Index: lib/Target/NDS32/CMakeLists.txt =================================================================== --- lib/Target/NDS32/CMakeLists.txt +++ lib/Target/NDS32/CMakeLists.txt @@ -15,6 +15,7 @@ NDS32RegisterInfo.cpp NDS32InstrInfo.cpp NDS32ISelDAGToDAG.cpp + NDS32ISelLowering.cpp ) add_subdirectory(TargetInfo) Index: lib/Target/NDS32/MCTargetDesc/NDS32BaseInfo.h =================================================================== --- /dev/null +++ lib/Target/NDS32/MCTargetDesc/NDS32BaseInfo.h @@ -0,0 +1,57 @@ +//===-- NDS32BaseInfo.h - Top level definitions for NDS32 MC ----*- 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 small standalone helper functions and enum definitions for +// the NDS32 target useful for the compiler back-end and the MC libraries. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_LIB_TARGET_NDS32_MCTARGETDESC_NDS32BASEINFO_H +#define LLVM_LIB_TARGET_NDS32_MCTARGETDESC_NDS32BASEINFO_H + +#include "NDS32MCTargetDesc.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/Support/DataTypes.h" +#include "llvm/Support/ErrorHandling.h" + +namespace llvm { + +/// NDS32II - This namespace holds all of the target specific flags that +/// instruction info tracks. +/// +namespace NDS32II { + /// Target Operand Flag enum. + enum TOF { + //===------------------------------------------------------------------===// + // NDS32 Specific MachineOperand flags. + MO_NO_FLAG, + + /// MO_ABS_HI/LO - Represents the hi or low part of an absolute symbol + /// address. + MO_HI20, + MO_LO12, + + }; +} + +/// isNDS32LowRegister - Returns true if the register is a low register (r0-r7). +/// +static inline bool isNDS32LowRegister(unsigned Reg) { + using namespace NDS32; + switch (Reg) { + case R0: case R1: case R2: case R3: + case R4: case R5: case R6: case R7: + return true; + default: + return false; + } +} + +} + +#endif Index: lib/Target/NDS32/NDS32ISelLowering.h =================================================================== --- /dev/null +++ lib/Target/NDS32/NDS32ISelLowering.h @@ -0,0 +1,118 @@ +//===-- NDS32ISelLowering.h - NDS32 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 NDS32 uses to lower LLVM code into a +// selection DAG. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_NDS32_NDS32ISELLOWERING_H +#define LLVM_LIB_TARGET_NDS32_NDS32ISELLOWERING_H + +#include "NDS32.h" +#include "llvm/CodeGen/SelectionDAG.h" +#include "llvm/Target/TargetLowering.h" +#include "MCTargetDesc/NDS32BaseInfo.h" + +namespace llvm { + namespace NDS32ISD { + enum NodeType : unsigned { + FIRST_NUMBER = ISD::BUILTIN_OP_END, + + // Get the Higher 20 bits from a 32-bit immediate/symbol + Hi20, + + // Get the Lower 12 bits from a 32-bit immediate/symbol + Lo12, + + /// Function return. Operand 0 is the chain operand. + RET, + + /// Same as RET, but used for returning from ISRs. + IRET, + + // Pseudo-instruction representing a memory copy using lmw/smw + // instructions. + MEMCPY, + + /// CALL - These operations represent an abstract call + /// instruction, which includes a bunch of information. + CALL, + + /// Wrapper - A wrapper node for TargetConstantPool, TargetExternalSymbol, + /// and TargetGlobalAddress. + Wrapper, + + /// SDIVREM, UDIVREM - Multiple output division instructions. + SDIVREM, UDIVREM + }; + } + + class NDS32Subtarget; + class NDS32TargetLowering : public TargetLowering { + public: + explicit NDS32TargetLowering(const TargetMachine &TM, + const NDS32Subtarget &STI); + + MVT getScalarShiftAmountTy(const DataLayout &, EVT) const override { + return MVT::i32; + } + + /// LowerOperation - Provide custom lowering hooks for some operations. + SDValue LowerOperation(SDValue Op, SelectionDAG &DAG) const override; + + /// getTargetNodeName - This method returns the name of a target specific + /// DAG node. + const char *getTargetNodeName(unsigned Opcode) const override; + + TargetLowering::ConstraintType + getConstraintType(StringRef Constraint) const override; + std::pair + getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI, + StringRef Constraint, MVT VT) const override; + + /// isLegalAddressingMode - Return 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; + + bool isOffsetFoldingLegal(const GlobalAddressSDNode *GA) const override; + + /// If a physical register, this returns the register that receives the + /// exception address on entry to an EH pad. + unsigned + getExceptionPointerRegister(const Constant *PersonalityFn) const override { + return NDS32::R0; + } + + /// If a physical register, this returns the register that receives the + /// exception typeid on entry to a landing pad. + unsigned + getExceptionSelectorRegister(const Constant *PersonalityFn) const override { + return NDS32::R1; + } + + + private: + /// Subtarget - Keep a pointer to the NDS32Subtarget around so that we can + /// make the right decision when generating code for different targets. + const NDS32Subtarget *Subtarget; + + SDValue + LowerFormalArguments(SDValue Chain, CallingConv::ID CallConv, bool isVarArg, + const SmallVectorImpl &Ins, + const SDLoc &dl, SelectionDAG &DAG, + SmallVectorImpl &InVals) const override; + SDValue + LowerCall(TargetLowering::CallLoweringInfo &CLI, + SmallVectorImpl &InVals) const override; + }; +} // namespace llvm + +#endif Index: lib/Target/NDS32/NDS32ISelLowering.cpp =================================================================== --- /dev/null +++ lib/Target/NDS32/NDS32ISelLowering.cpp @@ -0,0 +1,288 @@ +//===-- NDS32ISelLowering.cpp - NDS32 DAG Lowering Implementation --------===// +// +// 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 NDS32TargetLowering class. +// +//===----------------------------------------------------------------------===// + +#include "NDS32ISelLowering.h" +#include "NDS32.h" +#include "NDS32Subtarget.h" +#include "NDS32TargetMachine.h" +#include "llvm/CodeGen/CallingConvLower.h" +#include "llvm/CodeGen/MachineFrameInfo.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/CodeGen/SelectionDAGISel.h" +#include "llvm/CodeGen/TargetLoweringObjectFileImpl.h" +#include "llvm/CodeGen/ValueTypes.h" +#include "llvm/IR/CallingConv.h" +#include "llvm/IR/DerivedTypes.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/GlobalAlias.h" +#include "llvm/IR/GlobalVariable.h" +#include "llvm/IR/Intrinsics.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" +using namespace llvm; + +#define DEBUG_TYPE "NDS32-lower" + + +NDS32TargetLowering::NDS32TargetLowering(const TargetMachine &TM, + const NDS32Subtarget &STI) + : TargetLowering(TM), Subtarget(&STI) { + + // Set up the register classes. + addRegisterClass(MVT::i32, &NDS32::GPRRegClass); + + // Compute derived properties from the register classes + computeRegisterProperties(STI.getRegisterInfo()); + + // Load extented operations for i1 types must be promoted + for (MVT VT : MVT::integer_valuetypes()) { + setLoadExtAction(ISD::EXTLOAD, VT, MVT::i1, Promote); + setLoadExtAction(ISD::ZEXTLOAD, VT, MVT::i1, Promote); + setLoadExtAction(ISD::SEXTLOAD, VT, MVT::i1, Promote); + } + + // Post increment load/store are legal in NDS32 ISA + setIndexedLoadAction(ISD::POST_INC, MVT::i32, Legal); + setIndexedLoadAction(ISD::POST_INC, MVT::i16, Legal); + setIndexedLoadAction(ISD::POST_INC, MVT::i8, Legal); + setIndexedStoreAction(ISD::POST_INC, MVT::i32, Legal); + setIndexedStoreAction(ISD::POST_INC, MVT::i16, Legal); + setIndexedStoreAction(ISD::POST_INC, MVT::i8, Legal); + + setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i1, Expand); + + setOperationAction(ISD::BR_CC, MVT::i32, Expand); + setOperationAction(ISD::SELECT_CC, MVT::i32, Expand); + + setOperationAction(ISD::ADDE, MVT::i32, Expand); + setOperationAction(ISD::ADDC, MVT::i32, Expand); + setOperationAction(ISD::SUBE, MVT::i32, Expand); + setOperationAction(ISD::SUBC, MVT::i32, Expand); + + // Expand multiplication operations + setOperationAction(ISD::MULHU, MVT::i32, Expand); + setOperationAction(ISD::MULHS, MVT::i32, Expand); + setOperationAction(ISD::UMUL_LOHI, MVT::i32, Expand); + setOperationAction(ISD::SMUL_LOHI, MVT::i32, Expand); + + // Expand division operations + setOperationAction(ISD::UREM, MVT::i32, Expand); + setOperationAction(ISD::SREM, MVT::i32, Expand); + setOperationAction(ISD::UDIVREM, MVT::i32, Custom); + setOperationAction(ISD::SDIVREM, MVT::i32, Custom); + setOperationAction(ISD::UDIV, MVT::i32, Expand); + setOperationAction(ISD::SDIV, MVT::i32, Expand); + + setOperationAction(ISD::BR_JT, MVT::Other, Expand); + setOperationAction(ISD::JumpTable, MVT::i32, Custom); + setOperationAction(ISD::GlobalAddress, MVT::i32, Custom); + setOperationAction(ISD::BlockAddress, MVT::i32, Custom); + + setOperationAction(ISD::VASTART, MVT::Other, Custom); + setOperationAction(ISD::VAARG, MVT::Other, Expand); + setOperationAction(ISD::VACOPY, MVT::Other, Expand); + setOperationAction(ISD::VAEND, MVT::Other, Expand); + + setOperationAction(ISD::CTTZ, MVT::i32, Expand); + setOperationAction(ISD::CTTZ, MVT::i64, Expand); + setOperationAction(ISD::ROTL, MVT::i32, Expand); + setOperationAction(ISD::ROTL, MVT::i64, Expand); + setOperationAction(ISD::DYNAMIC_STACKALLOC, MVT::i32, Expand); + setOperationAction(ISD::DYNAMIC_STACKALLOC, MVT::i64, Expand); + + setOperationAction(ISD::STACKSAVE, MVT::Other, Expand); + setOperationAction(ISD::STACKRESTORE, MVT::Other, Expand); + + setOperationAction(ISD::SHL_PARTS, MVT::i32, Expand); + setOperationAction(ISD::SRA_PARTS, MVT::i32, Expand); + setOperationAction(ISD::SRL_PARTS, MVT::i32, Expand); + + setOperationAction(ISD::BSWAP, MVT::i32, Expand); + setOperationAction(ISD::BSWAP, MVT::i64, Expand); + + setOperationAction(ISD::CTPOP, MVT::i32, Expand); + + // Set them all for expansion, which will force libcalls. + setOperationAction(ISD::ATOMIC_CMP_SWAP, MVT::i32, Expand); + setOperationAction(ISD::ATOMIC_SWAP, MVT::i32, Expand); + setOperationAction(ISD::ATOMIC_LOAD_ADD, MVT::i32, Expand); + setOperationAction(ISD::ATOMIC_LOAD_SUB, MVT::i32, Expand); + setOperationAction(ISD::ATOMIC_LOAD_AND, MVT::i32, Expand); + setOperationAction(ISD::ATOMIC_LOAD_OR, MVT::i32, Expand); + setOperationAction(ISD::ATOMIC_LOAD_XOR, MVT::i32, Expand); + setOperationAction(ISD::ATOMIC_LOAD_NAND, MVT::i32, Expand); + setOperationAction(ISD::ATOMIC_LOAD_MIN, MVT::i32, Expand); + setOperationAction(ISD::ATOMIC_LOAD_MAX, MVT::i32, Expand); + setOperationAction(ISD::ATOMIC_LOAD_UMIN, MVT::i32, Expand); + setOperationAction(ISD::ATOMIC_LOAD_UMAX, MVT::i32, Expand); + + // Provide all sorts of operation actions + setStackPointerRegisterToSaveRestore(NDS32::SP); + setBooleanContents(ZeroOrOneBooleanContent); + setBooleanVectorContents(ZeroOrOneBooleanContent); + + setMinFunctionAlignment(2); + setPrefFunctionAlignment(4); +} + +SDValue NDS32TargetLowering::LowerOperation(SDValue Op, + SelectionDAG &DAG) const { + switch (Op.getOpcode()) { + default: + llvm_unreachable("unimplemented operand"); + } +} + +//===----------------------------------------------------------------------===// +// NDS32 Addressing Mode Support +//===----------------------------------------------------------------------===// + +/// isLegalAddressImmediate - Return true if the integer value can be used +/// as the offset of the target addressing mode for load / store of the +/// given type. +static bool isLegalAddressImmediate(int64_t V, EVT VT, + const NDS32Subtarget *Subtarget) { + if (V == 0) + return true; + + if (!VT.isSimple()) + return false; + + if (V < 0) + V = - V; + + switch (VT.getSimpleVT().SimpleTy) { + default: return false; + case MVT::i8: + // imm15s + return V == (V & ((1LL << 15) - 1)); + case MVT::i16: + // imm15s << 1 + return (V == (V & ((1LL << 16) - 1))) && (V % 2 == 0); + case MVT::i32: + // imm15s << 2 + return (V == (V & ((1LL << 17) - 1))) && (V % 4 == 0); + case MVT::f32: + case MVT::f64: + return false; + } +} + +/// isLegalAddressingMode - Return true if the addressing mode represented +/// by AM is legal for this target, for a load/store of the specified type. +bool NDS32TargetLowering::isLegalAddressingMode(const DataLayout &DL, + const AddrMode &AM, Type *Ty, + unsigned AS) const { + EVT VT = getValueType(DL, Ty, true); + if (!isLegalAddressImmediate(AM.BaseOffs, VT, Subtarget)) + return false; + + // Can never fold addr of global into load/store. + if (AM.BaseGV) + return false; + + switch (AM.Scale) { + case 0: // no scale reg, must be "r+i" or "r", or "i". + break; + case 1: + if (AM.HasBaseReg && AM.BaseOffs) // "r+r+i" is not allowed. + return false; + // Otherwise we have r+r or r+i. + break; + default: + return false; + } + return true; +} + +// Always return false to avoid SelectionDAG::FoldSymbolOffset() +// folding offset into symbol which the NDS32 target not support. +bool +NDS32TargetLowering::isOffsetFoldingLegal(const GlobalAddressSDNode *GA) const { + return false; +} + + +//===----------------------------------------------------------------------===// +// NDS32 Inline Assembly Support +//===----------------------------------------------------------------------===// + +/// getConstraintType - Given a constraint letter, return the type of +/// constraint it is for this target. +TargetLowering::ConstraintType +NDS32TargetLowering::getConstraintType(StringRef Constraint) const { + if (Constraint.size() == 1) { + switch (Constraint[0]) { + case 'r': + return C_RegisterClass; + default: + break; + } + } + return TargetLowering::getConstraintType(Constraint); +} + +std::pair +NDS32TargetLowering::getRegForInlineAsmConstraint( + const TargetRegisterInfo *TRI, StringRef Constraint, MVT VT) const { + if (Constraint.size() == 1) { + // GCC Constraint Letters + switch (Constraint[0]) { + default: break; + case 'r': // GENERAL_REGS + return std::make_pair(0U, &NDS32::GPRRegClass); + } + } + + return TargetLowering::getRegForInlineAsmConstraint(TRI, Constraint, VT); +} + +//===----------------------------------------------------------------------===// +// Calling Convention Implementation +//===----------------------------------------------------------------------===// + +// LowerFormalArguments - Specify how callee get arguments +SDValue NDS32TargetLowering::LowerFormalArguments( + SDValue Chain, CallingConv::ID CallConv, bool IsVarArg, + const SmallVectorImpl &Ins, const SDLoc &DL, + SelectionDAG &DAG, SmallVectorImpl &InVals) const { + + return Chain; +} + +// LowerCall - Specify how caller passing arguments +SDValue +NDS32TargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI, + SmallVectorImpl &InVals) const { + SDValue Chain; + return Chain; +} + +const char *NDS32TargetLowering::getTargetNodeName(unsigned Opcode) const { + switch ((NDS32ISD::NodeType)Opcode) { + case NDS32ISD::FIRST_NUMBER: break; + case NDS32ISD::CALL: return "NDS32ISD::CALL"; + case NDS32ISD::RET: return "NDS32ISD::RET"; + case NDS32ISD::IRET: return "NDS32ISD::IRET"; + case NDS32ISD::Hi20: return "NDS32ISD::Hi20"; + case NDS32ISD::Lo12: return "NDS32ISD::Lo12"; + case NDS32ISD::MEMCPY: return "NDS32ISD::MEMCPY"; + default: + break; + } + return nullptr; +} Index: lib/Target/NDS32/NDS32Subtarget.h =================================================================== --- lib/Target/NDS32/NDS32Subtarget.h +++ lib/Target/NDS32/NDS32Subtarget.h @@ -15,8 +15,10 @@ #define LLVM_LIB_TARGET_NDS32_NDS32SUBTARGET_H #include "NDS32FrameLowering.h" +#include "NDS32ISelLowering.h" #include "NDS32InstrInfo.h" #include "NDS32RegisterInfo.h" +#include "llvm/CodeGen/SelectionDAGTargetInfo.h" #include "llvm/IR/DataLayout.h" #include "llvm/Target/TargetSubtargetInfo.h" #include @@ -31,6 +33,8 @@ virtual void anchor(); NDS32FrameLowering FrameLowering; std::unique_ptr InstrInfo; + NDS32TargetLowering TLInfo; + const SelectionDAGTargetInfo TSInfo; public: /// This constructor initializes the data members to match that @@ -52,6 +56,12 @@ const NDS32RegisterInfo *getRegisterInfo() const override { return &InstrInfo->getRegisterInfo(); } + const NDS32TargetLowering *getTargetLowering() const override { + return &TLInfo; + } + const SelectionDAGTargetInfo *getSelectionDAGInfo() const override { + return &TSInfo; + } protected: /// No16Bit - Not generate 16-Bit ISA Index: lib/Target/NDS32/NDS32Subtarget.cpp =================================================================== --- lib/Target/NDS32/NDS32Subtarget.cpp +++ lib/Target/NDS32/NDS32Subtarget.cpp @@ -34,6 +34,7 @@ NDS32Subtarget::NDS32Subtarget(const Triple &TT, const std::string &CPU, const std::string &FS, const TargetMachine &TM) : NDS32GenSubtargetInfo(TT, CPU, FS), FrameLowering(), - InstrInfo(NDS32InstrInfo::create(initializeSubtargetDependencies(CPU, FS))) { + InstrInfo(NDS32InstrInfo::create(initializeSubtargetDependencies(CPU, FS))), + TLInfo(TM, *this) { ParseSubtargetFeatures(CPU, FS); }