Index: lib/Target/NDS32/CMakeLists.txt =================================================================== --- lib/Target/NDS32/CMakeLists.txt +++ lib/Target/NDS32/CMakeLists.txt @@ -4,11 +4,13 @@ tablegen(LLVM NDS32GenInstrInfo.inc -gen-instr-info) tablegen(LLVM NDS32GenCallingConv.inc -gen-callingconv) tablegen(LLVM NDS32GenSubtargetInfo.inc -gen-subtarget) +tablegen(LLVM NDS32GenDAGISel.inc -gen-dag-isel) add_public_tablegen_target(NDS32CommonTableGen) add_llvm_target(NDS32CodeGen + NDS32ISelDAGToDAG.cpp NDS32TargetMachine.cpp ) Index: lib/Target/NDS32/LLVMBuild.txt =================================================================== --- lib/Target/NDS32/LLVMBuild.txt +++ lib/Target/NDS32/LLVMBuild.txt @@ -27,5 +27,5 @@ type = Library name = NDS32CodeGen parent = NDS32 -required_libraries = CodeGen Core NDS32Info NDS32Desc Support Target +required_libraries = CodeGen Core SelectionDAG NDS32Info NDS32Desc Support Target add_to_library_groups = NDS32 Index: lib/Target/NDS32/NDS32.h =================================================================== --- lib/Target/NDS32/NDS32.h +++ lib/Target/NDS32/NDS32.h @@ -21,6 +21,10 @@ namespace llvm { class NDS32TargetMachine; class FunctionPass; + + FunctionPass *createNDS32ISelDag(NDS32TargetMachine &TM, + CodeGenOpt::Level OptLevel); + } // end namespace llvm; #endif Index: lib/Target/NDS32/NDS32ISelDAGToDAG.cpp =================================================================== --- /dev/null +++ lib/Target/NDS32/NDS32ISelDAGToDAG.cpp @@ -0,0 +1,846 @@ +//===-- NDS32ISelDAGToDAG.cpp - A dag to dag inst selector for NDS32 ------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines an instruction selector for the NDS32 target. +// +//===----------------------------------------------------------------------===// + +#include "NDS32.h" +#include "NDS32TargetMachine.h" +#include "llvm/CodeGen/MachineFrameInfo.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/CodeGen/SelectionDAG.h" +#include "llvm/CodeGen/SelectionDAGISel.h" +#include "llvm/IR/CallingConv.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/DerivedTypes.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/Intrinsics.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Target/TargetLowering.h" +using namespace llvm; + +#define DEBUG_TYPE "NDS32-isel" + +namespace { + struct NDS32ISelAddressMode { + enum { + RegBase, + FrameIndexBase + } BaseType; + + struct { // This is really a union, discriminated by BaseType! + SDValue Reg; + int FrameIndex; + } Base; + + int16_t Disp; + const GlobalValue *GV; + const Constant *CP; + const BlockAddress *BlockAddr; + const char *ES; + int JT; + unsigned Align; // CP alignment. + + NDS32ISelAddressMode() + : BaseType(RegBase), Disp(0), GV(nullptr), CP(nullptr), + BlockAddr(nullptr), ES(nullptr), JT(-1), Align(0) { + } + + bool hasSymbolicDisplacement() const { + return GV != nullptr || CP != nullptr || ES != nullptr || JT != -1; + } + + void dump() { + errs() << "NDS32ISelAddressMode " << this << '\n'; + if (BaseType == RegBase && Base.Reg.getNode() != nullptr) { + errs() << "Base.Reg "; + Base.Reg.getNode()->dump(); + } else if (BaseType == FrameIndexBase) { + errs() << " Base.FrameIndex " << Base.FrameIndex << '\n'; + } + errs() << " Disp " << Disp << '\n'; + if (GV) { + errs() << "GV "; + GV->dump(); + } else if (CP) { + errs() << " CP "; + CP->dump(); + errs() << " Align" << Align << '\n'; + } else if (ES) { + errs() << "ES "; + errs() << ES << '\n'; + } else if (JT != -1) + errs() << " JT" << JT << " Align" << Align << '\n'; + } + }; +} + +/// NDS32DAGToDAGISel - NDS32 specific code to select NDS32 machine +/// instructions for SelectionDAG operations. +/// +namespace { + class NDS32DAGToDAGISel : public SelectionDAGISel { + /// 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; + + public: + NDS32DAGToDAGISel(NDS32TargetMachine &TM, CodeGenOpt::Level OptLevel) + : SelectionDAGISel(TM, OptLevel) {} + + bool runOnMachineFunction(MachineFunction &MF) override { + // Reset the subtarget each time through. + Subtarget = &MF.getSubtarget(); + SelectionDAGISel::runOnMachineFunction(MF); + return true; + } + + // Pass Name + StringRef getPassName() const override { + return "NDS32 DAG->DAG Pattern Instruction Selection"; + } + + bool MatchAddress(SDValue N, NDS32ISelAddressMode &AM); + bool MatchWrapper(SDValue N, NDS32ISelAddressMode &AM); + bool MatchAddressBase(SDValue N, NDS32ISelAddressMode &AM); + + bool SelectInlineAsmMemoryOperand(const SDValue &Op, unsigned ConstraintID, + std::vector &OutOps) override; + + bool selectAddrFrameIndex(SDValue Addr, SDValue &Base, + SDValue &Offset) const; + bool selectAddrFrameIndexOffset(SDValue Addr, SDValue &Base, + SDValue &Offset, unsigned OffsetBits, + unsigned ShiftBits) const; + + // Select addressing mode for imm15s word width load/store instruction. + bool SelectAddrImm15sWord(SDValue Addr, SDValue &Base, + SDValue &Offset) const; + // Select addressing mode for imm15s half word width load/store instruction. + bool SelectAddrImm15sHalf(SDValue Addr, SDValue &Base, + SDValue &Offset) const; + // Select addressing mode for imm15s byte width load/store instruction. + bool SelectAddrImm15sByte(SDValue Addr, SDValue &Base, + SDValue &Offset) const; + // Select addressing mode for [Reg] + bool SelectAddrReg(SDValue N, SDValue &Base); + + // Select offset operand as Reg in ([Reg], Reg) POST_INC addressing mode + bool SelectAddrOffsetReg(SDNode *Op, SDValue N, + SDValue &Offset, SDValue &Opc); + // Select addressing mode for imm15s word width load/store POST_INC + // instructions. + bool SelectAddrImm15sWordPostInc(SDNode *Op, SDValue N, + SDValue &Offset, SDValue &Opc) const; + // Select addressing mode for imm15s half width load/store POST_INC + // instructions. + bool SelectAddrImm15sHalfPostInc(SDNode *Op, SDValue N, + SDValue &Offset, SDValue &Opc) const; + // Select addressing mode for imm15s byte width load/store post POST_NIC + // instructions. + bool SelectAddrImm15sBytePostInc(SDNode *Op, SDValue N, + SDValue &Offset, SDValue &Opc) const; + + // Select addressing mode for (reg + reg << imm) + bool SelectLdStRegShift(SDValue N, SDValue &Base, SDValue &OffsetReg, + SDValue &Shift); + + bool SelectAddr16BitInstOffset(SDValue Addr, SDValue &Base, + SDValue &Offset, unsigned OffsetBits, + unsigned ShiftBits) const; + + // Select addressing mode for imm3u byte width load/store instruction. + bool SelectAddrImm3uByte(SDValue Addr, SDValue &Base, + SDValue &Offset) const; + // Select addressing mode for imm3u half word width load/store instruction. + bool SelectAddrImm3uHalf(SDValue Addr, SDValue &Base, + SDValue &Offset) const; + // Select addressing mode for imm3u word width load/store instruction. + bool SelectAddrImm3uWord(SDValue Addr, SDValue &Base, + SDValue &Offset) const; + + // Include the pieces autogenerated from the target description. + #include "NDS32GenDAGISel.inc" + + private: + void Select(SDNode *N) override; + bool tryIndexedLoad(SDNode *Op); + bool tryIndexedStore(SDNode *Op); + + bool SelectAddr(SDValue Addr, SDValue &Base, SDValue &Disp); + + // getImm - Return a target constant with the specified value. + inline SDValue getImm(const SDNode *Node, uint64_t Imm) { + return CurDAG->getTargetConstant(Imm, SDLoc(Node), Node->getValueType(0)); + } + }; +} // end anonymous namespace + +/// createNDS32ISelDag - This pass converts a legalized DAG into a +/// NDS32-specific DAG, ready for instruction scheduling. +/// +FunctionPass *llvm::createNDS32ISelDag(NDS32TargetMachine &TM, + CodeGenOpt::Level OptLevel) { + return new NDS32DAGToDAGISel(TM, OptLevel); +} + +bool NDS32DAGToDAGISel::SelectAddrReg(SDValue N, SDValue &Base) { + Base = N; + return true; +} + +bool NDS32DAGToDAGISel::SelectAddrOffsetReg(SDNode *Op, SDValue N, + SDValue &Offset, SDValue &Opc) { + Offset = N; + return true; +} + +/// Match frameindex +bool NDS32DAGToDAGISel::selectAddrFrameIndex(SDValue Addr, SDValue &Base, + SDValue &Offset) const { + if (FrameIndexSDNode *FIN = dyn_cast(Addr)) { + EVT ValTy = Addr.getValueType(); + + Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), ValTy); + Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), ValTy); + return true; + // Allow addressing mode as TargetGlobalAddress, TargetExternalSymbol + } else if (!CurDAG->isBaseWithConstantOffset(Addr)) { + if (Addr.getOpcode() == NDS32ISD::Wrapper && + Addr.getOperand(0).getOpcode() != ISD::TargetGlobalAddress && + Addr.getOperand(0).getOpcode() != ISD::TargetExternalSymbol) { + Base = Addr.getOperand(0); + } else + Base = Addr; + + Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32); + return true; + } + + // Default split Addr out of addressing mode + // E.g. Reg = SP + 3, load [Reg] + Base = Addr; + Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32); + return true; +} + +/// Match frameindex + offset +bool NDS32DAGToDAGISel::selectAddrFrameIndexOffset(SDValue Addr, SDValue &Base, + SDValue &Offset, + unsigned OffsetBits, + unsigned ShiftBits) const { + if (CurDAG->isBaseWithConstantOffset(Addr)) { + ConstantSDNode *CN = dyn_cast(Addr.getOperand(1)); + + if (isIntN(OffsetBits + ShiftBits, CN->getSExtValue())) { + EVT ValTy = Addr.getValueType(); + + // Return false if the offset not align on (1 << ShiftBits) + if (ShiftBits) + if (CN->getSExtValue() % (1 << ShiftBits) != 0) + return false; + + // If the first operand is a FI, get the TargetFI Node + if (FrameIndexSDNode *FIN = dyn_cast + (Addr.getOperand(0))) + Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), ValTy); + else + Base = Addr.getOperand(0); + + Offset = CurDAG->getTargetConstant(CN->getZExtValue(), SDLoc(Addr), + ValTy); + return true; + } + } + return false; +} +// Used on NDS32 Load/Store word aligned instructions (15-bit offset) +// Range with imm15s << 2 with 4 byte alignment +bool NDS32DAGToDAGISel::SelectAddrImm15sWord(SDValue Addr, SDValue &Base, + SDValue &Offset) const { + if ((Addr.getOpcode() == ISD::ADD + || Addr.getOpcode() == ISD::OR) + && selectAddrFrameIndexOffset(Addr, Base, Offset, 15, 2)) + return true; + + if (selectAddrFrameIndex(Addr, Base, Offset)) + return true; + + return false; +} +// Used on NDS32 Load/Store half word aligned instructions (15-bit offset) +// Range with imm15s << 1 with 2 byte alignment +bool NDS32DAGToDAGISel::SelectAddrImm15sHalf(SDValue Addr, SDValue &Base, + SDValue &Offset) const { + if ((Addr.getOpcode() == ISD::ADD + || Addr.getOpcode() == ISD::OR) + && selectAddrFrameIndexOffset(Addr, Base, Offset, 15, 1)) + return true; + + if (selectAddrFrameIndex(Addr, Base, Offset)) + return true; + + return false; +} + +// Used on NDS32 Load/Store byte aligned instructions (15-bit offset) +// Range with imm15s with byte alignment +bool NDS32DAGToDAGISel::SelectAddrImm15sByte(SDValue Addr, SDValue &Base, + SDValue &Offset) const { + if ((Addr.getOpcode() == ISD::ADD + || Addr.getOpcode() == ISD::OR) + && selectAddrFrameIndexOffset(Addr, Base, Offset, 15, 0)) + return true; + + if (selectAddrFrameIndex(Addr, Base, Offset)) + return true; + + return false; +} + +// Used on NDS32 16 bit Load/Store instruction selection +bool NDS32DAGToDAGISel::SelectAddr16BitInstOffset(SDValue Addr, + SDValue &Base, + SDValue &Offset, + unsigned OffsetBits, + unsigned ShiftBits) const { + if ((Addr.getOpcode() == ISD::ADD + || Addr.getOpcode() == ISD::OR) && + CurDAG->isBaseWithConstantOffset(Addr)) { + ConstantSDNode *CN = dyn_cast(Addr.getOperand(1)); + + if (isUIntN(OffsetBits + ShiftBits, CN->getSExtValue())) { + EVT ValTy = Addr.getValueType(); + + // Return false if the offset not align on (1 << ShiftBits) + if (ShiftBits) + if (CN->getSExtValue() % (1 << ShiftBits) != 0) + return false; + + // 16 bit instruction not allow base as SP or FP. + if (dyn_cast(Addr.getOperand(0))) + return false; + else + Base = Addr.getOperand(0); + + Offset = CurDAG->getTargetConstant(CN->getZExtValue(), SDLoc(Addr), + ValTy); + return true; + } + } + + return false; +} + + +// Used on NDS32 Load/Store byte aligned instructions (3-bit offset) +// Range with imm3u with byte alignment +bool NDS32DAGToDAGISel::SelectAddrImm3uByte(SDValue Addr, SDValue &Base, + SDValue &Offset) const { + if (SelectAddr16BitInstOffset(Addr, Base, Offset, 3, 0)) + return true; + + return false; +} + +// Used on NDS32 Load/Store byte aligned instructions (3-bit offset) +// Range with imm3u with half word alignment +bool NDS32DAGToDAGISel::SelectAddrImm3uHalf(SDValue Addr, SDValue &Base, + SDValue &Offset) const { + if (SelectAddr16BitInstOffset(Addr, Base, Offset, 3, 1)) + return true; + + return false; +} + +// Used on NDS32 Load/Store byte aligned instructions (3-bit offset) +// Range with imm3u with word alignment +bool NDS32DAGToDAGISel::SelectAddrImm3uWord(SDValue Addr, SDValue &Base, + SDValue &Offset) const { + if (SelectAddr16BitInstOffset(Addr, Base, Offset, 3, 2)) + return true; + + return false; +} + + +static bool SelectAddrPostInc (SDNode *Op) { + unsigned Opcode = Op->getOpcode(); + ISD::MemIndexedMode AM = (Opcode == ISD::LOAD) + ? cast(Op)->getAddressingMode() + : cast(Op)->getAddressingMode(); + + return (AM == ISD::POST_INC); +} + +// For selecting post increment load/store word instructions +bool NDS32DAGToDAGISel::SelectAddrImm15sWordPostInc(SDNode *Op, + SDValue N, + SDValue &Offset, + SDValue &Opc) const { + ConstantSDNode *CN = dyn_cast(N); + int Val = CN->getSExtValue(); + + if (SelectAddrPostInc (Op) + && isIntN(17, Val) + && ((Val % 4) == 0)) { + Offset = CurDAG->getTargetConstant(Val, SDLoc(Op), MVT::i32); + Opc = Offset; + return true; + } + + Offset = N; + Opc = Offset; + return false; +} + +// For selecting post increment load/store word instructions +bool NDS32DAGToDAGISel::SelectAddrImm15sHalfPostInc(SDNode *Op, + SDValue N, + SDValue &Offset, + SDValue &Opc) const { + ConstantSDNode *CN = dyn_cast(N); + int Val = CN->getSExtValue(); + if (SelectAddrPostInc (Op) + && isIntN(16, Val) + && ((Val % 2) == 0)) { + Offset = CurDAG->getTargetConstant(Val, SDLoc(Op), MVT::i32); + Opc = Offset; + return true; + } + + Offset = N; + Opc = Offset; + return false; +} + +// For selecting post increment load/store word instructions +bool NDS32DAGToDAGISel::SelectAddrImm15sBytePostInc(SDNode *Op, + SDValue N, + SDValue &Offset, + SDValue &Opc) const { + ConstantSDNode *CN = dyn_cast(N); + int Val = CN->getSExtValue(); + + if (SelectAddrPostInc (Op) + && isIntN(15, Val)) { + Offset = CurDAG->getTargetConstant(Val, SDLoc(Op), MVT::i32); + Opc = Offset; + return true; + } + + Offset = N; + Opc = Offset; + return false; +} + +bool NDS32DAGToDAGISel::SelectLdStRegShift(SDValue N, SDValue &Base, + SDValue &OffsetReg, + SDValue &Shift) { + if (N.getOpcode() != ISD::ADD && + // ISD::OR that is equivalent to an ISD::ADD. + !CurDAG->isBaseWithConstantOffset(N)) + return false; + + unsigned ShAmt = 0; + + if (N.getOperand(1).getOpcode() == ISD::SHL) { + Base = N.getOperand(0); + + // Check to see if the RHS of the shift is a constant, if not, we can't fold + // it. + if (ConstantSDNode *Sh = + dyn_cast(N.getOperand(1).getOperand(1))) { + ShAmt = Sh->getZExtValue(); + if (ShAmt < 4) { + OffsetReg = N.getOperand(1).getOperand(0); + Shift = CurDAG->getTargetConstant(ShAmt, SDLoc(N), MVT::i32); + return true; + } else { + return false; + } + } + // Try matching (R shl C) + (R). + } else if (N.getOpcode() != ISD::SUB && (N.getOperand(0).hasOneUse())) { + if (N.getOperand(0).getOpcode() == ISD::SHL) { + Base = N.getOperand(1); + // Check to see if the RHS of the shift is a constant, if not, we can't + // fold it. + if (ConstantSDNode *Sh = + dyn_cast(N.getOperand(0).getOperand(1))) { + ShAmt = Sh->getZExtValue(); + if (ShAmt < 4) { + OffsetReg = N.getOperand(0).getOperand(0); + Shift = CurDAG->getTargetConstant(ShAmt, SDLoc(N), MVT::i32); + return true; + } else { + ShAmt = 0; + return false; + } + } + } + } + + // return [r + r] addressing mode + Base = N.getOperand(1); + OffsetReg = N.getOperand(0); + Shift = CurDAG->getTargetConstant(0, SDLoc(N), MVT::i32); + + return true; +} + + +/// MatchWrapper - Try to match NDS32ISD::Wrapper node into an addressing mode. +/// These wrap things that will resolve down into a symbol reference. If no +/// match is possible, this returns true, otherwise it returns false. +bool NDS32DAGToDAGISel::MatchWrapper(SDValue N, NDS32ISelAddressMode &AM) { + // If the addressing mode already has a symbol as the displacement, we can + // never match another symbol. + if (AM.hasSymbolicDisplacement()) + return true; + + SDValue N0 = N.getOperand(0); + + if (GlobalAddressSDNode *G = dyn_cast(N0)) { + AM.GV = G->getGlobal(); + AM.Disp += G->getOffset(); + //AM.SymbolFlags = G->getTargetFlags(); + } else if (ConstantPoolSDNode *CP = dyn_cast(N0)) { + AM.CP = CP->getConstVal(); + AM.Align = CP->getAlignment(); + AM.Disp += CP->getOffset(); + //AM.SymbolFlags = CP->getTargetFlags(); + } else if (ExternalSymbolSDNode *S = dyn_cast(N0)) { + AM.ES = S->getSymbol(); + //AM.SymbolFlags = S->getTargetFlags(); + } else if (JumpTableSDNode *J = dyn_cast(N0)) { + AM.JT = J->getIndex(); + //AM.SymbolFlags = J->getTargetFlags(); + } else { + AM.BlockAddr = cast(N0)->getBlockAddress(); + //AM.SymbolFlags = cast(N0)->getTargetFlags(); + } + return false; +} + +/// MatchAddressBase - Helper for MatchAddress. Add the specified node to the +/// specified addressing mode without any further recursion. +bool NDS32DAGToDAGISel::MatchAddressBase(SDValue N, NDS32ISelAddressMode &AM) { + // Is the base register already occupied? + if (AM.BaseType != NDS32ISelAddressMode::RegBase || AM.Base.Reg.getNode()) { + // If so, we cannot select it. + return true; + } + + // Default, generate it as a register. + AM.BaseType = NDS32ISelAddressMode::RegBase; + AM.Base.Reg = N; + return false; +} + +bool NDS32DAGToDAGISel::MatchAddress(SDValue N, NDS32ISelAddressMode &AM) { + DEBUG(errs() << "MatchAddress: "; AM.dump()); + + switch (N.getOpcode()) { + default: break; + case ISD::Constant: { + uint64_t Val = cast(N)->getSExtValue(); + AM.Disp += Val; + return false; + } + + case NDS32ISD::Wrapper: + if (!MatchWrapper(N, AM)) + return false; + break; + + case ISD::FrameIndex: + if (AM.BaseType == NDS32ISelAddressMode::RegBase + && AM.Base.Reg.getNode() == nullptr) { + AM.BaseType = NDS32ISelAddressMode::FrameIndexBase; + AM.Base.FrameIndex = cast(N)->getIndex(); + return false; + } + break; + + case ISD::ADD: { + NDS32ISelAddressMode Backup = AM; + if (!MatchAddress(N.getNode()->getOperand(0), AM) && + !MatchAddress(N.getNode()->getOperand(1), AM)) + return false; + AM = Backup; + if (!MatchAddress(N.getNode()->getOperand(1), AM) && + !MatchAddress(N.getNode()->getOperand(0), AM)) + return false; + AM = Backup; + + break; + } + + case ISD::OR: + // Handle "X | C" as "X + C" iff X is known to have C bits clear. + if (ConstantSDNode *CN = dyn_cast(N.getOperand(1))) { + NDS32ISelAddressMode Backup = AM; + uint64_t Offset = CN->getSExtValue(); + // Start with the LHS as an addr mode. + if (!MatchAddress(N.getOperand(0), AM) && + // Address could not have picked a GV address for the displacement. + AM.GV == nullptr && + // Check to see if the LHS & C is zero. + CurDAG->MaskedValueIsZero(N.getOperand(0), CN->getAPIntValue())) { + AM.Disp += Offset; + return false; + } + AM = Backup; + } + break; + } + + return MatchAddressBase(N, AM); +} + +/// SelectAddr - returns true if it is able pattern match an addressing mode. +/// It returns the operands which make up the maximal addressing mode it can +/// match by reference. +bool NDS32DAGToDAGISel::SelectAddr(SDValue N, + SDValue &Base, SDValue &Disp) { + NDS32ISelAddressMode AM; + + if (MatchAddress(N, AM)) + return false; + + EVT VT = N.getValueType(); + if (AM.BaseType == NDS32ISelAddressMode::RegBase) { + if (!AM.Base.Reg.getNode()) + AM.Base.Reg = CurDAG->getRegister(0, VT); + } + + Base = (AM.BaseType == NDS32ISelAddressMode::FrameIndexBase) + ? CurDAG->getTargetFrameIndex( + AM.Base.FrameIndex, + getTargetLowering()->getPointerTy(CurDAG->getDataLayout())) + : AM.Base.Reg; + + if (AM.GV) + Disp = CurDAG->getTargetGlobalAddress(AM.GV, SDLoc(N), + MVT::i32, AM.Disp, + 0/*AM.SymbolFlags*/); + else if (AM.CP) + Disp = CurDAG->getTargetConstantPool(AM.CP, MVT::i32, + AM.Align, AM.Disp, 0/*AM.SymbolFlags*/); + else if (AM.ES) + Disp = CurDAG->getTargetExternalSymbol(AM.ES, MVT::i32, 0/*AM.SymbolFlags*/); + else if (AM.JT != -1) + Disp = CurDAG->getTargetJumpTable(AM.JT, MVT::i32, 0/*AM.SymbolFlags*/); + else if (AM.BlockAddr) + Disp = CurDAG->getTargetBlockAddress(AM.BlockAddr, MVT::i32, 0, + 0/*AM.SymbolFlags*/); + else + Disp = CurDAG->getTargetConstant(AM.Disp, SDLoc(N), MVT::i32); + + return true; +} + +bool NDS32DAGToDAGISel:: +SelectInlineAsmMemoryOperand(const SDValue &Op, unsigned ConstraintID, + std::vector &OutOps) { + SDValue Op0, Op1; + switch (ConstraintID) { + default: return true; + // All memory constraints can at least accept raw pointers. + case InlineAsm::Constraint_i: + OutOps.push_back(Op); + OutOps.push_back(CurDAG->getTargetConstant(0, SDLoc(Op), MVT::i32)); + return false; + case InlineAsm::Constraint_m: // memory + if (!SelectAddr(Op, Op0, Op1)) + return true; + break; + } + + OutOps.push_back(Op0); + OutOps.push_back(Op1); + return false; +} + +bool NDS32DAGToDAGISel::tryIndexedLoad(SDNode *N) { + LoadSDNode *LD = cast(N); + ISD::MemIndexedMode AM = LD->getAddressingMode(); + + if (AM == ISD::UNINDEXED) + return false; + + unsigned Opcode = 0; + bool Match = false; + SDValue Offset; + SDValue Opc; + + MVT VT = LD->getMemoryVT().getSimpleVT(); + if ((AM == ISD::POST_INC) && (VT == MVT::i32)) { + if (SelectAddrImm15sWordPostInc (N, LD->getOffset(), Offset, Opc)) { + Opcode = NDS32::LWI_BI; + } else { + Opcode = NDS32::LW_BI; + } + Match = true; + } + else if ((AM == ISD::POST_INC) && (VT == MVT::i16)) { + if (SelectAddrImm15sHalfPostInc (N, LD->getOffset(), Offset, Opc)) { + Opcode = (LD->getExtensionType() == ISD::SEXTLOAD) + ? NDS32::LHSI_BI : NDS32::LHI_BI; + } else { + Opcode = (LD->getExtensionType() == ISD::SEXTLOAD) + ? NDS32::LHS_BI : NDS32::LH_BI; + } + Match = true; + } + else if ((AM == ISD::POST_INC) && (VT == MVT::i8)) { + if (SelectAddrImm15sBytePostInc (N, LD->getOffset(), Offset, Opc)) { + Opcode = (LD->getExtensionType() == ISD::SEXTLOAD) + ? NDS32::LBSI_BI : NDS32::LBI_BI; + } else { + Opcode = (LD->getExtensionType() == ISD::SEXTLOAD) + ? NDS32::LBS_BI : NDS32::LB_BI; + } + Match = true; + } + + if (Match) { + SDValue Chain = LD->getChain(); + SDValue Base = LD->getBasePtr(); + SDValue Ops[]= { Base, Offset, CurDAG->getRegister(0, MVT::i32), Chain }; + + ReplaceNode(N, CurDAG->getMachineNode(Opcode, SDLoc(N), MVT::i32, + MVT::i32, MVT::Other, Ops)); + return true; + } + + return false; +} + +bool NDS32DAGToDAGISel::tryIndexedStore(SDNode *N) { + StoreSDNode *ST = cast(N); + ISD::MemIndexedMode AM = ST->getAddressingMode(); + + if (AM == ISD::UNINDEXED) + return false; + + unsigned Opcode = 0; + bool Match = false; + SDValue Offset; + SDValue Opc; + + MVT VT = ST->getMemoryVT().getSimpleVT(); + if ((AM == ISD::POST_INC) && (VT == MVT::i32)) { + if (SelectAddrImm15sWordPostInc(N, ST->getOffset(), Offset, Opc)) { + Opcode = NDS32::SWI_BI; + } else { + Opcode = NDS32::SW_BI; + } + Match = true; + } + else if ((AM == ISD::POST_INC) && (VT == MVT::i16)) { + if (SelectAddrImm15sHalfPostInc(N, ST->getOffset(), Offset, Opc)) { + Opcode = NDS32::SHI_BI; + } else { + Opcode = NDS32::SH_BI; + } + Match = true; + } + else if ((AM == ISD::POST_INC) && (VT == MVT::i8)) { + if (SelectAddrImm15sBytePostInc(N, ST->getOffset(), Offset, Opc)) { + Opcode = NDS32::SBI_BI; + } else { + Opcode = NDS32::SB_BI; + } + Match = true; + } + + if (Match) { + SDValue Chain = ST->getChain(); + SDValue Base = ST->getBasePtr(); + SDValue Value = ST->getValue(); + SDValue Ops[]= { Value, Base, Offset, CurDAG->getRegister(0, MVT::i32), + Chain }; + + ReplaceNode(N, CurDAG->getMachineNode(Opcode, SDLoc(N), MVT::i32, + MVT::Other, Ops)); + return true; + } + + return false; +} + +void NDS32DAGToDAGISel::Select(SDNode *Node) { + SDLoc dl(Node); + + // Dump information about the Node being selected + DEBUG(errs() << "Selecting: "); + DEBUG(Node->dump(CurDAG)); + DEBUG(errs() << "\n"); + + // If we have a custom node, we already have selected! + if (Node->isMachineOpcode()) { + DEBUG(errs() << "== "; + Node->dump(CurDAG); + errs() << "\n"); + Node->setNodeId(-1); + return; + } + + // Few custom selection stuff. + switch (Node->getOpcode()) { + default: break; + case ISD::FrameIndex: { + assert(Node->getValueType(0) == MVT::i32); + int FI = cast(Node)->getIndex(); + SDValue TFI = CurDAG->getTargetFrameIndex(FI, MVT::i32); + if (Node->hasOneUse()) { + CurDAG->SelectNodeTo(Node, NDS32::ADDI, MVT::i32, TFI, + CurDAG->getTargetConstant(0, dl, MVT::i32)); + return; + } + ReplaceNode(Node, CurDAG->getMachineNode( + NDS32::ADDI, dl, MVT::i32, TFI, + CurDAG->getTargetConstant(0, dl, MVT::i32))); + return; + } + case ISD::LOAD: + if (tryIndexedLoad(Node)) + return; + break; + case ISD::STORE: + if (tryIndexedStore(Node)) + return; + break; + case ISD::ADD: + // Other cases are autogenerated. + break; + case ISD::SUB: + // Other cases are autogenerated. + break; + case ISD::AND: + // Other cases are autogenerated. + break; + case ISD::OR: + // Other cases are autogenerated. + break; + case ISD::XOR: + // Other cases are autogenerated. + break; + } + + // Select the default instruction + SelectCode(Node); +} Index: lib/Target/NDS32/NDS32TargetMachine.cpp =================================================================== --- lib/Target/NDS32/NDS32TargetMachine.cpp +++ lib/Target/NDS32/NDS32TargetMachine.cpp @@ -114,9 +114,17 @@ NDS32TargetMachine &getNDS32TargetMachine() const { return getTM(); } + + bool addInstSelector() override; }; } // namespace TargetPassConfig *NDS32TargetMachine::createPassConfig(PassManagerBase &PM) { return new NDS32PassConfig(this, PM); } + +bool NDS32PassConfig::addInstSelector() { + // Install an instruction selector. + addPass(createNDS32ISelDag(getNDS32TargetMachine(), getOptLevel())); + return false; +}