| //===- ExecutionDomainFix.cpp - Fix execution domain issues ----*- C++ -*--===// | |
| // | |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| // See https://llvm.org/LICENSE.txt for license information. | |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| // | |
| //===----------------------------------------------------------------------===// | |
| #include "llvm/CodeGen/ExecutionDomainFix.h" | |
| #include "llvm/CodeGen/MachineRegisterInfo.h" | |
| #include "llvm/CodeGen/TargetInstrInfo.h" | |
| #include "llvm/Support/Debug.h" | |
| using namespace llvm; | |
| #define DEBUG_TYPE "execution-deps-fix" | |
| iterator_range<SmallVectorImpl<int>::const_iterator> | |
| ExecutionDomainFix::regIndices(MCRegister Reg) const { | |
| assert(Reg < AliasMap.size() && "Invalid register"); | |
| const auto &Entry = AliasMap[Reg.id()]; | |
| 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 = llvm::countr_zero(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. | |
| const int Def = RDI->getReachingDef(mi, RC->getRegister(rx)); | |
| auto I = partition_point(Regs, [&](int I) { | |
| return RDI->getReachingDef(mi, RC->getRegister(I)) <= Def; | |
| }); | |
| 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 (const 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; | |
| RDI = &getAnalysis<ReachingDefInfoWrapperPass>().getRDI(); | |
| // 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).id()].push_back(i); | |
| } | |
| // Initialize the MBBOutRegsInfos | |
| MBBOutRegsInfos.resize(mf.getNumBlockIDs()); | |
| // Traverse the basic blocks. | |
| LoopTraversal Traversal; | |
| LoopTraversal::TraversalOrder TraversedMBBOrder = Traversal.traverse(mf); | |
| for (const LoopTraversal::TraversedMBBInfo &TraversedMBB : TraversedMBBOrder) | |
| processBasicBlock(TraversedMBB); | |
| for (const LiveRegsDVInfo &OutLiveRegs : MBBOutRegsInfos) | |
| for (DomainValue *OutLiveReg : OutLiveRegs) | |
| if (OutLiveReg) | |
| release(OutLiveReg); | |
| MBBOutRegsInfos.clear(); | |
| Avail.clear(); | |
| Allocator.DestroyAll(); | |
| return false; | |
| } |