diff options
Diffstat (limited to 'test/Transforms')
-rw-r--r-- | test/Transforms/ArgumentPromotion/musttail.ll | 45 | ||||
-rw-r--r-- | test/Transforms/CallSiteSplitting/musttail.ll | 109 | ||||
-rw-r--r-- | test/Transforms/DeadArgElim/musttail-caller.ll | 16 | ||||
-rw-r--r-- | test/Transforms/GlobalOpt/musttail_cc.ll | 34 | ||||
-rw-r--r-- | test/Transforms/IPConstantProp/musttail-call.ll | 58 | ||||
-rw-r--r-- | test/Transforms/InstCombine/gep-addrspace.ll | 19 | ||||
-rw-r--r-- | test/Transforms/JumpThreading/header-succ.ll | 99 | ||||
-rw-r--r-- | test/Transforms/MergeFunc/inline-asm.ll | 53 | ||||
-rw-r--r-- | test/Transforms/MergeFunc/weak-small.ll | 16 |
9 files changed, 449 insertions, 0 deletions
diff --git a/test/Transforms/ArgumentPromotion/musttail.ll b/test/Transforms/ArgumentPromotion/musttail.ll new file mode 100644 index 0000000000000..aa18711686938 --- /dev/null +++ b/test/Transforms/ArgumentPromotion/musttail.ll @@ -0,0 +1,45 @@ +; RUN: opt < %s -argpromotion -S | FileCheck %s +; PR36543 + +; Don't promote arguments of musttail callee + +%T = type { i32, i32, i32, i32 } + +; CHECK-LABEL: define internal i32 @test(%T* %p) +define internal i32 @test(%T* %p) { + %a.gep = getelementptr %T, %T* %p, i64 0, i32 3 + %b.gep = getelementptr %T, %T* %p, i64 0, i32 2 + %a = load i32, i32* %a.gep + %b = load i32, i32* %b.gep + %v = add i32 %a, %b + ret i32 %v +} + +; CHECK-LABEL: define i32 @caller(%T* %p) +define i32 @caller(%T* %p) { + %v = musttail call i32 @test(%T* %p) + ret i32 %v +} + +; Don't promote arguments of musttail caller + +define i32 @foo(%T* %p, i32 %v) { + ret i32 0 +} + +; CHECK-LABEL: define internal i32 @test2(%T* %p, i32 %p2) +define internal i32 @test2(%T* %p, i32 %p2) { + %a.gep = getelementptr %T, %T* %p, i64 0, i32 3 + %b.gep = getelementptr %T, %T* %p, i64 0, i32 2 + %a = load i32, i32* %a.gep + %b = load i32, i32* %b.gep + %v = add i32 %a, %b + %ca = musttail call i32 @foo(%T* undef, i32 %v) + ret i32 %ca +} + +; CHECK-LABEL: define i32 @caller2(%T* %g) +define i32 @caller2(%T* %g) { + %v = call i32 @test2(%T* %g, i32 0) + ret i32 %v +} diff --git a/test/Transforms/CallSiteSplitting/musttail.ll b/test/Transforms/CallSiteSplitting/musttail.ll new file mode 100644 index 0000000000000..97548501cd5cd --- /dev/null +++ b/test/Transforms/CallSiteSplitting/musttail.ll @@ -0,0 +1,109 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt < %s -callsite-splitting -S | FileCheck %s + +define i8* @caller(i8* %a, i8* %b) { +; CHECK-LABEL: @caller( +; CHECK-NEXT: Top: +; CHECK-NEXT: [[C:%.*]] = icmp eq i8* [[A:%.*]], null +; CHECK-NEXT: br i1 [[C]], label [[TAIL_PREDBB1_SPLIT:%.*]], label [[TBB:%.*]] +; CHECK: TBB: +; CHECK-NEXT: [[C2:%.*]] = icmp eq i8* [[B:%.*]], null +; CHECK-NEXT: br i1 [[C2]], label [[TAIL_PREDBB2_SPLIT:%.*]], label [[END:%.*]] +; CHECK: Tail.predBB1.split: +; CHECK-NEXT: [[TMP0:%.*]] = musttail call i8* @callee(i8* null, i8* [[B]]) +; CHECK-NEXT: [[CB1:%.*]] = bitcast i8* [[TMP0]] to i8* +; CHECK-NEXT: ret i8* [[CB1]] +; CHECK: Tail.predBB2.split: +; CHECK-NEXT: [[TMP1:%.*]] = musttail call i8* @callee(i8* nonnull [[A]], i8* null) +; CHECK-NEXT: [[CB2:%.*]] = bitcast i8* [[TMP1]] to i8* +; CHECK-NEXT: ret i8* [[CB2]] +; CHECK: End: +; CHECK-NEXT: ret i8* null +; +Top: + %c = icmp eq i8* %a, null + br i1 %c, label %Tail, label %TBB +TBB: + %c2 = icmp eq i8* %b, null + br i1 %c2, label %Tail, label %End +Tail: + %ca = musttail call i8* @callee(i8* %a, i8* %b) + %cb = bitcast i8* %ca to i8* + ret i8* %cb +End: + ret i8* null +} + +define i8* @callee(i8* %a, i8* %b) noinline { +; CHECK-LABEL: define i8* @callee( +; CHECK-NEXT: ret i8* [[A:%.*]] +; + ret i8* %a +} + +define i8* @no_cast_caller(i8* %a, i8* %b) { +; CHECK-LABEL: @no_cast_caller( +; CHECK-NEXT: Top: +; CHECK-NEXT: [[C:%.*]] = icmp eq i8* [[A:%.*]], null +; CHECK-NEXT: br i1 [[C]], label [[TAIL_PREDBB1_SPLIT:%.*]], label [[TBB:%.*]] +; CHECK: TBB: +; CHECK-NEXT: [[C2:%.*]] = icmp eq i8* [[B:%.*]], null +; CHECK-NEXT: br i1 [[C2]], label [[TAIL_PREDBB2_SPLIT:%.*]], label [[END:%.*]] +; CHECK: Tail.predBB1.split: +; CHECK-NEXT: [[TMP0:%.*]] = musttail call i8* @callee(i8* null, i8* [[B]]) +; CHECK-NEXT: ret i8* [[TMP0]] +; CHECK: Tail.predBB2.split: +; CHECK-NEXT: [[TMP1:%.*]] = musttail call i8* @callee(i8* nonnull [[A]], i8* null) +; CHECK-NEXT: ret i8* [[TMP1]] +; CHECK: End: +; CHECK-NEXT: ret i8* null +; +Top: + %c = icmp eq i8* %a, null + br i1 %c, label %Tail, label %TBB +TBB: + %c2 = icmp eq i8* %b, null + br i1 %c2, label %Tail, label %End +Tail: + %ca = musttail call i8* @callee(i8* %a, i8* %b) + ret i8* %ca +End: + ret i8* null +} + +define void @void_caller(i8* %a, i8* %b) { +; CHECK-LABEL: @void_caller( +; CHECK-NEXT: Top: +; CHECK-NEXT: [[C:%.*]] = icmp eq i8* [[A:%.*]], null +; CHECK-NEXT: br i1 [[C]], label [[TAIL_PREDBB1_SPLIT:%.*]], label [[TBB:%.*]] +; CHECK: TBB: +; CHECK-NEXT: [[C2:%.*]] = icmp eq i8* [[B:%.*]], null +; CHECK-NEXT: br i1 [[C2]], label [[TAIL_PREDBB2_SPLIT:%.*]], label [[END:%.*]] +; CHECK: Tail.predBB1.split: +; CHECK-NEXT: musttail call void @void_callee(i8* null, i8* [[B]]) +; CHECK-NEXT: ret void +; CHECK: Tail.predBB2.split: +; CHECK-NEXT: musttail call void @void_callee(i8* nonnull [[A]], i8* null) +; CHECK-NEXT: ret void +; CHECK: End: +; CHECK-NEXT: ret void +; +Top: + %c = icmp eq i8* %a, null + br i1 %c, label %Tail, label %TBB +TBB: + %c2 = icmp eq i8* %b, null + br i1 %c2, label %Tail, label %End +Tail: + musttail call void @void_callee(i8* %a, i8* %b) + ret void +End: + ret void +} + +define void @void_callee(i8* %a, i8* %b) noinline { +; CHECK-LABEL: define void @void_callee( +; CHECK-NEXT: ret void +; + ret void +} diff --git a/test/Transforms/DeadArgElim/musttail-caller.ll b/test/Transforms/DeadArgElim/musttail-caller.ll new file mode 100644 index 0000000000000..981326bba0aa3 --- /dev/null +++ b/test/Transforms/DeadArgElim/musttail-caller.ll @@ -0,0 +1,16 @@ +; RUN: opt -deadargelim -S < %s | FileCheck %s +; PR36441 +; Dead arguments should not be removed in presence of `musttail` calls. + +; CHECK-LABEL: define internal void @test(i32 %a, i32 %b) +; CHECK: musttail call void @foo(i32 %a, i32 0) +; FIXME: we should replace those with `undef`s +define internal void @test(i32 %a, i32 %b) { + musttail call void @foo(i32 %a, i32 0) + ret void +} + +; CHECK-LABEL: define internal void @foo(i32 %a, i32 %b) +define internal void @foo(i32 %a, i32 %b) { + ret void +} diff --git a/test/Transforms/GlobalOpt/musttail_cc.ll b/test/Transforms/GlobalOpt/musttail_cc.ll new file mode 100644 index 0000000000000..fc927ea91dd8f --- /dev/null +++ b/test/Transforms/GlobalOpt/musttail_cc.ll @@ -0,0 +1,34 @@ +; RUN: opt < %s -globalopt -S | FileCheck %s +; PR36546 + +; Check that musttail callee preserves its calling convention + +define i32 @test(i32 %a) { + ; CHECK: %ca = musttail call i32 @foo(i32 %a) + %ca = musttail call i32 @foo(i32 %a) + ret i32 %ca +} + +; CHECK-LABEL: define internal i32 @foo(i32 %a) +define internal i32 @foo(i32 %a) { + ret i32 %a +} + +; Check that musttail caller preserves its calling convention + +define i32 @test2(i32 %a) { + %ca = call i32 @foo1(i32 %a) + ret i32 %ca +} + +; CHECK-LABEL: define internal i32 @foo1(i32 %a) +define internal i32 @foo1(i32 %a) { + ; CHECK: %ca = musttail call i32 @foo2(i32 %a) + %ca = musttail call i32 @foo2(i32 %a) + ret i32 %ca +} + +; CHECK-LABEL: define internal i32 @foo2(i32 %a) +define internal i32 @foo2(i32 %a) { + ret i32 %a +} diff --git a/test/Transforms/IPConstantProp/musttail-call.ll b/test/Transforms/IPConstantProp/musttail-call.ll new file mode 100644 index 0000000000000..f02f6992a70d1 --- /dev/null +++ b/test/Transforms/IPConstantProp/musttail-call.ll @@ -0,0 +1,58 @@ +; RUN: opt < %s -ipsccp -S | FileCheck %s +; PR36485 +; musttail call result can\'t be replaced with a constant, unless the call +; can be removed + +declare i32 @external() + +define i8* @start(i8 %v) { + %c1 = icmp eq i8 %v, 0 + br i1 %c1, label %true, label %false +true: + ; CHECK: %ca = musttail call i8* @side_effects(i8 %v) + ; CHECK: ret i8* %ca + %ca = musttail call i8* @side_effects(i8 %v) + ret i8* %ca +false: + %c2 = icmp eq i8 %v, 1 + br i1 %c2, label %c2_true, label %c2_false +c2_true: + ; CHECK: %ca1 = musttail call i8* @no_side_effects(i8 %v) + ; CHECK: ret i8* %ca1 + %ca1 = musttail call i8* @no_side_effects(i8 %v) + ret i8* %ca1 +c2_false: + ; CHECK: %ca2 = musttail call i8* @dont_zap_me(i8 %v) + ; CHECK: ret i8* %ca2 + %ca2 = musttail call i8* @dont_zap_me(i8 %v) + ret i8* %ca2 +} + +define internal i8* @side_effects(i8 %v) { + %i1 = call i32 @external() + + ; since this goes back to `start` the SCPP should be see that the return value + ; is always `null`. + ; The call can't be removed due to `external` call above, though. + + ; CHECK: %ca = musttail call i8* @start(i8 %v) + %ca = musttail call i8* @start(i8 %v) + + ; Thus the result must be returned anyway + ; CHECK: ret i8* %ca + ret i8* %ca +} + +define internal i8* @no_side_effects(i8 %v) readonly nounwind { + ; CHECK: ret i8* null + ret i8* null +} + +define internal i8* @dont_zap_me(i8 %v) { + %i1 = call i32 @external() + + ; The call to this function cannot be removed due to side effects. Thus the + ; return value should stay as it is, and should not be zapped. + ; CHECK: ret i8* null + ret i8* null +} diff --git a/test/Transforms/InstCombine/gep-addrspace.ll b/test/Transforms/InstCombine/gep-addrspace.ll index aa46ea6713025..4a4951dee7fd1 100644 --- a/test/Transforms/InstCombine/gep-addrspace.ll +++ b/test/Transforms/InstCombine/gep-addrspace.ll @@ -32,3 +32,22 @@ entry: ret void } +declare void @escape_alloca(i16*) + +; check that addrspacecast is not ignored (leading to an assertion failure) +; when trying to mark a GEP as inbounds +define { i8, i8 } @inbounds_after_addrspacecast() { +top: +; CHECK-LABEL: @inbounds_after_addrspacecast + %0 = alloca i16, align 2 + call void @escape_alloca(i16* %0) + %tmpcast = bitcast i16* %0 to [2 x i8]* +; CHECK: addrspacecast [2 x i8]* %tmpcast to [2 x i8] addrspace(11)* + %1 = addrspacecast [2 x i8]* %tmpcast to [2 x i8] addrspace(11)* +; CHECK: getelementptr [2 x i8], [2 x i8] addrspace(11)* %1, i64 0, i64 1 + %2 = getelementptr [2 x i8], [2 x i8] addrspace(11)* %1, i64 0, i64 1 +; CHECK: addrspace(11) + %3 = load i8, i8 addrspace(11)* %2, align 1 + %.fca.1.insert = insertvalue { i8, i8 } zeroinitializer, i8 %3, 1 + ret { i8, i8 } %.fca.1.insert +} diff --git a/test/Transforms/JumpThreading/header-succ.ll b/test/Transforms/JumpThreading/header-succ.ll new file mode 100644 index 0000000000000..859d44cff2939 --- /dev/null +++ b/test/Transforms/JumpThreading/header-succ.ll @@ -0,0 +1,99 @@ +; RUN: opt -S -jump-threading < %s | FileCheck %s + +; Check that the heuristic for avoiding accidental introduction of irreducible +; loops doesn't also prevent us from threading simple constructs where this +; isn't a problem. + +declare void @opaque_body() + +define void @jump_threading_loopheader() { +; CHECK-LABEL: @jump_threading_loopheader +top: + br label %entry + +entry: + %ind = phi i32 [0, %top], [%nextind, %latch] + %nextind = add i32 %ind, 1 + %cmp = icmp ule i32 %ind, 10 +; CHECK: br i1 %cmp, label %latch, label %exit + br i1 %cmp, label %body, label %latch + +body: + call void @opaque_body() +; CHECK: br label %entry + br label %latch + +latch: + %cond = phi i2 [1, %entry], [2, %body] + switch i2 %cond, label %unreach [ + i2 2, label %entry + i2 1, label %exit + ] + +unreach: + unreachable + +exit: + ret void +} + +; We also need to check the opposite order of the branches, in the switch +; instruction because jump-threading relies on that to decide which edge to +; try to thread first. +define void @jump_threading_loopheader2() { +; CHECK-LABEL: @jump_threading_loopheader2 +top: + br label %entry + +entry: + %ind = phi i32 [0, %top], [%nextind, %latch] + %nextind = add i32 %ind, 1 + %cmp = icmp ule i32 %ind, 10 +; CHECK: br i1 %cmp, label %exit, label %latch + br i1 %cmp, label %body, label %latch + +body: + call void @opaque_body() +; CHECK: br label %entry + br label %latch + +latch: + %cond = phi i2 [1, %entry], [2, %body] + switch i2 %cond, label %unreach [ + i2 1, label %entry + i2 2, label %exit + ] + +unreach: + unreachable + +exit: + ret void +} + +; Check if we can handle undef branch condition. +define void @jump_threading_loopheader3() { +; CHECK-LABEL: @jump_threading_loopheader3 +top: + br label %entry + +entry: + %ind = phi i32 [0, %top], [%nextind, %latch] + %nextind = add i32 %ind, 1 + %cmp = icmp ule i32 %ind, 10 +; CHECK: br i1 %cmp, label %latch, label %exit + br i1 %cmp, label %body, label %latch + +body: + call void @opaque_body() +; CHECK: br label %entry + br label %latch + +latch: + %phi = phi i32 [undef, %entry], [0, %body] + %cmp1 = icmp eq i32 %phi, 0 + br i1 %cmp1, label %entry, label %exit + +exit: + ret void +} diff --git a/test/Transforms/MergeFunc/inline-asm.ll b/test/Transforms/MergeFunc/inline-asm.ll new file mode 100644 index 0000000000000..370d3c56f060e --- /dev/null +++ b/test/Transforms/MergeFunc/inline-asm.ll @@ -0,0 +1,53 @@ +; RUN: opt -mergefunc -S < %s | FileCheck %s + +; CHECK-LABEL: @int_ptr_arg_different +; CHECK-NEXT: call void asm + +; CHECK-LABEL: @int_ptr_arg_same +; CHECK-NEXT: %2 = bitcast i32* %0 to float* +; CHECK-NEXT: tail call void @float_ptr_arg_same(float* %2) + +; CHECK-LABEL: @int_ptr_null +; CHECK-NEXT: tail call void @float_ptr_null() + +; Used to satisfy minimum size limit +declare void @stuff() + +; Can be merged +define void @float_ptr_null() { + call void asm "nop", "r"(float* null) + call void @stuff() + ret void +} + +define void @int_ptr_null() { + call void asm "nop", "r"(i32* null) + call void @stuff() + ret void +} + +; Can be merged (uses same argument differing by pointer type) +define void @float_ptr_arg_same(float*) { + call void asm "nop", "r"(float* %0) + call void @stuff() + ret void +} + +define void @int_ptr_arg_same(i32*) { + call void asm "nop", "r"(i32* %0) + call void @stuff() + ret void +} + +; Can not be merged (uses different arguments) +define void @float_ptr_arg_different(float*, float*) { + call void asm "nop", "r"(float* %0) + call void @stuff() + ret void +} + +define void @int_ptr_arg_different(i32*, i32*) { + call void asm "nop", "r"(i32* %1) + call void @stuff() + ret void +} diff --git a/test/Transforms/MergeFunc/weak-small.ll b/test/Transforms/MergeFunc/weak-small.ll new file mode 100644 index 0000000000000..64f1083174623 --- /dev/null +++ b/test/Transforms/MergeFunc/weak-small.ll @@ -0,0 +1,16 @@ +; RUN: opt -mergefunc -S < %s | FileCheck %s + +; Weak functions too small for merging to be profitable + +; CHECK: define weak i32 @foo(i8*, i32) +; CHECK-NEXT: ret i32 %1 +; CHECK: define weak i32 @bar(i8*, i32) +; CHECK-NEXT: ret i32 %1 + +define weak i32 @foo(i8*, i32) #0 { + ret i32 %1 +} + +define weak i32 @bar(i8*, i32) #0 { + ret i32 %1 +} |