[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