ARMISelDAGToDAG.cpp revision a4e64359aafaf23e440e9dc171859daef1995f1b
1//===-- ARMISelDAGToDAG.cpp - A dag to dag inst selector for ARM ----------===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file was developed by Chris Lattner and is distributed under
6// the University of Illinois Open Source License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file defines an instruction selector for the ARM target.
11//
12//===----------------------------------------------------------------------===//
13
14#include "ARM.h"
15#include "ARMTargetMachine.h"
16#include "llvm/DerivedTypes.h"
17#include "llvm/Function.h"
18#include "llvm/Intrinsics.h"
19#include "llvm/CodeGen/MachineFrameInfo.h"
20#include "llvm/CodeGen/MachineFunction.h"
21#include "llvm/CodeGen/MachineInstrBuilder.h"
22#include "llvm/CodeGen/SelectionDAG.h"
23#include "llvm/CodeGen/SelectionDAGISel.h"
24#include "llvm/CodeGen/SSARegMap.h"
25#include "llvm/Target/TargetLowering.h"
26#include "llvm/Support/Debug.h"
27#include <iostream>
28#include <set>
29using namespace llvm;
30
31namespace {
32  class ARMTargetLowering : public TargetLowering {
33  public:
34    ARMTargetLowering(TargetMachine &TM);
35    virtual SDOperand LowerOperation(SDOperand Op, SelectionDAG &DAG);
36  };
37
38}
39
40ARMTargetLowering::ARMTargetLowering(TargetMachine &TM)
41  : TargetLowering(TM) {
42  setOperationAction(ISD::RET, MVT::Other, Custom);
43}
44
45static SDOperand LowerCALL(SDOperand Op, SelectionDAG &DAG) {
46  assert(0 && "Not implemented");
47  abort();
48}
49
50static SDOperand LowerRET(SDOperand Op, SelectionDAG &DAG) {
51  SDOperand Copy;
52  SDOperand Chain = Op.getOperand(0);
53  switch(Op.getNumOperands()) {
54  default:
55    assert(0 && "Do not know how to return this many arguments!");
56    abort();
57  case 1: {
58    SDOperand LR = DAG.getRegister(ARM::R14, MVT::i32);
59    return DAG.getNode(ISD::BRIND, MVT::Other, Chain, LR);
60  }
61  case 3:
62    Copy = DAG.getCopyToReg(Chain, ARM::R0, Op.getOperand(1), SDOperand());
63    if (DAG.getMachineFunction().liveout_empty())
64      DAG.getMachineFunction().addLiveOut(ARM::R0);
65    break;
66  }
67
68  SDOperand LR = DAG.getRegister(ARM::R14, MVT::i32);
69
70  //bug: the copy and branch should be linked with a flag so that the
71  //scheduller can't move an instruction that destroys R0 in between them
72  //return DAG.getNode(ISD::BRIND, MVT::Other, Copy, LR, Copy.getValue(1));
73
74  return DAG.getNode(ISD::BRIND, MVT::Other, Copy, LR);
75}
76
77static SDOperand LowerFORMAL_ARGUMENT(SDOperand Op, SelectionDAG &DAG,
78				      unsigned ArgNo) {
79  MachineFunction &MF = DAG.getMachineFunction();
80  MVT::ValueType ObjectVT = Op.getValue(ArgNo).getValueType();
81  assert (ObjectVT == MVT::i32);
82  SDOperand Root = Op.getOperand(0);
83  SSARegMap *RegMap = MF.getSSARegMap();
84
85  unsigned num_regs = 4;
86  static const unsigned REGS[] = {
87    ARM::R0, ARM::R1, ARM::R2, ARM::R3
88  };
89
90  if(ArgNo < num_regs) {
91    unsigned VReg = RegMap->createVirtualRegister(&ARM::IntRegsRegClass);
92    MF.addLiveIn(REGS[ArgNo], VReg);
93    return DAG.getCopyFromReg(Root, VReg, MVT::i32);
94  } else {
95    // If the argument is actually used, emit a load from the right stack
96      // slot.
97    if (!Op.Val->hasNUsesOfValue(0, ArgNo)) {
98      unsigned ArgOffset = (ArgNo - num_regs) * 4;
99
100      MachineFrameInfo *MFI = MF.getFrameInfo();
101      unsigned ObjSize = MVT::getSizeInBits(ObjectVT)/8;
102      int FI = MFI->CreateFixedObject(ObjSize, ArgOffset);
103      SDOperand FIN = DAG.getFrameIndex(FI, MVT::i32);
104      return DAG.getLoad(ObjectVT, Root, FIN,
105			 DAG.getSrcValue(NULL));
106    } else {
107      // Don't emit a dead load.
108      return DAG.getNode(ISD::UNDEF, ObjectVT);
109    }
110  }
111}
112
113static SDOperand LowerFORMAL_ARGUMENTS(SDOperand Op, SelectionDAG &DAG) {
114  std::vector<SDOperand> ArgValues;
115  SDOperand Root = Op.getOperand(0);
116
117  for (unsigned ArgNo = 0, e = Op.Val->getNumValues()-1; ArgNo != e; ++ArgNo) {
118    SDOperand ArgVal = LowerFORMAL_ARGUMENT(Op, DAG, ArgNo);
119
120    ArgValues.push_back(ArgVal);
121  }
122
123  bool isVarArg = cast<ConstantSDNode>(Op.getOperand(2))->getValue() != 0;
124  assert(!isVarArg);
125
126  ArgValues.push_back(Root);
127
128  // Return the new list of results.
129  std::vector<MVT::ValueType> RetVT(Op.Val->value_begin(),
130                                    Op.Val->value_end());
131  return DAG.getNode(ISD::MERGE_VALUES, RetVT, ArgValues);
132}
133
134SDOperand ARMTargetLowering::LowerOperation(SDOperand Op, SelectionDAG &DAG) {
135  switch (Op.getOpcode()) {
136  default:
137    assert(0 && "Should not custom lower this!");
138    abort();
139  case ISD::FORMAL_ARGUMENTS:
140    return LowerFORMAL_ARGUMENTS(Op, DAG);
141  case ISD::CALL:
142    return LowerCALL(Op, DAG);
143  case ISD::RET:
144    return LowerRET(Op, DAG);
145  }
146}
147
148//===----------------------------------------------------------------------===//
149// Instruction Selector Implementation
150//===----------------------------------------------------------------------===//
151
152//===--------------------------------------------------------------------===//
153/// ARMDAGToDAGISel - ARM specific code to select ARM machine
154/// instructions for SelectionDAG operations.
155///
156namespace {
157class ARMDAGToDAGISel : public SelectionDAGISel {
158  ARMTargetLowering Lowering;
159
160public:
161  ARMDAGToDAGISel(TargetMachine &TM)
162    : SelectionDAGISel(Lowering), Lowering(TM) {
163  }
164
165  void Select(SDOperand &Result, SDOperand Op);
166  virtual void InstructionSelectBasicBlock(SelectionDAG &DAG);
167  bool SelectAddrRegImm(SDOperand N, SDOperand &Offset, SDOperand &Base);
168
169  // Include the pieces autogenerated from the target description.
170#include "ARMGenDAGISel.inc"
171};
172
173void ARMDAGToDAGISel::InstructionSelectBasicBlock(SelectionDAG &DAG) {
174  DEBUG(BB->dump());
175
176  DAG.setRoot(SelectRoot(DAG.getRoot()));
177  assert(InFlightSet.empty() && "ISel InFlightSet has not been emptied!");
178  CodeGenMap.clear();
179  HandleMap.clear();
180  ReplaceMap.clear();
181  DAG.RemoveDeadNodes();
182
183  ScheduleAndEmitDAG(DAG);
184}
185
186//register plus/minus 12 bit offset
187bool ARMDAGToDAGISel::SelectAddrRegImm(SDOperand N, SDOperand &Offset,
188				    SDOperand &Base) {
189  Offset = CurDAG->getTargetConstant(0, MVT::i32);
190  if (FrameIndexSDNode *FI = dyn_cast<FrameIndexSDNode>(N)) {
191    Base = CurDAG->getTargetFrameIndex(FI->getIndex(), N.getValueType());
192  }
193  else
194    Base = N;
195  return true;      //any address fits in a register
196}
197
198void ARMDAGToDAGISel::Select(SDOperand &Result, SDOperand Op) {
199  SDNode *N = Op.Val;
200
201  switch (N->getOpcode()) {
202  default:
203    SelectCode(Result, Op);
204    break;
205  }
206}
207
208}  // end anonymous namespace
209
210/// createARMISelDag - This pass converts a legalized DAG into a
211/// ARM-specific DAG, ready for instruction scheduling.
212///
213FunctionPass *llvm::createARMISelDag(TargetMachine &TM) {
214  return new ARMDAGToDAGISel(TM);
215}
216