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