1 ; RUN: opt -S -passes="print<stack-safety-local>" -disable-output < %s 2>&1 | FileCheck %s
2 ; RUN: opt -S -passes="print-stack-safety" -disable-output < %s 2>&1 | FileCheck %s --check-prefixes=CHECK,GLOBAL
4 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
5 target triple = "x86_64-unknown-linux-gnu"
7 declare void @llvm.memset.p0.i64(ptr %dest, i8 %val, i64 %len, i1 %isvolatile)
8 declare void @llvm.memset.p0.i32(ptr %dest, i8 %val, i32 %len, i1 %isvolatile)
9 declare void @llvm.memcpy.p0.p0.i32(ptr %dest, ptr %src, i32 %len, i1 %isvolatile)
10 declare void @llvm.memmove.p0.p0.i32(ptr %dest, ptr %src, i32 %len, i1 %isvolatile)
12 define void @MemsetInBounds() {
13 ; CHECK-LABEL: MemsetInBounds dso_preemptable{{$}}
14 ; CHECK-NEXT: args uses:
15 ; CHECK-NEXT: allocas uses:
16 ; CHECK-NEXT: x[4]: [0,4){{$}}
17 ; GLOBAL-NEXT: safe accesses:
18 ; GLOBAL-NEXT: call void @llvm.memset.p0.i32(ptr %x, i8 42, i32 4, i1 false)
21 %x = alloca i32, align 4
22 call void @llvm.memset.p0.i32(ptr %x, i8 42, i32 4, i1 false)
26 ; Volatile does not matter for access bounds.
27 define void @VolatileMemsetInBounds() {
28 ; CHECK-LABEL: VolatileMemsetInBounds dso_preemptable{{$}}
29 ; CHECK-NEXT: args uses:
30 ; CHECK-NEXT: allocas uses:
31 ; CHECK-NEXT: x[4]: [0,4){{$}}
32 ; GLOBAL-NEXT: safe accesses:
33 ; GLOBAL-NEXT: call void @llvm.memset.p0.i32(ptr %x, i8 42, i32 4, i1 true)
36 %x = alloca i32, align 4
37 call void @llvm.memset.p0.i32(ptr %x, i8 42, i32 4, i1 true)
41 define void @MemsetOutOfBounds() {
42 ; CHECK-LABEL: MemsetOutOfBounds dso_preemptable{{$}}
43 ; CHECK-NEXT: args uses:
44 ; CHECK-NEXT: allocas uses:
45 ; CHECK-NEXT: x[4]: [0,5){{$}}
46 ; GLOBAL-NEXT: safe accesses:
49 %x = alloca i32, align 4
50 call void @llvm.memset.p0.i32(ptr %x, i8 42, i32 5, i1 false)
54 define void @MemsetNonConst(i32 %size) {
55 ; CHECK-LABEL: MemsetNonConst dso_preemptable{{$}}
56 ; CHECK-NEXT: args uses:
57 ; CHECK-NEXT: allocas uses:
58 ; CHECK-NEXT: x[4]: [0,4294967295){{$}}
59 ; GLOBAL-NEXT: safe accesses:
62 %x = alloca i32, align 4
63 call void @llvm.memset.p0.i32(ptr %x, i8 42, i32 %size, i1 false)
67 ; FIXME: memintrinsics should look at size range when possible
68 ; Right now we refuse any non-constant size.
69 define void @MemsetNonConstInBounds(i1 zeroext %z) {
70 ; CHECK-LABEL: MemsetNonConstInBounds dso_preemptable{{$}}
71 ; CHECK-NEXT: args uses:
72 ; CHECK-NEXT: allocas uses:
73 ; CHECK-NEXT: x[4]: [0,7){{$}}
74 ; GLOBAL-NEXT: safe accesses:
77 %x = alloca i32, align 4
78 %size = select i1 %z, i32 3, i32 4
79 call void @llvm.memset.p0.i32(ptr %x, i8 42, i32 %size, i1 false)
83 define void @MemsetNonConstSize() {
84 ; CHECK-LABEL: MemsetNonConstSize dso_preemptable{{$}}
85 ; CHECK-NEXT: args uses:
86 ; CHECK-NEXT: allocas uses:
87 ; CHECK-NEXT: x[4]: [0,4294967295){{$}}
88 ; CHECK-NEXT: y[4]: empty-set{{$}}
89 ; GLOBAL-NEXT: safe accesses:
92 %x = alloca i32, align 4
93 %y = alloca i32, align 4
94 %xint = ptrtoint ptr %x to i32
95 %yint = ptrtoint ptr %y to i32
96 %d = sub i32 %xint, %yint
97 call void @llvm.memset.p0.i32(ptr %x, i8 42, i32 %d, i1 false)
101 define void @MemcpyInBounds() {
102 ; CHECK-LABEL: MemcpyInBounds dso_preemptable{{$}}
103 ; CHECK-NEXT: args uses:
104 ; CHECK-NEXT: allocas uses:
105 ; CHECK-NEXT: x[4]: [0,4){{$}}
106 ; CHECK-NEXT: y[4]: [0,4){{$}}
107 ; GLOBAL-NEXT: safe accesses:
108 ; GLOBAL-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr %x, ptr %y, i32 4, i1 false)
111 %x = alloca i32, align 4
112 %y = alloca i32, align 4
113 call void @llvm.memcpy.p0.p0.i32(ptr %x, ptr %y, i32 4, i1 false)
117 define void @MemcpySrcOutOfBounds() {
118 ; CHECK-LABEL: MemcpySrcOutOfBounds dso_preemptable{{$}}
119 ; CHECK-NEXT: args uses:
120 ; CHECK-NEXT: allocas uses:
121 ; CHECK-NEXT: x[8]: [0,5){{$}}
122 ; CHECK-NEXT: y[4]: [0,5){{$}}
123 ; GLOBAL-NEXT: safe accesses
126 %x = alloca i64, align 4
127 %y = alloca i32, align 4
128 call void @llvm.memcpy.p0.p0.i32(ptr %x, ptr %y, i32 5, i1 false)
132 define void @MemcpyDstOutOfBounds() {
133 ; CHECK-LABEL: MemcpyDstOutOfBounds dso_preemptable{{$}}
134 ; CHECK-NEXT: args uses:
135 ; CHECK-NEXT: allocas uses:
136 ; CHECK-NEXT: x[4]: [0,5){{$}}
137 ; CHECK-NEXT: y[8]: [0,5){{$}}
138 ; GLOBAL-NEXT: safe accesses
141 %x = alloca i32, align 4
142 %y = alloca i64, align 4
143 call void @llvm.memcpy.p0.p0.i32(ptr %x, ptr %y, i32 5, i1 false)
147 define void @MemcpyBothOutOfBounds() {
148 ; CHECK-LABEL: MemcpyBothOutOfBounds dso_preemptable{{$}}
149 ; CHECK-NEXT: args uses:
150 ; CHECK-NEXT: allocas uses:
151 ; CHECK-NEXT: x[4]: [0,9){{$}}
152 ; CHECK-NEXT: y[8]: [0,9){{$}}
153 ; GLOBAL-NEXT: safe accesses
156 %x = alloca i32, align 4
157 %y = alloca i64, align 4
158 call void @llvm.memcpy.p0.p0.i32(ptr %x, ptr %y, i32 9, i1 false)
162 define void @MemcpySelfInBounds() {
163 ; CHECK-LABEL: MemcpySelfInBounds dso_preemptable{{$}}
164 ; CHECK-NEXT: args uses:
165 ; CHECK-NEXT: allocas uses:
166 ; CHECK-NEXT: x[8]: [0,8){{$}}
167 ; GLOBAL-NEXT: safe accesses
168 ; GLOBAL-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr %x, ptr %x2, i32 3, i1 false)
171 %x = alloca i64, align 4
172 %x2 = getelementptr i8, ptr %x, i64 5
173 call void @llvm.memcpy.p0.p0.i32(ptr %x, ptr %x2, i32 3, i1 false)
177 define void @MemcpySelfSrcOutOfBounds() {
178 ; CHECK-LABEL: MemcpySelfSrcOutOfBounds dso_preemptable{{$}}
179 ; CHECK-NEXT: args uses:
180 ; CHECK-NEXT: allocas uses:
181 ; CHECK-NEXT: x[8]: [0,9){{$}}
182 ; GLOBAL-NEXT: safe accesses:
185 %x = alloca i64, align 4
186 %x2 = getelementptr i8, ptr %x, i64 5
187 call void @llvm.memcpy.p0.p0.i32(ptr %x, ptr %x2, i32 4, i1 false)
191 define void @MemcpySelfDstOutOfBounds() {
192 ; CHECK-LABEL: MemcpySelfDstOutOfBounds dso_preemptable{{$}}
193 ; CHECK-NEXT: args uses:
194 ; CHECK-NEXT: allocas uses:
195 ; CHECK-NEXT: x[8]: [0,9){{$}}
196 ; GLOBAL-NEXT: safe accesses:
199 %x = alloca i64, align 4
200 %x2 = getelementptr i8, ptr %x, i64 5
201 call void @llvm.memcpy.p0.p0.i32(ptr %x2, ptr %x, i32 4, i1 false)
205 define void @MemmoveSelfBothOutOfBounds() {
206 ; CHECK-LABEL: MemmoveSelfBothOutOfBounds dso_preemptable{{$}}
207 ; CHECK-NEXT: args uses:
208 ; CHECK-NEXT: allocas uses:
209 ; CHECK-NEXT: x[8]: [0,14){{$}}
210 ; GLOBAL-NEXT: safe accesses:
213 %x = alloca i64, align 4
214 %x2 = getelementptr i8, ptr %x, i64 5
215 call void @llvm.memmove.p0.p0.i32(ptr %x, ptr %x2, i32 9, i1 false)
219 define void @MemsetInBoundsCast() {
220 ; CHECK-LABEL: MemsetInBoundsCast dso_preemptable{{$}}
221 ; CHECK-NEXT: args uses:
222 ; CHECK-NEXT: allocas uses:
223 ; CHECK-NEXT: x[4]: [0,4){{$}}
224 ; CHECK-NEXT: y[1]: empty-set{{$}}
225 ; GLOBAL-NEXT: safe accesses:
226 ; GLOBAL-NEXT: call void @llvm.memset.p0.i32(ptr %x, i8 %yint, i32 4, i1 false)
229 %x = alloca i32, align 4
230 %y = alloca i8, align 1
231 %yint = ptrtoint ptr %y to i8
232 call void @llvm.memset.p0.i32(ptr %x, i8 %yint, i32 4, i1 false)
236 define void @MemcpyInBoundsCast2(i8 %zint8) {
237 ; CHECK-LABEL: MemcpyInBoundsCast2 dso_preemptable{{$}}
238 ; CHECK-NEXT: args uses:
239 ; CHECK-NEXT: allocas uses:
240 ; CHECK-NEXT: x[256]: [0,255){{$}}
241 ; CHECK-NEXT: y[256]: [0,255){{$}}
242 ; CHECK-NEXT: z[1]: empty-set{{$}}
243 ; GLOBAL-NEXT: safe accesses:
244 ; GLOBAL-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr %x, ptr %y, i32 %zint32, i1 false)
247 %x = alloca [256 x i8], align 4
248 %y = alloca [256 x i8], align 4
249 %z = alloca i8, align 1
250 %zint32 = zext i8 %zint8 to i32
251 call void @llvm.memcpy.p0.p0.i32(ptr %x, ptr %y, i32 %zint32, i1 false)