[llvm] [ARM] Take advantage of built-in mod of shift amount in variable-shift rotations and shifts (PR #157208)

via llvm-commits llvm-commits at lists.llvm.org
Fri Sep 5 17:57:37 PDT 2025


https://github.com/AZero13 updated https://github.com/llvm/llvm-project/pull/157208

>From 420dab42506650d5ba8ca714606ba858476b2211 Mon Sep 17 00:00:00 2001
From: AZero13 <gfunni234 at gmail.com>
Date: Fri, 5 Sep 2025 12:03:17 -0400
Subject: [PATCH 1/2] Pre-commit test (NFC)

---
 llvm/test/CodeGen/ARM/shift-mod.ll | 1068 ++++++++++++++++++++++++++++
 1 file changed, 1068 insertions(+)
 create mode 100644 llvm/test/CodeGen/ARM/shift-mod.ll

diff --git a/llvm/test/CodeGen/ARM/shift-mod.ll b/llvm/test/CodeGen/ARM/shift-mod.ll
new file mode 100644
index 0000000000000..3ba591e11acd1
--- /dev/null
+++ b/llvm/test/CodeGen/ARM/shift-mod.ll
@@ -0,0 +1,1068 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc -mtriple=armv7-linux-gnueabihf %s -o - | FileCheck %s --check-prefixes=CHECK-COMMON,CHECK-ARM
+; RUN: llc -mtriple=armv7eb-linux-gnueabihf %s -o - | FileCheck %s --check-prefixes=CHECK-BE
+; RUN: llc -mtriple=thumbv7-linux-gnueabihf %s -o - | FileCheck %s --check-prefixes=CHECK-COMMON,CHECK-THUMB
+; RUN: llc -mtriple=thumbv7m %s -o - | FileCheck %s --check-prefixes=CHECK-COMMON,CHECK-THUMB
+; RUN: llc -mtriple=thumbv7m -mattr=+strict-align %s -o - | FileCheck %s --check-prefixes=CHECK-COMMON,CHECK-ALIGN
+; RUN: llc -mtriple=thumbv6m %s -o - | FileCheck %s --check-prefix=CHECK-V6M
+
+; -----------------------------------------------------------------
+; LSL (shl) group
+; -----------------------------------------------------------------
+
+; (amount = amt + 32) => should remove the ADD and emit LSL directly.
+define i32 @lsl_add_mod(i32 %val, i32 %amt) #0 {
+; CHECK-LABEL: lsl_add_mod:
+; CHECK:       @ %bb.0: @ %entry
+; CHECK-NEXT:    add r1, r1, #32
+; CHECK-NEXT:    lsl r0, r0, r1
+; CHECK-NEXT:    bx lr
+;
+; CHECK-ARM-LABEL: lsl_add_mod:
+; CHECK-ARM:       @ %bb.0: @ %entry
+; CHECK-ARM-NEXT:    add r1, r1, #32
+; CHECK-ARM-NEXT:    lsl r0, r0, r1
+; CHECK-ARM-NEXT:    bx lr
+;
+; CHECK-BE-LABEL: lsl_add_mod:
+; CHECK-BE:       @ %bb.0: @ %entry
+; CHECK-BE-NEXT:    add r1, r1, #32
+; CHECK-BE-NEXT:    lsl r0, r0, r1
+; CHECK-BE-NEXT:    bx lr
+;
+; CHECK-THUMB-LABEL: lsl_add_mod:
+; CHECK-THUMB:       @ %bb.0: @ %entry
+; CHECK-THUMB-NEXT:    adds r1, #32
+; CHECK-THUMB-NEXT:    lsls r0, r1
+; CHECK-THUMB-NEXT:    bx lr
+;
+; CHECK-ALIGN-LABEL: lsl_add_mod:
+; CHECK-ALIGN:       @ %bb.0: @ %entry
+; CHECK-ALIGN-NEXT:    adds r1, #32
+; CHECK-ALIGN-NEXT:    lsls r0, r1
+; CHECK-ALIGN-NEXT:    bx lr
+;
+; CHECK-V6M-LABEL: lsl_add_mod:
+; CHECK-V6M:       @ %bb.0: @ %entry
+; CHECK-V6M-NEXT:    adds r1, #32
+; CHECK-V6M-NEXT:    lsls r0, r1
+; CHECK-V6M-NEXT:    bx lr
+entry:
+  %sa = add i32 %amt, 32
+  %r  = shl i32 %val, %sa
+  ret i32 %r
+}
+
+; (amount = 32 - amt) => should become RSB/NEG then used by LSL.
+define i32 @lsl_sub_rsb(i32 %val, i32 %amt) #0 {
+; CHECK-LABEL: lsl_sub_rsb:
+; CHECK:       @ %bb.0: @ %entry
+; CHECK-NEXT:    rsb r1, r1, #32
+; CHECK-NEXT:    lsl r0, r0, r1
+; CHECK-NEXT:    bx lr
+;
+; CHECK-ARM-LABEL: lsl_sub_rsb:
+; CHECK-ARM:       @ %bb.0: @ %entry
+; CHECK-ARM-NEXT:    rsb r1, r1, #32
+; CHECK-ARM-NEXT:    lsl r0, r0, r1
+; CHECK-ARM-NEXT:    bx lr
+;
+; CHECK-BE-LABEL: lsl_sub_rsb:
+; CHECK-BE:       @ %bb.0: @ %entry
+; CHECK-BE-NEXT:    rsb r1, r1, #32
+; CHECK-BE-NEXT:    lsl r0, r0, r1
+; CHECK-BE-NEXT:    bx lr
+;
+; CHECK-THUMB-LABEL: lsl_sub_rsb:
+; CHECK-THUMB:       @ %bb.0: @ %entry
+; CHECK-THUMB-NEXT:    rsb.w r1, r1, #32
+; CHECK-THUMB-NEXT:    lsls r0, r1
+; CHECK-THUMB-NEXT:    bx lr
+;
+; CHECK-ALIGN-LABEL: lsl_sub_rsb:
+; CHECK-ALIGN:       @ %bb.0: @ %entry
+; CHECK-ALIGN-NEXT:    rsb.w r1, r1, #32
+; CHECK-ALIGN-NEXT:    lsls r0, r1
+; CHECK-ALIGN-NEXT:    bx lr
+;
+; CHECK-V6M-LABEL: lsl_sub_rsb:
+; CHECK-V6M:       @ %bb.0: @ %entry
+; CHECK-V6M-NEXT:    movs r2, #32
+; CHECK-V6M-NEXT:    subs r1, r2, r1
+; CHECK-V6M-NEXT:    lsls r0, r1
+; CHECK-V6M-NEXT:    bx lr
+entry:
+  %sa = sub i32 32, %amt
+  %r  = shl i32 %val, %sa
+  ret i32 %r
+}
+
+; (amount = 31 - amt) => should become MVN(amt) then used by LSL.
+define i32 @lsl_sub_mvn(i32 %val, i32 %amt) #0 {
+; CHECK-LABEL: lsl_sub_mvn:
+; CHECK:       @ %bb.0: @ %entry
+; CHECK-NEXT:    rsb r1, r1, #31
+; CHECK-NEXT:    lsl r0, r0, r1
+; CHECK-NEXT:    bx lr
+;
+; CHECK-ARM-LABEL: lsl_sub_mvn:
+; CHECK-ARM:       @ %bb.0: @ %entry
+; CHECK-ARM-NEXT:    rsb r1, r1, #31
+; CHECK-ARM-NEXT:    lsl r0, r0, r1
+; CHECK-ARM-NEXT:    bx lr
+;
+; CHECK-BE-LABEL: lsl_sub_mvn:
+; CHECK-BE:       @ %bb.0: @ %entry
+; CHECK-BE-NEXT:    rsb r1, r1, #31
+; CHECK-BE-NEXT:    lsl r0, r0, r1
+; CHECK-BE-NEXT:    bx lr
+;
+; CHECK-THUMB-LABEL: lsl_sub_mvn:
+; CHECK-THUMB:       @ %bb.0: @ %entry
+; CHECK-THUMB-NEXT:    rsb.w r1, r1, #31
+; CHECK-THUMB-NEXT:    lsls r0, r1
+; CHECK-THUMB-NEXT:    bx lr
+;
+; CHECK-ALIGN-LABEL: lsl_sub_mvn:
+; CHECK-ALIGN:       @ %bb.0: @ %entry
+; CHECK-ALIGN-NEXT:    rsb.w r1, r1, #31
+; CHECK-ALIGN-NEXT:    lsls r0, r1
+; CHECK-ALIGN-NEXT:    bx lr
+;
+; CHECK-V6M-LABEL: lsl_sub_mvn:
+; CHECK-V6M:       @ %bb.0: @ %entry
+; CHECK-V6M-NEXT:    movs r2, #31
+; CHECK-V6M-NEXT:    subs r1, r2, r1
+; CHECK-V6M-NEXT:    lsls r0, r1
+; CHECK-V6M-NEXT:    bx lr
+entry:
+  %sa = sub i32 31, %amt
+  %r  = shl i32 %val, %sa
+  ret i32 %r
+}
+
+; (amount = amt & 31) => AND is redundant; should be removed and emit LSL only.
+define i32 @lsl_and_mask(i32 %val, i32 %amt) #0 {
+; CHECK-LABEL: lsl_and_mask:
+; CHECK:       @ %bb.0: @ %entry
+; CHECK-NEXT:    and r1, r1, #31
+; CHECK-NEXT:    lsl r0, r0, r1
+; CHECK-NEXT:    bx lr
+;
+; CHECK-ARM-LABEL: lsl_and_mask:
+; CHECK-ARM:       @ %bb.0: @ %entry
+; CHECK-ARM-NEXT:    and r1, r1, #31
+; CHECK-ARM-NEXT:    lsl r0, r0, r1
+; CHECK-ARM-NEXT:    bx lr
+;
+; CHECK-BE-LABEL: lsl_and_mask:
+; CHECK-BE:       @ %bb.0: @ %entry
+; CHECK-BE-NEXT:    and r1, r1, #31
+; CHECK-BE-NEXT:    lsl r0, r0, r1
+; CHECK-BE-NEXT:    bx lr
+;
+; CHECK-THUMB-LABEL: lsl_and_mask:
+; CHECK-THUMB:       @ %bb.0: @ %entry
+; CHECK-THUMB-NEXT:    and r1, r1, #31
+; CHECK-THUMB-NEXT:    lsls r0, r1
+; CHECK-THUMB-NEXT:    bx lr
+;
+; CHECK-ALIGN-LABEL: lsl_and_mask:
+; CHECK-ALIGN:       @ %bb.0: @ %entry
+; CHECK-ALIGN-NEXT:    and r1, r1, #31
+; CHECK-ALIGN-NEXT:    lsls r0, r1
+; CHECK-ALIGN-NEXT:    bx lr
+;
+; CHECK-V6M-LABEL: lsl_and_mask:
+; CHECK-V6M:       @ %bb.0: @ %entry
+; CHECK-V6M-NEXT:    movs r2, #31
+; CHECK-V6M-NEXT:    ands r2, r1
+; CHECK-V6M-NEXT:    lsls r0, r2
+; CHECK-V6M-NEXT:    bx lr
+entry:
+  %sa = and i32 %amt, 31
+  %r  = shl i32 %val, %sa
+  ret i32 %r
+}
+
+; -----------------------------------------------------------------
+; LSR (logical right) group
+; -----------------------------------------------------------------
+
+; (amount = amt + 32) => should remove the ADD and emit LSR directly.
+define i32 @lsr_add_mod(i32 %val, i32 %amt) #0 {
+; CHECK-LABEL: lsr_add_mod:
+; CHECK:       @ %bb.0: @ %entry
+; CHECK-NEXT:    add r1, r1, #32
+; CHECK-NEXT:    lsr r0, r0, r1
+; CHECK-NEXT:    bx lr
+;
+; CHECK-ARM-LABEL: lsr_add_mod:
+; CHECK-ARM:       @ %bb.0: @ %entry
+; CHECK-ARM-NEXT:    add r1, r1, #32
+; CHECK-ARM-NEXT:    lsr r0, r0, r1
+; CHECK-ARM-NEXT:    bx lr
+;
+; CHECK-BE-LABEL: lsr_add_mod:
+; CHECK-BE:       @ %bb.0: @ %entry
+; CHECK-BE-NEXT:    add r1, r1, #32
+; CHECK-BE-NEXT:    lsr r0, r0, r1
+; CHECK-BE-NEXT:    bx lr
+;
+; CHECK-THUMB-LABEL: lsr_add_mod:
+; CHECK-THUMB:       @ %bb.0: @ %entry
+; CHECK-THUMB-NEXT:    adds r1, #32
+; CHECK-THUMB-NEXT:    lsrs r0, r1
+; CHECK-THUMB-NEXT:    bx lr
+;
+; CHECK-ALIGN-LABEL: lsr_add_mod:
+; CHECK-ALIGN:       @ %bb.0: @ %entry
+; CHECK-ALIGN-NEXT:    adds r1, #32
+; CHECK-ALIGN-NEXT:    lsrs r0, r1
+; CHECK-ALIGN-NEXT:    bx lr
+;
+; CHECK-V6M-LABEL: lsr_add_mod:
+; CHECK-V6M:       @ %bb.0: @ %entry
+; CHECK-V6M-NEXT:    adds r1, #32
+; CHECK-V6M-NEXT:    lsrs r0, r1
+; CHECK-V6M-NEXT:    bx lr
+entry:
+  %sa = add i32 %amt, 32
+  %r  = lshr i32 %val, %sa
+  ret i32 %r
+}
+
+; (amount = 32 - amt) => should become RSB/NEG then used by LSR (and in some targets may be lowered to ROR form).
+define i32 @lsr_sub_rsb(i32 %val, i32 %amt) #0 {
+; CHECK-LABEL: lsr_sub_rsb:
+; CHECK:       @ %bb.0: @ %entry
+; CHECK-NEXT:    rsb r1, r1, #32
+; CHECK-NEXT:    lsr r0, r0, r1
+; CHECK-NEXT:    bx lr
+;
+; CHECK-ARM-LABEL: lsr_sub_rsb:
+; CHECK-ARM:       @ %bb.0: @ %entry
+; CHECK-ARM-NEXT:    rsb r1, r1, #32
+; CHECK-ARM-NEXT:    lsr r0, r0, r1
+; CHECK-ARM-NEXT:    bx lr
+;
+; CHECK-BE-LABEL: lsr_sub_rsb:
+; CHECK-BE:       @ %bb.0: @ %entry
+; CHECK-BE-NEXT:    rsb r1, r1, #32
+; CHECK-BE-NEXT:    lsr r0, r0, r1
+; CHECK-BE-NEXT:    bx lr
+;
+; CHECK-THUMB-LABEL: lsr_sub_rsb:
+; CHECK-THUMB:       @ %bb.0: @ %entry
+; CHECK-THUMB-NEXT:    rsb.w r1, r1, #32
+; CHECK-THUMB-NEXT:    lsrs r0, r1
+; CHECK-THUMB-NEXT:    bx lr
+;
+; CHECK-ALIGN-LABEL: lsr_sub_rsb:
+; CHECK-ALIGN:       @ %bb.0: @ %entry
+; CHECK-ALIGN-NEXT:    rsb.w r1, r1, #32
+; CHECK-ALIGN-NEXT:    lsrs r0, r1
+; CHECK-ALIGN-NEXT:    bx lr
+;
+; CHECK-V6M-LABEL: lsr_sub_rsb:
+; CHECK-V6M:       @ %bb.0: @ %entry
+; CHECK-V6M-NEXT:    movs r2, #32
+; CHECK-V6M-NEXT:    subs r1, r2, r1
+; CHECK-V6M-NEXT:    lsrs r0, r1
+; CHECK-V6M-NEXT:    bx lr
+entry:
+  %sa = sub i32 32, %amt
+  %r  = lshr i32 %val, %sa
+  ret i32 %r
+}
+
+; (amount = 31 - amt) => should become MVN(amt) then used by LSR.
+define i32 @lsr_sub_mvn(i32 %val, i32 %amt) #0 {
+; CHECK-LABEL: lsr_sub_mvn:
+; CHECK:       @ %bb.0: @ %entry
+; CHECK-NEXT:    rsb r1, r1, #31
+; CHECK-NEXT:    lsr r0, r0, r1
+; CHECK-NEXT:    bx lr
+;
+; CHECK-ARM-LABEL: lsr_sub_mvn:
+; CHECK-ARM:       @ %bb.0: @ %entry
+; CHECK-ARM-NEXT:    rsb r1, r1, #31
+; CHECK-ARM-NEXT:    lsr r0, r0, r1
+; CHECK-ARM-NEXT:    bx lr
+;
+; CHECK-BE-LABEL: lsr_sub_mvn:
+; CHECK-BE:       @ %bb.0: @ %entry
+; CHECK-BE-NEXT:    rsb r1, r1, #31
+; CHECK-BE-NEXT:    lsr r0, r0, r1
+; CHECK-BE-NEXT:    bx lr
+;
+; CHECK-THUMB-LABEL: lsr_sub_mvn:
+; CHECK-THUMB:       @ %bb.0: @ %entry
+; CHECK-THUMB-NEXT:    rsb.w r1, r1, #31
+; CHECK-THUMB-NEXT:    lsrs r0, r1
+; CHECK-THUMB-NEXT:    bx lr
+;
+; CHECK-ALIGN-LABEL: lsr_sub_mvn:
+; CHECK-ALIGN:       @ %bb.0: @ %entry
+; CHECK-ALIGN-NEXT:    rsb.w r1, r1, #31
+; CHECK-ALIGN-NEXT:    lsrs r0, r1
+; CHECK-ALIGN-NEXT:    bx lr
+;
+; CHECK-V6M-LABEL: lsr_sub_mvn:
+; CHECK-V6M:       @ %bb.0: @ %entry
+; CHECK-V6M-NEXT:    movs r2, #31
+; CHECK-V6M-NEXT:    subs r1, r2, r1
+; CHECK-V6M-NEXT:    lsrs r0, r1
+; CHECK-V6M-NEXT:    bx lr
+entry:
+  %sa = sub i32 31, %amt
+  %r  = lshr i32 %val, %sa
+  ret i32 %r
+}
+
+; (amount = amt & 31) => AND is redundant; should be removed and emit LSR only.
+define i32 @lsr_and_mask(i32 %val, i32 %amt) #0 {
+; CHECK-LABEL: lsr_and_mask:
+; CHECK:       @ %bb.0: @ %entry
+; CHECK-NEXT:    and r1, r1, #31
+; CHECK-NEXT:    lsr r0, r0, r1
+; CHECK-NEXT:    bx lr
+;
+; CHECK-ARM-LABEL: lsr_and_mask:
+; CHECK-ARM:       @ %bb.0: @ %entry
+; CHECK-ARM-NEXT:    and r1, r1, #31
+; CHECK-ARM-NEXT:    lsr r0, r0, r1
+; CHECK-ARM-NEXT:    bx lr
+;
+; CHECK-BE-LABEL: lsr_and_mask:
+; CHECK-BE:       @ %bb.0: @ %entry
+; CHECK-BE-NEXT:    and r1, r1, #31
+; CHECK-BE-NEXT:    lsr r0, r0, r1
+; CHECK-BE-NEXT:    bx lr
+;
+; CHECK-THUMB-LABEL: lsr_and_mask:
+; CHECK-THUMB:       @ %bb.0: @ %entry
+; CHECK-THUMB-NEXT:    and r1, r1, #31
+; CHECK-THUMB-NEXT:    lsrs r0, r1
+; CHECK-THUMB-NEXT:    bx lr
+;
+; CHECK-ALIGN-LABEL: lsr_and_mask:
+; CHECK-ALIGN:       @ %bb.0: @ %entry
+; CHECK-ALIGN-NEXT:    and r1, r1, #31
+; CHECK-ALIGN-NEXT:    lsrs r0, r1
+; CHECK-ALIGN-NEXT:    bx lr
+;
+; CHECK-V6M-LABEL: lsr_and_mask:
+; CHECK-V6M:       @ %bb.0: @ %entry
+; CHECK-V6M-NEXT:    movs r2, #31
+; CHECK-V6M-NEXT:    ands r2, r1
+; CHECK-V6M-NEXT:    lsrs r0, r2
+; CHECK-V6M-NEXT:    bx lr
+entry:
+  %sa = and i32 %amt, 31
+  %r  = lshr i32 %val, %sa
+  ret i32 %r
+}
+
+; -----------------------------------------------------------------
+; ASR (arithmetic right) group
+; -----------------------------------------------------------------
+
+; (amount = amt + 32) => should remove the ADD and emit ASR directly.
+; CHECK-LABEL: asr_add_mod:
+; CHECK-NOT: add
+; CHECK: asr
+; THUMB-LABEL: asr_add_mod:
+; THUMB-NOT: add
+; THUMB: asr
+define i32 @asr_add_mod(i32 %val, i32 %amt) #0 {
+; CHECK-LABEL: asr_add_mod:
+; CHECK:       @ %bb.0: @ %entry
+; CHECK-NEXT:    add r1, r1, #32
+; CHECK-NEXT:    asr r0, r0, r1
+; CHECK-NEXT:    bx lr
+;
+; CHECK-ARM-LABEL: asr_add_mod:
+; CHECK-ARM:       @ %bb.0: @ %entry
+; CHECK-ARM-NEXT:    add r1, r1, #32
+; CHECK-ARM-NEXT:    asr r0, r0, r1
+; CHECK-ARM-NEXT:    bx lr
+;
+; CHECK-BE-LABEL: asr_add_mod:
+; CHECK-BE:       @ %bb.0: @ %entry
+; CHECK-BE-NEXT:    add r1, r1, #32
+; CHECK-BE-NEXT:    asr r0, r0, r1
+; CHECK-BE-NEXT:    bx lr
+;
+; CHECK-THUMB-LABEL: asr_add_mod:
+; CHECK-THUMB:       @ %bb.0: @ %entry
+; CHECK-THUMB-NEXT:    adds r1, #32
+; CHECK-THUMB-NEXT:    asrs r0, r1
+; CHECK-THUMB-NEXT:    bx lr
+;
+; CHECK-ALIGN-LABEL: asr_add_mod:
+; CHECK-ALIGN:       @ %bb.0: @ %entry
+; CHECK-ALIGN-NEXT:    adds r1, #32
+; CHECK-ALIGN-NEXT:    asrs r0, r1
+; CHECK-ALIGN-NEXT:    bx lr
+;
+; CHECK-V6M-LABEL: asr_add_mod:
+; CHECK-V6M:       @ %bb.0: @ %entry
+; CHECK-V6M-NEXT:    adds r1, #32
+; CHECK-V6M-NEXT:    asrs r0, r1
+; CHECK-V6M-NEXT:    bx lr
+entry:
+  %sa = add i32 %amt, 32
+  %r  = ashr i32 %val, %sa
+  ret i32 %r
+}
+
+; (amount = 32 - amt) => should become RSB/NEG then used by ASR.
+; CHECK-LABEL: asr_sub_rsb:
+; CHECK: rsb
+; CHECK: asr
+; THUMB-LABEL: asr_sub_rsb:
+; THUMB: rsb
+; THUMB: asr
+define i32 @asr_sub_rsb(i32 %val, i32 %amt) #0 {
+; CHECK-LABEL: asr_sub_rsb:
+; CHECK:       @ %bb.0: @ %entry
+; CHECK-NEXT:    rsb r1, r1, #32
+; CHECK-NEXT:    asr r0, r0, r1
+; CHECK-NEXT:    bx lr
+;
+; CHECK-ARM-LABEL: asr_sub_rsb:
+; CHECK-ARM:       @ %bb.0: @ %entry
+; CHECK-ARM-NEXT:    rsb r1, r1, #32
+; CHECK-ARM-NEXT:    asr r0, r0, r1
+; CHECK-ARM-NEXT:    bx lr
+;
+; CHECK-BE-LABEL: asr_sub_rsb:
+; CHECK-BE:       @ %bb.0: @ %entry
+; CHECK-BE-NEXT:    rsb r1, r1, #32
+; CHECK-BE-NEXT:    asr r0, r0, r1
+; CHECK-BE-NEXT:    bx lr
+;
+; CHECK-THUMB-LABEL: asr_sub_rsb:
+; CHECK-THUMB:       @ %bb.0: @ %entry
+; CHECK-THUMB-NEXT:    rsb.w r1, r1, #32
+; CHECK-THUMB-NEXT:    asrs r0, r1
+; CHECK-THUMB-NEXT:    bx lr
+;
+; CHECK-ALIGN-LABEL: asr_sub_rsb:
+; CHECK-ALIGN:       @ %bb.0: @ %entry
+; CHECK-ALIGN-NEXT:    rsb.w r1, r1, #32
+; CHECK-ALIGN-NEXT:    asrs r0, r1
+; CHECK-ALIGN-NEXT:    bx lr
+;
+; CHECK-V6M-LABEL: asr_sub_rsb:
+; CHECK-V6M:       @ %bb.0: @ %entry
+; CHECK-V6M-NEXT:    movs r2, #32
+; CHECK-V6M-NEXT:    subs r1, r2, r1
+; CHECK-V6M-NEXT:    asrs r0, r1
+; CHECK-V6M-NEXT:    bx lr
+entry:
+  %sa = sub i32 32, %amt
+  %r  = ashr i32 %val, %sa
+  ret i32 %r
+}
+
+; (amount = 31 - amt) => should become MVN(amt) then used by ASR.
+; CHECK-LABEL: asr_sub_mvn:
+; CHECK: mvn
+; CHECK: asr
+; THUMB-LABEL: asr_sub_mvn:
+; THUMB: mvn
+; THUMB: asr
+define i32 @asr_sub_mvn(i32 %val, i32 %amt) #0 {
+; CHECK-LABEL: asr_sub_mvn:
+; CHECK:       @ %bb.0: @ %entry
+; CHECK-NEXT:    rsb r1, r1, #31
+; CHECK-NEXT:    asr r0, r0, r1
+; CHECK-NEXT:    bx lr
+;
+; CHECK-ARM-LABEL: asr_sub_mvn:
+; CHECK-ARM:       @ %bb.0: @ %entry
+; CHECK-ARM-NEXT:    rsb r1, r1, #31
+; CHECK-ARM-NEXT:    asr r0, r0, r1
+; CHECK-ARM-NEXT:    bx lr
+;
+; CHECK-BE-LABEL: asr_sub_mvn:
+; CHECK-BE:       @ %bb.0: @ %entry
+; CHECK-BE-NEXT:    rsb r1, r1, #31
+; CHECK-BE-NEXT:    asr r0, r0, r1
+; CHECK-BE-NEXT:    bx lr
+;
+; CHECK-THUMB-LABEL: asr_sub_mvn:
+; CHECK-THUMB:       @ %bb.0: @ %entry
+; CHECK-THUMB-NEXT:    rsb.w r1, r1, #31
+; CHECK-THUMB-NEXT:    asrs r0, r1
+; CHECK-THUMB-NEXT:    bx lr
+;
+; CHECK-ALIGN-LABEL: asr_sub_mvn:
+; CHECK-ALIGN:       @ %bb.0: @ %entry
+; CHECK-ALIGN-NEXT:    rsb.w r1, r1, #31
+; CHECK-ALIGN-NEXT:    asrs r0, r1
+; CHECK-ALIGN-NEXT:    bx lr
+;
+; CHECK-V6M-LABEL: asr_sub_mvn:
+; CHECK-V6M:       @ %bb.0: @ %entry
+; CHECK-V6M-NEXT:    movs r2, #31
+; CHECK-V6M-NEXT:    subs r1, r2, r1
+; CHECK-V6M-NEXT:    asrs r0, r1
+; CHECK-V6M-NEXT:    bx lr
+entry:
+  %sa = sub i32 31, %amt
+  %r  = ashr i32 %val, %sa
+  ret i32 %r
+}
+
+; (amount = amt & 31) => AND is redundant; should be removed and emit ASR only.
+; CHECK-LABEL: asr_and_mask:
+; CHECK-NOT: and
+; CHECK: asr
+; THUMB-LABEL: asr_and_mask:
+; THUMB-NOT: and
+; THUMB: asr
+define i32 @asr_and_mask(i32 %val, i32 %amt) #0 {
+; CHECK-LABEL: asr_and_mask:
+; CHECK:       @ %bb.0: @ %entry
+; CHECK-NEXT:    and r1, r1, #31
+; CHECK-NEXT:    asr r0, r0, r1
+; CHECK-NEXT:    bx lr
+;
+; CHECK-ARM-LABEL: asr_and_mask:
+; CHECK-ARM:       @ %bb.0: @ %entry
+; CHECK-ARM-NEXT:    and r1, r1, #31
+; CHECK-ARM-NEXT:    asr r0, r0, r1
+; CHECK-ARM-NEXT:    bx lr
+;
+; CHECK-BE-LABEL: asr_and_mask:
+; CHECK-BE:       @ %bb.0: @ %entry
+; CHECK-BE-NEXT:    and r1, r1, #31
+; CHECK-BE-NEXT:    asr r0, r0, r1
+; CHECK-BE-NEXT:    bx lr
+;
+; CHECK-THUMB-LABEL: asr_and_mask:
+; CHECK-THUMB:       @ %bb.0: @ %entry
+; CHECK-THUMB-NEXT:    and r1, r1, #31
+; CHECK-THUMB-NEXT:    asrs r0, r1
+; CHECK-THUMB-NEXT:    bx lr
+;
+; CHECK-ALIGN-LABEL: asr_and_mask:
+; CHECK-ALIGN:       @ %bb.0: @ %entry
+; CHECK-ALIGN-NEXT:    and r1, r1, #31
+; CHECK-ALIGN-NEXT:    asrs r0, r1
+; CHECK-ALIGN-NEXT:    bx lr
+;
+; CHECK-V6M-LABEL: asr_and_mask:
+; CHECK-V6M:       @ %bb.0: @ %entry
+; CHECK-V6M-NEXT:    movs r2, #31
+; CHECK-V6M-NEXT:    ands r2, r1
+; CHECK-V6M-NEXT:    asrs r0, r2
+; CHECK-V6M-NEXT:    bx lr
+entry:
+  %sa = and i32 %amt, 31
+  %r  = ashr i32 %val, %sa
+  ret i32 %r
+}
+
+; (amount = amt + 32) => remove ADD and emit ROR/LSR as appropriate (we check for absence of ADD and presence of LSR/ROR)
+define i32 @ror_add_mod(i32 %val, i32 %amt) #0 {
+; CHECK-LABEL: ror_add_mod:
+; CHECK:       @ %bb.0: @ %entry
+; CHECK-NEXT:    add r1, r1, #32
+; CHECK-NEXT:    lsr r0, r0, r1
+; CHECK-NEXT:    bx lr
+;
+; CHECK-ARM-LABEL: ror_add_mod:
+; CHECK-ARM:       @ %bb.0: @ %entry
+; CHECK-ARM-NEXT:    add r1, r1, #32
+; CHECK-ARM-NEXT:    lsr r0, r0, r1
+; CHECK-ARM-NEXT:    bx lr
+;
+; CHECK-BE-LABEL: ror_add_mod:
+; CHECK-BE:       @ %bb.0: @ %entry
+; CHECK-BE-NEXT:    add r1, r1, #32
+; CHECK-BE-NEXT:    lsr r0, r0, r1
+; CHECK-BE-NEXT:    bx lr
+;
+; CHECK-THUMB-LABEL: ror_add_mod:
+; CHECK-THUMB:       @ %bb.0: @ %entry
+; CHECK-THUMB-NEXT:    adds r1, #32
+; CHECK-THUMB-NEXT:    lsrs r0, r1
+; CHECK-THUMB-NEXT:    bx lr
+;
+; CHECK-ALIGN-LABEL: ror_add_mod:
+; CHECK-ALIGN:       @ %bb.0: @ %entry
+; CHECK-ALIGN-NEXT:    adds r1, #32
+; CHECK-ALIGN-NEXT:    lsrs r0, r1
+; CHECK-ALIGN-NEXT:    bx lr
+;
+; CHECK-V6M-LABEL: ror_add_mod:
+; CHECK-V6M:       @ %bb.0: @ %entry
+; CHECK-V6M-NEXT:    adds r1, #32
+; CHECK-V6M-NEXT:    lsrs r0, r1
+; CHECK-V6M-NEXT:    bx lr
+entry:
+  %sa = add i32 %amt, 32
+  %r  = lshr i32 %val, %sa
+  ret i32 %r
+}
+
+define i32 @ror_sub_rsb(i32 %val, i32 %amt) #0 {
+; CHECK-LABEL: ror_sub_rsb:
+; CHECK:       @ %bb.0: @ %entry
+; CHECK-NEXT:    rsb r1, r1, #32
+; CHECK-NEXT:    lsr r0, r0, r1
+; CHECK-NEXT:    bx lr
+;
+; CHECK-ARM-LABEL: ror_sub_rsb:
+; CHECK-ARM:       @ %bb.0: @ %entry
+; CHECK-ARM-NEXT:    rsb r1, r1, #32
+; CHECK-ARM-NEXT:    lsr r0, r0, r1
+; CHECK-ARM-NEXT:    bx lr
+;
+; CHECK-BE-LABEL: ror_sub_rsb:
+; CHECK-BE:       @ %bb.0: @ %entry
+; CHECK-BE-NEXT:    rsb r1, r1, #32
+; CHECK-BE-NEXT:    lsr r0, r0, r1
+; CHECK-BE-NEXT:    bx lr
+;
+; CHECK-THUMB-LABEL: ror_sub_rsb:
+; CHECK-THUMB:       @ %bb.0: @ %entry
+; CHECK-THUMB-NEXT:    rsb.w r1, r1, #32
+; CHECK-THUMB-NEXT:    lsrs r0, r1
+; CHECK-THUMB-NEXT:    bx lr
+;
+; CHECK-ALIGN-LABEL: ror_sub_rsb:
+; CHECK-ALIGN:       @ %bb.0: @ %entry
+; CHECK-ALIGN-NEXT:    rsb.w r1, r1, #32
+; CHECK-ALIGN-NEXT:    lsrs r0, r1
+; CHECK-ALIGN-NEXT:    bx lr
+;
+; CHECK-V6M-LABEL: ror_sub_rsb:
+; CHECK-V6M:       @ %bb.0: @ %entry
+; CHECK-V6M-NEXT:    movs r2, #32
+; CHECK-V6M-NEXT:    subs r1, r2, r1
+; CHECK-V6M-NEXT:    lsrs r0, r1
+; CHECK-V6M-NEXT:    bx lr
+entry:
+  %sa = sub i32 32, %amt
+  %r  = lshr i32 %val, %sa
+  ret i32 %r
+}
+
+define i32 @ror_sub_mvn(i32 %val, i32 %amt) #0 {
+; CHECK-LABEL: ror_sub_mvn:
+; CHECK:       @ %bb.0: @ %entry
+; CHECK-NEXT:    rsb r1, r1, #31
+; CHECK-NEXT:    lsr r0, r0, r1
+; CHECK-NEXT:    bx lr
+;
+; CHECK-ARM-LABEL: ror_sub_mvn:
+; CHECK-ARM:       @ %bb.0: @ %entry
+; CHECK-ARM-NEXT:    rsb r1, r1, #31
+; CHECK-ARM-NEXT:    lsr r0, r0, r1
+; CHECK-ARM-NEXT:    bx lr
+;
+; CHECK-BE-LABEL: ror_sub_mvn:
+; CHECK-BE:       @ %bb.0: @ %entry
+; CHECK-BE-NEXT:    rsb r1, r1, #31
+; CHECK-BE-NEXT:    lsr r0, r0, r1
+; CHECK-BE-NEXT:    bx lr
+;
+; CHECK-THUMB-LABEL: ror_sub_mvn:
+; CHECK-THUMB:       @ %bb.0: @ %entry
+; CHECK-THUMB-NEXT:    rsb.w r1, r1, #31
+; CHECK-THUMB-NEXT:    lsrs r0, r1
+; CHECK-THUMB-NEXT:    bx lr
+;
+; CHECK-ALIGN-LABEL: ror_sub_mvn:
+; CHECK-ALIGN:       @ %bb.0: @ %entry
+; CHECK-ALIGN-NEXT:    rsb.w r1, r1, #31
+; CHECK-ALIGN-NEXT:    lsrs r0, r1
+; CHECK-ALIGN-NEXT:    bx lr
+;
+; CHECK-V6M-LABEL: ror_sub_mvn:
+; CHECK-V6M:       @ %bb.0: @ %entry
+; CHECK-V6M-NEXT:    movs r2, #31
+; CHECK-V6M-NEXT:    subs r1, r2, r1
+; CHECK-V6M-NEXT:    lsrs r0, r1
+; CHECK-V6M-NEXT:    bx lr
+entry:
+  %sa = sub i32 31, %amt
+  %r  = lshr i32 %val, %sa
+  ret i32 %r
+}
+
+define i32 @ror_and_mask(i32 %val, i32 %amt) #0 {
+; CHECK-LABEL: ror_and_mask:
+; CHECK:       @ %bb.0: @ %entry
+; CHECK-NEXT:    and r1, r1, #31
+; CHECK-NEXT:    lsr r0, r0, r1
+; CHECK-NEXT:    bx lr
+;
+; CHECK-ARM-LABEL: ror_and_mask:
+; CHECK-ARM:       @ %bb.0: @ %entry
+; CHECK-ARM-NEXT:    and r1, r1, #31
+; CHECK-ARM-NEXT:    lsr r0, r0, r1
+; CHECK-ARM-NEXT:    bx lr
+;
+; CHECK-BE-LABEL: ror_and_mask:
+; CHECK-BE:       @ %bb.0: @ %entry
+; CHECK-BE-NEXT:    and r1, r1, #31
+; CHECK-BE-NEXT:    lsr r0, r0, r1
+; CHECK-BE-NEXT:    bx lr
+;
+; CHECK-THUMB-LABEL: ror_and_mask:
+; CHECK-THUMB:       @ %bb.0: @ %entry
+; CHECK-THUMB-NEXT:    and r1, r1, #31
+; CHECK-THUMB-NEXT:    lsrs r0, r1
+; CHECK-THUMB-NEXT:    bx lr
+;
+; CHECK-ALIGN-LABEL: ror_and_mask:
+; CHECK-ALIGN:       @ %bb.0: @ %entry
+; CHECK-ALIGN-NEXT:    and r1, r1, #31
+; CHECK-ALIGN-NEXT:    lsrs r0, r1
+; CHECK-ALIGN-NEXT:    bx lr
+;
+; CHECK-V6M-LABEL: ror_and_mask:
+; CHECK-V6M:       @ %bb.0: @ %entry
+; CHECK-V6M-NEXT:    movs r2, #31
+; CHECK-V6M-NEXT:    ands r2, r1
+; CHECK-V6M-NEXT:    lsrs r0, r2
+; CHECK-V6M-NEXT:    bx lr
+entry:
+  %sa = and i32 %amt, 31
+  %r  = lshr i32 %val, %sa
+  ret i32 %r
+}
+
+
+declare i32 @llvm.fshl.i32(i32, i32, i32)
+declare i32 @llvm.fshr.i32(i32, i32, i32)
+
+; -----------------------
+; fshl (funnel-shift left) group
+; fshl(x,x, s) == rotate-left(x, s)
+; -----------------------
+
+; amt + 32 -> REMOVE ADD (mod 32), expect rotate lowering (ror/lsl/lsr depending on selector)
+define i32 @fshl_add_mod(i32 %x, i32 %amt) #0 {
+; CHECK-ARM-LABEL: fshl_add_mod:
+; CHECK-ARM:       @ %bb.0: @ %entry
+; CHECK-ARM-NEXT:    mvn r2, #31
+; CHECK-ARM-NEXT:    sub r1, r2, r1
+; CHECK-ARM-NEXT:    ror r0, r0, r1
+; CHECK-ARM-NEXT:    bx lr
+;
+; CHECK-BE-LABEL: fshl_add_mod:
+; CHECK-BE:       @ %bb.0: @ %entry
+; CHECK-BE-NEXT:    mvn r2, #31
+; CHECK-BE-NEXT:    sub r1, r2, r1
+; CHECK-BE-NEXT:    ror r0, r0, r1
+; CHECK-BE-NEXT:    bx lr
+;
+; CHECK-THUMB-LABEL: fshl_add_mod:
+; CHECK-THUMB:       @ %bb.0: @ %entry
+; CHECK-THUMB-NEXT:    mvn r2, #31
+; CHECK-THUMB-NEXT:    subs r1, r2, r1
+; CHECK-THUMB-NEXT:    rors r0, r1
+; CHECK-THUMB-NEXT:    bx lr
+;
+; CHECK-ALIGN-LABEL: fshl_add_mod:
+; CHECK-ALIGN:       @ %bb.0: @ %entry
+; CHECK-ALIGN-NEXT:    mvn r2, #31
+; CHECK-ALIGN-NEXT:    subs r1, r2, r1
+; CHECK-ALIGN-NEXT:    rors r0, r1
+; CHECK-ALIGN-NEXT:    bx lr
+;
+; CHECK-V6M-LABEL: fshl_add_mod:
+; CHECK-V6M:       @ %bb.0: @ %entry
+; CHECK-V6M-NEXT:    movs r2, #31
+; CHECK-V6M-NEXT:    mvns r2, r2
+; CHECK-V6M-NEXT:    subs r1, r2, r1
+; CHECK-V6M-NEXT:    rors r0, r1
+; CHECK-V6M-NEXT:    bx lr
+entry:
+  %sa = add i32 %amt, 32
+  %r  = call i32 @llvm.fshl.i32(i32 %x, i32 %x, i32 %sa)
+  ret i32 %r
+}
+
+; 32 - amt -> expect RSB/NEG materialization then rotate lowering
+; CHECK-LABEL: fshl_sub_rsb:
+; CHECK: rsb
+; CHECK: ror
+; THUMB-LABEL: fshl_sub_rsb:
+; THUMB: rsb
+; THUMB: ror
+define i32 @fshl_sub_rsb(i32 %x, i32 %amt) #0 {
+; CHECK-ARM-LABEL: fshl_sub_rsb:
+; CHECK-ARM:       @ %bb.0: @ %entry
+; CHECK-ARM-NEXT:    sub r1, r1, #32
+; CHECK-ARM-NEXT:    ror r0, r0, r1
+; CHECK-ARM-NEXT:    bx lr
+;
+; CHECK-BE-LABEL: fshl_sub_rsb:
+; CHECK-BE:       @ %bb.0: @ %entry
+; CHECK-BE-NEXT:    sub r1, r1, #32
+; CHECK-BE-NEXT:    ror r0, r0, r1
+; CHECK-BE-NEXT:    bx lr
+;
+; CHECK-THUMB-LABEL: fshl_sub_rsb:
+; CHECK-THUMB:       @ %bb.0: @ %entry
+; CHECK-THUMB-NEXT:    subs r1, #32
+; CHECK-THUMB-NEXT:    rors r0, r1
+; CHECK-THUMB-NEXT:    bx lr
+;
+; CHECK-ALIGN-LABEL: fshl_sub_rsb:
+; CHECK-ALIGN:       @ %bb.0: @ %entry
+; CHECK-ALIGN-NEXT:    subs r1, #32
+; CHECK-ALIGN-NEXT:    rors r0, r1
+; CHECK-ALIGN-NEXT:    bx lr
+;
+; CHECK-V6M-LABEL: fshl_sub_rsb:
+; CHECK-V6M:       @ %bb.0: @ %entry
+; CHECK-V6M-NEXT:    subs r1, #32
+; CHECK-V6M-NEXT:    rors r0, r1
+; CHECK-V6M-NEXT:    bx lr
+entry:
+  %sa = sub i32 32, %amt
+  %r  = call i32 @llvm.fshl.i32(i32 %x, i32 %x, i32 %sa)
+  ret i32 %r
+}
+
+; 31 - amt -> expect MVN(amt) (i.e. NOT) then rotate lowering (selector may use NOT+rotate form)
+; CHECK-LABEL: fshl_sub_mvn:
+; CHECK: mvn
+; CHECK: ror
+; THUMB-LABEL: fshl_sub_mvn:
+; THUMB: mvn
+; THUMB: ror
+define i32 @fshl_sub_mvn(i32 %x, i32 %amt) #0 {
+; CHECK-ARM-LABEL: fshl_sub_mvn:
+; CHECK-ARM:       @ %bb.0: @ %entry
+; CHECK-ARM-NEXT:    sub r1, r1, #31
+; CHECK-ARM-NEXT:    ror r0, r0, r1
+; CHECK-ARM-NEXT:    bx lr
+;
+; CHECK-BE-LABEL: fshl_sub_mvn:
+; CHECK-BE:       @ %bb.0: @ %entry
+; CHECK-BE-NEXT:    sub r1, r1, #31
+; CHECK-BE-NEXT:    ror r0, r0, r1
+; CHECK-BE-NEXT:    bx lr
+;
+; CHECK-THUMB-LABEL: fshl_sub_mvn:
+; CHECK-THUMB:       @ %bb.0: @ %entry
+; CHECK-THUMB-NEXT:    subs r1, #31
+; CHECK-THUMB-NEXT:    rors r0, r1
+; CHECK-THUMB-NEXT:    bx lr
+;
+; CHECK-ALIGN-LABEL: fshl_sub_mvn:
+; CHECK-ALIGN:       @ %bb.0: @ %entry
+; CHECK-ALIGN-NEXT:    subs r1, #31
+; CHECK-ALIGN-NEXT:    rors r0, r1
+; CHECK-ALIGN-NEXT:    bx lr
+;
+; CHECK-V6M-LABEL: fshl_sub_mvn:
+; CHECK-V6M:       @ %bb.0: @ %entry
+; CHECK-V6M-NEXT:    subs r1, #31
+; CHECK-V6M-NEXT:    rors r0, r1
+; CHECK-V6M-NEXT:    bx lr
+entry:
+  %sa = sub i32 31, %amt
+  %r  = call i32 @llvm.fshl.i32(i32 %x, i32 %x, i32 %sa)
+  ret i32 %r
+}
+
+; amt & 31 -> AND redundant (hardware masks low 5 bits) -> expect rotate lowering with no AND
+define i32 @fshl_and_mask(i32 %x, i32 %amt) #0 {
+; CHECK-ARM-LABEL: fshl_and_mask:
+; CHECK-ARM:       @ %bb.0: @ %entry
+; CHECK-ARM-NEXT:    rsb r1, r1, #0
+; CHECK-ARM-NEXT:    ror r0, r0, r1
+; CHECK-ARM-NEXT:    bx lr
+;
+; CHECK-BE-LABEL: fshl_and_mask:
+; CHECK-BE:       @ %bb.0: @ %entry
+; CHECK-BE-NEXT:    rsb r1, r1, #0
+; CHECK-BE-NEXT:    ror r0, r0, r1
+; CHECK-BE-NEXT:    bx lr
+;
+; CHECK-THUMB-LABEL: fshl_and_mask:
+; CHECK-THUMB:       @ %bb.0: @ %entry
+; CHECK-THUMB-NEXT:    rsbs r1, r1, #0
+; CHECK-THUMB-NEXT:    rors r0, r1
+; CHECK-THUMB-NEXT:    bx lr
+;
+; CHECK-ALIGN-LABEL: fshl_and_mask:
+; CHECK-ALIGN:       @ %bb.0: @ %entry
+; CHECK-ALIGN-NEXT:    rsbs r1, r1, #0
+; CHECK-ALIGN-NEXT:    rors r0, r1
+; CHECK-ALIGN-NEXT:    bx lr
+;
+; CHECK-V6M-LABEL: fshl_and_mask:
+; CHECK-V6M:       @ %bb.0: @ %entry
+; CHECK-V6M-NEXT:    rsbs r1, r1, #0
+; CHECK-V6M-NEXT:    rors r0, r1
+; CHECK-V6M-NEXT:    bx lr
+entry:
+  %sa = and i32 %amt, 31
+  %r  = call i32 @llvm.fshl.i32(i32 %x, i32 %x, i32 %sa)
+  ret i32 %r
+}
+
+; -----------------------
+; fshr (funnel-shift right) group
+; fshr(x,x, s) == rotate-right(x, s)
+; -----------------------
+
+; amt + 32 -> REMOVE ADD (mod 32) -> expect rotate lowering
+define i32 @fshr_add_mod(i32 %x, i32 %amt) #0 {
+; CHECK-ARM-LABEL: fshr_add_mod:
+; CHECK-ARM:       @ %bb.0: @ %entry
+; CHECK-ARM-NEXT:    add r1, r1, #32
+; CHECK-ARM-NEXT:    ror r0, r0, r1
+; CHECK-ARM-NEXT:    bx lr
+;
+; CHECK-BE-LABEL: fshr_add_mod:
+; CHECK-BE:       @ %bb.0: @ %entry
+; CHECK-BE-NEXT:    add r1, r1, #32
+; CHECK-BE-NEXT:    ror r0, r0, r1
+; CHECK-BE-NEXT:    bx lr
+;
+; CHECK-THUMB-LABEL: fshr_add_mod:
+; CHECK-THUMB:       @ %bb.0: @ %entry
+; CHECK-THUMB-NEXT:    adds r1, #32
+; CHECK-THUMB-NEXT:    rors r0, r1
+; CHECK-THUMB-NEXT:    bx lr
+;
+; CHECK-ALIGN-LABEL: fshr_add_mod:
+; CHECK-ALIGN:       @ %bb.0: @ %entry
+; CHECK-ALIGN-NEXT:    adds r1, #32
+; CHECK-ALIGN-NEXT:    rors r0, r1
+; CHECK-ALIGN-NEXT:    bx lr
+;
+; CHECK-V6M-LABEL: fshr_add_mod:
+; CHECK-V6M:       @ %bb.0: @ %entry
+; CHECK-V6M-NEXT:    adds r1, #32
+; CHECK-V6M-NEXT:    rors r0, r1
+; CHECK-V6M-NEXT:    bx lr
+entry:
+  %sa = add i32 %amt, 32
+  %r  = call i32 @llvm.fshr.i32(i32 %x, i32 %x, i32 %sa)
+  ret i32 %r
+}
+
+; 32 - amt -> expect RSB then rotate lowering
+define i32 @fshr_sub_rsb(i32 %x, i32 %amt) #0 {
+; CHECK-ARM-LABEL: fshr_sub_rsb:
+; CHECK-ARM:       @ %bb.0: @ %entry
+; CHECK-ARM-NEXT:    rsb r1, r1, #32
+; CHECK-ARM-NEXT:    ror r0, r0, r1
+; CHECK-ARM-NEXT:    bx lr
+;
+; CHECK-BE-LABEL: fshr_sub_rsb:
+; CHECK-BE:       @ %bb.0: @ %entry
+; CHECK-BE-NEXT:    rsb r1, r1, #32
+; CHECK-BE-NEXT:    ror r0, r0, r1
+; CHECK-BE-NEXT:    bx lr
+;
+; CHECK-THUMB-LABEL: fshr_sub_rsb:
+; CHECK-THUMB:       @ %bb.0: @ %entry
+; CHECK-THUMB-NEXT:    rsb.w r1, r1, #32
+; CHECK-THUMB-NEXT:    rors r0, r1
+; CHECK-THUMB-NEXT:    bx lr
+;
+; CHECK-ALIGN-LABEL: fshr_sub_rsb:
+; CHECK-ALIGN:       @ %bb.0: @ %entry
+; CHECK-ALIGN-NEXT:    rsb.w r1, r1, #32
+; CHECK-ALIGN-NEXT:    rors r0, r1
+; CHECK-ALIGN-NEXT:    bx lr
+;
+; CHECK-V6M-LABEL: fshr_sub_rsb:
+; CHECK-V6M:       @ %bb.0: @ %entry
+; CHECK-V6M-NEXT:    movs r2, #32
+; CHECK-V6M-NEXT:    subs r1, r2, r1
+; CHECK-V6M-NEXT:    rors r0, r1
+; CHECK-V6M-NEXT:    bx lr
+entry:
+  %sa = sub i32 32, %amt
+  %r  = call i32 @llvm.fshr.i32(i32 %x, i32 %x, i32 %sa)
+  ret i32 %r
+}
+
+; 31 - amt -> expect MVN then rotate lowering
+define i32 @fshr_sub_mvn(i32 %x, i32 %amt) #0 {
+; CHECK-ARM-LABEL: fshr_sub_mvn:
+; CHECK-ARM:       @ %bb.0: @ %entry
+; CHECK-ARM-NEXT:    rsb r1, r1, #31
+; CHECK-ARM-NEXT:    ror r0, r0, r1
+; CHECK-ARM-NEXT:    bx lr
+;
+; CHECK-BE-LABEL: fshr_sub_mvn:
+; CHECK-BE:       @ %bb.0: @ %entry
+; CHECK-BE-NEXT:    rsb r1, r1, #31
+; CHECK-BE-NEXT:    ror r0, r0, r1
+; CHECK-BE-NEXT:    bx lr
+;
+; CHECK-THUMB-LABEL: fshr_sub_mvn:
+; CHECK-THUMB:       @ %bb.0: @ %entry
+; CHECK-THUMB-NEXT:    rsb.w r1, r1, #31
+; CHECK-THUMB-NEXT:    rors r0, r1
+; CHECK-THUMB-NEXT:    bx lr
+;
+; CHECK-ALIGN-LABEL: fshr_sub_mvn:
+; CHECK-ALIGN:       @ %bb.0: @ %entry
+; CHECK-ALIGN-NEXT:    rsb.w r1, r1, #31
+; CHECK-ALIGN-NEXT:    rors r0, r1
+; CHECK-ALIGN-NEXT:    bx lr
+;
+; CHECK-V6M-LABEL: fshr_sub_mvn:
+; CHECK-V6M:       @ %bb.0: @ %entry
+; CHECK-V6M-NEXT:    movs r2, #31
+; CHECK-V6M-NEXT:    subs r1, r2, r1
+; CHECK-V6M-NEXT:    rors r0, r1
+; CHECK-V6M-NEXT:    bx lr
+entry:
+  %sa = sub i32 31, %amt
+  %r  = call i32 @llvm.fshr.i32(i32 %x, i32 %x, i32 %sa)
+  ret i32 %r
+}
+
+; amt & 31 -> AND redundant -> expect rotate lowering with no AND
+define i32 @fshr_and_mask(i32 %x, i32 %amt) #0 {
+; CHECK-ARM-LABEL: fshr_and_mask:
+; CHECK-ARM:       @ %bb.0: @ %entry
+; CHECK-ARM-NEXT:    ror r0, r0, r1
+; CHECK-ARM-NEXT:    bx lr
+;
+; CHECK-BE-LABEL: fshr_and_mask:
+; CHECK-BE:       @ %bb.0: @ %entry
+; CHECK-BE-NEXT:    ror r0, r0, r1
+; CHECK-BE-NEXT:    bx lr
+;
+; CHECK-THUMB-LABEL: fshr_and_mask:
+; CHECK-THUMB:       @ %bb.0: @ %entry
+; CHECK-THUMB-NEXT:    rors r0, r1
+; CHECK-THUMB-NEXT:    bx lr
+;
+; CHECK-ALIGN-LABEL: fshr_and_mask:
+; CHECK-ALIGN:       @ %bb.0: @ %entry
+; CHECK-ALIGN-NEXT:    rors r0, r1
+; CHECK-ALIGN-NEXT:    bx lr
+;
+; CHECK-V6M-LABEL: fshr_and_mask:
+; CHECK-V6M:       @ %bb.0: @ %entry
+; CHECK-V6M-NEXT:    rors r0, r1
+; CHECK-V6M-NEXT:    bx lr
+entry:
+  %sa = and i32 %amt, 31
+  %r  = call i32 @llvm.fshr.i32(i32 %x, i32 %x, i32 %sa)
+  ret i32 %r
+}
+
+;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
+; CHECK-COMMON: {{.*}}

>From ee37cdca903580b6ea6802aeedc9f01f94be87e3 Mon Sep 17 00:00:00 2001
From: AZero13 <gfunni234 at gmail.com>
Date: Fri, 5 Sep 2025 12:19:34 -0400
Subject: [PATCH 2/2] [ARM] Take advantage of built-in mod of shift amount in
 variable-shift rotations

---
 .../Target/AArch64/AArch64ISelDAGToDAG.cpp    |   2 +-
 llvm/lib/Target/ARM/ARMISelDAGToDAG.cpp       | 156 +++++++++++++++
 llvm/test/CodeGen/ARM/funnel-shift-rot.ll     |  20 +-
 llvm/test/CodeGen/ARM/funnel-shift.ll         | 120 ++++++-----
 ...st-and-by-const-from-lshr-in-eqcmp-zero.ll |  47 ++---
 ...ist-and-by-const-from-shl-in-eqcmp-zero.ll |  40 +---
 llvm/test/CodeGen/ARM/rotate-add.ll           |   3 +-
 llvm/test/CodeGen/ARM/shift-i64.ll            |   2 +-
 llvm/test/CodeGen/ARM/shift-mod.ll            | 188 ++++++------------
 llvm/test/CodeGen/ARM/shifter_operand.ll      |   2 -
 llvm/test/CodeGen/Thumb2/shift_parts.ll       |  59 +++---
 llvm/test/CodeGen/Thumb2/thumb2-shifter.ll    |   3 -
 12 files changed, 336 insertions(+), 306 deletions(-)

diff --git a/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp b/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp
index 6fdc981fc21a5..28e84fe4ce88b 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp
@@ -527,7 +527,7 @@ char AArch64DAGToDAGISelLegacy::ID = 0;
 INITIALIZE_PASS(AArch64DAGToDAGISelLegacy, DEBUG_TYPE, PASS_NAME, false, false)
 
 /// isIntImmediate - This method tests to see if the node is a constant
-/// operand. If so Imm will receive the 32-bit value.
+/// operand. If so Imm will receive the 64-bit value.
 static bool isIntImmediate(const SDNode *N, uint64_t &Imm) {
   if (const ConstantSDNode *C = dyn_cast<const ConstantSDNode>(N)) {
     Imm = C->getZExtValue();
diff --git a/llvm/lib/Target/ARM/ARMISelDAGToDAG.cpp b/llvm/lib/Target/ARM/ARMISelDAGToDAG.cpp
index 9ad46df159c20..4427a6fed52a7 100644
--- a/llvm/lib/Target/ARM/ARMISelDAGToDAG.cpp
+++ b/llvm/lib/Target/ARM/ARMISelDAGToDAG.cpp
@@ -306,6 +306,8 @@ class ARMDAGToDAGISel : public SelectionDAGISel {
 
   bool tryInsertVectorElt(SDNode *N);
 
+  bool tryShiftAmountMod(SDNode *N);
+
   // Select special operations if node forms integer ABS pattern
   bool tryABSOp(SDNode *N);
 
@@ -3158,6 +3160,152 @@ bool ARMDAGToDAGISel::tryInsertVectorElt(SDNode *N) {
   return false;
 }
 
+/// tryShiftAmountMod - Take advantage of built-in mod of shift amount in
+/// variable shift/rotate instructions.
+bool ARMDAGToDAGISel::tryShiftAmountMod(SDNode *N) {
+  EVT VT = N->getValueType(0);
+
+  if (VT != MVT::i32)
+    return false;
+
+  unsigned Opc;
+  switch (N->getOpcode()) {
+  case ISD::ROTR:
+    Opc = Subtarget->isThumb()
+              ? (Subtarget->hasThumb2() ? ARM::t2RORrr : ARM::tROR)
+              : ARM::MOVsr;
+    break;
+  case ISD::SHL:
+    Opc = Subtarget->isThumb()
+              ? (Subtarget->hasThumb2() ? ARM::t2LSLrr : ARM::tLSLrr)
+              : ARM::MOVsr;
+    break;
+  case ISD::SRL:
+    Opc = Subtarget->isThumb()
+              ? (Subtarget->hasThumb2() ? ARM::t2LSRrr : ARM::tLSRrr)
+              : ARM::MOVsr;
+    break;
+  case ISD::SRA:
+    Opc = Subtarget->isThumb()
+              ? (Subtarget->hasThumb2() ? ARM::t2ASRrr : ARM::tASRrr)
+              : ARM::MOVsr;
+    break;
+  default:
+    return false;
+  }
+
+  SDValue ShiftAmt = N->getOperand(1);
+  SDLoc DL(N);
+  SDValue NewShiftAmt;
+
+  if (ShiftAmt->getOpcode() == ISD::ADD || ShiftAmt->getOpcode() == ISD::SUB) {
+    SDValue Add0 = ShiftAmt->getOperand(0);
+    SDValue Add1 = ShiftAmt->getOperand(1);
+    unsigned Add0Imm;
+    unsigned Add1Imm;
+
+    if (isInt32Immediate(Add1, Add1Imm) && ((Add1Imm & 31) == 0)) {
+      NewShiftAmt = Add0;
+    } else if (ShiftAmt->getOpcode() == ISD::SUB &&
+               isInt32Immediate(Add0, Add0Imm) && Add0Imm != 0 &&
+               ((Add0Imm & 31) == 0)) {
+
+      unsigned NegOpc =
+          Subtarget->isThumb()
+              ? (Subtarget->hasThumb2() ? ARM::t2RSBri : ARM::tRSB)
+              : ARM::RSBri;
+
+      SDValue ZeroImm = CurDAG->getTargetConstant(0, DL, MVT::i32);
+
+      if (Subtarget->isThumb2()) {
+        SDValue Ops[] = {Add1, ZeroImm, getAL(CurDAG, DL),
+                         CurDAG->getRegister(0, MVT::i32),
+                         CurDAG->getRegister(0, MVT::i32)};
+        MachineSDNode *Neg = CurDAG->getMachineNode(NegOpc, DL, MVT::i32, Ops);
+        NewShiftAmt = SDValue(Neg, 0);
+      } else if (Subtarget->isThumb1Only()) {
+        SDValue Ops[] = {CurDAG->getRegister(ARM::CPSR, MVT::i32), Add1,
+                         getAL(CurDAG, DL), CurDAG->getRegister(0, MVT::i32)};
+        MachineSDNode *Neg = CurDAG->getMachineNode(NegOpc, DL, MVT::i32, Ops);
+        NewShiftAmt = SDValue(Neg, 0);
+      } else {
+        SDValue Ops[] = {Add1, ZeroImm, getAL(CurDAG, DL),
+                         CurDAG->getRegister(0, MVT::i32),
+                         CurDAG->getRegister(0, MVT::i32)};
+        MachineSDNode *Neg = CurDAG->getMachineNode(NegOpc, DL, MVT::i32, Ops);
+        NewShiftAmt = SDValue(Neg, 0);
+      }
+    } else if (ShiftAmt->getOpcode() == ISD::SUB &&
+               isInt32Immediate(Add0, Add0Imm) && ((Add0Imm & 31) == 31)) {
+      unsigned NotOpc = Subtarget->isThumb()
+                            ? (Subtarget->isThumb2() ? ARM::t2MVNr : ARM::tMVN)
+                            : ARM::MVNr;
+
+      if (Subtarget->isThumb2()) {
+        SDValue Ops[] = {Add1, getAL(CurDAG, DL),
+                         CurDAG->getRegister(0, MVT::i32),
+                         CurDAG->getRegister(0, MVT::i32)};
+        MachineSDNode *Not = CurDAG->getMachineNode(NotOpc, DL, MVT::i32, Ops);
+        NewShiftAmt = SDValue(Not, 0);
+      } else if (Subtarget->isThumb1Only()) {
+        SDValue Ops[] = {CurDAG->getRegister(ARM::CPSR, MVT::i32), Add1,
+                         getAL(CurDAG, DL), CurDAG->getRegister(0, MVT::i32)};
+        MachineSDNode *Not = CurDAG->getMachineNode(NotOpc, DL, MVT::i32, Ops);
+        NewShiftAmt = SDValue(Not, 0);
+      } else {
+        SDValue Ops[] = {Add1, getAL(CurDAG, DL),
+                         CurDAG->getRegister(0, MVT::i32),
+                         CurDAG->getRegister(0, MVT::i32)};
+        MachineSDNode *Not = CurDAG->getMachineNode(NotOpc, DL, MVT::i32, Ops);
+        NewShiftAmt = SDValue(Not, 0);
+      }
+    } else {
+      return false;
+    }
+  } else {
+    // Check if shift amount is masked with AND covering low 5 bits
+    unsigned MaskImm;
+    if (!isOpcWithIntImmediate(ShiftAmt.getNode(), ISD::AND, MaskImm))
+      return false;
+
+    if ((unsigned)llvm::countr_one(MaskImm) < 5)
+      return false;
+
+    NewShiftAmt = ShiftAmt->getOperand(0);
+  }
+
+  if (Subtarget->isThumb()) {
+    if (Subtarget->isThumb1Only()) {
+      SDValue Ops[] = {CurDAG->getRegister(ARM::CPSR, MVT::i32),
+                       N->getOperand(0), NewShiftAmt, getAL(CurDAG, DL),
+                       CurDAG->getRegister(0, MVT::i32)};
+      CurDAG->SelectNodeTo(N, Opc, VT, Ops);
+    } else {
+      SDValue Ops[] = {N->getOperand(0), NewShiftAmt, getAL(CurDAG, DL),
+                       CurDAG->getRegister(0, MVT::i32),
+                       CurDAG->getRegister(0, MVT::i32)};
+      CurDAG->SelectNodeTo(N, Opc, VT, Ops);
+    }
+  } else {
+    ARM_AM::ShiftOpc ShOpcVal = ARM_AM::getShiftOpcForNode(N->getOpcode());
+    if (ShOpcVal == ARM_AM::no_shift)
+      return false;
+
+    SDValue BaseReg = N->getOperand(0);
+    SDValue ShReg = NewShiftAmt;
+    SDValue OpcEnc = CurDAG->getTargetConstant(ARM_AM::getSORegOpc(ShOpcVal, 0),
+                                               DL, MVT::i32);
+    SDValue Ops[] = {BaseReg,
+                     ShReg,
+                     OpcEnc,
+                     getAL(CurDAG, DL),
+                     CurDAG->getRegister(0, MVT::i32),
+                     CurDAG->getRegister(0, MVT::i32)};
+    CurDAG->SelectNodeTo(N, Opc, VT, Ops);
+  }
+  return true;
+}
+
 bool ARMDAGToDAGISel::transformFixedFloatingPointConversion(SDNode *N,
                                                             SDNode *FMul,
                                                             bool IsUnsigned,
@@ -3770,11 +3918,19 @@ void ARMDAGToDAGISel::Select(SDNode *N) {
   case ISD::SRL:
     if (tryV6T2BitfieldExtractOp(N, false))
       return;
+    if (tryShiftAmountMod(N))
+      return;
     break;
   case ISD::SIGN_EXTEND_INREG:
   case ISD::SRA:
     if (tryV6T2BitfieldExtractOp(N, true))
       return;
+    [[fallthrough]];
+  case ISD::ROTR:
+  case ISD::SHL:
+    if (tryShiftAmountMod(N))
+      return;
+    break;
     break;
   case ISD::FP_TO_UINT:
   case ISD::FP_TO_SINT:
diff --git a/llvm/test/CodeGen/ARM/funnel-shift-rot.ll b/llvm/test/CodeGen/ARM/funnel-shift-rot.ll
index a1b6847d623d0..dd5c5ee4f26c2 100644
--- a/llvm/test/CodeGen/ARM/funnel-shift-rot.ll
+++ b/llvm/test/CodeGen/ARM/funnel-shift-rot.ll
@@ -73,17 +73,16 @@ define i64 @rotl_i64(i64 %x, i64 %z) {
 ; CHECK-NEXT:    push {r4, lr}
 ; CHECK-NEXT:    tst r2, #32
 ; CHECK-NEXT:    mov r3, r0
-; CHECK-NEXT:    and r12, r2, #31
 ; CHECK-NEXT:    movne r3, r1
 ; CHECK-NEXT:    movne r1, r0
-; CHECK-NEXT:    mov r4, #31
-; CHECK-NEXT:    bic r2, r4, r2
-; CHECK-NEXT:    lsl lr, r3, r12
-; CHECK-NEXT:    lsr r0, r1, #1
-; CHECK-NEXT:    lsl r1, r1, r12
-; CHECK-NEXT:    lsr r3, r3, #1
-; CHECK-NEXT:    orr r0, lr, r0, lsr r2
-; CHECK-NEXT:    orr r1, r1, r3, lsr r2
+; CHECK-NEXT:    mov r0, #31
+; CHECK-NEXT:    bic r4, r0, r2
+; CHECK-NEXT:    lsr lr, r1, #1
+; CHECK-NEXT:    lsl r12, r3, r2
+; CHECK-NEXT:    lsl r1, r1, r2
+; CHECK-NEXT:    lsr r2, r3, #1
+; CHECK-NEXT:    orr r0, r12, lr, lsr r4
+; CHECK-NEXT:    orr r1, r1, r2, lsr r4
 ; CHECK-NEXT:    pop {r4, pc}
   %f = call i64 @llvm.fshl.i64(i64 %x, i64 %x, i64 %z)
   ret i64 %f
@@ -210,9 +209,8 @@ define i64 @rotr_i64(i64 %x, i64 %z) {
 ; CHECK-NEXT:    mov r3, r1
 ; CHECK-NEXT:    moveq r3, r0
 ; CHECK-NEXT:    moveq r0, r1
-; CHECK-NEXT:    mov r1, #31
+; CHECK-NEXT:    mvn r1, r2
 ; CHECK-NEXT:    lsl r12, r0, #1
-; CHECK-NEXT:    bic r1, r1, r2
 ; CHECK-NEXT:    and r2, r2, #31
 ; CHECK-NEXT:    lsl r12, r12, r1
 ; CHECK-NEXT:    orr r12, r12, r3, lsr r2
diff --git a/llvm/test/CodeGen/ARM/funnel-shift.ll b/llvm/test/CodeGen/ARM/funnel-shift.ll
index 191155ae30f3e..f48bf9ef8ef82 100644
--- a/llvm/test/CodeGen/ARM/funnel-shift.ll
+++ b/llvm/test/CodeGen/ARM/funnel-shift.ll
@@ -32,10 +32,9 @@ define i32 @fshl_i32(i32 %x, i32 %y, i32 %z) {
 ; CHECK-LABEL: fshl_i32:
 ; CHECK:       @ %bb.0:
 ; CHECK-NEXT:    mov r3, #31
-; CHECK-NEXT:    lsr r1, r1, #1
-; CHECK-NEXT:    bic r3, r3, r2
-; CHECK-NEXT:    and r2, r2, #31
 ; CHECK-NEXT:    lsl r0, r0, r2
+; CHECK-NEXT:    bic r3, r3, r2
+; CHECK-NEXT:    lsr r1, r1, #1
 ; CHECK-NEXT:    orr r0, r0, r1, lsr r3
 ; CHECK-NEXT:    bx lr
   %f = call i32 @llvm.fshl.i32(i32 %x, i32 %y, i32 %z)
@@ -47,9 +46,9 @@ declare i37 @llvm.fshl.i37(i37, i37, i37)
 define i37 @fshl_i37(i37 %x, i37 %y, i37 %z) {
 ; SCALAR-LABEL: fshl_i37:
 ; SCALAR:       @ %bb.0:
-; SCALAR-NEXT:    .save {r4, r5, r6, r7, r8, lr}
-; SCALAR-NEXT:    push {r4, r5, r6, r7, r8, lr}
-; SCALAR-NEXT:    mov r8, r0
+; SCALAR-NEXT:    .save {r4, r5, r6, r7, r11, lr}
+; SCALAR-NEXT:    push {r4, r5, r6, r7, r11, lr}
+; SCALAR-NEXT:    mov r7, r0
 ; SCALAR-NEXT:    ldr r0, [sp, #28]
 ; SCALAR-NEXT:    mov r4, r1
 ; SCALAR-NEXT:    mov r5, r3
@@ -60,30 +59,29 @@ define i37 @fshl_i37(i37 %x, i37 %y, i37 %z) {
 ; SCALAR-NEXT:    mov r3, #0
 ; SCALAR-NEXT:    bl __aeabi_uldivmod
 ; SCALAR-NEXT:    lsl r0, r5, #27
-; SCALAR-NEXT:    tst r2, #32
+; SCALAR-NEXT:    mov r5, #31
 ; SCALAR-NEXT:    orr r0, r0, r6, lsr #5
-; SCALAR-NEXT:    mov r1, r8
-; SCALAR-NEXT:    and r3, r2, #31
-; SCALAR-NEXT:    mov r7, #31
+; SCALAR-NEXT:    tst r2, #32
+; SCALAR-NEXT:    mov r1, r7
+; SCALAR-NEXT:    bic r5, r5, r2
 ; SCALAR-NEXT:    movne r1, r0
 ; SCALAR-NEXT:    lslne r0, r6, #27
-; SCALAR-NEXT:    bic r2, r7, r2
-; SCALAR-NEXT:    lsl r5, r1, r3
+; SCALAR-NEXT:    lsl r3, r1, r2
 ; SCALAR-NEXT:    lsr r0, r0, #1
-; SCALAR-NEXT:    movne r4, r8
+; SCALAR-NEXT:    movne r4, r7
 ; SCALAR-NEXT:    lsr r1, r1, #1
-; SCALAR-NEXT:    lsl r3, r4, r3
-; SCALAR-NEXT:    orr r0, r5, r0, lsr r2
-; SCALAR-NEXT:    orr r1, r3, r1, lsr r2
-; SCALAR-NEXT:    pop {r4, r5, r6, r7, r8, pc}
+; SCALAR-NEXT:    lsl r2, r4, r2
+; SCALAR-NEXT:    orr r0, r3, r0, lsr r5
+; SCALAR-NEXT:    orr r1, r2, r1, lsr r5
+; SCALAR-NEXT:    pop {r4, r5, r6, r7, r11, pc}
 ;
 ; NEON-LABEL: fshl_i37:
 ; NEON:       @ %bb.0:
-; NEON-NEXT:    .save {r4, r5, r6, r7, r8, lr}
-; NEON-NEXT:    push {r4, r5, r6, r7, r8, lr}
+; NEON-NEXT:    .save {r4, r5, r6, r7, r11, lr}
+; NEON-NEXT:    push {r4, r5, r6, r7, r11, lr}
 ; NEON-NEXT:    mov r4, r1
 ; NEON-NEXT:    ldr r1, [sp, #28]
-; NEON-NEXT:    mov r8, r0
+; NEON-NEXT:    mov r7, r0
 ; NEON-NEXT:    ldr r0, [sp, #24]
 ; NEON-NEXT:    and r1, r1, #31
 ; NEON-NEXT:    mov r5, r3
@@ -92,22 +90,21 @@ define i37 @fshl_i37(i37 %x, i37 %y, i37 %z) {
 ; NEON-NEXT:    mov r3, #0
 ; NEON-NEXT:    bl __aeabi_uldivmod
 ; NEON-NEXT:    lsl r0, r5, #27
-; NEON-NEXT:    tst r2, #32
+; NEON-NEXT:    mov r5, #31
 ; NEON-NEXT:    orr r0, r0, r6, lsr #5
-; NEON-NEXT:    mov r1, r8
-; NEON-NEXT:    and r3, r2, #31
-; NEON-NEXT:    mov r7, #31
+; NEON-NEXT:    tst r2, #32
+; NEON-NEXT:    mov r1, r7
+; NEON-NEXT:    bic r5, r5, r2
 ; NEON-NEXT:    movne r1, r0
 ; NEON-NEXT:    lslne r0, r6, #27
-; NEON-NEXT:    bic r2, r7, r2
-; NEON-NEXT:    lsl r5, r1, r3
+; NEON-NEXT:    lsl r3, r1, r2
 ; NEON-NEXT:    lsr r0, r0, #1
-; NEON-NEXT:    movne r4, r8
+; NEON-NEXT:    movne r4, r7
 ; NEON-NEXT:    lsr r1, r1, #1
-; NEON-NEXT:    lsl r3, r4, r3
-; NEON-NEXT:    orr r0, r5, r0, lsr r2
-; NEON-NEXT:    orr r1, r3, r1, lsr r2
-; NEON-NEXT:    pop {r4, r5, r6, r7, r8, pc}
+; NEON-NEXT:    lsl r2, r4, r2
+; NEON-NEXT:    orr r0, r3, r0, lsr r5
+; NEON-NEXT:    orr r1, r2, r1, lsr r5
+; NEON-NEXT:    pop {r4, r5, r6, r7, r11, pc}
   %f = call i37 @llvm.fshl.i37(i37 %x, i37 %y, i37 %z)
   ret i37 %f
 }
@@ -219,9 +216,8 @@ define i16 @fshr_i16(i16 %x, i16 %y, i16 %z) {
 define i32 @fshr_i32(i32 %x, i32 %y, i32 %z) {
 ; CHECK-LABEL: fshr_i32:
 ; CHECK:       @ %bb.0:
-; CHECK-NEXT:    mov r3, #31
+; CHECK-NEXT:    mvn r3, r2
 ; CHECK-NEXT:    lsl r0, r0, #1
-; CHECK-NEXT:    bic r3, r3, r2
 ; CHECK-NEXT:    and r2, r2, #31
 ; CHECK-NEXT:    lsl r0, r0, r3
 ; CHECK-NEXT:    orr r0, r0, r1, lsr r2
@@ -237,33 +233,32 @@ define i37 @fshr_i37(i37 %x, i37 %y, i37 %z) {
 ; SCALAR:       @ %bb.0:
 ; SCALAR-NEXT:    .save {r4, r5, r6, r7, r11, lr}
 ; SCALAR-NEXT:    push {r4, r5, r6, r7, r11, lr}
-; SCALAR-NEXT:    mov r5, r0
+; SCALAR-NEXT:    mov r7, r0
 ; SCALAR-NEXT:    ldr r0, [sp, #28]
 ; SCALAR-NEXT:    mov r4, r1
-; SCALAR-NEXT:    mov r6, r3
+; SCALAR-NEXT:    mov r5, r3
 ; SCALAR-NEXT:    and r1, r0, #31
 ; SCALAR-NEXT:    ldr r0, [sp, #24]
-; SCALAR-NEXT:    mov r7, r2
+; SCALAR-NEXT:    mov r6, r2
 ; SCALAR-NEXT:    mov r2, #37
 ; SCALAR-NEXT:    mov r3, #0
 ; SCALAR-NEXT:    bl __aeabi_uldivmod
 ; SCALAR-NEXT:    add r0, r2, #27
-; SCALAR-NEXT:    lsl r2, r6, #27
-; SCALAR-NEXT:    orr r2, r2, r7, lsr #5
-; SCALAR-NEXT:    mov r1, #31
+; SCALAR-NEXT:    lsl r2, r5, #27
+; SCALAR-NEXT:    orr r2, r2, r6, lsr #5
 ; SCALAR-NEXT:    tst r0, #32
-; SCALAR-NEXT:    mov r3, r5
+; SCALAR-NEXT:    mov r3, r7
+; SCALAR-NEXT:    mvn r1, r0
 ; SCALAR-NEXT:    moveq r3, r2
-; SCALAR-NEXT:    lsleq r2, r7, #27
-; SCALAR-NEXT:    bic r1, r1, r0
-; SCALAR-NEXT:    and r7, r0, #31
-; SCALAR-NEXT:    lsl r6, r3, #1
-; SCALAR-NEXT:    moveq r4, r5
-; SCALAR-NEXT:    lsl r6, r6, r1
-; SCALAR-NEXT:    orr r0, r6, r2, lsr r7
+; SCALAR-NEXT:    lsleq r2, r6, #27
+; SCALAR-NEXT:    and r6, r0, #31
+; SCALAR-NEXT:    lsl r5, r3, #1
+; SCALAR-NEXT:    moveq r4, r7
+; SCALAR-NEXT:    lsl r5, r5, r1
+; SCALAR-NEXT:    orr r0, r5, r2, lsr r6
 ; SCALAR-NEXT:    lsl r2, r4, #1
 ; SCALAR-NEXT:    lsl r1, r2, r1
-; SCALAR-NEXT:    orr r1, r1, r3, lsr r7
+; SCALAR-NEXT:    orr r1, r1, r3, lsr r6
 ; SCALAR-NEXT:    pop {r4, r5, r6, r7, r11, pc}
 ;
 ; NEON-LABEL: fshr_i37:
@@ -272,31 +267,30 @@ define i37 @fshr_i37(i37 %x, i37 %y, i37 %z) {
 ; NEON-NEXT:    push {r4, r5, r6, r7, r11, lr}
 ; NEON-NEXT:    mov r4, r1
 ; NEON-NEXT:    ldr r1, [sp, #28]
-; NEON-NEXT:    mov r5, r0
+; NEON-NEXT:    mov r7, r0
 ; NEON-NEXT:    ldr r0, [sp, #24]
 ; NEON-NEXT:    and r1, r1, #31
-; NEON-NEXT:    mov r6, r3
-; NEON-NEXT:    mov r7, r2
+; NEON-NEXT:    mov r5, r3
+; NEON-NEXT:    mov r6, r2
 ; NEON-NEXT:    mov r2, #37
 ; NEON-NEXT:    mov r3, #0
 ; NEON-NEXT:    bl __aeabi_uldivmod
 ; NEON-NEXT:    add r0, r2, #27
-; NEON-NEXT:    lsl r2, r6, #27
-; NEON-NEXT:    orr r2, r2, r7, lsr #5
-; NEON-NEXT:    mov r1, #31
+; NEON-NEXT:    lsl r2, r5, #27
+; NEON-NEXT:    orr r2, r2, r6, lsr #5
 ; NEON-NEXT:    tst r0, #32
-; NEON-NEXT:    mov r3, r5
+; NEON-NEXT:    mov r3, r7
+; NEON-NEXT:    mvn r1, r0
 ; NEON-NEXT:    moveq r3, r2
-; NEON-NEXT:    lsleq r2, r7, #27
-; NEON-NEXT:    bic r1, r1, r0
-; NEON-NEXT:    and r7, r0, #31
-; NEON-NEXT:    lsl r6, r3, #1
-; NEON-NEXT:    moveq r4, r5
-; NEON-NEXT:    lsl r6, r6, r1
-; NEON-NEXT:    orr r0, r6, r2, lsr r7
+; NEON-NEXT:    lsleq r2, r6, #27
+; NEON-NEXT:    and r6, r0, #31
+; NEON-NEXT:    lsl r5, r3, #1
+; NEON-NEXT:    moveq r4, r7
+; NEON-NEXT:    lsl r5, r5, r1
+; NEON-NEXT:    orr r0, r5, r2, lsr r6
 ; NEON-NEXT:    lsl r2, r4, #1
 ; NEON-NEXT:    lsl r1, r2, r1
-; NEON-NEXT:    orr r1, r1, r3, lsr r7
+; NEON-NEXT:    orr r1, r1, r3, lsr r6
 ; NEON-NEXT:    pop {r4, r5, r6, r7, r11, pc}
   %f = call i37 @llvm.fshr.i37(i37 %x, i37 %y, i37 %z)
   ret i37 %f
diff --git a/llvm/test/CodeGen/ARM/hoist-and-by-const-from-lshr-in-eqcmp-zero.ll b/llvm/test/CodeGen/ARM/hoist-and-by-const-from-lshr-in-eqcmp-zero.ll
index 7cc623fb0a616..5b732ef928455 100644
--- a/llvm/test/CodeGen/ARM/hoist-and-by-const-from-lshr-in-eqcmp-zero.ll
+++ b/llvm/test/CodeGen/ARM/hoist-and-by-const-from-lshr-in-eqcmp-zero.ll
@@ -20,7 +20,6 @@
 define i1 @scalar_i8_signbit_eq(i8 %x, i8 %y) nounwind {
 ; ARM-LABEL: scalar_i8_signbit_eq:
 ; ARM:       @ %bb.0:
-; ARM-NEXT:    uxtb r1, r1
 ; ARM-NEXT:    lsl r0, r0, r1
 ; ARM-NEXT:    mov r1, #1
 ; ARM-NEXT:    uxtb r0, r0
@@ -29,7 +28,6 @@ define i1 @scalar_i8_signbit_eq(i8 %x, i8 %y) nounwind {
 ;
 ; THUMB6-LABEL: scalar_i8_signbit_eq:
 ; THUMB6:       @ %bb.0:
-; THUMB6-NEXT:    uxtb r1, r1
 ; THUMB6-NEXT:    lsls r0, r1
 ; THUMB6-NEXT:    movs r1, #128
 ; THUMB6-NEXT:    ands r0, r1
@@ -39,7 +37,6 @@ define i1 @scalar_i8_signbit_eq(i8 %x, i8 %y) nounwind {
 ;
 ; THUMB78-LABEL: scalar_i8_signbit_eq:
 ; THUMB78:       @ %bb.0:
-; THUMB78-NEXT:    uxtb r1, r1
 ; THUMB78-NEXT:    lsls r0, r1
 ; THUMB78-NEXT:    movs r1, #1
 ; THUMB78-NEXT:    uxtb r0, r0
@@ -61,7 +58,6 @@ define i1 @scalar_i8_lowestbit_eq(i8 %x, i8 %y) nounwind {
 ;
 ; THUMB6-LABEL: scalar_i8_lowestbit_eq:
 ; THUMB6:       @ %bb.0:
-; THUMB6-NEXT:    uxtb r1, r1
 ; THUMB6-NEXT:    lsls r0, r1
 ; THUMB6-NEXT:    movs r1, #1
 ; THUMB6-NEXT:    ands r0, r1
@@ -71,7 +67,6 @@ define i1 @scalar_i8_lowestbit_eq(i8 %x, i8 %y) nounwind {
 ;
 ; THUMB78-LABEL: scalar_i8_lowestbit_eq:
 ; THUMB78:       @ %bb.0:
-; THUMB78-NEXT:    uxtb r1, r1
 ; THUMB78-NEXT:    lsls r0, r1
 ; THUMB78-NEXT:    movs r1, #1
 ; THUMB78-NEXT:    bic.w r0, r1, r0
@@ -94,7 +89,6 @@ define i1 @scalar_i8_bitsinmiddle_eq(i8 %x, i8 %y) nounwind {
 ;
 ; THUMB6-LABEL: scalar_i8_bitsinmiddle_eq:
 ; THUMB6:       @ %bb.0:
-; THUMB6-NEXT:    uxtb r1, r1
 ; THUMB6-NEXT:    lsls r0, r1
 ; THUMB6-NEXT:    movs r1, #24
 ; THUMB6-NEXT:    ands r0, r1
@@ -104,7 +98,6 @@ define i1 @scalar_i8_bitsinmiddle_eq(i8 %x, i8 %y) nounwind {
 ;
 ; THUMB78-LABEL: scalar_i8_bitsinmiddle_eq:
 ; THUMB78:       @ %bb.0:
-; THUMB78-NEXT:    uxtb r1, r1
 ; THUMB78-NEXT:    lsls r0, r1
 ; THUMB78-NEXT:    and r0, r0, #24
 ; THUMB78-NEXT:    clz r0, r0
@@ -121,7 +114,6 @@ define i1 @scalar_i8_bitsinmiddle_eq(i8 %x, i8 %y) nounwind {
 define i1 @scalar_i16_signbit_eq(i16 %x, i16 %y) nounwind {
 ; ARM-LABEL: scalar_i16_signbit_eq:
 ; ARM:       @ %bb.0:
-; ARM-NEXT:    uxth r1, r1
 ; ARM-NEXT:    lsl r0, r0, r1
 ; ARM-NEXT:    mov r1, #1
 ; ARM-NEXT:    uxth r0, r0
@@ -130,7 +122,6 @@ define i1 @scalar_i16_signbit_eq(i16 %x, i16 %y) nounwind {
 ;
 ; THUMB6-LABEL: scalar_i16_signbit_eq:
 ; THUMB6:       @ %bb.0:
-; THUMB6-NEXT:    uxth r1, r1
 ; THUMB6-NEXT:    lsls r0, r1
 ; THUMB6-NEXT:    movs r1, #1
 ; THUMB6-NEXT:    lsls r1, r1, #15
@@ -141,7 +132,6 @@ define i1 @scalar_i16_signbit_eq(i16 %x, i16 %y) nounwind {
 ;
 ; THUMB78-LABEL: scalar_i16_signbit_eq:
 ; THUMB78:       @ %bb.0:
-; THUMB78-NEXT:    uxth r1, r1
 ; THUMB78-NEXT:    lsls r0, r1
 ; THUMB78-NEXT:    movs r1, #1
 ; THUMB78-NEXT:    uxth r0, r0
@@ -163,7 +153,6 @@ define i1 @scalar_i16_lowestbit_eq(i16 %x, i16 %y) nounwind {
 ;
 ; THUMB6-LABEL: scalar_i16_lowestbit_eq:
 ; THUMB6:       @ %bb.0:
-; THUMB6-NEXT:    uxth r1, r1
 ; THUMB6-NEXT:    lsls r0, r1
 ; THUMB6-NEXT:    movs r1, #1
 ; THUMB6-NEXT:    ands r0, r1
@@ -173,7 +162,6 @@ define i1 @scalar_i16_lowestbit_eq(i16 %x, i16 %y) nounwind {
 ;
 ; THUMB78-LABEL: scalar_i16_lowestbit_eq:
 ; THUMB78:       @ %bb.0:
-; THUMB78-NEXT:    uxth r1, r1
 ; THUMB78-NEXT:    lsls r0, r1
 ; THUMB78-NEXT:    movs r1, #1
 ; THUMB78-NEXT:    bic.w r0, r1, r0
@@ -196,7 +184,6 @@ define i1 @scalar_i16_bitsinmiddle_eq(i16 %x, i16 %y) nounwind {
 ;
 ; THUMB6-LABEL: scalar_i16_bitsinmiddle_eq:
 ; THUMB6:       @ %bb.0:
-; THUMB6-NEXT:    uxth r1, r1
 ; THUMB6-NEXT:    lsls r0, r1
 ; THUMB6-NEXT:    movs r1, #255
 ; THUMB6-NEXT:    lsls r1, r1, #4
@@ -207,7 +194,6 @@ define i1 @scalar_i16_bitsinmiddle_eq(i16 %x, i16 %y) nounwind {
 ;
 ; THUMB78-LABEL: scalar_i16_bitsinmiddle_eq:
 ; THUMB78:       @ %bb.0:
-; THUMB78-NEXT:    uxth r1, r1
 ; THUMB78-NEXT:    lsls r0, r1
 ; THUMB78-NEXT:    and r0, r0, #4080
 ; THUMB78-NEXT:    clz r0, r0
@@ -330,7 +316,7 @@ define i1 @scalar_i32_bitsinmiddle_eq(i32 %x, i32 %y) nounwind {
 define i1 @scalar_i64_signbit_eq(i64 %x, i64 %y) nounwind {
 ; ARM-LABEL: scalar_i64_signbit_eq:
 ; ARM:       @ %bb.0:
-; ARM-NEXT:    rsb r3, r2, #32
+; ARM-NEXT:    rsb r3, r2, #0
 ; ARM-NEXT:    lsr r3, r0, r3
 ; ARM-NEXT:    orr r1, r3, r1, lsl r2
 ; ARM-NEXT:    subs r2, r2, #32
@@ -352,11 +338,11 @@ define i1 @scalar_i64_signbit_eq(i64 %x, i64 %y) nounwind {
 ;
 ; THUMB78-LABEL: scalar_i64_signbit_eq:
 ; THUMB78:       @ %bb.0:
-; THUMB78-NEXT:    rsb.w r3, r2, #32
+; THUMB78-NEXT:    rsbs r3, r2, #0
 ; THUMB78-NEXT:    lsls r1, r2
-; THUMB78-NEXT:    subs r2, #32
 ; THUMB78-NEXT:    lsr.w r3, r0, r3
-; THUMB78-NEXT:    orr.w r1, r1, r3
+; THUMB78-NEXT:    orrs r1, r3
+; THUMB78-NEXT:    subs.w r3, r2, #32
 ; THUMB78-NEXT:    it pl
 ; THUMB78-NEXT:    lslpl.w r1, r0, r2
 ; THUMB78-NEXT:    mvns r0, r1
@@ -415,7 +401,7 @@ define i1 @scalar_i64_lowestbit_eq(i64 %x, i64 %y) nounwind {
 define i1 @scalar_i64_bitsinmiddle_eq(i64 %x, i64 %y) nounwind {
 ; ARM6-LABEL: scalar_i64_bitsinmiddle_eq:
 ; ARM6:       @ %bb.0:
-; ARM6-NEXT:    rsb r3, r2, #32
+; ARM6-NEXT:    rsb r3, r2, #0
 ; ARM6-NEXT:    lsr r3, r0, r3
 ; ARM6-NEXT:    orr r1, r3, r1, lsl r2
 ; ARM6-NEXT:    subs r3, r2, #32
@@ -429,7 +415,7 @@ define i1 @scalar_i64_bitsinmiddle_eq(i64 %x, i64 %y) nounwind {
 ;
 ; ARM78-LABEL: scalar_i64_bitsinmiddle_eq:
 ; ARM78:       @ %bb.0:
-; ARM78-NEXT:    rsb r3, r2, #32
+; ARM78-NEXT:    rsb r3, r2, #0
 ; ARM78-NEXT:    lsr r3, r0, r3
 ; ARM78-NEXT:    orr r1, r3, r1, lsl r2
 ; ARM78-NEXT:    subs r3, r2, #32
@@ -459,17 +445,16 @@ define i1 @scalar_i64_bitsinmiddle_eq(i64 %x, i64 %y) nounwind {
 ;
 ; THUMB78-LABEL: scalar_i64_bitsinmiddle_eq:
 ; THUMB78:       @ %bb.0:
-; THUMB78-NEXT:    rsb.w r3, r2, #32
+; THUMB78-NEXT:    rsbs r3, r2, #0
 ; THUMB78-NEXT:    lsls r1, r2
 ; THUMB78-NEXT:    lsr.w r3, r0, r3
-; THUMB78-NEXT:    orrs r1, r3
-; THUMB78-NEXT:    subs.w r3, r2, #32
-; THUMB78-NEXT:    it pl
-; THUMB78-NEXT:    lslpl.w r1, r0, r3
-; THUMB78-NEXT:    lsl.w r0, r0, r2
-; THUMB78-NEXT:    it pl
+; THUMB78-NEXT:    lsls r0, r2
+; THUMB78-NEXT:    subs r2, #32
+; THUMB78-NEXT:    mov r2, r0
+; THUMB78-NEXT:    ite mi
+; THUMB78-NEXT:    orrmi.w r2, r3, r1
 ; THUMB78-NEXT:    movpl r0, #0
-; THUMB78-NEXT:    pkhbt r0, r1, r0
+; THUMB78-NEXT:    pkhbt r0, r2, r0
 ; THUMB78-NEXT:    clz r0, r0
 ; THUMB78-NEXT:    lsrs r0, r0, #5
 ; THUMB78-NEXT:    bx lr
@@ -864,7 +849,6 @@ define <4 x i1> @vec_4xi32_nonsplat_undef2_eq(<4 x i32> %x, <4 x i32> %y) nounwi
 define i1 @scalar_i8_signbit_ne(i8 %x, i8 %y) nounwind {
 ; ARM-LABEL: scalar_i8_signbit_ne:
 ; ARM:       @ %bb.0:
-; ARM-NEXT:    uxtb r1, r1
 ; ARM-NEXT:    lsl r0, r0, r1
 ; ARM-NEXT:    uxtb r0, r0
 ; ARM-NEXT:    lsr r0, r0, #7
@@ -872,7 +856,6 @@ define i1 @scalar_i8_signbit_ne(i8 %x, i8 %y) nounwind {
 ;
 ; THUMB-LABEL: scalar_i8_signbit_ne:
 ; THUMB:       @ %bb.0:
-; THUMB-NEXT:    uxtb r1, r1
 ; THUMB-NEXT:    lsls r0, r1
 ; THUMB-NEXT:    uxtb r0, r0
 ; THUMB-NEXT:    lsrs r0, r0, #7
@@ -986,7 +969,6 @@ define i1 @negative_scalar_i8_bitsinmiddle_slt(i8 %x, i8 %y) nounwind {
 ;
 ; THUMB6-LABEL: negative_scalar_i8_bitsinmiddle_slt:
 ; THUMB6:       @ %bb.0:
-; THUMB6-NEXT:    uxtb r1, r1
 ; THUMB6-NEXT:    movs r2, #24
 ; THUMB6-NEXT:    lsrs r2, r1
 ; THUMB6-NEXT:    ands r2, r0
@@ -1000,7 +982,6 @@ define i1 @negative_scalar_i8_bitsinmiddle_slt(i8 %x, i8 %y) nounwind {
 ;
 ; THUMB78-LABEL: negative_scalar_i8_bitsinmiddle_slt:
 ; THUMB78:       @ %bb.0:
-; THUMB78-NEXT:    uxtb r1, r1
 ; THUMB78-NEXT:    movs r2, #24
 ; THUMB78-NEXT:    lsr.w r1, r2, r1
 ; THUMB78-NEXT:    ands r0, r1
@@ -1027,7 +1008,6 @@ define i1 @scalar_i8_signbit_eq_with_nonzero(i8 %x, i8 %y) nounwind {
 ;
 ; THUMB6-LABEL: scalar_i8_signbit_eq_with_nonzero:
 ; THUMB6:       @ %bb.0:
-; THUMB6-NEXT:    uxtb r1, r1
 ; THUMB6-NEXT:    movs r2, #128
 ; THUMB6-NEXT:    lsrs r2, r1
 ; THUMB6-NEXT:    ands r2, r0
@@ -1038,7 +1018,6 @@ define i1 @scalar_i8_signbit_eq_with_nonzero(i8 %x, i8 %y) nounwind {
 ;
 ; THUMB78-LABEL: scalar_i8_signbit_eq_with_nonzero:
 ; THUMB78:       @ %bb.0:
-; THUMB78-NEXT:    uxtb r1, r1
 ; THUMB78-NEXT:    movs r2, #128
 ; THUMB78-NEXT:    lsr.w r1, r2, r1
 ; THUMB78-NEXT:    ands r0, r1
diff --git a/llvm/test/CodeGen/ARM/hoist-and-by-const-from-shl-in-eqcmp-zero.ll b/llvm/test/CodeGen/ARM/hoist-and-by-const-from-shl-in-eqcmp-zero.ll
index a8421ae9a6a89..fb07d205c8e23 100644
--- a/llvm/test/CodeGen/ARM/hoist-and-by-const-from-shl-in-eqcmp-zero.ll
+++ b/llvm/test/CodeGen/ARM/hoist-and-by-const-from-shl-in-eqcmp-zero.ll
@@ -20,7 +20,6 @@
 define i1 @scalar_i8_signbit_eq(i8 %x, i8 %y) nounwind {
 ; ARM-LABEL: scalar_i8_signbit_eq:
 ; ARM:       @ %bb.0:
-; ARM-NEXT:    uxtb r1, r1
 ; ARM-NEXT:    uxtb r0, r0
 ; ARM-NEXT:    lsr r0, r0, r1
 ; ARM-NEXT:    mov r1, #1
@@ -29,7 +28,6 @@ define i1 @scalar_i8_signbit_eq(i8 %x, i8 %y) nounwind {
 ;
 ; THUMB6-LABEL: scalar_i8_signbit_eq:
 ; THUMB6:       @ %bb.0:
-; THUMB6-NEXT:    uxtb r1, r1
 ; THUMB6-NEXT:    uxtb r0, r0
 ; THUMB6-NEXT:    lsrs r0, r1
 ; THUMB6-NEXT:    movs r1, #128
@@ -40,7 +38,6 @@ define i1 @scalar_i8_signbit_eq(i8 %x, i8 %y) nounwind {
 ;
 ; THUMB78-LABEL: scalar_i8_signbit_eq:
 ; THUMB78:       @ %bb.0:
-; THUMB78-NEXT:    uxtb r1, r1
 ; THUMB78-NEXT:    uxtb r0, r0
 ; THUMB78-NEXT:    lsrs r0, r1
 ; THUMB78-NEXT:    movs r1, #1
@@ -63,7 +60,6 @@ define i1 @scalar_i8_lowestbit_eq(i8 %x, i8 %y) nounwind {
 ;
 ; THUMB6-LABEL: scalar_i8_lowestbit_eq:
 ; THUMB6:       @ %bb.0:
-; THUMB6-NEXT:    uxtb r1, r1
 ; THUMB6-NEXT:    uxtb r0, r0
 ; THUMB6-NEXT:    lsrs r0, r1
 ; THUMB6-NEXT:    movs r1, #1
@@ -74,7 +70,6 @@ define i1 @scalar_i8_lowestbit_eq(i8 %x, i8 %y) nounwind {
 ;
 ; THUMB78-LABEL: scalar_i8_lowestbit_eq:
 ; THUMB78:       @ %bb.0:
-; THUMB78-NEXT:    uxtb r1, r1
 ; THUMB78-NEXT:    uxtb r0, r0
 ; THUMB78-NEXT:    lsrs r0, r1
 ; THUMB78-NEXT:    movs r1, #1
@@ -99,7 +94,6 @@ define i1 @scalar_i8_bitsinmiddle_eq(i8 %x, i8 %y) nounwind {
 ;
 ; THUMB6-LABEL: scalar_i8_bitsinmiddle_eq:
 ; THUMB6:       @ %bb.0:
-; THUMB6-NEXT:    uxtb r1, r1
 ; THUMB6-NEXT:    uxtb r0, r0
 ; THUMB6-NEXT:    lsrs r0, r1
 ; THUMB6-NEXT:    movs r1, #24
@@ -110,7 +104,6 @@ define i1 @scalar_i8_bitsinmiddle_eq(i8 %x, i8 %y) nounwind {
 ;
 ; THUMB78-LABEL: scalar_i8_bitsinmiddle_eq:
 ; THUMB78:       @ %bb.0:
-; THUMB78-NEXT:    uxtb r1, r1
 ; THUMB78-NEXT:    uxtb r0, r0
 ; THUMB78-NEXT:    lsrs r0, r1
 ; THUMB78-NEXT:    and r0, r0, #24
@@ -128,7 +121,6 @@ define i1 @scalar_i8_bitsinmiddle_eq(i8 %x, i8 %y) nounwind {
 define i1 @scalar_i16_signbit_eq(i16 %x, i16 %y) nounwind {
 ; ARM-LABEL: scalar_i16_signbit_eq:
 ; ARM:       @ %bb.0:
-; ARM-NEXT:    uxth r1, r1
 ; ARM-NEXT:    uxth r0, r0
 ; ARM-NEXT:    lsr r0, r0, r1
 ; ARM-NEXT:    mov r1, #1
@@ -137,7 +129,6 @@ define i1 @scalar_i16_signbit_eq(i16 %x, i16 %y) nounwind {
 ;
 ; THUMB6-LABEL: scalar_i16_signbit_eq:
 ; THUMB6:       @ %bb.0:
-; THUMB6-NEXT:    uxth r1, r1
 ; THUMB6-NEXT:    uxth r0, r0
 ; THUMB6-NEXT:    lsrs r0, r1
 ; THUMB6-NEXT:    movs r1, #1
@@ -149,7 +140,6 @@ define i1 @scalar_i16_signbit_eq(i16 %x, i16 %y) nounwind {
 ;
 ; THUMB78-LABEL: scalar_i16_signbit_eq:
 ; THUMB78:       @ %bb.0:
-; THUMB78-NEXT:    uxth r1, r1
 ; THUMB78-NEXT:    uxth r0, r0
 ; THUMB78-NEXT:    lsrs r0, r1
 ; THUMB78-NEXT:    movs r1, #1
@@ -172,7 +162,6 @@ define i1 @scalar_i16_lowestbit_eq(i16 %x, i16 %y) nounwind {
 ;
 ; THUMB6-LABEL: scalar_i16_lowestbit_eq:
 ; THUMB6:       @ %bb.0:
-; THUMB6-NEXT:    uxth r1, r1
 ; THUMB6-NEXT:    uxth r0, r0
 ; THUMB6-NEXT:    lsrs r0, r1
 ; THUMB6-NEXT:    movs r1, #1
@@ -183,7 +172,6 @@ define i1 @scalar_i16_lowestbit_eq(i16 %x, i16 %y) nounwind {
 ;
 ; THUMB78-LABEL: scalar_i16_lowestbit_eq:
 ; THUMB78:       @ %bb.0:
-; THUMB78-NEXT:    uxth r1, r1
 ; THUMB78-NEXT:    uxth r0, r0
 ; THUMB78-NEXT:    lsrs r0, r1
 ; THUMB78-NEXT:    movs r1, #1
@@ -208,7 +196,6 @@ define i1 @scalar_i16_bitsinmiddle_eq(i16 %x, i16 %y) nounwind {
 ;
 ; THUMB6-LABEL: scalar_i16_bitsinmiddle_eq:
 ; THUMB6:       @ %bb.0:
-; THUMB6-NEXT:    uxth r1, r1
 ; THUMB6-NEXT:    uxth r0, r0
 ; THUMB6-NEXT:    lsrs r0, r1
 ; THUMB6-NEXT:    movs r1, #255
@@ -220,7 +207,6 @@ define i1 @scalar_i16_bitsinmiddle_eq(i16 %x, i16 %y) nounwind {
 ;
 ; THUMB78-LABEL: scalar_i16_bitsinmiddle_eq:
 ; THUMB78:       @ %bb.0:
-; THUMB78-NEXT:    uxth r1, r1
 ; THUMB78-NEXT:    uxth r0, r0
 ; THUMB78-NEXT:    lsrs r0, r1
 ; THUMB78-NEXT:    and r0, r0, #4080
@@ -410,11 +396,11 @@ define i1 @scalar_i64_lowestbit_eq(i64 %x, i64 %y) nounwind {
 ;
 ; THUMB78-LABEL: scalar_i64_lowestbit_eq:
 ; THUMB78:       @ %bb.0:
-; THUMB78-NEXT:    rsb.w r3, r2, #32
+; THUMB78-NEXT:    rsbs r3, r2, #0
 ; THUMB78-NEXT:    lsrs r0, r2
-; THUMB78-NEXT:    subs r2, #32
 ; THUMB78-NEXT:    lsl.w r3, r1, r3
-; THUMB78-NEXT:    orr.w r0, r0, r3
+; THUMB78-NEXT:    orrs r0, r3
+; THUMB78-NEXT:    subs.w r3, r2, #32
 ; THUMB78-NEXT:    it pl
 ; THUMB78-NEXT:    lsrpl.w r0, r1, r2
 ; THUMB78-NEXT:    movs r1, #1
@@ -473,17 +459,16 @@ define i1 @scalar_i64_bitsinmiddle_eq(i64 %x, i64 %y) nounwind {
 ;
 ; THUMB78-LABEL: scalar_i64_bitsinmiddle_eq:
 ; THUMB78:       @ %bb.0:
-; THUMB78-NEXT:    rsb.w r3, r2, #32
+; THUMB78-NEXT:    rsbs r3, r2, #0
 ; THUMB78-NEXT:    lsrs r0, r2
 ; THUMB78-NEXT:    lsl.w r3, r1, r3
-; THUMB78-NEXT:    orrs r0, r3
-; THUMB78-NEXT:    subs.w r3, r2, #32
-; THUMB78-NEXT:    it pl
-; THUMB78-NEXT:    lsrpl.w r0, r1, r3
-; THUMB78-NEXT:    lsr.w r1, r1, r2
-; THUMB78-NEXT:    it pl
+; THUMB78-NEXT:    lsrs r1, r2
+; THUMB78-NEXT:    subs r2, #32
+; THUMB78-NEXT:    mov r2, r1
+; THUMB78-NEXT:    ite mi
+; THUMB78-NEXT:    orrmi.w r2, r0, r3
 ; THUMB78-NEXT:    movpl r1, #0
-; THUMB78-NEXT:    pkhbt r0, r1, r0
+; THUMB78-NEXT:    pkhbt r0, r1, r2
 ; THUMB78-NEXT:    clz r0, r0
 ; THUMB78-NEXT:    lsrs r0, r0, #5
 ; THUMB78-NEXT:    bx lr
@@ -876,7 +861,6 @@ define <4 x i1> @vec_4xi32_nonsplat_undef2_eq(<4 x i32> %x, <4 x i32> %y) nounwi
 define i1 @scalar_i8_signbit_ne(i8 %x, i8 %y) nounwind {
 ; ARM-LABEL: scalar_i8_signbit_ne:
 ; ARM:       @ %bb.0:
-; ARM-NEXT:    uxtb r1, r1
 ; ARM-NEXT:    uxtb r0, r0
 ; ARM-NEXT:    lsr r0, r0, r1
 ; ARM-NEXT:    lsr r0, r0, #7
@@ -884,7 +868,6 @@ define i1 @scalar_i8_signbit_ne(i8 %x, i8 %y) nounwind {
 ;
 ; THUMB-LABEL: scalar_i8_signbit_ne:
 ; THUMB:       @ %bb.0:
-; THUMB-NEXT:    uxtb r1, r1
 ; THUMB-NEXT:    uxtb r0, r0
 ; THUMB-NEXT:    lsrs r0, r1
 ; THUMB-NEXT:    lsrs r0, r0, #7
@@ -1029,7 +1012,6 @@ define i1 @negative_scalar_i8_bitsinmiddle_slt(i8 %x, i8 %y) nounwind {
 ;
 ; THUMB6-LABEL: negative_scalar_i8_bitsinmiddle_slt:
 ; THUMB6:       @ %bb.0:
-; THUMB6-NEXT:    uxtb r1, r1
 ; THUMB6-NEXT:    movs r2, #24
 ; THUMB6-NEXT:    lsls r2, r1
 ; THUMB6-NEXT:    ands r2, r0
@@ -1045,7 +1027,6 @@ define i1 @negative_scalar_i8_bitsinmiddle_slt(i8 %x, i8 %y) nounwind {
 ;
 ; THUMB78-LABEL: negative_scalar_i8_bitsinmiddle_slt:
 ; THUMB78:       @ %bb.0:
-; THUMB78-NEXT:    uxtb r1, r1
 ; THUMB78-NEXT:    movs r2, #24
 ; THUMB78-NEXT:    lsl.w r1, r2, r1
 ; THUMB78-NEXT:    ands r0, r1
@@ -1069,7 +1050,6 @@ define i1 @scalar_i8_signbit_eq_with_nonzero(i8 %x, i8 %y) nounwind {
 ;
 ; THUMB6-LABEL: scalar_i8_signbit_eq_with_nonzero:
 ; THUMB6:       @ %bb.0:
-; THUMB6-NEXT:    uxtb r1, r1
 ; THUMB6-NEXT:    movs r2, #127
 ; THUMB6-NEXT:    mvns r2, r2
 ; THUMB6-NEXT:    lsls r2, r1
diff --git a/llvm/test/CodeGen/ARM/rotate-add.ll b/llvm/test/CodeGen/ARM/rotate-add.ll
index fd3055e5e2725..62d6089178db2 100644
--- a/llvm/test/CodeGen/ARM/rotate-add.ll
+++ b/llvm/test/CodeGen/ARM/rotate-add.ll
@@ -29,7 +29,7 @@ define i32 @test_simple_rotr(i32 %x) {
 define i32 @test_rotl_var(i32 %x, i32 %y) {
 ; CHECK-LABEL: test_rotl_var:
 ; CHECK:       @ %bb.0:
-; CHECK-NEXT:    rsb r1, r1, #32
+; CHECK-NEXT:    rsb r1, r1, #0
 ; CHECK-NEXT:    ror r0, r0, r1
 ; CHECK-NEXT:    bx lr
   %shl = shl i32 %x, %y
@@ -55,7 +55,6 @@ define i32 @test_invalid_rotl_var_and(i32 %x, i32 %y) {
 ; CHECK-LABEL: test_invalid_rotl_var_and:
 ; CHECK:       @ %bb.0:
 ; CHECK-NEXT:    rsb r2, r1, #0
-; CHECK-NEXT:    and r2, r2, #31
 ; CHECK-NEXT:    lsr r2, r0, r2
 ; CHECK-NEXT:    add r0, r2, r0, lsl r1
 ; CHECK-NEXT:    bx lr
diff --git a/llvm/test/CodeGen/ARM/shift-i64.ll b/llvm/test/CodeGen/ARM/shift-i64.ll
index c326ac1529b2f..1c297731baf67 100644
--- a/llvm/test/CodeGen/ARM/shift-i64.ll
+++ b/llvm/test/CodeGen/ARM/shift-i64.ll
@@ -5,7 +5,7 @@
 define i64 @test_shl(i64 %val, i64 %amt) {
 ; CHECK-LABEL: test_shl:
 ; CHECK:       @ %bb.0:
-; CHECK-NEXT:    rsb r3, r2, #32
+; CHECK-NEXT:    rsb r3, r2, #0
 ; CHECK-NEXT:    lsr r3, r0, r3
 ; CHECK-NEXT:    orr r1, r3, r1, lsl r2
 ; CHECK-NEXT:    subs r3, r2, #32
diff --git a/llvm/test/CodeGen/ARM/shift-mod.ll b/llvm/test/CodeGen/ARM/shift-mod.ll
index 3ba591e11acd1..931a8d766ab4f 100644
--- a/llvm/test/CodeGen/ARM/shift-mod.ll
+++ b/llvm/test/CodeGen/ARM/shift-mod.ll
@@ -20,31 +20,26 @@ define i32 @lsl_add_mod(i32 %val, i32 %amt) #0 {
 ;
 ; CHECK-ARM-LABEL: lsl_add_mod:
 ; CHECK-ARM:       @ %bb.0: @ %entry
-; CHECK-ARM-NEXT:    add r1, r1, #32
 ; CHECK-ARM-NEXT:    lsl r0, r0, r1
 ; CHECK-ARM-NEXT:    bx lr
 ;
 ; CHECK-BE-LABEL: lsl_add_mod:
 ; CHECK-BE:       @ %bb.0: @ %entry
-; CHECK-BE-NEXT:    add r1, r1, #32
 ; CHECK-BE-NEXT:    lsl r0, r0, r1
 ; CHECK-BE-NEXT:    bx lr
 ;
 ; CHECK-THUMB-LABEL: lsl_add_mod:
 ; CHECK-THUMB:       @ %bb.0: @ %entry
-; CHECK-THUMB-NEXT:    adds r1, #32
 ; CHECK-THUMB-NEXT:    lsls r0, r1
 ; CHECK-THUMB-NEXT:    bx lr
 ;
 ; CHECK-ALIGN-LABEL: lsl_add_mod:
 ; CHECK-ALIGN:       @ %bb.0: @ %entry
-; CHECK-ALIGN-NEXT:    adds r1, #32
 ; CHECK-ALIGN-NEXT:    lsls r0, r1
 ; CHECK-ALIGN-NEXT:    bx lr
 ;
 ; CHECK-V6M-LABEL: lsl_add_mod:
 ; CHECK-V6M:       @ %bb.0: @ %entry
-; CHECK-V6M-NEXT:    adds r1, #32
 ; CHECK-V6M-NEXT:    lsls r0, r1
 ; CHECK-V6M-NEXT:    bx lr
 entry:
@@ -63,32 +58,31 @@ define i32 @lsl_sub_rsb(i32 %val, i32 %amt) #0 {
 ;
 ; CHECK-ARM-LABEL: lsl_sub_rsb:
 ; CHECK-ARM:       @ %bb.0: @ %entry
-; CHECK-ARM-NEXT:    rsb r1, r1, #32
+; CHECK-ARM-NEXT:    rsb r1, r1, #0
 ; CHECK-ARM-NEXT:    lsl r0, r0, r1
 ; CHECK-ARM-NEXT:    bx lr
 ;
 ; CHECK-BE-LABEL: lsl_sub_rsb:
 ; CHECK-BE:       @ %bb.0: @ %entry
-; CHECK-BE-NEXT:    rsb r1, r1, #32
+; CHECK-BE-NEXT:    rsb r1, r1, #0
 ; CHECK-BE-NEXT:    lsl r0, r0, r1
 ; CHECK-BE-NEXT:    bx lr
 ;
 ; CHECK-THUMB-LABEL: lsl_sub_rsb:
 ; CHECK-THUMB:       @ %bb.0: @ %entry
-; CHECK-THUMB-NEXT:    rsb.w r1, r1, #32
+; CHECK-THUMB-NEXT:    rsbs r1, r1, #0
 ; CHECK-THUMB-NEXT:    lsls r0, r1
 ; CHECK-THUMB-NEXT:    bx lr
 ;
 ; CHECK-ALIGN-LABEL: lsl_sub_rsb:
 ; CHECK-ALIGN:       @ %bb.0: @ %entry
-; CHECK-ALIGN-NEXT:    rsb.w r1, r1, #32
+; CHECK-ALIGN-NEXT:    rsbs r1, r1, #0
 ; CHECK-ALIGN-NEXT:    lsls r0, r1
 ; CHECK-ALIGN-NEXT:    bx lr
 ;
 ; CHECK-V6M-LABEL: lsl_sub_rsb:
 ; CHECK-V6M:       @ %bb.0: @ %entry
-; CHECK-V6M-NEXT:    movs r2, #32
-; CHECK-V6M-NEXT:    subs r1, r2, r1
+; CHECK-V6M-NEXT:    rsbs r1, r1, #0
 ; CHECK-V6M-NEXT:    lsls r0, r1
 ; CHECK-V6M-NEXT:    bx lr
 entry:
@@ -107,32 +101,31 @@ define i32 @lsl_sub_mvn(i32 %val, i32 %amt) #0 {
 ;
 ; CHECK-ARM-LABEL: lsl_sub_mvn:
 ; CHECK-ARM:       @ %bb.0: @ %entry
-; CHECK-ARM-NEXT:    rsb r1, r1, #31
+; CHECK-ARM-NEXT:    mvn r1, r1
 ; CHECK-ARM-NEXT:    lsl r0, r0, r1
 ; CHECK-ARM-NEXT:    bx lr
 ;
 ; CHECK-BE-LABEL: lsl_sub_mvn:
 ; CHECK-BE:       @ %bb.0: @ %entry
-; CHECK-BE-NEXT:    rsb r1, r1, #31
+; CHECK-BE-NEXT:    mvn r1, r1
 ; CHECK-BE-NEXT:    lsl r0, r0, r1
 ; CHECK-BE-NEXT:    bx lr
 ;
 ; CHECK-THUMB-LABEL: lsl_sub_mvn:
 ; CHECK-THUMB:       @ %bb.0: @ %entry
-; CHECK-THUMB-NEXT:    rsb.w r1, r1, #31
+; CHECK-THUMB-NEXT:    mvns r1, r1
 ; CHECK-THUMB-NEXT:    lsls r0, r1
 ; CHECK-THUMB-NEXT:    bx lr
 ;
 ; CHECK-ALIGN-LABEL: lsl_sub_mvn:
 ; CHECK-ALIGN:       @ %bb.0: @ %entry
-; CHECK-ALIGN-NEXT:    rsb.w r1, r1, #31
+; CHECK-ALIGN-NEXT:    mvns r1, r1
 ; CHECK-ALIGN-NEXT:    lsls r0, r1
 ; CHECK-ALIGN-NEXT:    bx lr
 ;
 ; CHECK-V6M-LABEL: lsl_sub_mvn:
 ; CHECK-V6M:       @ %bb.0: @ %entry
-; CHECK-V6M-NEXT:    movs r2, #31
-; CHECK-V6M-NEXT:    subs r1, r2, r1
+; CHECK-V6M-NEXT:    mvns r1, r1
 ; CHECK-V6M-NEXT:    lsls r0, r1
 ; CHECK-V6M-NEXT:    bx lr
 entry:
@@ -151,33 +144,27 @@ define i32 @lsl_and_mask(i32 %val, i32 %amt) #0 {
 ;
 ; CHECK-ARM-LABEL: lsl_and_mask:
 ; CHECK-ARM:       @ %bb.0: @ %entry
-; CHECK-ARM-NEXT:    and r1, r1, #31
 ; CHECK-ARM-NEXT:    lsl r0, r0, r1
 ; CHECK-ARM-NEXT:    bx lr
 ;
 ; CHECK-BE-LABEL: lsl_and_mask:
 ; CHECK-BE:       @ %bb.0: @ %entry
-; CHECK-BE-NEXT:    and r1, r1, #31
 ; CHECK-BE-NEXT:    lsl r0, r0, r1
 ; CHECK-BE-NEXT:    bx lr
 ;
 ; CHECK-THUMB-LABEL: lsl_and_mask:
 ; CHECK-THUMB:       @ %bb.0: @ %entry
-; CHECK-THUMB-NEXT:    and r1, r1, #31
 ; CHECK-THUMB-NEXT:    lsls r0, r1
 ; CHECK-THUMB-NEXT:    bx lr
 ;
 ; CHECK-ALIGN-LABEL: lsl_and_mask:
 ; CHECK-ALIGN:       @ %bb.0: @ %entry
-; CHECK-ALIGN-NEXT:    and r1, r1, #31
 ; CHECK-ALIGN-NEXT:    lsls r0, r1
 ; CHECK-ALIGN-NEXT:    bx lr
 ;
 ; CHECK-V6M-LABEL: lsl_and_mask:
 ; CHECK-V6M:       @ %bb.0: @ %entry
-; CHECK-V6M-NEXT:    movs r2, #31
-; CHECK-V6M-NEXT:    ands r2, r1
-; CHECK-V6M-NEXT:    lsls r0, r2
+; CHECK-V6M-NEXT:    lsls r0, r1
 ; CHECK-V6M-NEXT:    bx lr
 entry:
   %sa = and i32 %amt, 31
@@ -199,31 +186,26 @@ define i32 @lsr_add_mod(i32 %val, i32 %amt) #0 {
 ;
 ; CHECK-ARM-LABEL: lsr_add_mod:
 ; CHECK-ARM:       @ %bb.0: @ %entry
-; CHECK-ARM-NEXT:    add r1, r1, #32
 ; CHECK-ARM-NEXT:    lsr r0, r0, r1
 ; CHECK-ARM-NEXT:    bx lr
 ;
 ; CHECK-BE-LABEL: lsr_add_mod:
 ; CHECK-BE:       @ %bb.0: @ %entry
-; CHECK-BE-NEXT:    add r1, r1, #32
 ; CHECK-BE-NEXT:    lsr r0, r0, r1
 ; CHECK-BE-NEXT:    bx lr
 ;
 ; CHECK-THUMB-LABEL: lsr_add_mod:
 ; CHECK-THUMB:       @ %bb.0: @ %entry
-; CHECK-THUMB-NEXT:    adds r1, #32
 ; CHECK-THUMB-NEXT:    lsrs r0, r1
 ; CHECK-THUMB-NEXT:    bx lr
 ;
 ; CHECK-ALIGN-LABEL: lsr_add_mod:
 ; CHECK-ALIGN:       @ %bb.0: @ %entry
-; CHECK-ALIGN-NEXT:    adds r1, #32
 ; CHECK-ALIGN-NEXT:    lsrs r0, r1
 ; CHECK-ALIGN-NEXT:    bx lr
 ;
 ; CHECK-V6M-LABEL: lsr_add_mod:
 ; CHECK-V6M:       @ %bb.0: @ %entry
-; CHECK-V6M-NEXT:    adds r1, #32
 ; CHECK-V6M-NEXT:    lsrs r0, r1
 ; CHECK-V6M-NEXT:    bx lr
 entry:
@@ -242,32 +224,31 @@ define i32 @lsr_sub_rsb(i32 %val, i32 %amt) #0 {
 ;
 ; CHECK-ARM-LABEL: lsr_sub_rsb:
 ; CHECK-ARM:       @ %bb.0: @ %entry
-; CHECK-ARM-NEXT:    rsb r1, r1, #32
+; CHECK-ARM-NEXT:    rsb r1, r1, #0
 ; CHECK-ARM-NEXT:    lsr r0, r0, r1
 ; CHECK-ARM-NEXT:    bx lr
 ;
 ; CHECK-BE-LABEL: lsr_sub_rsb:
 ; CHECK-BE:       @ %bb.0: @ %entry
-; CHECK-BE-NEXT:    rsb r1, r1, #32
+; CHECK-BE-NEXT:    rsb r1, r1, #0
 ; CHECK-BE-NEXT:    lsr r0, r0, r1
 ; CHECK-BE-NEXT:    bx lr
 ;
 ; CHECK-THUMB-LABEL: lsr_sub_rsb:
 ; CHECK-THUMB:       @ %bb.0: @ %entry
-; CHECK-THUMB-NEXT:    rsb.w r1, r1, #32
+; CHECK-THUMB-NEXT:    rsbs r1, r1, #0
 ; CHECK-THUMB-NEXT:    lsrs r0, r1
 ; CHECK-THUMB-NEXT:    bx lr
 ;
 ; CHECK-ALIGN-LABEL: lsr_sub_rsb:
 ; CHECK-ALIGN:       @ %bb.0: @ %entry
-; CHECK-ALIGN-NEXT:    rsb.w r1, r1, #32
+; CHECK-ALIGN-NEXT:    rsbs r1, r1, #0
 ; CHECK-ALIGN-NEXT:    lsrs r0, r1
 ; CHECK-ALIGN-NEXT:    bx lr
 ;
 ; CHECK-V6M-LABEL: lsr_sub_rsb:
 ; CHECK-V6M:       @ %bb.0: @ %entry
-; CHECK-V6M-NEXT:    movs r2, #32
-; CHECK-V6M-NEXT:    subs r1, r2, r1
+; CHECK-V6M-NEXT:    rsbs r1, r1, #0
 ; CHECK-V6M-NEXT:    lsrs r0, r1
 ; CHECK-V6M-NEXT:    bx lr
 entry:
@@ -286,32 +267,31 @@ define i32 @lsr_sub_mvn(i32 %val, i32 %amt) #0 {
 ;
 ; CHECK-ARM-LABEL: lsr_sub_mvn:
 ; CHECK-ARM:       @ %bb.0: @ %entry
-; CHECK-ARM-NEXT:    rsb r1, r1, #31
+; CHECK-ARM-NEXT:    mvn r1, r1
 ; CHECK-ARM-NEXT:    lsr r0, r0, r1
 ; CHECK-ARM-NEXT:    bx lr
 ;
 ; CHECK-BE-LABEL: lsr_sub_mvn:
 ; CHECK-BE:       @ %bb.0: @ %entry
-; CHECK-BE-NEXT:    rsb r1, r1, #31
+; CHECK-BE-NEXT:    mvn r1, r1
 ; CHECK-BE-NEXT:    lsr r0, r0, r1
 ; CHECK-BE-NEXT:    bx lr
 ;
 ; CHECK-THUMB-LABEL: lsr_sub_mvn:
 ; CHECK-THUMB:       @ %bb.0: @ %entry
-; CHECK-THUMB-NEXT:    rsb.w r1, r1, #31
+; CHECK-THUMB-NEXT:    mvns r1, r1
 ; CHECK-THUMB-NEXT:    lsrs r0, r1
 ; CHECK-THUMB-NEXT:    bx lr
 ;
 ; CHECK-ALIGN-LABEL: lsr_sub_mvn:
 ; CHECK-ALIGN:       @ %bb.0: @ %entry
-; CHECK-ALIGN-NEXT:    rsb.w r1, r1, #31
+; CHECK-ALIGN-NEXT:    mvns r1, r1
 ; CHECK-ALIGN-NEXT:    lsrs r0, r1
 ; CHECK-ALIGN-NEXT:    bx lr
 ;
 ; CHECK-V6M-LABEL: lsr_sub_mvn:
 ; CHECK-V6M:       @ %bb.0: @ %entry
-; CHECK-V6M-NEXT:    movs r2, #31
-; CHECK-V6M-NEXT:    subs r1, r2, r1
+; CHECK-V6M-NEXT:    mvns r1, r1
 ; CHECK-V6M-NEXT:    lsrs r0, r1
 ; CHECK-V6M-NEXT:    bx lr
 entry:
@@ -330,33 +310,27 @@ define i32 @lsr_and_mask(i32 %val, i32 %amt) #0 {
 ;
 ; CHECK-ARM-LABEL: lsr_and_mask:
 ; CHECK-ARM:       @ %bb.0: @ %entry
-; CHECK-ARM-NEXT:    and r1, r1, #31
 ; CHECK-ARM-NEXT:    lsr r0, r0, r1
 ; CHECK-ARM-NEXT:    bx lr
 ;
 ; CHECK-BE-LABEL: lsr_and_mask:
 ; CHECK-BE:       @ %bb.0: @ %entry
-; CHECK-BE-NEXT:    and r1, r1, #31
 ; CHECK-BE-NEXT:    lsr r0, r0, r1
 ; CHECK-BE-NEXT:    bx lr
 ;
 ; CHECK-THUMB-LABEL: lsr_and_mask:
 ; CHECK-THUMB:       @ %bb.0: @ %entry
-; CHECK-THUMB-NEXT:    and r1, r1, #31
 ; CHECK-THUMB-NEXT:    lsrs r0, r1
 ; CHECK-THUMB-NEXT:    bx lr
 ;
 ; CHECK-ALIGN-LABEL: lsr_and_mask:
 ; CHECK-ALIGN:       @ %bb.0: @ %entry
-; CHECK-ALIGN-NEXT:    and r1, r1, #31
 ; CHECK-ALIGN-NEXT:    lsrs r0, r1
 ; CHECK-ALIGN-NEXT:    bx lr
 ;
 ; CHECK-V6M-LABEL: lsr_and_mask:
 ; CHECK-V6M:       @ %bb.0: @ %entry
-; CHECK-V6M-NEXT:    movs r2, #31
-; CHECK-V6M-NEXT:    ands r2, r1
-; CHECK-V6M-NEXT:    lsrs r0, r2
+; CHECK-V6M-NEXT:    lsrs r0, r1
 ; CHECK-V6M-NEXT:    bx lr
 entry:
   %sa = and i32 %amt, 31
@@ -384,31 +358,26 @@ define i32 @asr_add_mod(i32 %val, i32 %amt) #0 {
 ;
 ; CHECK-ARM-LABEL: asr_add_mod:
 ; CHECK-ARM:       @ %bb.0: @ %entry
-; CHECK-ARM-NEXT:    add r1, r1, #32
 ; CHECK-ARM-NEXT:    asr r0, r0, r1
 ; CHECK-ARM-NEXT:    bx lr
 ;
 ; CHECK-BE-LABEL: asr_add_mod:
 ; CHECK-BE:       @ %bb.0: @ %entry
-; CHECK-BE-NEXT:    add r1, r1, #32
 ; CHECK-BE-NEXT:    asr r0, r0, r1
 ; CHECK-BE-NEXT:    bx lr
 ;
 ; CHECK-THUMB-LABEL: asr_add_mod:
 ; CHECK-THUMB:       @ %bb.0: @ %entry
-; CHECK-THUMB-NEXT:    adds r1, #32
 ; CHECK-THUMB-NEXT:    asrs r0, r1
 ; CHECK-THUMB-NEXT:    bx lr
 ;
 ; CHECK-ALIGN-LABEL: asr_add_mod:
 ; CHECK-ALIGN:       @ %bb.0: @ %entry
-; CHECK-ALIGN-NEXT:    adds r1, #32
 ; CHECK-ALIGN-NEXT:    asrs r0, r1
 ; CHECK-ALIGN-NEXT:    bx lr
 ;
 ; CHECK-V6M-LABEL: asr_add_mod:
 ; CHECK-V6M:       @ %bb.0: @ %entry
-; CHECK-V6M-NEXT:    adds r1, #32
 ; CHECK-V6M-NEXT:    asrs r0, r1
 ; CHECK-V6M-NEXT:    bx lr
 entry:
@@ -433,32 +402,31 @@ define i32 @asr_sub_rsb(i32 %val, i32 %amt) #0 {
 ;
 ; CHECK-ARM-LABEL: asr_sub_rsb:
 ; CHECK-ARM:       @ %bb.0: @ %entry
-; CHECK-ARM-NEXT:    rsb r1, r1, #32
+; CHECK-ARM-NEXT:    rsb r1, r1, #0
 ; CHECK-ARM-NEXT:    asr r0, r0, r1
 ; CHECK-ARM-NEXT:    bx lr
 ;
 ; CHECK-BE-LABEL: asr_sub_rsb:
 ; CHECK-BE:       @ %bb.0: @ %entry
-; CHECK-BE-NEXT:    rsb r1, r1, #32
+; CHECK-BE-NEXT:    rsb r1, r1, #0
 ; CHECK-BE-NEXT:    asr r0, r0, r1
 ; CHECK-BE-NEXT:    bx lr
 ;
 ; CHECK-THUMB-LABEL: asr_sub_rsb:
 ; CHECK-THUMB:       @ %bb.0: @ %entry
-; CHECK-THUMB-NEXT:    rsb.w r1, r1, #32
+; CHECK-THUMB-NEXT:    rsbs r1, r1, #0
 ; CHECK-THUMB-NEXT:    asrs r0, r1
 ; CHECK-THUMB-NEXT:    bx lr
 ;
 ; CHECK-ALIGN-LABEL: asr_sub_rsb:
 ; CHECK-ALIGN:       @ %bb.0: @ %entry
-; CHECK-ALIGN-NEXT:    rsb.w r1, r1, #32
+; CHECK-ALIGN-NEXT:    rsbs r1, r1, #0
 ; CHECK-ALIGN-NEXT:    asrs r0, r1
 ; CHECK-ALIGN-NEXT:    bx lr
 ;
 ; CHECK-V6M-LABEL: asr_sub_rsb:
 ; CHECK-V6M:       @ %bb.0: @ %entry
-; CHECK-V6M-NEXT:    movs r2, #32
-; CHECK-V6M-NEXT:    subs r1, r2, r1
+; CHECK-V6M-NEXT:    rsbs r1, r1, #0
 ; CHECK-V6M-NEXT:    asrs r0, r1
 ; CHECK-V6M-NEXT:    bx lr
 entry:
@@ -483,32 +451,31 @@ define i32 @asr_sub_mvn(i32 %val, i32 %amt) #0 {
 ;
 ; CHECK-ARM-LABEL: asr_sub_mvn:
 ; CHECK-ARM:       @ %bb.0: @ %entry
-; CHECK-ARM-NEXT:    rsb r1, r1, #31
+; CHECK-ARM-NEXT:    mvn r1, r1
 ; CHECK-ARM-NEXT:    asr r0, r0, r1
 ; CHECK-ARM-NEXT:    bx lr
 ;
 ; CHECK-BE-LABEL: asr_sub_mvn:
 ; CHECK-BE:       @ %bb.0: @ %entry
-; CHECK-BE-NEXT:    rsb r1, r1, #31
+; CHECK-BE-NEXT:    mvn r1, r1
 ; CHECK-BE-NEXT:    asr r0, r0, r1
 ; CHECK-BE-NEXT:    bx lr
 ;
 ; CHECK-THUMB-LABEL: asr_sub_mvn:
 ; CHECK-THUMB:       @ %bb.0: @ %entry
-; CHECK-THUMB-NEXT:    rsb.w r1, r1, #31
+; CHECK-THUMB-NEXT:    mvns r1, r1
 ; CHECK-THUMB-NEXT:    asrs r0, r1
 ; CHECK-THUMB-NEXT:    bx lr
 ;
 ; CHECK-ALIGN-LABEL: asr_sub_mvn:
 ; CHECK-ALIGN:       @ %bb.0: @ %entry
-; CHECK-ALIGN-NEXT:    rsb.w r1, r1, #31
+; CHECK-ALIGN-NEXT:    mvns r1, r1
 ; CHECK-ALIGN-NEXT:    asrs r0, r1
 ; CHECK-ALIGN-NEXT:    bx lr
 ;
 ; CHECK-V6M-LABEL: asr_sub_mvn:
 ; CHECK-V6M:       @ %bb.0: @ %entry
-; CHECK-V6M-NEXT:    movs r2, #31
-; CHECK-V6M-NEXT:    subs r1, r2, r1
+; CHECK-V6M-NEXT:    mvns r1, r1
 ; CHECK-V6M-NEXT:    asrs r0, r1
 ; CHECK-V6M-NEXT:    bx lr
 entry:
@@ -533,33 +500,27 @@ define i32 @asr_and_mask(i32 %val, i32 %amt) #0 {
 ;
 ; CHECK-ARM-LABEL: asr_and_mask:
 ; CHECK-ARM:       @ %bb.0: @ %entry
-; CHECK-ARM-NEXT:    and r1, r1, #31
 ; CHECK-ARM-NEXT:    asr r0, r0, r1
 ; CHECK-ARM-NEXT:    bx lr
 ;
 ; CHECK-BE-LABEL: asr_and_mask:
 ; CHECK-BE:       @ %bb.0: @ %entry
-; CHECK-BE-NEXT:    and r1, r1, #31
 ; CHECK-BE-NEXT:    asr r0, r0, r1
 ; CHECK-BE-NEXT:    bx lr
 ;
 ; CHECK-THUMB-LABEL: asr_and_mask:
 ; CHECK-THUMB:       @ %bb.0: @ %entry
-; CHECK-THUMB-NEXT:    and r1, r1, #31
 ; CHECK-THUMB-NEXT:    asrs r0, r1
 ; CHECK-THUMB-NEXT:    bx lr
 ;
 ; CHECK-ALIGN-LABEL: asr_and_mask:
 ; CHECK-ALIGN:       @ %bb.0: @ %entry
-; CHECK-ALIGN-NEXT:    and r1, r1, #31
 ; CHECK-ALIGN-NEXT:    asrs r0, r1
 ; CHECK-ALIGN-NEXT:    bx lr
 ;
 ; CHECK-V6M-LABEL: asr_and_mask:
 ; CHECK-V6M:       @ %bb.0: @ %entry
-; CHECK-V6M-NEXT:    movs r2, #31
-; CHECK-V6M-NEXT:    ands r2, r1
-; CHECK-V6M-NEXT:    asrs r0, r2
+; CHECK-V6M-NEXT:    asrs r0, r1
 ; CHECK-V6M-NEXT:    bx lr
 entry:
   %sa = and i32 %amt, 31
@@ -577,31 +538,26 @@ define i32 @ror_add_mod(i32 %val, i32 %amt) #0 {
 ;
 ; CHECK-ARM-LABEL: ror_add_mod:
 ; CHECK-ARM:       @ %bb.0: @ %entry
-; CHECK-ARM-NEXT:    add r1, r1, #32
 ; CHECK-ARM-NEXT:    lsr r0, r0, r1
 ; CHECK-ARM-NEXT:    bx lr
 ;
 ; CHECK-BE-LABEL: ror_add_mod:
 ; CHECK-BE:       @ %bb.0: @ %entry
-; CHECK-BE-NEXT:    add r1, r1, #32
 ; CHECK-BE-NEXT:    lsr r0, r0, r1
 ; CHECK-BE-NEXT:    bx lr
 ;
 ; CHECK-THUMB-LABEL: ror_add_mod:
 ; CHECK-THUMB:       @ %bb.0: @ %entry
-; CHECK-THUMB-NEXT:    adds r1, #32
 ; CHECK-THUMB-NEXT:    lsrs r0, r1
 ; CHECK-THUMB-NEXT:    bx lr
 ;
 ; CHECK-ALIGN-LABEL: ror_add_mod:
 ; CHECK-ALIGN:       @ %bb.0: @ %entry
-; CHECK-ALIGN-NEXT:    adds r1, #32
 ; CHECK-ALIGN-NEXT:    lsrs r0, r1
 ; CHECK-ALIGN-NEXT:    bx lr
 ;
 ; CHECK-V6M-LABEL: ror_add_mod:
 ; CHECK-V6M:       @ %bb.0: @ %entry
-; CHECK-V6M-NEXT:    adds r1, #32
 ; CHECK-V6M-NEXT:    lsrs r0, r1
 ; CHECK-V6M-NEXT:    bx lr
 entry:
@@ -619,32 +575,31 @@ define i32 @ror_sub_rsb(i32 %val, i32 %amt) #0 {
 ;
 ; CHECK-ARM-LABEL: ror_sub_rsb:
 ; CHECK-ARM:       @ %bb.0: @ %entry
-; CHECK-ARM-NEXT:    rsb r1, r1, #32
+; CHECK-ARM-NEXT:    rsb r1, r1, #0
 ; CHECK-ARM-NEXT:    lsr r0, r0, r1
 ; CHECK-ARM-NEXT:    bx lr
 ;
 ; CHECK-BE-LABEL: ror_sub_rsb:
 ; CHECK-BE:       @ %bb.0: @ %entry
-; CHECK-BE-NEXT:    rsb r1, r1, #32
+; CHECK-BE-NEXT:    rsb r1, r1, #0
 ; CHECK-BE-NEXT:    lsr r0, r0, r1
 ; CHECK-BE-NEXT:    bx lr
 ;
 ; CHECK-THUMB-LABEL: ror_sub_rsb:
 ; CHECK-THUMB:       @ %bb.0: @ %entry
-; CHECK-THUMB-NEXT:    rsb.w r1, r1, #32
+; CHECK-THUMB-NEXT:    rsbs r1, r1, #0
 ; CHECK-THUMB-NEXT:    lsrs r0, r1
 ; CHECK-THUMB-NEXT:    bx lr
 ;
 ; CHECK-ALIGN-LABEL: ror_sub_rsb:
 ; CHECK-ALIGN:       @ %bb.0: @ %entry
-; CHECK-ALIGN-NEXT:    rsb.w r1, r1, #32
+; CHECK-ALIGN-NEXT:    rsbs r1, r1, #0
 ; CHECK-ALIGN-NEXT:    lsrs r0, r1
 ; CHECK-ALIGN-NEXT:    bx lr
 ;
 ; CHECK-V6M-LABEL: ror_sub_rsb:
 ; CHECK-V6M:       @ %bb.0: @ %entry
-; CHECK-V6M-NEXT:    movs r2, #32
-; CHECK-V6M-NEXT:    subs r1, r2, r1
+; CHECK-V6M-NEXT:    rsbs r1, r1, #0
 ; CHECK-V6M-NEXT:    lsrs r0, r1
 ; CHECK-V6M-NEXT:    bx lr
 entry:
@@ -662,32 +617,31 @@ define i32 @ror_sub_mvn(i32 %val, i32 %amt) #0 {
 ;
 ; CHECK-ARM-LABEL: ror_sub_mvn:
 ; CHECK-ARM:       @ %bb.0: @ %entry
-; CHECK-ARM-NEXT:    rsb r1, r1, #31
+; CHECK-ARM-NEXT:    mvn r1, r1
 ; CHECK-ARM-NEXT:    lsr r0, r0, r1
 ; CHECK-ARM-NEXT:    bx lr
 ;
 ; CHECK-BE-LABEL: ror_sub_mvn:
 ; CHECK-BE:       @ %bb.0: @ %entry
-; CHECK-BE-NEXT:    rsb r1, r1, #31
+; CHECK-BE-NEXT:    mvn r1, r1
 ; CHECK-BE-NEXT:    lsr r0, r0, r1
 ; CHECK-BE-NEXT:    bx lr
 ;
 ; CHECK-THUMB-LABEL: ror_sub_mvn:
 ; CHECK-THUMB:       @ %bb.0: @ %entry
-; CHECK-THUMB-NEXT:    rsb.w r1, r1, #31
+; CHECK-THUMB-NEXT:    mvns r1, r1
 ; CHECK-THUMB-NEXT:    lsrs r0, r1
 ; CHECK-THUMB-NEXT:    bx lr
 ;
 ; CHECK-ALIGN-LABEL: ror_sub_mvn:
 ; CHECK-ALIGN:       @ %bb.0: @ %entry
-; CHECK-ALIGN-NEXT:    rsb.w r1, r1, #31
+; CHECK-ALIGN-NEXT:    mvns r1, r1
 ; CHECK-ALIGN-NEXT:    lsrs r0, r1
 ; CHECK-ALIGN-NEXT:    bx lr
 ;
 ; CHECK-V6M-LABEL: ror_sub_mvn:
 ; CHECK-V6M:       @ %bb.0: @ %entry
-; CHECK-V6M-NEXT:    movs r2, #31
-; CHECK-V6M-NEXT:    subs r1, r2, r1
+; CHECK-V6M-NEXT:    mvns r1, r1
 ; CHECK-V6M-NEXT:    lsrs r0, r1
 ; CHECK-V6M-NEXT:    bx lr
 entry:
@@ -705,33 +659,27 @@ define i32 @ror_and_mask(i32 %val, i32 %amt) #0 {
 ;
 ; CHECK-ARM-LABEL: ror_and_mask:
 ; CHECK-ARM:       @ %bb.0: @ %entry
-; CHECK-ARM-NEXT:    and r1, r1, #31
 ; CHECK-ARM-NEXT:    lsr r0, r0, r1
 ; CHECK-ARM-NEXT:    bx lr
 ;
 ; CHECK-BE-LABEL: ror_and_mask:
 ; CHECK-BE:       @ %bb.0: @ %entry
-; CHECK-BE-NEXT:    and r1, r1, #31
 ; CHECK-BE-NEXT:    lsr r0, r0, r1
 ; CHECK-BE-NEXT:    bx lr
 ;
 ; CHECK-THUMB-LABEL: ror_and_mask:
 ; CHECK-THUMB:       @ %bb.0: @ %entry
-; CHECK-THUMB-NEXT:    and r1, r1, #31
 ; CHECK-THUMB-NEXT:    lsrs r0, r1
 ; CHECK-THUMB-NEXT:    bx lr
 ;
 ; CHECK-ALIGN-LABEL: ror_and_mask:
 ; CHECK-ALIGN:       @ %bb.0: @ %entry
-; CHECK-ALIGN-NEXT:    and r1, r1, #31
 ; CHECK-ALIGN-NEXT:    lsrs r0, r1
 ; CHECK-ALIGN-NEXT:    bx lr
 ;
 ; CHECK-V6M-LABEL: ror_and_mask:
 ; CHECK-V6M:       @ %bb.0: @ %entry
-; CHECK-V6M-NEXT:    movs r2, #31
-; CHECK-V6M-NEXT:    ands r2, r1
-; CHECK-V6M-NEXT:    lsrs r0, r2
+; CHECK-V6M-NEXT:    lsrs r0, r1
 ; CHECK-V6M-NEXT:    bx lr
 entry:
   %sa = and i32 %amt, 31
@@ -752,37 +700,31 @@ declare i32 @llvm.fshr.i32(i32, i32, i32)
 define i32 @fshl_add_mod(i32 %x, i32 %amt) #0 {
 ; CHECK-ARM-LABEL: fshl_add_mod:
 ; CHECK-ARM:       @ %bb.0: @ %entry
-; CHECK-ARM-NEXT:    mvn r2, #31
-; CHECK-ARM-NEXT:    sub r1, r2, r1
+; CHECK-ARM-NEXT:    rsb r1, r1, #0
 ; CHECK-ARM-NEXT:    ror r0, r0, r1
 ; CHECK-ARM-NEXT:    bx lr
 ;
 ; CHECK-BE-LABEL: fshl_add_mod:
 ; CHECK-BE:       @ %bb.0: @ %entry
-; CHECK-BE-NEXT:    mvn r2, #31
-; CHECK-BE-NEXT:    sub r1, r2, r1
+; CHECK-BE-NEXT:    rsb r1, r1, #0
 ; CHECK-BE-NEXT:    ror r0, r0, r1
 ; CHECK-BE-NEXT:    bx lr
 ;
 ; CHECK-THUMB-LABEL: fshl_add_mod:
 ; CHECK-THUMB:       @ %bb.0: @ %entry
-; CHECK-THUMB-NEXT:    mvn r2, #31
-; CHECK-THUMB-NEXT:    subs r1, r2, r1
+; CHECK-THUMB-NEXT:    rsbs r1, r1, #0
 ; CHECK-THUMB-NEXT:    rors r0, r1
 ; CHECK-THUMB-NEXT:    bx lr
 ;
 ; CHECK-ALIGN-LABEL: fshl_add_mod:
 ; CHECK-ALIGN:       @ %bb.0: @ %entry
-; CHECK-ALIGN-NEXT:    mvn r2, #31
-; CHECK-ALIGN-NEXT:    subs r1, r2, r1
+; CHECK-ALIGN-NEXT:    rsbs r1, r1, #0
 ; CHECK-ALIGN-NEXT:    rors r0, r1
 ; CHECK-ALIGN-NEXT:    bx lr
 ;
 ; CHECK-V6M-LABEL: fshl_add_mod:
 ; CHECK-V6M:       @ %bb.0: @ %entry
-; CHECK-V6M-NEXT:    movs r2, #31
-; CHECK-V6M-NEXT:    mvns r2, r2
-; CHECK-V6M-NEXT:    subs r1, r2, r1
+; CHECK-V6M-NEXT:    rsbs r1, r1, #0
 ; CHECK-V6M-NEXT:    rors r0, r1
 ; CHECK-V6M-NEXT:    bx lr
 entry:
@@ -801,31 +743,26 @@ entry:
 define i32 @fshl_sub_rsb(i32 %x, i32 %amt) #0 {
 ; CHECK-ARM-LABEL: fshl_sub_rsb:
 ; CHECK-ARM:       @ %bb.0: @ %entry
-; CHECK-ARM-NEXT:    sub r1, r1, #32
 ; CHECK-ARM-NEXT:    ror r0, r0, r1
 ; CHECK-ARM-NEXT:    bx lr
 ;
 ; CHECK-BE-LABEL: fshl_sub_rsb:
 ; CHECK-BE:       @ %bb.0: @ %entry
-; CHECK-BE-NEXT:    sub r1, r1, #32
 ; CHECK-BE-NEXT:    ror r0, r0, r1
 ; CHECK-BE-NEXT:    bx lr
 ;
 ; CHECK-THUMB-LABEL: fshl_sub_rsb:
 ; CHECK-THUMB:       @ %bb.0: @ %entry
-; CHECK-THUMB-NEXT:    subs r1, #32
 ; CHECK-THUMB-NEXT:    rors r0, r1
 ; CHECK-THUMB-NEXT:    bx lr
 ;
 ; CHECK-ALIGN-LABEL: fshl_sub_rsb:
 ; CHECK-ALIGN:       @ %bb.0: @ %entry
-; CHECK-ALIGN-NEXT:    subs r1, #32
 ; CHECK-ALIGN-NEXT:    rors r0, r1
 ; CHECK-ALIGN-NEXT:    bx lr
 ;
 ; CHECK-V6M-LABEL: fshl_sub_rsb:
 ; CHECK-V6M:       @ %bb.0: @ %entry
-; CHECK-V6M-NEXT:    subs r1, #32
 ; CHECK-V6M-NEXT:    rors r0, r1
 ; CHECK-V6M-NEXT:    bx lr
 entry:
@@ -923,31 +860,26 @@ entry:
 define i32 @fshr_add_mod(i32 %x, i32 %amt) #0 {
 ; CHECK-ARM-LABEL: fshr_add_mod:
 ; CHECK-ARM:       @ %bb.0: @ %entry
-; CHECK-ARM-NEXT:    add r1, r1, #32
 ; CHECK-ARM-NEXT:    ror r0, r0, r1
 ; CHECK-ARM-NEXT:    bx lr
 ;
 ; CHECK-BE-LABEL: fshr_add_mod:
 ; CHECK-BE:       @ %bb.0: @ %entry
-; CHECK-BE-NEXT:    add r1, r1, #32
 ; CHECK-BE-NEXT:    ror r0, r0, r1
 ; CHECK-BE-NEXT:    bx lr
 ;
 ; CHECK-THUMB-LABEL: fshr_add_mod:
 ; CHECK-THUMB:       @ %bb.0: @ %entry
-; CHECK-THUMB-NEXT:    adds r1, #32
 ; CHECK-THUMB-NEXT:    rors r0, r1
 ; CHECK-THUMB-NEXT:    bx lr
 ;
 ; CHECK-ALIGN-LABEL: fshr_add_mod:
 ; CHECK-ALIGN:       @ %bb.0: @ %entry
-; CHECK-ALIGN-NEXT:    adds r1, #32
 ; CHECK-ALIGN-NEXT:    rors r0, r1
 ; CHECK-ALIGN-NEXT:    bx lr
 ;
 ; CHECK-V6M-LABEL: fshr_add_mod:
 ; CHECK-V6M:       @ %bb.0: @ %entry
-; CHECK-V6M-NEXT:    adds r1, #32
 ; CHECK-V6M-NEXT:    rors r0, r1
 ; CHECK-V6M-NEXT:    bx lr
 entry:
@@ -960,32 +892,31 @@ entry:
 define i32 @fshr_sub_rsb(i32 %x, i32 %amt) #0 {
 ; CHECK-ARM-LABEL: fshr_sub_rsb:
 ; CHECK-ARM:       @ %bb.0: @ %entry
-; CHECK-ARM-NEXT:    rsb r1, r1, #32
+; CHECK-ARM-NEXT:    rsb r1, r1, #0
 ; CHECK-ARM-NEXT:    ror r0, r0, r1
 ; CHECK-ARM-NEXT:    bx lr
 ;
 ; CHECK-BE-LABEL: fshr_sub_rsb:
 ; CHECK-BE:       @ %bb.0: @ %entry
-; CHECK-BE-NEXT:    rsb r1, r1, #32
+; CHECK-BE-NEXT:    rsb r1, r1, #0
 ; CHECK-BE-NEXT:    ror r0, r0, r1
 ; CHECK-BE-NEXT:    bx lr
 ;
 ; CHECK-THUMB-LABEL: fshr_sub_rsb:
 ; CHECK-THUMB:       @ %bb.0: @ %entry
-; CHECK-THUMB-NEXT:    rsb.w r1, r1, #32
+; CHECK-THUMB-NEXT:    rsbs r1, r1, #0
 ; CHECK-THUMB-NEXT:    rors r0, r1
 ; CHECK-THUMB-NEXT:    bx lr
 ;
 ; CHECK-ALIGN-LABEL: fshr_sub_rsb:
 ; CHECK-ALIGN:       @ %bb.0: @ %entry
-; CHECK-ALIGN-NEXT:    rsb.w r1, r1, #32
+; CHECK-ALIGN-NEXT:    rsbs r1, r1, #0
 ; CHECK-ALIGN-NEXT:    rors r0, r1
 ; CHECK-ALIGN-NEXT:    bx lr
 ;
 ; CHECK-V6M-LABEL: fshr_sub_rsb:
 ; CHECK-V6M:       @ %bb.0: @ %entry
-; CHECK-V6M-NEXT:    movs r2, #32
-; CHECK-V6M-NEXT:    subs r1, r2, r1
+; CHECK-V6M-NEXT:    rsbs r1, r1, #0
 ; CHECK-V6M-NEXT:    rors r0, r1
 ; CHECK-V6M-NEXT:    bx lr
 entry:
@@ -998,32 +929,31 @@ entry:
 define i32 @fshr_sub_mvn(i32 %x, i32 %amt) #0 {
 ; CHECK-ARM-LABEL: fshr_sub_mvn:
 ; CHECK-ARM:       @ %bb.0: @ %entry
-; CHECK-ARM-NEXT:    rsb r1, r1, #31
+; CHECK-ARM-NEXT:    mvn r1, r1
 ; CHECK-ARM-NEXT:    ror r0, r0, r1
 ; CHECK-ARM-NEXT:    bx lr
 ;
 ; CHECK-BE-LABEL: fshr_sub_mvn:
 ; CHECK-BE:       @ %bb.0: @ %entry
-; CHECK-BE-NEXT:    rsb r1, r1, #31
+; CHECK-BE-NEXT:    mvn r1, r1
 ; CHECK-BE-NEXT:    ror r0, r0, r1
 ; CHECK-BE-NEXT:    bx lr
 ;
 ; CHECK-THUMB-LABEL: fshr_sub_mvn:
 ; CHECK-THUMB:       @ %bb.0: @ %entry
-; CHECK-THUMB-NEXT:    rsb.w r1, r1, #31
+; CHECK-THUMB-NEXT:    mvns r1, r1
 ; CHECK-THUMB-NEXT:    rors r0, r1
 ; CHECK-THUMB-NEXT:    bx lr
 ;
 ; CHECK-ALIGN-LABEL: fshr_sub_mvn:
 ; CHECK-ALIGN:       @ %bb.0: @ %entry
-; CHECK-ALIGN-NEXT:    rsb.w r1, r1, #31
+; CHECK-ALIGN-NEXT:    mvns r1, r1
 ; CHECK-ALIGN-NEXT:    rors r0, r1
 ; CHECK-ALIGN-NEXT:    bx lr
 ;
 ; CHECK-V6M-LABEL: fshr_sub_mvn:
 ; CHECK-V6M:       @ %bb.0: @ %entry
-; CHECK-V6M-NEXT:    movs r2, #31
-; CHECK-V6M-NEXT:    subs r1, r2, r1
+; CHECK-V6M-NEXT:    mvns r1, r1
 ; CHECK-V6M-NEXT:    rors r0, r1
 ; CHECK-V6M-NEXT:    bx lr
 entry:
diff --git a/llvm/test/CodeGen/ARM/shifter_operand.ll b/llvm/test/CodeGen/ARM/shifter_operand.ll
index 00922b1bf2492..b9e2a3aa30e4d 100644
--- a/llvm/test/CodeGen/ARM/shifter_operand.ll
+++ b/llvm/test/CodeGen/ARM/shifter_operand.ll
@@ -14,7 +14,6 @@ define i32 @test1(i32 %X, i32 %Y, i8 %sh) {
 ;
 ; CHECK-THUMB-LABEL: test1:
 ; CHECK-THUMB:       @ %bb.0:
-; CHECK-THUMB-NEXT:    uxtb r2, r2
 ; CHECK-THUMB-NEXT:    lsls r1, r2
 ; CHECK-THUMB-NEXT:    add r0, r1
 ; CHECK-THUMB-NEXT:    bx lr
@@ -33,7 +32,6 @@ define i32 @test2(i32 %X, i32 %Y, i8 %sh) {
 ;
 ; CHECK-THUMB-LABEL: test2:
 ; CHECK-THUMB:       @ %bb.0:
-; CHECK-THUMB-NEXT:    uxtb r2, r2
 ; CHECK-THUMB-NEXT:    asrs r1, r2
 ; CHECK-THUMB-NEXT:    bics r0, r1
 ; CHECK-THUMB-NEXT:    bx lr
diff --git a/llvm/test/CodeGen/Thumb2/shift_parts.ll b/llvm/test/CodeGen/Thumb2/shift_parts.ll
index b4ac405d82ed5..6e2103b140b25 100644
--- a/llvm/test/CodeGen/Thumb2/shift_parts.ll
+++ b/llvm/test/CodeGen/Thumb2/shift_parts.ll
@@ -10,15 +10,14 @@ define i64 @shift_left_reg(i64 %x, i64 %y) {
 ;
 ; CHECK-NON-MVE-LABEL: shift_left_reg:
 ; CHECK-NON-MVE:       @ %bb.0: @ %entry
-; CHECK-NON-MVE-NEXT:    rsb.w r3, r2, #32
-; CHECK-NON-MVE-NEXT:    lsls r1, r2
-; CHECK-NON-MVE-NEXT:    lsr.w r3, r0, r3
-; CHECK-NON-MVE-NEXT:    orrs r1, r3
-; CHECK-NON-MVE-NEXT:    subs.w r3, r2, #32
-; CHECK-NON-MVE-NEXT:    it pl
-; CHECK-NON-MVE-NEXT:    lslpl.w r1, r0, r3
-; CHECK-NON-MVE-NEXT:    lsl.w r0, r0, r2
-; CHECK-NON-MVE-NEXT:    it pl
+; CHECK-NON-MVE-NEXT:    lsl.w r12, r1, r2
+; CHECK-NON-MVE-NEXT:    rsbs r1, r2, #0
+; CHECK-NON-MVE-NEXT:    lsr.w r3, r0, r1
+; CHECK-NON-MVE-NEXT:    lsls r0, r2
+; CHECK-NON-MVE-NEXT:    subs.w r1, r2, #32
+; CHECK-NON-MVE-NEXT:    mov r1, r0
+; CHECK-NON-MVE-NEXT:    ite mi
+; CHECK-NON-MVE-NEXT:    orrmi.w r1, r3, r12
 ; CHECK-NON-MVE-NEXT:    movpl r0, #0
 ; CHECK-NON-MVE-NEXT:    bx lr
 entry:
@@ -85,15 +84,14 @@ define i64 @shift_right_reg(i64 %x, i64 %y) {
 ;
 ; CHECK-NON-MVE-LABEL: shift_right_reg:
 ; CHECK-NON-MVE:       @ %bb.0: @ %entry
-; CHECK-NON-MVE-NEXT:    rsb.w r3, r2, #32
-; CHECK-NON-MVE-NEXT:    lsrs r0, r2
-; CHECK-NON-MVE-NEXT:    lsl.w r3, r1, r3
-; CHECK-NON-MVE-NEXT:    orrs r0, r3
-; CHECK-NON-MVE-NEXT:    subs.w r3, r2, #32
-; CHECK-NON-MVE-NEXT:    it pl
-; CHECK-NON-MVE-NEXT:    lsrpl.w r0, r1, r3
-; CHECK-NON-MVE-NEXT:    lsr.w r1, r1, r2
-; CHECK-NON-MVE-NEXT:    it pl
+; CHECK-NON-MVE-NEXT:    lsr.w r12, r0, r2
+; CHECK-NON-MVE-NEXT:    rsbs r0, r2, #0
+; CHECK-NON-MVE-NEXT:    lsl.w r3, r1, r0
+; CHECK-NON-MVE-NEXT:    lsrs r1, r2
+; CHECK-NON-MVE-NEXT:    subs.w r0, r2, #32
+; CHECK-NON-MVE-NEXT:    mov r0, r1
+; CHECK-NON-MVE-NEXT:    ite mi
+; CHECK-NON-MVE-NEXT:    orrmi.w r0, r12, r3
 ; CHECK-NON-MVE-NEXT:    movpl r1, #0
 ; CHECK-NON-MVE-NEXT:    bx lr
 entry:
@@ -159,18 +157,19 @@ define i64 @shift_arithmetic_right_reg(i64 %x, i64 %y) {
 ;
 ; CHECK-NON-MVE-LABEL: shift_arithmetic_right_reg:
 ; CHECK-NON-MVE:       @ %bb.0: @ %entry
-; CHECK-NON-MVE-NEXT:    rsb.w r3, r2, #32
-; CHECK-NON-MVE-NEXT:    lsrs r0, r2
-; CHECK-NON-MVE-NEXT:    lsl.w r3, r1, r3
-; CHECK-NON-MVE-NEXT:    orrs r0, r3
-; CHECK-NON-MVE-NEXT:    subs.w r3, r2, #32
-; CHECK-NON-MVE-NEXT:    asr.w r2, r1, r2
-; CHECK-NON-MVE-NEXT:    it pl
-; CHECK-NON-MVE-NEXT:    asrpl.w r0, r1, r3
-; CHECK-NON-MVE-NEXT:    it pl
-; CHECK-NON-MVE-NEXT:    asrpl r2, r1, #31
-; CHECK-NON-MVE-NEXT:    mov r1, r2
-; CHECK-NON-MVE-NEXT:    bx lr
+; CHECK-NON-MVE-NEXT:    .save {r7, lr}
+; CHECK-NON-MVE-NEXT:    push {r7, lr}
+; CHECK-NON-MVE-NEXT:    lsr.w r12, r0, r2
+; CHECK-NON-MVE-NEXT:    rsbs r0, r2, #0
+; CHECK-NON-MVE-NEXT:    asr.w r3, r1, r2
+; CHECK-NON-MVE-NEXT:    lsl.w lr, r1, r0
+; CHECK-NON-MVE-NEXT:    subs.w r0, r2, #32
+; CHECK-NON-MVE-NEXT:    mov r0, r3
+; CHECK-NON-MVE-NEXT:    ite mi
+; CHECK-NON-MVE-NEXT:    orrmi.w r0, r12, lr
+; CHECK-NON-MVE-NEXT:    asrpl r3, r1, #31
+; CHECK-NON-MVE-NEXT:    mov r1, r3
+; CHECK-NON-MVE-NEXT:    pop {r7, pc}
 entry:
   %shr = ashr i64 %x, %y
   ret i64 %shr
diff --git a/llvm/test/CodeGen/Thumb2/thumb2-shifter.ll b/llvm/test/CodeGen/Thumb2/thumb2-shifter.ll
index 538fc2214d2c8..effa595ba073e 100644
--- a/llvm/test/CodeGen/Thumb2/thumb2-shifter.ll
+++ b/llvm/test/CodeGen/Thumb2/thumb2-shifter.ll
@@ -40,7 +40,6 @@ define i32 @t2ADDrs_ror(i32 %X, i32 %Y) {
 
 define i32 @t2ADDrs_noRegShift(i32 %X, i32 %Y, i8 %sh) {
 ; A8: t2ADDrs_noRegShift
-; A8: uxtb r2, r2
 ; A8: lsls r1, r2
 ; A8: add  r0, r1
 
@@ -55,7 +54,6 @@ define i32 @t2ADDrs_noRegShift(i32 %X, i32 %Y, i8 %sh) {
 
 define i32 @t2ADDrs_noRegShift2(i32 %X, i32 %Y, i8 %sh) {
 ; A8: t2ADDrs_noRegShift2
-; A8: uxtb r2, r2
 ; A8: lsrs r1, r2
 ; A8: add  r0, r1
 
@@ -70,7 +68,6 @@ define i32 @t2ADDrs_noRegShift2(i32 %X, i32 %Y, i8 %sh) {
 
 define i32 @t2ADDrs_noRegShift3(i32 %X, i32 %Y, i8 %sh) {
 ; A8: t2ADDrs_noRegShift3
-; A8: uxtb r2, r2
 ; A8: asrs r1, r2
 ; A8: add  r0, r1
 



More information about the llvm-commits mailing list