diff options
Diffstat (limited to 'llvm/test/Transforms/FunctionAttrs/liveness.ll')
-rw-r--r-- | llvm/test/Transforms/FunctionAttrs/liveness.ll | 97 |
1 files changed, 59 insertions, 38 deletions
diff --git a/llvm/test/Transforms/FunctionAttrs/liveness.ll b/llvm/test/Transforms/FunctionAttrs/liveness.ll index 1de005d15c5..42ef89cfe8a 100644 --- a/llvm/test/Transforms/FunctionAttrs/liveness.ll +++ b/llvm/test/Transforms/FunctionAttrs/liveness.ll @@ -1,21 +1,67 @@ ; RUN: opt -attributor --attributor-disable=false -S < %s | FileCheck %s -declare void @no_return_call() noreturn +declare void @no_return_call() nofree noreturn nounwind readnone -declare void @normal_call() +declare void @normal_call() readnone declare i32 @foo() declare i32 @foo_noreturn() noreturn -declare i32 @bar() +declare i32 @bar() nosync readnone -; TEST 1: cond.true is dead, but cond.end is not, since cond.false is live +; CHECK: Function Attrs: nofree norecurse nounwind uwtable willreturn +define i32 @volatile_load(i32*) norecurse nounwind uwtable { + %2 = load volatile i32, i32* %0, align 4 + ret i32 %2 +} + +; CHECK: Function Attrs: nofree norecurse nosync nounwind uwtable willreturn +; CHECK-NEXT: define internal i32 @internal_load(i32* nonnull) +define internal i32 @internal_load(i32*) norecurse nounwind uwtable { + %2 = load i32, i32* %0, align 4 + ret i32 %2 +} +; TEST 1: Only first block is live. + +; CHECK: Function Attrs: nofree nosync nounwind +; CHECK-NEXT: define i32 @first_block_no_return(i32 %a, i32* nonnull %ptr1, i32* %ptr2) +define i32 @first_block_no_return(i32 %a, i32* nonnull %ptr1, i32* %ptr2) #0 { +entry: + call i32 @internal_load(i32* %ptr1) + ; CHECK: call i32 @internal_load(i32* nonnull %ptr1) + call void @no_return_call() + ; CHECK: call void @no_return_call() + ; CHECK-NEXT: unreachable + %cmp = icmp eq i32 %a, 0 + br i1 %cmp, label %cond.true, label %cond.false + +cond.true: ; preds = %entry + call i32 @internal_load(i32* %ptr2) + ; CHECK: call i32 @internal_load(i32* %ptr2) + %load = call i32 @volatile_load(i32* %ptr1) + call void @normal_call() + %call = call i32 @foo() + br label %cond.end + +cond.false: ; preds = %entry + call void @normal_call() + %call1 = call i32 @bar() + br label %cond.end + +cond.end: ; preds = %cond.false, %cond.true + %cond = phi i32 [ %call, %cond.true ], [ %call1, %cond.false ] + ret i32 %cond +} + +; TEST 2: cond.true is dead, but cond.end is not, since cond.false is live ; This is just an example. For example we can put a sync call in a ; dead block and check if it is deduced. -define i32 @dead_block_present(i32 %a) #0 { +; CHECK: Function Attrs: nosync +; CHECK-NEXT: define i32 @dead_block_present(i32 %a, i32* %ptr1) +define i32 @dead_block_present(i32 %a, i32* %ptr1) #0 { entry: %cmp = icmp eq i32 %a, 0 br i1 %cmp, label %cond.true, label %cond.false @@ -24,7 +70,7 @@ cond.true: ; preds = %entry call void @no_return_call() ; CHECK: call void @no_return_call() ; CHECK-NEXT: unreachable - %call = call i32 @foo() + %call = call i32 @volatile_load(i32* %ptr1) br label %cond.end cond.false: ; preds = %entry @@ -37,7 +83,7 @@ cond.end: ; preds = %cond.false, %cond.t ret i32 %cond } -; TEST 2: both cond.true and cond.false are dead, therfore cond.end is dead as well. +; TEST 3: both cond.true and cond.false are dead, therfore cond.end is dead as well. define i32 @all_dead(i32 %a) #0 { entry: @@ -65,7 +111,7 @@ cond.end: ; preds = %cond.false, %cond.t declare i32 @__gxx_personality_v0(...) -; TEST 3: All blocks are live. +; TEST 4: All blocks are live. ; CHECK: define i32 @all_live(i32 %a) define i32 @all_live(i32 %a) #0 { @@ -88,7 +134,7 @@ cond.end: ; preds = %cond.false, %cond.t ret i32 %cond } -; TEST 4 noreturn invoke instruction replaced by a call and an unreachable instruction +; TEST 5 noreturn invoke instruction replaced by a call and an unreachable instruction ; put after it. ; CHECK: define i32 @invoke_noreturn(i32 %a) @@ -122,7 +168,7 @@ cleanup: ret i32 0 } -; TEST 5: Undefined behvior, taken from LangRef. +; TEST 6: Undefined behvior, taken from LangRef. ; FIXME: Should be able to detect undefined behavior. ; CHECK define @ub(i32) @@ -142,7 +188,7 @@ while.body: ; preds = %entry, %while.body br label %while.body } -; TEST 6: Infinite loop. +; TEST 7: Infinite loop. ; FIXME: Detect infloops, and mark affected blocks dead. define i32 @test5(i32, i32) #0 { @@ -173,7 +219,7 @@ entry: ret void } -; TEST 7: Recursion +; TEST 8: Recursion ; FIXME: everything after first block should be marked dead ; and unreachable should be put after call to @rec(). @@ -199,7 +245,7 @@ cond.end: ; preds = %cond.if, %con %7 = phi i32 [ %1, %cond.elseif ], [ 0, %cond.else ], [ 0, %cond.if ] ret i32 %7 } -; TEST 8: Recursion +; TEST 9: Recursion ; FIXME: contains recursive call to itself in cond.elseif block define i32 @test7(i32, i32) #0 { @@ -223,28 +269,3 @@ cond.end: ; preds = %cond.if, %con %8 = phi i32 [ %1, %cond.elseif ], [ 0, %cond.else ], [ 0, %cond.if ] ret i32 %8 } - -; TEST 9: Only first block is live. - -define i32 @first_block_no_return(i32 %a) #0 { -entry: - call void @no_return_call() - ; CHECK: call void @no_return_call() - ; CHECK-NEXT: unreachable - %cmp = icmp eq i32 %a, 0 - br i1 %cmp, label %cond.true, label %cond.false - -cond.true: ; preds = %entry - call void @normal_call() - %call = call i32 @foo() - br label %cond.end - -cond.false: ; preds = %entry - call void @normal_call() - %call1 = call i32 @bar() - br label %cond.end - -cond.end: ; preds = %cond.false, %cond.true - %cond = phi i32 [ %call, %cond.true ], [ %call1, %cond.false ] - ret i32 %cond -} |