// We have identified this II could be feeder to NVJ, // verify that it can be. static bool canBeFeederToNewValueJump(const HexagonInstrInfo *QII, const TargetRegisterInfo *TRI, MachineBasicBlock::iterator II, MachineBasicBlock::iterator end, MachineBasicBlock::iterator skip, MachineFunction &MF) { // Predicated instruction can not be feeder to NVJ. if (QII->isPredicated(*II)) return false; // Bail out if feederReg is a paired register (double regs in // our case). One would think that we can check to see if a given // register cmpReg1 or cmpReg2 is a sub register of feederReg // using -- if (QRI->isSubRegister(feederReg, cmpReg1) logic // before the callsite of this function // But we can not as it comes in the following fashion. // %D0<def> = Hexagon_S2_lsr_r_p %D0<kill>, %R2<kill> // %R0<def> = KILL %R0, %D0<imp-use,kill> // %P0<def> = CMPEQri %R0<kill>, 0 // Hence, we need to check if it's a KILL instruction. if (II->getOpcode() == TargetOpcode::KILL) return false; if (II->isImplicitDef()) return false; // Make sure there there is no 'def' or 'use' of any of the uses of // feeder insn between it's definition, this MI and jump, jmpInst // skipping compare, cmpInst. // Here's the example. // r21=memub(r22+r24<<#0) // p0 = cmp.eq(r21, #0) // r4=memub(r3+r21<<#0) // if (p0.new) jump:t .LBB29_45 // Without this check, it will be converted into // r4=memub(r3+r21<<#0) // r21=memub(r22+r24<<#0) // p0 = cmp.eq(r21, #0) // if (p0.new) jump:t .LBB29_45 // and result WAR hazards if converted to New Value Jump. for (unsigned i = 0; i < II->getNumOperands(); ++i) { if (II->getOperand(i).isReg() && (II->getOperand(i).isUse() || II->getOperand(i).isDef())) { MachineBasicBlock::iterator localII = II; ++localII; unsigned Reg = II->getOperand(i).getReg(); for (MachineBasicBlock::iterator localBegin = localII; localBegin != end; ++localBegin) { if (localBegin == skip ) continue; // Check for Subregisters too. if (localBegin->modifiesRegister(Reg, TRI) || localBegin->readsRegister(Reg, TRI)) return false; } } } return true; }
bool Filler::delayHasHazard(MachineBasicBlock::iterator candidate, bool &sawLoad, bool &sawStore, SmallSet<unsigned, 32> &RegDefs, SmallSet<unsigned, 32> &RegUses) { if (candidate->isImplicitDef() || candidate->isKill()) return true; if (candidate->mayLoad()) { sawLoad = true; if (sawStore) return true; } if (candidate->mayStore()) { if (sawStore) return true; sawStore = true; if (sawLoad) return true; } for (unsigned i = 0, e = candidate->getNumOperands(); i!= e; ++i) { const MachineOperand &MO = candidate->getOperand(i); if (!MO.isReg()) continue; // skip unsigned Reg = MO.getReg(); if (MO.isDef()) { // check whether Reg is defined or used before delay slot. if (IsRegInSet(RegDefs, Reg) || IsRegInSet(RegUses, Reg)) return true; } if (MO.isUse()) { // check whether Reg is defined before delay slot. if (IsRegInSet(RegDefs, Reg)) return true; } } unsigned Opcode = candidate->getOpcode(); // LD and LDD may have NOPs inserted afterwards in the case of some LEON // processors, so we can't use the delay slot if this feature is switched-on. if (Subtarget->insertNOPLoad() && Opcode >= SP::LDDArr && Opcode <= SP::LDrr) return true; // Same as above for FDIV and FSQRT on some LEON processors. if (Subtarget->fixAllFDIVSQRT() && Opcode >= SP::FDIVD && Opcode <= SP::FSQRTD) return true; return false; }
bool Filler::delayHasHazard(MachineBasicBlock::iterator candidate, bool &sawLoad, bool &sawStore, SmallSet<unsigned, 32> &RegDefs, SmallSet<unsigned, 32> &RegUses) { if (candidate->isImplicitDef() || candidate->isKill()) return true; // Loads or stores cannot be moved past a store to the delay slot // and stores cannot be moved past a load. if (candidate->mayLoad()) { if (sawStore) return true; sawLoad = true; } if (candidate->mayStore()) { if (sawStore) return true; sawStore = true; if (sawLoad) return true; } assert((!candidate->isCall() && !candidate->isReturn()) && "Cannot put calls or returns in delay slot."); for (unsigned i = 0, e = candidate->getNumOperands(); i!= e; ++i) { const MachineOperand &MO = candidate->getOperand(i); unsigned Reg; if (!MO.isReg() || !(Reg = MO.getReg())) continue; // skip if (MO.isDef()) { // check whether Reg is defined or used before delay slot. if (IsRegInSet(RegDefs, Reg) || IsRegInSet(RegUses, Reg)) return true; } if (MO.isUse()) { // check whether Reg is defined before delay slot. if (IsRegInSet(RegDefs, Reg)) return true; } } return false; }
bool Filler::delayHasHazard(MachineBasicBlock::iterator candidate, bool &sawLoad, bool &sawStore, SmallSet<unsigned, 32> &RegDefs, SmallSet<unsigned, 32> &RegUses) { if (candidate->isImplicitDef() || candidate->isKill()) return true; if (candidate->mayLoad()) { sawLoad = true; if (sawStore) return true; } if (candidate->mayStore()) { if (sawStore) return true; sawStore = true; if (sawLoad) return true; } for (unsigned i = 0, e = candidate->getNumOperands(); i!= e; ++i) { const MachineOperand &MO = candidate->getOperand(i); if (!MO.isReg()) continue; // skip unsigned Reg = MO.getReg(); if (MO.isDef()) { //check whether Reg is defined or used before delay slot. if (IsRegInSet(RegDefs, Reg) || IsRegInSet(RegUses, Reg)) return true; } if (MO.isUse()) { //check whether Reg is defined before delay slot. if (IsRegInSet(RegDefs, Reg)) return true; } } return false; }