Index: llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h =================================================================== --- llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h +++ llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h @@ -231,6 +231,9 @@ /// Optimize (x op x) -> x bool matchBinOpSameVal(MachineInstr &MI); + /// Check if operand \p OpIdx is zero. + bool matchOperandIsZero(MachineInstr &MI, unsigned OpIdx); + /// Try to transform \p MI by using all of the above /// combine functions. Returns true if changed. bool tryCombine(MachineInstr &MI); Index: llvm/include/llvm/Target/GlobalISel/Combine.td =================================================================== --- llvm/include/llvm/Target/GlobalISel/Combine.td +++ llvm/include/llvm/Target/GlobalISel/Combine.td @@ -208,6 +208,22 @@ (apply [{ return Helper.replaceSingleDefInstWithOperand(*${root}, 1); }]) >; +// Fold (0 op x) - > 0 +def binop_left_to_zero: GICombineRule< + (defs root:$root), + (match (wip_match_opcode G_SDIV, G_UDIV, G_SREM, G_UREM):$root, + [{ return Helper.matchOperandIsZero(*${root}, 1); }]), + (apply [{ return Helper.replaceSingleDefInstWithOperand(*${root}, 1); }]) +>; + +// Fold (x op 0) - > 0 +def binop_right_to_zero: GICombineRule< + (defs root:$root), + (match (wip_match_opcode G_MUL):$root, + [{ return Helper.matchOperandIsZero(*${root}, 2); }]), + (apply [{ return Helper.replaceSingleDefInstWithOperand(*${root}, 2); }]) +>; + // 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, @@ -216,7 +232,8 @@ propagate_undef_shuffle_mask]>; def identity_combines : GICombineGroup<[select_same_val, right_identity_zero, - binop_same_val]>; + binop_same_val, binop_left_to_zero, + binop_right_to_zero]>; 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 @@ -1587,6 +1587,12 @@ MRI); } +bool CombinerHelper::matchOperandIsZero(MachineInstr &MI, unsigned OpIdx) { + return matchConstantOp(MI.getOperand(OpIdx), 0) && + canReplaceReg(MI.getOperand(0).getReg(), MI.getOperand(OpIdx).getReg(), + MRI); +} + bool CombinerHelper::replaceInstWithFConstant(MachineInstr &MI, double C) { assert(MI.getNumDefs() == 1 && "Expected only one def?"); Builder.setInstr(MI); Index: llvm/test/CodeGen/AArch64/GlobalISel/prelegalizercombiner-trivial-arith.mir =================================================================== --- llvm/test/CodeGen/AArch64/GlobalISel/prelegalizercombiner-trivial-arith.mir +++ llvm/test/CodeGen/AArch64/GlobalISel/prelegalizercombiner-trivial-arith.mir @@ -40,6 +40,132 @@ RET_ReallyLR implicit $w0 ... +--- +name: mul_0 +tracksRegLiveness: true +body: | + bb.1.entry: + liveins: $w0 + ; Fold (x * 0) -> 0 + ; + ; CHECK-LABEL: name: mul_0 + ; CHECK: liveins: $w0 + ; CHECK: %cst:_(s32) = G_CONSTANT i32 0 + ; CHECK: $w0 = COPY %cst(s32) + ; CHECK: RET_ReallyLR implicit $w0 + %x:_(s32) = COPY $w0 + %cst:_(s32) = G_CONSTANT i32 0 + %op:_(s32) = G_MUL %x(s32), %cst + $w0 = COPY %op(s32) + RET_ReallyLR implicit $w0 + +... + +# FIXME: Probably should be able to replace this. +--- +name: mul_0_cant_replace +tracksRegLiveness: true +body: | + bb.1.entry: + liveins: $w0 + ; Fold (x * 0) -> 0 + ; + ; CHECK-LABEL: name: mul_0_cant_replace + ; CHECK: liveins: $w0 + ; CHECK: %x:_(s32) = COPY $w0 + ; CHECK: %cst:_(s32) = G_CONSTANT i32 0 + ; CHECK: %op:gpr(s32) = G_MUL %x, %cst + ; CHECK: $w0 = COPY %op(s32) + ; CHECK: RET_ReallyLR implicit $w0 + %x:_(s32) = COPY $w0 + %cst:_(s32) = G_CONSTANT i32 0 + %op:gpr(s32) = G_MUL %x(s32), %cst + $w0 = COPY %op(s32) + RET_ReallyLR implicit $w0 + +... + +--- +name: sdiv_0 +tracksRegLiveness: true +body: | + bb.1.entry: + liveins: $w0 + ; Fold (0 / x) -> 0 + ; + ; CHECK-LABEL: name: sdiv_0 + ; CHECK: liveins: $w0 + ; CHECK: %cst:_(s32) = G_CONSTANT i32 0 + ; CHECK: $w0 = COPY %cst(s32) + ; CHECK: RET_ReallyLR implicit $w0 + %x:_(s32) = COPY $w0 + %cst:_(s32) = G_CONSTANT i32 0 + %op:_(s32) = G_SDIV %cst, %x + $w0 = COPY %op(s32) + RET_ReallyLR implicit $w0 + +... +--- +name: udiv_0 +tracksRegLiveness: true +body: | + bb.1.entry: + liveins: $w0 + ; Fold (0 / x) -> 0 + ; + ; CHECK-LABEL: name: udiv_0 + ; CHECK: liveins: $w0 + ; CHECK: %cst:_(s32) = G_CONSTANT i32 0 + ; CHECK: $w0 = COPY %cst(s32) + ; CHECK: RET_ReallyLR implicit $w0 + %x:_(s32) = COPY $w0 + %cst:_(s32) = G_CONSTANT i32 0 + %op:_(s32) = G_UDIV %cst, %x + $w0 = COPY %op(s32) + RET_ReallyLR implicit $w0 + +... +--- +name: srem_0 +tracksRegLiveness: true +body: | + bb.1.entry: + liveins: $w0 + ; Fold (0 % x) -> 0 + ; + ; CHECK-LABEL: name: srem_0 + ; CHECK: liveins: $w0 + ; CHECK: %cst:_(s32) = G_CONSTANT i32 0 + ; CHECK: $w0 = COPY %cst(s32) + ; CHECK: RET_ReallyLR implicit $w0 + %x:_(s32) = COPY $w0 + %cst:_(s32) = G_CONSTANT i32 0 + %op:_(s32) = G_SREM %cst, %x + $w0 = COPY %op(s32) + RET_ReallyLR implicit $w0 + +... +--- +name: urem_0 +tracksRegLiveness: true +body: | + bb.1.entry: + liveins: $w0 + ; Fold (0 % x) -> 0 + ; + ; CHECK-LABEL: name: urem_0 + ; CHECK: liveins: $w0 + ; CHECK: %cst:_(s32) = G_CONSTANT i32 0 + ; CHECK: $w0 = COPY %cst(s32) + ; CHECK: RET_ReallyLR implicit $w0 + %x:_(s32) = COPY $w0 + %cst:_(s32) = G_CONSTANT i32 0 + %op:_(s32) = G_UREM %cst, %x + $w0 = COPY %op(s32) + RET_ReallyLR implicit $w0 + +... + --- name: right_ident_or tracksRegLiveness: true