text: //===-- SparcISelDAGToDAG.cpp - A dag to dag inst selector for Sparc ------===//
  //
  //                     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 SPARC target.
  //
  //===----------------------------------------------------------------------===//
  
  #include "SparcTargetMachine.h"
  #include "llvm/Intrinsics.h"
  #include "llvm/CodeGen/SelectionDAGISel.h"
  #include "llvm/Support/Compiler.h"
  #include "llvm/Support/Debug.h"
  #include "llvm/Support/ErrorHandling.h"
  #include "llvm/Support/raw_ostream.h"
  using namespace llvm;
  
  //===----------------------------------------------------------------------===//
  // Instruction Selector Implementation
  //===----------------------------------------------------------------------===//
  
  //===--------------------------------------------------------------------===//
  /// SparcDAGToDAGISel - SPARC specific code to select SPARC machine
  /// instructions for SelectionDAG operations.
  ///
  namespace {
  class SparcDAGToDAGISel : public SelectionDAGISel {
    /// Subtarget - Keep a pointer to the Sparc Subtarget around so that we can
    /// make the right decision when generating code for different targets.
    const SparcSubtarget &Subtarget;
    SparcTargetMachine& TM;
  public:
    explicit SparcDAGToDAGISel(SparcTargetMachine &tm)
      : SelectionDAGISel(tm),
        Subtarget(tm.getSubtarget<SparcSubtarget>()),
        TM(tm) {
    }
  
    SDNode *Select(SDNode *N);
  
    // Complex Pattern Selectors.
    bool SelectADDRrr(SDValue N, SDValue &R1, SDValue &R2);
    bool SelectADDRri(SDValue N, SDValue &Base, SDValue &Offset);
  
    /// SelectInlineAsmMemoryOperand - Implement addressing mode selection for
    /// inline asm expressions.
    virtual bool SelectInlineAsmMemoryOperand(const SDValue &Op,
                                              char ConstraintCode,
                                              std::vector<SDValue> &OutOps);
  
    virtual const char *getPassName() const {
      return "SPARC DAG->DAG Pattern Instruction Selection";
    }
  
    // Include the pieces autogenerated from the target description.
  #include "SparcGenDAGISel.inc"
  
  private:
    SDNode* getGlobalBaseReg();
  };
  }  // end anonymous namespace
  
  SDNode* SparcDAGToDAGISel::getGlobalBaseReg() {
    unsigned GlobalBaseReg = TM.getInstrInfo()->getGlobalBaseReg(MF);
    return CurDAG->getRegister(GlobalBaseReg, TLI.getPointerTy()).getNode();
  }
  
  bool SparcDAGToDAGISel::SelectADDRri(SDValue Addr,
                                       SDValue &Base, SDValue &Offset) {
    if (FrameIndexSDNode *FIN = dyn_cast<FrameIndexSDNode>(Addr)) {
      Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i32);
      Offset = CurDAG->getTargetConstant(0, MVT::i32);
      return true;
    }
    if (Addr.getOpcode() == ISD::TargetExternalSymbol ||
        Addr.getOpcode() == ISD::TargetGlobalAddress)
      return false;  // direct calls.
  
    if (Addr.getOpcode() == ISD::ADD) {
      if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1))) {
        if (isInt<13>(CN->getSExtValue())) {
          if (FrameIndexSDNode *FIN =
                  dyn_cast<FrameIndexSDNode>(Addr.getOperand(0))) {
            // Constant offset from frame ref.
            Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i32);
          } else {
            Base = Addr.getOperand(0);
          }
          Offset = CurDAG->getTargetConstant(CN->getZExtValue(), MVT::i32);
          return true;
        }
      }
      if (Addr.getOperand(0).getOpcode() == SPISD::Lo) {
        Base = Addr.getOperand(1);
        Offset = Addr.getOperand(0).getOperand(0);
        return true;
      }
      if (Addr.getOperand(1).getOpcode() == SPISD::Lo) {
        Base = Addr.getOperand(0);
        Offset = Addr.getOperand(1).getOperand(0);
        return true;
      }
    }
    Base = Addr;
    Offset = CurDAG->getTargetConstant(0, MVT::i32);
    return true;
  }
  
  bool SparcDAGToDAGISel::SelectADDRrr(SDValue Addr, SDValue &R1, SDValue &R2) {
    if (Addr.getOpcode() == ISD::FrameIndex) return false;
    if (Addr.getOpcode() == ISD::TargetExternalSymbol ||
        Addr.getOpcode() == ISD::TargetGlobalAddress)
      return false;  // direct calls.
  
    if (Addr.getOpcode() == ISD::ADD) {
      if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1)))
        if (isInt<13>(CN->getSExtValue()))
          return false;  // Let the reg+imm pattern catch this!
      if (Addr.getOperand(0).getOpcode() == SPISD::Lo ||
          Addr.getOperand(1).getOpcode() == SPISD::Lo)
        return false;  // Let the reg+imm pattern catch this!
      R1 = Addr.getOperand(0);
      R2 = Addr.getOperand(1);
      return true;
    }
  
    R1 = Addr;
    R2 = CurDAG->getRegister(SP::G0, MVT::i32);
    return true;
  }
  
  SDNode *SparcDAGToDAGISel::Select(SDNode *N) {
    DebugLoc dl = N->getDebugLoc();
    if (N->isMachineOpcode())
      return NULL;   // Already selected.
  
    switch (N->getOpcode()) {
    default: break;
    case SPISD::GLOBAL_BASE_REG:
      return getGlobalBaseReg();
  
    case ISD::SDIV:
    case ISD::UDIV: {
      // FIXME: should use a custom expander to expose the SRA to the dag.
      SDValue DivLHS = N->getOperand(0);
      SDValue DivRHS = N->getOperand(1);
  
      // Set the Y register to the high-part.
      SDValue TopPart;
      if (N->getOpcode() == ISD::SDIV) {
        TopPart = SDValue(CurDAG->getMachineNode(SP::SRAri, dl, MVT::i32, DivLHS,
                                     CurDAG->getTargetConstant(31, MVT::i32)), 0);
      } else {
        TopPart = CurDAG->getRegister(SP::G0, MVT::i32);
      }
      TopPart = SDValue(CurDAG->getMachineNode(SP::WRYrr, dl, MVT::Glue, TopPart,
                                       CurDAG->getRegister(SP::G0, MVT::i32)), 0);
  
      // FIXME: Handle div by immediate.
      unsigned Opcode = N->getOpcode() == ISD::SDIV ? SP::SDIVrr : SP::UDIVrr;
      return CurDAG->SelectNodeTo(N, Opcode, MVT::i32, DivLHS, DivRHS,
                                  TopPart);
    }
    case ISD::MULHU:
    case ISD::MULHS: {
      // FIXME: Handle mul by immediate.
      SDValue MulLHS = N->getOperand(0);
      SDValue MulRHS = N->getOperand(1);
      unsigned Opcode = N->getOpcode() == ISD::MULHU ? SP::UMULrr : SP::SMULrr;
      SDNode *Mul = CurDAG->getMachineNode(Opcode, dl, MVT::i32, MVT::Glue,
                                           MulLHS, MulRHS);
      // The high part is in the Y register.
      return CurDAG->SelectNodeTo(N, SP::RDY, MVT::i32, SDValue(Mul, 1));
    }
    }
  
    return SelectCode(N);
  }
  
  
  /// SelectInlineAsmMemoryOperand - Implement addressing mode selection for
  /// inline asm expressions.
  bool
  SparcDAGToDAGISel::SelectInlineAsmMemoryOperand(const SDValue &Op,
                                                  char ConstraintCode,
                                                  std::vector<SDValue> &OutOps) {
    SDValue Op0, Op1;
    switch (ConstraintCode) {
    default: return true;
    case 'm':   // memory
     if (!SelectADDRrr(Op, Op0, Op1))
       SelectADDRri(Op, Op0, Op1);
     break;
    }
  
    OutOps.push_back(Op0);
    OutOps.push_back(Op1);
    return false;
  }
  
  /// createSparcISelDag - This pass converts a legalized DAG into a
  /// SPARC-specific DAG, ready for instruction scheduling.
  ///
  FunctionPass *llvm::createSparcISelDag(SparcTargetMachine &TM) {
    return new SparcDAGToDAGISel(TM);
  }
  