mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-12-15 23:57:48 +00:00
[AVR] Add a majority of the backend code
Summary: This adds the majority of the AVR backend. Reviewers: hfinkel, dsanders, vkalintiris, arsenm Subscribers: dylanmckay Differential Revision: http://reviews.llvm.org/D17906 llvm-svn: 268722
This commit is contained in:
parent
725ddde257
commit
3be6c5786f
48
lib/Target/AVR/AVRFrameLowering.h
Normal file
48
lib/Target/AVR/AVRFrameLowering.h
Normal file
@ -0,0 +1,48 @@
|
||||
//===-- AVRFrameLowering.h - Define frame lowering for AVR ------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_AVR_FRAME_LOWERING_H
|
||||
#define LLVM_AVR_FRAME_LOWERING_H
|
||||
|
||||
#include "AVRConfig.h"
|
||||
|
||||
#include "llvm/Target/TargetFrameLowering.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
/// Utilities for creating function call frames.
|
||||
class AVRFrameLowering : public TargetFrameLowering {
|
||||
public:
|
||||
explicit AVRFrameLowering();
|
||||
|
||||
public:
|
||||
void emitPrologue(MachineFunction &MF, MachineBasicBlock &MBB) const override;
|
||||
void emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const override;
|
||||
bool hasFP(const MachineFunction &MF) const override;
|
||||
bool spillCalleeSavedRegisters(MachineBasicBlock &MBB,
|
||||
MachineBasicBlock::iterator MI,
|
||||
const std::vector<CalleeSavedInfo> &CSI,
|
||||
const TargetRegisterInfo *TRI) const override;
|
||||
bool
|
||||
restoreCalleeSavedRegisters(MachineBasicBlock &MBB,
|
||||
MachineBasicBlock::iterator MI,
|
||||
const std::vector<CalleeSavedInfo> &CSI,
|
||||
const TargetRegisterInfo *TRI) const override;
|
||||
bool hasReservedCallFrame(const MachineFunction &MF) const override;
|
||||
bool canSimplifyCallFramePseudos(const MachineFunction &MF) const override;
|
||||
void determineCalleeSaves(MachineFunction &MF, BitVector &SavedRegs,
|
||||
RegScavenger *RS = nullptr) const override;
|
||||
void
|
||||
eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB,
|
||||
MachineBasicBlock::iterator MI) const override;
|
||||
};
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_AVR_FRAME_LOWERING_H
|
154
lib/Target/AVR/AVRISelLowering.h
Normal file
154
lib/Target/AVR/AVRISelLowering.h
Normal file
@ -0,0 +1,154 @@
|
||||
//===-- AVRISelLowering.h - AVR DAG Lowering Interface ----------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines the interfaces that AVR uses to lower LLVM code into a
|
||||
// selection DAG.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_AVR_ISEL_LOWERING_H
|
||||
#define LLVM_AVR_ISEL_LOWERING_H
|
||||
|
||||
#include "AVRConfig.h"
|
||||
|
||||
#include "llvm/Target/TargetLowering.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
namespace AVRISD {
|
||||
|
||||
/// AVR Specific DAG Nodes
|
||||
enum NodeType {
|
||||
/// Start the numbering where the builtin ops leave off.
|
||||
FIRST_NUMBER = ISD::BUILTIN_OP_END,
|
||||
/// Return from subroutine.
|
||||
RET_FLAG,
|
||||
/// Return from ISR.
|
||||
RETI_FLAG,
|
||||
/// Represents an abstract call instruction,
|
||||
/// which includes a bunch of information.
|
||||
CALL,
|
||||
/// A wrapper node for TargetConstantPool,
|
||||
/// TargetExternalSymbol, and TargetGlobalAddress.
|
||||
WRAPPER,
|
||||
LSL, ///< Logical shift left.
|
||||
LSR, ///< Logical shift right.
|
||||
ASR, ///< Arithmetic shift right.
|
||||
ROR, ///< Bit rotate right.
|
||||
ROL, ///< Bit rotate left.
|
||||
LSLLOOP, ///< A loop of single logical shift left instructions.
|
||||
LSRLOOP, ///< A loop of single logical shift right instructions.
|
||||
ASRLOOP, ///< A loop of single arithmetic shift right instructions.
|
||||
/// AVR conditional branches. Operand 0 is the chain operand, operand 1
|
||||
/// is the block to branch if condition is true, operand 2 is the
|
||||
/// condition code, and operand 3 is the flag operand produced by a CMP
|
||||
/// or TEST instruction.
|
||||
BRCOND,
|
||||
/// Compare instruction.
|
||||
CMP,
|
||||
/// Compare with carry instruction.
|
||||
CMPC,
|
||||
/// Test for zero or minus instruction.
|
||||
TST,
|
||||
/// Operand 0 and operand 1 are selection variable, operand 2
|
||||
/// is condition code and operand 3 is flag operand.
|
||||
SELECT_CC
|
||||
};
|
||||
|
||||
} // end of namespace AVRISD
|
||||
|
||||
class AVRTargetMachine;
|
||||
|
||||
/// Performs target lowering for the AVR.
|
||||
class AVRTargetLowering : public TargetLowering {
|
||||
public:
|
||||
explicit AVRTargetLowering(AVRTargetMachine &TM);
|
||||
|
||||
public:
|
||||
MVT getScalarShiftAmountTy(const DataLayout &, EVT LHSTy) const override {
|
||||
return MVT::i8;
|
||||
}
|
||||
const char *getTargetNodeName(unsigned Opcode) const override;
|
||||
|
||||
SDValue LowerOperation(SDValue Op, SelectionDAG &DAG) const override;
|
||||
|
||||
void ReplaceNodeResults(SDNode *N, SmallVectorImpl<SDValue> &Results,
|
||||
SelectionDAG &DAG) const override;
|
||||
|
||||
bool isLegalAddressingMode(const DataLayout &DL, const AddrMode &AM, Type *Ty,
|
||||
unsigned AS) const override;
|
||||
|
||||
bool getPreIndexedAddressParts(SDNode *N, SDValue &Base, SDValue &Offset,
|
||||
ISD::MemIndexedMode &AM,
|
||||
SelectionDAG &DAG) const override;
|
||||
|
||||
bool getPostIndexedAddressParts(SDNode *N, SDNode *Op, SDValue &Base,
|
||||
SDValue &Offset, ISD::MemIndexedMode &AM,
|
||||
SelectionDAG &DAG) const override;
|
||||
|
||||
bool isOffsetFoldingLegal(const GlobalAddressSDNode *GA) const override;
|
||||
|
||||
MachineBasicBlock *
|
||||
EmitInstrWithCustomInserter(MachineInstr *MI,
|
||||
MachineBasicBlock *MBB) const override;
|
||||
|
||||
ConstraintType getConstraintType(StringRef Constraint) const override;
|
||||
|
||||
ConstraintWeight
|
||||
getSingleConstraintMatchWeight(AsmOperandInfo &info,
|
||||
const char *constraint) const override;
|
||||
|
||||
std::pair<unsigned, const TargetRegisterClass *>
|
||||
getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI,
|
||||
StringRef Constraint, MVT VT) const override;
|
||||
|
||||
unsigned getInlineAsmMemConstraint(StringRef ConstraintCode) const override;
|
||||
|
||||
void LowerAsmOperandForConstraint(SDValue Op, std::string &Constraint,
|
||||
std::vector<SDValue> &Ops,
|
||||
SelectionDAG &DAG) const override;
|
||||
|
||||
private:
|
||||
SDValue getAVRCmp(SDValue LHS, SDValue RHS, ISD::CondCode CC, SDValue &AVRcc,
|
||||
SelectionDAG &DAG, SDLoc dl) const;
|
||||
SDValue LowerShifts(SDValue Op, SelectionDAG &DAG) const;
|
||||
SDValue LowerDivRem(SDValue Op, SelectionDAG &DAG) const;
|
||||
SDValue LowerGlobalAddress(SDValue Op, SelectionDAG &DAG) const;
|
||||
SDValue LowerBlockAddress(SDValue Op, SelectionDAG &DAG) const;
|
||||
SDValue LowerBR_CC(SDValue Op, SelectionDAG &DAG) const;
|
||||
SDValue LowerINLINEASM(SDValue Op, SelectionDAG &DAG) const;
|
||||
SDValue LowerSELECT_CC(SDValue Op, SelectionDAG &DAG) const;
|
||||
SDValue LowerSETCC(SDValue Op, SelectionDAG &DAG) const;
|
||||
SDValue LowerVASTART(SDValue Op, SelectionDAG &DAG) const;
|
||||
|
||||
SDValue LowerReturn(SDValue Chain, CallingConv::ID CallConv, bool isVarArg,
|
||||
const SmallVectorImpl<ISD::OutputArg> &Outs,
|
||||
const SmallVectorImpl<SDValue> &OutVals, SDLoc dl,
|
||||
SelectionDAG &DAG) const override;
|
||||
SDValue LowerFormalArguments(SDValue Chain, CallingConv::ID CallConv,
|
||||
bool isVarArg,
|
||||
const SmallVectorImpl<ISD::InputArg> &Ins,
|
||||
SDLoc dl, SelectionDAG &DAG,
|
||||
SmallVectorImpl<SDValue> &InVals) const override;
|
||||
SDValue LowerCall(TargetLowering::CallLoweringInfo &CLI,
|
||||
SmallVectorImpl<SDValue> &InVals) const override;
|
||||
SDValue LowerCallResult(SDValue Chain, SDValue InFlag,
|
||||
CallingConv::ID CallConv, bool isVarArg,
|
||||
const SmallVectorImpl<ISD::InputArg> &Ins, SDLoc dl,
|
||||
SelectionDAG &DAG,
|
||||
SmallVectorImpl<SDValue> &InVals) const;
|
||||
|
||||
private:
|
||||
MachineBasicBlock *insertShift(MachineInstr *MI, MachineBasicBlock *BB) const;
|
||||
MachineBasicBlock *insertMul(MachineInstr *MI, MachineBasicBlock *BB) const;
|
||||
};
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_AVR_ISEL_LOWERING_H
|
467
lib/Target/AVR/AVRInstrInfo.cpp
Normal file
467
lib/Target/AVR/AVRInstrInfo.cpp
Normal file
@ -0,0 +1,467 @@
|
||||
//===-- AVRInstrInfo.cpp - AVR Instruction Information --------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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 "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, DebugLoc DL,
|
||||
unsigned DestReg, unsigned SrcReg,
|
||||
bool KillSrc) const {
|
||||
unsigned Opc;
|
||||
|
||||
if (AVR::GPR8RegClass.contains(DestReg, SrcReg)) {
|
||||
Opc = AVR::MOVRdRr;
|
||||
} else if (AVR::DREGSRegClass.contains(DestReg, SrcReg)) {
|
||||
Opc = AVR::MOVWRdRr;
|
||||
} 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>();
|
||||
|
||||
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 (RC->hasType(MVT::i8)) {
|
||||
Opcode = AVR::STDPtrQRr;
|
||||
} else if (RC->hasType(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 (RC->hasType(MVT::i8)) {
|
||||
Opcode = AVR::LDDRdPtrQ;
|
||||
} else if (RC->hasType(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->isDebugValue()) {
|
||||
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,
|
||||
DebugLoc DL) 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) &&
|
||||
"AVR branch conditions have one component!");
|
||||
|
||||
if (Cond.empty()) {
|
||||
assert(!FBB && "Unconditional branch with multiple successors!");
|
||||
BuildMI(&MBB, DL, get(AVR::RJMPk)).addMBB(TBB);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Conditional branch.
|
||||
unsigned Count = 0;
|
||||
AVRCC::CondCodes CC = (AVRCC::CondCodes)Cond[0].getImm();
|
||||
BuildMI(&MBB, DL, getBrCond(CC)).addMBB(TBB);
|
||||
++Count;
|
||||
|
||||
if (FBB) {
|
||||
// Two-way Conditional branch. Insert the second branch.
|
||||
BuildMI(&MBB, DL, get(AVR::RJMPk)).addMBB(FBB);
|
||||
++Count;
|
||||
}
|
||||
|
||||
return Count;
|
||||
}
|
||||
|
||||
unsigned AVRInstrInfo::RemoveBranch(MachineBasicBlock &MBB) const {
|
||||
MachineBasicBlock::iterator I = MBB.end();
|
||||
unsigned Count = 0;
|
||||
|
||||
while (I != MBB.begin()) {
|
||||
--I;
|
||||
if (I->isDebugValue()) {
|
||||
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.
|
||||
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 TargetInstrInfo &TII = *TM.getSubtargetImpl()->getInstrInfo();
|
||||
return TII.getInlineAsmLength(MI->getOperand(0).getSymbolName(),
|
||||
*TM.getMCAsmInfo());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // end of namespace llvm
|
112
lib/Target/AVR/AVRInstrInfo.h
Normal file
112
lib/Target/AVR/AVRInstrInfo.h
Normal file
@ -0,0 +1,112 @@
|
||||
//===-- AVRInstrInfo.h - AVR Instruction Information ------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file contains the AVR implementation of the TargetInstrInfo class.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_AVR_INSTR_INFO_H
|
||||
#define LLVM_AVR_INSTR_INFO_H
|
||||
|
||||
#include "llvm/Target/TargetInstrInfo.h"
|
||||
|
||||
#include "AVRRegisterInfo.h"
|
||||
|
||||
#define GET_INSTRINFO_HEADER
|
||||
#include "AVRGenInstrInfo.inc"
|
||||
#undef GET_INSTRINFO_HEADER
|
||||
|
||||
namespace llvm {
|
||||
|
||||
namespace AVRCC {
|
||||
|
||||
/// AVR specific condition codes.
|
||||
/// These correspond to `AVR_*_COND` in `AVRInstrInfo.td`.
|
||||
/// They must be kept in synch.
|
||||
enum CondCodes {
|
||||
COND_EQ, //!< Equal
|
||||
COND_NE, //!< Not equal
|
||||
COND_GE, //!< Greater than or equal
|
||||
COND_LT, //!< Less than
|
||||
COND_SH, //!< Unsigned same or higher
|
||||
COND_LO, //!< Unsigned lower
|
||||
COND_MI, //!< Minus
|
||||
COND_PL, //!< Plus
|
||||
COND_INVALID
|
||||
};
|
||||
|
||||
} // end of namespace AVRCC
|
||||
|
||||
namespace AVRII {
|
||||
|
||||
/// Specifies a target operand flag.
|
||||
enum TOF {
|
||||
MO_NO_FLAG,
|
||||
|
||||
/// On a symbol operand, this represents the lo part.
|
||||
MO_LO = (1 << 1),
|
||||
|
||||
/// On a symbol operand, this represents the hi part.
|
||||
MO_HI = (1 << 2),
|
||||
|
||||
/// On a symbol operand, this represents it has to be negated.
|
||||
MO_NEG = (1 << 3)
|
||||
};
|
||||
|
||||
} // end of namespace AVRII
|
||||
|
||||
/**
|
||||
* Utilities related to the AVR instruction set.
|
||||
*/
|
||||
class AVRInstrInfo : public AVRGenInstrInfo {
|
||||
public:
|
||||
explicit AVRInstrInfo();
|
||||
|
||||
const AVRRegisterInfo &getRegisterInfo() const { return RI; }
|
||||
const MCInstrDesc &getBrCond(AVRCC::CondCodes CC) const;
|
||||
AVRCC::CondCodes getCondFromBranchOpc(unsigned Opc) const;
|
||||
AVRCC::CondCodes getOppositeCondition(AVRCC::CondCodes CC) const;
|
||||
unsigned GetInstSizeInBytes(const MachineInstr *MI) const;
|
||||
|
||||
void copyPhysReg(MachineBasicBlock &MBB, MachineBasicBlock::iterator MI,
|
||||
DebugLoc DL, unsigned DestReg, unsigned SrcReg,
|
||||
bool KillSrc) const override;
|
||||
void storeRegToStackSlot(MachineBasicBlock &MBB,
|
||||
MachineBasicBlock::iterator MI, unsigned SrcReg,
|
||||
bool isKill, int FrameIndex,
|
||||
const TargetRegisterClass *RC,
|
||||
const TargetRegisterInfo *TRI) const override;
|
||||
void loadRegFromStackSlot(MachineBasicBlock &MBB,
|
||||
MachineBasicBlock::iterator MI, unsigned DestReg,
|
||||
int FrameIndex, const TargetRegisterClass *RC,
|
||||
const TargetRegisterInfo *TRI) const override;
|
||||
unsigned isLoadFromStackSlot(const MachineInstr *MI,
|
||||
int &FrameIndex) const override;
|
||||
unsigned isStoreToStackSlot(const MachineInstr *MI,
|
||||
int &FrameIndex) const override;
|
||||
|
||||
// Branch analysis.
|
||||
bool AnalyzeBranch(MachineBasicBlock &MBB, MachineBasicBlock *&TBB,
|
||||
MachineBasicBlock *&FBB,
|
||||
SmallVectorImpl<MachineOperand> &Cond,
|
||||
bool AllowModify = false) const override;
|
||||
unsigned InsertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB,
|
||||
MachineBasicBlock *FBB, ArrayRef<MachineOperand> Cond,
|
||||
DebugLoc DL) const override;
|
||||
unsigned RemoveBranch(MachineBasicBlock &MBB) const override;
|
||||
bool
|
||||
ReverseBranchCondition(SmallVectorImpl<MachineOperand> &Cond) const override;
|
||||
|
||||
private:
|
||||
const AVRRegisterInfo RI;
|
||||
};
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_AVR_INSTR_INFO_H
|
@ -45,7 +45,7 @@ def AVRcallseq_end : SDNode<"ISD::CALLSEQ_END", SDT_AVRCallSeqEnd,
|
||||
def AVRcall : SDNode<"AVRISD::CALL", SDT_AVRCall,
|
||||
[SDNPHasChain, SDNPOutGlue, SDNPOptInGlue, SDNPVariadic]>;
|
||||
|
||||
def AVRWrapper : SDNode<"AVRISD::Wrapper", SDT_AVRWrapper>;
|
||||
def AVRWrapper : SDNode<"AVRISD::WRAPPER", SDT_AVRWrapper>;
|
||||
|
||||
def AVRbrcond : SDNode<"AVRISD::BRCOND", SDT_AVRBrcond,
|
||||
[SDNPHasChain, SDNPInGlue]>;
|
||||
|
256
lib/Target/AVR/AVRRegisterInfo.cpp
Normal file
256
lib/Target/AVR/AVRRegisterInfo.cpp
Normal file
@ -0,0 +1,256 @@
|
||||
//===-- AVRRegisterInfo.cpp - AVR Register Information --------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file contains the AVR implementation of the TargetRegisterInfo class.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "AVRRegisterInfo.h"
|
||||
|
||||
#include "llvm/ADT/BitVector.h"
|
||||
#include "llvm/CodeGen/MachineFrameInfo.h"
|
||||
#include "llvm/CodeGen/MachineFunction.h"
|
||||
#include "llvm/CodeGen/MachineInstrBuilder.h"
|
||||
#include "llvm/IR/Function.h"
|
||||
#include "llvm/Target/TargetFrameLowering.h"
|
||||
|
||||
#include "AVR.h"
|
||||
#include "AVRInstrInfo.h"
|
||||
#include "AVRTargetMachine.h"
|
||||
#include "MCTargetDesc/AVRMCTargetDesc.h"
|
||||
|
||||
#define GET_REGINFO_TARGET_DESC
|
||||
#include "AVRGenRegisterInfo.inc"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
AVRRegisterInfo::AVRRegisterInfo() : AVRGenRegisterInfo(0) {}
|
||||
|
||||
const uint16_t *
|
||||
AVRRegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) const {
|
||||
CallingConv::ID CC = MF->getFunction()->getCallingConv();
|
||||
|
||||
return ((CC == CallingConv::AVR_INTR || CC == CallingConv::AVR_SIGNAL)
|
||||
? CSR_Interrupts_SaveList
|
||||
: CSR_Normal_SaveList);
|
||||
}
|
||||
|
||||
const uint32_t *
|
||||
AVRRegisterInfo::getCallPreservedMask(const MachineFunction &MF,
|
||||
CallingConv::ID CC) const {
|
||||
return ((CC == CallingConv::AVR_INTR || CC == CallingConv::AVR_SIGNAL)
|
||||
? CSR_Interrupts_RegMask
|
||||
: CSR_Normal_RegMask);
|
||||
}
|
||||
|
||||
BitVector AVRRegisterInfo::getReservedRegs(const MachineFunction &MF) const {
|
||||
BitVector Reserved(getNumRegs());
|
||||
const AVRTargetMachine &TM = static_cast<const AVRTargetMachine&>(MF.getTarget());
|
||||
const TargetFrameLowering *TFI = TM.getSubtargetImpl()->getFrameLowering();
|
||||
|
||||
// Reserve the intermediate result registers r1 and r2
|
||||
// The result of instructions like 'mul' is always stored here.
|
||||
Reserved.set(AVR::R0);
|
||||
Reserved.set(AVR::R1);
|
||||
Reserved.set(AVR::R1R0);
|
||||
|
||||
// Reserve the stack pointer.
|
||||
Reserved.set(AVR::SPL);
|
||||
Reserved.set(AVR::SPH);
|
||||
Reserved.set(AVR::SP);
|
||||
|
||||
// Reserve the frame pointer registers r28 and r29 if the function requires one.
|
||||
if (TFI->hasFP(MF)) {
|
||||
Reserved.set(AVR::R28);
|
||||
Reserved.set(AVR::R29);
|
||||
Reserved.set(AVR::R29R28);
|
||||
}
|
||||
|
||||
return Reserved;
|
||||
}
|
||||
|
||||
const TargetRegisterClass *
|
||||
AVRRegisterInfo::getLargestLegalSuperClass(const TargetRegisterClass *RC,
|
||||
const MachineFunction &MF) const {
|
||||
if (RC->hasType(MVT::i16)) {
|
||||
return &AVR::DREGSRegClass;
|
||||
}
|
||||
|
||||
if (RC->hasType(MVT::i8)) {
|
||||
return &AVR::GPR8RegClass;
|
||||
}
|
||||
|
||||
llvm_unreachable("Invalid register size");
|
||||
}
|
||||
|
||||
/// Fold a frame offset shared between two add instructions into a single one.
|
||||
static void foldFrameOffset(MachineInstr &MI, int &Offset, unsigned DstReg) {
|
||||
int Opcode = MI.getOpcode();
|
||||
|
||||
// Don't bother trying if the next instruction is not an add or a sub.
|
||||
if ((Opcode != AVR::SUBIWRdK) && (Opcode != AVR::ADIWRdK)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check that DstReg matches with next instruction, otherwise the instruction
|
||||
// is not related to stack address manipulation.
|
||||
if (DstReg != MI.getOperand(0).getReg()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Add the offset in the next instruction to our offset.
|
||||
switch (Opcode) {
|
||||
case AVR::SUBIWRdK:
|
||||
Offset += -MI.getOperand(2).getImm();
|
||||
break;
|
||||
case AVR::ADIWRdK:
|
||||
Offset += MI.getOperand(2).getImm();
|
||||
break;
|
||||
}
|
||||
|
||||
// Finally remove the instruction.
|
||||
MI.eraseFromParent();
|
||||
}
|
||||
|
||||
void AVRRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II,
|
||||
int SPAdj, unsigned FIOperandNum,
|
||||
RegScavenger *RS) const {
|
||||
assert(SPAdj == 0 && "Unexpected SPAdj value");
|
||||
|
||||
MachineInstr &MI = *II;
|
||||
DebugLoc dl = MI.getDebugLoc();
|
||||
MachineBasicBlock &MBB = *MI.getParent();
|
||||
const MachineFunction &MF = *MBB.getParent();
|
||||
const AVRTargetMachine &TM = (const AVRTargetMachine &)MF.getTarget();
|
||||
const TargetInstrInfo &TII = *TM.getSubtargetImpl()->getInstrInfo();
|
||||
const MachineFrameInfo *MFI = MF.getFrameInfo();
|
||||
const TargetFrameLowering *TFI = TM.getSubtargetImpl()->getFrameLowering();
|
||||
int FrameIndex = MI.getOperand(FIOperandNum).getIndex();
|
||||
int Offset = MFI->getObjectOffset(FrameIndex);
|
||||
|
||||
// Add one to the offset because SP points to an empty slot.
|
||||
Offset += MFI->getStackSize() - TFI->getOffsetOfLocalArea() + 1;
|
||||
// Fold incoming offset.
|
||||
Offset += MI.getOperand(FIOperandNum + 1).getImm();
|
||||
|
||||
// This is actually "load effective address" of the stack slot
|
||||
// instruction. We have only two-address instructions, thus we need to
|
||||
// expand it into move + add.
|
||||
if (MI.getOpcode() == AVR::FRMIDX) {
|
||||
MI.setDesc(TII.get(AVR::MOVWRdRr));
|
||||
MI.getOperand(FIOperandNum).ChangeToRegister(AVR::R29R28, false);
|
||||
|
||||
assert(Offset > 0 && "Invalid offset");
|
||||
|
||||
// We need to materialize the offset via an add instruction.
|
||||
unsigned Opcode;
|
||||
unsigned DstReg = MI.getOperand(0).getReg();
|
||||
assert(DstReg != AVR::R29R28 && "Dest reg cannot be the frame pointer");
|
||||
|
||||
// Generally, to load a frame address two add instructions are emitted that
|
||||
// could get folded into a single one:
|
||||
// movw r31:r30, r29:r28
|
||||
// adiw r31:r30, 29
|
||||
// adiw r31:r30, 16
|
||||
// to:
|
||||
// movw r31:r30, r29:r28
|
||||
// adiw r31:r30, 45
|
||||
foldFrameOffset(*std::next(II), Offset, DstReg);
|
||||
|
||||
// Select the best opcode based on DstReg and the offset size.
|
||||
switch (DstReg) {
|
||||
case AVR::R25R24:
|
||||
case AVR::R27R26:
|
||||
case AVR::R31R30: {
|
||||
if (isUInt<6>(Offset)) {
|
||||
Opcode = AVR::ADIWRdK;
|
||||
break;
|
||||
}
|
||||
// Fallthrough
|
||||
}
|
||||
default: {
|
||||
// This opcode will get expanded into a pair of subi/sbci.
|
||||
Opcode = AVR::SUBIWRdK;
|
||||
Offset = -Offset;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
MachineInstr *New = BuildMI(MBB, std::next(II), dl, TII.get(Opcode), DstReg)
|
||||
.addReg(DstReg, RegState::Kill)
|
||||
.addImm(Offset);
|
||||
New->getOperand(3).setIsDead();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// If the offset is too big we have to adjust and restore the frame pointer
|
||||
// to materialize a valid load/store with displacement.
|
||||
//:TODO: consider using only one adiw/sbiw chain for more than one frame index
|
||||
if (Offset >= 63) {
|
||||
unsigned AddOpc = AVR::ADIWRdK, SubOpc = AVR::SBIWRdK;
|
||||
int AddOffset = Offset - 63 + 1;
|
||||
|
||||
// For huge offsets where adiw/sbiw cannot be used use a pair of subi/sbci.
|
||||
if ((Offset - 63 + 1) > 63) {
|
||||
AddOpc = AVR::SUBIWRdK;
|
||||
SubOpc = AVR::SUBIWRdK;
|
||||
AddOffset = -AddOffset;
|
||||
}
|
||||
|
||||
// It is possible that the spiller places this frame instruction in between
|
||||
// a compare and branch, invalidating the contents of SREG set by the
|
||||
// compare instruction because of the add/sub pairs. Conservatively save and
|
||||
// restore SREG before and after each add/sub pair.
|
||||
BuildMI(MBB, II, dl, TII.get(AVR::INRdA), AVR::R0).addImm(0x3f);
|
||||
|
||||
MachineInstr *New = BuildMI(MBB, II, dl, TII.get(AddOpc), AVR::R29R28)
|
||||
.addReg(AVR::R29R28, RegState::Kill)
|
||||
.addImm(AddOffset);
|
||||
New->getOperand(3).setIsDead();
|
||||
|
||||
// Restore SREG.
|
||||
BuildMI(MBB, std::next(II), dl, TII.get(AVR::OUTARr))
|
||||
.addImm(0x3f)
|
||||
.addReg(AVR::R0, RegState::Kill);
|
||||
|
||||
// No need to set SREG as dead here otherwise if the next instruction is a
|
||||
// cond branch it will be using a dead register.
|
||||
New = BuildMI(MBB, std::next(II), dl, TII.get(SubOpc), AVR::R29R28)
|
||||
.addReg(AVR::R29R28, RegState::Kill)
|
||||
.addImm(Offset - 63 + 1);
|
||||
|
||||
Offset = 62;
|
||||
}
|
||||
|
||||
MI.getOperand(FIOperandNum).ChangeToRegister(AVR::R29R28, false);
|
||||
assert(isUInt<6>(Offset) && "Offset is out of range");
|
||||
MI.getOperand(FIOperandNum + 1).ChangeToImmediate(Offset);
|
||||
}
|
||||
|
||||
unsigned AVRRegisterInfo::getFrameRegister(const MachineFunction &MF) const {
|
||||
const TargetFrameLowering *TFI = MF.getSubtarget().getFrameLowering();
|
||||
if (TFI->hasFP(MF)) {
|
||||
// The Y pointer register
|
||||
return AVR::R28;
|
||||
}
|
||||
|
||||
return AVR::SP;
|
||||
}
|
||||
|
||||
const TargetRegisterClass *
|
||||
AVRRegisterInfo::getPointerRegClass(const MachineFunction &MF,
|
||||
unsigned Kind) const {
|
||||
// FIXME: Currently we're using avr-gcc as reference, so we restrict
|
||||
// ptrs to Y and Z regs. Though avr-gcc has buggy implementation
|
||||
// of memory constraint, so we can fix it and bit avr-gcc here ;-)
|
||||
return &AVR::PTRDISPREGSRegClass;
|
||||
}
|
||||
|
||||
} // end of namespace llvm
|
56
lib/Target/AVR/AVRRegisterInfo.h
Normal file
56
lib/Target/AVR/AVRRegisterInfo.h
Normal file
@ -0,0 +1,56 @@
|
||||
//===-- AVRRegisterInfo.h - AVR Register Information Impl -------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file contains the AVR implementation of the TargetRegisterInfo class.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_AVR_REGISTER_INFO_H
|
||||
#define LLVM_AVR_REGISTER_INFO_H
|
||||
|
||||
#include "llvm/Target/TargetRegisterInfo.h"
|
||||
|
||||
#define GET_REGINFO_HEADER
|
||||
#include "AVRGenRegisterInfo.inc"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
/// Utilities relating to AVR registers.
|
||||
class AVRRegisterInfo : public AVRGenRegisterInfo {
|
||||
public:
|
||||
AVRRegisterInfo();
|
||||
|
||||
public:
|
||||
const uint16_t *
|
||||
getCalleeSavedRegs(const MachineFunction *MF = 0) const override;
|
||||
const uint32_t *getCallPreservedMask(const MachineFunction &MF,
|
||||
CallingConv::ID CC) const override;
|
||||
BitVector getReservedRegs(const MachineFunction &MF) const override;
|
||||
|
||||
const TargetRegisterClass *
|
||||
getLargestLegalSuperClass(const TargetRegisterClass *RC,
|
||||
const MachineFunction &MF) const override;
|
||||
|
||||
/// Stack Frame Processing Methods
|
||||
void eliminateFrameIndex(MachineBasicBlock::iterator MI, int SPAdj,
|
||||
unsigned FIOperandNum,
|
||||
RegScavenger *RS = NULL) const override;
|
||||
|
||||
/// Debug information queries.
|
||||
unsigned getFrameRegister(const MachineFunction &MF) const override;
|
||||
|
||||
/// Returns a TargetRegisterClass used for pointer values.
|
||||
const TargetRegisterClass *
|
||||
getPointerRegClass(const MachineFunction &MF,
|
||||
unsigned Kind = 0) const override;
|
||||
};
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_AVR_REGISTER_INFO_H
|
47
lib/Target/AVR/AVRSubtarget.cpp
Normal file
47
lib/Target/AVR/AVRSubtarget.cpp
Normal file
@ -0,0 +1,47 @@
|
||||
//===-- AVRSubtarget.cpp - AVR Subtarget Information ----------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements the AVR specific subclass of TargetSubtargetInfo.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "AVRSubtarget.h"
|
||||
|
||||
#include "llvm/Support/ELF.h"
|
||||
#include "llvm/Support/TargetRegistry.h"
|
||||
|
||||
#include "AVR.h"
|
||||
#include "AVRTargetMachine.h"
|
||||
#include "MCTargetDesc/AVRMCTargetDesc.h"
|
||||
|
||||
#define DEBUG_TYPE "avr-subtarget"
|
||||
|
||||
#define GET_SUBTARGETINFO_TARGET_DESC
|
||||
#define GET_SUBTARGETINFO_CTOR
|
||||
#include "AVRGenSubtargetInfo.inc"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
AVRSubtarget::AVRSubtarget(const Triple &TT, const std::string &CPU,
|
||||
const std::string &FS, AVRTargetMachine &TM)
|
||||
: AVRGenSubtargetInfo(TT, CPU, FS), InstrInfo(), FrameLowering(),
|
||||
TLInfo(TM), TSInfo(),
|
||||
|
||||
// Subtarget features
|
||||
m_hasSRAM(false), m_hasJMPCALL(false), m_hasIJMPCALL(false),
|
||||
m_hasEIJMPCALL(false), m_hasADDSUBIW(false), m_hasSmallStack(false),
|
||||
m_hasMOVW(false), m_hasLPM(false), m_hasLPMX(false), m_hasELPM(false),
|
||||
m_hasELPMX(false), m_hasSPM(false), m_hasSPMX(false), m_hasDES(false),
|
||||
m_supportsRMW(false), m_supportsMultiplication(false), m_hasBREAK(false),
|
||||
m_hasTinyEncoding(false), ELFArch(false), m_FeatureSetDummy(false) {
|
||||
// Parse features string.
|
||||
ParseSubtargetFeatures(CPU, FS);
|
||||
}
|
||||
|
||||
} // end of namespace llvm
|
121
lib/Target/AVR/AVRSubtarget.h
Normal file
121
lib/Target/AVR/AVRSubtarget.h
Normal file
@ -0,0 +1,121 @@
|
||||
//===-- AVRSubtarget.h - Define Subtarget for the AVR -----------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file declares the AVR specific subclass of TargetSubtargetInfo.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_AVR_SUBTARGET_H
|
||||
#define LLVM_AVR_SUBTARGET_H
|
||||
|
||||
#include "AVRConfig.h"
|
||||
|
||||
#include "llvm/Target/TargetSubtargetInfo.h"
|
||||
#include "llvm/IR/DataLayout.h"
|
||||
#include "llvm/IR/DataLayout.h"
|
||||
#include "llvm/Target/TargetMachine.h"
|
||||
|
||||
#include "AVRFrameLowering.h"
|
||||
#include "AVRISelLowering.h"
|
||||
#include "AVRInstrInfo.h"
|
||||
#include "AVRSelectionDAGInfo.h"
|
||||
|
||||
#define GET_SUBTARGETINFO_HEADER
|
||||
#include "AVRGenSubtargetInfo.inc"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
/// A specific AVR target MCU.
|
||||
class AVRSubtarget : public AVRGenSubtargetInfo {
|
||||
public:
|
||||
//! Creates an AVR subtarget.
|
||||
//! \param TT The target triple.
|
||||
//! \param CPU The CPU to target.
|
||||
//! \param FS The feature string.
|
||||
//! \param TM The target machine.
|
||||
AVRSubtarget(const Triple &TT, const std::string &CPU, const std::string &FS,
|
||||
AVRTargetMachine &TM);
|
||||
|
||||
const AVRInstrInfo *getInstrInfo() const override { return &InstrInfo; }
|
||||
const TargetFrameLowering *getFrameLowering() const override { return &FrameLowering; }
|
||||
const AVRTargetLowering *getTargetLowering() const override { return &TLInfo; }
|
||||
const AVRSelectionDAGInfo *getSelectionDAGInfo() const override { return &TSInfo; }
|
||||
const AVRRegisterInfo *getRegisterInfo() const override { return &InstrInfo.getRegisterInfo(); }
|
||||
|
||||
/// Parses a subtarget feature string, setting appropriate options.
|
||||
/// \note Definition of function is auto generated by `tblgen`.
|
||||
void ParseSubtargetFeatures(StringRef CPU, StringRef FS);
|
||||
|
||||
// Subtarget feature getters.
|
||||
// See AVR.td for details.
|
||||
bool hasSRAM() const { return m_hasSRAM; }
|
||||
bool hasJMPCALL() const { return m_hasJMPCALL; }
|
||||
bool hasIJMPCALL() const { return m_hasIJMPCALL; }
|
||||
bool hasEIJMPCALL() const { return m_hasEIJMPCALL; }
|
||||
bool hasADDSUBIW() const { return m_hasADDSUBIW; }
|
||||
bool hasSmallStack() const { return m_hasSmallStack; }
|
||||
bool hasMOVW() const { return m_hasMOVW; }
|
||||
bool hasLPM() const { return m_hasLPM; }
|
||||
bool hasLPMX() const { return m_hasLPMX; }
|
||||
bool hasELPM() const { return m_hasELPM; }
|
||||
bool hasELPMX() const { return m_hasELPMX; }
|
||||
bool hasSPM() const { return m_hasSPM; }
|
||||
bool hasSPMX() const { return m_hasSPMX; }
|
||||
bool hasDES() const { return m_hasDES; }
|
||||
bool supportsRMW() const { return m_supportsRMW; }
|
||||
bool supportsMultiplication() const { return m_supportsMultiplication; }
|
||||
bool hasBREAK() const { return m_hasBREAK; }
|
||||
bool hasTinyEncoding() const { return m_hasTinyEncoding; }
|
||||
|
||||
/// Gets the ELF architecture for the e_flags field
|
||||
/// of an ELF object file.
|
||||
unsigned getELFArch() const {
|
||||
assert(ELFArch != 0 &&
|
||||
"every device must have an associate ELF architecture");
|
||||
return ELFArch;
|
||||
}
|
||||
|
||||
private:
|
||||
AVRInstrInfo InstrInfo;
|
||||
AVRFrameLowering FrameLowering;
|
||||
AVRTargetLowering TLInfo;
|
||||
AVRSelectionDAGInfo TSInfo;
|
||||
|
||||
// Subtarget feature settings
|
||||
// See AVR.td for details.
|
||||
bool m_hasSRAM;
|
||||
bool m_hasJMPCALL;
|
||||
bool m_hasIJMPCALL;
|
||||
bool m_hasEIJMPCALL;
|
||||
bool m_hasADDSUBIW;
|
||||
bool m_hasSmallStack;
|
||||
bool m_hasMOVW;
|
||||
bool m_hasLPM;
|
||||
bool m_hasLPMX;
|
||||
bool m_hasELPM;
|
||||
bool m_hasELPMX;
|
||||
bool m_hasSPM;
|
||||
bool m_hasSPMX;
|
||||
bool m_hasDES;
|
||||
bool m_supportsRMW;
|
||||
bool m_supportsMultiplication;
|
||||
bool m_hasBREAK;
|
||||
bool m_hasTinyEncoding;
|
||||
|
||||
/// The ELF e_flags architecture.
|
||||
unsigned ELFArch;
|
||||
|
||||
// Dummy member, used by FeatureSet's. We cannot have a SubtargetFeature with
|
||||
// no variable, so we instead bind pseudo features to this variable.
|
||||
bool m_FeatureSetDummy;
|
||||
};
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_AVR_SUBTARGET_H
|
@ -1,4 +1,100 @@
|
||||
//===-- AVRTargetMachine.cpp - Define TargetMachine for AVR ---------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines the AVR specific subclass of TargetMachine.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "AVRTargetMachine.h"
|
||||
|
||||
#include "llvm/CodeGen/Passes.h"
|
||||
#include "llvm/IR/Module.h"
|
||||
#include "llvm/IR/LegacyPassManager.h"
|
||||
#include "llvm/Support/TargetRegistry.h"
|
||||
|
||||
#include "AVRTargetObjectFile.h"
|
||||
#include "AVR.h"
|
||||
#include "MCTargetDesc/AVRMCTargetDesc.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
/// Processes a CPU name.
|
||||
static StringRef getTargetCPU(StringRef CPU) {
|
||||
if (CPU.empty() || CPU == "generic") {
|
||||
return "avr2";
|
||||
}
|
||||
|
||||
return CPU;
|
||||
}
|
||||
|
||||
AVRTargetMachine::AVRTargetMachine(const Target &T, const Triple &TT,
|
||||
StringRef CPU, StringRef FS,
|
||||
const TargetOptions &Options,
|
||||
Reloc::Model RM, CodeModel::Model CM,
|
||||
CodeGenOpt::Level OL)
|
||||
: LLVMTargetMachine(
|
||||
T, "e-p:16:8:8-i8:8:8-i16:8:8-i32:8:8-i64:8:8-f32:8:8-f64:8:8-n8", TT,
|
||||
getTargetCPU(CPU), FS, Options, RM, CM, OL),
|
||||
SubTarget(TT, GetTargetCPU(CPU), FS, *this) {
|
||||
this->TLOF = make_unique<AVRTargetObjectFile>();
|
||||
initAsmInfo();
|
||||
}
|
||||
|
||||
namespace {
|
||||
/// AVR Code Generator Pass Configuration Options.
|
||||
class AVRPassConfig : public TargetPassConfig {
|
||||
public:
|
||||
AVRPassConfig(AVRTargetMachine *TM, PassManagerBase &PM)
|
||||
: TargetPassConfig(TM, PM) {}
|
||||
|
||||
AVRTargetMachine &getAVRTargetMachine() const {
|
||||
return getTM<AVRTargetMachine>();
|
||||
}
|
||||
|
||||
bool addInstSelector() override;
|
||||
void addPreSched2() override;
|
||||
void addPreRegAlloc() override;
|
||||
void addPreEmitPass() override;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
TargetPassConfig *AVRTargetMachine::createPassConfig(PassManagerBase &PM) {
|
||||
return new AVRPassConfig(this, PM);
|
||||
}
|
||||
|
||||
extern "C" void LLVMInitializeAVRTarget() {
|
||||
|
||||
// Register the target.
|
||||
RegisterTargetMachine<AVRTargetMachine> X(TheAVRTarget);
|
||||
}
|
||||
|
||||
const AVRSubtarget *AVRTargetMachine::getSubtargetImpl() const {
|
||||
return &SubTarget;
|
||||
}
|
||||
|
||||
const AVRSubtarget *AVRTargetMachine::getSubtargetImpl(const Function &) const {
|
||||
return &SubTarget;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Pass Pipeline Configuration
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
bool AVRPassConfig::addInstSelector() {
|
||||
return false;
|
||||
}
|
||||
|
||||
void AVRPassConfig::addPreRegAlloc() {
|
||||
}
|
||||
|
||||
void AVRPassConfig::addPreSched2() { }
|
||||
|
||||
void AVRPassConfig::addPreEmitPass() {
|
||||
}
|
||||
|
||||
} // end of namespace llvm
|
||||
|
56
lib/Target/AVR/AVRTargetMachine.h
Normal file
56
lib/Target/AVR/AVRTargetMachine.h
Normal file
@ -0,0 +1,56 @@
|
||||
//===-- AVRTargetMachine.h - Define TargetMachine for AVR -------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file declares the AVR specific subclass of TargetMachine.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_AVR_TARGET_MACHINE_H
|
||||
#define LLVM_AVR_TARGET_MACHINE_H
|
||||
|
||||
#include "AVRConfig.h"
|
||||
|
||||
#include "llvm/IR/DataLayout.h"
|
||||
#include "llvm/Target/TargetMachine.h"
|
||||
|
||||
#include "AVRFrameLowering.h"
|
||||
#include "AVRISelLowering.h"
|
||||
#include "AVRInstrInfo.h"
|
||||
#include "AVRSelectionDAGInfo.h"
|
||||
#include "AVRSubtarget.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
/**
|
||||
* A generic AVR implementation.
|
||||
*/
|
||||
class AVRTargetMachine : public LLVMTargetMachine {
|
||||
public:
|
||||
AVRTargetMachine(const Target &T, const Triple &TT, StringRef CPU,
|
||||
StringRef FS, const TargetOptions &Options, Reloc::Model RM,
|
||||
CodeModel::Model CM, CodeGenOpt::Level OL);
|
||||
|
||||
const AVRSubtarget *getSubtargetImpl() const;
|
||||
const AVRSubtarget *getSubtargetImpl(const Function &) const override;
|
||||
|
||||
TargetLoweringObjectFile *getObjFileLowering() const override {
|
||||
return this->TLOF.get();
|
||||
}
|
||||
|
||||
// Pass Pipeline Configuration.
|
||||
TargetPassConfig *createPassConfig(PassManagerBase &PM) override;
|
||||
|
||||
private:
|
||||
std::unique_ptr<TargetLoweringObjectFile> TLOF;
|
||||
AVRSubtarget SubTarget;
|
||||
};
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_AVR_TARGET_MACHINE_H
|
@ -3,11 +3,15 @@ set(LLVM_TARGET_DEFINITIONS AVR.td)
|
||||
tablegen(LLVM AVRGenRegisterInfo.inc -gen-register-info)
|
||||
tablegen(LLVM AVRGenInstrInfo.inc -gen-instr-info)
|
||||
tablegen(LLVM AVRGenCallingConv.inc -gen-callingconv)
|
||||
tablegen(LLVM AVRGenSubtargetInfo.inc -gen-subtarget)
|
||||
add_public_tablegen_target(AVRCommonTableGen)
|
||||
|
||||
add_llvm_target(AVRCodeGen
|
||||
AVRTargetMachine.cpp
|
||||
AVRTargetObjectFile.cpp
|
||||
AVRSubtarget.cpp
|
||||
AVRInstrInfo.cpp
|
||||
AVRRegisterInfo.cpp
|
||||
)
|
||||
|
||||
add_dependencies(LLVMAVRCodeGen intrinsics_gen)
|
||||
|
65
lib/Target/AVR/MCTargetDesc/AVRMCTargetDesc.h
Normal file
65
lib/Target/AVR/MCTargetDesc/AVRMCTargetDesc.h
Normal file
@ -0,0 +1,65 @@
|
||||
//===-- AVRMCTargetDesc.h - AVR Target Descriptions -------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file provides AVR specific target descriptions.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_AVR_MCTARGET_DESC_H
|
||||
#define LLVM_AVR_MCTARGET_DESC_H
|
||||
|
||||
#include "AVRConfig.h"
|
||||
|
||||
#include "llvm/Support/DataTypes.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class MCAsmBackend;
|
||||
class MCCodeEmitter;
|
||||
class MCContext;
|
||||
class MCInstrInfo;
|
||||
class MCObjectWriter;
|
||||
class MCRegisterInfo;
|
||||
class StringRef;
|
||||
class Target;
|
||||
class Triple;
|
||||
class raw_pwrite_stream;
|
||||
|
||||
extern Target TheAVRTarget;
|
||||
|
||||
/**
|
||||
* Creates a machine code emitter for AVR.
|
||||
*/
|
||||
MCCodeEmitter *createAVRMCCodeEmitter(const MCInstrInfo &MCII,
|
||||
const MCRegisterInfo &MRI,
|
||||
MCContext &Ctx);
|
||||
|
||||
/**
|
||||
* Creates an assembly backend for AVR.
|
||||
*/
|
||||
MCAsmBackend *createAVRAsmBackend(const Target &T, const MCRegisterInfo &MRI,
|
||||
const Triple &TT, StringRef CPU);
|
||||
|
||||
/**
|
||||
* Creates an ELF object writer for AVR.
|
||||
*/
|
||||
MCObjectWriter *createAVRELFObjectWriter(raw_pwrite_stream &OS, uint8_t OSABI);
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#define GET_REGINFO_ENUM
|
||||
#include "AVRGenRegisterInfo.inc"
|
||||
|
||||
#define GET_INSTRINFO_ENUM
|
||||
#include "AVRGenInstrInfo.inc"
|
||||
|
||||
#define GET_SUBTARGETINFO_ENUM
|
||||
#include "AVRGenSubtargetInfo.inc"
|
||||
|
||||
#endif // LLVM_AVR_MCTARGET_DESC_H
|
Loading…
Reference in New Issue
Block a user