xref: /llvm-project/llvm/test/Transforms/Inline/dynamic-alloca-simplified-large.ll (revision 25bc999d1fb2efccc3ece398550af738aea7d310)
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature
2; RUN: opt -passes=inline < %s -S -o - | FileCheck %s
3target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
4target triple = "x86_64-apple-macosx10.15.0"
5
6define void @caller1(ptr %p1, i1 %b) {
7; CHECK-LABEL: define {{[^@]+}}@caller1
8; CHECK-SAME: (ptr [[P1:%.*]], i1 [[B:%.*]]) {
9; CHECK-NEXT:  entry:
10; CHECK-NEXT:    [[COND:%.*]] = icmp eq i1 [[B]], true
11; CHECK-NEXT:    br i1 [[COND]], label [[EXIT:%.*]], label [[SPLIT:%.*]]
12; CHECK:       split:
13; CHECK-NEXT:    call void @callee(ptr [[P1]], i32 0, i32 -1)
14; CHECK-NEXT:    br label [[EXIT]]
15; CHECK:       exit:
16; CHECK-NEXT:    ret void
17;
18entry:
19  %cond = icmp eq i1 %b, true
20  br i1 %cond, label %exit, label %split
21
22split:
23  ; This path may be generated from CS splitting and never taken at runtime.
24  call void @callee(ptr %p1, i32 0, i32 -1)
25  br label %exit
26
27exit:
28  ret void
29}
30
31define  void @callee(ptr %p1, i32 %l1, i32 %l2) {
32; CHECK-LABEL: define {{[^@]+}}@callee
33; CHECK-SAME: (ptr [[P1:%.*]], i32 [[L1:%.*]], i32 [[L2:%.*]]) {
34; CHECK-NEXT:  entry:
35; CHECK-NEXT:    [[EXT:%.*]] = zext i32 [[L2]] to i64
36; CHECK-NEXT:    [[VLA:%.*]] = alloca float, i64 [[EXT]], align 16
37; CHECK-NEXT:    call void @extern_call(ptr nonnull [[VLA]]) #[[ATTR3:[0-9]+]]
38; CHECK-NEXT:    ret void
39;
40entry:
41  %ext = zext i32 %l2 to i64
42  %vla = alloca float, i64 %ext, align 16
43  call void @extern_call(ptr nonnull %vla) #3
44  ret void
45}
46
47
48define void @caller2_below_threshold(ptr %p1, i1 %b) {
49; CHECK-LABEL: define {{[^@]+}}@caller2_below_threshold
50; CHECK-SAME: (ptr [[P1:%.*]], i1 [[B:%.*]]) {
51; CHECK-NEXT:  entry:
52; CHECK-NEXT:    [[VLA_I:%.*]] = alloca float, i64 15000, align 16
53; CHECK-NEXT:    [[COND:%.*]] = icmp eq i1 [[B]], true
54; CHECK-NEXT:    br i1 [[COND]], label [[EXIT:%.*]], label [[SPLIT:%.*]]
55; CHECK:       split:
56; CHECK-NEXT:    [[SAVEDSTACK:%.*]] = call ptr @llvm.stacksave.p0()
57; CHECK-NEXT:    call void @llvm.lifetime.start.p0(i64 60000, ptr [[VLA_I]])
58; CHECK-NEXT:    call void @extern_call(ptr nonnull [[VLA_I]]) #[[ATTR3]]
59; CHECK-NEXT:    call void @llvm.lifetime.end.p0(i64 60000, ptr [[VLA_I]])
60; CHECK-NEXT:    call void @llvm.stackrestore.p0(ptr [[SAVEDSTACK]])
61; CHECK-NEXT:    br label [[EXIT]]
62; CHECK:       exit:
63; CHECK-NEXT:    ret void
64;
65entry:
66  %cond = icmp eq i1 %b, true
67  br i1 %cond, label %exit, label %split
68
69split:
70  call void @callee(ptr %p1, i32 0, i32 15000)
71  br label %exit
72
73exit:
74  ret void
75}
76
77define  void @callee2_not_in_entry(ptr %p1, i32 %l1, i32 %l2) {
78; CHECK-LABEL: define {{[^@]+}}@callee2_not_in_entry
79; CHECK-SAME: (ptr [[P1:%.*]], i32 [[L1:%.*]], i32 [[L2:%.*]]) {
80; CHECK-NEXT:  entry:
81; CHECK-NEXT:    [[EXT:%.*]] = zext i32 [[L2]] to i64
82; CHECK-NEXT:    [[C:%.*]] = icmp eq i32 [[L1]], 42
83; CHECK-NEXT:    br i1 [[C]], label [[BB2:%.*]], label [[BB3:%.*]]
84; CHECK:       bb2:
85; CHECK-NEXT:    [[VLA:%.*]] = alloca float, i64 [[EXT]], align 16
86; CHECK-NEXT:    call void @extern_call(ptr nonnull [[VLA]]) #[[ATTR3]]
87; CHECK-NEXT:    ret void
88; CHECK:       bb3:
89; CHECK-NEXT:    ret void
90;
91entry:
92  %ext = zext i32 %l2 to i64
93  %c = icmp eq i32 %l1, 42
94  br i1 %c, label %bb2, label %bb3
95bb2:
96  %vla = alloca float, i64 %ext, align 16
97  call void @extern_call(ptr nonnull %vla) #3
98  ret void
99bb3:
100  ret void
101}
102
103define void @caller3_alloca_not_in_entry(ptr %p1, i1 %b) {
104; CHECK-LABEL: define {{[^@]+}}@caller3_alloca_not_in_entry
105; CHECK-SAME: (ptr [[P1:%.*]], i1 [[B:%.*]]) {
106; CHECK-NEXT:  entry:
107; CHECK-NEXT:    [[COND:%.*]] = icmp eq i1 [[B]], true
108; CHECK-NEXT:    br i1 [[COND]], label [[EXIT:%.*]], label [[SPLIT:%.*]]
109; CHECK:       split:
110; CHECK-NEXT:    br label [[EXIT]]
111; CHECK:       exit:
112; CHECK-NEXT:    ret void
113;
114entry:
115  %cond = icmp eq i1 %b, true
116  br i1 %cond, label %exit, label %split
117
118split:
119  call void @callee2_not_in_entry(ptr %p1, i32 0, i32 -1)
120  br label %exit
121
122exit:
123  ret void
124}
125
126define void @caller4_over_threshold(ptr %p1, i1 %b, i32 %len) {
127; CHECK-LABEL: define {{[^@]+}}@caller4_over_threshold
128; CHECK-SAME: (ptr [[P1:%.*]], i1 [[B:%.*]], i32 [[LEN:%.*]]) {
129; CHECK-NEXT:  entry:
130; CHECK-NEXT:    [[COND:%.*]] = icmp eq i1 [[B]], true
131; CHECK-NEXT:    br i1 [[COND]], label [[EXIT:%.*]], label [[SPLIT:%.*]]
132; CHECK:       split:
133; CHECK-NEXT:    call void @callee(ptr [[P1]], i32 0, i32 16500)
134; CHECK-NEXT:    br label [[EXIT]]
135; CHECK:       exit:
136; CHECK-NEXT:    ret void
137;
138entry:
139  %cond = icmp eq i1 %b, true
140  br i1 %cond, label %exit, label %split
141
142split:
143  call void @callee(ptr %p1, i32 0, i32 16500)
144  br label %exit
145
146exit:
147  ret void
148}
149
150declare noalias ptr @malloc(i64)
151define ptr @stack_allocate(i32 %size) #2 {
152; CHECK-LABEL: define {{[^@]+}}@stack_allocate
153; CHECK-SAME: (i32 [[SIZE:%.*]]) #[[ATTR0:[0-9]+]] {
154; CHECK-NEXT:  entry:
155; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i32 [[SIZE]], 100
156; CHECK-NEXT:    [[CONV:%.*]] = zext i32 [[SIZE]] to i64
157; CHECK-NEXT:    br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
158; CHECK:       if.then:
159; CHECK-NEXT:    [[TMP0:%.*]] = alloca i8, i64 [[CONV]], align 8
160; CHECK-NEXT:    br label [[RETURN:%.*]]
161; CHECK:       if.end:
162; CHECK-NEXT:    [[CALL:%.*]] = tail call ptr @malloc(i64 [[CONV]]) #[[ATTR3]]
163; CHECK-NEXT:    br label [[RETURN]]
164; CHECK:       return:
165; CHECK-NEXT:    [[RETVAL_0:%.*]] = phi ptr [ [[TMP0]], [[IF_THEN]] ], [ [[CALL]], [[IF_END]] ]
166; CHECK-NEXT:    ret ptr [[RETVAL_0]]
167;
168entry:
169  %cmp = icmp ult i32 %size, 100
170  %conv = zext i32 %size to i64
171  br i1 %cmp, label %if.then, label %if.end
172
173if.then:                                          ; preds = %entry
174  %0 = alloca i8, i64 %conv, align 8
175  br label %return
176
177if.end:                                           ; preds = %entry
178  %call = tail call ptr @malloc(i64 %conv) #3
179  br label %return
180
181return:                                           ; preds = %if.end, %if.then
182  %retval.0 = phi ptr [ %0, %if.then ], [ %call, %if.end ]
183  ret ptr %retval.0
184}
185
186define ptr @test_stack_allocate_always(i32 %size) {
187; CHECK-LABEL: define {{[^@]+}}@test_stack_allocate_always
188; CHECK-SAME: (i32 [[SIZE:%.*]]) {
189; CHECK-NEXT:  entry:
190; CHECK-NEXT:    [[SAVEDSTACK:%.*]] = call ptr @llvm.stacksave.p0()
191; CHECK-NEXT:    [[CMP_I:%.*]] = icmp ult i32 [[SIZE]], 100
192; CHECK-NEXT:    [[CONV_I:%.*]] = zext i32 [[SIZE]] to i64
193; CHECK-NEXT:    br i1 [[CMP_I]], label [[IF_THEN_I:%.*]], label [[IF_END_I:%.*]]
194; CHECK:       if.then.i:
195; CHECK-NEXT:    [[TMP0:%.*]] = alloca i8, i64 [[CONV_I]], align 8
196; CHECK-NEXT:    br label [[STACK_ALLOCATE_EXIT:%.*]]
197; CHECK:       if.end.i:
198; CHECK-NEXT:    [[CALL_I:%.*]] = tail call ptr @malloc(i64 [[CONV_I]]) #[[ATTR3]]
199; CHECK-NEXT:    br label [[STACK_ALLOCATE_EXIT]]
200; CHECK:       stack_allocate.exit:
201; CHECK-NEXT:    [[RETVAL_0_I:%.*]] = phi ptr [ [[TMP0]], [[IF_THEN_I]] ], [ [[CALL_I]], [[IF_END_I]] ]
202; CHECK-NEXT:    call void @llvm.stackrestore.p0(ptr [[SAVEDSTACK]])
203; CHECK-NEXT:    ret ptr [[RETVAL_0_I]]
204;
205entry:
206  %call = tail call ptr @stack_allocate(i32 %size)
207  ret ptr %call
208}
209
210declare void @extern_call(ptr)
211
212attributes #1 = { argmemonly nounwind willreturn writeonly }
213attributes #2 = { alwaysinline }
214attributes #3 = { nounwind }
215
216