1; RUN: llc -mtriple=powerpc64le -O0 < %s | FileCheck %s
2; RUN: llc -mtriple=powerpc64-ibm-aix-xcoff -O0 < %s | FileCheck %s --check-prefix=AIX
3; RUN: llc -mtriple=powerpc-ibm-aix-xcoff -O0 < %s | FileCheck %s --check-prefix=AIX
4
5; CHECK-LABEL: in_bounds:
6; CHECK-NOT: __stack_chk_guard
7; AIX-NOT: __ssp_canary_word
8define i32 @in_bounds() #0 {
9  %var = alloca i32, align 4
10  store i32 0, i32* %var, align 4
11  %gep = getelementptr inbounds i32, i32* %var, i32 0
12  %ret = load i32, i32* %gep, align 4
13  ret i32 %ret
14}
15
16; CHECK-LABEL: constant_out_of_bounds:
17; CHECK: __stack_chk_guard
18; AIX: __ssp_canary_word
19define i32 @constant_out_of_bounds() #0 {
20  %var = alloca i32, align 4
21  store i32 0, i32* %var, align 4
22  %gep = getelementptr inbounds i32, i32* %var, i32 1
23  %ret = load i32, i32* %gep, align 4
24  ret i32 %ret
25}
26
27; CHECK-LABEL: nonconstant_out_of_bounds:
28; CHECK: __stack_chk_guard
29; AIX: __ssp_canary_word
30define i32 @nonconstant_out_of_bounds(i32 %n) #0 {
31  %var = alloca i32, align 4
32  store i32 0, i32* %var, align 4
33  %gep = getelementptr inbounds i32, i32* %var, i32 %n
34  %ret = load i32, i32* %gep, align 4
35  ret i32 %ret
36}
37
38; CHECK-LABEL: phi_before_gep_in_bounds:
39; CHECK-NOT: __stack_chk_guard
40; AIX-NOT: __ssp_canary_word
41define i32 @phi_before_gep_in_bounds(i32 %k) #0 {
42entry:
43  %var1 = alloca i32, align 4
44  %var2 = alloca i32, align 4
45  store i32 0, i32* %var1, align 4
46  store i32 0, i32* %var2, align 4
47  %cmp = icmp ne i32 %k, 0
48  br i1 %cmp, label %if, label %then
49
50if:
51  br label %then
52
53then:
54  %ptr = phi i32* [ %var1, %entry ], [ %var2, %if ]
55  %gep = getelementptr inbounds i32, i32* %ptr, i32 0
56  %ret = load i32, i32* %gep, align 4
57  ret i32 %ret
58}
59
60; CHECK-LABEL: phi_before_gep_constant_out_of_bounds:
61; CHECK: __stack_chk_guard
62; AIX: __ssp_canary_word
63define i32 @phi_before_gep_constant_out_of_bounds(i32 %k) #0 {
64entry:
65  %var1 = alloca i32, align 4
66  %var2 = alloca i32, align 4
67  store i32 0, i32* %var1, align 4
68  store i32 0, i32* %var2, align 4
69  %cmp = icmp ne i32 %k, 0
70  br i1 %cmp, label %if, label %then
71
72if:
73  br label %then
74
75then:
76  %ptr = phi i32* [ %var1, %entry ], [ %var2, %if ]
77  %gep = getelementptr inbounds i32, i32* %ptr, i32 1
78  %ret = load i32, i32* %gep, align 4
79  ret i32 %ret
80}
81
82; CHECK-LABEL: phi_before_gep_nonconstant_out_of_bounds:
83; CHECK: __stack_chk_guard
84; AIX: __ssp_canary_word
85define i32 @phi_before_gep_nonconstant_out_of_bounds(i32 %k, i32 %n) #0 {
86entry:
87  %var1 = alloca i32, align 4
88  %var2 = alloca i32, align 4
89  store i32 0, i32* %var1, align 4
90  store i32 0, i32* %var2, align 4
91  %cmp = icmp ne i32 %k, 0
92  br i1 %cmp, label %if, label %then
93
94if:
95  br label %then
96
97then:
98  %ptr = phi i32* [ %var1, %entry ], [ %var2, %if ]
99  %gep = getelementptr inbounds i32, i32* %ptr, i32 %n
100  %ret = load i32, i32* %gep, align 4
101  ret i32 %ret
102}
103
104; CHECK-LABEL: phi_after_gep_in_bounds:
105; CHECK-NOT: __stack_chk_guard
106; AIX-NOT: __ssp_canary_word
107define i32 @phi_after_gep_in_bounds(i32 %k) #0 {
108entry:
109  %var1 = alloca i32, align 4
110  %var2 = alloca i32, align 4
111  store i32 0, i32* %var1, align 4
112  store i32 0, i32* %var2, align 4
113  %cmp = icmp ne i32 %k, 0
114  br i1 %cmp, label %if, label %else
115
116if:
117  %gep1 = getelementptr inbounds i32, i32* %var1, i32 0
118  br label %then
119
120else:
121  %gep2 = getelementptr inbounds i32, i32* %var2, i32 0
122  br label %then
123
124then:
125  %ptr = phi i32* [ %gep1, %if ], [ %gep2, %else ]
126  %ret = load i32, i32* %ptr, align 4
127  ret i32 %ret
128}
129
130; CHECK-LABEL: phi_after_gep_constant_out_of_bounds_a:
131; CHECK: __stack_chk_guard
132; AIX: __ssp_canary_word
133define i32 @phi_after_gep_constant_out_of_bounds_a(i32 %k) #0 {
134entry:
135  %var1 = alloca i32, align 4
136  %var2 = alloca i32, align 4
137  store i32 0, i32* %var1, align 4
138  store i32 0, i32* %var2, align 4
139  %cmp = icmp ne i32 %k, 0
140  br i1 %cmp, label %if, label %else
141
142if:
143  %gep1 = getelementptr inbounds i32, i32* %var1, i32 0
144  br label %then
145
146else:
147  %gep2 = getelementptr inbounds i32, i32* %var2, i32 1
148  br label %then
149
150then:
151  %ptr = phi i32* [ %gep1, %if ], [ %gep2, %else ]
152  %ret = load i32, i32* %ptr, align 4
153  ret i32 %ret
154}
155
156; CHECK-LABEL: phi_after_gep_constant_out_of_bounds_b:
157; CHECK: __stack_chk_guard
158; AIX: __ssp_canary_word
159define i32 @phi_after_gep_constant_out_of_bounds_b(i32 %k) #0 {
160entry:
161  %var1 = alloca i32, align 4
162  %var2 = alloca i32, align 4
163  store i32 0, i32* %var1, align 4
164  store i32 0, i32* %var2, align 4
165  %cmp = icmp ne i32 %k, 0
166  br i1 %cmp, label %if, label %else
167
168if:
169  %gep1 = getelementptr inbounds i32, i32* %var1, i32 1
170  br label %then
171
172else:
173  %gep2 = getelementptr inbounds i32, i32* %var2, i32 0
174  br label %then
175
176then:
177  %ptr = phi i32* [ %gep1, %if ], [ %gep2, %else ]
178  %ret = load i32, i32* %ptr, align 4
179  ret i32 %ret
180}
181
182; CHECK-LABEL: phi_different_types_a:
183; CHECK: __stack_chk_guard
184; AIX: __ssp_canary_word
185define i64 @phi_different_types_a(i32 %k) #0 {
186entry:
187  %var1 = alloca i64, align 4
188  %var2 = alloca i32, align 4
189  store i64 0, i64* %var1, align 4
190  store i32 0, i32* %var2, align 4
191  %cmp = icmp ne i32 %k, 0
192  br i1 %cmp, label %if, label %then
193
194if:
195  %bitcast = bitcast i32* %var2 to i64*
196  br label %then
197
198then:
199  %ptr = phi i64* [ %var1, %entry ], [ %bitcast, %if ]
200  %ret = load i64, i64* %ptr, align 4
201  ret i64 %ret
202}
203
204; CHECK-LABEL: phi_different_types_b:
205; CHECK: __stack_chk_guard
206; AIX: __ssp_canary_word
207define i64 @phi_different_types_b(i32 %k) #0 {
208entry:
209  %var1 = alloca i32, align 4
210  %var2 = alloca i64, align 4
211  store i32 0, i32* %var1, align 4
212  store i64 0, i64* %var2, align 4
213  %cmp = icmp ne i32 %k, 0
214  br i1 %cmp, label %if, label %then
215
216if:
217  %bitcast = bitcast i32* %var1 to i64*
218  br label %then
219
220then:
221  %ptr = phi i64* [ %var2, %entry ], [ %bitcast, %if ]
222  %ret = load i64, i64* %ptr, align 4
223  ret i64 %ret
224}
225
226; CHECK-LABEL: phi_after_gep_nonconstant_out_of_bounds_a:
227; CHECK: __stack_chk_guard
228; AIX: __ssp_canary_word
229define i32 @phi_after_gep_nonconstant_out_of_bounds_a(i32 %k, i32 %n) #0 {
230entry:
231  %var1 = alloca i32, align 4
232  %var2 = alloca i32, align 4
233  store i32 0, i32* %var1, align 4
234  store i32 0, i32* %var2, align 4
235  %cmp = icmp ne i32 %k, 0
236  br i1 %cmp, label %if, label %else
237
238if:
239  %gep1 = getelementptr inbounds i32, i32* %var1, i32 0
240  br label %then
241
242else:
243  %gep2 = getelementptr inbounds i32, i32* %var2, i32 %n
244  br label %then
245
246then:
247  %ptr = phi i32* [ %gep1, %if ], [ %gep2, %else ]
248  %ret = load i32, i32* %ptr, align 4
249  ret i32 %ret
250}
251
252; CHECK-LABEL: phi_after_gep_nonconstant_out_of_bounds_b:
253; CHECK: __stack_chk_guard
254; AIX: __ssp_canary_word
255define i32 @phi_after_gep_nonconstant_out_of_bounds_b(i32 %k, i32 %n) #0 {
256entry:
257  %var1 = alloca i32, align 4
258  %var2 = alloca i32, align 4
259  store i32 0, i32* %var1, align 4
260  store i32 0, i32* %var2, align 4
261  %cmp = icmp ne i32 %k, 0
262  br i1 %cmp, label %if, label %else
263
264if:
265  %gep1 = getelementptr inbounds i32, i32* %var1, i32 %n
266  br label %then
267
268else:
269  %gep2 = getelementptr inbounds i32, i32* %var2, i32 0
270  br label %then
271
272then:
273  %ptr = phi i32* [ %gep1, %if ], [ %gep2, %else ]
274  %ret = load i32, i32* %ptr, align 4
275  ret i32 %ret
276}
277
278%struct.outer = type { %struct.inner, %struct.inner }
279%struct.inner = type { i32, i32 }
280
281; CHECK-LABEL: struct_in_bounds:
282; CHECK-NOT: __stack_chk_guard
283; AIX-NOT: __ssp_canary_word
284define void @struct_in_bounds() #0 {
285  %var = alloca %struct.outer, align 4
286  %outergep = getelementptr inbounds %struct.outer, %struct.outer* %var, i32 0, i32 1
287  %innergep = getelementptr inbounds %struct.inner, %struct.inner* %outergep, i32 0, i32 1
288  store i32 0, i32* %innergep, align 4
289  ret void
290}
291
292; CHECK-LABEL: struct_constant_out_of_bounds_a:
293; CHECK: __stack_chk_guard
294; AIX: __ssp_canary_word
295define void @struct_constant_out_of_bounds_a() #0 {
296  %var = alloca %struct.outer, align 4
297  %outergep = getelementptr inbounds %struct.outer, %struct.outer* %var, i32 1, i32 0
298  %innergep = getelementptr inbounds %struct.inner, %struct.inner* %outergep, i32 0, i32 0
299  store i32 0, i32* %innergep, align 4
300  ret void
301}
302
303; CHECK-LABEL: struct_constant_out_of_bounds_b:
304; Here the offset is out-of-bounds of the addressed struct.inner member, but
305; still within bounds of the outer struct so no stack guard is needed.
306; CHECK-NOT: __stack_chk_guard
307; AIX-NOT: __ssp_canary_word
308define void @struct_constant_out_of_bounds_b() #0 {
309  %var = alloca %struct.outer, align 4
310  %outergep = getelementptr inbounds %struct.outer, %struct.outer* %var, i32 0, i32 0
311  %innergep = getelementptr inbounds %struct.inner, %struct.inner* %outergep, i32 1, i32 0
312  store i32 0, i32* %innergep, align 4
313  ret void
314}
315
316; CHECK-LABEL: struct_constant_out_of_bounds_c:
317; Here we are out-of-bounds of both the inner and outer struct.
318; CHECK: __stack_chk_guard
319; AIX: __ssp_canary_word
320define void @struct_constant_out_of_bounds_c() #0 {
321  %var = alloca %struct.outer, align 4
322  %outergep = getelementptr inbounds %struct.outer, %struct.outer* %var, i32 0, i32 1
323  %innergep = getelementptr inbounds %struct.inner, %struct.inner* %outergep, i32 1, i32 0
324  store i32 0, i32* %innergep, align 4
325  ret void
326}
327
328; CHECK-LABEL: struct_nonconstant_out_of_bounds_a:
329; CHECK: __stack_chk_guard
330; AIX: __ssp_canary_word
331define void @struct_nonconstant_out_of_bounds_a(i32 %n) #0 {
332  %var = alloca %struct.outer, align 4
333  %outergep = getelementptr inbounds %struct.outer, %struct.outer* %var, i32 %n, i32 0
334  %innergep = getelementptr inbounds %struct.inner, %struct.inner* %outergep, i32 0, i32 0
335  store i32 0, i32* %innergep, align 4
336  ret void
337}
338
339; CHECK-LABEL: struct_nonconstant_out_of_bounds_b:
340; CHECK: __stack_chk_guard
341; AIX: __ssp_canary_word
342define void @struct_nonconstant_out_of_bounds_b(i32 %n) #0 {
343  %var = alloca %struct.outer, align 4
344  %outergep = getelementptr inbounds %struct.outer, %struct.outer* %var, i32 0, i32 0
345  %innergep = getelementptr inbounds %struct.inner, %struct.inner* %outergep, i32 %n, i32 0
346  store i32 0, i32* %innergep, align 4
347  ret void
348}
349
350; CHECK-LABEL: bitcast_smaller_load
351; CHECK-NOT: __stack_chk_guard
352; AIX-NOT: __ssp_canary_word
353define i32 @bitcast_smaller_load() #0 {
354  %var = alloca i64, align 4
355  store i64 0, i64* %var, align 4
356  %bitcast = bitcast i64* %var to i32*
357  %ret = load i32, i32* %bitcast, align 4
358  ret i32 %ret
359}
360
361; CHECK-LABEL: bitcast_same_size_load
362; CHECK-NOT: __stack_chk_guard
363; AIX-NOT: __ssp_canary_word
364define i32 @bitcast_same_size_load() #0 {
365  %var = alloca i64, align 4
366  store i64 0, i64* %var, align 4
367  %bitcast = bitcast i64* %var to %struct.inner*
368  %gep = getelementptr inbounds %struct.inner, %struct.inner* %bitcast, i32 0, i32 1
369  %ret = load i32, i32* %gep, align 4
370  ret i32 %ret
371}
372
373; CHECK-LABEL: bitcast_larger_load
374; CHECK: __stack_chk_guard
375; AIX: __ssp_canary_word
376define i64 @bitcast_larger_load() #0 {
377  %var = alloca i32, align 4
378  store i32 0, i32* %var, align 4
379  %bitcast = bitcast i32* %var to i64*
380  %ret = load i64, i64* %bitcast, align 4
381  ret i64 %ret
382}
383
384; CHECK-LABEL: bitcast_larger_store
385; CHECK: __stack_chk_guard
386; AIX: __ssp_canary_word
387define i32 @bitcast_larger_store() #0 {
388  %var = alloca i32, align 4
389  %bitcast = bitcast i32* %var to i64*
390  store i64 0, i64* %bitcast, align 4
391  %ret = load i32, i32* %var, align 4
392  ret i32 %ret
393}
394
395; CHECK-LABEL: bitcast_larger_cmpxchg
396; CHECK: __stack_chk_guard
397; AIX: __ssp_canary_word
398define i64 @bitcast_larger_cmpxchg(i64 %desired, i64 %new) #0 {
399  %var = alloca i32, align 4
400  %bitcast = bitcast i32* %var to i64*
401  %pair = cmpxchg i64* %bitcast, i64 %desired, i64 %new seq_cst monotonic
402  %ret = extractvalue { i64, i1 } %pair, 0
403  ret i64 %ret
404}
405
406; CHECK-LABEL: bitcast_larger_atomic_rmw
407; CHECK: __stack_chk_guard
408; AIX: __ssp_canary_word
409define i64 @bitcast_larger_atomic_rmw() #0 {
410  %var = alloca i32, align 4
411  %bitcast = bitcast i32* %var to i64*
412  %ret = atomicrmw add i64* %bitcast, i64 1 monotonic
413  ret i64 %ret
414}
415
416%struct.packed = type <{ i16, i32 }>
417
418; CHECK-LABEL: bitcast_overlap
419; CHECK: __stack_chk_guard
420; AIX: __ssp_canary_word
421define i32 @bitcast_overlap() #0 {
422  %var = alloca i32, align 4
423  %bitcast = bitcast i32* %var to %struct.packed*
424  %gep = getelementptr inbounds %struct.packed, %struct.packed* %bitcast, i32 0, i32 1
425  %ret = load i32, i32* %gep, align 2
426  ret i32 %ret
427}
428
429%struct.multi_dimensional = type { [10 x [10 x i32]], i32 }
430
431; CHECK-LABEL: multi_dimensional_array
432; CHECK: __stack_chk_guard
433; AIX: __ssp_canary_word
434define i32 @multi_dimensional_array() #0 {
435  %var = alloca %struct.multi_dimensional, align 4
436  %gep1 = getelementptr inbounds %struct.multi_dimensional, %struct.multi_dimensional* %var, i32 0, i32 0
437  %gep2 = getelementptr inbounds [10 x [10 x i32]], [10 x [10 x i32]]* %gep1, i32 0, i32 10
438  %gep3 = getelementptr inbounds [10 x i32], [10 x i32]* %gep2, i32 0, i32 5
439  %ret = load i32, i32* %gep3, align 4
440  ret i32 %ret
441}
442
443attributes #0 = { sspstrong }
444