XCoreISelDAGToDAG.cpp revision 251662
1//===-- XCoreISelDAGToDAG.cpp - A dag to dag inst selector for XCore ------===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file defines an instruction selector for the XCore target.
11//
12//===----------------------------------------------------------------------===//
13
14#include "XCore.h"
15#include "XCoreTargetMachine.h"
16#include "llvm/CodeGen/MachineFrameInfo.h"
17#include "llvm/CodeGen/MachineFunction.h"
18#include "llvm/CodeGen/MachineInstrBuilder.h"
19#include "llvm/CodeGen/MachineRegisterInfo.h"
20#include "llvm/CodeGen/SelectionDAG.h"
21#include "llvm/CodeGen/SelectionDAGISel.h"
22#include "llvm/IR/CallingConv.h"
23#include "llvm/IR/Constants.h"
24#include "llvm/IR/DerivedTypes.h"
25#include "llvm/IR/Function.h"
26#include "llvm/IR/Intrinsics.h"
27#include "llvm/IR/LLVMContext.h"
28#include "llvm/Support/Compiler.h"
29#include "llvm/Support/Debug.h"
30#include "llvm/Support/ErrorHandling.h"
31#include "llvm/Support/raw_ostream.h"
32#include "llvm/Target/TargetLowering.h"
33using namespace llvm;
34
35/// XCoreDAGToDAGISel - XCore specific code to select XCore machine
36/// instructions for SelectionDAG operations.
37///
38namespace {
39  class XCoreDAGToDAGISel : public SelectionDAGISel {
40    const XCoreTargetLowering &Lowering;
41    const XCoreSubtarget &Subtarget;
42
43  public:
44    XCoreDAGToDAGISel(XCoreTargetMachine &TM, CodeGenOpt::Level OptLevel)
45      : SelectionDAGISel(TM, OptLevel),
46        Lowering(*TM.getTargetLowering()),
47        Subtarget(*TM.getSubtargetImpl()) { }
48
49    SDNode *Select(SDNode *N);
50    SDNode *SelectBRIND(SDNode *N);
51
52    /// getI32Imm - Return a target constant with the specified value, of type
53    /// i32.
54    inline SDValue getI32Imm(unsigned Imm) {
55      return CurDAG->getTargetConstant(Imm, MVT::i32);
56    }
57
58    inline bool immMskBitp(SDNode *inN) const {
59      ConstantSDNode *N = cast<ConstantSDNode>(inN);
60      uint32_t value = (uint32_t)N->getZExtValue();
61      if (!isMask_32(value)) {
62        return false;
63      }
64      int msksize = 32 - CountLeadingZeros_32(value);
65      return (msksize >= 1 && msksize <= 8) ||
66              msksize == 16 || msksize == 24 || msksize == 32;
67    }
68
69    // Complex Pattern Selectors.
70    bool SelectADDRspii(SDValue Addr, SDValue &Base, SDValue &Offset);
71
72    virtual const char *getPassName() const {
73      return "XCore DAG->DAG Pattern Instruction Selection";
74    }
75
76    // Include the pieces autogenerated from the target description.
77  #include "XCoreGenDAGISel.inc"
78  };
79}  // end anonymous namespace
80
81/// createXCoreISelDag - This pass converts a legalized DAG into a
82/// XCore-specific DAG, ready for instruction scheduling.
83///
84FunctionPass *llvm::createXCoreISelDag(XCoreTargetMachine &TM,
85                                       CodeGenOpt::Level OptLevel) {
86  return new XCoreDAGToDAGISel(TM, OptLevel);
87}
88
89bool XCoreDAGToDAGISel::SelectADDRspii(SDValue Addr, SDValue &Base,
90                                       SDValue &Offset) {
91  FrameIndexSDNode *FIN = 0;
92  if ((FIN = dyn_cast<FrameIndexSDNode>(Addr))) {
93    Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i32);
94    Offset = CurDAG->getTargetConstant(0, MVT::i32);
95    return true;
96  }
97  if (Addr.getOpcode() == ISD::ADD) {
98    ConstantSDNode *CN = 0;
99    if ((FIN = dyn_cast<FrameIndexSDNode>(Addr.getOperand(0)))
100      && (CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1)))
101      && (CN->getSExtValue() % 4 == 0 && CN->getSExtValue() >= 0)) {
102      // Constant positive word offset from frame index
103      Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i32);
104      Offset = CurDAG->getTargetConstant(CN->getSExtValue(), MVT::i32);
105      return true;
106    }
107  }
108  return false;
109}
110
111SDNode *XCoreDAGToDAGISel::Select(SDNode *N) {
112  DebugLoc dl = N->getDebugLoc();
113  switch (N->getOpcode()) {
114  default: break;
115  case ISD::Constant: {
116    uint64_t Val = cast<ConstantSDNode>(N)->getZExtValue();
117    if (immMskBitp(N)) {
118      // Transformation function: get the size of a mask
119      // Look for the first non-zero bit
120      SDValue MskSize = getI32Imm(32 - CountLeadingZeros_32(Val));
121      return CurDAG->getMachineNode(XCore::MKMSK_rus, dl,
122                                    MVT::i32, MskSize);
123    }
124    else if (!isUInt<16>(Val)) {
125      SDValue CPIdx =
126        CurDAG->getTargetConstantPool(ConstantInt::get(
127                              Type::getInt32Ty(*CurDAG->getContext()), Val),
128                                      TLI.getPointerTy());
129      SDNode *node = CurDAG->getMachineNode(XCore::LDWCP_lru6, dl, MVT::i32,
130                                            MVT::Other, CPIdx,
131                                            CurDAG->getEntryNode());
132      MachineSDNode::mmo_iterator MemOp = MF->allocateMemRefsArray(1);
133      MemOp[0] = MF->getMachineMemOperand(
134        MachinePointerInfo::getConstantPool(), MachineMemOperand::MOLoad, 4, 4);
135      cast<MachineSDNode>(node)->setMemRefs(MemOp, MemOp + 1);
136      return node;
137    }
138    break;
139  }
140  case XCoreISD::LADD: {
141    SDValue Ops[] = { N->getOperand(0), N->getOperand(1),
142                        N->getOperand(2) };
143    return CurDAG->getMachineNode(XCore::LADD_l5r, dl, MVT::i32, MVT::i32,
144                                  Ops);
145  }
146  case XCoreISD::LSUB: {
147    SDValue Ops[] = { N->getOperand(0), N->getOperand(1),
148                        N->getOperand(2) };
149    return CurDAG->getMachineNode(XCore::LSUB_l5r, dl, MVT::i32, MVT::i32,
150                                  Ops);
151  }
152  case XCoreISD::MACCU: {
153    SDValue Ops[] = { N->getOperand(0), N->getOperand(1),
154                      N->getOperand(2), N->getOperand(3) };
155    return CurDAG->getMachineNode(XCore::MACCU_l4r, dl, MVT::i32, MVT::i32,
156                                  Ops);
157  }
158  case XCoreISD::MACCS: {
159    SDValue Ops[] = { N->getOperand(0), N->getOperand(1),
160                      N->getOperand(2), N->getOperand(3) };
161    return CurDAG->getMachineNode(XCore::MACCS_l4r, dl, MVT::i32, MVT::i32,
162                                  Ops);
163  }
164  case XCoreISD::LMUL: {
165    SDValue Ops[] = { N->getOperand(0), N->getOperand(1),
166                      N->getOperand(2), N->getOperand(3) };
167    return CurDAG->getMachineNode(XCore::LMUL_l6r, dl, MVT::i32, MVT::i32,
168                                  Ops);
169  }
170  case XCoreISD::CRC8: {
171    SDValue Ops[] = { N->getOperand(0), N->getOperand(1), N->getOperand(2) };
172    return CurDAG->getMachineNode(XCore::CRC8_l4r, dl, MVT::i32, MVT::i32,
173                                  Ops);
174  }
175  case ISD::BRIND:
176    if (SDNode *ResNode = SelectBRIND(N))
177      return ResNode;
178    break;
179  // Other cases are autogenerated.
180  }
181  return SelectCode(N);
182}
183
184/// Given a chain return a new chain where any appearance of Old is replaced
185/// by New. There must be at most one instruction between Old and Chain and
186/// this instruction must be a TokenFactor. Returns an empty SDValue if
187/// these conditions don't hold.
188static SDValue
189replaceInChain(SelectionDAG *CurDAG, SDValue Chain, SDValue Old, SDValue New)
190{
191  if (Chain == Old)
192    return New;
193  if (Chain->getOpcode() != ISD::TokenFactor)
194    return SDValue();
195  SmallVector<SDValue, 8> Ops;
196  bool found = false;
197  for (unsigned i = 0, e = Chain->getNumOperands(); i != e; ++i) {
198    if (Chain->getOperand(i) == Old) {
199      Ops.push_back(New);
200      found = true;
201    } else {
202      Ops.push_back(Chain->getOperand(i));
203    }
204  }
205  if (!found)
206    return SDValue();
207  return CurDAG->getNode(ISD::TokenFactor, Chain->getDebugLoc(), MVT::Other,
208                         &Ops[0], Ops.size());
209}
210
211SDNode *XCoreDAGToDAGISel::SelectBRIND(SDNode *N) {
212  DebugLoc dl = N->getDebugLoc();
213  // (brind (int_xcore_checkevent (addr)))
214  SDValue Chain = N->getOperand(0);
215  SDValue Addr = N->getOperand(1);
216  if (Addr->getOpcode() != ISD::INTRINSIC_W_CHAIN)
217    return 0;
218  unsigned IntNo = cast<ConstantSDNode>(Addr->getOperand(1))->getZExtValue();
219  if (IntNo != Intrinsic::xcore_checkevent)
220    return 0;
221  SDValue nextAddr = Addr->getOperand(2);
222  SDValue CheckEventChainOut(Addr.getNode(), 1);
223  if (!CheckEventChainOut.use_empty()) {
224    // If the chain out of the checkevent intrinsic is an operand of the
225    // indirect branch or used in a TokenFactor which is the operand of the
226    // indirect branch then build a new chain which uses the chain coming into
227    // the checkevent intrinsic instead.
228    SDValue CheckEventChainIn = Addr->getOperand(0);
229    SDValue NewChain = replaceInChain(CurDAG, Chain, CheckEventChainOut,
230                                      CheckEventChainIn);
231    if (!NewChain.getNode())
232      return 0;
233    Chain = NewChain;
234  }
235  // Enable events on the thread using setsr 1 and then disable them immediately
236  // after with clrsr 1. If any resources owned by the thread are ready an event
237  // will be taken. If no resource is ready we branch to the address which was
238  // the operand to the checkevent intrinsic.
239  SDValue constOne = getI32Imm(1);
240  SDValue Glue =
241    SDValue(CurDAG->getMachineNode(XCore::SETSR_branch_u6, dl, MVT::Glue,
242                                   constOne, Chain), 0);
243  Glue =
244    SDValue(CurDAG->getMachineNode(XCore::CLRSR_branch_u6, dl, MVT::Glue,
245                                   constOne, Glue), 0);
246  if (nextAddr->getOpcode() == XCoreISD::PCRelativeWrapper &&
247      nextAddr->getOperand(0)->getOpcode() == ISD::TargetBlockAddress) {
248    return CurDAG->SelectNodeTo(N, XCore::BRFU_lu6, MVT::Other,
249                                nextAddr->getOperand(0), Glue);
250  }
251  return CurDAG->SelectNodeTo(N, XCore::BAU_1r, MVT::Other, nextAddr, Glue);
252}
253