mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-26 12:43:36 +01:00
ae65e281f3
to reflect the new license. We understand that people may be surprised that we're moving the header entirely to discuss the new license. We checked this carefully with the Foundation's lawyer and we believe this is the correct approach. Essentially, all code in the project is now made available by the LLVM project under our new license, so you will see that the license headers include that license only. Some of our contributors have contributed code under our old license, and accordingly, we have retained a copy of our old license notice in the top-level files in each project and repository. llvm-svn: 351636
574 lines
17 KiB
C++
574 lines
17 KiB
C++
//===-- 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: {
|
|
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
|
|
|