1; RUN: opt -S -analyze -stack-safety-local < %s | FileCheck %s
2; RUN: opt -S -passes="print<stack-safety-local>" -disable-output < %s 2>&1 | FileCheck %s
3; RUN: opt -S -analyze -stack-safety < %s | FileCheck %s
4; RUN: opt -S -passes="print-stack-safety" -disable-output < %s 2>&1 | FileCheck %s
5
6target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
7target triple = "x86_64-unknown-linux-gnu"
8
9declare void @llvm.memset.p0i8.i32(i8* %dest, i8 %val, i32 %len, i1 %isvolatile)
10declare void @llvm.memcpy.p0i8.p0i8.i32(i8* %dest, i8* %src, i32 %len, i1 %isvolatile)
11declare void @llvm.memmove.p0i8.p0i8.i32(i8* %dest, i8* %src, i32 %len, i1 %isvolatile)
12
13define void @MemsetInBounds() {
14; CHECK-LABEL: MemsetInBounds dso_preemptable{{$}}
15; CHECK-NEXT: args uses:
16; CHECK-NEXT: allocas uses:
17; CHECK-NEXT: x[4]: [0,4){{$}}
18; CHECK-NOT: ]:
19entry:
20  %x = alloca i32, align 4
21  %x1 = bitcast i32* %x to i8*
22  call void @llvm.memset.p0i8.i32(i8* %x1, 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; CHECK-NOT: ]:
33entry:
34  %x = alloca i32, align 4
35    %x1 = bitcast i32* %x to i8*
36  call void @llvm.memset.p0i8.i32(i8* %x1, i8 42, i32 4, i1 true)
37  ret void
38}
39
40define void @MemsetOutOfBounds() {
41; CHECK-LABEL: MemsetOutOfBounds dso_preemptable{{$}}
42; CHECK-NEXT: args uses:
43; CHECK-NEXT: allocas uses:
44; CHECK-NEXT: x[4]: [0,5){{$}}
45; CHECK-NOT: ]:
46entry:
47  %x = alloca i32, align 4
48    %x1 = bitcast i32* %x to i8*
49  call void @llvm.memset.p0i8.i32(i8* %x1, i8 42, i32 5, i1 false)
50  ret void
51}
52
53define void @MemsetNonConst(i32 %size) {
54; CHECK-LABEL: MemsetNonConst dso_preemptable{{$}}
55; CHECK-NEXT: args uses:
56; CHECK-NEXT: size[]: [0,1){{$}}
57; CHECK-NEXT: allocas uses:
58; CHECK-NEXT: x[4]: full-set{{$}}
59; CHECK-NOT: ]:
60entry:
61  %x = alloca i32, align 4
62    %x1 = bitcast i32* %x to i8*
63  call void @llvm.memset.p0i8.i32(i8* %x1, 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: z[]: [0,1){{$}}
73; CHECK-NEXT: allocas uses:
74; CHECK-NEXT: x[4]: full-set{{$}}
75; CHECK-NOT: ]:
76entry:
77  %x = alloca i32, align 4
78  %x1 = bitcast i32* %x to i8*
79  %size = select i1 %z, i32 3, i32 4
80  call void @llvm.memset.p0i8.i32(i8* %x1, i8 42, i32 %size, i1 false)
81  ret void
82}
83
84define void @MemcpyInBounds() {
85; CHECK-LABEL: MemcpyInBounds dso_preemptable{{$}}
86; CHECK-NEXT: args uses:
87; CHECK-NEXT: allocas uses:
88; CHECK-NEXT: x[4]: [0,4){{$}}
89; CHECK-NEXT: y[4]: [0,4){{$}}
90; CHECK-NOT: ]:
91entry:
92  %x = alloca i32, align 4
93  %y = alloca i32, align 4
94  %x1 = bitcast i32* %x to i8*
95  %y1 = bitcast i32* %y to i8*
96  call void @llvm.memcpy.p0i8.p0i8.i32(i8* %x1, i8* %y1, i32 4, i1 false)
97  ret void
98}
99
100define void @MemcpySrcOutOfBounds() {
101; CHECK-LABEL: MemcpySrcOutOfBounds dso_preemptable{{$}}
102; CHECK-NEXT: args uses:
103; CHECK-NEXT: allocas uses:
104; CHECK-NEXT: x[8]: [0,5){{$}}
105; CHECK-NEXT: y[4]: [0,5){{$}}
106; CHECK-NOT: ]:
107entry:
108  %x = alloca i64, align 4
109  %y = alloca i32, align 4
110  %x1 = bitcast i64* %x to i8*
111  %y1 = bitcast i32* %y to i8*
112  call void @llvm.memcpy.p0i8.p0i8.i32(i8* %x1, i8* %y1, i32 5, i1 false)
113  ret void
114}
115
116define void @MemcpyDstOutOfBounds() {
117; CHECK-LABEL: MemcpyDstOutOfBounds dso_preemptable{{$}}
118; CHECK-NEXT: args uses:
119; CHECK-NEXT: allocas uses:
120; CHECK-NEXT: x[4]: [0,5){{$}}
121; CHECK-NEXT: y[8]: [0,5){{$}}
122; CHECK-NOT: ]:
123entry:
124  %x = alloca i32, align 4
125  %y = alloca i64, align 4
126  %x1 = bitcast i32* %x to i8*
127  %y1 = bitcast i64* %y to i8*
128  call void @llvm.memcpy.p0i8.p0i8.i32(i8* %x1, i8* %y1, i32 5, i1 false)
129  ret void
130}
131
132define void @MemcpyBothOutOfBounds() {
133; CHECK-LABEL: MemcpyBothOutOfBounds dso_preemptable{{$}}
134; CHECK-NEXT: args uses:
135; CHECK-NEXT: allocas uses:
136; CHECK-NEXT: x[4]: [0,9){{$}}
137; CHECK-NEXT: y[8]: [0,9){{$}}
138; CHECK-NOT: ]:
139entry:
140  %x = alloca i32, align 4
141  %y = alloca i64, align 4
142  %x1 = bitcast i32* %x to i8*
143  %y1 = bitcast i64* %y to i8*
144  call void @llvm.memcpy.p0i8.p0i8.i32(i8* %x1, i8* %y1, i32 9, i1 false)
145  ret void
146}
147
148define void @MemcpySelfInBounds() {
149; CHECK-LABEL: MemcpySelfInBounds dso_preemptable{{$}}
150; CHECK-NEXT: args uses:
151; CHECK-NEXT: allocas uses:
152; CHECK-NEXT: x[8]: [0,8){{$}}
153; CHECK-NOT: ]:
154entry:
155  %x = alloca i64, align 4
156  %x1 = bitcast i64* %x to i8*
157  %x2 = getelementptr i8, i8* %x1, i64 5
158  call void @llvm.memcpy.p0i8.p0i8.i32(i8* %x1, i8* %x2, i32 3, i1 false)
159  ret void
160}
161
162define void @MemcpySelfSrcOutOfBounds() {
163; CHECK-LABEL: MemcpySelfSrcOutOfBounds dso_preemptable{{$}}
164; CHECK-NEXT: args uses:
165; CHECK-NEXT: allocas uses:
166; CHECK-NEXT: x[8]: [0,9){{$}}
167; CHECK-NOT: ]:
168entry:
169  %x = alloca i64, align 4
170  %x1 = bitcast i64* %x to i8*
171  %x2 = getelementptr i8, i8* %x1, i64 5
172  call void @llvm.memcpy.p0i8.p0i8.i32(i8* %x1, i8* %x2, i32 4, i1 false)
173  ret void
174}
175
176define void @MemcpySelfDstOutOfBounds() {
177; CHECK-LABEL: MemcpySelfDstOutOfBounds dso_preemptable{{$}}
178; CHECK-NEXT: args uses:
179; CHECK-NEXT: allocas uses:
180; CHECK-NEXT: x[8]: [0,9){{$}}
181; CHECK-NOT: ]:
182entry:
183  %x = alloca i64, align 4
184  %x1 = bitcast i64* %x to i8*
185  %x2 = getelementptr i8, i8* %x1, i64 5
186  call void @llvm.memcpy.p0i8.p0i8.i32(i8* %x2, i8* %x1, i32 4, i1 false)
187  ret void
188}
189
190define void @MemmoveSelfBothOutOfBounds() {
191; CHECK-LABEL: MemmoveSelfBothOutOfBounds dso_preemptable{{$}}
192; CHECK-NEXT: args uses:
193; CHECK-NEXT: allocas uses:
194; CHECK-NEXT: x[8]: [0,14){{$}}
195; CHECK-NOT: ]:
196entry:
197  %x = alloca i64, align 4
198  %x1 = bitcast i64* %x to i8*
199  %x2 = getelementptr i8, i8* %x1, i64 5
200  call void @llvm.memmove.p0i8.p0i8.i32(i8* %x1, i8* %x2, i32 9, i1 false)
201  ret void
202}
203