@@ -626,93 +626,260 @@ llvm::Value *LLVMBuildUtils::removeNaN(llvm::Value *num)
626626
627627void 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
718885llvm::Value *LLVMBuildUtils::getListItem (const LLVMListPtr &listPtr, llvm::Value *index)
0 commit comments