2017-10-20 23:47:29 +02:00
|
|
|
//===- StructurizeCFG.cpp -------------------------------------------------===//
|
2012-12-19 23:10:31 +01:00
|
|
|
//
|
2019-01-19 09:50:56 +01: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
|
2012-12-19 23:10:31 +01:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2017-10-20 23:47:29 +02:00
|
|
|
#include "llvm/ADT/DenseMap.h"
|
2013-03-26 11:24:20 +01:00
|
|
|
#include "llvm/ADT/MapVector.h"
|
2015-02-04 21:49:44 +01:00
|
|
|
#include "llvm/ADT/PostOrderIterator.h"
|
2017-10-20 23:47:29 +02:00
|
|
|
#include "llvm/ADT/STLExtras.h"
|
|
|
|
#include "llvm/ADT/SmallPtrSet.h"
|
|
|
|
#include "llvm/ADT/SmallVector.h"
|
2018-10-17 17:37:41 +02:00
|
|
|
#include "llvm/Analysis/InstructionSimplify.h"
|
2018-08-30 16:21:36 +02:00
|
|
|
#include "llvm/Analysis/LegacyDivergenceAnalysis.h"
|
2018-01-24 19:02:05 +01:00
|
|
|
#include "llvm/Analysis/LoopInfo.h"
|
2012-12-19 23:10:31 +01:00
|
|
|
#include "llvm/Analysis/RegionInfo.h"
|
2013-01-02 11:22:59 +01:00
|
|
|
#include "llvm/Analysis/RegionIterator.h"
|
2012-12-19 23:10:31 +01:00
|
|
|
#include "llvm/Analysis/RegionPass.h"
|
2017-10-20 23:47:29 +02:00
|
|
|
#include "llvm/IR/Argument.h"
|
|
|
|
#include "llvm/IR/BasicBlock.h"
|
|
|
|
#include "llvm/IR/CFG.h"
|
|
|
|
#include "llvm/IR/Constant.h"
|
|
|
|
#include "llvm/IR/Constants.h"
|
|
|
|
#include "llvm/IR/Dominators.h"
|
|
|
|
#include "llvm/IR/Function.h"
|
|
|
|
#include "llvm/IR/InstrTypes.h"
|
|
|
|
#include "llvm/IR/Instruction.h"
|
|
|
|
#include "llvm/IR/Instructions.h"
|
|
|
|
#include "llvm/IR/Metadata.h"
|
2014-03-04 12:08:18 +01:00
|
|
|
#include "llvm/IR/PatternMatch.h"
|
2017-10-20 23:47:29 +02:00
|
|
|
#include "llvm/IR/Type.h"
|
|
|
|
#include "llvm/IR/Use.h"
|
|
|
|
#include "llvm/IR/User.h"
|
|
|
|
#include "llvm/IR/Value.h"
|
2020-03-05 04:39:46 +01:00
|
|
|
#include "llvm/IR/ValueHandle.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-13 22:15:01 +01:00
|
|
|
#include "llvm/InitializePasses.h"
|
2017-10-20 23:47:29 +02:00
|
|
|
#include "llvm/Pass.h"
|
|
|
|
#include "llvm/Support/Casting.h"
|
2019-11-15 00:15:48 +01:00
|
|
|
#include "llvm/Support/CommandLine.h"
|
2015-02-04 21:49:44 +01:00
|
|
|
#include "llvm/Support/Debug.h"
|
2017-10-20 23:47:29 +02:00
|
|
|
#include "llvm/Support/ErrorHandling.h"
|
2015-03-23 20:32:43 +01:00
|
|
|
#include "llvm/Support/raw_ostream.h"
|
2017-06-06 13:49:48 +02:00
|
|
|
#include "llvm/Transforms/Scalar.h"
|
2018-03-28 19:44:36 +02:00
|
|
|
#include "llvm/Transforms/Utils.h"
|
2013-05-23 19:10:37 +02:00
|
|
|
#include "llvm/Transforms/Utils/SSAUpdater.h"
|
2017-10-20 23:47:29 +02:00
|
|
|
#include <algorithm>
|
|
|
|
#include <cassert>
|
|
|
|
#include <utility>
|
2012-12-19 23:10:31 +01:00
|
|
|
|
|
|
|
using namespace llvm;
|
2013-02-16 12:27:50 +01:00
|
|
|
using namespace llvm::PatternMatch;
|
2012-12-19 23:10:31 +01:00
|
|
|
|
2014-04-22 04:55:47 +02:00
|
|
|
#define DEBUG_TYPE "structurizecfg"
|
|
|
|
|
2017-10-20 23:47:29 +02:00
|
|
|
// The name for newly created blocks.
|
|
|
|
static const char *const FlowBlockName = "Flow";
|
|
|
|
|
2012-12-19 23:10:31 +01:00
|
|
|
namespace {
|
|
|
|
|
2018-04-04 12:58:15 +02:00
|
|
|
static cl::opt<bool> ForceSkipUniformRegions(
|
|
|
|
"structurizecfg-skip-uniform-regions",
|
|
|
|
cl::Hidden,
|
|
|
|
cl::desc("Force whether the StructurizeCFG pass skips uniform regions"),
|
|
|
|
cl::init(false));
|
|
|
|
|
2019-05-24 10:59:17 +02:00
|
|
|
static cl::opt<bool>
|
|
|
|
RelaxedUniformRegions("structurizecfg-relaxed-uniform-regions", cl::Hidden,
|
|
|
|
cl::desc("Allow relaxed uniform region checks"),
|
2019-08-06 16:30:19 +02:00
|
|
|
cl::init(true));
|
2019-05-24 10:59:17 +02:00
|
|
|
|
2012-12-19 23:10:31 +01:00
|
|
|
// Definition of the complex types used in this pass.
|
|
|
|
|
2017-10-20 23:47:29 +02:00
|
|
|
using BBValuePair = std::pair<BasicBlock *, Value *>;
|
2012-12-19 23:10:31 +01:00
|
|
|
|
2017-10-20 23:47:29 +02:00
|
|
|
using RNVector = SmallVector<RegionNode *, 8>;
|
|
|
|
using BBVector = SmallVector<BasicBlock *, 8>;
|
|
|
|
using BranchVector = SmallVector<BranchInst *, 8>;
|
|
|
|
using BBValueVector = SmallVector<BBValuePair, 2>;
|
2012-12-19 23:10:31 +01:00
|
|
|
|
2017-10-20 23:47:29 +02:00
|
|
|
using BBSet = SmallPtrSet<BasicBlock *, 8>;
|
2013-02-08 23:24:37 +01:00
|
|
|
|
2017-10-20 23:47:29 +02:00
|
|
|
using PhiMap = MapVector<PHINode *, BBValueVector>;
|
|
|
|
using BB2BBVecMap = MapVector<BasicBlock *, BBVector>;
|
2013-03-26 11:24:20 +01:00
|
|
|
|
2017-10-20 23:47:29 +02:00
|
|
|
using BBPhiMap = DenseMap<BasicBlock *, PhiMap>;
|
|
|
|
using BBPredicates = DenseMap<BasicBlock *, Value *>;
|
|
|
|
using PredMap = DenseMap<BasicBlock *, BBPredicates>;
|
|
|
|
using BB2BBMap = DenseMap<BasicBlock *, BasicBlock *>;
|
2012-12-19 23:10:31 +01:00
|
|
|
|
[StructurizeCFG] Refactor NearestCommonDominator.
Summary:
As far as I can tell, doing our own computations in
NearestCommonDominator is a false optimization -- DomTree will build up
what appears to be exactly this data when it decides it's worthwhile.
Moreover, by building the cache ourselves, we cannot take advantage of
the cache that the domtree might have available.
In addition, I am not convinced of the correctness of the original code.
In particular, setting ResultIndex = 1 on the first addBlock instead of
setting it to 0 is quite fishy. Similarly, it's not clear to me that
setting IndexMap[Node] = 0 for every node as we walk up the tree finding
a common parent is correct. But rather than ponder over these
questions, I'd rather just make the code do the obviously-correct thing.
This patch also changes the NearestCommonDominator API a bit, improving
the names and getting rid of the boolean parameter in addBlock -- see
http://jlebar.com/2011/12/16/Boolean_parameters_to_API_functions_considered_harmful..html
Reviewers: arsenm
Subscribers: aemerson, wdng, llvm-commits
Differential Revision: https://reviews.llvm.org/D26998
llvm-svn: 288050
2016-11-28 19:49:59 +01:00
|
|
|
/// Finds the nearest common dominator of a set of BasicBlocks.
|
2013-02-16 12:27:29 +01:00
|
|
|
///
|
[StructurizeCFG] Refactor NearestCommonDominator.
Summary:
As far as I can tell, doing our own computations in
NearestCommonDominator is a false optimization -- DomTree will build up
what appears to be exactly this data when it decides it's worthwhile.
Moreover, by building the cache ourselves, we cannot take advantage of
the cache that the domtree might have available.
In addition, I am not convinced of the correctness of the original code.
In particular, setting ResultIndex = 1 on the first addBlock instead of
setting it to 0 is quite fishy. Similarly, it's not clear to me that
setting IndexMap[Node] = 0 for every node as we walk up the tree finding
a common parent is correct. But rather than ponder over these
questions, I'd rather just make the code do the obviously-correct thing.
This patch also changes the NearestCommonDominator API a bit, improving
the names and getting rid of the boolean parameter in addBlock -- see
http://jlebar.com/2011/12/16/Boolean_parameters_to_API_functions_considered_harmful..html
Reviewers: arsenm
Subscribers: aemerson, wdng, llvm-commits
Differential Revision: https://reviews.llvm.org/D26998
llvm-svn: 288050
2016-11-28 19:49:59 +01:00
|
|
|
/// For every BB you add to the set, you can specify whether we "remember" the
|
|
|
|
/// block. When you get the common dominator, you can also ask whether it's one
|
|
|
|
/// of the blocks we remembered.
|
2013-02-16 12:27:29 +01:00
|
|
|
class NearestCommonDominator {
|
|
|
|
DominatorTree *DT;
|
[StructurizeCFG] Refactor NearestCommonDominator.
Summary:
As far as I can tell, doing our own computations in
NearestCommonDominator is a false optimization -- DomTree will build up
what appears to be exactly this data when it decides it's worthwhile.
Moreover, by building the cache ourselves, we cannot take advantage of
the cache that the domtree might have available.
In addition, I am not convinced of the correctness of the original code.
In particular, setting ResultIndex = 1 on the first addBlock instead of
setting it to 0 is quite fishy. Similarly, it's not clear to me that
setting IndexMap[Node] = 0 for every node as we walk up the tree finding
a common parent is correct. But rather than ponder over these
questions, I'd rather just make the code do the obviously-correct thing.
This patch also changes the NearestCommonDominator API a bit, improving
the names and getting rid of the boolean parameter in addBlock -- see
http://jlebar.com/2011/12/16/Boolean_parameters_to_API_functions_considered_harmful..html
Reviewers: arsenm
Subscribers: aemerson, wdng, llvm-commits
Differential Revision: https://reviews.llvm.org/D26998
llvm-svn: 288050
2016-11-28 19:49:59 +01:00
|
|
|
BasicBlock *Result = nullptr;
|
|
|
|
bool ResultIsRemembered = false;
|
2013-02-16 12:27:29 +01:00
|
|
|
|
[StructurizeCFG] Refactor NearestCommonDominator.
Summary:
As far as I can tell, doing our own computations in
NearestCommonDominator is a false optimization -- DomTree will build up
what appears to be exactly this data when it decides it's worthwhile.
Moreover, by building the cache ourselves, we cannot take advantage of
the cache that the domtree might have available.
In addition, I am not convinced of the correctness of the original code.
In particular, setting ResultIndex = 1 on the first addBlock instead of
setting it to 0 is quite fishy. Similarly, it's not clear to me that
setting IndexMap[Node] = 0 for every node as we walk up the tree finding
a common parent is correct. But rather than ponder over these
questions, I'd rather just make the code do the obviously-correct thing.
This patch also changes the NearestCommonDominator API a bit, improving
the names and getting rid of the boolean parameter in addBlock -- see
http://jlebar.com/2011/12/16/Boolean_parameters_to_API_functions_considered_harmful..html
Reviewers: arsenm
Subscribers: aemerson, wdng, llvm-commits
Differential Revision: https://reviews.llvm.org/D26998
llvm-svn: 288050
2016-11-28 19:49:59 +01:00
|
|
|
/// Add BB to the resulting dominator.
|
|
|
|
void addBlock(BasicBlock *BB, bool Remember) {
|
2014-04-25 07:29:35 +02:00
|
|
|
if (!Result) {
|
2013-02-16 12:27:29 +01:00
|
|
|
Result = BB;
|
[StructurizeCFG] Refactor NearestCommonDominator.
Summary:
As far as I can tell, doing our own computations in
NearestCommonDominator is a false optimization -- DomTree will build up
what appears to be exactly this data when it decides it's worthwhile.
Moreover, by building the cache ourselves, we cannot take advantage of
the cache that the domtree might have available.
In addition, I am not convinced of the correctness of the original code.
In particular, setting ResultIndex = 1 on the first addBlock instead of
setting it to 0 is quite fishy. Similarly, it's not clear to me that
setting IndexMap[Node] = 0 for every node as we walk up the tree finding
a common parent is correct. But rather than ponder over these
questions, I'd rather just make the code do the obviously-correct thing.
This patch also changes the NearestCommonDominator API a bit, improving
the names and getting rid of the boolean parameter in addBlock -- see
http://jlebar.com/2011/12/16/Boolean_parameters_to_API_functions_considered_harmful..html
Reviewers: arsenm
Subscribers: aemerson, wdng, llvm-commits
Differential Revision: https://reviews.llvm.org/D26998
llvm-svn: 288050
2016-11-28 19:49:59 +01:00
|
|
|
ResultIsRemembered = Remember;
|
2013-02-16 12:27:29 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
[StructurizeCFG] Refactor NearestCommonDominator.
Summary:
As far as I can tell, doing our own computations in
NearestCommonDominator is a false optimization -- DomTree will build up
what appears to be exactly this data when it decides it's worthwhile.
Moreover, by building the cache ourselves, we cannot take advantage of
the cache that the domtree might have available.
In addition, I am not convinced of the correctness of the original code.
In particular, setting ResultIndex = 1 on the first addBlock instead of
setting it to 0 is quite fishy. Similarly, it's not clear to me that
setting IndexMap[Node] = 0 for every node as we walk up the tree finding
a common parent is correct. But rather than ponder over these
questions, I'd rather just make the code do the obviously-correct thing.
This patch also changes the NearestCommonDominator API a bit, improving
the names and getting rid of the boolean parameter in addBlock -- see
http://jlebar.com/2011/12/16/Boolean_parameters_to_API_functions_considered_harmful..html
Reviewers: arsenm
Subscribers: aemerson, wdng, llvm-commits
Differential Revision: https://reviews.llvm.org/D26998
llvm-svn: 288050
2016-11-28 19:49:59 +01:00
|
|
|
BasicBlock *NewResult = DT->findNearestCommonDominator(Result, BB);
|
|
|
|
if (NewResult != Result)
|
|
|
|
ResultIsRemembered = false;
|
|
|
|
if (NewResult == BB)
|
|
|
|
ResultIsRemembered |= Remember;
|
|
|
|
Result = NewResult;
|
|
|
|
}
|
2013-02-16 12:27:29 +01:00
|
|
|
|
[StructurizeCFG] Refactor NearestCommonDominator.
Summary:
As far as I can tell, doing our own computations in
NearestCommonDominator is a false optimization -- DomTree will build up
what appears to be exactly this data when it decides it's worthwhile.
Moreover, by building the cache ourselves, we cannot take advantage of
the cache that the domtree might have available.
In addition, I am not convinced of the correctness of the original code.
In particular, setting ResultIndex = 1 on the first addBlock instead of
setting it to 0 is quite fishy. Similarly, it's not clear to me that
setting IndexMap[Node] = 0 for every node as we walk up the tree finding
a common parent is correct. But rather than ponder over these
questions, I'd rather just make the code do the obviously-correct thing.
This patch also changes the NearestCommonDominator API a bit, improving
the names and getting rid of the boolean parameter in addBlock -- see
http://jlebar.com/2011/12/16/Boolean_parameters_to_API_functions_considered_harmful..html
Reviewers: arsenm
Subscribers: aemerson, wdng, llvm-commits
Differential Revision: https://reviews.llvm.org/D26998
llvm-svn: 288050
2016-11-28 19:49:59 +01:00
|
|
|
public:
|
|
|
|
explicit NearestCommonDominator(DominatorTree *DomTree) : DT(DomTree) {}
|
2013-02-16 12:27:29 +01:00
|
|
|
|
[StructurizeCFG] Refactor NearestCommonDominator.
Summary:
As far as I can tell, doing our own computations in
NearestCommonDominator is a false optimization -- DomTree will build up
what appears to be exactly this data when it decides it's worthwhile.
Moreover, by building the cache ourselves, we cannot take advantage of
the cache that the domtree might have available.
In addition, I am not convinced of the correctness of the original code.
In particular, setting ResultIndex = 1 on the first addBlock instead of
setting it to 0 is quite fishy. Similarly, it's not clear to me that
setting IndexMap[Node] = 0 for every node as we walk up the tree finding
a common parent is correct. But rather than ponder over these
questions, I'd rather just make the code do the obviously-correct thing.
This patch also changes the NearestCommonDominator API a bit, improving
the names and getting rid of the boolean parameter in addBlock -- see
http://jlebar.com/2011/12/16/Boolean_parameters_to_API_functions_considered_harmful..html
Reviewers: arsenm
Subscribers: aemerson, wdng, llvm-commits
Differential Revision: https://reviews.llvm.org/D26998
llvm-svn: 288050
2016-11-28 19:49:59 +01:00
|
|
|
void addBlock(BasicBlock *BB) {
|
|
|
|
addBlock(BB, /* Remember = */ false);
|
2013-02-16 12:27:29 +01:00
|
|
|
}
|
|
|
|
|
[StructurizeCFG] Refactor NearestCommonDominator.
Summary:
As far as I can tell, doing our own computations in
NearestCommonDominator is a false optimization -- DomTree will build up
what appears to be exactly this data when it decides it's worthwhile.
Moreover, by building the cache ourselves, we cannot take advantage of
the cache that the domtree might have available.
In addition, I am not convinced of the correctness of the original code.
In particular, setting ResultIndex = 1 on the first addBlock instead of
setting it to 0 is quite fishy. Similarly, it's not clear to me that
setting IndexMap[Node] = 0 for every node as we walk up the tree finding
a common parent is correct. But rather than ponder over these
questions, I'd rather just make the code do the obviously-correct thing.
This patch also changes the NearestCommonDominator API a bit, improving
the names and getting rid of the boolean parameter in addBlock -- see
http://jlebar.com/2011/12/16/Boolean_parameters_to_API_functions_considered_harmful..html
Reviewers: arsenm
Subscribers: aemerson, wdng, llvm-commits
Differential Revision: https://reviews.llvm.org/D26998
llvm-svn: 288050
2016-11-28 19:49:59 +01:00
|
|
|
void addAndRememberBlock(BasicBlock *BB) {
|
|
|
|
addBlock(BB, /* Remember = */ true);
|
2013-02-16 12:27:29 +01:00
|
|
|
}
|
|
|
|
|
[StructurizeCFG] Refactor NearestCommonDominator.
Summary:
As far as I can tell, doing our own computations in
NearestCommonDominator is a false optimization -- DomTree will build up
what appears to be exactly this data when it decides it's worthwhile.
Moreover, by building the cache ourselves, we cannot take advantage of
the cache that the domtree might have available.
In addition, I am not convinced of the correctness of the original code.
In particular, setting ResultIndex = 1 on the first addBlock instead of
setting it to 0 is quite fishy. Similarly, it's not clear to me that
setting IndexMap[Node] = 0 for every node as we walk up the tree finding
a common parent is correct. But rather than ponder over these
questions, I'd rather just make the code do the obviously-correct thing.
This patch also changes the NearestCommonDominator API a bit, improving
the names and getting rid of the boolean parameter in addBlock -- see
http://jlebar.com/2011/12/16/Boolean_parameters_to_API_functions_considered_harmful..html
Reviewers: arsenm
Subscribers: aemerson, wdng, llvm-commits
Differential Revision: https://reviews.llvm.org/D26998
llvm-svn: 288050
2016-11-28 19:49:59 +01:00
|
|
|
/// Get the nearest common dominator of all the BBs added via addBlock() and
|
|
|
|
/// addAndRememberBlock().
|
|
|
|
BasicBlock *result() { return Result; }
|
|
|
|
|
|
|
|
/// Is the BB returned by getResult() one of the blocks we added to the set
|
|
|
|
/// with addAndRememberBlock()?
|
|
|
|
bool resultIsRememberedBlock() { return ResultIsRemembered; }
|
2013-02-16 12:27:29 +01:00
|
|
|
};
|
|
|
|
|
2018-05-01 18:10:38 +02:00
|
|
|
/// Transforms the control flow graph on one single entry/exit region
|
2012-12-19 23:10:31 +01:00
|
|
|
/// at a time.
|
|
|
|
///
|
|
|
|
/// After the transform all "If"/"Then"/"Else" style control flow looks like
|
|
|
|
/// this:
|
|
|
|
///
|
|
|
|
/// \verbatim
|
|
|
|
/// 1
|
|
|
|
/// ||
|
|
|
|
/// | |
|
|
|
|
/// 2 |
|
|
|
|
/// | /
|
2013-06-19 22:18:24 +02:00
|
|
|
/// |/
|
2012-12-19 23:10:31 +01:00
|
|
|
/// 3
|
|
|
|
/// || Where:
|
|
|
|
/// | | 1 = "If" block, calculates the condition
|
|
|
|
/// 4 | 2 = "Then" subregion, runs if the condition is true
|
|
|
|
/// | / 3 = "Flow" blocks, newly inserted flow blocks, rejoins the flow
|
|
|
|
/// |/ 4 = "Else" optional subregion, runs if the condition is false
|
|
|
|
/// 5 5 = "End" block, also rejoins the control flow
|
|
|
|
/// \endverbatim
|
|
|
|
///
|
|
|
|
/// Control flow is expressed as a branch where the true exit goes into the
|
|
|
|
/// "Then"/"Else" region, while the false exit skips the region
|
|
|
|
/// The condition for the optional "Else" region is expressed as a PHI node.
|
2016-11-20 14:19:49 +01:00
|
|
|
/// The incoming values of the PHI node are true for the "If" edge and false
|
2012-12-19 23:10:31 +01:00
|
|
|
/// for the "Then" edge.
|
|
|
|
///
|
|
|
|
/// Additionally to that even complicated loops look like this:
|
|
|
|
///
|
|
|
|
/// \verbatim
|
|
|
|
/// 1
|
|
|
|
/// ||
|
|
|
|
/// | |
|
|
|
|
/// 2 ^ Where:
|
|
|
|
/// | / 1 = "Entry" block
|
|
|
|
/// |/ 2 = "Loop" optional subregion, with all exits at "Flow" block
|
|
|
|
/// 3 3 = "Flow" block, with back edge to entry block
|
|
|
|
/// |
|
|
|
|
/// \endverbatim
|
|
|
|
///
|
|
|
|
/// The back edge of the "Flow" block is always on the false side of the branch
|
|
|
|
/// while the true side continues the general flow. So the loop condition
|
|
|
|
/// consist of a network of PHI nodes where the true incoming values expresses
|
|
|
|
/// breaks and the false values expresses continue states.
|
2013-06-19 22:18:24 +02:00
|
|
|
class StructurizeCFG : public RegionPass {
|
2016-02-10 01:39:37 +01:00
|
|
|
bool SkipUniformRegions;
|
|
|
|
|
2012-12-19 23:10:31 +01:00
|
|
|
Type *Boolean;
|
|
|
|
ConstantInt *BoolTrue;
|
|
|
|
ConstantInt *BoolFalse;
|
|
|
|
UndefValue *BoolUndef;
|
|
|
|
|
|
|
|
Function *Func;
|
|
|
|
Region *ParentRegion;
|
|
|
|
|
2018-08-30 16:21:36 +02:00
|
|
|
LegacyDivergenceAnalysis *DA;
|
2012-12-19 23:10:31 +01:00
|
|
|
DominatorTree *DT;
|
2018-01-24 19:02:05 +01:00
|
|
|
LoopInfo *LI;
|
2012-12-19 23:10:31 +01:00
|
|
|
|
2018-01-24 19:02:05 +01:00
|
|
|
SmallVector<RegionNode *, 8> Order;
|
2013-02-08 23:24:38 +01:00
|
|
|
BBSet Visited;
|
2013-02-16 12:27:45 +01:00
|
|
|
|
2020-03-05 04:39:46 +01:00
|
|
|
SmallVector<WeakVH, 8> AffectedPhis;
|
2012-12-19 23:10:31 +01:00
|
|
|
BBPhiMap DeletedPhis;
|
2013-02-08 23:24:35 +01:00
|
|
|
BB2BBVecMap AddedPhis;
|
2013-02-16 12:27:45 +01:00
|
|
|
|
|
|
|
PredMap Predicates;
|
2013-02-08 23:24:37 +01:00
|
|
|
BranchVector Conditions;
|
2012-12-19 23:10:31 +01:00
|
|
|
|
2013-02-16 12:27:45 +01:00
|
|
|
BB2BBMap Loops;
|
|
|
|
PredMap LoopPreds;
|
|
|
|
BranchVector LoopConds;
|
2012-12-19 23:10:31 +01:00
|
|
|
|
2013-02-16 12:27:45 +01:00
|
|
|
RegionNode *PrevNode;
|
2012-12-19 23:10:31 +01:00
|
|
|
|
2013-02-16 12:27:45 +01:00
|
|
|
void orderNodes();
|
2013-02-08 23:24:37 +01:00
|
|
|
|
2018-05-23 20:34:48 +02:00
|
|
|
Loop *getAdjustedLoop(RegionNode *RN);
|
|
|
|
unsigned getAdjustedLoopDepth(RegionNode *RN);
|
|
|
|
|
2013-02-16 12:27:45 +01:00
|
|
|
void analyzeLoops(RegionNode *N);
|
2012-12-19 23:10:31 +01:00
|
|
|
|
2013-02-16 12:27:50 +01:00
|
|
|
Value *invert(Value *Condition);
|
|
|
|
|
2013-02-16 12:27:45 +01:00
|
|
|
Value *buildCondition(BranchInst *Term, unsigned Idx, bool Invert);
|
2012-12-19 23:10:31 +01:00
|
|
|
|
2013-02-16 12:27:45 +01:00
|
|
|
void gatherPredicates(RegionNode *N);
|
2012-12-19 23:10:31 +01:00
|
|
|
|
2018-01-24 19:02:05 +01:00
|
|
|
void collectInfos();
|
2012-12-19 23:10:31 +01:00
|
|
|
|
2013-02-16 12:27:45 +01:00
|
|
|
void insertConditions(bool Loops);
|
2013-02-08 23:24:37 +01:00
|
|
|
|
2013-02-08 23:24:35 +01:00
|
|
|
void delPhiValues(BasicBlock *From, BasicBlock *To);
|
|
|
|
|
|
|
|
void addPhiValues(BasicBlock *From, BasicBlock *To);
|
|
|
|
|
|
|
|
void setPhiValues();
|
|
|
|
|
2020-03-05 04:39:46 +01:00
|
|
|
void simplifyAffectedPhis();
|
|
|
|
|
2012-12-19 23:10:31 +01:00
|
|
|
void killTerminator(BasicBlock *BB);
|
|
|
|
|
2013-02-08 23:24:38 +01:00
|
|
|
void changeExit(RegionNode *Node, BasicBlock *NewExit,
|
|
|
|
bool IncludeDominator);
|
|
|
|
|
|
|
|
BasicBlock *getNextFlow(BasicBlock *Dominator);
|
|
|
|
|
2013-02-16 12:27:45 +01:00
|
|
|
BasicBlock *needPrefix(bool NeedEmpty);
|
2012-12-19 23:10:31 +01:00
|
|
|
|
2013-02-08 23:24:38 +01:00
|
|
|
BasicBlock *needPostfix(BasicBlock *Flow, bool ExitUseAllowed);
|
2012-12-19 23:10:31 +01:00
|
|
|
|
2013-02-16 12:27:45 +01:00
|
|
|
void setPrevNode(BasicBlock *BB);
|
2012-12-19 23:10:31 +01:00
|
|
|
|
2013-02-08 23:24:38 +01:00
|
|
|
bool dominatesPredicates(BasicBlock *BB, RegionNode *Node);
|
|
|
|
|
2013-02-16 12:27:45 +01:00
|
|
|
bool isPredictableTrue(RegionNode *Node);
|
|
|
|
|
|
|
|
void wireFlow(bool ExitUseAllowed, BasicBlock *LoopEnd);
|
2013-02-08 23:24:38 +01:00
|
|
|
|
2013-02-16 12:27:45 +01:00
|
|
|
void handleLoops(bool ExitUseAllowed, BasicBlock *LoopEnd);
|
2012-12-19 23:10:31 +01:00
|
|
|
|
|
|
|
void createFlow();
|
|
|
|
|
|
|
|
void rebuildSSA();
|
|
|
|
|
|
|
|
public:
|
2013-06-19 22:18:24 +02:00
|
|
|
static char ID;
|
2012-12-19 23:10:31 +01:00
|
|
|
|
2018-04-04 12:58:15 +02:00
|
|
|
explicit StructurizeCFG(bool SkipUniformRegions_ = false)
|
|
|
|
: RegionPass(ID),
|
|
|
|
SkipUniformRegions(SkipUniformRegions_) {
|
|
|
|
if (ForceSkipUniformRegions.getNumOccurrences())
|
|
|
|
SkipUniformRegions = ForceSkipUniformRegions.getValue();
|
2016-02-10 01:39:37 +01:00
|
|
|
initializeStructurizeCFGPass(*PassRegistry::getPassRegistry());
|
|
|
|
}
|
|
|
|
|
2014-03-05 10:10:37 +01:00
|
|
|
bool doInitialization(Region *R, RGPassManager &RGM) override;
|
2012-12-19 23:10:31 +01:00
|
|
|
|
2014-03-05 10:10:37 +01:00
|
|
|
bool runOnRegion(Region *R, RGPassManager &RGM) override;
|
2012-12-19 23:10:31 +01:00
|
|
|
|
2016-10-01 04:56:57 +02:00
|
|
|
StringRef getPassName() const override { return "Structurize control flow"; }
|
2012-12-19 23:10:31 +01:00
|
|
|
|
2014-03-05 10:10:37 +01:00
|
|
|
void getAnalysisUsage(AnalysisUsage &AU) const override {
|
2016-02-10 01:39:37 +01:00
|
|
|
if (SkipUniformRegions)
|
2018-08-30 16:21:36 +02:00
|
|
|
AU.addRequired<LegacyDivergenceAnalysis>();
|
2013-10-02 19:04:59 +02:00
|
|
|
AU.addRequiredID(LowerSwitchID);
|
2014-01-13 14:07:17 +01:00
|
|
|
AU.addRequired<DominatorTreeWrapperPass>();
|
2018-01-24 19:02:05 +01:00
|
|
|
AU.addRequired<LoopInfoWrapperPass>();
|
2016-11-23 00:14:07 +01:00
|
|
|
|
2014-01-13 14:07:17 +01:00
|
|
|
AU.addPreserved<DominatorTreeWrapperPass>();
|
2012-12-19 23:10:31 +01:00
|
|
|
RegionPass::getAnalysisUsage(AU);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
} // end anonymous namespace
|
|
|
|
|
2013-06-19 22:18:24 +02:00
|
|
|
char StructurizeCFG::ID = 0;
|
|
|
|
|
|
|
|
INITIALIZE_PASS_BEGIN(StructurizeCFG, "structurizecfg", "Structurize the CFG",
|
|
|
|
false, false)
|
2018-08-30 16:21:36 +02:00
|
|
|
INITIALIZE_PASS_DEPENDENCY(LegacyDivergenceAnalysis)
|
2013-10-02 19:04:59 +02:00
|
|
|
INITIALIZE_PASS_DEPENDENCY(LowerSwitch)
|
2014-01-13 14:07:17 +01:00
|
|
|
INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)
|
2014-07-19 20:29:29 +02:00
|
|
|
INITIALIZE_PASS_DEPENDENCY(RegionInfoPass)
|
2013-06-19 22:18:24 +02:00
|
|
|
INITIALIZE_PASS_END(StructurizeCFG, "structurizecfg", "Structurize the CFG",
|
|
|
|
false, false)
|
2012-12-19 23:10:31 +01:00
|
|
|
|
2018-05-01 17:54:18 +02:00
|
|
|
/// Initialize the types and constants used in the pass
|
2013-06-19 22:18:24 +02:00
|
|
|
bool StructurizeCFG::doInitialization(Region *R, RGPassManager &RGM) {
|
2012-12-19 23:10:31 +01:00
|
|
|
LLVMContext &Context = R->getEntry()->getContext();
|
|
|
|
|
|
|
|
Boolean = Type::getInt1Ty(Context);
|
|
|
|
BoolTrue = ConstantInt::getTrue(Context);
|
|
|
|
BoolFalse = ConstantInt::getFalse(Context);
|
|
|
|
BoolUndef = UndefValue::get(Boolean);
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2018-05-23 20:34:48 +02:00
|
|
|
/// Use the exit block to determine the loop if RN is a SubRegion.
|
|
|
|
Loop *StructurizeCFG::getAdjustedLoop(RegionNode *RN) {
|
|
|
|
if (RN->isSubRegion()) {
|
|
|
|
Region *SubRegion = RN->getNodeAs<Region>();
|
|
|
|
return LI->getLoopFor(SubRegion->getExit());
|
|
|
|
}
|
|
|
|
|
|
|
|
return LI->getLoopFor(RN->getEntry());
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Use the exit block to determine the loop depth if RN is a SubRegion.
|
|
|
|
unsigned StructurizeCFG::getAdjustedLoopDepth(RegionNode *RN) {
|
|
|
|
if (RN->isSubRegion()) {
|
|
|
|
Region *SubR = RN->getNodeAs<Region>();
|
|
|
|
return LI->getLoopDepth(SubR->getExit());
|
|
|
|
}
|
|
|
|
|
|
|
|
return LI->getLoopDepth(RN->getEntry());
|
|
|
|
}
|
|
|
|
|
2018-05-01 17:54:18 +02:00
|
|
|
/// Build up the general order of nodes
|
2013-06-19 22:18:24 +02:00
|
|
|
void StructurizeCFG::orderNodes() {
|
2018-01-24 19:02:05 +01:00
|
|
|
ReversePostOrderTraversal<Region*> RPOT(ParentRegion);
|
|
|
|
SmallDenseMap<Loop*, unsigned, 8> LoopBlocks;
|
|
|
|
|
|
|
|
// The reverse post-order traversal of the list gives us an ordering close
|
|
|
|
// to what we want. The only problem with it is that sometimes backedges
|
|
|
|
// for outer loops will be visited before backedges for inner loops.
|
|
|
|
for (RegionNode *RN : RPOT) {
|
2018-05-23 20:34:48 +02:00
|
|
|
Loop *Loop = getAdjustedLoop(RN);
|
2018-01-24 19:02:05 +01:00
|
|
|
++LoopBlocks[Loop];
|
2015-02-04 21:49:44 +01:00
|
|
|
}
|
2018-01-24 19:02:05 +01:00
|
|
|
|
|
|
|
unsigned CurrentLoopDepth = 0;
|
|
|
|
Loop *CurrentLoop = nullptr;
|
|
|
|
for (auto I = RPOT.begin(), E = RPOT.end(); I != E; ++I) {
|
2018-05-23 20:34:48 +02:00
|
|
|
RegionNode *RN = cast<RegionNode>(*I);
|
|
|
|
unsigned LoopDepth = getAdjustedLoopDepth(RN);
|
2018-01-24 19:02:05 +01:00
|
|
|
|
|
|
|
if (is_contained(Order, *I))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (LoopDepth < CurrentLoopDepth) {
|
|
|
|
// Make sure we have visited all blocks in this loop before moving back to
|
|
|
|
// the outer loop.
|
|
|
|
|
|
|
|
auto LoopI = I;
|
|
|
|
while (unsigned &BlockCount = LoopBlocks[CurrentLoop]) {
|
|
|
|
LoopI++;
|
2018-05-23 20:34:48 +02:00
|
|
|
if (getAdjustedLoop(cast<RegionNode>(*LoopI)) == CurrentLoop) {
|
2018-01-24 19:02:05 +01:00
|
|
|
--BlockCount;
|
|
|
|
Order.push_back(*LoopI);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-05-23 20:34:48 +02:00
|
|
|
CurrentLoop = getAdjustedLoop(RN);
|
2018-01-24 19:02:05 +01:00
|
|
|
if (CurrentLoop)
|
|
|
|
LoopBlocks[CurrentLoop]--;
|
|
|
|
|
|
|
|
CurrentLoopDepth = LoopDepth;
|
|
|
|
Order.push_back(*I);
|
|
|
|
}
|
|
|
|
|
|
|
|
// This pass originally used a post-order traversal and then operated on
|
|
|
|
// the list in reverse. Now that we are using a reverse post-order traversal
|
|
|
|
// rather than re-working the whole pass to operate on the list in order,
|
|
|
|
// we just reverse the list and continue to operate on it in reverse.
|
|
|
|
std::reverse(Order.begin(), Order.end());
|
2012-12-19 23:10:31 +01:00
|
|
|
}
|
|
|
|
|
2018-05-01 17:54:18 +02:00
|
|
|
/// Determine the end of the loops
|
2013-06-19 22:18:24 +02:00
|
|
|
void StructurizeCFG::analyzeLoops(RegionNode *N) {
|
2013-02-16 12:27:45 +01:00
|
|
|
if (N->isSubRegion()) {
|
|
|
|
// Test for exit as back edge
|
|
|
|
BasicBlock *Exit = N->getNodeAs<Region>()->getExit();
|
|
|
|
if (Visited.count(Exit))
|
|
|
|
Loops[Exit] = N->getEntry();
|
|
|
|
|
|
|
|
} else {
|
2017-07-09 07:54:44 +02:00
|
|
|
// Test for successors as back edge
|
2013-02-16 12:27:45 +01:00
|
|
|
BasicBlock *BB = N->getNodeAs<BasicBlock>();
|
|
|
|
BranchInst *Term = cast<BranchInst>(BB->getTerminator());
|
|
|
|
|
2015-08-06 22:22:46 +02:00
|
|
|
for (BasicBlock *Succ : Term->successors())
|
|
|
|
if (Visited.count(Succ))
|
2013-02-16 12:27:45 +01:00
|
|
|
Loops[Succ] = BB;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-05-01 17:54:18 +02:00
|
|
|
/// Invert the given condition
|
2013-06-19 22:18:24 +02:00
|
|
|
Value *StructurizeCFG::invert(Value *Condition) {
|
2013-02-16 12:27:50 +01:00
|
|
|
// First: Check if it's a constant
|
2016-07-16 00:13:16 +02:00
|
|
|
if (Constant *C = dyn_cast<Constant>(Condition))
|
|
|
|
return ConstantExpr::getNot(C);
|
2013-02-16 12:27:50 +01:00
|
|
|
|
|
|
|
// Second: If the condition is already inverted, return the original value
|
2018-05-15 23:41:55 +02:00
|
|
|
Value *NotCondition;
|
|
|
|
if (match(Condition, m_Not(m_Value(NotCondition))))
|
|
|
|
return NotCondition;
|
2013-02-16 12:27:50 +01:00
|
|
|
|
2013-11-22 20:24:37 +01:00
|
|
|
if (Instruction *Inst = dyn_cast<Instruction>(Condition)) {
|
|
|
|
// Third: Check all the users for an invert
|
|
|
|
BasicBlock *Parent = Inst->getParent();
|
2017-04-24 22:25:01 +02:00
|
|
|
for (User *U : Condition->users())
|
|
|
|
if (Instruction *I = dyn_cast<Instruction>(U))
|
2014-03-09 04:16:01 +01:00
|
|
|
if (I->getParent() == Parent && match(I, m_Not(m_Specific(Condition))))
|
|
|
|
return I;
|
2013-02-16 12:27:50 +01:00
|
|
|
|
2013-11-22 20:24:37 +01:00
|
|
|
// Last option: Create a new instruction
|
|
|
|
return BinaryOperator::CreateNot(Condition, "", Parent->getTerminator());
|
|
|
|
}
|
2013-02-16 12:27:50 +01:00
|
|
|
|
2013-11-22 20:24:37 +01:00
|
|
|
if (Argument *Arg = dyn_cast<Argument>(Condition)) {
|
|
|
|
BasicBlock &EntryBlock = Arg->getParent()->getEntryBlock();
|
|
|
|
return BinaryOperator::CreateNot(Condition,
|
|
|
|
Arg->getName() + ".inv",
|
|
|
|
EntryBlock.getTerminator());
|
2013-02-16 12:27:50 +01:00
|
|
|
}
|
|
|
|
|
2013-11-22 20:24:37 +01:00
|
|
|
llvm_unreachable("Unhandled condition to invert");
|
2013-02-16 12:27:50 +01:00
|
|
|
}
|
|
|
|
|
2018-05-01 17:54:18 +02:00
|
|
|
/// Build the condition for one edge
|
2013-06-19 22:18:24 +02:00
|
|
|
Value *StructurizeCFG::buildCondition(BranchInst *Term, unsigned Idx,
|
|
|
|
bool Invert) {
|
2013-02-08 23:24:37 +01:00
|
|
|
Value *Cond = Invert ? BoolFalse : BoolTrue;
|
|
|
|
if (Term->isConditional()) {
|
|
|
|
Cond = Term->getCondition();
|
2012-12-19 23:10:31 +01:00
|
|
|
|
2013-06-04 03:03:03 +02:00
|
|
|
if (Idx != (unsigned)Invert)
|
2013-02-16 12:27:50 +01:00
|
|
|
Cond = invert(Cond);
|
2013-02-08 23:24:37 +01:00
|
|
|
}
|
|
|
|
return Cond;
|
|
|
|
}
|
2012-12-19 23:10:31 +01:00
|
|
|
|
2018-05-01 17:54:18 +02:00
|
|
|
/// Analyze the predecessors of each block and build up predicates
|
2013-06-19 22:18:24 +02:00
|
|
|
void StructurizeCFG::gatherPredicates(RegionNode *N) {
|
2013-02-08 23:24:37 +01:00
|
|
|
RegionInfo *RI = ParentRegion->getRegionInfo();
|
|
|
|
BasicBlock *BB = N->getEntry();
|
|
|
|
BBPredicates &Pred = Predicates[BB];
|
2013-02-16 12:27:45 +01:00
|
|
|
BBPredicates &LPred = LoopPreds[BB];
|
2012-12-19 23:10:31 +01:00
|
|
|
|
2016-11-28 19:50:03 +01:00
|
|
|
for (BasicBlock *P : predecessors(BB)) {
|
2013-02-16 12:27:45 +01:00
|
|
|
// Ignore it if it's a branch from outside into our region entry
|
2016-11-28 19:50:03 +01:00
|
|
|
if (!ParentRegion->contains(P))
|
2013-02-08 23:24:37 +01:00
|
|
|
continue;
|
2012-12-19 23:10:31 +01:00
|
|
|
|
2016-11-28 19:50:03 +01:00
|
|
|
Region *R = RI->getRegionFor(P);
|
2013-02-08 23:24:37 +01:00
|
|
|
if (R == ParentRegion) {
|
|
|
|
// It's a top level block in our region
|
2016-11-28 19:50:03 +01:00
|
|
|
BranchInst *Term = cast<BranchInst>(P->getTerminator());
|
2013-02-08 23:24:37 +01:00
|
|
|
for (unsigned i = 0, e = Term->getNumSuccessors(); i != e; ++i) {
|
|
|
|
BasicBlock *Succ = Term->getSuccessor(i);
|
|
|
|
if (Succ != BB)
|
|
|
|
continue;
|
2012-12-19 23:10:31 +01:00
|
|
|
|
2016-11-28 19:50:03 +01:00
|
|
|
if (Visited.count(P)) {
|
2013-02-08 23:24:37 +01:00
|
|
|
// Normal forward edge
|
|
|
|
if (Term->isConditional()) {
|
|
|
|
// Try to treat it like an ELSE block
|
|
|
|
BasicBlock *Other = Term->getSuccessor(!i);
|
2013-02-16 12:27:45 +01:00
|
|
|
if (Visited.count(Other) && !Loops.count(Other) &&
|
2016-11-28 19:50:03 +01:00
|
|
|
!Pred.count(Other) && !Pred.count(P)) {
|
2013-02-08 23:24:37 +01:00
|
|
|
|
|
|
|
Pred[Other] = BoolFalse;
|
2016-11-28 19:50:03 +01:00
|
|
|
Pred[P] = BoolTrue;
|
2013-02-08 23:24:37 +01:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
2016-11-28 19:50:03 +01:00
|
|
|
Pred[P] = buildCondition(Term, i, false);
|
2013-02-08 23:24:37 +01:00
|
|
|
} else {
|
|
|
|
// Back edge
|
2016-11-28 19:50:03 +01:00
|
|
|
LPred[P] = buildCondition(Term, i, true);
|
2013-02-08 23:24:37 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// It's an exit from a sub region
|
2014-07-19 20:29:29 +02:00
|
|
|
while (R->getParent() != ParentRegion)
|
2013-02-08 23:24:37 +01:00
|
|
|
R = R->getParent();
|
|
|
|
|
|
|
|
// Edge from inside a subregion to its entry, ignore it
|
2014-07-19 20:29:29 +02:00
|
|
|
if (*R == *N)
|
2012-12-19 23:10:31 +01:00
|
|
|
continue;
|
2013-02-08 23:24:37 +01:00
|
|
|
|
|
|
|
BasicBlock *Entry = R->getEntry();
|
2013-02-16 12:27:45 +01:00
|
|
|
if (Visited.count(Entry))
|
|
|
|
Pred[Entry] = BoolTrue;
|
|
|
|
else
|
|
|
|
LPred[Entry] = BoolFalse;
|
2012-12-19 23:10:31 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-05-01 17:54:18 +02:00
|
|
|
/// Collect various loop and predicate infos
|
2018-01-24 19:02:05 +01:00
|
|
|
void StructurizeCFG::collectInfos() {
|
|
|
|
// Reset predicate
|
|
|
|
Predicates.clear();
|
|
|
|
|
|
|
|
// and loop infos
|
|
|
|
Loops.clear();
|
|
|
|
LoopPreds.clear();
|
2012-12-19 23:10:31 +01:00
|
|
|
|
2018-01-24 19:02:05 +01:00
|
|
|
// Reset the visited nodes
|
|
|
|
Visited.clear();
|
|
|
|
|
|
|
|
for (RegionNode *RN : reverse(Order)) {
|
2018-05-14 14:53:11 +02:00
|
|
|
LLVM_DEBUG(dbgs() << "Visiting: "
|
|
|
|
<< (RN->isSubRegion() ? "SubRegion with entry: " : "")
|
|
|
|
<< RN->getEntry()->getName() << " Loop Depth: "
|
|
|
|
<< LI->getLoopDepth(RN->getEntry()) << "\n");
|
2018-01-24 19:02:05 +01:00
|
|
|
|
|
|
|
// Analyze all the conditions leading to a node
|
|
|
|
gatherPredicates(RN);
|
2012-12-19 23:10:31 +01:00
|
|
|
|
2018-01-24 19:02:05 +01:00
|
|
|
// Remember that we've seen this node
|
|
|
|
Visited.insert(RN->getEntry());
|
2012-12-19 23:10:31 +01:00
|
|
|
|
2018-01-24 19:02:05 +01:00
|
|
|
// Find the last back edges
|
|
|
|
analyzeLoops(RN);
|
|
|
|
}
|
2013-02-08 23:24:37 +01:00
|
|
|
}
|
|
|
|
|
2018-05-01 17:54:18 +02:00
|
|
|
/// Insert the missing branch conditions
|
2013-06-19 22:18:24 +02:00
|
|
|
void StructurizeCFG::insertConditions(bool Loops) {
|
2013-02-16 12:27:45 +01:00
|
|
|
BranchVector &Conds = Loops ? LoopConds : Conditions;
|
|
|
|
Value *Default = Loops ? BoolTrue : BoolFalse;
|
2013-02-08 23:24:37 +01:00
|
|
|
SSAUpdater PhiInserter;
|
|
|
|
|
2014-05-19 19:52:48 +02:00
|
|
|
for (BranchInst *Term : Conds) {
|
2013-02-08 23:24:37 +01:00
|
|
|
assert(Term->isConditional());
|
|
|
|
|
2013-02-16 12:27:45 +01:00
|
|
|
BasicBlock *Parent = Term->getParent();
|
|
|
|
BasicBlock *SuccTrue = Term->getSuccessor(0);
|
|
|
|
BasicBlock *SuccFalse = Term->getSuccessor(1);
|
2013-02-16 12:27:40 +01:00
|
|
|
|
2013-02-08 23:24:37 +01:00
|
|
|
PhiInserter.Initialize(Boolean, "");
|
2013-02-16 12:27:40 +01:00
|
|
|
PhiInserter.AddAvailableValue(&Func->getEntryBlock(), Default);
|
2013-02-16 12:27:45 +01:00
|
|
|
PhiInserter.AddAvailableValue(Loops ? SuccFalse : Parent, Default);
|
2013-02-08 23:24:37 +01:00
|
|
|
|
2013-02-16 12:27:45 +01:00
|
|
|
BBPredicates &Preds = Loops ? LoopPreds[SuccFalse] : Predicates[SuccTrue];
|
2013-02-16 12:27:40 +01:00
|
|
|
|
|
|
|
NearestCommonDominator Dominator(DT);
|
[StructurizeCFG] Refactor NearestCommonDominator.
Summary:
As far as I can tell, doing our own computations in
NearestCommonDominator is a false optimization -- DomTree will build up
what appears to be exactly this data when it decides it's worthwhile.
Moreover, by building the cache ourselves, we cannot take advantage of
the cache that the domtree might have available.
In addition, I am not convinced of the correctness of the original code.
In particular, setting ResultIndex = 1 on the first addBlock instead of
setting it to 0 is quite fishy. Similarly, it's not clear to me that
setting IndexMap[Node] = 0 for every node as we walk up the tree finding
a common parent is correct. But rather than ponder over these
questions, I'd rather just make the code do the obviously-correct thing.
This patch also changes the NearestCommonDominator API a bit, improving
the names and getting rid of the boolean parameter in addBlock -- see
http://jlebar.com/2011/12/16/Boolean_parameters_to_API_functions_considered_harmful..html
Reviewers: arsenm
Subscribers: aemerson, wdng, llvm-commits
Differential Revision: https://reviews.llvm.org/D26998
llvm-svn: 288050
2016-11-28 19:49:59 +01:00
|
|
|
Dominator.addBlock(Parent);
|
2013-02-16 12:27:40 +01:00
|
|
|
|
2014-04-25 07:29:35 +02:00
|
|
|
Value *ParentValue = nullptr;
|
2016-11-28 19:50:03 +01:00
|
|
|
for (std::pair<BasicBlock *, Value *> BBAndPred : Preds) {
|
|
|
|
BasicBlock *BB = BBAndPred.first;
|
|
|
|
Value *Pred = BBAndPred.second;
|
2013-02-08 23:24:37 +01:00
|
|
|
|
2016-11-28 19:50:03 +01:00
|
|
|
if (BB == Parent) {
|
|
|
|
ParentValue = Pred;
|
2013-02-16 12:27:40 +01:00
|
|
|
break;
|
|
|
|
}
|
2016-11-28 19:50:03 +01:00
|
|
|
PhiInserter.AddAvailableValue(BB, Pred);
|
|
|
|
Dominator.addAndRememberBlock(BB);
|
2013-02-08 23:24:37 +01:00
|
|
|
}
|
|
|
|
|
2013-02-16 12:27:40 +01:00
|
|
|
if (ParentValue) {
|
|
|
|
Term->setCondition(ParentValue);
|
|
|
|
} else {
|
[StructurizeCFG] Refactor NearestCommonDominator.
Summary:
As far as I can tell, doing our own computations in
NearestCommonDominator is a false optimization -- DomTree will build up
what appears to be exactly this data when it decides it's worthwhile.
Moreover, by building the cache ourselves, we cannot take advantage of
the cache that the domtree might have available.
In addition, I am not convinced of the correctness of the original code.
In particular, setting ResultIndex = 1 on the first addBlock instead of
setting it to 0 is quite fishy. Similarly, it's not clear to me that
setting IndexMap[Node] = 0 for every node as we walk up the tree finding
a common parent is correct. But rather than ponder over these
questions, I'd rather just make the code do the obviously-correct thing.
This patch also changes the NearestCommonDominator API a bit, improving
the names and getting rid of the boolean parameter in addBlock -- see
http://jlebar.com/2011/12/16/Boolean_parameters_to_API_functions_considered_harmful..html
Reviewers: arsenm
Subscribers: aemerson, wdng, llvm-commits
Differential Revision: https://reviews.llvm.org/D26998
llvm-svn: 288050
2016-11-28 19:49:59 +01:00
|
|
|
if (!Dominator.resultIsRememberedBlock())
|
|
|
|
PhiInserter.AddAvailableValue(Dominator.result(), Default);
|
2013-02-16 12:27:40 +01:00
|
|
|
|
2013-02-08 23:24:37 +01:00
|
|
|
Term->setCondition(PhiInserter.GetValueInMiddleOfBlock(Parent));
|
2013-02-16 12:27:40 +01:00
|
|
|
}
|
2012-12-19 23:10:31 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-05-01 17:54:18 +02:00
|
|
|
/// Remove all PHI values coming from "From" into "To" and remember
|
2013-02-08 23:24:35 +01:00
|
|
|
/// them in DeletedPhis
|
2013-06-19 22:18:24 +02:00
|
|
|
void StructurizeCFG::delPhiValues(BasicBlock *From, BasicBlock *To) {
|
2013-02-08 23:24:35 +01:00
|
|
|
PhiMap &Map = DeletedPhis[To];
|
2017-12-29 20:25:57 +01:00
|
|
|
for (PHINode &Phi : To->phis()) {
|
2020-03-05 04:39:46 +01:00
|
|
|
bool Recorded = false;
|
2013-02-08 23:24:35 +01:00
|
|
|
while (Phi.getBasicBlockIndex(From) != -1) {
|
|
|
|
Value *Deleted = Phi.removeIncomingValue(From, false);
|
|
|
|
Map[&Phi].push_back(std::make_pair(From, Deleted));
|
2020-03-05 04:39:46 +01:00
|
|
|
if (!Recorded) {
|
|
|
|
AffectedPhis.push_back(&Phi);
|
|
|
|
Recorded = true;
|
|
|
|
}
|
2013-02-08 23:24:35 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-05-01 17:54:18 +02:00
|
|
|
/// Add a dummy PHI value as soon as we knew the new predecessor
|
2013-06-19 22:18:24 +02:00
|
|
|
void StructurizeCFG::addPhiValues(BasicBlock *From, BasicBlock *To) {
|
2017-12-29 20:25:57 +01:00
|
|
|
for (PHINode &Phi : To->phis()) {
|
2013-02-08 23:24:35 +01:00
|
|
|
Value *Undef = UndefValue::get(Phi.getType());
|
|
|
|
Phi.addIncoming(Undef, From);
|
|
|
|
}
|
|
|
|
AddedPhis[To].push_back(From);
|
|
|
|
}
|
|
|
|
|
2018-05-01 17:54:18 +02:00
|
|
|
/// Add the real PHI value as soon as everything is set up
|
2013-06-19 22:18:24 +02:00
|
|
|
void StructurizeCFG::setPhiValues() {
|
2018-10-17 17:37:41 +02:00
|
|
|
SmallVector<PHINode *, 8> InsertedPhis;
|
|
|
|
SSAUpdater Updater(&InsertedPhis);
|
2016-06-26 14:28:59 +02:00
|
|
|
for (const auto &AddedPhi : AddedPhis) {
|
|
|
|
BasicBlock *To = AddedPhi.first;
|
|
|
|
const BBVector &From = AddedPhi.second;
|
2013-02-08 23:24:35 +01:00
|
|
|
|
|
|
|
if (!DeletedPhis.count(To))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
PhiMap &Map = DeletedPhis[To];
|
2016-06-26 14:28:59 +02:00
|
|
|
for (const auto &PI : Map) {
|
|
|
|
PHINode *Phi = PI.first;
|
2013-02-08 23:24:35 +01:00
|
|
|
Value *Undef = UndefValue::get(Phi->getType());
|
|
|
|
Updater.Initialize(Phi->getType(), "");
|
|
|
|
Updater.AddAvailableValue(&Func->getEntryBlock(), Undef);
|
|
|
|
Updater.AddAvailableValue(To, Undef);
|
|
|
|
|
2013-02-16 12:27:35 +01:00
|
|
|
NearestCommonDominator Dominator(DT);
|
[StructurizeCFG] Refactor NearestCommonDominator.
Summary:
As far as I can tell, doing our own computations in
NearestCommonDominator is a false optimization -- DomTree will build up
what appears to be exactly this data when it decides it's worthwhile.
Moreover, by building the cache ourselves, we cannot take advantage of
the cache that the domtree might have available.
In addition, I am not convinced of the correctness of the original code.
In particular, setting ResultIndex = 1 on the first addBlock instead of
setting it to 0 is quite fishy. Similarly, it's not clear to me that
setting IndexMap[Node] = 0 for every node as we walk up the tree finding
a common parent is correct. But rather than ponder over these
questions, I'd rather just make the code do the obviously-correct thing.
This patch also changes the NearestCommonDominator API a bit, improving
the names and getting rid of the boolean parameter in addBlock -- see
http://jlebar.com/2011/12/16/Boolean_parameters_to_API_functions_considered_harmful..html
Reviewers: arsenm
Subscribers: aemerson, wdng, llvm-commits
Differential Revision: https://reviews.llvm.org/D26998
llvm-svn: 288050
2016-11-28 19:49:59 +01:00
|
|
|
Dominator.addBlock(To);
|
2016-06-26 14:28:59 +02:00
|
|
|
for (const auto &VI : PI.second) {
|
|
|
|
Updater.AddAvailableValue(VI.first, VI.second);
|
[StructurizeCFG] Refactor NearestCommonDominator.
Summary:
As far as I can tell, doing our own computations in
NearestCommonDominator is a false optimization -- DomTree will build up
what appears to be exactly this data when it decides it's worthwhile.
Moreover, by building the cache ourselves, we cannot take advantage of
the cache that the domtree might have available.
In addition, I am not convinced of the correctness of the original code.
In particular, setting ResultIndex = 1 on the first addBlock instead of
setting it to 0 is quite fishy. Similarly, it's not clear to me that
setting IndexMap[Node] = 0 for every node as we walk up the tree finding
a common parent is correct. But rather than ponder over these
questions, I'd rather just make the code do the obviously-correct thing.
This patch also changes the NearestCommonDominator API a bit, improving
the names and getting rid of the boolean parameter in addBlock -- see
http://jlebar.com/2011/12/16/Boolean_parameters_to_API_functions_considered_harmful..html
Reviewers: arsenm
Subscribers: aemerson, wdng, llvm-commits
Differential Revision: https://reviews.llvm.org/D26998
llvm-svn: 288050
2016-11-28 19:49:59 +01:00
|
|
|
Dominator.addAndRememberBlock(VI.first);
|
2013-02-08 23:24:35 +01:00
|
|
|
}
|
|
|
|
|
[StructurizeCFG] Refactor NearestCommonDominator.
Summary:
As far as I can tell, doing our own computations in
NearestCommonDominator is a false optimization -- DomTree will build up
what appears to be exactly this data when it decides it's worthwhile.
Moreover, by building the cache ourselves, we cannot take advantage of
the cache that the domtree might have available.
In addition, I am not convinced of the correctness of the original code.
In particular, setting ResultIndex = 1 on the first addBlock instead of
setting it to 0 is quite fishy. Similarly, it's not clear to me that
setting IndexMap[Node] = 0 for every node as we walk up the tree finding
a common parent is correct. But rather than ponder over these
questions, I'd rather just make the code do the obviously-correct thing.
This patch also changes the NearestCommonDominator API a bit, improving
the names and getting rid of the boolean parameter in addBlock -- see
http://jlebar.com/2011/12/16/Boolean_parameters_to_API_functions_considered_harmful..html
Reviewers: arsenm
Subscribers: aemerson, wdng, llvm-commits
Differential Revision: https://reviews.llvm.org/D26998
llvm-svn: 288050
2016-11-28 19:49:59 +01:00
|
|
|
if (!Dominator.resultIsRememberedBlock())
|
|
|
|
Updater.AddAvailableValue(Dominator.result(), Undef);
|
2013-02-16 12:27:35 +01:00
|
|
|
|
PHINode: introduce setIncomingValueForBlock() function, and use it.
Summary:
There is PHINode::getBasicBlockIndex() and PHINode::setIncomingValue()
but no function to replace incoming value for a specified BasicBlock*
predecessor.
Clearly, there are a lot of places that could use that functionality.
Reviewer: craig.topper, lebedev.ri, Meinersbur, kbarton, fhahn
Reviewed By: Meinersbur, fhahn
Subscribers: fhahn, hiraditya, zzheng, jsji, llvm-commits
Tag: LLVM
Differential Revision: https://reviews.llvm.org/D63338
llvm-svn: 363566
2019-06-17 16:38:56 +02:00
|
|
|
for (BasicBlock *FI : From)
|
|
|
|
Phi->setIncomingValueForBlock(FI, Updater.GetValueAtEndOfBlock(FI));
|
2020-03-05 04:39:46 +01:00
|
|
|
AffectedPhis.push_back(Phi);
|
2013-02-08 23:24:35 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
DeletedPhis.erase(To);
|
|
|
|
}
|
|
|
|
assert(DeletedPhis.empty());
|
2018-10-17 17:37:41 +02:00
|
|
|
|
2020-03-05 04:39:46 +01:00
|
|
|
AffectedPhis.append(InsertedPhis.begin(), InsertedPhis.end());
|
|
|
|
}
|
|
|
|
|
|
|
|
void StructurizeCFG::simplifyAffectedPhis() {
|
2018-10-17 17:37:41 +02:00
|
|
|
bool Changed;
|
|
|
|
do {
|
|
|
|
Changed = false;
|
|
|
|
SimplifyQuery Q(Func->getParent()->getDataLayout());
|
|
|
|
Q.DT = DT;
|
2020-03-05 04:39:46 +01:00
|
|
|
for (WeakVH VH : AffectedPhis) {
|
|
|
|
if (auto Phi = dyn_cast_or_null<PHINode>(VH)) {
|
|
|
|
if (auto NewValue = SimplifyInstruction(Phi, Q)) {
|
|
|
|
Phi->replaceAllUsesWith(NewValue);
|
|
|
|
Phi->eraseFromParent();
|
|
|
|
Changed = true;
|
|
|
|
}
|
2018-10-17 17:37:41 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} while (Changed);
|
2013-02-08 23:24:35 +01:00
|
|
|
}
|
|
|
|
|
2018-05-01 17:54:18 +02:00
|
|
|
/// Remove phi values from all successors and then remove the terminator.
|
2013-06-19 22:18:24 +02:00
|
|
|
void StructurizeCFG::killTerminator(BasicBlock *BB) {
|
2018-10-15 12:04:59 +02:00
|
|
|
Instruction *Term = BB->getTerminator();
|
2012-12-19 23:10:31 +01:00
|
|
|
if (!Term)
|
|
|
|
return;
|
|
|
|
|
2014-07-21 19:06:51 +02:00
|
|
|
for (succ_iterator SI = succ_begin(BB), SE = succ_end(BB);
|
2016-11-28 19:50:03 +01:00
|
|
|
SI != SE; ++SI)
|
2014-07-21 19:06:51 +02:00
|
|
|
delPhiValues(BB, *SI);
|
2012-12-19 23:10:31 +01:00
|
|
|
|
2018-04-04 12:58:15 +02:00
|
|
|
if (DA)
|
|
|
|
DA->removeValue(Term);
|
2012-12-19 23:10:31 +01:00
|
|
|
Term->eraseFromParent();
|
|
|
|
}
|
|
|
|
|
2018-05-01 17:54:18 +02:00
|
|
|
/// Let node exit(s) point to NewExit
|
2013-06-19 22:18:24 +02:00
|
|
|
void StructurizeCFG::changeExit(RegionNode *Node, BasicBlock *NewExit,
|
|
|
|
bool IncludeDominator) {
|
2013-02-08 23:24:38 +01:00
|
|
|
if (Node->isSubRegion()) {
|
|
|
|
Region *SubRegion = Node->getNodeAs<Region>();
|
|
|
|
BasicBlock *OldExit = SubRegion->getExit();
|
2014-04-25 07:29:35 +02:00
|
|
|
BasicBlock *Dominator = nullptr;
|
2012-12-19 23:10:31 +01:00
|
|
|
|
2013-02-08 23:24:38 +01:00
|
|
|
// Find all the edges from the sub region to the exit
|
2016-11-28 19:50:03 +01:00
|
|
|
for (auto BBI = pred_begin(OldExit), E = pred_end(OldExit); BBI != E;) {
|
|
|
|
// Incrememt BBI before mucking with BB's terminator.
|
|
|
|
BasicBlock *BB = *BBI++;
|
2014-07-21 19:06:51 +02:00
|
|
|
|
2013-02-08 23:24:38 +01:00
|
|
|
if (!SubRegion->contains(BB))
|
|
|
|
continue;
|
2012-12-19 23:10:31 +01:00
|
|
|
|
2013-02-08 23:24:38 +01:00
|
|
|
// Modify the edges to point to the new exit
|
|
|
|
delPhiValues(BB, OldExit);
|
|
|
|
BB->getTerminator()->replaceUsesOfWith(OldExit, NewExit);
|
|
|
|
addPhiValues(BB, NewExit);
|
|
|
|
|
|
|
|
// Find the new dominator (if requested)
|
|
|
|
if (IncludeDominator) {
|
|
|
|
if (!Dominator)
|
|
|
|
Dominator = BB;
|
|
|
|
else
|
|
|
|
Dominator = DT->findNearestCommonDominator(Dominator, BB);
|
|
|
|
}
|
|
|
|
}
|
2012-12-19 23:10:31 +01:00
|
|
|
|
2013-02-08 23:24:38 +01:00
|
|
|
// Change the dominator (if requested)
|
|
|
|
if (Dominator)
|
|
|
|
DT->changeImmediateDominator(NewExit, Dominator);
|
2012-12-19 23:10:31 +01:00
|
|
|
|
2013-02-08 23:24:38 +01:00
|
|
|
// Update the region info
|
|
|
|
SubRegion->replaceExit(NewExit);
|
2012-12-19 23:10:31 +01:00
|
|
|
} else {
|
2013-02-08 23:24:38 +01:00
|
|
|
BasicBlock *BB = Node->getNodeAs<BasicBlock>();
|
|
|
|
killTerminator(BB);
|
|
|
|
BranchInst::Create(NewExit, BB);
|
|
|
|
addPhiValues(BB, NewExit);
|
|
|
|
if (IncludeDominator)
|
|
|
|
DT->changeImmediateDominator(NewExit, BB);
|
2012-12-19 23:10:31 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-05-01 17:54:18 +02:00
|
|
|
/// Create a new flow node and update dominator tree and region info
|
2013-06-19 22:18:24 +02:00
|
|
|
BasicBlock *StructurizeCFG::getNextFlow(BasicBlock *Dominator) {
|
2012-12-19 23:10:31 +01:00
|
|
|
LLVMContext &Context = Func->getContext();
|
|
|
|
BasicBlock *Insert = Order.empty() ? ParentRegion->getExit() :
|
2018-01-24 19:02:05 +01:00
|
|
|
Order.back()->getEntry();
|
2012-12-19 23:10:31 +01:00
|
|
|
BasicBlock *Flow = BasicBlock::Create(Context, FlowBlockName,
|
|
|
|
Func, Insert);
|
2013-02-08 23:24:38 +01:00
|
|
|
DT->addNewBlock(Flow, Dominator);
|
2012-12-19 23:10:31 +01:00
|
|
|
ParentRegion->getRegionInfo()->setRegionFor(Flow, ParentRegion);
|
|
|
|
return Flow;
|
|
|
|
}
|
|
|
|
|
2018-05-01 17:54:18 +02:00
|
|
|
/// Create a new or reuse the previous node as flow node
|
2013-06-19 22:18:24 +02:00
|
|
|
BasicBlock *StructurizeCFG::needPrefix(bool NeedEmpty) {
|
2013-02-16 12:27:45 +01:00
|
|
|
BasicBlock *Entry = PrevNode->getEntry();
|
2013-02-08 23:24:38 +01:00
|
|
|
|
2013-02-16 12:27:45 +01:00
|
|
|
if (!PrevNode->isSubRegion()) {
|
|
|
|
killTerminator(Entry);
|
|
|
|
if (!NeedEmpty || Entry->getFirstInsertionPt() == Entry->end())
|
|
|
|
return Entry;
|
2013-06-19 22:18:24 +02:00
|
|
|
}
|
2013-02-08 23:24:38 +01:00
|
|
|
|
2013-02-16 12:27:45 +01:00
|
|
|
// create a new flow node
|
|
|
|
BasicBlock *Flow = getNextFlow(Entry);
|
2013-02-08 23:24:38 +01:00
|
|
|
|
2013-02-16 12:27:45 +01:00
|
|
|
// and wire it up
|
|
|
|
changeExit(PrevNode, Flow, true);
|
|
|
|
PrevNode = ParentRegion->getBBNode(Flow);
|
|
|
|
return Flow;
|
2013-02-08 23:24:38 +01:00
|
|
|
}
|
|
|
|
|
2018-05-01 17:54:18 +02:00
|
|
|
/// Returns the region exit if possible, otherwise just a new flow node
|
2013-06-19 22:18:24 +02:00
|
|
|
BasicBlock *StructurizeCFG::needPostfix(BasicBlock *Flow,
|
|
|
|
bool ExitUseAllowed) {
|
2016-11-28 19:50:03 +01:00
|
|
|
if (!Order.empty() || !ExitUseAllowed)
|
|
|
|
return getNextFlow(Flow);
|
|
|
|
|
|
|
|
BasicBlock *Exit = ParentRegion->getExit();
|
|
|
|
DT->changeImmediateDominator(Exit, Flow);
|
|
|
|
addPhiValues(Flow, Exit);
|
|
|
|
return Exit;
|
2013-02-08 23:24:38 +01:00
|
|
|
}
|
|
|
|
|
2018-05-01 17:54:18 +02:00
|
|
|
/// Set the previous node
|
2013-06-19 22:18:24 +02:00
|
|
|
void StructurizeCFG::setPrevNode(BasicBlock *BB) {
|
2014-04-25 07:29:35 +02:00
|
|
|
PrevNode = ParentRegion->contains(BB) ? ParentRegion->getBBNode(BB)
|
|
|
|
: nullptr;
|
2013-02-08 23:24:38 +01:00
|
|
|
}
|
|
|
|
|
2018-05-01 17:54:18 +02:00
|
|
|
/// Does BB dominate all the predicates of Node?
|
2013-06-19 22:18:24 +02:00
|
|
|
bool StructurizeCFG::dominatesPredicates(BasicBlock *BB, RegionNode *Node) {
|
2013-02-08 23:24:38 +01:00
|
|
|
BBPredicates &Preds = Predicates[Node->getEntry()];
|
2016-11-28 19:50:03 +01:00
|
|
|
return llvm::all_of(Preds, [&](std::pair<BasicBlock *, Value *> Pred) {
|
|
|
|
return DT->dominates(BB, Pred.first);
|
|
|
|
});
|
2013-02-08 23:24:38 +01:00
|
|
|
}
|
|
|
|
|
2018-05-01 17:54:18 +02:00
|
|
|
/// Can we predict that this node will always be called?
|
2013-06-19 22:18:24 +02:00
|
|
|
bool StructurizeCFG::isPredictableTrue(RegionNode *Node) {
|
2013-02-16 12:27:45 +01:00
|
|
|
BBPredicates &Preds = Predicates[Node->getEntry()];
|
|
|
|
bool Dominated = false;
|
|
|
|
|
|
|
|
// Regionentry is always true
|
2014-04-25 07:29:35 +02:00
|
|
|
if (!PrevNode)
|
2013-02-16 12:27:45 +01:00
|
|
|
return true;
|
2012-12-19 23:10:31 +01:00
|
|
|
|
2016-11-28 19:50:03 +01:00
|
|
|
for (std::pair<BasicBlock*, Value*> Pred : Preds) {
|
|
|
|
BasicBlock *BB = Pred.first;
|
|
|
|
Value *V = Pred.second;
|
2012-12-19 23:10:31 +01:00
|
|
|
|
2016-11-28 19:50:03 +01:00
|
|
|
if (V != BoolTrue)
|
2012-12-19 23:10:31 +01:00
|
|
|
return false;
|
|
|
|
|
2016-11-28 19:50:03 +01:00
|
|
|
if (!Dominated && DT->dominates(BB, PrevNode->getEntry()))
|
2012-12-19 23:10:31 +01:00
|
|
|
Dominated = true;
|
|
|
|
}
|
2013-02-08 23:24:38 +01:00
|
|
|
|
|
|
|
// TODO: The dominator check is too strict
|
2012-12-19 23:10:31 +01:00
|
|
|
return Dominated;
|
|
|
|
}
|
|
|
|
|
2013-02-08 23:24:38 +01:00
|
|
|
/// Take one node from the order vector and wire it up
|
2013-06-19 22:18:24 +02:00
|
|
|
void StructurizeCFG::wireFlow(bool ExitUseAllowed,
|
|
|
|
BasicBlock *LoopEnd) {
|
2018-01-24 19:02:05 +01:00
|
|
|
RegionNode *Node = Order.pop_back_val();
|
2013-02-16 12:27:45 +01:00
|
|
|
Visited.insert(Node->getEntry());
|
2012-12-19 23:10:31 +01:00
|
|
|
|
2013-02-16 12:27:45 +01:00
|
|
|
if (isPredictableTrue(Node)) {
|
2013-02-08 23:24:38 +01:00
|
|
|
// Just a linear flow
|
2013-02-16 12:27:45 +01:00
|
|
|
if (PrevNode) {
|
|
|
|
changeExit(PrevNode, Node->getEntry(), true);
|
2013-02-08 23:24:38 +01:00
|
|
|
}
|
2013-02-16 12:27:45 +01:00
|
|
|
PrevNode = Node;
|
2012-12-19 23:10:31 +01:00
|
|
|
} else {
|
2013-02-08 23:24:38 +01:00
|
|
|
// Insert extra prefix node (or reuse last one)
|
2013-02-16 12:27:45 +01:00
|
|
|
BasicBlock *Flow = needPrefix(false);
|
2012-12-19 23:10:31 +01:00
|
|
|
|
2013-02-08 23:24:38 +01:00
|
|
|
// Insert extra postfix node (or use exit instead)
|
|
|
|
BasicBlock *Entry = Node->getEntry();
|
2013-02-16 12:27:45 +01:00
|
|
|
BasicBlock *Next = needPostfix(Flow, ExitUseAllowed);
|
2013-02-08 23:24:38 +01:00
|
|
|
|
|
|
|
// let it point to entry and next block
|
|
|
|
Conditions.push_back(BranchInst::Create(Entry, Next, BoolUndef, Flow));
|
|
|
|
addPhiValues(Flow, Entry);
|
|
|
|
DT->changeImmediateDominator(Entry, Flow);
|
|
|
|
|
2013-02-16 12:27:45 +01:00
|
|
|
PrevNode = Node;
|
|
|
|
while (!Order.empty() && !Visited.count(LoopEnd) &&
|
2018-01-24 19:02:05 +01:00
|
|
|
dominatesPredicates(Entry, Order.back())) {
|
2013-02-16 12:27:45 +01:00
|
|
|
handleLoops(false, LoopEnd);
|
2012-12-19 23:10:31 +01:00
|
|
|
}
|
|
|
|
|
2013-02-16 12:27:45 +01:00
|
|
|
changeExit(PrevNode, Next, false);
|
|
|
|
setPrevNode(Next);
|
2012-12-19 23:10:31 +01:00
|
|
|
}
|
2013-02-16 12:27:45 +01:00
|
|
|
}
|
2012-12-19 23:10:31 +01:00
|
|
|
|
2013-06-19 22:18:24 +02:00
|
|
|
void StructurizeCFG::handleLoops(bool ExitUseAllowed,
|
|
|
|
BasicBlock *LoopEnd) {
|
2018-01-24 19:02:05 +01:00
|
|
|
RegionNode *Node = Order.back();
|
2013-02-16 12:27:45 +01:00
|
|
|
BasicBlock *LoopStart = Node->getEntry();
|
|
|
|
|
|
|
|
if (!Loops.count(LoopStart)) {
|
|
|
|
wireFlow(ExitUseAllowed, LoopEnd);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!isPredictableTrue(Node))
|
|
|
|
LoopStart = needPrefix(true);
|
|
|
|
|
|
|
|
LoopEnd = Loops[Node->getEntry()];
|
|
|
|
wireFlow(false, LoopEnd);
|
|
|
|
while (!Visited.count(LoopEnd)) {
|
|
|
|
handleLoops(false, LoopEnd);
|
|
|
|
}
|
|
|
|
|
2013-11-22 20:24:39 +01:00
|
|
|
// If the start of the loop is the entry block, we can't branch to it so
|
|
|
|
// insert a new dummy entry block.
|
|
|
|
Function *LoopFunc = LoopStart->getParent();
|
|
|
|
if (LoopStart == &LoopFunc->getEntryBlock()) {
|
|
|
|
LoopStart->setName("entry.orig");
|
|
|
|
|
|
|
|
BasicBlock *NewEntry =
|
|
|
|
BasicBlock::Create(LoopStart->getContext(),
|
|
|
|
"entry",
|
|
|
|
LoopFunc,
|
|
|
|
LoopStart);
|
|
|
|
BranchInst::Create(LoopStart, NewEntry);
|
2017-01-10 03:50:47 +01:00
|
|
|
DT->setNewRoot(NewEntry);
|
2013-11-22 20:24:39 +01:00
|
|
|
}
|
|
|
|
|
2013-02-16 12:27:45 +01:00
|
|
|
// Create an extra loop end node
|
|
|
|
LoopEnd = needPrefix(false);
|
|
|
|
BasicBlock *Next = needPostfix(LoopEnd, ExitUseAllowed);
|
|
|
|
LoopConds.push_back(BranchInst::Create(Next, LoopStart,
|
|
|
|
BoolUndef, LoopEnd));
|
|
|
|
addPhiValues(LoopEnd, LoopStart);
|
|
|
|
setPrevNode(Next);
|
2012-12-19 23:10:31 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/// After this function control flow looks like it should be, but
|
2013-02-08 23:24:38 +01:00
|
|
|
/// branches and PHI nodes only have undefined conditions.
|
2013-06-19 22:18:24 +02:00
|
|
|
void StructurizeCFG::createFlow() {
|
2013-02-08 23:24:38 +01:00
|
|
|
BasicBlock *Exit = ParentRegion->getExit();
|
|
|
|
bool EntryDominatesExit = DT->dominates(ParentRegion->getEntry(), Exit);
|
|
|
|
|
2020-03-05 04:39:46 +01:00
|
|
|
AffectedPhis.clear();
|
2012-12-19 23:10:31 +01:00
|
|
|
DeletedPhis.clear();
|
2013-02-08 23:24:35 +01:00
|
|
|
AddedPhis.clear();
|
2013-02-08 23:24:38 +01:00
|
|
|
Conditions.clear();
|
2013-02-16 12:27:45 +01:00
|
|
|
LoopConds.clear();
|
2012-12-19 23:10:31 +01:00
|
|
|
|
2014-04-25 07:29:35 +02:00
|
|
|
PrevNode = nullptr;
|
2013-02-16 12:27:45 +01:00
|
|
|
Visited.clear();
|
2013-02-08 23:24:38 +01:00
|
|
|
|
2013-02-16 12:27:45 +01:00
|
|
|
while (!Order.empty()) {
|
2014-04-25 07:29:35 +02:00
|
|
|
handleLoops(EntryDominatesExit, nullptr);
|
2012-12-19 23:10:31 +01:00
|
|
|
}
|
|
|
|
|
2013-02-16 12:27:45 +01:00
|
|
|
if (PrevNode)
|
|
|
|
changeExit(PrevNode, Exit, EntryDominatesExit);
|
2013-02-08 23:24:38 +01:00
|
|
|
else
|
|
|
|
assert(EntryDominatesExit);
|
2012-12-19 23:10:31 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Handle a rare case where the disintegrated nodes instructions
|
2018-06-14 07:41:49 +02:00
|
|
|
/// no longer dominate all their uses. Not sure if this is really necessary
|
2013-06-19 22:18:24 +02:00
|
|
|
void StructurizeCFG::rebuildSSA() {
|
2012-12-19 23:10:31 +01:00
|
|
|
SSAUpdater Updater;
|
2016-11-28 19:50:03 +01:00
|
|
|
for (BasicBlock *BB : ParentRegion->blocks())
|
|
|
|
for (Instruction &I : *BB) {
|
2012-12-19 23:10:31 +01:00
|
|
|
bool Initialized = false;
|
2016-11-29 22:49:02 +01:00
|
|
|
// We may modify the use list as we iterate over it, so be careful to
|
|
|
|
// compute the next element in the use list at the top of the loop.
|
|
|
|
for (auto UI = I.use_begin(), E = I.use_end(); UI != E;) {
|
|
|
|
Use &U = *UI++;
|
2014-03-09 04:16:01 +01:00
|
|
|
Instruction *User = cast<Instruction>(U.getUser());
|
2012-12-19 23:10:31 +01:00
|
|
|
if (User->getParent() == BB) {
|
|
|
|
continue;
|
|
|
|
} else if (PHINode *UserPN = dyn_cast<PHINode>(User)) {
|
2014-03-09 04:16:01 +01:00
|
|
|
if (UserPN->getIncomingBlock(U) == BB)
|
2012-12-19 23:10:31 +01:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2016-11-28 19:50:03 +01:00
|
|
|
if (DT->dominates(&I, User))
|
2012-12-19 23:10:31 +01:00
|
|
|
continue;
|
|
|
|
|
|
|
|
if (!Initialized) {
|
2016-11-28 19:50:03 +01:00
|
|
|
Value *Undef = UndefValue::get(I.getType());
|
|
|
|
Updater.Initialize(I.getType(), "");
|
2012-12-19 23:10:31 +01:00
|
|
|
Updater.AddAvailableValue(&Func->getEntryBlock(), Undef);
|
2016-11-28 19:50:03 +01:00
|
|
|
Updater.AddAvailableValue(BB, &I);
|
2012-12-19 23:10:31 +01:00
|
|
|
Initialized = true;
|
|
|
|
}
|
2014-03-09 04:16:01 +01:00
|
|
|
Updater.RewriteUseAfterInsertions(U);
|
2012-12-19 23:10:31 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-04 12:58:15 +02:00
|
|
|
static bool hasOnlyUniformBranches(Region *R, unsigned UniformMDKindID,
|
2018-08-30 16:21:36 +02:00
|
|
|
const LegacyDivergenceAnalysis &DA) {
|
2019-05-24 10:59:17 +02:00
|
|
|
// Bool for if all sub-regions are uniform.
|
|
|
|
bool SubRegionsAreUniform = true;
|
|
|
|
// Count of how many direct children are conditional.
|
|
|
|
unsigned ConditionalDirectChildren = 0;
|
|
|
|
|
2018-04-04 12:58:15 +02:00
|
|
|
for (auto E : R->elements()) {
|
|
|
|
if (!E->isSubRegion()) {
|
|
|
|
auto Br = dyn_cast<BranchInst>(E->getEntry()->getTerminator());
|
|
|
|
if (!Br || !Br->isConditional())
|
|
|
|
continue;
|
2016-02-10 01:39:37 +01:00
|
|
|
|
2018-04-04 12:58:15 +02:00
|
|
|
if (!DA.isUniform(Br))
|
|
|
|
return false;
|
2019-05-24 10:59:17 +02:00
|
|
|
|
|
|
|
// One of our direct children is conditional.
|
|
|
|
ConditionalDirectChildren++;
|
|
|
|
|
2018-05-14 14:53:11 +02:00
|
|
|
LLVM_DEBUG(dbgs() << "BB: " << Br->getParent()->getName()
|
|
|
|
<< " has uniform terminator\n");
|
2018-04-04 12:58:15 +02:00
|
|
|
} else {
|
|
|
|
// Explicitly refuse to treat regions as uniform if they have non-uniform
|
|
|
|
// subregions. We cannot rely on DivergenceAnalysis for branches in
|
|
|
|
// subregions because those branches may have been removed and re-created,
|
|
|
|
// so we look for our metadata instead.
|
|
|
|
//
|
|
|
|
// Warning: It would be nice to treat regions as uniform based only on
|
|
|
|
// their direct child basic blocks' terminators, regardless of whether
|
|
|
|
// subregions are uniform or not. However, this requires a very careful
|
|
|
|
// look at SIAnnotateControlFlow to make sure nothing breaks there.
|
|
|
|
for (auto BB : E->getNodeAs<Region>()->blocks()) {
|
|
|
|
auto Br = dyn_cast<BranchInst>(BB->getTerminator());
|
|
|
|
if (!Br || !Br->isConditional())
|
|
|
|
continue;
|
|
|
|
|
2019-05-24 10:59:17 +02:00
|
|
|
if (!Br->getMetadata(UniformMDKindID)) {
|
|
|
|
// Early exit if we cannot have relaxed uniform regions.
|
|
|
|
if (!RelaxedUniformRegions)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
SubRegionsAreUniform = false;
|
|
|
|
break;
|
|
|
|
}
|
2018-04-04 12:58:15 +02:00
|
|
|
}
|
|
|
|
}
|
2016-02-10 01:39:37 +01:00
|
|
|
}
|
2019-05-24 10:59:17 +02:00
|
|
|
|
|
|
|
// Our region is uniform if:
|
|
|
|
// 1. All conditional branches that are direct children are uniform (checked
|
|
|
|
// above).
|
|
|
|
// 2. And either:
|
|
|
|
// a. All sub-regions are uniform.
|
|
|
|
// b. There is one or less conditional branches among the direct children.
|
|
|
|
return SubRegionsAreUniform || (ConditionalDirectChildren <= 1);
|
2016-02-10 01:39:37 +01:00
|
|
|
}
|
|
|
|
|
2018-05-01 17:54:18 +02:00
|
|
|
/// Run the transformation for each region found
|
2013-06-19 22:18:24 +02:00
|
|
|
bool StructurizeCFG::runOnRegion(Region *R, RGPassManager &RGM) {
|
2012-12-19 23:10:31 +01:00
|
|
|
if (R->isTopLevelRegion())
|
|
|
|
return false;
|
|
|
|
|
2018-04-04 12:58:15 +02:00
|
|
|
DA = nullptr;
|
|
|
|
|
2016-02-10 01:39:37 +01:00
|
|
|
if (SkipUniformRegions) {
|
|
|
|
// TODO: We could probably be smarter here with how we handle sub-regions.
|
2018-04-04 12:58:15 +02:00
|
|
|
// We currently rely on the fact that metadata is set by earlier invocations
|
|
|
|
// of the pass on sub-regions, and that this metadata doesn't get lost --
|
|
|
|
// but we shouldn't rely on metadata for correctness!
|
|
|
|
unsigned UniformMDKindID =
|
|
|
|
R->getEntry()->getContext().getMDKindID("structurizecfg.uniform");
|
2018-08-30 16:21:36 +02:00
|
|
|
DA = &getAnalysis<LegacyDivergenceAnalysis>();
|
2018-04-04 12:58:15 +02:00
|
|
|
|
|
|
|
if (hasOnlyUniformBranches(R, UniformMDKindID, *DA)) {
|
2018-05-14 14:53:11 +02:00
|
|
|
LLVM_DEBUG(dbgs() << "Skipping region with uniform control flow: " << *R
|
|
|
|
<< '\n');
|
2016-04-14 19:42:35 +02:00
|
|
|
|
|
|
|
// Mark all direct child block terminators as having been treated as
|
|
|
|
// uniform. To account for a possible future in which non-uniform
|
|
|
|
// sub-regions are treated more cleverly, indirect children are not
|
|
|
|
// marked as uniform.
|
|
|
|
MDNode *MD = MDNode::get(R->getEntry()->getParent()->getContext(), {});
|
2016-11-23 00:13:37 +01:00
|
|
|
for (RegionNode *E : R->elements()) {
|
|
|
|
if (E->isSubRegion())
|
2016-04-14 19:42:35 +02:00
|
|
|
continue;
|
|
|
|
|
2016-11-23 00:13:37 +01:00
|
|
|
if (Instruction *Term = E->getEntry()->getTerminator())
|
2018-04-04 12:58:15 +02:00
|
|
|
Term->setMetadata(UniformMDKindID, MD);
|
2016-04-14 19:42:35 +02:00
|
|
|
}
|
|
|
|
|
2016-02-10 01:39:37 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-12-19 23:10:31 +01:00
|
|
|
Func = R->getEntry()->getParent();
|
|
|
|
ParentRegion = R;
|
|
|
|
|
2014-01-13 14:07:17 +01:00
|
|
|
DT = &getAnalysis<DominatorTreeWrapperPass>().getDomTree();
|
2018-01-24 19:02:05 +01:00
|
|
|
LI = &getAnalysis<LoopInfoWrapperPass>().getLoopInfo();
|
2012-12-19 23:10:31 +01:00
|
|
|
|
|
|
|
orderNodes();
|
2018-01-24 19:02:05 +01:00
|
|
|
collectInfos();
|
2012-12-19 23:10:31 +01:00
|
|
|
createFlow();
|
2013-02-16 12:27:45 +01:00
|
|
|
insertConditions(false);
|
|
|
|
insertConditions(true);
|
2013-02-08 23:24:35 +01:00
|
|
|
setPhiValues();
|
2020-03-05 04:39:46 +01:00
|
|
|
simplifyAffectedPhis();
|
2012-12-19 23:10:31 +01:00
|
|
|
rebuildSSA();
|
|
|
|
|
2013-02-08 23:24:37 +01:00
|
|
|
// Cleanup
|
2012-12-19 23:10:31 +01:00
|
|
|
Order.clear();
|
|
|
|
Visited.clear();
|
|
|
|
DeletedPhis.clear();
|
2013-02-08 23:24:35 +01:00
|
|
|
AddedPhis.clear();
|
2013-02-16 12:27:45 +01:00
|
|
|
Predicates.clear();
|
2013-02-08 23:24:37 +01:00
|
|
|
Conditions.clear();
|
2013-02-16 12:27:45 +01:00
|
|
|
Loops.clear();
|
|
|
|
LoopPreds.clear();
|
|
|
|
LoopConds.clear();
|
2012-12-19 23:10:31 +01:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-02-10 01:39:37 +01:00
|
|
|
Pass *llvm::createStructurizeCFGPass(bool SkipUniformRegions) {
|
|
|
|
return new StructurizeCFG(SkipUniformRegions);
|
2012-12-19 23:10:31 +01:00
|
|
|
}
|