Skip to content

Commit 31dbd17

Browse files
committed
Implement casting from mixed type values
1 parent 8db2ec3 commit 31dbd17

File tree

6 files changed

+596
-51
lines changed

6 files changed

+596
-51
lines changed

src/engine/internal/llvm/llvmbuildutils.cpp

Lines changed: 258 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -414,86 +414,293 @@ llvm::Value *LLVMBuildUtils::castValue(LLVMRegister *reg, Compiler::StaticType t
414414
assert(reg->type() != Compiler::StaticType::Void && targetType != Compiler::StaticType::Void);
415415

416416
switch (targetType) {
417-
case Compiler::StaticType::Number:
418-
switch (reg->type()) {
419-
case Compiler::StaticType::Number: {
420-
// Read number directly
417+
case Compiler::StaticType::Number: {
418+
Compiler::StaticType type = reg->type();
419+
bool singleType = isSingleType(type);
420+
421+
if (singleType) {
422+
// Handle single type cases directly
423+
switch (type) {
424+
case Compiler::StaticType::Number: {
425+
// Read number directly
426+
llvm::Value *ptr = m_builder.CreateStructGEP(m_valueDataType, reg->value, 0);
427+
return m_builder.CreateLoad(m_builder.getDoubleTy(), ptr);
428+
}
429+
430+
case Compiler::StaticType::Bool: {
431+
// Read boolean and cast to double
432+
llvm::Value *ptr = m_builder.CreateStructGEP(m_valueDataType, reg->value, 0);
433+
llvm::Value *boolValue = m_builder.CreateLoad(m_builder.getInt1Ty(), ptr);
434+
return m_builder.CreateUIToFP(boolValue, m_builder.getDoubleTy());
435+
}
436+
437+
case Compiler::StaticType::String:
438+
// Convert to double
439+
// TODO: Use value_stringToDouble()
440+
return m_builder.CreateCall(m_functions.resolve_value_toDouble(), reg->value);
441+
442+
default:
443+
assert(false);
444+
return nullptr;
445+
}
446+
} else {
447+
// Handle multiple type cases with runtime switch
448+
llvm::Value *typePtr = m_builder.CreateStructGEP(m_valueDataType, reg->value, 1);
449+
llvm::Value *loadedType = m_builder.CreateLoad(m_builder.getInt32Ty(), typePtr);
450+
451+
llvm::BasicBlock *mergeBlock = llvm::BasicBlock::Create(m_llvmCtx, "merge", m_function);
452+
llvm::BasicBlock *defaultBlock = llvm::BasicBlock::Create(m_llvmCtx, "default", m_function);
453+
454+
llvm::SwitchInst *sw = m_builder.CreateSwitch(loadedType, defaultBlock, 4);
455+
456+
std::vector<std::pair<llvm::BasicBlock *, llvm::Value *>> results;
457+
458+
// Number case
459+
if ((type & Compiler::StaticType::Number) == Compiler::StaticType::Number) {
460+
llvm::BasicBlock *numberBlock = llvm::BasicBlock::Create(m_llvmCtx, "number", m_function);
461+
sw->addCase(m_builder.getInt32(static_cast<uint32_t>(ValueType::Number)), numberBlock);
462+
463+
m_builder.SetInsertPoint(numberBlock);
421464
llvm::Value *ptr = m_builder.CreateStructGEP(m_valueDataType, reg->value, 0);
422-
return m_builder.CreateLoad(m_builder.getDoubleTy(), ptr);
465+
llvm::Value *numberResult = m_builder.CreateLoad(m_builder.getDoubleTy(), ptr);
466+
m_builder.CreateBr(mergeBlock);
467+
results.push_back({ numberBlock, numberResult });
423468
}
424469

425-
case Compiler::StaticType::Bool: {
426-
// Read boolean and cast to double
470+
// Bool case
471+
if ((type & Compiler::StaticType::Bool) == Compiler::StaticType::Bool) {
472+
llvm::BasicBlock *boolBlock = llvm::BasicBlock::Create(m_llvmCtx, "bool", m_function);
473+
sw->addCase(m_builder.getInt32(static_cast<uint32_t>(ValueType::Bool)), boolBlock);
474+
475+
m_builder.SetInsertPoint(boolBlock);
427476
llvm::Value *ptr = m_builder.CreateStructGEP(m_valueDataType, reg->value, 0);
428477
llvm::Value *boolValue = m_builder.CreateLoad(m_builder.getInt1Ty(), ptr);
429-
return m_builder.CreateSIToFP(boolValue, m_builder.getDoubleTy());
478+
llvm::Value *boolResult = m_builder.CreateUIToFP(boolValue, m_builder.getDoubleTy());
479+
m_builder.CreateBr(mergeBlock);
480+
results.push_back({ boolBlock, boolResult });
430481
}
431482

432-
case Compiler::StaticType::String:
433-
case Compiler::StaticType::Unknown: {
434-
// Convert to double
435-
return m_builder.CreateCall(m_functions.resolve_value_toDouble(), reg->value);
483+
// String case
484+
if ((type & Compiler::StaticType::String) == Compiler::StaticType::String) {
485+
llvm::BasicBlock *stringBlock = llvm::BasicBlock::Create(m_llvmCtx, "string", m_function);
486+
sw->addCase(m_builder.getInt32(static_cast<uint32_t>(ValueType::String)), stringBlock);
487+
488+
m_builder.SetInsertPoint(stringBlock);
489+
// TODO: Use value_stringToDouble()
490+
llvm::Value *stringResult = m_builder.CreateCall(m_functions.resolve_value_toDouble(), reg->value);
491+
m_builder.CreateBr(mergeBlock);
492+
results.push_back({ stringBlock, stringResult });
436493
}
437494

438-
default:
439-
assert(false);
440-
return nullptr;
495+
// Default case
496+
m_builder.SetInsertPoint(defaultBlock);
497+
498+
// All possible types are covered, mark as unreachable
499+
m_builder.CreateUnreachable();
500+
501+
// Create phi node to merge results
502+
m_builder.SetInsertPoint(mergeBlock);
503+
llvm::PHINode *result = m_builder.CreatePHI(m_builder.getDoubleTy(), results.size());
504+
505+
for (auto &pair : results)
506+
result->addIncoming(pair.second, pair.first);
507+
508+
return result;
441509
}
510+
}
442511

443-
case Compiler::StaticType::Bool:
444-
switch (reg->type()) {
445-
case Compiler::StaticType::Number: {
446-
// True if != 0
512+
case Compiler::StaticType::Bool: {
513+
Compiler::StaticType type = reg->type();
514+
bool singleType = isSingleType(type);
515+
516+
if (singleType) {
517+
// Handle single type cases directly
518+
switch (type) {
519+
case Compiler::StaticType::Number: {
520+
// True if != 0
521+
llvm::Value *ptr = m_builder.CreateStructGEP(m_valueDataType, reg->value, 0);
522+
llvm::Value *numberValue = m_builder.CreateLoad(m_builder.getDoubleTy(), ptr);
523+
return m_builder.CreateFCmpONE(numberValue, llvm::ConstantFP::get(m_llvmCtx, llvm::APFloat(0.0)));
524+
}
525+
526+
case Compiler::StaticType::Bool: {
527+
// Read boolean directly
528+
llvm::Value *ptr = m_builder.CreateStructGEP(m_valueDataType, reg->value, 0);
529+
return m_builder.CreateLoad(m_builder.getInt1Ty(), ptr);
530+
}
531+
532+
case Compiler::StaticType::String:
533+
// Convert to bool
534+
// TODO: Use value_stringToBool()
535+
return m_builder.CreateCall(m_functions.resolve_value_toBool(), reg->value);
536+
537+
default:
538+
assert(false);
539+
return nullptr;
540+
}
541+
} else {
542+
// Handle multiple type cases with runtime switch
543+
llvm::Value *typePtr = m_builder.CreateStructGEP(m_valueDataType, reg->value, 1);
544+
llvm::Value *loadedType = m_builder.CreateLoad(m_builder.getInt32Ty(), typePtr);
545+
546+
llvm::BasicBlock *mergeBlock = llvm::BasicBlock::Create(m_llvmCtx, "merge", m_function);
547+
llvm::BasicBlock *defaultBlock = llvm::BasicBlock::Create(m_llvmCtx, "default", m_function);
548+
549+
llvm::SwitchInst *sw = m_builder.CreateSwitch(loadedType, defaultBlock, 4);
550+
551+
std::vector<std::pair<llvm::BasicBlock *, llvm::Value *>> results;
552+
553+
// Number case
554+
if ((type & Compiler::StaticType::Number) == Compiler::StaticType::Number) {
555+
llvm::BasicBlock *numberBlock = llvm::BasicBlock::Create(m_llvmCtx, "number", m_function);
556+
sw->addCase(m_builder.getInt32(static_cast<uint32_t>(ValueType::Number)), numberBlock);
557+
558+
m_builder.SetInsertPoint(numberBlock);
447559
llvm::Value *ptr = m_builder.CreateStructGEP(m_valueDataType, reg->value, 0);
448560
llvm::Value *numberValue = m_builder.CreateLoad(m_builder.getDoubleTy(), ptr);
449-
return m_builder.CreateFCmpONE(numberValue, llvm::ConstantFP::get(m_llvmCtx, llvm::APFloat(0.0)));
561+
llvm::Value *numberResult = m_builder.CreateFCmpONE(numberValue, llvm::ConstantFP::get(m_llvmCtx, llvm::APFloat(0.0)));
562+
m_builder.CreateBr(mergeBlock);
563+
results.push_back({ numberBlock, numberResult });
450564
}
451565

452-
case Compiler::StaticType::Bool: {
453-
// Read boolean directly
566+
// Bool case
567+
if ((type & Compiler::StaticType::Bool) == Compiler::StaticType::Bool) {
568+
llvm::BasicBlock *boolBlock = llvm::BasicBlock::Create(m_llvmCtx, "bool", m_function);
569+
sw->addCase(m_builder.getInt32(static_cast<uint32_t>(ValueType::Bool)), boolBlock);
570+
571+
m_builder.SetInsertPoint(boolBlock);
454572
llvm::Value *ptr = m_builder.CreateStructGEP(m_valueDataType, reg->value, 0);
455-
return m_builder.CreateLoad(m_builder.getInt1Ty(), ptr);
573+
llvm::Value *boolResult = m_builder.CreateLoad(m_builder.getInt1Ty(), ptr);
574+
m_builder.CreateBr(mergeBlock);
575+
results.push_back({ boolBlock, boolResult });
456576
}
457577

458-
case Compiler::StaticType::String:
459-
case Compiler::StaticType::Unknown:
460-
// Convert to bool
461-
return m_builder.CreateCall(m_functions.resolve_value_toBool(), reg->value);
578+
// String case
579+
if ((type & Compiler::StaticType::String) == Compiler::StaticType::String) {
580+
llvm::BasicBlock *stringBlock = llvm::BasicBlock::Create(m_llvmCtx, "string", m_function);
581+
sw->addCase(m_builder.getInt32(static_cast<uint32_t>(ValueType::String)), stringBlock);
462582

463-
default:
464-
assert(false);
465-
return nullptr;
583+
m_builder.SetInsertPoint(stringBlock);
584+
// TODO: Use value_stringToBool()
585+
llvm::Value *stringResult = m_builder.CreateCall(m_functions.resolve_value_toBool(), reg->value);
586+
m_builder.CreateBr(mergeBlock);
587+
results.push_back({ stringBlock, stringResult });
588+
}
589+
590+
// Default case
591+
m_builder.SetInsertPoint(defaultBlock);
592+
593+
// All possible types are covered, mark as unreachable
594+
m_builder.CreateUnreachable();
595+
596+
// Create phi node to merge results
597+
m_builder.SetInsertPoint(mergeBlock);
598+
llvm::PHINode *result = m_builder.CreatePHI(m_builder.getInt1Ty(), results.size());
599+
600+
for (auto &pair : results)
601+
result->addIncoming(pair.second, pair.first);
602+
603+
return result;
466604
}
605+
}
467606

468-
case Compiler::StaticType::String:
469-
switch (reg->type()) {
470-
case Compiler::StaticType::Number:
471-
case Compiler::StaticType::Bool:
472-
case Compiler::StaticType::Unknown: {
473-
// Cast to string
474-
// TODO: Use value_stringToDouble() and value_stringToBool()
475-
llvm::Value *ptr = m_builder.CreateCall(m_functions.resolve_value_toStringPtr(), reg->value);
476-
freeStringLater(ptr);
477-
return ptr;
607+
case Compiler::StaticType::String: {
608+
Compiler::StaticType type = reg->type();
609+
bool singleType = isSingleType(type);
610+
611+
if (singleType) {
612+
// Handle single type cases directly
613+
switch (type) {
614+
case Compiler::StaticType::Number:
615+
case Compiler::StaticType::Bool: {
616+
// Cast to string
617+
// TODO: Use value_doubleToStringPtr() and value_boolToStringPtr()
618+
llvm::Value *ptr = m_builder.CreateCall(m_functions.resolve_value_toStringPtr(), reg->value);
619+
freeStringLater(ptr);
620+
return ptr;
621+
}
622+
623+
case Compiler::StaticType::String: {
624+
// Read string pointer directly
625+
llvm::Value *ptr = m_builder.CreateStructGEP(m_valueDataType, reg->value, 0);
626+
return m_builder.CreateLoad(m_stringPtrType->getPointerTo(), ptr);
627+
}
628+
629+
default:
630+
assert(false);
631+
return nullptr;
478632
}
633+
} else {
634+
// Handle multiple type cases with runtime switch
635+
llvm::Value *typePtr = m_builder.CreateStructGEP(m_valueDataType, reg->value, 1);
636+
llvm::Value *loadedType = m_builder.CreateLoad(m_builder.getInt32Ty(), typePtr);
479637

480-
case Compiler::StaticType::String: {
481-
// Read string pointer directly
638+
llvm::BasicBlock *mergeBlock = llvm::BasicBlock::Create(m_llvmCtx, "merge", m_function);
639+
llvm::BasicBlock *defaultBlock = llvm::BasicBlock::Create(m_llvmCtx, "default", m_function);
640+
641+
llvm::SwitchInst *sw = m_builder.CreateSwitch(loadedType, defaultBlock, 4);
642+
643+
std::vector<std::pair<llvm::BasicBlock *, llvm::Value *>> results;
644+
645+
// Number case
646+
if ((type & Compiler::StaticType::Number) == Compiler::StaticType::Number) {
647+
llvm::BasicBlock *numberBlock = llvm::BasicBlock::Create(m_llvmCtx, "number", m_function);
648+
sw->addCase(m_builder.getInt32(static_cast<uint32_t>(ValueType::Number)), numberBlock);
649+
650+
m_builder.SetInsertPoint(numberBlock);
651+
// TODO: Use value_doubleToStringPtr()
652+
llvm::Value *numberResult = m_builder.CreateCall(m_functions.resolve_value_toStringPtr(), reg->value);
653+
m_builder.CreateBr(mergeBlock);
654+
results.push_back({ numberBlock, numberResult });
655+
}
656+
657+
// Bool case
658+
if ((type & Compiler::StaticType::Bool) == Compiler::StaticType::Bool) {
659+
llvm::BasicBlock *boolBlock = llvm::BasicBlock::Create(m_llvmCtx, "bool", m_function);
660+
sw->addCase(m_builder.getInt32(static_cast<uint32_t>(ValueType::Bool)), boolBlock);
661+
662+
m_builder.SetInsertPoint(boolBlock);
663+
// TODO: Use value_boolToStringPtr()
664+
llvm::Value *boolResult = m_builder.CreateCall(m_functions.resolve_value_toStringPtr(), reg->value);
665+
m_builder.CreateBr(mergeBlock);
666+
results.push_back({ boolBlock, boolResult });
667+
}
668+
669+
// String case
670+
if ((type & Compiler::StaticType::String) == Compiler::StaticType::String) {
671+
llvm::BasicBlock *stringBlock = llvm::BasicBlock::Create(m_llvmCtx, "string", m_function);
672+
sw->addCase(m_builder.getInt32(static_cast<uint32_t>(ValueType::String)), stringBlock);
673+
674+
m_builder.SetInsertPoint(stringBlock);
482675
llvm::Value *ptr = m_builder.CreateStructGEP(m_valueDataType, reg->value, 0);
483-
return m_builder.CreateLoad(m_stringPtrType->getPointerTo(), ptr);
676+
llvm::Value *stringPtr = m_builder.CreateLoad(m_stringPtrType->getPointerTo(), ptr);
677+
llvm::Value *stringResult = m_builder.CreateCall(m_functions.resolve_string_pool_new(), m_builder.getInt1(true));
678+
m_builder.CreateCall(m_functions.resolve_string_assign(), { stringResult, stringPtr });
679+
m_builder.CreateBr(mergeBlock);
680+
results.push_back({ stringBlock, stringResult });
484681
}
485682

486-
default:
487-
assert(false);
488-
return nullptr;
489-
}
683+
// Default case
684+
m_builder.SetInsertPoint(defaultBlock);
490685

491-
case Compiler::StaticType::Unknown:
492-
return createValue(reg);
686+
// All possible types are covered, mark as unreachable
687+
m_builder.CreateUnreachable();
688+
689+
// Create phi node to merge results
690+
m_builder.SetInsertPoint(mergeBlock);
691+
llvm::PHINode *result = m_builder.CreatePHI(m_stringPtrType->getPointerTo(), results.size());
692+
693+
for (auto &pair : results)
694+
result->addIncoming(pair.second, pair.first);
695+
696+
freeStringLater(result);
697+
return result;
698+
}
699+
}
493700

494701
default:
495-
assert(false);
496-
return nullptr;
702+
// Multiple types
703+
return createValue(reg);
497704
}
498705
}
499706

0 commit comments

Comments
 (0)