(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,
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,
#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"
#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.
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?");
--- /dev/null
+# 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
+...