blob: d6cbc601fe08404a554d456c18fb404e49d4eb1f [file] [log] [blame]
Rafael Espindola7bc59bc2006-05-14 22:18:28 +00001//===-- ARMISelDAGToDAG.cpp - A dag to dag inst selector for ARM ----------===//
2//
3// The LLVM Compiler Infrastructure
4//
Chris Lattner4ee451d2007-12-29 20:36:04 +00005// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
Rafael Espindola7bc59bc2006-05-14 22:18:28 +00007//
8//===----------------------------------------------------------------------===//
9//
10// This file defines an instruction selector for the ARM target.
11//
12//===----------------------------------------------------------------------===//
13
14#include "ARM.h"
Evan Chenge5ad88e2008-12-10 21:54:21 +000015#include "ARMAddressingModes.h"
Evan Chenga8e29892007-01-19 07:51:42 +000016#include "ARMISelLowering.h"
Rafael Espindola7bc59bc2006-05-14 22:18:28 +000017#include "ARMTargetMachine.h"
Rafael Espindola84b19be2006-07-16 01:02:57 +000018#include "llvm/CallingConv.h"
Evan Chenga8e29892007-01-19 07:51:42 +000019#include "llvm/Constants.h"
Rafael Espindola7bc59bc2006-05-14 22:18:28 +000020#include "llvm/DerivedTypes.h"
21#include "llvm/Function.h"
22#include "llvm/Intrinsics.h"
Owen Anderson9adc0ab2009-07-14 23:09:55 +000023#include "llvm/LLVMContext.h"
Rafael Espindola7bc59bc2006-05-14 22:18:28 +000024#include "llvm/CodeGen/MachineFrameInfo.h"
25#include "llvm/CodeGen/MachineFunction.h"
26#include "llvm/CodeGen/MachineInstrBuilder.h"
27#include "llvm/CodeGen/SelectionDAG.h"
28#include "llvm/CodeGen/SelectionDAGISel.h"
Rafael Espindola7bc59bc2006-05-14 22:18:28 +000029#include "llvm/Target/TargetLowering.h"
Chris Lattner72939122007-05-03 00:32:00 +000030#include "llvm/Target/TargetOptions.h"
Chris Lattner3d62d782008-02-03 05:43:57 +000031#include "llvm/Support/Compiler.h"
Rafael Espindola7bc59bc2006-05-14 22:18:28 +000032#include "llvm/Support/Debug.h"
Torok Edwindac237e2009-07-08 20:53:28 +000033#include "llvm/Support/ErrorHandling.h"
34#include "llvm/Support/raw_ostream.h"
35
Rafael Espindola7bc59bc2006-05-14 22:18:28 +000036using namespace llvm;
37
Rafael Espindola7bc59bc2006-05-14 22:18:28 +000038//===--------------------------------------------------------------------===//
39/// ARMDAGToDAGISel - ARM specific code to select ARM machine
40/// instructions for SelectionDAG operations.
41///
42namespace {
43class ARMDAGToDAGISel : public SelectionDAGISel {
Anton Korobeynikovd49ea772009-06-26 21:28:53 +000044 ARMBaseTargetMachine &TM;
Evan Cheng3f7eb8e2008-09-18 07:24:33 +000045
Evan Chenga8e29892007-01-19 07:51:42 +000046 /// Subtarget - Keep a pointer to the ARMSubtarget around so that we can
47 /// make the right decision when generating code for different targets.
48 const ARMSubtarget *Subtarget;
49
Rafael Espindola7bc59bc2006-05-14 22:18:28 +000050public:
Bob Wilson522ce972009-09-28 14:30:20 +000051 explicit ARMDAGToDAGISel(ARMBaseTargetMachine &tm,
52 CodeGenOpt::Level OptLevel)
53 : SelectionDAGISel(tm, OptLevel), TM(tm),
Evan Chenga8e29892007-01-19 07:51:42 +000054 Subtarget(&TM.getSubtarget<ARMSubtarget>()) {
Rafael Espindola7bc59bc2006-05-14 22:18:28 +000055 }
56
Evan Chenga8e29892007-01-19 07:51:42 +000057 virtual const char *getPassName() const {
58 return "ARM Instruction Selection";
Anton Korobeynikov52237112009-06-17 18:13:58 +000059 }
60
Bob Wilsonaf4a8912009-10-08 18:51:31 +000061 /// getI32Imm - Return a target constant of type i32 with the specified
62 /// value.
Anton Korobeynikov52237112009-06-17 18:13:58 +000063 inline SDValue getI32Imm(unsigned Imm) {
Owen Anderson825b72b2009-08-11 20:47:22 +000064 return CurDAG->getTargetConstant(Imm, MVT::i32);
Anton Korobeynikov52237112009-06-17 18:13:58 +000065 }
66
Dan Gohmaneeb3a002010-01-05 01:24:18 +000067 SDNode *Select(SDNode *N);
Evan Cheng014bf212010-02-15 19:41:07 +000068
Dan Gohmaneeb3a002010-01-05 01:24:18 +000069 bool SelectShifterOperandReg(SDNode *Op, SDValue N, SDValue &A,
Evan Cheng055b0312009-06-29 07:51:04 +000070 SDValue &B, SDValue &C);
Dan Gohmaneeb3a002010-01-05 01:24:18 +000071 bool SelectAddrMode2(SDNode *Op, SDValue N, SDValue &Base,
Dan Gohman475871a2008-07-27 21:46:04 +000072 SDValue &Offset, SDValue &Opc);
Dan Gohmaneeb3a002010-01-05 01:24:18 +000073 bool SelectAddrMode2Offset(SDNode *Op, SDValue N,
Dan Gohman475871a2008-07-27 21:46:04 +000074 SDValue &Offset, SDValue &Opc);
Dan Gohmaneeb3a002010-01-05 01:24:18 +000075 bool SelectAddrMode3(SDNode *Op, SDValue N, SDValue &Base,
Dan Gohman475871a2008-07-27 21:46:04 +000076 SDValue &Offset, SDValue &Opc);
Dan Gohmaneeb3a002010-01-05 01:24:18 +000077 bool SelectAddrMode3Offset(SDNode *Op, SDValue N,
Dan Gohman475871a2008-07-27 21:46:04 +000078 SDValue &Offset, SDValue &Opc);
Dan Gohmaneeb3a002010-01-05 01:24:18 +000079 bool SelectAddrMode4(SDNode *Op, SDValue N, SDValue &Addr,
Anton Korobeynikovbaf31082009-08-08 13:35:48 +000080 SDValue &Mode);
Dan Gohmaneeb3a002010-01-05 01:24:18 +000081 bool SelectAddrMode5(SDNode *Op, SDValue N, SDValue &Base,
Dan Gohman475871a2008-07-27 21:46:04 +000082 SDValue &Offset);
Bob Wilson226036e2010-03-20 22:13:40 +000083 bool SelectAddrMode6(SDNode *Op, SDValue N, SDValue &Addr, SDValue &Align);
Rafael Espindola7bc59bc2006-05-14 22:18:28 +000084
Dan Gohmaneeb3a002010-01-05 01:24:18 +000085 bool SelectAddrModePC(SDNode *Op, SDValue N, SDValue &Offset,
Bob Wilson8b024a52009-07-01 23:16:05 +000086 SDValue &Label);
Evan Chenga8e29892007-01-19 07:51:42 +000087
Dan Gohmaneeb3a002010-01-05 01:24:18 +000088 bool SelectThumbAddrModeRR(SDNode *Op, SDValue N, SDValue &Base,
Dan Gohman475871a2008-07-27 21:46:04 +000089 SDValue &Offset);
Dan Gohmaneeb3a002010-01-05 01:24:18 +000090 bool SelectThumbAddrModeRI5(SDNode *Op, SDValue N, unsigned Scale,
Dan Gohman475871a2008-07-27 21:46:04 +000091 SDValue &Base, SDValue &OffImm,
92 SDValue &Offset);
Dan Gohmaneeb3a002010-01-05 01:24:18 +000093 bool SelectThumbAddrModeS1(SDNode *Op, SDValue N, SDValue &Base,
Dan Gohman475871a2008-07-27 21:46:04 +000094 SDValue &OffImm, SDValue &Offset);
Dan Gohmaneeb3a002010-01-05 01:24:18 +000095 bool SelectThumbAddrModeS2(SDNode *Op, SDValue N, SDValue &Base,
Dan Gohman475871a2008-07-27 21:46:04 +000096 SDValue &OffImm, SDValue &Offset);
Dan Gohmaneeb3a002010-01-05 01:24:18 +000097 bool SelectThumbAddrModeS4(SDNode *Op, SDValue N, SDValue &Base,
Dan Gohman475871a2008-07-27 21:46:04 +000098 SDValue &OffImm, SDValue &Offset);
Dan Gohmaneeb3a002010-01-05 01:24:18 +000099 bool SelectThumbAddrModeSP(SDNode *Op, SDValue N, SDValue &Base,
Dan Gohman475871a2008-07-27 21:46:04 +0000100 SDValue &OffImm);
Evan Chenga8e29892007-01-19 07:51:42 +0000101
Dan Gohmaneeb3a002010-01-05 01:24:18 +0000102 bool SelectT2ShifterOperandReg(SDNode *Op, SDValue N,
Evan Cheng9cb9e672009-06-27 02:26:13 +0000103 SDValue &BaseReg, SDValue &Opc);
Dan Gohmaneeb3a002010-01-05 01:24:18 +0000104 bool SelectT2AddrModeImm12(SDNode *Op, SDValue N, SDValue &Base,
Evan Cheng055b0312009-06-29 07:51:04 +0000105 SDValue &OffImm);
Dan Gohmaneeb3a002010-01-05 01:24:18 +0000106 bool SelectT2AddrModeImm8(SDNode *Op, SDValue N, SDValue &Base,
Evan Cheng055b0312009-06-29 07:51:04 +0000107 SDValue &OffImm);
Dan Gohmaneeb3a002010-01-05 01:24:18 +0000108 bool SelectT2AddrModeImm8Offset(SDNode *Op, SDValue N,
Evan Chenge88d5ce2009-07-02 07:28:31 +0000109 SDValue &OffImm);
Dan Gohmaneeb3a002010-01-05 01:24:18 +0000110 bool SelectT2AddrModeImm8s4(SDNode *Op, SDValue N, SDValue &Base,
David Goodwin6647cea2009-06-30 22:50:01 +0000111 SDValue &OffImm);
Dan Gohmaneeb3a002010-01-05 01:24:18 +0000112 bool SelectT2AddrModeSoReg(SDNode *Op, SDValue N, SDValue &Base,
Evan Cheng055b0312009-06-29 07:51:04 +0000113 SDValue &OffReg, SDValue &ShImm);
114
Rafael Espindola7bc59bc2006-05-14 22:18:28 +0000115 // Include the pieces autogenerated from the target description.
116#include "ARMGenDAGISel.inc"
Bob Wilson224c2442009-05-19 05:53:42 +0000117
118private:
Evan Chenge88d5ce2009-07-02 07:28:31 +0000119 /// SelectARMIndexedLoad - Indexed (pre/post inc/dec) load matching code for
120 /// ARM.
Dan Gohmaneeb3a002010-01-05 01:24:18 +0000121 SDNode *SelectARMIndexedLoad(SDNode *N);
122 SDNode *SelectT2IndexedLoad(SDNode *N);
Evan Chenge88d5ce2009-07-02 07:28:31 +0000123
Bob Wilson621f1952010-03-23 05:25:43 +0000124 /// SelectVLD - Select NEON load intrinsics. NumVecs should be
125 /// 1, 2, 3 or 4. The opcode arrays specify the instructions used for
Bob Wilson3e36f132009-10-14 17:28:52 +0000126 /// loads of D registers and even subregs and odd subregs of Q registers.
Bob Wilson621f1952010-03-23 05:25:43 +0000127 /// For NumVecs <= 2, QOpcodes1 is not used.
Dan Gohmaneeb3a002010-01-05 01:24:18 +0000128 SDNode *SelectVLD(SDNode *N, unsigned NumVecs, unsigned *DOpcodes,
Bob Wilson3e36f132009-10-14 17:28:52 +0000129 unsigned *QOpcodes0, unsigned *QOpcodes1);
130
Bob Wilson24f995d2009-10-14 18:32:29 +0000131 /// SelectVST - Select NEON store intrinsics. NumVecs should
Bob Wilson11d98992010-03-23 06:20:33 +0000132 /// be 1, 2, 3 or 4. The opcode arrays specify the instructions used for
Bob Wilson24f995d2009-10-14 18:32:29 +0000133 /// stores of D registers and even subregs and odd subregs of Q registers.
Bob Wilson11d98992010-03-23 06:20:33 +0000134 /// For NumVecs <= 2, QOpcodes1 is not used.
Dan Gohmaneeb3a002010-01-05 01:24:18 +0000135 SDNode *SelectVST(SDNode *N, unsigned NumVecs, unsigned *DOpcodes,
Bob Wilson24f995d2009-10-14 18:32:29 +0000136 unsigned *QOpcodes0, unsigned *QOpcodes1);
137
Bob Wilson96493442009-10-14 16:46:45 +0000138 /// SelectVLDSTLane - Select NEON load/store lane intrinsics. NumVecs should
Bob Wilsona7c397c2009-10-14 16:19:03 +0000139 /// be 2, 3 or 4. The opcode arrays specify the instructions used for
Bob Wilson96493442009-10-14 16:46:45 +0000140 /// load/store of D registers and even subregs and odd subregs of Q registers.
Dan Gohmaneeb3a002010-01-05 01:24:18 +0000141 SDNode *SelectVLDSTLane(SDNode *N, bool IsLoad, unsigned NumVecs,
Bob Wilson96493442009-10-14 16:46:45 +0000142 unsigned *DOpcodes, unsigned *QOpcodes0,
143 unsigned *QOpcodes1);
Bob Wilsona7c397c2009-10-14 16:19:03 +0000144
Sandeep Patel4e1ed882009-10-13 20:25:58 +0000145 /// SelectV6T2BitfieldExtractOp - Select SBFX/UBFX instructions for ARM.
Dan Gohmaneeb3a002010-01-05 01:24:18 +0000146 SDNode *SelectV6T2BitfieldExtractOp(SDNode *N, unsigned Opc);
Sandeep Patel47eedaa2009-10-13 18:59:48 +0000147
Evan Cheng07ba9062009-11-19 21:45:22 +0000148 /// SelectCMOVOp - Select CMOV instructions for ARM.
Dan Gohmaneeb3a002010-01-05 01:24:18 +0000149 SDNode *SelectCMOVOp(SDNode *N);
150 SDNode *SelectT2CMOVShiftOp(SDNode *N, SDValue FalseVal, SDValue TrueVal,
Evan Cheng9ef48352009-11-20 00:54:03 +0000151 ARMCC::CondCodes CCVal, SDValue CCR,
152 SDValue InFlag);
Dan Gohmaneeb3a002010-01-05 01:24:18 +0000153 SDNode *SelectARMCMOVShiftOp(SDNode *N, SDValue FalseVal, SDValue TrueVal,
Evan Cheng9ef48352009-11-20 00:54:03 +0000154 ARMCC::CondCodes CCVal, SDValue CCR,
155 SDValue InFlag);
Dan Gohmaneeb3a002010-01-05 01:24:18 +0000156 SDNode *SelectT2CMOVSoImmOp(SDNode *N, SDValue FalseVal, SDValue TrueVal,
Evan Cheng9ef48352009-11-20 00:54:03 +0000157 ARMCC::CondCodes CCVal, SDValue CCR,
158 SDValue InFlag);
Dan Gohmaneeb3a002010-01-05 01:24:18 +0000159 SDNode *SelectARMCMOVSoImmOp(SDNode *N, SDValue FalseVal, SDValue TrueVal,
Evan Cheng9ef48352009-11-20 00:54:03 +0000160 ARMCC::CondCodes CCVal, SDValue CCR,
161 SDValue InFlag);
Evan Cheng07ba9062009-11-19 21:45:22 +0000162
Evan Chengaf4550f2009-07-02 01:23:32 +0000163 /// SelectInlineAsmMemoryOperand - Implement addressing mode selection for
164 /// inline asm expressions.
165 virtual bool SelectInlineAsmMemoryOperand(const SDValue &Op,
166 char ConstraintCode,
167 std::vector<SDValue> &OutOps);
Bob Wilson3bf12ab2009-10-06 22:01:59 +0000168
169 /// PairDRegs - Insert a pair of double registers into an implicit def to
170 /// form a quad register.
171 SDNode *PairDRegs(EVT VT, SDValue V0, SDValue V1);
Rafael Espindola7bc59bc2006-05-14 22:18:28 +0000172};
Evan Chenga8e29892007-01-19 07:51:42 +0000173}
Rafael Espindola7bc59bc2006-05-14 22:18:28 +0000174
Sandeep Patel47eedaa2009-10-13 18:59:48 +0000175/// isInt32Immediate - This method tests to see if the node is a 32-bit constant
176/// operand. If so Imm will receive the 32-bit value.
177static bool isInt32Immediate(SDNode *N, unsigned &Imm) {
178 if (N->getOpcode() == ISD::Constant && N->getValueType(0) == MVT::i32) {
179 Imm = cast<ConstantSDNode>(N)->getZExtValue();
180 return true;
181 }
182 return false;
183}
184
185// isInt32Immediate - This method tests to see if a constant operand.
186// If so Imm will receive the 32 bit value.
187static bool isInt32Immediate(SDValue N, unsigned &Imm) {
188 return isInt32Immediate(N.getNode(), Imm);
189}
190
191// isOpcWithIntImmediate - This method tests to see if the node is a specific
192// opcode and that it has a immediate integer right operand.
193// If so Imm will receive the 32 bit value.
194static bool isOpcWithIntImmediate(SDNode *N, unsigned Opc, unsigned& Imm) {
195 return N->getOpcode() == Opc &&
196 isInt32Immediate(N->getOperand(1).getNode(), Imm);
197}
198
199
Dan Gohmaneeb3a002010-01-05 01:24:18 +0000200bool ARMDAGToDAGISel::SelectShifterOperandReg(SDNode *Op,
Evan Cheng055b0312009-06-29 07:51:04 +0000201 SDValue N,
202 SDValue &BaseReg,
203 SDValue &ShReg,
204 SDValue &Opc) {
205 ARM_AM::ShiftOpc ShOpcVal = ARM_AM::getShiftOpcForNode(N);
206
207 // Don't match base register only case. That is matched to a separate
208 // lower complexity pattern with explicit register operand.
209 if (ShOpcVal == ARM_AM::no_shift) return false;
Jim Grosbach764ab522009-08-11 15:33:49 +0000210
Evan Cheng055b0312009-06-29 07:51:04 +0000211 BaseReg = N.getOperand(0);
212 unsigned ShImmVal = 0;
213 if (ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(N.getOperand(1))) {
Owen Anderson825b72b2009-08-11 20:47:22 +0000214 ShReg = CurDAG->getRegister(0, MVT::i32);
Evan Cheng055b0312009-06-29 07:51:04 +0000215 ShImmVal = RHS->getZExtValue() & 31;
216 } else {
217 ShReg = N.getOperand(1);
218 }
219 Opc = CurDAG->getTargetConstant(ARM_AM::getSORegOpc(ShOpcVal, ShImmVal),
Owen Anderson825b72b2009-08-11 20:47:22 +0000220 MVT::i32);
Evan Cheng055b0312009-06-29 07:51:04 +0000221 return true;
222}
223
Dan Gohmaneeb3a002010-01-05 01:24:18 +0000224bool ARMDAGToDAGISel::SelectAddrMode2(SDNode *Op, SDValue N,
Dan Gohman475871a2008-07-27 21:46:04 +0000225 SDValue &Base, SDValue &Offset,
226 SDValue &Opc) {
Evan Chenga13fd102007-03-13 21:05:54 +0000227 if (N.getOpcode() == ISD::MUL) {
228 if (ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(N.getOperand(1))) {
229 // X * [3,5,9] -> X + X * [2,4,8] etc.
Dan Gohmanf5aeb1a2008-09-12 16:56:44 +0000230 int RHSC = (int)RHS->getZExtValue();
Evan Chenga13fd102007-03-13 21:05:54 +0000231 if (RHSC & 1) {
232 RHSC = RHSC & ~1;
233 ARM_AM::AddrOpc AddSub = ARM_AM::add;
234 if (RHSC < 0) {
235 AddSub = ARM_AM::sub;
236 RHSC = - RHSC;
237 }
238 if (isPowerOf2_32(RHSC)) {
239 unsigned ShAmt = Log2_32(RHSC);
240 Base = Offset = N.getOperand(0);
241 Opc = CurDAG->getTargetConstant(ARM_AM::getAM2Opc(AddSub, ShAmt,
242 ARM_AM::lsl),
Owen Anderson825b72b2009-08-11 20:47:22 +0000243 MVT::i32);
Evan Chenga13fd102007-03-13 21:05:54 +0000244 return true;
245 }
246 }
247 }
248 }
249
Evan Chenga8e29892007-01-19 07:51:42 +0000250 if (N.getOpcode() != ISD::ADD && N.getOpcode() != ISD::SUB) {
251 Base = N;
252 if (N.getOpcode() == ISD::FrameIndex) {
253 int FI = cast<FrameIndexSDNode>(N)->getIndex();
254 Base = CurDAG->getTargetFrameIndex(FI, TLI.getPointerTy());
Anton Korobeynikov5cdc3a92009-11-24 00:44:37 +0000255 } else if (N.getOpcode() == ARMISD::Wrapper &&
256 !(Subtarget->useMovt() &&
257 N.getOperand(0).getOpcode() == ISD::TargetGlobalAddress)) {
Evan Chenga8e29892007-01-19 07:51:42 +0000258 Base = N.getOperand(0);
259 }
Owen Anderson825b72b2009-08-11 20:47:22 +0000260 Offset = CurDAG->getRegister(0, MVT::i32);
Evan Chenga8e29892007-01-19 07:51:42 +0000261 Opc = CurDAG->getTargetConstant(ARM_AM::getAM2Opc(ARM_AM::add, 0,
262 ARM_AM::no_shift),
Owen Anderson825b72b2009-08-11 20:47:22 +0000263 MVT::i32);
Rafael Espindola6e8c6492006-11-08 17:07:32 +0000264 return true;
265 }
Jim Grosbach764ab522009-08-11 15:33:49 +0000266
Evan Chenga8e29892007-01-19 07:51:42 +0000267 // Match simple R +/- imm12 operands.
268 if (N.getOpcode() == ISD::ADD)
269 if (ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(N.getOperand(1))) {
Dan Gohmanf5aeb1a2008-09-12 16:56:44 +0000270 int RHSC = (int)RHS->getZExtValue();
Evan Chenge966d642007-01-24 02:45:25 +0000271 if ((RHSC >= 0 && RHSC < 0x1000) ||
272 (RHSC < 0 && RHSC > -0x1000)) { // 12 bits.
Evan Chenga8e29892007-01-19 07:51:42 +0000273 Base = N.getOperand(0);
Evan Chenge966d642007-01-24 02:45:25 +0000274 if (Base.getOpcode() == ISD::FrameIndex) {
275 int FI = cast<FrameIndexSDNode>(Base)->getIndex();
276 Base = CurDAG->getTargetFrameIndex(FI, TLI.getPointerTy());
277 }
Owen Anderson825b72b2009-08-11 20:47:22 +0000278 Offset = CurDAG->getRegister(0, MVT::i32);
Evan Chenge966d642007-01-24 02:45:25 +0000279
280 ARM_AM::AddrOpc AddSub = ARM_AM::add;
281 if (RHSC < 0) {
282 AddSub = ARM_AM::sub;
283 RHSC = - RHSC;
284 }
285 Opc = CurDAG->getTargetConstant(ARM_AM::getAM2Opc(AddSub, RHSC,
Evan Chenga8e29892007-01-19 07:51:42 +0000286 ARM_AM::no_shift),
Owen Anderson825b72b2009-08-11 20:47:22 +0000287 MVT::i32);
Evan Chenga8e29892007-01-19 07:51:42 +0000288 return true;
Rafael Espindola6e8c6492006-11-08 17:07:32 +0000289 }
Evan Chenga8e29892007-01-19 07:51:42 +0000290 }
Jim Grosbach764ab522009-08-11 15:33:49 +0000291
Johnny Chen6a3b5ee2009-10-27 17:25:15 +0000292 // Otherwise this is R +/- [possibly shifted] R.
Evan Chenga8e29892007-01-19 07:51:42 +0000293 ARM_AM::AddrOpc AddSub = N.getOpcode() == ISD::ADD ? ARM_AM::add:ARM_AM::sub;
294 ARM_AM::ShiftOpc ShOpcVal = ARM_AM::getShiftOpcForNode(N.getOperand(1));
295 unsigned ShAmt = 0;
Jim Grosbach764ab522009-08-11 15:33:49 +0000296
Evan Chenga8e29892007-01-19 07:51:42 +0000297 Base = N.getOperand(0);
298 Offset = N.getOperand(1);
Jim Grosbach764ab522009-08-11 15:33:49 +0000299
Evan Chenga8e29892007-01-19 07:51:42 +0000300 if (ShOpcVal != ARM_AM::no_shift) {
301 // Check to see if the RHS of the shift is a constant, if not, we can't fold
302 // it.
303 if (ConstantSDNode *Sh =
304 dyn_cast<ConstantSDNode>(N.getOperand(1).getOperand(1))) {
Dan Gohmanf5aeb1a2008-09-12 16:56:44 +0000305 ShAmt = Sh->getZExtValue();
Evan Chenga8e29892007-01-19 07:51:42 +0000306 Offset = N.getOperand(1).getOperand(0);
307 } else {
308 ShOpcVal = ARM_AM::no_shift;
Rafael Espindola6e8c6492006-11-08 17:07:32 +0000309 }
310 }
Jim Grosbach764ab522009-08-11 15:33:49 +0000311
Evan Chenga8e29892007-01-19 07:51:42 +0000312 // Try matching (R shl C) + (R).
313 if (N.getOpcode() == ISD::ADD && ShOpcVal == ARM_AM::no_shift) {
314 ShOpcVal = ARM_AM::getShiftOpcForNode(N.getOperand(0));
315 if (ShOpcVal != ARM_AM::no_shift) {
316 // Check to see if the RHS of the shift is a constant, if not, we can't
317 // fold it.
318 if (ConstantSDNode *Sh =
319 dyn_cast<ConstantSDNode>(N.getOperand(0).getOperand(1))) {
Dan Gohmanf5aeb1a2008-09-12 16:56:44 +0000320 ShAmt = Sh->getZExtValue();
Evan Chenga8e29892007-01-19 07:51:42 +0000321 Offset = N.getOperand(0).getOperand(0);
322 Base = N.getOperand(1);
323 } else {
324 ShOpcVal = ARM_AM::no_shift;
325 }
326 }
327 }
Jim Grosbach764ab522009-08-11 15:33:49 +0000328
Evan Chenga8e29892007-01-19 07:51:42 +0000329 Opc = CurDAG->getTargetConstant(ARM_AM::getAM2Opc(AddSub, ShAmt, ShOpcVal),
Owen Anderson825b72b2009-08-11 20:47:22 +0000330 MVT::i32);
Rafael Espindola6e8c6492006-11-08 17:07:32 +0000331 return true;
332}
333
Dan Gohmaneeb3a002010-01-05 01:24:18 +0000334bool ARMDAGToDAGISel::SelectAddrMode2Offset(SDNode *Op, SDValue N,
Dan Gohman475871a2008-07-27 21:46:04 +0000335 SDValue &Offset, SDValue &Opc) {
Dan Gohmaneeb3a002010-01-05 01:24:18 +0000336 unsigned Opcode = Op->getOpcode();
Evan Chenga8e29892007-01-19 07:51:42 +0000337 ISD::MemIndexedMode AM = (Opcode == ISD::LOAD)
338 ? cast<LoadSDNode>(Op)->getAddressingMode()
339 : cast<StoreSDNode>(Op)->getAddressingMode();
340 ARM_AM::AddrOpc AddSub = (AM == ISD::PRE_INC || AM == ISD::POST_INC)
341 ? ARM_AM::add : ARM_AM::sub;
342 if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(N)) {
Dan Gohmanf5aeb1a2008-09-12 16:56:44 +0000343 int Val = (int)C->getZExtValue();
Evan Chenga8e29892007-01-19 07:51:42 +0000344 if (Val >= 0 && Val < 0x1000) { // 12 bits.
Owen Anderson825b72b2009-08-11 20:47:22 +0000345 Offset = CurDAG->getRegister(0, MVT::i32);
Evan Chenga8e29892007-01-19 07:51:42 +0000346 Opc = CurDAG->getTargetConstant(ARM_AM::getAM2Opc(AddSub, Val,
347 ARM_AM::no_shift),
Owen Anderson825b72b2009-08-11 20:47:22 +0000348 MVT::i32);
Evan Chenga8e29892007-01-19 07:51:42 +0000349 return true;
350 }
351 }
352
353 Offset = N;
354 ARM_AM::ShiftOpc ShOpcVal = ARM_AM::getShiftOpcForNode(N);
355 unsigned ShAmt = 0;
356 if (ShOpcVal != ARM_AM::no_shift) {
357 // Check to see if the RHS of the shift is a constant, if not, we can't fold
358 // it.
359 if (ConstantSDNode *Sh = dyn_cast<ConstantSDNode>(N.getOperand(1))) {
Dan Gohmanf5aeb1a2008-09-12 16:56:44 +0000360 ShAmt = Sh->getZExtValue();
Evan Chenga8e29892007-01-19 07:51:42 +0000361 Offset = N.getOperand(0);
362 } else {
363 ShOpcVal = ARM_AM::no_shift;
364 }
365 }
366
367 Opc = CurDAG->getTargetConstant(ARM_AM::getAM2Opc(AddSub, ShAmt, ShOpcVal),
Owen Anderson825b72b2009-08-11 20:47:22 +0000368 MVT::i32);
Rafael Espindola32bd5f42006-10-17 18:04:53 +0000369 return true;
370}
371
Evan Chenga8e29892007-01-19 07:51:42 +0000372
Dan Gohmaneeb3a002010-01-05 01:24:18 +0000373bool ARMDAGToDAGISel::SelectAddrMode3(SDNode *Op, SDValue N,
Dan Gohman475871a2008-07-27 21:46:04 +0000374 SDValue &Base, SDValue &Offset,
375 SDValue &Opc) {
Evan Chenga8e29892007-01-19 07:51:42 +0000376 if (N.getOpcode() == ISD::SUB) {
377 // X - C is canonicalize to X + -C, no need to handle it here.
378 Base = N.getOperand(0);
379 Offset = N.getOperand(1);
Owen Anderson825b72b2009-08-11 20:47:22 +0000380 Opc = CurDAG->getTargetConstant(ARM_AM::getAM3Opc(ARM_AM::sub, 0),MVT::i32);
Evan Chenga8e29892007-01-19 07:51:42 +0000381 return true;
382 }
Jim Grosbach764ab522009-08-11 15:33:49 +0000383
Evan Chenga8e29892007-01-19 07:51:42 +0000384 if (N.getOpcode() != ISD::ADD) {
385 Base = N;
386 if (N.getOpcode() == ISD::FrameIndex) {
387 int FI = cast<FrameIndexSDNode>(N)->getIndex();
388 Base = CurDAG->getTargetFrameIndex(FI, TLI.getPointerTy());
389 }
Owen Anderson825b72b2009-08-11 20:47:22 +0000390 Offset = CurDAG->getRegister(0, MVT::i32);
391 Opc = CurDAG->getTargetConstant(ARM_AM::getAM3Opc(ARM_AM::add, 0),MVT::i32);
Evan Chenga8e29892007-01-19 07:51:42 +0000392 return true;
393 }
Jim Grosbach764ab522009-08-11 15:33:49 +0000394
Evan Chenga8e29892007-01-19 07:51:42 +0000395 // If the RHS is +/- imm8, fold into addr mode.
396 if (ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(N.getOperand(1))) {
Dan Gohmanf5aeb1a2008-09-12 16:56:44 +0000397 int RHSC = (int)RHS->getZExtValue();
Evan Chenge966d642007-01-24 02:45:25 +0000398 if ((RHSC >= 0 && RHSC < 256) ||
399 (RHSC < 0 && RHSC > -256)) { // note -256 itself isn't allowed.
Evan Chenga8e29892007-01-19 07:51:42 +0000400 Base = N.getOperand(0);
Evan Chenge966d642007-01-24 02:45:25 +0000401 if (Base.getOpcode() == ISD::FrameIndex) {
402 int FI = cast<FrameIndexSDNode>(Base)->getIndex();
403 Base = CurDAG->getTargetFrameIndex(FI, TLI.getPointerTy());
404 }
Owen Anderson825b72b2009-08-11 20:47:22 +0000405 Offset = CurDAG->getRegister(0, MVT::i32);
Evan Chenge966d642007-01-24 02:45:25 +0000406
407 ARM_AM::AddrOpc AddSub = ARM_AM::add;
408 if (RHSC < 0) {
409 AddSub = ARM_AM::sub;
410 RHSC = - RHSC;
411 }
Owen Anderson825b72b2009-08-11 20:47:22 +0000412 Opc = CurDAG->getTargetConstant(ARM_AM::getAM3Opc(AddSub, RHSC),MVT::i32);
Evan Chenga8e29892007-01-19 07:51:42 +0000413 return true;
414 }
415 }
Jim Grosbach764ab522009-08-11 15:33:49 +0000416
Evan Chenga8e29892007-01-19 07:51:42 +0000417 Base = N.getOperand(0);
418 Offset = N.getOperand(1);
Owen Anderson825b72b2009-08-11 20:47:22 +0000419 Opc = CurDAG->getTargetConstant(ARM_AM::getAM3Opc(ARM_AM::add, 0), MVT::i32);
Evan Chenga8e29892007-01-19 07:51:42 +0000420 return true;
421}
422
Dan Gohmaneeb3a002010-01-05 01:24:18 +0000423bool ARMDAGToDAGISel::SelectAddrMode3Offset(SDNode *Op, SDValue N,
Dan Gohman475871a2008-07-27 21:46:04 +0000424 SDValue &Offset, SDValue &Opc) {
Dan Gohmaneeb3a002010-01-05 01:24:18 +0000425 unsigned Opcode = Op->getOpcode();
Evan Chenga8e29892007-01-19 07:51:42 +0000426 ISD::MemIndexedMode AM = (Opcode == ISD::LOAD)
427 ? cast<LoadSDNode>(Op)->getAddressingMode()
428 : cast<StoreSDNode>(Op)->getAddressingMode();
429 ARM_AM::AddrOpc AddSub = (AM == ISD::PRE_INC || AM == ISD::POST_INC)
430 ? ARM_AM::add : ARM_AM::sub;
431 if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(N)) {
Dan Gohmanf5aeb1a2008-09-12 16:56:44 +0000432 int Val = (int)C->getZExtValue();
Evan Chenga8e29892007-01-19 07:51:42 +0000433 if (Val >= 0 && Val < 256) {
Owen Anderson825b72b2009-08-11 20:47:22 +0000434 Offset = CurDAG->getRegister(0, MVT::i32);
435 Opc = CurDAG->getTargetConstant(ARM_AM::getAM3Opc(AddSub, Val), MVT::i32);
Evan Chenga8e29892007-01-19 07:51:42 +0000436 return true;
437 }
438 }
439
440 Offset = N;
Owen Anderson825b72b2009-08-11 20:47:22 +0000441 Opc = CurDAG->getTargetConstant(ARM_AM::getAM3Opc(AddSub, 0), MVT::i32);
Evan Chenga8e29892007-01-19 07:51:42 +0000442 return true;
443}
444
Dan Gohmaneeb3a002010-01-05 01:24:18 +0000445bool ARMDAGToDAGISel::SelectAddrMode4(SDNode *Op, SDValue N,
Anton Korobeynikovbaf31082009-08-08 13:35:48 +0000446 SDValue &Addr, SDValue &Mode) {
447 Addr = N;
Owen Anderson825b72b2009-08-11 20:47:22 +0000448 Mode = CurDAG->getTargetConstant(0, MVT::i32);
Anton Korobeynikovbaf31082009-08-08 13:35:48 +0000449 return true;
450}
Evan Chenga8e29892007-01-19 07:51:42 +0000451
Dan Gohmaneeb3a002010-01-05 01:24:18 +0000452bool ARMDAGToDAGISel::SelectAddrMode5(SDNode *Op, SDValue N,
Dan Gohman475871a2008-07-27 21:46:04 +0000453 SDValue &Base, SDValue &Offset) {
Evan Chenga8e29892007-01-19 07:51:42 +0000454 if (N.getOpcode() != ISD::ADD) {
455 Base = N;
456 if (N.getOpcode() == ISD::FrameIndex) {
457 int FI = cast<FrameIndexSDNode>(N)->getIndex();
458 Base = CurDAG->getTargetFrameIndex(FI, TLI.getPointerTy());
Anton Korobeynikov5cdc3a92009-11-24 00:44:37 +0000459 } else if (N.getOpcode() == ARMISD::Wrapper &&
460 !(Subtarget->useMovt() &&
461 N.getOperand(0).getOpcode() == ISD::TargetGlobalAddress)) {
Evan Chenga8e29892007-01-19 07:51:42 +0000462 Base = N.getOperand(0);
463 }
464 Offset = CurDAG->getTargetConstant(ARM_AM::getAM5Opc(ARM_AM::add, 0),
Owen Anderson825b72b2009-08-11 20:47:22 +0000465 MVT::i32);
Evan Chenga8e29892007-01-19 07:51:42 +0000466 return true;
467 }
Jim Grosbach764ab522009-08-11 15:33:49 +0000468
Evan Chenga8e29892007-01-19 07:51:42 +0000469 // If the RHS is +/- imm8, fold into addr mode.
470 if (ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(N.getOperand(1))) {
Dan Gohmanf5aeb1a2008-09-12 16:56:44 +0000471 int RHSC = (int)RHS->getZExtValue();
Evan Chenga8e29892007-01-19 07:51:42 +0000472 if ((RHSC & 3) == 0) { // The constant is implicitly multiplied by 4.
473 RHSC >>= 2;
Evan Chenge966d642007-01-24 02:45:25 +0000474 if ((RHSC >= 0 && RHSC < 256) ||
475 (RHSC < 0 && RHSC > -256)) { // note -256 itself isn't allowed.
Evan Chenga8e29892007-01-19 07:51:42 +0000476 Base = N.getOperand(0);
Evan Chenge966d642007-01-24 02:45:25 +0000477 if (Base.getOpcode() == ISD::FrameIndex) {
478 int FI = cast<FrameIndexSDNode>(Base)->getIndex();
479 Base = CurDAG->getTargetFrameIndex(FI, TLI.getPointerTy());
480 }
481
482 ARM_AM::AddrOpc AddSub = ARM_AM::add;
483 if (RHSC < 0) {
484 AddSub = ARM_AM::sub;
485 RHSC = - RHSC;
486 }
487 Offset = CurDAG->getTargetConstant(ARM_AM::getAM5Opc(AddSub, RHSC),
Owen Anderson825b72b2009-08-11 20:47:22 +0000488 MVT::i32);
Evan Chenga8e29892007-01-19 07:51:42 +0000489 return true;
490 }
491 }
492 }
Jim Grosbach764ab522009-08-11 15:33:49 +0000493
Evan Chenga8e29892007-01-19 07:51:42 +0000494 Base = N;
495 Offset = CurDAG->getTargetConstant(ARM_AM::getAM5Opc(ARM_AM::add, 0),
Owen Anderson825b72b2009-08-11 20:47:22 +0000496 MVT::i32);
Evan Chenga8e29892007-01-19 07:51:42 +0000497 return true;
498}
499
Dan Gohmaneeb3a002010-01-05 01:24:18 +0000500bool ARMDAGToDAGISel::SelectAddrMode6(SDNode *Op, SDValue N,
Bob Wilson226036e2010-03-20 22:13:40 +0000501 SDValue &Addr, SDValue &Align) {
Bob Wilson8b024a52009-07-01 23:16:05 +0000502 Addr = N;
Jim Grosbach8a5ec862009-11-07 21:25:39 +0000503 // Default to no alignment.
504 Align = CurDAG->getTargetConstant(0, MVT::i32);
Bob Wilson8b024a52009-07-01 23:16:05 +0000505 return true;
506}
507
Dan Gohmaneeb3a002010-01-05 01:24:18 +0000508bool ARMDAGToDAGISel::SelectAddrModePC(SDNode *Op, SDValue N,
Evan Chengbba9f5f2009-08-14 19:01:37 +0000509 SDValue &Offset, SDValue &Label) {
Evan Chenga8e29892007-01-19 07:51:42 +0000510 if (N.getOpcode() == ARMISD::PIC_ADD && N.hasOneUse()) {
511 Offset = N.getOperand(0);
Dan Gohman475871a2008-07-27 21:46:04 +0000512 SDValue N1 = N.getOperand(1);
Dan Gohmanf5aeb1a2008-09-12 16:56:44 +0000513 Label = CurDAG->getTargetConstant(cast<ConstantSDNode>(N1)->getZExtValue(),
Owen Anderson825b72b2009-08-11 20:47:22 +0000514 MVT::i32);
Evan Chenga8e29892007-01-19 07:51:42 +0000515 return true;
516 }
517 return false;
518}
519
Dan Gohmaneeb3a002010-01-05 01:24:18 +0000520bool ARMDAGToDAGISel::SelectThumbAddrModeRR(SDNode *Op, SDValue N,
Dan Gohman475871a2008-07-27 21:46:04 +0000521 SDValue &Base, SDValue &Offset){
Dale Johannesenf5f5dce2009-02-06 19:16:40 +0000522 // FIXME dl should come from the parent load or store, not the address
Dan Gohmaneeb3a002010-01-05 01:24:18 +0000523 DebugLoc dl = Op->getDebugLoc();
Evan Chengc38f2bc2007-01-23 22:59:13 +0000524 if (N.getOpcode() != ISD::ADD) {
Evan Cheng2f297df2009-07-11 07:08:13 +0000525 ConstantSDNode *NC = dyn_cast<ConstantSDNode>(N);
526 if (!NC || NC->getZExtValue() != 0)
527 return false;
528
529 Base = Offset = N;
Evan Chengc38f2bc2007-01-23 22:59:13 +0000530 return true;
531 }
532
Evan Chenga8e29892007-01-19 07:51:42 +0000533 Base = N.getOperand(0);
534 Offset = N.getOperand(1);
535 return true;
536}
537
Evan Cheng79d43262007-01-24 02:21:22 +0000538bool
Dan Gohmaneeb3a002010-01-05 01:24:18 +0000539ARMDAGToDAGISel::SelectThumbAddrModeRI5(SDNode *Op, SDValue N,
Dan Gohman475871a2008-07-27 21:46:04 +0000540 unsigned Scale, SDValue &Base,
541 SDValue &OffImm, SDValue &Offset) {
Evan Cheng79d43262007-01-24 02:21:22 +0000542 if (Scale == 4) {
Dan Gohman475871a2008-07-27 21:46:04 +0000543 SDValue TmpBase, TmpOffImm;
Evan Cheng79d43262007-01-24 02:21:22 +0000544 if (SelectThumbAddrModeSP(Op, N, TmpBase, TmpOffImm))
545 return false; // We want to select tLDRspi / tSTRspi instead.
Evan Cheng012f2d92007-01-24 08:53:17 +0000546 if (N.getOpcode() == ARMISD::Wrapper &&
547 N.getOperand(0).getOpcode() == ISD::TargetConstantPool)
548 return false; // We want to select tLDRpci instead.
Evan Cheng79d43262007-01-24 02:21:22 +0000549 }
550
Evan Chenga8e29892007-01-19 07:51:42 +0000551 if (N.getOpcode() != ISD::ADD) {
Anton Korobeynikov5cdc3a92009-11-24 00:44:37 +0000552 if (N.getOpcode() == ARMISD::Wrapper &&
553 !(Subtarget->useMovt() &&
554 N.getOperand(0).getOpcode() == ISD::TargetGlobalAddress)) {
555 Base = N.getOperand(0);
556 } else
557 Base = N;
558
Owen Anderson825b72b2009-08-11 20:47:22 +0000559 Offset = CurDAG->getRegister(0, MVT::i32);
560 OffImm = CurDAG->getTargetConstant(0, MVT::i32);
Evan Chenga8e29892007-01-19 07:51:42 +0000561 return true;
562 }
563
Evan Chengad0e4652007-02-06 00:22:06 +0000564 // Thumb does not have [sp, r] address mode.
565 RegisterSDNode *LHSR = dyn_cast<RegisterSDNode>(N.getOperand(0));
566 RegisterSDNode *RHSR = dyn_cast<RegisterSDNode>(N.getOperand(1));
567 if ((LHSR && LHSR->getReg() == ARM::SP) ||
568 (RHSR && RHSR->getReg() == ARM::SP)) {
569 Base = N;
Owen Anderson825b72b2009-08-11 20:47:22 +0000570 Offset = CurDAG->getRegister(0, MVT::i32);
571 OffImm = CurDAG->getTargetConstant(0, MVT::i32);
Evan Chengad0e4652007-02-06 00:22:06 +0000572 return true;
573 }
574
Evan Chenga8e29892007-01-19 07:51:42 +0000575 // If the RHS is + imm5 * scale, fold into addr mode.
576 if (ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(N.getOperand(1))) {
Dan Gohmanf5aeb1a2008-09-12 16:56:44 +0000577 int RHSC = (int)RHS->getZExtValue();
Evan Chenga8e29892007-01-19 07:51:42 +0000578 if ((RHSC & (Scale-1)) == 0) { // The constant is implicitly multiplied.
579 RHSC /= Scale;
580 if (RHSC >= 0 && RHSC < 32) {
581 Base = N.getOperand(0);
Owen Anderson825b72b2009-08-11 20:47:22 +0000582 Offset = CurDAG->getRegister(0, MVT::i32);
583 OffImm = CurDAG->getTargetConstant(RHSC, MVT::i32);
Evan Chenga8e29892007-01-19 07:51:42 +0000584 return true;
585 }
586 }
587 }
588
Evan Chengc38f2bc2007-01-23 22:59:13 +0000589 Base = N.getOperand(0);
590 Offset = N.getOperand(1);
Owen Anderson825b72b2009-08-11 20:47:22 +0000591 OffImm = CurDAG->getTargetConstant(0, MVT::i32);
Evan Chengc38f2bc2007-01-23 22:59:13 +0000592 return true;
Evan Chenga8e29892007-01-19 07:51:42 +0000593}
594
Dan Gohmaneeb3a002010-01-05 01:24:18 +0000595bool ARMDAGToDAGISel::SelectThumbAddrModeS1(SDNode *Op, SDValue N,
Dan Gohman475871a2008-07-27 21:46:04 +0000596 SDValue &Base, SDValue &OffImm,
597 SDValue &Offset) {
Evan Chengcea117d2007-01-30 02:35:32 +0000598 return SelectThumbAddrModeRI5(Op, N, 1, Base, OffImm, Offset);
Evan Chenga8e29892007-01-19 07:51:42 +0000599}
600
Dan Gohmaneeb3a002010-01-05 01:24:18 +0000601bool ARMDAGToDAGISel::SelectThumbAddrModeS2(SDNode *Op, SDValue N,
Dan Gohman475871a2008-07-27 21:46:04 +0000602 SDValue &Base, SDValue &OffImm,
603 SDValue &Offset) {
Evan Chengcea117d2007-01-30 02:35:32 +0000604 return SelectThumbAddrModeRI5(Op, N, 2, Base, OffImm, Offset);
Evan Chenga8e29892007-01-19 07:51:42 +0000605}
606
Dan Gohmaneeb3a002010-01-05 01:24:18 +0000607bool ARMDAGToDAGISel::SelectThumbAddrModeS4(SDNode *Op, SDValue N,
Dan Gohman475871a2008-07-27 21:46:04 +0000608 SDValue &Base, SDValue &OffImm,
609 SDValue &Offset) {
Evan Chengcea117d2007-01-30 02:35:32 +0000610 return SelectThumbAddrModeRI5(Op, N, 4, Base, OffImm, Offset);
Evan Chenga8e29892007-01-19 07:51:42 +0000611}
612
Dan Gohmaneeb3a002010-01-05 01:24:18 +0000613bool ARMDAGToDAGISel::SelectThumbAddrModeSP(SDNode *Op, SDValue N,
Dan Gohman475871a2008-07-27 21:46:04 +0000614 SDValue &Base, SDValue &OffImm) {
Evan Chenga8e29892007-01-19 07:51:42 +0000615 if (N.getOpcode() == ISD::FrameIndex) {
616 int FI = cast<FrameIndexSDNode>(N)->getIndex();
617 Base = CurDAG->getTargetFrameIndex(FI, TLI.getPointerTy());
Owen Anderson825b72b2009-08-11 20:47:22 +0000618 OffImm = CurDAG->getTargetConstant(0, MVT::i32);
Evan Chenga8e29892007-01-19 07:51:42 +0000619 return true;
620 }
Evan Cheng79d43262007-01-24 02:21:22 +0000621
Evan Chengad0e4652007-02-06 00:22:06 +0000622 if (N.getOpcode() != ISD::ADD)
623 return false;
624
625 RegisterSDNode *LHSR = dyn_cast<RegisterSDNode>(N.getOperand(0));
Evan Cheng8c1a73a2007-02-06 09:11:20 +0000626 if (N.getOperand(0).getOpcode() == ISD::FrameIndex ||
627 (LHSR && LHSR->getReg() == ARM::SP)) {
Evan Cheng79d43262007-01-24 02:21:22 +0000628 // If the RHS is + imm8 * scale, fold into addr mode.
629 if (ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(N.getOperand(1))) {
Dan Gohmanf5aeb1a2008-09-12 16:56:44 +0000630 int RHSC = (int)RHS->getZExtValue();
Evan Cheng79d43262007-01-24 02:21:22 +0000631 if ((RHSC & 3) == 0) { // The constant is implicitly multiplied.
632 RHSC >>= 2;
633 if (RHSC >= 0 && RHSC < 256) {
Evan Chengad0e4652007-02-06 00:22:06 +0000634 Base = N.getOperand(0);
Evan Cheng8c1a73a2007-02-06 09:11:20 +0000635 if (Base.getOpcode() == ISD::FrameIndex) {
636 int FI = cast<FrameIndexSDNode>(Base)->getIndex();
637 Base = CurDAG->getTargetFrameIndex(FI, TLI.getPointerTy());
638 }
Owen Anderson825b72b2009-08-11 20:47:22 +0000639 OffImm = CurDAG->getTargetConstant(RHSC, MVT::i32);
Evan Cheng79d43262007-01-24 02:21:22 +0000640 return true;
641 }
642 }
643 }
644 }
Jim Grosbach764ab522009-08-11 15:33:49 +0000645
Evan Chenga8e29892007-01-19 07:51:42 +0000646 return false;
647}
648
Dan Gohmaneeb3a002010-01-05 01:24:18 +0000649bool ARMDAGToDAGISel::SelectT2ShifterOperandReg(SDNode *Op, SDValue N,
Evan Cheng9cb9e672009-06-27 02:26:13 +0000650 SDValue &BaseReg,
651 SDValue &Opc) {
652 ARM_AM::ShiftOpc ShOpcVal = ARM_AM::getShiftOpcForNode(N);
653
654 // Don't match base register only case. That is matched to a separate
655 // lower complexity pattern with explicit register operand.
656 if (ShOpcVal == ARM_AM::no_shift) return false;
657
658 BaseReg = N.getOperand(0);
659 unsigned ShImmVal = 0;
660 if (ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(N.getOperand(1))) {
661 ShImmVal = RHS->getZExtValue() & 31;
662 Opc = getI32Imm(ARM_AM::getSORegOpc(ShOpcVal, ShImmVal));
663 return true;
664 }
665
666 return false;
667}
668
Dan Gohmaneeb3a002010-01-05 01:24:18 +0000669bool ARMDAGToDAGISel::SelectT2AddrModeImm12(SDNode *Op, SDValue N,
Evan Cheng055b0312009-06-29 07:51:04 +0000670 SDValue &Base, SDValue &OffImm) {
671 // Match simple R + imm12 operands.
David Goodwin31e7eba2009-07-20 15:55:39 +0000672
Evan Cheng3a214252009-08-11 08:52:18 +0000673 // Base only.
674 if (N.getOpcode() != ISD::ADD && N.getOpcode() != ISD::SUB) {
David Goodwin31e7eba2009-07-20 15:55:39 +0000675 if (N.getOpcode() == ISD::FrameIndex) {
Evan Cheng3a214252009-08-11 08:52:18 +0000676 // Match frame index...
David Goodwin31e7eba2009-07-20 15:55:39 +0000677 int FI = cast<FrameIndexSDNode>(N)->getIndex();
678 Base = CurDAG->getTargetFrameIndex(FI, TLI.getPointerTy());
Owen Anderson825b72b2009-08-11 20:47:22 +0000679 OffImm = CurDAG->getTargetConstant(0, MVT::i32);
David Goodwin31e7eba2009-07-20 15:55:39 +0000680 return true;
Anton Korobeynikov5cdc3a92009-11-24 00:44:37 +0000681 } else if (N.getOpcode() == ARMISD::Wrapper &&
682 !(Subtarget->useMovt() &&
683 N.getOperand(0).getOpcode() == ISD::TargetGlobalAddress)) {
Evan Cheng3a214252009-08-11 08:52:18 +0000684 Base = N.getOperand(0);
685 if (Base.getOpcode() == ISD::TargetConstantPool)
686 return false; // We want to select t2LDRpci instead.
687 } else
688 Base = N;
Owen Anderson825b72b2009-08-11 20:47:22 +0000689 OffImm = CurDAG->getTargetConstant(0, MVT::i32);
Evan Cheng3a214252009-08-11 08:52:18 +0000690 return true;
David Goodwin31e7eba2009-07-20 15:55:39 +0000691 }
Evan Cheng055b0312009-06-29 07:51:04 +0000692
693 if (ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(N.getOperand(1))) {
Evan Cheng3a214252009-08-11 08:52:18 +0000694 if (SelectT2AddrModeImm8(Op, N, Base, OffImm))
695 // Let t2LDRi8 handle (R - imm8).
696 return false;
697
Evan Cheng055b0312009-06-29 07:51:04 +0000698 int RHSC = (int)RHS->getZExtValue();
David Goodwind8c95b52009-07-30 18:56:48 +0000699 if (N.getOpcode() == ISD::SUB)
700 RHSC = -RHSC;
701
702 if (RHSC >= 0 && RHSC < 0x1000) { // 12 bits (unsigned)
Evan Cheng055b0312009-06-29 07:51:04 +0000703 Base = N.getOperand(0);
David Goodwind8c95b52009-07-30 18:56:48 +0000704 if (Base.getOpcode() == ISD::FrameIndex) {
705 int FI = cast<FrameIndexSDNode>(Base)->getIndex();
706 Base = CurDAG->getTargetFrameIndex(FI, TLI.getPointerTy());
707 }
Owen Anderson825b72b2009-08-11 20:47:22 +0000708 OffImm = CurDAG->getTargetConstant(RHSC, MVT::i32);
Evan Cheng055b0312009-06-29 07:51:04 +0000709 return true;
710 }
711 }
712
Evan Cheng3a214252009-08-11 08:52:18 +0000713 // Base only.
714 Base = N;
Owen Anderson825b72b2009-08-11 20:47:22 +0000715 OffImm = CurDAG->getTargetConstant(0, MVT::i32);
Evan Cheng3a214252009-08-11 08:52:18 +0000716 return true;
Evan Cheng055b0312009-06-29 07:51:04 +0000717}
718
Dan Gohmaneeb3a002010-01-05 01:24:18 +0000719bool ARMDAGToDAGISel::SelectT2AddrModeImm8(SDNode *Op, SDValue N,
Evan Cheng055b0312009-06-29 07:51:04 +0000720 SDValue &Base, SDValue &OffImm) {
David Goodwind8c95b52009-07-30 18:56:48 +0000721 // Match simple R - imm8 operands.
Evan Cheng3a214252009-08-11 08:52:18 +0000722 if (N.getOpcode() == ISD::ADD || N.getOpcode() == ISD::SUB) {
David Goodwin07337c02009-07-30 22:45:52 +0000723 if (ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(N.getOperand(1))) {
724 int RHSC = (int)RHS->getSExtValue();
725 if (N.getOpcode() == ISD::SUB)
726 RHSC = -RHSC;
Jim Grosbach764ab522009-08-11 15:33:49 +0000727
Evan Cheng3a214252009-08-11 08:52:18 +0000728 if ((RHSC >= -255) && (RHSC < 0)) { // 8 bits (always negative)
729 Base = N.getOperand(0);
David Goodwin07337c02009-07-30 22:45:52 +0000730 if (Base.getOpcode() == ISD::FrameIndex) {
731 int FI = cast<FrameIndexSDNode>(Base)->getIndex();
732 Base = CurDAG->getTargetFrameIndex(FI, TLI.getPointerTy());
733 }
Owen Anderson825b72b2009-08-11 20:47:22 +0000734 OffImm = CurDAG->getTargetConstant(RHSC, MVT::i32);
David Goodwin07337c02009-07-30 22:45:52 +0000735 return true;
Evan Cheng055b0312009-06-29 07:51:04 +0000736 }
Evan Cheng055b0312009-06-29 07:51:04 +0000737 }
738 }
739
740 return false;
741}
742
Dan Gohmaneeb3a002010-01-05 01:24:18 +0000743bool ARMDAGToDAGISel::SelectT2AddrModeImm8Offset(SDNode *Op, SDValue N,
Evan Chenge88d5ce2009-07-02 07:28:31 +0000744 SDValue &OffImm){
Dan Gohmaneeb3a002010-01-05 01:24:18 +0000745 unsigned Opcode = Op->getOpcode();
Evan Chenge88d5ce2009-07-02 07:28:31 +0000746 ISD::MemIndexedMode AM = (Opcode == ISD::LOAD)
747 ? cast<LoadSDNode>(Op)->getAddressingMode()
748 : cast<StoreSDNode>(Op)->getAddressingMode();
749 if (ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(N)) {
750 int RHSC = (int)RHS->getZExtValue();
751 if (RHSC >= 0 && RHSC < 0x100) { // 8 bits.
David Goodwin4cb73522009-07-14 21:29:29 +0000752 OffImm = ((AM == ISD::PRE_INC) || (AM == ISD::POST_INC))
Owen Anderson825b72b2009-08-11 20:47:22 +0000753 ? CurDAG->getTargetConstant(RHSC, MVT::i32)
754 : CurDAG->getTargetConstant(-RHSC, MVT::i32);
Evan Chenge88d5ce2009-07-02 07:28:31 +0000755 return true;
756 }
757 }
758
759 return false;
760}
761
Dan Gohmaneeb3a002010-01-05 01:24:18 +0000762bool ARMDAGToDAGISel::SelectT2AddrModeImm8s4(SDNode *Op, SDValue N,
David Goodwin6647cea2009-06-30 22:50:01 +0000763 SDValue &Base, SDValue &OffImm) {
764 if (N.getOpcode() == ISD::ADD) {
765 if (ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(N.getOperand(1))) {
766 int RHSC = (int)RHS->getZExtValue();
Evan Cheng5c874172009-07-09 22:21:59 +0000767 if (((RHSC & 0x3) == 0) &&
768 ((RHSC >= 0 && RHSC < 0x400) || (RHSC < 0 && RHSC > -0x400))) { // 8 bits.
David Goodwin6647cea2009-06-30 22:50:01 +0000769 Base = N.getOperand(0);
Owen Anderson825b72b2009-08-11 20:47:22 +0000770 OffImm = CurDAG->getTargetConstant(RHSC, MVT::i32);
David Goodwin6647cea2009-06-30 22:50:01 +0000771 return true;
772 }
773 }
774 } else if (N.getOpcode() == ISD::SUB) {
775 if (ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(N.getOperand(1))) {
776 int RHSC = (int)RHS->getZExtValue();
777 if (((RHSC & 0x3) == 0) && (RHSC >= 0 && RHSC < 0x400)) { // 8 bits.
778 Base = N.getOperand(0);
Owen Anderson825b72b2009-08-11 20:47:22 +0000779 OffImm = CurDAG->getTargetConstant(-RHSC, MVT::i32);
David Goodwin6647cea2009-06-30 22:50:01 +0000780 return true;
781 }
782 }
783 }
784
785 return false;
786}
787
Dan Gohmaneeb3a002010-01-05 01:24:18 +0000788bool ARMDAGToDAGISel::SelectT2AddrModeSoReg(SDNode *Op, SDValue N,
Evan Cheng055b0312009-06-29 07:51:04 +0000789 SDValue &Base,
790 SDValue &OffReg, SDValue &ShImm) {
Evan Cheng3a214252009-08-11 08:52:18 +0000791 // (R - imm8) should be handled by t2LDRi8. The rest are handled by t2LDRi12.
792 if (N.getOpcode() != ISD::ADD)
793 return false;
Evan Cheng055b0312009-06-29 07:51:04 +0000794
Evan Cheng3a214252009-08-11 08:52:18 +0000795 // Leave (R + imm12) for t2LDRi12, (R - imm8) for t2LDRi8.
796 if (ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(N.getOperand(1))) {
797 int RHSC = (int)RHS->getZExtValue();
798 if (RHSC >= 0 && RHSC < 0x1000) // 12 bits (unsigned)
799 return false;
800 else if (RHSC < 0 && RHSC >= -255) // 8 bits
David Goodwind8c95b52009-07-30 18:56:48 +0000801 return false;
802 }
803
Evan Cheng055b0312009-06-29 07:51:04 +0000804 // Look for (R + R) or (R + (R << [1,2,3])).
805 unsigned ShAmt = 0;
806 Base = N.getOperand(0);
807 OffReg = N.getOperand(1);
808
809 // Swap if it is ((R << c) + R).
810 ARM_AM::ShiftOpc ShOpcVal = ARM_AM::getShiftOpcForNode(OffReg);
811 if (ShOpcVal != ARM_AM::lsl) {
812 ShOpcVal = ARM_AM::getShiftOpcForNode(Base);
813 if (ShOpcVal == ARM_AM::lsl)
814 std::swap(Base, OffReg);
Jim Grosbach764ab522009-08-11 15:33:49 +0000815 }
816
Evan Cheng055b0312009-06-29 07:51:04 +0000817 if (ShOpcVal == ARM_AM::lsl) {
818 // Check to see if the RHS of the shift is a constant, if not, we can't fold
819 // it.
820 if (ConstantSDNode *Sh = dyn_cast<ConstantSDNode>(OffReg.getOperand(1))) {
821 ShAmt = Sh->getZExtValue();
822 if (ShAmt >= 4) {
823 ShAmt = 0;
824 ShOpcVal = ARM_AM::no_shift;
825 } else
826 OffReg = OffReg.getOperand(0);
827 } else {
828 ShOpcVal = ARM_AM::no_shift;
829 }
David Goodwin7ecc8502009-07-15 15:50:19 +0000830 }
Jim Grosbach764ab522009-08-11 15:33:49 +0000831
Owen Anderson825b72b2009-08-11 20:47:22 +0000832 ShImm = CurDAG->getTargetConstant(ShAmt, MVT::i32);
Evan Cheng055b0312009-06-29 07:51:04 +0000833
834 return true;
835}
836
837//===--------------------------------------------------------------------===//
838
Evan Chengee568cf2007-07-05 07:15:27 +0000839/// getAL - Returns a ARMCC::AL immediate node.
Dan Gohman475871a2008-07-27 21:46:04 +0000840static inline SDValue getAL(SelectionDAG *CurDAG) {
Owen Anderson825b72b2009-08-11 20:47:22 +0000841 return CurDAG->getTargetConstant((uint64_t)ARMCC::AL, MVT::i32);
Evan Cheng44bec522007-05-15 01:29:07 +0000842}
843
Dan Gohmaneeb3a002010-01-05 01:24:18 +0000844SDNode *ARMDAGToDAGISel::SelectARMIndexedLoad(SDNode *N) {
845 LoadSDNode *LD = cast<LoadSDNode>(N);
Evan Chengaf4550f2009-07-02 01:23:32 +0000846 ISD::MemIndexedMode AM = LD->getAddressingMode();
847 if (AM == ISD::UNINDEXED)
848 return NULL;
849
Owen Andersone50ed302009-08-10 22:56:29 +0000850 EVT LoadedVT = LD->getMemoryVT();
Evan Chengaf4550f2009-07-02 01:23:32 +0000851 SDValue Offset, AMOpc;
852 bool isPre = (AM == ISD::PRE_INC) || (AM == ISD::PRE_DEC);
853 unsigned Opcode = 0;
854 bool Match = false;
Owen Anderson825b72b2009-08-11 20:47:22 +0000855 if (LoadedVT == MVT::i32 &&
Dan Gohmaneeb3a002010-01-05 01:24:18 +0000856 SelectAddrMode2Offset(N, LD->getOffset(), Offset, AMOpc)) {
Evan Chengaf4550f2009-07-02 01:23:32 +0000857 Opcode = isPre ? ARM::LDR_PRE : ARM::LDR_POST;
858 Match = true;
Owen Anderson825b72b2009-08-11 20:47:22 +0000859 } else if (LoadedVT == MVT::i16 &&
Dan Gohmaneeb3a002010-01-05 01:24:18 +0000860 SelectAddrMode3Offset(N, LD->getOffset(), Offset, AMOpc)) {
Evan Chengaf4550f2009-07-02 01:23:32 +0000861 Match = true;
862 Opcode = (LD->getExtensionType() == ISD::SEXTLOAD)
863 ? (isPre ? ARM::LDRSH_PRE : ARM::LDRSH_POST)
864 : (isPre ? ARM::LDRH_PRE : ARM::LDRH_POST);
Owen Anderson825b72b2009-08-11 20:47:22 +0000865 } else if (LoadedVT == MVT::i8 || LoadedVT == MVT::i1) {
Evan Chengaf4550f2009-07-02 01:23:32 +0000866 if (LD->getExtensionType() == ISD::SEXTLOAD) {
Dan Gohmaneeb3a002010-01-05 01:24:18 +0000867 if (SelectAddrMode3Offset(N, LD->getOffset(), Offset, AMOpc)) {
Evan Chengaf4550f2009-07-02 01:23:32 +0000868 Match = true;
869 Opcode = isPre ? ARM::LDRSB_PRE : ARM::LDRSB_POST;
870 }
871 } else {
Dan Gohmaneeb3a002010-01-05 01:24:18 +0000872 if (SelectAddrMode2Offset(N, LD->getOffset(), Offset, AMOpc)) {
Evan Chengaf4550f2009-07-02 01:23:32 +0000873 Match = true;
874 Opcode = isPre ? ARM::LDRB_PRE : ARM::LDRB_POST;
875 }
876 }
877 }
878
879 if (Match) {
880 SDValue Chain = LD->getChain();
881 SDValue Base = LD->getBasePtr();
882 SDValue Ops[]= { Base, Offset, AMOpc, getAL(CurDAG),
Owen Anderson825b72b2009-08-11 20:47:22 +0000883 CurDAG->getRegister(0, MVT::i32), Chain };
Dan Gohmaneeb3a002010-01-05 01:24:18 +0000884 return CurDAG->getMachineNode(Opcode, N->getDebugLoc(), MVT::i32, MVT::i32,
Dan Gohman602b0c82009-09-25 18:54:59 +0000885 MVT::Other, Ops, 6);
Evan Chengaf4550f2009-07-02 01:23:32 +0000886 }
887
888 return NULL;
889}
890
Dan Gohmaneeb3a002010-01-05 01:24:18 +0000891SDNode *ARMDAGToDAGISel::SelectT2IndexedLoad(SDNode *N) {
892 LoadSDNode *LD = cast<LoadSDNode>(N);
Evan Chenge88d5ce2009-07-02 07:28:31 +0000893 ISD::MemIndexedMode AM = LD->getAddressingMode();
894 if (AM == ISD::UNINDEXED)
895 return NULL;
896
Owen Andersone50ed302009-08-10 22:56:29 +0000897 EVT LoadedVT = LD->getMemoryVT();
Evan Cheng4fbb9962009-07-02 23:16:11 +0000898 bool isSExtLd = LD->getExtensionType() == ISD::SEXTLOAD;
Evan Chenge88d5ce2009-07-02 07:28:31 +0000899 SDValue Offset;
900 bool isPre = (AM == ISD::PRE_INC) || (AM == ISD::PRE_DEC);
901 unsigned Opcode = 0;
902 bool Match = false;
Dan Gohmaneeb3a002010-01-05 01:24:18 +0000903 if (SelectT2AddrModeImm8Offset(N, LD->getOffset(), Offset)) {
Owen Anderson825b72b2009-08-11 20:47:22 +0000904 switch (LoadedVT.getSimpleVT().SimpleTy) {
905 case MVT::i32:
Evan Chenge88d5ce2009-07-02 07:28:31 +0000906 Opcode = isPre ? ARM::t2LDR_PRE : ARM::t2LDR_POST;
907 break;
Owen Anderson825b72b2009-08-11 20:47:22 +0000908 case MVT::i16:
Evan Cheng4fbb9962009-07-02 23:16:11 +0000909 if (isSExtLd)
910 Opcode = isPre ? ARM::t2LDRSH_PRE : ARM::t2LDRSH_POST;
911 else
912 Opcode = isPre ? ARM::t2LDRH_PRE : ARM::t2LDRH_POST;
Evan Chenge88d5ce2009-07-02 07:28:31 +0000913 break;
Owen Anderson825b72b2009-08-11 20:47:22 +0000914 case MVT::i8:
915 case MVT::i1:
Evan Cheng4fbb9962009-07-02 23:16:11 +0000916 if (isSExtLd)
917 Opcode = isPre ? ARM::t2LDRSB_PRE : ARM::t2LDRSB_POST;
918 else
919 Opcode = isPre ? ARM::t2LDRB_PRE : ARM::t2LDRB_POST;
Evan Chenge88d5ce2009-07-02 07:28:31 +0000920 break;
921 default:
922 return NULL;
923 }
924 Match = true;
925 }
926
927 if (Match) {
928 SDValue Chain = LD->getChain();
929 SDValue Base = LD->getBasePtr();
930 SDValue Ops[]= { Base, Offset, getAL(CurDAG),
Owen Anderson825b72b2009-08-11 20:47:22 +0000931 CurDAG->getRegister(0, MVT::i32), Chain };
Dan Gohmaneeb3a002010-01-05 01:24:18 +0000932 return CurDAG->getMachineNode(Opcode, N->getDebugLoc(), MVT::i32, MVT::i32,
Dan Gohman602b0c82009-09-25 18:54:59 +0000933 MVT::Other, Ops, 5);
Evan Chenge88d5ce2009-07-02 07:28:31 +0000934 }
935
936 return NULL;
937}
938
Bob Wilson3bf12ab2009-10-06 22:01:59 +0000939/// PairDRegs - Insert a pair of double registers into an implicit def to
940/// form a quad register.
941SDNode *ARMDAGToDAGISel::PairDRegs(EVT VT, SDValue V0, SDValue V1) {
942 DebugLoc dl = V0.getNode()->getDebugLoc();
943 SDValue Undef =
Chris Lattner518bb532010-02-09 19:54:29 +0000944 SDValue(CurDAG->getMachineNode(TargetOpcode::IMPLICIT_DEF, dl, VT), 0);
Bob Wilson3bf12ab2009-10-06 22:01:59 +0000945 SDValue SubReg0 = CurDAG->getTargetConstant(ARM::DSUBREG_0, MVT::i32);
946 SDValue SubReg1 = CurDAG->getTargetConstant(ARM::DSUBREG_1, MVT::i32);
Chris Lattner518bb532010-02-09 19:54:29 +0000947 SDNode *Pair = CurDAG->getMachineNode(TargetOpcode::INSERT_SUBREG, dl,
Bob Wilson3bf12ab2009-10-06 22:01:59 +0000948 VT, Undef, V0, SubReg0);
Chris Lattner518bb532010-02-09 19:54:29 +0000949 return CurDAG->getMachineNode(TargetOpcode::INSERT_SUBREG, dl,
Bob Wilson3bf12ab2009-10-06 22:01:59 +0000950 VT, SDValue(Pair, 0), V1, SubReg1);
951}
952
Bob Wilsona7c397c2009-10-14 16:19:03 +0000953/// GetNEONSubregVT - Given a type for a 128-bit NEON vector, return the type
954/// for a 64-bit subregister of the vector.
955static EVT GetNEONSubregVT(EVT VT) {
956 switch (VT.getSimpleVT().SimpleTy) {
957 default: llvm_unreachable("unhandled NEON type");
958 case MVT::v16i8: return MVT::v8i8;
959 case MVT::v8i16: return MVT::v4i16;
960 case MVT::v4f32: return MVT::v2f32;
961 case MVT::v4i32: return MVT::v2i32;
962 case MVT::v2i64: return MVT::v1i64;
963 }
964}
965
Dan Gohmaneeb3a002010-01-05 01:24:18 +0000966SDNode *ARMDAGToDAGISel::SelectVLD(SDNode *N, unsigned NumVecs,
Bob Wilson3e36f132009-10-14 17:28:52 +0000967 unsigned *DOpcodes, unsigned *QOpcodes0,
968 unsigned *QOpcodes1) {
Bob Wilson621f1952010-03-23 05:25:43 +0000969 assert(NumVecs >= 1 && NumVecs <= 4 && "VLD NumVecs out-of-range");
Bob Wilson3e36f132009-10-14 17:28:52 +0000970 DebugLoc dl = N->getDebugLoc();
971
Bob Wilson226036e2010-03-20 22:13:40 +0000972 SDValue MemAddr, Align;
973 if (!SelectAddrMode6(N, N->getOperand(2), MemAddr, Align))
Bob Wilson3e36f132009-10-14 17:28:52 +0000974 return NULL;
975
976 SDValue Chain = N->getOperand(0);
977 EVT VT = N->getValueType(0);
978 bool is64BitVector = VT.is64BitVector();
979
980 unsigned OpcodeIndex;
981 switch (VT.getSimpleVT().SimpleTy) {
982 default: llvm_unreachable("unhandled vld type");
983 // Double-register operations:
984 case MVT::v8i8: OpcodeIndex = 0; break;
985 case MVT::v4i16: OpcodeIndex = 1; break;
986 case MVT::v2f32:
987 case MVT::v2i32: OpcodeIndex = 2; break;
988 case MVT::v1i64: OpcodeIndex = 3; break;
989 // Quad-register operations:
990 case MVT::v16i8: OpcodeIndex = 0; break;
991 case MVT::v8i16: OpcodeIndex = 1; break;
992 case MVT::v4f32:
993 case MVT::v4i32: OpcodeIndex = 2; break;
Bob Wilson621f1952010-03-23 05:25:43 +0000994 case MVT::v2i64: OpcodeIndex = 3;
Bob Wilson11d98992010-03-23 06:20:33 +0000995 assert(NumVecs == 1 && "v2i64 type only supported for VLD1");
Bob Wilson621f1952010-03-23 05:25:43 +0000996 break;
Bob Wilson3e36f132009-10-14 17:28:52 +0000997 }
998
Evan Chengac0869d2009-11-21 06:21:52 +0000999 SDValue Pred = CurDAG->getTargetConstant(14, MVT::i32);
Bob Wilson226036e2010-03-20 22:13:40 +00001000 SDValue Reg0 = CurDAG->getRegister(0, MVT::i32);
Bob Wilson3e36f132009-10-14 17:28:52 +00001001 if (is64BitVector) {
1002 unsigned Opc = DOpcodes[OpcodeIndex];
Bob Wilson226036e2010-03-20 22:13:40 +00001003 const SDValue Ops[] = { MemAddr, Align, Pred, Reg0, Chain };
Bob Wilson3e36f132009-10-14 17:28:52 +00001004 std::vector<EVT> ResTys(NumVecs, VT);
1005 ResTys.push_back(MVT::Other);
Bob Wilson226036e2010-03-20 22:13:40 +00001006 return CurDAG->getMachineNode(Opc, dl, ResTys, Ops, 5);
Bob Wilson3e36f132009-10-14 17:28:52 +00001007 }
1008
1009 EVT RegVT = GetNEONSubregVT(VT);
Bob Wilson621f1952010-03-23 05:25:43 +00001010 if (NumVecs <= 2) {
1011 // Quad registers are directly supported for VLD1 and VLD2,
1012 // loading pairs of D regs.
Bob Wilson3e36f132009-10-14 17:28:52 +00001013 unsigned Opc = QOpcodes0[OpcodeIndex];
Bob Wilson226036e2010-03-20 22:13:40 +00001014 const SDValue Ops[] = { MemAddr, Align, Pred, Reg0, Chain };
Bob Wilson621f1952010-03-23 05:25:43 +00001015 std::vector<EVT> ResTys(2 * NumVecs, RegVT);
Bob Wilson3e36f132009-10-14 17:28:52 +00001016 ResTys.push_back(MVT::Other);
Bob Wilson226036e2010-03-20 22:13:40 +00001017 SDNode *VLd = CurDAG->getMachineNode(Opc, dl, ResTys, Ops, 5);
Bob Wilson621f1952010-03-23 05:25:43 +00001018 Chain = SDValue(VLd, 2 * NumVecs);
Bob Wilson3e36f132009-10-14 17:28:52 +00001019
1020 // Combine the even and odd subregs to produce the result.
1021 for (unsigned Vec = 0; Vec < NumVecs; ++Vec) {
1022 SDNode *Q = PairDRegs(VT, SDValue(VLd, 2*Vec), SDValue(VLd, 2*Vec+1));
1023 ReplaceUses(SDValue(N, Vec), SDValue(Q, 0));
1024 }
1025 } else {
1026 // Otherwise, quad registers are loaded with two separate instructions,
1027 // where one loads the even registers and the other loads the odd registers.
1028
Bob Wilson3e36f132009-10-14 17:28:52 +00001029 std::vector<EVT> ResTys(NumVecs, RegVT);
1030 ResTys.push_back(MemAddr.getValueType());
1031 ResTys.push_back(MVT::Other);
1032
Bob Wilson24f995d2009-10-14 18:32:29 +00001033 // Load the even subregs.
Bob Wilson3e36f132009-10-14 17:28:52 +00001034 unsigned Opc = QOpcodes0[OpcodeIndex];
Bob Wilson226036e2010-03-20 22:13:40 +00001035 const SDValue OpsA[] = { MemAddr, Align, Reg0, Pred, Reg0, Chain };
1036 SDNode *VLdA = CurDAG->getMachineNode(Opc, dl, ResTys, OpsA, 6);
Bob Wilson3e36f132009-10-14 17:28:52 +00001037 Chain = SDValue(VLdA, NumVecs+1);
1038
Bob Wilson24f995d2009-10-14 18:32:29 +00001039 // Load the odd subregs.
Bob Wilson3e36f132009-10-14 17:28:52 +00001040 Opc = QOpcodes1[OpcodeIndex];
Bob Wilson226036e2010-03-20 22:13:40 +00001041 const SDValue OpsB[] = { SDValue(VLdA, NumVecs),
1042 Align, Reg0, Pred, Reg0, Chain };
1043 SDNode *VLdB = CurDAG->getMachineNode(Opc, dl, ResTys, OpsB, 6);
Bob Wilson3e36f132009-10-14 17:28:52 +00001044 Chain = SDValue(VLdB, NumVecs+1);
1045
1046 // Combine the even and odd subregs to produce the result.
1047 for (unsigned Vec = 0; Vec < NumVecs; ++Vec) {
1048 SDNode *Q = PairDRegs(VT, SDValue(VLdA, Vec), SDValue(VLdB, Vec));
1049 ReplaceUses(SDValue(N, Vec), SDValue(Q, 0));
1050 }
1051 }
1052 ReplaceUses(SDValue(N, NumVecs), Chain);
1053 return NULL;
1054}
1055
Dan Gohmaneeb3a002010-01-05 01:24:18 +00001056SDNode *ARMDAGToDAGISel::SelectVST(SDNode *N, unsigned NumVecs,
Bob Wilson24f995d2009-10-14 18:32:29 +00001057 unsigned *DOpcodes, unsigned *QOpcodes0,
1058 unsigned *QOpcodes1) {
Bob Wilson11d98992010-03-23 06:20:33 +00001059 assert(NumVecs >=1 && NumVecs <= 4 && "VST NumVecs out-of-range");
Bob Wilson24f995d2009-10-14 18:32:29 +00001060 DebugLoc dl = N->getDebugLoc();
1061
Bob Wilson226036e2010-03-20 22:13:40 +00001062 SDValue MemAddr, Align;
1063 if (!SelectAddrMode6(N, N->getOperand(2), MemAddr, Align))
Bob Wilson24f995d2009-10-14 18:32:29 +00001064 return NULL;
1065
1066 SDValue Chain = N->getOperand(0);
1067 EVT VT = N->getOperand(3).getValueType();
1068 bool is64BitVector = VT.is64BitVector();
1069
1070 unsigned OpcodeIndex;
1071 switch (VT.getSimpleVT().SimpleTy) {
1072 default: llvm_unreachable("unhandled vst type");
1073 // Double-register operations:
1074 case MVT::v8i8: OpcodeIndex = 0; break;
1075 case MVT::v4i16: OpcodeIndex = 1; break;
1076 case MVT::v2f32:
1077 case MVT::v2i32: OpcodeIndex = 2; break;
1078 case MVT::v1i64: OpcodeIndex = 3; break;
1079 // Quad-register operations:
1080 case MVT::v16i8: OpcodeIndex = 0; break;
1081 case MVT::v8i16: OpcodeIndex = 1; break;
1082 case MVT::v4f32:
1083 case MVT::v4i32: OpcodeIndex = 2; break;
Bob Wilson11d98992010-03-23 06:20:33 +00001084 case MVT::v2i64: OpcodeIndex = 3;
1085 assert(NumVecs == 1 && "v2i64 type only supported for VST1");
1086 break;
Bob Wilson24f995d2009-10-14 18:32:29 +00001087 }
1088
Evan Chengac0869d2009-11-21 06:21:52 +00001089 SDValue Pred = CurDAG->getTargetConstant(14, MVT::i32);
Bob Wilson226036e2010-03-20 22:13:40 +00001090 SDValue Reg0 = CurDAG->getRegister(0, MVT::i32);
Evan Chengac0869d2009-11-21 06:21:52 +00001091
Bob Wilson226036e2010-03-20 22:13:40 +00001092 SmallVector<SDValue, 10> Ops;
Bob Wilson24f995d2009-10-14 18:32:29 +00001093 Ops.push_back(MemAddr);
Jim Grosbach8a5ec862009-11-07 21:25:39 +00001094 Ops.push_back(Align);
Bob Wilson24f995d2009-10-14 18:32:29 +00001095
1096 if (is64BitVector) {
1097 unsigned Opc = DOpcodes[OpcodeIndex];
1098 for (unsigned Vec = 0; Vec < NumVecs; ++Vec)
1099 Ops.push_back(N->getOperand(Vec+3));
Evan Chengac0869d2009-11-21 06:21:52 +00001100 Ops.push_back(Pred);
Bob Wilson226036e2010-03-20 22:13:40 +00001101 Ops.push_back(Reg0); // predicate register
Bob Wilson24f995d2009-10-14 18:32:29 +00001102 Ops.push_back(Chain);
Bob Wilson226036e2010-03-20 22:13:40 +00001103 return CurDAG->getMachineNode(Opc, dl, MVT::Other, Ops.data(), NumVecs+5);
Bob Wilson24f995d2009-10-14 18:32:29 +00001104 }
1105
1106 EVT RegVT = GetNEONSubregVT(VT);
Bob Wilson11d98992010-03-23 06:20:33 +00001107 if (NumVecs <= 2) {
1108 // Quad registers are directly supported for VST1 and VST2,
1109 // storing pairs of D regs.
Bob Wilson24f995d2009-10-14 18:32:29 +00001110 unsigned Opc = QOpcodes0[OpcodeIndex];
1111 for (unsigned Vec = 0; Vec < NumVecs; ++Vec) {
1112 Ops.push_back(CurDAG->getTargetExtractSubreg(ARM::DSUBREG_0, dl, RegVT,
1113 N->getOperand(Vec+3)));
1114 Ops.push_back(CurDAG->getTargetExtractSubreg(ARM::DSUBREG_1, dl, RegVT,
1115 N->getOperand(Vec+3)));
1116 }
Evan Chengac0869d2009-11-21 06:21:52 +00001117 Ops.push_back(Pred);
Bob Wilson226036e2010-03-20 22:13:40 +00001118 Ops.push_back(Reg0); // predicate register
Bob Wilson24f995d2009-10-14 18:32:29 +00001119 Ops.push_back(Chain);
Bob Wilson11d98992010-03-23 06:20:33 +00001120 return CurDAG->getMachineNode(Opc, dl, MVT::Other, Ops.data(),
1121 5 + 2 * NumVecs);
Bob Wilson24f995d2009-10-14 18:32:29 +00001122 }
1123
1124 // Otherwise, quad registers are stored with two separate instructions,
1125 // where one stores the even registers and the other stores the odd registers.
1126
Bob Wilson226036e2010-03-20 22:13:40 +00001127 Ops.push_back(Reg0); // post-access address offset
Bob Wilsona43e6bf2010-03-16 23:01:13 +00001128
Bob Wilson24f995d2009-10-14 18:32:29 +00001129 // Store the even subregs.
1130 for (unsigned Vec = 0; Vec < NumVecs; ++Vec)
1131 Ops.push_back(CurDAG->getTargetExtractSubreg(ARM::DSUBREG_0, dl, RegVT,
1132 N->getOperand(Vec+3)));
Evan Chengac0869d2009-11-21 06:21:52 +00001133 Ops.push_back(Pred);
Bob Wilson226036e2010-03-20 22:13:40 +00001134 Ops.push_back(Reg0); // predicate register
Bob Wilson24f995d2009-10-14 18:32:29 +00001135 Ops.push_back(Chain);
1136 unsigned Opc = QOpcodes0[OpcodeIndex];
1137 SDNode *VStA = CurDAG->getMachineNode(Opc, dl, MemAddr.getValueType(),
Bob Wilson226036e2010-03-20 22:13:40 +00001138 MVT::Other, Ops.data(), NumVecs+6);
Bob Wilson24f995d2009-10-14 18:32:29 +00001139 Chain = SDValue(VStA, 1);
1140
1141 // Store the odd subregs.
1142 Ops[0] = SDValue(VStA, 0); // MemAddr
1143 for (unsigned Vec = 0; Vec < NumVecs; ++Vec)
Bob Wilson226036e2010-03-20 22:13:40 +00001144 Ops[Vec+3] = CurDAG->getTargetExtractSubreg(ARM::DSUBREG_1, dl, RegVT,
Bob Wilson24f995d2009-10-14 18:32:29 +00001145 N->getOperand(Vec+3));
Bob Wilson226036e2010-03-20 22:13:40 +00001146 Ops[NumVecs+5] = Chain;
Bob Wilson24f995d2009-10-14 18:32:29 +00001147 Opc = QOpcodes1[OpcodeIndex];
1148 SDNode *VStB = CurDAG->getMachineNode(Opc, dl, MemAddr.getValueType(),
Bob Wilson226036e2010-03-20 22:13:40 +00001149 MVT::Other, Ops.data(), NumVecs+6);
Bob Wilson24f995d2009-10-14 18:32:29 +00001150 Chain = SDValue(VStB, 1);
1151 ReplaceUses(SDValue(N, 0), Chain);
1152 return NULL;
1153}
1154
Dan Gohmaneeb3a002010-01-05 01:24:18 +00001155SDNode *ARMDAGToDAGISel::SelectVLDSTLane(SDNode *N, bool IsLoad,
Bob Wilson96493442009-10-14 16:46:45 +00001156 unsigned NumVecs, unsigned *DOpcodes,
1157 unsigned *QOpcodes0,
1158 unsigned *QOpcodes1) {
1159 assert(NumVecs >=2 && NumVecs <= 4 && "VLDSTLane NumVecs out-of-range");
Bob Wilsona7c397c2009-10-14 16:19:03 +00001160 DebugLoc dl = N->getDebugLoc();
1161
Bob Wilson226036e2010-03-20 22:13:40 +00001162 SDValue MemAddr, Align;
1163 if (!SelectAddrMode6(N, N->getOperand(2), MemAddr, Align))
Bob Wilsona7c397c2009-10-14 16:19:03 +00001164 return NULL;
1165
1166 SDValue Chain = N->getOperand(0);
1167 unsigned Lane =
1168 cast<ConstantSDNode>(N->getOperand(NumVecs+3))->getZExtValue();
Bob Wilson96493442009-10-14 16:46:45 +00001169 EVT VT = IsLoad ? N->getValueType(0) : N->getOperand(3).getValueType();
Bob Wilsona7c397c2009-10-14 16:19:03 +00001170 bool is64BitVector = VT.is64BitVector();
1171
Bob Wilson96493442009-10-14 16:46:45 +00001172 // Quad registers are handled by load/store of subregs. Find the subreg info.
Bob Wilsona7c397c2009-10-14 16:19:03 +00001173 unsigned NumElts = 0;
1174 int SubregIdx = 0;
1175 EVT RegVT = VT;
1176 if (!is64BitVector) {
1177 RegVT = GetNEONSubregVT(VT);
1178 NumElts = RegVT.getVectorNumElements();
1179 SubregIdx = (Lane < NumElts) ? ARM::DSUBREG_0 : ARM::DSUBREG_1;
1180 }
1181
1182 unsigned OpcodeIndex;
1183 switch (VT.getSimpleVT().SimpleTy) {
Bob Wilson96493442009-10-14 16:46:45 +00001184 default: llvm_unreachable("unhandled vld/vst lane type");
Bob Wilsona7c397c2009-10-14 16:19:03 +00001185 // Double-register operations:
1186 case MVT::v8i8: OpcodeIndex = 0; break;
1187 case MVT::v4i16: OpcodeIndex = 1; break;
1188 case MVT::v2f32:
1189 case MVT::v2i32: OpcodeIndex = 2; break;
1190 // Quad-register operations:
1191 case MVT::v8i16: OpcodeIndex = 0; break;
1192 case MVT::v4f32:
1193 case MVT::v4i32: OpcodeIndex = 1; break;
1194 }
1195
Evan Chengac0869d2009-11-21 06:21:52 +00001196 SDValue Pred = CurDAG->getTargetConstant(14, MVT::i32);
Bob Wilson226036e2010-03-20 22:13:40 +00001197 SDValue Reg0 = CurDAG->getRegister(0, MVT::i32);
Evan Chengac0869d2009-11-21 06:21:52 +00001198
Bob Wilson226036e2010-03-20 22:13:40 +00001199 SmallVector<SDValue, 10> Ops;
Bob Wilsona7c397c2009-10-14 16:19:03 +00001200 Ops.push_back(MemAddr);
Jim Grosbach8a5ec862009-11-07 21:25:39 +00001201 Ops.push_back(Align);
Bob Wilsona7c397c2009-10-14 16:19:03 +00001202
1203 unsigned Opc = 0;
1204 if (is64BitVector) {
1205 Opc = DOpcodes[OpcodeIndex];
1206 for (unsigned Vec = 0; Vec < NumVecs; ++Vec)
1207 Ops.push_back(N->getOperand(Vec+3));
1208 } else {
1209 // Check if this is loading the even or odd subreg of a Q register.
1210 if (Lane < NumElts) {
1211 Opc = QOpcodes0[OpcodeIndex];
1212 } else {
1213 Lane -= NumElts;
1214 Opc = QOpcodes1[OpcodeIndex];
1215 }
1216 // Extract the subregs of the input vector.
1217 for (unsigned Vec = 0; Vec < NumVecs; ++Vec)
1218 Ops.push_back(CurDAG->getTargetExtractSubreg(SubregIdx, dl, RegVT,
1219 N->getOperand(Vec+3)));
1220 }
1221 Ops.push_back(getI32Imm(Lane));
Evan Chengac0869d2009-11-21 06:21:52 +00001222 Ops.push_back(Pred);
Bob Wilson226036e2010-03-20 22:13:40 +00001223 Ops.push_back(Reg0);
Bob Wilsona7c397c2009-10-14 16:19:03 +00001224 Ops.push_back(Chain);
1225
Bob Wilson96493442009-10-14 16:46:45 +00001226 if (!IsLoad)
Bob Wilson226036e2010-03-20 22:13:40 +00001227 return CurDAG->getMachineNode(Opc, dl, MVT::Other, Ops.data(), NumVecs+6);
Bob Wilson96493442009-10-14 16:46:45 +00001228
Bob Wilsona7c397c2009-10-14 16:19:03 +00001229 std::vector<EVT> ResTys(NumVecs, RegVT);
1230 ResTys.push_back(MVT::Other);
1231 SDNode *VLdLn =
Bob Wilson226036e2010-03-20 22:13:40 +00001232 CurDAG->getMachineNode(Opc, dl, ResTys, Ops.data(), NumVecs+6);
Bob Wilsona7c397c2009-10-14 16:19:03 +00001233 // For a 64-bit vector load to D registers, nothing more needs to be done.
1234 if (is64BitVector)
1235 return VLdLn;
1236
1237 // For 128-bit vectors, take the 64-bit results of the load and insert them
1238 // as subregs into the result.
1239 for (unsigned Vec = 0; Vec < NumVecs; ++Vec) {
1240 SDValue QuadVec = CurDAG->getTargetInsertSubreg(SubregIdx, dl, VT,
1241 N->getOperand(Vec+3),
1242 SDValue(VLdLn, Vec));
1243 ReplaceUses(SDValue(N, Vec), QuadVec);
1244 }
1245
1246 Chain = SDValue(VLdLn, NumVecs);
1247 ReplaceUses(SDValue(N, NumVecs), Chain);
1248 return NULL;
1249}
1250
Dan Gohmaneeb3a002010-01-05 01:24:18 +00001251SDNode *ARMDAGToDAGISel::SelectV6T2BitfieldExtractOp(SDNode *N,
Sandeep Patel47eedaa2009-10-13 18:59:48 +00001252 unsigned Opc) {
1253 if (!Subtarget->hasV6T2Ops())
1254 return NULL;
Bob Wilson96493442009-10-14 16:46:45 +00001255
Sandeep Patel47eedaa2009-10-13 18:59:48 +00001256 unsigned Shl_imm = 0;
Dan Gohmaneeb3a002010-01-05 01:24:18 +00001257 if (isOpcWithIntImmediate(N->getOperand(0).getNode(), ISD::SHL, Shl_imm)) {
Sandeep Patel47eedaa2009-10-13 18:59:48 +00001258 assert(Shl_imm > 0 && Shl_imm < 32 && "bad amount in shift node!");
1259 unsigned Srl_imm = 0;
Dan Gohmaneeb3a002010-01-05 01:24:18 +00001260 if (isInt32Immediate(N->getOperand(1), Srl_imm)) {
Sandeep Patel47eedaa2009-10-13 18:59:48 +00001261 assert(Srl_imm > 0 && Srl_imm < 32 && "bad amount in shift node!");
1262 unsigned Width = 32 - Srl_imm;
1263 int LSB = Srl_imm - Shl_imm;
Evan Cheng8000c6c2009-10-22 00:40:00 +00001264 if (LSB < 0)
Sandeep Patel47eedaa2009-10-13 18:59:48 +00001265 return NULL;
1266 SDValue Reg0 = CurDAG->getRegister(0, MVT::i32);
Dan Gohmaneeb3a002010-01-05 01:24:18 +00001267 SDValue Ops[] = { N->getOperand(0).getOperand(0),
Sandeep Patel47eedaa2009-10-13 18:59:48 +00001268 CurDAG->getTargetConstant(LSB, MVT::i32),
1269 CurDAG->getTargetConstant(Width, MVT::i32),
1270 getAL(CurDAG), Reg0 };
Dan Gohmaneeb3a002010-01-05 01:24:18 +00001271 return CurDAG->SelectNodeTo(N, Opc, MVT::i32, Ops, 5);
Sandeep Patel47eedaa2009-10-13 18:59:48 +00001272 }
1273 }
1274 return NULL;
1275}
1276
Evan Cheng9ef48352009-11-20 00:54:03 +00001277SDNode *ARMDAGToDAGISel::
Dan Gohmaneeb3a002010-01-05 01:24:18 +00001278SelectT2CMOVShiftOp(SDNode *N, SDValue FalseVal, SDValue TrueVal,
Evan Cheng9ef48352009-11-20 00:54:03 +00001279 ARMCC::CondCodes CCVal, SDValue CCR, SDValue InFlag) {
1280 SDValue CPTmp0;
1281 SDValue CPTmp1;
Dan Gohmaneeb3a002010-01-05 01:24:18 +00001282 if (SelectT2ShifterOperandReg(N, TrueVal, CPTmp0, CPTmp1)) {
Evan Cheng9ef48352009-11-20 00:54:03 +00001283 unsigned SOVal = cast<ConstantSDNode>(CPTmp1)->getZExtValue();
1284 unsigned SOShOp = ARM_AM::getSORegShOp(SOVal);
1285 unsigned Opc = 0;
1286 switch (SOShOp) {
1287 case ARM_AM::lsl: Opc = ARM::t2MOVCClsl; break;
1288 case ARM_AM::lsr: Opc = ARM::t2MOVCClsr; break;
1289 case ARM_AM::asr: Opc = ARM::t2MOVCCasr; break;
1290 case ARM_AM::ror: Opc = ARM::t2MOVCCror; break;
1291 default:
1292 llvm_unreachable("Unknown so_reg opcode!");
1293 break;
1294 }
1295 SDValue SOShImm =
1296 CurDAG->getTargetConstant(ARM_AM::getSORegOffset(SOVal), MVT::i32);
1297 SDValue CC = CurDAG->getTargetConstant(CCVal, MVT::i32);
1298 SDValue Ops[] = { FalseVal, CPTmp0, SOShImm, CC, CCR, InFlag };
Dan Gohmaneeb3a002010-01-05 01:24:18 +00001299 return CurDAG->SelectNodeTo(N, Opc, MVT::i32,Ops, 6);
Evan Cheng9ef48352009-11-20 00:54:03 +00001300 }
1301 return 0;
1302}
1303
1304SDNode *ARMDAGToDAGISel::
Dan Gohmaneeb3a002010-01-05 01:24:18 +00001305SelectARMCMOVShiftOp(SDNode *N, SDValue FalseVal, SDValue TrueVal,
Evan Cheng9ef48352009-11-20 00:54:03 +00001306 ARMCC::CondCodes CCVal, SDValue CCR, SDValue InFlag) {
1307 SDValue CPTmp0;
1308 SDValue CPTmp1;
1309 SDValue CPTmp2;
Dan Gohmaneeb3a002010-01-05 01:24:18 +00001310 if (SelectShifterOperandReg(N, TrueVal, CPTmp0, CPTmp1, CPTmp2)) {
Evan Cheng9ef48352009-11-20 00:54:03 +00001311 SDValue CC = CurDAG->getTargetConstant(CCVal, MVT::i32);
1312 SDValue Ops[] = { FalseVal, CPTmp0, CPTmp1, CPTmp2, CC, CCR, InFlag };
Dan Gohmaneeb3a002010-01-05 01:24:18 +00001313 return CurDAG->SelectNodeTo(N, ARM::MOVCCs, MVT::i32, Ops, 7);
Evan Cheng9ef48352009-11-20 00:54:03 +00001314 }
1315 return 0;
1316}
1317
1318SDNode *ARMDAGToDAGISel::
Dan Gohmaneeb3a002010-01-05 01:24:18 +00001319SelectT2CMOVSoImmOp(SDNode *N, SDValue FalseVal, SDValue TrueVal,
Evan Cheng9ef48352009-11-20 00:54:03 +00001320 ARMCC::CondCodes CCVal, SDValue CCR, SDValue InFlag) {
1321 ConstantSDNode *T = dyn_cast<ConstantSDNode>(TrueVal);
1322 if (!T)
1323 return 0;
1324
1325 if (Predicate_t2_so_imm(TrueVal.getNode())) {
1326 SDValue True = CurDAG->getTargetConstant(T->getZExtValue(), MVT::i32);
1327 SDValue CC = CurDAG->getTargetConstant(CCVal, MVT::i32);
1328 SDValue Ops[] = { FalseVal, True, CC, CCR, InFlag };
Dan Gohmaneeb3a002010-01-05 01:24:18 +00001329 return CurDAG->SelectNodeTo(N,
Evan Cheng9ef48352009-11-20 00:54:03 +00001330 ARM::t2MOVCCi, MVT::i32, Ops, 5);
1331 }
1332 return 0;
1333}
1334
1335SDNode *ARMDAGToDAGISel::
Dan Gohmaneeb3a002010-01-05 01:24:18 +00001336SelectARMCMOVSoImmOp(SDNode *N, SDValue FalseVal, SDValue TrueVal,
Evan Cheng9ef48352009-11-20 00:54:03 +00001337 ARMCC::CondCodes CCVal, SDValue CCR, SDValue InFlag) {
1338 ConstantSDNode *T = dyn_cast<ConstantSDNode>(TrueVal);
1339 if (!T)
1340 return 0;
1341
1342 if (Predicate_so_imm(TrueVal.getNode())) {
1343 SDValue True = CurDAG->getTargetConstant(T->getZExtValue(), MVT::i32);
1344 SDValue CC = CurDAG->getTargetConstant(CCVal, MVT::i32);
1345 SDValue Ops[] = { FalseVal, True, CC, CCR, InFlag };
Dan Gohmaneeb3a002010-01-05 01:24:18 +00001346 return CurDAG->SelectNodeTo(N,
Evan Cheng9ef48352009-11-20 00:54:03 +00001347 ARM::MOVCCi, MVT::i32, Ops, 5);
1348 }
1349 return 0;
1350}
1351
Dan Gohmaneeb3a002010-01-05 01:24:18 +00001352SDNode *ARMDAGToDAGISel::SelectCMOVOp(SDNode *N) {
1353 EVT VT = N->getValueType(0);
1354 SDValue FalseVal = N->getOperand(0);
1355 SDValue TrueVal = N->getOperand(1);
1356 SDValue CC = N->getOperand(2);
1357 SDValue CCR = N->getOperand(3);
1358 SDValue InFlag = N->getOperand(4);
Evan Cheng9ef48352009-11-20 00:54:03 +00001359 assert(CC.getOpcode() == ISD::Constant);
1360 assert(CCR.getOpcode() == ISD::Register);
1361 ARMCC::CondCodes CCVal =
1362 (ARMCC::CondCodes)cast<ConstantSDNode>(CC)->getZExtValue();
Evan Cheng07ba9062009-11-19 21:45:22 +00001363
1364 if (!Subtarget->isThumb1Only() && VT == MVT::i32) {
1365 // Pattern: (ARMcmov:i32 GPR:i32:$false, so_reg:i32:$true, (imm:i32):$cc)
1366 // Emits: (MOVCCs:i32 GPR:i32:$false, so_reg:i32:$true, (imm:i32):$cc)
1367 // Pattern complexity = 18 cost = 1 size = 0
1368 SDValue CPTmp0;
1369 SDValue CPTmp1;
1370 SDValue CPTmp2;
1371 if (Subtarget->isThumb()) {
Dan Gohmaneeb3a002010-01-05 01:24:18 +00001372 SDNode *Res = SelectT2CMOVShiftOp(N, FalseVal, TrueVal,
Evan Cheng9ef48352009-11-20 00:54:03 +00001373 CCVal, CCR, InFlag);
1374 if (!Res)
Dan Gohmaneeb3a002010-01-05 01:24:18 +00001375 Res = SelectT2CMOVShiftOp(N, TrueVal, FalseVal,
Evan Cheng9ef48352009-11-20 00:54:03 +00001376 ARMCC::getOppositeCondition(CCVal), CCR, InFlag);
1377 if (Res)
1378 return Res;
Evan Cheng07ba9062009-11-19 21:45:22 +00001379 } else {
Dan Gohmaneeb3a002010-01-05 01:24:18 +00001380 SDNode *Res = SelectARMCMOVShiftOp(N, FalseVal, TrueVal,
Evan Cheng9ef48352009-11-20 00:54:03 +00001381 CCVal, CCR, InFlag);
1382 if (!Res)
Dan Gohmaneeb3a002010-01-05 01:24:18 +00001383 Res = SelectARMCMOVShiftOp(N, TrueVal, FalseVal,
Evan Cheng9ef48352009-11-20 00:54:03 +00001384 ARMCC::getOppositeCondition(CCVal), CCR, InFlag);
1385 if (Res)
1386 return Res;
Evan Cheng07ba9062009-11-19 21:45:22 +00001387 }
1388
1389 // Pattern: (ARMcmov:i32 GPR:i32:$false,
1390 // (imm:i32)<<P:Predicate_so_imm>>:$true,
1391 // (imm:i32):$cc)
1392 // Emits: (MOVCCi:i32 GPR:i32:$false,
1393 // (so_imm:i32 (imm:i32):$true), (imm:i32):$cc)
1394 // Pattern complexity = 10 cost = 1 size = 0
Evan Cheng9ef48352009-11-20 00:54:03 +00001395 if (Subtarget->isThumb()) {
Dan Gohmaneeb3a002010-01-05 01:24:18 +00001396 SDNode *Res = SelectT2CMOVSoImmOp(N, FalseVal, TrueVal,
Evan Cheng9ef48352009-11-20 00:54:03 +00001397 CCVal, CCR, InFlag);
1398 if (!Res)
Dan Gohmaneeb3a002010-01-05 01:24:18 +00001399 Res = SelectT2CMOVSoImmOp(N, TrueVal, FalseVal,
Evan Cheng9ef48352009-11-20 00:54:03 +00001400 ARMCC::getOppositeCondition(CCVal), CCR, InFlag);
1401 if (Res)
1402 return Res;
1403 } else {
Dan Gohmaneeb3a002010-01-05 01:24:18 +00001404 SDNode *Res = SelectARMCMOVSoImmOp(N, FalseVal, TrueVal,
Evan Cheng9ef48352009-11-20 00:54:03 +00001405 CCVal, CCR, InFlag);
1406 if (!Res)
Dan Gohmaneeb3a002010-01-05 01:24:18 +00001407 Res = SelectARMCMOVSoImmOp(N, TrueVal, FalseVal,
Evan Cheng9ef48352009-11-20 00:54:03 +00001408 ARMCC::getOppositeCondition(CCVal), CCR, InFlag);
1409 if (Res)
1410 return Res;
Evan Cheng07ba9062009-11-19 21:45:22 +00001411 }
1412 }
1413
1414 // Pattern: (ARMcmov:i32 GPR:i32:$false, GPR:i32:$true, (imm:i32):$cc)
1415 // Emits: (MOVCCr:i32 GPR:i32:$false, GPR:i32:$true, (imm:i32):$cc)
1416 // Pattern complexity = 6 cost = 1 size = 0
1417 //
1418 // Pattern: (ARMcmov:i32 GPR:i32:$false, GPR:i32:$true, (imm:i32):$cc)
1419 // Emits: (tMOVCCr:i32 GPR:i32:$false, GPR:i32:$true, (imm:i32):$cc)
1420 // Pattern complexity = 6 cost = 11 size = 0
1421 //
1422 // Also FCPYScc and FCPYDcc.
Evan Cheng9ef48352009-11-20 00:54:03 +00001423 SDValue Tmp2 = CurDAG->getTargetConstant(CCVal, MVT::i32);
1424 SDValue Ops[] = { FalseVal, TrueVal, Tmp2, CCR, InFlag };
Evan Cheng07ba9062009-11-19 21:45:22 +00001425 unsigned Opc = 0;
1426 switch (VT.getSimpleVT().SimpleTy) {
1427 default: assert(false && "Illegal conditional move type!");
1428 break;
1429 case MVT::i32:
1430 Opc = Subtarget->isThumb()
1431 ? (Subtarget->hasThumb2() ? ARM::t2MOVCCr : ARM::tMOVCCr_pseudo)
1432 : ARM::MOVCCr;
1433 break;
1434 case MVT::f32:
1435 Opc = ARM::VMOVScc;
1436 break;
1437 case MVT::f64:
1438 Opc = ARM::VMOVDcc;
1439 break;
1440 }
Dan Gohmaneeb3a002010-01-05 01:24:18 +00001441 return CurDAG->SelectNodeTo(N, Opc, VT, Ops, 5);
Evan Cheng07ba9062009-11-19 21:45:22 +00001442}
1443
Dan Gohmaneeb3a002010-01-05 01:24:18 +00001444SDNode *ARMDAGToDAGISel::Select(SDNode *N) {
Dale Johannesened2eee62009-02-06 01:31:28 +00001445 DebugLoc dl = N->getDebugLoc();
Evan Chenga8e29892007-01-19 07:51:42 +00001446
Dan Gohmane8be6c62008-07-17 19:10:17 +00001447 if (N->isMachineOpcode())
Evan Chenga8e29892007-01-19 07:51:42 +00001448 return NULL; // Already selected.
Rafael Espindola337c4ad62006-06-12 12:28:08 +00001449
1450 switch (N->getOpcode()) {
Evan Chenga8e29892007-01-19 07:51:42 +00001451 default: break;
1452 case ISD::Constant: {
Dan Gohmanf5aeb1a2008-09-12 16:56:44 +00001453 unsigned Val = cast<ConstantSDNode>(N)->getZExtValue();
Evan Chenga8e29892007-01-19 07:51:42 +00001454 bool UseCP = true;
Anton Korobeynikov6a2fa322009-09-27 23:52:58 +00001455 if (Subtarget->hasThumb2())
1456 // Thumb2-aware targets have the MOVT instruction, so all immediates can
1457 // be done with MOV + MOVT, at worst.
1458 UseCP = 0;
1459 else {
1460 if (Subtarget->isThumb()) {
Bob Wilsone64e3cf2009-06-22 17:29:13 +00001461 UseCP = (Val > 255 && // MOV
1462 ~Val > 255 && // MOV + MVN
1463 !ARM_AM::isThumbImmShiftedVal(Val)); // MOV + LSL
Anton Korobeynikov6a2fa322009-09-27 23:52:58 +00001464 } else
1465 UseCP = (ARM_AM::getSOImmVal(Val) == -1 && // MOV
1466 ARM_AM::getSOImmVal(~Val) == -1 && // MVN
1467 !ARM_AM::isSOImmTwoPartVal(Val)); // two instrs.
1468 }
1469
Evan Chenga8e29892007-01-19 07:51:42 +00001470 if (UseCP) {
Dan Gohman475871a2008-07-27 21:46:04 +00001471 SDValue CPIdx =
Owen Anderson1d0be152009-08-13 21:58:54 +00001472 CurDAG->getTargetConstantPool(ConstantInt::get(
1473 Type::getInt32Ty(*CurDAG->getContext()), Val),
Evan Chenga8e29892007-01-19 07:51:42 +00001474 TLI.getPointerTy());
Evan Cheng012f2d92007-01-24 08:53:17 +00001475
1476 SDNode *ResNode;
Evan Cheng446c4282009-07-11 06:43:01 +00001477 if (Subtarget->isThumb1Only()) {
Evan Chengac0869d2009-11-21 06:21:52 +00001478 SDValue Pred = CurDAG->getTargetConstant(14, MVT::i32);
Owen Anderson825b72b2009-08-11 20:47:22 +00001479 SDValue PredReg = CurDAG->getRegister(0, MVT::i32);
Evan Cheng446c4282009-07-11 06:43:01 +00001480 SDValue Ops[] = { CPIdx, Pred, PredReg, CurDAG->getEntryNode() };
Dan Gohman602b0c82009-09-25 18:54:59 +00001481 ResNode = CurDAG->getMachineNode(ARM::tLDRcp, dl, MVT::i32, MVT::Other,
1482 Ops, 4);
Evan Cheng446c4282009-07-11 06:43:01 +00001483 } else {
Dan Gohman475871a2008-07-27 21:46:04 +00001484 SDValue Ops[] = {
Jim Grosbach764ab522009-08-11 15:33:49 +00001485 CPIdx,
Owen Anderson825b72b2009-08-11 20:47:22 +00001486 CurDAG->getRegister(0, MVT::i32),
1487 CurDAG->getTargetConstant(0, MVT::i32),
Evan Chengee568cf2007-07-05 07:15:27 +00001488 getAL(CurDAG),
Owen Anderson825b72b2009-08-11 20:47:22 +00001489 CurDAG->getRegister(0, MVT::i32),
Evan Cheng012f2d92007-01-24 08:53:17 +00001490 CurDAG->getEntryNode()
1491 };
Dan Gohman602b0c82009-09-25 18:54:59 +00001492 ResNode=CurDAG->getMachineNode(ARM::LDRcp, dl, MVT::i32, MVT::Other,
1493 Ops, 6);
Evan Cheng012f2d92007-01-24 08:53:17 +00001494 }
Dan Gohmaneeb3a002010-01-05 01:24:18 +00001495 ReplaceUses(SDValue(N, 0), SDValue(ResNode, 0));
Evan Chenga8e29892007-01-19 07:51:42 +00001496 return NULL;
1497 }
Jim Grosbach764ab522009-08-11 15:33:49 +00001498
Evan Chenga8e29892007-01-19 07:51:42 +00001499 // Other cases are autogenerated.
Rafael Espindola337c4ad62006-06-12 12:28:08 +00001500 break;
Evan Chenga8e29892007-01-19 07:51:42 +00001501 }
Rafael Espindolaf819a492006-11-09 13:58:55 +00001502 case ISD::FrameIndex: {
Evan Chenga8e29892007-01-19 07:51:42 +00001503 // Selects to ADDri FI, 0 which in turn will become ADDri SP, imm.
Rafael Espindolaf819a492006-11-09 13:58:55 +00001504 int FI = cast<FrameIndexSDNode>(N)->getIndex();
Dan Gohman475871a2008-07-27 21:46:04 +00001505 SDValue TFI = CurDAG->getTargetFrameIndex(FI, TLI.getPointerTy());
David Goodwinf1daf7d2009-07-08 23:10:31 +00001506 if (Subtarget->isThumb1Only()) {
Owen Anderson825b72b2009-08-11 20:47:22 +00001507 return CurDAG->SelectNodeTo(N, ARM::tADDrSPi, MVT::i32, TFI,
1508 CurDAG->getTargetConstant(0, MVT::i32));
Jim Grosbach30eae3c2009-04-07 20:34:09 +00001509 } else {
David Goodwin419c6152009-07-14 18:48:51 +00001510 unsigned Opc = ((Subtarget->isThumb() && Subtarget->hasThumb2()) ?
1511 ARM::t2ADDri : ARM::ADDri);
Owen Anderson825b72b2009-08-11 20:47:22 +00001512 SDValue Ops[] = { TFI, CurDAG->getTargetConstant(0, MVT::i32),
1513 getAL(CurDAG), CurDAG->getRegister(0, MVT::i32),
1514 CurDAG->getRegister(0, MVT::i32) };
1515 return CurDAG->SelectNodeTo(N, Opc, MVT::i32, Ops, 5);
Evan Chengee568cf2007-07-05 07:15:27 +00001516 }
Evan Chenga8e29892007-01-19 07:51:42 +00001517 }
Sandeep Patel47eedaa2009-10-13 18:59:48 +00001518 case ISD::SRL:
Dan Gohmaneeb3a002010-01-05 01:24:18 +00001519 if (SDNode *I = SelectV6T2BitfieldExtractOp(N,
Sandeep Patel47eedaa2009-10-13 18:59:48 +00001520 Subtarget->isThumb() ? ARM::t2UBFX : ARM::UBFX))
1521 return I;
1522 break;
1523 case ISD::SRA:
Dan Gohmaneeb3a002010-01-05 01:24:18 +00001524 if (SDNode *I = SelectV6T2BitfieldExtractOp(N,
Sandeep Patel47eedaa2009-10-13 18:59:48 +00001525 Subtarget->isThumb() ? ARM::t2SBFX : ARM::SBFX))
1526 return I;
1527 break;
Evan Chenga8e29892007-01-19 07:51:42 +00001528 case ISD::MUL:
Evan Cheng5b9fcd12009-07-07 01:17:28 +00001529 if (Subtarget->isThumb1Only())
Evan Cheng79d43262007-01-24 02:21:22 +00001530 break;
Dan Gohmaneeb3a002010-01-05 01:24:18 +00001531 if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(N->getOperand(1))) {
Dan Gohmanf5aeb1a2008-09-12 16:56:44 +00001532 unsigned RHSV = C->getZExtValue();
Evan Chenga8e29892007-01-19 07:51:42 +00001533 if (!RHSV) break;
1534 if (isPowerOf2_32(RHSV-1)) { // 2^n+1?
Evan Chengaf9e7a72009-07-21 00:31:12 +00001535 unsigned ShImm = Log2_32(RHSV-1);
1536 if (ShImm >= 32)
1537 break;
Dan Gohmaneeb3a002010-01-05 01:24:18 +00001538 SDValue V = N->getOperand(0);
Evan Chengaf9e7a72009-07-21 00:31:12 +00001539 ShImm = ARM_AM::getSORegOpc(ARM_AM::lsl, ShImm);
Owen Anderson825b72b2009-08-11 20:47:22 +00001540 SDValue ShImmOp = CurDAG->getTargetConstant(ShImm, MVT::i32);
1541 SDValue Reg0 = CurDAG->getRegister(0, MVT::i32);
Evan Cheng78dd9db2009-07-22 18:08:05 +00001542 if (Subtarget->isThumb()) {
Evan Chengaf9e7a72009-07-21 00:31:12 +00001543 SDValue Ops[] = { V, V, ShImmOp, getAL(CurDAG), Reg0, Reg0 };
Owen Anderson825b72b2009-08-11 20:47:22 +00001544 return CurDAG->SelectNodeTo(N, ARM::t2ADDrs, MVT::i32, Ops, 6);
Evan Chengaf9e7a72009-07-21 00:31:12 +00001545 } else {
1546 SDValue Ops[] = { V, V, Reg0, ShImmOp, getAL(CurDAG), Reg0, Reg0 };
Owen Anderson825b72b2009-08-11 20:47:22 +00001547 return CurDAG->SelectNodeTo(N, ARM::ADDrs, MVT::i32, Ops, 7);
Evan Chengaf9e7a72009-07-21 00:31:12 +00001548 }
Evan Chenga8e29892007-01-19 07:51:42 +00001549 }
1550 if (isPowerOf2_32(RHSV+1)) { // 2^n-1?
Evan Chengaf9e7a72009-07-21 00:31:12 +00001551 unsigned ShImm = Log2_32(RHSV+1);
1552 if (ShImm >= 32)
1553 break;
Dan Gohmaneeb3a002010-01-05 01:24:18 +00001554 SDValue V = N->getOperand(0);
Evan Chengaf9e7a72009-07-21 00:31:12 +00001555 ShImm = ARM_AM::getSORegOpc(ARM_AM::lsl, ShImm);
Owen Anderson825b72b2009-08-11 20:47:22 +00001556 SDValue ShImmOp = CurDAG->getTargetConstant(ShImm, MVT::i32);
1557 SDValue Reg0 = CurDAG->getRegister(0, MVT::i32);
Evan Cheng78dd9db2009-07-22 18:08:05 +00001558 if (Subtarget->isThumb()) {
Evan Chengaf9e7a72009-07-21 00:31:12 +00001559 SDValue Ops[] = { V, V, ShImmOp, getAL(CurDAG), Reg0 };
Owen Anderson825b72b2009-08-11 20:47:22 +00001560 return CurDAG->SelectNodeTo(N, ARM::t2RSBrs, MVT::i32, Ops, 5);
Evan Chengaf9e7a72009-07-21 00:31:12 +00001561 } else {
1562 SDValue Ops[] = { V, V, Reg0, ShImmOp, getAL(CurDAG), Reg0, Reg0 };
Owen Anderson825b72b2009-08-11 20:47:22 +00001563 return CurDAG->SelectNodeTo(N, ARM::RSBrs, MVT::i32, Ops, 7);
Evan Chengaf9e7a72009-07-21 00:31:12 +00001564 }
Evan Chenga8e29892007-01-19 07:51:42 +00001565 }
1566 }
1567 break;
Evan Cheng20956592009-10-21 08:15:52 +00001568 case ISD::AND: {
1569 // (and (or x, c2), c1) and top 16-bits of c1 and c2 match, lower 16-bits
1570 // of c1 are 0xffff, and lower 16-bit of c2 are 0. That is, the top 16-bits
1571 // are entirely contributed by c2 and lower 16-bits are entirely contributed
1572 // by x. That's equal to (or (and x, 0xffff), (and c1, 0xffff0000)).
1573 // Select it to: "movt x, ((c1 & 0xffff) >> 16)
Dan Gohmaneeb3a002010-01-05 01:24:18 +00001574 EVT VT = N->getValueType(0);
Evan Cheng20956592009-10-21 08:15:52 +00001575 if (VT != MVT::i32)
1576 break;
1577 unsigned Opc = (Subtarget->isThumb() && Subtarget->hasThumb2())
1578 ? ARM::t2MOVTi16
1579 : (Subtarget->hasV6T2Ops() ? ARM::MOVTi16 : 0);
1580 if (!Opc)
1581 break;
Dan Gohmaneeb3a002010-01-05 01:24:18 +00001582 SDValue N0 = N->getOperand(0), N1 = N->getOperand(1);
Evan Cheng20956592009-10-21 08:15:52 +00001583 ConstantSDNode *N1C = dyn_cast<ConstantSDNode>(N1);
1584 if (!N1C)
1585 break;
1586 if (N0.getOpcode() == ISD::OR && N0.getNode()->hasOneUse()) {
1587 SDValue N2 = N0.getOperand(1);
1588 ConstantSDNode *N2C = dyn_cast<ConstantSDNode>(N2);
1589 if (!N2C)
1590 break;
1591 unsigned N1CVal = N1C->getZExtValue();
1592 unsigned N2CVal = N2C->getZExtValue();
1593 if ((N1CVal & 0xffff0000U) == (N2CVal & 0xffff0000U) &&
1594 (N1CVal & 0xffffU) == 0xffffU &&
1595 (N2CVal & 0xffffU) == 0x0U) {
1596 SDValue Imm16 = CurDAG->getTargetConstant((N2CVal & 0xFFFF0000U) >> 16,
1597 MVT::i32);
1598 SDValue Ops[] = { N0.getOperand(0), Imm16,
1599 getAL(CurDAG), CurDAG->getRegister(0, MVT::i32) };
1600 return CurDAG->getMachineNode(Opc, dl, VT, Ops, 4);
1601 }
1602 }
1603 break;
1604 }
Jim Grosbache5165492009-11-09 00:11:35 +00001605 case ARMISD::VMOVRRD:
1606 return CurDAG->getMachineNode(ARM::VMOVRRD, dl, MVT::i32, MVT::i32,
Dan Gohmaneeb3a002010-01-05 01:24:18 +00001607 N->getOperand(0), getAL(CurDAG),
Dan Gohman602b0c82009-09-25 18:54:59 +00001608 CurDAG->getRegister(0, MVT::i32));
Dan Gohman525178c2007-10-08 18:33:35 +00001609 case ISD::UMUL_LOHI: {
Evan Cheng5b9fcd12009-07-07 01:17:28 +00001610 if (Subtarget->isThumb1Only())
1611 break;
1612 if (Subtarget->isThumb()) {
Dan Gohmaneeb3a002010-01-05 01:24:18 +00001613 SDValue Ops[] = { N->getOperand(0), N->getOperand(1),
Owen Anderson825b72b2009-08-11 20:47:22 +00001614 getAL(CurDAG), CurDAG->getRegister(0, MVT::i32),
1615 CurDAG->getRegister(0, MVT::i32) };
Dan Gohman602b0c82009-09-25 18:54:59 +00001616 return CurDAG->getMachineNode(ARM::t2UMULL, dl, MVT::i32, MVT::i32, Ops,4);
Evan Cheng5b9fcd12009-07-07 01:17:28 +00001617 } else {
Dan Gohmaneeb3a002010-01-05 01:24:18 +00001618 SDValue Ops[] = { N->getOperand(0), N->getOperand(1),
Owen Anderson825b72b2009-08-11 20:47:22 +00001619 getAL(CurDAG), CurDAG->getRegister(0, MVT::i32),
1620 CurDAG->getRegister(0, MVT::i32) };
Dan Gohman602b0c82009-09-25 18:54:59 +00001621 return CurDAG->getMachineNode(ARM::UMULL, dl, MVT::i32, MVT::i32, Ops, 5);
Evan Cheng5b9fcd12009-07-07 01:17:28 +00001622 }
Evan Chengee568cf2007-07-05 07:15:27 +00001623 }
Dan Gohman525178c2007-10-08 18:33:35 +00001624 case ISD::SMUL_LOHI: {
Evan Cheng5b9fcd12009-07-07 01:17:28 +00001625 if (Subtarget->isThumb1Only())
1626 break;
1627 if (Subtarget->isThumb()) {
Dan Gohmaneeb3a002010-01-05 01:24:18 +00001628 SDValue Ops[] = { N->getOperand(0), N->getOperand(1),
Owen Anderson825b72b2009-08-11 20:47:22 +00001629 getAL(CurDAG), CurDAG->getRegister(0, MVT::i32) };
Dan Gohman602b0c82009-09-25 18:54:59 +00001630 return CurDAG->getMachineNode(ARM::t2SMULL, dl, MVT::i32, MVT::i32, Ops,4);
Evan Cheng5b9fcd12009-07-07 01:17:28 +00001631 } else {
Dan Gohmaneeb3a002010-01-05 01:24:18 +00001632 SDValue Ops[] = { N->getOperand(0), N->getOperand(1),
Owen Anderson825b72b2009-08-11 20:47:22 +00001633 getAL(CurDAG), CurDAG->getRegister(0, MVT::i32),
1634 CurDAG->getRegister(0, MVT::i32) };
Dan Gohman602b0c82009-09-25 18:54:59 +00001635 return CurDAG->getMachineNode(ARM::SMULL, dl, MVT::i32, MVT::i32, Ops, 5);
Evan Cheng5b9fcd12009-07-07 01:17:28 +00001636 }
Evan Chengee568cf2007-07-05 07:15:27 +00001637 }
Evan Chenga8e29892007-01-19 07:51:42 +00001638 case ISD::LOAD: {
Evan Chenge88d5ce2009-07-02 07:28:31 +00001639 SDNode *ResNode = 0;
Evan Cheng5b9fcd12009-07-07 01:17:28 +00001640 if (Subtarget->isThumb() && Subtarget->hasThumb2())
Dan Gohmaneeb3a002010-01-05 01:24:18 +00001641 ResNode = SelectT2IndexedLoad(N);
Evan Chenge88d5ce2009-07-02 07:28:31 +00001642 else
Dan Gohmaneeb3a002010-01-05 01:24:18 +00001643 ResNode = SelectARMIndexedLoad(N);
Evan Chengaf4550f2009-07-02 01:23:32 +00001644 if (ResNode)
1645 return ResNode;
Bob Wilsondf9a4f02010-03-23 18:54:46 +00001646
1647 // VLDMQ must be custom-selected for "v2f64 load" to set the AM5Opc value.
1648 if (Subtarget->hasVFP2() &&
1649 N->getValueType(0).getSimpleVT().SimpleTy == MVT::v2f64) {
1650 SDValue Chain = N->getOperand(0);
1651 SDValue AM5Opc =
1652 CurDAG->getTargetConstant(ARM_AM::getAM5Opc(ARM_AM::ia, 4), MVT::i32);
1653 SDValue Pred = CurDAG->getTargetConstant(14, MVT::i32);
1654 SDValue PredReg = CurDAG->getRegister(0, MVT::i32);
1655 SDValue Ops[] = { N->getOperand(1), AM5Opc, Pred, PredReg, Chain };
1656 return CurDAG->getMachineNode(ARM::VLDMQ, dl, MVT::v2f64, MVT::Other,
1657 Ops, 5);
1658 }
1659 // Other cases are autogenerated.
1660 break;
1661 }
1662 case ISD::STORE: {
1663 // VSTMQ must be custom-selected for "v2f64 store" to set the AM5Opc value.
1664 if (Subtarget->hasVFP2() &&
1665 N->getOperand(1).getValueType().getSimpleVT().SimpleTy == MVT::v2f64) {
1666 SDValue Chain = N->getOperand(0);
1667 SDValue AM5Opc =
1668 CurDAG->getTargetConstant(ARM_AM::getAM5Opc(ARM_AM::ia, 4), MVT::i32);
1669 SDValue Pred = CurDAG->getTargetConstant(14, MVT::i32);
1670 SDValue PredReg = CurDAG->getRegister(0, MVT::i32);
1671 SDValue Ops[] = { N->getOperand(1), N->getOperand(2),
1672 AM5Opc, Pred, PredReg, Chain };
1673 return CurDAG->getMachineNode(ARM::VSTMQ, dl, MVT::Other, Ops, 6);
1674 }
Evan Chenga8e29892007-01-19 07:51:42 +00001675 // Other cases are autogenerated.
Rafael Espindolaf819a492006-11-09 13:58:55 +00001676 break;
Rafael Espindola337c4ad62006-06-12 12:28:08 +00001677 }
Evan Chengee568cf2007-07-05 07:15:27 +00001678 case ARMISD::BRCOND: {
1679 // Pattern: (ARMbrcond:void (bb:Other):$dst, (imm:i32):$cc)
1680 // Emits: (Bcc:void (bb:Other):$dst, (imm:i32):$cc)
1681 // Pattern complexity = 6 cost = 1 size = 0
Rafael Espindola7bc59bc2006-05-14 22:18:28 +00001682
Evan Chengee568cf2007-07-05 07:15:27 +00001683 // Pattern: (ARMbrcond:void (bb:Other):$dst, (imm:i32):$cc)
1684 // Emits: (tBcc:void (bb:Other):$dst, (imm:i32):$cc)
1685 // Pattern complexity = 6 cost = 1 size = 0
1686
David Goodwin5e47a9a2009-06-30 18:04:13 +00001687 // Pattern: (ARMbrcond:void (bb:Other):$dst, (imm:i32):$cc)
1688 // Emits: (t2Bcc:void (bb:Other):$dst, (imm:i32):$cc)
1689 // Pattern complexity = 6 cost = 1 size = 0
1690
Jim Grosbach764ab522009-08-11 15:33:49 +00001691 unsigned Opc = Subtarget->isThumb() ?
David Goodwin5e47a9a2009-06-30 18:04:13 +00001692 ((Subtarget->hasThumb2()) ? ARM::t2Bcc : ARM::tBcc) : ARM::Bcc;
Dan Gohmaneeb3a002010-01-05 01:24:18 +00001693 SDValue Chain = N->getOperand(0);
1694 SDValue N1 = N->getOperand(1);
1695 SDValue N2 = N->getOperand(2);
1696 SDValue N3 = N->getOperand(3);
1697 SDValue InFlag = N->getOperand(4);
Evan Chengee568cf2007-07-05 07:15:27 +00001698 assert(N1.getOpcode() == ISD::BasicBlock);
1699 assert(N2.getOpcode() == ISD::Constant);
1700 assert(N3.getOpcode() == ISD::Register);
1701
Dan Gohman475871a2008-07-27 21:46:04 +00001702 SDValue Tmp2 = CurDAG->getTargetConstant(((unsigned)
Dan Gohmanf5aeb1a2008-09-12 16:56:44 +00001703 cast<ConstantSDNode>(N2)->getZExtValue()),
Owen Anderson825b72b2009-08-11 20:47:22 +00001704 MVT::i32);
Dan Gohman475871a2008-07-27 21:46:04 +00001705 SDValue Ops[] = { N1, Tmp2, N3, Chain, InFlag };
Dan Gohman602b0c82009-09-25 18:54:59 +00001706 SDNode *ResNode = CurDAG->getMachineNode(Opc, dl, MVT::Other,
1707 MVT::Flag, Ops, 5);
Dan Gohman475871a2008-07-27 21:46:04 +00001708 Chain = SDValue(ResNode, 0);
Dan Gohmaneeb3a002010-01-05 01:24:18 +00001709 if (N->getNumValues() == 2) {
Dan Gohman475871a2008-07-27 21:46:04 +00001710 InFlag = SDValue(ResNode, 1);
Dan Gohmaneeb3a002010-01-05 01:24:18 +00001711 ReplaceUses(SDValue(N, 1), InFlag);
Chris Lattnera47b9bc2008-02-03 03:20:59 +00001712 }
Dan Gohmaneeb3a002010-01-05 01:24:18 +00001713 ReplaceUses(SDValue(N, 0),
Evan Chenged54de42009-11-19 08:16:50 +00001714 SDValue(Chain.getNode(), Chain.getResNo()));
Evan Chengee568cf2007-07-05 07:15:27 +00001715 return NULL;
1716 }
Evan Cheng07ba9062009-11-19 21:45:22 +00001717 case ARMISD::CMOV:
Dan Gohmaneeb3a002010-01-05 01:24:18 +00001718 return SelectCMOVOp(N);
Evan Chengee568cf2007-07-05 07:15:27 +00001719 case ARMISD::CNEG: {
Dan Gohmaneeb3a002010-01-05 01:24:18 +00001720 EVT VT = N->getValueType(0);
1721 SDValue N0 = N->getOperand(0);
1722 SDValue N1 = N->getOperand(1);
1723 SDValue N2 = N->getOperand(2);
1724 SDValue N3 = N->getOperand(3);
1725 SDValue InFlag = N->getOperand(4);
Evan Chengee568cf2007-07-05 07:15:27 +00001726 assert(N2.getOpcode() == ISD::Constant);
1727 assert(N3.getOpcode() == ISD::Register);
1728
Dan Gohman475871a2008-07-27 21:46:04 +00001729 SDValue Tmp2 = CurDAG->getTargetConstant(((unsigned)
Dan Gohmanf5aeb1a2008-09-12 16:56:44 +00001730 cast<ConstantSDNode>(N2)->getZExtValue()),
Owen Anderson825b72b2009-08-11 20:47:22 +00001731 MVT::i32);
Dan Gohman475871a2008-07-27 21:46:04 +00001732 SDValue Ops[] = { N0, N1, Tmp2, N3, InFlag };
Evan Chengee568cf2007-07-05 07:15:27 +00001733 unsigned Opc = 0;
Owen Anderson825b72b2009-08-11 20:47:22 +00001734 switch (VT.getSimpleVT().SimpleTy) {
Evan Chengee568cf2007-07-05 07:15:27 +00001735 default: assert(false && "Illegal conditional move type!");
1736 break;
Owen Anderson825b72b2009-08-11 20:47:22 +00001737 case MVT::f32:
Jim Grosbache5165492009-11-09 00:11:35 +00001738 Opc = ARM::VNEGScc;
Evan Chengee568cf2007-07-05 07:15:27 +00001739 break;
Owen Anderson825b72b2009-08-11 20:47:22 +00001740 case MVT::f64:
Jim Grosbache5165492009-11-09 00:11:35 +00001741 Opc = ARM::VNEGDcc;
Evan Chenge5ad88e2008-12-10 21:54:21 +00001742 break;
Evan Chengee568cf2007-07-05 07:15:27 +00001743 }
Dan Gohmaneeb3a002010-01-05 01:24:18 +00001744 return CurDAG->SelectNodeTo(N, Opc, VT, Ops, 5);
Evan Chengee568cf2007-07-05 07:15:27 +00001745 }
Evan Chenge5ad88e2008-12-10 21:54:21 +00001746
Anton Korobeynikov051cfd62009-08-21 12:41:42 +00001747 case ARMISD::VZIP: {
1748 unsigned Opc = 0;
Anton Korobeynikov62e84f12009-08-21 12:40:50 +00001749 EVT VT = N->getValueType(0);
Anton Korobeynikov051cfd62009-08-21 12:41:42 +00001750 switch (VT.getSimpleVT().SimpleTy) {
1751 default: return NULL;
1752 case MVT::v8i8: Opc = ARM::VZIPd8; break;
1753 case MVT::v4i16: Opc = ARM::VZIPd16; break;
1754 case MVT::v2f32:
1755 case MVT::v2i32: Opc = ARM::VZIPd32; break;
1756 case MVT::v16i8: Opc = ARM::VZIPq8; break;
1757 case MVT::v8i16: Opc = ARM::VZIPq16; break;
1758 case MVT::v4f32:
1759 case MVT::v4i32: Opc = ARM::VZIPq32; break;
1760 }
Evan Chengac0869d2009-11-21 06:21:52 +00001761 SDValue Pred = CurDAG->getTargetConstant(14, MVT::i32);
1762 SDValue PredReg = CurDAG->getRegister(0, MVT::i32);
1763 SDValue Ops[] = { N->getOperand(0), N->getOperand(1), Pred, PredReg };
1764 return CurDAG->getMachineNode(Opc, dl, VT, VT, Ops, 4);
Anton Korobeynikov62e84f12009-08-21 12:40:50 +00001765 }
Anton Korobeynikov051cfd62009-08-21 12:41:42 +00001766 case ARMISD::VUZP: {
1767 unsigned Opc = 0;
Anton Korobeynikov62e84f12009-08-21 12:40:50 +00001768 EVT VT = N->getValueType(0);
Anton Korobeynikov051cfd62009-08-21 12:41:42 +00001769 switch (VT.getSimpleVT().SimpleTy) {
1770 default: return NULL;
1771 case MVT::v8i8: Opc = ARM::VUZPd8; break;
1772 case MVT::v4i16: Opc = ARM::VUZPd16; break;
1773 case MVT::v2f32:
1774 case MVT::v2i32: Opc = ARM::VUZPd32; break;
1775 case MVT::v16i8: Opc = ARM::VUZPq8; break;
1776 case MVT::v8i16: Opc = ARM::VUZPq16; break;
1777 case MVT::v4f32:
1778 case MVT::v4i32: Opc = ARM::VUZPq32; break;
1779 }
Evan Chengac0869d2009-11-21 06:21:52 +00001780 SDValue Pred = CurDAG->getTargetConstant(14, MVT::i32);
1781 SDValue PredReg = CurDAG->getRegister(0, MVT::i32);
1782 SDValue Ops[] = { N->getOperand(0), N->getOperand(1), Pred, PredReg };
1783 return CurDAG->getMachineNode(Opc, dl, VT, VT, Ops, 4);
Anton Korobeynikov62e84f12009-08-21 12:40:50 +00001784 }
Anton Korobeynikov051cfd62009-08-21 12:41:42 +00001785 case ARMISD::VTRN: {
1786 unsigned Opc = 0;
Anton Korobeynikov62e84f12009-08-21 12:40:50 +00001787 EVT VT = N->getValueType(0);
Anton Korobeynikov051cfd62009-08-21 12:41:42 +00001788 switch (VT.getSimpleVT().SimpleTy) {
1789 default: return NULL;
1790 case MVT::v8i8: Opc = ARM::VTRNd8; break;
1791 case MVT::v4i16: Opc = ARM::VTRNd16; break;
1792 case MVT::v2f32:
1793 case MVT::v2i32: Opc = ARM::VTRNd32; break;
1794 case MVT::v16i8: Opc = ARM::VTRNq8; break;
1795 case MVT::v8i16: Opc = ARM::VTRNq16; break;
1796 case MVT::v4f32:
1797 case MVT::v4i32: Opc = ARM::VTRNq32; break;
1798 }
Evan Chengac0869d2009-11-21 06:21:52 +00001799 SDValue Pred = CurDAG->getTargetConstant(14, MVT::i32);
1800 SDValue PredReg = CurDAG->getRegister(0, MVT::i32);
1801 SDValue Ops[] = { N->getOperand(0), N->getOperand(1), Pred, PredReg };
1802 return CurDAG->getMachineNode(Opc, dl, VT, VT, Ops, 4);
Anton Korobeynikov62e84f12009-08-21 12:40:50 +00001803 }
Bob Wilson31fb12f2009-08-26 17:39:53 +00001804
1805 case ISD::INTRINSIC_VOID:
1806 case ISD::INTRINSIC_W_CHAIN: {
1807 unsigned IntNo = cast<ConstantSDNode>(N->getOperand(1))->getZExtValue();
Bob Wilson31fb12f2009-08-26 17:39:53 +00001808 switch (IntNo) {
1809 default:
1810 break;
1811
Bob Wilson621f1952010-03-23 05:25:43 +00001812 case Intrinsic::arm_neon_vld1: {
1813 unsigned DOpcodes[] = { ARM::VLD1d8, ARM::VLD1d16,
1814 ARM::VLD1d32, ARM::VLD1d64 };
1815 unsigned QOpcodes[] = { ARM::VLD1q8, ARM::VLD1q16,
1816 ARM::VLD1q32, ARM::VLD1q64 };
1817 return SelectVLD(N, 1, DOpcodes, QOpcodes, 0);
1818 }
1819
Bob Wilson31fb12f2009-08-26 17:39:53 +00001820 case Intrinsic::arm_neon_vld2: {
Bob Wilson3e36f132009-10-14 17:28:52 +00001821 unsigned DOpcodes[] = { ARM::VLD2d8, ARM::VLD2d16,
Bob Wilson621f1952010-03-23 05:25:43 +00001822 ARM::VLD2d32, ARM::VLD1q64 };
Bob Wilson3e36f132009-10-14 17:28:52 +00001823 unsigned QOpcodes[] = { ARM::VLD2q8, ARM::VLD2q16, ARM::VLD2q32 };
Dan Gohmaneeb3a002010-01-05 01:24:18 +00001824 return SelectVLD(N, 2, DOpcodes, QOpcodes, 0);
Bob Wilson31fb12f2009-08-26 17:39:53 +00001825 }
1826
1827 case Intrinsic::arm_neon_vld3: {
Bob Wilson3e36f132009-10-14 17:28:52 +00001828 unsigned DOpcodes[] = { ARM::VLD3d8, ARM::VLD3d16,
Bob Wilsona6979752010-03-22 18:13:18 +00001829 ARM::VLD3d32, ARM::VLD1d64T };
Bob Wilson95ffecd2010-03-20 18:35:24 +00001830 unsigned QOpcodes0[] = { ARM::VLD3q8_UPD,
1831 ARM::VLD3q16_UPD,
1832 ARM::VLD3q32_UPD };
1833 unsigned QOpcodes1[] = { ARM::VLD3q8odd_UPD,
1834 ARM::VLD3q16odd_UPD,
1835 ARM::VLD3q32odd_UPD };
Dan Gohmaneeb3a002010-01-05 01:24:18 +00001836 return SelectVLD(N, 3, DOpcodes, QOpcodes0, QOpcodes1);
Bob Wilson31fb12f2009-08-26 17:39:53 +00001837 }
1838
1839 case Intrinsic::arm_neon_vld4: {
Bob Wilson3e36f132009-10-14 17:28:52 +00001840 unsigned DOpcodes[] = { ARM::VLD4d8, ARM::VLD4d16,
Bob Wilsona6979752010-03-22 18:13:18 +00001841 ARM::VLD4d32, ARM::VLD1d64Q };
Bob Wilson95ffecd2010-03-20 18:35:24 +00001842 unsigned QOpcodes0[] = { ARM::VLD4q8_UPD,
1843 ARM::VLD4q16_UPD,
1844 ARM::VLD4q32_UPD };
1845 unsigned QOpcodes1[] = { ARM::VLD4q8odd_UPD,
1846 ARM::VLD4q16odd_UPD,
1847 ARM::VLD4q32odd_UPD };
Dan Gohmaneeb3a002010-01-05 01:24:18 +00001848 return SelectVLD(N, 4, DOpcodes, QOpcodes0, QOpcodes1);
Bob Wilson31fb12f2009-08-26 17:39:53 +00001849 }
1850
Bob Wilson243fcc52009-09-01 04:26:28 +00001851 case Intrinsic::arm_neon_vld2lane: {
Bob Wilsona7c397c2009-10-14 16:19:03 +00001852 unsigned DOpcodes[] = { ARM::VLD2LNd8, ARM::VLD2LNd16, ARM::VLD2LNd32 };
Bob Wilson95ffecd2010-03-20 18:35:24 +00001853 unsigned QOpcodes0[] = { ARM::VLD2LNq16, ARM::VLD2LNq32 };
1854 unsigned QOpcodes1[] = { ARM::VLD2LNq16odd, ARM::VLD2LNq32odd };
Dan Gohmaneeb3a002010-01-05 01:24:18 +00001855 return SelectVLDSTLane(N, true, 2, DOpcodes, QOpcodes0, QOpcodes1);
Bob Wilson243fcc52009-09-01 04:26:28 +00001856 }
1857
1858 case Intrinsic::arm_neon_vld3lane: {
Bob Wilsona7c397c2009-10-14 16:19:03 +00001859 unsigned DOpcodes[] = { ARM::VLD3LNd8, ARM::VLD3LNd16, ARM::VLD3LNd32 };
Bob Wilson95ffecd2010-03-20 18:35:24 +00001860 unsigned QOpcodes0[] = { ARM::VLD3LNq16, ARM::VLD3LNq32 };
1861 unsigned QOpcodes1[] = { ARM::VLD3LNq16odd, ARM::VLD3LNq32odd };
Dan Gohmaneeb3a002010-01-05 01:24:18 +00001862 return SelectVLDSTLane(N, true, 3, DOpcodes, QOpcodes0, QOpcodes1);
Bob Wilson243fcc52009-09-01 04:26:28 +00001863 }
1864
1865 case Intrinsic::arm_neon_vld4lane: {
Bob Wilsona7c397c2009-10-14 16:19:03 +00001866 unsigned DOpcodes[] = { ARM::VLD4LNd8, ARM::VLD4LNd16, ARM::VLD4LNd32 };
Bob Wilson95ffecd2010-03-20 18:35:24 +00001867 unsigned QOpcodes0[] = { ARM::VLD4LNq16, ARM::VLD4LNq32 };
1868 unsigned QOpcodes1[] = { ARM::VLD4LNq16odd, ARM::VLD4LNq32odd };
Dan Gohmaneeb3a002010-01-05 01:24:18 +00001869 return SelectVLDSTLane(N, true, 4, DOpcodes, QOpcodes0, QOpcodes1);
Bob Wilson243fcc52009-09-01 04:26:28 +00001870 }
1871
Bob Wilson11d98992010-03-23 06:20:33 +00001872 case Intrinsic::arm_neon_vst1: {
1873 unsigned DOpcodes[] = { ARM::VST1d8, ARM::VST1d16,
1874 ARM::VST1d32, ARM::VST1d64 };
1875 unsigned QOpcodes[] = { ARM::VST1q8, ARM::VST1q16,
1876 ARM::VST1q32, ARM::VST1q64 };
1877 return SelectVST(N, 1, DOpcodes, QOpcodes, 0);
1878 }
1879
Bob Wilson31fb12f2009-08-26 17:39:53 +00001880 case Intrinsic::arm_neon_vst2: {
Bob Wilson24f995d2009-10-14 18:32:29 +00001881 unsigned DOpcodes[] = { ARM::VST2d8, ARM::VST2d16,
Bob Wilson11d98992010-03-23 06:20:33 +00001882 ARM::VST2d32, ARM::VST1q64 };
Bob Wilson24f995d2009-10-14 18:32:29 +00001883 unsigned QOpcodes[] = { ARM::VST2q8, ARM::VST2q16, ARM::VST2q32 };
Dan Gohmaneeb3a002010-01-05 01:24:18 +00001884 return SelectVST(N, 2, DOpcodes, QOpcodes, 0);
Bob Wilson31fb12f2009-08-26 17:39:53 +00001885 }
1886
1887 case Intrinsic::arm_neon_vst3: {
Bob Wilson24f995d2009-10-14 18:32:29 +00001888 unsigned DOpcodes[] = { ARM::VST3d8, ARM::VST3d16,
Bob Wilsona6979752010-03-22 18:13:18 +00001889 ARM::VST3d32, ARM::VST1d64T };
Bob Wilson95ffecd2010-03-20 18:35:24 +00001890 unsigned QOpcodes0[] = { ARM::VST3q8_UPD,
1891 ARM::VST3q16_UPD,
1892 ARM::VST3q32_UPD };
1893 unsigned QOpcodes1[] = { ARM::VST3q8odd_UPD,
1894 ARM::VST3q16odd_UPD,
1895 ARM::VST3q32odd_UPD };
Dan Gohmaneeb3a002010-01-05 01:24:18 +00001896 return SelectVST(N, 3, DOpcodes, QOpcodes0, QOpcodes1);
Bob Wilson31fb12f2009-08-26 17:39:53 +00001897 }
1898
1899 case Intrinsic::arm_neon_vst4: {
Bob Wilson24f995d2009-10-14 18:32:29 +00001900 unsigned DOpcodes[] = { ARM::VST4d8, ARM::VST4d16,
Bob Wilsona6979752010-03-22 18:13:18 +00001901 ARM::VST4d32, ARM::VST1d64Q };
Bob Wilson95ffecd2010-03-20 18:35:24 +00001902 unsigned QOpcodes0[] = { ARM::VST4q8_UPD,
1903 ARM::VST4q16_UPD,
1904 ARM::VST4q32_UPD };
1905 unsigned QOpcodes1[] = { ARM::VST4q8odd_UPD,
1906 ARM::VST4q16odd_UPD,
1907 ARM::VST4q32odd_UPD };
Dan Gohmaneeb3a002010-01-05 01:24:18 +00001908 return SelectVST(N, 4, DOpcodes, QOpcodes0, QOpcodes1);
Bob Wilson31fb12f2009-08-26 17:39:53 +00001909 }
Bob Wilson8a3198b2009-09-01 18:51:56 +00001910
1911 case Intrinsic::arm_neon_vst2lane: {
Bob Wilson96493442009-10-14 16:46:45 +00001912 unsigned DOpcodes[] = { ARM::VST2LNd8, ARM::VST2LNd16, ARM::VST2LNd32 };
Bob Wilson95ffecd2010-03-20 18:35:24 +00001913 unsigned QOpcodes0[] = { ARM::VST2LNq16, ARM::VST2LNq32 };
1914 unsigned QOpcodes1[] = { ARM::VST2LNq16odd, ARM::VST2LNq32odd };
Dan Gohmaneeb3a002010-01-05 01:24:18 +00001915 return SelectVLDSTLane(N, false, 2, DOpcodes, QOpcodes0, QOpcodes1);
Bob Wilson8a3198b2009-09-01 18:51:56 +00001916 }
1917
1918 case Intrinsic::arm_neon_vst3lane: {
Bob Wilson96493442009-10-14 16:46:45 +00001919 unsigned DOpcodes[] = { ARM::VST3LNd8, ARM::VST3LNd16, ARM::VST3LNd32 };
Bob Wilson95ffecd2010-03-20 18:35:24 +00001920 unsigned QOpcodes0[] = { ARM::VST3LNq16, ARM::VST3LNq32 };
1921 unsigned QOpcodes1[] = { ARM::VST3LNq16odd, ARM::VST3LNq32odd };
Dan Gohmaneeb3a002010-01-05 01:24:18 +00001922 return SelectVLDSTLane(N, false, 3, DOpcodes, QOpcodes0, QOpcodes1);
Bob Wilson8a3198b2009-09-01 18:51:56 +00001923 }
1924
1925 case Intrinsic::arm_neon_vst4lane: {
Bob Wilson96493442009-10-14 16:46:45 +00001926 unsigned DOpcodes[] = { ARM::VST4LNd8, ARM::VST4LNd16, ARM::VST4LNd32 };
Bob Wilson95ffecd2010-03-20 18:35:24 +00001927 unsigned QOpcodes0[] = { ARM::VST4LNq16, ARM::VST4LNq32 };
1928 unsigned QOpcodes1[] = { ARM::VST4LNq16odd, ARM::VST4LNq32odd };
Dan Gohmaneeb3a002010-01-05 01:24:18 +00001929 return SelectVLDSTLane(N, false, 4, DOpcodes, QOpcodes0, QOpcodes1);
Bob Wilson8a3198b2009-09-01 18:51:56 +00001930 }
Bob Wilson31fb12f2009-08-26 17:39:53 +00001931 }
1932 }
Evan Chenge5ad88e2008-12-10 21:54:21 +00001933 }
1934
Dan Gohmaneeb3a002010-01-05 01:24:18 +00001935 return SelectCode(N);
Evan Chenga8e29892007-01-19 07:51:42 +00001936}
Rafael Espindola7bc59bc2006-05-14 22:18:28 +00001937
Bob Wilson224c2442009-05-19 05:53:42 +00001938bool ARMDAGToDAGISel::
1939SelectInlineAsmMemoryOperand(const SDValue &Op, char ConstraintCode,
1940 std::vector<SDValue> &OutOps) {
1941 assert(ConstraintCode == 'm' && "unexpected asm memory constraint");
Bob Wilson765cc0b2009-10-13 20:50:28 +00001942 // Require the address to be in a register. That is safe for all ARM
1943 // variants and it is hard to do anything much smarter without knowing
1944 // how the operand is used.
1945 OutOps.push_back(Op);
Bob Wilson224c2442009-05-19 05:53:42 +00001946 return false;
1947}
1948
Rafael Espindola7bc59bc2006-05-14 22:18:28 +00001949/// createARMISelDag - This pass converts a legalized DAG into a
1950/// ARM-specific DAG, ready for instruction scheduling.
1951///
Bob Wilson522ce972009-09-28 14:30:20 +00001952FunctionPass *llvm::createARMISelDag(ARMBaseTargetMachine &TM,
1953 CodeGenOpt::Level OptLevel) {
1954 return new ARMDAGToDAGISel(TM, OptLevel);
Rafael Espindola7bc59bc2006-05-14 22:18:28 +00001955}