GCC Code Coverage Report


Directory: ../
File: src/irgenerator/GenBuiltinFunctions.cpp
Date: 2025-02-05 01:09:36
Exec Total Coverage
Lines: 99 104 95.2%
Functions: 7 7 100.0%
Branches: 154 290 53.1%

Line Branch Exec Source
1 // Copyright (c) 2021-2025 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 1355 std::any IRGenerator::visitBuiltinCall(const BuiltinCallNode *node) {
13
2/2
✓ Branch 0 (2→3) taken 619 times.
✓ Branch 1 (2→4) taken 736 times.
1355 if (node->printfCall)
14 619 return visit(node->printfCall);
15
2/2
✓ Branch 0 (4→5) taken 126 times.
✓ Branch 1 (4→6) taken 610 times.
736 if (node->sizeofCall)
16 126 return visit(node->sizeofCall);
17
2/2
✓ Branch 0 (6→7) taken 11 times.
✓ Branch 1 (6→8) taken 599 times.
610 if (node->alignofCall)
18 11 return visit(node->alignofCall);
19
2/2
✓ Branch 0 (8→9) taken 35 times.
✓ Branch 1 (8→10) taken 564 times.
599 if (node->lenCall)
20 35 return visit(node->lenCall);
21
2/2
✓ Branch 0 (10→11) taken 563 times.
✓ Branch 1 (10→12) taken 1 times.
564 if (node->panicCall)
22 563 return visit(node->panicCall);
23
1/2
✓ Branch 0 (12→13) taken 1 times.
✗ Branch 1 (12→14) not taken.
1 if (node->sysCall)
24 1 return visit(node->sysCall);
25 assert_fail("Unknown builtin call");
26 return nullptr;
27 }
28
29 619 std::any IRGenerator::visitPrintfCall(const PrintfCallNode *node) {
30 // Retrieve printf function
31
1/2
✓ Branch 0 (2→3) taken 619 times.
✗ Branch 1 (2→114) not taken.
619 llvm::Function *printfFct = stdFunctionManager.getPrintfFct();
32
33 // Push the template string as first argument
34 619 std::vector<llvm::Value *> printfArgs;
35
2/4
✓ Branch 0 (5→6) taken 619 times.
✗ Branch 1 (5→75) not taken.
✓ Branch 2 (6→7) taken 619 times.
✗ Branch 3 (6→73) not taken.
1238 llvm::Constant *templateString = createGlobalStringConst("printf.str.", node->templatedString, node->codeLoc);
36
1/2
✓ Branch 0 (9→10) taken 619 times.
✗ Branch 1 (9→79) not taken.
619 printfArgs.push_back(templateString);
37
38 // Collect replacement arguments
39
2/2
✓ Branch 0 (62→12) taken 513 times.
✓ Branch 1 (62→63) taken 619 times.
1132 for (const AssignExprNode *arg : node->args) {
40 // Retrieve type of argument
41
1/2
✓ Branch 0 (13→14) taken 513 times.
✗ Branch 1 (13→106) not taken.
513 const QualType argSymbolType = arg->getEvaluatedSymbolType(manIdx);
42
43 // Re-map some values
44 llvm::Value *argVal;
45
2/4
✓ Branch 0 (14→15) taken 513 times.
✗ Branch 1 (14→106) not taken.
✗ Branch 2 (15→16) not taken.
✓ Branch 3 (15→28) taken 513 times.
513 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 0 (28→29) taken 513 times.
✗ Branch 1 (28→88) not taken.
✓ Branch 2 (29→30) taken 513 times.
✗ Branch 3 (29→88) not taken.
✓ Branch 4 (30→31) taken 41 times.
✓ Branch 5 (30→48) taken 472 times.
513 } else if (argSymbolType.getBase().isStringObj()) {
51
1/2
✓ Branch 0 (31→32) taken 41 times.
✗ Branch 1 (31→106) not taken.
41 llvm::Value *argValPtr = resolveAddress(arg);
52
2/4
✓ Branch 0 (32→33) taken 41 times.
✗ Branch 1 (32→89) not taken.
✓ Branch 2 (33→34) taken 41 times.
✗ Branch 3 (33→89) not taken.
41 llvm::Type *argBaseType = argSymbolType.getBase().toLLVMType(sourceFile);
53
1/2
✓ Branch 0 (37→38) taken 41 times.
✗ Branch 1 (37→90) not taken.
41 argValPtr = insertStructGEP(argBaseType, argValPtr, 0);
54
3/6
✓ Branch 0 (42→43) taken 41 times.
✗ Branch 1 (42→98) not taken.
✓ Branch 2 (43→44) taken 41 times.
✗ Branch 3 (43→96) not taken.
✓ Branch 4 (44→45) taken 41 times.
✗ Branch 5 (44→96) not taken.
82 argVal = insertLoad(builder.getPtrTy(), argValPtr);
55 } else {
56
1/2
✓ Branch 0 (48→49) taken 472 times.
✗ Branch 1 (48→106) not taken.
472 argVal = resolveValue(arg);
57 }
58
59 // Extend all integer types lower than 32 bit to 32 bit
60
4/6
✓ Branch 0 (50→51) taken 513 times.
✗ Branch 1 (50→103) not taken.
✓ Branch 2 (51→52) taken 513 times.
✗ Branch 3 (51→102) not taken.
✓ Branch 4 (52→53) taken 77 times.
✓ Branch 5 (52→59) taken 436 times.
513 if (argSymbolType.removeReferenceWrapper().isOneOf({TY_SHORT, TY_BYTE, TY_CHAR, TY_BOOL}))
61
5/10
✓ Branch 0 (53→54) taken 77 times.
✗ Branch 1 (53→105) not taken.
✓ Branch 2 (54→55) taken 77 times.
✗ Branch 3 (54→104) not taken.
✓ Branch 4 (55→56) taken 77 times.
✗ Branch 5 (55→104) not taken.
✓ Branch 6 (56→57) taken 77 times.
✗ Branch 7 (56→104) not taken.
✓ Branch 8 (57→58) taken 77 times.
✗ Branch 9 (57→104) not taken.
77 argVal = builder.CreateIntCast(argVal, builder.getInt32Ty(), argSymbolType.removeReferenceWrapper().isSigned());
62
63
1/2
✓ Branch 0 (59→60) taken 513 times.
✗ Branch 1 (59→106) not taken.
513 printfArgs.push_back(argVal);
64 }
65
66 // Call printf function
67
3/6
✓ Branch 0 (63→64) taken 619 times.
✗ Branch 1 (63→110) not taken.
✓ Branch 2 (65→66) taken 619 times.
✗ Branch 3 (65→108) not taken.
✓ Branch 4 (66→67) taken 619 times.
✗ Branch 5 (66→108) not taken.
619 llvm::CallInst *returnValue = builder.CreateCall(printfFct, printfArgs);
68
69 // Add noundef attribute to template string
70
1/2
✓ Branch 0 (67→68) taken 619 times.
✗ Branch 1 (67→112) not taken.
619 returnValue->addParamAttr(0, llvm::Attribute::NoUndef);
71
72
1/2
✓ Branch 0 (68→69) taken 619 times.
✗ Branch 1 (68→111) not taken.
1238 return LLVMExprResult{.value = returnValue};
73 619 }
74
75 126 std::any IRGenerator::visitSizeofCall(const SizeofCallNode *node) {
76 llvm::Type *type;
77
2/2
✓ Branch 0 (2→3) taken 109 times.
✓ Branch 1 (2→7) taken 17 times.
126 if (node->isType) { // Size of type
78
2/4
✓ Branch 0 (3→4) taken 109 times.
✗ Branch 1 (3→20) not taken.
✓ Branch 2 (4→5) taken 109 times.
✗ Branch 3 (4→18) not taken.
109 type = any_cast<llvm::Type *>(visit(node->dataType));
79 } else { // Size of value
80
2/4
✓ Branch 0 (7→8) taken 17 times.
✗ Branch 1 (7→22) not taken.
✓ Branch 2 (8→9) taken 17 times.
✗ Branch 3 (8→22) not taken.
17 type = node->assignExpr->getEvaluatedSymbolType(manIdx).toLLVMType(sourceFile);
81 }
82 // Calculate size at compile-time
83
1/2
✓ Branch 0 (11→12) taken 126 times.
✗ Branch 1 (11→22) not taken.
126 const llvm::TypeSize sizeInBits = module->getDataLayout().getTypeSizeInBits(type);
84
85 // Return size value
86
2/4
✓ Branch 0 (12→13) taken 126 times.
✗ Branch 1 (12→22) not taken.
✓ Branch 2 (13→14) taken 126 times.
✗ Branch 3 (13→22) not taken.
126 llvm::Value *sizeValue = builder.getInt64(sizeInBits);
87
1/2
✓ Branch 0 (14→15) taken 126 times.
✗ Branch 1 (14→21) not taken.
252 return LLVMExprResult{.value = sizeValue};
88 }
89
90 11 std::any IRGenerator::visitAlignofCall(const AlignofCallNode *node) {
91 llvm::Type *type;
92
2/2
✓ Branch 0 (2→3) taken 1 times.
✓ Branch 1 (2→7) taken 10 times.
11 if (node->isType) { // Align of type
93
2/4
✓ Branch 0 (3→4) taken 1 times.
✗ Branch 1 (3→20) not taken.
✓ Branch 2 (4→5) taken 1 times.
✗ Branch 3 (4→18) not taken.
1 type = any_cast<llvm::Type *>(visit(node->dataType));
94 } else { // Align of value
95
2/4
✓ Branch 0 (7→8) taken 10 times.
✗ Branch 1 (7→22) not taken.
✓ Branch 2 (8→9) taken 10 times.
✗ Branch 3 (8→22) not taken.
10 type = node->assignExpr->getEvaluatedSymbolType(manIdx).toLLVMType(sourceFile);
96 }
97 // Calculate size at compile-time
98
1/2
✓ Branch 0 (11→12) taken 11 times.
✗ Branch 1 (11→22) not taken.
11 const llvm::Align align = module->getDataLayout().getABITypeAlign(type);
99
100 // Return align value
101
1/2
✓ Branch 0 (13→14) taken 11 times.
✗ Branch 1 (13→22) not taken.
11 llvm::Value *sizeValue = builder.getInt64(align.value());
102
1/2
✓ Branch 0 (14→15) taken 11 times.
✗ Branch 1 (14→21) 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 0 (2→3) taken 35 times.
✗ Branch 1 (2→32) not taken.
35 QualType symbolType = node->assignExpr->getEvaluatedSymbolType(manIdx);
108
1/2
✓ Branch 0 (3→4) taken 35 times.
✗ Branch 1 (3→26) not taken.
35 symbolType = symbolType.removeReferenceWrapper();
109
110 llvm::Value *lengthValue;
111
3/4
✓ Branch 0 (4→5) taken 35 times.
✗ Branch 1 (4→32) not taken.
✓ Branch 2 (5→6) taken 23 times.
✓ Branch 3 (5→13) taken 12 times.
35 if (symbolType.is(TY_STRING)) {
112
1/2
✓ Branch 0 (6→7) taken 23 times.
✗ Branch 1 (6→32) not taken.
23 llvm::Function *getRawLengthFct = stdFunctionManager.getStringGetRawLengthStringFct();
113
4/8
✓ Branch 0 (7→8) taken 23 times.
✗ Branch 1 (7→30) not taken.
✓ Branch 2 (8→9) taken 23 times.
✗ Branch 3 (8→28) not taken.
✓ Branch 4 (10→11) taken 23 times.
✗ Branch 5 (10→27) not taken.
✓ Branch 6 (11→12) taken 23 times.
✗ Branch 7 (11→27) not taken.
23 lengthValue = builder.CreateCall(getRawLengthFct, resolveValue(node->assignExpr));
114 } else {
115
4/8
✓ Branch 0 (13→14) taken 12 times.
✗ Branch 1 (13→32) not taken.
✓ Branch 2 (14→15) taken 12 times.
✗ Branch 3 (14→18) not taken.
✓ Branch 4 (15→16) taken 12 times.
✗ Branch 5 (15→32) not taken.
✓ Branch 6 (16→17) taken 12 times.
✗ Branch 7 (16→18) not taken.
12 assert(symbolType.isArray() && symbolType.getArraySize() != ARRAY_SIZE_UNKNOWN);
116 // Return length value
117
2/4
✓ Branch 0 (19→20) taken 12 times.
✗ Branch 1 (19→32) not taken.
✓ Branch 2 (20→21) taken 12 times.
✗ Branch 3 (20→32) not taken.
12 lengthValue = builder.getInt64(symbolType.getArraySize());
118 }
119
1/2
✓ Branch 0 (22→23) taken 35 times.
✗ Branch 1 (22→31) not taken.
70 return LLVMExprResult{.value = lengthValue};
120 }
121
122 563 std::any IRGenerator::visitPanicCall(const PanicCallNode *node) {
123 // Get value for stderr
124
1/2
✓ Branch 0 (2→3) taken 563 times.
✗ Branch 1 (2→128) not taken.
563 llvm::PointerType *ptrTy = builder.getPtrTy();
125 563 constexpr auto globalName = "stderr";
126
2/4
✓ Branch 0 (3→4) taken 563 times.
✗ Branch 1 (3→71) not taken.
✓ Branch 2 (4→5) taken 563 times.
✗ Branch 3 (4→71) not taken.
563 module->getOrInsertGlobal(globalName, ptrTy);
127
2/4
✓ Branch 0 (5→6) taken 563 times.
✗ Branch 1 (5→72) not taken.
✓ Branch 2 (6→7) taken 563 times.
✗ Branch 3 (6→72) not taken.
563 llvm::GlobalVariable *stdErrPtr = module->getNamedGlobal(globalName);
128
1/2
✓ Branch 0 (7→8) taken 563 times.
✗ Branch 1 (7→128) not taken.
563 stdErrPtr->setLinkage(llvm::GlobalVariable::ExternalLinkage);
129 563 stdErrPtr->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Local);
130
2/4
✓ Branch 0 (9→10) taken 563 times.
✗ Branch 1 (9→73) not taken.
✓ Branch 2 (10→11) taken 563 times.
✗ Branch 3 (10→73) not taken.
563 stdErrPtr->setAlignment(llvm::MaybeAlign(8));
131
2/4
✓ Branch 0 (13→14) taken 563 times.
✗ Branch 1 (13→76) not taken.
✓ Branch 2 (14→15) taken 563 times.
✗ Branch 3 (14→74) not taken.
563 llvm::Value *stdErr = insertLoad(ptrTy, stdErrPtr);
132
133 // Create constant for error message
134
1/2
✓ Branch 0 (17→18) taken 563 times.
✗ Branch 1 (17→128) not taken.
563 const std::string codeLoc = node->codeLoc.toPrettyString();
135
5/10
✓ Branch 0 (18→19) taken 563 times.
✗ Branch 1 (18→90) not taken.
✓ Branch 2 (19→20) taken 563 times.
✗ Branch 3 (19→86) not taken.
✓ Branch 4 (20→21) taken 563 times.
✗ Branch 5 (20→84) not taken.
✓ Branch 6 (21→22) taken 563 times.
✗ Branch 7 (21→82) not taken.
✓ Branch 8 (22→23) taken 563 times.
✗ Branch 9 (22→80) not taken.
563 const std::string templateStr = "Program panicked at " + codeLoc + ": %s\n" + node->getErrorMessage() + "\n";
136
4/8
✓ Branch 0 (29→30) taken 563 times.
✗ Branch 1 (29→97) not taken.
✓ Branch 2 (30→31) taken 563 times.
✗ Branch 3 (30→95) not taken.
✓ Branch 4 (31→32) taken 563 times.
✗ Branch 5 (31→93) not taken.
✓ Branch 6 (33→34) taken 563 times.
✗ Branch 7 (33→92) not taken.
1126 llvm::Constant *globalString = builder.CreateGlobalString(templateStr, getUnusedGlobalName(ANON_GLOBAL_STRING_NAME));
137
138 // Get actual error message
139
1/2
✓ Branch 0 (37→38) taken 563 times.
✗ Branch 1 (37→124) not taken.
563 llvm::Value *errorObjPtr = resolveAddress(node->assignExpr);
140
2/4
✓ Branch 0 (38→39) taken 563 times.
✗ Branch 1 (38→124) not taken.
✓ Branch 2 (39→40) taken 563 times.
✗ Branch 3 (39→124) not taken.
563 llvm::Type *errorObjTy = node->assignExpr->getEvaluatedSymbolType(manIdx).toLLVMType(sourceFile);
141
1/2
✓ Branch 0 (43→44) taken 563 times.
✗ Branch 1 (43→103) not taken.
563 llvm::Value *errorMessagePtr = insertStructGEP(errorObjTy, errorObjPtr, 1);
142
2/4
✓ Branch 0 (48→49) taken 563 times.
✗ Branch 1 (48→111) not taken.
✓ Branch 2 (49→50) taken 563 times.
✗ Branch 3 (49→109) not taken.
563 llvm::Value *errorMessage = insertLoad(ptrTy, errorMessagePtr);
143
144 // Print the error message to stderr
145
1/2
✓ Branch 0 (52→53) taken 563 times.
✗ Branch 1 (52→124) not taken.
563 llvm::Function *fprintfFct = stdFunctionManager.getFPrintfFct();
146
3/6
✓ Branch 0 (53→54) taken 563 times.
✗ Branch 1 (53→118) not taken.
✓ Branch 2 (55→56) taken 563 times.
✗ Branch 3 (55→115) not taken.
✓ Branch 4 (56→57) taken 563 times.
✗ Branch 5 (56→115) not taken.
563 builder.CreateCall(fprintfFct, {stdErr, globalString, errorMessage});
147
148 // Generate call to exit()
149
1/2
✓ Branch 0 (57→58) taken 563 times.
✗ Branch 1 (57→124) not taken.
563 llvm::Function *exitFct = stdFunctionManager.getExitFct();
150
4/8
✓ Branch 0 (58→59) taken 563 times.
✗ Branch 1 (58→122) not taken.
✓ Branch 2 (59→60) taken 563 times.
✗ Branch 3 (59→120) not taken.
✓ Branch 4 (61→62) taken 563 times.
✗ Branch 5 (61→119) not taken.
✓ Branch 6 (62→63) taken 563 times.
✗ Branch 7 (62→119) not taken.
563 builder.CreateCall(exitFct, builder.getInt32(EXIT_FAILURE));
151 // Create unreachable instruction
152
1/2
✓ Branch 0 (63→64) taken 563 times.
✗ Branch 1 (63→124) not taken.
563 builder.CreateUnreachable();
153 // Unreachable counts as terminator
154
2/4
✓ Branch 0 (64→65) taken 563 times.
✗ Branch 1 (64→124) not taken.
✓ Branch 2 (65→66) taken 563 times.
✗ Branch 3 (65→124) not taken.
563 terminateBlock(node->getNextOuterStmtLst());
155
156
1/2
✓ Branch 0 (66→67) taken 563 times.
✗ Branch 1 (66→123) not taken.
1126 return nullptr;
157 563 }
158
159 1 std::any IRGenerator::visitSysCall(const SysCallNode *node) {
160 // Create assembly string
161 static constexpr uint8_t NUM_REGS = 7;
162
1/2
✓ Branch 0 (2→3) taken 1 times.
✗ Branch 1 (2→54) not taken.
1 const char *asmString = getSysCallAsmString();
163
1/2
✓ Branch 0 (3→4) taken 1 times.
✗ Branch 1 (3→54) not taken.
1 const char *constraints = getSysCallConstraintString();
164
165 // Create inline assembly
166
1/2
✓ Branch 0 (4→5) taken 1 times.
✗ Branch 1 (4→54) not taken.
1 llvm::Type *int64Ty = builder.getInt64Ty();
167 1 llvm::Type *argTypes[NUM_REGS] = {int64Ty, int64Ty, int64Ty, int64Ty, int64Ty, int64Ty, int64Ty};
168
2/4
✓ Branch 0 (6→7) taken 1 times.
✗ Branch 1 (6→43) not taken.
✓ Branch 2 (7→8) taken 1 times.
✗ Branch 3 (7→43) not taken.
1 llvm::FunctionType *fctType = llvm::FunctionType::get(builder.getVoidTy(), argTypes, false);
169
3/6
✓ Branch 0 (8→9) taken 1 times.
✗ Branch 1 (8→45) not taken.
✓ Branch 2 (9→10) taken 1 times.
✗ Branch 3 (9→44) not taken.
✓ Branch 4 (10→11) taken 1 times.
✗ Branch 5 (10→44) not taken.
1 llvm::InlineAsm *inlineAsm = llvm::InlineAsm::get(fctType, asmString, constraints, true);
170
171 // Fill arguments array (first argument is syscall number)
172 llvm::Value *argValues[NUM_REGS];
173
2/2
✓ Branch 0 (34→12) taken 7 times.
✓ Branch 1 (34→35) taken 1 times.
8 for (unsigned short i = 0; i < NUM_REGS; i++) {
174
2/2
✓ Branch 0 (13→14) taken 4 times.
✓ Branch 1 (13→31) taken 3 times.
7 if (i < node->args.size()) {
175
1/2
✓ Branch 0 (14→15) taken 4 times.
✗ Branch 1 (14→54) not taken.
4 const AssignExprNode *argNode = node->args.at(i);
176
1/2
✓ Branch 0 (15→16) taken 4 times.
✗ Branch 1 (15→54) not taken.
4 const QualType &argType = argNode->getEvaluatedSymbolType(manIdx);
177
2/4
✓ Branch 0 (16→17) taken 4 times.
✗ Branch 1 (16→46) not taken.
✗ Branch 2 (17→18) not taken.
✓ Branch 3 (17→19) taken 4 times.
4 assert(argType.isOneOf({TY_INT, TY_LONG, TY_SHORT, TY_BOOL, TY_BYTE, TY_PTR, TY_STRING}));
178
3/4
✓ Branch 0 (19→20) taken 4 times.
✗ Branch 1 (19→47) not taken.
✓ Branch 2 (20→21) taken 1 times.
✓ Branch 3 (20→26) taken 3 times.
4 if (argType.isOneOf({TY_PTR, TY_STRING}))
179
4/8
✓ Branch 0 (21→22) taken 1 times.
✗ Branch 1 (21→48) not taken.
✓ Branch 2 (22→23) taken 1 times.
✗ Branch 3 (22→48) not taken.
✓ Branch 4 (23→24) taken 1 times.
✗ Branch 5 (23→48) not taken.
✓ Branch 6 (24→25) taken 1 times.
✗ Branch 7 (24→48) not taken.
1 argValues[i] = builder.CreatePtrToInt(resolveValue(argNode), builder.getInt64Ty());
180 else
181
4/8
✓ Branch 0 (26→27) taken 3 times.
✗ Branch 1 (26→49) not taken.
✓ Branch 2 (27→28) taken 3 times.
✗ Branch 3 (27→49) not taken.
✓ Branch 4 (28→29) taken 3 times.
✗ Branch 5 (28→49) not taken.
✓ Branch 6 (29→30) taken 3 times.
✗ Branch 7 (29→49) not taken.
3 argValues[i] = builder.CreateZExt(resolveValue(argNode), builder.getInt64Ty());
182 } else {
183
1/2
✓ Branch 0 (31→32) taken 3 times.
✗ Branch 1 (31→54) not taken.
3 argValues[i] = builder.getInt64(0);
184 }
185 }
186
187 // Generate call
188
3/6
✓ Branch 0 (35→36) taken 1 times.
✗ Branch 1 (35→52) not taken.
✓ Branch 2 (37→38) taken 1 times.
✗ Branch 3 (37→50) not taken.
✓ Branch 4 (38→39) taken 1 times.
✗ Branch 5 (38→50) not taken.
1 llvm::Value *result = builder.CreateCall(inlineAsm, argValues);
189
190
1/2
✓ Branch 0 (39→40) taken 1 times.
✗ Branch 1 (39→53) not taken.
2 return LLVMExprResult{.value = result};
191 }
192
193 } // namespace spice::compiler
194