| //===-- 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 <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; |
| unsigned Dst = MIB->getOperand(0).getReg(); |
| unsigned 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; |
| |
| unsigned Dst = MIB->getOperand(0).getReg(); |
| unsigned 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 "); |
| |
| unsigned 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."); |
| unsigned 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()); |
| const auto *MI = MO.getParent(); |
| const uint8_t *Beads = M68k::getMCInstrBeads(MI->getOpcode()); |
| assert(*Beads); |
| |
| // Only addressing mode k has (non-pc) register with PCRel |
| // So we're looking for EA Beads equal to |
| // `3Bits<011>_1Bit<1>_2Bits<11>` |
| // FIXME: There is an important caveat and two assumptions |
| // here: The caveat is that EA encoding always sit on the LSB. |
| // Where the assumptions are that if there are more than one |
| // operands, the EA encoding for the source operand always sit |
| // on the LSB. At the same time, k addressing mode can not be used |
| // on destination operand. |
| // The last assumption is kinda dirty so we need to find a way around |
| // it |
| const uint8_t EncEAk[3] = {0b011, 0b1, 0b11}; |
| for (const uint8_t Pat : EncEAk) { |
| uint8_t Bead = *(Beads++); |
| if (!Bead) |
| return false; |
| |
| switch (Bead & 0xF) { |
| default: |
| return false; |
| case M68kBeads::Bits1: |
| case M68kBeads::Bits2: |
| case M68kBeads::Bits3: { |
| uint8_t Val = (Bead & 0xF0) >> 4; |
| if (Val != Pat) |
| return false; |
| } |
| } |
| } |
| return true; |
| } |
| |
| 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::MOVM8mp_P : M68k::MOVM8pm_P; |
| 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) const { |
| const MachineFunction &MF = *MBB.getParent(); |
| assert(MF.getFrameInfo().getObjectSize(FrameIndex) == 4 && |
| "Stack slot too small for 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) const { |
| const MachineFunction &MF = *MBB.getParent(); |
| assert(MF.getFrameInfo().getObjectSize(FrameIndex) == 4 && |
| "Stack slot too small for store"); |
| 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 makeArrayRef(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(); } |