blob: e35ec3f8a3afde8c9a0ee25d5f9dc1f0fabb438f [file] [log] [blame]
Rafael Espindolaffdc24b2006-05-14 22:18:28 +00001//===-- ARMISelDAGToDAG.cpp - A dag to dag inst selector for ARM ----------===//
2//
3// The LLVM Compiler Infrastructure
4//
Chris Lattnerf3ebc3f2007-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 Espindolaffdc24b2006-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 Cheng62c7b5b2010-12-05 22:04:16 +000015#include "ARMBaseInstrInfo.h"
Rafael Espindolaffdc24b2006-05-14 22:18:28 +000016#include "ARMTargetMachine.h"
Evan Chenga20cde32011-07-20 23:34:39 +000017#include "MCTargetDesc/ARMAddressingModes.h"
Luke Cheeseman85fd06d2015-06-01 12:02:47 +000018#include "llvm/ADT/StringSwitch.h"
Rafael Espindolaffdc24b2006-05-14 22:18:28 +000019#include "llvm/CodeGen/MachineFrameInfo.h"
20#include "llvm/CodeGen/MachineFunction.h"
21#include "llvm/CodeGen/MachineInstrBuilder.h"
Weiming Zhaoc5987002013-02-14 18:10:21 +000022#include "llvm/CodeGen/MachineRegisterInfo.h"
Rafael Espindolaffdc24b2006-05-14 22:18:28 +000023#include "llvm/CodeGen/SelectionDAG.h"
24#include "llvm/CodeGen/SelectionDAGISel.h"
Chandler Carruth9fb823b2013-01-02 11:36:10 +000025#include "llvm/IR/CallingConv.h"
26#include "llvm/IR/Constants.h"
27#include "llvm/IR/DerivedTypes.h"
28#include "llvm/IR/Function.h"
29#include "llvm/IR/Intrinsics.h"
30#include "llvm/IR/LLVMContext.h"
Evan Cheng8e6b40a2010-05-04 20:39:49 +000031#include "llvm/Support/CommandLine.h"
Rafael Espindolaffdc24b2006-05-14 22:18:28 +000032#include "llvm/Support/Debug.h"
Torok Edwinfb8d6d52009-07-08 20:53:28 +000033#include "llvm/Support/ErrorHandling.h"
Chandler Carruthed0881b2012-12-03 16:50:05 +000034#include "llvm/Target/TargetLowering.h"
35#include "llvm/Target/TargetOptions.h"
Torok Edwinfb8d6d52009-07-08 20:53:28 +000036
Rafael Espindolaffdc24b2006-05-14 22:18:28 +000037using namespace llvm;
38
Chandler Carruth84e68b22014-04-22 02:41:26 +000039#define DEBUG_TYPE "arm-isel"
40
Evan Cheng59069ec2010-07-30 23:33:54 +000041static cl::opt<bool>
42DisableShifterOp("disable-shifter-op", cl::Hidden,
43 cl::desc("Disable isel of shifter-op"),
44 cl::init(false));
45
Rafael Espindolaffdc24b2006-05-14 22:18:28 +000046//===--------------------------------------------------------------------===//
47/// ARMDAGToDAGISel - ARM specific code to select ARM machine
48/// instructions for SelectionDAG operations.
49///
50namespace {
Jim Grosbach08605202010-09-29 19:03:54 +000051
52enum AddrMode2Type {
53 AM2_BASE, // Simple AM2 (+-imm12)
54 AM2_SHOP // Shifter-op AM2
55};
56
Rafael Espindolaffdc24b2006-05-14 22:18:28 +000057class ARMDAGToDAGISel : public SelectionDAGISel {
Evan Cheng10043e22007-01-19 07:51:42 +000058 /// Subtarget - Keep a pointer to the ARMSubtarget around so that we can
59 /// make the right decision when generating code for different targets.
60 const ARMSubtarget *Subtarget;
61
Rafael Espindolaffdc24b2006-05-14 22:18:28 +000062public:
Eric Christopher2f991c92014-07-03 22:24:49 +000063 explicit ARMDAGToDAGISel(ARMBaseTargetMachine &tm, CodeGenOpt::Level OptLevel)
64 : SelectionDAGISel(tm, OptLevel) {}
Rafael Espindolaffdc24b2006-05-14 22:18:28 +000065
Eric Christopher0e6e7cf2014-05-22 02:00:27 +000066 bool runOnMachineFunction(MachineFunction &MF) override {
67 // Reset the subtarget each time through.
Eric Christopher22b2ad22015-02-20 08:24:37 +000068 Subtarget = &MF.getSubtarget<ARMSubtarget>();
Eric Christopher0e6e7cf2014-05-22 02:00:27 +000069 SelectionDAGISel::runOnMachineFunction(MF);
70 return true;
71 }
72
Mehdi Amini117296c2016-10-01 02:56:57 +000073 StringRef getPassName() const override { return "ARM Instruction Selection"; }
Anton Korobeynikov02bb33c2009-06-17 18:13:58 +000074
Craig Topper6bc27bf2014-03-10 02:09:33 +000075 void PreprocessISelDAG() override;
Evan Chengeae6d2c2012-12-19 20:16:09 +000076
Bob Wilson4facd962009-10-08 18:51:31 +000077 /// getI32Imm - Return a target constant of type i32 with the specified
78 /// value.
Benjamin Kramerbdc49562016-06-12 15:39:02 +000079 inline SDValue getI32Imm(unsigned Imm, const SDLoc &dl) {
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +000080 return CurDAG->getTargetConstant(Imm, dl, MVT::i32);
Anton Korobeynikov02bb33c2009-06-17 18:13:58 +000081 }
82
Justin Bogner45571362016-05-12 00:31:09 +000083 void Select(SDNode *N) override;
Evan Cheng62c7b5b2010-12-05 22:04:16 +000084
85 bool hasNoVMLxHazardUse(SDNode *N) const;
Evan Cheng59bbc542010-10-27 23:41:30 +000086 bool isShifterOpProfitable(const SDValue &Shift,
87 ARM_AM::ShiftOpc ShOpcVal, unsigned ShAmt);
Owen Andersonb595ed02011-07-21 18:54:16 +000088 bool SelectRegShifterOperand(SDValue N, SDValue &A,
89 SDValue &B, SDValue &C,
90 bool CheckProfitability = true);
91 bool SelectImmShifterOperand(SDValue N, SDValue &A,
Owen Anderson04912702011-07-21 23:38:37 +000092 SDValue &B, bool CheckProfitability = true);
93 bool SelectShiftRegShifterOperand(SDValue N, SDValue &A,
Owen Anderson6d557452011-03-18 19:46:58 +000094 SDValue &B, SDValue &C) {
95 // Don't apply the profitability check
Owen Anderson04912702011-07-21 23:38:37 +000096 return SelectRegShifterOperand(N, A, B, C, false);
97 }
98 bool SelectShiftImmShifterOperand(SDValue N, SDValue &A,
99 SDValue &B) {
100 // Don't apply the profitability check
101 return SelectImmShifterOperand(N, A, B, false);
Owen Anderson6d557452011-03-18 19:46:58 +0000102 }
103
Jim Grosbach1e4d9a12010-10-26 22:37:02 +0000104 bool SelectAddrModeImm12(SDValue N, SDValue &Base, SDValue &OffImm);
105 bool SelectLdStSOReg(SDValue N, SDValue &Base, SDValue &Offset, SDValue &Opc);
106
Jim Grosbach08605202010-09-29 19:03:54 +0000107 AddrMode2Type SelectAddrMode2Worker(SDValue N, SDValue &Base,
108 SDValue &Offset, SDValue &Opc);
109 bool SelectAddrMode2Base(SDValue N, SDValue &Base, SDValue &Offset,
110 SDValue &Opc) {
111 return SelectAddrMode2Worker(N, Base, Offset, Opc) == AM2_BASE;
112 }
113
114 bool SelectAddrMode2ShOp(SDValue N, SDValue &Base, SDValue &Offset,
115 SDValue &Opc) {
116 return SelectAddrMode2Worker(N, Base, Offset, Opc) == AM2_SHOP;
117 }
118
119 bool SelectAddrMode2(SDValue N, SDValue &Base, SDValue &Offset,
120 SDValue &Opc) {
121 SelectAddrMode2Worker(N, Base, Offset, Opc);
Jim Grosbach1e4d9a12010-10-26 22:37:02 +0000122// return SelectAddrMode2ShOp(N, Base, Offset, Opc);
Jim Grosbach08605202010-09-29 19:03:54 +0000123 // This always matches one way or another.
124 return true;
125 }
126
Tim Northover42180442013-08-22 09:57:11 +0000127 bool SelectCMOVPred(SDValue N, SDValue &Pred, SDValue &Reg) {
128 const ConstantSDNode *CN = cast<ConstantSDNode>(N);
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +0000129 Pred = CurDAG->getTargetConstant(CN->getZExtValue(), SDLoc(N), MVT::i32);
Tim Northover42180442013-08-22 09:57:11 +0000130 Reg = CurDAG->getRegister(ARM::CPSR, MVT::i32);
131 return true;
132 }
133
Owen Anderson2aedba62011-07-26 20:54:26 +0000134 bool SelectAddrMode2OffsetReg(SDNode *Op, SDValue N,
135 SDValue &Offset, SDValue &Opc);
136 bool SelectAddrMode2OffsetImm(SDNode *Op, SDValue N,
Dan Gohman2ce6f2a2008-07-27 21:46:04 +0000137 SDValue &Offset, SDValue &Opc);
Owen Anderson4d5c8f82011-08-29 20:16:50 +0000138 bool SelectAddrMode2OffsetImmPre(SDNode *Op, SDValue N,
139 SDValue &Offset, SDValue &Opc);
Jim Grosbachf0c95ca2011-08-05 20:35:44 +0000140 bool SelectAddrOffsetNone(SDValue N, SDValue &Base);
Chris Lattner0e023ea2010-09-21 20:31:19 +0000141 bool SelectAddrMode3(SDValue N, SDValue &Base,
Dan Gohman2ce6f2a2008-07-27 21:46:04 +0000142 SDValue &Offset, SDValue &Opc);
Dan Gohmanea6f91f2010-01-05 01:24:18 +0000143 bool SelectAddrMode3Offset(SDNode *Op, SDValue N,
Dan Gohman2ce6f2a2008-07-27 21:46:04 +0000144 SDValue &Offset, SDValue &Opc);
Chris Lattner0e023ea2010-09-21 20:31:19 +0000145 bool SelectAddrMode5(SDValue N, SDValue &Base,
Dan Gohman2ce6f2a2008-07-27 21:46:04 +0000146 SDValue &Offset);
Bob Wilsondd9fbaa2010-11-01 23:40:51 +0000147 bool SelectAddrMode6(SDNode *Parent, SDValue N, SDValue &Addr,SDValue &Align);
Bob Wilsone3ecd5f2011-02-25 06:42:42 +0000148 bool SelectAddrMode6Offset(SDNode *Op, SDValue N, SDValue &Offset);
Rafael Espindolaffdc24b2006-05-14 22:18:28 +0000149
Evan Chengdfce83c2011-01-17 08:03:18 +0000150 bool SelectAddrModePC(SDValue N, SDValue &Offset, SDValue &Label);
Evan Cheng10043e22007-01-19 07:51:42 +0000151
Bill Wendling092a7bd2010-12-14 03:36:38 +0000152 // Thumb Addressing Modes:
Chris Lattner0e023ea2010-09-21 20:31:19 +0000153 bool SelectThumbAddrModeRR(SDValue N, SDValue &Base, SDValue &Offset);
Bill Wendling092a7bd2010-12-14 03:36:38 +0000154 bool SelectThumbAddrModeImm5S(SDValue N, unsigned Scale, SDValue &Base,
155 SDValue &OffImm);
156 bool SelectThumbAddrModeImm5S1(SDValue N, SDValue &Base,
157 SDValue &OffImm);
158 bool SelectThumbAddrModeImm5S2(SDValue N, SDValue &Base,
159 SDValue &OffImm);
160 bool SelectThumbAddrModeImm5S4(SDValue N, SDValue &Base,
161 SDValue &OffImm);
Chris Lattner0e023ea2010-09-21 20:31:19 +0000162 bool SelectThumbAddrModeSP(SDValue N, SDValue &Base, SDValue &OffImm);
Evan Cheng10043e22007-01-19 07:51:42 +0000163
Bill Wendling092a7bd2010-12-14 03:36:38 +0000164 // Thumb 2 Addressing Modes:
Chris Lattner0e023ea2010-09-21 20:31:19 +0000165 bool SelectT2AddrModeImm12(SDValue N, SDValue &Base, SDValue &OffImm);
166 bool SelectT2AddrModeImm8(SDValue N, SDValue &Base,
Evan Chengb23b50d2009-06-29 07:51:04 +0000167 SDValue &OffImm);
Dan Gohmanea6f91f2010-01-05 01:24:18 +0000168 bool SelectT2AddrModeImm8Offset(SDNode *Op, SDValue N,
Evan Cheng84c6cda2009-07-02 07:28:31 +0000169 SDValue &OffImm);
Chris Lattner0e023ea2010-09-21 20:31:19 +0000170 bool SelectT2AddrModeSoReg(SDValue N, SDValue &Base,
Evan Chengb23b50d2009-06-29 07:51:04 +0000171 SDValue &OffReg, SDValue &ShImm);
Tim Northovera7ecd242013-07-16 09:46:55 +0000172 bool SelectT2AddrModeExclusive(SDValue N, SDValue &Base, SDValue &OffImm);
Evan Chengb23b50d2009-06-29 07:51:04 +0000173
Evan Cheng0fc80842010-11-12 22:42:47 +0000174 inline bool is_so_imm(unsigned Imm) const {
175 return ARM_AM::getSOImmVal(Imm) != -1;
176 }
177
178 inline bool is_so_imm_not(unsigned Imm) const {
179 return ARM_AM::getSOImmVal(~Imm) != -1;
180 }
181
182 inline bool is_t2_so_imm(unsigned Imm) const {
183 return ARM_AM::getT2SOImmVal(Imm) != -1;
184 }
185
186 inline bool is_t2_so_imm_not(unsigned Imm) const {
187 return ARM_AM::getT2SOImmVal(~Imm) != -1;
188 }
189
Rafael Espindolaffdc24b2006-05-14 22:18:28 +0000190 // Include the pieces autogenerated from the target description.
191#include "ARMGenDAGISel.inc"
Bob Wilsona2c462b2009-05-19 05:53:42 +0000192
193private:
Tim Northovereaee28b2016-09-19 09:11:09 +0000194 void transferMemOperands(SDNode *Src, SDNode *Dst);
195
Justin Bogner45571362016-05-12 00:31:09 +0000196 /// Indexed (pre/post inc/dec) load matching code for ARM.
197 bool tryARMIndexedLoad(SDNode *N);
James Molloyb3326df2016-07-15 08:03:56 +0000198 bool tryT1IndexedLoad(SDNode *N);
Justin Bogner45571362016-05-12 00:31:09 +0000199 bool tryT2IndexedLoad(SDNode *N);
Evan Cheng84c6cda2009-07-02 07:28:31 +0000200
Bob Wilson340861d2010-03-23 05:25:43 +0000201 /// SelectVLD - Select NEON load intrinsics. NumVecs should be
202 /// 1, 2, 3 or 4. The opcode arrays specify the instructions used for
Bob Wilson12b47992009-10-14 17:28:52 +0000203 /// loads of D registers and even subregs and odd subregs of Q registers.
Bob Wilson340861d2010-03-23 05:25:43 +0000204 /// For NumVecs <= 2, QOpcodes1 is not used.
Justin Bogner45571362016-05-12 00:31:09 +0000205 void SelectVLD(SDNode *N, bool isUpdating, unsigned NumVecs,
206 const uint16_t *DOpcodes, const uint16_t *QOpcodes0,
207 const uint16_t *QOpcodes1);
Bob Wilson12b47992009-10-14 17:28:52 +0000208
Bob Wilsonc350cdf2009-10-14 18:32:29 +0000209 /// SelectVST - Select NEON store intrinsics. NumVecs should
Bob Wilsoncc0a2a72010-03-23 06:20:33 +0000210 /// be 1, 2, 3 or 4. The opcode arrays specify the instructions used for
Bob Wilsonc350cdf2009-10-14 18:32:29 +0000211 /// stores of D registers and even subregs and odd subregs of Q registers.
Bob Wilsoncc0a2a72010-03-23 06:20:33 +0000212 /// For NumVecs <= 2, QOpcodes1 is not used.
Justin Bogner45571362016-05-12 00:31:09 +0000213 void SelectVST(SDNode *N, bool isUpdating, unsigned NumVecs,
214 const uint16_t *DOpcodes, const uint16_t *QOpcodes0,
215 const uint16_t *QOpcodes1);
Bob Wilsonc350cdf2009-10-14 18:32:29 +0000216
Bob Wilson93117bc2009-10-14 16:46:45 +0000217 /// SelectVLDSTLane - Select NEON load/store lane intrinsics. NumVecs should
Bob Wilson4145e3a2009-10-14 16:19:03 +0000218 /// be 2, 3 or 4. The opcode arrays specify the instructions used for
Bob Wilsond5c57a52010-09-13 23:01:35 +0000219 /// load/store of D registers and Q registers.
Justin Bogner45571362016-05-12 00:31:09 +0000220 void SelectVLDSTLane(SDNode *N, bool IsLoad, bool isUpdating,
221 unsigned NumVecs, const uint16_t *DOpcodes,
222 const uint16_t *QOpcodes);
Bob Wilson4145e3a2009-10-14 16:19:03 +0000223
Bob Wilson2d790df2010-11-28 06:51:26 +0000224 /// SelectVLDDup - Select NEON load-duplicate intrinsics. NumVecs
225 /// should be 2, 3 or 4. The opcode array specifies the instructions used
226 /// for loading D registers. (Q registers are not supported.)
Justin Bogner45571362016-05-12 00:31:09 +0000227 void SelectVLDDup(SDNode *N, bool isUpdating, unsigned NumVecs,
228 const uint16_t *Opcodes);
Bob Wilson2d790df2010-11-28 06:51:26 +0000229
Bob Wilson5bc8a792010-07-07 00:08:54 +0000230 /// SelectVTBL - Select NEON VTBL and VTBX intrinsics. NumVecs should be 2,
231 /// 3 or 4. These are custom-selected so that a REG_SEQUENCE can be
232 /// generated to force the table registers to be consecutive.
Justin Bogner45571362016-05-12 00:31:09 +0000233 void SelectVTBL(SDNode *N, bool IsExt, unsigned NumVecs, unsigned Opc);
Bob Wilson3ed511b2010-07-06 23:36:25 +0000234
Justin Bogner45571362016-05-12 00:31:09 +0000235 /// Try to select SBFX/UBFX instructions for ARM.
236 bool tryV6T2BitfieldExtractOp(SDNode *N, bool isSigned);
Sandeep Patel423e42b2009-10-13 18:59:48 +0000237
Bill Wendlinga7d697e2011-10-10 22:59:55 +0000238 // Select special operations if node forms integer ABS pattern
Justin Bogner45571362016-05-12 00:31:09 +0000239 bool tryABSOp(SDNode *N);
Bill Wendlinga7d697e2011-10-10 22:59:55 +0000240
Justin Bogner45571362016-05-12 00:31:09 +0000241 bool tryReadRegister(SDNode *N);
242 bool tryWriteRegister(SDNode *N);
Luke Cheeseman85fd06d2015-06-01 12:02:47 +0000243
Justin Bogner45571362016-05-12 00:31:09 +0000244 bool tryInlineAsm(SDNode *N);
Weiming Zhaoc5987002013-02-14 18:10:21 +0000245
Justin Bogner45571362016-05-12 00:31:09 +0000246 void SelectConcatVector(SDNode *N);
James Molloye7d97362016-11-03 14:08:01 +0000247
Justin Bogner45571362016-05-12 00:31:09 +0000248 bool trySMLAWSMULW(SDNode *N);
Sam Parker2d5126c2016-04-08 16:02:53 +0000249
Justin Bogner45571362016-05-12 00:31:09 +0000250 void SelectCMP_SWAP(SDNode *N);
Tim Northoverb629c772016-04-18 21:48:55 +0000251
Evan Chengd9c55362009-07-02 01:23:32 +0000252 /// SelectInlineAsmMemoryOperand - Implement addressing mode selection for
253 /// inline asm expressions.
Daniel Sanders60f1db02015-03-13 12:45:09 +0000254 bool SelectInlineAsmMemoryOperand(const SDValue &Op, unsigned ConstraintID,
Craig Topper6bc27bf2014-03-10 02:09:33 +0000255 std::vector<SDValue> &OutOps) override;
Bob Wilsone6b778d2009-10-06 22:01:59 +0000256
Weiming Zhao95782222012-11-17 00:23:35 +0000257 // Form pairs of consecutive R, S, D, or Q registers.
Weiming Zhao8f56f882012-11-16 21:55:34 +0000258 SDNode *createGPRPairNode(EVT VT, SDValue V0, SDValue V1);
Weiming Zhao95782222012-11-17 00:23:35 +0000259 SDNode *createSRegPairNode(EVT VT, SDValue V0, SDValue V1);
260 SDNode *createDRegPairNode(EVT VT, SDValue V0, SDValue V1);
261 SDNode *createQRegPairNode(EVT VT, SDValue V0, SDValue V1);
Evan Chengc2ae5f52010-05-10 17:34:18 +0000262
Bob Wilsond8a9a042010-06-04 00:04:02 +0000263 // Form sequences of 4 consecutive S, D, or Q registers.
Weiming Zhao95782222012-11-17 00:23:35 +0000264 SDNode *createQuadSRegsNode(EVT VT, SDValue V0, SDValue V1, SDValue V2, SDValue V3);
265 SDNode *createQuadDRegsNode(EVT VT, SDValue V0, SDValue V1, SDValue V2, SDValue V3);
266 SDNode *createQuadQRegsNode(EVT VT, SDValue V0, SDValue V1, SDValue V2, SDValue V3);
Bob Wilsondd9fbaa2010-11-01 23:40:51 +0000267
268 // Get the alignment operand for a NEON VLD or VST instruction.
Benjamin Kramerbdc49562016-06-12 15:39:02 +0000269 SDValue GetVLDSTAlign(SDValue Align, const SDLoc &dl, unsigned NumVecs,
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +0000270 bool is64BitVector);
John Brawn056e6782015-09-14 15:19:41 +0000271
272 /// Returns the number of instructions required to materialize the given
273 /// constant in a register, or 3 if a literal pool load is needed.
274 unsigned ConstantMaterializationCost(unsigned Val) const;
275
276 /// Checks if N is a multiplication by a constant where we can extract out a
277 /// power of two from the constant so that it can be used in a shift, but only
278 /// if it simplifies the materialization of the constant. Returns true if it
279 /// is, and assigns to PowerOfTwo the power of two that should be extracted
280 /// out and to NewMulConst the new constant to be multiplied by.
281 bool canExtractShiftFromMul(const SDValue &N, unsigned MaxShift,
282 unsigned &PowerOfTwo, SDValue &NewMulConst) const;
283
284 /// Replace N with M in CurDAG, in a way that also ensures that M gets
285 /// selected when N would have been selected.
286 void replaceDAGValue(const SDValue &N, SDValue M);
Rafael Espindolaffdc24b2006-05-14 22:18:28 +0000287};
Alexander Kornienkof00654e2015-06-23 09:49:53 +0000288}
Rafael Espindolaffdc24b2006-05-14 22:18:28 +0000289
Sandeep Patel423e42b2009-10-13 18:59:48 +0000290/// isInt32Immediate - This method tests to see if the node is a 32-bit constant
291/// operand. If so Imm will receive the 32-bit value.
292static bool isInt32Immediate(SDNode *N, unsigned &Imm) {
293 if (N->getOpcode() == ISD::Constant && N->getValueType(0) == MVT::i32) {
294 Imm = cast<ConstantSDNode>(N)->getZExtValue();
295 return true;
296 }
297 return false;
298}
299
300// isInt32Immediate - This method tests to see if a constant operand.
301// If so Imm will receive the 32 bit value.
302static bool isInt32Immediate(SDValue N, unsigned &Imm) {
303 return isInt32Immediate(N.getNode(), Imm);
304}
305
306// isOpcWithIntImmediate - This method tests to see if the node is a specific
307// opcode and that it has a immediate integer right operand.
308// If so Imm will receive the 32 bit value.
309static bool isOpcWithIntImmediate(SDNode *N, unsigned Opc, unsigned& Imm) {
310 return N->getOpcode() == Opc &&
311 isInt32Immediate(N->getOperand(1).getNode(), Imm);
312}
313
Daniel Dunbare0cd9ac2011-01-19 15:12:16 +0000314/// \brief Check whether a particular node is a constant value representable as
Dmitri Gribenko5485acd2012-09-14 14:57:36 +0000315/// (N * Scale) where (N in [\p RangeMin, \p RangeMax).
Daniel Dunbare0cd9ac2011-01-19 15:12:16 +0000316///
317/// \param ScaledConstant [out] - On success, the pre-scaled constant value.
Jakob Stoklund Olesen2056d152011-09-23 22:10:33 +0000318static bool isScaledConstantInRange(SDValue Node, int Scale,
Daniel Dunbare0cd9ac2011-01-19 15:12:16 +0000319 int RangeMin, int RangeMax,
320 int &ScaledConstant) {
Jakob Stoklund Olesen2056d152011-09-23 22:10:33 +0000321 assert(Scale > 0 && "Invalid scale!");
Daniel Dunbare0cd9ac2011-01-19 15:12:16 +0000322
323 // Check that this is a constant.
324 const ConstantSDNode *C = dyn_cast<ConstantSDNode>(Node);
325 if (!C)
326 return false;
327
328 ScaledConstant = (int) C->getZExtValue();
329 if ((ScaledConstant % Scale) != 0)
330 return false;
331
332 ScaledConstant /= Scale;
333 return ScaledConstant >= RangeMin && ScaledConstant < RangeMax;
334}
335
Evan Chengeae6d2c2012-12-19 20:16:09 +0000336void ARMDAGToDAGISel::PreprocessISelDAG() {
337 if (!Subtarget->hasV6T2Ops())
338 return;
339
340 bool isThumb2 = Subtarget->isThumb();
341 for (SelectionDAG::allnodes_iterator I = CurDAG->allnodes_begin(),
342 E = CurDAG->allnodes_end(); I != E; ) {
Duncan P. N. Exon Smith9f9559e2015-10-19 23:25:57 +0000343 SDNode *N = &*I++; // Preincrement iterator to avoid invalidation issues.
Evan Chengeae6d2c2012-12-19 20:16:09 +0000344
345 if (N->getOpcode() != ISD::ADD)
346 continue;
347
348 // Look for (add X1, (and (srl X2, c1), c2)) where c2 is constant with
349 // leading zeros, followed by consecutive set bits, followed by 1 or 2
350 // trailing zeros, e.g. 1020.
351 // Transform the expression to
352 // (add X1, (shl (and (srl X2, c1), (c2>>tz)), tz)) where tz is the number
353 // of trailing zeros of c2. The left shift would be folded as an shifter
354 // operand of 'add' and the 'and' and 'srl' would become a bits extraction
355 // node (UBFX).
356
357 SDValue N0 = N->getOperand(0);
358 SDValue N1 = N->getOperand(1);
359 unsigned And_imm = 0;
360 if (!isOpcWithIntImmediate(N1.getNode(), ISD::AND, And_imm)) {
361 if (isOpcWithIntImmediate(N0.getNode(), ISD::AND, And_imm))
362 std::swap(N0, N1);
363 }
364 if (!And_imm)
365 continue;
366
367 // Check if the AND mask is an immediate of the form: 000.....1111111100
Michael J. Spencerdf1ecbd72013-05-24 22:23:49 +0000368 unsigned TZ = countTrailingZeros(And_imm);
Evan Chengeae6d2c2012-12-19 20:16:09 +0000369 if (TZ != 1 && TZ != 2)
370 // Be conservative here. Shifter operands aren't always free. e.g. On
371 // Swift, left shifter operand of 1 / 2 for free but others are not.
372 // e.g.
373 // ubfx r3, r1, #16, #8
374 // ldr.w r3, [r0, r3, lsl #2]
375 // vs.
376 // mov.w r9, #1020
377 // and.w r2, r9, r1, lsr #14
378 // ldr r2, [r0, r2]
379 continue;
380 And_imm >>= TZ;
381 if (And_imm & (And_imm + 1))
382 continue;
383
384 // Look for (and (srl X, c1), c2).
385 SDValue Srl = N1.getOperand(0);
386 unsigned Srl_imm = 0;
387 if (!isOpcWithIntImmediate(Srl.getNode(), ISD::SRL, Srl_imm) ||
388 (Srl_imm <= 2))
389 continue;
390
391 // Make sure first operand is not a shifter operand which would prevent
392 // folding of the left shift.
393 SDValue CPTmp0;
394 SDValue CPTmp1;
395 SDValue CPTmp2;
396 if (isThumb2) {
John Brawnd8b405a2015-09-07 11:45:18 +0000397 if (SelectImmShifterOperand(N0, CPTmp0, CPTmp1))
Evan Chengeae6d2c2012-12-19 20:16:09 +0000398 continue;
399 } else {
400 if (SelectImmShifterOperand(N0, CPTmp0, CPTmp1) ||
401 SelectRegShifterOperand(N0, CPTmp0, CPTmp1, CPTmp2))
402 continue;
403 }
404
405 // Now make the transformation.
Andrew Trickef9de2a2013-05-25 02:42:55 +0000406 Srl = CurDAG->getNode(ISD::SRL, SDLoc(Srl), MVT::i32,
Evan Chengeae6d2c2012-12-19 20:16:09 +0000407 Srl.getOperand(0),
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +0000408 CurDAG->getConstant(Srl_imm + TZ, SDLoc(Srl),
409 MVT::i32));
Andrew Trickef9de2a2013-05-25 02:42:55 +0000410 N1 = CurDAG->getNode(ISD::AND, SDLoc(N1), MVT::i32,
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +0000411 Srl,
412 CurDAG->getConstant(And_imm, SDLoc(Srl), MVT::i32));
Andrew Trickef9de2a2013-05-25 02:42:55 +0000413 N1 = CurDAG->getNode(ISD::SHL, SDLoc(N1), MVT::i32,
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +0000414 N1, CurDAG->getConstant(TZ, SDLoc(Srl), MVT::i32));
Evan Chengeae6d2c2012-12-19 20:16:09 +0000415 CurDAG->UpdateNodeOperands(N, N0, N1);
Jim Grosbach1a597112014-04-03 23:43:18 +0000416 }
Evan Chengeae6d2c2012-12-19 20:16:09 +0000417}
418
Evan Cheng62c7b5b2010-12-05 22:04:16 +0000419/// hasNoVMLxHazardUse - Return true if it's desirable to select a FP MLA / MLS
420/// node. VFP / NEON fp VMLA / VMLS instructions have special RAW hazards (at
421/// least on current ARM implementations) which should be avoidded.
422bool ARMDAGToDAGISel::hasNoVMLxHazardUse(SDNode *N) const {
423 if (OptLevel == CodeGenOpt::None)
424 return true;
425
Diana Picus575f2bb2016-07-07 09:11:39 +0000426 if (!Subtarget->hasVMLxHazards())
Evan Cheng62c7b5b2010-12-05 22:04:16 +0000427 return true;
428
429 if (!N->hasOneUse())
430 return false;
431
432 SDNode *Use = *N->use_begin();
433 if (Use->getOpcode() == ISD::CopyToReg)
434 return true;
435 if (Use->isMachineOpcode()) {
Eric Christopher2f991c92014-07-03 22:24:49 +0000436 const ARMBaseInstrInfo *TII = static_cast<const ARMBaseInstrInfo *>(
Eric Christopherfc6de422014-08-05 02:39:49 +0000437 CurDAG->getSubtarget().getInstrInfo());
Bill Wendlinga3cd3502013-06-19 21:36:55 +0000438
Evan Cheng6cc775f2011-06-28 19:10:37 +0000439 const MCInstrDesc &MCID = TII->get(Use->getMachineOpcode());
440 if (MCID.mayStore())
Evan Cheng62c7b5b2010-12-05 22:04:16 +0000441 return true;
Evan Cheng6cc775f2011-06-28 19:10:37 +0000442 unsigned Opcode = MCID.getOpcode();
Evan Cheng62c7b5b2010-12-05 22:04:16 +0000443 if (Opcode == ARM::VMOVRS || Opcode == ARM::VMOVRRD)
444 return true;
445 // vmlx feeding into another vmlx. We actually want to unfold
446 // the use later in the MLxExpansion pass. e.g.
447 // vmla
448 // vmla (stall 8 cycles)
449 //
450 // vmul (5 cycles)
451 // vadd (5 cycles)
452 // vmla
453 // This adds up to about 18 - 19 cycles.
454 //
455 // vmla
456 // vmul (stall 4 cycles)
457 // vadd adds up to about 14 cycles.
458 return TII->isFpMLxInstruction(Opcode);
459 }
460
461 return false;
462}
Sandeep Patel423e42b2009-10-13 18:59:48 +0000463
Evan Cheng59bbc542010-10-27 23:41:30 +0000464bool ARMDAGToDAGISel::isShifterOpProfitable(const SDValue &Shift,
465 ARM_AM::ShiftOpc ShOpcVal,
466 unsigned ShAmt) {
Bob Wilsone8a549c2012-09-29 21:43:49 +0000467 if (!Subtarget->isLikeA9() && !Subtarget->isSwift())
Evan Cheng59bbc542010-10-27 23:41:30 +0000468 return true;
469 if (Shift.hasOneUse())
470 return true;
471 // R << 2 is free.
Bob Wilsone8a549c2012-09-29 21:43:49 +0000472 return ShOpcVal == ARM_AM::lsl &&
473 (ShAmt == 2 || (Subtarget->isSwift() && ShAmt == 1));
Evan Cheng59bbc542010-10-27 23:41:30 +0000474}
475
John Brawn056e6782015-09-14 15:19:41 +0000476unsigned ARMDAGToDAGISel::ConstantMaterializationCost(unsigned Val) const {
477 if (Subtarget->isThumb()) {
478 if (Val <= 255) return 1; // MOV
Weiming Zhaof68a6a72016-08-05 20:58:29 +0000479 if (Subtarget->hasV6T2Ops() &&
480 (Val <= 0xffff || ARM_AM::getT2SOImmValSplatVal(Val) != -1))
481 return 1; // MOVW
James Molloy65b6be12016-06-14 13:33:07 +0000482 if (Val <= 510) return 2; // MOV + ADDi8
John Brawn056e6782015-09-14 15:19:41 +0000483 if (~Val <= 255) return 2; // MOV + MVN
484 if (ARM_AM::isThumbImmShiftedVal(Val)) return 2; // MOV + LSL
485 } else {
486 if (ARM_AM::getSOImmVal(Val) != -1) return 1; // MOV
487 if (ARM_AM::getSOImmVal(~Val) != -1) return 1; // MVN
488 if (Subtarget->hasV6T2Ops() && Val <= 0xffff) return 1; // MOVW
489 if (ARM_AM::isSOImmTwoPartVal(Val)) return 2; // two instrs
490 }
491 if (Subtarget->useMovt(*MF)) return 2; // MOVW + MOVT
492 return 3; // Literal pool load
493}
494
495bool ARMDAGToDAGISel::canExtractShiftFromMul(const SDValue &N,
496 unsigned MaxShift,
497 unsigned &PowerOfTwo,
498 SDValue &NewMulConst) const {
499 assert(N.getOpcode() == ISD::MUL);
500 assert(MaxShift > 0);
501
502 // If the multiply is used in more than one place then changing the constant
503 // will make other uses incorrect, so don't.
504 if (!N.hasOneUse()) return false;
505 // Check if the multiply is by a constant
506 ConstantSDNode *MulConst = dyn_cast<ConstantSDNode>(N.getOperand(1));
507 if (!MulConst) return false;
508 // If the constant is used in more than one place then modifying it will mean
509 // we need to materialize two constants instead of one, which is a bad idea.
510 if (!MulConst->hasOneUse()) return false;
511 unsigned MulConstVal = MulConst->getZExtValue();
512 if (MulConstVal == 0) return false;
513
514 // Find the largest power of 2 that MulConstVal is a multiple of
515 PowerOfTwo = MaxShift;
516 while ((MulConstVal % (1 << PowerOfTwo)) != 0) {
517 --PowerOfTwo;
518 if (PowerOfTwo == 0) return false;
519 }
520
521 // Only optimise if the new cost is better
522 unsigned NewMulConstVal = MulConstVal / (1 << PowerOfTwo);
523 NewMulConst = CurDAG->getConstant(NewMulConstVal, SDLoc(N), MVT::i32);
524 unsigned OldCost = ConstantMaterializationCost(MulConstVal);
525 unsigned NewCost = ConstantMaterializationCost(NewMulConstVal);
526 return NewCost < OldCost;
527}
528
529void ARMDAGToDAGISel::replaceDAGValue(const SDValue &N, SDValue M) {
Duncan P. N. Exon Smith9f9559e2015-10-19 23:25:57 +0000530 CurDAG->RepositionNode(N.getNode()->getIterator(), M.getNode());
John Brawn056e6782015-09-14 15:19:41 +0000531 CurDAG->ReplaceAllUsesWith(N, M);
532}
533
Owen Andersonb595ed02011-07-21 18:54:16 +0000534bool ARMDAGToDAGISel::SelectImmShifterOperand(SDValue N,
Evan Chengb23b50d2009-06-29 07:51:04 +0000535 SDValue &BaseReg,
Owen Anderson6d557452011-03-18 19:46:58 +0000536 SDValue &Opc,
537 bool CheckProfitability) {
Evan Cheng59069ec2010-07-30 23:33:54 +0000538 if (DisableShifterOp)
539 return false;
540
John Brawn056e6782015-09-14 15:19:41 +0000541 // If N is a multiply-by-constant and it's profitable to extract a shift and
542 // use it in a shifted operand do so.
543 if (N.getOpcode() == ISD::MUL) {
544 unsigned PowerOfTwo = 0;
545 SDValue NewMulConst;
546 if (canExtractShiftFromMul(N, 31, PowerOfTwo, NewMulConst)) {
Justin Bogner8752be72016-05-05 01:43:49 +0000547 HandleSDNode Handle(N);
John Brawn056e6782015-09-14 15:19:41 +0000548 replaceDAGValue(N.getOperand(1), NewMulConst);
Justin Bogner8752be72016-05-05 01:43:49 +0000549 BaseReg = Handle.getValue();
John Brawn056e6782015-09-14 15:19:41 +0000550 Opc = CurDAG->getTargetConstant(ARM_AM::getSORegOpc(ARM_AM::lsl,
551 PowerOfTwo),
552 SDLoc(N), MVT::i32);
553 return true;
554 }
555 }
556
Evan Chenga20cde32011-07-20 23:34:39 +0000557 ARM_AM::ShiftOpc ShOpcVal = ARM_AM::getShiftOpcForNode(N.getOpcode());
Evan Chengb23b50d2009-06-29 07:51:04 +0000558
559 // Don't match base register only case. That is matched to a separate
560 // lower complexity pattern with explicit register operand.
561 if (ShOpcVal == ARM_AM::no_shift) return false;
Jim Grosbachf24f9d92009-08-11 15:33:49 +0000562
Evan Chengb23b50d2009-06-29 07:51:04 +0000563 BaseReg = N.getOperand(0);
564 unsigned ShImmVal = 0;
Owen Andersonb595ed02011-07-21 18:54:16 +0000565 ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(N.getOperand(1));
566 if (!RHS) return false;
Owen Andersonb595ed02011-07-21 18:54:16 +0000567 ShImmVal = RHS->getZExtValue() & 31;
Evan Cheng59bbc542010-10-27 23:41:30 +0000568 Opc = CurDAG->getTargetConstant(ARM_AM::getSORegOpc(ShOpcVal, ShImmVal),
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +0000569 SDLoc(N), MVT::i32);
Evan Cheng59bbc542010-10-27 23:41:30 +0000570 return true;
571}
572
Owen Andersonb595ed02011-07-21 18:54:16 +0000573bool ARMDAGToDAGISel::SelectRegShifterOperand(SDValue N,
574 SDValue &BaseReg,
575 SDValue &ShReg,
576 SDValue &Opc,
577 bool CheckProfitability) {
578 if (DisableShifterOp)
579 return false;
580
581 ARM_AM::ShiftOpc ShOpcVal = ARM_AM::getShiftOpcForNode(N.getOpcode());
582
583 // Don't match base register only case. That is matched to a separate
584 // lower complexity pattern with explicit register operand.
585 if (ShOpcVal == ARM_AM::no_shift) return false;
586
587 BaseReg = N.getOperand(0);
588 unsigned ShImmVal = 0;
589 ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(N.getOperand(1));
590 if (RHS) return false;
591
592 ShReg = N.getOperand(1);
593 if (CheckProfitability && !isShifterOpProfitable(N, ShOpcVal, ShImmVal))
594 return false;
595 Opc = CurDAG->getTargetConstant(ARM_AM::getSORegOpc(ShOpcVal, ShImmVal),
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +0000596 SDLoc(N), MVT::i32);
Owen Andersonb595ed02011-07-21 18:54:16 +0000597 return true;
598}
599
600
Jim Grosbach1e4d9a12010-10-26 22:37:02 +0000601bool ARMDAGToDAGISel::SelectAddrModeImm12(SDValue N,
602 SDValue &Base,
603 SDValue &OffImm) {
604 // Match simple R + imm12 operands.
605
606 // Base only.
Chris Lattner46c01a32011-02-13 22:25:43 +0000607 if (N.getOpcode() != ISD::ADD && N.getOpcode() != ISD::SUB &&
608 !CurDAG->isBaseWithConstantOffset(N)) {
Jim Grosbach1e4d9a12010-10-26 22:37:02 +0000609 if (N.getOpcode() == ISD::FrameIndex) {
Chris Lattner46c01a32011-02-13 22:25:43 +0000610 // Match frame index.
Jim Grosbach1e4d9a12010-10-26 22:37:02 +0000611 int FI = cast<FrameIndexSDNode>(N)->getIndex();
Mehdi Amini44ede332015-07-09 02:09:04 +0000612 Base = CurDAG->getTargetFrameIndex(
613 FI, TLI->getPointerTy(CurDAG->getDataLayout()));
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +0000614 OffImm = CurDAG->getTargetConstant(0, SDLoc(N), MVT::i32);
Jim Grosbach1e4d9a12010-10-26 22:37:02 +0000615 return true;
Chris Lattner46c01a32011-02-13 22:25:43 +0000616 }
Owen Anderson6d557452011-03-18 19:46:58 +0000617
Chris Lattner46c01a32011-02-13 22:25:43 +0000618 if (N.getOpcode() == ARMISD::Wrapper &&
Tim Northoverbd41cf82016-01-07 09:03:03 +0000619 N.getOperand(0).getOpcode() != ISD::TargetGlobalAddress &&
Saleem Abdulrasoolf36005a2016-02-03 18:21:59 +0000620 N.getOperand(0).getOpcode() != ISD::TargetExternalSymbol &&
Tim Northoverbd41cf82016-01-07 09:03:03 +0000621 N.getOperand(0).getOpcode() != ISD::TargetGlobalTLSAddress) {
Jim Grosbach1e4d9a12010-10-26 22:37:02 +0000622 Base = N.getOperand(0);
623 } else
624 Base = N;
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +0000625 OffImm = CurDAG->getTargetConstant(0, SDLoc(N), MVT::i32);
Jim Grosbach1e4d9a12010-10-26 22:37:02 +0000626 return true;
627 }
628
629 if (ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(N.getOperand(1))) {
Renato Golin63e27982014-09-09 09:57:59 +0000630 int RHSC = (int)RHS->getSExtValue();
Jim Grosbach1e4d9a12010-10-26 22:37:02 +0000631 if (N.getOpcode() == ISD::SUB)
632 RHSC = -RHSC;
633
Renato Golin63e27982014-09-09 09:57:59 +0000634 if (RHSC > -0x1000 && RHSC < 0x1000) { // 12 bits
Jim Grosbach1e4d9a12010-10-26 22:37:02 +0000635 Base = N.getOperand(0);
636 if (Base.getOpcode() == ISD::FrameIndex) {
637 int FI = cast<FrameIndexSDNode>(Base)->getIndex();
Mehdi Amini44ede332015-07-09 02:09:04 +0000638 Base = CurDAG->getTargetFrameIndex(
639 FI, TLI->getPointerTy(CurDAG->getDataLayout()));
Jim Grosbach1e4d9a12010-10-26 22:37:02 +0000640 }
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +0000641 OffImm = CurDAG->getTargetConstant(RHSC, SDLoc(N), MVT::i32);
Jim Grosbach1e4d9a12010-10-26 22:37:02 +0000642 return true;
643 }
644 }
645
646 // Base only.
647 Base = N;
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +0000648 OffImm = CurDAG->getTargetConstant(0, SDLoc(N), MVT::i32);
Jim Grosbach1e4d9a12010-10-26 22:37:02 +0000649 return true;
650}
651
652
653
654bool ARMDAGToDAGISel::SelectLdStSOReg(SDValue N, SDValue &Base, SDValue &Offset,
655 SDValue &Opc) {
Evan Cheng59bbc542010-10-27 23:41:30 +0000656 if (N.getOpcode() == ISD::MUL &&
Bob Wilsone8a549c2012-09-29 21:43:49 +0000657 ((!Subtarget->isLikeA9() && !Subtarget->isSwift()) || N.hasOneUse())) {
Jim Grosbach1e4d9a12010-10-26 22:37:02 +0000658 if (ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(N.getOperand(1))) {
659 // X * [3,5,9] -> X + X * [2,4,8] etc.
660 int RHSC = (int)RHS->getZExtValue();
661 if (RHSC & 1) {
662 RHSC = RHSC & ~1;
663 ARM_AM::AddrOpc AddSub = ARM_AM::add;
664 if (RHSC < 0) {
665 AddSub = ARM_AM::sub;
666 RHSC = - RHSC;
667 }
668 if (isPowerOf2_32(RHSC)) {
669 unsigned ShAmt = Log2_32(RHSC);
670 Base = Offset = N.getOperand(0);
671 Opc = CurDAG->getTargetConstant(ARM_AM::getAM2Opc(AddSub, ShAmt,
672 ARM_AM::lsl),
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +0000673 SDLoc(N), MVT::i32);
Jim Grosbach1e4d9a12010-10-26 22:37:02 +0000674 return true;
675 }
676 }
677 }
678 }
679
Chris Lattner46c01a32011-02-13 22:25:43 +0000680 if (N.getOpcode() != ISD::ADD && N.getOpcode() != ISD::SUB &&
681 // ISD::OR that is equivalent to an ISD::ADD.
682 !CurDAG->isBaseWithConstantOffset(N))
Jim Grosbach1e4d9a12010-10-26 22:37:02 +0000683 return false;
684
685 // Leave simple R +/- imm12 operands for LDRi12
Chris Lattner46c01a32011-02-13 22:25:43 +0000686 if (N.getOpcode() == ISD::ADD || N.getOpcode() == ISD::OR) {
Daniel Dunbare0cd9ac2011-01-19 15:12:16 +0000687 int RHSC;
688 if (isScaledConstantInRange(N.getOperand(1), /*Scale=*/1,
689 -0x1000+1, 0x1000, RHSC)) // 12 bits.
690 return false;
Jim Grosbach1e4d9a12010-10-26 22:37:02 +0000691 }
692
693 // Otherwise this is R +/- [possibly shifted] R.
Chris Lattner46c01a32011-02-13 22:25:43 +0000694 ARM_AM::AddrOpc AddSub = N.getOpcode() == ISD::SUB ? ARM_AM::sub:ARM_AM::add;
Evan Chenga20cde32011-07-20 23:34:39 +0000695 ARM_AM::ShiftOpc ShOpcVal =
696 ARM_AM::getShiftOpcForNode(N.getOperand(1).getOpcode());
Jim Grosbach1e4d9a12010-10-26 22:37:02 +0000697 unsigned ShAmt = 0;
698
699 Base = N.getOperand(0);
700 Offset = N.getOperand(1);
701
702 if (ShOpcVal != ARM_AM::no_shift) {
703 // Check to see if the RHS of the shift is a constant, if not, we can't fold
704 // it.
705 if (ConstantSDNode *Sh =
706 dyn_cast<ConstantSDNode>(N.getOperand(1).getOperand(1))) {
707 ShAmt = Sh->getZExtValue();
Evan Cheng59bbc542010-10-27 23:41:30 +0000708 if (isShifterOpProfitable(Offset, ShOpcVal, ShAmt))
709 Offset = N.getOperand(1).getOperand(0);
710 else {
711 ShAmt = 0;
712 ShOpcVal = ARM_AM::no_shift;
713 }
Jim Grosbach1e4d9a12010-10-26 22:37:02 +0000714 } else {
715 ShOpcVal = ARM_AM::no_shift;
716 }
717 }
718
719 // Try matching (R shl C) + (R).
Chris Lattner46c01a32011-02-13 22:25:43 +0000720 if (N.getOpcode() != ISD::SUB && ShOpcVal == ARM_AM::no_shift &&
Bob Wilsone8a549c2012-09-29 21:43:49 +0000721 !(Subtarget->isLikeA9() || Subtarget->isSwift() ||
722 N.getOperand(0).hasOneUse())) {
Evan Chenga20cde32011-07-20 23:34:39 +0000723 ShOpcVal = ARM_AM::getShiftOpcForNode(N.getOperand(0).getOpcode());
Jim Grosbach1e4d9a12010-10-26 22:37:02 +0000724 if (ShOpcVal != ARM_AM::no_shift) {
725 // Check to see if the RHS of the shift is a constant, if not, we can't
726 // fold it.
727 if (ConstantSDNode *Sh =
728 dyn_cast<ConstantSDNode>(N.getOperand(0).getOperand(1))) {
729 ShAmt = Sh->getZExtValue();
Cameron Zwarich842f99a2011-10-05 23:39:02 +0000730 if (isShifterOpProfitable(N.getOperand(0), ShOpcVal, ShAmt)) {
Evan Cheng59bbc542010-10-27 23:41:30 +0000731 Offset = N.getOperand(0).getOperand(0);
732 Base = N.getOperand(1);
733 } else {
734 ShAmt = 0;
735 ShOpcVal = ARM_AM::no_shift;
736 }
Jim Grosbach1e4d9a12010-10-26 22:37:02 +0000737 } else {
738 ShOpcVal = ARM_AM::no_shift;
739 }
740 }
741 }
742
John Brawn056e6782015-09-14 15:19:41 +0000743 // If Offset is a multiply-by-constant and it's profitable to extract a shift
744 // and use it in a shifted operand do so.
Tim Northoverc4093c32016-01-29 19:18:46 +0000745 if (Offset.getOpcode() == ISD::MUL && N.hasOneUse()) {
John Brawn056e6782015-09-14 15:19:41 +0000746 unsigned PowerOfTwo = 0;
747 SDValue NewMulConst;
748 if (canExtractShiftFromMul(Offset, 31, PowerOfTwo, NewMulConst)) {
749 replaceDAGValue(Offset.getOperand(1), NewMulConst);
750 ShAmt = PowerOfTwo;
751 ShOpcVal = ARM_AM::lsl;
752 }
753 }
754
Jim Grosbach1e4d9a12010-10-26 22:37:02 +0000755 Opc = CurDAG->getTargetConstant(ARM_AM::getAM2Opc(AddSub, ShAmt, ShOpcVal),
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +0000756 SDLoc(N), MVT::i32);
Jim Grosbach1e4d9a12010-10-26 22:37:02 +0000757 return true;
758}
759
760
Jim Grosbach1e4d9a12010-10-26 22:37:02 +0000761//-----
762
Jim Grosbach08605202010-09-29 19:03:54 +0000763AddrMode2Type ARMDAGToDAGISel::SelectAddrMode2Worker(SDValue N,
764 SDValue &Base,
765 SDValue &Offset,
766 SDValue &Opc) {
Evan Cheng59bbc542010-10-27 23:41:30 +0000767 if (N.getOpcode() == ISD::MUL &&
Bob Wilsone8a549c2012-09-29 21:43:49 +0000768 (!(Subtarget->isLikeA9() || Subtarget->isSwift()) || N.hasOneUse())) {
Evan Cheng72a8bcf2007-03-13 21:05:54 +0000769 if (ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(N.getOperand(1))) {
770 // X * [3,5,9] -> X + X * [2,4,8] etc.
Dan Gohmaneffb8942008-09-12 16:56:44 +0000771 int RHSC = (int)RHS->getZExtValue();
Evan Cheng72a8bcf2007-03-13 21:05:54 +0000772 if (RHSC & 1) {
773 RHSC = RHSC & ~1;
774 ARM_AM::AddrOpc AddSub = ARM_AM::add;
775 if (RHSC < 0) {
776 AddSub = ARM_AM::sub;
777 RHSC = - RHSC;
778 }
779 if (isPowerOf2_32(RHSC)) {
780 unsigned ShAmt = Log2_32(RHSC);
781 Base = Offset = N.getOperand(0);
782 Opc = CurDAG->getTargetConstant(ARM_AM::getAM2Opc(AddSub, ShAmt,
783 ARM_AM::lsl),
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +0000784 SDLoc(N), MVT::i32);
Jim Grosbach08605202010-09-29 19:03:54 +0000785 return AM2_SHOP;
Evan Cheng72a8bcf2007-03-13 21:05:54 +0000786 }
787 }
788 }
789 }
790
Chris Lattner46c01a32011-02-13 22:25:43 +0000791 if (N.getOpcode() != ISD::ADD && N.getOpcode() != ISD::SUB &&
792 // ISD::OR that is equivalent to an ADD.
793 !CurDAG->isBaseWithConstantOffset(N)) {
Evan Cheng10043e22007-01-19 07:51:42 +0000794 Base = N;
795 if (N.getOpcode() == ISD::FrameIndex) {
796 int FI = cast<FrameIndexSDNode>(N)->getIndex();
Mehdi Amini44ede332015-07-09 02:09:04 +0000797 Base = CurDAG->getTargetFrameIndex(
798 FI, TLI->getPointerTy(CurDAG->getDataLayout()));
Anton Korobeynikov25229082009-11-24 00:44:37 +0000799 } else if (N.getOpcode() == ARMISD::Wrapper &&
Tim Northoverbd41cf82016-01-07 09:03:03 +0000800 N.getOperand(0).getOpcode() != ISD::TargetGlobalAddress &&
Saleem Abdulrasoolf36005a2016-02-03 18:21:59 +0000801 N.getOperand(0).getOpcode() != ISD::TargetExternalSymbol &&
Tim Northoverbd41cf82016-01-07 09:03:03 +0000802 N.getOperand(0).getOpcode() != ISD::TargetGlobalTLSAddress) {
Evan Cheng10043e22007-01-19 07:51:42 +0000803 Base = N.getOperand(0);
804 }
Owen Anderson9f944592009-08-11 20:47:22 +0000805 Offset = CurDAG->getRegister(0, MVT::i32);
Evan Cheng10043e22007-01-19 07:51:42 +0000806 Opc = CurDAG->getTargetConstant(ARM_AM::getAM2Opc(ARM_AM::add, 0,
807 ARM_AM::no_shift),
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +0000808 SDLoc(N), MVT::i32);
Jim Grosbach08605202010-09-29 19:03:54 +0000809 return AM2_BASE;
Rafael Espindola708cb602006-11-08 17:07:32 +0000810 }
Jim Grosbachf24f9d92009-08-11 15:33:49 +0000811
Evan Cheng10043e22007-01-19 07:51:42 +0000812 // Match simple R +/- imm12 operands.
Chris Lattner46c01a32011-02-13 22:25:43 +0000813 if (N.getOpcode() != ISD::SUB) {
Daniel Dunbare0cd9ac2011-01-19 15:12:16 +0000814 int RHSC;
815 if (isScaledConstantInRange(N.getOperand(1), /*Scale=*/1,
816 -0x1000+1, 0x1000, RHSC)) { // 12 bits.
817 Base = N.getOperand(0);
818 if (Base.getOpcode() == ISD::FrameIndex) {
819 int FI = cast<FrameIndexSDNode>(Base)->getIndex();
Mehdi Amini44ede332015-07-09 02:09:04 +0000820 Base = CurDAG->getTargetFrameIndex(
821 FI, TLI->getPointerTy(CurDAG->getDataLayout()));
Rafael Espindola708cb602006-11-08 17:07:32 +0000822 }
Daniel Dunbare0cd9ac2011-01-19 15:12:16 +0000823 Offset = CurDAG->getRegister(0, MVT::i32);
824
825 ARM_AM::AddrOpc AddSub = ARM_AM::add;
826 if (RHSC < 0) {
827 AddSub = ARM_AM::sub;
828 RHSC = - RHSC;
829 }
830 Opc = CurDAG->getTargetConstant(ARM_AM::getAM2Opc(AddSub, RHSC,
831 ARM_AM::no_shift),
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +0000832 SDLoc(N), MVT::i32);
Daniel Dunbare0cd9ac2011-01-19 15:12:16 +0000833 return AM2_BASE;
Evan Cheng10043e22007-01-19 07:51:42 +0000834 }
Jim Grosbachc7b10f32010-09-29 17:32:29 +0000835 }
Jim Grosbachf24f9d92009-08-11 15:33:49 +0000836
Bob Wilsone8a549c2012-09-29 21:43:49 +0000837 if ((Subtarget->isLikeA9() || Subtarget->isSwift()) && !N.hasOneUse()) {
Evan Cheng59bbc542010-10-27 23:41:30 +0000838 // Compute R +/- (R << N) and reuse it.
839 Base = N;
840 Offset = CurDAG->getRegister(0, MVT::i32);
841 Opc = CurDAG->getTargetConstant(ARM_AM::getAM2Opc(ARM_AM::add, 0,
842 ARM_AM::no_shift),
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +0000843 SDLoc(N), MVT::i32);
Evan Cheng59bbc542010-10-27 23:41:30 +0000844 return AM2_BASE;
845 }
846
Johnny Chenb678a562009-10-27 17:25:15 +0000847 // Otherwise this is R +/- [possibly shifted] R.
Chris Lattner46c01a32011-02-13 22:25:43 +0000848 ARM_AM::AddrOpc AddSub = N.getOpcode() != ISD::SUB ? ARM_AM::add:ARM_AM::sub;
Evan Chenga20cde32011-07-20 23:34:39 +0000849 ARM_AM::ShiftOpc ShOpcVal =
850 ARM_AM::getShiftOpcForNode(N.getOperand(1).getOpcode());
Evan Cheng10043e22007-01-19 07:51:42 +0000851 unsigned ShAmt = 0;
Jim Grosbachf24f9d92009-08-11 15:33:49 +0000852
Evan Cheng10043e22007-01-19 07:51:42 +0000853 Base = N.getOperand(0);
854 Offset = N.getOperand(1);
Jim Grosbachf24f9d92009-08-11 15:33:49 +0000855
Evan Cheng10043e22007-01-19 07:51:42 +0000856 if (ShOpcVal != ARM_AM::no_shift) {
857 // Check to see if the RHS of the shift is a constant, if not, we can't fold
858 // it.
859 if (ConstantSDNode *Sh =
860 dyn_cast<ConstantSDNode>(N.getOperand(1).getOperand(1))) {
Dan Gohmaneffb8942008-09-12 16:56:44 +0000861 ShAmt = Sh->getZExtValue();
Evan Cheng59bbc542010-10-27 23:41:30 +0000862 if (isShifterOpProfitable(Offset, ShOpcVal, ShAmt))
863 Offset = N.getOperand(1).getOperand(0);
864 else {
865 ShAmt = 0;
866 ShOpcVal = ARM_AM::no_shift;
867 }
Evan Cheng10043e22007-01-19 07:51:42 +0000868 } else {
869 ShOpcVal = ARM_AM::no_shift;
Rafael Espindola708cb602006-11-08 17:07:32 +0000870 }
871 }
Jim Grosbachf24f9d92009-08-11 15:33:49 +0000872
Evan Cheng10043e22007-01-19 07:51:42 +0000873 // Try matching (R shl C) + (R).
Chris Lattner46c01a32011-02-13 22:25:43 +0000874 if (N.getOpcode() != ISD::SUB && ShOpcVal == ARM_AM::no_shift &&
Bob Wilsone8a549c2012-09-29 21:43:49 +0000875 !(Subtarget->isLikeA9() || Subtarget->isSwift() ||
876 N.getOperand(0).hasOneUse())) {
Evan Chenga20cde32011-07-20 23:34:39 +0000877 ShOpcVal = ARM_AM::getShiftOpcForNode(N.getOperand(0).getOpcode());
Evan Cheng10043e22007-01-19 07:51:42 +0000878 if (ShOpcVal != ARM_AM::no_shift) {
879 // Check to see if the RHS of the shift is a constant, if not, we can't
880 // fold it.
881 if (ConstantSDNode *Sh =
882 dyn_cast<ConstantSDNode>(N.getOperand(0).getOperand(1))) {
Dan Gohmaneffb8942008-09-12 16:56:44 +0000883 ShAmt = Sh->getZExtValue();
Cameron Zwarich842f99a2011-10-05 23:39:02 +0000884 if (isShifterOpProfitable(N.getOperand(0), ShOpcVal, ShAmt)) {
Evan Cheng59bbc542010-10-27 23:41:30 +0000885 Offset = N.getOperand(0).getOperand(0);
886 Base = N.getOperand(1);
887 } else {
888 ShAmt = 0;
889 ShOpcVal = ARM_AM::no_shift;
890 }
Evan Cheng10043e22007-01-19 07:51:42 +0000891 } else {
892 ShOpcVal = ARM_AM::no_shift;
893 }
894 }
895 }
Jim Grosbachf24f9d92009-08-11 15:33:49 +0000896
Evan Cheng10043e22007-01-19 07:51:42 +0000897 Opc = CurDAG->getTargetConstant(ARM_AM::getAM2Opc(AddSub, ShAmt, ShOpcVal),
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +0000898 SDLoc(N), MVT::i32);
Jim Grosbach08605202010-09-29 19:03:54 +0000899 return AM2_SHOP;
Rafael Espindola708cb602006-11-08 17:07:32 +0000900}
901
Owen Anderson2aedba62011-07-26 20:54:26 +0000902bool ARMDAGToDAGISel::SelectAddrMode2OffsetReg(SDNode *Op, SDValue N,
Dan Gohman2ce6f2a2008-07-27 21:46:04 +0000903 SDValue &Offset, SDValue &Opc) {
Dan Gohmanea6f91f2010-01-05 01:24:18 +0000904 unsigned Opcode = Op->getOpcode();
Evan Cheng10043e22007-01-19 07:51:42 +0000905 ISD::MemIndexedMode AM = (Opcode == ISD::LOAD)
906 ? cast<LoadSDNode>(Op)->getAddressingMode()
907 : cast<StoreSDNode>(Op)->getAddressingMode();
908 ARM_AM::AddrOpc AddSub = (AM == ISD::PRE_INC || AM == ISD::POST_INC)
909 ? ARM_AM::add : ARM_AM::sub;
Daniel Dunbare0cd9ac2011-01-19 15:12:16 +0000910 int Val;
Owen Anderson2aedba62011-07-26 20:54:26 +0000911 if (isScaledConstantInRange(N, /*Scale=*/1, 0, 0x1000, Val))
912 return false;
Evan Cheng10043e22007-01-19 07:51:42 +0000913
914 Offset = N;
Evan Chenga20cde32011-07-20 23:34:39 +0000915 ARM_AM::ShiftOpc ShOpcVal = ARM_AM::getShiftOpcForNode(N.getOpcode());
Evan Cheng10043e22007-01-19 07:51:42 +0000916 unsigned ShAmt = 0;
917 if (ShOpcVal != ARM_AM::no_shift) {
918 // Check to see if the RHS of the shift is a constant, if not, we can't fold
919 // it.
920 if (ConstantSDNode *Sh = dyn_cast<ConstantSDNode>(N.getOperand(1))) {
Dan Gohmaneffb8942008-09-12 16:56:44 +0000921 ShAmt = Sh->getZExtValue();
Evan Cheng59bbc542010-10-27 23:41:30 +0000922 if (isShifterOpProfitable(N, ShOpcVal, ShAmt))
923 Offset = N.getOperand(0);
924 else {
925 ShAmt = 0;
926 ShOpcVal = ARM_AM::no_shift;
927 }
Evan Cheng10043e22007-01-19 07:51:42 +0000928 } else {
929 ShOpcVal = ARM_AM::no_shift;
930 }
931 }
932
933 Opc = CurDAG->getTargetConstant(ARM_AM::getAM2Opc(AddSub, ShAmt, ShOpcVal),
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +0000934 SDLoc(N), MVT::i32);
Rafael Espindola19398ec2006-10-17 18:04:53 +0000935 return true;
936}
937
Owen Anderson4d5c8f82011-08-29 20:16:50 +0000938bool ARMDAGToDAGISel::SelectAddrMode2OffsetImmPre(SDNode *Op, SDValue N,
939 SDValue &Offset, SDValue &Opc) {
Owen Anderson939cd212011-08-31 20:00:11 +0000940 unsigned Opcode = Op->getOpcode();
941 ISD::MemIndexedMode AM = (Opcode == ISD::LOAD)
942 ? cast<LoadSDNode>(Op)->getAddressingMode()
943 : cast<StoreSDNode>(Op)->getAddressingMode();
944 ARM_AM::AddrOpc AddSub = (AM == ISD::PRE_INC || AM == ISD::POST_INC)
945 ? ARM_AM::add : ARM_AM::sub;
Owen Anderson4d5c8f82011-08-29 20:16:50 +0000946 int Val;
947 if (isScaledConstantInRange(N, /*Scale=*/1, 0, 0x1000, Val)) { // 12 bits.
Owen Anderson939cd212011-08-31 20:00:11 +0000948 if (AddSub == ARM_AM::sub) Val *= -1;
Owen Anderson4d5c8f82011-08-29 20:16:50 +0000949 Offset = CurDAG->getRegister(0, MVT::i32);
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +0000950 Opc = CurDAG->getTargetConstant(Val, SDLoc(Op), MVT::i32);
Owen Anderson4d5c8f82011-08-29 20:16:50 +0000951 return true;
952 }
953
954 return false;
955}
956
957
Owen Anderson2aedba62011-07-26 20:54:26 +0000958bool ARMDAGToDAGISel::SelectAddrMode2OffsetImm(SDNode *Op, SDValue N,
959 SDValue &Offset, SDValue &Opc) {
960 unsigned Opcode = Op->getOpcode();
961 ISD::MemIndexedMode AM = (Opcode == ISD::LOAD)
962 ? cast<LoadSDNode>(Op)->getAddressingMode()
963 : cast<StoreSDNode>(Op)->getAddressingMode();
964 ARM_AM::AddrOpc AddSub = (AM == ISD::PRE_INC || AM == ISD::POST_INC)
965 ? ARM_AM::add : ARM_AM::sub;
966 int Val;
967 if (isScaledConstantInRange(N, /*Scale=*/1, 0, 0x1000, Val)) { // 12 bits.
968 Offset = CurDAG->getRegister(0, MVT::i32);
969 Opc = CurDAG->getTargetConstant(ARM_AM::getAM2Opc(AddSub, Val,
970 ARM_AM::no_shift),
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +0000971 SDLoc(Op), MVT::i32);
Owen Anderson2aedba62011-07-26 20:54:26 +0000972 return true;
973 }
974
975 return false;
976}
977
Jim Grosbachf0c95ca2011-08-05 20:35:44 +0000978bool ARMDAGToDAGISel::SelectAddrOffsetNone(SDValue N, SDValue &Base) {
979 Base = N;
980 return true;
981}
Evan Cheng10043e22007-01-19 07:51:42 +0000982
Chris Lattner0e023ea2010-09-21 20:31:19 +0000983bool ARMDAGToDAGISel::SelectAddrMode3(SDValue N,
Dan Gohman2ce6f2a2008-07-27 21:46:04 +0000984 SDValue &Base, SDValue &Offset,
985 SDValue &Opc) {
Evan Cheng10043e22007-01-19 07:51:42 +0000986 if (N.getOpcode() == ISD::SUB) {
987 // X - C is canonicalize to X + -C, no need to handle it here.
988 Base = N.getOperand(0);
989 Offset = N.getOperand(1);
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +0000990 Opc = CurDAG->getTargetConstant(ARM_AM::getAM3Opc(ARM_AM::sub, 0), SDLoc(N),
991 MVT::i32);
Evan Cheng10043e22007-01-19 07:51:42 +0000992 return true;
993 }
Jim Grosbachf24f9d92009-08-11 15:33:49 +0000994
Chris Lattner46c01a32011-02-13 22:25:43 +0000995 if (!CurDAG->isBaseWithConstantOffset(N)) {
Evan Cheng10043e22007-01-19 07:51:42 +0000996 Base = N;
997 if (N.getOpcode() == ISD::FrameIndex) {
998 int FI = cast<FrameIndexSDNode>(N)->getIndex();
Mehdi Amini44ede332015-07-09 02:09:04 +0000999 Base = CurDAG->getTargetFrameIndex(
1000 FI, TLI->getPointerTy(CurDAG->getDataLayout()));
Evan Cheng10043e22007-01-19 07:51:42 +00001001 }
Owen Anderson9f944592009-08-11 20:47:22 +00001002 Offset = CurDAG->getRegister(0, MVT::i32);
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00001003 Opc = CurDAG->getTargetConstant(ARM_AM::getAM3Opc(ARM_AM::add, 0), SDLoc(N),
1004 MVT::i32);
Evan Cheng10043e22007-01-19 07:51:42 +00001005 return true;
1006 }
Jim Grosbachf24f9d92009-08-11 15:33:49 +00001007
Evan Cheng10043e22007-01-19 07:51:42 +00001008 // If the RHS is +/- imm8, fold into addr mode.
Daniel Dunbare0cd9ac2011-01-19 15:12:16 +00001009 int RHSC;
1010 if (isScaledConstantInRange(N.getOperand(1), /*Scale=*/1,
1011 -256 + 1, 256, RHSC)) { // 8 bits.
1012 Base = N.getOperand(0);
1013 if (Base.getOpcode() == ISD::FrameIndex) {
1014 int FI = cast<FrameIndexSDNode>(Base)->getIndex();
Mehdi Amini44ede332015-07-09 02:09:04 +00001015 Base = CurDAG->getTargetFrameIndex(
1016 FI, TLI->getPointerTy(CurDAG->getDataLayout()));
Evan Cheng10043e22007-01-19 07:51:42 +00001017 }
Daniel Dunbare0cd9ac2011-01-19 15:12:16 +00001018 Offset = CurDAG->getRegister(0, MVT::i32);
1019
1020 ARM_AM::AddrOpc AddSub = ARM_AM::add;
1021 if (RHSC < 0) {
1022 AddSub = ARM_AM::sub;
Chris Lattner46c01a32011-02-13 22:25:43 +00001023 RHSC = -RHSC;
Daniel Dunbare0cd9ac2011-01-19 15:12:16 +00001024 }
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00001025 Opc = CurDAG->getTargetConstant(ARM_AM::getAM3Opc(AddSub, RHSC), SDLoc(N),
1026 MVT::i32);
Daniel Dunbare0cd9ac2011-01-19 15:12:16 +00001027 return true;
Evan Cheng10043e22007-01-19 07:51:42 +00001028 }
Jim Grosbachf24f9d92009-08-11 15:33:49 +00001029
Evan Cheng10043e22007-01-19 07:51:42 +00001030 Base = N.getOperand(0);
1031 Offset = N.getOperand(1);
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00001032 Opc = CurDAG->getTargetConstant(ARM_AM::getAM3Opc(ARM_AM::add, 0), SDLoc(N),
1033 MVT::i32);
Evan Cheng10043e22007-01-19 07:51:42 +00001034 return true;
1035}
1036
Dan Gohmanea6f91f2010-01-05 01:24:18 +00001037bool ARMDAGToDAGISel::SelectAddrMode3Offset(SDNode *Op, SDValue N,
Dan Gohman2ce6f2a2008-07-27 21:46:04 +00001038 SDValue &Offset, SDValue &Opc) {
Dan Gohmanea6f91f2010-01-05 01:24:18 +00001039 unsigned Opcode = Op->getOpcode();
Evan Cheng10043e22007-01-19 07:51:42 +00001040 ISD::MemIndexedMode AM = (Opcode == ISD::LOAD)
1041 ? cast<LoadSDNode>(Op)->getAddressingMode()
1042 : cast<StoreSDNode>(Op)->getAddressingMode();
1043 ARM_AM::AddrOpc AddSub = (AM == ISD::PRE_INC || AM == ISD::POST_INC)
1044 ? ARM_AM::add : ARM_AM::sub;
Daniel Dunbare0cd9ac2011-01-19 15:12:16 +00001045 int Val;
1046 if (isScaledConstantInRange(N, /*Scale=*/1, 0, 256, Val)) { // 12 bits.
1047 Offset = CurDAG->getRegister(0, MVT::i32);
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00001048 Opc = CurDAG->getTargetConstant(ARM_AM::getAM3Opc(AddSub, Val), SDLoc(Op),
1049 MVT::i32);
Daniel Dunbare0cd9ac2011-01-19 15:12:16 +00001050 return true;
Evan Cheng10043e22007-01-19 07:51:42 +00001051 }
1052
1053 Offset = N;
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00001054 Opc = CurDAG->getTargetConstant(ARM_AM::getAM3Opc(AddSub, 0), SDLoc(Op),
1055 MVT::i32);
Evan Cheng10043e22007-01-19 07:51:42 +00001056 return true;
1057}
1058
Jim Grosbachd37f0712010-10-21 19:38:40 +00001059bool ARMDAGToDAGISel::SelectAddrMode5(SDValue N,
Dan Gohman2ce6f2a2008-07-27 21:46:04 +00001060 SDValue &Base, SDValue &Offset) {
Chris Lattner46c01a32011-02-13 22:25:43 +00001061 if (!CurDAG->isBaseWithConstantOffset(N)) {
Evan Cheng10043e22007-01-19 07:51:42 +00001062 Base = N;
1063 if (N.getOpcode() == ISD::FrameIndex) {
1064 int FI = cast<FrameIndexSDNode>(N)->getIndex();
Mehdi Amini44ede332015-07-09 02:09:04 +00001065 Base = CurDAG->getTargetFrameIndex(
1066 FI, TLI->getPointerTy(CurDAG->getDataLayout()));
Anton Korobeynikov25229082009-11-24 00:44:37 +00001067 } else if (N.getOpcode() == ARMISD::Wrapper &&
Tim Northoverbd41cf82016-01-07 09:03:03 +00001068 N.getOperand(0).getOpcode() != ISD::TargetGlobalAddress &&
Saleem Abdulrasoolf36005a2016-02-03 18:21:59 +00001069 N.getOperand(0).getOpcode() != ISD::TargetExternalSymbol &&
Tim Northoverbd41cf82016-01-07 09:03:03 +00001070 N.getOperand(0).getOpcode() != ISD::TargetGlobalTLSAddress) {
Evan Cheng10043e22007-01-19 07:51:42 +00001071 Base = N.getOperand(0);
1072 }
1073 Offset = CurDAG->getTargetConstant(ARM_AM::getAM5Opc(ARM_AM::add, 0),
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00001074 SDLoc(N), MVT::i32);
Evan Cheng10043e22007-01-19 07:51:42 +00001075 return true;
1076 }
Jim Grosbachf24f9d92009-08-11 15:33:49 +00001077
Evan Cheng10043e22007-01-19 07:51:42 +00001078 // If the RHS is +/- imm8, fold into addr mode.
Daniel Dunbare0cd9ac2011-01-19 15:12:16 +00001079 int RHSC;
1080 if (isScaledConstantInRange(N.getOperand(1), /*Scale=*/4,
1081 -256 + 1, 256, RHSC)) {
1082 Base = N.getOperand(0);
1083 if (Base.getOpcode() == ISD::FrameIndex) {
1084 int FI = cast<FrameIndexSDNode>(Base)->getIndex();
Mehdi Amini44ede332015-07-09 02:09:04 +00001085 Base = CurDAG->getTargetFrameIndex(
1086 FI, TLI->getPointerTy(CurDAG->getDataLayout()));
Evan Cheng10043e22007-01-19 07:51:42 +00001087 }
Daniel Dunbare0cd9ac2011-01-19 15:12:16 +00001088
1089 ARM_AM::AddrOpc AddSub = ARM_AM::add;
1090 if (RHSC < 0) {
1091 AddSub = ARM_AM::sub;
Chris Lattner46c01a32011-02-13 22:25:43 +00001092 RHSC = -RHSC;
Daniel Dunbare0cd9ac2011-01-19 15:12:16 +00001093 }
1094 Offset = CurDAG->getTargetConstant(ARM_AM::getAM5Opc(AddSub, RHSC),
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00001095 SDLoc(N), MVT::i32);
Daniel Dunbare0cd9ac2011-01-19 15:12:16 +00001096 return true;
Evan Cheng10043e22007-01-19 07:51:42 +00001097 }
Jim Grosbachf24f9d92009-08-11 15:33:49 +00001098
Evan Cheng10043e22007-01-19 07:51:42 +00001099 Base = N;
1100 Offset = CurDAG->getTargetConstant(ARM_AM::getAM5Opc(ARM_AM::add, 0),
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00001101 SDLoc(N), MVT::i32);
Evan Cheng10043e22007-01-19 07:51:42 +00001102 return true;
1103}
1104
Bob Wilsondd9fbaa2010-11-01 23:40:51 +00001105bool ARMDAGToDAGISel::SelectAddrMode6(SDNode *Parent, SDValue N, SDValue &Addr,
1106 SDValue &Align) {
Bob Wilsondeb35af2009-07-01 23:16:05 +00001107 Addr = N;
Bob Wilsondd9fbaa2010-11-01 23:40:51 +00001108
1109 unsigned Alignment = 0;
Ahmed Bougachadb141ac2015-02-19 23:52:41 +00001110
1111 MemSDNode *MemN = cast<MemSDNode>(Parent);
1112
1113 if (isa<LSBaseSDNode>(MemN) ||
1114 ((MemN->getOpcode() == ARMISD::VST1_UPD ||
1115 MemN->getOpcode() == ARMISD::VLD1_UPD) &&
1116 MemN->getConstantOperandVal(MemN->getNumOperands() - 1) == 1)) {
Bob Wilsondd9fbaa2010-11-01 23:40:51 +00001117 // This case occurs only for VLD1-lane/dup and VST1-lane instructions.
1118 // The maximum alignment is equal to the memory size being referenced.
Ahmed Bougachadb141ac2015-02-19 23:52:41 +00001119 unsigned MMOAlign = MemN->getAlignment();
1120 unsigned MemSize = MemN->getMemoryVT().getSizeInBits() / 8;
1121 if (MMOAlign >= MemSize && MemSize > 1)
Bob Wilsondd9fbaa2010-11-01 23:40:51 +00001122 Alignment = MemSize;
1123 } else {
1124 // All other uses of addrmode6 are for intrinsics. For now just record
1125 // the raw alignment value; it will be refined later based on the legal
1126 // alignment operands for the intrinsic.
Ahmed Bougachadb141ac2015-02-19 23:52:41 +00001127 Alignment = MemN->getAlignment();
Bob Wilsondd9fbaa2010-11-01 23:40:51 +00001128 }
1129
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00001130 Align = CurDAG->getTargetConstant(Alignment, SDLoc(N), MVT::i32);
Bob Wilsondeb35af2009-07-01 23:16:05 +00001131 return true;
1132}
1133
Bob Wilsone3ecd5f2011-02-25 06:42:42 +00001134bool ARMDAGToDAGISel::SelectAddrMode6Offset(SDNode *Op, SDValue N,
1135 SDValue &Offset) {
1136 LSBaseSDNode *LdSt = cast<LSBaseSDNode>(Op);
1137 ISD::MemIndexedMode AM = LdSt->getAddressingMode();
1138 if (AM != ISD::POST_INC)
1139 return false;
1140 Offset = N;
1141 if (ConstantSDNode *NC = dyn_cast<ConstantSDNode>(N)) {
1142 if (NC->getZExtValue() * 8 == LdSt->getMemoryVT().getSizeInBits())
1143 Offset = CurDAG->getRegister(0, MVT::i32);
1144 }
1145 return true;
1146}
1147
Chris Lattner0e023ea2010-09-21 20:31:19 +00001148bool ARMDAGToDAGISel::SelectAddrModePC(SDValue N,
Evan Cheng9a58aff2009-08-14 19:01:37 +00001149 SDValue &Offset, SDValue &Label) {
Evan Cheng10043e22007-01-19 07:51:42 +00001150 if (N.getOpcode() == ARMISD::PIC_ADD && N.hasOneUse()) {
1151 Offset = N.getOperand(0);
Dan Gohman2ce6f2a2008-07-27 21:46:04 +00001152 SDValue N1 = N.getOperand(1);
Evan Chengb8b0ad82011-01-20 08:34:58 +00001153 Label = CurDAG->getTargetConstant(cast<ConstantSDNode>(N1)->getZExtValue(),
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00001154 SDLoc(N), MVT::i32);
Evan Cheng10043e22007-01-19 07:51:42 +00001155 return true;
1156 }
Bill Wendling092a7bd2010-12-14 03:36:38 +00001157
Evan Cheng10043e22007-01-19 07:51:42 +00001158 return false;
1159}
1160
Bill Wendling092a7bd2010-12-14 03:36:38 +00001161
1162//===----------------------------------------------------------------------===//
1163// Thumb Addressing Modes
1164//===----------------------------------------------------------------------===//
1165
Chris Lattner0e023ea2010-09-21 20:31:19 +00001166bool ARMDAGToDAGISel::SelectThumbAddrModeRR(SDValue N,
Dan Gohman2ce6f2a2008-07-27 21:46:04 +00001167 SDValue &Base, SDValue &Offset){
Chris Lattner46c01a32011-02-13 22:25:43 +00001168 if (N.getOpcode() != ISD::ADD && !CurDAG->isBaseWithConstantOffset(N)) {
Evan Cheng0794c6a2009-07-11 07:08:13 +00001169 ConstantSDNode *NC = dyn_cast<ConstantSDNode>(N);
Dan Gohmanf1d83042010-06-18 14:22:04 +00001170 if (!NC || !NC->isNullValue())
Evan Cheng0794c6a2009-07-11 07:08:13 +00001171 return false;
1172
1173 Base = Offset = N;
Evan Chengc0b73662007-01-23 22:59:13 +00001174 return true;
1175 }
1176
Evan Cheng10043e22007-01-19 07:51:42 +00001177 Base = N.getOperand(0);
1178 Offset = N.getOperand(1);
1179 return true;
1180}
1181
Evan Cheng139edae2007-01-24 02:21:22 +00001182bool
Bill Wendling092a7bd2010-12-14 03:36:38 +00001183ARMDAGToDAGISel::SelectThumbAddrModeImm5S(SDValue N, unsigned Scale,
1184 SDValue &Base, SDValue &OffImm) {
Chris Lattner46c01a32011-02-13 22:25:43 +00001185 if (!CurDAG->isBaseWithConstantOffset(N)) {
John Brawn68acdcb2015-08-13 10:48:22 +00001186 if (N.getOpcode() == ISD::ADD) {
1187 return false; // We want to select register offset instead
1188 } else if (N.getOpcode() == ARMISD::Wrapper &&
Tim Northoverbd41cf82016-01-07 09:03:03 +00001189 N.getOperand(0).getOpcode() != ISD::TargetGlobalAddress &&
Saleem Abdulrasoolf36005a2016-02-03 18:21:59 +00001190 N.getOperand(0).getOpcode() != ISD::TargetExternalSymbol &&
James Molloyb7de4972016-10-05 14:52:13 +00001191 N.getOperand(0).getOpcode() != ISD::TargetConstantPool &&
Tim Northoverbd41cf82016-01-07 09:03:03 +00001192 N.getOperand(0).getOpcode() != ISD::TargetGlobalTLSAddress) {
Bill Wendling092a7bd2010-12-14 03:36:38 +00001193 Base = N.getOperand(0);
1194 } else {
1195 Base = N;
1196 }
1197
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00001198 OffImm = CurDAG->getTargetConstant(0, SDLoc(N), MVT::i32);
Evan Cheng650d0672007-02-06 00:22:06 +00001199 return true;
1200 }
1201
Evan Cheng10043e22007-01-19 07:51:42 +00001202 // If the RHS is + imm5 * scale, fold into addr mode.
Daniel Dunbare0cd9ac2011-01-19 15:12:16 +00001203 int RHSC;
1204 if (isScaledConstantInRange(N.getOperand(1), Scale, 0, 32, RHSC)) {
1205 Base = N.getOperand(0);
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00001206 OffImm = CurDAG->getTargetConstant(RHSC, SDLoc(N), MVT::i32);
Daniel Dunbare0cd9ac2011-01-19 15:12:16 +00001207 return true;
Evan Cheng10043e22007-01-19 07:51:42 +00001208 }
1209
John Brawn68acdcb2015-08-13 10:48:22 +00001210 // Offset is too large, so use register offset instead.
1211 return false;
Evan Cheng10043e22007-01-19 07:51:42 +00001212}
1213
Bill Wendling092a7bd2010-12-14 03:36:38 +00001214bool
1215ARMDAGToDAGISel::SelectThumbAddrModeImm5S4(SDValue N, SDValue &Base,
1216 SDValue &OffImm) {
1217 return SelectThumbAddrModeImm5S(N, 4, Base, OffImm);
Evan Cheng10043e22007-01-19 07:51:42 +00001218}
1219
Bill Wendling092a7bd2010-12-14 03:36:38 +00001220bool
1221ARMDAGToDAGISel::SelectThumbAddrModeImm5S2(SDValue N, SDValue &Base,
1222 SDValue &OffImm) {
1223 return SelectThumbAddrModeImm5S(N, 2, Base, OffImm);
Evan Cheng10043e22007-01-19 07:51:42 +00001224}
1225
Bill Wendling092a7bd2010-12-14 03:36:38 +00001226bool
1227ARMDAGToDAGISel::SelectThumbAddrModeImm5S1(SDValue N, SDValue &Base,
1228 SDValue &OffImm) {
1229 return SelectThumbAddrModeImm5S(N, 1, Base, OffImm);
Evan Cheng10043e22007-01-19 07:51:42 +00001230}
1231
Chris Lattner0e023ea2010-09-21 20:31:19 +00001232bool ARMDAGToDAGISel::SelectThumbAddrModeSP(SDValue N,
1233 SDValue &Base, SDValue &OffImm) {
Evan Cheng10043e22007-01-19 07:51:42 +00001234 if (N.getOpcode() == ISD::FrameIndex) {
1235 int FI = cast<FrameIndexSDNode>(N)->getIndex();
Renato Golinb9887ef2015-02-25 14:41:06 +00001236 // Only multiples of 4 are allowed for the offset, so the frame object
1237 // alignment must be at least 4.
Matthias Braun941a7052016-07-28 18:40:00 +00001238 MachineFrameInfo &MFI = MF->getFrameInfo();
1239 if (MFI.getObjectAlignment(FI) < 4)
1240 MFI.setObjectAlignment(FI, 4);
Mehdi Amini44ede332015-07-09 02:09:04 +00001241 Base = CurDAG->getTargetFrameIndex(
1242 FI, TLI->getPointerTy(CurDAG->getDataLayout()));
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00001243 OffImm = CurDAG->getTargetConstant(0, SDLoc(N), MVT::i32);
Evan Cheng10043e22007-01-19 07:51:42 +00001244 return true;
1245 }
Evan Cheng139edae2007-01-24 02:21:22 +00001246
Chris Lattner46c01a32011-02-13 22:25:43 +00001247 if (!CurDAG->isBaseWithConstantOffset(N))
Evan Cheng650d0672007-02-06 00:22:06 +00001248 return false;
1249
1250 RegisterSDNode *LHSR = dyn_cast<RegisterSDNode>(N.getOperand(0));
Evan Chenga9740312007-02-06 09:11:20 +00001251 if (N.getOperand(0).getOpcode() == ISD::FrameIndex ||
1252 (LHSR && LHSR->getReg() == ARM::SP)) {
Evan Cheng139edae2007-01-24 02:21:22 +00001253 // If the RHS is + imm8 * scale, fold into addr mode.
Daniel Dunbare0cd9ac2011-01-19 15:12:16 +00001254 int RHSC;
1255 if (isScaledConstantInRange(N.getOperand(1), /*Scale=*/4, 0, 256, RHSC)) {
1256 Base = N.getOperand(0);
1257 if (Base.getOpcode() == ISD::FrameIndex) {
1258 int FI = cast<FrameIndexSDNode>(Base)->getIndex();
Renato Golinb9887ef2015-02-25 14:41:06 +00001259 // For LHS+RHS to result in an offset that's a multiple of 4 the object
1260 // indexed by the LHS must be 4-byte aligned.
Matthias Braun941a7052016-07-28 18:40:00 +00001261 MachineFrameInfo &MFI = MF->getFrameInfo();
1262 if (MFI.getObjectAlignment(FI) < 4)
1263 MFI.setObjectAlignment(FI, 4);
Mehdi Amini44ede332015-07-09 02:09:04 +00001264 Base = CurDAG->getTargetFrameIndex(
1265 FI, TLI->getPointerTy(CurDAG->getDataLayout()));
Evan Cheng139edae2007-01-24 02:21:22 +00001266 }
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00001267 OffImm = CurDAG->getTargetConstant(RHSC, SDLoc(N), MVT::i32);
Daniel Dunbare0cd9ac2011-01-19 15:12:16 +00001268 return true;
Evan Cheng139edae2007-01-24 02:21:22 +00001269 }
1270 }
Jim Grosbachf24f9d92009-08-11 15:33:49 +00001271
Evan Cheng10043e22007-01-19 07:51:42 +00001272 return false;
1273}
1274
Bill Wendling092a7bd2010-12-14 03:36:38 +00001275
1276//===----------------------------------------------------------------------===//
1277// Thumb 2 Addressing Modes
1278//===----------------------------------------------------------------------===//
1279
1280
Chris Lattner0e023ea2010-09-21 20:31:19 +00001281bool ARMDAGToDAGISel::SelectT2AddrModeImm12(SDValue N,
Evan Chengb23b50d2009-06-29 07:51:04 +00001282 SDValue &Base, SDValue &OffImm) {
1283 // Match simple R + imm12 operands.
David Goodwin802a0b52009-07-20 15:55:39 +00001284
Evan Cheng36064672009-08-11 08:52:18 +00001285 // Base only.
Chris Lattner46c01a32011-02-13 22:25:43 +00001286 if (N.getOpcode() != ISD::ADD && N.getOpcode() != ISD::SUB &&
1287 !CurDAG->isBaseWithConstantOffset(N)) {
David Goodwin802a0b52009-07-20 15:55:39 +00001288 if (N.getOpcode() == ISD::FrameIndex) {
Chris Lattner46c01a32011-02-13 22:25:43 +00001289 // Match frame index.
David Goodwin802a0b52009-07-20 15:55:39 +00001290 int FI = cast<FrameIndexSDNode>(N)->getIndex();
Mehdi Amini44ede332015-07-09 02:09:04 +00001291 Base = CurDAG->getTargetFrameIndex(
1292 FI, TLI->getPointerTy(CurDAG->getDataLayout()));
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00001293 OffImm = CurDAG->getTargetConstant(0, SDLoc(N), MVT::i32);
David Goodwin802a0b52009-07-20 15:55:39 +00001294 return true;
Chris Lattner46c01a32011-02-13 22:25:43 +00001295 }
Owen Anderson6d557452011-03-18 19:46:58 +00001296
Chris Lattner46c01a32011-02-13 22:25:43 +00001297 if (N.getOpcode() == ARMISD::Wrapper &&
Tim Northoverbd41cf82016-01-07 09:03:03 +00001298 N.getOperand(0).getOpcode() != ISD::TargetGlobalAddress &&
Saleem Abdulrasoolf36005a2016-02-03 18:21:59 +00001299 N.getOperand(0).getOpcode() != ISD::TargetExternalSymbol &&
Tim Northoverbd41cf82016-01-07 09:03:03 +00001300 N.getOperand(0).getOpcode() != ISD::TargetGlobalTLSAddress) {
Evan Cheng36064672009-08-11 08:52:18 +00001301 Base = N.getOperand(0);
1302 if (Base.getOpcode() == ISD::TargetConstantPool)
1303 return false; // We want to select t2LDRpci instead.
1304 } else
1305 Base = N;
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00001306 OffImm = CurDAG->getTargetConstant(0, SDLoc(N), MVT::i32);
Evan Cheng36064672009-08-11 08:52:18 +00001307 return true;
David Goodwin802a0b52009-07-20 15:55:39 +00001308 }
Evan Chengb23b50d2009-06-29 07:51:04 +00001309
1310 if (ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(N.getOperand(1))) {
Chris Lattner0e023ea2010-09-21 20:31:19 +00001311 if (SelectT2AddrModeImm8(N, Base, OffImm))
Evan Cheng36064672009-08-11 08:52:18 +00001312 // Let t2LDRi8 handle (R - imm8).
1313 return false;
1314
Evan Chengb23b50d2009-06-29 07:51:04 +00001315 int RHSC = (int)RHS->getZExtValue();
David Goodwin79c079b2009-07-30 18:56:48 +00001316 if (N.getOpcode() == ISD::SUB)
1317 RHSC = -RHSC;
1318
1319 if (RHSC >= 0 && RHSC < 0x1000) { // 12 bits (unsigned)
Evan Chengb23b50d2009-06-29 07:51:04 +00001320 Base = N.getOperand(0);
David Goodwin79c079b2009-07-30 18:56:48 +00001321 if (Base.getOpcode() == ISD::FrameIndex) {
1322 int FI = cast<FrameIndexSDNode>(Base)->getIndex();
Mehdi Amini44ede332015-07-09 02:09:04 +00001323 Base = CurDAG->getTargetFrameIndex(
1324 FI, TLI->getPointerTy(CurDAG->getDataLayout()));
David Goodwin79c079b2009-07-30 18:56:48 +00001325 }
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00001326 OffImm = CurDAG->getTargetConstant(RHSC, SDLoc(N), MVT::i32);
Evan Chengb23b50d2009-06-29 07:51:04 +00001327 return true;
1328 }
1329 }
1330
Evan Cheng36064672009-08-11 08:52:18 +00001331 // Base only.
1332 Base = N;
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00001333 OffImm = CurDAG->getTargetConstant(0, SDLoc(N), MVT::i32);
Evan Cheng36064672009-08-11 08:52:18 +00001334 return true;
Evan Chengb23b50d2009-06-29 07:51:04 +00001335}
1336
Chris Lattner0e023ea2010-09-21 20:31:19 +00001337bool ARMDAGToDAGISel::SelectT2AddrModeImm8(SDValue N,
Evan Chengb23b50d2009-06-29 07:51:04 +00001338 SDValue &Base, SDValue &OffImm) {
David Goodwin79c079b2009-07-30 18:56:48 +00001339 // Match simple R - imm8 operands.
Chris Lattner46c01a32011-02-13 22:25:43 +00001340 if (N.getOpcode() != ISD::ADD && N.getOpcode() != ISD::SUB &&
1341 !CurDAG->isBaseWithConstantOffset(N))
1342 return false;
Owen Anderson6d557452011-03-18 19:46:58 +00001343
Chris Lattner46c01a32011-02-13 22:25:43 +00001344 if (ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(N.getOperand(1))) {
1345 int RHSC = (int)RHS->getSExtValue();
1346 if (N.getOpcode() == ISD::SUB)
1347 RHSC = -RHSC;
Jim Grosbachf24f9d92009-08-11 15:33:49 +00001348
Chris Lattner46c01a32011-02-13 22:25:43 +00001349 if ((RHSC >= -255) && (RHSC < 0)) { // 8 bits (always negative)
1350 Base = N.getOperand(0);
1351 if (Base.getOpcode() == ISD::FrameIndex) {
1352 int FI = cast<FrameIndexSDNode>(Base)->getIndex();
Mehdi Amini44ede332015-07-09 02:09:04 +00001353 Base = CurDAG->getTargetFrameIndex(
1354 FI, TLI->getPointerTy(CurDAG->getDataLayout()));
Evan Chengb23b50d2009-06-29 07:51:04 +00001355 }
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00001356 OffImm = CurDAG->getTargetConstant(RHSC, SDLoc(N), MVT::i32);
Chris Lattner46c01a32011-02-13 22:25:43 +00001357 return true;
Evan Chengb23b50d2009-06-29 07:51:04 +00001358 }
1359 }
1360
1361 return false;
1362}
1363
Dan Gohmanea6f91f2010-01-05 01:24:18 +00001364bool ARMDAGToDAGISel::SelectT2AddrModeImm8Offset(SDNode *Op, SDValue N,
Evan Cheng84c6cda2009-07-02 07:28:31 +00001365 SDValue &OffImm){
Dan Gohmanea6f91f2010-01-05 01:24:18 +00001366 unsigned Opcode = Op->getOpcode();
Evan Cheng84c6cda2009-07-02 07:28:31 +00001367 ISD::MemIndexedMode AM = (Opcode == ISD::LOAD)
1368 ? cast<LoadSDNode>(Op)->getAddressingMode()
1369 : cast<StoreSDNode>(Op)->getAddressingMode();
Daniel Dunbare0cd9ac2011-01-19 15:12:16 +00001370 int RHSC;
1371 if (isScaledConstantInRange(N, /*Scale=*/1, 0, 0x100, RHSC)) { // 8 bits.
1372 OffImm = ((AM == ISD::PRE_INC) || (AM == ISD::POST_INC))
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00001373 ? CurDAG->getTargetConstant(RHSC, SDLoc(N), MVT::i32)
1374 : CurDAG->getTargetConstant(-RHSC, SDLoc(N), MVT::i32);
Daniel Dunbare0cd9ac2011-01-19 15:12:16 +00001375 return true;
Evan Cheng84c6cda2009-07-02 07:28:31 +00001376 }
1377
1378 return false;
1379}
1380
Chris Lattner0e023ea2010-09-21 20:31:19 +00001381bool ARMDAGToDAGISel::SelectT2AddrModeSoReg(SDValue N,
Evan Chengb23b50d2009-06-29 07:51:04 +00001382 SDValue &Base,
1383 SDValue &OffReg, SDValue &ShImm) {
Evan Cheng36064672009-08-11 08:52:18 +00001384 // (R - imm8) should be handled by t2LDRi8. The rest are handled by t2LDRi12.
Chris Lattner46c01a32011-02-13 22:25:43 +00001385 if (N.getOpcode() != ISD::ADD && !CurDAG->isBaseWithConstantOffset(N))
Evan Cheng36064672009-08-11 08:52:18 +00001386 return false;
Evan Chengb23b50d2009-06-29 07:51:04 +00001387
Evan Cheng36064672009-08-11 08:52:18 +00001388 // Leave (R + imm12) for t2LDRi12, (R - imm8) for t2LDRi8.
1389 if (ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(N.getOperand(1))) {
1390 int RHSC = (int)RHS->getZExtValue();
1391 if (RHSC >= 0 && RHSC < 0x1000) // 12 bits (unsigned)
1392 return false;
1393 else if (RHSC < 0 && RHSC >= -255) // 8 bits
David Goodwin79c079b2009-07-30 18:56:48 +00001394 return false;
1395 }
1396
Evan Chengb23b50d2009-06-29 07:51:04 +00001397 // Look for (R + R) or (R + (R << [1,2,3])).
1398 unsigned ShAmt = 0;
1399 Base = N.getOperand(0);
1400 OffReg = N.getOperand(1);
1401
1402 // Swap if it is ((R << c) + R).
Evan Chenga20cde32011-07-20 23:34:39 +00001403 ARM_AM::ShiftOpc ShOpcVal = ARM_AM::getShiftOpcForNode(OffReg.getOpcode());
Evan Chengb23b50d2009-06-29 07:51:04 +00001404 if (ShOpcVal != ARM_AM::lsl) {
Evan Chenga20cde32011-07-20 23:34:39 +00001405 ShOpcVal = ARM_AM::getShiftOpcForNode(Base.getOpcode());
Evan Chengb23b50d2009-06-29 07:51:04 +00001406 if (ShOpcVal == ARM_AM::lsl)
1407 std::swap(Base, OffReg);
Jim Grosbachf24f9d92009-08-11 15:33:49 +00001408 }
1409
Evan Chengb23b50d2009-06-29 07:51:04 +00001410 if (ShOpcVal == ARM_AM::lsl) {
1411 // Check to see if the RHS of the shift is a constant, if not, we can't fold
1412 // it.
1413 if (ConstantSDNode *Sh = dyn_cast<ConstantSDNode>(OffReg.getOperand(1))) {
1414 ShAmt = Sh->getZExtValue();
Evan Cheng59bbc542010-10-27 23:41:30 +00001415 if (ShAmt < 4 && isShifterOpProfitable(OffReg, ShOpcVal, ShAmt))
1416 OffReg = OffReg.getOperand(0);
1417 else {
Evan Chengb23b50d2009-06-29 07:51:04 +00001418 ShAmt = 0;
Evan Cheng59bbc542010-10-27 23:41:30 +00001419 }
Evan Chengb23b50d2009-06-29 07:51:04 +00001420 }
David Goodwinf3912052009-07-15 15:50:19 +00001421 }
Jim Grosbachf24f9d92009-08-11 15:33:49 +00001422
John Brawn056e6782015-09-14 15:19:41 +00001423 // If OffReg is a multiply-by-constant and it's profitable to extract a shift
1424 // and use it in a shifted operand do so.
Tim Northoverc4093c32016-01-29 19:18:46 +00001425 if (OffReg.getOpcode() == ISD::MUL && N.hasOneUse()) {
John Brawn056e6782015-09-14 15:19:41 +00001426 unsigned PowerOfTwo = 0;
1427 SDValue NewMulConst;
1428 if (canExtractShiftFromMul(OffReg, 3, PowerOfTwo, NewMulConst)) {
1429 replaceDAGValue(OffReg.getOperand(1), NewMulConst);
1430 ShAmt = PowerOfTwo;
1431 }
1432 }
1433
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00001434 ShImm = CurDAG->getTargetConstant(ShAmt, SDLoc(N), MVT::i32);
Evan Chengb23b50d2009-06-29 07:51:04 +00001435
1436 return true;
1437}
1438
Tim Northovera7ecd242013-07-16 09:46:55 +00001439bool ARMDAGToDAGISel::SelectT2AddrModeExclusive(SDValue N, SDValue &Base,
1440 SDValue &OffImm) {
Alp Tokercb402912014-01-24 17:20:08 +00001441 // This *must* succeed since it's used for the irreplaceable ldrex and strex
Tim Northovera7ecd242013-07-16 09:46:55 +00001442 // instructions.
1443 Base = N;
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00001444 OffImm = CurDAG->getTargetConstant(0, SDLoc(N), MVT::i32);
Tim Northovera7ecd242013-07-16 09:46:55 +00001445
1446 if (N.getOpcode() != ISD::ADD || !CurDAG->isBaseWithConstantOffset(N))
1447 return true;
1448
1449 ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(N.getOperand(1));
1450 if (!RHS)
1451 return true;
1452
1453 uint32_t RHSC = (int)RHS->getZExtValue();
1454 if (RHSC > 1020 || RHSC % 4 != 0)
1455 return true;
1456
1457 Base = N.getOperand(0);
1458 if (Base.getOpcode() == ISD::FrameIndex) {
1459 int FI = cast<FrameIndexSDNode>(Base)->getIndex();
Mehdi Amini44ede332015-07-09 02:09:04 +00001460 Base = CurDAG->getTargetFrameIndex(
1461 FI, TLI->getPointerTy(CurDAG->getDataLayout()));
Tim Northovera7ecd242013-07-16 09:46:55 +00001462 }
1463
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00001464 OffImm = CurDAG->getTargetConstant(RHSC/4, SDLoc(N), MVT::i32);
Tim Northovera7ecd242013-07-16 09:46:55 +00001465 return true;
1466}
1467
Evan Chengb23b50d2009-06-29 07:51:04 +00001468//===--------------------------------------------------------------------===//
1469
Evan Cheng7e90b112007-07-05 07:15:27 +00001470/// getAL - Returns a ARMCC::AL immediate node.
Benjamin Kramerbdc49562016-06-12 15:39:02 +00001471static inline SDValue getAL(SelectionDAG *CurDAG, const SDLoc &dl) {
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00001472 return CurDAG->getTargetConstant((uint64_t)ARMCC::AL, dl, MVT::i32);
Evan Cheng0f7cbe82007-05-15 01:29:07 +00001473}
1474
Tim Northovereaee28b2016-09-19 09:11:09 +00001475void ARMDAGToDAGISel::transferMemOperands(SDNode *N, SDNode *Result) {
1476 MachineSDNode::mmo_iterator MemOp = MF->allocateMemRefsArray(1);
1477 MemOp[0] = cast<MemSDNode>(N)->getMemOperand();
1478 cast<MachineSDNode>(Result)->setMemRefs(MemOp, MemOp + 1);
1479}
1480
Justin Bogner45571362016-05-12 00:31:09 +00001481bool ARMDAGToDAGISel::tryARMIndexedLoad(SDNode *N) {
Dan Gohmanea6f91f2010-01-05 01:24:18 +00001482 LoadSDNode *LD = cast<LoadSDNode>(N);
Evan Chengd9c55362009-07-02 01:23:32 +00001483 ISD::MemIndexedMode AM = LD->getAddressingMode();
1484 if (AM == ISD::UNINDEXED)
Justin Bogner45571362016-05-12 00:31:09 +00001485 return false;
Evan Chengd9c55362009-07-02 01:23:32 +00001486
Owen Anderson53aa7a92009-08-10 22:56:29 +00001487 EVT LoadedVT = LD->getMemoryVT();
Evan Chengd9c55362009-07-02 01:23:32 +00001488 SDValue Offset, AMOpc;
1489 bool isPre = (AM == ISD::PRE_INC) || (AM == ISD::PRE_DEC);
1490 unsigned Opcode = 0;
1491 bool Match = false;
Owen Anderson4d5c8f82011-08-29 20:16:50 +00001492 if (LoadedVT == MVT::i32 && isPre &&
1493 SelectAddrMode2OffsetImmPre(N, LD->getOffset(), Offset, AMOpc)) {
1494 Opcode = ARM::LDR_PRE_IMM;
1495 Match = true;
1496 } else if (LoadedVT == MVT::i32 && !isPre &&
Owen Anderson2aedba62011-07-26 20:54:26 +00001497 SelectAddrMode2OffsetImm(N, LD->getOffset(), Offset, AMOpc)) {
Owen Anderson4d5c8f82011-08-29 20:16:50 +00001498 Opcode = ARM::LDR_POST_IMM;
Evan Chengd9c55362009-07-02 01:23:32 +00001499 Match = true;
Owen Anderson2aedba62011-07-26 20:54:26 +00001500 } else if (LoadedVT == MVT::i32 &&
1501 SelectAddrMode2OffsetReg(N, LD->getOffset(), Offset, AMOpc)) {
Owen Anderson16d33f32011-08-26 20:43:14 +00001502 Opcode = isPre ? ARM::LDR_PRE_REG : ARM::LDR_POST_REG;
Owen Anderson2aedba62011-07-26 20:54:26 +00001503 Match = true;
1504
Owen Anderson9f944592009-08-11 20:47:22 +00001505 } else if (LoadedVT == MVT::i16 &&
Dan Gohmanea6f91f2010-01-05 01:24:18 +00001506 SelectAddrMode3Offset(N, LD->getOffset(), Offset, AMOpc)) {
Evan Chengd9c55362009-07-02 01:23:32 +00001507 Match = true;
1508 Opcode = (LD->getExtensionType() == ISD::SEXTLOAD)
1509 ? (isPre ? ARM::LDRSH_PRE : ARM::LDRSH_POST)
1510 : (isPre ? ARM::LDRH_PRE : ARM::LDRH_POST);
Owen Anderson9f944592009-08-11 20:47:22 +00001511 } else if (LoadedVT == MVT::i8 || LoadedVT == MVT::i1) {
Evan Chengd9c55362009-07-02 01:23:32 +00001512 if (LD->getExtensionType() == ISD::SEXTLOAD) {
Dan Gohmanea6f91f2010-01-05 01:24:18 +00001513 if (SelectAddrMode3Offset(N, LD->getOffset(), Offset, AMOpc)) {
Evan Chengd9c55362009-07-02 01:23:32 +00001514 Match = true;
1515 Opcode = isPre ? ARM::LDRSB_PRE : ARM::LDRSB_POST;
1516 }
1517 } else {
Owen Anderson4d5c8f82011-08-29 20:16:50 +00001518 if (isPre &&
1519 SelectAddrMode2OffsetImmPre(N, LD->getOffset(), Offset, AMOpc)) {
Evan Chengd9c55362009-07-02 01:23:32 +00001520 Match = true;
Owen Anderson4d5c8f82011-08-29 20:16:50 +00001521 Opcode = ARM::LDRB_PRE_IMM;
1522 } else if (!isPre &&
1523 SelectAddrMode2OffsetImm(N, LD->getOffset(), Offset, AMOpc)) {
1524 Match = true;
1525 Opcode = ARM::LDRB_POST_IMM;
Owen Anderson2aedba62011-07-26 20:54:26 +00001526 } else if (SelectAddrMode2OffsetReg(N, LD->getOffset(), Offset, AMOpc)) {
1527 Match = true;
Owen Anderson16d33f32011-08-26 20:43:14 +00001528 Opcode = isPre ? ARM::LDRB_PRE_REG : ARM::LDRB_POST_REG;
Evan Chengd9c55362009-07-02 01:23:32 +00001529 }
1530 }
1531 }
1532
1533 if (Match) {
Owen Andersonfd60f602011-08-26 21:12:37 +00001534 if (Opcode == ARM::LDR_PRE_IMM || Opcode == ARM::LDRB_PRE_IMM) {
1535 SDValue Chain = LD->getChain();
1536 SDValue Base = LD->getBasePtr();
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00001537 SDValue Ops[]= { Base, AMOpc, getAL(CurDAG, SDLoc(N)),
Owen Andersonfd60f602011-08-26 21:12:37 +00001538 CurDAG->getRegister(0, MVT::i32), Chain };
Tim Northovereaee28b2016-09-19 09:11:09 +00001539 SDNode *New = CurDAG->getMachineNode(Opcode, SDLoc(N), MVT::i32, MVT::i32,
1540 MVT::Other, Ops);
1541 transferMemOperands(N, New);
1542 ReplaceNode(N, New);
Justin Bogner45571362016-05-12 00:31:09 +00001543 return true;
Owen Andersonfd60f602011-08-26 21:12:37 +00001544 } else {
1545 SDValue Chain = LD->getChain();
1546 SDValue Base = LD->getBasePtr();
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00001547 SDValue Ops[]= { Base, Offset, AMOpc, getAL(CurDAG, SDLoc(N)),
Owen Andersonfd60f602011-08-26 21:12:37 +00001548 CurDAG->getRegister(0, MVT::i32), Chain };
Tim Northovereaee28b2016-09-19 09:11:09 +00001549 SDNode *New = CurDAG->getMachineNode(Opcode, SDLoc(N), MVT::i32, MVT::i32,
1550 MVT::Other, Ops);
1551 transferMemOperands(N, New);
1552 ReplaceNode(N, New);
Justin Bogner45571362016-05-12 00:31:09 +00001553 return true;
Owen Andersonfd60f602011-08-26 21:12:37 +00001554 }
Evan Chengd9c55362009-07-02 01:23:32 +00001555 }
1556
Justin Bogner45571362016-05-12 00:31:09 +00001557 return false;
Evan Chengd9c55362009-07-02 01:23:32 +00001558}
1559
James Molloyb3326df2016-07-15 08:03:56 +00001560bool ARMDAGToDAGISel::tryT1IndexedLoad(SDNode *N) {
1561 LoadSDNode *LD = cast<LoadSDNode>(N);
1562 EVT LoadedVT = LD->getMemoryVT();
1563 ISD::MemIndexedMode AM = LD->getAddressingMode();
Chandler Carruth5589aa62016-11-03 17:42:02 +00001564 if (AM != ISD::POST_INC || LD->getExtensionType() != ISD::NON_EXTLOAD ||
1565 LoadedVT.getSimpleVT().SimpleTy != MVT::i32)
James Molloyb3326df2016-07-15 08:03:56 +00001566 return false;
1567
1568 auto *COffs = dyn_cast<ConstantSDNode>(LD->getOffset());
1569 if (!COffs || COffs->getZExtValue() != 4)
1570 return false;
1571
1572 // A T1 post-indexed load is just a single register LDM: LDM r0!, {r1}.
1573 // The encoding of LDM is not how the rest of ISel expects a post-inc load to
1574 // look however, so we use a pseudo here and switch it for a tLDMIA_UPD after
1575 // ISel.
1576 SDValue Chain = LD->getChain();
1577 SDValue Base = LD->getBasePtr();
1578 SDValue Ops[]= { Base, getAL(CurDAG, SDLoc(N)),
1579 CurDAG->getRegister(0, MVT::i32), Chain };
Tim Northovereaee28b2016-09-19 09:11:09 +00001580 SDNode *New = CurDAG->getMachineNode(ARM::tLDR_postidx, SDLoc(N), MVT::i32,
1581 MVT::i32, MVT::Other, Ops);
1582 transferMemOperands(N, New);
1583 ReplaceNode(N, New);
James Molloyb3326df2016-07-15 08:03:56 +00001584 return true;
1585}
1586
Justin Bogner45571362016-05-12 00:31:09 +00001587bool ARMDAGToDAGISel::tryT2IndexedLoad(SDNode *N) {
Dan Gohmanea6f91f2010-01-05 01:24:18 +00001588 LoadSDNode *LD = cast<LoadSDNode>(N);
Evan Cheng84c6cda2009-07-02 07:28:31 +00001589 ISD::MemIndexedMode AM = LD->getAddressingMode();
1590 if (AM == ISD::UNINDEXED)
Justin Bogner45571362016-05-12 00:31:09 +00001591 return false;
Evan Cheng84c6cda2009-07-02 07:28:31 +00001592
Owen Anderson53aa7a92009-08-10 22:56:29 +00001593 EVT LoadedVT = LD->getMemoryVT();
Evan Cheng8ecd7eb2009-07-02 23:16:11 +00001594 bool isSExtLd = LD->getExtensionType() == ISD::SEXTLOAD;
Evan Cheng84c6cda2009-07-02 07:28:31 +00001595 SDValue Offset;
1596 bool isPre = (AM == ISD::PRE_INC) || (AM == ISD::PRE_DEC);
1597 unsigned Opcode = 0;
1598 bool Match = false;
Dan Gohmanea6f91f2010-01-05 01:24:18 +00001599 if (SelectT2AddrModeImm8Offset(N, LD->getOffset(), Offset)) {
Owen Anderson9f944592009-08-11 20:47:22 +00001600 switch (LoadedVT.getSimpleVT().SimpleTy) {
1601 case MVT::i32:
Evan Cheng84c6cda2009-07-02 07:28:31 +00001602 Opcode = isPre ? ARM::t2LDR_PRE : ARM::t2LDR_POST;
1603 break;
Owen Anderson9f944592009-08-11 20:47:22 +00001604 case MVT::i16:
Evan Cheng8ecd7eb2009-07-02 23:16:11 +00001605 if (isSExtLd)
1606 Opcode = isPre ? ARM::t2LDRSH_PRE : ARM::t2LDRSH_POST;
1607 else
1608 Opcode = isPre ? ARM::t2LDRH_PRE : ARM::t2LDRH_POST;
Evan Cheng84c6cda2009-07-02 07:28:31 +00001609 break;
Owen Anderson9f944592009-08-11 20:47:22 +00001610 case MVT::i8:
1611 case MVT::i1:
Evan Cheng8ecd7eb2009-07-02 23:16:11 +00001612 if (isSExtLd)
1613 Opcode = isPre ? ARM::t2LDRSB_PRE : ARM::t2LDRSB_POST;
1614 else
1615 Opcode = isPre ? ARM::t2LDRB_PRE : ARM::t2LDRB_POST;
Evan Cheng84c6cda2009-07-02 07:28:31 +00001616 break;
1617 default:
Justin Bogner45571362016-05-12 00:31:09 +00001618 return false;
Evan Cheng84c6cda2009-07-02 07:28:31 +00001619 }
1620 Match = true;
1621 }
1622
1623 if (Match) {
1624 SDValue Chain = LD->getChain();
1625 SDValue Base = LD->getBasePtr();
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00001626 SDValue Ops[]= { Base, Offset, getAL(CurDAG, SDLoc(N)),
Owen Anderson9f944592009-08-11 20:47:22 +00001627 CurDAG->getRegister(0, MVT::i32), Chain };
Tim Northovereaee28b2016-09-19 09:11:09 +00001628 SDNode *New = CurDAG->getMachineNode(Opcode, SDLoc(N), MVT::i32, MVT::i32,
1629 MVT::Other, Ops);
1630 transferMemOperands(N, New);
1631 ReplaceNode(N, New);
Justin Bogner45571362016-05-12 00:31:09 +00001632 return true;
Evan Cheng84c6cda2009-07-02 07:28:31 +00001633 }
1634
Justin Bogner45571362016-05-12 00:31:09 +00001635 return false;
Evan Cheng84c6cda2009-07-02 07:28:31 +00001636}
1637
Weiming Zhao8f56f882012-11-16 21:55:34 +00001638/// \brief Form a GPRPair pseudo register from a pair of GPR regs.
1639SDNode *ARMDAGToDAGISel::createGPRPairNode(EVT VT, SDValue V0, SDValue V1) {
Andrew Trickef9de2a2013-05-25 02:42:55 +00001640 SDLoc dl(V0.getNode());
Weiming Zhao8f56f882012-11-16 21:55:34 +00001641 SDValue RegClass =
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00001642 CurDAG->getTargetConstant(ARM::GPRPairRegClassID, dl, MVT::i32);
1643 SDValue SubReg0 = CurDAG->getTargetConstant(ARM::gsub_0, dl, MVT::i32);
1644 SDValue SubReg1 = CurDAG->getTargetConstant(ARM::gsub_1, dl, MVT::i32);
Weiming Zhao8f56f882012-11-16 21:55:34 +00001645 const SDValue Ops[] = { RegClass, V0, SubReg0, V1, SubReg1 };
Michael Liaob53d8962013-04-19 22:22:57 +00001646 return CurDAG->getMachineNode(TargetOpcode::REG_SEQUENCE, dl, VT, Ops);
Weiming Zhao8f56f882012-11-16 21:55:34 +00001647}
1648
Weiming Zhao95782222012-11-17 00:23:35 +00001649/// \brief Form a D register from a pair of S registers.
1650SDNode *ARMDAGToDAGISel::createSRegPairNode(EVT VT, SDValue V0, SDValue V1) {
Andrew Trickef9de2a2013-05-25 02:42:55 +00001651 SDLoc dl(V0.getNode());
Owen Anderson5fc8b772011-06-16 18:17:13 +00001652 SDValue RegClass =
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00001653 CurDAG->getTargetConstant(ARM::DPR_VFP2RegClassID, dl, MVT::i32);
1654 SDValue SubReg0 = CurDAG->getTargetConstant(ARM::ssub_0, dl, MVT::i32);
1655 SDValue SubReg1 = CurDAG->getTargetConstant(ARM::ssub_1, dl, MVT::i32);
Owen Anderson5fc8b772011-06-16 18:17:13 +00001656 const SDValue Ops[] = { RegClass, V0, SubReg0, V1, SubReg1 };
Michael Liaob53d8962013-04-19 22:22:57 +00001657 return CurDAG->getMachineNode(TargetOpcode::REG_SEQUENCE, dl, VT, Ops);
Bob Wilsond8a9a042010-06-04 00:04:02 +00001658}
1659
Weiming Zhao95782222012-11-17 00:23:35 +00001660/// \brief Form a quad register from a pair of D registers.
1661SDNode *ARMDAGToDAGISel::createDRegPairNode(EVT VT, SDValue V0, SDValue V1) {
Andrew Trickef9de2a2013-05-25 02:42:55 +00001662 SDLoc dl(V0.getNode());
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00001663 SDValue RegClass = CurDAG->getTargetConstant(ARM::QPRRegClassID, dl,
1664 MVT::i32);
1665 SDValue SubReg0 = CurDAG->getTargetConstant(ARM::dsub_0, dl, MVT::i32);
1666 SDValue SubReg1 = CurDAG->getTargetConstant(ARM::dsub_1, dl, MVT::i32);
Owen Anderson5fc8b772011-06-16 18:17:13 +00001667 const SDValue Ops[] = { RegClass, V0, SubReg0, V1, SubReg1 };
Michael Liaob53d8962013-04-19 22:22:57 +00001668 return CurDAG->getMachineNode(TargetOpcode::REG_SEQUENCE, dl, VT, Ops);
Bob Wilsone6b778d2009-10-06 22:01:59 +00001669}
1670
Weiming Zhao95782222012-11-17 00:23:35 +00001671/// \brief Form 4 consecutive D registers from a pair of Q registers.
1672SDNode *ARMDAGToDAGISel::createQRegPairNode(EVT VT, SDValue V0, SDValue V1) {
Andrew Trickef9de2a2013-05-25 02:42:55 +00001673 SDLoc dl(V0.getNode());
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00001674 SDValue RegClass = CurDAG->getTargetConstant(ARM::QQPRRegClassID, dl,
1675 MVT::i32);
1676 SDValue SubReg0 = CurDAG->getTargetConstant(ARM::qsub_0, dl, MVT::i32);
1677 SDValue SubReg1 = CurDAG->getTargetConstant(ARM::qsub_1, dl, MVT::i32);
Owen Anderson5fc8b772011-06-16 18:17:13 +00001678 const SDValue Ops[] = { RegClass, V0, SubReg0, V1, SubReg1 };
Michael Liaob53d8962013-04-19 22:22:57 +00001679 return CurDAG->getMachineNode(TargetOpcode::REG_SEQUENCE, dl, VT, Ops);
Evan Chengc2ae5f52010-05-10 17:34:18 +00001680}
1681
Weiming Zhao95782222012-11-17 00:23:35 +00001682/// \brief Form 4 consecutive S registers.
1683SDNode *ARMDAGToDAGISel::createQuadSRegsNode(EVT VT, SDValue V0, SDValue V1,
Bob Wilsond8a9a042010-06-04 00:04:02 +00001684 SDValue V2, SDValue V3) {
Andrew Trickef9de2a2013-05-25 02:42:55 +00001685 SDLoc dl(V0.getNode());
Owen Anderson5fc8b772011-06-16 18:17:13 +00001686 SDValue RegClass =
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00001687 CurDAG->getTargetConstant(ARM::QPR_VFP2RegClassID, dl, MVT::i32);
1688 SDValue SubReg0 = CurDAG->getTargetConstant(ARM::ssub_0, dl, MVT::i32);
1689 SDValue SubReg1 = CurDAG->getTargetConstant(ARM::ssub_1, dl, MVT::i32);
1690 SDValue SubReg2 = CurDAG->getTargetConstant(ARM::ssub_2, dl, MVT::i32);
1691 SDValue SubReg3 = CurDAG->getTargetConstant(ARM::ssub_3, dl, MVT::i32);
Owen Anderson5fc8b772011-06-16 18:17:13 +00001692 const SDValue Ops[] = { RegClass, V0, SubReg0, V1, SubReg1,
1693 V2, SubReg2, V3, SubReg3 };
Michael Liaob53d8962013-04-19 22:22:57 +00001694 return CurDAG->getMachineNode(TargetOpcode::REG_SEQUENCE, dl, VT, Ops);
Bob Wilsond8a9a042010-06-04 00:04:02 +00001695}
1696
Weiming Zhao95782222012-11-17 00:23:35 +00001697/// \brief Form 4 consecutive D registers.
1698SDNode *ARMDAGToDAGISel::createQuadDRegsNode(EVT VT, SDValue V0, SDValue V1,
Evan Chengc2ae5f52010-05-10 17:34:18 +00001699 SDValue V2, SDValue V3) {
Andrew Trickef9de2a2013-05-25 02:42:55 +00001700 SDLoc dl(V0.getNode());
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00001701 SDValue RegClass = CurDAG->getTargetConstant(ARM::QQPRRegClassID, dl,
1702 MVT::i32);
1703 SDValue SubReg0 = CurDAG->getTargetConstant(ARM::dsub_0, dl, MVT::i32);
1704 SDValue SubReg1 = CurDAG->getTargetConstant(ARM::dsub_1, dl, MVT::i32);
1705 SDValue SubReg2 = CurDAG->getTargetConstant(ARM::dsub_2, dl, MVT::i32);
1706 SDValue SubReg3 = CurDAG->getTargetConstant(ARM::dsub_3, dl, MVT::i32);
Owen Anderson5fc8b772011-06-16 18:17:13 +00001707 const SDValue Ops[] = { RegClass, V0, SubReg0, V1, SubReg1,
1708 V2, SubReg2, V3, SubReg3 };
Michael Liaob53d8962013-04-19 22:22:57 +00001709 return CurDAG->getMachineNode(TargetOpcode::REG_SEQUENCE, dl, VT, Ops);
Evan Chengc2ae5f52010-05-10 17:34:18 +00001710}
1711
Weiming Zhao95782222012-11-17 00:23:35 +00001712/// \brief Form 4 consecutive Q registers.
1713SDNode *ARMDAGToDAGISel::createQuadQRegsNode(EVT VT, SDValue V0, SDValue V1,
Evan Cheng298e6b82010-05-16 03:27:48 +00001714 SDValue V2, SDValue V3) {
Andrew Trickef9de2a2013-05-25 02:42:55 +00001715 SDLoc dl(V0.getNode());
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00001716 SDValue RegClass = CurDAG->getTargetConstant(ARM::QQQQPRRegClassID, dl,
1717 MVT::i32);
1718 SDValue SubReg0 = CurDAG->getTargetConstant(ARM::qsub_0, dl, MVT::i32);
1719 SDValue SubReg1 = CurDAG->getTargetConstant(ARM::qsub_1, dl, MVT::i32);
1720 SDValue SubReg2 = CurDAG->getTargetConstant(ARM::qsub_2, dl, MVT::i32);
1721 SDValue SubReg3 = CurDAG->getTargetConstant(ARM::qsub_3, dl, MVT::i32);
Owen Anderson5fc8b772011-06-16 18:17:13 +00001722 const SDValue Ops[] = { RegClass, V0, SubReg0, V1, SubReg1,
1723 V2, SubReg2, V3, SubReg3 };
Michael Liaob53d8962013-04-19 22:22:57 +00001724 return CurDAG->getMachineNode(TargetOpcode::REG_SEQUENCE, dl, VT, Ops);
Evan Cheng298e6b82010-05-16 03:27:48 +00001725}
1726
Bob Wilson7fbbe9a2010-09-23 23:42:37 +00001727/// GetVLDSTAlign - Get the alignment (in bytes) for the alignment operand
1728/// of a NEON VLD or VST instruction. The supported values depend on the
1729/// number of registers being loaded.
Benjamin Kramerbdc49562016-06-12 15:39:02 +00001730SDValue ARMDAGToDAGISel::GetVLDSTAlign(SDValue Align, const SDLoc &dl,
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00001731 unsigned NumVecs, bool is64BitVector) {
Bob Wilson7fbbe9a2010-09-23 23:42:37 +00001732 unsigned NumRegs = NumVecs;
1733 if (!is64BitVector && NumVecs < 3)
1734 NumRegs *= 2;
1735
Bob Wilsondd9fbaa2010-11-01 23:40:51 +00001736 unsigned Alignment = cast<ConstantSDNode>(Align)->getZExtValue();
Bob Wilson7fbbe9a2010-09-23 23:42:37 +00001737 if (Alignment >= 32 && NumRegs == 4)
Bob Wilsondd9fbaa2010-11-01 23:40:51 +00001738 Alignment = 32;
1739 else if (Alignment >= 16 && (NumRegs == 2 || NumRegs == 4))
1740 Alignment = 16;
1741 else if (Alignment >= 8)
1742 Alignment = 8;
1743 else
1744 Alignment = 0;
1745
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00001746 return CurDAG->getTargetConstant(Alignment, dl, MVT::i32);
Bob Wilson7fbbe9a2010-09-23 23:42:37 +00001747}
1748
Jiangning Liu4df23632014-01-16 09:16:13 +00001749static bool isVLDfixed(unsigned Opc)
1750{
1751 switch (Opc) {
1752 default: return false;
1753 case ARM::VLD1d8wb_fixed : return true;
1754 case ARM::VLD1d16wb_fixed : return true;
1755 case ARM::VLD1d64Qwb_fixed : return true;
1756 case ARM::VLD1d32wb_fixed : return true;
1757 case ARM::VLD1d64wb_fixed : return true;
1758 case ARM::VLD1d64TPseudoWB_fixed : return true;
1759 case ARM::VLD1d64QPseudoWB_fixed : return true;
1760 case ARM::VLD1q8wb_fixed : return true;
1761 case ARM::VLD1q16wb_fixed : return true;
1762 case ARM::VLD1q32wb_fixed : return true;
1763 case ARM::VLD1q64wb_fixed : return true;
1764 case ARM::VLD2d8wb_fixed : return true;
1765 case ARM::VLD2d16wb_fixed : return true;
1766 case ARM::VLD2d32wb_fixed : return true;
1767 case ARM::VLD2q8PseudoWB_fixed : return true;
1768 case ARM::VLD2q16PseudoWB_fixed : return true;
1769 case ARM::VLD2q32PseudoWB_fixed : return true;
1770 case ARM::VLD2DUPd8wb_fixed : return true;
1771 case ARM::VLD2DUPd16wb_fixed : return true;
1772 case ARM::VLD2DUPd32wb_fixed : return true;
1773 }
1774}
1775
1776static bool isVSTfixed(unsigned Opc)
1777{
1778 switch (Opc) {
1779 default: return false;
1780 case ARM::VST1d8wb_fixed : return true;
1781 case ARM::VST1d16wb_fixed : return true;
1782 case ARM::VST1d32wb_fixed : return true;
1783 case ARM::VST1d64wb_fixed : return true;
Jim Grosbach1a597112014-04-03 23:43:18 +00001784 case ARM::VST1q8wb_fixed : return true;
1785 case ARM::VST1q16wb_fixed : return true;
1786 case ARM::VST1q32wb_fixed : return true;
1787 case ARM::VST1q64wb_fixed : return true;
Jiangning Liu4df23632014-01-16 09:16:13 +00001788 case ARM::VST1d64TPseudoWB_fixed : return true;
1789 case ARM::VST1d64QPseudoWB_fixed : return true;
1790 case ARM::VST2d8wb_fixed : return true;
1791 case ARM::VST2d16wb_fixed : return true;
1792 case ARM::VST2d32wb_fixed : return true;
1793 case ARM::VST2q8PseudoWB_fixed : return true;
1794 case ARM::VST2q16PseudoWB_fixed : return true;
1795 case ARM::VST2q32PseudoWB_fixed : return true;
1796 }
1797}
1798
Jim Grosbach2098cb12011-10-24 21:45:13 +00001799// Get the register stride update opcode of a VLD/VST instruction that
1800// is otherwise equivalent to the given fixed stride updating instruction.
1801static unsigned getVLDSTRegisterUpdateOpcode(unsigned Opc) {
Jiangning Liu4df23632014-01-16 09:16:13 +00001802 assert((isVLDfixed(Opc) || isVSTfixed(Opc))
1803 && "Incorrect fixed stride updating instruction.");
Jim Grosbach2098cb12011-10-24 21:45:13 +00001804 switch (Opc) {
1805 default: break;
1806 case ARM::VLD1d8wb_fixed: return ARM::VLD1d8wb_register;
1807 case ARM::VLD1d16wb_fixed: return ARM::VLD1d16wb_register;
1808 case ARM::VLD1d32wb_fixed: return ARM::VLD1d32wb_register;
1809 case ARM::VLD1d64wb_fixed: return ARM::VLD1d64wb_register;
1810 case ARM::VLD1q8wb_fixed: return ARM::VLD1q8wb_register;
1811 case ARM::VLD1q16wb_fixed: return ARM::VLD1q16wb_register;
1812 case ARM::VLD1q32wb_fixed: return ARM::VLD1q32wb_register;
1813 case ARM::VLD1q64wb_fixed: return ARM::VLD1q64wb_register;
Jiangning Liu4df23632014-01-16 09:16:13 +00001814 case ARM::VLD1d64Twb_fixed: return ARM::VLD1d64Twb_register;
1815 case ARM::VLD1d64Qwb_fixed: return ARM::VLD1d64Qwb_register;
1816 case ARM::VLD1d64TPseudoWB_fixed: return ARM::VLD1d64TPseudoWB_register;
1817 case ARM::VLD1d64QPseudoWB_fixed: return ARM::VLD1d64QPseudoWB_register;
Jim Grosbach05df4602011-10-31 21:50:31 +00001818
1819 case ARM::VST1d8wb_fixed: return ARM::VST1d8wb_register;
1820 case ARM::VST1d16wb_fixed: return ARM::VST1d16wb_register;
1821 case ARM::VST1d32wb_fixed: return ARM::VST1d32wb_register;
1822 case ARM::VST1d64wb_fixed: return ARM::VST1d64wb_register;
1823 case ARM::VST1q8wb_fixed: return ARM::VST1q8wb_register;
1824 case ARM::VST1q16wb_fixed: return ARM::VST1q16wb_register;
1825 case ARM::VST1q32wb_fixed: return ARM::VST1q32wb_register;
1826 case ARM::VST1q64wb_fixed: return ARM::VST1q64wb_register;
Jim Grosbach98d032f2011-11-29 22:38:04 +00001827 case ARM::VST1d64TPseudoWB_fixed: return ARM::VST1d64TPseudoWB_register;
Jim Grosbach5ee209c2011-11-29 22:58:48 +00001828 case ARM::VST1d64QPseudoWB_fixed: return ARM::VST1d64QPseudoWB_register;
Jim Grosbachd146a022011-12-09 21:28:25 +00001829
Jim Grosbachc988e0c2012-03-05 19:33:30 +00001830 case ARM::VLD2d8wb_fixed: return ARM::VLD2d8wb_register;
1831 case ARM::VLD2d16wb_fixed: return ARM::VLD2d16wb_register;
1832 case ARM::VLD2d32wb_fixed: return ARM::VLD2d32wb_register;
Jim Grosbachd146a022011-12-09 21:28:25 +00001833 case ARM::VLD2q8PseudoWB_fixed: return ARM::VLD2q8PseudoWB_register;
1834 case ARM::VLD2q16PseudoWB_fixed: return ARM::VLD2q16PseudoWB_register;
1835 case ARM::VLD2q32PseudoWB_fixed: return ARM::VLD2q32PseudoWB_register;
1836
Jim Grosbachc988e0c2012-03-05 19:33:30 +00001837 case ARM::VST2d8wb_fixed: return ARM::VST2d8wb_register;
1838 case ARM::VST2d16wb_fixed: return ARM::VST2d16wb_register;
1839 case ARM::VST2d32wb_fixed: return ARM::VST2d32wb_register;
Jim Grosbach88ac7612011-12-14 21:32:11 +00001840 case ARM::VST2q8PseudoWB_fixed: return ARM::VST2q8PseudoWB_register;
1841 case ARM::VST2q16PseudoWB_fixed: return ARM::VST2q16PseudoWB_register;
1842 case ARM::VST2q32PseudoWB_fixed: return ARM::VST2q32PseudoWB_register;
Jim Grosbachc80a2642011-12-21 19:40:55 +00001843
Jim Grosbach13a292c2012-03-06 22:01:44 +00001844 case ARM::VLD2DUPd8wb_fixed: return ARM::VLD2DUPd8wb_register;
1845 case ARM::VLD2DUPd16wb_fixed: return ARM::VLD2DUPd16wb_register;
1846 case ARM::VLD2DUPd32wb_fixed: return ARM::VLD2DUPd32wb_register;
Jim Grosbach2098cb12011-10-24 21:45:13 +00001847 }
1848 return Opc; // If not one we handle, return it unchanged.
1849}
1850
Justin Bogner45571362016-05-12 00:31:09 +00001851void ARMDAGToDAGISel::SelectVLD(SDNode *N, bool isUpdating, unsigned NumVecs,
1852 const uint16_t *DOpcodes,
1853 const uint16_t *QOpcodes0,
1854 const uint16_t *QOpcodes1) {
Bob Wilson340861d2010-03-23 05:25:43 +00001855 assert(NumVecs >= 1 && NumVecs <= 4 && "VLD NumVecs out-of-range");
Andrew Trickef9de2a2013-05-25 02:42:55 +00001856 SDLoc dl(N);
Bob Wilson12b47992009-10-14 17:28:52 +00001857
Bob Wilsonae08a732010-03-20 22:13:40 +00001858 SDValue MemAddr, Align;
Bob Wilson06fce872011-02-07 17:43:21 +00001859 unsigned AddrOpIdx = isUpdating ? 1 : 2;
1860 if (!SelectAddrMode6(N, N->getOperand(AddrOpIdx), MemAddr, Align))
Justin Bogner45571362016-05-12 00:31:09 +00001861 return;
Bob Wilson12b47992009-10-14 17:28:52 +00001862
1863 SDValue Chain = N->getOperand(0);
1864 EVT VT = N->getValueType(0);
1865 bool is64BitVector = VT.is64BitVector();
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00001866 Align = GetVLDSTAlign(Align, dl, NumVecs, is64BitVector);
Bob Wilson9eeb8902010-09-23 21:43:54 +00001867
Bob Wilson12b47992009-10-14 17:28:52 +00001868 unsigned OpcodeIndex;
1869 switch (VT.getSimpleVT().SimpleTy) {
1870 default: llvm_unreachable("unhandled vld type");
1871 // Double-register operations:
1872 case MVT::v8i8: OpcodeIndex = 0; break;
1873 case MVT::v4i16: OpcodeIndex = 1; break;
1874 case MVT::v2f32:
1875 case MVT::v2i32: OpcodeIndex = 2; break;
1876 case MVT::v1i64: OpcodeIndex = 3; break;
1877 // Quad-register operations:
1878 case MVT::v16i8: OpcodeIndex = 0; break;
1879 case MVT::v8i16: OpcodeIndex = 1; break;
1880 case MVT::v4f32:
1881 case MVT::v4i32: OpcodeIndex = 2; break;
Ahmed Bougachabe0b2272014-12-09 21:25:00 +00001882 case MVT::v2f64:
Bob Wilson340861d2010-03-23 05:25:43 +00001883 case MVT::v2i64: OpcodeIndex = 3;
Bob Wilsoncc0a2a72010-03-23 06:20:33 +00001884 assert(NumVecs == 1 && "v2i64 type only supported for VLD1");
Bob Wilson340861d2010-03-23 05:25:43 +00001885 break;
Bob Wilson12b47992009-10-14 17:28:52 +00001886 }
1887
Bob Wilson35fafca2010-09-03 18:16:02 +00001888 EVT ResTy;
1889 if (NumVecs == 1)
1890 ResTy = VT;
1891 else {
1892 unsigned ResTyElts = (NumVecs == 3) ? 4 : NumVecs;
1893 if (!is64BitVector)
1894 ResTyElts *= 2;
1895 ResTy = EVT::getVectorVT(*CurDAG->getContext(), MVT::i64, ResTyElts);
1896 }
Bob Wilson06fce872011-02-07 17:43:21 +00001897 std::vector<EVT> ResTys;
1898 ResTys.push_back(ResTy);
1899 if (isUpdating)
1900 ResTys.push_back(MVT::i32);
1901 ResTys.push_back(MVT::Other);
Bob Wilson35fafca2010-09-03 18:16:02 +00001902
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00001903 SDValue Pred = getAL(CurDAG, dl);
Bob Wilsonae08a732010-03-20 22:13:40 +00001904 SDValue Reg0 = CurDAG->getRegister(0, MVT::i32);
Bob Wilson06fce872011-02-07 17:43:21 +00001905 SDNode *VLd;
1906 SmallVector<SDValue, 7> Ops;
Evan Cheng630063a2010-05-10 21:26:24 +00001907
Bob Wilson06fce872011-02-07 17:43:21 +00001908 // Double registers and VLD1/VLD2 quad registers are directly supported.
1909 if (is64BitVector || NumVecs <= 2) {
1910 unsigned Opc = (is64BitVector ? DOpcodes[OpcodeIndex] :
1911 QOpcodes0[OpcodeIndex]);
1912 Ops.push_back(MemAddr);
1913 Ops.push_back(Align);
1914 if (isUpdating) {
1915 SDValue Inc = N->getOperand(AddrOpIdx + 1);
Jim Grosbachd146a022011-12-09 21:28:25 +00001916 // FIXME: VLD1/VLD2 fixed increment doesn't need Reg0. Remove the reg0
Jim Grosbach2098cb12011-10-24 21:45:13 +00001917 // case entirely when the rest are updated to that form, too.
Jiangning Liu4df23632014-01-16 09:16:13 +00001918 if ((NumVecs <= 2) && !isa<ConstantSDNode>(Inc.getNode()))
Jim Grosbach2098cb12011-10-24 21:45:13 +00001919 Opc = getVLDSTRegisterUpdateOpcode(Opc);
Jiangning Liu4df23632014-01-16 09:16:13 +00001920 // FIXME: We use a VLD1 for v1i64 even if the pseudo says vld2/3/4, so
Jim Grosbach05df4602011-10-31 21:50:31 +00001921 // check for that explicitly too. Horribly hacky, but temporary.
Jiangning Liu4df23632014-01-16 09:16:13 +00001922 if ((NumVecs > 2 && !isVLDfixed(Opc)) ||
Jim Grosbach05df4602011-10-31 21:50:31 +00001923 !isa<ConstantSDNode>(Inc.getNode()))
Jim Grosbach2098cb12011-10-24 21:45:13 +00001924 Ops.push_back(isa<ConstantSDNode>(Inc.getNode()) ? Reg0 : Inc);
Evan Cheng630063a2010-05-10 21:26:24 +00001925 }
Bob Wilson06fce872011-02-07 17:43:21 +00001926 Ops.push_back(Pred);
1927 Ops.push_back(Reg0);
1928 Ops.push_back(Chain);
Michael Liaob53d8962013-04-19 22:22:57 +00001929 VLd = CurDAG->getMachineNode(Opc, dl, ResTys, Ops);
Bob Wilson75a64082010-09-02 16:00:54 +00001930
Bob Wilson12b47992009-10-14 17:28:52 +00001931 } else {
1932 // Otherwise, quad registers are loaded with two separate instructions,
1933 // where one loads the even registers and the other loads the odd registers.
Bob Wilson35fafca2010-09-03 18:16:02 +00001934 EVT AddrTy = MemAddr.getValueType();
Bob Wilson12b47992009-10-14 17:28:52 +00001935
Bob Wilson06fce872011-02-07 17:43:21 +00001936 // Load the even subregs. This is always an updating load, so that it
1937 // provides the address to the second load for the odd subregs.
Bob Wilson35fafca2010-09-03 18:16:02 +00001938 SDValue ImplDef =
1939 SDValue(CurDAG->getMachineNode(TargetOpcode::IMPLICIT_DEF, dl, ResTy), 0);
1940 const SDValue OpsA[] = { MemAddr, Align, Reg0, ImplDef, Pred, Reg0, Chain };
Bob Wilsona609b892011-02-07 17:43:15 +00001941 SDNode *VLdA = CurDAG->getMachineNode(QOpcodes0[OpcodeIndex], dl,
Michael Liaob53d8962013-04-19 22:22:57 +00001942 ResTy, AddrTy, MVT::Other, OpsA);
Bob Wilson35fafca2010-09-03 18:16:02 +00001943 Chain = SDValue(VLdA, 2);
Bob Wilson12b47992009-10-14 17:28:52 +00001944
Bob Wilsonc350cdf2009-10-14 18:32:29 +00001945 // Load the odd subregs.
Bob Wilson06fce872011-02-07 17:43:21 +00001946 Ops.push_back(SDValue(VLdA, 1));
1947 Ops.push_back(Align);
1948 if (isUpdating) {
1949 SDValue Inc = N->getOperand(AddrOpIdx + 1);
1950 assert(isa<ConstantSDNode>(Inc.getNode()) &&
1951 "only constant post-increment update allowed for VLD3/4");
1952 (void)Inc;
1953 Ops.push_back(Reg0);
1954 }
1955 Ops.push_back(SDValue(VLdA, 0));
1956 Ops.push_back(Pred);
1957 Ops.push_back(Reg0);
1958 Ops.push_back(Chain);
Michael Liaob53d8962013-04-19 22:22:57 +00001959 VLd = CurDAG->getMachineNode(QOpcodes1[OpcodeIndex], dl, ResTys, Ops);
Bob Wilson35fafca2010-09-03 18:16:02 +00001960 }
Bob Wilson12b47992009-10-14 17:28:52 +00001961
Evan Cheng40791332011-04-19 00:04:03 +00001962 // Transfer memoperands.
1963 MachineSDNode::mmo_iterator MemOp = MF->allocateMemRefsArray(1);
1964 MemOp[0] = cast<MemIntrinsicSDNode>(N)->getMemOperand();
1965 cast<MachineSDNode>(VLd)->setMemRefs(MemOp, MemOp + 1);
1966
Justin Bogner45571362016-05-12 00:31:09 +00001967 if (NumVecs == 1) {
1968 ReplaceNode(N, VLd);
1969 return;
1970 }
Bob Wilson06fce872011-02-07 17:43:21 +00001971
1972 // Extract out the subregisters.
1973 SDValue SuperReg = SDValue(VLd, 0);
Benjamin Kramer3e9a5d32016-05-27 11:36:04 +00001974 static_assert(ARM::dsub_7 == ARM::dsub_0 + 7 &&
1975 ARM::qsub_3 == ARM::qsub_0 + 3,
1976 "Unexpected subreg numbering");
Bob Wilson06fce872011-02-07 17:43:21 +00001977 unsigned Sub0 = (is64BitVector ? ARM::dsub_0 : ARM::qsub_0);
1978 for (unsigned Vec = 0; Vec < NumVecs; ++Vec)
1979 ReplaceUses(SDValue(N, Vec),
1980 CurDAG->getTargetExtractSubreg(Sub0 + Vec, dl, VT, SuperReg));
1981 ReplaceUses(SDValue(N, NumVecs), SDValue(VLd, 1));
1982 if (isUpdating)
1983 ReplaceUses(SDValue(N, NumVecs + 1), SDValue(VLd, 2));
Justin Bognered4f3782016-05-12 00:20:19 +00001984 CurDAG->RemoveDeadNode(N);
Bob Wilson12b47992009-10-14 17:28:52 +00001985}
1986
Justin Bogner45571362016-05-12 00:31:09 +00001987void ARMDAGToDAGISel::SelectVST(SDNode *N, bool isUpdating, unsigned NumVecs,
1988 const uint16_t *DOpcodes,
1989 const uint16_t *QOpcodes0,
1990 const uint16_t *QOpcodes1) {
Bob Wilson3ed511b2010-07-06 23:36:25 +00001991 assert(NumVecs >= 1 && NumVecs <= 4 && "VST NumVecs out-of-range");
Andrew Trickef9de2a2013-05-25 02:42:55 +00001992 SDLoc dl(N);
Bob Wilsonc350cdf2009-10-14 18:32:29 +00001993
Bob Wilsonae08a732010-03-20 22:13:40 +00001994 SDValue MemAddr, Align;
Bob Wilson06fce872011-02-07 17:43:21 +00001995 unsigned AddrOpIdx = isUpdating ? 1 : 2;
1996 unsigned Vec0Idx = 3; // AddrOpIdx + (isUpdating ? 2 : 1)
1997 if (!SelectAddrMode6(N, N->getOperand(AddrOpIdx), MemAddr, Align))
Justin Bogner45571362016-05-12 00:31:09 +00001998 return;
Bob Wilsonc350cdf2009-10-14 18:32:29 +00001999
Evan Cheng40791332011-04-19 00:04:03 +00002000 MachineSDNode::mmo_iterator MemOp = MF->allocateMemRefsArray(1);
2001 MemOp[0] = cast<MemIntrinsicSDNode>(N)->getMemOperand();
2002
Bob Wilsonc350cdf2009-10-14 18:32:29 +00002003 SDValue Chain = N->getOperand(0);
Bob Wilson06fce872011-02-07 17:43:21 +00002004 EVT VT = N->getOperand(Vec0Idx).getValueType();
Bob Wilsonc350cdf2009-10-14 18:32:29 +00002005 bool is64BitVector = VT.is64BitVector();
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00002006 Align = GetVLDSTAlign(Align, dl, NumVecs, is64BitVector);
Bob Wilson7fbbe9a2010-09-23 23:42:37 +00002007
Bob Wilsonc350cdf2009-10-14 18:32:29 +00002008 unsigned OpcodeIndex;
2009 switch (VT.getSimpleVT().SimpleTy) {
2010 default: llvm_unreachable("unhandled vst type");
2011 // Double-register operations:
2012 case MVT::v8i8: OpcodeIndex = 0; break;
2013 case MVT::v4i16: OpcodeIndex = 1; break;
2014 case MVT::v2f32:
2015 case MVT::v2i32: OpcodeIndex = 2; break;
2016 case MVT::v1i64: OpcodeIndex = 3; break;
2017 // Quad-register operations:
2018 case MVT::v16i8: OpcodeIndex = 0; break;
2019 case MVT::v8i16: OpcodeIndex = 1; break;
2020 case MVT::v4f32:
2021 case MVT::v4i32: OpcodeIndex = 2; break;
Ahmed Bougachabe0b2272014-12-09 21:25:00 +00002022 case MVT::v2f64:
Bob Wilsoncc0a2a72010-03-23 06:20:33 +00002023 case MVT::v2i64: OpcodeIndex = 3;
2024 assert(NumVecs == 1 && "v2i64 type only supported for VST1");
2025 break;
Bob Wilsonc350cdf2009-10-14 18:32:29 +00002026 }
2027
Bob Wilson06fce872011-02-07 17:43:21 +00002028 std::vector<EVT> ResTys;
2029 if (isUpdating)
2030 ResTys.push_back(MVT::i32);
2031 ResTys.push_back(MVT::Other);
2032
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00002033 SDValue Pred = getAL(CurDAG, dl);
Bob Wilsonae08a732010-03-20 22:13:40 +00002034 SDValue Reg0 = CurDAG->getRegister(0, MVT::i32);
Bob Wilson06fce872011-02-07 17:43:21 +00002035 SmallVector<SDValue, 7> Ops;
Evan Chenga33fc862009-11-21 06:21:52 +00002036
Bob Wilson06fce872011-02-07 17:43:21 +00002037 // Double registers and VST1/VST2 quad registers are directly supported.
2038 if (is64BitVector || NumVecs <= 2) {
Bob Wilsona609b892011-02-07 17:43:15 +00002039 SDValue SrcReg;
Bob Wilson950882b2010-08-28 05:12:57 +00002040 if (NumVecs == 1) {
Bob Wilson06fce872011-02-07 17:43:21 +00002041 SrcReg = N->getOperand(Vec0Idx);
2042 } else if (is64BitVector) {
Evan Chenge276c182010-05-11 01:19:40 +00002043 // Form a REG_SEQUENCE to force register allocation.
Bob Wilson06fce872011-02-07 17:43:21 +00002044 SDValue V0 = N->getOperand(Vec0Idx + 0);
2045 SDValue V1 = N->getOperand(Vec0Idx + 1);
Evan Chenge276c182010-05-11 01:19:40 +00002046 if (NumVecs == 2)
Weiming Zhao95782222012-11-17 00:23:35 +00002047 SrcReg = SDValue(createDRegPairNode(MVT::v2i64, V0, V1), 0);
Evan Chenge276c182010-05-11 01:19:40 +00002048 else {
Bob Wilson06fce872011-02-07 17:43:21 +00002049 SDValue V2 = N->getOperand(Vec0Idx + 2);
Bob Wilsona609b892011-02-07 17:43:15 +00002050 // If it's a vst3, form a quad D-register and leave the last part as
Evan Chenge276c182010-05-11 01:19:40 +00002051 // an undef.
2052 SDValue V3 = (NumVecs == 3)
2053 ? SDValue(CurDAG->getMachineNode(TargetOpcode::IMPLICIT_DEF,dl,VT), 0)
Bob Wilson06fce872011-02-07 17:43:21 +00002054 : N->getOperand(Vec0Idx + 3);
Weiming Zhao95782222012-11-17 00:23:35 +00002055 SrcReg = SDValue(createQuadDRegsNode(MVT::v4i64, V0, V1, V2, V3), 0);
Evan Chenge276c182010-05-11 01:19:40 +00002056 }
Bob Wilson950882b2010-08-28 05:12:57 +00002057 } else {
2058 // Form a QQ register.
Bob Wilson06fce872011-02-07 17:43:21 +00002059 SDValue Q0 = N->getOperand(Vec0Idx);
2060 SDValue Q1 = N->getOperand(Vec0Idx + 1);
Weiming Zhao95782222012-11-17 00:23:35 +00002061 SrcReg = SDValue(createQRegPairNode(MVT::v4i64, Q0, Q1), 0);
Bob Wilsonc350cdf2009-10-14 18:32:29 +00002062 }
Bob Wilson06fce872011-02-07 17:43:21 +00002063
2064 unsigned Opc = (is64BitVector ? DOpcodes[OpcodeIndex] :
2065 QOpcodes0[OpcodeIndex]);
2066 Ops.push_back(MemAddr);
2067 Ops.push_back(Align);
2068 if (isUpdating) {
2069 SDValue Inc = N->getOperand(AddrOpIdx + 1);
Jim Grosbach88ac7612011-12-14 21:32:11 +00002070 // FIXME: VST1/VST2 fixed increment doesn't need Reg0. Remove the reg0
Jim Grosbach05df4602011-10-31 21:50:31 +00002071 // case entirely when the rest are updated to that form, too.
Jim Grosbach88ac7612011-12-14 21:32:11 +00002072 if (NumVecs <= 2 && !isa<ConstantSDNode>(Inc.getNode()))
Jim Grosbach05df4602011-10-31 21:50:31 +00002073 Opc = getVLDSTRegisterUpdateOpcode(Opc);
Jiangning Liu4df23632014-01-16 09:16:13 +00002074 // FIXME: We use a VST1 for v1i64 even if the pseudo says vld2/3/4, so
Jim Grosbach05df4602011-10-31 21:50:31 +00002075 // check for that explicitly too. Horribly hacky, but temporary.
Jiangning Liu4df23632014-01-16 09:16:13 +00002076 if (!isa<ConstantSDNode>(Inc.getNode()))
2077 Ops.push_back(Inc);
2078 else if (NumVecs > 2 && !isVSTfixed(Opc))
2079 Ops.push_back(Reg0);
Bob Wilson06fce872011-02-07 17:43:21 +00002080 }
2081 Ops.push_back(SrcReg);
2082 Ops.push_back(Pred);
2083 Ops.push_back(Reg0);
2084 Ops.push_back(Chain);
Michael Liaob53d8962013-04-19 22:22:57 +00002085 SDNode *VSt = CurDAG->getMachineNode(Opc, dl, ResTys, Ops);
Evan Cheng40791332011-04-19 00:04:03 +00002086
2087 // Transfer memoperands.
2088 cast<MachineSDNode>(VSt)->setMemRefs(MemOp, MemOp + 1);
2089
Justin Bogner45571362016-05-12 00:31:09 +00002090 ReplaceNode(N, VSt);
2091 return;
Bob Wilsonc350cdf2009-10-14 18:32:29 +00002092 }
2093
2094 // Otherwise, quad registers are stored with two separate instructions,
2095 // where one stores the even registers and the other stores the odd registers.
Evan Cheng9e688cb2010-05-15 07:53:37 +00002096
Bob Wilson01ac8f92010-06-16 21:34:01 +00002097 // Form the QQQQ REG_SEQUENCE.
Bob Wilson06fce872011-02-07 17:43:21 +00002098 SDValue V0 = N->getOperand(Vec0Idx + 0);
2099 SDValue V1 = N->getOperand(Vec0Idx + 1);
2100 SDValue V2 = N->getOperand(Vec0Idx + 2);
Bob Wilson950882b2010-08-28 05:12:57 +00002101 SDValue V3 = (NumVecs == 3)
2102 ? SDValue(CurDAG->getMachineNode(TargetOpcode::IMPLICIT_DEF, dl, VT), 0)
Bob Wilson06fce872011-02-07 17:43:21 +00002103 : N->getOperand(Vec0Idx + 3);
Weiming Zhao95782222012-11-17 00:23:35 +00002104 SDValue RegSeq = SDValue(createQuadQRegsNode(MVT::v8i64, V0, V1, V2, V3), 0);
Bob Wilson01ac8f92010-06-16 21:34:01 +00002105
Bob Wilson06fce872011-02-07 17:43:21 +00002106 // Store the even D registers. This is always an updating store, so that it
2107 // provides the address to the second store for the odd subregs.
Bob Wilsona609b892011-02-07 17:43:15 +00002108 const SDValue OpsA[] = { MemAddr, Align, Reg0, RegSeq, Pred, Reg0, Chain };
2109 SDNode *VStA = CurDAG->getMachineNode(QOpcodes0[OpcodeIndex], dl,
2110 MemAddr.getValueType(),
Michael Liaob53d8962013-04-19 22:22:57 +00002111 MVT::Other, OpsA);
Evan Cheng40791332011-04-19 00:04:03 +00002112 cast<MachineSDNode>(VStA)->setMemRefs(MemOp, MemOp + 1);
Bob Wilson01ac8f92010-06-16 21:34:01 +00002113 Chain = SDValue(VStA, 1);
2114
2115 // Store the odd D registers.
Bob Wilson06fce872011-02-07 17:43:21 +00002116 Ops.push_back(SDValue(VStA, 0));
2117 Ops.push_back(Align);
2118 if (isUpdating) {
2119 SDValue Inc = N->getOperand(AddrOpIdx + 1);
2120 assert(isa<ConstantSDNode>(Inc.getNode()) &&
2121 "only constant post-increment update allowed for VST3/4");
2122 (void)Inc;
2123 Ops.push_back(Reg0);
2124 }
2125 Ops.push_back(RegSeq);
2126 Ops.push_back(Pred);
2127 Ops.push_back(Reg0);
2128 Ops.push_back(Chain);
Evan Cheng40791332011-04-19 00:04:03 +00002129 SDNode *VStB = CurDAG->getMachineNode(QOpcodes1[OpcodeIndex], dl, ResTys,
Michael Liaob53d8962013-04-19 22:22:57 +00002130 Ops);
Evan Cheng40791332011-04-19 00:04:03 +00002131 cast<MachineSDNode>(VStB)->setMemRefs(MemOp, MemOp + 1);
Justin Bogner45571362016-05-12 00:31:09 +00002132 ReplaceNode(N, VStB);
Bob Wilsonc350cdf2009-10-14 18:32:29 +00002133}
2134
Justin Bogner45571362016-05-12 00:31:09 +00002135void ARMDAGToDAGISel::SelectVLDSTLane(SDNode *N, bool IsLoad, bool isUpdating,
2136 unsigned NumVecs,
2137 const uint16_t *DOpcodes,
2138 const uint16_t *QOpcodes) {
Bob Wilson93117bc2009-10-14 16:46:45 +00002139 assert(NumVecs >=2 && NumVecs <= 4 && "VLDSTLane NumVecs out-of-range");
Andrew Trickef9de2a2013-05-25 02:42:55 +00002140 SDLoc dl(N);
Bob Wilson4145e3a2009-10-14 16:19:03 +00002141
Bob Wilsonae08a732010-03-20 22:13:40 +00002142 SDValue MemAddr, Align;
Bob Wilson06fce872011-02-07 17:43:21 +00002143 unsigned AddrOpIdx = isUpdating ? 1 : 2;
2144 unsigned Vec0Idx = 3; // AddrOpIdx + (isUpdating ? 2 : 1)
2145 if (!SelectAddrMode6(N, N->getOperand(AddrOpIdx), MemAddr, Align))
Justin Bogner45571362016-05-12 00:31:09 +00002146 return;
Bob Wilson4145e3a2009-10-14 16:19:03 +00002147
Evan Cheng40791332011-04-19 00:04:03 +00002148 MachineSDNode::mmo_iterator MemOp = MF->allocateMemRefsArray(1);
2149 MemOp[0] = cast<MemIntrinsicSDNode>(N)->getMemOperand();
2150
Bob Wilson4145e3a2009-10-14 16:19:03 +00002151 SDValue Chain = N->getOperand(0);
2152 unsigned Lane =
Bob Wilson06fce872011-02-07 17:43:21 +00002153 cast<ConstantSDNode>(N->getOperand(Vec0Idx + NumVecs))->getZExtValue();
2154 EVT VT = N->getOperand(Vec0Idx).getValueType();
Bob Wilson4145e3a2009-10-14 16:19:03 +00002155 bool is64BitVector = VT.is64BitVector();
2156
Bob Wilsondd9fbaa2010-11-01 23:40:51 +00002157 unsigned Alignment = 0;
Bob Wilsonb6d61dc2010-10-19 00:16:32 +00002158 if (NumVecs != 3) {
Bob Wilsondd9fbaa2010-11-01 23:40:51 +00002159 Alignment = cast<ConstantSDNode>(Align)->getZExtValue();
Sanjay Patel1ed771f2016-09-14 16:37:15 +00002160 unsigned NumBytes = NumVecs * VT.getScalarSizeInBits() / 8;
Bob Wilsonb6d61dc2010-10-19 00:16:32 +00002161 if (Alignment > NumBytes)
2162 Alignment = NumBytes;
Bob Wilsond29b38c2010-12-10 19:37:42 +00002163 if (Alignment < 8 && Alignment < NumBytes)
2164 Alignment = 0;
Bob Wilsonb6d61dc2010-10-19 00:16:32 +00002165 // Alignment must be a power of two; make sure of that.
2166 Alignment = (Alignment & -Alignment);
Bob Wilsondd9fbaa2010-11-01 23:40:51 +00002167 if (Alignment == 1)
2168 Alignment = 0;
Bob Wilsonb6d61dc2010-10-19 00:16:32 +00002169 }
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00002170 Align = CurDAG->getTargetConstant(Alignment, dl, MVT::i32);
Bob Wilsonb6d61dc2010-10-19 00:16:32 +00002171
Bob Wilson4145e3a2009-10-14 16:19:03 +00002172 unsigned OpcodeIndex;
2173 switch (VT.getSimpleVT().SimpleTy) {
Bob Wilson93117bc2009-10-14 16:46:45 +00002174 default: llvm_unreachable("unhandled vld/vst lane type");
Bob Wilson4145e3a2009-10-14 16:19:03 +00002175 // Double-register operations:
2176 case MVT::v8i8: OpcodeIndex = 0; break;
2177 case MVT::v4i16: OpcodeIndex = 1; break;
2178 case MVT::v2f32:
2179 case MVT::v2i32: OpcodeIndex = 2; break;
2180 // Quad-register operations:
2181 case MVT::v8i16: OpcodeIndex = 0; break;
2182 case MVT::v4f32:
2183 case MVT::v4i32: OpcodeIndex = 1; break;
2184 }
2185
Bob Wilson06fce872011-02-07 17:43:21 +00002186 std::vector<EVT> ResTys;
2187 if (IsLoad) {
2188 unsigned ResTyElts = (NumVecs == 3) ? 4 : NumVecs;
2189 if (!is64BitVector)
2190 ResTyElts *= 2;
2191 ResTys.push_back(EVT::getVectorVT(*CurDAG->getContext(),
2192 MVT::i64, ResTyElts));
2193 }
2194 if (isUpdating)
2195 ResTys.push_back(MVT::i32);
2196 ResTys.push_back(MVT::Other);
2197
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00002198 SDValue Pred = getAL(CurDAG, dl);
Bob Wilsonae08a732010-03-20 22:13:40 +00002199 SDValue Reg0 = CurDAG->getRegister(0, MVT::i32);
Evan Chenga33fc862009-11-21 06:21:52 +00002200
Bob Wilson06fce872011-02-07 17:43:21 +00002201 SmallVector<SDValue, 8> Ops;
Bob Wilson4145e3a2009-10-14 16:19:03 +00002202 Ops.push_back(MemAddr);
Jim Grosbachd1d002a2009-11-07 21:25:39 +00002203 Ops.push_back(Align);
Bob Wilson06fce872011-02-07 17:43:21 +00002204 if (isUpdating) {
2205 SDValue Inc = N->getOperand(AddrOpIdx + 1);
2206 Ops.push_back(isa<ConstantSDNode>(Inc.getNode()) ? Reg0 : Inc);
2207 }
Bob Wilson01ac8f92010-06-16 21:34:01 +00002208
Bob Wilsond5c57a52010-09-13 23:01:35 +00002209 SDValue SuperReg;
Bob Wilson06fce872011-02-07 17:43:21 +00002210 SDValue V0 = N->getOperand(Vec0Idx + 0);
2211 SDValue V1 = N->getOperand(Vec0Idx + 1);
Bob Wilsond5c57a52010-09-13 23:01:35 +00002212 if (NumVecs == 2) {
2213 if (is64BitVector)
Weiming Zhao95782222012-11-17 00:23:35 +00002214 SuperReg = SDValue(createDRegPairNode(MVT::v2i64, V0, V1), 0);
Bob Wilsond5c57a52010-09-13 23:01:35 +00002215 else
Weiming Zhao95782222012-11-17 00:23:35 +00002216 SuperReg = SDValue(createQRegPairNode(MVT::v4i64, V0, V1), 0);
Bob Wilson4145e3a2009-10-14 16:19:03 +00002217 } else {
Bob Wilson06fce872011-02-07 17:43:21 +00002218 SDValue V2 = N->getOperand(Vec0Idx + 2);
Bob Wilsond5c57a52010-09-13 23:01:35 +00002219 SDValue V3 = (NumVecs == 3)
Bob Wilson06fce872011-02-07 17:43:21 +00002220 ? SDValue(CurDAG->getMachineNode(TargetOpcode::IMPLICIT_DEF, dl, VT), 0)
2221 : N->getOperand(Vec0Idx + 3);
Bob Wilsond5c57a52010-09-13 23:01:35 +00002222 if (is64BitVector)
Weiming Zhao95782222012-11-17 00:23:35 +00002223 SuperReg = SDValue(createQuadDRegsNode(MVT::v4i64, V0, V1, V2, V3), 0);
Bob Wilsond5c57a52010-09-13 23:01:35 +00002224 else
Weiming Zhao95782222012-11-17 00:23:35 +00002225 SuperReg = SDValue(createQuadQRegsNode(MVT::v8i64, V0, V1, V2, V3), 0);
Bob Wilson4145e3a2009-10-14 16:19:03 +00002226 }
Bob Wilsond5c57a52010-09-13 23:01:35 +00002227 Ops.push_back(SuperReg);
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00002228 Ops.push_back(getI32Imm(Lane, dl));
Evan Chenga33fc862009-11-21 06:21:52 +00002229 Ops.push_back(Pred);
Bob Wilsonae08a732010-03-20 22:13:40 +00002230 Ops.push_back(Reg0);
Bob Wilson4145e3a2009-10-14 16:19:03 +00002231 Ops.push_back(Chain);
2232
Bob Wilson06fce872011-02-07 17:43:21 +00002233 unsigned Opc = (is64BitVector ? DOpcodes[OpcodeIndex] :
2234 QOpcodes[OpcodeIndex]);
Michael Liaob53d8962013-04-19 22:22:57 +00002235 SDNode *VLdLn = CurDAG->getMachineNode(Opc, dl, ResTys, Ops);
Evan Cheng40791332011-04-19 00:04:03 +00002236 cast<MachineSDNode>(VLdLn)->setMemRefs(MemOp, MemOp + 1);
Justin Bogner45571362016-05-12 00:31:09 +00002237 if (!IsLoad) {
2238 ReplaceNode(N, VLdLn);
2239 return;
2240 }
Evan Cheng0cbd11d2010-05-15 01:36:29 +00002241
Bob Wilsond5c57a52010-09-13 23:01:35 +00002242 // Extract the subregisters.
Bob Wilson06fce872011-02-07 17:43:21 +00002243 SuperReg = SDValue(VLdLn, 0);
Benjamin Kramer3e9a5d32016-05-27 11:36:04 +00002244 static_assert(ARM::dsub_7 == ARM::dsub_0 + 7 &&
2245 ARM::qsub_3 == ARM::qsub_0 + 3,
2246 "Unexpected subreg numbering");
Bob Wilson06fce872011-02-07 17:43:21 +00002247 unsigned Sub0 = is64BitVector ? ARM::dsub_0 : ARM::qsub_0;
Bob Wilson01ac8f92010-06-16 21:34:01 +00002248 for (unsigned Vec = 0; Vec < NumVecs; ++Vec)
2249 ReplaceUses(SDValue(N, Vec),
Bob Wilson06fce872011-02-07 17:43:21 +00002250 CurDAG->getTargetExtractSubreg(Sub0 + Vec, dl, VT, SuperReg));
2251 ReplaceUses(SDValue(N, NumVecs), SDValue(VLdLn, 1));
2252 if (isUpdating)
2253 ReplaceUses(SDValue(N, NumVecs + 1), SDValue(VLdLn, 2));
Justin Bognered4f3782016-05-12 00:20:19 +00002254 CurDAG->RemoveDeadNode(N);
Bob Wilson4145e3a2009-10-14 16:19:03 +00002255}
2256
Justin Bogner45571362016-05-12 00:31:09 +00002257void ARMDAGToDAGISel::SelectVLDDup(SDNode *N, bool isUpdating, unsigned NumVecs,
2258 const uint16_t *Opcodes) {
Bob Wilson2d790df2010-11-28 06:51:26 +00002259 assert(NumVecs >=2 && NumVecs <= 4 && "VLDDup NumVecs out-of-range");
Andrew Trickef9de2a2013-05-25 02:42:55 +00002260 SDLoc dl(N);
Bob Wilson2d790df2010-11-28 06:51:26 +00002261
2262 SDValue MemAddr, Align;
2263 if (!SelectAddrMode6(N, N->getOperand(1), MemAddr, Align))
Justin Bogner45571362016-05-12 00:31:09 +00002264 return;
Bob Wilson2d790df2010-11-28 06:51:26 +00002265
Evan Cheng40791332011-04-19 00:04:03 +00002266 MachineSDNode::mmo_iterator MemOp = MF->allocateMemRefsArray(1);
2267 MemOp[0] = cast<MemIntrinsicSDNode>(N)->getMemOperand();
2268
Bob Wilson2d790df2010-11-28 06:51:26 +00002269 SDValue Chain = N->getOperand(0);
2270 EVT VT = N->getValueType(0);
2271
2272 unsigned Alignment = 0;
2273 if (NumVecs != 3) {
2274 Alignment = cast<ConstantSDNode>(Align)->getZExtValue();
Sanjay Patel1ed771f2016-09-14 16:37:15 +00002275 unsigned NumBytes = NumVecs * VT.getScalarSizeInBits() / 8;
Bob Wilson2d790df2010-11-28 06:51:26 +00002276 if (Alignment > NumBytes)
2277 Alignment = NumBytes;
Bob Wilsond29b38c2010-12-10 19:37:42 +00002278 if (Alignment < 8 && Alignment < NumBytes)
2279 Alignment = 0;
Bob Wilson2d790df2010-11-28 06:51:26 +00002280 // Alignment must be a power of two; make sure of that.
2281 Alignment = (Alignment & -Alignment);
2282 if (Alignment == 1)
2283 Alignment = 0;
2284 }
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00002285 Align = CurDAG->getTargetConstant(Alignment, dl, MVT::i32);
Bob Wilson2d790df2010-11-28 06:51:26 +00002286
2287 unsigned OpcodeIndex;
2288 switch (VT.getSimpleVT().SimpleTy) {
2289 default: llvm_unreachable("unhandled vld-dup type");
2290 case MVT::v8i8: OpcodeIndex = 0; break;
2291 case MVT::v4i16: OpcodeIndex = 1; break;
2292 case MVT::v2f32:
2293 case MVT::v2i32: OpcodeIndex = 2; break;
2294 }
2295
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00002296 SDValue Pred = getAL(CurDAG, dl);
Bob Wilson2d790df2010-11-28 06:51:26 +00002297 SDValue Reg0 = CurDAG->getRegister(0, MVT::i32);
2298 SDValue SuperReg;
2299 unsigned Opc = Opcodes[OpcodeIndex];
Bob Wilson06fce872011-02-07 17:43:21 +00002300 SmallVector<SDValue, 6> Ops;
2301 Ops.push_back(MemAddr);
2302 Ops.push_back(Align);
2303 if (isUpdating) {
Jim Grosbachc80a2642011-12-21 19:40:55 +00002304 // fixed-stride update instructions don't have an explicit writeback
2305 // operand. It's implicit in the opcode itself.
Bob Wilson06fce872011-02-07 17:43:21 +00002306 SDValue Inc = N->getOperand(2);
Jim Grosbachc80a2642011-12-21 19:40:55 +00002307 if (!isa<ConstantSDNode>(Inc.getNode()))
2308 Ops.push_back(Inc);
2309 // FIXME: VLD3 and VLD4 haven't been updated to that form yet.
2310 else if (NumVecs > 2)
2311 Ops.push_back(Reg0);
Bob Wilson06fce872011-02-07 17:43:21 +00002312 }
2313 Ops.push_back(Pred);
2314 Ops.push_back(Reg0);
2315 Ops.push_back(Chain);
Bob Wilson2d790df2010-11-28 06:51:26 +00002316
2317 unsigned ResTyElts = (NumVecs == 3) ? 4 : NumVecs;
Bob Wilson06fce872011-02-07 17:43:21 +00002318 std::vector<EVT> ResTys;
Evan Cheng40791332011-04-19 00:04:03 +00002319 ResTys.push_back(EVT::getVectorVT(*CurDAG->getContext(), MVT::i64,ResTyElts));
Bob Wilson06fce872011-02-07 17:43:21 +00002320 if (isUpdating)
2321 ResTys.push_back(MVT::i32);
2322 ResTys.push_back(MVT::Other);
Michael Liaob53d8962013-04-19 22:22:57 +00002323 SDNode *VLdDup = CurDAG->getMachineNode(Opc, dl, ResTys, Ops);
Evan Cheng40791332011-04-19 00:04:03 +00002324 cast<MachineSDNode>(VLdDup)->setMemRefs(MemOp, MemOp + 1);
Bob Wilson2d790df2010-11-28 06:51:26 +00002325 SuperReg = SDValue(VLdDup, 0);
Bob Wilson2d790df2010-11-28 06:51:26 +00002326
2327 // Extract the subregisters.
Benjamin Kramer3e9a5d32016-05-27 11:36:04 +00002328 static_assert(ARM::dsub_7 == ARM::dsub_0 + 7, "Unexpected subreg numbering");
Bob Wilson2d790df2010-11-28 06:51:26 +00002329 unsigned SubIdx = ARM::dsub_0;
2330 for (unsigned Vec = 0; Vec < NumVecs; ++Vec)
2331 ReplaceUses(SDValue(N, Vec),
2332 CurDAG->getTargetExtractSubreg(SubIdx+Vec, dl, VT, SuperReg));
Bob Wilson06fce872011-02-07 17:43:21 +00002333 ReplaceUses(SDValue(N, NumVecs), SDValue(VLdDup, 1));
2334 if (isUpdating)
2335 ReplaceUses(SDValue(N, NumVecs + 1), SDValue(VLdDup, 2));
Justin Bognered4f3782016-05-12 00:20:19 +00002336 CurDAG->RemoveDeadNode(N);
Bob Wilson2d790df2010-11-28 06:51:26 +00002337}
2338
Justin Bogner45571362016-05-12 00:31:09 +00002339void ARMDAGToDAGISel::SelectVTBL(SDNode *N, bool IsExt, unsigned NumVecs,
2340 unsigned Opc) {
Bob Wilson3ed511b2010-07-06 23:36:25 +00002341 assert(NumVecs >= 2 && NumVecs <= 4 && "VTBL NumVecs out-of-range");
Andrew Trickef9de2a2013-05-25 02:42:55 +00002342 SDLoc dl(N);
Bob Wilson3ed511b2010-07-06 23:36:25 +00002343 EVT VT = N->getValueType(0);
Bob Wilson5bc8a792010-07-07 00:08:54 +00002344 unsigned FirstTblReg = IsExt ? 2 : 1;
Bob Wilson3ed511b2010-07-06 23:36:25 +00002345
2346 // Form a REG_SEQUENCE to force register allocation.
2347 SDValue RegSeq;
Bob Wilson5bc8a792010-07-07 00:08:54 +00002348 SDValue V0 = N->getOperand(FirstTblReg + 0);
2349 SDValue V1 = N->getOperand(FirstTblReg + 1);
Bob Wilson3ed511b2010-07-06 23:36:25 +00002350 if (NumVecs == 2)
Weiming Zhao95782222012-11-17 00:23:35 +00002351 RegSeq = SDValue(createDRegPairNode(MVT::v16i8, V0, V1), 0);
Bob Wilson3ed511b2010-07-06 23:36:25 +00002352 else {
Bob Wilson5bc8a792010-07-07 00:08:54 +00002353 SDValue V2 = N->getOperand(FirstTblReg + 2);
Jim Grosbachd37f0712010-10-21 19:38:40 +00002354 // If it's a vtbl3, form a quad D-register and leave the last part as
Bob Wilson3ed511b2010-07-06 23:36:25 +00002355 // an undef.
2356 SDValue V3 = (NumVecs == 3)
2357 ? SDValue(CurDAG->getMachineNode(TargetOpcode::IMPLICIT_DEF, dl, VT), 0)
Bob Wilson5bc8a792010-07-07 00:08:54 +00002358 : N->getOperand(FirstTblReg + 3);
Weiming Zhao95782222012-11-17 00:23:35 +00002359 RegSeq = SDValue(createQuadDRegsNode(MVT::v4i64, V0, V1, V2, V3), 0);
Bob Wilson3ed511b2010-07-06 23:36:25 +00002360 }
2361
Bob Wilson5bc8a792010-07-07 00:08:54 +00002362 SmallVector<SDValue, 6> Ops;
2363 if (IsExt)
2364 Ops.push_back(N->getOperand(1));
Bob Wilsonc597fd3b2010-09-13 23:55:10 +00002365 Ops.push_back(RegSeq);
Bob Wilson5bc8a792010-07-07 00:08:54 +00002366 Ops.push_back(N->getOperand(FirstTblReg + NumVecs));
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00002367 Ops.push_back(getAL(CurDAG, dl)); // predicate
Bob Wilson3ed511b2010-07-06 23:36:25 +00002368 Ops.push_back(CurDAG->getRegister(0, MVT::i32)); // predicate register
Justin Bogner45571362016-05-12 00:31:09 +00002369 ReplaceNode(N, CurDAG->getMachineNode(Opc, dl, VT, Ops));
Bob Wilson3ed511b2010-07-06 23:36:25 +00002370}
2371
Justin Bogner45571362016-05-12 00:31:09 +00002372bool ARMDAGToDAGISel::tryV6T2BitfieldExtractOp(SDNode *N, bool isSigned) {
Sandeep Patel423e42b2009-10-13 18:59:48 +00002373 if (!Subtarget->hasV6T2Ops())
Justin Bogner45571362016-05-12 00:31:09 +00002374 return false;
Bob Wilson93117bc2009-10-14 16:46:45 +00002375
Evan Chengeae6d2c2012-12-19 20:16:09 +00002376 unsigned Opc = isSigned
2377 ? (Subtarget->isThumb() ? ARM::t2SBFX : ARM::SBFX)
Jim Grosbach825cb292010-04-22 23:24:18 +00002378 : (Subtarget->isThumb() ? ARM::t2UBFX : ARM::UBFX);
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00002379 SDLoc dl(N);
Jim Grosbach825cb292010-04-22 23:24:18 +00002380
Jim Grosbach825cb292010-04-22 23:24:18 +00002381 // For unsigned extracts, check for a shift right and mask
2382 unsigned And_imm = 0;
2383 if (N->getOpcode() == ISD::AND) {
2384 if (isOpcWithIntImmediate(N, ISD::AND, And_imm)) {
2385
Sylvestre Ledru91ce36c2012-09-27 10:14:43 +00002386 // The immediate is a mask of the low bits iff imm & (imm+1) == 0
Jim Grosbach825cb292010-04-22 23:24:18 +00002387 if (And_imm & (And_imm + 1))
Justin Bogner45571362016-05-12 00:31:09 +00002388 return false;
Jim Grosbach825cb292010-04-22 23:24:18 +00002389
2390 unsigned Srl_imm = 0;
2391 if (isOpcWithIntImmediate(N->getOperand(0).getNode(), ISD::SRL,
2392 Srl_imm)) {
2393 assert(Srl_imm > 0 && Srl_imm < 32 && "bad amount in shift node!");
2394
Jim Grosbach03f56d92011-07-27 21:09:25 +00002395 // Note: The width operand is encoded as width-1.
Benjamin Kramer5f6a9072015-02-12 15:35:40 +00002396 unsigned Width = countTrailingOnes(And_imm) - 1;
Jim Grosbach825cb292010-04-22 23:24:18 +00002397 unsigned LSB = Srl_imm;
Evan Chengeae6d2c2012-12-19 20:16:09 +00002398
Jim Grosbach825cb292010-04-22 23:24:18 +00002399 SDValue Reg0 = CurDAG->getRegister(0, MVT::i32);
Evan Chengeae6d2c2012-12-19 20:16:09 +00002400
2401 if ((LSB + Width + 1) == N->getValueType(0).getSizeInBits()) {
2402 // It's cheaper to use a right shift to extract the top bits.
2403 if (Subtarget->isThumb()) {
2404 Opc = isSigned ? ARM::t2ASRri : ARM::t2LSRri;
2405 SDValue Ops[] = { N->getOperand(0).getOperand(0),
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00002406 CurDAG->getTargetConstant(LSB, dl, MVT::i32),
2407 getAL(CurDAG, dl), Reg0, Reg0 };
Justin Bogner45571362016-05-12 00:31:09 +00002408 CurDAG->SelectNodeTo(N, Opc, MVT::i32, Ops);
2409 return true;
Evan Chengeae6d2c2012-12-19 20:16:09 +00002410 }
2411
2412 // ARM models shift instructions as MOVsi with shifter operand.
2413 ARM_AM::ShiftOpc ShOpcVal = ARM_AM::getShiftOpcForNode(ISD::SRL);
2414 SDValue ShOpc =
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00002415 CurDAG->getTargetConstant(ARM_AM::getSORegOpc(ShOpcVal, LSB), dl,
Evan Chengeae6d2c2012-12-19 20:16:09 +00002416 MVT::i32);
2417 SDValue Ops[] = { N->getOperand(0).getOperand(0), ShOpc,
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00002418 getAL(CurDAG, dl), Reg0, Reg0 };
Justin Bogner45571362016-05-12 00:31:09 +00002419 CurDAG->SelectNodeTo(N, ARM::MOVsi, MVT::i32, Ops);
2420 return true;
Evan Chengeae6d2c2012-12-19 20:16:09 +00002421 }
2422
Jim Grosbach825cb292010-04-22 23:24:18 +00002423 SDValue Ops[] = { N->getOperand(0).getOperand(0),
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00002424 CurDAG->getTargetConstant(LSB, dl, MVT::i32),
2425 CurDAG->getTargetConstant(Width, dl, MVT::i32),
2426 getAL(CurDAG, dl), Reg0 };
Justin Bogner45571362016-05-12 00:31:09 +00002427 CurDAG->SelectNodeTo(N, Opc, MVT::i32, Ops);
2428 return true;
Jim Grosbach825cb292010-04-22 23:24:18 +00002429 }
2430 }
Justin Bogner45571362016-05-12 00:31:09 +00002431 return false;
Jim Grosbach825cb292010-04-22 23:24:18 +00002432 }
2433
2434 // Otherwise, we're looking for a shift of a shift
Sandeep Patel423e42b2009-10-13 18:59:48 +00002435 unsigned Shl_imm = 0;
Dan Gohmanea6f91f2010-01-05 01:24:18 +00002436 if (isOpcWithIntImmediate(N->getOperand(0).getNode(), ISD::SHL, Shl_imm)) {
Sandeep Patel423e42b2009-10-13 18:59:48 +00002437 assert(Shl_imm > 0 && Shl_imm < 32 && "bad amount in shift node!");
2438 unsigned Srl_imm = 0;
Dan Gohmanea6f91f2010-01-05 01:24:18 +00002439 if (isInt32Immediate(N->getOperand(1), Srl_imm)) {
Sandeep Patel423e42b2009-10-13 18:59:48 +00002440 assert(Srl_imm > 0 && Srl_imm < 32 && "bad amount in shift node!");
Jim Grosbach03f56d92011-07-27 21:09:25 +00002441 // Note: The width operand is encoded as width-1.
2442 unsigned Width = 32 - Srl_imm - 1;
Sandeep Patel423e42b2009-10-13 18:59:48 +00002443 int LSB = Srl_imm - Shl_imm;
Evan Cheng0f55e9c2009-10-22 00:40:00 +00002444 if (LSB < 0)
Justin Bogner45571362016-05-12 00:31:09 +00002445 return false;
Sandeep Patel423e42b2009-10-13 18:59:48 +00002446 SDValue Reg0 = CurDAG->getRegister(0, MVT::i32);
Dan Gohmanea6f91f2010-01-05 01:24:18 +00002447 SDValue Ops[] = { N->getOperand(0).getOperand(0),
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00002448 CurDAG->getTargetConstant(LSB, dl, MVT::i32),
2449 CurDAG->getTargetConstant(Width, dl, MVT::i32),
2450 getAL(CurDAG, dl), Reg0 };
Justin Bogner45571362016-05-12 00:31:09 +00002451 CurDAG->SelectNodeTo(N, Opc, MVT::i32, Ops);
2452 return true;
Sandeep Patel423e42b2009-10-13 18:59:48 +00002453 }
2454 }
Tim Northover14ff2df2014-07-23 13:59:12 +00002455
Oliver Stannard92ca83c2016-06-01 12:01:01 +00002456 // Or we are looking for a shift of an and, with a mask operand
2457 if (isOpcWithIntImmediate(N->getOperand(0).getNode(), ISD::AND, And_imm) &&
2458 isShiftedMask_32(And_imm)) {
2459 unsigned Srl_imm = 0;
2460 unsigned LSB = countTrailingZeros(And_imm);
2461 // Shift must be the same as the ands lsb
2462 if (isInt32Immediate(N->getOperand(1), Srl_imm) && Srl_imm == LSB) {
2463 assert(Srl_imm > 0 && Srl_imm < 32 && "bad amount in shift node!");
2464 unsigned MSB = 31 - countLeadingZeros(And_imm);
2465 // Note: The width operand is encoded as width-1.
2466 unsigned Width = MSB - LSB;
2467 SDValue Reg0 = CurDAG->getRegister(0, MVT::i32);
2468 SDValue Ops[] = { N->getOperand(0).getOperand(0),
2469 CurDAG->getTargetConstant(Srl_imm, dl, MVT::i32),
2470 CurDAG->getTargetConstant(Width, dl, MVT::i32),
2471 getAL(CurDAG, dl), Reg0 };
2472 CurDAG->SelectNodeTo(N, Opc, MVT::i32, Ops);
2473 return true;
2474 }
2475 }
2476
Tim Northover14ff2df2014-07-23 13:59:12 +00002477 if (N->getOpcode() == ISD::SIGN_EXTEND_INREG) {
2478 unsigned Width = cast<VTSDNode>(N->getOperand(1))->getVT().getSizeInBits();
2479 unsigned LSB = 0;
2480 if (!isOpcWithIntImmediate(N->getOperand(0).getNode(), ISD::SRL, LSB) &&
2481 !isOpcWithIntImmediate(N->getOperand(0).getNode(), ISD::SRA, LSB))
Justin Bogner45571362016-05-12 00:31:09 +00002482 return false;
Tim Northover14ff2df2014-07-23 13:59:12 +00002483
2484 if (LSB + Width > 32)
Justin Bogner45571362016-05-12 00:31:09 +00002485 return false;
Tim Northover14ff2df2014-07-23 13:59:12 +00002486
2487 SDValue Reg0 = CurDAG->getRegister(0, MVT::i32);
2488 SDValue Ops[] = { N->getOperand(0).getOperand(0),
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00002489 CurDAG->getTargetConstant(LSB, dl, MVT::i32),
2490 CurDAG->getTargetConstant(Width - 1, dl, MVT::i32),
2491 getAL(CurDAG, dl), Reg0 };
Justin Bogner45571362016-05-12 00:31:09 +00002492 CurDAG->SelectNodeTo(N, Opc, MVT::i32, Ops);
2493 return true;
Tim Northover14ff2df2014-07-23 13:59:12 +00002494 }
2495
Justin Bogner45571362016-05-12 00:31:09 +00002496 return false;
Sandeep Patel423e42b2009-10-13 18:59:48 +00002497}
2498
Bill Wendlinga7d697e2011-10-10 22:59:55 +00002499/// Target-specific DAG combining for ISD::XOR.
2500/// Target-independent combining lowers SELECT_CC nodes of the form
2501/// select_cc setg[ge] X, 0, X, -X
2502/// select_cc setgt X, -1, X, -X
2503/// select_cc setl[te] X, 0, -X, X
2504/// select_cc setlt X, 1, -X, X
2505/// which represent Integer ABS into:
2506/// Y = sra (X, size(X)-1); xor (add (X, Y), Y)
2507/// ARM instruction selection detects the latter and matches it to
2508/// ARM::ABS or ARM::t2ABS machine node.
Justin Bogner45571362016-05-12 00:31:09 +00002509bool ARMDAGToDAGISel::tryABSOp(SDNode *N){
Bill Wendlinga7d697e2011-10-10 22:59:55 +00002510 SDValue XORSrc0 = N->getOperand(0);
2511 SDValue XORSrc1 = N->getOperand(1);
Bill Wendlinga7d697e2011-10-10 22:59:55 +00002512 EVT VT = N->getValueType(0);
2513
Bill Wendlinga7d697e2011-10-10 22:59:55 +00002514 if (Subtarget->isThumb1Only())
Justin Bogner45571362016-05-12 00:31:09 +00002515 return false;
Bill Wendlinga7d697e2011-10-10 22:59:55 +00002516
Jim Grosbachb437a8c2012-08-01 20:33:00 +00002517 if (XORSrc0.getOpcode() != ISD::ADD || XORSrc1.getOpcode() != ISD::SRA)
Justin Bogner45571362016-05-12 00:31:09 +00002518 return false;
Bill Wendlinga7d697e2011-10-10 22:59:55 +00002519
2520 SDValue ADDSrc0 = XORSrc0.getOperand(0);
2521 SDValue ADDSrc1 = XORSrc0.getOperand(1);
2522 SDValue SRASrc0 = XORSrc1.getOperand(0);
2523 SDValue SRASrc1 = XORSrc1.getOperand(1);
2524 ConstantSDNode *SRAConstant = dyn_cast<ConstantSDNode>(SRASrc1);
2525 EVT XType = SRASrc0.getValueType();
2526 unsigned Size = XType.getSizeInBits() - 1;
2527
Jim Grosbachb437a8c2012-08-01 20:33:00 +00002528 if (ADDSrc1 == XORSrc1 && ADDSrc0 == SRASrc0 &&
Craig Topper062a2ba2014-04-25 05:30:21 +00002529 XType.isInteger() && SRAConstant != nullptr &&
Bill Wendlinga7d697e2011-10-10 22:59:55 +00002530 Size == SRAConstant->getZExtValue()) {
Jim Grosbachb437a8c2012-08-01 20:33:00 +00002531 unsigned Opcode = Subtarget->isThumb2() ? ARM::t2ABS : ARM::ABS;
Justin Bogner45571362016-05-12 00:31:09 +00002532 CurDAG->SelectNodeTo(N, Opcode, VT, ADDSrc0);
2533 return true;
Bill Wendlinga7d697e2011-10-10 22:59:55 +00002534 }
2535
Justin Bogner45571362016-05-12 00:31:09 +00002536 return false;
Bill Wendlinga7d697e2011-10-10 22:59:55 +00002537}
2538
Sam Parker2d5126c2016-04-08 16:02:53 +00002539static bool SearchSignedMulShort(SDValue SignExt, unsigned *Opc, SDValue &Src1,
2540 bool Accumulate) {
2541 // For SM*WB, we need to some form of sext.
2542 // For SM*WT, we need to search for (sra X, 16)
2543 // Src1 then gets set to X.
2544 if ((SignExt.getOpcode() == ISD::SIGN_EXTEND ||
2545 SignExt.getOpcode() == ISD::SIGN_EXTEND_INREG ||
2546 SignExt.getOpcode() == ISD::AssertSext) &&
2547 SignExt.getValueType() == MVT::i32) {
2548
2549 *Opc = Accumulate ? ARM::SMLAWB : ARM::SMULWB;
2550 Src1 = SignExt.getOperand(0);
2551 return true;
2552 }
2553
2554 if (SignExt.getOpcode() != ISD::SRA)
2555 return false;
2556
2557 ConstantSDNode *SRASrc1 = dyn_cast<ConstantSDNode>(SignExt.getOperand(1));
2558 if (!SRASrc1 || SRASrc1->getZExtValue() != 16)
2559 return false;
2560
2561 SDValue Op0 = SignExt.getOperand(0);
2562
2563 // The sign extend operand for SM*WB could be generated by a shl and ashr.
2564 if (Op0.getOpcode() == ISD::SHL) {
2565 SDValue SHL = Op0;
2566 ConstantSDNode *SHLSrc1 = dyn_cast<ConstantSDNode>(SHL.getOperand(1));
2567 if (!SHLSrc1 || SHLSrc1->getZExtValue() != 16)
2568 return false;
2569
2570 *Opc = Accumulate ? ARM::SMLAWB : ARM::SMULWB;
2571 Src1 = Op0.getOperand(0);
2572 return true;
2573 }
2574 *Opc = Accumulate ? ARM::SMLAWT : ARM::SMULWT;
2575 Src1 = SignExt.getOperand(0);
2576 return true;
2577}
2578
2579static bool SearchSignedMulLong(SDValue OR, unsigned *Opc, SDValue &Src0,
2580 SDValue &Src1, bool Accumulate) {
2581 // First we look for:
2582 // (add (or (srl ?, 16), (shl ?, 16)))
2583 if (OR.getOpcode() != ISD::OR)
2584 return false;
2585
2586 SDValue SRL = OR.getOperand(0);
2587 SDValue SHL = OR.getOperand(1);
2588
2589 if (SRL.getOpcode() != ISD::SRL || SHL.getOpcode() != ISD::SHL) {
2590 SRL = OR.getOperand(1);
2591 SHL = OR.getOperand(0);
2592 if (SRL.getOpcode() != ISD::SRL || SHL.getOpcode() != ISD::SHL)
2593 return false;
2594 }
2595
2596 ConstantSDNode *SRLSrc1 = dyn_cast<ConstantSDNode>(SRL.getOperand(1));
2597 ConstantSDNode *SHLSrc1 = dyn_cast<ConstantSDNode>(SHL.getOperand(1));
2598 if (!SRLSrc1 || !SHLSrc1 || SRLSrc1->getZExtValue() != 16 ||
2599 SHLSrc1->getZExtValue() != 16)
2600 return false;
2601
2602 // The first operands to the shifts need to be the two results from the
2603 // same smul_lohi node.
2604 if ((SRL.getOperand(0).getNode() != SHL.getOperand(0).getNode()) ||
2605 SRL.getOperand(0).getOpcode() != ISD::SMUL_LOHI)
2606 return false;
2607
2608 SDNode *SMULLOHI = SRL.getOperand(0).getNode();
2609 if (SRL.getOperand(0) != SDValue(SMULLOHI, 0) ||
2610 SHL.getOperand(0) != SDValue(SMULLOHI, 1))
2611 return false;
2612
2613 // Now we have:
2614 // (add (or (srl (smul_lohi ?, ?), 16), (shl (smul_lohi ?, ?), 16)))
2615 // For SMLAW[B|T] smul_lohi will take a 32-bit and a 16-bit arguments.
2616 // For SMLAWB the 16-bit value will signed extended somehow.
2617 // For SMLAWT only the SRA is required.
2618
2619 // Check both sides of SMUL_LOHI
2620 if (SearchSignedMulShort(SMULLOHI->getOperand(0), Opc, Src1, Accumulate)) {
2621 Src0 = SMULLOHI->getOperand(1);
2622 } else if (SearchSignedMulShort(SMULLOHI->getOperand(1), Opc, Src1,
2623 Accumulate)) {
2624 Src0 = SMULLOHI->getOperand(0);
2625 } else {
2626 return false;
2627 }
2628 return true;
2629}
2630
Justin Bogner45571362016-05-12 00:31:09 +00002631bool ARMDAGToDAGISel::trySMLAWSMULW(SDNode *N) {
Sam Parkerd5ca0a62016-07-25 10:11:00 +00002632 if (!Subtarget->hasV6Ops() ||
2633 (Subtarget->isThumb() && !Subtarget->hasThumb2()))
2634 return false;
2635
Sam Parker2d5126c2016-04-08 16:02:53 +00002636 SDLoc dl(N);
2637 SDValue Src0 = N->getOperand(0);
2638 SDValue Src1 = N->getOperand(1);
2639 SDValue A, B;
2640 unsigned Opc = 0;
2641
2642 if (N->getOpcode() == ISD::ADD) {
2643 if (Src0.getOpcode() != ISD::OR && Src1.getOpcode() != ISD::OR)
Justin Bogner45571362016-05-12 00:31:09 +00002644 return false;
Sam Parker2d5126c2016-04-08 16:02:53 +00002645
2646 SDValue Acc;
2647 if (SearchSignedMulLong(Src0, &Opc, A, B, true)) {
2648 Acc = Src1;
2649 } else if (SearchSignedMulLong(Src1, &Opc, A, B, true)) {
2650 Acc = Src0;
2651 } else {
Justin Bogner45571362016-05-12 00:31:09 +00002652 return false;
Sam Parker2d5126c2016-04-08 16:02:53 +00002653 }
2654 if (Opc == 0)
Justin Bogner45571362016-05-12 00:31:09 +00002655 return false;
Sam Parker2d5126c2016-04-08 16:02:53 +00002656
2657 SDValue Ops[] = { A, B, Acc, getAL(CurDAG, dl),
2658 CurDAG->getRegister(0, MVT::i32) };
Justin Bogner45571362016-05-12 00:31:09 +00002659 CurDAG->SelectNodeTo(N, Opc, MVT::i32, MVT::Other, Ops);
2660 return true;
Sam Parker2d5126c2016-04-08 16:02:53 +00002661 } else if (N->getOpcode() == ISD::OR &&
2662 SearchSignedMulLong(SDValue(N, 0), &Opc, A, B, false)) {
2663 if (Opc == 0)
Justin Bogner45571362016-05-12 00:31:09 +00002664 return false;
Sam Parker2d5126c2016-04-08 16:02:53 +00002665
2666 SDValue Ops[] = { A, B, getAL(CurDAG, dl),
2667 CurDAG->getRegister(0, MVT::i32)};
Justin Bogner45571362016-05-12 00:31:09 +00002668 CurDAG->SelectNodeTo(N, Opc, MVT::i32, Ops);
2669 return true;
Sam Parker2d5126c2016-04-08 16:02:53 +00002670 }
Justin Bogner45571362016-05-12 00:31:09 +00002671 return false;
Sam Parker2d5126c2016-04-08 16:02:53 +00002672}
2673
Tim Northoverb629c772016-04-18 21:48:55 +00002674/// We've got special pseudo-instructions for these
Justin Bogner45571362016-05-12 00:31:09 +00002675void ARMDAGToDAGISel::SelectCMP_SWAP(SDNode *N) {
Tim Northoverb629c772016-04-18 21:48:55 +00002676 unsigned Opcode;
2677 EVT MemTy = cast<MemSDNode>(N)->getMemoryVT();
2678 if (MemTy == MVT::i8)
2679 Opcode = ARM::CMP_SWAP_8;
2680 else if (MemTy == MVT::i16)
2681 Opcode = ARM::CMP_SWAP_16;
2682 else if (MemTy == MVT::i32)
2683 Opcode = ARM::CMP_SWAP_32;
2684 else
2685 llvm_unreachable("Unknown AtomicCmpSwap type");
2686
2687 SDValue Ops[] = {N->getOperand(1), N->getOperand(2), N->getOperand(3),
2688 N->getOperand(0)};
2689 SDNode *CmpSwap = CurDAG->getMachineNode(
2690 Opcode, SDLoc(N),
2691 CurDAG->getVTList(MVT::i32, MVT::i32, MVT::Other), Ops);
2692
2693 MachineSDNode::mmo_iterator MemOp = MF->allocateMemRefsArray(1);
2694 MemOp[0] = cast<MemSDNode>(N)->getMemOperand();
2695 cast<MachineSDNode>(CmpSwap)->setMemRefs(MemOp, MemOp + 1);
2696
2697 ReplaceUses(SDValue(N, 0), SDValue(CmpSwap, 0));
2698 ReplaceUses(SDValue(N, 1), SDValue(CmpSwap, 2));
Justin Bognered4f3782016-05-12 00:20:19 +00002699 CurDAG->RemoveDeadNode(N);
Tim Northoverb629c772016-04-18 21:48:55 +00002700}
2701
Justin Bogner45571362016-05-12 00:31:09 +00002702void ARMDAGToDAGISel::SelectConcatVector(SDNode *N) {
Evan Chengd85631e2010-05-05 18:28:36 +00002703 // The only time a CONCAT_VECTORS operation can have legal types is when
2704 // two 64-bit vectors are concatenated to a 128-bit vector.
2705 EVT VT = N->getValueType(0);
2706 if (!VT.is128BitVector() || N->getNumOperands() != 2)
2707 llvm_unreachable("unexpected CONCAT_VECTORS");
Justin Bogner45571362016-05-12 00:31:09 +00002708 ReplaceNode(N, createDRegPairNode(VT, N->getOperand(0), N->getOperand(1)));
Evan Chengd85631e2010-05-05 18:28:36 +00002709}
2710
Justin Bogner45571362016-05-12 00:31:09 +00002711void ARMDAGToDAGISel::Select(SDNode *N) {
Andrew Trickef9de2a2013-05-25 02:42:55 +00002712 SDLoc dl(N);
Evan Cheng10043e22007-01-19 07:51:42 +00002713
Tim Northover31d093c2013-09-22 08:21:56 +00002714 if (N->isMachineOpcode()) {
2715 N->setNodeId(-1);
Justin Bogner45571362016-05-12 00:31:09 +00002716 return; // Already selected.
Tim Northover31d093c2013-09-22 08:21:56 +00002717 }
Rafael Espindola4e760152006-06-12 12:28:08 +00002718
2719 switch (N->getOpcode()) {
Evan Cheng10043e22007-01-19 07:51:42 +00002720 default: break;
Sam Parker2d5126c2016-04-08 16:02:53 +00002721 case ISD::ADD:
Justin Bogner45571362016-05-12 00:31:09 +00002722 case ISD::OR:
2723 if (trySMLAWSMULW(N))
2724 return;
Sam Parker2d5126c2016-04-08 16:02:53 +00002725 break;
Justin Bogner45571362016-05-12 00:31:09 +00002726 case ISD::WRITE_REGISTER:
2727 if (tryWriteRegister(N))
2728 return;
Luke Cheeseman85fd06d2015-06-01 12:02:47 +00002729 break;
Justin Bogner45571362016-05-12 00:31:09 +00002730 case ISD::READ_REGISTER:
2731 if (tryReadRegister(N))
2732 return;
Luke Cheeseman85fd06d2015-06-01 12:02:47 +00002733 break;
Justin Bogner45571362016-05-12 00:31:09 +00002734 case ISD::INLINEASM:
2735 if (tryInlineAsm(N))
2736 return;
Weiming Zhaoc5987002013-02-14 18:10:21 +00002737 break;
Justin Bogner45571362016-05-12 00:31:09 +00002738 case ISD::XOR:
Bill Wendlinga7d697e2011-10-10 22:59:55 +00002739 // Select special operations if XOR node forms integer ABS pattern
Justin Bogner45571362016-05-12 00:31:09 +00002740 if (tryABSOp(N))
2741 return;
Bill Wendlinga7d697e2011-10-10 22:59:55 +00002742 // Other cases are autogenerated.
2743 break;
Evan Cheng10043e22007-01-19 07:51:42 +00002744 case ISD::Constant: {
Dan Gohmaneffb8942008-09-12 16:56:44 +00002745 unsigned Val = cast<ConstantSDNode>(N)->getZExtValue();
John Brawn056e6782015-09-14 15:19:41 +00002746 // If we can't materialize the constant we need to use a literal pool
2747 if (ConstantMaterializationCost(Val) > 2) {
Eric Christopherb17140d2014-10-08 07:32:17 +00002748 SDValue CPIdx = CurDAG->getTargetConstantPool(
2749 ConstantInt::get(Type::getInt32Ty(*CurDAG->getContext()), Val),
Mehdi Amini44ede332015-07-09 02:09:04 +00002750 TLI->getPointerTy(CurDAG->getDataLayout()));
Evan Cheng1526ba52007-01-24 08:53:17 +00002751
2752 SDNode *ResNode;
Tim Northover55c625f2014-01-23 13:43:47 +00002753 if (Subtarget->isThumb()) {
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00002754 SDValue Pred = getAL(CurDAG, dl);
Owen Anderson9f944592009-08-11 20:47:22 +00002755 SDValue PredReg = CurDAG->getRegister(0, MVT::i32);
Evan Chengcd4cdd12009-07-11 06:43:01 +00002756 SDValue Ops[] = { CPIdx, Pred, PredReg, CurDAG->getEntryNode() };
Jim Grosbachbfef3092010-12-15 23:52:36 +00002757 ResNode = CurDAG->getMachineNode(ARM::tLDRpci, dl, MVT::i32, MVT::Other,
Michael Liaob53d8962013-04-19 22:22:57 +00002758 Ops);
Evan Chengcd4cdd12009-07-11 06:43:01 +00002759 } else {
Dan Gohman2ce6f2a2008-07-27 21:46:04 +00002760 SDValue Ops[] = {
Jim Grosbachf24f9d92009-08-11 15:33:49 +00002761 CPIdx,
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00002762 CurDAG->getTargetConstant(0, dl, MVT::i32),
2763 getAL(CurDAG, dl),
Owen Anderson9f944592009-08-11 20:47:22 +00002764 CurDAG->getRegister(0, MVT::i32),
Evan Cheng1526ba52007-01-24 08:53:17 +00002765 CurDAG->getEntryNode()
2766 };
Justin Bogner45571362016-05-12 00:31:09 +00002767 ResNode = CurDAG->getMachineNode(ARM::LDRcp, dl, MVT::i32, MVT::Other,
2768 Ops);
Evan Cheng1526ba52007-01-24 08:53:17 +00002769 }
Justin Bognered4f3782016-05-12 00:20:19 +00002770 ReplaceNode(N, ResNode);
Justin Bogner45571362016-05-12 00:31:09 +00002771 return;
Evan Cheng10043e22007-01-19 07:51:42 +00002772 }
Jim Grosbachf24f9d92009-08-11 15:33:49 +00002773
Evan Cheng10043e22007-01-19 07:51:42 +00002774 // Other cases are autogenerated.
Rafael Espindola4e760152006-06-12 12:28:08 +00002775 break;
Evan Cheng10043e22007-01-19 07:51:42 +00002776 }
Rafael Espindola5f7ab1b2006-11-09 13:58:55 +00002777 case ISD::FrameIndex: {
Evan Cheng10043e22007-01-19 07:51:42 +00002778 // Selects to ADDri FI, 0 which in turn will become ADDri SP, imm.
Rafael Espindola5f7ab1b2006-11-09 13:58:55 +00002779 int FI = cast<FrameIndexSDNode>(N)->getIndex();
Mehdi Amini44ede332015-07-09 02:09:04 +00002780 SDValue TFI = CurDAG->getTargetFrameIndex(
2781 FI, TLI->getPointerTy(CurDAG->getDataLayout()));
David Goodwin22c2fba2009-07-08 23:10:31 +00002782 if (Subtarget->isThumb1Only()) {
Renato Golinb9887ef2015-02-25 14:41:06 +00002783 // Set the alignment of the frame object to 4, to avoid having to generate
2784 // more than one ADD
Matthias Braun941a7052016-07-28 18:40:00 +00002785 MachineFrameInfo &MFI = MF->getFrameInfo();
2786 if (MFI.getObjectAlignment(FI) < 4)
2787 MFI.setObjectAlignment(FI, 4);
Justin Bogner45571362016-05-12 00:31:09 +00002788 CurDAG->SelectNodeTo(N, ARM::tADDframe, MVT::i32, TFI,
2789 CurDAG->getTargetConstant(0, dl, MVT::i32));
2790 return;
Jim Grosbachfde21102009-04-07 20:34:09 +00002791 } else {
David Goodwin4ad77972009-07-14 18:48:51 +00002792 unsigned Opc = ((Subtarget->isThumb() && Subtarget->hasThumb2()) ?
2793 ARM::t2ADDri : ARM::ADDri);
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00002794 SDValue Ops[] = { TFI, CurDAG->getTargetConstant(0, dl, MVT::i32),
2795 getAL(CurDAG, dl), CurDAG->getRegister(0, MVT::i32),
Owen Anderson9f944592009-08-11 20:47:22 +00002796 CurDAG->getRegister(0, MVT::i32) };
Justin Bogner45571362016-05-12 00:31:09 +00002797 CurDAG->SelectNodeTo(N, Opc, MVT::i32, Ops);
2798 return;
Evan Cheng7e90b112007-07-05 07:15:27 +00002799 }
Evan Cheng10043e22007-01-19 07:51:42 +00002800 }
Sandeep Patel423e42b2009-10-13 18:59:48 +00002801 case ISD::SRL:
Justin Bogner45571362016-05-12 00:31:09 +00002802 if (tryV6T2BitfieldExtractOp(N, false))
2803 return;
Sandeep Patel423e42b2009-10-13 18:59:48 +00002804 break;
Tim Northover14ff2df2014-07-23 13:59:12 +00002805 case ISD::SIGN_EXTEND_INREG:
Sandeep Patel423e42b2009-10-13 18:59:48 +00002806 case ISD::SRA:
Justin Bogner45571362016-05-12 00:31:09 +00002807 if (tryV6T2BitfieldExtractOp(N, true))
2808 return;
Sandeep Patel423e42b2009-10-13 18:59:48 +00002809 break;
Evan Cheng10043e22007-01-19 07:51:42 +00002810 case ISD::MUL:
Evan Chengb24e51e2009-07-07 01:17:28 +00002811 if (Subtarget->isThumb1Only())
Evan Cheng139edae2007-01-24 02:21:22 +00002812 break;
Dan Gohmanea6f91f2010-01-05 01:24:18 +00002813 if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(N->getOperand(1))) {
Dan Gohmaneffb8942008-09-12 16:56:44 +00002814 unsigned RHSV = C->getZExtValue();
Evan Cheng10043e22007-01-19 07:51:42 +00002815 if (!RHSV) break;
2816 if (isPowerOf2_32(RHSV-1)) { // 2^n+1?
Evan Cheng0d8b0cf2009-07-21 00:31:12 +00002817 unsigned ShImm = Log2_32(RHSV-1);
2818 if (ShImm >= 32)
2819 break;
Dan Gohmanea6f91f2010-01-05 01:24:18 +00002820 SDValue V = N->getOperand(0);
Evan Cheng0d8b0cf2009-07-21 00:31:12 +00002821 ShImm = ARM_AM::getSORegOpc(ARM_AM::lsl, ShImm);
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00002822 SDValue ShImmOp = CurDAG->getTargetConstant(ShImm, dl, MVT::i32);
Owen Anderson9f944592009-08-11 20:47:22 +00002823 SDValue Reg0 = CurDAG->getRegister(0, MVT::i32);
Evan Cheng1ec43962009-07-22 18:08:05 +00002824 if (Subtarget->isThumb()) {
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00002825 SDValue Ops[] = { V, V, ShImmOp, getAL(CurDAG, dl), Reg0, Reg0 };
Justin Bogner45571362016-05-12 00:31:09 +00002826 CurDAG->SelectNodeTo(N, ARM::t2ADDrs, MVT::i32, Ops);
2827 return;
Evan Cheng0d8b0cf2009-07-21 00:31:12 +00002828 } else {
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00002829 SDValue Ops[] = { V, V, Reg0, ShImmOp, getAL(CurDAG, dl), Reg0,
2830 Reg0 };
Justin Bogner45571362016-05-12 00:31:09 +00002831 CurDAG->SelectNodeTo(N, ARM::ADDrsi, MVT::i32, Ops);
2832 return;
Evan Cheng0d8b0cf2009-07-21 00:31:12 +00002833 }
Evan Cheng10043e22007-01-19 07:51:42 +00002834 }
2835 if (isPowerOf2_32(RHSV+1)) { // 2^n-1?
Evan Cheng0d8b0cf2009-07-21 00:31:12 +00002836 unsigned ShImm = Log2_32(RHSV+1);
2837 if (ShImm >= 32)
2838 break;
Dan Gohmanea6f91f2010-01-05 01:24:18 +00002839 SDValue V = N->getOperand(0);
Evan Cheng0d8b0cf2009-07-21 00:31:12 +00002840 ShImm = ARM_AM::getSORegOpc(ARM_AM::lsl, ShImm);
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00002841 SDValue ShImmOp = CurDAG->getTargetConstant(ShImm, dl, MVT::i32);
Owen Anderson9f944592009-08-11 20:47:22 +00002842 SDValue Reg0 = CurDAG->getRegister(0, MVT::i32);
Evan Cheng1ec43962009-07-22 18:08:05 +00002843 if (Subtarget->isThumb()) {
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00002844 SDValue Ops[] = { V, V, ShImmOp, getAL(CurDAG, dl), Reg0, Reg0 };
Justin Bogner45571362016-05-12 00:31:09 +00002845 CurDAG->SelectNodeTo(N, ARM::t2RSBrs, MVT::i32, Ops);
2846 return;
Evan Cheng0d8b0cf2009-07-21 00:31:12 +00002847 } else {
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00002848 SDValue Ops[] = { V, V, Reg0, ShImmOp, getAL(CurDAG, dl), Reg0,
2849 Reg0 };
Justin Bogner45571362016-05-12 00:31:09 +00002850 CurDAG->SelectNodeTo(N, ARM::RSBrsi, MVT::i32, Ops);
2851 return;
Evan Cheng0d8b0cf2009-07-21 00:31:12 +00002852 }
Evan Cheng10043e22007-01-19 07:51:42 +00002853 }
2854 }
2855 break;
Evan Cheng786b15f2009-10-21 08:15:52 +00002856 case ISD::AND: {
Jim Grosbach825cb292010-04-22 23:24:18 +00002857 // Check for unsigned bitfield extract
Justin Bogner45571362016-05-12 00:31:09 +00002858 if (tryV6T2BitfieldExtractOp(N, false))
2859 return;
Jim Grosbach825cb292010-04-22 23:24:18 +00002860
James Molloyae5ff992016-07-05 12:37:13 +00002861 // If an immediate is used in an AND node, it is possible that the immediate
2862 // can be more optimally materialized when negated. If this is the case we
2863 // can negate the immediate and use a BIC instead.
2864 auto *N1C = dyn_cast<ConstantSDNode>(N->getOperand(1));
2865 if (N1C && N1C->hasOneUse() && Subtarget->isThumb()) {
2866 uint32_t Imm = (uint32_t) N1C->getZExtValue();
2867
2868 // In Thumb2 mode, an AND can take a 12-bit immediate. If this
2869 // immediate can be negated and fit in the immediate operand of
2870 // a t2BIC, don't do any manual transform here as this can be
2871 // handled by the generic ISel machinery.
2872 bool PreferImmediateEncoding =
2873 Subtarget->hasThumb2() && (is_t2_so_imm(Imm) || is_t2_so_imm_not(Imm));
2874 if (!PreferImmediateEncoding &&
2875 ConstantMaterializationCost(Imm) >
2876 ConstantMaterializationCost(~Imm)) {
2877 // The current immediate costs more to materialize than a negated
2878 // immediate, so negate the immediate and use a BIC.
2879 SDValue NewImm =
2880 CurDAG->getConstant(~N1C->getZExtValue(), dl, MVT::i32);
2881 // If the new constant didn't exist before, reposition it in the topological
2882 // ordering so it is just before N. Otherwise, don't touch its location.
2883 if (NewImm->getNodeId() == -1)
2884 CurDAG->RepositionNode(N->getIterator(), NewImm.getNode());
2885
2886 if (!Subtarget->hasThumb2()) {
2887 SDValue Ops[] = {CurDAG->getRegister(ARM::CPSR, MVT::i32),
2888 N->getOperand(0), NewImm, getAL(CurDAG, dl),
2889 CurDAG->getRegister(0, MVT::i32)};
2890 ReplaceNode(N, CurDAG->getMachineNode(ARM::tBIC, dl, MVT::i32, Ops));
2891 return;
2892 } else {
2893 SDValue Ops[] = {N->getOperand(0), NewImm, getAL(CurDAG, dl),
2894 CurDAG->getRegister(0, MVT::i32),
2895 CurDAG->getRegister(0, MVT::i32)};
2896 ReplaceNode(N,
2897 CurDAG->getMachineNode(ARM::t2BICrr, dl, MVT::i32, Ops));
2898 return;
2899 }
2900 }
2901 }
2902
Evan Cheng786b15f2009-10-21 08:15:52 +00002903 // (and (or x, c2), c1) and top 16-bits of c1 and c2 match, lower 16-bits
2904 // of c1 are 0xffff, and lower 16-bit of c2 are 0. That is, the top 16-bits
2905 // are entirely contributed by c2 and lower 16-bits are entirely contributed
2906 // by x. That's equal to (or (and x, 0xffff), (and c1, 0xffff0000)).
2907 // Select it to: "movt x, ((c1 & 0xffff) >> 16)
Dan Gohmanea6f91f2010-01-05 01:24:18 +00002908 EVT VT = N->getValueType(0);
Evan Cheng786b15f2009-10-21 08:15:52 +00002909 if (VT != MVT::i32)
2910 break;
2911 unsigned Opc = (Subtarget->isThumb() && Subtarget->hasThumb2())
2912 ? ARM::t2MOVTi16
2913 : (Subtarget->hasV6T2Ops() ? ARM::MOVTi16 : 0);
2914 if (!Opc)
2915 break;
Dan Gohmanea6f91f2010-01-05 01:24:18 +00002916 SDValue N0 = N->getOperand(0), N1 = N->getOperand(1);
James Molloyae5ff992016-07-05 12:37:13 +00002917 N1C = dyn_cast<ConstantSDNode>(N1);
Evan Cheng786b15f2009-10-21 08:15:52 +00002918 if (!N1C)
2919 break;
2920 if (N0.getOpcode() == ISD::OR && N0.getNode()->hasOneUse()) {
2921 SDValue N2 = N0.getOperand(1);
2922 ConstantSDNode *N2C = dyn_cast<ConstantSDNode>(N2);
2923 if (!N2C)
2924 break;
2925 unsigned N1CVal = N1C->getZExtValue();
2926 unsigned N2CVal = N2C->getZExtValue();
2927 if ((N1CVal & 0xffff0000U) == (N2CVal & 0xffff0000U) &&
2928 (N1CVal & 0xffffU) == 0xffffU &&
2929 (N2CVal & 0xffffU) == 0x0U) {
2930 SDValue Imm16 = CurDAG->getTargetConstant((N2CVal & 0xFFFF0000U) >> 16,
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00002931 dl, MVT::i32);
Evan Cheng786b15f2009-10-21 08:15:52 +00002932 SDValue Ops[] = { N0.getOperand(0), Imm16,
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00002933 getAL(CurDAG, dl), CurDAG->getRegister(0, MVT::i32) };
Justin Bogner45571362016-05-12 00:31:09 +00002934 ReplaceNode(N, CurDAG->getMachineNode(Opc, dl, VT, Ops));
2935 return;
Evan Cheng786b15f2009-10-21 08:15:52 +00002936 }
2937 }
2938 break;
2939 }
Jim Grosbachd7cf55c2009-11-09 00:11:35 +00002940 case ARMISD::VMOVRRD:
Justin Bogner45571362016-05-12 00:31:09 +00002941 ReplaceNode(N, CurDAG->getMachineNode(ARM::VMOVRRD, dl, MVT::i32, MVT::i32,
2942 N->getOperand(0), getAL(CurDAG, dl),
2943 CurDAG->getRegister(0, MVT::i32)));
2944 return;
Dan Gohmana1603612007-10-08 18:33:35 +00002945 case ISD::UMUL_LOHI: {
Evan Chengb24e51e2009-07-07 01:17:28 +00002946 if (Subtarget->isThumb1Only())
2947 break;
2948 if (Subtarget->isThumb()) {
Dan Gohmanea6f91f2010-01-05 01:24:18 +00002949 SDValue Ops[] = { N->getOperand(0), N->getOperand(1),
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00002950 getAL(CurDAG, dl), CurDAG->getRegister(0, MVT::i32) };
Justin Bogner45571362016-05-12 00:31:09 +00002951 ReplaceNode(
2952 N, CurDAG->getMachineNode(ARM::t2UMULL, dl, MVT::i32, MVT::i32, Ops));
2953 return;
Evan Chengb24e51e2009-07-07 01:17:28 +00002954 } else {
Dan Gohmanea6f91f2010-01-05 01:24:18 +00002955 SDValue Ops[] = { N->getOperand(0), N->getOperand(1),
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00002956 getAL(CurDAG, dl), CurDAG->getRegister(0, MVT::i32),
Owen Anderson9f944592009-08-11 20:47:22 +00002957 CurDAG->getRegister(0, MVT::i32) };
Justin Bogner45571362016-05-12 00:31:09 +00002958 ReplaceNode(N, CurDAG->getMachineNode(
2959 Subtarget->hasV6Ops() ? ARM::UMULL : ARM::UMULLv5, dl,
2960 MVT::i32, MVT::i32, Ops));
2961 return;
Evan Chengb24e51e2009-07-07 01:17:28 +00002962 }
Evan Cheng7e90b112007-07-05 07:15:27 +00002963 }
Dan Gohmana1603612007-10-08 18:33:35 +00002964 case ISD::SMUL_LOHI: {
Evan Chengb24e51e2009-07-07 01:17:28 +00002965 if (Subtarget->isThumb1Only())
2966 break;
2967 if (Subtarget->isThumb()) {
Dan Gohmanea6f91f2010-01-05 01:24:18 +00002968 SDValue Ops[] = { N->getOperand(0), N->getOperand(1),
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00002969 getAL(CurDAG, dl), CurDAG->getRegister(0, MVT::i32) };
Justin Bogner45571362016-05-12 00:31:09 +00002970 ReplaceNode(
2971 N, CurDAG->getMachineNode(ARM::t2SMULL, dl, MVT::i32, MVT::i32, Ops));
2972 return;
Evan Chengb24e51e2009-07-07 01:17:28 +00002973 } else {
Dan Gohmanea6f91f2010-01-05 01:24:18 +00002974 SDValue Ops[] = { N->getOperand(0), N->getOperand(1),
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00002975 getAL(CurDAG, dl), CurDAG->getRegister(0, MVT::i32),
Owen Anderson9f944592009-08-11 20:47:22 +00002976 CurDAG->getRegister(0, MVT::i32) };
Justin Bogner45571362016-05-12 00:31:09 +00002977 ReplaceNode(N, CurDAG->getMachineNode(
2978 Subtarget->hasV6Ops() ? ARM::SMULL : ARM::SMULLv5, dl,
2979 MVT::i32, MVT::i32, Ops));
2980 return;
Evan Chengb24e51e2009-07-07 01:17:28 +00002981 }
Evan Cheng7e90b112007-07-05 07:15:27 +00002982 }
Sam Parkerd616cf02016-06-20 16:47:09 +00002983 case ARMISD::UMAAL: {
2984 unsigned Opc = Subtarget->isThumb() ? ARM::t2UMAAL : ARM::UMAAL;
2985 SDValue Ops[] = { N->getOperand(0), N->getOperand(1),
2986 N->getOperand(2), N->getOperand(3),
2987 getAL(CurDAG, dl),
2988 CurDAG->getRegister(0, MVT::i32) };
2989 ReplaceNode(N, CurDAG->getMachineNode(Opc, dl, MVT::i32, MVT::i32, Ops));
2990 return;
2991 }
Arnold Schwaighoferf00fb1c2012-09-04 14:37:49 +00002992 case ARMISD::UMLAL:{
Sam Parkerd616cf02016-06-20 16:47:09 +00002993 // UMAAL is similar to UMLAL but it adds two 32-bit values to the
2994 // 64-bit multiplication result.
Sam Parkere7d95052016-10-27 09:47:10 +00002995 if (Subtarget->hasV6Ops() && Subtarget->hasDSP() &&
2996 N->getOperand(2).getOpcode() == ARMISD::ADDC &&
Sam Parkerd616cf02016-06-20 16:47:09 +00002997 N->getOperand(3).getOpcode() == ARMISD::ADDE) {
2998
2999 SDValue Addc = N->getOperand(2);
3000 SDValue Adde = N->getOperand(3);
3001
3002 if (Adde.getOperand(2).getNode() == Addc.getNode()) {
3003
3004 ConstantSDNode *Op0 = dyn_cast<ConstantSDNode>(Adde.getOperand(0));
3005 ConstantSDNode *Op1 = dyn_cast<ConstantSDNode>(Adde.getOperand(1));
3006
3007 if (Op0 && Op1 && Op0->getZExtValue() == 0 && Op1->getZExtValue() == 0)
3008 {
3009 // Select UMAAL instead: UMAAL RdLo, RdHi, Rn, Rm
3010 // RdLo = one operand to be added, lower 32-bits of res
3011 // RdHi = other operand to be added, upper 32-bits of res
3012 // Rn = first multiply operand
3013 // Rm = second multiply operand
3014 SDValue Ops[] = { N->getOperand(0), N->getOperand(1),
3015 Addc.getOperand(0), Addc.getOperand(1),
3016 getAL(CurDAG, dl),
3017 CurDAG->getRegister(0, MVT::i32) };
3018 unsigned opc = Subtarget->isThumb() ? ARM::t2UMAAL : ARM::UMAAL;
3019 CurDAG->SelectNodeTo(N, opc, MVT::i32, MVT::i32, Ops);
3020 return;
3021 }
3022 }
3023 }
3024
Arnold Schwaighoferf00fb1c2012-09-04 14:37:49 +00003025 if (Subtarget->isThumb()) {
3026 SDValue Ops[] = { N->getOperand(0), N->getOperand(1), N->getOperand(2),
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00003027 N->getOperand(3), getAL(CurDAG, dl),
Arnold Schwaighoferf00fb1c2012-09-04 14:37:49 +00003028 CurDAG->getRegister(0, MVT::i32)};
Justin Bogner45571362016-05-12 00:31:09 +00003029 ReplaceNode(
3030 N, CurDAG->getMachineNode(ARM::t2UMLAL, dl, MVT::i32, MVT::i32, Ops));
3031 return;
Arnold Schwaighoferf00fb1c2012-09-04 14:37:49 +00003032 }else{
3033 SDValue Ops[] = { N->getOperand(0), N->getOperand(1), N->getOperand(2),
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00003034 N->getOperand(3), getAL(CurDAG, dl),
Arnold Schwaighoferf00fb1c2012-09-04 14:37:49 +00003035 CurDAG->getRegister(0, MVT::i32),
3036 CurDAG->getRegister(0, MVT::i32) };
Justin Bogner45571362016-05-12 00:31:09 +00003037 ReplaceNode(N, CurDAG->getMachineNode(
3038 Subtarget->hasV6Ops() ? ARM::UMLAL : ARM::UMLALv5, dl,
3039 MVT::i32, MVT::i32, Ops));
3040 return;
Arnold Schwaighoferf00fb1c2012-09-04 14:37:49 +00003041 }
3042 }
3043 case ARMISD::SMLAL:{
3044 if (Subtarget->isThumb()) {
3045 SDValue Ops[] = { N->getOperand(0), N->getOperand(1), N->getOperand(2),
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00003046 N->getOperand(3), getAL(CurDAG, dl),
Arnold Schwaighoferf00fb1c2012-09-04 14:37:49 +00003047 CurDAG->getRegister(0, MVT::i32)};
Justin Bogner45571362016-05-12 00:31:09 +00003048 ReplaceNode(
3049 N, CurDAG->getMachineNode(ARM::t2SMLAL, dl, MVT::i32, MVT::i32, Ops));
3050 return;
Arnold Schwaighoferf00fb1c2012-09-04 14:37:49 +00003051 }else{
3052 SDValue Ops[] = { N->getOperand(0), N->getOperand(1), N->getOperand(2),
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00003053 N->getOperand(3), getAL(CurDAG, dl),
Arnold Schwaighoferf00fb1c2012-09-04 14:37:49 +00003054 CurDAG->getRegister(0, MVT::i32),
3055 CurDAG->getRegister(0, MVT::i32) };
Justin Bogner45571362016-05-12 00:31:09 +00003056 ReplaceNode(N, CurDAG->getMachineNode(
3057 Subtarget->hasV6Ops() ? ARM::SMLAL : ARM::SMLALv5, dl,
3058 MVT::i32, MVT::i32, Ops));
3059 return;
Arnold Schwaighoferf00fb1c2012-09-04 14:37:49 +00003060 }
3061 }
Sam Parker68c71cd2016-07-25 09:20:20 +00003062 case ARMISD::SUBE: {
3063 if (!Subtarget->hasV6Ops())
3064 break;
3065 // Look for a pattern to match SMMLS
3066 // (sube a, (smul_loHi a, b), (subc 0, (smul_LOhi(a, b))))
3067 if (N->getOperand(1).getOpcode() != ISD::SMUL_LOHI ||
Tim Northover765777c2016-08-02 23:12:36 +00003068 N->getOperand(2).getOpcode() != ARMISD::SUBC ||
3069 !SDValue(N, 1).use_empty())
Sam Parker68c71cd2016-07-25 09:20:20 +00003070 break;
3071
3072 if (Subtarget->isThumb())
3073 assert(Subtarget->hasThumb2() &&
3074 "This pattern should not be generated for Thumb");
3075
3076 SDValue SmulLoHi = N->getOperand(1);
3077 SDValue Subc = N->getOperand(2);
3078 auto *Zero = dyn_cast<ConstantSDNode>(Subc.getOperand(0));
3079
3080 if (!Zero || Zero->getZExtValue() != 0 ||
3081 Subc.getOperand(1) != SmulLoHi.getValue(0) ||
3082 N->getOperand(1) != SmulLoHi.getValue(1) ||
3083 N->getOperand(2) != Subc.getValue(1))
3084 break;
3085
3086 unsigned Opc = Subtarget->isThumb2() ? ARM::t2SMMLS : ARM::SMMLS;
3087 SDValue Ops[] = { SmulLoHi.getOperand(0), SmulLoHi.getOperand(1),
3088 N->getOperand(0), getAL(CurDAG, dl),
3089 CurDAG->getRegister(0, MVT::i32) };
3090 ReplaceNode(N, CurDAG->getMachineNode(Opc, dl, MVT::i32, Ops));
3091 return;
3092 }
Evan Cheng10043e22007-01-19 07:51:42 +00003093 case ISD::LOAD: {
Justin Bogner45571362016-05-12 00:31:09 +00003094 if (Subtarget->isThumb() && Subtarget->hasThumb2()) {
3095 if (tryT2IndexedLoad(N))
3096 return;
James Molloyb3326df2016-07-15 08:03:56 +00003097 } else if (Subtarget->isThumb()) {
3098 if (tryT1IndexedLoad(N))
3099 return;
Justin Bogner45571362016-05-12 00:31:09 +00003100 } else if (tryARMIndexedLoad(N))
3101 return;
Evan Cheng10043e22007-01-19 07:51:42 +00003102 // Other cases are autogenerated.
Rafael Espindola5f7ab1b2006-11-09 13:58:55 +00003103 break;
Rafael Espindola4e760152006-06-12 12:28:08 +00003104 }
Evan Cheng7e90b112007-07-05 07:15:27 +00003105 case ARMISD::BRCOND: {
3106 // Pattern: (ARMbrcond:void (bb:Other):$dst, (imm:i32):$cc)
3107 // Emits: (Bcc:void (bb:Other):$dst, (imm:i32):$cc)
3108 // Pattern complexity = 6 cost = 1 size = 0
Rafael Espindolaffdc24b2006-05-14 22:18:28 +00003109
Evan Cheng7e90b112007-07-05 07:15:27 +00003110 // Pattern: (ARMbrcond:void (bb:Other):$dst, (imm:i32):$cc)
3111 // Emits: (tBcc:void (bb:Other):$dst, (imm:i32):$cc)
3112 // Pattern complexity = 6 cost = 1 size = 0
3113
David Goodwin27303cd2009-06-30 18:04:13 +00003114 // Pattern: (ARMbrcond:void (bb:Other):$dst, (imm:i32):$cc)
3115 // Emits: (t2Bcc:void (bb:Other):$dst, (imm:i32):$cc)
3116 // Pattern complexity = 6 cost = 1 size = 0
3117
Jim Grosbachf24f9d92009-08-11 15:33:49 +00003118 unsigned Opc = Subtarget->isThumb() ?
David Goodwin27303cd2009-06-30 18:04:13 +00003119 ((Subtarget->hasThumb2()) ? ARM::t2Bcc : ARM::tBcc) : ARM::Bcc;
Dan Gohmanea6f91f2010-01-05 01:24:18 +00003120 SDValue Chain = N->getOperand(0);
3121 SDValue N1 = N->getOperand(1);
3122 SDValue N2 = N->getOperand(2);
3123 SDValue N3 = N->getOperand(3);
3124 SDValue InFlag = N->getOperand(4);
Evan Cheng7e90b112007-07-05 07:15:27 +00003125 assert(N1.getOpcode() == ISD::BasicBlock);
3126 assert(N2.getOpcode() == ISD::Constant);
3127 assert(N3.getOpcode() == ISD::Register);
3128
James Molloye7d97362016-11-03 14:08:01 +00003129 SDValue Tmp2 = CurDAG->getTargetConstant(((unsigned)
3130 cast<ConstantSDNode>(N2)->getZExtValue()), dl,
3131 MVT::i32);
Dan Gohman2ce6f2a2008-07-27 21:46:04 +00003132 SDValue Ops[] = { N1, Tmp2, N3, Chain, InFlag };
Dan Gohman32f71d72009-09-25 18:54:59 +00003133 SDNode *ResNode = CurDAG->getMachineNode(Opc, dl, MVT::Other,
Michael Liaob53d8962013-04-19 22:22:57 +00003134 MVT::Glue, Ops);
Dan Gohman2ce6f2a2008-07-27 21:46:04 +00003135 Chain = SDValue(ResNode, 0);
Dan Gohmanea6f91f2010-01-05 01:24:18 +00003136 if (N->getNumValues() == 2) {
Dan Gohman2ce6f2a2008-07-27 21:46:04 +00003137 InFlag = SDValue(ResNode, 1);
Dan Gohmanea6f91f2010-01-05 01:24:18 +00003138 ReplaceUses(SDValue(N, 1), InFlag);
Chris Lattnere99faac2008-02-03 03:20:59 +00003139 }
Dan Gohmanea6f91f2010-01-05 01:24:18 +00003140 ReplaceUses(SDValue(N, 0),
Evan Cheng82adca82009-11-19 08:16:50 +00003141 SDValue(Chain.getNode(), Chain.getResNo()));
Justin Bognered4f3782016-05-12 00:20:19 +00003142 CurDAG->RemoveDeadNode(N);
Justin Bogner45571362016-05-12 00:31:09 +00003143 return;
Evan Cheng7e90b112007-07-05 07:15:27 +00003144 }
James Molloy4d86bed2016-09-09 12:52:24 +00003145
3146 case ARMISD::CMPZ: {
3147 // select (CMPZ X, #-C) -> (CMPZ (ADDS X, #C), #0)
3148 // This allows us to avoid materializing the expensive negative constant.
3149 // The CMPZ #0 is useless and will be peepholed away but we need to keep it
3150 // for its glue output.
3151 SDValue X = N->getOperand(0);
3152 auto *C = dyn_cast<ConstantSDNode>(N->getOperand(1).getNode());
3153 if (C && C->getSExtValue() < 0 && Subtarget->isThumb()) {
3154 int64_t Addend = -C->getSExtValue();
3155
3156 SDNode *Add = nullptr;
3157 // In T2 mode, ADDS can be better than CMN if the immediate fits in a
3158 // 16-bit ADDS, which means either [0,256) for tADDi8 or [0,8) for tADDi3.
3159 // Outside that range we can just use a CMN which is 32-bit but has a
3160 // 12-bit immediate range.
3161 if (Subtarget->isThumb2() && Addend < 1<<8) {
3162 SDValue Ops[] = { X, CurDAG->getTargetConstant(Addend, dl, MVT::i32),
3163 getAL(CurDAG, dl), CurDAG->getRegister(0, MVT::i32),
3164 CurDAG->getRegister(0, MVT::i32) };
3165 Add = CurDAG->getMachineNode(ARM::t2ADDri, dl, MVT::i32, Ops);
3166 } else if (!Subtarget->isThumb2() && Addend < 1<<8) {
3167 // FIXME: Add T1 tADDi8 code.
3168 SDValue Ops[] = {CurDAG->getRegister(ARM::CPSR, MVT::i32), X,
3169 CurDAG->getTargetConstant(Addend, dl, MVT::i32),
3170 getAL(CurDAG, dl), CurDAG->getRegister(0, MVT::i32)};
3171 Add = CurDAG->getMachineNode(ARM::tADDi8, dl, MVT::i32, Ops);
3172 } else if (!Subtarget->isThumb2() && Addend < 1<<3) {
3173 SDValue Ops[] = {CurDAG->getRegister(ARM::CPSR, MVT::i32), X,
3174 CurDAG->getTargetConstant(Addend, dl, MVT::i32),
3175 getAL(CurDAG, dl), CurDAG->getRegister(0, MVT::i32)};
3176 Add = CurDAG->getMachineNode(ARM::tADDi3, dl, MVT::i32, Ops);
3177 }
3178 if (Add) {
3179 SDValue Ops2[] = {SDValue(Add, 0), CurDAG->getConstant(0, dl, MVT::i32)};
3180 CurDAG->MorphNodeTo(N, ARMISD::CMPZ, CurDAG->getVTList(MVT::Glue), Ops2);
3181 }
3182 }
3183 // Other cases are autogenerated.
3184 break;
3185 }
3186
Anton Korobeynikov232b19c2009-08-21 12:41:42 +00003187 case ARMISD::VZIP: {
3188 unsigned Opc = 0;
Anton Korobeynikovce3ff1b2009-08-21 12:40:50 +00003189 EVT VT = N->getValueType(0);
Anton Korobeynikov232b19c2009-08-21 12:41:42 +00003190 switch (VT.getSimpleVT().SimpleTy) {
Justin Bogner45571362016-05-12 00:31:09 +00003191 default: return;
Anton Korobeynikov232b19c2009-08-21 12:41:42 +00003192 case MVT::v8i8: Opc = ARM::VZIPd8; break;
3193 case MVT::v4i16: Opc = ARM::VZIPd16; break;
3194 case MVT::v2f32:
Jim Grosbach4640c812012-04-11 16:53:25 +00003195 // vzip.32 Dd, Dm is a pseudo-instruction expanded to vtrn.32 Dd, Dm.
3196 case MVT::v2i32: Opc = ARM::VTRNd32; break;
Anton Korobeynikov232b19c2009-08-21 12:41:42 +00003197 case MVT::v16i8: Opc = ARM::VZIPq8; break;
3198 case MVT::v8i16: Opc = ARM::VZIPq16; break;
3199 case MVT::v4f32:
3200 case MVT::v4i32: Opc = ARM::VZIPq32; break;
3201 }
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00003202 SDValue Pred = getAL(CurDAG, dl);
Evan Chenga33fc862009-11-21 06:21:52 +00003203 SDValue PredReg = CurDAG->getRegister(0, MVT::i32);
3204 SDValue Ops[] = { N->getOperand(0), N->getOperand(1), Pred, PredReg };
Justin Bogner45571362016-05-12 00:31:09 +00003205 ReplaceNode(N, CurDAG->getMachineNode(Opc, dl, VT, VT, Ops));
3206 return;
Anton Korobeynikovce3ff1b2009-08-21 12:40:50 +00003207 }
Anton Korobeynikov232b19c2009-08-21 12:41:42 +00003208 case ARMISD::VUZP: {
3209 unsigned Opc = 0;
Anton Korobeynikovce3ff1b2009-08-21 12:40:50 +00003210 EVT VT = N->getValueType(0);
Anton Korobeynikov232b19c2009-08-21 12:41:42 +00003211 switch (VT.getSimpleVT().SimpleTy) {
Justin Bogner45571362016-05-12 00:31:09 +00003212 default: return;
Anton Korobeynikov232b19c2009-08-21 12:41:42 +00003213 case MVT::v8i8: Opc = ARM::VUZPd8; break;
3214 case MVT::v4i16: Opc = ARM::VUZPd16; break;
3215 case MVT::v2f32:
Jim Grosbach6e536de2012-04-11 17:40:18 +00003216 // vuzp.32 Dd, Dm is a pseudo-instruction expanded to vtrn.32 Dd, Dm.
3217 case MVT::v2i32: Opc = ARM::VTRNd32; break;
Anton Korobeynikov232b19c2009-08-21 12:41:42 +00003218 case MVT::v16i8: Opc = ARM::VUZPq8; break;
3219 case MVT::v8i16: Opc = ARM::VUZPq16; break;
3220 case MVT::v4f32:
3221 case MVT::v4i32: Opc = ARM::VUZPq32; break;
3222 }
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00003223 SDValue Pred = getAL(CurDAG, dl);
Evan Chenga33fc862009-11-21 06:21:52 +00003224 SDValue PredReg = CurDAG->getRegister(0, MVT::i32);
3225 SDValue Ops[] = { N->getOperand(0), N->getOperand(1), Pred, PredReg };
Justin Bogner45571362016-05-12 00:31:09 +00003226 ReplaceNode(N, CurDAG->getMachineNode(Opc, dl, VT, VT, Ops));
3227 return;
Anton Korobeynikovce3ff1b2009-08-21 12:40:50 +00003228 }
Anton Korobeynikov232b19c2009-08-21 12:41:42 +00003229 case ARMISD::VTRN: {
3230 unsigned Opc = 0;
Anton Korobeynikovce3ff1b2009-08-21 12:40:50 +00003231 EVT VT = N->getValueType(0);
Anton Korobeynikov232b19c2009-08-21 12:41:42 +00003232 switch (VT.getSimpleVT().SimpleTy) {
Justin Bogner45571362016-05-12 00:31:09 +00003233 default: return;
Anton Korobeynikov232b19c2009-08-21 12:41:42 +00003234 case MVT::v8i8: Opc = ARM::VTRNd8; break;
3235 case MVT::v4i16: Opc = ARM::VTRNd16; break;
3236 case MVT::v2f32:
3237 case MVT::v2i32: Opc = ARM::VTRNd32; break;
3238 case MVT::v16i8: Opc = ARM::VTRNq8; break;
3239 case MVT::v8i16: Opc = ARM::VTRNq16; break;
3240 case MVT::v4f32:
3241 case MVT::v4i32: Opc = ARM::VTRNq32; break;
3242 }
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00003243 SDValue Pred = getAL(CurDAG, dl);
Evan Chenga33fc862009-11-21 06:21:52 +00003244 SDValue PredReg = CurDAG->getRegister(0, MVT::i32);
3245 SDValue Ops[] = { N->getOperand(0), N->getOperand(1), Pred, PredReg };
Justin Bogner45571362016-05-12 00:31:09 +00003246 ReplaceNode(N, CurDAG->getMachineNode(Opc, dl, VT, VT, Ops));
3247 return;
Anton Korobeynikovce3ff1b2009-08-21 12:40:50 +00003248 }
Bob Wilsond8a9a042010-06-04 00:04:02 +00003249 case ARMISD::BUILD_VECTOR: {
3250 EVT VecVT = N->getValueType(0);
3251 EVT EltVT = VecVT.getVectorElementType();
3252 unsigned NumElts = VecVT.getVectorNumElements();
Duncan Sands14627772010-11-03 12:17:33 +00003253 if (EltVT == MVT::f64) {
Bob Wilsond8a9a042010-06-04 00:04:02 +00003254 assert(NumElts == 2 && "unexpected type for BUILD_VECTOR");
Justin Bogner45571362016-05-12 00:31:09 +00003255 ReplaceNode(
3256 N, createDRegPairNode(VecVT, N->getOperand(0), N->getOperand(1)));
3257 return;
Bob Wilsond8a9a042010-06-04 00:04:02 +00003258 }
Duncan Sands14627772010-11-03 12:17:33 +00003259 assert(EltVT == MVT::f32 && "unexpected type for BUILD_VECTOR");
Justin Bogner45571362016-05-12 00:31:09 +00003260 if (NumElts == 2) {
3261 ReplaceNode(
3262 N, createSRegPairNode(VecVT, N->getOperand(0), N->getOperand(1)));
3263 return;
3264 }
Bob Wilsond8a9a042010-06-04 00:04:02 +00003265 assert(NumElts == 4 && "unexpected type for BUILD_VECTOR");
Justin Bogner45571362016-05-12 00:31:09 +00003266 ReplaceNode(N,
3267 createQuadSRegsNode(VecVT, N->getOperand(0), N->getOperand(1),
3268 N->getOperand(2), N->getOperand(3)));
3269 return;
Bob Wilsond8a9a042010-06-04 00:04:02 +00003270 }
Bob Wilsone0636a72009-08-26 17:39:53 +00003271
Bob Wilson2d790df2010-11-28 06:51:26 +00003272 case ARMISD::VLD2DUP: {
Craig Topper01736f82012-05-24 05:17:00 +00003273 static const uint16_t Opcodes[] = { ARM::VLD2DUPd8, ARM::VLD2DUPd16,
3274 ARM::VLD2DUPd32 };
Justin Bogner45571362016-05-12 00:31:09 +00003275 SelectVLDDup(N, false, 2, Opcodes);
3276 return;
Bob Wilson2d790df2010-11-28 06:51:26 +00003277 }
3278
Bob Wilson77ab1652010-11-29 19:35:29 +00003279 case ARMISD::VLD3DUP: {
Craig Topper01736f82012-05-24 05:17:00 +00003280 static const uint16_t Opcodes[] = { ARM::VLD3DUPd8Pseudo,
3281 ARM::VLD3DUPd16Pseudo,
3282 ARM::VLD3DUPd32Pseudo };
Justin Bogner45571362016-05-12 00:31:09 +00003283 SelectVLDDup(N, false, 3, Opcodes);
3284 return;
Bob Wilson77ab1652010-11-29 19:35:29 +00003285 }
3286
Bob Wilson431ac4ef2010-11-30 00:00:35 +00003287 case ARMISD::VLD4DUP: {
Craig Topper01736f82012-05-24 05:17:00 +00003288 static const uint16_t Opcodes[] = { ARM::VLD4DUPd8Pseudo,
3289 ARM::VLD4DUPd16Pseudo,
3290 ARM::VLD4DUPd32Pseudo };
Justin Bogner45571362016-05-12 00:31:09 +00003291 SelectVLDDup(N, false, 4, Opcodes);
3292 return;
Bob Wilson06fce872011-02-07 17:43:21 +00003293 }
3294
3295 case ARMISD::VLD2DUP_UPD: {
Craig Topper01736f82012-05-24 05:17:00 +00003296 static const uint16_t Opcodes[] = { ARM::VLD2DUPd8wb_fixed,
3297 ARM::VLD2DUPd16wb_fixed,
3298 ARM::VLD2DUPd32wb_fixed };
Justin Bogner45571362016-05-12 00:31:09 +00003299 SelectVLDDup(N, true, 2, Opcodes);
3300 return;
Bob Wilson06fce872011-02-07 17:43:21 +00003301 }
3302
3303 case ARMISD::VLD3DUP_UPD: {
Craig Topper01736f82012-05-24 05:17:00 +00003304 static const uint16_t Opcodes[] = { ARM::VLD3DUPd8Pseudo_UPD,
3305 ARM::VLD3DUPd16Pseudo_UPD,
3306 ARM::VLD3DUPd32Pseudo_UPD };
Justin Bogner45571362016-05-12 00:31:09 +00003307 SelectVLDDup(N, true, 3, Opcodes);
3308 return;
Bob Wilson06fce872011-02-07 17:43:21 +00003309 }
3310
3311 case ARMISD::VLD4DUP_UPD: {
Craig Topper01736f82012-05-24 05:17:00 +00003312 static const uint16_t Opcodes[] = { ARM::VLD4DUPd8Pseudo_UPD,
3313 ARM::VLD4DUPd16Pseudo_UPD,
3314 ARM::VLD4DUPd32Pseudo_UPD };
Justin Bogner45571362016-05-12 00:31:09 +00003315 SelectVLDDup(N, true, 4, Opcodes);
3316 return;
Bob Wilson06fce872011-02-07 17:43:21 +00003317 }
3318
3319 case ARMISD::VLD1_UPD: {
Craig Topper01736f82012-05-24 05:17:00 +00003320 static const uint16_t DOpcodes[] = { ARM::VLD1d8wb_fixed,
3321 ARM::VLD1d16wb_fixed,
3322 ARM::VLD1d32wb_fixed,
3323 ARM::VLD1d64wb_fixed };
3324 static const uint16_t QOpcodes[] = { ARM::VLD1q8wb_fixed,
3325 ARM::VLD1q16wb_fixed,
3326 ARM::VLD1q32wb_fixed,
3327 ARM::VLD1q64wb_fixed };
Justin Bogner45571362016-05-12 00:31:09 +00003328 SelectVLD(N, true, 1, DOpcodes, QOpcodes, nullptr);
3329 return;
Bob Wilson06fce872011-02-07 17:43:21 +00003330 }
3331
3332 case ARMISD::VLD2_UPD: {
Craig Topper01736f82012-05-24 05:17:00 +00003333 static const uint16_t DOpcodes[] = { ARM::VLD2d8wb_fixed,
3334 ARM::VLD2d16wb_fixed,
3335 ARM::VLD2d32wb_fixed,
3336 ARM::VLD1q64wb_fixed};
3337 static const uint16_t QOpcodes[] = { ARM::VLD2q8PseudoWB_fixed,
3338 ARM::VLD2q16PseudoWB_fixed,
3339 ARM::VLD2q32PseudoWB_fixed };
Justin Bogner45571362016-05-12 00:31:09 +00003340 SelectVLD(N, true, 2, DOpcodes, QOpcodes, nullptr);
3341 return;
Bob Wilson06fce872011-02-07 17:43:21 +00003342 }
3343
3344 case ARMISD::VLD3_UPD: {
Craig Topper01736f82012-05-24 05:17:00 +00003345 static const uint16_t DOpcodes[] = { ARM::VLD3d8Pseudo_UPD,
3346 ARM::VLD3d16Pseudo_UPD,
3347 ARM::VLD3d32Pseudo_UPD,
Jiangning Liu4df23632014-01-16 09:16:13 +00003348 ARM::VLD1d64TPseudoWB_fixed};
Craig Topper01736f82012-05-24 05:17:00 +00003349 static const uint16_t QOpcodes0[] = { ARM::VLD3q8Pseudo_UPD,
3350 ARM::VLD3q16Pseudo_UPD,
3351 ARM::VLD3q32Pseudo_UPD };
3352 static const uint16_t QOpcodes1[] = { ARM::VLD3q8oddPseudo_UPD,
3353 ARM::VLD3q16oddPseudo_UPD,
3354 ARM::VLD3q32oddPseudo_UPD };
Justin Bogner45571362016-05-12 00:31:09 +00003355 SelectVLD(N, true, 3, DOpcodes, QOpcodes0, QOpcodes1);
3356 return;
Bob Wilson06fce872011-02-07 17:43:21 +00003357 }
3358
3359 case ARMISD::VLD4_UPD: {
Craig Topper01736f82012-05-24 05:17:00 +00003360 static const uint16_t DOpcodes[] = { ARM::VLD4d8Pseudo_UPD,
3361 ARM::VLD4d16Pseudo_UPD,
3362 ARM::VLD4d32Pseudo_UPD,
Jiangning Liu4df23632014-01-16 09:16:13 +00003363 ARM::VLD1d64QPseudoWB_fixed};
Craig Topper01736f82012-05-24 05:17:00 +00003364 static const uint16_t QOpcodes0[] = { ARM::VLD4q8Pseudo_UPD,
3365 ARM::VLD4q16Pseudo_UPD,
3366 ARM::VLD4q32Pseudo_UPD };
3367 static const uint16_t QOpcodes1[] = { ARM::VLD4q8oddPseudo_UPD,
3368 ARM::VLD4q16oddPseudo_UPD,
3369 ARM::VLD4q32oddPseudo_UPD };
Justin Bogner45571362016-05-12 00:31:09 +00003370 SelectVLD(N, true, 4, DOpcodes, QOpcodes0, QOpcodes1);
3371 return;
Bob Wilson06fce872011-02-07 17:43:21 +00003372 }
3373
3374 case ARMISD::VLD2LN_UPD: {
Craig Topper01736f82012-05-24 05:17:00 +00003375 static const uint16_t DOpcodes[] = { ARM::VLD2LNd8Pseudo_UPD,
3376 ARM::VLD2LNd16Pseudo_UPD,
3377 ARM::VLD2LNd32Pseudo_UPD };
3378 static const uint16_t QOpcodes[] = { ARM::VLD2LNq16Pseudo_UPD,
3379 ARM::VLD2LNq32Pseudo_UPD };
Justin Bogner45571362016-05-12 00:31:09 +00003380 SelectVLDSTLane(N, true, true, 2, DOpcodes, QOpcodes);
3381 return;
Bob Wilson06fce872011-02-07 17:43:21 +00003382 }
3383
3384 case ARMISD::VLD3LN_UPD: {
Craig Topper01736f82012-05-24 05:17:00 +00003385 static const uint16_t DOpcodes[] = { ARM::VLD3LNd8Pseudo_UPD,
3386 ARM::VLD3LNd16Pseudo_UPD,
3387 ARM::VLD3LNd32Pseudo_UPD };
3388 static const uint16_t QOpcodes[] = { ARM::VLD3LNq16Pseudo_UPD,
3389 ARM::VLD3LNq32Pseudo_UPD };
Justin Bogner45571362016-05-12 00:31:09 +00003390 SelectVLDSTLane(N, true, true, 3, DOpcodes, QOpcodes);
3391 return;
Bob Wilson06fce872011-02-07 17:43:21 +00003392 }
3393
3394 case ARMISD::VLD4LN_UPD: {
Craig Topper01736f82012-05-24 05:17:00 +00003395 static const uint16_t DOpcodes[] = { ARM::VLD4LNd8Pseudo_UPD,
3396 ARM::VLD4LNd16Pseudo_UPD,
3397 ARM::VLD4LNd32Pseudo_UPD };
3398 static const uint16_t QOpcodes[] = { ARM::VLD4LNq16Pseudo_UPD,
3399 ARM::VLD4LNq32Pseudo_UPD };
Justin Bogner45571362016-05-12 00:31:09 +00003400 SelectVLDSTLane(N, true, true, 4, DOpcodes, QOpcodes);
3401 return;
Bob Wilson06fce872011-02-07 17:43:21 +00003402 }
3403
3404 case ARMISD::VST1_UPD: {
Craig Topper01736f82012-05-24 05:17:00 +00003405 static const uint16_t DOpcodes[] = { ARM::VST1d8wb_fixed,
3406 ARM::VST1d16wb_fixed,
3407 ARM::VST1d32wb_fixed,
3408 ARM::VST1d64wb_fixed };
3409 static const uint16_t QOpcodes[] = { ARM::VST1q8wb_fixed,
3410 ARM::VST1q16wb_fixed,
3411 ARM::VST1q32wb_fixed,
3412 ARM::VST1q64wb_fixed };
Justin Bogner45571362016-05-12 00:31:09 +00003413 SelectVST(N, true, 1, DOpcodes, QOpcodes, nullptr);
3414 return;
Bob Wilson06fce872011-02-07 17:43:21 +00003415 }
3416
3417 case ARMISD::VST2_UPD: {
Craig Topper01736f82012-05-24 05:17:00 +00003418 static const uint16_t DOpcodes[] = { ARM::VST2d8wb_fixed,
3419 ARM::VST2d16wb_fixed,
3420 ARM::VST2d32wb_fixed,
3421 ARM::VST1q64wb_fixed};
3422 static const uint16_t QOpcodes[] = { ARM::VST2q8PseudoWB_fixed,
3423 ARM::VST2q16PseudoWB_fixed,
3424 ARM::VST2q32PseudoWB_fixed };
Justin Bogner45571362016-05-12 00:31:09 +00003425 SelectVST(N, true, 2, DOpcodes, QOpcodes, nullptr);
3426 return;
Bob Wilson06fce872011-02-07 17:43:21 +00003427 }
3428
3429 case ARMISD::VST3_UPD: {
Craig Topper01736f82012-05-24 05:17:00 +00003430 static const uint16_t DOpcodes[] = { ARM::VST3d8Pseudo_UPD,
3431 ARM::VST3d16Pseudo_UPD,
3432 ARM::VST3d32Pseudo_UPD,
3433 ARM::VST1d64TPseudoWB_fixed};
3434 static const uint16_t QOpcodes0[] = { ARM::VST3q8Pseudo_UPD,
3435 ARM::VST3q16Pseudo_UPD,
3436 ARM::VST3q32Pseudo_UPD };
3437 static const uint16_t QOpcodes1[] = { ARM::VST3q8oddPseudo_UPD,
3438 ARM::VST3q16oddPseudo_UPD,
3439 ARM::VST3q32oddPseudo_UPD };
Justin Bogner45571362016-05-12 00:31:09 +00003440 SelectVST(N, true, 3, DOpcodes, QOpcodes0, QOpcodes1);
3441 return;
Bob Wilson06fce872011-02-07 17:43:21 +00003442 }
3443
3444 case ARMISD::VST4_UPD: {
Craig Topper01736f82012-05-24 05:17:00 +00003445 static const uint16_t DOpcodes[] = { ARM::VST4d8Pseudo_UPD,
3446 ARM::VST4d16Pseudo_UPD,
3447 ARM::VST4d32Pseudo_UPD,
3448 ARM::VST1d64QPseudoWB_fixed};
3449 static const uint16_t QOpcodes0[] = { ARM::VST4q8Pseudo_UPD,
3450 ARM::VST4q16Pseudo_UPD,
3451 ARM::VST4q32Pseudo_UPD };
3452 static const uint16_t QOpcodes1[] = { ARM::VST4q8oddPseudo_UPD,
3453 ARM::VST4q16oddPseudo_UPD,
3454 ARM::VST4q32oddPseudo_UPD };
Justin Bogner45571362016-05-12 00:31:09 +00003455 SelectVST(N, true, 4, DOpcodes, QOpcodes0, QOpcodes1);
3456 return;
Bob Wilson06fce872011-02-07 17:43:21 +00003457 }
3458
3459 case ARMISD::VST2LN_UPD: {
Craig Topper01736f82012-05-24 05:17:00 +00003460 static const uint16_t DOpcodes[] = { ARM::VST2LNd8Pseudo_UPD,
3461 ARM::VST2LNd16Pseudo_UPD,
3462 ARM::VST2LNd32Pseudo_UPD };
3463 static const uint16_t QOpcodes[] = { ARM::VST2LNq16Pseudo_UPD,
3464 ARM::VST2LNq32Pseudo_UPD };
Justin Bogner45571362016-05-12 00:31:09 +00003465 SelectVLDSTLane(N, false, true, 2, DOpcodes, QOpcodes);
3466 return;
Bob Wilson06fce872011-02-07 17:43:21 +00003467 }
3468
3469 case ARMISD::VST3LN_UPD: {
Craig Topper01736f82012-05-24 05:17:00 +00003470 static const uint16_t DOpcodes[] = { ARM::VST3LNd8Pseudo_UPD,
3471 ARM::VST3LNd16Pseudo_UPD,
3472 ARM::VST3LNd32Pseudo_UPD };
3473 static const uint16_t QOpcodes[] = { ARM::VST3LNq16Pseudo_UPD,
3474 ARM::VST3LNq32Pseudo_UPD };
Justin Bogner45571362016-05-12 00:31:09 +00003475 SelectVLDSTLane(N, false, true, 3, DOpcodes, QOpcodes);
3476 return;
Bob Wilson06fce872011-02-07 17:43:21 +00003477 }
3478
3479 case ARMISD::VST4LN_UPD: {
Craig Topper01736f82012-05-24 05:17:00 +00003480 static const uint16_t DOpcodes[] = { ARM::VST4LNd8Pseudo_UPD,
3481 ARM::VST4LNd16Pseudo_UPD,
3482 ARM::VST4LNd32Pseudo_UPD };
3483 static const uint16_t QOpcodes[] = { ARM::VST4LNq16Pseudo_UPD,
3484 ARM::VST4LNq32Pseudo_UPD };
Justin Bogner45571362016-05-12 00:31:09 +00003485 SelectVLDSTLane(N, false, true, 4, DOpcodes, QOpcodes);
3486 return;
Bob Wilson431ac4ef2010-11-30 00:00:35 +00003487 }
3488
Bob Wilsone0636a72009-08-26 17:39:53 +00003489 case ISD::INTRINSIC_VOID:
3490 case ISD::INTRINSIC_W_CHAIN: {
3491 unsigned IntNo = cast<ConstantSDNode>(N->getOperand(1))->getZExtValue();
Bob Wilsone0636a72009-08-26 17:39:53 +00003492 switch (IntNo) {
3493 default:
Bob Wilsonf765e1f2010-05-06 16:05:26 +00003494 break;
Bob Wilsone0636a72009-08-26 17:39:53 +00003495
Ranjeet Singh39d2d092016-06-17 00:52:41 +00003496 case Intrinsic::arm_mrrc:
3497 case Intrinsic::arm_mrrc2: {
3498 SDLoc dl(N);
3499 SDValue Chain = N->getOperand(0);
3500 unsigned Opc;
3501
3502 if (Subtarget->isThumb())
3503 Opc = (IntNo == Intrinsic::arm_mrrc ? ARM::t2MRRC : ARM::t2MRRC2);
3504 else
3505 Opc = (IntNo == Intrinsic::arm_mrrc ? ARM::MRRC : ARM::MRRC2);
3506
3507 SmallVector<SDValue, 5> Ops;
3508 Ops.push_back(getI32Imm(cast<ConstantSDNode>(N->getOperand(2))->getZExtValue(), dl)); /* coproc */
3509 Ops.push_back(getI32Imm(cast<ConstantSDNode>(N->getOperand(3))->getZExtValue(), dl)); /* opc */
3510 Ops.push_back(getI32Imm(cast<ConstantSDNode>(N->getOperand(4))->getZExtValue(), dl)); /* CRm */
3511
3512 // The mrrc2 instruction in ARM doesn't allow predicates, the top 4 bits of the encoded
3513 // instruction will always be '1111' but it is possible in assembly language to specify
3514 // AL as a predicate to mrrc2 but it doesn't make any difference to the encoded instruction.
3515 if (Opc != ARM::MRRC2) {
3516 Ops.push_back(getAL(CurDAG, dl));
3517 Ops.push_back(CurDAG->getRegister(0, MVT::i32));
3518 }
3519
3520 Ops.push_back(Chain);
3521
3522 // Writes to two registers.
Benjamin Kramerf690da42016-06-17 14:14:29 +00003523 const EVT RetType[] = {MVT::i32, MVT::i32, MVT::Other};
Ranjeet Singh39d2d092016-06-17 00:52:41 +00003524
3525 ReplaceNode(N, CurDAG->getMachineNode(Opc, dl, RetType, Ops));
3526 return;
3527 }
Tim Northover1ff5f292014-03-26 14:39:31 +00003528 case Intrinsic::arm_ldaexd:
Bruno Cardoso Lopes325110f2011-05-28 04:07:29 +00003529 case Intrinsic::arm_ldrexd: {
Andrew Trickef9de2a2013-05-25 02:42:55 +00003530 SDLoc dl(N);
Bruno Cardoso Lopes325110f2011-05-28 04:07:29 +00003531 SDValue Chain = N->getOperand(0);
Tim Northover1ff5f292014-03-26 14:39:31 +00003532 SDValue MemAddr = N->getOperand(2);
Bradley Smith433c22e2016-01-15 10:26:51 +00003533 bool isThumb = Subtarget->isThumb() && Subtarget->hasV8MBaselineOps();
Tim Northover1ff5f292014-03-26 14:39:31 +00003534
3535 bool IsAcquire = IntNo == Intrinsic::arm_ldaexd;
3536 unsigned NewOpc = isThumb ? (IsAcquire ? ARM::t2LDAEXD : ARM::t2LDREXD)
3537 : (IsAcquire ? ARM::LDAEXD : ARM::LDREXD);
Bruno Cardoso Lopes325110f2011-05-28 04:07:29 +00003538
3539 // arm_ldrexd returns a i64 value in {i32, i32}
3540 std::vector<EVT> ResTys;
Weiming Zhao8f56f882012-11-16 21:55:34 +00003541 if (isThumb) {
3542 ResTys.push_back(MVT::i32);
3543 ResTys.push_back(MVT::i32);
3544 } else
3545 ResTys.push_back(MVT::Untyped);
Bruno Cardoso Lopes325110f2011-05-28 04:07:29 +00003546 ResTys.push_back(MVT::Other);
3547
Weiming Zhao8f56f882012-11-16 21:55:34 +00003548 // Place arguments in the right order.
Benjamin Kramerf690da42016-06-17 14:14:29 +00003549 SDValue Ops[] = {MemAddr, getAL(CurDAG, dl),
3550 CurDAG->getRegister(0, MVT::i32), Chain};
Michael Liaob53d8962013-04-19 22:22:57 +00003551 SDNode *Ld = CurDAG->getMachineNode(NewOpc, dl, ResTys, Ops);
Bruno Cardoso Lopes325110f2011-05-28 04:07:29 +00003552 // Transfer memoperands.
3553 MachineSDNode::mmo_iterator MemOp = MF->allocateMemRefsArray(1);
3554 MemOp[0] = cast<MemIntrinsicSDNode>(N)->getMemOperand();
3555 cast<MachineSDNode>(Ld)->setMemRefs(MemOp, MemOp + 1);
3556
Bruno Cardoso Lopes325110f2011-05-28 04:07:29 +00003557 // Remap uses.
Lang Hamesbe3d9712013-03-09 22:56:09 +00003558 SDValue OutChain = isThumb ? SDValue(Ld, 2) : SDValue(Ld, 1);
Bruno Cardoso Lopes325110f2011-05-28 04:07:29 +00003559 if (!SDValue(N, 0).use_empty()) {
Weiming Zhao8f56f882012-11-16 21:55:34 +00003560 SDValue Result;
3561 if (isThumb)
3562 Result = SDValue(Ld, 0);
3563 else {
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00003564 SDValue SubRegIdx =
3565 CurDAG->getTargetConstant(ARM::gsub_0, dl, MVT::i32);
Weiming Zhao8f56f882012-11-16 21:55:34 +00003566 SDNode *ResNode = CurDAG->getMachineNode(TargetOpcode::EXTRACT_SUBREG,
Lang Hamesbe3d9712013-03-09 22:56:09 +00003567 dl, MVT::i32, SDValue(Ld, 0), SubRegIdx);
Weiming Zhao8f56f882012-11-16 21:55:34 +00003568 Result = SDValue(ResNode,0);
Weiming Zhao8f56f882012-11-16 21:55:34 +00003569 }
Bruno Cardoso Lopes325110f2011-05-28 04:07:29 +00003570 ReplaceUses(SDValue(N, 0), Result);
3571 }
3572 if (!SDValue(N, 1).use_empty()) {
Weiming Zhao8f56f882012-11-16 21:55:34 +00003573 SDValue Result;
3574 if (isThumb)
3575 Result = SDValue(Ld, 1);
3576 else {
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00003577 SDValue SubRegIdx =
3578 CurDAG->getTargetConstant(ARM::gsub_1, dl, MVT::i32);
Weiming Zhao8f56f882012-11-16 21:55:34 +00003579 SDNode *ResNode = CurDAG->getMachineNode(TargetOpcode::EXTRACT_SUBREG,
Lang Hamesbe3d9712013-03-09 22:56:09 +00003580 dl, MVT::i32, SDValue(Ld, 0), SubRegIdx);
Weiming Zhao8f56f882012-11-16 21:55:34 +00003581 Result = SDValue(ResNode,0);
Weiming Zhao8f56f882012-11-16 21:55:34 +00003582 }
Bruno Cardoso Lopes325110f2011-05-28 04:07:29 +00003583 ReplaceUses(SDValue(N, 1), Result);
3584 }
Lang Hamesbe3d9712013-03-09 22:56:09 +00003585 ReplaceUses(SDValue(N, 2), OutChain);
Justin Bognered4f3782016-05-12 00:20:19 +00003586 CurDAG->RemoveDeadNode(N);
Justin Bogner45571362016-05-12 00:31:09 +00003587 return;
Bruno Cardoso Lopes325110f2011-05-28 04:07:29 +00003588 }
Tim Northover1ff5f292014-03-26 14:39:31 +00003589 case Intrinsic::arm_stlexd:
Bruno Cardoso Lopes325110f2011-05-28 04:07:29 +00003590 case Intrinsic::arm_strexd: {
Andrew Trickef9de2a2013-05-25 02:42:55 +00003591 SDLoc dl(N);
Bruno Cardoso Lopes325110f2011-05-28 04:07:29 +00003592 SDValue Chain = N->getOperand(0);
3593 SDValue Val0 = N->getOperand(2);
3594 SDValue Val1 = N->getOperand(3);
3595 SDValue MemAddr = N->getOperand(4);
3596
Bruno Cardoso Lopes325110f2011-05-28 04:07:29 +00003597 // Store exclusive double return a i32 value which is the return status
3598 // of the issued store.
Benjamin Kramer867bfc52015-03-07 17:41:00 +00003599 const EVT ResTys[] = {MVT::i32, MVT::Other};
Bruno Cardoso Lopes325110f2011-05-28 04:07:29 +00003600
Weiming Zhao8f56f882012-11-16 21:55:34 +00003601 bool isThumb = Subtarget->isThumb() && Subtarget->hasThumb2();
3602 // Place arguments in the right order.
Bruno Cardoso Lopes325110f2011-05-28 04:07:29 +00003603 SmallVector<SDValue, 7> Ops;
Weiming Zhao8f56f882012-11-16 21:55:34 +00003604 if (isThumb) {
3605 Ops.push_back(Val0);
3606 Ops.push_back(Val1);
3607 } else
3608 // arm_strexd uses GPRPair.
3609 Ops.push_back(SDValue(createGPRPairNode(MVT::Untyped, Val0, Val1), 0));
Bruno Cardoso Lopes325110f2011-05-28 04:07:29 +00003610 Ops.push_back(MemAddr);
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00003611 Ops.push_back(getAL(CurDAG, dl));
Bruno Cardoso Lopes325110f2011-05-28 04:07:29 +00003612 Ops.push_back(CurDAG->getRegister(0, MVT::i32));
3613 Ops.push_back(Chain);
3614
Tim Northover1ff5f292014-03-26 14:39:31 +00003615 bool IsRelease = IntNo == Intrinsic::arm_stlexd;
3616 unsigned NewOpc = isThumb ? (IsRelease ? ARM::t2STLEXD : ARM::t2STREXD)
3617 : (IsRelease ? ARM::STLEXD : ARM::STREXD);
Bruno Cardoso Lopes325110f2011-05-28 04:07:29 +00003618
Michael Liaob53d8962013-04-19 22:22:57 +00003619 SDNode *St = CurDAG->getMachineNode(NewOpc, dl, ResTys, Ops);
Bruno Cardoso Lopes325110f2011-05-28 04:07:29 +00003620 // Transfer memoperands.
3621 MachineSDNode::mmo_iterator MemOp = MF->allocateMemRefsArray(1);
3622 MemOp[0] = cast<MemIntrinsicSDNode>(N)->getMemOperand();
3623 cast<MachineSDNode>(St)->setMemRefs(MemOp, MemOp + 1);
3624
Justin Bogner45571362016-05-12 00:31:09 +00003625 ReplaceNode(N, St);
3626 return;
Bruno Cardoso Lopes325110f2011-05-28 04:07:29 +00003627 }
3628
Bob Wilson340861d2010-03-23 05:25:43 +00003629 case Intrinsic::arm_neon_vld1: {
Craig Topper01736f82012-05-24 05:17:00 +00003630 static const uint16_t DOpcodes[] = { ARM::VLD1d8, ARM::VLD1d16,
3631 ARM::VLD1d32, ARM::VLD1d64 };
3632 static const uint16_t QOpcodes[] = { ARM::VLD1q8, ARM::VLD1q16,
3633 ARM::VLD1q32, ARM::VLD1q64};
Justin Bogner45571362016-05-12 00:31:09 +00003634 SelectVLD(N, false, 1, DOpcodes, QOpcodes, nullptr);
3635 return;
Bob Wilson340861d2010-03-23 05:25:43 +00003636 }
3637
Bob Wilsone0636a72009-08-26 17:39:53 +00003638 case Intrinsic::arm_neon_vld2: {
Craig Topper01736f82012-05-24 05:17:00 +00003639 static const uint16_t DOpcodes[] = { ARM::VLD2d8, ARM::VLD2d16,
3640 ARM::VLD2d32, ARM::VLD1q64 };
3641 static const uint16_t QOpcodes[] = { ARM::VLD2q8Pseudo, ARM::VLD2q16Pseudo,
3642 ARM::VLD2q32Pseudo };
Justin Bogner45571362016-05-12 00:31:09 +00003643 SelectVLD(N, false, 2, DOpcodes, QOpcodes, nullptr);
3644 return;
Bob Wilsone0636a72009-08-26 17:39:53 +00003645 }
3646
3647 case Intrinsic::arm_neon_vld3: {
Craig Topper01736f82012-05-24 05:17:00 +00003648 static const uint16_t DOpcodes[] = { ARM::VLD3d8Pseudo,
3649 ARM::VLD3d16Pseudo,
3650 ARM::VLD3d32Pseudo,
3651 ARM::VLD1d64TPseudo };
3652 static const uint16_t QOpcodes0[] = { ARM::VLD3q8Pseudo_UPD,
3653 ARM::VLD3q16Pseudo_UPD,
3654 ARM::VLD3q32Pseudo_UPD };
3655 static const uint16_t QOpcodes1[] = { ARM::VLD3q8oddPseudo,
3656 ARM::VLD3q16oddPseudo,
3657 ARM::VLD3q32oddPseudo };
Justin Bogner45571362016-05-12 00:31:09 +00003658 SelectVLD(N, false, 3, DOpcodes, QOpcodes0, QOpcodes1);
3659 return;
Bob Wilsone0636a72009-08-26 17:39:53 +00003660 }
3661
3662 case Intrinsic::arm_neon_vld4: {
Craig Topper01736f82012-05-24 05:17:00 +00003663 static const uint16_t DOpcodes[] = { ARM::VLD4d8Pseudo,
3664 ARM::VLD4d16Pseudo,
3665 ARM::VLD4d32Pseudo,
3666 ARM::VLD1d64QPseudo };
3667 static const uint16_t QOpcodes0[] = { ARM::VLD4q8Pseudo_UPD,
3668 ARM::VLD4q16Pseudo_UPD,
3669 ARM::VLD4q32Pseudo_UPD };
3670 static const uint16_t QOpcodes1[] = { ARM::VLD4q8oddPseudo,
3671 ARM::VLD4q16oddPseudo,
3672 ARM::VLD4q32oddPseudo };
Justin Bogner45571362016-05-12 00:31:09 +00003673 SelectVLD(N, false, 4, DOpcodes, QOpcodes0, QOpcodes1);
3674 return;
Bob Wilsone0636a72009-08-26 17:39:53 +00003675 }
3676
Bob Wilsonda9817c2009-09-01 04:26:28 +00003677 case Intrinsic::arm_neon_vld2lane: {
Craig Topper01736f82012-05-24 05:17:00 +00003678 static const uint16_t DOpcodes[] = { ARM::VLD2LNd8Pseudo,
3679 ARM::VLD2LNd16Pseudo,
3680 ARM::VLD2LNd32Pseudo };
3681 static const uint16_t QOpcodes[] = { ARM::VLD2LNq16Pseudo,
3682 ARM::VLD2LNq32Pseudo };
Justin Bogner45571362016-05-12 00:31:09 +00003683 SelectVLDSTLane(N, true, false, 2, DOpcodes, QOpcodes);
3684 return;
Bob Wilsonda9817c2009-09-01 04:26:28 +00003685 }
3686
3687 case Intrinsic::arm_neon_vld3lane: {
Craig Topper01736f82012-05-24 05:17:00 +00003688 static const uint16_t DOpcodes[] = { ARM::VLD3LNd8Pseudo,
3689 ARM::VLD3LNd16Pseudo,
3690 ARM::VLD3LNd32Pseudo };
3691 static const uint16_t QOpcodes[] = { ARM::VLD3LNq16Pseudo,
3692 ARM::VLD3LNq32Pseudo };
Justin Bogner45571362016-05-12 00:31:09 +00003693 SelectVLDSTLane(N, true, false, 3, DOpcodes, QOpcodes);
3694 return;
Bob Wilsonda9817c2009-09-01 04:26:28 +00003695 }
3696
3697 case Intrinsic::arm_neon_vld4lane: {
Craig Topper01736f82012-05-24 05:17:00 +00003698 static const uint16_t DOpcodes[] = { ARM::VLD4LNd8Pseudo,
3699 ARM::VLD4LNd16Pseudo,
3700 ARM::VLD4LNd32Pseudo };
3701 static const uint16_t QOpcodes[] = { ARM::VLD4LNq16Pseudo,
3702 ARM::VLD4LNq32Pseudo };
Justin Bogner45571362016-05-12 00:31:09 +00003703 SelectVLDSTLane(N, true, false, 4, DOpcodes, QOpcodes);
3704 return;
Bob Wilsonda9817c2009-09-01 04:26:28 +00003705 }
3706
Bob Wilsoncc0a2a72010-03-23 06:20:33 +00003707 case Intrinsic::arm_neon_vst1: {
Craig Topper01736f82012-05-24 05:17:00 +00003708 static const uint16_t DOpcodes[] = { ARM::VST1d8, ARM::VST1d16,
3709 ARM::VST1d32, ARM::VST1d64 };
3710 static const uint16_t QOpcodes[] = { ARM::VST1q8, ARM::VST1q16,
3711 ARM::VST1q32, ARM::VST1q64 };
Justin Bogner45571362016-05-12 00:31:09 +00003712 SelectVST(N, false, 1, DOpcodes, QOpcodes, nullptr);
3713 return;
Bob Wilsoncc0a2a72010-03-23 06:20:33 +00003714 }
3715
Bob Wilsone0636a72009-08-26 17:39:53 +00003716 case Intrinsic::arm_neon_vst2: {
Craig Topper01736f82012-05-24 05:17:00 +00003717 static const uint16_t DOpcodes[] = { ARM::VST2d8, ARM::VST2d16,
3718 ARM::VST2d32, ARM::VST1q64 };
Benjamin Kramerf690da42016-06-17 14:14:29 +00003719 static const uint16_t QOpcodes[] = { ARM::VST2q8Pseudo, ARM::VST2q16Pseudo,
3720 ARM::VST2q32Pseudo };
Justin Bogner45571362016-05-12 00:31:09 +00003721 SelectVST(N, false, 2, DOpcodes, QOpcodes, nullptr);
3722 return;
Bob Wilsone0636a72009-08-26 17:39:53 +00003723 }
3724
3725 case Intrinsic::arm_neon_vst3: {
Craig Topper01736f82012-05-24 05:17:00 +00003726 static const uint16_t DOpcodes[] = { ARM::VST3d8Pseudo,
3727 ARM::VST3d16Pseudo,
3728 ARM::VST3d32Pseudo,
3729 ARM::VST1d64TPseudo };
3730 static const uint16_t QOpcodes0[] = { ARM::VST3q8Pseudo_UPD,
3731 ARM::VST3q16Pseudo_UPD,
3732 ARM::VST3q32Pseudo_UPD };
3733 static const uint16_t QOpcodes1[] = { ARM::VST3q8oddPseudo,
3734 ARM::VST3q16oddPseudo,
3735 ARM::VST3q32oddPseudo };
Justin Bogner45571362016-05-12 00:31:09 +00003736 SelectVST(N, false, 3, DOpcodes, QOpcodes0, QOpcodes1);
3737 return;
Bob Wilsone0636a72009-08-26 17:39:53 +00003738 }
3739
3740 case Intrinsic::arm_neon_vst4: {
Craig Topper01736f82012-05-24 05:17:00 +00003741 static const uint16_t DOpcodes[] = { ARM::VST4d8Pseudo,
3742 ARM::VST4d16Pseudo,
3743 ARM::VST4d32Pseudo,
3744 ARM::VST1d64QPseudo };
3745 static const uint16_t QOpcodes0[] = { ARM::VST4q8Pseudo_UPD,
3746 ARM::VST4q16Pseudo_UPD,
3747 ARM::VST4q32Pseudo_UPD };
3748 static const uint16_t QOpcodes1[] = { ARM::VST4q8oddPseudo,
3749 ARM::VST4q16oddPseudo,
3750 ARM::VST4q32oddPseudo };
Justin Bogner45571362016-05-12 00:31:09 +00003751 SelectVST(N, false, 4, DOpcodes, QOpcodes0, QOpcodes1);
3752 return;
Bob Wilsone0636a72009-08-26 17:39:53 +00003753 }
Bob Wilsond7797752009-09-01 18:51:56 +00003754
3755 case Intrinsic::arm_neon_vst2lane: {
Craig Topper01736f82012-05-24 05:17:00 +00003756 static const uint16_t DOpcodes[] = { ARM::VST2LNd8Pseudo,
3757 ARM::VST2LNd16Pseudo,
3758 ARM::VST2LNd32Pseudo };
3759 static const uint16_t QOpcodes[] = { ARM::VST2LNq16Pseudo,
3760 ARM::VST2LNq32Pseudo };
Justin Bogner45571362016-05-12 00:31:09 +00003761 SelectVLDSTLane(N, false, false, 2, DOpcodes, QOpcodes);
3762 return;
Bob Wilsond7797752009-09-01 18:51:56 +00003763 }
3764
3765 case Intrinsic::arm_neon_vst3lane: {
Craig Topper01736f82012-05-24 05:17:00 +00003766 static const uint16_t DOpcodes[] = { ARM::VST3LNd8Pseudo,
3767 ARM::VST3LNd16Pseudo,
3768 ARM::VST3LNd32Pseudo };
3769 static const uint16_t QOpcodes[] = { ARM::VST3LNq16Pseudo,
3770 ARM::VST3LNq32Pseudo };
Justin Bogner45571362016-05-12 00:31:09 +00003771 SelectVLDSTLane(N, false, false, 3, DOpcodes, QOpcodes);
3772 return;
Bob Wilsond7797752009-09-01 18:51:56 +00003773 }
3774
3775 case Intrinsic::arm_neon_vst4lane: {
Craig Topper01736f82012-05-24 05:17:00 +00003776 static const uint16_t DOpcodes[] = { ARM::VST4LNd8Pseudo,
3777 ARM::VST4LNd16Pseudo,
3778 ARM::VST4LNd32Pseudo };
3779 static const uint16_t QOpcodes[] = { ARM::VST4LNq16Pseudo,
3780 ARM::VST4LNq32Pseudo };
Justin Bogner45571362016-05-12 00:31:09 +00003781 SelectVLDSTLane(N, false, false, 4, DOpcodes, QOpcodes);
3782 return;
Bob Wilsond7797752009-09-01 18:51:56 +00003783 }
Bob Wilsone0636a72009-08-26 17:39:53 +00003784 }
Bob Wilsonf765e1f2010-05-06 16:05:26 +00003785 break;
Bob Wilsone0636a72009-08-26 17:39:53 +00003786 }
Evan Chengd85631e2010-05-05 18:28:36 +00003787
Bob Wilson3ed511b2010-07-06 23:36:25 +00003788 case ISD::INTRINSIC_WO_CHAIN: {
3789 unsigned IntNo = cast<ConstantSDNode>(N->getOperand(0))->getZExtValue();
3790 switch (IntNo) {
3791 default:
3792 break;
3793
3794 case Intrinsic::arm_neon_vtbl2:
Justin Bogner45571362016-05-12 00:31:09 +00003795 SelectVTBL(N, false, 2, ARM::VTBL2);
3796 return;
Bob Wilson3ed511b2010-07-06 23:36:25 +00003797 case Intrinsic::arm_neon_vtbl3:
Justin Bogner45571362016-05-12 00:31:09 +00003798 SelectVTBL(N, false, 3, ARM::VTBL3Pseudo);
3799 return;
Bob Wilson3ed511b2010-07-06 23:36:25 +00003800 case Intrinsic::arm_neon_vtbl4:
Justin Bogner45571362016-05-12 00:31:09 +00003801 SelectVTBL(N, false, 4, ARM::VTBL4Pseudo);
3802 return;
Bob Wilson5bc8a792010-07-07 00:08:54 +00003803
3804 case Intrinsic::arm_neon_vtbx2:
Justin Bogner45571362016-05-12 00:31:09 +00003805 SelectVTBL(N, true, 2, ARM::VTBX2);
3806 return;
Bob Wilson5bc8a792010-07-07 00:08:54 +00003807 case Intrinsic::arm_neon_vtbx3:
Justin Bogner45571362016-05-12 00:31:09 +00003808 SelectVTBL(N, true, 3, ARM::VTBX3Pseudo);
3809 return;
Bob Wilson5bc8a792010-07-07 00:08:54 +00003810 case Intrinsic::arm_neon_vtbx4:
Justin Bogner45571362016-05-12 00:31:09 +00003811 SelectVTBL(N, true, 4, ARM::VTBX4Pseudo);
3812 return;
Bob Wilson3ed511b2010-07-06 23:36:25 +00003813 }
3814 break;
3815 }
3816
Bill Wendlinge1fd78f2011-03-14 23:02:38 +00003817 case ARMISD::VTBL1: {
Andrew Trickef9de2a2013-05-25 02:42:55 +00003818 SDLoc dl(N);
Bill Wendlinge1fd78f2011-03-14 23:02:38 +00003819 EVT VT = N->getValueType(0);
Benjamin Kramerf690da42016-06-17 14:14:29 +00003820 SDValue Ops[] = {N->getOperand(0), N->getOperand(1),
3821 getAL(CurDAG, dl), // Predicate
3822 CurDAG->getRegister(0, MVT::i32)}; // Predicate Register
Justin Bogner45571362016-05-12 00:31:09 +00003823 ReplaceNode(N, CurDAG->getMachineNode(ARM::VTBL1, dl, VT, Ops));
3824 return;
Bill Wendlinge1fd78f2011-03-14 23:02:38 +00003825 }
3826 case ARMISD::VTBL2: {
Andrew Trickef9de2a2013-05-25 02:42:55 +00003827 SDLoc dl(N);
Bill Wendlinge1fd78f2011-03-14 23:02:38 +00003828 EVT VT = N->getValueType(0);
3829
3830 // Form a REG_SEQUENCE to force register allocation.
3831 SDValue V0 = N->getOperand(0);
3832 SDValue V1 = N->getOperand(1);
Weiming Zhao95782222012-11-17 00:23:35 +00003833 SDValue RegSeq = SDValue(createDRegPairNode(MVT::v16i8, V0, V1), 0);
Bill Wendlinge1fd78f2011-03-14 23:02:38 +00003834
Benjamin Kramerf690da42016-06-17 14:14:29 +00003835 SDValue Ops[] = {RegSeq, N->getOperand(2), getAL(CurDAG, dl), // Predicate
3836 CurDAG->getRegister(0, MVT::i32)}; // Predicate Register
Justin Bogner45571362016-05-12 00:31:09 +00003837 ReplaceNode(N, CurDAG->getMachineNode(ARM::VTBL2, dl, VT, Ops));
3838 return;
Bill Wendlinge1fd78f2011-03-14 23:02:38 +00003839 }
3840
Bob Wilsonf765e1f2010-05-06 16:05:26 +00003841 case ISD::CONCAT_VECTORS:
Justin Bogner45571362016-05-12 00:31:09 +00003842 SelectConcatVector(N);
3843 return;
Tim Northoverb629c772016-04-18 21:48:55 +00003844
3845 case ISD::ATOMIC_CMP_SWAP:
Justin Bogner45571362016-05-12 00:31:09 +00003846 SelectCMP_SWAP(N);
3847 return;
Evan Chengd85631e2010-05-05 18:28:36 +00003848 }
Evan Chengd5021732008-12-10 21:54:21 +00003849
Justin Bogner45571362016-05-12 00:31:09 +00003850 SelectCode(N);
Evan Cheng10043e22007-01-19 07:51:42 +00003851}
Rafael Espindolaffdc24b2006-05-14 22:18:28 +00003852
Luke Cheeseman85fd06d2015-06-01 12:02:47 +00003853// Inspect a register string of the form
3854// cp<coprocessor>:<opc1>:c<CRn>:c<CRm>:<opc2> (32bit) or
3855// cp<coprocessor>:<opc1>:c<CRm> (64bit) inspect the fields of the string
3856// and obtain the integer operands from them, adding these operands to the
3857// provided vector.
3858static void getIntOperandsFromRegisterString(StringRef RegString,
Benjamin Kramerbdc49562016-06-12 15:39:02 +00003859 SelectionDAG *CurDAG,
3860 const SDLoc &DL,
3861 std::vector<SDValue> &Ops) {
Luke Cheeseman85fd06d2015-06-01 12:02:47 +00003862 SmallVector<StringRef, 5> Fields;
Chandler Carruthe4405e92015-09-10 06:12:31 +00003863 RegString.split(Fields, ':');
Luke Cheeseman85fd06d2015-06-01 12:02:47 +00003864
3865 if (Fields.size() > 1) {
3866 bool AllIntFields = true;
3867
3868 for (StringRef Field : Fields) {
3869 // Need to trim out leading 'cp' characters and get the integer field.
3870 unsigned IntField;
3871 AllIntFields &= !Field.trim("CPcp").getAsInteger(10, IntField);
3872 Ops.push_back(CurDAG->getTargetConstant(IntField, DL, MVT::i32));
3873 }
3874
3875 assert(AllIntFields &&
3876 "Unexpected non-integer value in special register string.");
3877 }
3878}
3879
3880// Maps a Banked Register string to its mask value. The mask value returned is
3881// for use in the MRSbanked / MSRbanked instruction nodes as the Banked Register
3882// mask operand, which expresses which register is to be used, e.g. r8, and in
3883// which mode it is to be used, e.g. usr. Returns -1 to signify that the string
3884// was invalid.
3885static inline int getBankedRegisterMask(StringRef RegString) {
3886 return StringSwitch<int>(RegString.lower())
3887 .Case("r8_usr", 0x00)
3888 .Case("r9_usr", 0x01)
3889 .Case("r10_usr", 0x02)
3890 .Case("r11_usr", 0x03)
3891 .Case("r12_usr", 0x04)
3892 .Case("sp_usr", 0x05)
3893 .Case("lr_usr", 0x06)
3894 .Case("r8_fiq", 0x08)
3895 .Case("r9_fiq", 0x09)
3896 .Case("r10_fiq", 0x0a)
3897 .Case("r11_fiq", 0x0b)
3898 .Case("r12_fiq", 0x0c)
3899 .Case("sp_fiq", 0x0d)
3900 .Case("lr_fiq", 0x0e)
3901 .Case("lr_irq", 0x10)
3902 .Case("sp_irq", 0x11)
3903 .Case("lr_svc", 0x12)
3904 .Case("sp_svc", 0x13)
3905 .Case("lr_abt", 0x14)
3906 .Case("sp_abt", 0x15)
3907 .Case("lr_und", 0x16)
3908 .Case("sp_und", 0x17)
3909 .Case("lr_mon", 0x1c)
3910 .Case("sp_mon", 0x1d)
3911 .Case("elr_hyp", 0x1e)
3912 .Case("sp_hyp", 0x1f)
3913 .Case("spsr_fiq", 0x2e)
3914 .Case("spsr_irq", 0x30)
3915 .Case("spsr_svc", 0x32)
3916 .Case("spsr_abt", 0x34)
3917 .Case("spsr_und", 0x36)
3918 .Case("spsr_mon", 0x3c)
3919 .Case("spsr_hyp", 0x3e)
3920 .Default(-1);
3921}
3922
3923// Maps a MClass special register string to its value for use in the
3924// t2MRS_M / t2MSR_M instruction nodes as the SYSm value operand.
3925// Returns -1 to signify that the string was invalid.
3926static inline int getMClassRegisterSYSmValueMask(StringRef RegString) {
3927 return StringSwitch<int>(RegString.lower())
3928 .Case("apsr", 0x0)
3929 .Case("iapsr", 0x1)
3930 .Case("eapsr", 0x2)
3931 .Case("xpsr", 0x3)
3932 .Case("ipsr", 0x5)
3933 .Case("epsr", 0x6)
3934 .Case("iepsr", 0x7)
3935 .Case("msp", 0x8)
3936 .Case("psp", 0x9)
3937 .Case("primask", 0x10)
3938 .Case("basepri", 0x11)
3939 .Case("basepri_max", 0x12)
3940 .Case("faultmask", 0x13)
3941 .Case("control", 0x14)
Bradley Smithf277c8a2016-01-25 11:25:36 +00003942 .Case("msplim", 0x0a)
3943 .Case("psplim", 0x0b)
3944 .Case("sp", 0x18)
Luke Cheeseman85fd06d2015-06-01 12:02:47 +00003945 .Default(-1);
3946}
3947
3948// The flags here are common to those allowed for apsr in the A class cores and
3949// those allowed for the special registers in the M class cores. Returns a
3950// value representing which flags were present, -1 if invalid.
Artyom Skrobovcf296442015-09-24 17:31:16 +00003951static inline int getMClassFlagsMask(StringRef Flags, bool hasDSP) {
Luke Cheeseman85fd06d2015-06-01 12:02:47 +00003952 if (Flags.empty())
Artyom Skrobovcf296442015-09-24 17:31:16 +00003953 return 0x2 | (int)hasDSP;
Luke Cheeseman85fd06d2015-06-01 12:02:47 +00003954
3955 return StringSwitch<int>(Flags)
3956 .Case("g", 0x1)
3957 .Case("nzcvq", 0x2)
3958 .Case("nzcvqg", 0x3)
3959 .Default(-1);
3960}
3961
3962static int getMClassRegisterMask(StringRef Reg, StringRef Flags, bool IsRead,
3963 const ARMSubtarget *Subtarget) {
3964 // Ensure that the register (without flags) was a valid M Class special
3965 // register.
3966 int SYSmvalue = getMClassRegisterSYSmValueMask(Reg);
3967 if (SYSmvalue == -1)
3968 return -1;
3969
3970 // basepri, basepri_max and faultmask are only valid for V7m.
3971 if (!Subtarget->hasV7Ops() && SYSmvalue >= 0x11 && SYSmvalue <= 0x13)
3972 return -1;
3973
Bradley Smithf277c8a2016-01-25 11:25:36 +00003974 if (Subtarget->has8MSecExt() && Flags.lower() == "ns") {
3975 Flags = "";
3976 SYSmvalue |= 0x80;
3977 }
3978
3979 if (!Subtarget->has8MSecExt() &&
3980 (SYSmvalue == 0xa || SYSmvalue == 0xb || SYSmvalue > 0x14))
3981 return -1;
3982
3983 if (!Subtarget->hasV8MMainlineOps() &&
3984 (SYSmvalue == 0x8a || SYSmvalue == 0x8b || SYSmvalue == 0x91 ||
3985 SYSmvalue == 0x93))
3986 return -1;
3987
Luke Cheeseman85fd06d2015-06-01 12:02:47 +00003988 // If it was a read then we won't be expecting flags and so at this point
3989 // we can return the mask.
3990 if (IsRead) {
Bradley Smithf277c8a2016-01-25 11:25:36 +00003991 if (Flags.empty())
3992 return SYSmvalue;
3993 else
3994 return -1;
Luke Cheeseman85fd06d2015-06-01 12:02:47 +00003995 }
3996
3997 // We know we are now handling a write so need to get the mask for the flags.
Artyom Skrobovcf296442015-09-24 17:31:16 +00003998 int Mask = getMClassFlagsMask(Flags, Subtarget->hasDSP());
Luke Cheeseman85fd06d2015-06-01 12:02:47 +00003999
4000 // Only apsr, iapsr, eapsr, xpsr can have flags. The other register values
4001 // shouldn't have flags present.
4002 if ((SYSmvalue < 0x4 && Mask == -1) || (SYSmvalue > 0x4 && !Flags.empty()))
4003 return -1;
4004
4005 // The _g and _nzcvqg versions are only valid if the DSP extension is
4006 // available.
Artyom Skrobovcf296442015-09-24 17:31:16 +00004007 if (!Subtarget->hasDSP() && (Mask & 0x1))
Luke Cheeseman85fd06d2015-06-01 12:02:47 +00004008 return -1;
4009
4010 // The register was valid so need to put the mask in the correct place
4011 // (the flags need to be in bits 11-10) and combine with the SYSmvalue to
4012 // construct the operand for the instruction node.
4013 if (SYSmvalue < 0x4)
4014 return SYSmvalue | Mask << 10;
4015
4016 return SYSmvalue;
4017}
4018
4019static int getARClassRegisterMask(StringRef Reg, StringRef Flags) {
4020 // The mask operand contains the special register (R Bit) in bit 4, whether
4021 // the register is spsr (R bit is 1) or one of cpsr/apsr (R bit is 0), and
4022 // bits 3-0 contains the fields to be accessed in the special register, set by
4023 // the flags provided with the register.
4024 int Mask = 0;
4025 if (Reg == "apsr") {
4026 // The flags permitted for apsr are the same flags that are allowed in
4027 // M class registers. We get the flag value and then shift the flags into
4028 // the correct place to combine with the mask.
Artyom Skrobov6fbef2a2015-08-05 11:02:14 +00004029 Mask = getMClassFlagsMask(Flags, true);
Luke Cheeseman85fd06d2015-06-01 12:02:47 +00004030 if (Mask == -1)
4031 return -1;
4032 return Mask << 2;
4033 }
4034
4035 if (Reg != "cpsr" && Reg != "spsr") {
4036 return -1;
4037 }
4038
4039 // This is the same as if the flags were "fc"
4040 if (Flags.empty() || Flags == "all")
4041 return Mask | 0x9;
4042
4043 // Inspect the supplied flags string and set the bits in the mask for
4044 // the relevant and valid flags allowed for cpsr and spsr.
4045 for (char Flag : Flags) {
4046 int FlagVal;
4047 switch (Flag) {
4048 case 'c':
4049 FlagVal = 0x1;
4050 break;
4051 case 'x':
4052 FlagVal = 0x2;
4053 break;
4054 case 's':
4055 FlagVal = 0x4;
4056 break;
4057 case 'f':
4058 FlagVal = 0x8;
4059 break;
4060 default:
4061 FlagVal = 0;
4062 }
4063
4064 // This avoids allowing strings where the same flag bit appears twice.
4065 if (!FlagVal || (Mask & FlagVal))
4066 return -1;
4067 Mask |= FlagVal;
4068 }
4069
4070 // If the register is spsr then we need to set the R bit.
4071 if (Reg == "spsr")
4072 Mask |= 0x10;
4073
4074 return Mask;
4075}
4076
4077// Lower the read_register intrinsic to ARM specific DAG nodes
4078// using the supplied metadata string to select the instruction node to use
4079// and the registers/masks to construct as operands for the node.
Justin Bogner45571362016-05-12 00:31:09 +00004080bool ARMDAGToDAGISel::tryReadRegister(SDNode *N){
Luke Cheeseman85fd06d2015-06-01 12:02:47 +00004081 const MDNodeSDNode *MD = dyn_cast<MDNodeSDNode>(N->getOperand(1));
4082 const MDString *RegString = dyn_cast<MDString>(MD->getMD()->getOperand(0));
4083 bool IsThumb2 = Subtarget->isThumb2();
4084 SDLoc DL(N);
4085
4086 std::vector<SDValue> Ops;
4087 getIntOperandsFromRegisterString(RegString->getString(), CurDAG, DL, Ops);
4088
4089 if (!Ops.empty()) {
4090 // If the special register string was constructed of fields (as defined
4091 // in the ACLE) then need to lower to MRC node (32 bit) or
4092 // MRRC node(64 bit), we can make the distinction based on the number of
4093 // operands we have.
4094 unsigned Opcode;
4095 SmallVector<EVT, 3> ResTypes;
4096 if (Ops.size() == 5){
4097 Opcode = IsThumb2 ? ARM::t2MRC : ARM::MRC;
4098 ResTypes.append({ MVT::i32, MVT::Other });
4099 } else {
4100 assert(Ops.size() == 3 &&
4101 "Invalid number of fields in special register string.");
4102 Opcode = IsThumb2 ? ARM::t2MRRC : ARM::MRRC;
4103 ResTypes.append({ MVT::i32, MVT::i32, MVT::Other });
4104 }
4105
4106 Ops.push_back(getAL(CurDAG, DL));
4107 Ops.push_back(CurDAG->getRegister(0, MVT::i32));
4108 Ops.push_back(N->getOperand(0));
Justin Bogner45571362016-05-12 00:31:09 +00004109 ReplaceNode(N, CurDAG->getMachineNode(Opcode, DL, ResTypes, Ops));
4110 return true;
Luke Cheeseman85fd06d2015-06-01 12:02:47 +00004111 }
4112
4113 std::string SpecialReg = RegString->getString().lower();
4114
4115 int BankedReg = getBankedRegisterMask(SpecialReg);
4116 if (BankedReg != -1) {
4117 Ops = { CurDAG->getTargetConstant(BankedReg, DL, MVT::i32),
4118 getAL(CurDAG, DL), CurDAG->getRegister(0, MVT::i32),
4119 N->getOperand(0) };
Justin Bogner45571362016-05-12 00:31:09 +00004120 ReplaceNode(
4121 N, CurDAG->getMachineNode(IsThumb2 ? ARM::t2MRSbanked : ARM::MRSbanked,
4122 DL, MVT::i32, MVT::Other, Ops));
4123 return true;
Luke Cheeseman85fd06d2015-06-01 12:02:47 +00004124 }
4125
4126 // The VFP registers are read by creating SelectionDAG nodes with opcodes
4127 // corresponding to the register that is being read from. So we switch on the
4128 // string to find which opcode we need to use.
4129 unsigned Opcode = StringSwitch<unsigned>(SpecialReg)
4130 .Case("fpscr", ARM::VMRS)
4131 .Case("fpexc", ARM::VMRS_FPEXC)
4132 .Case("fpsid", ARM::VMRS_FPSID)
4133 .Case("mvfr0", ARM::VMRS_MVFR0)
4134 .Case("mvfr1", ARM::VMRS_MVFR1)
4135 .Case("mvfr2", ARM::VMRS_MVFR2)
4136 .Case("fpinst", ARM::VMRS_FPINST)
4137 .Case("fpinst2", ARM::VMRS_FPINST2)
4138 .Default(0);
4139
4140 // If an opcode was found then we can lower the read to a VFP instruction.
4141 if (Opcode) {
4142 if (!Subtarget->hasVFP2())
Justin Bogner45571362016-05-12 00:31:09 +00004143 return false;
Luke Cheeseman85fd06d2015-06-01 12:02:47 +00004144 if (Opcode == ARM::VMRS_MVFR2 && !Subtarget->hasFPARMv8())
Justin Bogner45571362016-05-12 00:31:09 +00004145 return false;
Luke Cheeseman85fd06d2015-06-01 12:02:47 +00004146
4147 Ops = { getAL(CurDAG, DL), CurDAG->getRegister(0, MVT::i32),
4148 N->getOperand(0) };
Justin Bogner45571362016-05-12 00:31:09 +00004149 ReplaceNode(N,
4150 CurDAG->getMachineNode(Opcode, DL, MVT::i32, MVT::Other, Ops));
4151 return true;
Luke Cheeseman85fd06d2015-06-01 12:02:47 +00004152 }
4153
4154 // If the target is M Class then need to validate that the register string
4155 // is an acceptable value, so check that a mask can be constructed from the
4156 // string.
4157 if (Subtarget->isMClass()) {
Bradley Smithf277c8a2016-01-25 11:25:36 +00004158 StringRef Flags = "", Reg = SpecialReg;
4159 if (Reg.endswith("_ns")) {
4160 Flags = "ns";
4161 Reg = Reg.drop_back(3);
4162 }
4163
4164 int SYSmValue = getMClassRegisterMask(Reg, Flags, true, Subtarget);
Luke Cheeseman85fd06d2015-06-01 12:02:47 +00004165 if (SYSmValue == -1)
Justin Bogner45571362016-05-12 00:31:09 +00004166 return false;
Luke Cheeseman85fd06d2015-06-01 12:02:47 +00004167
4168 SDValue Ops[] = { CurDAG->getTargetConstant(SYSmValue, DL, MVT::i32),
4169 getAL(CurDAG, DL), CurDAG->getRegister(0, MVT::i32),
4170 N->getOperand(0) };
Justin Bogner45571362016-05-12 00:31:09 +00004171 ReplaceNode(
4172 N, CurDAG->getMachineNode(ARM::t2MRS_M, DL, MVT::i32, MVT::Other, Ops));
4173 return true;
Luke Cheeseman85fd06d2015-06-01 12:02:47 +00004174 }
4175
4176 // Here we know the target is not M Class so we need to check if it is one
4177 // of the remaining possible values which are apsr, cpsr or spsr.
4178 if (SpecialReg == "apsr" || SpecialReg == "cpsr") {
4179 Ops = { getAL(CurDAG, DL), CurDAG->getRegister(0, MVT::i32),
4180 N->getOperand(0) };
Justin Bogner45571362016-05-12 00:31:09 +00004181 ReplaceNode(N, CurDAG->getMachineNode(IsThumb2 ? ARM::t2MRS_AR : ARM::MRS,
4182 DL, MVT::i32, MVT::Other, Ops));
4183 return true;
Luke Cheeseman85fd06d2015-06-01 12:02:47 +00004184 }
4185
4186 if (SpecialReg == "spsr") {
4187 Ops = { getAL(CurDAG, DL), CurDAG->getRegister(0, MVT::i32),
4188 N->getOperand(0) };
Justin Bogner45571362016-05-12 00:31:09 +00004189 ReplaceNode(
4190 N, CurDAG->getMachineNode(IsThumb2 ? ARM::t2MRSsys_AR : ARM::MRSsys, DL,
4191 MVT::i32, MVT::Other, Ops));
4192 return true;
Luke Cheeseman85fd06d2015-06-01 12:02:47 +00004193 }
4194
Justin Bogner45571362016-05-12 00:31:09 +00004195 return false;
Luke Cheeseman85fd06d2015-06-01 12:02:47 +00004196}
4197
4198// Lower the write_register intrinsic to ARM specific DAG nodes
4199// using the supplied metadata string to select the instruction node to use
4200// and the registers/masks to use in the nodes
Justin Bogner45571362016-05-12 00:31:09 +00004201bool ARMDAGToDAGISel::tryWriteRegister(SDNode *N){
Luke Cheeseman85fd06d2015-06-01 12:02:47 +00004202 const MDNodeSDNode *MD = dyn_cast<MDNodeSDNode>(N->getOperand(1));
4203 const MDString *RegString = dyn_cast<MDString>(MD->getMD()->getOperand(0));
4204 bool IsThumb2 = Subtarget->isThumb2();
4205 SDLoc DL(N);
4206
4207 std::vector<SDValue> Ops;
4208 getIntOperandsFromRegisterString(RegString->getString(), CurDAG, DL, Ops);
4209
4210 if (!Ops.empty()) {
4211 // If the special register string was constructed of fields (as defined
4212 // in the ACLE) then need to lower to MCR node (32 bit) or
4213 // MCRR node(64 bit), we can make the distinction based on the number of
4214 // operands we have.
4215 unsigned Opcode;
4216 if (Ops.size() == 5) {
4217 Opcode = IsThumb2 ? ARM::t2MCR : ARM::MCR;
4218 Ops.insert(Ops.begin()+2, N->getOperand(2));
4219 } else {
4220 assert(Ops.size() == 3 &&
4221 "Invalid number of fields in special register string.");
4222 Opcode = IsThumb2 ? ARM::t2MCRR : ARM::MCRR;
4223 SDValue WriteValue[] = { N->getOperand(2), N->getOperand(3) };
4224 Ops.insert(Ops.begin()+2, WriteValue, WriteValue+2);
4225 }
4226
4227 Ops.push_back(getAL(CurDAG, DL));
4228 Ops.push_back(CurDAG->getRegister(0, MVT::i32));
4229 Ops.push_back(N->getOperand(0));
4230
Justin Bogner45571362016-05-12 00:31:09 +00004231 ReplaceNode(N, CurDAG->getMachineNode(Opcode, DL, MVT::Other, Ops));
4232 return true;
Luke Cheeseman85fd06d2015-06-01 12:02:47 +00004233 }
4234
4235 std::string SpecialReg = RegString->getString().lower();
4236 int BankedReg = getBankedRegisterMask(SpecialReg);
4237 if (BankedReg != -1) {
4238 Ops = { CurDAG->getTargetConstant(BankedReg, DL, MVT::i32), N->getOperand(2),
4239 getAL(CurDAG, DL), CurDAG->getRegister(0, MVT::i32),
4240 N->getOperand(0) };
Justin Bogner45571362016-05-12 00:31:09 +00004241 ReplaceNode(
4242 N, CurDAG->getMachineNode(IsThumb2 ? ARM::t2MSRbanked : ARM::MSRbanked,
4243 DL, MVT::Other, Ops));
4244 return true;
Luke Cheeseman85fd06d2015-06-01 12:02:47 +00004245 }
4246
4247 // The VFP registers are written to by creating SelectionDAG nodes with
4248 // opcodes corresponding to the register that is being written. So we switch
4249 // on the string to find which opcode we need to use.
4250 unsigned Opcode = StringSwitch<unsigned>(SpecialReg)
4251 .Case("fpscr", ARM::VMSR)
4252 .Case("fpexc", ARM::VMSR_FPEXC)
4253 .Case("fpsid", ARM::VMSR_FPSID)
4254 .Case("fpinst", ARM::VMSR_FPINST)
4255 .Case("fpinst2", ARM::VMSR_FPINST2)
4256 .Default(0);
4257
4258 if (Opcode) {
4259 if (!Subtarget->hasVFP2())
Justin Bogner45571362016-05-12 00:31:09 +00004260 return false;
Luke Cheeseman85fd06d2015-06-01 12:02:47 +00004261 Ops = { N->getOperand(2), getAL(CurDAG, DL),
4262 CurDAG->getRegister(0, MVT::i32), N->getOperand(0) };
Justin Bogner45571362016-05-12 00:31:09 +00004263 ReplaceNode(N, CurDAG->getMachineNode(Opcode, DL, MVT::Other, Ops));
4264 return true;
Luke Cheeseman85fd06d2015-06-01 12:02:47 +00004265 }
4266
Bradley Smithf277c8a2016-01-25 11:25:36 +00004267 std::pair<StringRef, StringRef> Fields;
4268 Fields = StringRef(SpecialReg).rsplit('_');
4269 std::string Reg = Fields.first.str();
4270 StringRef Flags = Fields.second;
Luke Cheeseman85fd06d2015-06-01 12:02:47 +00004271
4272 // If the target was M Class then need to validate the special register value
4273 // and retrieve the mask for use in the instruction node.
4274 if (Subtarget->isMClass()) {
4275 // basepri_max gets split so need to correct Reg and Flags.
4276 if (SpecialReg == "basepri_max") {
4277 Reg = SpecialReg;
4278 Flags = "";
4279 }
4280 int SYSmValue = getMClassRegisterMask(Reg, Flags, false, Subtarget);
4281 if (SYSmValue == -1)
Justin Bogner45571362016-05-12 00:31:09 +00004282 return false;
Luke Cheeseman85fd06d2015-06-01 12:02:47 +00004283
4284 SDValue Ops[] = { CurDAG->getTargetConstant(SYSmValue, DL, MVT::i32),
4285 N->getOperand(2), getAL(CurDAG, DL),
4286 CurDAG->getRegister(0, MVT::i32), N->getOperand(0) };
Justin Bogner45571362016-05-12 00:31:09 +00004287 ReplaceNode(N, CurDAG->getMachineNode(ARM::t2MSR_M, DL, MVT::Other, Ops));
4288 return true;
Luke Cheeseman85fd06d2015-06-01 12:02:47 +00004289 }
4290
4291 // We then check to see if a valid mask can be constructed for one of the
4292 // register string values permitted for the A and R class cores. These values
4293 // are apsr, spsr and cpsr; these are also valid on older cores.
4294 int Mask = getARClassRegisterMask(Reg, Flags);
4295 if (Mask != -1) {
4296 Ops = { CurDAG->getTargetConstant(Mask, DL, MVT::i32), N->getOperand(2),
4297 getAL(CurDAG, DL), CurDAG->getRegister(0, MVT::i32),
4298 N->getOperand(0) };
Justin Bogner45571362016-05-12 00:31:09 +00004299 ReplaceNode(N, CurDAG->getMachineNode(IsThumb2 ? ARM::t2MSR_AR : ARM::MSR,
4300 DL, MVT::Other, Ops));
4301 return true;
Luke Cheeseman85fd06d2015-06-01 12:02:47 +00004302 }
4303
Justin Bogner45571362016-05-12 00:31:09 +00004304 return false;
Luke Cheeseman85fd06d2015-06-01 12:02:47 +00004305}
4306
Justin Bogner45571362016-05-12 00:31:09 +00004307bool ARMDAGToDAGISel::tryInlineAsm(SDNode *N){
Weiming Zhaoc5987002013-02-14 18:10:21 +00004308 std::vector<SDValue> AsmNodeOperands;
4309 unsigned Flag, Kind;
4310 bool Changed = false;
4311 unsigned NumOps = N->getNumOperands();
4312
Weiming Zhaoc5987002013-02-14 18:10:21 +00004313 // Normally, i64 data is bounded to two arbitrary GRPs for "%r" constraint.
4314 // However, some instrstions (e.g. ldrexd/strexd in ARM mode) require
4315 // (even/even+1) GPRs and use %n and %Hn to refer to the individual regs
4316 // respectively. Since there is no constraint to explicitly specify a
Weiming Zhaoa3d87a12013-06-28 17:26:02 +00004317 // reg pair, we use GPRPair reg class for "%r" for 64-bit data. For Thumb,
4318 // the 64-bit data may be referred by H, Q, R modifiers, so we still pack
4319 // them into a GPRPair.
Weiming Zhaoc5987002013-02-14 18:10:21 +00004320
Andrew Trickef9de2a2013-05-25 02:42:55 +00004321 SDLoc dl(N);
Craig Topper062a2ba2014-04-25 05:30:21 +00004322 SDValue Glue = N->getGluedNode() ? N->getOperand(NumOps-1)
4323 : SDValue(nullptr,0);
Weiming Zhaoc5987002013-02-14 18:10:21 +00004324
Weiming Zhaoa3d87a12013-06-28 17:26:02 +00004325 SmallVector<bool, 8> OpChanged;
Weiming Zhaoc5987002013-02-14 18:10:21 +00004326 // Glue node will be appended late.
Weiming Zhaoa3d87a12013-06-28 17:26:02 +00004327 for(unsigned i = 0, e = N->getGluedNode() ? NumOps - 1 : NumOps; i < e; ++i) {
Weiming Zhaoc5987002013-02-14 18:10:21 +00004328 SDValue op = N->getOperand(i);
4329 AsmNodeOperands.push_back(op);
4330
4331 if (i < InlineAsm::Op_FirstOperand)
4332 continue;
4333
4334 if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(N->getOperand(i))) {
4335 Flag = C->getZExtValue();
4336 Kind = InlineAsm::getKind(Flag);
4337 }
4338 else
4339 continue;
4340
Joey Gouly392cdad2013-07-08 19:52:51 +00004341 // Immediate operands to inline asm in the SelectionDAG are modeled with
4342 // two operands. The first is a constant of value InlineAsm::Kind_Imm, and
4343 // the second is a constant with the value of the immediate. If we get here
4344 // and we have a Kind_Imm, skip the next operand, and continue.
Joey Gouly606f3fb2013-07-05 10:19:40 +00004345 if (Kind == InlineAsm::Kind_Imm) {
4346 SDValue op = N->getOperand(++i);
4347 AsmNodeOperands.push_back(op);
4348 continue;
4349 }
4350
Weiming Zhaoa3d87a12013-06-28 17:26:02 +00004351 unsigned NumRegs = InlineAsm::getNumOperandRegisters(Flag);
4352 if (NumRegs)
4353 OpChanged.push_back(false);
4354
4355 unsigned DefIdx = 0;
4356 bool IsTiedToChangedOp = false;
4357 // If it's a use that is tied with a previous def, it has no
4358 // reg class constraint.
4359 if (Changed && InlineAsm::isUseOperandTiedToDef(Flag, DefIdx))
4360 IsTiedToChangedOp = OpChanged[DefIdx];
4361
Diana Picusf345d402016-07-20 09:48:24 +00004362 // Memory operands to inline asm in the SelectionDAG are modeled with two
4363 // operands: a constant of value InlineAsm::Kind_Mem followed by the input
4364 // operand. If we get here and we have a Kind_Mem, skip the next operand (so
4365 // it doesn't get misinterpreted), and continue. We do this here because
4366 // it's important to update the OpChanged array correctly before moving on.
4367 if (Kind == InlineAsm::Kind_Mem) {
4368 SDValue op = N->getOperand(++i);
4369 AsmNodeOperands.push_back(op);
4370 continue;
4371 }
4372
Weiming Zhaoc5987002013-02-14 18:10:21 +00004373 if (Kind != InlineAsm::Kind_RegUse && Kind != InlineAsm::Kind_RegDef
4374 && Kind != InlineAsm::Kind_RegDefEarlyClobber)
4375 continue;
4376
Weiming Zhaoc5987002013-02-14 18:10:21 +00004377 unsigned RC;
4378 bool HasRC = InlineAsm::hasRegClassConstraint(Flag, RC);
Weiming Zhaoa3d87a12013-06-28 17:26:02 +00004379 if ((!IsTiedToChangedOp && (!HasRC || RC != ARM::GPRRegClassID))
4380 || NumRegs != 2)
Weiming Zhaoc5987002013-02-14 18:10:21 +00004381 continue;
4382
Weiming Zhaoa3d87a12013-06-28 17:26:02 +00004383 assert((i+2 < NumOps) && "Invalid number of operands in inline asm");
Weiming Zhaoc5987002013-02-14 18:10:21 +00004384 SDValue V0 = N->getOperand(i+1);
4385 SDValue V1 = N->getOperand(i+2);
4386 unsigned Reg0 = cast<RegisterSDNode>(V0)->getReg();
4387 unsigned Reg1 = cast<RegisterSDNode>(V1)->getReg();
4388 SDValue PairedReg;
4389 MachineRegisterInfo &MRI = MF->getRegInfo();
4390
4391 if (Kind == InlineAsm::Kind_RegDef ||
4392 Kind == InlineAsm::Kind_RegDefEarlyClobber) {
4393 // Replace the two GPRs with 1 GPRPair and copy values from GPRPair to
4394 // the original GPRs.
4395
4396 unsigned GPVR = MRI.createVirtualRegister(&ARM::GPRPairRegClass);
4397 PairedReg = CurDAG->getRegister(GPVR, MVT::Untyped);
4398 SDValue Chain = SDValue(N,0);
4399
4400 SDNode *GU = N->getGluedUser();
4401 SDValue RegCopy = CurDAG->getCopyFromReg(Chain, dl, GPVR, MVT::Untyped,
4402 Chain.getValue(1));
4403
4404 // Extract values from a GPRPair reg and copy to the original GPR reg.
4405 SDValue Sub0 = CurDAG->getTargetExtractSubreg(ARM::gsub_0, dl, MVT::i32,
4406 RegCopy);
4407 SDValue Sub1 = CurDAG->getTargetExtractSubreg(ARM::gsub_1, dl, MVT::i32,
4408 RegCopy);
4409 SDValue T0 = CurDAG->getCopyToReg(Sub0, dl, Reg0, Sub0,
4410 RegCopy.getValue(1));
4411 SDValue T1 = CurDAG->getCopyToReg(Sub1, dl, Reg1, Sub1, T0.getValue(1));
4412
4413 // Update the original glue user.
4414 std::vector<SDValue> Ops(GU->op_begin(), GU->op_end()-1);
4415 Ops.push_back(T1.getValue(1));
Craig Topper8c0b4d02014-04-28 05:57:50 +00004416 CurDAG->UpdateNodeOperands(GU, Ops);
Weiming Zhaoc5987002013-02-14 18:10:21 +00004417 }
4418 else {
4419 // For Kind == InlineAsm::Kind_RegUse, we first copy two GPRs into a
4420 // GPRPair and then pass the GPRPair to the inline asm.
4421 SDValue Chain = AsmNodeOperands[InlineAsm::Op_InputChain];
4422
4423 // As REG_SEQ doesn't take RegisterSDNode, we copy them first.
4424 SDValue T0 = CurDAG->getCopyFromReg(Chain, dl, Reg0, MVT::i32,
4425 Chain.getValue(1));
4426 SDValue T1 = CurDAG->getCopyFromReg(Chain, dl, Reg1, MVT::i32,
4427 T0.getValue(1));
4428 SDValue Pair = SDValue(createGPRPairNode(MVT::Untyped, T0, T1), 0);
4429
4430 // Copy REG_SEQ into a GPRPair-typed VR and replace the original two
4431 // i32 VRs of inline asm with it.
4432 unsigned GPVR = MRI.createVirtualRegister(&ARM::GPRPairRegClass);
4433 PairedReg = CurDAG->getRegister(GPVR, MVT::Untyped);
4434 Chain = CurDAG->getCopyToReg(T1, dl, GPVR, Pair, T1.getValue(1));
4435
4436 AsmNodeOperands[InlineAsm::Op_InputChain] = Chain;
4437 Glue = Chain.getValue(1);
4438 }
4439
4440 Changed = true;
4441
4442 if(PairedReg.getNode()) {
Weiming Zhaoa3d87a12013-06-28 17:26:02 +00004443 OpChanged[OpChanged.size() -1 ] = true;
Weiming Zhaoc5987002013-02-14 18:10:21 +00004444 Flag = InlineAsm::getFlagWord(Kind, 1 /* RegNum*/);
Tim Northover55349a22013-08-18 18:06:03 +00004445 if (IsTiedToChangedOp)
4446 Flag = InlineAsm::getFlagWordForMatchingOp(Flag, DefIdx);
4447 else
4448 Flag = InlineAsm::getFlagWordForRegClass(Flag, ARM::GPRPairRegClassID);
Weiming Zhaoc5987002013-02-14 18:10:21 +00004449 // Replace the current flag.
4450 AsmNodeOperands[AsmNodeOperands.size() -1] = CurDAG->getTargetConstant(
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00004451 Flag, dl, MVT::i32);
Weiming Zhaoc5987002013-02-14 18:10:21 +00004452 // Add the new register node and skip the original two GPRs.
4453 AsmNodeOperands.push_back(PairedReg);
4454 // Skip the next two GPRs.
4455 i += 2;
4456 }
4457 }
4458
Weiming Zhaoa3d87a12013-06-28 17:26:02 +00004459 if (Glue.getNode())
4460 AsmNodeOperands.push_back(Glue);
Weiming Zhaoc5987002013-02-14 18:10:21 +00004461 if (!Changed)
Justin Bogner45571362016-05-12 00:31:09 +00004462 return false;
Weiming Zhaoc5987002013-02-14 18:10:21 +00004463
Andrew Trickef9de2a2013-05-25 02:42:55 +00004464 SDValue New = CurDAG->getNode(ISD::INLINEASM, SDLoc(N),
Craig Topper48d114b2014-04-26 18:35:24 +00004465 CurDAG->getVTList(MVT::Other, MVT::Glue), AsmNodeOperands);
Weiming Zhaoc5987002013-02-14 18:10:21 +00004466 New->setNodeId(-1);
Justin Bogner45571362016-05-12 00:31:09 +00004467 ReplaceNode(N, New.getNode());
4468 return true;
Weiming Zhaoc5987002013-02-14 18:10:21 +00004469}
4470
4471
Bob Wilsona2c462b2009-05-19 05:53:42 +00004472bool ARMDAGToDAGISel::
Daniel Sanders60f1db02015-03-13 12:45:09 +00004473SelectInlineAsmMemoryOperand(const SDValue &Op, unsigned ConstraintID,
Bob Wilsona2c462b2009-05-19 05:53:42 +00004474 std::vector<SDValue> &OutOps) {
Daniel Sanders1f58ef72015-06-03 12:33:56 +00004475 switch(ConstraintID) {
4476 default:
4477 llvm_unreachable("Unexpected asm memory constraint");
Daniel Sanders43a79bf2015-06-03 14:17:18 +00004478 case InlineAsm::Constraint_i:
4479 // FIXME: It seems strange that 'i' is needed here since it's supposed to
4480 // be an immediate and not a memory constraint.
Justin Bognerb03fd122016-08-17 05:10:15 +00004481 LLVM_FALLTHROUGH;
Daniel Sanders1f58ef72015-06-03 12:33:56 +00004482 case InlineAsm::Constraint_m:
James Molloy72222f52015-10-26 10:04:52 +00004483 case InlineAsm::Constraint_o:
Daniel Sanders1f58ef72015-06-03 12:33:56 +00004484 case InlineAsm::Constraint_Q:
4485 case InlineAsm::Constraint_Um:
4486 case InlineAsm::Constraint_Un:
4487 case InlineAsm::Constraint_Uq:
4488 case InlineAsm::Constraint_Us:
4489 case InlineAsm::Constraint_Ut:
4490 case InlineAsm::Constraint_Uv:
4491 case InlineAsm::Constraint_Uy:
4492 // Require the address to be in a register. That is safe for all ARM
4493 // variants and it is hard to do anything much smarter without knowing
4494 // how the operand is used.
4495 OutOps.push_back(Op);
4496 return false;
4497 }
4498 return true;
Bob Wilsona2c462b2009-05-19 05:53:42 +00004499}
4500
Rafael Espindolaffdc24b2006-05-14 22:18:28 +00004501/// createARMISelDag - This pass converts a legalized DAG into a
4502/// ARM-specific DAG, ready for instruction scheduling.
4503///
Bob Wilson2dd957f2009-09-28 14:30:20 +00004504FunctionPass *llvm::createARMISelDag(ARMBaseTargetMachine &TM,
4505 CodeGenOpt::Level OptLevel) {
4506 return new ARMDAGToDAGISel(TM, OptLevel);
Rafael Espindolaffdc24b2006-05-14 22:18:28 +00004507}