55#include < llvm/ExecutionEngine/Orc/LLJIT.h>
66#include < llvm/Passes/PassBuilder.h>
77
8+ #include < scratchcpp/stage.h>
9+ #include < scratchcpp/iengine.h>
10+ #include < scratchcpp/variable.h>
11+
812#include " llvmcodebuilder.h"
913#include " llvmexecutablecode.h"
1014
@@ -28,6 +32,7 @@ LLVMCodeBuilder::LLVMCodeBuilder(Target *target, const std::string &id, bool war
2832 m_constValues.push_back ({});
2933 m_regs.push_back ({});
3034 initTypes ();
35+ createVariableMap ();
3136}
3237
3338std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize ()
@@ -41,10 +46,12 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
4146 }
4247
4348 // Create function
44- // void *f(Target *)
49+ // void *f(Target *, ValueData ** )
4550 llvm::PointerType *pointerType = llvm::PointerType::get (llvm::Type::getInt8Ty (m_ctx), 0 );
46- llvm::FunctionType *funcType = llvm::FunctionType::get (pointerType, pointerType, false );
51+ llvm::FunctionType *funcType = llvm::FunctionType::get (pointerType, { pointerType, pointerType } , false );
4752 llvm::Function *func = llvm::Function::Create (funcType, llvm::Function::ExternalLinkage, " f" , m_module.get ());
53+ llvm::Value *targetPtr = func->getArg (0 );
54+ llvm::Value *targetVariables = func->getArg (1 );
4855
4956 llvm::BasicBlock *entry = llvm::BasicBlock::Create (m_ctx, " entry" , func);
5057 m_builder.SetInsertPoint (entry);
@@ -59,6 +66,20 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
5966 std::vector<Loop> loops;
6067 m_heap.clear ();
6168
69+ // Create variable pointers
70+ for (auto &[var, varPtr] : m_variablePtrs) {
71+ llvm::Value *ptr = getVariablePtr (targetVariables, var);
72+
73+ // Access variable directly (slow?)
74+ // varPtr.ptr = ptr;
75+
76+ // All variables are currently copied to the stack and synced later (seems to be faster)
77+ // NOTE: Strings are NOT copied, only the pointer and string size are copied
78+ varPtr.ptr = m_builder.CreateAlloca (m_valueDataType);
79+ varPtr.onStack = true ;
80+ createValueCopy (ptr, varPtr.ptr );
81+ }
82+
6283 // Execute recorded steps
6384 for (const Step &step : m_steps) {
6485 switch (step.type ) {
@@ -67,9 +88,8 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
6788 std::vector<llvm::Value *> args;
6889
6990 // Add target pointer arg
70- assert (func->arg_size () == 1 );
7191 types.push_back (llvm::PointerType::get (llvm::Type::getInt8Ty (m_ctx), 0 ));
72- args.push_back (func-> getArg ( 0 ) );
92+ args.push_back (targetPtr );
7393
7494 // Args
7595 for (auto &arg : step.args ) {
@@ -395,9 +415,26 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
395415 break ;
396416 }
397417
418+ case Step::Type::WriteVariable: {
419+ assert (step.args .size () == 1 );
420+ assert (m_variablePtrs.find (step.workVariable ) != m_variablePtrs.cend ());
421+ const auto &arg = step.args [0 ];
422+ const VariablePtr &varPtr = m_variablePtrs[step.workVariable ];
423+ createValueStore (arg.second , varPtr.ptr );
424+ break ;
425+ }
426+
427+ case Step::Type::ReadVariable: {
428+ assert (step.args .size () == 0 );
429+ const VariablePtr &varPtr = m_variablePtrs[step.workVariable ];
430+ step.functionReturnReg ->value = varPtr.ptr ;
431+ break ;
432+ }
433+
398434 case Step::Type::Yield:
399435 if (!m_warp) {
400436 freeHeap ();
437+ syncVariables (targetVariables);
401438 m_builder.CreateStore (m_builder.getInt1 (true ), coro.didSuspend );
402439 llvm::BasicBlock *resumeBranch = llvm::BasicBlock::Create (m_ctx, " " , func);
403440 llvm::Value *noneToken = llvm::ConstantTokenNone::get (m_ctx);
@@ -608,6 +645,7 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
608645 }
609646
610647 freeHeap ();
648+ syncVariables (targetVariables);
611649
612650 // Add final suspend point
613651 if (!m_warp) {
@@ -707,6 +745,18 @@ void LLVMCodeBuilder::addConstValue(const Value &value)
707745
708746void LLVMCodeBuilder::addVariableValue (Variable *variable)
709747{
748+ // TODO: Implement type prediction
749+ Step step (Step::Type::ReadVariable);
750+ step.workVariable = variable;
751+ m_variablePtrs[variable] = VariablePtr ();
752+
753+ auto ret = std::make_shared<Register>(Compiler::StaticType::Unknown);
754+ ret->isRawValue = false ;
755+ step.functionReturnReg = ret;
756+ m_regs[m_currentFunction].push_back (ret);
757+ m_tmpRegs.push_back (ret);
758+
759+ m_steps.push_back (step);
710760}
711761
712762void LLVMCodeBuilder::addListContents (List *list)
@@ -843,6 +893,13 @@ void LLVMCodeBuilder::createExp10()
843893 createOp (Step::Type::Exp10, Compiler::StaticType::Number, Compiler::StaticType::Number, 1 );
844894}
845895
896+ void LLVMCodeBuilder::createVariableWrite (Variable *variable)
897+ {
898+ Step &step = createOp (Step::Type::WriteVariable, Compiler::StaticType::Void, Compiler::StaticType::Unknown, 1 );
899+ step.workVariable = variable;
900+ m_variablePtrs[variable] = VariablePtr ();
901+ }
902+
846903void LLVMCodeBuilder::beginIfStatement ()
847904{
848905 Step step (Step::Type::BeginIf);
@@ -926,6 +983,36 @@ void LLVMCodeBuilder::initTypes()
926983 m_valueDataType->setBody ({ unionType, valueType, sizeType });
927984}
928985
986+ void LLVMCodeBuilder::createVariableMap ()
987+ {
988+ if (!m_target)
989+ return ;
990+
991+ // Map variable pointers to variable data array indices
992+ const auto &variables = m_target->variables ();
993+ ValueData **variableData = m_target->variableData ();
994+ const size_t len = variables.size ();
995+ m_targetVariableMap.clear ();
996+ m_targetVariableMap.reserve (len);
997+
998+ size_t i, j;
999+
1000+ for (i = 0 ; i < len; i++) {
1001+ Variable *var = variables[i].get ();
1002+
1003+ // Find the data for this variable
1004+ for (j = 0 ; j < len; j++) {
1005+ if (variableData[j] == &var->valuePtr ()->data ())
1006+ break ;
1007+ }
1008+
1009+ if (j < len)
1010+ m_targetVariableMap[var] = j;
1011+ else
1012+ assert (false );
1013+ }
1014+ }
1015+
9291016LLVMCodeBuilder::Coroutine LLVMCodeBuilder::initCoroutine (llvm::Function *func)
9301017{
9311018 // Set presplitcoroutine attribute
@@ -1224,7 +1311,30 @@ llvm::Value *LLVMCodeBuilder::removeNaN(llvm::Value *num)
12241311 return m_builder.CreateSelect (isNaN (num), llvm::ConstantFP::get (m_ctx, llvm::APFloat (0.0 )), num);
12251312}
12261313
1227- void LLVMCodeBuilder::createOp (Step::Type type, Compiler::StaticType retType, Compiler::StaticType argType, size_t argCount)
1314+ llvm::Value *LLVMCodeBuilder::getVariablePtr (llvm::Value *targetVariables, Variable *variable)
1315+ {
1316+ if (!m_target->isStage () && variable->target () == m_target) {
1317+ // If this is a local sprite variable, use the variable array at runtime (for clones)
1318+ assert (m_targetVariableMap.find (variable) != m_targetVariableMap.cend ());
1319+ const size_t index = m_targetVariableMap[variable];
1320+ llvm::Value *ptr = m_builder.CreateGEP (m_valueDataType->getPointerTo (), targetVariables, m_builder.getInt64 (index));
1321+ return m_builder.CreateLoad (m_valueDataType->getPointerTo (), ptr);
1322+ }
1323+
1324+ // Otherwise create a raw pointer at compile time
1325+ llvm::Value *addr = m_builder.getInt64 ((uintptr_t )&variable->value ().data ());
1326+ return m_builder.CreateIntToPtr (addr, m_valueDataType->getPointerTo ());
1327+ }
1328+
1329+ void LLVMCodeBuilder::syncVariables (llvm::Value *targetVariables)
1330+ {
1331+ for (const auto &[var, varPtr] : m_variablePtrs) {
1332+ if (varPtr.onStack )
1333+ createValueCopy (varPtr.ptr , getVariablePtr (targetVariables, var));
1334+ }
1335+ }
1336+
1337+ LLVMCodeBuilder::Step &LLVMCodeBuilder::createOp (Step::Type type, Compiler::StaticType retType, Compiler::StaticType argType, size_t argCount)
12281338{
12291339 Step step (type);
12301340
@@ -1236,13 +1346,71 @@ void LLVMCodeBuilder::createOp(Step::Type type, Compiler::StaticType retType, Co
12361346
12371347 m_tmpRegs.erase (m_tmpRegs.end () - argCount, m_tmpRegs.end ());
12381348
1239- auto ret = std::make_shared<Register>(retType);
1240- ret->isRawValue = true ;
1241- step.functionReturnReg = ret;
1242- m_regs[m_currentFunction].push_back (ret);
1243- m_tmpRegs.push_back (ret);
1349+ if (retType != Compiler::StaticType::Void) {
1350+ auto ret = std::make_shared<Register>(retType);
1351+ ret->isRawValue = true ;
1352+ step.functionReturnReg = ret;
1353+ m_regs[m_currentFunction].push_back (ret);
1354+ m_tmpRegs.push_back (ret);
1355+ }
12441356
12451357 m_steps.push_back (step);
1358+ return m_steps.back ();
1359+ }
1360+
1361+ void LLVMCodeBuilder::createValueStore (std::shared_ptr<Register> value, llvm::Value *targetPtr)
1362+ {
1363+ // TODO: Implement type prediction
1364+ Compiler::StaticType type = value->type ;
1365+ llvm::Value *converted = nullptr ;
1366+
1367+ // Optimize string constants that represent numbers
1368+ if (value->isConstValue && value->type == Compiler::StaticType::String && value->constValue .isValidNumber ())
1369+ type = Compiler::StaticType::Number;
1370+
1371+ switch (type) {
1372+ case Compiler::StaticType::Number:
1373+ converted = castValue (value, type);
1374+ m_builder.CreateCall (resolve_value_assign_double (), { targetPtr, converted });
1375+ /* {
1376+ llvm::Value *ptr = m_builder.CreateStructGEP(m_valueDataType, targetPtr, 0);
1377+ m_builder.CreateStore(converted, ptr);
1378+ }*/
1379+ break ;
1380+
1381+ case Compiler::StaticType::Bool:
1382+ converted = castValue (value, type);
1383+ m_builder.CreateCall (resolve_value_assign_bool (), { targetPtr, converted });
1384+ break ;
1385+
1386+ case Compiler::StaticType::String:
1387+ converted = castValue (value, type);
1388+ m_builder.CreateCall (resolve_value_assign_cstring (), { targetPtr, converted });
1389+ break ;
1390+
1391+ case Compiler::StaticType::Unknown:
1392+ m_builder.CreateCall (resolve_value_assign_copy (), { targetPtr, value->value });
1393+ break ;
1394+
1395+ default :
1396+ assert (false );
1397+ break ;
1398+ }
1399+ }
1400+
1401+ void LLVMCodeBuilder::createValueCopy (llvm::Value *source, llvm::Value *target)
1402+ {
1403+ // NOTE: This doesn't copy strings, but only the pointers
1404+ copyStructField (source, target, 0 , m_valueDataType, m_builder.getInt64Ty ()); // value
1405+ copyStructField (source, target, 1 , m_valueDataType, m_builder.getInt32Ty ()); // type
1406+ copyStructField (source, target, 2 , m_valueDataType, m_builder.getInt64Ty ()); // string size
1407+ }
1408+
1409+ void LLVMCodeBuilder::copyStructField (llvm::Value *source, llvm::Value *target, int index, llvm::StructType *structType, llvm::Type *fieldType)
1410+ {
1411+ llvm::Value *sourceField = m_builder.CreateStructGEP (structType, source, 0 );
1412+ llvm::Value *targetField = m_builder.CreateStructGEP (structType, target, 0 );
1413+ m_builder.CreateStore (m_builder.CreateLoad (fieldType, sourceField), targetField);
12461414}
12471415
12481416llvm::Value *LLVMCodeBuilder::createValue (std::shared_ptr<Register> reg)
@@ -1505,6 +1673,11 @@ llvm::FunctionCallee LLVMCodeBuilder::resolve_value_assign_special()
15051673 return resolveFunction (" value_assign_special" , llvm::FunctionType::get (m_builder.getVoidTy (), { m_valueDataType->getPointerTo (), m_builder.getInt32Ty () }, false ));
15061674}
15071675
1676+ llvm::FunctionCallee LLVMCodeBuilder::resolve_value_assign_copy ()
1677+ {
1678+ return resolveFunction (" value_assign_copy" , llvm::FunctionType::get (m_builder.getVoidTy (), { m_valueDataType->getPointerTo (), m_valueDataType->getPointerTo () }, false ));
1679+ }
1680+
15081681llvm::FunctionCallee LLVMCodeBuilder::resolve_value_toDouble ()
15091682{
15101683 return resolveFunction (" value_toDouble" , llvm::FunctionType::get (m_builder.getDoubleTy (), m_valueDataType->getPointerTo (), false ));
0 commit comments