| ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature |
| ; RUN: opt -passes=inline < %s -S -o - | FileCheck %s |
| target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" |
| target triple = "x86_64-apple-macosx10.15.0" |
| |
| define void @caller1(ptr %p1, i1 %b) { |
| ; CHECK-LABEL: define {{[^@]+}}@caller1 |
| ; CHECK-SAME: (ptr [[P1:%.*]], i1 [[B:%.*]]) { |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[COND:%.*]] = icmp eq i1 [[B]], true |
| ; CHECK-NEXT: br i1 [[COND]], label [[EXIT:%.*]], label [[SPLIT:%.*]] |
| ; CHECK: split: |
| ; CHECK-NEXT: call void @callee(ptr [[P1]], i32 0, i32 -1) |
| ; CHECK-NEXT: br label [[EXIT]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| %cond = icmp eq i1 %b, true |
| br i1 %cond, label %exit, label %split |
| |
| split: |
| ; This path may be generated from CS splitting and never taken at runtime. |
| call void @callee(ptr %p1, i32 0, i32 -1) |
| br label %exit |
| |
| exit: |
| ret void |
| } |
| |
| define void @callee(ptr %p1, i32 %l1, i32 %l2) { |
| ; CHECK-LABEL: define {{[^@]+}}@callee |
| ; CHECK-SAME: (ptr [[P1:%.*]], i32 [[L1:%.*]], i32 [[L2:%.*]]) { |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[EXT:%.*]] = zext i32 [[L2]] to i64 |
| ; CHECK-NEXT: [[VLA:%.*]] = alloca float, i64 [[EXT]], align 16 |
| ; CHECK-NEXT: call void @extern_call(ptr nonnull [[VLA]]) #[[ATTR3:[0-9]+]] |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| %ext = zext i32 %l2 to i64 |
| %vla = alloca float, i64 %ext, align 16 |
| call void @extern_call(ptr nonnull %vla) #3 |
| ret void |
| } |
| |
| |
| define void @caller2_below_threshold(ptr %p1, i1 %b) { |
| ; CHECK-LABEL: define {{[^@]+}}@caller2_below_threshold |
| ; CHECK-SAME: (ptr [[P1:%.*]], i1 [[B:%.*]]) { |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[VLA_I:%.*]] = alloca float, i64 15000, align 16 |
| ; CHECK-NEXT: [[COND:%.*]] = icmp eq i1 [[B]], true |
| ; CHECK-NEXT: br i1 [[COND]], label [[EXIT:%.*]], label [[SPLIT:%.*]] |
| ; CHECK: split: |
| ; CHECK-NEXT: [[SAVEDSTACK:%.*]] = call ptr @llvm.stacksave.p0() |
| ; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 60000, ptr [[VLA_I]]) |
| ; CHECK-NEXT: call void @extern_call(ptr nonnull [[VLA_I]]) #[[ATTR3]] |
| ; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 60000, ptr [[VLA_I]]) |
| ; CHECK-NEXT: call void @llvm.stackrestore.p0(ptr [[SAVEDSTACK]]) |
| ; CHECK-NEXT: br label [[EXIT]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| %cond = icmp eq i1 %b, true |
| br i1 %cond, label %exit, label %split |
| |
| split: |
| call void @callee(ptr %p1, i32 0, i32 15000) |
| br label %exit |
| |
| exit: |
| ret void |
| } |
| |
| define void @callee2_not_in_entry(ptr %p1, i32 %l1, i32 %l2) { |
| ; CHECK-LABEL: define {{[^@]+}}@callee2_not_in_entry |
| ; CHECK-SAME: (ptr [[P1:%.*]], i32 [[L1:%.*]], i32 [[L2:%.*]]) { |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[EXT:%.*]] = zext i32 [[L2]] to i64 |
| ; CHECK-NEXT: [[C:%.*]] = icmp eq i32 [[L1]], 42 |
| ; CHECK-NEXT: br i1 [[C]], label [[BB2:%.*]], label [[BB3:%.*]] |
| ; CHECK: bb2: |
| ; CHECK-NEXT: [[VLA:%.*]] = alloca float, i64 [[EXT]], align 16 |
| ; CHECK-NEXT: call void @extern_call(ptr nonnull [[VLA]]) #[[ATTR3]] |
| ; CHECK-NEXT: ret void |
| ; CHECK: bb3: |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| %ext = zext i32 %l2 to i64 |
| %c = icmp eq i32 %l1, 42 |
| br i1 %c, label %bb2, label %bb3 |
| bb2: |
| %vla = alloca float, i64 %ext, align 16 |
| call void @extern_call(ptr nonnull %vla) #3 |
| ret void |
| bb3: |
| ret void |
| } |
| |
| define void @caller3_alloca_not_in_entry(ptr %p1, i1 %b) { |
| ; CHECK-LABEL: define {{[^@]+}}@caller3_alloca_not_in_entry |
| ; CHECK-SAME: (ptr [[P1:%.*]], i1 [[B:%.*]]) { |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[COND:%.*]] = icmp eq i1 [[B]], true |
| ; CHECK-NEXT: br i1 [[COND]], label [[EXIT:%.*]], label [[SPLIT:%.*]] |
| ; CHECK: split: |
| ; CHECK-NEXT: br label [[EXIT]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| %cond = icmp eq i1 %b, true |
| br i1 %cond, label %exit, label %split |
| |
| split: |
| call void @callee2_not_in_entry(ptr %p1, i32 0, i32 -1) |
| br label %exit |
| |
| exit: |
| ret void |
| } |
| |
| define void @caller4_over_threshold(ptr %p1, i1 %b, i32 %len) { |
| ; CHECK-LABEL: define {{[^@]+}}@caller4_over_threshold |
| ; CHECK-SAME: (ptr [[P1:%.*]], i1 [[B:%.*]], i32 [[LEN:%.*]]) { |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[COND:%.*]] = icmp eq i1 [[B]], true |
| ; CHECK-NEXT: br i1 [[COND]], label [[EXIT:%.*]], label [[SPLIT:%.*]] |
| ; CHECK: split: |
| ; CHECK-NEXT: call void @callee(ptr [[P1]], i32 0, i32 16500) |
| ; CHECK-NEXT: br label [[EXIT]] |
| ; CHECK: exit: |
| ; CHECK-NEXT: ret void |
| ; |
| entry: |
| %cond = icmp eq i1 %b, true |
| br i1 %cond, label %exit, label %split |
| |
| split: |
| call void @callee(ptr %p1, i32 0, i32 16500) |
| br label %exit |
| |
| exit: |
| ret void |
| } |
| |
| declare noalias ptr @malloc(i64) |
| define ptr @stack_allocate(i32 %size) #2 { |
| ; CHECK-LABEL: define {{[^@]+}}@stack_allocate |
| ; CHECK-SAME: (i32 [[SIZE:%.*]]) #[[ATTR0:[0-9]+]] { |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[SIZE]], 100 |
| ; CHECK-NEXT: [[CONV:%.*]] = zext i32 [[SIZE]] to i64 |
| ; CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] |
| ; CHECK: if.then: |
| ; CHECK-NEXT: [[TMP0:%.*]] = alloca i8, i64 [[CONV]], align 8 |
| ; CHECK-NEXT: br label [[RETURN:%.*]] |
| ; CHECK: if.end: |
| ; CHECK-NEXT: [[CALL:%.*]] = tail call ptr @malloc(i64 [[CONV]]) #[[ATTR3]] |
| ; CHECK-NEXT: br label [[RETURN]] |
| ; CHECK: return: |
| ; CHECK-NEXT: [[RETVAL_0:%.*]] = phi ptr [ [[TMP0]], [[IF_THEN]] ], [ [[CALL]], [[IF_END]] ] |
| ; CHECK-NEXT: ret ptr [[RETVAL_0]] |
| ; |
| entry: |
| %cmp = icmp ult i32 %size, 100 |
| %conv = zext i32 %size to i64 |
| br i1 %cmp, label %if.then, label %if.end |
| |
| if.then: ; preds = %entry |
| %0 = alloca i8, i64 %conv, align 8 |
| br label %return |
| |
| if.end: ; preds = %entry |
| %call = tail call ptr @malloc(i64 %conv) #3 |
| br label %return |
| |
| return: ; preds = %if.end, %if.then |
| %retval.0 = phi ptr [ %0, %if.then ], [ %call, %if.end ] |
| ret ptr %retval.0 |
| } |
| |
| define ptr @test_stack_allocate_always(i32 %size) { |
| ; CHECK-LABEL: define {{[^@]+}}@test_stack_allocate_always |
| ; CHECK-SAME: (i32 [[SIZE:%.*]]) { |
| ; CHECK-NEXT: entry: |
| ; CHECK-NEXT: [[SAVEDSTACK:%.*]] = call ptr @llvm.stacksave.p0() |
| ; CHECK-NEXT: [[CMP_I:%.*]] = icmp ult i32 [[SIZE]], 100 |
| ; CHECK-NEXT: [[CONV_I:%.*]] = zext i32 [[SIZE]] to i64 |
| ; CHECK-NEXT: br i1 [[CMP_I]], label [[IF_THEN_I:%.*]], label [[IF_END_I:%.*]] |
| ; CHECK: if.then.i: |
| ; CHECK-NEXT: [[TMP0:%.*]] = alloca i8, i64 [[CONV_I]], align 8 |
| ; CHECK-NEXT: br label [[STACK_ALLOCATE_EXIT:%.*]] |
| ; CHECK: if.end.i: |
| ; CHECK-NEXT: [[CALL_I:%.*]] = tail call ptr @malloc(i64 [[CONV_I]]) #[[ATTR3]] |
| ; CHECK-NEXT: br label [[STACK_ALLOCATE_EXIT]] |
| ; CHECK: stack_allocate.exit: |
| ; CHECK-NEXT: [[RETVAL_0_I:%.*]] = phi ptr [ [[TMP0]], [[IF_THEN_I]] ], [ [[CALL_I]], [[IF_END_I]] ] |
| ; CHECK-NEXT: call void @llvm.stackrestore.p0(ptr [[SAVEDSTACK]]) |
| ; CHECK-NEXT: ret ptr [[RETVAL_0_I]] |
| ; |
| entry: |
| %call = tail call ptr @stack_allocate(i32 %size) |
| ret ptr %call |
| } |
| |
| declare void @extern_call(ptr) |
| |
| attributes #1 = { argmemonly nounwind willreturn writeonly } |
| attributes #2 = { alwaysinline } |
| attributes #3 = { nounwind } |
| |