-; RUN: opt < %s -inline -S | not grep "invoke void asm"
+; RUN: opt < %s -inline -S | FileCheck %s
; PR1335
-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"
target triple = "i686-pc-linux-gnu"
- %struct.gnat__strings__string_access = type { i8*, %struct.string___XUB* }
- %struct.string___XUB = type { i32, i32 }
-define void @bc__support__high_resolution_time__clock() {
-entry:
- call void asm "rdtsc\0A\09movl %eax, $0\0A\09movl %edx, $1", "=*imr,=*imr,~{dirflag},~{fpsr},~{flags},~{dx},~{ax}"( i32* null, i32* null ) nounwind
- unreachable
-}
+declare i32 @__gxx_personality_v0(...)
-define fastcc void @bc__support__high_resolution_time__initialize_clock_rate() personality i32 (...)* @__gxx_personality_v0 {
-entry:
- invoke void @gnat__os_lib__getenv( %struct.gnat__strings__string_access* null )
- to label %invcont unwind label %cleanup144
+declare void @a()
-invcont: ; preds = %entry
- invoke void @ada__calendar__delays__delay_for( )
- to label %invcont64 unwind label %cleanup144
+declare void @b()
-invcont64: ; preds = %invcont
- invoke void @ada__calendar__clock( )
- to label %invcont65 unwind label %cleanup144
+declare void @c()
-invcont65: ; preds = %invcont64
- invoke void @bc__support__high_resolution_time__clock( )
- to label %invcont67 unwind label %cleanup144
+define void @f() {
+; CHECK-LABEL: define void @f()
+entry:
+ call void asm "rdtsc\0A\09movl %eax, $0\0A\09movl %edx, $1", "=*imr,=*imr,~{dirflag},~{fpsr},~{flags},~{dx},~{ax}"( i32* null, i32* null ) nounwind
+; CHECK: call void asm
+ unreachable
+}
-invcont67: ; preds = %invcont65
- ret void
+define void @g() personality i32 (...)* @__gxx_personality_v0 {
+; CHECK-LABEL: define void @g() personality i32 (...)* @__gxx_personality_v0
+entry:
+ invoke void @a() to label %invcont1 unwind label %cleanup
+; CHECK-NOT: {{call|invoke}}
+; CHECK: invoke void @a()
-cleanup144: ; preds = %invcont65, %invcont64, %invcont, %entry
- %exn = landingpad {i8*, i32}
- cleanup
- resume { i8*, i32 } %exn
-}
+invcont1:
+ invoke void @b() to label %invcont2 unwind label %cleanup
+; CHECK-NOT: {{call|invoke}}
+; CHECK: invoke void @b()
-declare i32 @__gxx_personality_v0(...)
+invcont2:
+ invoke void @c() to label %invcont3 unwind label %cleanup
+; CHECK-NOT: {{call|invoke}}
+; CHECK: invoke void @c()
-declare void @gnat__os_lib__getenv(%struct.gnat__strings__string_access*)
+invcont3:
+ invoke void @f() to label %invcont4 unwind label %cleanup
+; CHECK-NOT: {{call|invoke}}
+; CHECK: call void asm
+; CHECK-NOT: {{call|invoke}}
-declare void @ada__calendar__delays__delay_for()
+invcont4:
+ ret void
-declare void @ada__calendar__clock()
+cleanup:
+ %ex = landingpad {i8*, i32} cleanup
+ resume { i8*, i32 } %ex
+}
-define void @bc__support__high_resolution_time___elabb() {
+define void @h() {
+; CHECK-LABEL: define void @h() personality i32 (...)* @__gxx_personality_v0
entry:
- call fastcc void @bc__support__high_resolution_time__initialize_clock_rate( )
- ret void
+ call void @g()
+; CHECK-NOT: {{call|invoke}}
+; CHECK: invoke void @a()
+; CHECK-NOT: {{call|invoke}}
+; CHECK: invoke void @b()
+; CHECK-NOT: {{call|invoke}}
+; CHECK: invoke void @c()
+; CHECK-NOT: {{call|invoke}}
+; CHECK: call void asm
+; CHECK-NOT: {{call|invoke}}
+
+ ret void
}
-; RUN: opt < %s -inline -S | grep call
+; RUN: opt < %s -inline -S | FileCheck %s
; 'bar' can be overridden at link-time, don't inline it.
-
-define void @foo() {
+define weak void @bar() {
+; CHECK-LABEL: define weak void @bar()
entry:
- tail call void @bar( ) ; <i32> [#uses=0]
- ret void
+ ret void
}
-define weak void @bar() {
- ret void
+define void @foo() {
+; CHECK-LABEL: define void @foo()
+entry:
+ tail call void @bar()
+; CHECK: tail call void @bar()
+ ret void
}
-; RUN: opt < %s -inline -S | grep nounwind
-; RUN: opt < %s -inline -S | grep unreachable
+; RUN: opt < %s -inline -S | FileCheck %s
declare i1 @extern()
define internal i32 @test() {
+; CHECK-NOT: define .* @test()
entry:
- %n = call i1 @extern( )
- br i1 %n, label %r, label %u
+ %n = call i1 @extern()
+ br i1 %n, label %r, label %u
+
r:
- ret i32 0
+ ret i32 0
+
u:
- unreachable
+ unreachable
}
define i32 @caller() {
- %X = call i32 @test( ) nounwind
- ret i32 %X
+; CHECK-LABEL: define i32 @caller()
+entry:
+ %X = call i32 @test() nounwind
+; CHECK-NOT: call i32 @test()
+; CHECK: call i1 @extern() #0
+; CHECK: br i1 %{{.*}}, label %[[R:.*]], label %[[U:.*]]
+
+; CHECK: [[U]]:
+; CHECK: unreachable
+
+; CHECK: [[R]]:
+ ret i32 %X
+; CHECK: ret i32 0
}
+
+; CHECK: attributes #0 = { nounwind }
-; RUN: opt < %s -inline -S | grep call | count 1
+; RUN: opt < %s -inline -S | FileCheck %s
define i32 @fn2() noinline {
+; CHECK-LABEL: define i32 @fn2()
+entry:
ret i32 1
}
define i32 @fn3() {
- %r = call i32 @fn2()
- ret i32 %r
+; CHECK-LABEL: define i32 @fn3()
+entry:
+ %r = call i32 @fn2()
+; CHECK: call i32 @fn2()
+
+ ret i32 %r
}
-; RUN: opt < %s -inline -S | grep call
-; Do not inline calls to variable-sized alloca.
+; RUN: opt < %s -inline -S | FileCheck %s
+; Do not inline calls with variable-sized alloca.
-@q = common global i8* null ; <i8**> [#uses=1]
+@q = common global i8* null
define i8* @a(i32 %i) nounwind {
+; CHECK-LABEL: define i8* @a
entry:
- %i_addr = alloca i32 ; <i32*> [#uses=2]
- %retval = alloca i8* ; <i8**> [#uses=1]
- %p = alloca i8* ; <i8**> [#uses=2]
- %"alloca point" = bitcast i32 0 to i32 ; <i32> [#uses=0]
- store i32 %i, i32* %i_addr
- %0 = load i32, i32* %i_addr, align 4 ; <i32> [#uses=1]
- %1 = alloca i8, i32 %0 ; <i8*> [#uses=1]
- store i8* %1, i8** %p, align 4
- %2 = load i8*, i8** %p, align 4 ; <i8*> [#uses=1]
- store i8* %2, i8** @q, align 4
- br label %return
+ %i_addr = alloca i32
+ %retval = alloca i8*
+ %p = alloca i8*
+ %"alloca point" = bitcast i32 0 to i32
+ store i32 %i, i32* %i_addr
+ %0 = load i32, i32* %i_addr, align 4
+ %1 = alloca i8, i32 %0
+ store i8* %1, i8** %p, align 4
+ %2 = load i8*, i8** %p, align 4
+ store i8* %2, i8** @q, align 4
+ br label %return
-return: ; preds = %entry
- %retval1 = load i8*, i8** %retval ; <i8*> [#uses=1]
- ret i8* %retval1
+return:
+ %retval1 = load i8*, i8** %retval
+ ret i8* %retval1
}
define void @b(i32 %i) nounwind {
+; CHECK-LABEL: define void @b
entry:
- %i_addr = alloca i32 ; <i32*> [#uses=2]
- %"alloca point" = bitcast i32 0 to i32 ; <i32> [#uses=0]
- store i32 %i, i32* %i_addr
- %0 = load i32, i32* %i_addr, align 4 ; <i32> [#uses=1]
- %1 = call i8* @a(i32 %0) nounwind ; <i8*> [#uses=0]
- br label %return
+ %i_addr = alloca i32
+ %"alloca point" = bitcast i32 0 to i32
+ store i32 %i, i32* %i_addr
+ %0 = load i32, i32* %i_addr, align 4
+ %1 = call i8* @a(i32 %0) nounwind
+; CHECK: call i8* @a
+ br label %return
-return: ; preds = %entry
- ret void
+return:
+ ret void
}
-; RUN: opt < %s -inline -S | grep "ret i32 1"
-; ModuleID = 'short.opt.bc'
-
-define i32 @testBool(i1 %X) {
- %tmp = zext i1 %X to i32 ; <i32> [#uses=1]
- ret i32 %tmp
-}
+; RUN: opt < %s -inline -S | FileCheck %s
define i32 @testByte(i8 %X) {
- %tmp = icmp ne i8 %X, 0 ; <i1> [#uses=1]
- %tmp.i = zext i1 %tmp to i32 ; <i32> [#uses=1]
- ret i32 %tmp.i
+entry:
+ %tmp = icmp ne i8 %X, 0
+ %tmp.i = zext i1 %tmp to i32
+ ret i32 %tmp.i
}
define i32 @main() {
- %rslt = call i32 @testByte( i8 123 ) ; <i32> [#uses=1]
- ret i32 %rslt
+; CHECK-LABEL: define i32 @main()
+entry:
+ %rslt = call i32 @testByte(i8 123)
+; CHECK-NOT: call
+ ret i32 %rslt
+; CHECK: ret i32 1
}
-
; This test ensures that inlining an "empty" function does not destroy the CFG
;
-; RUN: opt < %s -inline -S | not grep br
+; RUN: opt < %s -inline -S | FileCheck %s
define i32 @func(i32 %i) {
- ret i32 %i
+ ret i32 %i
}
-declare void @bar()
-define i32 @main(i32 %argc) {
-Entry:
- %X = call i32 @func( i32 7 ) ; <i32> [#uses=1]
- ret i32 %X
+define i32 @main() {
+; CHECK-LABEL: define i32 @main()
+entry:
+ %X = call i32 @func(i32 7)
+; CHECK-NOT: call
+; CHECK-NOT: br
+
+ ret i32 %X
+; CHECK: ret i32 7
}
-; RUN: opt < %s -inline -constprop -S > %t
-; RUN: not grep test_function %t
-; RUN: grep "ret i32 5" %t
+; RUN: opt < %s -inline -constprop -S | FileCheck %s
-
-; test_function should not be emitted to the .s file.
define available_externally i32 @test_function() {
+; CHECK-NOT: @test_function
+entry:
ret i32 4
}
define i32 @result() {
+; CHECK-LABEL: define i32 @result()
+entry:
%A = call i32 @test_function()
+; CHECK-NOT: call
+; CHECK-NOT: @test_function
+
%B = add i32 %A, 1
ret i32 %B
+; CHECK: ret i32 5
}
+
+; CHECK-NOT: @test_function
; PR3550
define internal void @foo(i32* %p, i32* %q) {
- %pp = bitcast i32* %p to i8*
- %qq = bitcast i32* %q to i8*
- tail call void @llvm.memcpy.p0i8.p0i8.i32(i8* %pp, i8* %qq, i32 4, i32 1, i1 false)
- ret void
+; CHECK-NOT: @foo
+entry:
+ %pp = bitcast i32* %p to i8*
+ %qq = bitcast i32* %q to i8*
+ tail call void @llvm.memcpy.p0i8.p0i8.i32(i8* %pp, i8* %qq, i32 4, i32 1, i1 false)
+ ret void
}
define i32 @main() personality i32 (...)* @__gxx_personality_v0 {
- %a = alloca i32 ; <i32*> [#uses=3]
- %b = alloca i32 ; <i32*> [#uses=2]
- store i32 1, i32* %a, align 4
- store i32 0, i32* %b, align 4
- invoke void @foo(i32* %a, i32* %b)
- to label %invcont unwind label %lpad
+; CHECK-LABEL: define i32 @main() personality i32 (...)* @__gxx_personality_v0
+entry:
+ %a = alloca i32
+ %b = alloca i32
+ store i32 1, i32* %a, align 4
+ store i32 0, i32* %b, align 4
+ invoke void @foo(i32* %a, i32* %b)
+ to label %invcont unwind label %lpad
+; CHECK-NOT: invoke
+; CHECK-NOT: @foo
+; CHECK-NOT: tail
+; CHCEK: call void @llvm.memcpy.p0i8.p0i8.i32
+; CHECK: br
invcont:
- %retval = load i32, i32* %a, align 4
- ret i32 %retval
+ %retval = load i32, i32* %a, align 4
+ ret i32 %retval
lpad:
- %exn = landingpad {i8*, i32}
- catch i8* null
- unreachable
+ %exn = landingpad {i8*, i32}
+ catch i8* null
+ unreachable
}
declare i32 @__gxx_personality_v0(...)
; RUN: not grep @reallysmall
define internal i32 @reallysmall(i32 %A) {
- ret i32 %A
+; CHECK-NOT: @reallysmall
+entry:
+ ret i32 %A
}
define void @caller1() {
- call i32 @reallysmall( i32 5 ) ; <i32>:1 [#uses=0]
- ret void
+; CHECK-LABEL: define void @caller1()
+entry:
+ call i32 @reallysmall(i32 5)
+; CHECK-NOT: call
+ ret void
}
define void @caller2(i32 %A) {
- call i32 @reallysmall( i32 %A ) ; <i32>:1 [#uses=0]
- ret void
+; CHECK-LABEL: define void @caller2(i32 %A)
+entry:
+ call i32 @reallysmall(i32 %A)
+; CHECK-NOT: call
+ ret void
}
define i32 @caller3(i32 %A) {
- %B = call i32 @reallysmall( i32 %A ) ; <i32> [#uses=1]
- ret i32 %B
+; CHECK-LABEL: define void @caller3(i32 %A)
+entry:
+ %B = call i32 @reallysmall(i32 %A)
+; CHECK-NOT: call
+ ret i32 %B
}
-; RUN: opt < %s -inline -S | \
-; RUN: not grep "callee[12]("
-; RUN: opt < %s -inline -S | not grep mul
+; RUN: opt < %s -inline -S | FileCheck %s
define internal i32 @callee1(i32 %A, i32 %B) {
- %cond = icmp eq i32 %A, 123 ; <i1> [#uses=1]
- br i1 %cond, label %T, label %F
+; CHECK-NOT: @callee1
+entry:
+ %cond = icmp eq i32 %A, 123
+ br i1 %cond, label %T, label %F
-T: ; preds = %0
- %C = mul i32 %B, %B ; <i32> [#uses=1]
- ret i32 %C
+T:
+ %C = mul i32 %B, %B
+ ret i32 %C
-F: ; preds = %0
- ret i32 0
+F:
+ ret i32 0
}
define internal i32 @callee2(i32 %A, i32 %B) {
- switch i32 %A, label %T [
- i32 10, label %F
- i32 1234, label %G
- ]
- ; No predecessors!
- %cond = icmp eq i32 %A, 123 ; <i1> [#uses=1]
- br i1 %cond, label %T, label %F
-
-T: ; preds = %1, %0
- %C = mul i32 %B, %B ; <i32> [#uses=1]
- ret i32 %C
-
-F: ; preds = %1, %0
- ret i32 0
-
-G: ; preds = %0
- %D = mul i32 %B, %B ; <i32> [#uses=1]
- %E = mul i32 %D, %B ; <i32> [#uses=1]
- ret i32 %E
+; CHECK-NOT: @callee2
+entry:
+ switch i32 %A, label %T [
+ i32 10, label %F
+ i32 1234, label %G
+ ]
+
+dead:
+ %cond = icmp eq i32 %A, 123
+ br i1 %cond, label %T, label %F
+
+T:
+ %C = mul i32 %B, %B
+ ret i32 %C
+
+F:
+ ret i32 0
+
+G:
+ %D = mul i32 %B, %B
+ %E = mul i32 %D, %B
+ ret i32 %E
}
define i32 @test(i32 %A) {
- %X = call i32 @callee1( i32 10, i32 %A ) ; <i32> [#uses=1]
- %Y = call i32 @callee2( i32 10, i32 %A ) ; <i32> [#uses=1]
- %Z = add i32 %X, %Y ; <i32> [#uses=1]
- ret i32 %Z
+; CHECK-LABEL: define i32 @test(i32 %A)
+entry:
+ %X = call i32 @callee1( i32 10, i32 %A )
+ %Y = call i32 @callee2( i32 10, i32 %A )
+; CHECK-NOT: call
+; CHECK-NOT: mul
+
+ %Z = add i32 %X, %Y
+ ret i32 %Z
}
; Test that we can inline a simple function, turning the calls in it into invoke
; instructions
-; RUN: opt < %s -inline -S | \
-; RUN: not grep "call[^e]"
+; RUN: opt < %s -inline -S | FileCheck %s
declare void @might_throw()
define internal void @callee() {
- call void @might_throw( )
- ret void
+entry:
+ call void @might_throw()
+ ret void
}
; caller returns true if might_throw throws an exception...
define i32 @caller() personality i32 (...)* @__gxx_personality_v0 {
- invoke void @callee( )
- to label %cont unwind label %exc
+; CHECK-LABEL: define i32 @caller() personality i32 (...)* @__gxx_personality_v0
+entry:
+ invoke void @callee()
+ to label %cont unwind label %exc
+; CHECK-NOT: @callee
+; CHECK: invoke void @might_throw()
-cont: ; preds = %0
- ret i32 0
+cont:
+ ret i32 0
-exc: ; preds = %0
- %exn = landingpad {i8*, i32}
- cleanup
- ret i32 1
+exc:
+ %exn = landingpad {i8*, i32}
+ cleanup
+ ret i32 1
}
declare i32 @__gxx_personality_v0(...)
; Test that if an invoked function is inlined, and if that function cannot
; throw, that the dead handler is now unreachable.
-; RUN: opt < %s -inline -simplifycfg -S | \
-; RUN: not grep UnreachableExceptionHandler
+; RUN: opt < %s -inline -simplifycfg -S | FileCheck %s
declare void @might_throw()
define internal i32 @callee() personality i32 (...)* @__gxx_personality_v0 {
- invoke void @might_throw( )
- to label %cont unwind label %exc
+enrty:
+ invoke void @might_throw()
+ to label %cont unwind label %exc
-cont: ; preds = %0
- ret i32 0
+cont:
+ ret i32 0
-exc: ; preds = %0
- %exn = landingpad {i8*, i32}
- cleanup
- ret i32 1
+exc:
+ %exn = landingpad {i8*, i32}
+ cleanup
+ ret i32 1
}
; caller returns true if might_throw throws an exception... callee cannot throw.
define i32 @caller() personality i32 (...)* @__gxx_personality_v0 {
- %X = invoke i32 @callee( )
- to label %cont unwind label %UnreachableExceptionHandler ; <i32> [#uses=1]
-
-cont: ; preds = %0
- ret i32 %X
-
-UnreachableExceptionHandler: ; preds = %0
- %exn = landingpad {i8*, i32}
- cleanup
- ret i32 -1
+; CHECK-LABEL: define i32 @caller() personality i32 (...)* @__gxx_personality_v0
+enrty:
+ %X = invoke i32 @callee()
+ to label %cont unwind label %UnreachableExceptionHandler
+; CHECK-NOT: @callee
+; CHECK: invoke void @might_throw()
+; CHECK: to label %[[C:.*]] unwind label %[[E:.*]]
+
+; CHECK: [[E]]:
+; CHECK: landingpad
+; CHECK: cleanup
+; CHECK: br label %[[C]]
+
+cont:
+; CHECK: [[C]]:
+ ret i32 %X
+; CHECK: %[[PHI:.*]] = phi i32
+; CHECK: ret i32 %[[PHI]]
+
+UnreachableExceptionHandler:
+; CHECK-NOT: UnreachableExceptionHandler:
+ %exn = landingpad {i8*, i32}
+ cleanup
+ ret i32 -1
+; CHECK-NOT: ret i32 -1
}
+; CHECK: }
declare i32 @__gxx_personality_v0(...)
; Test that any rethrown exceptions in an inlined function are automatically
; turned into branches to the invoke destination.
-; RUN: opt < %s -inline -S | not grep unwind$
+; RUN: opt < %s -inline -S | FileCheck %s
declare void @might_throw()
define internal i32 @callee() personality i32 (...)* @__gxx_personality_v0 {
- invoke void @might_throw( )
- to label %cont unwind label %exc
-
-cont: ; preds = %0
- ret i32 0
-
-exc: ; preds = %0a
- ; This just rethrows the exception!
- %exn = landingpad {i8*, i32}
- cleanup
- resume { i8*, i32 } %exn
+entry:
+ invoke void @might_throw()
+ to label %cont unwind label %exc
+
+cont:
+ ret i32 0
+
+exc:
+ ; This just rethrows the exception!
+ %exn = landingpad {i8*, i32}
+ cleanup
+ resume { i8*, i32 } %exn
}
; caller returns true if might_throw throws an exception... which gets
; propagated by callee.
define i32 @caller() personality i32 (...)* @__gxx_personality_v0 {
- %X = invoke i32 @callee( )
- to label %cont unwind label %Handler ; <i32> [#uses=1]
-
-cont: ; preds = %0
- ret i32 %X
-
-Handler: ; preds = %0
+; CHECK-LABEL: define i32 @caller()
+entry:
+ %X = invoke i32 @callee()
+ to label %cont unwind label %Handler
+; CHECK-NOT: @callee
+; CHECK: invoke void @might_throw()
+; At this point we just check that the rest of the function does not 'resume'
+; at any point and instead the inlined resume is threaded into normal control
+; flow.
+; CHECK-NOT: resume
+
+cont:
+ ret i32 %X
+
+Handler:
; This consumes an exception thrown by might_throw
- %exn = landingpad {i8*, i32}
- cleanup
- ret i32 1
+ %exn = landingpad {i8*, i32}
+ cleanup
+ ret i32 1
}
declare i32 @__gxx_personality_v0(...)