Skip to content

Commit 9408959

Browse files
committed
LLVMCodeBuilder: Implement while loop
1 parent e97b27c commit 9408959

File tree

7 files changed

+162
-0
lines changed

7 files changed

+162
-0
lines changed

src/dev/engine/internal/icodebuilder.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ class ICodeBuilder
3030
virtual void endIf() = 0;
3131

3232
virtual void beginRepeatLoop() = 0;
33+
virtual void beginWhileLoop() = 0;
34+
virtual void beginLoopCondition() = 0;
3335
virtual void endLoop() = 0;
3436

3537
virtual void yield() = 0;

src/dev/engine/internal/llvmcodebuilder.cpp

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,34 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
186186
break;
187187
}
188188

189+
case Step::Type::BeginWhileLoop: {
190+
assert(!loops.empty());
191+
Loop &loop = loops.back();
192+
193+
// Create branches
194+
llvm::BasicBlock *body = llvm::BasicBlock::Create(m_ctx, "", currentFunc);
195+
loop.afterLoop = llvm::BasicBlock::Create(m_ctx, "", currentFunc);
196+
197+
// Convert last reg to bool and add condition
198+
assert(step.args.size() == 1);
199+
llvm::Value *condition = m_builder.CreateCall(resolve_value_toBool(), step.args[0]->value);
200+
m_builder.CreateCondBr(condition, body, loop.afterLoop);
201+
202+
// Switch to body branch
203+
m_builder.SetInsertPoint(body);
204+
break;
205+
}
206+
207+
case Step::Type::BeginLoopCondition: {
208+
Loop loop;
209+
loop.isRepeatLoop = false;
210+
loop.conditionBranch = llvm::BasicBlock::Create(m_ctx, "", currentFunc);
211+
m_builder.CreateBr(loop.conditionBranch);
212+
m_builder.SetInsertPoint(loop.conditionBranch);
213+
loops.push_back(loop);
214+
break;
215+
}
216+
189217
case Step::Type::EndLoop: {
190218
assert(!loops.empty());
191219
Loop &loop = loops.back();
@@ -301,6 +329,20 @@ void LLVMCodeBuilder::beginRepeatLoop()
301329
m_steps.push_back(step);
302330
}
303331

332+
void LLVMCodeBuilder::beginWhileLoop()
333+
{
334+
Step step(Step::Type::BeginWhileLoop);
335+
assert(!m_tmpRegs.empty());
336+
step.args.push_back(m_tmpRegs.back());
337+
m_tmpRegs.pop_back();
338+
m_steps.push_back(step);
339+
}
340+
341+
void LLVMCodeBuilder::beginLoopCondition()
342+
{
343+
m_steps.push_back(Step(Step::Type::BeginLoopCondition));
344+
}
345+
304346
void LLVMCodeBuilder::endLoop()
305347
{
306348
m_steps.push_back(Step(Step::Type::EndLoop));

src/dev/engine/internal/llvmcodebuilder.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ class LLVMCodeBuilder : public ICodeBuilder
3232
void endIf() override;
3333

3434
void beginRepeatLoop() override;
35+
void beginWhileLoop() override;
36+
void beginLoopCondition() override;
3537
void endLoop() override;
3638

3739
void yield() override;
@@ -54,6 +56,8 @@ class LLVMCodeBuilder : public ICodeBuilder
5456
BeginElse,
5557
EndIf,
5658
BeginRepeatLoop,
59+
BeginWhileLoop,
60+
BeginLoopCondition,
5761
EndLoop
5862
};
5963

test/dev/llvm/llvmcodebuilder_test.cpp

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -360,3 +360,80 @@ TEST_F(LLVMCodeBuilderTest, RepeatLoop)
360360
code->run(ctx.get());
361361
ASSERT_EQ(testing::internal::GetCapturedStdout(), expected);
362362
}
363+
364+
TEST_F(LLVMCodeBuilderTest, WhileLoop)
365+
{
366+
// Const condition
367+
m_builder->beginLoopCondition();
368+
m_builder->addConstValue("false");
369+
m_builder->beginWhileLoop();
370+
m_builder->addFunctionCall("test_unreachable", 0, false);
371+
m_builder->endLoop();
372+
373+
m_builder->beginLoopCondition();
374+
m_builder->addConstValue(false);
375+
m_builder->beginWhileLoop();
376+
m_builder->addFunctionCall("test_unreachable", 0, false);
377+
m_builder->endLoop();
378+
379+
// Condition returned by function
380+
m_builder->addFunctionCall("test_reset_counter", 0, false);
381+
m_builder->beginLoopCondition();
382+
m_builder->addFunctionCall("test_get_counter", 0, true);
383+
m_builder->addConstValue(2);
384+
m_builder->addFunctionCall("test_lower_than", 2, true);
385+
m_builder->beginWhileLoop();
386+
m_builder->addConstValue(0);
387+
m_builder->addFunctionCall("test_function_1_arg", 1, false);
388+
m_builder->addFunctionCall("test_increment_counter", 0, false);
389+
m_builder->endLoop();
390+
391+
// Nested
392+
m_builder->addFunctionCall("test_reset_counter", 0, false);
393+
m_builder->beginLoopCondition();
394+
m_builder->addFunctionCall("test_get_counter", 0, true);
395+
m_builder->addConstValue(3);
396+
m_builder->addFunctionCall("test_lower_than", 2, true);
397+
m_builder->beginWhileLoop();
398+
{
399+
m_builder->beginLoopCondition();
400+
m_builder->addFunctionCall("test_get_counter", 0, true);
401+
m_builder->addConstValue(3);
402+
m_builder->addFunctionCall("test_lower_than", 2, true);
403+
m_builder->beginWhileLoop();
404+
{
405+
m_builder->addConstValue(1);
406+
m_builder->addFunctionCall("test_function_1_arg", 1, false);
407+
m_builder->addFunctionCall("test_increment_counter", 0, false);
408+
}
409+
m_builder->endLoop();
410+
411+
m_builder->addConstValue(2);
412+
m_builder->addFunctionCall("test_function_1_arg", 1, false);
413+
414+
m_builder->beginLoopCondition();
415+
m_builder->addConstValue(false);
416+
m_builder->beginWhileLoop();
417+
{
418+
m_builder->addFunctionCall("test_unreachable", 0, false);
419+
}
420+
m_builder->endLoop();
421+
}
422+
m_builder->endLoop();
423+
424+
auto code = m_builder->finalize();
425+
auto ctx = code->createExecutionContext(&m_target);
426+
427+
static const std::string expected =
428+
"1_arg 0\n"
429+
"1_arg 0\n"
430+
"1_arg 1\n"
431+
"1_arg 1\n"
432+
"1_arg 1\n"
433+
"1_arg 2\n";
434+
435+
EXPECT_CALL(m_target, isStage).WillRepeatedly(Return(false));
436+
testing::internal::CaptureStdout();
437+
code->run(ctx.get());
438+
ASSERT_EQ(testing::internal::GetCapturedStdout(), expected);
439+
}

test/dev/llvm/testfunctions.cpp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77

88
using namespace libscratchcpp;
99

10+
static int counter = 0;
11+
1012
extern "C"
1113
{
1214
void test_function(TestMock *mock, Target *target)
@@ -79,8 +81,34 @@ extern "C"
7981
value_assign_bool(ret, value_equals(a, b));
8082
}
8183

84+
void test_unreachable(Target *target)
85+
{
86+
std::cout << "error: unreachable reached" << std::endl;
87+
exit(1);
88+
}
89+
90+
void test_lower_than(Target *target, ValueData *ret, ValueData *a, ValueData *b)
91+
{
92+
value_assign_bool(ret, value_lower(a, b));
93+
}
94+
8295
void test_const(Target *target, ValueData *ret, ValueData *v)
8396
{
8497
value_assign_copy(ret, v);
8598
}
99+
100+
void test_reset_counter(Target *target)
101+
{
102+
counter = 0;
103+
}
104+
105+
void test_increment_counter(Target *target)
106+
{
107+
counter++;
108+
}
109+
110+
void test_get_counter(Target *target, ValueData *ret)
111+
{
112+
value_assign_int(ret, counter);
113+
}
86114
}

test/dev/llvm/testfunctions.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,14 @@ extern "C"
2020
void test_function_3_args_ret(Target *target, ValueData *ret, const ValueData *arg1, const ValueData *arg2, const ValueData *arg3);
2121

2222
void test_equals(Target *target, ValueData *ret, ValueData *a, ValueData *b);
23+
void test_lower_than(Target *target, ValueData *ret, ValueData *a, ValueData *b);
2324
void test_const(Target *target, ValueData *ret, ValueData *v);
25+
26+
void test_unreachable(Target *target);
27+
28+
void test_reset_counter(Target *target);
29+
void test_increment_counter(Target *target);
30+
void test_get_counter(Target *target, ValueData *ret);
2431
}
2532

2633
} // namespace libscratchcpp

test/mocks/codebuildermock.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ class CodeBuilderMock : public ICodeBuilder
1919
MOCK_METHOD(void, endIf, (), (override));
2020

2121
MOCK_METHOD(void, beginRepeatLoop, (), (override));
22+
MOCK_METHOD(void, beginWhileLoop, (), (override));
23+
MOCK_METHOD(void, beginLoopCondition, (), (override));
2224
MOCK_METHOD(void, endLoop, (), (override));
2325

2426
MOCK_METHOD(void, yield, (), (override));

0 commit comments

Comments
 (0)