diff --git a/llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h b/llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h index ecaece8b68342..538beaf1e7864 100644 --- a/llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h +++ b/llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h @@ -822,6 +822,9 @@ class CombinerHelper { // Given a binop \p MI, commute operands 1 and 2. void applyCommuteBinOpOperands(MachineInstr &MI); + /// Combine select to integer min/max. + bool matchSelectIMinMax(const MachineOperand &MO, BuildFnTy &MatchInfo); + /// Combine selects. bool matchSelect(MachineInstr &MI, BuildFnTy &MatchInfo); @@ -962,9 +965,6 @@ class CombinerHelper { bool tryFoldSelectOfConstants(GSelect *Select, BuildFnTy &MatchInfo); - /// Try to fold (icmp X, Y) ? X : Y -> integer minmax. - bool tryFoldSelectToIntMinMax(GSelect *Select, BuildFnTy &MatchInfo); - bool isOneOrOneSplat(Register Src, bool AllowUndefs); bool isZeroOrZeroSplat(Register Src, bool AllowUndefs); bool isConstantSplatVector(Register Src, int64_t SplatValue, diff --git a/llvm/include/llvm/Target/GlobalISel/Combine.td b/llvm/include/llvm/Target/GlobalISel/Combine.td index d61a5759d5a96..a1d39d910bc8e 100644 --- a/llvm/include/llvm/Target/GlobalISel/Combine.td +++ b/llvm/include/llvm/Target/GlobalISel/Combine.td @@ -1307,6 +1307,13 @@ def select_to_minmax: GICombineRule< [{ return Helper.matchSimplifySelectToMinMax(*${root}, ${info}); }]), (apply [{ Helper.applyBuildFn(*${root}, ${info}); }])>; +def select_to_iminmax: GICombineRule< + (defs root:$root, build_fn_matchinfo:$info), + (match (G_ICMP $tst, $tst1, $x, $y), + (G_SELECT $root, $tst, $x, $y), + [{ return Helper.matchSelectIMinMax(${root}, ${info}); }]), + (apply [{ Helper.applyBuildFnMO(${root}, ${info}); }])>; + def match_selects : GICombineRule< (defs root:$root, build_fn_matchinfo:$matchinfo), (match (wip_match_opcode G_SELECT):$root, @@ -1670,7 +1677,7 @@ def phi_combines : GICombineGroup<[extend_through_phis]>; def bitreverse_shift : GICombineGroup<[bitreverse_shl, bitreverse_lshr]>; def select_combines : GICombineGroup<[select_undef_cmp, select_constant_cmp, - match_selects]>; + select_to_iminmax, match_selects]>; def trivial_combines : GICombineGroup<[copy_prop, mul_to_shl, add_p2i_to_ptradd, mul_by_neg_one, idempotent_prop]>; diff --git a/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp b/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp index 809f13abcadd1..a87a26d72b452 100644 --- a/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp +++ b/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp @@ -6749,10 +6749,12 @@ bool CombinerHelper::tryFoldBoolSelectToLogic(GSelect *Select, return false; } -bool CombinerHelper::tryFoldSelectToIntMinMax(GSelect *Select, - BuildFnTy &MatchInfo) { +bool CombinerHelper::matchSelectIMinMax(const MachineOperand &MO, + BuildFnTy &MatchInfo) { + GSelect *Select = cast(MRI.getVRegDef(MO.getReg())); + GICmp *Cmp = cast(MRI.getVRegDef(Select->getCondReg())); + Register DstReg = Select->getReg(0); - Register Cond = Select->getCondReg(); Register True = Select->getTrueReg(); Register False = Select->getFalseReg(); LLT DstTy = MRI.getType(DstReg); @@ -6760,11 +6762,6 @@ bool CombinerHelper::tryFoldSelectToIntMinMax(GSelect *Select, if (DstTy.isPointer()) return false; - // We need an G_ICMP on the condition register. - GICmp *Cmp = getOpcodeDef(Cond, MRI); - if (!Cmp) - return false; - // We want to fold the icmp and replace the select. if (!MRI.hasOneNonDBGUse(Cmp->getReg(0))) return false; @@ -6775,62 +6772,46 @@ bool CombinerHelper::tryFoldSelectToIntMinMax(GSelect *Select, if (CmpInst::isEquality(Pred)) return false; - Register CmpLHS = Cmp->getLHSReg(); - Register CmpRHS = Cmp->getRHSReg(); - - // We can swap CmpLHS and CmpRHS for higher hitrate. - if (True == CmpRHS && False == CmpLHS) { - std::swap(CmpLHS, CmpRHS); - Pred = CmpInst::getSwappedPredicate(Pred); - } + [[maybe_unused]] Register CmpLHS = Cmp->getLHSReg(); + [[maybe_unused]] Register CmpRHS = Cmp->getRHSReg(); // (icmp X, Y) ? X : Y -> integer minmax. // see matchSelectPattern in ValueTracking. // Legality between G_SELECT and integer minmax can differ. - if (True == CmpLHS && False == CmpRHS) { - switch (Pred) { - case ICmpInst::ICMP_UGT: - case ICmpInst::ICMP_UGE: { - if (!isLegalOrBeforeLegalizer({TargetOpcode::G_UMAX, DstTy})) - return false; - MatchInfo = [=](MachineIRBuilder &B) { - B.buildUMax(DstReg, True, False); - }; - return true; - } - case ICmpInst::ICMP_SGT: - case ICmpInst::ICMP_SGE: { - if (!isLegalOrBeforeLegalizer({TargetOpcode::G_SMAX, DstTy})) - return false; - MatchInfo = [=](MachineIRBuilder &B) { - B.buildSMax(DstReg, True, False); - }; - return true; - } - case ICmpInst::ICMP_ULT: - case ICmpInst::ICMP_ULE: { - if (!isLegalOrBeforeLegalizer({TargetOpcode::G_UMIN, DstTy})) - return false; - MatchInfo = [=](MachineIRBuilder &B) { - B.buildUMin(DstReg, True, False); - }; - return true; - } - case ICmpInst::ICMP_SLT: - case ICmpInst::ICMP_SLE: { - if (!isLegalOrBeforeLegalizer({TargetOpcode::G_SMIN, DstTy})) - return false; - MatchInfo = [=](MachineIRBuilder &B) { - B.buildSMin(DstReg, True, False); - }; - return true; - } - default: + assert(True == CmpLHS && False == CmpRHS && "unexpected MIR pattern"); + + switch (Pred) { + case ICmpInst::ICMP_UGT: + case ICmpInst::ICMP_UGE: { + if (!isLegalOrBeforeLegalizer({TargetOpcode::G_UMAX, DstTy})) return false; - } + MatchInfo = [=](MachineIRBuilder &B) { B.buildUMax(DstReg, True, False); }; + return true; + } + case ICmpInst::ICMP_SGT: + case ICmpInst::ICMP_SGE: { + if (!isLegalOrBeforeLegalizer({TargetOpcode::G_SMAX, DstTy})) + return false; + MatchInfo = [=](MachineIRBuilder &B) { B.buildSMax(DstReg, True, False); }; + return true; + } + case ICmpInst::ICMP_ULT: + case ICmpInst::ICMP_ULE: { + if (!isLegalOrBeforeLegalizer({TargetOpcode::G_UMIN, DstTy})) + return false; + MatchInfo = [=](MachineIRBuilder &B) { B.buildUMin(DstReg, True, False); }; + return true; + } + case ICmpInst::ICMP_SLT: + case ICmpInst::ICMP_SLE: { + if (!isLegalOrBeforeLegalizer({TargetOpcode::G_SMIN, DstTy})) + return false; + MatchInfo = [=](MachineIRBuilder &B) { B.buildSMin(DstReg, True, False); }; + return true; + } + default: + return false; } - - return false; } bool CombinerHelper::matchSelect(MachineInstr &MI, BuildFnTy &MatchInfo) { @@ -6842,9 +6823,6 @@ bool CombinerHelper::matchSelect(MachineInstr &MI, BuildFnTy &MatchInfo) { if (tryFoldBoolSelectToLogic(Select, MatchInfo)) return true; - if (tryFoldSelectToIntMinMax(Select, MatchInfo)) - return true; - return false; } diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/combine-select.mir b/llvm/test/CodeGen/AArch64/GlobalISel/combine-select.mir index 2bf7e84a379ba..8d9ad8d7cacaf 100644 --- a/llvm/test/CodeGen/AArch64/GlobalISel/combine-select.mir +++ b/llvm/test/CodeGen/AArch64/GlobalISel/combine-select.mir @@ -896,3 +896,31 @@ body: | RET_ReallyLR ... +--- +# test failed select icmp_slef,t_t_f --> smin(t,f) +name: select_icmp_sle_f_t_t_f_smin_t_f +body: | + bb.1: + liveins: $x0, $x1, $x2 + ; CHECK-LABEL: name: select_icmp_sle_f_t_t_f_smin_t_f + ; CHECK: liveins: $x0, $x1, $x2 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(s64) = COPY $x0 + ; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(s64) = COPY $x1 + ; CHECK-NEXT: %t1:_(s32) = G_TRUNC [[COPY]](s64) + ; CHECK-NEXT: %f1:_(s32) = G_TRUNC [[COPY1]](s64) + ; CHECK-NEXT: %t:_(<4 x s32>) = G_BUILD_VECTOR %t1(s32), %t1(s32), %t1(s32), %t1(s32) + ; CHECK-NEXT: %f:_(<4 x s32>) = G_BUILD_VECTOR %f1(s32), %f1(s32), %f1(s32), %f1(s32) + ; CHECK-NEXT: %c:_(<4 x s32>) = G_ICMP intpred(sle), %f(<4 x s32>), %t + ; CHECK-NEXT: %sel:_(<4 x s32>) = exact G_SELECT %c(<4 x s32>), %t, %f + ; CHECK-NEXT: $q0 = COPY %sel(<4 x s32>) + %0:_(s64) = COPY $x0 + %1:_(s64) = COPY $x1 + %t1:_(s32) = G_TRUNC %0 + %f1:_(s32) = G_TRUNC %1 + %t:_(<4 x s32>) = G_BUILD_VECTOR %t1, %t1, %t1, %t1 + %f:_(<4 x s32>) = G_BUILD_VECTOR %f1, %f1, %f1, %f1 + %c:_(<4 x s32>) = G_ICMP intpred(sle), %f(<4 x s32>), %t(<4 x s32>) + %sel:_(<4 x s32>) = exact G_SELECT %c, %t, %f + $q0 = COPY %sel(<4 x s32>) +...