[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