XCoreISelDAGToDAG.cpp revision 234353
151078Speter//===-- XCoreISelDAGToDAG.cpp - A dag to dag inst selector for XCore ------===//
251078Speter//
351078Speter//                     The LLVM Compiler Infrastructure
451078Speter//
551078Speter// This file is distributed under the University of Illinois Open Source
651078Speter// License. See LICENSE.TXT for details.
751078Speter//
851078Speter//===----------------------------------------------------------------------===//
951078Speter//
1051078Speter// This file defines an instruction selector for the XCore target.
1151078Speter//
1251078Speter//===----------------------------------------------------------------------===//
1351078Speter
1451078Speter#include "XCore.h"
1551078Speter#include "XCoreTargetMachine.h"
1651078Speter#include "llvm/DerivedTypes.h"
1751078Speter#include "llvm/Function.h"
1851078Speter#include "llvm/Intrinsics.h"
1951078Speter#include "llvm/CallingConv.h"
2051078Speter#include "llvm/Constants.h"
2151078Speter#include "llvm/LLVMContext.h"
2251078Speter#include "llvm/CodeGen/MachineFrameInfo.h"
2351078Speter#include "llvm/CodeGen/MachineFunction.h"
2451078Speter#include "llvm/CodeGen/MachineInstrBuilder.h"
2551078Speter#include "llvm/CodeGen/MachineRegisterInfo.h"
2651078Speter#include "llvm/CodeGen/SelectionDAG.h"
2751078Speter#include "llvm/CodeGen/SelectionDAGISel.h"
2851078Speter#include "llvm/Target/TargetLowering.h"
2951078Speter#include "llvm/Support/Compiler.h"
3051078Speter#include "llvm/Support/Debug.h"
3151078Speter#include "llvm/Support/ErrorHandling.h"
3251078Speter#include "llvm/Support/raw_ostream.h"
33119419Sobrienusing namespace llvm;
34119419Sobrien
35119419Sobrien/// XCoreDAGToDAGISel - XCore specific code to select XCore machine
3651078Speter/// instructions for SelectionDAG operations.
3751078Speter///
38131939Smarcelnamespace {
39131939Smarcel  class XCoreDAGToDAGISel : public SelectionDAGISel {
4051078Speter    const XCoreTargetLowering &Lowering;
4151078Speter    const XCoreSubtarget &Subtarget;
4251078Speter
4351078Speter  public:
4451078Speter    XCoreDAGToDAGISel(XCoreTargetMachine &TM, CodeGenOpt::Level OptLevel)
4551078Speter      : SelectionDAGISel(TM, OptLevel),
4651078Speter        Lowering(*TM.getTargetLowering()),
4751078Speter        Subtarget(*TM.getSubtargetImpl()) { }
4851078Speter
4951078Speter    SDNode *Select(SDNode *N);
5051078Speter    SDNode *SelectBRIND(SDNode *N);
5151078Speter
5276166Smarkm    /// getI32Imm - Return a target constant with the specified value, of type
5365822Sjhb    /// i32.
5451078Speter    inline SDValue getI32Imm(unsigned Imm) {
5551078Speter      return CurDAG->getTargetConstant(Imm, MVT::i32);
5651078Speter    }
57131939Smarcel
5851078Speter    inline bool immMskBitp(SDNode *inN) const {
59114216Skan      ConstantSDNode *N = cast<ConstantSDNode>(inN);
6076166Smarkm      uint32_t value = (uint32_t)N->getZExtValue();
6176166Smarkm      if (!isMask_32(value)) {
6276166Smarkm        return false;
6376166Smarkm      }
6476166Smarkm      int msksize = 32 - CountLeadingZeros_32(value);
6576166Smarkm      return (msksize >= 1 && msksize <= 8) ||
66131094Sphk              msksize == 16 || msksize == 24 || msksize == 32;
6776166Smarkm    }
6851078Speter
6976166Smarkm    // Complex Pattern Selectors.
7060471Snyan    bool SelectADDRspii(SDValue Addr, SDValue &Base, SDValue &Offset);
7151078Speter    bool SelectADDRdpii(SDValue Addr, SDValue &Base, SDValue &Offset);
7251078Speter    bool SelectADDRcpii(SDValue Addr, SDValue &Base, SDValue &Offset);
7351078Speter
7493466Sbde    virtual const char *getPassName() const {
75119485Snjl      return "XCore DAG->DAG Pattern Instruction Selection";
7651078Speter    }
7786909Simp
7886909Simp    // Include the pieces autogenerated from the target description.
7951078Speter  #include "XCoreGenDAGISel.inc"
8051078Speter  };
8185302Simp}  // end anonymous namespace
8285365Simp
8351078Speter/// createXCoreISelDag - This pass converts a legalized DAG into a
8451078Speter/// XCore-specific DAG, ready for instruction scheduling.
8577726Sjoerg///
8651078SpeterFunctionPass *llvm::createXCoreISelDag(XCoreTargetMachine &TM,
8777726Sjoerg                                       CodeGenOpt::Level OptLevel) {
8851078Speter  return new XCoreDAGToDAGISel(TM, OptLevel);
8951078Speter}
9051078Speter
9151078Speterbool XCoreDAGToDAGISel::SelectADDRspii(SDValue Addr, SDValue &Base,
9251078Speter                                       SDValue &Offset) {
9351078Speter  FrameIndexSDNode *FIN = 0;
9451078Speter  if ((FIN = dyn_cast<FrameIndexSDNode>(Addr))) {
9551078Speter    Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i32);
9693470Sbde    Offset = CurDAG->getTargetConstant(0, MVT::i32);
9793470Sbde    return true;
9893470Sbde  }
9993470Sbde  if (Addr.getOpcode() == ISD::ADD) {
10051078Speter    ConstantSDNode *CN = 0;
10151078Speter    if ((FIN = dyn_cast<FrameIndexSDNode>(Addr.getOperand(0)))
10251078Speter      && (CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1)))
10351078Speter      && (CN->getSExtValue() % 4 == 0 && CN->getSExtValue() >= 0)) {
10451078Speter      // Constant positive word offset from frame index
10551078Speter      Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i32);
10651078Speter      Offset = CurDAG->getTargetConstant(CN->getSExtValue(), MVT::i32);
10751078Speter      return true;
108104067Sphk    }
109104067Sphk  }
11051078Speter  return false;
11151078Speter}
112120175Sbde
11351078Speterbool XCoreDAGToDAGISel::SelectADDRdpii(SDValue Addr, SDValue &Base,
114120175Sbde                                       SDValue &Offset) {
115120175Sbde  if (Addr.getOpcode() == XCoreISD::DPRelativeWrapper) {
11651078Speter    Base = Addr.getOperand(0);
117120175Sbde    Offset = CurDAG->getTargetConstant(0, MVT::i32);
11851078Speter    return true;
11951078Speter  }
120120175Sbde  if (Addr.getOpcode() == ISD::ADD) {
121120175Sbde    ConstantSDNode *CN = 0;
122120175Sbde    if ((Addr.getOperand(0).getOpcode() == XCoreISD::DPRelativeWrapper)
123111613Sphk      && (CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1)))
124120175Sbde      && (CN->getSExtValue() % 4 == 0 && CN->getSExtValue() >= 0)) {
125112384Ssobomax      // Constant word offset from a object in the data region
12651078Speter      Base = Addr.getOperand(0).getOperand(0);
12760471Snyan      Offset = CurDAG->getTargetConstant(CN->getSExtValue(), MVT::i32);
12860471Snyan      return true;
12960471Snyan    }
13060471Snyan  }
13160471Snyan  return false;
13251078Speter}
13351078Speter
13451078Speterbool XCoreDAGToDAGISel::SelectADDRcpii(SDValue Addr, SDValue &Base,
13551078Speter                                       SDValue &Offset) {
13651078Speter  if (Addr.getOpcode() == XCoreISD::CPRelativeWrapper) {
13751078Speter    Base = Addr.getOperand(0);
13851078Speter    Offset = CurDAG->getTargetConstant(0, MVT::i32);
13951078Speter    return true;
14053344Speter  }
14151078Speter  if (Addr.getOpcode() == ISD::ADD) {
14251078Speter    ConstantSDNode *CN = 0;
14351078Speter    if ((Addr.getOperand(0).getOpcode() == XCoreISD::CPRelativeWrapper)
14451078Speter      && (CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1)))
14551078Speter      && (CN->getSExtValue() % 4 == 0 && CN->getSExtValue() >= 0)) {
14651078Speter      // Constant word offset from a object in the data region
14751078Speter      Base = Addr.getOperand(0).getOperand(0);
14851078Speter      Offset = CurDAG->getTargetConstant(CN->getSExtValue(), MVT::i32);
14951078Speter      return true;
15051078Speter    }
15151078Speter  }
15251078Speter  return false;
15351078Speter}
15451078Speter
15551078SpeterSDNode *XCoreDAGToDAGISel::Select(SDNode *N) {
15651078Speter  DebugLoc dl = N->getDebugLoc();
15751078Speter  switch (N->getOpcode()) {
15851078Speter  default: break;
15951078Speter  case ISD::Constant: {
16051078Speter    uint64_t Val = cast<ConstantSDNode>(N)->getZExtValue();
16151078Speter    if (immMskBitp(N)) {
16251078Speter      // Transformation function: get the size of a mask
16351078Speter      // Look for the first non-zero bit
16451078Speter      SDValue MskSize = getI32Imm(32 - CountLeadingZeros_32(Val));
16551078Speter      return CurDAG->getMachineNode(XCore::MKMSK_rus, dl,
16686909Simp                                    MVT::i32, MskSize);
16751078Speter    }
16851078Speter    else if (!isUInt<16>(Val)) {
16986909Simp      SDValue CPIdx =
17086909Simp        CurDAG->getTargetConstantPool(ConstantInt::get(
17186909Simp                              Type::getInt32Ty(*CurDAG->getContext()), Val),
17286909Simp                                      TLI.getPointerTy());
17386909Simp      SDNode *node = CurDAG->getMachineNode(XCore::LDWCP_lru6, dl, MVT::i32,
17486909Simp                                            MVT::Other, CPIdx,
17586909Simp                                            CurDAG->getEntryNode());
17686909Simp      MachineSDNode::mmo_iterator MemOp = MF->allocateMemRefsArray(1);
17786909Simp      MemOp[0] = MF->getMachineMemOperand(
17886909Simp        MachinePointerInfo::getConstantPool(), MachineMemOperand::MOLoad, 4, 4);
17986909Simp      cast<MachineSDNode>(node)->setMemRefs(MemOp, MemOp + 1);
18086909Simp      return node;
18186909Simp    }
18286909Simp    break;
18386909Simp  }
18486909Simp  case XCoreISD::LADD: {
18586909Simp    SDValue Ops[] = { N->getOperand(0), N->getOperand(1),
18651078Speter                        N->getOperand(2) };
18786909Simp    return CurDAG->getMachineNode(XCore::LADD_l5r, dl, MVT::i32, MVT::i32,
18886909Simp                                  Ops, 3);
18986909Simp  }
19086909Simp  case XCoreISD::LSUB: {
19186909Simp    SDValue Ops[] = { N->getOperand(0), N->getOperand(1),
19286909Simp                        N->getOperand(2) };
19386909Simp    return CurDAG->getMachineNode(XCore::LSUB_l5r, dl, MVT::i32, MVT::i32,
19486909Simp                                  Ops, 3);
19586909Simp  }
19686909Simp  case XCoreISD::MACCU: {
19786909Simp    SDValue Ops[] = { N->getOperand(0), N->getOperand(1),
19886909Simp                      N->getOperand(2), N->getOperand(3) };
19986909Simp    return CurDAG->getMachineNode(XCore::MACCU_l4r, dl, MVT::i32, MVT::i32,
20086909Simp                                  Ops, 4);
201120175Sbde  }
20286909Simp  case XCoreISD::MACCS: {
203120189Sbde    SDValue Ops[] = { N->getOperand(0), N->getOperand(1),
20486909Simp                      N->getOperand(2), N->getOperand(3) };
20586909Simp    return CurDAG->getMachineNode(XCore::MACCS_l4r, dl, MVT::i32, MVT::i32,
20686909Simp                                  Ops, 4);
20786909Simp  }
20886909Simp  case XCoreISD::LMUL: {
20986909Simp    SDValue Ops[] = { N->getOperand(0), N->getOperand(1),
21086909Simp                      N->getOperand(2), N->getOperand(3) };
21186909Simp    return CurDAG->getMachineNode(XCore::LMUL_l6r, dl, MVT::i32, MVT::i32,
21286909Simp                                  Ops, 4);
21386909Simp  }
21486909Simp  case ISD::INTRINSIC_WO_CHAIN: {
21586909Simp    unsigned IntNo = cast<ConstantSDNode>(N->getOperand(0))->getZExtValue();
21686909Simp    switch (IntNo) {
21786909Simp    case Intrinsic::xcore_crc8:
21886909Simp      SDValue Ops[] = { N->getOperand(1), N->getOperand(2), N->getOperand(3) };
21986909Simp      return CurDAG->getMachineNode(XCore::CRC8_l4r, dl, MVT::i32, MVT::i32,
22086909Simp                                    Ops, 3);
22186909Simp    }
22286909Simp    break;
22386909Simp  }
22486909Simp  case ISD::BRIND:
22586909Simp    if (SDNode *ResNode = SelectBRIND(N))
22686909Simp      return ResNode;
22786909Simp    break;
22886909Simp  // Other cases are autogenerated.
22986909Simp  }
23086909Simp  return SelectCode(N);
23186909Simp}
23286909Simp
23386909Simp/// Given a chain return a new chain where any appearance of Old is replaced
234120189Sbde/// by New. There must be at most one instruction between Old and Chain and
23586909Simp/// this instruction must be a TokenFactor. Returns an empty SDValue if
23686909Simp/// these conditions don't hold.
23786909Simpstatic SDValue
23886909SimpreplaceInChain(SelectionDAG *CurDAG, SDValue Chain, SDValue Old, SDValue New)
23986909Simp{
24086909Simp  if (Chain == Old)
24186909Simp    return New;
24286909Simp  if (Chain->getOpcode() != ISD::TokenFactor)
24386909Simp    return SDValue();
24486909Simp  SmallVector<SDValue, 8> Ops;
245111613Sphk  bool found = false;
246119485Snjl  for (unsigned i = 0, e = Chain->getNumOperands(); i != e; ++i) {
247119485Snjl    if (Chain->getOperand(i) == Old) {
248119485Snjl      Ops.push_back(New);
24986909Simp      found = true;
25086909Simp    } else {
25186909Simp      Ops.push_back(Chain->getOperand(i));
25286909Simp    }
25386909Simp  }
25486909Simp  if (!found)
25589986Sjhay    return SDValue();
25689986Sjhay  return CurDAG->getNode(ISD::TokenFactor, Chain->getDebugLoc(), MVT::Other,
25786909Simp                         &Ops[0], Ops.size());
25886909Simp}
259116120Sscottl
260116120SscottlSDNode *XCoreDAGToDAGISel::SelectBRIND(SDNode *N) {
261130585Sphk  DebugLoc dl = N->getDebugLoc();
26286909Simp  // (brind (int_xcore_checkevent (addr)))
26386909Simp  SDValue Chain = N->getOperand(0);
26486909Simp  SDValue Addr = N->getOperand(1);
26586909Simp  if (Addr->getOpcode() != ISD::INTRINSIC_W_CHAIN)
26686909Simp    return 0;
26786909Simp  unsigned IntNo = cast<ConstantSDNode>(Addr->getOperand(1))->getZExtValue();
26886909Simp  if (IntNo != Intrinsic::xcore_checkevent)
26986909Simp    return 0;
27086909Simp  SDValue nextAddr = Addr->getOperand(2);
27186909Simp  SDValue CheckEventChainOut(Addr.getNode(), 1);
27293010Sbde  if (!CheckEventChainOut.use_empty()) {
27351078Speter    // If the chain out of the checkevent intrinsic is an operand of the
27451078Speter    // indirect branch or used in a TokenFactor which is the operand of the
275131373Sphk    // indirect branch then build a new chain which uses the chain coming into
27651078Speter    // the checkevent intrinsic instead.
27793010Sbde    SDValue CheckEventChainIn = Addr->getOperand(0);
27893010Sbde    SDValue NewChain = replaceInChain(CurDAG, Chain, CheckEventChainOut,
27993010Sbde                                      CheckEventChainIn);
28093010Sbde    if (!NewChain.getNode())
28193010Sbde      return 0;
282131094Sphk    Chain = NewChain;
28393010Sbde  }
28493010Sbde  // Enable events on the thread using setsr 1 and then disable them immediately
28593010Sbde  // after with clrsr 1. If any resources owned by the thread are ready an event
28693010Sbde  // will be taken. If no resource is ready we branch to the address which was
28793010Sbde  // the operand to the checkevent intrinsic.
28893010Sbde  SDValue constOne = getI32Imm(1);
28951078Speter  SDValue Glue =
29051078Speter    SDValue(CurDAG->getMachineNode(XCore::SETSR_branch_u6, dl, MVT::Glue,
29185365Simp                                   constOne, Chain), 0);
29270174Sjhb  Glue =
29370174Sjhb    SDValue(CurDAG->getMachineNode(XCore::CLRSR_branch_u6, dl, MVT::Glue,
29451078Speter                                   constOne, Glue), 0);
29551078Speter  if (nextAddr->getOpcode() == XCoreISD::PCRelativeWrapper &&
29685365Simp      nextAddr->getOperand(0)->getOpcode() == ISD::TargetBlockAddress) {
29751078Speter    return CurDAG->SelectNodeTo(N, XCore::BRFU_lu6, MVT::Other,
29886909Simp                                nextAddr->getOperand(0), Glue);
29951078Speter  }
30051078Speter  return CurDAG->SelectNodeTo(N, XCore::BAU_1r, MVT::Other, nextAddr, Glue);
30151078Speter}
30251078Speter