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 | 892 | IRGenerator::IRGenerator(GlobalResourceManager &resourceManager, SourceFile *sourceFile) | |
16 | 892 | : CompilerPass(resourceManager, sourceFile), context(cliOptions.useLTO ? resourceManager.ltoContext : sourceFile->context), | |
17 |
1/2✓ Branch 8 → 9 taken 892 times.
✗ Branch 8 → 61 not taken.
|
892 | builder(sourceFile->builder), module(sourceFile->llvmModule.get()), conversionManager(sourceFile, this), |
18 |
5/8✓ Branch 4 → 5 taken 2 times.
✓ Branch 4 → 6 taken 890 times.
✓ Branch 9 → 10 taken 892 times.
✗ Branch 9 → 61 not taken.
✓ Branch 10 → 11 taken 892 times.
✗ Branch 10 → 61 not taken.
✓ Branch 14 → 15 taken 892 times.
✗ Branch 14 → 55 not taken.
|
1784 | stdFunctionManager(sourceFile, resourceManager, module) { |
19 | // Attach information to the module | ||
20 |
1/2✓ Branch 16 → 17 taken 892 times.
✗ Branch 16 → 40 not taken.
|
892 | module->setTargetTriple(cliOptions.targetTriple); |
21 |
2/4✓ Branch 20 → 21 taken 892 times.
✗ Branch 20 → 43 not taken.
✓ Branch 21 → 22 taken 892 times.
✗ Branch 21 → 41 not taken.
|
892 | module->setDataLayout(sourceFile->targetMachine->createDataLayout()); |
22 |
1/2✓ Branch 23 → 24 taken 892 times.
✗ Branch 23 → 51 not taken.
|
892 | module->setPICLevel(llvm::PICLevel::BigPIC); |
23 |
1/2✓ Branch 24 → 25 taken 892 times.
✗ Branch 24 → 51 not taken.
|
892 | module->setPIELevel(llvm::PIELevel::Large); |
24 |
1/2✓ Branch 25 → 26 taken 892 times.
✗ Branch 25 → 51 not taken.
|
892 | module->setUwtable(llvm::UWTableKind::Default); |
25 |
1/2✓ Branch 26 → 27 taken 892 times.
✗ Branch 26 → 51 not taken.
|
892 | module->setFramePointer(llvm::FramePointerKind::All); |
26 | |||
27 | // Add module identifier metadata | ||
28 |
2/4✓ Branch 27 → 28 taken 892 times.
✗ Branch 27 → 44 not taken.
✓ Branch 28 → 29 taken 892 times.
✗ Branch 28 → 44 not taken.
|
892 | llvm::NamedMDNode *identifierMetadata = module->getOrInsertNamedMetadata("llvm.ident"); |
29 |
3/6✓ Branch 30 → 31 taken 892 times.
✗ Branch 30 → 45 not taken.
✓ Branch 32 → 33 taken 892 times.
✗ Branch 32 → 45 not taken.
✓ Branch 33 → 34 taken 892 times.
✗ Branch 33 → 45 not taken.
|
892 | identifierMetadata->addOperand(llvm::MDNode::get(context, llvm::MDString::get(context, PRODUCER_STRING))); |
30 | |||
31 | // Initialize debug info generator | ||
32 |
2/2✓ Branch 34 → 35 taken 15 times.
✓ Branch 34 → 39 taken 877 times.
|
892 | if (cliOptions.generateDebugInfo) |
33 |
2/4✓ Branch 35 → 36 taken 15 times.
✗ Branch 35 → 50 not taken.
✓ Branch 36 → 37 taken 15 times.
✗ Branch 36 → 48 not taken.
|
15 | diGenerator.initialize(sourceFile->fileName, sourceFile->fileDir); |
34 | 892 | } | |
35 | |||
36 | 892 | std::any IRGenerator::visitEntry(const EntryNode *node) { | |
37 | // Generate IR | ||
38 |
1/2✓ Branch 2 → 3 taken 892 times.
✗ Branch 2 → 19 not taken.
|
892 | visitChildren(node); |
39 | |||
40 | // Generate test main if required | ||
41 |
4/4✓ Branch 4 → 5 taken 236 times.
✓ Branch 4 → 7 taken 656 times.
✓ Branch 5 → 6 taken 2 times.
✓ Branch 5 → 7 taken 234 times.
|
892 | if (sourceFile->isMainFile && cliOptions.generateTestMain) |
42 | 2 | generateTestMain(); | |
43 | |||
44 | // Execute deferred VTable initializations | ||
45 |
2/2✓ Branch 13 → 9 taken 355 times.
✓ Branch 13 → 14 taken 892 times.
|
1247 | for (DeferredLogic &deferredVTableInit : deferredVTableInitializations) |
46 |
1/2✓ Branch 10 → 11 taken 355 times.
✗ Branch 10 → 20 not taken.
|
355 | deferredVTableInit.execute(); |
47 | |||
48 | // Finalize debug info generator | ||
49 | 892 | diGenerator.finalize(); | |
50 | |||
51 | // Verify module | ||
52 | 892 | verifyModule(node->codeLoc); | |
53 | |||
54 |
1/2✓ Branch 16 → 17 taken 892 times.
✗ Branch 16 → 21 not taken.
|
892 | return nullptr; |
55 | } | ||
56 | |||
57 | 33279 | llvm::Value *IRGenerator::insertAlloca(llvm::Type *llvmType, std::string varName) { | |
58 |
1/2✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 33279 times.
|
33279 | if (!cliOptions.namesForIRValues) |
59 | ✗ | varName = ""; | |
60 | |||
61 |
2/2✓ Branch 4 → 5 taken 23281 times.
✓ Branch 4 → 12 taken 9998 times.
|
33279 | if (allocaInsertInst != nullptr) { // If there is already an alloca inst, insert right after that |
62 |
2/4✓ Branch 5 → 6 taken 23281 times.
✗ Branch 5 → 29 not taken.
✓ Branch 6 → 7 taken 23281 times.
✗ Branch 6 → 29 not taken.
|
23281 | llvm::AllocaInst *allocaInst = builder.CreateAlloca(llvmType, nullptr, varName); |
63 |
1/2✓ Branch 8 → 9 taken 23281 times.
✗ Branch 8 → 30 not taken.
|
23281 | allocaInst->setDebugLoc(llvm::DebugLoc()); |
64 | 23281 | allocaInst->moveAfter(allocaInsertInst); | |
65 | 23281 | 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 | 9998 | llvm::BasicBlock *currentBlock = builder.GetInsertBlock(); | |
69 | 9998 | builder.SetInsertPoint(allocaInsertBlock, allocaInsertBlock->begin()); | |
70 | |||
71 | // Allocate the size of the given LLVM type | ||
72 |
2/4✓ Branch 15 → 16 taken 9998 times.
✗ Branch 15 → 33 not taken.
✓ Branch 16 → 17 taken 9998 times.
✗ Branch 16 → 33 not taken.
|
9998 | allocaInsertInst = builder.CreateAlloca(llvmType, nullptr, varName); |
73 |
1/2✓ Branch 18 → 19 taken 9998 times.
✗ Branch 18 → 34 not taken.
|
9998 | allocaInsertInst->setDebugLoc(llvm::DebugLoc()); |
74 | |||
75 | // Restore old basic block | ||
76 | 9998 | builder.SetInsertPoint(currentBlock); | |
77 | } | ||
78 | |||
79 | // Insert lifetime start marker | ||
80 |
1/2✗ Branch 21 → 22 not taken.
✓ Branch 21 → 27 taken 33279 times.
|
33279 | if (cliOptions.useLifetimeMarkers) { |
81 | ✗ | const uint64_t sizeInBytes = module->getDataLayout().getTypeAllocSize(llvmType); | |
82 | ✗ | builder.CreateLifetimeStart(allocaInsertInst, builder.getInt64(sizeInBytes)); | |
83 | } | ||
84 | |||
85 | 33279 | return allocaInsertInst; | |
86 | } | ||
87 | |||
88 | 66899 | llvm::Value *IRGenerator::insertLoad(llvm::Type *llvmType, llvm::Value *ptr, bool isVolatile, const std::string &varName) const { | |
89 |
1/2✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 66899 times.
|
66899 | assert(ptr->getType()->isPointerTy()); |
90 |
5/14✓ Branch 6 → 7 taken 66899 times.
✗ Branch 6 → 8 not taken.
✓ Branch 7 → 11 taken 66899 times.
✗ Branch 7 → 22 not taken.
✗ Branch 10 → 11 not taken.
✗ Branch 10 → 22 not taken.
✓ Branch 11 → 12 taken 66899 times.
✗ Branch 11 → 20 not taken.
✓ Branch 12 → 13 taken 66899 times.
✗ Branch 12 → 20 not taken.
✗ Branch 15 → 16 not taken.
✓ Branch 15 → 18 taken 66899 times.
✗ Branch 22 → 23 not taken.
✗ Branch 22 → 25 not taken.
|
66899 | return builder.CreateLoad(llvmType, ptr, isVolatile, cliOptions.namesForIRValues ? varName : ""); |
91 | } | ||
92 | |||
93 | 34512 | void IRGenerator::insertStore(llvm::Value *val, llvm::Value *ptr, bool isVolatile) const { | |
94 |
1/2✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 34512 times.
|
34512 | assert(ptr->getType()->isPointerTy()); |
95 | 34512 | builder.CreateStore(val, ptr, isVolatile); | |
96 | 34512 | } | |
97 | |||
98 | 17963 | llvm::Value *IRGenerator::insertInBoundsGEP(llvm::Type *type, llvm::Value *basePtr, llvm::ArrayRef<llvm::Value *> indices, | |
99 | std::string varName) const { | ||
100 |
1/2✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 17963 times.
|
17963 | assert(basePtr->getType()->isPointerTy()); |
101 |
1/2✗ Branch 7 → 8 not taken.
✓ Branch 7 → 9 taken 17963 times.
|
17963 | assert(!indices.empty()); |
102 |
4/6✓ Branch 4 → 5 taken 17654 times.
✓ Branch 4 → 7 taken 15713 times.
✓ Branch 6 → 7 taken 17654 times.
✗ Branch 6 → 8 not taken.
✗ Branch 10 → 11 not taken.
✓ Branch 10 → 12 taken 17963 times.
|
51330 | 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 12 → 13 not taken.
✓ Branch 12 → 14 taken 17963 times.
|
17963 | if (!cliOptions.namesForIRValues) |
108 | ✗ | varName = ""; | |
109 | |||
110 | // Insert GEP | ||
111 |
2/4✓ Branch 14 → 15 taken 17963 times.
✗ Branch 14 → 19 not taken.
✓ Branch 15 → 16 taken 17963 times.
✗ Branch 15 → 19 not taken.
|
17963 | return builder.CreateInBoundsGEP(type, basePtr, indices, varName); |
112 | } | ||
113 | |||
114 | 5155 | llvm::Value *IRGenerator::insertStructGEP(llvm::Type *type, llvm::Value *basePtr, unsigned int index, std::string varName) const { | |
115 |
1/2✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 5155 times.
|
5155 | assert(basePtr->getType()->isPointerTy()); |
116 | |||
117 |
1/2✗ Branch 6 → 7 not taken.
✓ Branch 6 → 8 taken 5155 times.
|
5155 | if (!cliOptions.namesForIRValues) |
118 | ✗ | varName = ""; | |
119 | |||
120 | // If we use index 0 we can use the base pointer directly | ||
121 |
2/2✓ Branch 8 → 9 taken 1798 times.
✓ Branch 8 → 10 taken 3357 times.
|
5155 | if (index == 0) |
122 | 1798 | return basePtr; | |
123 | |||
124 | // Insert GEP | ||
125 |
2/4✓ Branch 10 → 11 taken 3357 times.
✗ Branch 10 → 15 not taken.
✓ Branch 11 → 12 taken 3357 times.
✗ Branch 11 → 15 not taken.
|
3357 | return builder.CreateStructGEP(type, basePtr, index, varName); |
126 | } | ||
127 | |||
128 | 38316 | llvm::Value *IRGenerator::resolveValue(const ExprNode *node) { | |
129 | // Visit the given AST node | ||
130 |
2/4✓ Branch 2 → 3 taken 38316 times.
✗ Branch 2 → 11 not taken.
✓ Branch 3 → 4 taken 38316 times.
✗ Branch 3 → 9 not taken.
|
38316 | auto exprResult = any_cast<LLVMExprResult>(visit(node)); |
131 |
1/2✓ Branch 5 → 6 taken 38316 times.
✗ Branch 5 → 12 not taken.
|
76632 | return resolveValue(node, exprResult); |
132 | } | ||
133 | |||
134 | 44284 | llvm::Value *IRGenerator::resolveValue(const ExprNode *node, LLVMExprResult &exprResult) const { | |
135 | 44284 | return resolveValue(node->getEvaluatedSymbolType(manIdx), exprResult); | |
136 | } | ||
137 | |||
138 | 87370 | llvm::Value *IRGenerator::resolveValue(const QualType &qualType, LLVMExprResult &exprResult) const { | |
139 | // Check if the value is already present | ||
140 |
2/2✓ Branch 2 → 3 taken 28914 times.
✓ Branch 2 → 4 taken 58456 times.
|
87370 | if (exprResult.value != nullptr) |
141 | 28914 | return exprResult.value; | |
142 | |||
143 | // Check if a constant is present | ||
144 |
2/2✓ Branch 4 → 5 taken 15092 times.
✓ Branch 4 → 7 taken 43364 times.
|
58456 | if (exprResult.constant != nullptr) { |
145 | 15092 | materializeConstant(exprResult); | |
146 | 15092 | return exprResult.value; | |
147 | } | ||
148 | |||
149 |
3/4✓ Branch 7 → 8 taken 529 times.
✓ Branch 7 → 10 taken 42835 times.
✗ Branch 8 → 9 not taken.
✓ Branch 8 → 10 taken 529 times.
|
43364 | assert(exprResult.ptr != nullptr || exprResult.refPtr != nullptr); |
150 | |||
151 | // De-reference if reference type | ||
152 |
1/2✓ Branch 10 → 11 taken 43364 times.
✗ Branch 10 → 51 not taken.
|
43364 | const QualType referencedType = qualType.removeReferenceWrapper(); |
153 |
4/4✓ Branch 11 → 12 taken 533 times.
✓ Branch 11 → 25 taken 42831 times.
✓ Branch 12 → 13 taken 529 times.
✓ Branch 12 → 25 taken 4 times.
|
43364 | if (exprResult.refPtr != nullptr && exprResult.ptr == nullptr) |
154 |
6/10✓ Branch 15 → 16 taken 529 times.
✗ Branch 15 → 41 not taken.
✓ Branch 16 → 17 taken 529 times.
✗ Branch 16 → 19 not taken.
✓ Branch 17 → 18 taken 5 times.
✓ Branch 17 → 19 taken 524 times.
✓ Branch 20 → 21 taken 529 times.
✗ Branch 20 → 39 not taken.
✓ Branch 21 → 22 taken 529 times.
✗ Branch 21 → 39 not taken.
|
1058 | exprResult.ptr = insertLoad(builder.getPtrTy(), exprResult.refPtr, exprResult.entry && exprResult.entry->isVolatile); |
155 | |||
156 | // Load the value from the pointer | ||
157 |
1/2✓ Branch 25 → 26 taken 43364 times.
✗ Branch 25 → 51 not taken.
|
43364 | llvm::Type *valueTy = referencedType.toLLVMType(sourceFile); |
158 |
6/8✓ Branch 28 → 29 taken 43364 times.
✗ Branch 28 → 47 not taken.
✓ Branch 29 → 30 taken 39991 times.
✓ Branch 29 → 32 taken 3373 times.
✓ Branch 30 → 31 taken 10 times.
✓ Branch 30 → 32 taken 39981 times.
✓ Branch 33 → 34 taken 43364 times.
✗ Branch 33 → 45 not taken.
|
43364 | exprResult.value = insertLoad(valueTy, exprResult.ptr, exprResult.entry && exprResult.entry->isVolatile); |
159 | |||
160 | 43364 | return exprResult.value; | |
161 | } | ||
162 | |||
163 | 2772 | llvm::Value *IRGenerator::resolveAddress(const ASTNode *node) { | |
164 | // Visit the given AST node | ||
165 |
2/4✓ Branch 2 → 3 taken 2772 times.
✗ Branch 2 → 11 not taken.
✓ Branch 3 → 4 taken 2772 times.
✗ Branch 3 → 9 not taken.
|
2772 | auto exprResult = any_cast<LLVMExprResult>(visit(node)); |
166 |
1/2✓ Branch 5 → 6 taken 2772 times.
✗ Branch 5 → 12 not taken.
|
5544 | return resolveAddress(exprResult); |
167 | } | ||
168 | |||
169 | 20504 | llvm::Value *IRGenerator::resolveAddress(LLVMExprResult &exprResult) { | |
170 | // Check if an address is already present | ||
171 |
2/2✓ Branch 2 → 3 taken 17177 times.
✓ Branch 2 → 4 taken 3327 times.
|
20504 | if (exprResult.ptr != nullptr) |
172 | 17177 | return exprResult.ptr; | |
173 | |||
174 | // Check if the reference address is already present | ||
175 |
3/4✓ Branch 4 → 5 taken 2602 times.
✓ Branch 4 → 18 taken 725 times.
✓ Branch 5 → 6 taken 2602 times.
✗ Branch 5 → 18 not taken.
|
3327 | if (exprResult.refPtr != nullptr && exprResult.ptr == nullptr) { |
176 |
6/10✓ Branch 8 → 9 taken 2602 times.
✗ Branch 8 → 41 not taken.
✓ Branch 9 → 10 taken 2597 times.
✓ Branch 9 → 12 taken 5 times.
✗ Branch 10 → 11 not taken.
✓ Branch 10 → 12 taken 2597 times.
✓ Branch 13 → 14 taken 2602 times.
✗ Branch 13 → 39 not taken.
✓ Branch 14 → 15 taken 2602 times.
✗ Branch 14 → 39 not taken.
|
2602 | exprResult.ptr = insertLoad(builder.getPtrTy(), exprResult.refPtr, exprResult.entry && exprResult.entry->isVolatile); |
177 | 2602 | return exprResult.ptr; | |
178 | } | ||
179 | |||
180 | // If not, store the value or constant | ||
181 | 725 | materializeConstant(exprResult); | |
182 |
1/2✗ Branch 19 → 20 not taken.
✓ Branch 19 → 21 taken 725 times.
|
725 | assert(exprResult.value != nullptr); |
183 |
7/12✓ Branch 21 → 22 taken 6 times.
✓ Branch 21 → 23 taken 719 times.
✓ Branch 22 → 26 taken 6 times.
✗ Branch 22 → 47 not taken.
✓ Branch 25 → 26 taken 719 times.
✗ Branch 25 → 47 not taken.
✓ Branch 27 → 28 taken 725 times.
✗ Branch 27 → 45 not taken.
✓ Branch 29 → 30 taken 719 times.
✓ Branch 29 → 32 taken 6 times.
✗ Branch 47 → 48 not taken.
✗ Branch 47 → 50 not taken.
|
1444 | exprResult.ptr = insertAlloca(exprResult.value->getType(), exprResult.entry ? exprResult.entry->name : ""); |
184 |
3/4✓ Branch 32 → 33 taken 6 times.
✓ Branch 32 → 35 taken 719 times.
✗ Branch 33 → 34 not taken.
✓ Branch 33 → 35 taken 6 times.
|
725 | insertStore(exprResult.value, exprResult.ptr, exprResult.entry && exprResult.entry->isVolatile); |
185 | |||
186 | 725 | return exprResult.ptr; | |
187 | } | ||
188 | |||
189 | 2422 | llvm::Constant *IRGenerator::getDefaultValueForSymbolType(const QualType &symbolType) { // NOLINT(misc-no-recursion) | |
190 | // Double | ||
191 |
2/2✓ Branch 3 → 4 taken 4 times.
✓ Branch 3 → 9 taken 2418 times.
|
2422 | if (symbolType.is(TY_DOUBLE)) |
192 |
2/4✓ Branch 4 → 5 taken 4 times.
✗ Branch 4 → 132 not taken.
✓ Branch 5 → 6 taken 4 times.
✗ Branch 5 → 130 not taken.
|
4 | return llvm::ConstantFP::get(context, llvm::APFloat(0.0)); |
193 | |||
194 | // Int | ||
195 |
2/2✓ Branch 10 → 11 taken 326 times.
✓ Branch 10 → 13 taken 2092 times.
|
2418 | if (symbolType.is(TY_INT)) |
196 | 326 | return builder.getInt32(0); | |
197 | |||
198 | // Short | ||
199 |
2/2✓ Branch 14 → 15 taken 12 times.
✓ Branch 14 → 17 taken 2080 times.
|
2092 | if (symbolType.is(TY_SHORT)) |
200 | 12 | return builder.getInt16(0); | |
201 | |||
202 | // Long | ||
203 |
2/2✓ Branch 18 → 19 taken 906 times.
✓ Branch 18 → 21 taken 1174 times.
|
2080 | if (symbolType.is(TY_LONG)) |
204 | 906 | return builder.getInt64(0); | |
205 | |||
206 | // Byte or char | ||
207 |
3/4✓ Branch 21 → 22 taken 1174 times.
✗ Branch 21 → 133 not taken.
✓ Branch 22 → 23 taken 20 times.
✓ Branch 22 → 25 taken 1154 times.
|
1174 | if (symbolType.isOneOf({TY_BYTE, TY_CHAR})) |
208 | 20 | return builder.getInt8(0); | |
209 | |||
210 | // String | ||
211 |
2/2✓ Branch 26 → 27 taken 340 times.
✓ Branch 26 → 35 taken 814 times.
|
1154 | if (symbolType.is(TY_STRING)) { |
212 |
3/6✓ Branch 27 → 28 taken 340 times.
✗ Branch 27 → 135 not taken.
✓ Branch 28 → 29 taken 340 times.
✗ Branch 28 → 134 not taken.
✓ Branch 29 → 30 taken 340 times.
✗ Branch 29 → 134 not taken.
|
340 | llvm::GlobalVariable *globalString = builder.CreateGlobalString("", ""); |
213 |
1/2✓ Branch 30 → 31 taken 340 times.
✗ Branch 30 → 34 not taken.
|
340 | if (cliOptions.comparableOutput) |
214 |
2/4✓ Branch 31 → 32 taken 340 times.
✗ Branch 31 → 136 not taken.
✓ Branch 32 → 33 taken 340 times.
✗ Branch 32 → 136 not taken.
|
340 | globalString->setAlignment(llvm::Align(4)); |
215 | 340 | return globalString; | |
216 | } | ||
217 | |||
218 | // Bool | ||
219 |
2/2✓ Branch 36 → 37 taken 33 times.
✓ Branch 36 → 39 taken 781 times.
|
814 | if (symbolType.is(TY_BOOL)) |
220 | 33 | return builder.getFalse(); | |
221 | |||
222 | // Pointer or reference | ||
223 |
3/4✓ Branch 39 → 40 taken 781 times.
✗ Branch 39 → 137 not taken.
✓ Branch 40 → 41 taken 722 times.
✓ Branch 40 → 44 taken 59 times.
|
781 | if (symbolType.isOneOf({TY_PTR, TY_REF})) |
224 | 722 | return llvm::Constant::getNullValue(builder.getPtrTy()); | |
225 | |||
226 | // Array | ||
227 |
2/2✓ Branch 45 → 46 taken 15 times.
✓ Branch 45 → 61 taken 44 times.
|
59 | if (symbolType.isArray()) { |
228 | // Get array size | ||
229 |
1/2✓ Branch 46 → 47 taken 15 times.
✗ Branch 46 → 146 not taken.
|
15 | const size_t arraySize = symbolType.getArraySize(); |
230 | |||
231 | // Get default value for item | ||
232 |
2/4✓ Branch 47 → 48 taken 15 times.
✗ Branch 47 → 138 not taken.
✓ Branch 48 → 49 taken 15 times.
✗ Branch 48 → 138 not taken.
|
15 | llvm::Constant *defaultItemValue = getDefaultValueForSymbolType(symbolType.getContained()); |
233 | |||
234 | // Retrieve array and item type | ||
235 |
2/4✓ Branch 49 → 50 taken 15 times.
✗ Branch 49 → 139 not taken.
✓ Branch 50 → 51 taken 15 times.
✗ Branch 50 → 139 not taken.
|
15 | llvm::Type *itemType = symbolType.getContained().toLLVMType(sourceFile); |
236 |
1/2✓ Branch 51 → 52 taken 15 times.
✗ Branch 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 54 → 55 taken 15 times.
✗ Branch 54 → 140 not taken.
|
15 | const std::vector itemConstants(arraySize, defaultItemValue); |
240 |
1/2✓ Branch 57 → 58 taken 15 times.
✗ Branch 57 → 143 not taken.
|
15 | return llvm::ConstantArray::get(arrayType, itemConstants); |
241 | 15 | } | |
242 | |||
243 | // Function or procedure | ||
244 |
3/4✓ Branch 61 → 62 taken 44 times.
✗ Branch 61 → 147 not taken.
✓ Branch 62 → 63 taken 14 times.
✓ Branch 62 → 75 taken 30 times.
|
44 | if (symbolType.isOneOf({TY_FUNCTION, TY_PROCEDURE})) { |
245 |
2/2✓ Branch 63 → 64 taken 7 times.
✓ Branch 63 → 69 taken 7 times.
|
14 | if (!llvmTypes.fatPtrType) |
246 |
3/6✓ Branch 64 → 65 taken 7 times.
✗ Branch 64 → 148 not taken.
✓ Branch 65 → 66 taken 7 times.
✗ Branch 65 → 148 not taken.
✓ Branch 67 → 68 taken 7 times.
✗ Branch 67 → 148 not taken.
|
7 | llvmTypes.fatPtrType = llvm::StructType::get(context, {builder.getPtrTy(), builder.getPtrTy()}); |
247 | |||
248 |
2/4✓ Branch 69 → 70 taken 14 times.
✗ Branch 69 → 150 not taken.
✓ Branch 70 → 71 taken 14 times.
✗ Branch 70 → 150 not taken.
|
14 | llvm::Constant *ptrDefaultValue = getDefaultValueForSymbolType(QualType(TY_PTR)); |
249 |
1/2✓ Branch 72 → 73 taken 14 times.
✗ Branch 72 → 151 not taken.
|
14 | return llvm::ConstantStruct::get(llvmTypes.fatPtrType, {ptrDefaultValue, ptrDefaultValue}); |
250 | } | ||
251 | |||
252 | // Struct | ||
253 |
2/2✓ Branch 76 → 77 taken 29 times.
✓ Branch 76 → 114 taken 1 time.
|
30 | if (symbolType.is(TY_STRUCT)) { |
254 | // Retrieve field count | ||
255 |
1/2✓ Branch 77 → 78 taken 29 times.
✗ Branch 77 → 158 not taken.
|
29 | Scope *structScope = symbolType.getBodyScope(); |
256 |
1/2✗ Branch 78 → 79 not taken.
✓ Branch 78 → 80 taken 29 times.
|
29 | assert(structScope != nullptr); |
257 |
1/2✓ Branch 80 → 81 taken 29 times.
✗ Branch 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 81 → 82 taken 29 times.
✗ Branch 81 → 156 not taken.
|
29 | fieldConstants.reserve(fieldCount); |
262 | |||
263 | // Add default value for each struct field | ||
264 |
2/2✓ Branch 107 → 83 taken 66 times.
✓ Branch 107 → 108 taken 29 times.
|
95 | for (size_t i = 0; i < fieldCount; i++) { |
265 | // Get entry of the field | ||
266 |
1/2✗ Branch 83 → 84 not taken.
✓ Branch 83 → 85 taken 66 times.
|
66 | const SymbolTableEntry *fieldEntry = structScope->lookupField(i); |
267 |
3/6✓ Branch 88 → 89 taken 66 times.
✗ Branch 88 → 92 not taken.
✓ Branch 89 → 90 taken 66 times.
✗ Branch 89 → 154 not taken.
✓ Branch 90 → 91 taken 66 times.
✗ Branch 90 → 92 not taken.
|
66 | assert(fieldEntry != nullptr && fieldEntry->isField()); |
268 | |||
269 | // Retrieve default field value | ||
270 | llvm::Constant *defaultFieldValue; | ||
271 |
4/6✓ Branch 93 → 94 taken 66 times.
✗ Branch 93 → 95 not taken.
✓ Branch 96 → 97 taken 66 times.
✗ Branch 96 → 102 not taken.
✓ Branch 97 → 98 taken 5 times.
✓ Branch 97 → 102 taken 61 times.
|
66 | if (const auto fieldNode = dynamic_cast<FieldNode *>(fieldEntry->declNode); fieldNode && fieldNode->defaultValue) |
272 |
3/6✓ Branch 98 → 99 taken 5 times.
✗ Branch 98 → 154 not taken.
✓ Branch 99 → 100 taken 5 times.
✗ Branch 99 → 153 not taken.
✓ Branch 100 → 101 taken 5 times.
✗ Branch 100 → 153 not taken.
|
5 | defaultFieldValue = getConst(fieldNode->defaultValue->getCompileTimeValue(), fieldEntry->getQualType(), fieldNode); |
273 | else | ||
274 |
2/4✓ Branch 102 → 103 taken 61 times.
✗ Branch 102 → 154 not taken.
✓ Branch 103 → 104 taken 61 times.
✗ Branch 103 → 154 not taken.
|
61 | defaultFieldValue = getDefaultValueForSymbolType(fieldEntry->getQualType()); |
275 | |||
276 |
1/2✓ Branch 105 → 106 taken 66 times.
✗ Branch 105 → 154 not taken.
|
66 | fieldConstants.push_back(defaultFieldValue); |
277 | } | ||
278 | |||
279 |
1/2✓ Branch 108 → 109 taken 29 times.
✗ Branch 108 → 156 not taken.
|
29 | const auto structType = reinterpret_cast<llvm::StructType *>(symbolType.toLLVMType(sourceFile)); |
280 |
1/2✓ Branch 110 → 111 taken 29 times.
✗ Branch 110 → 155 not taken.
|
29 | return llvm::ConstantStruct::get(structType, fieldConstants); |
281 | 29 | } | |
282 | |||
283 | // Interface | ||
284 |
1/2✓ Branch 115 → 116 taken 1 time.
✗ Branch 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 | 15274 | llvm::Constant *IRGenerator::getConst(const CompileTimeValue &compileTimeValue, const QualType &type, const ASTNode *node) const { | |
293 |
2/2✓ Branch 3 → 4 taken 383 times.
✓ Branch 3 → 9 taken 14891 times.
|
15274 | if (type.is(TY_DOUBLE)) |
294 |
2/4✓ Branch 4 → 5 taken 383 times.
✗ Branch 4 → 56 not taken.
✓ Branch 5 → 6 taken 383 times.
✗ Branch 5 → 54 not taken.
|
383 | return llvm::ConstantFP::get(context, llvm::APFloat(compileTimeValue.doubleValue)); |
295 | |||
296 |
2/2✓ Branch 10 → 11 taken 3034 times.
✓ Branch 10 → 13 taken 11857 times.
|
14891 | if (type.is(TY_INT)) |
297 | 3034 | return builder.getInt32(compileTimeValue.intValue); | |
298 | |||
299 |
2/2✓ Branch 14 → 15 taken 576 times.
✓ Branch 14 → 17 taken 11281 times.
|
11857 | if (type.is(TY_SHORT)) |
300 | 576 | return builder.getInt16(compileTimeValue.shortValue); | |
301 | |||
302 |
2/2✓ Branch 18 → 19 taken 5606 times.
✓ Branch 18 → 21 taken 5675 times.
|
11281 | if (type.is(TY_LONG)) |
303 | 5606 | return builder.getInt64(compileTimeValue.longValue); | |
304 | |||
305 |
3/4✓ Branch 21 → 22 taken 5675 times.
✗ Branch 21 → 57 not taken.
✓ Branch 22 → 23 taken 2247 times.
✓ Branch 22 → 25 taken 3428 times.
|
5675 | if (type.isOneOf({TY_BYTE, TY_CHAR})) |
306 | 2247 | return builder.getInt8(compileTimeValue.charValue); | |
307 | |||
308 |
2/2✓ Branch 26 → 27 taken 2097 times.
✓ Branch 26 → 36 taken 1331 times.
|
3428 | if (type.is(TY_STRING)) { |
309 | 2097 | const std::string &stringValue = resourceManager.compileTimeStringValues.at(compileTimeValue.stringValueOffset); | |
310 |
2/4✓ Branch 30 → 31 taken 2097 times.
✗ Branch 30 → 60 not taken.
✓ Branch 31 → 32 taken 2097 times.
✗ Branch 31 → 58 not taken.
|
6291 | return createGlobalStringConst(ANON_GLOBAL_STRING_NAME, stringValue, node->codeLoc); |
311 | } | ||
312 | |||
313 |
1/2✓ Branch 37 → 38 taken 1331 times.
✗ Branch 37 → 40 not taken.
|
1331 | if (type.is(TY_BOOL)) |
314 | 1331 | 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 | 30313 | llvm::BasicBlock *IRGenerator::createBlock(const std::string &blockName /*=""*/) const { | |
323 |
2/4✓ Branch 2 → 3 taken 30313 times.
✗ Branch 2 → 7 not taken.
✓ Branch 3 → 4 taken 30313 times.
✗ Branch 3 → 7 not taken.
|
30313 | return llvm::BasicBlock::Create(context, blockName); |
324 | } | ||
325 | |||
326 | 30313 | void IRGenerator::switchToBlock(llvm::BasicBlock *block, llvm::Function *parentFct /*=nullptr*/) { | |
327 |
1/2✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 30313 times.
|
30313 | 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 5 → 6 taken 20277 times.
✓ Branch 5 → 8 taken 10036 times.
|
30313 | if (!parentFct) |
330 | 20277 | parentFct = builder.GetInsertBlock()->getParent(); | |
331 | // Append block to current function | ||
332 | 30313 | parentFct->insert(parentFct->end(), block); | |
333 | // Set insert point to the block | ||
334 | 30313 | builder.SetInsertPoint(block); | |
335 | 30313 | blockAlreadyTerminated = false; | |
336 | 30313 | } | |
337 | |||
338 | 9480 | void IRGenerator::terminateBlock(const StmtLstNode *stmtLstNode) { | |
339 | 9480 | diGenerator.setSourceLocation(stmtLstNode->closingBraceCodeLoc); | |
340 | 9480 | generateScopeCleanup(stmtLstNode); | |
341 | 9480 | blockAlreadyTerminated = true; | |
342 | 9480 | } | |
343 | |||
344 | 11585 | void IRGenerator::insertJump(llvm::BasicBlock *targetBlock) { | |
345 |
2/2✓ Branch 2 → 3 taken 3317 times.
✓ Branch 2 → 4 taken 8268 times.
|
11585 | if (blockAlreadyTerminated) |
346 | 3317 | return; | |
347 | 8268 | builder.CreateBr(targetBlock); | |
348 | 8268 | blockAlreadyTerminated = true; | |
349 | } | ||
350 | |||
351 | 8370 | void IRGenerator::insertCondJump(llvm::Value *condition, llvm::BasicBlock *trueBlock, llvm::BasicBlock *falseBlock, | |
352 | Likeliness likeliness /*=UNSPECIFIED*/) { | ||
353 |
1/2✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 8370 times.
|
8370 | if (blockAlreadyTerminated) |
354 | ✗ | return; | |
355 | 8370 | llvm::BranchInst *jumpInst = builder.CreateCondBr(condition, trueBlock, falseBlock); | |
356 | 8370 | blockAlreadyTerminated = true; | |
357 | |||
358 |
2/2✓ Branch 5 → 6 taken 761 times.
✓ Branch 5 → 22 taken 7609 times.
|
8370 | if (likeliness != UNSPECIFIED) { |
359 | 761 | const bool likely = likeliness == LIKELY; | |
360 | 761 | llvm::Metadata *name = llvm::MDString::get(context, "branch_weights"); | |
361 |
1/2✓ Branch 7 → 8 taken 761 times.
✗ Branch 7 → 9 not taken.
|
761 | llvm::Metadata *trueBranchWeight = llvm::ConstantAsMetadata::get(builder.getInt32(likely ? 2000 : 1)); |
362 |
1/2✓ Branch 12 → 13 taken 761 times.
✗ Branch 12 → 14 not taken.
|
761 | llvm::Metadata *falseBranchWeight = llvm::ConstantAsMetadata::get(builder.getInt32(likely ? 1 : 2000)); |
363 |
1/2✓ Branch 18 → 19 taken 761 times.
✗ Branch 18 → 23 not taken.
|
761 | const auto profMetadata = llvm::MDNode::get(context, {name, trueBranchWeight, falseBranchWeight}); |
364 |
2/4✓ Branch 19 → 20 taken 761 times.
✗ Branch 19 → 25 not taken.
✓ Branch 20 → 21 taken 761 times.
✗ Branch 20 → 25 not taken.
|
761 | jumpInst->setMetadata("prof", profMetadata); |
365 | } | ||
366 | } | ||
367 | |||
368 | 10036 | 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 2 → 3 taken 10036 times.
✗ Branch 2 → 4 not taken.
✓ Branch 3 → 4 taken 173 times.
✓ Branch 3 → 5 taken 9863 times.
|
10036 | if (cliOptions.disableVerifier || cliOptions.generateDebugInfo) |
371 | 173 | return; | |
372 | |||
373 | // Verify function | ||
374 | 9863 | std::string output; | |
375 |
1/2✓ Branch 6 → 7 taken 9863 times.
✗ Branch 6 → 21 not taken.
|
9863 | 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 | 9863 | } | |
379 | |||
380 | 892 | 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 2 → 3 taken 892 times.
✗ Branch 2 → 4 not taken.
✓ Branch 3 → 4 taken 15 times.
✓ Branch 3 → 5 taken 877 times.
|
892 | if (cliOptions.disableVerifier || cliOptions.generateDebugInfo) |
383 | 15 | return; | |
384 | |||
385 | // Verify module | ||
386 | 877 | std::string output; | |
387 |
1/2✓ Branch 6 → 7 taken 877 times.
✗ Branch 6 → 21 not taken.
|
877 | 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 | 877 | } | |
391 | |||
392 | 5282 | LLVMExprResult IRGenerator::doAssignment(const ASTNode *lhsNode, const ExprNode *rhsNode, const ASTNode *node) { | |
393 | // Get entry of left side | ||
394 |
2/4✓ Branch 2 → 3 taken 5282 times.
✗ Branch 2 → 17 not taken.
✓ Branch 3 → 4 taken 5282 times.
✗ Branch 3 → 15 not taken.
|
5282 | auto [value, constant, ptr, refPtr, entry, _] = std::any_cast<LLVMExprResult>(visit(lhsNode)); |
395 |
6/8✓ Branch 5 → 6 taken 4522 times.
✓ Branch 5 → 10 taken 760 times.
✓ Branch 6 → 7 taken 4522 times.
✗ Branch 6 → 18 not taken.
✓ Branch 7 → 8 taken 4522 times.
✗ Branch 7 → 18 not taken.
✓ Branch 8 → 9 taken 231 times.
✓ Branch 8 → 10 taken 4291 times.
|
5282 | llvm::Value *lhsAddress = entry != nullptr && entry->getQualType().isRef() ? refPtr : ptr; |
396 |
1/2✓ Branch 11 → 12 taken 5282 times.
✗ Branch 11 → 18 not taken.
|
10564 | return doAssignment(lhsAddress, entry, rhsNode, node); |
397 | } | ||
398 | |||
399 | 12375 | 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 2 → 3 taken 12375 times.
✗ Branch 2 → 13 not taken.
|
12375 | const QualType &rhsSType = rhsNode->getEvaluatedSymbolType(manIdx); |
403 |
2/4✓ Branch 3 → 4 taken 12375 times.
✗ Branch 3 → 12 not taken.
✓ Branch 4 → 5 taken 12375 times.
✗ Branch 4 → 10 not taken.
|
12375 | auto rhs = std::any_cast<LLVMExprResult>(visit(rhsNode)); |
404 |
1/2✓ Branch 6 → 7 taken 12375 times.
✗ Branch 6 → 13 not taken.
|
24750 | return doAssignment(lhsAddress, lhsEntry, rhs, rhsSType, node, isDecl); |
405 | } | ||
406 | |||
407 | 12490 | 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 2 → 3 taken 11730 times.
✓ Branch 2 → 7 taken 760 times.
✓ Branch 5 → 6 taken 470 times.
✓ Branch 5 → 7 taken 11260 times.
|
12490 | const bool isRefAssign = lhsEntry != nullptr && lhsEntry->getQualType().isRef(); |
411 |
8/10✓ Branch 8 → 9 taken 12020 times.
✓ Branch 8 → 15 taken 470 times.
✓ Branch 9 → 10 taken 12020 times.
✗ Branch 9 → 179 not taken.
✓ Branch 10 → 11 taken 12020 times.
✗ Branch 10 → 179 not taken.
✓ Branch 11 → 12 taken 1334 times.
✓ Branch 11 → 15 taken 10686 times.
✓ Branch 13 → 14 taken 169 times.
✓ Branch 13 → 15 taken 1165 times.
|
12490 | const bool needsCopy = !isRefAssign && rhsSType.removeReferenceWrapper().is(TY_STRUCT) && !rhs.isTemporary(); |
412 | |||
413 |
2/2✓ Branch 16 → 17 taken 470 times.
✓ Branch 16 → 57 taken 12020 times.
|
12490 | if (isRefAssign) { |
414 |
1/2✗ Branch 17 → 18 not taken.
✓ Branch 17 → 19 taken 470 times.
|
470 | assert(lhsEntry != nullptr); |
415 |
2/2✓ Branch 19 → 20 taken 239 times.
✓ Branch 19 → 33 taken 231 times.
|
470 | if (isDecl) { // Reference gets initially assigned |
416 | // Get address of right side | ||
417 | 239 | llvm::Value *rhsAddress = resolveAddress(rhs); | |
418 |
1/2✗ Branch 21 → 22 not taken.
✓ Branch 21 → 23 taken 239 times.
|
239 | assert(rhsAddress != nullptr); |
419 | |||
420 | // Store lhs pointer to rhs | ||
421 |
2/4✓ Branch 26 → 27 taken 239 times.
✗ Branch 26 → 180 not taken.
✓ Branch 27 → 28 taken 239 times.
✗ Branch 27 → 180 not taken.
|
239 | llvm::Value *refAddress = insertAlloca(builder.getPtrTy()); |
422 | 239 | lhsEntry->updateAddress(refAddress); | |
423 | 239 | insertStore(rhsAddress, refAddress); | |
424 | |||
425 | 239 | 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 33 → 34 taken 159 times.
✓ Branch 33 → 40 taken 72 times.
✓ Branch 35 → 36 taken 159 times.
✗ Branch 35 → 40 not taken.
✓ Branch 36 → 37 taken 153 times.
✓ Branch 36 → 40 taken 6 times.
✓ Branch 38 → 39 taken 153 times.
✗ Branch 38 → 40 not taken.
|
231 | const bool isInitialFieldRefAssign = isInCtorBody && rhsSType.isRef() && rhs.entry && lhsEntry->isField(); |
431 | // Assigning the result variable | ||
432 | 231 | const bool isReturnValAssign = lhsEntry->name == RETURN_VARIABLE_NAME; | |
433 |
4/4✓ Branch 42 → 43 taken 78 times.
✓ Branch 42 → 44 taken 153 times.
✓ Branch 43 → 44 taken 2 times.
✓ Branch 43 → 49 taken 76 times.
|
231 | if (isInitialFieldRefAssign || isReturnValAssign) { |
434 | // Get address of right side | ||
435 | 155 | llvm::Value *referencedAddress = resolveAddress(rhs); | |
436 |
1/2✗ Branch 45 → 46 not taken.
✓ Branch 45 → 47 taken 155 times.
|
155 | assert(referencedAddress != nullptr); |
437 | |||
438 | // Store the rhs* to the lhs** | ||
439 | 155 | insertStore(referencedAddress, lhsAddress); | |
440 | |||
441 | 155 | return LLVMExprResult{.value = referencedAddress, .ptr = lhsAddress, .entry = lhsEntry}; | |
442 | } | ||
443 | |||
444 | // Load referenced address | ||
445 |
3/6✓ Branch 51 → 52 taken 76 times.
✗ Branch 51 → 188 not taken.
✓ Branch 52 → 53 taken 76 times.
✗ Branch 52 → 186 not taken.
✓ Branch 53 → 54 taken 76 times.
✗ Branch 53 → 186 not taken.
|
152 | 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 57 → 58 taken 169 times.
✓ Branch 57 → 124 taken 11927 times.
|
12096 | if (needsCopy) { |
450 | // Get address of right side | ||
451 |
1/2✓ Branch 58 → 59 taken 169 times.
✗ Branch 58 → 239 not taken.
|
169 | llvm::Value *rhsAddress = resolveAddress(rhs); |
452 |
1/2✗ Branch 59 → 60 not taken.
✓ Branch 59 → 61 taken 169 times.
|
169 | assert(rhsAddress != nullptr); |
453 | |||
454 | // Allocate new memory if the lhs address does not exist | ||
455 |
2/2✓ Branch 61 → 62 taken 4 times.
✓ Branch 61 → 73 taken 165 times.
|
169 | if (!lhsAddress) { |
456 |
1/2✗ Branch 62 → 63 not taken.
✓ Branch 62 → 64 taken 4 times.
|
4 | assert(lhsEntry != nullptr); |
457 |
3/6✓ Branch 67 → 68 taken 4 times.
✗ Branch 67 → 192 not taken.
✓ Branch 68 → 69 taken 4 times.
✗ Branch 68 → 192 not taken.
✓ Branch 69 → 70 taken 4 times.
✗ Branch 69 → 192 not taken.
|
4 | lhsAddress = insertAlloca(lhsEntry->getQualType().toLLVMType(sourceFile)); |
458 |
1/2✓ Branch 72 → 73 taken 4 times.
✗ Branch 72 → 239 not taken.
|
4 | lhsEntry->updateAddress(lhsAddress); |
459 | } | ||
460 | |||
461 | // Check if we have a copy ctor | ||
462 |
2/4✓ Branch 73 → 74 taken 169 times.
✗ Branch 73 → 198 not taken.
✓ Branch 74 → 75 taken 169 times.
✗ Branch 74 → 198 not taken.
|
169 | const QualType rhsSTypeNonRef = rhsSType.removeReferenceWrapper().toNonConst(); |
463 |
1/2✓ Branch 75 → 76 taken 169 times.
✗ Branch 75 → 239 not taken.
|
169 | Scope *structScope = rhsSTypeNonRef.getBodyScope(); |
464 |
2/4✓ Branch 76 → 77 taken 169 times.
✗ Branch 76 → 203 not taken.
✓ Branch 81 → 82 taken 169 times.
✗ Branch 81 → 199 not taken.
|
507 | const ArgList args = {{rhsSTypeNonRef.toConstRef(node), rhs.isTemporary()}}; |
465 |
2/4✓ Branch 85 → 86 taken 169 times.
✗ Branch 85 → 207 not taken.
✓ Branch 86 → 87 taken 169 times.
✗ Branch 86 → 205 not taken.
|
169 | const Function *copyCtor = FunctionManager::lookup(structScope, CTOR_FUNCTION_NAME, rhsSTypeNonRef, args, true); |
466 |
2/2✓ Branch 89 → 90 taken 73 times.
✓ Branch 89 → 97 taken 96 times.
|
169 | if (copyCtor != nullptr) { |
467 | // Call copy ctor | ||
468 |
2/4✓ Branch 92 → 93 taken 73 times.
✗ Branch 92 → 213 not taken.
✓ Branch 93 → 94 taken 73 times.
✗ Branch 93 → 211 not taken.
|
219 | generateCtorOrDtorCall(lhsAddress, copyCtor, {rhsAddress}); |
469 |
2/4✓ Branch 97 → 98 taken 96 times.
✗ Branch 97 → 237 not taken.
✓ Branch 98 → 99 taken 96 times.
✗ Branch 98 → 115 not taken.
|
96 | } else if (rhsSTypeNonRef.isTriviallyCopyable(node)) { |
470 | // Create shallow copy | ||
471 |
1/2✓ Branch 99 → 100 taken 96 times.
✗ Branch 99 → 225 not taken.
|
96 | llvm::Type *rhsType = rhsSTypeNonRef.toLLVMType(sourceFile); |
472 |
6/10✓ Branch 100 → 101 taken 91 times.
✓ Branch 100 → 102 taken 5 times.
✓ Branch 101 → 105 taken 91 times.
✗ Branch 101 → 218 not taken.
✓ Branch 104 → 105 taken 5 times.
✗ Branch 104 → 218 not taken.
✓ Branch 105 → 106 taken 5 times.
✓ Branch 105 → 108 taken 91 times.
✗ Branch 218 → 219 not taken.
✗ Branch 218 → 221 not taken.
|
101 | const std::string copyName = lhsEntry ? lhsEntry->name : ""; |
473 |
4/6✓ Branch 108 → 109 taken 91 times.
✓ Branch 108 → 111 taken 5 times.
✗ Branch 109 → 110 not taken.
✓ Branch 109 → 111 taken 91 times.
✓ Branch 112 → 113 taken 96 times.
✗ Branch 112 → 223 not taken.
|
96 | generateShallowCopy(rhsAddress, rhsType, lhsAddress, lhsEntry && lhsEntry->isVolatile); |
474 | 96 | } 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 | 169 | return LLVMExprResult{.ptr = lhsAddress, .entry = lhsEntry}; | |
480 | 169 | } | |
481 | |||
482 |
7/8✓ Branch 124 → 125 taken 6965 times.
✓ Branch 124 → 130 taken 4962 times.
✓ Branch 126 → 127 taken 868 times.
✓ Branch 126 → 130 taken 6097 times.
✓ Branch 128 → 129 taken 868 times.
✗ Branch 128 → 130 not taken.
✓ Branch 131 → 132 taken 868 times.
✓ Branch 131 → 137 taken 11059 times.
|
11927 | if (isDecl && rhsSType.is(TY_STRUCT) && rhs.isTemporary()) { |
483 |
1/2✗ Branch 132 → 133 not taken.
✓ Branch 132 → 134 taken 868 times.
|
868 | assert(lhsEntry != nullptr); |
484 | // Directly set the address to the lhs entry (temp stealing) | ||
485 | 868 | llvm::Value *rhsAddress = resolveAddress(rhs); | |
486 | 868 | lhsEntry->updateAddress(rhsAddress); | |
487 | 868 | rhs.entry = lhsEntry; | |
488 | 868 | return rhs; | |
489 | } | ||
490 | |||
491 | // Allocate new memory if the lhs address does not exist | ||
492 |
2/2✓ Branch 137 → 138 taken 6066 times.
✓ Branch 137 → 149 taken 4993 times.
|
11059 | if (!lhsAddress) { |
493 |
1/2✗ Branch 138 → 139 not taken.
✓ Branch 138 → 140 taken 6066 times.
|
6066 | assert(lhsEntry != nullptr); |
494 |
3/6✓ Branch 143 → 144 taken 6066 times.
✗ Branch 143 → 240 not taken.
✓ Branch 144 → 145 taken 6066 times.
✗ Branch 144 → 240 not taken.
✓ Branch 145 → 146 taken 6066 times.
✗ Branch 145 → 240 not taken.
|
6066 | lhsAddress = insertAlloca(lhsEntry->getQualType().toLLVMType(sourceFile)); |
495 | 6066 | 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 149 → 150 taken 10319 times.
✓ Branch 149 → 158 taken 740 times.
✓ Branch 152 → 153 taken 2092 times.
✓ Branch 152 → 158 taken 8227 times.
✓ Branch 154 → 155 taken 5 times.
✓ Branch 154 → 158 taken 2087 times.
✓ Branch 156 → 157 taken 1 time.
✓ Branch 156 → 158 taken 4 times.
✓ Branch 159 → 160 taken 1 time.
✓ Branch 159 → 175 taken 11058 times.
|
11059 | if (lhsEntry && lhsEntry->getQualType().isPtr() && rhsSType.isArray() && rhsSType.getArraySize() != ARRAY_SIZE_UNKNOWN) { |
500 | // Get address of right side | ||
501 |
1/2✓ Branch 160 → 161 taken 1 time.
✗ Branch 160 → 253 not taken.
|
1 | llvm::Value *rhsAddress = resolveAddress(rhs); |
502 |
1/2✗ Branch 161 → 162 not taken.
✓ Branch 161 → 163 taken 1 time.
|
1 | assert(rhsAddress != nullptr); |
503 |
1/2✓ Branch 163 → 164 taken 1 time.
✗ Branch 163 → 253 not taken.
|
1 | llvm::Type *elementTy = rhsSType.toLLVMType(sourceFile); |
504 |
2/4✓ Branch 164 → 165 taken 1 time.
✗ Branch 164 → 253 not taken.
✓ Branch 165 → 166 taken 1 time.
✗ Branch 165 → 253 not taken.
|
1 | llvm::Value *indices[2] = {builder.getInt64(0), builder.getInt32(0)}; |
505 |
1/2✓ Branch 170 → 171 taken 1 time.
✗ Branch 170 → 246 not taken.
|
1 | llvm::Value *firstItemAddress = insertInBoundsGEP(elementTy, rhsAddress, indices); |
506 |
1/2✓ Branch 173 → 174 taken 1 time.
✗ Branch 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 | 11058 | llvm::Value *rhsValue = resolveValue(rhsSType, rhs); | |
513 | // Store the value to the address | ||
514 | 11058 | insertStore(rhsValue, lhsAddress); | |
515 | 11058 | return LLVMExprResult{.value = rhsValue, .ptr = lhsAddress, .entry = lhsEntry}; | |
516 | } | ||
517 | |||
518 | 133 | 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 3 → 4 taken 133 times.
✗ Branch 3 → 19 not taken.
|
133 | const llvm::TypeSize typeSize = module->getDataLayout().getTypeAllocSize(varType); |
522 | |||
523 | // Create values for memcpy intrinsic | ||
524 |
2/4✓ Branch 4 → 5 taken 133 times.
✗ Branch 4 → 19 not taken.
✓ Branch 5 → 6 taken 133 times.
✗ Branch 5 → 19 not taken.
|
133 | llvm::Value *structSize = builder.getInt64(typeSize); |
525 |
1/2✓ Branch 6 → 7 taken 133 times.
✗ Branch 6 → 19 not taken.
|
133 | llvm::Value *copyVolatile = builder.getInt1(isVolatile); |
526 | |||
527 | // Call memcpy intrinsic to execute the shallow copy | ||
528 |
1/2✓ Branch 7 → 8 taken 133 times.
✗ Branch 7 → 19 not taken.
|
133 | llvm::Function *memcpyFct = stdFunctionManager.getMemcpyIntrinsic(); |
529 |
1/2✗ Branch 8 → 9 not taken.
✓ Branch 8 → 10 taken 133 times.
|
133 | assert(targetAddress != nullptr); |
530 |
3/6✓ Branch 10 → 11 taken 133 times.
✗ Branch 10 → 18 not taken.
✓ Branch 12 → 13 taken 133 times.
✗ Branch 12 → 15 not taken.
✓ Branch 13 → 14 taken 133 times.
✗ Branch 13 → 15 not taken.
|
133 | builder.CreateCall(memcpyFct, {targetAddress, oldAddress, structSize, copyVolatile}); |
531 | 133 | } | |
532 | |||
533 | 21456 | void IRGenerator::autoDeReferencePtr(llvm::Value *&ptr, QualType &symbolType) const { | |
534 |
6/6✓ Branch 13 → 14 taken 22320 times.
✓ Branch 13 → 16 taken 16007 times.
✓ Branch 15 → 16 taken 864 times.
✓ Branch 15 → 17 taken 21456 times.
✓ Branch 18 → 3 taken 16871 times.
✓ Branch 18 → 19 taken 21456 times.
|
38327 | while (symbolType.isPtr() || symbolType.isRef()) { |
535 |
3/6✓ Branch 5 → 6 taken 16871 times.
✗ Branch 5 → 22 not taken.
✓ Branch 6 → 7 taken 16871 times.
✗ Branch 6 → 20 not taken.
✓ Branch 7 → 8 taken 16871 times.
✗ Branch 7 → 20 not taken.
|
16871 | ptr = insertLoad(symbolType.toLLVMType(sourceFile), ptr); |
536 |
1/2✓ Branch 10 → 11 taken 16871 times.
✗ Branch 10 → 26 not taken.
|
16871 | symbolType = symbolType.getContained(); |
537 | } | ||
538 | 21456 | } | |
539 | |||
540 | 52 | llvm::GlobalVariable *IRGenerator::createGlobalConst(const std::string &baseName, llvm::Constant *constant) const { | |
541 | // Get unused name | ||
542 |
1/2✓ Branch 2 → 3 taken 52 times.
✗ Branch 2 → 19 not taken.
|
52 | const std::string globalName = getUnusedGlobalName(baseName); |
543 | // Create global | ||
544 |
1/2✓ Branch 5 → 6 taken 52 times.
✗ Branch 5 → 15 not taken.
|
52 | module->getOrInsertGlobal(globalName, constant->getType()); |
545 |
1/2✓ Branch 7 → 8 taken 52 times.
✗ Branch 7 → 16 not taken.
|
52 | llvm::GlobalVariable *global = module->getNamedGlobal(globalName); |
546 | // Set initializer to the given constant | ||
547 |
1/2✓ Branch 8 → 9 taken 52 times.
✗ Branch 8 → 17 not taken.
|
52 | global->setInitializer(constant); |
548 | 52 | global->setConstant(true); | |
549 |
1/2✓ Branch 10 → 11 taken 52 times.
✗ Branch 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 | 2851 | llvm::GlobalVariable *IRGenerator::createGlobalStringConst(const std::string &baseName, const std::string &value) const { | |
555 | // Get unused name | ||
556 |
1/2✓ Branch 2 → 3 taken 2851 times.
✗ Branch 2 → 21 not taken.
|
2851 | const std::string globalName = getUnusedGlobalName(baseName); |
557 | // Create global | ||
558 |
2/4✓ Branch 3 → 4 taken 2851 times.
✗ Branch 3 → 16 not taken.
✓ Branch 5 → 6 taken 2851 times.
✗ Branch 5 → 15 not taken.
|
2851 | builder.CreateGlobalString(value, globalName, 0, module); |
559 |
1/2✓ Branch 7 → 8 taken 2851 times.
✗ Branch 7 → 17 not taken.
|
2851 | llvm::GlobalVariable *global = module->getNamedGlobal(globalName); |
560 | // If the output should be comparable, fix alignment to 4 bytes | ||
561 |
1/2✓ Branch 8 → 9 taken 2851 times.
✗ Branch 8 → 12 not taken.
|
2851 | if (cliOptions.comparableOutput) |
562 |
2/4✓ Branch 9 → 10 taken 2851 times.
✗ Branch 9 → 18 not taken.
✓ Branch 10 → 11 taken 2851 times.
✗ Branch 10 → 18 not taken.
|
2851 | global->setAlignment(llvm::Align(4)); |
563 | 2851 | return global; | |
564 | 2851 | } | |
565 | |||
566 | 2851 | llvm::GlobalVariable *IRGenerator::createGlobalStringConst(const std::string &baseName, const std::string &value, | |
567 | const CodeLoc &codeLoc) const { | ||
568 | 2851 | llvm::GlobalVariable *global = createGlobalStringConst(baseName, value); | |
569 | // Create debug info | ||
570 |
2/2✓ Branch 3 → 4 taken 33 times.
✓ Branch 3 → 10 taken 2818 times.
|
2851 | if (cliOptions.generateDebugInfo) |
571 |
3/6✓ Branch 5 → 6 taken 33 times.
✗ Branch 5 → 14 not taken.
✓ Branch 6 → 7 taken 33 times.
✗ Branch 6 → 14 not taken.
✓ Branch 7 → 8 taken 33 times.
✗ Branch 7 → 12 not taken.
|
33 | diGenerator.generateGlobalStringDebugInfo(global, global->getName().str(), value.length(), codeLoc); |
572 | 2851 | return global; | |
573 | } | ||
574 | |||
575 | 4310 | std::string IRGenerator::getUnusedGlobalName(const std::string &baseName) const { | |
576 | // Find an unused global name | ||
577 | 4310 | std::string globalName; | |
578 | 4310 | unsigned int suffixNumber = 0; | |
579 | do { | ||
580 |
1/2✓ Branch 5 → 6 taken 48749 times.
✗ Branch 5 → 15 not taken.
|
48749 | globalName = baseName + std::to_string(suffixNumber); |
581 | 48749 | suffixNumber++; | |
582 |
3/4✓ Branch 10 → 11 taken 48749 times.
✗ Branch 10 → 19 not taken.
✓ Branch 11 → 12 taken 44439 times.
✓ Branch 11 → 13 taken 4310 times.
|
48749 | } while (module->getNamedGlobal(globalName) != nullptr); |
583 | 4310 | return globalName; | |
584 | ✗ | } | |
585 | |||
586 | 15817 | void IRGenerator::materializeConstant(LLVMExprResult &exprResult) { | |
587 | // Skip results, that do not contain a constant or already have a value | ||
588 |
3/4✓ Branch 2 → 3 taken 15443 times.
✓ Branch 2 → 4 taken 374 times.
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 15443 times.
|
15817 | if (exprResult.value != nullptr || exprResult.constant == nullptr) |
589 | 374 | return; | |
590 | |||
591 | // Default case: the value to the constant | ||
592 | 15443 | exprResult.value = exprResult.constant; | |
593 | } | ||
594 | |||
595 | 924 | std::string IRGenerator::getIRString(llvm::Module *llvmModule, bool comparableOutput) { | |
596 |
1/2✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 924 times.
|
924 | assert(llvmModule != nullptr); // Make sure the module hasn't been moved away |
597 | |||
598 | // Backup target triple and data layout | ||
599 | 924 | const llvm::Triple &targetTriple = llvmModule->getTargetTriple(); | |
600 |
1/2✓ Branch 6 → 7 taken 924 times.
✗ Branch 6 → 37 not taken.
|
924 | const std::string targetDataLayout = llvmModule->getDataLayoutStr(); |
601 | // Remove target triple and data layout | ||
602 |
1/2✓ Branch 7 → 8 taken 924 times.
✗ Branch 7 → 14 not taken.
|
924 | if (comparableOutput) { |
603 | 924 | llvmModule->setTargetTriple(llvm::Triple()); | |
604 |
2/4✓ Branch 11 → 12 taken 924 times.
✗ Branch 11 → 28 not taken.
✓ Branch 12 → 13 taken 924 times.
✗ Branch 12 → 28 not taken.
|
924 | llvmModule->setDataLayout(""); |
605 | } | ||
606 | |||
607 | // Get IR string | ||
608 | 924 | std::string output; | |
609 |
1/2✓ Branch 15 → 16 taken 924 times.
✗ Branch 15 → 33 not taken.
|
924 | llvm::raw_string_ostream oss(output); |
610 |
1/2✓ Branch 16 → 17 taken 924 times.
✗ Branch 16 → 31 not taken.
|
924 | llvmModule->print(oss, nullptr); |
611 | |||
612 | // Restore target triple and data layout | ||
613 |
1/2✓ Branch 17 → 18 taken 924 times.
✗ Branch 17 → 24 not taken.
|
924 | if (comparableOutput) { |
614 |
1/2✓ Branch 18 → 19 taken 924 times.
✗ Branch 18 → 29 not taken.
|
924 | llvmModule->setTargetTriple(targetTriple); |
615 |
1/2✓ Branch 22 → 23 taken 924 times.
✗ Branch 22 → 30 not taken.
|
924 | llvmModule->setDataLayout(targetDataLayout); |
616 | } | ||
617 | |||
618 | 924 | return output; | |
619 | 924 | } | |
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 | 17388 | const std::vector<const Function *> &IRGenerator::getOpFctPointers(const ASTNode *node) const { | |
628 |
1/2✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 17388 times.
|
17388 | assert(node->getOpFctPointers()->size() > manIdx); |
629 | 17388 | return node->getOpFctPointers()->at(manIdx); | |
630 | } | ||
631 | |||
632 | } // namespace spice::compiler | ||
633 |