This pseudo-instruction stores two small (8-bit) registers into one wide (16-bit) register. But apparently the order matters a lot to the register allocator. This patch changes the order of inserting the registers to optimize for the best register allocation in the tests of shift32.ll. It might be detrimental in other cases, but keeping the registers in the same physical register seems like it would be a common case. Differential Revision: https://reviews.llvm.org/D140573
578 lines
14 KiB
LLVM
578 lines
14 KiB
LLVM
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
|
|
; RUN: llc < %s -mtriple=avr -mattr=movw -verify-machineinstrs | FileCheck %s
|
|
|
|
define i32 @shl_i32_1(i32 %a) {
|
|
; CHECK-LABEL: shl_i32_1:
|
|
; CHECK: ; %bb.0:
|
|
; CHECK-NEXT: lsl r22
|
|
; CHECK-NEXT: rol r23
|
|
; CHECK-NEXT: rol r24
|
|
; CHECK-NEXT: rol r25
|
|
; CHECK-NEXT: ret
|
|
%res = shl i32 %a, 1
|
|
ret i32 %res
|
|
}
|
|
|
|
define i32 @shl_i32_2(i32 %a) {
|
|
; CHECK-LABEL: shl_i32_2:
|
|
; CHECK: ; %bb.0:
|
|
; CHECK-NEXT: lsl r22
|
|
; CHECK-NEXT: rol r23
|
|
; CHECK-NEXT: rol r24
|
|
; CHECK-NEXT: rol r25
|
|
; CHECK-NEXT: lsl r22
|
|
; CHECK-NEXT: rol r23
|
|
; CHECK-NEXT: rol r24
|
|
; CHECK-NEXT: rol r25
|
|
; CHECK-NEXT: ret
|
|
%res = shl i32 %a, 2
|
|
ret i32 %res
|
|
}
|
|
|
|
define i32 @shl_i32_4(i32 %a) {
|
|
; CHECK-LABEL: shl_i32_4:
|
|
; CHECK: ; %bb.0:
|
|
; CHECK-NEXT: swap r25
|
|
; CHECK-NEXT: andi r25, 240
|
|
; CHECK-NEXT: swap r24
|
|
; CHECK-NEXT: eor r25, r24
|
|
; CHECK-NEXT: andi r24, 240
|
|
; CHECK-NEXT: eor r25, r24
|
|
; CHECK-NEXT: swap r23
|
|
; CHECK-NEXT: eor r24, r23
|
|
; CHECK-NEXT: andi r23, 240
|
|
; CHECK-NEXT: eor r24, r23
|
|
; CHECK-NEXT: swap r22
|
|
; CHECK-NEXT: eor r23, r22
|
|
; CHECK-NEXT: andi r22, 240
|
|
; CHECK-NEXT: eor r23, r22
|
|
; CHECK-NEXT: ret
|
|
%res = shl i32 %a, 4
|
|
ret i32 %res
|
|
}
|
|
|
|
; shift four bits and then shift one bit
|
|
define i32 @shl_i32_5(i32 %a) {
|
|
; CHECK-LABEL: shl_i32_5:
|
|
; CHECK: ; %bb.0:
|
|
; CHECK-NEXT: swap r25
|
|
; CHECK-NEXT: andi r25, 240
|
|
; CHECK-NEXT: swap r24
|
|
; CHECK-NEXT: eor r25, r24
|
|
; CHECK-NEXT: andi r24, 240
|
|
; CHECK-NEXT: eor r25, r24
|
|
; CHECK-NEXT: swap r23
|
|
; CHECK-NEXT: eor r24, r23
|
|
; CHECK-NEXT: andi r23, 240
|
|
; CHECK-NEXT: eor r24, r23
|
|
; CHECK-NEXT: swap r22
|
|
; CHECK-NEXT: eor r23, r22
|
|
; CHECK-NEXT: andi r22, 240
|
|
; CHECK-NEXT: eor r23, r22
|
|
; CHECK-NEXT: lsl r22
|
|
; CHECK-NEXT: rol r23
|
|
; CHECK-NEXT: rol r24
|
|
; CHECK-NEXT: rol r25
|
|
; CHECK-NEXT: ret
|
|
%res = shl i32 %a, 5
|
|
ret i32 %res
|
|
}
|
|
|
|
; shift two to the right and move the registers around
|
|
define i32 @shl_i32_6(i32 %a) {
|
|
; CHECK-LABEL: shl_i32_6:
|
|
; CHECK: ; %bb.0:
|
|
; CHECK-NEXT: lsr r25
|
|
; CHECK-NEXT: ror r24
|
|
; CHECK-NEXT: ror r23
|
|
; CHECK-NEXT: ror r22
|
|
; CHECK-NEXT: mov r18, r1
|
|
; CHECK-NEXT: ror r18
|
|
; CHECK-NEXT: lsr r25
|
|
; CHECK-NEXT: ror r24
|
|
; CHECK-NEXT: ror r23
|
|
; CHECK-NEXT: ror r22
|
|
; CHECK-NEXT: ror r18
|
|
; CHECK-NEXT: mov r25, r24
|
|
; CHECK-NEXT: mov r24, r23
|
|
; CHECK-NEXT: mov r19, r22
|
|
; CHECK-NEXT: movw r22, r18
|
|
; CHECK-NEXT: ret
|
|
%res = shl i32 %a, 6
|
|
ret i32 %res
|
|
}
|
|
|
|
|
|
; shift one to the right and move registers around
|
|
define i32 @shl_i32_7(i32 %a) {
|
|
; CHECK-LABEL: shl_i32_7:
|
|
; CHECK: ; %bb.0:
|
|
; CHECK-NEXT: lsr r25
|
|
; CHECK-NEXT: ror r24
|
|
; CHECK-NEXT: ror r23
|
|
; CHECK-NEXT: ror r22
|
|
; CHECK-NEXT: mov r18, r1
|
|
; CHECK-NEXT: ror r18
|
|
; CHECK-NEXT: mov r25, r24
|
|
; CHECK-NEXT: mov r24, r23
|
|
; CHECK-NEXT: mov r19, r22
|
|
; CHECK-NEXT: movw r22, r18
|
|
; CHECK-NEXT: ret
|
|
%res = shl i32 %a, 7
|
|
ret i32 %res
|
|
}
|
|
|
|
define i32 @shl_i32_8(i32 %a) {
|
|
; CHECK-LABEL: shl_i32_8:
|
|
; CHECK: ; %bb.0:
|
|
; CHECK-NEXT: mov r25, r24
|
|
; CHECK-NEXT: mov r24, r23
|
|
; CHECK-NEXT: mov r23, r22
|
|
; CHECK-NEXT: mov r22, r1
|
|
; CHECK-NEXT: ret
|
|
%res = shl i32 %a, 8
|
|
ret i32 %res
|
|
}
|
|
|
|
define i32 @shl_i32_9(i32 %a) {
|
|
; CHECK-LABEL: shl_i32_9:
|
|
; CHECK: ; %bb.0:
|
|
; CHECK-NEXT: lsl r22
|
|
; CHECK-NEXT: rol r23
|
|
; CHECK-NEXT: rol r24
|
|
; CHECK-NEXT: mov r25, r24
|
|
; CHECK-NEXT: mov r24, r23
|
|
; CHECK-NEXT: mov r23, r22
|
|
; CHECK-NEXT: mov r22, r1
|
|
; CHECK-NEXT: ret
|
|
%res = shl i32 %a, 9
|
|
ret i32 %res
|
|
}
|
|
|
|
; shift 3 of 4 registers and move the others around
|
|
define i32 @shl_i32_12(i32 %a) {
|
|
; CHECK-LABEL: shl_i32_12:
|
|
; CHECK: ; %bb.0:
|
|
; CHECK-NEXT: swap r24
|
|
; CHECK-NEXT: andi r24, 240
|
|
; CHECK-NEXT: swap r23
|
|
; CHECK-NEXT: eor r24, r23
|
|
; CHECK-NEXT: andi r23, 240
|
|
; CHECK-NEXT: eor r24, r23
|
|
; CHECK-NEXT: swap r22
|
|
; CHECK-NEXT: eor r23, r22
|
|
; CHECK-NEXT: andi r22, 240
|
|
; CHECK-NEXT: eor r23, r22
|
|
; CHECK-NEXT: mov r25, r24
|
|
; CHECK-NEXT: mov r24, r23
|
|
; CHECK-NEXT: mov r23, r22
|
|
; CHECK-NEXT: mov r22, r1
|
|
; CHECK-NEXT: ret
|
|
%res = shl i32 %a, 12
|
|
ret i32 %res
|
|
}
|
|
|
|
define i32 @shl_i32_15(i32 %a) {
|
|
; CHECK-LABEL: shl_i32_15:
|
|
; CHECK: ; %bb.0:
|
|
; CHECK-NEXT: movw r18, r22
|
|
; CHECK-NEXT: lsr r24
|
|
; CHECK-NEXT: ror r19
|
|
; CHECK-NEXT: ror r18
|
|
; CHECK-NEXT: mov r23, r1
|
|
; CHECK-NEXT: ror r23
|
|
; CHECK-NEXT: mov r22, r1
|
|
; CHECK-NEXT: movw r24, r18
|
|
; CHECK-NEXT: ret
|
|
%res = shl i32 %a, 15
|
|
ret i32 %res
|
|
}
|
|
|
|
; This is a special case: this shift is performed directly inside SelectionDAG
|
|
; instead of as a custom lowering like the other shift operations.
|
|
define i32 @shl_i32_16(i32 %a) {
|
|
; CHECK-LABEL: shl_i32_16:
|
|
; CHECK: ; %bb.0:
|
|
; CHECK-NEXT: movw r24, r22
|
|
; CHECK-NEXT: ldi r22, 0
|
|
; CHECK-NEXT: ldi r23, 0
|
|
; CHECK-NEXT: ret
|
|
%res = shl i32 %a, 16
|
|
ret i32 %res
|
|
}
|
|
|
|
; Combined with the register allocator, shift instructions can sometimes be
|
|
; optimized away entirely. The least significant registers are simply stored
|
|
; directly instead of moving them first.
|
|
define void @shl_i32_16_ptr(i32 %a, ptr %ptr) {
|
|
; CHECK-LABEL: shl_i32_16_ptr:
|
|
; CHECK: ; %bb.0:
|
|
; CHECK-NEXT: movw r30, r20
|
|
; CHECK-NEXT: std Z+2, r22
|
|
; CHECK-NEXT: std Z+3, r23
|
|
; CHECK-NEXT: ldi r24, 0
|
|
; CHECK-NEXT: ldi r25, 0
|
|
; CHECK-NEXT: st Z, r24
|
|
; CHECK-NEXT: std Z+1, r25
|
|
; CHECK-NEXT: ret
|
|
%res = shl i32 %a, 16
|
|
store i32 %res, ptr %ptr
|
|
ret void
|
|
}
|
|
|
|
; shift only the most significant byte and then move it
|
|
define i32 @shl_i32_28(i32 %a) {
|
|
; CHECK-LABEL: shl_i32_28:
|
|
; CHECK: ; %bb.0:
|
|
; CHECK-NEXT: swap r22
|
|
; CHECK-NEXT: andi r22, 240
|
|
; CHECK-NEXT: mov r25, r22
|
|
; CHECK-NEXT: mov r24, r1
|
|
; CHECK-NEXT: mov r23, r1
|
|
; CHECK-NEXT: mov r22, r1
|
|
; CHECK-NEXT: ret
|
|
%res = shl i32 %a, 28
|
|
ret i32 %res
|
|
}
|
|
|
|
; move the rightmost bit to the leftmost bit and clear the rest
|
|
define i32 @shl_i32_31(i32 %a) {
|
|
; CHECK-LABEL: shl_i32_31:
|
|
; CHECK: ; %bb.0:
|
|
; CHECK-NEXT: lsr r22
|
|
; CHECK-NEXT: mov r25, r1
|
|
; CHECK-NEXT: ror r25
|
|
; CHECK-NEXT: mov r24, r1
|
|
; CHECK-NEXT: mov r23, r1
|
|
; CHECK-NEXT: mov r22, r1
|
|
; CHECK-NEXT: ret
|
|
%res = shl i32 %a, 31
|
|
ret i32 %res
|
|
}
|
|
|
|
define i32 @lshr_i32_1(i32 %a) {
|
|
; CHECK-LABEL: lshr_i32_1:
|
|
; CHECK: ; %bb.0:
|
|
; CHECK-NEXT: lsr r25
|
|
; CHECK-NEXT: ror r24
|
|
; CHECK-NEXT: ror r23
|
|
; CHECK-NEXT: ror r22
|
|
; CHECK-NEXT: ret
|
|
%res = lshr i32 %a, 1
|
|
ret i32 %res
|
|
}
|
|
|
|
define i32 @lshr_i32_2(i32 %a) {
|
|
; CHECK-LABEL: lshr_i32_2:
|
|
; CHECK: ; %bb.0:
|
|
; CHECK-NEXT: lsr r25
|
|
; CHECK-NEXT: ror r24
|
|
; CHECK-NEXT: ror r23
|
|
; CHECK-NEXT: ror r22
|
|
; CHECK-NEXT: lsr r25
|
|
; CHECK-NEXT: ror r24
|
|
; CHECK-NEXT: ror r23
|
|
; CHECK-NEXT: ror r22
|
|
; CHECK-NEXT: ret
|
|
%res = lshr i32 %a, 2
|
|
ret i32 %res
|
|
}
|
|
|
|
define i32 @lshr_i32_4(i32 %a) {
|
|
; CHECK-LABEL: lshr_i32_4:
|
|
; CHECK: ; %bb.0:
|
|
; CHECK-NEXT: swap r22
|
|
; CHECK-NEXT: andi r22, 15
|
|
; CHECK-NEXT: swap r23
|
|
; CHECK-NEXT: eor r22, r23
|
|
; CHECK-NEXT: andi r23, 15
|
|
; CHECK-NEXT: eor r22, r23
|
|
; CHECK-NEXT: swap r24
|
|
; CHECK-NEXT: eor r23, r24
|
|
; CHECK-NEXT: andi r24, 15
|
|
; CHECK-NEXT: eor r23, r24
|
|
; CHECK-NEXT: swap r25
|
|
; CHECK-NEXT: eor r24, r25
|
|
; CHECK-NEXT: andi r25, 15
|
|
; CHECK-NEXT: eor r24, r25
|
|
; CHECK-NEXT: ret
|
|
%res = lshr i32 %a, 4
|
|
ret i32 %res
|
|
}
|
|
|
|
define i32 @lshr_i32_6(i32 %a) {
|
|
; CHECK-LABEL: lshr_i32_6:
|
|
; CHECK: ; %bb.0:
|
|
; CHECK-NEXT: lsl r22
|
|
; CHECK-NEXT: rol r23
|
|
; CHECK-NEXT: rol r24
|
|
; CHECK-NEXT: rol r25
|
|
; CHECK-NEXT: mov r19, r1
|
|
; CHECK-NEXT: rol r19
|
|
; CHECK-NEXT: lsl r22
|
|
; CHECK-NEXT: rol r23
|
|
; CHECK-NEXT: rol r24
|
|
; CHECK-NEXT: rol r25
|
|
; CHECK-NEXT: rol r19
|
|
; CHECK-NEXT: mov r22, r23
|
|
; CHECK-NEXT: mov r23, r24
|
|
; CHECK-NEXT: mov r18, r25
|
|
; CHECK-NEXT: movw r24, r18
|
|
; CHECK-NEXT: ret
|
|
%res = lshr i32 %a, 6
|
|
ret i32 %res
|
|
}
|
|
|
|
define i32 @lshr_i32_7(i32 %a) {
|
|
; CHECK-LABEL: lshr_i32_7:
|
|
; CHECK: ; %bb.0:
|
|
; CHECK-NEXT: lsl r22
|
|
; CHECK-NEXT: rol r23
|
|
; CHECK-NEXT: rol r24
|
|
; CHECK-NEXT: rol r25
|
|
; CHECK-NEXT: mov r19, r1
|
|
; CHECK-NEXT: rol r19
|
|
; CHECK-NEXT: mov r22, r23
|
|
; CHECK-NEXT: mov r23, r24
|
|
; CHECK-NEXT: mov r18, r25
|
|
; CHECK-NEXT: movw r24, r18
|
|
; CHECK-NEXT: ret
|
|
%res = lshr i32 %a, 7
|
|
ret i32 %res
|
|
}
|
|
|
|
define i32 @lshr_i32_8(i32 %a) {
|
|
; CHECK-LABEL: lshr_i32_8:
|
|
; CHECK: ; %bb.0:
|
|
; CHECK-NEXT: mov r22, r23
|
|
; CHECK-NEXT: mov r23, r24
|
|
; CHECK-NEXT: mov r24, r25
|
|
; CHECK-NEXT: mov r25, r1
|
|
; CHECK-NEXT: ret
|
|
%res = lshr i32 %a, 8
|
|
ret i32 %res
|
|
}
|
|
|
|
define i32 @lshr_i32_9(i32 %a) {
|
|
; CHECK-LABEL: lshr_i32_9:
|
|
; CHECK: ; %bb.0:
|
|
; CHECK-NEXT: lsr r25
|
|
; CHECK-NEXT: ror r24
|
|
; CHECK-NEXT: ror r23
|
|
; CHECK-NEXT: mov r22, r23
|
|
; CHECK-NEXT: mov r23, r24
|
|
; CHECK-NEXT: mov r24, r25
|
|
; CHECK-NEXT: mov r25, r1
|
|
; CHECK-NEXT: ret
|
|
%res = lshr i32 %a, 9
|
|
ret i32 %res
|
|
}
|
|
|
|
define i32 @lshr_i32_16(i32 %a) {
|
|
; CHECK-LABEL: lshr_i32_16:
|
|
; CHECK: ; %bb.0:
|
|
; CHECK-NEXT: movw r22, r24
|
|
; CHECK-NEXT: ldi r24, 0
|
|
; CHECK-NEXT: ldi r25, 0
|
|
; CHECK-NEXT: ret
|
|
%res = lshr i32 %a, 16
|
|
ret i32 %res
|
|
}
|
|
|
|
define i32 @lshr_i32_24(i32 %a) {
|
|
; CHECK-LABEL: lshr_i32_24:
|
|
; CHECK: ; %bb.0:
|
|
; CHECK-NEXT: mov r22, r25
|
|
; CHECK-NEXT: mov r23, r1
|
|
; CHECK-NEXT: mov r24, r1
|
|
; CHECK-NEXT: mov r25, r1
|
|
; CHECK-NEXT: ret
|
|
%res = lshr i32 %a, 24
|
|
ret i32 %res
|
|
}
|
|
|
|
define i32 @lshr_i32_31(i32 %a) {
|
|
; CHECK-LABEL: lshr_i32_31:
|
|
; CHECK: ; %bb.0:
|
|
; CHECK-NEXT: lsl r25
|
|
; CHECK-NEXT: mov r22, r1
|
|
; CHECK-NEXT: rol r22
|
|
; CHECK-NEXT: mov r23, r1
|
|
; CHECK-NEXT: mov r24, r1
|
|
; CHECK-NEXT: mov r25, r1
|
|
; CHECK-NEXT: ret
|
|
%res = lshr i32 %a, 31
|
|
ret i32 %res
|
|
}
|
|
|
|
define i32 @ashr_i32_1(i32 %a) {
|
|
; CHECK-LABEL: ashr_i32_1:
|
|
; CHECK: ; %bb.0:
|
|
; CHECK-NEXT: asr r25
|
|
; CHECK-NEXT: ror r24
|
|
; CHECK-NEXT: ror r23
|
|
; CHECK-NEXT: ror r22
|
|
; CHECK-NEXT: ret
|
|
%res = ashr i32 %a, 1
|
|
ret i32 %res
|
|
}
|
|
|
|
define i32 @ashr_i32_2(i32 %a) {
|
|
; CHECK-LABEL: ashr_i32_2:
|
|
; CHECK: ; %bb.0:
|
|
; CHECK-NEXT: asr r25
|
|
; CHECK-NEXT: ror r24
|
|
; CHECK-NEXT: ror r23
|
|
; CHECK-NEXT: ror r22
|
|
; CHECK-NEXT: asr r25
|
|
; CHECK-NEXT: ror r24
|
|
; CHECK-NEXT: ror r23
|
|
; CHECK-NEXT: ror r22
|
|
; CHECK-NEXT: ret
|
|
%res = ashr i32 %a, 2
|
|
ret i32 %res
|
|
}
|
|
|
|
; can't use the swap/andi/eor trick here
|
|
define i32 @ashr_i32_4(i32 %a) {
|
|
; CHECK-LABEL: ashr_i32_4:
|
|
; CHECK: ; %bb.0:
|
|
; CHECK-NEXT: asr r25
|
|
; CHECK-NEXT: ror r24
|
|
; CHECK-NEXT: ror r23
|
|
; CHECK-NEXT: ror r22
|
|
; CHECK-NEXT: asr r25
|
|
; CHECK-NEXT: ror r24
|
|
; CHECK-NEXT: ror r23
|
|
; CHECK-NEXT: ror r22
|
|
; CHECK-NEXT: asr r25
|
|
; CHECK-NEXT: ror r24
|
|
; CHECK-NEXT: ror r23
|
|
; CHECK-NEXT: ror r22
|
|
; CHECK-NEXT: asr r25
|
|
; CHECK-NEXT: ror r24
|
|
; CHECK-NEXT: ror r23
|
|
; CHECK-NEXT: ror r22
|
|
; CHECK-NEXT: ret
|
|
%res = ashr i32 %a, 4
|
|
ret i32 %res
|
|
}
|
|
|
|
define i32 @ashr_i32_7(i32 %a) {
|
|
; CHECK-LABEL: ashr_i32_7:
|
|
; CHECK: ; %bb.0:
|
|
; CHECK-NEXT: lsl r22
|
|
; CHECK-NEXT: rol r23
|
|
; CHECK-NEXT: rol r24
|
|
; CHECK-NEXT: rol r25
|
|
; CHECK-NEXT: sbc r19, r19
|
|
; CHECK-NEXT: mov r22, r23
|
|
; CHECK-NEXT: mov r23, r24
|
|
; CHECK-NEXT: mov r18, r25
|
|
; CHECK-NEXT: movw r24, r18
|
|
; CHECK-NEXT: ret
|
|
%res = ashr i32 %a, 7
|
|
ret i32 %res
|
|
}
|
|
|
|
; TODO: this could be optimized to 4 movs, instead of 5.
|
|
define i32 @ashr_i32_8(i32 %a) {
|
|
; CHECK-LABEL: ashr_i32_8:
|
|
; CHECK: ; %bb.0:
|
|
; CHECK-NEXT: mov r19, r25
|
|
; CHECK-NEXT: lsl r19
|
|
; CHECK-NEXT: sbc r19, r19
|
|
; CHECK-NEXT: mov r22, r23
|
|
; CHECK-NEXT: mov r23, r24
|
|
; CHECK-NEXT: mov r18, r25
|
|
; CHECK-NEXT: movw r24, r18
|
|
; CHECK-NEXT: ret
|
|
%res = ashr i32 %a, 8
|
|
ret i32 %res
|
|
}
|
|
|
|
define i32 @ashr_i32_16(i32 %a) {
|
|
; CHECK-LABEL: ashr_i32_16:
|
|
; CHECK: ; %bb.0:
|
|
; CHECK-NEXT: movw r22, r24
|
|
; CHECK-NEXT: lsl r25
|
|
; CHECK-NEXT: sbc r25, r25
|
|
; CHECK-NEXT: mov r24, r25
|
|
; CHECK-NEXT: ret
|
|
%res = ashr i32 %a, 16
|
|
ret i32 %res
|
|
}
|
|
|
|
define i32 @ashr_i32_17(i32 %a) {
|
|
; CHECK-LABEL: ashr_i32_17:
|
|
; CHECK: ; %bb.0:
|
|
; CHECK-NEXT: movw r22, r24
|
|
; CHECK-NEXT: lsl r25
|
|
; CHECK-NEXT: sbc r25, r25
|
|
; CHECK-NEXT: asr r23
|
|
; CHECK-NEXT: ror r22
|
|
; CHECK-NEXT: mov r24, r25
|
|
; CHECK-NEXT: ret
|
|
%res = ashr i32 %a, 17
|
|
ret i32 %res
|
|
}
|
|
|
|
define i32 @ashr_i32_22(i32 %a) {
|
|
; CHECK-LABEL: ashr_i32_22:
|
|
; CHECK: ; %bb.0:
|
|
; CHECK-NEXT: lsl r24
|
|
; CHECK-NEXT: rol r25
|
|
; CHECK-NEXT: sbc r18, r18
|
|
; CHECK-NEXT: lsl r24
|
|
; CHECK-NEXT: rol r25
|
|
; CHECK-NEXT: mov r23, r18
|
|
; CHECK-NEXT: rol r23
|
|
; CHECK-NEXT: mov r22, r25
|
|
; CHECK-NEXT: mov r19, r18
|
|
; CHECK-NEXT: movw r24, r18
|
|
; CHECK-NEXT: ret
|
|
%res = ashr i32 %a, 22
|
|
ret i32 %res
|
|
}
|
|
|
|
define i32 @ashr_i32_23(i32 %a) {
|
|
; CHECK-LABEL: ashr_i32_23:
|
|
; CHECK: ; %bb.0:
|
|
; CHECK-NEXT: lsl r24
|
|
; CHECK-NEXT: rol r25
|
|
; CHECK-NEXT: sbc r23, r23
|
|
; CHECK-NEXT: mov r22, r25
|
|
; CHECK-NEXT: mov r24, r23
|
|
; CHECK-NEXT: mov r25, r23
|
|
; CHECK-NEXT: ret
|
|
%res = ashr i32 %a, 23
|
|
ret i32 %res
|
|
}
|
|
|
|
define i32 @ashr_i32_30(i32 %a) {
|
|
; CHECK-LABEL: ashr_i32_30:
|
|
; CHECK: ; %bb.0:
|
|
; CHECK-NEXT: lsl r25
|
|
; CHECK-NEXT: sbc r23, r23
|
|
; CHECK-NEXT: lsl r25
|
|
; CHECK-NEXT: mov r22, r23
|
|
; CHECK-NEXT: rol r22
|
|
; CHECK-NEXT: mov r24, r23
|
|
; CHECK-NEXT: mov r25, r23
|
|
; CHECK-NEXT: ret
|
|
%res = ashr i32 %a, 30
|
|
ret i32 %res
|
|
}
|
|
|
|
define i32 @ashr_i32_31(i32 %a) {
|
|
; CHECK-LABEL: ashr_i32_31:
|
|
; CHECK: ; %bb.0:
|
|
; CHECK-NEXT: lsl r25
|
|
; CHECK-NEXT: sbc r22, r22
|
|
; CHECK-NEXT: mov r23, r22
|
|
; CHECK-NEXT: movw r24, r22
|
|
; CHECK-NEXT: ret
|
|
%res = ashr i32 %a, 31
|
|
ret i32 %res
|
|
}
|