Skip to content

Commit d19dbfa

Browse files
committed
LLVMCodeBuilder: Implement repeat until loop
1 parent 92ad9fa commit d19dbfa

File tree

7 files changed

+117
-0
lines changed

7 files changed

+117
-0
lines changed

src/dev/engine/internal/icodebuilder.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ class ICodeBuilder
3131

3232
virtual void beginRepeatLoop() = 0;
3333
virtual void beginWhileLoop() = 0;
34+
virtual void beginRepeatUntilLoop() = 0;
3435
virtual void beginLoopCondition() = 0;
3536
virtual void endLoop() = 0;
3637

src/dev/engine/internal/llvmcodebuilder.cpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,24 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
204204
break;
205205
}
206206

207+
case Step::Type::BeginRepeatUntilLoop: {
208+
assert(!loops.empty());
209+
Loop &loop = loops.back();
210+
211+
// Create branches
212+
llvm::BasicBlock *body = llvm::BasicBlock::Create(m_ctx, "", currentFunc);
213+
loop.afterLoop = llvm::BasicBlock::Create(m_ctx, "", currentFunc);
214+
215+
// Convert last reg to bool and add condition
216+
assert(step.args.size() == 1);
217+
llvm::Value *condition = m_builder.CreateCall(resolve_value_toBool(), step.args[0]->value);
218+
m_builder.CreateCondBr(condition, loop.afterLoop, body);
219+
220+
// Switch to body branch
221+
m_builder.SetInsertPoint(body);
222+
break;
223+
}
224+
207225
case Step::Type::BeginLoopCondition: {
208226
Loop loop;
209227
loop.isRepeatLoop = false;
@@ -338,6 +356,15 @@ void LLVMCodeBuilder::beginWhileLoop()
338356
m_steps.push_back(step);
339357
}
340358

359+
void LLVMCodeBuilder::beginRepeatUntilLoop()
360+
{
361+
Step step(Step::Type::BeginRepeatUntilLoop);
362+
assert(!m_tmpRegs.empty());
363+
step.args.push_back(m_tmpRegs.back());
364+
m_tmpRegs.pop_back();
365+
m_steps.push_back(step);
366+
}
367+
341368
void LLVMCodeBuilder::beginLoopCondition()
342369
{
343370
m_steps.push_back(Step(Step::Type::BeginLoopCondition));

src/dev/engine/internal/llvmcodebuilder.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ class LLVMCodeBuilder : public ICodeBuilder
3333

3434
void beginRepeatLoop() override;
3535
void beginWhileLoop() override;
36+
void beginRepeatUntilLoop() override;
3637
void beginLoopCondition() override;
3738
void endLoop() override;
3839

@@ -57,6 +58,7 @@ class LLVMCodeBuilder : public ICodeBuilder
5758
EndIf,
5859
BeginRepeatLoop,
5960
BeginWhileLoop,
61+
BeginRepeatUntilLoop,
6062
BeginLoopCondition,
6163
EndLoop
6264
};

test/dev/llvm/llvmcodebuilder_test.cpp

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -437,3 +437,83 @@ TEST_F(LLVMCodeBuilderTest, WhileLoop)
437437
code->run(ctx.get());
438438
ASSERT_EQ(testing::internal::GetCapturedStdout(), expected);
439439
}
440+
441+
TEST_F(LLVMCodeBuilderTest, RepeatUntilLoop)
442+
{
443+
// Const condition
444+
m_builder->beginLoopCondition();
445+
m_builder->addConstValue("true");
446+
m_builder->beginRepeatUntilLoop();
447+
m_builder->addFunctionCall("test_unreachable", 0, false);
448+
m_builder->endLoop();
449+
450+
m_builder->beginLoopCondition();
451+
m_builder->addConstValue(true);
452+
m_builder->beginRepeatUntilLoop();
453+
m_builder->addFunctionCall("test_unreachable", 0, false);
454+
m_builder->endLoop();
455+
456+
// Condition returned by function
457+
m_builder->addFunctionCall("test_reset_counter", 0, false);
458+
m_builder->beginLoopCondition();
459+
m_builder->addFunctionCall("test_get_counter", 0, true);
460+
m_builder->addConstValue(2);
461+
m_builder->addFunctionCall("test_lower_than", 2, true);
462+
m_builder->addFunctionCall("test_not", 1, true);
463+
m_builder->beginRepeatUntilLoop();
464+
m_builder->addConstValue(0);
465+
m_builder->addFunctionCall("test_function_1_arg", 1, false);
466+
m_builder->addFunctionCall("test_increment_counter", 0, false);
467+
m_builder->endLoop();
468+
469+
// Nested
470+
m_builder->addFunctionCall("test_reset_counter", 0, false);
471+
m_builder->beginLoopCondition();
472+
m_builder->addFunctionCall("test_get_counter", 0, true);
473+
m_builder->addConstValue(3);
474+
m_builder->addFunctionCall("test_lower_than", 2, true);
475+
m_builder->addFunctionCall("test_not", 1, true);
476+
m_builder->beginRepeatUntilLoop();
477+
{
478+
m_builder->beginLoopCondition();
479+
m_builder->addFunctionCall("test_get_counter", 0, true);
480+
m_builder->addConstValue(3);
481+
m_builder->addFunctionCall("test_lower_than", 2, true);
482+
m_builder->addFunctionCall("test_not", 1, true);
483+
m_builder->beginRepeatUntilLoop();
484+
{
485+
m_builder->addConstValue(1);
486+
m_builder->addFunctionCall("test_function_1_arg", 1, false);
487+
m_builder->addFunctionCall("test_increment_counter", 0, false);
488+
}
489+
m_builder->endLoop();
490+
491+
m_builder->addConstValue(2);
492+
m_builder->addFunctionCall("test_function_1_arg", 1, false);
493+
494+
m_builder->beginLoopCondition();
495+
m_builder->addConstValue(true);
496+
m_builder->beginRepeatUntilLoop();
497+
{
498+
m_builder->addFunctionCall("test_unreachable", 0, false);
499+
}
500+
m_builder->endLoop();
501+
}
502+
m_builder->endLoop();
503+
504+
auto code = m_builder->finalize();
505+
auto ctx = code->createExecutionContext(&m_target);
506+
507+
static const std::string expected =
508+
"1_arg 0\n"
509+
"1_arg 0\n"
510+
"1_arg 1\n"
511+
"1_arg 1\n"
512+
"1_arg 1\n"
513+
"1_arg 2\n";
514+
515+
EXPECT_CALL(m_target, isStage).WillRepeatedly(Return(false));
516+
testing::internal::CaptureStdout();
517+
code->run(ctx.get());
518+
ASSERT_EQ(testing::internal::GetCapturedStdout(), expected);
519+
}

test/dev/llvm/testfunctions.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,11 @@ extern "C"
9797
value_assign_copy(ret, v);
9898
}
9999

100+
void test_not(Target *target, ValueData *ret, ValueData *arg)
101+
{
102+
value_assign_bool(ret, !value_toBool(arg));
103+
}
104+
100105
void test_reset_counter(Target *target)
101106
{
102107
counter = 0;

test/dev/llvm/testfunctions.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ extern "C"
2121

2222
void test_equals(Target *target, ValueData *ret, ValueData *a, ValueData *b);
2323
void test_lower_than(Target *target, ValueData *ret, ValueData *a, ValueData *b);
24+
void test_not(Target *target, ValueData *ret, ValueData *arg);
2425
void test_const(Target *target, ValueData *ret, ValueData *v);
2526

2627
void test_unreachable(Target *target);

test/mocks/codebuildermock.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ class CodeBuilderMock : public ICodeBuilder
2020

2121
MOCK_METHOD(void, beginRepeatLoop, (), (override));
2222
MOCK_METHOD(void, beginWhileLoop, (), (override));
23+
MOCK_METHOD(void, beginRepeatUntilLoop, (), (override));
2324
MOCK_METHOD(void, beginLoopCondition, (), (override));
2425
MOCK_METHOD(void, endLoop, (), (override));
2526

0 commit comments

Comments
 (0)