diff --git a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp --- a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp +++ b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp @@ -115,6 +115,25 @@ llvm_unreachable("not yet handled"); } +static Type *getFloatTypeForLLT(LLVMContext &Ctx, LLT Ty) { + + if (!Ty.isScalar()) + return nullptr; + + switch (Ty.getSizeInBits()) { + case 16: + return Type::getHalfTy(Ctx); + case 32: + return Type::getFloatTy(Ctx); + case 64: + return Type::getDoubleTy(Ctx); + case 128: + return Type::getFP128Ty(Ctx); + default: + return nullptr; + } +} + LegalizerHelper::LegalizerHelper(MachineFunction &MF, GISelChangeObserver &Observer, MachineIRBuilder &Builder) @@ -702,36 +721,23 @@ case TargetOpcode::G_FEXP2: case TargetOpcode::G_FCEIL: case TargetOpcode::G_FFLOOR: { - if (Size > 64) { - LLVM_DEBUG(dbgs() << "Size " << Size << " too large to legalize.\n"); + Type *HLTy = getFloatTypeForLLT(Ctx, LLTy); + if (!HLTy || (Size != 32 && Size != 64)) { + LLVM_DEBUG(dbgs() << "No libcall available for size " << Size << ".\n"); return UnableToLegalize; } - Type *HLTy = Size == 64 ? Type::getDoubleTy(Ctx) : Type::getFloatTy(Ctx); auto Status = simpleLibcall(MI, MIRBuilder, Size, HLTy); if (Status != Legalized) return Status; break; } - case TargetOpcode::G_FPEXT: { - // FIXME: Support other floating point types (half, fp128 etc) - unsigned FromSize = MRI.getType(MI.getOperand(1).getReg()).getSizeInBits(); - unsigned ToSize = MRI.getType(MI.getOperand(0).getReg()).getSizeInBits(); - if (ToSize != 64 || FromSize != 32) - return UnableToLegalize; - LegalizeResult Status = conversionLibcall( - MI, MIRBuilder, Type::getDoubleTy(Ctx), Type::getFloatTy(Ctx)); - if (Status != Legalized) - return Status; - break; - } + case TargetOpcode::G_FPEXT: case TargetOpcode::G_FPTRUNC: { - // FIXME: Support other floating point types (half, fp128 etc) - unsigned FromSize = MRI.getType(MI.getOperand(1).getReg()).getSizeInBits(); - unsigned ToSize = MRI.getType(MI.getOperand(0).getReg()).getSizeInBits(); - if (ToSize != 32 || FromSize != 64) + Type *FromTy = getFloatTypeForLLT(Ctx, MRI.getType(MI.getOperand(1).getReg())); + Type *ToTy = getFloatTypeForLLT(Ctx, MRI.getType(MI.getOperand(0).getReg())); + if (!FromTy || !ToTy) return UnableToLegalize; - LegalizeResult Status = conversionLibcall( - MI, MIRBuilder, Type::getFloatTy(Ctx), Type::getDoubleTy(Ctx)); + LegalizeResult Status = conversionLibcall(MI, MIRBuilder, ToTy, FromTy ); if (Status != Legalized) return Status; break; @@ -2222,24 +2228,10 @@ if (Ty.isVector()) return UnableToLegalize; Register Res = MI.getOperand(0).getReg(); - Type *ZeroTy; LLVMContext &Ctx = MIRBuilder.getMF().getFunction().getContext(); - switch (Ty.getSizeInBits()) { - case 16: - ZeroTy = Type::getHalfTy(Ctx); - break; - case 32: - ZeroTy = Type::getFloatTy(Ctx); - break; - case 64: - ZeroTy = Type::getDoubleTy(Ctx); - break; - case 128: - ZeroTy = Type::getFP128Ty(Ctx); - break; - default: - llvm_unreachable("unexpected floating-point type"); - } + Type *ZeroTy = getFloatTypeForLLT(Ctx, Ty); + if (!ZeroTy) + return UnableToLegalize; ConstantFP &ZeroForNegation = *cast(ConstantFP::getZeroValueForNegation(ZeroTy)); auto Zero = MIRBuilder.buildFConstant(Ty, ZeroForNegation); diff --git a/llvm/unittests/CodeGen/GlobalISel/GISelMITest.h b/llvm/unittests/CodeGen/GlobalISel/GISelMITest.h --- a/llvm/unittests/CodeGen/GlobalISel/GISelMITest.h +++ b/llvm/unittests/CodeGen/GlobalISel/GISelMITest.h @@ -176,6 +176,8 @@ (void)s32; \ const LLT s64 = LLT::scalar(64); \ (void)s64; \ + const LLT s128 = LLT::scalar(128); \ + (void)s128; \ do \ SettingUpActionsBlock while (0); \ computeTables(); \ diff --git a/llvm/unittests/CodeGen/GlobalISel/LegalizerHelperTest.cpp b/llvm/unittests/CodeGen/GlobalISel/LegalizerHelperTest.cpp --- a/llvm/unittests/CodeGen/GlobalISel/LegalizerHelperTest.cpp +++ b/llvm/unittests/CodeGen/GlobalISel/LegalizerHelperTest.cpp @@ -1179,4 +1179,108 @@ // Check ASSERT_TRUE(CheckMachineFunction(*MF, CheckStr)); } + +TEST_F(GISelMITest, LibcallFPExt) { + setUp(); + if (!TM) + return; + + // Declare your legalization info + DefineLegalizerInfo(A, { + getActionDefinitionsBuilder(G_FPEXT).libcallFor({{s32, s16}, {s128, s64}}); + }); + + LLT S16{LLT::scalar(16)}; + LLT S32{LLT::scalar(32)}; + LLT S128{LLT::scalar(128)}; + auto MIBTrunc = B.buildTrunc(S16, Copies[0]); + auto MIBFPExt1 = + B.buildInstr(TargetOpcode::G_FPEXT, {S32}, {MIBTrunc}); + + auto MIBFPExt2 = + B.buildInstr(TargetOpcode::G_FPEXT, {S128}, {Copies[1]}); + AInfo Info(MF->getSubtarget()); + DummyGISelObserver Observer; + LegalizerHelper Helper(*MF, Info, Observer, B); + EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, + Helper.libcall(*MIBFPExt1)); + + EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, + Helper.libcall(*MIBFPExt2)); + auto CheckStr = R"( + CHECK: [[TRUNC:%[0-9]+]]:_(s16) = G_TRUNC + CHECK: $h0 = COPY [[TRUNC]] + CHECK: BL &__gnu_h2f_ieee + CHECK: $d0 = COPY + CHECK: BL &__extenddftf2 + )"; + + // Check + EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; +} + +TEST_F(GISelMITest, LibcallFPTrunc) { + setUp(); + if (!TM) + return; + + // Declare your legalization info + DefineLegalizerInfo(A, { + getActionDefinitionsBuilder(G_FPTRUNC).libcallFor({{s16, s32}, {s64, s128}}); + }); + + LLT S16{LLT::scalar(16)}; + LLT S32{LLT::scalar(32)}; + LLT S64{LLT::scalar(64)}; + LLT S128{LLT::scalar(128)}; + auto MIBTrunc = B.buildTrunc(S32, Copies[0]); + auto MIBFPTrunc1 = + B.buildInstr(TargetOpcode::G_FPTRUNC, {S16}, {MIBTrunc}); + + auto MIBMerge = B.buildMerge(S128, {Copies[1], Copies[2]}); + + auto MIBFPTrunc2 = + B.buildInstr(TargetOpcode::G_FPTRUNC, {S64}, {MIBMerge}); + AInfo Info(MF->getSubtarget()); + DummyGISelObserver Observer; + LegalizerHelper Helper(*MF, Info, Observer, B); + EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, + Helper.libcall(*MIBFPTrunc1)); + + EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, + Helper.libcall(*MIBFPTrunc2)); + auto CheckStr = R"( + CHECK: [[TRUNC:%[0-9]+]]:_(s32) = G_TRUNC + CHECK: $s0 = COPY [[TRUNC]] + CHECK: BL &__gnu_f2h_ieee + CHECK: $q0 = COPY + CHECK: BL &__trunctfdf2 + )"; + + // Check + EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; +} + +TEST_F(GISelMITest, LibcallSimple) { + setUp(); + if (!TM) + return; + + // Declare your legalization info + DefineLegalizerInfo(A, { + getActionDefinitionsBuilder(G_FADD).libcallFor({s16}); + }); + + LLT S16{LLT::scalar(16)}; + auto MIBTrunc = B.buildTrunc(S16, Copies[0]); + auto MIBFADD = + B.buildInstr(TargetOpcode::G_FADD, {S16}, {MIBTrunc, MIBTrunc}); + + AInfo Info(MF->getSubtarget()); + DummyGISelObserver Observer; + LegalizerHelper Helper(*MF, Info, Observer, B); + // Make sure we do not crash anymore + EXPECT_EQ(LegalizerHelper::LegalizeResult::UnableToLegalize, + Helper.libcall(*MIBFADD)); +} } // namespace