@@ -80,16 +80,18 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
80
80
for (auto &[var, varPtr] : m_variablePtrs) {
81
81
llvm::Value *ptr = getVariablePtr (targetVariables, var);
82
82
83
- // Access variable directly (slow?)
84
- // varPtr.ptr = ptr;
83
+ // Direct access
84
+ varPtr.heapPtr = ptr;
85
85
86
- // All variables are currently copied to the stack and synced later (seems to be faster)
86
+ // All variables are currently created on the stack and synced later (seems to be faster)
87
87
// NOTE: Strings are NOT copied, only the pointer and string size are copied
88
- varPtr.ptr = m_builder.CreateAlloca (m_valueDataType);
89
- varPtr.onStack = true ;
90
- createValueCopy (ptr, varPtr.ptr );
88
+ varPtr.stackPtr = m_builder.CreateAlloca (m_valueDataType);
89
+ varPtr.onStack = false ; // use heap before the first assignment
91
90
}
92
91
92
+ m_scopeVariables.clear ();
93
+ m_scopeVariables.push_back ({});
94
+
93
95
// Execute recorded steps
94
96
for (const LLVMInstruction &step : m_instructions) {
95
97
switch (step.type ) {
@@ -430,16 +432,41 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
430
432
assert (step.args .size () == 1 );
431
433
assert (m_variablePtrs.find (step.workVariable ) != m_variablePtrs.cend ());
432
434
const auto &arg = step.args [0 ];
435
+ Compiler::StaticType type = optimizeRegisterType (arg.second );
433
436
LLVMVariablePtr &varPtr = m_variablePtrs[step.workVariable ];
434
437
varPtr.changed = true ;
435
- createValueStore (arg.second , varPtr.ptr );
438
+
439
+ // Initialize stack variable on first assignment
440
+ if (!varPtr.onStack ) {
441
+ varPtr.onStack = true ;
442
+ varPtr.type = type; // don't care about unknown type on first assignment
443
+
444
+ ValueType mappedType;
445
+
446
+ if (type == Compiler::StaticType::String || type == Compiler::StaticType::Unknown) {
447
+ // Value functions are used for these types, so don't break them
448
+ mappedType = ValueType::Number;
449
+ } else {
450
+ auto it = std::find_if (TYPE_MAP.begin (), TYPE_MAP.end (), [type](const std::pair<ValueType, Compiler::StaticType> &pair) { return pair.second == type; });
451
+ assert (it != TYPE_MAP.cend ());
452
+ mappedType = it->first ;
453
+ }
454
+
455
+ llvm::Value *typeField = m_builder.CreateStructGEP (m_valueDataType, varPtr.stackPtr , 1 );
456
+ m_builder.CreateStore (m_builder.getInt32 (static_cast <uint32_t >(mappedType)), typeField);
457
+ }
458
+
459
+ createValueStore (arg.second , varPtr.stackPtr , type, varPtr.type );
460
+ varPtr.type = type;
461
+ m_scopeVariables.back ()[&varPtr] = varPtr.type ;
436
462
break ;
437
463
}
438
464
439
465
case LLVMInstruction::Type::ReadVariable: {
440
466
assert (step.args .size () == 0 );
441
467
const LLVMVariablePtr &varPtr = m_variablePtrs[step.workVariable ];
442
- step.functionReturnReg ->value = varPtr.ptr ;
468
+ step.functionReturnReg ->value = varPtr.onStack ? varPtr.stackPtr : varPtr.heapPtr ;
469
+ step.functionReturnReg ->type = varPtr.type ;
443
470
break ;
444
471
}
445
472
@@ -448,6 +475,7 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
448
475
freeHeap ();
449
476
syncVariables (targetVariables);
450
477
coro->createSuspend ();
478
+ reloadVariables (targetVariables);
451
479
}
452
480
453
481
break ;
@@ -468,13 +496,23 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
468
496
m_builder.SetInsertPoint (statement.body );
469
497
470
498
ifStatements.push_back (statement);
499
+ pushScopeLevel ();
471
500
break ;
472
501
}
473
502
474
503
case LLVMInstruction::Type::BeginElse: {
475
504
assert (!ifStatements.empty ());
476
505
LLVMIfStatement &statement = ifStatements.back ();
477
506
507
+ // Restore types from parent scope
508
+ std::unordered_map<LLVMVariablePtr *, Compiler::StaticType> parentScopeVariables = m_scopeVariables[m_scopeVariables.size () - 2 ]; // no reference!
509
+ popScopeLevel ();
510
+
511
+ for (auto &[ptr, type] : parentScopeVariables)
512
+ ptr->type = type;
513
+
514
+ pushScopeLevel ();
515
+
478
516
// Jump to the branch after the if statement
479
517
assert (!statement.afterIf );
480
518
statement.afterIf = llvm::BasicBlock::Create (m_ctx, " " , func);
@@ -516,6 +554,7 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
516
554
m_builder.SetInsertPoint (statement.afterIf );
517
555
518
556
ifStatements.pop_back ();
557
+ popScopeLevel ();
519
558
break ;
520
559
}
521
560
@@ -569,6 +608,7 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
569
608
m_builder.SetInsertPoint (body);
570
609
571
610
loops.push_back (loop);
611
+ pushScopeLevel ();
572
612
break ;
573
613
}
574
614
@@ -590,6 +630,7 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
590
630
591
631
// Switch to body branch
592
632
m_builder.SetInsertPoint (body);
633
+ pushScopeLevel ();
593
634
break ;
594
635
}
595
636
@@ -611,6 +652,7 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
611
652
612
653
// Switch to body branch
613
654
m_builder.SetInsertPoint (body);
655
+ pushScopeLevel ();
614
656
break ;
615
657
}
616
658
@@ -644,6 +686,7 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
644
686
m_builder.SetInsertPoint (loop.afterLoop );
645
687
646
688
loops.pop_back ();
689
+ popScopeLevel ();
647
690
break ;
648
691
}
649
692
}
@@ -728,7 +771,6 @@ void LLVMCodeBuilder::addConstValue(const Value &value)
728
771
729
772
void LLVMCodeBuilder::addVariableValue (Variable *variable)
730
773
{
731
- // TODO: Implement type prediction
732
774
LLVMInstruction ins (LLVMInstruction::Type::ReadVariable);
733
775
ins.workVariable = variable;
734
776
m_variablePtrs[variable] = LLVMVariablePtr ();
@@ -989,6 +1031,23 @@ void LLVMCodeBuilder::createVariableMap()
989
1031
}
990
1032
}
991
1033
1034
+ void LLVMCodeBuilder::pushScopeLevel ()
1035
+ {
1036
+ m_scopeVariables.push_back ({});
1037
+ }
1038
+
1039
+ void LLVMCodeBuilder::popScopeLevel ()
1040
+ {
1041
+ for (size_t i = 0 ; i < m_scopeVariables.size () - 1 ; i++) {
1042
+ for (auto &[ptr, type] : m_scopeVariables[i]) {
1043
+ if (ptr->type != type)
1044
+ ptr->type = Compiler::StaticType::Unknown;
1045
+ }
1046
+ }
1047
+
1048
+ m_scopeVariables.pop_back ();
1049
+ }
1050
+
992
1051
void LLVMCodeBuilder::verifyFunction (llvm::Function *func)
993
1052
{
994
1053
if (llvm::verifyFunction (*func, &llvm::errs ())) {
@@ -1198,6 +1257,17 @@ llvm::Constant *LLVMCodeBuilder::castConstValue(const Value &value, Compiler::St
1198
1257
}
1199
1258
}
1200
1259
1260
+ Compiler::StaticType LLVMCodeBuilder::optimizeRegisterType (LLVMRegisterPtr reg)
1261
+ {
1262
+ Compiler::StaticType ret = reg->type ;
1263
+
1264
+ // Optimize string constants that represent numbers
1265
+ if (reg->isConstValue && reg->type == Compiler::StaticType::String && reg->constValue .isValidNumber ())
1266
+ ret = Compiler::StaticType::Number;
1267
+
1268
+ return ret;
1269
+ }
1270
+
1201
1271
llvm::Type *LLVMCodeBuilder::getType (Compiler::StaticType type)
1202
1272
{
1203
1273
switch (type) {
@@ -1247,14 +1317,25 @@ llvm::Value *LLVMCodeBuilder::getVariablePtr(llvm::Value *targetVariables, Varia
1247
1317
1248
1318
void LLVMCodeBuilder::syncVariables (llvm::Value *targetVariables)
1249
1319
{
1320
+ // Copy stack variables to the actual variables
1250
1321
for (auto &[var, varPtr] : m_variablePtrs) {
1251
1322
if (varPtr.onStack && varPtr.changed )
1252
- createValueCopy (varPtr.ptr , getVariablePtr (targetVariables, var));
1323
+ createValueCopy (varPtr.stackPtr , getVariablePtr (targetVariables, var));
1253
1324
1254
1325
varPtr.changed = false ;
1255
1326
}
1256
1327
}
1257
1328
1329
+ void LLVMCodeBuilder::reloadVariables (llvm::Value *targetVariables)
1330
+ {
1331
+ // Reset variables to use heap
1332
+ for (auto &[var, varPtr] : m_variablePtrs) {
1333
+ varPtr.onStack = false ;
1334
+ varPtr.changed = false ;
1335
+ varPtr.type = Compiler::StaticType::Unknown;
1336
+ }
1337
+ }
1338
+
1258
1339
LLVMInstruction &LLVMCodeBuilder::createOp (LLVMInstruction::Type type, Compiler::StaticType retType, Compiler::StaticType argType, size_t argCount)
1259
1340
{
1260
1341
LLVMInstruction ins (type);
@@ -1279,33 +1360,69 @@ LLVMInstruction &LLVMCodeBuilder::createOp(LLVMInstruction::Type type, Compiler:
1279
1360
return m_instructions.back ();
1280
1361
}
1281
1362
1282
- void LLVMCodeBuilder::createValueStore (LLVMRegisterPtr reg, llvm::Value *targetPtr)
1363
+ void LLVMCodeBuilder::createValueStore (LLVMRegisterPtr reg, llvm::Value *targetPtr, Compiler::StaticType sourceType, Compiler::StaticType targetType )
1283
1364
{
1284
- // TODO: Implement type prediction
1285
- Compiler::StaticType type = reg->type ;
1286
1365
llvm::Value *converted = nullptr ;
1287
1366
1288
- // Optimize string constants that represent numbers
1289
- if (reg->isConstValue && reg->type == Compiler::StaticType::String && reg->constValue .isValidNumber ())
1290
- type = Compiler::StaticType::Number;
1367
+ if (sourceType != Compiler::StaticType::Unknown)
1368
+ converted = castValue (reg, sourceType);
1291
1369
1292
- switch (type) {
1370
+ auto it = std::find_if (TYPE_MAP.begin (), TYPE_MAP.end (), [sourceType](const std::pair<ValueType, Compiler::StaticType> &pair) { return pair.second == sourceType; });
1371
+ const ValueType mappedType = it == TYPE_MAP.cend () ? ValueType::Number : it->first ; // unknown type can be ignored
1372
+
1373
+ switch (sourceType) {
1293
1374
case Compiler::StaticType::Number:
1294
- converted = castValue (reg, type);
1295
- m_builder.CreateCall (resolve_value_assign_double (), { targetPtr, converted });
1296
- /* {
1297
- llvm::Value *ptr = m_builder.CreateStructGEP(m_valueDataType, targetPtr, 0);
1298
- m_builder.CreateStore(converted, ptr);
1299
- }*/
1375
+ switch (targetType) {
1376
+ case Compiler::StaticType::Number: {
1377
+ // Write number to number directly
1378
+ llvm::Value *ptr = m_builder.CreateStructGEP (m_valueDataType, targetPtr, 0 );
1379
+ m_builder.CreateStore (converted, ptr);
1380
+ break ;
1381
+ }
1382
+
1383
+ case Compiler::StaticType::Bool: {
1384
+ // Write number to bool value directly and change type
1385
+ llvm::Value *ptr = m_builder.CreateStructGEP (m_valueDataType, targetPtr, 0 );
1386
+ llvm::Value *typePtr = m_builder.CreateStructGEP (m_valueDataType, targetPtr, 0 );
1387
+ m_builder.CreateStore (converted, ptr);
1388
+ m_builder.CreateStore (m_builder.getInt32 (static_cast <uint32_t >(mappedType)), typePtr);
1389
+ break ;
1390
+ }
1391
+
1392
+ default :
1393
+ m_builder.CreateCall (resolve_value_assign_double (), { targetPtr, converted });
1394
+ break ;
1395
+ }
1396
+
1300
1397
break ;
1301
1398
1302
1399
case Compiler::StaticType::Bool:
1303
- converted = castValue (reg, type);
1304
- m_builder.CreateCall (resolve_value_assign_bool (), { targetPtr, converted });
1400
+ switch (targetType) {
1401
+ case Compiler::StaticType::Number: {
1402
+ // Write bool to number value directly and change type
1403
+ llvm::Value *ptr = m_builder.CreateStructGEP (m_valueDataType, targetPtr, 0 );
1404
+ m_builder.CreateStore (converted, ptr);
1405
+ llvm::Value *typePtr = m_builder.CreateStructGEP (m_valueDataType, targetPtr, 0 );
1406
+ m_builder.CreateStore (converted, ptr);
1407
+ m_builder.CreateStore (m_builder.getInt32 (static_cast <uint32_t >(mappedType)), typePtr);
1408
+ break ;
1409
+ }
1410
+
1411
+ case Compiler::StaticType::Bool: {
1412
+ // Write bool to bool directly
1413
+ llvm::Value *ptr = m_builder.CreateStructGEP (m_valueDataType, targetPtr, 0 );
1414
+ m_builder.CreateStore (converted, ptr);
1415
+ break ;
1416
+ }
1417
+
1418
+ default :
1419
+ m_builder.CreateCall (resolve_value_assign_bool (), { targetPtr, converted });
1420
+ break ;
1421
+ }
1422
+
1305
1423
break ;
1306
1424
1307
1425
case Compiler::StaticType::String:
1308
- converted = castValue (reg, type);
1309
1426
m_builder.CreateCall (resolve_value_assign_cstring (), { targetPtr, converted });
1310
1427
break ;
1311
1428
0 commit comments