GCC Code Coverage Report


Directory: ../
File: src/irgenerator/GenBuiltinFunctions.cpp
Date: 2024-12-24 01:17:15
Exec Total Coverage
Lines: 87 92 94.6%
Functions: 7 7 100.0%
Branches: 139 262 53.1%

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 1093 std::any IRGenerator::visitBuiltinCall(const BuiltinCallNode *node) {
13
2/2
✓ Branch 0 taken 579 times.
✓ Branch 1 taken 514 times.
1093 if (node->printfCall)
14 579 return visit(node->printfCall);
15
2/2
✓ Branch 0 taken 119 times.
✓ Branch 1 taken 395 times.
514 if (node->sizeofCall)
16 119 return visit(node->sizeofCall);
17
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 384 times.
395 if (node->alignofCall)
18 11 return visit(node->alignofCall);
19
2/2
✓ Branch 0 taken 35 times.
✓ Branch 1 taken 349 times.
384 if (node->lenCall)
20 35 return visit(node->lenCall);
21
2/2
✓ Branch 0 taken 348 times.
✓ Branch 1 taken 1 times.
349 if (node->panicCall)
22 348 return visit(node->panicCall);
23
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (node->sysCall)
24 1 return visit(node->sysCall);
25 assert_fail("Unknown builtin call");
26 return nullptr;
27 }
28
29 579 std::any IRGenerator::visitPrintfCall(const PrintfCallNode *node) {
30 // Retrieve printf function
31
1/2
✓ Branch 1 taken 579 times.
✗ Branch 2 not taken.
579 llvm::Function *printfFct = stdFunctionManager.getPrintfFct();
32
33 // Push the template string as first argument
34 579 std::vector<llvm::Value *> printfArgs;
35
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);
36
1/2
✓ Branch 1 taken 579 times.
✗ Branch 2 not taken.
579 printfArgs.push_back(templateString);
37
38 // Collect replacement arguments
39
2/2
✓ Branch 5 taken 489 times.
✓ Branch 6 taken 579 times.
1068 for (const AssignExprNode *arg : node->args) {
40 // Retrieve type of argument
41
1/2
✓ Branch 1 taken 489 times.
✗ Branch 2 not taken.
489 const QualType argSymbolType = arg->getEvaluatedSymbolType(manIdx);
42
43 // Re-map some values
44 llvm::Value *argVal;
45
2/4
✓ Branch 1 taken 489 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 489 times.
489 if (argSymbolType.isArray()) {
46 llvm::Value *argValPtr = resolveAddress(arg);
47 llvm::Value *indices[2] = {builder.getInt64(0), builder.getInt32(0)};
48 llvm::Type *argType = argSymbolType.toLLVMType(sourceFile);
49 argVal = insertInBoundsGEP(argType, argValPtr, indices);
50
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()) {
51
1/2
✓ Branch 1 taken 27 times.
✗ Branch 2 not taken.
27 llvm::Value *argValPtr = resolveAddress(arg);
52
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);
53
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);
54
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);
55 } else {
56
1/2
✓ Branch 1 taken 462 times.
✗ Branch 2 not taken.
462 argVal = resolveValue(arg);
57 }
58
59 // Extend all integer types lower than 32 bit to 32 bit
60
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}))
61
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());
62
63
1/2
✓ Branch 1 taken 489 times.
✗ Branch 2 not taken.
489 printfArgs.push_back(argVal);
64 }
65
66 // Call printf function
67
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);
68
69 // Add noundef attribute to template string
70
1/2
✓ Branch 1 taken 579 times.
✗ Branch 2 not taken.
579 returnValue->addParamAttr(0, llvm::Attribute::NoUndef);
71
72
1/2
✓ Branch 1 taken 579 times.
✗ Branch 2 not taken.
1158 return LLVMExprResult{.value = returnValue};
73 579 }
74
75 119 std::any IRGenerator::visitSizeofCall(const SizeofCallNode *node) {
76 llvm::Type *type;
77
2/2
✓ Branch 0 taken 102 times.
✓ Branch 1 taken 17 times.
119 if (node->isType) { // Size of type
78
2/4
✓ Branch 1 taken 102 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 102 times.
✗ Branch 5 not taken.
102 type = any_cast<llvm::Type *>(visit(node->dataType));
79 } else { // Size of value
80
2/4
✓ Branch 1 taken 17 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 17 times.
✗ Branch 5 not taken.
17 type = node->assignExpr->getEvaluatedSymbolType(manIdx).toLLVMType(sourceFile);
81 }
82 // Calculate size at compile-time
83
1/2
✓ Branch 2 taken 119 times.
✗ Branch 3 not taken.
119 const llvm::TypeSize sizeInBits = module->getDataLayout().getTypeSizeInBits(type);
84
85 // Return size value
86
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);
87
1/2
✓ Branch 1 taken 119 times.
✗ Branch 2 not taken.
238 return LLVMExprResult{.value = sizeValue};
88 }
89
90 11 std::any IRGenerator::visitAlignofCall(const AlignofCallNode *node) {
91 llvm::Type *type;
92
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 10 times.
11 if (node->isType) { // Align of type
93
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
1 type = any_cast<llvm::Type *>(visit(node->dataType));
94 } else { // Align of value
95
2/4
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 10 times.
✗ Branch 5 not taken.
10 type = node->assignExpr->getEvaluatedSymbolType(manIdx).toLLVMType(sourceFile);
96 }
97 // Calculate size at compile-time
98
1/2
✓ Branch 2 taken 11 times.
✗ Branch 3 not taken.
11 const llvm::Align align = module->getDataLayout().getABITypeAlign(type);
99
100 // Return align value
101
1/2
✓ Branch 2 taken 11 times.
✗ Branch 3 not taken.
11 llvm::Value *sizeValue = builder.getInt64(align.value());
102
1/2
✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
22 return LLVMExprResult{.value = sizeValue};
103 }
104
105 35 std::any IRGenerator::visitLenCall(const LenCallNode *node) {
106 // Check if the length is fixed and known via the symbol type
107
1/2
✓ Branch 1 taken 35 times.
✗ Branch 2 not taken.
35 QualType symbolType = node->assignExpr->getEvaluatedSymbolType(manIdx);
108
1/2
✓ Branch 1 taken 35 times.
✗ Branch 2 not taken.
35 symbolType = symbolType.removeReferenceWrapper();
109
110 llvm::Value *lengthValue;
111
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)) {
112
1/2
✓ Branch 1 taken 23 times.
✗ Branch 2 not taken.
23 llvm::Function *getRawLengthFct = stdFunctionManager.getStringGetRawLengthStringFct();
113
4/8
✓ Branch 1 taken 23 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 23 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 23 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 23 times.
✗ Branch 12 not taken.
23 lengthValue = builder.CreateCall(getRawLengthFct, resolveValue(node->assignExpr));
114 } else {
115
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);
116 // Return length value
117
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());
118 }
119
1/2
✓ Branch 1 taken 35 times.
✗ Branch 2 not taken.
70 return LLVMExprResult{.value = lengthValue};
120 }
121
122 348 std::any IRGenerator::visitPanicCall(const PanicCallNode *node) {
123 // Create constant for error message
124
1/2
✓ Branch 1 taken 348 times.
✗ Branch 2 not taken.
348 const std::string codeLoc = node->codeLoc.toPrettyString();
125
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";
126
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));
127 // Print the error message
128
1/2
✓ Branch 1 taken 348 times.
✗ Branch 2 not taken.
348 llvm::Function *printfFct = stdFunctionManager.getPrintfFct();
129
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);
130 // Generate call to exit()
131
1/2
✓ Branch 1 taken 348 times.
✗ Branch 2 not taken.
348 llvm::Function *exitFct = stdFunctionManager.getExitFct();
132
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));
133 // Create unreachable instruction
134
1/2
✓ Branch 1 taken 348 times.
✗ Branch 2 not taken.
348 builder.CreateUnreachable();
135 // Unreachable counts as terminator
136
2/4
✓ Branch 1 taken 348 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 348 times.
✗ Branch 5 not taken.
348 terminateBlock(node->getNextOuterStmtLst());
137
138
1/2
✓ Branch 1 taken 348 times.
✗ Branch 2 not taken.
696 return nullptr;
139 348 }
140
141 1 std::any IRGenerator::visitSysCall(const SysCallNode *node) {
142 // Create assembly string
143 static constexpr uint8_t NUM_REGS = 7;
144
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 const char *asmString = getSysCallAsmString();
145
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 const char *constraints = getSysCallConstraintString();
146
147 // Create inline assembly
148
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 llvm::Type *int64Ty = builder.getInt64Ty();
149 1 llvm::Type *argTypes[NUM_REGS] = {int64Ty, int64Ty, int64Ty, int64Ty, int64Ty, int64Ty, int64Ty};
150
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);
151
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);
152
153 // Fill arguments array (first argument is syscall number)
154 llvm::Value *argValues[NUM_REGS];
155
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 1 times.
8 for (unsigned short i = 0; i < NUM_REGS; i++) {
156
2/2
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 3 times.
7 if (i < node->args.size()) {
157
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 const AssignExprNode *argNode = node->args.at(i);
158
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 const QualType &argType = argNode->getEvaluatedSymbolType(manIdx);
159
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}));
160
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}))
161
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());
162 else
163
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());
164 } else {
165
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 argValues[i] = builder.getInt64(0);
166 }
167 }
168
169 // Generate call
170
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);
171
172
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
2 return LLVMExprResult{.value = result};
173 }
174
175 } // namespace spice::compiler
176