| ; 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 | |
| } | |