aboutsummaryrefslogtreecommitdiff
path: root/test/Feature
diff options
context:
space:
mode:
Diffstat (limited to 'test/Feature')
-rw-r--r--test/Feature/OperandBundles/adce.ll49
-rw-r--r--test/Feature/OperandBundles/basic-aa-argmemonly.ll51
-rw-r--r--test/Feature/OperandBundles/dse.ll62
-rw-r--r--test/Feature/OperandBundles/early-cse.ll89
-rw-r--r--test/Feature/OperandBundles/function-attrs.ll33
-rw-r--r--test/Feature/OperandBundles/inliner-conservative.ll17
-rw-r--r--test/Feature/OperandBundles/merge-func.ll64
-rw-r--r--test/Feature/OperandBundles/special-state.ll21
-rw-r--r--test/Feature/alias2.ll24
-rw-r--r--test/Feature/aliases.ll18
-rw-r--r--test/Feature/callingconventions.ll7
-rw-r--r--test/Feature/comdat.ll4
-rw-r--r--test/Feature/exception.ll109
-rw-r--r--test/Feature/optnone-llc.ll10
14 files changed, 533 insertions, 25 deletions
diff --git a/test/Feature/OperandBundles/adce.ll b/test/Feature/OperandBundles/adce.ll
new file mode 100644
index 000000000000..a729ba710689
--- /dev/null
+++ b/test/Feature/OperandBundles/adce.ll
@@ -0,0 +1,49 @@
+; RUN: opt -S -adce < %s | FileCheck %s
+
+; While it is normally okay to DCE out calls to @readonly_function and
+; @readnone_function, we cannot do that if they're carrying operand
+; bundles since the presence of unknown operand bundles implies
+; arbitrary memory effects.
+
+declare void @readonly_function() readonly nounwind
+declare void @readnone_function() readnone nounwind
+
+define void @test0() {
+; CHECK-LABEL: @test0(
+ entry:
+ call void @readonly_function() [ "tag"() ]
+; CHECK: call void @readonly_function
+ ret void
+}
+
+define void @test1() {
+; CHECK-LABEL: @test1(
+ entry:
+ call void @readnone_function() [ "tag"() ]
+; CHECK: call void @readnone_function
+ ret void
+}
+
+define void @test2() {
+; CHECK-LABEL: @test2(
+ entry:
+; CHECK-NOT: @readonly_function(
+ call void @readonly_function() readonly [ "tag"() ]
+ ret void
+}
+
+define void @test3() {
+; CHECK-LABEL: @test3(
+ entry:
+; CHECK-NOT: @readnone_function(
+ call void @readnone_function() readnone [ "tag"() ]
+ ret void
+}
+
+define void @test4() {
+; CHECK-LABEL: @test4(
+ entry:
+; CHECK-NOT: @readonly_function()
+ call void @readonly_function() [ "deopt"() ]
+ ret void
+}
diff --git a/test/Feature/OperandBundles/basic-aa-argmemonly.ll b/test/Feature/OperandBundles/basic-aa-argmemonly.ll
new file mode 100644
index 000000000000..aa9445886060
--- /dev/null
+++ b/test/Feature/OperandBundles/basic-aa-argmemonly.ll
@@ -0,0 +1,51 @@
+; RUN: opt -S -basicaa -gvn < %s | FileCheck %s
+
+declare void @argmemonly_function(i32 *) argmemonly
+
+define i32 @test0(i32* %P, i32* noalias %P2) {
+; CHECK-LABEL: @test0(
+ %v1 = load i32, i32* %P
+; CHECK: %v1 = load i32, i32* %P
+ call void @argmemonly_function(i32* %P2) [ "tag"() ]
+; CHECK: call void @argmemonly_function(
+ %v2 = load i32, i32* %P
+; CHECK: %v2 = load i32, i32* %P
+ %diff = sub i32 %v1, %v2
+; CHECK: %diff = sub i32 %v1, %v2
+ ret i32 %diff
+; CHECK: ret i32 %diff
+}
+
+define i32 @test1(i32* %P, i32* noalias %P2) {
+; CHECK-LABEL: @test1(
+ %v1 = load i32, i32* %P
+ call void @argmemonly_function(i32* %P2) argmemonly [ "tag"() ]
+; CHECK: call void @argmemonly_function(
+ %v2 = load i32, i32* %P
+ %diff = sub i32 %v1, %v2
+ ret i32 %diff
+; CHECK: ret i32 0
+}
+
+define i32 @test2(i32* %P, i32* noalias %P2) {
+; Note: in this test we //can// GVN %v1 and %v2 into one value in theory. Calls
+; with deopt operand bundles are not argmemonly because they *read* the entire
+; heap, but they don't write to any location in the heap if the callee does not
+; deoptimize the caller. This fact, combined with the fact that
+; @argmemonly_function is, well, an argmemonly function, can be used to conclude
+; that %P is not written to at the callsite. However LLVM currently cannot
+; describe the "does not write to non-args, and reads the entire heap" effect on
+; a callsite.
+
+; CHECK-LABEL: @test2(
+ %v1 = load i32, i32* %P
+; CHECK: %v1 = load i32, i32* %P
+ call void @argmemonly_function(i32* %P2) [ "deopt"() ]
+; CHECK: call void @argmemonly_function(
+ %v2 = load i32, i32* %P
+; CHECK: %v2 = load i32, i32* %P
+ %diff = sub i32 %v1, %v2
+; CHECK: %diff = sub i32 %v1, %v2
+ ret i32 %diff
+; CHECK: ret i32 %diff
+}
diff --git a/test/Feature/OperandBundles/dse.ll b/test/Feature/OperandBundles/dse.ll
new file mode 100644
index 000000000000..9ddf7f02e384
--- /dev/null
+++ b/test/Feature/OperandBundles/dse.ll
@@ -0,0 +1,62 @@
+; RUN: opt -S -dse < %s | FileCheck %s
+
+declare void @f()
+declare noalias i8* @malloc(i32) nounwind
+
+define void @test_0() {
+; CHECK-LABEL: @test_0(
+ %m = call i8* @malloc(i32 24)
+ tail call void @f() [ "unknown"(i8* %m) ]
+; CHECK: store i8 -19, i8* %m
+ store i8 -19, i8* %m
+ ret void
+}
+
+define i8* @test_1() {
+; CHECK-LABEL: @test_1(
+ %m = call i8* @malloc(i32 24)
+ tail call void @f() [ "unknown"(i8* %m) ]
+ store i8 -19, i8* %m
+ tail call void @f()
+ store i8 101, i8* %m
+
+; CHECK: tail call void @f() [ "unknown"(i8* %m) ]
+; CHECK: store i8 -19, i8* %m
+; CHECK: tail call void @f()
+; CHECK: store i8 101, i8* %m
+
+ ret i8* %m
+}
+
+define void @test_2() {
+; Since the deopt operand bundle does not escape %m (see caveat below), it is
+; legal to elide the final store that location.
+
+; CHECK-LABEL: @test_2(
+ %m = call i8* @malloc(i32 24)
+ tail call void @f() [ "deopt"(i8* %m) ]
+ store i8 -19, i8* %m
+ ret void
+
+; CHECK: tail call void @f() [ "deopt"(i8* %m) ]
+; CHECK-NEXT ret void
+}
+
+define i8* @test_3() {
+; Since the deopt operand bundle does not escape %m (see caveat below), @f
+; cannot observe the stores to %m
+
+; CHECK-LABEL: @test_3(
+ %m = call i8* @malloc(i32 24)
+ tail call void @f() [ "deopt"(i8* %m) ]
+ store i8 -19, i8* %m
+ tail call void @f()
+ store i8 101, i8* %m
+ ret i8* %m
+}
+
+
+; Caveat: technically, %m can only escape if the calling function is deoptimized
+; at the call site (i.e. the call returns to the "deopt" continuation). Since
+; the calling function body will be invalidated in that case, the calling
+; function can be optimized under the assumption that %m does not escape.
diff --git a/test/Feature/OperandBundles/early-cse.ll b/test/Feature/OperandBundles/early-cse.ll
new file mode 100644
index 000000000000..fc201479d8ce
--- /dev/null
+++ b/test/Feature/OperandBundles/early-cse.ll
@@ -0,0 +1,89 @@
+; RUN: opt -S -early-cse < %s | FileCheck %s
+
+; While it is normally okay to do memory optimizations over calls to
+; @readonly_function and @readnone_function, we cannot do that if
+; they're carrying unknown operand bundles since the presence of
+; unknown operand bundles implies arbitrary memory effects.
+
+declare void @readonly_function() readonly nounwind
+declare void @readnone_function() readnone nounwind
+
+define i32 @test0(i32* %x) {
+; CHECK-LABEL: @test0(
+ entry:
+ store i32 100, i32* %x
+; CHECK: store i32 100, i32* %x
+ call void @readonly_function() [ "tag"() ]
+; CHECK: call void @readonly_function()
+
+ %v = load i32, i32* %x
+; CHECK: %v = load i32, i32* %x
+; CHECK: ret i32 %v
+ ret i32 %v
+}
+
+define i32 @test1(i32* %x) {
+; CHECK: @test1(
+ entry:
+ store i32 100, i32* %x
+; CHECK: store i32 100, i32* %x
+ call void @readonly_function() readonly [ "tag"() ]
+; CHECK-NOT: call void @readonly_function
+ %v = load i32, i32* %x
+ ret i32 %v
+; CHECK: ret i32 100
+}
+
+define i32 @test3(i32* %x) {
+; CHECK-LABEL: @test3(
+ entry:
+ store i32 100, i32* %x
+; CHECK: store i32 100, i32* %x
+ call void @readonly_function()
+; CHECK-NOT: call void @readonly_function
+ %v = load i32, i32* %x
+ ret i32 %v
+; CHECK: ret i32 100
+}
+
+define void @test4(i32* %x) {
+; CHECK-LABEL: @test4(
+ entry:
+ store i32 100, i32* %x
+; CHECK: store i32 100, i32* %x
+ call void @readnone_function() [ "tag"() ]
+; CHECK: call void @readnone_function
+ store i32 200, i32* %x
+; CHECK: store i32 200, i32* %x
+ ret void
+}
+
+define void @test5(i32* %x) {
+; CHECK-LABEL: @test5(
+ entry:
+ store i32 100, i32* %x
+; CHECK-NOT: store i32 100, i32* %x
+; CHECK-NOT: call void @readnone_function
+ call void @readnone_function() readnone [ "tag"() ]
+ store i32 200, i32* %x
+; CHECK: store i32 200, i32* %x
+ ret void
+}
+
+define void @test6(i32* %x) {
+; The "deopt" operand bundle does not make the call to
+; @readonly_function read-write; and so the nounwind readonly call can
+; be deleted.
+
+; CHECK-LABEL: @test6(
+ entry:
+
+; CHECK-NEXT: entry:
+; CHECK-NEXT: store i32 200, i32* %x
+; CHECK-NEXT: ret void
+
+ store i32 100, i32* %x
+ call void @readonly_function() [ "deopt"() ]
+ store i32 200, i32* %x
+ ret void
+}
diff --git a/test/Feature/OperandBundles/function-attrs.ll b/test/Feature/OperandBundles/function-attrs.ll
new file mode 100644
index 000000000000..808f396fed8b
--- /dev/null
+++ b/test/Feature/OperandBundles/function-attrs.ll
@@ -0,0 +1,33 @@
+; RUN: opt -S -functionattrs < %s | FileCheck %s
+
+declare void @f_readonly() readonly
+declare void @f_readnone() readnone
+
+define void @test_0(i32* %x) {
+; FunctionAttrs must not infer readonly / readnone for %x
+
+; CHECK-LABEL: define void @test_0(i32* %x) {
+ entry:
+ ; CHECK: call void @f_readonly() [ "foo"(i32* %x) ]
+ call void @f_readonly() [ "foo"(i32* %x) ]
+ ret void
+}
+
+define void @test_1(i32* %x) {
+; FunctionAttrs must not infer readonly / readnone for %x
+
+; CHECK-LABEL: define void @test_1(i32* %x) {
+ entry:
+ ; CHECK: call void @f_readnone() [ "foo"(i32* %x) ]
+ call void @f_readnone() [ "foo"(i32* %x) ]
+ ret void
+}
+
+define void @test_2(i32* %x) {
+; The "deopt" operand bundle does not capture or write to %x.
+
+; CHECK-LABEL: define void @test_2(i32* nocapture readonly %x)
+ entry:
+ call void @f_readonly() [ "deopt"(i32* %x) ]
+ ret void
+}
diff --git a/test/Feature/OperandBundles/inliner-conservative.ll b/test/Feature/OperandBundles/inliner-conservative.ll
new file mode 100644
index 000000000000..d9f09f71d905
--- /dev/null
+++ b/test/Feature/OperandBundles/inliner-conservative.ll
@@ -0,0 +1,17 @@
+; RUN: opt -S -inline < %s | FileCheck %s
+
+; Check that the inliner does not inline through arbitrary unknown
+; operand bundles.
+
+define i32 @callee() {
+ entry:
+ ret i32 2
+}
+
+define i32 @caller() {
+; CHECK: @caller(
+ entry:
+; CHECK: call i32 @callee() [ "unknown"() ]
+ %x = call i32 @callee() [ "unknown"() ]
+ ret i32 %x
+}
diff --git a/test/Feature/OperandBundles/merge-func.ll b/test/Feature/OperandBundles/merge-func.ll
new file mode 100644
index 000000000000..1fa6eb093084
--- /dev/null
+++ b/test/Feature/OperandBundles/merge-func.ll
@@ -0,0 +1,64 @@
+; RUN: opt -S -mergefunc < %s | FileCheck %s
+
+; Minor note: functions need to be at least three instructions long
+; to be considered by -mergefunc.
+
+declare i32 @foo(...)
+
+define i32 @f() {
+; CHECK-LABEL: @f(
+ entry:
+ %v0 = call i32 (...) @foo(i32 10) [ "foo"(i32 20) ]
+ %v1 = call i32 (...) @foo(i32 10) [ "foo"(i32 20) ]
+ %v2 = call i32 (...) @foo(i32 10) [ "foo"(i32 20) ]
+
+; CHECK: %v0 = call i32 (...) @foo(i32 10) [ "foo"(i32 20) ]
+; CHECK: %v1 = call i32 (...) @foo(i32 10) [ "foo"(i32 20) ]
+; CHECK: %v2 = call i32 (...) @foo(i32 10) [ "foo"(i32 20) ]
+
+ ret i32 %v2
+}
+
+define i32 @g() {
+; CHECK-LABEL: @g(
+ entry:
+ %v0 = call i32 (...) @foo() [ "foo"(i32 10, i32 20) ]
+ %v1 = call i32 (...) @foo() [ "foo"(i32 10, i32 20) ]
+ %v2 = call i32 (...) @foo() [ "foo"(i32 10, i32 20) ]
+
+; CHECK: %v0 = call i32 (...) @foo() [ "foo"(i32 10, i32 20) ]
+; CHECK: %v1 = call i32 (...) @foo() [ "foo"(i32 10, i32 20) ]
+; CHECK: %v2 = call i32 (...) @foo() [ "foo"(i32 10, i32 20) ]
+
+ ret i32 %v2
+}
+
+define i32 @f.invoke() personality i8 3 {
+; CHECK-LABEL: @f.invoke(
+ entry:
+; CHECK: %v0 = invoke i32 (...) @foo(i32 10) [ "foo"(i32 20) ]
+ %v0 = invoke i32 (...) @foo(i32 10) [ "foo"(i32 20) ]
+ to label %normal unwind label %exception
+
+ normal:
+ ret i32 %v0
+
+ exception:
+ %cleanup = landingpad i8 cleanup
+ ret i32 0
+}
+
+define i32 @g.invoke() personality i8 3 {
+; CHECK-LABEL: @g.invoke(
+ entry:
+; CHECK: %v0 = invoke i32 (...) @foo() [ "foo"(i32 10, i32 20) ]
+ %v0 = invoke i32 (...) @foo() [ "foo"(i32 10, i32 20) ]
+ to label %normal unwind label %exception
+
+ normal:
+ ret i32 %v0
+
+ exception:
+ %cleanup = landingpad i8 cleanup
+ ret i32 0
+}
diff --git a/test/Feature/OperandBundles/special-state.ll b/test/Feature/OperandBundles/special-state.ll
new file mode 100644
index 000000000000..56e337cc16b3
--- /dev/null
+++ b/test/Feature/OperandBundles/special-state.ll
@@ -0,0 +1,21 @@
+; RUN: opt -S -early-cse < %s | FileCheck %s
+
+; This test isn't directly related to EarlyCSE or varargs. It is just
+; using these as a vehicle for testing the correctness of
+; haveSameSpecialState around operand bundles.
+
+declare i32 @foo(...)
+
+define i32 @f() {
+; CHECK-LABEL: @f(
+ entry:
+; CHECK: %v0 = call i32 (...) @foo(
+; CHECK: %v1 = call i32 (...) @foo(
+; CHECK: %v = add i32 %v0, %v1
+; CHECK: ret i32 %v
+
+ %v0 = call i32 (...) @foo(i32 10) readonly [ "foo"(i32 20) ]
+ %v1 = call i32 (...) @foo() readonly [ "foo"(i32 10, i32 20) ]
+ %v = add i32 %v0, %v1
+ ret i32 %v
+}
diff --git a/test/Feature/alias2.ll b/test/Feature/alias2.ll
index e461854e7514..ae5bc11d71a9 100644
--- a/test/Feature/alias2.ll
+++ b/test/Feature/alias2.ll
@@ -9,20 +9,20 @@
@v3 = global [2 x i16] zeroinitializer
; CHECK: @v3 = global [2 x i16] zeroinitializer
-@a1 = alias bitcast (i32* @v1 to i16*)
-; CHECK: @a1 = alias bitcast (i32* @v1 to i16*)
+@a1 = alias i16, bitcast (i32* @v1 to i16*)
+; CHECK: @a1 = alias i16, bitcast (i32* @v1 to i16*)
-@a2 = alias bitcast([1 x i32]* @v2 to i32*)
-; CHECK: @a2 = alias getelementptr inbounds ([1 x i32], [1 x i32]* @v2, i32 0, i32 0)
+@a2 = alias i32, bitcast([1 x i32]* @v2 to i32*)
+; CHECK: @a2 = alias i32, getelementptr inbounds ([1 x i32], [1 x i32]* @v2, i32 0, i32 0)
-@a3 = alias addrspacecast (i32* @v1 to i32 addrspace(2)*)
-; CHECK: @a3 = alias addrspacecast (i32* @v1 to i32 addrspace(2)*)
+@a3 = alias i32, addrspacecast (i32* @v1 to i32 addrspace(2)*)
+; CHECK: @a3 = alias i32, addrspacecast (i32* @v1 to i32 addrspace(2)*)
-@a4 = alias bitcast (i32* @v1 to i16*)
-; CHECK: @a4 = alias bitcast (i32* @v1 to i16*)
+@a4 = alias i16, bitcast (i32* @v1 to i16*)
+; CHECK: @a4 = alias i16, bitcast (i32* @v1 to i16*)
-@a5 = thread_local(localdynamic) alias i32* @v1
-; CHECK: @a5 = thread_local(localdynamic) alias i32* @v1
+@a5 = thread_local(localdynamic) alias i32, i32* @v1
+; CHECK: @a5 = thread_local(localdynamic) alias i32, i32* @v1
-@a6 = alias getelementptr ([2 x i16], [2 x i16]* @v3, i32 1, i32 1)
-; CHECK: @a6 = alias getelementptr ([2 x i16], [2 x i16]* @v3, i32 1, i32 1)
+@a6 = alias i16, getelementptr ([2 x i16], [2 x i16]* @v3, i32 1, i32 1)
+; CHECK: @a6 = alias i16, getelementptr ([2 x i16], [2 x i16]* @v3, i32 1, i32 1)
diff --git a/test/Feature/aliases.ll b/test/Feature/aliases.ll
index b3b9ceba527b..a8c95e9fd0c3 100644
--- a/test/Feature/aliases.ll
+++ b/test/Feature/aliases.ll
@@ -5,28 +5,28 @@
@llvm.used = appending global [1 x i8*] [i8* bitcast (i32* @foo1 to i8*)], section "llvm.metadata"
@bar = global i32 0
-@foo1 = alias i32* @bar
-@foo2 = alias i32* @bar
-@foo3 = alias i32* @foo2
-@foo4 = unnamed_addr alias i32* @foo2
+@foo1 = alias i32, i32* @bar
+@foo2 = alias i32, i32* @bar
+@foo3 = alias i32, i32* @foo2
+@foo4 = unnamed_addr alias i32, i32* @foo2
; Make sure the verifier does not complain about references to a global
; declaration from an initializer.
@decl = external global i32
@ptr = global i32* @decl
-@ptr_a = alias i32** @ptr
+@ptr_a = alias i32*, i32** @ptr
%FunTy = type i32()
define i32 @foo_f() {
ret i32 0
}
-@bar_f = weak_odr alias %FunTy* @foo_f
-@bar_ff = alias i32()* @bar_f
+@bar_f = weak_odr alias %FunTy, %FunTy* @foo_f
+@bar_ff = alias i32(), i32()* @bar_f
-@bar_i = internal alias i32* @bar
+@bar_i = internal alias i32, i32* @bar
-@A = alias bitcast (i32* @bar to i64*)
+@A = alias i64, bitcast (i32* @bar to i64*)
define i32 @test() {
entry:
diff --git a/test/Feature/callingconventions.ll b/test/Feature/callingconventions.ll
index 9aafb36c7573..ac4c5090a51d 100644
--- a/test/Feature/callingconventions.ll
+++ b/test/Feature/callingconventions.ll
@@ -59,4 +59,11 @@ define void @ghc_caller() {
ret void
}
+declare hhvm_ccc void @hhvm_c_callee()
+
+define hhvmcc void @hhvm_caller() {
+ call hhvm_ccc void @hhvm_c_callee()
+ ret void
+}
+
declare i32 @__gxx_personality_v0(...)
diff --git a/test/Feature/comdat.ll b/test/Feature/comdat.ll
index c2a9d6396293..b0286c06ea0f 100644
--- a/test/Feature/comdat.ll
+++ b/test/Feature/comdat.ll
@@ -9,8 +9,8 @@ $f2 = comdat any
@v = global i32 0, comdat($f)
; CHECK: @v = global i32 0, comdat($f)
-@a = alias i32* @v
-; CHECK: @a = alias i32* @v{{$}}
+@a = alias i32, i32* @v
+; CHECK: @a = alias i32, i32* @v{{$}}
define void @f() comdat($f) {
ret void
diff --git a/test/Feature/exception.ll b/test/Feature/exception.ll
index 7568ecfa5f75..2634692f4252 100644
--- a/test/Feature/exception.ll
+++ b/test/Feature/exception.ll
@@ -25,3 +25,112 @@ lpad: ; preds = %entry
declare void @_Z3quxv() optsize
declare i32 @__gxx_personality_v0(...)
+
+define void @cleanupret0() personality i32 (...)* @__gxx_personality_v0 {
+entry:
+ invoke void @_Z3quxv() optsize
+ to label %exit unwind label %pad
+pad:
+ %cp = cleanuppad within none [i7 4]
+ cleanupret from %cp unwind to caller
+exit:
+ ret void
+}
+
+; forward ref by name
+define void @cleanupret1() personality i32 (...)* @__gxx_personality_v0 {
+entry:
+ invoke void @_Z3quxv() optsize
+ to label %exit unwind label %pad
+cleanup:
+ cleanupret from %cp unwind label %pad
+pad:
+ %cp = cleanuppad within none []
+ br label %cleanup
+exit:
+ ret void
+}
+
+; forward ref by ID
+define void @cleanupret2() personality i32 (...)* @__gxx_personality_v0 {
+entry:
+ invoke void @_Z3quxv() optsize
+ to label %exit unwind label %pad
+cleanup:
+ cleanupret from %0 unwind label %pad
+pad:
+ %0 = cleanuppad within none []
+ br label %cleanup
+exit:
+ ret void
+}
+
+define void @catchret0() personality i32 (...)* @__gxx_personality_v0 {
+entry:
+ invoke void @_Z3quxv() optsize
+ to label %exit unwind label %pad
+pad:
+ %cs1 = catchswitch within none [label %catch] unwind to caller
+catch:
+ %cp = catchpad within %cs1 [i7 4]
+ catchret from %cp to label %exit
+exit:
+ ret void
+}
+
+; forward ref by name
+define void @catchret1() personality i32 (...)* @__gxx_personality_v0 {
+entry:
+ invoke void @_Z3quxv() optsize
+ to label %exit unwind label %pad
+catchret:
+ catchret from %cp to label %exit
+pad:
+ %cs1 = catchswitch within none [label %catch] unwind to caller
+catch:
+ %cp = catchpad within %cs1 [i7 4]
+ br label %catchret
+exit:
+ ret void
+}
+
+; forward ref by ID
+define void @catchret2() personality i32 (...)* @__gxx_personality_v0 {
+entry:
+ invoke void @_Z3quxv() optsize
+ to label %exit unwind label %pad
+catchret:
+ catchret from %0 to label %exit
+pad:
+ %cs1 = catchswitch within none [label %catch] unwind to caller
+catch:
+ %0 = catchpad within %cs1 [i7 4]
+ br label %catchret
+exit:
+ ret void
+}
+
+define i8 @catchpad() personality i32 (...)* @__gxx_personality_v0 {
+entry:
+ invoke void @_Z3quxv() optsize
+ to label %exit unwind label %bb2
+bb2:
+ %cs1 = catchswitch within none [label %catch] unwind to caller
+catch:
+ catchpad within %cs1 [i7 4]
+ br label %exit
+exit:
+ ret i8 0
+}
+
+define void @cleanuppad() personality i32 (...)* @__gxx_personality_v0 {
+entry:
+ br label %try.cont
+
+try.cont:
+ invoke void @_Z3quxv() optsize
+ to label %try.cont unwind label %bb
+bb:
+ cleanuppad within none [i7 4]
+ ret void
+}
diff --git a/test/Feature/optnone-llc.ll b/test/Feature/optnone-llc.ll
index b848b19d528b..94f61efea4aa 100644
--- a/test/Feature/optnone-llc.ll
+++ b/test/Feature/optnone-llc.ll
@@ -3,11 +3,13 @@
; RUN: llc -O2 -debug %s -o /dev/null 2>&1 | FileCheck %s --check-prefix=LLC-Ox
; RUN: llc -O3 -debug %s -o /dev/null 2>&1 | FileCheck %s --check-prefix=LLC-Ox
; RUN: llc -misched-postra -debug %s -o /dev/null 2>&1 | FileCheck %s --check-prefix=LLC-MORE
+; RUN: llc -O1 -debug-only=isel %s -o /dev/null 2>&1 | FileCheck %s --check-prefix=FAST
+; RUN: llc -O1 -debug-only=isel -fast-isel=false %s -o /dev/null 2>&1 | FileCheck %s --check-prefix=NOFAST
-; REQUIRES: asserts
+; REQUIRES: asserts, default_triple
; This test verifies that we don't run Machine Function optimizations
-; on optnone functions.
+; on optnone functions, and that we can turn off FastISel.
; Function Attrs: noinline optnone
define i32 @_Z3fooi(i32 %x) #0 {
@@ -52,3 +54,7 @@ attributes #0 = { optnone noinline }
; Alternate post-RA scheduler.
; LLC-MORE: Skipping pass 'PostRA Machine Instruction Scheduler'
+
+; Selectively disable FastISel for optnone functions.
+; FAST: FastISel is enabled
+; NOFAST: FastISel is disabled