Line | Branch | Exec | Source |
---|---|---|---|
1 | // Copyright (c) 2021-2025 ChilliBits. All rights reserved. | ||
2 | |||
3 | #include "IRGenerator.h" | ||
4 | |||
5 | #include <llvm/IR/Module.h> | ||
6 | #include <llvm/IR/Verifier.h> | ||
7 | |||
8 | #include <SourceFile.h> | ||
9 | #include <global/GlobalResourceManager.h> | ||
10 | #include <irgenerator/NameMangling.h> | ||
11 | #include <symboltablebuilder/SymbolTableBuilder.h> | ||
12 | |||
13 | namespace spice::compiler { | ||
14 | |||
15 | 831 | IRGenerator::IRGenerator(GlobalResourceManager &resourceManager, SourceFile *sourceFile) | |
16 | 831 | : CompilerPass(resourceManager, sourceFile), context(cliOptions.useLTO ? resourceManager.ltoContext : sourceFile->context), | |
17 |
1/2✓ Branch 0 (8→9) taken 831 times.
✗ Branch 1 (8→61) not taken.
|
831 | builder(sourceFile->builder), module(sourceFile->llvmModule.get()), conversionManager(sourceFile, this), |
18 |
5/8✓ Branch 0 (4→5) taken 2 times.
✓ Branch 1 (4→6) taken 829 times.
✓ Branch 2 (9→10) taken 831 times.
✗ Branch 3 (9→61) not taken.
✓ Branch 4 (10→11) taken 831 times.
✗ Branch 5 (10→61) not taken.
✓ Branch 6 (14→15) taken 831 times.
✗ Branch 7 (14→55) not taken.
|
1662 | stdFunctionManager(sourceFile, resourceManager, module) { |
19 | // Attach information to the module | ||
20 |
1/2✓ Branch 0 (16→17) taken 831 times.
✗ Branch 1 (16→40) not taken.
|
831 | module->setTargetTriple(cliOptions.targetTriple); |
21 |
2/4✓ Branch 0 (20→21) taken 831 times.
✗ Branch 1 (20→43) not taken.
✓ Branch 2 (21→22) taken 831 times.
✗ Branch 3 (21→41) not taken.
|
831 | module->setDataLayout(sourceFile->targetMachine->createDataLayout()); |
22 |
1/2✓ Branch 0 (23→24) taken 831 times.
✗ Branch 1 (23→51) not taken.
|
831 | module->setPICLevel(llvm::PICLevel::BigPIC); |
23 |
1/2✓ Branch 0 (24→25) taken 831 times.
✗ Branch 1 (24→51) not taken.
|
831 | module->setPIELevel(llvm::PIELevel::Large); |
24 |
1/2✓ Branch 0 (25→26) taken 831 times.
✗ Branch 1 (25→51) not taken.
|
831 | module->setUwtable(llvm::UWTableKind::Default); |
25 |
1/2✓ Branch 0 (26→27) taken 831 times.
✗ Branch 1 (26→51) not taken.
|
831 | module->setFramePointer(llvm::FramePointerKind::All); |
26 | |||
27 | // Add module identifier metadata | ||
28 |
2/4✓ Branch 0 (27→28) taken 831 times.
✗ Branch 1 (27→44) not taken.
✓ Branch 2 (28→29) taken 831 times.
✗ Branch 3 (28→44) not taken.
|
831 | llvm::NamedMDNode *identifierMetadata = module->getOrInsertNamedMetadata("llvm.ident"); |
29 |
3/6✓ Branch 0 (30→31) taken 831 times.
✗ Branch 1 (30→45) not taken.
✓ Branch 2 (32→33) taken 831 times.
✗ Branch 3 (32→45) not taken.
✓ Branch 4 (33→34) taken 831 times.
✗ Branch 5 (33→45) not taken.
|
831 | identifierMetadata->addOperand(llvm::MDNode::get(context, llvm::MDString::get(context, PRODUCER_STRING))); |
30 | |||
31 | // Initialize debug info generator | ||
32 |
2/2✓ Branch 0 (34→35) taken 15 times.
✓ Branch 1 (34→39) taken 816 times.
|
831 | if (cliOptions.generateDebugInfo) |
33 |
2/4✓ Branch 0 (35→36) taken 15 times.
✗ Branch 1 (35→50) not taken.
✓ Branch 2 (36→37) taken 15 times.
✗ Branch 3 (36→48) not taken.
|
15 | diGenerator.initialize(sourceFile->fileName, sourceFile->fileDir); |
34 | 831 | } | |
35 | |||
36 | 831 | std::any IRGenerator::visitEntry(const EntryNode *node) { | |
37 | // Generate IR | ||
38 |
1/2✓ Branch 0 (2→3) taken 831 times.
✗ Branch 1 (2→19) not taken.
|
831 | visitChildren(node); |
39 | |||
40 | // Generate test main if required | ||
41 |
4/4✓ Branch 0 (4→5) taken 230 times.
✓ Branch 1 (4→7) taken 601 times.
✓ Branch 2 (5→6) taken 2 times.
✓ Branch 3 (5→7) taken 228 times.
|
831 | if (sourceFile->isMainFile && cliOptions.generateTestMain) |
42 | 2 | generateTestMain(); | |
43 | |||
44 | // Execute deferred VTable initializations | ||
45 |
2/2✓ Branch 0 (13→9) taken 293 times.
✓ Branch 1 (13→14) taken 831 times.
|
1124 | for (DeferredLogic &deferredVTableInit : deferredVTableInitializations) |
46 |
1/2✓ Branch 0 (10→11) taken 293 times.
✗ Branch 1 (10→20) not taken.
|
293 | deferredVTableInit.execute(); |
47 | |||
48 | // Finalize debug info generator | ||
49 | 831 | diGenerator.finalize(); | |
50 | |||
51 | // Verify module | ||
52 | 831 | verifyModule(node->codeLoc); | |
53 | |||
54 |
1/2✓ Branch 0 (16→17) taken 831 times.
✗ Branch 1 (16→21) not taken.
|
831 | return nullptr; |
55 | } | ||
56 | |||
57 | 31331 | llvm::Value *IRGenerator::insertAlloca(llvm::Type *llvmType, std::string varName) { | |
58 |
1/2✗ Branch 0 (2→3) not taken.
✓ Branch 1 (2→4) taken 31331 times.
|
31331 | if (!cliOptions.namesForIRValues) |
59 | ✗ | varName = ""; | |
60 | |||
61 |
2/2✓ Branch 0 (4→5) taken 21945 times.
✓ Branch 1 (4→12) taken 9386 times.
|
31331 | if (allocaInsertInst != nullptr) { // If there is already an alloca inst, insert right after that |
62 |
2/4✓ Branch 0 (5→6) taken 21945 times.
✗ Branch 1 (5→29) not taken.
✓ Branch 2 (6→7) taken 21945 times.
✗ Branch 3 (6→29) not taken.
|
21945 | llvm::AllocaInst *allocaInst = builder.CreateAlloca(llvmType, nullptr, varName); |
63 |
1/2✓ Branch 0 (8→9) taken 21945 times.
✗ Branch 1 (8→30) not taken.
|
21945 | allocaInst->setDebugLoc(llvm::DebugLoc()); |
64 | 21945 | allocaInst->moveAfter(allocaInsertInst); | |
65 | 21945 | allocaInsertInst = allocaInst; | |
66 | } else { // This is the first alloca inst in the current function -> insert at the entry block | ||
67 | // Save current basic block and move insert cursor to entry block of the current function | ||
68 | 9386 | llvm::BasicBlock *currentBlock = builder.GetInsertBlock(); | |
69 | 9386 | builder.SetInsertPoint(allocaInsertBlock, allocaInsertBlock->begin()); | |
70 | |||
71 | // Allocate the size of the given LLVM type | ||
72 |
2/4✓ Branch 0 (15→16) taken 9386 times.
✗ Branch 1 (15→33) not taken.
✓ Branch 2 (16→17) taken 9386 times.
✗ Branch 3 (16→33) not taken.
|
9386 | allocaInsertInst = builder.CreateAlloca(llvmType, nullptr, varName); |
73 |
1/2✓ Branch 0 (18→19) taken 9386 times.
✗ Branch 1 (18→34) not taken.
|
9386 | allocaInsertInst->setDebugLoc(llvm::DebugLoc()); |
74 | |||
75 | // Restore old basic block | ||
76 | 9386 | builder.SetInsertPoint(currentBlock); | |
77 | } | ||
78 | |||
79 | // Insert lifetime start marker | ||
80 |
1/2✗ Branch 0 (21→22) not taken.
✓ Branch 1 (21→27) taken 31331 times.
|
31331 | if (cliOptions.useLifetimeMarkers) { |
81 | ✗ | const uint64_t sizeInBytes = module->getDataLayout().getTypeAllocSize(llvmType); | |
82 | ✗ | builder.CreateLifetimeStart(allocaInsertInst, builder.getInt64(sizeInBytes)); | |
83 | } | ||
84 | |||
85 | 31331 | return allocaInsertInst; | |
86 | } | ||
87 | |||
88 | 62561 | llvm::Value *IRGenerator::insertLoad(llvm::Type *llvmType, llvm::Value *ptr, bool isVolatile, const std::string &varName) const { | |
89 |
1/2✗ Branch 0 (4→5) not taken.
✓ Branch 1 (4→6) taken 62561 times.
|
62561 | assert(ptr->getType()->isPointerTy()); |
90 |
5/14✓ Branch 0 (6→7) taken 62561 times.
✗ Branch 1 (6→8) not taken.
✓ Branch 2 (7→11) taken 62561 times.
✗ Branch 3 (7→22) not taken.
✗ Branch 4 (10→11) not taken.
✗ Branch 5 (10→22) not taken.
✓ Branch 6 (11→12) taken 62561 times.
✗ Branch 7 (11→20) not taken.
✓ Branch 8 (12→13) taken 62561 times.
✗ Branch 9 (12→20) not taken.
✗ Branch 10 (15→16) not taken.
✓ Branch 11 (15→18) taken 62561 times.
✗ Branch 12 (22→23) not taken.
✗ Branch 13 (22→25) not taken.
|
62561 | return builder.CreateLoad(llvmType, ptr, isVolatile, cliOptions.namesForIRValues ? varName : ""); |
91 | } | ||
92 | |||
93 | 32285 | void IRGenerator::insertStore(llvm::Value *val, llvm::Value *ptr, bool isVolatile) const { | |
94 |
1/2✗ Branch 0 (4→5) not taken.
✓ Branch 1 (4→6) taken 32285 times.
|
32285 | assert(ptr->getType()->isPointerTy()); |
95 | 32285 | builder.CreateStore(val, ptr, isVolatile); | |
96 | 32285 | } | |
97 | |||
98 | 16676 | llvm::Value *IRGenerator::insertInBoundsGEP(llvm::Type *type, llvm::Value *basePtr, llvm::ArrayRef<llvm::Value *> indices, | |
99 | std::string varName) const { | ||
100 |
1/2✗ Branch 0 (4→5) not taken.
✓ Branch 1 (4→6) taken 16676 times.
|
16676 | assert(basePtr->getType()->isPointerTy()); |
101 |
1/2✗ Branch 0 (7→8) not taken.
✓ Branch 1 (7→9) taken 16676 times.
|
16676 | assert(!indices.empty()); |
102 |
4/6✗ Branch 0 (10→11) not taken.
✓ Branch 1 (10→12) taken 16676 times.
✓ Branch 2 (4→5) taken 16379 times.
✓ Branch 3 (4→7) taken 14516 times.
✓ Branch 4 (6→7) taken 16379 times.
✗ Branch 5 (6→8) not taken.
|
47571 | assert(std::ranges::all_of(indices, [](const llvm::Value *index) { |
103 | const llvm::Type *indexType = index->getType(); | ||
104 | return indexType->isIntegerTy(32) || indexType->isIntegerTy(64); | ||
105 | })); | ||
106 | |||
107 |
1/2✗ Branch 0 (12→13) not taken.
✓ Branch 1 (12→14) taken 16676 times.
|
16676 | if (!cliOptions.namesForIRValues) |
108 | ✗ | varName = ""; | |
109 | |||
110 | // Insert GEP | ||
111 |
2/4✓ Branch 0 (14→15) taken 16676 times.
✗ Branch 1 (14→19) not taken.
✓ Branch 2 (15→16) taken 16676 times.
✗ Branch 3 (15→19) not taken.
|
16676 | return builder.CreateInBoundsGEP(type, basePtr, indices, varName); |
112 | } | ||
113 | |||
114 | 4739 | llvm::Value *IRGenerator::insertStructGEP(llvm::Type *type, llvm::Value *basePtr, unsigned int index, std::string varName) const { | |
115 |
1/2✗ Branch 0 (4→5) not taken.
✓ Branch 1 (4→6) taken 4739 times.
|
4739 | assert(basePtr->getType()->isPointerTy()); |
116 | |||
117 |
1/2✗ Branch 0 (6→7) not taken.
✓ Branch 1 (6→8) taken 4739 times.
|
4739 | if (!cliOptions.namesForIRValues) |
118 | ✗ | varName = ""; | |
119 | |||
120 | // If we use index 0 we can use the base pointer directly | ||
121 |
2/2✓ Branch 0 (8→9) taken 1730 times.
✓ Branch 1 (8→10) taken 3009 times.
|
4739 | if (index == 0) |
122 | 1730 | return basePtr; | |
123 | |||
124 | // Insert GEP | ||
125 |
2/4✓ Branch 0 (10→11) taken 3009 times.
✗ Branch 1 (10→15) not taken.
✓ Branch 2 (11→12) taken 3009 times.
✗ Branch 3 (11→15) not taken.
|
3009 | return builder.CreateStructGEP(type, basePtr, index, varName); |
126 | } | ||
127 | |||
128 | 36319 | llvm::Value *IRGenerator::resolveValue(const ExprNode *node) { | |
129 | // Visit the given AST node | ||
130 |
2/4✓ Branch 0 (2→3) taken 36319 times.
✗ Branch 1 (2→11) not taken.
✓ Branch 2 (3→4) taken 36319 times.
✗ Branch 3 (3→9) not taken.
|
36319 | auto exprResult = any_cast<LLVMExprResult>(visit(node)); |
131 |
1/2✓ Branch 0 (5→6) taken 36319 times.
✗ Branch 1 (5→12) not taken.
|
72638 | return resolveValue(node, exprResult); |
132 | } | ||
133 | |||
134 | 41948 | llvm::Value *IRGenerator::resolveValue(const ExprNode *node, LLVMExprResult &exprResult) const { | |
135 | 41948 | return resolveValue(node->getEvaluatedSymbolType(manIdx), exprResult); | |
136 | } | ||
137 | |||
138 | 82508 | llvm::Value *IRGenerator::resolveValue(const QualType &qualType, LLVMExprResult &exprResult) const { | |
139 | // Check if the value is already present | ||
140 |
2/2✓ Branch 0 (2→3) taken 27270 times.
✓ Branch 1 (2→4) taken 55238 times.
|
82508 | if (exprResult.value != nullptr) |
141 | 27270 | return exprResult.value; | |
142 | |||
143 | // Check if a constant is present | ||
144 |
2/2✓ Branch 0 (4→5) taken 14267 times.
✓ Branch 1 (4→7) taken 40971 times.
|
55238 | if (exprResult.constant != nullptr) { |
145 | 14267 | materializeConstant(exprResult); | |
146 | 14267 | return exprResult.value; | |
147 | } | ||
148 | |||
149 |
3/4✓ Branch 0 (7→8) taken 467 times.
✓ Branch 1 (7→10) taken 40504 times.
✗ Branch 2 (8→9) not taken.
✓ Branch 3 (8→10) taken 467 times.
|
40971 | assert(exprResult.ptr != nullptr || exprResult.refPtr != nullptr); |
150 | |||
151 | // De-reference if reference type | ||
152 |
1/2✓ Branch 0 (10→11) taken 40971 times.
✗ Branch 1 (10→51) not taken.
|
40971 | const QualType referencedType = qualType.removeReferenceWrapper(); |
153 |
4/4✓ Branch 0 (11→12) taken 471 times.
✓ Branch 1 (11→25) taken 40500 times.
✓ Branch 2 (12→13) taken 467 times.
✓ Branch 3 (12→25) taken 4 times.
|
40971 | if (exprResult.refPtr != nullptr && exprResult.ptr == nullptr) |
154 |
6/10✓ Branch 0 (15→16) taken 467 times.
✗ Branch 1 (15→41) not taken.
✓ Branch 2 (16→17) taken 467 times.
✗ Branch 3 (16→19) not taken.
✓ Branch 4 (17→18) taken 5 times.
✓ Branch 5 (17→19) taken 462 times.
✓ Branch 6 (20→21) taken 467 times.
✗ Branch 7 (20→39) not taken.
✓ Branch 8 (21→22) taken 467 times.
✗ Branch 9 (21→39) not taken.
|
934 | exprResult.ptr = insertLoad(builder.getPtrTy(), exprResult.refPtr, exprResult.entry && exprResult.entry->isVolatile); |
155 | |||
156 | // Load the value from the pointer | ||
157 |
1/2✓ Branch 0 (25→26) taken 40971 times.
✗ Branch 1 (25→51) not taken.
|
40971 | llvm::Type *valueTy = referencedType.toLLVMType(sourceFile); |
158 |
6/8✓ Branch 0 (28→29) taken 40971 times.
✗ Branch 1 (28→47) not taken.
✓ Branch 2 (29→30) taken 37767 times.
✓ Branch 3 (29→32) taken 3204 times.
✓ Branch 4 (30→31) taken 10 times.
✓ Branch 5 (30→32) taken 37757 times.
✓ Branch 6 (33→34) taken 40971 times.
✗ Branch 7 (33→45) not taken.
|
40971 | exprResult.value = insertLoad(valueTy, exprResult.ptr, exprResult.entry && exprResult.entry->isVolatile); |
159 | |||
160 | 40971 | return exprResult.value; | |
161 | } | ||
162 | |||
163 | 2504 | llvm::Value *IRGenerator::resolveAddress(const ASTNode *node) { | |
164 | // Visit the given AST node | ||
165 |
2/4✓ Branch 0 (2→3) taken 2504 times.
✗ Branch 1 (2→11) not taken.
✓ Branch 2 (3→4) taken 2504 times.
✗ Branch 3 (3→9) not taken.
|
2504 | auto exprResult = any_cast<LLVMExprResult>(visit(node)); |
166 |
1/2✓ Branch 0 (5→6) taken 2504 times.
✗ Branch 1 (5→12) not taken.
|
5008 | return resolveAddress(exprResult); |
167 | } | ||
168 | |||
169 | 18957 | llvm::Value *IRGenerator::resolveAddress(LLVMExprResult &exprResult) { | |
170 | // Check if an address is already present | ||
171 |
2/2✓ Branch 0 (2→3) taken 15886 times.
✓ Branch 1 (2→4) taken 3071 times.
|
18957 | if (exprResult.ptr != nullptr) |
172 | 15886 | return exprResult.ptr; | |
173 | |||
174 | // Check if the reference address is already present | ||
175 |
3/4✓ Branch 0 (4→5) taken 2414 times.
✓ Branch 1 (4→18) taken 657 times.
✓ Branch 2 (5→6) taken 2414 times.
✗ Branch 3 (5→18) not taken.
|
3071 | if (exprResult.refPtr != nullptr && exprResult.ptr == nullptr) { |
176 |
6/10✓ Branch 0 (8→9) taken 2414 times.
✗ Branch 1 (8→41) not taken.
✓ Branch 2 (9→10) taken 2409 times.
✓ Branch 3 (9→12) taken 5 times.
✗ Branch 4 (10→11) not taken.
✓ Branch 5 (10→12) taken 2409 times.
✓ Branch 6 (13→14) taken 2414 times.
✗ Branch 7 (13→39) not taken.
✓ Branch 8 (14→15) taken 2414 times.
✗ Branch 9 (14→39) not taken.
|
2414 | exprResult.ptr = insertLoad(builder.getPtrTy(), exprResult.refPtr, exprResult.entry && exprResult.entry->isVolatile); |
177 | 2414 | return exprResult.ptr; | |
178 | } | ||
179 | |||
180 | // If not, store the value or constant | ||
181 | 657 | materializeConstant(exprResult); | |
182 |
1/2✗ Branch 0 (19→20) not taken.
✓ Branch 1 (19→21) taken 657 times.
|
657 | assert(exprResult.value != nullptr); |
183 |
7/12✓ Branch 0 (21→22) taken 6 times.
✓ Branch 1 (21→23) taken 651 times.
✓ Branch 2 (22→26) taken 6 times.
✗ Branch 3 (22→47) not taken.
✓ Branch 4 (25→26) taken 651 times.
✗ Branch 5 (25→47) not taken.
✓ Branch 6 (27→28) taken 657 times.
✗ Branch 7 (27→45) not taken.
✓ Branch 8 (29→30) taken 651 times.
✓ Branch 9 (29→32) taken 6 times.
✗ Branch 10 (47→48) not taken.
✗ Branch 11 (47→50) not taken.
|
1308 | exprResult.ptr = insertAlloca(exprResult.value->getType(), exprResult.entry ? exprResult.entry->name : ""); |
184 |
3/4✓ Branch 0 (32→33) taken 6 times.
✓ Branch 1 (32→35) taken 651 times.
✗ Branch 2 (33→34) not taken.
✓ Branch 3 (33→35) taken 6 times.
|
657 | insertStore(exprResult.value, exprResult.ptr, exprResult.entry && exprResult.entry->isVolatile); |
185 | |||
186 | 657 | return exprResult.ptr; | |
187 | } | ||
188 | |||
189 | 2275 | llvm::Constant *IRGenerator::getDefaultValueForSymbolType(const QualType &symbolType) { // NOLINT(misc-no-recursion) | |
190 | // Double | ||
191 |
2/2✓ Branch 0 (3→4) taken 4 times.
✓ Branch 1 (3→9) taken 2271 times.
|
2275 | if (symbolType.is(TY_DOUBLE)) |
192 |
2/4✓ Branch 0 (4→5) taken 4 times.
✗ Branch 1 (4→132) not taken.
✓ Branch 2 (5→6) taken 4 times.
✗ Branch 3 (5→130) not taken.
|
4 | return llvm::ConstantFP::get(context, llvm::APFloat(0.0)); |
193 | |||
194 | // Int | ||
195 |
2/2✓ Branch 0 (10→11) taken 309 times.
✓ Branch 1 (10→13) taken 1962 times.
|
2271 | if (symbolType.is(TY_INT)) |
196 | 309 | return builder.getInt32(0); | |
197 | |||
198 | // Short | ||
199 |
2/2✓ Branch 0 (14→15) taken 12 times.
✓ Branch 1 (14→17) taken 1950 times.
|
1962 | if (symbolType.is(TY_SHORT)) |
200 | 12 | return builder.getInt16(0); | |
201 | |||
202 | // Long | ||
203 |
2/2✓ Branch 0 (18→19) taken 858 times.
✓ Branch 1 (18→21) taken 1092 times.
|
1950 | if (symbolType.is(TY_LONG)) |
204 | 858 | return builder.getInt64(0); | |
205 | |||
206 | // Byte or char | ||
207 |
3/4✓ Branch 0 (21→22) taken 1092 times.
✗ Branch 1 (21→133) not taken.
✓ Branch 2 (22→23) taken 20 times.
✓ Branch 3 (22→25) taken 1072 times.
|
1092 | if (symbolType.isOneOf({TY_BYTE, TY_CHAR})) |
208 | 20 | return builder.getInt8(0); | |
209 | |||
210 | // String | ||
211 |
2/2✓ Branch 0 (26→27) taken 321 times.
✓ Branch 1 (26→35) taken 751 times.
|
1072 | if (symbolType.is(TY_STRING)) { |
212 |
3/6✓ Branch 0 (27→28) taken 321 times.
✗ Branch 1 (27→135) not taken.
✓ Branch 2 (28→29) taken 321 times.
✗ Branch 3 (28→134) not taken.
✓ Branch 4 (29→30) taken 321 times.
✗ Branch 5 (29→134) not taken.
|
321 | llvm::GlobalVariable *globalString = builder.CreateGlobalString("", ""); |
213 |
1/2✓ Branch 0 (30→31) taken 321 times.
✗ Branch 1 (30→34) not taken.
|
321 | if (cliOptions.comparableOutput) |
214 |
2/4✓ Branch 0 (31→32) taken 321 times.
✗ Branch 1 (31→136) not taken.
✓ Branch 2 (32→33) taken 321 times.
✗ Branch 3 (32→136) not taken.
|
321 | globalString->setAlignment(llvm::Align(4)); |
215 | 321 | return globalString; | |
216 | } | ||
217 | |||
218 | // Bool | ||
219 |
2/2✓ Branch 0 (36→37) taken 31 times.
✓ Branch 1 (36→39) taken 720 times.
|
751 | if (symbolType.is(TY_BOOL)) |
220 | 31 | return builder.getFalse(); | |
221 | |||
222 | // Pointer or reference | ||
223 |
3/4✓ Branch 0 (39→40) taken 720 times.
✗ Branch 1 (39→137) not taken.
✓ Branch 2 (40→41) taken 661 times.
✓ Branch 3 (40→44) taken 59 times.
|
720 | if (symbolType.isOneOf({TY_PTR, TY_REF})) |
224 | 661 | return llvm::Constant::getNullValue(builder.getPtrTy()); | |
225 | |||
226 | // Array | ||
227 |
2/2✓ Branch 0 (45→46) taken 15 times.
✓ Branch 1 (45→61) taken 44 times.
|
59 | if (symbolType.isArray()) { |
228 | // Get array size | ||
229 |
1/2✓ Branch 0 (46→47) taken 15 times.
✗ Branch 1 (46→146) not taken.
|
15 | const size_t arraySize = symbolType.getArraySize(); |
230 | |||
231 | // Get default value for item | ||
232 |
2/4✓ Branch 0 (47→48) taken 15 times.
✗ Branch 1 (47→138) not taken.
✓ Branch 2 (48→49) taken 15 times.
✗ Branch 3 (48→138) not taken.
|
15 | llvm::Constant *defaultItemValue = getDefaultValueForSymbolType(symbolType.getContained()); |
233 | |||
234 | // Retrieve array and item type | ||
235 |
2/4✓ Branch 0 (49→50) taken 15 times.
✗ Branch 1 (49→139) not taken.
✓ Branch 2 (50→51) taken 15 times.
✗ Branch 3 (50→139) not taken.
|
15 | llvm::Type *itemType = symbolType.getContained().toLLVMType(sourceFile); |
236 |
1/2✓ Branch 0 (51→52) taken 15 times.
✗ Branch 1 (51→146) not taken.
|
15 | llvm::ArrayType *arrayType = llvm::ArrayType::get(itemType, arraySize); |
237 | |||
238 | // Create a constant array with n times the default value | ||
239 |
1/2✓ Branch 0 (54→55) taken 15 times.
✗ Branch 1 (54→140) not taken.
|
15 | const std::vector itemConstants(arraySize, defaultItemValue); |
240 |
1/2✓ Branch 0 (57→58) taken 15 times.
✗ Branch 1 (57→143) not taken.
|
15 | return llvm::ConstantArray::get(arrayType, itemConstants); |
241 | 15 | } | |
242 | |||
243 | // Function or procedure | ||
244 |
3/4✓ Branch 0 (61→62) taken 44 times.
✗ Branch 1 (61→147) not taken.
✓ Branch 2 (62→63) taken 14 times.
✓ Branch 3 (62→75) taken 30 times.
|
44 | if (symbolType.isOneOf({TY_FUNCTION, TY_PROCEDURE})) { |
245 |
2/2✓ Branch 0 (63→64) taken 7 times.
✓ Branch 1 (63→69) taken 7 times.
|
14 | if (!llvmTypes.fatPtrType) |
246 |
3/6✓ Branch 0 (64→65) taken 7 times.
✗ Branch 1 (64→148) not taken.
✓ Branch 2 (65→66) taken 7 times.
✗ Branch 3 (65→148) not taken.
✓ Branch 4 (67→68) taken 7 times.
✗ Branch 5 (67→148) not taken.
|
7 | llvmTypes.fatPtrType = llvm::StructType::get(context, {builder.getPtrTy(), builder.getPtrTy()}); |
247 | |||
248 |
2/4✓ Branch 0 (69→70) taken 14 times.
✗ Branch 1 (69→150) not taken.
✓ Branch 2 (70→71) taken 14 times.
✗ Branch 3 (70→150) not taken.
|
14 | llvm::Constant *ptrDefaultValue = getDefaultValueForSymbolType(QualType(TY_PTR)); |
249 |
1/2✓ Branch 0 (72→73) taken 14 times.
✗ Branch 1 (72→151) not taken.
|
14 | return llvm::ConstantStruct::get(llvmTypes.fatPtrType, {ptrDefaultValue, ptrDefaultValue}); |
250 | } | ||
251 | |||
252 | // Struct | ||
253 |
2/2✓ Branch 0 (76→77) taken 29 times.
✓ Branch 1 (76→114) taken 1 times.
|
30 | if (symbolType.is(TY_STRUCT)) { |
254 | // Retrieve field count | ||
255 |
1/2✓ Branch 0 (77→78) taken 29 times.
✗ Branch 1 (77→158) not taken.
|
29 | Scope *structScope = symbolType.getBodyScope(); |
256 |
1/2✗ Branch 0 (78→79) not taken.
✓ Branch 1 (78→80) taken 29 times.
|
29 | assert(structScope != nullptr); |
257 |
1/2✓ Branch 0 (80→81) taken 29 times.
✗ Branch 1 (80→158) not taken.
|
29 | const size_t fieldCount = structScope->getFieldCount(); |
258 | |||
259 | // Get default values for all fields of the struct | ||
260 | 29 | std::vector<llvm::Constant *> fieldConstants; | |
261 |
1/2✓ Branch 0 (81→82) taken 29 times.
✗ Branch 1 (81→156) not taken.
|
29 | fieldConstants.reserve(fieldCount); |
262 | |||
263 | // Add default value for each struct field | ||
264 |
2/2✓ Branch 0 (107→83) taken 66 times.
✓ Branch 1 (107→108) taken 29 times.
|
95 | for (size_t i = 0; i < fieldCount; i++) { |
265 | // Get entry of the field | ||
266 |
1/2✗ Branch 0 (83→84) not taken.
✓ Branch 1 (83→85) taken 66 times.
|
66 | const SymbolTableEntry *fieldEntry = structScope->lookupField(i); |
267 |
3/6✓ Branch 0 (88→89) taken 66 times.
✗ Branch 1 (88→92) not taken.
✓ Branch 2 (89→90) taken 66 times.
✗ Branch 3 (89→154) not taken.
✓ Branch 4 (90→91) taken 66 times.
✗ Branch 5 (90→92) not taken.
|
66 | assert(fieldEntry != nullptr && fieldEntry->isField()); |
268 | |||
269 | // Retrieve default field value | ||
270 | llvm::Constant *defaultFieldValue; | ||
271 |
4/6✓ Branch 0 (93→94) taken 66 times.
✗ Branch 1 (93→95) not taken.
✓ Branch 2 (96→97) taken 66 times.
✗ Branch 3 (96→102) not taken.
✓ Branch 4 (97→98) taken 5 times.
✓ Branch 5 (97→102) taken 61 times.
|
66 | if (const auto fieldNode = dynamic_cast<FieldNode *>(fieldEntry->declNode); fieldNode && fieldNode->defaultValue) |
272 |
3/6✓ Branch 0 (98→99) taken 5 times.
✗ Branch 1 (98→154) not taken.
✓ Branch 2 (99→100) taken 5 times.
✗ Branch 3 (99→153) not taken.
✓ Branch 4 (100→101) taken 5 times.
✗ Branch 5 (100→153) not taken.
|
5 | defaultFieldValue = getConst(fieldNode->defaultValue->getCompileTimeValue(), fieldEntry->getQualType(), fieldNode); |
273 | else | ||
274 |
2/4✓ Branch 0 (102→103) taken 61 times.
✗ Branch 1 (102→154) not taken.
✓ Branch 2 (103→104) taken 61 times.
✗ Branch 3 (103→154) not taken.
|
61 | defaultFieldValue = getDefaultValueForSymbolType(fieldEntry->getQualType()); |
275 | |||
276 |
1/2✓ Branch 0 (105→106) taken 66 times.
✗ Branch 1 (105→154) not taken.
|
66 | fieldConstants.push_back(defaultFieldValue); |
277 | } | ||
278 | |||
279 |
1/2✓ Branch 0 (108→109) taken 29 times.
✗ Branch 1 (108→156) not taken.
|
29 | const auto structType = reinterpret_cast<llvm::StructType *>(symbolType.toLLVMType(sourceFile)); |
280 |
1/2✓ Branch 0 (110→111) taken 29 times.
✗ Branch 1 (110→155) not taken.
|
29 | return llvm::ConstantStruct::get(structType, fieldConstants); |
281 | 29 | } | |
282 | |||
283 | // Interface | ||
284 |
1/2✓ Branch 0 (115→116) taken 1 times.
✗ Branch 1 (115→121) not taken.
|
1 | if (symbolType.is(TY_INTERFACE)) { |
285 | 1 | const auto structType = reinterpret_cast<llvm::StructType *>(symbolType.toLLVMType(sourceFile)); | |
286 | 1 | return llvm::ConstantStruct::get(structType, llvm::Constant::getNullValue(builder.getPtrTy())); | |
287 | } | ||
288 | |||
289 | − | throw CompilerError(INTERNAL_ERROR, "Cannot determine default value for symbol type"); // GCOV_EXCL_LINE | |
290 | } | ||
291 | |||
292 | 14589 | llvm::Constant *IRGenerator::getConst(const CompileTimeValue &compileTimeValue, const QualType &type, const ASTNode *node) const { | |
293 |
2/2✓ Branch 0 (3→4) taken 379 times.
✓ Branch 1 (3→9) taken 14210 times.
|
14589 | if (type.is(TY_DOUBLE)) |
294 |
2/4✓ Branch 0 (4→5) taken 379 times.
✗ Branch 1 (4→56) not taken.
✓ Branch 2 (5→6) taken 379 times.
✗ Branch 3 (5→54) not taken.
|
379 | return llvm::ConstantFP::get(context, llvm::APFloat(compileTimeValue.doubleValue)); |
295 | |||
296 |
2/2✓ Branch 0 (10→11) taken 2931 times.
✓ Branch 1 (10→13) taken 11279 times.
|
14210 | if (type.is(TY_INT)) |
297 | 2931 | return builder.getInt32(compileTimeValue.intValue); | |
298 | |||
299 |
2/2✓ Branch 0 (14→15) taken 576 times.
✓ Branch 1 (14→17) taken 10703 times.
|
11279 | if (type.is(TY_SHORT)) |
300 | 576 | return builder.getInt16(compileTimeValue.shortValue); | |
301 | |||
302 |
2/2✓ Branch 0 (18→19) taken 5275 times.
✓ Branch 1 (18→21) taken 5428 times.
|
10703 | if (type.is(TY_LONG)) |
303 | 5275 | return builder.getInt64(compileTimeValue.longValue); | |
304 | |||
305 |
3/4✓ Branch 0 (21→22) taken 5428 times.
✗ Branch 1 (21→57) not taken.
✓ Branch 2 (22→23) taken 2147 times.
✓ Branch 3 (22→25) taken 3281 times.
|
5428 | if (type.isOneOf({TY_BYTE, TY_CHAR})) |
306 | 2147 | return builder.getInt8(compileTimeValue.charValue); | |
307 | |||
308 |
2/2✓ Branch 0 (26→27) taken 2014 times.
✓ Branch 1 (26→36) taken 1267 times.
|
3281 | if (type.is(TY_STRING)) { |
309 | 2014 | const std::string &stringValue = resourceManager.compileTimeStringValues.at(compileTimeValue.stringValueOffset); | |
310 |
2/4✓ Branch 0 (30→31) taken 2014 times.
✗ Branch 1 (30→60) not taken.
✓ Branch 2 (31→32) taken 2014 times.
✗ Branch 3 (31→58) not taken.
|
6042 | return createGlobalStringConst(ANON_GLOBAL_STRING_NAME, stringValue, node->codeLoc); |
311 | } | ||
312 | |||
313 |
1/2✓ Branch 0 (37→38) taken 1267 times.
✗ Branch 1 (37→40) not taken.
|
1267 | if (type.is(TY_BOOL)) |
314 | 1267 | return builder.getInt1(compileTimeValue.boolValue); | |
315 | |||
316 | ✗ | if (type.is(TY_PTR)) | |
317 | ✗ | return llvm::Constant::getNullValue(builder.getPtrTy()); | |
318 | |||
319 | − | throw CompilerError(UNHANDLED_BRANCH, "Constant fall-through"); // GCOV_EXCL_LINE | |
320 | } | ||
321 | |||
322 | 28405 | llvm::BasicBlock *IRGenerator::createBlock(const std::string &blockName /*=""*/) const { | |
323 |
2/4✓ Branch 0 (2→3) taken 28405 times.
✗ Branch 1 (2→7) not taken.
✓ Branch 2 (3→4) taken 28405 times.
✗ Branch 3 (3→7) not taken.
|
28405 | return llvm::BasicBlock::Create(context, blockName); |
324 | } | ||
325 | |||
326 | 28405 | void IRGenerator::switchToBlock(llvm::BasicBlock *block, llvm::Function *parentFct /*=nullptr*/) { | |
327 |
1/2✗ Branch 0 (3→4) not taken.
✓ Branch 1 (3→5) taken 28405 times.
|
28405 | assert(block->getParent() == nullptr); // Ensure that the block was not added to a function already |
328 | // If no parent function were passed, use the current function | ||
329 |
2/2✓ Branch 0 (5→6) taken 18981 times.
✓ Branch 1 (5→8) taken 9424 times.
|
28405 | if (!parentFct) |
330 | 18981 | parentFct = builder.GetInsertBlock()->getParent(); | |
331 | // Append block to current function | ||
332 | 28405 | parentFct->insert(parentFct->end(), block); | |
333 | // Set insert point to the block | ||
334 | 28405 | builder.SetInsertPoint(block); | |
335 | 28405 | blockAlreadyTerminated = false; | |
336 | 28405 | } | |
337 | |||
338 | 8932 | void IRGenerator::terminateBlock(const StmtLstNode *stmtLstNode) { | |
339 | 8932 | diGenerator.setSourceLocation(stmtLstNode->closingBraceCodeLoc); | |
340 | 8932 | generateScopeCleanup(stmtLstNode); | |
341 | 8932 | blockAlreadyTerminated = true; | |
342 | 8932 | } | |
343 | |||
344 | 10822 | void IRGenerator::insertJump(llvm::BasicBlock *targetBlock) { | |
345 |
2/2✓ Branch 0 (2→3) taken 3116 times.
✓ Branch 1 (2→4) taken 7706 times.
|
10822 | if (blockAlreadyTerminated) |
346 | 3116 | return; | |
347 | 7706 | builder.CreateBr(targetBlock); | |
348 | 7706 | blockAlreadyTerminated = true; | |
349 | } | ||
350 | |||
351 | 7839 | void IRGenerator::insertCondJump(llvm::Value *condition, llvm::BasicBlock *trueBlock, llvm::BasicBlock *falseBlock, | |
352 | Likeliness likeliness /*=UNSPECIFIED*/) { | ||
353 |
1/2✗ Branch 0 (2→3) not taken.
✓ Branch 1 (2→4) taken 7839 times.
|
7839 | if (blockAlreadyTerminated) |
354 | ✗ | return; | |
355 | 7839 | llvm::BranchInst *jumpInst = builder.CreateCondBr(condition, trueBlock, falseBlock); | |
356 | 7839 | blockAlreadyTerminated = true; | |
357 | |||
358 |
2/2✓ Branch 0 (5→6) taken 739 times.
✓ Branch 1 (5→22) taken 7100 times.
|
7839 | if (likeliness != UNSPECIFIED) { |
359 | 739 | const bool likely = likeliness == LIKELY; | |
360 | 739 | llvm::Metadata *name = llvm::MDString::get(context, "branch_weights"); | |
361 |
1/2✓ Branch 0 (7→8) taken 739 times.
✗ Branch 1 (7→9) not taken.
|
739 | llvm::Metadata *trueBranchWeight = llvm::ConstantAsMetadata::get(builder.getInt32(likely ? 2000 : 1)); |
362 |
1/2✓ Branch 0 (12→13) taken 739 times.
✗ Branch 1 (12→14) not taken.
|
739 | llvm::Metadata *falseBranchWeight = llvm::ConstantAsMetadata::get(builder.getInt32(likely ? 1 : 2000)); |
363 |
1/2✓ Branch 0 (18→19) taken 739 times.
✗ Branch 1 (18→23) not taken.
|
739 | const auto profMetadata = llvm::MDNode::get(context, {name, trueBranchWeight, falseBranchWeight}); |
364 |
2/4✓ Branch 0 (19→20) taken 739 times.
✗ Branch 1 (19→25) not taken.
✓ Branch 2 (20→21) taken 739 times.
✗ Branch 3 (20→25) not taken.
|
739 | jumpInst->setMetadata("prof", profMetadata); |
365 | } | ||
366 | } | ||
367 | |||
368 | 9424 | void IRGenerator::verifyFunction(const llvm::Function *fct, const CodeLoc &codeLoc) const { | |
369 | // Skip the verifying step if the verifier was disabled manually or debug info is emitted | ||
370 |
3/4✓ Branch 0 (2→3) taken 9424 times.
✗ Branch 1 (2→4) not taken.
✓ Branch 2 (3→4) taken 173 times.
✓ Branch 3 (3→5) taken 9251 times.
|
9424 | if (cliOptions.disableVerifier || cliOptions.generateDebugInfo) |
371 | 173 | return; | |
372 | |||
373 | // Verify function | ||
374 | 9251 | std::string output; | |
375 |
1/2✓ Branch 0 (6→7) taken 9251 times.
✗ Branch 1 (6→21) not taken.
|
9251 | llvm::raw_string_ostream oss(output); |
376 | − | if (llvm::verifyFunction(*fct, &oss)) // LCOV_EXCL_LINE | |
377 | − | throw CompilerError(codeLoc, INVALID_FUNCTION, output); // LCOV_EXCL_LINE | |
378 | 9251 | } | |
379 | |||
380 | 831 | void IRGenerator::verifyModule(const CodeLoc &codeLoc) const { | |
381 | // Skip the verifying step if the verifier was disabled manually or debug info is emitted | ||
382 |
3/4✓ Branch 0 (2→3) taken 831 times.
✗ Branch 1 (2→4) not taken.
✓ Branch 2 (3→4) taken 15 times.
✓ Branch 3 (3→5) taken 816 times.
|
831 | if (cliOptions.disableVerifier || cliOptions.generateDebugInfo) |
383 | 15 | return; | |
384 | |||
385 | // Verify module | ||
386 | 816 | std::string output; | |
387 |
1/2✓ Branch 0 (6→7) taken 816 times.
✗ Branch 1 (6→21) not taken.
|
816 | llvm::raw_string_ostream oss(output); |
388 | − | if (llvm::verifyModule(*module, &oss)) // LCOV_EXCL_LINE | |
389 | − | throw CompilerError(codeLoc, INVALID_MODULE, output); // LCOV_EXCL_LINE | |
390 | 816 | } | |
391 | |||
392 | 4841 | LLVMExprResult IRGenerator::doAssignment(const ASTNode *lhsNode, const ExprNode *rhsNode, const ASTNode *node) { | |
393 | // Get entry of left side | ||
394 |
2/4✓ Branch 0 (2→3) taken 4841 times.
✗ Branch 1 (2→17) not taken.
✓ Branch 2 (3→4) taken 4841 times.
✗ Branch 3 (3→15) not taken.
|
4841 | auto [value, constant, ptr, refPtr, entry, _] = std::any_cast<LLVMExprResult>(visit(lhsNode)); |
395 |
6/8✓ Branch 0 (5→6) taken 4115 times.
✓ Branch 1 (5→10) taken 726 times.
✓ Branch 2 (6→7) taken 4115 times.
✗ Branch 3 (6→18) not taken.
✓ Branch 4 (7→8) taken 4115 times.
✗ Branch 5 (7→18) not taken.
✓ Branch 6 (8→9) taken 187 times.
✓ Branch 7 (8→10) taken 3928 times.
|
4841 | llvm::Value *lhsAddress = entry != nullptr && entry->getQualType().isRef() ? refPtr : ptr; |
396 |
1/2✓ Branch 0 (11→12) taken 4841 times.
✗ Branch 1 (11→18) not taken.
|
9682 | return doAssignment(lhsAddress, entry, rhsNode, node); |
397 | } | ||
398 | |||
399 | 11550 | LLVMExprResult IRGenerator::doAssignment(llvm::Value *lhsAddress, SymbolTableEntry *lhsEntry, const ExprNode *rhsNode, | |
400 | const ASTNode *node, bool isDecl) { | ||
401 | // Get symbol type of right side | ||
402 |
1/2✓ Branch 0 (2→3) taken 11550 times.
✗ Branch 1 (2→13) not taken.
|
11550 | const QualType &rhsSType = rhsNode->getEvaluatedSymbolType(manIdx); |
403 |
2/4✓ Branch 0 (3→4) taken 11550 times.
✗ Branch 1 (3→12) not taken.
✓ Branch 2 (4→5) taken 11550 times.
✗ Branch 3 (4→10) not taken.
|
11550 | auto rhs = std::any_cast<LLVMExprResult>(visit(rhsNode)); |
404 |
1/2✓ Branch 0 (6→7) taken 11550 times.
✗ Branch 1 (6→13) not taken.
|
23100 | return doAssignment(lhsAddress, lhsEntry, rhs, rhsSType, node, isDecl); |
405 | } | ||
406 | |||
407 | 11655 | LLVMExprResult IRGenerator::doAssignment(llvm::Value *lhsAddress, SymbolTableEntry *lhsEntry, LLVMExprResult &rhs, | |
408 | const QualType &rhsSType, const ASTNode *node, bool isDecl) { | ||
409 | // Deduce some information about the assignment | ||
410 |
4/4✓ Branch 0 (2→3) taken 10929 times.
✓ Branch 1 (2→7) taken 726 times.
✓ Branch 2 (5→6) taken 389 times.
✓ Branch 3 (5→7) taken 10540 times.
|
11655 | const bool isRefAssign = lhsEntry != nullptr && lhsEntry->getQualType().isRef(); |
411 |
8/10✓ Branch 0 (8→9) taken 11266 times.
✓ Branch 1 (8→15) taken 389 times.
✓ Branch 2 (9→10) taken 11266 times.
✗ Branch 3 (9→179) not taken.
✓ Branch 4 (10→11) taken 11266 times.
✗ Branch 5 (10→179) not taken.
✓ Branch 6 (11→12) taken 1268 times.
✓ Branch 7 (11→15) taken 9998 times.
✓ Branch 8 (13→14) taken 160 times.
✓ Branch 9 (13→15) taken 1108 times.
|
11655 | const bool needsCopy = !isRefAssign && rhsSType.removeReferenceWrapper().is(TY_STRUCT) && !rhs.isTemporary(); |
412 | |||
413 |
2/2✓ Branch 0 (16→17) taken 389 times.
✓ Branch 1 (16→57) taken 11266 times.
|
11655 | if (isRefAssign) { |
414 |
1/2✗ Branch 0 (17→18) not taken.
✓ Branch 1 (17→19) taken 389 times.
|
389 | assert(lhsEntry != nullptr); |
415 |
2/2✓ Branch 0 (19→20) taken 202 times.
✓ Branch 1 (19→33) taken 187 times.
|
389 | if (isDecl) { // Reference gets initially assigned |
416 | // Get address of right side | ||
417 | 202 | llvm::Value *rhsAddress = resolveAddress(rhs); | |
418 |
1/2✗ Branch 0 (21→22) not taken.
✓ Branch 1 (21→23) taken 202 times.
|
202 | assert(rhsAddress != nullptr); |
419 | |||
420 | // Store lhs pointer to rhs | ||
421 |
2/4✓ Branch 0 (26→27) taken 202 times.
✗ Branch 1 (26→180) not taken.
✓ Branch 2 (27→28) taken 202 times.
✗ Branch 3 (27→180) not taken.
|
202 | llvm::Value *refAddress = insertAlloca(builder.getPtrTy()); |
422 | 202 | lhsEntry->updateAddress(refAddress); | |
423 | 202 | insertStore(rhsAddress, refAddress); | |
424 | |||
425 | 202 | return LLVMExprResult{.value = rhsAddress, .ptr = refAddress, .entry = lhsEntry}; | |
426 | } | ||
427 | |||
428 | // Reference to reference assignment (only for struct fields that are not initialized yet) | ||
429 | // These are only allowed inside a ctor body. In other cases, the value of the reference gets assigned, not the ref itself. | ||
430 |
6/8✓ Branch 0 (33→34) taken 129 times.
✓ Branch 1 (33→40) taken 58 times.
✓ Branch 2 (35→36) taken 129 times.
✗ Branch 3 (35→40) not taken.
✓ Branch 4 (36→37) taken 125 times.
✓ Branch 5 (36→40) taken 4 times.
✓ Branch 6 (38→39) taken 125 times.
✗ Branch 7 (38→40) not taken.
|
187 | const bool isInitialFieldRefAssign = isInCtorBody && rhsSType.isRef() && rhs.entry && lhsEntry->isField(); |
431 | // Assigning the result variable | ||
432 | 187 | const bool isReturnValAssign = lhsEntry->name == RETURN_VARIABLE_NAME; | |
433 |
4/4✓ Branch 0 (42→43) taken 62 times.
✓ Branch 1 (42→44) taken 125 times.
✓ Branch 2 (43→44) taken 2 times.
✓ Branch 3 (43→49) taken 60 times.
|
187 | if (isInitialFieldRefAssign || isReturnValAssign) { |
434 | // Get address of right side | ||
435 | 127 | llvm::Value *referencedAddress = resolveAddress(rhs); | |
436 |
1/2✗ Branch 0 (45→46) not taken.
✓ Branch 1 (45→47) taken 127 times.
|
127 | assert(referencedAddress != nullptr); |
437 | |||
438 | // Store the rhs* to the lhs** | ||
439 | 127 | insertStore(referencedAddress, lhsAddress); | |
440 | |||
441 | 127 | return LLVMExprResult{.value = referencedAddress, .ptr = lhsAddress, .entry = lhsEntry}; | |
442 | } | ||
443 | |||
444 | // Load referenced address | ||
445 |
3/6✓ Branch 0 (51→52) taken 60 times.
✗ Branch 1 (51→188) not taken.
✓ Branch 2 (52→53) taken 60 times.
✗ Branch 3 (52→186) not taken.
✓ Branch 4 (53→54) taken 60 times.
✗ Branch 5 (53→186) not taken.
|
120 | lhsAddress = insertLoad(builder.getPtrTy(), lhsAddress); |
446 | } | ||
447 | |||
448 | // Check if we need to copy the rhs to the lhs. This happens for structs | ||
449 |
2/2✓ Branch 0 (57→58) taken 160 times.
✓ Branch 1 (57→124) taken 11166 times.
|
11326 | if (needsCopy) { |
450 | // Get address of right side | ||
451 |
1/2✓ Branch 0 (58→59) taken 160 times.
✗ Branch 1 (58→239) not taken.
|
160 | llvm::Value *rhsAddress = resolveAddress(rhs); |
452 |
1/2✗ Branch 0 (59→60) not taken.
✓ Branch 1 (59→61) taken 160 times.
|
160 | assert(rhsAddress != nullptr); |
453 | |||
454 | // Allocate new memory if the lhs address does not exist | ||
455 |
2/2✓ Branch 0 (61→62) taken 4 times.
✓ Branch 1 (61→73) taken 156 times.
|
160 | if (!lhsAddress) { |
456 |
1/2✗ Branch 0 (62→63) not taken.
✓ Branch 1 (62→64) taken 4 times.
|
4 | assert(lhsEntry != nullptr); |
457 |
3/6✓ Branch 0 (67→68) taken 4 times.
✗ Branch 1 (67→192) not taken.
✓ Branch 2 (68→69) taken 4 times.
✗ Branch 3 (68→192) not taken.
✓ Branch 4 (69→70) taken 4 times.
✗ Branch 5 (69→192) not taken.
|
4 | lhsAddress = insertAlloca(lhsEntry->getQualType().toLLVMType(sourceFile)); |
458 |
1/2✓ Branch 0 (72→73) taken 4 times.
✗ Branch 1 (72→239) not taken.
|
4 | lhsEntry->updateAddress(lhsAddress); |
459 | } | ||
460 | |||
461 | // Check if we have a copy ctor | ||
462 |
2/4✓ Branch 0 (73→74) taken 160 times.
✗ Branch 1 (73→198) not taken.
✓ Branch 2 (74→75) taken 160 times.
✗ Branch 3 (74→198) not taken.
|
160 | const QualType rhsSTypeNonRef = rhsSType.removeReferenceWrapper().toNonConst(); |
463 |
1/2✓ Branch 0 (75→76) taken 160 times.
✗ Branch 1 (75→239) not taken.
|
160 | Scope *structScope = rhsSTypeNonRef.getBodyScope(); |
464 |
2/4✓ Branch 0 (76→77) taken 160 times.
✗ Branch 1 (76→203) not taken.
✓ Branch 2 (81→82) taken 160 times.
✗ Branch 3 (81→199) not taken.
|
480 | const ArgList args = {{rhsSTypeNonRef.toConstRef(node), rhs.isTemporary()}}; |
465 |
2/4✓ Branch 0 (85→86) taken 160 times.
✗ Branch 1 (85→207) not taken.
✓ Branch 2 (86→87) taken 160 times.
✗ Branch 3 (86→205) not taken.
|
160 | const Function *copyCtor = FunctionManager::lookup(structScope, CTOR_FUNCTION_NAME, rhsSTypeNonRef, args, true); |
466 |
2/2✓ Branch 0 (89→90) taken 69 times.
✓ Branch 1 (89→97) taken 91 times.
|
160 | if (copyCtor != nullptr) { |
467 | // Call copy ctor | ||
468 |
2/4✓ Branch 0 (92→93) taken 69 times.
✗ Branch 1 (92→213) not taken.
✓ Branch 2 (93→94) taken 69 times.
✗ Branch 3 (93→211) not taken.
|
207 | generateCtorOrDtorCall(lhsAddress, copyCtor, {rhsAddress}); |
469 |
2/4✓ Branch 0 (97→98) taken 91 times.
✗ Branch 1 (97→237) not taken.
✓ Branch 2 (98→99) taken 91 times.
✗ Branch 3 (98→115) not taken.
|
91 | } else if (rhsSTypeNonRef.isTriviallyCopyable(node)) { |
470 | // Create shallow copy | ||
471 |
1/2✓ Branch 0 (99→100) taken 91 times.
✗ Branch 1 (99→225) not taken.
|
91 | llvm::Type *rhsType = rhsSTypeNonRef.toLLVMType(sourceFile); |
472 |
6/10✓ Branch 0 (100→101) taken 86 times.
✓ Branch 1 (100→102) taken 5 times.
✓ Branch 2 (101→105) taken 86 times.
✗ Branch 3 (101→218) not taken.
✓ Branch 4 (104→105) taken 5 times.
✗ Branch 5 (104→218) not taken.
✓ Branch 6 (105→106) taken 5 times.
✓ Branch 7 (105→108) taken 86 times.
✗ Branch 8 (218→219) not taken.
✗ Branch 9 (218→221) not taken.
|
96 | const std::string copyName = lhsEntry ? lhsEntry->name : ""; |
473 |
4/6✓ Branch 0 (108→109) taken 86 times.
✓ Branch 1 (108→111) taken 5 times.
✗ Branch 2 (109→110) not taken.
✓ Branch 3 (109→111) taken 86 times.
✓ Branch 4 (112→113) taken 91 times.
✗ Branch 5 (112→223) not taken.
|
91 | generateShallowCopy(rhsAddress, rhsType, lhsAddress, lhsEntry && lhsEntry->isVolatile); |
474 | 91 | } else { | |
475 | ✗ | const std::string structName = rhsSTypeNonRef.getName(); | |
476 | ✗ | const std::string msg = "Cannot copy struct '" + structName + "', as it is not trivially copyable and has no copy ctor"; | |
477 | ✗ | throw SemanticError(node, COPY_CTOR_REQUIRED, msg); | |
478 | ✗ | } | |
479 | 160 | return LLVMExprResult{.ptr = lhsAddress, .entry = lhsEntry}; | |
480 | 160 | } | |
481 | |||
482 |
7/8✓ Branch 0 (124→125) taken 6608 times.
✓ Branch 1 (124→130) taken 4558 times.
✓ Branch 2 (126→127) taken 829 times.
✓ Branch 3 (126→130) taken 5779 times.
✓ Branch 4 (128→129) taken 829 times.
✗ Branch 5 (128→130) not taken.
✓ Branch 6 (131→132) taken 829 times.
✓ Branch 7 (131→137) taken 10337 times.
|
11166 | if (isDecl && rhsSType.is(TY_STRUCT) && rhs.isTemporary()) { |
483 |
1/2✗ Branch 0 (132→133) not taken.
✓ Branch 1 (132→134) taken 829 times.
|
829 | assert(lhsEntry != nullptr); |
484 | // Directly set the address to the lhs entry (temp stealing) | ||
485 | 829 | llvm::Value *rhsAddress = resolveAddress(rhs); | |
486 | 829 | lhsEntry->updateAddress(rhsAddress); | |
487 | 829 | rhs.entry = lhsEntry; | |
488 | 829 | return rhs; | |
489 | } | ||
490 | |||
491 | // Allocate new memory if the lhs address does not exist | ||
492 |
2/2✓ Branch 0 (137→138) taken 5748 times.
✓ Branch 1 (137→149) taken 4589 times.
|
10337 | if (!lhsAddress) { |
493 |
1/2✗ Branch 0 (138→139) not taken.
✓ Branch 1 (138→140) taken 5748 times.
|
5748 | assert(lhsEntry != nullptr); |
494 |
3/6✓ Branch 0 (143→144) taken 5748 times.
✗ Branch 1 (143→240) not taken.
✓ Branch 2 (144→145) taken 5748 times.
✗ Branch 3 (144→240) not taken.
✓ Branch 4 (145→146) taken 5748 times.
✗ Branch 5 (145→240) not taken.
|
5748 | lhsAddress = insertAlloca(lhsEntry->getQualType().toLLVMType(sourceFile)); |
495 | 5748 | lhsEntry->updateAddress(lhsAddress); | |
496 | } | ||
497 | |||
498 | // Check if we try to assign an array by value to a pointer. Here we have to store the address of the first element to the lhs | ||
499 |
10/10✓ Branch 0 (149→150) taken 9629 times.
✓ Branch 1 (149→158) taken 708 times.
✓ Branch 2 (152→153) taken 1853 times.
✓ Branch 3 (152→158) taken 7776 times.
✓ Branch 4 (154→155) taken 5 times.
✓ Branch 5 (154→158) taken 1848 times.
✓ Branch 6 (156→157) taken 1 times.
✓ Branch 7 (156→158) taken 4 times.
✓ Branch 8 (159→160) taken 1 times.
✓ Branch 9 (159→175) taken 10336 times.
|
10337 | if (lhsEntry && lhsEntry->getQualType().isPtr() && rhsSType.isArray() && rhsSType.getArraySize() != ARRAY_SIZE_UNKNOWN) { |
500 | // Get address of right side | ||
501 |
1/2✓ Branch 0 (160→161) taken 1 times.
✗ Branch 1 (160→253) not taken.
|
1 | llvm::Value *rhsAddress = resolveAddress(rhs); |
502 |
1/2✗ Branch 0 (161→162) not taken.
✓ Branch 1 (161→163) taken 1 times.
|
1 | assert(rhsAddress != nullptr); |
503 |
1/2✓ Branch 0 (163→164) taken 1 times.
✗ Branch 1 (163→253) not taken.
|
1 | llvm::Type *elementTy = rhsSType.toLLVMType(sourceFile); |
504 |
2/4✓ Branch 0 (164→165) taken 1 times.
✗ Branch 1 (164→253) not taken.
✓ Branch 2 (165→166) taken 1 times.
✗ Branch 3 (165→253) not taken.
|
1 | llvm::Value *indices[2] = {builder.getInt64(0), builder.getInt32(0)}; |
505 |
1/2✓ Branch 0 (170→171) taken 1 times.
✗ Branch 1 (170→246) not taken.
|
1 | llvm::Value *firstItemAddress = insertInBoundsGEP(elementTy, rhsAddress, indices); |
506 |
1/2✓ Branch 0 (173→174) taken 1 times.
✗ Branch 1 (173→253) not taken.
|
1 | insertStore(firstItemAddress, lhsAddress); |
507 | 1 | return LLVMExprResult{.value = rhsAddress, .ptr = lhsAddress, .entry = lhsEntry}; | |
508 | } | ||
509 | |||
510 | // We can load the value from the right side and store it to the left side | ||
511 | // Retrieve value of the right side | ||
512 | 10336 | llvm::Value *rhsValue = resolveValue(rhsSType, rhs); | |
513 | // Store the value to the address | ||
514 | 10336 | insertStore(rhsValue, lhsAddress); | |
515 | 10336 | return LLVMExprResult{.value = rhsValue, .ptr = lhsAddress, .entry = lhsEntry}; | |
516 | } | ||
517 | |||
518 | 122 | void IRGenerator::generateShallowCopy(llvm::Value *oldAddress, llvm::Type *varType, llvm::Value *targetAddress, | |
519 | bool isVolatile) const { | ||
520 | // Retrieve size to copy | ||
521 |
1/2✓ Branch 0 (3→4) taken 122 times.
✗ Branch 1 (3→19) not taken.
|
122 | const llvm::TypeSize typeSize = module->getDataLayout().getTypeAllocSize(varType); |
522 | |||
523 | // Create values for memcpy intrinsic | ||
524 |
2/4✓ Branch 0 (4→5) taken 122 times.
✗ Branch 1 (4→19) not taken.
✓ Branch 2 (5→6) taken 122 times.
✗ Branch 3 (5→19) not taken.
|
122 | llvm::Value *structSize = builder.getInt64(typeSize); |
525 |
1/2✓ Branch 0 (6→7) taken 122 times.
✗ Branch 1 (6→19) not taken.
|
122 | llvm::Value *copyVolatile = builder.getInt1(isVolatile); |
526 | |||
527 | // Call memcpy intrinsic to execute the shallow copy | ||
528 |
1/2✓ Branch 0 (7→8) taken 122 times.
✗ Branch 1 (7→19) not taken.
|
122 | llvm::Function *memcpyFct = stdFunctionManager.getMemcpyIntrinsic(); |
529 |
1/2✗ Branch 0 (8→9) not taken.
✓ Branch 1 (8→10) taken 122 times.
|
122 | assert(targetAddress != nullptr); |
530 |
3/6✓ Branch 0 (10→11) taken 122 times.
✗ Branch 1 (10→18) not taken.
✓ Branch 2 (12→13) taken 122 times.
✗ Branch 3 (12→15) not taken.
✓ Branch 4 (13→14) taken 122 times.
✗ Branch 5 (13→15) not taken.
|
122 | builder.CreateCall(memcpyFct, {targetAddress, oldAddress, structSize, copyVolatile}); |
531 | 122 | } | |
532 | |||
533 | 19775 | void IRGenerator::autoDeReferencePtr(llvm::Value *&ptr, QualType &symbolType) const { | |
534 |
6/6✓ Branch 0 (13→14) taken 20543 times.
✓ Branch 1 (13→16) taken 14678 times.
✓ Branch 2 (15→16) taken 768 times.
✓ Branch 3 (15→17) taken 19775 times.
✓ Branch 4 (18→3) taken 15446 times.
✓ Branch 5 (18→19) taken 19775 times.
|
35221 | while (symbolType.isPtr() || symbolType.isRef()) { |
535 |
3/6✓ Branch 0 (5→6) taken 15446 times.
✗ Branch 1 (5→22) not taken.
✓ Branch 2 (6→7) taken 15446 times.
✗ Branch 3 (6→20) not taken.
✓ Branch 4 (7→8) taken 15446 times.
✗ Branch 5 (7→20) not taken.
|
15446 | ptr = insertLoad(symbolType.toLLVMType(sourceFile), ptr); |
536 |
1/2✓ Branch 0 (10→11) taken 15446 times.
✗ Branch 1 (10→26) not taken.
|
15446 | symbolType = symbolType.getContained(); |
537 | } | ||
538 | 19775 | } | |
539 | |||
540 | 52 | llvm::GlobalVariable *IRGenerator::createGlobalConst(const std::string &baseName, llvm::Constant *constant) const { | |
541 | // Get unused name | ||
542 |
1/2✓ Branch 0 (2→3) taken 52 times.
✗ Branch 1 (2→19) not taken.
|
52 | const std::string globalName = getUnusedGlobalName(baseName); |
543 | // Create global | ||
544 |
1/2✓ Branch 0 (5→6) taken 52 times.
✗ Branch 1 (5→15) not taken.
|
52 | module->getOrInsertGlobal(globalName, constant->getType()); |
545 |
1/2✓ Branch 0 (7→8) taken 52 times.
✗ Branch 1 (7→16) not taken.
|
52 | llvm::GlobalVariable *global = module->getNamedGlobal(globalName); |
546 | // Set initializer to the given constant | ||
547 |
1/2✓ Branch 0 (8→9) taken 52 times.
✗ Branch 1 (8→17) not taken.
|
52 | global->setInitializer(constant); |
548 | 52 | global->setConstant(true); | |
549 |
1/2✓ Branch 0 (10→11) taken 52 times.
✗ Branch 1 (10→17) not taken.
|
52 | global->setLinkage(llvm::GlobalValue::PrivateLinkage); |
550 | 52 | global->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global); | |
551 | 52 | return global; | |
552 | 52 | } | |
553 | |||
554 | 2756 | llvm::GlobalVariable *IRGenerator::createGlobalStringConst(const std::string &baseName, const std::string &value) const { | |
555 | // Get unused name | ||
556 |
1/2✓ Branch 0 (2→3) taken 2756 times.
✗ Branch 1 (2→21) not taken.
|
2756 | const std::string globalName = getUnusedGlobalName(baseName); |
557 | // Create global | ||
558 |
2/4✓ Branch 0 (3→4) taken 2756 times.
✗ Branch 1 (3→16) not taken.
✓ Branch 2 (5→6) taken 2756 times.
✗ Branch 3 (5→15) not taken.
|
2756 | builder.CreateGlobalString(value, globalName, 0, module); |
559 |
1/2✓ Branch 0 (7→8) taken 2756 times.
✗ Branch 1 (7→17) not taken.
|
2756 | llvm::GlobalVariable *global = module->getNamedGlobal(globalName); |
560 | // If the output should be comparable, fix alignment to 4 bytes | ||
561 |
1/2✓ Branch 0 (8→9) taken 2756 times.
✗ Branch 1 (8→12) not taken.
|
2756 | if (cliOptions.comparableOutput) |
562 |
2/4✓ Branch 0 (9→10) taken 2756 times.
✗ Branch 1 (9→18) not taken.
✓ Branch 2 (10→11) taken 2756 times.
✗ Branch 3 (10→18) not taken.
|
2756 | global->setAlignment(llvm::Align(4)); |
563 | 2756 | return global; | |
564 | 2756 | } | |
565 | |||
566 | 2756 | llvm::GlobalVariable *IRGenerator::createGlobalStringConst(const std::string &baseName, const std::string &value, | |
567 | const CodeLoc &codeLoc) const { | ||
568 | 2756 | llvm::GlobalVariable *global = createGlobalStringConst(baseName, value); | |
569 | // Create debug info | ||
570 |
2/2✓ Branch 0 (3→4) taken 33 times.
✓ Branch 1 (3→10) taken 2723 times.
|
2756 | if (cliOptions.generateDebugInfo) |
571 |
3/6✓ Branch 0 (5→6) taken 33 times.
✗ Branch 1 (5→14) not taken.
✓ Branch 2 (6→7) taken 33 times.
✗ Branch 3 (6→14) not taken.
✓ Branch 4 (7→8) taken 33 times.
✗ Branch 5 (7→12) not taken.
|
33 | diGenerator.generateGlobalStringDebugInfo(global, global->getName().str(), value.length(), codeLoc); |
572 | 2756 | return global; | |
573 | } | ||
574 | |||
575 | 4138 | std::string IRGenerator::getUnusedGlobalName(const std::string &baseName) const { | |
576 | // Find an unused global name | ||
577 | 4138 | std::string globalName; | |
578 | 4138 | unsigned int suffixNumber = 0; | |
579 | do { | ||
580 |
1/2✓ Branch 0 (5→6) taken 47871 times.
✗ Branch 1 (5→15) not taken.
|
47871 | globalName = baseName + std::to_string(suffixNumber); |
581 | 47871 | suffixNumber++; | |
582 |
3/4✓ Branch 0 (10→11) taken 47871 times.
✗ Branch 1 (10→19) not taken.
✓ Branch 2 (11→12) taken 43733 times.
✓ Branch 3 (11→13) taken 4138 times.
|
47871 | } while (module->getNamedGlobal(globalName) != nullptr); |
583 | 4138 | return globalName; | |
584 | ✗ | } | |
585 | |||
586 | 14924 | void IRGenerator::materializeConstant(LLVMExprResult &exprResult) { | |
587 | // Skip results, that do not contain a constant or already have a value | ||
588 |
3/4✓ Branch 0 (2→3) taken 14575 times.
✓ Branch 1 (2→4) taken 349 times.
✗ Branch 2 (3→4) not taken.
✓ Branch 3 (3→5) taken 14575 times.
|
14924 | if (exprResult.value != nullptr || exprResult.constant == nullptr) |
589 | 349 | return; | |
590 | |||
591 | // Default case: the value to the constant | ||
592 | 14575 | exprResult.value = exprResult.constant; | |
593 | } | ||
594 | |||
595 | 863 | std::string IRGenerator::getIRString(llvm::Module *llvmModule, bool comparableOutput) { | |
596 |
1/2✗ Branch 0 (2→3) not taken.
✓ Branch 1 (2→4) taken 863 times.
|
863 | assert(llvmModule != nullptr); // Make sure the module hasn't been moved away |
597 | |||
598 | // Backup target triple and data layout | ||
599 | 863 | const llvm::Triple &targetTriple = llvmModule->getTargetTriple(); | |
600 |
1/2✓ Branch 0 (6→7) taken 863 times.
✗ Branch 1 (6→37) not taken.
|
863 | const std::string targetDataLayout = llvmModule->getDataLayoutStr(); |
601 | // Remove target triple and data layout | ||
602 |
1/2✓ Branch 0 (7→8) taken 863 times.
✗ Branch 1 (7→14) not taken.
|
863 | if (comparableOutput) { |
603 | 863 | llvmModule->setTargetTriple(llvm::Triple()); | |
604 |
2/4✓ Branch 0 (11→12) taken 863 times.
✗ Branch 1 (11→28) not taken.
✓ Branch 2 (12→13) taken 863 times.
✗ Branch 3 (12→28) not taken.
|
863 | llvmModule->setDataLayout(""); |
605 | } | ||
606 | |||
607 | // Get IR string | ||
608 | 863 | std::string output; | |
609 |
1/2✓ Branch 0 (15→16) taken 863 times.
✗ Branch 1 (15→33) not taken.
|
863 | llvm::raw_string_ostream oss(output); |
610 |
1/2✓ Branch 0 (16→17) taken 863 times.
✗ Branch 1 (16→31) not taken.
|
863 | llvmModule->print(oss, nullptr); |
611 | |||
612 | // Restore target triple and data layout | ||
613 |
1/2✓ Branch 0 (17→18) taken 863 times.
✗ Branch 1 (17→24) not taken.
|
863 | if (comparableOutput) { |
614 |
1/2✓ Branch 0 (18→19) taken 863 times.
✗ Branch 1 (18→29) not taken.
|
863 | llvmModule->setTargetTriple(targetTriple); |
615 |
1/2✓ Branch 0 (22→23) taken 863 times.
✗ Branch 1 (22→30) not taken.
|
863 | llvmModule->setDataLayout(targetDataLayout); |
616 | } | ||
617 | |||
618 | 863 | return output; | |
619 | 863 | } | |
620 | |||
621 | /** | ||
622 | * Returns the operator function list for the current manifestation and the given node | ||
623 | * | ||
624 | * @param node Node to retrieve the op fct pointer list from | ||
625 | * @return Op fct pointer list | ||
626 | */ | ||
627 | 16448 | const std::vector<const Function *> &IRGenerator::getOpFctPointers(const ASTNode *node) const { | |
628 |
1/2✗ Branch 0 (4→5) not taken.
✓ Branch 1 (4→6) taken 16448 times.
|
16448 | assert(node->getOpFctPointers()->size() > manIdx); |
629 | 16448 | return node->getOpFctPointers()->at(manIdx); | |
630 | } | ||
631 | |||
632 | } // namespace spice::compiler | ||
633 |