llvm/llvm/test/CodeGen/SystemZ/risbg-04.ll

; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
; Test sequences that can use RISBG with a zeroed first operand.
; The tests here assume that RISBLG is available.
;
; RUN: llc < %s -mtriple=s390x-linux-gnu -mcpu=z196 | FileCheck %s

; Test an extraction of bit 0 from a right-shifted value.
define i32 @f1(i32 %foo) {
; CHECK-LABEL: f1:
; CHECK:       # %bb.0:
; CHECK-NEXT:    risblg %r2, %r2, 31, 159, 54
; CHECK-NEXT:    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:       # %bb.0:
; CHECK-NEXT:    risbg %r2, %r2, 63, 191, 54
; CHECK-NEXT:    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:       # %bb.0:
; CHECK-NEXT:    risblg %r2, %r2, 28, 157, 42
; CHECK-NEXT:    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:       # %bb.0:
; CHECK-NEXT:    risbg %r2, %r2, 60, 189, 42
; CHECK-NEXT:    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:       # %bb.0:
; CHECK-NEXT:    risblg %r2, %r2, 2, 156, 62
; CHECK-NEXT:    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:       # %bb.0:
; CHECK-NEXT:    risbg %r2, %r2, 2, 188, 62
; CHECK-NEXT:    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:       # %bb.0:
; CHECK-NEXT:    srl %r2, 2
; CHECK-NEXT:    nill %r2, 65529
; CHECK-NEXT:    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:       # %bb.0:
; CHECK-NEXT:    srlg %r2, %r2, 2
; CHECK-NEXT:    nill %r2, 65529
; CHECK-NEXT:    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:       # %bb.0:
; CHECK-NEXT:    risblg %r2, %r2, 24, 157, 2
; CHECK-NEXT:    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:       # %bb.0:
; CHECK-NEXT:    risbg %r2, %r2, 56, 189, 2
; CHECK-NEXT:    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:       # %bb.0:
; CHECK-NEXT:    sll %r2, 2
; CHECK-NEXT:    nill %r2, 65295
; CHECK-NEXT:    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:       # %bb.0:
; CHECK-NEXT:    sllg %r2, %r2, 2
; CHECK-NEXT:    nill %r2, 65295
; CHECK-NEXT:    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:       # %bb.0:
; CHECK-NEXT:    risblg %r2, %r2, 24, 156, 46
; CHECK-NEXT:    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:       # %bb.0:
; CHECK-NEXT:    risbg %r2, %r2, 56, 188, 14
; CHECK-NEXT:    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:       # %bb.0:
; CHECK-NEXT:    risblg %r2, %r2, 15, 145, 14
; CHECK-NEXT:    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:       # %bb.0:
; CHECK-NEXT:    risbg %r2, %r2, 47, 177, 14
; CHECK-NEXT:    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:       # %bb.0:
; CHECK-NEXT:    rll %r2, %r2, 4
; CHECK-NEXT:    nilf %r2, 126
; CHECK-NEXT:    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:       # %bb.0:
; CHECK-NEXT:    risbg %r2, %r2, 57, 190, 4
; CHECK-NEXT:    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:       # %bb.0:
; CHECK-NEXT:    sra %r2, 28
; CHECK-NEXT:    nilf %r2, 30
; CHECK-NEXT:    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:       # %bb.0:
; CHECK-NEXT:    srag %r0, %r2, 60
; CHECK-NEXT:    risbg %r2, %r0, 59, 190, 0
; CHECK-NEXT:    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, ptr %dest) {
; CHECK-LABEL: f21:
; CHECK:       # %bb.0:
; CHECK-NEXT:    srak %r0, %r2, 28
; CHECK-NEXT:    risblg %r2, %r2, 28, 158, 36
; CHECK-NEXT:    st %r0, 0(%r3)
; CHECK-NEXT:    br %r14
  %shr = ashr i32 %foo, 28
  store i32 %shr, ptr %dest
  %and = and i32 %shr, 14
  ret i32 %and
}

; ...and again with i64.
define i64 @f22(i64 %foo, ptr %dest) {
; CHECK-LABEL: f22:
; CHECK:       # %bb.0:
; CHECK-NEXT:    srag %r0, %r2, 60
; CHECK-NEXT:    risbg %r2, %r2, 60, 190, 4
; CHECK-NEXT:    stg %r0, 0(%r3)
; CHECK-NEXT:    br %r14
  %shr = ashr i64 %foo, 60
  store i64 %shr, ptr %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:       # %bb.0:
; CHECK-NEXT:    risbg %r2, %r2, 56, 191, 62
; CHECK-NEXT:    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:       # %bb.0:
; CHECK-NEXT:    nilf %r2, 254
; CHECK-NEXT:    rll %r2, %r2, 29
; CHECK-NEXT:    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:       # %bb.0:
; CHECK-NEXT:    risbg %r2, %r2, 57, 187, 3
; CHECK-NEXT:    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:       # %bb.0:
; CHECK-NEXT:    nill %r2, 65487
; CHECK-NEXT:    rll %r2, %r2, 5
; CHECK-NEXT:    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:       # %bb.0:
; CHECK-NEXT:    risbg %r2, %r2, 55, 180, 5
; CHECK-NEXT:    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:       # %bb.0:
; CHECK-NEXT:    risblg %r2, %r2, 0, 141, 17
; CHECK-NEXT:    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:       # %bb.0:
; CHECK-NEXT:    risbg %r2, %r2, 0, 141, 49
; CHECK-NEXT:    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:       # %bb.0:
; CHECK-NEXT:    risblg %r2, %r2, 0, 140, 18
; CHECK-NEXT:    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:       # %bb.0:
; CHECK-NEXT:    risbg %r2, %r2, 0, 140, 50
; CHECK-NEXT:    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:       # %bb.0:
; CHECK-NEXT:    nilf %r2, 4194297
; CHECK-NEXT:    sll %r2, 10
; CHECK-NEXT:    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:       # %bb.0:
; CHECK-NEXT:    llihf %r0, 4194303
; CHECK-NEXT:    oilf %r0, 4294967289
; CHECK-NEXT:    ngr %r0, %r2
; CHECK-NEXT:    sllg %r2, %r0, 10
; CHECK-NEXT:    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:       # %bb.0:
; CHECK-NEXT:    risblg %r2, %r2, 25, 159, 55
; CHECK-NEXT:    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:       # %bb.0:
; CHECK-NEXT:    risbg %r2, %r2, 57, 191, 55
; CHECK-NEXT:    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:       # %bb.0:
; CHECK-NEXT:    nill %r2, 65510
; CHECK-NEXT:    srl %r2, 1
; CHECK-NEXT:    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:       # %bb.0:
; CHECK-NEXT:    nill %r2, 65510
; CHECK-NEXT:    srlg %r2, %r2, 1
; CHECK-NEXT:    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:       # %bb.0:
; CHECK-NEXT:    srag %r0, %r2, 32
; CHECK-NEXT:    sllg %r2, %r0, 5
; CHECK-NEXT:    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, ptr %dest) {
; CHECK-LABEL: f39:
; CHECK:       # %bb.0:
; CHECK-NEXT:    srag %r0, %r2, 35
; CHECK-NEXT:    risbg %r2, %r2, 33, 189, 31
; CHECK-NEXT:    stg %r0, 0(%r3)
; CHECK-NEXT:    br %r14
  %ashr = ashr i64 %foo, 35
  store i64 %ashr, ptr %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, ptr %dest) {
; CHECK-LABEL: f40:
; CHECK:       # %bb.0:
; CHECK-NEXT:    srag %r0, %r2, 36
; CHECK-NEXT:    risbg %r2, %r0, 33, 189, 2
; CHECK-NEXT:    stg %r0, 0(%r3)
; CHECK-NEXT:    br %r14
  %ashr = ashr i64 %foo, 36
  store i64 %ashr, ptr %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:       # %bb.0:
; CHECK-NEXT:    # kill: def $r2l killed $r2l def $r2d
; CHECK-NEXT:    risbg %r2, %r2, 36, 191, 62
; CHECK-NEXT:    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:       # %bb.0:
; CHECK-NEXT:    nilf %r2, 1
; CHECK-NEXT:    lcr %r0, %r2
; CHECK-NEXT:    llgcr %r2, %r0
; CHECK-NEXT:    br %r14
  %ext = sext i1 %x to i8
  %ext2 = zext i8 %ext to i64
  ret i64 %ext2
}

; Check that we get the case where a 64-bit shift is used by a 32-bit and.
; Note that this cannot use RISBLG, but should use RISBG.
define signext i32 @f43(i64 %x) {
; CHECK-LABEL: f43:
; CHECK:       # %bb.0:
; CHECK-NEXT:    risbg %r0, %r2, 32, 189, 52
; CHECK-NEXT:    lgfr %r2, %r0
; CHECK-NEXT:    br %r14
  %shr3 = lshr i64 %x, 12
  %shr3.tr = trunc i64 %shr3 to i32
  %conv = and i32 %shr3.tr, -4
  ret i32 %conv
}

; Check that we don't get the case where the 32-bit and mask is not contiguous
define signext i32 @f44(i64 %x) {
; CHECK-LABEL: f44:
; CHECK:       # %bb.0:
; CHECK-NEXT:    srlg %r2, %r2, 12
; CHECK-NEXT:    lghi %r0, 10
; CHECK-NEXT:    ngr %r2, %r0
; CHECK-NEXT:    br %r14
  %shr4 = lshr i64 %x, 12
  %conv = trunc i64 %shr4 to i32
  %and = and i32 %conv, 10
  ret i32 %and
}