static bool combineRestoreADD(MachineBasicBlock::iterator RestoreMI, MachineBasicBlock::iterator AddMI, const TargetInstrInfo *TII) { // Before: add <op0>, <op1>, %i[0-7] // restore %g0, %g0, %i[0-7] // // After : restore <op0>, <op1>, %o[0-7] unsigned reg = AddMI->getOperand(0).getReg(); if (reg < SP::I0 || reg > SP::I7) return false; // Erase RESTORE. RestoreMI->eraseFromParent(); // Change ADD to RESTORE. AddMI->setDesc(TII->get((AddMI->getOpcode() == SP::ADDrr) ? SP::RESTORErr : SP::RESTOREri)); // Map the destination register. AddMI->getOperand(0).setReg(reg - SP::I0 + SP::O0); return true; }
// MI is a 128-bit load or store. Split it into two 64-bit loads or stores, // each having the opcode given by NewOpcode. void SystemZInstrInfo::splitMove(MachineBasicBlock::iterator MI, unsigned NewOpcode) const { MachineBasicBlock *MBB = MI->getParent(); MachineFunction &MF = *MBB->getParent(); // Get two load or store instructions. Use the original instruction for one // of them (arbitarily the second here) and create a clone for the other. MachineInstr *EarlierMI = MF.CloneMachineInstr(MI); MBB->insert(MI, EarlierMI); // Set up the two 64-bit registers. MachineOperand &HighRegOp = EarlierMI->getOperand(0); MachineOperand &LowRegOp = MI->getOperand(0); HighRegOp.setReg(RI.getSubReg(HighRegOp.getReg(), SystemZ::subreg_high)); LowRegOp.setReg(RI.getSubReg(LowRegOp.getReg(), SystemZ::subreg_low)); // The address in the first (high) instruction is already correct. // Adjust the offset in the second (low) instruction. MachineOperand &HighOffsetOp = EarlierMI->getOperand(2); MachineOperand &LowOffsetOp = MI->getOperand(2); LowOffsetOp.setImm(LowOffsetOp.getImm() + 8); // Set the opcodes. unsigned HighOpcode = getOpcodeForOffset(NewOpcode, HighOffsetOp.getImm()); unsigned LowOpcode = getOpcodeForOffset(NewOpcode, LowOffsetOp.getImm()); assert(HighOpcode && LowOpcode && "Both offsets should be in range"); EarlierMI->setDesc(get(HighOpcode)); MI->setDesc(get(LowOpcode)); }
MachineBasicBlock::iterator Filler::findDelayInstr(MachineBasicBlock &MBB, MachineBasicBlock::iterator slot) { SmallSet<unsigned, 32> RegDefs; SmallSet<unsigned, 32> RegUses; bool sawLoad = false; bool sawStore = false; if (slot == MBB.begin()) return MBB.end(); if (slot->getOpcode() == SP::RET || slot->getOpcode() == SP::TLS_CALL) return MBB.end(); if (slot->getOpcode() == SP::RETL) { MachineBasicBlock::iterator J = slot; --J; if (J->getOpcode() == SP::RESTORErr || J->getOpcode() == SP::RESTOREri) { // change retl to ret. slot->setDesc(TM.getInstrInfo()->get(SP::RET)); return J; } } // Call's delay filler can def some of call's uses. if (slot->isCall()) insertCallDefsUses(slot, RegDefs, RegUses); else insertDefsUses(slot, RegDefs, RegUses); bool done = false; MachineBasicBlock::iterator I = slot; while (!done) { done = (I == MBB.begin()); if (!done) --I; // skip debug value if (I->isDebugValue()) continue; if (I->hasUnmodeledSideEffects() || I->isInlineAsm() || I->isPosition() || I->hasDelaySlot() || I->isBundledWithSucc()) break; if (delayHasHazard(I, sawLoad, sawStore, RegDefs, RegUses)) { insertDefsUses(I, RegDefs, RegUses); continue; } return I; } return MBB.end(); }
MachineBasicBlock::iterator Filler::findDelayInstr(MachineBasicBlock &MBB, MachineBasicBlock::iterator slot) { SmallSet<unsigned, 32> RegDefs; SmallSet<unsigned, 32> RegUses; bool sawLoad = false; bool sawStore = false; MachineBasicBlock::iterator I = slot; if (slot->getOpcode() == SP::RET) return MBB.end(); if (slot->getOpcode() == SP::RETL) { --I; if (I->getOpcode() != SP::RESTORErr) return MBB.end(); //change retl to ret slot->setDesc(TII->get(SP::RET)); return I; } //Call's delay filler can def some of call's uses. if (slot->isCall()) insertCallUses(slot, RegUses); else insertDefsUses(slot, RegDefs, RegUses); bool done = false; while (!done) { done = (I == MBB.begin()); if (!done) --I; // skip debug value if (I->isDebugValue()) continue; if (I->hasUnmodeledSideEffects() || I->isInlineAsm() || I->isLabel() || I->hasDelaySlot() || isDelayFiller(MBB, I)) break; if (delayHasHazard(I, sawLoad, sawStore, RegDefs, RegUses)) { insertDefsUses(I, RegDefs, RegUses); continue; } return I; } return MBB.end(); }
/// Replace pseudo store instructions that pass arguments through the stack with /// real instructions. If insertPushes is true then all instructions are /// replaced with push instructions, otherwise regular std instructions are /// inserted. static void fixStackStores(MachineBasicBlock &MBB, MachineBasicBlock::iterator MI, const TargetInstrInfo &TII, bool insertPushes) { const AVRSubtarget &STI = MBB.getParent()->getSubtarget<AVRSubtarget>(); const TargetRegisterInfo &TRI = *STI.getRegisterInfo(); // Iterate through the BB until we hit a call instruction or we reach the end. for (auto I = MI, E = MBB.end(); I != E && !I->isCall();) { MachineBasicBlock::iterator NextMI = std::next(I); MachineInstr &MI = *I; unsigned Opcode = I->getOpcode(); // Only care of pseudo store instructions where SP is the base pointer. if (Opcode != AVR::STDSPQRr && Opcode != AVR::STDWSPQRr) { I = NextMI; continue; } assert(MI.getOperand(0).getReg() == AVR::SP && "Invalid register, should be SP!"); if (insertPushes) { // Replace this instruction with a push. unsigned SrcReg = MI.getOperand(2).getReg(); bool SrcIsKill = MI.getOperand(2).isKill(); // We can't use PUSHWRr here because when expanded the order of the new // instructions are reversed from what we need. Perform the expansion now. if (Opcode == AVR::STDWSPQRr) { BuildMI(MBB, I, MI.getDebugLoc(), TII.get(AVR::PUSHRr)) .addReg(TRI.getSubReg(SrcReg, AVR::sub_hi), getKillRegState(SrcIsKill)); BuildMI(MBB, I, MI.getDebugLoc(), TII.get(AVR::PUSHRr)) .addReg(TRI.getSubReg(SrcReg, AVR::sub_lo), getKillRegState(SrcIsKill)); } else { BuildMI(MBB, I, MI.getDebugLoc(), TII.get(AVR::PUSHRr)) .addReg(SrcReg, getKillRegState(SrcIsKill)); } MI.eraseFromParent(); I = NextMI; continue; } // Replace this instruction with a regular store. Use Y as the base // pointer since it is guaranteed to contain a copy of SP. unsigned STOpc = (Opcode == AVR::STDWSPQRr) ? AVR::STDWPtrQRr : AVR::STDPtrQRr; MI.setDesc(TII.get(STOpc)); MI.getOperand(0).setReg(AVR::R29R28); I = NextMI; } }
// Split ADJDYNALLOC instruction MI. void SystemZInstrInfo::splitAdjDynAlloc(MachineBasicBlock::iterator MI) const { MachineBasicBlock *MBB = MI->getParent(); MachineFunction &MF = *MBB->getParent(); MachineFrameInfo *MFFrame = MF.getFrameInfo(); MachineOperand &OffsetMO = MI->getOperand(2); uint64_t Offset = (MFFrame->getMaxCallFrameSize() + SystemZMC::CallFrameSize + OffsetMO.getImm()); unsigned NewOpcode = getOpcodeForOffset(SystemZ::LA, Offset); assert(NewOpcode && "No support for huge argument lists yet"); MI->setDesc(get(NewOpcode)); OffsetMO.setImm(Offset); }
void SystemZFrameLowering::emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const { MachineBasicBlock::iterator MBBI = MBB.getLastNonDebugInstr(); const SystemZInstrInfo *ZII = static_cast<const SystemZInstrInfo*>(MF.getTarget().getInstrInfo()); SystemZMachineFunctionInfo *ZFI = MF.getInfo<SystemZMachineFunctionInfo>(); // Skip the return instruction. assert(MBBI->getOpcode() == SystemZ::RET && "Can only insert epilogue into returning blocks"); uint64_t StackSize = getAllocatedStackSize(MF); if (ZFI->getLowSavedGPR()) { --MBBI; unsigned Opcode = MBBI->getOpcode(); if (Opcode != SystemZ::LMG) llvm_unreachable("Expected to see callee-save register restore code"); unsigned AddrOpNo = 2; DebugLoc DL = MBBI->getDebugLoc(); uint64_t Offset = StackSize + MBBI->getOperand(AddrOpNo + 1).getImm(); unsigned NewOpcode = ZII->getOpcodeForOffset(Opcode, Offset); // If the offset is too large, use the largest stack-aligned offset // and add the rest to the base register (the stack or frame pointer). if (!NewOpcode) { uint64_t NumBytes = Offset - 0x7fff8; emitIncrement(MBB, MBBI, DL, MBBI->getOperand(AddrOpNo).getReg(), NumBytes, ZII); Offset -= NumBytes; NewOpcode = ZII->getOpcodeForOffset(Opcode, Offset); assert(NewOpcode && "No restore instruction available"); } MBBI->setDesc(ZII->get(NewOpcode)); MBBI->getOperand(AddrOpNo + 1).ChangeToImmediate(Offset); } else if (StackSize) { DebugLoc DL = MBBI->getDebugLoc(); emitIncrement(MBB, MBBI, DL, SystemZ::R15D, StackSize, ZII); } }
static bool combineRestoreSETHIi(MachineBasicBlock::iterator RestoreMI, MachineBasicBlock::iterator SetHiMI, const TargetInstrInfo *TII) { // Before: sethi imm3, %i[0-7] // restore %g0, %g0, %g0 // // After : restore %g0, (imm3<<10), %o[0-7] unsigned reg = SetHiMI->getOperand(0).getReg(); if (reg < SP::I0 || reg > SP::I7) return false; if (!SetHiMI->getOperand(1).isImm()) return false; int64_t imm = SetHiMI->getOperand(1).getImm(); // Is it a 3 bit immediate? if (!isInt<3>(imm)) return false; // Make it a 13 bit immediate. imm = (imm << 10) & 0x1FFF; assert(RestoreMI->getOpcode() == SP::RESTORErr); RestoreMI->setDesc(TII->get(SP::RESTOREri)); RestoreMI->getOperand(0).setReg(reg - SP::I0 + SP::O0); RestoreMI->getOperand(1).setReg(SP::G0); RestoreMI->getOperand(2).ChangeToImmediate(imm); // Erase the original SETHI. SetHiMI->eraseFromParent(); return true; }
static bool combineRestoreOR(MachineBasicBlock::iterator RestoreMI, MachineBasicBlock::iterator OrMI, const TargetInstrInfo *TII) { // Before: or <op0>, <op1>, %i[0-7] // restore %g0, %g0, %i[0-7] // and <op0> or <op1> is zero, // // After : restore <op0>, <op1>, %o[0-7] unsigned reg = OrMI->getOperand(0).getReg(); if (reg < SP::I0 || reg > SP::I7) return false; // check whether it is a copy. if (OrMI->getOpcode() == SP::ORrr && OrMI->getOperand(1).getReg() != SP::G0 && OrMI->getOperand(2).getReg() != SP::G0) return false; if (OrMI->getOpcode() == SP::ORri && OrMI->getOperand(1).getReg() != SP::G0 && (!OrMI->getOperand(2).isImm() || OrMI->getOperand(2).getImm() != 0)) return false; // Erase RESTORE. RestoreMI->eraseFromParent(); // Change OR to RESTORE. OrMI->setDesc(TII->get((OrMI->getOpcode() == SP::ORrr) ? SP::RESTORErr : SP::RESTOREri)); // Map the destination register. OrMI->getOperand(0).setReg(reg - SP::I0 + SP::O0); return true; }
bool AlphaBSel::runOnMachineFunction(MachineFunction &Fn) { for (MachineFunction::iterator MFI = Fn.begin(), E = Fn.end(); MFI != E; ++MFI) { MachineBasicBlock *MBB = MFI; for (MachineBasicBlock::iterator MBBI = MBB->begin(), EE = MBB->end(); MBBI != EE; ++MBBI) { if (MBBI->getOpcode() == Alpha::COND_BRANCH_I || MBBI->getOpcode() == Alpha::COND_BRANCH_F) { // condbranch operands: // 0. bc opcode // 1. reg // 2. target MBB const TargetInstrInfo *TII = Fn.getTarget().getInstrInfo(); MBBI->setDesc(TII->get(MBBI->getOperand(0).getImm())); } } } return true; }
bool runOnMachineFunction(MachineFunction &MF) override { ST = &MF.getSubtarget<R600Subtarget>(); MaxFetchInst = ST->getTexVTXClauseSize(); TII = ST->getInstrInfo(); TRI = ST->getRegisterInfo(); R600MachineFunctionInfo *MFI = MF.getInfo<R600MachineFunctionInfo>(); CFStack CFStack(ST, MF.getFunction().getCallingConv()); for (MachineFunction::iterator MB = MF.begin(), ME = MF.end(); MB != ME; ++MB) { MachineBasicBlock &MBB = *MB; unsigned CfCount = 0; std::vector<std::pair<unsigned, std::set<MachineInstr *>>> LoopStack; std::vector<MachineInstr * > IfThenElseStack; if (MF.getFunction().getCallingConv() == CallingConv::AMDGPU_VS) { BuildMI(MBB, MBB.begin(), MBB.findDebugLoc(MBB.begin()), getHWInstrDesc(CF_CALL_FS)); CfCount++; } std::vector<ClauseFile> FetchClauses, AluClauses; std::vector<MachineInstr *> LastAlu(1); std::vector<MachineInstr *> ToPopAfter; for (MachineBasicBlock::iterator I = MBB.begin(), E = MBB.end(); I != E;) { if (TII->usesTextureCache(*I) || TII->usesVertexCache(*I)) { LLVM_DEBUG(dbgs() << CfCount << ":"; I->dump();); FetchClauses.push_back(MakeFetchClause(MBB, I)); CfCount++; LastAlu.back() = nullptr; continue; } MachineBasicBlock::iterator MI = I; if (MI->getOpcode() != R600::ENDIF) LastAlu.back() = nullptr; if (MI->getOpcode() == R600::CF_ALU) LastAlu.back() = &*MI; I++; bool RequiresWorkAround = CFStack.requiresWorkAroundForInst(MI->getOpcode()); switch (MI->getOpcode()) { case R600::CF_ALU_PUSH_BEFORE: if (RequiresWorkAround) { LLVM_DEBUG(dbgs() << "Applying bug work-around for ALU_PUSH_BEFORE\n"); BuildMI(MBB, MI, MBB.findDebugLoc(MI), TII->get(R600::CF_PUSH_EG)) .addImm(CfCount + 1) .addImm(1); MI->setDesc(TII->get(R600::CF_ALU)); CfCount++; CFStack.pushBranch(R600::CF_PUSH_EG); } else CFStack.pushBranch(R600::CF_ALU_PUSH_BEFORE); LLVM_FALLTHROUGH; case R600::CF_ALU: I = MI; AluClauses.push_back(MakeALUClause(MBB, I)); LLVM_DEBUG(dbgs() << CfCount << ":"; MI->dump();); CfCount++; break; case R600::WHILELOOP: { CFStack.pushLoop(); MachineInstr *MIb = BuildMI(MBB, MI, MBB.findDebugLoc(MI), getHWInstrDesc(CF_WHILE_LOOP)) .addImm(1); std::pair<unsigned, std::set<MachineInstr *>> Pair(CfCount, std::set<MachineInstr *>()); Pair.second.insert(MIb); LoopStack.push_back(std::move(Pair)); MI->eraseFromParent(); CfCount++; break; } case R600::ENDLOOP: { CFStack.popLoop(); std::pair<unsigned, std::set<MachineInstr *>> Pair = std::move(LoopStack.back()); LoopStack.pop_back(); CounterPropagateAddr(Pair.second, CfCount); BuildMI(MBB, MI, MBB.findDebugLoc(MI), getHWInstrDesc(CF_END_LOOP)) .addImm(Pair.first + 1); MI->eraseFromParent(); CfCount++; break; } case R600::IF_PREDICATE_SET: { LastAlu.push_back(nullptr); MachineInstr *MIb = BuildMI(MBB, MI, MBB.findDebugLoc(MI), getHWInstrDesc(CF_JUMP)) .addImm(0) .addImm(0); IfThenElseStack.push_back(MIb); LLVM_DEBUG(dbgs() << CfCount << ":"; MIb->dump();); MI->eraseFromParent(); CfCount++; break; }
virtual bool runOnMachineFunction(MachineFunction &MF) { TII=static_cast<const R600InstrInfo *>(MF.getTarget().getInstrInfo()); TRI=static_cast<const R600RegisterInfo *>(MF.getTarget().getRegisterInfo()); unsigned MaxStack = 0; unsigned CurrentStack = 0; unsigned CurrentLoopDepth = 0; bool HasPush = false; for (MachineFunction::iterator MB = MF.begin(), ME = MF.end(); MB != ME; ++MB) { MachineBasicBlock &MBB = *MB; unsigned CfCount = 0; std::vector<std::pair<unsigned, std::set<MachineInstr *> > > LoopStack; std::vector<MachineInstr * > IfThenElseStack; R600MachineFunctionInfo *MFI = MF.getInfo<R600MachineFunctionInfo>(); if (MFI->ShaderType == 1) { BuildMI(MBB, MBB.begin(), MBB.findDebugLoc(MBB.begin()), getHWInstrDesc(CF_CALL_FS)); CfCount++; MaxStack = 1; } std::vector<ClauseFile> FetchClauses, AluClauses; std::vector<MachineInstr *> LastAlu(1); std::vector<MachineInstr *> ToPopAfter; for (MachineBasicBlock::iterator I = MBB.begin(), E = MBB.end(); I != E;) { if (TII->usesTextureCache(I) || TII->usesVertexCache(I)) { DEBUG(dbgs() << CfCount << ":"; I->dump();); FetchClauses.push_back(MakeFetchClause(MBB, I)); CfCount++; continue; } MachineBasicBlock::iterator MI = I; if (MI->getOpcode() != AMDGPU::ENDIF) LastAlu.back() = 0; if (MI->getOpcode() == AMDGPU::CF_ALU) LastAlu.back() = MI; I++; switch (MI->getOpcode()) { case AMDGPU::CF_ALU_PUSH_BEFORE: CurrentStack++; MaxStack = std::max(MaxStack, CurrentStack); HasPush = true; if (ST.hasCaymanISA() && CurrentLoopDepth > 1) { BuildMI(MBB, MI, MBB.findDebugLoc(MI), TII->get(AMDGPU::CF_PUSH_CM)) .addImm(CfCount + 1) .addImm(1); MI->setDesc(TII->get(AMDGPU::CF_ALU)); CfCount++; } case AMDGPU::CF_ALU: I = MI; AluClauses.push_back(MakeALUClause(MBB, I)); DEBUG(dbgs() << CfCount << ":"; MI->dump();); CfCount++; break; case AMDGPU::WHILELOOP: { CurrentStack+=4; CurrentLoopDepth++; MaxStack = std::max(MaxStack, CurrentStack); MachineInstr *MIb = BuildMI(MBB, MI, MBB.findDebugLoc(MI), getHWInstrDesc(CF_WHILE_LOOP)) .addImm(1); std::pair<unsigned, std::set<MachineInstr *> > Pair(CfCount, std::set<MachineInstr *>()); Pair.second.insert(MIb); LoopStack.push_back(Pair); MI->eraseFromParent(); CfCount++; break; } case AMDGPU::ENDLOOP: { CurrentStack-=4; CurrentLoopDepth--; std::pair<unsigned, std::set<MachineInstr *> > Pair = LoopStack.back(); LoopStack.pop_back(); CounterPropagateAddr(Pair.second, CfCount); BuildMI(MBB, MI, MBB.findDebugLoc(MI), getHWInstrDesc(CF_END_LOOP)) .addImm(Pair.first + 1); MI->eraseFromParent(); CfCount++; break; } case AMDGPU::IF_PREDICATE_SET: { LastAlu.push_back(0); MachineInstr *MIb = BuildMI(MBB, MI, MBB.findDebugLoc(MI), getHWInstrDesc(CF_JUMP)) .addImm(0) .addImm(0); IfThenElseStack.push_back(MIb); DEBUG(dbgs() << CfCount << ":"; MIb->dump();); MI->eraseFromParent(); CfCount++; break; }
void SystemZRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator MI, int SPAdj, unsigned FIOperandNum, RegScavenger *RS) const { assert(SPAdj == 0 && "Outgoing arguments should be part of the frame"); MachineBasicBlock &MBB = *MI->getParent(); MachineFunction &MF = *MBB.getParent(); auto *TII = static_cast<const SystemZInstrInfo *>(MF.getSubtarget().getInstrInfo()); const SystemZFrameLowering *TFI = getFrameLowering(MF); DebugLoc DL = MI->getDebugLoc(); // Decompose the frame index into a base and offset. int FrameIndex = MI->getOperand(FIOperandNum).getIndex(); unsigned BasePtr = getFrameRegister(MF); int64_t Offset = (TFI->getFrameIndexOffset(MF, FrameIndex) + MI->getOperand(FIOperandNum + 1).getImm()); // Special handling of dbg_value instructions. if (MI->isDebugValue()) { MI->getOperand(FIOperandNum).ChangeToRegister(BasePtr, /*isDef*/ false); MI->getOperand(FIOperandNum + 1).ChangeToImmediate(Offset); return; } // See if the offset is in range, or if an equivalent instruction that // accepts the offset exists. unsigned Opcode = MI->getOpcode(); unsigned OpcodeForOffset = TII->getOpcodeForOffset(Opcode, Offset); if (OpcodeForOffset) MI->getOperand(FIOperandNum).ChangeToRegister(BasePtr, false); else { // Create an anchor point that is in range. Start at 0xffff so that // can use LLILH to load the immediate. int64_t OldOffset = Offset; int64_t Mask = 0xffff; do { Offset = OldOffset & Mask; OpcodeForOffset = TII->getOpcodeForOffset(Opcode, Offset); Mask >>= 1; assert(Mask && "One offset must be OK"); } while (!OpcodeForOffset); unsigned ScratchReg = MF.getRegInfo().createVirtualRegister(&SystemZ::ADDR64BitRegClass); int64_t HighOffset = OldOffset - Offset; if (MI->getDesc().TSFlags & SystemZII::HasIndex && MI->getOperand(FIOperandNum + 2).getReg() == 0) { // Load the offset into the scratch register and use it as an index. // The scratch register then dies here. TII->loadImmediate(MBB, MI, ScratchReg, HighOffset); MI->getOperand(FIOperandNum).ChangeToRegister(BasePtr, false); MI->getOperand(FIOperandNum + 2).ChangeToRegister(ScratchReg, false, false, true); } else { // Load the anchor address into a scratch register. unsigned LAOpcode = TII->getOpcodeForOffset(SystemZ::LA, HighOffset); if (LAOpcode) BuildMI(MBB, MI, DL, TII->get(LAOpcode),ScratchReg) .addReg(BasePtr).addImm(HighOffset).addReg(0); else { // Load the high offset into the scratch register and use it as // an index. TII->loadImmediate(MBB, MI, ScratchReg, HighOffset); BuildMI(MBB, MI, DL, TII->get(SystemZ::AGR),ScratchReg) .addReg(ScratchReg, RegState::Kill).addReg(BasePtr); } // Use the scratch register as the base. It then dies here. MI->getOperand(FIOperandNum).ChangeToRegister(ScratchReg, false, false, true); } } MI->setDesc(TII->get(OpcodeForOffset)); MI->getOperand(FIOperandNum + 1).ChangeToImmediate(Offset); }