Skip to content

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

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
132 changes: 124 additions & 8 deletions llvm/test/tools/llvm-reduce/reduce-conditionals.ll
Original file line number Diff line number Diff line change
@@ -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:
Expand All @@ -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
Expand All @@ -36,4 +121,35 @@ bb2:

bb3:
ret void

dead_code:
store i32 %arg, ptr null
br label %dead_code
}

@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
}
19 changes: 13 additions & 6 deletions llvm/tools/llvm-reduce/deltas/ReduceUsingSimplifyCFG.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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 ||
Expand All @@ -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,
Expand Down
39 changes: 39 additions & 0 deletions llvm/tools/llvm-reduce/deltas/Utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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();
}
6 changes: 6 additions & 0 deletions llvm/tools/llvm-reduce/deltas/Utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include "llvm/Support/CommandLine.h"

namespace llvm {
class BasicBlock;
class Function;
class Type;
class Value;
Expand All @@ -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