xref: /llvm-project/clang/test/Frontend/stack-layout-remark.c (revision 557a5bc336ffb9b03c53d4d13fd8f0bc9418ec96)
1 // Check that backend stack layout diagnostics are working correctly with and
2 // without debug information, and when optimizations are enabled
3 //
4 // REQUIRES: x86-registered-target
5 //
6 // RUN: rm -rf %t
7 // RUN: mkdir -p %t
8 // RUN: %clang_cc1 %s -emit-codegen-only -triple x86_64-unknown-linux-gnu -target-cpu corei7 -Rpass-analysis=stack-frame-layout -o /dev/null  -O0  2>&1 | FileCheck %s --check-prefix=O0-NODEBUG
9 // RUN: %clang_cc1 %s -emit-codegen-only -triple x86_64-unknown-linux-gnu -target-cpu corei7 -Rpass-analysis=stack-frame-layout -o /dev/null  -O0  -debug-info-kind=constructor  -dwarf-version=5 -debugger-tuning=gdb 2>&1 | FileCheck %s --check-prefix=O0-DEBUG
10 // RUN: %clang_cc1 %s -emit-codegen-only -triple x86_64-unknown-linux-gnu -target-cpu corei7 -funwind-tables=2 -O3 -Rpass-analysis=stack-frame-layout   -debug-info-kind=constructor  -dwarf-version=5 -debugger-tuning=gdb -opt-record-file %t/stack-layout-remark.c.yml -opt-record-passes stack-frame-layout 2>&1 | FileCheck %s --check-prefix=O3-DEBUG
11 // RUN: cat %t/stack-layout-remark.c.yml | FileCheck %s --check-prefix=YAML
12 
13 #define NULL (void*)0
14 
15 extern void* allocate(unsigned size);
16 extern void deallocate(void* ptr);
17 extern int work(char *ary, int size);
18 extern int rand(void);
19 
20 // Test YAML Ouput
21 // YAML: --- !Analysis
22 // YAML: Pass:            stack-frame-layout
23 // YAML: Name:            StackLayout
24 // YAML: DebugLoc:        { File: '{{.*}}stack-layout-remark.c',{{[[:space:]]*}}Line: [[# @LINE + 24]],
25 // YAML: Function:        foo
26 // YAML: Args:
27 // YAML:   - Offset:          '-40'
28 // YAML:   - Type:            Variable
29 // YAML:   - Align:           '16'
30 // YAML:   - Size:            '32'
31 // YAML:   - DataLoc:         'a @ {{.*}}stack-layout-remark.c:[[# @LINE + 19]]'
32 // YAML:   - DataLoc:         'f @ {{.*}}stack-layout-remark.c:[[# @LINE + 21]]'
33 
34 //      O0-NODEBUG: Function: foo
35 // O0-NODEBUG-NEXT: Offset: [SP-40], Type: Variable, Align: 16, Size: 32
36 // O0-NODEBUG-NEXT: Offset: [SP-72], Type: Variable, Align: 16, Size: 32
37 //
38 //      O0-DEBUG: Function: foo
39 // O0-DEBUG-NEXT: Offset: [SP-40], Type: Variable, Align: 16, Size: 32
40 // O0-DEBUG-NEXT:     a @ {{.*}}stack-layout-remark.c:[[# @LINE + 10]]
41 // O0-DEBUG-NEXT: Offset: [SP-72], Type: Variable, Align: 16, Size: 32
42 // O0-DEBUG-NEXT:     f @ {{.*}}stack-layout-remark.c:[[# @LINE + 11]]
43 
44 //      O3-DEBUG: Function: foo
45 // O3-DEBUG-NEXT: Offset: [SP-40], Type: Variable, Align: 16, Size: 32
46 // O3-DEBUG-NEXT:     a @ {{.*}}stack-layout-remark.c:[[# @LINE + 4]]
47 // O3-DEBUG-NEXT:     f @ {{.*}}stack-layout-remark.c:[[# @LINE + 6]]
foo()48 void foo() {
49   {
50     char a[32] = {0};
51     work(a, sizeof(a));
52   }
53   char f[32] = {0};
54   work(f, sizeof(f));
55 }
56 //      O0-NODEBUG: Function: bar
57 // O0-NODEBUG-NEXT: Offset: [SP-40], Type: Variable, Align: 16, Size: 32
58 // O0-NODEBUG-NEXT: Offset: [SP-72], Type: Variable, Align: 16, Size: 32
59 
60 //      O0-DEBUG: Function: bar
61 // O0-DEBUG-NEXT: Offset: [SP-40], Type: Variable, Align: 16, Size: 32
62 // O0-DEBUG-NEXT:     f @ {{.*}}stack-layout-remark.c:[[# @LINE + 10]]
63 // O0-DEBUG-NEXT: Offset: [SP-72], Type: Variable, Align: 16, Size: 32
64 // O0-DEBUG-NEXT:     a @ {{.*}}stack-layout-remark.c:[[# @LINE + 10]]
65 
66 //      O3-DEBUG: Function: bar
67 // O3-DEBUG-NEXT: Offset: [SP-40], Type: Variable, Align: 16, Size: 32
68 // O3-DEBUG-NEXT:     f @ {{.*}}stack-layout-remark.c:[[# @LINE + 4]]
69 // O3-DEBUG-NEXT: Offset: [SP-72], Type: Variable, Align: 16, Size: 32
70 // O3-DEBUG-NEXT:     a @ {{.*}}stack-layout-remark.c:[[# @LINE + 4]]
bar()71 void bar() {
72   char f[32] = {0};
73   {
74     char a[32] = {0};
75     work(a, sizeof(a));
76   }
77   work(f, sizeof(f));
78 }
79 
80 struct Array {
81   int *data;
82   int size;
83 };
84 
85 struct Result {
86   struct Array *data;
87   int sum;
88 };
89 
90 //      O0-NODEBUG: Function: cleanup_array
91 // O0-NODEBUG-NEXT: Offset: [SP-8], Type: Variable, Align: 8, Size: 8
92 
93 //      O0-DEBUG: Function: cleanup_array
94 // O0-DEBUG-NEXT: Offset: [SP-8], Type: Variable, Align: 8, Size: 8
95 // O0-DEBUG-NEXT:     a @ {{.*}}stack-layout-remark.c:[[# @LINE + 5]]
96 
97 //      O3-DEBUG: Function: cleanup_array
98 //      O3-DEBUG: Function: cleanup_result
99 // O3-DEBUG-NEXT: Offset: [SP-8], Type: Spill, Align: 16, Size: 8
cleanup_array(struct Array * a)100 void cleanup_array(struct Array *a) {
101   if (!a)
102     return;
103   if (!a->data)
104     return;
105   deallocate(a->data);
106 }
107 
108 //      O0-NODEBUG: Function: cleanup_result
109 // O0-NODEBUG-NEXT: Offset: [SP-8], Type: Variable, Align: 8, Size: 8
110 
111 //      O0-DEBUG: Function: cleanup_result
112 // O0-DEBUG-NEXT: Offset: [SP-8], Type: Variable, Align: 8, Size: 8
113 // O0-DEBUG-NEXT:     res @ {{.*}}stack-layout-remark.c:[[# @LINE + 1]]
cleanup_result(struct Result * res)114 void cleanup_result(struct Result *res) {
115   if (!res)
116     return;
117   if (!res->data)
118     return;
119   cleanup_array(res->data);
120   deallocate(res->data);
121 }
122 
123 extern void use_dot_vector(struct Array *data);
124 
125 //      O0-NODEBUG: Function: do_work
126 // O0-NODEBUG-NEXT: Offset: [SP-4], Type: Variable, Align: 4, Size: 4
127 // O0-NODEBUG-NEXT: Offset: [SP-16], Type: Variable, Align: 8, Size: 8
128 // O0-NODEBUG-NEXT: Offset: [SP-24], Type: Variable, Align: 8, Size: 8
129 // O0-NODEBUG-NEXT: Offset: [SP-32], Type: Variable, Align: 8, Size: 8
130 // O0-NODEBUG-NEXT: Offset: [SP-36], Type: Variable, Align: 4, Size: 4
131 // O0-NODEBUG-NEXT: Offset: [SP-48], Type: Variable, Align: 8, Size: 8
132 // O0-NODEBUG-NEXT: Offset: [SP-52], Type: Variable, Align: 4, Size: 4
133 // O0-NODEBUG-NEXT: Offset: [SP-56], Type: Variable, Align: 4, Size: 4
134 
135 //      O0-DEBUG: Function: do_work
136 // O0-DEBUG-NEXT: Offset: [SP-4], Type: Variable, Align: 4, Size: 4
137 // O0-DEBUG-NEXT: Offset: [SP-16], Type: Variable, Align: 8, Size: 8
138 // O0-DEBUG-NEXT:     A @ {{.*}}stack-layout-remark.c:[[# @LINE + 20]]
139 // O0-DEBUG-NEXT: Offset: [SP-24], Type: Variable, Align: 8, Size: 8
140 // O0-DEBUG-NEXT:     B @ {{.*}}stack-layout-remark.c:[[# @LINE + 18]]
141 // O0-DEBUG-NEXT: Offset: [SP-32], Type: Variable, Align: 8, Size: 8
142 // O0-DEBUG-NEXT:     out @ {{.*}}stack-layout-remark.c:[[# @LINE + 16]]
143 // O0-DEBUG-NEXT: Offset: [SP-36], Type: Variable, Align: 4, Size: 4
144 // O0-DEBUG-NEXT:     len @ {{.*}}stack-layout-remark.c:[[# @LINE + 19]]
145 // O0-DEBUG-NEXT: Offset: [SP-48], Type: Variable, Align: 8, Size: 8
146 // O0-DEBUG-NEXT:     AB @ {{.*}}stack-layout-remark.c:[[# @LINE + 18]]
147 // O0-DEBUG-NEXT: Offset: [SP-52], Type: Variable, Align: 4, Size: 4
148 // O0-DEBUG-NEXT:     sum @ {{.*}}stack-layout-remark.c:[[# @LINE + 32]]
149 // O0-DEBUG-NEXT: Offset: [SP-56], Type: Variable, Align: 4, Size: 4
150 // O0-DEBUG-NEXT:     i @ {{.*}}stack-layout-remark.c:[[# @LINE + 31]]
151 
152 //      O3-DEBUG: Function: do_work
153 // O3-DEBUG-NEXT: Offset: [SP-8], Type: Spill, Align: 16, Size: 8
154 // O3-DEBUG-NEXT: Offset: [SP-16], Type: Spill, Align: 8, Size: 8
155 // O3-DEBUG-NEXT: Offset: [SP-24], Type: Spill, Align: 16, Size: 8
156 // O3-DEBUG-NEXT: Offset: [SP-32], Type: Spill, Align: 8, Size: 8
157 // O3-DEBUG-NEXT: Offset: [SP-40], Type: Spill, Align: 16, Size: 8
do_work(struct Array * A,struct Array * B,struct Result * out)158 int do_work(struct Array *A, struct Array *B, struct Result *out) {
159   if (!A || !B)
160     return -1;
161   if (A->size != B->size)
162     return -1;
163   const int len = A->size;
164   struct Array *AB;
165   if (out->data == NULL) {
166     AB = (struct Array *)allocate(sizeof(struct Array));
167     AB->data = NULL;
168     AB->size = 0;
169     out->data = AB;
170   } else {
171     AB = out->data;
172   }
173 
174   if (AB->data)
175     deallocate(AB->data);
176 
177   AB->data = (int *)allocate(len * sizeof(int));
178   AB->size = len;
179 
180   int sum = 0;
181   for (int i = 0; i < len; ++i) {
182     AB->data[i] = A->data[i] * B->data[i];
183     sum += AB->data[i];
184   }
185   return sum;
186 }
187 
188 //      O0-NODEBUG: Function: gen_array
189 // O0-NODEBUG-NEXT: Offset: [SP-8], Type: Variable, Align: 8, Size: 8
190 // O0-NODEBUG-NEXT: Offset: [SP-12], Type: Variable, Align: 4, Size: 4
191 // O0-NODEBUG-NEXT: Offset: [SP-24], Type: Variable, Align: 8, Size: 8
192 // O0-NODEBUG-NEXT: Offset: [SP-28], Type: Variable, Align: 4, Size: 4
193 
194 //      O0-DEBUG: Function: gen_array
195 // O0-DEBUG-NEXT: Offset: [SP-8], Type: Variable, Align: 8, Size: 8
196 // O0-DEBUG-NEXT: Offset: [SP-12], Type: Variable, Align: 4, Size: 4
197 // O0-DEBUG-NEXT:     size @ {{.*}}stack-layout-remark.c:[[# @LINE + 10]]
198 // O0-DEBUG-NEXT: Offset: [SP-24], Type: Variable, Align: 8, Size: 8
199 // O0-DEBUG-NEXT:     res @ {{.*}}stack-layout-remark.c:[[# @LINE + 11]]
200 // O0-DEBUG-NEXT: Offset: [SP-28], Type: Variable, Align: 4, Size: 4
201 // O0-DEBUG-NEXT:     i @ {{.*}}stack-layout-remark.c:[[# @LINE + 13]]
202 
203 //      O3-DEBUG: Function: gen_array
204 // O3-DEBUG-NEXT: Offset: [SP-8], Type: Spill, Align: 16, Size: 8
205 // O3-DEBUG-NEXT: Offset: [SP-16], Type: Spill, Align: 8, Size: 8
206 // O3-DEBUG-NEXT: Offset: [SP-24], Type: Spill, Align: 16, Size: 8
gen_array(int size)207 struct Array *gen_array(int size) {
208   if (size < 0)
209     return NULL;
210   struct Array *res = (struct Array *)allocate(sizeof(struct Array));
211   res->size = size;
212   res->data = (int *)allocate(size * sizeof(int));
213 
214   for (int i = 0; i < size; ++i) {
215     res->data[i] = rand();
216   }
217 
218   return res;
219 }
220 
221 // YAML: --- !Analysis
222 // YAML: Pass:            stack-frame-layout
223 // YAML: Name:            StackLayout
224 // YAML: DebugLoc:        { File: '{{.*}}stack-layout-remark.c',{{[[:space:]]*}}Line: [[# @LINE + 59]],
225 // YAML: Function:        caller
226 // YAML: Args:
227 // YAML:   - Offset:          '-8'
228 // YAML:   - Type:            Spill
229 // YAML:   - Align:           '16'
230 // YAML:   - Size:            '8'
231 // YAML:   - Offset:          '-16'
232 // YAML:   - Type:            Spill
233 // YAML:   - Align:           '8'
234 // YAML:   - Size:            '8'
235 // YAML:   - Offset:          '-24'
236 // YAML:   - Type:            Spill
237 // YAML:   - Align:           '16'
238 // YAML:   - Size:            '8'
239 // YAML:   - Offset:          '-32'
240 // YAML:   - Type:            Spill
241 // YAML:   - Align:           '8'
242 // YAML:   - Size:            '8'
243 // YAML:   - Offset:          '-40'
244 // YAML:   - Type:            Spill
245 // YAML:   - Align:           '16'
246 // YAML:   - Size:            '8'
247 // YAML:   - Offset:          '-48'
248 // YAML:   - Type:            Spill
249 // YAML:   - Align:           '8'
250 // YAML:   - Size:            '8'
251 
252 //      O0-NODEBUG: Function: caller
253 // O0-NODEBUG-NEXT: Offset: [SP-4], Type: Variable, Align: 4, Size: 4
254 // O0-NODEBUG-NEXT: Offset: [SP-8], Type: Variable, Align: 4, Size: 4
255 // O0-NODEBUG-NEXT: Offset: [SP-16], Type: Variable, Align: 8, Size: 8
256 // O0-NODEBUG-NEXT: Offset: [SP-24], Type: Variable, Align: 8, Size: 8
257 // O0-NODEBUG-NEXT: Offset: [SP-32], Type: Variable, Align: 8, Size: 8
258 // O0-NODEBUG-NEXT: Offset: [SP-36], Type: Variable, Align: 4, Size: 4
259 // O0-NODEBUG-NEXT: Offset: [SP-40], Type: Variable, Align: 4, Size: 4
260 
261 //      O0-DEBUG: Function: caller
262 // O0-DEBUG-NEXT: Offset: [SP-4], Type: Variable, Align: 4, Size: 4
263 // O0-DEBUG-NEXT: Offset: [SP-8], Type: Variable, Align: 4, Size: 4
264 // O0-DEBUG-NEXT:     size @ {{.*}}stack-layout-remark.c:[[# @LINE + 20]]
265 // O0-DEBUG-NEXT: Offset: [SP-16], Type: Variable, Align: 8, Size: 8
266 // O0-DEBUG-NEXT:     A @ {{.*}}stack-layout-remark.c:[[# @LINE + 19]]
267 // O0-DEBUG-NEXT: Offset: [SP-24], Type: Variable, Align: 8, Size: 8
268 // O0-DEBUG-NEXT:     B @ {{.*}}stack-layout-remark.c:[[# @LINE + 18]]
269 // O0-DEBUG-NEXT: Offset: [SP-32], Type: Variable, Align: 8, Size: 8
270 // O0-DEBUG-NEXT:     res @ {{.*}}stack-layout-remark.c:[[# @LINE + 17]]
271 // O0-DEBUG-NEXT: Offset: [SP-36], Type: Variable, Align: 4, Size: 4
272 // O0-DEBUG-NEXT:     ret @ {{.*}}stack-layout-remark.c:[[# @LINE + 16]]
273 // O0-DEBUG-NEXT: Offset: [SP-40], Type: Variable, Align: 4, Size: 4
274 // O0-DEBUG-NEXT:     err @ {{.*}}stack-layout-remark.c:[[# @LINE + 16]]
275 
276 //      O3-DEBUG: Function: caller
277 // O3-DEBUG-NEXT: Offset: [SP-8], Type: Spill, Align: 16, Size: 8
278 // O3-DEBUG-NEXT: Offset: [SP-16], Type: Spill, Align: 8, Size: 8
279 // O3-DEBUG-NEXT: Offset: [SP-24], Type: Spill, Align: 16, Size: 8
280 // O3-DEBUG-NEXT: Offset: [SP-32], Type: Spill, Align: 8, Size: 8
281 // O3-DEBUG-NEXT: Offset: [SP-40], Type: Spill, Align: 16, Size: 8
282 // O3-DEBUG-NEXT: Offset: [SP-48], Type: Spill, Align: 8, Size: 8
caller()283 int caller() {
284   const int size = 100;
285   struct Array *A = gen_array(size);
286   struct Array *B = gen_array(size);
287   struct Result *res = (struct Result *)allocate(sizeof(struct Result));
288   int ret = -1;
289 
290   int err = do_work(A, B, res);
291   if (err == -1) {
292     goto cleanup;
293   }
294 
295   ret = res->sum;
296   if (ret == -1)
297     return caller();
298 
299   use_dot_vector(res->data);
300 
301 cleanup:
302   cleanup_array(A);
303   cleanup_array(B);
304   cleanup_result(res);
305 
306   return ret;
307 }
308 
309