Skip to content

Commit eca7a73

Browse files
committed
LLVMCodeBuilder: Implement 'and' and 'or' gates
1 parent e1ad826 commit eca7a73

File tree

5 files changed

+208
-10
lines changed

5 files changed

+208
-10
lines changed

src/dev/engine/internal/icodebuilder.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ class ICodeBuilder
3333
virtual void createCmpGT() = 0;
3434
virtual void createCmpLT() = 0;
3535

36+
virtual void createAnd() = 0;
37+
virtual void createOr() = 0;
3638
virtual void beginIfStatement() = 0;
3739
virtual void beginElseBranch() = 0;
3840
virtual void endIf() = 0;

src/dev/engine/internal/llvmcodebuilder.cpp

Lines changed: 39 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,26 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
152152
break;
153153
}
154154

155+
case Step::Type::And: {
156+
assert(step.args.size() == 2);
157+
const auto &arg1 = step.args[0];
158+
const auto &arg2 = step.args[1];
159+
llvm::Value *bool1 = castValue(arg1.second, arg1.first);
160+
llvm::Value *bool2 = castValue(arg2.second, arg2.first);
161+
step.functionReturnReg->value = m_builder.CreateAnd(bool1, bool2);
162+
break;
163+
}
164+
165+
case Step::Type::Or: {
166+
assert(step.args.size() == 2);
167+
const auto &arg1 = step.args[0];
168+
const auto &arg2 = step.args[1];
169+
llvm::Value *bool1 = castValue(arg1.second, arg1.first);
170+
llvm::Value *bool2 = castValue(arg2.second, arg2.first);
171+
step.functionReturnReg->value = m_builder.CreateOr(bool1, bool2);
172+
break;
173+
}
174+
155175
case Step::Type::Yield:
156176
if (!m_warp) {
157177
freeHeap();
@@ -472,37 +492,47 @@ void LLVMCodeBuilder::addListContents(List *list)
472492

473493
void LLVMCodeBuilder::createAdd()
474494
{
475-
createOp(Step::Type::Add, Compiler::StaticType::Number, 2);
495+
createOp(Step::Type::Add, Compiler::StaticType::Number, Compiler::StaticType::Number, 2);
476496
}
477497

478498
void LLVMCodeBuilder::createSub()
479499
{
480-
createOp(Step::Type::Sub, Compiler::StaticType::Number, 2);
500+
createOp(Step::Type::Sub, Compiler::StaticType::Number, Compiler::StaticType::Number, 2);
481501
}
482502

483503
void LLVMCodeBuilder::createMul()
484504
{
485-
createOp(Step::Type::Mul, Compiler::StaticType::Number, 2);
505+
createOp(Step::Type::Mul, Compiler::StaticType::Number, Compiler::StaticType::Number, 2);
486506
}
487507

488508
void LLVMCodeBuilder::createDiv()
489509
{
490-
createOp(Step::Type::Div, Compiler::StaticType::Number, 2);
510+
createOp(Step::Type::Div, Compiler::StaticType::Number, Compiler::StaticType::Number, 2);
491511
}
492512

493513
void LLVMCodeBuilder::createCmpEQ()
494514
{
495-
createOp(Step::Type::CmpEQ, Compiler::StaticType::Bool, 2);
515+
createOp(Step::Type::CmpEQ, Compiler::StaticType::Bool, Compiler::StaticType::Number, 2);
496516
}
497517

498518
void LLVMCodeBuilder::createCmpGT()
499519
{
500-
createOp(Step::Type::CmpGT, Compiler::StaticType::Bool, 2);
520+
createOp(Step::Type::CmpGT, Compiler::StaticType::Bool, Compiler::StaticType::Number, 2);
501521
}
502522

503523
void LLVMCodeBuilder::createCmpLT()
504524
{
505-
createOp(Step::Type::CmpLT, Compiler::StaticType::Bool, 2);
525+
createOp(Step::Type::CmpLT, Compiler::StaticType::Bool, Compiler::StaticType::Number, 2);
526+
}
527+
528+
void LLVMCodeBuilder::createAnd()
529+
{
530+
createOp(Step::Type::And, Compiler::StaticType::Bool, Compiler::StaticType::Bool, 2);
531+
}
532+
533+
void LLVMCodeBuilder::createOr()
534+
{
535+
createOp(Step::Type::Or, Compiler::StaticType::Bool, Compiler::StaticType::Bool, 2);
506536
}
507537

508538
void LLVMCodeBuilder::beginIfStatement()
@@ -881,15 +911,15 @@ llvm::Value *LLVMCodeBuilder::removeNaN(llvm::Value *num)
881911
return m_builder.CreateSelect(isNaN(num), llvm::ConstantFP::get(m_ctx, llvm::APFloat(0.0)), num);
882912
}
883913

884-
void LLVMCodeBuilder::createOp(Step::Type type, Compiler::StaticType retType, size_t argCount)
914+
void LLVMCodeBuilder::createOp(Step::Type type, Compiler::StaticType retType, Compiler::StaticType argType, size_t argCount)
885915
{
886916
Step step(type);
887917

888918
assert(m_tmpRegs.size() >= argCount);
889919
size_t j = 0;
890920

891921
for (size_t i = m_tmpRegs.size() - argCount; i < m_tmpRegs.size(); i++)
892-
step.args.push_back({ Compiler::StaticType::Number, m_tmpRegs[i] });
922+
step.args.push_back({ argType, m_tmpRegs[i] });
893923

894924
m_tmpRegs.erase(m_tmpRegs.end() - argCount, m_tmpRegs.end());
895925

src/dev/engine/internal/llvmcodebuilder.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ class LLVMCodeBuilder : public ICodeBuilder
3535
void createCmpGT() override;
3636
void createCmpLT() override;
3737

38+
void createAnd() override;
39+
void createOr() override;
3840
void beginIfStatement() override;
3941
void beginElseBranch() override;
4042
void endIf() override;
@@ -74,6 +76,8 @@ class LLVMCodeBuilder : public ICodeBuilder
7476
CmpEQ,
7577
CmpGT,
7678
CmpLT,
79+
And,
80+
Or,
7781
Yield,
7882
BeginIf,
7983
BeginElse,
@@ -150,7 +154,7 @@ class LLVMCodeBuilder : public ICodeBuilder
150154
llvm::Value *isNaN(llvm::Value *num);
151155
llvm::Value *removeNaN(llvm::Value *num);
152156

153-
void createOp(Step::Type type, Compiler::StaticType retType, size_t argCount);
157+
void createOp(Step::Type type, Compiler::StaticType retType, Compiler::StaticType argType, size_t argCount);
154158
llvm::Value *createValue(std::shared_ptr<Register> reg);
155159
llvm::Value *createComparison(std::shared_ptr<Register> arg1, std::shared_ptr<Register> arg2, Comparison type);
156160

test/dev/llvm/llvmcodebuilder_test.cpp

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -802,6 +802,166 @@ TEST_F(LLVMCodeBuilderTest, GreaterAndLowerThanComparison)
802802
addOpTest(nan, "0");
803803
}
804804

805+
TEST_F(LLVMCodeBuilderTest, AndOr)
806+
{
807+
auto addOpTest = [this](Value v1, Value v2) {
808+
// And
809+
createBuilder(true);
810+
811+
m_builder->addConstValue(v1);
812+
m_builder->addConstValue(v2);
813+
m_builder->createAnd();
814+
m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String });
815+
816+
m_builder->addConstValue(v1);
817+
callConstFuncForType(v1.type());
818+
m_builder->addConstValue(v2);
819+
callConstFuncForType(v2.type());
820+
m_builder->createAnd();
821+
m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String });
822+
823+
std::string str = Value(v1.toBool() && v2.toBool()).toString() + '\n';
824+
std::string expected = str + str;
825+
826+
auto code = m_builder->finalize();
827+
auto ctx = code->createExecutionContext(&m_target);
828+
829+
testing::internal::CaptureStdout();
830+
code->run(ctx.get());
831+
const std::string quotes1 = v1.isString() ? "\"" : "";
832+
const std::string quotes2 = v2.isString() ? "\"" : "";
833+
ASSERT_THAT(testing::internal::GetCapturedStdout(), Eq(expected)) << "AND: " << quotes1 << v1.toString() << quotes1 << " " << quotes2 << v2.toString() << quotes2;
834+
835+
// Or
836+
createBuilder(true);
837+
838+
m_builder->addConstValue(v1);
839+
m_builder->addConstValue(v2);
840+
m_builder->createOr();
841+
m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String });
842+
843+
m_builder->addConstValue(v1);
844+
callConstFuncForType(v1.type());
845+
m_builder->addConstValue(v2);
846+
callConstFuncForType(v2.type());
847+
m_builder->createOr();
848+
m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String });
849+
850+
str = Value(v1.toBool() || v2.toBool()).toString() + '\n';
851+
expected = str + str;
852+
853+
code = m_builder->finalize();
854+
ctx = code->createExecutionContext(&m_target);
855+
856+
testing::internal::CaptureStdout();
857+
code->run(ctx.get());
858+
ASSERT_THAT(testing::internal::GetCapturedStdout(), Eq(expected)) << "OR: " << quotes1 << v1.toString() << quotes1 << " " << quotes2 << v2.toString() << quotes2;
859+
};
860+
861+
addOpTest(10, 8);
862+
addOpTest(-4.25, -4.25);
863+
addOpTest(-4.25, 5.312);
864+
865+
addOpTest(true, true);
866+
addOpTest(true, false);
867+
addOpTest(false, true);
868+
869+
addOpTest(1, true);
870+
addOpTest(1, false);
871+
872+
addOpTest("abc", "def");
873+
addOpTest("true", "true");
874+
addOpTest("true", "false");
875+
addOpTest("false", "true");
876+
addOpTest("false", "false");
877+
878+
addOpTest(5.25, "5.25");
879+
addOpTest("5.25", 5.25);
880+
addOpTest(0, "1");
881+
addOpTest("1", 0);
882+
addOpTest(0, "test");
883+
addOpTest("test", 0);
884+
885+
static const double inf = std::numeric_limits<double>::infinity();
886+
static const double nan = std::numeric_limits<double>::quiet_NaN();
887+
888+
addOpTest(inf, inf);
889+
addOpTest(-inf, -inf);
890+
addOpTest(nan, nan);
891+
addOpTest(inf, -inf);
892+
addOpTest(-inf, inf);
893+
addOpTest(inf, nan);
894+
addOpTest(nan, inf);
895+
addOpTest(-inf, nan);
896+
addOpTest(nan, -inf);
897+
898+
addOpTest(true, "true");
899+
addOpTest("true", true);
900+
addOpTest(false, "false");
901+
addOpTest("false", false);
902+
addOpTest(false, "true");
903+
addOpTest("true", false);
904+
addOpTest(true, "false");
905+
addOpTest("false", true);
906+
addOpTest(true, "TRUE");
907+
addOpTest("TRUE", true);
908+
addOpTest(false, "FALSE");
909+
addOpTest("FALSE", false);
910+
911+
addOpTest(true, "00001");
912+
addOpTest("00001", true);
913+
addOpTest(true, "00000");
914+
addOpTest("00000", true);
915+
addOpTest(false, "00000");
916+
addOpTest("00000", false);
917+
918+
addOpTest("true", 1);
919+
addOpTest(1, "true");
920+
addOpTest("true", 0);
921+
addOpTest(0, "true");
922+
addOpTest("false", 0);
923+
addOpTest(0, "false");
924+
addOpTest("false", 1);
925+
addOpTest(1, "false");
926+
927+
addOpTest("true", "TRUE");
928+
addOpTest("true", "FALSE");
929+
addOpTest("false", "FALSE");
930+
addOpTest("false", "TRUE");
931+
932+
addOpTest(true, inf);
933+
addOpTest(inf, true);
934+
addOpTest(true, -inf);
935+
addOpTest(-inf, true);
936+
addOpTest(true, nan);
937+
addOpTest(nan, true);
938+
addOpTest(false, inf);
939+
addOpTest(inf, false);
940+
addOpTest(false, -inf);
941+
addOpTest(-inf, false);
942+
addOpTest(false, nan);
943+
addOpTest(nan, false);
944+
945+
addOpTest("Infinity", inf);
946+
addOpTest("Infinity", -inf);
947+
addOpTest("Infinity", nan);
948+
addOpTest("infinity", inf);
949+
addOpTest("infinity", -inf);
950+
addOpTest("infinity", nan);
951+
addOpTest("-Infinity", inf);
952+
addOpTest("-Infinity", -inf);
953+
addOpTest("-Infinity", nan);
954+
addOpTest("-infinity", inf);
955+
addOpTest("-infinity", -inf);
956+
addOpTest("-infinity", nan);
957+
addOpTest("NaN", inf);
958+
addOpTest("NaN", -inf);
959+
addOpTest("NaN", nan);
960+
addOpTest("nan", inf);
961+
addOpTest("nan", -inf);
962+
addOpTest("nan", nan);
963+
}
964+
805965
TEST_F(LLVMCodeBuilderTest, Yield)
806966
{
807967
auto build = [this]() {

test/mocks/codebuildermock.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ class CodeBuilderMock : public ICodeBuilder
2323
MOCK_METHOD(void, createCmpGT, (), (override));
2424
MOCK_METHOD(void, createCmpLT, (), (override));
2525

26+
MOCK_METHOD(void, createAnd, (), (override));
27+
MOCK_METHOD(void, createOr, (), (override));
2628
MOCK_METHOD(void, beginIfStatement, (), (override));
2729
MOCK_METHOD(void, beginElseBranch, (), (override));
2830
MOCK_METHOD(void, endIf, (), (override));

0 commit comments

Comments
 (0)