2008-05-15 04:38:44 +08:00
|
|
|
//===- SimplifyCFGPass.cpp - CFG Simplification Pass ----------------------===//
|
2005-04-22 07:48:37 +08:00
|
|
|
//
|
2019-01-19 16:50:56 +08:00
|
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
2005-04-22 07:48:37 +08:00
|
|
|
//
|
2003-10-21 03:43:21 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
2002-05-22 04:49:37 +08:00
|
|
|
//
|
2007-12-04 03:43:18 +08:00
|
|
|
// This file implements dead code elimination and basic block merging, along
|
|
|
|
// with a collection of other peephole control flow optimizations. For example:
|
2002-05-22 04:49:37 +08:00
|
|
|
//
|
2007-11-05 00:15:04 +08:00
|
|
|
// * Removes basic blocks with no predecessors.
|
|
|
|
// * Merges a basic block into its predecessor if there is only one and the
|
2002-05-22 04:49:37 +08:00
|
|
|
// predecessor only has one successor.
|
2007-11-05 00:15:04 +08:00
|
|
|
// * Eliminates PHI nodes for basic blocks with a single predecessor.
|
|
|
|
// * Eliminates a basic block that only contains an unconditional branch.
|
2007-12-04 03:43:18 +08:00
|
|
|
// * Changes invoke instructions to nounwind functions to be calls.
|
|
|
|
// * Change things like "if (x) if (y)" into "if (x&y)".
|
|
|
|
// * etc..
|
2002-05-22 04:49:37 +08:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2012-12-04 00:50:05 +08:00
|
|
|
#include "llvm/ADT/SmallPtrSet.h"
|
|
|
|
#include "llvm/ADT/SmallVector.h"
|
|
|
|
#include "llvm/ADT/Statistic.h"
|
2016-12-19 16:22:17 +08:00
|
|
|
#include "llvm/Analysis/AssumptionCache.h"
|
2016-03-29 12:08:57 +08:00
|
|
|
#include "llvm/Analysis/CFG.h"
|
2016-05-27 22:27:24 +08:00
|
|
|
#include "llvm/Analysis/GlobalsModRef.h"
|
|
|
|
#include "llvm/Analysis/TargetTransformInfo.h"
|
2013-01-02 19:36:10 +08:00
|
|
|
#include "llvm/IR/Attributes.h"
|
2014-03-04 19:45:46 +08:00
|
|
|
#include "llvm/IR/CFG.h"
|
2013-01-02 19:36:10 +08:00
|
|
|
#include "llvm/IR/Constants.h"
|
|
|
|
#include "llvm/IR/DataLayout.h"
|
|
|
|
#include "llvm/IR/Instructions.h"
|
|
|
|
#include "llvm/IR/IntrinsicInst.h"
|
|
|
|
#include "llvm/IR/Module.h"
|
Sink all InitializePasses.h includes
This file lists every pass in LLVM, and is included by Pass.h, which is
very popular. Every time we add, remove, or rename a pass in LLVM, it
caused lots of recompilation.
I found this fact by looking at this table, which is sorted by the
number of times a file was changed over the last 100,000 git commits
multiplied by the number of object files that depend on it in the
current checkout:
recompiles touches affected_files header
342380 95 3604 llvm/include/llvm/ADT/STLExtras.h
314730 234 1345 llvm/include/llvm/InitializePasses.h
307036 118 2602 llvm/include/llvm/ADT/APInt.h
213049 59 3611 llvm/include/llvm/Support/MathExtras.h
170422 47 3626 llvm/include/llvm/Support/Compiler.h
162225 45 3605 llvm/include/llvm/ADT/Optional.h
158319 63 2513 llvm/include/llvm/ADT/Triple.h
140322 39 3598 llvm/include/llvm/ADT/StringRef.h
137647 59 2333 llvm/include/llvm/Support/Error.h
131619 73 1803 llvm/include/llvm/Support/FileSystem.h
Before this change, touching InitializePasses.h would cause 1345 files
to recompile. After this change, touching it only causes 550 compiles in
an incremental rebuild.
Reviewers: bkramer, asbirlea, bollu, jdoerfert
Differential Revision: https://reviews.llvm.org/D70211
2019-11-14 05:15:01 +08:00
|
|
|
#include "llvm/InitializePasses.h"
|
2002-05-22 04:49:37 +08:00
|
|
|
#include "llvm/Pass.h"
|
[SimplifyCFG] threshold for folding branches with common destination
Summary:
This patch adds a threshold that controls the number of bonus instructions
allowed for folding branches with common destination. The original code allows
at most one bonus instruction. With this patch, users can customize the
threshold to allow multiple bonus instructions. The default threshold is still
1, so that the code behaves the same as before when users do not specify this
threshold.
The motivation of this change is that tuning this threshold significantly (up
to 25%) improves the performance of some CUDA programs in our internal code
base. In general, branch instructions are very expensive for GPU programs.
Therefore, it is sometimes worth trading more arithmetic computation for a more
straightened control flow. Here's a reduced example:
__global__ void foo(int a, int b, int c, int d, int e, int n,
const int *input, int *output) {
int sum = 0;
for (int i = 0; i < n; ++i)
sum += (((i ^ a) > b) && (((i | c ) ^ d) > e)) ? 0 : input[i];
*output = sum;
}
The select statement in the loop body translates to two branch instructions "if
((i ^ a) > b)" and "if (((i | c) ^ d) > e)" which share a common destination.
With the default threshold, SimplifyCFG is unable to fold them, because
computing the condition of the second branch "(i | c) ^ d > e" requires two
bonus instructions. With the threshold increased, SimplifyCFG can fold the two
branches so that the loop body contains only one branch, making the code
conceptually look like:
sum += (((i ^ a) > b) & (((i | c ) ^ d) > e)) ? 0 : input[i];
Increasing the threshold significantly improves the performance of this
particular example. In the configuration where both conditions are guaranteed
to be true, increasing the threshold from 1 to 2 improves the performance by
18.24%. Even in the configuration where the first condition is false and the
second condition is true, which favors shortcuts, increasing the threshold from
1 to 2 still improves the performance by 4.35%.
We are still looking for a good threshold and maybe a better cost model than
just counting the number of bonus instructions. However, according to the above
numbers, we think it is at least worth adding a threshold to enable more
experiments and tuning. Let me know what you think. Thanks!
Test Plan: Added one test case to check the threshold is in effect
Reviewers: nadav, eliben, meheff, resistor, hfinkel
Reviewed By: hfinkel
Subscribers: hfinkel, llvm-commits
Differential Revision: http://reviews.llvm.org/D5529
llvm-svn: 218711
2014-10-01 06:23:38 +08:00
|
|
|
#include "llvm/Support/CommandLine.h"
|
2015-02-01 19:34:21 +08:00
|
|
|
#include "llvm/Transforms/Scalar.h"
|
2016-05-27 22:27:24 +08:00
|
|
|
#include "llvm/Transforms/Scalar/SimplifyCFG.h"
|
Sink all InitializePasses.h includes
This file lists every pass in LLVM, and is included by Pass.h, which is
very popular. Every time we add, remove, or rename a pass in LLVM, it
caused lots of recompilation.
I found this fact by looking at this table, which is sorted by the
number of times a file was changed over the last 100,000 git commits
multiplied by the number of object files that depend on it in the
current checkout:
recompiles touches affected_files header
342380 95 3604 llvm/include/llvm/ADT/STLExtras.h
314730 234 1345 llvm/include/llvm/InitializePasses.h
307036 118 2602 llvm/include/llvm/ADT/APInt.h
213049 59 3611 llvm/include/llvm/Support/MathExtras.h
170422 47 3626 llvm/include/llvm/Support/Compiler.h
162225 45 3605 llvm/include/llvm/ADT/Optional.h
158319 63 2513 llvm/include/llvm/ADT/Triple.h
140322 39 3598 llvm/include/llvm/ADT/StringRef.h
137647 59 2333 llvm/include/llvm/Support/Error.h
131619 73 1803 llvm/include/llvm/Support/FileSystem.h
Before this change, touching InitializePasses.h would cause 1345 files
to recompile. After this change, touching it only causes 550 compiles in
an incremental rebuild.
Reviewers: bkramer, asbirlea, bollu, jdoerfert
Differential Revision: https://reviews.llvm.org/D70211
2019-11-14 05:15:01 +08:00
|
|
|
#include "llvm/Transforms/Utils/Local.h"
|
2016-05-27 22:27:24 +08:00
|
|
|
#include <utility>
|
2004-01-09 14:02:20 +08:00
|
|
|
using namespace llvm;
|
2003-11-12 06:41:34 +08:00
|
|
|
|
2014-04-22 10:55:47 +08:00
|
|
|
#define DEBUG_TYPE "simplifycfg"
|
|
|
|
|
2017-10-29 02:43:07 +08:00
|
|
|
static cl::opt<unsigned> UserBonusInstThreshold(
|
|
|
|
"bonus-inst-threshold", cl::Hidden, cl::init(1),
|
|
|
|
cl::desc("Control the number of bonus instructions (default = 1)"));
|
|
|
|
|
|
|
|
static cl::opt<bool> UserKeepLoops(
|
|
|
|
"keep-loops", cl::Hidden, cl::init(true),
|
|
|
|
cl::desc("Preserve canonical loop structure (default = true)"));
|
|
|
|
|
|
|
|
static cl::opt<bool> UserSwitchToLookup(
|
|
|
|
"switch-to-lookup", cl::Hidden, cl::init(false),
|
|
|
|
cl::desc("Convert switches to lookup tables (default = false)"));
|
|
|
|
|
|
|
|
static cl::opt<bool> UserForwardSwitchCond(
|
|
|
|
"forward-switch-cond", cl::Hidden, cl::init(false),
|
|
|
|
cl::desc("Forward switch condition to phi ops (default = false)"));
|
[SimplifyCFG] threshold for folding branches with common destination
Summary:
This patch adds a threshold that controls the number of bonus instructions
allowed for folding branches with common destination. The original code allows
at most one bonus instruction. With this patch, users can customize the
threshold to allow multiple bonus instructions. The default threshold is still
1, so that the code behaves the same as before when users do not specify this
threshold.
The motivation of this change is that tuning this threshold significantly (up
to 25%) improves the performance of some CUDA programs in our internal code
base. In general, branch instructions are very expensive for GPU programs.
Therefore, it is sometimes worth trading more arithmetic computation for a more
straightened control flow. Here's a reduced example:
__global__ void foo(int a, int b, int c, int d, int e, int n,
const int *input, int *output) {
int sum = 0;
for (int i = 0; i < n; ++i)
sum += (((i ^ a) > b) && (((i | c ) ^ d) > e)) ? 0 : input[i];
*output = sum;
}
The select statement in the loop body translates to two branch instructions "if
((i ^ a) > b)" and "if (((i | c) ^ d) > e)" which share a common destination.
With the default threshold, SimplifyCFG is unable to fold them, because
computing the condition of the second branch "(i | c) ^ d > e" requires two
bonus instructions. With the threshold increased, SimplifyCFG can fold the two
branches so that the loop body contains only one branch, making the code
conceptually look like:
sum += (((i ^ a) > b) & (((i | c ) ^ d) > e)) ? 0 : input[i];
Increasing the threshold significantly improves the performance of this
particular example. In the configuration where both conditions are guaranteed
to be true, increasing the threshold from 1 to 2 improves the performance by
18.24%. Even in the configuration where the first condition is false and the
second condition is true, which favors shortcuts, increasing the threshold from
1 to 2 still improves the performance by 4.35%.
We are still looking for a good threshold and maybe a better cost model than
just counting the number of bonus instructions. However, according to the above
numbers, we think it is at least worth adding a threshold to enable more
experiments and tuning. Let me know what you think. Thanks!
Test Plan: Added one test case to check the threshold is in effect
Reviewers: nadav, eliben, meheff, resistor, hfinkel
Reviewed By: hfinkel
Subscribers: hfinkel, llvm-commits
Differential Revision: http://reviews.llvm.org/D5529
llvm-svn: 218711
2014-10-01 06:23:38 +08:00
|
|
|
|
2017-12-15 06:05:20 +08:00
|
|
|
static cl::opt<bool> UserSinkCommonInsts(
|
|
|
|
"sink-common-insts", cl::Hidden, cl::init(false),
|
|
|
|
cl::desc("Sink common instructions (default = false)"));
|
|
|
|
|
|
|
|
|
2006-12-20 05:40:18 +08:00
|
|
|
STATISTIC(NumSimpl, "Number of blocks simplified");
|
2002-10-02 06:38:41 +08:00
|
|
|
|
2015-06-25 04:40:57 +08:00
|
|
|
/// If we have more than one empty (other than phi node) return blocks,
|
|
|
|
/// merge them together to promote recursive block merging.
|
2012-09-06 08:59:08 +08:00
|
|
|
static bool mergeEmptyReturnBlocks(Function &F) {
|
2009-12-22 14:07:30 +08:00
|
|
|
bool Changed = false;
|
2012-07-24 18:51:42 +08:00
|
|
|
|
2014-04-25 13:29:35 +08:00
|
|
|
BasicBlock *RetBlock = nullptr;
|
2012-07-24 18:51:42 +08:00
|
|
|
|
2009-12-22 14:07:30 +08:00
|
|
|
// Scan all the blocks in the function, looking for empty return blocks.
|
|
|
|
for (Function::iterator BBI = F.begin(), E = F.end(); BBI != E; ) {
|
|
|
|
BasicBlock &BB = *BBI++;
|
2012-07-24 18:51:42 +08:00
|
|
|
|
2009-12-22 14:07:30 +08:00
|
|
|
// Only look at return blocks.
|
|
|
|
ReturnInst *Ret = dyn_cast<ReturnInst>(BB.getTerminator());
|
2014-04-25 13:29:35 +08:00
|
|
|
if (!Ret) continue;
|
2012-07-24 18:51:42 +08:00
|
|
|
|
2009-12-22 14:07:30 +08:00
|
|
|
// Only look at the block if it is empty or the only other thing in it is a
|
|
|
|
// single PHI node that is the operand to the return.
|
|
|
|
if (Ret != &BB.front()) {
|
|
|
|
// Check for something else in the block.
|
2015-10-14 03:26:58 +08:00
|
|
|
BasicBlock::iterator I(Ret);
|
2009-12-22 14:07:30 +08:00
|
|
|
--I;
|
2010-03-14 18:40:55 +08:00
|
|
|
// Skip over debug info.
|
|
|
|
while (isa<DbgInfoIntrinsic>(I) && I != BB.begin())
|
|
|
|
--I;
|
|
|
|
if (!isa<DbgInfoIntrinsic>(I) &&
|
2015-10-14 03:26:58 +08:00
|
|
|
(!isa<PHINode>(I) || I != BB.begin() || Ret->getNumOperands() == 0 ||
|
|
|
|
Ret->getOperand(0) != &*I))
|
2009-12-22 14:07:30 +08:00
|
|
|
continue;
|
|
|
|
}
|
2010-03-14 18:40:55 +08:00
|
|
|
|
2009-12-22 14:07:30 +08:00
|
|
|
// If this is the first returning block, remember it and keep going.
|
2014-04-25 13:29:35 +08:00
|
|
|
if (!RetBlock) {
|
2009-12-22 14:07:30 +08:00
|
|
|
RetBlock = &BB;
|
|
|
|
continue;
|
|
|
|
}
|
2012-07-24 18:51:42 +08:00
|
|
|
|
2020-03-05 00:11:40 +08:00
|
|
|
// Skip merging if this would result in a CallBr instruction with a
|
|
|
|
// duplicate destination. FIXME: See note in CodeGenPrepare.cpp.
|
|
|
|
bool SkipCallBr = false;
|
|
|
|
for (pred_iterator PI = pred_begin(&BB), E = pred_end(&BB);
|
|
|
|
PI != E && !SkipCallBr; ++PI) {
|
|
|
|
if (auto *CBI = dyn_cast<CallBrInst>((*PI)->getTerminator()))
|
|
|
|
for (unsigned i = 0, e = CBI->getNumSuccessors(); i != e; ++i)
|
|
|
|
if (RetBlock == CBI->getSuccessor(i)) {
|
|
|
|
SkipCallBr = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (SkipCallBr)
|
|
|
|
continue;
|
|
|
|
|
2009-12-22 14:07:30 +08:00
|
|
|
// Otherwise, we found a duplicate return block. Merge the two.
|
|
|
|
Changed = true;
|
2012-07-24 18:51:42 +08:00
|
|
|
|
2009-12-22 14:07:30 +08:00
|
|
|
// Case when there is no input to the return or when the returned values
|
|
|
|
// agree is trivial. Note that they can't agree if there are phis in the
|
|
|
|
// blocks.
|
|
|
|
if (Ret->getNumOperands() == 0 ||
|
2012-07-24 18:51:42 +08:00
|
|
|
Ret->getOperand(0) ==
|
2009-12-22 14:07:30 +08:00
|
|
|
cast<ReturnInst>(RetBlock->getTerminator())->getOperand(0)) {
|
|
|
|
BB.replaceAllUsesWith(RetBlock);
|
|
|
|
BB.eraseFromParent();
|
|
|
|
continue;
|
|
|
|
}
|
2012-07-24 18:51:42 +08:00
|
|
|
|
2009-12-22 14:07:30 +08:00
|
|
|
// If the canonical return block has no PHI node, create one now.
|
|
|
|
PHINode *RetBlockPHI = dyn_cast<PHINode>(RetBlock->begin());
|
2014-04-25 13:29:35 +08:00
|
|
|
if (!RetBlockPHI) {
|
2010-03-16 03:05:46 +08:00
|
|
|
Value *InVal = cast<ReturnInst>(RetBlock->getTerminator())->getOperand(0);
|
2011-03-30 19:19:20 +08:00
|
|
|
pred_iterator PB = pred_begin(RetBlock), PE = pred_end(RetBlock);
|
2011-03-30 19:28:46 +08:00
|
|
|
RetBlockPHI = PHINode::Create(Ret->getOperand(0)->getType(),
|
|
|
|
std::distance(PB, PE), "merge",
|
2009-12-22 14:07:30 +08:00
|
|
|
&RetBlock->front());
|
2012-07-24 18:51:42 +08:00
|
|
|
|
2011-03-30 19:19:20 +08:00
|
|
|
for (pred_iterator PI = PB; PI != PE; ++PI)
|
2009-12-22 14:07:30 +08:00
|
|
|
RetBlockPHI->addIncoming(InVal, *PI);
|
|
|
|
RetBlock->getTerminator()->setOperand(0, RetBlockPHI);
|
|
|
|
}
|
2012-07-24 18:51:42 +08:00
|
|
|
|
2009-12-22 14:07:30 +08:00
|
|
|
// Turn BB into a block that just unconditionally branches to the return
|
|
|
|
// block. This handles the case when the two return blocks have a common
|
|
|
|
// predecessor but that return different things.
|
|
|
|
RetBlockPHI->addIncoming(Ret->getOperand(0), &BB);
|
|
|
|
BB.getTerminator()->eraseFromParent();
|
|
|
|
BranchInst::Create(RetBlock, &BB);
|
|
|
|
}
|
2012-07-24 18:51:42 +08:00
|
|
|
|
2009-12-22 14:07:30 +08:00
|
|
|
return Changed;
|
|
|
|
}
|
|
|
|
|
2015-06-25 04:40:57 +08:00
|
|
|
/// Call SimplifyCFG on all the blocks in the function,
|
2007-11-13 15:32:38 +08:00
|
|
|
/// iterating until no more changes are made.
|
2013-01-07 11:53:25 +08:00
|
|
|
static bool iterativelySimplifyCFG(Function &F, const TargetTransformInfo &TTI,
|
2017-09-27 22:54:16 +08:00
|
|
|
const SimplifyCFGOptions &Options) {
|
2007-11-13 15:32:38 +08:00
|
|
|
bool Changed = false;
|
2016-03-29 02:07:40 +08:00
|
|
|
bool LocalChange = true;
|
2016-03-29 12:08:57 +08:00
|
|
|
|
|
|
|
SmallVector<std::pair<const BasicBlock *, const BasicBlock *>, 32> Edges;
|
|
|
|
FindFunctionBackedges(F, Edges);
|
|
|
|
SmallPtrSet<BasicBlock *, 16> LoopHeaders;
|
|
|
|
for (unsigned i = 0, e = Edges.size(); i != e; ++i)
|
|
|
|
LoopHeaders.insert(const_cast<BasicBlock *>(Edges[i].second));
|
|
|
|
|
2002-05-22 04:49:37 +08:00
|
|
|
while (LocalChange) {
|
|
|
|
LocalChange = false;
|
2012-07-24 18:51:42 +08:00
|
|
|
|
2015-06-25 04:42:33 +08:00
|
|
|
// Loop over all of the basic blocks and remove them if they are unneeded.
|
2010-08-14 08:29:42 +08:00
|
|
|
for (Function::iterator BBIt = F.begin(); BBIt != F.end(); ) {
|
2017-10-05 04:26:25 +08:00
|
|
|
if (simplifyCFG(&*BBIt++, TTI, Options, &LoopHeaders)) {
|
2002-05-22 04:49:37 +08:00
|
|
|
LocalChange = true;
|
|
|
|
++NumSimpl;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Changed |= LocalChange;
|
|
|
|
}
|
|
|
|
return Changed;
|
|
|
|
}
|
2007-11-13 15:32:38 +08:00
|
|
|
|
2015-02-01 19:34:21 +08:00
|
|
|
static bool simplifyFunctionCFG(Function &F, const TargetTransformInfo &TTI,
|
2017-09-27 22:54:16 +08:00
|
|
|
const SimplifyCFGOptions &Options) {
|
2013-08-13 06:38:43 +08:00
|
|
|
bool EverChanged = removeUnreachableBlocks(F);
|
2012-09-06 08:59:08 +08:00
|
|
|
EverChanged |= mergeEmptyReturnBlocks(F);
|
2017-10-05 04:26:25 +08:00
|
|
|
EverChanged |= iterativelySimplifyCFG(F, TTI, Options);
|
2010-02-06 06:03:18 +08:00
|
|
|
|
2007-11-13 15:32:38 +08:00
|
|
|
// If neither pass changed anything, we're done.
|
|
|
|
if (!EverChanged) return false;
|
|
|
|
|
2012-09-06 08:59:08 +08:00
|
|
|
// iterativelySimplifyCFG can (rarely) make some loops dead. If this happens,
|
2013-08-13 06:38:43 +08:00
|
|
|
// removeUnreachableBlocks is needed to nuke them, which means we should
|
2007-11-13 15:32:38 +08:00
|
|
|
// iterate between the two optimizations. We structure the code like this to
|
2015-06-25 04:42:33 +08:00
|
|
|
// avoid rerunning iterativelySimplifyCFG if the second pass of
|
2013-08-13 06:38:43 +08:00
|
|
|
// removeUnreachableBlocks doesn't do anything.
|
|
|
|
if (!removeUnreachableBlocks(F))
|
2007-11-13 15:32:38 +08:00
|
|
|
return true;
|
2010-02-06 06:03:18 +08:00
|
|
|
|
2007-11-13 15:32:38 +08:00
|
|
|
do {
|
2017-10-05 04:26:25 +08:00
|
|
|
EverChanged = iterativelySimplifyCFG(F, TTI, Options);
|
2013-08-13 06:38:43 +08:00
|
|
|
EverChanged |= removeUnreachableBlocks(F);
|
2007-11-13 15:32:38 +08:00
|
|
|
} while (EverChanged);
|
2010-02-06 06:03:18 +08:00
|
|
|
|
2007-11-13 15:32:38 +08:00
|
|
|
return true;
|
|
|
|
}
|
2015-02-01 19:34:21 +08:00
|
|
|
|
2017-10-29 02:43:07 +08:00
|
|
|
// Command-line settings override compile-time settings.
|
|
|
|
SimplifyCFGPass::SimplifyCFGPass(const SimplifyCFGOptions &Opts) {
|
|
|
|
Options.BonusInstThreshold = UserBonusInstThreshold.getNumOccurrences()
|
|
|
|
? UserBonusInstThreshold
|
|
|
|
: Opts.BonusInstThreshold;
|
|
|
|
Options.ForwardSwitchCondToPhi = UserForwardSwitchCond.getNumOccurrences()
|
|
|
|
? UserForwardSwitchCond
|
|
|
|
: Opts.ForwardSwitchCondToPhi;
|
|
|
|
Options.ConvertSwitchToLookupTable = UserSwitchToLookup.getNumOccurrences()
|
|
|
|
? UserSwitchToLookup
|
|
|
|
: Opts.ConvertSwitchToLookupTable;
|
|
|
|
Options.NeedCanonicalLoop = UserKeepLoops.getNumOccurrences()
|
|
|
|
? UserKeepLoops
|
|
|
|
: Opts.NeedCanonicalLoop;
|
2017-12-15 06:05:20 +08:00
|
|
|
Options.SinkCommonInsts = UserSinkCommonInsts.getNumOccurrences()
|
|
|
|
? UserSinkCommonInsts
|
|
|
|
: Opts.SinkCommonInsts;
|
2017-10-29 02:43:07 +08:00
|
|
|
}
|
2015-02-01 19:34:21 +08:00
|
|
|
|
|
|
|
PreservedAnalyses SimplifyCFGPass::run(Function &F,
|
2016-08-09 08:28:15 +08:00
|
|
|
FunctionAnalysisManager &AM) {
|
2016-03-11 19:05:24 +08:00
|
|
|
auto &TTI = AM.getResult<TargetIRAnalysis>(F);
|
2017-10-05 04:26:25 +08:00
|
|
|
Options.AC = &AM.getResult<AssumptionAnalysis>(F);
|
|
|
|
if (!simplifyFunctionCFG(F, TTI, Options))
|
2016-06-08 21:32:23 +08:00
|
|
|
return PreservedAnalyses::all();
|
|
|
|
PreservedAnalyses PA;
|
|
|
|
PA.preserve<GlobalsAA>();
|
|
|
|
return PA;
|
2015-02-01 19:34:21 +08:00
|
|
|
}
|
|
|
|
|
2016-05-06 04:47:53 +08:00
|
|
|
namespace {
|
2017-10-29 02:43:07 +08:00
|
|
|
struct CFGSimplifyPass : public FunctionPass {
|
|
|
|
static char ID;
|
|
|
|
SimplifyCFGOptions Options;
|
2016-05-06 04:47:53 +08:00
|
|
|
std::function<bool(const Function &)> PredicateFtor;
|
2017-10-29 02:43:07 +08:00
|
|
|
|
2020-07-16 05:48:36 +08:00
|
|
|
CFGSimplifyPass(SimplifyCFGOptions Options_ = SimplifyCFGOptions(),
|
2017-10-29 02:43:07 +08:00
|
|
|
std::function<bool(const Function &)> Ftor = nullptr)
|
2020-07-16 05:48:36 +08:00
|
|
|
: FunctionPass(ID), Options(Options_), PredicateFtor(std::move(Ftor)) {
|
2017-10-29 02:43:07 +08:00
|
|
|
|
|
|
|
initializeCFGSimplifyPassPass(*PassRegistry::getPassRegistry());
|
|
|
|
|
|
|
|
// Check for command-line overrides of options for debug/customization.
|
2020-07-16 05:48:36 +08:00
|
|
|
if (UserBonusInstThreshold.getNumOccurrences())
|
|
|
|
Options.BonusInstThreshold = UserBonusInstThreshold;
|
2017-10-29 02:43:07 +08:00
|
|
|
|
2020-07-16 05:48:36 +08:00
|
|
|
if (UserForwardSwitchCond.getNumOccurrences())
|
|
|
|
Options.ForwardSwitchCondToPhi = UserForwardSwitchCond;
|
2017-10-29 02:43:07 +08:00
|
|
|
|
2020-07-16 05:48:36 +08:00
|
|
|
if (UserSwitchToLookup.getNumOccurrences())
|
|
|
|
Options.ConvertSwitchToLookupTable = UserSwitchToLookup;
|
2017-10-29 02:43:07 +08:00
|
|
|
|
2020-07-16 05:48:36 +08:00
|
|
|
if (UserKeepLoops.getNumOccurrences())
|
|
|
|
Options.NeedCanonicalLoop = UserKeepLoops;
|
2017-12-15 06:05:20 +08:00
|
|
|
|
2020-07-16 05:48:36 +08:00
|
|
|
if (UserSinkCommonInsts.getNumOccurrences())
|
|
|
|
Options.SinkCommonInsts = UserSinkCommonInsts;
|
2016-05-06 04:47:53 +08:00
|
|
|
}
|
2017-10-29 02:43:07 +08:00
|
|
|
|
2016-05-06 04:47:53 +08:00
|
|
|
bool runOnFunction(Function &F) override {
|
|
|
|
if (skipFunction(F) || (PredicateFtor && !PredicateFtor(F)))
|
|
|
|
return false;
|
|
|
|
|
2017-10-29 02:43:07 +08:00
|
|
|
Options.AC = &getAnalysis<AssumptionCacheTracker>().getAssumptionCache(F);
|
2020-05-21 08:05:07 +08:00
|
|
|
if (F.hasFnAttribute(Attribute::OptForFuzzing)) {
|
|
|
|
Options.setSimplifyCondBranch(false)
|
|
|
|
.setFoldTwoEntryPHINode(false);
|
|
|
|
} else {
|
|
|
|
Options.setSimplifyCondBranch(true)
|
|
|
|
.setFoldTwoEntryPHINode(true);
|
|
|
|
}
|
|
|
|
|
2017-10-29 02:43:07 +08:00
|
|
|
auto &TTI = getAnalysis<TargetTransformInfoWrapperPass>().getTTI(F);
|
|
|
|
return simplifyFunctionCFG(F, TTI, Options);
|
2016-05-06 04:47:53 +08:00
|
|
|
}
|
|
|
|
void getAnalysisUsage(AnalysisUsage &AU) const override {
|
2016-12-19 16:22:17 +08:00
|
|
|
AU.addRequired<AssumptionCacheTracker>();
|
2016-05-06 04:47:53 +08:00
|
|
|
AU.addRequired<TargetTransformInfoWrapperPass>();
|
|
|
|
AU.addPreserved<GlobalsAAWrapperPass>();
|
|
|
|
}
|
|
|
|
};
|
2015-06-23 17:49:53 +08:00
|
|
|
}
|
2015-02-01 19:34:21 +08:00
|
|
|
|
|
|
|
char CFGSimplifyPass::ID = 0;
|
|
|
|
INITIALIZE_PASS_BEGIN(CFGSimplifyPass, "simplifycfg", "Simplify the CFG", false,
|
|
|
|
false)
|
|
|
|
INITIALIZE_PASS_DEPENDENCY(TargetTransformInfoWrapperPass)
|
2016-12-19 16:22:17 +08:00
|
|
|
INITIALIZE_PASS_DEPENDENCY(AssumptionCacheTracker)
|
2015-02-01 19:34:21 +08:00
|
|
|
INITIALIZE_PASS_END(CFGSimplifyPass, "simplifycfg", "Simplify the CFG", false,
|
|
|
|
false)
|
|
|
|
|
|
|
|
// Public interface to the CFGSimplification pass
|
2015-06-09 02:50:43 +08:00
|
|
|
FunctionPass *
|
2020-07-16 16:54:10 +08:00
|
|
|
llvm::createCFGSimplificationPass(unsigned Threshold, bool ForwardSwitchCond,
|
|
|
|
bool ConvertSwitch, bool KeepLoops,
|
|
|
|
bool SinkCommon,
|
2017-03-26 14:44:08 +08:00
|
|
|
std::function<bool(const Function &)> Ftor) {
|
2020-07-16 16:54:10 +08:00
|
|
|
return new CFGSimplifyPass(SimplifyCFGOptions()
|
|
|
|
.bonusInstThreshold(Threshold)
|
|
|
|
.forwardSwitchCondToPhi(ForwardSwitchCond)
|
|
|
|
.convertSwitchToLookupTable(ConvertSwitch)
|
|
|
|
.needCanonicalLoops(KeepLoops)
|
|
|
|
.sinkCommonInsts(SinkCommon),
|
|
|
|
std::move(Ftor));
|
2017-03-26 14:44:08 +08:00
|
|
|
}
|