xref: /llvm-project/llvm/test/Analysis/StackSafetyAnalysis/memintrin.ll (revision a6d401703b7542e00c85767513be0851df6c67cf)
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
3
4target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
5target triple = "x86_64-unknown-linux-gnu"
6
7declare void @llvm.memset.p0.i64(ptr %dest, i8 %val, i64 %len, i1 %isvolatile)
8declare void @llvm.memset.p0.i32(ptr %dest, i8 %val, i32 %len, i1 %isvolatile)
9declare void @llvm.memcpy.p0.p0.i32(ptr %dest, ptr %src, i32 %len, i1 %isvolatile)
10declare void @llvm.memmove.p0.p0.i32(ptr %dest, ptr %src, i32 %len, i1 %isvolatile)
11
12define 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)
19; CHECK-EMPTY:
20entry:
21  %x = alloca i32, align 4
22  call void @llvm.memset.p0.i32(ptr %x, i8 42, i32 4, i1 false)
23  ret void
24}
25
26; Volatile does not matter for access bounds.
27define 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)
34; CHECK-EMPTY:
35entry:
36  %x = alloca i32, align 4
37  call void @llvm.memset.p0.i32(ptr %x, i8 42, i32 4, i1 true)
38  ret void
39}
40
41define 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:
47; CHECK-EMPTY:
48entry:
49  %x = alloca i32, align 4
50  call void @llvm.memset.p0.i32(ptr %x, i8 42, i32 5, i1 false)
51  ret void
52}
53
54define 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:
60; CHECK-EMPTY:
61entry:
62  %x = alloca i32, align 4
63  call void @llvm.memset.p0.i32(ptr %x, i8 42, i32 %size, i1 false)
64  ret void
65}
66
67; FIXME: memintrinsics should look at size range when possible
68; Right now we refuse any non-constant size.
69define 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:
75; CHECK-EMPTY:
76entry:
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)
80  ret void
81}
82
83define 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:
90; CHECK-EMPTY:
91entry:
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)
98  ret void
99}
100
101define void @MemsetHugeUpper_m1(i1 %bool) {
102; CHECK-LABEL: MemsetHugeUpper_m1 dso_preemptable{{$}}
103; CHECK-NEXT: args uses:
104; CHECK-NEXT: allocas uses:
105; CHECK-NEXT:   x[4]: full-set
106entry:
107  %x = alloca i32, align 4
108  br i1 %bool, label %if.then, label %if.end
109
110if.then:
111  call void @llvm.memset.p0.i64(ptr %x, i8 0, i64 -1, i1 false)
112  br label %if.end
113
114if.end:
115  ret void
116}
117
118define void @MemsetHugeUpper_m2(i1 %bool) {
119; CHECK-LABEL: MemsetHugeUpper_m2 dso_preemptable{{$}}
120; CHECK-NEXT: args uses:
121; CHECK-NEXT: allocas uses:
122; CHECK-NEXT:   x[4]: full-set
123entry:
124  %x = alloca i32, align 4
125  br i1 %bool, label %if.then, label %if.end
126
127if.then:
128  call void @llvm.memset.p0.i64(ptr %x, i8 0, i64 -2, i1 false)
129  br label %if.end
130
131if.end:
132  ret void
133}
134
135define void @MemcpyInBounds() {
136; CHECK-LABEL: MemcpyInBounds dso_preemptable{{$}}
137; CHECK-NEXT: args uses:
138; CHECK-NEXT: allocas uses:
139; CHECK-NEXT: x[4]: [0,4){{$}}
140; CHECK-NEXT: y[4]: [0,4){{$}}
141; GLOBAL-NEXT: safe accesses:
142; GLOBAL-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr %x, ptr %y, i32 4, i1 false)
143; CHECK-EMPTY:
144entry:
145  %x = alloca i32, align 4
146  %y = alloca i32, align 4
147  call void @llvm.memcpy.p0.p0.i32(ptr %x, ptr %y, i32 4, i1 false)
148  ret void
149}
150
151define void @MemcpySrcOutOfBounds() {
152; CHECK-LABEL: MemcpySrcOutOfBounds dso_preemptable{{$}}
153; CHECK-NEXT: args uses:
154; CHECK-NEXT: allocas uses:
155; CHECK-NEXT: x[8]: [0,5){{$}}
156; CHECK-NEXT: y[4]: [0,5){{$}}
157; GLOBAL-NEXT: safe accesses
158; CHECK-EMPTY:
159entry:
160  %x = alloca i64, align 4
161  %y = alloca i32, align 4
162  call void @llvm.memcpy.p0.p0.i32(ptr %x, ptr %y, i32 5, i1 false)
163  ret void
164}
165
166define void @MemcpyDstOutOfBounds() {
167; CHECK-LABEL: MemcpyDstOutOfBounds dso_preemptable{{$}}
168; CHECK-NEXT: args uses:
169; CHECK-NEXT: allocas uses:
170; CHECK-NEXT: x[4]: [0,5){{$}}
171; CHECK-NEXT: y[8]: [0,5){{$}}
172; GLOBAL-NEXT: safe accesses
173; CHECK-EMPTY:
174entry:
175  %x = alloca i32, align 4
176  %y = alloca i64, align 4
177  call void @llvm.memcpy.p0.p0.i32(ptr %x, ptr %y, i32 5, i1 false)
178  ret void
179}
180
181define void @MemcpyBothOutOfBounds() {
182; CHECK-LABEL: MemcpyBothOutOfBounds dso_preemptable{{$}}
183; CHECK-NEXT: args uses:
184; CHECK-NEXT: allocas uses:
185; CHECK-NEXT: x[4]: [0,9){{$}}
186; CHECK-NEXT: y[8]: [0,9){{$}}
187; GLOBAL-NEXT: safe accesses
188; CHECK-EMPTY:
189entry:
190  %x = alloca i32, align 4
191  %y = alloca i64, align 4
192  call void @llvm.memcpy.p0.p0.i32(ptr %x, ptr %y, i32 9, i1 false)
193  ret void
194}
195
196define void @MemcpySelfInBounds() {
197; CHECK-LABEL: MemcpySelfInBounds dso_preemptable{{$}}
198; CHECK-NEXT: args uses:
199; CHECK-NEXT: allocas uses:
200; CHECK-NEXT: x[8]: [0,8){{$}}
201; GLOBAL-NEXT: safe accesses
202; GLOBAL-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr %x, ptr %x2, i32 3, i1 false)
203; CHECK-EMPTY:
204entry:
205  %x = alloca i64, align 4
206  %x2 = getelementptr i8, ptr %x, i64 5
207  call void @llvm.memcpy.p0.p0.i32(ptr %x, ptr %x2, i32 3, i1 false)
208  ret void
209}
210
211define void @MemcpySelfSrcOutOfBounds() {
212; CHECK-LABEL: MemcpySelfSrcOutOfBounds dso_preemptable{{$}}
213; CHECK-NEXT: args uses:
214; CHECK-NEXT: allocas uses:
215; CHECK-NEXT: x[8]: [0,9){{$}}
216; GLOBAL-NEXT: safe accesses:
217; CHECK-EMPTY:
218entry:
219  %x = alloca i64, align 4
220  %x2 = getelementptr i8, ptr %x, i64 5
221  call void @llvm.memcpy.p0.p0.i32(ptr %x, ptr %x2, i32 4, i1 false)
222  ret void
223}
224
225define void @MemcpySelfDstOutOfBounds() {
226; CHECK-LABEL: MemcpySelfDstOutOfBounds dso_preemptable{{$}}
227; CHECK-NEXT: args uses:
228; CHECK-NEXT: allocas uses:
229; CHECK-NEXT: x[8]: [0,9){{$}}
230; GLOBAL-NEXT: safe accesses:
231; CHECK-EMPTY:
232entry:
233  %x = alloca i64, align 4
234  %x2 = getelementptr i8, ptr %x, i64 5
235  call void @llvm.memcpy.p0.p0.i32(ptr %x2, ptr %x, i32 4, i1 false)
236  ret void
237}
238
239define void @MemmoveSelfBothOutOfBounds() {
240; CHECK-LABEL: MemmoveSelfBothOutOfBounds dso_preemptable{{$}}
241; CHECK-NEXT: args uses:
242; CHECK-NEXT: allocas uses:
243; CHECK-NEXT: x[8]: [0,14){{$}}
244; GLOBAL-NEXT: safe accesses:
245; CHECK-EMPTY:
246entry:
247  %x = alloca i64, align 4
248  %x2 = getelementptr i8, ptr %x, i64 5
249  call void @llvm.memmove.p0.p0.i32(ptr %x, ptr %x2, i32 9, i1 false)
250  ret void
251}
252
253define void @MemsetInBoundsCast() {
254; CHECK-LABEL: MemsetInBoundsCast dso_preemptable{{$}}
255; CHECK-NEXT: args uses:
256; CHECK-NEXT: allocas uses:
257; CHECK-NEXT: x[4]: [0,4){{$}}
258; CHECK-NEXT: y[1]: empty-set{{$}}
259; GLOBAL-NEXT: safe accesses:
260; GLOBAL-NEXT: call void @llvm.memset.p0.i32(ptr %x, i8 %yint, i32 4, i1 false)
261; CHECK-EMPTY:
262entry:
263  %x = alloca i32, align 4
264  %y = alloca i8, align 1
265  %yint = ptrtoint ptr %y to i8
266  call void @llvm.memset.p0.i32(ptr %x, i8 %yint, i32 4, i1 false)
267  ret void
268}
269
270define void @MemcpyInBoundsCast2(i8 %zint8) {
271; CHECK-LABEL: MemcpyInBoundsCast2 dso_preemptable{{$}}
272; CHECK-NEXT: args uses:
273; CHECK-NEXT: allocas uses:
274; CHECK-NEXT: x[256]: [0,255){{$}}
275; CHECK-NEXT: y[256]: [0,255){{$}}
276; CHECK-NEXT: z[1]: empty-set{{$}}
277; GLOBAL-NEXT: safe accesses:
278; GLOBAL-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr %x, ptr %y, i32 %zint32, i1 false)
279; CHECK-EMPTY:
280entry:
281  %x = alloca [256 x i8], align 4
282  %y = alloca [256 x i8], align 4
283  %z = alloca i8, align 1
284  %zint32 = zext i8 %zint8 to i32
285  call void @llvm.memcpy.p0.p0.i32(ptr %x, ptr %y, i32 %zint32, i1 false)
286  ret void
287}
288