Index: llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h =================================================================== --- llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h +++ llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h @@ -217,6 +217,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); Index: llvm/include/llvm/Target/GlobalISel/Combine.td =================================================================== --- llvm/include/llvm/Target/GlobalISel/Combine.td +++ llvm/include/llvm/Target/GlobalISel/Combine.td @@ -192,6 +192,14 @@ (apply [{ return Helper.replaceSingleDefInstWithOperand(*${root}, 2); }]) >; +// Fold x - 0 -> x +def sub_identity: GICombineRule< + (defs root:$root), + (match (wip_match_opcode G_SUB):$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, sub_identity]>; def trivial_combines : GICombineGroup<[copy_prop, mul_to_shl]>; def all_combines : GICombineGroup<[trivial_combines, ptr_add_immed_chain, Index: llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp =================================================================== --- llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp +++ llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp @@ -1519,6 +1519,13 @@ return Builder.getTII().produceSameValue(*I1, *I2, &MRI); } +bool CombinerHelper::matchConstantOp(const MachineOperand &MOP, int64_t C) { + if (!MOP.isReg()) + return false; + auto ValAndVReg = getConstantVRegValWithLookThrough(MOP.getReg(), MRI); + return ValAndVReg && ValAndVReg->Value == C; +} + bool CombinerHelper::replaceSingleDefInstWithOperand(MachineInstr &MI, unsigned OpIdx) { assert(OpIdx < MI.getNumOperands() && "OpIdx is out of bounds"); Index: llvm/test/CodeGen/AArch64/GlobalISel/prelegalizercombiner-trivial-arith.mir =================================================================== --- /dev/null +++ llvm/test/CodeGen/AArch64/GlobalISel/prelegalizercombiner-trivial-arith.mir @@ -0,0 +1,22 @@ +# 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