[llvm] [GlobalISel] [AArch64] Skip redundant shift amount masking during isel (PR #223136)
Deepak Shirke via llvm-commits
llvm-commits at lists.llvm.org
Wed Sep 16 13:54:46 PDT 2026
https://github.com/deepakshirkem updated https://github.com/llvm/llvm-project/pull/223136
>From 962a994fa4cce73105b6f8fc798ee5ced0611469 Mon Sep 17 00:00:00 2001
From: deepakshirkem <deepakshirke509 at gmail.com>
Date: Mon, 14 Sep 2026 18:14:17 +0530
Subject: [PATCH] AArch64: Skip redundant shift amount masking using isel
ComplexPattern
AArch64 shift instructions (LSL/LSR/ASR) only use the low 5 bits (i32)
or 6 bits (i64) of the shift amount. Add SelectShiftMask ComplexPattern
and GIComplexOperandMatcher that strip redundant AND masks or zero-extensions
from shift amounts during instruction selection, when the mask exactly
covers a narrow type (byte, halfword, or word).
This mirrors what AArch64DAGToDAGISel::tryShiftAmountMod does, and adds
equivalent GlobalISel support via GIComplexPatternEquiv.
---
.../Target/AArch64/AArch64ISelDAGToDAG.cpp | 22 +++
.../lib/Target/AArch64/AArch64InstrFormats.td | 15 ++
llvm/lib/Target/AArch64/AArch64InstrInfo.td | 5 +
.../GISel/AArch64InstructionSelector.cpp | 57 ++++++++
.../AArch64/GlobalISel/shift-amount-mod.ll | 79 +++++++++++
llvm/test/CodeGen/AArch64/extract-bits.ll | 42 +++---
llvm/test/CodeGen/AArch64/extract-lowbits.ll | 20 +--
llvm/test/CodeGen/AArch64/frem-power2.ll | 6 +-
llvm/test/CodeGen/AArch64/fsh.ll | 37 ++---
llvm/test/CodeGen/AArch64/funnel-shift.ll | 130 +++++++-----------
...st-and-by-const-from-lshr-in-eqcmp-zero.ll | 47 ++-----
...ist-and-by-const-from-shl-in-eqcmp-zero.ll | 24 ++--
llvm/test/CodeGen/AArch64/select_const.ll | 3 -
llvm/test/CodeGen/AArch64/shift-mod.ll | 84 ++++++++++-
llvm/test/CodeGen/AArch64/shift.ll | 96 ++++---------
15 files changed, 402 insertions(+), 265 deletions(-)
create mode 100644 llvm/test/CodeGen/AArch64/GlobalISel/shift-amount-mod.ll
diff --git a/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp b/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp
index 531478517ef9a..73d3e3dee1dd3 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp
@@ -89,6 +89,9 @@ class AArch64DAGToDAGISel : public SelectionDAGISel {
bool SelectLogicalShiftedRegister(SDValue N, SDValue &Reg, SDValue &Shift) {
return SelectShiftedRegister(N, true, Reg, Shift);
}
+ template <unsigned ShiftWidth>
+ bool SelectShiftMask(SDValue N, SDValue &ShAmt);
+
bool SelectAddrModeIndexed7S8(SDValue N, SDValue &Base, SDValue &OffImm) {
return SelectAddrModeIndexed7S(N, 1, Base, OffImm);
}
@@ -762,6 +765,25 @@ bool AArch64DAGToDAGISel::SelectInlineAsmMemoryOperand(
return true;
}
+template <unsigned ShiftWidth>
+bool AArch64DAGToDAGISel::SelectShiftMask(SDValue N, SDValue &ShAmt) {
+ // AArch64 shift instructions only use the low log2(ShiftWidth) bits of the
+ // shift amount. If the shift amount has a redundant AND mask that exactly
+ // covers a narrow type, we can remove it.
+ // Note: do not strip ZERO_EXTEND/ANY_EXTEND here as that can cause
+ // register class mismatches (e.g. returning a 32-bit value for an i64 shift).
+ if (N.getOpcode() == ISD::AND && isa<ConstantSDNode>(N.getOperand(1)) &&
+ N.getValueType() == (ShiftWidth == 32 ? MVT::i32 : MVT::i64)) {
+ uint64_t Mask = N.getConstantOperandVal(1);
+ // Only remove AND if it exactly masks a narrow type (byte, halfword, word).
+ if (Mask == 0xff || Mask == 0xffff || Mask == 0xffffffff)
+ N = N.getOperand(0);
+ }
+
+ ShAmt = N;
+ return true;
+}
+
/// SelectArithImmed - Select an immediate value that can be represented as
/// a 12-bit value shifted left by either 0 or 12. If so, return true with
/// Val set to the 12-bit value and Shift set to the shifter operand.
diff --git a/llvm/lib/Target/AArch64/AArch64InstrFormats.td b/llvm/lib/Target/AArch64/AArch64InstrFormats.td
index 68c80f5d112ae..125838469ea0d 100644
--- a/llvm/lib/Target/AArch64/AArch64InstrFormats.td
+++ b/llvm/lib/Target/AArch64/AArch64InstrFormats.td
@@ -2749,6 +2749,16 @@ class BaseShift<bit size, bits<2> shift_type, RegisterClass regtype, string asm,
let Inst{11-10} = shift_type;
}
+// ComplexPattern to match shift amounts with redundant AND masks.
+// AArch64 shift instructions only use the low 5 bits (i32) or 6 bits (i64),
+// so AND masks that exactly cover a narrow type are redundant.
+def shiftMask32 : ComplexPattern<i32, 1, "SelectShiftMask<32>", [], [], 0>;
+def gi_shift_mask32 : GIComplexOperandMatcher<s32, "selectShiftMask32">,
+ GIComplexPatternEquiv<shiftMask32>;
+def shiftMask64 : ComplexPattern<i64, 1, "SelectShiftMask<64>", [], [], 0>;
+def gi_shift_mask64 : GIComplexOperandMatcher<s64, "selectShiftMask64">,
+ GIComplexPatternEquiv<shiftMask64>;
+
multiclass Shift<bits<2> shift_type, string asm, SDNode OpNode> {
def Wr : BaseShift<0b0, shift_type, GPR32, asm>;
@@ -2774,6 +2784,11 @@ multiclass Shift<bits<2> shift_type, string asm, SDNode OpNode> {
def : Pat<(i64 (OpNode GPR64:$Rn, (i64 (zext GPR32:$Rm)))),
(!cast<Instruction>(NAME # "Xr") GPR64:$Rn,
(SUBREG_TO_REG GPR32:$Rm, sub_32))>;
+
+ def : Pat<(i32 (OpNode GPR32:$Rn, shiftMask32:$Rm)),
+ (!cast<Instruction>(NAME # "Wr") GPR32:$Rn, shiftMask32:$Rm)>;
+ def : Pat<(i64 (OpNode GPR64:$Rn, shiftMask64:$Rm)),
+ (!cast<Instruction>(NAME # "Xr") GPR64:$Rn, shiftMask64:$Rm)>;
}
class ShiftAlias<string asm, Instruction inst, RegisterClass regtype>
diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.td b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
index ac2f9b16ca229..b2ab0826e5852 100644
--- a/llvm/lib/Target/AArch64/AArch64InstrInfo.td
+++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
@@ -2967,6 +2967,11 @@ def : ShiftAlias<"lsrv", LSRVXr, GPR64>;
def : ShiftAlias<"rorv", RORVWr, GPR32>;
def : ShiftAlias<"rorv", RORVXr, GPR64>;
+// ComplexPattern to match shift amounts with redundant AND masks.
+// AArch64 shift instructions only use the low 5 bits (i32) or 6 bits (i64),
+// so AND masks that cover those bits are redundant.
+
+
// Multiply-add
let AddedComplexity = 5 in {
defm MADD : MulAccum<0, "madd">;
diff --git a/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp b/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp
index 0499d7771683e..b95ae5c0ead69 100644
--- a/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp
+++ b/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp
@@ -385,6 +385,8 @@ class AArch64InstructionSelector : public InstructionSelector {
ComplexRendererFns selectShiftA_64(const MachineOperand &Root) const;
ComplexRendererFns selectShiftB_64(const MachineOperand &Root) const;
+ ComplexRendererFns selectShiftMask32(MachineOperand &Root) const;
+ ComplexRendererFns selectShiftMask64(MachineOperand &Root) const;
ComplexRendererFns select12BitValueWithLeftShift(uint64_t Immed) const;
ComplexRendererFns selectArithImmed(MachineOperand &Root) const;
ComplexRendererFns selectNegArithImmed(MachineOperand &Root) const;
@@ -7302,6 +7304,61 @@ AArch64InstructionSelector::selectShiftB_64(const MachineOperand &Root) const {
return {{[=](MachineInstrBuilder &MIB) { MIB.addImm(Enc); }}};
}
+InstructionSelector::ComplexRendererFns
+AArch64InstructionSelector::selectShiftMask32(MachineOperand &Root) const {
+ if (!Root.isReg())
+ return std::nullopt;
+
+ MachineRegisterInfo &MRI =
+ Root.getParent()->getParent()->getParent()->getRegInfo();
+
+ Register ShAmtReg = Root.getReg();
+
+ // Peek through zext.
+ Register ZExtSrcReg;
+ if (mi_match(ShAmtReg, MRI, m_GZExt(m_Reg(ZExtSrcReg))))
+ ShAmtReg = ZExtSrcReg;
+
+ // Remove redundant AND mask. AArch64 i32 shift instructions only use
+ // the low 5 bits of the shift amount, so an AND that covers those bits
+ // is redundant.
+ APInt AndMask;
+ Register AndSrcReg;
+ if (mi_match(ShAmtReg, MRI, m_GAnd(m_Reg(AndSrcReg), m_ICst(AndMask)))) {
+ APInt ShMask(AndMask.getBitWidth(), 31);
+ if (ShMask.isSubsetOf(AndMask))
+ ShAmtReg = AndSrcReg;
+ }
+
+ return {{[=](MachineInstrBuilder &MIB) { MIB.addReg(ShAmtReg); }}};
+}
+
+InstructionSelector::ComplexRendererFns
+AArch64InstructionSelector::selectShiftMask64(MachineOperand &Root) const {
+ if (!Root.isReg())
+ return std::nullopt;
+
+ MachineRegisterInfo &MRI =
+ Root.getParent()->getParent()->getParent()->getRegInfo();
+
+ Register ShAmtReg = Root.getReg();
+
+ // Remove redundant AND mask introduced by legalization of a narrow zext.
+ // Only remove if the mask exactly covers a byte, halfword, or word,
+ // and the source register is already 64-bit to avoid register class
+ // mismatches.
+ APInt AndMask;
+ Register AndSrcReg;
+ if (mi_match(ShAmtReg, MRI, m_GAnd(m_Reg(AndSrcReg), m_ICst(AndMask)))) {
+ uint64_t UMask = AndMask.getZExtValue();
+ if ((UMask == 0xff || UMask == 0xffff || UMask == 0xffffffff) &&
+ MRI.getType(AndSrcReg).getSizeInBits() == 64)
+ ShAmtReg = AndSrcReg;
+ }
+
+ return {{[=](MachineInstrBuilder &MIB) { MIB.addReg(ShAmtReg); }}};
+}
+
/// Helper to select an immediate value that can be represented as a 12-bit
/// value shifted left by either 0 or 12. If it is possible to do so, return
/// the immediate and shift value. If not, return std::nullopt.
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/shift-amount-mod.ll b/llvm/test/CodeGen/AArch64/GlobalISel/shift-amount-mod.ll
new file mode 100644
index 0000000000000..75fd645e0cdf9
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/shift-amount-mod.ll
@@ -0,0 +1,79 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc -global-isel -mtriple=aarch64 < %s | FileCheck %s --check-prefixes=CHECK,GI
+; RUN: llc -global-isel=0 -mtriple=aarch64 < %s | FileCheck %s --check-prefixes=CHECK,SD
+
+define i32 @shl_i32_i8(i32 %x, i8 %amt) {
+; CHECK-LABEL: shl_i32_i8:
+; CHECK: // %bb.0:
+; CHECK-NEXT: lsl w0, w0, w1
+; CHECK-NEXT: ret
+ %ext = zext i8 %amt to i32
+ %r = shl i32 %x, %ext
+ ret i32 %r
+}
+
+define i32 @lshr_i32_i8(i32 %x, i8 %amt) {
+; CHECK-LABEL: lshr_i32_i8:
+; CHECK: // %bb.0:
+; CHECK-NEXT: lsr w0, w0, w1
+; CHECK-NEXT: ret
+ %ext = zext i8 %amt to i32
+ %r = lshr i32 %x, %ext
+ ret i32 %r
+}
+
+define i32 @ashr_i32_i8(i32 %x, i8 %amt) {
+; CHECK-LABEL: ashr_i32_i8:
+; CHECK: // %bb.0:
+; CHECK-NEXT: asr w0, w0, w1
+; CHECK-NEXT: ret
+ %ext = zext i8 %amt to i32
+ %r = ashr i32 %x, %ext
+ ret i32 %r
+}
+
+define i32 @shl_i32_i16(i32 %x, i16 %amt) {
+; CHECK-LABEL: shl_i32_i16:
+; CHECK: // %bb.0:
+; CHECK-NEXT: lsl w0, w0, w1
+; CHECK-NEXT: ret
+ %ext = zext i16 %amt to i32
+ %r = shl i32 %x, %ext
+ ret i32 %r
+}
+
+define i64 @shl_i64_i8(i64 %x, i8 %amt) {
+; CHECK-LABEL: shl_i64_i8:
+; CHECK: // %bb.0:
+; CHECK-NEXT: // kill: def $w1 killed $w1 def $x1
+; CHECK-NEXT: lsl x0, x0, x1
+; CHECK-NEXT: ret
+ %ext = zext i8 %amt to i64
+ %r = shl i64 %x, %ext
+ ret i64 %r
+}
+
+define i64 @lshr_i64_i8(i64 %x, i8 %amt) {
+; CHECK-LABEL: lshr_i64_i8:
+; CHECK: // %bb.0:
+; CHECK-NEXT: // kill: def $w1 killed $w1 def $x1
+; CHECK-NEXT: lsr x0, x0, x1
+; CHECK-NEXT: ret
+ %ext = zext i8 %amt to i64
+ %r = lshr i64 %x, %ext
+ ret i64 %r
+}
+
+define i64 @ashr_i64_i16(i64 %x, i16 %amt) {
+; CHECK-LABEL: ashr_i64_i16:
+; CHECK: // %bb.0:
+; CHECK-NEXT: // kill: def $w1 killed $w1 def $x1
+; CHECK-NEXT: asr x0, x0, x1
+; CHECK-NEXT: ret
+ %ext = zext i16 %amt to i64
+ %r = ashr i64 %x, %ext
+ ret i64 %r
+}
+;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
+; GI: {{.*}}
+; SD: {{.*}}
diff --git a/llvm/test/CodeGen/AArch64/extract-bits.ll b/llvm/test/CodeGen/AArch64/extract-bits.ll
index 5a96116142b51..5d9cfe9be48b6 100644
--- a/llvm/test/CodeGen/AArch64/extract-bits.ll
+++ b/llvm/test/CodeGen/AArch64/extract-bits.ll
@@ -159,11 +159,11 @@ define i64 @bextr64_a0_arithmetic(i64 %val, i64 %numskipbits, i64 %numlowbits) n
define i64 @bextr64_a1_indexzext(i64 %val, i8 zeroext %numskipbits, i8 zeroext %numlowbits) nounwind {
; CHECK-LABEL: bextr64_a1_indexzext:
; CHECK: // %bb.0:
-; CHECK-NEXT: mov w8, #1 // =0x1
-; CHECK-NEXT: // kill: def $w2 killed $w2 def $x2
-; CHECK-NEXT: // kill: def $w1 killed $w1 def $x1
-; CHECK-NEXT: lsr x9, x0, x1
-; CHECK-NEXT: lsl x8, x8, x2
+; CHECK-NEXT: mov w8, w2
+; CHECK-NEXT: mov w9, #1 // =0x1
+; CHECK-NEXT: mov w10, w1
+; CHECK-NEXT: lsl x8, x9, x8
+; CHECK-NEXT: lsr x9, x0, x10
; CHECK-NEXT: sub x8, x8, #1
; CHECK-NEXT: and x0, x8, x9
; CHECK-NEXT: ret
@@ -198,11 +198,11 @@ define i64 @bextr64_a3_load_indexzext(ptr %w, i8 zeroext %numskipbits, i8 zeroex
; CHECK-LABEL: bextr64_a3_load_indexzext:
; CHECK: // %bb.0:
; CHECK-NEXT: ldr x8, [x0]
-; CHECK-NEXT: mov w9, #1 // =0x1
-; CHECK-NEXT: // kill: def $w2 killed $w2 def $x2
-; CHECK-NEXT: // kill: def $w1 killed $w1 def $x1
-; CHECK-NEXT: lsl x9, x9, x2
-; CHECK-NEXT: lsr x8, x8, x1
+; CHECK-NEXT: mov w9, w2
+; CHECK-NEXT: mov w10, #1 // =0x1
+; CHECK-NEXT: mov w11, w1
+; CHECK-NEXT: lsl x9, x10, x9
+; CHECK-NEXT: lsr x8, x8, x11
; CHECK-NEXT: sub x9, x9, #1
; CHECK-NEXT: and x0, x9, x8
; CHECK-NEXT: ret
@@ -397,12 +397,12 @@ define i64 @bextr64_b0(i64 %val, i64 %numskipbits, i64 %numlowbits) nounwind {
define i64 @bextr64_b1_indexzext(i64 %val, i8 zeroext %numskipbits, i8 zeroext %numlowbits) nounwind {
; CHECK-LABEL: bextr64_b1_indexzext:
; CHECK: // %bb.0:
-; CHECK-NEXT: mov x8, #-1 // =0xffffffffffffffff
-; CHECK-NEXT: // kill: def $w2 killed $w2 def $x2
-; CHECK-NEXT: // kill: def $w1 killed $w1 def $x1
-; CHECK-NEXT: lsr x9, x0, x1
-; CHECK-NEXT: lsl x8, x8, x2
-; CHECK-NEXT: bic x0, x9, x8
+; CHECK-NEXT: mov w8, w1
+; CHECK-NEXT: mov w9, w2
+; CHECK-NEXT: mov x10, #-1 // =0xffffffffffffffff
+; CHECK-NEXT: lsr x8, x0, x8
+; CHECK-NEXT: lsl x9, x10, x9
+; CHECK-NEXT: bic x0, x8, x9
; CHECK-NEXT: ret
%skip = zext i8 %numskipbits to i64
%shifted = lshr i64 %val, %skip
@@ -434,11 +434,11 @@ define i64 @bextr64_b3_load_indexzext(ptr %w, i8 zeroext %numskipbits, i8 zeroex
; CHECK-LABEL: bextr64_b3_load_indexzext:
; CHECK: // %bb.0:
; CHECK-NEXT: ldr x8, [x0]
-; CHECK-NEXT: mov x9, #-1 // =0xffffffffffffffff
-; CHECK-NEXT: // kill: def $w2 killed $w2 def $x2
-; CHECK-NEXT: // kill: def $w1 killed $w1 def $x1
-; CHECK-NEXT: lsl x9, x9, x2
-; CHECK-NEXT: lsr x8, x8, x1
+; CHECK-NEXT: mov w9, w1
+; CHECK-NEXT: mov w10, w2
+; CHECK-NEXT: mov x11, #-1 // =0xffffffffffffffff
+; CHECK-NEXT: lsr x8, x8, x9
+; CHECK-NEXT: lsl x9, x11, x10
; CHECK-NEXT: bic x0, x8, x9
; CHECK-NEXT: ret
%val = load i64, ptr %w
diff --git a/llvm/test/CodeGen/AArch64/extract-lowbits.ll b/llvm/test/CodeGen/AArch64/extract-lowbits.ll
index 368440c65df84..1696de12944e9 100644
--- a/llvm/test/CodeGen/AArch64/extract-lowbits.ll
+++ b/llvm/test/CodeGen/AArch64/extract-lowbits.ll
@@ -130,8 +130,8 @@ define i64 @bzhi64_a1_indexzext(i64 %val, i8 zeroext %numlowbits) nounwind {
; CHECK-LABEL: bzhi64_a1_indexzext:
; CHECK: // %bb.0:
; CHECK-NEXT: mov w8, #1 // =0x1
-; CHECK-NEXT: // kill: def $w1 killed $w1 def $x1
-; CHECK-NEXT: lsl x8, x8, x1
+; CHECK-NEXT: mov w9, w1
+; CHECK-NEXT: lsl x8, x8, x9
; CHECK-NEXT: sub x8, x8, #1
; CHECK-NEXT: and x0, x8, x0
; CHECK-NEXT: ret
@@ -162,9 +162,9 @@ define i64 @bzhi64_a3_load_indexzext(ptr %w, i8 zeroext %numlowbits) nounwind {
; CHECK-LABEL: bzhi64_a3_load_indexzext:
; CHECK: // %bb.0:
; CHECK-NEXT: mov w8, #1 // =0x1
-; CHECK-NEXT: // kill: def $w1 killed $w1 def $x1
+; CHECK-NEXT: mov w9, w1
+; CHECK-NEXT: lsl x8, x8, x9
; CHECK-NEXT: ldr x9, [x0]
-; CHECK-NEXT: lsl x8, x8, x1
; CHECK-NEXT: sub x8, x8, #1
; CHECK-NEXT: and x0, x8, x9
; CHECK-NEXT: ret
@@ -284,8 +284,8 @@ define i64 @bzhi64_b1_indexzext(i64 %val, i8 zeroext %numlowbits) nounwind {
; CHECK-LABEL: bzhi64_b1_indexzext:
; CHECK: // %bb.0:
; CHECK-NEXT: mov x8, #-1 // =0xffffffffffffffff
-; CHECK-NEXT: // kill: def $w1 killed $w1 def $x1
-; CHECK-NEXT: lsl x8, x8, x1
+; CHECK-NEXT: mov w9, w1
+; CHECK-NEXT: lsl x8, x8, x9
; CHECK-NEXT: bic x0, x0, x8
; CHECK-NEXT: ret
%conv = zext i8 %numlowbits to i64
@@ -314,10 +314,10 @@ define i64 @bzhi64_b3_load_indexzext(ptr %w, i8 zeroext %numlowbits) nounwind {
; CHECK-LABEL: bzhi64_b3_load_indexzext:
; CHECK: // %bb.0:
; CHECK-NEXT: mov x8, #-1 // =0xffffffffffffffff
-; CHECK-NEXT: // kill: def $w1 killed $w1 def $x1
-; CHECK-NEXT: ldr x9, [x0]
-; CHECK-NEXT: lsl x8, x8, x1
-; CHECK-NEXT: bic x0, x9, x8
+; CHECK-NEXT: mov w9, w1
+; CHECK-NEXT: ldr x10, [x0]
+; CHECK-NEXT: lsl x8, x8, x9
+; CHECK-NEXT: bic x0, x10, x8
; CHECK-NEXT: ret
%val = load i64, ptr %w
%conv = zext i8 %numlowbits to i64
diff --git a/llvm/test/CodeGen/AArch64/frem-power2.ll b/llvm/test/CodeGen/AArch64/frem-power2.ll
index 548079dc5c4aa..7314ee72e8d20 100644
--- a/llvm/test/CodeGen/AArch64/frem-power2.ll
+++ b/llvm/test/CodeGen/AArch64/frem-power2.ll
@@ -665,9 +665,8 @@ define float @frem2_const_sitofp(float %x, i32 %sa) {
; CHECK-GI-LABEL: frem2_const_sitofp:
; CHECK-GI: // %bb.0: // %entry
; CHECK-GI-NEXT: mov w8, #1 // =0x1
-; CHECK-GI-NEXT: and w9, w0, #0x1f
; CHECK-GI-NEXT: fmov s0, #12.50000000
-; CHECK-GI-NEXT: lsl w8, w8, w9
+; CHECK-GI-NEXT: lsl w8, w8, w0
; CHECK-GI-NEXT: scvtf s1, w8
; CHECK-GI-NEXT: b fmodf
entry:
@@ -695,9 +694,8 @@ define float @frem2_constneg_sitofp(float %x, i32 %sa) {
; CHECK-GI-LABEL: frem2_constneg_sitofp:
; CHECK-GI: // %bb.0: // %entry
; CHECK-GI-NEXT: mov w8, #1 // =0x1
-; CHECK-GI-NEXT: and w9, w0, #0x1f
; CHECK-GI-NEXT: fmov s0, #-12.50000000
-; CHECK-GI-NEXT: lsl w8, w8, w9
+; CHECK-GI-NEXT: lsl w8, w8, w0
; CHECK-GI-NEXT: scvtf s1, w8
; CHECK-GI-NEXT: b fmodf
entry:
diff --git a/llvm/test/CodeGen/AArch64/fsh.ll b/llvm/test/CodeGen/AArch64/fsh.ll
index 312010904cf50..a3af83353692d 100644
--- a/llvm/test/CodeGen/AArch64/fsh.ll
+++ b/llvm/test/CodeGen/AArch64/fsh.ll
@@ -385,25 +385,14 @@ entry:
}
define i32 @fshl_i32(i32 %a, i32 %b, i32 %c) {
-; CHECK-SD-LABEL: fshl_i32:
-; CHECK-SD: // %bb.0: // %entry
-; CHECK-SD-NEXT: lsr w8, w1, #1
-; CHECK-SD-NEXT: mvn w9, w2
-; CHECK-SD-NEXT: lsl w10, w0, w2
-; CHECK-SD-NEXT: lsr w8, w8, w9
-; CHECK-SD-NEXT: orr w0, w10, w8
-; CHECK-SD-NEXT: ret
-;
-; CHECK-GI-LABEL: fshl_i32:
-; CHECK-GI: // %bb.0: // %entry
-; CHECK-GI-NEXT: mov w8, #31 // =0x1f
-; CHECK-GI-NEXT: lsr w9, w1, #1
-; CHECK-GI-NEXT: and w10, w2, #0x1f
-; CHECK-GI-NEXT: bic w8, w8, w2
-; CHECK-GI-NEXT: lsl w10, w0, w10
-; CHECK-GI-NEXT: lsr w8, w9, w8
-; CHECK-GI-NEXT: orr w0, w10, w8
-; CHECK-GI-NEXT: ret
+; CHECK-LABEL: fshl_i32:
+; CHECK: // %bb.0: // %entry
+; CHECK-NEXT: lsr w8, w1, #1
+; CHECK-NEXT: mvn w9, w2
+; CHECK-NEXT: lsl w10, w0, w2
+; CHECK-NEXT: lsr w8, w8, w9
+; CHECK-NEXT: orr w0, w10, w8
+; CHECK-NEXT: ret
entry:
%d = call i32 @llvm.fshl(i32 %a, i32 %b, i32 %c)
ret i32 %d
@@ -421,12 +410,10 @@ define i32 @fshr_i32(i32 %a, i32 %b, i32 %c) {
;
; CHECK-GI-LABEL: fshr_i32:
; CHECK-GI: // %bb.0: // %entry
-; CHECK-GI-NEXT: mov w8, #31 // =0x1f
-; CHECK-GI-NEXT: lsl w9, w0, #1
-; CHECK-GI-NEXT: and w10, w2, #0x1f
-; CHECK-GI-NEXT: bic w8, w8, w2
-; CHECK-GI-NEXT: lsl w8, w9, w8
-; CHECK-GI-NEXT: lsr w9, w1, w10
+; CHECK-GI-NEXT: lsl w8, w0, #1
+; CHECK-GI-NEXT: mvn w9, w2
+; CHECK-GI-NEXT: lsl w8, w8, w9
+; CHECK-GI-NEXT: lsr w9, w1, w2
; CHECK-GI-NEXT: orr w0, w8, w9
; CHECK-GI-NEXT: ret
entry:
diff --git a/llvm/test/CodeGen/AArch64/funnel-shift.ll b/llvm/test/CodeGen/AArch64/funnel-shift.ll
index c4e4d3c7dcd2b..8bc8fefc2aeb8 100644
--- a/llvm/test/CodeGen/AArch64/funnel-shift.ll
+++ b/llvm/test/CodeGen/AArch64/funnel-shift.ll
@@ -18,25 +18,14 @@ declare <4 x i32> @llvm.fshr.v4i32(<4 x i32>, <4 x i32>, <4 x i32>)
; General case - all operands can be variables.
define i32 @fshl_i32(i32 %x, i32 %y, i32 %z) {
-; CHECK-SD-LABEL: fshl_i32:
-; CHECK-SD: // %bb.0:
-; CHECK-SD-NEXT: lsr w8, w1, #1
-; CHECK-SD-NEXT: mvn w9, w2
-; CHECK-SD-NEXT: lsl w10, w0, w2
-; CHECK-SD-NEXT: lsr w8, w8, w9
-; CHECK-SD-NEXT: orr w0, w10, w8
-; CHECK-SD-NEXT: ret
-;
-; CHECK-GI-LABEL: fshl_i32:
-; CHECK-GI: // %bb.0:
-; CHECK-GI-NEXT: mov w8, #31 // =0x1f
-; CHECK-GI-NEXT: lsr w9, w1, #1
-; CHECK-GI-NEXT: and w10, w2, #0x1f
-; CHECK-GI-NEXT: bic w8, w8, w2
-; CHECK-GI-NEXT: lsl w10, w0, w10
-; CHECK-GI-NEXT: lsr w8, w9, w8
-; CHECK-GI-NEXT: orr w0, w10, w8
-; CHECK-GI-NEXT: ret
+; CHECK-LABEL: fshl_i32:
+; CHECK: // %bb.0:
+; CHECK-NEXT: lsr w8, w1, #1
+; CHECK-NEXT: mvn w9, w2
+; CHECK-NEXT: lsl w10, w0, w2
+; CHECK-NEXT: lsr w8, w8, w9
+; CHECK-NEXT: orr w0, w10, w8
+; CHECK-NEXT: ret
%f = call i32 @llvm.fshl.i32(i32 %x, i32 %y, i32 %z)
ret i32 %f
}
@@ -300,12 +289,10 @@ define i32 @fshr_i32(i32 %x, i32 %y, i32 %z) {
;
; CHECK-GI-LABEL: fshr_i32:
; CHECK-GI: // %bb.0:
-; CHECK-GI-NEXT: mov w8, #31 // =0x1f
-; CHECK-GI-NEXT: lsl w9, w0, #1
-; CHECK-GI-NEXT: and w10, w2, #0x1f
-; CHECK-GI-NEXT: bic w8, w8, w2
-; CHECK-GI-NEXT: lsl w8, w9, w8
-; CHECK-GI-NEXT: lsr w9, w1, w10
+; CHECK-GI-NEXT: lsl w8, w0, #1
+; CHECK-GI-NEXT: mvn w9, w2
+; CHECK-GI-NEXT: lsl w8, w8, w9
+; CHECK-GI-NEXT: lsr w9, w1, w2
; CHECK-GI-NEXT: orr w0, w8, w9
; CHECK-GI-NEXT: ret
%f = call i32 @llvm.fshr.i32(i32 %x, i32 %y, i32 %z)
@@ -551,14 +538,12 @@ define i32 @or_shl_fshl(i32 %x, i32 %y, i32 %s) {
;
; CHECK-GI-LABEL: or_shl_fshl:
; CHECK-GI: // %bb.0:
-; CHECK-GI-NEXT: mov w8, #31 // =0x1f
-; CHECK-GI-NEXT: and w9, w2, #0x1f
-; CHECK-GI-NEXT: lsr w10, w1, #1
-; CHECK-GI-NEXT: lsl w11, w1, w2
-; CHECK-GI-NEXT: bic w8, w8, w2
-; CHECK-GI-NEXT: lsl w9, w0, w9
-; CHECK-GI-NEXT: lsr w8, w10, w8
-; CHECK-GI-NEXT: orr w9, w9, w11
+; CHECK-GI-NEXT: lsr w8, w1, #1
+; CHECK-GI-NEXT: lsl w9, w1, w2
+; CHECK-GI-NEXT: mvn w10, w2
+; CHECK-GI-NEXT: lsl w11, w0, w2
+; CHECK-GI-NEXT: lsr w8, w8, w10
+; CHECK-GI-NEXT: orr w9, w11, w9
; CHECK-GI-NEXT: orr w0, w9, w8
; CHECK-GI-NEXT: ret
%shy = shl i32 %y, %s
@@ -594,14 +579,12 @@ define i32 @or_shl_fshl_commute(i32 %x, i32 %y, i32 %s) {
;
; CHECK-GI-LABEL: or_shl_fshl_commute:
; CHECK-GI: // %bb.0:
-; CHECK-GI-NEXT: mov w8, #31 // =0x1f
-; CHECK-GI-NEXT: and w9, w2, #0x1f
-; CHECK-GI-NEXT: lsr w10, w1, #1
-; CHECK-GI-NEXT: lsl w11, w1, w2
-; CHECK-GI-NEXT: bic w8, w8, w2
-; CHECK-GI-NEXT: lsl w9, w0, w9
-; CHECK-GI-NEXT: lsr w8, w10, w8
-; CHECK-GI-NEXT: orr w9, w11, w9
+; CHECK-GI-NEXT: lsr w8, w1, #1
+; CHECK-GI-NEXT: lsl w9, w1, w2
+; CHECK-GI-NEXT: mvn w10, w2
+; CHECK-GI-NEXT: lsl w11, w0, w2
+; CHECK-GI-NEXT: lsr w8, w8, w10
+; CHECK-GI-NEXT: orr w9, w9, w11
; CHECK-GI-NEXT: orr w0, w9, w8
; CHECK-GI-NEXT: ret
%shy = shl i32 %y, %s
@@ -637,14 +620,12 @@ define i32 @or_lshr_fshr(i32 %x, i32 %y, i32 %s) {
;
; CHECK-GI-LABEL: or_lshr_fshr:
; CHECK-GI: // %bb.0:
-; CHECK-GI-NEXT: mov w8, #31 // =0x1f
-; CHECK-GI-NEXT: and w9, w2, #0x1f
-; CHECK-GI-NEXT: lsl w10, w1, #1
-; CHECK-GI-NEXT: lsr w11, w1, w2
-; CHECK-GI-NEXT: bic w8, w8, w2
-; CHECK-GI-NEXT: lsr w9, w0, w9
-; CHECK-GI-NEXT: lsl w8, w10, w8
-; CHECK-GI-NEXT: orr w9, w9, w11
+; CHECK-GI-NEXT: lsl w8, w1, #1
+; CHECK-GI-NEXT: lsr w9, w1, w2
+; CHECK-GI-NEXT: mvn w10, w2
+; CHECK-GI-NEXT: lsr w11, w0, w2
+; CHECK-GI-NEXT: lsl w8, w8, w10
+; CHECK-GI-NEXT: orr w9, w11, w9
; CHECK-GI-NEXT: orr w0, w8, w9
; CHECK-GI-NEXT: ret
%shy = lshr i32 %y, %s
@@ -679,14 +660,12 @@ define i32 @or_lshr_fshr_commute(i32 %x, i32 %y, i32 %s) {
;
; CHECK-GI-LABEL: or_lshr_fshr_commute:
; CHECK-GI: // %bb.0:
-; CHECK-GI-NEXT: mov w8, #31 // =0x1f
-; CHECK-GI-NEXT: and w9, w2, #0x1f
-; CHECK-GI-NEXT: lsl w10, w1, #1
-; CHECK-GI-NEXT: lsr w11, w1, w2
-; CHECK-GI-NEXT: bic w8, w8, w2
-; CHECK-GI-NEXT: lsr w9, w0, w9
-; CHECK-GI-NEXT: lsl w8, w10, w8
-; CHECK-GI-NEXT: orr w9, w11, w9
+; CHECK-GI-NEXT: lsl w8, w1, #1
+; CHECK-GI-NEXT: lsr w9, w1, w2
+; CHECK-GI-NEXT: mvn w10, w2
+; CHECK-GI-NEXT: lsr w11, w0, w2
+; CHECK-GI-NEXT: lsl w8, w8, w10
+; CHECK-GI-NEXT: orr w9, w9, w11
; CHECK-GI-NEXT: orr w0, w9, w8
; CHECK-GI-NEXT: ret
%shy = lshr i32 %y, %s
@@ -709,25 +688,14 @@ define i32 @or_lshr_rotr_commute(i32 %x, i32 %y, i32 %s) {
}
define i32 @or_shl_fshl_simplify(i32 %x, i32 %y, i32 %s) {
-; CHECK-SD-LABEL: or_shl_fshl_simplify:
-; CHECK-SD: // %bb.0:
-; CHECK-SD-NEXT: lsr w8, w0, #1
-; CHECK-SD-NEXT: mvn w9, w2
-; CHECK-SD-NEXT: lsl w10, w1, w2
-; CHECK-SD-NEXT: lsr w8, w8, w9
-; CHECK-SD-NEXT: orr w0, w10, w8
-; CHECK-SD-NEXT: ret
-;
-; CHECK-GI-LABEL: or_shl_fshl_simplify:
-; CHECK-GI: // %bb.0:
-; CHECK-GI-NEXT: mov w8, #31 // =0x1f
-; CHECK-GI-NEXT: lsr w9, w0, #1
-; CHECK-GI-NEXT: and w10, w2, #0x1f
-; CHECK-GI-NEXT: bic w8, w8, w2
-; CHECK-GI-NEXT: lsl w10, w1, w10
-; CHECK-GI-NEXT: lsr w8, w9, w8
-; CHECK-GI-NEXT: orr w0, w10, w8
-; CHECK-GI-NEXT: ret
+; CHECK-LABEL: or_shl_fshl_simplify:
+; CHECK: // %bb.0:
+; CHECK-NEXT: lsr w8, w0, #1
+; CHECK-NEXT: mvn w9, w2
+; CHECK-NEXT: lsl w10, w1, w2
+; CHECK-NEXT: lsr w8, w8, w9
+; CHECK-NEXT: orr w0, w10, w8
+; CHECK-NEXT: ret
%shy = shl i32 %y, %s
%fun = call i32 @llvm.fshl.i32(i32 %y, i32 %x, i32 %s)
%or = or i32 %fun, %shy
@@ -746,12 +714,10 @@ define i32 @or_lshr_fshr_simplify(i32 %x, i32 %y, i32 %s) {
;
; CHECK-GI-LABEL: or_lshr_fshr_simplify:
; CHECK-GI: // %bb.0:
-; CHECK-GI-NEXT: mov w8, #31 // =0x1f
-; CHECK-GI-NEXT: lsl w9, w0, #1
-; CHECK-GI-NEXT: and w10, w2, #0x1f
-; CHECK-GI-NEXT: bic w8, w8, w2
-; CHECK-GI-NEXT: lsl w8, w9, w8
-; CHECK-GI-NEXT: lsr w9, w1, w10
+; CHECK-GI-NEXT: lsl w8, w0, #1
+; CHECK-GI-NEXT: mvn w9, w2
+; CHECK-GI-NEXT: lsl w8, w8, w9
+; CHECK-GI-NEXT: lsr w9, w1, w2
; CHECK-GI-NEXT: orr w0, w8, w9
; CHECK-GI-NEXT: ret
%shy = lshr i32 %y, %s
diff --git a/llvm/test/CodeGen/AArch64/hoist-and-by-const-from-lshr-in-eqcmp-zero.ll b/llvm/test/CodeGen/AArch64/hoist-and-by-const-from-lshr-in-eqcmp-zero.ll
index 7d8ff9ac11e30..78efedb0c9317 100644
--- a/llvm/test/CodeGen/AArch64/hoist-and-by-const-from-lshr-in-eqcmp-zero.ll
+++ b/llvm/test/CodeGen/AArch64/hoist-and-by-const-from-lshr-in-eqcmp-zero.ll
@@ -24,8 +24,7 @@ define i1 @scalar_i8_signbit_eq(i8 %x, i8 %y) nounwind {
; CHECK-GI-LABEL: scalar_i8_signbit_eq:
; CHECK-GI: // %bb.0:
; CHECK-GI-NEXT: mov w8, #128 // =0x80
-; CHECK-GI-NEXT: and w9, w1, #0xff
-; CHECK-GI-NEXT: lsr w8, w8, w9
+; CHECK-GI-NEXT: lsr w8, w8, w1
; CHECK-GI-NEXT: tst w8, w0
; CHECK-GI-NEXT: cset w0, eq
; CHECK-GI-NEXT: ret
@@ -46,8 +45,7 @@ define i1 @scalar_i8_lowestbit_eq(i8 %x, i8 %y) nounwind {
; CHECK-GI-LABEL: scalar_i8_lowestbit_eq:
; CHECK-GI: // %bb.0:
; CHECK-GI-NEXT: mov w8, #1 // =0x1
-; CHECK-GI-NEXT: and w9, w1, #0xff
-; CHECK-GI-NEXT: lsr w8, w8, w9
+; CHECK-GI-NEXT: lsr w8, w8, w1
; CHECK-GI-NEXT: tst w8, w0
; CHECK-GI-NEXT: cset w0, eq
; CHECK-GI-NEXT: ret
@@ -68,8 +66,7 @@ define i1 @scalar_i8_bitsinmiddle_eq(i8 %x, i8 %y) nounwind {
; CHECK-GI-LABEL: scalar_i8_bitsinmiddle_eq:
; CHECK-GI: // %bb.0:
; CHECK-GI-NEXT: mov w8, #24 // =0x18
-; CHECK-GI-NEXT: and w9, w1, #0xff
-; CHECK-GI-NEXT: lsr w8, w8, w9
+; CHECK-GI-NEXT: lsr w8, w8, w1
; CHECK-GI-NEXT: tst w8, w0
; CHECK-GI-NEXT: cset w0, eq
; CHECK-GI-NEXT: ret
@@ -92,8 +89,7 @@ define i1 @scalar_i16_signbit_eq(i16 %x, i16 %y) nounwind {
; CHECK-GI-LABEL: scalar_i16_signbit_eq:
; CHECK-GI: // %bb.0:
; CHECK-GI-NEXT: mov w8, #32768 // =0x8000
-; CHECK-GI-NEXT: and w9, w1, #0xffff
-; CHECK-GI-NEXT: lsr w8, w8, w9
+; CHECK-GI-NEXT: lsr w8, w8, w1
; CHECK-GI-NEXT: tst w8, w0
; CHECK-GI-NEXT: cset w0, eq
; CHECK-GI-NEXT: ret
@@ -114,8 +110,7 @@ define i1 @scalar_i16_lowestbit_eq(i16 %x, i16 %y) nounwind {
; CHECK-GI-LABEL: scalar_i16_lowestbit_eq:
; CHECK-GI: // %bb.0:
; CHECK-GI-NEXT: mov w8, #1 // =0x1
-; CHECK-GI-NEXT: and w9, w1, #0xffff
-; CHECK-GI-NEXT: lsr w8, w8, w9
+; CHECK-GI-NEXT: lsr w8, w8, w1
; CHECK-GI-NEXT: tst w8, w0
; CHECK-GI-NEXT: cset w0, eq
; CHECK-GI-NEXT: ret
@@ -136,8 +131,7 @@ define i1 @scalar_i16_bitsinmiddle_eq(i16 %x, i16 %y) nounwind {
; CHECK-GI-LABEL: scalar_i16_bitsinmiddle_eq:
; CHECK-GI: // %bb.0:
; CHECK-GI-NEXT: mov w8, #4080 // =0xff0
-; CHECK-GI-NEXT: and w9, w1, #0xffff
-; CHECK-GI-NEXT: lsr w8, w8, w9
+; CHECK-GI-NEXT: lsr w8, w8, w1
; CHECK-GI-NEXT: tst w8, w0
; CHECK-GI-NEXT: cset w0, eq
; CHECK-GI-NEXT: ret
@@ -425,8 +419,7 @@ define i1 @scalar_i8_signbit_ne(i8 %x, i8 %y) nounwind {
; CHECK-GI-LABEL: scalar_i8_signbit_ne:
; CHECK-GI: // %bb.0:
; CHECK-GI-NEXT: mov w8, #128 // =0x80
-; CHECK-GI-NEXT: and w9, w1, #0xff
-; CHECK-GI-NEXT: lsr w8, w8, w9
+; CHECK-GI-NEXT: lsr w8, w8, w1
; CHECK-GI-NEXT: tst w8, w0
; CHECK-GI-NEXT: cset w0, ne
; CHECK-GI-NEXT: ret
@@ -480,24 +473,14 @@ define i1 @scalar_i8_bitsinmiddle_slt(i8 %x, i8 %y) nounwind {
}
define i1 @scalar_i8_signbit_eq_with_nonzero(i8 %x, i8 %y) nounwind {
-; CHECK-SD-LABEL: scalar_i8_signbit_eq_with_nonzero:
-; CHECK-SD: // %bb.0:
-; CHECK-SD-NEXT: mov w8, #128 // =0x80
-; CHECK-SD-NEXT: lsr w8, w8, w1
-; CHECK-SD-NEXT: and w8, w8, w0
-; CHECK-SD-NEXT: cmp w8, #1
-; CHECK-SD-NEXT: cset w0, eq
-; CHECK-SD-NEXT: ret
-;
-; CHECK-GI-LABEL: scalar_i8_signbit_eq_with_nonzero:
-; CHECK-GI: // %bb.0:
-; CHECK-GI-NEXT: mov w8, #128 // =0x80
-; CHECK-GI-NEXT: and w9, w1, #0xff
-; CHECK-GI-NEXT: lsr w8, w8, w9
-; CHECK-GI-NEXT: and w8, w8, w0
-; CHECK-GI-NEXT: cmp w8, #1
-; CHECK-GI-NEXT: cset w0, eq
-; CHECK-GI-NEXT: ret
+; CHECK-LABEL: scalar_i8_signbit_eq_with_nonzero:
+; CHECK: // %bb.0:
+; CHECK-NEXT: mov w8, #128 // =0x80
+; CHECK-NEXT: lsr w8, w8, w1
+; CHECK-NEXT: and w8, w8, w0
+; CHECK-NEXT: cmp w8, #1
+; CHECK-NEXT: cset w0, eq
+; CHECK-NEXT: ret
%t0 = lshr i8 128, %y
%t1 = and i8 %t0, %x
%res = icmp eq i8 %t1, 1 ; should be comparing with 0
diff --git a/llvm/test/CodeGen/AArch64/hoist-and-by-const-from-shl-in-eqcmp-zero.ll b/llvm/test/CodeGen/AArch64/hoist-and-by-const-from-shl-in-eqcmp-zero.ll
index f61e4303ca2be..b55efeb580ee7 100644
--- a/llvm/test/CodeGen/AArch64/hoist-and-by-const-from-shl-in-eqcmp-zero.ll
+++ b/llvm/test/CodeGen/AArch64/hoist-and-by-const-from-shl-in-eqcmp-zero.ll
@@ -25,8 +25,7 @@ define i1 @scalar_i8_signbit_eq(i8 %x, i8 %y) nounwind {
; CHECK-GI-LABEL: scalar_i8_signbit_eq:
; CHECK-GI: // %bb.0:
; CHECK-GI-NEXT: mov w8, #-128 // =0xffffff80
-; CHECK-GI-NEXT: and w9, w1, #0xff
-; CHECK-GI-NEXT: lsl w8, w8, w9
+; CHECK-GI-NEXT: lsl w8, w8, w1
; CHECK-GI-NEXT: and w8, w8, w0
; CHECK-GI-NEXT: tst w8, #0xff
; CHECK-GI-NEXT: cset w0, eq
@@ -49,8 +48,7 @@ define i1 @scalar_i8_lowestbit_eq(i8 %x, i8 %y) nounwind {
; CHECK-GI-LABEL: scalar_i8_lowestbit_eq:
; CHECK-GI: // %bb.0:
; CHECK-GI-NEXT: mov w8, #1 // =0x1
-; CHECK-GI-NEXT: and w9, w1, #0xff
-; CHECK-GI-NEXT: lsl w8, w8, w9
+; CHECK-GI-NEXT: lsl w8, w8, w1
; CHECK-GI-NEXT: and w8, w8, w0
; CHECK-GI-NEXT: tst w8, #0xff
; CHECK-GI-NEXT: cset w0, eq
@@ -73,8 +71,7 @@ define i1 @scalar_i8_bitsinmiddle_eq(i8 %x, i8 %y) nounwind {
; CHECK-GI-LABEL: scalar_i8_bitsinmiddle_eq:
; CHECK-GI: // %bb.0:
; CHECK-GI-NEXT: mov w8, #24 // =0x18
-; CHECK-GI-NEXT: and w9, w1, #0xff
-; CHECK-GI-NEXT: lsl w8, w8, w9
+; CHECK-GI-NEXT: lsl w8, w8, w1
; CHECK-GI-NEXT: and w8, w8, w0
; CHECK-GI-NEXT: tst w8, #0xff
; CHECK-GI-NEXT: cset w0, eq
@@ -99,8 +96,7 @@ define i1 @scalar_i16_signbit_eq(i16 %x, i16 %y) nounwind {
; CHECK-GI-LABEL: scalar_i16_signbit_eq:
; CHECK-GI: // %bb.0:
; CHECK-GI-NEXT: mov w8, #-32768 // =0xffff8000
-; CHECK-GI-NEXT: and w9, w1, #0xffff
-; CHECK-GI-NEXT: lsl w8, w8, w9
+; CHECK-GI-NEXT: lsl w8, w8, w1
; CHECK-GI-NEXT: and w8, w8, w0
; CHECK-GI-NEXT: tst w8, #0xffff
; CHECK-GI-NEXT: cset w0, eq
@@ -123,8 +119,7 @@ define i1 @scalar_i16_lowestbit_eq(i16 %x, i16 %y) nounwind {
; CHECK-GI-LABEL: scalar_i16_lowestbit_eq:
; CHECK-GI: // %bb.0:
; CHECK-GI-NEXT: mov w8, #1 // =0x1
-; CHECK-GI-NEXT: and w9, w1, #0xffff
-; CHECK-GI-NEXT: lsl w8, w8, w9
+; CHECK-GI-NEXT: lsl w8, w8, w1
; CHECK-GI-NEXT: and w8, w8, w0
; CHECK-GI-NEXT: tst w8, #0xffff
; CHECK-GI-NEXT: cset w0, eq
@@ -147,8 +142,7 @@ define i1 @scalar_i16_bitsinmiddle_eq(i16 %x, i16 %y) nounwind {
; CHECK-GI-LABEL: scalar_i16_bitsinmiddle_eq:
; CHECK-GI: // %bb.0:
; CHECK-GI-NEXT: mov w8, #4080 // =0xff0
-; CHECK-GI-NEXT: and w9, w1, #0xffff
-; CHECK-GI-NEXT: lsl w8, w8, w9
+; CHECK-GI-NEXT: lsl w8, w8, w1
; CHECK-GI-NEXT: and w8, w8, w0
; CHECK-GI-NEXT: tst w8, #0xffff
; CHECK-GI-NEXT: cset w0, eq
@@ -430,8 +424,7 @@ define i1 @scalar_i8_signbit_ne(i8 %x, i8 %y) nounwind {
; CHECK-GI-LABEL: scalar_i8_signbit_ne:
; CHECK-GI: // %bb.0:
; CHECK-GI-NEXT: mov w8, #-128 // =0xffffff80
-; CHECK-GI-NEXT: and w9, w1, #0xff
-; CHECK-GI-NEXT: lsl w8, w8, w9
+; CHECK-GI-NEXT: lsl w8, w8, w1
; CHECK-GI-NEXT: and w8, w8, w0
; CHECK-GI-NEXT: tst w8, #0xff
; CHECK-GI-NEXT: cset w0, ne
@@ -488,8 +481,7 @@ define i1 @scalar_i8_bitsinmiddle_slt(i8 %x, i8 %y) nounwind {
; CHECK-GI-LABEL: scalar_i8_bitsinmiddle_slt:
; CHECK-GI: // %bb.0:
; CHECK-GI-NEXT: mov w8, #24 // =0x18
-; CHECK-GI-NEXT: and w9, w1, #0xff
-; CHECK-GI-NEXT: lsl w8, w8, w9
+; CHECK-GI-NEXT: lsl w8, w8, w1
; CHECK-GI-NEXT: and w8, w8, w0
; CHECK-GI-NEXT: sxtb w8, w8
; CHECK-GI-NEXT: cmp w8, #0
diff --git a/llvm/test/CodeGen/AArch64/select_const.ll b/llvm/test/CodeGen/AArch64/select_const.ll
index daa9971dbcd58..c67d527dbfed1 100644
--- a/llvm/test/CodeGen/AArch64/select_const.ll
+++ b/llvm/test/CodeGen/AArch64/select_const.ll
@@ -672,7 +672,6 @@ define i8 @shl_constant_sel_constants(i1 %cond) {
; CHECK-GI-NEXT: sbfx w9, w0, #0, #1
; CHECK-GI-NEXT: mov w8, #1 // =0x1
; CHECK-GI-NEXT: add w9, w9, #3
-; CHECK-GI-NEXT: and w9, w9, #0xff
; CHECK-GI-NEXT: lsl w0, w8, w9
; CHECK-GI-NEXT: ret
%sel = select i1 %cond, i8 2, i8 3
@@ -714,7 +713,6 @@ define i8 @lshr_constant_sel_constants(i1 %cond) {
; CHECK-GI-NEXT: sbfx w9, w0, #0, #1
; CHECK-GI-NEXT: mov w8, #64 // =0x40
; CHECK-GI-NEXT: add w9, w9, #3
-; CHECK-GI-NEXT: and w9, w9, #0xff
; CHECK-GI-NEXT: lsr w0, w8, w9
; CHECK-GI-NEXT: ret
%sel = select i1 %cond, i8 2, i8 3
@@ -747,7 +745,6 @@ define i8 @ashr_constant_sel_constants(i1 %cond) {
; CHECK-GI-NEXT: sbfx w9, w0, #0, #1
; CHECK-GI-NEXT: mov w8, #-128 // =0xffffff80
; CHECK-GI-NEXT: add w9, w9, #3
-; CHECK-GI-NEXT: and w9, w9, #0xff
; CHECK-GI-NEXT: asr w0, w8, w9
; CHECK-GI-NEXT: ret
%sel = select i1 %cond, i8 2, i8 3
diff --git a/llvm/test/CodeGen/AArch64/shift-mod.ll b/llvm/test/CodeGen/AArch64/shift-mod.ll
index a235b3628ded5..e87d6aaea1532 100644
--- a/llvm/test/CodeGen/AArch64/shift-mod.ll
+++ b/llvm/test/CodeGen/AArch64/shift-mod.ll
@@ -54,8 +54,8 @@ define i64 @test3(i64 %x, i64 %y) {
define i64 @test4(i64 %y, i32 %s) {
; CHECK-LABEL: test4:
; CHECK: // %bb.0: // %entry
-; CHECK-NEXT: // kill: def $w1 killed $w1 def $x1
-; CHECK-NEXT: asr x0, x0, x1
+; CHECK-NEXT: mov w8, w1
+; CHECK-NEXT: asr x0, x0, x8
; CHECK-NEXT: ret
entry:
%sh_prom = zext i32 %s to i64
@@ -67,7 +67,8 @@ define i64 @test5(i64 %y, i32 %s) {
; CHECK-LABEL: test5:
; CHECK: // %bb.0: // %entry
; CHECK-NEXT: // kill: def $w1 killed $w1 def $x1
-; CHECK-NEXT: asr x0, x0, x1
+; CHECK-NEXT: sxtw x8, w1
+; CHECK-NEXT: asr x0, x0, x8
; CHECK-NEXT: ret
entry:
%sh_prom = sext i32 %s to i64
@@ -79,7 +80,8 @@ define i64 @test6(i64 %y, i32 %s) {
; CHECK-LABEL: test6:
; CHECK: // %bb.0: // %entry
; CHECK-NEXT: // kill: def $w1 killed $w1 def $x1
-; CHECK-NEXT: lsl x0, x0, x1
+; CHECK-NEXT: sxtw x8, w1
+; CHECK-NEXT: lsl x0, x0, x8
; CHECK-NEXT: ret
entry:
%sh_prom = sext i32 %s to i64
@@ -191,3 +193,77 @@ define i64 @ashr_add_shl_mismatch_shifts2(i64 %r) {
%conv1 = ashr i64 %sext, 8
ret i64 %conv1
}
+
+; Test that narrow shift amounts (i8/i16) don't generate redundant AND.
+define i32 @shl_i32_i8(i32 %x, i8 %amt) {
+; CHECK-LABEL: shl_i32_i8:
+; CHECK: // %bb.0:
+; CHECK-NEXT: lsl w0, w0, w1
+; CHECK-NEXT: ret
+ %ext = zext i8 %amt to i32
+ %r = shl i32 %x, %ext
+ ret i32 %r
+}
+
+define i32 @lshr_i32_i8(i32 %x, i8 %amt) {
+; CHECK-LABEL: lshr_i32_i8:
+; CHECK: // %bb.0:
+; CHECK-NEXT: lsr w0, w0, w1
+; CHECK-NEXT: ret
+ %ext = zext i8 %amt to i32
+ %r = lshr i32 %x, %ext
+ ret i32 %r
+}
+
+define i32 @ashr_i32_i8(i32 %x, i8 %amt) {
+; CHECK-LABEL: ashr_i32_i8:
+; CHECK: // %bb.0:
+; CHECK-NEXT: asr w0, w0, w1
+; CHECK-NEXT: ret
+ %ext = zext i8 %amt to i32
+ %r = ashr i32 %x, %ext
+ ret i32 %r
+}
+
+define i32 @shl_i32_i16(i32 %x, i16 %amt) {
+; CHECK-LABEL: shl_i32_i16:
+; CHECK: // %bb.0:
+; CHECK-NEXT: lsl w0, w0, w1
+; CHECK-NEXT: ret
+ %ext = zext i16 %amt to i32
+ %r = shl i32 %x, %ext
+ ret i32 %r
+}
+
+define i64 @shl_i64_i8(i64 %x, i8 %amt) {
+; CHECK-LABEL: shl_i64_i8:
+; CHECK: // %bb.0:
+; CHECK-NEXT: // kill: def $w1 killed $w1 def $x1
+; CHECK-NEXT: lsl x0, x0, x1
+; CHECK-NEXT: ret
+ %ext = zext i8 %amt to i64
+ %r = shl i64 %x, %ext
+ ret i64 %r
+}
+
+define i64 @lshr_i64_i8(i64 %x, i8 %amt) {
+; CHECK-LABEL: lshr_i64_i8:
+; CHECK: // %bb.0:
+; CHECK-NEXT: // kill: def $w1 killed $w1 def $x1
+; CHECK-NEXT: lsr x0, x0, x1
+; CHECK-NEXT: ret
+ %ext = zext i8 %amt to i64
+ %r = lshr i64 %x, %ext
+ ret i64 %r
+}
+
+define i64 @ashr_i64_i16(i64 %x, i16 %amt) {
+; CHECK-LABEL: ashr_i64_i16:
+; CHECK: // %bb.0:
+; CHECK-NEXT: // kill: def $w1 killed $w1 def $x1
+; CHECK-NEXT: asr x0, x0, x1
+; CHECK-NEXT: ret
+ %ext = zext i16 %amt to i64
+ %r = ashr i64 %x, %ext
+ ret i64 %r
+}
diff --git a/llvm/test/CodeGen/AArch64/shift.ll b/llvm/test/CodeGen/AArch64/shift.ll
index 5d7935474c903..eb5f56f771a0f 100644
--- a/llvm/test/CodeGen/AArch64/shift.ll
+++ b/llvm/test/CodeGen/AArch64/shift.ll
@@ -19,31 +19,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
}
@@ -118,35 +106,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
}
@@ -223,35 +197,21 @@ define i1 @lshr_i1(i1 %0, i1 %1){
}
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