• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

daisytuner / docc / 25823993703

13 May 2026 08:16PM UTC coverage: 60.954% (-4.8%) from 65.785%
25823993703

push

github

web-flow
Merge pull request #710 from daisytuner/publish-llvm-frontend

Publish LLVM (C/C++) frontend

2664 of 8267 new or added lines in 27 files covered. (32.22%)

35005 of 57429 relevant lines covered (60.95%)

11126.36 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.71
/llvm/src/lifting/function_to_sdfg.cpp
1
#include "docc/lifting/function_to_sdfg.h"
2

3
#include <llvm/IR/Function.h>
4
#include <llvm/IR/IntrinsicInst.h>
5
#include <llvm/IR/Verifier.h>
6
#include <llvm/Transforms/Utils/Cloning.h>
7
#include <llvm/Transforms/Utils/CodeExtractor.h>
8
#include <llvm/Transforms/Utils/ModuleUtils.h>
9

10
#include <docc/target/tenstorrent/math_node_implementation_override_pass.h>
11
#include <docc/target/tenstorrent/tenstorrent_transform.h>
12
#include <sdfg/analysis/analysis.h>
13
#include <sdfg/analysis/users.h>
14
#include <sdfg/builder/sdfg_builder.h>
15
#include <sdfg/helpers/helpers.h>
16
#include <sdfg/passes/debug_info_propagation.h>
17
#include <sdfg/passes/normalization/loop_normal_form.h>
18
#include <sdfg/passes/opt_pipeline.h>
19
#include <sdfg/passes/pipeline.h>
20
#include <sdfg/passes/schedules/expansion_pass.h>
21
#include <sdfg/passes/structured_control_flow/pointer_evolution.h>
22
#include <sdfg/passes/structured_control_flow/unify_loop_exits.h>
23
#include <sdfg/passes/structured_control_flow/while_to_for_conversion.h>
24
#include <sdfg/passes/symbolic/symbol_promotion.h>
25
#include <sdfg/passes/symbolic/type_minimization.h>
26

27
#include "docc/lifting/functions/function_lifting.h"
28
#include "docc/lifting/lift_report.h"
29
#include "docc/lifting/lifting.h"
30
#include "docc/utils.h"
31

32
llvm::cl::opt<std::string> DOCC_expand(
33
    "docc-expand",
34
    llvm::cl::desc("Overrides when to expand library nodes"),
35
    llvm::cl::init("none"),
36
    llvm::cl::value_desc("none|all")
37
);
38

39
namespace docc {
40
namespace lifting {
41

NEW
42
std::unique_ptr<llvm::Region> FunctionToSDFG::expand_region(std::unique_ptr<llvm::Region>& R) {
×
NEW
43
    std::unique_ptr<llvm::Region> current = std::move(R);
×
NEW
44
    std::unique_ptr<llvm::Region> last_valid = nullptr;
×
NEW
45
    while (current) {
×
NEW
46
        auto res = this->can_be_applied(*current);
×
NEW
47
        if (!res.first) break;
×
48

NEW
49
        last_valid = std::move(current);
×
NEW
50
        current = std::unique_ptr<llvm::Region>(last_valid->getExpandedRegion());
×
NEW
51
    }
×
52

NEW
53
    return last_valid;
×
NEW
54
}
×
55

56
bool FunctionToSDFG::is_blacklisted(llvm::Function& F, bool apply_on_linkonce_odr) {
1✔
57
    // Variadic functions
58
    if (F.isVarArg()) {
1✔
59
        return true;
1✔
60
    }
1✔
61

62
    // clang
NEW
63
    if (F.getName().starts_with("__clang")) {
×
NEW
64
        return true;
×
NEW
65
    }
×
66
    // c++, e.g., __cxx_global_var_init
NEW
67
    if (F.getName().starts_with("__cxx")) {
×
NEW
68
        return true;
×
NEW
69
    }
×
70
    // daisy, previously lifted
NEW
71
    if (F.getName().starts_with("__daisy")) {
×
NEW
72
        return true;
×
NEW
73
    }
×
74
    // global ctors
NEW
75
    if (F.hasSection() && F.getSection().contains("startup")) {
×
NEW
76
        return true;
×
NEW
77
    }
×
78
    // global dtors
NEW
79
    if (F.hasSection() && F.getSection().contains("exit")) {
×
NEW
80
        return true;
×
NEW
81
    }
×
82

83
    // aliased functions cannot be modified
NEW
84
    llvm::Module* Mod = F.getParent();
×
NEW
85
    for (const auto& alias : Mod->aliases()) {
×
NEW
86
        if (alias.getAliasee() == &F) {
×
NEW
87
            return true;
×
NEW
88
        }
×
NEW
89
    }
×
90

91
    // LinkOnceODR only if explicitly allowed
NEW
92
    if (apply_on_linkonce_odr) {
×
NEW
93
        if (F.getLinkage() == llvm::GlobalValue::LinkOnceODRLinkage) {
×
NEW
94
            return false;
×
NEW
95
        } else {
×
NEW
96
            return true;
×
NEW
97
        }
×
NEW
98
    }
×
99

100
    // Supported linkage: external, internal, private
NEW
101
    if (F.getLinkage() != llvm::GlobalValue::ExternalLinkage && F.getLinkage() != llvm::GlobalValue::InternalLinkage &&
×
NEW
102
        F.getLinkage() != llvm::GlobalValue::PrivateLinkage) {
×
NEW
103
        return true;
×
NEW
104
    }
×
105

106
    // No optnone, alwaysinline
107
    // if (F.hasFnAttribute(llvm::Attribute::OptimizeNone) ||
108
    //     F.hasFnAttribute(llvm::Attribute::AlwaysInline)) {
109
    //     return true;
110
    // }
111

NEW
112
    return false;
×
NEW
113
}
×
114

115
FunctionToSDFG::FunctionToSDFG(llvm::Function& function, llvm::FunctionAnalysisManager& FAM, bool apply_on_linkonce_odr)
NEW
116
    : function_(function), FAM_(FAM), sdfg_counter(0), apply_on_linkonce_odr_(apply_on_linkonce_odr) {}
×
117

NEW
118
std::vector<std::unique_ptr<sdfg::StructuredSDFG>> FunctionToSDFG::run() {
×
NEW
119
    auto& TLI = this->FAM_.getResult<llvm::TargetLibraryAnalysis>(this->function_);
×
NEW
120
    llvm::LibFunc lf;
×
NEW
121
    if (TLI.getLibFunc(this->function_.getName(), lf)) {
×
NEW
122
        return {};
×
NEW
123
    }
×
124

125
    // Attempt lifting the entire function
NEW
126
    auto res = this->can_be_applied();
×
NEW
127
    if (res.first) {
×
NEW
128
        try {
×
NEW
129
            auto sdfg = this->apply();
×
NEW
130
            if (sdfg) {
×
NEW
131
                std::vector<std::unique_ptr<sdfg::StructuredSDFG>> sdfgs;
×
NEW
132
                sdfgs.push_back(std::move(sdfg));
×
NEW
133
                return sdfgs;
×
NEW
134
            }
×
NEW
135
        } catch (sdfg::UnstructuredControlFlowException& e) {
×
136
            // Fallthrough
NEW
137
            LLVM_DEBUG_PRINTLN("UnstructuredControlFlowException on '" << this->function_.getName() << "': " << e.what());
×
NEW
138
        } catch (NotImplementedException& e) {
×
139
            // Fallthrough
NEW
140
            LLVM_DEBUG_PRINTLN("NotImplementedException on '" << this->function_.getName() << "': " << e.what());
×
NEW
141
        } catch (sdfg::InvalidSDFGException& e) {
×
142
            // Fallthrough
NEW
143
            LLVM_DEBUG_PRINTLN("InvalidSDFGException on '" << this->function_.getName() << "': " << e.what());
×
NEW
144
        }
×
NEW
145
    } else {
×
NEW
146
        if (res.second != nullptr) {
×
NEW
147
            sdfg::DebugInfo dbg_info;
×
NEW
148
            if (auto* inst = llvm::dyn_cast<llvm::Instruction>(res.second)) {
×
NEW
149
                dbg_info = ::docc::utils::get_debug_info(*inst);
×
NEW
150
            }
×
NEW
151
            LiftingReport::add_failed_lift(dbg_info, "Unsupported instruction", ::docc::utils::toIRString(*res.second));
×
NEW
152
        }
×
153

154
        // For LinkOnceODR, we must give up if the entire function cannot be lifted
NEW
155
        if (this->function_.getLinkage() == llvm::GlobalValue::LinkOnceODRLinkage) {
×
NEW
156
            return {};
×
NEW
157
        }
×
NEW
158
    }
×
159

160
    // Attempt lifting of Single-Entry-Single-Exit regions
NEW
161
    auto& RI = this->FAM_.getResult<llvm::RegionInfoAnalysis>(this->function_);
×
NEW
162
    std::list<std::unique_ptr<llvm::Region>> canonical_regions;
×
NEW
163
    for (auto& sub : *RI.getTopLevelRegion()) {
×
NEW
164
        canonical_regions.push_back(std::move(sub));
×
NEW
165
    }
×
166

NEW
167
    std::vector<std::unique_ptr<sdfg::StructuredSDFG>> sdfgs;
×
NEW
168
    while (!canonical_regions.empty()) {
×
NEW
169
        auto canon_region = std::move(canonical_regions.front());
×
NEW
170
        canonical_regions.pop_front();
×
171

NEW
172
        auto expanded_region = this->expand_region(canon_region);
×
NEW
173
        if (!expanded_region) {
×
NEW
174
            continue;
×
NEW
175
        }
×
176

177
        // Collect subregions
NEW
178
        std::list<llvm::Region*> subregions;
×
NEW
179
        for (auto& sub : canonical_regions) {
×
NEW
180
            if (expanded_region->contains(sub.get())) {
×
NEW
181
                subregions.push_back(sub.get());
×
NEW
182
            }
×
NEW
183
        }
×
184

NEW
185
        if (FunctionToSDFG::loop_count(this->function_, *expanded_region, this->FAM_) < 2) {
×
NEW
186
            for (auto& subregion : subregions) {
×
NEW
187
                for (auto it = canonical_regions.begin(); it != canonical_regions.end(); ++it) {
×
NEW
188
                    if (it->get() == subregion) {
×
NEW
189
                        canonical_regions.erase(it);
×
NEW
190
                        break;
×
NEW
191
                    }
×
NEW
192
                }
×
NEW
193
            }
×
NEW
194
            continue;
×
NEW
195
        }
×
196

NEW
197
        try {
×
NEW
198
            auto sdfg = this->apply(*expanded_region);
×
NEW
199
            if (sdfg) {
×
NEW
200
                sdfgs.push_back(std::move(sdfg));
×
NEW
201
                for (auto& subregion : subregions) {
×
NEW
202
                    for (auto it = canonical_regions.begin(); it != canonical_regions.end(); ++it) {
×
NEW
203
                        if (it->get() == subregion) {
×
NEW
204
                            canonical_regions.erase(it);
×
NEW
205
                            break;
×
NEW
206
                        }
×
NEW
207
                    }
×
NEW
208
                }
×
NEW
209
                continue;
×
NEW
210
            }
×
NEW
211
        } catch (sdfg::UnstructuredControlFlowException& e) {
×
212
            // Fallthrough
NEW
213
        } catch (NotImplementedException& e) {
×
214
            // Fallthrough
NEW
215
        } catch (sdfg::InvalidSDFGException& e) {
×
216
            // Fallthrough
NEW
217
        }
×
218

219
        // Region failed, give up
NEW
220
        break;
×
NEW
221
    }
×
222

NEW
223
    return sdfgs;
×
NEW
224
}
×
225

NEW
226
std::pair<bool, llvm::Value*> FunctionToSDFG::can_be_applied(llvm::Region& region) {
×
227
    // Criterion: Regions must be extractable into functions
NEW
228
    llvm::SmallVector<llvm::BasicBlock*> blocks;
×
NEW
229
    for (auto block : region.blocks()) {
×
NEW
230
        blocks.push_back(block);
×
NEW
231
    }
×
NEW
232
    llvm::CodeExtractor code_extractor(
×
NEW
233
        blocks,
×
NEW
234
        nullptr, // DT
×
NEW
235
        false, // Aggregate args
×
NEW
236
        nullptr, // BFI
×
NEW
237
        nullptr, // BPI
×
NEW
238
        nullptr, // AC
×
NEW
239
        false, // Var args
×
NEW
240
        false, // Allow alloca
×
NEW
241
        nullptr, // Alloc block
×
NEW
242
        "" // Suffix
×
NEW
243
    );
×
NEW
244
    if (!code_extractor.isEligible()) {
×
NEW
245
        return {false, nullptr};
×
NEW
246
    }
×
247

248
    // Criterion: No unsupported instructions
NEW
249
    auto& TLI = this->FAM_.getResult<llvm::TargetLibraryAnalysis>(this->function_);
×
NEW
250
    for (auto block : region.blocks()) {
×
NEW
251
        for (auto& inst : *block) {
×
252
            // TODO: Switch
NEW
253
            if (llvm::dyn_cast<const llvm::SwitchInst>(&inst)) {
×
NEW
254
                return {false, &inst};
×
NEW
255
            }
×
NEW
256
            if (auto phi_inst = llvm::dyn_cast<const llvm::PHINode>(&inst)) {
×
NEW
257
                for (size_t i = 0; i < phi_inst->getNumIncomingValues(); ++i) {
×
NEW
258
                    auto phi_value = phi_inst->getIncomingValue(i);
×
259
                    // Must be first-class type: scalar or pointer
NEW
260
                    if (phi_value->getType()->isVectorTy() || phi_value->getType()->isAggregateType()) {
×
NEW
261
                        return {false, &inst};
×
NEW
262
                    }
×
NEW
263
                }
×
NEW
264
            }
×
265

266
            // Poison
NEW
267
            if (llvm::dyn_cast<const llvm::FreezeInst>(&inst)) {
×
NEW
268
                return {false, &inst};
×
NEW
269
            }
×
270

271
            // Unsafe casts
NEW
272
            if (llvm::isa<llvm::AddrSpaceCastInst>(&inst)) {
×
NEW
273
                return {false, &inst};
×
NEW
274
            } else if (llvm::isa<llvm::BitCastInst>(&inst)) {
×
NEW
275
                return {false, &inst};
×
NEW
276
            } else if (llvm::isa<llvm::IntToPtrInst>(&inst)) {
×
NEW
277
                return {false, &inst};
×
NEW
278
            }
×
279

280
            // Atomic operations
NEW
281
            if (llvm::isa<const llvm::AtomicRMWInst>(&inst)) {
×
NEW
282
                return {false, &inst};
×
NEW
283
            } else if (llvm::isa<const llvm::AtomicCmpXchgInst>(&inst)) {
×
NEW
284
                return {false, &inst};
×
NEW
285
            } else if (llvm::isa<const llvm::FenceInst>(&inst)) {
×
NEW
286
                return {false, &inst};
×
NEW
287
            }
×
288

289
            // Function calls
NEW
290
            if (auto call_base = llvm::dyn_cast<const llvm::CallBase>(&inst)) {
×
NEW
291
                if (!FunctionLifting::is_supported(TLI, call_base)) {
×
NEW
292
                    return {false, &inst};
×
NEW
293
                }
×
NEW
294
            }
×
NEW
295
            if (auto landing_pad = llvm::dyn_cast<const llvm::LandingPadInst>(&inst)) {
×
NEW
296
                return {false, &inst};
×
NEW
297
            }
×
NEW
298
            if (auto resume = llvm::dyn_cast<const llvm::ResumeInst>(&inst)) {
×
NEW
299
                return {false, &inst};
×
NEW
300
            }
×
301

302
            // Constant expressions
NEW
303
            for (const llvm::Use& U : inst.operands()) {
×
NEW
304
                if (llvm::isa<llvm::ConstantExpr>(U.get())) {
×
NEW
305
                    return {false, &inst};
×
NEW
306
                }
×
NEW
307
            }
×
308

309
            // Not implemented instructions
NEW
310
            if (llvm::isa<const llvm::ExtractValueInst>(&inst)) {
×
NEW
311
                return {false, &inst};
×
NEW
312
            }
×
NEW
313
            if (llvm::isa<const llvm::InsertValueInst>(&inst)) {
×
NEW
314
                return {false, &inst};
×
NEW
315
            }
×
NEW
316
            if (llvm::isa<const llvm::InsertElementInst>(&inst)) {
×
NEW
317
                return {false, &inst};
×
NEW
318
            }
×
319

320
            // Unsupported types
NEW
321
            auto output_type = inst.getType();
×
NEW
322
            if (output_type->isIntegerTy()) {
×
NEW
323
                switch (output_type->getIntegerBitWidth()) {
×
NEW
324
                    case 1:
×
NEW
325
                    case 8:
×
NEW
326
                    case 16:
×
NEW
327
                    case 32:
×
NEW
328
                    case 64:
×
NEW
329
                    case 128:
×
NEW
330
                        break;
×
NEW
331
                    default: {
×
NEW
332
                        return {false, &inst};
×
NEW
333
                    }
×
NEW
334
                }
×
NEW
335
            }
×
NEW
336
        }
×
NEW
337
        llvm::Instruction* terminator = block->getTerminator();
×
NEW
338
        if (!llvm::isa<llvm::UnreachableInst>(terminator) && !llvm::isa<llvm::ReturnInst>(terminator) &&
×
NEW
339
            !llvm::isa<llvm::BranchInst>(terminator) && !llvm::isa<llvm::InvokeInst>(terminator)) {
×
NEW
340
            return {false, terminator};
×
NEW
341
        }
×
NEW
342
    }
×
343

NEW
344
    return {true, nullptr};
×
NEW
345
}
×
346

NEW
347
std::pair<bool, llvm::Value*> FunctionToSDFG::can_be_applied() {
×
NEW
348
    auto& TLI = this->FAM_.getResult<llvm::TargetLibraryAnalysis>(this->function_);
×
349

350
    // Criterion: No unsupported globals' initializers
NEW
351
    std::unordered_set<llvm::GlobalObject*> globals;
×
NEW
352
    Lifting::collect_globals(this->function_, globals);
×
NEW
353
    for (llvm::GlobalObject* GV : globals) {
×
NEW
354
        switch (GV->getLinkage()) {
×
NEW
355
            case llvm::GlobalValue::LinkageTypes::ExternalLinkage:
×
NEW
356
            case llvm::GlobalValue::LinkageTypes::AvailableExternallyLinkage:
×
NEW
357
            case llvm::GlobalValue::LinkageTypes::LinkOnceAnyLinkage:
×
NEW
358
            case llvm::GlobalValue::LinkageTypes::LinkOnceODRLinkage:
×
NEW
359
            case llvm::GlobalValue::LinkageTypes::WeakAnyLinkage:
×
NEW
360
            case llvm::GlobalValue::LinkageTypes::WeakODRLinkage: {
×
361
                // Always allowed
NEW
362
                continue;
×
NEW
363
            }
×
NEW
364
            case llvm::GlobalValue::LinkageTypes::InternalLinkage: {
×
365
                // Renamed to globally unique and set to external linkage
366
                // Thus, initializer need not be lifted
NEW
367
                continue;
×
NEW
368
            }
×
NEW
369
            case llvm::GlobalValue::LinkageTypes::PrivateLinkage: {
×
370
                // Renamed to globally unique and set to external linkage
371
                // Thus, initializer need not be lifted
NEW
372
                continue;
×
NEW
373
            }
×
NEW
374
            default:
×
NEW
375
                return {false, GV};
×
NEW
376
        }
×
NEW
377
    }
×
378

379
    // Criterion: No unsupported instructions
NEW
380
    for (auto& block : this->function_) {
×
NEW
381
        for (auto& inst : block) {
×
382
            // TODO: Switch
NEW
383
            if (llvm::dyn_cast<const llvm::SwitchInst>(&inst)) {
×
NEW
384
                return {false, &inst};
×
NEW
385
            }
×
NEW
386
            if (auto phi_inst = llvm::dyn_cast<const llvm::PHINode>(&inst)) {
×
NEW
387
                for (size_t i = 0; i < phi_inst->getNumIncomingValues(); ++i) {
×
NEW
388
                    auto phi_value = phi_inst->getIncomingValue(i);
×
389
                    // Must be first-class type: scalar or pointer
NEW
390
                    if (phi_value->getType()->isVectorTy() || phi_value->getType()->isAggregateType()) {
×
NEW
391
                        return {false, &inst};
×
NEW
392
                    }
×
NEW
393
                }
×
NEW
394
            }
×
395

396
            // Poison
NEW
397
            if (llvm::dyn_cast<const llvm::FreezeInst>(&inst)) {
×
NEW
398
                return {false, &inst};
×
NEW
399
            }
×
400

401
            // Unsafe casts
NEW
402
            if (llvm::isa<llvm::AddrSpaceCastInst>(&inst)) {
×
NEW
403
                return {false, &inst};
×
NEW
404
            } else if (llvm::isa<llvm::BitCastInst>(&inst)) {
×
NEW
405
                return {false, &inst};
×
NEW
406
            } else if (llvm::isa<llvm::IntToPtrInst>(&inst)) {
×
NEW
407
                return {false, &inst};
×
NEW
408
            }
×
409

410
            // Atomic operations
NEW
411
            if (llvm::isa<const llvm::AtomicRMWInst>(&inst)) {
×
NEW
412
                return {false, &inst};
×
NEW
413
            } else if (llvm::isa<const llvm::AtomicCmpXchgInst>(&inst)) {
×
NEW
414
                return {false, &inst};
×
NEW
415
            } else if (llvm::isa<const llvm::FenceInst>(&inst)) {
×
NEW
416
                return {false, &inst};
×
NEW
417
            }
×
418

419
            // Function calls
NEW
420
            if (auto call_base = llvm::dyn_cast<const llvm::CallBase>(&inst)) {
×
NEW
421
                if (!FunctionLifting::is_supported(TLI, call_base)) {
×
NEW
422
                    return {false, &inst};
×
NEW
423
                }
×
NEW
424
            }
×
NEW
425
            if (auto landing_pad = llvm::dyn_cast<const llvm::LandingPadInst>(&inst)) {
×
NEW
426
                return {false, &inst};
×
NEW
427
            }
×
NEW
428
            if (auto resume = llvm::dyn_cast<const llvm::ResumeInst>(&inst)) {
×
NEW
429
                return {false, &inst};
×
NEW
430
            }
×
431

432
            // Constant expressions
NEW
433
            for (const llvm::Use& U : inst.operands()) {
×
NEW
434
                if (llvm::isa<llvm::ConstantExpr>(U.get())) {
×
NEW
435
                    return {false, &inst};
×
NEW
436
                }
×
NEW
437
            }
×
438

439
            // Not implemented instructions
NEW
440
            if (llvm::isa<const llvm::ExtractValueInst>(&inst)) {
×
NEW
441
                return {false, &inst};
×
NEW
442
            }
×
NEW
443
            if (llvm::isa<const llvm::InsertValueInst>(&inst)) {
×
NEW
444
                return {false, &inst};
×
NEW
445
            }
×
NEW
446
            if (llvm::isa<const llvm::InsertElementInst>(&inst)) {
×
NEW
447
                return {false, &inst};
×
NEW
448
            }
×
449

450
            // Unsupported types
NEW
451
            auto output_type = inst.getType();
×
NEW
452
            if (output_type->isIntegerTy()) {
×
NEW
453
                switch (output_type->getIntegerBitWidth()) {
×
NEW
454
                    case 1:
×
NEW
455
                    case 8:
×
NEW
456
                    case 16:
×
NEW
457
                    case 32:
×
NEW
458
                    case 64:
×
NEW
459
                    case 128:
×
NEW
460
                        break;
×
NEW
461
                    default: {
×
NEW
462
                        return {false, &inst};
×
NEW
463
                    }
×
NEW
464
                }
×
NEW
465
            }
×
NEW
466
        }
×
NEW
467
        llvm::Instruction* terminator = block.getTerminator();
×
NEW
468
        if (!llvm::isa<llvm::UnreachableInst>(terminator) && !llvm::isa<llvm::ReturnInst>(terminator) &&
×
NEW
469
            !llvm::isa<llvm::BranchInst>(terminator) && !llvm::isa<llvm::InvokeInst>(terminator)) {
×
NEW
470
            return {false, terminator};
×
NEW
471
        }
×
NEW
472
    }
×
473

NEW
474
    return {true, nullptr};
×
NEW
475
}
×
476

NEW
477
std::unique_ptr<sdfg::StructuredSDFG> FunctionToSDFG::apply(llvm::Region& region) {
×
NEW
478
    std::filesystem::path module_path = this->function_.getParent()->getName().str();
×
NEW
479
    std::string module_name = module_path.stem();
×
480

481
    // Refactor region into separate function
NEW
482
    llvm::SmallVector<llvm::BasicBlock*> blocks;
×
NEW
483
    for (auto block : region.blocks()) {
×
NEW
484
        blocks.push_back(block);
×
NEW
485
    }
×
486

NEW
487
    llvm::CodeExtractor code_extractor(
×
NEW
488
        blocks,
×
NEW
489
        nullptr, // DT
×
NEW
490
        false, // Aggregate args
×
NEW
491
        nullptr, // BFI
×
NEW
492
        nullptr, // BPI
×
NEW
493
        nullptr, // AC
×
NEW
494
        false, // Var args
×
NEW
495
        false, // Allow alloca
×
NEW
496
        nullptr, // Alloc block
×
NEW
497
        "" // Suffix
×
NEW
498
    );
×
NEW
499
    assert(code_extractor.isEligible());
×
NEW
500
    llvm::CodeExtractorAnalysisCache CEAC(this->function_);
×
NEW
501
    llvm::Function* external_function = code_extractor.extractCodeRegion(CEAC);
×
502

503
    // Set name of new function
NEW
504
    std::string new_function_name = ::docc::utils::hash_function_name(utils::get_name(external_function));
×
NEW
505
    new_function_name = utils::normalize_name(module_name) + utils::normalize_name(new_function_name);
×
NEW
506
    new_function_name = "__daisy_" + new_function_name + "_" + std::to_string(sdfg_counter++);
×
NEW
507
    external_function->setName(new_function_name);
×
NEW
508
    external_function->setLinkage(this->function_.getLinkage());
×
509

510
    // Criterion: No unsupported globals' initializers
NEW
511
    std::unordered_set<llvm::GlobalObject*> globals;
×
NEW
512
    Lifting::collect_globals(*external_function, globals);
×
NEW
513
    for (llvm::GlobalObject* GV : globals) {
×
NEW
514
        switch (GV->getLinkage()) {
×
NEW
515
            case llvm::GlobalValue::LinkageTypes::ExternalLinkage:
×
NEW
516
            case llvm::GlobalValue::LinkageTypes::AvailableExternallyLinkage:
×
NEW
517
            case llvm::GlobalValue::LinkageTypes::LinkOnceAnyLinkage:
×
NEW
518
            case llvm::GlobalValue::LinkageTypes::LinkOnceODRLinkage:
×
NEW
519
            case llvm::GlobalValue::LinkageTypes::WeakAnyLinkage:
×
NEW
520
            case llvm::GlobalValue::LinkageTypes::WeakODRLinkage: {
×
521
                // Always allowed
NEW
522
                continue;
×
NEW
523
            }
×
NEW
524
            case llvm::GlobalValue::LinkageTypes::InternalLinkage: {
×
525
                // Renamed to globally unique and set to external linkage
526
                // Thus, initializer need not be lifted
NEW
527
                continue;
×
NEW
528
            }
×
NEW
529
            case llvm::GlobalValue::LinkageTypes::PrivateLinkage: {
×
530
                // Renamed to globally unique and set to external linkage
531
                // Thus, initializer need not be lifted
NEW
532
                continue;
×
NEW
533
            }
×
NEW
534
            default:
×
NEW
535
                return nullptr;
×
NEW
536
        }
×
NEW
537
    }
×
538

539
    // Lift SDFG
NEW
540
    auto& TLI = this->FAM_.getResult<llvm::TargetLibraryAnalysis>(this->function_);
×
NEW
541
    Lifting lifting(TLI, *external_function, sdfg::FunctionType_CPU);
×
NEW
542
    std::unique_ptr<sdfg::SDFG> sdfg = lifting.run();
×
NEW
543
    sdfg->validate();
×
544

NEW
545
    sdfg::builder::SDFGBuilder builder_canon(sdfg);
×
NEW
546
    sdfg::passes::UnifyLoopExits unify_loop_exits_pass;
×
NEW
547
    unify_loop_exits_pass.run(builder_canon);
×
NEW
548
    unify_loop_exits_pass.run(builder_canon);
×
NEW
549
    unify_loop_exits_pass.run(builder_canon);
×
NEW
550
    sdfg = builder_canon.move();
×
551

552
    // Build StructuredSDFG
NEW
553
    sdfg::builder::StructuredSDFGBuilder structured_builder(*sdfg);
×
554

555
    // Propagate debug info
NEW
556
    sdfg::analysis::AnalysisManager analysis_manager(structured_builder.subject());
×
NEW
557
    sdfg::passes::DebugInfoPropagation debug_info_propagation_pass;
×
NEW
558
    debug_info_propagation_pass.run(structured_builder, analysis_manager);
×
559

NEW
560
    LiftingReport::add_successful_lift(::docc::utils::get_debug_info(*external_function));
×
NEW
561
    auto structured_sdfg = structured_builder.move();
×
562

563
    // Simplify SDFG
NEW
564
    auto simplified_sdfg = this->simplify(structured_sdfg);
×
565

566
    // Prevent further inlining
NEW
567
    external_function->addFnAttr(llvm::Attribute::NoInline);
×
NEW
568
    external_function->addFnAttr(llvm::Attribute::OptimizeNone);
×
NEW
569
    llvm::appendToUsed(*this->function_.getParent(), {external_function});
×
570

NEW
571
    bool verify_dbg = false;
×
NEW
572
    bool failed = llvm::verifyModule(*this->function_.getParent(), &llvm::errs(), &verify_dbg);
×
NEW
573
    if (failed) {
×
NEW
574
        throw sdfg::InvalidSDFGException("Module is broken after lifting region.");
×
NEW
575
    }
×
576

NEW
577
    return simplified_sdfg;
×
NEW
578
}
×
579

NEW
580
std::unique_ptr<sdfg::StructuredSDFG> FunctionToSDFG::apply() {
×
581
    // Lift SDFG
NEW
582
    auto& TLI = this->FAM_.getResult<llvm::TargetLibraryAnalysis>(this->function_);
×
NEW
583
    Lifting lifting(TLI, this->function_, sdfg::FunctionType_CPU);
×
NEW
584
    std::unique_ptr<sdfg::SDFG> sdfg = lifting.run();
×
NEW
585
    sdfg->validate();
×
586

587
    // Increase of graph complexity
NEW
588
    sdfg::builder::SDFGBuilder builder_canon(sdfg);
×
NEW
589
    sdfg::passes::UnifyLoopExits unify_loop_exits_pass;
×
NEW
590
    unify_loop_exits_pass.run(builder_canon);
×
NEW
591
    unify_loop_exits_pass.run(builder_canon);
×
NEW
592
    unify_loop_exits_pass.run(builder_canon);
×
NEW
593
    sdfg = builder_canon.move();
×
594

595
    // Build StructuredSDFG
NEW
596
    sdfg::builder::StructuredSDFGBuilder structured_builder(*sdfg);
×
597

598
    // Propagate debug info
NEW
599
    sdfg::analysis::AnalysisManager analysis_manager(structured_builder.subject());
×
NEW
600
    sdfg::passes::DebugInfoPropagation debug_info_propagation_pass;
×
NEW
601
    debug_info_propagation_pass.run(structured_builder, analysis_manager);
×
602

NEW
603
    LiftingReport::add_successful_lift(::docc::utils::get_debug_info(this->function_));
×
NEW
604
    auto structured_sdfg = structured_builder.move();
×
605

606
    // Simplify SDFG
NEW
607
    auto simplified_sdfg = this->simplify(structured_sdfg);
×
608

609
    // If LinkOnceODR, internalize original function
NEW
610
    if (this->function_.getLinkage() == llvm::GlobalValue::LinkOnceODRLinkage) {
×
NEW
611
        std::string module_path = this->function_.getParent()->getName().str();
×
NEW
612
        std::string module_name = std::filesystem::path(module_path).stem().string();
×
613

NEW
614
        llvm::Function* internal_function = llvm::Function::Create(
×
NEW
615
            this->function_.getFunctionType(),
×
NEW
616
            llvm::GlobalValue::ExternalLinkage,
×
NEW
617
            "__daisy_odr_" + utils::normalize_name(module_name) + "_" + this->function_.getName(),
×
NEW
618
            this->function_.getParent()
×
NEW
619
        );
×
NEW
620
        internal_function->copyAttributesFrom(&this->function_);
×
NEW
621
        internal_function->setComdat(nullptr);
×
622

623
        // Map arguments and the function itself for recursion
NEW
624
        llvm::ValueToValueMapTy VMap;
×
NEW
625
        auto dest_arg_it = internal_function->arg_begin();
×
NEW
626
        for (auto& src_arg : this->function_.args()) {
×
NEW
627
            dest_arg_it->setName(src_arg.getName());
×
NEW
628
            VMap[&src_arg] = &*dest_arg_it++;
×
NEW
629
        }
×
NEW
630
        VMap[&this->function_] = internal_function; // Handle recursive calls
×
631

NEW
632
        llvm::SmallVector<llvm::ReturnInst*, 8> Returns;
×
633
        // Clone the function body
NEW
634
        llvm::CloneFunctionInto(
×
NEW
635
            internal_function, &this->function_, VMap, llvm::CloneFunctionChangeType::LocalChangesOnly, Returns
×
NEW
636
        );
×
637

638
        // Redirect all uses in this module to the clone
NEW
639
        llvm::SmallVector<llvm::Use*, 16> Uses;
×
NEW
640
        for (llvm::Use& U : this->function_.uses()) {
×
NEW
641
            Uses.push_back(&U);
×
NEW
642
        }
×
NEW
643
        for (llvm::Use* U : Uses) {
×
NEW
644
            U->set(internal_function);
×
NEW
645
        }
×
646

647
        // Rename sdfg to match internal function
NEW
648
        simplified_sdfg->name(internal_function->getName().str());
×
649

650
        // Prevent further inlining
NEW
651
        internal_function->addFnAttr(llvm::Attribute::NoInline);
×
NEW
652
        internal_function->addFnAttr(llvm::Attribute::OptimizeNone);
×
NEW
653
        llvm::appendToUsed(*internal_function->getParent(), {internal_function});
×
654

NEW
655
        llvm::appendToUsed(*this->function_.getParent(), {&this->function_});
×
NEW
656
    } else {
×
657
        // Prevent further inlining
NEW
658
        this->function_.addFnAttr(llvm::Attribute::NoInline);
×
NEW
659
        this->function_.addFnAttr(llvm::Attribute::OptimizeNone);
×
NEW
660
        llvm::appendToUsed(*this->function_.getParent(), {&this->function_});
×
NEW
661
    }
×
662

NEW
663
    bool verify_dbg = false;
×
NEW
664
    bool failed = llvm::verifyModule(*this->function_.getParent(), &llvm::errs(), &verify_dbg);
×
NEW
665
    if (failed) {
×
NEW
666
        throw sdfg::InvalidSDFGException("Module is broken after lifting region.");
×
NEW
667
    }
×
668

NEW
669
    return simplified_sdfg;
×
NEW
670
}
×
671

NEW
672
std::unique_ptr<sdfg::StructuredSDFG> FunctionToSDFG::simplify(std::unique_ptr<sdfg::StructuredSDFG>& sdfg) {
×
NEW
673
    sdfg::builder::StructuredSDFGBuilder builder_opt(sdfg);
×
NEW
674
    sdfg::analysis::AnalysisManager analysis_manager(builder_opt.subject());
×
675

676
    // Optimization Pipelines
NEW
677
    sdfg::passes::Pipeline dataflow_simplification = sdfg::passes::Pipeline::dataflow_simplification();
×
NEW
678
    sdfg::passes::Pipeline symbolic_simplification = sdfg::passes::Pipeline::symbolic_simplification();
×
NEW
679
    sdfg::passes::Pipeline dce = sdfg::passes::Pipeline::dead_code_elimination();
×
NEW
680
    sdfg::passes::Pipeline memlet_combine = sdfg::passes::Pipeline::memlet_combine();
×
NEW
681
    sdfg::passes::DeadDataElimination dde;
×
NEW
682
    sdfg::passes::SymbolPropagation symbol_propagation_pass;
×
683

684
    // Promote tasklets into symbolic assignments
NEW
685
    sdfg::passes::SymbolPromotion symbol_promotion_pass;
×
NEW
686
    symbol_promotion_pass.run(builder_opt, analysis_manager);
×
687

688
    // Expand library nodes if requested
NEW
689
    if (DOCC_expand == "tenstorrent") {
×
NEW
690
        LLVM_DEBUG_PRINTLN("Overriding all library nodes to Tenstorrent");
×
NEW
691
        auto pass = sdfg::tenstorrent::MathNodeImplementationOverridePass();
×
NEW
692
        bool success = pass.run(builder_opt, analysis_manager);
×
NEW
693
    } else if (DOCC_expand != "none") {
×
NEW
694
        LLVM_DEBUG_PRINTLN("Expanding all library nodes");
×
NEW
695
        auto expansion_pass = sdfg::passes::ExpansionPass();
×
NEW
696
        bool expanded = expansion_pass.run(builder_opt, analysis_manager);
×
NEW
697
    }
×
698

699
    /***** SDFG Minimization *****/
700

701
    // Minimize SDFG by fusing blocks, tasklets and sequences
NEW
702
    dataflow_simplification.run(builder_opt, analysis_manager);
×
NEW
703
    dde.run(builder_opt, analysis_manager);
×
NEW
704
    dce.run(builder_opt, analysis_manager);
×
705

706
    // Minimize SDFG by fusing symbolic expressions
NEW
707
    symbolic_simplification.run(builder_opt, analysis_manager);
×
NEW
708
    dde.run(builder_opt, analysis_manager);
×
NEW
709
    dce.run(builder_opt, analysis_manager);
×
710

711
    /***** Structured Loops *****/
712

713
    // Unify continue/break inside branches
NEW
714
    {
×
NEW
715
        sdfg::passes::CommonAssignmentElimination common_assignment_elimination;
×
NEW
716
        bool applies = false;
×
NEW
717
        do {
×
NEW
718
            applies = false;
×
NEW
719
            applies |= common_assignment_elimination.run(builder_opt, analysis_manager);
×
NEW
720
        } while (applies);
×
NEW
721
        dde.run(builder_opt, analysis_manager);
×
NEW
722
        dce.run(builder_opt, analysis_manager);
×
NEW
723
        symbolic_simplification.run(builder_opt, analysis_manager);
×
NEW
724
    }
×
725

726
    // Propagate variables into constants
NEW
727
    {
×
NEW
728
        sdfg::passes::ConstantPropagation constant_propagation_pass;
×
NEW
729
        bool applies = false;
×
NEW
730
        do {
×
NEW
731
            applies = false;
×
NEW
732
            applies |= constant_propagation_pass.run(builder_opt, analysis_manager);
×
NEW
733
        } while (applies);
×
NEW
734
    }
×
735

736
    // Convert loops into structured loops
NEW
737
    sdfg::passes::WhileToForConversion for_conversion_pass;
×
NEW
738
    for_conversion_pass.run(builder_opt, analysis_manager);
×
739

740
    // Propagate for simpler indvar usage
NEW
741
    symbol_propagation_pass.run(builder_opt, analysis_manager);
×
742

743
    // Eliminate redundant branches
NEW
744
    {
×
NEW
745
        bool applies = false;
×
NEW
746
        sdfg::passes::ConditionEliminationPass condition_elimination_pass;
×
NEW
747
        do {
×
NEW
748
            applies = false;
×
NEW
749
            applies |= condition_elimination_pass.run(builder_opt, analysis_manager);
×
NEW
750
        } while (applies);
×
NEW
751
    }
×
752

753
    // Normalize loop condition and update (run twice)
NEW
754
    sdfg::passes::normalization::LoopNormalFormPass loop_normalization_pass;
×
NEW
755
    loop_normalization_pass.run(builder_opt, analysis_manager);
×
NEW
756
    symbol_propagation_pass.run(builder_opt, analysis_manager);
×
NEW
757
    dde.run(builder_opt, analysis_manager);
×
NEW
758
    dce.run(builder_opt, analysis_manager);
×
759

760
    // Eliminate symbols correlated to loop iterators
NEW
761
    sdfg::passes::SymbolEvolution symbol_evolution_pass;
×
NEW
762
    symbol_evolution_pass.run(builder_opt, analysis_manager);
×
763

764
    // Dead code elimination
NEW
765
    symbol_propagation_pass.run(builder_opt, analysis_manager);
×
NEW
766
    dde.run(builder_opt, analysis_manager);
×
NEW
767
    dce.run(builder_opt, analysis_manager);
×
768

769
    /***** Data Parallelism *****/
770

771
    // Combine address calculations in memlets
NEW
772
    memlet_combine.run(builder_opt, analysis_manager);
×
773

774
    // Move code out of loops where possible
NEW
775
    sdfg::passes::Pipeline code_motion = sdfg::passes::code_motion();
×
NEW
776
    code_motion.run(builder_opt, analysis_manager);
×
777

778
    // Convert pointer-based iterators to indvar usage
NEW
779
    sdfg::passes::PointerEvolution pointer_evolution_pass;
×
NEW
780
    pointer_evolution_pass.run(builder_opt, analysis_manager);
×
NEW
781
    loop_normalization_pass.run(builder_opt, analysis_manager);
×
782

783
    // Convert lib-calls into managed memory
NEW
784
    sdfg::passes::Pipeline memory = sdfg::passes::Pipeline::memory();
×
NEW
785
    memory.run(builder_opt, analysis_manager);
×
786

NEW
787
    sdfg::passes::TypeMinimizationPass type_minimization_pass;
×
NEW
788
    type_minimization_pass.run(builder_opt, analysis_manager);
×
NEW
789
    type_minimization_pass.run(builder_opt, analysis_manager);
×
790

791
    // Dead code elimination
NEW
792
    symbol_propagation_pass.run(builder_opt, analysis_manager);
×
NEW
793
    dce.run(builder_opt, analysis_manager);
×
NEW
794
    dde.run(builder_opt, analysis_manager);
×
795

796
    // Convert for loops into maps
NEW
797
    sdfg::passes::For2MapPass map_conversion_pass;
×
NEW
798
    map_conversion_pass.run(builder_opt, analysis_manager);
×
799

800
    // Move code out of maps where possible
NEW
801
    code_motion.run(builder_opt, analysis_manager);
×
802

803
    // Dead code elimination
NEW
804
    dde.run(builder_opt, analysis_manager);
×
NEW
805
    dce.run(builder_opt, analysis_manager);
×
NEW
806
    dataflow_simplification.run(builder_opt, analysis_manager);
×
807

NEW
808
    return builder_opt.move();
×
NEW
809
};
×
810

811
} // namespace lifting
812
} // namespace docc
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc