src/irgenerator/IRGenerator.cpp
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | // Copyright (c) 2021-2026 ChilliBits. All rights reserved. | ||
| 2 | |||
| 3 | #include "IRGenerator.h" | ||
| 4 | |||
| 5 | #include <SourceFile.h> | ||
| 6 | #include <driver/Driver.h> | ||
| 7 | #include <global/GlobalResourceManager.h> | ||
| 8 | #include <model/Function.h> | ||
| 9 | #include <symboltablebuilder/SymbolTableBuilder.h> | ||
| 10 | #include <typechecker/FunctionManager.h> | ||
| 11 | |||
| 12 | #include <llvm/IR/Module.h> | ||
| 13 | #include <llvm/IR/Verifier.h> | ||
| 14 | |||
| 15 | namespace spice::compiler { | ||
| 16 | |||
| 17 | const std::string PRODUCER_STRING = "spice version " + std::string(SPICE_VERSION) + " (https://github.com/spicelang/spice)"; | ||
| 18 | |||
| 19 | 2175 | IRGenerator::IRGenerator(GlobalResourceManager &resourceManager, SourceFile *sourceFile) | |
| 20 | 2175 | : CompilerPass(resourceManager, sourceFile), context(cliOptions.useLTO ? resourceManager.ltoContext : sourceFile->context), | |
| 21 |
1/2✓ Branch 8 → 9 taken 2175 times.
✗ Branch 8 → 78 not taken.
|
2175 | builder(sourceFile->builder), module(sourceFile->llvmModule.get()), conversionManager(sourceFile, this), |
| 22 |
6/10✓ Branch 4 → 5 taken 2 times.
✓ Branch 4 → 6 taken 2173 times.
✓ Branch 9 → 10 taken 2175 times.
✗ Branch 9 → 78 not taken.
✓ Branch 10 → 11 taken 2175 times.
✗ Branch 10 → 78 not taken.
✓ Branch 11 → 12 taken 2175 times.
✗ Branch 11 → 76 not taken.
✓ Branch 15 → 16 taken 2175 times.
✗ Branch 15 → 72 not taken.
|
4350 | stdFunctionManager(sourceFile, resourceManager, module) { |
| 23 | // Attach information to the module | ||
| 24 |
1/2✓ Branch 19 → 20 taken 2175 times.
✗ Branch 19 → 51 not taken.
|
2175 | module->setTargetTriple(cliOptions.targetTriple); |
| 25 |
2/4✓ Branch 23 → 24 taken 2175 times.
✗ Branch 23 → 54 not taken.
✓ Branch 24 → 25 taken 2175 times.
✗ Branch 24 → 52 not taken.
|
2175 | module->setDataLayout(sourceFile->targetMachine->createDataLayout()); |
| 26 |
2/2✓ Branch 26 → 27 taken 1 time.
✓ Branch 26 → 29 taken 2174 times.
|
2175 | if (cliOptions.outputContainer == OutputContainer::SHARED_LIBRARY) { |
| 27 |
1/2✓ Branch 27 → 28 taken 1 time.
✗ Branch 27 → 64 not taken.
|
1 | module->setPICLevel(llvm::PICLevel::SmallPIC); |
| 28 |
1/2✓ Branch 28 → 31 taken 1 time.
✗ Branch 28 → 64 not taken.
|
1 | module->setPIELevel(llvm::PIELevel::Default); |
| 29 | } else { | ||
| 30 |
1/2✓ Branch 29 → 30 taken 2174 times.
✗ Branch 29 → 64 not taken.
|
2174 | module->setPICLevel(llvm::PICLevel::BigPIC); |
| 31 |
1/2✓ Branch 30 → 31 taken 2174 times.
✗ Branch 30 → 64 not taken.
|
2174 | module->setPIELevel(llvm::PIELevel::Large); |
| 32 | } | ||
| 33 |
1/2✓ Branch 31 → 32 taken 2175 times.
✗ Branch 31 → 64 not taken.
|
2175 | module->setUwtable(llvm::UWTableKind::Default); |
| 34 |
1/2✓ Branch 32 → 33 taken 2175 times.
✗ Branch 32 → 64 not taken.
|
2175 | module->setFramePointer(llvm::FramePointerKind::All); |
| 35 | |||
| 36 | // Add module identifier metadata | ||
| 37 |
2/4✓ Branch 33 → 34 taken 2175 times.
✗ Branch 33 → 55 not taken.
✓ Branch 34 → 35 taken 2175 times.
✗ Branch 34 → 55 not taken.
|
2175 | llvm::NamedMDNode *identifierMetadata = module->getOrInsertNamedMetadata("llvm.ident"); |
| 38 |
3/6✓ Branch 36 → 37 taken 2175 times.
✗ Branch 36 → 56 not taken.
✓ Branch 38 → 39 taken 2175 times.
✗ Branch 38 → 56 not taken.
✓ Branch 39 → 40 taken 2175 times.
✗ Branch 39 → 56 not taken.
|
2175 | identifierMetadata->addOperand(llvm::MDNode::get(context, llvm::MDString::get(context, PRODUCER_STRING))); |
| 39 | |||
| 40 | // Initialize common LLVM types | ||
| 41 |
4/8✓ Branch 40 → 41 taken 2175 times.
✗ Branch 40 → 59 not taken.
✓ Branch 41 → 42 taken 2175 times.
✗ Branch 41 → 59 not taken.
✓ Branch 42 → 43 taken 2175 times.
✗ Branch 42 → 59 not taken.
✓ Branch 44 → 45 taken 2175 times.
✗ Branch 44 → 59 not taken.
|
2175 | llvmTypes.lambdaFatPtrType = llvm::StructType::get(context, {builder.getPtrTy(), builder.getPtrTy(), builder.getInt64Ty()}); |
| 42 | |||
| 43 | // Initialize debug info generator | ||
| 44 |
2/2✓ Branch 45 → 46 taken 27 times.
✓ Branch 45 → 50 taken 2148 times.
|
2175 | if (cliOptions.instrumentation.generateDebugInfo) |
| 45 |
2/4✓ Branch 46 → 47 taken 27 times.
✗ Branch 46 → 63 not taken.
✓ Branch 47 → 48 taken 27 times.
✗ Branch 47 → 61 not taken.
|
27 | diGenerator.initialize(sourceFile->fileName, sourceFile->fileDir); |
| 46 | 2175 | } | |
| 47 | |||
| 48 | 2175 | std::any IRGenerator::visitEntry(const EntryNode *node) { | |
| 49 | // Generate IR | ||
| 50 |
1/2✓ Branch 2 → 3 taken 2175 times.
✗ Branch 2 → 28 not taken.
|
2175 | visitChildren(node); |
| 51 | |||
| 52 | // Generate test main if required | ||
| 53 |
4/4✓ Branch 4 → 5 taken 369 times.
✓ Branch 4 → 7 taken 1806 times.
✓ Branch 5 → 6 taken 4 times.
✓ Branch 5 → 7 taken 365 times.
|
2175 | if (sourceFile->isMainFile && cliOptions.generateTestMain) |
| 54 | 4 | generateTestMain(); | |
| 55 | |||
| 56 | // Execute deferred VTable initializations | ||
| 57 |
2/2✓ Branch 21 → 9 taken 2250 times.
✓ Branch 21 → 22 taken 2175 times.
|
6600 | for (DeferredLogic &deferredVTableInit : deferredVTableInitializations) |
| 58 |
1/2✓ Branch 11 → 12 taken 2250 times.
✗ Branch 11 → 29 not taken.
|
2250 | deferredVTableInit.execute(); |
| 59 | |||
| 60 | // Finalize debug info generator | ||
| 61 | 2175 | diGenerator.finalize(); | |
| 62 | |||
| 63 | // Verify module | ||
| 64 | 2175 | verifyModule(node->codeLoc); | |
| 65 | |||
| 66 |
1/2✓ Branch 24 → 25 taken 2175 times.
✗ Branch 24 → 30 not taken.
|
4350 | return nullptr; |
| 67 | } | ||
| 68 | |||
| 69 | 119120 | llvm::AllocaInst *IRGenerator::insertAlloca(llvm::Type *llvmType, const std::string &varName) { | |
| 70 |
2/2✓ Branch 2 → 3 taken 84458 times.
✓ Branch 2 → 8 taken 34662 times.
|
119120 | if (allocaInsertInst != nullptr) { // If there is already an alloca inst, insert right after that |
| 71 |
2/4✓ Branch 3 → 4 taken 84458 times.
✗ Branch 3 → 19 not taken.
✓ Branch 4 → 5 taken 84458 times.
✗ Branch 4 → 19 not taken.
|
84458 | llvm::AllocaInst *allocaInst = builder.CreateAlloca(llvmType, nullptr, varName); |
| 72 | 84458 | allocaInst->dropLocation(); // Part of prologue | |
| 73 | 84458 | allocaInst->moveAfter(allocaInsertInst); | |
| 74 | 84458 | allocaInsertInst = allocaInst; | |
| 75 | } else { // This is the first alloca inst in the current function -> insert at the entry block | ||
| 76 | // Save current basic block and move insert cursor to entry block of the current function | ||
| 77 | 34662 | llvm::BasicBlock *currentBlock = builder.GetInsertBlock(); | |
| 78 | 34662 | builder.SetInsertPoint(allocaInsertBlock, allocaInsertBlock->begin()); | |
| 79 | |||
| 80 | // Allocate the size of the given LLVM type | ||
| 81 |
2/4✓ Branch 11 → 12 taken 34662 times.
✗ Branch 11 → 20 not taken.
✓ Branch 12 → 13 taken 34662 times.
✗ Branch 12 → 20 not taken.
|
34662 | allocaInsertInst = builder.CreateAlloca(llvmType, nullptr, varName); |
| 82 | 34662 | allocaInsertInst->dropLocation(); // Part of prologue | |
| 83 | |||
| 84 | // Restore old basic block | ||
| 85 | 34662 | builder.SetInsertPoint(currentBlock); | |
| 86 | } | ||
| 87 | |||
| 88 | // Insert lifetime start marker | ||
| 89 |
2/2✓ Branch 15 → 16 taken 54 times.
✓ Branch 15 → 17 taken 119066 times.
|
119120 | if (cliOptions.useLifetimeMarkers) |
| 90 | 54 | builder.CreateLifetimeStart(allocaInsertInst); | |
| 91 | |||
| 92 | 119120 | return allocaInsertInst; | |
| 93 | } | ||
| 94 | |||
| 95 | 98178 | llvm::AllocaInst *IRGenerator::insertAlloca(const QualType &qualType, const std::string &varName) { | |
| 96 | 98178 | llvm::Type *llvmType = qualType.toLLVMType(sourceFile); | |
| 97 | 98178 | llvm::AllocaInst *alloca = insertAlloca(llvmType, varName); | |
| 98 | |||
| 99 | // Insert type metadata | ||
| 100 |
2/2✓ Branch 4 → 5 taken 9 times.
✓ Branch 4 → 6 taken 98169 times.
|
98178 | if (cliOptions.useTBAAMetadata) |
| 101 | 9 | mdGenerator.generateTypeMetadata(allocaInsertInst, qualType); | |
| 102 | |||
| 103 | 98178 | return alloca; | |
| 104 | } | ||
| 105 | |||
| 106 | 215844 | llvm::LoadInst *IRGenerator::insertLoad(llvm::Type *llvmType, llvm::Value *ptr, bool isVolatile, | |
| 107 | const std::string &varName) const { | ||
| 108 |
1/2✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 215844 times.
|
215844 | assert(ptr->getType()->isPointerTy()); |
| 109 |
2/4✓ Branch 6 → 7 taken 215844 times.
✗ Branch 6 → 11 not taken.
✓ Branch 7 → 8 taken 215844 times.
✗ Branch 7 → 11 not taken.
|
215844 | return builder.CreateLoad(llvmType, ptr, isVolatile, varName); |
| 110 | } | ||
| 111 | |||
| 112 | 184300 | llvm::LoadInst *IRGenerator::insertLoad(const QualType &qualType, llvm::Value *ptr, bool isVolatile, const std::string &varName) { | |
| 113 | 184300 | llvm::Type *llvmType = qualType.toLLVMType(sourceFile); | |
| 114 | 184300 | llvm::LoadInst *load = insertLoad(llvmType, ptr, isVolatile, varName); | |
| 115 |
2/2✓ Branch 4 → 5 taken 6 times.
✓ Branch 4 → 6 taken 184294 times.
|
184300 | if (cliOptions.useTBAAMetadata) |
| 116 | 6 | mdGenerator.generateTBAAMetadata(load, qualType); | |
| 117 | 184300 | return load; | |
| 118 | } | ||
| 119 | |||
| 120 | 118459 | llvm::StoreInst *IRGenerator::insertStore(llvm::Value *val, llvm::Value *ptr, bool isVolatile) const { | |
| 121 |
1/2✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 118459 times.
|
118459 | assert(ptr->getType()->isPointerTy()); |
| 122 | 118459 | return builder.CreateStore(val, ptr, isVolatile); | |
| 123 | } | ||
| 124 | |||
| 125 | 31977 | void IRGenerator::insertStore(llvm::Value *val, llvm::Value *ptr, const QualType &qualType, bool isVolatile) { | |
| 126 | 31977 | llvm::StoreInst *store = insertStore(val, ptr, isVolatile); | |
| 127 |
2/2✓ Branch 3 → 4 taken 9 times.
✓ Branch 3 → 5 taken 31968 times.
|
31977 | if (cliOptions.useTBAAMetadata) |
| 128 | 9 | mdGenerator.generateTBAAMetadata(store, qualType); | |
| 129 | 31977 | } | |
| 130 | |||
| 131 | 59769 | llvm::Value *IRGenerator::insertInBoundsGEP(llvm::Type *type, llvm::Value *basePtr, llvm::ArrayRef<llvm::Value *> indices, | |
| 132 | const std::string &varName) const { | ||
| 133 |
1/2✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 59769 times.
|
59769 | assert(basePtr->getType()->isPointerTy()); |
| 134 |
1/2✗ Branch 7 → 8 not taken.
✓ Branch 7 → 9 taken 59769 times.
|
59769 | assert(!indices.empty()); |
| 135 |
4/6✓ Branch 4 → 5 taken 59081 times.
✓ Branch 4 → 7 taken 53941 times.
✓ Branch 6 → 7 taken 59081 times.
✗ Branch 6 → 8 not taken.
✗ Branch 10 → 11 not taken.
✓ Branch 10 → 12 taken 59769 times.
|
172791 | assert(std::ranges::all_of(indices, [](const llvm::Value *index) { |
| 136 | const llvm::Type *indexType = index->getType(); | ||
| 137 | return indexType->isIntegerTy(32) || indexType->isIntegerTy(64); | ||
| 138 | })); | ||
| 139 | |||
| 140 | // Insert GEP | ||
| 141 |
2/4✓ Branch 12 → 13 taken 59769 times.
✗ Branch 12 → 17 not taken.
✓ Branch 13 → 14 taken 59769 times.
✗ Branch 13 → 17 not taken.
|
59769 | return builder.CreateInBoundsGEP(type, basePtr, indices, varName); |
| 142 | } | ||
| 143 | |||
| 144 | 25474 | llvm::Value *IRGenerator::insertStructGEP(llvm::Type *type, llvm::Value *basePtr, unsigned int index, | |
| 145 | const std::string &varName) const { | ||
| 146 |
1/2✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 25474 times.
|
25474 | assert(basePtr->getType()->isPointerTy()); |
| 147 | |||
| 148 | // If we use index 0 we can use the base pointer directly | ||
| 149 |
2/2✓ Branch 6 → 7 taken 8056 times.
✓ Branch 6 → 8 taken 17418 times.
|
25474 | if (index == 0) |
| 150 | 8056 | return basePtr; | |
| 151 | |||
| 152 | // Insert GEP | ||
| 153 |
2/4✓ Branch 8 → 9 taken 17418 times.
✗ Branch 8 → 13 not taken.
✓ Branch 9 → 10 taken 17418 times.
✗ Branch 9 → 13 not taken.
|
17418 | return builder.CreateStructGEP(type, basePtr, index, varName); |
| 154 | } | ||
| 155 | |||
| 156 | 120942 | llvm::Value *IRGenerator::resolveValue(const ExprNode *node) { | |
| 157 | // Visit the given AST node | ||
| 158 |
2/4✓ Branch 2 → 3 taken 120942 times.
✗ Branch 2 → 11 not taken.
✓ Branch 3 → 4 taken 120942 times.
✗ Branch 3 → 9 not taken.
|
120942 | auto exprResult = any_cast<LLVMExprResult>(visit(node)); |
| 159 |
1/2✓ Branch 5 → 6 taken 120942 times.
✗ Branch 5 → 12 not taken.
|
241884 | return resolveValue(node, exprResult); |
| 160 | } | ||
| 161 | |||
| 162 | 133187 | llvm::Value *IRGenerator::resolveValue(const ExprNode *node, LLVMExprResult &exprResult) { | |
| 163 | 133187 | return resolveValue(node->getEvaluatedSymbolType(manIdx), exprResult); | |
| 164 | } | ||
| 165 | |||
| 166 | 253714 | llvm::Value *IRGenerator::resolveValue(const QualType &qualType, LLVMExprResult &exprResult) { | |
| 167 | // Check if the value is already present | ||
| 168 |
2/2✓ Branch 2 → 3 taken 81888 times.
✓ Branch 2 → 4 taken 171826 times.
|
253714 | if (exprResult.value != nullptr) |
| 169 | 81888 | return exprResult.value; | |
| 170 | |||
| 171 | // Check if a constant is present | ||
| 172 |
2/2✓ Branch 4 → 5 taken 48979 times.
✓ Branch 4 → 7 taken 122847 times.
|
171826 | if (exprResult.constant != nullptr) { |
| 173 | 48979 | materializeConstant(exprResult); | |
| 174 | 48979 | return exprResult.value; | |
| 175 | } | ||
| 176 | |||
| 177 |
3/4✓ Branch 7 → 8 taken 1603 times.
✓ Branch 7 → 10 taken 121244 times.
✗ Branch 8 → 9 not taken.
✓ Branch 8 → 10 taken 1603 times.
|
122847 | assert(exprResult.ptr != nullptr || exprResult.refPtr != nullptr); |
| 178 | |||
| 179 | // De-reference if reference type | ||
| 180 |
4/4✓ Branch 10 → 11 taken 113217 times.
✓ Branch 10 → 13 taken 9630 times.
✓ Branch 11 → 12 taken 7 times.
✓ Branch 11 → 13 taken 113210 times.
|
122847 | const bool isVolatile = exprResult.entry && exprResult.entry->isVolatile; |
| 181 |
4/4✓ Branch 14 → 15 taken 1613 times.
✓ Branch 14 → 24 taken 121234 times.
✓ Branch 15 → 16 taken 1603 times.
✓ Branch 15 → 24 taken 10 times.
|
122847 | if (exprResult.refPtr != nullptr && exprResult.ptr == nullptr) |
| 182 |
2/4✓ Branch 19 → 20 taken 1603 times.
✗ Branch 19 → 34 not taken.
✓ Branch 20 → 21 taken 1603 times.
✗ Branch 20 → 34 not taken.
|
1603 | exprResult.ptr = insertLoad(builder.getPtrTy(), exprResult.refPtr, isVolatile); |
| 183 | |||
| 184 | // Load the value from the pointer | ||
| 185 |
1/2✓ Branch 24 → 25 taken 122847 times.
✗ Branch 24 → 46 not taken.
|
122847 | const QualType referencedType = qualType.removeReferenceWrapper(); |
| 186 |
1/2✓ Branch 28 → 29 taken 122847 times.
✗ Branch 28 → 40 not taken.
|
122847 | exprResult.value = insertLoad(referencedType, exprResult.ptr, isVolatile); |
| 187 | |||
| 188 | 122847 | return exprResult.value; | |
| 189 | } | ||
| 190 | |||
| 191 | 13099 | llvm::Value *IRGenerator::resolveAddress(const ASTNode *node) { | |
| 192 | // Visit the given AST node | ||
| 193 |
2/4✓ Branch 2 → 3 taken 13099 times.
✗ Branch 2 → 11 not taken.
✓ Branch 3 → 4 taken 13099 times.
✗ Branch 3 → 9 not taken.
|
13099 | auto exprResult = any_cast<LLVMExprResult>(visit(node)); |
| 194 |
1/2✓ Branch 5 → 6 taken 13099 times.
✗ Branch 5 → 12 not taken.
|
26198 | return resolveAddress(exprResult); |
| 195 | } | ||
| 196 | |||
| 197 | 96190 | llvm::Value *IRGenerator::resolveAddress(LLVMExprResult &exprResult) { | |
| 198 | // Check if an address is already present | ||
| 199 |
2/2✓ Branch 2 → 3 taken 79149 times.
✓ Branch 2 → 4 taken 17041 times.
|
96190 | if (exprResult.ptr != nullptr) |
| 200 | 79149 | return exprResult.ptr; | |
| 201 | |||
| 202 | // Check if the reference address is already present | ||
| 203 |
3/4✓ Branch 4 → 5 taken 12683 times.
✓ Branch 4 → 7 taken 4358 times.
✗ Branch 5 → 6 not taken.
✓ Branch 5 → 7 taken 12683 times.
|
17041 | const bool isVolatile = exprResult.entry && exprResult.entry->isVolatile; |
| 204 |
3/4✓ Branch 8 → 9 taken 13605 times.
✓ Branch 8 → 18 taken 3436 times.
✓ Branch 9 → 10 taken 13605 times.
✗ Branch 9 → 18 not taken.
|
17041 | if (exprResult.refPtr != nullptr && exprResult.ptr == nullptr) { |
| 205 |
2/4✓ Branch 13 → 14 taken 13605 times.
✗ Branch 13 → 35 not taken.
✓ Branch 14 → 15 taken 13605 times.
✗ Branch 14 → 35 not taken.
|
13605 | exprResult.ptr = insertLoad(builder.getPtrTy(), exprResult.refPtr, isVolatile); |
| 206 | 13605 | return exprResult.ptr; | |
| 207 | } | ||
| 208 | |||
| 209 | // If not, store the value or constant | ||
| 210 | 3436 | materializeConstant(exprResult); | |
| 211 |
1/2✗ Branch 19 → 20 not taken.
✓ Branch 19 → 21 taken 3436 times.
|
3436 | assert(exprResult.value != nullptr); |
| 212 |
7/12✓ Branch 21 → 22 taken 6 times.
✓ Branch 21 → 23 taken 3430 times.
✓ Branch 22 → 26 taken 6 times.
✗ Branch 22 → 43 not taken.
✓ Branch 25 → 26 taken 3430 times.
✗ Branch 25 → 43 not taken.
✓ Branch 27 → 28 taken 3436 times.
✗ Branch 27 → 41 not taken.
✓ Branch 29 → 30 taken 3430 times.
✓ Branch 29 → 32 taken 6 times.
✗ Branch 43 → 44 not taken.
✗ Branch 43 → 46 not taken.
|
6866 | exprResult.ptr = insertAlloca(exprResult.value->getType(), exprResult.entry ? exprResult.entry->name : ""); |
| 213 | 3436 | insertStore(exprResult.value, exprResult.ptr, isVolatile); | |
| 214 | |||
| 215 | 3436 | return exprResult.ptr; | |
| 216 | } | ||
| 217 | |||
| 218 | 7597 | llvm::Constant *IRGenerator::getDefaultValueForSymbolType(const QualType &symbolType) { // NOLINT(misc-no-recursion) | |
| 219 | // Double | ||
| 220 |
2/2✓ Branch 3 → 4 taken 18 times.
✓ Branch 3 → 9 taken 7579 times.
|
7597 | if (symbolType.is(TY_DOUBLE)) |
| 221 |
2/4✓ Branch 4 → 5 taken 18 times.
✗ Branch 4 → 129 not taken.
✓ Branch 5 → 6 taken 18 times.
✗ Branch 5 → 127 not taken.
|
18 | return llvm::ConstantFP::get(context, llvm::APFloat(0.0)); |
| 222 | |||
| 223 | // Int | ||
| 224 |
2/2✓ Branch 10 → 11 taken 741 times.
✓ Branch 10 → 13 taken 6838 times.
|
7579 | if (symbolType.is(TY_INT)) |
| 225 | 741 | return builder.getInt32(0); | |
| 226 | |||
| 227 | // Short | ||
| 228 |
2/2✓ Branch 14 → 15 taken 9 times.
✓ Branch 14 → 17 taken 6829 times.
|
6838 | if (symbolType.is(TY_SHORT)) |
| 229 | 9 | return builder.getInt16(0); | |
| 230 | |||
| 231 | // Long | ||
| 232 |
2/2✓ Branch 18 → 19 taken 2666 times.
✓ Branch 18 → 21 taken 4163 times.
|
6829 | if (symbolType.is(TY_LONG)) |
| 233 | 2666 | return builder.getInt64(0); | |
| 234 | |||
| 235 | // Byte or char | ||
| 236 |
3/4✓ Branch 21 → 22 taken 4163 times.
✗ Branch 21 → 130 not taken.
✓ Branch 22 → 23 taken 90 times.
✓ Branch 22 → 25 taken 4073 times.
|
4163 | if (symbolType.isOneOf({TY_BYTE, TY_CHAR})) |
| 237 | 90 | return builder.getInt8(0); | |
| 238 | |||
| 239 | // String | ||
| 240 |
2/2✓ Branch 26 → 27 taken 749 times.
✓ Branch 26 → 35 taken 3324 times.
|
4073 | if (symbolType.is(TY_STRING)) { |
| 241 |
3/6✓ Branch 27 → 28 taken 749 times.
✗ Branch 27 → 132 not taken.
✓ Branch 28 → 29 taken 749 times.
✗ Branch 28 → 131 not taken.
✓ Branch 29 → 30 taken 749 times.
✗ Branch 29 → 131 not taken.
|
749 | llvm::GlobalVariable *globalString = builder.CreateGlobalString("", ""); |
| 242 |
1/2✓ Branch 30 → 31 taken 749 times.
✗ Branch 30 → 34 not taken.
|
749 | if (cliOptions.comparableOutput) |
| 243 |
2/4✓ Branch 31 → 32 taken 749 times.
✗ Branch 31 → 133 not taken.
✓ Branch 32 → 33 taken 749 times.
✗ Branch 32 → 133 not taken.
|
749 | globalString->setAlignment(llvm::Align(4)); |
| 244 | 749 | return globalString; | |
| 245 | } | ||
| 246 | |||
| 247 | // Bool | ||
| 248 |
2/2✓ Branch 36 → 37 taken 88 times.
✓ Branch 36 → 39 taken 3236 times.
|
3324 | if (symbolType.is(TY_BOOL)) |
| 249 | 88 | return builder.getFalse(); | |
| 250 | |||
| 251 | // Pointer or reference | ||
| 252 |
3/4✓ Branch 39 → 40 taken 3236 times.
✗ Branch 39 → 134 not taken.
✓ Branch 40 → 41 taken 3072 times.
✓ Branch 40 → 44 taken 164 times.
|
3236 | if (symbolType.isOneOf({TY_PTR, TY_REF})) |
| 253 | 3072 | return llvm::Constant::getNullValue(builder.getPtrTy()); | |
| 254 | |||
| 255 | // Array | ||
| 256 |
2/2✓ Branch 45 → 46 taken 52 times.
✓ Branch 45 → 61 taken 112 times.
|
164 | if (symbolType.isArray()) { |
| 257 | // Get array size | ||
| 258 |
1/2✓ Branch 46 → 47 taken 52 times.
✗ Branch 46 → 143 not taken.
|
52 | const size_t arraySize = symbolType.getArraySize(); |
| 259 | |||
| 260 | // Get default value for item | ||
| 261 |
2/4✓ Branch 47 → 48 taken 52 times.
✗ Branch 47 → 135 not taken.
✓ Branch 48 → 49 taken 52 times.
✗ Branch 48 → 135 not taken.
|
52 | llvm::Constant *defaultItemValue = getDefaultValueForSymbolType(symbolType.getContained()); |
| 262 | |||
| 263 | // Retrieve array and item type | ||
| 264 |
2/4✓ Branch 49 → 50 taken 52 times.
✗ Branch 49 → 136 not taken.
✓ Branch 50 → 51 taken 52 times.
✗ Branch 50 → 136 not taken.
|
52 | llvm::Type *itemType = symbolType.getContained().toLLVMType(sourceFile); |
| 265 |
1/2✓ Branch 51 → 52 taken 52 times.
✗ Branch 51 → 143 not taken.
|
52 | llvm::ArrayType *arrayType = llvm::ArrayType::get(itemType, arraySize); |
| 266 | |||
| 267 | // Create a constant array with n times the default value | ||
| 268 |
1/2✓ Branch 54 → 55 taken 52 times.
✗ Branch 54 → 137 not taken.
|
104 | const std::vector itemConstants(arraySize, defaultItemValue); |
| 269 |
1/2✓ Branch 57 → 58 taken 52 times.
✗ Branch 57 → 140 not taken.
|
52 | return llvm::ConstantArray::get(arrayType, itemConstants); |
| 270 | 52 | } | |
| 271 | |||
| 272 | // Function or procedure | ||
| 273 |
3/4✓ Branch 61 → 62 taken 112 times.
✗ Branch 61 → 144 not taken.
✓ Branch 62 → 63 taken 58 times.
✓ Branch 62 → 70 taken 54 times.
|
112 | if (symbolType.isOneOf({TY_FUNCTION, TY_PROCEDURE})) { |
| 274 |
2/4✓ Branch 63 → 64 taken 58 times.
✗ Branch 63 → 145 not taken.
✓ Branch 64 → 65 taken 58 times.
✗ Branch 64 → 145 not taken.
|
58 | llvm::Constant *ptrDefaultValue = getDefaultValueForSymbolType(QualType(TY_PTR)); |
| 275 | 58 | llvm::Constant *sizeDefaultValue = builder.getInt64(0); | |
| 276 |
1/2✓ Branch 67 → 68 taken 58 times.
✗ Branch 67 → 146 not taken.
|
58 | return llvm::ConstantStruct::get(llvmTypes.lambdaFatPtrType, {ptrDefaultValue, ptrDefaultValue, sizeDefaultValue}); |
| 277 | } | ||
| 278 | |||
| 279 | // Struct | ||
| 280 |
2/2✓ Branch 71 → 72 taken 53 times.
✓ Branch 71 → 110 taken 1 time.
|
54 | if (symbolType.is(TY_STRUCT)) { |
| 281 | // Retrieve field count | ||
| 282 |
1/2✓ Branch 72 → 73 taken 53 times.
✗ Branch 72 → 153 not taken.
|
53 | Scope *structScope = symbolType.getBodyScope(); |
| 283 |
1/2✗ Branch 73 → 74 not taken.
✓ Branch 73 → 75 taken 53 times.
|
53 | assert(structScope != nullptr); |
| 284 |
1/2✓ Branch 75 → 76 taken 53 times.
✗ Branch 75 → 153 not taken.
|
53 | const size_t fieldCount = structScope->getFieldCount(); |
| 285 | |||
| 286 | // Get default values for all fields of the struct | ||
| 287 | 53 | std::vector<llvm::Constant *> fieldConstants; | |
| 288 |
1/2✓ Branch 76 → 77 taken 53 times.
✗ Branch 76 → 151 not taken.
|
53 | fieldConstants.reserve(fieldCount); |
| 289 | |||
| 290 | // Add default value for each struct field | ||
| 291 |
2/2✓ Branch 102 → 78 taken 108 times.
✓ Branch 102 → 103 taken 53 times.
|
161 | for (size_t i = 0; i < fieldCount; i++) { |
| 292 | // Get entry of the field | ||
| 293 |
1/2✗ Branch 78 → 79 not taken.
✓ Branch 78 → 80 taken 108 times.
|
108 | const SymbolTableEntry *fieldEntry = structScope->lookupField(i); |
| 294 |
3/6✓ Branch 83 → 84 taken 108 times.
✗ Branch 83 → 87 not taken.
✓ Branch 84 → 85 taken 108 times.
✗ Branch 84 → 149 not taken.
✓ Branch 85 → 86 taken 108 times.
✗ Branch 85 → 87 not taken.
|
108 | assert(fieldEntry != nullptr && fieldEntry->isField()); |
| 295 | |||
| 296 | // Retrieve default field value | ||
| 297 | llvm::Constant *defaultFieldValue; | ||
| 298 |
4/6✓ Branch 88 → 89 taken 108 times.
✗ Branch 88 → 90 not taken.
✓ Branch 91 → 92 taken 108 times.
✗ Branch 91 → 97 not taken.
✓ Branch 92 → 93 taken 2 times.
✓ Branch 92 → 97 taken 106 times.
|
108 | if (const auto fieldNode = dynamic_cast<FieldNode *>(fieldEntry->declNode); fieldNode && fieldNode->defaultValue) |
| 299 |
3/6✓ Branch 93 → 94 taken 2 times.
✗ Branch 93 → 149 not taken.
✓ Branch 94 → 95 taken 2 times.
✗ Branch 94 → 148 not taken.
✓ Branch 95 → 96 taken 2 times.
✗ Branch 95 → 148 not taken.
|
2 | defaultFieldValue = getConst(fieldNode->defaultValue->getCompileTimeValue(manIdx), fieldEntry->getQualType(), fieldNode); |
| 300 | else | ||
| 301 |
2/4✓ Branch 97 → 98 taken 106 times.
✗ Branch 97 → 149 not taken.
✓ Branch 98 → 99 taken 106 times.
✗ Branch 98 → 149 not taken.
|
106 | defaultFieldValue = getDefaultValueForSymbolType(fieldEntry->getQualType()); |
| 302 | |||
| 303 |
1/2✓ Branch 100 → 101 taken 108 times.
✗ Branch 100 → 149 not taken.
|
108 | fieldConstants.push_back(defaultFieldValue); |
| 304 | } | ||
| 305 | |||
| 306 |
2/4✓ Branch 103 → 104 taken 53 times.
✗ Branch 103 → 151 not taken.
✓ Branch 104 → 105 taken 53 times.
✗ Branch 104 → 151 not taken.
|
53 | const auto structType = llvm::cast<llvm::StructType>(symbolType.toLLVMType(sourceFile)); |
| 307 |
1/2✓ Branch 106 → 107 taken 53 times.
✗ Branch 106 → 150 not taken.
|
53 | return llvm::ConstantStruct::get(structType, fieldConstants); |
| 308 | 53 | } | |
| 309 | |||
| 310 | // Interface | ||
| 311 |
1/2✓ Branch 111 → 112 taken 1 time.
✗ Branch 111 → 118 not taken.
|
1 | if (symbolType.is(TY_INTERFACE)) { |
| 312 | 1 | const auto structType = llvm::cast<llvm::StructType>(symbolType.toLLVMType(sourceFile)); | |
| 313 | 1 | return llvm::ConstantStruct::get(structType, llvm::Constant::getNullValue(builder.getPtrTy())); | |
| 314 | } | ||
| 315 | |||
| 316 | − | throw CompilerError(INTERNAL_ERROR, "Cannot determine default value for symbol type"); // GCOV_EXCL_LINE | |
| 317 | } | ||
| 318 | |||
| 319 | 46389 | llvm::Constant *IRGenerator::getConst(const CompileTimeValue &compileTimeValue, const QualType &type, const ASTNode *node) const { | |
| 320 |
2/2✓ Branch 3 → 4 taken 1765 times.
✓ Branch 3 → 9 taken 44624 times.
|
46389 | if (type.is(TY_DOUBLE)) |
| 321 |
2/4✓ Branch 4 → 5 taken 1765 times.
✗ Branch 4 → 56 not taken.
✓ Branch 5 → 6 taken 1765 times.
✗ Branch 5 → 54 not taken.
|
1765 | return llvm::ConstantFP::get(context, llvm::APFloat(compileTimeValue.doubleValue)); |
| 322 | |||
| 323 |
2/2✓ Branch 10 → 11 taken 7901 times.
✓ Branch 10 → 13 taken 36723 times.
|
44624 | if (type.is(TY_INT)) |
| 324 | 7901 | return builder.getInt32(compileTimeValue.intValue); | |
| 325 | |||
| 326 |
2/2✓ Branch 14 → 15 taken 1219 times.
✓ Branch 14 → 17 taken 35504 times.
|
36723 | if (type.is(TY_SHORT)) |
| 327 | 1219 | return builder.getInt16(compileTimeValue.shortValue); | |
| 328 | |||
| 329 |
2/2✓ Branch 18 → 19 taken 16897 times.
✓ Branch 18 → 21 taken 18607 times.
|
35504 | if (type.is(TY_LONG)) |
| 330 | 16897 | return builder.getInt64(compileTimeValue.longValue); | |
| 331 | |||
| 332 |
3/4✓ Branch 21 → 22 taken 18607 times.
✗ Branch 21 → 57 not taken.
✓ Branch 22 → 23 taken 4740 times.
✓ Branch 22 → 25 taken 13867 times.
|
18607 | if (type.isOneOf({TY_BYTE, TY_CHAR})) |
| 333 | 4740 | return builder.getInt8(compileTimeValue.charValue); | |
| 334 | |||
| 335 |
2/2✓ Branch 26 → 27 taken 8919 times.
✓ Branch 26 → 36 taken 4948 times.
|
13867 | if (type.is(TY_STRING)) { |
| 336 | 8919 | const std::string &stringValue = resourceManager.compileTimeStringValues.at(compileTimeValue.stringValueOffset); | |
| 337 |
2/4✓ Branch 30 → 31 taken 8919 times.
✗ Branch 30 → 60 not taken.
✓ Branch 31 → 32 taken 8919 times.
✗ Branch 31 → 58 not taken.
|
26757 | return createGlobalStringConst(ANON_GLOBAL_STRING_NAME, stringValue, node->codeLoc); |
| 338 | } | ||
| 339 | |||
| 340 |
1/2✓ Branch 37 → 38 taken 4948 times.
✗ Branch 37 → 40 not taken.
|
4948 | if (type.is(TY_BOOL)) |
| 341 | 4948 | return builder.getInt1(compileTimeValue.boolValue); | |
| 342 | |||
| 343 | ✗ | if (type.is(TY_PTR)) | |
| 344 | ✗ | return llvm::Constant::getNullValue(builder.getPtrTy()); | |
| 345 | |||
| 346 | − | throw CompilerError(UNHANDLED_BRANCH, "Constant fall-through"); // GCOV_EXCL_LINE | |
| 347 | } | ||
| 348 | |||
| 349 | 97601 | llvm::BasicBlock *IRGenerator::createBlock(const std::string &blockName /*=""*/) const { | |
| 350 |
2/4✓ Branch 2 → 3 taken 97601 times.
✗ Branch 2 → 7 not taken.
✓ Branch 3 → 4 taken 97601 times.
✗ Branch 3 → 7 not taken.
|
97601 | return llvm::BasicBlock::Create(context, blockName); |
| 351 | } | ||
| 352 | |||
| 353 | 97601 | void IRGenerator::switchToBlock(llvm::BasicBlock *block, llvm::Function *parentFct /*=nullptr*/) { | |
| 354 |
1/2✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 97601 times.
|
97601 | assert(block->getParent() == nullptr); // Ensure that the block was not added to a function already |
| 355 | // If no parent function were passed, use the current function | ||
| 356 |
2/2✓ Branch 5 → 6 taken 62766 times.
✓ Branch 5 → 8 taken 34835 times.
|
97601 | if (!parentFct) |
| 357 | 62766 | parentFct = builder.GetInsertBlock()->getParent(); | |
| 358 | // Append block to current function | ||
| 359 | 97601 | parentFct->insert(parentFct->end(), block); | |
| 360 | // Set insert point to the block | ||
| 361 | 97601 | builder.SetInsertPoint(block); | |
| 362 | 97601 | blockAlreadyTerminated = false; | |
| 363 | 97601 | } | |
| 364 | |||
| 365 | 29496 | void IRGenerator::terminateBlock(const StmtLstNode *stmtLstNode) { | |
| 366 | 29496 | generateScopeCleanup(stmtLstNode); | |
| 367 | 29496 | blockAlreadyTerminated = true; | |
| 368 | 29496 | } | |
| 369 | |||
| 370 | 32309 | void IRGenerator::insertJump(llvm::BasicBlock *targetBlock) { | |
| 371 |
2/2✓ Branch 2 → 3 taken 9067 times.
✓ Branch 2 → 4 taken 23242 times.
|
32309 | if (blockAlreadyTerminated) |
| 372 | 9067 | return; | |
| 373 | 23242 | builder.CreateBr(targetBlock); | |
| 374 | 23242 | blockAlreadyTerminated = true; | |
| 375 | } | ||
| 376 | |||
| 377 | 26599 | void IRGenerator::insertCondJump(llvm::Value *condition, llvm::BasicBlock *trueBlock, llvm::BasicBlock *falseBlock, | |
| 378 | Likelihood likelihood /*=UNSPECIFIED*/) { | ||
| 379 |
1/2✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 26599 times.
|
26599 | if (blockAlreadyTerminated) |
| 380 | ✗ | return; | |
| 381 | 26599 | llvm::BranchInst *jumpInst = builder.CreateCondBr(condition, trueBlock, falseBlock); | |
| 382 | 26599 | blockAlreadyTerminated = true; | |
| 383 | |||
| 384 |
2/2✓ Branch 5 → 6 taken 4741 times.
✓ Branch 5 → 7 taken 21858 times.
|
26599 | if (likelihood != Likelihood::UNSPECIFIED) |
| 385 | 4741 | mdGenerator.generateBranchWeightsMetadata(jumpInst, likelihood); | |
| 386 | } | ||
| 387 | |||
| 388 | 34822 | void IRGenerator::verifyFunction(const llvm::Function *fct, const CodeLoc &codeLoc) const { | |
| 389 | // Skip the verifying step if the verifier was disabled manually or debug info is emitted | ||
| 390 |
1/2✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 34822 times.
|
34822 | if (cliOptions.disableVerifier) |
| 391 | ✗ | return; | |
| 392 | |||
| 393 | // Verify function | ||
| 394 | 34822 | std::string output; | |
| 395 |
1/2✓ Branch 5 → 6 taken 34822 times.
✗ Branch 5 → 20 not taken.
|
34822 | llvm::raw_string_ostream oss(output); |
| 396 | − | if (llvm::verifyFunction(*fct, &oss)) // LCOV_EXCL_LINE | |
| 397 | − | throw CompilerError(codeLoc, INVALID_FUNCTION, output); // LCOV_EXCL_LINE | |
| 398 | 34822 | } | |
| 399 | |||
| 400 | 2175 | void IRGenerator::verifyModule(const CodeLoc &codeLoc) const { | |
| 401 | // Skip the verifying step if the verifier was disabled manually or debug info is emitted | ||
| 402 |
1/2✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 2175 times.
|
2175 | if (cliOptions.disableVerifier) |
| 403 | ✗ | return; | |
| 404 | |||
| 405 | // Verify module | ||
| 406 | 2175 | std::string output; | |
| 407 |
1/2✓ Branch 5 → 6 taken 2175 times.
✗ Branch 5 → 20 not taken.
|
2175 | llvm::raw_string_ostream oss(output); |
| 408 | − | if (llvm::verifyModule(*module, &oss)) // LCOV_EXCL_LINE | |
| 409 | − | throw CompilerError(codeLoc, INVALID_MODULE, output); // LCOV_EXCL_LINE | |
| 410 | 2175 | } | |
| 411 | |||
| 412 | 17199 | LLVMExprResult IRGenerator::doAssignment(const ASTNode *lhsNode, const ExprNode *rhsNode, const ASTNode *node) { | |
| 413 | // Get entry of left side | ||
| 414 |
2/4✓ Branch 2 → 3 taken 17199 times.
✗ Branch 2 → 18 not taken.
✓ Branch 3 → 4 taken 17199 times.
✗ Branch 3 → 16 not taken.
|
17199 | auto exprResult = std::any_cast<LLVMExprResult>(visit(lhsNode)); |
| 415 | 17199 | const SymbolTableEntry *entry = exprResult.entry; | |
| 416 |
7/10✓ Branch 5 → 6 taken 15746 times.
✓ Branch 5 → 10 taken 1453 times.
✓ Branch 6 → 7 taken 15746 times.
✗ Branch 6 → 19 not taken.
✓ Branch 7 → 8 taken 15746 times.
✗ Branch 7 → 19 not taken.
✓ Branch 8 → 9 taken 1312 times.
✓ Branch 8 → 10 taken 14434 times.
✓ Branch 10 → 11 taken 15887 times.
✗ Branch 10 → 19 not taken.
|
17199 | llvm::Value *lhsAddress = entry != nullptr && entry->getQualType().isRef() ? exprResult.refPtr : resolveAddress(exprResult); |
| 417 |
1/2✓ Branch 12 → 13 taken 17199 times.
✗ Branch 12 → 19 not taken.
|
34398 | return doAssignment(lhsAddress, entry, rhsNode, node); |
| 418 | } | ||
| 419 | |||
| 420 | 39789 | LLVMExprResult IRGenerator::doAssignment(llvm::Value *lhsAddress, const SymbolTableEntry *lhsEntry, const ExprNode *rhsNode, | |
| 421 | const ASTNode *node, bool isDecl) { | ||
| 422 | // Get symbol type of right side | ||
| 423 |
1/2✓ Branch 2 → 3 taken 39789 times.
✗ Branch 2 → 13 not taken.
|
39789 | const QualType &rhsSType = rhsNode->getEvaluatedSymbolType(manIdx); |
| 424 |
2/4✓ Branch 3 → 4 taken 39789 times.
✗ Branch 3 → 12 not taken.
✓ Branch 4 → 5 taken 39789 times.
✗ Branch 4 → 10 not taken.
|
39789 | auto rhs = std::any_cast<LLVMExprResult>(visit(rhsNode)); |
| 425 |
1/2✓ Branch 6 → 7 taken 39789 times.
✗ Branch 6 → 13 not taken.
|
79578 | return doAssignment(lhsAddress, lhsEntry, rhs, rhsSType, node, isDecl); |
| 426 | } | ||
| 427 | |||
| 428 | 40492 | LLVMExprResult IRGenerator::doAssignment(llvm::Value *lhsAddress, const SymbolTableEntry *lhsEntry, LLVMExprResult &rhs, | |
| 429 | const QualType &rhsSType, const ASTNode *node, bool isDecl) { | ||
| 430 | // Deduce some information about the assignment | ||
| 431 |
4/4✓ Branch 2 → 3 taken 39039 times.
✓ Branch 2 → 7 taken 1453 times.
✓ Branch 5 → 6 taken 2963 times.
✓ Branch 5 → 7 taken 36076 times.
|
40492 | const bool isRefAssign = lhsEntry != nullptr && lhsEntry->getQualType().isRef(); |
| 432 | // A non-temporary struct value assigned by value needs a deep copy. This holds whether the destination is a direct | ||
| 433 | // lvalue or the value behind an already-bound reference (assign-through): the binding cases of a reference assignment | ||
| 434 | // (declaration/initial field ref/return value) all return early above before this is consumed, so the remaining | ||
| 435 | // reference assignments are assign-throughs that must copy into the referent instead of shallow-copying (which would | ||
| 436 | // alias the rhs' owned members and double-free). | ||
| 437 |
6/8✓ Branch 8 → 9 taken 40492 times.
✗ Branch 8 → 249 not taken.
✓ Branch 9 → 10 taken 40492 times.
✗ Branch 9 → 249 not taken.
✓ Branch 10 → 11 taken 8479 times.
✓ Branch 10 → 14 taken 32013 times.
✓ Branch 12 → 13 taken 1445 times.
✓ Branch 12 → 14 taken 7034 times.
|
40492 | const bool needsCopy = rhsSType.removeReferenceWrapper().is(TY_STRUCT) && !rhs.isTemporary(); |
| 438 | |||
| 439 |
2/2✓ Branch 15 → 16 taken 2963 times.
✓ Branch 15 → 57 taken 37529 times.
|
40492 | if (isRefAssign) { |
| 440 |
1/2✗ Branch 16 → 17 not taken.
✓ Branch 16 → 18 taken 2963 times.
|
2963 | assert(lhsEntry != nullptr); |
| 441 |
2/2✓ Branch 18 → 19 taken 1651 times.
✓ Branch 18 → 33 taken 1312 times.
|
2963 | if (isDecl) { // Reference gets initially assigned |
| 442 | // Store lhs pointer to rhs | ||
| 443 |
2/4✓ Branch 22 → 23 taken 1651 times.
✗ Branch 22 → 250 not taken.
✓ Branch 23 → 24 taken 1651 times.
✗ Branch 23 → 250 not taken.
|
1651 | llvm::Value *refAddress = insertAlloca(builder.getPtrTy()); |
| 444 | 1651 | updateAddress(lhsEntry, refAddress); | |
| 445 | |||
| 446 | // Generate debug info for variable declaration | ||
| 447 | 1651 | diGenerator.generateLocalVarDebugInfo(lhsEntry->name, refAddress); | |
| 448 | |||
| 449 | // Get address of right side | ||
| 450 | 1651 | llvm::Value *rhsAddress = resolveAddress(rhs); | |
| 451 |
1/2✗ Branch 29 → 30 not taken.
✓ Branch 29 → 31 taken 1651 times.
|
1651 | assert(rhsAddress != nullptr); |
| 452 | 1651 | insertStore(rhsAddress, refAddress); | |
| 453 | |||
| 454 | 1651 | return LLVMExprResult{.value = rhsAddress, .ptr = refAddress, .entry = lhsEntry}; | |
| 455 | } | ||
| 456 | |||
| 457 | // Reference to reference assignment (only for struct fields that are not initialized yet) | ||
| 458 | // These are only allowed inside a ctor body. In other cases, the value of the reference gets assigned, not the ref itself. | ||
| 459 |
7/8✓ Branch 33 → 34 taken 1048 times.
✓ Branch 33 → 40 taken 264 times.
✓ Branch 35 → 36 taken 1044 times.
✓ Branch 35 → 40 taken 4 times.
✓ Branch 36 → 37 taken 1007 times.
✓ Branch 36 → 40 taken 37 times.
✓ Branch 38 → 39 taken 1007 times.
✗ Branch 38 → 40 not taken.
|
1312 | const bool isInitialFieldRefAssign = isInCtorBody && rhsSType.isRef() && rhs.entry && lhsEntry->isField(); |
| 460 | // Assigning the result variable | ||
| 461 | 1312 | const bool isReturnValAssign = lhsEntry->name == RETURN_VARIABLE_NAME; | |
| 462 |
4/4✓ Branch 42 → 43 taken 305 times.
✓ Branch 42 → 44 taken 1007 times.
✓ Branch 43 → 44 taken 11 times.
✓ Branch 43 → 49 taken 294 times.
|
1312 | if (isInitialFieldRefAssign || isReturnValAssign) { |
| 463 | // Get address of right side | ||
| 464 | 1018 | llvm::Value *referencedAddress = resolveAddress(rhs); | |
| 465 |
1/2✗ Branch 45 → 46 not taken.
✓ Branch 45 → 47 taken 1018 times.
|
1018 | assert(referencedAddress != nullptr); |
| 466 | |||
| 467 | // Store the rhs* to the lhs** | ||
| 468 | 1018 | insertStore(referencedAddress, lhsAddress); | |
| 469 | |||
| 470 | 1018 | return LLVMExprResult{.value = referencedAddress, .ptr = lhsAddress, .entry = lhsEntry}; | |
| 471 | } | ||
| 472 | |||
| 473 | // Load referenced address | ||
| 474 |
2/4✓ Branch 52 → 53 taken 294 times.
✗ Branch 52 → 256 not taken.
✓ Branch 53 → 54 taken 294 times.
✗ Branch 53 → 256 not taken.
|
294 | lhsAddress = insertLoad(builder.getPtrTy(), lhsAddress); |
| 475 | } | ||
| 476 | |||
| 477 |
8/8✓ Branch 57 → 58 taken 21642 times.
✓ Branch 57 → 63 taken 16181 times.
✓ Branch 59 → 60 taken 3425 times.
✓ Branch 59 → 63 taken 18217 times.
✓ Branch 61 → 62 taken 3414 times.
✓ Branch 61 → 63 taken 11 times.
✓ Branch 64 → 65 taken 3414 times.
✓ Branch 64 → 71 taken 34409 times.
|
37823 | if (isDecl && rhsSType.is(TY_STRUCT) && rhs.isTemporary()) { |
| 478 |
1/2✗ Branch 65 → 66 not taken.
✓ Branch 65 → 67 taken 3414 times.
|
3414 | assert(lhsEntry != nullptr); |
| 479 | // Directly set the address to the lhs entry (temp stealing) | ||
| 480 | 3414 | llvm::Value *rhsAddress = resolveAddress(rhs); | |
| 481 | 3414 | updateAddress(lhsEntry, rhsAddress); | |
| 482 | 3414 | rhs.entry = lhsEntry; | |
| 483 | // Generate debug info for variable declaration | ||
| 484 | 3414 | diGenerator.generateLocalVarDebugInfo(lhsEntry->name, rhsAddress); | |
| 485 | 3414 | return rhs; | |
| 486 | } | ||
| 487 | |||
| 488 | // Allocate new memory if the lhs address does not exist | ||
| 489 |
2/2✓ Branch 71 → 72 taken 18008 times.
✓ Branch 71 → 83 taken 16401 times.
|
34409 | if (!lhsAddress) { |
| 490 |
1/2✗ Branch 72 → 73 not taken.
✓ Branch 72 → 74 taken 18008 times.
|
18008 | assert(lhsEntry != nullptr); |
| 491 |
2/4✓ Branch 77 → 78 taken 18008 times.
✗ Branch 77 → 262 not taken.
✓ Branch 78 → 79 taken 18008 times.
✗ Branch 78 → 262 not taken.
|
18008 | lhsAddress = insertAlloca(lhsEntry->getQualType()); |
| 492 | 18008 | updateAddress(lhsEntry, lhsAddress); | |
| 493 | // Generate debug info for variable declaration | ||
| 494 | 18008 | diGenerator.generateLocalVarDebugInfo(lhsEntry->name, lhsAddress); | |
| 495 | } | ||
| 496 | |||
| 497 | // 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 | ||
| 498 |
10/10✓ Branch 83 → 84 taken 32956 times.
✓ Branch 83 → 92 taken 1453 times.
✓ Branch 86 → 87 taken 7696 times.
✓ Branch 86 → 92 taken 25260 times.
✓ Branch 88 → 89 taken 7 times.
✓ Branch 88 → 92 taken 7689 times.
✓ Branch 90 → 91 taken 2 times.
✓ Branch 90 → 92 taken 5 times.
✓ Branch 93 → 94 taken 2 times.
✓ Branch 93 → 109 taken 34407 times.
|
34409 | if (lhsEntry && lhsEntry->getQualType().isPtr() && rhsSType.isArray() && rhsSType.getArraySize() != ARRAY_SIZE_UNKNOWN) { |
| 499 | // Get address of right side | ||
| 500 |
1/2✓ Branch 94 → 95 taken 2 times.
✗ Branch 94 → 275 not taken.
|
2 | llvm::Value *rhsAddress = resolveAddress(rhs); |
| 501 |
1/2✗ Branch 95 → 96 not taken.
✓ Branch 95 → 97 taken 2 times.
|
2 | assert(rhsAddress != nullptr); |
| 502 |
1/2✓ Branch 97 → 98 taken 2 times.
✗ Branch 97 → 275 not taken.
|
2 | llvm::Type *elementTy = rhsSType.toLLVMType(sourceFile); |
| 503 |
2/4✓ Branch 98 → 99 taken 2 times.
✗ Branch 98 → 275 not taken.
✓ Branch 99 → 100 taken 2 times.
✗ Branch 99 → 275 not taken.
|
2 | llvm::Value *indices[2] = {builder.getInt64(0), builder.getInt32(0)}; |
| 504 |
1/2✓ Branch 104 → 105 taken 2 times.
✗ Branch 104 → 268 not taken.
|
2 | llvm::Value *firstItemAddress = insertInBoundsGEP(elementTy, rhsAddress, indices); |
| 505 |
1/2✓ Branch 107 → 108 taken 2 times.
✗ Branch 107 → 275 not taken.
|
2 | insertStore(firstItemAddress, lhsAddress); |
| 506 | 2 | return LLVMExprResult{.value = rhsAddress, .ptr = lhsAddress, .entry = lhsEntry}; | |
| 507 | } | ||
| 508 | |||
| 509 | // Handle operator overloads | ||
| 510 |
6/6✓ Branch 109 → 110 taken 16181 times.
✓ Branch 109 → 113 taken 18226 times.
✓ Branch 111 → 112 taken 419 times.
✓ Branch 111 → 113 taken 15762 times.
✓ Branch 114 → 115 taken 419 times.
✓ Branch 114 → 131 taken 33988 times.
|
34407 | if (!isDecl && conversionManager.callsOverloadedOpFct(node, DEFAULT_OP_IDX)) { |
| 511 | 419 | ResolverFct lhsV = [&] { return static_cast<llvm::Value *>(nullptr); }; | |
| 512 |
1/2✓ Branch 116 → 117 taken 419 times.
✗ Branch 116 → 276 not taken.
|
419 | ResolverFct rhsV = [&] { return resolveValue(rhsSType, rhs); }; |
| 513 | 838 | ResolverFct lhsP = [&] { return lhsAddress; }; | |
| 514 | 838 | ResolverFct rhsP = [&] { return resolveAddress(rhs); }; | |
| 515 | 419 | return conversionManager.callOperatorOverloadFct<2>(node, {lhsV, lhsP, rhsV, rhsP}, DEFAULT_OP_IDX); | |
| 516 | 419 | } | |
| 517 | |||
| 518 | // Check if we need to copy the rhs to the lhs. This happens for structs | ||
| 519 |
2/2✓ Branch 131 → 132 taken 462 times.
✓ Branch 131 → 217 taken 33526 times.
|
33988 | if (needsCopy) { |
| 520 | // Get address of right side | ||
| 521 |
1/2✓ Branch 132 → 133 taken 462 times.
✗ Branch 132 → 352 not taken.
|
462 | llvm::Value *rhsAddress = resolveAddress(rhs); |
| 522 |
1/2✗ Branch 133 → 134 not taken.
✓ Branch 133 → 135 taken 462 times.
|
462 | assert(rhsAddress != nullptr); |
| 523 | |||
| 524 | // If the lhs already holds an initialized, non-trivially-destructible struct, its old value must be | ||
| 525 | // destructed before the copy overwrites it, otherwise its owning members (heap pointers, strings, ...) | ||
| 526 | // would leak. The typechecker only sets a dtor in exactly those cases. To stay correct for a self- | ||
| 527 | // assignment like 'a = a', the destruct + copy are skipped entirely when both sides share the address | ||
| 528 | // (the assignment is a no-op in that case, and destructing first would corrupt the value to copy from). | ||
| 529 |
1/2✓ Branch 135 → 136 taken 462 times.
✗ Branch 135 → 137 not taken.
|
462 | const auto *assignNode = dynamic_cast<const AssignExprNode *>(node); |
| 530 |
3/4✓ Branch 138 → 139 taken 451 times.
✓ Branch 138 → 141 taken 11 times.
✓ Branch 139 → 140 taken 451 times.
✗ Branch 139 → 352 not taken.
|
462 | const Function *lhsDtor = assignNode ? assignNode->lhsDtorFct.at(manIdx) : nullptr; |
| 531 | 462 | llvm::BasicBlock *bCopyEnd = nullptr; | |
| 532 |
2/2✓ Branch 142 → 143 taken 11 times.
✓ Branch 142 → 163 taken 451 times.
|
462 | if (lhsDtor != nullptr) { |
| 533 |
2/4✓ Branch 145 → 146 taken 11 times.
✗ Branch 145 → 296 not taken.
✓ Branch 146 → 147 taken 11 times.
✗ Branch 146 → 294 not taken.
|
22 | llvm::BasicBlock *bCopy = createBlock("assign.copy"); |
| 534 |
2/4✓ Branch 151 → 152 taken 11 times.
✗ Branch 151 → 302 not taken.
✓ Branch 152 → 153 taken 11 times.
✗ Branch 152 → 300 not taken.
|
11 | bCopyEnd = createBlock("assign.copy.end"); |
| 535 |
3/6✓ Branch 155 → 156 taken 11 times.
✗ Branch 155 → 306 not taken.
✓ Branch 156 → 157 taken 11 times.
✗ Branch 156 → 306 not taken.
✓ Branch 157 → 158 taken 11 times.
✗ Branch 157 → 306 not taken.
|
11 | insertCondJump(builder.CreateICmpEQ(lhsAddress, rhsAddress), bCopyEnd, bCopy); |
| 536 |
1/2✓ Branch 158 → 159 taken 11 times.
✗ Branch 158 → 352 not taken.
|
11 | switchToBlock(bCopy); |
| 537 |
1/2✓ Branch 160 → 161 taken 11 times.
✗ Branch 160 → 307 not taken.
|
11 | generateCtorOrDtorCall(lhsAddress, lhsDtor, {}); |
| 538 | } | ||
| 539 | |||
| 540 |
2/4✓ Branch 163 → 164 taken 462 times.
✗ Branch 163 → 310 not taken.
✓ Branch 164 → 165 taken 462 times.
✗ Branch 164 → 310 not taken.
|
462 | const QualType rhsSTypeNonRef = rhsSType.removeReferenceWrapper().toNonConst(); |
| 541 |
3/4✓ Branch 165 → 166 taken 462 times.
✗ Branch 165 → 352 not taken.
✓ Branch 166 → 167 taken 320 times.
✓ Branch 166 → 183 taken 142 times.
|
462 | if (rhsSTypeNonRef.isTriviallyCopyable(node)) { |
| 542 | // Create shallow copy | ||
| 543 |
1/2✓ Branch 167 → 168 taken 320 times.
✗ Branch 167 → 318 not taken.
|
320 | llvm::Type *rhsType = rhsSTypeNonRef.toLLVMType(sourceFile); |
| 544 |
3/10✓ Branch 168 → 169 taken 320 times.
✗ Branch 168 → 170 not taken.
✓ Branch 169 → 173 taken 320 times.
✗ Branch 169 → 311 not taken.
✗ Branch 172 → 173 not taken.
✗ Branch 172 → 311 not taken.
✗ Branch 173 → 174 not taken.
✓ Branch 173 → 176 taken 320 times.
✗ Branch 311 → 312 not taken.
✗ Branch 311 → 314 not taken.
|
320 | const std::string copyName = lhsEntry ? lhsEntry->name : ""; |
| 545 |
3/6✓ Branch 176 → 177 taken 320 times.
✗ Branch 176 → 179 not taken.
✗ Branch 177 → 178 not taken.
✓ Branch 177 → 179 taken 320 times.
✓ Branch 180 → 181 taken 320 times.
✗ Branch 180 → 316 not taken.
|
320 | generateShallowCopy(rhsAddress, rhsType, lhsAddress, lhsEntry && lhsEntry->isVolatile); |
| 546 | 320 | } else { | |
| 547 | // Check if we have a copy ctor | ||
| 548 |
1/2✓ Branch 183 → 184 taken 142 times.
✗ Branch 183 → 351 not taken.
|
142 | Scope *structScope = rhsSTypeNonRef.getBodyScope(); |
| 549 |
2/4✓ Branch 184 → 185 taken 142 times.
✗ Branch 184 → 323 not taken.
✓ Branch 189 → 190 taken 142 times.
✗ Branch 189 → 319 not taken.
|
426 | const ArgList args = {{rhsSTypeNonRef.toConstRef(node), rhs.isTemporary()}}; |
| 550 |
2/4✓ Branch 193 → 194 taken 142 times.
✗ Branch 193 → 327 not taken.
✓ Branch 194 → 195 taken 142 times.
✗ Branch 194 → 325 not taken.
|
142 | const Function *copyCtor = FunctionManager::lookup(structScope, CTOR_FUNCTION_NAME, rhsSTypeNonRef, args, true); |
| 551 |
1/2✓ Branch 197 → 198 taken 142 times.
✗ Branch 197 → 206 not taken.
|
142 | if (copyCtor != nullptr) { |
| 552 | // Call copy ctor | ||
| 553 |
2/4✓ Branch 200 → 201 taken 142 times.
✗ Branch 200 → 333 not taken.
✓ Branch 201 → 202 taken 142 times.
✗ Branch 201 → 331 not taken.
|
284 | generateCtorOrDtorCall(lhsAddress, copyCtor, {rhsAddress}); |
| 554 | } else { | ||
| 555 | ✗ | const std::string structName = rhsSTypeNonRef.getName(); | |
| 556 | ✗ | const std::string msg = "Cannot copy struct '" + structName + "', as it is not trivially copyable and has no copy ctor"; | |
| 557 | ✗ | throw SemanticError(node, COPY_CTOR_REQUIRED, msg); | |
| 558 | ✗ | } | |
| 559 | 142 | } | |
| 560 | |||
| 561 | // Close the self-assignment guard | ||
| 562 |
2/2✓ Branch 213 → 214 taken 11 times.
✓ Branch 213 → 216 taken 451 times.
|
462 | if (bCopyEnd != nullptr) { |
| 563 |
1/2✓ Branch 214 → 215 taken 11 times.
✗ Branch 214 → 352 not taken.
|
11 | insertJump(bCopyEnd); |
| 564 |
1/2✓ Branch 215 → 216 taken 11 times.
✗ Branch 215 → 352 not taken.
|
11 | switchToBlock(bCopyEnd); |
| 565 | } | ||
| 566 | 462 | return LLVMExprResult{.ptr = lhsAddress, .entry = lhsEntry}; | |
| 567 | } | ||
| 568 | |||
| 569 | // Optimization: If we have the address of both sides, we can do a memcpy instead of loading and storing the value | ||
| 570 | 33526 | llvm::Value *rhsValue = nullptr; | |
| 571 |
8/8✓ Branch 218 → 219 taken 1979 times.
✓ Branch 218 → 222 taken 31547 times.
✓ Branch 219 → 220 taken 1918 times.
✓ Branch 219 → 222 taken 61 times.
✓ Branch 220 → 221 taken 1911 times.
✓ Branch 220 → 222 taken 7 times.
✓ Branch 223 → 224 taken 1911 times.
✓ Branch 223 → 245 taken 31615 times.
|
33526 | if (rhsSType.is(TY_STRUCT) && rhs.value == nullptr && rhs.constant == nullptr) { |
| 572 | // Create shallow copy | ||
| 573 |
2/4✓ Branch 224 → 225 taken 1911 times.
✗ Branch 224 → 353 not taken.
✓ Branch 225 → 226 taken 1911 times.
✗ Branch 225 → 353 not taken.
|
1911 | const QualType rhsSTypeNonRef = rhsSType.removeReferenceWrapper().toNonConst(); |
| 574 |
1/2✓ Branch 226 → 227 taken 1911 times.
✗ Branch 226 → 361 not taken.
|
1911 | llvm::Type *rhsType = rhsSTypeNonRef.toLLVMType(sourceFile); |
| 575 |
1/2✓ Branch 227 → 228 taken 1911 times.
✗ Branch 227 → 361 not taken.
|
1911 | llvm::Value *rhsAddress = resolveAddress(rhs); |
| 576 |
1/2✗ Branch 228 → 229 not taken.
✓ Branch 228 → 230 taken 1911 times.
|
1911 | assert(rhsAddress != nullptr); |
| 577 |
6/10✓ Branch 230 → 231 taken 1903 times.
✓ Branch 230 → 232 taken 8 times.
✓ Branch 231 → 235 taken 1903 times.
✗ Branch 231 → 354 not taken.
✓ Branch 234 → 235 taken 8 times.
✗ Branch 234 → 354 not taken.
✓ Branch 235 → 236 taken 8 times.
✓ Branch 235 → 238 taken 1903 times.
✗ Branch 354 → 355 not taken.
✗ Branch 354 → 357 not taken.
|
1919 | const std::string copyName = lhsEntry ? lhsEntry->name : ""; |
| 578 |
4/6✓ Branch 238 → 239 taken 1903 times.
✓ Branch 238 → 241 taken 8 times.
✗ Branch 239 → 240 not taken.
✓ Branch 239 → 241 taken 1903 times.
✓ Branch 242 → 243 taken 1911 times.
✗ Branch 242 → 359 not taken.
|
1911 | generateShallowCopy(rhsAddress, rhsType, lhsAddress, lhsEntry && lhsEntry->isVolatile); |
| 579 | 1911 | } else { | |
| 580 | // We can load the value from the right side and store it to the left side | ||
| 581 | // Retrieve value of the right side | ||
| 582 | 31615 | rhsValue = resolveValue(rhsSType, rhs); | |
| 583 | // Store the value to the address | ||
| 584 | 31615 | insertStore(rhsValue, lhsAddress, rhsSType); | |
| 585 | } | ||
| 586 | |||
| 587 | 33526 | return LLVMExprResult{.value = rhsValue, .ptr = lhsAddress, .entry = lhsEntry}; | |
| 588 |
5/14✓ Branch 119 → 120 taken 419 times.
✗ Branch 119 → 279 not taken.
✓ Branch 120 → 121 taken 419 times.
✗ Branch 120 → 279 not taken.
✓ Branch 121 → 122 taken 419 times.
✗ Branch 121 → 279 not taken.
✓ Branch 122 → 123 taken 419 times.
✗ Branch 122 → 279 not taken.
✓ Branch 123 → 124 taken 419 times.
✗ Branch 123 → 277 not taken.
✗ Branch 279 → 280 not taken.
✗ Branch 279 → 283 not taken.
✗ Branch 281 → 282 not taken.
✗ Branch 281 → 283 not taken.
|
419 | } |
| 589 | |||
| 590 | 2616 | void IRGenerator::generateShallowCopy(llvm::Value *oldAddress, llvm::Type *varType, llvm::Value *targetAddress, | |
| 591 | bool isVolatile) const { | ||
| 592 | // Retrieve size to copy | ||
| 593 |
1/2✓ Branch 3 → 4 taken 2616 times.
✗ Branch 3 → 19 not taken.
|
2616 | const llvm::TypeSize typeSize = module->getDataLayout().getTypeAllocSize(varType); |
| 594 | |||
| 595 | // Create values for memcpy intrinsic | ||
| 596 |
2/4✓ Branch 4 → 5 taken 2616 times.
✗ Branch 4 → 19 not taken.
✓ Branch 5 → 6 taken 2616 times.
✗ Branch 5 → 19 not taken.
|
2616 | llvm::Value *structSize = builder.getInt64(typeSize); |
| 597 |
1/2✓ Branch 6 → 7 taken 2616 times.
✗ Branch 6 → 19 not taken.
|
2616 | llvm::Value *copyVolatile = builder.getInt1(isVolatile); |
| 598 | |||
| 599 | // Call memcpy intrinsic to execute the shallow copy | ||
| 600 |
1/2✓ Branch 7 → 8 taken 2616 times.
✗ Branch 7 → 19 not taken.
|
2616 | llvm::Function *memcpyFct = stdFunctionManager.getMemcpyIntrinsic(); |
| 601 |
1/2✗ Branch 8 → 9 not taken.
✓ Branch 8 → 10 taken 2616 times.
|
2616 | assert(targetAddress != nullptr); |
| 602 |
3/6✓ Branch 10 → 11 taken 2616 times.
✗ Branch 10 → 18 not taken.
✓ Branch 12 → 13 taken 2616 times.
✗ Branch 12 → 15 not taken.
✓ Branch 13 → 14 taken 2616 times.
✗ Branch 13 → 15 not taken.
|
2616 | builder.CreateCall(memcpyFct, {targetAddress, oldAddress, structSize, copyVolatile}); |
| 603 | 2616 | } | |
| 604 | |||
| 605 | 84842 | void IRGenerator::autoDeReferencePtr(llvm::Value *&ptr, QualType &symbolType) { | |
| 606 |
6/6✓ Branch 12 → 13 taken 89672 times.
✓ Branch 12 → 15 taken 56623 times.
✓ Branch 14 → 15 taken 4830 times.
✓ Branch 14 → 16 taken 84842 times.
✓ Branch 17 → 3 taken 61453 times.
✓ Branch 17 → 18 taken 84842 times.
|
146295 | while (symbolType.isPtr() || symbolType.isRef()) { |
| 607 |
1/2✓ Branch 6 → 7 taken 61453 times.
✗ Branch 6 → 19 not taken.
|
61453 | ptr = insertLoad(symbolType, ptr); |
| 608 |
1/2✓ Branch 9 → 10 taken 61453 times.
✗ Branch 9 → 25 not taken.
|
61453 | symbolType = symbolType.getContained(); |
| 609 | } | ||
| 610 | 84842 | } | |
| 611 | |||
| 612 | 298 | llvm::GlobalVariable *IRGenerator::createGlobalConst(const std::string &baseName, llvm::Constant *constant) const { | |
| 613 | // Get unused name | ||
| 614 |
1/2✓ Branch 2 → 3 taken 298 times.
✗ Branch 2 → 19 not taken.
|
298 | const std::string globalName = getUnusedGlobalName(baseName); |
| 615 | // Create global | ||
| 616 |
1/2✓ Branch 5 → 6 taken 298 times.
✗ Branch 5 → 15 not taken.
|
298 | module->getOrInsertGlobal(globalName, constant->getType()); |
| 617 |
1/2✓ Branch 7 → 8 taken 298 times.
✗ Branch 7 → 16 not taken.
|
298 | llvm::GlobalVariable *global = module->getNamedGlobal(globalName); |
| 618 | // Set initializer to the given constant | ||
| 619 |
1/2✓ Branch 8 → 9 taken 298 times.
✗ Branch 8 → 17 not taken.
|
298 | global->setInitializer(constant); |
| 620 | 298 | global->setConstant(true); | |
| 621 |
1/2✓ Branch 10 → 11 taken 298 times.
✗ Branch 10 → 17 not taken.
|
298 | global->setLinkage(llvm::GlobalValue::PrivateLinkage); |
| 622 | 298 | global->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global); | |
| 623 | 298 | return global; | |
| 624 | 298 | } | |
| 625 | |||
| 626 | 10183 | llvm::GlobalVariable *IRGenerator::createGlobalStringConst(const std::string &baseName, const std::string &value) const { | |
| 627 | // Get unused name | ||
| 628 |
1/2✓ Branch 2 → 3 taken 10183 times.
✗ Branch 2 → 21 not taken.
|
10183 | const std::string globalName = getUnusedGlobalName(baseName); |
| 629 | // Create global | ||
| 630 |
2/4✓ Branch 3 → 4 taken 10183 times.
✗ Branch 3 → 16 not taken.
✓ Branch 5 → 6 taken 10183 times.
✗ Branch 5 → 15 not taken.
|
10183 | builder.CreateGlobalString(value, globalName, 0, module); |
| 631 |
1/2✓ Branch 7 → 8 taken 10183 times.
✗ Branch 7 → 17 not taken.
|
10183 | llvm::GlobalVariable *global = module->getNamedGlobal(globalName); |
| 632 | // If the output should be comparable, fix alignment to 4 bytes | ||
| 633 |
1/2✓ Branch 8 → 9 taken 10183 times.
✗ Branch 8 → 12 not taken.
|
10183 | if (cliOptions.comparableOutput) |
| 634 |
2/4✓ Branch 9 → 10 taken 10183 times.
✗ Branch 9 → 18 not taken.
✓ Branch 10 → 11 taken 10183 times.
✗ Branch 10 → 18 not taken.
|
10183 | global->setAlignment(llvm::Align(4)); |
| 635 | 10183 | return global; | |
| 636 | 10183 | } | |
| 637 | |||
| 638 | 10183 | llvm::GlobalVariable *IRGenerator::createGlobalStringConst(const std::string &baseName, const std::string &value, | |
| 639 | const CodeLoc &codeLoc) const { | ||
| 640 | 10183 | llvm::GlobalVariable *global = createGlobalStringConst(baseName, value); | |
| 641 | // Create debug info | ||
| 642 |
2/2✓ Branch 3 → 4 taken 52 times.
✓ Branch 3 → 10 taken 10131 times.
|
10183 | if (cliOptions.instrumentation.generateDebugInfo) |
| 643 |
3/6✓ Branch 5 → 6 taken 52 times.
✗ Branch 5 → 14 not taken.
✓ Branch 6 → 7 taken 52 times.
✗ Branch 6 → 14 not taken.
✓ Branch 7 → 8 taken 52 times.
✗ Branch 7 → 12 not taken.
|
52 | diGenerator.generateGlobalStringDebugInfo(global, global->getName().str(), value.length(), codeLoc); |
| 644 | 10183 | return global; | |
| 645 | } | ||
| 646 | |||
| 647 | 17428 | std::string IRGenerator::getUnusedGlobalName(const std::string &baseName) const { | |
| 648 | // Find an unused global name | ||
| 649 | 17428 | std::string globalName; | |
| 650 | 17428 | unsigned int suffixNumber = 0; | |
| 651 | do { | ||
| 652 |
1/2✓ Branch 5 → 6 taken 675053 times.
✗ Branch 5 → 15 not taken.
|
675053 | globalName = baseName + std::to_string(suffixNumber); |
| 653 | 675053 | suffixNumber++; | |
| 654 |
3/4✓ Branch 10 → 11 taken 675053 times.
✗ Branch 10 → 19 not taken.
✓ Branch 11 → 12 taken 657625 times.
✓ Branch 11 → 13 taken 17428 times.
|
675053 | } while (module->getNamedGlobal(globalName) != nullptr); |
| 655 | 17428 | return globalName; | |
| 656 | ✗ | } | |
| 657 | |||
| 658 | 52415 | void IRGenerator::materializeConstant(LLVMExprResult &exprResult) { | |
| 659 | // Skip results, that do not contain a constant or already have a value | ||
| 660 |
3/4✓ Branch 2 → 3 taken 50088 times.
✓ Branch 2 → 4 taken 2327 times.
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 50088 times.
|
52415 | if (exprResult.value != nullptr || exprResult.constant == nullptr) |
| 661 | 2327 | return; | |
| 662 | |||
| 663 | // Default case: the value to the constant | ||
| 664 | 50088 | exprResult.value = exprResult.constant; | |
| 665 | } | ||
| 666 | |||
| 667 | 42424 | bool IRGenerator::isSymbolDSOLocal(bool isPublic) const { | |
| 668 | // If we are compiling a shared library and export the global symbol, we need to drop dso_local | ||
| 669 | // because it may be interposed by other shared objects by the dynamic linker. | ||
| 670 |
3/4✓ Branch 2 → 3 taken 38582 times.
✓ Branch 2 → 4 taken 3842 times.
✓ Branch 3 → 4 taken 38582 times.
✗ Branch 3 → 5 not taken.
|
42424 | return !(isPublic && cliOptions.outputContainer == OutputContainer::SHARED_LIBRARY); |
| 671 | } | ||
| 672 | |||
| 673 | 14631 | llvm::GlobalValue::LinkageTypes IRGenerator::getSymbolLinkageType(bool isPublic) const { | |
| 674 |
2/2✓ Branch 2 → 3 taken 11962 times.
✓ Branch 2 → 4 taken 2669 times.
|
14631 | return isPublic ? llvm::GlobalValue::ExternalLinkage : llvm::GlobalValue::PrivateLinkage; |
| 675 | } | ||
| 676 | |||
| 677 | 6750 | llvm::GlobalValue::LinkageTypes IRGenerator::getVTableLinkageType(bool isPublic) const { | |
| 678 | // VTables, type infos and type info names are ODR entities that may legitimately be emitted in more than one | ||
| 679 | // translation unit (e.g. an interface that is defined in one file and used from several importing files). Giving | ||
| 680 | // them weak ODR linkage lets the linker coalesce the duplicates. On ELF this pairs with the comdat group below; on | ||
| 681 | // MachO, which has no comdat support, the weak/coalesced linkage is what prevents a duplicate-symbol error. | ||
| 682 |
2/2✓ Branch 2 → 3 taken 6669 times.
✓ Branch 2 → 4 taken 81 times.
|
6750 | return isPublic ? llvm::GlobalValue::WeakODRLinkage : llvm::GlobalValue::PrivateLinkage; |
| 683 | } | ||
| 684 | |||
| 685 | 6750 | void IRGenerator::attachComdatToSymbol(llvm::GlobalVariable *global, const std::string &comdatName, bool isPublic) const { | |
| 686 | // MachO does not support comdat annotations | ||
| 687 |
6/6✓ Branch 2 → 3 taken 6669 times.
✓ Branch 2 → 6 taken 81 times.
✓ Branch 4 → 5 taken 6654 times.
✓ Branch 4 → 6 taken 15 times.
✓ Branch 7 → 8 taken 6654 times.
✓ Branch 7 → 12 taken 96 times.
|
6750 | if (isPublic && cliOptions.targetTriple.getObjectFormat() != llvm::Triple::MachO) |
| 688 |
2/4✓ Branch 9 → 10 taken 6654 times.
✗ Branch 9 → 13 not taken.
✓ Branch 10 → 11 taken 6654 times.
✗ Branch 10 → 13 not taken.
|
6654 | global->setComdat(module->getOrInsertComdat(comdatName)); |
| 689 | 6750 | } | |
| 690 | |||
| 691 | 208974 | llvm::Value *IRGenerator::getAddress(const SymbolTableEntry *entry) { | |
| 692 |
1/2✓ Branch 2 → 3 taken 208974 times.
✗ Branch 2 → 18 not taken.
|
208974 | const auto it = addressMap.find(entry); |
| 693 |
5/6✓ Branch 5 → 6 taken 208924 times.
✓ Branch 5 → 9 taken 50 times.
✗ Branch 8 → 9 not taken.
✓ Branch 8 → 10 taken 208924 times.
✓ Branch 11 → 12 taken 50 times.
✓ Branch 11 → 13 taken 208924 times.
|
208974 | if (it == addressMap.end() || it->second.empty()) |
| 694 | 50 | return nullptr; | |
| 695 | 208924 | return it->second.top(); | |
| 696 | } | ||
| 697 | |||
| 698 | 166869 | void IRGenerator::updateAddress(const SymbolTableEntry *entry, llvm::Value *address) { | |
| 699 |
1/2✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 166869 times.
|
166869 | assert(address != nullptr); |
| 700 |
1/2✗ Branch 6 → 7 not taken.
✓ Branch 6 → 8 taken 166869 times.
|
166869 | assert(address->getType()->isPointerTy()); |
| 701 | 166869 | auto &stack = addressMap[entry]; | |
| 702 |
2/2✓ Branch 10 → 11 taken 135530 times.
✓ Branch 10 → 12 taken 31339 times.
|
166869 | if (stack.empty()) |
| 703 | 135530 | stack.push(address); | |
| 704 | else | ||
| 705 | 31339 | stack.top() = address; | |
| 706 | 166869 | } | |
| 707 | |||
| 708 | 54 | void IRGenerator::pushAddress(const SymbolTableEntry *entry, llvm::Value *address) { | |
| 709 |
1/2✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 54 times.
|
54 | assert(address != nullptr); |
| 710 | 54 | addressMap[entry].push(address); | |
| 711 | 54 | } | |
| 712 | |||
| 713 | 54 | void IRGenerator::popAddress(const SymbolTableEntry *entry) { | |
| 714 |
1/2✓ Branch 2 → 3 taken 54 times.
✗ Branch 2 → 14 not taken.
|
54 | auto it = addressMap.find(entry); |
| 715 |
2/4✓ Branch 5 → 6 taken 54 times.
✗ Branch 5 → 10 not taken.
✓ Branch 8 → 9 taken 54 times.
✗ Branch 8 → 10 not taken.
|
54 | assert(it != addressMap.end() && !it->second.empty()); |
| 716 | 54 | it->second.pop(); | |
| 717 | 54 | } | |
| 718 | |||
| 719 | 7328 | llvm::Function *IRGenerator::getLLVMFunction(const Function *spiceFunc) { | |
| 720 |
1/2✓ Branch 2 → 3 taken 7328 times.
✗ Branch 2 → 12 not taken.
|
7328 | const auto it = llvmFunctions.find(spiceFunc); |
| 721 |
2/2✓ Branch 5 → 6 taken 2951 times.
✓ Branch 5 → 8 taken 4377 times.
|
14656 | return it != llvmFunctions.end() ? it->second : nullptr; |
| 722 | } | ||
| 723 | |||
| 724 | 33326 | void IRGenerator::setLLVMFunction(const Function *spiceFunc, llvm::Function *llvmFunction) { | |
| 725 |
1/2✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 33326 times.
|
33326 | assert(llvmFunction != nullptr); |
| 726 | 33326 | llvmFunctions[spiceFunc] = llvmFunction; | |
| 727 | 33326 | } | |
| 728 | |||
| 729 | 4182 | std::string IRGenerator::getIRString(llvm::Module *llvmModule, const CliOptions &cliOptions) { | |
| 730 |
1/2✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 4182 times.
|
4182 | assert(llvmModule != nullptr); // Make sure the module hasn't been moved away |
| 731 |
3/4✓ Branch 4 → 5 taken 4182 times.
✗ Branch 4 → 7 not taken.
✓ Branch 5 → 6 taken 4084 times.
✓ Branch 5 → 7 taken 98 times.
|
4182 | const bool eliminateTarget = cliOptions.comparableOutput && cliOptions.isNativeTarget; |
| 732 | |||
| 733 | // Backup target triple and data layout | ||
| 734 |
1/2✓ Branch 9 → 10 taken 4182 times.
✗ Branch 9 → 45 not taken.
|
4182 | const llvm::Triple targetTriple = llvmModule->getTargetTriple(); |
| 735 |
1/2✓ Branch 11 → 12 taken 4182 times.
✗ Branch 11 → 43 not taken.
|
4182 | const std::string targetDataLayout = llvmModule->getDataLayoutStr(); |
| 736 | // Remove target triple and data layout | ||
| 737 |
2/2✓ Branch 12 → 13 taken 4084 times.
✓ Branch 12 → 19 taken 98 times.
|
4182 | if (eliminateTarget) { |
| 738 | 4084 | llvmModule->setTargetTriple(llvm::Triple()); | |
| 739 |
2/4✓ Branch 16 → 17 taken 4084 times.
✗ Branch 16 → 34 not taken.
✓ Branch 17 → 18 taken 4084 times.
✗ Branch 17 → 34 not taken.
|
4084 | llvmModule->setDataLayout(""); |
| 740 | } | ||
| 741 | |||
| 742 | // Get IR string | ||
| 743 | 4182 | std::string output; | |
| 744 |
1/2✓ Branch 20 → 21 taken 4182 times.
✗ Branch 20 → 39 not taken.
|
4182 | llvm::raw_string_ostream oss(output); |
| 745 |
1/2✓ Branch 21 → 22 taken 4182 times.
✗ Branch 21 → 37 not taken.
|
4182 | llvmModule->print(oss, nullptr); |
| 746 | |||
| 747 | // Restore target triple and data layout | ||
| 748 |
2/2✓ Branch 22 → 23 taken 4084 times.
✓ Branch 22 → 29 taken 98 times.
|
4182 | if (eliminateTarget) { |
| 749 |
1/2✓ Branch 23 → 24 taken 4084 times.
✗ Branch 23 → 35 not taken.
|
4084 | llvmModule->setTargetTriple(targetTriple); |
| 750 |
1/2✓ Branch 27 → 28 taken 4084 times.
✗ Branch 27 → 36 not taken.
|
4084 | llvmModule->setDataLayout(targetDataLayout); |
| 751 | } | ||
| 752 | |||
| 753 | 4182 | return output; | |
| 754 | 4182 | } | |
| 755 | |||
| 756 | /** | ||
| 757 | * Returns the operator function list for the current manifestation and the given node | ||
| 758 | * | ||
| 759 | * @param node Node to retrieve the op fct pointer list from | ||
| 760 | * @return Op fct pointer list | ||
| 761 | */ | ||
| 762 | 63525 | const std::vector<const Function *> &IRGenerator::getOpFctPointers(const ASTNode *node) const { | |
| 763 |
1/2✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 63525 times.
|
63525 | assert(node->getOpFctPointers()->size() > manIdx); |
| 764 | 63525 | return node->getOpFctPointers()->at(manIdx); | |
| 765 | } | ||
| 766 | |||
| 767 | } // namespace spice::compiler | ||
| 768 |