diff --git a/llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h b/llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h --- a/llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h +++ b/llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h @@ -221,6 +221,10 @@ /// equivalent instructions. bool matchEqualDefs(const MachineOperand &MOP1, const MachineOperand &MOP2); + /// Return true if \p MOP is defined by a G_CONSTANT with a value equal to + /// \p C. + bool matchConstantOp(const MachineOperand &MOP, int64_t C); + /// Optimize (cond ? x : x) -> x bool matchSelectSameVal(MachineInstr &MI); diff --git a/llvm/include/llvm/Target/GlobalISel/Combine.td b/llvm/include/llvm/Target/GlobalISel/Combine.td --- a/llvm/include/llvm/Target/GlobalISel/Combine.td +++ b/llvm/include/llvm/Target/GlobalISel/Combine.td @@ -192,6 +192,14 @@ (apply [{ return Helper.replaceSingleDefInstWithOperand(*${root}, 2); }]) >; +// Fold x op 0 -> x +def right_identity_zero: GICombineRule< + (defs root:$root), + (match (wip_match_opcode G_SUB, G_ADD, G_OR, G_XOR, G_SHL, G_ASHR, G_LSHR):$root, + [{ return Helper.matchConstantOp(${root}->getOperand(2), 0); }]), + (apply [{ return Helper.replaceSingleDefInstWithOperand(*${root}, 1); }]) +>; + // FIXME: These should use the custom predicate feature once it lands. def undef_combines : GICombineGroup<[undef_to_fp_zero, undef_to_int_zero, undef_to_negative_one, @@ -199,7 +207,7 @@ propagate_undef_all_ops, propagate_undef_shuffle_mask]>; -def identity_combines : GICombineGroup<[select_same_val]>; +def identity_combines : GICombineGroup<[select_same_val, right_identity_zero]>; def trivial_combines : GICombineGroup<[copy_prop, mul_to_shl]>; def all_combines : GICombineGroup<[trivial_combines, ptr_add_immed_chain, diff --git a/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp b/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp --- a/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp +++ b/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp @@ -9,6 +9,7 @@ #include "llvm/CodeGen/GlobalISel/Combiner.h" #include "llvm/CodeGen/GlobalISel/GISelChangeObserver.h" #include "llvm/CodeGen/GlobalISel/GISelKnownBits.h" +#include "llvm/CodeGen/GlobalISel/MIPatternMatch.h" #include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h" #include "llvm/CodeGen/GlobalISel/Utils.h" #include "llvm/CodeGen/MachineDominators.h" @@ -23,6 +24,7 @@ #define DEBUG_TYPE "gi-combiner" using namespace llvm; +using namespace MIPatternMatch; // Option to allow testing of the combiner while no targets know about indexed // addressing. @@ -1546,6 +1548,13 @@ return Builder.getTII().produceSameValue(*I1, *I2, &MRI); } +bool CombinerHelper::matchConstantOp(const MachineOperand &MOP, int64_t C) { + if (!MOP.isReg()) + return false; + int64_t Cst; + return mi_match(MOP.getReg(), MRI, m_ICst(Cst)) && Cst == C; +} + bool CombinerHelper::replaceSingleDefInstWithOperand(MachineInstr &MI, unsigned OpIdx) { assert(MI.getNumExplicitDefs() == 1 && "Expected one explicit def?"); diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/prelegalizercombiner-trivial-arith.mir b/llvm/test/CodeGen/AArch64/GlobalISel/prelegalizercombiner-trivial-arith.mir new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/AArch64/GlobalISel/prelegalizercombiner-trivial-arith.mir @@ -0,0 +1,163 @@ +# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py +# RUN: llc -mtriple aarch64 -run-pass=aarch64-prelegalizer-combiner -verify-machineinstrs %s -o - | FileCheck %s + +name: right_ident_sub +tracksRegLiveness: true +body: | + bb.1.entry: + liveins: $w0 + ; Fold (x - 0) -> x + ; + ; CHECK-LABEL: name: right_ident_sub + ; CHECK: liveins: $w0 + ; CHECK: %x:_(s32) = COPY $w0 + ; CHECK: $w0 = COPY %x(s32) + ; CHECK: RET_ReallyLR implicit $w0 + %x:_(s32) = COPY $w0 + %cst:_(s32) = G_CONSTANT i32 0 + %op:_(s32) = G_SUB %x(s32), %cst + $w0 = COPY %op(s32) + RET_ReallyLR implicit $w0 + +... +--- +name: right_ident_add +tracksRegLiveness: true +body: | + bb.1.entry: + liveins: $w0 + ; Fold (x + 0) -> x + ; + ; CHECK-LABEL: name: right_ident_add + ; CHECK: liveins: $w0 + ; CHECK: %x:_(s32) = COPY $w0 + ; CHECK: $w0 = COPY %x(s32) + ; CHECK: RET_ReallyLR implicit $w0 + %x:_(s32) = COPY $w0 + %cst:_(s32) = G_CONSTANT i32 0 + %op:_(s32) = G_ADD %x(s32), %cst + $w0 = COPY %op(s32) + RET_ReallyLR implicit $w0 + +... +--- +name: right_ident_or +tracksRegLiveness: true +body: | + bb.1.entry: + liveins: $w0 + ; Fold (x || 0) -> x + ; + ; CHECK-LABEL: name: right_ident_or + ; CHECK: liveins: $w0 + ; CHECK: %x:_(s32) = COPY $w0 + ; CHECK: $w0 = COPY %x(s32) + ; CHECK: RET_ReallyLR implicit $w0 + %x:_(s32) = COPY $w0 + %cst:_(s32) = G_CONSTANT i32 0 + %op:_(s32) = G_OR %x(s32), %cst + $w0 = COPY %op(s32) + RET_ReallyLR implicit $w0 + +... +--- +name: right_ident_xor +tracksRegLiveness: true +body: | + bb.1.entry: + liveins: $w0 + ; Fold (x | 0) -> x + ; + ; CHECK-LABEL: name: right_ident_xor + ; CHECK: liveins: $w0 + ; CHECK: %x:_(s32) = COPY $w0 + ; CHECK: $w0 = COPY %x(s32) + ; CHECK: RET_ReallyLR implicit $w0 + %x:_(s32) = COPY $w0 + %cst:_(s32) = G_CONSTANT i32 0 + %op:_(s32) = G_XOR %x(s32), %cst + $w0 = COPY %op(s32) + RET_ReallyLR implicit $w0 + +... +--- +name: right_ident_shl +tracksRegLiveness: true +body: | + bb.1.entry: + liveins: $w0 + ; Fold (x << 0) -> x + ; + ; CHECK-LABEL: name: right_ident_shl + ; CHECK: liveins: $w0 + ; CHECK: %x:_(s32) = COPY $w0 + ; CHECK: $w0 = COPY %x(s32) + ; CHECK: RET_ReallyLR implicit $w0 + %x:_(s32) = COPY $w0 + %cst:_(s32) = G_CONSTANT i32 0 + %op:_(s32) = G_SHL %x(s32), %cst + $w0 = COPY %op(s32) + RET_ReallyLR implicit $w0 + +... +--- +name: right_ident_ashr +tracksRegLiveness: true +body: | + bb.1.entry: + liveins: $w0 + ; Fold (x ashr 0) -> x + ; + ; CHECK-LABEL: name: right_ident_ashr + ; CHECK: liveins: $w0 + ; CHECK: %x:_(s32) = COPY $w0 + ; CHECK: $w0 = COPY %x(s32) + ; CHECK: RET_ReallyLR implicit $w0 + %x:_(s32) = COPY $w0 + %cst:_(s32) = G_CONSTANT i32 0 + %op:_(s32) = G_ASHR %x(s32), %cst + $w0 = COPY %op(s32) + RET_ReallyLR implicit $w0 + +... +--- +name: right_ident_lshr +tracksRegLiveness: true +body: | + bb.1.entry: + liveins: $w0 + ; Fold (x lshr 0) -> x + ; + ; CHECK-LABEL: name: right_ident_lshr + ; CHECK: liveins: $w0 + ; CHECK: %x:_(s32) = COPY $w0 + ; CHECK: $w0 = COPY %x(s32) + ; CHECK: RET_ReallyLR implicit $w0 + %x:_(s32) = COPY $w0 + %cst:_(s32) = G_CONSTANT i32 0 + %op:_(s32) = G_LSHR %x(s32), %cst + $w0 = COPY %op(s32) + RET_ReallyLR implicit $w0 + +... +--- +name: dont_fold_sub +tracksRegLiveness: true +body: | + bb.1.entry: + liveins: $w0 + ; Not an identity, no folding. + ; + ; CHECK-LABEL: name: dont_fold_sub + ; CHECK: liveins: $w0 + ; CHECK: %x:_(s32) = COPY $w0 + ; CHECK: %cst:_(s32) = G_CONSTANT i32 1 + ; CHECK: %op:_(s32) = G_SUB %x, %cst + ; CHECK: $w0 = COPY %op(s32) + ; CHECK: RET_ReallyLR implicit $w0 + %x:_(s32) = COPY $w0 + %cst:_(s32) = G_CONSTANT i32 1 + %op:_(s32) = G_SUB %x(s32), %cst + $w0 = COPY %op(s32) + RET_ReallyLR implicit $w0 +...