GCC Code Coverage Report


Directory: ../
File: src/irgenerator/IRGenerator.cpp
Date: 2025-02-05 01:09:36
Exec Total Coverage
Lines: 326 339 96.2%
Functions: 33 33 100.0%
Branches: 391 640 61.1%

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