[llvm] b046eb1 - [AArch64][GlobalISel] combine (and (or x, c1), c2) => (and x, c2) iff c1 & c2 == 0
Jon Roelofs via llvm-commits
llvm-commits at lists.llvm.org
Wed Oct 20 12:12:18 PDT 2021
Author: Jon Roelofs
Date: 2021-10-20T12:11:52-07:00
New Revision: b046eb19b8a42ffa3b4742e765cc013d3eefd6b5
URL: https://github.com/llvm/llvm-project/commit/b046eb19b8a42ffa3b4742e765cc013d3eefd6b5
DIFF: https://github.com/llvm/llvm-project/commit/b046eb19b8a42ffa3b4742e765cc013d3eefd6b5.diff
LOG: [AArch64][GlobalISel] combine (and (or x, c1), c2) => (and x, c2) iff c1 & c2 == 0
https://godbolt.org/z/h8ejrG4hb
rdar://83597585
Differential Revision: https://reviews.llvm.org/D111856
Added:
llvm/test/CodeGen/AArch64/GlobalISel/combine-and-or-disjoint-mask.mir
Modified:
llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h
llvm/include/llvm/Target/GlobalISel/Combine.td
llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp
Removed:
################################################################################
diff --git a/llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h b/llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h
index cc07b8e7042d5..120e90c9022e8 100644
--- a/llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h
+++ b/llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h
@@ -575,6 +575,9 @@ class CombinerHelper {
matchICmpToLHSKnownBits(MachineInstr &MI,
BuildFnTy &MatchInfo);
+ /// \returns true if (and (or x, c1), c2) can be replaced with (and x, c2)
+ bool matchAndOrDisjointMask(MachineInstr &MI, BuildFnTy &MatchInfo);
+
bool matchBitfieldExtractFromSExtInReg(MachineInstr &MI,
BuildFnTy &MatchInfo);
/// Match: and (lshr x, cst), mask -> ubfx x, cst, width
diff --git a/llvm/include/llvm/Target/GlobalISel/Combine.td b/llvm/include/llvm/Target/GlobalISel/Combine.td
index 87e827dca3047..e2d3dbdda88a4 100644
--- a/llvm/include/llvm/Target/GlobalISel/Combine.td
+++ b/llvm/include/llvm/Target/GlobalISel/Combine.td
@@ -671,6 +671,12 @@ def icmp_to_lhs_known_bits : GICombineRule<
[{ return Helper.matchICmpToLHSKnownBits(*${root}, ${info}); }]),
(apply [{ Helper.applyBuildFn(*${root}, ${info}); }])>;
+def and_or_disjoint_mask : GICombineRule<
+ (defs root:$root, build_fn_matchinfo:$info),
+ (match (wip_match_opcode G_AND):$root,
+ [{ return Helper.matchAndOrDisjointMask(*${root}, ${info}); }]),
+ (apply [{ Helper.applyBuildFnNoErase(*${root}, ${info}); }])>;
+
def bitfield_extract_from_and : GICombineRule<
(defs root:$root, build_fn_matchinfo:$info),
(match (wip_match_opcode G_AND):$root,
@@ -792,7 +798,8 @@ def all_combines : GICombineGroup<[trivial_combines, insert_vec_elt_combines,
shift_immed_chain, shift_of_shifted_logic_chain, load_or_combine,
truncstore_merge, div_rem_to_divrem, funnel_shift_combines,
form_bitfield_extract, constant_fold, fabs_fneg_fold,
- intdiv_combines, mulh_combines, redundant_neg_operands]>;
+ intdiv_combines, mulh_combines, redundant_neg_operands,
+ and_or_disjoint_mask ]>;
// A combine group used to for prelegalizer combiners at -O0. The combines in
// this group have been selected based on experiments to balance code size and
diff --git a/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp b/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp
index 92cc28797a1a0..9eac2d8867948 100644
--- a/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp
@@ -4009,6 +4009,36 @@ bool CombinerHelper::matchICmpToLHSKnownBits(
return true;
}
+// Replace (and (or x, c1), c2) with (and x, c2) iff c1 & c2 == 0
+bool CombinerHelper::matchAndOrDisjointMask(
+ MachineInstr &MI, std::function<void(MachineIRBuilder &)> &MatchInfo) {
+ assert(MI.getOpcode() == TargetOpcode::G_AND);
+
+ // Ignore vector types to simplify matching the two constants.
+ // TODO: do this for vectors and scalars via a demanded bits analysis.
+ LLT Ty = MRI.getType(MI.getOperand(0).getReg());
+ if (Ty.isVector())
+ return false;
+
+ Register Src;
+ int64_t MaskAnd;
+ int64_t MaskOr;
+ if (!mi_match(MI, MRI,
+ m_GAnd(m_GOr(m_Reg(Src), m_ICst(MaskOr)), m_ICst(MaskAnd))))
+ return false;
+
+ // Check if MaskOr could turn on any bits in Src.
+ if (MaskAnd & MaskOr)
+ return false;
+
+ MatchInfo = [=, &MI](MachineIRBuilder &B) {
+ Observer.changingInstr(MI);
+ MI.getOperand(1).setReg(Src);
+ Observer.changedInstr(MI);
+ };
+ return true;
+}
+
/// Form a G_SBFX from a G_SEXT_INREG fed by a right shift.
bool CombinerHelper::matchBitfieldExtractFromSExtInReg(
MachineInstr &MI, std::function<void(MachineIRBuilder &)> &MatchInfo) {
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/combine-and-or-disjoint-mask.mir b/llvm/test/CodeGen/AArch64/GlobalISel/combine-and-or-disjoint-mask.mir
new file mode 100644
index 0000000000000..1fb6f2ec3f1e6
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/combine-and-or-disjoint-mask.mir
@@ -0,0 +1,83 @@
+# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
+
+# RUN: llc -mtriple aarch64 -run-pass=aarch64-prelegalizer-combiner --aarch64prelegalizercombinerhelper-only-enable-rule="and_or_disjoint_mask" -global-isel -verify-machineinstrs %s -o - | FileCheck %s
+# REQUIRES: asserts
+
+...
+---
+name: disjoint_masks
+tracksRegLiveness: true
+machineFunctionInfo: {}
+body: |
+ bb.0:
+ liveins: $w0
+ ; CHECK-LABEL: name: disjoint_masks
+ ; CHECK: liveins: $w0
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: %x:_(s32) = COPY $w0
+ ; CHECK-NEXT: %two:_(s32) = G_CONSTANT i32 2
+ ; CHECK-NEXT: %and:_(s32) = G_AND %x, %two
+ ; CHECK-NEXT: $w0 = COPY %and(s32)
+ ; CHECK-NEXT: RET_ReallyLR implicit $w0
+ %x:_(s32) = COPY $w0
+ %one:_(s32) = G_CONSTANT i32 1
+ %two:_(s32) = G_CONSTANT i32 2
+ %or:_(s32) = G_OR %x, %one
+ %and:_(s32) = G_AND %or, %two
+ $w0 = COPY %and(s32)
+ RET_ReallyLR implicit $w0
+...
+---
+name: intersecting_masks
+tracksRegLiveness: true
+machineFunctionInfo: {}
+body: |
+ bb.0:
+ liveins: $w0
+ ; CHECK-LABEL: name: intersecting_masks
+ ; CHECK: liveins: $w0
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: %x:_(s32) = COPY $w0
+ ; CHECK-NEXT: %one:_(s32) = G_CONSTANT i32 3
+ ; CHECK-NEXT: %two:_(s32) = G_CONSTANT i32 2
+ ; CHECK-NEXT: %or:_(s32) = G_OR %x, %one
+ ; CHECK-NEXT: %and:_(s32) = G_AND %or, %two
+ ; CHECK-NEXT: $w0 = COPY %and(s32)
+ ; CHECK-NEXT: RET_ReallyLR implicit $w0
+ %x:_(s32) = COPY $w0
+ %one:_(s32) = G_CONSTANT i32 3
+ %two:_(s32) = G_CONSTANT i32 2
+ %or:_(s32) = G_OR %x, %one
+ %and:_(s32) = G_AND %or, %two
+ $w0 = COPY %and(s32)
+ RET_ReallyLR implicit $w0
+...
+---
+name: disjoint_masks_v
+tracksRegLiveness: true
+machineFunctionInfo: {}
+body: |
+ bb.0:
+ liveins: $x0
+ ; CHECK-LABEL: name: disjoint_masks_v
+ ; CHECK: liveins: $x0
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: %x:_(<2 x s32>) = COPY $x0
+ ; CHECK-NEXT: %one:_(s32) = G_CONSTANT i32 1
+ ; CHECK-NEXT: %one_v:_(<2 x s32>) = G_DUP %one(s32)
+ ; CHECK-NEXT: %two:_(s32) = G_CONSTANT i32 2
+ ; CHECK-NEXT: %two_v:_(<2 x s32>) = G_DUP %two(s32)
+ ; CHECK-NEXT: %or:_(<2 x s32>) = G_OR %x, %one_v
+ ; CHECK-NEXT: %and:_(<2 x s32>) = G_AND %or, %two_v
+ ; CHECK-NEXT: $x0 = COPY %and(<2 x s32>)
+ ; CHECK-NEXT: RET_ReallyLR implicit $x0
+ %x:_(<2 x s32>) = COPY $x0
+ %one:_(s32) = G_CONSTANT i32 1
+ %one_v:_(<2 x s32>) = G_DUP %one
+ %two:_(s32) = G_CONSTANT i32 2
+ %two_v:_(<2 x s32>) = G_DUP %two
+ %or:_(<2 x s32>) = G_OR %x, %one_v
+ %and:_(<2 x s32>) = G_AND %or, %two_v
+ $x0 = COPY %and(<2 x s32>)
+ RET_ReallyLR implicit $x0
+...
More information about the llvm-commits
mailing list