Line | Branch | Exec | Source |
---|---|---|---|
1 | // Copyright (c) 2021-2024 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 | 678 | IRGenerator::IRGenerator(GlobalResourceManager &resourceManager, SourceFile *sourceFile) | |
16 | 678 | : CompilerPass(resourceManager, sourceFile), context(cliOptions.useLTO ? resourceManager.ltoContext : sourceFile->context), | |
17 |
1/2✓ Branch 2 taken 678 times.
✗ Branch 3 not taken.
|
678 | builder(sourceFile->builder), module(sourceFile->llvmModule.get()), conversionManager(sourceFile, this), |
18 |
5/8✓ Branch 2 taken 2 times.
✓ Branch 3 taken 676 times.
✓ Branch 5 taken 678 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 678 times.
✗ Branch 9 not taken.
✓ Branch 14 taken 678 times.
✗ Branch 15 not taken.
|
1356 | stdFunctionManager(sourceFile, resourceManager, module) { |
19 | // Attach information to the module | ||
20 |
1/2✓ Branch 2 taken 678 times.
✗ Branch 3 not taken.
|
678 | module->setTargetTriple(cliOptions.targetTriple); |
21 |
2/4✓ Branch 2 taken 678 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 678 times.
✗ Branch 6 not taken.
|
678 | module->setDataLayout(sourceFile->targetMachine->createDataLayout()); |
22 | |||
23 | // Initialize debug info generator | ||
24 |
2/2✓ Branch 0 taken 13 times.
✓ Branch 1 taken 665 times.
|
678 | if (cliOptions.generateDebugInfo) |
25 |
2/4✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 13 times.
✗ Branch 5 not taken.
|
13 | diGenerator.initialize(sourceFile->fileName, sourceFile->fileDir); |
26 | 678 | } | |
27 | |||
28 | 678 | std::any IRGenerator::visitEntry(const EntryNode *node) { | |
29 | // Generate IR | ||
30 |
1/2✓ Branch 1 taken 678 times.
✗ Branch 2 not taken.
|
678 | visitChildren(node); |
31 | |||
32 | // Generate test main if required | ||
33 |
4/4✓ Branch 0 taken 214 times.
✓ Branch 1 taken 464 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 212 times.
|
678 | if (sourceFile->isMainFile && cliOptions.generateTestMain) |
34 | 2 | generateTestMain(); | |
35 | |||
36 | // Execute deferred VTable initializations | ||
37 |
2/2✓ Branch 5 taken 249 times.
✓ Branch 6 taken 678 times.
|
927 | for (DeferredLogic &deferredVTableInit : deferredVTableInitializations) |
38 |
1/2✓ Branch 1 taken 249 times.
✗ Branch 2 not taken.
|
249 | deferredVTableInit.execute(); |
39 | |||
40 | // Finalize debug info generator | ||
41 | 678 | diGenerator.finalize(); | |
42 | |||
43 | // Verify module | ||
44 | 678 | verifyModule(node->codeLoc); | |
45 | |||
46 |
1/2✓ Branch 1 taken 678 times.
✗ Branch 2 not taken.
|
678 | return nullptr; |
47 | } | ||
48 | |||
49 | 22602 | llvm::Value *IRGenerator::insertAlloca(llvm::Type *llvmType, std::string varName) { | |
50 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 22602 times.
|
22602 | if (!cliOptions.namesForIRValues) |
51 | ✗ | varName = ""; | |
52 | |||
53 |
2/2✓ Branch 0 taken 16283 times.
✓ Branch 1 taken 6319 times.
|
22602 | if (allocaInsertInst != nullptr) { // If there is already an alloca inst, insert right after that |
54 |
2/4✓ Branch 1 taken 16283 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 16283 times.
✗ Branch 5 not taken.
|
16283 | llvm::AllocaInst *allocaInst = builder.CreateAlloca(llvmType, nullptr, varName); |
55 |
1/2✓ Branch 2 taken 16283 times.
✗ Branch 3 not taken.
|
16283 | allocaInst->setDebugLoc(llvm::DebugLoc()); |
56 | 16283 | allocaInst->moveAfter(allocaInsertInst); | |
57 | 16283 | allocaInsertInst = allocaInst; | |
58 | } else { // This is the first alloca inst in the current function -> insert at the entry block | ||
59 | // Save current basic block and move insert cursor to entry block of the current function | ||
60 | 6319 | llvm::BasicBlock *currentBlock = builder.GetInsertBlock(); | |
61 | 6319 | builder.SetInsertPoint(allocaInsertBlock); | |
62 | |||
63 | // Allocate the size of the given LLVM type | ||
64 |
2/4✓ Branch 1 taken 6319 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 6319 times.
✗ Branch 5 not taken.
|
6319 | allocaInsertInst = builder.CreateAlloca(llvmType, nullptr, varName); |
65 |
1/2✓ Branch 2 taken 6319 times.
✗ Branch 3 not taken.
|
6319 | allocaInsertInst->setDebugLoc(llvm::DebugLoc()); |
66 | |||
67 | // Restore old basic block | ||
68 | 6319 | builder.SetInsertPoint(currentBlock); | |
69 | } | ||
70 | |||
71 | // Insert lifetime start marker | ||
72 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 22602 times.
|
22602 | if (cliOptions.useLifetimeMarkers) { |
73 | ✗ | const uint64_t sizeInBytes = module->getDataLayout().getTypeAllocSize(llvmType); | |
74 | ✗ | builder.CreateLifetimeStart(allocaInsertInst, builder.getInt64(sizeInBytes)); | |
75 | } | ||
76 | |||
77 | 22602 | return allocaInsertInst; | |
78 | } | ||
79 | |||
80 | 47154 | llvm::Value *IRGenerator::insertLoad(llvm::Type *llvmType, llvm::Value *ptr, bool isVolatile, const std::string &varName) const { | |
81 |
1/2✗ Branch 2 not taken.
✓ Branch 3 taken 47154 times.
|
47154 | assert(ptr->getType()->isPointerTy()); |
82 |
5/14✓ Branch 0 taken 47154 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 47154 times.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 9 taken 47154 times.
✗ Branch 10 not taken.
✓ Branch 12 taken 47154 times.
✗ Branch 13 not taken.
✗ Branch 15 not taken.
✓ Branch 16 taken 47154 times.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
|
47154 | return builder.CreateLoad(llvmType, ptr, isVolatile, cliOptions.namesForIRValues ? varName : ""); |
83 | } | ||
84 | |||
85 | 25757 | void IRGenerator::insertStore(llvm::Value *val, llvm::Value *ptr, bool isVolatile) const { | |
86 |
1/2✗ Branch 2 not taken.
✓ Branch 3 taken 25757 times.
|
25757 | assert(ptr->getType()->isPointerTy()); |
87 | 25757 | builder.CreateStore(val, ptr, isVolatile); | |
88 | 25757 | } | |
89 | |||
90 | 16833 | llvm::Value *IRGenerator::insertInBoundsGEP(llvm::Type *type, llvm::Value *basePtr, llvm::ArrayRef<llvm::Value *> indices, | |
91 | std::string varName) const { | ||
92 |
1/2✗ Branch 2 not taken.
✓ Branch 3 taken 16833 times.
|
16833 | assert(basePtr->getType()->isPointerTy()); |
93 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 16833 times.
|
16833 | assert(!indices.empty()); |
94 |
4/6✗ Branch 1 not taken.
✓ Branch 2 taken 16833 times.
✓ Branch 6 taken 16575 times.
✓ Branch 7 taken 15239 times.
✓ Branch 9 taken 16575 times.
✗ Branch 10 not taken.
|
48647 | assert(std::ranges::all_of(indices, [](llvm::Value *index) { |
95 | llvm::Type *indexType = index->getType(); | ||
96 | return indexType->isIntegerTy(32) || indexType->isIntegerTy(64); | ||
97 | })); | ||
98 | |||
99 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 16833 times.
|
16833 | if (!cliOptions.namesForIRValues) |
100 | ✗ | varName = ""; | |
101 | |||
102 | // Insert GEP | ||
103 |
2/4✓ Branch 1 taken 16833 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 16833 times.
✗ Branch 5 not taken.
|
16833 | return builder.CreateInBoundsGEP(type, basePtr, indices, varName); |
104 | } | ||
105 | |||
106 | 380 | llvm::Value *IRGenerator::insertStructGEP(llvm::Type *type, llvm::Value *basePtr, unsigned int index, std::string varName) const { | |
107 |
1/2✗ Branch 2 not taken.
✓ Branch 3 taken 380 times.
|
380 | assert(basePtr->getType()->isPointerTy()); |
108 | |||
109 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 380 times.
|
380 | if (!cliOptions.namesForIRValues) |
110 | ✗ | varName = ""; | |
111 | |||
112 | // If we use index 0 we can use the base pointer directly | ||
113 |
2/2✓ Branch 0 taken 256 times.
✓ Branch 1 taken 124 times.
|
380 | if (index == 0) |
114 | 256 | return basePtr; | |
115 | |||
116 | // Insert GEP | ||
117 |
2/4✓ Branch 1 taken 124 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 124 times.
✗ Branch 5 not taken.
|
124 | return builder.CreateStructGEP(type, basePtr, index, varName); |
118 | } | ||
119 | |||
120 | 23404 | llvm::Value *IRGenerator::resolveValue(const ASTNode *node) { | |
121 | // Visit the given AST node | ||
122 |
2/4✓ Branch 1 taken 23404 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 23404 times.
✗ Branch 5 not taken.
|
23404 | auto exprResult = any_cast<LLVMExprResult>(visit(node)); |
123 |
1/2✓ Branch 1 taken 23404 times.
✗ Branch 2 not taken.
|
46808 | return resolveValue(node, exprResult); |
124 | } | ||
125 | |||
126 | 27719 | llvm::Value *IRGenerator::resolveValue(const ASTNode *node, LLVMExprResult &exprResult) const { | |
127 | 27719 | return resolveValue(node->getEvaluatedSymbolType(manIdx), exprResult); | |
128 | } | ||
129 | |||
130 | 59992 | llvm::Value *IRGenerator::resolveValue(const QualType &qualType, LLVMExprResult &exprResult) const { | |
131 | // Check if the value is already present | ||
132 |
2/2✓ Branch 0 taken 20577 times.
✓ Branch 1 taken 39415 times.
|
59992 | if (exprResult.value != nullptr) |
133 | 20577 | return exprResult.value; | |
134 | |||
135 | // Check if a constant is present | ||
136 |
2/2✓ Branch 0 taken 9476 times.
✓ Branch 1 taken 29939 times.
|
39415 | if (exprResult.constant != nullptr) { |
137 | 9476 | materializeConstant(exprResult); | |
138 | 9476 | return exprResult.value; | |
139 | } | ||
140 | |||
141 |
3/4✓ Branch 0 taken 417 times.
✓ Branch 1 taken 29522 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 417 times.
|
29939 | assert(exprResult.ptr != nullptr || exprResult.refPtr != nullptr); |
142 | |||
143 | // De-reference if reference type | ||
144 |
1/2✓ Branch 1 taken 29939 times.
✗ Branch 2 not taken.
|
29939 | const QualType referencedType = qualType.removeReferenceWrapper(); |
145 |
4/4✓ Branch 0 taken 421 times.
✓ Branch 1 taken 29518 times.
✓ Branch 2 taken 417 times.
✓ Branch 3 taken 4 times.
|
29939 | if (exprResult.refPtr != nullptr && exprResult.ptr == nullptr) |
146 |
6/10✓ Branch 1 taken 417 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 417 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 5 times.
✓ Branch 6 taken 412 times.
✓ Branch 8 taken 417 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 417 times.
✗ Branch 12 not taken.
|
834 | exprResult.ptr = insertLoad(builder.getPtrTy(), exprResult.refPtr, exprResult.entry && exprResult.entry->isVolatile); |
147 | |||
148 | // Load the value from the pointer | ||
149 |
1/2✓ Branch 1 taken 29939 times.
✗ Branch 2 not taken.
|
29939 | llvm::Type *valueTy = referencedType.toLLVMType(sourceFile); |
150 |
6/8✓ Branch 1 taken 29939 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 27644 times.
✓ Branch 4 taken 2295 times.
✓ Branch 5 taken 10 times.
✓ Branch 6 taken 27634 times.
✓ Branch 8 taken 29939 times.
✗ Branch 9 not taken.
|
29939 | exprResult.value = insertLoad(valueTy, exprResult.ptr, exprResult.entry && exprResult.entry->isVolatile); |
151 | |||
152 | 29939 | return exprResult.value; | |
153 | } | ||
154 | |||
155 | 1326 | llvm::Value *IRGenerator::resolveAddress(const ASTNode *node) { | |
156 | // Visit the given AST node | ||
157 |
2/4✓ Branch 1 taken 1326 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1326 times.
✗ Branch 5 not taken.
|
1326 | auto exprResult = any_cast<LLVMExprResult>(visit(node)); |
158 |
1/2✓ Branch 1 taken 1326 times.
✗ Branch 2 not taken.
|
2652 | return resolveAddress(exprResult); |
159 | } | ||
160 | |||
161 | 14701 | llvm::Value *IRGenerator::resolveAddress(LLVMExprResult &exprResult) { | |
162 | // Check if an address is already present | ||
163 |
2/2✓ Branch 0 taken 12146 times.
✓ Branch 1 taken 2555 times.
|
14701 | if (exprResult.ptr != nullptr) |
164 | 12146 | return exprResult.ptr; | |
165 | |||
166 | // Check if the reference address is already present | ||
167 |
3/4✓ Branch 0 taken 1908 times.
✓ Branch 1 taken 647 times.
✓ Branch 2 taken 1908 times.
✗ Branch 3 not taken.
|
2555 | if (exprResult.refPtr != nullptr && exprResult.ptr == nullptr) { |
168 |
6/10✓ Branch 1 taken 1908 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1903 times.
✓ Branch 4 taken 5 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1903 times.
✓ Branch 8 taken 1908 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 1908 times.
✗ Branch 12 not taken.
|
1908 | exprResult.ptr = insertLoad(builder.getPtrTy(), exprResult.refPtr, exprResult.entry && exprResult.entry->isVolatile); |
169 | 1908 | return exprResult.ptr; | |
170 | } | ||
171 | |||
172 | // If not, store the value or constant | ||
173 | 647 | materializeConstant(exprResult); | |
174 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 647 times.
|
647 | assert(exprResult.value != nullptr); |
175 |
7/12✓ Branch 0 taken 2 times.
✓ Branch 1 taken 645 times.
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 645 times.
✗ Branch 7 not taken.
✓ Branch 10 taken 647 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 645 times.
✓ Branch 14 taken 2 times.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
|
1292 | exprResult.ptr = insertAlloca(exprResult.value->getType(), exprResult.entry ? exprResult.entry->name : ""); |
176 |
3/4✓ Branch 0 taken 2 times.
✓ Branch 1 taken 645 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
|
647 | insertStore(exprResult.value, exprResult.ptr, exprResult.entry && exprResult.entry->isVolatile); |
177 | |||
178 | 647 | return exprResult.ptr; | |
179 | } | ||
180 | |||
181 | 2161 | llvm::Constant *IRGenerator::getDefaultValueForSymbolType(const QualType &symbolType) { // NOLINT(misc-no-recursion) | |
182 | // Double | ||
183 |
2/2✓ Branch 1 taken 4 times.
✓ Branch 2 taken 2157 times.
|
2161 | if (symbolType.is(TY_DOUBLE)) |
184 |
2/4✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
|
4 | return llvm::ConstantFP::get(context, llvm::APFloat(0.0)); |
185 | |||
186 | // Int | ||
187 |
2/2✓ Branch 1 taken 296 times.
✓ Branch 2 taken 1861 times.
|
2157 | if (symbolType.is(TY_INT)) |
188 | 296 | return builder.getInt32(0); | |
189 | |||
190 | // Short | ||
191 |
2/2✓ Branch 1 taken 12 times.
✓ Branch 2 taken 1849 times.
|
1861 | if (symbolType.is(TY_SHORT)) |
192 | 12 | return builder.getInt16(0); | |
193 | |||
194 | // Long | ||
195 |
2/2✓ Branch 1 taken 779 times.
✓ Branch 2 taken 1070 times.
|
1849 | if (symbolType.is(TY_LONG)) |
196 | 779 | return builder.getInt64(0); | |
197 | |||
198 | // Byte or char | ||
199 |
3/4✓ Branch 1 taken 1070 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 18 times.
✓ Branch 4 taken 1052 times.
|
1070 | if (symbolType.isOneOf({TY_BYTE, TY_CHAR})) |
200 | 18 | return builder.getInt8(0); | |
201 | |||
202 | // String | ||
203 |
2/2✓ Branch 1 taken 346 times.
✓ Branch 2 taken 706 times.
|
1052 | if (symbolType.is(TY_STRING)) |
204 |
3/6✓ Branch 1 taken 346 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 346 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 346 times.
✗ Branch 8 not taken.
|
346 | return builder.CreateGlobalStringPtr("", "", 0, module); |
205 | |||
206 | // Bool | ||
207 |
2/2✓ Branch 1 taken 25 times.
✓ Branch 2 taken 681 times.
|
706 | if (symbolType.is(TY_BOOL)) |
208 | 25 | return builder.getFalse(); | |
209 | |||
210 | // Pointer or reference | ||
211 |
3/4✓ Branch 1 taken 681 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 608 times.
✓ Branch 4 taken 73 times.
|
681 | if (symbolType.isOneOf({TY_PTR, TY_REF})) |
212 | 608 | return llvm::Constant::getNullValue(builder.getPtrTy()); | |
213 | |||
214 | // Array | ||
215 |
2/2✓ Branch 1 taken 16 times.
✓ Branch 2 taken 57 times.
|
73 | if (symbolType.isArray()) { |
216 | // Get array size | ||
217 |
1/2✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
|
16 | const size_t arraySize = symbolType.getArraySize(); |
218 | |||
219 | // Get default value for item | ||
220 |
2/4✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 16 times.
✗ Branch 5 not taken.
|
16 | llvm::Constant *defaultItemValue = getDefaultValueForSymbolType(symbolType.getContained()); |
221 | |||
222 | // Retrieve array and item type | ||
223 |
2/4✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 16 times.
✗ Branch 5 not taken.
|
16 | llvm::Type *itemType = symbolType.getContained().toLLVMType(sourceFile); |
224 |
1/2✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
|
16 | llvm::ArrayType *arrayType = llvm::ArrayType::get(itemType, arraySize); |
225 | |||
226 | // Create a constant array with n times the default value | ||
227 |
1/2✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
|
16 | const std::vector<llvm::Constant *> itemConstants(arraySize, defaultItemValue); |
228 |
1/2✓ Branch 2 taken 16 times.
✗ Branch 3 not taken.
|
16 | return llvm::ConstantArray::get(arrayType, itemConstants); |
229 | 16 | } | |
230 | |||
231 | // Function or procedure | ||
232 |
3/4✓ Branch 1 taken 57 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 28 times.
✓ Branch 4 taken 29 times.
|
57 | if (symbolType.isOneOf({TY_FUNCTION, TY_PROCEDURE})) { |
233 |
2/2✓ Branch 0 taken 7 times.
✓ Branch 1 taken 21 times.
|
28 | if (!llvmTypes.fatPtrType) |
234 |
3/6✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 7 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 7 times.
✗ Branch 9 not taken.
|
7 | llvmTypes.fatPtrType = llvm::StructType::get(context, {builder.getPtrTy(), builder.getPtrTy()}); |
235 | |||
236 |
2/4✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 28 times.
✗ Branch 5 not taken.
|
28 | llvm::Constant *ptrDefaultValue = getDefaultValueForSymbolType(QualType(TY_PTR)); |
237 |
1/2✓ Branch 2 taken 28 times.
✗ Branch 3 not taken.
|
28 | return llvm::ConstantStruct::get(llvmTypes.fatPtrType, {ptrDefaultValue, ptrDefaultValue}); |
238 | } | ||
239 | |||
240 | // Struct | ||
241 |
2/2✓ Branch 1 taken 28 times.
✓ Branch 2 taken 1 times.
|
29 | if (symbolType.is(TY_STRUCT)) { |
242 | // Retrieve field count | ||
243 |
1/2✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
|
28 | Scope *structScope = symbolType.getBodyScope(); |
244 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 28 times.
|
28 | assert(structScope != nullptr); |
245 |
1/2✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
|
28 | const size_t fieldCount = structScope->getFieldCount(); |
246 | |||
247 | // Get default values for all fields of the struct | ||
248 | 28 | std::vector<llvm::Constant *> fieldConstants; | |
249 |
1/2✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
|
28 | fieldConstants.reserve(fieldCount); |
250 | |||
251 | // Add default value for each struct field | ||
252 |
2/2✓ Branch 0 taken 65 times.
✓ Branch 1 taken 28 times.
|
93 | for (size_t i = 0; i < fieldCount; i++) { |
253 | // Get entry of the field | ||
254 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 65 times.
|
65 | const SymbolTableEntry *fieldEntry = structScope->lookupField(i); |
255 |
3/6✓ Branch 0 taken 65 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 65 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 65 times.
✗ Branch 6 not taken.
|
65 | assert(fieldEntry != nullptr && fieldEntry->isField()); |
256 | |||
257 | // Retrieve default field value | ||
258 | llvm::Constant *defaultFieldValue; | ||
259 |
7/10✓ Branch 0 taken 65 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 65 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 65 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 5 times.
✓ Branch 8 taken 60 times.
✓ Branch 9 taken 5 times.
✓ Branch 10 taken 60 times.
|
65 | if (const auto fieldNode = dynamic_cast<FieldNode *>(fieldEntry->declNode); fieldNode && fieldNode->defaultValue()) |
260 |
4/8✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 5 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 5 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 5 times.
✗ Branch 11 not taken.
|
5 | defaultFieldValue = getConst(fieldNode->defaultValue()->getCompileTimeValue(), fieldEntry->getQualType(), fieldNode); |
261 | else | ||
262 |
2/4✓ Branch 1 taken 60 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 60 times.
✗ Branch 5 not taken.
|
60 | defaultFieldValue = getDefaultValueForSymbolType(fieldEntry->getQualType()); |
263 | |||
264 |
1/2✓ Branch 1 taken 65 times.
✗ Branch 2 not taken.
|
65 | fieldConstants.push_back(defaultFieldValue); |
265 | } | ||
266 | |||
267 |
1/2✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
|
28 | const auto structType = reinterpret_cast<llvm::StructType *>(symbolType.toLLVMType(sourceFile)); |
268 |
1/2✓ Branch 2 taken 28 times.
✗ Branch 3 not taken.
|
28 | return llvm::ConstantStruct::get(structType, fieldConstants); |
269 | 28 | } | |
270 | |||
271 | // Interface | ||
272 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | if (symbolType.is(TY_INTERFACE)) { |
273 | 1 | const auto structType = reinterpret_cast<llvm::StructType *>(symbolType.toLLVMType(sourceFile)); | |
274 | 1 | return llvm::ConstantStruct::get(structType, llvm::Constant::getNullValue(builder.getPtrTy())); | |
275 | } | ||
276 | |||
277 | − | throw CompilerError(INTERNAL_ERROR, "Cannot determine default value for symbol type"); // GCOV_EXCL_LINE | |
278 | } | ||
279 | |||
280 | 9711 | llvm::Constant *IRGenerator::getConst(const CompileTimeValue &compileTimeValue, const QualType &type, const ASTNode *node) const { | |
281 |
2/2✓ Branch 1 taken 169 times.
✓ Branch 2 taken 9542 times.
|
9711 | if (type.is(TY_DOUBLE)) |
282 |
2/4✓ Branch 1 taken 169 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 169 times.
✗ Branch 5 not taken.
|
169 | return llvm::ConstantFP::get(context, llvm::APFloat(compileTimeValue.doubleValue)); |
283 | |||
284 |
2/2✓ Branch 1 taken 2448 times.
✓ Branch 2 taken 7094 times.
|
9542 | if (type.is(TY_INT)) |
285 | 2448 | return builder.getInt32(compileTimeValue.intValue); | |
286 | |||
287 |
2/2✓ Branch 1 taken 170 times.
✓ Branch 2 taken 6924 times.
|
7094 | if (type.is(TY_SHORT)) |
288 | 170 | return builder.getInt16(compileTimeValue.shortValue); | |
289 | |||
290 |
2/2✓ Branch 1 taken 4270 times.
✓ Branch 2 taken 2654 times.
|
6924 | if (type.is(TY_LONG)) |
291 | 4270 | return builder.getInt64(compileTimeValue.longValue); | |
292 | |||
293 |
3/4✓ Branch 1 taken 2654 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 576 times.
✓ Branch 4 taken 2078 times.
|
2654 | if (type.isOneOf({TY_BYTE, TY_CHAR})) |
294 | 576 | return builder.getInt8(compileTimeValue.charValue); | |
295 | |||
296 |
2/2✓ Branch 1 taken 1001 times.
✓ Branch 2 taken 1077 times.
|
2078 | if (type.is(TY_STRING)) { |
297 | 1001 | const std::string &stringValue = resourceManager.compileTimeStringValues.at(compileTimeValue.stringValueOffset); | |
298 |
2/4✓ Branch 1 taken 1001 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1001 times.
✗ Branch 5 not taken.
|
3003 | return createGlobalStringConst(ANON_GLOBAL_STRING_NAME, stringValue, node->codeLoc); |
299 | } | ||
300 | |||
301 |
1/2✓ Branch 1 taken 1077 times.
✗ Branch 2 not taken.
|
1077 | if (type.is(TY_BOOL)) |
302 | 1077 | return builder.getInt1(compileTimeValue.boolValue); | |
303 | |||
304 | ✗ | if (type.is(TY_PTR)) | |
305 | ✗ | return llvm::Constant::getNullValue(builder.getPtrTy()); | |
306 | |||
307 | − | throw CompilerError(UNHANDLED_BRANCH, "Constant fall-through"); // GCOV_EXCL_LINE | |
308 | } | ||
309 | |||
310 | 19473 | llvm::BasicBlock *IRGenerator::createBlock(const std::string &blockName /*=""*/) const { | |
311 |
2/4✓ Branch 1 taken 19473 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 19473 times.
✗ Branch 5 not taken.
|
19473 | return llvm::BasicBlock::Create(context, blockName); |
312 | } | ||
313 | |||
314 | 19473 | void IRGenerator::switchToBlock(llvm::BasicBlock *block, llvm::Function *parentFct /*=nullptr*/) { | |
315 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 19473 times.
|
19473 | assert(block->getParent() == nullptr); // Ensure that the block was not added to a function already |
316 | // If no parent function were passed, use the current function | ||
317 |
2/2✓ Branch 0 taken 13126 times.
✓ Branch 1 taken 6347 times.
|
19473 | if (!parentFct) |
318 | 13126 | parentFct = builder.GetInsertBlock()->getParent(); | |
319 | // Append block to current function | ||
320 | 19473 | parentFct->insert(parentFct->end(), block); | |
321 | // Set insert point to the block | ||
322 | 19473 | builder.SetInsertPoint(block); | |
323 | 19473 | blockAlreadyTerminated = false; | |
324 | 19473 | } | |
325 | |||
326 | 5746 | void IRGenerator::terminateBlock(const StmtLstNode *stmtLstNode) { | |
327 | 5746 | diGenerator.setSourceLocation(stmtLstNode->closingBraceCodeLoc); | |
328 | 5746 | generateScopeCleanup(stmtLstNode); | |
329 | 5746 | blockAlreadyTerminated = true; | |
330 | 5746 | } | |
331 | |||
332 | 7622 | void IRGenerator::insertJump(llvm::BasicBlock *targetBlock) { | |
333 |
2/2✓ Branch 0 taken 2441 times.
✓ Branch 1 taken 5181 times.
|
7622 | if (blockAlreadyTerminated) |
334 | 2441 | return; | |
335 | 5181 | builder.CreateBr(targetBlock); | |
336 | 5181 | blockAlreadyTerminated = true; | |
337 | } | ||
338 | |||
339 | 5243 | void IRGenerator::insertCondJump(llvm::Value *condition, llvm::BasicBlock *trueBlock, llvm::BasicBlock *falseBlock, | |
340 | Likeliness likeliness /*=UNSPECIFIED*/) { | ||
341 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 5243 times.
|
5243 | if (blockAlreadyTerminated) |
342 | ✗ | return; | |
343 | 5243 | llvm::BranchInst *jumpInst = builder.CreateCondBr(condition, trueBlock, falseBlock); | |
344 | 5243 | blockAlreadyTerminated = true; | |
345 | |||
346 |
2/2✓ Branch 0 taken 653 times.
✓ Branch 1 taken 4590 times.
|
5243 | if (likeliness != UNSPECIFIED) { |
347 | 653 | const bool likely = likeliness == LIKELY; | |
348 | 653 | llvm::Metadata *name = llvm::MDString::get(context, "branch_weights"); | |
349 |
1/2✓ Branch 0 taken 653 times.
✗ Branch 1 not taken.
|
653 | llvm::Metadata *trueBranchWeight = llvm::ConstantAsMetadata::get(builder.getInt32(likely ? 2000 : 1)); |
350 |
1/2✓ Branch 0 taken 653 times.
✗ Branch 1 not taken.
|
653 | llvm::Metadata *falseBranchWeight = llvm::ConstantAsMetadata::get(builder.getInt32(likely ? 1 : 2000)); |
351 |
1/2✓ Branch 2 taken 653 times.
✗ Branch 3 not taken.
|
653 | const auto profMetadata = llvm::MDNode::get(context, {name, trueBranchWeight, falseBranchWeight}); |
352 |
2/4✓ Branch 1 taken 653 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 653 times.
✗ Branch 5 not taken.
|
653 | jumpInst->setMetadata("prof", profMetadata); |
353 | } | ||
354 | } | ||
355 | |||
356 | 6347 | void IRGenerator::verifyFunction(const llvm::Function *fct, const CodeLoc &codeLoc) const { | |
357 | // Skip the verifying step if the verifier was disabled manually or debug info is emitted | ||
358 |
3/4✓ Branch 0 taken 6347 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 133 times.
✓ Branch 3 taken 6214 times.
|
6347 | if (cliOptions.disableVerifier || cliOptions.generateDebugInfo) |
359 | 133 | return; | |
360 | |||
361 | // Verify function | ||
362 | 6214 | std::string output; | |
363 |
1/2✓ Branch 1 taken 6214 times.
✗ Branch 2 not taken.
|
6214 | llvm::raw_string_ostream oss(output); |
364 | − | if (llvm::verifyFunction(*fct, &oss)) // LCOV_EXCL_LINE | |
365 | − | throw CompilerError(codeLoc, INVALID_FUNCTION, output); // LCOV_EXCL_LINE | |
366 | 6214 | } | |
367 | |||
368 | 678 | void IRGenerator::verifyModule(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 taken 678 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 13 times.
✓ Branch 3 taken 665 times.
|
678 | if (cliOptions.disableVerifier || cliOptions.generateDebugInfo) |
371 | 13 | return; | |
372 | |||
373 | // Verify module | ||
374 | 665 | std::string output; | |
375 |
1/2✓ Branch 1 taken 665 times.
✗ Branch 2 not taken.
|
665 | llvm::raw_string_ostream oss(output); |
376 | − | if (llvm::verifyModule(*module, &oss)) // LCOV_EXCL_LINE | |
377 | − | throw CompilerError(codeLoc, INVALID_MODULE, output); // LCOV_EXCL_LINE | |
378 | 665 | } | |
379 | |||
380 | 3949 | LLVMExprResult IRGenerator::doAssignment(const ASTNode *lhsNode, const ASTNode *rhsNode, const ASTNode *node) { | |
381 | // Get entry of left side | ||
382 |
2/4✓ Branch 1 taken 3949 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3949 times.
✗ Branch 5 not taken.
|
3949 | auto [value, constant, ptr, refPtr, entry, _] = std::any_cast<LLVMExprResult>(visit(lhsNode)); |
383 |
6/8✓ Branch 0 taken 3418 times.
✓ Branch 1 taken 531 times.
✓ Branch 3 taken 3418 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 3418 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 167 times.
✓ Branch 9 taken 3251 times.
|
3949 | llvm::Value *lhsAddress = entry != nullptr && entry->getQualType().isRef() ? refPtr : ptr; |
384 |
1/2✓ Branch 1 taken 3949 times.
✗ Branch 2 not taken.
|
7898 | return doAssignment(lhsAddress, entry, rhsNode, node); |
385 | } | ||
386 | |||
387 | 9506 | LLVMExprResult IRGenerator::doAssignment(llvm::Value *lhsAddress, SymbolTableEntry *lhsEntry, const ASTNode *rhsNode, | |
388 | const ASTNode *node, bool isDecl) { | ||
389 | // Get symbol type of right side | ||
390 |
1/2✓ Branch 1 taken 9506 times.
✗ Branch 2 not taken.
|
9506 | const QualType &rhsSType = rhsNode->getEvaluatedSymbolType(manIdx); |
391 |
2/4✓ Branch 1 taken 9506 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 9506 times.
✗ Branch 5 not taken.
|
9506 | auto rhs = std::any_cast<LLVMExprResult>(visit(rhsNode)); |
392 |
1/2✓ Branch 1 taken 9506 times.
✗ Branch 2 not taken.
|
19012 | return doAssignment(lhsAddress, lhsEntry, rhs, rhsSType, node, isDecl); |
393 | } | ||
394 | |||
395 | 9596 | LLVMExprResult IRGenerator::doAssignment(llvm::Value *lhsAddress, SymbolTableEntry *lhsEntry, LLVMExprResult &rhs, | |
396 | const QualType &rhsSType, const ASTNode *node, bool isDecl) { | ||
397 | // Deduce some information about the assignment | ||
398 |
4/4✓ Branch 0 taken 9065 times.
✓ Branch 1 taken 531 times.
✓ Branch 4 taken 353 times.
✓ Branch 5 taken 8712 times.
|
9596 | const bool isRefAssign = lhsEntry != nullptr && lhsEntry->getQualType().isRef(); |
399 |
8/10✓ Branch 0 taken 9243 times.
✓ Branch 1 taken 353 times.
✓ Branch 3 taken 9243 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 9243 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1031 times.
✓ Branch 9 taken 8212 times.
✓ Branch 11 taken 120 times.
✓ Branch 12 taken 911 times.
|
9596 | const bool needsCopy = !isRefAssign && rhsSType.removeReferenceWrapper().is(TY_STRUCT) && !rhs.isTemporary(); |
400 | |||
401 |
2/2✓ Branch 0 taken 353 times.
✓ Branch 1 taken 9243 times.
|
9596 | if (isRefAssign) { |
402 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 353 times.
|
353 | assert(lhsEntry != nullptr); |
403 |
2/2✓ Branch 0 taken 186 times.
✓ Branch 1 taken 167 times.
|
353 | if (isDecl) { // Reference gets initially assigned |
404 | // Get address of right side | ||
405 | 186 | llvm::Value *rhsAddress = resolveAddress(rhs); | |
406 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 186 times.
|
186 | assert(rhsAddress != nullptr); |
407 | |||
408 | // Store lhs pointer to rhs | ||
409 |
3/6✓ Branch 1 taken 186 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 186 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 186 times.
✗ Branch 8 not taken.
|
186 | llvm::Value *refAddress = insertAlloca(builder.getPtrTy()); |
410 | 186 | lhsEntry->updateAddress(refAddress); | |
411 | 186 | insertStore(rhsAddress, refAddress); | |
412 | |||
413 | 186 | return LLVMExprResult{.value = rhsAddress, .ptr = refAddress, .entry = lhsEntry}; | |
414 | } | ||
415 | |||
416 | // Reference to reference assignment (only for struct fields that are not initialized yet) | ||
417 |
8/8✓ Branch 1 taken 124 times.
✓ Branch 2 taken 43 times.
✓ Branch 3 taken 115 times.
✓ Branch 4 taken 9 times.
✓ Branch 6 taken 114 times.
✓ Branch 7 taken 1 times.
✓ Branch 8 taken 114 times.
✓ Branch 9 taken 53 times.
|
167 | if (rhsSType.isRef() && rhs.entry && lhsEntry->isField()) { |
418 | // Get address of right side | ||
419 | 114 | llvm::Value *referencedAddress = resolveAddress(rhs); | |
420 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 114 times.
|
114 | assert(referencedAddress != nullptr); |
421 | |||
422 | // Store the rhs* to the lhs** | ||
423 | 114 | insertStore(referencedAddress, lhsAddress); | |
424 | |||
425 | 114 | return LLVMExprResult{.value = referencedAddress, .ptr = lhsAddress, .entry = lhsEntry}; | |
426 | } | ||
427 | |||
428 | // Load referenced address | ||
429 |
3/6✓ Branch 1 taken 53 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 53 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 53 times.
✗ Branch 8 not taken.
|
106 | lhsAddress = insertLoad(builder.getPtrTy(), lhsAddress); |
430 | } | ||
431 | |||
432 | // Check if we need to copy the rhs to the lhs. This happens for structs | ||
433 |
2/2✓ Branch 0 taken 120 times.
✓ Branch 1 taken 9176 times.
|
9296 | if (needsCopy) { |
434 | // Get address of right side | ||
435 |
1/2✓ Branch 1 taken 120 times.
✗ Branch 2 not taken.
|
120 | llvm::Value *rhsAddress = resolveAddress(rhs); |
436 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 120 times.
|
120 | assert(rhsAddress != nullptr); |
437 | |||
438 | // Allocate new memory if the lhs address does not exist | ||
439 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 118 times.
|
120 | if (!lhsAddress) { |
440 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | assert(lhsEntry != nullptr); |
441 |
4/8✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 2 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 2 times.
✗ Branch 11 not taken.
|
2 | lhsAddress = insertAlloca(lhsEntry->getQualType().toLLVMType(sourceFile)); |
442 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | lhsEntry->updateAddress(lhsAddress); |
443 | } | ||
444 | |||
445 | // Check if we have a copy ctor | ||
446 |
2/4✓ Branch 1 taken 120 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 120 times.
✗ Branch 5 not taken.
|
120 | const QualType rhsSTypeNonRef = rhsSType.removeReferenceWrapper().toNonConst(); |
447 |
1/2✓ Branch 1 taken 120 times.
✗ Branch 2 not taken.
|
120 | Scope *structScope = rhsSTypeNonRef.getBodyScope(); |
448 |
2/4✓ Branch 1 taken 120 times.
✗ Branch 2 not taken.
✓ Branch 6 taken 120 times.
✗ Branch 7 not taken.
|
360 | const ArgList args = {{rhsSTypeNonRef.toConstRef(node), rhs.isTemporary()}}; |
449 |
2/4✓ Branch 1 taken 120 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 120 times.
✗ Branch 5 not taken.
|
120 | const Function *copyCtor = FunctionManager::lookup(structScope, CTOR_FUNCTION_NAME, rhsSTypeNonRef, args, true); |
450 |
2/2✓ Branch 0 taken 42 times.
✓ Branch 1 taken 78 times.
|
120 | if (copyCtor != nullptr) { |
451 | // Call copy ctor | ||
452 |
2/4✓ Branch 1 taken 42 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 42 times.
✗ Branch 5 not taken.
|
126 | generateCtorOrDtorCall(lhsAddress, copyCtor, {rhsAddress}); |
453 |
2/4✓ Branch 1 taken 78 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 78 times.
✗ Branch 4 not taken.
|
78 | } else if (rhsSTypeNonRef.isTriviallyCopyable(node)) { |
454 | // Create shallow copy | ||
455 |
1/2✓ Branch 1 taken 78 times.
✗ Branch 2 not taken.
|
78 | llvm::Type *rhsType = rhsSTypeNonRef.toLLVMType(sourceFile); |
456 |
6/10✓ Branch 0 taken 73 times.
✓ Branch 1 taken 5 times.
✓ Branch 3 taken 73 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 5 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 5 times.
✓ Branch 9 taken 73 times.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
|
83 | const std::string copyName = lhsEntry ? lhsEntry->name : ""; |
457 |
4/6✓ Branch 0 taken 73 times.
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 73 times.
✓ Branch 5 taken 78 times.
✗ Branch 6 not taken.
|
78 | generateShallowCopy(rhsAddress, rhsType, lhsAddress, lhsEntry && lhsEntry->isVolatile); |
458 | 78 | } else { | |
459 | ✗ | const std::string structName = rhsSTypeNonRef.getName(); | |
460 | ✗ | const std::string msg = "Cannot copy struct '" + structName + "', as it is not trivially copyable and has no copy ctor"; | |
461 | ✗ | throw SemanticError(node, COPY_CTOR_REQUIRED, msg); | |
462 | ✗ | } | |
463 | 120 | return LLVMExprResult{.ptr = lhsAddress, .entry = lhsEntry}; | |
464 | 120 | } | |
465 | |||
466 |
7/8✓ Branch 0 taken 5459 times.
✓ Branch 1 taken 3717 times.
✓ Branch 3 taken 771 times.
✓ Branch 4 taken 4688 times.
✓ Branch 6 taken 771 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 771 times.
✓ Branch 9 taken 8405 times.
|
9176 | if (isDecl && rhsSType.is(TY_STRUCT) && rhs.isTemporary()) { |
467 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 771 times.
|
771 | assert(lhsEntry != nullptr); |
468 | // Directly set the address to the lhs entry | ||
469 | 771 | llvm::Value *rhsAddress = resolveAddress(rhs); | |
470 | 771 | lhsEntry->updateAddress(rhsAddress); | |
471 | 771 | rhs.entry = lhsEntry; | |
472 | 771 | return rhs; | |
473 | } | ||
474 | |||
475 | // Allocate new memory if the lhs address does not exist | ||
476 |
2/2✓ Branch 0 taken 4656 times.
✓ Branch 1 taken 3749 times.
|
8405 | if (!lhsAddress) { |
477 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4656 times.
|
4656 | assert(lhsEntry != nullptr); |
478 |
4/8✓ Branch 1 taken 4656 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4656 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 4656 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 4656 times.
✗ Branch 11 not taken.
|
4656 | lhsAddress = insertAlloca(lhsEntry->getQualType().toLLVMType(sourceFile)); |
479 | 4656 | lhsEntry->updateAddress(lhsAddress); | |
480 | } | ||
481 | |||
482 | // 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 | ||
483 |
10/10✓ Branch 0 taken 7895 times.
✓ Branch 1 taken 510 times.
✓ Branch 4 taken 1559 times.
✓ Branch 5 taken 6336 times.
✓ Branch 7 taken 5 times.
✓ Branch 8 taken 1554 times.
✓ Branch 10 taken 1 times.
✓ Branch 11 taken 4 times.
✓ Branch 12 taken 1 times.
✓ Branch 13 taken 8404 times.
|
8405 | if (lhsEntry && lhsEntry->getQualType().isPtr() && rhsSType.isArray() && rhsSType.getArraySize() != ARRAY_SIZE_UNKNOWN) { |
484 | // Get address of right side | ||
485 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | llvm::Value *rhsAddress = resolveAddress(rhs); |
486 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | assert(rhsAddress != nullptr); |
487 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | llvm::Type *elementTy = rhsSType.toLLVMType(sourceFile); |
488 |
2/4✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
1 | llvm::Value *indices[2] = {builder.getInt64(0), builder.getInt32(0)}; |
489 |
2/4✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
|
1 | llvm::Value *firstItemAddress = insertInBoundsGEP(elementTy, rhsAddress, indices); |
490 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | insertStore(firstItemAddress, lhsAddress); |
491 | 1 | return LLVMExprResult{.value = rhsAddress, .ptr = lhsAddress, .entry = lhsEntry}; | |
492 | } | ||
493 | |||
494 | // We can load the value from the right side and store it to the left side | ||
495 | // Retrieve value of the right side | ||
496 | 8404 | llvm::Value *rhsValue = resolveValue(rhsSType, rhs); | |
497 | // Store the value to the address | ||
498 | 8404 | insertStore(rhsValue, lhsAddress); | |
499 | 8404 | return LLVMExprResult{.value = rhsValue, .ptr = lhsAddress, .entry = lhsEntry}; | |
500 | } | ||
501 | |||
502 | 155 | void IRGenerator::generateShallowCopy(llvm::Value *oldAddress, llvm::Type *varType, llvm::Value *targetAddress, | |
503 | bool isVolatile) const { | ||
504 | // Retrieve size to copy | ||
505 |
1/2✓ Branch 2 taken 155 times.
✗ Branch 3 not taken.
|
155 | const llvm::TypeSize typeSize = module->getDataLayout().getTypeAllocSize(varType); |
506 | |||
507 | // Create values for memcpy intrinsic | ||
508 |
2/4✓ Branch 1 taken 155 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 155 times.
✗ Branch 5 not taken.
|
155 | llvm::Value *structSize = builder.getInt64(typeSize); |
509 |
1/2✓ Branch 1 taken 155 times.
✗ Branch 2 not taken.
|
155 | llvm::Value *copyVolatile = builder.getInt1(isVolatile); |
510 | |||
511 | // Call memcpy intrinsic to execute the shallow copy | ||
512 |
1/2✓ Branch 1 taken 155 times.
✗ Branch 2 not taken.
|
155 | llvm::Function *memcpyFct = stdFunctionManager.getMemcpyIntrinsic(); |
513 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 155 times.
|
155 | assert(targetAddress != nullptr); |
514 |
3/6✓ Branch 1 taken 155 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 155 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 155 times.
✗ Branch 9 not taken.
|
155 | builder.CreateCall(memcpyFct, {targetAddress, oldAddress, structSize, copyVolatile}); |
515 | 155 | } | |
516 | |||
517 | 16278 | void IRGenerator::autoDeReferencePtr(llvm::Value *&ptr, QualType &symbolType) const { | |
518 |
6/6✓ Branch 1 taken 16892 times.
✓ Branch 2 taken 12388 times.
✓ Branch 4 taken 614 times.
✓ Branch 5 taken 16278 times.
✓ Branch 6 taken 13002 times.
✓ Branch 7 taken 16278 times.
|
29280 | while (symbolType.isPtr() || symbolType.isRef()) { |
519 |
3/6✓ Branch 1 taken 13002 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 13002 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 13002 times.
✗ Branch 8 not taken.
|
13002 | ptr = insertLoad(symbolType.toLLVMType(sourceFile), ptr); |
520 |
1/2✓ Branch 1 taken 13002 times.
✗ Branch 2 not taken.
|
13002 | symbolType = symbolType.getContained(); |
521 | } | ||
522 | 16278 | } | |
523 | |||
524 | 44 | llvm::GlobalVariable *IRGenerator::createGlobalConst(const std::string &baseName, llvm::Constant *constant) const { | |
525 | // Get unused name | ||
526 |
1/2✓ Branch 1 taken 44 times.
✗ Branch 2 not taken.
|
44 | const std::string globalName = getUnusedGlobalName(baseName); |
527 | // Create global | ||
528 |
1/2✓ Branch 3 taken 44 times.
✗ Branch 4 not taken.
|
44 | module->getOrInsertGlobal(globalName, constant->getType()); |
529 |
1/2✓ Branch 2 taken 44 times.
✗ Branch 3 not taken.
|
44 | llvm::GlobalVariable *global = module->getNamedGlobal(globalName); |
530 | // Set initializer to the given constant | ||
531 |
1/2✓ Branch 1 taken 44 times.
✗ Branch 2 not taken.
|
44 | global->setInitializer(constant); |
532 | 44 | global->setConstant(true); | |
533 |
1/2✓ Branch 1 taken 44 times.
✗ Branch 2 not taken.
|
44 | global->setLinkage(llvm::GlobalValue::PrivateLinkage); |
534 | 44 | global->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global); | |
535 | 44 | return global; | |
536 | 44 | } | |
537 | |||
538 | 1607 | llvm::Constant *IRGenerator::createGlobalStringConst(const std::string &baseName, const std::string &value, | |
539 | const CodeLoc &codeLoc) const { | ||
540 | // Get unused name | ||
541 |
1/2✓ Branch 1 taken 1607 times.
✗ Branch 2 not taken.
|
1607 | const std::string globalName = getUnusedGlobalName(baseName); |
542 | // Create global | ||
543 |
2/4✓ Branch 1 taken 1607 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 1607 times.
✗ Branch 6 not taken.
|
1607 | llvm::Constant *globalAddr = builder.CreateGlobalStringPtr(value, globalName, 0, module); |
544 |
1/2✓ Branch 2 taken 1607 times.
✗ Branch 3 not taken.
|
1607 | llvm::GlobalVariable *global = module->getNamedGlobal(globalName); |
545 | // Create debug info | ||
546 |
2/2✓ Branch 0 taken 14 times.
✓ Branch 1 taken 1593 times.
|
1607 | if (cliOptions.generateDebugInfo) |
547 |
1/2✓ Branch 2 taken 14 times.
✗ Branch 3 not taken.
|
14 | diGenerator.generateGlobalStringDebugInfo(global, globalName, value.length(), codeLoc); |
548 | 1607 | return globalAddr; | |
549 | 1607 | } | |
550 | |||
551 | 2652 | std::string IRGenerator::getUnusedGlobalName(const std::string &baseName) const { | |
552 | // Find an unused global name | ||
553 | 2652 | std::string globalName; | |
554 | 2652 | unsigned int suffixNumber = 0; | |
555 | do { | ||
556 |
1/2✓ Branch 2 taken 30701 times.
✗ Branch 3 not taken.
|
30701 | globalName = baseName + std::to_string(suffixNumber); |
557 | 30701 | suffixNumber++; | |
558 |
3/4✓ Branch 2 taken 30701 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 28049 times.
✓ Branch 5 taken 2652 times.
|
30701 | } while (module->getNamedGlobal(globalName) != nullptr); |
559 | 2652 | return globalName; | |
560 | ✗ | } | |
561 | |||
562 | 10123 | void IRGenerator::materializeConstant(LLVMExprResult &exprResult) { | |
563 | // Skip results, that do not contain a constant or already have a value | ||
564 |
3/4✓ Branch 0 taken 9763 times.
✓ Branch 1 taken 360 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 9763 times.
|
10123 | if (exprResult.value != nullptr || exprResult.constant == nullptr) |
565 | 360 | return; | |
566 | |||
567 | // Default case: the value to the constant | ||
568 | 9763 | exprResult.value = exprResult.constant; | |
569 | } | ||
570 | |||
571 | 709 | std::string IRGenerator::getIRString(llvm::Module *llvmModule, bool withoutTargetData) { | |
572 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 709 times.
|
709 | assert(llvmModule != nullptr); // Make sure the module hasn't been moved away |
573 | |||
574 | // Backup target triple and data layout | ||
575 |
1/2✓ Branch 2 taken 709 times.
✗ Branch 3 not taken.
|
709 | const std::string targetTriple = llvmModule->getTargetTriple(); |
576 |
1/2✓ Branch 2 taken 709 times.
✗ Branch 3 not taken.
|
709 | const std::string targetDataLayout = llvmModule->getDataLayoutStr(); |
577 | // Remove target triple and data layout | ||
578 |
1/2✓ Branch 0 taken 709 times.
✗ Branch 1 not taken.
|
709 | if (withoutTargetData) { |
579 |
2/4✓ Branch 1 taken 709 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 709 times.
✗ Branch 5 not taken.
|
709 | llvmModule->setTargetTriple(""); |
580 |
2/4✓ Branch 1 taken 709 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 709 times.
✗ Branch 5 not taken.
|
709 | llvmModule->setDataLayout(""); |
581 | } | ||
582 | |||
583 | // Get IR string | ||
584 | 709 | std::string output; | |
585 |
1/2✓ Branch 1 taken 709 times.
✗ Branch 2 not taken.
|
709 | llvm::raw_string_ostream oss(output); |
586 |
1/2✓ Branch 1 taken 709 times.
✗ Branch 2 not taken.
|
709 | llvmModule->print(oss, nullptr); |
587 | |||
588 | // Restore target triple and data layout | ||
589 |
1/2✓ Branch 0 taken 709 times.
✗ Branch 1 not taken.
|
709 | if (withoutTargetData) { |
590 |
1/2✓ Branch 2 taken 709 times.
✗ Branch 3 not taken.
|
709 | llvmModule->setTargetTriple(targetTriple); |
591 |
1/2✓ Branch 2 taken 709 times.
✗ Branch 3 not taken.
|
709 | llvmModule->setDataLayout(targetDataLayout); |
592 | } | ||
593 | |||
594 | 1418 | return output; | |
595 | 709 | } | |
596 | |||
597 | /** | ||
598 | * Returns the operator function list for the current manifestation and the given node | ||
599 | * | ||
600 | * @param node Node to retrieve the op fct pointer list from | ||
601 | * @return Op fct pointer list | ||
602 | */ | ||
603 | 10595 | const std::vector<const Function *> &IRGenerator::getOpFctPointers(const ASTNode *node) const { | |
604 |
1/2✗ Branch 2 not taken.
✓ Branch 3 taken 10595 times.
|
10595 | assert(node->getOpFctPointers()->size() > manIdx); |
605 | 10595 | return node->getOpFctPointers()->at(manIdx); | |
606 | } | ||
607 | |||
608 | } // namespace spice::compiler | ||
609 |