Skip to content

Commit

Permalink
[SimplifyCFG] don't sink common insts too soon (PR34603)
Browse files Browse the repository at this point in the history
This should solve:
https://bugs.llvm.org/show_bug.cgi?id=34603
...by preventing SimplifyCFG from altering redundant instructions before early-cse has a chance to run.
It changes the default (canonical-forming) behavior of SimplifyCFG, so we're only doing the
sinking transform later in the optimization pipeline.

Differential Revision: https://reviews.llvm.org/D38566

llvm-svn: 320749
  • Loading branch information
rotateright committed Dec 14, 2017
1 parent 34ccadc commit 0ab0c1a
Show file tree
Hide file tree
Showing 15 changed files with 55 additions and 27 deletions.
2 changes: 1 addition & 1 deletion llvm/include/llvm/Transforms/Scalar.h
Expand Up @@ -267,7 +267,7 @@ FunctionPass *createJumpThreadingPass(int Threshold = -1);
//
FunctionPass *createCFGSimplificationPass(
unsigned Threshold = 1, bool ForwardSwitchCond = false,
bool ConvertSwitch = false, bool KeepLoops = true,
bool ConvertSwitch = false, bool KeepLoops = true, bool SinkCommon = false,
std::function<bool(const Function &)> Ftor = nullptr);

//===----------------------------------------------------------------------===//
Expand Down
3 changes: 2 additions & 1 deletion llvm/include/llvm/Transforms/Scalar/SimplifyCFG.h
Expand Up @@ -39,7 +39,8 @@ class SimplifyCFGPass : public PassInfoMixin<SimplifyCFGPass> {
: SimplifyCFGPass(SimplifyCFGOptions()
.forwardSwitchCondToPhi(false)
.convertSwitchToLookupTable(false)
.needCanonicalLoops(true)) {}
.needCanonicalLoops(true)
.sinkCommonInsts(false)) {}


/// Construct a pass with optional optimizations.
Expand Down
10 changes: 9 additions & 1 deletion llvm/include/llvm/Transforms/Utils/Local.h
Expand Up @@ -63,16 +63,20 @@ struct SimplifyCFGOptions {
bool ForwardSwitchCondToPhi;
bool ConvertSwitchToLookupTable;
bool NeedCanonicalLoop;
bool SinkCommonInsts;
AssumptionCache *AC;

SimplifyCFGOptions(unsigned BonusThreshold = 1,
bool ForwardSwitchCond = false,
bool SwitchToLookup = false, bool CanonicalLoops = true,
bool SinkCommon = false,
AssumptionCache *AssumpCache = nullptr)
: BonusInstThreshold(BonusThreshold),
ForwardSwitchCondToPhi(ForwardSwitchCond),
ConvertSwitchToLookupTable(SwitchToLookup),
NeedCanonicalLoop(CanonicalLoops), AC(AssumpCache) {}
NeedCanonicalLoop(CanonicalLoops),
SinkCommonInsts(SinkCommon),
AC(AssumpCache) {}

// Support 'builder' pattern to set members by name at construction time.
SimplifyCFGOptions &bonusInstThreshold(int I) {
Expand All @@ -91,6 +95,10 @@ struct SimplifyCFGOptions {
NeedCanonicalLoop = B;
return *this;
}
SimplifyCFGOptions &sinkCommonInsts(bool B) {
SinkCommonInsts = B;
return *this;
}
SimplifyCFGOptions &setAssumptionCache(AssumptionCache *Cache) {
AC = Cache;
return *this;
Expand Down
19 changes: 11 additions & 8 deletions llvm/lib/Passes/PassBuilder.cpp
Expand Up @@ -747,21 +747,24 @@ PassBuilder::buildModuleOptimizationPipeline(OptimizationLevel Level,
// Cleanup after the loop optimization passes.
OptimizePM.addPass(InstCombinePass());


// Now that we've formed fast to execute loop structures, we do further
// optimizations. These are run afterward as they might block doing complex
// analyses and transforms such as what are needed for loop vectorization.

// Optimize parallel scalar instruction chains into SIMD instructions.
OptimizePM.addPass(SLPVectorizerPass());

// Cleanup after all of the vectorizers. Simplification passes like CVP and
// Cleanup after loop vectorization, etc. Simplification passes like CVP and
// GVN, loop transforms, and others have already run, so it's now better to
// convert to more optimized IR using more aggressive simplify CFG options.
// The extra sinking transform can create larger basic blocks, so do this
// before SLP vectorization.
OptimizePM.addPass(SimplifyCFGPass(SimplifyCFGOptions().
forwardSwitchCondToPhi(true).
convertSwitchToLookupTable(true).
needCanonicalLoops(false)));
forwardSwitchCondToPhi(true).
convertSwitchToLookupTable(true).
needCanonicalLoops(false).
sinkCommonInsts(true)));

// Optimize parallel scalar instruction chains into SIMD instructions.
OptimizePM.addPass(SLPVectorizerPass());

OptimizePM.addPass(InstCombinePass());

// Unroll small loops to hide loop backedge latency and saturate any parallel
Expand Down
2 changes: 1 addition & 1 deletion llvm/lib/Target/AArch64/AArch64TargetMachine.cpp
Expand Up @@ -365,7 +365,7 @@ void AArch64PassConfig::addIRPasses() {
// determine whether it succeeded. We can exploit existing control-flow in
// ldrex/strex loops to simplify this, but it needs tidying up.
if (TM->getOptLevel() != CodeGenOpt::None && EnableAtomicTidy)
addPass(createCFGSimplificationPass(1, true, true, false));
addPass(createCFGSimplificationPass(1, true, true, false, true));

// Run LoopDataPrefetch
//
Expand Down
2 changes: 1 addition & 1 deletion llvm/lib/Target/ARM/ARMTargetMachine.cpp
Expand Up @@ -385,7 +385,7 @@ void ARMPassConfig::addIRPasses() {
// ldrex/strex loops to simplify this, but it needs tidying up.
if (TM->getOptLevel() != CodeGenOpt::None && EnableAtomicTidy)
addPass(createCFGSimplificationPass(
1, false, false, true, [this](const Function &F) {
1, false, false, true, true, [this](const Function &F) {
const auto &ST = this->TM->getSubtarget<ARMSubtarget>(F);
return ST.hasAnyDataBarrier() && !ST.isThumb1Only();
}));
Expand Down
10 changes: 7 additions & 3 deletions llvm/lib/Transforms/IPO/PassManagerBuilder.cpp
Expand Up @@ -630,6 +630,13 @@ void PassManagerBuilder::populateModulePassManager(
addInstructionCombiningPass(MPM);
}

// Cleanup after loop vectorization, etc. Simplification passes like CVP and
// GVN, loop transforms, and others have already run, so it's now better to
// convert to more optimized IR using more aggressive simplify CFG options.
// The extra sinking transform can create larger basic blocks, so do this
// before SLP vectorization.
MPM.add(createCFGSimplificationPass(1, true, true, false, true));

if (RunSLPAfterLoopVectorization && SLPVectorize) {
MPM.add(createSLPVectorizerPass()); // Vectorize parallel scalar chains.
if (OptLevel > 1 && ExtraVectorizerPasses) {
Expand All @@ -638,9 +645,6 @@ void PassManagerBuilder::populateModulePassManager(
}

addExtensionsToPM(EP_Peephole, MPM);
// Switches to lookup tables and other transforms that may not be considered
// canonical by other IR passes.
MPM.add(createCFGSimplificationPass(1, true, true, false));
addInstructionCombiningPass(MPM);

if (!DisableUnrollLoops) {
Expand Down
16 changes: 15 additions & 1 deletion llvm/lib/Transforms/Scalar/SimplifyCFGPass.cpp
Expand Up @@ -61,6 +61,11 @@ static cl::opt<bool> UserForwardSwitchCond(
"forward-switch-cond", cl::Hidden, cl::init(false),
cl::desc("Forward switch condition to phi ops (default = false)"));

static cl::opt<bool> UserSinkCommonInsts(
"sink-common-insts", cl::Hidden, cl::init(false),
cl::desc("Sink common instructions (default = false)"));


STATISTIC(NumSimpl, "Number of blocks simplified");

/// If we have more than one empty (other than phi node) return blocks,
Expand Down Expand Up @@ -205,6 +210,9 @@ SimplifyCFGPass::SimplifyCFGPass(const SimplifyCFGOptions &Opts) {
Options.NeedCanonicalLoop = UserKeepLoops.getNumOccurrences()
? UserKeepLoops
: Opts.NeedCanonicalLoop;
Options.SinkCommonInsts = UserSinkCommonInsts.getNumOccurrences()
? UserSinkCommonInsts
: Opts.SinkCommonInsts;
}

PreservedAnalyses SimplifyCFGPass::run(Function &F,
Expand All @@ -226,6 +234,7 @@ struct CFGSimplifyPass : public FunctionPass {

CFGSimplifyPass(unsigned Threshold = 1, bool ForwardSwitchCond = false,
bool ConvertSwitch = false, bool KeepLoops = true,
bool SinkCommon = false,
std::function<bool(const Function &)> Ftor = nullptr)
: FunctionPass(ID), PredicateFtor(std::move(Ftor)) {

Expand All @@ -246,6 +255,10 @@ struct CFGSimplifyPass : public FunctionPass {

Options.NeedCanonicalLoop =
UserKeepLoops.getNumOccurrences() ? UserKeepLoops : KeepLoops;

Options.SinkCommonInsts = UserSinkCommonInsts.getNumOccurrences()
? UserSinkCommonInsts
: SinkCommon;
}

bool runOnFunction(Function &F) override {
Expand Down Expand Up @@ -276,7 +289,8 @@ INITIALIZE_PASS_END(CFGSimplifyPass, "simplifycfg", "Simplify the CFG", false,
FunctionPass *
llvm::createCFGSimplificationPass(unsigned Threshold, bool ForwardSwitchCond,
bool ConvertSwitch, bool KeepLoops,
bool SinkCommon,
std::function<bool(const Function &)> Ftor) {
return new CFGSimplifyPass(Threshold, ForwardSwitchCond, ConvertSwitch,
KeepLoops, std::move(Ftor));
KeepLoops, SinkCommon, std::move(Ftor));
}
2 changes: 1 addition & 1 deletion llvm/lib/Transforms/Utils/SimplifyCFG.cpp
Expand Up @@ -5728,7 +5728,7 @@ bool SimplifyCFGOpt::SimplifyUncondBranch(BranchInst *BI,
BasicBlock *BB = BI->getParent();
BasicBlock *Succ = BI->getSuccessor(0);

if (SinkCommon && SinkThenElseCodeToEnd(BI))
if (SinkCommon && Options.SinkCommonInsts && SinkThenElseCodeToEnd(BI))
return true;

// If the Terminator is the only non-phi instruction, simplify the block.
Expand Down
2 changes: 1 addition & 1 deletion llvm/test/DebugInfo/Generic/simplifycfg_sink_last_inst.ll
@@ -1,4 +1,4 @@
; RUN: opt -simplifycfg -S < %s | FileCheck %s
; RUN: opt -simplifycfg -sink-common-insts -S < %s | FileCheck %s

target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"
Expand Down
2 changes: 1 addition & 1 deletion llvm/test/Other/new-pm-defaults.ll
Expand Up @@ -197,8 +197,8 @@
; CHECK-O-NEXT: Running pass: LoopLoadEliminationPass
; CHECK-O-NEXT: Running analysis: LoopAccessAnalysis
; CHECK-O-NEXT: Running pass: InstCombinePass
; CHECK-O-NEXT: Running pass: SLPVectorizerPass
; CHECK-O-NEXT: Running pass: SimplifyCFGPass
; CHECK-O-NEXT: Running pass: SLPVectorizerPass
; CHECK-O-NEXT: Running pass: InstCombinePass
; CHECK-O-NEXT: Running pass: LoopUnrollPass
; CHECK-O-NEXT: Running analysis: OuterAnalysisManagerProxy
Expand Down
2 changes: 1 addition & 1 deletion llvm/test/Other/new-pm-thinlto-defaults.ll
Expand Up @@ -185,8 +185,8 @@
; CHECK-POSTLINK-O-NEXT: Running pass: LoopLoadEliminationPass
; CHECK-POSTLINK-O-NEXT: Running analysis: LoopAccessAnalysis
; CHECK-POSTLINK-O-NEXT: Running pass: InstCombinePass
; CHECK-POSTLINK-O-NEXT: Running pass: SLPVectorizerPass
; CHECK-POSTLINK-O-NEXT: Running pass: SimplifyCFGPass
; CHECK-POSTLINK-O-NEXT: Running pass: SLPVectorizerPass
; CHECK-POSTLINK-O-NEXT: Running pass: InstCombinePass
; CHECK-POSTLINK-O-NEXT: Running pass: LoopUnrollPass
; CHECK-POSTLINK-O-NEXT: Running analysis: OuterAnalysisManagerProxy
Expand Down
6 changes: 2 additions & 4 deletions llvm/test/Transforms/PhaseOrdering/simplifycfg-options.ll
Expand Up @@ -76,10 +76,8 @@ define double @max_of_loads(double* %x, double* %y, i64 %i) {
; ALL-NEXT: [[XI:%.*]] = load double, double* [[XI_PTR]], align 8
; ALL-NEXT: [[YI:%.*]] = load double, double* [[YI_PTR]], align 8
; ALL-NEXT: [[CMP:%.*]] = fcmp ogt double [[XI]], [[YI]]
; ALL-NEXT: [[Y_SINK:%.*]] = select i1 [[CMP]], double* [[X]], double* [[Y]]
; ALL-NEXT: [[YI_PTR_AGAIN:%.*]] = getelementptr double, double* [[Y_SINK]], i64 [[I]]
; ALL-NEXT: [[YI_AGAIN:%.*]] = load double, double* [[YI_PTR_AGAIN]], align 8
; ALL-NEXT: ret double [[YI_AGAIN]]
; ALL-NEXT: [[XI_YI:%.*]] = select i1 [[CMP]], double [[XI]], double [[YI]]
; ALL-NEXT: ret double [[XI_YI]]
;
entry:
%xi_ptr = getelementptr double, double* %x, i64 %i
Expand Down
2 changes: 1 addition & 1 deletion llvm/test/Transforms/SimplifyCFG/no-md-sink.ll
@@ -1,4 +1,4 @@
; RUN: opt < %s -simplifycfg -S | FileCheck %s
; RUN: opt < %s -simplifycfg -sink-common-insts -S | FileCheck %s

define i1 @test1(i1 zeroext %flag, i8* %y) #0 {
entry:
Expand Down
2 changes: 1 addition & 1 deletion llvm/test/Transforms/SimplifyCFG/sink-common-code.ll
@@ -1,4 +1,4 @@
; RUN: opt < %s -simplifycfg -S | FileCheck -enable-var-scope %s
; RUN: opt < %s -simplifycfg -sink-common-insts -S | FileCheck -enable-var-scope %s

define zeroext i1 @test1(i1 zeroext %flag, i32 %blksA, i32 %blksB, i32 %nblks) {
entry:
Expand Down

0 comments on commit 0ab0c1a

Please sign in to comment.