mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-23 11:13:28 +01:00
eb66b33867
I did this a long time ago with a janky python script, but now clang-format has built-in support for this. I fed clang-format every line with a #include and let it re-sort things according to the precise LLVM rules for include ordering baked into clang-format these days. I've reverted a number of files where the results of sorting includes isn't healthy. Either places where we have legacy code relying on particular include ordering (where possible, I'll fix these separately) or where we have particular formatting around #include lines that I didn't want to disturb in this patch. This patch is *entirely* mechanical. If you get merge conflicts or anything, just ignore the changes in this patch and run clang-format over your #include lines in the files. Sorry for any noise here, but it is important to keep these things stable. I was seeing an increasing number of patches with irrelevant re-ordering of #include lines because clang-format was used. This patch at least isolates that churn, makes it easy to skip when resolving conflicts, and gets us to a clean baseline (again). llvm-svn: 304787
297 lines
10 KiB
C++
297 lines
10 KiB
C++
//=- WebAssemblyFixIrreducibleControlFlow.cpp - Fix irreducible control flow -//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
///
|
|
/// \file
|
|
/// \brief This file implements a pass that transforms irreducible control flow
|
|
/// into reducible control flow. Irreducible control flow means multiple-entry
|
|
/// loops; they appear as CFG cycles that are not recorded in MachineLoopInfo
|
|
/// due to being unnatural.
|
|
///
|
|
/// Note that LLVM has a generic pass that lowers irreducible control flow, but
|
|
/// it linearizes control flow, turning diamonds into two triangles, which is
|
|
/// both unnecessary and undesirable for WebAssembly.
|
|
///
|
|
/// TODO: The transformation implemented here handles all irreducible control
|
|
/// flow, without exponential code-size expansion, though it does so by creating
|
|
/// inefficient code in many cases. Ideally, we should add other
|
|
/// transformations, including code-duplicating cases, which can be more
|
|
/// efficient in common cases, and they can fall back to this conservative
|
|
/// implementation as needed.
|
|
///
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
|
|
#include "WebAssembly.h"
|
|
#include "WebAssemblyMachineFunctionInfo.h"
|
|
#include "WebAssemblySubtarget.h"
|
|
#include "llvm/ADT/PriorityQueue.h"
|
|
#include "llvm/ADT/SCCIterator.h"
|
|
#include "llvm/ADT/SetVector.h"
|
|
#include "llvm/CodeGen/MachineDominators.h"
|
|
#include "llvm/CodeGen/MachineFunction.h"
|
|
#include "llvm/CodeGen/MachineInstrBuilder.h"
|
|
#include "llvm/CodeGen/MachineLoopInfo.h"
|
|
#include "llvm/CodeGen/MachineRegisterInfo.h"
|
|
#include "llvm/CodeGen/Passes.h"
|
|
#include "llvm/Support/Debug.h"
|
|
#include "llvm/Support/raw_ostream.h"
|
|
using namespace llvm;
|
|
|
|
#define DEBUG_TYPE "wasm-fix-irreducible-control-flow"
|
|
|
|
namespace {
|
|
class WebAssemblyFixIrreducibleControlFlow final : public MachineFunctionPass {
|
|
StringRef getPassName() const override {
|
|
return "WebAssembly Fix Irreducible Control Flow";
|
|
}
|
|
|
|
void getAnalysisUsage(AnalysisUsage &AU) const override {
|
|
AU.setPreservesCFG();
|
|
AU.addRequired<MachineDominatorTree>();
|
|
AU.addPreserved<MachineDominatorTree>();
|
|
AU.addRequired<MachineLoopInfo>();
|
|
AU.addPreserved<MachineLoopInfo>();
|
|
MachineFunctionPass::getAnalysisUsage(AU);
|
|
}
|
|
|
|
bool runOnMachineFunction(MachineFunction &MF) override;
|
|
|
|
bool VisitLoop(MachineFunction &MF, MachineLoopInfo &MLI, MachineLoop *Loop);
|
|
|
|
public:
|
|
static char ID; // Pass identification, replacement for typeid
|
|
WebAssemblyFixIrreducibleControlFlow() : MachineFunctionPass(ID) {}
|
|
};
|
|
} // end anonymous namespace
|
|
|
|
char WebAssemblyFixIrreducibleControlFlow::ID = 0;
|
|
FunctionPass *llvm::createWebAssemblyFixIrreducibleControlFlow() {
|
|
return new WebAssemblyFixIrreducibleControlFlow();
|
|
}
|
|
|
|
namespace {
|
|
|
|
/// A utility for walking the blocks of a loop, handling a nested inner
|
|
/// loop as a monolithic conceptual block.
|
|
class MetaBlock {
|
|
MachineBasicBlock *Block;
|
|
SmallVector<MachineBasicBlock *, 2> Preds;
|
|
SmallVector<MachineBasicBlock *, 2> Succs;
|
|
|
|
public:
|
|
explicit MetaBlock(MachineBasicBlock *MBB)
|
|
: Block(MBB), Preds(MBB->pred_begin(), MBB->pred_end()),
|
|
Succs(MBB->succ_begin(), MBB->succ_end()) {}
|
|
|
|
explicit MetaBlock(MachineLoop *Loop) : Block(Loop->getHeader()) {
|
|
Loop->getExitBlocks(Succs);
|
|
for (MachineBasicBlock *Pred : Block->predecessors())
|
|
if (!Loop->contains(Pred))
|
|
Preds.push_back(Pred);
|
|
}
|
|
|
|
MachineBasicBlock *getBlock() const { return Block; }
|
|
|
|
const SmallVectorImpl<MachineBasicBlock *> &predecessors() const {
|
|
return Preds;
|
|
}
|
|
const SmallVectorImpl<MachineBasicBlock *> &successors() const {
|
|
return Succs;
|
|
}
|
|
|
|
bool operator==(const MetaBlock &MBB) { return Block == MBB.Block; }
|
|
bool operator!=(const MetaBlock &MBB) { return Block != MBB.Block; }
|
|
};
|
|
|
|
class SuccessorList final : public MetaBlock {
|
|
size_t Index;
|
|
size_t Num;
|
|
|
|
public:
|
|
explicit SuccessorList(MachineBasicBlock *MBB)
|
|
: MetaBlock(MBB), Index(0), Num(successors().size()) {}
|
|
|
|
explicit SuccessorList(MachineLoop *Loop)
|
|
: MetaBlock(Loop), Index(0), Num(successors().size()) {}
|
|
|
|
bool HasNext() const { return Index != Num; }
|
|
|
|
MachineBasicBlock *Next() {
|
|
assert(HasNext());
|
|
return successors()[Index++];
|
|
}
|
|
};
|
|
|
|
} // end anonymous namespace
|
|
|
|
bool WebAssemblyFixIrreducibleControlFlow::VisitLoop(MachineFunction &MF,
|
|
MachineLoopInfo &MLI,
|
|
MachineLoop *Loop) {
|
|
MachineBasicBlock *Header = Loop ? Loop->getHeader() : &*MF.begin();
|
|
SetVector<MachineBasicBlock *> RewriteSuccs;
|
|
|
|
// DFS through Loop's body, looking for for irreducible control flow. Loop is
|
|
// natural, and we stay in its body, and we treat any nested loops
|
|
// monolithically, so any cycles we encounter indicate irreducibility.
|
|
SmallPtrSet<MachineBasicBlock *, 8> OnStack;
|
|
SmallPtrSet<MachineBasicBlock *, 8> Visited;
|
|
SmallVector<SuccessorList, 4> LoopWorklist;
|
|
LoopWorklist.push_back(SuccessorList(Header));
|
|
OnStack.insert(Header);
|
|
Visited.insert(Header);
|
|
while (!LoopWorklist.empty()) {
|
|
SuccessorList &Top = LoopWorklist.back();
|
|
if (Top.HasNext()) {
|
|
MachineBasicBlock *Next = Top.Next();
|
|
if (Next == Header || (Loop && !Loop->contains(Next)))
|
|
continue;
|
|
if (LLVM_LIKELY(OnStack.insert(Next).second)) {
|
|
if (!Visited.insert(Next).second) {
|
|
OnStack.erase(Next);
|
|
continue;
|
|
}
|
|
MachineLoop *InnerLoop = MLI.getLoopFor(Next);
|
|
if (InnerLoop != Loop)
|
|
LoopWorklist.push_back(SuccessorList(InnerLoop));
|
|
else
|
|
LoopWorklist.push_back(SuccessorList(Next));
|
|
} else {
|
|
RewriteSuccs.insert(Top.getBlock());
|
|
}
|
|
continue;
|
|
}
|
|
OnStack.erase(Top.getBlock());
|
|
LoopWorklist.pop_back();
|
|
}
|
|
|
|
// Most likely, we didn't find any irreducible control flow.
|
|
if (LLVM_LIKELY(RewriteSuccs.empty()))
|
|
return false;
|
|
|
|
DEBUG(dbgs() << "Irreducible control flow detected!\n");
|
|
|
|
// Ok. We have irreducible control flow! Create a dispatch block which will
|
|
// contains a jump table to any block in the problematic set of blocks.
|
|
MachineBasicBlock *Dispatch = MF.CreateMachineBasicBlock();
|
|
MF.insert(MF.end(), Dispatch);
|
|
MLI.changeLoopFor(Dispatch, Loop);
|
|
|
|
// Add the jump table.
|
|
const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
|
|
MachineInstrBuilder MIB = BuildMI(*Dispatch, Dispatch->end(), DebugLoc(),
|
|
TII.get(WebAssembly::BR_TABLE_I32));
|
|
|
|
// Add the register which will be used to tell the jump table which block to
|
|
// jump to.
|
|
MachineRegisterInfo &MRI = MF.getRegInfo();
|
|
unsigned Reg = MRI.createVirtualRegister(&WebAssembly::I32RegClass);
|
|
MIB.addReg(Reg);
|
|
|
|
// Collect all the blocks which need to have their successors rewritten,
|
|
// add the successors to the jump table, and remember their index.
|
|
DenseMap<MachineBasicBlock *, unsigned> Indices;
|
|
SmallVector<MachineBasicBlock *, 4> SuccWorklist(RewriteSuccs.begin(),
|
|
RewriteSuccs.end());
|
|
while (!SuccWorklist.empty()) {
|
|
MachineBasicBlock *MBB = SuccWorklist.pop_back_val();
|
|
auto Pair = Indices.insert(std::make_pair(MBB, 0));
|
|
if (!Pair.second)
|
|
continue;
|
|
|
|
unsigned Index = MIB.getInstr()->getNumExplicitOperands() - 1;
|
|
DEBUG(dbgs() << "MBB#" << MBB->getNumber() << " has index " << Index
|
|
<< "\n");
|
|
|
|
Pair.first->second = Index;
|
|
for (auto Pred : MBB->predecessors())
|
|
RewriteSuccs.insert(Pred);
|
|
|
|
MIB.addMBB(MBB);
|
|
Dispatch->addSuccessor(MBB);
|
|
|
|
MetaBlock Meta(MBB);
|
|
for (auto *Succ : Meta.successors())
|
|
if (Succ != Header && (!Loop || Loop->contains(Succ)))
|
|
SuccWorklist.push_back(Succ);
|
|
}
|
|
|
|
// Rewrite the problematic successors for every block in RewriteSuccs.
|
|
// For simplicity, we just introduce a new block for every edge we need to
|
|
// rewrite. Fancier things are possible.
|
|
for (MachineBasicBlock *MBB : RewriteSuccs) {
|
|
DenseMap<MachineBasicBlock *, MachineBasicBlock *> Map;
|
|
for (auto *Succ : MBB->successors()) {
|
|
if (!Indices.count(Succ))
|
|
continue;
|
|
|
|
MachineBasicBlock *Split = MF.CreateMachineBasicBlock();
|
|
MF.insert(MBB->isLayoutSuccessor(Succ) ? MachineFunction::iterator(Succ)
|
|
: MF.end(),
|
|
Split);
|
|
MLI.changeLoopFor(Split, Loop);
|
|
|
|
// Set the jump table's register of the index of the block we wish to
|
|
// jump to, and jump to the jump table.
|
|
BuildMI(*Split, Split->end(), DebugLoc(), TII.get(WebAssembly::CONST_I32),
|
|
Reg)
|
|
.addImm(Indices[Succ]);
|
|
BuildMI(*Split, Split->end(), DebugLoc(), TII.get(WebAssembly::BR))
|
|
.addMBB(Dispatch);
|
|
Split->addSuccessor(Dispatch);
|
|
Map[Succ] = Split;
|
|
}
|
|
// Remap the terminator operands and the successor list.
|
|
for (MachineInstr &Term : MBB->terminators())
|
|
for (auto &Op : Term.explicit_uses())
|
|
if (Op.isMBB() && Indices.count(Op.getMBB()))
|
|
Op.setMBB(Map[Op.getMBB()]);
|
|
for (auto Rewrite : Map)
|
|
MBB->replaceSuccessor(Rewrite.first, Rewrite.second);
|
|
}
|
|
|
|
// Create a fake default label, because br_table requires one.
|
|
MIB.addMBB(MIB.getInstr()
|
|
->getOperand(MIB.getInstr()->getNumExplicitOperands() - 1)
|
|
.getMBB());
|
|
|
|
return true;
|
|
}
|
|
|
|
bool WebAssemblyFixIrreducibleControlFlow::runOnMachineFunction(
|
|
MachineFunction &MF) {
|
|
DEBUG(dbgs() << "********** Fixing Irreducible Control Flow **********\n"
|
|
"********** Function: "
|
|
<< MF.getName() << '\n');
|
|
|
|
bool Changed = false;
|
|
auto &MLI = getAnalysis<MachineLoopInfo>();
|
|
|
|
// Visit the function body, which is identified as a null loop.
|
|
Changed |= VisitLoop(MF, MLI, nullptr);
|
|
|
|
// Visit all the loops.
|
|
SmallVector<MachineLoop *, 8> Worklist(MLI.begin(), MLI.end());
|
|
while (!Worklist.empty()) {
|
|
MachineLoop *CurLoop = Worklist.pop_back_val();
|
|
Worklist.append(CurLoop->begin(), CurLoop->end());
|
|
Changed |= VisitLoop(MF, MLI, CurLoop);
|
|
}
|
|
|
|
// If we made any changes, completely recompute everything.
|
|
if (LLVM_UNLIKELY(Changed)) {
|
|
DEBUG(dbgs() << "Recomputing dominators and loops.\n");
|
|
MF.getRegInfo().invalidateLiveness();
|
|
MF.RenumberBlocks();
|
|
getAnalysis<MachineDominatorTree>().runOnMachineFunction(MF);
|
|
MLI.runOnMachineFunction(MF);
|
|
}
|
|
|
|
return Changed;
|
|
}
|