Line | Branch | Exec | Source |
---|---|---|---|
1 | // Copyright (c) 2021-2024 ChilliBits. All rights reserved. | ||
2 | |||
3 | #include "IRGenerator.h" | ||
4 | |||
5 | #include <ast/ASTNodes.h> | ||
6 | #include <llvm/IR/InlineAsm.h> | ||
7 | |||
8 | #include <llvm/IR/Module.h> | ||
9 | |||
10 | namespace spice::compiler { | ||
11 | |||
12 | 579 | std::any IRGenerator::visitPrintfCall(const PrintfCallNode *node) { | |
13 | // Retrieve printf function | ||
14 |
1/2✓ Branch 1 taken 579 times.
✗ Branch 2 not taken.
|
579 | llvm::Function *printfFct = stdFunctionManager.getPrintfFct(); |
15 | |||
16 | // Push the template string as first argument | ||
17 | 579 | std::vector<llvm::Value *> printfArgs; | |
18 |
2/4✓ Branch 1 taken 579 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 579 times.
✗ Branch 5 not taken.
|
1158 | llvm::Constant *templateString = createGlobalStringConst("printf.str.", node->templatedString, node->codeLoc); |
19 |
1/2✓ Branch 1 taken 579 times.
✗ Branch 2 not taken.
|
579 | printfArgs.push_back(templateString); |
20 | |||
21 | // Collect replacement arguments | ||
22 |
3/4✓ Branch 1 taken 579 times.
✗ Branch 2 not taken.
✓ Branch 8 taken 489 times.
✓ Branch 9 taken 579 times.
|
1068 | for (const AssignExprNode *arg : node->args()) { |
23 | // Retrieve type of argument | ||
24 |
1/2✓ Branch 1 taken 489 times.
✗ Branch 2 not taken.
|
489 | const QualType argSymbolType = arg->getEvaluatedSymbolType(manIdx); |
25 | |||
26 | // Re-map some values | ||
27 | llvm::Value *argVal; | ||
28 |
2/4✓ Branch 1 taken 489 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 489 times.
|
489 | if (argSymbolType.isArray()) { |
29 | ✗ | llvm::Value *argValPtr = resolveAddress(arg); | |
30 | ✗ | llvm::Value *indices[2] = {builder.getInt64(0), builder.getInt32(0)}; | |
31 | ✗ | llvm::Type *argType = argSymbolType.toLLVMType(sourceFile); | |
32 | ✗ | argVal = insertInBoundsGEP(argType, argValPtr, indices); | |
33 |
4/6✓ Branch 1 taken 489 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 489 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 27 times.
✓ Branch 7 taken 462 times.
|
489 | } else if (argSymbolType.getBase().isStringObj()) { |
34 |
1/2✓ Branch 1 taken 27 times.
✗ Branch 2 not taken.
|
27 | llvm::Value *argValPtr = resolveAddress(arg); |
35 |
2/4✓ Branch 1 taken 27 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 27 times.
✗ Branch 5 not taken.
|
27 | llvm::Type *argBaseType = argSymbolType.getBase().toLLVMType(sourceFile); |
36 |
2/4✓ Branch 1 taken 27 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 27 times.
✗ Branch 5 not taken.
|
54 | argValPtr = insertStructGEP(argBaseType, argValPtr, 0); |
37 |
3/6✓ Branch 1 taken 27 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 27 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 27 times.
✗ Branch 8 not taken.
|
54 | argVal = insertLoad(builder.getPtrTy(), argValPtr); |
38 | } else { | ||
39 |
1/2✓ Branch 1 taken 462 times.
✗ Branch 2 not taken.
|
462 | argVal = resolveValue(arg); |
40 | } | ||
41 | |||
42 | // Extend all integer types lower than 32 bit to 32 bit | ||
43 |
4/6✓ Branch 1 taken 489 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 489 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 77 times.
✓ Branch 7 taken 412 times.
|
489 | if (argSymbolType.removeReferenceWrapper().isOneOf({TY_SHORT, TY_BYTE, TY_CHAR, TY_BOOL})) |
44 |
5/10✓ Branch 1 taken 77 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 77 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 77 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 77 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 77 times.
✗ Branch 14 not taken.
|
77 | argVal = builder.CreateIntCast(argVal, builder.getInt32Ty(), argSymbolType.removeReferenceWrapper().isSigned()); |
45 | |||
46 |
1/2✓ Branch 1 taken 489 times.
✗ Branch 2 not taken.
|
489 | printfArgs.push_back(argVal); |
47 | 579 | } | |
48 | |||
49 | // Call printf function | ||
50 |
3/6✓ Branch 1 taken 579 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 579 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 579 times.
✗ Branch 9 not taken.
|
579 | llvm::CallInst *returnValue = builder.CreateCall(printfFct, printfArgs); |
51 | |||
52 | // Add noundef attribute to template string | ||
53 |
1/2✓ Branch 1 taken 579 times.
✗ Branch 2 not taken.
|
579 | returnValue->addParamAttr(0, llvm::Attribute::NoUndef); |
54 | |||
55 |
1/2✓ Branch 1 taken 579 times.
✗ Branch 2 not taken.
|
1158 | return LLVMExprResult{.value = returnValue}; |
56 | 579 | } | |
57 | |||
58 | 119 | std::any IRGenerator::visitSizeofCall(const SizeofCallNode *node) { | |
59 | llvm::Type *type; | ||
60 |
2/2✓ Branch 0 taken 102 times.
✓ Branch 1 taken 17 times.
|
119 | if (node->isType) { // Size of type |
61 |
3/6✓ Branch 1 taken 102 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 102 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 102 times.
✗ Branch 8 not taken.
|
102 | type = any_cast<llvm::Type *>(visit(node->dataType())); |
62 | } else { // Size of value | ||
63 |
3/6✓ Branch 1 taken 17 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 17 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 17 times.
✗ Branch 8 not taken.
|
17 | type = node->assignExpr()->getEvaluatedSymbolType(manIdx).toLLVMType(sourceFile); |
64 | } | ||
65 | // Calculate size at compile-time | ||
66 |
1/2✓ Branch 2 taken 119 times.
✗ Branch 3 not taken.
|
119 | const llvm::TypeSize sizeInBits = module->getDataLayout().getTypeSizeInBits(type); |
67 | |||
68 | // Return size value | ||
69 |
2/4✓ Branch 1 taken 119 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 119 times.
✗ Branch 5 not taken.
|
119 | llvm::Value *sizeValue = builder.getInt64(sizeInBits); |
70 |
1/2✓ Branch 1 taken 119 times.
✗ Branch 2 not taken.
|
238 | return LLVMExprResult{.value = sizeValue}; |
71 | } | ||
72 | |||
73 | 11 | std::any IRGenerator::visitAlignofCall(const AlignofCallNode *node) { | |
74 | llvm::Type *type; | ||
75 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 10 times.
|
11 | if (node->isType) { // Align of type |
76 |
3/6✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
|
1 | type = any_cast<llvm::Type *>(visit(node->dataType())); |
77 | } else { // Align of value | ||
78 |
3/6✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 10 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 10 times.
✗ Branch 8 not taken.
|
10 | type = node->assignExpr()->getEvaluatedSymbolType(manIdx).toLLVMType(sourceFile); |
79 | } | ||
80 | // Calculate size at compile-time | ||
81 |
1/2✓ Branch 2 taken 11 times.
✗ Branch 3 not taken.
|
11 | const llvm::Align align = module->getDataLayout().getABITypeAlign(type); |
82 | |||
83 | // Return align value | ||
84 |
1/2✓ Branch 2 taken 11 times.
✗ Branch 3 not taken.
|
11 | llvm::Value *sizeValue = builder.getInt64(align.value()); |
85 |
1/2✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
|
22 | return LLVMExprResult{.value = sizeValue}; |
86 | } | ||
87 | |||
88 | 35 | std::any IRGenerator::visitLenCall(const LenCallNode *node) { | |
89 | // Check if the length is fixed and known via the symbol type | ||
90 |
2/4✓ Branch 1 taken 35 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 35 times.
✗ Branch 5 not taken.
|
35 | QualType symbolType = node->assignExpr()->getEvaluatedSymbolType(manIdx); |
91 |
1/2✓ Branch 1 taken 35 times.
✗ Branch 2 not taken.
|
35 | symbolType = symbolType.removeReferenceWrapper(); |
92 | |||
93 | llvm::Value *lengthValue; | ||
94 |
3/4✓ Branch 1 taken 35 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 23 times.
✓ Branch 4 taken 12 times.
|
35 | if (symbolType.is(TY_STRING)) { |
95 |
1/2✓ Branch 1 taken 23 times.
✗ Branch 2 not taken.
|
23 | llvm::Function *getRawLengthFct = stdFunctionManager.getStringGetRawLengthStringFct(); |
96 |
5/10✓ Branch 1 taken 23 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 23 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 23 times.
✗ Branch 8 not taken.
✓ Branch 11 taken 23 times.
✗ Branch 12 not taken.
✓ Branch 14 taken 23 times.
✗ Branch 15 not taken.
|
23 | lengthValue = builder.CreateCall(getRawLengthFct, resolveValue(node->assignExpr())); |
97 | } else { | ||
98 |
4/8✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 12 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 12 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 12 times.
✗ Branch 9 not taken.
|
12 | assert(symbolType.isArray() && symbolType.getArraySize() != ARRAY_SIZE_UNKNOWN); |
99 | // Return length value | ||
100 |
2/4✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 12 times.
✗ Branch 5 not taken.
|
12 | lengthValue = builder.getInt64(symbolType.getArraySize()); |
101 | } | ||
102 |
1/2✓ Branch 1 taken 35 times.
✗ Branch 2 not taken.
|
70 | return LLVMExprResult{.value = lengthValue}; |
103 | } | ||
104 | |||
105 | 348 | std::any IRGenerator::visitPanicCall(const PanicCallNode *node) { | |
106 | // Create constant for error message | ||
107 |
1/2✓ Branch 1 taken 348 times.
✗ Branch 2 not taken.
|
348 | const std::string codeLoc = node->codeLoc.toPrettyString(); |
108 |
5/10✓ Branch 1 taken 348 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 348 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 348 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 348 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 348 times.
✗ Branch 14 not taken.
|
348 | const std::string errorMsg = "Program panicked at " + codeLoc + ":\n" + node->getErrorMessage() + "\n"; |
109 |
4/8✓ Branch 1 taken 348 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 348 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 348 times.
✗ Branch 8 not taken.
✓ Branch 11 taken 348 times.
✗ Branch 12 not taken.
|
696 | llvm::Constant *globalString = builder.CreateGlobalStringPtr(errorMsg, getUnusedGlobalName(ANON_GLOBAL_STRING_NAME)); |
110 | // Print the error message | ||
111 |
1/2✓ Branch 1 taken 348 times.
✗ Branch 2 not taken.
|
348 | llvm::Function *printfFct = stdFunctionManager.getPrintfFct(); |
112 |
3/6✓ Branch 1 taken 348 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 348 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 348 times.
✗ Branch 9 not taken.
|
348 | builder.CreateCall(printfFct, globalString); |
113 | // Generate call to exit() | ||
114 |
1/2✓ Branch 1 taken 348 times.
✗ Branch 2 not taken.
|
348 | llvm::Function *exitFct = stdFunctionManager.getExitFct(); |
115 |
4/8✓ Branch 1 taken 348 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 348 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 348 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 348 times.
✗ Branch 12 not taken.
|
348 | builder.CreateCall(exitFct, builder.getInt32(EXIT_FAILURE)); |
116 | // Create unreachable instruction | ||
117 |
1/2✓ Branch 1 taken 348 times.
✗ Branch 2 not taken.
|
348 | builder.CreateUnreachable(); |
118 | // Unreachable counts as terminator | ||
119 |
2/4✓ Branch 1 taken 348 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 348 times.
✗ Branch 5 not taken.
|
348 | terminateBlock(node->getNextOuterStmtLst()); |
120 | |||
121 |
1/2✓ Branch 1 taken 348 times.
✗ Branch 2 not taken.
|
696 | return nullptr; |
122 | 348 | } | |
123 | |||
124 | 1 | std::any IRGenerator::visitSysCall(const SysCallNode *node) { | |
125 | // Create assembly string | ||
126 | static constexpr uint8_t NUM_REGS = 7; | ||
127 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | const char *asmString = getSysCallAsmString(); |
128 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | const char *constraints = getSysCallConstraintString(); |
129 | |||
130 | // Create inline assembly | ||
131 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | llvm::Type *int64Ty = builder.getInt64Ty(); |
132 | 1 | llvm::Type *argTypes[NUM_REGS] = {int64Ty, int64Ty, int64Ty, int64Ty, int64Ty, int64Ty, int64Ty}; | |
133 |
2/4✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
|
1 | llvm::FunctionType *fctType = llvm::FunctionType::get(builder.getVoidTy(), argTypes, false); |
134 |
3/6✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
|
1 | llvm::InlineAsm *inlineAsm = llvm::InlineAsm::get(fctType, asmString, constraints, true); |
135 | |||
136 | // Fill arguments array (first argument is syscall number) | ||
137 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | const std::vector<AssignExprNode *> assignExprs = node->assignExprs(); |
138 | llvm::Value *argValues[NUM_REGS]; | ||
139 |
2/2✓ Branch 0 taken 7 times.
✓ Branch 1 taken 1 times.
|
8 | for (unsigned short i = 0; i < NUM_REGS; i++) { |
140 |
2/2✓ Branch 1 taken 4 times.
✓ Branch 2 taken 3 times.
|
7 | if (i < assignExprs.size()) { |
141 |
1/2✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
|
4 | const AssignExprNode *argNode = assignExprs.at(i); |
142 |
1/2✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
|
4 | const QualType &argType = argNode->getEvaluatedSymbolType(manIdx); |
143 |
2/4✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
|
4 | assert(argType.isOneOf({TY_INT, TY_LONG, TY_SHORT, TY_BOOL, TY_BYTE, TY_PTR, TY_STRING})); |
144 |
3/4✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 3 times.
|
4 | if (argType.isOneOf({TY_PTR, TY_STRING})) |
145 |
4/8✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 1 times.
✗ Branch 11 not taken.
|
1 | argValues[i] = builder.CreatePtrToInt(resolveValue(argNode), builder.getInt64Ty()); |
146 | else | ||
147 |
4/8✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 3 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 3 times.
✗ Branch 11 not taken.
|
3 | argValues[i] = builder.CreateZExt(resolveValue(argNode), builder.getInt64Ty()); |
148 | } else { | ||
149 |
1/2✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
|
3 | argValues[i] = builder.getInt64(0); |
150 | } | ||
151 | } | ||
152 | |||
153 | // Generate call | ||
154 |
3/6✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 9 not taken.
|
1 | llvm::Value *result = builder.CreateCall(inlineAsm, argValues); |
155 | |||
156 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
2 | return LLVMExprResult{.value = result}; |
157 | 1 | } | |
158 | |||
159 | } // namespace spice::compiler | ||
160 |