bool ExpandPseudo::expandCopyACC(MachineBasicBlock &MBB, Iter I, unsigned Dst, unsigned Src, unsigned RegSize) { // copy $vr0, src_lo // copy dst_lo, $vr0 // copy $vr1, src_hi // copy dst_hi, $vr1 const MipsSEInstrInfo &TII = *static_cast<const MipsSEInstrInfo*>(MF.getTarget().getInstrInfo()); const MipsRegisterInfo &RegInfo = *static_cast<const MipsRegisterInfo*>(MF.getTarget().getRegisterInfo()); const TargetRegisterClass *RC = RegInfo.intRegClass(RegSize); unsigned VR0 = MRI.createVirtualRegister(RC); unsigned VR1 = MRI.createVirtualRegister(RC); unsigned SrcKill = getKillRegState(I->getOperand(1).isKill()); unsigned DstLo = RegInfo.getSubReg(Dst, Mips::sub_lo); unsigned DstHi = RegInfo.getSubReg(Dst, Mips::sub_hi); unsigned SrcLo = RegInfo.getSubReg(Src, Mips::sub_lo); unsigned SrcHi = RegInfo.getSubReg(Src, Mips::sub_hi); DebugLoc DL = I->getDebugLoc(); BuildMI(MBB, I, DL, TII.get(TargetOpcode::COPY), VR0).addReg(SrcLo, SrcKill); BuildMI(MBB, I, DL, TII.get(TargetOpcode::COPY), DstLo) .addReg(VR0, RegState::Kill); BuildMI(MBB, I, DL, TII.get(TargetOpcode::COPY), VR1).addReg(SrcHi, SrcKill); BuildMI(MBB, I, DL, TII.get(TargetOpcode::COPY), DstHi) .addReg(VR1, RegState::Kill); return true; }
void ExpandPseudo::expandLoadACC(MachineBasicBlock &MBB, Iter I, unsigned RegSize) { // load $vr0, FI // copy lo, $vr0 // load $vr1, FI + 4 // copy hi, $vr1 assert(I->getOperand(0).isReg() && I->getOperand(1).isFI()); const MipsSEInstrInfo &TII = *static_cast<const MipsSEInstrInfo*>(MF.getTarget().getInstrInfo()); const MipsRegisterInfo &RegInfo = *static_cast<const MipsRegisterInfo*>(MF.getTarget().getRegisterInfo()); const TargetRegisterClass *RC = RegInfo.intRegClass(RegSize); unsigned VR0 = MRI.createVirtualRegister(RC); unsigned VR1 = MRI.createVirtualRegister(RC); unsigned Dst = I->getOperand(0).getReg(), FI = I->getOperand(1).getIndex(); unsigned Lo = RegInfo.getSubReg(Dst, Mips::sub_lo); unsigned Hi = RegInfo.getSubReg(Dst, Mips::sub_hi); DebugLoc DL = I->getDebugLoc(); const MCInstrDesc &Desc = TII.get(TargetOpcode::COPY); TII.loadRegFromStack(MBB, I, VR0, FI, RC, &RegInfo, 0); BuildMI(MBB, I, DL, Desc, Lo).addReg(VR0, RegState::Kill); TII.loadRegFromStack(MBB, I, VR1, FI, RC, &RegInfo, RegSize); BuildMI(MBB, I, DL, Desc, Hi).addReg(VR1, RegState::Kill); }
void ExpandPseudo::expandStoreACC(MachineBasicBlock &MBB, Iter I, unsigned RegSize) { // copy $vr0, lo // store $vr0, FI // copy $vr1, hi // store $vr1, FI + 4 assert(I->getOperand(0).isReg() && I->getOperand(1).isFI()); const MipsSEInstrInfo &TII = *static_cast<const MipsSEInstrInfo*>(MF.getTarget().getInstrInfo()); const MipsRegisterInfo &RegInfo = *static_cast<const MipsRegisterInfo*>(MF.getTarget().getRegisterInfo()); const TargetRegisterClass *RC = RegInfo.intRegClass(RegSize); unsigned VR0 = MRI.createVirtualRegister(RC); unsigned VR1 = MRI.createVirtualRegister(RC); unsigned Src = I->getOperand(0).getReg(), FI = I->getOperand(1).getIndex(); unsigned SrcKill = getKillRegState(I->getOperand(0).isKill()); unsigned Lo = RegInfo.getSubReg(Src, Mips::sub_lo); unsigned Hi = RegInfo.getSubReg(Src, Mips::sub_hi); DebugLoc DL = I->getDebugLoc(); BuildMI(MBB, I, DL, TII.get(TargetOpcode::COPY), VR0).addReg(Lo, SrcKill); TII.storeRegToStack(MBB, I, VR0, true, FI, RC, &RegInfo, 0); BuildMI(MBB, I, DL, TII.get(TargetOpcode::COPY), VR1).addReg(Hi, SrcKill); TII.storeRegToStack(MBB, I, VR1, true, FI, RC, &RegInfo, RegSize); }
bool ExpandPseudo::expandCopyACC(MachineBasicBlock &MBB, Iter I, unsigned MFHiOpc, unsigned MFLoOpc) { // mflo $vr0, src // copy dst_lo, $vr0 // mfhi $vr1, src // copy dst_hi, $vr1 unsigned Dst = I->getOperand(0).getReg(), Src = I->getOperand(1).getReg(); unsigned VRegSize = RegInfo.getMinimalPhysRegClass(Dst)->getSize() / 2; const TargetRegisterClass *RC = RegInfo.intRegClass(VRegSize); unsigned VR0 = MRI.createVirtualRegister(RC); unsigned VR1 = MRI.createVirtualRegister(RC); unsigned SrcKill = getKillRegState(I->getOperand(1).isKill()); unsigned DstLo = RegInfo.getSubReg(Dst, Mips::sub_lo); unsigned DstHi = RegInfo.getSubReg(Dst, Mips::sub_hi); DebugLoc DL = I->getDebugLoc(); BuildMI(MBB, I, DL, TII.get(MFLoOpc), VR0).addReg(Src); BuildMI(MBB, I, DL, TII.get(TargetOpcode::COPY), DstLo) .addReg(VR0, RegState::Kill); BuildMI(MBB, I, DL, TII.get(MFHiOpc), VR1).addReg(Src, SrcKill); BuildMI(MBB, I, DL, TII.get(TargetOpcode::COPY), DstHi) .addReg(VR1, RegState::Kill); return true; }
/// runOnMachineBasicBlock - Fill in delay slots for the given basic block. /// We assume there is only one delay slot per delayed instruction. bool Filler::runOnMachineBasicBlock(MachineBasicBlock &MBB) { bool Changed = false; for (Iter I = MBB.begin(); I != MBB.end(); ++I) { if (!hasUnoccupiedSlot(&*I)) continue; ++FilledSlots; Changed = true; // Delay slot filling is disabled at -O0. if (!DisableDelaySlotFiller && (TM.getOptLevel() != CodeGenOpt::None)) { if (searchBackward(MBB, I)) continue; if (I->isTerminator()) { if (searchSuccBBs(MBB, I)) continue; } else if (searchForward(MBB, I)) { continue; } } // Bundle the NOP to the instruction with the delay slot. BuildMI(MBB, llvm::next(I), I->getDebugLoc(), TII->get(Mips::NOP)); MIBundleBuilder(MBB, I, llvm::next(llvm::next(I))); } return Changed; }
void ExpandPseudo::expandStoreACC(MachineBasicBlock &MBB, Iter I, unsigned MFHiOpc, unsigned MFLoOpc, unsigned RegSize) { // mflo $vr0, src // store $vr0, FI // mfhi $vr1, src // store $vr1, FI + 4 assert(I->getOperand(0).isReg() && I->getOperand(1).isFI()); const MipsSEInstrInfo &TII = *static_cast<const MipsSEInstrInfo*>(MF.getTarget().getInstrInfo()); const MipsRegisterInfo &RegInfo = *static_cast<const MipsRegisterInfo*>(MF.getTarget().getRegisterInfo()); const TargetRegisterClass *RC = RegInfo.intRegClass(RegSize); unsigned VR0 = MRI.createVirtualRegister(RC); unsigned VR1 = MRI.createVirtualRegister(RC); unsigned Src = I->getOperand(0).getReg(), FI = I->getOperand(1).getIndex(); unsigned SrcKill = getKillRegState(I->getOperand(0).isKill()); DebugLoc DL = I->getDebugLoc(); BuildMI(MBB, I, DL, TII.get(MFLoOpc), VR0).addReg(Src); TII.storeRegToStack(MBB, I, VR0, true, FI, RC, &RegInfo, 0); BuildMI(MBB, I, DL, TII.get(MFHiOpc), VR1).addReg(Src, SrcKill); TII.storeRegToStack(MBB, I, VR1, true, FI, RC, &RegInfo, RegSize); }
/// runOnMachineBasicBlock - Fill in delay slots for the given basic block. /// We assume there is only one delay slot per delayed instruction. bool Filler::runOnMachineBasicBlock(MachineBasicBlock &MBB) { bool Changed = false; for (Iter I = MBB.begin(); I != MBB.end(); ++I) { if (!I->hasDelaySlot()) continue; ++FilledSlots; Changed = true; Iter D; // Delay slot filling is disabled at -O0. if (!DisableDelaySlotFiller && (TM.getOptLevel() != CodeGenOpt::None) && findDelayInstr(MBB, I, D)) { MBB.splice(llvm::next(I), &MBB, D); ++UsefulSlots; } else BuildMI(MBB, llvm::next(I), I->getDebugLoc(), TII->get(Mips::NOP)); // Bundle the delay slot filler to the instruction with the delay slot. MIBundleBuilder(MBB, I, llvm::next(llvm::next(I))); } return Changed; }
void ExpandPseudo::expandStoreCCond(MachineBasicBlock &MBB, Iter I) { // copy $vr, ccond // store $vr, FI assert(I->getOperand(0).isReg() && I->getOperand(1).isFI()); const TargetRegisterClass *RC = RegInfo.intRegClass(4); unsigned VR = MRI.createVirtualRegister(RC); unsigned Src = I->getOperand(0).getReg(), FI = I->getOperand(1).getIndex(); BuildMI(MBB, I, I->getDebugLoc(), TII.get(TargetOpcode::COPY), VR) .addReg(Src, getKillRegState(I->getOperand(0).isKill())); TII.storeRegToStack(MBB, I, VR, true, FI, RC, &RegInfo, 0); }
void ExpandPseudo::expandLoadCCond(MachineBasicBlock &MBB, Iter I) { // load $vr, FI // copy ccond, $vr assert(I->getOperand(0).isReg() && I->getOperand(1).isFI()); const TargetRegisterClass *RC = RegInfo.intRegClass(4); unsigned VR = MRI.createVirtualRegister(RC); unsigned Dst = I->getOperand(0).getReg(), FI = I->getOperand(1).getIndex(); TII.loadRegFromStack(MBB, I, VR, FI, RC, &RegInfo, 0); BuildMI(MBB, I, I->getDebugLoc(), TII.get(TargetOpcode::COPY), Dst) .addReg(VR, RegState::Kill); }
bool MipsHazardSchedule::runOnMachineFunction(MachineFunction &MF) { const MipsSubtarget *STI = &static_cast<const MipsSubtarget &>(MF.getSubtarget()); // Forbidden slot hazards are only defined for MIPSR6. if (!STI->hasMips32r6() || STI->inMicroMipsMode()) return false; bool Changed = false; const MipsInstrInfo *TII = STI->getInstrInfo(); for (MachineFunction::iterator FI = MF.begin(); FI != MF.end(); ++FI) { for (Iter I = FI->begin(); I != FI->end(); ++I) { // Forbidden slot hazard handling. Use lookahead over state. if (!TII->HasForbiddenSlot(*I)) continue; bool InsertNop = false; // Next instruction in the basic block. if (std::next(I) != FI->end() && !TII->SafeInForbiddenSlot(*getNextMachineInstr(std::next(I)))) { InsertNop = true; } else { // Next instruction in the physical successor basic block. for (auto *Succ : FI->successors()) { if (FI->isLayoutSuccessor(Succ) && getNextMachineInstr(Succ->begin()) != Succ->end() && !TII->SafeInForbiddenSlot(*getNextMachineInstr(Succ->begin()))) { InsertNop = true; break; } } } if (InsertNop) { Changed = true; MIBundleBuilder(I) .append(BuildMI(MF, I->getDebugLoc(), TII->get(Mips::NOP))); NumInsertedNops++; } } } return Changed; }
bool MipsHazardSchedule::runOnMachineFunction(MachineFunction &MF) { const MipsSubtarget *STI = &static_cast<const MipsSubtarget &>(MF.getSubtarget()); // Forbidden slot hazards are only defined for MIPSR6 but not microMIPSR6. if (!STI->hasMips32r6() || STI->inMicroMipsMode()) return false; bool Changed = false; const MipsInstrInfo *TII = STI->getInstrInfo(); for (MachineFunction::iterator FI = MF.begin(); FI != MF.end(); ++FI) { for (Iter I = FI->begin(); I != FI->end(); ++I) { // Forbidden slot hazard handling. Use lookahead over state. if (!TII->HasForbiddenSlot(*I)) continue; Iter Inst; bool LastInstInFunction = std::next(I) == FI->end() && std::next(FI) == MF.end(); if (!LastInstInFunction) { if (std::next(I) != FI->end()) { // Start looking from the next instruction in the basic block. Inst = getNextMachineInstr(std::next(I)); } else { // Next instruction in the physical successor basic block. Inst = getNextMachineInstr(I); } } if (LastInstInFunction || !TII->SafeInForbiddenSlot(*Inst)) { Changed = true; MIBundleBuilder(&*I) .append(BuildMI(MF, I->getDebugLoc(), TII->get(Mips::NOP))); NumInsertedNops++; } } } return Changed; }
/// runOnMachineBasicBlock - Fill in delay slots for the given basic block. /// We assume there is only one delay slot per delayed instruction. bool Filler::runOnMachineBasicBlock(MachineBasicBlock &MBB) { bool Changed = false; const MipsSubtarget &STI = MBB.getParent()->getSubtarget<MipsSubtarget>(); bool InMicroMipsMode = STI.inMicroMipsMode(); const MipsInstrInfo *TII = STI.getInstrInfo(); for (Iter I = MBB.begin(); I != MBB.end(); ++I) { if (!hasUnoccupiedSlot(&*I)) continue; ++FilledSlots; Changed = true; // Delay slot filling is disabled at -O0. if (!DisableDelaySlotFiller && (TM.getOptLevel() != CodeGenOpt::None)) { bool Filled = false; if (searchBackward(MBB, I)) { Filled = true; } else if (I->isTerminator()) { if (searchSuccBBs(MBB, I)) { Filled = true; } } else if (searchForward(MBB, I)) { Filled = true; } if (Filled) { // Get instruction with delay slot. MachineBasicBlock::instr_iterator DSI(I); if (InMicroMipsMode && TII->GetInstSizeInBytes(std::next(DSI)) == 2 && DSI->isCall()) { // If instruction in delay slot is 16b change opcode to // corresponding instruction with short delay slot. DSI->setDesc(TII->get(getEquivalentCallShort(DSI->getOpcode()))); } continue; } } // If instruction is BEQ or BNE with one ZERO register, then instead of // adding NOP replace this instruction with the corresponding compact // branch instruction, i.e. BEQZC or BNEZC. unsigned Opcode = I->getOpcode(); if (InMicroMipsMode) { switch (Opcode) { case Mips::BEQ: case Mips::BNE: if (((unsigned) I->getOperand(1).getReg()) == Mips::ZERO) { I = replaceWithCompactBranch(MBB, I, I->getDebugLoc()); continue; } break; case Mips::JR: case Mips::PseudoReturn: case Mips::PseudoIndirectBranch: // For microMIPS the PseudoReturn and PseudoIndirectBranch are allways // expanded to JR_MM, so they can be replaced with JRC16_MM. I = replaceWithCompactJump(MBB, I, I->getDebugLoc()); continue; default: break; } } // Bundle the NOP to the instruction with the delay slot. BuildMI(MBB, std::next(I), I->getDebugLoc(), TII->get(Mips::NOP)); MIBundleBuilder(MBB, I, std::next(I, 2)); } return Changed; }
/// runOnMachineBasicBlock - Fill in delay slots for the given basic block. /// We assume there is only one delay slot per delayed instruction. bool Filler::runOnMachineBasicBlock(MachineBasicBlock &MBB) { bool Changed = false; const MipsSubtarget &STI = MBB.getParent()->getSubtarget<MipsSubtarget>(); bool InMicroMipsMode = STI.inMicroMipsMode(); const MipsInstrInfo *TII = STI.getInstrInfo(); if (InMicroMipsMode && STI.hasMips32r6()) { // This is microMIPS32r6 or microMIPS64r6 processor. Delay slot for // branching instructions is not needed. return Changed; } for (Iter I = MBB.begin(); I != MBB.end(); ++I) { if (!hasUnoccupiedSlot(&*I)) continue; ++FilledSlots; Changed = true; // Delay slot filling is disabled at -O0. if (!DisableDelaySlotFiller && (TM.getOptLevel() != CodeGenOpt::None)) { bool Filled = false; if (searchBackward(MBB, I)) { Filled = true; } else if (I->isTerminator()) { if (searchSuccBBs(MBB, I)) { Filled = true; } } else if (searchForward(MBB, I)) { Filled = true; } if (Filled) { // Get instruction with delay slot. MachineBasicBlock::instr_iterator DSI(I); if (InMicroMipsMode && TII->GetInstSizeInBytes(&*std::next(DSI)) == 2 && DSI->isCall()) { // If instruction in delay slot is 16b change opcode to // corresponding instruction with short delay slot. DSI->setDesc(TII->get(getEquivalentCallShort(DSI->getOpcode()))); } continue; } } // For microMIPS if instruction is BEQ or BNE with one ZERO register, then // instead of adding NOP replace this instruction with the corresponding // compact branch instruction, i.e. BEQZC or BNEZC. Additionally // PseudoReturn and PseudoIndirectBranch are expanded to JR_MM, so they can // be replaced with JRC16_MM. // For MIPSR6 attempt to produce the corresponding compact (no delay slot) // form of the CTI. For indirect jumps this will not require inserting a // NOP and for branches will hopefully avoid requiring a NOP. if ((InMicroMipsMode || STI.hasMips32r6()) && TII->getEquivalentCompactForm(I)) { I = replaceWithCompactBranch(MBB, I, I->getDebugLoc()); continue; } // Bundle the NOP to the instruction with the delay slot. BuildMI(MBB, std::next(I), I->getDebugLoc(), TII->get(Mips::NOP)); MIBundleBuilder(MBB, I, std::next(I, 2)); } return Changed; }