1; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s
2;
3; Test PC-relative memory accesses of globals with packed struct types.
4; PC-relative memory accesses cannot be used when the address is not
5; aligned. This can happen with programs like the following (which are not
6; strictly correct):
7;
8; #pragma pack(1)
9; struct  {
10;   short a;
11;   int b;
12; } c;
13;
14; void main()    {
15;   int *e = &c.b;
16;   *e = 0;
17; }
18;
19
20%packed.i16i32 = type <{ i16, i32 }>
21%packed.i16i32i16i32 = type <{ i16, i32, i16, i32 }>
22%packed.i16i64 = type <{ i16, i64 }>
23%packed.i8i16 = type <{ i8, i16 }>
24
25@A_align2 = dso_local global %packed.i16i32 zeroinitializer, align 2
26@B_align2 = dso_local global %packed.i16i32i16i32 zeroinitializer, align 2
27@C_align2 = dso_local global %packed.i16i64 zeroinitializer, align 2
28@D_align4 = dso_local global %packed.i16i32 zeroinitializer, align 4
29@E_align4 = dso_local global %packed.i16i32i16i32 zeroinitializer, align 4
30@F_align2 = dso_local global %packed.i8i16 zeroinitializer, align 2
31
32;;; Stores
33
34; unaligned packed struct + 2  -> unaligned address
35define dso_local void @f1() {
36; CHECK-LABEL: f1:
37; CHECK: larl %r1, A_align2
38; CHECK: mvhi 2(%r1), 0
39; CHECK: br %r14
40  store i32 0, i32* getelementptr inbounds (%packed.i16i32, %packed.i16i32* @A_align2, i64 0, i32 1), align 4
41  ret void
42}
43
44; unaligned packed struct  + 8  -> unaligned address
45define dso_local void @f2() {
46; CHECK-LABEL: f2:
47; CHECK: larl %r1, B_align2
48; CHECK: mvhi 8(%r1), 0
49; CHECK: br %r14
50  store i32 0, i32* getelementptr inbounds (%packed.i16i32i16i32, %packed.i16i32i16i32* @B_align2, i64 0, i32 3), align 4
51  ret void
52}
53
54; aligned packed struct + 2  -> unaligned address
55define dso_local void @f3() {
56; CHECK-LABEL: f3:
57; CHECK: larl %r1, D_align4
58; CHECK: mvhi 2(%r1), 0
59; CHECK: br %r14
60  store i32 0, i32* getelementptr inbounds (%packed.i16i32, %packed.i16i32* @D_align4, i64 0, i32 1), align 4
61  ret void
62}
63
64; aligned packed struct + 8  -> aligned address
65define dso_local void @f4() {
66; CHECK-LABEL: f4:
67; CHECK: lhi %r0, 0
68; CHECK: strl %r0, E_align4+8
69; CHECK: br %r14
70  store i32 0, i32* getelementptr inbounds (%packed.i16i32i16i32, %packed.i16i32i16i32* @E_align4, i64 0, i32 3), align 4
71  ret void
72}
73
74define dso_local void @f5() {
75; CHECK-LABEL: f5:
76; CHECK: larl %r1, C_align2
77; CHECK: mvghi 2(%r1), 0
78; CHECK: br %r14
79  store i64 0, i64* getelementptr inbounds (%packed.i16i64, %packed.i16i64* @C_align2, i64 0, i32 1), align 8
80  ret void
81}
82
83define dso_local void @f6() {
84; CHECK-LABEL: f6:
85; CHECK-NOT: sthrl
86  store i16 0, i16* getelementptr inbounds (%packed.i8i16, %packed.i8i16* @F_align2, i64 0, i32 1), align 2
87  ret void
88}
89
90define dso_local void @f7(i64* %Src) {
91; CHECK-LABEL: f7:
92; CHECK: lg %r0, 0(%r2)
93; CHECK: larl %r1, D_align4
94; CHECK: st %r0, 2(%r1)
95; CHECK: br      %r14
96  %L = load i64, i64* %Src
97  %T = trunc i64 %L to i32
98  store i32 %T, i32* getelementptr inbounds (%packed.i16i32, %packed.i16i32* @D_align4, i64 0, i32 1), align 4
99  ret void
100}
101
102define dso_local void @f8(i64* %Src) {
103; CHECK-LABEL: f8:
104; CHECK-NOT: sthrl
105  %L = load i64, i64* %Src
106  %T = trunc i64 %L to i16
107  store i16 %T, i16* getelementptr inbounds (%packed.i8i16, %packed.i8i16* @F_align2, i64 0, i32 1), align 2
108  ret void
109}
110
111;;; Loads
112
113; unaligned packed struct + 2  -> unaligned address
114define dso_local i32 @f9() {
115; CHECK-LABEL: f9:
116; CHECK: larl %r1, A_align2
117; CHECK: l %r2, 2(%r1)
118; CHECK: br %r14
119  %L = load i32, i32* getelementptr inbounds (%packed.i16i32, %packed.i16i32* @A_align2, i64 0, i32 1), align 4
120  ret i32 %L
121}
122
123; unaligned packed struct  + 8  -> unaligned address
124define dso_local i32 @f10() {
125; CHECK-LABEL: f10:
126; CHECK: larl %r1, B_align2
127; CHECK: l %r2, 8(%r1)
128; CHECK: br %r14
129  %L = load i32, i32* getelementptr inbounds (%packed.i16i32i16i32, %packed.i16i32i16i32* @B_align2, i64 0, i32 3), align 4
130  ret i32 %L
131}
132
133; aligned packed struct + 2  -> unaligned address
134define dso_local i32 @f11() {
135; CHECK-LABEL: f11:
136; CHECK: larl %r1, D_align4
137; CHECK: l %r2, 2(%r1)
138; CHECK: br %r14
139  %L = load i32, i32* getelementptr inbounds (%packed.i16i32, %packed.i16i32* @D_align4, i64 0, i32 1), align 4
140  ret i32 %L
141}
142
143; aligned packed struct + 8  -> aligned address
144define dso_local i32 @f12() {
145; CHECK-LABEL: f12:
146; CHECK: lrl %r2, E_align4+8
147; CHECK: br %r14
148  %L = load i32, i32* getelementptr inbounds (%packed.i16i32i16i32, %packed.i16i32i16i32* @E_align4, i64 0, i32 3), align 4
149  ret i32 %L
150}
151
152define dso_local i64 @f13() {
153; CHECK-LABEL: f13:
154; CHECK: larl %r1, C_align2
155; CHECK: lg %r2, 2(%r1)
156; CHECK: br %r14
157  %L = load i64, i64* getelementptr inbounds (%packed.i16i64, %packed.i16i64* @C_align2, i64 0, i32 1), align 8
158  ret i64 %L
159}
160
161define dso_local i32 @f14() {
162; CHECK-LABEL: f14:
163; CHECK-NOT: lhrl
164  %L = load i16, i16* getelementptr inbounds (%packed.i8i16, %packed.i8i16* @F_align2, i64 0, i32 1), align 2
165  %ext = sext i16 %L to i32
166  ret i32 %ext
167}
168
169define dso_local i64 @f15() {
170; CHECK-LABEL: f15:
171; CHECK-NOT: llghrl
172  %L = load i16, i16* getelementptr inbounds (%packed.i8i16, %packed.i8i16* @F_align2, i64 0, i32 1), align 2
173  %ext = zext i16 %L to i64
174  ret i64 %ext
175}
176
177;;; Loads folded into compare instructions
178
179define dso_local i32 @f16(i32 %src1) {
180; CHECK-LABEL: f16:
181; CHECK: larl %r1, A_align2
182; CHECK: c %r2, 2(%r1)
183entry:
184  %src2 = load i32, i32* getelementptr inbounds (%packed.i16i32, %packed.i16i32* @A_align2, i64 0, i32 1), align 4
185  %cond = icmp slt i32 %src1, %src2
186  br i1 %cond, label %exit, label %mulb
187mulb:
188  %mul = mul i32 %src1, %src1
189  br label %exit
190exit:
191  %res = phi i32 [ %src1, %entry ], [ %mul, %mulb ]
192  ret i32 %res
193}
194
195define dso_local i64 @f17(i64 %src1) {
196; CHECK-LABEL: f17:
197; CHECK: larl %r1, C_align2
198; CHECK: clg %r2, 2(%r1)
199entry:
200  %src2 = load i64, i64* getelementptr inbounds (%packed.i16i64, %packed.i16i64* @C_align2, i64 0, i32 1), align 8
201  %cond = icmp ult i64 %src1, %src2
202  br i1 %cond, label %exit, label %mulb
203mulb:
204  %mul = mul i64 %src1, %src1
205  br label %exit
206exit:
207  %res = phi i64 [ %src1, %entry ], [ %mul, %mulb ]
208  ret i64 %res
209}
210