[llvm] 3a0c95f - llvm-reduce: Fix introducing unreachable code in simplify conditionals (#133842)

via llvm-commits llvm-commits at lists.llvm.org
Mon Apr 7 18:51:23 PDT 2025


Author: Matt Arsenault
Date: 2025-04-08T08:51:20+07:00
New Revision: 3a0c95fb506301fdd083b6e5dff0a0c88da4a665

URL: https://github.com/llvm/llvm-project/commit/3a0c95fb506301fdd083b6e5dff0a0c88da4a665
DIFF: https://github.com/llvm/llvm-project/commit/3a0c95fb506301fdd083b6e5dff0a0c88da4a665.diff

LOG: llvm-reduce: Fix introducing unreachable code in simplify conditionals (#133842)

After replacing the branch condition, this was calling simplifyCFG to
perform the cleanups of the branch. This is far too heavy of a hammer.
We do not want all of the extra optimizations in simplifyCFG, and
this could also leave behind dead code. Instead, minimally fold the
terminator and try to delete the newly dead code.

This is pretty much a direct copy of what bugpoint does.

Added: 
    

Modified: 
    llvm/test/tools/llvm-reduce/reduce-conditionals.ll
    llvm/tools/llvm-reduce/deltas/ReduceUsingSimplifyCFG.cpp
    llvm/tools/llvm-reduce/deltas/Utils.cpp
    llvm/tools/llvm-reduce/deltas/Utils.h

Removed: 
    


################################################################################
diff  --git a/llvm/test/tools/llvm-reduce/reduce-conditionals.ll b/llvm/test/tools/llvm-reduce/reduce-conditionals.ll
index a832673d7350b..e1a9f3ae13944 100644
--- a/llvm/test/tools/llvm-reduce/reduce-conditionals.ll
+++ b/llvm/test/tools/llvm-reduce/reduce-conditionals.ll
@@ -1,10 +1,12 @@
-; RUN: llvm-reduce --abort-on-invalid-reduction --delta-passes=simplify-conditionals-true --test FileCheck --test-arg --check-prefixes=CHECK-INTERESTINGNESS --test-arg %s --test-arg --input-file %s -o %t
-; RUN: FileCheck --check-prefixes=RESULT-TRUE %s < %t
+; RUN: llvm-reduce --abort-on-invalid-reduction --delta-passes=simplify-conditionals-true --test FileCheck --test-arg --check-prefixes=CHECK-INTERESTINGNESS,CHECK --test-arg %s --test-arg --input-file %s -o %t
+; RUN: FileCheck --check-prefixes=RESULT-TRUE,RESULT,CHECK %s < %t
 
-; RUN: llvm-reduce --abort-on-invalid-reduction --delta-passes=simplify-conditionals-false --test FileCheck --test-arg --check-prefixes=CHECK-INTERESTINGNESS --test-arg %s --test-arg --input-file %s -o %t
-; RUN: FileCheck --check-prefixes=RESULT-FALSE %s < %t
+; RUN: llvm-reduce --abort-on-invalid-reduction --delta-passes=simplify-conditionals-false --test FileCheck --test-arg --check-prefixes=CHECK-INTERESTINGNESS,CHECK --test-arg %s --test-arg --input-file %s -o %t
+; RUN: FileCheck --check-prefixes=RESULT-FALSE,RESULT,CHECK %s < %t
 
-; CHECK-INTERESTINGNESS-LABEL: @func(
+; Make sure there is no unreachable code introduced by the reduction
+
+; CHECK-LABEL: @func_simplifies_true(
 ; CHECK-INTERESTINGNESS: store i32 1,
 
 ; RESULT-TRUE: bb0:
@@ -13,15 +15,98 @@
 ; RESULT-TRUE-NEXT: br label %bb2
 ; RESULT-TRUE-NOT: bb1
 
+; RESULT-FALSE: bb0:
+; RESULT-FALSE-NEXT: store i32 0, ptr null, align 4
+; RESULT-FALSE-NEXT: br i1 %cond0, label %bb1, label %bb2
+
+; RESULT-FALSE: bb1:                                              ; preds = %bb0
+; RESULT-FALSE-NEXT: store i32 1, ptr null, align 4
+; RESULT-FALSE-NEXT: br label %bb3
+
+; RESULT-FALSE: bb2:                                              ; preds = %bb0
+; RESULT-FALSE-NEXT: store i32 2, ptr null, align 4
+; RESULT-FALSE-NEXT: br label %bb3
+
+; RESULT-FALSE: bb3:                                              ; preds = %bb1, %bb2
+; RESULT-FALSE-NEXT: ret void
+define void @func_simplifies_true(i1 %cond0, i1 %cond1) {
+bb0:
+  store i32 0, ptr null
+  br i1 %cond0, label %bb1, label %bb2
+
+bb1:
+  store i32 1, ptr null
+  br i1 %cond1, label %bb2, label %bb3
+
+bb2:
+  store i32 2, ptr null
+  br label %bb3
+
+bb3:
+  ret void
+}
+
+; CHECK-LABEL: @func_simplifies_false(
+; CHECK-INTERESTINGNESS: store i32 0,
+
+; RESULT-TRUE: bb0:
+; RESULT-TRUE: store i32 0, ptr null, align 4
+; RESULT-TRUE-NEXT: store i32 1, ptr null, align 4
+; RESULT-TRUE-NEXT: br label %bb2
+; RESULT-TRUE-NOT: bb1
+
 
 ; RESULT-FALSE: bb0:
 ; RESULT-FALSE: store i32 0, ptr null, align 4
 ; RESULT-FALSE-NEXT: br label %bb2
 
-; RESULT-FALSE: bb1: ; No predecessors!
-; RESULT-FALSE-NEXT: store i32 1, ptr null, align 4
+; RESULT-FALSE: bb2: ; preds = %bb0
+; RESULT-FALSE-NEXT: store i32 2, ptr null, align 4
 ; RESULT-FALSE-NEXT: br label %bb3
-define void @func(i1 %cond0, i1 %cond1) {
+
+; RESULT-FALSE: bb3: ; preds = %bb2
+; RESULT-FALSE-NEXT: ret void
+define void @func_simplifies_false(i1 %cond0, i1 %cond1) {
+bb0:
+  store i32 0, ptr null
+  br i1 %cond0, label %bb1, label %bb2
+
+bb1:
+  store i32 1, ptr null
+  br i1 %cond1, label %bb2, label %bb3
+
+bb2:
+  store i32 2, ptr null
+  br label %bb3
+
+bb3:
+  ret void
+}
+
+; Make sure we don't break the reduction in the other functions by
+; having something interesting in unrelated unreachable code.
+
+; CHECK-LABEL: @func_simplifies_true_with_interesting_unreachable_code(
+; CHECK-INTERESTINGNESS: store i32 0,
+; CHECK-INTERESTINGNESS: store i32 %arg,
+
+
+; RESULT: bb0:
+; RESULT-NEXT: store i32 0
+; RESULT-NEXT: br i1 %cond0, label %bb1, label %bb2
+
+; RESULT: bb1:
+; RESULT-NEXT: store i32 1
+; RESULT-NEXT: br i1 %cond1, label %bb2, label %bb3
+
+; RESULT: bb2:
+; RESULT-NEXT: store i32 2
+; RESULT-NEXT: br label %bb3
+
+; RESULT: dead_code: ; preds = %dead_code
+; RESULT-NEXT: store i32 %arg,
+; RESULT-NEXT: br label %dead_code
+define void @func_simplifies_true_with_interesting_unreachable_code(i1 %cond0, i1 %cond1, i32 %arg) {
 bb0:
   store i32 0, ptr null
   br i1 %cond0, label %bb1, label %bb2
@@ -36,4 +121,35 @@ bb2:
 
 bb3:
   ret void
+
+dead_code:
+  store i32 %arg, ptr null
+  br label %dead_code
+}
+
+ at block_address_user = constant [1 x ptr] [ptr blockaddress(@will_be_unreachable_blockaddress_use, %will_be_unreachable)]
+
+; CHECK-LABEL: @will_be_unreachable_blockaddress_use(
+; CHECK-INTERESTINGNESS: inttoptr
+
+; RESULT-FALSE: entry:
+; RESULT-FALSE-NEXT: %i2p = inttoptr i64 %int to ptr
+; RESULT-FALSE-NEXT: br label %exit
+
+; RESULT-FALSE: exit: ; preds = %entry
+; RESULT-FALSE-NEXT: ret i1 false
+define i1 @will_be_unreachable_blockaddress_use(i1 %cond, i64 %int) {
+entry:
+  %i2p = inttoptr i64 %int to ptr
+  br i1 %cond, label %will_be_unreachable, label %exit
+
+will_be_unreachable:
+  %load = load ptr, ptr %i2p, align 8
+  br label %for.body
+
+for.body:
+  br label %for.body
+
+exit:
+  ret i1 false
 }

diff  --git a/llvm/tools/llvm-reduce/deltas/ReduceUsingSimplifyCFG.cpp b/llvm/tools/llvm-reduce/deltas/ReduceUsingSimplifyCFG.cpp
index 3d6b35d1895e7..a982524af4cf6 100644
--- a/llvm/tools/llvm-reduce/deltas/ReduceUsingSimplifyCFG.cpp
+++ b/llvm/tools/llvm-reduce/deltas/ReduceUsingSimplifyCFG.cpp
@@ -12,6 +12,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "ReduceUsingSimplifyCFG.h"
+#include "Utils.h"
 #include "llvm/Analysis/TargetTransformInfo.h"
 #include "llvm/IR/Constants.h"
 #include "llvm/IR/Instructions.h"
@@ -35,13 +36,17 @@ void llvm::reduceUsingSimplifyCFGDeltaPass(Oracle &O,
 static void reduceConditionals(Oracle &O, ReducerWorkItem &WorkItem,
                                bool Direction) {
   Module &M = WorkItem.getModule();
-  SmallVector<BasicBlock *, 16> ToSimplify;
 
   LLVMContext &Ctx = M.getContext();
   ConstantInt *ConstValToSet =
       Direction ? ConstantInt::getTrue(Ctx) : ConstantInt::getFalse(Ctx);
 
-  for (auto &F : M) {
+  for (Function &F : M) {
+    if (F.isDeclaration())
+      continue;
+
+    SmallVector<BasicBlock *, 16> ToSimplify;
+
     for (auto &BB : F) {
       auto *BR = dyn_cast<BranchInst>(BB.getTerminator());
       if (!BR || !BR->isConditional() || BR->getCondition() == ConstValToSet ||
@@ -51,11 +56,13 @@ static void reduceConditionals(Oracle &O, ReducerWorkItem &WorkItem,
       BR->setCondition(ConstValToSet);
       ToSimplify.push_back(&BB);
     }
-  }
 
-  TargetTransformInfo TTI(M.getDataLayout());
-  for (auto *BB : ToSimplify)
-    simplifyCFG(BB, TTI);
+    if (!ToSimplify.empty()) {
+      // TODO: Should probably leave MergeBlockIntoPredecessor for a separate
+      // reduction
+      simpleSimplifyCFG(F, ToSimplify);
+    }
+  }
 }
 
 void llvm::reduceConditionalsTrueDeltaPass(Oracle &O,

diff  --git a/llvm/tools/llvm-reduce/deltas/Utils.cpp b/llvm/tools/llvm-reduce/deltas/Utils.cpp
index 92a44921a7cfb..a980a0f9fad2f 100644
--- a/llvm/tools/llvm-reduce/deltas/Utils.cpp
+++ b/llvm/tools/llvm-reduce/deltas/Utils.cpp
@@ -14,6 +14,8 @@
 #include "llvm/IR/Constants.h"
 #include "llvm/IR/GlobalAlias.h"
 #include "llvm/IR/GlobalIFunc.h"
+#include "llvm/Transforms/Utils/BasicBlockUtils.h"
+#include "llvm/Transforms/Utils/Local.h"
 
 using namespace llvm;
 
@@ -47,3 +49,40 @@ bool llvm::hasAliasOrBlockAddressUse(Function &F) {
     return isa<GlobalAlias, GlobalIFunc, BlockAddress>(U);
   });
 }
+
+void llvm::simpleSimplifyCFG(Function &F, ArrayRef<BasicBlock *> BBs,
+                             bool FoldBlockIntoPredecessor) {
+
+  for (BasicBlock *BB : BBs) {
+    ConstantFoldTerminator(BB);
+    if (FoldBlockIntoPredecessor)
+      MergeBlockIntoPredecessor(BB);
+  }
+
+  // Remove unreachable blocks
+  //
+  // removeUnreachableBlocks can't be used here, it will turn various undefined
+  // behavior into unreachables, but llvm-reduce was the thing that generated
+  // the undefined behavior, and we don't want it to kill the entire program.
+  SmallPtrSet<BasicBlock *, 16> Visited(llvm::from_range,
+                                        depth_first(&F.getEntryBlock()));
+
+  SmallVector<BasicBlock *, 16> Unreachable;
+  for (BasicBlock &BB : F) {
+    if (!Visited.count(&BB))
+      Unreachable.push_back(&BB);
+  }
+
+  // The dead BB's may be in a dead cycle or otherwise have references to each
+  // other.  Because of this, we have to drop all references first, then delete
+  // them all at once.
+  for (BasicBlock *BB : Unreachable) {
+    for (BasicBlock *Successor : successors(&*BB))
+      if (Visited.count(Successor))
+        Successor->removePredecessor(&*BB);
+    BB->dropAllReferences();
+  }
+
+  for (BasicBlock *BB : Unreachable)
+    BB->eraseFromParent();
+}

diff  --git a/llvm/tools/llvm-reduce/deltas/Utils.h b/llvm/tools/llvm-reduce/deltas/Utils.h
index 8cb4a3ebaf644..940030cca02f8 100644
--- a/llvm/tools/llvm-reduce/deltas/Utils.h
+++ b/llvm/tools/llvm-reduce/deltas/Utils.h
@@ -16,6 +16,7 @@
 #include "llvm/Support/CommandLine.h"
 
 namespace llvm {
+class BasicBlock;
 class Function;
 class Type;
 class Value;
@@ -26,6 +27,11 @@ Value *getDefaultValue(Type *T);
 bool hasAliasUse(Function &F);
 bool hasAliasOrBlockAddressUse(Function &F);
 
+// Constant fold terminators in \p and minimally prune unreachable code from the
+// function.
+void simpleSimplifyCFG(Function &F, ArrayRef<BasicBlock *> BBs,
+                       bool FoldBlockIntoPredecessor = true);
+
 } // namespace llvm
 
 #endif


        


More information about the llvm-commits mailing list