| //===-- M68kInstrInfo.cpp - M68k Instruction Information --------*- 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 | |
| // | |
| //===----------------------------------------------------------------------===// | |
| /// | |
| /// \file | |
| /// This file contains the M68k declaration of the TargetInstrInfo class. | |
| /// | |
| //===----------------------------------------------------------------------===// | |
| #include "M68kInstrInfo.h" | |
| #include "M68kInstrBuilder.h" | |
| #include "M68kMachineFunction.h" | |
| #include "M68kTargetMachine.h" | |
| #include "MCTargetDesc/M68kMCCodeEmitter.h" | |
| #include "llvm/ADT/STLExtras.h" | |
| #include "llvm/ADT/ScopeExit.h" | |
| #include "llvm/CodeGen/LivePhysRegs.h" | |
| #include "llvm/CodeGen/LiveVariables.h" | |
| #include "llvm/CodeGen/MachineInstrBuilder.h" | |
| #include "llvm/CodeGen/MachineRegisterInfo.h" | |
| #include "llvm/MC/TargetRegistry.h" | |
| #include "llvm/Support/ErrorHandling.h" | |
| #include "llvm/Support/Regex.h" | |
| #include <functional> | |
| using namespace llvm; | |
| #define DEBUG_TYPE "M68k-instr-info" | |
| #define GET_INSTRINFO_CTOR_DTOR | |
| #include "M68kGenInstrInfo.inc" | |
| // Pin the vtable to this file. | |
| void M68kInstrInfo::anchor() {} | |
| M68kInstrInfo::M68kInstrInfo(const M68kSubtarget &STI) | |
| : M68kGenInstrInfo(M68k::ADJCALLSTACKDOWN, M68k::ADJCALLSTACKUP, 0, | |
| M68k::RET), | |
| Subtarget(STI), RI(STI) {} | |
| static M68k::CondCode getCondFromBranchOpc(unsigned BrOpc) { | |
| switch (BrOpc) { | |
| default: | |
| return M68k::COND_INVALID; | |
| case M68k::Beq8: | |
| return M68k::COND_EQ; | |
| case M68k::Bne8: | |
| return M68k::COND_NE; | |
| case M68k::Blt8: | |
| return M68k::COND_LT; | |
| case M68k::Ble8: | |
| return M68k::COND_LE; | |
| case M68k::Bgt8: | |
| return M68k::COND_GT; | |
| case M68k::Bge8: | |
| return M68k::COND_GE; | |
| case M68k::Bcs8: | |
| return M68k::COND_CS; | |
| case M68k::Bls8: | |
| return M68k::COND_LS; | |
| case M68k::Bhi8: | |
| return M68k::COND_HI; | |
| case M68k::Bcc8: | |
| return M68k::COND_CC; | |
| case M68k::Bmi8: | |
| return M68k::COND_MI; | |
| case M68k::Bpl8: | |
| return M68k::COND_PL; | |
| case M68k::Bvs8: | |
| return M68k::COND_VS; | |
| case M68k::Bvc8: | |
| return M68k::COND_VC; | |
| } | |
| } | |
| bool M68kInstrInfo::AnalyzeBranchImpl(MachineBasicBlock &MBB, | |
| MachineBasicBlock *&TBB, | |
| MachineBasicBlock *&FBB, | |
| SmallVectorImpl<MachineOperand> &Cond, | |
| bool AllowModify) const { | |
| auto UncondBranch = | |
| std::pair<MachineBasicBlock::reverse_iterator, MachineBasicBlock *>{ | |
| MBB.rend(), nullptr}; | |
| // Erase any instructions if allowed at the end of the scope. | |
| std::vector<std::reference_wrapper<llvm::MachineInstr>> EraseList; | |
| auto FinalizeOnReturn = llvm::make_scope_exit([&EraseList] { | |
| std::for_each(EraseList.begin(), EraseList.end(), | |
| [](auto &ref) { ref.get().eraseFromParent(); }); | |
| }); | |
| // Start from the bottom of the block and work up, examining the | |
| // terminator instructions. | |
| for (auto iter = MBB.rbegin(); iter != MBB.rend(); iter = std::next(iter)) { | |
| unsigned Opcode = iter->getOpcode(); | |
| if (iter->isDebugInstr()) | |
| continue; | |
| // Working from the bottom, when we see a non-terminator instruction, we're | |
| // done. | |
| if (!isUnpredicatedTerminator(*iter)) | |
| break; | |
| // A terminator that isn't a branch can't easily be handled by this | |
| // analysis. | |
| if (!iter->isBranch()) | |
| return true; | |
| // Handle unconditional branches. | |
| if (Opcode == M68k::BRA8 || Opcode == M68k::BRA16) { | |
| if (!iter->getOperand(0).isMBB()) | |
| return true; | |
| UncondBranch = {iter, iter->getOperand(0).getMBB()}; | |
| // TBB is used to indicate the unconditional destination. | |
| TBB = UncondBranch.second; | |
| if (!AllowModify) | |
| continue; | |
| // If the block has any instructions after a JMP, erase them. | |
| EraseList.insert(EraseList.begin(), MBB.rbegin(), iter); | |
| Cond.clear(); | |
| FBB = nullptr; | |
| // Erase the JMP if it's equivalent to a fall-through. | |
| if (MBB.isLayoutSuccessor(UncondBranch.second)) { | |
| TBB = nullptr; | |
| EraseList.push_back(*iter); | |
| UncondBranch = {MBB.rend(), nullptr}; | |
| } | |
| continue; | |
| } | |
| // Handle conditional branches. | |
| auto BranchCode = M68k::GetCondFromBranchOpc(Opcode); | |
| // Can't handle indirect branch. | |
| if (BranchCode == M68k::COND_INVALID) | |
| return true; | |
| // In practice we should never have an undef CCR operand, if we do | |
| // abort here as we are not prepared to preserve the flag. | |
| // ??? Is this required? | |
| // if (iter->getOperand(1).isUndef()) | |
| // return true; | |
| // Working from the bottom, handle the first conditional branch. | |
| if (Cond.empty()) { | |
| if (!iter->getOperand(0).isMBB()) | |
| return true; | |
| MachineBasicBlock *CondBranchTarget = iter->getOperand(0).getMBB(); | |
| // If we see something like this: | |
| // | |
| // bcc l1 | |
| // bra l2 | |
| // ... | |
| // l1: | |
| // ... | |
| // l2: | |
| if (UncondBranch.first != MBB.rend()) { | |
| assert(std::next(UncondBranch.first) == iter && "Wrong block layout."); | |
| // And we are allowed to modify the block and the target block of the | |
| // conditional branch is the direct successor of this block: | |
| // | |
| // bcc l1 | |
| // bra l2 | |
| // l1: | |
| // ... | |
| // l2: | |
| // | |
| // we change it to this if allowed: | |
| // | |
| // bncc l2 | |
| // l1: | |
| // ... | |
| // l2: | |
| // | |
| // Which is a bit more efficient. | |
| if (AllowModify && MBB.isLayoutSuccessor(CondBranchTarget)) { | |
| BranchCode = GetOppositeBranchCondition(BranchCode); | |
| unsigned BNCC = GetCondBranchFromCond(BranchCode); | |
| BuildMI(MBB, *UncondBranch.first, MBB.rfindDebugLoc(iter), get(BNCC)) | |
| .addMBB(UncondBranch.second); | |
| EraseList.push_back(*iter); | |
| EraseList.push_back(*UncondBranch.first); | |
| TBB = UncondBranch.second; | |
| FBB = nullptr; | |
| Cond.push_back(MachineOperand::CreateImm(BranchCode)); | |
| // Otherwise preserve TBB, FBB and Cond as requested | |
| } else { | |
| TBB = CondBranchTarget; | |
| FBB = UncondBranch.second; | |
| Cond.push_back(MachineOperand::CreateImm(BranchCode)); | |
| } | |
| UncondBranch = {MBB.rend(), nullptr}; | |
| continue; | |
| } | |
| TBB = CondBranchTarget; | |
| FBB = nullptr; | |
| Cond.push_back(MachineOperand::CreateImm(BranchCode)); | |
| continue; | |
| } | |
| // Handle subsequent conditional branches. Only handle the case where all | |
| // conditional branches branch to the same destination and their condition | |
| // opcodes fit one of the special multi-branch idioms. | |
| assert(Cond.size() == 1); | |
| assert(TBB); | |
| // If the conditions are the same, we can leave them alone. | |
| auto OldBranchCode = static_cast<M68k::CondCode>(Cond[0].getImm()); | |
| if (!iter->getOperand(0).isMBB()) | |
| return true; | |
| auto NewTBB = iter->getOperand(0).getMBB(); | |
| if (OldBranchCode == BranchCode && TBB == NewTBB) | |
| continue; | |
| // If they differ we cannot do much here. | |
| return true; | |
| } | |
| return false; | |
| } | |
| bool M68kInstrInfo::analyzeBranch(MachineBasicBlock &MBB, | |
| MachineBasicBlock *&TBB, | |
| MachineBasicBlock *&FBB, | |
| SmallVectorImpl<MachineOperand> &Cond, | |
| bool AllowModify) const { | |
| return AnalyzeBranchImpl(MBB, TBB, FBB, Cond, AllowModify); | |
| } | |
| unsigned M68kInstrInfo::removeBranch(MachineBasicBlock &MBB, | |
| int *BytesRemoved) const { | |
| assert(!BytesRemoved && "code size not handled"); | |
| MachineBasicBlock::iterator I = MBB.end(); | |
| unsigned Count = 0; | |
| while (I != MBB.begin()) { | |
| --I; | |
| if (I->isDebugValue()) | |
| continue; | |
| if (I->getOpcode() != M68k::BRA8 && | |
| getCondFromBranchOpc(I->getOpcode()) == M68k::COND_INVALID) | |
| break; | |
| // Remove the branch. | |
| I->eraseFromParent(); | |
| I = MBB.end(); | |
| ++Count; | |
| } | |
| return Count; | |
| } | |
| unsigned M68kInstrInfo::insertBranch( | |
| MachineBasicBlock &MBB, MachineBasicBlock *TBB, MachineBasicBlock *FBB, | |
| ArrayRef<MachineOperand> Cond, const DebugLoc &DL, int *BytesAdded) const { | |
| // Shouldn't be a fall through. | |
| assert(TBB && "InsertBranch must not be told to insert a fallthrough"); | |
| assert((Cond.size() == 1 || Cond.size() == 0) && | |
| "M68k branch conditions have one component!"); | |
| assert(!BytesAdded && "code size not handled"); | |
| if (Cond.empty()) { | |
| // Unconditional branch? | |
| assert(!FBB && "Unconditional branch with multiple successors!"); | |
| BuildMI(&MBB, DL, get(M68k::BRA8)).addMBB(TBB); | |
| return 1; | |
| } | |
| // If FBB is null, it is implied to be a fall-through block. | |
| bool FallThru = FBB == nullptr; | |
| // Conditional branch. | |
| unsigned Count = 0; | |
| M68k::CondCode CC = (M68k::CondCode)Cond[0].getImm(); | |
| unsigned Opc = GetCondBranchFromCond(CC); | |
| BuildMI(&MBB, DL, get(Opc)).addMBB(TBB); | |
| ++Count; | |
| if (!FallThru) { | |
| // Two-way Conditional branch. Insert the second branch. | |
| BuildMI(&MBB, DL, get(M68k::BRA8)).addMBB(FBB); | |
| ++Count; | |
| } | |
| return Count; | |
| } | |
| void M68kInstrInfo::AddSExt(MachineBasicBlock &MBB, | |
| MachineBasicBlock::iterator I, DebugLoc DL, | |
| unsigned Reg, MVT From, MVT To) const { | |
| if (From == MVT::i8) { | |
| unsigned R = Reg; | |
| // EXT16 requires i16 register | |
| if (To == MVT::i32) { | |
| R = RI.getSubReg(Reg, M68k::MxSubRegIndex16Lo); | |
| assert(R && "No viable SUB register available"); | |
| } | |
| BuildMI(MBB, I, DL, get(M68k::EXT16), R).addReg(R); | |
| } | |
| if (To == MVT::i32) | |
| BuildMI(MBB, I, DL, get(M68k::EXT32), Reg).addReg(Reg); | |
| } | |
| void M68kInstrInfo::AddZExt(MachineBasicBlock &MBB, | |
| MachineBasicBlock::iterator I, DebugLoc DL, | |
| unsigned Reg, MVT From, MVT To) const { | |
| unsigned Mask, And; | |
| if (From == MVT::i8) | |
| Mask = 0xFF; | |
| else | |
| Mask = 0xFFFF; | |
| if (To == MVT::i16) | |
| And = M68k::AND16di; | |
| else // i32 | |
| And = M68k::AND32di; | |
| // TODO use xor r,r to decrease size | |
| BuildMI(MBB, I, DL, get(And), Reg).addReg(Reg).addImm(Mask); | |
| } | |
| bool M68kInstrInfo::ExpandMOVX_RR(MachineInstrBuilder &MIB, MVT MVTDst, | |
| MVT MVTSrc) const { | |
| unsigned Move = MVTDst == MVT::i16 ? M68k::MOV16rr : M68k::MOV32rr; | |
| Register Dst = MIB->getOperand(0).getReg(); | |
| Register Src = MIB->getOperand(1).getReg(); | |
| assert(Dst != Src && "You cannot use the same Regs with MOVX_RR"); | |
| const auto &TRI = getRegisterInfo(); | |
| const auto *RCDst = TRI.getMaximalPhysRegClass(Dst, MVTDst); | |
| const auto *RCSrc = TRI.getMaximalPhysRegClass(Src, MVTSrc); | |
| assert(RCDst && RCSrc && "Wrong use of MOVX_RR"); | |
| assert(RCDst != RCSrc && "You cannot use the same Reg Classes with MOVX_RR"); | |
| // We need to find the super source register that matches the size of Dst | |
| unsigned SSrc = RI.getMatchingMegaReg(Src, RCDst); | |
| assert(SSrc && "No viable MEGA register available"); | |
| DebugLoc DL = MIB->getDebugLoc(); | |
| // If it happens to that super source register is the destination register | |
| // we do nothing | |
| if (Dst == SSrc) { | |
| LLVM_DEBUG(dbgs() << "Remove " << *MIB.getInstr() << '\n'); | |
| MIB->eraseFromParent(); | |
| } else { // otherwise we need to MOV | |
| LLVM_DEBUG(dbgs() << "Expand " << *MIB.getInstr() << " to MOV\n"); | |
| MIB->setDesc(get(Move)); | |
| MIB->getOperand(1).setReg(SSrc); | |
| } | |
| return true; | |
| } | |
| /// Expand SExt MOVE pseudos into a MOV and a EXT if the operands are two | |
| /// different registers or just EXT if it is the same register | |
| bool M68kInstrInfo::ExpandMOVSZX_RR(MachineInstrBuilder &MIB, bool IsSigned, | |
| MVT MVTDst, MVT MVTSrc) const { | |
| LLVM_DEBUG(dbgs() << "Expand " << *MIB.getInstr() << " to "); | |
| unsigned Move; | |
| if (MVTDst == MVT::i16) | |
| Move = M68k::MOV16rr; | |
| else // i32 | |
| Move = M68k::MOV32rr; | |
| Register Dst = MIB->getOperand(0).getReg(); | |
| Register Src = MIB->getOperand(1).getReg(); | |
| assert(Dst != Src && "You cannot use the same Regs with MOVSX_RR"); | |
| const auto &TRI = getRegisterInfo(); | |
| const auto *RCDst = TRI.getMaximalPhysRegClass(Dst, MVTDst); | |
| const auto *RCSrc = TRI.getMaximalPhysRegClass(Src, MVTSrc); | |
| assert(RCDst && RCSrc && "Wrong use of MOVSX_RR"); | |
| assert(RCDst != RCSrc && "You cannot use the same Reg Classes with MOVSX_RR"); | |
| // We need to find the super source register that matches the size of Dst | |
| unsigned SSrc = RI.getMatchingMegaReg(Src, RCDst); | |
| assert(SSrc && "No viable MEGA register available"); | |
| MachineBasicBlock &MBB = *MIB->getParent(); | |
| DebugLoc DL = MIB->getDebugLoc(); | |
| if (Dst != SSrc) { | |
| LLVM_DEBUG(dbgs() << "Move and " << '\n'); | |
| BuildMI(MBB, MIB.getInstr(), DL, get(Move), Dst).addReg(SSrc); | |
| } | |
| if (IsSigned) { | |
| LLVM_DEBUG(dbgs() << "Sign Extend" << '\n'); | |
| AddSExt(MBB, MIB.getInstr(), DL, Dst, MVTSrc, MVTDst); | |
| } else { | |
| LLVM_DEBUG(dbgs() << "Zero Extend" << '\n'); | |
| AddZExt(MBB, MIB.getInstr(), DL, Dst, MVTSrc, MVTDst); | |
| } | |
| MIB->eraseFromParent(); | |
| return true; | |
| } | |
| bool M68kInstrInfo::ExpandMOVSZX_RM(MachineInstrBuilder &MIB, bool IsSigned, | |
| const MCInstrDesc &Desc, MVT MVTDst, | |
| MVT MVTSrc) const { | |
| LLVM_DEBUG(dbgs() << "Expand " << *MIB.getInstr() << " to LOAD and "); | |
| Register Dst = MIB->getOperand(0).getReg(); | |
| // We need the subreg of Dst to make instruction verifier happy because the | |
| // real machine instruction consumes and produces values of the same size and | |
| // the registers the will be used here fall into different classes and this | |
| // makes IV cry. We could use a bigger operation, but this will put some | |
| // pressure on cache and memory, so no. | |
| unsigned SubDst = | |
| RI.getSubReg(Dst, MVTSrc == MVT::i8 ? M68k::MxSubRegIndex8Lo | |
| : M68k::MxSubRegIndex16Lo); | |
| assert(SubDst && "No viable SUB register available"); | |
| // Make this a plain move | |
| MIB->setDesc(Desc); | |
| MIB->getOperand(0).setReg(SubDst); | |
| MachineBasicBlock::iterator I = MIB.getInstr(); | |
| I++; | |
| MachineBasicBlock &MBB = *MIB->getParent(); | |
| DebugLoc DL = MIB->getDebugLoc(); | |
| if (IsSigned) { | |
| LLVM_DEBUG(dbgs() << "Sign Extend" << '\n'); | |
| AddSExt(MBB, I, DL, Dst, MVTSrc, MVTDst); | |
| } else { | |
| LLVM_DEBUG(dbgs() << "Zero Extend" << '\n'); | |
| AddZExt(MBB, I, DL, Dst, MVTSrc, MVTDst); | |
| } | |
| return true; | |
| } | |
| bool M68kInstrInfo::ExpandPUSH_POP(MachineInstrBuilder &MIB, | |
| const MCInstrDesc &Desc, bool IsPush) const { | |
| MachineBasicBlock::iterator I = MIB.getInstr(); | |
| I++; | |
| MachineBasicBlock &MBB = *MIB->getParent(); | |
| MachineOperand MO = MIB->getOperand(0); | |
| DebugLoc DL = MIB->getDebugLoc(); | |
| if (IsPush) | |
| BuildMI(MBB, I, DL, Desc).addReg(RI.getStackRegister()).add(MO); | |
| else | |
| BuildMI(MBB, I, DL, Desc, MO.getReg()).addReg(RI.getStackRegister()); | |
| MIB->eraseFromParent(); | |
| return true; | |
| } | |
| bool M68kInstrInfo::ExpandCCR(MachineInstrBuilder &MIB, bool IsToCCR) const { | |
| // Replace the pseudo instruction with the real one | |
| if (IsToCCR) | |
| MIB->setDesc(get(M68k::MOV16cd)); | |
| else | |
| // FIXME M68010 or later is required | |
| MIB->setDesc(get(M68k::MOV16dc)); | |
| // Promote used register to the next class | |
| auto &Opd = MIB->getOperand(1); | |
| Opd.setReg(getRegisterInfo().getMatchingSuperReg( | |
| Opd.getReg(), M68k::MxSubRegIndex8Lo, &M68k::DR16RegClass)); | |
| return true; | |
| } | |
| bool M68kInstrInfo::ExpandMOVEM(MachineInstrBuilder &MIB, | |
| const MCInstrDesc &Desc, bool IsRM) const { | |
| int Reg = 0, Offset = 0, Base = 0; | |
| auto XR32 = RI.getRegClass(M68k::XR32RegClassID); | |
| auto DL = MIB->getDebugLoc(); | |
| auto MI = MIB.getInstr(); | |
| auto &MBB = *MIB->getParent(); | |
| if (IsRM) { | |
| Reg = MIB->getOperand(0).getReg(); | |
| Offset = MIB->getOperand(1).getImm(); | |
| Base = MIB->getOperand(2).getReg(); | |
| } else { | |
| Offset = MIB->getOperand(0).getImm(); | |
| Base = MIB->getOperand(1).getReg(); | |
| Reg = MIB->getOperand(2).getReg(); | |
| } | |
| // If the register is not in XR32 then it is smaller than 32 bit, we | |
| // implicitly promote it to 32 | |
| if (!XR32->contains(Reg)) { | |
| Reg = RI.getMatchingMegaReg(Reg, XR32); | |
| assert(Reg && "Has not meaningful MEGA register"); | |
| } | |
| unsigned Mask = 1 << RI.getSpillRegisterOrder(Reg); | |
| if (IsRM) { | |
| BuildMI(MBB, MI, DL, Desc) | |
| .addImm(Mask) | |
| .addImm(Offset) | |
| .addReg(Base) | |
| .addReg(Reg, RegState::ImplicitDefine) | |
| .copyImplicitOps(*MIB); | |
| } else { | |
| BuildMI(MBB, MI, DL, Desc) | |
| .addImm(Offset) | |
| .addReg(Base) | |
| .addImm(Mask) | |
| .addReg(Reg, RegState::Implicit) | |
| .copyImplicitOps(*MIB); | |
| } | |
| MIB->eraseFromParent(); | |
| return true; | |
| } | |
| /// Expand a single-def pseudo instruction to a two-addr | |
| /// instruction with two undef reads of the register being defined. | |
| /// This is used for mapping: | |
| /// %d0 = SETCS_C32d | |
| /// to: | |
| /// %d0 = SUBX32dd %d0<undef>, %d0<undef> | |
| /// | |
| static bool Expand2AddrUndef(MachineInstrBuilder &MIB, | |
| const MCInstrDesc &Desc) { | |
| assert(Desc.getNumOperands() == 3 && "Expected two-addr instruction."); | |
| Register Reg = MIB->getOperand(0).getReg(); | |
| MIB->setDesc(Desc); | |
| // MachineInstr::addOperand() will insert explicit operands before any | |
| // implicit operands. | |
| MIB.addReg(Reg, RegState::Undef).addReg(Reg, RegState::Undef); | |
| // But we don't trust that. | |
| assert(MIB->getOperand(1).getReg() == Reg && | |
| MIB->getOperand(2).getReg() == Reg && "Misplaced operand"); | |
| return true; | |
| } | |
| bool M68kInstrInfo::expandPostRAPseudo(MachineInstr &MI) const { | |
| MachineInstrBuilder MIB(*MI.getParent()->getParent(), MI); | |
| switch (MI.getOpcode()) { | |
| case M68k::PUSH8d: | |
| return ExpandPUSH_POP(MIB, get(M68k::MOV8ed), true); | |
| case M68k::PUSH16d: | |
| return ExpandPUSH_POP(MIB, get(M68k::MOV16er), true); | |
| case M68k::PUSH32r: | |
| return ExpandPUSH_POP(MIB, get(M68k::MOV32er), true); | |
| case M68k::POP8d: | |
| return ExpandPUSH_POP(MIB, get(M68k::MOV8do), false); | |
| case M68k::POP16d: | |
| return ExpandPUSH_POP(MIB, get(M68k::MOV16ro), false); | |
| case M68k::POP32r: | |
| return ExpandPUSH_POP(MIB, get(M68k::MOV32ro), false); | |
| case M68k::SETCS_C8d: | |
| return Expand2AddrUndef(MIB, get(M68k::SUBX8dd)); | |
| case M68k::SETCS_C16d: | |
| return Expand2AddrUndef(MIB, get(M68k::SUBX16dd)); | |
| case M68k::SETCS_C32d: | |
| return Expand2AddrUndef(MIB, get(M68k::SUBX32dd)); | |
| } | |
| return false; | |
| } | |
| bool M68kInstrInfo::isPCRelRegisterOperandLegal( | |
| const MachineOperand &MO) const { | |
| assert(MO.isReg()); | |
| // Check whether this MO belongs to an instruction with addressing mode 'k', | |
| // Refer to TargetInstrInfo.h for more information about this function. | |
| const MachineInstr *MI = MO.getParent(); | |
| const unsigned NameIndices = M68kInstrNameIndices[MI->getOpcode()]; | |
| StringRef InstrName(&M68kInstrNameData[NameIndices]); | |
| const unsigned OperandNo = MI->getOperandNo(&MO); | |
| // If this machine operand is the 2nd operand, then check | |
| // whether the instruction has destination addressing mode 'k'. | |
| if (OperandNo == 1) | |
| return Regex("[A-Z]+(8|16|32)k[a-z](_TC)?$").match(InstrName); | |
| // If this machine operand is the last one, then check | |
| // whether the instruction has source addressing mode 'k'. | |
| if (OperandNo == MI->getNumExplicitOperands() - 1) | |
| return Regex("[A-Z]+(8|16|32)[a-z]k(_TC)?$").match(InstrName); | |
| return false; | |
| } | |
| void M68kInstrInfo::copyPhysReg(MachineBasicBlock &MBB, | |
| MachineBasicBlock::iterator MI, | |
| const DebugLoc &DL, MCRegister DstReg, | |
| MCRegister SrcReg, bool KillSrc) const { | |
| unsigned Opc = 0; | |
| // First deal with the normal symmetric copies. | |
| if (M68k::XR32RegClass.contains(DstReg, SrcReg)) | |
| Opc = M68k::MOV32rr; | |
| else if (M68k::XR16RegClass.contains(DstReg, SrcReg)) | |
| Opc = M68k::MOV16rr; | |
| else if (M68k::DR8RegClass.contains(DstReg, SrcReg)) | |
| Opc = M68k::MOV8dd; | |
| if (Opc) { | |
| BuildMI(MBB, MI, DL, get(Opc), DstReg) | |
| .addReg(SrcReg, getKillRegState(KillSrc)); | |
| return; | |
| } | |
| // Now deal with asymmetrically sized copies. The cases that follow are upcast | |
| // moves. | |
| // | |
| // NOTE | |
| // These moves are not aware of type nature of these values and thus | |
| // won't do any SExt or ZExt and upper bits will basically contain garbage. | |
| MachineInstrBuilder MIB(*MBB.getParent(), MI); | |
| if (M68k::DR8RegClass.contains(SrcReg)) { | |
| if (M68k::XR16RegClass.contains(DstReg)) | |
| Opc = M68k::MOVXd16d8; | |
| else if (M68k::XR32RegClass.contains(DstReg)) | |
| Opc = M68k::MOVXd32d8; | |
| } else if (M68k::XR16RegClass.contains(SrcReg) && | |
| M68k::XR32RegClass.contains(DstReg)) | |
| Opc = M68k::MOVXd32d16; | |
| if (Opc) { | |
| BuildMI(MBB, MI, DL, get(Opc), DstReg) | |
| .addReg(SrcReg, getKillRegState(KillSrc)); | |
| return; | |
| } | |
| bool FromCCR = SrcReg == M68k::CCR; | |
| bool FromSR = SrcReg == M68k::SR; | |
| bool ToCCR = DstReg == M68k::CCR; | |
| bool ToSR = DstReg == M68k::SR; | |
| if (FromCCR) { | |
| assert(M68k::DR8RegClass.contains(DstReg) && | |
| "Need DR8 register to copy CCR"); | |
| Opc = M68k::MOV8dc; | |
| } else if (ToCCR) { | |
| assert(M68k::DR8RegClass.contains(SrcReg) && | |
| "Need DR8 register to copy CCR"); | |
| Opc = M68k::MOV8cd; | |
| } else if (FromSR || ToSR) | |
| llvm_unreachable("Cannot emit SR copy instruction"); | |
| if (Opc) { | |
| BuildMI(MBB, MI, DL, get(Opc), DstReg) | |
| .addReg(SrcReg, getKillRegState(KillSrc)); | |
| return; | |
| } | |
| LLVM_DEBUG(dbgs() << "Cannot copy " << RI.getName(SrcReg) << " to " | |
| << RI.getName(DstReg) << '\n'); | |
| llvm_unreachable("Cannot emit physreg copy instruction"); | |
| } | |
| namespace { | |
| unsigned getLoadStoreRegOpcode(unsigned Reg, const TargetRegisterClass *RC, | |
| const TargetRegisterInfo *TRI, | |
| const M68kSubtarget &STI, bool load) { | |
| switch (TRI->getRegSizeInBits(*RC)) { | |
| default: | |
| llvm_unreachable("Unknown spill size"); | |
| case 8: | |
| if (M68k::DR8RegClass.hasSubClassEq(RC)) | |
| return load ? M68k::MOV8dp : M68k::MOV8pd; | |
| if (M68k::CCRCRegClass.hasSubClassEq(RC)) | |
| return load ? M68k::MOV16cp : M68k::MOV16pc; | |
| llvm_unreachable("Unknown 1-byte regclass"); | |
| case 16: | |
| assert(M68k::XR16RegClass.hasSubClassEq(RC) && "Unknown 2-byte regclass"); | |
| return load ? M68k::MOVM16mp_P : M68k::MOVM16pm_P; | |
| case 32: | |
| assert(M68k::XR32RegClass.hasSubClassEq(RC) && "Unknown 4-byte regclass"); | |
| return load ? M68k::MOVM32mp_P : M68k::MOVM32pm_P; | |
| } | |
| } | |
| unsigned getStoreRegOpcode(unsigned SrcReg, const TargetRegisterClass *RC, | |
| const TargetRegisterInfo *TRI, | |
| const M68kSubtarget &STI) { | |
| return getLoadStoreRegOpcode(SrcReg, RC, TRI, STI, false); | |
| } | |
| unsigned getLoadRegOpcode(unsigned DstReg, const TargetRegisterClass *RC, | |
| const TargetRegisterInfo *TRI, | |
| const M68kSubtarget &STI) { | |
| return getLoadStoreRegOpcode(DstReg, RC, TRI, STI, true); | |
| } | |
| } // end anonymous namespace | |
| bool M68kInstrInfo::getStackSlotRange(const TargetRegisterClass *RC, | |
| unsigned SubIdx, unsigned &Size, | |
| unsigned &Offset, | |
| const MachineFunction &MF) const { | |
| // The slot size must be the maximum size so we can easily use MOVEM.L | |
| Size = 4; | |
| Offset = 0; | |
| return true; | |
| } | |
| void M68kInstrInfo::storeRegToStackSlot( | |
| MachineBasicBlock &MBB, MachineBasicBlock::iterator MI, Register SrcReg, | |
| bool IsKill, int FrameIndex, const TargetRegisterClass *RC, | |
| const TargetRegisterInfo *TRI, Register VReg) const { | |
| const MachineFrameInfo &MFI = MBB.getParent()->getFrameInfo(); | |
| assert(MFI.getObjectSize(FrameIndex) >= TRI->getSpillSize(*RC) && | |
| "Stack slot is too small to store"); | |
| unsigned Opc = getStoreRegOpcode(SrcReg, RC, TRI, Subtarget); | |
| DebugLoc DL = MBB.findDebugLoc(MI); | |
| // (0,FrameIndex) <- $reg | |
| M68k::addFrameReference(BuildMI(MBB, MI, DL, get(Opc)), FrameIndex) | |
| .addReg(SrcReg, getKillRegState(IsKill)); | |
| } | |
| void M68kInstrInfo::loadRegFromStackSlot(MachineBasicBlock &MBB, | |
| MachineBasicBlock::iterator MI, | |
| Register DstReg, int FrameIndex, | |
| const TargetRegisterClass *RC, | |
| const TargetRegisterInfo *TRI, | |
| Register VReg) const { | |
| const MachineFrameInfo &MFI = MBB.getParent()->getFrameInfo(); | |
| assert(MFI.getObjectSize(FrameIndex) >= TRI->getSpillSize(*RC) && | |
| "Stack slot is too small to load"); | |
| unsigned Opc = getLoadRegOpcode(DstReg, RC, TRI, Subtarget); | |
| DebugLoc DL = MBB.findDebugLoc(MI); | |
| M68k::addFrameReference(BuildMI(MBB, MI, DL, get(Opc), DstReg), FrameIndex); | |
| } | |
| /// Return a virtual register initialized with the the global base register | |
| /// value. Output instructions required to initialize the register in the | |
| /// function entry block, if necessary. | |
| /// | |
| /// TODO Move this function to M68kMachineFunctionInfo. | |
| unsigned M68kInstrInfo::getGlobalBaseReg(MachineFunction *MF) const { | |
| M68kMachineFunctionInfo *MxFI = MF->getInfo<M68kMachineFunctionInfo>(); | |
| unsigned GlobalBaseReg = MxFI->getGlobalBaseReg(); | |
| if (GlobalBaseReg != 0) | |
| return GlobalBaseReg; | |
| // Create the register. The code to initialize it is inserted later, | |
| // by the CGBR pass (below). | |
| // | |
| // NOTE | |
| // Normally M68k uses A5 register as global base pointer but this will | |
| // create unnecessary spill if we use less then 4 registers in code; since A5 | |
| // is callee-save anyway we could try to allocate caller-save first and if | |
| // lucky get one, otherwise it does not really matter which callee-save to | |
| // use. | |
| MachineRegisterInfo &RegInfo = MF->getRegInfo(); | |
| GlobalBaseReg = RegInfo.createVirtualRegister(&M68k::AR32_NOSPRegClass); | |
| MxFI->setGlobalBaseReg(GlobalBaseReg); | |
| return GlobalBaseReg; | |
| } | |
| std::pair<unsigned, unsigned> | |
| M68kInstrInfo::decomposeMachineOperandsTargetFlags(unsigned TF) const { | |
| return std::make_pair(TF, 0u); | |
| } | |
| ArrayRef<std::pair<unsigned, const char *>> | |
| M68kInstrInfo::getSerializableDirectMachineOperandTargetFlags() const { | |
| using namespace M68kII; | |
| static const std::pair<unsigned, const char *> TargetFlags[] = { | |
| {MO_ABSOLUTE_ADDRESS, "m68k-absolute"}, | |
| {MO_PC_RELATIVE_ADDRESS, "m68k-pcrel"}, | |
| {MO_GOT, "m68k-got"}, | |
| {MO_GOTOFF, "m68k-gotoff"}, | |
| {MO_GOTPCREL, "m68k-gotpcrel"}, | |
| {MO_PLT, "m68k-plt"}}; | |
| return ArrayRef(TargetFlags); | |
| } | |
| namespace { | |
| /// Create Global Base Reg pass. This initializes the PIC global base register | |
| struct CGBR : public MachineFunctionPass { | |
| static char ID; | |
| CGBR() : MachineFunctionPass(ID) {} | |
| bool runOnMachineFunction(MachineFunction &MF) override { | |
| const M68kSubtarget &STI = MF.getSubtarget<M68kSubtarget>(); | |
| M68kMachineFunctionInfo *MxFI = MF.getInfo<M68kMachineFunctionInfo>(); | |
| unsigned GlobalBaseReg = MxFI->getGlobalBaseReg(); | |
| // If we didn't need a GlobalBaseReg, don't insert code. | |
| if (GlobalBaseReg == 0) | |
| return false; | |
| // Insert the set of GlobalBaseReg into the first MBB of the function | |
| MachineBasicBlock &FirstMBB = MF.front(); | |
| MachineBasicBlock::iterator MBBI = FirstMBB.begin(); | |
| DebugLoc DL = FirstMBB.findDebugLoc(MBBI); | |
| const M68kInstrInfo *TII = STI.getInstrInfo(); | |
| // Generate lea (__GLOBAL_OFFSET_TABLE_,%PC), %A5 | |
| BuildMI(FirstMBB, MBBI, DL, TII->get(M68k::LEA32q), GlobalBaseReg) | |
| .addExternalSymbol("_GLOBAL_OFFSET_TABLE_", M68kII::MO_GOTPCREL); | |
| return true; | |
| } | |
| StringRef getPassName() const override { | |
| return "M68k PIC Global Base Reg Initialization"; | |
| } | |
| void getAnalysisUsage(AnalysisUsage &AU) const override { | |
| AU.setPreservesCFG(); | |
| MachineFunctionPass::getAnalysisUsage(AU); | |
| } | |
| }; | |
| } // namespace | |
| char CGBR::ID = 0; | |
| FunctionPass *llvm::createM68kGlobalBaseRegPass() { return new CGBR(); } |