llvm-reduce: Fix invalid reductions for exceptions, tokens and swifterror
authorMatt Arsenault <Matthew.Arsenault@amd.com>
Sun, 1 Jan 2023 23:07:07 +0000 (18:07 -0500)
committerMatt Arsenault <Matthew.Arsenault@amd.com>
Tue, 3 Jan 2023 22:03:20 +0000 (17:03 -0500)
Copies the same special cases that bugpoint uses. Technically the
token condition is stricter than what the verifier enforces.

Part 1 of #58815

llvm/test/tools/llvm-reduce/reduce-instructions-swifterror.ll [new file with mode: 0644]
llvm/test/tools/llvm-reduce/reduce-instructions-token-preallocated.ll [new file with mode: 0644]
llvm/test/tools/llvm-reduce/reduce-instructions-token.ll [new file with mode: 0644]
llvm/test/tools/llvm-reduce/remove-invoked-functions.ll
llvm/tools/llvm-reduce/deltas/ReduceInstructions.cpp

diff --git a/llvm/test/tools/llvm-reduce/reduce-instructions-swifterror.ll b/llvm/test/tools/llvm-reduce/reduce-instructions-swifterror.ll
new file mode 100644 (file)
index 0000000..f7d1ed4
--- /dev/null
@@ -0,0 +1,28 @@
+; 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
+}
diff --git a/llvm/test/tools/llvm-reduce/reduce-instructions-token-preallocated.ll b/llvm/test/tools/llvm-reduce/reduce-instructions-token-preallocated.ll
new file mode 100644 (file)
index 0000000..f8b9fe3
--- /dev/null
@@ -0,0 +1,23 @@
+; 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
+}
diff --git a/llvm/test/tools/llvm-reduce/reduce-instructions-token.ll b/llvm/test/tools/llvm-reduce/reduce-instructions-token.ll
new file mode 100644 (file)
index 0000000..8f177f1
--- /dev/null
@@ -0,0 +1,21 @@
+; 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)
index b18b47a..d30dc16 100644 (file)
@@ -1,4 +1,4 @@
-; 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(
index bdd227b..8dd9872 100644 (file)
 
 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) {
@@ -27,9 +36,10 @@ 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