Index: llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h =================================================================== --- llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h +++ llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h @@ -211,6 +211,17 @@ /// Return true if a G_STORE instruction \p MI is storing an undef value. bool matchUndefStore(MachineInstr &MI); + /// Return true if a G_SELECT instruction \p MI has an undef comparison. + bool matchUndefSelectCmp(MachineInstr &MI); + + /// Return true if a G_SELECT instruction \p MI has an undef select value. If + /// true, \p OpIdx will store the operand index of the known selected value. + bool matchUndefSelectVals(MachineInstr &MI, unsigned &ValIdx); + + /// Return true if a G_SELECT instruction \p MI has a constant comparison. If + /// true, \p OpIdx will store the operand index of the known selected value. + bool matchConstantSelectCmp(MachineInstr &MI, unsigned &OpIdx); + /// Replace an instruction with a G_FCONSTANT with value \p C. bool replaceInstWithFConstant(MachineInstr &MI, double C); Index: llvm/include/llvm/Target/GlobalISel/Combine.td =================================================================== --- llvm/include/llvm/Target/GlobalISel/Combine.td +++ llvm/include/llvm/Target/GlobalISel/Combine.td @@ -203,6 +203,35 @@ (apply [{ return Helper.replaceSingleDefInstWithOperand(*${root}, 2); }]) >; +// Fold (undef ? x : y) -> x +def select_undef_cmp: GICombineRule< + (defs root:$root), + (match (wip_match_opcode G_SELECT):$root, + [{ return Helper.matchUndefSelectCmp(*${root}); }]), + (apply [{ return Helper.replaceSingleDefInstWithOperand(*${root}, 2); }]) +>; + +// Fold (cmp ? x : undef) -> x +// Fold (cmp ? undef : y) -> y +// Fold (cmp ? undef : undef) -> undef +def select_undef_val_matchdata : GIDefMatchData<"unsigned">; +def select_undef_val: GICombineRule< + (defs root:$root, select_undef_val_matchdata:$matchinfo), + (match (wip_match_opcode G_SELECT):$root, + [{ return Helper.matchUndefSelectVals(*${root}, ${matchinfo}); }]), + (apply [{ return Helper.replaceSingleDefInstWithOperand(*${root}, ${matchinfo}); }]) +>; + +// Fold (true ? x : y) -> x +// Fold (false ? x : y) -> y +def select_constant_cmp_matchdata : GIDefMatchData<"unsigned">; +def select_constant_cmp: GICombineRule< + (defs root:$root, select_constant_cmp_matchdata:$matchinfo), + (match (wip_match_opcode G_SELECT):$root, + [{ return Helper.matchConstantSelectCmp(*${root}, ${matchinfo}); }]), + (apply [{ return Helper.replaceSingleDefInstWithOperand(*${root}, ${matchinfo}); }]) +>; + // Fold x op 0 -> x def right_identity_zero: GICombineRule< (defs root:$root), @@ -263,7 +292,10 @@ binop_same_val, binop_left_to_zero, binop_right_to_zero]>; +def select_combines : GICombineGroup<[select_undef_cmp, select_undef_val, + select_constant_cmp]>; + def trivial_combines : GICombineGroup<[copy_prop, mul_to_shl]>; def all_combines : GICombineGroup<[trivial_combines, ptr_add_immed_chain, combines_for_extload, combine_indexed_load_store, undef_combines, - identity_combines, simplify_add_to_sub]>; + identity_combines, select_combines, simplify_add_to_sub]>; Index: llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp =================================================================== --- llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp +++ llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp @@ -1537,6 +1537,39 @@ MRI); } +bool CombinerHelper::matchUndefSelectCmp(MachineInstr &MI) { + assert(MI.getOpcode() == TargetOpcode::G_SELECT); + return getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, MI.getOperand(1).getReg(), + MRI); +} + +bool CombinerHelper::matchUndefSelectVals(MachineInstr &MI, unsigned &OpIdx) { + assert(MI.getOpcode() == TargetOpcode::G_SELECT); + if (getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, MI.getOperand(2).getReg(), + MRI)) { + // Select val0 is undef, choose select val1. + OpIdx = 3; + return true; + } + if (getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, MI.getOperand(3).getReg(), + MRI)) { + // Select val1 is undef, choose select val0. + OpIdx = 2; + return true; + } + return false; +} + +bool CombinerHelper::matchConstantSelectCmp(MachineInstr &MI, unsigned &OpIdx) { + assert(MI.getOpcode() == TargetOpcode::G_SELECT); + if (auto MaybeCstCmp = + getConstantVRegValWithLookThrough(MI.getOperand(1).getReg(), MRI)) { + OpIdx = MaybeCstCmp->Value ? 2 : 3; + return true; + } + return false; +} + bool CombinerHelper::eraseInst(MachineInstr &MI) { MI.eraseFromParent(); return true; Index: llvm/test/CodeGen/AArch64/GlobalISel/combine-select.mir =================================================================== --- /dev/null +++ llvm/test/CodeGen/AArch64/GlobalISel/combine-select.mir @@ -0,0 +1,108 @@ +# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py +# RUN: llc -run-pass=aarch64-prelegalizer-combiner -verify-machineinstrs -mtriple aarch64-unknown-unknown %s -o - | FileCheck %s +# RUN: llc -debugify-and-strip-all-safe -run-pass=aarch64-prelegalizer-combiner -verify-machineinstrs -mtriple aarch64-unknown-unknown %s -o - | FileCheck %s +--- +# select (c, x, x) -> x +name: agc.test_combine_select_same_res +body: | + bb.1: + liveins: $x0, $x1 + ; CHECK-LABEL: name: agc.test_combine_select_same_res + ; CHECK: [[COPY:%[0-9]+]]:_(s64) = COPY $x0 + ; CHECK: $x0 = COPY [[COPY]](s64) + %0:_(s64) = COPY $x0 + %1:_(s1) = G_TRUNC %0 + %2:_(s64) = G_SELECT %1, %0, %0 + $x0 = COPY %2(s64) +... +--- +# select (undef, x, y) -> x +name: agc.test_combine_select_undef_res0_res1 +body: | + bb.1: + liveins: $x0, $x1 + ; CHECK-LABEL: name: agc.test_combine_select_undef_res0_res1 + ; CHECK: [[COPY:%[0-9]+]]:_(s64) = COPY $x0 + ; CHECK: $x0 = COPY [[COPY]](s64) + %0:_(s64) = COPY $x0 + %1:_(s64) = COPY $x1 + %2:_(s1) = G_IMPLICIT_DEF + %3:_(s64) = G_SELECT %2, %0, %1 + $x0 = COPY %3(s64) +... +--- +# select (c, undef, y) -> y +name: agc.test_combine_select_cmp_undef_res1 +body: | + bb.1: + liveins: $x0 + ; CHECK-LABEL: name: agc.test_combine_select_cmp_undef_res1 + ; CHECK: [[COPY:%[0-9]+]]:_(s64) = COPY $x0 + ; CHECK: $x0 = COPY [[COPY]](s64) + %0:_(s64) = COPY $x0 + %1:_(s1) = G_TRUNC %0 + %2:_(s64) = G_IMPLICIT_DEF + %3:_(s64) = G_SELECT %1, %2, %0 + $x0 = COPY %3(s64) +... +--- +# select (c, x, undef) -> x +name: agc.test_combine_select_cmp_res0_undef +body: | + bb.1: + liveins: $x0 + ; CHECK-LABEL: name: agc.test_combine_select_cmp_res0_undef + ; CHECK: [[COPY:%[0-9]+]]:_(s64) = COPY $x0 + ; CHECK: $x0 = COPY [[COPY]](s64) + %0:_(s64) = COPY $x0 + %1:_(s1) = G_TRUNC %0 + %2:_(s64) = G_IMPLICIT_DEF + %3:_(s64) = G_SELECT %1, %0, %2 + $x0 = COPY %3(s64) +... +--- +# select (c, undef, undef) -> undef +name: agc.test_combine_select_cmp_undef_undef +body: | + bb.1: + liveins: $x0 + ; CHECK-LABEL: name: agc.test_combine_select_cmp_undef_undef + ; CHECK: [[DEF:%[0-9]+]]:_(s64) = G_IMPLICIT_DEF + ; CHECK: $x0 = COPY [[DEF]](s64) + %0:_(s64) = COPY $x0 + %1:_(s1) = G_TRUNC %0 + %2:_(s64) = G_IMPLICIT_DEF + %3:_(s64) = G_IMPLICIT_DEF + %4:_(s64) = G_SELECT %1, %2, %3 + $x0 = COPY %3(s64) +... +--- +# select (false, x, y) -> y +name: agc.test_combine_select_false_res0_res1 +body: | + bb.1: + liveins: $x0, $x1 + ; CHECK-LABEL: name: agc.test_combine_select_false_res0_res1 + ; CHECK: [[COPY:%[0-9]+]]:_(s64) = COPY $x1 + ; CHECK: $x0 = COPY [[COPY]](s64) + %0:_(s64) = COPY $x0 + %1:_(s64) = COPY $x1 + %2:_(s1) = G_CONSTANT i1 false + %3:_(s64) = G_SELECT %2, %0, %1 + $x0 = COPY %3(s64) +... +--- +# select (true, x, y) -> x +name: agc.test_combine_select_true_res0_res1 +body: | + bb.1: + liveins: $x0, $x1 + ; CHECK-LABEL: name: agc.test_combine_select_true_res0_res1 + ; CHECK: [[COPY:%[0-9]+]]:_(s64) = COPY $x0 + ; CHECK: $x0 = COPY [[COPY]](s64) + %0:_(s64) = COPY $x0 + %1:_(s64) = COPY $x1 + %2:_(s1) = G_CONSTANT i1 true + %3:_(s64) = G_SELECT %2, %0, %1 + $x0 = COPY %3(s64) +...