[llvm] [GlobalISel] Use G_ANYEXT instead of G_ZEXT for shift amount widening (PR #223136)
Deepak Shirke via llvm-commits
llvm-commits at lists.llvm.org
Sat Sep 12 03:57:19 PDT 2026
https://github.com/deepakshirkem created https://github.com/llvm/llvm-project/pull/223136
When widening the shift amount type for G_SHL, G_LSHR, and G_ASHR, use G_ANYEXT instead of G_ZEXT. The shift amount is undefined behavior for values >= the type width, so the high bits do not need to be zeroed. Using G_ANYEXT avoids generating a redundant AND instruction.
Before (GlobalISel shl i8):
and w8, w1, #0xff
lsl w0, w0, w8
After (GlobalISel shl i8, matches SelectionDAG):
lsl w0, w0, w1
CC: @davemgreen @arsenm
>From ac299764d0630a020bb2237c2606b9b0e055938c Mon Sep 17 00:00:00 2001
From: deepakshirkem <deepakshirke509 at gmail.com>
Date: Sat, 12 Sep 2026 16:25:00 +0530
Subject: [PATCH] [GlobalISel] Use G_ANYEXT instead of G_ZEXT for shift amount
widening
When widening the shift amount type for G_SHL, G_LSHR, and G_ASHR,
use G_ANYEXT instead of G_ZEXT. The shift amount is undefined behavior
for values >= the type width, so we don't need to zero-extend it.
Using G_ANYEXT avoids generating a redundant AND instruction.
Before (GlobalISel):
and w8, w1, #0xff
lsl w0, w0, w8
After (GlobalISel, matches SelectionDAG):
lsl w0, w0, w1
---
.../CodeGen/GlobalISel/LegalizerHelper.cpp | 14 ++-
.../AArch64/GlobalISel/shift-amount-anyext.ll | 34 ++++++
llvm/test/CodeGen/AArch64/shift.ll | 107 ++++++------------
3 files changed, 74 insertions(+), 81 deletions(-)
create mode 100644 llvm/test/CodeGen/AArch64/GlobalISel/shift-amount-anyext.ll
diff --git a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
index a109d984c3e25..3533f550150a0 100644
--- a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
@@ -3044,9 +3044,10 @@ LegalizerHelper::widenScalar(MachineInstr &MI, unsigned TypeIdx, LLT WideTy) {
widenScalarDst(MI, WideTy);
} else {
assert(TypeIdx == 1);
- // The "number of bits to shift" operand must preserve its value as an
- // unsigned integer:
- widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ZEXT);
+ // The shift amount is undefined behavior for values >= type width,
+ // so we can use G_ANYEXT instead of G_ZEXT to avoid generating
+ // a redundant AND instruction.
+ widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ANYEXT);
}
Observer.changedInstr(MI);
@@ -3096,9 +3097,10 @@ LegalizerHelper::widenScalar(MachineInstr &MI, unsigned TypeIdx, LLT WideTy) {
widenScalarDst(MI, WideTy);
} else {
assert(TypeIdx == 1);
- // The "number of bits to shift" operand must preserve its value as an
- // unsigned integer:
- widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ZEXT);
+ // The shift amount is undefined behavior for values >= type width,
+ // so we can use G_ANYEXT instead of G_ZEXT to avoid generating
+ // a redundant AND instruction.
+ widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ANYEXT);
}
Observer.changedInstr(MI);
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/shift-amount-anyext.ll b/llvm/test/CodeGen/AArch64/GlobalISel/shift-amount-anyext.ll
new file mode 100644
index 0000000000000..363957a6c2b62
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/shift-amount-anyext.ll
@@ -0,0 +1,34 @@
+; RUN: llc -mtriple=aarch64 -global-isel -verify-machineinstrs %s -o - | FileCheck %s
+
+; Check that shift amount is not masked with AND for small types
+; GlobalISel should match SelectionDAG behavior
+
+; CHECK-LABEL: shl_i8
+; CHECK: lsl w0, w0, w1
+; CHECK-NOT: and
+define i8 @shl_i8(i8 %a, i8 %b) {
+ %r = shl i8 %a, %b
+ ret i8 %r
+}
+
+; CHECK-LABEL: shl_i16
+; CHECK: lsl w0, w0, w1
+; CHECK-NOT: and
+define i16 @shl_i16(i16 %a, i16 %b) {
+ %r = shl i16 %a, %b
+ ret i16 %r
+}
+
+; CHECK-LABEL: lshr_i8
+; CHECK-NOT: and w{{[0-9]+}}, w1
+define i8 @lshr_i8(i8 %a, i8 %b) {
+ %r = lshr i8 %a, %b
+ ret i8 %r
+}
+
+; CHECK-LABEL: ashr_i8
+; CHECK-NOT: and w{{[0-9]+}}, w1
+define i8 @ashr_i8(i8 %a, i8 %b) {
+ %r = ashr i8 %a, %b
+ ret i8 %r
+}
diff --git a/llvm/test/CodeGen/AArch64/shift.ll b/llvm/test/CodeGen/AArch64/shift.ll
index 5d7935474c903..1fb0377e00fc4 100644
--- a/llvm/test/CodeGen/AArch64/shift.ll
+++ b/llvm/test/CodeGen/AArch64/shift.ll
@@ -10,8 +10,7 @@ define i1 @shl_i1(i1 %0, i1 %1){
;
; CHECK-GI-LABEL: shl_i1:
; CHECK-GI: // %bb.0:
-; CHECK-GI-NEXT: and w8, w1, #0x1
-; CHECK-GI-NEXT: lsl w8, w0, w8
+; CHECK-GI-NEXT: lsl w8, w0, w1
; CHECK-GI-NEXT: and w0, w8, #0x1
; CHECK-GI-NEXT: ret
%3 = shl i1 %0, %1
@@ -19,31 +18,19 @@ define i1 @shl_i1(i1 %0, i1 %1){
}
define i8 @shl_i8(i8 %0, i8 %1){
-; CHECK-SD-LABEL: shl_i8:
-; CHECK-SD: // %bb.0:
-; CHECK-SD-NEXT: lsl w0, w0, w1
-; CHECK-SD-NEXT: ret
-;
-; CHECK-GI-LABEL: shl_i8:
-; CHECK-GI: // %bb.0:
-; CHECK-GI-NEXT: and w8, w1, #0xff
-; CHECK-GI-NEXT: lsl w0, w0, w8
-; CHECK-GI-NEXT: ret
+; CHECK-LABEL: shl_i8:
+; CHECK: // %bb.0:
+; CHECK-NEXT: lsl w0, w0, w1
+; CHECK-NEXT: ret
%3 = shl i8 %0, %1
ret i8 %3
}
define i16 @shl_i16(i16 %0, i16 %1){
-; CHECK-SD-LABEL: shl_i16:
-; CHECK-SD: // %bb.0:
-; CHECK-SD-NEXT: lsl w0, w0, w1
-; CHECK-SD-NEXT: ret
-;
-; CHECK-GI-LABEL: shl_i16:
-; CHECK-GI: // %bb.0:
-; CHECK-GI-NEXT: and w8, w1, #0xffff
-; CHECK-GI-NEXT: lsl w0, w0, w8
-; CHECK-GI-NEXT: ret
+; CHECK-LABEL: shl_i16:
+; CHECK: // %bb.0:
+; CHECK-NEXT: lsl w0, w0, w1
+; CHECK-NEXT: ret
%3 = shl i16 %0, %1
ret i16 %3
}
@@ -109,8 +96,7 @@ define i1 @ashr_i1(i1 %0, i1 %1){
; CHECK-GI-LABEL: ashr_i1:
; CHECK-GI: // %bb.0:
; CHECK-GI-NEXT: sbfx w8, w0, #0, #1
-; CHECK-GI-NEXT: and w9, w1, #0x1
-; CHECK-GI-NEXT: asr w8, w8, w9
+; CHECK-GI-NEXT: asr w8, w8, w1
; CHECK-GI-NEXT: and w0, w8, #0x1
; CHECK-GI-NEXT: ret
%3 = ashr i1 %0, %1
@@ -118,35 +104,21 @@ define i1 @ashr_i1(i1 %0, i1 %1){
}
define i8 @ashr_i8(i8 %0, i8 %1){
-; CHECK-SD-LABEL: ashr_i8:
-; CHECK-SD: // %bb.0:
-; CHECK-SD-NEXT: sxtb w8, w0
-; CHECK-SD-NEXT: asr w0, w8, w1
-; CHECK-SD-NEXT: ret
-;
-; CHECK-GI-LABEL: ashr_i8:
-; CHECK-GI: // %bb.0:
-; CHECK-GI-NEXT: sxtb w8, w0
-; CHECK-GI-NEXT: and w9, w1, #0xff
-; CHECK-GI-NEXT: asr w0, w8, w9
-; CHECK-GI-NEXT: ret
+; CHECK-LABEL: ashr_i8:
+; CHECK: // %bb.0:
+; CHECK-NEXT: sxtb w8, w0
+; CHECK-NEXT: asr w0, w8, w1
+; CHECK-NEXT: ret
%3 = ashr i8 %0, %1
ret i8 %3
}
define i16 @ashr_i16(i16 %0, i16 %1){
-; CHECK-SD-LABEL: ashr_i16:
-; CHECK-SD: // %bb.0:
-; CHECK-SD-NEXT: sxth w8, w0
-; CHECK-SD-NEXT: asr w0, w8, w1
-; CHECK-SD-NEXT: ret
-;
-; CHECK-GI-LABEL: ashr_i16:
-; CHECK-GI: // %bb.0:
-; CHECK-GI-NEXT: sxth w8, w0
-; CHECK-GI-NEXT: and w9, w1, #0xffff
-; CHECK-GI-NEXT: asr w0, w8, w9
-; CHECK-GI-NEXT: ret
+; CHECK-LABEL: ashr_i16:
+; CHECK: // %bb.0:
+; CHECK-NEXT: sxth w8, w0
+; CHECK-NEXT: asr w0, w8, w1
+; CHECK-NEXT: ret
%3 = ashr i16 %0, %1
ret i16 %3
}
@@ -214,44 +186,29 @@ define i1 @lshr_i1(i1 %0, i1 %1){
;
; CHECK-GI-LABEL: lshr_i1:
; CHECK-GI: // %bb.0:
-; CHECK-GI-NEXT: and w8, w1, #0x1
-; CHECK-GI-NEXT: and w9, w0, #0x1
-; CHECK-GI-NEXT: lsr w0, w9, w8
+; CHECK-GI-NEXT: and w8, w0, #0x1
+; CHECK-GI-NEXT: lsr w0, w8, w1
; CHECK-GI-NEXT: ret
%3 = lshr i1 %0, %1
ret i1 %3
}
define i8 @lshr_i8(i8 %0, i8 %1){
-; CHECK-SD-LABEL: lshr_i8:
-; CHECK-SD: // %bb.0:
-; CHECK-SD-NEXT: and w8, w0, #0xff
-; CHECK-SD-NEXT: lsr w0, w8, w1
-; CHECK-SD-NEXT: ret
-;
-; CHECK-GI-LABEL: lshr_i8:
-; CHECK-GI: // %bb.0:
-; CHECK-GI-NEXT: and w8, w1, #0xff
-; CHECK-GI-NEXT: and w9, w0, #0xff
-; CHECK-GI-NEXT: lsr w0, w9, w8
-; CHECK-GI-NEXT: ret
+; CHECK-LABEL: lshr_i8:
+; CHECK: // %bb.0:
+; CHECK-NEXT: and w8, w0, #0xff
+; CHECK-NEXT: lsr w0, w8, w1
+; CHECK-NEXT: ret
%3 = lshr i8 %0, %1
ret i8 %3
}
define i16 @lshr_i16(i16 %0, i16 %1){
-; CHECK-SD-LABEL: lshr_i16:
-; CHECK-SD: // %bb.0:
-; CHECK-SD-NEXT: and w8, w0, #0xffff
-; CHECK-SD-NEXT: lsr w0, w8, w1
-; CHECK-SD-NEXT: ret
-;
-; CHECK-GI-LABEL: lshr_i16:
-; CHECK-GI: // %bb.0:
-; CHECK-GI-NEXT: and w8, w1, #0xffff
-; CHECK-GI-NEXT: and w9, w0, #0xffff
-; CHECK-GI-NEXT: lsr w0, w9, w8
-; CHECK-GI-NEXT: ret
+; CHECK-LABEL: lshr_i16:
+; CHECK: // %bb.0:
+; CHECK-NEXT: and w8, w0, #0xffff
+; CHECK-NEXT: lsr w0, w8, w1
+; CHECK-NEXT: ret
%3 = lshr i16 %0, %1
ret i16 %3
}
More information about the llvm-commits
mailing list