blob: 8f6515c423eb4283cc488918b34c8e9247201b83 [file] [log] [blame]
Rafael Espindolaffdc24b2006-05-14 22:18:28 +00001//===-- ARMISelDAGToDAG.cpp - A dag to dag inst selector for ARM ----------===//
2//
Chandler Carruth2946cd72019-01-19 08:50:56 +00003// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
Rafael Espindolaffdc24b2006-05-14 22:18:28 +00006//
7//===----------------------------------------------------------------------===//
8//
9// This file defines an instruction selector for the ARM target.
10//
11//===----------------------------------------------------------------------===//
12
13#include "ARM.h"
Evan Cheng62c7b5b2010-12-05 22:04:16 +000014#include "ARMBaseInstrInfo.h"
Rafael Espindolaffdc24b2006-05-14 22:18:28 +000015#include "ARMTargetMachine.h"
Evan Chenga20cde32011-07-20 23:34:39 +000016#include "MCTargetDesc/ARMAddressingModes.h"
David Blaikieb3bde2e2017-11-17 01:07:10 +000017#include "Utils/ARMBaseInfo.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"
David Blaikieb3bde2e2017-11-17 01:07:10 +000025#include "llvm/CodeGen/TargetLowering.h"
Chandler Carruth9fb823b2013-01-02 11:36:10 +000026#include "llvm/IR/CallingConv.h"
27#include "llvm/IR/Constants.h"
28#include "llvm/IR/DerivedTypes.h"
29#include "llvm/IR/Function.h"
30#include "llvm/IR/Intrinsics.h"
31#include "llvm/IR/LLVMContext.h"
Evan Cheng8e6b40a2010-05-04 20:39:49 +000032#include "llvm/Support/CommandLine.h"
Rafael Espindolaffdc24b2006-05-14 22:18:28 +000033#include "llvm/Support/Debug.h"
Torok Edwinfb8d6d52009-07-08 20:53:28 +000034#include "llvm/Support/ErrorHandling.h"
Chandler Carruthed0881b2012-12-03 16:50:05 +000035#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
Rafael Espindolaffdc24b2006-05-14 22:18:28 +000052class ARMDAGToDAGISel : public SelectionDAGISel {
Evan Cheng10043e22007-01-19 07:51:42 +000053 /// Subtarget - Keep a pointer to the ARMSubtarget around so that we can
54 /// make the right decision when generating code for different targets.
55 const ARMSubtarget *Subtarget;
56
Rafael Espindolaffdc24b2006-05-14 22:18:28 +000057public:
Eric Christopher2f991c92014-07-03 22:24:49 +000058 explicit ARMDAGToDAGISel(ARMBaseTargetMachine &tm, CodeGenOpt::Level OptLevel)
59 : SelectionDAGISel(tm, OptLevel) {}
Rafael Espindolaffdc24b2006-05-14 22:18:28 +000060
Eric Christopher0e6e7cf2014-05-22 02:00:27 +000061 bool runOnMachineFunction(MachineFunction &MF) override {
62 // Reset the subtarget each time through.
Eric Christopher22b2ad22015-02-20 08:24:37 +000063 Subtarget = &MF.getSubtarget<ARMSubtarget>();
Eric Christopher0e6e7cf2014-05-22 02:00:27 +000064 SelectionDAGISel::runOnMachineFunction(MF);
65 return true;
66 }
67
Mehdi Amini117296c2016-10-01 02:56:57 +000068 StringRef getPassName() const override { return "ARM Instruction Selection"; }
Anton Korobeynikov02bb33c2009-06-17 18:13:58 +000069
Craig Topper6bc27bf2014-03-10 02:09:33 +000070 void PreprocessISelDAG() override;
Evan Chengeae6d2c2012-12-19 20:16:09 +000071
Bob Wilson4facd962009-10-08 18:51:31 +000072 /// getI32Imm - Return a target constant of type i32 with the specified
73 /// value.
Benjamin Kramerbdc49562016-06-12 15:39:02 +000074 inline SDValue getI32Imm(unsigned Imm, const SDLoc &dl) {
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +000075 return CurDAG->getTargetConstant(Imm, dl, MVT::i32);
Anton Korobeynikov02bb33c2009-06-17 18:13:58 +000076 }
77
Justin Bogner45571362016-05-12 00:31:09 +000078 void Select(SDNode *N) override;
Evan Cheng62c7b5b2010-12-05 22:04:16 +000079
80 bool hasNoVMLxHazardUse(SDNode *N) const;
Evan Cheng59bbc542010-10-27 23:41:30 +000081 bool isShifterOpProfitable(const SDValue &Shift,
82 ARM_AM::ShiftOpc ShOpcVal, unsigned ShAmt);
Owen Andersonb595ed02011-07-21 18:54:16 +000083 bool SelectRegShifterOperand(SDValue N, SDValue &A,
84 SDValue &B, SDValue &C,
85 bool CheckProfitability = true);
86 bool SelectImmShifterOperand(SDValue N, SDValue &A,
Owen Anderson04912702011-07-21 23:38:37 +000087 SDValue &B, bool CheckProfitability = true);
88 bool SelectShiftRegShifterOperand(SDValue N, SDValue &A,
Owen Anderson6d557452011-03-18 19:46:58 +000089 SDValue &B, SDValue &C) {
90 // Don't apply the profitability check
Owen Anderson04912702011-07-21 23:38:37 +000091 return SelectRegShifterOperand(N, A, B, C, false);
92 }
93 bool SelectShiftImmShifterOperand(SDValue N, SDValue &A,
94 SDValue &B) {
95 // Don't apply the profitability check
96 return SelectImmShifterOperand(N, A, B, false);
Owen Anderson6d557452011-03-18 19:46:58 +000097 }
98
Tim Northover644a8192018-06-20 12:09:44 +000099 bool SelectAddLikeOr(SDNode *Parent, SDValue N, SDValue &Out);
100
Jim Grosbach1e4d9a12010-10-26 22:37:02 +0000101 bool SelectAddrModeImm12(SDValue N, SDValue &Base, SDValue &OffImm);
102 bool SelectLdStSOReg(SDValue N, SDValue &Base, SDValue &Offset, SDValue &Opc);
103
Tim Northover42180442013-08-22 09:57:11 +0000104 bool SelectCMOVPred(SDValue N, SDValue &Pred, SDValue &Reg) {
105 const ConstantSDNode *CN = cast<ConstantSDNode>(N);
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +0000106 Pred = CurDAG->getTargetConstant(CN->getZExtValue(), SDLoc(N), MVT::i32);
Tim Northover42180442013-08-22 09:57:11 +0000107 Reg = CurDAG->getRegister(ARM::CPSR, MVT::i32);
108 return true;
109 }
110
Owen Anderson2aedba62011-07-26 20:54:26 +0000111 bool SelectAddrMode2OffsetReg(SDNode *Op, SDValue N,
112 SDValue &Offset, SDValue &Opc);
113 bool SelectAddrMode2OffsetImm(SDNode *Op, SDValue N,
Dan Gohman2ce6f2a2008-07-27 21:46:04 +0000114 SDValue &Offset, SDValue &Opc);
Owen Anderson4d5c8f82011-08-29 20:16:50 +0000115 bool SelectAddrMode2OffsetImmPre(SDNode *Op, SDValue N,
116 SDValue &Offset, SDValue &Opc);
Jim Grosbachf0c95ca2011-08-05 20:35:44 +0000117 bool SelectAddrOffsetNone(SDValue N, SDValue &Base);
Chris Lattner0e023ea2010-09-21 20:31:19 +0000118 bool SelectAddrMode3(SDValue N, SDValue &Base,
Dan Gohman2ce6f2a2008-07-27 21:46:04 +0000119 SDValue &Offset, SDValue &Opc);
Dan Gohmanea6f91f2010-01-05 01:24:18 +0000120 bool SelectAddrMode3Offset(SDNode *Op, SDValue N,
Dan Gohman2ce6f2a2008-07-27 21:46:04 +0000121 SDValue &Offset, SDValue &Opc);
Oliver Stannard181afc72019-03-04 09:17:38 +0000122 bool IsAddressingMode5(SDValue N, SDValue &Base, SDValue &Offset, bool FP16);
Sjoerd Meijer011de9c2018-01-26 09:26:40 +0000123 bool SelectAddrMode5(SDValue N, SDValue &Base, SDValue &Offset);
124 bool SelectAddrMode5FP16(SDValue N, SDValue &Base, SDValue &Offset);
Bob Wilsondd9fbaa2010-11-01 23:40:51 +0000125 bool SelectAddrMode6(SDNode *Parent, SDValue N, SDValue &Addr,SDValue &Align);
Bob Wilsone3ecd5f2011-02-25 06:42:42 +0000126 bool SelectAddrMode6Offset(SDNode *Op, SDValue N, SDValue &Offset);
Rafael Espindolaffdc24b2006-05-14 22:18:28 +0000127
Evan Chengdfce83c2011-01-17 08:03:18 +0000128 bool SelectAddrModePC(SDValue N, SDValue &Offset, SDValue &Label);
Evan Cheng10043e22007-01-19 07:51:42 +0000129
Bill Wendling092a7bd2010-12-14 03:36:38 +0000130 // Thumb Addressing Modes:
Chris Lattner0e023ea2010-09-21 20:31:19 +0000131 bool SelectThumbAddrModeRR(SDValue N, SDValue &Base, SDValue &Offset);
David Green54b01152019-01-29 10:40:31 +0000132 bool SelectThumbAddrModeRRSext(SDValue N, SDValue &Base, SDValue &Offset);
Bill Wendling092a7bd2010-12-14 03:36:38 +0000133 bool SelectThumbAddrModeImm5S(SDValue N, unsigned Scale, SDValue &Base,
134 SDValue &OffImm);
135 bool SelectThumbAddrModeImm5S1(SDValue N, SDValue &Base,
136 SDValue &OffImm);
137 bool SelectThumbAddrModeImm5S2(SDValue N, SDValue &Base,
138 SDValue &OffImm);
139 bool SelectThumbAddrModeImm5S4(SDValue N, SDValue &Base,
140 SDValue &OffImm);
Chris Lattner0e023ea2010-09-21 20:31:19 +0000141 bool SelectThumbAddrModeSP(SDValue N, SDValue &Base, SDValue &OffImm);
David Green91724b82019-09-17 15:32:28 +0000142 template <unsigned Shift>
143 bool SelectTAddrModeImm7(SDValue N, SDValue &Base, SDValue &OffImm);
Evan Cheng10043e22007-01-19 07:51:42 +0000144
Bill Wendling092a7bd2010-12-14 03:36:38 +0000145 // Thumb 2 Addressing Modes:
Chris Lattner0e023ea2010-09-21 20:31:19 +0000146 bool SelectT2AddrModeImm12(SDValue N, SDValue &Base, SDValue &OffImm);
147 bool SelectT2AddrModeImm8(SDValue N, SDValue &Base,
Evan Chengb23b50d2009-06-29 07:51:04 +0000148 SDValue &OffImm);
Dan Gohmanea6f91f2010-01-05 01:24:18 +0000149 bool SelectT2AddrModeImm8Offset(SDNode *Op, SDValue N,
Evan Cheng84c6cda2009-07-02 07:28:31 +0000150 SDValue &OffImm);
David Green27ca82f2019-08-08 15:27:58 +0000151 template <unsigned Shift>
152 bool SelectT2AddrModeImm7Offset(SDNode *Op, SDValue N, SDValue &OffImm);
153 bool SelectT2AddrModeImm7Offset(SDNode *Op, SDValue N, SDValue &OffImm,
154 unsigned Shift);
155 template <unsigned Shift>
156 bool SelectT2AddrModeImm7(SDValue N, SDValue &Base, SDValue &OffImm);
Chris Lattner0e023ea2010-09-21 20:31:19 +0000157 bool SelectT2AddrModeSoReg(SDValue N, SDValue &Base,
Evan Chengb23b50d2009-06-29 07:51:04 +0000158 SDValue &OffReg, SDValue &ShImm);
Tim Northovera7ecd242013-07-16 09:46:55 +0000159 bool SelectT2AddrModeExclusive(SDValue N, SDValue &Base, SDValue &OffImm);
Evan Chengb23b50d2009-06-29 07:51:04 +0000160
Evan Cheng0fc80842010-11-12 22:42:47 +0000161 inline bool is_so_imm(unsigned Imm) const {
162 return ARM_AM::getSOImmVal(Imm) != -1;
163 }
164
165 inline bool is_so_imm_not(unsigned Imm) const {
166 return ARM_AM::getSOImmVal(~Imm) != -1;
167 }
168
169 inline bool is_t2_so_imm(unsigned Imm) const {
170 return ARM_AM::getT2SOImmVal(Imm) != -1;
171 }
172
173 inline bool is_t2_so_imm_not(unsigned Imm) const {
174 return ARM_AM::getT2SOImmVal(~Imm) != -1;
175 }
176
Rafael Espindolaffdc24b2006-05-14 22:18:28 +0000177 // Include the pieces autogenerated from the target description.
178#include "ARMGenDAGISel.inc"
Bob Wilsona2c462b2009-05-19 05:53:42 +0000179
180private:
Tim Northovereaee28b2016-09-19 09:11:09 +0000181 void transferMemOperands(SDNode *Src, SDNode *Dst);
182
Justin Bogner45571362016-05-12 00:31:09 +0000183 /// Indexed (pre/post inc/dec) load matching code for ARM.
184 bool tryARMIndexedLoad(SDNode *N);
James Molloyb3326df2016-07-15 08:03:56 +0000185 bool tryT1IndexedLoad(SDNode *N);
Justin Bogner45571362016-05-12 00:31:09 +0000186 bool tryT2IndexedLoad(SDNode *N);
David Green27ca82f2019-08-08 15:27:58 +0000187 bool tryMVEIndexedLoad(SDNode *N);
Evan Cheng84c6cda2009-07-02 07:28:31 +0000188
Bob Wilson340861d2010-03-23 05:25:43 +0000189 /// SelectVLD - Select NEON load intrinsics. NumVecs should be
190 /// 1, 2, 3 or 4. The opcode arrays specify the instructions used for
Bob Wilson12b47992009-10-14 17:28:52 +0000191 /// loads of D registers and even subregs and odd subregs of Q registers.
Bob Wilson340861d2010-03-23 05:25:43 +0000192 /// For NumVecs <= 2, QOpcodes1 is not used.
Justin Bogner45571362016-05-12 00:31:09 +0000193 void SelectVLD(SDNode *N, bool isUpdating, unsigned NumVecs,
194 const uint16_t *DOpcodes, const uint16_t *QOpcodes0,
195 const uint16_t *QOpcodes1);
Bob Wilson12b47992009-10-14 17:28:52 +0000196
Bob Wilsonc350cdf2009-10-14 18:32:29 +0000197 /// SelectVST - Select NEON store intrinsics. NumVecs should
Bob Wilsoncc0a2a72010-03-23 06:20:33 +0000198 /// be 1, 2, 3 or 4. The opcode arrays specify the instructions used for
Bob Wilsonc350cdf2009-10-14 18:32:29 +0000199 /// stores of D registers and even subregs and odd subregs of Q registers.
Bob Wilsoncc0a2a72010-03-23 06:20:33 +0000200 /// For NumVecs <= 2, QOpcodes1 is not used.
Justin Bogner45571362016-05-12 00:31:09 +0000201 void SelectVST(SDNode *N, bool isUpdating, unsigned NumVecs,
202 const uint16_t *DOpcodes, const uint16_t *QOpcodes0,
203 const uint16_t *QOpcodes1);
Bob Wilsonc350cdf2009-10-14 18:32:29 +0000204
Bob Wilson93117bc2009-10-14 16:46:45 +0000205 /// SelectVLDSTLane - Select NEON load/store lane intrinsics. NumVecs should
Bob Wilson4145e3a2009-10-14 16:19:03 +0000206 /// be 2, 3 or 4. The opcode arrays specify the instructions used for
Bob Wilsond5c57a52010-09-13 23:01:35 +0000207 /// load/store of D registers and Q registers.
Justin Bogner45571362016-05-12 00:31:09 +0000208 void SelectVLDSTLane(SDNode *N, bool IsLoad, bool isUpdating,
209 unsigned NumVecs, const uint16_t *DOpcodes,
210 const uint16_t *QOpcodes);
Bob Wilson4145e3a2009-10-14 16:19:03 +0000211
Bob Wilson2d790df2010-11-28 06:51:26 +0000212 /// SelectVLDDup - Select NEON load-duplicate intrinsics. NumVecs
Eli Friedmanf624ec22016-12-16 18:44:08 +0000213 /// should be 1, 2, 3 or 4. The opcode array specifies the instructions used
Ivan A. Kosarev72315982018-06-27 13:57:52 +0000214 /// for loading D registers.
215 void SelectVLDDup(SDNode *N, bool IsIntrinsic, bool isUpdating,
216 unsigned NumVecs, const uint16_t *DOpcodes,
217 const uint16_t *QOpcodes0 = nullptr,
218 const uint16_t *QOpcodes1 = nullptr);
Bob Wilson2d790df2010-11-28 06:51:26 +0000219
Justin Bogner45571362016-05-12 00:31:09 +0000220 /// Try to select SBFX/UBFX instructions for ARM.
221 bool tryV6T2BitfieldExtractOp(SDNode *N, bool isSigned);
Sandeep Patel423e42b2009-10-13 18:59:48 +0000222
Bill Wendlinga7d697e2011-10-10 22:59:55 +0000223 // Select special operations if node forms integer ABS pattern
Justin Bogner45571362016-05-12 00:31:09 +0000224 bool tryABSOp(SDNode *N);
Bill Wendlinga7d697e2011-10-10 22:59:55 +0000225
Justin Bogner45571362016-05-12 00:31:09 +0000226 bool tryReadRegister(SDNode *N);
227 bool tryWriteRegister(SDNode *N);
Luke Cheeseman85fd06d2015-06-01 12:02:47 +0000228
Justin Bogner45571362016-05-12 00:31:09 +0000229 bool tryInlineAsm(SDNode *N);
Weiming Zhaoc5987002013-02-14 18:10:21 +0000230
Sjoerd Meijer96e10b52016-12-15 09:38:59 +0000231 void SelectCMPZ(SDNode *N, bool &SwitchEQNEToPLMI);
James Molloye7d97362016-11-03 14:08:01 +0000232
Justin Bogner45571362016-05-12 00:31:09 +0000233 void SelectCMP_SWAP(SDNode *N);
Tim Northoverb629c772016-04-18 21:48:55 +0000234
Evan Chengd9c55362009-07-02 01:23:32 +0000235 /// SelectInlineAsmMemoryOperand - Implement addressing mode selection for
236 /// inline asm expressions.
Daniel Sanders60f1db02015-03-13 12:45:09 +0000237 bool SelectInlineAsmMemoryOperand(const SDValue &Op, unsigned ConstraintID,
Craig Topper6bc27bf2014-03-10 02:09:33 +0000238 std::vector<SDValue> &OutOps) override;
Bob Wilsone6b778d2009-10-06 22:01:59 +0000239
Weiming Zhao95782222012-11-17 00:23:35 +0000240 // Form pairs of consecutive R, S, D, or Q registers.
Weiming Zhao8f56f882012-11-16 21:55:34 +0000241 SDNode *createGPRPairNode(EVT VT, SDValue V0, SDValue V1);
Weiming Zhao95782222012-11-17 00:23:35 +0000242 SDNode *createSRegPairNode(EVT VT, SDValue V0, SDValue V1);
243 SDNode *createDRegPairNode(EVT VT, SDValue V0, SDValue V1);
244 SDNode *createQRegPairNode(EVT VT, SDValue V0, SDValue V1);
Evan Chengc2ae5f52010-05-10 17:34:18 +0000245
Bob Wilsond8a9a042010-06-04 00:04:02 +0000246 // Form sequences of 4 consecutive S, D, or Q registers.
Weiming Zhao95782222012-11-17 00:23:35 +0000247 SDNode *createQuadSRegsNode(EVT VT, SDValue V0, SDValue V1, SDValue V2, SDValue V3);
248 SDNode *createQuadDRegsNode(EVT VT, SDValue V0, SDValue V1, SDValue V2, SDValue V3);
249 SDNode *createQuadQRegsNode(EVT VT, SDValue V0, SDValue V1, SDValue V2, SDValue V3);
Bob Wilsondd9fbaa2010-11-01 23:40:51 +0000250
251 // Get the alignment operand for a NEON VLD or VST instruction.
Benjamin Kramerbdc49562016-06-12 15:39:02 +0000252 SDValue GetVLDSTAlign(SDValue Align, const SDLoc &dl, unsigned NumVecs,
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +0000253 bool is64BitVector);
John Brawn056e6782015-09-14 15:19:41 +0000254
John Brawn056e6782015-09-14 15:19:41 +0000255 /// Checks if N is a multiplication by a constant where we can extract out a
256 /// power of two from the constant so that it can be used in a shift, but only
257 /// if it simplifies the materialization of the constant. Returns true if it
258 /// is, and assigns to PowerOfTwo the power of two that should be extracted
259 /// out and to NewMulConst the new constant to be multiplied by.
260 bool canExtractShiftFromMul(const SDValue &N, unsigned MaxShift,
261 unsigned &PowerOfTwo, SDValue &NewMulConst) const;
262
263 /// Replace N with M in CurDAG, in a way that also ensures that M gets
264 /// selected when N would have been selected.
265 void replaceDAGValue(const SDValue &N, SDValue M);
Rafael Espindolaffdc24b2006-05-14 22:18:28 +0000266};
Alexander Kornienkof00654e2015-06-23 09:49:53 +0000267}
Rafael Espindolaffdc24b2006-05-14 22:18:28 +0000268
Sandeep Patel423e42b2009-10-13 18:59:48 +0000269/// isInt32Immediate - This method tests to see if the node is a 32-bit constant
270/// operand. If so Imm will receive the 32-bit value.
271static bool isInt32Immediate(SDNode *N, unsigned &Imm) {
272 if (N->getOpcode() == ISD::Constant && N->getValueType(0) == MVT::i32) {
273 Imm = cast<ConstantSDNode>(N)->getZExtValue();
274 return true;
275 }
276 return false;
277}
278
279// isInt32Immediate - This method tests to see if a constant operand.
280// If so Imm will receive the 32 bit value.
281static bool isInt32Immediate(SDValue N, unsigned &Imm) {
282 return isInt32Immediate(N.getNode(), Imm);
283}
284
285// isOpcWithIntImmediate - This method tests to see if the node is a specific
286// opcode and that it has a immediate integer right operand.
287// If so Imm will receive the 32 bit value.
288static bool isOpcWithIntImmediate(SDNode *N, unsigned Opc, unsigned& Imm) {
289 return N->getOpcode() == Opc &&
290 isInt32Immediate(N->getOperand(1).getNode(), Imm);
291}
292
Adrian Prantl5f8f34e42018-05-01 15:54:18 +0000293/// Check whether a particular node is a constant value representable as
Dmitri Gribenko5485acd2012-09-14 14:57:36 +0000294/// (N * Scale) where (N in [\p RangeMin, \p RangeMax).
Daniel Dunbare0cd9ac2011-01-19 15:12:16 +0000295///
296/// \param ScaledConstant [out] - On success, the pre-scaled constant value.
Jakob Stoklund Olesen2056d152011-09-23 22:10:33 +0000297static bool isScaledConstantInRange(SDValue Node, int Scale,
Daniel Dunbare0cd9ac2011-01-19 15:12:16 +0000298 int RangeMin, int RangeMax,
299 int &ScaledConstant) {
Jakob Stoklund Olesen2056d152011-09-23 22:10:33 +0000300 assert(Scale > 0 && "Invalid scale!");
Daniel Dunbare0cd9ac2011-01-19 15:12:16 +0000301
302 // Check that this is a constant.
303 const ConstantSDNode *C = dyn_cast<ConstantSDNode>(Node);
304 if (!C)
305 return false;
306
307 ScaledConstant = (int) C->getZExtValue();
308 if ((ScaledConstant % Scale) != 0)
309 return false;
310
311 ScaledConstant /= Scale;
312 return ScaledConstant >= RangeMin && ScaledConstant < RangeMax;
313}
314
Evan Chengeae6d2c2012-12-19 20:16:09 +0000315void ARMDAGToDAGISel::PreprocessISelDAG() {
316 if (!Subtarget->hasV6T2Ops())
317 return;
318
319 bool isThumb2 = Subtarget->isThumb();
320 for (SelectionDAG::allnodes_iterator I = CurDAG->allnodes_begin(),
321 E = CurDAG->allnodes_end(); I != E; ) {
Duncan P. N. Exon Smith9f9559e2015-10-19 23:25:57 +0000322 SDNode *N = &*I++; // Preincrement iterator to avoid invalidation issues.
Evan Chengeae6d2c2012-12-19 20:16:09 +0000323
324 if (N->getOpcode() != ISD::ADD)
325 continue;
326
327 // Look for (add X1, (and (srl X2, c1), c2)) where c2 is constant with
328 // leading zeros, followed by consecutive set bits, followed by 1 or 2
329 // trailing zeros, e.g. 1020.
330 // Transform the expression to
331 // (add X1, (shl (and (srl X2, c1), (c2>>tz)), tz)) where tz is the number
332 // of trailing zeros of c2. The left shift would be folded as an shifter
333 // operand of 'add' and the 'and' and 'srl' would become a bits extraction
334 // node (UBFX).
335
336 SDValue N0 = N->getOperand(0);
337 SDValue N1 = N->getOperand(1);
338 unsigned And_imm = 0;
339 if (!isOpcWithIntImmediate(N1.getNode(), ISD::AND, And_imm)) {
340 if (isOpcWithIntImmediate(N0.getNode(), ISD::AND, And_imm))
341 std::swap(N0, N1);
342 }
343 if (!And_imm)
344 continue;
345
346 // Check if the AND mask is an immediate of the form: 000.....1111111100
Michael J. Spencerdf1ecbd72013-05-24 22:23:49 +0000347 unsigned TZ = countTrailingZeros(And_imm);
Evan Chengeae6d2c2012-12-19 20:16:09 +0000348 if (TZ != 1 && TZ != 2)
349 // Be conservative here. Shifter operands aren't always free. e.g. On
350 // Swift, left shifter operand of 1 / 2 for free but others are not.
351 // e.g.
352 // ubfx r3, r1, #16, #8
353 // ldr.w r3, [r0, r3, lsl #2]
354 // vs.
355 // mov.w r9, #1020
356 // and.w r2, r9, r1, lsr #14
357 // ldr r2, [r0, r2]
358 continue;
359 And_imm >>= TZ;
360 if (And_imm & (And_imm + 1))
361 continue;
362
363 // Look for (and (srl X, c1), c2).
364 SDValue Srl = N1.getOperand(0);
365 unsigned Srl_imm = 0;
366 if (!isOpcWithIntImmediate(Srl.getNode(), ISD::SRL, Srl_imm) ||
367 (Srl_imm <= 2))
368 continue;
369
370 // Make sure first operand is not a shifter operand which would prevent
371 // folding of the left shift.
372 SDValue CPTmp0;
373 SDValue CPTmp1;
374 SDValue CPTmp2;
375 if (isThumb2) {
John Brawnd8b405a2015-09-07 11:45:18 +0000376 if (SelectImmShifterOperand(N0, CPTmp0, CPTmp1))
Evan Chengeae6d2c2012-12-19 20:16:09 +0000377 continue;
378 } else {
379 if (SelectImmShifterOperand(N0, CPTmp0, CPTmp1) ||
380 SelectRegShifterOperand(N0, CPTmp0, CPTmp1, CPTmp2))
381 continue;
382 }
383
384 // Now make the transformation.
Andrew Trickef9de2a2013-05-25 02:42:55 +0000385 Srl = CurDAG->getNode(ISD::SRL, SDLoc(Srl), MVT::i32,
Evan Chengeae6d2c2012-12-19 20:16:09 +0000386 Srl.getOperand(0),
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +0000387 CurDAG->getConstant(Srl_imm + TZ, SDLoc(Srl),
388 MVT::i32));
Andrew Trickef9de2a2013-05-25 02:42:55 +0000389 N1 = CurDAG->getNode(ISD::AND, SDLoc(N1), MVT::i32,
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +0000390 Srl,
391 CurDAG->getConstant(And_imm, SDLoc(Srl), MVT::i32));
Andrew Trickef9de2a2013-05-25 02:42:55 +0000392 N1 = CurDAG->getNode(ISD::SHL, SDLoc(N1), MVT::i32,
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +0000393 N1, CurDAG->getConstant(TZ, SDLoc(Srl), MVT::i32));
Evan Chengeae6d2c2012-12-19 20:16:09 +0000394 CurDAG->UpdateNodeOperands(N, N0, N1);
Jim Grosbach1a597112014-04-03 23:43:18 +0000395 }
Evan Chengeae6d2c2012-12-19 20:16:09 +0000396}
397
Evan Cheng62c7b5b2010-12-05 22:04:16 +0000398/// hasNoVMLxHazardUse - Return true if it's desirable to select a FP MLA / MLS
399/// node. VFP / NEON fp VMLA / VMLS instructions have special RAW hazards (at
400/// least on current ARM implementations) which should be avoidded.
401bool ARMDAGToDAGISel::hasNoVMLxHazardUse(SDNode *N) const {
402 if (OptLevel == CodeGenOpt::None)
403 return true;
404
Diana Picus575f2bb2016-07-07 09:11:39 +0000405 if (!Subtarget->hasVMLxHazards())
Evan Cheng62c7b5b2010-12-05 22:04:16 +0000406 return true;
407
408 if (!N->hasOneUse())
409 return false;
410
411 SDNode *Use = *N->use_begin();
412 if (Use->getOpcode() == ISD::CopyToReg)
413 return true;
414 if (Use->isMachineOpcode()) {
Eric Christopher2f991c92014-07-03 22:24:49 +0000415 const ARMBaseInstrInfo *TII = static_cast<const ARMBaseInstrInfo *>(
Eric Christopherfc6de422014-08-05 02:39:49 +0000416 CurDAG->getSubtarget().getInstrInfo());
Bill Wendlinga3cd3502013-06-19 21:36:55 +0000417
Evan Cheng6cc775f2011-06-28 19:10:37 +0000418 const MCInstrDesc &MCID = TII->get(Use->getMachineOpcode());
419 if (MCID.mayStore())
Evan Cheng62c7b5b2010-12-05 22:04:16 +0000420 return true;
Evan Cheng6cc775f2011-06-28 19:10:37 +0000421 unsigned Opcode = MCID.getOpcode();
Evan Cheng62c7b5b2010-12-05 22:04:16 +0000422 if (Opcode == ARM::VMOVRS || Opcode == ARM::VMOVRRD)
423 return true;
424 // vmlx feeding into another vmlx. We actually want to unfold
425 // the use later in the MLxExpansion pass. e.g.
426 // vmla
427 // vmla (stall 8 cycles)
428 //
429 // vmul (5 cycles)
430 // vadd (5 cycles)
431 // vmla
432 // This adds up to about 18 - 19 cycles.
433 //
434 // vmla
435 // vmul (stall 4 cycles)
436 // vadd adds up to about 14 cycles.
437 return TII->isFpMLxInstruction(Opcode);
438 }
439
440 return false;
441}
Sandeep Patel423e42b2009-10-13 18:59:48 +0000442
Evan Cheng59bbc542010-10-27 23:41:30 +0000443bool ARMDAGToDAGISel::isShifterOpProfitable(const SDValue &Shift,
444 ARM_AM::ShiftOpc ShOpcVal,
445 unsigned ShAmt) {
Bob Wilsone8a549c2012-09-29 21:43:49 +0000446 if (!Subtarget->isLikeA9() && !Subtarget->isSwift())
Evan Cheng59bbc542010-10-27 23:41:30 +0000447 return true;
448 if (Shift.hasOneUse())
449 return true;
450 // R << 2 is free.
Bob Wilsone8a549c2012-09-29 21:43:49 +0000451 return ShOpcVal == ARM_AM::lsl &&
452 (ShAmt == 2 || (Subtarget->isSwift() && ShAmt == 1));
Evan Cheng59bbc542010-10-27 23:41:30 +0000453}
454
John Brawn056e6782015-09-14 15:19:41 +0000455bool ARMDAGToDAGISel::canExtractShiftFromMul(const SDValue &N,
456 unsigned MaxShift,
457 unsigned &PowerOfTwo,
458 SDValue &NewMulConst) const {
459 assert(N.getOpcode() == ISD::MUL);
460 assert(MaxShift > 0);
461
462 // If the multiply is used in more than one place then changing the constant
463 // will make other uses incorrect, so don't.
464 if (!N.hasOneUse()) return false;
465 // Check if the multiply is by a constant
466 ConstantSDNode *MulConst = dyn_cast<ConstantSDNode>(N.getOperand(1));
467 if (!MulConst) return false;
468 // If the constant is used in more than one place then modifying it will mean
469 // we need to materialize two constants instead of one, which is a bad idea.
470 if (!MulConst->hasOneUse()) return false;
471 unsigned MulConstVal = MulConst->getZExtValue();
472 if (MulConstVal == 0) return false;
473
474 // Find the largest power of 2 that MulConstVal is a multiple of
475 PowerOfTwo = MaxShift;
476 while ((MulConstVal % (1 << PowerOfTwo)) != 0) {
477 --PowerOfTwo;
478 if (PowerOfTwo == 0) return false;
479 }
480
481 // Only optimise if the new cost is better
482 unsigned NewMulConstVal = MulConstVal / (1 << PowerOfTwo);
483 NewMulConst = CurDAG->getConstant(NewMulConstVal, SDLoc(N), MVT::i32);
David Green61973d92019-09-03 11:06:24 +0000484 unsigned OldCost = ConstantMaterializationCost(MulConstVal, Subtarget);
485 unsigned NewCost = ConstantMaterializationCost(NewMulConstVal, Subtarget);
John Brawn056e6782015-09-14 15:19:41 +0000486 return NewCost < OldCost;
487}
488
489void ARMDAGToDAGISel::replaceDAGValue(const SDValue &N, SDValue M) {
Duncan P. N. Exon Smith9f9559e2015-10-19 23:25:57 +0000490 CurDAG->RepositionNode(N.getNode()->getIterator(), M.getNode());
Nirav Dave3264c1b2018-03-19 20:19:46 +0000491 ReplaceUses(N, M);
John Brawn056e6782015-09-14 15:19:41 +0000492}
493
Owen Andersonb595ed02011-07-21 18:54:16 +0000494bool ARMDAGToDAGISel::SelectImmShifterOperand(SDValue N,
Evan Chengb23b50d2009-06-29 07:51:04 +0000495 SDValue &BaseReg,
Owen Anderson6d557452011-03-18 19:46:58 +0000496 SDValue &Opc,
497 bool CheckProfitability) {
Evan Cheng59069ec2010-07-30 23:33:54 +0000498 if (DisableShifterOp)
499 return false;
500
John Brawn056e6782015-09-14 15:19:41 +0000501 // If N is a multiply-by-constant and it's profitable to extract a shift and
502 // use it in a shifted operand do so.
503 if (N.getOpcode() == ISD::MUL) {
504 unsigned PowerOfTwo = 0;
505 SDValue NewMulConst;
506 if (canExtractShiftFromMul(N, 31, PowerOfTwo, NewMulConst)) {
Justin Bogner8752be72016-05-05 01:43:49 +0000507 HandleSDNode Handle(N);
Benjamin Kramer58dadd52017-04-20 18:29:14 +0000508 SDLoc Loc(N);
John Brawn056e6782015-09-14 15:19:41 +0000509 replaceDAGValue(N.getOperand(1), NewMulConst);
Justin Bogner8752be72016-05-05 01:43:49 +0000510 BaseReg = Handle.getValue();
Benjamin Kramer58dadd52017-04-20 18:29:14 +0000511 Opc = CurDAG->getTargetConstant(
512 ARM_AM::getSORegOpc(ARM_AM::lsl, PowerOfTwo), Loc, MVT::i32);
John Brawn056e6782015-09-14 15:19:41 +0000513 return true;
514 }
515 }
516
Evan Chenga20cde32011-07-20 23:34:39 +0000517 ARM_AM::ShiftOpc ShOpcVal = ARM_AM::getShiftOpcForNode(N.getOpcode());
Evan Chengb23b50d2009-06-29 07:51:04 +0000518
519 // Don't match base register only case. That is matched to a separate
520 // lower complexity pattern with explicit register operand.
521 if (ShOpcVal == ARM_AM::no_shift) return false;
Jim Grosbachf24f9d92009-08-11 15:33:49 +0000522
Evan Chengb23b50d2009-06-29 07:51:04 +0000523 BaseReg = N.getOperand(0);
524 unsigned ShImmVal = 0;
Owen Andersonb595ed02011-07-21 18:54:16 +0000525 ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(N.getOperand(1));
526 if (!RHS) return false;
Owen Andersonb595ed02011-07-21 18:54:16 +0000527 ShImmVal = RHS->getZExtValue() & 31;
Evan Cheng59bbc542010-10-27 23:41:30 +0000528 Opc = CurDAG->getTargetConstant(ARM_AM::getSORegOpc(ShOpcVal, ShImmVal),
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +0000529 SDLoc(N), MVT::i32);
Evan Cheng59bbc542010-10-27 23:41:30 +0000530 return true;
531}
532
Owen Andersonb595ed02011-07-21 18:54:16 +0000533bool ARMDAGToDAGISel::SelectRegShifterOperand(SDValue N,
534 SDValue &BaseReg,
535 SDValue &ShReg,
536 SDValue &Opc,
537 bool CheckProfitability) {
538 if (DisableShifterOp)
539 return false;
540
541 ARM_AM::ShiftOpc ShOpcVal = ARM_AM::getShiftOpcForNode(N.getOpcode());
542
543 // Don't match base register only case. That is matched to a separate
544 // lower complexity pattern with explicit register operand.
545 if (ShOpcVal == ARM_AM::no_shift) return false;
546
547 BaseReg = N.getOperand(0);
548 unsigned ShImmVal = 0;
549 ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(N.getOperand(1));
550 if (RHS) return false;
551
552 ShReg = N.getOperand(1);
553 if (CheckProfitability && !isShifterOpProfitable(N, ShOpcVal, ShImmVal))
554 return false;
555 Opc = CurDAG->getTargetConstant(ARM_AM::getSORegOpc(ShOpcVal, ShImmVal),
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +0000556 SDLoc(N), MVT::i32);
Owen Andersonb595ed02011-07-21 18:54:16 +0000557 return true;
558}
559
Tim Northover644a8192018-06-20 12:09:44 +0000560// Determine whether an ISD::OR's operands are suitable to turn the operation
561// into an addition, which often has more compact encodings.
562bool ARMDAGToDAGISel::SelectAddLikeOr(SDNode *Parent, SDValue N, SDValue &Out) {
563 assert(Parent->getOpcode() == ISD::OR && "unexpected parent");
564 Out = N;
565 return CurDAG->haveNoCommonBitsSet(N, Parent->getOperand(1));
566}
567
Owen Andersonb595ed02011-07-21 18:54:16 +0000568
Jim Grosbach1e4d9a12010-10-26 22:37:02 +0000569bool ARMDAGToDAGISel::SelectAddrModeImm12(SDValue N,
570 SDValue &Base,
571 SDValue &OffImm) {
572 // Match simple R + imm12 operands.
573
574 // Base only.
Chris Lattner46c01a32011-02-13 22:25:43 +0000575 if (N.getOpcode() != ISD::ADD && N.getOpcode() != ISD::SUB &&
576 !CurDAG->isBaseWithConstantOffset(N)) {
Jim Grosbach1e4d9a12010-10-26 22:37:02 +0000577 if (N.getOpcode() == ISD::FrameIndex) {
Chris Lattner46c01a32011-02-13 22:25:43 +0000578 // Match frame index.
Jim Grosbach1e4d9a12010-10-26 22:37:02 +0000579 int FI = cast<FrameIndexSDNode>(N)->getIndex();
Mehdi Amini44ede332015-07-09 02:09:04 +0000580 Base = CurDAG->getTargetFrameIndex(
581 FI, TLI->getPointerTy(CurDAG->getDataLayout()));
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +0000582 OffImm = CurDAG->getTargetConstant(0, SDLoc(N), MVT::i32);
Jim Grosbach1e4d9a12010-10-26 22:37:02 +0000583 return true;
Chris Lattner46c01a32011-02-13 22:25:43 +0000584 }
Owen Anderson6d557452011-03-18 19:46:58 +0000585
Chris Lattner46c01a32011-02-13 22:25:43 +0000586 if (N.getOpcode() == ARMISD::Wrapper &&
Tim Northoverbd41cf82016-01-07 09:03:03 +0000587 N.getOperand(0).getOpcode() != ISD::TargetGlobalAddress &&
Saleem Abdulrasoolf36005a2016-02-03 18:21:59 +0000588 N.getOperand(0).getOpcode() != ISD::TargetExternalSymbol &&
Tim Northoverbd41cf82016-01-07 09:03:03 +0000589 N.getOperand(0).getOpcode() != ISD::TargetGlobalTLSAddress) {
Jim Grosbach1e4d9a12010-10-26 22:37:02 +0000590 Base = N.getOperand(0);
591 } else
592 Base = N;
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +0000593 OffImm = CurDAG->getTargetConstant(0, SDLoc(N), MVT::i32);
Jim Grosbach1e4d9a12010-10-26 22:37:02 +0000594 return true;
595 }
596
597 if (ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(N.getOperand(1))) {
Renato Golin63e27982014-09-09 09:57:59 +0000598 int RHSC = (int)RHS->getSExtValue();
Jim Grosbach1e4d9a12010-10-26 22:37:02 +0000599 if (N.getOpcode() == ISD::SUB)
600 RHSC = -RHSC;
601
Renato Golin63e27982014-09-09 09:57:59 +0000602 if (RHSC > -0x1000 && RHSC < 0x1000) { // 12 bits
Jim Grosbach1e4d9a12010-10-26 22:37:02 +0000603 Base = N.getOperand(0);
604 if (Base.getOpcode() == ISD::FrameIndex) {
605 int FI = cast<FrameIndexSDNode>(Base)->getIndex();
Mehdi Amini44ede332015-07-09 02:09:04 +0000606 Base = CurDAG->getTargetFrameIndex(
607 FI, TLI->getPointerTy(CurDAG->getDataLayout()));
Jim Grosbach1e4d9a12010-10-26 22:37:02 +0000608 }
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +0000609 OffImm = CurDAG->getTargetConstant(RHSC, SDLoc(N), MVT::i32);
Jim Grosbach1e4d9a12010-10-26 22:37:02 +0000610 return true;
611 }
612 }
613
614 // Base only.
615 Base = N;
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +0000616 OffImm = CurDAG->getTargetConstant(0, SDLoc(N), MVT::i32);
Jim Grosbach1e4d9a12010-10-26 22:37:02 +0000617 return true;
618}
619
620
621
622bool ARMDAGToDAGISel::SelectLdStSOReg(SDValue N, SDValue &Base, SDValue &Offset,
623 SDValue &Opc) {
Evan Cheng59bbc542010-10-27 23:41:30 +0000624 if (N.getOpcode() == ISD::MUL &&
Bob Wilsone8a549c2012-09-29 21:43:49 +0000625 ((!Subtarget->isLikeA9() && !Subtarget->isSwift()) || N.hasOneUse())) {
Jim Grosbach1e4d9a12010-10-26 22:37:02 +0000626 if (ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(N.getOperand(1))) {
627 // X * [3,5,9] -> X + X * [2,4,8] etc.
628 int RHSC = (int)RHS->getZExtValue();
629 if (RHSC & 1) {
630 RHSC = RHSC & ~1;
631 ARM_AM::AddrOpc AddSub = ARM_AM::add;
632 if (RHSC < 0) {
633 AddSub = ARM_AM::sub;
634 RHSC = - RHSC;
635 }
636 if (isPowerOf2_32(RHSC)) {
637 unsigned ShAmt = Log2_32(RHSC);
638 Base = Offset = N.getOperand(0);
639 Opc = CurDAG->getTargetConstant(ARM_AM::getAM2Opc(AddSub, ShAmt,
640 ARM_AM::lsl),
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +0000641 SDLoc(N), MVT::i32);
Jim Grosbach1e4d9a12010-10-26 22:37:02 +0000642 return true;
643 }
644 }
645 }
646 }
647
Chris Lattner46c01a32011-02-13 22:25:43 +0000648 if (N.getOpcode() != ISD::ADD && N.getOpcode() != ISD::SUB &&
649 // ISD::OR that is equivalent to an ISD::ADD.
650 !CurDAG->isBaseWithConstantOffset(N))
Jim Grosbach1e4d9a12010-10-26 22:37:02 +0000651 return false;
652
653 // Leave simple R +/- imm12 operands for LDRi12
Chris Lattner46c01a32011-02-13 22:25:43 +0000654 if (N.getOpcode() == ISD::ADD || N.getOpcode() == ISD::OR) {
Daniel Dunbare0cd9ac2011-01-19 15:12:16 +0000655 int RHSC;
656 if (isScaledConstantInRange(N.getOperand(1), /*Scale=*/1,
657 -0x1000+1, 0x1000, RHSC)) // 12 bits.
658 return false;
Jim Grosbach1e4d9a12010-10-26 22:37:02 +0000659 }
660
661 // Otherwise this is R +/- [possibly shifted] R.
Chris Lattner46c01a32011-02-13 22:25:43 +0000662 ARM_AM::AddrOpc AddSub = N.getOpcode() == ISD::SUB ? ARM_AM::sub:ARM_AM::add;
Evan Chenga20cde32011-07-20 23:34:39 +0000663 ARM_AM::ShiftOpc ShOpcVal =
664 ARM_AM::getShiftOpcForNode(N.getOperand(1).getOpcode());
Jim Grosbach1e4d9a12010-10-26 22:37:02 +0000665 unsigned ShAmt = 0;
666
667 Base = N.getOperand(0);
668 Offset = N.getOperand(1);
669
670 if (ShOpcVal != ARM_AM::no_shift) {
671 // Check to see if the RHS of the shift is a constant, if not, we can't fold
672 // it.
673 if (ConstantSDNode *Sh =
674 dyn_cast<ConstantSDNode>(N.getOperand(1).getOperand(1))) {
675 ShAmt = Sh->getZExtValue();
Evan Cheng59bbc542010-10-27 23:41:30 +0000676 if (isShifterOpProfitable(Offset, ShOpcVal, ShAmt))
677 Offset = N.getOperand(1).getOperand(0);
678 else {
679 ShAmt = 0;
680 ShOpcVal = ARM_AM::no_shift;
681 }
Jim Grosbach1e4d9a12010-10-26 22:37:02 +0000682 } else {
683 ShOpcVal = ARM_AM::no_shift;
684 }
685 }
686
687 // Try matching (R shl C) + (R).
Chris Lattner46c01a32011-02-13 22:25:43 +0000688 if (N.getOpcode() != ISD::SUB && ShOpcVal == ARM_AM::no_shift &&
Bob Wilsone8a549c2012-09-29 21:43:49 +0000689 !(Subtarget->isLikeA9() || Subtarget->isSwift() ||
690 N.getOperand(0).hasOneUse())) {
Evan Chenga20cde32011-07-20 23:34:39 +0000691 ShOpcVal = ARM_AM::getShiftOpcForNode(N.getOperand(0).getOpcode());
Jim Grosbach1e4d9a12010-10-26 22:37:02 +0000692 if (ShOpcVal != ARM_AM::no_shift) {
693 // Check to see if the RHS of the shift is a constant, if not, we can't
694 // fold it.
695 if (ConstantSDNode *Sh =
696 dyn_cast<ConstantSDNode>(N.getOperand(0).getOperand(1))) {
697 ShAmt = Sh->getZExtValue();
Cameron Zwarich842f99a2011-10-05 23:39:02 +0000698 if (isShifterOpProfitable(N.getOperand(0), ShOpcVal, ShAmt)) {
Evan Cheng59bbc542010-10-27 23:41:30 +0000699 Offset = N.getOperand(0).getOperand(0);
700 Base = N.getOperand(1);
701 } else {
702 ShAmt = 0;
703 ShOpcVal = ARM_AM::no_shift;
704 }
Jim Grosbach1e4d9a12010-10-26 22:37:02 +0000705 } else {
706 ShOpcVal = ARM_AM::no_shift;
707 }
708 }
709 }
710
John Brawn056e6782015-09-14 15:19:41 +0000711 // If Offset is a multiply-by-constant and it's profitable to extract a shift
712 // and use it in a shifted operand do so.
Tim Northoverc4093c32016-01-29 19:18:46 +0000713 if (Offset.getOpcode() == ISD::MUL && N.hasOneUse()) {
John Brawn056e6782015-09-14 15:19:41 +0000714 unsigned PowerOfTwo = 0;
715 SDValue NewMulConst;
716 if (canExtractShiftFromMul(Offset, 31, PowerOfTwo, NewMulConst)) {
Tim Northover4a01ffb2017-05-02 22:45:19 +0000717 HandleSDNode Handle(Offset);
John Brawn056e6782015-09-14 15:19:41 +0000718 replaceDAGValue(Offset.getOperand(1), NewMulConst);
Tim Northover4a01ffb2017-05-02 22:45:19 +0000719 Offset = Handle.getValue();
John Brawn056e6782015-09-14 15:19:41 +0000720 ShAmt = PowerOfTwo;
721 ShOpcVal = ARM_AM::lsl;
722 }
723 }
724
Jim Grosbach1e4d9a12010-10-26 22:37:02 +0000725 Opc = CurDAG->getTargetConstant(ARM_AM::getAM2Opc(AddSub, ShAmt, ShOpcVal),
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +0000726 SDLoc(N), MVT::i32);
Jim Grosbach1e4d9a12010-10-26 22:37:02 +0000727 return true;
728}
729
Owen Anderson2aedba62011-07-26 20:54:26 +0000730bool ARMDAGToDAGISel::SelectAddrMode2OffsetReg(SDNode *Op, SDValue N,
Dan Gohman2ce6f2a2008-07-27 21:46:04 +0000731 SDValue &Offset, SDValue &Opc) {
Dan Gohmanea6f91f2010-01-05 01:24:18 +0000732 unsigned Opcode = Op->getOpcode();
Evan Cheng10043e22007-01-19 07:51:42 +0000733 ISD::MemIndexedMode AM = (Opcode == ISD::LOAD)
734 ? cast<LoadSDNode>(Op)->getAddressingMode()
735 : cast<StoreSDNode>(Op)->getAddressingMode();
736 ARM_AM::AddrOpc AddSub = (AM == ISD::PRE_INC || AM == ISD::POST_INC)
737 ? ARM_AM::add : ARM_AM::sub;
Daniel Dunbare0cd9ac2011-01-19 15:12:16 +0000738 int Val;
Owen Anderson2aedba62011-07-26 20:54:26 +0000739 if (isScaledConstantInRange(N, /*Scale=*/1, 0, 0x1000, Val))
740 return false;
Evan Cheng10043e22007-01-19 07:51:42 +0000741
742 Offset = N;
Evan Chenga20cde32011-07-20 23:34:39 +0000743 ARM_AM::ShiftOpc ShOpcVal = ARM_AM::getShiftOpcForNode(N.getOpcode());
Evan Cheng10043e22007-01-19 07:51:42 +0000744 unsigned ShAmt = 0;
745 if (ShOpcVal != ARM_AM::no_shift) {
746 // Check to see if the RHS of the shift is a constant, if not, we can't fold
747 // it.
748 if (ConstantSDNode *Sh = dyn_cast<ConstantSDNode>(N.getOperand(1))) {
Dan Gohmaneffb8942008-09-12 16:56:44 +0000749 ShAmt = Sh->getZExtValue();
Evan Cheng59bbc542010-10-27 23:41:30 +0000750 if (isShifterOpProfitable(N, ShOpcVal, ShAmt))
751 Offset = N.getOperand(0);
752 else {
753 ShAmt = 0;
754 ShOpcVal = ARM_AM::no_shift;
755 }
Evan Cheng10043e22007-01-19 07:51:42 +0000756 } else {
757 ShOpcVal = ARM_AM::no_shift;
758 }
759 }
760
761 Opc = CurDAG->getTargetConstant(ARM_AM::getAM2Opc(AddSub, ShAmt, ShOpcVal),
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +0000762 SDLoc(N), MVT::i32);
Rafael Espindola19398ec2006-10-17 18:04:53 +0000763 return true;
764}
765
Owen Anderson4d5c8f82011-08-29 20:16:50 +0000766bool ARMDAGToDAGISel::SelectAddrMode2OffsetImmPre(SDNode *Op, SDValue N,
767 SDValue &Offset, SDValue &Opc) {
Owen Anderson939cd212011-08-31 20:00:11 +0000768 unsigned Opcode = Op->getOpcode();
769 ISD::MemIndexedMode AM = (Opcode == ISD::LOAD)
770 ? cast<LoadSDNode>(Op)->getAddressingMode()
771 : cast<StoreSDNode>(Op)->getAddressingMode();
772 ARM_AM::AddrOpc AddSub = (AM == ISD::PRE_INC || AM == ISD::POST_INC)
773 ? ARM_AM::add : ARM_AM::sub;
Owen Anderson4d5c8f82011-08-29 20:16:50 +0000774 int Val;
775 if (isScaledConstantInRange(N, /*Scale=*/1, 0, 0x1000, Val)) { // 12 bits.
Owen Anderson939cd212011-08-31 20:00:11 +0000776 if (AddSub == ARM_AM::sub) Val *= -1;
Owen Anderson4d5c8f82011-08-29 20:16:50 +0000777 Offset = CurDAG->getRegister(0, MVT::i32);
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +0000778 Opc = CurDAG->getTargetConstant(Val, SDLoc(Op), MVT::i32);
Owen Anderson4d5c8f82011-08-29 20:16:50 +0000779 return true;
780 }
781
782 return false;
783}
784
785
Owen Anderson2aedba62011-07-26 20:54:26 +0000786bool ARMDAGToDAGISel::SelectAddrMode2OffsetImm(SDNode *Op, SDValue N,
787 SDValue &Offset, SDValue &Opc) {
788 unsigned Opcode = Op->getOpcode();
789 ISD::MemIndexedMode AM = (Opcode == ISD::LOAD)
790 ? cast<LoadSDNode>(Op)->getAddressingMode()
791 : cast<StoreSDNode>(Op)->getAddressingMode();
792 ARM_AM::AddrOpc AddSub = (AM == ISD::PRE_INC || AM == ISD::POST_INC)
793 ? ARM_AM::add : ARM_AM::sub;
794 int Val;
795 if (isScaledConstantInRange(N, /*Scale=*/1, 0, 0x1000, Val)) { // 12 bits.
796 Offset = CurDAG->getRegister(0, MVT::i32);
797 Opc = CurDAG->getTargetConstant(ARM_AM::getAM2Opc(AddSub, Val,
798 ARM_AM::no_shift),
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +0000799 SDLoc(Op), MVT::i32);
Owen Anderson2aedba62011-07-26 20:54:26 +0000800 return true;
801 }
802
803 return false;
804}
805
Jim Grosbachf0c95ca2011-08-05 20:35:44 +0000806bool ARMDAGToDAGISel::SelectAddrOffsetNone(SDValue N, SDValue &Base) {
807 Base = N;
808 return true;
809}
Evan Cheng10043e22007-01-19 07:51:42 +0000810
Chris Lattner0e023ea2010-09-21 20:31:19 +0000811bool ARMDAGToDAGISel::SelectAddrMode3(SDValue N,
Dan Gohman2ce6f2a2008-07-27 21:46:04 +0000812 SDValue &Base, SDValue &Offset,
813 SDValue &Opc) {
Evan Cheng10043e22007-01-19 07:51:42 +0000814 if (N.getOpcode() == ISD::SUB) {
815 // X - C is canonicalize to X + -C, no need to handle it here.
816 Base = N.getOperand(0);
817 Offset = N.getOperand(1);
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +0000818 Opc = CurDAG->getTargetConstant(ARM_AM::getAM3Opc(ARM_AM::sub, 0), SDLoc(N),
819 MVT::i32);
Evan Cheng10043e22007-01-19 07:51:42 +0000820 return true;
821 }
Jim Grosbachf24f9d92009-08-11 15:33:49 +0000822
Chris Lattner46c01a32011-02-13 22:25:43 +0000823 if (!CurDAG->isBaseWithConstantOffset(N)) {
Evan Cheng10043e22007-01-19 07:51:42 +0000824 Base = N;
825 if (N.getOpcode() == ISD::FrameIndex) {
826 int FI = cast<FrameIndexSDNode>(N)->getIndex();
Mehdi Amini44ede332015-07-09 02:09:04 +0000827 Base = CurDAG->getTargetFrameIndex(
828 FI, TLI->getPointerTy(CurDAG->getDataLayout()));
Evan Cheng10043e22007-01-19 07:51:42 +0000829 }
Owen Anderson9f944592009-08-11 20:47:22 +0000830 Offset = CurDAG->getRegister(0, MVT::i32);
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +0000831 Opc = CurDAG->getTargetConstant(ARM_AM::getAM3Opc(ARM_AM::add, 0), SDLoc(N),
832 MVT::i32);
Evan Cheng10043e22007-01-19 07:51:42 +0000833 return true;
834 }
Jim Grosbachf24f9d92009-08-11 15:33:49 +0000835
Evan Cheng10043e22007-01-19 07:51:42 +0000836 // If the RHS is +/- imm8, fold into addr mode.
Daniel Dunbare0cd9ac2011-01-19 15:12:16 +0000837 int RHSC;
838 if (isScaledConstantInRange(N.getOperand(1), /*Scale=*/1,
839 -256 + 1, 256, RHSC)) { // 8 bits.
840 Base = N.getOperand(0);
841 if (Base.getOpcode() == ISD::FrameIndex) {
842 int FI = cast<FrameIndexSDNode>(Base)->getIndex();
Mehdi Amini44ede332015-07-09 02:09:04 +0000843 Base = CurDAG->getTargetFrameIndex(
844 FI, TLI->getPointerTy(CurDAG->getDataLayout()));
Evan Cheng10043e22007-01-19 07:51:42 +0000845 }
Daniel Dunbare0cd9ac2011-01-19 15:12:16 +0000846 Offset = CurDAG->getRegister(0, MVT::i32);
847
848 ARM_AM::AddrOpc AddSub = ARM_AM::add;
849 if (RHSC < 0) {
850 AddSub = ARM_AM::sub;
Chris Lattner46c01a32011-02-13 22:25:43 +0000851 RHSC = -RHSC;
Daniel Dunbare0cd9ac2011-01-19 15:12:16 +0000852 }
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +0000853 Opc = CurDAG->getTargetConstant(ARM_AM::getAM3Opc(AddSub, RHSC), SDLoc(N),
854 MVT::i32);
Daniel Dunbare0cd9ac2011-01-19 15:12:16 +0000855 return true;
Evan Cheng10043e22007-01-19 07:51:42 +0000856 }
Jim Grosbachf24f9d92009-08-11 15:33:49 +0000857
Evan Cheng10043e22007-01-19 07:51:42 +0000858 Base = N.getOperand(0);
859 Offset = N.getOperand(1);
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +0000860 Opc = CurDAG->getTargetConstant(ARM_AM::getAM3Opc(ARM_AM::add, 0), SDLoc(N),
861 MVT::i32);
Evan Cheng10043e22007-01-19 07:51:42 +0000862 return true;
863}
864
Dan Gohmanea6f91f2010-01-05 01:24:18 +0000865bool ARMDAGToDAGISel::SelectAddrMode3Offset(SDNode *Op, SDValue N,
Dan Gohman2ce6f2a2008-07-27 21:46:04 +0000866 SDValue &Offset, SDValue &Opc) {
Dan Gohmanea6f91f2010-01-05 01:24:18 +0000867 unsigned Opcode = Op->getOpcode();
Evan Cheng10043e22007-01-19 07:51:42 +0000868 ISD::MemIndexedMode AM = (Opcode == ISD::LOAD)
869 ? cast<LoadSDNode>(Op)->getAddressingMode()
870 : cast<StoreSDNode>(Op)->getAddressingMode();
871 ARM_AM::AddrOpc AddSub = (AM == ISD::PRE_INC || AM == ISD::POST_INC)
872 ? ARM_AM::add : ARM_AM::sub;
Daniel Dunbare0cd9ac2011-01-19 15:12:16 +0000873 int Val;
874 if (isScaledConstantInRange(N, /*Scale=*/1, 0, 256, Val)) { // 12 bits.
875 Offset = CurDAG->getRegister(0, MVT::i32);
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +0000876 Opc = CurDAG->getTargetConstant(ARM_AM::getAM3Opc(AddSub, Val), SDLoc(Op),
877 MVT::i32);
Daniel Dunbare0cd9ac2011-01-19 15:12:16 +0000878 return true;
Evan Cheng10043e22007-01-19 07:51:42 +0000879 }
880
881 Offset = N;
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +0000882 Opc = CurDAG->getTargetConstant(ARM_AM::getAM3Opc(AddSub, 0), SDLoc(Op),
883 MVT::i32);
Evan Cheng10043e22007-01-19 07:51:42 +0000884 return true;
885}
886
Sjoerd Meijer011de9c2018-01-26 09:26:40 +0000887bool ARMDAGToDAGISel::IsAddressingMode5(SDValue N, SDValue &Base, SDValue &Offset,
Oliver Stannard181afc72019-03-04 09:17:38 +0000888 bool FP16) {
Chris Lattner46c01a32011-02-13 22:25:43 +0000889 if (!CurDAG->isBaseWithConstantOffset(N)) {
Evan Cheng10043e22007-01-19 07:51:42 +0000890 Base = N;
891 if (N.getOpcode() == ISD::FrameIndex) {
892 int FI = cast<FrameIndexSDNode>(N)->getIndex();
Mehdi Amini44ede332015-07-09 02:09:04 +0000893 Base = CurDAG->getTargetFrameIndex(
894 FI, TLI->getPointerTy(CurDAG->getDataLayout()));
Anton Korobeynikov25229082009-11-24 00:44:37 +0000895 } else if (N.getOpcode() == ARMISD::Wrapper &&
Tim Northoverbd41cf82016-01-07 09:03:03 +0000896 N.getOperand(0).getOpcode() != ISD::TargetGlobalAddress &&
Saleem Abdulrasoolf36005a2016-02-03 18:21:59 +0000897 N.getOperand(0).getOpcode() != ISD::TargetExternalSymbol &&
Tim Northoverbd41cf82016-01-07 09:03:03 +0000898 N.getOperand(0).getOpcode() != ISD::TargetGlobalTLSAddress) {
Evan Cheng10043e22007-01-19 07:51:42 +0000899 Base = N.getOperand(0);
900 }
901 Offset = CurDAG->getTargetConstant(ARM_AM::getAM5Opc(ARM_AM::add, 0),
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +0000902 SDLoc(N), MVT::i32);
Evan Cheng10043e22007-01-19 07:51:42 +0000903 return true;
904 }
Jim Grosbachf24f9d92009-08-11 15:33:49 +0000905
Evan Cheng10043e22007-01-19 07:51:42 +0000906 // If the RHS is +/- imm8, fold into addr mode.
Daniel Dunbare0cd9ac2011-01-19 15:12:16 +0000907 int RHSC;
Sjoerd Meijer011de9c2018-01-26 09:26:40 +0000908 const int Scale = FP16 ? 2 : 4;
909
Oliver Stannard181afc72019-03-04 09:17:38 +0000910 if (isScaledConstantInRange(N.getOperand(1), Scale, -255, 256, RHSC)) {
Daniel Dunbare0cd9ac2011-01-19 15:12:16 +0000911 Base = N.getOperand(0);
912 if (Base.getOpcode() == ISD::FrameIndex) {
913 int FI = cast<FrameIndexSDNode>(Base)->getIndex();
Mehdi Amini44ede332015-07-09 02:09:04 +0000914 Base = CurDAG->getTargetFrameIndex(
915 FI, TLI->getPointerTy(CurDAG->getDataLayout()));
Evan Cheng10043e22007-01-19 07:51:42 +0000916 }
Daniel Dunbare0cd9ac2011-01-19 15:12:16 +0000917
918 ARM_AM::AddrOpc AddSub = ARM_AM::add;
919 if (RHSC < 0) {
920 AddSub = ARM_AM::sub;
Chris Lattner46c01a32011-02-13 22:25:43 +0000921 RHSC = -RHSC;
Daniel Dunbare0cd9ac2011-01-19 15:12:16 +0000922 }
Sjoerd Meijer011de9c2018-01-26 09:26:40 +0000923
924 if (FP16)
925 Offset = CurDAG->getTargetConstant(ARM_AM::getAM5FP16Opc(AddSub, RHSC),
926 SDLoc(N), MVT::i32);
927 else
928 Offset = CurDAG->getTargetConstant(ARM_AM::getAM5Opc(AddSub, RHSC),
929 SDLoc(N), MVT::i32);
930
Daniel Dunbare0cd9ac2011-01-19 15:12:16 +0000931 return true;
Evan Cheng10043e22007-01-19 07:51:42 +0000932 }
Jim Grosbachf24f9d92009-08-11 15:33:49 +0000933
Evan Cheng10043e22007-01-19 07:51:42 +0000934 Base = N;
Sjoerd Meijer011de9c2018-01-26 09:26:40 +0000935
936 if (FP16)
937 Offset = CurDAG->getTargetConstant(ARM_AM::getAM5FP16Opc(ARM_AM::add, 0),
938 SDLoc(N), MVT::i32);
939 else
940 Offset = CurDAG->getTargetConstant(ARM_AM::getAM5Opc(ARM_AM::add, 0),
941 SDLoc(N), MVT::i32);
942
Evan Cheng10043e22007-01-19 07:51:42 +0000943 return true;
944}
945
Sjoerd Meijer011de9c2018-01-26 09:26:40 +0000946bool ARMDAGToDAGISel::SelectAddrMode5(SDValue N,
947 SDValue &Base, SDValue &Offset) {
Oliver Stannard181afc72019-03-04 09:17:38 +0000948 return IsAddressingMode5(N, Base, Offset, /*FP16=*/ false);
Sjoerd Meijer011de9c2018-01-26 09:26:40 +0000949}
950
951bool ARMDAGToDAGISel::SelectAddrMode5FP16(SDValue N,
952 SDValue &Base, SDValue &Offset) {
Oliver Stannard181afc72019-03-04 09:17:38 +0000953 return IsAddressingMode5(N, Base, Offset, /*FP16=*/ true);
Sjoerd Meijer011de9c2018-01-26 09:26:40 +0000954}
955
Bob Wilsondd9fbaa2010-11-01 23:40:51 +0000956bool ARMDAGToDAGISel::SelectAddrMode6(SDNode *Parent, SDValue N, SDValue &Addr,
957 SDValue &Align) {
Bob Wilsondeb35af2009-07-01 23:16:05 +0000958 Addr = N;
Bob Wilsondd9fbaa2010-11-01 23:40:51 +0000959
960 unsigned Alignment = 0;
Ahmed Bougachadb141ac2015-02-19 23:52:41 +0000961
962 MemSDNode *MemN = cast<MemSDNode>(Parent);
963
964 if (isa<LSBaseSDNode>(MemN) ||
965 ((MemN->getOpcode() == ARMISD::VST1_UPD ||
966 MemN->getOpcode() == ARMISD::VLD1_UPD) &&
967 MemN->getConstantOperandVal(MemN->getNumOperands() - 1) == 1)) {
Bob Wilsondd9fbaa2010-11-01 23:40:51 +0000968 // This case occurs only for VLD1-lane/dup and VST1-lane instructions.
969 // The maximum alignment is equal to the memory size being referenced.
Ahmed Bougachadb141ac2015-02-19 23:52:41 +0000970 unsigned MMOAlign = MemN->getAlignment();
971 unsigned MemSize = MemN->getMemoryVT().getSizeInBits() / 8;
972 if (MMOAlign >= MemSize && MemSize > 1)
Bob Wilsondd9fbaa2010-11-01 23:40:51 +0000973 Alignment = MemSize;
974 } else {
975 // All other uses of addrmode6 are for intrinsics. For now just record
976 // the raw alignment value; it will be refined later based on the legal
977 // alignment operands for the intrinsic.
Ahmed Bougachadb141ac2015-02-19 23:52:41 +0000978 Alignment = MemN->getAlignment();
Bob Wilsondd9fbaa2010-11-01 23:40:51 +0000979 }
980
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +0000981 Align = CurDAG->getTargetConstant(Alignment, SDLoc(N), MVT::i32);
Bob Wilsondeb35af2009-07-01 23:16:05 +0000982 return true;
983}
984
Bob Wilsone3ecd5f2011-02-25 06:42:42 +0000985bool ARMDAGToDAGISel::SelectAddrMode6Offset(SDNode *Op, SDValue N,
986 SDValue &Offset) {
987 LSBaseSDNode *LdSt = cast<LSBaseSDNode>(Op);
988 ISD::MemIndexedMode AM = LdSt->getAddressingMode();
989 if (AM != ISD::POST_INC)
990 return false;
991 Offset = N;
992 if (ConstantSDNode *NC = dyn_cast<ConstantSDNode>(N)) {
993 if (NC->getZExtValue() * 8 == LdSt->getMemoryVT().getSizeInBits())
994 Offset = CurDAG->getRegister(0, MVT::i32);
995 }
996 return true;
997}
998
Chris Lattner0e023ea2010-09-21 20:31:19 +0000999bool ARMDAGToDAGISel::SelectAddrModePC(SDValue N,
Evan Cheng9a58aff2009-08-14 19:01:37 +00001000 SDValue &Offset, SDValue &Label) {
Evan Cheng10043e22007-01-19 07:51:42 +00001001 if (N.getOpcode() == ARMISD::PIC_ADD && N.hasOneUse()) {
1002 Offset = N.getOperand(0);
Dan Gohman2ce6f2a2008-07-27 21:46:04 +00001003 SDValue N1 = N.getOperand(1);
Evan Chengb8b0ad82011-01-20 08:34:58 +00001004 Label = CurDAG->getTargetConstant(cast<ConstantSDNode>(N1)->getZExtValue(),
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00001005 SDLoc(N), MVT::i32);
Evan Cheng10043e22007-01-19 07:51:42 +00001006 return true;
1007 }
Bill Wendling092a7bd2010-12-14 03:36:38 +00001008
Evan Cheng10043e22007-01-19 07:51:42 +00001009 return false;
1010}
1011
Bill Wendling092a7bd2010-12-14 03:36:38 +00001012
1013//===----------------------------------------------------------------------===//
1014// Thumb Addressing Modes
1015//===----------------------------------------------------------------------===//
1016
David Green54b01152019-01-29 10:40:31 +00001017static bool shouldUseZeroOffsetLdSt(SDValue N) {
1018 // Negative numbers are difficult to materialise in thumb1. If we are
1019 // selecting the add of a negative, instead try to select ri with a zero
1020 // offset, so create the add node directly which will become a sub.
1021 if (N.getOpcode() != ISD::ADD)
1022 return false;
1023
1024 // Look for an imm which is not legal for ld/st, but is legal for sub.
1025 if (auto C = dyn_cast<ConstantSDNode>(N.getOperand(1)))
1026 return C->getSExtValue() < 0 && C->getSExtValue() >= -255;
1027
1028 return false;
1029}
1030
1031bool ARMDAGToDAGISel::SelectThumbAddrModeRRSext(SDValue N, SDValue &Base,
1032 SDValue &Offset) {
Chris Lattner46c01a32011-02-13 22:25:43 +00001033 if (N.getOpcode() != ISD::ADD && !CurDAG->isBaseWithConstantOffset(N)) {
Evan Cheng0794c6a2009-07-11 07:08:13 +00001034 ConstantSDNode *NC = dyn_cast<ConstantSDNode>(N);
Dan Gohmanf1d83042010-06-18 14:22:04 +00001035 if (!NC || !NC->isNullValue())
Evan Cheng0794c6a2009-07-11 07:08:13 +00001036 return false;
1037
1038 Base = Offset = N;
Evan Chengc0b73662007-01-23 22:59:13 +00001039 return true;
1040 }
1041
Evan Cheng10043e22007-01-19 07:51:42 +00001042 Base = N.getOperand(0);
1043 Offset = N.getOperand(1);
1044 return true;
1045}
1046
David Green54b01152019-01-29 10:40:31 +00001047bool ARMDAGToDAGISel::SelectThumbAddrModeRR(SDValue N, SDValue &Base,
1048 SDValue &Offset) {
1049 if (shouldUseZeroOffsetLdSt(N))
1050 return false; // Select ri instead
1051 return SelectThumbAddrModeRRSext(N, Base, Offset);
1052}
1053
Evan Cheng139edae2007-01-24 02:21:22 +00001054bool
Bill Wendling092a7bd2010-12-14 03:36:38 +00001055ARMDAGToDAGISel::SelectThumbAddrModeImm5S(SDValue N, unsigned Scale,
1056 SDValue &Base, SDValue &OffImm) {
David Green54b01152019-01-29 10:40:31 +00001057 if (shouldUseZeroOffsetLdSt(N)) {
1058 Base = N;
1059 OffImm = CurDAG->getTargetConstant(0, SDLoc(N), MVT::i32);
1060 return true;
1061 }
1062
Chris Lattner46c01a32011-02-13 22:25:43 +00001063 if (!CurDAG->isBaseWithConstantOffset(N)) {
John Brawn68acdcb2015-08-13 10:48:22 +00001064 if (N.getOpcode() == ISD::ADD) {
1065 return false; // We want to select register offset instead
1066 } else if (N.getOpcode() == ARMISD::Wrapper &&
Tim Northoverbd41cf82016-01-07 09:03:03 +00001067 N.getOperand(0).getOpcode() != ISD::TargetGlobalAddress &&
Saleem Abdulrasoolf36005a2016-02-03 18:21:59 +00001068 N.getOperand(0).getOpcode() != ISD::TargetExternalSymbol &&
James Molloyb7de4972016-10-05 14:52:13 +00001069 N.getOperand(0).getOpcode() != ISD::TargetConstantPool &&
Tim Northoverbd41cf82016-01-07 09:03:03 +00001070 N.getOperand(0).getOpcode() != ISD::TargetGlobalTLSAddress) {
Bill Wendling092a7bd2010-12-14 03:36:38 +00001071 Base = N.getOperand(0);
1072 } else {
1073 Base = N;
1074 }
1075
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00001076 OffImm = CurDAG->getTargetConstant(0, SDLoc(N), MVT::i32);
Evan Cheng650d0672007-02-06 00:22:06 +00001077 return true;
1078 }
1079
Evan Cheng10043e22007-01-19 07:51:42 +00001080 // If the RHS is + imm5 * scale, fold into addr mode.
Daniel Dunbare0cd9ac2011-01-19 15:12:16 +00001081 int RHSC;
1082 if (isScaledConstantInRange(N.getOperand(1), Scale, 0, 32, RHSC)) {
1083 Base = N.getOperand(0);
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00001084 OffImm = CurDAG->getTargetConstant(RHSC, SDLoc(N), MVT::i32);
Daniel Dunbare0cd9ac2011-01-19 15:12:16 +00001085 return true;
Evan Cheng10043e22007-01-19 07:51:42 +00001086 }
1087
John Brawn68acdcb2015-08-13 10:48:22 +00001088 // Offset is too large, so use register offset instead.
1089 return false;
Evan Cheng10043e22007-01-19 07:51:42 +00001090}
1091
Bill Wendling092a7bd2010-12-14 03:36:38 +00001092bool
1093ARMDAGToDAGISel::SelectThumbAddrModeImm5S4(SDValue N, SDValue &Base,
1094 SDValue &OffImm) {
1095 return SelectThumbAddrModeImm5S(N, 4, Base, OffImm);
Evan Cheng10043e22007-01-19 07:51:42 +00001096}
1097
Bill Wendling092a7bd2010-12-14 03:36:38 +00001098bool
1099ARMDAGToDAGISel::SelectThumbAddrModeImm5S2(SDValue N, SDValue &Base,
1100 SDValue &OffImm) {
1101 return SelectThumbAddrModeImm5S(N, 2, Base, OffImm);
Evan Cheng10043e22007-01-19 07:51:42 +00001102}
1103
Bill Wendling092a7bd2010-12-14 03:36:38 +00001104bool
1105ARMDAGToDAGISel::SelectThumbAddrModeImm5S1(SDValue N, SDValue &Base,
1106 SDValue &OffImm) {
1107 return SelectThumbAddrModeImm5S(N, 1, Base, OffImm);
Evan Cheng10043e22007-01-19 07:51:42 +00001108}
1109
Chris Lattner0e023ea2010-09-21 20:31:19 +00001110bool ARMDAGToDAGISel::SelectThumbAddrModeSP(SDValue N,
1111 SDValue &Base, SDValue &OffImm) {
Evan Cheng10043e22007-01-19 07:51:42 +00001112 if (N.getOpcode() == ISD::FrameIndex) {
1113 int FI = cast<FrameIndexSDNode>(N)->getIndex();
Renato Golinb9887ef2015-02-25 14:41:06 +00001114 // Only multiples of 4 are allowed for the offset, so the frame object
1115 // alignment must be at least 4.
Matthias Braun941a7052016-07-28 18:40:00 +00001116 MachineFrameInfo &MFI = MF->getFrameInfo();
1117 if (MFI.getObjectAlignment(FI) < 4)
1118 MFI.setObjectAlignment(FI, 4);
Mehdi Amini44ede332015-07-09 02:09:04 +00001119 Base = CurDAG->getTargetFrameIndex(
1120 FI, TLI->getPointerTy(CurDAG->getDataLayout()));
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00001121 OffImm = CurDAG->getTargetConstant(0, SDLoc(N), MVT::i32);
Evan Cheng10043e22007-01-19 07:51:42 +00001122 return true;
1123 }
Evan Cheng139edae2007-01-24 02:21:22 +00001124
Chris Lattner46c01a32011-02-13 22:25:43 +00001125 if (!CurDAG->isBaseWithConstantOffset(N))
Evan Cheng650d0672007-02-06 00:22:06 +00001126 return false;
1127
Eli Friedman638be662019-03-20 19:40:45 +00001128 if (N.getOperand(0).getOpcode() == ISD::FrameIndex) {
Evan Cheng139edae2007-01-24 02:21:22 +00001129 // If the RHS is + imm8 * scale, fold into addr mode.
Daniel Dunbare0cd9ac2011-01-19 15:12:16 +00001130 int RHSC;
1131 if (isScaledConstantInRange(N.getOperand(1), /*Scale=*/4, 0, 256, RHSC)) {
1132 Base = N.getOperand(0);
Eli Friedman638be662019-03-20 19:40:45 +00001133 int FI = cast<FrameIndexSDNode>(Base)->getIndex();
Eli Friedmanab1d73e2019-06-26 23:46:51 +00001134 // Make sure the offset is inside the object, or we might fail to
1135 // allocate an emergency spill slot. (An out-of-range access is UB, but
1136 // it could show up anyway.)
Eli Friedman638be662019-03-20 19:40:45 +00001137 MachineFrameInfo &MFI = MF->getFrameInfo();
Eli Friedmanab1d73e2019-06-26 23:46:51 +00001138 if (RHSC * 4 < MFI.getObjectSize(FI)) {
1139 // For LHS+RHS to result in an offset that's a multiple of 4 the object
1140 // indexed by the LHS must be 4-byte aligned.
1141 if (!MFI.isFixedObjectIndex(FI) && MFI.getObjectAlignment(FI) < 4)
1142 MFI.setObjectAlignment(FI, 4);
1143 if (MFI.getObjectAlignment(FI) >= 4) {
1144 Base = CurDAG->getTargetFrameIndex(
1145 FI, TLI->getPointerTy(CurDAG->getDataLayout()));
1146 OffImm = CurDAG->getTargetConstant(RHSC, SDLoc(N), MVT::i32);
1147 return true;
1148 }
1149 }
Evan Cheng139edae2007-01-24 02:21:22 +00001150 }
1151 }
Jim Grosbachf24f9d92009-08-11 15:33:49 +00001152
Evan Cheng10043e22007-01-19 07:51:42 +00001153 return false;
1154}
1155
David Green91724b82019-09-17 15:32:28 +00001156template <unsigned Shift>
1157bool ARMDAGToDAGISel::SelectTAddrModeImm7(SDValue N, SDValue &Base,
1158 SDValue &OffImm) {
1159 if (N.getOpcode() == ISD::SUB || CurDAG->isBaseWithConstantOffset(N)) {
1160 int RHSC;
1161 if (isScaledConstantInRange(N.getOperand(1), 1 << Shift, -0x7f, 0x80,
1162 RHSC)) {
1163 Base = N.getOperand(0);
1164 if (N.getOpcode() == ISD::SUB)
1165 RHSC = -RHSC;
1166 OffImm =
1167 CurDAG->getTargetConstant(RHSC * (1 << Shift), SDLoc(N), MVT::i32);
1168 return true;
1169 }
1170 }
1171
1172 // Base only.
1173 Base = N;
1174 OffImm = CurDAG->getTargetConstant(0, SDLoc(N), MVT::i32);
1175 return true;
1176}
1177
Bill Wendling092a7bd2010-12-14 03:36:38 +00001178
1179//===----------------------------------------------------------------------===//
1180// Thumb 2 Addressing Modes
1181//===----------------------------------------------------------------------===//
1182
1183
Chris Lattner0e023ea2010-09-21 20:31:19 +00001184bool ARMDAGToDAGISel::SelectT2AddrModeImm12(SDValue N,
Evan Chengb23b50d2009-06-29 07:51:04 +00001185 SDValue &Base, SDValue &OffImm) {
1186 // Match simple R + imm12 operands.
David Goodwin802a0b52009-07-20 15:55:39 +00001187
Evan Cheng36064672009-08-11 08:52:18 +00001188 // Base only.
Chris Lattner46c01a32011-02-13 22:25:43 +00001189 if (N.getOpcode() != ISD::ADD && N.getOpcode() != ISD::SUB &&
1190 !CurDAG->isBaseWithConstantOffset(N)) {
David Goodwin802a0b52009-07-20 15:55:39 +00001191 if (N.getOpcode() == ISD::FrameIndex) {
Chris Lattner46c01a32011-02-13 22:25:43 +00001192 // Match frame index.
David Goodwin802a0b52009-07-20 15:55:39 +00001193 int FI = cast<FrameIndexSDNode>(N)->getIndex();
Mehdi Amini44ede332015-07-09 02:09:04 +00001194 Base = CurDAG->getTargetFrameIndex(
1195 FI, TLI->getPointerTy(CurDAG->getDataLayout()));
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00001196 OffImm = CurDAG->getTargetConstant(0, SDLoc(N), MVT::i32);
David Goodwin802a0b52009-07-20 15:55:39 +00001197 return true;
Chris Lattner46c01a32011-02-13 22:25:43 +00001198 }
Owen Anderson6d557452011-03-18 19:46:58 +00001199
Chris Lattner46c01a32011-02-13 22:25:43 +00001200 if (N.getOpcode() == ARMISD::Wrapper &&
Tim Northoverbd41cf82016-01-07 09:03:03 +00001201 N.getOperand(0).getOpcode() != ISD::TargetGlobalAddress &&
Saleem Abdulrasoolf36005a2016-02-03 18:21:59 +00001202 N.getOperand(0).getOpcode() != ISD::TargetExternalSymbol &&
Tim Northoverbd41cf82016-01-07 09:03:03 +00001203 N.getOperand(0).getOpcode() != ISD::TargetGlobalTLSAddress) {
Evan Cheng36064672009-08-11 08:52:18 +00001204 Base = N.getOperand(0);
1205 if (Base.getOpcode() == ISD::TargetConstantPool)
1206 return false; // We want to select t2LDRpci instead.
1207 } else
1208 Base = N;
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00001209 OffImm = CurDAG->getTargetConstant(0, SDLoc(N), MVT::i32);
Evan Cheng36064672009-08-11 08:52:18 +00001210 return true;
David Goodwin802a0b52009-07-20 15:55:39 +00001211 }
Evan Chengb23b50d2009-06-29 07:51:04 +00001212
1213 if (ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(N.getOperand(1))) {
Chris Lattner0e023ea2010-09-21 20:31:19 +00001214 if (SelectT2AddrModeImm8(N, Base, OffImm))
Evan Cheng36064672009-08-11 08:52:18 +00001215 // Let t2LDRi8 handle (R - imm8).
1216 return false;
1217
Evan Chengb23b50d2009-06-29 07:51:04 +00001218 int RHSC = (int)RHS->getZExtValue();
David Goodwin79c079b2009-07-30 18:56:48 +00001219 if (N.getOpcode() == ISD::SUB)
1220 RHSC = -RHSC;
1221
1222 if (RHSC >= 0 && RHSC < 0x1000) { // 12 bits (unsigned)
Evan Chengb23b50d2009-06-29 07:51:04 +00001223 Base = N.getOperand(0);
David Goodwin79c079b2009-07-30 18:56:48 +00001224 if (Base.getOpcode() == ISD::FrameIndex) {
1225 int FI = cast<FrameIndexSDNode>(Base)->getIndex();
Mehdi Amini44ede332015-07-09 02:09:04 +00001226 Base = CurDAG->getTargetFrameIndex(
1227 FI, TLI->getPointerTy(CurDAG->getDataLayout()));
David Goodwin79c079b2009-07-30 18:56:48 +00001228 }
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00001229 OffImm = CurDAG->getTargetConstant(RHSC, SDLoc(N), MVT::i32);
Evan Chengb23b50d2009-06-29 07:51:04 +00001230 return true;
1231 }
1232 }
1233
Evan Cheng36064672009-08-11 08:52:18 +00001234 // Base only.
1235 Base = N;
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00001236 OffImm = CurDAG->getTargetConstant(0, SDLoc(N), MVT::i32);
Evan Cheng36064672009-08-11 08:52:18 +00001237 return true;
Evan Chengb23b50d2009-06-29 07:51:04 +00001238}
1239
Chris Lattner0e023ea2010-09-21 20:31:19 +00001240bool ARMDAGToDAGISel::SelectT2AddrModeImm8(SDValue N,
Evan Chengb23b50d2009-06-29 07:51:04 +00001241 SDValue &Base, SDValue &OffImm) {
David Goodwin79c079b2009-07-30 18:56:48 +00001242 // Match simple R - imm8 operands.
Chris Lattner46c01a32011-02-13 22:25:43 +00001243 if (N.getOpcode() != ISD::ADD && N.getOpcode() != ISD::SUB &&
1244 !CurDAG->isBaseWithConstantOffset(N))
1245 return false;
Owen Anderson6d557452011-03-18 19:46:58 +00001246
Chris Lattner46c01a32011-02-13 22:25:43 +00001247 if (ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(N.getOperand(1))) {
1248 int RHSC = (int)RHS->getSExtValue();
1249 if (N.getOpcode() == ISD::SUB)
1250 RHSC = -RHSC;
Jim Grosbachf24f9d92009-08-11 15:33:49 +00001251
Chris Lattner46c01a32011-02-13 22:25:43 +00001252 if ((RHSC >= -255) && (RHSC < 0)) { // 8 bits (always negative)
1253 Base = N.getOperand(0);
1254 if (Base.getOpcode() == ISD::FrameIndex) {
1255 int FI = cast<FrameIndexSDNode>(Base)->getIndex();
Mehdi Amini44ede332015-07-09 02:09:04 +00001256 Base = CurDAG->getTargetFrameIndex(
1257 FI, TLI->getPointerTy(CurDAG->getDataLayout()));
Evan Chengb23b50d2009-06-29 07:51:04 +00001258 }
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00001259 OffImm = CurDAG->getTargetConstant(RHSC, SDLoc(N), MVT::i32);
Chris Lattner46c01a32011-02-13 22:25:43 +00001260 return true;
Evan Chengb23b50d2009-06-29 07:51:04 +00001261 }
1262 }
1263
1264 return false;
1265}
1266
Dan Gohmanea6f91f2010-01-05 01:24:18 +00001267bool ARMDAGToDAGISel::SelectT2AddrModeImm8Offset(SDNode *Op, SDValue N,
Evan Cheng84c6cda2009-07-02 07:28:31 +00001268 SDValue &OffImm){
Dan Gohmanea6f91f2010-01-05 01:24:18 +00001269 unsigned Opcode = Op->getOpcode();
Evan Cheng84c6cda2009-07-02 07:28:31 +00001270 ISD::MemIndexedMode AM = (Opcode == ISD::LOAD)
1271 ? cast<LoadSDNode>(Op)->getAddressingMode()
1272 : cast<StoreSDNode>(Op)->getAddressingMode();
Daniel Dunbare0cd9ac2011-01-19 15:12:16 +00001273 int RHSC;
1274 if (isScaledConstantInRange(N, /*Scale=*/1, 0, 0x100, RHSC)) { // 8 bits.
1275 OffImm = ((AM == ISD::PRE_INC) || (AM == ISD::POST_INC))
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00001276 ? CurDAG->getTargetConstant(RHSC, SDLoc(N), MVT::i32)
1277 : CurDAG->getTargetConstant(-RHSC, SDLoc(N), MVT::i32);
Daniel Dunbare0cd9ac2011-01-19 15:12:16 +00001278 return true;
Evan Cheng84c6cda2009-07-02 07:28:31 +00001279 }
1280
1281 return false;
1282}
1283
David Green3e8d5f32019-09-03 09:57:02 +00001284template <unsigned Shift>
1285bool ARMDAGToDAGISel::SelectT2AddrModeImm7(SDValue N, SDValue &Base,
1286 SDValue &OffImm) {
1287 if (N.getOpcode() == ISD::SUB || CurDAG->isBaseWithConstantOffset(N)) {
1288 int RHSC;
1289 if (isScaledConstantInRange(N.getOperand(1), 1 << Shift, -0x7f, 0x80,
1290 RHSC)) {
1291 Base = N.getOperand(0);
1292 if (Base.getOpcode() == ISD::FrameIndex) {
1293 int FI = cast<FrameIndexSDNode>(Base)->getIndex();
1294 Base = CurDAG->getTargetFrameIndex(
1295 FI, TLI->getPointerTy(CurDAG->getDataLayout()));
1296 }
1297
Simon Tathama4b415a2019-06-25 16:48:46 +00001298 if (N.getOpcode() == ISD::SUB)
1299 RHSC = -RHSC;
David Green3e8d5f32019-09-03 09:57:02 +00001300 OffImm =
1301 CurDAG->getTargetConstant(RHSC * (1 << Shift), SDLoc(N), MVT::i32);
1302 return true;
Simon Tathama4b415a2019-06-25 16:48:46 +00001303 }
1304 }
1305
1306 // Base only.
1307 Base = N;
David Green3e8d5f32019-09-03 09:57:02 +00001308 OffImm = CurDAG->getTargetConstant(0, SDLoc(N), MVT::i32);
Simon Tathama4b415a2019-06-25 16:48:46 +00001309 return true;
1310}
1311
David Green27ca82f2019-08-08 15:27:58 +00001312template <unsigned Shift>
1313bool ARMDAGToDAGISel::SelectT2AddrModeImm7Offset(SDNode *Op, SDValue N,
1314 SDValue &OffImm) {
1315 return SelectT2AddrModeImm7Offset(Op, N, OffImm, Shift);
1316}
1317
1318bool ARMDAGToDAGISel::SelectT2AddrModeImm7Offset(SDNode *Op, SDValue N,
1319 SDValue &OffImm,
1320 unsigned Shift) {
1321 unsigned Opcode = Op->getOpcode();
1322 ISD::MemIndexedMode AM = (Opcode == ISD::LOAD)
1323 ? cast<LoadSDNode>(Op)->getAddressingMode()
1324 : cast<StoreSDNode>(Op)->getAddressingMode();
1325 int RHSC;
1326 if (isScaledConstantInRange(N, 1 << Shift, 0, 0x80, RHSC)) { // 7 bits.
1327 OffImm =
1328 ((AM == ISD::PRE_INC) || (AM == ISD::POST_INC))
1329 ? CurDAG->getTargetConstant(RHSC * (1 << Shift), SDLoc(N), MVT::i32)
1330 : CurDAG->getTargetConstant(-RHSC * (1 << Shift), SDLoc(N),
1331 MVT::i32);
1332 return true;
1333 }
1334 return false;
1335}
1336
Chris Lattner0e023ea2010-09-21 20:31:19 +00001337bool ARMDAGToDAGISel::SelectT2AddrModeSoReg(SDValue N,
Evan Chengb23b50d2009-06-29 07:51:04 +00001338 SDValue &Base,
1339 SDValue &OffReg, SDValue &ShImm) {
Evan Cheng36064672009-08-11 08:52:18 +00001340 // (R - imm8) should be handled by t2LDRi8. The rest are handled by t2LDRi12.
Chris Lattner46c01a32011-02-13 22:25:43 +00001341 if (N.getOpcode() != ISD::ADD && !CurDAG->isBaseWithConstantOffset(N))
Evan Cheng36064672009-08-11 08:52:18 +00001342 return false;
Evan Chengb23b50d2009-06-29 07:51:04 +00001343
Evan Cheng36064672009-08-11 08:52:18 +00001344 // Leave (R + imm12) for t2LDRi12, (R - imm8) for t2LDRi8.
1345 if (ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(N.getOperand(1))) {
1346 int RHSC = (int)RHS->getZExtValue();
1347 if (RHSC >= 0 && RHSC < 0x1000) // 12 bits (unsigned)
1348 return false;
1349 else if (RHSC < 0 && RHSC >= -255) // 8 bits
David Goodwin79c079b2009-07-30 18:56:48 +00001350 return false;
1351 }
1352
Evan Chengb23b50d2009-06-29 07:51:04 +00001353 // Look for (R + R) or (R + (R << [1,2,3])).
1354 unsigned ShAmt = 0;
1355 Base = N.getOperand(0);
1356 OffReg = N.getOperand(1);
1357
1358 // Swap if it is ((R << c) + R).
Evan Chenga20cde32011-07-20 23:34:39 +00001359 ARM_AM::ShiftOpc ShOpcVal = ARM_AM::getShiftOpcForNode(OffReg.getOpcode());
Evan Chengb23b50d2009-06-29 07:51:04 +00001360 if (ShOpcVal != ARM_AM::lsl) {
Evan Chenga20cde32011-07-20 23:34:39 +00001361 ShOpcVal = ARM_AM::getShiftOpcForNode(Base.getOpcode());
Evan Chengb23b50d2009-06-29 07:51:04 +00001362 if (ShOpcVal == ARM_AM::lsl)
1363 std::swap(Base, OffReg);
Jim Grosbachf24f9d92009-08-11 15:33:49 +00001364 }
1365
Evan Chengb23b50d2009-06-29 07:51:04 +00001366 if (ShOpcVal == ARM_AM::lsl) {
1367 // Check to see if the RHS of the shift is a constant, if not, we can't fold
1368 // it.
1369 if (ConstantSDNode *Sh = dyn_cast<ConstantSDNode>(OffReg.getOperand(1))) {
1370 ShAmt = Sh->getZExtValue();
Evan Cheng59bbc542010-10-27 23:41:30 +00001371 if (ShAmt < 4 && isShifterOpProfitable(OffReg, ShOpcVal, ShAmt))
1372 OffReg = OffReg.getOperand(0);
1373 else {
Evan Chengb23b50d2009-06-29 07:51:04 +00001374 ShAmt = 0;
Evan Cheng59bbc542010-10-27 23:41:30 +00001375 }
Evan Chengb23b50d2009-06-29 07:51:04 +00001376 }
David Goodwinf3912052009-07-15 15:50:19 +00001377 }
Jim Grosbachf24f9d92009-08-11 15:33:49 +00001378
John Brawn056e6782015-09-14 15:19:41 +00001379 // If OffReg is a multiply-by-constant and it's profitable to extract a shift
1380 // and use it in a shifted operand do so.
Tim Northoverc4093c32016-01-29 19:18:46 +00001381 if (OffReg.getOpcode() == ISD::MUL && N.hasOneUse()) {
John Brawn056e6782015-09-14 15:19:41 +00001382 unsigned PowerOfTwo = 0;
1383 SDValue NewMulConst;
1384 if (canExtractShiftFromMul(OffReg, 3, PowerOfTwo, NewMulConst)) {
Tim Northover4a01ffb2017-05-02 22:45:19 +00001385 HandleSDNode Handle(OffReg);
John Brawn056e6782015-09-14 15:19:41 +00001386 replaceDAGValue(OffReg.getOperand(1), NewMulConst);
Tim Northover4a01ffb2017-05-02 22:45:19 +00001387 OffReg = Handle.getValue();
John Brawn056e6782015-09-14 15:19:41 +00001388 ShAmt = PowerOfTwo;
1389 }
1390 }
1391
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00001392 ShImm = CurDAG->getTargetConstant(ShAmt, SDLoc(N), MVT::i32);
Evan Chengb23b50d2009-06-29 07:51:04 +00001393
1394 return true;
1395}
1396
Tim Northovera7ecd242013-07-16 09:46:55 +00001397bool ARMDAGToDAGISel::SelectT2AddrModeExclusive(SDValue N, SDValue &Base,
1398 SDValue &OffImm) {
Alp Tokercb402912014-01-24 17:20:08 +00001399 // This *must* succeed since it's used for the irreplaceable ldrex and strex
Tim Northovera7ecd242013-07-16 09:46:55 +00001400 // instructions.
1401 Base = N;
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00001402 OffImm = CurDAG->getTargetConstant(0, SDLoc(N), MVT::i32);
Tim Northovera7ecd242013-07-16 09:46:55 +00001403
1404 if (N.getOpcode() != ISD::ADD || !CurDAG->isBaseWithConstantOffset(N))
1405 return true;
1406
1407 ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(N.getOperand(1));
1408 if (!RHS)
1409 return true;
1410
1411 uint32_t RHSC = (int)RHS->getZExtValue();
1412 if (RHSC > 1020 || RHSC % 4 != 0)
1413 return true;
1414
1415 Base = N.getOperand(0);
1416 if (Base.getOpcode() == ISD::FrameIndex) {
1417 int FI = cast<FrameIndexSDNode>(Base)->getIndex();
Mehdi Amini44ede332015-07-09 02:09:04 +00001418 Base = CurDAG->getTargetFrameIndex(
1419 FI, TLI->getPointerTy(CurDAG->getDataLayout()));
Tim Northovera7ecd242013-07-16 09:46:55 +00001420 }
1421
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00001422 OffImm = CurDAG->getTargetConstant(RHSC/4, SDLoc(N), MVT::i32);
Tim Northovera7ecd242013-07-16 09:46:55 +00001423 return true;
1424}
1425
Evan Chengb23b50d2009-06-29 07:51:04 +00001426//===--------------------------------------------------------------------===//
1427
Evan Cheng7e90b112007-07-05 07:15:27 +00001428/// getAL - Returns a ARMCC::AL immediate node.
Benjamin Kramerbdc49562016-06-12 15:39:02 +00001429static inline SDValue getAL(SelectionDAG *CurDAG, const SDLoc &dl) {
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00001430 return CurDAG->getTargetConstant((uint64_t)ARMCC::AL, dl, MVT::i32);
Evan Cheng0f7cbe82007-05-15 01:29:07 +00001431}
1432
Tim Northovereaee28b2016-09-19 09:11:09 +00001433void ARMDAGToDAGISel::transferMemOperands(SDNode *N, SDNode *Result) {
Chandler Carruth66654b72018-08-14 23:30:32 +00001434 MachineMemOperand *MemOp = cast<MemSDNode>(N)->getMemOperand();
1435 CurDAG->setNodeMemRefs(cast<MachineSDNode>(Result), {MemOp});
Tim Northovereaee28b2016-09-19 09:11:09 +00001436}
1437
Justin Bogner45571362016-05-12 00:31:09 +00001438bool ARMDAGToDAGISel::tryARMIndexedLoad(SDNode *N) {
Dan Gohmanea6f91f2010-01-05 01:24:18 +00001439 LoadSDNode *LD = cast<LoadSDNode>(N);
Evan Chengd9c55362009-07-02 01:23:32 +00001440 ISD::MemIndexedMode AM = LD->getAddressingMode();
1441 if (AM == ISD::UNINDEXED)
Justin Bogner45571362016-05-12 00:31:09 +00001442 return false;
Evan Chengd9c55362009-07-02 01:23:32 +00001443
Owen Anderson53aa7a92009-08-10 22:56:29 +00001444 EVT LoadedVT = LD->getMemoryVT();
Evan Chengd9c55362009-07-02 01:23:32 +00001445 SDValue Offset, AMOpc;
1446 bool isPre = (AM == ISD::PRE_INC) || (AM == ISD::PRE_DEC);
1447 unsigned Opcode = 0;
1448 bool Match = false;
Owen Anderson4d5c8f82011-08-29 20:16:50 +00001449 if (LoadedVT == MVT::i32 && isPre &&
1450 SelectAddrMode2OffsetImmPre(N, LD->getOffset(), Offset, AMOpc)) {
1451 Opcode = ARM::LDR_PRE_IMM;
1452 Match = true;
1453 } else if (LoadedVT == MVT::i32 && !isPre &&
Owen Anderson2aedba62011-07-26 20:54:26 +00001454 SelectAddrMode2OffsetImm(N, LD->getOffset(), Offset, AMOpc)) {
Owen Anderson4d5c8f82011-08-29 20:16:50 +00001455 Opcode = ARM::LDR_POST_IMM;
Evan Chengd9c55362009-07-02 01:23:32 +00001456 Match = true;
Owen Anderson2aedba62011-07-26 20:54:26 +00001457 } else if (LoadedVT == MVT::i32 &&
1458 SelectAddrMode2OffsetReg(N, LD->getOffset(), Offset, AMOpc)) {
Owen Anderson16d33f32011-08-26 20:43:14 +00001459 Opcode = isPre ? ARM::LDR_PRE_REG : ARM::LDR_POST_REG;
Owen Anderson2aedba62011-07-26 20:54:26 +00001460 Match = true;
1461
Owen Anderson9f944592009-08-11 20:47:22 +00001462 } else if (LoadedVT == MVT::i16 &&
Dan Gohmanea6f91f2010-01-05 01:24:18 +00001463 SelectAddrMode3Offset(N, LD->getOffset(), Offset, AMOpc)) {
Evan Chengd9c55362009-07-02 01:23:32 +00001464 Match = true;
1465 Opcode = (LD->getExtensionType() == ISD::SEXTLOAD)
1466 ? (isPre ? ARM::LDRSH_PRE : ARM::LDRSH_POST)
1467 : (isPre ? ARM::LDRH_PRE : ARM::LDRH_POST);
Owen Anderson9f944592009-08-11 20:47:22 +00001468 } else if (LoadedVT == MVT::i8 || LoadedVT == MVT::i1) {
Evan Chengd9c55362009-07-02 01:23:32 +00001469 if (LD->getExtensionType() == ISD::SEXTLOAD) {
Dan Gohmanea6f91f2010-01-05 01:24:18 +00001470 if (SelectAddrMode3Offset(N, LD->getOffset(), Offset, AMOpc)) {
Evan Chengd9c55362009-07-02 01:23:32 +00001471 Match = true;
1472 Opcode = isPre ? ARM::LDRSB_PRE : ARM::LDRSB_POST;
1473 }
1474 } else {
Owen Anderson4d5c8f82011-08-29 20:16:50 +00001475 if (isPre &&
1476 SelectAddrMode2OffsetImmPre(N, LD->getOffset(), Offset, AMOpc)) {
Evan Chengd9c55362009-07-02 01:23:32 +00001477 Match = true;
Owen Anderson4d5c8f82011-08-29 20:16:50 +00001478 Opcode = ARM::LDRB_PRE_IMM;
1479 } else if (!isPre &&
1480 SelectAddrMode2OffsetImm(N, LD->getOffset(), Offset, AMOpc)) {
1481 Match = true;
1482 Opcode = ARM::LDRB_POST_IMM;
Owen Anderson2aedba62011-07-26 20:54:26 +00001483 } else if (SelectAddrMode2OffsetReg(N, LD->getOffset(), Offset, AMOpc)) {
1484 Match = true;
Owen Anderson16d33f32011-08-26 20:43:14 +00001485 Opcode = isPre ? ARM::LDRB_PRE_REG : ARM::LDRB_POST_REG;
Evan Chengd9c55362009-07-02 01:23:32 +00001486 }
1487 }
1488 }
1489
1490 if (Match) {
Owen Andersonfd60f602011-08-26 21:12:37 +00001491 if (Opcode == ARM::LDR_PRE_IMM || Opcode == ARM::LDRB_PRE_IMM) {
1492 SDValue Chain = LD->getChain();
1493 SDValue Base = LD->getBasePtr();
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00001494 SDValue Ops[]= { Base, AMOpc, getAL(CurDAG, SDLoc(N)),
Owen Andersonfd60f602011-08-26 21:12:37 +00001495 CurDAG->getRegister(0, MVT::i32), Chain };
Tim Northovereaee28b2016-09-19 09:11:09 +00001496 SDNode *New = CurDAG->getMachineNode(Opcode, SDLoc(N), MVT::i32, MVT::i32,
1497 MVT::Other, Ops);
1498 transferMemOperands(N, New);
1499 ReplaceNode(N, New);
Justin Bogner45571362016-05-12 00:31:09 +00001500 return true;
Owen Andersonfd60f602011-08-26 21:12:37 +00001501 } else {
1502 SDValue Chain = LD->getChain();
1503 SDValue Base = LD->getBasePtr();
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00001504 SDValue Ops[]= { Base, Offset, AMOpc, getAL(CurDAG, SDLoc(N)),
Owen Andersonfd60f602011-08-26 21:12:37 +00001505 CurDAG->getRegister(0, MVT::i32), Chain };
Tim Northovereaee28b2016-09-19 09:11:09 +00001506 SDNode *New = CurDAG->getMachineNode(Opcode, SDLoc(N), MVT::i32, MVT::i32,
1507 MVT::Other, Ops);
1508 transferMemOperands(N, New);
1509 ReplaceNode(N, New);
Justin Bogner45571362016-05-12 00:31:09 +00001510 return true;
Owen Andersonfd60f602011-08-26 21:12:37 +00001511 }
Evan Chengd9c55362009-07-02 01:23:32 +00001512 }
1513
Justin Bogner45571362016-05-12 00:31:09 +00001514 return false;
Evan Chengd9c55362009-07-02 01:23:32 +00001515}
1516
James Molloyb3326df2016-07-15 08:03:56 +00001517bool ARMDAGToDAGISel::tryT1IndexedLoad(SDNode *N) {
1518 LoadSDNode *LD = cast<LoadSDNode>(N);
1519 EVT LoadedVT = LD->getMemoryVT();
1520 ISD::MemIndexedMode AM = LD->getAddressingMode();
Chandler Carruth5589aa62016-11-03 17:42:02 +00001521 if (AM != ISD::POST_INC || LD->getExtensionType() != ISD::NON_EXTLOAD ||
1522 LoadedVT.getSimpleVT().SimpleTy != MVT::i32)
James Molloyb3326df2016-07-15 08:03:56 +00001523 return false;
1524
1525 auto *COffs = dyn_cast<ConstantSDNode>(LD->getOffset());
1526 if (!COffs || COffs->getZExtValue() != 4)
1527 return false;
1528
1529 // A T1 post-indexed load is just a single register LDM: LDM r0!, {r1}.
1530 // The encoding of LDM is not how the rest of ISel expects a post-inc load to
1531 // look however, so we use a pseudo here and switch it for a tLDMIA_UPD after
1532 // ISel.
1533 SDValue Chain = LD->getChain();
1534 SDValue Base = LD->getBasePtr();
1535 SDValue Ops[]= { Base, getAL(CurDAG, SDLoc(N)),
1536 CurDAG->getRegister(0, MVT::i32), Chain };
Tim Northovereaee28b2016-09-19 09:11:09 +00001537 SDNode *New = CurDAG->getMachineNode(ARM::tLDR_postidx, SDLoc(N), MVT::i32,
1538 MVT::i32, MVT::Other, Ops);
1539 transferMemOperands(N, New);
1540 ReplaceNode(N, New);
James Molloyb3326df2016-07-15 08:03:56 +00001541 return true;
1542}
1543
Justin Bogner45571362016-05-12 00:31:09 +00001544bool ARMDAGToDAGISel::tryT2IndexedLoad(SDNode *N) {
Dan Gohmanea6f91f2010-01-05 01:24:18 +00001545 LoadSDNode *LD = cast<LoadSDNode>(N);
Evan Cheng84c6cda2009-07-02 07:28:31 +00001546 ISD::MemIndexedMode AM = LD->getAddressingMode();
1547 if (AM == ISD::UNINDEXED)
Justin Bogner45571362016-05-12 00:31:09 +00001548 return false;
Evan Cheng84c6cda2009-07-02 07:28:31 +00001549
Owen Anderson53aa7a92009-08-10 22:56:29 +00001550 EVT LoadedVT = LD->getMemoryVT();
Evan Cheng8ecd7eb2009-07-02 23:16:11 +00001551 bool isSExtLd = LD->getExtensionType() == ISD::SEXTLOAD;
Evan Cheng84c6cda2009-07-02 07:28:31 +00001552 SDValue Offset;
1553 bool isPre = (AM == ISD::PRE_INC) || (AM == ISD::PRE_DEC);
1554 unsigned Opcode = 0;
1555 bool Match = false;
Dan Gohmanea6f91f2010-01-05 01:24:18 +00001556 if (SelectT2AddrModeImm8Offset(N, LD->getOffset(), Offset)) {
Owen Anderson9f944592009-08-11 20:47:22 +00001557 switch (LoadedVT.getSimpleVT().SimpleTy) {
1558 case MVT::i32:
Evan Cheng84c6cda2009-07-02 07:28:31 +00001559 Opcode = isPre ? ARM::t2LDR_PRE : ARM::t2LDR_POST;
1560 break;
Owen Anderson9f944592009-08-11 20:47:22 +00001561 case MVT::i16:
Evan Cheng8ecd7eb2009-07-02 23:16:11 +00001562 if (isSExtLd)
1563 Opcode = isPre ? ARM::t2LDRSH_PRE : ARM::t2LDRSH_POST;
1564 else
1565 Opcode = isPre ? ARM::t2LDRH_PRE : ARM::t2LDRH_POST;
Evan Cheng84c6cda2009-07-02 07:28:31 +00001566 break;
Owen Anderson9f944592009-08-11 20:47:22 +00001567 case MVT::i8:
1568 case MVT::i1:
Evan Cheng8ecd7eb2009-07-02 23:16:11 +00001569 if (isSExtLd)
1570 Opcode = isPre ? ARM::t2LDRSB_PRE : ARM::t2LDRSB_POST;
1571 else
1572 Opcode = isPre ? ARM::t2LDRB_PRE : ARM::t2LDRB_POST;
Evan Cheng84c6cda2009-07-02 07:28:31 +00001573 break;
1574 default:
Justin Bogner45571362016-05-12 00:31:09 +00001575 return false;
Evan Cheng84c6cda2009-07-02 07:28:31 +00001576 }
1577 Match = true;
1578 }
1579
1580 if (Match) {
1581 SDValue Chain = LD->getChain();
1582 SDValue Base = LD->getBasePtr();
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00001583 SDValue Ops[]= { Base, Offset, getAL(CurDAG, SDLoc(N)),
Owen Anderson9f944592009-08-11 20:47:22 +00001584 CurDAG->getRegister(0, MVT::i32), Chain };
Tim Northovereaee28b2016-09-19 09:11:09 +00001585 SDNode *New = CurDAG->getMachineNode(Opcode, SDLoc(N), MVT::i32, MVT::i32,
1586 MVT::Other, Ops);
1587 transferMemOperands(N, New);
1588 ReplaceNode(N, New);
Justin Bogner45571362016-05-12 00:31:09 +00001589 return true;
Evan Cheng84c6cda2009-07-02 07:28:31 +00001590 }
1591
Justin Bogner45571362016-05-12 00:31:09 +00001592 return false;
Evan Cheng84c6cda2009-07-02 07:28:31 +00001593}
1594
David Green27ca82f2019-08-08 15:27:58 +00001595bool ARMDAGToDAGISel::tryMVEIndexedLoad(SDNode *N) {
1596 LoadSDNode *LD = cast<LoadSDNode>(N);
1597 ISD::MemIndexedMode AM = LD->getAddressingMode();
1598 if (AM == ISD::UNINDEXED)
1599 return false;
1600 EVT LoadedVT = LD->getMemoryVT();
1601 if (!LoadedVT.isVector())
1602 return false;
1603 bool isSExtLd = LD->getExtensionType() == ISD::SEXTLOAD;
1604 SDValue Offset;
1605 bool isPre = (AM == ISD::PRE_INC) || (AM == ISD::PRE_DEC);
1606 unsigned Opcode = 0;
1607 unsigned Align = LD->getAlignment();
1608 bool IsLE = Subtarget->isLittle();
1609
1610 if (Align >= 2 && LoadedVT == MVT::v4i16 &&
1611 SelectT2AddrModeImm7Offset(N, LD->getOffset(), Offset, 1)) {
1612 if (isSExtLd)
1613 Opcode = isPre ? ARM::MVE_VLDRHS32_pre : ARM::MVE_VLDRHS32_post;
1614 else
1615 Opcode = isPre ? ARM::MVE_VLDRHU32_pre : ARM::MVE_VLDRHU32_post;
1616 } else if (LoadedVT == MVT::v8i8 &&
1617 SelectT2AddrModeImm7Offset(N, LD->getOffset(), Offset, 0)) {
1618 if (isSExtLd)
1619 Opcode = isPre ? ARM::MVE_VLDRBS16_pre : ARM::MVE_VLDRBS16_post;
1620 else
1621 Opcode = isPre ? ARM::MVE_VLDRBU16_pre : ARM::MVE_VLDRBU16_post;
1622 } else if (LoadedVT == MVT::v4i8 &&
1623 SelectT2AddrModeImm7Offset(N, LD->getOffset(), Offset, 0)) {
1624 if (isSExtLd)
1625 Opcode = isPre ? ARM::MVE_VLDRBS32_pre : ARM::MVE_VLDRBS32_post;
1626 else
1627 Opcode = isPre ? ARM::MVE_VLDRBU32_pre : ARM::MVE_VLDRBU32_post;
1628 } else if (Align >= 4 &&
1629 (IsLE || LoadedVT == MVT::v4i32 || LoadedVT == MVT::v4f32) &&
1630 SelectT2AddrModeImm7Offset(N, LD->getOffset(), Offset, 2))
1631 Opcode = isPre ? ARM::MVE_VLDRWU32_pre : ARM::MVE_VLDRWU32_post;
1632 else if (Align >= 2 &&
1633 (IsLE || LoadedVT == MVT::v8i16 || LoadedVT == MVT::v8f16) &&
1634 SelectT2AddrModeImm7Offset(N, LD->getOffset(), Offset, 1))
1635 Opcode = isPre ? ARM::MVE_VLDRHU16_pre : ARM::MVE_VLDRHU16_post;
1636 else if ((IsLE || LoadedVT == MVT::v16i8) &&
1637 SelectT2AddrModeImm7Offset(N, LD->getOffset(), Offset, 0))
1638 Opcode = isPre ? ARM::MVE_VLDRBU8_pre : ARM::MVE_VLDRBU8_post;
1639 else
1640 return false;
1641
1642 SDValue Chain = LD->getChain();
1643 SDValue Base = LD->getBasePtr();
1644 SDValue Ops[] = {Base, Offset,
1645 CurDAG->getTargetConstant(ARMVCC::None, SDLoc(N), MVT::i32),
1646 CurDAG->getRegister(0, MVT::i32), Chain};
1647 SDNode *New = CurDAG->getMachineNode(Opcode, SDLoc(N), LD->getValueType(0),
1648 MVT::i32, MVT::Other, Ops);
1649 transferMemOperands(N, New);
1650 ReplaceUses(SDValue(N, 0), SDValue(New, 1));
1651 ReplaceUses(SDValue(N, 1), SDValue(New, 0));
1652 ReplaceUses(SDValue(N, 2), SDValue(New, 2));
1653 CurDAG->RemoveDeadNode(N);
1654 return true;
1655}
1656
Adrian Prantl5f8f34e42018-05-01 15:54:18 +00001657/// Form a GPRPair pseudo register from a pair of GPR regs.
Weiming Zhao8f56f882012-11-16 21:55:34 +00001658SDNode *ARMDAGToDAGISel::createGPRPairNode(EVT VT, SDValue V0, SDValue V1) {
Andrew Trickef9de2a2013-05-25 02:42:55 +00001659 SDLoc dl(V0.getNode());
Weiming Zhao8f56f882012-11-16 21:55:34 +00001660 SDValue RegClass =
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00001661 CurDAG->getTargetConstant(ARM::GPRPairRegClassID, dl, MVT::i32);
1662 SDValue SubReg0 = CurDAG->getTargetConstant(ARM::gsub_0, dl, MVT::i32);
1663 SDValue SubReg1 = CurDAG->getTargetConstant(ARM::gsub_1, dl, MVT::i32);
Weiming Zhao8f56f882012-11-16 21:55:34 +00001664 const SDValue Ops[] = { RegClass, V0, SubReg0, V1, SubReg1 };
Michael Liaob53d8962013-04-19 22:22:57 +00001665 return CurDAG->getMachineNode(TargetOpcode::REG_SEQUENCE, dl, VT, Ops);
Weiming Zhao8f56f882012-11-16 21:55:34 +00001666}
1667
Adrian Prantl5f8f34e42018-05-01 15:54:18 +00001668/// Form a D register from a pair of S registers.
Weiming Zhao95782222012-11-17 00:23:35 +00001669SDNode *ARMDAGToDAGISel::createSRegPairNode(EVT VT, SDValue V0, SDValue V1) {
Andrew Trickef9de2a2013-05-25 02:42:55 +00001670 SDLoc dl(V0.getNode());
Owen Anderson5fc8b772011-06-16 18:17:13 +00001671 SDValue RegClass =
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00001672 CurDAG->getTargetConstant(ARM::DPR_VFP2RegClassID, dl, MVT::i32);
1673 SDValue SubReg0 = CurDAG->getTargetConstant(ARM::ssub_0, dl, MVT::i32);
1674 SDValue SubReg1 = CurDAG->getTargetConstant(ARM::ssub_1, dl, MVT::i32);
Owen Anderson5fc8b772011-06-16 18:17:13 +00001675 const SDValue Ops[] = { RegClass, V0, SubReg0, V1, SubReg1 };
Michael Liaob53d8962013-04-19 22:22:57 +00001676 return CurDAG->getMachineNode(TargetOpcode::REG_SEQUENCE, dl, VT, Ops);
Bob Wilsond8a9a042010-06-04 00:04:02 +00001677}
1678
Adrian Prantl5f8f34e42018-05-01 15:54:18 +00001679/// Form a quad register from a pair of D registers.
Weiming Zhao95782222012-11-17 00:23:35 +00001680SDNode *ARMDAGToDAGISel::createDRegPairNode(EVT VT, SDValue V0, SDValue V1) {
Andrew Trickef9de2a2013-05-25 02:42:55 +00001681 SDLoc dl(V0.getNode());
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00001682 SDValue RegClass = CurDAG->getTargetConstant(ARM::QPRRegClassID, dl,
1683 MVT::i32);
1684 SDValue SubReg0 = CurDAG->getTargetConstant(ARM::dsub_0, dl, MVT::i32);
1685 SDValue SubReg1 = CurDAG->getTargetConstant(ARM::dsub_1, dl, MVT::i32);
Owen Anderson5fc8b772011-06-16 18:17:13 +00001686 const SDValue Ops[] = { RegClass, V0, SubReg0, V1, SubReg1 };
Michael Liaob53d8962013-04-19 22:22:57 +00001687 return CurDAG->getMachineNode(TargetOpcode::REG_SEQUENCE, dl, VT, Ops);
Bob Wilsone6b778d2009-10-06 22:01:59 +00001688}
1689
Adrian Prantl5f8f34e42018-05-01 15:54:18 +00001690/// Form 4 consecutive D registers from a pair of Q registers.
Weiming Zhao95782222012-11-17 00:23:35 +00001691SDNode *ARMDAGToDAGISel::createQRegPairNode(EVT VT, SDValue V0, SDValue V1) {
Andrew Trickef9de2a2013-05-25 02:42:55 +00001692 SDLoc dl(V0.getNode());
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00001693 SDValue RegClass = CurDAG->getTargetConstant(ARM::QQPRRegClassID, dl,
1694 MVT::i32);
1695 SDValue SubReg0 = CurDAG->getTargetConstant(ARM::qsub_0, dl, MVT::i32);
1696 SDValue SubReg1 = CurDAG->getTargetConstant(ARM::qsub_1, dl, MVT::i32);
Owen Anderson5fc8b772011-06-16 18:17:13 +00001697 const SDValue Ops[] = { RegClass, V0, SubReg0, V1, SubReg1 };
Michael Liaob53d8962013-04-19 22:22:57 +00001698 return CurDAG->getMachineNode(TargetOpcode::REG_SEQUENCE, dl, VT, Ops);
Evan Chengc2ae5f52010-05-10 17:34:18 +00001699}
1700
Adrian Prantl5f8f34e42018-05-01 15:54:18 +00001701/// Form 4 consecutive S registers.
Weiming Zhao95782222012-11-17 00:23:35 +00001702SDNode *ARMDAGToDAGISel::createQuadSRegsNode(EVT VT, SDValue V0, SDValue V1,
Bob Wilsond8a9a042010-06-04 00:04:02 +00001703 SDValue V2, SDValue V3) {
Andrew Trickef9de2a2013-05-25 02:42:55 +00001704 SDLoc dl(V0.getNode());
Owen Anderson5fc8b772011-06-16 18:17:13 +00001705 SDValue RegClass =
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00001706 CurDAG->getTargetConstant(ARM::QPR_VFP2RegClassID, dl, MVT::i32);
1707 SDValue SubReg0 = CurDAG->getTargetConstant(ARM::ssub_0, dl, MVT::i32);
1708 SDValue SubReg1 = CurDAG->getTargetConstant(ARM::ssub_1, dl, MVT::i32);
1709 SDValue SubReg2 = CurDAG->getTargetConstant(ARM::ssub_2, dl, MVT::i32);
1710 SDValue SubReg3 = CurDAG->getTargetConstant(ARM::ssub_3, dl, MVT::i32);
Owen Anderson5fc8b772011-06-16 18:17:13 +00001711 const SDValue Ops[] = { RegClass, V0, SubReg0, V1, SubReg1,
1712 V2, SubReg2, V3, SubReg3 };
Michael Liaob53d8962013-04-19 22:22:57 +00001713 return CurDAG->getMachineNode(TargetOpcode::REG_SEQUENCE, dl, VT, Ops);
Bob Wilsond8a9a042010-06-04 00:04:02 +00001714}
1715
Adrian Prantl5f8f34e42018-05-01 15:54:18 +00001716/// Form 4 consecutive D registers.
Weiming Zhao95782222012-11-17 00:23:35 +00001717SDNode *ARMDAGToDAGISel::createQuadDRegsNode(EVT VT, SDValue V0, SDValue V1,
Evan Chengc2ae5f52010-05-10 17:34:18 +00001718 SDValue V2, SDValue V3) {
Andrew Trickef9de2a2013-05-25 02:42:55 +00001719 SDLoc dl(V0.getNode());
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00001720 SDValue RegClass = CurDAG->getTargetConstant(ARM::QQPRRegClassID, dl,
1721 MVT::i32);
1722 SDValue SubReg0 = CurDAG->getTargetConstant(ARM::dsub_0, dl, MVT::i32);
1723 SDValue SubReg1 = CurDAG->getTargetConstant(ARM::dsub_1, dl, MVT::i32);
1724 SDValue SubReg2 = CurDAG->getTargetConstant(ARM::dsub_2, dl, MVT::i32);
1725 SDValue SubReg3 = CurDAG->getTargetConstant(ARM::dsub_3, dl, MVT::i32);
Owen Anderson5fc8b772011-06-16 18:17:13 +00001726 const SDValue Ops[] = { RegClass, V0, SubReg0, V1, SubReg1,
1727 V2, SubReg2, V3, SubReg3 };
Michael Liaob53d8962013-04-19 22:22:57 +00001728 return CurDAG->getMachineNode(TargetOpcode::REG_SEQUENCE, dl, VT, Ops);
Evan Chengc2ae5f52010-05-10 17:34:18 +00001729}
1730
Adrian Prantl5f8f34e42018-05-01 15:54:18 +00001731/// Form 4 consecutive Q registers.
Weiming Zhao95782222012-11-17 00:23:35 +00001732SDNode *ARMDAGToDAGISel::createQuadQRegsNode(EVT VT, SDValue V0, SDValue V1,
Evan Cheng298e6b82010-05-16 03:27:48 +00001733 SDValue V2, SDValue V3) {
Andrew Trickef9de2a2013-05-25 02:42:55 +00001734 SDLoc dl(V0.getNode());
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00001735 SDValue RegClass = CurDAG->getTargetConstant(ARM::QQQQPRRegClassID, dl,
1736 MVT::i32);
1737 SDValue SubReg0 = CurDAG->getTargetConstant(ARM::qsub_0, dl, MVT::i32);
1738 SDValue SubReg1 = CurDAG->getTargetConstant(ARM::qsub_1, dl, MVT::i32);
1739 SDValue SubReg2 = CurDAG->getTargetConstant(ARM::qsub_2, dl, MVT::i32);
1740 SDValue SubReg3 = CurDAG->getTargetConstant(ARM::qsub_3, dl, MVT::i32);
Owen Anderson5fc8b772011-06-16 18:17:13 +00001741 const SDValue Ops[] = { RegClass, V0, SubReg0, V1, SubReg1,
1742 V2, SubReg2, V3, SubReg3 };
Michael Liaob53d8962013-04-19 22:22:57 +00001743 return CurDAG->getMachineNode(TargetOpcode::REG_SEQUENCE, dl, VT, Ops);
Evan Cheng298e6b82010-05-16 03:27:48 +00001744}
1745
Bob Wilson7fbbe9a2010-09-23 23:42:37 +00001746/// GetVLDSTAlign - Get the alignment (in bytes) for the alignment operand
1747/// of a NEON VLD or VST instruction. The supported values depend on the
1748/// number of registers being loaded.
Benjamin Kramerbdc49562016-06-12 15:39:02 +00001749SDValue ARMDAGToDAGISel::GetVLDSTAlign(SDValue Align, const SDLoc &dl,
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00001750 unsigned NumVecs, bool is64BitVector) {
Bob Wilson7fbbe9a2010-09-23 23:42:37 +00001751 unsigned NumRegs = NumVecs;
1752 if (!is64BitVector && NumVecs < 3)
1753 NumRegs *= 2;
1754
Bob Wilsondd9fbaa2010-11-01 23:40:51 +00001755 unsigned Alignment = cast<ConstantSDNode>(Align)->getZExtValue();
Bob Wilson7fbbe9a2010-09-23 23:42:37 +00001756 if (Alignment >= 32 && NumRegs == 4)
Bob Wilsondd9fbaa2010-11-01 23:40:51 +00001757 Alignment = 32;
1758 else if (Alignment >= 16 && (NumRegs == 2 || NumRegs == 4))
1759 Alignment = 16;
1760 else if (Alignment >= 8)
1761 Alignment = 8;
1762 else
1763 Alignment = 0;
1764
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00001765 return CurDAG->getTargetConstant(Alignment, dl, MVT::i32);
Bob Wilson7fbbe9a2010-09-23 23:42:37 +00001766}
1767
Jiangning Liu4df23632014-01-16 09:16:13 +00001768static bool isVLDfixed(unsigned Opc)
1769{
1770 switch (Opc) {
1771 default: return false;
1772 case ARM::VLD1d8wb_fixed : return true;
1773 case ARM::VLD1d16wb_fixed : return true;
1774 case ARM::VLD1d64Qwb_fixed : return true;
1775 case ARM::VLD1d32wb_fixed : return true;
1776 case ARM::VLD1d64wb_fixed : return true;
1777 case ARM::VLD1d64TPseudoWB_fixed : return true;
1778 case ARM::VLD1d64QPseudoWB_fixed : return true;
1779 case ARM::VLD1q8wb_fixed : return true;
1780 case ARM::VLD1q16wb_fixed : return true;
1781 case ARM::VLD1q32wb_fixed : return true;
1782 case ARM::VLD1q64wb_fixed : return true;
Eli Friedmanf624ec22016-12-16 18:44:08 +00001783 case ARM::VLD1DUPd8wb_fixed : return true;
1784 case ARM::VLD1DUPd16wb_fixed : return true;
1785 case ARM::VLD1DUPd32wb_fixed : return true;
1786 case ARM::VLD1DUPq8wb_fixed : return true;
1787 case ARM::VLD1DUPq16wb_fixed : return true;
1788 case ARM::VLD1DUPq32wb_fixed : return true;
Jiangning Liu4df23632014-01-16 09:16:13 +00001789 case ARM::VLD2d8wb_fixed : return true;
1790 case ARM::VLD2d16wb_fixed : return true;
1791 case ARM::VLD2d32wb_fixed : return true;
1792 case ARM::VLD2q8PseudoWB_fixed : return true;
1793 case ARM::VLD2q16PseudoWB_fixed : return true;
1794 case ARM::VLD2q32PseudoWB_fixed : return true;
1795 case ARM::VLD2DUPd8wb_fixed : return true;
1796 case ARM::VLD2DUPd16wb_fixed : return true;
1797 case ARM::VLD2DUPd32wb_fixed : return true;
1798 }
1799}
1800
1801static bool isVSTfixed(unsigned Opc)
1802{
1803 switch (Opc) {
1804 default: return false;
1805 case ARM::VST1d8wb_fixed : return true;
1806 case ARM::VST1d16wb_fixed : return true;
1807 case ARM::VST1d32wb_fixed : return true;
1808 case ARM::VST1d64wb_fixed : return true;
Jim Grosbach1a597112014-04-03 23:43:18 +00001809 case ARM::VST1q8wb_fixed : return true;
1810 case ARM::VST1q16wb_fixed : return true;
1811 case ARM::VST1q32wb_fixed : return true;
1812 case ARM::VST1q64wb_fixed : return true;
Jiangning Liu4df23632014-01-16 09:16:13 +00001813 case ARM::VST1d64TPseudoWB_fixed : return true;
1814 case ARM::VST1d64QPseudoWB_fixed : return true;
1815 case ARM::VST2d8wb_fixed : return true;
1816 case ARM::VST2d16wb_fixed : return true;
1817 case ARM::VST2d32wb_fixed : return true;
1818 case ARM::VST2q8PseudoWB_fixed : return true;
1819 case ARM::VST2q16PseudoWB_fixed : return true;
1820 case ARM::VST2q32PseudoWB_fixed : return true;
1821 }
1822}
1823
Jim Grosbach2098cb12011-10-24 21:45:13 +00001824// Get the register stride update opcode of a VLD/VST instruction that
1825// is otherwise equivalent to the given fixed stride updating instruction.
1826static unsigned getVLDSTRegisterUpdateOpcode(unsigned Opc) {
Jiangning Liu4df23632014-01-16 09:16:13 +00001827 assert((isVLDfixed(Opc) || isVSTfixed(Opc))
1828 && "Incorrect fixed stride updating instruction.");
Jim Grosbach2098cb12011-10-24 21:45:13 +00001829 switch (Opc) {
1830 default: break;
1831 case ARM::VLD1d8wb_fixed: return ARM::VLD1d8wb_register;
1832 case ARM::VLD1d16wb_fixed: return ARM::VLD1d16wb_register;
1833 case ARM::VLD1d32wb_fixed: return ARM::VLD1d32wb_register;
1834 case ARM::VLD1d64wb_fixed: return ARM::VLD1d64wb_register;
1835 case ARM::VLD1q8wb_fixed: return ARM::VLD1q8wb_register;
1836 case ARM::VLD1q16wb_fixed: return ARM::VLD1q16wb_register;
1837 case ARM::VLD1q32wb_fixed: return ARM::VLD1q32wb_register;
1838 case ARM::VLD1q64wb_fixed: return ARM::VLD1q64wb_register;
Jiangning Liu4df23632014-01-16 09:16:13 +00001839 case ARM::VLD1d64Twb_fixed: return ARM::VLD1d64Twb_register;
1840 case ARM::VLD1d64Qwb_fixed: return ARM::VLD1d64Qwb_register;
1841 case ARM::VLD1d64TPseudoWB_fixed: return ARM::VLD1d64TPseudoWB_register;
1842 case ARM::VLD1d64QPseudoWB_fixed: return ARM::VLD1d64QPseudoWB_register;
Eli Friedmanf624ec22016-12-16 18:44:08 +00001843 case ARM::VLD1DUPd8wb_fixed : return ARM::VLD1DUPd8wb_register;
1844 case ARM::VLD1DUPd16wb_fixed : return ARM::VLD1DUPd16wb_register;
1845 case ARM::VLD1DUPd32wb_fixed : return ARM::VLD1DUPd32wb_register;
1846 case ARM::VLD1DUPq8wb_fixed : return ARM::VLD1DUPq8wb_register;
1847 case ARM::VLD1DUPq16wb_fixed : return ARM::VLD1DUPq16wb_register;
1848 case ARM::VLD1DUPq32wb_fixed : return ARM::VLD1DUPq32wb_register;
Jim Grosbach05df4602011-10-31 21:50:31 +00001849
1850 case ARM::VST1d8wb_fixed: return ARM::VST1d8wb_register;
1851 case ARM::VST1d16wb_fixed: return ARM::VST1d16wb_register;
1852 case ARM::VST1d32wb_fixed: return ARM::VST1d32wb_register;
1853 case ARM::VST1d64wb_fixed: return ARM::VST1d64wb_register;
1854 case ARM::VST1q8wb_fixed: return ARM::VST1q8wb_register;
1855 case ARM::VST1q16wb_fixed: return ARM::VST1q16wb_register;
1856 case ARM::VST1q32wb_fixed: return ARM::VST1q32wb_register;
1857 case ARM::VST1q64wb_fixed: return ARM::VST1q64wb_register;
Jim Grosbach98d032f2011-11-29 22:38:04 +00001858 case ARM::VST1d64TPseudoWB_fixed: return ARM::VST1d64TPseudoWB_register;
Jim Grosbach5ee209c2011-11-29 22:58:48 +00001859 case ARM::VST1d64QPseudoWB_fixed: return ARM::VST1d64QPseudoWB_register;
Jim Grosbachd146a022011-12-09 21:28:25 +00001860
Jim Grosbachc988e0c2012-03-05 19:33:30 +00001861 case ARM::VLD2d8wb_fixed: return ARM::VLD2d8wb_register;
1862 case ARM::VLD2d16wb_fixed: return ARM::VLD2d16wb_register;
1863 case ARM::VLD2d32wb_fixed: return ARM::VLD2d32wb_register;
Jim Grosbachd146a022011-12-09 21:28:25 +00001864 case ARM::VLD2q8PseudoWB_fixed: return ARM::VLD2q8PseudoWB_register;
1865 case ARM::VLD2q16PseudoWB_fixed: return ARM::VLD2q16PseudoWB_register;
1866 case ARM::VLD2q32PseudoWB_fixed: return ARM::VLD2q32PseudoWB_register;
1867
Jim Grosbachc988e0c2012-03-05 19:33:30 +00001868 case ARM::VST2d8wb_fixed: return ARM::VST2d8wb_register;
1869 case ARM::VST2d16wb_fixed: return ARM::VST2d16wb_register;
1870 case ARM::VST2d32wb_fixed: return ARM::VST2d32wb_register;
Jim Grosbach88ac7612011-12-14 21:32:11 +00001871 case ARM::VST2q8PseudoWB_fixed: return ARM::VST2q8PseudoWB_register;
1872 case ARM::VST2q16PseudoWB_fixed: return ARM::VST2q16PseudoWB_register;
1873 case ARM::VST2q32PseudoWB_fixed: return ARM::VST2q32PseudoWB_register;
Jim Grosbachc80a2642011-12-21 19:40:55 +00001874
Jim Grosbach13a292c2012-03-06 22:01:44 +00001875 case ARM::VLD2DUPd8wb_fixed: return ARM::VLD2DUPd8wb_register;
1876 case ARM::VLD2DUPd16wb_fixed: return ARM::VLD2DUPd16wb_register;
1877 case ARM::VLD2DUPd32wb_fixed: return ARM::VLD2DUPd32wb_register;
Jim Grosbach2098cb12011-10-24 21:45:13 +00001878 }
1879 return Opc; // If not one we handle, return it unchanged.
1880}
1881
Tim Northover8b1240b2017-04-20 19:54:02 +00001882/// Returns true if the given increment is a Constant known to be equal to the
1883/// access size performed by a NEON load/store. This means the "[rN]!" form can
1884/// be used.
1885static bool isPerfectIncrement(SDValue Inc, EVT VecTy, unsigned NumVecs) {
1886 auto C = dyn_cast<ConstantSDNode>(Inc);
1887 return C && C->getZExtValue() == VecTy.getSizeInBits() / 8 * NumVecs;
1888}
1889
Justin Bogner45571362016-05-12 00:31:09 +00001890void ARMDAGToDAGISel::SelectVLD(SDNode *N, bool isUpdating, unsigned NumVecs,
1891 const uint16_t *DOpcodes,
1892 const uint16_t *QOpcodes0,
1893 const uint16_t *QOpcodes1) {
Bob Wilson340861d2010-03-23 05:25:43 +00001894 assert(NumVecs >= 1 && NumVecs <= 4 && "VLD NumVecs out-of-range");
Andrew Trickef9de2a2013-05-25 02:42:55 +00001895 SDLoc dl(N);
Bob Wilson12b47992009-10-14 17:28:52 +00001896
Bob Wilsonae08a732010-03-20 22:13:40 +00001897 SDValue MemAddr, Align;
Ivan A. Kosarev72315982018-06-27 13:57:52 +00001898 bool IsIntrinsic = !isUpdating; // By coincidence, all supported updating
1899 // nodes are not intrinsics.
1900 unsigned AddrOpIdx = IsIntrinsic ? 2 : 1;
Bob Wilson06fce872011-02-07 17:43:21 +00001901 if (!SelectAddrMode6(N, N->getOperand(AddrOpIdx), MemAddr, Align))
Justin Bogner45571362016-05-12 00:31:09 +00001902 return;
Bob Wilson12b47992009-10-14 17:28:52 +00001903
1904 SDValue Chain = N->getOperand(0);
1905 EVT VT = N->getValueType(0);
1906 bool is64BitVector = VT.is64BitVector();
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00001907 Align = GetVLDSTAlign(Align, dl, NumVecs, is64BitVector);
Bob Wilson9eeb8902010-09-23 21:43:54 +00001908
Bob Wilson12b47992009-10-14 17:28:52 +00001909 unsigned OpcodeIndex;
1910 switch (VT.getSimpleVT().SimpleTy) {
1911 default: llvm_unreachable("unhandled vld type");
1912 // Double-register operations:
1913 case MVT::v8i8: OpcodeIndex = 0; break;
Sjoerd Meijer5afc9572018-12-03 08:26:34 +00001914 case MVT::v4f16:
Bob Wilson12b47992009-10-14 17:28:52 +00001915 case MVT::v4i16: OpcodeIndex = 1; break;
1916 case MVT::v2f32:
1917 case MVT::v2i32: OpcodeIndex = 2; break;
1918 case MVT::v1i64: OpcodeIndex = 3; break;
1919 // Quad-register operations:
1920 case MVT::v16i8: OpcodeIndex = 0; break;
Sjoerd Meijer5afc9572018-12-03 08:26:34 +00001921 case MVT::v8f16:
Bob Wilson12b47992009-10-14 17:28:52 +00001922 case MVT::v8i16: OpcodeIndex = 1; break;
1923 case MVT::v4f32:
1924 case MVT::v4i32: OpcodeIndex = 2; break;
Ahmed Bougachabe0b2272014-12-09 21:25:00 +00001925 case MVT::v2f64:
Ivan A. Kosarev60a991e2018-06-02 16:40:03 +00001926 case MVT::v2i64: OpcodeIndex = 3; break;
Bob Wilson12b47992009-10-14 17:28:52 +00001927 }
1928
Bob Wilson35fafca2010-09-03 18:16:02 +00001929 EVT ResTy;
1930 if (NumVecs == 1)
1931 ResTy = VT;
1932 else {
1933 unsigned ResTyElts = (NumVecs == 3) ? 4 : NumVecs;
1934 if (!is64BitVector)
1935 ResTyElts *= 2;
1936 ResTy = EVT::getVectorVT(*CurDAG->getContext(), MVT::i64, ResTyElts);
1937 }
Bob Wilson06fce872011-02-07 17:43:21 +00001938 std::vector<EVT> ResTys;
1939 ResTys.push_back(ResTy);
1940 if (isUpdating)
1941 ResTys.push_back(MVT::i32);
1942 ResTys.push_back(MVT::Other);
Bob Wilson35fafca2010-09-03 18:16:02 +00001943
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00001944 SDValue Pred = getAL(CurDAG, dl);
Bob Wilsonae08a732010-03-20 22:13:40 +00001945 SDValue Reg0 = CurDAG->getRegister(0, MVT::i32);
Bob Wilson06fce872011-02-07 17:43:21 +00001946 SDNode *VLd;
1947 SmallVector<SDValue, 7> Ops;
Evan Cheng630063a2010-05-10 21:26:24 +00001948
Bob Wilson06fce872011-02-07 17:43:21 +00001949 // Double registers and VLD1/VLD2 quad registers are directly supported.
1950 if (is64BitVector || NumVecs <= 2) {
1951 unsigned Opc = (is64BitVector ? DOpcodes[OpcodeIndex] :
1952 QOpcodes0[OpcodeIndex]);
1953 Ops.push_back(MemAddr);
1954 Ops.push_back(Align);
1955 if (isUpdating) {
1956 SDValue Inc = N->getOperand(AddrOpIdx + 1);
Tim Northover8b1240b2017-04-20 19:54:02 +00001957 bool IsImmUpdate = isPerfectIncrement(Inc, VT, NumVecs);
Florian Hahn9deef202018-03-02 13:02:55 +00001958 if (!IsImmUpdate) {
1959 // We use a VLD1 for v1i64 even if the pseudo says vld2/3/4, so
1960 // check for the opcode rather than the number of vector elements.
1961 if (isVLDfixed(Opc))
1962 Opc = getVLDSTRegisterUpdateOpcode(Opc);
1963 Ops.push_back(Inc);
1964 // VLD1/VLD2 fixed increment does not need Reg0 so only include it in
1965 // the operands if not such an opcode.
1966 } else if (!isVLDfixed(Opc))
1967 Ops.push_back(Reg0);
Evan Cheng630063a2010-05-10 21:26:24 +00001968 }
Bob Wilson06fce872011-02-07 17:43:21 +00001969 Ops.push_back(Pred);
1970 Ops.push_back(Reg0);
1971 Ops.push_back(Chain);
Michael Liaob53d8962013-04-19 22:22:57 +00001972 VLd = CurDAG->getMachineNode(Opc, dl, ResTys, Ops);
Bob Wilson75a64082010-09-02 16:00:54 +00001973
Bob Wilson12b47992009-10-14 17:28:52 +00001974 } else {
1975 // Otherwise, quad registers are loaded with two separate instructions,
1976 // where one loads the even registers and the other loads the odd registers.
Bob Wilson35fafca2010-09-03 18:16:02 +00001977 EVT AddrTy = MemAddr.getValueType();
Bob Wilson12b47992009-10-14 17:28:52 +00001978
Bob Wilson06fce872011-02-07 17:43:21 +00001979 // Load the even subregs. This is always an updating load, so that it
1980 // provides the address to the second load for the odd subregs.
Bob Wilson35fafca2010-09-03 18:16:02 +00001981 SDValue ImplDef =
1982 SDValue(CurDAG->getMachineNode(TargetOpcode::IMPLICIT_DEF, dl, ResTy), 0);
1983 const SDValue OpsA[] = { MemAddr, Align, Reg0, ImplDef, Pred, Reg0, Chain };
Bob Wilsona609b892011-02-07 17:43:15 +00001984 SDNode *VLdA = CurDAG->getMachineNode(QOpcodes0[OpcodeIndex], dl,
Michael Liaob53d8962013-04-19 22:22:57 +00001985 ResTy, AddrTy, MVT::Other, OpsA);
Bob Wilson35fafca2010-09-03 18:16:02 +00001986 Chain = SDValue(VLdA, 2);
Bob Wilson12b47992009-10-14 17:28:52 +00001987
Bob Wilsonc350cdf2009-10-14 18:32:29 +00001988 // Load the odd subregs.
Bob Wilson06fce872011-02-07 17:43:21 +00001989 Ops.push_back(SDValue(VLdA, 1));
1990 Ops.push_back(Align);
1991 if (isUpdating) {
1992 SDValue Inc = N->getOperand(AddrOpIdx + 1);
1993 assert(isa<ConstantSDNode>(Inc.getNode()) &&
1994 "only constant post-increment update allowed for VLD3/4");
1995 (void)Inc;
1996 Ops.push_back(Reg0);
1997 }
1998 Ops.push_back(SDValue(VLdA, 0));
1999 Ops.push_back(Pred);
2000 Ops.push_back(Reg0);
2001 Ops.push_back(Chain);
Michael Liaob53d8962013-04-19 22:22:57 +00002002 VLd = CurDAG->getMachineNode(QOpcodes1[OpcodeIndex], dl, ResTys, Ops);
Bob Wilson35fafca2010-09-03 18:16:02 +00002003 }
Bob Wilson12b47992009-10-14 17:28:52 +00002004
Evan Cheng40791332011-04-19 00:04:03 +00002005 // Transfer memoperands.
Chandler Carruth66654b72018-08-14 23:30:32 +00002006 MachineMemOperand *MemOp = cast<MemIntrinsicSDNode>(N)->getMemOperand();
2007 CurDAG->setNodeMemRefs(cast<MachineSDNode>(VLd), {MemOp});
Evan Cheng40791332011-04-19 00:04:03 +00002008
Justin Bogner45571362016-05-12 00:31:09 +00002009 if (NumVecs == 1) {
2010 ReplaceNode(N, VLd);
2011 return;
2012 }
Bob Wilson06fce872011-02-07 17:43:21 +00002013
2014 // Extract out the subregisters.
2015 SDValue SuperReg = SDValue(VLd, 0);
Benjamin Kramer3e9a5d32016-05-27 11:36:04 +00002016 static_assert(ARM::dsub_7 == ARM::dsub_0 + 7 &&
2017 ARM::qsub_3 == ARM::qsub_0 + 3,
2018 "Unexpected subreg numbering");
Bob Wilson06fce872011-02-07 17:43:21 +00002019 unsigned Sub0 = (is64BitVector ? ARM::dsub_0 : ARM::qsub_0);
2020 for (unsigned Vec = 0; Vec < NumVecs; ++Vec)
2021 ReplaceUses(SDValue(N, Vec),
2022 CurDAG->getTargetExtractSubreg(Sub0 + Vec, dl, VT, SuperReg));
2023 ReplaceUses(SDValue(N, NumVecs), SDValue(VLd, 1));
2024 if (isUpdating)
2025 ReplaceUses(SDValue(N, NumVecs + 1), SDValue(VLd, 2));
Justin Bognered4f3782016-05-12 00:20:19 +00002026 CurDAG->RemoveDeadNode(N);
Bob Wilson12b47992009-10-14 17:28:52 +00002027}
2028
Justin Bogner45571362016-05-12 00:31:09 +00002029void ARMDAGToDAGISel::SelectVST(SDNode *N, bool isUpdating, unsigned NumVecs,
2030 const uint16_t *DOpcodes,
2031 const uint16_t *QOpcodes0,
2032 const uint16_t *QOpcodes1) {
Bob Wilson3ed511b2010-07-06 23:36:25 +00002033 assert(NumVecs >= 1 && NumVecs <= 4 && "VST NumVecs out-of-range");
Andrew Trickef9de2a2013-05-25 02:42:55 +00002034 SDLoc dl(N);
Bob Wilsonc350cdf2009-10-14 18:32:29 +00002035
Bob Wilsonae08a732010-03-20 22:13:40 +00002036 SDValue MemAddr, Align;
Ivan A. Kosarev72315982018-06-27 13:57:52 +00002037 bool IsIntrinsic = !isUpdating; // By coincidence, all supported updating
2038 // nodes are not intrinsics.
2039 unsigned AddrOpIdx = IsIntrinsic ? 2 : 1;
Bob Wilson06fce872011-02-07 17:43:21 +00002040 unsigned Vec0Idx = 3; // AddrOpIdx + (isUpdating ? 2 : 1)
2041 if (!SelectAddrMode6(N, N->getOperand(AddrOpIdx), MemAddr, Align))
Justin Bogner45571362016-05-12 00:31:09 +00002042 return;
Bob Wilsonc350cdf2009-10-14 18:32:29 +00002043
Chandler Carruth66654b72018-08-14 23:30:32 +00002044 MachineMemOperand *MemOp = cast<MemIntrinsicSDNode>(N)->getMemOperand();
Evan Cheng40791332011-04-19 00:04:03 +00002045
Bob Wilsonc350cdf2009-10-14 18:32:29 +00002046 SDValue Chain = N->getOperand(0);
Bob Wilson06fce872011-02-07 17:43:21 +00002047 EVT VT = N->getOperand(Vec0Idx).getValueType();
Bob Wilsonc350cdf2009-10-14 18:32:29 +00002048 bool is64BitVector = VT.is64BitVector();
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00002049 Align = GetVLDSTAlign(Align, dl, NumVecs, is64BitVector);
Bob Wilson7fbbe9a2010-09-23 23:42:37 +00002050
Bob Wilsonc350cdf2009-10-14 18:32:29 +00002051 unsigned OpcodeIndex;
2052 switch (VT.getSimpleVT().SimpleTy) {
2053 default: llvm_unreachable("unhandled vst type");
2054 // Double-register operations:
2055 case MVT::v8i8: OpcodeIndex = 0; break;
Sjoerd Meijerd16037d2018-03-19 13:35:25 +00002056 case MVT::v4f16:
Bob Wilsonc350cdf2009-10-14 18:32:29 +00002057 case MVT::v4i16: OpcodeIndex = 1; break;
2058 case MVT::v2f32:
2059 case MVT::v2i32: OpcodeIndex = 2; break;
2060 case MVT::v1i64: OpcodeIndex = 3; break;
2061 // Quad-register operations:
2062 case MVT::v16i8: OpcodeIndex = 0; break;
Sjoerd Meijerd16037d2018-03-19 13:35:25 +00002063 case MVT::v8f16:
Bob Wilsonc350cdf2009-10-14 18:32:29 +00002064 case MVT::v8i16: OpcodeIndex = 1; break;
2065 case MVT::v4f32:
2066 case MVT::v4i32: OpcodeIndex = 2; break;
Ahmed Bougachabe0b2272014-12-09 21:25:00 +00002067 case MVT::v2f64:
Ivan A. Kosarev847daa12018-06-10 09:27:27 +00002068 case MVT::v2i64: OpcodeIndex = 3; break;
Bob Wilsonc350cdf2009-10-14 18:32:29 +00002069 }
2070
Bob Wilson06fce872011-02-07 17:43:21 +00002071 std::vector<EVT> ResTys;
2072 if (isUpdating)
2073 ResTys.push_back(MVT::i32);
2074 ResTys.push_back(MVT::Other);
2075
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00002076 SDValue Pred = getAL(CurDAG, dl);
Bob Wilsonae08a732010-03-20 22:13:40 +00002077 SDValue Reg0 = CurDAG->getRegister(0, MVT::i32);
Bob Wilson06fce872011-02-07 17:43:21 +00002078 SmallVector<SDValue, 7> Ops;
Evan Chenga33fc862009-11-21 06:21:52 +00002079
Bob Wilson06fce872011-02-07 17:43:21 +00002080 // Double registers and VST1/VST2 quad registers are directly supported.
2081 if (is64BitVector || NumVecs <= 2) {
Bob Wilsona609b892011-02-07 17:43:15 +00002082 SDValue SrcReg;
Bob Wilson950882b2010-08-28 05:12:57 +00002083 if (NumVecs == 1) {
Bob Wilson06fce872011-02-07 17:43:21 +00002084 SrcReg = N->getOperand(Vec0Idx);
2085 } else if (is64BitVector) {
Evan Chenge276c182010-05-11 01:19:40 +00002086 // Form a REG_SEQUENCE to force register allocation.
Bob Wilson06fce872011-02-07 17:43:21 +00002087 SDValue V0 = N->getOperand(Vec0Idx + 0);
2088 SDValue V1 = N->getOperand(Vec0Idx + 1);
Evan Chenge276c182010-05-11 01:19:40 +00002089 if (NumVecs == 2)
Weiming Zhao95782222012-11-17 00:23:35 +00002090 SrcReg = SDValue(createDRegPairNode(MVT::v2i64, V0, V1), 0);
Evan Chenge276c182010-05-11 01:19:40 +00002091 else {
Bob Wilson06fce872011-02-07 17:43:21 +00002092 SDValue V2 = N->getOperand(Vec0Idx + 2);
Bob Wilsona609b892011-02-07 17:43:15 +00002093 // If it's a vst3, form a quad D-register and leave the last part as
Evan Chenge276c182010-05-11 01:19:40 +00002094 // an undef.
2095 SDValue V3 = (NumVecs == 3)
2096 ? SDValue(CurDAG->getMachineNode(TargetOpcode::IMPLICIT_DEF,dl,VT), 0)
Bob Wilson06fce872011-02-07 17:43:21 +00002097 : N->getOperand(Vec0Idx + 3);
Weiming Zhao95782222012-11-17 00:23:35 +00002098 SrcReg = SDValue(createQuadDRegsNode(MVT::v4i64, V0, V1, V2, V3), 0);
Evan Chenge276c182010-05-11 01:19:40 +00002099 }
Bob Wilson950882b2010-08-28 05:12:57 +00002100 } else {
2101 // Form a QQ register.
Bob Wilson06fce872011-02-07 17:43:21 +00002102 SDValue Q0 = N->getOperand(Vec0Idx);
2103 SDValue Q1 = N->getOperand(Vec0Idx + 1);
Weiming Zhao95782222012-11-17 00:23:35 +00002104 SrcReg = SDValue(createQRegPairNode(MVT::v4i64, Q0, Q1), 0);
Bob Wilsonc350cdf2009-10-14 18:32:29 +00002105 }
Bob Wilson06fce872011-02-07 17:43:21 +00002106
2107 unsigned Opc = (is64BitVector ? DOpcodes[OpcodeIndex] :
2108 QOpcodes0[OpcodeIndex]);
2109 Ops.push_back(MemAddr);
2110 Ops.push_back(Align);
2111 if (isUpdating) {
2112 SDValue Inc = N->getOperand(AddrOpIdx + 1);
Tim Northover8b1240b2017-04-20 19:54:02 +00002113 bool IsImmUpdate = isPerfectIncrement(Inc, VT, NumVecs);
Florian Hahn9deef202018-03-02 13:02:55 +00002114 if (!IsImmUpdate) {
2115 // We use a VST1 for v1i64 even if the pseudo says VST2/3/4, so
2116 // check for the opcode rather than the number of vector elements.
2117 if (isVSTfixed(Opc))
2118 Opc = getVLDSTRegisterUpdateOpcode(Opc);
Jiangning Liu4df23632014-01-16 09:16:13 +00002119 Ops.push_back(Inc);
Florian Hahn9deef202018-03-02 13:02:55 +00002120 }
2121 // VST1/VST2 fixed increment does not need Reg0 so only include it in
2122 // the operands if not such an opcode.
2123 else if (!isVSTfixed(Opc))
Jiangning Liu4df23632014-01-16 09:16:13 +00002124 Ops.push_back(Reg0);
Bob Wilson06fce872011-02-07 17:43:21 +00002125 }
2126 Ops.push_back(SrcReg);
2127 Ops.push_back(Pred);
2128 Ops.push_back(Reg0);
2129 Ops.push_back(Chain);
Michael Liaob53d8962013-04-19 22:22:57 +00002130 SDNode *VSt = CurDAG->getMachineNode(Opc, dl, ResTys, Ops);
Evan Cheng40791332011-04-19 00:04:03 +00002131
2132 // Transfer memoperands.
Chandler Carruth66654b72018-08-14 23:30:32 +00002133 CurDAG->setNodeMemRefs(cast<MachineSDNode>(VSt), {MemOp});
Evan Cheng40791332011-04-19 00:04:03 +00002134
Justin Bogner45571362016-05-12 00:31:09 +00002135 ReplaceNode(N, VSt);
2136 return;
Bob Wilsonc350cdf2009-10-14 18:32:29 +00002137 }
2138
2139 // Otherwise, quad registers are stored with two separate instructions,
2140 // where one stores the even registers and the other stores the odd registers.
Evan Cheng9e688cb2010-05-15 07:53:37 +00002141
Bob Wilson01ac8f92010-06-16 21:34:01 +00002142 // Form the QQQQ REG_SEQUENCE.
Bob Wilson06fce872011-02-07 17:43:21 +00002143 SDValue V0 = N->getOperand(Vec0Idx + 0);
2144 SDValue V1 = N->getOperand(Vec0Idx + 1);
2145 SDValue V2 = N->getOperand(Vec0Idx + 2);
Bob Wilson950882b2010-08-28 05:12:57 +00002146 SDValue V3 = (NumVecs == 3)
2147 ? SDValue(CurDAG->getMachineNode(TargetOpcode::IMPLICIT_DEF, dl, VT), 0)
Bob Wilson06fce872011-02-07 17:43:21 +00002148 : N->getOperand(Vec0Idx + 3);
Weiming Zhao95782222012-11-17 00:23:35 +00002149 SDValue RegSeq = SDValue(createQuadQRegsNode(MVT::v8i64, V0, V1, V2, V3), 0);
Bob Wilson01ac8f92010-06-16 21:34:01 +00002150
Bob Wilson06fce872011-02-07 17:43:21 +00002151 // Store the even D registers. This is always an updating store, so that it
2152 // provides the address to the second store for the odd subregs.
Bob Wilsona609b892011-02-07 17:43:15 +00002153 const SDValue OpsA[] = { MemAddr, Align, Reg0, RegSeq, Pred, Reg0, Chain };
2154 SDNode *VStA = CurDAG->getMachineNode(QOpcodes0[OpcodeIndex], dl,
2155 MemAddr.getValueType(),
Michael Liaob53d8962013-04-19 22:22:57 +00002156 MVT::Other, OpsA);
Chandler Carruth66654b72018-08-14 23:30:32 +00002157 CurDAG->setNodeMemRefs(cast<MachineSDNode>(VStA), {MemOp});
Bob Wilson01ac8f92010-06-16 21:34:01 +00002158 Chain = SDValue(VStA, 1);
2159
2160 // Store the odd D registers.
Bob Wilson06fce872011-02-07 17:43:21 +00002161 Ops.push_back(SDValue(VStA, 0));
2162 Ops.push_back(Align);
2163 if (isUpdating) {
2164 SDValue Inc = N->getOperand(AddrOpIdx + 1);
2165 assert(isa<ConstantSDNode>(Inc.getNode()) &&
2166 "only constant post-increment update allowed for VST3/4");
2167 (void)Inc;
2168 Ops.push_back(Reg0);
2169 }
2170 Ops.push_back(RegSeq);
2171 Ops.push_back(Pred);
2172 Ops.push_back(Reg0);
2173 Ops.push_back(Chain);
Evan Cheng40791332011-04-19 00:04:03 +00002174 SDNode *VStB = CurDAG->getMachineNode(QOpcodes1[OpcodeIndex], dl, ResTys,
Michael Liaob53d8962013-04-19 22:22:57 +00002175 Ops);
Chandler Carruth66654b72018-08-14 23:30:32 +00002176 CurDAG->setNodeMemRefs(cast<MachineSDNode>(VStB), {MemOp});
Justin Bogner45571362016-05-12 00:31:09 +00002177 ReplaceNode(N, VStB);
Bob Wilsonc350cdf2009-10-14 18:32:29 +00002178}
2179
Justin Bogner45571362016-05-12 00:31:09 +00002180void ARMDAGToDAGISel::SelectVLDSTLane(SDNode *N, bool IsLoad, bool isUpdating,
2181 unsigned NumVecs,
2182 const uint16_t *DOpcodes,
2183 const uint16_t *QOpcodes) {
Bob Wilson93117bc2009-10-14 16:46:45 +00002184 assert(NumVecs >=2 && NumVecs <= 4 && "VLDSTLane NumVecs out-of-range");
Andrew Trickef9de2a2013-05-25 02:42:55 +00002185 SDLoc dl(N);
Bob Wilson4145e3a2009-10-14 16:19:03 +00002186
Bob Wilsonae08a732010-03-20 22:13:40 +00002187 SDValue MemAddr, Align;
Ivan A. Kosarev72315982018-06-27 13:57:52 +00002188 bool IsIntrinsic = !isUpdating; // By coincidence, all supported updating
2189 // nodes are not intrinsics.
2190 unsigned AddrOpIdx = IsIntrinsic ? 2 : 1;
Bob Wilson06fce872011-02-07 17:43:21 +00002191 unsigned Vec0Idx = 3; // AddrOpIdx + (isUpdating ? 2 : 1)
2192 if (!SelectAddrMode6(N, N->getOperand(AddrOpIdx), MemAddr, Align))
Justin Bogner45571362016-05-12 00:31:09 +00002193 return;
Bob Wilson4145e3a2009-10-14 16:19:03 +00002194
Chandler Carruth66654b72018-08-14 23:30:32 +00002195 MachineMemOperand *MemOp = cast<MemIntrinsicSDNode>(N)->getMemOperand();
Evan Cheng40791332011-04-19 00:04:03 +00002196
Bob Wilson4145e3a2009-10-14 16:19:03 +00002197 SDValue Chain = N->getOperand(0);
2198 unsigned Lane =
Bob Wilson06fce872011-02-07 17:43:21 +00002199 cast<ConstantSDNode>(N->getOperand(Vec0Idx + NumVecs))->getZExtValue();
2200 EVT VT = N->getOperand(Vec0Idx).getValueType();
Bob Wilson4145e3a2009-10-14 16:19:03 +00002201 bool is64BitVector = VT.is64BitVector();
2202
Bob Wilsondd9fbaa2010-11-01 23:40:51 +00002203 unsigned Alignment = 0;
Bob Wilsonb6d61dc2010-10-19 00:16:32 +00002204 if (NumVecs != 3) {
Bob Wilsondd9fbaa2010-11-01 23:40:51 +00002205 Alignment = cast<ConstantSDNode>(Align)->getZExtValue();
Sanjay Patel1ed771f2016-09-14 16:37:15 +00002206 unsigned NumBytes = NumVecs * VT.getScalarSizeInBits() / 8;
Bob Wilsonb6d61dc2010-10-19 00:16:32 +00002207 if (Alignment > NumBytes)
2208 Alignment = NumBytes;
Bob Wilsond29b38c2010-12-10 19:37:42 +00002209 if (Alignment < 8 && Alignment < NumBytes)
2210 Alignment = 0;
Bob Wilsonb6d61dc2010-10-19 00:16:32 +00002211 // Alignment must be a power of two; make sure of that.
2212 Alignment = (Alignment & -Alignment);
Bob Wilsondd9fbaa2010-11-01 23:40:51 +00002213 if (Alignment == 1)
2214 Alignment = 0;
Bob Wilsonb6d61dc2010-10-19 00:16:32 +00002215 }
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00002216 Align = CurDAG->getTargetConstant(Alignment, dl, MVT::i32);
Bob Wilsonb6d61dc2010-10-19 00:16:32 +00002217
Bob Wilson4145e3a2009-10-14 16:19:03 +00002218 unsigned OpcodeIndex;
2219 switch (VT.getSimpleVT().SimpleTy) {
Bob Wilson93117bc2009-10-14 16:46:45 +00002220 default: llvm_unreachable("unhandled vld/vst lane type");
Bob Wilson4145e3a2009-10-14 16:19:03 +00002221 // Double-register operations:
2222 case MVT::v8i8: OpcodeIndex = 0; break;
Diogo N. Sampaio2619f392019-04-23 09:36:39 +00002223 case MVT::v4f16:
Bob Wilson4145e3a2009-10-14 16:19:03 +00002224 case MVT::v4i16: OpcodeIndex = 1; break;
2225 case MVT::v2f32:
2226 case MVT::v2i32: OpcodeIndex = 2; break;
2227 // Quad-register operations:
Diogo N. Sampaio2619f392019-04-23 09:36:39 +00002228 case MVT::v8f16:
Bob Wilson4145e3a2009-10-14 16:19:03 +00002229 case MVT::v8i16: OpcodeIndex = 0; break;
2230 case MVT::v4f32:
2231 case MVT::v4i32: OpcodeIndex = 1; break;
2232 }
2233
Bob Wilson06fce872011-02-07 17:43:21 +00002234 std::vector<EVT> ResTys;
2235 if (IsLoad) {
2236 unsigned ResTyElts = (NumVecs == 3) ? 4 : NumVecs;
2237 if (!is64BitVector)
2238 ResTyElts *= 2;
2239 ResTys.push_back(EVT::getVectorVT(*CurDAG->getContext(),
2240 MVT::i64, ResTyElts));
2241 }
2242 if (isUpdating)
2243 ResTys.push_back(MVT::i32);
2244 ResTys.push_back(MVT::Other);
2245
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00002246 SDValue Pred = getAL(CurDAG, dl);
Bob Wilsonae08a732010-03-20 22:13:40 +00002247 SDValue Reg0 = CurDAG->getRegister(0, MVT::i32);
Evan Chenga33fc862009-11-21 06:21:52 +00002248
Bob Wilson06fce872011-02-07 17:43:21 +00002249 SmallVector<SDValue, 8> Ops;
Bob Wilson4145e3a2009-10-14 16:19:03 +00002250 Ops.push_back(MemAddr);
Jim Grosbachd1d002a2009-11-07 21:25:39 +00002251 Ops.push_back(Align);
Bob Wilson06fce872011-02-07 17:43:21 +00002252 if (isUpdating) {
2253 SDValue Inc = N->getOperand(AddrOpIdx + 1);
Tim Northover8b1240b2017-04-20 19:54:02 +00002254 bool IsImmUpdate =
2255 isPerfectIncrement(Inc, VT.getVectorElementType(), NumVecs);
2256 Ops.push_back(IsImmUpdate ? Reg0 : Inc);
Bob Wilson06fce872011-02-07 17:43:21 +00002257 }
Bob Wilson01ac8f92010-06-16 21:34:01 +00002258
Bob Wilsond5c57a52010-09-13 23:01:35 +00002259 SDValue SuperReg;
Bob Wilson06fce872011-02-07 17:43:21 +00002260 SDValue V0 = N->getOperand(Vec0Idx + 0);
2261 SDValue V1 = N->getOperand(Vec0Idx + 1);
Bob Wilsond5c57a52010-09-13 23:01:35 +00002262 if (NumVecs == 2) {
2263 if (is64BitVector)
Weiming Zhao95782222012-11-17 00:23:35 +00002264 SuperReg = SDValue(createDRegPairNode(MVT::v2i64, V0, V1), 0);
Bob Wilsond5c57a52010-09-13 23:01:35 +00002265 else
Weiming Zhao95782222012-11-17 00:23:35 +00002266 SuperReg = SDValue(createQRegPairNode(MVT::v4i64, V0, V1), 0);
Bob Wilson4145e3a2009-10-14 16:19:03 +00002267 } else {
Bob Wilson06fce872011-02-07 17:43:21 +00002268 SDValue V2 = N->getOperand(Vec0Idx + 2);
Bob Wilsond5c57a52010-09-13 23:01:35 +00002269 SDValue V3 = (NumVecs == 3)
Bob Wilson06fce872011-02-07 17:43:21 +00002270 ? SDValue(CurDAG->getMachineNode(TargetOpcode::IMPLICIT_DEF, dl, VT), 0)
2271 : N->getOperand(Vec0Idx + 3);
Bob Wilsond5c57a52010-09-13 23:01:35 +00002272 if (is64BitVector)
Weiming Zhao95782222012-11-17 00:23:35 +00002273 SuperReg = SDValue(createQuadDRegsNode(MVT::v4i64, V0, V1, V2, V3), 0);
Bob Wilsond5c57a52010-09-13 23:01:35 +00002274 else
Weiming Zhao95782222012-11-17 00:23:35 +00002275 SuperReg = SDValue(createQuadQRegsNode(MVT::v8i64, V0, V1, V2, V3), 0);
Bob Wilson4145e3a2009-10-14 16:19:03 +00002276 }
Bob Wilsond5c57a52010-09-13 23:01:35 +00002277 Ops.push_back(SuperReg);
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00002278 Ops.push_back(getI32Imm(Lane, dl));
Evan Chenga33fc862009-11-21 06:21:52 +00002279 Ops.push_back(Pred);
Bob Wilsonae08a732010-03-20 22:13:40 +00002280 Ops.push_back(Reg0);
Bob Wilson4145e3a2009-10-14 16:19:03 +00002281 Ops.push_back(Chain);
2282
Bob Wilson06fce872011-02-07 17:43:21 +00002283 unsigned Opc = (is64BitVector ? DOpcodes[OpcodeIndex] :
2284 QOpcodes[OpcodeIndex]);
Michael Liaob53d8962013-04-19 22:22:57 +00002285 SDNode *VLdLn = CurDAG->getMachineNode(Opc, dl, ResTys, Ops);
Chandler Carruth66654b72018-08-14 23:30:32 +00002286 CurDAG->setNodeMemRefs(cast<MachineSDNode>(VLdLn), {MemOp});
Justin Bogner45571362016-05-12 00:31:09 +00002287 if (!IsLoad) {
2288 ReplaceNode(N, VLdLn);
2289 return;
2290 }
Evan Cheng0cbd11d2010-05-15 01:36:29 +00002291
Bob Wilsond5c57a52010-09-13 23:01:35 +00002292 // Extract the subregisters.
Bob Wilson06fce872011-02-07 17:43:21 +00002293 SuperReg = SDValue(VLdLn, 0);
Benjamin Kramer3e9a5d32016-05-27 11:36:04 +00002294 static_assert(ARM::dsub_7 == ARM::dsub_0 + 7 &&
2295 ARM::qsub_3 == ARM::qsub_0 + 3,
2296 "Unexpected subreg numbering");
Bob Wilson06fce872011-02-07 17:43:21 +00002297 unsigned Sub0 = is64BitVector ? ARM::dsub_0 : ARM::qsub_0;
Bob Wilson01ac8f92010-06-16 21:34:01 +00002298 for (unsigned Vec = 0; Vec < NumVecs; ++Vec)
2299 ReplaceUses(SDValue(N, Vec),
Bob Wilson06fce872011-02-07 17:43:21 +00002300 CurDAG->getTargetExtractSubreg(Sub0 + Vec, dl, VT, SuperReg));
2301 ReplaceUses(SDValue(N, NumVecs), SDValue(VLdLn, 1));
2302 if (isUpdating)
2303 ReplaceUses(SDValue(N, NumVecs + 1), SDValue(VLdLn, 2));
Justin Bognered4f3782016-05-12 00:20:19 +00002304 CurDAG->RemoveDeadNode(N);
Bob Wilson4145e3a2009-10-14 16:19:03 +00002305}
2306
Ivan A. Kosarev72315982018-06-27 13:57:52 +00002307void ARMDAGToDAGISel::SelectVLDDup(SDNode *N, bool IsIntrinsic,
2308 bool isUpdating, unsigned NumVecs,
Eli Friedmanf624ec22016-12-16 18:44:08 +00002309 const uint16_t *DOpcodes,
Ivan A. Kosarev72315982018-06-27 13:57:52 +00002310 const uint16_t *QOpcodes0,
2311 const uint16_t *QOpcodes1) {
Eli Friedmanf624ec22016-12-16 18:44:08 +00002312 assert(NumVecs >= 1 && NumVecs <= 4 && "VLDDup NumVecs out-of-range");
Andrew Trickef9de2a2013-05-25 02:42:55 +00002313 SDLoc dl(N);
Bob Wilson2d790df2010-11-28 06:51:26 +00002314
2315 SDValue MemAddr, Align;
Ivan A. Kosarev72315982018-06-27 13:57:52 +00002316 unsigned AddrOpIdx = IsIntrinsic ? 2 : 1;
2317 if (!SelectAddrMode6(N, N->getOperand(AddrOpIdx), MemAddr, Align))
Justin Bogner45571362016-05-12 00:31:09 +00002318 return;
Bob Wilson2d790df2010-11-28 06:51:26 +00002319
2320 SDValue Chain = N->getOperand(0);
2321 EVT VT = N->getValueType(0);
Ivan A. Kosarev72315982018-06-27 13:57:52 +00002322 bool is64BitVector = VT.is64BitVector();
Bob Wilson2d790df2010-11-28 06:51:26 +00002323
2324 unsigned Alignment = 0;
2325 if (NumVecs != 3) {
2326 Alignment = cast<ConstantSDNode>(Align)->getZExtValue();
Sanjay Patel1ed771f2016-09-14 16:37:15 +00002327 unsigned NumBytes = NumVecs * VT.getScalarSizeInBits() / 8;
Bob Wilson2d790df2010-11-28 06:51:26 +00002328 if (Alignment > NumBytes)
2329 Alignment = NumBytes;
Bob Wilsond29b38c2010-12-10 19:37:42 +00002330 if (Alignment < 8 && Alignment < NumBytes)
2331 Alignment = 0;
Bob Wilson2d790df2010-11-28 06:51:26 +00002332 // Alignment must be a power of two; make sure of that.
2333 Alignment = (Alignment & -Alignment);
2334 if (Alignment == 1)
2335 Alignment = 0;
2336 }
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00002337 Align = CurDAG->getTargetConstant(Alignment, dl, MVT::i32);
Bob Wilson2d790df2010-11-28 06:51:26 +00002338
Ivan A. Kosarev72315982018-06-27 13:57:52 +00002339 unsigned OpcodeIndex;
Bob Wilson2d790df2010-11-28 06:51:26 +00002340 switch (VT.getSimpleVT().SimpleTy) {
2341 default: llvm_unreachable("unhandled vld-dup type");
Ivan A. Kosarev72315982018-06-27 13:57:52 +00002342 case MVT::v8i8:
2343 case MVT::v16i8: OpcodeIndex = 0; break;
2344 case MVT::v4i16:
Diogo N. Sampaio651463e2019-04-10 13:28:06 +00002345 case MVT::v8i16:
2346 case MVT::v4f16:
2347 case MVT::v8f16:
2348 OpcodeIndex = 1; break;
Bob Wilson2d790df2010-11-28 06:51:26 +00002349 case MVT::v2f32:
Ivan A. Kosarev72315982018-06-27 13:57:52 +00002350 case MVT::v2i32:
Eli Friedmanf624ec22016-12-16 18:44:08 +00002351 case MVT::v4f32:
Ivan A. Kosarev72315982018-06-27 13:57:52 +00002352 case MVT::v4i32: OpcodeIndex = 2; break;
2353 case MVT::v1f64:
2354 case MVT::v1i64: OpcodeIndex = 3; break;
Bob Wilson2d790df2010-11-28 06:51:26 +00002355 }
2356
Bob Wilson2d790df2010-11-28 06:51:26 +00002357 unsigned ResTyElts = (NumVecs == 3) ? 4 : NumVecs;
Ivan A. Kosarev72315982018-06-27 13:57:52 +00002358 if (!is64BitVector)
2359 ResTyElts *= 2;
2360 EVT ResTy = EVT::getVectorVT(*CurDAG->getContext(), MVT::i64, ResTyElts);
2361
Bob Wilson06fce872011-02-07 17:43:21 +00002362 std::vector<EVT> ResTys;
Ivan A. Kosarev72315982018-06-27 13:57:52 +00002363 ResTys.push_back(ResTy);
Bob Wilson06fce872011-02-07 17:43:21 +00002364 if (isUpdating)
2365 ResTys.push_back(MVT::i32);
2366 ResTys.push_back(MVT::Other);
Ivan A. Kosarev72315982018-06-27 13:57:52 +00002367
2368 SDValue Pred = getAL(CurDAG, dl);
2369 SDValue Reg0 = CurDAG->getRegister(0, MVT::i32);
2370
2371 SDNode *VLdDup;
2372 if (is64BitVector || NumVecs == 1) {
2373 SmallVector<SDValue, 6> Ops;
2374 Ops.push_back(MemAddr);
2375 Ops.push_back(Align);
2376 unsigned Opc = is64BitVector ? DOpcodes[OpcodeIndex] :
2377 QOpcodes0[OpcodeIndex];
2378 if (isUpdating) {
2379 // fixed-stride update instructions don't have an explicit writeback
2380 // operand. It's implicit in the opcode itself.
2381 SDValue Inc = N->getOperand(2);
2382 bool IsImmUpdate =
2383 isPerfectIncrement(Inc, VT.getVectorElementType(), NumVecs);
2384 if (NumVecs <= 2 && !IsImmUpdate)
2385 Opc = getVLDSTRegisterUpdateOpcode(Opc);
2386 if (!IsImmUpdate)
2387 Ops.push_back(Inc);
2388 // FIXME: VLD3 and VLD4 haven't been updated to that form yet.
2389 else if (NumVecs > 2)
2390 Ops.push_back(Reg0);
2391 }
2392 Ops.push_back(Pred);
2393 Ops.push_back(Reg0);
2394 Ops.push_back(Chain);
2395 VLdDup = CurDAG->getMachineNode(Opc, dl, ResTys, Ops);
2396 } else if (NumVecs == 2) {
2397 const SDValue OpsA[] = { MemAddr, Align, Pred, Reg0, Chain };
2398 SDNode *VLdA = CurDAG->getMachineNode(QOpcodes0[OpcodeIndex],
2399 dl, ResTys, OpsA);
2400
2401 Chain = SDValue(VLdA, 1);
2402 const SDValue OpsB[] = { MemAddr, Align, Pred, Reg0, Chain };
2403 VLdDup = CurDAG->getMachineNode(QOpcodes1[OpcodeIndex], dl, ResTys, OpsB);
2404 } else {
2405 SDValue ImplDef =
2406 SDValue(CurDAG->getMachineNode(TargetOpcode::IMPLICIT_DEF, dl, ResTy), 0);
2407 const SDValue OpsA[] = { MemAddr, Align, ImplDef, Pred, Reg0, Chain };
2408 SDNode *VLdA = CurDAG->getMachineNode(QOpcodes0[OpcodeIndex],
2409 dl, ResTys, OpsA);
2410
2411 SDValue SuperReg = SDValue(VLdA, 0);
2412 Chain = SDValue(VLdA, 1);
2413 const SDValue OpsB[] = { MemAddr, Align, SuperReg, Pred, Reg0, Chain };
2414 VLdDup = CurDAG->getMachineNode(QOpcodes1[OpcodeIndex], dl, ResTys, OpsB);
2415 }
2416
2417 // Transfer memoperands.
Chandler Carruth66654b72018-08-14 23:30:32 +00002418 MachineMemOperand *MemOp = cast<MemIntrinsicSDNode>(N)->getMemOperand();
2419 CurDAG->setNodeMemRefs(cast<MachineSDNode>(VLdDup), {MemOp});
Bob Wilson2d790df2010-11-28 06:51:26 +00002420
2421 // Extract the subregisters.
Eli Friedmanf624ec22016-12-16 18:44:08 +00002422 if (NumVecs == 1) {
2423 ReplaceUses(SDValue(N, 0), SDValue(VLdDup, 0));
2424 } else {
2425 SDValue SuperReg = SDValue(VLdDup, 0);
2426 static_assert(ARM::dsub_7 == ARM::dsub_0 + 7, "Unexpected subreg numbering");
Ivan A. Kosarev72315982018-06-27 13:57:52 +00002427 unsigned SubIdx = is64BitVector ? ARM::dsub_0 : ARM::qsub_0;
2428 for (unsigned Vec = 0; Vec != NumVecs; ++Vec) {
Eli Friedmanf624ec22016-12-16 18:44:08 +00002429 ReplaceUses(SDValue(N, Vec),
2430 CurDAG->getTargetExtractSubreg(SubIdx+Vec, dl, VT, SuperReg));
Ivan A. Kosarev72315982018-06-27 13:57:52 +00002431 }
Eli Friedmanf624ec22016-12-16 18:44:08 +00002432 }
Bob Wilson06fce872011-02-07 17:43:21 +00002433 ReplaceUses(SDValue(N, NumVecs), SDValue(VLdDup, 1));
2434 if (isUpdating)
2435 ReplaceUses(SDValue(N, NumVecs + 1), SDValue(VLdDup, 2));
Justin Bognered4f3782016-05-12 00:20:19 +00002436 CurDAG->RemoveDeadNode(N);
Bob Wilson2d790df2010-11-28 06:51:26 +00002437}
2438
Justin Bogner45571362016-05-12 00:31:09 +00002439bool ARMDAGToDAGISel::tryV6T2BitfieldExtractOp(SDNode *N, bool isSigned) {
Sandeep Patel423e42b2009-10-13 18:59:48 +00002440 if (!Subtarget->hasV6T2Ops())
Justin Bogner45571362016-05-12 00:31:09 +00002441 return false;
Bob Wilson93117bc2009-10-14 16:46:45 +00002442
Evan Chengeae6d2c2012-12-19 20:16:09 +00002443 unsigned Opc = isSigned
2444 ? (Subtarget->isThumb() ? ARM::t2SBFX : ARM::SBFX)
Jim Grosbach825cb292010-04-22 23:24:18 +00002445 : (Subtarget->isThumb() ? ARM::t2UBFX : ARM::UBFX);
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00002446 SDLoc dl(N);
Jim Grosbach825cb292010-04-22 23:24:18 +00002447
Jim Grosbach825cb292010-04-22 23:24:18 +00002448 // For unsigned extracts, check for a shift right and mask
2449 unsigned And_imm = 0;
2450 if (N->getOpcode() == ISD::AND) {
2451 if (isOpcWithIntImmediate(N, ISD::AND, And_imm)) {
2452
Sylvestre Ledru91ce36c2012-09-27 10:14:43 +00002453 // The immediate is a mask of the low bits iff imm & (imm+1) == 0
Jim Grosbach825cb292010-04-22 23:24:18 +00002454 if (And_imm & (And_imm + 1))
Justin Bogner45571362016-05-12 00:31:09 +00002455 return false;
Jim Grosbach825cb292010-04-22 23:24:18 +00002456
2457 unsigned Srl_imm = 0;
2458 if (isOpcWithIntImmediate(N->getOperand(0).getNode(), ISD::SRL,
2459 Srl_imm)) {
2460 assert(Srl_imm > 0 && Srl_imm < 32 && "bad amount in shift node!");
2461
Eli Friedmane1687a892018-08-10 21:21:53 +00002462 // Mask off the unnecessary bits of the AND immediate; normally
2463 // DAGCombine will do this, but that might not happen if
2464 // targetShrinkDemandedConstant chooses a different immediate.
2465 And_imm &= -1U >> Srl_imm;
2466
Jim Grosbach03f56d92011-07-27 21:09:25 +00002467 // Note: The width operand is encoded as width-1.
Benjamin Kramer5f6a9072015-02-12 15:35:40 +00002468 unsigned Width = countTrailingOnes(And_imm) - 1;
Jim Grosbach825cb292010-04-22 23:24:18 +00002469 unsigned LSB = Srl_imm;
Evan Chengeae6d2c2012-12-19 20:16:09 +00002470
Jim Grosbach825cb292010-04-22 23:24:18 +00002471 SDValue Reg0 = CurDAG->getRegister(0, MVT::i32);
Evan Chengeae6d2c2012-12-19 20:16:09 +00002472
2473 if ((LSB + Width + 1) == N->getValueType(0).getSizeInBits()) {
2474 // It's cheaper to use a right shift to extract the top bits.
2475 if (Subtarget->isThumb()) {
2476 Opc = isSigned ? ARM::t2ASRri : ARM::t2LSRri;
2477 SDValue Ops[] = { N->getOperand(0).getOperand(0),
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00002478 CurDAG->getTargetConstant(LSB, dl, MVT::i32),
2479 getAL(CurDAG, dl), Reg0, Reg0 };
Justin Bogner45571362016-05-12 00:31:09 +00002480 CurDAG->SelectNodeTo(N, Opc, MVT::i32, Ops);
2481 return true;
Evan Chengeae6d2c2012-12-19 20:16:09 +00002482 }
2483
2484 // ARM models shift instructions as MOVsi with shifter operand.
2485 ARM_AM::ShiftOpc ShOpcVal = ARM_AM::getShiftOpcForNode(ISD::SRL);
2486 SDValue ShOpc =
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00002487 CurDAG->getTargetConstant(ARM_AM::getSORegOpc(ShOpcVal, LSB), dl,
Evan Chengeae6d2c2012-12-19 20:16:09 +00002488 MVT::i32);
2489 SDValue Ops[] = { N->getOperand(0).getOperand(0), ShOpc,
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00002490 getAL(CurDAG, dl), Reg0, Reg0 };
Justin Bogner45571362016-05-12 00:31:09 +00002491 CurDAG->SelectNodeTo(N, ARM::MOVsi, MVT::i32, Ops);
2492 return true;
Evan Chengeae6d2c2012-12-19 20:16:09 +00002493 }
2494
Eli Friedman65d885e2018-06-28 21:49:41 +00002495 assert(LSB + Width + 1 <= 32 && "Shouldn't create an invalid ubfx");
Jim Grosbach825cb292010-04-22 23:24:18 +00002496 SDValue Ops[] = { N->getOperand(0).getOperand(0),
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00002497 CurDAG->getTargetConstant(LSB, dl, MVT::i32),
2498 CurDAG->getTargetConstant(Width, dl, MVT::i32),
2499 getAL(CurDAG, dl), Reg0 };
Justin Bogner45571362016-05-12 00:31:09 +00002500 CurDAG->SelectNodeTo(N, Opc, MVT::i32, Ops);
2501 return true;
Jim Grosbach825cb292010-04-22 23:24:18 +00002502 }
2503 }
Justin Bogner45571362016-05-12 00:31:09 +00002504 return false;
Jim Grosbach825cb292010-04-22 23:24:18 +00002505 }
2506
2507 // Otherwise, we're looking for a shift of a shift
Sandeep Patel423e42b2009-10-13 18:59:48 +00002508 unsigned Shl_imm = 0;
Dan Gohmanea6f91f2010-01-05 01:24:18 +00002509 if (isOpcWithIntImmediate(N->getOperand(0).getNode(), ISD::SHL, Shl_imm)) {
Sandeep Patel423e42b2009-10-13 18:59:48 +00002510 assert(Shl_imm > 0 && Shl_imm < 32 && "bad amount in shift node!");
2511 unsigned Srl_imm = 0;
Dan Gohmanea6f91f2010-01-05 01:24:18 +00002512 if (isInt32Immediate(N->getOperand(1), Srl_imm)) {
Sandeep Patel423e42b2009-10-13 18:59:48 +00002513 assert(Srl_imm > 0 && Srl_imm < 32 && "bad amount in shift node!");
Jim Grosbach03f56d92011-07-27 21:09:25 +00002514 // Note: The width operand is encoded as width-1.
2515 unsigned Width = 32 - Srl_imm - 1;
Sandeep Patel423e42b2009-10-13 18:59:48 +00002516 int LSB = Srl_imm - Shl_imm;
Evan Cheng0f55e9c2009-10-22 00:40:00 +00002517 if (LSB < 0)
Justin Bogner45571362016-05-12 00:31:09 +00002518 return false;
Sandeep Patel423e42b2009-10-13 18:59:48 +00002519 SDValue Reg0 = CurDAG->getRegister(0, MVT::i32);
Eli Friedman65d885e2018-06-28 21:49:41 +00002520 assert(LSB + Width + 1 <= 32 && "Shouldn't create an invalid ubfx");
Dan Gohmanea6f91f2010-01-05 01:24:18 +00002521 SDValue Ops[] = { N->getOperand(0).getOperand(0),
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00002522 CurDAG->getTargetConstant(LSB, dl, MVT::i32),
2523 CurDAG->getTargetConstant(Width, dl, MVT::i32),
2524 getAL(CurDAG, dl), Reg0 };
Justin Bogner45571362016-05-12 00:31:09 +00002525 CurDAG->SelectNodeTo(N, Opc, MVT::i32, Ops);
2526 return true;
Sandeep Patel423e42b2009-10-13 18:59:48 +00002527 }
2528 }
Tim Northover14ff2df2014-07-23 13:59:12 +00002529
Oliver Stannard92ca83c2016-06-01 12:01:01 +00002530 // Or we are looking for a shift of an and, with a mask operand
2531 if (isOpcWithIntImmediate(N->getOperand(0).getNode(), ISD::AND, And_imm) &&
2532 isShiftedMask_32(And_imm)) {
2533 unsigned Srl_imm = 0;
2534 unsigned LSB = countTrailingZeros(And_imm);
2535 // Shift must be the same as the ands lsb
2536 if (isInt32Immediate(N->getOperand(1), Srl_imm) && Srl_imm == LSB) {
2537 assert(Srl_imm > 0 && Srl_imm < 32 && "bad amount in shift node!");
2538 unsigned MSB = 31 - countLeadingZeros(And_imm);
2539 // Note: The width operand is encoded as width-1.
2540 unsigned Width = MSB - LSB;
2541 SDValue Reg0 = CurDAG->getRegister(0, MVT::i32);
Eli Friedman65d885e2018-06-28 21:49:41 +00002542 assert(Srl_imm + Width + 1 <= 32 && "Shouldn't create an invalid ubfx");
Oliver Stannard92ca83c2016-06-01 12:01:01 +00002543 SDValue Ops[] = { N->getOperand(0).getOperand(0),
2544 CurDAG->getTargetConstant(Srl_imm, dl, MVT::i32),
2545 CurDAG->getTargetConstant(Width, dl, MVT::i32),
2546 getAL(CurDAG, dl), Reg0 };
2547 CurDAG->SelectNodeTo(N, Opc, MVT::i32, Ops);
2548 return true;
2549 }
2550 }
2551
Tim Northover14ff2df2014-07-23 13:59:12 +00002552 if (N->getOpcode() == ISD::SIGN_EXTEND_INREG) {
2553 unsigned Width = cast<VTSDNode>(N->getOperand(1))->getVT().getSizeInBits();
2554 unsigned LSB = 0;
2555 if (!isOpcWithIntImmediate(N->getOperand(0).getNode(), ISD::SRL, LSB) &&
2556 !isOpcWithIntImmediate(N->getOperand(0).getNode(), ISD::SRA, LSB))
Justin Bogner45571362016-05-12 00:31:09 +00002557 return false;
Tim Northover14ff2df2014-07-23 13:59:12 +00002558
2559 if (LSB + Width > 32)
Justin Bogner45571362016-05-12 00:31:09 +00002560 return false;
Tim Northover14ff2df2014-07-23 13:59:12 +00002561
2562 SDValue Reg0 = CurDAG->getRegister(0, MVT::i32);
Eli Friedman65d885e2018-06-28 21:49:41 +00002563 assert(LSB + Width <= 32 && "Shouldn't create an invalid ubfx");
Tim Northover14ff2df2014-07-23 13:59:12 +00002564 SDValue Ops[] = { N->getOperand(0).getOperand(0),
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00002565 CurDAG->getTargetConstant(LSB, dl, MVT::i32),
2566 CurDAG->getTargetConstant(Width - 1, dl, MVT::i32),
2567 getAL(CurDAG, dl), Reg0 };
Justin Bogner45571362016-05-12 00:31:09 +00002568 CurDAG->SelectNodeTo(N, Opc, MVT::i32, Ops);
2569 return true;
Tim Northover14ff2df2014-07-23 13:59:12 +00002570 }
2571
Justin Bogner45571362016-05-12 00:31:09 +00002572 return false;
Sandeep Patel423e42b2009-10-13 18:59:48 +00002573}
2574
Bill Wendlinga7d697e2011-10-10 22:59:55 +00002575/// Target-specific DAG combining for ISD::XOR.
2576/// Target-independent combining lowers SELECT_CC nodes of the form
2577/// select_cc setg[ge] X, 0, X, -X
2578/// select_cc setgt X, -1, X, -X
2579/// select_cc setl[te] X, 0, -X, X
2580/// select_cc setlt X, 1, -X, X
2581/// which represent Integer ABS into:
2582/// Y = sra (X, size(X)-1); xor (add (X, Y), Y)
2583/// ARM instruction selection detects the latter and matches it to
2584/// ARM::ABS or ARM::t2ABS machine node.
Justin Bogner45571362016-05-12 00:31:09 +00002585bool ARMDAGToDAGISel::tryABSOp(SDNode *N){
Bill Wendlinga7d697e2011-10-10 22:59:55 +00002586 SDValue XORSrc0 = N->getOperand(0);
2587 SDValue XORSrc1 = N->getOperand(1);
Bill Wendlinga7d697e2011-10-10 22:59:55 +00002588 EVT VT = N->getValueType(0);
2589
Bill Wendlinga7d697e2011-10-10 22:59:55 +00002590 if (Subtarget->isThumb1Only())
Justin Bogner45571362016-05-12 00:31:09 +00002591 return false;
Bill Wendlinga7d697e2011-10-10 22:59:55 +00002592
Jim Grosbachb437a8c2012-08-01 20:33:00 +00002593 if (XORSrc0.getOpcode() != ISD::ADD || XORSrc1.getOpcode() != ISD::SRA)
Justin Bogner45571362016-05-12 00:31:09 +00002594 return false;
Bill Wendlinga7d697e2011-10-10 22:59:55 +00002595
2596 SDValue ADDSrc0 = XORSrc0.getOperand(0);
2597 SDValue ADDSrc1 = XORSrc0.getOperand(1);
2598 SDValue SRASrc0 = XORSrc1.getOperand(0);
2599 SDValue SRASrc1 = XORSrc1.getOperand(1);
2600 ConstantSDNode *SRAConstant = dyn_cast<ConstantSDNode>(SRASrc1);
2601 EVT XType = SRASrc0.getValueType();
2602 unsigned Size = XType.getSizeInBits() - 1;
2603
Jim Grosbachb437a8c2012-08-01 20:33:00 +00002604 if (ADDSrc1 == XORSrc1 && ADDSrc0 == SRASrc0 &&
Craig Topper062a2ba2014-04-25 05:30:21 +00002605 XType.isInteger() && SRAConstant != nullptr &&
Bill Wendlinga7d697e2011-10-10 22:59:55 +00002606 Size == SRAConstant->getZExtValue()) {
Jim Grosbachb437a8c2012-08-01 20:33:00 +00002607 unsigned Opcode = Subtarget->isThumb2() ? ARM::t2ABS : ARM::ABS;
Justin Bogner45571362016-05-12 00:31:09 +00002608 CurDAG->SelectNodeTo(N, Opcode, VT, ADDSrc0);
2609 return true;
Bill Wendlinga7d697e2011-10-10 22:59:55 +00002610 }
2611
Justin Bogner45571362016-05-12 00:31:09 +00002612 return false;
Bill Wendlinga7d697e2011-10-10 22:59:55 +00002613}
2614
Tim Northoverb629c772016-04-18 21:48:55 +00002615/// We've got special pseudo-instructions for these
Justin Bogner45571362016-05-12 00:31:09 +00002616void ARMDAGToDAGISel::SelectCMP_SWAP(SDNode *N) {
Tim Northoverb629c772016-04-18 21:48:55 +00002617 unsigned Opcode;
2618 EVT MemTy = cast<MemSDNode>(N)->getMemoryVT();
2619 if (MemTy == MVT::i8)
2620 Opcode = ARM::CMP_SWAP_8;
2621 else if (MemTy == MVT::i16)
2622 Opcode = ARM::CMP_SWAP_16;
2623 else if (MemTy == MVT::i32)
2624 Opcode = ARM::CMP_SWAP_32;
2625 else
2626 llvm_unreachable("Unknown AtomicCmpSwap type");
2627
2628 SDValue Ops[] = {N->getOperand(1), N->getOperand(2), N->getOperand(3),
2629 N->getOperand(0)};
2630 SDNode *CmpSwap = CurDAG->getMachineNode(
2631 Opcode, SDLoc(N),
2632 CurDAG->getVTList(MVT::i32, MVT::i32, MVT::Other), Ops);
2633
Chandler Carruth66654b72018-08-14 23:30:32 +00002634 MachineMemOperand *MemOp = cast<MemSDNode>(N)->getMemOperand();
2635 CurDAG->setNodeMemRefs(cast<MachineSDNode>(CmpSwap), {MemOp});
Tim Northoverb629c772016-04-18 21:48:55 +00002636
2637 ReplaceUses(SDValue(N, 0), SDValue(CmpSwap, 0));
2638 ReplaceUses(SDValue(N, 1), SDValue(CmpSwap, 2));
Justin Bognered4f3782016-05-12 00:20:19 +00002639 CurDAG->RemoveDeadNode(N);
Tim Northoverb629c772016-04-18 21:48:55 +00002640}
2641
Sjoerd Meijer96e10b52016-12-15 09:38:59 +00002642static Optional<std::pair<unsigned, unsigned>>
2643getContiguousRangeOfSetBits(const APInt &A) {
2644 unsigned FirstOne = A.getBitWidth() - A.countLeadingZeros() - 1;
2645 unsigned LastOne = A.countTrailingZeros();
2646 if (A.countPopulation() != (FirstOne - LastOne + 1))
2647 return Optional<std::pair<unsigned,unsigned>>();
2648 return std::make_pair(FirstOne, LastOne);
2649}
2650
2651void ARMDAGToDAGISel::SelectCMPZ(SDNode *N, bool &SwitchEQNEToPLMI) {
2652 assert(N->getOpcode() == ARMISD::CMPZ);
2653 SwitchEQNEToPLMI = false;
2654
2655 if (!Subtarget->isThumb())
2656 // FIXME: Work out whether it is profitable to do this in A32 mode - LSL and
2657 // LSR don't exist as standalone instructions - they need the barrel shifter.
2658 return;
2659
2660 // select (cmpz (and X, C), #0) -> (LSLS X) or (LSRS X) or (LSRS (LSLS X))
2661 SDValue And = N->getOperand(0);
2662 if (!And->hasOneUse())
2663 return;
2664
2665 SDValue Zero = N->getOperand(1);
2666 if (!isa<ConstantSDNode>(Zero) || !cast<ConstantSDNode>(Zero)->isNullValue() ||
2667 And->getOpcode() != ISD::AND)
2668 return;
2669 SDValue X = And.getOperand(0);
2670 auto C = dyn_cast<ConstantSDNode>(And.getOperand(1));
2671
Eli Friedman864df222018-06-08 21:16:56 +00002672 if (!C)
Sjoerd Meijer96e10b52016-12-15 09:38:59 +00002673 return;
2674 auto Range = getContiguousRangeOfSetBits(C->getAPIntValue());
2675 if (!Range)
2676 return;
2677
2678 // There are several ways to lower this:
2679 SDNode *NewN;
2680 SDLoc dl(N);
2681
2682 auto EmitShift = [&](unsigned Opc, SDValue Src, unsigned Imm) -> SDNode* {
2683 if (Subtarget->isThumb2()) {
2684 Opc = (Opc == ARM::tLSLri) ? ARM::t2LSLri : ARM::t2LSRri;
2685 SDValue Ops[] = { Src, CurDAG->getTargetConstant(Imm, dl, MVT::i32),
2686 getAL(CurDAG, dl), CurDAG->getRegister(0, MVT::i32),
2687 CurDAG->getRegister(0, MVT::i32) };
2688 return CurDAG->getMachineNode(Opc, dl, MVT::i32, Ops);
2689 } else {
2690 SDValue Ops[] = {CurDAG->getRegister(ARM::CPSR, MVT::i32), Src,
2691 CurDAG->getTargetConstant(Imm, dl, MVT::i32),
2692 getAL(CurDAG, dl), CurDAG->getRegister(0, MVT::i32)};
2693 return CurDAG->getMachineNode(Opc, dl, MVT::i32, Ops);
2694 }
2695 };
Fangrui Songf78650a2018-07-30 19:41:25 +00002696
Sjoerd Meijer96e10b52016-12-15 09:38:59 +00002697 if (Range->second == 0) {
2698 // 1. Mask includes the LSB -> Simply shift the top N bits off
2699 NewN = EmitShift(ARM::tLSLri, X, 31 - Range->first);
2700 ReplaceNode(And.getNode(), NewN);
2701 } else if (Range->first == 31) {
2702 // 2. Mask includes the MSB -> Simply shift the bottom N bits off
2703 NewN = EmitShift(ARM::tLSRri, X, Range->second);
2704 ReplaceNode(And.getNode(), NewN);
2705 } else if (Range->first == Range->second) {
2706 // 3. Only one bit is set. We can shift this into the sign bit and use a
2707 // PL/MI comparison.
2708 NewN = EmitShift(ARM::tLSLri, X, 31 - Range->first);
2709 ReplaceNode(And.getNode(), NewN);
2710
2711 SwitchEQNEToPLMI = true;
2712 } else if (!Subtarget->hasV6T2Ops()) {
2713 // 4. Do a double shift to clear bottom and top bits, but only in
2714 // thumb-1 mode as in thumb-2 we can use UBFX.
2715 NewN = EmitShift(ARM::tLSLri, X, 31 - Range->first);
2716 NewN = EmitShift(ARM::tLSRri, SDValue(NewN, 0),
2717 Range->second + (31 - Range->first));
2718 ReplaceNode(And.getNode(), NewN);
2719 }
2720
2721}
2722
Justin Bogner45571362016-05-12 00:31:09 +00002723void ARMDAGToDAGISel::Select(SDNode *N) {
Andrew Trickef9de2a2013-05-25 02:42:55 +00002724 SDLoc dl(N);
Evan Cheng10043e22007-01-19 07:51:42 +00002725
Tim Northover31d093c2013-09-22 08:21:56 +00002726 if (N->isMachineOpcode()) {
2727 N->setNodeId(-1);
Justin Bogner45571362016-05-12 00:31:09 +00002728 return; // Already selected.
Tim Northover31d093c2013-09-22 08:21:56 +00002729 }
Rafael Espindola4e760152006-06-12 12:28:08 +00002730
2731 switch (N->getOpcode()) {
Evan Cheng10043e22007-01-19 07:51:42 +00002732 default: break;
Eli Friedman638be662019-03-20 19:40:45 +00002733 case ISD::STORE: {
2734 // For Thumb1, match an sp-relative store in C++. This is a little
2735 // unfortunate, but I don't think I can make the chain check work
2736 // otherwise. (The chain of the store has to be the same as the chain
2737 // of the CopyFromReg, or else we can't replace the CopyFromReg with
2738 // a direct reference to "SP".)
2739 //
2740 // This is only necessary on Thumb1 because Thumb1 sp-relative stores use
2741 // a different addressing mode from other four-byte stores.
2742 //
2743 // This pattern usually comes up with call arguments.
2744 StoreSDNode *ST = cast<StoreSDNode>(N);
2745 SDValue Ptr = ST->getBasePtr();
2746 if (Subtarget->isThumb1Only() && ST->isUnindexed()) {
2747 int RHSC = 0;
2748 if (Ptr.getOpcode() == ISD::ADD &&
2749 isScaledConstantInRange(Ptr.getOperand(1), /*Scale=*/4, 0, 256, RHSC))
2750 Ptr = Ptr.getOperand(0);
2751
2752 if (Ptr.getOpcode() == ISD::CopyFromReg &&
2753 cast<RegisterSDNode>(Ptr.getOperand(1))->getReg() == ARM::SP &&
2754 Ptr.getOperand(0) == ST->getChain()) {
2755 SDValue Ops[] = {ST->getValue(),
2756 CurDAG->getRegister(ARM::SP, MVT::i32),
2757 CurDAG->getTargetConstant(RHSC, dl, MVT::i32),
2758 getAL(CurDAG, dl),
2759 CurDAG->getRegister(0, MVT::i32),
2760 ST->getChain()};
2761 MachineSDNode *ResNode =
2762 CurDAG->getMachineNode(ARM::tSTRspi, dl, MVT::Other, Ops);
2763 MachineMemOperand *MemOp = ST->getMemOperand();
2764 CurDAG->setNodeMemRefs(cast<MachineSDNode>(ResNode), {MemOp});
2765 ReplaceNode(N, ResNode);
2766 return;
2767 }
2768 }
2769 break;
2770 }
Justin Bogner45571362016-05-12 00:31:09 +00002771 case ISD::WRITE_REGISTER:
2772 if (tryWriteRegister(N))
2773 return;
Luke Cheeseman85fd06d2015-06-01 12:02:47 +00002774 break;
Justin Bogner45571362016-05-12 00:31:09 +00002775 case ISD::READ_REGISTER:
2776 if (tryReadRegister(N))
2777 return;
Luke Cheeseman85fd06d2015-06-01 12:02:47 +00002778 break;
Justin Bogner45571362016-05-12 00:31:09 +00002779 case ISD::INLINEASM:
Craig Topper784929d2019-02-08 20:48:56 +00002780 case ISD::INLINEASM_BR:
Justin Bogner45571362016-05-12 00:31:09 +00002781 if (tryInlineAsm(N))
2782 return;
Weiming Zhaoc5987002013-02-14 18:10:21 +00002783 break;
Justin Bogner45571362016-05-12 00:31:09 +00002784 case ISD::XOR:
Bill Wendlinga7d697e2011-10-10 22:59:55 +00002785 // Select special operations if XOR node forms integer ABS pattern
Justin Bogner45571362016-05-12 00:31:09 +00002786 if (tryABSOp(N))
2787 return;
Bill Wendlinga7d697e2011-10-10 22:59:55 +00002788 // Other cases are autogenerated.
2789 break;
Evan Cheng10043e22007-01-19 07:51:42 +00002790 case ISD::Constant: {
Dan Gohmaneffb8942008-09-12 16:56:44 +00002791 unsigned Val = cast<ConstantSDNode>(N)->getZExtValue();
John Brawn056e6782015-09-14 15:19:41 +00002792 // If we can't materialize the constant we need to use a literal pool
David Green61973d92019-09-03 11:06:24 +00002793 if (ConstantMaterializationCost(Val, Subtarget) > 2) {
Eric Christopherb17140d2014-10-08 07:32:17 +00002794 SDValue CPIdx = CurDAG->getTargetConstantPool(
2795 ConstantInt::get(Type::getInt32Ty(*CurDAG->getContext()), Val),
Mehdi Amini44ede332015-07-09 02:09:04 +00002796 TLI->getPointerTy(CurDAG->getDataLayout()));
Evan Cheng1526ba52007-01-24 08:53:17 +00002797
2798 SDNode *ResNode;
Tim Northover55c625f2014-01-23 13:43:47 +00002799 if (Subtarget->isThumb()) {
Sam Parker28934482017-07-14 08:23:56 +00002800 SDValue Ops[] = {
2801 CPIdx,
2802 getAL(CurDAG, dl),
2803 CurDAG->getRegister(0, MVT::i32),
2804 CurDAG->getEntryNode()
2805 };
Jim Grosbachbfef3092010-12-15 23:52:36 +00002806 ResNode = CurDAG->getMachineNode(ARM::tLDRpci, dl, MVT::i32, MVT::Other,
Michael Liaob53d8962013-04-19 22:22:57 +00002807 Ops);
Evan Chengcd4cdd12009-07-11 06:43:01 +00002808 } else {
Dan Gohman2ce6f2a2008-07-27 21:46:04 +00002809 SDValue Ops[] = {
Jim Grosbachf24f9d92009-08-11 15:33:49 +00002810 CPIdx,
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00002811 CurDAG->getTargetConstant(0, dl, MVT::i32),
2812 getAL(CurDAG, dl),
Owen Anderson9f944592009-08-11 20:47:22 +00002813 CurDAG->getRegister(0, MVT::i32),
Evan Cheng1526ba52007-01-24 08:53:17 +00002814 CurDAG->getEntryNode()
2815 };
Justin Bogner45571362016-05-12 00:31:09 +00002816 ResNode = CurDAG->getMachineNode(ARM::LDRcp, dl, MVT::i32, MVT::Other,
2817 Ops);
Evan Cheng1526ba52007-01-24 08:53:17 +00002818 }
Sam Parker28934482017-07-14 08:23:56 +00002819 // Annotate the Node with memory operand information so that MachineInstr
2820 // queries work properly. This e.g. gives the register allocation the
2821 // required information for rematerialization.
2822 MachineFunction& MF = CurDAG->getMachineFunction();
Chandler Carruth66654b72018-08-14 23:30:32 +00002823 MachineMemOperand *MemOp =
2824 MF.getMachineMemOperand(MachinePointerInfo::getConstantPool(MF),
2825 MachineMemOperand::MOLoad, 4, 4);
Sam Parker28934482017-07-14 08:23:56 +00002826
Chandler Carruth66654b72018-08-14 23:30:32 +00002827 CurDAG->setNodeMemRefs(cast<MachineSDNode>(ResNode), {MemOp});
Fangrui Songf78650a2018-07-30 19:41:25 +00002828
Justin Bognered4f3782016-05-12 00:20:19 +00002829 ReplaceNode(N, ResNode);
Justin Bogner45571362016-05-12 00:31:09 +00002830 return;
Evan Cheng10043e22007-01-19 07:51:42 +00002831 }
Jim Grosbachf24f9d92009-08-11 15:33:49 +00002832
Evan Cheng10043e22007-01-19 07:51:42 +00002833 // Other cases are autogenerated.
Rafael Espindola4e760152006-06-12 12:28:08 +00002834 break;
Evan Cheng10043e22007-01-19 07:51:42 +00002835 }
Rafael Espindola5f7ab1b2006-11-09 13:58:55 +00002836 case ISD::FrameIndex: {
Evan Cheng10043e22007-01-19 07:51:42 +00002837 // Selects to ADDri FI, 0 which in turn will become ADDri SP, imm.
Rafael Espindola5f7ab1b2006-11-09 13:58:55 +00002838 int FI = cast<FrameIndexSDNode>(N)->getIndex();
Mehdi Amini44ede332015-07-09 02:09:04 +00002839 SDValue TFI = CurDAG->getTargetFrameIndex(
2840 FI, TLI->getPointerTy(CurDAG->getDataLayout()));
David Goodwin22c2fba2009-07-08 23:10:31 +00002841 if (Subtarget->isThumb1Only()) {
Renato Golinb9887ef2015-02-25 14:41:06 +00002842 // Set the alignment of the frame object to 4, to avoid having to generate
2843 // more than one ADD
Matthias Braun941a7052016-07-28 18:40:00 +00002844 MachineFrameInfo &MFI = MF->getFrameInfo();
2845 if (MFI.getObjectAlignment(FI) < 4)
2846 MFI.setObjectAlignment(FI, 4);
Justin Bogner45571362016-05-12 00:31:09 +00002847 CurDAG->SelectNodeTo(N, ARM::tADDframe, MVT::i32, TFI,
2848 CurDAG->getTargetConstant(0, dl, MVT::i32));
2849 return;
Jim Grosbachfde21102009-04-07 20:34:09 +00002850 } else {
David Goodwin4ad77972009-07-14 18:48:51 +00002851 unsigned Opc = ((Subtarget->isThumb() && Subtarget->hasThumb2()) ?
2852 ARM::t2ADDri : ARM::ADDri);
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00002853 SDValue Ops[] = { TFI, CurDAG->getTargetConstant(0, dl, MVT::i32),
2854 getAL(CurDAG, dl), CurDAG->getRegister(0, MVT::i32),
Owen Anderson9f944592009-08-11 20:47:22 +00002855 CurDAG->getRegister(0, MVT::i32) };
Justin Bogner45571362016-05-12 00:31:09 +00002856 CurDAG->SelectNodeTo(N, Opc, MVT::i32, Ops);
2857 return;
Evan Cheng7e90b112007-07-05 07:15:27 +00002858 }
Evan Cheng10043e22007-01-19 07:51:42 +00002859 }
Sandeep Patel423e42b2009-10-13 18:59:48 +00002860 case ISD::SRL:
Justin Bogner45571362016-05-12 00:31:09 +00002861 if (tryV6T2BitfieldExtractOp(N, false))
2862 return;
Sandeep Patel423e42b2009-10-13 18:59:48 +00002863 break;
Tim Northover14ff2df2014-07-23 13:59:12 +00002864 case ISD::SIGN_EXTEND_INREG:
Sandeep Patel423e42b2009-10-13 18:59:48 +00002865 case ISD::SRA:
Justin Bogner45571362016-05-12 00:31:09 +00002866 if (tryV6T2BitfieldExtractOp(N, true))
2867 return;
Sandeep Patel423e42b2009-10-13 18:59:48 +00002868 break;
Evan Cheng10043e22007-01-19 07:51:42 +00002869 case ISD::MUL:
Evan Chengb24e51e2009-07-07 01:17:28 +00002870 if (Subtarget->isThumb1Only())
Evan Cheng139edae2007-01-24 02:21:22 +00002871 break;
Dan Gohmanea6f91f2010-01-05 01:24:18 +00002872 if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(N->getOperand(1))) {
Dan Gohmaneffb8942008-09-12 16:56:44 +00002873 unsigned RHSV = C->getZExtValue();
Evan Cheng10043e22007-01-19 07:51:42 +00002874 if (!RHSV) break;
2875 if (isPowerOf2_32(RHSV-1)) { // 2^n+1?
Evan Cheng0d8b0cf2009-07-21 00:31:12 +00002876 unsigned ShImm = Log2_32(RHSV-1);
2877 if (ShImm >= 32)
2878 break;
Dan Gohmanea6f91f2010-01-05 01:24:18 +00002879 SDValue V = N->getOperand(0);
Evan Cheng0d8b0cf2009-07-21 00:31:12 +00002880 ShImm = ARM_AM::getSORegOpc(ARM_AM::lsl, ShImm);
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00002881 SDValue ShImmOp = CurDAG->getTargetConstant(ShImm, dl, MVT::i32);
Owen Anderson9f944592009-08-11 20:47:22 +00002882 SDValue Reg0 = CurDAG->getRegister(0, MVT::i32);
Evan Cheng1ec43962009-07-22 18:08:05 +00002883 if (Subtarget->isThumb()) {
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00002884 SDValue Ops[] = { V, V, ShImmOp, getAL(CurDAG, dl), Reg0, Reg0 };
Justin Bogner45571362016-05-12 00:31:09 +00002885 CurDAG->SelectNodeTo(N, ARM::t2ADDrs, MVT::i32, Ops);
2886 return;
Evan Cheng0d8b0cf2009-07-21 00:31:12 +00002887 } else {
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00002888 SDValue Ops[] = { V, V, Reg0, ShImmOp, getAL(CurDAG, dl), Reg0,
2889 Reg0 };
Justin Bogner45571362016-05-12 00:31:09 +00002890 CurDAG->SelectNodeTo(N, ARM::ADDrsi, MVT::i32, Ops);
2891 return;
Evan Cheng0d8b0cf2009-07-21 00:31:12 +00002892 }
Evan Cheng10043e22007-01-19 07:51:42 +00002893 }
2894 if (isPowerOf2_32(RHSV+1)) { // 2^n-1?
Evan Cheng0d8b0cf2009-07-21 00:31:12 +00002895 unsigned ShImm = Log2_32(RHSV+1);
2896 if (ShImm >= 32)
2897 break;
Dan Gohmanea6f91f2010-01-05 01:24:18 +00002898 SDValue V = N->getOperand(0);
Evan Cheng0d8b0cf2009-07-21 00:31:12 +00002899 ShImm = ARM_AM::getSORegOpc(ARM_AM::lsl, ShImm);
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00002900 SDValue ShImmOp = CurDAG->getTargetConstant(ShImm, dl, MVT::i32);
Owen Anderson9f944592009-08-11 20:47:22 +00002901 SDValue Reg0 = CurDAG->getRegister(0, MVT::i32);
Evan Cheng1ec43962009-07-22 18:08:05 +00002902 if (Subtarget->isThumb()) {
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00002903 SDValue Ops[] = { V, V, ShImmOp, getAL(CurDAG, dl), Reg0, Reg0 };
Justin Bogner45571362016-05-12 00:31:09 +00002904 CurDAG->SelectNodeTo(N, ARM::t2RSBrs, MVT::i32, Ops);
2905 return;
Evan Cheng0d8b0cf2009-07-21 00:31:12 +00002906 } else {
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00002907 SDValue Ops[] = { V, V, Reg0, ShImmOp, getAL(CurDAG, dl), Reg0,
2908 Reg0 };
Justin Bogner45571362016-05-12 00:31:09 +00002909 CurDAG->SelectNodeTo(N, ARM::RSBrsi, MVT::i32, Ops);
2910 return;
Evan Cheng0d8b0cf2009-07-21 00:31:12 +00002911 }
Evan Cheng10043e22007-01-19 07:51:42 +00002912 }
2913 }
2914 break;
Evan Cheng786b15f2009-10-21 08:15:52 +00002915 case ISD::AND: {
Jim Grosbach825cb292010-04-22 23:24:18 +00002916 // Check for unsigned bitfield extract
Justin Bogner45571362016-05-12 00:31:09 +00002917 if (tryV6T2BitfieldExtractOp(N, false))
2918 return;
Jim Grosbach825cb292010-04-22 23:24:18 +00002919
James Molloyae5ff992016-07-05 12:37:13 +00002920 // If an immediate is used in an AND node, it is possible that the immediate
2921 // can be more optimally materialized when negated. If this is the case we
2922 // can negate the immediate and use a BIC instead.
2923 auto *N1C = dyn_cast<ConstantSDNode>(N->getOperand(1));
2924 if (N1C && N1C->hasOneUse() && Subtarget->isThumb()) {
2925 uint32_t Imm = (uint32_t) N1C->getZExtValue();
2926
2927 // In Thumb2 mode, an AND can take a 12-bit immediate. If this
2928 // immediate can be negated and fit in the immediate operand of
2929 // a t2BIC, don't do any manual transform here as this can be
2930 // handled by the generic ISel machinery.
2931 bool PreferImmediateEncoding =
2932 Subtarget->hasThumb2() && (is_t2_so_imm(Imm) || is_t2_so_imm_not(Imm));
2933 if (!PreferImmediateEncoding &&
David Green61973d92019-09-03 11:06:24 +00002934 ConstantMaterializationCost(Imm, Subtarget) >
2935 ConstantMaterializationCost(~Imm, Subtarget)) {
James Molloyae5ff992016-07-05 12:37:13 +00002936 // The current immediate costs more to materialize than a negated
2937 // immediate, so negate the immediate and use a BIC.
2938 SDValue NewImm =
2939 CurDAG->getConstant(~N1C->getZExtValue(), dl, MVT::i32);
2940 // If the new constant didn't exist before, reposition it in the topological
2941 // ordering so it is just before N. Otherwise, don't touch its location.
2942 if (NewImm->getNodeId() == -1)
2943 CurDAG->RepositionNode(N->getIterator(), NewImm.getNode());
2944
2945 if (!Subtarget->hasThumb2()) {
2946 SDValue Ops[] = {CurDAG->getRegister(ARM::CPSR, MVT::i32),
2947 N->getOperand(0), NewImm, getAL(CurDAG, dl),
2948 CurDAG->getRegister(0, MVT::i32)};
2949 ReplaceNode(N, CurDAG->getMachineNode(ARM::tBIC, dl, MVT::i32, Ops));
2950 return;
2951 } else {
2952 SDValue Ops[] = {N->getOperand(0), NewImm, getAL(CurDAG, dl),
2953 CurDAG->getRegister(0, MVT::i32),
2954 CurDAG->getRegister(0, MVT::i32)};
2955 ReplaceNode(N,
2956 CurDAG->getMachineNode(ARM::t2BICrr, dl, MVT::i32, Ops));
2957 return;
2958 }
2959 }
2960 }
2961
Evan Cheng786b15f2009-10-21 08:15:52 +00002962 // (and (or x, c2), c1) and top 16-bits of c1 and c2 match, lower 16-bits
2963 // of c1 are 0xffff, and lower 16-bit of c2 are 0. That is, the top 16-bits
2964 // are entirely contributed by c2 and lower 16-bits are entirely contributed
2965 // by x. That's equal to (or (and x, 0xffff), (and c1, 0xffff0000)).
2966 // Select it to: "movt x, ((c1 & 0xffff) >> 16)
Dan Gohmanea6f91f2010-01-05 01:24:18 +00002967 EVT VT = N->getValueType(0);
Evan Cheng786b15f2009-10-21 08:15:52 +00002968 if (VT != MVT::i32)
2969 break;
2970 unsigned Opc = (Subtarget->isThumb() && Subtarget->hasThumb2())
2971 ? ARM::t2MOVTi16
2972 : (Subtarget->hasV6T2Ops() ? ARM::MOVTi16 : 0);
2973 if (!Opc)
2974 break;
Dan Gohmanea6f91f2010-01-05 01:24:18 +00002975 SDValue N0 = N->getOperand(0), N1 = N->getOperand(1);
James Molloyae5ff992016-07-05 12:37:13 +00002976 N1C = dyn_cast<ConstantSDNode>(N1);
Evan Cheng786b15f2009-10-21 08:15:52 +00002977 if (!N1C)
2978 break;
2979 if (N0.getOpcode() == ISD::OR && N0.getNode()->hasOneUse()) {
2980 SDValue N2 = N0.getOperand(1);
2981 ConstantSDNode *N2C = dyn_cast<ConstantSDNode>(N2);
2982 if (!N2C)
2983 break;
2984 unsigned N1CVal = N1C->getZExtValue();
2985 unsigned N2CVal = N2C->getZExtValue();
2986 if ((N1CVal & 0xffff0000U) == (N2CVal & 0xffff0000U) &&
2987 (N1CVal & 0xffffU) == 0xffffU &&
2988 (N2CVal & 0xffffU) == 0x0U) {
2989 SDValue Imm16 = CurDAG->getTargetConstant((N2CVal & 0xFFFF0000U) >> 16,
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00002990 dl, MVT::i32);
Evan Cheng786b15f2009-10-21 08:15:52 +00002991 SDValue Ops[] = { N0.getOperand(0), Imm16,
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00002992 getAL(CurDAG, dl), CurDAG->getRegister(0, MVT::i32) };
Justin Bogner45571362016-05-12 00:31:09 +00002993 ReplaceNode(N, CurDAG->getMachineNode(Opc, dl, VT, Ops));
2994 return;
Evan Cheng786b15f2009-10-21 08:15:52 +00002995 }
2996 }
Sjoerd Meijer96e10b52016-12-15 09:38:59 +00002997
Evan Cheng786b15f2009-10-21 08:15:52 +00002998 break;
2999 }
Sam Parkerd616cf02016-06-20 16:47:09 +00003000 case ARMISD::UMAAL: {
3001 unsigned Opc = Subtarget->isThumb() ? ARM::t2UMAAL : ARM::UMAAL;
3002 SDValue Ops[] = { N->getOperand(0), N->getOperand(1),
3003 N->getOperand(2), N->getOperand(3),
3004 getAL(CurDAG, dl),
3005 CurDAG->getRegister(0, MVT::i32) };
3006 ReplaceNode(N, CurDAG->getMachineNode(Opc, dl, MVT::i32, MVT::i32, Ops));
3007 return;
3008 }
Arnold Schwaighoferf00fb1c2012-09-04 14:37:49 +00003009 case ARMISD::UMLAL:{
3010 if (Subtarget->isThumb()) {
3011 SDValue Ops[] = { N->getOperand(0), N->getOperand(1), N->getOperand(2),
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00003012 N->getOperand(3), getAL(CurDAG, dl),
Arnold Schwaighoferf00fb1c2012-09-04 14:37:49 +00003013 CurDAG->getRegister(0, MVT::i32)};
Justin Bogner45571362016-05-12 00:31:09 +00003014 ReplaceNode(
3015 N, CurDAG->getMachineNode(ARM::t2UMLAL, dl, MVT::i32, MVT::i32, Ops));
3016 return;
Arnold Schwaighoferf00fb1c2012-09-04 14:37:49 +00003017 }else{
3018 SDValue Ops[] = { N->getOperand(0), N->getOperand(1), N->getOperand(2),
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00003019 N->getOperand(3), getAL(CurDAG, dl),
Arnold Schwaighoferf00fb1c2012-09-04 14:37:49 +00003020 CurDAG->getRegister(0, MVT::i32),
3021 CurDAG->getRegister(0, MVT::i32) };
Justin Bogner45571362016-05-12 00:31:09 +00003022 ReplaceNode(N, CurDAG->getMachineNode(
3023 Subtarget->hasV6Ops() ? ARM::UMLAL : ARM::UMLALv5, dl,
3024 MVT::i32, MVT::i32, Ops));
3025 return;
Arnold Schwaighoferf00fb1c2012-09-04 14:37:49 +00003026 }
3027 }
3028 case ARMISD::SMLAL:{
3029 if (Subtarget->isThumb()) {
3030 SDValue Ops[] = { N->getOperand(0), N->getOperand(1), N->getOperand(2),
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00003031 N->getOperand(3), getAL(CurDAG, dl),
Arnold Schwaighoferf00fb1c2012-09-04 14:37:49 +00003032 CurDAG->getRegister(0, MVT::i32)};
Justin Bogner45571362016-05-12 00:31:09 +00003033 ReplaceNode(
3034 N, CurDAG->getMachineNode(ARM::t2SMLAL, dl, MVT::i32, MVT::i32, Ops));
3035 return;
Arnold Schwaighoferf00fb1c2012-09-04 14:37:49 +00003036 }else{
3037 SDValue Ops[] = { N->getOperand(0), N->getOperand(1), N->getOperand(2),
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00003038 N->getOperand(3), getAL(CurDAG, dl),
Arnold Schwaighoferf00fb1c2012-09-04 14:37:49 +00003039 CurDAG->getRegister(0, MVT::i32),
3040 CurDAG->getRegister(0, MVT::i32) };
Justin Bogner45571362016-05-12 00:31:09 +00003041 ReplaceNode(N, CurDAG->getMachineNode(
3042 Subtarget->hasV6Ops() ? ARM::SMLAL : ARM::SMLALv5, dl,
3043 MVT::i32, MVT::i32, Ops));
3044 return;
Arnold Schwaighoferf00fb1c2012-09-04 14:37:49 +00003045 }
3046 }
Sam Parker68c71cd2016-07-25 09:20:20 +00003047 case ARMISD::SUBE: {
Andre Vieira26b9de92018-01-12 09:21:09 +00003048 if (!Subtarget->hasV6Ops() || !Subtarget->hasDSP())
Sam Parker68c71cd2016-07-25 09:20:20 +00003049 break;
3050 // Look for a pattern to match SMMLS
3051 // (sube a, (smul_loHi a, b), (subc 0, (smul_LOhi(a, b))))
3052 if (N->getOperand(1).getOpcode() != ISD::SMUL_LOHI ||
Tim Northover765777c2016-08-02 23:12:36 +00003053 N->getOperand(2).getOpcode() != ARMISD::SUBC ||
3054 !SDValue(N, 1).use_empty())
Sam Parker68c71cd2016-07-25 09:20:20 +00003055 break;
3056
3057 if (Subtarget->isThumb())
3058 assert(Subtarget->hasThumb2() &&
3059 "This pattern should not be generated for Thumb");
3060
3061 SDValue SmulLoHi = N->getOperand(1);
3062 SDValue Subc = N->getOperand(2);
3063 auto *Zero = dyn_cast<ConstantSDNode>(Subc.getOperand(0));
3064
3065 if (!Zero || Zero->getZExtValue() != 0 ||
3066 Subc.getOperand(1) != SmulLoHi.getValue(0) ||
3067 N->getOperand(1) != SmulLoHi.getValue(1) ||
3068 N->getOperand(2) != Subc.getValue(1))
3069 break;
3070
3071 unsigned Opc = Subtarget->isThumb2() ? ARM::t2SMMLS : ARM::SMMLS;
3072 SDValue Ops[] = { SmulLoHi.getOperand(0), SmulLoHi.getOperand(1),
3073 N->getOperand(0), getAL(CurDAG, dl),
3074 CurDAG->getRegister(0, MVT::i32) };
3075 ReplaceNode(N, CurDAG->getMachineNode(Opc, dl, MVT::i32, Ops));
3076 return;
3077 }
Evan Cheng10043e22007-01-19 07:51:42 +00003078 case ISD::LOAD: {
David Green27ca82f2019-08-08 15:27:58 +00003079 if (Subtarget->hasMVEIntegerOps() && tryMVEIndexedLoad(N))
3080 return;
Justin Bogner45571362016-05-12 00:31:09 +00003081 if (Subtarget->isThumb() && Subtarget->hasThumb2()) {
3082 if (tryT2IndexedLoad(N))
3083 return;
James Molloyb3326df2016-07-15 08:03:56 +00003084 } else if (Subtarget->isThumb()) {
3085 if (tryT1IndexedLoad(N))
3086 return;
Justin Bogner45571362016-05-12 00:31:09 +00003087 } else if (tryARMIndexedLoad(N))
3088 return;
Evan Cheng10043e22007-01-19 07:51:42 +00003089 // Other cases are autogenerated.
Rafael Espindola5f7ab1b2006-11-09 13:58:55 +00003090 break;
Rafael Espindola4e760152006-06-12 12:28:08 +00003091 }
Sam Parker57e87dd2019-07-23 14:08:46 +00003092 case ARMISD::WLS:
3093 case ARMISD::LE: {
3094 SDValue Ops[] = { N->getOperand(1),
3095 N->getOperand(2),
Sam Parker98722692019-07-01 08:21:28 +00003096 N->getOperand(0) };
Sam Parker57e87dd2019-07-23 14:08:46 +00003097 unsigned Opc = N->getOpcode() == ARMISD::WLS ?
3098 ARM::t2WhileLoopStart : ARM::t2LoopEnd;
3099 SDNode *New = CurDAG->getMachineNode(Opc, dl, MVT::Other, Ops);
3100 ReplaceUses(N, New);
3101 CurDAG->RemoveDeadNode(N);
3102 return;
3103 }
3104 case ARMISD::LOOP_DEC: {
3105 SDValue Ops[] = { N->getOperand(1),
3106 N->getOperand(2),
3107 N->getOperand(0) };
3108 SDNode *Dec =
3109 CurDAG->getMachineNode(ARM::t2LoopDec, dl,
3110 CurDAG->getVTList(MVT::i32, MVT::Other), Ops);
3111 ReplaceUses(N, Dec);
Sam Parker98722692019-07-01 08:21:28 +00003112 CurDAG->RemoveDeadNode(N);
3113 return;
3114 }
Evan Cheng7e90b112007-07-05 07:15:27 +00003115 case ARMISD::BRCOND: {
3116 // Pattern: (ARMbrcond:void (bb:Other):$dst, (imm:i32):$cc)
3117 // Emits: (Bcc:void (bb:Other):$dst, (imm:i32):$cc)
3118 // Pattern complexity = 6 cost = 1 size = 0
Rafael Espindolaffdc24b2006-05-14 22:18:28 +00003119
Evan Cheng7e90b112007-07-05 07:15:27 +00003120 // Pattern: (ARMbrcond:void (bb:Other):$dst, (imm:i32):$cc)
3121 // Emits: (tBcc:void (bb:Other):$dst, (imm:i32):$cc)
3122 // Pattern complexity = 6 cost = 1 size = 0
3123
David Goodwin27303cd2009-06-30 18:04:13 +00003124 // Pattern: (ARMbrcond:void (bb:Other):$dst, (imm:i32):$cc)
3125 // Emits: (t2Bcc:void (bb:Other):$dst, (imm:i32):$cc)
3126 // Pattern complexity = 6 cost = 1 size = 0
3127
Jim Grosbachf24f9d92009-08-11 15:33:49 +00003128 unsigned Opc = Subtarget->isThumb() ?
David Goodwin27303cd2009-06-30 18:04:13 +00003129 ((Subtarget->hasThumb2()) ? ARM::t2Bcc : ARM::tBcc) : ARM::Bcc;
Dan Gohmanea6f91f2010-01-05 01:24:18 +00003130 SDValue Chain = N->getOperand(0);
3131 SDValue N1 = N->getOperand(1);
3132 SDValue N2 = N->getOperand(2);
3133 SDValue N3 = N->getOperand(3);
3134 SDValue InFlag = N->getOperand(4);
Evan Cheng7e90b112007-07-05 07:15:27 +00003135 assert(N1.getOpcode() == ISD::BasicBlock);
3136 assert(N2.getOpcode() == ISD::Constant);
3137 assert(N3.getOpcode() == ISD::Register);
3138
Sjoerd Meijer96e10b52016-12-15 09:38:59 +00003139 unsigned CC = (unsigned) cast<ConstantSDNode>(N2)->getZExtValue();
Fangrui Songf78650a2018-07-30 19:41:25 +00003140
Sjoerd Meijer96e10b52016-12-15 09:38:59 +00003141 if (InFlag.getOpcode() == ARMISD::CMPZ) {
Sam Parkera6fd9192019-06-25 10:45:51 +00003142 if (InFlag.getOperand(0).getOpcode() == ISD::INTRINSIC_W_CHAIN) {
3143 SDValue Int = InFlag.getOperand(0);
3144 uint64_t ID = cast<ConstantSDNode>(Int->getOperand(1))->getZExtValue();
3145
3146 // Handle low-overhead loops.
3147 if (ID == Intrinsic::loop_decrement_reg) {
3148 SDValue Elements = Int.getOperand(2);
3149 SDValue Size = CurDAG->getTargetConstant(
3150 cast<ConstantSDNode>(Int.getOperand(3))->getZExtValue(), dl,
3151 MVT::i32);
3152
3153 SDValue Args[] = { Elements, Size, Int.getOperand(0) };
3154 SDNode *LoopDec =
3155 CurDAG->getMachineNode(ARM::t2LoopDec, dl,
3156 CurDAG->getVTList(MVT::i32, MVT::Other),
3157 Args);
3158 ReplaceUses(Int.getNode(), LoopDec);
3159
3160 SDValue EndArgs[] = { SDValue(LoopDec, 0), N1, Chain };
3161 SDNode *LoopEnd =
3162 CurDAG->getMachineNode(ARM::t2LoopEnd, dl, MVT::Other, EndArgs);
3163
3164 ReplaceUses(N, LoopEnd);
3165 CurDAG->RemoveDeadNode(N);
3166 CurDAG->RemoveDeadNode(InFlag.getNode());
3167 CurDAG->RemoveDeadNode(Int.getNode());
3168 return;
3169 }
3170 }
3171
Sjoerd Meijer96e10b52016-12-15 09:38:59 +00003172 bool SwitchEQNEToPLMI;
3173 SelectCMPZ(InFlag.getNode(), SwitchEQNEToPLMI);
3174 InFlag = N->getOperand(4);
3175
3176 if (SwitchEQNEToPLMI) {
3177 switch ((ARMCC::CondCodes)CC) {
3178 default: llvm_unreachable("CMPZ must be either NE or EQ!");
3179 case ARMCC::NE:
3180 CC = (unsigned)ARMCC::MI;
3181 break;
3182 case ARMCC::EQ:
3183 CC = (unsigned)ARMCC::PL;
3184 break;
3185 }
3186 }
3187 }
3188
3189 SDValue Tmp2 = CurDAG->getTargetConstant(CC, dl, MVT::i32);
Dan Gohman2ce6f2a2008-07-27 21:46:04 +00003190 SDValue Ops[] = { N1, Tmp2, N3, Chain, InFlag };
Dan Gohman32f71d72009-09-25 18:54:59 +00003191 SDNode *ResNode = CurDAG->getMachineNode(Opc, dl, MVT::Other,
Michael Liaob53d8962013-04-19 22:22:57 +00003192 MVT::Glue, Ops);
Dan Gohman2ce6f2a2008-07-27 21:46:04 +00003193 Chain = SDValue(ResNode, 0);
Dan Gohmanea6f91f2010-01-05 01:24:18 +00003194 if (N->getNumValues() == 2) {
Dan Gohman2ce6f2a2008-07-27 21:46:04 +00003195 InFlag = SDValue(ResNode, 1);
Dan Gohmanea6f91f2010-01-05 01:24:18 +00003196 ReplaceUses(SDValue(N, 1), InFlag);
Chris Lattnere99faac2008-02-03 03:20:59 +00003197 }
Dan Gohmanea6f91f2010-01-05 01:24:18 +00003198 ReplaceUses(SDValue(N, 0),
Evan Cheng82adca82009-11-19 08:16:50 +00003199 SDValue(Chain.getNode(), Chain.getResNo()));
Justin Bognered4f3782016-05-12 00:20:19 +00003200 CurDAG->RemoveDeadNode(N);
Justin Bogner45571362016-05-12 00:31:09 +00003201 return;
Evan Cheng7e90b112007-07-05 07:15:27 +00003202 }
James Molloy4d86bed2016-09-09 12:52:24 +00003203
3204 case ARMISD::CMPZ: {
3205 // select (CMPZ X, #-C) -> (CMPZ (ADDS X, #C), #0)
3206 // This allows us to avoid materializing the expensive negative constant.
3207 // The CMPZ #0 is useless and will be peepholed away but we need to keep it
3208 // for its glue output.
3209 SDValue X = N->getOperand(0);
3210 auto *C = dyn_cast<ConstantSDNode>(N->getOperand(1).getNode());
3211 if (C && C->getSExtValue() < 0 && Subtarget->isThumb()) {
3212 int64_t Addend = -C->getSExtValue();
3213
3214 SDNode *Add = nullptr;
Artyom Skrobov4592f622017-02-17 18:59:16 +00003215 // ADDS can be better than CMN if the immediate fits in a
James Molloy4d86bed2016-09-09 12:52:24 +00003216 // 16-bit ADDS, which means either [0,256) for tADDi8 or [0,8) for tADDi3.
3217 // Outside that range we can just use a CMN which is 32-bit but has a
3218 // 12-bit immediate range.
Artyom Skrobov4592f622017-02-17 18:59:16 +00003219 if (Addend < 1<<8) {
3220 if (Subtarget->isThumb2()) {
3221 SDValue Ops[] = { X, CurDAG->getTargetConstant(Addend, dl, MVT::i32),
3222 getAL(CurDAG, dl), CurDAG->getRegister(0, MVT::i32),
3223 CurDAG->getRegister(0, MVT::i32) };
3224 Add = CurDAG->getMachineNode(ARM::t2ADDri, dl, MVT::i32, Ops);
3225 } else {
3226 unsigned Opc = (Addend < 1<<3) ? ARM::tADDi3 : ARM::tADDi8;
3227 SDValue Ops[] = {CurDAG->getRegister(ARM::CPSR, MVT::i32), X,
3228 CurDAG->getTargetConstant(Addend, dl, MVT::i32),
3229 getAL(CurDAG, dl), CurDAG->getRegister(0, MVT::i32)};
3230 Add = CurDAG->getMachineNode(Opc, dl, MVT::i32, Ops);
3231 }
James Molloy4d86bed2016-09-09 12:52:24 +00003232 }
3233 if (Add) {
3234 SDValue Ops2[] = {SDValue(Add, 0), CurDAG->getConstant(0, dl, MVT::i32)};
3235 CurDAG->MorphNodeTo(N, ARMISD::CMPZ, CurDAG->getVTList(MVT::Glue), Ops2);
3236 }
3237 }
3238 // Other cases are autogenerated.
3239 break;
3240 }
Sjoerd Meijer96e10b52016-12-15 09:38:59 +00003241
3242 case ARMISD::CMOV: {
3243 SDValue InFlag = N->getOperand(4);
3244
3245 if (InFlag.getOpcode() == ARMISD::CMPZ) {
3246 bool SwitchEQNEToPLMI;
3247 SelectCMPZ(InFlag.getNode(), SwitchEQNEToPLMI);
3248
3249 if (SwitchEQNEToPLMI) {
3250 SDValue ARMcc = N->getOperand(2);
3251 ARMCC::CondCodes CC =
3252 (ARMCC::CondCodes)cast<ConstantSDNode>(ARMcc)->getZExtValue();
3253
3254 switch (CC) {
3255 default: llvm_unreachable("CMPZ must be either NE or EQ!");
3256 case ARMCC::NE:
3257 CC = ARMCC::MI;
3258 break;
3259 case ARMCC::EQ:
3260 CC = ARMCC::PL;
3261 break;
3262 }
3263 SDValue NewARMcc = CurDAG->getConstant((unsigned)CC, dl, MVT::i32);
3264 SDValue Ops[] = {N->getOperand(0), N->getOperand(1), NewARMcc,
3265 N->getOperand(3), N->getOperand(4)};
3266 CurDAG->MorphNodeTo(N, ARMISD::CMOV, N->getVTList(), Ops);
3267 }
3268
3269 }
3270 // Other cases are autogenerated.
3271 break;
3272 }
Fangrui Songf78650a2018-07-30 19:41:25 +00003273
Anton Korobeynikov232b19c2009-08-21 12:41:42 +00003274 case ARMISD::VZIP: {
3275 unsigned Opc = 0;
Anton Korobeynikovce3ff1b2009-08-21 12:40:50 +00003276 EVT VT = N->getValueType(0);
Anton Korobeynikov232b19c2009-08-21 12:41:42 +00003277 switch (VT.getSimpleVT().SimpleTy) {
Justin Bogner45571362016-05-12 00:31:09 +00003278 default: return;
Anton Korobeynikov232b19c2009-08-21 12:41:42 +00003279 case MVT::v8i8: Opc = ARM::VZIPd8; break;
Sjoerd Meijerd62c5ec22018-08-03 09:24:29 +00003280 case MVT::v4f16:
Anton Korobeynikov232b19c2009-08-21 12:41:42 +00003281 case MVT::v4i16: Opc = ARM::VZIPd16; break;
3282 case MVT::v2f32:
Jim Grosbach4640c812012-04-11 16:53:25 +00003283 // vzip.32 Dd, Dm is a pseudo-instruction expanded to vtrn.32 Dd, Dm.
3284 case MVT::v2i32: Opc = ARM::VTRNd32; break;
Anton Korobeynikov232b19c2009-08-21 12:41:42 +00003285 case MVT::v16i8: Opc = ARM::VZIPq8; break;
Sjoerd Meijerd62c5ec22018-08-03 09:24:29 +00003286 case MVT::v8f16:
Anton Korobeynikov232b19c2009-08-21 12:41:42 +00003287 case MVT::v8i16: Opc = ARM::VZIPq16; break;
3288 case MVT::v4f32:
3289 case MVT::v4i32: Opc = ARM::VZIPq32; break;
3290 }
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00003291 SDValue Pred = getAL(CurDAG, dl);
Evan Chenga33fc862009-11-21 06:21:52 +00003292 SDValue PredReg = CurDAG->getRegister(0, MVT::i32);
3293 SDValue Ops[] = { N->getOperand(0), N->getOperand(1), Pred, PredReg };
Justin Bogner45571362016-05-12 00:31:09 +00003294 ReplaceNode(N, CurDAG->getMachineNode(Opc, dl, VT, VT, Ops));
3295 return;
Anton Korobeynikovce3ff1b2009-08-21 12:40:50 +00003296 }
Anton Korobeynikov232b19c2009-08-21 12:41:42 +00003297 case ARMISD::VUZP: {
3298 unsigned Opc = 0;
Anton Korobeynikovce3ff1b2009-08-21 12:40:50 +00003299 EVT VT = N->getValueType(0);
Anton Korobeynikov232b19c2009-08-21 12:41:42 +00003300 switch (VT.getSimpleVT().SimpleTy) {
Justin Bogner45571362016-05-12 00:31:09 +00003301 default: return;
Anton Korobeynikov232b19c2009-08-21 12:41:42 +00003302 case MVT::v8i8: Opc = ARM::VUZPd8; break;
Sjoerd Meijerd62c5ec22018-08-03 09:24:29 +00003303 case MVT::v4f16:
Anton Korobeynikov232b19c2009-08-21 12:41:42 +00003304 case MVT::v4i16: Opc = ARM::VUZPd16; break;
3305 case MVT::v2f32:
Jim Grosbach6e536de2012-04-11 17:40:18 +00003306 // vuzp.32 Dd, Dm is a pseudo-instruction expanded to vtrn.32 Dd, Dm.
3307 case MVT::v2i32: Opc = ARM::VTRNd32; break;
Anton Korobeynikov232b19c2009-08-21 12:41:42 +00003308 case MVT::v16i8: Opc = ARM::VUZPq8; break;
Sjoerd Meijerd62c5ec22018-08-03 09:24:29 +00003309 case MVT::v8f16:
Anton Korobeynikov232b19c2009-08-21 12:41:42 +00003310 case MVT::v8i16: Opc = ARM::VUZPq16; break;
3311 case MVT::v4f32:
3312 case MVT::v4i32: Opc = ARM::VUZPq32; break;
3313 }
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00003314 SDValue Pred = getAL(CurDAG, dl);
Evan Chenga33fc862009-11-21 06:21:52 +00003315 SDValue PredReg = CurDAG->getRegister(0, MVT::i32);
3316 SDValue Ops[] = { N->getOperand(0), N->getOperand(1), Pred, PredReg };
Justin Bogner45571362016-05-12 00:31:09 +00003317 ReplaceNode(N, CurDAG->getMachineNode(Opc, dl, VT, VT, Ops));
3318 return;
Anton Korobeynikovce3ff1b2009-08-21 12:40:50 +00003319 }
Anton Korobeynikov232b19c2009-08-21 12:41:42 +00003320 case ARMISD::VTRN: {
3321 unsigned Opc = 0;
Anton Korobeynikovce3ff1b2009-08-21 12:40:50 +00003322 EVT VT = N->getValueType(0);
Anton Korobeynikov232b19c2009-08-21 12:41:42 +00003323 switch (VT.getSimpleVT().SimpleTy) {
Justin Bogner45571362016-05-12 00:31:09 +00003324 default: return;
Anton Korobeynikov232b19c2009-08-21 12:41:42 +00003325 case MVT::v8i8: Opc = ARM::VTRNd8; break;
Sjoerd Meijer806f70d2018-08-09 12:45:09 +00003326 case MVT::v4f16:
Anton Korobeynikov232b19c2009-08-21 12:41:42 +00003327 case MVT::v4i16: Opc = ARM::VTRNd16; break;
3328 case MVT::v2f32:
3329 case MVT::v2i32: Opc = ARM::VTRNd32; break;
3330 case MVT::v16i8: Opc = ARM::VTRNq8; break;
Sjoerd Meijer806f70d2018-08-09 12:45:09 +00003331 case MVT::v8f16:
Anton Korobeynikov232b19c2009-08-21 12:41:42 +00003332 case MVT::v8i16: Opc = ARM::VTRNq16; break;
3333 case MVT::v4f32:
3334 case MVT::v4i32: Opc = ARM::VTRNq32; break;
3335 }
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00003336 SDValue Pred = getAL(CurDAG, dl);
Evan Chenga33fc862009-11-21 06:21:52 +00003337 SDValue PredReg = CurDAG->getRegister(0, MVT::i32);
3338 SDValue Ops[] = { N->getOperand(0), N->getOperand(1), Pred, PredReg };
Justin Bogner45571362016-05-12 00:31:09 +00003339 ReplaceNode(N, CurDAG->getMachineNode(Opc, dl, VT, VT, Ops));
3340 return;
Anton Korobeynikovce3ff1b2009-08-21 12:40:50 +00003341 }
Bob Wilsond8a9a042010-06-04 00:04:02 +00003342 case ARMISD::BUILD_VECTOR: {
3343 EVT VecVT = N->getValueType(0);
3344 EVT EltVT = VecVT.getVectorElementType();
3345 unsigned NumElts = VecVT.getVectorNumElements();
Duncan Sands14627772010-11-03 12:17:33 +00003346 if (EltVT == MVT::f64) {
Bob Wilsond8a9a042010-06-04 00:04:02 +00003347 assert(NumElts == 2 && "unexpected type for BUILD_VECTOR");
Justin Bogner45571362016-05-12 00:31:09 +00003348 ReplaceNode(
3349 N, createDRegPairNode(VecVT, N->getOperand(0), N->getOperand(1)));
3350 return;
Bob Wilsond8a9a042010-06-04 00:04:02 +00003351 }
Duncan Sands14627772010-11-03 12:17:33 +00003352 assert(EltVT == MVT::f32 && "unexpected type for BUILD_VECTOR");
Justin Bogner45571362016-05-12 00:31:09 +00003353 if (NumElts == 2) {
3354 ReplaceNode(
3355 N, createSRegPairNode(VecVT, N->getOperand(0), N->getOperand(1)));
3356 return;
3357 }
Bob Wilsond8a9a042010-06-04 00:04:02 +00003358 assert(NumElts == 4 && "unexpected type for BUILD_VECTOR");
Justin Bogner45571362016-05-12 00:31:09 +00003359 ReplaceNode(N,
3360 createQuadSRegsNode(VecVT, N->getOperand(0), N->getOperand(1),
3361 N->getOperand(2), N->getOperand(3)));
3362 return;
Bob Wilsond8a9a042010-06-04 00:04:02 +00003363 }
Bob Wilsone0636a72009-08-26 17:39:53 +00003364
Eli Friedmanf624ec22016-12-16 18:44:08 +00003365 case ARMISD::VLD1DUP: {
3366 static const uint16_t DOpcodes[] = { ARM::VLD1DUPd8, ARM::VLD1DUPd16,
3367 ARM::VLD1DUPd32 };
3368 static const uint16_t QOpcodes[] = { ARM::VLD1DUPq8, ARM::VLD1DUPq16,
3369 ARM::VLD1DUPq32 };
Ivan A. Kosarev72315982018-06-27 13:57:52 +00003370 SelectVLDDup(N, /* IsIntrinsic= */ false, false, 1, DOpcodes, QOpcodes);
Eli Friedmanf624ec22016-12-16 18:44:08 +00003371 return;
3372 }
3373
Bob Wilson2d790df2010-11-28 06:51:26 +00003374 case ARMISD::VLD2DUP: {
Craig Topper01736f82012-05-24 05:17:00 +00003375 static const uint16_t Opcodes[] = { ARM::VLD2DUPd8, ARM::VLD2DUPd16,
3376 ARM::VLD2DUPd32 };
Ivan A. Kosarev72315982018-06-27 13:57:52 +00003377 SelectVLDDup(N, /* IsIntrinsic= */ false, false, 2, Opcodes);
Justin Bogner45571362016-05-12 00:31:09 +00003378 return;
Bob Wilson2d790df2010-11-28 06:51:26 +00003379 }
3380
Bob Wilson77ab1652010-11-29 19:35:29 +00003381 case ARMISD::VLD3DUP: {
Craig Topper01736f82012-05-24 05:17:00 +00003382 static const uint16_t Opcodes[] = { ARM::VLD3DUPd8Pseudo,
3383 ARM::VLD3DUPd16Pseudo,
3384 ARM::VLD3DUPd32Pseudo };
Ivan A. Kosarev72315982018-06-27 13:57:52 +00003385 SelectVLDDup(N, /* IsIntrinsic= */ false, false, 3, Opcodes);
Justin Bogner45571362016-05-12 00:31:09 +00003386 return;
Bob Wilson77ab1652010-11-29 19:35:29 +00003387 }
3388
Bob Wilson431ac4ef2010-11-30 00:00:35 +00003389 case ARMISD::VLD4DUP: {
Craig Topper01736f82012-05-24 05:17:00 +00003390 static const uint16_t Opcodes[] = { ARM::VLD4DUPd8Pseudo,
3391 ARM::VLD4DUPd16Pseudo,
3392 ARM::VLD4DUPd32Pseudo };
Ivan A. Kosarev72315982018-06-27 13:57:52 +00003393 SelectVLDDup(N, /* IsIntrinsic= */ false, false, 4, Opcodes);
Justin Bogner45571362016-05-12 00:31:09 +00003394 return;
Bob Wilson06fce872011-02-07 17:43:21 +00003395 }
3396
Eli Friedmanf624ec22016-12-16 18:44:08 +00003397 case ARMISD::VLD1DUP_UPD: {
3398 static const uint16_t DOpcodes[] = { ARM::VLD1DUPd8wb_fixed,
3399 ARM::VLD1DUPd16wb_fixed,
3400 ARM::VLD1DUPd32wb_fixed };
3401 static const uint16_t QOpcodes[] = { ARM::VLD1DUPq8wb_fixed,
3402 ARM::VLD1DUPq16wb_fixed,
3403 ARM::VLD1DUPq32wb_fixed };
Ivan A. Kosarev72315982018-06-27 13:57:52 +00003404 SelectVLDDup(N, /* IsIntrinsic= */ false, true, 1, DOpcodes, QOpcodes);
Eli Friedmanf624ec22016-12-16 18:44:08 +00003405 return;
3406 }
3407
Bob Wilson06fce872011-02-07 17:43:21 +00003408 case ARMISD::VLD2DUP_UPD: {
Craig Topper01736f82012-05-24 05:17:00 +00003409 static const uint16_t Opcodes[] = { ARM::VLD2DUPd8wb_fixed,
3410 ARM::VLD2DUPd16wb_fixed,
3411 ARM::VLD2DUPd32wb_fixed };
Ivan A. Kosarev72315982018-06-27 13:57:52 +00003412 SelectVLDDup(N, /* IsIntrinsic= */ false, true, 2, Opcodes);
Justin Bogner45571362016-05-12 00:31:09 +00003413 return;
Bob Wilson06fce872011-02-07 17:43:21 +00003414 }
3415
3416 case ARMISD::VLD3DUP_UPD: {
Craig Topper01736f82012-05-24 05:17:00 +00003417 static const uint16_t Opcodes[] = { ARM::VLD3DUPd8Pseudo_UPD,
3418 ARM::VLD3DUPd16Pseudo_UPD,
3419 ARM::VLD3DUPd32Pseudo_UPD };
Ivan A. Kosarev72315982018-06-27 13:57:52 +00003420 SelectVLDDup(N, /* IsIntrinsic= */ false, true, 3, Opcodes);
Justin Bogner45571362016-05-12 00:31:09 +00003421 return;
Bob Wilson06fce872011-02-07 17:43:21 +00003422 }
3423
3424 case ARMISD::VLD4DUP_UPD: {
Craig Topper01736f82012-05-24 05:17:00 +00003425 static const uint16_t Opcodes[] = { ARM::VLD4DUPd8Pseudo_UPD,
3426 ARM::VLD4DUPd16Pseudo_UPD,
3427 ARM::VLD4DUPd32Pseudo_UPD };
Ivan A. Kosarev72315982018-06-27 13:57:52 +00003428 SelectVLDDup(N, /* IsIntrinsic= */ false, true, 4, Opcodes);
Justin Bogner45571362016-05-12 00:31:09 +00003429 return;
Bob Wilson06fce872011-02-07 17:43:21 +00003430 }
3431
3432 case ARMISD::VLD1_UPD: {
Craig Topper01736f82012-05-24 05:17:00 +00003433 static const uint16_t DOpcodes[] = { ARM::VLD1d8wb_fixed,
3434 ARM::VLD1d16wb_fixed,
3435 ARM::VLD1d32wb_fixed,
3436 ARM::VLD1d64wb_fixed };
3437 static const uint16_t QOpcodes[] = { ARM::VLD1q8wb_fixed,
3438 ARM::VLD1q16wb_fixed,
3439 ARM::VLD1q32wb_fixed,
3440 ARM::VLD1q64wb_fixed };
Justin Bogner45571362016-05-12 00:31:09 +00003441 SelectVLD(N, true, 1, DOpcodes, QOpcodes, nullptr);
3442 return;
Bob Wilson06fce872011-02-07 17:43:21 +00003443 }
3444
3445 case ARMISD::VLD2_UPD: {
Craig Topper01736f82012-05-24 05:17:00 +00003446 static const uint16_t DOpcodes[] = { ARM::VLD2d8wb_fixed,
3447 ARM::VLD2d16wb_fixed,
3448 ARM::VLD2d32wb_fixed,
3449 ARM::VLD1q64wb_fixed};
3450 static const uint16_t QOpcodes[] = { ARM::VLD2q8PseudoWB_fixed,
3451 ARM::VLD2q16PseudoWB_fixed,
3452 ARM::VLD2q32PseudoWB_fixed };
Justin Bogner45571362016-05-12 00:31:09 +00003453 SelectVLD(N, true, 2, DOpcodes, QOpcodes, nullptr);
3454 return;
Bob Wilson06fce872011-02-07 17:43:21 +00003455 }
3456
3457 case ARMISD::VLD3_UPD: {
Craig Topper01736f82012-05-24 05:17:00 +00003458 static const uint16_t DOpcodes[] = { ARM::VLD3d8Pseudo_UPD,
3459 ARM::VLD3d16Pseudo_UPD,
3460 ARM::VLD3d32Pseudo_UPD,
Jiangning Liu4df23632014-01-16 09:16:13 +00003461 ARM::VLD1d64TPseudoWB_fixed};
Craig Topper01736f82012-05-24 05:17:00 +00003462 static const uint16_t QOpcodes0[] = { ARM::VLD3q8Pseudo_UPD,
3463 ARM::VLD3q16Pseudo_UPD,
3464 ARM::VLD3q32Pseudo_UPD };
3465 static const uint16_t QOpcodes1[] = { ARM::VLD3q8oddPseudo_UPD,
3466 ARM::VLD3q16oddPseudo_UPD,
3467 ARM::VLD3q32oddPseudo_UPD };
Justin Bogner45571362016-05-12 00:31:09 +00003468 SelectVLD(N, true, 3, DOpcodes, QOpcodes0, QOpcodes1);
3469 return;
Bob Wilson06fce872011-02-07 17:43:21 +00003470 }
3471
3472 case ARMISD::VLD4_UPD: {
Craig Topper01736f82012-05-24 05:17:00 +00003473 static const uint16_t DOpcodes[] = { ARM::VLD4d8Pseudo_UPD,
3474 ARM::VLD4d16Pseudo_UPD,
3475 ARM::VLD4d32Pseudo_UPD,
Jiangning Liu4df23632014-01-16 09:16:13 +00003476 ARM::VLD1d64QPseudoWB_fixed};
Craig Topper01736f82012-05-24 05:17:00 +00003477 static const uint16_t QOpcodes0[] = { ARM::VLD4q8Pseudo_UPD,
3478 ARM::VLD4q16Pseudo_UPD,
3479 ARM::VLD4q32Pseudo_UPD };
3480 static const uint16_t QOpcodes1[] = { ARM::VLD4q8oddPseudo_UPD,
3481 ARM::VLD4q16oddPseudo_UPD,
3482 ARM::VLD4q32oddPseudo_UPD };
Justin Bogner45571362016-05-12 00:31:09 +00003483 SelectVLD(N, true, 4, DOpcodes, QOpcodes0, QOpcodes1);
3484 return;
Bob Wilson06fce872011-02-07 17:43:21 +00003485 }
3486
3487 case ARMISD::VLD2LN_UPD: {
Craig Topper01736f82012-05-24 05:17:00 +00003488 static const uint16_t DOpcodes[] = { ARM::VLD2LNd8Pseudo_UPD,
3489 ARM::VLD2LNd16Pseudo_UPD,
3490 ARM::VLD2LNd32Pseudo_UPD };
3491 static const uint16_t QOpcodes[] = { ARM::VLD2LNq16Pseudo_UPD,
3492 ARM::VLD2LNq32Pseudo_UPD };
Justin Bogner45571362016-05-12 00:31:09 +00003493 SelectVLDSTLane(N, true, true, 2, DOpcodes, QOpcodes);
3494 return;
Bob Wilson06fce872011-02-07 17:43:21 +00003495 }
3496
3497 case ARMISD::VLD3LN_UPD: {
Craig Topper01736f82012-05-24 05:17:00 +00003498 static const uint16_t DOpcodes[] = { ARM::VLD3LNd8Pseudo_UPD,
3499 ARM::VLD3LNd16Pseudo_UPD,
3500 ARM::VLD3LNd32Pseudo_UPD };
3501 static const uint16_t QOpcodes[] = { ARM::VLD3LNq16Pseudo_UPD,
3502 ARM::VLD3LNq32Pseudo_UPD };
Justin Bogner45571362016-05-12 00:31:09 +00003503 SelectVLDSTLane(N, true, true, 3, DOpcodes, QOpcodes);
3504 return;
Bob Wilson06fce872011-02-07 17:43:21 +00003505 }
3506
3507 case ARMISD::VLD4LN_UPD: {
Craig Topper01736f82012-05-24 05:17:00 +00003508 static const uint16_t DOpcodes[] = { ARM::VLD4LNd8Pseudo_UPD,
3509 ARM::VLD4LNd16Pseudo_UPD,
3510 ARM::VLD4LNd32Pseudo_UPD };
3511 static const uint16_t QOpcodes[] = { ARM::VLD4LNq16Pseudo_UPD,
3512 ARM::VLD4LNq32Pseudo_UPD };
Justin Bogner45571362016-05-12 00:31:09 +00003513 SelectVLDSTLane(N, true, true, 4, DOpcodes, QOpcodes);
3514 return;
Bob Wilson06fce872011-02-07 17:43:21 +00003515 }
3516
3517 case ARMISD::VST1_UPD: {
Craig Topper01736f82012-05-24 05:17:00 +00003518 static const uint16_t DOpcodes[] = { ARM::VST1d8wb_fixed,
3519 ARM::VST1d16wb_fixed,
3520 ARM::VST1d32wb_fixed,
3521 ARM::VST1d64wb_fixed };
3522 static const uint16_t QOpcodes[] = { ARM::VST1q8wb_fixed,
3523 ARM::VST1q16wb_fixed,
3524 ARM::VST1q32wb_fixed,
3525 ARM::VST1q64wb_fixed };
Justin Bogner45571362016-05-12 00:31:09 +00003526 SelectVST(N, true, 1, DOpcodes, QOpcodes, nullptr);
3527 return;
Bob Wilson06fce872011-02-07 17:43:21 +00003528 }
3529
3530 case ARMISD::VST2_UPD: {
Craig Topper01736f82012-05-24 05:17:00 +00003531 static const uint16_t DOpcodes[] = { ARM::VST2d8wb_fixed,
3532 ARM::VST2d16wb_fixed,
3533 ARM::VST2d32wb_fixed,
3534 ARM::VST1q64wb_fixed};
3535 static const uint16_t QOpcodes[] = { ARM::VST2q8PseudoWB_fixed,
3536 ARM::VST2q16PseudoWB_fixed,
3537 ARM::VST2q32PseudoWB_fixed };
Justin Bogner45571362016-05-12 00:31:09 +00003538 SelectVST(N, true, 2, DOpcodes, QOpcodes, nullptr);
3539 return;
Bob Wilson06fce872011-02-07 17:43:21 +00003540 }
3541
3542 case ARMISD::VST3_UPD: {
Craig Topper01736f82012-05-24 05:17:00 +00003543 static const uint16_t DOpcodes[] = { ARM::VST3d8Pseudo_UPD,
3544 ARM::VST3d16Pseudo_UPD,
3545 ARM::VST3d32Pseudo_UPD,
3546 ARM::VST1d64TPseudoWB_fixed};
3547 static const uint16_t QOpcodes0[] = { ARM::VST3q8Pseudo_UPD,
3548 ARM::VST3q16Pseudo_UPD,
3549 ARM::VST3q32Pseudo_UPD };
3550 static const uint16_t QOpcodes1[] = { ARM::VST3q8oddPseudo_UPD,
3551 ARM::VST3q16oddPseudo_UPD,
3552 ARM::VST3q32oddPseudo_UPD };
Justin Bogner45571362016-05-12 00:31:09 +00003553 SelectVST(N, true, 3, DOpcodes, QOpcodes0, QOpcodes1);
3554 return;
Bob Wilson06fce872011-02-07 17:43:21 +00003555 }
3556
3557 case ARMISD::VST4_UPD: {
Craig Topper01736f82012-05-24 05:17:00 +00003558 static const uint16_t DOpcodes[] = { ARM::VST4d8Pseudo_UPD,
3559 ARM::VST4d16Pseudo_UPD,
3560 ARM::VST4d32Pseudo_UPD,
3561 ARM::VST1d64QPseudoWB_fixed};
3562 static const uint16_t QOpcodes0[] = { ARM::VST4q8Pseudo_UPD,
3563 ARM::VST4q16Pseudo_UPD,
3564 ARM::VST4q32Pseudo_UPD };
3565 static const uint16_t QOpcodes1[] = { ARM::VST4q8oddPseudo_UPD,
3566 ARM::VST4q16oddPseudo_UPD,
3567 ARM::VST4q32oddPseudo_UPD };
Justin Bogner45571362016-05-12 00:31:09 +00003568 SelectVST(N, true, 4, DOpcodes, QOpcodes0, QOpcodes1);
3569 return;
Bob Wilson06fce872011-02-07 17:43:21 +00003570 }
3571
3572 case ARMISD::VST2LN_UPD: {
Craig Topper01736f82012-05-24 05:17:00 +00003573 static const uint16_t DOpcodes[] = { ARM::VST2LNd8Pseudo_UPD,
3574 ARM::VST2LNd16Pseudo_UPD,
3575 ARM::VST2LNd32Pseudo_UPD };
3576 static const uint16_t QOpcodes[] = { ARM::VST2LNq16Pseudo_UPD,
3577 ARM::VST2LNq32Pseudo_UPD };
Justin Bogner45571362016-05-12 00:31:09 +00003578 SelectVLDSTLane(N, false, true, 2, DOpcodes, QOpcodes);
3579 return;
Bob Wilson06fce872011-02-07 17:43:21 +00003580 }
3581
3582 case ARMISD::VST3LN_UPD: {
Craig Topper01736f82012-05-24 05:17:00 +00003583 static const uint16_t DOpcodes[] = { ARM::VST3LNd8Pseudo_UPD,
3584 ARM::VST3LNd16Pseudo_UPD,
3585 ARM::VST3LNd32Pseudo_UPD };
3586 static const uint16_t QOpcodes[] = { ARM::VST3LNq16Pseudo_UPD,
3587 ARM::VST3LNq32Pseudo_UPD };
Justin Bogner45571362016-05-12 00:31:09 +00003588 SelectVLDSTLane(N, false, true, 3, DOpcodes, QOpcodes);
3589 return;
Bob Wilson06fce872011-02-07 17:43:21 +00003590 }
3591
3592 case ARMISD::VST4LN_UPD: {
Craig Topper01736f82012-05-24 05:17:00 +00003593 static const uint16_t DOpcodes[] = { ARM::VST4LNd8Pseudo_UPD,
3594 ARM::VST4LNd16Pseudo_UPD,
3595 ARM::VST4LNd32Pseudo_UPD };
3596 static const uint16_t QOpcodes[] = { ARM::VST4LNq16Pseudo_UPD,
3597 ARM::VST4LNq32Pseudo_UPD };
Justin Bogner45571362016-05-12 00:31:09 +00003598 SelectVLDSTLane(N, false, true, 4, DOpcodes, QOpcodes);
3599 return;
Bob Wilson431ac4ef2010-11-30 00:00:35 +00003600 }
3601
Bob Wilsone0636a72009-08-26 17:39:53 +00003602 case ISD::INTRINSIC_VOID:
3603 case ISD::INTRINSIC_W_CHAIN: {
3604 unsigned IntNo = cast<ConstantSDNode>(N->getOperand(1))->getZExtValue();
Bob Wilsone0636a72009-08-26 17:39:53 +00003605 switch (IntNo) {
3606 default:
Bob Wilsonf765e1f2010-05-06 16:05:26 +00003607 break;
Bob Wilsone0636a72009-08-26 17:39:53 +00003608
Ranjeet Singh39d2d092016-06-17 00:52:41 +00003609 case Intrinsic::arm_mrrc:
3610 case Intrinsic::arm_mrrc2: {
3611 SDLoc dl(N);
3612 SDValue Chain = N->getOperand(0);
3613 unsigned Opc;
3614
3615 if (Subtarget->isThumb())
3616 Opc = (IntNo == Intrinsic::arm_mrrc ? ARM::t2MRRC : ARM::t2MRRC2);
3617 else
3618 Opc = (IntNo == Intrinsic::arm_mrrc ? ARM::MRRC : ARM::MRRC2);
3619
3620 SmallVector<SDValue, 5> Ops;
3621 Ops.push_back(getI32Imm(cast<ConstantSDNode>(N->getOperand(2))->getZExtValue(), dl)); /* coproc */
3622 Ops.push_back(getI32Imm(cast<ConstantSDNode>(N->getOperand(3))->getZExtValue(), dl)); /* opc */
3623 Ops.push_back(getI32Imm(cast<ConstantSDNode>(N->getOperand(4))->getZExtValue(), dl)); /* CRm */
3624
3625 // The mrrc2 instruction in ARM doesn't allow predicates, the top 4 bits of the encoded
3626 // instruction will always be '1111' but it is possible in assembly language to specify
3627 // AL as a predicate to mrrc2 but it doesn't make any difference to the encoded instruction.
3628 if (Opc != ARM::MRRC2) {
3629 Ops.push_back(getAL(CurDAG, dl));
3630 Ops.push_back(CurDAG->getRegister(0, MVT::i32));
3631 }
3632
3633 Ops.push_back(Chain);
3634
3635 // Writes to two registers.
Benjamin Kramerf690da42016-06-17 14:14:29 +00003636 const EVT RetType[] = {MVT::i32, MVT::i32, MVT::Other};
Ranjeet Singh39d2d092016-06-17 00:52:41 +00003637
3638 ReplaceNode(N, CurDAG->getMachineNode(Opc, dl, RetType, Ops));
3639 return;
3640 }
Tim Northover1ff5f292014-03-26 14:39:31 +00003641 case Intrinsic::arm_ldaexd:
Bruno Cardoso Lopes325110f2011-05-28 04:07:29 +00003642 case Intrinsic::arm_ldrexd: {
Andrew Trickef9de2a2013-05-25 02:42:55 +00003643 SDLoc dl(N);
Bruno Cardoso Lopes325110f2011-05-28 04:07:29 +00003644 SDValue Chain = N->getOperand(0);
Tim Northover1ff5f292014-03-26 14:39:31 +00003645 SDValue MemAddr = N->getOperand(2);
Bradley Smith433c22e2016-01-15 10:26:51 +00003646 bool isThumb = Subtarget->isThumb() && Subtarget->hasV8MBaselineOps();
Tim Northover1ff5f292014-03-26 14:39:31 +00003647
3648 bool IsAcquire = IntNo == Intrinsic::arm_ldaexd;
3649 unsigned NewOpc = isThumb ? (IsAcquire ? ARM::t2LDAEXD : ARM::t2LDREXD)
3650 : (IsAcquire ? ARM::LDAEXD : ARM::LDREXD);
Bruno Cardoso Lopes325110f2011-05-28 04:07:29 +00003651
3652 // arm_ldrexd returns a i64 value in {i32, i32}
3653 std::vector<EVT> ResTys;
Weiming Zhao8f56f882012-11-16 21:55:34 +00003654 if (isThumb) {
3655 ResTys.push_back(MVT::i32);
3656 ResTys.push_back(MVT::i32);
3657 } else
3658 ResTys.push_back(MVT::Untyped);
Bruno Cardoso Lopes325110f2011-05-28 04:07:29 +00003659 ResTys.push_back(MVT::Other);
3660
Weiming Zhao8f56f882012-11-16 21:55:34 +00003661 // Place arguments in the right order.
Benjamin Kramerf690da42016-06-17 14:14:29 +00003662 SDValue Ops[] = {MemAddr, getAL(CurDAG, dl),
3663 CurDAG->getRegister(0, MVT::i32), Chain};
Michael Liaob53d8962013-04-19 22:22:57 +00003664 SDNode *Ld = CurDAG->getMachineNode(NewOpc, dl, ResTys, Ops);
Bruno Cardoso Lopes325110f2011-05-28 04:07:29 +00003665 // Transfer memoperands.
Chandler Carruth66654b72018-08-14 23:30:32 +00003666 MachineMemOperand *MemOp = cast<MemIntrinsicSDNode>(N)->getMemOperand();
3667 CurDAG->setNodeMemRefs(cast<MachineSDNode>(Ld), {MemOp});
Bruno Cardoso Lopes325110f2011-05-28 04:07:29 +00003668
Bruno Cardoso Lopes325110f2011-05-28 04:07:29 +00003669 // Remap uses.
Lang Hamesbe3d9712013-03-09 22:56:09 +00003670 SDValue OutChain = isThumb ? SDValue(Ld, 2) : SDValue(Ld, 1);
Bruno Cardoso Lopes325110f2011-05-28 04:07:29 +00003671 if (!SDValue(N, 0).use_empty()) {
Weiming Zhao8f56f882012-11-16 21:55:34 +00003672 SDValue Result;
3673 if (isThumb)
3674 Result = SDValue(Ld, 0);
3675 else {
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00003676 SDValue SubRegIdx =
3677 CurDAG->getTargetConstant(ARM::gsub_0, dl, MVT::i32);
Weiming Zhao8f56f882012-11-16 21:55:34 +00003678 SDNode *ResNode = CurDAG->getMachineNode(TargetOpcode::EXTRACT_SUBREG,
Lang Hamesbe3d9712013-03-09 22:56:09 +00003679 dl, MVT::i32, SDValue(Ld, 0), SubRegIdx);
Weiming Zhao8f56f882012-11-16 21:55:34 +00003680 Result = SDValue(ResNode,0);
Weiming Zhao8f56f882012-11-16 21:55:34 +00003681 }
Bruno Cardoso Lopes325110f2011-05-28 04:07:29 +00003682 ReplaceUses(SDValue(N, 0), Result);
3683 }
3684 if (!SDValue(N, 1).use_empty()) {
Weiming Zhao8f56f882012-11-16 21:55:34 +00003685 SDValue Result;
3686 if (isThumb)
3687 Result = SDValue(Ld, 1);
3688 else {
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00003689 SDValue SubRegIdx =
3690 CurDAG->getTargetConstant(ARM::gsub_1, dl, MVT::i32);
Weiming Zhao8f56f882012-11-16 21:55:34 +00003691 SDNode *ResNode = CurDAG->getMachineNode(TargetOpcode::EXTRACT_SUBREG,
Lang Hamesbe3d9712013-03-09 22:56:09 +00003692 dl, MVT::i32, SDValue(Ld, 0), SubRegIdx);
Weiming Zhao8f56f882012-11-16 21:55:34 +00003693 Result = SDValue(ResNode,0);
Weiming Zhao8f56f882012-11-16 21:55:34 +00003694 }
Bruno Cardoso Lopes325110f2011-05-28 04:07:29 +00003695 ReplaceUses(SDValue(N, 1), Result);
3696 }
Lang Hamesbe3d9712013-03-09 22:56:09 +00003697 ReplaceUses(SDValue(N, 2), OutChain);
Justin Bognered4f3782016-05-12 00:20:19 +00003698 CurDAG->RemoveDeadNode(N);
Justin Bogner45571362016-05-12 00:31:09 +00003699 return;
Bruno Cardoso Lopes325110f2011-05-28 04:07:29 +00003700 }
Tim Northover1ff5f292014-03-26 14:39:31 +00003701 case Intrinsic::arm_stlexd:
Bruno Cardoso Lopes325110f2011-05-28 04:07:29 +00003702 case Intrinsic::arm_strexd: {
Andrew Trickef9de2a2013-05-25 02:42:55 +00003703 SDLoc dl(N);
Bruno Cardoso Lopes325110f2011-05-28 04:07:29 +00003704 SDValue Chain = N->getOperand(0);
3705 SDValue Val0 = N->getOperand(2);
3706 SDValue Val1 = N->getOperand(3);
3707 SDValue MemAddr = N->getOperand(4);
3708
Bruno Cardoso Lopes325110f2011-05-28 04:07:29 +00003709 // Store exclusive double return a i32 value which is the return status
3710 // of the issued store.
Benjamin Kramer867bfc52015-03-07 17:41:00 +00003711 const EVT ResTys[] = {MVT::i32, MVT::Other};
Bruno Cardoso Lopes325110f2011-05-28 04:07:29 +00003712
Weiming Zhao8f56f882012-11-16 21:55:34 +00003713 bool isThumb = Subtarget->isThumb() && Subtarget->hasThumb2();
3714 // Place arguments in the right order.
Bruno Cardoso Lopes325110f2011-05-28 04:07:29 +00003715 SmallVector<SDValue, 7> Ops;
Weiming Zhao8f56f882012-11-16 21:55:34 +00003716 if (isThumb) {
3717 Ops.push_back(Val0);
3718 Ops.push_back(Val1);
3719 } else
3720 // arm_strexd uses GPRPair.
3721 Ops.push_back(SDValue(createGPRPairNode(MVT::Untyped, Val0, Val1), 0));
Bruno Cardoso Lopes325110f2011-05-28 04:07:29 +00003722 Ops.push_back(MemAddr);
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00003723 Ops.push_back(getAL(CurDAG, dl));
Bruno Cardoso Lopes325110f2011-05-28 04:07:29 +00003724 Ops.push_back(CurDAG->getRegister(0, MVT::i32));
3725 Ops.push_back(Chain);
3726
Tim Northover1ff5f292014-03-26 14:39:31 +00003727 bool IsRelease = IntNo == Intrinsic::arm_stlexd;
3728 unsigned NewOpc = isThumb ? (IsRelease ? ARM::t2STLEXD : ARM::t2STREXD)
3729 : (IsRelease ? ARM::STLEXD : ARM::STREXD);
Bruno Cardoso Lopes325110f2011-05-28 04:07:29 +00003730
Michael Liaob53d8962013-04-19 22:22:57 +00003731 SDNode *St = CurDAG->getMachineNode(NewOpc, dl, ResTys, Ops);
Bruno Cardoso Lopes325110f2011-05-28 04:07:29 +00003732 // Transfer memoperands.
Chandler Carruth66654b72018-08-14 23:30:32 +00003733 MachineMemOperand *MemOp = cast<MemIntrinsicSDNode>(N)->getMemOperand();
3734 CurDAG->setNodeMemRefs(cast<MachineSDNode>(St), {MemOp});
Bruno Cardoso Lopes325110f2011-05-28 04:07:29 +00003735
Justin Bogner45571362016-05-12 00:31:09 +00003736 ReplaceNode(N, St);
3737 return;
Bruno Cardoso Lopes325110f2011-05-28 04:07:29 +00003738 }
3739
Bob Wilson340861d2010-03-23 05:25:43 +00003740 case Intrinsic::arm_neon_vld1: {
Craig Topper01736f82012-05-24 05:17:00 +00003741 static const uint16_t DOpcodes[] = { ARM::VLD1d8, ARM::VLD1d16,
3742 ARM::VLD1d32, ARM::VLD1d64 };
3743 static const uint16_t QOpcodes[] = { ARM::VLD1q8, ARM::VLD1q16,
3744 ARM::VLD1q32, ARM::VLD1q64};
Justin Bogner45571362016-05-12 00:31:09 +00003745 SelectVLD(N, false, 1, DOpcodes, QOpcodes, nullptr);
3746 return;
Bob Wilson340861d2010-03-23 05:25:43 +00003747 }
3748
Ivan A. Kosarev60a991e2018-06-02 16:40:03 +00003749 case Intrinsic::arm_neon_vld1x2: {
3750 static const uint16_t DOpcodes[] = { ARM::VLD1q8, ARM::VLD1q16,
3751 ARM::VLD1q32, ARM::VLD1q64 };
3752 static const uint16_t QOpcodes[] = { ARM::VLD1d8QPseudo,
3753 ARM::VLD1d16QPseudo,
3754 ARM::VLD1d32QPseudo,
3755 ARM::VLD1d64QPseudo };
3756 SelectVLD(N, false, 2, DOpcodes, QOpcodes, nullptr);
3757 return;
3758 }
3759
3760 case Intrinsic::arm_neon_vld1x3: {
3761 static const uint16_t DOpcodes[] = { ARM::VLD1d8TPseudo,
3762 ARM::VLD1d16TPseudo,
3763 ARM::VLD1d32TPseudo,
3764 ARM::VLD1d64TPseudo };
3765 static const uint16_t QOpcodes0[] = { ARM::VLD1q8LowTPseudo_UPD,
3766 ARM::VLD1q16LowTPseudo_UPD,
3767 ARM::VLD1q32LowTPseudo_UPD,
3768 ARM::VLD1q64LowTPseudo_UPD };
3769 static const uint16_t QOpcodes1[] = { ARM::VLD1q8HighTPseudo,
3770 ARM::VLD1q16HighTPseudo,
3771 ARM::VLD1q32HighTPseudo,
3772 ARM::VLD1q64HighTPseudo };
3773 SelectVLD(N, false, 3, DOpcodes, QOpcodes0, QOpcodes1);
3774 return;
3775 }
3776
3777 case Intrinsic::arm_neon_vld1x4: {
3778 static const uint16_t DOpcodes[] = { ARM::VLD1d8QPseudo,
3779 ARM::VLD1d16QPseudo,
3780 ARM::VLD1d32QPseudo,
3781 ARM::VLD1d64QPseudo };
3782 static const uint16_t QOpcodes0[] = { ARM::VLD1q8LowQPseudo_UPD,
3783 ARM::VLD1q16LowQPseudo_UPD,
3784 ARM::VLD1q32LowQPseudo_UPD,
3785 ARM::VLD1q64LowQPseudo_UPD };
3786 static const uint16_t QOpcodes1[] = { ARM::VLD1q8HighQPseudo,
3787 ARM::VLD1q16HighQPseudo,
3788 ARM::VLD1q32HighQPseudo,
3789 ARM::VLD1q64HighQPseudo };
3790 SelectVLD(N, false, 4, DOpcodes, QOpcodes0, QOpcodes1);
3791 return;
3792 }
3793
Bob Wilsone0636a72009-08-26 17:39:53 +00003794 case Intrinsic::arm_neon_vld2: {
Craig Topper01736f82012-05-24 05:17:00 +00003795 static const uint16_t DOpcodes[] = { ARM::VLD2d8, ARM::VLD2d16,
3796 ARM::VLD2d32, ARM::VLD1q64 };
3797 static const uint16_t QOpcodes[] = { ARM::VLD2q8Pseudo, ARM::VLD2q16Pseudo,
3798 ARM::VLD2q32Pseudo };
Justin Bogner45571362016-05-12 00:31:09 +00003799 SelectVLD(N, false, 2, DOpcodes, QOpcodes, nullptr);
3800 return;
Bob Wilsone0636a72009-08-26 17:39:53 +00003801 }
3802
3803 case Intrinsic::arm_neon_vld3: {
Craig Topper01736f82012-05-24 05:17:00 +00003804 static const uint16_t DOpcodes[] = { ARM::VLD3d8Pseudo,
3805 ARM::VLD3d16Pseudo,
3806 ARM::VLD3d32Pseudo,
3807 ARM::VLD1d64TPseudo };
3808 static const uint16_t QOpcodes0[] = { ARM::VLD3q8Pseudo_UPD,
3809 ARM::VLD3q16Pseudo_UPD,
3810 ARM::VLD3q32Pseudo_UPD };
3811 static const uint16_t QOpcodes1[] = { ARM::VLD3q8oddPseudo,
3812 ARM::VLD3q16oddPseudo,
3813 ARM::VLD3q32oddPseudo };
Justin Bogner45571362016-05-12 00:31:09 +00003814 SelectVLD(N, false, 3, DOpcodes, QOpcodes0, QOpcodes1);
3815 return;
Bob Wilsone0636a72009-08-26 17:39:53 +00003816 }
3817
3818 case Intrinsic::arm_neon_vld4: {
Craig Topper01736f82012-05-24 05:17:00 +00003819 static const uint16_t DOpcodes[] = { ARM::VLD4d8Pseudo,
3820 ARM::VLD4d16Pseudo,
3821 ARM::VLD4d32Pseudo,
3822 ARM::VLD1d64QPseudo };
3823 static const uint16_t QOpcodes0[] = { ARM::VLD4q8Pseudo_UPD,
3824 ARM::VLD4q16Pseudo_UPD,
3825 ARM::VLD4q32Pseudo_UPD };
3826 static const uint16_t QOpcodes1[] = { ARM::VLD4q8oddPseudo,
3827 ARM::VLD4q16oddPseudo,
3828 ARM::VLD4q32oddPseudo };
Justin Bogner45571362016-05-12 00:31:09 +00003829 SelectVLD(N, false, 4, DOpcodes, QOpcodes0, QOpcodes1);
3830 return;
Bob Wilsone0636a72009-08-26 17:39:53 +00003831 }
3832
Ivan A. Kosarev72315982018-06-27 13:57:52 +00003833 case Intrinsic::arm_neon_vld2dup: {
3834 static const uint16_t DOpcodes[] = { ARM::VLD2DUPd8, ARM::VLD2DUPd16,
3835 ARM::VLD2DUPd32, ARM::VLD1q64 };
3836 static const uint16_t QOpcodes0[] = { ARM::VLD2DUPq8EvenPseudo,
3837 ARM::VLD2DUPq16EvenPseudo,
3838 ARM::VLD2DUPq32EvenPseudo };
3839 static const uint16_t QOpcodes1[] = { ARM::VLD2DUPq8OddPseudo,
3840 ARM::VLD2DUPq16OddPseudo,
3841 ARM::VLD2DUPq32OddPseudo };
3842 SelectVLDDup(N, /* IsIntrinsic= */ true, false, 2,
3843 DOpcodes, QOpcodes0, QOpcodes1);
3844 return;
3845 }
3846
3847 case Intrinsic::arm_neon_vld3dup: {
3848 static const uint16_t DOpcodes[] = { ARM::VLD3DUPd8Pseudo,
3849 ARM::VLD3DUPd16Pseudo,
3850 ARM::VLD3DUPd32Pseudo,
3851 ARM::VLD1d64TPseudo };
3852 static const uint16_t QOpcodes0[] = { ARM::VLD3DUPq8EvenPseudo,
3853 ARM::VLD3DUPq16EvenPseudo,
3854 ARM::VLD3DUPq32EvenPseudo };
3855 static const uint16_t QOpcodes1[] = { ARM::VLD3DUPq8OddPseudo,
3856 ARM::VLD3DUPq16OddPseudo,
3857 ARM::VLD3DUPq32OddPseudo };
3858 SelectVLDDup(N, /* IsIntrinsic= */ true, false, 3,
3859 DOpcodes, QOpcodes0, QOpcodes1);
3860 return;
3861 }
3862
3863 case Intrinsic::arm_neon_vld4dup: {
3864 static const uint16_t DOpcodes[] = { ARM::VLD4DUPd8Pseudo,
3865 ARM::VLD4DUPd16Pseudo,
3866 ARM::VLD4DUPd32Pseudo,
3867 ARM::VLD1d64QPseudo };
3868 static const uint16_t QOpcodes0[] = { ARM::VLD4DUPq8EvenPseudo,
3869 ARM::VLD4DUPq16EvenPseudo,
3870 ARM::VLD4DUPq32EvenPseudo };
3871 static const uint16_t QOpcodes1[] = { ARM::VLD4DUPq8OddPseudo,
3872 ARM::VLD4DUPq16OddPseudo,
3873 ARM::VLD4DUPq32OddPseudo };
3874 SelectVLDDup(N, /* IsIntrinsic= */ true, false, 4,
3875 DOpcodes, QOpcodes0, QOpcodes1);
3876 return;
3877 }
3878
Bob Wilsonda9817c2009-09-01 04:26:28 +00003879 case Intrinsic::arm_neon_vld2lane: {
Craig Topper01736f82012-05-24 05:17:00 +00003880 static const uint16_t DOpcodes[] = { ARM::VLD2LNd8Pseudo,
3881 ARM::VLD2LNd16Pseudo,
3882 ARM::VLD2LNd32Pseudo };
3883 static const uint16_t QOpcodes[] = { ARM::VLD2LNq16Pseudo,
3884 ARM::VLD2LNq32Pseudo };
Justin Bogner45571362016-05-12 00:31:09 +00003885 SelectVLDSTLane(N, true, false, 2, DOpcodes, QOpcodes);
3886 return;
Bob Wilsonda9817c2009-09-01 04:26:28 +00003887 }
3888
3889 case Intrinsic::arm_neon_vld3lane: {
Craig Topper01736f82012-05-24 05:17:00 +00003890 static const uint16_t DOpcodes[] = { ARM::VLD3LNd8Pseudo,
3891 ARM::VLD3LNd16Pseudo,
3892 ARM::VLD3LNd32Pseudo };
3893 static const uint16_t QOpcodes[] = { ARM::VLD3LNq16Pseudo,
3894 ARM::VLD3LNq32Pseudo };
Justin Bogner45571362016-05-12 00:31:09 +00003895 SelectVLDSTLane(N, true, false, 3, DOpcodes, QOpcodes);
3896 return;
Bob Wilsonda9817c2009-09-01 04:26:28 +00003897 }
3898
3899 case Intrinsic::arm_neon_vld4lane: {
Craig Topper01736f82012-05-24 05:17:00 +00003900 static const uint16_t DOpcodes[] = { ARM::VLD4LNd8Pseudo,
3901 ARM::VLD4LNd16Pseudo,
3902 ARM::VLD4LNd32Pseudo };
3903 static const uint16_t QOpcodes[] = { ARM::VLD4LNq16Pseudo,
3904 ARM::VLD4LNq32Pseudo };
Justin Bogner45571362016-05-12 00:31:09 +00003905 SelectVLDSTLane(N, true, false, 4, DOpcodes, QOpcodes);
3906 return;
Bob Wilsonda9817c2009-09-01 04:26:28 +00003907 }
3908
Bob Wilsoncc0a2a72010-03-23 06:20:33 +00003909 case Intrinsic::arm_neon_vst1: {
Craig Topper01736f82012-05-24 05:17:00 +00003910 static const uint16_t DOpcodes[] = { ARM::VST1d8, ARM::VST1d16,
3911 ARM::VST1d32, ARM::VST1d64 };
3912 static const uint16_t QOpcodes[] = { ARM::VST1q8, ARM::VST1q16,
3913 ARM::VST1q32, ARM::VST1q64 };
Justin Bogner45571362016-05-12 00:31:09 +00003914 SelectVST(N, false, 1, DOpcodes, QOpcodes, nullptr);
3915 return;
Bob Wilsoncc0a2a72010-03-23 06:20:33 +00003916 }
3917
Ivan A. Kosarev847daa12018-06-10 09:27:27 +00003918 case Intrinsic::arm_neon_vst1x2: {
3919 static const uint16_t DOpcodes[] = { ARM::VST1q8, ARM::VST1q16,
3920 ARM::VST1q32, ARM::VST1q64 };
3921 static const uint16_t QOpcodes[] = { ARM::VST1d8QPseudo,
3922 ARM::VST1d16QPseudo,
3923 ARM::VST1d32QPseudo,
3924 ARM::VST1d64QPseudo };
3925 SelectVST(N, false, 2, DOpcodes, QOpcodes, nullptr);
3926 return;
3927 }
3928
3929 case Intrinsic::arm_neon_vst1x3: {
3930 static const uint16_t DOpcodes[] = { ARM::VST1d8TPseudo,
3931 ARM::VST1d16TPseudo,
3932 ARM::VST1d32TPseudo,
3933 ARM::VST1d64TPseudo };
3934 static const uint16_t QOpcodes0[] = { ARM::VST1q8LowTPseudo_UPD,
3935 ARM::VST1q16LowTPseudo_UPD,
3936 ARM::VST1q32LowTPseudo_UPD,
3937 ARM::VST1q64LowTPseudo_UPD };
3938 static const uint16_t QOpcodes1[] = { ARM::VST1q8HighTPseudo,
3939 ARM::VST1q16HighTPseudo,
3940 ARM::VST1q32HighTPseudo,
3941 ARM::VST1q64HighTPseudo };
3942 SelectVST(N, false, 3, DOpcodes, QOpcodes0, QOpcodes1);
3943 return;
3944 }
3945
3946 case Intrinsic::arm_neon_vst1x4: {
3947 static const uint16_t DOpcodes[] = { ARM::VST1d8QPseudo,
3948 ARM::VST1d16QPseudo,
3949 ARM::VST1d32QPseudo,
3950 ARM::VST1d64QPseudo };
3951 static const uint16_t QOpcodes0[] = { ARM::VST1q8LowQPseudo_UPD,
3952 ARM::VST1q16LowQPseudo_UPD,
3953 ARM::VST1q32LowQPseudo_UPD,
3954 ARM::VST1q64LowQPseudo_UPD };
3955 static const uint16_t QOpcodes1[] = { ARM::VST1q8HighQPseudo,
3956 ARM::VST1q16HighQPseudo,
3957 ARM::VST1q32HighQPseudo,
3958 ARM::VST1q64HighQPseudo };
3959 SelectVST(N, false, 4, DOpcodes, QOpcodes0, QOpcodes1);
3960 return;
3961 }
3962
Bob Wilsone0636a72009-08-26 17:39:53 +00003963 case Intrinsic::arm_neon_vst2: {
Craig Topper01736f82012-05-24 05:17:00 +00003964 static const uint16_t DOpcodes[] = { ARM::VST2d8, ARM::VST2d16,
3965 ARM::VST2d32, ARM::VST1q64 };
Benjamin Kramerf690da42016-06-17 14:14:29 +00003966 static const uint16_t QOpcodes[] = { ARM::VST2q8Pseudo, ARM::VST2q16Pseudo,
3967 ARM::VST2q32Pseudo };
Justin Bogner45571362016-05-12 00:31:09 +00003968 SelectVST(N, false, 2, DOpcodes, QOpcodes, nullptr);
3969 return;
Bob Wilsone0636a72009-08-26 17:39:53 +00003970 }
3971
3972 case Intrinsic::arm_neon_vst3: {
Craig Topper01736f82012-05-24 05:17:00 +00003973 static const uint16_t DOpcodes[] = { ARM::VST3d8Pseudo,
3974 ARM::VST3d16Pseudo,
3975 ARM::VST3d32Pseudo,
3976 ARM::VST1d64TPseudo };
3977 static const uint16_t QOpcodes0[] = { ARM::VST3q8Pseudo_UPD,
3978 ARM::VST3q16Pseudo_UPD,
3979 ARM::VST3q32Pseudo_UPD };
3980 static const uint16_t QOpcodes1[] = { ARM::VST3q8oddPseudo,
3981 ARM::VST3q16oddPseudo,
3982 ARM::VST3q32oddPseudo };
Justin Bogner45571362016-05-12 00:31:09 +00003983 SelectVST(N, false, 3, DOpcodes, QOpcodes0, QOpcodes1);
3984 return;
Bob Wilsone0636a72009-08-26 17:39:53 +00003985 }
3986
3987 case Intrinsic::arm_neon_vst4: {
Craig Topper01736f82012-05-24 05:17:00 +00003988 static const uint16_t DOpcodes[] = { ARM::VST4d8Pseudo,
3989 ARM::VST4d16Pseudo,
3990 ARM::VST4d32Pseudo,
3991 ARM::VST1d64QPseudo };
3992 static const uint16_t QOpcodes0[] = { ARM::VST4q8Pseudo_UPD,
3993 ARM::VST4q16Pseudo_UPD,
3994 ARM::VST4q32Pseudo_UPD };
3995 static const uint16_t QOpcodes1[] = { ARM::VST4q8oddPseudo,
3996 ARM::VST4q16oddPseudo,
3997 ARM::VST4q32oddPseudo };
Justin Bogner45571362016-05-12 00:31:09 +00003998 SelectVST(N, false, 4, DOpcodes, QOpcodes0, QOpcodes1);
3999 return;
Bob Wilsone0636a72009-08-26 17:39:53 +00004000 }
Bob Wilsond7797752009-09-01 18:51:56 +00004001
4002 case Intrinsic::arm_neon_vst2lane: {
Craig Topper01736f82012-05-24 05:17:00 +00004003 static const uint16_t DOpcodes[] = { ARM::VST2LNd8Pseudo,
4004 ARM::VST2LNd16Pseudo,
4005 ARM::VST2LNd32Pseudo };
4006 static const uint16_t QOpcodes[] = { ARM::VST2LNq16Pseudo,
4007 ARM::VST2LNq32Pseudo };
Justin Bogner45571362016-05-12 00:31:09 +00004008 SelectVLDSTLane(N, false, false, 2, DOpcodes, QOpcodes);
4009 return;
Bob Wilsond7797752009-09-01 18:51:56 +00004010 }
4011
4012 case Intrinsic::arm_neon_vst3lane: {
Craig Topper01736f82012-05-24 05:17:00 +00004013 static const uint16_t DOpcodes[] = { ARM::VST3LNd8Pseudo,
4014 ARM::VST3LNd16Pseudo,
4015 ARM::VST3LNd32Pseudo };
4016 static const uint16_t QOpcodes[] = { ARM::VST3LNq16Pseudo,
4017 ARM::VST3LNq32Pseudo };
Justin Bogner45571362016-05-12 00:31:09 +00004018 SelectVLDSTLane(N, false, false, 3, DOpcodes, QOpcodes);
4019 return;
Bob Wilsond7797752009-09-01 18:51:56 +00004020 }
4021
4022 case Intrinsic::arm_neon_vst4lane: {
Craig Topper01736f82012-05-24 05:17:00 +00004023 static const uint16_t DOpcodes[] = { ARM::VST4LNd8Pseudo,
4024 ARM::VST4LNd16Pseudo,
4025 ARM::VST4LNd32Pseudo };
4026 static const uint16_t QOpcodes[] = { ARM::VST4LNq16Pseudo,
4027 ARM::VST4LNq32Pseudo };
Justin Bogner45571362016-05-12 00:31:09 +00004028 SelectVLDSTLane(N, false, false, 4, DOpcodes, QOpcodes);
4029 return;
Bob Wilsond7797752009-09-01 18:51:56 +00004030 }
Bob Wilsone0636a72009-08-26 17:39:53 +00004031 }
Bob Wilsonf765e1f2010-05-06 16:05:26 +00004032 break;
Bob Wilsone0636a72009-08-26 17:39:53 +00004033 }
Evan Chengd85631e2010-05-05 18:28:36 +00004034
Tim Northoverb629c772016-04-18 21:48:55 +00004035 case ISD::ATOMIC_CMP_SWAP:
Justin Bogner45571362016-05-12 00:31:09 +00004036 SelectCMP_SWAP(N);
4037 return;
Evan Chengd85631e2010-05-05 18:28:36 +00004038 }
Evan Chengd5021732008-12-10 21:54:21 +00004039
Justin Bogner45571362016-05-12 00:31:09 +00004040 SelectCode(N);
Evan Cheng10043e22007-01-19 07:51:42 +00004041}
Rafael Espindolaffdc24b2006-05-14 22:18:28 +00004042
Luke Cheeseman85fd06d2015-06-01 12:02:47 +00004043// Inspect a register string of the form
4044// cp<coprocessor>:<opc1>:c<CRn>:c<CRm>:<opc2> (32bit) or
4045// cp<coprocessor>:<opc1>:c<CRm> (64bit) inspect the fields of the string
4046// and obtain the integer operands from them, adding these operands to the
4047// provided vector.
4048static void getIntOperandsFromRegisterString(StringRef RegString,
Benjamin Kramerbdc49562016-06-12 15:39:02 +00004049 SelectionDAG *CurDAG,
4050 const SDLoc &DL,
4051 std::vector<SDValue> &Ops) {
Luke Cheeseman85fd06d2015-06-01 12:02:47 +00004052 SmallVector<StringRef, 5> Fields;
Chandler Carruthe4405e92015-09-10 06:12:31 +00004053 RegString.split(Fields, ':');
Luke Cheeseman85fd06d2015-06-01 12:02:47 +00004054
4055 if (Fields.size() > 1) {
4056 bool AllIntFields = true;
4057
4058 for (StringRef Field : Fields) {
4059 // Need to trim out leading 'cp' characters and get the integer field.
4060 unsigned IntField;
4061 AllIntFields &= !Field.trim("CPcp").getAsInteger(10, IntField);
4062 Ops.push_back(CurDAG->getTargetConstant(IntField, DL, MVT::i32));
4063 }
4064
4065 assert(AllIntFields &&
4066 "Unexpected non-integer value in special register string.");
4067 }
4068}
4069
4070// Maps a Banked Register string to its mask value. The mask value returned is
4071// for use in the MRSbanked / MSRbanked instruction nodes as the Banked Register
4072// mask operand, which expresses which register is to be used, e.g. r8, and in
4073// which mode it is to be used, e.g. usr. Returns -1 to signify that the string
4074// was invalid.
4075static inline int getBankedRegisterMask(StringRef RegString) {
Javed Absar054d1ae2017-08-03 01:24:12 +00004076 auto TheReg = ARMBankedReg::lookupBankedRegByName(RegString.lower());
4077 if (!TheReg)
4078 return -1;
4079 return TheReg->Encoding;
Luke Cheeseman85fd06d2015-06-01 12:02:47 +00004080}
4081
Luke Cheeseman85fd06d2015-06-01 12:02:47 +00004082// The flags here are common to those allowed for apsr in the A class cores and
4083// those allowed for the special registers in the M class cores. Returns a
4084// value representing which flags were present, -1 if invalid.
John Brawne60f4e42017-02-10 17:41:08 +00004085static inline int getMClassFlagsMask(StringRef Flags) {
Luke Cheeseman85fd06d2015-06-01 12:02:47 +00004086 return StringSwitch<int>(Flags)
John Brawne60f4e42017-02-10 17:41:08 +00004087 .Case("", 0x2) // no flags means nzcvq for psr registers, and 0x2 is
4088 // correct when flags are not permitted
Luke Cheeseman85fd06d2015-06-01 12:02:47 +00004089 .Case("g", 0x1)
4090 .Case("nzcvq", 0x2)
4091 .Case("nzcvqg", 0x3)
4092 .Default(-1);
4093}
4094
Javed Absar2cb0c952017-07-19 12:57:16 +00004095// Maps MClass special registers string to its value for use in the
4096// t2MRS_M/t2MSR_M instruction nodes as the SYSm value operand.
4097// Returns -1 to signify that the string was invalid.
4098static int getMClassRegisterMask(StringRef Reg, const ARMSubtarget *Subtarget) {
4099 auto TheReg = ARMSysReg::lookupMClassSysRegByName(Reg);
4100 const FeatureBitset &FeatureBits = Subtarget->getFeatureBits();
4101 if (!TheReg || !TheReg->hasRequiredFeatures(FeatureBits))
Luke Cheeseman85fd06d2015-06-01 12:02:47 +00004102 return -1;
Javed Absar2cb0c952017-07-19 12:57:16 +00004103 return (int)(TheReg->Encoding & 0xFFF); // SYSm value
Luke Cheeseman85fd06d2015-06-01 12:02:47 +00004104}
4105
4106static int getARClassRegisterMask(StringRef Reg, StringRef Flags) {
4107 // The mask operand contains the special register (R Bit) in bit 4, whether
4108 // the register is spsr (R bit is 1) or one of cpsr/apsr (R bit is 0), and
4109 // bits 3-0 contains the fields to be accessed in the special register, set by
4110 // the flags provided with the register.
4111 int Mask = 0;
4112 if (Reg == "apsr") {
4113 // The flags permitted for apsr are the same flags that are allowed in
4114 // M class registers. We get the flag value and then shift the flags into
4115 // the correct place to combine with the mask.
John Brawne60f4e42017-02-10 17:41:08 +00004116 Mask = getMClassFlagsMask(Flags);
Luke Cheeseman85fd06d2015-06-01 12:02:47 +00004117 if (Mask == -1)
4118 return -1;
4119 return Mask << 2;
4120 }
4121
4122 if (Reg != "cpsr" && Reg != "spsr") {
4123 return -1;
4124 }
4125
4126 // This is the same as if the flags were "fc"
4127 if (Flags.empty() || Flags == "all")
4128 return Mask | 0x9;
4129
4130 // Inspect the supplied flags string and set the bits in the mask for
4131 // the relevant and valid flags allowed for cpsr and spsr.
4132 for (char Flag : Flags) {
4133 int FlagVal;
4134 switch (Flag) {
4135 case 'c':
4136 FlagVal = 0x1;
4137 break;
4138 case 'x':
4139 FlagVal = 0x2;
4140 break;
4141 case 's':
4142 FlagVal = 0x4;
4143 break;
4144 case 'f':
4145 FlagVal = 0x8;
4146 break;
4147 default:
4148 FlagVal = 0;
4149 }
4150
4151 // This avoids allowing strings where the same flag bit appears twice.
4152 if (!FlagVal || (Mask & FlagVal))
4153 return -1;
4154 Mask |= FlagVal;
4155 }
4156
4157 // If the register is spsr then we need to set the R bit.
4158 if (Reg == "spsr")
4159 Mask |= 0x10;
4160
4161 return Mask;
4162}
4163
4164// Lower the read_register intrinsic to ARM specific DAG nodes
4165// using the supplied metadata string to select the instruction node to use
4166// and the registers/masks to construct as operands for the node.
Justin Bogner45571362016-05-12 00:31:09 +00004167bool ARMDAGToDAGISel::tryReadRegister(SDNode *N){
Luke Cheeseman85fd06d2015-06-01 12:02:47 +00004168 const MDNodeSDNode *MD = dyn_cast<MDNodeSDNode>(N->getOperand(1));
4169 const MDString *RegString = dyn_cast<MDString>(MD->getMD()->getOperand(0));
4170 bool IsThumb2 = Subtarget->isThumb2();
4171 SDLoc DL(N);
4172
4173 std::vector<SDValue> Ops;
4174 getIntOperandsFromRegisterString(RegString->getString(), CurDAG, DL, Ops);
4175
4176 if (!Ops.empty()) {
4177 // If the special register string was constructed of fields (as defined
4178 // in the ACLE) then need to lower to MRC node (32 bit) or
4179 // MRRC node(64 bit), we can make the distinction based on the number of
4180 // operands we have.
4181 unsigned Opcode;
4182 SmallVector<EVT, 3> ResTypes;
4183 if (Ops.size() == 5){
4184 Opcode = IsThumb2 ? ARM::t2MRC : ARM::MRC;
4185 ResTypes.append({ MVT::i32, MVT::Other });
4186 } else {
4187 assert(Ops.size() == 3 &&
4188 "Invalid number of fields in special register string.");
4189 Opcode = IsThumb2 ? ARM::t2MRRC : ARM::MRRC;
4190 ResTypes.append({ MVT::i32, MVT::i32, MVT::Other });
4191 }
4192
4193 Ops.push_back(getAL(CurDAG, DL));
4194 Ops.push_back(CurDAG->getRegister(0, MVT::i32));
4195 Ops.push_back(N->getOperand(0));
Justin Bogner45571362016-05-12 00:31:09 +00004196 ReplaceNode(N, CurDAG->getMachineNode(Opcode, DL, ResTypes, Ops));
4197 return true;
Luke Cheeseman85fd06d2015-06-01 12:02:47 +00004198 }
4199
4200 std::string SpecialReg = RegString->getString().lower();
4201
4202 int BankedReg = getBankedRegisterMask(SpecialReg);
4203 if (BankedReg != -1) {
4204 Ops = { CurDAG->getTargetConstant(BankedReg, DL, MVT::i32),
4205 getAL(CurDAG, DL), CurDAG->getRegister(0, MVT::i32),
4206 N->getOperand(0) };
Justin Bogner45571362016-05-12 00:31:09 +00004207 ReplaceNode(
4208 N, CurDAG->getMachineNode(IsThumb2 ? ARM::t2MRSbanked : ARM::MRSbanked,
4209 DL, MVT::i32, MVT::Other, Ops));
4210 return true;
Luke Cheeseman85fd06d2015-06-01 12:02:47 +00004211 }
4212
4213 // The VFP registers are read by creating SelectionDAG nodes with opcodes
4214 // corresponding to the register that is being read from. So we switch on the
4215 // string to find which opcode we need to use.
4216 unsigned Opcode = StringSwitch<unsigned>(SpecialReg)
4217 .Case("fpscr", ARM::VMRS)
4218 .Case("fpexc", ARM::VMRS_FPEXC)
4219 .Case("fpsid", ARM::VMRS_FPSID)
4220 .Case("mvfr0", ARM::VMRS_MVFR0)
4221 .Case("mvfr1", ARM::VMRS_MVFR1)
4222 .Case("mvfr2", ARM::VMRS_MVFR2)
4223 .Case("fpinst", ARM::VMRS_FPINST)
4224 .Case("fpinst2", ARM::VMRS_FPINST2)
4225 .Default(0);
4226
4227 // If an opcode was found then we can lower the read to a VFP instruction.
4228 if (Opcode) {
Simon Tatham760df472019-05-28 16:13:20 +00004229 if (!Subtarget->hasVFP2Base())
Justin Bogner45571362016-05-12 00:31:09 +00004230 return false;
Simon Tatham760df472019-05-28 16:13:20 +00004231 if (Opcode == ARM::VMRS_MVFR2 && !Subtarget->hasFPARMv8Base())
Justin Bogner45571362016-05-12 00:31:09 +00004232 return false;
Luke Cheeseman85fd06d2015-06-01 12:02:47 +00004233
4234 Ops = { getAL(CurDAG, DL), CurDAG->getRegister(0, MVT::i32),
4235 N->getOperand(0) };
Justin Bogner45571362016-05-12 00:31:09 +00004236 ReplaceNode(N,
4237 CurDAG->getMachineNode(Opcode, DL, MVT::i32, MVT::Other, Ops));
4238 return true;
Luke Cheeseman85fd06d2015-06-01 12:02:47 +00004239 }
4240
4241 // If the target is M Class then need to validate that the register string
4242 // is an acceptable value, so check that a mask can be constructed from the
4243 // string.
4244 if (Subtarget->isMClass()) {
Javed Absar2cb0c952017-07-19 12:57:16 +00004245 int SYSmValue = getMClassRegisterMask(SpecialReg, Subtarget);
Luke Cheeseman85fd06d2015-06-01 12:02:47 +00004246 if (SYSmValue == -1)
Justin Bogner45571362016-05-12 00:31:09 +00004247 return false;
Luke Cheeseman85fd06d2015-06-01 12:02:47 +00004248
4249 SDValue Ops[] = { CurDAG->getTargetConstant(SYSmValue, DL, MVT::i32),
4250 getAL(CurDAG, DL), CurDAG->getRegister(0, MVT::i32),
4251 N->getOperand(0) };
Justin Bogner45571362016-05-12 00:31:09 +00004252 ReplaceNode(
4253 N, CurDAG->getMachineNode(ARM::t2MRS_M, DL, MVT::i32, MVT::Other, Ops));
4254 return true;
Luke Cheeseman85fd06d2015-06-01 12:02:47 +00004255 }
4256
4257 // Here we know the target is not M Class so we need to check if it is one
4258 // of the remaining possible values which are apsr, cpsr or spsr.
4259 if (SpecialReg == "apsr" || SpecialReg == "cpsr") {
4260 Ops = { getAL(CurDAG, DL), CurDAG->getRegister(0, MVT::i32),
4261 N->getOperand(0) };
Justin Bogner45571362016-05-12 00:31:09 +00004262 ReplaceNode(N, CurDAG->getMachineNode(IsThumb2 ? ARM::t2MRS_AR : ARM::MRS,
4263 DL, MVT::i32, MVT::Other, Ops));
4264 return true;
Luke Cheeseman85fd06d2015-06-01 12:02:47 +00004265 }
4266
4267 if (SpecialReg == "spsr") {
4268 Ops = { getAL(CurDAG, DL), CurDAG->getRegister(0, MVT::i32),
4269 N->getOperand(0) };
Justin Bogner45571362016-05-12 00:31:09 +00004270 ReplaceNode(
4271 N, CurDAG->getMachineNode(IsThumb2 ? ARM::t2MRSsys_AR : ARM::MRSsys, DL,
4272 MVT::i32, MVT::Other, Ops));
4273 return true;
Luke Cheeseman85fd06d2015-06-01 12:02:47 +00004274 }
4275
Justin Bogner45571362016-05-12 00:31:09 +00004276 return false;
Luke Cheeseman85fd06d2015-06-01 12:02:47 +00004277}
4278
4279// Lower the write_register intrinsic to ARM specific DAG nodes
4280// using the supplied metadata string to select the instruction node to use
4281// and the registers/masks to use in the nodes
Justin Bogner45571362016-05-12 00:31:09 +00004282bool ARMDAGToDAGISel::tryWriteRegister(SDNode *N){
Luke Cheeseman85fd06d2015-06-01 12:02:47 +00004283 const MDNodeSDNode *MD = dyn_cast<MDNodeSDNode>(N->getOperand(1));
4284 const MDString *RegString = dyn_cast<MDString>(MD->getMD()->getOperand(0));
4285 bool IsThumb2 = Subtarget->isThumb2();
4286 SDLoc DL(N);
4287
4288 std::vector<SDValue> Ops;
4289 getIntOperandsFromRegisterString(RegString->getString(), CurDAG, DL, Ops);
4290
4291 if (!Ops.empty()) {
4292 // If the special register string was constructed of fields (as defined
4293 // in the ACLE) then need to lower to MCR node (32 bit) or
4294 // MCRR node(64 bit), we can make the distinction based on the number of
4295 // operands we have.
4296 unsigned Opcode;
4297 if (Ops.size() == 5) {
4298 Opcode = IsThumb2 ? ARM::t2MCR : ARM::MCR;
4299 Ops.insert(Ops.begin()+2, N->getOperand(2));
4300 } else {
4301 assert(Ops.size() == 3 &&
4302 "Invalid number of fields in special register string.");
4303 Opcode = IsThumb2 ? ARM::t2MCRR : ARM::MCRR;
4304 SDValue WriteValue[] = { N->getOperand(2), N->getOperand(3) };
4305 Ops.insert(Ops.begin()+2, WriteValue, WriteValue+2);
4306 }
4307
4308 Ops.push_back(getAL(CurDAG, DL));
4309 Ops.push_back(CurDAG->getRegister(0, MVT::i32));
4310 Ops.push_back(N->getOperand(0));
4311
Justin Bogner45571362016-05-12 00:31:09 +00004312 ReplaceNode(N, CurDAG->getMachineNode(Opcode, DL, MVT::Other, Ops));
4313 return true;
Luke Cheeseman85fd06d2015-06-01 12:02:47 +00004314 }
4315
4316 std::string SpecialReg = RegString->getString().lower();
4317 int BankedReg = getBankedRegisterMask(SpecialReg);
4318 if (BankedReg != -1) {
4319 Ops = { CurDAG->getTargetConstant(BankedReg, DL, MVT::i32), N->getOperand(2),
4320 getAL(CurDAG, DL), CurDAG->getRegister(0, MVT::i32),
4321 N->getOperand(0) };
Justin Bogner45571362016-05-12 00:31:09 +00004322 ReplaceNode(
4323 N, CurDAG->getMachineNode(IsThumb2 ? ARM::t2MSRbanked : ARM::MSRbanked,
4324 DL, MVT::Other, Ops));
4325 return true;
Luke Cheeseman85fd06d2015-06-01 12:02:47 +00004326 }
4327
4328 // The VFP registers are written to by creating SelectionDAG nodes with
4329 // opcodes corresponding to the register that is being written. So we switch
4330 // on the string to find which opcode we need to use.
4331 unsigned Opcode = StringSwitch<unsigned>(SpecialReg)
4332 .Case("fpscr", ARM::VMSR)
4333 .Case("fpexc", ARM::VMSR_FPEXC)
4334 .Case("fpsid", ARM::VMSR_FPSID)
4335 .Case("fpinst", ARM::VMSR_FPINST)
4336 .Case("fpinst2", ARM::VMSR_FPINST2)
4337 .Default(0);
4338
4339 if (Opcode) {
Simon Tatham760df472019-05-28 16:13:20 +00004340 if (!Subtarget->hasVFP2Base())
Justin Bogner45571362016-05-12 00:31:09 +00004341 return false;
Luke Cheeseman85fd06d2015-06-01 12:02:47 +00004342 Ops = { N->getOperand(2), getAL(CurDAG, DL),
4343 CurDAG->getRegister(0, MVT::i32), N->getOperand(0) };
Justin Bogner45571362016-05-12 00:31:09 +00004344 ReplaceNode(N, CurDAG->getMachineNode(Opcode, DL, MVT::Other, Ops));
4345 return true;
Luke Cheeseman85fd06d2015-06-01 12:02:47 +00004346 }
4347
Bradley Smithf277c8a2016-01-25 11:25:36 +00004348 std::pair<StringRef, StringRef> Fields;
4349 Fields = StringRef(SpecialReg).rsplit('_');
4350 std::string Reg = Fields.first.str();
4351 StringRef Flags = Fields.second;
Luke Cheeseman85fd06d2015-06-01 12:02:47 +00004352
4353 // If the target was M Class then need to validate the special register value
4354 // and retrieve the mask for use in the instruction node.
4355 if (Subtarget->isMClass()) {
Javed Absar2cb0c952017-07-19 12:57:16 +00004356 int SYSmValue = getMClassRegisterMask(SpecialReg, Subtarget);
Luke Cheeseman85fd06d2015-06-01 12:02:47 +00004357 if (SYSmValue == -1)
Justin Bogner45571362016-05-12 00:31:09 +00004358 return false;
Luke Cheeseman85fd06d2015-06-01 12:02:47 +00004359
4360 SDValue Ops[] = { CurDAG->getTargetConstant(SYSmValue, DL, MVT::i32),
4361 N->getOperand(2), getAL(CurDAG, DL),
4362 CurDAG->getRegister(0, MVT::i32), N->getOperand(0) };
Justin Bogner45571362016-05-12 00:31:09 +00004363 ReplaceNode(N, CurDAG->getMachineNode(ARM::t2MSR_M, DL, MVT::Other, Ops));
4364 return true;
Luke Cheeseman85fd06d2015-06-01 12:02:47 +00004365 }
4366
4367 // We then check to see if a valid mask can be constructed for one of the
4368 // register string values permitted for the A and R class cores. These values
4369 // are apsr, spsr and cpsr; these are also valid on older cores.
4370 int Mask = getARClassRegisterMask(Reg, Flags);
4371 if (Mask != -1) {
4372 Ops = { CurDAG->getTargetConstant(Mask, DL, MVT::i32), N->getOperand(2),
4373 getAL(CurDAG, DL), CurDAG->getRegister(0, MVT::i32),
4374 N->getOperand(0) };
Justin Bogner45571362016-05-12 00:31:09 +00004375 ReplaceNode(N, CurDAG->getMachineNode(IsThumb2 ? ARM::t2MSR_AR : ARM::MSR,
4376 DL, MVT::Other, Ops));
4377 return true;
Luke Cheeseman85fd06d2015-06-01 12:02:47 +00004378 }
4379
Justin Bogner45571362016-05-12 00:31:09 +00004380 return false;
Luke Cheeseman85fd06d2015-06-01 12:02:47 +00004381}
4382
Justin Bogner45571362016-05-12 00:31:09 +00004383bool ARMDAGToDAGISel::tryInlineAsm(SDNode *N){
Weiming Zhaoc5987002013-02-14 18:10:21 +00004384 std::vector<SDValue> AsmNodeOperands;
4385 unsigned Flag, Kind;
4386 bool Changed = false;
4387 unsigned NumOps = N->getNumOperands();
4388
Weiming Zhaoc5987002013-02-14 18:10:21 +00004389 // Normally, i64 data is bounded to two arbitrary GRPs for "%r" constraint.
4390 // However, some instrstions (e.g. ldrexd/strexd in ARM mode) require
4391 // (even/even+1) GPRs and use %n and %Hn to refer to the individual regs
4392 // respectively. Since there is no constraint to explicitly specify a
Weiming Zhaoa3d87a12013-06-28 17:26:02 +00004393 // reg pair, we use GPRPair reg class for "%r" for 64-bit data. For Thumb,
4394 // the 64-bit data may be referred by H, Q, R modifiers, so we still pack
4395 // them into a GPRPair.
Weiming Zhaoc5987002013-02-14 18:10:21 +00004396
Andrew Trickef9de2a2013-05-25 02:42:55 +00004397 SDLoc dl(N);
Craig Topper062a2ba2014-04-25 05:30:21 +00004398 SDValue Glue = N->getGluedNode() ? N->getOperand(NumOps-1)
4399 : SDValue(nullptr,0);
Weiming Zhaoc5987002013-02-14 18:10:21 +00004400
Weiming Zhaoa3d87a12013-06-28 17:26:02 +00004401 SmallVector<bool, 8> OpChanged;
Weiming Zhaoc5987002013-02-14 18:10:21 +00004402 // Glue node will be appended late.
Weiming Zhaoa3d87a12013-06-28 17:26:02 +00004403 for(unsigned i = 0, e = N->getGluedNode() ? NumOps - 1 : NumOps; i < e; ++i) {
Weiming Zhaoc5987002013-02-14 18:10:21 +00004404 SDValue op = N->getOperand(i);
4405 AsmNodeOperands.push_back(op);
4406
4407 if (i < InlineAsm::Op_FirstOperand)
4408 continue;
4409
4410 if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(N->getOperand(i))) {
4411 Flag = C->getZExtValue();
4412 Kind = InlineAsm::getKind(Flag);
4413 }
4414 else
4415 continue;
4416
Joey Gouly392cdad2013-07-08 19:52:51 +00004417 // Immediate operands to inline asm in the SelectionDAG are modeled with
4418 // two operands. The first is a constant of value InlineAsm::Kind_Imm, and
4419 // the second is a constant with the value of the immediate. If we get here
4420 // and we have a Kind_Imm, skip the next operand, and continue.
Joey Gouly606f3fb2013-07-05 10:19:40 +00004421 if (Kind == InlineAsm::Kind_Imm) {
4422 SDValue op = N->getOperand(++i);
4423 AsmNodeOperands.push_back(op);
4424 continue;
4425 }
4426
Weiming Zhaoa3d87a12013-06-28 17:26:02 +00004427 unsigned NumRegs = InlineAsm::getNumOperandRegisters(Flag);
4428 if (NumRegs)
4429 OpChanged.push_back(false);
4430
4431 unsigned DefIdx = 0;
4432 bool IsTiedToChangedOp = false;
4433 // If it's a use that is tied with a previous def, it has no
4434 // reg class constraint.
4435 if (Changed && InlineAsm::isUseOperandTiedToDef(Flag, DefIdx))
4436 IsTiedToChangedOp = OpChanged[DefIdx];
4437
Diana Picusf345d402016-07-20 09:48:24 +00004438 // Memory operands to inline asm in the SelectionDAG are modeled with two
4439 // operands: a constant of value InlineAsm::Kind_Mem followed by the input
4440 // operand. If we get here and we have a Kind_Mem, skip the next operand (so
4441 // it doesn't get misinterpreted), and continue. We do this here because
4442 // it's important to update the OpChanged array correctly before moving on.
4443 if (Kind == InlineAsm::Kind_Mem) {
4444 SDValue op = N->getOperand(++i);
4445 AsmNodeOperands.push_back(op);
4446 continue;
4447 }
4448
Weiming Zhaoc5987002013-02-14 18:10:21 +00004449 if (Kind != InlineAsm::Kind_RegUse && Kind != InlineAsm::Kind_RegDef
4450 && Kind != InlineAsm::Kind_RegDefEarlyClobber)
4451 continue;
4452
Weiming Zhaoc5987002013-02-14 18:10:21 +00004453 unsigned RC;
4454 bool HasRC = InlineAsm::hasRegClassConstraint(Flag, RC);
Weiming Zhaoa3d87a12013-06-28 17:26:02 +00004455 if ((!IsTiedToChangedOp && (!HasRC || RC != ARM::GPRRegClassID))
4456 || NumRegs != 2)
Weiming Zhaoc5987002013-02-14 18:10:21 +00004457 continue;
4458
Weiming Zhaoa3d87a12013-06-28 17:26:02 +00004459 assert((i+2 < NumOps) && "Invalid number of operands in inline asm");
Weiming Zhaoc5987002013-02-14 18:10:21 +00004460 SDValue V0 = N->getOperand(i+1);
4461 SDValue V1 = N->getOperand(i+2);
4462 unsigned Reg0 = cast<RegisterSDNode>(V0)->getReg();
4463 unsigned Reg1 = cast<RegisterSDNode>(V1)->getReg();
4464 SDValue PairedReg;
4465 MachineRegisterInfo &MRI = MF->getRegInfo();
4466
4467 if (Kind == InlineAsm::Kind_RegDef ||
4468 Kind == InlineAsm::Kind_RegDefEarlyClobber) {
4469 // Replace the two GPRs with 1 GPRPair and copy values from GPRPair to
4470 // the original GPRs.
4471
Daniel Sanders0c476112019-08-15 19:22:08 +00004472 Register GPVR = MRI.createVirtualRegister(&ARM::GPRPairRegClass);
Weiming Zhaoc5987002013-02-14 18:10:21 +00004473 PairedReg = CurDAG->getRegister(GPVR, MVT::Untyped);
4474 SDValue Chain = SDValue(N,0);
4475
4476 SDNode *GU = N->getGluedUser();
4477 SDValue RegCopy = CurDAG->getCopyFromReg(Chain, dl, GPVR, MVT::Untyped,
4478 Chain.getValue(1));
4479
4480 // Extract values from a GPRPair reg and copy to the original GPR reg.
4481 SDValue Sub0 = CurDAG->getTargetExtractSubreg(ARM::gsub_0, dl, MVT::i32,
4482 RegCopy);
4483 SDValue Sub1 = CurDAG->getTargetExtractSubreg(ARM::gsub_1, dl, MVT::i32,
4484 RegCopy);
4485 SDValue T0 = CurDAG->getCopyToReg(Sub0, dl, Reg0, Sub0,
4486 RegCopy.getValue(1));
4487 SDValue T1 = CurDAG->getCopyToReg(Sub1, dl, Reg1, Sub1, T0.getValue(1));
4488
4489 // Update the original glue user.
4490 std::vector<SDValue> Ops(GU->op_begin(), GU->op_end()-1);
4491 Ops.push_back(T1.getValue(1));
Craig Topper8c0b4d02014-04-28 05:57:50 +00004492 CurDAG->UpdateNodeOperands(GU, Ops);
Weiming Zhaoc5987002013-02-14 18:10:21 +00004493 }
4494 else {
4495 // For Kind == InlineAsm::Kind_RegUse, we first copy two GPRs into a
4496 // GPRPair and then pass the GPRPair to the inline asm.
4497 SDValue Chain = AsmNodeOperands[InlineAsm::Op_InputChain];
4498
4499 // As REG_SEQ doesn't take RegisterSDNode, we copy them first.
4500 SDValue T0 = CurDAG->getCopyFromReg(Chain, dl, Reg0, MVT::i32,
4501 Chain.getValue(1));
4502 SDValue T1 = CurDAG->getCopyFromReg(Chain, dl, Reg1, MVT::i32,
4503 T0.getValue(1));
4504 SDValue Pair = SDValue(createGPRPairNode(MVT::Untyped, T0, T1), 0);
4505
4506 // Copy REG_SEQ into a GPRPair-typed VR and replace the original two
4507 // i32 VRs of inline asm with it.
Daniel Sanders0c476112019-08-15 19:22:08 +00004508 Register GPVR = MRI.createVirtualRegister(&ARM::GPRPairRegClass);
Weiming Zhaoc5987002013-02-14 18:10:21 +00004509 PairedReg = CurDAG->getRegister(GPVR, MVT::Untyped);
4510 Chain = CurDAG->getCopyToReg(T1, dl, GPVR, Pair, T1.getValue(1));
4511
4512 AsmNodeOperands[InlineAsm::Op_InputChain] = Chain;
4513 Glue = Chain.getValue(1);
4514 }
4515
4516 Changed = true;
4517
4518 if(PairedReg.getNode()) {
Weiming Zhaoa3d87a12013-06-28 17:26:02 +00004519 OpChanged[OpChanged.size() -1 ] = true;
Weiming Zhaoc5987002013-02-14 18:10:21 +00004520 Flag = InlineAsm::getFlagWord(Kind, 1 /* RegNum*/);
Tim Northover55349a22013-08-18 18:06:03 +00004521 if (IsTiedToChangedOp)
4522 Flag = InlineAsm::getFlagWordForMatchingOp(Flag, DefIdx);
4523 else
4524 Flag = InlineAsm::getFlagWordForRegClass(Flag, ARM::GPRPairRegClassID);
Weiming Zhaoc5987002013-02-14 18:10:21 +00004525 // Replace the current flag.
4526 AsmNodeOperands[AsmNodeOperands.size() -1] = CurDAG->getTargetConstant(
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +00004527 Flag, dl, MVT::i32);
Weiming Zhaoc5987002013-02-14 18:10:21 +00004528 // Add the new register node and skip the original two GPRs.
4529 AsmNodeOperands.push_back(PairedReg);
4530 // Skip the next two GPRs.
4531 i += 2;
4532 }
4533 }
4534
Weiming Zhaoa3d87a12013-06-28 17:26:02 +00004535 if (Glue.getNode())
4536 AsmNodeOperands.push_back(Glue);
Weiming Zhaoc5987002013-02-14 18:10:21 +00004537 if (!Changed)
Justin Bogner45571362016-05-12 00:31:09 +00004538 return false;
Weiming Zhaoc5987002013-02-14 18:10:21 +00004539
Craig Topper784929d2019-02-08 20:48:56 +00004540 SDValue New = CurDAG->getNode(N->getOpcode(), SDLoc(N),
Craig Topper48d114b2014-04-26 18:35:24 +00004541 CurDAG->getVTList(MVT::Other, MVT::Glue), AsmNodeOperands);
Weiming Zhaoc5987002013-02-14 18:10:21 +00004542 New->setNodeId(-1);
Justin Bogner45571362016-05-12 00:31:09 +00004543 ReplaceNode(N, New.getNode());
4544 return true;
Weiming Zhaoc5987002013-02-14 18:10:21 +00004545}
4546
4547
Bob Wilsona2c462b2009-05-19 05:53:42 +00004548bool ARMDAGToDAGISel::
Daniel Sanders60f1db02015-03-13 12:45:09 +00004549SelectInlineAsmMemoryOperand(const SDValue &Op, unsigned ConstraintID,
Bob Wilsona2c462b2009-05-19 05:53:42 +00004550 std::vector<SDValue> &OutOps) {
Daniel Sanders1f58ef72015-06-03 12:33:56 +00004551 switch(ConstraintID) {
4552 default:
4553 llvm_unreachable("Unexpected asm memory constraint");
Daniel Sanders43a79bf2015-06-03 14:17:18 +00004554 case InlineAsm::Constraint_i:
4555 // FIXME: It seems strange that 'i' is needed here since it's supposed to
4556 // be an immediate and not a memory constraint.
Justin Bognerb03fd122016-08-17 05:10:15 +00004557 LLVM_FALLTHROUGH;
Daniel Sanders1f58ef72015-06-03 12:33:56 +00004558 case InlineAsm::Constraint_m:
James Molloy72222f52015-10-26 10:04:52 +00004559 case InlineAsm::Constraint_o:
Daniel Sanders1f58ef72015-06-03 12:33:56 +00004560 case InlineAsm::Constraint_Q:
4561 case InlineAsm::Constraint_Um:
4562 case InlineAsm::Constraint_Un:
4563 case InlineAsm::Constraint_Uq:
4564 case InlineAsm::Constraint_Us:
4565 case InlineAsm::Constraint_Ut:
4566 case InlineAsm::Constraint_Uv:
4567 case InlineAsm::Constraint_Uy:
4568 // Require the address to be in a register. That is safe for all ARM
4569 // variants and it is hard to do anything much smarter without knowing
4570 // how the operand is used.
4571 OutOps.push_back(Op);
4572 return false;
4573 }
4574 return true;
Bob Wilsona2c462b2009-05-19 05:53:42 +00004575}
4576
Rafael Espindolaffdc24b2006-05-14 22:18:28 +00004577/// createARMISelDag - This pass converts a legalized DAG into a
4578/// ARM-specific DAG, ready for instruction scheduling.
4579///
Bob Wilson2dd957f2009-09-28 14:30:20 +00004580FunctionPass *llvm::createARMISelDag(ARMBaseTargetMachine &TM,
4581 CodeGenOpt::Level OptLevel) {
4582 return new ARMDAGToDAGISel(TM, OptLevel);
Rafael Espindolaffdc24b2006-05-14 22:18:28 +00004583}