[llvm] [GlobalISel] Migrate overlapping_and to MIR pattern match (PR #222478)
Jinsong Ji via llvm-commits
llvm-commits at lists.llvm.org
Wed Sep 9 16:58:09 PDT 2026
https://github.com/jsji updated https://github.com/llvm/llvm-project/pull/222478
>From 2da60c0219926516580a07ab406fa9a76cabd41c Mon Sep 17 00:00:00 2001
From: Jinsong Ji <jinsong.ji at intel.com>
Date: Wed, 9 Sep 2026 04:38:48 +0200
Subject: [PATCH 1/2] [GlobalISel] Migrate overlapping_and to MIR pattern match
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
3741dacd195a migrated redundant_and from wip_match_opcode to MIR
pattern. In the generated combiner match table, wip_match_opcode
rules run before MIR-pattern rules. This demoted redundant_and
below overlapping_and, reversing their original relative priority.
For and(and(x, C), C), redundant_and (using KnownBits) correctly
replaces the outer AND via register substitution, while
overlapping_and creates a new G_CONSTANT (C & C = C) that lacks
a register bank — crashing the machine verifier in regBankSelected
functions.
Migrate overlapping_and to MIR-pattern match so both rules are in
the same section of the match table, restoring the original ordering
where redundant_and (in known_bits_simplifications) precedes
overlapping_and (in const_combines).
Assisted-By: Claude Opus 4.6
---
.../include/llvm/Target/GlobalISel/Combine.td | 2 +-
.../redundant-and-beats-overlapping-and.mir | 69 +++++++++++++++++++
2 files changed, 70 insertions(+), 1 deletion(-)
create mode 100644 llvm/test/CodeGen/AArch64/GlobalISel/redundant-and-beats-overlapping-and.mir
diff --git a/llvm/include/llvm/Target/GlobalISel/Combine.td b/llvm/include/llvm/Target/GlobalISel/Combine.td
index 3735e95ee8f68..00da49d1e5c85 100644
--- a/llvm/include/llvm/Target/GlobalISel/Combine.td
+++ b/llvm/include/llvm/Target/GlobalISel/Combine.td
@@ -1000,7 +1000,7 @@ def neg_and_one_to_sext_inreg : GICombineRule<
// Fold and(and(x, C1), C2) -> C1&C2 ? and(x, C1&C2) : 0
def overlapping_and: GICombineRule <
(defs root:$root, build_fn_matchinfo:$info),
- (match (wip_match_opcode G_AND):$root,
+ (match (G_AND $root, $src1, $src2):$root,
[{ return Helper.matchOverlappingAnd(*${root}, ${info}); }]),
(apply [{ Helper.applyBuildFn(*${root}, ${info}); }])
>;
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/redundant-and-beats-overlapping-and.mir b/llvm/test/CodeGen/AArch64/GlobalISel/redundant-and-beats-overlapping-and.mir
new file mode 100644
index 0000000000000..5aa4ee0d32c50
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/redundant-and-beats-overlapping-and.mir
@@ -0,0 +1,69 @@
+# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
+# RUN: llc -mtriple arm64-apple-ios -run-pass=aarch64-postlegalizer-combiner -global-isel -verify-machineinstrs %s -o - | FileCheck %s
+
+# Test that redundant_and fires before overlapping_and for and(and(x, C), C)
+# where both constants are identical.
+#
+# Before 97f2b2f1a136, commit 3741dacd195a migrated redundant_and from
+# wip_match_opcode to MIR-pattern but left overlapping_and as
+# wip_match_opcode. In the generated combiner match table, wip_match_opcode
+# rules run before MIR-pattern rules, so overlapping_and fired first and
+# created a new G_CONSTANT (C & C = C) via MachineIRBuilder. That new
+# constant lacks a register bank, which crashes the machine verifier in
+# regBankSelected functions.
+#
+# With the fix, both rules are MIR-pattern, restoring the original ordering
+# where redundant_and (in known_bits_simplifications, listed earlier in the
+# combiner) takes priority and replaces the outer AND via register
+# substitution — no new instructions.
+
+---
+name: and_same_const_pre_regbankselect
+legalized: true
+tracksRegLiveness: true
+body: |
+ bb.0:
+ liveins: $w0
+ ; CHECK-LABEL: name: and_same_const_pre_regbankselect
+ ; CHECK: liveins: $w0
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: %x:_(s32) = COPY $w0
+ ; CHECK-NEXT: %c1:_(s32) = G_CONSTANT i32 255
+ ; CHECK-NEXT: %inner:_(s32) = G_AND %x, %c1
+ ; CHECK-NEXT: $w0 = COPY %inner(s32)
+ ; CHECK-NEXT: RET_ReallyLR implicit $w0
+ %x:_(s32) = COPY $w0
+ %c1:_(s32) = G_CONSTANT i32 255
+ %c2:_(s32) = G_CONSTANT i32 255
+ %inner:_(s32) = G_AND %x, %c1
+ %outer:_(s32) = G_AND %inner, %c2
+ $w0 = COPY %outer(s32)
+ RET_ReallyLR implicit $w0
+...
+---
+# Same test but with a regBankSelected function. Before the fix,
+# overlapping_and would fire and create a G_CONSTANT without a register
+# bank, crashing -verify-machineinstrs.
+name: and_same_const_regbankselected
+legalized: true
+regBankSelected: true
+tracksRegLiveness: true
+body: |
+ bb.0:
+ liveins: $w0
+ ; CHECK-LABEL: name: and_same_const_regbankselected
+ ; CHECK: liveins: $w0
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: %x:gpr(s32) = COPY $w0
+ ; CHECK-NEXT: %c1:gpr(s32) = G_CONSTANT i32 255
+ ; CHECK-NEXT: %inner:gpr(s32) = G_AND %x, %c1
+ ; CHECK-NEXT: $w0 = COPY %inner(s32)
+ ; CHECK-NEXT: RET_ReallyLR implicit $w0
+ %x:gpr(s32) = COPY $w0
+ %c1:gpr(s32) = G_CONSTANT i32 255
+ %c2:gpr(s32) = G_CONSTANT i32 255
+ %inner:gpr(s32) = G_AND %x, %c1
+ %outer:gpr(s32) = G_AND %inner, %c2
+ $w0 = COPY %outer(s32)
+ RET_ReallyLR implicit $w0
+...
>From ef15912e6e00766ae09242a66b22e39b906601f3 Mon Sep 17 00:00:00 2001
From: Jinsong Ji <jinsong.ji at intel.com>
Date: Thu, 10 Sep 2026 01:57:53 +0200
Subject: [PATCH 2/2] fix comments
---
.../AArch64/GlobalISel/redundant-and-beats-overlapping-and.mir | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/redundant-and-beats-overlapping-and.mir b/llvm/test/CodeGen/AArch64/GlobalISel/redundant-and-beats-overlapping-and.mir
index 5aa4ee0d32c50..f9fee8496de0e 100644
--- a/llvm/test/CodeGen/AArch64/GlobalISel/redundant-and-beats-overlapping-and.mir
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/redundant-and-beats-overlapping-and.mir
@@ -4,7 +4,7 @@
# Test that redundant_and fires before overlapping_and for and(and(x, C), C)
# where both constants are identical.
#
-# Before 97f2b2f1a136, commit 3741dacd195a migrated redundant_and from
+# Commit 3741dacd195a migrated redundant_and from
# wip_match_opcode to MIR-pattern but left overlapping_and as
# wip_match_opcode. In the generated combiner match table, wip_match_opcode
# rules run before MIR-pattern rules, so overlapping_and fired first and
More information about the llvm-commits
mailing list