Skip to content

Commit c92cd6a

Browse files
committed
LLVMCodeBuilder: Implement reporters
1 parent 601bd29 commit c92cd6a

File tree

3 files changed

+121
-3
lines changed

3 files changed

+121
-3
lines changed

src/engine/internal/llvm/llvmcodebuilder.cpp

Lines changed: 58 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1327,7 +1327,13 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
13271327
coro->end();
13281328
break;
13291329

1330-
// TODO: Implement reporter code type
1330+
case Compiler::CodeType::Reporter: {
1331+
// Use last instruction return value and create a ValueData instance
1332+
assert(!m_instructions.empty());
1333+
LLVMRegister *ret = m_instructions.back()->functionReturnReg;
1334+
m_builder.CreateRet(m_builder.CreateLoad(m_valueDataType, createNewValue(ret))); // return copy
1335+
break;
1336+
}
13311337
case Compiler::CodeType::HatPredicate:
13321338
// Use last instruction return value
13331339
assert(!m_instructions.empty());
@@ -2031,7 +2037,10 @@ std::string LLVMCodeBuilder::getMainFunctionName(BlockPrototype *procedureProtot
20312037
name = "script";
20322038
break;
20332039

2034-
// TODO: Implement reporter code type
2040+
case Compiler::CodeType::Reporter:
2041+
name = "reporter";
2042+
break;
2043+
20352044
case Compiler::CodeType::HatPredicate:
20362045
name = "predicate";
20372046
break;
@@ -2048,6 +2057,7 @@ std::string LLVMCodeBuilder::getResumeFunctionName(BlockPrototype *procedureProt
20482057
llvm::FunctionType *LLVMCodeBuilder::getMainFunctionType(BlockPrototype *procedurePrototype)
20492058
{
20502059
// void *f(ExecutionContext *, Target *, ValueData **, List **, (warp arg), (procedure args...))
2060+
// ValueData f(...) (reporters)
20512061
// bool f(...) (hat predicates)
20522062
llvm::Type *pointerType = llvm::PointerType::get(llvm::Type::getInt8Ty(m_llvmCtx), 0);
20532063
std::vector<llvm::Type *> argTypes = { pointerType, pointerType, pointerType, pointerType };
@@ -2071,7 +2081,10 @@ llvm::FunctionType *LLVMCodeBuilder::getMainFunctionType(BlockPrototype *procedu
20712081
retType = pointerType;
20722082
break;
20732083

2074-
// TODO: Implement reporter code type
2084+
case Compiler::CodeType::Reporter:
2085+
retType = m_valueDataType;
2086+
break;
2087+
20752088
case Compiler::CodeType::HatPredicate:
20762089
retType = m_builder.getInt1Ty();
20772090
break;
@@ -2902,6 +2915,43 @@ llvm::Value *LLVMCodeBuilder::createValue(LLVMRegister *reg)
29022915
return reg->value;
29032916
}
29042917

2918+
llvm::Value *LLVMCodeBuilder::createNewValue(LLVMRegister *reg)
2919+
{
2920+
// Same as createValue(), but creates a copy of the contents
2921+
// NOTE: It is the caller's responsibility to free the value.
2922+
if (reg->isConst())
2923+
return createValue(reg);
2924+
else if (reg->isRawValue) {
2925+
if (reg->type() == Compiler::StaticType::String) {
2926+
llvm::Value *value = castRawValue(reg, reg->type());
2927+
llvm::Value *ret = addAlloca(m_valueDataType);
2928+
2929+
// Allocate string
2930+
llvm::Value *result = m_builder.CreateCall(resolve_string_pool_new(), m_builder.getInt1(false)); // false: do not free after thread is dead
2931+
// NOTE: Do not free later
2932+
2933+
// Copy string
2934+
m_builder.CreateCall(resolve_string_assign(), { result, value });
2935+
2936+
// Store string pointer
2937+
llvm::Value *valueField = m_builder.CreateStructGEP(m_valueDataType, ret, 0);
2938+
m_builder.CreateStore(value, valueField);
2939+
2940+
// Store type
2941+
llvm::Value *typeField = m_builder.CreateStructGEP(m_valueDataType, ret, 1);
2942+
m_builder.CreateStore(m_builder.getInt32(static_cast<uint32_t>(ValueType::String)), typeField);
2943+
2944+
return ret;
2945+
} else
2946+
return createValue(reg);
2947+
} else {
2948+
llvm::Value *ret = addAlloca(m_valueDataType);
2949+
m_builder.CreateCall(resolve_value_init(), { ret });
2950+
m_builder.CreateCall(resolve_value_assign_copy(), { ret, reg->value });
2951+
return ret;
2952+
}
2953+
}
2954+
29052955
llvm::Value *LLVMCodeBuilder::createComparison(LLVMRegister *arg1, LLVMRegister *arg2, Comparison type)
29062956
{
29072957
auto type1 = arg1->type();
@@ -3372,6 +3422,11 @@ llvm::FunctionCallee LLVMCodeBuilder::resolve_string_alloc()
33723422
return resolveFunction("string_alloc", llvm::FunctionType::get(m_builder.getVoidTy(), { m_stringPtrType->getPointerTo(), m_builder.getInt64Ty() }, false));
33733423
}
33743424

3425+
llvm::FunctionCallee LLVMCodeBuilder::resolve_string_assign()
3426+
{
3427+
return resolveFunction("string_assign", llvm::FunctionType::get(m_builder.getVoidTy(), { m_stringPtrType->getPointerTo(), m_stringPtrType->getPointerTo() }, false));
3428+
}
3429+
33753430
llvm::FunctionCallee LLVMCodeBuilder::resolve_string_compare_case_sensitive()
33763431
{
33773432
llvm::Type *stringPtr = m_stringPtrType->getPointerTo();

src/engine/internal/llvm/llvmcodebuilder.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,7 @@ class LLVMCodeBuilder : public ICodeBuilder
170170
llvm::Value *getListItem(const LLVMListPtr &listPtr, llvm::Value *index);
171171
llvm::Value *getListItemIndex(const LLVMListPtr &listPtr, LLVMRegister *item);
172172
llvm::Value *createValue(LLVMRegister *reg);
173+
llvm::Value *createNewValue(LLVMRegister *reg);
173174
llvm::Value *createComparison(LLVMRegister *arg1, LLVMRegister *arg2, Comparison type);
174175
llvm::Value *createStringComparison(LLVMRegister *arg1, LLVMRegister *arg2, bool caseSensitive);
175176

@@ -209,6 +210,7 @@ class LLVMCodeBuilder : public ICodeBuilder
209210
llvm::FunctionCallee resolve_string_pool_new();
210211
llvm::FunctionCallee resolve_string_pool_free();
211212
llvm::FunctionCallee resolve_string_alloc();
213+
llvm::FunctionCallee resolve_string_assign();
212214
llvm::FunctionCallee resolve_string_compare_case_sensitive();
213215
llvm::FunctionCallee resolve_string_compare_case_insensitive();
214216

test/llvm/llvmcodebuilder_test.cpp

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,8 @@ class LLVMCodeBuilderTest : public testing::Test
8282
createBuilder(target, m_procedurePrototype.get());
8383
}
8484

85+
void createReporterBuilder(Target *target) { createBuilder(target, nullptr, Compiler::CodeType::Reporter); }
86+
8587
void createPredicateBuilder(Target *target) { createBuilder(target, nullptr, Compiler::CodeType::HatPredicate); }
8688

8789
void createBuilder(bool warp) { createBuilder(nullptr, warp); }
@@ -6032,3 +6034,62 @@ TEST_F(LLVMCodeBuilderTest, HatPredicates)
60326034

60336035
ASSERT_FALSE(code2->runPredicate(ctx.get()));
60346036
}
6037+
6038+
TEST_F(LLVMCodeBuilderTest, Reporters)
6039+
{
6040+
Sprite sprite;
6041+
auto var = std::make_shared<Variable>("", "");
6042+
var->setValue("Hello world!");
6043+
sprite.addVariable(var);
6044+
6045+
// Reporter 1
6046+
createReporterBuilder(&sprite);
6047+
6048+
CompilerValue *v = m_builder->addConstValue(-45.23);
6049+
m_builder->addFunctionCall("test_const_number", Compiler::StaticType::Number, { Compiler::StaticType::Number }, { v });
6050+
6051+
auto code1 = m_builder->finalize();
6052+
6053+
// Reporter 2
6054+
createReporterBuilder(&sprite);
6055+
6056+
v = m_builder->addConstValue("test");
6057+
m_builder->addFunctionCall("test_const_string", Compiler::StaticType::String, { Compiler::StaticType::String }, { v });
6058+
6059+
auto code2 = m_builder->finalize();
6060+
6061+
// Reporter 3
6062+
createReporterBuilder(&sprite);
6063+
m_builder->addVariableValue(var.get());
6064+
6065+
auto code3 = m_builder->finalize();
6066+
6067+
Script script1(&sprite, nullptr, nullptr);
6068+
script1.setCode(code1);
6069+
Thread thread1(&sprite, nullptr, &script1);
6070+
auto ctx = code1->createExecutionContext(&thread1);
6071+
6072+
ValueData ret = code1->runReporter(ctx.get());
6073+
ASSERT_TRUE(value_isNumber(&ret));
6074+
ASSERT_EQ(value_toDouble(&ret), -45.23);
6075+
value_free(&ret);
6076+
6077+
Script script2(&sprite, nullptr, nullptr);
6078+
script2.setCode(code2);
6079+
Thread thread2(&sprite, nullptr, &script2);
6080+
ctx = code2->createExecutionContext(&thread2);
6081+
6082+
ret = code2->runReporter(ctx.get());
6083+
ASSERT_EQ(Value(ret).toString(), "test");
6084+
value_free(&ret);
6085+
6086+
Script script3(&sprite, nullptr, nullptr);
6087+
script3.setCode(code3);
6088+
Thread thread3(&sprite, nullptr, &script3);
6089+
ctx = code3->createExecutionContext(&thread3);
6090+
6091+
ret = code3->runReporter(ctx.get());
6092+
var->setValue("abc"); // the string should be copied
6093+
ASSERT_EQ(Value(ret).toString(), "Hello world!");
6094+
value_free(&ret);
6095+
}

0 commit comments

Comments
 (0)