; 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-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-THUMB ; RUN: llc -mtriple=thumbv7m %s -o - | FileCheck %s --check-prefixes=CHECK-THUMB ; RUN: llc -mtriple=thumbv6m %s -o - | FileCheck %s --check-prefix=CHECK-V6M 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: 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: 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: rsbs r1, r1, #0 ; CHECK-THUMB-NEXT: rors r0, r1 ; CHECK-THUMB-NEXT: bx lr ; ; CHECK-V6M-LABEL: fshl_add_mod: ; 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 = 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 define i32 @fshl_sub_rsb(i32 %x, i32 %amt) #0 { ; CHECK-ARM-LABEL: fshl_sub_rsb: ; CHECK-ARM: @ %bb.0: @ %entry ; 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: ror r0, r0, r1 ; CHECK-BE-NEXT: bx lr ; ; CHECK-THUMB-LABEL: fshl_sub_rsb: ; CHECK-THUMB: @ %bb.0: @ %entry ; CHECK-THUMB-NEXT: rors r0, r1 ; CHECK-THUMB-NEXT: bx lr ; ; CHECK-V6M-LABEL: fshl_sub_rsb: ; CHECK-V6M: @ %bb.0: @ %entry ; 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 -> fshl lowers to sub amt,#31 then ror (mod-32 equivalent); fshr uses MVN+ror define i32 @fshl_sub_31(i32 %x, i32 %amt) #0 { ; CHECK-ARM-LABEL: fshl_sub_31: ; 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_31: ; 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_31: ; CHECK-THUMB: @ %bb.0: @ %entry ; CHECK-THUMB-NEXT: subs r1, #31 ; CHECK-THUMB-NEXT: rors r0, r1 ; CHECK-THUMB-NEXT: bx lr ; ; CHECK-V6M-LABEL: fshl_sub_31: ; 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-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: ror r0, r0, r1 ; CHECK-ARM-NEXT: bx lr ; ; CHECK-BE-LABEL: fshr_add_mod: ; CHECK-BE: @ %bb.0: @ %entry ; 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: rors r0, r1 ; CHECK-THUMB-NEXT: bx lr ; ; CHECK-V6M-LABEL: fshr_add_mod: ; CHECK-V6M: @ %bb.0: @ %entry ; 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, #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, #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: rsbs r1, r1, #0 ; CHECK-THUMB-NEXT: rors r0, r1 ; CHECK-THUMB-NEXT: bx lr ; ; CHECK-V6M-LABEL: fshr_sub_rsb: ; 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 = 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: 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: 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: mvns r1, r1 ; CHECK-THUMB-NEXT: rors r0, r1 ; CHECK-THUMB-NEXT: bx lr ; ; CHECK-V6M-LABEL: fshr_sub_mvn: ; CHECK-V6M: @ %bb.0: @ %entry ; CHECK-V6M-NEXT: mvns r1, 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-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 }