bool MachineCSE::ProcessBlock(MachineBasicBlock *MBB) { bool Changed = false; SmallVector<std::pair<unsigned, unsigned>, 8> CSEPairs; SmallVector<unsigned, 2> ImplicitDefsToUpdate; SmallVector<unsigned, 2> ImplicitDefs; for (MachineBasicBlock::iterator I = MBB->begin(), E = MBB->end(); I != E; ) { MachineInstr *MI = &*I; ++I; if (!isCSECandidate(MI)) continue; bool FoundCSE = VNT.count(MI); if (!FoundCSE) { // Using trivial copy propagation to find more CSE opportunities. if (PerformTrivialCopyPropagation(MI, MBB)) { Changed = true; // After coalescing MI itself may become a copy. if (MI->isCopyLike()) continue; // Try again to see if CSE is possible. FoundCSE = VNT.count(MI); } } // Commute commutable instructions. bool Commuted = false; if (!FoundCSE && MI->isCommutable()) { if (MachineInstr *NewMI = TII->commuteInstruction(*MI)) { Commuted = true; FoundCSE = VNT.count(NewMI); if (NewMI != MI) { // New instruction. It doesn't need to be kept. NewMI->eraseFromParent(); Changed = true; } else if (!FoundCSE) // MI was changed but it didn't help, commute it back! (void)TII->commuteInstruction(*MI); } } // If the instruction defines physical registers and the values *may* be // used, then it's not safe to replace it with a common subexpression. // It's also not safe if the instruction uses physical registers. bool CrossMBBPhysDef = false; SmallSet<unsigned, 8> PhysRefs; SmallVector<unsigned, 2> PhysDefs; bool PhysUseDef = false; if (FoundCSE && hasLivePhysRegDefUses(MI, MBB, PhysRefs, PhysDefs, PhysUseDef)) { FoundCSE = false; // ... Unless the CS is local or is in the sole predecessor block // and it also defines the physical register which is not clobbered // in between and the physical register uses were not clobbered. // This can never be the case if the instruction both uses and // defines the same physical register, which was detected above. if (!PhysUseDef) { unsigned CSVN = VNT.lookup(MI); MachineInstr *CSMI = Exps[CSVN]; if (PhysRegDefsReach(CSMI, MI, PhysRefs, PhysDefs, CrossMBBPhysDef)) FoundCSE = true; } } if (!FoundCSE) { VNT.insert(MI, CurrVN++); Exps.push_back(MI); continue; } // Found a common subexpression, eliminate it. unsigned CSVN = VNT.lookup(MI); MachineInstr *CSMI = Exps[CSVN]; DEBUG(dbgs() << "Examining: " << *MI); DEBUG(dbgs() << "*** Found a common subexpression: " << *CSMI); // Check if it's profitable to perform this CSE. bool DoCSE = true; unsigned NumDefs = MI->getDesc().getNumDefs() + MI->getDesc().getNumImplicitDefs(); for (unsigned i = 0, e = MI->getNumOperands(); NumDefs && i != e; ++i) { MachineOperand &MO = MI->getOperand(i); if (!MO.isReg() || !MO.isDef()) continue; unsigned OldReg = MO.getReg(); unsigned NewReg = CSMI->getOperand(i).getReg(); // Go through implicit defs of CSMI and MI, if a def is not dead at MI, // we should make sure it is not dead at CSMI. if (MO.isImplicit() && !MO.isDead() && CSMI->getOperand(i).isDead()) ImplicitDefsToUpdate.push_back(i); // Keep track of implicit defs of CSMI and MI, to clear possibly // made-redundant kill flags. if (MO.isImplicit() && !MO.isDead() && OldReg == NewReg) ImplicitDefs.push_back(OldReg); if (OldReg == NewReg) { --NumDefs; continue; } assert(TargetRegisterInfo::isVirtualRegister(OldReg) && TargetRegisterInfo::isVirtualRegister(NewReg) && "Do not CSE physical register defs!"); if (!isProfitableToCSE(NewReg, OldReg, CSMI, MI)) { DEBUG(dbgs() << "*** Not profitable, avoid CSE!\n"); DoCSE = false; break; } // Don't perform CSE if the result of the old instruction cannot exist // within the register class of the new instruction. const TargetRegisterClass *OldRC = MRI->getRegClass(OldReg); if (!MRI->constrainRegClass(NewReg, OldRC)) { DEBUG(dbgs() << "*** Not the same register class, avoid CSE!\n"); DoCSE = false; break; } CSEPairs.push_back(std::make_pair(OldReg, NewReg)); --NumDefs; } // Actually perform the elimination. if (DoCSE) { for (std::pair<unsigned, unsigned> &CSEPair : CSEPairs) { unsigned OldReg = CSEPair.first; unsigned NewReg = CSEPair.second; // OldReg may have been unused but is used now, clear the Dead flag MachineInstr *Def = MRI->getUniqueVRegDef(NewReg); assert(Def != nullptr && "CSEd register has no unique definition?"); Def->clearRegisterDeads(NewReg); // Replace with NewReg and clear kill flags which may be wrong now. MRI->replaceRegWith(OldReg, NewReg); MRI->clearKillFlags(NewReg); } // Go through implicit defs of CSMI and MI, if a def is not dead at MI, // we should make sure it is not dead at CSMI. for (unsigned ImplicitDefToUpdate : ImplicitDefsToUpdate) CSMI->getOperand(ImplicitDefToUpdate).setIsDead(false); // Go through implicit defs of CSMI and MI, and clear the kill flags on // their uses in all the instructions between CSMI and MI. // We might have made some of the kill flags redundant, consider: // subs ... %NZCV<imp-def> <- CSMI // csinc ... %NZCV<imp-use,kill> <- this kill flag isn't valid anymore // subs ... %NZCV<imp-def> <- MI, to be eliminated // csinc ... %NZCV<imp-use,kill> // Since we eliminated MI, and reused a register imp-def'd by CSMI // (here %NZCV), that register, if it was killed before MI, should have // that kill flag removed, because it's lifetime was extended. if (CSMI->getParent() == MI->getParent()) { for (MachineBasicBlock::iterator II = CSMI, IE = MI; II != IE; ++II) for (auto ImplicitDef : ImplicitDefs) if (MachineOperand *MO = II->findRegisterUseOperand( ImplicitDef, /*isKill=*/true, TRI)) MO->setIsKill(false); } else { // If the instructions aren't in the same BB, bail out and clear the // kill flag on all uses of the imp-def'd register. for (auto ImplicitDef : ImplicitDefs) MRI->clearKillFlags(ImplicitDef); } if (CrossMBBPhysDef) { // Add physical register defs now coming in from a predecessor to MBB // livein list. while (!PhysDefs.empty()) { unsigned LiveIn = PhysDefs.pop_back_val(); if (!MBB->isLiveIn(LiveIn)) MBB->addLiveIn(LiveIn); } ++NumCrossBBCSEs; } MI->eraseFromParent(); ++NumCSEs; if (!PhysRefs.empty()) ++NumPhysCSEs; if (Commuted) ++NumCommutes; Changed = true; } else { VNT.insert(MI, CurrVN++); Exps.push_back(MI); } CSEPairs.clear(); ImplicitDefsToUpdate.clear(); ImplicitDefs.clear(); } return Changed; }