aboutsummaryrefslogtreecommitdiffstats
path: root/test/Transforms/Inline
diff options
context:
space:
mode:
Diffstat (limited to 'test/Transforms/Inline')
-rw-r--r--test/Transforms/Inline/2010-05-31-ByvalTailcall.ll24
-rw-r--r--test/Transforms/Inline/always-inline.ll11
-rw-r--r--test/Transforms/Inline/byval-tail-call.ll38
-rw-r--r--test/Transforms/Inline/byval_lifetime.ll26
-rw-r--r--test/Transforms/Inline/inline-cold.ll116
-rw-r--r--test/Transforms/Inline/inline-tail.ll185
-rw-r--r--test/Transforms/Inline/inline-vla.ll38
-rw-r--r--test/Transforms/Inline/optimization-remarks.ll60
-rw-r--r--test/Transforms/Inline/switch.ll60
9 files changed, 523 insertions, 35 deletions
diff --git a/test/Transforms/Inline/2010-05-31-ByvalTailcall.ll b/test/Transforms/Inline/2010-05-31-ByvalTailcall.ll
deleted file mode 100644
index b37b9f2..0000000
--- a/test/Transforms/Inline/2010-05-31-ByvalTailcall.ll
+++ /dev/null
@@ -1,24 +0,0 @@
-; RUN: opt < %s -tailcallelim -inline -instcombine -dse -S | FileCheck %s
-; PR7272
-
-; When inlining through a byval call site, the inliner creates allocas which may
-; be used by inlined calls, so any inlined calls need to have their 'tail' flags
-; cleared. If not then you can get nastiness like with this testcase, where the
-; (inlined) call to 'ext' in 'foo' was being passed an uninitialized value.
-
-target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:32:32-n8:16:32"
-target triple = "i386-pc-linux-gnu"
-
-declare void @ext(i32*)
-
-define void @bar(i32* byval %x) {
- call void @ext(i32* %x)
- ret void
-}
-
-define void @foo(i32* %x) {
-; CHECK-LABEL: define void @foo(
-; CHECK: store i32 %1, i32* %x
- call void @bar(i32* byval %x)
- ret void
-}
diff --git a/test/Transforms/Inline/always-inline.ll b/test/Transforms/Inline/always-inline.ll
index a8703b8..5ad1bde 100644
--- a/test/Transforms/Inline/always-inline.ll
+++ b/test/Transforms/Inline/always-inline.ll
@@ -122,3 +122,14 @@ entry:
ret void
}
+define i32 @inner7() {
+ ret i32 1
+}
+define i32 @outer7() {
+; CHECK-LABEL: @outer7(
+; CHECK-NOT: call
+; CHECK: ret
+
+ %r = call i32 @inner7() alwaysinline
+ ret i32 %r
+}
diff --git a/test/Transforms/Inline/byval-tail-call.ll b/test/Transforms/Inline/byval-tail-call.ll
new file mode 100644
index 0000000..3a8906a
--- /dev/null
+++ b/test/Transforms/Inline/byval-tail-call.ll
@@ -0,0 +1,38 @@
+; RUN: opt < %s -tailcallelim -inline -instcombine -dse -S | FileCheck %s
+; PR7272
+
+; Calls that capture byval parameters cannot be marked as tail calls. Other
+; tails that don't capture byval parameters can still be tail calls.
+
+target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:32:32-n8:16:32"
+target triple = "i386-pc-linux-gnu"
+
+declare void @ext(i32*)
+
+define void @bar(i32* byval %x) {
+ call void @ext(i32* %x)
+ ret void
+}
+
+define void @foo(i32* %x) {
+; CHECK-LABEL: define void @foo(
+; CHECK: llvm.lifetime.start
+; CHECK: store i32 %2, i32* %x
+ call void @bar(i32* byval %x)
+ ret void
+}
+
+define internal void @qux(i32* byval %x) {
+ call void @ext(i32* %x)
+ tail call void @ext(i32* null)
+ ret void
+}
+define void @frob(i32* %x) {
+; CHECK-LABEL: define void @frob(
+; CHECK: alloca i32
+; CHECK: {{^ *}}call void @ext(
+; CHECK: tail call void @ext(i32* null)
+; CHECK: ret void
+ tail call void @qux(i32* byval %x)
+ ret void
+}
diff --git a/test/Transforms/Inline/byval_lifetime.ll b/test/Transforms/Inline/byval_lifetime.ll
new file mode 100644
index 0000000..e8dff2a
--- /dev/null
+++ b/test/Transforms/Inline/byval_lifetime.ll
@@ -0,0 +1,26 @@
+; RUN: opt -S -inline < %s | FileCheck %s
+; END.
+
+; By inlining foo, an alloca is created in main to hold the byval argument, so
+; a lifetime marker should be generated as well by default.
+
+%struct.foo = type { i32, [16 x i32] }
+
+@gFoo = global %struct.foo zeroinitializer, align 8
+
+define i32 @foo(%struct.foo* byval align 8 %f, i32 %a) {
+entry:
+ %a1 = getelementptr inbounds %struct.foo* %f, i32 0, i32 1
+ %arrayidx = getelementptr inbounds [16 x i32]* %a1, i32 0, i32 %a
+ %tmp2 = load i32* %arrayidx, align 1
+ ret i32 %tmp2
+}
+
+define i32 @main(i32 %argc, i8** %argv) {
+; CHECK-LABEL: @main
+; CHECK: llvm.lifetime.start
+; CHECK: memcpy
+entry:
+ %call = call i32 @foo(%struct.foo* byval align 8 @gFoo, i32 %argc)
+ ret i32 %call
+}
diff --git a/test/Transforms/Inline/inline-cold.ll b/test/Transforms/Inline/inline-cold.ll
index bb8c008..5743377 100644
--- a/test/Transforms/Inline/inline-cold.ll
+++ b/test/Transforms/Inline/inline-cold.ll
@@ -1,8 +1,15 @@
; RUN: opt < %s -inline -S -inlinecold-threshold=75 | FileCheck %s
-
; Test that functions with attribute Cold are not inlined while the
; same function without attribute Cold will be inlined.
+; RUN: opt < %s -inline -S -inline-threshold=600 | FileCheck %s -check-prefix=OVERRIDE
+; The command line argument for inline-threshold should override
+; the default cold threshold, so a cold function with size bigger
+; than the default cold threshold (225) will be inlined.
+
+; RUN: opt < %s -inline -S | FileCheck %s -check-prefix=DEFAULT
+; The same cold function will not be inlined with the default behavior.
+
@a = global i32 4
; This function should be larger than the cold threshold (75), but smaller
@@ -42,6 +49,10 @@ entry:
define i32 @ColdFunction(i32 %a) #1 {
; CHECK-LABEL: @ColdFunction
; CHECK: ret
+; OVERRIDE-LABEL: @ColdFunction
+; OVERRIDE: ret
+; DEFAULT-LABEL: @ColdFunction
+; DEFAULT: ret
entry:
%a1 = load volatile i32* @a
%x1 = add i32 %a1, %a1
@@ -71,16 +82,117 @@ entry:
ret i32 %add
}
+; This function should be larger than the default cold threshold (225).
+define i32 @ColdFunction2(i32 %a) #1 {
+; CHECK-LABEL: @ColdFunction2
+; CHECK: ret
+; OVERRIDE-LABEL: @ColdFunction2
+; OVERRIDE: ret
+; DEFAULT-LABEL: @ColdFunction2
+; DEFAULT: ret
+entry:
+ %a1 = load volatile i32* @a
+ %x1 = add i32 %a1, %a1
+ %a2 = load volatile i32* @a
+ %x2 = add i32 %x1, %a2
+ %a3 = load volatile i32* @a
+ %x3 = add i32 %x2, %a3
+ %a4 = load volatile i32* @a
+ %x4 = add i32 %x3, %a4
+ %a5 = load volatile i32* @a
+ %x5 = add i32 %x4, %a5
+ %a6 = load volatile i32* @a
+ %x6 = add i32 %x5, %a6
+ %a7 = load volatile i32* @a
+ %x7 = add i32 %x6, %a7
+ %a8 = load volatile i32* @a
+ %x8 = add i32 %x7, %a8
+ %a9 = load volatile i32* @a
+ %x9 = add i32 %x8, %a9
+ %a10 = load volatile i32* @a
+ %x10 = add i32 %x9, %a10
+ %a11 = load volatile i32* @a
+ %x11 = add i32 %x10, %a11
+ %a12 = load volatile i32* @a
+ %x12 = add i32 %x11, %a12
+
+ %a21 = load volatile i32* @a
+ %x21 = add i32 %x12, %a21
+ %a22 = load volatile i32* @a
+ %x22 = add i32 %x21, %a22
+ %a23 = load volatile i32* @a
+ %x23 = add i32 %x22, %a23
+ %a24 = load volatile i32* @a
+ %x24 = add i32 %x23, %a24
+ %a25 = load volatile i32* @a
+ %x25 = add i32 %x24, %a25
+ %a26 = load volatile i32* @a
+ %x26 = add i32 %x25, %a26
+ %a27 = load volatile i32* @a
+ %x27 = add i32 %x26, %a27
+ %a28 = load volatile i32* @a
+ %x28 = add i32 %x27, %a28
+ %a29 = load volatile i32* @a
+ %x29 = add i32 %x28, %a29
+ %a30 = load volatile i32* @a
+ %x30 = add i32 %x29, %a30
+ %a31 = load volatile i32* @a
+ %x31 = add i32 %x30, %a31
+ %a32 = load volatile i32* @a
+ %x32 = add i32 %x31, %a32
+
+ %a41 = load volatile i32* @a
+ %x41 = add i32 %x32, %a41
+ %a42 = load volatile i32* @a
+ %x42 = add i32 %x41, %a42
+ %a43 = load volatile i32* @a
+ %x43 = add i32 %x42, %a43
+ %a44 = load volatile i32* @a
+ %x44 = add i32 %x43, %a44
+ %a45 = load volatile i32* @a
+ %x45 = add i32 %x44, %a45
+ %a46 = load volatile i32* @a
+ %x46 = add i32 %x45, %a46
+ %a47 = load volatile i32* @a
+ %x47 = add i32 %x46, %a47
+ %a48 = load volatile i32* @a
+ %x48 = add i32 %x47, %a48
+ %a49 = load volatile i32* @a
+ %x49 = add i32 %x48, %a49
+ %a50 = load volatile i32* @a
+ %x50 = add i32 %x49, %a50
+ %a51 = load volatile i32* @a
+ %x51 = add i32 %x50, %a51
+ %a52 = load volatile i32* @a
+ %x52 = add i32 %x51, %a52
+
+ %add = add i32 %x52, %a
+ ret i32 %add
+}
+
; Function Attrs: nounwind readnone uwtable
define i32 @bar(i32 %a) #0 {
; CHECK-LABEL: @bar
; CHECK: call i32 @ColdFunction(i32 5)
; CHECK-NOT: call i32 @simpleFunction(i32 6)
+; CHECK: call i32 @ColdFunction2(i32 5)
; CHECK: ret
+; OVERRIDE-LABEL: @bar
+; OVERRIDE-NOT: call i32 @ColdFunction(i32 5)
+; OVERRIDE-NOT: call i32 @simpleFunction(i32 6)
+; OVERRIDE-NOT: call i32 @ColdFunction2(i32 5)
+; OVERRIDE: ret
+; DEFAULT-LABEL: @bar
+; DEFAULT-NOT: call i32 @ColdFunction(i32 5)
+; DEFAULT-NOT: call i32 @simpleFunction(i32 6)
+; DEFAULT: call i32 @ColdFunction2(i32 5)
+; DEFAULT: ret
entry:
%0 = tail call i32 @ColdFunction(i32 5)
%1 = tail call i32 @simpleFunction(i32 6)
- %add = add i32 %0, %1
+ %2 = tail call i32 @ColdFunction2(i32 5)
+ %3 = add i32 %0, %1
+ %add = add i32 %2, %3
ret i32 %add
}
diff --git a/test/Transforms/Inline/inline-tail.ll b/test/Transforms/Inline/inline-tail.ll
index 8bb059d..b40328e 100644
--- a/test/Transforms/Inline/inline-tail.ll
+++ b/test/Transforms/Inline/inline-tail.ll
@@ -1,15 +1,182 @@
-; RUN: opt < %s -inline -S | not grep tail
+; RUN: opt < %s -inline -S | FileCheck %s
-declare void @bar(i32*)
+; We have to apply the less restrictive TailCallKind of the call site being
+; inlined and any call sites cloned into the caller.
-define internal void @foo(i32* %P) {
- tail call void @bar( i32* %P )
- ret void
+; No tail marker after inlining, since test_capture_c captures an alloca.
+; CHECK: define void @test_capture_a(
+; CHECK-NOT: tail
+; CHECK: call void @test_capture_c(
+
+declare void @test_capture_c(i32*)
+define internal void @test_capture_b(i32* %P) {
+ tail call void @test_capture_c(i32* %P)
+ ret void
+}
+define void @test_capture_a() {
+ %A = alloca i32 ; captured by test_capture_b
+ call void @test_capture_b(i32* %A)
+ ret void
+}
+
+; No musttail marker after inlining, since the prototypes don't match.
+; CHECK: define void @test_proto_mismatch_a(
+; CHECK-NOT: musttail
+; CHECK: call void @test_proto_mismatch_c(
+
+declare void @test_proto_mismatch_c(i32*)
+define internal void @test_proto_mismatch_b(i32* %p) {
+ musttail call void @test_proto_mismatch_c(i32* %p)
+ ret void
+}
+define void @test_proto_mismatch_a() {
+ call void @test_proto_mismatch_b(i32* null)
+ ret void
+}
+
+; After inlining through a musttail call site, we need to keep musttail markers
+; to prevent unbounded stack growth.
+; CHECK: define void @test_musttail_basic_a(
+; CHECK: musttail call void @test_musttail_basic_c(
+
+declare void @test_musttail_basic_c(i32* %p)
+define internal void @test_musttail_basic_b(i32* %p) {
+ musttail call void @test_musttail_basic_c(i32* %p)
+ ret void
+}
+define void @test_musttail_basic_a(i32* %p) {
+ musttail call void @test_musttail_basic_b(i32* %p)
+ ret void
+}
+
+; Don't insert lifetime end markers here, the lifetime is trivially over due
+; the return.
+; CHECK: define void @test_byval_a(
+; CHECK: musttail call void @test_byval_c(
+; CHECK-NEXT: ret void
+
+declare void @test_byval_c(i32* byval %p)
+define internal void @test_byval_b(i32* byval %p) {
+ musttail call void @test_byval_c(i32* byval %p)
+ ret void
+}
+define void @test_byval_a(i32* byval %p) {
+ musttail call void @test_byval_b(i32* byval %p)
+ ret void
}
-define void @caller() {
- %A = alloca i32 ; <i32*> [#uses=1]
- call void @foo( i32* %A )
- ret void
+; Don't insert a stack restore, we're about to return.
+; CHECK: define void @test_dynalloca_a(
+; CHECK: call i8* @llvm.stacksave(
+; CHECK: alloca i8, i32 %n
+; CHECK: musttail call void @test_dynalloca_c(
+; CHECK-NEXT: ret void
+
+declare void @escape(i8* %buf)
+declare void @test_dynalloca_c(i32* byval %p, i32 %n)
+define internal void @test_dynalloca_b(i32* byval %p, i32 %n) alwaysinline {
+ %buf = alloca i8, i32 %n ; dynamic alloca
+ call void @escape(i8* %buf) ; escape it
+ musttail call void @test_dynalloca_c(i32* byval %p, i32 %n)
+ ret void
+}
+define void @test_dynalloca_a(i32* byval %p, i32 %n) {
+ musttail call void @test_dynalloca_b(i32* byval %p, i32 %n)
+ ret void
}
+; We can't merge the returns.
+; CHECK: define void @test_multiret_a(
+; CHECK: musttail call void @test_multiret_c(
+; CHECK-NEXT: ret void
+; CHECK: musttail call void @test_multiret_d(
+; CHECK-NEXT: ret void
+
+declare void @test_multiret_c(i1 zeroext %b)
+declare void @test_multiret_d(i1 zeroext %b)
+define internal void @test_multiret_b(i1 zeroext %b) {
+ br i1 %b, label %c, label %d
+c:
+ musttail call void @test_multiret_c(i1 zeroext %b)
+ ret void
+d:
+ musttail call void @test_multiret_d(i1 zeroext %b)
+ ret void
+}
+define void @test_multiret_a(i1 zeroext %b) {
+ musttail call void @test_multiret_b(i1 zeroext %b)
+ ret void
+}
+
+; We have to avoid bitcast chains.
+; CHECK: define i32* @test_retptr_a(
+; CHECK: musttail call i8* @test_retptr_c(
+; CHECK-NEXT: bitcast i8* {{.*}} to i32*
+; CHECK-NEXT: ret i32*
+
+declare i8* @test_retptr_c()
+define internal i16* @test_retptr_b() {
+ %rv = musttail call i8* @test_retptr_c()
+ %v = bitcast i8* %rv to i16*
+ ret i16* %v
+}
+define i32* @test_retptr_a() {
+ %rv = musttail call i16* @test_retptr_b()
+ %v = bitcast i16* %rv to i32*
+ ret i32* %v
+}
+
+; Combine the last two cases: multiple returns with pointer bitcasts.
+; CHECK: define i32* @test_multiptrret_a(
+; CHECK: musttail call i8* @test_multiptrret_c(
+; CHECK-NEXT: bitcast i8* {{.*}} to i32*
+; CHECK-NEXT: ret i32*
+; CHECK: musttail call i8* @test_multiptrret_d(
+; CHECK-NEXT: bitcast i8* {{.*}} to i32*
+; CHECK-NEXT: ret i32*
+
+declare i8* @test_multiptrret_c(i1 zeroext %b)
+declare i8* @test_multiptrret_d(i1 zeroext %b)
+define internal i16* @test_multiptrret_b(i1 zeroext %b) {
+ br i1 %b, label %c, label %d
+c:
+ %c_rv = musttail call i8* @test_multiptrret_c(i1 zeroext %b)
+ %c_v = bitcast i8* %c_rv to i16*
+ ret i16* %c_v
+d:
+ %d_rv = musttail call i8* @test_multiptrret_d(i1 zeroext %b)
+ %d_v = bitcast i8* %d_rv to i16*
+ ret i16* %d_v
+}
+define i32* @test_multiptrret_a(i1 zeroext %b) {
+ %rv = musttail call i16* @test_multiptrret_b(i1 zeroext %b)
+ %v = bitcast i16* %rv to i32*
+ ret i32* %v
+}
+
+; Inline a musttail call site which contains a normal return and a musttail call.
+; CHECK: define i32 @test_mixedret_a(
+; CHECK: br i1 %b
+; CHECK: musttail call i32 @test_mixedret_c(
+; CHECK-NEXT: ret i32
+; CHECK: call i32 @test_mixedret_d(i1 zeroext %b)
+; CHECK: add i32 1,
+; CHECK-NOT: br
+; CHECK: ret i32
+
+declare i32 @test_mixedret_c(i1 zeroext %b)
+declare i32 @test_mixedret_d(i1 zeroext %b)
+define internal i32 @test_mixedret_b(i1 zeroext %b) {
+ br i1 %b, label %c, label %d
+c:
+ %c_rv = musttail call i32 @test_mixedret_c(i1 zeroext %b)
+ ret i32 %c_rv
+d:
+ %d_rv = call i32 @test_mixedret_d(i1 zeroext %b)
+ %d_rv1 = add i32 1, %d_rv
+ ret i32 %d_rv1
+}
+define i32 @test_mixedret_a(i1 zeroext %b) {
+ %rv = musttail call i32 @test_mixedret_b(i1 zeroext %b)
+ ret i32 %rv
+}
diff --git a/test/Transforms/Inline/inline-vla.ll b/test/Transforms/Inline/inline-vla.ll
new file mode 100644
index 0000000..dc9deaa
--- /dev/null
+++ b/test/Transforms/Inline/inline-vla.ll
@@ -0,0 +1,38 @@
+; RUN: opt -S -inline %s -o - | FileCheck %s
+
+; Check that memcpy2 is completely inlined away.
+; CHECK-NOT: memcpy2
+
+@.str = private unnamed_addr constant [2 x i8] c"a\00", align 1
+@.str1 = private unnamed_addr constant [3 x i8] c"ab\00", align 1
+
+; Function Attrs: nounwind ssp uwtable
+define i32 @main(i32 %argc, i8** nocapture readnone %argv) #0 {
+entry:
+ %data = alloca [2 x i8], align 1
+ %arraydecay = getelementptr inbounds [2 x i8]* %data, i64 0, i64 0
+ call fastcc void @memcpy2(i8* %arraydecay, i8* getelementptr inbounds ([2 x i8]* @.str, i64 0, i64 0), i64 1)
+ call fastcc void @memcpy2(i8* %arraydecay, i8* getelementptr inbounds ([3 x i8]* @.str1, i64 0, i64 0), i64 2)
+ ret i32 0
+}
+
+; Function Attrs: inlinehint nounwind ssp uwtable
+define internal fastcc void @memcpy2(i8* nocapture %dst, i8* nocapture readonly %src, i64 %size) #1 {
+entry:
+ %vla = alloca i64, i64 %size, align 16
+ %0 = bitcast i64* %vla to i8*
+ call void @llvm.memcpy.p0i8.p0i8.i64(i8* %0, i8* %src, i64 %size, i32 1, i1 false)
+ call void @llvm.memcpy.p0i8.p0i8.i64(i8* %dst, i8* %0, i64 %size, i32 1, i1 false)
+ ret void
+}
+
+; Function Attrs: nounwind
+declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture, i8* nocapture readonly, i64, i32, i1) #2
+
+attributes #0 = { nounwind ssp uwtable "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { inlinehint nounwind ssp uwtable "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #2 = { nounwind }
+
+!llvm.ident = !{!0}
+
+!0 = metadata !{metadata !"clang version 3.5.0 (trunk 205695) (llvm/trunk 205706)"}
diff --git a/test/Transforms/Inline/optimization-remarks.ll b/test/Transforms/Inline/optimization-remarks.ll
new file mode 100644
index 0000000..9108f3a
--- /dev/null
+++ b/test/Transforms/Inline/optimization-remarks.ll
@@ -0,0 +1,60 @@
+; RUN: opt < %s -inline -pass-remarks=inline -pass-remarks-missed=inline -pass-remarks-analysis=inline -S 2>&1 | FileCheck %s
+
+; CHECK: foo should always be inlined (cost=always)
+; CHECK: foo inlined into bar
+; CHECK: foz should never be inlined (cost=never)
+; CHECK: foz will not be inlined into bar
+
+; Function Attrs: alwaysinline nounwind uwtable
+define i32 @foo(i32 %x, i32 %y) #0 {
+entry:
+ %x.addr = alloca i32, align 4
+ %y.addr = alloca i32, align 4
+ store i32 %x, i32* %x.addr, align 4
+ store i32 %y, i32* %y.addr, align 4
+ %0 = load i32* %x.addr, align 4
+ %1 = load i32* %y.addr, align 4
+ %add = add nsw i32 %0, %1
+ ret i32 %add
+}
+
+; Function Attrs: noinline nounwind uwtable
+define float @foz(i32 %x, i32 %y) #1 {
+entry:
+ %x.addr = alloca i32, align 4
+ %y.addr = alloca i32, align 4
+ store i32 %x, i32* %x.addr, align 4
+ store i32 %y, i32* %y.addr, align 4
+ %0 = load i32* %x.addr, align 4
+ %1 = load i32* %y.addr, align 4
+ %mul = mul nsw i32 %0, %1
+ %conv = sitofp i32 %mul to float
+ ret float %conv
+}
+
+; Function Attrs: nounwind uwtable
+define i32 @bar(i32 %j) #2 {
+entry:
+ %j.addr = alloca i32, align 4
+ store i32 %j, i32* %j.addr, align 4
+ %0 = load i32* %j.addr, align 4
+ %1 = load i32* %j.addr, align 4
+ %sub = sub nsw i32 %1, 2
+ %call = call i32 @foo(i32 %0, i32 %sub)
+ %conv = sitofp i32 %call to float
+ %2 = load i32* %j.addr, align 4
+ %sub1 = sub nsw i32 %2, 2
+ %3 = load i32* %j.addr, align 4
+ %call2 = call float @foz(i32 %sub1, i32 %3)
+ %mul = fmul float %conv, %call2
+ %conv3 = fptosi float %mul to i32
+ ret i32 %conv3
+}
+
+attributes #0 = { alwaysinline nounwind uwtable "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { noinline nounwind uwtable "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #2 = { nounwind uwtable "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
+
+!llvm.ident = !{!0}
+
+!0 = metadata !{metadata !"clang version 3.5.0 "}
diff --git a/test/Transforms/Inline/switch.ll b/test/Transforms/Inline/switch.ll
new file mode 100644
index 0000000..c5dab53
--- /dev/null
+++ b/test/Transforms/Inline/switch.ll
@@ -0,0 +1,60 @@
+; RUN: opt < %s -inline -inline-threshold=20 -S | FileCheck %s
+
+define i32 @callee(i32 %a) {
+ switch i32 %a, label %sw.default [
+ i32 0, label %sw.bb0
+ i32 1, label %sw.bb1
+ i32 2, label %sw.bb2
+ i32 3, label %sw.bb3
+ i32 4, label %sw.bb4
+ i32 5, label %sw.bb5
+ i32 6, label %sw.bb6
+ i32 7, label %sw.bb7
+ i32 8, label %sw.bb8
+ i32 9, label %sw.bb9
+ ]
+
+sw.default:
+ br label %return
+
+sw.bb0:
+ br label %return
+
+sw.bb1:
+ br label %return
+
+sw.bb2:
+ br label %return
+
+sw.bb3:
+ br label %return
+
+sw.bb4:
+ br label %return
+
+sw.bb5:
+ br label %return
+
+sw.bb6:
+ br label %return
+
+sw.bb7:
+ br label %return
+
+sw.bb8:
+ br label %return
+
+sw.bb9:
+ br label %return
+
+return:
+ ret i32 42
+}
+
+define i32 @caller(i32 %a) {
+; CHECK-LABEL: @caller(
+; CHECK: call i32 @callee(
+
+ %result = call i32 @callee(i32 %a)
+ ret i32 %result
+}