1; Test memcmp using CLC.
2;
3; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s
4
5declare signext i32 @memcmp(i8 *%src1, i8 *%src2, i64 %size)
6
7; Zero-length comparisons should be optimized away.
8define i32 @f1(i8 *%src1, i8 *%src2) {
9; CHECK-LABEL: f1:
10; CHECK: lhi %r2, 0
11; CHECK: br %r14
12  %res = call i32 @memcmp(i8 *%src1, i8 *%src2, i64 0)
13  ret i32 %res
14}
15
16; Check a case where the result is used as an integer.
17define i32 @f2(i8 *%src1, i8 *%src2) {
18; CHECK-LABEL: f2:
19; CHECK: clc 0(2,%r2), 0(%r3)
20; CHECK: ipm %r2
21; CHECK: sll %r2, 2
22; CHECK: sra %r2, 30
23; CHECK: br %r14
24  %res = call i32 @memcmp(i8 *%src1, i8 *%src2, i64 2)
25  ret i32 %res
26}
27
28; Check a case where the result is tested for equality.
29define void @f3(i8 *%src1, i8 *%src2, i32 *%dest) {
30; CHECK-LABEL: f3:
31; CHECK: clc 0(3,%r2), 0(%r3)
32; CHECK-NEXT: je {{\..*}}
33; CHECK: br %r14
34  %res = call i32 @memcmp(i8 *%src1, i8 *%src2, i64 3)
35  %cmp = icmp eq i32 %res, 0
36  br i1 %cmp, label %exit, label %store
37
38store:
39  store i32 0, i32 *%dest
40  br label %exit
41
42exit:
43  ret void
44}
45
46; Check a case where the result is tested for inequality.
47define void @f4(i8 *%src1, i8 *%src2, i32 *%dest) {
48; CHECK-LABEL: f4:
49; CHECK: clc 0(4,%r2), 0(%r3)
50; CHECK-NEXT: jlh {{\..*}}
51; CHECK: br %r14
52entry:
53  %res = call i32 @memcmp(i8 *%src1, i8 *%src2, i64 4)
54  %cmp = icmp ne i32 %res, 0
55  br i1 %cmp, label %exit, label %store
56
57store:
58  store i32 0, i32 *%dest
59  br label %exit
60
61exit:
62  ret void
63}
64
65; Check a case where the result is tested via slt.
66define void @f5(i8 *%src1, i8 *%src2, i32 *%dest) {
67; CHECK-LABEL: f5:
68; CHECK: clc 0(5,%r2), 0(%r3)
69; CHECK-NEXT: jl {{\..*}}
70; CHECK: br %r14
71entry:
72  %res = call i32 @memcmp(i8 *%src1, i8 *%src2, i64 5)
73  %cmp = icmp slt i32 %res, 0
74  br i1 %cmp, label %exit, label %store
75
76store:
77  store i32 0, i32 *%dest
78  br label %exit
79
80exit:
81  ret void
82}
83
84; Check a case where the result is tested for sgt.
85define void @f6(i8 *%src1, i8 *%src2, i32 *%dest) {
86; CHECK-LABEL: f6:
87; CHECK: clc 0(6,%r2), 0(%r3)
88; CHECK-NEXT: jh {{\..*}}
89; CHECK: br %r14
90entry:
91  %res = call i32 @memcmp(i8 *%src1, i8 *%src2, i64 6)
92  %cmp = icmp sgt i32 %res, 0
93  br i1 %cmp, label %exit, label %store
94
95store:
96  store i32 0, i32 *%dest
97  br label %exit
98
99exit:
100  ret void
101}
102
103; Check the upper end of the CLC range.  Here the result is used both as
104; an integer and for branching, but it's better to branch on the result
105; of the SRA.
106define i32 @f7(i8 *%src1, i8 *%src2, i32 *%dest) {
107; CHECK-LABEL: f7:
108; CHECK: clc 0(256,%r2), 0(%r3)
109; CHECK: ipm %r2
110; CHECK: sll %r2, 2
111; CHECK: sra %r2, 30
112; CHECK: jl {{.L*}}
113; CHECK: br %r14
114entry:
115  %res = call i32 @memcmp(i8 *%src1, i8 *%src2, i64 256)
116  %cmp = icmp slt i32 %res, 0
117  br i1 %cmp, label %exit, label %store
118
119store:
120  store i32 0, i32 *%dest
121  br label %exit
122
123exit:
124  ret i32 %res
125}
126
127; 257 bytes is too big for a single CLC.  For now expect a call instead.
128define i32 @f8(i8 *%src1, i8 *%src2) {
129; CHECK-LABEL: f8:
130; CHECK: brasl %r14, memcmp@PLT
131; CHECK: br %r14
132  %res = call i32 @memcmp(i8 *%src1, i8 *%src2, i64 257)
133  ret i32 %res
134}
135