[GlobalOpt] Fix assertion failure during instruction deletion
authorNikita Popov <nikita.ppv@gmail.com>
Thu, 2 Dec 2021 10:55:56 +0000 (11:55 +0100)
committerNikita Popov <nikita.ppv@gmail.com>
Thu, 2 Dec 2021 10:58:39 +0000 (11:58 +0100)
This fixes the assertion failure reported in https://reviews.llvm.org/D114889#3166417,
by making RecursivelyDeleteTriviallyDeadInstructionsPermissive()
more permissive. As the function accepts a WeakTrackingVH, even if
originally only Instructions were inserted, we may end up with
different Value types after a RAUW operation. As such, we should
not assume that the vector only contains instructions.

Notably this matches the behavior of the
RecursivelyDeleteTriviallyDeadInstructions() function variant which
accepts a single value rather than vector.

llvm/lib/Transforms/Utils/Local.cpp
llvm/test/Transforms/GlobalOpt/recursively-delete-dead-inst-assertion.ll [new file with mode: 0644]

index 99eed9e065f874439338022923a5a72f167e25d5..ec926b1f5a94ac22a3cbdc9d8e33a362089f6283 100644 (file)
@@ -529,8 +529,8 @@ bool llvm::RecursivelyDeleteTriviallyDeadInstructionsPermissive(
     std::function<void(Value *)> AboutToDeleteCallback) {
   unsigned S = 0, E = DeadInsts.size(), Alive = 0;
   for (; S != E; ++S) {
-    auto *I = cast<Instruction>(DeadInsts[S]);
-    if (!isInstructionTriviallyDead(I)) {
+    auto *I = dyn_cast<Instruction>(DeadInsts[S]);
+    if (!I || !isInstructionTriviallyDead(I)) {
       DeadInsts[S] = nullptr;
       ++Alive;
     }
diff --git a/llvm/test/Transforms/GlobalOpt/recursively-delete-dead-inst-assertion.ll b/llvm/test/Transforms/GlobalOpt/recursively-delete-dead-inst-assertion.ll
new file mode 100644 (file)
index 0000000..6378279
--- /dev/null
@@ -0,0 +1,20 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt -S -globalopt < %s | FileCheck %s
+
+; In this case an instruction queued for recursive deletion gets RAUWd with
+; a constant in the meantime. Make sure this does not cause an assertion
+; failure.
+
+@a = internal global i32** null
+@b = internal global i32*** @a
+
+define void @test() {
+; CHECK-LABEL: @test(
+; CHECK-NEXT:    ret void
+;
+  %v1 = load i32***, i32**** @b
+  %v2 = load i32**, i32*** %v1
+  store i32** %v2, i32*** @a
+  ret void
+}
+