mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-12-23 15:29:51 +00:00
be110d99db
The old mask in f24 wasn't well chosen because the lshr would always be zero. CodeGen didn't detect this but InstCombine would. The new mask ensures that both shifts are needed. f26 is specifically testing for a wrap-around mask. The AND can be applied to just the shift left, either before or after the shift. Again, CodeGen kept it in the original form but InstCombine would mask after the shift instead. The exact choice of NILF isn't important for the test so I just dropped it and kept the rotate. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@199115 91177308-0d34-0410-b5e6-96231b3b80d8
483 lines
11 KiB
LLVM
483 lines
11 KiB
LLVM
; Test sequences that can use RISBG with a zeroed first operand.
|
|
; The tests here assume that RISBLG isn't available.
|
|
;
|
|
; RUN: llc < %s -mtriple=s390x-linux-gnu -mcpu=z10 | FileCheck %s
|
|
|
|
; Test an extraction of bit 0 from a right-shifted value.
|
|
define i32 @f1(i32 %foo) {
|
|
; CHECK-LABEL: f1:
|
|
; CHECK: risbg %r2, %r2, 63, 191, 54
|
|
; CHECK: br %r14
|
|
%shr = lshr i32 %foo, 10
|
|
%and = and i32 %shr, 1
|
|
ret i32 %and
|
|
}
|
|
|
|
; ...and again with i64.
|
|
define i64 @f2(i64 %foo) {
|
|
; CHECK-LABEL: f2:
|
|
; CHECK: risbg %r2, %r2, 63, 191, 54
|
|
; CHECK: br %r14
|
|
%shr = lshr i64 %foo, 10
|
|
%and = and i64 %shr, 1
|
|
ret i64 %and
|
|
}
|
|
|
|
; Test an extraction of other bits from a right-shifted value.
|
|
define i32 @f3(i32 %foo) {
|
|
; CHECK-LABEL: f3:
|
|
; CHECK: risbg %r2, %r2, 60, 189, 42
|
|
; CHECK: br %r14
|
|
%shr = lshr i32 %foo, 22
|
|
%and = and i32 %shr, 12
|
|
ret i32 %and
|
|
}
|
|
|
|
; ...and again with i64.
|
|
define i64 @f4(i64 %foo) {
|
|
; CHECK-LABEL: f4:
|
|
; CHECK: risbg %r2, %r2, 60, 189, 42
|
|
; CHECK: br %r14
|
|
%shr = lshr i64 %foo, 22
|
|
%and = and i64 %shr, 12
|
|
ret i64 %and
|
|
}
|
|
|
|
; Test an extraction of most bits from a right-shifted value.
|
|
; The range should be reduced to exclude the zeroed high bits.
|
|
define i32 @f5(i32 %foo) {
|
|
; CHECK-LABEL: f5:
|
|
; CHECK: risbg %r2, %r2, 34, 188, 62
|
|
; CHECK: br %r14
|
|
%shr = lshr i32 %foo, 2
|
|
%and = and i32 %shr, -8
|
|
ret i32 %and
|
|
}
|
|
|
|
; ...and again with i64.
|
|
define i64 @f6(i64 %foo) {
|
|
; CHECK-LABEL: f6:
|
|
; CHECK: risbg %r2, %r2, 2, 188, 62
|
|
; CHECK: br %r14
|
|
%shr = lshr i64 %foo, 2
|
|
%and = and i64 %shr, -8
|
|
ret i64 %and
|
|
}
|
|
|
|
; Try the next value up (mask ....1111001). This needs a separate shift
|
|
; and mask.
|
|
define i32 @f7(i32 %foo) {
|
|
; CHECK-LABEL: f7:
|
|
; CHECK: srl %r2, 2
|
|
; CHECK: nill %r2, 65529
|
|
; CHECK: br %r14
|
|
%shr = lshr i32 %foo, 2
|
|
%and = and i32 %shr, -7
|
|
ret i32 %and
|
|
}
|
|
|
|
; ...and again with i64.
|
|
define i64 @f8(i64 %foo) {
|
|
; CHECK-LABEL: f8:
|
|
; CHECK: srlg %r2, %r2, 2
|
|
; CHECK: nill %r2, 65529
|
|
; CHECK: br %r14
|
|
%shr = lshr i64 %foo, 2
|
|
%and = and i64 %shr, -7
|
|
ret i64 %and
|
|
}
|
|
|
|
; Test an extraction of bits from a left-shifted value. The range should
|
|
; be reduced to exclude the zeroed low bits.
|
|
define i32 @f9(i32 %foo) {
|
|
; CHECK-LABEL: f9:
|
|
; CHECK: risbg %r2, %r2, 56, 189, 2
|
|
; CHECK: br %r14
|
|
%shr = shl i32 %foo, 2
|
|
%and = and i32 %shr, 255
|
|
ret i32 %and
|
|
}
|
|
|
|
; ...and again with i64.
|
|
define i64 @f10(i64 %foo) {
|
|
; CHECK-LABEL: f10:
|
|
; CHECK: risbg %r2, %r2, 56, 189, 2
|
|
; CHECK: br %r14
|
|
%shr = shl i64 %foo, 2
|
|
%and = and i64 %shr, 255
|
|
ret i64 %and
|
|
}
|
|
|
|
; Try a wrap-around mask (mask ....111100001111). This needs a separate shift
|
|
; and mask.
|
|
define i32 @f11(i32 %foo) {
|
|
; CHECK-LABEL: f11:
|
|
; CHECK: sll %r2, 2
|
|
; CHECK: nill %r2, 65295
|
|
; CHECK: br %r14
|
|
%shr = shl i32 %foo, 2
|
|
%and = and i32 %shr, -241
|
|
ret i32 %and
|
|
}
|
|
|
|
; ...and again with i64.
|
|
define i64 @f12(i64 %foo) {
|
|
; CHECK-LABEL: f12:
|
|
; CHECK: sllg %r2, %r2, 2
|
|
; CHECK: nill %r2, 65295
|
|
; CHECK: br %r14
|
|
%shr = shl i64 %foo, 2
|
|
%and = and i64 %shr, -241
|
|
ret i64 %and
|
|
}
|
|
|
|
; Test an extraction from a rotated value, no mask wraparound.
|
|
; This is equivalent to the lshr case, because the bits from the
|
|
; shl are not used.
|
|
define i32 @f13(i32 %foo) {
|
|
; CHECK-LABEL: f13:
|
|
; CHECK: risbg %r2, %r2, 56, 188, 46
|
|
; CHECK: br %r14
|
|
%parta = shl i32 %foo, 14
|
|
%partb = lshr i32 %foo, 18
|
|
%rotl = or i32 %parta, %partb
|
|
%and = and i32 %rotl, 248
|
|
ret i32 %and
|
|
}
|
|
|
|
; ...and again with i64.
|
|
define i64 @f14(i64 %foo) {
|
|
; CHECK-LABEL: f14:
|
|
; CHECK: risbg %r2, %r2, 56, 188, 14
|
|
; CHECK: br %r14
|
|
%parta = shl i64 %foo, 14
|
|
%partb = lshr i64 %foo, 50
|
|
%rotl = or i64 %parta, %partb
|
|
%and = and i64 %rotl, 248
|
|
ret i64 %and
|
|
}
|
|
|
|
; Try a case in which only the bits from the shl are used.
|
|
define i32 @f15(i32 %foo) {
|
|
; CHECK-LABEL: f15:
|
|
; CHECK: risbg %r2, %r2, 47, 177, 14
|
|
; CHECK: br %r14
|
|
%parta = shl i32 %foo, 14
|
|
%partb = lshr i32 %foo, 18
|
|
%rotl = or i32 %parta, %partb
|
|
%and = and i32 %rotl, 114688
|
|
ret i32 %and
|
|
}
|
|
|
|
; ...and again with i64.
|
|
define i64 @f16(i64 %foo) {
|
|
; CHECK-LABEL: f16:
|
|
; CHECK: risbg %r2, %r2, 47, 177, 14
|
|
; CHECK: br %r14
|
|
%parta = shl i64 %foo, 14
|
|
%partb = lshr i64 %foo, 50
|
|
%rotl = or i64 %parta, %partb
|
|
%and = and i64 %rotl, 114688
|
|
ret i64 %and
|
|
}
|
|
|
|
; Test a 32-bit rotate in which both parts of the OR are needed.
|
|
; This needs a separate shift and mask.
|
|
define i32 @f17(i32 %foo) {
|
|
; CHECK-LABEL: f17:
|
|
; CHECK: rll %r2, %r2, 4
|
|
; CHECK: nilf %r2, 126
|
|
; CHECK: br %r14
|
|
%parta = shl i32 %foo, 4
|
|
%partb = lshr i32 %foo, 28
|
|
%rotl = or i32 %parta, %partb
|
|
%and = and i32 %rotl, 126
|
|
ret i32 %and
|
|
}
|
|
|
|
; ...and for i64, where RISBG should do the rotate too.
|
|
define i64 @f18(i64 %foo) {
|
|
; CHECK-LABEL: f18:
|
|
; CHECK: risbg %r2, %r2, 57, 190, 4
|
|
; CHECK: br %r14
|
|
%parta = shl i64 %foo, 4
|
|
%partb = lshr i64 %foo, 60
|
|
%rotl = or i64 %parta, %partb
|
|
%and = and i64 %rotl, 126
|
|
ret i64 %and
|
|
}
|
|
|
|
; Test an arithmetic shift right in which some of the sign bits are kept.
|
|
; This needs a separate shift and mask.
|
|
define i32 @f19(i32 %foo) {
|
|
; CHECK-LABEL: f19:
|
|
; CHECK: sra %r2, 28
|
|
; CHECK: nilf %r2, 30
|
|
; CHECK: br %r14
|
|
%shr = ashr i32 %foo, 28
|
|
%and = and i32 %shr, 30
|
|
ret i32 %and
|
|
}
|
|
|
|
; ...and again with i64. In this case RISBG is the best way of doing the AND.
|
|
define i64 @f20(i64 %foo) {
|
|
; CHECK-LABEL: f20:
|
|
; CHECK: srag [[REG:%r[0-5]]], %r2, 60
|
|
; CHECK: risbg %r2, [[REG]], 59, 190, 0
|
|
; CHECK: br %r14
|
|
%shr = ashr i64 %foo, 60
|
|
%and = and i64 %shr, 30
|
|
ret i64 %and
|
|
}
|
|
|
|
; Now try an arithmetic right shift in which the sign bits aren't needed.
|
|
; Introduce a second use of %shr so that the ashr doesn't decompose to
|
|
; an lshr.
|
|
define i32 @f21(i32 %foo, i32 *%dest) {
|
|
; CHECK-LABEL: f21:
|
|
; CHECK: risbg %r2, %r2, 60, 190, 36
|
|
; CHECK: br %r14
|
|
%shr = ashr i32 %foo, 28
|
|
store i32 %shr, i32 *%dest
|
|
%and = and i32 %shr, 14
|
|
ret i32 %and
|
|
}
|
|
|
|
; ...and again with i64.
|
|
define i64 @f22(i64 %foo, i64 *%dest) {
|
|
; CHECK-LABEL: f22:
|
|
; CHECK: risbg %r2, %r2, 60, 190, 4
|
|
; CHECK: br %r14
|
|
%shr = ashr i64 %foo, 60
|
|
store i64 %shr, i64 *%dest
|
|
%and = and i64 %shr, 14
|
|
ret i64 %and
|
|
}
|
|
|
|
; Check that we use RISBG for shifted values even if the AND is a
|
|
; natural zero extension.
|
|
define i64 @f23(i64 %foo) {
|
|
; CHECK-LABEL: f23:
|
|
; CHECK: risbg %r2, %r2, 56, 191, 62
|
|
; CHECK: br %r14
|
|
%shr = lshr i64 %foo, 2
|
|
%and = and i64 %shr, 255
|
|
ret i64 %and
|
|
}
|
|
|
|
; Test a case where the AND comes before a rotate. This needs a separate
|
|
; mask and rotate.
|
|
define i32 @f24(i32 %foo) {
|
|
; CHECK-LABEL: f24:
|
|
; CHECK: nilf %r2, 254
|
|
; CHECK: rll %r2, %r2, 29
|
|
; CHECK: br %r14
|
|
%and = and i32 %foo, 254
|
|
%parta = lshr i32 %and, 3
|
|
%partb = shl i32 %and, 29
|
|
%rotl = or i32 %parta, %partb
|
|
ret i32 %rotl
|
|
}
|
|
|
|
; ...and again with i64, where a single RISBG is enough.
|
|
define i64 @f25(i64 %foo) {
|
|
; CHECK-LABEL: f25:
|
|
; CHECK: risbg %r2, %r2, 57, 187, 3
|
|
; CHECK: br %r14
|
|
%and = and i64 %foo, 14
|
|
%parta = shl i64 %and, 3
|
|
%partb = lshr i64 %and, 61
|
|
%rotl = or i64 %parta, %partb
|
|
ret i64 %rotl
|
|
}
|
|
|
|
; Test a wrap-around case in which the AND comes before a rotate.
|
|
; This again needs a separate mask and rotate.
|
|
define i32 @f26(i32 %foo) {
|
|
; CHECK-LABEL: f26:
|
|
; CHECK: rll %r2, %r2, 5
|
|
; CHECK: br %r14
|
|
%and = and i32 %foo, -49
|
|
%parta = shl i32 %and, 5
|
|
%partb = lshr i32 %and, 27
|
|
%rotl = or i32 %parta, %partb
|
|
ret i32 %rotl
|
|
}
|
|
|
|
; ...and again with i64, where a single RISBG is OK.
|
|
define i64 @f27(i64 %foo) {
|
|
; CHECK-LABEL: f27:
|
|
; CHECK: risbg %r2, %r2, 55, 180, 5
|
|
; CHECK: br %r14
|
|
%and = and i64 %foo, -49
|
|
%parta = shl i64 %and, 5
|
|
%partb = lshr i64 %and, 59
|
|
%rotl = or i64 %parta, %partb
|
|
ret i64 %rotl
|
|
}
|
|
|
|
; Test a case where the AND comes before a shift left.
|
|
define i32 @f28(i32 %foo) {
|
|
; CHECK-LABEL: f28:
|
|
; CHECK: risbg %r2, %r2, 32, 173, 17
|
|
; CHECK: br %r14
|
|
%and = and i32 %foo, 32766
|
|
%shl = shl i32 %and, 17
|
|
ret i32 %shl
|
|
}
|
|
|
|
; ...and again with i64.
|
|
define i64 @f29(i64 %foo) {
|
|
; CHECK-LABEL: f29:
|
|
; CHECK: risbg %r2, %r2, 0, 141, 49
|
|
; CHECK: br %r14
|
|
%and = and i64 %foo, 32766
|
|
%shl = shl i64 %and, 49
|
|
ret i64 %shl
|
|
}
|
|
|
|
; Test the next shift up from f28, in which the mask should get shortened.
|
|
define i32 @f30(i32 %foo) {
|
|
; CHECK-LABEL: f30:
|
|
; CHECK: risbg %r2, %r2, 32, 172, 18
|
|
; CHECK: br %r14
|
|
%and = and i32 %foo, 32766
|
|
%shl = shl i32 %and, 18
|
|
ret i32 %shl
|
|
}
|
|
|
|
; ...and again with i64.
|
|
define i64 @f31(i64 %foo) {
|
|
; CHECK-LABEL: f31:
|
|
; CHECK: risbg %r2, %r2, 0, 140, 50
|
|
; CHECK: br %r14
|
|
%and = and i64 %foo, 32766
|
|
%shl = shl i64 %and, 50
|
|
ret i64 %shl
|
|
}
|
|
|
|
; Test a wrap-around case in which the shift left comes after the AND.
|
|
; We can't use RISBG for the shift in that case.
|
|
define i32 @f32(i32 %foo) {
|
|
; CHECK-LABEL: f32:
|
|
; CHECK: sll %r2
|
|
; CHECK: br %r14
|
|
%and = and i32 %foo, -7
|
|
%shl = shl i32 %and, 10
|
|
ret i32 %shl
|
|
}
|
|
|
|
; ...and again with i64.
|
|
define i64 @f33(i64 %foo) {
|
|
; CHECK-LABEL: f33:
|
|
; CHECK: sllg %r2
|
|
; CHECK: br %r14
|
|
%and = and i64 %foo, -7
|
|
%shl = shl i64 %and, 10
|
|
ret i64 %shl
|
|
}
|
|
|
|
; Test a case where the AND comes before a shift right.
|
|
define i32 @f34(i32 %foo) {
|
|
; CHECK-LABEL: f34:
|
|
; CHECK: risbg %r2, %r2, 57, 191, 55
|
|
; CHECK: br %r14
|
|
%and = and i32 %foo, 65535
|
|
%shl = lshr i32 %and, 9
|
|
ret i32 %shl
|
|
}
|
|
|
|
; ...and again with i64.
|
|
define i64 @f35(i64 %foo) {
|
|
; CHECK-LABEL: f35:
|
|
; CHECK: risbg %r2, %r2, 57, 191, 55
|
|
; CHECK: br %r14
|
|
%and = and i64 %foo, 65535
|
|
%shl = lshr i64 %and, 9
|
|
ret i64 %shl
|
|
}
|
|
|
|
; Test a wrap-around case where the AND comes before a shift right.
|
|
; We can't use RISBG for the shift in that case.
|
|
define i32 @f36(i32 %foo) {
|
|
; CHECK-LABEL: f36:
|
|
; CHECK: srl %r2
|
|
; CHECK: br %r14
|
|
%and = and i32 %foo, -25
|
|
%shl = lshr i32 %and, 1
|
|
ret i32 %shl
|
|
}
|
|
|
|
; ...and again with i64.
|
|
define i64 @f37(i64 %foo) {
|
|
; CHECK-LABEL: f37:
|
|
; CHECK: srlg %r2
|
|
; CHECK: br %r14
|
|
%and = and i64 %foo, -25
|
|
%shl = lshr i64 %and, 1
|
|
ret i64 %shl
|
|
}
|
|
|
|
; Test a combination involving a large ASHR and a shift left. We can't
|
|
; use RISBG there.
|
|
define i64 @f38(i64 %foo) {
|
|
; CHECK-LABEL: f38:
|
|
; CHECK: srag {{%r[0-5]}}
|
|
; CHECK: sllg {{%r[0-5]}}
|
|
; CHECK: br %r14
|
|
%ashr = ashr i64 %foo, 32
|
|
%shl = shl i64 %ashr, 5
|
|
ret i64 %shl
|
|
}
|
|
|
|
; Try a similar thing in which no shifted sign bits are kept.
|
|
define i64 @f39(i64 %foo, i64 *%dest) {
|
|
; CHECK-LABEL: f39:
|
|
; CHECK: srag [[REG:%r[01345]]], %r2, 35
|
|
; CHECK: risbg %r2, %r2, 33, 189, 31
|
|
; CHECK: br %r14
|
|
%ashr = ashr i64 %foo, 35
|
|
store i64 %ashr, i64 *%dest
|
|
%shl = shl i64 %ashr, 2
|
|
%and = and i64 %shl, 2147483647
|
|
ret i64 %and
|
|
}
|
|
|
|
; ...and again with the next highest shift value, where one sign bit is kept.
|
|
define i64 @f40(i64 %foo, i64 *%dest) {
|
|
; CHECK-LABEL: f40:
|
|
; CHECK: srag [[REG:%r[01345]]], %r2, 36
|
|
; CHECK: risbg %r2, [[REG]], 33, 189, 2
|
|
; CHECK: br %r14
|
|
%ashr = ashr i64 %foo, 36
|
|
store i64 %ashr, i64 *%dest
|
|
%shl = shl i64 %ashr, 2
|
|
%and = and i64 %shl, 2147483647
|
|
ret i64 %and
|
|
}
|
|
|
|
; Check a case where the result is zero-extended.
|
|
define i64 @f41(i32 %a) {
|
|
; CHECK-LABEL: f41
|
|
; CHECK: risbg %r2, %r2, 36, 191, 62
|
|
; CHECK: br %r14
|
|
%shl = shl i32 %a, 2
|
|
%shr = lshr i32 %shl, 4
|
|
%ext = zext i32 %shr to i64
|
|
ret i64 %ext
|
|
}
|
|
|
|
; In this case the sign extension is converted to a pair of 32-bit shifts,
|
|
; which is then extended to 64 bits. We previously used the wrong bit size
|
|
; when testing whether the shifted-in bits of the shift right were significant.
|
|
define i64 @f42(i1 %x) {
|
|
; CHECK-LABEL: f42:
|
|
; CHECK: sll %r2, 31
|
|
; CHECK: sra %r2, 31
|
|
; CHECK: llgcr %r2, %r2
|
|
; CHECK: br %r14
|
|
%ext = sext i1 %x to i8
|
|
%ext2 = zext i8 %ext to i64
|
|
ret i64 %ext2
|
|
}
|