[llvm] [GlobalISel] Add G_SEXT_INREG(G_ZEXT) -> G_SEXT combine. (PR #213606)
David Green via llvm-commits
llvm-commits at lists.llvm.org
Sun Aug 2 23:58:14 PDT 2026
https://github.com/davemgreen created https://github.com/llvm/llvm-project/pull/213606
This converts a G_ZEXT or G_ANYEXT to a G_SEXT if we will G_SEXT_INREG the bits away.
>From d2702716f26e635a2985417a5f920cda94152ff7 Mon Sep 17 00:00:00 2001
From: David Green <david.green at arm.com>
Date: Sun, 2 Aug 2026 15:13:29 +0100
Subject: [PATCH 1/2] Test
---
.../AArch64/GlobalISel/combine-sext-inreg.mir | 142 ++++++++++++++++++
1 file changed, 142 insertions(+)
create mode 100644 llvm/test/CodeGen/AArch64/GlobalISel/combine-sext-inreg.mir
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/combine-sext-inreg.mir b/llvm/test/CodeGen/AArch64/GlobalISel/combine-sext-inreg.mir
new file mode 100644
index 0000000000000..cab4694e71aa5
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/combine-sext-inreg.mir
@@ -0,0 +1,142 @@
+# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
+# RUN: llc -mtriple aarch64 -run-pass=aarch64-postlegalizer-combiner %s -o - | FileCheck %s
+
+---
+name: zext_sextinreg_7
+tracksRegLiveness: true
+legalized: true
+body: |
+ bb.0:
+ liveins: $w0
+
+ ; CHECK-LABEL: name: zext_sextinreg_7
+ ; CHECK: liveins: $w0
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(i32) = COPY $w0
+ ; CHECK-NEXT: [[C:%[0-9]+]]:_(i32) = G_CONSTANT i32 24
+ ; CHECK-NEXT: [[ASHR:%[0-9]+]]:_(i32) = G_ASHR [[COPY]], [[C]](i32)
+ ; CHECK-NEXT: [[ZEXT:%[0-9]+]]:_(i64) = G_ZEXT [[ASHR]](i32)
+ ; CHECK-NEXT: [[SEXT_INREG:%[0-9]+]]:_(i64) = G_SEXT_INREG [[ZEXT]], 7
+ ; CHECK-NEXT: $x0 = COPY [[SEXT_INREG]](i64)
+ %0:_(i32) = COPY $w0
+ %1:_(i32) = G_CONSTANT i32 24
+ %2:_(i32) = G_ASHR %0, %1
+ %3:_(i64) = G_ZEXT %2
+ %4:_(i64) = G_SEXT_INREG %3, 7
+ $x0 = COPY %4
+...
+---
+name: aext_sextinreg_7
+tracksRegLiveness: true
+legalized: true
+body: |
+ bb.0:
+ liveins: $w0
+
+ ; CHECK-LABEL: name: aext_sextinreg_7
+ ; CHECK: liveins: $w0
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(i32) = COPY $w0
+ ; CHECK-NEXT: [[C:%[0-9]+]]:_(i32) = G_CONSTANT i32 24
+ ; CHECK-NEXT: [[ASHR:%[0-9]+]]:_(i32) = G_ASHR [[COPY]], [[C]](i32)
+ ; CHECK-NEXT: [[ANYEXT:%[0-9]+]]:_(i64) = G_ANYEXT [[ASHR]](i32)
+ ; CHECK-NEXT: [[SEXT_INREG:%[0-9]+]]:_(i64) = G_SEXT_INREG [[ANYEXT]], 7
+ ; CHECK-NEXT: $x0 = COPY [[SEXT_INREG]](i64)
+ %0:_(i32) = COPY $w0
+ %1:_(i32) = G_CONSTANT i32 24
+ %2:_(i32) = G_ASHR %0, %1
+ %3:_(i64) = G_ANYEXT %2
+ %4:_(i64) = G_SEXT_INREG %3, 7
+ $x0 = COPY %4
+...
+---
+name: zext_sextinreg_8
+tracksRegLiveness: true
+legalized: true
+body: |
+ bb.0:
+ liveins: $w0
+
+ ; CHECK-LABEL: name: zext_sextinreg_8
+ ; CHECK: liveins: $w0
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(i32) = COPY $w0
+ ; CHECK-NEXT: [[C:%[0-9]+]]:_(i32) = G_CONSTANT i32 24
+ ; CHECK-NEXT: [[ASHR:%[0-9]+]]:_(i32) = G_ASHR [[COPY]], [[C]](i32)
+ ; CHECK-NEXT: [[ZEXT:%[0-9]+]]:_(i64) = G_ZEXT [[ASHR]](i32)
+ ; CHECK-NEXT: [[SEXT_INREG:%[0-9]+]]:_(i64) = G_SEXT_INREG [[ZEXT]], 8
+ ; CHECK-NEXT: $x0 = COPY [[SEXT_INREG]](i64)
+ %0:_(i32) = COPY $w0
+ %1:_(i32) = G_CONSTANT i32 24
+ %2:_(i32) = G_ASHR %0, %1
+ %3:_(i64) = G_ZEXT %2
+ %4:_(i64) = G_SEXT_INREG %3, 8
+ $x0 = COPY %4
+...
+---
+name: aext_sextinreg_8
+tracksRegLiveness: true
+legalized: true
+body: |
+ bb.0:
+ liveins: $w0
+
+ ; CHECK-LABEL: name: aext_sextinreg_8
+ ; CHECK: liveins: $w0
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(i32) = COPY $w0
+ ; CHECK-NEXT: [[C:%[0-9]+]]:_(i32) = G_CONSTANT i32 24
+ ; CHECK-NEXT: [[ASHR:%[0-9]+]]:_(i32) = G_ASHR [[COPY]], [[C]](i32)
+ ; CHECK-NEXT: [[ANYEXT:%[0-9]+]]:_(i64) = G_ANYEXT [[ASHR]](i32)
+ ; CHECK-NEXT: [[SEXT_INREG:%[0-9]+]]:_(i64) = G_SEXT_INREG [[ANYEXT]], 8
+ ; CHECK-NEXT: $x0 = COPY [[SEXT_INREG]](i64)
+ %0:_(i32) = COPY $w0
+ %1:_(i32) = G_CONSTANT i32 24
+ %2:_(i32) = G_ASHR %0, %1
+ %3:_(i64) = G_ANYEXT %2
+ %4:_(i64) = G_SEXT_INREG %3, 8
+ $x0 = COPY %4
+...
+---
+name: zext_sextinreg_48
+tracksRegLiveness: true
+legalized: true
+body: |
+ bb.0:
+ liveins: $w0
+
+ ; CHECK-LABEL: name: zext_sextinreg_48
+ ; CHECK: liveins: $w0
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(i32) = COPY $w0
+ ; CHECK-NEXT: [[C:%[0-9]+]]:_(i32) = G_CONSTANT i32 24
+ ; CHECK-NEXT: [[ASHR:%[0-9]+]]:_(i32) = G_ASHR [[COPY]], [[C]](i32)
+ ; CHECK-NEXT: [[ZEXT:%[0-9]+]]:_(i64) = G_ZEXT [[ASHR]](i32)
+ ; CHECK-NEXT: $x0 = COPY [[ZEXT]](i64)
+ %0:_(i32) = COPY $w0
+ %1:_(i32) = G_CONSTANT i32 24
+ %2:_(i32) = G_ASHR %0, %1
+ %3:_(i64) = G_ZEXT %2
+ %4:_(i64) = G_SEXT_INREG %3, 48
+ $x0 = COPY %4
+...
+---
+name: zext_sextinreg_32
+tracksRegLiveness: true
+legalized: true
+body: |
+ bb.0:
+ liveins: $w0
+
+ ; CHECK-LABEL: name: zext_sextinreg_32
+ ; CHECK: liveins: $w0
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[COPY:%[0-9]+]]:_(i32) = COPY $w0
+ ; CHECK-NEXT: [[ZEXT:%[0-9]+]]:_(i64) = G_ZEXT [[COPY]](i32)
+ ; CHECK-NEXT: [[SEXT_INREG:%[0-9]+]]:_(i64) = G_SEXT_INREG [[ZEXT]], 32
+ ; CHECK-NEXT: $x0 = COPY [[SEXT_INREG]](i64)
+ %0:_(i32) = COPY $w0
+ %1:_(i64) = G_ZEXT %0
+ %2:_(i64) = G_SEXT_INREG %1, 32
+ $x0 = COPY %2
+...
>From 8ccb933b766e3c2aaae03aee8c5e3bddfca829a7 Mon Sep 17 00:00:00 2001
From: David Green <david.green at arm.com>
Date: Sun, 2 Aug 2026 18:06:43 +0100
Subject: [PATCH 2/2] [GlobalISel] Add G_SEXT_INREG(G_ZEXT) -> G_SEXT combine.
This converts a G_ZEXT or G_ANYEXT to a G_SEXT if we will G_SEXT_INREG the bits
away.
---
llvm/include/llvm/Target/GlobalISel/Combine.td | 18 ++++++++++++++++--
llvm/lib/Target/AArch64/AArch64Combine.td | 1 +
.../AArch64/GlobalISel/combine-sext-inreg.mir | 15 ++++++---------
llvm/test/CodeGen/AArch64/fcmp.ll | 4 +---
.../CodeGen/AArch64/neon-shift-left-long.ll | 4 +---
llvm/test/CodeGen/AArch64/select_cc.ll | 4 +---
.../AArch64/vec-combine-trunc-dup-ext.ll | 4 +---
.../GlobalISel/artifact-combiner-asserts.ll | 10 ++++------
8 files changed, 31 insertions(+), 29 deletions(-)
diff --git a/llvm/include/llvm/Target/GlobalISel/Combine.td b/llvm/include/llvm/Target/GlobalISel/Combine.td
index 830c48c10a39b..77dc627b5dfdd 100644
--- a/llvm/include/llvm/Target/GlobalISel/Combine.td
+++ b/llvm/include/llvm/Target/GlobalISel/Combine.td
@@ -942,6 +942,20 @@ def redundant_sext_inreg: GICombineRule <
(apply [{ Helper.replaceSingleDefInstWithOperand(*${root}, 1); }])
>;
+// Convert G_SEXT_INREG(G_ZEXT) -> G_SEXT
+class redundant_ext_sext_inreg<Instruction Ext>: GICombineRule <
+ (defs root:$root),
+ (match (Ext $tmp, $src),
+ (G_SEXT_INREG $dst, $tmp, $amt):$root,
+ [{ LLT SrcTy = MRI.getType(${src}.getReg());
+ return ${amt}.getImm() <= SrcTy.getScalarSizeInBits() &&
+ VT->computeNumSignBits(${src}.getReg()) >=
+ (SrcTy.getScalarSizeInBits() - ${amt}.getImm() + 1); }]),
+ (apply (G_SEXT $dst, $src))
+>;
+def redundant_zext_sext_inreg : redundant_ext_sext_inreg<G_ZEXT>;
+def redundant_aext_sext_inreg : redundant_ext_sext_inreg<G_ANYEXT>;
+
// Fold (anyext (trunc x)) -> x if the source type is same as
// the destination type.
def anyext_trunc_fold: GICombineRule <
@@ -2604,8 +2618,8 @@ def const_combines : GICombineGroup<[constant_fold_fp_ops, const_ptradd_to_i2p,
combine_minmax_nan, expand_const_fpowi]>;
def known_bits_simplifications : GICombineGroup<[
- redundant_and, redundant_sext_inreg, redundant_or, urem_pow2_to_mask,
- zext_trunc_fold,
+ redundant_sext_inreg, redundant_zext_sext_inreg, redundant_aext_sext_inreg,
+ redundant_and, redundant_or, urem_pow2_to_mask, zext_trunc_fold,
sext_inreg_to_zext_inreg]>;
def width_reduction_combines : GICombineGroup<[reduce_shl_of_extend,
diff --git a/llvm/lib/Target/AArch64/AArch64Combine.td b/llvm/lib/Target/AArch64/AArch64Combine.td
index 82b9cec960d89..1b2308e4f45e9 100644
--- a/llvm/lib/Target/AArch64/AArch64Combine.td
+++ b/llvm/lib/Target/AArch64/AArch64Combine.td
@@ -395,6 +395,7 @@ def AArch64PostLegalizerCombiner
redundant_and, xor_of_and_with_same_reg,
extractvecelt_pairwise_add, redundant_or,
mul_const, redundant_sext_inreg,
+ redundant_zext_sext_inreg, redundant_aext_sext_inreg,
form_bitfield_extract, rotate_out_of_range,
icmp_to_true_false_known_bits, overflow_combines,
select_combines, select_zero_true, select_zero_false, select_not,
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/combine-sext-inreg.mir b/llvm/test/CodeGen/AArch64/GlobalISel/combine-sext-inreg.mir
index cab4694e71aa5..fcd824a7f6209 100644
--- a/llvm/test/CodeGen/AArch64/GlobalISel/combine-sext-inreg.mir
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/combine-sext-inreg.mir
@@ -63,9 +63,8 @@ body: |
; CHECK-NEXT: [[COPY:%[0-9]+]]:_(i32) = COPY $w0
; CHECK-NEXT: [[C:%[0-9]+]]:_(i32) = G_CONSTANT i32 24
; CHECK-NEXT: [[ASHR:%[0-9]+]]:_(i32) = G_ASHR [[COPY]], [[C]](i32)
- ; CHECK-NEXT: [[ZEXT:%[0-9]+]]:_(i64) = G_ZEXT [[ASHR]](i32)
- ; CHECK-NEXT: [[SEXT_INREG:%[0-9]+]]:_(i64) = G_SEXT_INREG [[ZEXT]], 8
- ; CHECK-NEXT: $x0 = COPY [[SEXT_INREG]](i64)
+ ; CHECK-NEXT: [[SEXT:%[0-9]+]]:_(i64) = G_SEXT [[ASHR]](i32)
+ ; CHECK-NEXT: $x0 = COPY [[SEXT]](i64)
%0:_(i32) = COPY $w0
%1:_(i32) = G_CONSTANT i32 24
%2:_(i32) = G_ASHR %0, %1
@@ -87,9 +86,8 @@ body: |
; CHECK-NEXT: [[COPY:%[0-9]+]]:_(i32) = COPY $w0
; CHECK-NEXT: [[C:%[0-9]+]]:_(i32) = G_CONSTANT i32 24
; CHECK-NEXT: [[ASHR:%[0-9]+]]:_(i32) = G_ASHR [[COPY]], [[C]](i32)
- ; CHECK-NEXT: [[ANYEXT:%[0-9]+]]:_(i64) = G_ANYEXT [[ASHR]](i32)
- ; CHECK-NEXT: [[SEXT_INREG:%[0-9]+]]:_(i64) = G_SEXT_INREG [[ANYEXT]], 8
- ; CHECK-NEXT: $x0 = COPY [[SEXT_INREG]](i64)
+ ; CHECK-NEXT: [[SEXT:%[0-9]+]]:_(i64) = G_SEXT [[ASHR]](i32)
+ ; CHECK-NEXT: $x0 = COPY [[SEXT]](i64)
%0:_(i32) = COPY $w0
%1:_(i32) = G_CONSTANT i32 24
%2:_(i32) = G_ASHR %0, %1
@@ -132,9 +130,8 @@ body: |
; CHECK: liveins: $w0
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: [[COPY:%[0-9]+]]:_(i32) = COPY $w0
- ; CHECK-NEXT: [[ZEXT:%[0-9]+]]:_(i64) = G_ZEXT [[COPY]](i32)
- ; CHECK-NEXT: [[SEXT_INREG:%[0-9]+]]:_(i64) = G_SEXT_INREG [[ZEXT]], 32
- ; CHECK-NEXT: $x0 = COPY [[SEXT_INREG]](i64)
+ ; CHECK-NEXT: [[SEXT:%[0-9]+]]:_(i64) = G_SEXT [[COPY]](i32)
+ ; CHECK-NEXT: $x0 = COPY [[SEXT]](i64)
%0:_(i32) = COPY $w0
%1:_(i64) = G_ZEXT %0
%2:_(i64) = G_SEXT_INREG %1, 32
diff --git a/llvm/test/CodeGen/AArch64/fcmp.ll b/llvm/test/CodeGen/AArch64/fcmp.ll
index cd948f231453e..56d3d0ed7deed 100644
--- a/llvm/test/CodeGen/AArch64/fcmp.ll
+++ b/llvm/test/CodeGen/AArch64/fcmp.ll
@@ -1521,9 +1521,7 @@ define <4 x i32> @v4f16_i32(<4 x half> %a, <4 x half> %b, <4 x i32> %d, <4 x i32
; CHECK-GI-FP16-LABEL: v4f16_i32:
; CHECK-GI-FP16: // %bb.0: // %entry
; CHECK-GI-FP16-NEXT: fcmgt v0.4h, v1.4h, v0.4h
-; CHECK-GI-FP16-NEXT: ushll v0.4s, v0.4h, #0
-; CHECK-GI-FP16-NEXT: shl v0.4s, v0.4s, #31
-; CHECK-GI-FP16-NEXT: cmlt v0.4s, v0.4s, #0
+; CHECK-GI-FP16-NEXT: sshll v0.4s, v0.4h, #0
; CHECK-GI-FP16-NEXT: bsl v0.16b, v2.16b, v3.16b
; CHECK-GI-FP16-NEXT: ret
entry:
diff --git a/llvm/test/CodeGen/AArch64/neon-shift-left-long.ll b/llvm/test/CodeGen/AArch64/neon-shift-left-long.ll
index a8c55b476b810..2a514633cd851 100644
--- a/llvm/test/CodeGen/AArch64/neon-shift-left-long.ll
+++ b/llvm/test/CodeGen/AArch64/neon-shift-left-long.ll
@@ -463,9 +463,7 @@ define <8 x i16> @test_ushll_cmp(<8 x i8> %a, <8 x i8> %b) #0 {
; CHECK-GI: // %bb.0:
; CHECK-GI-NEXT: cmeq v0.8b, v0.8b, v1.8b
; CHECK-GI-NEXT: movi v1.2d, #0xff00ff00ff00ff
-; CHECK-GI-NEXT: ushll v0.8h, v0.8b, #0
-; CHECK-GI-NEXT: shl v0.8h, v0.8h, #15
-; CHECK-GI-NEXT: cmlt v0.8h, v0.8h, #0
+; CHECK-GI-NEXT: sshll v0.8h, v0.8b, #0
; CHECK-GI-NEXT: and v0.16b, v0.16b, v1.16b
; CHECK-GI-NEXT: ret
%cmp.i = icmp eq <8 x i8> %a, %b
diff --git a/llvm/test/CodeGen/AArch64/select_cc.ll b/llvm/test/CodeGen/AArch64/select_cc.ll
index a21307b555810..9d243ec724dd8 100644
--- a/llvm/test/CodeGen/AArch64/select_cc.ll
+++ b/llvm/test/CodeGen/AArch64/select_cc.ll
@@ -96,9 +96,7 @@ define <2 x double> @select_olt_load_cmp(<2 x double> %a, ptr %src) {
; CHECK-GI-NEXT: ldr d1, [x0]
; CHECK-GI-NEXT: movi v2.2d, #0000000000000000
; CHECK-GI-NEXT: fcmgt v1.2s, v1.2s, #0.0
-; CHECK-GI-NEXT: ushll v1.2d, v1.2s, #0
-; CHECK-GI-NEXT: shl v1.2d, v1.2d, #63
-; CHECK-GI-NEXT: cmlt v1.2d, v1.2d, #0
+; CHECK-GI-NEXT: sshll v1.2d, v1.2s, #0
; CHECK-GI-NEXT: bif v0.16b, v2.16b, v1.16b
; CHECK-GI-NEXT: ret
entry:
diff --git a/llvm/test/CodeGen/AArch64/vec-combine-trunc-dup-ext.ll b/llvm/test/CodeGen/AArch64/vec-combine-trunc-dup-ext.ll
index 01e545eb6bc7b..ac71e888cccb8 100644
--- a/llvm/test/CodeGen/AArch64/vec-combine-trunc-dup-ext.ll
+++ b/llvm/test/CodeGen/AArch64/vec-combine-trunc-dup-ext.ll
@@ -183,9 +183,7 @@ define <8 x i16> @dup_trunc_sext_v8i16(<8 x i16> %a, <8 x i16> %b, <8 x i16> %x,
; CHECK-GI-NEXT: cmgt v0.8h, v1.8h, v0.8h
; CHECK-GI-NEXT: xtn v0.8b, v0.8h
; CHECK-GI-NEXT: dup v0.8b, v0.b[2]
-; CHECK-GI-NEXT: ushll v0.8h, v0.8b, #0
-; CHECK-GI-NEXT: shl v0.8h, v0.8h, #15
-; CHECK-GI-NEXT: cmlt v0.8h, v0.8h, #0
+; CHECK-GI-NEXT: sshll v0.8h, v0.8b, #0
; CHECK-GI-NEXT: bsl v0.16b, v2.16b, v3.16b
; CHECK-GI-NEXT: ret
%cmp = icmp slt <8 x i16> %a, %b
diff --git a/llvm/test/CodeGen/AMDGPU/GlobalISel/artifact-combiner-asserts.ll b/llvm/test/CodeGen/AMDGPU/GlobalISel/artifact-combiner-asserts.ll
index 7fccbd78cec9c..40420b8da5ca4 100644
--- a/llvm/test/CodeGen/AMDGPU/GlobalISel/artifact-combiner-asserts.ll
+++ b/llvm/test/CodeGen/AMDGPU/GlobalISel/artifact-combiner-asserts.ll
@@ -6,13 +6,11 @@ define hidden <2 x i64> @icmp_v2i32_sext_to_v2i64(<2 x i32> %arg) {
; CHECK: ; %bb.0:
; CHECK-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
; CHECK-NEXT: v_cmp_eq_u32_e32 vcc_lo, 0, v0
-; CHECK-NEXT: v_cndmask_b32_e64 v0, 0, 1, vcc_lo
+; CHECK-NEXT: v_cndmask_b32_e64 v0, 0, -1, vcc_lo
; CHECK-NEXT: v_cmp_eq_u32_e32 vcc_lo, 0, v1
-; CHECK-NEXT: v_bfe_i32 v0, v0, 0, 1
-; CHECK-NEXT: v_cndmask_b32_e64 v1, 0, 1, vcc_lo
-; CHECK-NEXT: v_bfe_i32 v2, v1, 0, 1
-; CHECK-NEXT: v_ashrrev_i32_e32 v1, 31, v0
-; CHECK-NEXT: v_ashrrev_i32_e32 v3, 31, v2
+; CHECK-NEXT: v_mov_b32_e32 v1, v0
+; CHECK-NEXT: v_cndmask_b32_e64 v2, 0, -1, vcc_lo
+; CHECK-NEXT: v_mov_b32_e32 v3, v2
; CHECK-NEXT: s_setpc_b64 s[30:31]
%cmp = icmp eq <2 x i32> %arg, zeroinitializer
%sext = sext <2 x i1> %cmp to <2 x i64>
More information about the llvm-commits
mailing list