63#define DEBUG_TYPE "wasm-fix-irreducible-control-flow"
70static BlockVector getSortedEntries(
const BlockSet &Entries) {
71 BlockVector SortedEntries(Entries.begin(), Entries.end());
74 auto ANum =
A->getNumber();
75 auto BNum =
B->getNumber();
84class ReachabilityGraph {
103 auto I = Reachable.find(
From);
104 if (
I == Reachable.end())
106 return I->second.count(To);
111 const BlockSet &getLoopers()
const {
return Loopers; }
114 const BlockSet &getLoopEntries()
const {
return LoopEntries; }
118 assert(inRegion(LoopEntry));
119 auto I = LoopEnterers.find(LoopEntry);
120 assert(
I != LoopEnterers.end());
128 BlockSet Loopers, LoopEntries;
139 using BlockPair = std::pair<MachineBasicBlock *, MachineBasicBlock *>;
145 if (Succ != Entry && inRegion(Succ)) {
152 while (!WorkList.
empty()) {
155 assert(inRegion(
MBB) && Succ != Entry && inRegion(Succ));
160 if (Reachable[Pred].insert(Succ).second) {
173 assert(!Loopers.count(Entry));
177 for (
auto *Looper : Loopers) {
178 for (
auto *Pred : Looper->predecessors()) {
181 if (!canReach(Looper, Pred)) {
182 LoopEntries.insert(Looper);
183 LoopEnterers[Looper].
insert(Pred);
195 : Entry(Entry), Enterers(Enterers) {
199 BlockSet &getBlocks() {
return Blocks; }
203 const BlockSet &Enterers;
210 BlockVector WorkList;
211 BlockSet AddedToWorkList;
213 for (
auto *Pred : Entry->predecessors()) {
214 if (!Enterers.count(Pred)) {
215 WorkList.push_back(Pred);
216 AddedToWorkList.insert(Pred);
220 while (!WorkList.empty()) {
221 auto *
MBB = WorkList.pop_back_val();
225 if (AddedToWorkList.insert(Pred).second)
226 WorkList.push_back(Pred);
235 return "WebAssembly Fix Irreducible Control Flow";
243 void makeSingleEntryLoop(BlockSet &Entries, BlockSet &
Blocks,
251bool WebAssemblyFixIrreducibleControlFlow::processRegion(
253 bool Changed =
false;
257 ReachabilityGraph Graph(Entry,
Blocks);
259 bool FoundIrreducibility =
false;
261 for (
auto *LoopEntry : getSortedEntries(Graph.getLoopEntries())) {
287 BlockSet MutualLoopEntries;
288 MutualLoopEntries.insert(LoopEntry);
289 for (
auto *OtherLoopEntry : Graph.getLoopEntries()) {
290 if (OtherLoopEntry != LoopEntry &&
291 Graph.canReach(LoopEntry, OtherLoopEntry) &&
292 Graph.canReach(OtherLoopEntry, LoopEntry)) {
293 MutualLoopEntries.insert(OtherLoopEntry);
297 if (MutualLoopEntries.size() > 1) {
298 makeSingleEntryLoop(MutualLoopEntries,
Blocks, MF, Graph);
299 FoundIrreducibility =
true;
310 if (FoundIrreducibility) {
314 for (
auto *LoopEntry : Graph.getLoopEntries()) {
315 LoopBlocks InnerBlocks(LoopEntry, Graph.getLoopEnterers(LoopEntry));
322 if (processRegion(LoopEntry, InnerBlocks.getBlocks(), MF)) {
337void WebAssemblyFixIrreducibleControlFlow::makeSingleEntryLoop(
339 const ReachabilityGraph &Graph) {
340 assert(Entries.size() >= 2);
343 BlockVector SortedEntries = getSortedEntries(Entries);
346 for (
auto *
Block : SortedEntries)
348 if (SortedEntries.size() > 1) {
349 for (
auto I = SortedEntries.begin(), E = SortedEntries.end() - 1;
I != E;
351 auto ANum = (*I)->getNumber();
352 auto BNum = (*(std::next(
I)))->getNumber();
371 Register Reg =
MRI.createVirtualRegister(&WebAssembly::I32RegClass);
377 for (
auto *Entry : SortedEntries) {
378 auto Pair = Indices.
insert(std::make_pair(Entry, 0));
382 Pair.first->second = Index;
392 BlockVector AllPreds;
393 for (
auto *Entry : SortedEntries) {
394 for (
auto *Pred : Entry->predecessors()) {
395 if (Pred != Dispatch) {
396 AllPreds.push_back(Pred);
403 for (
auto *Pred : AllPreds) {
404 for (
auto *Entry : Pred->successors()) {
405 if (!Entries.count(Entry))
407 if (Graph.canReach(Entry, Pred)) {
418 for (
auto *Pred : AllPreds) {
419 bool PredInLoop = InLoop.
count(Pred);
420 for (
auto *Entry : Pred->successors())
421 if (Entries.count(Entry) && Pred->isLayoutSuccessor(Entry))
422 EntryToLayoutPred[{Entry, PredInLoop}] = Pred;
431 for (
auto *Pred : AllPreds) {
432 bool PredInLoop = InLoop.
count(Pred);
433 for (
auto *Entry : Pred->successors()) {
434 if (!Entries.count(Entry) || Map.count({Entry, PredInLoop}))
439 if (
auto *OtherPred = EntryToLayoutPred.
lookup({Entry, PredInLoop}))
440 if (OtherPred != Pred)
445 MF.
insert(Pred->isLayoutSuccessor(Entry)
457 Map[{Entry, PredInLoop}] = Routing;
461 for (
auto *Pred : AllPreds) {
462 bool PredInLoop = InLoop.
count(Pred);
465 for (
auto &
Op : Term.explicit_uses())
466 if (
Op.isMBB() && Indices.
count(
Op.getMBB()))
467 Op.setMBB(Map[{
Op.getMBB(), PredInLoop}]);
469 for (
auto *Succ : Pred->successors()) {
470 if (!Entries.count(Succ))
472 auto *Routing = Map[{Succ, PredInLoop}];
473 Pred->replaceSuccessor(Succ, Routing);
485char WebAssemblyFixIrreducibleControlFlow::ID = 0;
487 "Removes irreducible control flow",
false,
false)
490 return new WebAssemblyFixIrreducibleControlFlow();
495 for (
const auto &Def :
MRI.def_instructions(Reg))
508 for (
unsigned I = 0, E =
MRI.getNumVirtRegs();
I < E; ++
I) {
512 if (
MRI.use_nodbg_empty(Reg))
520 TII.get(WebAssembly::IMPLICIT_DEF), Reg);
527 MI.removeFromParent();
528 Entry.insert(Entry.begin(), &
MI);
533bool WebAssemblyFixIrreducibleControlFlow::runOnMachineFunction(
535 LLVM_DEBUG(
dbgs() <<
"********** Fixing Irreducible Control Flow **********\n"
536 "********** Function: "
541 for (
auto &
MBB : MF) {
542 AllBlocks.insert(&
MBB);
545 if (
LLVM_UNLIKELY(processRegion(&*MF.begin(), AllBlocks, MF))) {
unsigned const MachineRegisterInfo * MRI
BlockVerifier::State From
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
#define LLVM_UNLIKELY(EXPR)
DenseMap< Block *, BlockRelaxAux > Blocks
const HexagonInstrInfo * TII
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
static bool hasArgumentDef(unsigned Reg, const MachineRegisterInfo &MRI)
static void addImplicitDefs(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.
This class represents an Operation in the Expression.
ValueT lookup(const_arg_type_t< KeyT > Val) const
lookup - Return the entry for the specified key, or a default constructed value if no such entry exis...
size_type count(const_arg_type_t< KeyT > Val) const
Return 1 if the specified key is in the map, 0 otherwise.
std::pair< iterator, bool > insert(const std::pair< KeyT, ValueT > &KV)
Implements a dense probed hash-table based set.
FunctionPass class - This class is used to implement most global optimizations.
void addSuccessor(MachineBasicBlock *Succ, BranchProbability Prob=BranchProbability::getUnknown())
Add Succ as a successor of this MachineBasicBlock.
iterator_range< succ_iterator > successors()
iterator_range< pred_iterator > predecessors()
MachineFunctionPass - This class adapts the FunctionPass interface to allow convenient creation of pa...
virtual bool runOnMachineFunction(MachineFunction &MF)=0
runOnMachineFunction - This method must be overloaded to perform the desired machine code transformat...
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.
MachineBasicBlock * CreateMachineBasicBlock(const BasicBlock *BB=nullptr, std::optional< UniqueBBID > BBID=std::nullopt)
CreateMachineBasicBlock - Allocate a new MachineBasicBlock.
void insert(iterator MBBI, MachineBasicBlock *MBB)
const MachineInstrBuilder & addImm(int64_t Val) const
Add a new immediate operand.
const MachineInstrBuilder & addReg(Register RegNo, unsigned flags=0, unsigned SubReg=0) const
Add a new virtual register 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.
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,...
virtual StringRef getPassName() const
getPassName - Return a nice clean name for a pass.
Wrapper class representing virtual and physical registers.
static Register index2VirtReg(unsigned Index)
Convert a 0-based index to a virtual register number.
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
reference emplace_back(ArgTypes &&... Args)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
StringRef - Represent a constant reference to a string, i.e.
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.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
bool isArgument(unsigned Opc)
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< 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...
void sort(IteratorTy Start, IteratorTy End)
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
FunctionPass * createWebAssemblyFixIrreducibleControlFlow()