diff options
Diffstat (limited to 'contrib/llvm/lib/CodeGen/ExecutionDomainFix.cpp')
| -rw-r--r-- | contrib/llvm/lib/CodeGen/ExecutionDomainFix.cpp | 473 | 
1 files changed, 473 insertions, 0 deletions
| diff --git a/contrib/llvm/lib/CodeGen/ExecutionDomainFix.cpp b/contrib/llvm/lib/CodeGen/ExecutionDomainFix.cpp new file mode 100644 index 000000000000..458dcf2b0e26 --- /dev/null +++ b/contrib/llvm/lib/CodeGen/ExecutionDomainFix.cpp @@ -0,0 +1,473 @@ +//===- ExecutionDomainFix.cpp - Fix execution domain issues ----*- C++ -*--===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/CodeGen/ExecutionDomainFix.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/CodeGen/TargetInstrInfo.h" + +using namespace llvm; + +#define DEBUG_TYPE "execution-deps-fix" + +iterator_range<SmallVectorImpl<int>::const_iterator> +ExecutionDomainFix::regIndices(unsigned Reg) const { +  assert(Reg < AliasMap.size() && "Invalid register"); +  const auto &Entry = AliasMap[Reg]; +  return make_range(Entry.begin(), Entry.end()); +} + +DomainValue *ExecutionDomainFix::alloc(int domain) { +  DomainValue *dv = Avail.empty() ? new (Allocator.Allocate()) DomainValue +                                  : Avail.pop_back_val(); +  if (domain >= 0) +    dv->addDomain(domain); +  assert(dv->Refs == 0 && "Reference count wasn't cleared"); +  assert(!dv->Next && "Chained DomainValue shouldn't have been recycled"); +  return dv; +} + +void ExecutionDomainFix::release(DomainValue *DV) { +  while (DV) { +    assert(DV->Refs && "Bad DomainValue"); +    if (--DV->Refs) +      return; + +    // There are no more DV references. Collapse any contained instructions. +    if (DV->AvailableDomains && !DV->isCollapsed()) +      collapse(DV, DV->getFirstDomain()); + +    DomainValue *Next = DV->Next; +    DV->clear(); +    Avail.push_back(DV); +    // Also release the next DomainValue in the chain. +    DV = Next; +  } +} + +DomainValue *ExecutionDomainFix::resolve(DomainValue *&DVRef) { +  DomainValue *DV = DVRef; +  if (!DV || !DV->Next) +    return DV; + +  // DV has a chain. Find the end. +  do +    DV = DV->Next; +  while (DV->Next); + +  // Update DVRef to point to DV. +  retain(DV); +  release(DVRef); +  DVRef = DV; +  return DV; +} + +void ExecutionDomainFix::setLiveReg(int rx, DomainValue *dv) { +  assert(unsigned(rx) < NumRegs && "Invalid index"); +  assert(!LiveRegs.empty() && "Must enter basic block first."); + +  if (LiveRegs[rx] == dv) +    return; +  if (LiveRegs[rx]) +    release(LiveRegs[rx]); +  LiveRegs[rx] = retain(dv); +} + +void ExecutionDomainFix::kill(int rx) { +  assert(unsigned(rx) < NumRegs && "Invalid index"); +  assert(!LiveRegs.empty() && "Must enter basic block first."); +  if (!LiveRegs[rx]) +    return; + +  release(LiveRegs[rx]); +  LiveRegs[rx] = nullptr; +} + +void ExecutionDomainFix::force(int rx, unsigned domain) { +  assert(unsigned(rx) < NumRegs && "Invalid index"); +  assert(!LiveRegs.empty() && "Must enter basic block first."); +  if (DomainValue *dv = LiveRegs[rx]) { +    if (dv->isCollapsed()) +      dv->addDomain(domain); +    else if (dv->hasDomain(domain)) +      collapse(dv, domain); +    else { +      // This is an incompatible open DomainValue. Collapse it to whatever and +      // force the new value into domain. This costs a domain crossing. +      collapse(dv, dv->getFirstDomain()); +      assert(LiveRegs[rx] && "Not live after collapse?"); +      LiveRegs[rx]->addDomain(domain); +    } +  } else { +    // Set up basic collapsed DomainValue. +    setLiveReg(rx, alloc(domain)); +  } +} + +void ExecutionDomainFix::collapse(DomainValue *dv, unsigned domain) { +  assert(dv->hasDomain(domain) && "Cannot collapse"); + +  // Collapse all the instructions. +  while (!dv->Instrs.empty()) +    TII->setExecutionDomain(*dv->Instrs.pop_back_val(), domain); +  dv->setSingleDomain(domain); + +  // If there are multiple users, give them new, unique DomainValues. +  if (!LiveRegs.empty() && dv->Refs > 1) +    for (unsigned rx = 0; rx != NumRegs; ++rx) +      if (LiveRegs[rx] == dv) +        setLiveReg(rx, alloc(domain)); +} + +bool ExecutionDomainFix::merge(DomainValue *A, DomainValue *B) { +  assert(!A->isCollapsed() && "Cannot merge into collapsed"); +  assert(!B->isCollapsed() && "Cannot merge from collapsed"); +  if (A == B) +    return true; +  // Restrict to the domains that A and B have in common. +  unsigned common = A->getCommonDomains(B->AvailableDomains); +  if (!common) +    return false; +  A->AvailableDomains = common; +  A->Instrs.append(B->Instrs.begin(), B->Instrs.end()); + +  // Clear the old DomainValue so we won't try to swizzle instructions twice. +  B->clear(); +  // All uses of B are referred to A. +  B->Next = retain(A); + +  for (unsigned rx = 0; rx != NumRegs; ++rx) { +    assert(!LiveRegs.empty() && "no space allocated for live registers"); +    if (LiveRegs[rx] == B) +      setLiveReg(rx, A); +  } +  return true; +} + +void ExecutionDomainFix::enterBasicBlock( +    const LoopTraversal::TraversedMBBInfo &TraversedMBB) { + +  MachineBasicBlock *MBB = TraversedMBB.MBB; + +  // Set up LiveRegs to represent registers entering MBB. +  // Set default domain values to 'no domain' (nullptr) +  if (LiveRegs.empty()) +    LiveRegs.assign(NumRegs, nullptr); + +  // This is the entry block. +  if (MBB->pred_empty()) { +    LLVM_DEBUG(dbgs() << printMBBReference(*MBB) << ": entry\n"); +    return; +  } + +  // Try to coalesce live-out registers from predecessors. +  for (MachineBasicBlock *pred : MBB->predecessors()) { +    assert(unsigned(pred->getNumber()) < MBBOutRegsInfos.size() && +           "Should have pre-allocated MBBInfos for all MBBs"); +    LiveRegsDVInfo &Incoming = MBBOutRegsInfos[pred->getNumber()]; +    // Incoming is null if this is a backedge from a BB +    // we haven't processed yet +    if (Incoming.empty()) +      continue; + +    for (unsigned rx = 0; rx != NumRegs; ++rx) { +      DomainValue *pdv = resolve(Incoming[rx]); +      if (!pdv) +        continue; +      if (!LiveRegs[rx]) { +        setLiveReg(rx, pdv); +        continue; +      } + +      // We have a live DomainValue from more than one predecessor. +      if (LiveRegs[rx]->isCollapsed()) { +        // We are already collapsed, but predecessor is not. Force it. +        unsigned Domain = LiveRegs[rx]->getFirstDomain(); +        if (!pdv->isCollapsed() && pdv->hasDomain(Domain)) +          collapse(pdv, Domain); +        continue; +      } + +      // Currently open, merge in predecessor. +      if (!pdv->isCollapsed()) +        merge(LiveRegs[rx], pdv); +      else +        force(rx, pdv->getFirstDomain()); +    } +  } +  LLVM_DEBUG(dbgs() << printMBBReference(*MBB) +                    << (!TraversedMBB.IsDone ? ": incomplete\n" +                                             : ": all preds known\n")); +} + +void ExecutionDomainFix::leaveBasicBlock( +    const LoopTraversal::TraversedMBBInfo &TraversedMBB) { +  assert(!LiveRegs.empty() && "Must enter basic block first."); +  unsigned MBBNumber = TraversedMBB.MBB->getNumber(); +  assert(MBBNumber < MBBOutRegsInfos.size() && +         "Unexpected basic block number."); +  // Save register clearances at end of MBB - used by enterBasicBlock(). +  for (DomainValue *OldLiveReg : MBBOutRegsInfos[MBBNumber]) { +    release(OldLiveReg); +  } +  MBBOutRegsInfos[MBBNumber] = LiveRegs; +  LiveRegs.clear(); +} + +bool ExecutionDomainFix::visitInstr(MachineInstr *MI) { +  // Update instructions with explicit execution domains. +  std::pair<uint16_t, uint16_t> DomP = TII->getExecutionDomain(*MI); +  if (DomP.first) { +    if (DomP.second) +      visitSoftInstr(MI, DomP.second); +    else +      visitHardInstr(MI, DomP.first); +  } + +  return !DomP.first; +} + +void ExecutionDomainFix::processDefs(MachineInstr *MI, bool Kill) { +  assert(!MI->isDebugInstr() && "Won't process debug values"); +  const MCInstrDesc &MCID = MI->getDesc(); +  for (unsigned i = 0, +                e = MI->isVariadic() ? MI->getNumOperands() : MCID.getNumDefs(); +       i != e; ++i) { +    MachineOperand &MO = MI->getOperand(i); +    if (!MO.isReg()) +      continue; +    if (MO.isUse()) +      continue; +    for (int rx : regIndices(MO.getReg())) { +      // This instruction explicitly defines rx. +      LLVM_DEBUG(dbgs() << printReg(RC->getRegister(rx), TRI) << ":\t" << *MI); + +      // Kill off domains redefined by generic instructions. +      if (Kill) +        kill(rx); +    } +  } +} + +void ExecutionDomainFix::visitHardInstr(MachineInstr *mi, unsigned domain) { +  // Collapse all uses. +  for (unsigned i = mi->getDesc().getNumDefs(), +                e = mi->getDesc().getNumOperands(); +       i != e; ++i) { +    MachineOperand &mo = mi->getOperand(i); +    if (!mo.isReg()) +      continue; +    for (int rx : regIndices(mo.getReg())) { +      force(rx, domain); +    } +  } + +  // Kill all defs and force them. +  for (unsigned i = 0, e = mi->getDesc().getNumDefs(); i != e; ++i) { +    MachineOperand &mo = mi->getOperand(i); +    if (!mo.isReg()) +      continue; +    for (int rx : regIndices(mo.getReg())) { +      kill(rx); +      force(rx, domain); +    } +  } +} + +void ExecutionDomainFix::visitSoftInstr(MachineInstr *mi, unsigned mask) { +  // Bitmask of available domains for this instruction after taking collapsed +  // operands into account. +  unsigned available = mask; + +  // Scan the explicit use operands for incoming domains. +  SmallVector<int, 4> used; +  if (!LiveRegs.empty()) +    for (unsigned i = mi->getDesc().getNumDefs(), +                  e = mi->getDesc().getNumOperands(); +         i != e; ++i) { +      MachineOperand &mo = mi->getOperand(i); +      if (!mo.isReg()) +        continue; +      for (int rx : regIndices(mo.getReg())) { +        DomainValue *dv = LiveRegs[rx]; +        if (dv == nullptr) +          continue; +        // Bitmask of domains that dv and available have in common. +        unsigned common = dv->getCommonDomains(available); +        // Is it possible to use this collapsed register for free? +        if (dv->isCollapsed()) { +          // Restrict available domains to the ones in common with the operand. +          // If there are no common domains, we must pay the cross-domain +          // penalty for this operand. +          if (common) +            available = common; +        } else if (common) +          // Open DomainValue is compatible, save it for merging. +          used.push_back(rx); +        else +          // Open DomainValue is not compatible with instruction. It is useless +          // now. +          kill(rx); +      } +    } + +  // If the collapsed operands force a single domain, propagate the collapse. +  if (isPowerOf2_32(available)) { +    unsigned domain = countTrailingZeros(available); +    TII->setExecutionDomain(*mi, domain); +    visitHardInstr(mi, domain); +    return; +  } + +  // Kill off any remaining uses that don't match available, and build a list of +  // incoming DomainValues that we want to merge. +  SmallVector<int, 4> Regs; +  for (int rx : used) { +    assert(!LiveRegs.empty() && "no space allocated for live registers"); +    DomainValue *&LR = LiveRegs[rx]; +    // This useless DomainValue could have been missed above. +    if (!LR->getCommonDomains(available)) { +      kill(rx); +      continue; +    } +    // Sorted insertion. +    // Enables giving priority to the latest domains during merging. +    auto I = std::upper_bound( +        Regs.begin(), Regs.end(), rx, [&](int LHS, const int RHS) { +          return RDA->getReachingDef(mi, RC->getRegister(LHS)) < +                 RDA->getReachingDef(mi, RC->getRegister(RHS)); +        }); +    Regs.insert(I, rx); +  } + +  // doms are now sorted in order of appearance. Try to merge them all, giving +  // priority to the latest ones. +  DomainValue *dv = nullptr; +  while (!Regs.empty()) { +    if (!dv) { +      dv = LiveRegs[Regs.pop_back_val()]; +      // Force the first dv to match the current instruction. +      dv->AvailableDomains = dv->getCommonDomains(available); +      assert(dv->AvailableDomains && "Domain should have been filtered"); +      continue; +    } + +    DomainValue *Latest = LiveRegs[Regs.pop_back_val()]; +    // Skip already merged values. +    if (Latest == dv || Latest->Next) +      continue; +    if (merge(dv, Latest)) +      continue; + +    // If latest didn't merge, it is useless now. Kill all registers using it. +    for (int i : used) { +      assert(!LiveRegs.empty() && "no space allocated for live registers"); +      if (LiveRegs[i] == Latest) +        kill(i); +    } +  } + +  // dv is the DomainValue we are going to use for this instruction. +  if (!dv) { +    dv = alloc(); +    dv->AvailableDomains = available; +  } +  dv->Instrs.push_back(mi); + +  // Finally set all defs and non-collapsed uses to dv. We must iterate through +  // all the operators, including imp-def ones. +  for (MachineOperand &mo : mi->operands()) { +    if (!mo.isReg()) +      continue; +    for (int rx : regIndices(mo.getReg())) { +      if (!LiveRegs[rx] || (mo.isDef() && LiveRegs[rx] != dv)) { +        kill(rx); +        setLiveReg(rx, dv); +      } +    } +  } +} + +void ExecutionDomainFix::processBasicBlock( +    const LoopTraversal::TraversedMBBInfo &TraversedMBB) { +  enterBasicBlock(TraversedMBB); +  // If this block is not done, it makes little sense to make any decisions +  // based on clearance information. We need to make a second pass anyway, +  // and by then we'll have better information, so we can avoid doing the work +  // to try and break dependencies now. +  for (MachineInstr &MI : *TraversedMBB.MBB) { +    if (!MI.isDebugInstr()) { +      bool Kill = false; +      if (TraversedMBB.PrimaryPass) +        Kill = visitInstr(&MI); +      processDefs(&MI, Kill); +    } +  } +  leaveBasicBlock(TraversedMBB); +} + +bool ExecutionDomainFix::runOnMachineFunction(MachineFunction &mf) { +  if (skipFunction(mf.getFunction())) +    return false; +  MF = &mf; +  TII = MF->getSubtarget().getInstrInfo(); +  TRI = MF->getSubtarget().getRegisterInfo(); +  LiveRegs.clear(); +  assert(NumRegs == RC->getNumRegs() && "Bad regclass"); + +  LLVM_DEBUG(dbgs() << "********** FIX EXECUTION DOMAIN: " +                    << TRI->getRegClassName(RC) << " **********\n"); + +  // If no relevant registers are used in the function, we can skip it +  // completely. +  bool anyregs = false; +  const MachineRegisterInfo &MRI = mf.getRegInfo(); +  for (unsigned Reg : *RC) { +    if (MRI.isPhysRegUsed(Reg)) { +      anyregs = true; +      break; +    } +  } +  if (!anyregs) +    return false; + +  RDA = &getAnalysis<ReachingDefAnalysis>(); + +  // Initialize the AliasMap on the first use. +  if (AliasMap.empty()) { +    // Given a PhysReg, AliasMap[PhysReg] returns a list of indices into RC and +    // therefore the LiveRegs array. +    AliasMap.resize(TRI->getNumRegs()); +    for (unsigned i = 0, e = RC->getNumRegs(); i != e; ++i) +      for (MCRegAliasIterator AI(RC->getRegister(i), TRI, true); AI.isValid(); +           ++AI) +        AliasMap[*AI].push_back(i); +  } + +  // Initialize the MBBOutRegsInfos +  MBBOutRegsInfos.resize(mf.getNumBlockIDs()); + +  // Traverse the basic blocks. +  LoopTraversal Traversal; +  LoopTraversal::TraversalOrder TraversedMBBOrder = Traversal.traverse(mf); +  for (LoopTraversal::TraversedMBBInfo TraversedMBB : TraversedMBBOrder) { +    processBasicBlock(TraversedMBB); +  } + +  for (LiveRegsDVInfo OutLiveRegs : MBBOutRegsInfos) { +    for (DomainValue *OutLiveReg : OutLiveRegs) { +      if (OutLiveReg) +        release(OutLiveReg); +    } +  } +  MBBOutRegsInfos.clear(); +  Avail.clear(); +  Allocator.DestroyAll(); + +  return false; +} | 
