summaryrefslogtreecommitdiff
path: root/test/Transforms
diff options
context:
space:
mode:
Diffstat (limited to 'test/Transforms')
-rw-r--r--test/Transforms/ArgumentPromotion/musttail.ll45
-rw-r--r--test/Transforms/CallSiteSplitting/musttail.ll109
-rw-r--r--test/Transforms/DeadArgElim/musttail-caller.ll16
-rw-r--r--test/Transforms/GlobalOpt/musttail_cc.ll34
-rw-r--r--test/Transforms/IPConstantProp/musttail-call.ll58
-rw-r--r--test/Transforms/InstCombine/gep-addrspace.ll19
-rw-r--r--test/Transforms/JumpThreading/header-succ.ll99
-rw-r--r--test/Transforms/MergeFunc/inline-asm.ll53
-rw-r--r--test/Transforms/MergeFunc/weak-small.ll16
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
+}