From: Matt Arsenault Date: Mon, 1 Jul 2019 17:18:03 +0000 (+0000) Subject: GlobalISel: Implement lower for min/max X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=b82c63f999aa560e6eaa1c4fe920d31cb84e41f4;p=llvm GlobalISel: Implement lower for min/max git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@364816 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/llvm/CodeGen/GlobalISel/LegalizerHelper.h b/include/llvm/CodeGen/GlobalISel/LegalizerHelper.h index 6ee09134c5c..1b95b3a90d3 100644 --- a/include/llvm/CodeGen/GlobalISel/LegalizerHelper.h +++ b/include/llvm/CodeGen/GlobalISel/LegalizerHelper.h @@ -218,6 +218,7 @@ private: LegalizeResult lowerU64ToF32BitOps(MachineInstr &MI); LegalizeResult lowerUITOFP(MachineInstr &MI, unsigned TypeIdx, LLT Ty); LegalizeResult lowerSITOFP(MachineInstr &MI, unsigned TypeIdx, LLT Ty); + LegalizeResult lowerMinMax(MachineInstr &MI, unsigned TypeIdx, LLT Ty); MachineRegisterInfo &MRI; const LegalizerInfo &LI; diff --git a/lib/CodeGen/GlobalISel/LegalizerHelper.cpp b/lib/CodeGen/GlobalISel/LegalizerHelper.cpp index adc0eb5c166..88c9715e764 100644 --- a/lib/CodeGen/GlobalISel/LegalizerHelper.cpp +++ b/lib/CodeGen/GlobalISel/LegalizerHelper.cpp @@ -1612,6 +1612,11 @@ LegalizerHelper::lower(MachineInstr &MI, unsigned TypeIdx, LLT Ty) { return lowerUITOFP(MI, TypeIdx, Ty); case G_SITOFP: return lowerSITOFP(MI, TypeIdx, Ty); + case G_SMIN: + case G_SMAX: + case G_UMIN: + case G_UMAX: + return lowerMinMax(MI, TypeIdx, Ty); } } @@ -3110,3 +3115,34 @@ LegalizerHelper::lowerSITOFP(MachineInstr &MI, unsigned TypeIdx, LLT Ty) { return UnableToLegalize; } + +static CmpInst::Predicate minMaxToCompare(unsigned Opc) { + switch (Opc) { + case TargetOpcode::G_SMIN: + return CmpInst::ICMP_SLT; + case TargetOpcode::G_SMAX: + return CmpInst::ICMP_SGT; + case TargetOpcode::G_UMIN: + return CmpInst::ICMP_ULT; + case TargetOpcode::G_UMAX: + return CmpInst::ICMP_UGT; + default: + llvm_unreachable("not in integer min/max"); + } +} + +LegalizerHelper::LegalizeResult +LegalizerHelper::lowerMinMax(MachineInstr &MI, unsigned TypeIdx, LLT Ty) { + Register Dst = MI.getOperand(0).getReg(); + Register Src0 = MI.getOperand(1).getReg(); + Register Src1 = MI.getOperand(2).getReg(); + + const CmpInst::Predicate Pred = minMaxToCompare(MI.getOpcode()); + LLT CmpType = MRI.getType(Dst).changeElementSize(1); + + auto Cmp = MIRBuilder.buildICmp(Pred, CmpType, Src0, Src1); + MIRBuilder.buildSelect(Dst, Cmp, Src0, Src1); + + MI.eraseFromParent(); + return Legalized; +} diff --git a/unittests/CodeGen/GlobalISel/LegalizerHelperTest.cpp b/unittests/CodeGen/GlobalISel/LegalizerHelperTest.cpp index 09082b20bc9..988841d84d7 100644 --- a/unittests/CodeGen/GlobalISel/LegalizerHelperTest.cpp +++ b/unittests/CodeGen/GlobalISel/LegalizerHelperTest.cpp @@ -775,4 +775,82 @@ TEST_F(GISelMITest, LowerFNEG) { // Check EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } + +TEST_F(GISelMITest, LowerMinMax) { + if (!TM) + return; + + LLT s64 = LLT::scalar(64); + LLT v2s32 = LLT::vector(2, 32); + + DefineLegalizerInfo(A, { + getActionDefinitionsBuilder({G_SMIN, G_SMAX, G_UMIN, G_UMAX}) + .lowerFor({s64, LLT::vector(2, s32)}); + }); + + auto SMin = B.buildSMin(s64, Copies[0], Copies[1]); + auto SMax = B.buildSMax(s64, Copies[0], Copies[1]); + auto UMin = B.buildUMin(s64, Copies[0], Copies[1]); + auto UMax = B.buildUMax(s64, Copies[0], Copies[1]); + + auto VecVal0 = B.buildBitcast(v2s32, Copies[0]); + auto VecVal1 = B.buildBitcast(v2s32, Copies[1]); + + auto SMinV = B.buildSMin(v2s32, VecVal0, VecVal1); + auto SMaxV = B.buildSMax(v2s32, VecVal0, VecVal1); + auto UMinV = B.buildUMin(v2s32, VecVal0, VecVal1); + auto UMaxV = B.buildUMax(v2s32, VecVal0, VecVal1); + + AInfo Info(MF->getSubtarget()); + DummyGISelObserver Observer; + LegalizerHelper Helper(*MF, Info, Observer, B); + EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, + Helper.lower(*SMin, 0, s64)); + EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, + Helper.lower(*SMax, 0, s64)); + EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, + Helper.lower(*UMin, 0, s64)); + EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, + Helper.lower(*UMax, 0, s64)); + + EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, + Helper.lower(*SMinV, 0, v2s32)); + EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, + Helper.lower(*SMaxV, 0, v2s32)); + EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, + Helper.lower(*UMinV, 0, v2s32)); + EXPECT_EQ(LegalizerHelper::LegalizeResult::Legalized, + Helper.lower(*UMaxV, 0, v2s32)); + + auto CheckStr = R"( + CHECK: [[CMP0:%[0-9]+]]:_(s1) = G_ICMP intpred(slt), %0:_(s64), %1:_ + CHECK: [[SMIN:%[0-9]+]]:_(s64) = G_SELECT [[CMP0]]:_(s1), %0:_, %1:_ + + CHECK: [[CMP1:%[0-9]+]]:_(s1) = G_ICMP intpred(sgt), %0:_(s64), %1:_ + CHECK: [[SMAX:%[0-9]+]]:_(s64) = G_SELECT [[CMP1]]:_(s1), %0:_, %1:_ + + CHECK: [[CMP2:%[0-9]+]]:_(s1) = G_ICMP intpred(ult), %0:_(s64), %1:_ + CHECK: [[UMIN:%[0-9]+]]:_(s64) = G_SELECT [[CMP2]]:_(s1), %0:_, %1:_ + + CHECK: [[CMP3:%[0-9]+]]:_(s1) = G_ICMP intpred(ugt), %0:_(s64), %1:_ + CHECK: [[UMAX:%[0-9]+]]:_(s64) = G_SELECT [[CMP3]]:_(s1), %0:_, %1:_ + + CHECK: [[VEC0:%[0-9]+]]:_(<2 x s32>) = G_BITCAST %0:_(s64) + CHECK: [[VEC1:%[0-9]+]]:_(<2 x s32>) = G_BITCAST %1:_(s64) + + CHECK: [[VCMP0:%[0-9]+]]:_(<2 x s1>) = G_ICMP intpred(slt), [[VEC0]]:_(<2 x s32>), [[VEC1]]:_ + CHECK: [[SMINV:%[0-9]+]]:_(<2 x s32>) = G_SELECT [[VCMP0]]:_(<2 x s1>), [[VEC0]]:_, [[VEC1]]:_ + + CHECK: [[VCMP1:%[0-9]+]]:_(<2 x s1>) = G_ICMP intpred(sgt), [[VEC0]]:_(<2 x s32>), [[VEC1]]:_ + CHECK: [[SMAXV:%[0-9]+]]:_(<2 x s32>) = G_SELECT [[VCMP1]]:_(<2 x s1>), [[VEC0]]:_, [[VEC1]]:_ + + CHECK: [[VCMP2:%[0-9]+]]:_(<2 x s1>) = G_ICMP intpred(ult), [[VEC0]]:_(<2 x s32>), [[VEC1]]:_ + CHECK: [[UMINV:%[0-9]+]]:_(<2 x s32>) = G_SELECT [[VCMP2]]:_(<2 x s1>), [[VEC0]]:_, [[VEC1]]:_ + + CHECK: [[VCMP3:%[0-9]+]]:_(<2 x s1>) = G_ICMP intpred(ugt), [[VEC0]]:_(<2 x s32>), [[VEC1]]:_ + CHECK: [[UMAXV:%[0-9]+]]:_(<2 x s32>) = G_SELECT [[VCMP3]]:_(<2 x s1>), [[VEC0]]:_, [[VEC1]]:_ + )"; + + EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; +} } // namespace