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,27 @@ 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+ VariablePtr &varPtr = m_variablePtrs[step.workVariable ];
423+ varPtr.changed = true ;
424+ createValueStore (arg.second , varPtr.ptr );
425+ break ;
426+ }
427+
428+ case Step::Type::ReadVariable: {
429+ assert (step.args .size () == 0 );
430+ const VariablePtr &varPtr = m_variablePtrs[step.workVariable ];
431+ step.functionReturnReg ->value = varPtr.ptr ;
432+ break ;
433+ }
434+
398435 case Step::Type::Yield:
399436 if (!m_warp) {
400437 freeHeap ();
438+ syncVariables (targetVariables);
401439 m_builder.CreateStore (m_builder.getInt1 (true ), coro.didSuspend );
402440 llvm::BasicBlock *resumeBranch = llvm::BasicBlock::Create (m_ctx, " " , func);
403441 llvm::Value *noneToken = llvm::ConstantTokenNone::get (m_ctx);
@@ -608,6 +646,7 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
608646 }
609647
610648 freeHeap ();
649+ syncVariables (targetVariables);
611650
612651 // Add final suspend point
613652 if (!m_warp) {
@@ -707,6 +746,18 @@ void LLVMCodeBuilder::addConstValue(const Value &value)
707746
708747void LLVMCodeBuilder::addVariableValue (Variable *variable)
709748{
749+ // TODO: Implement type prediction
750+ Step step (Step::Type::ReadVariable);
751+ step.workVariable = variable;
752+ m_variablePtrs[variable] = VariablePtr ();
753+
754+ auto ret = std::make_shared<Register>(Compiler::StaticType::Unknown);
755+ ret->isRawValue = false ;
756+ step.functionReturnReg = ret;
757+ m_regs[m_currentFunction].push_back (ret);
758+ m_tmpRegs.push_back (ret);
759+
760+ m_steps.push_back (step);
710761}
711762
712763void LLVMCodeBuilder::addListContents (List *list)
@@ -843,6 +894,13 @@ void LLVMCodeBuilder::createExp10()
843894 createOp (Step::Type::Exp10, Compiler::StaticType::Number, Compiler::StaticType::Number, 1 );
844895}
845896
897+ void LLVMCodeBuilder::createVariableWrite (Variable *variable)
898+ {
899+ Step &step = createOp (Step::Type::WriteVariable, Compiler::StaticType::Void, Compiler::StaticType::Unknown, 1 );
900+ step.workVariable = variable;
901+ m_variablePtrs[variable] = VariablePtr ();
902+ }
903+
846904void LLVMCodeBuilder::beginIfStatement ()
847905{
848906 Step step (Step::Type::BeginIf);
@@ -926,6 +984,36 @@ void LLVMCodeBuilder::initTypes()
926984 m_valueDataType->setBody ({ unionType, valueType, sizeType });
927985}
928986
987+ void LLVMCodeBuilder::createVariableMap ()
988+ {
989+ if (!m_target)
990+ return ;
991+
992+ // Map variable pointers to variable data array indices
993+ const auto &variables = m_target->variables ();
994+ ValueData **variableData = m_target->variableData ();
995+ const size_t len = variables.size ();
996+ m_targetVariableMap.clear ();
997+ m_targetVariableMap.reserve (len);
998+
999+ size_t i, j;
1000+
1001+ for (i = 0 ; i < len; i++) {
1002+ Variable *var = variables[i].get ();
1003+
1004+ // Find the data for this variable
1005+ for (j = 0 ; j < len; j++) {
1006+ if (variableData[j] == &var->valuePtr ()->data ())
1007+ break ;
1008+ }
1009+
1010+ if (j < len)
1011+ m_targetVariableMap[var] = j;
1012+ else
1013+ assert (false );
1014+ }
1015+ }
1016+
9291017LLVMCodeBuilder::Coroutine LLVMCodeBuilder::initCoroutine (llvm::Function *func)
9301018{
9311019 // Set presplitcoroutine attribute
@@ -1224,7 +1312,32 @@ llvm::Value *LLVMCodeBuilder::removeNaN(llvm::Value *num)
12241312 return m_builder.CreateSelect (isNaN (num), llvm::ConstantFP::get (m_ctx, llvm::APFloat (0.0 )), num);
12251313}
12261314
1227- void LLVMCodeBuilder::createOp (Step::Type type, Compiler::StaticType retType, Compiler::StaticType argType, size_t argCount)
1315+ llvm::Value *LLVMCodeBuilder::getVariablePtr (llvm::Value *targetVariables, Variable *variable)
1316+ {
1317+ if (!m_target->isStage () && variable->target () == m_target) {
1318+ // If this is a local sprite variable, use the variable array at runtime (for clones)
1319+ assert (m_targetVariableMap.find (variable) != m_targetVariableMap.cend ());
1320+ const size_t index = m_targetVariableMap[variable];
1321+ llvm::Value *ptr = m_builder.CreateGEP (m_valueDataType->getPointerTo (), targetVariables, m_builder.getInt64 (index));
1322+ return m_builder.CreateLoad (m_valueDataType->getPointerTo (), ptr);
1323+ }
1324+
1325+ // Otherwise create a raw pointer at compile time
1326+ llvm::Value *addr = m_builder.getInt64 ((uintptr_t )&variable->value ().data ());
1327+ return m_builder.CreateIntToPtr (addr, m_valueDataType->getPointerTo ());
1328+ }
1329+
1330+ void LLVMCodeBuilder::syncVariables (llvm::Value *targetVariables)
1331+ {
1332+ for (auto &[var, varPtr] : m_variablePtrs) {
1333+ if (varPtr.onStack && varPtr.changed )
1334+ createValueCopy (varPtr.ptr , getVariablePtr (targetVariables, var));
1335+
1336+ varPtr.changed = false ;
1337+ }
1338+ }
1339+
1340+ LLVMCodeBuilder::Step &LLVMCodeBuilder::createOp (Step::Type type, Compiler::StaticType retType, Compiler::StaticType argType, size_t argCount)
12281341{
12291342 Step step (type);
12301343
@@ -1236,13 +1349,71 @@ void LLVMCodeBuilder::createOp(Step::Type type, Compiler::StaticType retType, Co
12361349
12371350 m_tmpRegs.erase (m_tmpRegs.end () - argCount, m_tmpRegs.end ());
12381351
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);
1352+ if (retType != Compiler::StaticType::Void) {
1353+ auto ret = std::make_shared<Register>(retType);
1354+ ret->isRawValue = true ;
1355+ step.functionReturnReg = ret;
1356+ m_regs[m_currentFunction].push_back (ret);
1357+ m_tmpRegs.push_back (ret);
1358+ }
12441359
12451360 m_steps.push_back (step);
1361+ return m_steps.back ();
1362+ }
1363+
1364+ void LLVMCodeBuilder::createValueStore (std::shared_ptr<Register> reg, llvm::Value *targetPtr)
1365+ {
1366+ // TODO: Implement type prediction
1367+ Compiler::StaticType type = reg->type ;
1368+ llvm::Value *converted = nullptr ;
1369+
1370+ // Optimize string constants that represent numbers
1371+ if (reg->isConstValue && reg->type == Compiler::StaticType::String && reg->constValue .isValidNumber ())
1372+ type = Compiler::StaticType::Number;
1373+
1374+ switch (type) {
1375+ case Compiler::StaticType::Number:
1376+ converted = castValue (reg, type);
1377+ m_builder.CreateCall (resolve_value_assign_double (), { targetPtr, converted });
1378+ /* {
1379+ llvm::Value *ptr = m_builder.CreateStructGEP(m_valueDataType, targetPtr, 0);
1380+ m_builder.CreateStore(converted, ptr);
1381+ }*/
1382+ break ;
1383+
1384+ case Compiler::StaticType::Bool:
1385+ converted = castValue (reg, type);
1386+ m_builder.CreateCall (resolve_value_assign_bool (), { targetPtr, converted });
1387+ break ;
1388+
1389+ case Compiler::StaticType::String:
1390+ converted = castValue (reg, type);
1391+ m_builder.CreateCall (resolve_value_assign_cstring (), { targetPtr, converted });
1392+ break ;
1393+
1394+ case Compiler::StaticType::Unknown:
1395+ m_builder.CreateCall (resolve_value_assign_copy (), { targetPtr, reg->value });
1396+ break ;
1397+
1398+ default :
1399+ assert (false );
1400+ break ;
1401+ }
1402+ }
1403+
1404+ void LLVMCodeBuilder::createValueCopy (llvm::Value *source, llvm::Value *target)
1405+ {
1406+ // NOTE: This doesn't copy strings, but only the pointers
1407+ copyStructField (source, target, 0 , m_valueDataType, m_builder.getInt64Ty ()); // value
1408+ copyStructField (source, target, 1 , m_valueDataType, m_builder.getInt32Ty ()); // type
1409+ copyStructField (source, target, 2 , m_valueDataType, m_builder.getInt64Ty ()); // string size
1410+ }
1411+
1412+ void LLVMCodeBuilder::copyStructField (llvm::Value *source, llvm::Value *target, int index, llvm::StructType *structType, llvm::Type *fieldType)
1413+ {
1414+ llvm::Value *sourceField = m_builder.CreateStructGEP (structType, source, index);
1415+ llvm::Value *targetField = m_builder.CreateStructGEP (structType, target, index);
1416+ m_builder.CreateStore (m_builder.CreateLoad (fieldType, sourceField), targetField);
12461417}
12471418
12481419llvm::Value *LLVMCodeBuilder::createValue (std::shared_ptr<Register> reg)
@@ -1505,6 +1676,11 @@ llvm::FunctionCallee LLVMCodeBuilder::resolve_value_assign_special()
15051676 return resolveFunction (" value_assign_special" , llvm::FunctionType::get (m_builder.getVoidTy (), { m_valueDataType->getPointerTo (), m_builder.getInt32Ty () }, false ));
15061677}
15071678
1679+ llvm::FunctionCallee LLVMCodeBuilder::resolve_value_assign_copy ()
1680+ {
1681+ return resolveFunction (" value_assign_copy" , llvm::FunctionType::get (m_builder.getVoidTy (), { m_valueDataType->getPointerTo (), m_valueDataType->getPointerTo () }, false ));
1682+ }
1683+
15081684llvm::FunctionCallee LLVMCodeBuilder::resolve_value_toDouble ()
15091685{
15101686 return resolveFunction (" value_toDouble" , llvm::FunctionType::get (m_builder.getDoubleTy (), m_valueDataType->getPointerTo (), false ));
0 commit comments