| //===-- 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); | |
| } |