Bump version to 19.1.0-rc3
[llvm-project.git] / llvm / test / Transforms / LICM / gep-reassociate.ll
blob630a751999c496c96be32f57cfcbe0e2556d8e96
1 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 2
2 ; RUN: opt -S -passes=licm < %s | FileCheck %s --check-prefixes=CHECK,SPEC
3 ; RUN: opt -S -passes='licm<no-allowspeculation>' < %s | FileCheck %s --check-prefixes=CHECK,NOSPEC
5 declare void @use(ptr)
6 declare i32 @get.i32()
7 declare i64 @get.i64()
8 declare ptr @get.ptr()
10 define void @only_one_inbounds(ptr %ptr, i1 %c, i32 %arg) {
11 ; CHECK-LABEL: define void @only_one_inbounds
12 ; CHECK-SAME: (ptr [[PTR:%.*]], i1 [[C:%.*]], i32 [[ARG:%.*]]) {
13 ; CHECK-NEXT:  entry:
14 ; CHECK-NEXT:    [[ARG_EXT:%.*]] = zext i32 [[ARG]] to i64
15 ; CHECK-NEXT:    [[INVARIANT_GEP:%.*]] = getelementptr i8, ptr [[PTR]], i64 [[ARG_EXT]]
16 ; CHECK-NEXT:    br label [[LOOP:%.*]]
17 ; CHECK:       loop:
18 ; CHECK-NEXT:    [[VAL:%.*]] = call i32 @get.i32()
19 ; CHECK-NEXT:    [[VAL_EXT:%.*]] = zext i32 [[VAL]] to i64
20 ; CHECK-NEXT:    [[GEP:%.*]] = getelementptr i8, ptr [[INVARIANT_GEP]], i64 [[VAL_EXT]]
21 ; CHECK-NEXT:    call void @use(ptr [[GEP]])
22 ; CHECK-NEXT:    br i1 [[C]], label [[LOOP]], label [[EXIT:%.*]]
23 ; CHECK:       exit:
24 ; CHECK-NEXT:    ret void
26 entry:
27   %arg.ext = zext i32 %arg to i64
28   br label %loop
30 loop:
31   %val = call i32 @get.i32()
32   %val.ext = zext i32 %val to i64
33   %ptr2 = getelementptr inbounds i8, ptr %ptr, i64 %val.ext
34   %ptr3 = getelementptr i8, ptr %ptr2, i64 %arg.ext
35   call void @use(ptr %ptr3)
36   br i1 %c, label %loop, label %exit
38 exit:
39   ret void
42 define void @both_inbounds_one_neg(ptr %ptr, i1 %c) {
43 ; CHECK-LABEL: define void @both_inbounds_one_neg
44 ; CHECK-SAME: (ptr [[PTR:%.*]], i1 [[C:%.*]]) {
45 ; CHECK-NEXT:  entry:
46 ; CHECK-NEXT:    [[INVARIANT_GEP:%.*]] = getelementptr i8, ptr [[PTR]], i64 -1
47 ; CHECK-NEXT:    br label [[LOOP:%.*]]
48 ; CHECK:       loop:
49 ; CHECK-NEXT:    [[VAL:%.*]] = call i32 @get.i32()
50 ; CHECK-NEXT:    [[VAL_EXT:%.*]] = zext i32 [[VAL]] to i64
51 ; CHECK-NEXT:    [[GEP:%.*]] = getelementptr i8, ptr [[INVARIANT_GEP]], i64 [[VAL_EXT]]
52 ; CHECK-NEXT:    call void @use(ptr [[GEP]])
53 ; CHECK-NEXT:    br i1 [[C]], label [[LOOP]], label [[EXIT:%.*]]
54 ; CHECK:       exit:
55 ; CHECK-NEXT:    ret void
57 entry:
58   br label %loop
60 loop:
61   %val = call i32 @get.i32()
62   %val.ext = zext i32 %val to i64
63   %ptr2 = getelementptr inbounds i8, ptr %ptr, i64 %val.ext
64   %ptr3 = getelementptr i8, ptr %ptr2, i64 -1
65   call void @use(ptr %ptr3)
66   br i1 %c, label %loop, label %exit
68 exit:
69   ret void
72 define void @both_inbounds_pos(ptr %ptr, i1 %c) {
73 ; CHECK-LABEL: define void @both_inbounds_pos
74 ; CHECK-SAME: (ptr [[PTR:%.*]], i1 [[C:%.*]]) {
75 ; CHECK-NEXT:  entry:
76 ; CHECK-NEXT:    [[INVARIANT_GEP:%.*]] = getelementptr inbounds i8, ptr [[PTR]], i64 1
77 ; CHECK-NEXT:    br label [[LOOP:%.*]]
78 ; CHECK:       loop:
79 ; CHECK-NEXT:    [[VAL:%.*]] = call i32 @get.i32()
80 ; CHECK-NEXT:    [[VAL_EXT:%.*]] = zext i32 [[VAL]] to i64
81 ; CHECK-NEXT:    [[GEP:%.*]] = getelementptr inbounds i8, ptr [[INVARIANT_GEP]], i64 [[VAL_EXT]]
82 ; CHECK-NEXT:    call void @use(ptr [[GEP]])
83 ; CHECK-NEXT:    br i1 [[C]], label [[LOOP]], label [[EXIT:%.*]]
84 ; CHECK:       exit:
85 ; CHECK-NEXT:    ret void
87 entry:
88   br label %loop
90 loop:
91   %val = call i32 @get.i32()
92   %val.ext = zext i32 %val to i64
93   %ptr2 = getelementptr inbounds i8, ptr %ptr, i64 %val.ext
94   %ptr3 = getelementptr inbounds i8, ptr %ptr2, i64 1
95   call void @use(ptr %ptr3)
96   br i1 %c, label %loop, label %exit
98 exit:
99   ret void
102 define void @different_elem_types(ptr %ptr, i1 %c, i64 %arg) {
103 ; CHECK-LABEL: define void @different_elem_types
104 ; CHECK-SAME: (ptr [[PTR:%.*]], i1 [[C:%.*]], i64 [[ARG:%.*]]) {
105 ; CHECK-NEXT:  entry:
106 ; CHECK-NEXT:    [[INVARIANT_GEP:%.*]] = getelementptr i64, ptr [[PTR]], i64 [[ARG]]
107 ; CHECK-NEXT:    br label [[LOOP:%.*]]
108 ; CHECK:       loop:
109 ; CHECK-NEXT:    [[VAL:%.*]] = call i64 @get.i64()
110 ; CHECK-NEXT:    [[GEP:%.*]] = getelementptr i32, ptr [[INVARIANT_GEP]], i64 [[VAL]]
111 ; CHECK-NEXT:    call void @use(ptr [[GEP]])
112 ; CHECK-NEXT:    br i1 [[C]], label [[LOOP]], label [[EXIT:%.*]]
113 ; CHECK:       exit:
114 ; CHECK-NEXT:    ret void
116 entry:
117   br label %loop
119 loop:
120   %val = call i64 @get.i64()
121   %ptr2 = getelementptr i32, ptr %ptr, i64 %val
122   %ptr3 = getelementptr i64, ptr %ptr2, i64 %arg
123   call void @use(ptr %ptr3)
124   br i1 %c, label %loop, label %exit
126 exit:
127   ret void
130 define void @different_index_types(ptr %ptr, i1 %c, i32 %arg) {
131 ; CHECK-LABEL: define void @different_index_types
132 ; CHECK-SAME: (ptr [[PTR:%.*]], i1 [[C:%.*]], i32 [[ARG:%.*]]) {
133 ; CHECK-NEXT:  entry:
134 ; CHECK-NEXT:    [[INVARIANT_GEP:%.*]] = getelementptr i8, ptr [[PTR]], i32 [[ARG]]
135 ; CHECK-NEXT:    br label [[LOOP:%.*]]
136 ; CHECK:       loop:
137 ; CHECK-NEXT:    [[VAL:%.*]] = call i64 @get.i64()
138 ; CHECK-NEXT:    [[GEP:%.*]] = getelementptr i8, ptr [[INVARIANT_GEP]], i64 [[VAL]]
139 ; CHECK-NEXT:    call void @use(ptr [[GEP]])
140 ; CHECK-NEXT:    br i1 [[C]], label [[LOOP]], label [[EXIT:%.*]]
141 ; CHECK:       exit:
142 ; CHECK-NEXT:    ret void
144 entry:
145   br label %loop
147 loop:
148   %val = call i64 @get.i64()
149   %ptr2 = getelementptr i8, ptr %ptr, i64 %val
150   %ptr3 = getelementptr i8, ptr %ptr2, i32 %arg
151   call void @use(ptr %ptr3)
152   br i1 %c, label %loop, label %exit
154 exit:
155   ret void
158 define void @different_index_count(ptr %ptr, i1 %c, i64 %arg1, i64 %arg2) {
159 ; CHECK-LABEL: define void @different_index_count
160 ; CHECK-SAME: (ptr [[PTR:%.*]], i1 [[C:%.*]], i64 [[ARG1:%.*]], i64 [[ARG2:%.*]]) {
161 ; CHECK-NEXT:  entry:
162 ; CHECK-NEXT:    [[INVARIANT_GEP:%.*]] = getelementptr [0 x i8], ptr [[PTR]], i64 [[ARG1]], i64 [[ARG2]]
163 ; CHECK-NEXT:    br label [[LOOP:%.*]]
164 ; CHECK:       loop:
165 ; CHECK-NEXT:    [[VAL:%.*]] = call i64 @get.i64()
166 ; CHECK-NEXT:    [[GEP:%.*]] = getelementptr i8, ptr [[INVARIANT_GEP]], i64 [[VAL]]
167 ; CHECK-NEXT:    call void @use(ptr [[GEP]])
168 ; CHECK-NEXT:    br i1 [[C]], label [[LOOP]], label [[EXIT:%.*]]
169 ; CHECK:       exit:
170 ; CHECK-NEXT:    ret void
172 entry:
173   br label %loop
175 loop:
176   %val = call i64 @get.i64()
177   %ptr2 = getelementptr i8, ptr %ptr, i64 %val
178   %ptr3 = getelementptr [0 x i8], ptr %ptr2, i64 %arg1, i64 %arg2
179   call void @use(ptr %ptr3)
180   br i1 %c, label %loop, label %exit
182 exit:
183   ret void
186 define void @src_has_extra_use(ptr %ptr, i1 %c, i64 %arg) {
187 ; CHECK-LABEL: define void @src_has_extra_use
188 ; CHECK-SAME: (ptr [[PTR:%.*]], i1 [[C:%.*]], i64 [[ARG:%.*]]) {
189 ; CHECK-NEXT:  entry:
190 ; CHECK-NEXT:    br label [[LOOP:%.*]]
191 ; CHECK:       loop:
192 ; CHECK-NEXT:    [[VAL:%.*]] = call i64 @get.i64()
193 ; CHECK-NEXT:    [[PTR2:%.*]] = getelementptr i8, ptr [[PTR]], i64 [[VAL]]
194 ; CHECK-NEXT:    call void @use(ptr [[PTR2]])
195 ; CHECK-NEXT:    [[PTR3:%.*]] = getelementptr i8, ptr [[PTR2]], i64 [[ARG]]
196 ; CHECK-NEXT:    call void @use(ptr [[PTR3]])
197 ; CHECK-NEXT:    br i1 [[C]], label [[LOOP]], label [[EXIT:%.*]]
198 ; CHECK:       exit:
199 ; CHECK-NEXT:    ret void
201 entry:
202   br label %loop
204 loop:
205   %val = call i64 @get.i64()
206   %ptr2 = getelementptr i8, ptr %ptr, i64 %val
207   call void @use(ptr %ptr2)
208   %ptr3 = getelementptr i8, ptr %ptr2, i64 %arg
209   call void @use(ptr %ptr3)
210   br i1 %c, label %loop, label %exit
212 exit:
213   ret void
216 define void @src_already_invariant(ptr %ptr, i1 %c, i64 %arg1, i64 %arg2) {
217 ; CHECK-LABEL: define void @src_already_invariant
218 ; CHECK-SAME: (ptr [[PTR:%.*]], i1 [[C:%.*]], i64 [[ARG1:%.*]], i64 [[ARG2:%.*]]) {
219 ; CHECK-NEXT:  entry:
220 ; CHECK-NEXT:    [[PTR2:%.*]] = getelementptr i8, ptr [[PTR]], i64 [[ARG1]]
221 ; CHECK-NEXT:    [[PTR3:%.*]] = getelementptr i8, ptr [[PTR2]], i64 [[ARG2]]
222 ; CHECK-NEXT:    br label [[LOOP:%.*]]
223 ; CHECK:       loop:
224 ; CHECK-NEXT:    call void @use(ptr [[PTR3]])
225 ; CHECK-NEXT:    br i1 [[C]], label [[LOOP]], label [[EXIT:%.*]]
226 ; CHECK:       exit:
227 ; CHECK-NEXT:    ret void
229 entry:
230   br label %loop
232 loop:
233   %ptr2 = getelementptr i8, ptr %ptr, i64 %arg1
234   %ptr3 = getelementptr i8, ptr %ptr2, i64 %arg2
235   call void @use(ptr %ptr3)
236   br i1 %c, label %loop, label %exit
238 exit:
239   ret void
242 define void @gep_idx_not_invariant(ptr %ptr, i1 %c) {
243 ; CHECK-LABEL: define void @gep_idx_not_invariant
244 ; CHECK-SAME: (ptr [[PTR:%.*]], i1 [[C:%.*]]) {
245 ; CHECK-NEXT:  entry:
246 ; CHECK-NEXT:    br label [[LOOP:%.*]]
247 ; CHECK:       loop:
248 ; CHECK-NEXT:    [[VAL1:%.*]] = call i64 @get.i64()
249 ; CHECK-NEXT:    [[VAL2:%.*]] = call i64 @get.i64()
250 ; CHECK-NEXT:    [[PTR2:%.*]] = getelementptr i8, ptr [[PTR]], i64 [[VAL1]]
251 ; CHECK-NEXT:    [[PTR3:%.*]] = getelementptr i8, ptr [[PTR2]], i64 [[VAL2]]
252 ; CHECK-NEXT:    call void @use(ptr [[PTR3]])
253 ; CHECK-NEXT:    br i1 [[C]], label [[LOOP]], label [[EXIT:%.*]]
254 ; CHECK:       exit:
255 ; CHECK-NEXT:    ret void
257 entry:
258   br label %loop
260 loop:
261   %val1 = call i64 @get.i64()
262   %val2 = call i64 @get.i64()
263   %ptr2 = getelementptr i8, ptr %ptr, i64 %val1
264   %ptr3 = getelementptr i8, ptr %ptr2, i64 %val2
265   call void @use(ptr %ptr3)
266   br i1 %c, label %loop, label %exit
268 exit:
269   ret void
272 define void @src_ptr_not_invariant(i1 %c, i64 %arg) {
273 ; CHECK-LABEL: define void @src_ptr_not_invariant
274 ; CHECK-SAME: (i1 [[C:%.*]], i64 [[ARG:%.*]]) {
275 ; CHECK-NEXT:  entry:
276 ; CHECK-NEXT:    br label [[LOOP:%.*]]
277 ; CHECK:       loop:
278 ; CHECK-NEXT:    [[VAL:%.*]] = call i64 @get.i64()
279 ; CHECK-NEXT:    [[PTR:%.*]] = call ptr @get.ptr()
280 ; CHECK-NEXT:    [[PTR2:%.*]] = getelementptr i8, ptr [[PTR]], i64 [[ARG]]
281 ; CHECK-NEXT:    [[PTR3:%.*]] = getelementptr i8, ptr [[PTR2]], i64 [[VAL]]
282 ; CHECK-NEXT:    call void @use(ptr [[PTR3]])
283 ; CHECK-NEXT:    br i1 [[C]], label [[LOOP]], label [[EXIT:%.*]]
284 ; CHECK:       exit:
285 ; CHECK-NEXT:    ret void
287 entry:
288   br label %loop
290 loop:
291   %val = call i64 @get.i64()
292   %ptr = call ptr @get.ptr()
293   %ptr2 = getelementptr i8, ptr %ptr, i64 %arg
294   %ptr3 = getelementptr i8, ptr %ptr2, i64 %val
295   call void @use(ptr %ptr3)
296   br i1 %c, label %loop, label %exit
298 exit:
299   ret void
302 define void @multiple_indices(ptr %ptr, i1 %c, i64 %arg1, i64 %arg2) {
303 ; CHECK-LABEL: define void @multiple_indices
304 ; CHECK-SAME: (ptr [[PTR:%.*]], i1 [[C:%.*]], i64 [[ARG1:%.*]], i64 [[ARG2:%.*]]) {
305 ; CHECK-NEXT:  entry:
306 ; CHECK-NEXT:    [[INVARIANT_GEP:%.*]] = getelementptr [0 x i8], ptr [[PTR]], i64 [[ARG1]], i64 [[ARG2]]
307 ; CHECK-NEXT:    br label [[LOOP:%.*]]
308 ; CHECK:       loop:
309 ; CHECK-NEXT:    [[VAL1:%.*]] = call i64 @get.i64()
310 ; CHECK-NEXT:    [[VAL2:%.*]] = call i64 @get.i64()
311 ; CHECK-NEXT:    [[GEP:%.*]] = getelementptr [0 x i8], ptr [[INVARIANT_GEP]], i64 [[VAL1]], i64 [[VAL2]]
312 ; CHECK-NEXT:    call void @use(ptr [[GEP]])
313 ; CHECK-NEXT:    br i1 [[C]], label [[LOOP]], label [[EXIT:%.*]]
314 ; CHECK:       exit:
315 ; CHECK-NEXT:    ret void
317 entry:
318   br label %loop
320 loop:
321   %val1 = call i64 @get.i64()
322   %val2 = call i64 @get.i64()
323   %ptr2 = getelementptr [0 x i8], ptr %ptr, i64 %val1, i64 %val2
324   %ptr3 = getelementptr [0 x i8], ptr %ptr2, i64 %arg1, i64 %arg2
325   call void @use(ptr %ptr3)
326   br i1 %c, label %loop, label %exit
328 exit:
329   ret void
332 define void @multiple_indices_not_invariant(ptr %ptr, i1 %c, i64 %arg1) {
333 ; CHECK-LABEL: define void @multiple_indices_not_invariant
334 ; CHECK-SAME: (ptr [[PTR:%.*]], i1 [[C:%.*]], i64 [[ARG1:%.*]]) {
335 ; CHECK-NEXT:  entry:
336 ; CHECK-NEXT:    br label [[LOOP:%.*]]
337 ; CHECK:       loop:
338 ; CHECK-NEXT:    [[VAL1:%.*]] = call i64 @get.i64()
339 ; CHECK-NEXT:    [[VAL2:%.*]] = call i64 @get.i64()
340 ; CHECK-NEXT:    [[VAL3:%.*]] = call i64 @get.i64()
341 ; CHECK-NEXT:    [[PTR2:%.*]] = getelementptr [0 x i8], ptr [[PTR]], i64 [[VAL1]], i64 [[VAL2]]
342 ; CHECK-NEXT:    [[PTR3:%.*]] = getelementptr [0 x i8], ptr [[PTR2]], i64 [[ARG1]], i64 [[VAL3]]
343 ; CHECK-NEXT:    call void @use(ptr [[PTR3]])
344 ; CHECK-NEXT:    br i1 [[C]], label [[LOOP]], label [[EXIT:%.*]]
345 ; CHECK:       exit:
346 ; CHECK-NEXT:    ret void
348 entry:
349   br label %loop
351 loop:
352   %val1 = call i64 @get.i64()
353   %val2 = call i64 @get.i64()
354   %val3 = call i64 @get.i64()
355   %ptr2 = getelementptr [0 x i8], ptr %ptr, i64 %val1, i64 %val2
356   %ptr3 = getelementptr [0 x i8], ptr %ptr2, i64 %arg1, i64 %val3
357   call void @use(ptr %ptr3)
358   br i1 %c, label %loop, label %exit
360 exit:
361   ret void
364 define void @multiple_indices_very_invariant(ptr %ptr, i1 %c, i64 %arg1, i64 %arg2, i64 %arg3) {
365 ; CHECK-LABEL: define void @multiple_indices_very_invariant
366 ; CHECK-SAME: (ptr [[PTR:%.*]], i1 [[C:%.*]], i64 [[ARG1:%.*]], i64 [[ARG2:%.*]], i64 [[ARG3:%.*]]) {
367 ; CHECK-NEXT:  entry:
368 ; CHECK-NEXT:    [[INVARIANT_GEP:%.*]] = getelementptr [0 x i8], ptr [[PTR]], i64 [[ARG1]], i64 [[ARG2]]
369 ; CHECK-NEXT:    br label [[LOOP:%.*]]
370 ; CHECK:       loop:
371 ; CHECK-NEXT:    [[VAL1:%.*]] = call i64 @get.i64()
372 ; CHECK-NEXT:    [[GEP:%.*]] = getelementptr [0 x i8], ptr [[INVARIANT_GEP]], i64 [[ARG3]], i64 [[VAL1]]
373 ; CHECK-NEXT:    call void @use(ptr [[GEP]])
374 ; CHECK-NEXT:    br i1 [[C]], label [[LOOP]], label [[EXIT:%.*]]
375 ; CHECK:       exit:
376 ; CHECK-NEXT:    ret void
378 entry:
379   br label %loop
381 loop:
382   %val1 = call i64 @get.i64()
383   %ptr2 = getelementptr [0 x i8], ptr %ptr, i64 %arg3, i64 %val1
384   %ptr3 = getelementptr [0 x i8], ptr %ptr2, i64 %arg1, i64 %arg2
385   call void @use(ptr %ptr3)
386   br i1 %c, label %loop, label %exit
388 exit:
389   ret void
392 define void @src_already_invariant_speculation(ptr %ptr, i1 %c, i1 %c2, i64 %arg1, i64 %arg2) {
393 ; SPEC-LABEL: define void @src_already_invariant_speculation
394 ; SPEC-SAME: (ptr [[PTR:%.*]], i1 [[C:%.*]], i1 [[C2:%.*]], i64 [[ARG1:%.*]], i64 [[ARG2:%.*]]) {
395 ; SPEC-NEXT:  entry:
396 ; SPEC-NEXT:    [[PTR2:%.*]] = getelementptr i8, ptr [[PTR]], i64 [[ARG1]]
397 ; SPEC-NEXT:    [[PTR3:%.*]] = getelementptr i8, ptr [[PTR2]], i64 [[ARG2]]
398 ; SPEC-NEXT:    br label [[LOOP:%.*]]
399 ; SPEC:       loop:
400 ; SPEC-NEXT:    br i1 [[C2]], label [[IF:%.*]], label [[LATCH:%.*]]
401 ; SPEC:       if:
402 ; SPEC-NEXT:    call void @use(ptr [[PTR3]])
403 ; SPEC-NEXT:    br label [[LATCH]]
404 ; SPEC:       latch:
405 ; SPEC-NEXT:    br i1 [[C]], label [[LOOP]], label [[EXIT:%.*]]
406 ; SPEC:       exit:
407 ; SPEC-NEXT:    ret void
409 ; NOSPEC-LABEL: define void @src_already_invariant_speculation
410 ; NOSPEC-SAME: (ptr [[PTR:%.*]], i1 [[C:%.*]], i1 [[C2:%.*]], i64 [[ARG1:%.*]], i64 [[ARG2:%.*]]) {
411 ; NOSPEC-NEXT:  entry:
412 ; NOSPEC-NEXT:    br label [[LOOP:%.*]]
413 ; NOSPEC:       loop:
414 ; NOSPEC-NEXT:    br i1 [[C2]], label [[IF:%.*]], label [[LATCH:%.*]]
415 ; NOSPEC:       if:
416 ; NOSPEC-NEXT:    [[PTR2:%.*]] = getelementptr i8, ptr [[PTR]], i64 [[ARG1]]
417 ; NOSPEC-NEXT:    [[PTR3:%.*]] = getelementptr i8, ptr [[PTR2]], i64 [[ARG2]]
418 ; NOSPEC-NEXT:    call void @use(ptr [[PTR3]])
419 ; NOSPEC-NEXT:    br label [[LATCH]]
420 ; NOSPEC:       latch:
421 ; NOSPEC-NEXT:    br i1 [[C]], label [[LOOP]], label [[EXIT:%.*]]
422 ; NOSPEC:       exit:
423 ; NOSPEC-NEXT:    ret void
425 entry:
426   br label %loop
428 loop:
429   br i1 %c2, label %if, label %latch
432   %ptr2 = getelementptr i8, ptr %ptr, i64 %arg1
433   %ptr3 = getelementptr i8, ptr %ptr2, i64 %arg2
434   call void @use(ptr %ptr3)
435   br label %latch
437 latch:
438   br i1 %c, label %loop, label %exit
440 exit:
441   ret void