@@ -796,10 +796,134 @@ conversionLibcall(MachineInstr &MI, MachineIRBuilder &MIRBuilder, Type *ToType,
796796 {{MI.getOperand (1 ).getReg (), FromType, 0 }});
797797}
798798
799+ static RTLIB::Libcall
800+ getStateLibraryFunctionFor (MachineInstr &MI, const TargetLowering &TLI) {
801+ RTLIB::Libcall RTLibcall;
802+ switch (MI.getOpcode ()) {
803+ case TargetOpcode::G_GET_FPMODE:
804+ RTLibcall = RTLIB::FEGETMODE;
805+ break ;
806+ case TargetOpcode::G_SET_FPMODE:
807+ case TargetOpcode::G_RESET_FPMODE:
808+ RTLibcall = RTLIB::FESETMODE;
809+ break ;
810+ default :
811+ llvm_unreachable (" Unexpected opcode" );
812+ }
813+ return RTLibcall;
814+ }
815+
816+ // Some library functions that read FP state (fegetmode, fegetenv) write the
817+ // state into a region in memory. IR intrinsics that do the same operations
818+ // (get_fpmode, get_fpenv) return the state as integer value. To implement these
819+ // intrinsics via the library functions, we need to use temporary variable,
820+ // for example:
821+ //
822+ // %0:_(s32) = G_GET_FPMODE
823+ //
824+ // is transformed to:
825+ //
826+ // %1:_(p0) = G_FRAME_INDEX %stack.0
827+ // BL &fegetmode
828+ // %0:_(s32) = G_LOAD % 1
829+ //
830+ LegalizerHelper::LegalizeResult
831+ LegalizerHelper::createGetStateLibcall (MachineIRBuilder &MIRBuilder,
832+ MachineInstr &MI) {
833+ const DataLayout &DL = MIRBuilder.getDataLayout ();
834+ auto &MF = MIRBuilder.getMF ();
835+ auto &MRI = *MIRBuilder.getMRI ();
836+ auto &Ctx = MF.getFunction ().getContext ();
837+
838+ // Create temporary, where library function will put the read state.
839+ Register Dst = MI.getOperand (0 ).getReg ();
840+ LLT StateTy = MRI.getType (Dst);
841+ TypeSize StateSize = StateTy.getSizeInBytes ();
842+ Align TempAlign = getStackTemporaryAlignment (StateTy);
843+ MachinePointerInfo TempPtrInfo;
844+ auto Temp = createStackTemporary (StateSize, TempAlign, TempPtrInfo);
845+
846+ // Create a call to library function, with the temporary as an argument.
847+ unsigned TempAddrSpace = DL.getAllocaAddrSpace ();
848+ Type *StatePtrTy = PointerType::get (Ctx, TempAddrSpace);
849+ RTLIB::Libcall RTLibcall = getStateLibraryFunctionFor (MI, TLI);
850+ auto Res =
851+ createLibcall (MIRBuilder, RTLibcall,
852+ CallLowering::ArgInfo ({0 }, Type::getVoidTy (Ctx), 0 ),
853+ CallLowering::ArgInfo ({Temp.getReg (0 ), StatePtrTy, 0 }));
854+ if (Res != LegalizerHelper::Legalized)
855+ return Res;
856+
857+ // Create a load from the temporary.
858+ MachineMemOperand *MMO = MF.getMachineMemOperand (
859+ TempPtrInfo, MachineMemOperand::MOLoad, StateTy, TempAlign);
860+ MIRBuilder.buildLoadInstr (TargetOpcode::G_LOAD, Dst, Temp, *MMO);
861+
862+ return LegalizerHelper::Legalized;
863+ }
864+
865+ // Similar to `createGetStateLibcall` the function calls a library function
866+ // using transient space in stack. In this case the library function reads
867+ // content of memory region.
868+ LegalizerHelper::LegalizeResult
869+ LegalizerHelper::createSetStateLibcall (MachineIRBuilder &MIRBuilder,
870+ MachineInstr &MI) {
871+ const DataLayout &DL = MIRBuilder.getDataLayout ();
872+ auto &MF = MIRBuilder.getMF ();
873+ auto &MRI = *MIRBuilder.getMRI ();
874+ auto &Ctx = MF.getFunction ().getContext ();
875+
876+ // Create temporary, where library function will get the new state.
877+ Register Src = MI.getOperand (0 ).getReg ();
878+ LLT StateTy = MRI.getType (Src);
879+ TypeSize StateSize = StateTy.getSizeInBytes ();
880+ Align TempAlign = getStackTemporaryAlignment (StateTy);
881+ MachinePointerInfo TempPtrInfo;
882+ auto Temp = createStackTemporary (StateSize, TempAlign, TempPtrInfo);
883+
884+ // Put the new state into the temporary.
885+ MachineMemOperand *MMO = MF.getMachineMemOperand (
886+ TempPtrInfo, MachineMemOperand::MOStore, StateTy, TempAlign);
887+ MIRBuilder.buildStore (Src, Temp, *MMO);
888+
889+ // Create a call to library function, with the temporary as an argument.
890+ unsigned TempAddrSpace = DL.getAllocaAddrSpace ();
891+ Type *StatePtrTy = PointerType::get (Ctx, TempAddrSpace);
892+ RTLIB::Libcall RTLibcall = getStateLibraryFunctionFor (MI, TLI);
893+ return createLibcall (MIRBuilder, RTLibcall,
894+ CallLowering::ArgInfo ({0 }, Type::getVoidTy (Ctx), 0 ),
895+ CallLowering::ArgInfo ({Temp.getReg (0 ), StatePtrTy, 0 }));
896+ }
897+
898+ // The function is used to legalize operations that set default environment
899+ // state. In C library a call like `fesetmode(FE_DFL_MODE)` is used for that.
900+ // On most targets supported in glibc FE_DFL_MODE is defined as
901+ // `((const femode_t *) -1)`. Such assumption is used here. If for some target
902+ // it is not true, the target must provide custom lowering.
903+ LegalizerHelper::LegalizeResult
904+ LegalizerHelper::createResetStateLibcall (MachineIRBuilder &MIRBuilder,
905+ MachineInstr &MI) {
906+ const DataLayout &DL = MIRBuilder.getDataLayout ();
907+ auto &MF = MIRBuilder.getMF ();
908+ auto &Ctx = MF.getFunction ().getContext ();
909+
910+ // Create an argument for the library function.
911+ unsigned AddrSpace = DL.getDefaultGlobalsAddressSpace ();
912+ Type *StatePtrTy = PointerType::get (Ctx, AddrSpace);
913+ unsigned PtrSize = DL.getPointerSizeInBits (AddrSpace);
914+ LLT MemTy = LLT::pointer (AddrSpace, PtrSize);
915+ auto DefValue = MIRBuilder.buildConstant (LLT::scalar (PtrSize), -1LL );
916+ DstOp Dest (MRI.createGenericVirtualRegister (MemTy));
917+ MIRBuilder.buildIntToPtr (Dest, DefValue);
918+
919+ RTLIB::Libcall RTLibcall = getStateLibraryFunctionFor (MI, TLI);
920+ return createLibcall (MIRBuilder, RTLibcall,
921+ CallLowering::ArgInfo ({0 }, Type::getVoidTy (Ctx), 0 ),
922+ CallLowering::ArgInfo ({ Dest.getReg (), StatePtrTy, 0 }));
923+ }
924+
799925LegalizerHelper::LegalizeResult
800926LegalizerHelper::libcall (MachineInstr &MI, LostDebugLocObserver &LocObserver) {
801- LLT LLTy = MRI.getType (MI.getOperand (0 ).getReg ());
802- unsigned Size = LLTy.getSizeInBits ();
803927 auto &Ctx = MIRBuilder.getMF ().getFunction ().getContext ();
804928
805929 switch (MI.getOpcode ()) {
@@ -811,6 +935,8 @@ LegalizerHelper::libcall(MachineInstr &MI, LostDebugLocObserver &LocObserver) {
811935 case TargetOpcode::G_SREM:
812936 case TargetOpcode::G_UREM:
813937 case TargetOpcode::G_CTLZ_ZERO_UNDEF: {
938+ LLT LLTy = MRI.getType (MI.getOperand (0 ).getReg ());
939+ unsigned Size = LLTy.getSizeInBits ();
814940 Type *HLTy = IntegerType::get (Ctx, Size);
815941 auto Status = simpleLibcall (MI, MIRBuilder, Size, HLTy);
816942 if (Status != Legalized)
@@ -841,6 +967,8 @@ LegalizerHelper::libcall(MachineInstr &MI, LostDebugLocObserver &LocObserver) {
841967 case TargetOpcode::G_FRINT:
842968 case TargetOpcode::G_FNEARBYINT:
843969 case TargetOpcode::G_INTRINSIC_ROUNDEVEN: {
970+ LLT LLTy = MRI.getType (MI.getOperand (0 ).getReg ());
971+ unsigned Size = LLTy.getSizeInBits ();
844972 Type *HLTy = getFloatTypeForLLT (Ctx, LLTy);
845973 if (!HLTy || (Size != 32 && Size != 64 && Size != 80 && Size != 128 )) {
846974 LLVM_DEBUG (dbgs () << " No libcall available for type " << LLTy << " .\n " );
@@ -903,6 +1031,24 @@ LegalizerHelper::libcall(MachineInstr &MI, LostDebugLocObserver &LocObserver) {
9031031 MI.eraseFromParent ();
9041032 return Result;
9051033 }
1034+ case TargetOpcode::G_GET_FPMODE: {
1035+ LegalizeResult Result = createGetStateLibcall (MIRBuilder, MI);
1036+ if (Result != Legalized)
1037+ return Result;
1038+ break ;
1039+ }
1040+ case TargetOpcode::G_SET_FPMODE: {
1041+ LegalizeResult Result = createSetStateLibcall (MIRBuilder, MI);
1042+ if (Result != Legalized)
1043+ return Result;
1044+ break ;
1045+ }
1046+ case TargetOpcode::G_RESET_FPMODE: {
1047+ LegalizeResult Result = createResetStateLibcall (MIRBuilder, MI);
1048+ if (Result != Legalized)
1049+ return Result;
1050+ break ;
1051+ }
9061052 }
9071053
9081054 MI.eraseFromParent ();
0 commit comments