GCC Code Coverage Report


Directory: ../
File: src/irgenerator/GenBuiltinFunctions.cpp
Date: 2024-11-22 23:10:59
Exec Total Coverage
Lines: 77 81 95.1%
Functions: 6 6 100.0%
Branches: 136 266 51.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 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