70#define DEBUG_TYPE "wasm-fix-irreducible-control-flow"
77static BlockVector getSortedEntries(
const BlockSet &Entries) {
78 BlockVector SortedEntries(Entries.
begin(), Entries.
end());
81 auto ANum =
A->getNumber();
82 auto BNum =
B->getNumber();
88struct ReachabilityNode {
91 unsigned SCCId = std::numeric_limits<unsigned>::max();
97class ReachabilityGraph {
100 : Entry(Entry), Blocks(Blocks) {
103 for (
auto *
MBB : Blocks) {
105 for (
auto *Pred :
MBB->predecessors()) {
115 const BlockSet &getLoopEntries()
const {
return LoopEntries; }
116 const BlockSet &getLoopEntriesForSCC(
unsigned SCCId)
const {
117 return LoopEntriesBySCC[SCCId];
139 return MBBToNodeMap.
at(
MBB);
152 return G->getNode(
G->Entry);
156 return N->Succs.begin();
160 return N->Succs.end();
167void ReachabilityGraph::calculate() {
168 auto NumBlocks = Blocks.size();
169 Nodes.assign(NumBlocks, {});
171 MBBToNodeMap.clear();
172 MBBToNodeMap.reserve(NumBlocks);
176 for (
auto *
MBB : Blocks) {
177 auto &
Node = Nodes[MBBIdx++];
185 for (
auto *
MBB : Blocks) {
186 auto &
Node = Nodes[MBBIdx++];
189 if (Succ != Entry && inRegion(Succ)) {
195 unsigned CurrSCCIdx = 0;
197 LoopEntriesBySCC.push_back({});
198 auto &SCCLoopEntries = LoopEntriesBySCC.back();
200 for (
auto *Node : SCC) {
202 assert(
Node->SCCId == std::numeric_limits<unsigned>::max());
204 Node->SCCId = CurrSCCIdx;
207 bool SelfLoop =
false;
208 if (
SCC.size() == 1) {
211 for (
auto *Succ :
Node->Succs) {
222 if (
SCC.size() > 1 || SelfLoop) {
225 for (
auto *Node : SCC) {
226 if (
Node->MBB == Entry)
229 for (
auto *Pred :
Node->MBB->predecessors()) {
232 if (getSCCId(Pred) != CurrSCCIdx) {
233 LoopEntries.insert(
Node->MBB);
234 SCCLoopEntries.insert(
Node->MBB);
244 for (
auto &Node : Nodes) {
245 assert(
Node.SCCId != std::numeric_limits<unsigned>::max());
250class WebAssemblyFixIrreducibleControlFlowLegacy final
251 :
public MachineFunctionPass {
252 StringRef getPassName()
const override {
253 return "WebAssembly Fix Irreducible Control Flow";
256 bool runOnMachineFunction(MachineFunction &MF)
override;
260 WebAssemblyFixIrreducibleControlFlowLegacy() : MachineFunctionPass(
ID) {}
270 MachineFunction &MF,
const ReachabilityGraph &Graph) {
274 BlockVector SortedEntries = getSortedEntries(Entries);
277 for (
auto *
Block : SortedEntries)
279 if (SortedEntries.size() > 1) {
280 for (
auto I = SortedEntries.begin(),
E = SortedEntries.end() - 1;
I !=
E;
282 auto ANum = (*I)->getNumber();
283 auto BNum = (*(std::next(
I)))->getNumber();
295 const auto &
TII = *MF.
getSubtarget<WebAssemblySubtarget>().getInstrInfo();
296 MachineInstrBuilder MIB =
307 DenseMap<MachineBasicBlock *, unsigned> Indices;
308 for (
auto *Entry : SortedEntries) {
313 Pair.first->second =
Index;
323 BlockVector AllPreds;
324 for (
auto *Entry : SortedEntries) {
325 for (
auto *Pred :
Entry->predecessors()) {
327 AllPreds.push_back(Pred);
333 DenseSet<MachineBasicBlock *> InLoop;
334 for (
auto *Pred : AllPreds) {
335 auto PredSCCId = Graph.getSCCId(Pred);
337 for (
auto *Entry : Pred->successors()) {
338 if (!Entries.
count(Entry))
340 if (Graph.getSCCId(Entry) == PredSCCId) {
349 DenseMap<PointerIntPair<MachineBasicBlock *, 1, bool>, MachineBasicBlock *>
351 for (
auto *Pred : AllPreds) {
352 bool PredInLoop = InLoop.
count(Pred);
353 for (
auto *Entry : Pred->successors())
354 if (Entries.
count(Entry) && Pred->isLayoutSuccessor(Entry))
355 EntryToLayoutPred[{
Entry, PredInLoop}] = Pred;
362 DenseMap<PointerIntPair<MachineBasicBlock *, 1, bool>, MachineBasicBlock *>
364 for (
auto *Pred : AllPreds) {
365 bool PredInLoop = InLoop.
count(Pred);
366 for (
auto *Entry : Pred->successors()) {
367 if (!Entries.
count(Entry) ||
Map.count({Entry, PredInLoop}))
372 if (
auto *OtherPred = EntryToLayoutPred.
lookup({Entry, PredInLoop}))
373 if (OtherPred != Pred)
378 MF.
insert(Pred->isLayoutSuccessor(Entry)
394 for (
auto *Pred : AllPreds) {
395 bool PredInLoop = InLoop.
count(Pred);
397 for (MachineInstr &Term : Pred->terminators())
398 for (
auto &
Op :
Term.explicit_uses())
399 if (
Op.isMBB() && Indices.
count(
Op.getMBB()))
400 Op.setMBB(Map[{
Op.getMBB(), PredInLoop}]);
402 for (
auto *Succ : Pred->successors()) {
403 if (!Entries.
count(Succ))
405 auto *Routing =
Map[{Succ, PredInLoop}];
406 Pred->replaceSuccessor(Succ, Routing);
416bool processRegion(MachineBasicBlock *Entry,
BlockSet &Blocks,
417 MachineFunction &MF) {
422 ReachabilityGraph Graph(Entry, Blocks);
424 bool FoundIrreducibility =
false;
426 for (
auto *LoopEntry : getSortedEntries(Graph.getLoopEntries())) {
452 auto &MutualLoopEntries =
453 Graph.getLoopEntriesForSCC(Graph.getSCCId(LoopEntry));
455 if (MutualLoopEntries.size() > 1) {
456 makeSingleEntryLoop(MutualLoopEntries, Blocks, MF, Graph);
457 FoundIrreducibility =
true;
469 if (FoundIrreducibility) {
473 for (
auto *LoopEntry : Graph.getLoopEntries()) {
476 auto EntrySCCId = Graph.getSCCId(LoopEntry);
477 for (
auto *
Block : Blocks) {
478 if (EntrySCCId == Graph.getSCCId(
Block)) {
489 if (processRegion(LoopEntry, InnerBlocks, MF)) {
500char WebAssemblyFixIrreducibleControlFlowLegacy::ID = 0;
502 "Removes irreducible control flow",
false,
false)
505 return new WebAssemblyFixIrreducibleControlFlowLegacy();
535 TII.get(WebAssembly::IMPLICIT_DEF),
Reg);
542 MI.removeFromParent();
543 Entry.insert(Entry.begin(), &
MI);
549 LLVM_DEBUG(
dbgs() <<
"********** Fixing Irreducible Control Flow **********\n"
550 "********** Function: "
555 for (
auto &
MBB : MF) {
576bool WebAssemblyFixIrreducibleControlFlowLegacy::runOnMachineFunction(
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static msgpack::DocNode getNode(msgpack::DocNode DN, msgpack::Type Type, MCValue Val)
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
#define LLVM_UNLIKELY(EXPR)
const HexagonInstrInfo * TII
Promote Memory to Register
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
This builds on the llvm/ADT/GraphTraits.h file to find the strongly connected components (SCCs) of a ...
SmallPtrSet< BasicBlock *, 0 > BlockSet
static bool hasArgumentDef(unsigned Reg, const MachineRegisterInfo &MRI)
static void addImplicitDefs(MachineFunction &MF)
static bool fixIrreducibleControlFlow(MachineFunction &MF)
This file provides WebAssembly-specific target descriptions.
This file declares the WebAssembly-specific subclass of TargetSubtarget.
This file contains the entry points for global functions defined in the LLVM WebAssembly back-end.
ValueT & at(const_arg_type_t< KeyT > Val)
Return the entry for the specified key, or abort if no such entry exists.
ValueT lookup(const_arg_type_t< KeyT > Val) const
Return the entry for the specified key, or a default constructed value if no such entry exists.
std::pair< iterator, bool > try_emplace(KeyT &&Key, Ts &&...Args)
size_type count(const_arg_type_t< KeyT > Val) const
Return 1 if the specified key is in the map, 0 otherwise.
FunctionPass class - This class is used to implement most global optimizations.
LLVM_ABI void addSuccessor(MachineBasicBlock *Succ, BranchProbability Prob=BranchProbability::getUnknown())
Add Succ as a successor of this MachineBasicBlock.
iterator_range< succ_iterator > successors()
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
StringRef getName() const
getName - Return the name of the corresponding LLVM function.
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
BasicBlockListType::iterator iterator
void RenumberBlocks(MachineBasicBlock *MBBFrom=nullptr)
RenumberBlocks - This discards all of the MachineBasicBlock numbers and recomputes them.
MachineBasicBlock * CreateMachineBasicBlock(const BasicBlock *BB=nullptr, std::optional< UniqueBBID > BBID=std::nullopt)
CreateMachineInstr - Allocate a new MachineInstr.
void insert(iterator MBBI, MachineBasicBlock *MBB)
const MachineInstrBuilder & addReg(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a new virtual register operand.
const MachineInstrBuilder & addImm(int64_t Val) const
Add a new immediate operand.
const MachineInstrBuilder & addMBB(MachineBasicBlock *MBB, unsigned TargetFlags=0) const
MachineInstr * getInstr() const
If conversion operators fail, use this method to get the MachineInstr explicitly.
Representation of each machine instruction.
LLVM_ABI unsigned getNumExplicitOperands() const
Returns the number of non-implicit operands.
const MachineOperand & getOperand(unsigned i) const
MachineBasicBlock * getMBB() const
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
iterator_range< def_instr_iterator > def_instructions(Register Reg) const
bool use_nodbg_empty(Register RegNo) const
use_nodbg_empty - Return true if there are no non-Debug instructions using the specified register.
LLVM_ABI Register createVirtualRegister(const TargetRegisterClass *RegClass, StringRef Name="")
createVirtualRegister - Create and return a new virtual register in the function with the specified r...
unsigned getNumVirtRegs() const
getNumVirtRegs - Return the number of virtual registers created.
A set of analyses that are preserved following a run of a transformation pass.
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
Wrapper class representing virtual and physical registers.
static Register index2VirtReg(unsigned Index)
Convert a 0-based index to a virtual register number.
size_type count(ConstPtrType Ptr) const
count - Return 1 if the specified pointer is in the set, 0 otherwise.
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
typename SuperClass::iterator iterator
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
PreservedAnalyses run(MachineFunction &MF, MachineFunctionAnalysisManager &MFAM)
std::pair< iterator, bool > insert(const ValueT &V)
size_type count(const_arg_type_t< ValueT > V) const
Return 1 if the specified key is in the set, 0 otherwise.
Pass manager infrastructure for declaring and invalidating analyses.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
bool isArgument(unsigned Opc)
NodeAddr< NodeBase * > Node
This is an optimization pass for GlobalISel generic memory operations.
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
iterator_range< T > make_range(T x, T y)
Convenience function for iterating over sub-ranges.
scc_iterator< T > scc_begin(const T &G)
Construct the begin iterator for a deduced graph type T.
iterator_range< early_inc_iterator_impl< detail::IterOfRange< RangeT > > > make_early_inc_range(RangeT &&Range)
Make a range that does early increment to allow mutation of the underlying range without disrupting i...
AnalysisManager< MachineFunction > MachineFunctionAnalysisManager
LLVM_ABI PreservedAnalyses getMachineFunctionPassPreservedAnalyses()
Returns the minimum set of Analyses that all machine function passes must preserve.
void sort(IteratorTy Start, IteratorTy End)
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
FunctionPass * createWebAssemblyFixIrreducibleControlFlowLegacyPass()
DWARFExpression::Operation Op
scc_iterator< T > scc_end(const T &G)
Construct the end iterator for a deduced graph type T.
static ChildIteratorType child_end(NodeRef N)
SmallVectorImpl< NodeRef >::iterator ChildIteratorType
ReachabilityNode * NodeRef
static ChildIteratorType child_begin(NodeRef N)
static NodeRef getEntryNode(ReachabilityGraph *G)