[SystemZ] Add CodeGen test cases

This adds all CodeGen tests for the SystemZ target.

This version of the patch incorporates feedback from a review by
Sean Silva.  Thanks to all reviewers!

Patch by Richard Sandiford.



git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@181204 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Ulrich Weigand 2013-05-06 16:17:29 +00:00
parent 1d09d56fe1
commit b503b49b51
296 changed files with 31125 additions and 0 deletions

View File

@ -0,0 +1,107 @@
; Test selection of addresses with indices in cases where the address
; is used once.
;
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s
; A simple index address.
define void @f1(i64 %addr, i64 %index) {
; CHECK: f1:
; CHECK: lb %r0, 0(%r3,%r2)
; CHECK: br %r14
%add = add i64 %addr, %index
%ptr = inttoptr i64 %add to i8 *
%a = load volatile i8 *%ptr
ret void
}
; An address with an index and a displacement (order 1).
define void @f2(i64 %addr, i64 %index) {
; CHECK: f2:
; CHECK: lb %r0, 100(%r3,%r2)
; CHECK: br %r14
%add1 = add i64 %addr, %index
%add2 = add i64 %add1, 100
%ptr = inttoptr i64 %add2 to i8 *
%a = load volatile i8 *%ptr
ret void
}
; An address with an index and a displacement (order 2).
define void @f3(i64 %addr, i64 %index) {
; CHECK: f3:
; CHECK: lb %r0, 100(%r3,%r2)
; CHECK: br %r14
%add1 = add i64 %addr, 100
%add2 = add i64 %add1, %index
%ptr = inttoptr i64 %add2 to i8 *
%a = load volatile i8 *%ptr
ret void
}
; An address with an index and a subtracted displacement (order 1).
define void @f4(i64 %addr, i64 %index) {
; CHECK: f4:
; CHECK: lb %r0, -100(%r3,%r2)
; CHECK: br %r14
%add1 = add i64 %addr, %index
%add2 = sub i64 %add1, 100
%ptr = inttoptr i64 %add2 to i8 *
%a = load volatile i8 *%ptr
ret void
}
; An address with an index and a subtracted displacement (order 2).
define void @f5(i64 %addr, i64 %index) {
; CHECK: f5:
; CHECK: lb %r0, -100(%r3,%r2)
; CHECK: br %r14
%add1 = sub i64 %addr, 100
%add2 = add i64 %add1, %index
%ptr = inttoptr i64 %add2 to i8 *
%a = load volatile i8 *%ptr
ret void
}
; An address with an index and a displacement added using OR.
define void @f6(i64 %addr, i64 %index) {
; CHECK: f6:
; CHECK: nill %r2, 65528
; CHECK: lb %r0, 6(%r3,%r2)
; CHECK: br %r14
%aligned = and i64 %addr, -8
%or = or i64 %aligned, 6
%add = add i64 %or, %index
%ptr = inttoptr i64 %add to i8 *
%a = load volatile i8 *%ptr
ret void
}
; Like f6, but without the masking. This OR doesn't count as a displacement.
define void @f7(i64 %addr, i64 %index) {
; CHECK: f7:
; CHECK: oill %r2, 6
; CHECK: lb %r0, 0(%r3,%r2)
; CHECK: br %r14
%or = or i64 %addr, 6
%add = add i64 %or, %index
%ptr = inttoptr i64 %add to i8 *
%a = load volatile i8 *%ptr
ret void
}
; Like f6, but with the OR applied after the index. We don't know anything
; about the alignment of %add here.
define void @f8(i64 %addr, i64 %index) {
; CHECK: f8:
; CHECK: nill %r2, 65528
; CHECK: agr %r2, %r3
; CHECK: oill %r2, 6
; CHECK: lb %r0, 0(%r2)
; CHECK: br %r14
%aligned = and i64 %addr, -8
%add = add i64 %aligned, %index
%or = or i64 %add, 6
%ptr = inttoptr i64 %or to i8 *
%a = load volatile i8 *%ptr
ret void
}

View File

@ -0,0 +1,116 @@
; addr-01.ll in which the address is also used in a non-address context.
; The assumption here is that we should match complex addresses where
; possible, but this might well need to change in future.
;
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s
; A simple index address.
define void @f1(i64 %addr, i64 %index, i8 **%dst) {
; CHECK: f1:
; CHECK: lb %r0, 0(%r3,%r2)
; CHECK: br %r14
%add = add i64 %addr, %index
%ptr = inttoptr i64 %add to i8 *
%a = load volatile i8 *%ptr
store volatile i8 *%ptr, i8 **%dst
ret void
}
; An address with an index and a displacement (order 1).
define void @f2(i64 %addr, i64 %index, i8 **%dst) {
; CHECK: f2:
; CHECK: lb %r0, 100(%r3,%r2)
; CHECK: br %r14
%add1 = add i64 %addr, %index
%add2 = add i64 %add1, 100
%ptr = inttoptr i64 %add2 to i8 *
%a = load volatile i8 *%ptr
store volatile i8 *%ptr, i8 **%dst
ret void
}
; An address with an index and a displacement (order 2).
define void @f3(i64 %addr, i64 %index, i8 **%dst) {
; CHECK: f3:
; CHECK: lb %r0, 100(%r3,%r2)
; CHECK: br %r14
%add1 = add i64 %addr, 100
%add2 = add i64 %add1, %index
%ptr = inttoptr i64 %add2 to i8 *
%a = load volatile i8 *%ptr
store volatile i8 *%ptr, i8 **%dst
ret void
}
; An address with an index and a subtracted displacement (order 1).
define void @f4(i64 %addr, i64 %index, i8 **%dst) {
; CHECK: f4:
; CHECK: lb %r0, -100(%r3,%r2)
; CHECK: br %r14
%add1 = add i64 %addr, %index
%add2 = sub i64 %add1, 100
%ptr = inttoptr i64 %add2 to i8 *
%a = load volatile i8 *%ptr
store volatile i8 *%ptr, i8 **%dst
ret void
}
; An address with an index and a subtracted displacement (order 2).
define void @f5(i64 %addr, i64 %index, i8 **%dst) {
; CHECK: f5:
; CHECK: lb %r0, -100(%r3,%r2)
; CHECK: br %r14
%add1 = sub i64 %addr, 100
%add2 = add i64 %add1, %index
%ptr = inttoptr i64 %add2 to i8 *
%a = load volatile i8 *%ptr
store volatile i8 *%ptr, i8 **%dst
ret void
}
; An address with an index and a displacement added using OR.
define void @f6(i64 %addr, i64 %index, i8 **%dst) {
; CHECK: f6:
; CHECK: nill %r2, 65528
; CHECK: lb %r0, 6(%r3,%r2)
; CHECK: br %r14
%aligned = and i64 %addr, -8
%or = or i64 %aligned, 6
%add = add i64 %or, %index
%ptr = inttoptr i64 %add to i8 *
%a = load volatile i8 *%ptr
store volatile i8 *%ptr, i8 **%dst
ret void
}
; Like f6, but without the masking. This OR doesn't count as a displacement.
define void @f7(i64 %addr, i64 %index, i8 **%dst) {
; CHECK: f7:
; CHECK: oill %r2, 6
; CHECK: lb %r0, 0(%r3,%r2)
; CHECK: br %r14
%or = or i64 %addr, 6
%add = add i64 %or, %index
%ptr = inttoptr i64 %add to i8 *
%a = load volatile i8 *%ptr
store volatile i8 *%ptr, i8 **%dst
ret void
}
; Like f6, but with the OR applied after the index. We don't know anything
; about the alignment of %add here.
define void @f8(i64 %addr, i64 %index, i8 **%dst) {
; CHECK: f8:
; CHECK: nill %r2, 65528
; CHECK: agr %r2, %r3
; CHECK: oill %r2, 6
; CHECK: lb %r0, 0(%r2)
; CHECK: br %r14
%aligned = and i64 %addr, -8
%add = add i64 %aligned, %index
%or = or i64 %add, 6
%ptr = inttoptr i64 %or to i8 *
%a = load volatile i8 *%ptr
store volatile i8 *%ptr, i8 **%dst
ret void
}

View File

@ -0,0 +1,48 @@
; Test constant addresses, unlikely as they are.
;
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s
define void @f1() {
; CHECK: f1:
; CHECK: lb %r0, 0
; CHECK: br %r14
%ptr = inttoptr i64 0 to i8 *
%val = load volatile i8 *%ptr
ret void
}
define void @f2() {
; CHECK: f2:
; CHECK: lb %r0, -524288
; CHECK: br %r14
%ptr = inttoptr i64 -524288 to i8 *
%val = load volatile i8 *%ptr
ret void
}
define void @f3() {
; CHECK: f3:
; CHECK-NOT: lb %r0, -524289
; CHECK: br %r14
%ptr = inttoptr i64 -524289 to i8 *
%val = load volatile i8 *%ptr
ret void
}
define void @f4() {
; CHECK: f4:
; CHECK: lb %r0, 524287
; CHECK: br %r14
%ptr = inttoptr i64 524287 to i8 *
%val = load volatile i8 *%ptr
ret void
}
define void @f5() {
; CHECK: f5:
; CHECK-NOT: lb %r0, 524288
; CHECK: br %r14
%ptr = inttoptr i64 524288 to i8 *
%val = load volatile i8 *%ptr
ret void
}

View File

@ -0,0 +1,81 @@
; Test variable-sized allocas and addresses based on them in cases where
; stack arguments are needed.
;
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s -check-prefix=CHECK1
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s -check-prefix=CHECK2
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s -check-prefix=CHECK-A
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s -check-prefix=CHECK-B
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s -check-prefix=CHECK-C
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s -check-prefix=CHECK-D
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s -check-prefix=CHECK-FP
declare i64 @bar(i8 *%a, i8 *%b, i8 *%c, i8 *%d, i8 *%e, i64 %f, i64 %g)
; Allocate %length bytes and take addresses based on the result.
; There are two stack arguments, so an offset of 160 + 2 * 8 == 176
; is added to the copy of %r15.
define i64 @f1(i64 %length, i64 %index) {
; The full allocation sequence is:
;
; la %r0, 7(%r2) 1
; nill %r0, 0xfff8 1
; lgr %r1, %r15 2
; sgr %r1, %r0 1 2
; lgr %r15, %r1 2
;
; The third instruction does not depend on the first two, so check for
; two fully-ordered sequences.
;
; FIXME: a better sequence would be:
;
; lgr %r1, %r15
; sgr %r1, %r2
; nill %r1, 0xfff8
; lgr %r15, %r1
;
; CHECK1: f1:
; CHECK1: la %r0, 7(%r2)
; CHECK1: nill %r0, 65528
; CHECK1: sgr %r1, %r0
; CHECK1: lgr %r15, %r1
;
; CHECK2: f1:
; CHECK2: lgr %r1, %r15
; CHECK2: sgr %r1, %r0
; CHECK2: lgr %r15, %r1
;
; CHECK-A: f1:
; CHECK-A: lgr %r15, %r1
; CHECK-A: la %r2, 176(%r1)
;
; CHECK-B: f1:
; CHECK-B: lgr %r15, %r1
; CHECK-B: la %r3, 177(%r1)
;
; CHECK-C: f1:
; CHECK-C: lgr %r15, %r1
; CHECK-C: la %r4, 4095({{%r3,%r1|%r1,%r3}})
;
; CHECK-D: f1:
; CHECK-D: lgr %r15, %r1
; CHECK-D: lay %r5, 4096({{%r3,%r1|%r1,%r3}})
;
; CHECK-E: f1:
; CHECK-E: lgr %r15, %r1
; CHECK-E: lay %r6, 4271({{%r3,%r1|%r1,%r3}})
;
; CHECK-FP: f1:
; CHECK-FP: lgr %r11, %r15
; CHECK-FP: lmg %r6, %r15, 224(%r11)
%a = alloca i8, i64 %length
%b = getelementptr i8 *%a, i64 1
%cindex = add i64 %index, 3919
%c = getelementptr i8 *%a, i64 %cindex
%dindex = add i64 %index, 3920
%d = getelementptr i8 *%a, i64 %dindex
%eindex = add i64 %index, 4095
%e = getelementptr i8 *%a, i64 %eindex
%count = call i64 @bar(i8 *%a, i8 *%b, i8 *%c, i8 *%d, i8 *%e, i64 0, i64 0)
%res = add i64 %count, 1
ret i64 %res
}

View File

@ -0,0 +1,49 @@
; Make sure that the alloca offset isn't lost when the alloca result is
; used directly in a load or store. There must always be an LA or LAY.
;
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s -check-prefix=CHECK-A
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s -check-prefix=CHECK-B
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s -check-prefix=CHECK-C
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s -check-prefix=CHECK-D
declare i64 @bar(i8 *%a)
define i64 @f1(i64 %length, i64 %index) {
; CHECK-A: f1:
; CHECK-A: lgr %r15, [[ADDR:%r[1-5]]]
; CHECK-A: la %r2, 160([[ADDR]])
; CHECK-A: mvi 0(%r2), 0
;
; CHECK-B: f1:
; CHECK-B: lgr %r15, [[ADDR:%r[1-5]]]
; CHECK-B: la %r2, 160([[ADDR]])
; CHECK-B: mvi 4095(%r2), 1
;
; CHECK-C: f1:
; CHECK-C: lgr %r15, [[ADDR:%r[1-5]]]
; CHECK-C: la [[TMP:%r[1-5]]], 160(%r3,[[ADDR]])
; CHECK-C: mvi 0([[TMP]]), 2
;
; CHECK-D: f1:
; CHECK-D: lgr %r15, [[ADDR:%r[1-5]]]
; CHECK-D: la [[TMP:%r[1-5]]], 160(%r3,[[ADDR]])
; CHECK-D: mvi 4095([[TMP]]), 3
;
; CHECK-E: f1:
; CHECK-E: lgr %r15, [[ADDR:%r[1-5]]]
; CHECK-E: la [[TMP:%r[1-5]]], 160(%r3,[[ADDR]])
; CHECK-E: mviy 4096([[TMP]]), 4
%a = alloca i8, i64 %length
store i8 0, i8 *%a
%b = getelementptr i8 *%a, i64 4095
store i8 1, i8 *%b
%c = getelementptr i8 *%a, i64 %index
store i8 2, i8 *%c
%d = getelementptr i8 *%c, i64 4095
store i8 3, i8 *%d
%e = getelementptr i8 *%d, i64 1
store i8 4, i8 *%e
%count = call i64 @bar(i8 *%a)
%res = add i64 %count, 1
ret i64 %res
}

View File

@ -0,0 +1,129 @@
; Test 32-bit ANDs in which the second operand is variable.
;
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s
; Check NR.
define i32 @f1(i32 %a, i32 %b) {
; CHECK: f1:
; CHECK: nr %r2, %r3
; CHECK: br %r14
%and = and i32 %a, %b
ret i32 %and
}
; Check the low end of the N range.
define i32 @f2(i32 %a, i32 *%src) {
; CHECK: f2:
; CHECK: n %r2, 0(%r3)
; CHECK: br %r14
%b = load i32 *%src
%and = and i32 %a, %b
ret i32 %and
}
; Check the high end of the aligned N range.
define i32 @f3(i32 %a, i32 *%src) {
; CHECK: f3:
; CHECK: n %r2, 4092(%r3)
; CHECK: br %r14
%ptr = getelementptr i32 *%src, i64 1023
%b = load i32 *%ptr
%and = and i32 %a, %b
ret i32 %and
}
; Check the next word up, which should use NY instead of N.
define i32 @f4(i32 %a, i32 *%src) {
; CHECK: f4:
; CHECK: ny %r2, 4096(%r3)
; CHECK: br %r14
%ptr = getelementptr i32 *%src, i64 1024
%b = load i32 *%ptr
%and = and i32 %a, %b
ret i32 %and
}
; Check the high end of the aligned NY range.
define i32 @f5(i32 %a, i32 *%src) {
; CHECK: f5:
; CHECK: ny %r2, 524284(%r3)
; CHECK: br %r14
%ptr = getelementptr i32 *%src, i64 131071
%b = load i32 *%ptr
%and = and i32 %a, %b
ret i32 %and
}
; Check the next word up, which needs separate address logic.
; Other sequences besides this one would be OK.
define i32 @f6(i32 %a, i32 *%src) {
; CHECK: f6:
; CHECK: agfi %r3, 524288
; CHECK: n %r2, 0(%r3)
; CHECK: br %r14
%ptr = getelementptr i32 *%src, i64 131072
%b = load i32 *%ptr
%and = and i32 %a, %b
ret i32 %and
}
; Check the high end of the negative aligned NY range.
define i32 @f7(i32 %a, i32 *%src) {
; CHECK: f7:
; CHECK: ny %r2, -4(%r3)
; CHECK: br %r14
%ptr = getelementptr i32 *%src, i64 -1
%b = load i32 *%ptr
%and = and i32 %a, %b
ret i32 %and
}
; Check the low end of the NY range.
define i32 @f8(i32 %a, i32 *%src) {
; CHECK: f8:
; CHECK: ny %r2, -524288(%r3)
; CHECK: br %r14
%ptr = getelementptr i32 *%src, i64 -131072
%b = load i32 *%ptr
%and = and i32 %a, %b
ret i32 %and
}
; Check the next word down, which needs separate address logic.
; Other sequences besides this one would be OK.
define i32 @f9(i32 %a, i32 *%src) {
; CHECK: f9:
; CHECK: agfi %r3, -524292
; CHECK: n %r2, 0(%r3)
; CHECK: br %r14
%ptr = getelementptr i32 *%src, i64 -131073
%b = load i32 *%ptr
%and = and i32 %a, %b
ret i32 %and
}
; Check that N allows an index.
define i32 @f10(i32 %a, i64 %src, i64 %index) {
; CHECK: f10:
; CHECK: n %r2, 4092({{%r4,%r3|%r3,%r4}})
; CHECK: br %r14
%add1 = add i64 %src, %index
%add2 = add i64 %add1, 4092
%ptr = inttoptr i64 %add2 to i32 *
%b = load i32 *%ptr
%and = and i32 %a, %b
ret i32 %and
}
; Check that NY allows an index.
define i32 @f11(i32 %a, i64 %src, i64 %index) {
; CHECK: f11:
; CHECK: ny %r2, 4096({{%r4,%r3|%r3,%r4}})
; CHECK: br %r14
%add1 = add i64 %src, %index
%add2 = add i64 %add1, 4096
%ptr = inttoptr i64 %add2 to i32 *
%b = load i32 *%ptr
%and = and i32 %a, %b
ret i32 %and
}

View File

@ -0,0 +1,93 @@
; Test 32-bit ANDs in which the second operand is constant.
;
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s
; Check the lowest useful NILF value.
define i32 @f1(i32 %a) {
; CHECK: f1:
; CHECK: nilf %r2, 1
; CHECK: br %r14
%and = and i32 %a, 1
ret i32 %and
}
; Check the highest 16-bit constant that must be handled by NILF.
define i32 @f2(i32 %a) {
; CHECK: f2:
; CHECK: nilf %r2, 65534
; CHECK: br %r14
%and = and i32 %a, 65534
ret i32 %and
}
; ANDs of 0xffff are zero extensions from i16.
define i32 @f3(i32 %a) {
; CHECK: f3:
; CHECK: llhr %r2, %r2
; CHECK: br %r14
%and = and i32 %a, 65535
ret i32 %and
}
; Check the next value up, which must again use NILF.
define i32 @f4(i32 %a) {
; CHECK: f4:
; CHECK: nilf %r2, 65536
; CHECK: br %r14
%and = and i32 %a, 65536
ret i32 %and
}
; Check the lowest useful NILH value. (LLHR is used instead of NILH of 0.)
define i32 @f5(i32 %a) {
; CHECK: f5:
; CHECK: nilh %r2, 1
; CHECK: br %r14
%and = and i32 %a, 131071
ret i32 %and
}
; Check the highest useful NILF value.
define i32 @f6(i32 %a) {
; CHECK: f6:
; CHECK: nilf %r2, 4294901758
; CHECK: br %r14
%and = and i32 %a, -65538
ret i32 %and
}
; Check the highest useful NILH value, which is one up from the above.
define i32 @f7(i32 %a) {
; CHECK: f7:
; CHECK: nilh %r2, 65534
; CHECK: br %r14
%and = and i32 %a, -65537
ret i32 %and
}
; Check the low end of the NILL range, which is one up again.
define i32 @f8(i32 %a) {
; CHECK: f8:
; CHECK: nill %r2, 0
; CHECK: br %r14
%and = and i32 %a, -65536
ret i32 %and
}
; Check the next value up.
define i32 @f9(i32 %a) {
; CHECK: f9:
; CHECK: nill %r2, 1
; CHECK: br %r14
%and = and i32 %a, -65535
ret i32 %and
}
; Check the highest useful NILL value.
define i32 @f10(i32 %a) {
; CHECK: f10:
; CHECK: nill %r2, 65534
; CHECK: br %r14
%and = and i32 %a, -2
ret i32 %and
}

View File

@ -0,0 +1,94 @@
; Test 64-bit ANDs in which the second operand is variable.
;
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s
; Check NGR.
define i64 @f1(i64 %a, i64 %b) {
; CHECK: f1:
; CHECK: ngr %r2, %r3
; CHECK: br %r14
%and = and i64 %a, %b
ret i64 %and
}
; Check NG with no displacement.
define i64 @f2(i64 %a, i64 *%src) {
; CHECK: f2:
; CHECK: ng %r2, 0(%r3)
; CHECK: br %r14
%b = load i64 *%src
%and = and i64 %a, %b
ret i64 %and
}
; Check the high end of the aligned NG range.
define i64 @f3(i64 %a, i64 *%src) {
; CHECK: f3:
; CHECK: ng %r2, 524280(%r3)
; CHECK: br %r14
%ptr = getelementptr i64 *%src, i64 65535
%b = load i64 *%ptr
%and = and i64 %a, %b
ret i64 %and
}
; Check the next doubleword up, which needs separate address logic.
; Other sequences besides this one would be OK.
define i64 @f4(i64 %a, i64 *%src) {
; CHECK: f4:
; CHECK: agfi %r3, 524288
; CHECK: ng %r2, 0(%r3)
; CHECK: br %r14
%ptr = getelementptr i64 *%src, i64 65536
%b = load i64 *%ptr
%and = and i64 %a, %b
ret i64 %and
}
; Check the high end of the negative aligned NG range.
define i64 @f5(i64 %a, i64 *%src) {
; CHECK: f5:
; CHECK: ng %r2, -8(%r3)
; CHECK: br %r14
%ptr = getelementptr i64 *%src, i64 -1
%b = load i64 *%ptr
%and = and i64 %a, %b
ret i64 %and
}
; Check the low end of the NG range.
define i64 @f6(i64 %a, i64 *%src) {
; CHECK: f6:
; CHECK: ng %r2, -524288(%r3)
; CHECK: br %r14
%ptr = getelementptr i64 *%src, i64 -65536
%b = load i64 *%ptr
%and = and i64 %a, %b
ret i64 %and
}
; Check the next doubleword down, which needs separate address logic.
; Other sequences besides this one would be OK.
define i64 @f7(i64 %a, i64 *%src) {
; CHECK: f7:
; CHECK: agfi %r3, -524296
; CHECK: ng %r2, 0(%r3)
; CHECK: br %r14
%ptr = getelementptr i64 *%src, i64 -65537
%b = load i64 *%ptr
%and = and i64 %a, %b
ret i64 %and
}
; Check that NG allows an index.
define i64 @f8(i64 %a, i64 %src, i64 %index) {
; CHECK: f8:
; CHECK: ng %r2, 524280({{%r4,%r3|%r3,%r4}})
; CHECK: br %r14
%add1 = add i64 %src, %index
%add2 = add i64 %add1, 524280
%ptr = inttoptr i64 %add2 to i64 *
%b = load i64 *%ptr
%and = and i64 %a, %b
ret i64 %and
}

View File

@ -0,0 +1,180 @@
; Test 64-bit ANDs in which the second operand is constant.
;
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s
; There is no 64-bit AND instruction for a mask of 1.
; FIXME: we ought to be able to require "ngr %r2, %r0", but at the moment,
; two-address optimisations force "ngr %r0, %r2; lgr %r2, %r0" instead.
define i64 @f1(i64 %a) {
; CHECK: f1:
; CHECK: lghi %r0, 1
; CHECK: ngr
; CHECK: br %r14
%and = and i64 %a, 1
ret i64 %and
}
; Likewise 0xfffe.
define i64 @f2(i64 %a) {
; CHECK: f2:
; CHECK: llill %r0, 65534
; CHECK: ngr
; CHECK: br %r14
%and = and i64 %a, 65534
ret i64 %and
}
; ...but 0xffff is a 16-bit zero extension.
define i64 @f3(i64 %a) {
; CHECK: f3:
; CHECK: llghr %r2, %r2
; CHECK: br %r14
%and = and i64 %a, 65535
ret i64 %and
}
; Check the next value up, which again has no dedicated instruction.
define i64 @f4(i64 %a) {
; CHECK: f4:
; CHECK: llilh %r0, 1
; CHECK: ngr
; CHECK: br %r14
%and = and i64 %a, 65536
ret i64 %and
}
; Check 0xfffffffe.
define i64 @f5(i64 %a) {
; CHECK: f5:
; CHECK: lilf %r0, 4294967294
; CHECK: ngr
; CHECK: br %r14
%and = and i64 %a, 4294967294
ret i64 %and
}
; Check the next value up, which is a 32-bit zero extension.
define i64 @f6(i64 %a) {
; CHECK: f6:
; CHECK: llgfr %r2, %r2
; CHECK: br %r14
%and = and i64 %a, 4294967295
ret i64 %and
}
; Check the lowest useful NIHF value (0x00000001_ffffffff).
define i64 @f7(i64 %a) {
; CHECK: f7:
; CHECK: nihf %r2, 1
; CHECK: br %r14
%and = and i64 %a, 8589934591
ret i64 %and
}
; Check the low end of the NIHH range (0x0000ffff_ffffffff).
define i64 @f8(i64 %a) {
; CHECK: f8:
; CHECK: nihh %r2, 0
; CHECK: br %r14
%and = and i64 %a, 281474976710655
ret i64 %and
}
; Check the highest useful NIHH value (0xfffeffff_ffffffff).
define i64 @f9(i64 %a) {
; CHECK: f9:
; CHECK: nihh %r2, 65534
; CHECK: br %r14
%and = and i64 %a, -281474976710657
ret i64 %and
}
; Check the highest useful NIHF value (0xfffefffe_ffffffff).
define i64 @f10(i64 %a) {
; CHECK: f10:
; CHECK: nihf %r2, 4294901758
; CHECK: br %r14
%and = and i64 %a, -281479271677953
ret i64 %and
}
; Check the low end of the NIHL range (0xffff0000_ffffffff).
define i64 @f11(i64 %a) {
; CHECK: f11:
; CHECK: nihl %r2, 0
; CHECK: br %r14
%and = and i64 %a, -281470681743361
ret i64 %and
}
; Check the highest useful NIHL value (0xfffffffe_ffffffff).
define i64 @f12(i64 %a) {
; CHECK: f12:
; CHECK: nihl %r2, 65534
; CHECK: br %r14
%and = and i64 %a, -4294967297
ret i64 %and
}
; Check the low end of the NILF range (0xffffffff_00000000).
define i64 @f13(i64 %a) {
; CHECK: f13:
; CHECK: nilf %r2, 0
; CHECK: br %r14
%and = and i64 %a, -4294967296
ret i64 %and
}
; Check the low end of the NILH range (0xffffffff_0000ffff).
define i64 @f14(i64 %a) {
; CHECK: f14:
; CHECK: nilh %r2, 0
; CHECK: br %r14
%and = and i64 %a, -4294901761
ret i64 %and
}
; Check the next value up, which must use NILF.
define i64 @f15(i64 %a) {
; CHECK: f15:
; CHECK: nilf %r2, 65536
; CHECK: br %r14
%and = and i64 %a, -4294901760
ret i64 %and
}
; Check the maximum useful NILF value (0xffffffff_fffefffe).
define i64 @f16(i64 %a) {
; CHECK: f16:
; CHECK: nilf %r2, 4294901758
; CHECK: br %r14
%and = and i64 %a, -65538
ret i64 %and
}
; Check the highest useful NILH value, which is one greater than the above.
define i64 @f17(i64 %a) {
; CHECK: f17:
; CHECK: nilh %r2, 65534
; CHECK: br %r14
%and = and i64 %a, -65537
ret i64 %and
}
; Check the low end of the NILL range, which is one greater again.
define i64 @f18(i64 %a) {
; CHECK: f18:
; CHECK: nill %r2, 0
; CHECK: br %r14
%and = and i64 %a, -65536
ret i64 %and
}
; Check the highest useful NILL value.
define i64 @f19(i64 %a) {
; CHECK: f19:
; CHECK: nill %r2, 65534
; CHECK: br %r14
%and = and i64 %a, -2
ret i64 %and
}

View File

@ -0,0 +1,165 @@
; Test ANDs of a constant into a byte of memory.
;
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s
; Check the lowest useful constant, expressed as a signed integer.
define void @f1(i8 *%ptr) {
; CHECK: f1:
; CHECK: ni 0(%r2), 1
; CHECK: br %r14
%val = load i8 *%ptr
%and = and i8 %val, -255
store i8 %and, i8 *%ptr
ret void
}
; Check the highest useful constant, expressed as a signed integer.
define void @f2(i8 *%ptr) {
; CHECK: f2:
; CHECK: ni 0(%r2), 254
; CHECK: br %r14
%val = load i8 *%ptr
%and = and i8 %val, -2
store i8 %and, i8 *%ptr
ret void
}
; Check the lowest useful constant, expressed as an unsigned integer.
define void @f3(i8 *%ptr) {
; CHECK: f3:
; CHECK: ni 0(%r2), 1
; CHECK: br %r14
%val = load i8 *%ptr
%and = and i8 %val, 1
store i8 %and, i8 *%ptr
ret void
}
; Check the highest useful constant, expressed as a unsigned integer.
define void @f4(i8 *%ptr) {
; CHECK: f4:
; CHECK: ni 0(%r2), 254
; CHECK: br %r14
%val = load i8 *%ptr
%and = and i8 %val, 254
store i8 %and, i8 *%ptr
ret void
}
; Check the high end of the NI range.
define void @f5(i8 *%src) {
; CHECK: f5:
; CHECK: ni 4095(%r2), 127
; CHECK: br %r14
%ptr = getelementptr i8 *%src, i64 4095
%val = load i8 *%ptr
%and = and i8 %val, 127
store i8 %and, i8 *%ptr
ret void
}
; Check the next byte up, which should use NIY instead of NI.
define void @f6(i8 *%src) {
; CHECK: f6:
; CHECK: niy 4096(%r2), 127
; CHECK: br %r14
%ptr = getelementptr i8 *%src, i64 4096
%val = load i8 *%ptr
%and = and i8 %val, 127
store i8 %and, i8 *%ptr
ret void
}
; Check the high end of the NIY range.
define void @f7(i8 *%src) {
; CHECK: f7:
; CHECK: niy 524287(%r2), 127
; CHECK: br %r14
%ptr = getelementptr i8 *%src, i64 524287
%val = load i8 *%ptr
%and = and i8 %val, 127
store i8 %and, i8 *%ptr
ret void
}
; Check the next byte up, which needs separate address logic.
; Other sequences besides this one would be OK.
define void @f8(i8 *%src) {
; CHECK: f8:
; CHECK: agfi %r2, 524288
; CHECK: ni 0(%r2), 127
; CHECK: br %r14
%ptr = getelementptr i8 *%src, i64 524288
%val = load i8 *%ptr
%and = and i8 %val, 127
store i8 %and, i8 *%ptr
ret void
}
; Check the high end of the negative NIY range.
define void @f9(i8 *%src) {
; CHECK: f9:
; CHECK: niy -1(%r2), 127
; CHECK: br %r14
%ptr = getelementptr i8 *%src, i64 -1
%val = load i8 *%ptr
%and = and i8 %val, 127
store i8 %and, i8 *%ptr
ret void
}
; Check the low end of the NIY range.
define void @f10(i8 *%src) {
; CHECK: f10:
; CHECK: niy -524288(%r2), 127
; CHECK: br %r14
%ptr = getelementptr i8 *%src, i64 -524288
%val = load i8 *%ptr
%and = and i8 %val, 127
store i8 %and, i8 *%ptr
ret void
}
; Check the next byte down, which needs separate address logic.
; Other sequences besides this one would be OK.
define void @f11(i8 *%src) {
; CHECK: f11:
; CHECK: agfi %r2, -524289
; CHECK: ni 0(%r2), 127
; CHECK: br %r14
%ptr = getelementptr i8 *%src, i64 -524289
%val = load i8 *%ptr
%and = and i8 %val, 127
store i8 %and, i8 *%ptr
ret void
}
; Check that NI does not allow an index
define void @f12(i64 %src, i64 %index) {
; CHECK: f12:
; CHECK: agr %r2, %r3
; CHECK: ni 4095(%r2), 127
; CHECK: br %r14
%add1 = add i64 %src, %index
%add2 = add i64 %add1, 4095
%ptr = inttoptr i64 %add2 to i8 *
%val = load i8 *%ptr
%and = and i8 %val, 127
store i8 %and, i8 *%ptr
ret void
}
; Check that NIY does not allow an index
define void @f13(i64 %src, i64 %index) {
; CHECK: f13:
; CHECK: agr %r2, %r3
; CHECK: niy 4096(%r2), 127
; CHECK: br %r14
%add1 = add i64 %src, %index
%add2 = add i64 %add1, 4096
%ptr = inttoptr i64 %add2 to i8 *
%val = load i8 *%ptr
%and = and i8 %val, 127
store i8 %and, i8 *%ptr
ret void
}

View File

@ -0,0 +1,108 @@
; Test that we can use NI for byte operations that are expressed as i32
; or i64 operations.
;
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s
; Zero extension to 32 bits, negative constant.
define void @f1(i8 *%ptr) {
; CHECK: f1:
; CHECK: ni 0(%r2), 254
; CHECK: br %r14
%val = load i8 *%ptr
%ext = zext i8 %val to i32
%and = and i32 %ext, -2
%trunc = trunc i32 %and to i8
store i8 %trunc, i8 *%ptr
ret void
}
; Zero extension to 64 bits, negative constant.
define void @f2(i8 *%ptr) {
; CHECK: f2:
; CHECK: ni 0(%r2), 254
; CHECK: br %r14
%val = load i8 *%ptr
%ext = zext i8 %val to i64
%and = and i64 %ext, -2
%trunc = trunc i64 %and to i8
store i8 %trunc, i8 *%ptr
ret void
}
; Zero extension to 32 bits, positive constant.
define void @f3(i8 *%ptr) {
; CHECK: f3:
; CHECK: ni 0(%r2), 254
; CHECK: br %r14
%val = load i8 *%ptr
%ext = zext i8 %val to i32
%and = and i32 %ext, 254
%trunc = trunc i32 %and to i8
store i8 %trunc, i8 *%ptr
ret void
}
; Zero extension to 64 bits, positive constant.
define void @f4(i8 *%ptr) {
; CHECK: f4:
; CHECK: ni 0(%r2), 254
; CHECK: br %r14
%val = load i8 *%ptr
%ext = zext i8 %val to i64
%and = and i64 %ext, 254
%trunc = trunc i64 %and to i8
store i8 %trunc, i8 *%ptr
ret void
}
; Sign extension to 32 bits, negative constant.
define void @f5(i8 *%ptr) {
; CHECK: f5:
; CHECK: ni 0(%r2), 254
; CHECK: br %r14
%val = load i8 *%ptr
%ext = sext i8 %val to i32
%and = and i32 %ext, -2
%trunc = trunc i32 %and to i8
store i8 %trunc, i8 *%ptr
ret void
}
; Sign extension to 64 bits, negative constant.
define void @f6(i8 *%ptr) {
; CHECK: f6:
; CHECK: ni 0(%r2), 254
; CHECK: br %r14
%val = load i8 *%ptr
%ext = sext i8 %val to i64
%and = and i64 %ext, -2
%trunc = trunc i64 %and to i8
store i8 %trunc, i8 *%ptr
ret void
}
; Sign extension to 32 bits, positive constant.
define void @f7(i8 *%ptr) {
; CHECK: f7:
; CHECK: ni 0(%r2), 254
; CHECK: br %r14
%val = load i8 *%ptr
%ext = sext i8 %val to i32
%and = and i32 %ext, 254
%trunc = trunc i32 %and to i8
store i8 %trunc, i8 *%ptr
ret void
}
; Sign extension to 64 bits, positive constant.
define void @f8(i8 *%ptr) {
; CHECK: f8:
; CHECK: ni 0(%r2), 254
; CHECK: br %r14
%val = load i8 *%ptr
%ext = sext i8 %val to i64
%and = and i64 %ext, 254
%trunc = trunc i64 %and to i8
store i8 %trunc, i8 *%ptr
ret void
}

View File

@ -0,0 +1,74 @@
; Test the handling of GPR, FPR and stack arguments when no extension
; type is given. This type of argument is used for passing structures, etc.
;
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s -check-prefix=CHECK-INT
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s -check-prefix=CHECK-FLOAT
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s -check-prefix=CHECK-DOUBLE
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s -check-prefix=CHECK-FP128-1
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s -check-prefix=CHECK-FP128-2
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s -check-prefix=CHECK-STACK
declare void @bar(i8, i16, i32, i64, float, double, fp128, i64,
float, double, i8, i16, i32, i64, float, double, fp128)
; There are two indirect fp128 slots, one at offset 224 (the first available
; byte after the outgoing arguments) and one immediately after it at 240.
; These slots should be set up outside the glued call sequence, so would
; normally use %f0/%f2 as the first available 128-bit pair. This choice
; is hard-coded in the FP128 tests.
;
; The order of the CHECK-INT loads doesn't matter. The same goes for the
; CHECK_FP128-* stores and the CHECK-STACK stores. It would be OK to reorder
; them in response to future code changes.
define void @foo() {
; CHECK-INT: foo:
; CHECK-INT: lhi %r2, 1
; CHECK-INT: lhi %r3, 2
; CHECK-INT: lhi %r4, 3
; CHECK-INT: lghi %r5, 4
; CHECK-INT: la %r6, {{224|240}}(%r15)
; CHECK-INT: brasl %r14, bar@PLT
;
; CHECK-FLOAT: foo:
; CHECK-FLOAT: lzer %f0
; CHECK-FLOAT: lcebr %f4, %f0
; CHECK-FLOAT: brasl %r14, bar@PLT
;
; CHECK-DOUBLE: foo:
; CHECK-DOUBLE: lzdr %f2
; CHECK-DOUBLE: lcdbr %f6, %f2
; CHECK-DOUBLE: brasl %r14, bar@PLT
;
; CHECK-FP128-1: foo:
; CHECK-FP128-1: aghi %r15, -256
; CHECK-FP128-1: lzxr %f0
; CHECK-FP128-1: std %f0, 224(%r15)
; CHECK-FP128-1: std %f2, 232(%r15)
; CHECK-FP128-1: brasl %r14, bar@PLT
;
; CHECK-FP128-2: foo:
; CHECK-FP128-2: aghi %r15, -256
; CHECK-FP128-2: lzxr %f0
; CHECK-FP128-2: std %f0, 240(%r15)
; CHECK-FP128-2: std %f2, 248(%r15)
; CHECK-FP128-2: brasl %r14, bar@PLT
;
; CHECK-STACK: foo:
; CHECK-STACK: aghi %r15, -256
; CHECK-STACK: la [[REGISTER:%r[0-5]+]], {{224|240}}(%r15)
; CHECK-STACK: stg [[REGISTER]], 216(%r15)
; CHECK-STACK: mvghi 208(%r15), 0
; CHECK-STACK: mvhi 204(%r15), 0
; CHECK-STACK: mvghi 192(%r15), 9
; CHECK-STACK: mvhi 188(%r15), 8
; CHECK-STACK: mvhi 180(%r15), 7
; CHECK-STACK: mvhi 172(%r15), 6
; CHECK-STACK: mvghi 160(%r15), 5
; CHECK-STACK: brasl %r14, bar@PLT
call void @bar (i8 1, i16 2, i32 3, i64 4, float 0.0, double 0.0,
fp128 0xL00000000000000000000000000000000, i64 5,
float -0.0, double -0.0, i8 6, i16 7, i32 8, i64 9, float 0.0,
double 0.0, fp128 0xL00000000000000000000000000000000)
ret void
}

View File

@ -0,0 +1,76 @@
; Test the handling of GPR, FPR and stack arguments when integers are
; sign-extended.
;
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s -check-prefix=CHECK-INT
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s -check-prefix=CHECK-FLOAT
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s -check-prefix=CHECK-DOUBLE
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s -check-prefix=CHECK-FP128-1
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s -check-prefix=CHECK-FP128-2
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s -check-prefix=CHECK-STACK
declare void @bar(i8 signext, i16 signext, i32 signext, i64, float, double,
fp128, i64, float, double, i8 signext, i16 signext,
i32 signext, i64, float, double, fp128)
; There are two indirect fp128 slots, one at offset 224 (the first available
; byte after the outgoing arguments) and one immediately after it at 240.
; These slots should be set up outside the glued call sequence, so would
; normally use %f0/%f2 as the first available 128-bit pair. This choice
; is hard-coded in the FP128 tests.
;
; The order of the CHECK-INT loads doesn't matter. The same goes for the
; CHECK_FP128-* stores and the CHECK-STACK stores. It would be OK to reorder
; them in response to future code changes.
define void @foo() {
; CHECK-INT: foo:
; CHECK-INT: lghi %r2, -1
; CHECK-INT: lghi %r3, -2
; CHECK-INT: lghi %r4, -3
; CHECK-INT: lghi %r5, -4
; CHECK-INT: la %r6, {{224|240}}(%r15)
; CHECK-INT: brasl %r14, bar@PLT
;
; CHECK-FLOAT: foo:
; CHECK-FLOAT: lzer %f0
; CHECK-FLOAT: lcebr %f4, %f0
; CHECK-FLOAT: brasl %r14, bar@PLT
;
; CHECK-DOUBLE: foo:
; CHECK-DOUBLE: lzdr %f2
; CHECK-DOUBLE: lcdbr %f6, %f2
; CHECK-DOUBLE: brasl %r14, bar@PLT
;
; CHECK-FP128-1: foo:
; CHECK-FP128-1: aghi %r15, -256
; CHECK-FP128-1: lzxr %f0
; CHECK-FP128-1: std %f0, 224(%r15)
; CHECK-FP128-1: std %f2, 232(%r15)
; CHECK-FP128-1: brasl %r14, bar@PLT
;
; CHECK-FP128-2: foo:
; CHECK-FP128-2: aghi %r15, -256
; CHECK-FP128-2: lzxr %f0
; CHECK-FP128-2: std %f0, 240(%r15)
; CHECK-FP128-2: std %f2, 248(%r15)
; CHECK-FP128-2: brasl %r14, bar@PLT
;
; CHECK-STACK: foo:
; CHECK-STACK: aghi %r15, -256
; CHECK-STACK: la [[REGISTER:%r[0-5]+]], {{224|240}}(%r15)
; CHECK-STACK: stg [[REGISTER]], 216(%r15)
; CHECK-STACK: mvghi 208(%r15), 0
; CHECK-STACK: mvhi 204(%r15), 0
; CHECK-STACK: mvghi 192(%r15), -9
; CHECK-STACK: mvghi 184(%r15), -8
; CHECK-STACK: mvghi 176(%r15), -7
; CHECK-STACK: mvghi 168(%r15), -6
; CHECK-STACK: mvghi 160(%r15), -5
; CHECK-STACK: brasl %r14, bar@PLT
call void @bar (i8 -1, i16 -2, i32 -3, i64 -4, float 0.0, double 0.0,
fp128 0xL00000000000000000000000000000000, i64 -5,
float -0.0, double -0.0, i8 -6, i16 -7, i32 -8, i64 -9,
float 0.0, double 0.0,
fp128 0xL00000000000000000000000000000000)
ret void
}

View File

@ -0,0 +1,78 @@
; Test the handling of GPR, FPR and stack arguments when integers are
; zero-extended.
;
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s -check-prefix=CHECK-INT
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s -check-prefix=CHECK-FLOAT
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s -check-prefix=CHECK-DOUBLE
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s -check-prefix=CHECK-FP128-1
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s -check-prefix=CHECK-FP128-2
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s -check-prefix=CHECK-STACK
declare void @bar(i8 zeroext, i16 zeroext, i32 zeroext, i64, float, double,
fp128, i64, float, double, i8 zeroext, i16 zeroext,
i32 zeroext, i64, float, double, fp128)
; There are two indirect fp128 slots, one at offset 224 (the first available
; byte after the outgoing arguments) and one immediately after it at 240.
; These slots should be set up outside the glued call sequence, so would
; normally use %f0/%f2 as the first available 128-bit pair. This choice
; is hard-coded in the FP128 tests.
;
; The order of the CHECK-INT loads doesn't matter. The same goes for the
; CHECK_FP128-* stores and the CHECK-STACK stores. It would be OK to reorder
; them in response to future code changes.
define void @foo() {
; CHECK-INT: foo:
; CHECK-INT: lghi %r2, 255
; CHECK-INT: llill %r3, 65534
; CHECK-INT: llilf %r4, 4294967293
; CHECK-INT: lghi %r5, -4
; CHECK-INT: la %r6, {{224|240}}(%r15)
; CHECK-INT: brasl %r14, bar@PLT
;
; CHECK-FLOAT: foo:
; CHECK-FLOAT: lzer %f0
; CHECK-FLOAT: lcebr %f4, %f0
; CHECK-FLOAT: brasl %r14, bar@PLT
;
; CHECK-DOUBLE: foo:
; CHECK-DOUBLE: lzdr %f2
; CHECK-DOUBLE: lcdbr %f6, %f2
; CHECK-DOUBLE: brasl %r14, bar@PLT
;
; CHECK-FP128-1: foo:
; CHECK-FP128-1: aghi %r15, -256
; CHECK-FP128-1: lzxr %f0
; CHECK-FP128-1: std %f0, 224(%r15)
; CHECK-FP128-1: std %f2, 232(%r15)
; CHECK-FP128-1: brasl %r14, bar@PLT
;
; CHECK-FP128-2: foo:
; CHECK-FP128-2: aghi %r15, -256
; CHECK-FP128-2: lzxr %f0
; CHECK-FP128-2: std %f0, 240(%r15)
; CHECK-FP128-2: std %f2, 248(%r15)
; CHECK-FP128-2: brasl %r14, bar@PLT
;
; CHECK-STACK: foo:
; CHECK-STACK: aghi %r15, -256
; CHECK-STACK: la [[REGISTER:%r[0-5]+]], {{224|240}}(%r15)
; CHECK-STACK: stg [[REGISTER]], 216(%r15)
; CHECK-STACK: llilf [[AT184:%r[0-5]+]], 4294967288
; CHECK-STACK: stg [[AT184]], 184(%r15)
; CHECK-STACK: llill [[AT176:%r[0-5]+]], 65529
; CHECK-STACK: stg [[AT176]], 176(%r15)
; CHECK-STACK: mvghi 208(%r15), 0
; CHECK-STACK: mvhi 204(%r15), 0
; CHECK-STACK: mvghi 192(%r15), -9
; CHECK-STACK: mvghi 168(%r15), 250
; CHECK-STACK: mvghi 160(%r15), -5
; CHECK-STACK: brasl %r14, bar@PLT
call void @bar (i8 -1, i16 -2, i32 -3, i64 -4, float 0.0, double 0.0,
fp128 0xL00000000000000000000000000000000, i64 -5,
float -0.0, double -0.0, i8 -6, i16 -7, i32 -8, i64 -9,
float 0.0, double 0.0,
fp128 0xL00000000000000000000000000000000)
ret void
}

View File

@ -0,0 +1,126 @@
; Test incoming GPR, FPR and stack arguments when no extension type is given.
; This type of argument is used for passing structures, etc.
;
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s
; Do some arithmetic so that we can see the register being used.
define i8 @f1(i8 %r2) {
; CHECK: f1:
; CHECK: ahi %r2, 1
; CHECK: br %r14
%y = add i8 %r2, 1
ret i8 %y
}
define i16 @f2(i8 %r2, i16 %r3) {
; CHECK: f2:
; CHECK: {{lr|lgr}} %r2, %r3
; CHECK: br %r14
ret i16 %r3
}
define i32 @f3(i8 %r2, i16 %r3, i32 %r4) {
; CHECK: f3:
; CHECK: {{lr|lgr}} %r2, %r4
; CHECK: br %r14
ret i32 %r4
}
define i64 @f4(i8 %r2, i16 %r3, i32 %r4, i64 %r5) {
; CHECK: f4:
; CHECK: {{lr|lgr}} %r2, %r5
; CHECK: br %r14
ret i64 %r5
}
; Do some arithmetic so that we can see the register being used.
define float @f5(i8 %r2, i16 %r3, i32 %r4, i64 %r5, float %f0) {
; CHECK: f5:
; CHECK: aebr %f0, %f0
; CHECK: br %r14
%y = fadd float %f0, %f0
ret float %y
}
define double @f6(i8 %r2, i16 %r3, i32 %r4, i64 %r5, float %f0, double %f2) {
; CHECK: f6:
; CHECK: ldr %f0, %f2
; CHECK: br %r14
ret double %f2
}
; fp128s are passed indirectly. Do some arithmetic so that the value
; must be interpreted as a float, rather than as a block of memory to
; be copied.
define void @f7(fp128 *%r2, i16 %r3, i32 %r4, i64 %r5, float %f0, double %f2,
fp128 %r6) {
; CHECK: f7:
; CHECK: ld %f0, 0(%r6)
; CHECK: ld %f2, 8(%r6)
; CHECK: axbr %f0, %f0
; CHECK: std %f0, 0(%r2)
; CHECK: std %f2, 8(%r2)
; CHECK: br %r14
%y = fadd fp128 %r6, %r6
store fp128 %y, fp128 *%r2
ret void
}
define i64 @f8(i8 %r2, i16 %r3, i32 %r4, i64 %r5, float %f0, double %f2,
fp128 %r6, i64 %s1) {
; CHECK: f8:
; CHECK: lg %r2, 160(%r15)
; CHECK: br %r14
ret i64 %s1
}
define float @f9(i8 %r2, i16 %r3, i32 %r4, i64 %r5, float %f0, double %f2,
fp128 %r6, i64 %s1, float %f4) {
; CHECK: f9:
; CHECK: ler %f0, %f4
; CHECK: br %r14
ret float %f4
}
define double @f10(i8 %r2, i16 %r3, i32 %r4, i64 %r5, float %f0, double %f2,
fp128 %r6, i64 %s1, float %f4, double %f6) {
; CHECK: f10:
; CHECK: ldr %f0, %f6
; CHECK: br %r14
ret double %f6
}
define i64 @f11(i8 %r2, i16 %r3, i32 %r4, i64 %r5, float %f0, double %f2,
fp128 %r6, i64 %s1, float %f4, double %f6, i64 %s2) {
; CHECK: f11:
; CHECK: lg %r2, 168(%r15)
; CHECK: br %r14
ret i64 %s2
}
; Floats are passed right-justified.
define float @f12(i8 %r2, i16 %r3, i32 %r4, i64 %r5, float %f0, double %f2,
fp128 %r6, i64 %s1, float %f4, double %f6, i64 %s2,
float %s3) {
; CHECK: f12:
; CHECK: le %f0, 180(%r15)
; CHECK: br %r14
ret float %s3
}
; Test a case where the fp128 address is passed on the stack.
define void @f13(fp128 *%r2, i16 %r3, i32 %r4, i64 %r5, float %f0, double %f2,
fp128 %r6, i64 %s1, float %f4, double %f6, i64 %s2,
float %s3, fp128 %s4) {
; CHECK: f13:
; CHECK: lg [[REGISTER:%r[1-5]+]], 184(%r15)
; CHECK: ld %f0, 0([[REGISTER]])
; CHECK: ld %f2, 8([[REGISTER]])
; CHECK: axbr %f0, %f0
; CHECK: std %f0, 0(%r2)
; CHECK: std %f2, 8(%r2)
; CHECK: br %r14
%y = fadd fp128 %s4, %s4
store fp128 %y, fp128 *%r2
ret void
}

View File

@ -0,0 +1,47 @@
; Test that we take advantage of signext and zeroext annotations.
;
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s
; Zero extension of something that is already zero-extended.
define void @f1(i32 zeroext %r2, i64 *%r3) {
; CHECK: f1:
; CHECK-NOT: %r2
; CHECK: stg %r2, 0(%r3)
; CHECK: br %r14
%conv = zext i32 %r2 to i64
store i64 %conv, i64* %r3
ret void
}
; Sign extension of something that is already sign-extended.
define void @f2(i32 signext %r2, i64 *%r3) {
; CHECK: f2:
; CHECK-NOT: %r2
; CHECK: stg %r2, 0(%r3)
; CHECK: br %r14
%conv = sext i32 %r2 to i64
store i64 %conv, i64* %r3
ret void
}
; Sign extension of something that is already zero-extended.
define void @f3(i32 zeroext %r2, i64 *%r3) {
; CHECK: f3:
; CHECK: lgfr [[REGISTER:%r[0-5]+]], %r2
; CHECK: stg [[REGISTER]], 0(%r3)
; CHECK: br %r14
%conv = sext i32 %r2 to i64
store i64 %conv, i64* %r3
ret void
}
; Zero extension of something that is already sign-extended.
define void @f4(i32 signext %r2, i64 *%r3) {
; CHECK: f4:
; CHECK: llgfr [[REGISTER:%r[0-5]+]], %r2
; CHECK: stg [[REGISTER]], 0(%r3)
; CHECK: br %r14
%conv = zext i32 %r2 to i64
store i64 %conv, i64* %r3
ret void
}

View File

@ -0,0 +1,76 @@
; Test the padding of unextended integer stack parameters. These are used
; to pass structures.
;
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s
define i8 @f1(i8 %a, i8 %b, i8 %c, i8 %d, i8 %e, i8 %f, i8 %g) {
; CHECK: f1:
; CHECK: ar %r2, %r3
; CHECK: ar %r2, %r4
; CHECK: ar %r2, %r5
; CHECK: ar %r2, %r6
; CHECK: lb {{%r[0-5]}}, 167(%r15)
; CHECK: lb {{%r[0-5]}}, 175(%r15)
; CHECK: br %r14
%addb = add i8 %a, %b
%addc = add i8 %addb, %c
%addd = add i8 %addc, %d
%adde = add i8 %addd, %e
%addf = add i8 %adde, %f
%addg = add i8 %addf, %g
ret i8 %addg
}
define i16 @f2(i16 %a, i16 %b, i16 %c, i16 %d, i16 %e, i16 %f, i16 %g) {
; CHECK: f2:
; CHECK: ar %r2, %r3
; CHECK: ar %r2, %r4
; CHECK: ar %r2, %r5
; CHECK: ar %r2, %r6
; CHECK: lh {{%r[0-5]}}, 166(%r15)
; CHECK: lh {{%r[0-5]}}, 174(%r15)
; CHECK: br %r14
%addb = add i16 %a, %b
%addc = add i16 %addb, %c
%addd = add i16 %addc, %d
%adde = add i16 %addd, %e
%addf = add i16 %adde, %f
%addg = add i16 %addf, %g
ret i16 %addg
}
define i32 @f3(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e, i32 %f, i32 %g) {
; CHECK: f3:
; CHECK: ar %r2, %r3
; CHECK: ar %r2, %r4
; CHECK: ar %r2, %r5
; CHECK: ar %r2, %r6
; CHECK: a %r2, 164(%r15)
; CHECK: a %r2, 172(%r15)
; CHECK: br %r14
%addb = add i32 %a, %b
%addc = add i32 %addb, %c
%addd = add i32 %addc, %d
%adde = add i32 %addd, %e
%addf = add i32 %adde, %f
%addg = add i32 %addf, %g
ret i32 %addg
}
define i64 @f4(i64 %a, i64 %b, i64 %c, i64 %d, i64 %e, i64 %f, i64 %g) {
; CHECK: f4:
; CHECK: agr %r2, %r3
; CHECK: agr %r2, %r4
; CHECK: agr %r2, %r5
; CHECK: agr %r2, %r6
; CHECK: ag %r2, 160(%r15)
; CHECK: ag %r2, 168(%r15)
; CHECK: br %r14
%addb = add i64 %a, %b
%addc = add i64 %addb, %c
%addd = add i64 %addc, %d
%adde = add i64 %addd, %e
%addf = add i64 %adde, %f
%addg = add i64 %addf, %g
ret i64 %addg
}

View File

@ -0,0 +1,61 @@
; Test the "Q" asm constraint, which accepts addresses that have a base
; and a 12-bit displacement.
;
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s
; Check the lowest range.
define void @f1(i64 %base) {
; CHECK: f1:
; CHECK: blah 0(%r2)
; CHECK: br %r14
%addr = inttoptr i64 %base to i64 *
call void asm "blah $0", "=*Q" (i64 *%addr)
ret void
}
; Check the next lowest byte.
define void @f2(i64 %base) {
; CHECK: f2:
; CHECK: aghi %r2, -1
; CHECK: blah 0(%r2)
; CHECK: br %r14
%add = add i64 %base, -1
%addr = inttoptr i64 %add to i64 *
call void asm "blah $0", "=*Q" (i64 *%addr)
ret void
}
; Check the highest range.
define void @f3(i64 %base) {
; CHECK: f3:
; CHECK: blah 4095(%r2)
; CHECK: br %r14
%add = add i64 %base, 4095
%addr = inttoptr i64 %add to i64 *
call void asm "blah $0", "=*Q" (i64 *%addr)
ret void
}
; Check the next highest byte.
define void @f4(i64 %base) {
; CHECK: f4:
; CHECK: aghi %r2, 4096
; CHECK: blah 0(%r2)
; CHECK: br %r14
%add = add i64 %base, 4096
%addr = inttoptr i64 %add to i64 *
call void asm "blah $0", "=*Q" (i64 *%addr)
ret void
}
; Check that indices aren't allowed
define void @f5(i64 %base, i64 %index) {
; CHECK: f5:
; CHECK: agr %r2, %r3
; CHECK: blah 0(%r2)
; CHECK: br %r14
%add = add i64 %base, %index
%addr = inttoptr i64 %add to i64 *
call void asm "blah $0", "=*Q" (i64 *%addr)
ret void
}

View File

@ -0,0 +1,52 @@
; Test the "R" asm constraint, which accepts addresses that have a base,
; an index and a 12-bit displacement.
;
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s
; Check the lowest range.
define void @f1(i64 %base) {
; CHECK: f1:
; CHECK: blah 0(%r2)
; CHECK: br %r14
%addr = inttoptr i64 %base to i64 *
call void asm "blah $0", "=*R" (i64 *%addr)
ret void
}
; Check the next lowest byte.
define void @f2(i64 %base) {
; CHECK: f2:
; CHECK: aghi %r2, -1
; CHECK: blah 0(%r2)
; CHECK: br %r14
%add = add i64 %base, -1
%addr = inttoptr i64 %add to i64 *
call void asm "blah $0", "=*R" (i64 *%addr)
ret void
}
; Check the highest range.
define void @f3(i64 %base) {
; CHECK: f3:
; CHECK: blah 4095(%r2)
; CHECK: br %r14
%add = add i64 %base, 4095
%addr = inttoptr i64 %add to i64 *
call void asm "blah $0", "=*R" (i64 *%addr)
ret void
}
; Check the next highest byte.
define void @f4(i64 %base) {
; CHECK: f4:
; CHECK: aghi %r2, 4096
; CHECK: blah 0(%r2)
; CHECK: br %r14
%add = add i64 %base, 4096
%addr = inttoptr i64 %add to i64 *
call void asm "blah $0", "=*R" (i64 *%addr)
ret void
}
; FIXME: at the moment the precise constraint is not passed down to
; target code, so we must conservatively treat "R" as "Q".

View File

@ -0,0 +1,16 @@
; Test the "S" asm constraint, which accepts addresses that have a base
; and a 20-bit displacement.
;
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s
define void @f1(i64 %base) {
; CHECK: f1:
; CHECK: blah 0(%r2)
; CHECK: br %r14
%addr = inttoptr i64 %base to i64 *
call void asm "blah $0", "=*S" (i64 *%addr)
ret void
}
; FIXME: at the moment the precise constraint is not passed down to
; target code, so we must conservatively treat "S" as "Q".

View File

@ -0,0 +1,16 @@
; Test the "T" asm constraint, which accepts addresses that have a base,
; an index and a 20-bit displacement.
;
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s
define void @f1(i64 %base) {
; CHECK: f1:
; CHECK: blah 0(%r2)
; CHECK: br %r14
%addr = inttoptr i64 %base to i64 *
call void asm "blah $0", "=*T" (i64 *%addr)
ret void
}
; FIXME: at the moment the precise constraint is not passed down to
; target code, so we must conservatively treat "T" as "Q".

View File

@ -0,0 +1,15 @@
; Test the "m" asm constraint, which is equivalent to "T".
;
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s
define void @f1(i64 %base) {
; CHECK: f1:
; CHECK: blah 0(%r2)
; CHECK: br %r14
%addr = inttoptr i64 %base to i64 *
call void asm "blah $0", "=*m" (i64 *%addr)
ret void
}
; FIXME: at the moment the precise constraint is not passed down to
; target code, so we must conservatively treat "m" as "Q".

View File

@ -0,0 +1,39 @@
; Test the GPR constraint "a", which forbids %r0.
;
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s
define i64 @f1() {
; CHECK: f1:
; CHECK: lhi %r1, 1
; CHECK: blah %r2 %r1
; CHECK: br %r14
%val = call i64 asm "blah $0 $1", "=r,a" (i8 1)
ret i64 %val
}
define i64 @f2() {
; CHECK: f2:
; CHECK: lhi %r1, 2
; CHECK: blah %r2 %r1
; CHECK: br %r14
%val = call i64 asm "blah $0 $1", "=r,a" (i16 2)
ret i64 %val
}
define i64 @f3() {
; CHECK: f3:
; CHECK: lhi %r1, 3
; CHECK: blah %r2 %r1
; CHECK: br %r14
%val = call i64 asm "blah $0 $1", "=r,a" (i32 3)
ret i64 %val
}
define i64 @f4() {
; CHECK: f4:
; CHECK: lghi %r1, 4
; CHECK: blah %r2 %r1
; CHECK: br %r14
%val = call i64 asm "blah $0 $1", "=r,a" (i64 4)
ret i64 %val
}

View File

@ -0,0 +1,39 @@
; Test the GPR constraint "r".
;
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s
define i64 @f1() {
; CHECK: f1:
; CHECK: lhi %r0, 1
; CHECK: blah %r2 %r0
; CHECK: br %r14
%val = call i64 asm "blah $0 $1", "=r,r" (i8 1)
ret i64 %val
}
define i64 @f2() {
; CHECK: f2:
; CHECK: lhi %r0, 2
; CHECK: blah %r2 %r0
; CHECK: br %r14
%val = call i64 asm "blah $0 $1", "=r,r" (i16 2)
ret i64 %val
}
define i64 @f3() {
; CHECK: f3:
; CHECK: lhi %r0, 3
; CHECK: blah %r2 %r0
; CHECK: br %r14
%val = call i64 asm "blah $0 $1", "=r,r" (i32 3)
ret i64 %val
}
define i64 @f4() {
; CHECK: f4:
; CHECK: lghi %r0, 4
; CHECK: blah %r2 %r0
; CHECK: br %r14
%val = call i64 asm "blah $0 $1", "=r,r" (i64 4)
ret i64 %val
}

View File

@ -0,0 +1,39 @@
; Test the GPR constraint "d", which is equivalent to "r".
;
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s
define i64 @f1() {
; CHECK: f1:
; CHECK: lhi %r0, 1
; CHECK: blah %r2 %r0
; CHECK: br %r14
%val = call i64 asm "blah $0 $1", "=d,d" (i8 1)
ret i64 %val
}
define i64 @f2() {
; CHECK: f2:
; CHECK: lhi %r0, 2
; CHECK: blah %r2 %r0
; CHECK: br %r14
%val = call i64 asm "blah $0 $1", "=d,d" (i16 2)
ret i64 %val
}
define i64 @f3() {
; CHECK: f3:
; CHECK: lhi %r0, 3
; CHECK: blah %r2 %r0
; CHECK: br %r14
%val = call i64 asm "blah $0 $1", "=d,d" (i32 3)
ret i64 %val
}
define i64 @f4() {
; CHECK: f4:
; CHECK: lghi %r0, 4
; CHECK: blah %r2 %r0
; CHECK: br %r14
%val = call i64 asm "blah $0 $1", "=d,d" (i64 4)
ret i64 %val
}

View File

@ -0,0 +1,83 @@
; Test matching operands with the GPR constraint "r".
;
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s
define void @f1(i32 *%dst) {
; CHECK: f1:
; CHECK: lhi %r0, 100
; CHECK: blah %r0
; CHECK: st %r0, 0(%r2)
; CHECK: br %r14
%val = call i32 asm "blah $0", "=r,0" (i8 100)
store i32 %val, i32 *%dst
ret void
}
define void @f2(i32 *%dst) {
; CHECK: f2:
; CHECK: lhi %r0, 101
; CHECK: blah %r0
; CHECK: st %r0, 0(%r2)
; CHECK: br %r14
%val = call i32 asm "blah $0", "=r,0" (i16 101)
store i32 %val, i32 *%dst
ret void
}
define void @f3(i32 *%dst) {
; CHECK: f3:
; CHECK: lhi %r0, 102
; CHECK: blah %r0
; CHECK: st %r0, 0(%r2)
; CHECK: br %r14
%val = call i32 asm "blah $0", "=r,0" (i32 102)
store i32 %val, i32 *%dst
ret void
}
; FIXME: this uses "lhi %r0, 103", but should use "lghi %r0, 103".
define void @f4(i32 *%dst) {
; CHECK: f4:
; CHECK: blah %r0
; CHECK: st %r0, 0(%r2)
; CHECK: br %r14
%val = call i32 asm "blah $0", "=r,0" (i64 103)
store i32 %val, i32 *%dst
ret void
}
define i64 @f5() {
; CHECK: f5:
; CHECK: lghi %r2, 104
; CHECK: blah %r2
; CHECK: br %r14
%val = call i64 asm "blah $0", "=r,0" (i8 104)
ret i64 %val
}
define i64 @f6() {
; CHECK: f6:
; CHECK: lghi %r2, 105
; CHECK: blah %r2
; CHECK: br %r14
%val = call i64 asm "blah $0", "=r,0" (i16 105)
ret i64 %val
}
define i64 @f7() {
; CHECK: f7:
; CHECK: lghi %r2, 106
; CHECK: blah %r2
; CHECK: br %r14
%val = call i64 asm "blah $0", "=r,0" (i32 106)
ret i64 %val
}
define i64 @f8() {
; CHECK: f8:
; CHECK: lghi %r2, 107
; CHECK: blah %r2
; CHECK: br %r14
%val = call i64 asm "blah $0", "=r,0" (i64 107)
ret i64 %val
}

View File

@ -0,0 +1,30 @@
; Test the FPR constraint "f".
;
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s
define float @f1() {
; CHECK: f1:
; CHECK: lzer %f1
; CHECK: blah %f0 %f1
; CHECK: br %r14
%val = call float asm "blah $0 $1", "=&f,f" (float 0.0)
ret float %val
}
define double @f2() {
; CHECK: f2:
; CHECK: lzdr %f1
; CHECK: blah %f0 %f1
; CHECK: br %r14
%val = call double asm "blah $0 $1", "=&f,f" (double 0.0)
ret double %val
}
define double @f3() {
; CHECK: f3:
; CHECK: lzxr %f1
; CHECK: blah %f0 %f1
; CHECK: br %r14
%val = call double asm "blah $0 $1", "=&f,f" (fp128 0xL00000000000000000000000000000000)
ret double %val
}

View File

@ -0,0 +1,41 @@
; Test the "I" constraint (8-bit unsigned constants).
;
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s
; Test 1 below the first valid value.
define i32 @f1() {
; CHECK: f1:
; CHECK: lhi [[REG:%r[0-5]]], -1
; CHECK: blah %r2 [[REG]]
; CHECK: br %r14
%val = call i32 asm "blah $0 $1", "=&r,rI" (i32 -1)
ret i32 %val
}
; Test the first valid value.
define i32 @f2() {
; CHECK: f2:
; CHECK: blah %r2 0
; CHECK: br %r14
%val = call i32 asm "blah $0 $1", "=&r,rI" (i32 0)
ret i32 %val
}
; Test the last valid value.
define i32 @f3() {
; CHECK: f3:
; CHECK: blah %r2 255
; CHECK: br %r14
%val = call i32 asm "blah $0 $1", "=&r,rI" (i32 255)
ret i32 %val
}
; Test 1 above the last valid value.
define i32 @f4() {
; CHECK: f4:
; CHECK: lhi [[REG:%r[0-5]]], 256
; CHECK: blah %r2 [[REG]]
; CHECK: br %r14
%val = call i32 asm "blah $0 $1", "=&r,rI" (i32 256)
ret i32 %val
}

View File

@ -0,0 +1,41 @@
; Test the "J" constraint (12-bit unsigned constants).
;
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s
; Test 1 below the first valid value.
define i32 @f1() {
; CHECK: f1:
; CHECK: lhi [[REG:%r[0-5]]], -1
; CHECK: blah %r2 [[REG]]
; CHECK: br %r14
%val = call i32 asm "blah $0 $1", "=&r,rJ" (i32 -1)
ret i32 %val
}
; Test the first valid value.
define i32 @f2() {
; CHECK: f2:
; CHECK: blah %r2 0
; CHECK: br %r14
%val = call i32 asm "blah $0 $1", "=&r,rJ" (i32 0)
ret i32 %val
}
; Test the last valid value.
define i32 @f3() {
; CHECK: f3:
; CHECK: blah %r2 4095
; CHECK: br %r14
%val = call i32 asm "blah $0 $1", "=&r,rJ" (i32 4095)
ret i32 %val
}
; Test 1 above the last valid value.
define i32 @f4() {
; CHECK: f4:
; CHECK: lhi [[REG:%r[0-5]]], 4096
; CHECK: blah %r2 [[REG]]
; CHECK: br %r14
%val = call i32 asm "blah $0 $1", "=&r,rJ" (i32 4096)
ret i32 %val
}

View File

@ -0,0 +1,41 @@
; Test the "K" constraint (16-bit signed constants).
;
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s
; Test 1 below the first valid value.
define i32 @f1() {
; CHECK: f1:
; CHECK: iilf [[REG:%r[0-5]]], 4294934527
; CHECK: blah %r2 [[REG]]
; CHECK: br %r14
%val = call i32 asm "blah $0 $1", "=&r,rK" (i32 -32769)
ret i32 %val
}
; Test the first valid value.
define i32 @f2() {
; CHECK: f2:
; CHECK: blah %r2 -32768
; CHECK: br %r14
%val = call i32 asm "blah $0 $1", "=&r,rK" (i32 -32768)
ret i32 %val
}
; Test the last valid value.
define i32 @f3() {
; CHECK: f3:
; CHECK: blah %r2 32767
; CHECK: br %r14
%val = call i32 asm "blah $0 $1", "=&r,rK" (i32 32767)
ret i32 %val
}
; Test 1 above the last valid value.
define i32 @f4() {
; CHECK: f4:
; CHECK: llill [[REG:%r[0-5]]], 32768
; CHECK: blah %r2 [[REG]]
; CHECK: br %r14
%val = call i32 asm "blah $0 $1", "=&r,rK" (i32 32768)
ret i32 %val
}

View File

@ -0,0 +1,41 @@
; Test the "L" constraint (20-bit signed constants).
;
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s
; Test 1 below the first valid value.
define i32 @f1() {
; CHECK: f1:
; CHECK: iilf [[REG:%r[0-5]]], 4294443007
; CHECK: blah %r2 [[REG]]
; CHECK: br %r14
%val = call i32 asm "blah $0 $1", "=&r,rL" (i32 -524289)
ret i32 %val
}
; Test the first valid value.
define i32 @f2() {
; CHECK: f2:
; CHECK: blah %r2 -524288
; CHECK: br %r14
%val = call i32 asm "blah $0 $1", "=&r,rL" (i32 -524288)
ret i32 %val
}
; Test the last valid value.
define i32 @f3() {
; CHECK: f3:
; CHECK: blah %r2 524287
; CHECK: br %r14
%val = call i32 asm "blah $0 $1", "=&r,rL" (i32 524287)
ret i32 %val
}
; Test 1 above the last valid value.
define i32 @f4() {
; CHECK: f4:
; CHECK: llilh [[REG:%r[0-5]]], 8
; CHECK: blah %r2 [[REG]]
; CHECK: br %r14
%val = call i32 asm "blah $0 $1", "=&r,rL" (i32 524288)
ret i32 %val
}

View File

@ -0,0 +1,32 @@
; Test the "M" constraint (0x7fffffff)
;
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s
; Test 1 below the valid value.
define i32 @f1() {
; CHECK: f1:
; CHECK: iilf [[REG:%r[0-5]]], 2147483646
; CHECK: blah %r2 [[REG]]
; CHECK: br %r14
%val = call i32 asm "blah $0 $1", "=&r,rM" (i32 2147483646)
ret i32 %val
}
; Test the first valid value.
define i32 @f2() {
; CHECK: f2:
; CHECK: blah %r2 2147483647
; CHECK: br %r14
%val = call i32 asm "blah $0 $1", "=&r,rM" (i32 2147483647)
ret i32 %val
}
; Test 1 above the valid value.
define i32 @f3() {
; CHECK: f3:
; CHECK: llilh [[REG:%r[0-5]]], 32768
; CHECK: blah %r2 [[REG]]
; CHECK: br %r14
%val = call i32 asm "blah $0 $1", "=&r,rM" (i32 2147483648)
ret i32 %val
}

View File

@ -0,0 +1,32 @@
; Test the "M" constraint (0x7fffffff)
;
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s
; Test 1 below the valid value.
define i32 @f1() {
; CHECK: f1:
; CHECK: iilf [[REG:%r[0-5]]], 2147483646
; CHECK: blah %r2 [[REG]]
; CHECK: br %r14
%val = call i32 asm "blah $0 $1", "=&r,rM" (i32 2147483646)
ret i32 %val
}
; Test the first valid value.
define i32 @f2() {
; CHECK: f2:
; CHECK: blah %r2 2147483647
; CHECK: br %r14
%val = call i32 asm "blah $0 $1", "=&r,rM" (i32 2147483647)
ret i32 %val
}
; Test 1 above the valid value.
define i32 @f3() {
; CHECK: f3:
; CHECK: llilh [[REG:%r[0-5]]], 32768
; CHECK: blah %r2 [[REG]]
; CHECK: br %r14
%val = call i32 asm "blah $0 $1", "=&r,rM" (i32 2147483648)
ret i32 %val
}

View File

@ -0,0 +1,13 @@
; Test 8-bit atomic loads.
;
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s
; This is just a placeholder to make sure that loads are handled.
; The CS-based sequence is probably far too conservative.
define i8 @f1(i8 *%src) {
; CHECK: f1:
; CHECK: cs
; CHECK: br %r14
%val = load atomic i8 *%src seq_cst, align 1
ret i8 %val
}

View File

@ -0,0 +1,13 @@
; Test 16-bit atomic loads.
;
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s
; This is just a placeholder to make sure that loads are handled.
; The CS-based sequence is probably far too conservative.
define i16 @f1(i16 *%src) {
; CHECK: f1:
; CHECK: cs
; CHECK: br %r14
%val = load atomic i16 *%src seq_cst, align 2
ret i16 %val
}

View File

@ -0,0 +1,14 @@
; Test 32-bit atomic loads.
;
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s
; This is just a placeholder to make sure that loads are handled.
; Using CS is probably too conservative.
define i32 @f1(i32 %dummy, i32 *%src) {
; CHECK: f1:
; CHECK: lhi %r2, 0
; CHECK: cs %r2, %r2, 0(%r3)
; CHECK: br %r14
%val = load atomic i32 *%src seq_cst, align 4
ret i32 %val
}

View File

@ -0,0 +1,14 @@
; Test 64-bit atomic loads.
;
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s
; This is just a placeholder to make sure that loads are handled.
; Using CSG is probably too conservative.
define i64 @f1(i64 %dummy, i64 *%src) {
; CHECK: f1:
; CHECK: lghi %r2, 0
; CHECK: csg %r2, %r2, 0(%r3)
; CHECK: br %r14
%val = load atomic i64 *%src seq_cst, align 8
ret i64 %val
}

View File

@ -0,0 +1,13 @@
; Test 8-bit atomic stores.
;
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s
; This is just a placeholder to make sure that stores are handled.
; The CS-based sequence is probably far too conservative.
define void @f1(i8 %val, i8 *%src) {
; CHECK: f1:
; CHECK: cs
; CHECK: br %r14
store atomic i8 %val, i8 *%src seq_cst, align 1
ret void
}

View File

@ -0,0 +1,13 @@
; Test 16-bit atomic stores.
;
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s
; This is just a placeholder to make sure that stores are handled.
; The CS-based sequence is probably far too conservative.
define void @f1(i16 %val, i16 *%src) {
; CHECK: f1:
; CHECK: cs
; CHECK: br %r14
store atomic i16 %val, i16 *%src seq_cst, align 2
ret void
}

View File

@ -0,0 +1,16 @@
; Test 32-bit atomic stores.
;
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s
; This is just a placeholder to make sure that stores are handled.
; Using CS is probably too conservative.
define void @f1(i32 %val, i32 *%src) {
; CHECK: f1:
; CHECK: l %r0, 0(%r3)
; CHECK: [[LABEL:\.[^:]*]]:
; CHECK: cs %r0, %r2, 0(%r3)
; CHECK: j{{g?}}lh [[LABEL]]
; CHECK: br %r14
store atomic i32 %val, i32 *%src seq_cst, align 4
ret void
}

View File

@ -0,0 +1,16 @@
; Test 64-bit atomic stores.
;
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s
; This is just a placeholder to make sure that stores are handled.
; Using CS is probably too conservative.
define void @f1(i64 %val, i64 *%src) {
; CHECK: f1:
; CHECK: lg %r0, 0(%r3)
; CHECK: [[LABEL:\.[^:]*]]:
; CHECK: csg %r0, %r2, 0(%r3)
; CHECK: j{{g?}}lh [[LABEL]]
; CHECK: br %r14
store atomic i64 %val, i64 *%src seq_cst, align 8
ret void
}

View File

@ -0,0 +1,132 @@
; Test 8-bit atomic additions.
;
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s -check-prefix=CHECK
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s -check-prefix=CHECK-SHIFT1
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s -check-prefix=CHECK-SHIFT2
; Check addition of a variable.
; - CHECK is for the main loop.
; - CHECK-SHIFT1 makes sure that the negated shift count used by the second
; RLL is set up correctly. The negation is independent of the NILL and L
; tested in CHECK.
; - CHECK-SHIFT2 makes sure that %b is shifted into the high part of the word
; before being used. This shift is independent of the other loop prologue
; instructions.
define i8 @f1(i8 *%src, i8 %b) {
; CHECK: f1:
; CHECK: sllg [[SHIFT:%r[1-9]+]], %r2, 3
; CHECK: nill %r2, 65532
; CHECK: l [[OLD:%r[0-9]+]], 0(%r2)
; CHECK: [[LABEL:\.[^:]*]]:
; CHECK: rll [[ROT:%r[0-9]+]], [[OLD]], 0([[SHIFT]])
; CHECK: ar [[ROT]], %r3
; CHECK: rll [[NEW:%r[0-9]+]], [[ROT]], 0({{%r[1-9]+}})
; CHECK: cs [[OLD]], [[NEW]], 0(%r2)
; CHECK: j{{g?}}lh [[LABEL]]
; CHECK: rll %r2, [[OLD]], 8([[SHIFT]])
; CHECK: br %r14
;
; CHECK-SHIFT1: f1:
; CHECK-SHIFT1: sllg [[SHIFT:%r[1-9]+]], %r2, 3
; CHECK-SHIFT1: lcr [[NEGSHIFT:%r[1-9]+]], [[SHIFT]]
; CHECK-SHIFT1: rll
; CHECK-SHIFT1: rll {{%r[0-9]+}}, {{%r[0-9]+}}, 0([[NEGSHIFT]])
; CHECK-SHIFT1: rll
; CHECK-SHIFT1: br %r14
;
; CHECK-SHIFT2: f1:
; CHECK-SHIFT2: sll %r3, 24
; CHECK-SHIFT2: rll
; CHECK-SHIFT2: ar {{%r[0-9]+}}, %r3
; CHECK-SHIFT2: rll
; CHECK-SHIFT2: rll
; CHECK-SHIFT2: br %r14
%res = atomicrmw add i8 *%src, i8 %b seq_cst
ret i8 %res
}
; Check the minimum signed value. We add 0x80000000 to the rotated word.
define i8 @f2(i8 *%src) {
; CHECK: f2:
; CHECK: sllg [[SHIFT:%r[1-9]+]], %r2, 3
; CHECK: nill %r2, 65532
; CHECK: l [[OLD:%r[0-9]+]], 0(%r2)
; CHECK: [[LABEL:\.[^:]*]]:
; CHECK: rll [[ROT:%r[0-9]+]], [[OLD]], 0([[SHIFT]])
; CHECK: afi [[ROT]], -2147483648
; CHECK: rll [[NEW:%r[0-9]+]], [[ROT]], 0([[NEGSHIFT:%r[1-9]+]])
; CHECK: cs [[OLD]], [[NEW]], 0(%r2)
; CHECK: j{{g?}}lh [[LABEL]]
; CHECK: rll %r2, [[OLD]], 8([[SHIFT]])
; CHECK: br %r14
;
; CHECK-SHIFT1: f2:
; CHECK-SHIFT1: sllg [[SHIFT:%r[1-9]+]], %r2, 3
; CHECK-SHIFT1: lcr [[NEGSHIFT:%r[1-9]+]], [[SHIFT]]
; CHECK-SHIFT1: rll
; CHECK-SHIFT1: rll {{%r[0-9]+}}, {{%r[0-9]+}}, 0([[NEGSHIFT]])
; CHECK-SHIFT1: rll
; CHECK-SHIFT1: br %r14
;
; CHECK-SHIFT2: f2:
; CHECK-SHIFT2: br %r14
%res = atomicrmw add i8 *%src, i8 -128 seq_cst
ret i8 %res
}
; Check addition of -1. We add 0xff000000 to the rotated word.
define i8 @f3(i8 *%src) {
; CHECK: f3:
; CHECK: afi [[ROT]], -16777216
; CHECK: br %r14
;
; CHECK-SHIFT1: f3:
; CHECK-SHIFT1: br %r14
; CHECK-SHIFT2: f3:
; CHECK-SHIFT2: br %r14
%res = atomicrmw add i8 *%src, i8 -1 seq_cst
ret i8 %res
}
; Check addition of 1. We add 0x01000000 to the rotated word.
define i8 @f4(i8 *%src) {
; CHECK: f4:
; CHECK: afi [[ROT]], 16777216
; CHECK: br %r14
;
; CHECK-SHIFT1: f4:
; CHECK-SHIFT1: br %r14
; CHECK-SHIFT2: f4:
; CHECK-SHIFT2: br %r14
%res = atomicrmw add i8 *%src, i8 1 seq_cst
ret i8 %res
}
; Check the maximum signed value. We add 0x7f000000 to the rotated word.
define i8 @f5(i8 *%src) {
; CHECK: f5:
; CHECK: afi [[ROT]], 2130706432
; CHECK: br %r14
;
; CHECK-SHIFT1: f5:
; CHECK-SHIFT1: br %r14
; CHECK-SHIFT2: f5:
; CHECK-SHIFT2: br %r14
%res = atomicrmw add i8 *%src, i8 127 seq_cst
ret i8 %res
}
; Check addition of a large unsigned value. We add 0xfe000000 to the
; rotated word, expressed as a negative AFI operand.
define i8 @f6(i8 *%src) {
; CHECK: f6:
; CHECK: afi [[ROT]], -33554432
; CHECK: br %r14
;
; CHECK-SHIFT1: f6:
; CHECK-SHIFT1: br %r14
; CHECK-SHIFT2: f6:
; CHECK-SHIFT2: br %r14
%res = atomicrmw add i8 *%src, i8 254 seq_cst
ret i8 %res
}

View File

@ -0,0 +1,132 @@
; Test 16-bit atomic additions.
;
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s -check-prefix=CHECK
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s -check-prefix=CHECK-SHIFT1
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s -check-prefix=CHECK-SHIFT2
; Check addition of a variable.
; - CHECK is for the main loop.
; - CHECK-SHIFT1 makes sure that the negated shift count used by the second
; RLL is set up correctly. The negation is independent of the NILL and L
; tested in CHECK.
; - CHECK-SHIFT2 makes sure that %b is shifted into the high part of the word
; before being used. This shift is independent of the other loop prologue
; instructions.
define i16 @f1(i16 *%src, i16 %b) {
; CHECK: f1:
; CHECK: sllg [[SHIFT:%r[1-9]+]], %r2, 3
; CHECK: nill %r2, 65532
; CHECK: l [[OLD:%r[0-9]+]], 0(%r2)
; CHECK: [[LABEL:\.[^:]*]]:
; CHECK: rll [[ROT:%r[0-9]+]], [[OLD]], 0([[SHIFT]])
; CHECK: ar [[ROT]], %r3
; CHECK: rll [[NEW:%r[0-9]+]], [[ROT]], 0({{%r[1-9]+}})
; CHECK: cs [[OLD]], [[NEW]], 0(%r2)
; CHECK: j{{g?}}lh [[LABEL]]
; CHECK: rll %r2, [[OLD]], 16([[SHIFT]])
; CHECK: br %r14
;
; CHECK-SHIFT1: f1:
; CHECK-SHIFT1: sllg [[SHIFT:%r[1-9]+]], %r2, 3
; CHECK-SHIFT1: lcr [[NEGSHIFT:%r[1-9]+]], [[SHIFT]]
; CHECK-SHIFT1: rll
; CHECK-SHIFT1: rll {{%r[0-9]+}}, {{%r[0-9]+}}, 0([[NEGSHIFT]])
; CHECK-SHIFT1: rll
; CHECK-SHIFT1: br %r14
;
; CHECK-SHIFT2: f1:
; CHECK-SHIFT2: sll %r3, 16
; CHECK-SHIFT2: rll
; CHECK-SHIFT2: ar {{%r[0-9]+}}, %r3
; CHECK-SHIFT2: rll
; CHECK-SHIFT2: rll
; CHECK-SHIFT2: br %r14
%res = atomicrmw add i16 *%src, i16 %b seq_cst
ret i16 %res
}
; Check the minimum signed value. We add 0x80000000 to the rotated word.
define i16 @f2(i16 *%src) {
; CHECK: f2:
; CHECK: sllg [[SHIFT:%r[1-9]+]], %r2, 3
; CHECK: nill %r2, 65532
; CHECK: l [[OLD:%r[0-9]+]], 0(%r2)
; CHECK: [[LABEL:\.[^:]*]]:
; CHECK: rll [[ROT:%r[0-9]+]], [[OLD]], 0([[SHIFT]])
; CHECK: afi [[ROT]], -2147483648
; CHECK: rll [[NEW:%r[0-9]+]], [[ROT]], 0([[NEGSHIFT:%r[1-9]+]])
; CHECK: cs [[OLD]], [[NEW]], 0(%r2)
; CHECK: j{{g?}}lh [[LABEL]]
; CHECK: rll %r2, [[OLD]], 16([[SHIFT]])
; CHECK: br %r14
;
; CHECK-SHIFT1: f2:
; CHECK-SHIFT1: sllg [[SHIFT:%r[1-9]+]], %r2, 3
; CHECK-SHIFT1: lcr [[NEGSHIFT:%r[1-9]+]], [[SHIFT]]
; CHECK-SHIFT1: rll
; CHECK-SHIFT1: rll {{%r[0-9]+}}, {{%r[0-9]+}}, 0([[NEGSHIFT]])
; CHECK-SHIFT1: rll
; CHECK-SHIFT1: br %r14
;
; CHECK-SHIFT2: f2:
; CHECK-SHIFT2: br %r14
%res = atomicrmw add i16 *%src, i16 -32768 seq_cst
ret i16 %res
}
; Check addition of -1. We add 0xffff0000 to the rotated word.
define i16 @f3(i16 *%src) {
; CHECK: f3:
; CHECK: afi [[ROT]], -65536
; CHECK: br %r14
;
; CHECK-SHIFT1: f3:
; CHECK-SHIFT1: br %r14
; CHECK-SHIFT2: f3:
; CHECK-SHIFT2: br %r14
%res = atomicrmw add i16 *%src, i16 -1 seq_cst
ret i16 %res
}
; Check addition of 1. We add 0x00010000 to the rotated word.
define i16 @f4(i16 *%src) {
; CHECK: f4:
; CHECK: afi [[ROT]], 65536
; CHECK: br %r14
;
; CHECK-SHIFT1: f4:
; CHECK-SHIFT1: br %r14
; CHECK-SHIFT2: f4:
; CHECK-SHIFT2: br %r14
%res = atomicrmw add i16 *%src, i16 1 seq_cst
ret i16 %res
}
; Check the maximum signed value. We add 0x7fff0000 to the rotated word.
define i16 @f5(i16 *%src) {
; CHECK: f5:
; CHECK: afi [[ROT]], 2147418112
; CHECK: br %r14
;
; CHECK-SHIFT1: f5:
; CHECK-SHIFT1: br %r14
; CHECK-SHIFT2: f5:
; CHECK-SHIFT2: br %r14
%res = atomicrmw add i16 *%src, i16 32767 seq_cst
ret i16 %res
}
; Check addition of a large unsigned value. We add 0xfffe0000 to the
; rotated word, expressed as a negative AFI operand.
define i16 @f6(i16 *%src) {
; CHECK: f6:
; CHECK: afi [[ROT]], -131072
; CHECK: br %r14
;
; CHECK-SHIFT1: f6:
; CHECK-SHIFT1: br %r14
; CHECK-SHIFT2: f6:
; CHECK-SHIFT2: br %r14
%res = atomicrmw add i16 *%src, i16 65534 seq_cst
ret i16 %res
}

View File

@ -0,0 +1,94 @@
; Test 32-bit atomic additions.
;
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s
; Check addition of a variable.
define i32 @f1(i32 %dummy, i32 *%src, i32 %b) {
; CHECK: f1:
; CHECK: l %r2, 0(%r3)
; CHECK: [[LABEL:\.[^:]*]]:
; CHECK: lr %r0, %r2
; CHECK: ar %r0, %r4
; CHECK: cs %r2, %r0, 0(%r3)
; CHECK: j{{g?}}lh [[LABEL]]
; CHECK: br %r14
%res = atomicrmw add i32 *%src, i32 %b seq_cst
ret i32 %res
}
; Check addition of 1, which can use AHI.
define i32 @f2(i32 %dummy, i32 *%src) {
; CHECK: f2:
; CHECK: l %r2, 0(%r3)
; CHECK: [[LABEL:\.[^:]*]]:
; CHECK: lr %r0, %r2
; CHECK: ahi %r0, 1
; CHECK: cs %r2, %r0, 0(%r3)
; CHECK: j{{g?}}lh [[LABEL]]
; CHECK: br %r14
%res = atomicrmw add i32 *%src, i32 1 seq_cst
ret i32 %res
}
; Check the high end of the AHI range.
define i32 @f3(i32 %dummy, i32 *%src) {
; CHECK: f3:
; CHECK: ahi %r0, 32767
; CHECK: br %r14
%res = atomicrmw add i32 *%src, i32 32767 seq_cst
ret i32 %res
}
; Check the next value up, which must use AFI.
define i32 @f4(i32 %dummy, i32 *%src) {
; CHECK: f4:
; CHECK: afi %r0, 32768
; CHECK: br %r14
%res = atomicrmw add i32 *%src, i32 32768 seq_cst
ret i32 %res
}
; Check the high end of the AFI range.
define i32 @f5(i32 %dummy, i32 *%src) {
; CHECK: f5:
; CHECK: afi %r0, 2147483647
; CHECK: br %r14
%res = atomicrmw add i32 *%src, i32 2147483647 seq_cst
ret i32 %res
}
; Check the next value up, which gets treated as a negative operand.
define i32 @f6(i32 %dummy, i32 *%src) {
; CHECK: f6:
; CHECK: afi %r0, -2147483648
; CHECK: br %r14
%res = atomicrmw add i32 *%src, i32 2147483648 seq_cst
ret i32 %res
}
; Check addition of -1, which can use AHI.
define i32 @f7(i32 %dummy, i32 *%src) {
; CHECK: f7:
; CHECK: ahi %r0, -1
; CHECK: br %r14
%res = atomicrmw add i32 *%src, i32 -1 seq_cst
ret i32 %res
}
; Check the low end of the AHI range.
define i32 @f8(i32 %dummy, i32 *%src) {
; CHECK: f8:
; CHECK: ahi %r0, -32768
; CHECK: br %r14
%res = atomicrmw add i32 *%src, i32 -32768 seq_cst
ret i32 %res
}
; Check the next value down, which must use AFI instead.
define i32 @f9(i32 %dummy, i32 *%src) {
; CHECK: f9:
; CHECK: afi %r0, -32769
; CHECK: br %r14
%res = atomicrmw add i32 *%src, i32 -32769 seq_cst
ret i32 %res
}

View File

@ -0,0 +1,112 @@
; Test 64-bit atomic additions.
;
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s
; Check addition of a variable.
define i64 @f1(i64 %dummy, i64 *%src, i64 %b) {
; CHECK: f1:
; CHECK: lg %r2, 0(%r3)
; CHECK: [[LABEL:\.[^:]*]]:
; CHECK: lgr %r0, %r2
; CHECK: agr %r0, %r4
; CHECK: csg %r2, %r0, 0(%r3)
; CHECK: j{{g?}}lh [[LABEL]]
; CHECK: br %r14
%res = atomicrmw add i64 *%src, i64 %b seq_cst
ret i64 %res
}
; Check addition of 1, which can use AGHI.
define i64 @f2(i64 %dummy, i64 *%src) {
; CHECK: f2:
; CHECK: lg %r2, 0(%r3)
; CHECK: [[LABEL:\.[^:]*]]:
; CHECK: lgr %r0, %r2
; CHECK: aghi %r0, 1
; CHECK: csg %r2, %r0, 0(%r3)
; CHECK: j{{g?}}lh [[LABEL]]
; CHECK: br %r14
%res = atomicrmw add i64 *%src, i64 1 seq_cst
ret i64 %res
}
; Check the high end of the AGHI range.
define i64 @f3(i64 %dummy, i64 *%src) {
; CHECK: f3:
; CHECK: aghi %r0, 32767
; CHECK: br %r14
%res = atomicrmw add i64 *%src, i64 32767 seq_cst
ret i64 %res
}
; Check the next value up, which must use AGFI.
define i64 @f4(i64 %dummy, i64 *%src) {
; CHECK: f4:
; CHECK: agfi %r0, 32768
; CHECK: br %r14
%res = atomicrmw add i64 *%src, i64 32768 seq_cst
ret i64 %res
}
; Check the high end of the AGFI range.
define i64 @f5(i64 %dummy, i64 *%src) {
; CHECK: f5:
; CHECK: agfi %r0, 2147483647
; CHECK: br %r14
%res = atomicrmw add i64 *%src, i64 2147483647 seq_cst
ret i64 %res
}
; Check the next value up, which must use a register addition.
define i64 @f6(i64 %dummy, i64 *%src) {
; CHECK: f6:
; CHECK: agr
; CHECK: br %r14
%res = atomicrmw add i64 *%src, i64 2147483648 seq_cst
ret i64 %res
}
; Check addition of -1, which can use AGHI.
define i64 @f7(i64 %dummy, i64 *%src) {
; CHECK: f7:
; CHECK: aghi %r0, -1
; CHECK: br %r14
%res = atomicrmw add i64 *%src, i64 -1 seq_cst
ret i64 %res
}
; Check the low end of the AGHI range.
define i64 @f8(i64 %dummy, i64 *%src) {
; CHECK: f8:
; CHECK: aghi %r0, -32768
; CHECK: br %r14
%res = atomicrmw add i64 *%src, i64 -32768 seq_cst
ret i64 %res
}
; Check the next value down, which must use AGFI instead.
define i64 @f9(i64 %dummy, i64 *%src) {
; CHECK: f9:
; CHECK: agfi %r0, -32769
; CHECK: br %r14
%res = atomicrmw add i64 *%src, i64 -32769 seq_cst
ret i64 %res
}
; Check the low end of the AGFI range.
define i64 @f10(i64 %dummy, i64 *%src) {
; CHECK: f10:
; CHECK: agfi %r0, -2147483648
; CHECK: br %r14
%res = atomicrmw add i64 *%src, i64 -2147483648 seq_cst
ret i64 %res
}
; Check the next value down, which must use a register addition.
define i64 @f11(i64 %dummy, i64 *%src) {
; CHECK: f11:
; CHECK: agr
; CHECK: br %r14
%res = atomicrmw add i64 *%src, i64 -2147483649 seq_cst
ret i64 %res
}

View File

@ -0,0 +1,133 @@
; Test 8-bit atomic ANDs.
;
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s -check-prefix=CHECK
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s -check-prefix=CHECK-SHIFT1
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s -check-prefix=CHECK-SHIFT2
; Check AND of a variable.
; - CHECK is for the main loop.
; - CHECK-SHIFT1 makes sure that the negated shift count used by the second
; RLL is set up correctly. The negation is independent of the NILL and L
; tested in CHECK.
; - CHECK-SHIFT2 makes sure that %b is shifted into the high part of the word
; before being used, and that the low bits are set to 1. This sequence is
; independent of the other loop prologue instructions.
define i8 @f1(i8 *%src, i8 %b) {
; CHECK: f1:
; CHECK: sllg [[SHIFT:%r[1-9]+]], %r2, 3
; CHECK: nill %r2, 65532
; CHECK: l [[OLD:%r[0-9]+]], 0(%r2)
; CHECK: [[LABEL:\.[^:]*]]:
; CHECK: rll [[ROT:%r[0-9]+]], [[OLD]], 0([[SHIFT]])
; CHECK: nr [[ROT]], %r3
; CHECK: rll [[NEW:%r[0-9]+]], [[ROT]], 0({{%r[1-9]+}})
; CHECK: cs [[OLD]], [[NEW]], 0(%r2)
; CHECK: j{{g?}}lh [[LABEL]]
; CHECK: rll %r2, [[OLD]], 8([[SHIFT]])
; CHECK: br %r14
;
; CHECK-SHIFT1: f1:
; CHECK-SHIFT1: sllg [[SHIFT:%r[1-9]+]], %r2, 3
; CHECK-SHIFT1: lcr [[NEGSHIFT:%r[1-9]+]], [[SHIFT]]
; CHECK-SHIFT1: rll
; CHECK-SHIFT1: rll {{%r[0-9]+}}, {{%r[0-9]+}}, 0([[NEGSHIFT]])
; CHECK-SHIFT1: rll
; CHECK-SHIFT1: br %r14
;
; CHECK-SHIFT2: f1:
; CHECK-SHIFT2: sll %r3, 24
; CHECK-SHIFT2: oilf %r3, 16777215
; CHECK-SHIFT2: rll
; CHECK-SHIFT2: nr {{%r[0-9]+}}, %r3
; CHECK-SHIFT2: rll
; CHECK-SHIFT2: rll
; CHECK-SHIFT2: br %r14
%res = atomicrmw and i8 *%src, i8 %b seq_cst
ret i8 %res
}
; Check the minimum signed value. We AND the rotated word with 0x80ffffff.
define i8 @f2(i8 *%src) {
; CHECK: f2:
; CHECK: sllg [[SHIFT:%r[1-9]+]], %r2, 3
; CHECK: nill %r2, 65532
; CHECK: l [[OLD:%r[0-9]+]], 0(%r2)
; CHECK: [[LABEL:\.[^:]*]]:
; CHECK: rll [[ROT:%r[0-9]+]], [[OLD]], 0([[SHIFT]])
; CHECK: nilh [[ROT]], 33023
; CHECK: rll [[NEW:%r[0-9]+]], [[ROT]], 0([[NEGSHIFT:%r[1-9]+]])
; CHECK: cs [[OLD]], [[NEW]], 0(%r2)
; CHECK: j{{g?}}lh [[LABEL]]
; CHECK: rll %r2, [[OLD]], 8([[SHIFT]])
; CHECK: br %r14
;
; CHECK-SHIFT1: f2:
; CHECK-SHIFT1: sllg [[SHIFT:%r[1-9]+]], %r2, 3
; CHECK-SHIFT1: lcr [[NEGSHIFT:%r[1-9]+]], [[SHIFT]]
; CHECK-SHIFT1: rll
; CHECK-SHIFT1: rll {{%r[0-9]+}}, {{%r[0-9]+}}, 0([[NEGSHIFT]])
; CHECK-SHIFT1: rll
; CHECK-SHIFT1: br %r14
;
; CHECK-SHIFT2: f2:
; CHECK-SHIFT2: br %r14
%res = atomicrmw and i8 *%src, i8 -128 seq_cst
ret i8 %res
}
; Check ANDs of -2 (-1 isn't useful). We AND the rotated word with 0xfeffffff.
define i8 @f3(i8 *%src) {
; CHECK: f3:
; CHECK: nilh [[ROT]], 65279
; CHECK: br %r14
;
; CHECK-SHIFT1: f3:
; CHECK-SHIFT1: br %r14
; CHECK-SHIFT2: f3:
; CHECK-SHIFT2: br %r14
%res = atomicrmw and i8 *%src, i8 -2 seq_cst
ret i8 %res
}
; Check ANDs of 1. We AND the rotated word with 0x01ffffff.
define i8 @f4(i8 *%src) {
; CHECK: f4:
; CHECK: nilh [[ROT]], 511
; CHECK: br %r14
;
; CHECK-SHIFT1: f4:
; CHECK-SHIFT1: br %r14
; CHECK-SHIFT2: f4:
; CHECK-SHIFT2: br %r14
%res = atomicrmw and i8 *%src, i8 1 seq_cst
ret i8 %res
}
; Check the maximum signed value. We AND the rotated word with 0x7fffffff.
define i8 @f5(i8 *%src) {
; CHECK: f5:
; CHECK: nilh [[ROT]], 32767
; CHECK: br %r14
;
; CHECK-SHIFT1: f5:
; CHECK-SHIFT1: br %r14
; CHECK-SHIFT2: f5:
; CHECK-SHIFT2: br %r14
%res = atomicrmw and i8 *%src, i8 127 seq_cst
ret i8 %res
}
; Check ANDs of a large unsigned value. We AND the rotated word with
; 0xfdffffff.
define i8 @f6(i8 *%src) {
; CHECK: f6:
; CHECK: nilh [[ROT]], 65023
; CHECK: br %r14
;
; CHECK-SHIFT1: f6:
; CHECK-SHIFT1: br %r14
; CHECK-SHIFT2: f6:
; CHECK-SHIFT2: br %r14
%res = atomicrmw and i8 *%src, i8 253 seq_cst
ret i8 %res
}

View File

@ -0,0 +1,133 @@
; Test 16-bit atomic ANDs.
;
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s -check-prefix=CHECK
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s -check-prefix=CHECK-SHIFT1
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s -check-prefix=CHECK-SHIFT2
; Check AND of a variable.
; - CHECK is for the main loop.
; - CHECK-SHIFT1 makes sure that the negated shift count used by the second
; RLL is set up correctly. The negation is independent of the NILL and L
; tested in CHECK.
; - CHECK-SHIFT2 makes sure that %b is shifted into the high part of the word
; before being used, and that the low bits are set to 1. This sequence is
; independent of the other loop prologue instructions.
define i16 @f1(i16 *%src, i16 %b) {
; CHECK: f1:
; CHECK: sllg [[SHIFT:%r[1-9]+]], %r2, 3
; CHECK: nill %r2, 65532
; CHECK: l [[OLD:%r[0-9]+]], 0(%r2)
; CHECK: [[LABEL:\.[^:]*]]:
; CHECK: rll [[ROT:%r[0-9]+]], [[OLD]], 0([[SHIFT]])
; CHECK: nr [[ROT]], %r3
; CHECK: rll [[NEW:%r[0-9]+]], [[ROT]], 0({{%r[1-9]+}})
; CHECK: cs [[OLD]], [[NEW]], 0(%r2)
; CHECK: j{{g?}}lh [[LABEL]]
; CHECK: rll %r2, [[OLD]], 16([[SHIFT]])
; CHECK: br %r14
;
; CHECK-SHIFT1: f1:
; CHECK-SHIFT1: sllg [[SHIFT:%r[1-9]+]], %r2, 3
; CHECK-SHIFT1: lcr [[NEGSHIFT:%r[1-9]+]], [[SHIFT]]
; CHECK-SHIFT1: rll
; CHECK-SHIFT1: rll {{%r[0-9]+}}, {{%r[0-9]+}}, 0([[NEGSHIFT]])
; CHECK-SHIFT1: rll
; CHECK-SHIFT1: br %r14
;
; CHECK-SHIFT2: f1:
; CHECK-SHIFT2: sll %r3, 16
; CHECK-SHIFT2: oill %r3, 65535
; CHECK-SHIFT2: rll
; CHECK-SHIFT2: nr {{%r[0-9]+}}, %r3
; CHECK-SHIFT2: rll
; CHECK-SHIFT2: rll
; CHECK-SHIFT2: br %r14
%res = atomicrmw and i16 *%src, i16 %b seq_cst
ret i16 %res
}
; Check the minimum signed value. We AND the rotated word with 0x8000ffff.
define i16 @f2(i16 *%src) {
; CHECK: f2:
; CHECK: sllg [[SHIFT:%r[1-9]+]], %r2, 3
; CHECK: nill %r2, 65532
; CHECK: l [[OLD:%r[0-9]+]], 0(%r2)
; CHECK: [[LABEL:\.[^:]*]]:
; CHECK: rll [[ROT:%r[0-9]+]], [[OLD]], 0([[SHIFT]])
; CHECK: nilh [[ROT]], 32768
; CHECK: rll [[NEW:%r[0-9]+]], [[ROT]], 0([[NEGSHIFT:%r[1-9]+]])
; CHECK: cs [[OLD]], [[NEW]], 0(%r2)
; CHECK: j{{g?}}lh [[LABEL]]
; CHECK: rll %r2, [[OLD]], 16([[SHIFT]])
; CHECK: br %r14
;
; CHECK-SHIFT1: f2:
; CHECK-SHIFT1: sllg [[SHIFT:%r[1-9]+]], %r2, 3
; CHECK-SHIFT1: lcr [[NEGSHIFT:%r[1-9]+]], [[SHIFT]]
; CHECK-SHIFT1: rll
; CHECK-SHIFT1: rll {{%r[0-9]+}}, {{%r[0-9]+}}, 0([[NEGSHIFT]])
; CHECK-SHIFT1: rll
; CHECK-SHIFT1: br %r14
;
; CHECK-SHIFT2: f2:
; CHECK-SHIFT2: br %r14
%res = atomicrmw and i16 *%src, i16 -32768 seq_cst
ret i16 %res
}
; Check ANDs of -2 (-1 isn't useful). We AND the rotated word with 0xfffeffff.
define i16 @f3(i16 *%src) {
; CHECK: f3:
; CHECK: nilh [[ROT]], 65534
; CHECK: br %r14
;
; CHECK-SHIFT1: f3:
; CHECK-SHIFT1: br %r14
; CHECK-SHIFT2: f3:
; CHECK-SHIFT2: br %r14
%res = atomicrmw and i16 *%src, i16 -2 seq_cst
ret i16 %res
}
; Check ANDs of 1. We AND the rotated word with 0x0001ffff.
define i16 @f4(i16 *%src) {
; CHECK: f4:
; CHECK: nilh [[ROT]], 1
; CHECK: br %r14
;
; CHECK-SHIFT1: f4:
; CHECK-SHIFT1: br %r14
; CHECK-SHIFT2: f4:
; CHECK-SHIFT2: br %r14
%res = atomicrmw and i16 *%src, i16 1 seq_cst
ret i16 %res
}
; Check the maximum signed value. We AND the rotated word with 0x7fffffff.
define i16 @f5(i16 *%src) {
; CHECK: f5:
; CHECK: nilh [[ROT]], 32767
; CHECK: br %r14
;
; CHECK-SHIFT1: f5:
; CHECK-SHIFT1: br %r14
; CHECK-SHIFT2: f5:
; CHECK-SHIFT2: br %r14
%res = atomicrmw and i16 *%src, i16 32767 seq_cst
ret i16 %res
}
; Check ANDs of a large unsigned value. We AND the rotated word with
; 0xfffdffff.
define i16 @f6(i16 *%src) {
; CHECK: f6:
; CHECK: nilh [[ROT]], 65533
; CHECK: br %r14
;
; CHECK-SHIFT1: f6:
; CHECK-SHIFT1: br %r14
; CHECK-SHIFT2: f6:
; CHECK-SHIFT2: br %r14
%res = atomicrmw and i16 *%src, i16 65533 seq_cst
ret i16 %res
}

View File

@ -0,0 +1,85 @@
; Test 32-bit atomic ANDs.
;
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s
; Check ANDs of a variable.
define i32 @f1(i32 %dummy, i32 *%src, i32 %b) {
; CHECK: f1:
; CHECK: l %r2, 0(%r3)
; CHECK: [[LABEL:\.[^ ]*]]:
; CHECK: lr %r0, %r2
; CHECK: nr %r0, %r4
; CHECK: cs %r2, %r0, 0(%r3)
; CHECK: j{{g?}}lh [[LABEL]]
; CHECK: br %r14
%res = atomicrmw and i32 *%src, i32 %b seq_cst
ret i32 %res
}
; Check ANDs of 1.
define i32 @f2(i32 %dummy, i32 *%src) {
; CHECK: f2:
; CHECK: l %r2, 0(%r3)
; CHECK: [[LABEL:\.[^ ]*]]:
; CHECK: lr %r0, %r2
; CHECK: nilf %r0, 1
; CHECK: cs %r2, %r0, 0(%r3)
; CHECK: j{{g?}}lh [[LABEL]]
; CHECK: br %r14
%res = atomicrmw and i32 *%src, i32 1 seq_cst
ret i32 %res
}
; Check ANDs of the low end of the NILH range.
define i32 @f3(i32 %dummy, i32 *%src) {
; CHECK: f3:
; CHECK: nilh %r0, 0
; CHECK: br %r14
%res = atomicrmw and i32 *%src, i32 65535 seq_cst
ret i32 %res
}
; Check the next value up, which must use NILF.
define i32 @f4(i32 %dummy, i32 *%src) {
; CHECK: f4:
; CHECK: nilf %r0, 65536
; CHECK: br %r14
%res = atomicrmw and i32 *%src, i32 65536 seq_cst
ret i32 %res
}
; Check the largest useful NILL value.
define i32 @f5(i32 %dummy, i32 *%src) {
; CHECK: f5:
; CHECK: nill %r0, 65534
; CHECK: br %r14
%res = atomicrmw and i32 *%src, i32 -2 seq_cst
ret i32 %res
}
; Check the low end of the NILL range.
define i32 @f6(i32 %dummy, i32 *%src) {
; CHECK: f6:
; CHECK: nill %r0, 0
; CHECK: br %r14
%res = atomicrmw and i32 *%src, i32 -65536 seq_cst
ret i32 %res
}
; Check the largest useful NILH value, which is one less than the above.
define i32 @f7(i32 %dummy, i32 *%src) {
; CHECK: f7:
; CHECK: nilh %r0, 65534
; CHECK: br %r14
%res = atomicrmw and i32 *%src, i32 -65537 seq_cst
ret i32 %res
}
; Check the highest useful NILF value, which is one less than the above.
define i32 @f8(i32 %dummy, i32 *%src) {
; CHECK: f8:
; CHECK: nilf %r0, 4294901758
; CHECK: br %r14
%res = atomicrmw and i32 *%src, i32 -65538 seq_cst
ret i32 %res
}

View File

@ -0,0 +1,157 @@
; Test 64-bit atomic ANDs.
;
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s
; Check ANDs of a variable.
define i64 @f1(i64 %dummy, i64 *%src, i64 %b) {
; CHECK: f1:
; CHECK: lg %r2, 0(%r3)
; CHECK: [[LABEL:\.[^:]*]]:
; CHECK: lgr %r0, %r2
; CHECK: ngr %r0, %r4
; CHECK: csg %r2, %r0, 0(%r3)
; CHECK: j{{g?}}lh [[LABEL]]
; CHECK: br %r14
%res = atomicrmw and i64 *%src, i64 %b seq_cst
ret i64 %res
}
; Check ANDs of 1, which must be done using a register.
define i64 @f2(i64 %dummy, i64 *%src) {
; CHECK: f2:
; CHECK: ngr
; CHECK: br %r14
%res = atomicrmw and i64 *%src, i64 1 seq_cst
ret i64 %res
}
; Check the low end of the NIHF range.
define i64 @f3(i64 %dummy, i64 *%src) {
; CHECK: f3:
; CHECK: lg %r2, 0(%r3)
; CHECK: [[LABEL:\.[^:]*]]:
; CHECK: lgr %r0, %r2
; CHECK: nihf %r0, 0
; CHECK: csg %r2, %r0, 0(%r3)
; CHECK: j{{g?}}lh [[LABEL]]
; CHECK: br %r14
%res = atomicrmw and i64 *%src, i64 4294967295 seq_cst
ret i64 %res
}
; Check the next value up, which must use a register.
define i64 @f4(i64 %dummy, i64 *%src) {
; CHECK: f4:
; CHECK: ngr
; CHECK: br %r14
%res = atomicrmw and i64 *%src, i64 4294967296 seq_cst
ret i64 %res
}
; Check the low end of the NIHH range.
define i64 @f5(i64 %dummy, i64 *%src) {
; CHECK: f5:
; CHECK: nihh %r0, 0
; CHECK: br %r14
%res = atomicrmw and i64 *%src, i64 281474976710655 seq_cst
ret i64 %res
}
; Check the next value up, which must use a register.
define i64 @f6(i64 %dummy, i64 *%src) {
; CHECK: f6:
; CHECK: ngr
; CHECK: br %r14
%res = atomicrmw and i64 *%src, i64 281474976710656 seq_cst
ret i64 %res
}
; Check the highest useful NILL value.
define i64 @f7(i64 %dummy, i64 *%src) {
; CHECK: f7:
; CHECK: nill %r0, 65534
; CHECK: br %r14
%res = atomicrmw and i64 *%src, i64 -2 seq_cst
ret i64 %res
}
; Check the low end of the NILL range.
define i64 @f8(i64 %dummy, i64 *%src) {
; CHECK: f8:
; CHECK: nill %r0, 0
; CHECK: br %r14
%res = atomicrmw and i64 *%src, i64 -65536 seq_cst
ret i64 %res
}
; Check the highest useful NILH value, which is one less than the above.
define i64 @f9(i64 %dummy, i64 *%src) {
; CHECK: f9:
; CHECK: nilh %r0, 65534
; CHECK: br %r14
%res = atomicrmw and i64 *%src, i64 -65537 seq_cst
ret i64 %res
}
; Check the highest useful NILF value, which is one less than the above.
define i64 @f10(i64 %dummy, i64 *%src) {
; CHECK: f10:
; CHECK: nilf %r0, 4294901758
; CHECK: br %r14
%res = atomicrmw and i64 *%src, i64 -65538 seq_cst
ret i64 %res
}
; Check the low end of the NILH range.
define i64 @f11(i64 %dummy, i64 *%src) {
; CHECK: f11:
; CHECK: nilh %r0, 0
; CHECK: br %r14
%res = atomicrmw and i64 *%src, i64 -4294901761 seq_cst
ret i64 %res
}
; Check the low end of the NILF range.
define i64 @f12(i64 %dummy, i64 *%src) {
; CHECK: f12:
; CHECK: nilf %r0, 0
; CHECK: br %r14
%res = atomicrmw and i64 *%src, i64 -4294967296 seq_cst
ret i64 %res
}
; Check the highest useful NIHL value, which is one less than the above.
define i64 @f13(i64 %dummy, i64 *%src) {
; CHECK: f13:
; CHECK: nihl %r0, 65534
; CHECK: br %r14
%res = atomicrmw and i64 *%src, i64 -4294967297 seq_cst
ret i64 %res
}
; Check the low end of the NIHL range.
define i64 @f14(i64 %dummy, i64 *%src) {
; CHECK: f14:
; CHECK: nihl %r0, 0
; CHECK: br %r14
%res = atomicrmw and i64 *%src, i64 -281470681743361 seq_cst
ret i64 %res
}
; Check the highest useful NIHH value, which is 1<<32 less than the above.
define i64 @f15(i64 %dummy, i64 *%src) {
; CHECK: f15:
; CHECK: nihh %r0, 65534
; CHECK: br %r14
%res = atomicrmw and i64 *%src, i64 -281474976710657 seq_cst
ret i64 %res
}
; Check the highest useful NIHF value, which is 1<<32 less than the above.
define i64 @f16(i64 %dummy, i64 *%src) {
; CHECK: f16:
; CHECK: nihf %r0, 4294901758
; CHECK: br %r14
%res = atomicrmw and i64 *%src, i64 -281479271677953 seq_cst
ret i64 %res
}

View File

@ -0,0 +1,228 @@
; Test 8-bit atomic min/max operations.
;
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s -check-prefix=CHECK
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s -check-prefix=CHECK-SHIFT1
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s -check-prefix=CHECK-SHIFT2
; Check signed minimum.
; - CHECK is for the main loop.
; - CHECK-SHIFT1 makes sure that the negated shift count used by the second
; RLL is set up correctly. The negation is independent of the NILL and L
; tested in CHECK.
; - CHECK-SHIFT2 makes sure that %b is shifted into the high part of the word
; before being used, and that the low bits are set to 1. This sequence is
; independent of the other loop prologue instructions.
define i8 @f1(i8 *%src, i8 %b) {
; CHECK: f1:
; CHECK: sllg [[SHIFT:%r[1-9]+]], %r2, 3
; CHECK: nill %r2, 65532
; CHECK: l [[OLD:%r[0-9]+]], 0(%r2)
; CHECK: [[LOOP:\.[^:]*]]:
; CHECK: rll [[ROT:%r[0-9]+]], [[OLD]], 0([[SHIFT]])
; CHECK: cr [[ROT]], %r3
; CHECK: j{{g?}}le [[KEEP:\..*]]
; CHECK: risbg [[ROT]], %r3, 32, 39, 0
; CHECK: [[KEEP]]:
; CHECK: rll [[NEW:%r[0-9]+]], [[ROT]], 0({{%r[1-9]+}})
; CHECK: cs [[OLD]], [[NEW]], 0(%r2)
; CHECK: j{{g?}}lh [[LOOP]]
; CHECK: rll %r2, [[OLD]], 8([[SHIFT]])
; CHECK: br %r14
;
; CHECK-SHIFT1: f1:
; CHECK-SHIFT1: sllg [[SHIFT:%r[1-9]+]], %r2, 3
; CHECK-SHIFT1: lcr [[NEGSHIFT:%r[1-9]+]], [[SHIFT]]
; CHECK-SHIFT1: rll
; CHECK-SHIFT1: rll {{%r[0-9]+}}, {{%r[0-9]+}}, 0([[NEGSHIFT]])
; CHECK-SHIFT1: rll
; CHECK-SHIFT1: br %r14
;
; CHECK-SHIFT2: f1:
; CHECK-SHIFT2: sll %r3, 24
; CHECK-SHIFT2: rll
; CHECK-SHIFT2: cr {{%r[0-9]+}}, %r3
; CHECK-SHIFT2: rll
; CHECK-SHIFT2: rll
; CHECK-SHIFT2: br %r14
%res = atomicrmw min i8 *%src, i8 %b seq_cst
ret i8 %res
}
; Check signed maximum.
define i8 @f2(i8 *%src, i8 %b) {
; CHECK: f2:
; CHECK: sllg [[SHIFT:%r[1-9]+]], %r2, 3
; CHECK: nill %r2, 65532
; CHECK: l [[OLD:%r[0-9]+]], 0(%r2)
; CHECK: [[LOOP:\.[^:]*]]:
; CHECK: rll [[ROT:%r[0-9]+]], [[OLD]], 0([[SHIFT]])
; CHECK: cr [[ROT]], %r3
; CHECK: j{{g?}}he [[KEEP:\..*]]
; CHECK: risbg [[ROT]], %r3, 32, 39, 0
; CHECK: [[KEEP]]:
; CHECK: rll [[NEW:%r[0-9]+]], [[ROT]], 0({{%r[1-9]+}})
; CHECK: cs [[OLD]], [[NEW]], 0(%r2)
; CHECK: j{{g?}}lh [[LOOP]]
; CHECK: rll %r2, [[OLD]], 8([[SHIFT]])
; CHECK: br %r14
;
; CHECK-SHIFT1: f2:
; CHECK-SHIFT1: sllg [[SHIFT:%r[1-9]+]], %r2, 3
; CHECK-SHIFT1: lcr [[NEGSHIFT:%r[1-9]+]], [[SHIFT]]
; CHECK-SHIFT1: rll
; CHECK-SHIFT1: rll {{%r[0-9]+}}, {{%r[0-9]+}}, 0([[NEGSHIFT]])
; CHECK-SHIFT1: rll
; CHECK-SHIFT1: br %r14
;
; CHECK-SHIFT2: f2:
; CHECK-SHIFT2: sll %r3, 24
; CHECK-SHIFT2: rll
; CHECK-SHIFT2: cr {{%r[0-9]+}}, %r3
; CHECK-SHIFT2: rll
; CHECK-SHIFT2: rll
; CHECK-SHIFT2: br %r14
%res = atomicrmw max i8 *%src, i8 %b seq_cst
ret i8 %res
}
; Check unsigned minimum.
define i8 @f3(i8 *%src, i8 %b) {
; CHECK: f3:
; CHECK: sllg [[SHIFT:%r[1-9]+]], %r2, 3
; CHECK: nill %r2, 65532
; CHECK: l [[OLD:%r[0-9]+]], 0(%r2)
; CHECK: [[LOOP:\.[^:]*]]:
; CHECK: rll [[ROT:%r[0-9]+]], [[OLD]], 0([[SHIFT]])
; CHECK: clr [[ROT]], %r3
; CHECK: j{{g?}}le [[KEEP:\..*]]
; CHECK: risbg [[ROT]], %r3, 32, 39, 0
; CHECK: [[KEEP]]:
; CHECK: rll [[NEW:%r[0-9]+]], [[ROT]], 0({{%r[1-9]+}})
; CHECK: cs [[OLD]], [[NEW]], 0(%r2)
; CHECK: j{{g?}}lh [[LOOP]]
; CHECK: rll %r2, [[OLD]], 8([[SHIFT]])
; CHECK: br %r14
;
; CHECK-SHIFT1: f3:
; CHECK-SHIFT1: sllg [[SHIFT:%r[1-9]+]], %r2, 3
; CHECK-SHIFT1: lcr [[NEGSHIFT:%r[1-9]+]], [[SHIFT]]
; CHECK-SHIFT1: rll
; CHECK-SHIFT1: rll {{%r[0-9]+}}, {{%r[0-9]+}}, 0([[NEGSHIFT]])
; CHECK-SHIFT1: rll
; CHECK-SHIFT1: br %r14
;
; CHECK-SHIFT2: f3:
; CHECK-SHIFT2: sll %r3, 24
; CHECK-SHIFT2: rll
; CHECK-SHIFT2: clr {{%r[0-9]+}}, %r3
; CHECK-SHIFT2: rll
; CHECK-SHIFT2: rll
; CHECK-SHIFT2: br %r14
%res = atomicrmw umin i8 *%src, i8 %b seq_cst
ret i8 %res
}
; Check unsigned maximum.
define i8 @f4(i8 *%src, i8 %b) {
; CHECK: f4:
; CHECK: sllg [[SHIFT:%r[1-9]+]], %r2, 3
; CHECK: nill %r2, 65532
; CHECK: l [[OLD:%r[0-9]+]], 0(%r2)
; CHECK: [[LOOP:\.[^:]*]]:
; CHECK: rll [[ROT:%r[0-9]+]], [[OLD]], 0([[SHIFT]])
; CHECK: clr [[ROT]], %r3
; CHECK: j{{g?}}he [[KEEP:\..*]]
; CHECK: risbg [[ROT]], %r3, 32, 39, 0
; CHECK: [[KEEP]]:
; CHECK: rll [[NEW:%r[0-9]+]], [[ROT]], 0({{%r[1-9]+}})
; CHECK: cs [[OLD]], [[NEW]], 0(%r2)
; CHECK: j{{g?}}lh [[LOOP]]
; CHECK: rll %r2, [[OLD]], 8([[SHIFT]])
; CHECK: br %r14
;
; CHECK-SHIFT1: f4:
; CHECK-SHIFT1: sllg [[SHIFT:%r[1-9]+]], %r2, 3
; CHECK-SHIFT1: lcr [[NEGSHIFT:%r[1-9]+]], [[SHIFT]]
; CHECK-SHIFT1: rll
; CHECK-SHIFT1: rll {{%r[0-9]+}}, {{%r[0-9]+}}, 0([[NEGSHIFT]])
; CHECK-SHIFT1: rll
; CHECK-SHIFT1: br %r14
;
; CHECK-SHIFT2: f4:
; CHECK-SHIFT2: sll %r3, 24
; CHECK-SHIFT2: rll
; CHECK-SHIFT2: clr {{%r[0-9]+}}, %r3
; CHECK-SHIFT2: rll
; CHECK-SHIFT2: rll
; CHECK-SHIFT2: br %r14
%res = atomicrmw umax i8 *%src, i8 %b seq_cst
ret i8 %res
}
; Check the lowest useful signed minimum value. We need to load 0x81000000
; into the source register.
define i8 @f5(i8 *%src) {
; CHECK: f5:
; CHECK: llilh [[SRC2:%r[0-9]+]], 33024
; CHECK: cr [[ROT:%r[0-9]+]], [[SRC2]]
; CHECK: risbg [[ROT]], [[SRC2]], 32, 39, 0
; CHECK: br %r14
;
; CHECK-SHIFT1: f5:
; CHECK-SHIFT1: br %r14
; CHECK-SHIFT2: f5:
; CHECK-SHIFT2: br %r14
%res = atomicrmw min i8 *%src, i8 -127 seq_cst
ret i8 %res
}
; Check the highest useful signed maximum value. We need to load 0x7e000000
; into the source register.
define i8 @f6(i8 *%src) {
; CHECK: f6:
; CHECK: llilh [[SRC2:%r[0-9]+]], 32256
; CHECK: cr [[ROT:%r[0-9]+]], [[SRC2]]
; CHECK: risbg [[ROT]], [[SRC2]], 32, 39, 0
; CHECK: br %r14
;
; CHECK-SHIFT1: f6:
; CHECK-SHIFT1: br %r14
; CHECK-SHIFT2: f6:
; CHECK-SHIFT2: br %r14
%res = atomicrmw max i8 *%src, i8 126 seq_cst
ret i8 %res
}
; Check the lowest useful unsigned minimum value. We need to load 0x01000000
; into the source register.
define i8 @f7(i8 *%src) {
; CHECK: f7:
; CHECK: llilh [[SRC2:%r[0-9]+]], 256
; CHECK: clr [[ROT:%r[0-9]+]], [[SRC2]]
; CHECK: risbg [[ROT]], [[SRC2]], 32, 39, 0
; CHECK: br %r14
;
; CHECK-SHIFT1: f7:
; CHECK-SHIFT1: br %r14
; CHECK-SHIFT2: f7:
; CHECK-SHIFT2: br %r14
%res = atomicrmw umin i8 *%src, i8 1 seq_cst
ret i8 %res
}
; Check the highest useful unsigned maximum value. We need to load 0xfe000000
; into the source register.
define i8 @f8(i8 *%src) {
; CHECK: f8:
; CHECK: llilh [[SRC2:%r[0-9]+]], 65024
; CHECK: clr [[ROT:%r[0-9]+]], [[SRC2]]
; CHECK: risbg [[ROT]], [[SRC2]], 32, 39, 0
; CHECK: br %r14
;
; CHECK-SHIFT1: f8:
; CHECK-SHIFT1: br %r14
; CHECK-SHIFT2: f8:
; CHECK-SHIFT2: br %r14
%res = atomicrmw umax i8 *%src, i8 254 seq_cst
ret i8 %res
}

View File

@ -0,0 +1,228 @@
; Test 8-bit atomic min/max operations.
;
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s -check-prefix=CHECK
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s -check-prefix=CHECK-SHIFT1
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s -check-prefix=CHECK-SHIFT2
; Check signed minimum.
; - CHECK is for the main loop.
; - CHECK-SHIFT1 makes sure that the negated shift count used by the second
; RLL is set up correctly. The negation is independent of the NILL and L
; tested in CHECK.
; - CHECK-SHIFT2 makes sure that %b is shifted into the high part of the word
; before being used, and that the low bits are set to 1. This sequence is
; independent of the other loop prologue instructions.
define i16 @f1(i16 *%src, i16 %b) {
; CHECK: f1:
; CHECK: sllg [[SHIFT:%r[1-9]+]], %r2, 3
; CHECK: nill %r2, 65532
; CHECK: l [[OLD:%r[0-9]+]], 0(%r2)
; CHECK: [[LOOP:\.[^:]*]]:
; CHECK: rll [[ROT:%r[0-9]+]], [[OLD]], 0([[SHIFT]])
; CHECK: cr [[ROT]], %r3
; CHECK: j{{g?}}le [[KEEP:\..*]]
; CHECK: risbg [[ROT]], %r3, 32, 47, 0
; CHECK: [[KEEP]]:
; CHECK: rll [[NEW:%r[0-9]+]], [[ROT]], 0({{%r[1-9]+}})
; CHECK: cs [[OLD]], [[NEW]], 0(%r2)
; CHECK: j{{g?}}lh [[LOOP]]
; CHECK: rll %r2, [[OLD]], 16([[SHIFT]])
; CHECK: br %r14
;
; CHECK-SHIFT1: f1:
; CHECK-SHIFT1: sllg [[SHIFT:%r[1-9]+]], %r2, 3
; CHECK-SHIFT1: lcr [[NEGSHIFT:%r[1-9]+]], [[SHIFT]]
; CHECK-SHIFT1: rll
; CHECK-SHIFT1: rll {{%r[0-9]+}}, {{%r[0-9]+}}, 0([[NEGSHIFT]])
; CHECK-SHIFT1: rll
; CHECK-SHIFT1: br %r14
;
; CHECK-SHIFT2: f1:
; CHECK-SHIFT2: sll %r3, 16
; CHECK-SHIFT2: rll
; CHECK-SHIFT2: cr {{%r[0-9]+}}, %r3
; CHECK-SHIFT2: rll
; CHECK-SHIFT2: rll
; CHECK-SHIFT2: br %r14
%res = atomicrmw min i16 *%src, i16 %b seq_cst
ret i16 %res
}
; Check signed maximum.
define i16 @f2(i16 *%src, i16 %b) {
; CHECK: f2:
; CHECK: sllg [[SHIFT:%r[1-9]+]], %r2, 3
; CHECK: nill %r2, 65532
; CHECK: l [[OLD:%r[0-9]+]], 0(%r2)
; CHECK: [[LOOP:\.[^:]*]]:
; CHECK: rll [[ROT:%r[0-9]+]], [[OLD]], 0([[SHIFT]])
; CHECK: cr [[ROT]], %r3
; CHECK: j{{g?}}he [[KEEP:\..*]]
; CHECK: risbg [[ROT]], %r3, 32, 47, 0
; CHECK: [[KEEP]]:
; CHECK: rll [[NEW:%r[0-9]+]], [[ROT]], 0({{%r[1-9]+}})
; CHECK: cs [[OLD]], [[NEW]], 0(%r2)
; CHECK: j{{g?}}lh [[LOOP]]
; CHECK: rll %r2, [[OLD]], 16([[SHIFT]])
; CHECK: br %r14
;
; CHECK-SHIFT1: f2:
; CHECK-SHIFT1: sllg [[SHIFT:%r[1-9]+]], %r2, 3
; CHECK-SHIFT1: lcr [[NEGSHIFT:%r[1-9]+]], [[SHIFT]]
; CHECK-SHIFT1: rll
; CHECK-SHIFT1: rll {{%r[0-9]+}}, {{%r[0-9]+}}, 0([[NEGSHIFT]])
; CHECK-SHIFT1: rll
; CHECK-SHIFT1: br %r14
;
; CHECK-SHIFT2: f2:
; CHECK-SHIFT2: sll %r3, 16
; CHECK-SHIFT2: rll
; CHECK-SHIFT2: cr {{%r[0-9]+}}, %r3
; CHECK-SHIFT2: rll
; CHECK-SHIFT2: rll
; CHECK-SHIFT2: br %r14
%res = atomicrmw max i16 *%src, i16 %b seq_cst
ret i16 %res
}
; Check unsigned minimum.
define i16 @f3(i16 *%src, i16 %b) {
; CHECK: f3:
; CHECK: sllg [[SHIFT:%r[1-9]+]], %r2, 3
; CHECK: nill %r2, 65532
; CHECK: l [[OLD:%r[0-9]+]], 0(%r2)
; CHECK: [[LOOP:\.[^:]*]]:
; CHECK: rll [[ROT:%r[0-9]+]], [[OLD]], 0([[SHIFT]])
; CHECK: clr [[ROT]], %r3
; CHECK: j{{g?}}le [[KEEP:\..*]]
; CHECK: risbg [[ROT]], %r3, 32, 47, 0
; CHECK: [[KEEP]]:
; CHECK: rll [[NEW:%r[0-9]+]], [[ROT]], 0({{%r[1-9]+}})
; CHECK: cs [[OLD]], [[NEW]], 0(%r2)
; CHECK: j{{g?}}lh [[LOOP]]
; CHECK: rll %r2, [[OLD]], 16([[SHIFT]])
; CHECK: br %r14
;
; CHECK-SHIFT1: f3:
; CHECK-SHIFT1: sllg [[SHIFT:%r[1-9]+]], %r2, 3
; CHECK-SHIFT1: lcr [[NEGSHIFT:%r[1-9]+]], [[SHIFT]]
; CHECK-SHIFT1: rll
; CHECK-SHIFT1: rll {{%r[0-9]+}}, {{%r[0-9]+}}, 0([[NEGSHIFT]])
; CHECK-SHIFT1: rll
; CHECK-SHIFT1: br %r14
;
; CHECK-SHIFT2: f3:
; CHECK-SHIFT2: sll %r3, 16
; CHECK-SHIFT2: rll
; CHECK-SHIFT2: clr {{%r[0-9]+}}, %r3
; CHECK-SHIFT2: rll
; CHECK-SHIFT2: rll
; CHECK-SHIFT2: br %r14
%res = atomicrmw umin i16 *%src, i16 %b seq_cst
ret i16 %res
}
; Check unsigned maximum.
define i16 @f4(i16 *%src, i16 %b) {
; CHECK: f4:
; CHECK: sllg [[SHIFT:%r[1-9]+]], %r2, 3
; CHECK: nill %r2, 65532
; CHECK: l [[OLD:%r[0-9]+]], 0(%r2)
; CHECK: [[LOOP:\.[^:]*]]:
; CHECK: rll [[ROT:%r[0-9]+]], [[OLD]], 0([[SHIFT]])
; CHECK: clr [[ROT]], %r3
; CHECK: j{{g?}}he [[KEEP:\..*]]
; CHECK: risbg [[ROT]], %r3, 32, 47, 0
; CHECK: [[KEEP]]:
; CHECK: rll [[NEW:%r[0-9]+]], [[ROT]], 0({{%r[1-9]+}})
; CHECK: cs [[OLD]], [[NEW]], 0(%r2)
; CHECK: j{{g?}}lh [[LOOP]]
; CHECK: rll %r2, [[OLD]], 16([[SHIFT]])
; CHECK: br %r14
;
; CHECK-SHIFT1: f4:
; CHECK-SHIFT1: sllg [[SHIFT:%r[1-9]+]], %r2, 3
; CHECK-SHIFT1: lcr [[NEGSHIFT:%r[1-9]+]], [[SHIFT]]
; CHECK-SHIFT1: rll
; CHECK-SHIFT1: rll {{%r[0-9]+}}, {{%r[0-9]+}}, 0([[NEGSHIFT]])
; CHECK-SHIFT1: rll
; CHECK-SHIFT1: br %r14
;
; CHECK-SHIFT2: f4:
; CHECK-SHIFT2: sll %r3, 16
; CHECK-SHIFT2: rll
; CHECK-SHIFT2: clr {{%r[0-9]+}}, %r3
; CHECK-SHIFT2: rll
; CHECK-SHIFT2: rll
; CHECK-SHIFT2: br %r14
%res = atomicrmw umax i16 *%src, i16 %b seq_cst
ret i16 %res
}
; Check the lowest useful signed minimum value. We need to load 0x80010000
; into the source register.
define i16 @f5(i16 *%src) {
; CHECK: f5:
; CHECK: llilh [[SRC2:%r[0-9]+]], 32769
; CHECK: cr [[ROT:%r[0-9]+]], [[SRC2]]
; CHECK: risbg [[ROT]], [[SRC2]], 32, 47, 0
; CHECK: br %r14
;
; CHECK-SHIFT1: f5:
; CHECK-SHIFT1: br %r14
; CHECK-SHIFT2: f5:
; CHECK-SHIFT2: br %r14
%res = atomicrmw min i16 *%src, i16 -32767 seq_cst
ret i16 %res
}
; Check the highest useful signed maximum value. We need to load 0x7ffe0000
; into the source register.
define i16 @f6(i16 *%src) {
; CHECK: f6:
; CHECK: llilh [[SRC2:%r[0-9]+]], 32766
; CHECK: cr [[ROT:%r[0-9]+]], [[SRC2]]
; CHECK: risbg [[ROT]], [[SRC2]], 32, 47, 0
; CHECK: br %r14
;
; CHECK-SHIFT1: f6:
; CHECK-SHIFT1: br %r14
; CHECK-SHIFT2: f6:
; CHECK-SHIFT2: br %r14
%res = atomicrmw max i16 *%src, i16 32766 seq_cst
ret i16 %res
}
; Check the lowest useful unsigned maximum value. We need to load 0x00010000
; into the source register.
define i16 @f7(i16 *%src) {
; CHECK: f7:
; CHECK: llilh [[SRC2:%r[0-9]+]], 1
; CHECK: clr [[ROT:%r[0-9]+]], [[SRC2]]
; CHECK: risbg [[ROT]], [[SRC2]], 32, 47, 0
; CHECK: br %r14
;
; CHECK-SHIFT1: f7:
; CHECK-SHIFT1: br %r14
; CHECK-SHIFT2: f7:
; CHECK-SHIFT2: br %r14
%res = atomicrmw umin i16 *%src, i16 1 seq_cst
ret i16 %res
}
; Check the highest useful unsigned maximum value. We need to load 0xfffe0000
; into the source register.
define i16 @f8(i16 *%src) {
; CHECK: f8:
; CHECK: llilh [[SRC2:%r[0-9]+]], 65534
; CHECK: clr [[ROT:%r[0-9]+]], [[SRC2]]
; CHECK: risbg [[ROT]], [[SRC2]], 32, 47, 0
; CHECK: br %r14
;
; CHECK-SHIFT1: f8:
; CHECK-SHIFT1: br %r14
; CHECK-SHIFT2: f8:
; CHECK-SHIFT2: br %r14
%res = atomicrmw umax i16 *%src, i16 65534 seq_cst
ret i16 %res
}

View File

@ -0,0 +1,176 @@
; Test 32-bit atomic minimum and maximum.
;
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s
; Check signed minium.
define i32 @f1(i32 %dummy, i32 *%src, i32 %b) {
; CHECK: f1:
; CHECK: l %r2, 0(%r3)
; CHECK: [[LOOP:\.[^:]*]]:
; CHECK: cr %r2, %r4
; CHECK: lr [[NEW:%r[0-9]+]], %r2
; CHECK: j{{g?}}le [[KEEP:\..*]]
; CHECK: lr [[NEW]], %r4
; CHECK: cs %r2, [[NEW]], 0(%r3)
; CHECK: j{{g?}}lh [[LOOP]]
; CHECK: br %r14
%res = atomicrmw min i32 *%src, i32 %b seq_cst
ret i32 %res
}
; Check signed maximum.
define i32 @f2(i32 %dummy, i32 *%src, i32 %b) {
; CHECK: f2:
; CHECK: l %r2, 0(%r3)
; CHECK: [[LOOP:\.[^:]*]]:
; CHECK: cr %r2, %r4
; CHECK: lr [[NEW:%r[0-9]+]], %r2
; CHECK: j{{g?}}he [[KEEP:\..*]]
; CHECK: lr [[NEW]], %r4
; CHECK: cs %r2, [[NEW]], 0(%r3)
; CHECK: j{{g?}}lh [[LOOP]]
; CHECK: br %r14
%res = atomicrmw max i32 *%src, i32 %b seq_cst
ret i32 %res
}
; Check unsigned minimum.
define i32 @f3(i32 %dummy, i32 *%src, i32 %b) {
; CHECK: f3:
; CHECK: l %r2, 0(%r3)
; CHECK: [[LOOP:\.[^:]*]]:
; CHECK: clr %r2, %r4
; CHECK: lr [[NEW:%r[0-9]+]], %r2
; CHECK: j{{g?}}le [[KEEP:\..*]]
; CHECK: lr [[NEW]], %r4
; CHECK: cs %r2, [[NEW]], 0(%r3)
; CHECK: j{{g?}}lh [[LOOP]]
; CHECK: br %r14
%res = atomicrmw umin i32 *%src, i32 %b seq_cst
ret i32 %res
}
; Check unsigned maximum.
define i32 @f4(i32 %dummy, i32 *%src, i32 %b) {
; CHECK: f4:
; CHECK: l %r2, 0(%r3)
; CHECK: [[LOOP:\.[^:]*]]:
; CHECK: clr %r2, %r4
; CHECK: lr [[NEW:%r[0-9]+]], %r2
; CHECK: j{{g?}}he [[KEEP:\..*]]
; CHECK: lr [[NEW]], %r4
; CHECK: cs %r2, [[NEW]], 0(%r3)
; CHECK: j{{g?}}lh [[LOOP]]
; CHECK: br %r14
%res = atomicrmw umax i32 *%src, i32 %b seq_cst
ret i32 %res
}
; Check the high end of the aligned CS range.
define i32 @f5(i32 %dummy, i32 *%src, i32 %b) {
; CHECK: f5:
; CHECK: l %r2, 4092(%r3)
; CHECK: cs %r2, {{%r[0-9]+}}, 4092(%r3)
; CHECK: br %r14
%ptr = getelementptr i32 *%src, i64 1023
%res = atomicrmw min i32 *%ptr, i32 %b seq_cst
ret i32 %res
}
; Check the next word up, which requires CSY.
define i32 @f6(i32 %dummy, i32 *%src, i32 %b) {
; CHECK: f6:
; CHECK: ly %r2, 4096(%r3)
; CHECK: csy %r2, {{%r[0-9]+}}, 4096(%r3)
; CHECK: br %r14
%ptr = getelementptr i32 *%src, i64 1024
%res = atomicrmw min i32 *%ptr, i32 %b seq_cst
ret i32 %res
}
; Check the high end of the aligned CSY range.
define i32 @f7(i32 %dummy, i32 *%src, i32 %b) {
; CHECK: f7:
; CHECK: ly %r2, 524284(%r3)
; CHECK: csy %r2, {{%r[0-9]+}}, 524284(%r3)
; CHECK: br %r14
%ptr = getelementptr i32 *%src, i64 131071
%res = atomicrmw min i32 *%ptr, i32 %b seq_cst
ret i32 %res
}
; Check the next word up, which needs separate address logic.
define i32 @f8(i32 %dummy, i32 *%src, i32 %b) {
; CHECK: f8:
; CHECK: agfi %r3, 524288
; CHECK: l %r2, 0(%r3)
; CHECK: cs %r2, {{%r[0-9]+}}, 0(%r3)
; CHECK: br %r14
%ptr = getelementptr i32 *%src, i64 131072
%res = atomicrmw min i32 *%ptr, i32 %b seq_cst
ret i32 %res
}
; Check the high end of the negative aligned CSY range.
define i32 @f9(i32 %dummy, i32 *%src, i32 %b) {
; CHECK: f9:
; CHECK: ly %r2, -4(%r3)
; CHECK: csy %r2, {{%r[0-9]+}}, -4(%r3)
; CHECK: br %r14
%ptr = getelementptr i32 *%src, i64 -1
%res = atomicrmw min i32 *%ptr, i32 %b seq_cst
ret i32 %res
}
; Check the low end of the CSY range.
define i32 @f10(i32 %dummy, i32 *%src, i32 %b) {
; CHECK: f10:
; CHECK: ly %r2, -524288(%r3)
; CHECK: csy %r2, {{%r[0-9]+}}, -524288(%r3)
; CHECK: br %r14
%ptr = getelementptr i32 *%src, i64 -131072
%res = atomicrmw min i32 *%ptr, i32 %b seq_cst
ret i32 %res
}
; Check the next word down, which needs separate address logic.
define i32 @f11(i32 %dummy, i32 *%src, i32 %b) {
; CHECK: f11:
; CHECK: agfi %r3, -524292
; CHECK: l %r2, 0(%r3)
; CHECK: cs %r2, {{%r[0-9]+}}, 0(%r3)
; CHECK: br %r14
%ptr = getelementptr i32 *%src, i64 -131073
%res = atomicrmw min i32 *%ptr, i32 %b seq_cst
ret i32 %res
}
; Check that indexed addresses are not allowed.
define i32 @f12(i32 %dummy, i64 %base, i64 %index, i32 %b) {
; CHECK: f12:
; CHECK: agr %r3, %r4
; CHECK: l %r2, 0(%r3)
; CHECK: cs %r2, {{%r[0-9]+}}, 0(%r3)
; CHECK: br %r14
%add = add i64 %base, %index
%ptr = inttoptr i64 %add to i32 *
%res = atomicrmw min i32 *%ptr, i32 %b seq_cst
ret i32 %res
}
; Check that constants are forced into a register.
define i32 @f13(i32 %dummy, i32 *%ptr) {
; CHECK: f13:
; CHECK: lhi [[LIMIT:%r[0-9]+]], 42
; CHECK: l %r2, 0(%r3)
; CHECK: [[LOOP:\.[^:]*]]:
; CHECK: cr %r2, [[LIMIT]]
; CHECK: lr [[NEW:%r[0-9]+]], %r2
; CHECK: j{{g?}}le [[KEEP:\..*]]
; CHECK: lr [[NEW]], [[LIMIT]]
; CHECK: cs %r2, [[NEW]], 0(%r3)
; CHECK: j{{g?}}lh [[LOOP]]
; CHECK: br %r14
%res = atomicrmw min i32 *%ptr, i32 42 seq_cst
ret i32 %res
}

View File

@ -0,0 +1,143 @@
; Test 64-bit atomic minimum and maximum.
;
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s
; Check signed minium.
define i64 @f1(i64 %dummy, i64 *%src, i64 %b) {
; CHECK: f1:
; CHECK: lg %r2, 0(%r3)
; CHECK: [[LOOP:\.[^:]*]]:
; CHECK: cgr %r2, %r4
; CHECK: lgr [[NEW:%r[0-9]+]], %r2
; CHECK: j{{g?}}le [[KEEP:\..*]]
; CHECK: lgr [[NEW]], %r4
; CHECK: csg %r2, [[NEW]], 0(%r3)
; CHECK: j{{g?}}lh [[LOOP]]
; CHECK: br %r14
%res = atomicrmw min i64 *%src, i64 %b seq_cst
ret i64 %res
}
; Check signed maximum.
define i64 @f2(i64 %dummy, i64 *%src, i64 %b) {
; CHECK: f2:
; CHECK: lg %r2, 0(%r3)
; CHECK: [[LOOP:\.[^:]*]]:
; CHECK: cgr %r2, %r4
; CHECK: lgr [[NEW:%r[0-9]+]], %r2
; CHECK: j{{g?}}he [[KEEP:\..*]]
; CHECK: lgr [[NEW]], %r4
; CHECK: csg %r2, [[NEW]], 0(%r3)
; CHECK: j{{g?}}lh [[LOOP]]
; CHECK: br %r14
%res = atomicrmw max i64 *%src, i64 %b seq_cst
ret i64 %res
}
; Check unsigned minimum.
define i64 @f3(i64 %dummy, i64 *%src, i64 %b) {
; CHECK: f3:
; CHECK: lg %r2, 0(%r3)
; CHECK: [[LOOP:\.[^:]*]]:
; CHECK: clgr %r2, %r4
; CHECK: lgr [[NEW:%r[0-9]+]], %r2
; CHECK: j{{g?}}le [[KEEP:\..*]]
; CHECK: lgr [[NEW]], %r4
; CHECK: csg %r2, [[NEW]], 0(%r3)
; CHECK: j{{g?}}lh [[LOOP]]
; CHECK: br %r14
%res = atomicrmw umin i64 *%src, i64 %b seq_cst
ret i64 %res
}
; Check unsigned maximum.
define i64 @f4(i64 %dummy, i64 *%src, i64 %b) {
; CHECK: f4:
; CHECK: lg %r2, 0(%r3)
; CHECK: [[LOOP:\.[^:]*]]:
; CHECK: clgr %r2, %r4
; CHECK: lgr [[NEW:%r[0-9]+]], %r2
; CHECK: j{{g?}}he [[KEEP:\..*]]
; CHECK: lgr [[NEW]], %r4
; CHECK: csg %r2, [[NEW]], 0(%r3)
; CHECK: j{{g?}}lh [[LOOP]]
; CHECK: br %r14
%res = atomicrmw umax i64 *%src, i64 %b seq_cst
ret i64 %res
}
; Check the high end of the aligned CSG range.
define i64 @f5(i64 %dummy, i64 *%src, i64 %b) {
; CHECK: f5:
; CHECK: lg %r2, 524280(%r3)
; CHECK: csg %r2, {{%r[0-9]+}}, 524280(%r3)
; CHECK: br %r14
%ptr = getelementptr i64 *%src, i64 65535
%res = atomicrmw min i64 *%ptr, i64 %b seq_cst
ret i64 %res
}
; Check the next doubleword up, which requires separate address logic.
define i64 @f6(i64 %dummy, i64 *%src, i64 %b) {
; CHECK: f6:
; CHECK: agfi %r3, 524288
; CHECK: lg %r2, 0(%r3)
; CHECK: csg %r2, {{%r[0-9]+}}, 0(%r3)
; CHECK: br %r14
%ptr = getelementptr i64 *%src, i64 65536
%res = atomicrmw min i64 *%ptr, i64 %b seq_cst
ret i64 %res
}
; Check the low end of the CSG range.
define i64 @f7(i64 %dummy, i64 *%src, i64 %b) {
; CHECK: f7:
; CHECK: lg %r2, -524288(%r3)
; CHECK: csg %r2, {{%r[0-9]+}}, -524288(%r3)
; CHECK: br %r14
%ptr = getelementptr i64 *%src, i64 -65536
%res = atomicrmw min i64 *%ptr, i64 %b seq_cst
ret i64 %res
}
; Check the next doubleword down, which requires separate address logic.
define i64 @f8(i64 %dummy, i64 *%src, i64 %b) {
; CHECK: f8:
; CHECK: agfi %r3, -524296
; CHECK: lg %r2, 0(%r3)
; CHECK: csg %r2, {{%r[0-9]+}}, 0(%r3)
; CHECK: br %r14
%ptr = getelementptr i64 *%src, i64 -65537
%res = atomicrmw min i64 *%ptr, i64 %b seq_cst
ret i64 %res
}
; Check that indexed addresses are not allowed.
define i64 @f9(i64 %dummy, i64 %base, i64 %index, i64 %b) {
; CHECK: f9:
; CHECK: agr %r3, %r4
; CHECK: lg %r2, 0(%r3)
; CHECK: csg %r2, {{%r[0-9]+}}, 0(%r3)
; CHECK: br %r14
%add = add i64 %base, %index
%ptr = inttoptr i64 %add to i64 *
%res = atomicrmw min i64 *%ptr, i64 %b seq_cst
ret i64 %res
}
; Check that constants are forced into a register.
define i64 @f10(i64 %dummy, i64 *%ptr) {
; CHECK: f10:
; CHECK: lghi [[LIMIT:%r[0-9]+]], 42
; CHECK: lg %r2, 0(%r3)
; CHECK: [[LOOP:\.[^:]*]]:
; CHECK: cgr %r2, [[LIMIT]]
; CHECK: lgr [[NEW:%r[0-9]+]], %r2
; CHECK: j{{g?}}le [[KEEP:\..*]]
; CHECK: lgr [[NEW]], [[LIMIT]]
; CHECK: csg %r2, [[NEW]], 0(%r3)
; CHECK: j{{g?}}lh [[LOOP]]
; CHECK: br %r14
%res = atomicrmw min i64 *%ptr, i64 42 seq_cst
ret i64 %res
}

View File

@ -0,0 +1,139 @@
; Test 8-bit atomic NANDs.
;
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s -check-prefix=CHECK
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s -check-prefix=CHECK-SHIFT1
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s -check-prefix=CHECK-SHIFT2
; Check NAND of a variable.
; - CHECK is for the main loop.
; - CHECK-SHIFT1 makes sure that the negated shift count used by the second
; RLL is set up correctly. The negation is independent of the NILL and L
; tested in CHECK.
; - CHECK-SHIFT2 makes sure that %b is shifted into the high part of the word
; before being used, and that the low bits are set to 1. This sequence is
; independent of the other loop prologue instructions.
define i8 @f1(i8 *%src, i8 %b) {
; CHECK: f1:
; CHECK: sllg [[SHIFT:%r[1-9]+]], %r2, 3
; CHECK: nill %r2, 65532
; CHECK: l [[OLD:%r[0-9]+]], 0(%r2)
; CHECK: [[LABEL:\.[^:]*]]:
; CHECK: rll [[ROT:%r[0-9]+]], [[OLD]], 0([[SHIFT]])
; CHECK: nr [[ROT]], %r3
; CHECK: xilf [[ROT]], 4278190080
; CHECK: rll [[NEW:%r[0-9]+]], [[ROT]], 0({{%r[1-9]+}})
; CHECK: cs [[OLD]], [[NEW]], 0(%r2)
; CHECK: j{{g?}}lh [[LABEL]]
; CHECK: rll %r2, [[OLD]], 8([[SHIFT]])
; CHECK: br %r14
;
; CHECK-SHIFT1: f1:
; CHECK-SHIFT1: sllg [[SHIFT:%r[1-9]+]], %r2, 3
; CHECK-SHIFT1: lcr [[NEGSHIFT:%r[1-9]+]], [[SHIFT]]
; CHECK-SHIFT1: rll
; CHECK-SHIFT1: rll {{%r[0-9]+}}, {{%r[0-9]+}}, 0([[NEGSHIFT]])
; CHECK-SHIFT1: rll
; CHECK-SHIFT1: br %r14
;
; CHECK-SHIFT2: f1:
; CHECK-SHIFT2: sll %r3, 24
; CHECK-SHIFT2: oilf %r3, 16777215
; CHECK-SHIFT2: rll
; CHECK-SHIFT2: nr {{%r[0-9]+}}, %r3
; CHECK-SHIFT2: rll
; CHECK-SHIFT2: rll
; CHECK-SHIFT2: br %r14
%res = atomicrmw nand i8 *%src, i8 %b seq_cst
ret i8 %res
}
; Check the minimum signed value. We AND the rotated word with 0x80ffffff.
define i8 @f2(i8 *%src) {
; CHECK: f2:
; CHECK: sllg [[SHIFT:%r[1-9]+]], %r2, 3
; CHECK: nill %r2, 65532
; CHECK: l [[OLD:%r[0-9]+]], 0(%r2)
; CHECK: [[LABEL:\.[^:]*]]:
; CHECK: rll [[ROT:%r[0-9]+]], [[OLD]], 0([[SHIFT]])
; CHECK: nilh [[ROT]], 33023
; CHECK: xilf [[ROT]], 4278190080
; CHECK: rll [[NEW:%r[0-9]+]], [[ROT]], 0([[NEGSHIFT:%r[1-9]+]])
; CHECK: cs [[OLD]], [[NEW]], 0(%r2)
; CHECK: j{{g?}}lh [[LABEL]]
; CHECK: rll %r2, [[OLD]], 8([[SHIFT]])
; CHECK: br %r14
;
; CHECK-SHIFT1: f2:
; CHECK-SHIFT1: sllg [[SHIFT:%r[1-9]+]], %r2, 3
; CHECK-SHIFT1: lcr [[NEGSHIFT:%r[1-9]+]], [[SHIFT]]
; CHECK-SHIFT1: rll
; CHECK-SHIFT1: rll {{%r[0-9]+}}, {{%r[0-9]+}}, 0([[NEGSHIFT]])
; CHECK-SHIFT1: rll
; CHECK-SHIFT1: br %r14
;
; CHECK-SHIFT2: f2:
; CHECK-SHIFT2: br %r14
%res = atomicrmw nand i8 *%src, i8 -128 seq_cst
ret i8 %res
}
; Check NANDs of -2 (-1 isn't useful). We AND the rotated word with 0xfeffffff.
define i8 @f3(i8 *%src) {
; CHECK: f3:
; CHECK: nilh [[ROT]], 65279
; CHECK: xilf [[ROT]], 4278190080
; CHECK: br %r14
;
; CHECK-SHIFT1: f3:
; CHECK-SHIFT1: br %r14
; CHECK-SHIFT2: f3:
; CHECK-SHIFT2: br %r14
%res = atomicrmw nand i8 *%src, i8 -2 seq_cst
ret i8 %res
}
; Check NANDs of 1. We AND the rotated word with 0x01ffffff.
define i8 @f4(i8 *%src) {
; CHECK: f4:
; CHECK: nilh [[ROT]], 511
; CHECK: xilf [[ROT]], 4278190080
; CHECK: br %r14
;
; CHECK-SHIFT1: f4:
; CHECK-SHIFT1: br %r14
; CHECK-SHIFT2: f4:
; CHECK-SHIFT2: br %r14
%res = atomicrmw nand i8 *%src, i8 1 seq_cst
ret i8 %res
}
; Check the maximum signed value. We AND the rotated word with 0x7fffffff.
define i8 @f5(i8 *%src) {
; CHECK: f5:
; CHECK: nilh [[ROT]], 32767
; CHECK: xilf [[ROT]], 4278190080
; CHECK: br %r14
;
; CHECK-SHIFT1: f5:
; CHECK-SHIFT1: br %r14
; CHECK-SHIFT2: f5:
; CHECK-SHIFT2: br %r14
%res = atomicrmw nand i8 *%src, i8 127 seq_cst
ret i8 %res
}
; Check NANDs of a large unsigned value. We AND the rotated word with
; 0xfdffffff.
define i8 @f6(i8 *%src) {
; CHECK: f6:
; CHECK: nilh [[ROT]], 65023
; CHECK: xilf [[ROT]], 4278190080
; CHECK: br %r14
;
; CHECK-SHIFT1: f6:
; CHECK-SHIFT1: br %r14
; CHECK-SHIFT2: f6:
; CHECK-SHIFT2: br %r14
%res = atomicrmw nand i8 *%src, i8 253 seq_cst
ret i8 %res
}

View File

@ -0,0 +1,139 @@
; Test 16-bit atomic NANDs.
;
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s -check-prefix=CHECK
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s -check-prefix=CHECK-SHIFT1
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s -check-prefix=CHECK-SHIFT2
; Check NAND of a variable.
; - CHECK is for the main loop.
; - CHECK-SHIFT1 makes sure that the negated shift count used by the second
; RLL is set up correctly. The negation is independent of the NILL and L
; tested in CHECK.
; - CHECK-SHIFT2 makes sure that %b is shifted into the high part of the word
; before being used, and that the low bits are set to 1. This sequence is
; independent of the other loop prologue instructions.
define i16 @f1(i16 *%src, i16 %b) {
; CHECK: f1:
; CHECK: sllg [[SHIFT:%r[1-9]+]], %r2, 3
; CHECK: nill %r2, 65532
; CHECK: l [[OLD:%r[0-9]+]], 0(%r2)
; CHECK: [[LABEL:\.[^:]*]]:
; CHECK: rll [[ROT:%r[0-9]+]], [[OLD]], 0([[SHIFT]])
; CHECK: nr [[ROT]], %r3
; CHECK: xilf [[ROT]], 4294901760
; CHECK: rll [[NEW:%r[0-9]+]], [[ROT]], 0({{%r[1-9]+}})
; CHECK: cs [[OLD]], [[NEW]], 0(%r2)
; CHECK: j{{g?}}lh [[LABEL]]
; CHECK: rll %r2, [[OLD]], 16([[SHIFT]])
; CHECK: br %r14
;
; CHECK-SHIFT1: f1:
; CHECK-SHIFT1: sllg [[SHIFT:%r[1-9]+]], %r2, 3
; CHECK-SHIFT1: lcr [[NEGSHIFT:%r[1-9]+]], [[SHIFT]]
; CHECK-SHIFT1: rll
; CHECK-SHIFT1: rll {{%r[0-9]+}}, {{%r[0-9]+}}, 0([[NEGSHIFT]])
; CHECK-SHIFT1: rll
; CHECK-SHIFT1: br %r14
;
; CHECK-SHIFT2: f1:
; CHECK-SHIFT2: sll %r3, 16
; CHECK-SHIFT2: oill %r3, 65535
; CHECK-SHIFT2: rll
; CHECK-SHIFT2: nr {{%r[0-9]+}}, %r3
; CHECK-SHIFT2: rll
; CHECK-SHIFT2: rll
; CHECK-SHIFT2: br %r14
%res = atomicrmw nand i16 *%src, i16 %b seq_cst
ret i16 %res
}
; Check the minimum signed value. We AND the rotated word with 0x8000ffff.
define i16 @f2(i16 *%src) {
; CHECK: f2:
; CHECK: sllg [[SHIFT:%r[1-9]+]], %r2, 3
; CHECK: nill %r2, 65532
; CHECK: l [[OLD:%r[0-9]+]], 0(%r2)
; CHECK: [[LABEL:\.[^:]*]]:
; CHECK: rll [[ROT:%r[0-9]+]], [[OLD]], 0([[SHIFT]])
; CHECK: nilh [[ROT]], 32768
; CHECK: xilf [[ROT]], 4294901760
; CHECK: rll [[NEW:%r[0-9]+]], [[ROT]], 0([[NEGSHIFT:%r[1-9]+]])
; CHECK: cs [[OLD]], [[NEW]], 0(%r2)
; CHECK: j{{g?}}lh [[LABEL]]
; CHECK: rll %r2, [[OLD]], 16([[SHIFT]])
; CHECK: br %r14
;
; CHECK-SHIFT1: f2:
; CHECK-SHIFT1: sllg [[SHIFT:%r[1-9]+]], %r2, 3
; CHECK-SHIFT1: lcr [[NEGSHIFT:%r[1-9]+]], [[SHIFT]]
; CHECK-SHIFT1: rll
; CHECK-SHIFT1: rll {{%r[0-9]+}}, {{%r[0-9]+}}, 0([[NEGSHIFT]])
; CHECK-SHIFT1: rll
; CHECK-SHIFT1: br %r14
;
; CHECK-SHIFT2: f2:
; CHECK-SHIFT2: br %r14
%res = atomicrmw nand i16 *%src, i16 -32768 seq_cst
ret i16 %res
}
; Check NANDs of -2 (-1 isn't useful). We AND the rotated word with 0xfffeffff.
define i16 @f3(i16 *%src) {
; CHECK: f3:
; CHECK: nilh [[ROT]], 65534
; CHECK: xilf [[ROT]], 4294901760
; CHECK: br %r14
;
; CHECK-SHIFT1: f3:
; CHECK-SHIFT1: br %r14
; CHECK-SHIFT2: f3:
; CHECK-SHIFT2: br %r14
%res = atomicrmw nand i16 *%src, i16 -2 seq_cst
ret i16 %res
}
; Check ANDs of 1. We AND the rotated word with 0x0001ffff.
define i16 @f4(i16 *%src) {
; CHECK: f4:
; CHECK: nilh [[ROT]], 1
; CHECK: xilf [[ROT]], 4294901760
; CHECK: br %r14
;
; CHECK-SHIFT1: f4:
; CHECK-SHIFT1: br %r14
; CHECK-SHIFT2: f4:
; CHECK-SHIFT2: br %r14
%res = atomicrmw nand i16 *%src, i16 1 seq_cst
ret i16 %res
}
; Check the maximum signed value. We AND the rotated word with 0x7fffffff.
define i16 @f5(i16 *%src) {
; CHECK: f5:
; CHECK: nilh [[ROT]], 32767
; CHECK: xilf [[ROT]], 4294901760
; CHECK: br %r14
;
; CHECK-SHIFT1: f5:
; CHECK-SHIFT1: br %r14
; CHECK-SHIFT2: f5:
; CHECK-SHIFT2: br %r14
%res = atomicrmw nand i16 *%src, i16 32767 seq_cst
ret i16 %res
}
; Check NANDs of a large unsigned value. We AND the rotated word with
; 0xfffdffff.
define i16 @f6(i16 *%src) {
; CHECK: f6:
; CHECK: nilh [[ROT]], 65533
; CHECK: xilf [[ROT]], 4294901760
; CHECK: br %r14
;
; CHECK-SHIFT1: f6:
; CHECK-SHIFT1: br %r14
; CHECK-SHIFT2: f6:
; CHECK-SHIFT2: br %r14
%res = atomicrmw nand i16 *%src, i16 65533 seq_cst
ret i16 %res
}

View File

@ -0,0 +1,93 @@
; Test 32-bit atomic NANDs.
;
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s
; Check NANDs of a variable.
define i32 @f1(i32 %dummy, i32 *%src, i32 %b) {
; CHECK: f1:
; CHECK: l %r2, 0(%r3)
; CHECK: [[LABEL:\.[^ ]*]]:
; CHECK: lr %r0, %r2
; CHECK: nr %r0, %r4
; CHECK: xilf %r0, 4294967295
; CHECK: cs %r2, %r0, 0(%r3)
; CHECK: j{{g?}}lh [[LABEL]]
; CHECK: br %r14
%res = atomicrmw nand i32 *%src, i32 %b seq_cst
ret i32 %res
}
; Check NANDs of 1.
define i32 @f2(i32 %dummy, i32 *%src) {
; CHECK: f2:
; CHECK: l %r2, 0(%r3)
; CHECK: [[LABEL:\.[^ ]*]]:
; CHECK: lr %r0, %r2
; CHECK: nilf %r0, 1
; CHECK: xilf %r0, 4294967295
; CHECK: cs %r2, %r0, 0(%r3)
; CHECK: j{{g?}}lh [[LABEL]]
; CHECK: br %r14
%res = atomicrmw nand i32 *%src, i32 1 seq_cst
ret i32 %res
}
; Check NANDs of the low end of the NILH range.
define i32 @f3(i32 %dummy, i32 *%src) {
; CHECK: f3:
; CHECK: nilh %r0, 0
; CHECK: xilf %r0, 4294967295
; CHECK: br %r14
%res = atomicrmw nand i32 *%src, i32 65535 seq_cst
ret i32 %res
}
; Check the next value up, which must use NILF.
define i32 @f4(i32 %dummy, i32 *%src) {
; CHECK: f4:
; CHECK: nilf %r0, 65536
; CHECK: xilf %r0, 4294967295
; CHECK: br %r14
%res = atomicrmw nand i32 *%src, i32 65536 seq_cst
ret i32 %res
}
; Check the largest useful NILL value.
define i32 @f5(i32 %dummy, i32 *%src) {
; CHECK: f5:
; CHECK: nill %r0, 65534
; CHECK: xilf %r0, 4294967295
; CHECK: br %r14
%res = atomicrmw nand i32 *%src, i32 -2 seq_cst
ret i32 %res
}
; Check the low end of the NILL range.
define i32 @f6(i32 %dummy, i32 *%src) {
; CHECK: f6:
; CHECK: nill %r0, 0
; CHECK: xilf %r0, 4294967295
; CHECK: br %r14
%res = atomicrmw nand i32 *%src, i32 -65536 seq_cst
ret i32 %res
}
; Check the largest useful NILH value, which is one less than the above.
define i32 @f7(i32 %dummy, i32 *%src) {
; CHECK: f7:
; CHECK: nilh %r0, 65534
; CHECK: xilf %r0, 4294967295
; CHECK: br %r14
%res = atomicrmw nand i32 *%src, i32 -65537 seq_cst
ret i32 %res
}
; Check the highest useful NILF value, which is one less than the above.
define i32 @f8(i32 %dummy, i32 *%src) {
; CHECK: f8:
; CHECK: nilf %r0, 4294901758
; CHECK: xilf %r0, 4294967295
; CHECK: br %r14
%res = atomicrmw nand i32 *%src, i32 -65538 seq_cst
ret i32 %res
}

View File

@ -0,0 +1,183 @@
; Test 64-bit atomic NANDs.
;
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s
; Check NANDs of a variable.
define i64 @f1(i64 %dummy, i64 *%src, i64 %b) {
; CHECK: f1:
; CHECK: lg %r2, 0(%r3)
; CHECK: [[LABEL:\.[^:]*]]:
; CHECK: lgr %r0, %r2
; CHECK: ngr %r0, %r4
; CHECK: lcgr %r0, %r0
; CHECK: aghi %r0, -1
; CHECK: csg %r2, %r0, 0(%r3)
; CHECK: j{{g?}}lh [[LABEL]]
; CHECK: br %r14
%res = atomicrmw nand i64 *%src, i64 %b seq_cst
ret i64 %res
}
; Check NANDs of 1, which must be done using a register.
define i64 @f2(i64 %dummy, i64 *%src) {
; CHECK: f2:
; CHECK: ngr
; CHECK: br %r14
%res = atomicrmw nand i64 *%src, i64 1 seq_cst
ret i64 %res
}
; Check the low end of the NIHF range.
define i64 @f3(i64 %dummy, i64 *%src) {
; CHECK: f3:
; CHECK: lg %r2, 0(%r3)
; CHECK: [[LABEL:\.[^:]*]]:
; CHECK: lgr %r0, %r2
; CHECK: nihf %r0, 0
; CHECK: lcgr %r0, %r0
; CHECK: aghi %r0, -1
; CHECK: csg %r2, %r0, 0(%r3)
; CHECK: j{{g?}}lh [[LABEL]]
; CHECK: br %r14
%res = atomicrmw nand i64 *%src, i64 4294967295 seq_cst
ret i64 %res
}
; Check the next value up, which must use a register.
define i64 @f4(i64 %dummy, i64 *%src) {
; CHECK: f4:
; CHECK: ngr
; CHECK: br %r14
%res = atomicrmw nand i64 *%src, i64 4294967296 seq_cst
ret i64 %res
}
; Check the low end of the NIHH range.
define i64 @f5(i64 %dummy, i64 *%src) {
; CHECK: f5:
; CHECK: nihh %r0, 0
; CHECK: lcgr %r0, %r0
; CHECK: aghi %r0, -1
; CHECK: br %r14
%res = atomicrmw nand i64 *%src, i64 281474976710655 seq_cst
ret i64 %res
}
; Check the next value up, which must use a register.
define i64 @f6(i64 %dummy, i64 *%src) {
; CHECK: f6:
; CHECK: ngr
; CHECK: br %r14
%res = atomicrmw nand i64 *%src, i64 281474976710656 seq_cst
ret i64 %res
}
; Check the highest useful NILL value.
define i64 @f7(i64 %dummy, i64 *%src) {
; CHECK: f7:
; CHECK: nill %r0, 65534
; CHECK: lcgr %r0, %r0
; CHECK: aghi %r0, -1
; CHECK: br %r14
%res = atomicrmw nand i64 *%src, i64 -2 seq_cst
ret i64 %res
}
; Check the low end of the NILL range.
define i64 @f8(i64 %dummy, i64 *%src) {
; CHECK: f8:
; CHECK: nill %r0, 0
; CHECK: lcgr %r0, %r0
; CHECK: aghi %r0, -1
; CHECK: br %r14
%res = atomicrmw nand i64 *%src, i64 -65536 seq_cst
ret i64 %res
}
; Check the highest useful NILH value, which is one less than the above.
define i64 @f9(i64 %dummy, i64 *%src) {
; CHECK: f9:
; CHECK: nilh %r0, 65534
; CHECK: lcgr %r0, %r0
; CHECK: aghi %r0, -1
; CHECK: br %r14
%res = atomicrmw nand i64 *%src, i64 -65537 seq_cst
ret i64 %res
}
; Check the highest useful NILF value, which is one less than the above.
define i64 @f10(i64 %dummy, i64 *%src) {
; CHECK: f10:
; CHECK: nilf %r0, 4294901758
; CHECK: lcgr %r0, %r0
; CHECK: aghi %r0, -1
; CHECK: br %r14
%res = atomicrmw nand i64 *%src, i64 -65538 seq_cst
ret i64 %res
}
; Check the low end of the NILH range.
define i64 @f11(i64 %dummy, i64 *%src) {
; CHECK: f11:
; CHECK: nilh %r0, 0
; CHECK: lcgr %r0, %r0
; CHECK: aghi %r0, -1
; CHECK: br %r14
%res = atomicrmw nand i64 *%src, i64 -4294901761 seq_cst
ret i64 %res
}
; Check the low end of the NILF range.
define i64 @f12(i64 %dummy, i64 *%src) {
; CHECK: f12:
; CHECK: nilf %r0, 0
; CHECK: lcgr %r0, %r0
; CHECK: aghi %r0, -1
; CHECK: br %r14
%res = atomicrmw nand i64 *%src, i64 -4294967296 seq_cst
ret i64 %res
}
; Check the highest useful NIHL value, which is one less than the above.
define i64 @f13(i64 %dummy, i64 *%src) {
; CHECK: f13:
; CHECK: nihl %r0, 65534
; CHECK: lcgr %r0, %r0
; CHECK: aghi %r0, -1
; CHECK: br %r14
%res = atomicrmw nand i64 *%src, i64 -4294967297 seq_cst
ret i64 %res
}
; Check the low end of the NIHL range.
define i64 @f14(i64 %dummy, i64 *%src) {
; CHECK: f14:
; CHECK: nihl %r0, 0
; CHECK: lcgr %r0, %r0
; CHECK: aghi %r0, -1
; CHECK: br %r14
%res = atomicrmw nand i64 *%src, i64 -281470681743361 seq_cst
ret i64 %res
}
; Check the highest useful NIHH value, which is 1<<32 less than the above.
define i64 @f15(i64 %dummy, i64 *%src) {
; CHECK: f15:
; CHECK: nihh %r0, 65534
; CHECK: lcgr %r0, %r0
; CHECK: aghi %r0, -1
; CHECK: br %r14
%res = atomicrmw nand i64 *%src, i64 -281474976710657 seq_cst
ret i64 %res
}
; Check the highest useful NIHF value, which is 1<<32 less than the above.
define i64 @f16(i64 %dummy, i64 *%src) {
; CHECK: f16:
; CHECK: nihf %r0, 4294901758
; CHECK: lcgr %r0, %r0
; CHECK: aghi %r0, -1
; CHECK: br %r14
%res = atomicrmw nand i64 *%src, i64 -281479271677953 seq_cst
ret i64 %res
}

View File

@ -0,0 +1,132 @@
; Test 8-bit atomic ORs.
;
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s -check-prefix=CHECK
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s -check-prefix=CHECK-SHIFT1
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s -check-prefix=CHECK-SHIFT2
; Check OR of a variable.
; - CHECK is for the main loop.
; - CHECK-SHIFT1 makes sure that the negated shift count used by the second
; RLL is set up correctly. The negation is independent of the NILL and L
; tested in CHECK.
; - CHECK-SHIFT2 makes sure that %b is shifted into the high part of the word
; before being used. This shift is independent of the other loop prologue
; instructions.
define i8 @f1(i8 *%src, i8 %b) {
; CHECK: f1:
; CHECK: sllg [[SHIFT:%r[1-9]+]], %r2, 3
; CHECK: nill %r2, 65532
; CHECK: l [[OLD:%r[0-9]+]], 0(%r2)
; CHECK: [[LABEL:\.[^:]*]]:
; CHECK: rll [[ROT:%r[0-9]+]], [[OLD]], 0([[SHIFT]])
; CHECK: or [[ROT]], %r3
; CHECK: rll [[NEW:%r[0-9]+]], [[ROT]], 0({{%r[1-9]+}})
; CHECK: cs [[OLD]], [[NEW]], 0(%r2)
; CHECK: j{{g?}}lh [[LABEL]]
; CHECK: rll %r2, [[OLD]], 8([[SHIFT]])
; CHECK: br %r14
;
; CHECK-SHIFT1: f1:
; CHECK-SHIFT1: sllg [[SHIFT:%r[1-9]+]], %r2, 3
; CHECK-SHIFT1: lcr [[NEGSHIFT:%r[1-9]+]], [[SHIFT]]
; CHECK-SHIFT1: rll
; CHECK-SHIFT1: rll {{%r[0-9]+}}, {{%r[0-9]+}}, 0([[NEGSHIFT]])
; CHECK-SHIFT1: rll
; CHECK-SHIFT1: br %r14
;
; CHECK-SHIFT2: f1:
; CHECK-SHIFT2: sll %r3, 24
; CHECK-SHIFT2: rll
; CHECK-SHIFT2: or {{%r[0-9]+}}, %r3
; CHECK-SHIFT2: rll
; CHECK-SHIFT2: rll
; CHECK-SHIFT2: br %r14
%res = atomicrmw or i8 *%src, i8 %b seq_cst
ret i8 %res
}
; Check the minimum signed value. We OR the rotated word with 0x80000000.
define i8 @f2(i8 *%src) {
; CHECK: f2:
; CHECK: sllg [[SHIFT:%r[1-9]+]], %r2, 3
; CHECK: nill %r2, 65532
; CHECK: l [[OLD:%r[0-9]+]], 0(%r2)
; CHECK: [[LABEL:\.[^:]*]]:
; CHECK: rll [[ROT:%r[0-9]+]], [[OLD]], 0([[SHIFT]])
; CHECK: oilh [[ROT]], 32768
; CHECK: rll [[NEW:%r[0-9]+]], [[ROT]], 0([[NEGSHIFT:%r[1-9]+]])
; CHECK: cs [[OLD]], [[NEW]], 0(%r2)
; CHECK: j{{g?}}lh [[LABEL]]
; CHECK: rll %r2, [[OLD]], 8([[SHIFT]])
; CHECK: br %r14
;
; CHECK-SHIFT1: f2:
; CHECK-SHIFT1: sllg [[SHIFT:%r[1-9]+]], %r2, 3
; CHECK-SHIFT1: lcr [[NEGSHIFT:%r[1-9]+]], [[SHIFT]]
; CHECK-SHIFT1: rll
; CHECK-SHIFT1: rll {{%r[0-9]+}}, {{%r[0-9]+}}, 0([[NEGSHIFT]])
; CHECK-SHIFT1: rll
; CHECK-SHIFT1: br %r14
;
; CHECK-SHIFT2: f2:
; CHECK-SHIFT2: br %r14
%res = atomicrmw or i8 *%src, i8 -128 seq_cst
ret i8 %res
}
; Check ORs of -2 (-1 isn't useful). We OR the rotated word with 0xfe000000.
define i8 @f3(i8 *%src) {
; CHECK: f3:
; CHECK: oilh [[ROT]], 65024
; CHECK: br %r14
;
; CHECK-SHIFT1: f3:
; CHECK-SHIFT1: br %r14
; CHECK-SHIFT2: f3:
; CHECK-SHIFT2: br %r14
%res = atomicrmw or i8 *%src, i8 -2 seq_cst
ret i8 %res
}
; Check ORs of 1. We OR the rotated word with 0x01000000.
define i8 @f4(i8 *%src) {
; CHECK: f4:
; CHECK: oilh [[ROT]], 256
; CHECK: br %r14
;
; CHECK-SHIFT1: f4:
; CHECK-SHIFT1: br %r14
; CHECK-SHIFT2: f4:
; CHECK-SHIFT2: br %r14
%res = atomicrmw or i8 *%src, i8 1 seq_cst
ret i8 %res
}
; Check the maximum signed value. We OR the rotated word with 0x7f000000.
define i8 @f5(i8 *%src) {
; CHECK: f5:
; CHECK: oilh [[ROT]], 32512
; CHECK: br %r14
;
; CHECK-SHIFT1: f5:
; CHECK-SHIFT1: br %r14
; CHECK-SHIFT2: f5:
; CHECK-SHIFT2: br %r14
%res = atomicrmw or i8 *%src, i8 127 seq_cst
ret i8 %res
}
; Check ORs of a large unsigned value. We OR the rotated word with
; 0xfd000000.
define i8 @f6(i8 *%src) {
; CHECK: f6:
; CHECK: oilh [[ROT]], 64768
; CHECK: br %r14
;
; CHECK-SHIFT1: f6:
; CHECK-SHIFT1: br %r14
; CHECK-SHIFT2: f6:
; CHECK-SHIFT2: br %r14
%res = atomicrmw or i8 *%src, i8 253 seq_cst
ret i8 %res
}

View File

@ -0,0 +1,132 @@
; Test 16-bit atomic ORs.
;
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s -check-prefix=CHECK
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s -check-prefix=CHECK-SHIFT1
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s -check-prefix=CHECK-SHIFT2
; Check OR of a variable.
; - CHECK is for the main loop.
; - CHECK-SHIFT1 makes sure that the negated shift count used by the second
; RLL is set up correctly. The negation is independent of the NILL and L
; tested in CHECK.
; - CHECK-SHIFT2 makes sure that %b is shifted into the high part of the word
; before being used. This shift is independent of the other loop prologue
; instructions.
define i16 @f1(i16 *%src, i16 %b) {
; CHECK: f1:
; CHECK: sllg [[SHIFT:%r[1-9]+]], %r2, 3
; CHECK: nill %r2, 65532
; CHECK: l [[OLD:%r[0-9]+]], 0(%r2)
; CHECK: [[LABEL:\.[^:]*]]:
; CHECK: rll [[ROT:%r[0-9]+]], [[OLD]], 0([[SHIFT]])
; CHECK: or [[ROT]], %r3
; CHECK: rll [[NEW:%r[0-9]+]], [[ROT]], 0({{%r[1-9]+}})
; CHECK: cs [[OLD]], [[NEW]], 0(%r2)
; CHECK: j{{g?}}lh [[LABEL]]
; CHECK: rll %r2, [[OLD]], 16([[SHIFT]])
; CHECK: br %r14
;
; CHECK-SHIFT1: f1:
; CHECK-SHIFT1: sllg [[SHIFT:%r[1-9]+]], %r2, 3
; CHECK-SHIFT1: lcr [[NEGSHIFT:%r[1-9]+]], [[SHIFT]]
; CHECK-SHIFT1: rll
; CHECK-SHIFT1: rll {{%r[0-9]+}}, {{%r[0-9]+}}, 0([[NEGSHIFT]])
; CHECK-SHIFT1: rll
; CHECK-SHIFT1: br %r14
;
; CHECK-SHIFT2: f1:
; CHECK-SHIFT2: sll %r3, 16
; CHECK-SHIFT2: rll
; CHECK-SHIFT2: or {{%r[0-9]+}}, %r3
; CHECK-SHIFT2: rll
; CHECK-SHIFT2: rll
; CHECK-SHIFT2: br %r14
%res = atomicrmw or i16 *%src, i16 %b seq_cst
ret i16 %res
}
; Check the minimum signed value. We OR the rotated word with 0x80000000.
define i16 @f2(i16 *%src) {
; CHECK: f2:
; CHECK: sllg [[SHIFT:%r[1-9]+]], %r2, 3
; CHECK: nill %r2, 65532
; CHECK: l [[OLD:%r[0-9]+]], 0(%r2)
; CHECK: [[LABEL:\.[^:]*]]:
; CHECK: rll [[ROT:%r[0-9]+]], [[OLD]], 0([[SHIFT]])
; CHECK: oilh [[ROT]], 32768
; CHECK: rll [[NEW:%r[0-9]+]], [[ROT]], 0([[NEGSHIFT:%r[1-9]+]])
; CHECK: cs [[OLD]], [[NEW]], 0(%r2)
; CHECK: j{{g?}}lh [[LABEL]]
; CHECK: rll %r2, [[OLD]], 16([[SHIFT]])
; CHECK: br %r14
;
; CHECK-SHIFT1: f2:
; CHECK-SHIFT1: sllg [[SHIFT:%r[1-9]+]], %r2, 3
; CHECK-SHIFT1: lcr [[NEGSHIFT:%r[1-9]+]], [[SHIFT]]
; CHECK-SHIFT1: rll
; CHECK-SHIFT1: rll {{%r[0-9]+}}, {{%r[0-9]+}}, 0([[NEGSHIFT]])
; CHECK-SHIFT1: rll
; CHECK-SHIFT1: br %r14
;
; CHECK-SHIFT2: f2:
; CHECK-SHIFT2: br %r14
%res = atomicrmw or i16 *%src, i16 -32768 seq_cst
ret i16 %res
}
; Check ORs of -2 (-1 isn't useful). We OR the rotated word with 0xfffe0000.
define i16 @f3(i16 *%src) {
; CHECK: f3:
; CHECK: oilh [[ROT]], 65534
; CHECK: br %r14
;
; CHECK-SHIFT1: f3:
; CHECK-SHIFT1: br %r14
; CHECK-SHIFT2: f3:
; CHECK-SHIFT2: br %r14
%res = atomicrmw or i16 *%src, i16 -2 seq_cst
ret i16 %res
}
; Check ORs of 1. We OR the rotated word with 0x00010000.
define i16 @f4(i16 *%src) {
; CHECK: f4:
; CHECK: oilh [[ROT]], 1
; CHECK: br %r14
;
; CHECK-SHIFT1: f4:
; CHECK-SHIFT1: br %r14
; CHECK-SHIFT2: f4:
; CHECK-SHIFT2: br %r14
%res = atomicrmw or i16 *%src, i16 1 seq_cst
ret i16 %res
}
; Check the maximum signed value. We OR the rotated word with 0x7fff0000.
define i16 @f5(i16 *%src) {
; CHECK: f5:
; CHECK: oilh [[ROT]], 32767
; CHECK: br %r14
;
; CHECK-SHIFT1: f5:
; CHECK-SHIFT1: br %r14
; CHECK-SHIFT2: f5:
; CHECK-SHIFT2: br %r14
%res = atomicrmw or i16 *%src, i16 32767 seq_cst
ret i16 %res
}
; Check ORs of a large unsigned value. We OR the rotated word with
; 0xfffd0000.
define i16 @f6(i16 *%src) {
; CHECK: f6:
; CHECK: oilh [[ROT]], 65533
; CHECK: br %r14
;
; CHECK-SHIFT1: f6:
; CHECK-SHIFT1: br %r14
; CHECK-SHIFT2: f6:
; CHECK-SHIFT2: br %r14
%res = atomicrmw or i16 *%src, i16 65533 seq_cst
ret i16 %res
}

View File

@ -0,0 +1,85 @@
; Test 32-bit atomic ORs.
;
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s
; Check ORs of a variable.
define i32 @f1(i32 %dummy, i32 *%src, i32 %b) {
; CHECK: f1:
; CHECK: l %r2, 0(%r3)
; CHECK: [[LABEL:\.[^ ]*]]:
; CHECK: lr %r0, %r2
; CHECK: or %r0, %r4
; CHECK: cs %r2, %r0, 0(%r3)
; CHECK: j{{g?}}lh [[LABEL]]
; CHECK: br %r14
%res = atomicrmw or i32 *%src, i32 %b seq_cst
ret i32 %res
}
; Check the lowest useful OILL value.
define i32 @f2(i32 %dummy, i32 *%src) {
; CHECK: f2:
; CHECK: l %r2, 0(%r3)
; CHECK: [[LABEL:\.[^ ]*]]:
; CHECK: lr %r0, %r2
; CHECK: oill %r0, 1
; CHECK: cs %r2, %r0, 0(%r3)
; CHECK: j{{g?}}lh [[LABEL]]
; CHECK: br %r14
%res = atomicrmw or i32 *%src, i32 1 seq_cst
ret i32 %res
}
; Check the high end of the OILL range.
define i32 @f3(i32 %dummy, i32 *%src) {
; CHECK: f3:
; CHECK: oill %r0, 65535
; CHECK: br %r14
%res = atomicrmw or i32 *%src, i32 65535 seq_cst
ret i32 %res
}
; Check the lowest useful OILH value, which is the next value up.
define i32 @f4(i32 %dummy, i32 *%src) {
; CHECK: f4:
; CHECK: oilh %r0, 1
; CHECK: br %r14
%res = atomicrmw or i32 *%src, i32 65536 seq_cst
ret i32 %res
}
; Check the lowest useful OILF value, which is the next value up.
define i32 @f5(i32 %dummy, i32 *%src) {
; CHECK: f5:
; CHECK: oilf %r0, 65537
; CHECK: br %r14
%res = atomicrmw or i32 *%src, i32 65537 seq_cst
ret i32 %res
}
; Check the high end of the OILH range.
define i32 @f6(i32 %dummy, i32 *%src) {
; CHECK: f6:
; CHECK: oilh %r0, 65535
; CHECK: br %r14
%res = atomicrmw or i32 *%src, i32 -65536 seq_cst
ret i32 %res
}
; Check the next value up, which must use OILF.
define i32 @f7(i32 %dummy, i32 *%src) {
; CHECK: f7:
; CHECK: oilf %r0, 4294901761
; CHECK: br %r14
%res = atomicrmw or i32 *%src, i32 -65535 seq_cst
ret i32 %res
}
; Check the largest useful OILF value.
define i32 @f8(i32 %dummy, i32 *%src) {
; CHECK: f8:
; CHECK: oilf %r0, 4294967294
; CHECK: br %r14
%res = atomicrmw or i32 *%src, i32 -2 seq_cst
ret i32 %res
}

View File

@ -0,0 +1,158 @@
; Test 64-bit atomic ORs.
;
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s
; Check ORs of a variable.
define i64 @f1(i64 %dummy, i64 *%src, i64 %b) {
; CHECK: f1:
; CHECK: lg %r2, 0(%r3)
; CHECK: [[LABEL:\.[^ ]*]]:
; CHECK: lgr %r0, %r2
; CHECK: ogr %r0, %r4
; CHECK: csg %r2, %r0, 0(%r3)
; CHECK: j{{g?}}lh [[LABEL]]
; CHECK: br %r14
%res = atomicrmw or i64 *%src, i64 %b seq_cst
ret i64 %res
}
; Check the lowest useful OILL value.
define i64 @f2(i64 %dummy, i64 *%src) {
; CHECK: f2:
; CHECK: lg %r2, 0(%r3)
; CHECK: [[LABEL:\.[^ ]*]]:
; CHECK: lgr %r0, %r2
; CHECK: oill %r0, 1
; CHECK: csg %r2, %r0, 0(%r3)
; CHECK: j{{g?}}lh [[LABEL]]
; CHECK: br %r14
%res = atomicrmw or i64 *%src, i64 1 seq_cst
ret i64 %res
}
; Check the high end of the OILL range.
define i64 @f3(i64 %dummy, i64 *%src) {
; CHECK: f3:
; CHECK: oill %r0, 65535
; CHECK: br %r14
%res = atomicrmw or i64 *%src, i64 65535 seq_cst
ret i64 %res
}
; Check the lowest useful OILH value, which is the next value up.
define i64 @f4(i64 %dummy, i64 *%src) {
; CHECK: f4:
; CHECK: oilh %r0, 1
; CHECK: br %r14
%res = atomicrmw or i64 *%src, i64 65536 seq_cst
ret i64 %res
}
; Check the lowest useful OILF value, which is the next value up again.
define i64 @f5(i64 %dummy, i64 *%src) {
; CHECK: f5:
; CHECK: oilf %r0, 65537
; CHECK: br %r14
%res = atomicrmw or i64 *%src, i64 65537 seq_cst
ret i64 %res
}
; Check the high end of the OILH range.
define i64 @f6(i64 %dummy, i64 *%src) {
; CHECK: f6:
; CHECK: oilh %r0, 65535
; CHECK: br %r14
%res = atomicrmw or i64 *%src, i64 4294901760 seq_cst
ret i64 %res
}
; Check the next value up, which must use OILF.
define i64 @f7(i64 %dummy, i64 *%src) {
; CHECK: f7:
; CHECK: oilf %r0, 4294901761
; CHECK: br %r14
%res = atomicrmw or i64 *%src, i64 4294901761 seq_cst
ret i64 %res
}
; Check the high end of the OILF range.
define i64 @f8(i64 %dummy, i64 *%src) {
; CHECK: f8:
; CHECK: oilf %r0, 4294967295
; CHECK: br %r14
%res = atomicrmw or i64 *%src, i64 4294967295 seq_cst
ret i64 %res
}
; Check the lowest useful OIHL value, which is one greater than above.
define i64 @f9(i64 %dummy, i64 *%src) {
; CHECK: f9:
; CHECK: oihl %r0, 1
; CHECK: br %r14
%res = atomicrmw or i64 *%src, i64 4294967296 seq_cst
ret i64 %res
}
; Check the next value up, which must use a register. (We could use
; combinations of OIH* and OIL* instead, but that isn't implemented.)
define i64 @f10(i64 %dummy, i64 *%src) {
; CHECK: f10:
; CHECK: ogr
; CHECK: br %r14
%res = atomicrmw or i64 *%src, i64 4294967297 seq_cst
ret i64 %res
}
; Check the high end of the OIHL range.
define i64 @f11(i64 %dummy, i64 *%src) {
; CHECK: f11:
; CHECK: oihl %r0, 65535
; CHECK: br %r14
%res = atomicrmw or i64 *%src, i64 281470681743360 seq_cst
ret i64 %res
}
; Check the lowest useful OIHH value, which is 1<<32 greater than above.
define i64 @f12(i64 %dummy, i64 *%src) {
; CHECK: f12:
; CHECK: oihh %r0, 1
; CHECK: br %r14
%res = atomicrmw or i64 *%src, i64 281474976710656 seq_cst
ret i64 %res
}
; Check the lowest useful OIHF value, which is 1<<32 greater again.
define i64 @f13(i64 %dummy, i64 *%src) {
; CHECK: f13:
; CHECK: oihf %r0, 65537
; CHECK: br %r14
%res = atomicrmw or i64 *%src, i64 281479271677952 seq_cst
ret i64 %res
}
; Check the high end of the OIHH range.
define i64 @f14(i64 %dummy, i64 *%src) {
; CHECK: f14:
; CHECK: oihh %r0, 65535
; CHECK: br %r14
%res = atomicrmw or i64 *%src, i64 18446462598732840960 seq_cst
ret i64 %res
}
; Check the next value up, which must use a register.
define i64 @f15(i64 %dummy, i64 *%src) {
; CHECK: f15:
; CHECK: ogr
; CHECK: br %r14
%res = atomicrmw or i64 *%src, i64 18446462598732840961 seq_cst
ret i64 %res
}
; Check the high end of the OIHF range.
define i64 @f16(i64 %dummy, i64 *%src) {
; CHECK: f16:
; CHECK: oihf %r0, 4294967295
; CHECK: br %r14
%res = atomicrmw or i64 *%src, i64 -4294967296 seq_cst
ret i64 %res
}

View File

@ -0,0 +1,132 @@
; Test 8-bit atomic subtractions.
;
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s -check-prefix=CHECK
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s -check-prefix=CHECK-SHIFT1
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s -check-prefix=CHECK-SHIFT2
; Check subtraction of a variable.
; - CHECK is for the main loop.
; - CHECK-SHIFT1 makes sure that the negated shift count used by the second
; RLL is set up correctly. The negation is independent of the NILL and L
; tested in CHECK.
; - CHECK-SHIFT2 makes sure that %b is shifted into the high part of the word
; before being used. This shift is independent of the other loop prologue
; instructions.
define i8 @f1(i8 *%src, i8 %b) {
; CHECK: f1:
; CHECK: sllg [[SHIFT:%r[1-9]+]], %r2, 3
; CHECK: nill %r2, 65532
; CHECK: l [[OLD:%r[0-9]+]], 0(%r2)
; CHECK: [[LABEL:\.[^:]*]]:
; CHECK: rll [[ROT:%r[0-9]+]], [[OLD]], 0([[SHIFT]])
; CHECK: sr [[ROT]], %r3
; CHECK: rll [[NEW:%r[0-9]+]], [[ROT]], 0({{%r[1-9]+}})
; CHECK: cs [[OLD]], [[NEW]], 0(%r2)
; CHECK: j{{g?}}lh [[LABEL]]
; CHECK: rll %r2, [[OLD]], 8([[SHIFT]])
; CHECK: br %r14
;
; CHECK-SHIFT1: f1:
; CHECK-SHIFT1: sllg [[SHIFT:%r[1-9]+]], %r2, 3
; CHECK-SHIFT1: lcr [[NEGSHIFT:%r[1-9]+]], [[SHIFT]]
; CHECK-SHIFT1: rll
; CHECK-SHIFT1: rll {{%r[0-9]+}}, {{%r[0-9]+}}, 0([[NEGSHIFT]])
; CHECK-SHIFT1: rll
; CHECK-SHIFT1: br %r14
;
; CHECK-SHIFT2: f1:
; CHECK-SHIFT2: sll %r3, 24
; CHECK-SHIFT2: rll
; CHECK-SHIFT2: sr {{%r[0-9]+}}, %r3
; CHECK-SHIFT2: rll
; CHECK-SHIFT2: rll
; CHECK-SHIFT2: br %r14
%res = atomicrmw sub i8 *%src, i8 %b seq_cst
ret i8 %res
}
; Check the minimum signed value. We add 0x80000000 to the rotated word.
define i8 @f2(i8 *%src) {
; CHECK: f2:
; CHECK: sllg [[SHIFT:%r[1-9]+]], %r2, 3
; CHECK: nill %r2, 65532
; CHECK: l [[OLD:%r[0-9]+]], 0(%r2)
; CHECK: [[LABEL:\.[^:]*]]:
; CHECK: rll [[ROT:%r[0-9]+]], [[OLD]], 0([[SHIFT]])
; CHECK: afi [[ROT]], -2147483648
; CHECK: rll [[NEW:%r[0-9]+]], [[ROT]], 0([[NEGSHIFT:%r[1-9]+]])
; CHECK: cs [[OLD]], [[NEW]], 0(%r2)
; CHECK: j{{g?}}lh [[LABEL]]
; CHECK: rll %r2, [[OLD]], 8([[SHIFT]])
; CHECK: br %r14
;
; CHECK-SHIFT1: f2:
; CHECK-SHIFT1: sllg [[SHIFT:%r[1-9]+]], %r2, 3
; CHECK-SHIFT1: lcr [[NEGSHIFT:%r[1-9]+]], [[SHIFT]]
; CHECK-SHIFT1: rll
; CHECK-SHIFT1: rll {{%r[0-9]+}}, {{%r[0-9]+}}, 0([[NEGSHIFT]])
; CHECK-SHIFT1: rll
; CHECK-SHIFT1: br %r14
;
; CHECK-SHIFT2: f2:
; CHECK-SHIFT2: br %r14
%res = atomicrmw sub i8 *%src, i8 -128 seq_cst
ret i8 %res
}
; Check subtraction of -1. We add 0x01000000 to the rotated word.
define i8 @f3(i8 *%src) {
; CHECK: f3:
; CHECK: afi [[ROT]], 16777216
; CHECK: br %r14
;
; CHECK-SHIFT1: f3:
; CHECK-SHIFT1: br %r14
; CHECK-SHIFT2: f3:
; CHECK-SHIFT2: br %r14
%res = atomicrmw sub i8 *%src, i8 -1 seq_cst
ret i8 %res
}
; Check subtraction of -1. We add 0xff000000 to the rotated word.
define i8 @f4(i8 *%src) {
; CHECK: f4:
; CHECK: afi [[ROT]], -16777216
; CHECK: br %r14
;
; CHECK-SHIFT1: f4:
; CHECK-SHIFT1: br %r14
; CHECK-SHIFT2: f4:
; CHECK-SHIFT2: br %r14
%res = atomicrmw sub i8 *%src, i8 1 seq_cst
ret i8 %res
}
; Check the maximum signed value. We add 0x81000000 to the rotated word.
define i8 @f5(i8 *%src) {
; CHECK: f5:
; CHECK: afi [[ROT]], -2130706432
; CHECK: br %r14
;
; CHECK-SHIFT1: f5:
; CHECK-SHIFT1: br %r14
; CHECK-SHIFT2: f5:
; CHECK-SHIFT2: br %r14
%res = atomicrmw sub i8 *%src, i8 127 seq_cst
ret i8 %res
}
; Check subtraction of a large unsigned value. We add 0x02000000 to the
; rotated word.
define i8 @f6(i8 *%src) {
; CHECK: f6:
; CHECK: afi [[ROT]], 33554432
; CHECK: br %r14
;
; CHECK-SHIFT1: f6:
; CHECK-SHIFT1: br %r14
; CHECK-SHIFT2: f6:
; CHECK-SHIFT2: br %r14
%res = atomicrmw sub i8 *%src, i8 254 seq_cst
ret i8 %res
}

View File

@ -0,0 +1,132 @@
; Test 16-bit atomic subtractions.
;
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s -check-prefix=CHECK
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s -check-prefix=CHECK-SHIFT1
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s -check-prefix=CHECK-SHIFT2
; Check subtraction of a variable.
; - CHECK is for the main loop.
; - CHECK-SHIFT1 makes sure that the negated shift count used by the second
; RLL is set up correctly. The negation is independent of the NILL and L
; tested in CHECK.
; - CHECK-SHIFT2 makes sure that %b is shifted into the high part of the word
; before being used. This shift is independent of the other loop prologue
; instructions.
define i16 @f1(i16 *%src, i16 %b) {
; CHECK: f1:
; CHECK: sllg [[SHIFT:%r[1-9]+]], %r2, 3
; CHECK: nill %r2, 65532
; CHECK: l [[OLD:%r[0-9]+]], 0(%r2)
; CHECK: [[LABEL:\.[^:]*]]:
; CHECK: rll [[ROT:%r[0-9]+]], [[OLD]], 0([[SHIFT]])
; CHECK: sr [[ROT]], %r3
; CHECK: rll [[NEW:%r[0-9]+]], [[ROT]], 0({{%r[1-9]+}})
; CHECK: cs [[OLD]], [[NEW]], 0(%r2)
; CHECK: j{{g?}}lh [[LABEL]]
; CHECK: rll %r2, [[OLD]], 16([[SHIFT]])
; CHECK: br %r14
;
; CHECK-SHIFT1: f1:
; CHECK-SHIFT1: sllg [[SHIFT:%r[1-9]+]], %r2, 3
; CHECK-SHIFT1: lcr [[NEGSHIFT:%r[1-9]+]], [[SHIFT]]
; CHECK-SHIFT1: rll
; CHECK-SHIFT1: rll {{%r[0-9]+}}, {{%r[0-9]+}}, 0([[NEGSHIFT]])
; CHECK-SHIFT1: rll
; CHECK-SHIFT1: br %r14
;
; CHECK-SHIFT2: f1:
; CHECK-SHIFT2: sll %r3, 16
; CHECK-SHIFT2: rll
; CHECK-SHIFT2: sr {{%r[0-9]+}}, %r3
; CHECK-SHIFT2: rll
; CHECK-SHIFT2: rll
; CHECK-SHIFT2: br %r14
%res = atomicrmw sub i16 *%src, i16 %b seq_cst
ret i16 %res
}
; Check the minimum signed value. We add 0x80000000 to the rotated word.
define i16 @f2(i16 *%src) {
; CHECK: f2:
; CHECK: sllg [[SHIFT:%r[1-9]+]], %r2, 3
; CHECK: nill %r2, 65532
; CHECK: l [[OLD:%r[0-9]+]], 0(%r2)
; CHECK: [[LABEL:\.[^:]*]]:
; CHECK: rll [[ROT:%r[0-9]+]], [[OLD]], 0([[SHIFT]])
; CHECK: afi [[ROT]], -2147483648
; CHECK: rll [[NEW:%r[0-9]+]], [[ROT]], 0([[NEGSHIFT:%r[1-9]+]])
; CHECK: cs [[OLD]], [[NEW]], 0(%r2)
; CHECK: j{{g?}}lh [[LABEL]]
; CHECK: rll %r2, [[OLD]], 16([[SHIFT]])
; CHECK: br %r14
;
; CHECK-SHIFT1: f2:
; CHECK-SHIFT1: sllg [[SHIFT:%r[1-9]+]], %r2, 3
; CHECK-SHIFT1: lcr [[NEGSHIFT:%r[1-9]+]], [[SHIFT]]
; CHECK-SHIFT1: rll
; CHECK-SHIFT1: rll {{%r[0-9]+}}, {{%r[0-9]+}}, 0([[NEGSHIFT]])
; CHECK-SHIFT1: rll
; CHECK-SHIFT1: br %r14
;
; CHECK-SHIFT2: f2:
; CHECK-SHIFT2: br %r14
%res = atomicrmw sub i16 *%src, i16 -32768 seq_cst
ret i16 %res
}
; Check subtraction of -1. We add 0x00010000 to the rotated word.
define i16 @f3(i16 *%src) {
; CHECK: f3:
; CHECK: afi [[ROT]], 65536
; CHECK: br %r14
;
; CHECK-SHIFT1: f3:
; CHECK-SHIFT1: br %r14
; CHECK-SHIFT2: f3:
; CHECK-SHIFT2: br %r14
%res = atomicrmw sub i16 *%src, i16 -1 seq_cst
ret i16 %res
}
; Check subtraction of 1. We add 0xffff0000 to the rotated word.
define i16 @f4(i16 *%src) {
; CHECK: f4:
; CHECK: afi [[ROT]], -65536
; CHECK: br %r14
;
; CHECK-SHIFT1: f4:
; CHECK-SHIFT1: br %r14
; CHECK-SHIFT2: f4:
; CHECK-SHIFT2: br %r14
%res = atomicrmw sub i16 *%src, i16 1 seq_cst
ret i16 %res
}
; Check the maximum signed value. We add 0x80010000 to the rotated word.
define i16 @f5(i16 *%src) {
; CHECK: f5:
; CHECK: afi [[ROT]], -2147418112
; CHECK: br %r14
;
; CHECK-SHIFT1: f5:
; CHECK-SHIFT1: br %r14
; CHECK-SHIFT2: f5:
; CHECK-SHIFT2: br %r14
%res = atomicrmw sub i16 *%src, i16 32767 seq_cst
ret i16 %res
}
; Check subtraction of a large unsigned value. We add 0x00020000 to the
; rotated word.
define i16 @f6(i16 *%src) {
; CHECK: f6:
; CHECK: afi [[ROT]], 131072
; CHECK: br %r14
;
; CHECK-SHIFT1: f6:
; CHECK-SHIFT1: br %r14
; CHECK-SHIFT2: f6:
; CHECK-SHIFT2: br %r14
%res = atomicrmw sub i16 *%src, i16 65534 seq_cst
ret i16 %res
}

View File

@ -0,0 +1,94 @@
; Test 32-bit atomic subtractions.
;
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s
; Check subtraction of a variable.
define i32 @f1(i32 %dummy, i32 *%src, i32 %b) {
; CHECK: f1:
; CHECK: l %r2, 0(%r3)
; CHECK: [[LABEL:\.[^:]*]]:
; CHECK: lr %r0, %r2
; CHECK: sr %r0, %r4
; CHECK: cs %r2, %r0, 0(%r3)
; CHECK: j{{g?}}lh [[LABEL]]
; CHECK: br %r14
%res = atomicrmw sub i32 *%src, i32 %b seq_cst
ret i32 %res
}
; Check subtraction of 1, which can use AHI.
define i32 @f2(i32 %dummy, i32 *%src) {
; CHECK: f2:
; CHECK: l %r2, 0(%r3)
; CHECK: [[LABEL:\.[^:]*]]:
; CHECK: lr %r0, %r2
; CHECK: ahi %r0, -1
; CHECK: cs %r2, %r0, 0(%r3)
; CHECK: j{{g?}}lh [[LABEL]]
; CHECK: br %r14
%res = atomicrmw sub i32 *%src, i32 1 seq_cst
ret i32 %res
}
; Check the low end of the AHI range.
define i32 @f3(i32 %dummy, i32 *%src) {
; CHECK: f3:
; CHECK: ahi %r0, -32768
; CHECK: br %r14
%res = atomicrmw sub i32 *%src, i32 32768 seq_cst
ret i32 %res
}
; Check the next value down, which must use AFI.
define i32 @f4(i32 %dummy, i32 *%src) {
; CHECK: f4:
; CHECK: afi %r0, -32769
; CHECK: br %r14
%res = atomicrmw sub i32 *%src, i32 32769 seq_cst
ret i32 %res
}
; Check the low end of the AFI range.
define i32 @f5(i32 %dummy, i32 *%src) {
; CHECK: f5:
; CHECK: afi %r0, -2147483648
; CHECK: br %r14
%res = atomicrmw sub i32 *%src, i32 2147483648 seq_cst
ret i32 %res
}
; Check the next value up, which gets treated as a positive operand.
define i32 @f6(i32 %dummy, i32 *%src) {
; CHECK: f6:
; CHECK: afi %r0, 2147483647
; CHECK: br %r14
%res = atomicrmw sub i32 *%src, i32 2147483649 seq_cst
ret i32 %res
}
; Check subtraction of -1, which can use AHI.
define i32 @f7(i32 %dummy, i32 *%src) {
; CHECK: f7:
; CHECK: ahi %r0, 1
; CHECK: br %r14
%res = atomicrmw sub i32 *%src, i32 -1 seq_cst
ret i32 %res
}
; Check the high end of the AHI range.
define i32 @f8(i32 %dummy, i32 *%src) {
; CHECK: f8:
; CHECK: ahi %r0, 32767
; CHECK: br %r14
%res = atomicrmw sub i32 *%src, i32 -32767 seq_cst
ret i32 %res
}
; Check the next value down, which must use AFI instead.
define i32 @f9(i32 %dummy, i32 *%src) {
; CHECK: f9:
; CHECK: afi %r0, 32768
; CHECK: br %r14
%res = atomicrmw sub i32 *%src, i32 -32768 seq_cst
ret i32 %res
}

View File

@ -0,0 +1,112 @@
; Test 64-bit atomic subtractions.
;
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s
; Check subtraction of a variable.
define i64 @f1(i64 %dummy, i64 *%src, i64 %b) {
; CHECK: f1:
; CHECK: lg %r2, 0(%r3)
; CHECK: [[LABEL:\.[^:]*]]:
; CHECK: lgr %r0, %r2
; CHECK: sgr %r0, %r4
; CHECK: csg %r2, %r0, 0(%r3)
; CHECK: j{{g?}}lh [[LABEL]]
; CHECK: br %r14
%res = atomicrmw sub i64 *%src, i64 %b seq_cst
ret i64 %res
}
; Check subtraction of 1, which can use AGHI.
define i64 @f2(i64 %dummy, i64 *%src) {
; CHECK: f2:
; CHECK: lg %r2, 0(%r3)
; CHECK: [[LABEL:\.[^:]*]]:
; CHECK: lgr %r0, %r2
; CHECK: aghi %r0, -1
; CHECK: csg %r2, %r0, 0(%r3)
; CHECK: j{{g?}}lh [[LABEL]]
; CHECK: br %r14
%res = atomicrmw sub i64 *%src, i64 1 seq_cst
ret i64 %res
}
; Check the low end of the AGHI range.
define i64 @f3(i64 %dummy, i64 *%src) {
; CHECK: f3:
; CHECK: aghi %r0, -32768
; CHECK: br %r14
%res = atomicrmw sub i64 *%src, i64 32768 seq_cst
ret i64 %res
}
; Check the next value up, which must use AGFI.
define i64 @f4(i64 %dummy, i64 *%src) {
; CHECK: f4:
; CHECK: agfi %r0, -32769
; CHECK: br %r14
%res = atomicrmw sub i64 *%src, i64 32769 seq_cst
ret i64 %res
}
; Check the low end of the AGFI range.
define i64 @f5(i64 %dummy, i64 *%src) {
; CHECK: f5:
; CHECK: agfi %r0, -2147483648
; CHECK: br %r14
%res = atomicrmw sub i64 *%src, i64 2147483648 seq_cst
ret i64 %res
}
; Check the next value up, which must use a register operation.
define i64 @f6(i64 %dummy, i64 *%src) {
; CHECK: f6:
; CHECK: sgr
; CHECK: br %r14
%res = atomicrmw sub i64 *%src, i64 2147483649 seq_cst
ret i64 %res
}
; Check subtraction of -1, which can use AGHI.
define i64 @f7(i64 %dummy, i64 *%src) {
; CHECK: f7:
; CHECK: aghi %r0, 1
; CHECK: br %r14
%res = atomicrmw sub i64 *%src, i64 -1 seq_cst
ret i64 %res
}
; Check the high end of the AGHI range.
define i64 @f8(i64 %dummy, i64 *%src) {
; CHECK: f8:
; CHECK: aghi %r0, 32767
; CHECK: br %r14
%res = atomicrmw sub i64 *%src, i64 -32767 seq_cst
ret i64 %res
}
; Check the next value down, which must use AGFI instead.
define i64 @f9(i64 %dummy, i64 *%src) {
; CHECK: f9:
; CHECK: agfi %r0, 32768
; CHECK: br %r14
%res = atomicrmw sub i64 *%src, i64 -32768 seq_cst
ret i64 %res
}
; Check the high end of the AGFI range.
define i64 @f10(i64 %dummy, i64 *%src) {
; CHECK: f10:
; CHECK: agfi %r0, 2147483647
; CHECK: br %r14
%res = atomicrmw sub i64 *%src, i64 -2147483647 seq_cst
ret i64 %res
}
; Check the next value down, which must use a register operation.
define i64 @f11(i64 %dummy, i64 *%src) {
; CHECK: f11:
; CHECK: sgr
; CHECK: br %r14
%res = atomicrmw sub i64 *%src, i64 -2147483648 seq_cst
ret i64 %res
}

View File

@ -0,0 +1,55 @@
; Test 8-bit atomic exchange.
;
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s -check-prefix=CHECK
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s -check-prefix=CHECK-SHIFT
; Check exchange with a variable.
; - CHECK is for the main loop.
; - CHECK-SHIFT makes sure that the negated shift count used by the second
; RLL is set up correctly. The negation is independent of the NILL and L
; tested in CHECK. CHECK-SHIFT also checks that %r3 is not modified before
; being used in the RISBG (in contrast to things like atomic addition,
; which shift %r3 left so that %b is at the high end of the word).
define i8 @f1(i8 *%src, i8 %b) {
; CHECK: f1:
; CHECK: sllg [[SHIFT:%r[1-9]+]], %r2, 3
; CHECK: nill %r2, 65532
; CHECK: l [[OLD:%r[0-9]+]], 0(%r2)
; CHECK: [[LABEL:\.[^:]*]]:
; CHECK: rll [[ROT:%r[0-9]+]], [[OLD]], 0([[SHIFT]])
; CHECK: risbg [[ROT]], %r3, 32, 39, 24
; CHECK: rll [[NEW:%r[0-9]+]], [[ROT]], 0({{%r[1-9]+}})
; CHECK: cs [[OLD]], [[NEW]], 0(%r2)
; CHECK: j{{g?}}lh [[LABEL]]
; CHECK: rll %r2, [[OLD]], 8([[SHIFT]])
; CHECK: br %r14
;
; CHECK-SHIFT: f1:
; CHECK-SHIFT-NOT: %r3
; CHECK-SHIFT: sllg [[SHIFT:%r[1-9]+]], %r2, 3
; CHECK-SHIFT-NOT: %r3
; CHECK-SHIFT: lcr [[NEGSHIFT:%r[1-9]+]], [[SHIFT]]
; CHECK-SHIFT-NOT: %r3
; CHECK-SHIFT: rll
; CHECK-SHIFT-NOT: %r3
; CHECK-SHIFT: risbg {{%r[0-9]+}}, %r3, 32, 39, 24
; CHECK-SHIFT: rll {{%r[0-9]+}}, {{%r[0-9]+}}, 0([[NEGSHIFT]])
; CHECK-SHIFT: rll
; CHECK-SHIFT: br %r14
%res = atomicrmw xchg i8 *%src, i8 %b seq_cst
ret i8 %res
}
; Check exchange with a constant. We should force the constant into
; a register and use the sequence above.
define i8 @f2(i8 *%src) {
; CHECK: f2:
; CHECK: lhi [[VALUE:%r[0-9]+]], 88
; CHECK: risbg {{%r[0-9]+}}, [[VALUE]], 32, 39, 24
; CHECK: br %r14
;
; CHECK-SHIFT: f2:
; CHECK-SHIFT: br %r14
%res = atomicrmw xchg i8 *%src, i8 88 seq_cst
ret i8 %res
}

View File

@ -0,0 +1,55 @@
; Test 16-bit atomic exchange.
;
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s -check-prefix=CHECK
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s -check-prefix=CHECK-SHIFT
; Check exchange with a variable.
; - CHECK is for the main loop.
; - CHECK-SHIFT makes sure that the negated shift count used by the second
; RLL is set up correctly. The negation is independent of the NILL and L
; tested in CHECK. CHECK-SHIFT also checks that %r3 is not modified before
; being used in the RISBG (in contrast to things like atomic addition,
; which shift %r3 left so that %b is at the high end of the word).
define i16 @f1(i16 *%src, i16 %b) {
; CHECK: f1:
; CHECK: sllg [[SHIFT:%r[1-9]+]], %r2, 3
; CHECK: nill %r2, 65532
; CHECK: l [[OLD:%r[0-9]+]], 0(%r2)
; CHECK: [[LABEL:\.[^:]*]]:
; CHECK: rll [[ROT:%r[0-9]+]], [[OLD]], 0([[SHIFT]])
; CHECK: risbg [[ROT]], %r3, 32, 47, 16
; CHECK: rll [[NEW:%r[0-9]+]], [[ROT]], 0({{%r[1-9]+}})
; CHECK: cs [[OLD]], [[NEW]], 0(%r2)
; CHECK: j{{g?}}lh [[LABEL]]
; CHECK: rll %r2, [[OLD]], 16([[SHIFT]])
; CHECK: br %r14
;
; CHECK-SHIFT: f1:
; CHECK-SHIFT-NOT: %r3
; CHECK-SHIFT: sllg [[SHIFT:%r[1-9]+]], %r2, 3
; CHECK-SHIFT-NOT: %r3
; CHECK-SHIFT: lcr [[NEGSHIFT:%r[1-9]+]], [[SHIFT]]
; CHECK-SHIFT-NOT: %r3
; CHECK-SHIFT: rll
; CHECK-SHIFT-NOT: %r3
; CHECK-SHIFT: risbg {{%r[0-9]+}}, %r3, 32, 47, 16
; CHECK-SHIFT: rll {{%r[0-9]+}}, {{%r[0-9]+}}, 0([[NEGSHIFT]])
; CHECK-SHIFT: rll
; CHECK-SHIFT: br %r14
%res = atomicrmw xchg i16 *%src, i16 %b seq_cst
ret i16 %res
}
; Check exchange with a constant. We should force the constant into
; a register and use the sequence above.
define i16 @f2(i16 *%src) {
; CHECK: f2:
; CHECK: lhi [[VALUE:%r[0-9]+]], -25536
; CHECK: risbg {{%r[0-9]+}}, [[VALUE]], 32, 47, 16
; CHECK: br %r14
;
; CHECK-SHIFT: f2:
; CHECK-SHIFT: br %r14
%res = atomicrmw xchg i16 *%src, i16 40000 seq_cst
ret i16 %res
}

View File

@ -0,0 +1,122 @@
; Test 32-bit atomic exchange.
;
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s
; Check register exchange.
define i32 @f1(i32 %dummy, i32 *%src, i32 %b) {
; CHECK: f1:
; CHECK: l %r2, 0(%r3)
; CHECK: [[LABEL:\.[^:]*]]:
; CHECK: cs %r2, %r4, 0(%r3)
; CHECK: j{{g?}}lh [[LABEL]]
; CHECK: br %r14
%res = atomicrmw xchg i32 *%src, i32 %b seq_cst
ret i32 %res
}
; Check the high end of the aligned CS range.
define i32 @f2(i32 %dummy, i32 *%src, i32 %b) {
; CHECK: f2:
; CHECK: l %r2, 4092(%r3)
; CHECK: cs %r2, {{%r[0-9]+}}, 4092(%r3)
; CHECK: br %r14
%ptr = getelementptr i32 *%src, i64 1023
%res = atomicrmw xchg i32 *%ptr, i32 %b seq_cst
ret i32 %res
}
; Check the next word up, which requires CSY.
define i32 @f3(i32 %dummy, i32 *%src, i32 %b) {
; CHECK: f3:
; CHECK: ly %r2, 4096(%r3)
; CHECK: csy %r2, {{%r[0-9]+}}, 4096(%r3)
; CHECK: br %r14
%ptr = getelementptr i32 *%src, i64 1024
%res = atomicrmw xchg i32 *%ptr, i32 %b seq_cst
ret i32 %res
}
; Check the high end of the aligned CSY range.
define i32 @f4(i32 %dummy, i32 *%src, i32 %b) {
; CHECK: f4:
; CHECK: ly %r2, 524284(%r3)
; CHECK: csy %r2, {{%r[0-9]+}}, 524284(%r3)
; CHECK: br %r14
%ptr = getelementptr i32 *%src, i64 131071
%res = atomicrmw xchg i32 *%ptr, i32 %b seq_cst
ret i32 %res
}
; Check the next word up, which needs separate address logic.
define i32 @f5(i32 %dummy, i32 *%src, i32 %b) {
; CHECK: f5:
; CHECK: agfi %r3, 524288
; CHECK: l %r2, 0(%r3)
; CHECK: cs %r2, {{%r[0-9]+}}, 0(%r3)
; CHECK: br %r14
%ptr = getelementptr i32 *%src, i64 131072
%res = atomicrmw xchg i32 *%ptr, i32 %b seq_cst
ret i32 %res
}
; Check the high end of the negative aligned CSY range.
define i32 @f6(i32 %dummy, i32 *%src, i32 %b) {
; CHECK: f6:
; CHECK: ly %r2, -4(%r3)
; CHECK: csy %r2, {{%r[0-9]+}}, -4(%r3)
; CHECK: br %r14
%ptr = getelementptr i32 *%src, i64 -1
%res = atomicrmw xchg i32 *%ptr, i32 %b seq_cst
ret i32 %res
}
; Check the low end of the CSY range.
define i32 @f7(i32 %dummy, i32 *%src, i32 %b) {
; CHECK: f7:
; CHECK: ly %r2, -524288(%r3)
; CHECK: csy %r2, {{%r[0-9]+}}, -524288(%r3)
; CHECK: br %r14
%ptr = getelementptr i32 *%src, i64 -131072
%res = atomicrmw xchg i32 *%ptr, i32 %b seq_cst
ret i32 %res
}
; Check the next word down, which needs separate address logic.
define i32 @f8(i32 %dummy, i32 *%src, i32 %b) {
; CHECK: f8:
; CHECK: agfi %r3, -524292
; CHECK: l %r2, 0(%r3)
; CHECK: cs %r2, {{%r[0-9]+}}, 0(%r3)
; CHECK: br %r14
%ptr = getelementptr i32 *%src, i64 -131073
%res = atomicrmw xchg i32 *%ptr, i32 %b seq_cst
ret i32 %res
}
; Check that indexed addresses are not allowed.
define i32 @f9(i32 %dummy, i64 %base, i64 %index, i32 %b) {
; CHECK: f9:
; CHECK: agr %r3, %r4
; CHECK: l %r2, 0(%r3)
; CHECK: cs %r2, {{%r[0-9]+}}, 0(%r3)
; CHECK: br %r14
%add = add i64 %base, %index
%ptr = inttoptr i64 %add to i32 *
%res = atomicrmw xchg i32 *%ptr, i32 %b seq_cst
ret i32 %res
}
; Check exchange of a constant. We should force it into a register and
; use the sequence above.
define i32 @f10(i32 %dummy, i32 *%src) {
; CHECK: f10:
; CHECK: llill [[VALUE:%r[0-9+]]], 40000
; CHECK: l %r2, 0(%r3)
; CHECK: [[LABEL:\.[^:]*]]:
; CHECK: cs %r2, [[VALUE]], 0(%r3)
; CHECK: j{{g?}}lh [[LABEL]]
; CHECK: br %r14
%res = atomicrmw xchg i32 *%src, i32 40000 seq_cst
ret i32 %res
}

View File

@ -0,0 +1,88 @@
; Test 64-bit atomic exchange.
;
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s
; Check register exchange.
define i64 @f1(i64 %dummy, i64 *%src, i64 %b) {
; CHECK: f1:
; CHECK: lg %r2, 0(%r3)
; CHECK: [[LABEL:\.[^:]*]]:
; CHECK: csg %r2, %r4, 0(%r3)
; CHECK: j{{g?}}lh [[LABEL]]
; CHECK: br %r14
%res = atomicrmw xchg i64 *%src, i64 %b seq_cst
ret i64 %res
}
; Check the high end of the aligned CSG range.
define i64 @f2(i64 %dummy, i64 *%src, i64 %b) {
; CHECK: f2:
; CHECK: lg %r2, 524280(%r3)
; CHECK: csg %r2, {{%r[0-9]+}}, 524280(%r3)
; CHECK: br %r14
%ptr = getelementptr i64 *%src, i64 65535
%res = atomicrmw xchg i64 *%ptr, i64 %b seq_cst
ret i64 %res
}
; Check the next doubleword up, which requires separate address logic.
define i64 @f3(i64 %dummy, i64 *%src, i64 %b) {
; CHECK: f3:
; CHECK: agfi %r3, 524288
; CHECK: lg %r2, 0(%r3)
; CHECK: csg %r2, {{%r[0-9]+}}, 0(%r3)
; CHECK: br %r14
%ptr = getelementptr i64 *%src, i64 65536
%res = atomicrmw xchg i64 *%ptr, i64 %b seq_cst
ret i64 %res
}
; Check the low end of the CSG range.
define i64 @f4(i64 %dummy, i64 *%src, i64 %b) {
; CHECK: f4:
; CHECK: lg %r2, -524288(%r3)
; CHECK: csg %r2, {{%r[0-9]+}}, -524288(%r3)
; CHECK: br %r14
%ptr = getelementptr i64 *%src, i64 -65536
%res = atomicrmw xchg i64 *%ptr, i64 %b seq_cst
ret i64 %res
}
; Check the next doubleword down, which requires separate address logic.
define i64 @f5(i64 %dummy, i64 *%src, i64 %b) {
; CHECK: f5:
; CHECK: agfi %r3, -524296
; CHECK: lg %r2, 0(%r3)
; CHECK: csg %r2, {{%r[0-9]+}}, 0(%r3)
; CHECK: br %r14
%ptr = getelementptr i64 *%src, i64 -65537
%res = atomicrmw xchg i64 *%ptr, i64 %b seq_cst
ret i64 %res
}
; Check that indexed addresses are not allowed.
define i64 @f6(i64 %dummy, i64 %base, i64 %index, i64 %b) {
; CHECK: f6:
; CHECK: agr %r3, %r4
; CHECK: lg %r2, 0(%r3)
; CHECK: csg %r2, {{%r[0-9]+}}, 0(%r3)
; CHECK: br %r14
%add = add i64 %base, %index
%ptr = inttoptr i64 %add to i64 *
%res = atomicrmw xchg i64 *%ptr, i64 %b seq_cst
ret i64 %res
}
; Check exchange of a constant. We should force it into a register and
; use the sequence above.
define i64 @f7(i64 %dummy, i64 *%ptr) {
; CHECK: f7:
; CHECK: llilf [[VALUE:%r[0-9+]]], 3000000000
; CHECK: lg %r2, 0(%r3)
; CHECK: [[LABEL:\.[^:]*]]:
; CHECK: csg %r2, [[VALUE]], 0(%r3)
; CHECK: j{{g?}}lh [[LABEL]]
; CHECK: br %r14
%res = atomicrmw xchg i64 *%ptr, i64 3000000000 seq_cst
ret i64 %res
}

View File

@ -0,0 +1,132 @@
; Test 8-bit atomic XORs.
;
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s -check-prefix=CHECK
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s -check-prefix=CHECK-SHIFT1
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s -check-prefix=CHECK-SHIFT2
; Check XOR of a variable.
; - CHECK is for the main loop.
; - CHECK-SHIFT1 makes sure that the negated shift count used by the second
; RLL is set up correctly. The negation is independent of the NILL and L
; tested in CHECK.
; - CHECK-SHIFT2 makes sure that %b is shifted into the high part of the word
; before being used. This shift is independent of the other loop prologue
; instructions.
define i8 @f1(i8 *%src, i8 %b) {
; CHECK: f1:
; CHECK: sllg [[SHIFT:%r[1-9]+]], %r2, 3
; CHECK: nill %r2, 65532
; CHECK: l [[OLD:%r[0-9]+]], 0(%r2)
; CHECK: [[LABEL:\.[^:]*]]:
; CHECK: rll [[ROT:%r[0-9]+]], [[OLD]], 0([[SHIFT]])
; CHECK: xr [[ROT]], %r3
; CHECK: rll [[NEW:%r[0-9]+]], [[ROT]], 0({{%r[1-9]+}})
; CHECK: cs [[OLD]], [[NEW]], 0(%r2)
; CHECK: j{{g?}}lh [[LABEL]]
; CHECK: rll %r2, [[OLD]], 8([[SHIFT]])
; CHECK: br %r14
;
; CHECK-SHIFT1: f1:
; CHECK-SHIFT1: sllg [[SHIFT:%r[1-9]+]], %r2, 3
; CHECK-SHIFT1: lcr [[NEGSHIFT:%r[1-9]+]], [[SHIFT]]
; CHECK-SHIFT1: rll
; CHECK-SHIFT1: rll {{%r[0-9]+}}, {{%r[0-9]+}}, 0([[NEGSHIFT]])
; CHECK-SHIFT1: rll
; CHECK-SHIFT1: br %r14
;
; CHECK-SHIFT2: f1:
; CHECK-SHIFT2: sll %r3, 24
; CHECK-SHIFT2: rll
; CHECK-SHIFT2: xr {{%r[0-9]+}}, %r3
; CHECK-SHIFT2: rll
; CHECK-SHIFT2: rll
; CHECK-SHIFT2: br %r14
%res = atomicrmw xor i8 *%src, i8 %b seq_cst
ret i8 %res
}
; Check the minimum signed value. We XOR the rotated word with 0x80000000.
define i8 @f2(i8 *%src) {
; CHECK: f2:
; CHECK: sllg [[SHIFT:%r[1-9]+]], %r2, 3
; CHECK: nill %r2, 65532
; CHECK: l [[OLD:%r[0-9]+]], 0(%r2)
; CHECK: [[LABEL:\.[^:]*]]:
; CHECK: rll [[ROT:%r[0-9]+]], [[OLD]], 0([[SHIFT]])
; CHECK: xilf [[ROT]], 2147483648
; CHECK: rll [[NEW:%r[0-9]+]], [[ROT]], 0([[NEGSHIFT:%r[1-9]+]])
; CHECK: cs [[OLD]], [[NEW]], 0(%r2)
; CHECK: j{{g?}}lh [[LABEL]]
; CHECK: rll %r2, [[OLD]], 8([[SHIFT]])
; CHECK: br %r14
;
; CHECK-SHIFT1: f2:
; CHECK-SHIFT1: sllg [[SHIFT:%r[1-9]+]], %r2, 3
; CHECK-SHIFT1: lcr [[NEGSHIFT:%r[1-9]+]], [[SHIFT]]
; CHECK-SHIFT1: rll
; CHECK-SHIFT1: rll {{%r[0-9]+}}, {{%r[0-9]+}}, 0([[NEGSHIFT]])
; CHECK-SHIFT1: rll
; CHECK-SHIFT1: br %r14
;
; CHECK-SHIFT2: f2:
; CHECK-SHIFT2: br %r14
%res = atomicrmw xor i8 *%src, i8 -128 seq_cst
ret i8 %res
}
; Check XORs of -1. We XOR the rotated word with 0xff000000.
define i8 @f3(i8 *%src) {
; CHECK: f3:
; CHECK: xilf [[ROT]], 4278190080
; CHECK: br %r14
;
; CHECK-SHIFT1: f3:
; CHECK-SHIFT1: br %r14
; CHECK-SHIFT2: f3:
; CHECK-SHIFT2: br %r14
%res = atomicrmw xor i8 *%src, i8 -1 seq_cst
ret i8 %res
}
; Check XORs of 1. We XOR the rotated word with 0x01000000.
define i8 @f4(i8 *%src) {
; CHECK: f4:
; CHECK: xilf [[ROT]], 16777216
; CHECK: br %r14
;
; CHECK-SHIFT1: f4:
; CHECK-SHIFT1: br %r14
; CHECK-SHIFT2: f4:
; CHECK-SHIFT2: br %r14
%res = atomicrmw xor i8 *%src, i8 1 seq_cst
ret i8 %res
}
; Check the maximum signed value. We XOR the rotated word with 0x7f000000.
define i8 @f5(i8 *%src) {
; CHECK: f5:
; CHECK: xilf [[ROT]], 2130706432
; CHECK: br %r14
;
; CHECK-SHIFT1: f5:
; CHECK-SHIFT1: br %r14
; CHECK-SHIFT2: f5:
; CHECK-SHIFT2: br %r14
%res = atomicrmw xor i8 *%src, i8 127 seq_cst
ret i8 %res
}
; Check XORs of a large unsigned value. We XOR the rotated word with
; 0xfd000000.
define i8 @f6(i8 *%src) {
; CHECK: f6:
; CHECK: xilf [[ROT]], 4244635648
; CHECK: br %r14
;
; CHECK-SHIFT1: f6:
; CHECK-SHIFT1: br %r14
; CHECK-SHIFT2: f6:
; CHECK-SHIFT2: br %r14
%res = atomicrmw xor i8 *%src, i8 253 seq_cst
ret i8 %res
}

View File

@ -0,0 +1,132 @@
; Test 16-bit atomic XORs.
;
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s -check-prefix=CHECK
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s -check-prefix=CHECK-SHIFT1
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s -check-prefix=CHECK-SHIFT2
; Check XOR of a variable.
; - CHECK is for the main loop.
; - CHECK-SHIFT1 makes sure that the negated shift count used by the second
; RLL is set up correctly. The negation is independent of the NILL and L
; tested in CHECK.
; - CHECK-SHIFT2 makes sure that %b is shifted into the high part of the word
; before being used. This shift is independent of the other loop prologue
; instructions.
define i16 @f1(i16 *%src, i16 %b) {
; CHECK: f1:
; CHECK: sllg [[SHIFT:%r[1-9]+]], %r2, 3
; CHECK: nill %r2, 65532
; CHECK: l [[OLD:%r[0-9]+]], 0(%r2)
; CHECK: [[LABEL:\.[^:]*]]:
; CHECK: rll [[ROT:%r[0-9]+]], [[OLD]], 0([[SHIFT]])
; CHECK: xr [[ROT]], %r3
; CHECK: rll [[NEW:%r[0-9]+]], [[ROT]], 0({{%r[1-9]+}})
; CHECK: cs [[OLD]], [[NEW]], 0(%r2)
; CHECK: j{{g?}}lh [[LABEL]]
; CHECK: rll %r2, [[OLD]], 16([[SHIFT]])
; CHECK: br %r14
;
; CHECK-SHIFT1: f1:
; CHECK-SHIFT1: sllg [[SHIFT:%r[1-9]+]], %r2, 3
; CHECK-SHIFT1: lcr [[NEGSHIFT:%r[1-9]+]], [[SHIFT]]
; CHECK-SHIFT1: rll
; CHECK-SHIFT1: rll {{%r[0-9]+}}, {{%r[0-9]+}}, 0([[NEGSHIFT]])
; CHECK-SHIFT1: rll
; CHECK-SHIFT1: br %r14
;
; CHECK-SHIFT2: f1:
; CHECK-SHIFT2: sll %r3, 16
; CHECK-SHIFT2: rll
; CHECK-SHIFT2: xr {{%r[0-9]+}}, %r3
; CHECK-SHIFT2: rll
; CHECK-SHIFT2: rll
; CHECK-SHIFT2: br %r14
%res = atomicrmw xor i16 *%src, i16 %b seq_cst
ret i16 %res
}
; Check the minimum signed value. We XOR the rotated word with 0x80000000.
define i16 @f2(i16 *%src) {
; CHECK: f2:
; CHECK: sllg [[SHIFT:%r[1-9]+]], %r2, 3
; CHECK: nill %r2, 65532
; CHECK: l [[OLD:%r[0-9]+]], 0(%r2)
; CHECK: [[LABEL:\.[^:]*]]:
; CHECK: rll [[ROT:%r[0-9]+]], [[OLD]], 0([[SHIFT]])
; CHECK: xilf [[ROT]], 2147483648
; CHECK: rll [[NEW:%r[0-9]+]], [[ROT]], 0([[NEGSHIFT:%r[1-9]+]])
; CHECK: cs [[OLD]], [[NEW]], 0(%r2)
; CHECK: j{{g?}}lh [[LABEL]]
; CHECK: rll %r2, [[OLD]], 16([[SHIFT]])
; CHECK: br %r14
;
; CHECK-SHIFT1: f2:
; CHECK-SHIFT1: sllg [[SHIFT:%r[1-9]+]], %r2, 3
; CHECK-SHIFT1: lcr [[NEGSHIFT:%r[1-9]+]], [[SHIFT]]
; CHECK-SHIFT1: rll
; CHECK-SHIFT1: rll {{%r[0-9]+}}, {{%r[0-9]+}}, 0([[NEGSHIFT]])
; CHECK-SHIFT1: rll
; CHECK-SHIFT1: br %r14
;
; CHECK-SHIFT2: f2:
; CHECK-SHIFT2: br %r14
%res = atomicrmw xor i16 *%src, i16 -32768 seq_cst
ret i16 %res
}
; Check XORs of -1. We XOR the rotated word with 0xffff0000.
define i16 @f3(i16 *%src) {
; CHECK: f3:
; CHECK: xilf [[ROT]], 4294901760
; CHECK: br %r14
;
; CHECK-SHIFT1: f3:
; CHECK-SHIFT1: br %r14
; CHECK-SHIFT2: f3:
; CHECK-SHIFT2: br %r14
%res = atomicrmw xor i16 *%src, i16 -1 seq_cst
ret i16 %res
}
; Check XORs of 1. We XOR the rotated word with 0x00010000.
define i16 @f4(i16 *%src) {
; CHECK: f4:
; CHECK: xilf [[ROT]], 65536
; CHECK: br %r14
;
; CHECK-SHIFT1: f4:
; CHECK-SHIFT1: br %r14
; CHECK-SHIFT2: f4:
; CHECK-SHIFT2: br %r14
%res = atomicrmw xor i16 *%src, i16 1 seq_cst
ret i16 %res
}
; Check the maximum signed value. We XOR the rotated word with 0x7fff0000.
define i16 @f5(i16 *%src) {
; CHECK: f5:
; CHECK: xilf [[ROT]], 2147418112
; CHECK: br %r14
;
; CHECK-SHIFT1: f5:
; CHECK-SHIFT1: br %r14
; CHECK-SHIFT2: f5:
; CHECK-SHIFT2: br %r14
%res = atomicrmw xor i16 *%src, i16 32767 seq_cst
ret i16 %res
}
; Check XORs of a large unsigned value. We XOR the rotated word with
; 0xfffd0000.
define i16 @f6(i16 *%src) {
; CHECK: f6:
; CHECK: xilf [[ROT]], 4294770688
; CHECK: br %r14
;
; CHECK-SHIFT1: f6:
; CHECK-SHIFT1: br %r14
; CHECK-SHIFT2: f6:
; CHECK-SHIFT2: br %r14
%res = atomicrmw xor i16 *%src, i16 65533 seq_cst
ret i16 %res
}

View File

@ -0,0 +1,49 @@
; Test 32-bit atomic XORs.
;
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s
; Check XORs of a variable.
define i32 @f1(i32 %dummy, i32 *%src, i32 %b) {
; CHECK: f1:
; CHECK: l %r2, 0(%r3)
; CHECK: [[LABEL:\.[^ ]*]]:
; CHECK: lr %r0, %r2
; CHECK: xr %r0, %r4
; CHECK: cs %r2, %r0, 0(%r3)
; CHECK: j{{g?}}lh [[LABEL]]
; CHECK: br %r14
%res = atomicrmw xor i32 *%src, i32 %b seq_cst
ret i32 %res
}
; Check the lowest useful constant.
define i32 @f2(i32 %dummy, i32 *%src) {
; CHECK: f2:
; CHECK: l %r2, 0(%r3)
; CHECK: [[LABEL:\.[^ ]*]]:
; CHECK: lr %r0, %r2
; CHECK: xilf %r0, 1
; CHECK: cs %r2, %r0, 0(%r3)
; CHECK: j{{g?}}lh [[LABEL]]
; CHECK: br %r14
%res = atomicrmw xor i32 *%src, i32 1 seq_cst
ret i32 %res
}
; Check an arbitrary constant.
define i32 @f3(i32 %dummy, i32 *%src) {
; CHECK: f3:
; CHECK: xilf %r0, 3000000000
; CHECK: br %r14
%res = atomicrmw xor i32 *%src, i32 3000000000 seq_cst
ret i32 %res
}
; Check bitwise negation.
define i32 @f4(i32 %dummy, i32 *%src) {
; CHECK: f4:
; CHECK: xilf %r0, 4294967295
; CHECK: br %r14
%res = atomicrmw xor i32 *%src, i32 -1 seq_cst
ret i32 %res
}

View File

@ -0,0 +1,77 @@
; Test 64-bit atomic XORs.
;
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s
; Check XORs of a variable.
define i64 @f1(i64 %dummy, i64 *%src, i64 %b) {
; CHECK: f1:
; CHECK: lg %r2, 0(%r3)
; CHECK: [[LABEL:\.[^ ]*]]:
; CHECK: lgr %r0, %r2
; CHECK: xgr %r0, %r4
; CHECK: csg %r2, %r0, 0(%r3)
; CHECK: j{{g?}}lh [[LABEL]]
; CHECK: br %r14
%res = atomicrmw xor i64 *%src, i64 %b seq_cst
ret i64 %res
}
; Check the lowest useful XILF value.
define i64 @f2(i64 %dummy, i64 *%src) {
; CHECK: f2:
; CHECK: lg %r2, 0(%r3)
; CHECK: [[LABEL:\.[^ ]*]]:
; CHECK: lgr %r0, %r2
; CHECK: xilf %r0, 1
; CHECK: csg %r2, %r0, 0(%r3)
; CHECK: j{{g?}}lh [[LABEL]]
; CHECK: br %r14
%res = atomicrmw xor i64 *%src, i64 1 seq_cst
ret i64 %res
}
; Check the high end of the XILF range.
define i64 @f3(i64 %dummy, i64 *%src) {
; CHECK: f3:
; CHECK: xilf %r0, 4294967295
; CHECK: br %r14
%res = atomicrmw xor i64 *%src, i64 4294967295 seq_cst
ret i64 %res
}
; Check the lowest useful XIHF value, which is one greater than above.
define i64 @f4(i64 %dummy, i64 *%src) {
; CHECK: f4:
; CHECK: xihf %r0, 1
; CHECK: br %r14
%res = atomicrmw xor i64 *%src, i64 4294967296 seq_cst
ret i64 %res
}
; Check the next value up, which must use a register. (We could use
; combinations of XIH* and XIL* instead, but that isn't implemented.)
define i64 @f5(i64 %dummy, i64 *%src) {
; CHECK: f5:
; CHECK: xgr
; CHECK: br %r14
%res = atomicrmw xor i64 *%src, i64 4294967297 seq_cst
ret i64 %res
}
; Check the high end of the XIHF range.
define i64 @f6(i64 %dummy, i64 *%src) {
; CHECK: f6:
; CHECK: xihf %r0, 4294967295
; CHECK: br %r14
%res = atomicrmw xor i64 *%src, i64 -4294967296 seq_cst
ret i64 %res
}
; Check the next value up, which must use a register.
define i64 @f7(i64 %dummy, i64 *%src) {
; CHECK: f7:
; CHECK: xgr
; CHECK: br %r14
%res = atomicrmw xor i64 *%src, i64 -4294967295 seq_cst
ret i64 %res
}

View File

@ -0,0 +1,14 @@
; Test a simple unconditional jump.
;
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s
define void @f1(i8 *%dest) {
; CHECK: f1:
; CHECK: .L[[LABEL:.*]]:
; CHECK: mvi 0(%r2), 1
; CHECK: j{{g?}} .L[[LABEL]]
br label %loop
loop:
store volatile i8 1, i8 *%dest
br label %loop
}

View File

@ -0,0 +1,94 @@
; Test all condition-code masks that are relevant for signed integer
; comparisons.
;
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s
define void @f1(i32 *%src, i32 %target) {
; CHECK: f1:
; CHECK: .cfi_startproc
; CHECK: .L[[LABEL:.*]]:
; CHECK: c %r3, 0(%r2)
; CHECK-NEXT: j{{g?}}e .L[[LABEL]]
br label %loop
loop:
%val = load volatile i32 *%src
%cond = icmp eq i32 %target, %val
br i1 %cond, label %loop, label %exit
exit:
ret void
}
define void @f2(i32 *%src, i32 %target) {
; CHECK: f2:
; CHECK: .cfi_startproc
; CHECK: .L[[LABEL:.*]]:
; CHECK: c %r3, 0(%r2)
; CHECK-NEXT: j{{g?}}lh .L[[LABEL]]
br label %loop
loop:
%val = load volatile i32 *%src
%cond = icmp ne i32 %target, %val
br i1 %cond, label %loop, label %exit
exit:
ret void
}
define void @f3(i32 *%src, i32 %target) {
; CHECK: f3:
; CHECK: .cfi_startproc
; CHECK: .L[[LABEL:.*]]:
; CHECK: c %r3, 0(%r2)
; CHECK-NEXT: j{{g?}}le .L[[LABEL]]
br label %loop
loop:
%val = load volatile i32 *%src
%cond = icmp sle i32 %target, %val
br i1 %cond, label %loop, label %exit
exit:
ret void
}
define void @f4(i32 *%src, i32 %target) {
; CHECK: f4:
; CHECK: .cfi_startproc
; CHECK: .L[[LABEL:.*]]:
; CHECK: c %r3, 0(%r2)
; CHECK-NEXT: j{{g?}}l .L[[LABEL]]
br label %loop
loop:
%val = load volatile i32 *%src
%cond = icmp slt i32 %target, %val
br i1 %cond, label %loop, label %exit
exit:
ret void
}
define void @f5(i32 *%src, i32 %target) {
; CHECK: f5:
; CHECK: .cfi_startproc
; CHECK: .L[[LABEL:.*]]:
; CHECK: c %r3, 0(%r2)
; CHECK-NEXT: j{{g?}}h .L[[LABEL]]
br label %loop
loop:
%val = load volatile i32 *%src
%cond = icmp sgt i32 %target, %val
br i1 %cond, label %loop, label %exit
exit:
ret void
}
define void @f6(i32 *%src, i32 %target) {
; CHECK: f6:
; CHECK: .cfi_startproc
; CHECK: .L[[LABEL:.*]]:
; CHECK: c %r3, 0(%r2)
; CHECK-NEXT: j{{g?}}he .L[[LABEL]]
br label %loop
loop:
%val = load volatile i32 *%src
%cond = icmp sge i32 %target, %val
br i1 %cond, label %loop, label %exit
exit:
ret void
}

View File

@ -0,0 +1,63 @@
; Test all condition-code masks that are relevant for unsigned integer
; comparisons.
;
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s
define void @f1(i32 *%src, i32 %target) {
; CHECK: f1:
; CHECK: .cfi_startproc
; CHECK: .L[[LABEL:.*]]:
; CHECK: cl %r3, 0(%r2)
; CHECK-NEXT: j{{g?}}le .L[[LABEL]]
br label %loop
loop:
%val = load volatile i32 *%src
%cond = icmp ule i32 %target, %val
br i1 %cond, label %loop, label %exit
exit:
ret void
}
define void @f2(i32 *%src, i32 %target) {
; CHECK: f2:
; CHECK: .cfi_startproc
; CHECK: .L[[LABEL:.*]]:
; CHECK: cl %r3, 0(%r2)
; CHECK-NEXT: j{{g?}}l .L[[LABEL]]
br label %loop
loop:
%val = load volatile i32 *%src
%cond = icmp ult i32 %target, %val
br i1 %cond, label %loop, label %exit
exit:
ret void
}
define void @f3(i32 *%src, i32 %target) {
; CHECK: f3:
; CHECK: .cfi_startproc
; CHECK: .L[[LABEL:.*]]:
; CHECK: cl %r3, 0(%r2)
; CHECK-NEXT: j{{g?}}h .L[[LABEL]]
br label %loop
loop:
%val = load volatile i32 *%src
%cond = icmp ugt i32 %target, %val
br i1 %cond, label %loop, label %exit
exit:
ret void
}
define void @f4(i32 *%src, i32 %target) {
; CHECK: f4:
; CHECK: .cfi_startproc
; CHECK: .L[[LABEL:.*]]:
; CHECK: cl %r3, 0(%r2)
; CHECK-NEXT: j{{g?}}he .L[[LABEL]]
br label %loop
loop:
%val = load volatile i32 *%src
%cond = icmp uge i32 %target, %val
br i1 %cond, label %loop, label %exit
exit:
ret void
}

View File

@ -0,0 +1,218 @@
; Test all condition-code masks that are relevant for floating-point
; comparisons.
;
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s
define void @f1(float *%src, float %target) {
; CHECK: f1:
; CHECK: .cfi_startproc
; CHECK: .L[[LABEL:.*]]:
; CHECK: ceb %f0, 0(%r2)
; CHECK-NEXT: j{{g?}}e .L[[LABEL]]
br label %loop
loop:
%val = load volatile float *%src
%cond = fcmp oeq float %target, %val
br i1 %cond, label %loop, label %exit
exit:
ret void
}
define void @f2(float *%src, float %target) {
; CHECK: f2:
; CHECK: .cfi_startproc
; CHECK: .L[[LABEL:.*]]:
; CHECK: ceb %f0, 0(%r2)
; CHECK-NEXT: j{{g?}}lh .L[[LABEL]]
br label %loop
loop:
%val = load volatile float *%src
%cond = fcmp one float %target, %val
br i1 %cond, label %loop, label %exit
exit:
ret void
}
define void @f3(float *%src, float %target) {
; CHECK: f3:
; CHECK: .cfi_startproc
; CHECK: .L[[LABEL:.*]]:
; CHECK: ceb %f0, 0(%r2)
; CHECK-NEXT: j{{g?}}le .L[[LABEL]]
br label %loop
loop:
%val = load volatile float *%src
%cond = fcmp ole float %target, %val
br i1 %cond, label %loop, label %exit
exit:
ret void
}
define void @f4(float *%src, float %target) {
; CHECK: f4:
; CHECK: .cfi_startproc
; CHECK: .L[[LABEL:.*]]:
; CHECK: ceb %f0, 0(%r2)
; CHECK-NEXT: j{{g?}}l .L[[LABEL]]
br label %loop
loop:
%val = load volatile float *%src
%cond = fcmp olt float %target, %val
br i1 %cond, label %loop, label %exit
exit:
ret void
}
define void @f5(float *%src, float %target) {
; CHECK: f5:
; CHECK: .cfi_startproc
; CHECK: .L[[LABEL:.*]]:
; CHECK: ceb %f0, 0(%r2)
; CHECK-NEXT: j{{g?}}h .L[[LABEL]]
br label %loop
loop:
%val = load volatile float *%src
%cond = fcmp ogt float %target, %val
br i1 %cond, label %loop, label %exit
exit:
ret void
}
define void @f6(float *%src, float %target) {
; CHECK: f6:
; CHECK: .cfi_startproc
; CHECK: .L[[LABEL:.*]]:
; CHECK: ceb %f0, 0(%r2)
; CHECK-NEXT: j{{g?}}he .L[[LABEL]]
br label %loop
loop:
%val = load volatile float *%src
%cond = fcmp oge float %target, %val
br i1 %cond, label %loop, label %exit
exit:
ret void
}
define void @f7(float *%src, float %target) {
; CHECK: f7:
; CHECK: .cfi_startproc
; CHECK: .L[[LABEL:.*]]:
; CHECK: ceb %f0, 0(%r2)
; CHECK-NEXT: j{{g?}}nlh .L[[LABEL]]
br label %loop
loop:
%val = load volatile float *%src
%cond = fcmp ueq float %target, %val
br i1 %cond, label %loop, label %exit
exit:
ret void
}
define void @f8(float *%src, float %target) {
; CHECK: f8:
; CHECK: .cfi_startproc
; CHECK: .L[[LABEL:.*]]:
; CHECK: ceb %f0, 0(%r2)
; CHECK-NEXT: j{{g?}}ne .L[[LABEL]]
br label %loop
loop:
%val = load volatile float *%src
%cond = fcmp une float %target, %val
br i1 %cond, label %loop, label %exit
exit:
ret void
}
define void @f9(float *%src, float %target) {
; CHECK: f9:
; CHECK: .cfi_startproc
; CHECK: .L[[LABEL:.*]]:
; CHECK: ceb %f0, 0(%r2)
; CHECK-NEXT: j{{g?}}nh .L[[LABEL]]
br label %loop
loop:
%val = load volatile float *%src
%cond = fcmp ule float %target, %val
br i1 %cond, label %loop, label %exit
exit:
ret void
}
define void @f10(float *%src, float %target) {
; CHECK: f10:
; CHECK: .cfi_startproc
; CHECK: .L[[LABEL:.*]]:
; CHECK: ceb %f0, 0(%r2)
; CHECK-NEXT: j{{g?}}nhe .L[[LABEL]]
br label %loop
loop:
%val = load volatile float *%src
%cond = fcmp ult float %target, %val
br i1 %cond, label %loop, label %exit
exit:
ret void
}
define void @f11(float *%src, float %target) {
; CHECK: f11:
; CHECK: .cfi_startproc
; CHECK: .L[[LABEL:.*]]:
; CHECK: ceb %f0, 0(%r2)
; CHECK-NEXT: j{{g?}}nle .L[[LABEL]]
br label %loop
loop:
%val = load volatile float *%src
%cond = fcmp ugt float %target, %val
br i1 %cond, label %loop, label %exit
exit:
ret void
}
define void @f12(float *%src, float %target) {
; CHECK: f12:
; CHECK: .cfi_startproc
; CHECK: .L[[LABEL:.*]]:
; CHECK: ceb %f0, 0(%r2)
; CHECK-NEXT: j{{g?}}nl .L[[LABEL]]
br label %loop
loop:
%val = load volatile float *%src
%cond = fcmp uge float %target, %val
br i1 %cond, label %loop, label %exit
exit:
ret void
}
; "jno" == "jump if no overflow", which corresponds to "jump if ordered"
; rather than "jump if not ordered" after a floating-point comparison.
define void @f13(float *%src, float %target) {
; CHECK: f13:
; CHECK: .cfi_startproc
; CHECK: .L[[LABEL:.*]]:
; CHECK: ceb %f0, 0(%r2)
; CHECK-NEXT: j{{g?}}no .L[[LABEL]]
br label %loop
loop:
%val = load volatile float *%src
%cond = fcmp ord float %target, %val
br i1 %cond, label %loop, label %exit
exit:
ret void
}
; "jo" == "jump if overflow", which corresponds to "jump if not ordered"
; rather than "jump if ordered" after a floating-point comparison.
define void @f14(float *%src, float %target) {
; CHECK: f14:
; CHECK: .cfi_startproc
; CHECK: .L[[LABEL:.*]]:
; CHECK: ceb %f0, 0(%r2)
; CHECK-NEXT: j{{g?}}o .L[[LABEL]]
br label %loop
loop:
%val = load volatile float *%src
%cond = fcmp uno float %target, %val
br i1 %cond, label %loop, label %exit
exit:
ret void
}

View File

@ -0,0 +1,58 @@
; Test indirect jumps.
;
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s
define i32 @f1(i32 %x, i32 %y, i32 %op) {
; CHECK: f1:
; CHECK: ahi %r4, -1
; CHECK: clfi %r4, 5
; CHECK-NEXT: j{{g?}}g
; CHECK: llgfr [[OP64:%r[0-5]]], %r4
; CHECK: sllg [[INDEX:%r[1-5]]], [[OP64]], 3
; CHECK: larl [[BASE:%r[1-5]]]
; CHECK: lg [[TARGET:%r[1-5]]], 0([[BASE]],[[INDEX]])
; CHECK: br [[TARGET]]
entry:
switch i32 %op, label %exit [
i32 1, label %b.add
i32 2, label %b.sub
i32 3, label %b.and
i32 4, label %b.or
i32 5, label %b.xor
i32 6, label %b.mul
]
b.add:
%add = add i32 %x, %y
br label %exit
b.sub:
%sub = sub i32 %x, %y
br label %exit
b.and:
%and = and i32 %x, %y
br label %exit
b.or:
%or = or i32 %x, %y
br label %exit
b.xor:
%xor = xor i32 %x, %y
br label %exit
b.mul:
%mul = mul i32 %x, %y
br label %exit
exit:
%res = phi i32 [ %x, %entry ],
[ %add, %b.add ],
[ %sub, %b.sub ],
[ %and, %b.and ],
[ %or, %b.or ],
[ %xor, %b.xor ],
[ %mul, %b.mul ]
ret i32 %res
}

View File

@ -0,0 +1,24 @@
; Test byteswaps between registers.
;
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s
declare i32 @llvm.bswap.i32(i32 %a)
declare i64 @llvm.bswap.i64(i64 %a)
; Check 32-bit register-to-register byteswaps.
define i32 @f1(i32 %a) {
; CHECK: f1:
; CHECK: lrvr [[REGISTER:%r[0-5]]], %r2
; CHECk: br %r14
%swapped = call i32 @llvm.bswap.i32(i32 %a)
ret i32 %swapped
}
; Check 64-bit register-to-register byteswaps.
define i64 @f2(i64 %a) {
; CHECK: f2:
; CHECK: lrvgr %r2, %r2
; CHECk: br %r14
%swapped = call i64 @llvm.bswap.i64(i64 %a)
ret i64 %swapped
}

View File

@ -0,0 +1,87 @@
; Test 32-bit byteswaps from memory to registers.
;
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s
declare i32 @llvm.bswap.i32(i32 %a)
; Check LRV with no displacement.
define i32 @f1(i32 *%src) {
; CHECK: f1:
; CHECK: lrv %r2, 0(%r2)
; CHECK: br %r14
%a = load i32 *%src
%swapped = call i32 @llvm.bswap.i32(i32 %a)
ret i32 %swapped
}
; Check the high end of the aligned LRV range.
define i32 @f2(i32 *%src) {
; CHECK: f2:
; CHECK: lrv %r2, 524284(%r2)
; CHECK: br %r14
%ptr = getelementptr i32 *%src, i64 131071
%a = load i32 *%ptr
%swapped = call i32 @llvm.bswap.i32(i32 %a)
ret i32 %swapped
}
; Check the next word up, which needs separate address logic.
; Other sequences besides this one would be OK.
define i32 @f3(i32 *%src) {
; CHECK: f3:
; CHECK: agfi %r2, 524288
; CHECK: lrv %r2, 0(%r2)
; CHECK: br %r14
%ptr = getelementptr i32 *%src, i64 131072
%a = load i32 *%ptr
%swapped = call i32 @llvm.bswap.i32(i32 %a)
ret i32 %swapped
}
; Check the high end of the negative aligned LRV range.
define i32 @f4(i32 *%src) {
; CHECK: f4:
; CHECK: lrv %r2, -4(%r2)
; CHECK: br %r14
%ptr = getelementptr i32 *%src, i64 -1
%a = load i32 *%ptr
%swapped = call i32 @llvm.bswap.i32(i32 %a)
ret i32 %swapped
}
; Check the low end of the LRV range.
define i32 @f5(i32 *%src) {
; CHECK: f5:
; CHECK: lrv %r2, -524288(%r2)
; CHECK: br %r14
%ptr = getelementptr i32 *%src, i64 -131072
%a = load i32 *%ptr
%swapped = call i32 @llvm.bswap.i32(i32 %a)
ret i32 %swapped
}
; Check the next word down, which needs separate address logic.
; Other sequences besides this one would be OK.
define i32 @f6(i32 *%src) {
; CHECK: f6:
; CHECK: agfi %r2, -524292
; CHECK: lrv %r2, 0(%r2)
; CHECK: br %r14
%ptr = getelementptr i32 *%src, i64 -131073
%a = load i32 *%ptr
%swapped = call i32 @llvm.bswap.i32(i32 %a)
ret i32 %swapped
}
; Check that LRV allows an index.
define i32 @f7(i64 %src, i64 %index) {
; CHECK: f7:
; CHECK: lrv %r2, 524287({{%r3,%r2|%r2,%r3}})
; CHECK: br %r14
%add1 = add i64 %src, %index
%add2 = add i64 %add1, 524287
%ptr = inttoptr i64 %add2 to i32 *
%a = load i32 *%ptr
%swapped = call i32 @llvm.bswap.i32(i32 %a)
ret i32 %swapped
}

View File

@ -0,0 +1,87 @@
; Test 64-bit byteswaps from memory to registers.
;
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s
declare i64 @llvm.bswap.i64(i64 %a)
; Check LRVG with no displacement.
define i64 @f1(i64 *%src) {
; CHECK: f1:
; CHECK: lrvg %r2, 0(%r2)
; CHECK: br %r14
%a = load i64 *%src
%swapped = call i64 @llvm.bswap.i64(i64 %a)
ret i64 %swapped
}
; Check the high end of the aligned LRVG range.
define i64 @f2(i64 *%src) {
; CHECK: f2:
; CHECK: lrvg %r2, 524280(%r2)
; CHECK: br %r14
%ptr = getelementptr i64 *%src, i64 65535
%a = load i64 *%ptr
%swapped = call i64 @llvm.bswap.i64(i64 %a)
ret i64 %swapped
}
; Check the next doubleword up, which needs separate address logic.
; Other sequences besides this one would be OK.
define i64 @f3(i64 *%src) {
; CHECK: f3:
; CHECK: agfi %r2, 524288
; CHECK: lrvg %r2, 0(%r2)
; CHECK: br %r14
%ptr = getelementptr i64 *%src, i64 65536
%a = load i64 *%ptr
%swapped = call i64 @llvm.bswap.i64(i64 %a)
ret i64 %swapped
}
; Check the high end of the negative aligned LRVG range.
define i64 @f4(i64 *%src) {
; CHECK: f4:
; CHECK: lrvg %r2, -8(%r2)
; CHECK: br %r14
%ptr = getelementptr i64 *%src, i64 -1
%a = load i64 *%ptr
%swapped = call i64 @llvm.bswap.i64(i64 %a)
ret i64 %swapped
}
; Check the low end of the LRVG range.
define i64 @f5(i64 *%src) {
; CHECK: f5:
; CHECK: lrvg %r2, -524288(%r2)
; CHECK: br %r14
%ptr = getelementptr i64 *%src, i64 -65536
%a = load i64 *%ptr
%swapped = call i64 @llvm.bswap.i64(i64 %a)
ret i64 %swapped
}
; Check the next doubleword down, which needs separate address logic.
; Other sequences besides this one would be OK.
define i64 @f6(i64 *%src) {
; CHECK: f6:
; CHECK: agfi %r2, -524296
; CHECK: lrvg %r2, 0(%r2)
; CHECK: br %r14
%ptr = getelementptr i64 *%src, i64 -65537
%a = load i64 *%ptr
%swapped = call i64 @llvm.bswap.i64(i64 %a)
ret i64 %swapped
}
; Check that LRVG allows an index.
define i64 @f7(i64 %src, i64 %index) {
; CHECK: f7:
; CHECK: lrvg %r2, 524287({{%r3,%r2|%r2,%r3}})
; CHECK: br %r14
%add1 = add i64 %src, %index
%add2 = add i64 %add1, 524287
%ptr = inttoptr i64 %add2 to i64 *
%a = load i64 *%ptr
%swapped = call i64 @llvm.bswap.i64(i64 %a)
ret i64 %swapped
}

View File

@ -0,0 +1,87 @@
; Test 32-bit byteswaps from registers to memory.
;
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s
declare i32 @llvm.bswap.i32(i32 %a)
; Check STRV with no displacement.
define void @f1(i32 *%src, i32 %a) {
; CHECK: f1:
; CHECK: strv %r3, 0(%r2)
; CHECK: br %r14
%swapped = call i32 @llvm.bswap.i32(i32 %a)
store i32 %swapped, i32 *%src
ret void
}
; Check the high end of the aligned STRV range.
define void @f2(i32 *%src, i32 %a) {
; CHECK: f2:
; CHECK: strv %r3, 524284(%r2)
; CHECK: br %r14
%ptr = getelementptr i32 *%src, i64 131071
%swapped = call i32 @llvm.bswap.i32(i32 %a)
store i32 %swapped, i32 *%ptr
ret void
}
; Check the next word up, which needs separate address logic.
; Other sequences besides this one would be OK.
define void @f3(i32 *%src, i32 %a) {
; CHECK: f3:
; CHECK: agfi %r2, 524288
; CHECK: strv %r3, 0(%r2)
; CHECK: br %r14
%ptr = getelementptr i32 *%src, i64 131072
%swapped = call i32 @llvm.bswap.i32(i32 %a)
store i32 %swapped, i32 *%ptr
ret void
}
; Check the high end of the negative aligned STRV range.
define void @f4(i32 *%src, i32 %a) {
; CHECK: f4:
; CHECK: strv %r3, -4(%r2)
; CHECK: br %r14
%ptr = getelementptr i32 *%src, i64 -1
%swapped = call i32 @llvm.bswap.i32(i32 %a)
store i32 %swapped, i32 *%ptr
ret void
}
; Check the low end of the STRV range.
define void @f5(i32 *%src, i32 %a) {
; CHECK: f5:
; CHECK: strv %r3, -524288(%r2)
; CHECK: br %r14
%ptr = getelementptr i32 *%src, i64 -131072
%swapped = call i32 @llvm.bswap.i32(i32 %a)
store i32 %swapped, i32 *%ptr
ret void
}
; Check the next word down, which needs separate address logic.
; Other sequences besides this one would be OK.
define void @f6(i32 *%src, i32 %a) {
; CHECK: f6:
; CHECK: agfi %r2, -524292
; CHECK: strv %r3, 0(%r2)
; CHECK: br %r14
%ptr = getelementptr i32 *%src, i64 -131073
%swapped = call i32 @llvm.bswap.i32(i32 %a)
store i32 %swapped, i32 *%ptr
ret void
}
; Check that STRV allows an index.
define void @f7(i64 %src, i64 %index, i32 %a) {
; CHECK: f7:
; CHECK: strv %r4, 524287({{%r3,%r2|%r2,%r3}})
; CHECK: br %r14
%add1 = add i64 %src, %index
%add2 = add i64 %add1, 524287
%ptr = inttoptr i64 %add2 to i32 *
%swapped = call i32 @llvm.bswap.i32(i32 %a)
store i32 %swapped, i32 *%ptr
ret void
}

View File

@ -0,0 +1,87 @@
; Test 64-bit byteswaps from registers to memory.
;
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s
declare i64 @llvm.bswap.i64(i64 %a)
; Check STRVG with no displacement.
define void @f1(i64 *%src, i64 %a) {
; CHECK: f1:
; CHECK: strvg %r3, 0(%r2)
; CHECK: br %r14
%swapped = call i64 @llvm.bswap.i64(i64 %a)
store i64 %swapped, i64 *%src
ret void
}
; Check the high end of the aligned STRVG range.
define void @f2(i64 *%src, i64 %a) {
; CHECK: f2:
; CHECK: strvg %r3, 524280(%r2)
; CHECK: br %r14
%ptr = getelementptr i64 *%src, i64 65535
%swapped = call i64 @llvm.bswap.i64(i64 %a)
store i64 %swapped, i64 *%ptr
ret void
}
; Check the next doubleword up, which needs separate address logic.
; Other sequences besides this one would be OK.
define void @f3(i64 *%src, i64 %a) {
; CHECK: f3:
; CHECK: agfi %r2, 524288
; CHECK: strvg %r3, 0(%r2)
; CHECK: br %r14
%ptr = getelementptr i64 *%src, i64 65536
%swapped = call i64 @llvm.bswap.i64(i64 %a)
store i64 %swapped, i64 *%ptr
ret void
}
; Check the high end of the negative aligned STRVG range.
define void @f4(i64 *%src, i64 %a) {
; CHECK: f4:
; CHECK: strvg %r3, -8(%r2)
; CHECK: br %r14
%ptr = getelementptr i64 *%src, i64 -1
%swapped = call i64 @llvm.bswap.i64(i64 %a)
store i64 %swapped, i64 *%ptr
ret void
}
; Check the low end of the STRVG range.
define void @f5(i64 *%src, i64 %a) {
; CHECK: f5:
; CHECK: strvg %r3, -524288(%r2)
; CHECK: br %r14
%ptr = getelementptr i64 *%src, i64 -65536
%swapped = call i64 @llvm.bswap.i64(i64 %a)
store i64 %swapped, i64 *%ptr
ret void
}
; Check the next doubleword down, which needs separate address logic.
; Other sequences besides this one would be OK.
define void @f6(i64 *%src, i64 %a) {
; CHECK: f6:
; CHECK: agfi %r2, -524296
; CHECK: strvg %r3, 0(%r2)
; CHECK: br %r14
%ptr = getelementptr i64 *%src, i64 -65537
%swapped = call i64 @llvm.bswap.i64(i64 %a)
store i64 %swapped, i64 *%ptr
ret void
}
; Check that STRVG allows an index.
define void @f7(i64 %src, i64 %index, i64 %a) {
; CHECK: f7:
; CHECK: strvg %r4, 524287({{%r3,%r2|%r2,%r3}})
; CHECK: br %r14
%add1 = add i64 %src, %index
%add2 = add i64 %add1, 524287
%ptr = inttoptr i64 %add2 to i64 *
%swapped = call i64 @llvm.bswap.i64(i64 %a)
store i64 %swapped, i64 *%ptr
ret void
}

View File

@ -0,0 +1,18 @@
; Test direct calls.
;
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s
declare i64 @bar()
; We must allocate 160 bytes for the callee and save and restore %r14.
define i64 @f1() {
; CHECK: f1:
; CHECK: stmg %r14, %r15, 112(%r15)
; CHECK: aghi %r15, -160
; CHECK: brasl %r14, bar@PLT
; CHECK: lmg %r14, %r15, 272(%r15)
; CHECK: br %r14
%ret = call i64 @bar()
%inc = add i64 %ret, 1
ret i64 %inc
}

View File

@ -0,0 +1,16 @@
; Test indirect calls.
;
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s
; We must allocate 160 bytes for the callee and save and restore %r14.
define i64 @f1(i64() *%bar) {
; CHECK: f1:
; CHECK: stmg %r14, %r15, 112(%r15)
; CHECK: aghi %r15, -160
; CHECK: basr %r14, %r2
; CHECK: lmg %r14, %r15, 272(%r15)
; CHECK: br %r14
%ret = call i64 %bar()
%inc = add i64 %ret, 1
ret i64 %inc
}

View File

@ -0,0 +1,56 @@
; Test 8-bit compare and swap.
;
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s -check-prefix=CHECK-MAIN
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s -check-prefix=CHECK-SHIFT
; Check compare and swap with a variable.
; - CHECK is for the main loop.
; - CHECK-SHIFT makes sure that the negated shift count used by the second
; RLL is set up correctly. The negation is independent of the NILL and L
; tested in CHECK. CHECK-SHIFT also checks that %r3 is not modified before
; being used in the RISBG (in contrast to things like atomic addition,
; which shift %r3 left so that %b is at the high end of the word).
define i8 @f1(i8 %dummy, i8 *%src, i8 %cmp, i8 %swap) {
; CHECK-MAIN: f1:
; CHECK-MAIN: sllg [[SHIFT:%r[1-9]+]], %r3, 3
; CHECK-MAIN: nill %r3, 65532
; CHECK-MAIN: l [[OLD:%r[0-9]+]], 0(%r3)
; CHECK-MAIN: [[LOOP:\.[^ ]*]]:
; CHECK-MAIN: rll %r2, [[OLD]], 8([[SHIFT]])
; CHECK-MAIN: risbg %r4, %r2, 32, 55, 0
; CHECK-MAIN: cr %r2, %r4
; CHECK-MAIN: j{{g?}}lh [[EXIT:\.[^ ]*]]
; CHECK-MAIN: risbg %r5, %r2, 32, 55, 0
; CHECK-MAIN: rll [[NEW:%r[0-9]+]], %r5, -8({{%r[1-9]+}})
; CHECK-MAIN: cs [[OLD]], [[NEW]], 0(%r3)
; CHECK-MAIN: j{{g?}}lh [[LOOP]]
; CHECK-MAIN: [[EXIT]]:
; CHECK-MAIN-NOT: %r2
; CHECK-MAIN: br %r14
;
; CHECK-SHIFT: f1:
; CHECK-SHIFT: sllg [[SHIFT:%r[1-9]+]], %r3, 3
; CHECK-SHIFT: lcr [[NEGSHIFT:%r[1-9]+]], [[SHIFT]]
; CHECK-SHIFT: rll
; CHECK-SHIFT: rll {{%r[0-9]+}}, %r5, -8([[NEGSHIFT]])
%res = cmpxchg i8 *%src, i8 %cmp, i8 %swap seq_cst
ret i8 %res
}
; Check compare and swap with constants. We should force the constants into
; registers and use the sequence above.
define i8 @f2(i8 *%src) {
; CHECK: f2:
; CHECK: lhi [[CMP:%r[0-9]+]], 42
; CHECK: risbg [[CMP]], {{%r[0-9]+}}, 32, 55, 0
; CHECK: risbg
; CHECK: br %r14
;
; CHECK-SHIFT: f2:
; CHECK-SHIFT: lhi [[SWAP:%r[0-9]+]], 88
; CHECK-SHIFT: risbg
; CHECK-SHIFT: risbg [[SWAP]], {{%r[0-9]+}}, 32, 55, 0
; CHECK-SHIFT: br %r14
%res = cmpxchg i8 *%src, i8 42, i8 88 seq_cst
ret i8 %res
}

View File

@ -0,0 +1,56 @@
; Test 16-bit compare and swap.
;
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s -check-prefix=CHECK-MAIN
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s -check-prefix=CHECK-SHIFT
; Check compare and swap with a variable.
; - CHECK is for the main loop.
; - CHECK-SHIFT makes sure that the negated shift count used by the second
; RLL is set up correctly. The negation is independent of the NILL and L
; tested in CHECK. CHECK-SHIFT also checks that %r3 is not modified before
; being used in the RISBG (in contrast to things like atomic addition,
; which shift %r3 left so that %b is at the high end of the word).
define i16 @f1(i16 %dummy, i16 *%src, i16 %cmp, i16 %swap) {
; CHECK-MAIN: f1:
; CHECK-MAIN: sllg [[SHIFT:%r[1-9]+]], %r3, 3
; CHECK-MAIN: nill %r3, 65532
; CHECK-MAIN: l [[OLD:%r[0-9]+]], 0(%r3)
; CHECK-MAIN: [[LOOP:\.[^ ]*]]:
; CHECK-MAIN: rll %r2, [[OLD]], 16([[SHIFT]])
; CHECK-MAIN: risbg %r4, %r2, 32, 47, 0
; CHECK-MAIN: cr %r2, %r4
; CHECK-MAIN: j{{g?}}lh [[EXIT:\.[^ ]*]]
; CHECK-MAIN: risbg %r5, %r2, 32, 47, 0
; CHECK-MAIN: rll [[NEW:%r[0-9]+]], %r5, -16({{%r[1-9]+}})
; CHECK-MAIN: cs [[OLD]], [[NEW]], 0(%r3)
; CHECK-MAIN: j{{g?}}lh [[LOOP]]
; CHECK-MAIN: [[EXIT]]:
; CHECK-MAIN-NOT: %r2
; CHECK-MAIN: br %r14
;
; CHECK-SHIFT: f1:
; CHECK-SHIFT: sllg [[SHIFT:%r[1-9]+]], %r3, 3
; CHECK-SHIFT: lcr [[NEGSHIFT:%r[1-9]+]], [[SHIFT]]
; CHECK-SHIFT: rll
; CHECK-SHIFT: rll {{%r[0-9]+}}, %r5, -16([[NEGSHIFT]])
%res = cmpxchg i16 *%src, i16 %cmp, i16 %swap seq_cst
ret i16 %res
}
; Check compare and swap with constants. We should force the constants into
; registers and use the sequence above.
define i16 @f2(i16 *%src) {
; CHECK: f2:
; CHECK: lhi [[CMP:%r[0-9]+]], 42
; CHECK: risbg [[CMP]], {{%r[0-9]+}}, 32, 47, 0
; CHECK: risbg
; CHECK: br %r14
;
; CHECK-SHIFT: f2:
; CHECK-SHIFT: lhi [[SWAP:%r[0-9]+]], 88
; CHECK-SHIFT: risbg
; CHECK-SHIFT: risbg [[SWAP]], {{%r[0-9]+}}, 32, 47, 0
; CHECK-SHIFT: br %r14
%res = cmpxchg i16 *%src, i16 42, i16 88 seq_cst
ret i16 %res
}

View File

@ -0,0 +1,131 @@
; Test 32-bit compare and swap.
;
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s
; Check the low end of the CS range.
define i32 @f1(i32 %cmp, i32 %swap, i32 *%src) {
; CHECK: f1:
; CHECK: cs %r2, %r3, 0(%r4)
; CHECK: br %r14
%val = cmpxchg i32 *%src, i32 %cmp, i32 %swap seq_cst
ret i32 %val
}
; Check the high end of the aligned CS range.
define i32 @f2(i32 %cmp, i32 %swap, i32 *%src) {
; CHECK: f2:
; CHECK: cs %r2, %r3, 4092(%r4)
; CHECK: br %r14
%ptr = getelementptr i32 *%src, i64 1023
%val = cmpxchg i32 *%ptr, i32 %cmp, i32 %swap seq_cst
ret i32 %val
}
; Check the next word up, which should use CSY instead of CS.
define i32 @f3(i32 %cmp, i32 %swap, i32 *%src) {
; CHECK: f3:
; CHECK: csy %r2, %r3, 4096(%r4)
; CHECK: br %r14
%ptr = getelementptr i32 *%src, i64 1024
%val = cmpxchg i32 *%ptr, i32 %cmp, i32 %swap seq_cst
ret i32 %val
}
; Check the high end of the aligned CSY range.
define i32 @f4(i32 %cmp, i32 %swap, i32 *%src) {
; CHECK: f4:
; CHECK: csy %r2, %r3, 524284(%r4)
; CHECK: br %r14
%ptr = getelementptr i32 *%src, i64 131071
%val = cmpxchg i32 *%ptr, i32 %cmp, i32 %swap seq_cst
ret i32 %val
}
; Check the next word up, which needs separate address logic.
; Other sequences besides this one would be OK.
define i32 @f5(i32 %cmp, i32 %swap, i32 *%src) {
; CHECK: f5:
; CHECK: agfi %r4, 524288
; CHECK: cs %r2, %r3, 0(%r4)
; CHECK: br %r14
%ptr = getelementptr i32 *%src, i64 131072
%val = cmpxchg i32 *%ptr, i32 %cmp, i32 %swap seq_cst
ret i32 %val
}
; Check the high end of the negative aligned CSY range.
define i32 @f6(i32 %cmp, i32 %swap, i32 *%src) {
; CHECK: f6:
; CHECK: csy %r2, %r3, -4(%r4)
; CHECK: br %r14
%ptr = getelementptr i32 *%src, i64 -1
%val = cmpxchg i32 *%ptr, i32 %cmp, i32 %swap seq_cst
ret i32 %val
}
; Check the low end of the CSY range.
define i32 @f7(i32 %cmp, i32 %swap, i32 *%src) {
; CHECK: f7:
; CHECK: csy %r2, %r3, -524288(%r4)
; CHECK: br %r14
%ptr = getelementptr i32 *%src, i64 -131072
%val = cmpxchg i32 *%ptr, i32 %cmp, i32 %swap seq_cst
ret i32 %val
}
; Check the next word down, which needs separate address logic.
; Other sequences besides this one would be OK.
define i32 @f8(i32 %cmp, i32 %swap, i32 *%src) {
; CHECK: f8:
; CHECK: agfi %r4, -524292
; CHECK: cs %r2, %r3, 0(%r4)
; CHECK: br %r14
%ptr = getelementptr i32 *%src, i64 -131073
%val = cmpxchg i32 *%ptr, i32 %cmp, i32 %swap seq_cst
ret i32 %val
}
; Check that CS does not allow an index.
define i32 @f9(i32 %cmp, i32 %swap, i64 %src, i64 %index) {
; CHECK: f9:
; CHECK: agr %r4, %r5
; CHECK: cs %r2, %r3, 0(%r4)
; CHECK: br %r14
%add1 = add i64 %src, %index
%ptr = inttoptr i64 %add1 to i32 *
%val = cmpxchg i32 *%ptr, i32 %cmp, i32 %swap seq_cst
ret i32 %val
}
; Check that CSY does not allow an index.
define i32 @f10(i32 %cmp, i32 %swap, i64 %src, i64 %index) {
; CHECK: f10:
; CHECK: agr %r4, %r5
; CHECK: csy %r2, %r3, 4096(%r4)
; CHECK: br %r14
%add1 = add i64 %src, %index
%add2 = add i64 %add1, 4096
%ptr = inttoptr i64 %add2 to i32 *
%val = cmpxchg i32 *%ptr, i32 %cmp, i32 %swap seq_cst
ret i32 %val
}
; Check that a constant %cmp value is loaded into a register first.
define i32 @f11(i32 %dummy, i32 %swap, i32 *%ptr) {
; CHECK: f11:
; CHECK: lhi %r2, 1001
; CHECK: cs %r2, %r3, 0(%r4)
; CHECK: br %r14
%val = cmpxchg i32 *%ptr, i32 1001, i32 %swap seq_cst
ret i32 %val
}
; Check that a constant %swap value is loaded into a register first.
define i32 @f12(i32 %cmp, i32 *%ptr) {
; CHECK: f12:
; CHECK: lhi [[SWAP:%r[0-9]+]], 1002
; CHECK: cs %r2, [[SWAP]], 0(%r3)
; CHECK: br %r14
%val = cmpxchg i32 *%ptr, i32 %cmp, i32 1002 seq_cst
ret i32 %val
}

View File

@ -0,0 +1,98 @@
; Test 64-bit compare and swap.
;
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s
; Check CSG without a displacement.
define i64 @f1(i64 %cmp, i64 %swap, i64 *%src) {
; CHECK: f1:
; CHECK: csg %r2, %r3, 0(%r4)
; CHECK: br %r14
%val = cmpxchg i64 *%src, i64 %cmp, i64 %swap seq_cst
ret i64 %val
}
; Check the high end of the aligned CSG range.
define i64 @f2(i64 %cmp, i64 %swap, i64 *%src) {
; CHECK: f2:
; CHECK: csg %r2, %r3, 524280(%r4)
; CHECK: br %r14
%ptr = getelementptr i64 *%src, i64 65535
%val = cmpxchg i64 *%ptr, i64 %cmp, i64 %swap seq_cst
ret i64 %val
}
; Check the next doubleword up, which needs separate address logic.
; Other sequences besides this one would be OK.
define i64 @f3(i64 %cmp, i64 %swap, i64 *%src) {
; CHECK: f3:
; CHECK: agfi %r4, 524288
; CHECK: csg %r2, %r3, 0(%r4)
; CHECK: br %r14
%ptr = getelementptr i64 *%src, i64 65536
%val = cmpxchg i64 *%ptr, i64 %cmp, i64 %swap seq_cst
ret i64 %val
}
; Check the high end of the negative aligned CSG range.
define i64 @f4(i64 %cmp, i64 %swap, i64 *%src) {
; CHECK: f4:
; CHECK: csg %r2, %r3, -8(%r4)
; CHECK: br %r14
%ptr = getelementptr i64 *%src, i64 -1
%val = cmpxchg i64 *%ptr, i64 %cmp, i64 %swap seq_cst
ret i64 %val
}
; Check the low end of the CSG range.
define i64 @f5(i64 %cmp, i64 %swap, i64 *%src) {
; CHECK: f5:
; CHECK: csg %r2, %r3, -524288(%r4)
; CHECK: br %r14
%ptr = getelementptr i64 *%src, i64 -65536
%val = cmpxchg i64 *%ptr, i64 %cmp, i64 %swap seq_cst
ret i64 %val
}
; Check the next doubleword down, which needs separate address logic.
; Other sequences besides this one would be OK.
define i64 @f6(i64 %cmp, i64 %swap, i64 *%src) {
; CHECK: f6:
; CHECK: agfi %r4, -524296
; CHECK: csg %r2, %r3, 0(%r4)
; CHECK: br %r14
%ptr = getelementptr i64 *%src, i64 -65537
%val = cmpxchg i64 *%ptr, i64 %cmp, i64 %swap seq_cst
ret i64 %val
}
; Check that CSG does not allow an index.
define i64 @f7(i64 %cmp, i64 %swap, i64 %src, i64 %index) {
; CHECK: f7:
; CHECK: agr %r4, %r5
; CHECK: csg %r2, %r3, 0(%r4)
; CHECK: br %r14
%add1 = add i64 %src, %index
%ptr = inttoptr i64 %add1 to i64 *
%val = cmpxchg i64 *%ptr, i64 %cmp, i64 %swap seq_cst
ret i64 %val
}
; Check that a constant %cmp value is loaded into a register first.
define i64 @f8(i64 %dummy, i64 %swap, i64 *%ptr) {
; CHECK: f8:
; CHECK: lghi %r2, 1001
; CHECK: csg %r2, %r3, 0(%r4)
; CHECK: br %r14
%val = cmpxchg i64 *%ptr, i64 1001, i64 %swap seq_cst
ret i64 %val
}
; Check that a constant %swap value is loaded into a register first.
define i64 @f9(i64 %cmp, i64 *%ptr) {
; CHECK: f9:
; CHECK: lghi [[SWAP:%r[0-9]+]], 1002
; CHECK: csg %r2, [[SWAP]], 0(%r3)
; CHECK: br %r14
%val = cmpxchg i64 *%ptr, i64 %cmp, i64 1002 seq_cst
ret i64 %val
}

View File

@ -0,0 +1,40 @@
; Test floating-point absolute.
;
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s
; Test f32.
declare float @llvm.fabs.f32(float %f)
define float @f1(float %f) {
; CHECK: f1:
; CHECK: lpebr %f0, %f0
; CHECK: br %r14
%res = call float @llvm.fabs.f32(float %f)
ret float %res
}
; Test f64.
declare double @llvm.fabs.f64(double %f)
define double @f2(double %f) {
; CHECK: f2:
; CHECK: lpdbr %f0, %f0
; CHECK: br %r14
%res = call double @llvm.fabs.f64(double %f)
ret double %res
}
; Test f128. With the loads and stores, a pure absolute would probably
; be better implemented using an NI on the upper byte. Do some extra
; processing so that using FPRs is unequivocally better.
declare fp128 @llvm.fabs.f128(fp128 %f)
define void @f3(fp128 *%ptr, fp128 *%ptr2) {
; CHECK: f3:
; CHECK: lpxbr
; CHECK: dxbr
; CHECK: br %r14
%orig = load fp128 *%ptr
%abs = call fp128 @llvm.fabs.f128(fp128 %orig)
%op2 = load fp128 *%ptr2
%res = fdiv fp128 %abs, %op2
store fp128 %res, fp128 *%ptr
ret void
}

View File

@ -0,0 +1,43 @@
; Test negated floating-point absolute.
;
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s
; Test f32.
declare float @llvm.fabs.f32(float %f)
define float @f1(float %f) {
; CHECK: f1:
; CHECK: lnebr %f0, %f0
; CHECK: br %r14
%abs = call float @llvm.fabs.f32(float %f)
%res = fsub float -0.0, %abs
ret float %res
}
; Test f64.
declare double @llvm.fabs.f64(double %f)
define double @f2(double %f) {
; CHECK: f2:
; CHECK: lndbr %f0, %f0
; CHECK: br %r14
%abs = call double @llvm.fabs.f64(double %f)
%res = fsub double -0.0, %abs
ret double %res
}
; Test f128. With the loads and stores, a pure negative-absolute would
; probably be better implemented using an OI on the upper byte. Do some
; extra processing so that using FPRs is unequivocally better.
declare fp128 @llvm.fabs.f128(fp128 %f)
define void @f3(fp128 *%ptr, fp128 *%ptr2) {
; CHECK: f3:
; CHECK: lnxbr
; CHECK: dxbr
; CHECK: br %r14
%orig = load fp128 *%ptr
%abs = call fp128 @llvm.fabs.f128(fp128 %orig)
%negabs = fsub fp128 0xL00000000000000008000000000000000, %abs
%op2 = load fp128 *%ptr2
%res = fdiv fp128 %negabs, %op2
store fp128 %res, fp128 *%ptr
ret void
}

View File

@ -0,0 +1,71 @@
; Test 32-bit floating-point addition.
;
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s
; Check register addition.
define float @f1(float %f1, float %f2) {
; CHECK: f1:
; CHECK: aebr %f0, %f2
; CHECK: br %r14
%res = fadd float %f1, %f2
ret float %res
}
; Check the low end of the AEB range.
define float @f2(float %f1, float *%ptr) {
; CHECK: f2:
; CHECK: aeb %f0, 0(%r2)
; CHECK: br %r14
%f2 = load float *%ptr
%res = fadd float %f1, %f2
ret float %res
}
; Check the high end of the aligned AEB range.
define float @f3(float %f1, float *%base) {
; CHECK: f3:
; CHECK: aeb %f0, 4092(%r2)
; CHECK: br %r14
%ptr = getelementptr float *%base, i64 1023
%f2 = load float *%ptr
%res = fadd float %f1, %f2
ret float %res
}
; Check the next word up, which needs separate address logic.
; Other sequences besides this one would be OK.
define float @f4(float %f1, float *%base) {
; CHECK: f4:
; CHECK: aghi %r2, 4096
; CHECK: aeb %f0, 0(%r2)
; CHECK: br %r14
%ptr = getelementptr float *%base, i64 1024
%f2 = load float *%ptr
%res = fadd float %f1, %f2
ret float %res
}
; Check negative displacements, which also need separate address logic.
define float @f5(float %f1, float *%base) {
; CHECK: f5:
; CHECK: aghi %r2, -4
; CHECK: aeb %f0, 0(%r2)
; CHECK: br %r14
%ptr = getelementptr float *%base, i64 -1
%f2 = load float *%ptr
%res = fadd float %f1, %f2
ret float %res
}
; Check that AEB allows indices.
define float @f6(float %f1, float *%base, i64 %index) {
; CHECK: f6:
; CHECK: sllg %r1, %r3, 2
; CHECK: aeb %f0, 400(%r1,%r2)
; CHECK: br %r14
%ptr1 = getelementptr float *%base, i64 %index
%ptr2 = getelementptr float *%ptr1, i64 100
%f2 = load float *%ptr2
%res = fadd float %f1, %f2
ret float %res
}

View File

@ -0,0 +1,71 @@
; Test 64-bit floating-point addition.
;
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s
; Check register addition.
define double @f1(double %f1, double %f2) {
; CHECK: f1:
; CHECK: adbr %f0, %f2
; CHECK: br %r14
%res = fadd double %f1, %f2
ret double %res
}
; Check the low end of the ADB range.
define double @f2(double %f1, double *%ptr) {
; CHECK: f2:
; CHECK: adb %f0, 0(%r2)
; CHECK: br %r14
%f2 = load double *%ptr
%res = fadd double %f1, %f2
ret double %res
}
; Check the high end of the aligned ADB range.
define double @f3(double %f1, double *%base) {
; CHECK: f3:
; CHECK: adb %f0, 4088(%r2)
; CHECK: br %r14
%ptr = getelementptr double *%base, i64 511
%f2 = load double *%ptr
%res = fadd double %f1, %f2
ret double %res
}
; Check the next doubleword up, which needs separate address logic.
; Other sequences besides this one would be OK.
define double @f4(double %f1, double *%base) {
; CHECK: f4:
; CHECK: aghi %r2, 4096
; CHECK: adb %f0, 0(%r2)
; CHECK: br %r14
%ptr = getelementptr double *%base, i64 512
%f2 = load double *%ptr
%res = fadd double %f1, %f2
ret double %res
}
; Check negative displacements, which also need separate address logic.
define double @f5(double %f1, double *%base) {
; CHECK: f5:
; CHECK: aghi %r2, -8
; CHECK: adb %f0, 0(%r2)
; CHECK: br %r14
%ptr = getelementptr double *%base, i64 -1
%f2 = load double *%ptr
%res = fadd double %f1, %f2
ret double %res
}
; Check that ADB allows indices.
define double @f6(double %f1, double *%base, i64 %index) {
; CHECK: f6:
; CHECK: sllg %r1, %r3, 3
; CHECK: adb %f0, 800(%r1,%r2)
; CHECK: br %r14
%ptr1 = getelementptr double *%base, i64 %index
%ptr2 = getelementptr double *%ptr1, i64 100
%f2 = load double *%ptr2
%res = fadd double %f1, %f2
ret double %res
}

View File

@ -0,0 +1,20 @@
; Test 128-bit floating-point addition.
;
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s
; There is no memory form of 128-bit addition.
define void @f1(fp128 *%ptr, float %f2) {
; CHECK: f1:
; CHECK: lxebr %f0, %f0
; CHECK: ld %f1, 0(%r2)
; CHECK: ld %f3, 8(%r2)
; CHECK: axbr %f1, %f0
; CHECK: std %f1, 0(%r2)
; CHECK: std %f3, 8(%r2)
; CHECK: br %r14
%f1 = load fp128 *%ptr
%f2x = fpext float %f2 to fp128
%sum = fadd fp128 %f1, %f2x
store fp128 %sum, fp128 *%ptr
ret void
}

View File

@ -0,0 +1,89 @@
; Test 32-bit floating-point comparison.
;
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s
; Check comparison with registers.
define i64 @f1(i64 %a, i64 %b, float %f1, float %f2) {
; CHECK: f1:
; CHECK: cebr %f0, %f2
; CHECK-NEXT: j{{g?}}e
; CHECK: lgr %r2, %r3
; CHECK: br %r14
%cond = fcmp oeq float %f1, %f2
%res = select i1 %cond, i64 %a, i64 %b
ret i64 %res
}
; Check the low end of the CEB range.
define i64 @f2(i64 %a, i64 %b, float %f1, float *%ptr) {
; CHECK: f2:
; CHECK: ceb %f0, 0(%r4)
; CHECK-NEXT: j{{g?}}e
; CHECK: lgr %r2, %r3
; CHECK: br %r14
%f2 = load float *%ptr
%cond = fcmp oeq float %f1, %f2
%res = select i1 %cond, i64 %a, i64 %b
ret i64 %res
}
; Check the high end of the aligned CEB range.
define i64 @f3(i64 %a, i64 %b, float %f1, float *%base) {
; CHECK: f3:
; CHECK: ceb %f0, 4092(%r4)
; CHECK-NEXT: j{{g?}}e
; CHECK: lgr %r2, %r3
; CHECK: br %r14
%ptr = getelementptr float *%base, i64 1023
%f2 = load float *%ptr
%cond = fcmp oeq float %f1, %f2
%res = select i1 %cond, i64 %a, i64 %b
ret i64 %res
}
; Check the next word up, which needs separate address logic.
; Other sequences besides this one would be OK.
define i64 @f4(i64 %a, i64 %b, float %f1, float *%base) {
; CHECK: f4:
; CHECK: aghi %r4, 4096
; CHECK: ceb %f0, 0(%r4)
; CHECK-NEXT: j{{g?}}e
; CHECK: lgr %r2, %r3
; CHECK: br %r14
%ptr = getelementptr float *%base, i64 1024
%f2 = load float *%ptr
%cond = fcmp oeq float %f1, %f2
%res = select i1 %cond, i64 %a, i64 %b
ret i64 %res
}
; Check negative displacements, which also need separate address logic.
define i64 @f5(i64 %a, i64 %b, float %f1, float *%base) {
; CHECK: f5:
; CHECK: aghi %r4, -4
; CHECK: ceb %f0, 0(%r4)
; CHECK-NEXT: j{{g?}}e
; CHECK: lgr %r2, %r3
; CHECK: br %r14
%ptr = getelementptr float *%base, i64 -1
%f2 = load float *%ptr
%cond = fcmp oeq float %f1, %f2
%res = select i1 %cond, i64 %a, i64 %b
ret i64 %res
}
; Check that CEB allows indices.
define i64 @f6(i64 %a, i64 %b, float %f1, float *%base, i64 %index) {
; CHECK: f6:
; CHECK: sllg %r1, %r5, 2
; CHECK: ceb %f0, 400(%r1,%r4)
; CHECK-NEXT: j{{g?}}e
; CHECK: lgr %r2, %r3
; CHECK: br %r14
%ptr1 = getelementptr float *%base, i64 %index
%ptr2 = getelementptr float *%ptr1, i64 100
%f2 = load float *%ptr2
%cond = fcmp oeq float %f1, %f2
%res = select i1 %cond, i64 %a, i64 %b
ret i64 %res
}

View File

@ -0,0 +1,89 @@
; Test 64-bit floating-point comparison.
;
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s
; Check comparison with registers.
define i64 @f1(i64 %a, i64 %b, double %f1, double %f2) {
; CHECK: f1:
; CHECK: cdbr %f0, %f2
; CHECK-NEXT: j{{g?}}e
; CHECK: lgr %r2, %r3
; CHECK: br %r14
%cond = fcmp oeq double %f1, %f2
%res = select i1 %cond, i64 %a, i64 %b
ret i64 %res
}
; Check the low end of the CDB range.
define i64 @f2(i64 %a, i64 %b, double %f1, double *%ptr) {
; CHECK: f2:
; CHECK: cdb %f0, 0(%r4)
; CHECK-NEXT: j{{g?}}e
; CHECK: lgr %r2, %r3
; CHECK: br %r14
%f2 = load double *%ptr
%cond = fcmp oeq double %f1, %f2
%res = select i1 %cond, i64 %a, i64 %b
ret i64 %res
}
; Check the high end of the aligned CDB range.
define i64 @f3(i64 %a, i64 %b, double %f1, double *%base) {
; CHECK: f3:
; CHECK: cdb %f0, 4088(%r4)
; CHECK-NEXT: j{{g?}}e
; CHECK: lgr %r2, %r3
; CHECK: br %r14
%ptr = getelementptr double *%base, i64 511
%f2 = load double *%ptr
%cond = fcmp oeq double %f1, %f2
%res = select i1 %cond, i64 %a, i64 %b
ret i64 %res
}
; Check the next doubleword up, which needs separate address logic.
; Other sequences besides this one would be OK.
define i64 @f4(i64 %a, i64 %b, double %f1, double *%base) {
; CHECK: f4:
; CHECK: aghi %r4, 4096
; CHECK: cdb %f0, 0(%r4)
; CHECK-NEXT: j{{g?}}e
; CHECK: lgr %r2, %r3
; CHECK: br %r14
%ptr = getelementptr double *%base, i64 512
%f2 = load double *%ptr
%cond = fcmp oeq double %f1, %f2
%res = select i1 %cond, i64 %a, i64 %b
ret i64 %res
}
; Check negative displacements, which also need separate address logic.
define i64 @f5(i64 %a, i64 %b, double %f1, double *%base) {
; CHECK: f5:
; CHECK: aghi %r4, -8
; CHECK: cdb %f0, 0(%r4)
; CHECK-NEXT: j{{g?}}e
; CHECK: lgr %r2, %r3
; CHECK: br %r14
%ptr = getelementptr double *%base, i64 -1
%f2 = load double *%ptr
%cond = fcmp oeq double %f1, %f2
%res = select i1 %cond, i64 %a, i64 %b
ret i64 %res
}
; Check that CDB allows indices.
define i64 @f6(i64 %a, i64 %b, double %f1, double *%base, i64 %index) {
; CHECK: f6:
; CHECK: sllg %r1, %r5, 3
; CHECK: cdb %f0, 800(%r1,%r4)
; CHECK-NEXT: j{{g?}}e
; CHECK: lgr %r2, %r3
; CHECK: br %r14
%ptr1 = getelementptr double *%base, i64 %index
%ptr2 = getelementptr double *%ptr1, i64 100
%f2 = load double *%ptr2
%cond = fcmp oeq double %f1, %f2
%res = select i1 %cond, i64 %a, i64 %b
ret i64 %res
}

View File

@ -0,0 +1,20 @@
; Test 128-bit floating-point comparison.
;
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s
; There is no memory form of 128-bit comparison.
define i64 @f1(i64 %a, i64 %b, fp128 *%ptr, float %f2) {
; CHECK: f1:
; CHECK: lxebr %f0, %f0
; CHECK: ld %f1, 0(%r4)
; CHECK: ld %f3, 8(%r4)
; CHECK: cxbr %f1, %f0
; CHECK-NEXT: j{{g?}}e
; CHECK: lgr %r2, %r3
; CHECK: br %r14
%f2x = fpext float %f2 to fp128
%f1 = load fp128 *%ptr
%cond = fcmp oeq fp128 %f1, %f2x
%res = select i1 %cond, i64 %a, i64 %b
ret i64 %res
}

View File

@ -0,0 +1,30 @@
; Test loads of floating-point zero.
;
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s
; Test f32.
define float @f1() {
; CHECK: f1:
; CHECK: lzer %f0
; CHECK: br %r14
ret float 0.0
}
; Test f64.
define double @f2() {
; CHECK: f2:
; CHECK: lzdr %f0
; CHECK: br %r14
ret double 0.0
}
; Test f128.
define void @f3(fp128 *%x) {
; CHECK: f3:
; CHECK: lzxr %f0
; CHECK: std %f0, 0(%r2)
; CHECK: std %f2, 8(%r2)
; CHECK: br %r14
store fp128 0xL00000000000000000000000000000000, fp128 *%x
ret void
}

View File

@ -0,0 +1,31 @@
; Test loads of negative floating-point zero.
;
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s
; Test f32.
define float @f1() {
; CHECK: f1:
; CHECK: lzer [[REGISTER:%f[0-5]+]]
; CHECK: lcebr %f0, [[REGISTER]]
; CHECK: br %r14
ret float -0.0
}
; Test f64.
define double @f2() {
; CHECK: f2:
; CHECK: lzdr [[REGISTER:%f[0-5]+]]
; CHECK: lcdbr %f0, [[REGISTER]]
; CHECK: br %r14
ret double -0.0
}
; Test f128.
define void @f3(fp128 *%x) {
; CHECK: f3:
; CHECK: lzxr [[REGISTER:%f[0-5]+]]
; CHECK: lcxbr %f0, [[REGISTER]]
; CHECK: br %r14
store fp128 0xL00000000000000008000000000000000, fp128 *%x
ret void
}

View File

@ -0,0 +1,14 @@
; Test loads of 32-bit floating-point constants.
;
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s -check-prefix=CONST
define float @f1() {
; CHECK: f1:
; CHECK: larl [[REGISTER:%r[1-5]]], {{.*}}
; CHECK: le %f0, 0([[REGISTER]])
; CHECK: br %r14
;
; CONST: .long 1065353217
ret float 0x3ff0000020000000
}

Some files were not shown because too many files have changed in this diff Show More