Index: lib/Target/AVR/AVRFrameLowering.h =================================================================== --- /dev/null +++ lib/Target/AVR/AVRFrameLowering.h @@ -0,0 +1,54 @@ +//===-- 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: // TargetFrameLowering + 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 &CSI, + const TargetRegisterInfo *TRI) const override; + bool + restoreCalleeSavedRegisters(MachineBasicBlock &MBB, + MachineBasicBlock::iterator MI, + const std::vector &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 Index: lib/Target/AVR/AVRISelLowering.h =================================================================== --- /dev/null +++ lib/Target/AVR/AVRISelLowering.h @@ -0,0 +1,185 @@ +//===-- 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; + + /*! + * Provide custom lowering hooks for some operations. + */ + SDValue LowerOperation(SDValue Op, SelectionDAG &DAG) const override; + + /*! + * Replace the results of node with an illegal result + * type with new values built out of custom code. + */ + void ReplaceNodeResults(SDNode *N, SmallVectorImpl &Results, + SelectionDAG &DAG) const override; + + /*! + * Returns true if the addressing mode represented + * by AM is legal for this target, for a load/store + * of the specified type. + */ + bool isLegalAddressingMode(const DataLayout &DL, const AddrMode &AM, Type *Ty, + unsigned AS) const override; + + /*! + * Returns true by value, base pointer and + * offset pointer and addressing mode by reference if the node's address + * can be legally represented as pre-indexed load / store address. + */ + bool getPreIndexedAddressParts(SDNode *N, SDValue &Base, SDValue &Offset, + ISD::MemIndexedMode &AM, + SelectionDAG &DAG) const override; + + /*! + * Returns true by value, base pointer and + * offset pointer and addressing mode by reference if this node can be + * combined with a load / store to form a post-indexed load / store. + */ + bool getPostIndexedAddressParts(SDNode *N, SDNode *Op, SDValue &Base, + SDValue &Offset, ISD::MemIndexedMode &AM, + SelectionDAG &DAG) const override; + + /*! + * Return true if folding a constant offset + * with the given GlobalAddress is legal. It is frequently not legal in + * PIC relocation models. + */ + bool isOffsetFoldingLegal(const GlobalAddressSDNode *GA) const override; + + MachineBasicBlock * + EmitInstrWithCustomInserter(MachineInstr *MI, + MachineBasicBlock *MBB) const override; + + /// Inline Asm support. + /// Implementation of TargetLowering hooks. + ConstraintType getConstraintType(StringRef Constraint) const override; + + ConstraintWeight + getSingleConstraintMatchWeight(AsmOperandInfo &info, + const char *constraint) const override; + + std::pair + 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 &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 &Outs, + const SmallVectorImpl &OutVals, SDLoc dl, + SelectionDAG &DAG) const override; + SDValue LowerFormalArguments(SDValue Chain, CallingConv::ID CallConv, + bool isVarArg, + const SmallVectorImpl &Ins, + SDLoc dl, SelectionDAG &DAG, + SmallVectorImpl &InVals) const override; + SDValue LowerCall(TargetLowering::CallLoweringInfo &CLI, + SmallVectorImpl &InVals) const override; + SDValue LowerCallResult(SDValue Chain, SDValue InFlag, + CallingConv::ID CallConv, bool isVarArg, + const SmallVectorImpl &Ins, SDLoc dl, + SelectionDAG &DAG, + SmallVectorImpl &InVals) const; + +private: // custom inserters + MachineBasicBlock *insertShift(MachineInstr *MI, MachineBasicBlock *BB) const; + MachineBasicBlock *insertMul(MachineInstr *MI, MachineBasicBlock *BB) const; +}; + +} // end namespace llvm + +#endif // LLVM_AVR_ISEL_LOWERING_H Index: lib/Target/AVR/AVRInstrInfo.h =================================================================== --- /dev/null +++ lib/Target/AVR/AVRInstrInfo.h @@ -0,0 +1,117 @@ +//===-- 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" + +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(); + /*! + * TargetInstrInfo is a superset of MRegister info. + * As such, whenever a client has an instance of instruction info, it should + * always be able to get register info as well (through this method). + */ + 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 &Cond, + bool AllowModify = false) const override; + unsigned InsertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB, + MachineBasicBlock *FBB, ArrayRef Cond, + DebugLoc DL) const override; + unsigned RemoveBranch(MachineBasicBlock &MBB) const override; + bool + ReverseBranchCondition(SmallVectorImpl &Cond) const override; + +private: + const AVRRegisterInfo RI; +}; + +} // end namespace llvm + +#endif // LLVM_AVR_INSTR_INFO_H Index: lib/Target/AVR/AVRInstrInfo.cpp =================================================================== --- /dev/null +++ lib/Target/AVR/AVRInstrInfo.cpp @@ -0,0 +1,482 @@ +//===-- 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 { + +// External variable defined inside the register allocator to indicate if +// we should reserve REG_Y if it is going to be used as the frame pointer. +extern bool RA_ReserveREG_Y; +// External variable defined inside the register allocator to indicate if +// the register allocator is executing code inside the spiller. +extern bool RA_InSpillerCode; + +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 + // case AVR::LDDWRdPtrQ: + { + 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(); + + if (RA_InSpillerCode && !AFI->getHasSpills()) { + AFI->setHasSpills(true); + RA_ReserveREG_Y = 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 (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 &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 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()) { + // Unconditional branch? + 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 &Cond) const { + assert(Cond.size() == 1 && "Invalid AVR branch condition!"); + + AVRCC::CondCodes CC = static_cast(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 = (const AVRTargetMachine &)MF->getTarget(); + const TargetInstrInfo &TII = *TM.getSubtargetImpl()->getInstrInfo(); + return TII.getInlineAsmLength(MI->getOperand(0).getSymbolName(), + *TM.getMCAsmInfo()); + } + } +} + +} // end of namespace llvm Index: lib/Target/AVR/AVRRegisterInfo.h =================================================================== --- /dev/null +++ lib/Target/AVR/AVRRegisterInfo.h @@ -0,0 +1,57 @@ +//===-- 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 Index: lib/Target/AVR/AVRRegisterInfo.cpp =================================================================== --- /dev/null +++ lib/Target/AVR/AVRRegisterInfo.cpp @@ -0,0 +1,252 @@ +//===-- 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 = (const AVRTargetMachine &)MF.getTarget(); + const TargetFrameLowering *TFI = TM.getSubtargetImpl()->getFrameLowering(); + + Reserved.set(AVR::R0); + Reserved.set(AVR::R1); + Reserved.set(AVR::R1R0); + + Reserved.set(AVR::SPL); + Reserved.set(AVR::SPH); + Reserved.set(AVR::SP); + + 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; + } + // Fallthru + } + 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 Index: lib/Target/AVR/AVRSubtarget.h =================================================================== --- /dev/null +++ lib/Target/AVR/AVRSubtarget.h @@ -0,0 +1,132 @@ +//===-- 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 this->m_hasSRAM; } + bool hasJMPCALL() const { return this->m_hasJMPCALL; } + bool hasIJMPCALL() const { return this->m_hasIJMPCALL; } + bool hasEIJMPCALL() const { return this->m_hasEIJMPCALL; } + bool hasADDSUBIW() const { return this->m_hasADDSUBIW; } + bool hasSmallStack() const { return m_hasSmallStack; } + bool hasMOVW() const { return this->m_hasMOVW; } + bool hasLPM() const { return this->m_hasLPM; } + bool hasLPMX() const { return this->m_hasLPMX; } + bool hasELPM() const { return this->m_hasELPM; } + bool hasELPMX() const { return this->m_hasELPMX; } + bool hasSPM() const { return this->m_hasSPM; } + bool hasSPMX() const { return this->m_hasSPMX; } + bool hasDES() const { return this->m_hasDES; } + bool supportsRMW() const { return this->m_supportsRMW; } + bool supportsMultiplication() const { return this->m_supportsMultiplication; } + bool hasBREAK() const { return this->m_hasBREAK; } + bool hasTinyEncoding() const { return this->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 this->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 Index: lib/Target/AVR/AVRSubtarget.cpp =================================================================== --- /dev/null +++ lib/Target/AVR/AVRSubtarget.cpp @@ -0,0 +1,46 @@ +//===-- 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(), m_hasJMPCALL(), m_hasIJMPCALL(), m_hasEIJMPCALL(), + m_hasADDSUBIW(), m_hasSmallStack(), m_hasMOVW(), m_hasLPM(), m_hasLPMX(), + m_hasELPM(), m_hasELPMX(), m_hasSPM(), m_hasSPMX(), m_hasDES(), + m_supportsRMW(), m_supportsMultiplication(), m_hasBREAK(), + m_hasTinyEncoding(), ELFArch(), m_FeatureSetDummy() { + // Parse features string. + ParseSubtargetFeatures(CPU, FS); +} + +} // end of namespace llvm Index: lib/Target/AVR/AVRTargetMachine.h =================================================================== --- /dev/null +++ lib/Target/AVR/AVRTargetMachine.h @@ -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 TLOF; + AVRSubtarget SubTarget; +}; + +} // end namespace llvm + +#endif // LLVM_AVR_TARGET_MACHINE_H Index: lib/Target/AVR/AVRTargetMachine.cpp =================================================================== --- lib/Target/AVR/AVRTargetMachine.cpp +++ lib/Target/AVR/AVRTargetMachine.cpp @@ -1,4 +1,114 @@ +//===-- 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 { + +// The default CPU to choose if an empty string is passed. +namespace { +const char *DefaultCPU = "avr2"; + +/// Processes a CPU name. +StringRef GetTargetCPU(StringRef CPU) { + if (CPU.empty() || CPU == "generic") { + return DefaultCPU; + } else { + 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(); + 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(); + } + + 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 X(TheAVRTarget); +} + +const AVRSubtarget *AVRTargetMachine::getSubtargetImpl() const { + return &SubTarget; +} + +const AVRSubtarget *AVRTargetMachine::getSubtargetImpl(const Function &) const { + return &SubTarget; +} + +//===----------------------------------------------------------------------===// +// Pass Pipeline Configuration +//===----------------------------------------------------------------------===// +bool AVRPassConfig::addInstSelector() { + // Install an instruction selector. + addPass(createAVRISelDag(getAVRTargetMachine(), getOptLevel())); + // Create the frame analyzer pass used by the PEI pass. + addPass(createAVRFrameAnalyzerPass()); + + return false; +} + +void AVRPassConfig::addPreRegAlloc() { + // Create the dynalloc SP save/restore pass to handle variable sized allocas. + addPass(createAVRDynAllocaSRPass()); } + +void AVRPassConfig::addPreSched2() { addPass(createAVRExpandPseudoPass()); } + +void AVRPassConfig::addPreEmitPass() { + // Must run branch selection immediately preceding the asm printer. + addPass(createAVRBranchSelectionPass()); +} + +} // end of namespace llvm Index: lib/Target/AVR/CMakeLists.txt =================================================================== --- lib/Target/AVR/CMakeLists.txt +++ lib/Target/AVR/CMakeLists.txt @@ -3,11 +3,15 @@ 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) Index: lib/Target/AVR/MCTargetDesc/AVRMCTargetDesc.h =================================================================== --- /dev/null +++ lib/Target/AVR/MCTargetDesc/AVRMCTargetDesc.h @@ -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 MCCodeEmitter; +class MCAsmBackend; +class MCRegisterInfo; +class MCObjectWriter; +class MCInstrInfo; +class MCContext; +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