//===-- MBlazeISelDAGToDAG.cpp - A dag to dag inst selector for MBlaze ----===// // // 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 MBlaze target. // //===----------------------------------------------------------------------===// #define DEBUG_TYPE "mblaze-isel" #include "MBlaze.h" #include "MBlazeMachineFunction.h" #include "MBlazeRegisterInfo.h" #include "MBlazeSubtarget.h" #include "MBlazeTargetMachine.h" #include "llvm/GlobalValue.h" #include "llvm/Instructions.h" #include "llvm/Intrinsics.h" #include "llvm/Support/CFG.h" #include "llvm/Type.h" #include "llvm/CodeGen/MachineConstantPool.h" #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineFrameInfo.h" #include "llvm/CodeGen/MachineInstrBuilder.h" #include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/CodeGen/SelectionDAGISel.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" using namespace llvm; //===----------------------------------------------------------------------===// // Instruction Selector Implementation //===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===// // MBlazeDAGToDAGISel - MBlaze specific code to select MBlaze machine // instructions for SelectionDAG operations. //===----------------------------------------------------------------------===// namespace { class MBlazeDAGToDAGISel : public SelectionDAGISel { /// TM - Keep a reference to MBlazeTargetMachine. MBlazeTargetMachine &TM; /// Subtarget - Keep a pointer to the MBlazeSubtarget around so that we can /// make the right decision when generating code for different targets. const MBlazeSubtarget &Subtarget; public: explicit MBlazeDAGToDAGISel(MBlazeTargetMachine &tm) : SelectionDAGISel(tm), TM(tm), Subtarget(tm.getSubtarget<MBlazeSubtarget>()) {} // Pass Name virtual const char *getPassName() const { return "MBlaze DAG->DAG Pattern Instruction Selection"; } private: // Include the pieces autogenerated from the target description. #include "MBlazeGenDAGISel.inc" /// getTargetMachine - Return a reference to the TargetMachine, casted /// to the target-specific type. const MBlazeTargetMachine &getTargetMachine() { return static_cast<const MBlazeTargetMachine &>(TM); } /// getInstrInfo - Return a reference to the TargetInstrInfo, casted /// to the target-specific type. const MBlazeInstrInfo *getInstrInfo() { return getTargetMachine().getInstrInfo(); } SDNode *getGlobalBaseReg(); SDNode *Select(SDNode *N); // Address Selection bool SelectAddrRegReg(SDValue N, SDValue &Base, SDValue &Index); bool SelectAddrRegImm(SDValue N, SDValue &Disp, SDValue &Base); // getI32Imm - Return a target constant with the specified value, of type i32. inline SDValue getI32Imm(unsigned Imm) { return CurDAG->getTargetConstant(Imm, MVT::i32); } }; } /// isIntS32Immediate - This method tests to see if the node is either a 32-bit /// or 64-bit immediate, and if the value can be accurately represented as a /// sign extension from a 32-bit value. If so, this returns true and the /// immediate. static bool isIntS32Immediate(SDNode *N, int32_t &Imm) { unsigned Opc = N->getOpcode(); if (Opc != ISD::Constant) return false; Imm = (int32_t)cast<ConstantSDNode>(N)->getZExtValue(); if (N->getValueType(0) == MVT::i32) return Imm == (int32_t)cast<ConstantSDNode>(N)->getZExtValue(); else return Imm == (int64_t)cast<ConstantSDNode>(N)->getZExtValue(); } static bool isIntS32Immediate(SDValue Op, int32_t &Imm) { return isIntS32Immediate(Op.getNode(), Imm); } /// SelectAddressRegReg - Given the specified addressed, check to see if it /// can be represented as an indexed [r+r] operation. Returns false if it /// can be more efficiently represented with [r+imm]. bool MBlazeDAGToDAGISel:: SelectAddrRegReg(SDValue N, SDValue &Base, SDValue &Index) { if (N.getOpcode() == ISD::FrameIndex) return false; if (N.getOpcode() == ISD::TargetExternalSymbol || N.getOpcode() == ISD::TargetGlobalAddress) return false; // direct calls. int32_t imm = 0; if (N.getOpcode() == ISD::ADD || N.getOpcode() == ISD::OR) { if (isIntS32Immediate(N.getOperand(1), imm)) return false; // r+i if (N.getOperand(0).getOpcode() == ISD::TargetJumpTable || N.getOperand(1).getOpcode() == ISD::TargetJumpTable) return false; // jump tables. Base = N.getOperand(0); Index = N.getOperand(1); return true; } return false; } /// Returns true if the address N can be represented by a base register plus /// a signed 32-bit displacement [r+imm], and if it is not better /// represented as reg+reg. bool MBlazeDAGToDAGISel:: SelectAddrRegImm(SDValue N, SDValue &Base, SDValue &Disp) { // If this can be more profitably realized as r+r, fail. if (SelectAddrRegReg(N, Base, Disp)) return false; if (N.getOpcode() == ISD::ADD || N.getOpcode() == ISD::OR) { int32_t imm = 0; if (isIntS32Immediate(N.getOperand(1), imm)) { Disp = CurDAG->getTargetConstant(imm, MVT::i32); if (FrameIndexSDNode *FI = dyn_cast<FrameIndexSDNode>(N.getOperand(0))) { Base = CurDAG->getTargetFrameIndex(FI->getIndex(), N.getValueType()); } else { Base = N.getOperand(0); } return true; // [r+i] } } else if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(N)) { // Loading from a constant address. uint32_t Imm = CN->getZExtValue(); Disp = CurDAG->getTargetConstant(Imm, CN->getValueType(0)); Base = CurDAG->getRegister(MBlaze::R0, CN->getValueType(0)); return true; } Disp = CurDAG->getTargetConstant(0, TM.getTargetLowering()->getPointerTy()); if (FrameIndexSDNode *FI = dyn_cast<FrameIndexSDNode>(N)) Base = CurDAG->getTargetFrameIndex(FI->getIndex(), N.getValueType()); else Base = N; return true; // [r+0] } /// getGlobalBaseReg - Output the instructions required to put the /// GOT address into a register. SDNode *MBlazeDAGToDAGISel::getGlobalBaseReg() { unsigned GlobalBaseReg = getInstrInfo()->getGlobalBaseReg(MF); return CurDAG->getRegister(GlobalBaseReg, TLI.getPointerTy()).getNode(); } /// Select instructions not customized! Used for /// expanded, promoted and normal instructions SDNode* MBlazeDAGToDAGISel::Select(SDNode *Node) { unsigned Opcode = Node->getOpcode(); DebugLoc dl = Node->getDebugLoc(); // If we have a custom node, we already have selected! if (Node->isMachineOpcode()) return NULL; /// // Instruction Selection not handled by the auto-generated // tablegen selection should be handled here. /// switch (Opcode) { default: break; // Get target GOT address. case ISD::GLOBAL_OFFSET_TABLE: return getGlobalBaseReg(); case ISD::FrameIndex: { SDValue imm = CurDAG->getTargetConstant(0, MVT::i32); int FI = dyn_cast<FrameIndexSDNode>(Node)->getIndex(); EVT VT = Node->getValueType(0); SDValue TFI = CurDAG->getTargetFrameIndex(FI, VT); unsigned Opc = MBlaze::ADDIK; if (Node->hasOneUse()) return CurDAG->SelectNodeTo(Node, Opc, VT, TFI, imm); return CurDAG->getMachineNode(Opc, dl, VT, TFI, imm); } /// Handle direct and indirect calls when using PIC. On PIC, when /// GOT is smaller than about 64k (small code) the GA target is /// loaded with only one instruction. Otherwise GA's target must /// be loaded with 3 instructions. case MBlazeISD::JmpLink: { if (TM.getRelocationModel() == Reloc::PIC_) { SDValue Chain = Node->getOperand(0); SDValue Callee = Node->getOperand(1); SDValue R20Reg = CurDAG->getRegister(MBlaze::R20, MVT::i32); SDValue InFlag(0, 0); if ((isa<GlobalAddressSDNode>(Callee)) || (isa<ExternalSymbolSDNode>(Callee))) { /// Direct call for global addresses and external symbols SDValue GPReg = CurDAG->getRegister(MBlaze::R15, MVT::i32); // Use load to get GOT target SDValue Ops[] = { Callee, GPReg, Chain }; SDValue Load = SDValue(CurDAG->getMachineNode(MBlaze::LW, dl, MVT::i32, MVT::Other, Ops, 3), 0); Chain = Load.getValue(1); // Call target must be on T9 Chain = CurDAG->getCopyToReg(Chain, dl, R20Reg, Load, InFlag); } else /// Indirect call Chain = CurDAG->getCopyToReg(Chain, dl, R20Reg, Callee, InFlag); // Emit Jump and Link Register SDNode *ResNode = CurDAG->getMachineNode(MBlaze::BRLID, dl, MVT::Other, MVT::Glue, R20Reg, Chain); Chain = SDValue(ResNode, 0); InFlag = SDValue(ResNode, 1); ReplaceUses(SDValue(Node, 0), Chain); ReplaceUses(SDValue(Node, 1), InFlag); return ResNode; } } } // Select the default instruction SDNode *ResNode = SelectCode(Node); DEBUG(errs() << "=> "); if (ResNode == NULL || ResNode == Node) DEBUG(Node->dump(CurDAG)); else DEBUG(ResNode->dump(CurDAG)); DEBUG(errs() << "\n"); return ResNode; } /// createMBlazeISelDag - This pass converts a legalized DAG into a /// MBlaze-specific DAG, ready for instruction scheduling. FunctionPass *llvm::createMBlazeISelDag(MBlazeTargetMachine &TM) { return new MBlazeDAGToDAGISel(TM); }