• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

vla5924-practice / compiler-project / 13927446881

18 Mar 2025 03:42PM UTC coverage: 82.886% (+6.2%) from 76.638%
13927446881

Pull #212

github

web-flow
Merge 96ffcc954 into 993c9a6a4
Pull Request #212: Implement fold control flow optimization

35 of 37 new or added lines in 1 file covered. (94.59%)

234 existing lines in 10 files now uncovered.

4722 of 5697 relevant lines covered (82.89%)

270.6 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

82.34
/compiler/lib/codegen/ast_to_llvmir/ir_generator.cpp
1
#include "ir_generator.hpp"
2

3
#include <array>
4
#include <cassert>
5
#include <cstdint>
6
#include <iostream>
7

8
#include "compiler/utils/language.hpp"
9

10
using namespace ast;
11
using namespace ir_generator;
12

13
namespace language = utils::language;
14

15
namespace {
16

17
bool lhsRequiresPtr(BinaryOperation op) {
6✔
18
    switch (op) {
6✔
19
    case BinaryOperation::Assign:
3✔
20
    case BinaryOperation::FAssign:
21
        return true;
3✔
22
    default:
3✔
23
        return false;
3✔
24
    }
25
}
26

27
bool isLLVMPointer(llvm::Value *value) {
10✔
28
    return value->getType()->isPointerTy();
10✔
29
}
30

31
constexpr const char *const PRINTF_FUNCTION_NAME = "printf";
32
constexpr const char *const SCANF_FUNCTION_NAME = "scanf";
33

34
constexpr const char *const PLACEHOLDER_INT_NAME = ".placeholder.int";
35
constexpr const char *const PLACEHOLDER_FLOAT_NAME = ".placeholder.float";
36
constexpr const char *const PLACEHOLDER_STR_NAME = ".placeholder.str";
37
constexpr const char *const PLACEHOLDER_TRUE_NAME = ".placeholder.true";
38
constexpr const char *const PLACEHOLDER_FALSE_NAME = ".placeholder.false";
39
constexpr const char *const PLACEHOLDER_NONE_NAME = ".placeholder.none";
40
constexpr const char *const PLACEHOLDER_POINTER_NAME = ".placeholder.pointer";
41
constexpr const char *const PLACEHOLDER_NEWLINE_NAME = ".placeholder.newline";
42

43
const char *const placeholderNameByTypeId(TypeId id) {
4✔
44
    switch (id) {
4✔
45
    case BuiltInTypes::IntType:
1✔
46
        return PLACEHOLDER_INT_NAME;
1✔
47
    case BuiltInTypes::FloatType:
2✔
48
        return PLACEHOLDER_FLOAT_NAME;
2✔
49
    case BuiltInTypes::StrType:
1✔
50
        return PLACEHOLDER_STR_NAME;
1✔
51
    default:
×
UNCOV
52
        return PLACEHOLDER_POINTER_NAME;
×
53
    }
54
}
55

56
TypeId findVariableType(Node::Ptr node) {
1✔
57
    const std::string &name = node->str();
1✔
58
    auto currentNode = node->parent;
1✔
59
    while (currentNode) {
4✔
60
        if (currentNode->type == NodeType::BranchRoot) {
4✔
61
            auto &variables = currentNode->variables();
1✔
62
            auto it = variables.find(name);
1✔
63
            if (it != variables.end())
1✔
64
                return it->second.type;
1✔
65
        }
66
        currentNode = currentNode->parent;
3✔
67
    }
UNCOV
68
    return BuiltInTypes::NoneType;
×
69
}
1✔
70

71
TypeId detectExpressionType(Node::Ptr node) {
5✔
72
    switch (node->type) {
5✔
73
    case NodeType::Expression:
3✔
74
        return node->typeId();
3✔
75
    case NodeType::IntegerLiteralValue:
1✔
76
        return BuiltInTypes::IntType;
1✔
77
    case NodeType::FloatingPointLiteralValue:
×
78
        return BuiltInTypes::FloatType;
×
79
    case NodeType::StringLiteralValue:
×
UNCOV
80
        return BuiltInTypes::StrType;
×
81
    case NodeType::VariableName:
1✔
82
        return findVariableType(node);
1✔
83
    default:
×
UNCOV
84
        return BuiltInTypes::NoneType;
×
85
    }
86
}
87

88
} // namespace
89

90
static const std::unordered_map<std::string, std::string> placeholders = {
91
    {PLACEHOLDER_INT_NAME, "%d"},     {PLACEHOLDER_FLOAT_NAME, "%f"},    {PLACEHOLDER_STR_NAME, "%s"},
92
    {PLACEHOLDER_TRUE_NAME, "True"},  {PLACEHOLDER_FALSE_NAME, "False"}, {PLACEHOLDER_NONE_NAME, "None"},
93
    {PLACEHOLDER_POINTER_NAME, "%x"}, {PLACEHOLDER_NEWLINE_NAME, "\n"},
94
};
95

96
const std::unordered_map<std::string, IRGenerator::NodeVisitor> IRGenerator::builtInFunctions = {
97
    {language::funcPrint, &IRGenerator::visitPrintFunctionCall},
98
    {language::funcInput, &IRGenerator::visitInputFunctionCall},
99
};
100

101
IRGenerator::IRGenerator(const std::string &moduleName, bool emitDebugInfo)
3✔
102
    : context(), module(new llvm::Module(llvm::StringRef(moduleName), context)), builder(new llvm::IRBuilder(context)),
3✔
103
      currentBlock(nullptr), currentFunction(nullptr) {
3✔
104
    std::array<const char *const, 2> varArgFunctions = {PRINTF_FUNCTION_NAME, SCANF_FUNCTION_NAME};
3✔
105
    for (auto funcName : varArgFunctions) {
9✔
106
        std::vector<llvm::Type *> arguments = {llvm::PointerType::get(llvm::Type::getInt8Ty(context), 0)};
6✔
107
        llvm::Function *function =
108
            llvm::Function::Create(llvm::FunctionType::get(llvm::IntegerType::getInt32Ty(context), arguments,
6✔
109
                                                           /* bool isVarArg = */ true),
110
                                   llvm::Function::ExternalLinkage, funcName, module.get());
6✔
111
        internalFunctions.insert_or_assign(funcName, function);
6✔
112
    }
6✔
113

114
    for (const auto &[name, value] : placeholders) {
27✔
115
        declareString(value, name);
24✔
116
    }
117
}
3✔
118

119
void IRGenerator::process(const SyntaxTree &tree) {
2✔
120
    initializeFunctions(tree);
2✔
121
    processNode(tree.root);
2✔
122
}
2✔
123

124
void IRGenerator::writeToFile(const std::string &filename) {
×
125
    std::error_code error;
×
126
    llvm::raw_fd_ostream file(filename, error);
×
127
    module->print(file, nullptr);
×
128
    file.close();
×
UNCOV
129
}
×
130

131
void IRGenerator::dump(llvm::raw_ostream &stream) {
1✔
132
    module->print(stream, nullptr);
1✔
133
}
1✔
134

135
void IRGenerator::dump(std::ostream &stream) {
×
136
    if (&stream == &std::cout) {
×
137
        dump(llvm::outs());
×
UNCOV
138
        return;
×
139
    }
140
    if (&stream == &std::cerr) {
×
141
        dump(llvm::errs());
×
UNCOV
142
        return;
×
143
    }
UNCOV
144
    assert(false && "Only std::cout and std::cerr stream objects are supported.");
×
145
}
146

147
std::string IRGenerator::dump() {
1✔
148
    std::string str;
1✔
149
    llvm::raw_string_ostream stream(str);
1✔
150
    dump(stream);
1✔
151
    return str;
2✔
152
}
1✔
153

154
llvm::Type *IRGenerator::createLLVMType(TypeId id) {
23✔
155
    switch (id) {
23✔
156
    case BuiltInTypes::BoolType:
×
UNCOV
157
        return llvm::Type::getInt1Ty(context);
×
158
    case BuiltInTypes::IntType:
5✔
159
        return llvm::Type::getInt64Ty(context);
5✔
160
    case BuiltInTypes::FloatType:
6✔
161
        return llvm::Type::getDoubleTy(context);
6✔
162
    case BuiltInTypes::StrType:
10✔
163
        return llvm::PointerType::get(llvm::Type::getInt8Ty(context), 0);
10✔
164
    case BuiltInTypes::NoneType:
2✔
165
        return llvm::Type::getVoidTy(context);
2✔
166
    }
UNCOV
167
    return llvm::Type::getInt64Ty(context);
×
168
}
169

170
void IRGenerator::initializeFunctions(const SyntaxTree &tree) {
2✔
171
    FunctionsTable knownFunctions = tree.functions;
2✔
172
    for (const auto &[funcName, function] : builtInFunctions) {
6✔
173
        knownFunctions.erase(funcName);
4✔
174
    }
175

176
    for (const auto &[funcName, function] : knownFunctions) {
5✔
177
        std::vector<llvm::Type *> arguments(function.argumentsTypes.size());
3✔
178
        for (size_t i = 0; i < arguments.size(); i++)
4✔
179
            arguments[i] = createLLVMType(function.argumentsTypes[i]);
1✔
180
        llvm::FunctionType *funcType = llvm::FunctionType::get(createLLVMType(function.returnType), arguments, false);
3✔
181
        llvm::Function *llvmFunc =
182
            llvm::Function::Create(funcType, llvm::Function::ExternalLinkage, funcName, module.get());
3✔
183
        functions.insert_or_assign(funcName, llvmFunc);
3✔
184
    }
3✔
185
}
2✔
186

187
llvm::BasicBlock *IRGenerator::processBranchRoot(Node::Ptr node, bool createBlock) {
6✔
188
    assert(node && node->type == NodeType::BranchRoot);
6✔
189

190
    if (createBlock) {
6✔
191
        llvm::BasicBlock *nextBlock = llvm::BasicBlock::Create(context, "block");
3✔
192
        builder->CreateBr(nextBlock);
3✔
193
        nextBlock->insertInto(currentFunction);
3✔
194
        currentBlock = nextBlock;
3✔
195
    }
196
    localVariables.emplace_back();
6✔
197
    builder->SetInsertPoint(currentBlock);
6✔
198
    for (auto &n : node->children)
20✔
199
        processNode(n);
14✔
200
    localVariables.pop_back();
6✔
201
    return currentBlock;
6✔
202
}
203

204
llvm::Value *IRGenerator::declareString(const std::string &str, std::string name) {
25✔
205
    if (name.empty()) {
25✔
206
        static size_t counter = 0;
207
        name = ".str." + std::to_string(counter++);
1✔
208
    }
209
    return builder->CreateGlobalString(str, name, 0, module.get());
25✔
210
}
211

212
void IRGenerator::declareLocalVariable(TypeId type, std::string &name, llvm::Value *initialValue) {
6✔
213
    llvm::Type *llvmType = createLLVMType(type);
6✔
214
    llvm::AllocaInst *inst = new llvm::AllocaInst(llvmType, 0, name, currentBlock);
6✔
215
    localVariables.back().insert_or_assign(name, inst);
6✔
216
    valuesTypes[inst] = llvmType;
6✔
217
    if (initialValue != nullptr) {
6✔
218
        if (isLLVMPointer(initialValue))
5✔
UNCOV
219
            initialValue = builder->CreateLoad(llvmType, initialValue);
×
220
        builder->CreateStore(initialValue, inst);
5✔
221
    }
222
}
6✔
223

224
llvm::Constant *IRGenerator::getGlobalString(const std::string &name) {
7✔
225
    llvm::Type *charPointerType = createLLVMType(BuiltInTypes::StrType);
7✔
226
    llvm::GlobalVariable *globalVariable = module->getNamedGlobal(name);
7✔
227
    return llvm::ConstantExpr::getBitCast(globalVariable, charPointerType);
7✔
228
}
229

230
llvm::Value *IRGenerator::visitNode(Node::Ptr node) {
46✔
231
    assert(node);
46✔
232
    assert(node->type == NodeType::BinaryOperation || node->type == NodeType::Expression ||
46✔
233
           node->type == NodeType::FloatingPointLiteralValue || node->type == NodeType::FunctionCall ||
234
           node->type == NodeType::IntegerLiteralValue || node->type == NodeType::StringLiteralValue ||
235
           node->type == NodeType::TypeConversion || node->type == NodeType::VariableName);
236

237
    Node *rawNode = node.get();
46✔
238
    switch (node->type) {
46✔
239
    case NodeType::BinaryOperation:
9✔
240
        return visitBinaryOperation(rawNode);
9✔
241
    case NodeType::Expression:
10✔
242
        return visitExpression(rawNode);
10✔
243
    case NodeType::FloatingPointLiteralValue:
3✔
244
        return visitFloatingPointLiteralValue(rawNode);
3✔
245
    case NodeType::FunctionCall:
5✔
246
        return visitFunctionCall(rawNode);
5✔
247
    case NodeType::IntegerLiteralValue:
6✔
248
        return visitIntegerLiteralValue(rawNode);
6✔
249
    case NodeType::StringLiteralValue:
1✔
250
        return visitStringLiteralValue(rawNode);
1✔
251
    case NodeType::TypeConversion:
2✔
252
        return visitTypeConversion(rawNode);
2✔
253
    case NodeType::VariableName:
10✔
254
        return visitVariableName(rawNode);
10✔
255
    default:
×
UNCOV
256
        return nullptr;
×
257
    }
258
}
259

260
llvm::Value *IRGenerator::visitBinaryOperation(Node *node) {
9✔
261
    assert(node && node->type == NodeType::BinaryOperation);
9✔
262

263
    Node::Ptr &lhsNode = node->firstChild();
9✔
264
    Node::Ptr &rhsNode = node->lastChild();
9✔
265
    llvm::Value *lhs = visitNode(lhsNode);
9✔
266
    llvm::Value *rhs = visitNode(rhsNode);
9✔
267

268
    BinaryOperation op = node->binOp();
9✔
269
    if (lhsNode->type == NodeType::VariableName && !lhsRequiresPtr(op))
9✔
270
        lhs = builder->CreateLoad(valuesTypes[lhs], lhs);
3✔
271
    if (rhsNode->type == NodeType::VariableName)
9✔
272
        rhs = builder->CreateLoad(valuesTypes[rhs], rhs);
1✔
273
    switch (op) {
9✔
274
    case BinaryOperation::Add:
2✔
275
        return builder->CreateAdd(lhs, rhs);
2✔
276
    case BinaryOperation::Sub:
×
277
        return builder->CreateSub(lhs, rhs);
×
278
    case BinaryOperation::Mult:
×
279
        return builder->CreateMul(lhs, rhs);
×
280
    case BinaryOperation::Div:
×
UNCOV
281
        return builder->CreateSDiv(lhs, rhs);
×
282
    case BinaryOperation::FAdd:
1✔
283
        return builder->CreateFAdd(lhs, rhs);
1✔
284
    case BinaryOperation::FSub:
×
UNCOV
285
        return builder->CreateFSub(lhs, rhs);
×
286
    case BinaryOperation::FMult:
1✔
287
        return builder->CreateFMul(lhs, rhs);
1✔
288
    case BinaryOperation::FDiv:
×
UNCOV
289
        return builder->CreateFDiv(lhs, rhs);
×
290
    case BinaryOperation::Assign:
3✔
291
    case BinaryOperation::FAssign:
292
        return builder->CreateStore(rhs, lhs);
3✔
293
    case BinaryOperation::Equal:
×
294
        return builder->CreateICmp(llvm::ICmpInst::ICMP_EQ, lhs, rhs);
×
295
    case BinaryOperation::FEqual:
×
296
        return builder->CreateFCmp(llvm::FCmpInst::FCMP_OEQ, lhs, rhs);
×
297
    case BinaryOperation::NotEqual:
×
298
        return builder->CreateICmp(llvm::ICmpInst::ICMP_NE, lhs, rhs);
×
299
    case BinaryOperation::FNotEqual:
×
300
        return builder->CreateFCmp(llvm::FCmpInst::FCMP_ONE, lhs, rhs);
×
301
    case BinaryOperation::Greater:
×
UNCOV
302
        return builder->CreateICmp(llvm::ICmpInst::ICMP_SGT, lhs, rhs);
×
303
    case BinaryOperation::FGreater:
1✔
304
        return builder->CreateFCmp(llvm::ICmpInst::FCMP_OGT, lhs, rhs);
1✔
305
    case BinaryOperation::GreaterEqual:
×
306
        return builder->CreateICmp(llvm::ICmpInst::ICMP_SGE, lhs, rhs);
×
307
    case BinaryOperation::FGreaterEqual:
×
UNCOV
308
        return builder->CreateFCmp(llvm::ICmpInst::FCMP_OGE, lhs, rhs);
×
309
    case BinaryOperation::Less:
1✔
310
        return builder->CreateICmp(llvm::ICmpInst::ICMP_SLT, lhs, rhs);
1✔
311
    case BinaryOperation::FLess:
×
312
        return builder->CreateFCmp(llvm::ICmpInst::FCMP_OLT, lhs, rhs);
×
313
    case BinaryOperation::LessEqual:
×
314
        return builder->CreateICmp(llvm::ICmpInst::ICMP_SLE, lhs, rhs);
×
315
    case BinaryOperation::FLessEqual:
×
316
        return builder->CreateFCmp(llvm::ICmpInst::FCMP_OLE, lhs, rhs);
×
UNCOV
317
    case BinaryOperation::And:
×
318
    case BinaryOperation::FAnd:
319
        return builder->CreateAnd(lhs, rhs);
×
UNCOV
320
    case BinaryOperation::Or:
×
321
    case BinaryOperation::FOr:
322
        return builder->CreateOr(lhs, rhs);
×
323
    case BinaryOperation::Unknown:
×
UNCOV
324
        return nullptr;
×
325
    }
UNCOV
326
    return nullptr;
×
327
}
328

329
llvm::Value *IRGenerator::visitExpression(Node *node) {
11✔
330
    assert(node && node->type == NodeType::Expression);
11✔
331
    return visitNode(node->firstChild());
11✔
332
}
333

334
llvm::Value *IRGenerator::visitFloatingPointLiteralValue(Node *node) {
3✔
335
    assert(node && node->type == NodeType::FloatingPointLiteralValue);
3✔
336

337
    double value = node->fpNum();
3✔
338
    return llvm::ConstantFP::get(context, llvm::APFloat(value));
3✔
339
}
340

341
llvm::Value *IRGenerator::visitFunctionCall(Node *node) {
5✔
342
    assert(node && node->type == NodeType::FunctionCall);
5✔
343

344
    const std::string &name = node->firstChild()->str();
5✔
345
    auto visitorIter = builtInFunctions.find(name);
5✔
346
    if (visitorIter != builtInFunctions.end()) {
5✔
347
        NodeVisitor visitor = visitorIter->second;
4✔
348
        return (this->*visitor)(node);
4✔
349
    }
350

351
    auto argsNode = node->lastChild();
1✔
352
    std::vector<llvm::Value *> arguments;
1✔
353
    for (const auto &currentNode : argsNode->children) {
2✔
354
        llvm::Value *arg = visitExpression(currentNode.get());
1✔
355
        if (isLLVMPointer(arg))
1✔
356
            arg = builder->CreateLoad(valuesTypes[arg], arg);
1✔
357
        arguments.push_back(arg);
1✔
358
    }
359
    return builder->CreateCall(functions[name], arguments);
1✔
360
}
1✔
361

362
llvm::Value *IRGenerator::visitIntegerLiteralValue(Node *node) {
6✔
363
    assert(node && node->type == NodeType::IntegerLiteralValue);
6✔
364

365
    int64_t value = node->intNum();
6✔
366
    return llvm::ConstantInt::get(context, llvm::APInt(64, value, true));
6✔
367
}
368

369
llvm::Value *IRGenerator::visitStringLiteralValue(Node *node) {
1✔
370
    assert(node && node->type == NodeType::StringLiteralValue);
1✔
371

372
    const std::string &value = node->str();
1✔
373
    return declareString(value);
1✔
374
}
375

376
llvm::Value *IRGenerator::visitTypeConversion(Node *node) {
2✔
377
    assert(node && node->type == NodeType::TypeConversion);
2✔
378

379
    Node::Ptr &base = node->lastChild();
2✔
380
    llvm::Value *operand = nullptr;
2✔
381
    if (base->type == NodeType::VariableName) {
2✔
382
        llvm::Value *ptr = visitVariableName(base.get());
1✔
383
        operand = builder->CreateLoad(valuesTypes[ptr], ptr);
1✔
384
    } else
385
        operand = visitNode(base);
1✔
386
    TypeId srcType = detectExpressionType(base);
2✔
387
    TypeId dstType = node->firstChild()->typeId();
2✔
388

389
    if (srcType == dstType)
2✔
UNCOV
390
        return operand;
×
391
    if (srcType == BuiltInTypes::IntType && dstType == BuiltInTypes::FloatType)
2✔
392
        return new llvm::SIToFPInst(operand, createLLVMType(dstType), "typeconv", currentBlock);
2✔
393
    if (srcType == BuiltInTypes::FloatType && dstType == BuiltInTypes::IntType)
×
394
        return new llvm::FPToSIInst(operand, createLLVMType(dstType), "typeconv", currentBlock);
×
UNCOV
395
    return nullptr;
×
396
}
397

398
llvm::Value *IRGenerator::visitVariableName(Node *node) {
11✔
399
    assert(node && node->type == NodeType::VariableName);
11✔
400

401
    for (const auto &layer : localVariables) {
21✔
402
        auto it = layer.find(node->str());
21✔
403
        if (it != layer.end()) {
21✔
404
            return it->second;
11✔
405
        }
406
    }
UNCOV
407
    return nullptr;
×
408
}
409

410
llvm::Value *IRGenerator::visitPrintFunctionCall(Node *node) {
3✔
411
    assert(node && node->type == NodeType::FunctionCall && node->firstChild()->str() == language::funcPrint);
3✔
412

413
    auto argsNode = node->lastChild();
3✔
414
    assert(argsNode->numChildren() == 1U); // print requires only one argument
3✔
415

416
    auto valueNode = argsNode->firstChild();
3✔
417
    auto placeholderName = placeholderNameByTypeId(detectExpressionType(valueNode));
3✔
418
    std::vector<llvm::Value *> arguments = {getGlobalString(placeholderName)};
6✔
419
    if (placeholders.find(placeholderName)->second[0] == '%') {
3✔
420
        llvm::Value *arg = visitNode(valueNode);
3✔
421
        if (isLLVMPointer(arg) && arg->getType() != createLLVMType(BuiltInTypes::StrType))
3✔
UNCOV
422
            arg = builder->CreateLoad(valuesTypes[arg], arg);
×
423
        arguments.push_back(arg);
3✔
424
    }
425
    llvm::Function *function = internalFunctions[PRINTF_FUNCTION_NAME];
3✔
426
    builder->CreateCall(function, arguments);
3✔
427
    builder->CreateCall(function, {getGlobalString(PLACEHOLDER_NEWLINE_NAME)});
3✔
428

429
    return nullptr;
3✔
430
}
3✔
431

432
llvm::Value *IRGenerator::visitInputFunctionCall(Node *node) {
1✔
433
    assert(node && node->type == NodeType::FunctionCall && node->firstChild()->str() == language::funcInput);
1✔
434

435
    TypeId returnType = node->lastChild()->typeId();
1✔
436
    llvm::Type *llvmType = createLLVMType(returnType);
1✔
437
    llvm::AllocaInst *temporary = new llvm::AllocaInst(llvmType, 0, "input", currentBlock);
1✔
438
    valuesTypes[temporary] = llvmType;
1✔
439
    std::vector<llvm::Value *> arguments = {getGlobalString(placeholderNameByTypeId(returnType)), temporary};
2✔
440
    builder->CreateCall(internalFunctions[SCANF_FUNCTION_NAME], arguments);
1✔
441
    return builder->CreateLoad(llvmType, temporary);
2✔
442
}
1✔
443

444
void IRGenerator::processNode(Node::Ptr node) {
19✔
445
    assert(node);
19✔
446
    assert(node->type == NodeType::Expression || node->type == NodeType::FunctionDefinition ||
19✔
447
           node->type == NodeType::IfStatement || node->type == NodeType::ProgramRoot ||
448
           node->type == NodeType::ReturnStatement || node->type == NodeType::VariableDeclaration ||
449
           node->type == NodeType::WhileStatement);
450

451
    Node *rawNode = node.get();
19✔
452
    switch (node->type) {
19✔
453
    case NodeType::Expression:
6✔
454
        processExpression(rawNode);
6✔
455
        return;
6✔
456
    case NodeType::FunctionDefinition:
3✔
457
        processFunctionDefinition(rawNode);
3✔
458
        return;
3✔
459
    case NodeType::IfStatement:
1✔
460
        processIfStatement(rawNode);
1✔
461
        return;
1✔
462
    case NodeType::ProgramRoot:
2✔
463
        processProgramRoot(rawNode);
2✔
464
        return;
2✔
465
    case NodeType::ReturnStatement:
1✔
466
        processReturnStatement(rawNode);
1✔
467
        return;
1✔
468
    case NodeType::VariableDeclaration:
5✔
469
        processVariableDeclaration(rawNode);
5✔
470
        return;
5✔
471
    case NodeType::WhileStatement:
1✔
472
        processWhileStatement(rawNode);
1✔
473
        return;
1✔
474
    default:
×
UNCOV
475
        return;
×
476
    }
477
}
478

479
void IRGenerator::processExpression(Node *node) {
6✔
480
    assert(node && node->type == NodeType::Expression);
6✔
481
    visitNode(node->firstChild());
6✔
482
}
6✔
483

484
void IRGenerator::processFunctionDefinition(Node *node) {
3✔
485
    assert(node && node->type == NodeType::FunctionDefinition);
3✔
486

487
    std::string name = node->firstChild()->str();
3✔
488
    llvm::Function *function = module->getFunction(name);
3✔
489
    llvm::BasicBlock *body = llvm::BasicBlock::Create(context, name + "_entry", function);
3✔
490
    currentBlock = body;
3✔
491
    currentFunction = function;
3✔
492
    builder->SetInsertPoint(body);
3✔
493

494
    Node::Ptr &argsNode = node->secondChild();
3✔
495
    unsigned argIndex = 0u;
3✔
496
    localVariables.emplace_back();
3✔
497
    for (auto &argNode : argsNode->children) {
4✔
498
        assert(argNode->type == NodeType::FunctionArgument);
1✔
499

500
        auto nodeIter = argNode->children.begin();
1✔
501
        TypeId typeId = (*nodeIter)->typeId();
1✔
502
        nodeIter++;
1✔
503
        std::string name = (*nodeIter)->str();
1✔
504
        declareLocalVariable(typeId, name, function->getArg(argIndex++));
1✔
505
    }
1✔
506
    processBranchRoot(node->lastChild());
3✔
507
    localVariables.pop_back();
3✔
508

509
    if (function->getReturnType()->isVoidTy()) {
3✔
510
        builder->CreateRetVoid();
2✔
511
    }
512
}
3✔
513

514
void IRGenerator::processIfStatement(Node *node) {
1✔
515
    assert(node && node->type == NodeType::IfStatement);
1✔
516

517
    llvm::BasicBlock *endBlock = llvm::BasicBlock::Create(context, "endif");
1✔
518
    llvm::BasicBlock *elseBlock = nullptr;
1✔
519

520
    bool hasAdditionals = node->numChildren() > 2U;
1✔
521
    auto lastElse = node->lastChild();
1✔
522

523
    if (hasAdditionals && lastElse->type == NodeType::ElseStatement) {
1✔
524
        elseBlock = llvm::BasicBlock::Create(context, "elsebody");
1✔
525
    }
526

527
    auto tempElif = std::make_shared<Node>(NodeType::ElifStatement);
1✔
528
    tempElif->children.push_back(node->firstChild());
1✔
529
    tempElif->children.push_back(node->secondChild());
1✔
530
    node->children.insert(std::next(node->children.begin(), 2), tempElif);
1✔
531

532
    llvm::BasicBlock *condBlock = nullptr;
1✔
533
    llvm::BasicBlock *nextBlock = nullptr;
1✔
534

535
    for (auto nodeIter = std::next(node->children.begin(), 2);
1✔
536
         nodeIter != node->children.end() && (*nodeIter)->type == NodeType::ElifStatement; nodeIter++) {
2✔
537
        if (nextBlock == nullptr) {
1✔
538
            condBlock = llvm::BasicBlock::Create(context, "ifcond");
1✔
539
            builder->CreateBr(condBlock);
1✔
540
            condBlock->insertInto(currentFunction);
1✔
541
        } else {
542
            condBlock = nextBlock;
×
UNCOV
543
            nextBlock->insertInto(currentFunction);
×
544
        }
545
        llvm::BasicBlock *trueBlock = llvm::BasicBlock::Create(context, "ifbody", currentFunction);
1✔
546
        llvm::BasicBlock *falseBlock = nullptr;
1✔
547
        auto nextNode = std::next(nodeIter);
1✔
548
        bool lastNode = nextNode == node->children.end() || (*nextNode)->type == NodeType::ElseStatement;
1✔
549
        if (lastNode) {
1✔
550
            if (elseBlock) {
1✔
551
                falseBlock = elseBlock;
1✔
552
            } else {
UNCOV
553
                falseBlock = endBlock;
×
554
            }
555
        } else {
556
            falseBlock = llvm::BasicBlock::Create(context, "ifcond");
×
UNCOV
557
            nextBlock = falseBlock;
×
558
        }
559
        builder->SetInsertPoint(condBlock);
1✔
560
        Node *currentNode = nodeIter->get();
1✔
561
        llvm::Value *condition = visitNode(currentNode->firstChild());
1✔
562
        builder->CreateCondBr(condition, trueBlock, falseBlock);
1✔
563
        currentBlock = trueBlock;
1✔
564
        processBranchRoot(currentNode->lastChild(), false);
1✔
565
        builder->CreateBr(endBlock);
1✔
566
        builder->SetInsertPoint(falseBlock);
1✔
567
    }
568

569
    if (elseBlock) {
1✔
570
        elseBlock->insertInto(currentFunction);
1✔
571
        currentBlock = elseBlock;
1✔
572
        processBranchRoot(lastElse->lastChild(), false);
1✔
573
        builder->CreateBr(endBlock);
1✔
574
    }
575
    endBlock->insertInto(currentFunction);
1✔
576
    builder->SetInsertPoint(endBlock);
1✔
577
    currentBlock = endBlock;
1✔
578

579
    node->children.erase(std::next(node->children.begin(), 2));
1✔
580
}
1✔
581

582
void IRGenerator::processProgramRoot(Node *node) {
2✔
583
    assert(node && node->type == NodeType::ProgramRoot);
2✔
584

585
    for (auto &func : node->children)
5✔
586
        processNode(func);
3✔
587
}
2✔
588

589
void IRGenerator::processReturnStatement(Node *node) {
1✔
590
    assert(node && node->type == NodeType::ReturnStatement);
1✔
591

592
    llvm::Value *ret = visitNode(node->firstChild());
1✔
593
    if (isLLVMPointer(ret))
1✔
UNCOV
594
        ret = builder->CreateLoad(valuesTypes[ret], ret);
×
595
    builder->CreateRet(ret);
1✔
596
}
1✔
597

598
void IRGenerator::processVariableDeclaration(Node *node) {
5✔
599
    assert(node && node->type == NodeType::VariableDeclaration);
5✔
600

601
    auto nodeIter = node->children.begin();
5✔
602
    TypeId typeId = (*nodeIter)->typeId();
5✔
603
    nodeIter++;
5✔
604
    std::string name = (*nodeIter)->str();
5✔
605
    nodeIter++;
5✔
606
    llvm::Value *initialValue = nodeIter != node->children.end() ? visitNode(*nodeIter) : nullptr;
5✔
607
    declareLocalVariable(typeId, name, initialValue);
5✔
608
}
5✔
609

610
void IRGenerator::processWhileStatement(Node *node) {
1✔
611
    assert(node && node->type == NodeType::WhileStatement);
1✔
612

613
    llvm::BasicBlock *condBlock = llvm::BasicBlock::Create(context, "whilecond");
1✔
614
    llvm::BasicBlock *beginBlock = llvm::BasicBlock::Create(context, "whilebody");
1✔
615
    llvm::BasicBlock *endBlock = llvm::BasicBlock::Create(context, "endwhile");
1✔
616

617
    builder->CreateBr(condBlock);
1✔
618
    condBlock->insertInto(currentFunction);
1✔
619
    builder->SetInsertPoint(condBlock);
1✔
620
    llvm::Value *condition = visitNode(node->firstChild());
1✔
621
    builder->CreateCondBr(condition, beginBlock, endBlock);
1✔
622
    currentBlock = beginBlock;
1✔
623
    beginBlock->insertInto(currentFunction);
1✔
624
    processBranchRoot(node->lastChild(), false);
1✔
625
    builder->CreateBr(condBlock);
1✔
626
    endBlock->insertInto(currentFunction);
1✔
627
    builder->SetInsertPoint(endBlock);
1✔
628
    currentBlock = endBlock;
1✔
629
}
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc