--- /dev/null
+; RUN: llvm-reduce --abort-on-invalid-reduction --delta-passes=instructions --test FileCheck --test-arg --check-prefixes=CHECK,INTERESTING --test-arg %s --test-arg --input-file %s -o %t
+; RUN: FileCheck -check-prefixes=CHECK,RESULT %s < %t
+
+; Make sure verifier errors aren't produced from trying to delete
+; swifterror instructions.
+
+%swift_error = type { i64, i8 }
+
+declare float @foo(ptr swifterror %error_ptr_ref)
+
+; CHECK-LABEL: define float @caller(
+; INTERESTING: call float @foo(
+
+; RESULT: %error_ptr_ref = alloca swifterror ptr, align 8
+; RESULT-NEXT: %call = call float @foo(ptr swifterror %error_ptr_ref)
+; RESULT-NEXT: ret float
+define float @caller(ptr %error_ref) {
+entry:
+ %error_ptr_ref = alloca swifterror ptr
+ store ptr null, ptr %error_ptr_ref
+ %call = call float @foo(ptr swifterror %error_ptr_ref)
+ %error_from_foo = load ptr, ptr %error_ptr_ref
+ %had_error_from_foo = icmp ne ptr %error_from_foo, null
+ %v1 = getelementptr inbounds %swift_error, ptr %error_from_foo, i64 0, i32 1
+ %t = load i8, ptr %v1
+ store i8 %t, ptr %error_ref
+ ret float 1.0
+}
--- /dev/null
+; RUN: llvm-reduce --abort-on-invalid-reduction --delta-passes=instructions --test FileCheck --test-arg --check-prefixes=CHECK,INTERESTING --test-arg %s --test-arg --input-file %s -o %t
+; RUN: FileCheck -check-prefixes=CHECK,RESULT %s < %t
+
+%Foo = type { i32, i32 }
+
+declare token @llvm.call.preallocated.setup(i32)
+declare ptr @llvm.call.preallocated.arg(token, i32)
+declare void @init(ptr)
+declare void @foo_p(ptr preallocated(%Foo))
+
+; CHECK-LABEL: define void @preallocated_with_init() {
+; INTERESTING: call void @foo_p
+
+; RESULT: %t = call token @llvm.call.preallocated.setup(i32 1)
+; RESULT-NEXT: call void @foo_p(ptr preallocated(%Foo) null) [ "preallocated"(token %t) ]
+; RESULT-NEXT: ret void
+define void @preallocated_with_init() {
+ %t = call token @llvm.call.preallocated.setup(i32 1)
+ %a = call ptr @llvm.call.preallocated.arg(token %t, i32 0) preallocated(%Foo)
+ call void @init(ptr %a)
+ call void @foo_p(ptr preallocated(%Foo) %a) ["preallocated"(token %t)]
+ ret void
+}
--- /dev/null
+; RUN: llvm-reduce --abort-on-invalid-reduction --delta-passes=instructions --test FileCheck --test-arg --check-prefixes=CHECK,INTERESTING --test-arg %s --test-arg --input-file %s -o %t
+; RUN: FileCheck -check-prefixes=CHECK,RESULT %s < %t
+
+; CHECK-LABEL: define void @tokens(
+; INTERESTING: store i32 0
+; INTERESTING: call void @llvm.token.consumer
+
+; RESULT: %token = call token @llvm.token.producer()
+; RESULT-NEXT: store i32 0, ptr %ptr, align 4
+; RESULT-NEXT: call void @llvm.token.consumer(token %token)
+; RESULT-NEXT: ret void
+define void @tokens(ptr %ptr) {
+ %token = call token @llvm.token.producer()
+ store i32 0, ptr %ptr
+ call void @llvm.token.consumer(token %token)
+ store i32 1, ptr %ptr
+ ret void
+}
+
+declare token @llvm.token.producer()
+declare void @llvm.token.consumer(token)
-; RUN: llvm-reduce --delta-passes=instructions --test FileCheck --test-arg --check-prefixes=CHECK-ALL,CHECK-INTERESTINGNESS --test-arg %s --test-arg --input-file %s -o %t
+; RUN: llvm-reduce --abort-on-invalid-reduction --delta-passes=instructions --test FileCheck --test-arg --check-prefixes=CHECK-ALL,CHECK-INTERESTINGNESS --test-arg %s --test-arg --input-file %s -o %t
; RUN: FileCheck --check-prefixes=CHECK-ALL,CHECK-FINAL %s < %t
; CHECK-INTERESTINGNESS: define i32 @maybe_throwing_callee(
using namespace llvm;
+/// Filter out cases where deleting the instruction will likely cause the
+/// user/def of the instruction to fail the verifier.
+//
+// TODO: Technically the verifier only enforces preallocated token usage and
+// there is a none token.
+static bool shouldAlwaysKeep(const Instruction &I) {
+ return I.isEHPad() || I.getType()->isTokenTy() || I.isSwiftError();
+}
+
/// Removes out-of-chunk arguments from functions, and modifies their calls
/// accordingly. It also removes allocations of out-of-chunk arguments.
static void extractInstrFromModule(Oracle &O, Module &Program) {
// Removing the terminator would make the block invalid. Only iterate over
// instructions before the terminator.
InitInstToKeep.push_back(BB.getTerminator());
- for (auto &Inst : make_range(BB.begin(), std::prev(BB.end())))
- if (O.shouldKeep())
+ for (auto &Inst : make_range(BB.begin(), std::prev(BB.end()))) {
+ if (shouldAlwaysKeep(Inst) || O.shouldKeep())
InitInstToKeep.push_back(&Inst);
+ }
}
// We create a vector first, then convert it to a set, so that we don't have