Skip to content

Commit d009a5d

Browse files
committed
Implement mixed type stores
1 parent a51bfad commit d009a5d

File tree

4 files changed

+244
-71
lines changed

4 files changed

+244
-71
lines changed

src/engine/internal/llvm/instructions/lists.cpp

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -109,8 +109,6 @@ LLVMInstruction *Lists::buildAppendToList(LLVMInstruction *ins)
109109
Compiler::StaticType type = m_utils.optimizeRegisterType(arg.second);
110110
LLVMListPtr &listPtr = m_utils.listPtr(ins->targetList);
111111

112-
Compiler::StaticType listType = ins->targetType;
113-
114112
// Check if enough space is allocated
115113
llvm::Value *allocatedSize = m_builder.CreateLoad(m_builder.getInt64Ty(), listPtr.allocatedSizePtr);
116114
llvm::Value *size = m_builder.CreateLoad(m_builder.getInt64Ty(), listPtr.sizePtr);
@@ -123,14 +121,15 @@ LLVMInstruction *Lists::buildAppendToList(LLVMInstruction *ins)
123121
// If there's enough space, use the allocated memory
124122
m_builder.SetInsertPoint(ifBlock);
125123
llvm::Value *itemPtr = m_utils.getListItem(listPtr, size);
126-
m_utils.createReusedValueStore(arg.second, itemPtr, listType, type);
124+
m_utils.createValueStore(arg.second, itemPtr, type);
127125
m_builder.CreateStore(m_builder.CreateAdd(size, m_builder.getInt64(1)), listPtr.sizePtr);
128126
m_builder.CreateBr(nextBlock);
129127

130128
// Otherwise call appendEmpty()
131129
m_builder.SetInsertPoint(elseBlock);
132130
itemPtr = m_builder.CreateCall(m_utils.functions().resolve_list_append_empty(), listPtr.ptr);
133-
m_utils.createReusedValueStore(arg.second, itemPtr, listType, type);
131+
// NOTE: Items created using appendEmpty() are always numbers
132+
m_utils.createValueStore(arg.second, itemPtr, Compiler::StaticType::Number, type);
134133
m_builder.CreateBr(nextBlock);
135134

136135
m_builder.SetInsertPoint(nextBlock);
@@ -164,7 +163,7 @@ LLVMInstruction *Lists::buildInsertToList(LLVMInstruction *ins)
164163
m_builder.SetInsertPoint(insertBlock);
165164
index = m_builder.CreateFPToUI(index, m_builder.getInt64Ty());
166165
llvm::Value *itemPtr = m_builder.CreateCall(m_utils.functions().resolve_list_insert_empty(), { listPtr.ptr, index });
167-
m_utils.createReusedValueStore(valueArg.second, itemPtr, listType, type);
166+
m_utils.createValueStore(valueArg.second, itemPtr, type);
168167

169168
m_builder.CreateBr(nextBlock);
170169

src/engine/internal/llvm/llvmbuildutils.cpp

Lines changed: 232 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -626,93 +626,260 @@ llvm::Value *LLVMBuildUtils::removeNaN(llvm::Value *num)
626626

627627
void LLVMBuildUtils::createValueStore(LLVMRegister *reg, llvm::Value *destPtr, Compiler::StaticType destType, Compiler::StaticType targetType)
628628
{
629-
llvm::Value *converted = nullptr;
629+
llvm::Value *targetPtr = nullptr;
630+
const bool targetTypeIsSingle = isSingleType(targetType);
630631

631-
if (targetType != Compiler::StaticType::Unknown)
632-
converted = castValue(reg, targetType);
632+
if (targetTypeIsSingle)
633+
targetPtr = castValue(reg, targetType);
633634

634635
auto it = std::find_if(TYPE_MAP.begin(), TYPE_MAP.end(), [targetType](const std::pair<ValueType, Compiler::StaticType> &pair) { return pair.second == targetType; });
635636
const ValueType mappedType = it == TYPE_MAP.cend() ? ValueType::Number : it->first; // unknown type can be ignored
637+
assert(!(reg->isRawValue && it == TYPE_MAP.cend()));
636638

637-
switch (targetType) {
638-
case Compiler::StaticType::Number:
639-
switch (destType) {
640-
case Compiler::StaticType::Number: {
641-
// Write number to number directly
642-
llvm::Value *ptr = m_builder.CreateStructGEP(m_valueDataType, destPtr, 0);
643-
m_builder.CreateStore(converted, ptr);
644-
break;
645-
}
639+
// Handle multiple type cases with runtime switch
640+
llvm::Value *loadedTargetType = nullptr;
646641

647-
case Compiler::StaticType::Bool: {
648-
// Write number to bool value directly and change type
649-
llvm::Value *ptr = m_builder.CreateStructGEP(m_valueDataType, destPtr, 0);
650-
llvm::Value *typePtr = m_builder.CreateStructGEP(m_valueDataType, destPtr, 1);
651-
m_builder.CreateStore(converted, ptr);
652-
m_builder.CreateStore(m_builder.getInt32(static_cast<uint32_t>(mappedType)), typePtr);
653-
break;
654-
}
642+
if (reg->isRawValue)
643+
loadedTargetType = m_builder.getInt32(static_cast<uint32_t>(mappedType));
644+
else {
645+
assert(!reg->isConst());
646+
llvm::Value *targetTypePtr = m_builder.CreateStructGEP(m_valueDataType, reg->value, 1);
647+
loadedTargetType = m_builder.CreateLoad(m_builder.getInt32Ty(), targetTypePtr);
648+
}
655649

656-
default:
657-
m_builder.CreateCall(m_functions.resolve_value_assign_double(), { destPtr, converted });
658-
break;
650+
llvm::Value *destTypePtr = m_builder.CreateStructGEP(m_valueDataType, destPtr, 1);
651+
llvm::Value *loadedDestType = m_builder.CreateLoad(m_builder.getInt32Ty(), destTypePtr);
652+
653+
llvm::BasicBlock *mergeBlock = llvm::BasicBlock::Create(m_llvmCtx, "merge", m_function);
654+
llvm::BasicBlock *defaultBlock = llvm::BasicBlock::Create(m_llvmCtx, "default", m_function);
655+
656+
llvm::SwitchInst *sw = m_builder.CreateSwitch(loadedDestType, defaultBlock, 4);
657+
658+
if ((destType & Compiler::StaticType::Number) == Compiler::StaticType::Number) {
659+
// Writing to number
660+
llvm::BasicBlock *numberDestBlock = llvm::BasicBlock::Create(m_llvmCtx, "numberDest", m_function);
661+
sw->addCase(m_builder.getInt32(static_cast<uint32_t>(ValueType::Number)), numberDestBlock);
662+
m_builder.SetInsertPoint(numberDestBlock);
663+
664+
llvm::SwitchInst *targetSw = m_builder.CreateSwitch(loadedTargetType, defaultBlock, 4);
665+
666+
if ((targetType & Compiler::StaticType::Number) == Compiler::StaticType::Number) {
667+
// Writing number to number
668+
llvm::BasicBlock *numberBlock = llvm::BasicBlock::Create(m_llvmCtx, "number", m_function);
669+
targetSw->addCase(m_builder.getInt32(static_cast<uint32_t>(ValueType::Number)), numberBlock);
670+
m_builder.SetInsertPoint(numberBlock);
671+
672+
// Load number
673+
if (!targetTypeIsSingle) {
674+
llvm::Value *ptr = m_builder.CreateStructGEP(m_valueDataType, reg->value, 0);
675+
targetPtr = m_builder.CreateLoad(m_builder.getDoubleTy(), ptr);
659676
}
660677

661-
break;
678+
// Write number to number directly
679+
llvm::Value *ptr = m_builder.CreateStructGEP(m_valueDataType, destPtr, 0);
680+
m_builder.CreateStore(targetPtr, ptr);
681+
m_builder.CreateBr(mergeBlock);
682+
}
662683

663-
case Compiler::StaticType::Bool:
664-
switch (destType) {
665-
case Compiler::StaticType::Number: {
666-
// Write bool to number value directly and change type
667-
llvm::Value *ptr = m_builder.CreateStructGEP(m_valueDataType, destPtr, 0);
668-
m_builder.CreateStore(converted, ptr);
669-
llvm::Value *typePtr = m_builder.CreateStructGEP(m_valueDataType, destPtr, 1);
670-
m_builder.CreateStore(converted, ptr);
671-
m_builder.CreateStore(m_builder.getInt32(static_cast<uint32_t>(mappedType)), typePtr);
672-
break;
673-
}
684+
if ((targetType & Compiler::StaticType::Bool) == Compiler::StaticType::Bool) {
685+
// Writing bool to number
686+
llvm::BasicBlock *boolBlock = llvm::BasicBlock::Create(m_llvmCtx, "bool", m_function);
687+
targetSw->addCase(m_builder.getInt32(static_cast<uint32_t>(ValueType::Bool)), boolBlock);
688+
m_builder.SetInsertPoint(boolBlock);
674689

675-
case Compiler::StaticType::Bool: {
676-
// Write bool to bool directly
677-
llvm::Value *ptr = m_builder.CreateStructGEP(m_valueDataType, destPtr, 0);
678-
m_builder.CreateStore(converted, ptr);
679-
break;
680-
}
690+
// Load bool
691+
if (!targetTypeIsSingle) {
692+
llvm::Value *ptr = m_builder.CreateStructGEP(m_valueDataType, reg->value, 0);
693+
targetPtr = m_builder.CreateLoad(m_builder.getInt1Ty(), ptr);
694+
}
681695

682-
default:
683-
m_builder.CreateCall(m_functions.resolve_value_assign_bool(), { destPtr, converted });
684-
break;
696+
// Write bool to number value directly and change type
697+
llvm::Value *ptr = m_builder.CreateStructGEP(m_valueDataType, destPtr, 0);
698+
m_builder.CreateStore(targetPtr, ptr);
699+
llvm::Value *typePtr = m_builder.CreateStructGEP(m_valueDataType, destPtr, 1);
700+
m_builder.CreateStore(m_builder.getInt32(static_cast<uint32_t>(ValueType::Bool)), typePtr);
701+
m_builder.CreateBr(mergeBlock);
702+
}
703+
704+
if ((targetType & Compiler::StaticType::String) == Compiler::StaticType::String) {
705+
// Writing string to number
706+
llvm::BasicBlock *stringBlock = llvm::BasicBlock::Create(m_llvmCtx, "string", m_function);
707+
targetSw->addCase(m_builder.getInt32(static_cast<uint32_t>(ValueType::String)), stringBlock);
708+
m_builder.SetInsertPoint(stringBlock);
709+
710+
// Load string pointer
711+
if (!targetTypeIsSingle) {
712+
llvm::Value *ptr = m_builder.CreateStructGEP(m_valueDataType, reg->value, 0);
713+
targetPtr = m_builder.CreateLoad(m_stringPtrType->getPointerTo(), ptr);
685714
}
686715

687-
break;
716+
// Create a new string, change type and assign
717+
llvm::Value *ptr = m_builder.CreateStructGEP(m_valueDataType, destPtr, 0);
718+
llvm::Value *destStringPtr = m_builder.CreateCall(m_functions.resolve_string_pool_new(), m_builder.getInt1(false));
688719

689-
case Compiler::StaticType::String:
690-
m_builder.CreateCall(m_functions.resolve_value_assign_stringPtr(), { destPtr, converted });
691-
break;
720+
llvm::Value *typePtr = m_builder.CreateStructGEP(m_valueDataType, destPtr, 1);
721+
m_builder.CreateStore(m_builder.getInt32(static_cast<uint32_t>(ValueType::String)), typePtr);
722+
m_builder.CreateStore(destStringPtr, ptr);
723+
m_builder.CreateCall(m_functions.resolve_string_assign(), { destStringPtr, targetPtr });
692724

693-
case Compiler::StaticType::Unknown:
694-
m_builder.CreateCall(m_functions.resolve_value_assign_copy(), { destPtr, reg->value });
695-
break;
725+
m_builder.CreateBr(mergeBlock);
726+
}
727+
}
696728

697-
default:
698-
assert(false);
699-
break;
729+
if ((destType & Compiler::StaticType::Bool) == Compiler::StaticType::Bool) {
730+
// Writing to bool
731+
llvm::BasicBlock *boolDestBlock = llvm::BasicBlock::Create(m_llvmCtx, "boolDest", m_function);
732+
sw->addCase(m_builder.getInt32(static_cast<uint32_t>(ValueType::Bool)), boolDestBlock);
733+
m_builder.SetInsertPoint(boolDestBlock);
734+
735+
llvm::SwitchInst *targetSw = m_builder.CreateSwitch(loadedTargetType, defaultBlock, 4);
736+
737+
if ((targetType & Compiler::StaticType::Number) == Compiler::StaticType::Number) {
738+
// Writing number to bool
739+
llvm::BasicBlock *numberBlock = llvm::BasicBlock::Create(m_llvmCtx, "number", m_function);
740+
targetSw->addCase(m_builder.getInt32(static_cast<uint32_t>(ValueType::Number)), numberBlock);
741+
m_builder.SetInsertPoint(numberBlock);
742+
743+
// Load number
744+
if (!targetTypeIsSingle) {
745+
llvm::Value *ptr = m_builder.CreateStructGEP(m_valueDataType, reg->value, 0);
746+
targetPtr = m_builder.CreateLoad(m_builder.getDoubleTy(), ptr);
747+
}
748+
749+
// Write number to bool value directly and change type
750+
llvm::Value *ptr = m_builder.CreateStructGEP(m_valueDataType, destPtr, 0);
751+
llvm::Value *typePtr = m_builder.CreateStructGEP(m_valueDataType, destPtr, 1);
752+
m_builder.CreateStore(targetPtr, ptr);
753+
m_builder.CreateStore(m_builder.getInt32(static_cast<uint32_t>(ValueType::Number)), typePtr);
754+
m_builder.CreateBr(mergeBlock);
755+
}
756+
757+
if ((targetType & Compiler::StaticType::Bool) == Compiler::StaticType::Bool) {
758+
// Writing bool to bool
759+
llvm::BasicBlock *boolBlock = llvm::BasicBlock::Create(m_llvmCtx, "bool", m_function);
760+
targetSw->addCase(m_builder.getInt32(static_cast<uint32_t>(ValueType::Bool)), boolBlock);
761+
m_builder.SetInsertPoint(boolBlock);
762+
763+
// Load bool
764+
if (!targetTypeIsSingle) {
765+
llvm::Value *ptr = m_builder.CreateStructGEP(m_valueDataType, reg->value, 0);
766+
targetPtr = m_builder.CreateLoad(m_builder.getInt1Ty(), ptr);
767+
}
768+
769+
// Write bool to bool directly
770+
llvm::Value *ptr = m_builder.CreateStructGEP(m_valueDataType, destPtr, 0);
771+
m_builder.CreateStore(targetPtr, ptr);
772+
m_builder.CreateBr(mergeBlock);
773+
}
774+
775+
if ((targetType & Compiler::StaticType::String) == Compiler::StaticType::String) {
776+
// Writing string to bool
777+
llvm::BasicBlock *stringBlock = llvm::BasicBlock::Create(m_llvmCtx, "string", m_function);
778+
targetSw->addCase(m_builder.getInt32(static_cast<uint32_t>(ValueType::String)), stringBlock);
779+
m_builder.SetInsertPoint(stringBlock);
780+
781+
// Load string pointer
782+
if (!targetTypeIsSingle) {
783+
llvm::Value *ptr = m_builder.CreateStructGEP(m_valueDataType, reg->value, 0);
784+
targetPtr = m_builder.CreateLoad(m_stringPtrType->getPointerTo(), ptr);
785+
}
786+
787+
// Create a new string, change type and assign
788+
llvm::Value *ptr = m_builder.CreateStructGEP(m_valueDataType, destPtr, 0);
789+
llvm::Value *destStringPtr = m_builder.CreateCall(m_functions.resolve_string_pool_new(), m_builder.getInt1(false));
790+
791+
llvm::Value *typePtr = m_builder.CreateStructGEP(m_valueDataType, destPtr, 1);
792+
m_builder.CreateStore(m_builder.getInt32(static_cast<uint32_t>(ValueType::String)), typePtr);
793+
m_builder.CreateStore(destStringPtr, ptr);
794+
m_builder.CreateCall(m_functions.resolve_string_assign(), { destStringPtr, targetPtr });
795+
796+
m_builder.CreateBr(mergeBlock);
797+
}
700798
}
701-
}
702799

703-
void LLVMBuildUtils::createReusedValueStore(LLVMRegister *reg, llvm::Value *destPtr, Compiler::StaticType destType, Compiler::StaticType targetType)
704-
{
705-
// Same as createValueStore(), but ensures that type is updated
706-
createValueStore(reg, destPtr, destType, targetType);
800+
if ((destType & Compiler::StaticType::String) == Compiler::StaticType::String) {
801+
// Writing to string
802+
llvm::BasicBlock *stringDestBlock = llvm::BasicBlock::Create(m_llvmCtx, "stringDest", m_function);
803+
sw->addCase(m_builder.getInt32(static_cast<uint32_t>(ValueType::String)), stringDestBlock);
804+
m_builder.SetInsertPoint(stringDestBlock);
707805

708-
auto it = std::find_if(TYPE_MAP.begin(), TYPE_MAP.end(), [targetType](const std::pair<ValueType, Compiler::StaticType> &pair) { return pair.second == targetType; });
709-
const ValueType mappedType = it == TYPE_MAP.cend() ? ValueType::Number : it->first; // unknown type can be ignored
806+
llvm::SwitchInst *targetSw = m_builder.CreateSwitch(loadedTargetType, defaultBlock, 4);
807+
808+
if ((targetType & Compiler::StaticType::Number) == Compiler::StaticType::Number) {
809+
// Writing number to string
810+
llvm::BasicBlock *numberBlock = llvm::BasicBlock::Create(m_llvmCtx, "number", m_function);
811+
targetSw->addCase(m_builder.getInt32(static_cast<uint32_t>(ValueType::Number)), numberBlock);
812+
m_builder.SetInsertPoint(numberBlock);
710813

711-
if ((targetType == Compiler::StaticType::Number || targetType == Compiler::StaticType::Bool) && targetType == destType) {
712-
// Update type when writing number to number and bool to bool
713-
llvm::Value *typePtr = m_builder.CreateStructGEP(m_valueDataType, destPtr, 1);
714-
m_builder.CreateStore(m_builder.getInt32(static_cast<uint32_t>(mappedType)), typePtr);
814+
// Load number
815+
if (!targetTypeIsSingle) {
816+
llvm::Value *ptr = m_builder.CreateStructGEP(m_valueDataType, reg->value, 0);
817+
targetPtr = m_builder.CreateLoad(m_builder.getDoubleTy(), ptr);
818+
}
819+
820+
// Free the string, write the number and change type
821+
llvm::Value *ptr = m_builder.CreateStructGEP(m_valueDataType, destPtr, 0);
822+
llvm::Value *destStringPtr = m_builder.CreateLoad(m_stringPtrType->getPointerTo(), ptr);
823+
m_builder.CreateCall(m_functions.resolve_string_pool_free(), destStringPtr);
824+
m_builder.CreateStore(targetPtr, ptr);
825+
llvm::Value *typePtr = m_builder.CreateStructGEP(m_valueDataType, destPtr, 1);
826+
m_builder.CreateStore(m_builder.getInt32(static_cast<uint32_t>(ValueType::Number)), typePtr);
827+
m_builder.CreateBr(mergeBlock);
828+
}
829+
830+
if ((targetType & Compiler::StaticType::Bool) == Compiler::StaticType::Bool) {
831+
// Writing bool to string
832+
llvm::BasicBlock *boolBlock = llvm::BasicBlock::Create(m_llvmCtx, "bool", m_function);
833+
targetSw->addCase(m_builder.getInt32(static_cast<uint32_t>(ValueType::Bool)), boolBlock);
834+
m_builder.SetInsertPoint(boolBlock);
835+
836+
// Load bool
837+
if (!targetTypeIsSingle) {
838+
llvm::Value *ptr = m_builder.CreateStructGEP(m_valueDataType, reg->value, 0);
839+
targetPtr = m_builder.CreateLoad(m_builder.getInt1Ty(), ptr);
840+
}
841+
842+
// Free the string, write the bool and change type
843+
llvm::Value *ptr = m_builder.CreateStructGEP(m_valueDataType, destPtr, 0);
844+
llvm::Value *destStringPtr = m_builder.CreateLoad(m_stringPtrType->getPointerTo(), ptr);
845+
m_builder.CreateCall(m_functions.resolve_string_pool_free(), destStringPtr);
846+
m_builder.CreateStore(targetPtr, ptr);
847+
llvm::Value *typePtr = m_builder.CreateStructGEP(m_valueDataType, destPtr, 1);
848+
m_builder.CreateStore(m_builder.getInt32(static_cast<uint32_t>(ValueType::Bool)), typePtr);
849+
m_builder.CreateBr(mergeBlock);
850+
}
851+
852+
if ((targetType & Compiler::StaticType::String) == Compiler::StaticType::String) {
853+
// Writing string to string
854+
llvm::BasicBlock *stringBlock = llvm::BasicBlock::Create(m_llvmCtx, "string", m_function);
855+
targetSw->addCase(m_builder.getInt32(static_cast<uint32_t>(ValueType::String)), stringBlock);
856+
m_builder.SetInsertPoint(stringBlock);
857+
858+
// Load string pointer
859+
if (!targetTypeIsSingle) {
860+
llvm::Value *ptr = m_builder.CreateStructGEP(m_valueDataType, reg->value, 0);
861+
targetPtr = m_builder.CreateLoad(m_stringPtrType->getPointerTo(), ptr);
862+
}
863+
864+
// Assign string directly
865+
llvm::Value *ptr = m_builder.CreateStructGEP(m_valueDataType, destPtr, 0);
866+
llvm::Value *destStringPtr = m_builder.CreateLoad(m_stringPtrType->getPointerTo(), ptr);
867+
m_builder.CreateCall(m_functions.resolve_string_assign(), { destStringPtr, targetPtr });
868+
m_builder.CreateBr(mergeBlock);
869+
}
715870
}
871+
872+
// Default case - unreachable
873+
m_builder.SetInsertPoint(defaultBlock);
874+
m_builder.CreateUnreachable();
875+
876+
m_builder.SetInsertPoint(mergeBlock);
877+
}
878+
879+
void LLVMBuildUtils::createValueStore(LLVMRegister *reg, llvm::Value *destPtr, Compiler::StaticType targetType)
880+
{
881+
// Same as createValueStore(), but the destination type is unknown at compile time
882+
createValueStore(reg, destPtr, Compiler::StaticType::Unknown, targetType);
716883
}
717884

718885
llvm::Value *LLVMBuildUtils::getListItem(const LLVMListPtr &listPtr, llvm::Value *index)

0 commit comments

Comments
 (0)