Skip to content

Commit 1c3dca5

Browse files
committed
LLVMCodeBuilder: Implement procedure arguments
1 parent 70611b2 commit 1c3dca5

File tree

6 files changed

+96
-21
lines changed

6 files changed

+96
-21
lines changed

src/dev/engine/internal/icodebuilder.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ class ICodeBuilder
3232
virtual CompilerValue *addListItemIndex(List *list, CompilerValue *item) = 0;
3333
virtual CompilerValue *addListContains(List *list, CompilerValue *item) = 0;
3434
virtual CompilerValue *addListSize(List *list) = 0;
35+
virtual CompilerValue *addProcedureArgument(const std::string &name) = 0;
3536

3637
virtual CompilerValue *createAdd(CompilerValue *operand1, CompilerValue *operand2) = 0;
3738
virtual CompilerValue *createSub(CompilerValue *operand1, CompilerValue *operand2) = 0;
@@ -93,7 +94,7 @@ class ICodeBuilder
9394

9495
virtual void createStop() = 0;
9596

96-
virtual void createProcedureCall(BlockPrototype *prototype) = 0;
97+
virtual void createProcedureCall(BlockPrototype *prototype, const Compiler::Args &args) = 0;
9798
};
9899

99100
} // namespace libscratchcpp

src/dev/engine/internal/llvm/llvmcodebuilder.cpp

Lines changed: 60 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
#include <scratchcpp/iengine.h>
99
#include <scratchcpp/variable.h>
1010
#include <scratchcpp/list.h>
11-
#include <scratchcpp/blockprototype.h>
1211
#include <scratchcpp/dev/compilerconstant.h>
1312
#include <scratchcpp/dev/compilerlocalvariable.h>
1413

@@ -38,6 +37,9 @@ LLVMCodeBuilder::LLVMCodeBuilder(LLVMCompilerContext *ctx, BlockPrototype *proce
3837
initTypes();
3938
createVariableMap();
4039
createListMap();
40+
41+
llvm::FunctionType *funcType = getMainFunctionType(nullptr);
42+
m_defaultArgCount = funcType->getNumParams();
4143
}
4244

4345
std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
@@ -1030,15 +1032,15 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
10301032

10311033
case LLVMInstruction::Type::CallProcedure: {
10321034
assert(step.procedurePrototype);
1035+
assert(step.args.size() == step.procedurePrototype->argumentTypes().size());
10331036
freeScopeHeap();
10341037
syncVariables(targetVariables);
10351038

10361039
std::string name = getMainFunctionName(step.procedurePrototype);
10371040
llvm::FunctionType *type = getMainFunctionType(step.procedurePrototype);
10381041
std::vector<llvm::Value *> args;
1039-
const size_t argCount = type->getNumParams() - 1 - step.procedurePrototype->argumentTypes().size(); // omit warp arg and procedure args
10401042

1041-
for (size_t i = 0; i < argCount; i++)
1043+
for (size_t i = 0; i < m_defaultArgCount; i++)
10421044
args.push_back(func->getArg(i));
10431045

10441046
// Add warp arg
@@ -1047,7 +1049,14 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
10471049
else
10481050
args.push_back(m_procedurePrototype ? warpArg : m_builder.getInt1(false));
10491051

1050-
// TODO: Add procedure args
1052+
// Add procedure args
1053+
for (const auto &arg : step.args) {
1054+
if (arg.first == Compiler::StaticType::Unknown)
1055+
args.push_back(createValue(arg.second));
1056+
else
1057+
args.push_back(castValue(arg.second, arg.first));
1058+
}
1059+
10511060
llvm::Value *handle = m_builder.CreateCall(resolveFunction(name, type), args);
10521061

10531062
if (!m_warp && !step.procedurePrototype->warp()) {
@@ -1068,6 +1077,13 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
10681077
reloadLists();
10691078
break;
10701079
}
1080+
1081+
case LLVMInstruction::Type::ProcedureArg: {
1082+
assert(m_procedurePrototype);
1083+
llvm::Value *arg = func->getArg(m_defaultArgCount + 1 + step.procedureArgIndex); // omit warp arg
1084+
step.functionReturnReg->value = arg;
1085+
break;
1086+
}
10711087
}
10721088
}
10731089

@@ -1230,6 +1246,31 @@ CompilerValue *LLVMCodeBuilder::addListSize(List *list)
12301246
return createOp(ins, Compiler::StaticType::Number);
12311247
}
12321248

1249+
CompilerValue *LLVMCodeBuilder::addProcedureArgument(const std::string &name)
1250+
{
1251+
if (!m_procedurePrototype)
1252+
return addConstValue(Value());
1253+
1254+
const auto &argNames = m_procedurePrototype->argumentNames();
1255+
auto it = std::find(argNames.begin(), argNames.end(), name);
1256+
1257+
if (it == argNames.end()) {
1258+
std::cout << "warning: could not find argument '" << name << "' in custom block '" << m_procedurePrototype->procCode() << "'" << std::endl;
1259+
return addConstValue(Value());
1260+
}
1261+
1262+
const auto index = it - argNames.begin();
1263+
const Compiler::StaticType type = getProcedureArgType(m_procedurePrototype->argumentTypes()[index]);
1264+
LLVMInstruction ins(LLVMInstruction::Type::ProcedureArg);
1265+
auto ret = std::make_shared<LLVMRegister>(type);
1266+
ret->isRawValue = (type != Compiler::StaticType::Unknown);
1267+
ins.functionReturnReg = ret.get();
1268+
ins.procedureArgIndex = index;
1269+
1270+
m_instructions.push_back(ins);
1271+
return addReg(ret);
1272+
}
1273+
12331274
CompilerValue *LLVMCodeBuilder::createAdd(CompilerValue *operand1, CompilerValue *operand2)
12341275
{
12351276
return createOp(LLVMInstruction::Type::Add, Compiler::StaticType::Number, Compiler::StaticType::Number, { operand1, operand2 });
@@ -1502,11 +1543,19 @@ void LLVMCodeBuilder::createStop()
15021543
m_instructions.push_back({ LLVMInstruction::Type::Stop });
15031544
}
15041545

1505-
void LLVMCodeBuilder::createProcedureCall(BlockPrototype *prototype)
1546+
void LLVMCodeBuilder::createProcedureCall(BlockPrototype *prototype, const Compiler::Args &args)
15061547
{
1548+
assert(prototype);
1549+
assert(prototype->argumentTypes().size() == args.size());
1550+
const auto &procedureArgs = prototype->argumentTypes();
1551+
Compiler::ArgTypes types;
1552+
1553+
for (BlockPrototype::ArgType type : procedureArgs)
1554+
types.push_back(getProcedureArgType(type));
1555+
15071556
LLVMInstruction ins(LLVMInstruction::Type::CallProcedure);
15081557
ins.procedurePrototype = prototype;
1509-
m_instructions.push_back(ins);
1558+
createOp(ins, Compiler::StaticType::Void, types, args);
15101559
}
15111560

15121561
void LLVMCodeBuilder::initTypes()
@@ -1920,6 +1969,11 @@ llvm::Type *LLVMCodeBuilder::getType(Compiler::StaticType type)
19201969
}
19211970
}
19221971

1972+
Compiler::StaticType LLVMCodeBuilder::getProcedureArgType(BlockPrototype::ArgType type)
1973+
{
1974+
return type == BlockPrototype::ArgType::Bool ? Compiler::StaticType::Bool : Compiler::StaticType::Unknown;
1975+
}
1976+
19231977
llvm::Value *LLVMCodeBuilder::isNaN(llvm::Value *num)
19241978
{
19251979
return m_builder.CreateFCmpUNO(num, num);

src/dev/engine/internal/llvm/llvmcodebuilder.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
#pragma once
44

55
#include <scratchcpp/value.h>
6+
#include <scratchcpp/blockprototype.h>
7+
68
#include <llvm/IR/LLVMContext.h>
79
#include <llvm/IR/Module.h>
810
#include <llvm/IR/IRBuilder.h>
@@ -38,6 +40,7 @@ class LLVMCodeBuilder : public ICodeBuilder
3840
CompilerValue *addListItemIndex(List *list, CompilerValue *item) override;
3941
CompilerValue *addListContains(List *list, CompilerValue *item) override;
4042
CompilerValue *addListSize(List *list) override;
43+
CompilerValue *addProcedureArgument(const std::string &name) override;
4144

4245
CompilerValue *createAdd(CompilerValue *operand1, CompilerValue *operand2) override;
4346
CompilerValue *createSub(CompilerValue *operand1, CompilerValue *operand2) override;
@@ -99,7 +102,7 @@ class LLVMCodeBuilder : public ICodeBuilder
99102

100103
void createStop() override;
101104

102-
void createProcedureCall(BlockPrototype *prototype) override;
105+
void createProcedureCall(BlockPrototype *prototype, const Compiler::Args &args) override;
103106

104107
private:
105108
enum class Comparison
@@ -131,6 +134,7 @@ class LLVMCodeBuilder : public ICodeBuilder
131134
llvm::Constant *castConstValue(const Value &value, Compiler::StaticType targetType);
132135
Compiler::StaticType optimizeRegisterType(LLVMRegister *reg);
133136
llvm::Type *getType(Compiler::StaticType type);
137+
Compiler::StaticType getProcedureArgType(BlockPrototype::ArgType type);
134138
llvm::Value *isNaN(llvm::Value *num);
135139
llvm::Value *removeNaN(llvm::Value *num);
136140

@@ -212,6 +216,7 @@ class LLVMCodeBuilder : public ICodeBuilder
212216
BlockPrototype *m_procedurePrototype = nullptr;
213217
bool m_defaultWarp = false;
214218
bool m_warp = false;
219+
int m_defaultArgCount = 0;
215220

216221
std::vector<std::vector<llvm::Value *>> m_heap; // scopes
217222

src/dev/engine/internal/llvm/llvminstruction.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,8 @@ struct LLVMInstruction
7171
BeginLoopCondition,
7272
EndLoop,
7373
Stop,
74-
CallProcedure
74+
CallProcedure,
75+
ProcedureArg
7576
};
7677

7778
LLVMInstruction(Type type) :
@@ -88,6 +89,7 @@ struct LLVMInstruction
8889
Variable *workVariable = nullptr; // for variables
8990
List *workList = nullptr; // for lists
9091
BlockPrototype *procedurePrototype = nullptr;
92+
size_t procedureArgIndex = 0;
9193
};
9294

9395
} // namespace libscratchcpp

test/dev/llvm/llvmcodebuilder_test.cpp

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3951,7 +3951,9 @@ TEST_F(LLVMCodeBuilderTest, Procedures)
39513951

39523952
// Procedure 1
39533953
BlockPrototype prototype1;
3954-
prototype1.setProcCode("procedure 1");
3954+
prototype1.setProcCode("procedure 1 %s %s %b");
3955+
prototype1.setArgumentNames({ "any type 1", "any type 2", "bool" });
3956+
prototype1.setArgumentIds({ "a", "b", "c" });
39553957
prototype1.setWarp(false);
39563958
createBuilder(&sprite, &prototype1);
39573959

@@ -3960,16 +3962,20 @@ TEST_F(LLVMCodeBuilderTest, Procedures)
39603962
m_builder->addTargetFunctionCall("test_function_no_args", Compiler::StaticType::Void, {}, {});
39613963
m_builder->endLoop();
39623964

3963-
m_builder->createVariableWrite(var.get(), m_builder->addConstValue("test"));
3965+
m_builder->createVariableWrite(var.get(), m_builder->addProcedureArgument("any type 1"));
39643966
m_builder->createListClear(list.get());
3965-
m_builder->createListAppend(list.get(), m_builder->addConstValue("hello world"));
3967+
m_builder->createListAppend(list.get(), m_builder->addProcedureArgument("any type 2"));
39663968

39673969
v = m_builder->addVariableValue(var.get());
39683970
m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
39693971

39703972
v = m_builder->addListItem(list.get(), m_builder->addConstValue(0));
39713973
m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
39723974

3975+
v = m_builder->addProcedureArgument("bool");
3976+
m_builder->addFunctionCall("test_print_string", Compiler::StaticType::Void, { Compiler::StaticType::String }, { v });
3977+
m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number }, { v });
3978+
39733979
m_builder->finalize();
39743980

39753981
// Procedure 2
@@ -3980,31 +3986,37 @@ TEST_F(LLVMCodeBuilderTest, Procedures)
39803986

39813987
v = m_builder->addConstValue(2);
39823988
m_builder->beginRepeatLoop(v);
3983-
m_builder->createProcedureCall(&prototype1);
3989+
m_builder->createProcedureCall(&prototype1, { m_builder->addConstValue(-652.3), m_builder->addConstValue(false), m_builder->addConstValue(true) });
39843990
m_builder->endLoop();
39853991

39863992
m_builder->finalize();
39873993

39883994
// Script
39893995
createBuilder(&sprite, false);
3990-
m_builder->createProcedureCall(&prototype1);
3991-
m_builder->createProcedureCall(&prototype2);
3996+
m_builder->createProcedureCall(&prototype1, { m_builder->addConstValue("test"), m_builder->addConstValue(true), m_builder->addConstValue(false) });
3997+
m_builder->createProcedureCall(&prototype2, {});
39923998

39933999
std::string expected1 = "no_args\n";
39944000

39954001
std::string expected2 =
39964002
"test\n"
3997-
"hello world\n";
4003+
"true\n"
4004+
"false\n"
4005+
"0\n";
39984006

39994007
std::string expected3 =
40004008
"no_args\n"
40014009
"no_args\n"
4002-
"test\n"
4003-
"hello world\n"
4010+
"-652.3\n"
4011+
"false\n"
4012+
"true\n"
4013+
"1\n"
40044014
"no_args\n"
40054015
"no_args\n"
4006-
"test\n"
4007-
"hello world\n";
4016+
"-652.3\n"
4017+
"false\n"
4018+
"true\n"
4019+
"1\n";
40084020

40094021
auto code = m_builder->finalize();
40104022
Script script(&sprite, nullptr, nullptr);

test/mocks/codebuildermock.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ class CodeBuilderMock : public ICodeBuilder
2121
MOCK_METHOD(CompilerValue *, addListItemIndex, (List *, CompilerValue *), (override));
2222
MOCK_METHOD(CompilerValue *, addListContains, (List *, CompilerValue *), (override));
2323
MOCK_METHOD(CompilerValue *, addListSize, (List *), (override));
24+
MOCK_METHOD(CompilerValue *, addProcedureArgument, (const std::string &), (override));
2425

2526
MOCK_METHOD(CompilerValue *, createAdd, (CompilerValue *, CompilerValue *), (override));
2627
MOCK_METHOD(CompilerValue *, createSub, (CompilerValue *, CompilerValue *), (override));
@@ -82,5 +83,5 @@ class CodeBuilderMock : public ICodeBuilder
8283

8384
MOCK_METHOD(void, createStop, (), (override));
8485

85-
MOCK_METHOD(void, createProcedureCall, (BlockPrototype *), (override));
86+
MOCK_METHOD(void, createProcedureCall, (BlockPrototype *, const Compiler::Args &), (override));
8687
};

0 commit comments

Comments
 (0)