diff options
| author | Dimitry Andric <dim@FreeBSD.org> | 2017-01-02 19:17:04 +0000 | 
|---|---|---|
| committer | Dimitry Andric <dim@FreeBSD.org> | 2017-01-02 19:17:04 +0000 | 
| commit | b915e9e0fc85ba6f398b3fab0db6a81a8913af94 (patch) | |
| tree | 98b8f811c7aff2547cab8642daf372d6c59502fb /lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp | |
| parent | 6421cca32f69ac849537a3cff78c352195e99f1b (diff) | |
Notes
Diffstat (limited to 'lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp')
| -rw-r--r-- | lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp | 148 | 
1 files changed, 96 insertions, 52 deletions
| diff --git a/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp b/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp index 33166f5b554fd..49b9754e6b62c 100644 --- a/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp +++ b/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp @@ -27,6 +27,7 @@  #include "MCTargetDesc/WebAssemblyMCTargetDesc.h"  #include "WebAssemblyMachineFunctionInfo.h"  #include "WebAssemblySubtarget.h" +#include "WebAssemblyUtilities.h"  #include "llvm/ADT/PriorityQueue.h"  #include "llvm/ADT/SetVector.h"  #include "llvm/CodeGen/MachineDominators.h" @@ -43,9 +44,7 @@ using namespace llvm;  namespace {  class WebAssemblyCFGStackify final : public MachineFunctionPass { -  const char *getPassName() const override { -    return "WebAssembly CFG Stackify"; -  } +  StringRef getPassName() const override { return "WebAssembly CFG Stackify"; }    void getAnalysisUsage(AnalysisUsage &AU) const override {      AU.setPreservesCFG(); @@ -294,26 +293,16 @@ static bool ExplicitlyBranchesTo(MachineBasicBlock *Pred,    return false;  } -/// Test whether MI is a child of some other node in an expression tree. -static bool IsChild(const MachineInstr &MI, -                    const WebAssemblyFunctionInfo &MFI) { -  if (MI.getNumOperands() == 0) -    return false; -  const MachineOperand &MO = MI.getOperand(0); -  if (!MO.isReg() || MO.isImplicit() || !MO.isDef()) -    return false; -  unsigned Reg = MO.getReg(); -  return TargetRegisterInfo::isVirtualRegister(Reg) && -         MFI.isVRegStackified(Reg); -} -  /// Insert a BLOCK marker for branches to MBB (if needed). -static void PlaceBlockMarker(MachineBasicBlock &MBB, MachineFunction &MF, -                             SmallVectorImpl<MachineBasicBlock *> &ScopeTops, -                             const WebAssemblyInstrInfo &TII, -                             const MachineLoopInfo &MLI, -                             MachineDominatorTree &MDT, -                             WebAssemblyFunctionInfo &MFI) { +static void PlaceBlockMarker( +    MachineBasicBlock &MBB, MachineFunction &MF, +    SmallVectorImpl<MachineBasicBlock *> &ScopeTops, +    DenseMap<const MachineInstr *, MachineInstr *> &BlockTops, +    DenseMap<const MachineInstr *, MachineInstr *> &LoopTops, +    const WebAssemblyInstrInfo &TII, +    const MachineLoopInfo &MLI, +    MachineDominatorTree &MDT, +    WebAssemblyFunctionInfo &MFI) {    // First compute the nearest common dominator of all forward non-fallthrough    // predecessors so that we minimize the time that the BLOCK is on the stack,    // which reduces overall stack height. @@ -332,7 +321,7 @@ static void PlaceBlockMarker(MachineBasicBlock &MBB, MachineFunction &MF,      return;    assert(&MBB != &MF.front() && "Header blocks shouldn't have predecessors"); -  MachineBasicBlock *LayoutPred = &*prev(MachineFunction::iterator(&MBB)); +  MachineBasicBlock *LayoutPred = &*std::prev(MachineFunction::iterator(&MBB));    // If the nearest common dominator is inside a more deeply nested context,    // walk out to the nearest scope which isn't more deeply nested. @@ -340,7 +329,7 @@ static void PlaceBlockMarker(MachineBasicBlock &MBB, MachineFunction &MF,      if (MachineBasicBlock *ScopeTop = ScopeTops[I->getNumber()]) {        if (ScopeTop->getNumber() > Header->getNumber()) {          // Skip over an intervening scope. -        I = next(MachineFunction::iterator(ScopeTop)); +        I = std::next(MachineFunction::iterator(ScopeTop));        } else {          // We found a scope level at an appropriate depth.          Header = ScopeTop; @@ -349,13 +338,6 @@ static void PlaceBlockMarker(MachineBasicBlock &MBB, MachineFunction &MF,      }    } -  // If there's a loop which ends just before MBB which contains Header, we can -  // reuse its label instead of inserting a new BLOCK. -  for (MachineLoop *Loop = MLI.getLoopFor(LayoutPred); -       Loop && Loop->contains(LayoutPred); Loop = Loop->getParentLoop()) -    if (Loop && LoopBottom(Loop) == LayoutPred && Loop->contains(Header)) -      return; -    // Decide where in Header to put the BLOCK.    MachineBasicBlock::iterator InsertPos;    MachineLoop *HeaderLoop = MLI.getLoopFor(Header); @@ -363,28 +345,35 @@ static void PlaceBlockMarker(MachineBasicBlock &MBB, MachineFunction &MF,      // Header is the header of a loop that does not lexically contain MBB, so      // the BLOCK needs to be above the LOOP, after any END constructs.      InsertPos = Header->begin(); -    while (InsertPos->getOpcode() != WebAssembly::LOOP) +    while (InsertPos->getOpcode() == WebAssembly::END_BLOCK || +           InsertPos->getOpcode() == WebAssembly::END_LOOP)        ++InsertPos;    } else {      // Otherwise, insert the BLOCK as late in Header as we can, but before the      // beginning of the local expression tree and any nested BLOCKs.      InsertPos = Header->getFirstTerminator(); -    while (InsertPos != Header->begin() && IsChild(*prev(InsertPos), MFI) && -           prev(InsertPos)->getOpcode() != WebAssembly::LOOP && -           prev(InsertPos)->getOpcode() != WebAssembly::END_BLOCK && -           prev(InsertPos)->getOpcode() != WebAssembly::END_LOOP) +    while (InsertPos != Header->begin() && +           WebAssembly::isChild(*std::prev(InsertPos), MFI) && +           std::prev(InsertPos)->getOpcode() != WebAssembly::LOOP && +           std::prev(InsertPos)->getOpcode() != WebAssembly::END_BLOCK && +           std::prev(InsertPos)->getOpcode() != WebAssembly::END_LOOP)        --InsertPos;    }    // Add the BLOCK. -  BuildMI(*Header, InsertPos, DebugLoc(), TII.get(WebAssembly::BLOCK)); +  MachineInstr *Begin = BuildMI(*Header, InsertPos, DebugLoc(), +                                TII.get(WebAssembly::BLOCK)) +      .addImm(int64_t(WebAssembly::ExprType::Void));    // Mark the end of the block.    InsertPos = MBB.begin();    while (InsertPos != MBB.end() && -         InsertPos->getOpcode() == WebAssembly::END_LOOP) +         InsertPos->getOpcode() == WebAssembly::END_LOOP && +         LoopTops[&*InsertPos]->getParent()->getNumber() >= Header->getNumber())      ++InsertPos; -  BuildMI(MBB, InsertPos, DebugLoc(), TII.get(WebAssembly::END_BLOCK)); +  MachineInstr *End = BuildMI(MBB, InsertPos, DebugLoc(), +                              TII.get(WebAssembly::END_BLOCK)); +  BlockTops[End] = Begin;    // Track the farthest-spanning scope that ends at this point.    int Number = MBB.getNumber(); @@ -397,7 +386,7 @@ static void PlaceBlockMarker(MachineBasicBlock &MBB, MachineFunction &MF,  static void PlaceLoopMarker(      MachineBasicBlock &MBB, MachineFunction &MF,      SmallVectorImpl<MachineBasicBlock *> &ScopeTops, -    DenseMap<const MachineInstr *, const MachineBasicBlock *> &LoopTops, +    DenseMap<const MachineInstr *, MachineInstr *> &LoopTops,      const WebAssemblyInstrInfo &TII, const MachineLoopInfo &MLI) {    MachineLoop *Loop = MLI.getLoopFor(&MBB);    if (!Loop || Loop->getHeader() != &MBB) @@ -406,13 +395,13 @@ static void PlaceLoopMarker(    // The operand of a LOOP is the first block after the loop. If the loop is the    // bottom of the function, insert a dummy block at the end.    MachineBasicBlock *Bottom = LoopBottom(Loop); -  auto Iter = next(MachineFunction::iterator(Bottom)); +  auto Iter = std::next(MachineFunction::iterator(Bottom));    if (Iter == MF.end()) {      MachineBasicBlock *Label = MF.CreateMachineBasicBlock();      // Give it a fake predecessor so that AsmPrinter prints its label.      Label->addSuccessor(Label);      MF.push_back(Label); -    Iter = next(MachineFunction::iterator(Bottom)); +    Iter = std::next(MachineFunction::iterator(Bottom));    }    MachineBasicBlock *AfterLoop = &*Iter; @@ -422,12 +411,14 @@ static void PlaceLoopMarker(    while (InsertPos != MBB.end() &&           InsertPos->getOpcode() == WebAssembly::END_LOOP)      ++InsertPos; -  BuildMI(MBB, InsertPos, DebugLoc(), TII.get(WebAssembly::LOOP)); +  MachineInstr *Begin = BuildMI(MBB, InsertPos, DebugLoc(), +                                TII.get(WebAssembly::LOOP)) +      .addImm(int64_t(WebAssembly::ExprType::Void));    // Mark the end of the loop.    MachineInstr *End = BuildMI(*AfterLoop, AfterLoop->begin(), DebugLoc(),                                TII.get(WebAssembly::END_LOOP)); -  LoopTops[End] = &MBB; +  LoopTops[End] = Begin;    assert((!ScopeTops[AfterLoop->getNumber()] ||            ScopeTops[AfterLoop->getNumber()]->getNumber() < MBB.getNumber()) && @@ -449,6 +440,54 @@ GetDepth(const SmallVectorImpl<const MachineBasicBlock *> &Stack,    return Depth;  } +/// In normal assembly languages, when the end of a function is unreachable, +/// because the function ends in an infinite loop or a noreturn call or similar, +/// it isn't necessary to worry about the function return type at the end of +/// the function, because it's never reached. However, in WebAssembly, blocks +/// that end at the function end need to have a return type signature that +/// matches the function signature, even though it's unreachable. This function +/// checks for such cases and fixes up the signatures. +static void FixEndsAtEndOfFunction( +    MachineFunction &MF, +    const WebAssemblyFunctionInfo &MFI, +    DenseMap<const MachineInstr *, MachineInstr *> &BlockTops, +    DenseMap<const MachineInstr *, MachineInstr *> &LoopTops) { +  assert(MFI.getResults().size() <= 1); + +  if (MFI.getResults().empty()) +    return; + +  WebAssembly::ExprType retType; +  switch (MFI.getResults().front().SimpleTy) { +  case MVT::i32: retType = WebAssembly::ExprType::I32; break; +  case MVT::i64: retType = WebAssembly::ExprType::I64; break; +  case MVT::f32: retType = WebAssembly::ExprType::F32; break; +  case MVT::f64: retType = WebAssembly::ExprType::F64; break; +  case MVT::v16i8: retType = WebAssembly::ExprType::I8x16; break; +  case MVT::v8i16: retType = WebAssembly::ExprType::I16x8; break; +  case MVT::v4i32: retType = WebAssembly::ExprType::I32x4; break; +  case MVT::v4f32: retType = WebAssembly::ExprType::F32x4; break; +  default: llvm_unreachable("unexpected return type"); +  } + +  for (MachineBasicBlock &MBB : reverse(MF)) { +    for (MachineInstr &MI : reverse(MBB)) { +      if (MI.isPosition() || MI.isDebugValue()) +        continue; +      if (MI.getOpcode() == WebAssembly::END_BLOCK) { +        BlockTops[&MI]->getOperand(0).setImm(int32_t(retType)); +        continue; +      } +      if (MI.getOpcode() == WebAssembly::END_LOOP) { +        LoopTops[&MI]->getOperand(0).setImm(int32_t(retType)); +        continue; +      } +      // Something other than an `end`. We're done. +      return; +    } +  } +} +  /// Insert LOOP and BLOCK markers at appropriate places.  static void PlaceMarkers(MachineFunction &MF, const MachineLoopInfo &MLI,                           const WebAssemblyInstrInfo &TII, @@ -461,15 +500,18 @@ static void PlaceMarkers(MachineFunction &MF, const MachineLoopInfo &MLI,    // we may insert at the end.    SmallVector<MachineBasicBlock *, 8> ScopeTops(MF.getNumBlockIDs() + 1); -  // For eacn LOOP_END, the corresponding LOOP. -  DenseMap<const MachineInstr *, const MachineBasicBlock *> LoopTops; +  // For each LOOP_END, the corresponding LOOP. +  DenseMap<const MachineInstr *, MachineInstr *> LoopTops; + +  // For each END_BLOCK, the corresponding BLOCK. +  DenseMap<const MachineInstr *, MachineInstr *> BlockTops;    for (auto &MBB : MF) {      // Place the LOOP for MBB if MBB is the header of a loop.      PlaceLoopMarker(MBB, MF, ScopeTops, LoopTops, TII, MLI);      // Place the BLOCK for MBB if MBB is branched to from above. -    PlaceBlockMarker(MBB, MF, ScopeTops, TII, MLI, MDT, MFI); +    PlaceBlockMarker(MBB, MF, ScopeTops, BlockTops, LoopTops, TII, MLI, MDT, MFI);    }    // Now rewrite references to basic blocks to be depth immediates. @@ -478,21 +520,19 @@ static void PlaceMarkers(MachineFunction &MF, const MachineLoopInfo &MLI,      for (auto &MI : reverse(MBB)) {        switch (MI.getOpcode()) {        case WebAssembly::BLOCK: -        assert(ScopeTops[Stack.back()->getNumber()] == &MBB && +        assert(ScopeTops[Stack.back()->getNumber()]->getNumber() <= MBB.getNumber() &&                 "Block should be balanced");          Stack.pop_back();          break;        case WebAssembly::LOOP:          assert(Stack.back() == &MBB && "Loop top should be balanced");          Stack.pop_back(); -        Stack.pop_back();          break;        case WebAssembly::END_BLOCK:          Stack.push_back(&MBB);          break;        case WebAssembly::END_LOOP: -        Stack.push_back(&MBB); -        Stack.push_back(LoopTops[&MI]); +        Stack.push_back(LoopTops[&MI]->getParent());          break;        default:          if (MI.isTerminator()) { @@ -511,6 +551,10 @@ static void PlaceMarkers(MachineFunction &MF, const MachineLoopInfo &MLI,      }    }    assert(Stack.empty() && "Control flow should be balanced"); + +  // Fix up block/loop signatures at the end of the function to conform to +  // WebAssembly's rules. +  FixEndsAtEndOfFunction(MF, MFI, BlockTops, LoopTops);  }  bool WebAssemblyCFGStackify::runOnMachineFunction(MachineFunction &MF) { @@ -520,7 +564,7 @@ bool WebAssemblyCFGStackify::runOnMachineFunction(MachineFunction &MF) {    const auto &MLI = getAnalysis<MachineLoopInfo>();    auto &MDT = getAnalysis<MachineDominatorTree>(); -  // Liveness is not tracked for EXPR_STACK physreg. +  // Liveness is not tracked for VALUE_STACK physreg.    const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();    WebAssemblyFunctionInfo &MFI = *MF.getInfo<WebAssemblyFunctionInfo>();    MF.getRegInfo().invalidateLiveness(); | 
