diff options
Diffstat (limited to 'contrib/llvm-project/llvm/lib/Target/AVR/AVRInstrInfo.cpp')
| -rw-r--r-- | contrib/llvm-project/llvm/lib/Target/AVR/AVRInstrInfo.cpp | 574 |
1 files changed, 574 insertions, 0 deletions
diff --git a/contrib/llvm-project/llvm/lib/Target/AVR/AVRInstrInfo.cpp b/contrib/llvm-project/llvm/lib/Target/AVR/AVRInstrInfo.cpp new file mode 100644 index 000000000000..ba7a95e92c5c --- /dev/null +++ b/contrib/llvm-project/llvm/lib/Target/AVR/AVRInstrInfo.cpp @@ -0,0 +1,574 @@ +//===-- AVRInstrInfo.cpp - AVR Instruction Information --------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// This file contains the AVR implementation of the TargetInstrInfo class. +// +//===----------------------------------------------------------------------===// + +#include "AVRInstrInfo.h" + +#include "llvm/ADT/STLExtras.h" +#include "llvm/CodeGen/MachineConstantPool.h" +#include "llvm/CodeGen/MachineFrameInfo.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineMemOperand.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/Function.h" +#include "llvm/MC/MCContext.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/TargetRegistry.h" + +#include "AVR.h" +#include "AVRMachineFunctionInfo.h" +#include "AVRRegisterInfo.h" +#include "AVRTargetMachine.h" +#include "MCTargetDesc/AVRMCTargetDesc.h" + +#define GET_INSTRINFO_CTOR_DTOR +#include "AVRGenInstrInfo.inc" + +namespace llvm { + +AVRInstrInfo::AVRInstrInfo() + : AVRGenInstrInfo(AVR::ADJCALLSTACKDOWN, AVR::ADJCALLSTACKUP), RI() {} + +void AVRInstrInfo::copyPhysReg(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI, + const DebugLoc &DL, unsigned DestReg, + unsigned SrcReg, bool KillSrc) const { + const AVRSubtarget &STI = MBB.getParent()->getSubtarget<AVRSubtarget>(); + const AVRRegisterInfo &TRI = *STI.getRegisterInfo(); + unsigned Opc; + + // Not all AVR devices support the 16-bit `MOVW` instruction. + if (AVR::DREGSRegClass.contains(DestReg, SrcReg)) { + if (STI.hasMOVW()) { + BuildMI(MBB, MI, DL, get(AVR::MOVWRdRr), DestReg) + .addReg(SrcReg, getKillRegState(KillSrc)); + } else { + unsigned DestLo, DestHi, SrcLo, SrcHi; + + TRI.splitReg(DestReg, DestLo, DestHi); + TRI.splitReg(SrcReg, SrcLo, SrcHi); + + // Copy each individual register with the `MOV` instruction. + BuildMI(MBB, MI, DL, get(AVR::MOVRdRr), DestLo) + .addReg(SrcLo, getKillRegState(KillSrc)); + BuildMI(MBB, MI, DL, get(AVR::MOVRdRr), DestHi) + .addReg(SrcHi, getKillRegState(KillSrc)); + } + } else { + if (AVR::GPR8RegClass.contains(DestReg, SrcReg)) { + Opc = AVR::MOVRdRr; + } else if (SrcReg == AVR::SP && AVR::DREGSRegClass.contains(DestReg)) { + Opc = AVR::SPREAD; + } else if (DestReg == AVR::SP && AVR::DREGSRegClass.contains(SrcReg)) { + Opc = AVR::SPWRITE; + } else { + llvm_unreachable("Impossible reg-to-reg copy"); + } + + BuildMI(MBB, MI, DL, get(Opc), DestReg) + .addReg(SrcReg, getKillRegState(KillSrc)); + } +} + +unsigned AVRInstrInfo::isLoadFromStackSlot(const MachineInstr &MI, + int &FrameIndex) const { + switch (MI.getOpcode()) { + case AVR::LDDRdPtrQ: + case AVR::LDDWRdYQ: { //:FIXME: remove this once PR13375 gets fixed + if (MI.getOperand(1).isFI() && MI.getOperand(2).isImm() && + MI.getOperand(2).getImm() == 0) { + FrameIndex = MI.getOperand(1).getIndex(); + return MI.getOperand(0).getReg(); + } + break; + } + default: + break; + } + + return 0; +} + +unsigned AVRInstrInfo::isStoreToStackSlot(const MachineInstr &MI, + int &FrameIndex) const { + switch (MI.getOpcode()) { + case AVR::STDPtrQRr: + case AVR::STDWPtrQRr: { + if (MI.getOperand(0).isFI() && MI.getOperand(1).isImm() && + MI.getOperand(1).getImm() == 0) { + FrameIndex = MI.getOperand(0).getIndex(); + return MI.getOperand(2).getReg(); + } + break; + } + default: + break; + } + + return 0; +} + +void AVRInstrInfo::storeRegToStackSlot(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI, + unsigned SrcReg, bool isKill, + int FrameIndex, + const TargetRegisterClass *RC, + const TargetRegisterInfo *TRI) const { + MachineFunction &MF = *MBB.getParent(); + AVRMachineFunctionInfo *AFI = MF.getInfo<AVRMachineFunctionInfo>(); + + AFI->setHasSpills(true); + + DebugLoc DL; + if (MI != MBB.end()) { + DL = MI->getDebugLoc(); + } + + const MachineFrameInfo &MFI = MF.getFrameInfo(); + + MachineMemOperand *MMO = MF.getMachineMemOperand( + MachinePointerInfo::getFixedStack(MF, FrameIndex), + MachineMemOperand::MOStore, MFI.getObjectSize(FrameIndex), + MFI.getObjectAlignment(FrameIndex)); + + unsigned Opcode = 0; + if (TRI->isTypeLegalForClass(*RC, MVT::i8)) { + Opcode = AVR::STDPtrQRr; + } else if (TRI->isTypeLegalForClass(*RC, MVT::i16)) { + Opcode = AVR::STDWPtrQRr; + } else { + llvm_unreachable("Cannot store this register into a stack slot!"); + } + + BuildMI(MBB, MI, DL, get(Opcode)) + .addFrameIndex(FrameIndex) + .addImm(0) + .addReg(SrcReg, getKillRegState(isKill)) + .addMemOperand(MMO); +} + +void AVRInstrInfo::loadRegFromStackSlot(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI, + unsigned DestReg, int FrameIndex, + const TargetRegisterClass *RC, + const TargetRegisterInfo *TRI) const { + DebugLoc DL; + if (MI != MBB.end()) { + DL = MI->getDebugLoc(); + } + + MachineFunction &MF = *MBB.getParent(); + const MachineFrameInfo &MFI = MF.getFrameInfo(); + + MachineMemOperand *MMO = MF.getMachineMemOperand( + MachinePointerInfo::getFixedStack(MF, FrameIndex), + MachineMemOperand::MOLoad, MFI.getObjectSize(FrameIndex), + MFI.getObjectAlignment(FrameIndex)); + + unsigned Opcode = 0; + if (TRI->isTypeLegalForClass(*RC, MVT::i8)) { + Opcode = AVR::LDDRdPtrQ; + } else if (TRI->isTypeLegalForClass(*RC, MVT::i16)) { + // Opcode = AVR::LDDWRdPtrQ; + //:FIXME: remove this once PR13375 gets fixed + Opcode = AVR::LDDWRdYQ; + } else { + llvm_unreachable("Cannot load this register from a stack slot!"); + } + + BuildMI(MBB, MI, DL, get(Opcode), DestReg) + .addFrameIndex(FrameIndex) + .addImm(0) + .addMemOperand(MMO); +} + +const MCInstrDesc &AVRInstrInfo::getBrCond(AVRCC::CondCodes CC) const { + switch (CC) { + default: + llvm_unreachable("Unknown condition code!"); + case AVRCC::COND_EQ: + return get(AVR::BREQk); + case AVRCC::COND_NE: + return get(AVR::BRNEk); + case AVRCC::COND_GE: + return get(AVR::BRGEk); + case AVRCC::COND_LT: + return get(AVR::BRLTk); + case AVRCC::COND_SH: + return get(AVR::BRSHk); + case AVRCC::COND_LO: + return get(AVR::BRLOk); + case AVRCC::COND_MI: + return get(AVR::BRMIk); + case AVRCC::COND_PL: + return get(AVR::BRPLk); + } +} + +AVRCC::CondCodes AVRInstrInfo::getCondFromBranchOpc(unsigned Opc) const { + switch (Opc) { + default: + return AVRCC::COND_INVALID; + case AVR::BREQk: + return AVRCC::COND_EQ; + case AVR::BRNEk: + return AVRCC::COND_NE; + case AVR::BRSHk: + return AVRCC::COND_SH; + case AVR::BRLOk: + return AVRCC::COND_LO; + case AVR::BRMIk: + return AVRCC::COND_MI; + case AVR::BRPLk: + return AVRCC::COND_PL; + case AVR::BRGEk: + return AVRCC::COND_GE; + case AVR::BRLTk: + return AVRCC::COND_LT; + } +} + +AVRCC::CondCodes AVRInstrInfo::getOppositeCondition(AVRCC::CondCodes CC) const { + switch (CC) { + default: + llvm_unreachable("Invalid condition!"); + case AVRCC::COND_EQ: + return AVRCC::COND_NE; + case AVRCC::COND_NE: + return AVRCC::COND_EQ; + case AVRCC::COND_SH: + return AVRCC::COND_LO; + case AVRCC::COND_LO: + return AVRCC::COND_SH; + case AVRCC::COND_GE: + return AVRCC::COND_LT; + case AVRCC::COND_LT: + return AVRCC::COND_GE; + case AVRCC::COND_MI: + return AVRCC::COND_PL; + case AVRCC::COND_PL: + return AVRCC::COND_MI; + } +} + +bool AVRInstrInfo::analyzeBranch(MachineBasicBlock &MBB, + MachineBasicBlock *&TBB, + MachineBasicBlock *&FBB, + SmallVectorImpl<MachineOperand> &Cond, + bool AllowModify) const { + // Start from the bottom of the block and work up, examining the + // terminator instructions. + MachineBasicBlock::iterator I = MBB.end(); + MachineBasicBlock::iterator UnCondBrIter = MBB.end(); + + while (I != MBB.begin()) { + --I; + if (I->isDebugInstr()) { + continue; + } + + // Working from the bottom, when we see a non-terminator + // instruction, we're done. + if (!isUnpredicatedTerminator(*I)) { + break; + } + + // A terminator that isn't a branch can't easily be handled + // by this analysis. + if (!I->getDesc().isBranch()) { + return true; + } + + // Handle unconditional branches. + //:TODO: add here jmp + if (I->getOpcode() == AVR::RJMPk) { + UnCondBrIter = I; + + if (!AllowModify) { + TBB = I->getOperand(0).getMBB(); + continue; + } + + // If the block has any instructions after a JMP, delete them. + while (std::next(I) != MBB.end()) { + std::next(I)->eraseFromParent(); + } + + Cond.clear(); + FBB = 0; + + // Delete the JMP if it's equivalent to a fall-through. + if (MBB.isLayoutSuccessor(I->getOperand(0).getMBB())) { + TBB = 0; + I->eraseFromParent(); + I = MBB.end(); + UnCondBrIter = MBB.end(); + continue; + } + + // TBB is used to indicate the unconditinal destination. + TBB = I->getOperand(0).getMBB(); + continue; + } + + // Handle conditional branches. + AVRCC::CondCodes BranchCode = getCondFromBranchOpc(I->getOpcode()); + if (BranchCode == AVRCC::COND_INVALID) { + return true; // Can't handle indirect branch. + } + + // Working from the bottom, handle the first conditional branch. + if (Cond.empty()) { + MachineBasicBlock *TargetBB = I->getOperand(0).getMBB(); + if (AllowModify && UnCondBrIter != MBB.end() && + MBB.isLayoutSuccessor(TargetBB)) { + // If we can modify the code and it ends in something like: + // + // jCC L1 + // jmp L2 + // L1: + // ... + // L2: + // + // Then we can change this to: + // + // jnCC L2 + // L1: + // ... + // L2: + // + // Which is a bit more efficient. + // We conditionally jump to the fall-through block. + BranchCode = getOppositeCondition(BranchCode); + unsigned JNCC = getBrCond(BranchCode).getOpcode(); + MachineBasicBlock::iterator OldInst = I; + + BuildMI(MBB, UnCondBrIter, MBB.findDebugLoc(I), get(JNCC)) + .addMBB(UnCondBrIter->getOperand(0).getMBB()); + BuildMI(MBB, UnCondBrIter, MBB.findDebugLoc(I), get(AVR::RJMPk)) + .addMBB(TargetBB); + + OldInst->eraseFromParent(); + UnCondBrIter->eraseFromParent(); + + // Restart the analysis. + UnCondBrIter = MBB.end(); + I = MBB.end(); + continue; + } + + FBB = TBB; + TBB = I->getOperand(0).getMBB(); + Cond.push_back(MachineOperand::CreateImm(BranchCode)); + continue; + } + + // Handle subsequent conditional branches. Only handle the case where all + // conditional branches branch to the same destination. + assert(Cond.size() == 1); + assert(TBB); + + // Only handle the case where all conditional branches branch to + // the same destination. + if (TBB != I->getOperand(0).getMBB()) { + return true; + } + + AVRCC::CondCodes OldBranchCode = (AVRCC::CondCodes)Cond[0].getImm(); + // If the conditions are the same, we can leave them alone. + if (OldBranchCode == BranchCode) { + continue; + } + + return true; + } + + return false; +} + +unsigned AVRInstrInfo::insertBranch(MachineBasicBlock &MBB, + MachineBasicBlock *TBB, + MachineBasicBlock *FBB, + ArrayRef<MachineOperand> Cond, + const DebugLoc &DL, + int *BytesAdded) const { + if (BytesAdded) *BytesAdded = 0; + + // Shouldn't be a fall through. + assert(TBB && "insertBranch must not be told to insert a fallthrough"); + assert((Cond.size() == 1 || Cond.size() == 0) && + "AVR branch conditions have one component!"); + + if (Cond.empty()) { + assert(!FBB && "Unconditional branch with multiple successors!"); + auto &MI = *BuildMI(&MBB, DL, get(AVR::RJMPk)).addMBB(TBB); + if (BytesAdded) + *BytesAdded += getInstSizeInBytes(MI); + return 1; + } + + // Conditional branch. + unsigned Count = 0; + AVRCC::CondCodes CC = (AVRCC::CondCodes)Cond[0].getImm(); + auto &CondMI = *BuildMI(&MBB, DL, getBrCond(CC)).addMBB(TBB); + + if (BytesAdded) *BytesAdded += getInstSizeInBytes(CondMI); + ++Count; + + if (FBB) { + // Two-way Conditional branch. Insert the second branch. + auto &MI = *BuildMI(&MBB, DL, get(AVR::RJMPk)).addMBB(FBB); + if (BytesAdded) *BytesAdded += getInstSizeInBytes(MI); + ++Count; + } + + return Count; +} + +unsigned AVRInstrInfo::removeBranch(MachineBasicBlock &MBB, + int *BytesRemoved) const { + if (BytesRemoved) *BytesRemoved = 0; + + MachineBasicBlock::iterator I = MBB.end(); + unsigned Count = 0; + + while (I != MBB.begin()) { + --I; + if (I->isDebugInstr()) { + continue; + } + //:TODO: add here the missing jmp instructions once they are implemented + // like jmp, {e}ijmp, and other cond branches, ... + if (I->getOpcode() != AVR::RJMPk && + getCondFromBranchOpc(I->getOpcode()) == AVRCC::COND_INVALID) { + break; + } + + // Remove the branch. + if (BytesRemoved) *BytesRemoved += getInstSizeInBytes(*I); + I->eraseFromParent(); + I = MBB.end(); + ++Count; + } + + return Count; +} + +bool AVRInstrInfo::reverseBranchCondition( + SmallVectorImpl<MachineOperand> &Cond) const { + assert(Cond.size() == 1 && "Invalid AVR branch condition!"); + + AVRCC::CondCodes CC = static_cast<AVRCC::CondCodes>(Cond[0].getImm()); + Cond[0].setImm(getOppositeCondition(CC)); + + return false; +} + +unsigned AVRInstrInfo::getInstSizeInBytes(const MachineInstr &MI) const { + unsigned Opcode = MI.getOpcode(); + + switch (Opcode) { + // A regular instruction + default: { + const MCInstrDesc &Desc = get(Opcode); + return Desc.getSize(); + } + case TargetOpcode::EH_LABEL: + case TargetOpcode::IMPLICIT_DEF: + case TargetOpcode::KILL: + case TargetOpcode::DBG_VALUE: + return 0; + case TargetOpcode::INLINEASM: + case TargetOpcode::INLINEASM_BR: { + const MachineFunction &MF = *MI.getParent()->getParent(); + const AVRTargetMachine &TM = static_cast<const AVRTargetMachine&>(MF.getTarget()); + const AVRSubtarget &STI = MF.getSubtarget<AVRSubtarget>(); + const TargetInstrInfo &TII = *STI.getInstrInfo(); + + return TII.getInlineAsmLength(MI.getOperand(0).getSymbolName(), + *TM.getMCAsmInfo()); + } + } +} + +MachineBasicBlock * +AVRInstrInfo::getBranchDestBlock(const MachineInstr &MI) const { + switch (MI.getOpcode()) { + default: + llvm_unreachable("unexpected opcode!"); + case AVR::JMPk: + case AVR::CALLk: + case AVR::RCALLk: + case AVR::RJMPk: + case AVR::BREQk: + case AVR::BRNEk: + case AVR::BRSHk: + case AVR::BRLOk: + case AVR::BRMIk: + case AVR::BRPLk: + case AVR::BRGEk: + case AVR::BRLTk: + return MI.getOperand(0).getMBB(); + case AVR::BRBSsk: + case AVR::BRBCsk: + return MI.getOperand(1).getMBB(); + case AVR::SBRCRrB: + case AVR::SBRSRrB: + case AVR::SBICAb: + case AVR::SBISAb: + llvm_unreachable("unimplemented branch instructions"); + } +} + +bool AVRInstrInfo::isBranchOffsetInRange(unsigned BranchOp, + int64_t BrOffset) const { + + switch (BranchOp) { + default: + llvm_unreachable("unexpected opcode!"); + case AVR::JMPk: + case AVR::CALLk: + return true; + case AVR::RCALLk: + case AVR::RJMPk: + return isIntN(13, BrOffset); + case AVR::BRBSsk: + case AVR::BRBCsk: + case AVR::BREQk: + case AVR::BRNEk: + case AVR::BRSHk: + case AVR::BRLOk: + case AVR::BRMIk: + case AVR::BRPLk: + case AVR::BRGEk: + case AVR::BRLTk: + return isIntN(7, BrOffset); + } +} + +unsigned AVRInstrInfo::insertIndirectBranch(MachineBasicBlock &MBB, + MachineBasicBlock &NewDestBB, + const DebugLoc &DL, + int64_t BrOffset, + RegScavenger *RS) const { + // This method inserts a *direct* branch (JMP), despite its name. + // LLVM calls this method to fixup unconditional branches; it never calls + // insertBranch or some hypothetical "insertDirectBranch". + // See lib/CodeGen/RegisterRelaxation.cpp for details. + // We end up here when a jump is too long for a RJMP instruction. + auto &MI = *BuildMI(&MBB, DL, get(AVR::JMPk)).addMBB(&NewDestBB); + + return getInstSizeInBytes(MI); +} + +} // end of namespace llvm + |
