blob: 3a284622db3ab38a05223926da39bf3c99d622c0 [file] [log] [blame]
Jia Liub22310f2012-02-18 12:03:15 +00001//===-- HexagonISelDAGToDAG.cpp - A dag to dag inst selector for Hexagon --===//
Tony Linthicum1213a7a2011-12-12 21:14:40 +00002//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file defines an instruction selector for the Hexagon target.
11//
12//===----------------------------------------------------------------------===//
13
Chandler Carruthed0881b2012-12-03 16:50:05 +000014#include "Hexagon.h"
Tony Linthicum1213a7a2011-12-12 21:14:40 +000015#include "HexagonISelLowering.h"
Krzysztof Parzyszek4fa2a9f2015-04-22 16:43:53 +000016#include "HexagonMachineFunctionInfo.h"
Tony Linthicum1213a7a2011-12-12 21:14:40 +000017#include "HexagonTargetMachine.h"
Krzysztof Parzyszek4fa2a9f2015-04-22 16:43:53 +000018#include "llvm/CodeGen/FunctionLoweringInfo.h"
19#include "llvm/CodeGen/MachineInstrBuilder.h"
Jyotsna Vermad9225242013-02-13 21:38:46 +000020#include "llvm/CodeGen/SelectionDAGISel.h"
Chandler Carruth8a8cd2b2014-01-07 11:48:04 +000021#include "llvm/IR/Intrinsics.h"
Jyotsna Vermad9225242013-02-13 21:38:46 +000022#include "llvm/Support/CommandLine.h"
Tony Linthicum1213a7a2011-12-12 21:14:40 +000023#include "llvm/Support/Debug.h"
Tony Linthicum1213a7a2011-12-12 21:14:40 +000024using namespace llvm;
25
Chandler Carruth84e68b22014-04-22 02:41:26 +000026#define DEBUG_TYPE "hexagon-isel"
27
Jyotsna Vermad9225242013-02-13 21:38:46 +000028static
Krzysztof Parzyszek0006e1a2016-07-29 15:15:35 +000029cl::opt<bool>
30EnableAddressRebalancing("isel-rebalance-addr", cl::Hidden, cl::init(true),
31 cl::desc("Rebalance address calculation trees to improve "
32 "instruction selection"));
33
34// Rebalance only if this allows e.g. combining a GA with an offset or
35// factoring out a shift.
36static
37cl::opt<bool>
38RebalanceOnlyForOptimizations("rebalance-only-opt", cl::Hidden, cl::init(false),
39 cl::desc("Rebalance address tree only if this allows optimizations"));
40
41static
42cl::opt<bool>
43RebalanceOnlyImbalancedTrees("rebalance-only-imbal", cl::Hidden,
44 cl::init(false), cl::desc("Rebalance address tree only if it is imbalanced"));
45
Tony Linthicum1213a7a2011-12-12 21:14:40 +000046//===----------------------------------------------------------------------===//
47// Instruction Selector Implementation
48//===----------------------------------------------------------------------===//
49
50//===--------------------------------------------------------------------===//
51/// HexagonDAGToDAGISel - Hexagon specific code to select Hexagon machine
52/// instructions for SelectionDAG operations.
53///
54namespace {
55class HexagonDAGToDAGISel : public SelectionDAGISel {
Eric Christopher23a7d1e2015-03-21 03:12:59 +000056 const HexagonSubtarget *HST;
Krzysztof Parzyszek08ff8882015-11-26 18:38:27 +000057 const HexagonInstrInfo *HII;
58 const HexagonRegisterInfo *HRI;
Tony Linthicum1213a7a2011-12-12 21:14:40 +000059public:
Krzysztof Parzyszeka29622a2015-03-12 16:44:50 +000060 explicit HexagonDAGToDAGISel(HexagonTargetMachine &tm,
Jyotsna Vermad9225242013-02-13 21:38:46 +000061 CodeGenOpt::Level OptLevel)
Krzysztof Parzyszek0006e1a2016-07-29 15:15:35 +000062 : SelectionDAGISel(tm, OptLevel), HST(nullptr), HII(nullptr),
Chandler Carruth9ac86ef2016-06-03 10:13:31 +000063 HRI(nullptr) {}
Eric Christopher23a7d1e2015-03-21 03:12:59 +000064
65 bool runOnMachineFunction(MachineFunction &MF) override {
66 // Reset the subtarget each time through.
67 HST = &MF.getSubtarget<HexagonSubtarget>();
Krzysztof Parzyszek08ff8882015-11-26 18:38:27 +000068 HII = HST->getInstrInfo();
69 HRI = HST->getRegisterInfo();
Eric Christopher23a7d1e2015-03-21 03:12:59 +000070 SelectionDAGISel::runOnMachineFunction(MF);
71 return true;
72 }
73
Krzysztof Parzyszek317d42c2016-08-01 20:31:50 +000074 void PreprocessISelDAG() override;
75 void EmitFunctionEntryCode() override;
Tony Linthicum1213a7a2011-12-12 21:14:40 +000076
Justin Bognerec37a022016-05-12 21:46:18 +000077 void Select(SDNode *N) override;
Tony Linthicum1213a7a2011-12-12 21:14:40 +000078
79 // Complex Pattern Selectors.
Colin LeMahieu987b0942015-02-04 20:38:01 +000080 inline bool SelectAddrGA(SDValue &N, SDValue &R);
Colin LeMahieu51491352015-02-04 22:36:28 +000081 inline bool SelectAddrGP(SDValue &N, SDValue &R);
Colin LeMahieu987b0942015-02-04 20:38:01 +000082 bool SelectGlobalAddress(SDValue &N, SDValue &R, bool UseGP);
Colin LeMahieuc7522f32015-01-14 23:07:36 +000083 bool SelectAddrFI(SDValue &N, SDValue &R);
84
Mehdi Amini117296c2016-10-01 02:56:57 +000085 StringRef getPassName() const override {
Tony Linthicum1213a7a2011-12-12 21:14:40 +000086 return "Hexagon DAG->DAG Pattern Instruction Selection";
87 }
88
Krzysztof Parzyszek7d5b4db2016-02-12 17:01:51 +000089 // Generate a machine instruction node corresponding to the circ/brev
90 // load intrinsic.
91 MachineSDNode *LoadInstrForLoadIntrinsic(SDNode *IntN);
92 // Given the circ/brev load intrinsic and the already generated machine
93 // instruction, generate the appropriate store (that is a part of the
94 // intrinsic's functionality).
95 SDNode *StoreInstrForLoadIntrinsic(MachineSDNode *LoadN, SDNode *IntN);
96
Justin Bognerec37a022016-05-12 21:46:18 +000097 void SelectFrameIndex(SDNode *N);
Tony Linthicum1213a7a2011-12-12 21:14:40 +000098 /// SelectInlineAsmMemoryOperand - Implement addressing mode selection for
99 /// inline asm expressions.
Craig Topper906c2cd2014-04-29 07:58:16 +0000100 bool SelectInlineAsmMemoryOperand(const SDValue &Op,
Daniel Sanders60f1db02015-03-13 12:45:09 +0000101 unsigned ConstraintID,
Craig Topper906c2cd2014-04-29 07:58:16 +0000102 std::vector<SDValue> &OutOps) override;
Justin Bognerec37a022016-05-12 21:46:18 +0000103 bool tryLoadOfLoadIntrinsic(LoadSDNode *N);
104 void SelectLoad(SDNode *N);
Benjamin Kramerbdc49562016-06-12 15:39:02 +0000105 void SelectIndexedLoad(LoadSDNode *LD, const SDLoc &dl);
Benjamin Kramerbdc49562016-06-12 15:39:02 +0000106 void SelectIndexedStore(StoreSDNode *ST, const SDLoc &dl);
Justin Bognerec37a022016-05-12 21:46:18 +0000107 void SelectStore(SDNode *N);
108 void SelectSHL(SDNode *N);
109 void SelectMul(SDNode *N);
110 void SelectZeroExtend(SDNode *N);
111 void SelectIntrinsicWChain(SDNode *N);
112 void SelectIntrinsicWOChain(SDNode *N);
113 void SelectConstant(SDNode *N);
114 void SelectConstantFP(SDNode *N);
Krzysztof Parzyszek5da24e52016-06-27 15:08:22 +0000115 void SelectBitcast(SDNode *N);
Tony Linthicum1213a7a2011-12-12 21:14:40 +0000116
Krzysztof Parzyszeka29622a2015-03-12 16:44:50 +0000117 // Include the pieces autogenerated from the target description.
118 #include "HexagonGenDAGISel.inc"
Colin LeMahieu0ee02fc2015-01-19 20:31:18 +0000119
120private:
Krzysztof Parzyszeka29622a2015-03-12 16:44:50 +0000121 bool isValueExtension(const SDValue &Val, unsigned FromBits, SDValue &Src);
Krzysztof Parzyszekb16a4e52016-11-14 20:53:09 +0000122 bool isOrEquivalentToAdd(const SDNode *N) const;
Krzysztof Parzyszek2d65ea72016-03-28 15:43:03 +0000123 bool isAlignedMemNode(const MemSDNode *N) const;
Krzysztof Parzyszek2839b292016-11-05 21:44:50 +0000124 bool isPositiveHalfWord(const SDNode *N) const;
Krzysztof Parzyszek0006e1a2016-07-29 15:15:35 +0000125
126 SmallDenseMap<SDNode *,int> RootWeights;
127 SmallDenseMap<SDNode *,int> RootHeights;
128 SmallDenseMap<const Value *,int> GAUsesInFunction;
129 int getWeight(SDNode *N);
130 int getHeight(SDNode *N);
131 SDValue getMultiplierForSHL(SDNode *N);
132 SDValue factorOutPowerOf2(SDValue V, unsigned Power);
133 unsigned getUsesInFunction(const Value *V);
134 SDValue balanceSubTree(SDNode *N, bool Factorize = false);
135 void rebalanceAddressTrees();
Krzysztof Parzyszeka29622a2015-03-12 16:44:50 +0000136}; // end HexagonDAGToDAGISel
Tony Linthicum1213a7a2011-12-12 21:14:40 +0000137} // end anonymous namespace
138
139
140/// createHexagonISelDag - This pass converts a legalized DAG into a
141/// Hexagon-specific DAG, ready for instruction scheduling.
142///
Krzysztof Parzyszeka29622a2015-03-12 16:44:50 +0000143namespace llvm {
144FunctionPass *createHexagonISelDag(HexagonTargetMachine &TM,
145 CodeGenOpt::Level OptLevel) {
Jyotsna Vermad9225242013-02-13 21:38:46 +0000146 return new HexagonDAGToDAGISel(TM, OptLevel);
Tony Linthicum1213a7a2011-12-12 21:14:40 +0000147}
Krzysztof Parzyszeka29622a2015-03-12 16:44:50 +0000148}
Tony Linthicum1213a7a2011-12-12 21:14:40 +0000149
Tony Linthicum1213a7a2011-12-12 21:14:40 +0000150// Intrinsics that return a a predicate.
Krzysztof Parzyszek08ff8882015-11-26 18:38:27 +0000151static bool doesIntrinsicReturnPredicate(unsigned ID) {
Tony Linthicum1213a7a2011-12-12 21:14:40 +0000152 switch (ID) {
153 default:
Krzysztof Parzyszek08ff8882015-11-26 18:38:27 +0000154 return false;
Tony Linthicum1213a7a2011-12-12 21:14:40 +0000155 case Intrinsic::hexagon_C2_cmpeq:
156 case Intrinsic::hexagon_C2_cmpgt:
157 case Intrinsic::hexagon_C2_cmpgtu:
158 case Intrinsic::hexagon_C2_cmpgtup:
159 case Intrinsic::hexagon_C2_cmpgtp:
160 case Intrinsic::hexagon_C2_cmpeqp:
161 case Intrinsic::hexagon_C2_bitsset:
162 case Intrinsic::hexagon_C2_bitsclr:
163 case Intrinsic::hexagon_C2_cmpeqi:
164 case Intrinsic::hexagon_C2_cmpgti:
165 case Intrinsic::hexagon_C2_cmpgtui:
166 case Intrinsic::hexagon_C2_cmpgei:
167 case Intrinsic::hexagon_C2_cmpgeui:
168 case Intrinsic::hexagon_C2_cmplt:
169 case Intrinsic::hexagon_C2_cmpltu:
170 case Intrinsic::hexagon_C2_bitsclri:
171 case Intrinsic::hexagon_C2_and:
172 case Intrinsic::hexagon_C2_or:
173 case Intrinsic::hexagon_C2_xor:
174 case Intrinsic::hexagon_C2_andn:
175 case Intrinsic::hexagon_C2_not:
176 case Intrinsic::hexagon_C2_orn:
177 case Intrinsic::hexagon_C2_pxfer_map:
178 case Intrinsic::hexagon_C2_any8:
179 case Intrinsic::hexagon_C2_all8:
180 case Intrinsic::hexagon_A2_vcmpbeq:
181 case Intrinsic::hexagon_A2_vcmpbgtu:
182 case Intrinsic::hexagon_A2_vcmpheq:
183 case Intrinsic::hexagon_A2_vcmphgt:
184 case Intrinsic::hexagon_A2_vcmphgtu:
185 case Intrinsic::hexagon_A2_vcmpweq:
186 case Intrinsic::hexagon_A2_vcmpwgt:
187 case Intrinsic::hexagon_A2_vcmpwgtu:
188 case Intrinsic::hexagon_C2_tfrrp:
189 case Intrinsic::hexagon_S2_tstbit_i:
190 case Intrinsic::hexagon_S2_tstbit_r:
Krzysztof Parzyszek08ff8882015-11-26 18:38:27 +0000191 return true;
Tony Linthicum1213a7a2011-12-12 21:14:40 +0000192 }
193}
194
Benjamin Kramerbdc49562016-06-12 15:39:02 +0000195void HexagonDAGToDAGISel::SelectIndexedLoad(LoadSDNode *LD, const SDLoc &dl) {
Tony Linthicum1213a7a2011-12-12 21:14:40 +0000196 SDValue Chain = LD->getChain();
197 SDValue Base = LD->getBasePtr();
198 SDValue Offset = LD->getOffset();
Krzysztof Parzyszek709a6262016-06-24 21:27:17 +0000199 int32_t Inc = cast<ConstantSDNode>(Offset.getNode())->getSExtValue();
Tony Linthicum1213a7a2011-12-12 21:14:40 +0000200 EVT LoadedVT = LD->getMemoryVT();
201 unsigned Opcode = 0;
202
Krzysztof Parzyszeka29622a2015-03-12 16:44:50 +0000203 // Check for zero extended loads. Treat any-extend loads as zero extended
204 // loads.
205 ISD::LoadExtType ExtType = LD->getExtensionType();
206 bool IsZeroExt = (ExtType == ISD::ZEXTLOAD || ExtType == ISD::EXTLOAD);
Krzysztof Parzyszek709a6262016-06-24 21:27:17 +0000207 bool IsValidInc = HII->isValidAutoIncImm(LoadedVT, Inc);
Tony Linthicum1213a7a2011-12-12 21:14:40 +0000208
Krzysztof Parzyszek709a6262016-06-24 21:27:17 +0000209 assert(LoadedVT.isSimple());
210 switch (LoadedVT.getSimpleVT().SimpleTy) {
211 case MVT::i8:
212 if (IsZeroExt)
213 Opcode = IsValidInc ? Hexagon::L2_loadrub_pi : Hexagon::L2_loadrub_io;
Tony Linthicum1213a7a2011-12-12 21:14:40 +0000214 else
Krzysztof Parzyszek709a6262016-06-24 21:27:17 +0000215 Opcode = IsValidInc ? Hexagon::L2_loadrb_pi : Hexagon::L2_loadrb_io;
216 break;
217 case MVT::i16:
218 if (IsZeroExt)
219 Opcode = IsValidInc ? Hexagon::L2_loadruh_pi : Hexagon::L2_loadruh_io;
Tony Linthicum1213a7a2011-12-12 21:14:40 +0000220 else
Krzysztof Parzyszek709a6262016-06-24 21:27:17 +0000221 Opcode = IsValidInc ? Hexagon::L2_loadrh_pi : Hexagon::L2_loadrh_io;
222 break;
223 case MVT::i32:
224 Opcode = IsValidInc ? Hexagon::L2_loadri_pi : Hexagon::L2_loadri_io;
225 break;
226 case MVT::i64:
227 Opcode = IsValidInc ? Hexagon::L2_loadrd_pi : Hexagon::L2_loadrd_io;
228 break;
229 // 64B
230 case MVT::v64i8:
231 case MVT::v32i16:
232 case MVT::v16i32:
233 case MVT::v8i64:
234 if (isAlignedMemNode(LD))
235 Opcode = IsValidInc ? Hexagon::V6_vL32b_pi : Hexagon::V6_vL32b_ai;
Tony Linthicum1213a7a2011-12-12 21:14:40 +0000236 else
Krzysztof Parzyszek709a6262016-06-24 21:27:17 +0000237 Opcode = IsValidInc ? Hexagon::V6_vL32Ub_pi : Hexagon::V6_vL32Ub_ai;
238 break;
Krzysztof Parzyszek08ff8882015-11-26 18:38:27 +0000239 // 128B
Krzysztof Parzyszek709a6262016-06-24 21:27:17 +0000240 case MVT::v128i8:
241 case MVT::v64i16:
242 case MVT::v32i32:
243 case MVT::v16i64:
244 if (isAlignedMemNode(LD))
245 Opcode = IsValidInc ? Hexagon::V6_vL32b_pi_128B
246 : Hexagon::V6_vL32b_ai_128B;
247 else
248 Opcode = IsValidInc ? Hexagon::V6_vL32Ub_pi_128B
249 : Hexagon::V6_vL32Ub_ai_128B;
250 break;
251 default:
252 llvm_unreachable("Unexpected memory type in indexed load");
Justin Bognerec37a022016-05-12 21:46:18 +0000253 }
Krzysztof Parzyszeka29622a2015-03-12 16:44:50 +0000254
Krzysztof Parzyszek709a6262016-06-24 21:27:17 +0000255 SDValue IncV = CurDAG->getTargetConstant(Inc, dl, MVT::i32);
256 MachineSDNode::mmo_iterator MemOp = MF->allocateMemRefsArray(1);
257 MemOp[0] = LD->getMemOperand();
258
259 auto getExt64 = [this,ExtType] (MachineSDNode *N, const SDLoc &dl)
260 -> MachineSDNode* {
261 if (ExtType == ISD::ZEXTLOAD || ExtType == ISD::EXTLOAD) {
262 SDValue Zero = CurDAG->getTargetConstant(0, dl, MVT::i32);
263 return CurDAG->getMachineNode(Hexagon::A4_combineir, dl, MVT::i64,
264 Zero, SDValue(N, 0));
Krzysztof Parzyszek08ff8882015-11-26 18:38:27 +0000265 }
Krzysztof Parzyszek709a6262016-06-24 21:27:17 +0000266 if (ExtType == ISD::SEXTLOAD)
267 return CurDAG->getMachineNode(Hexagon::A2_sxtw, dl, MVT::i64,
268 SDValue(N, 0));
269 return N;
270 };
271
272 // Loaded value Next address Chain
273 SDValue From[3] = { SDValue(LD,0), SDValue(LD,1), SDValue(LD,2) };
274 SDValue To[3];
275
276 EVT ValueVT = LD->getValueType(0);
277 if (ValueVT == MVT::i64 && ExtType != ISD::NON_EXTLOAD) {
278 // A load extending to i64 will actually produce i32, which will then
279 // need to be extended to i64.
280 assert(LoadedVT.getSizeInBits() <= 32);
281 ValueVT = MVT::i32;
282 }
283
284 if (IsValidInc) {
285 MachineSDNode *L = CurDAG->getMachineNode(Opcode, dl, ValueVT,
286 MVT::i32, MVT::Other, Base,
287 IncV, Chain);
288 L->setMemRefs(MemOp, MemOp+1);
289 To[1] = SDValue(L, 1); // Next address.
290 To[2] = SDValue(L, 2); // Chain.
291 // Handle special case for extension to i64.
292 if (LD->getValueType(0) == MVT::i64)
293 L = getExt64(L, dl);
294 To[0] = SDValue(L, 0); // Loaded (extended) value.
Tony Linthicum1213a7a2011-12-12 21:14:40 +0000295 } else {
Krzysztof Parzyszek709a6262016-06-24 21:27:17 +0000296 SDValue Zero = CurDAG->getTargetConstant(0, dl, MVT::i32);
297 MachineSDNode *L = CurDAG->getMachineNode(Opcode, dl, ValueVT, MVT::Other,
298 Base, Zero, Chain);
299 L->setMemRefs(MemOp, MemOp+1);
300 To[2] = SDValue(L, 1); // Chain.
301 MachineSDNode *A = CurDAG->getMachineNode(Hexagon::A2_addi, dl, MVT::i32,
302 Base, IncV);
303 To[1] = SDValue(A, 0); // Next address.
304 // Handle special case for extension to i64.
305 if (LD->getValueType(0) == MVT::i64)
306 L = getExt64(L, dl);
307 To[0] = SDValue(L, 0); // Loaded (extended) value.
Tony Linthicum1213a7a2011-12-12 21:14:40 +0000308 }
Krzysztof Parzyszek709a6262016-06-24 21:27:17 +0000309 ReplaceUses(From, To, 3);
310 CurDAG->RemoveDeadNode(LD);
Tony Linthicum1213a7a2011-12-12 21:14:40 +0000311}
312
313
Krzysztof Parzyszek7d5b4db2016-02-12 17:01:51 +0000314MachineSDNode *HexagonDAGToDAGISel::LoadInstrForLoadIntrinsic(SDNode *IntN) {
315 if (IntN->getOpcode() != ISD::INTRINSIC_W_CHAIN)
316 return nullptr;
317
318 SDLoc dl(IntN);
319 unsigned IntNo = cast<ConstantSDNode>(IntN->getOperand(1))->getZExtValue();
320
321 static std::map<unsigned,unsigned> LoadPciMap = {
322 { Intrinsic::hexagon_circ_ldb, Hexagon::L2_loadrb_pci },
323 { Intrinsic::hexagon_circ_ldub, Hexagon::L2_loadrub_pci },
324 { Intrinsic::hexagon_circ_ldh, Hexagon::L2_loadrh_pci },
325 { Intrinsic::hexagon_circ_lduh, Hexagon::L2_loadruh_pci },
326 { Intrinsic::hexagon_circ_ldw, Hexagon::L2_loadri_pci },
327 { Intrinsic::hexagon_circ_ldd, Hexagon::L2_loadrd_pci },
328 };
329 auto FLC = LoadPciMap.find(IntNo);
330 if (FLC != LoadPciMap.end()) {
331 SDNode *Mod = CurDAG->getMachineNode(Hexagon::A2_tfrrcr, dl, MVT::i32,
332 IntN->getOperand(4));
333 EVT ValTy = (IntNo == Intrinsic::hexagon_circ_ldd) ? MVT::i64 : MVT::i32;
334 EVT RTys[] = { ValTy, MVT::i32, MVT::Other };
335 // Operands: { Base, Increment, Modifier, Chain }
336 auto Inc = cast<ConstantSDNode>(IntN->getOperand(5));
337 SDValue I = CurDAG->getTargetConstant(Inc->getSExtValue(), dl, MVT::i32);
338 MachineSDNode *Res = CurDAG->getMachineNode(FLC->second, dl, RTys,
339 { IntN->getOperand(2), I, SDValue(Mod,0), IntN->getOperand(0) });
340 return Res;
341 }
342
343 static std::map<unsigned,unsigned> LoadPbrMap = {
344 { Intrinsic::hexagon_brev_ldb, Hexagon::L2_loadrb_pbr },
345 { Intrinsic::hexagon_brev_ldub, Hexagon::L2_loadrub_pbr },
346 { Intrinsic::hexagon_brev_ldh, Hexagon::L2_loadrh_pbr },
347 { Intrinsic::hexagon_brev_lduh, Hexagon::L2_loadruh_pbr },
348 { Intrinsic::hexagon_brev_ldw, Hexagon::L2_loadri_pbr },
349 { Intrinsic::hexagon_brev_ldd, Hexagon::L2_loadrd_pbr },
350 };
351 auto FLB = LoadPbrMap.find(IntNo);
352 if (FLB != LoadPbrMap.end()) {
353 SDNode *Mod = CurDAG->getMachineNode(Hexagon::A2_tfrrcr, dl, MVT::i32,
354 IntN->getOperand(4));
355 EVT ValTy = (IntNo == Intrinsic::hexagon_brev_ldd) ? MVT::i64 : MVT::i32;
356 EVT RTys[] = { ValTy, MVT::i32, MVT::Other };
357 // Operands: { Base, Modifier, Chain }
358 MachineSDNode *Res = CurDAG->getMachineNode(FLB->second, dl, RTys,
359 { IntN->getOperand(2), SDValue(Mod,0), IntN->getOperand(0) });
360 return Res;
361 }
362
363 return nullptr;
364}
365
366SDNode *HexagonDAGToDAGISel::StoreInstrForLoadIntrinsic(MachineSDNode *LoadN,
367 SDNode *IntN) {
368 // The "LoadN" is just a machine load instruction. The intrinsic also
369 // involves storing it. Generate an appropriate store to the location
370 // given in the intrinsic's operand(3).
371 uint64_t F = HII->get(LoadN->getMachineOpcode()).TSFlags;
372 unsigned SizeBits = (F >> HexagonII::MemAccessSizePos) &
373 HexagonII::MemAccesSizeMask;
374 unsigned Size = 1U << (SizeBits-1);
375
376 SDLoc dl(IntN);
377 MachinePointerInfo PI;
378 SDValue TS;
379 SDValue Loc = IntN->getOperand(3);
380
381 if (Size >= 4)
Justin Lebar9c375812016-07-15 18:27:10 +0000382 TS = CurDAG->getStore(SDValue(LoadN, 2), dl, SDValue(LoadN, 0), Loc, PI,
383 Size);
Krzysztof Parzyszek7d5b4db2016-02-12 17:01:51 +0000384 else
Justin Lebar9c375812016-07-15 18:27:10 +0000385 TS = CurDAG->getTruncStore(SDValue(LoadN, 2), dl, SDValue(LoadN, 0), Loc,
386 PI, MVT::getIntegerVT(Size * 8), Size);
Justin Bognerdcb7a822016-05-10 20:31:53 +0000387
388 SDNode *StoreN;
389 {
390 HandleSDNode Handle(TS);
391 SelectStore(TS.getNode());
392 StoreN = Handle.getValue().getNode();
393 }
Krzysztof Parzyszek7d5b4db2016-02-12 17:01:51 +0000394
395 // Load's results are { Loaded value, Updated pointer, Chain }
396 ReplaceUses(SDValue(IntN, 0), SDValue(LoadN, 1));
397 ReplaceUses(SDValue(IntN, 1), SDValue(StoreN, 0));
398 return StoreN;
399}
400
Justin Bognerec37a022016-05-12 21:46:18 +0000401bool HexagonDAGToDAGISel::tryLoadOfLoadIntrinsic(LoadSDNode *N) {
Krzysztof Parzyszek7d5b4db2016-02-12 17:01:51 +0000402 // The intrinsics for load circ/brev perform two operations:
403 // 1. Load a value V from the specified location, using the addressing
404 // mode corresponding to the intrinsic.
405 // 2. Store V into a specified location. This location is typically a
406 // local, temporary object.
407 // In many cases, the program using these intrinsics will immediately
408 // load V again from the local object. In those cases, when certain
409 // conditions are met, the last load can be removed.
410 // This function identifies and optimizes this pattern. If the pattern
411 // cannot be optimized, it returns nullptr, which will cause the load
412 // to be selected separately from the intrinsic (which will be handled
413 // in SelectIntrinsicWChain).
414
415 SDValue Ch = N->getOperand(0);
416 SDValue Loc = N->getOperand(1);
417
418 // Assume that the load and the intrinsic are connected directly with a
419 // chain:
420 // t1: i32,ch = int.load ..., ..., ..., Loc, ... // <-- C
421 // t2: i32,ch = load t1:1, Loc, ...
422 SDNode *C = Ch.getNode();
423
424 if (C->getOpcode() != ISD::INTRINSIC_W_CHAIN)
Justin Bognerec37a022016-05-12 21:46:18 +0000425 return false;
Krzysztof Parzyszek7d5b4db2016-02-12 17:01:51 +0000426
427 // The second load can only be eliminated if its extension type matches
428 // that of the load instruction corresponding to the intrinsic. The user
429 // can provide an address of an unsigned variable to store the result of
430 // a sign-extending intrinsic into (or the other way around).
431 ISD::LoadExtType IntExt;
432 switch (cast<ConstantSDNode>(C->getOperand(1))->getZExtValue()) {
433 case Intrinsic::hexagon_brev_ldub:
434 case Intrinsic::hexagon_brev_lduh:
435 case Intrinsic::hexagon_circ_ldub:
436 case Intrinsic::hexagon_circ_lduh:
437 IntExt = ISD::ZEXTLOAD;
438 break;
439 case Intrinsic::hexagon_brev_ldw:
440 case Intrinsic::hexagon_brev_ldd:
441 case Intrinsic::hexagon_circ_ldw:
442 case Intrinsic::hexagon_circ_ldd:
443 IntExt = ISD::NON_EXTLOAD;
444 break;
445 default:
446 IntExt = ISD::SEXTLOAD;
447 break;
448 }
449 if (N->getExtensionType() != IntExt)
Justin Bognerec37a022016-05-12 21:46:18 +0000450 return false;
Krzysztof Parzyszek7d5b4db2016-02-12 17:01:51 +0000451
452 // Make sure the target location for the loaded value in the load intrinsic
453 // is the location from which LD (or N) is loading.
454 if (C->getNumOperands() < 4 || Loc.getNode() != C->getOperand(3).getNode())
Justin Bognerec37a022016-05-12 21:46:18 +0000455 return false;
Krzysztof Parzyszek7d5b4db2016-02-12 17:01:51 +0000456
457 if (MachineSDNode *L = LoadInstrForLoadIntrinsic(C)) {
458 SDNode *S = StoreInstrForLoadIntrinsic(L, C);
459 SDValue F[] = { SDValue(N,0), SDValue(N,1), SDValue(C,0), SDValue(C,1) };
460 SDValue T[] = { SDValue(L,0), SDValue(S,0), SDValue(L,1), SDValue(S,0) };
461 ReplaceUses(F, T, array_lengthof(T));
462 // This transformation will leave the intrinsic dead. If it remains in
463 // the DAG, the selection code will see it again, but without the load,
464 // and it will generate a store that is normally required for it.
Krzysztof Parzyszek0f791f42016-05-13 18:48:15 +0000465 CurDAG->RemoveDeadNode(C);
Justin Bognerec37a022016-05-12 21:46:18 +0000466 return true;
Krzysztof Parzyszek7d5b4db2016-02-12 17:01:51 +0000467 }
468
Justin Bognerec37a022016-05-12 21:46:18 +0000469 return false;
Krzysztof Parzyszek7d5b4db2016-02-12 17:01:51 +0000470}
471
Justin Bognerec37a022016-05-12 21:46:18 +0000472void HexagonDAGToDAGISel::SelectLoad(SDNode *N) {
Andrew Trickef9de2a2013-05-25 02:42:55 +0000473 SDLoc dl(N);
Tony Linthicum1213a7a2011-12-12 21:14:40 +0000474 LoadSDNode *LD = cast<LoadSDNode>(N);
475 ISD::MemIndexedMode AM = LD->getAddressingMode();
476
477 // Handle indexed loads.
Justin Bognerec37a022016-05-12 21:46:18 +0000478 if (AM != ISD::UNINDEXED) {
479 SelectIndexedLoad(LD, dl);
480 return;
481 }
Tony Linthicum1213a7a2011-12-12 21:14:40 +0000482
Krzysztof Parzyszek7d5b4db2016-02-12 17:01:51 +0000483 // Handle patterns using circ/brev load intrinsics.
Justin Bognerec37a022016-05-12 21:46:18 +0000484 if (tryLoadOfLoadIntrinsic(LD))
485 return;
Krzysztof Parzyszek7d5b4db2016-02-12 17:01:51 +0000486
Justin Bognerec37a022016-05-12 21:46:18 +0000487 SelectCode(LD);
Tony Linthicum1213a7a2011-12-12 21:14:40 +0000488}
489
Benjamin Kramerbdc49562016-06-12 15:39:02 +0000490void HexagonDAGToDAGISel::SelectIndexedStore(StoreSDNode *ST, const SDLoc &dl) {
Tony Linthicum1213a7a2011-12-12 21:14:40 +0000491 SDValue Chain = ST->getChain();
492 SDValue Base = ST->getBasePtr();
493 SDValue Offset = ST->getOffset();
494 SDValue Value = ST->getValue();
Tony Linthicum1213a7a2011-12-12 21:14:40 +0000495 // Get the constant value.
Krzysztof Parzyszek709a6262016-06-24 21:27:17 +0000496 int32_t Inc = cast<ConstantSDNode>(Offset.getNode())->getSExtValue();
Tony Linthicum1213a7a2011-12-12 21:14:40 +0000497 EVT StoredVT = ST->getMemoryVT();
Krzysztof Parzyszeka29622a2015-03-12 16:44:50 +0000498 EVT ValueVT = Value.getValueType();
Tony Linthicum1213a7a2011-12-12 21:14:40 +0000499
Krzysztof Parzyszek709a6262016-06-24 21:27:17 +0000500 bool IsValidInc = HII->isValidAutoIncImm(StoredVT, Inc);
Tony Linthicum1213a7a2011-12-12 21:14:40 +0000501 unsigned Opcode = 0;
502
Krzysztof Parzyszek709a6262016-06-24 21:27:17 +0000503 assert(StoredVT.isSimple());
504 switch (StoredVT.getSimpleVT().SimpleTy) {
505 case MVT::i8:
506 Opcode = IsValidInc ? Hexagon::S2_storerb_pi : Hexagon::S2_storerb_io;
507 break;
508 case MVT::i16:
509 Opcode = IsValidInc ? Hexagon::S2_storerh_pi : Hexagon::S2_storerh_io;
510 break;
511 case MVT::i32:
512 Opcode = IsValidInc ? Hexagon::S2_storeri_pi : Hexagon::S2_storeri_io;
513 break;
514 case MVT::i64:
515 Opcode = IsValidInc ? Hexagon::S2_storerd_pi : Hexagon::S2_storerd_io;
516 break;
517 // 64B
518 case MVT::v64i8:
519 case MVT::v32i16:
520 case MVT::v16i32:
521 case MVT::v8i64:
Krzysztof Parzyszek2d65ea72016-03-28 15:43:03 +0000522 if (isAlignedMemNode(ST))
Krzysztof Parzyszek709a6262016-06-24 21:27:17 +0000523 Opcode = IsValidInc ? Hexagon::V6_vS32b_pi : Hexagon::V6_vS32b_ai;
Krzysztof Parzyszek2d65ea72016-03-28 15:43:03 +0000524 else
Krzysztof Parzyszek709a6262016-06-24 21:27:17 +0000525 Opcode = IsValidInc ? Hexagon::V6_vS32Ub_pi : Hexagon::V6_vS32Ub_ai;
526 break;
Krzysztof Parzyszek08ff8882015-11-26 18:38:27 +0000527 // 128B
Krzysztof Parzyszek709a6262016-06-24 21:27:17 +0000528 case MVT::v128i8:
529 case MVT::v64i16:
530 case MVT::v32i32:
531 case MVT::v16i64:
Krzysztof Parzyszek2d65ea72016-03-28 15:43:03 +0000532 if (isAlignedMemNode(ST))
Krzysztof Parzyszek709a6262016-06-24 21:27:17 +0000533 Opcode = IsValidInc ? Hexagon::V6_vS32b_pi_128B
534 : Hexagon::V6_vS32b_ai_128B;
Krzysztof Parzyszek2d65ea72016-03-28 15:43:03 +0000535 else
Krzysztof Parzyszek709a6262016-06-24 21:27:17 +0000536 Opcode = IsValidInc ? Hexagon::V6_vS32Ub_pi_128B
537 : Hexagon::V6_vS32Ub_ai_128B;
538 break;
539 default:
540 llvm_unreachable("Unexpected memory type in indexed store");
Krzysztof Parzyszek2d65ea72016-03-28 15:43:03 +0000541 }
Tony Linthicum1213a7a2011-12-12 21:14:40 +0000542
Krzysztof Parzyszek709a6262016-06-24 21:27:17 +0000543 if (ST->isTruncatingStore() && ValueVT.getSizeInBits() == 64) {
544 assert(StoredVT.getSizeInBits() < 64 && "Not a truncating store");
Krzysztof Parzyszeka5409972016-11-09 16:19:08 +0000545 Value = CurDAG->getTargetExtractSubreg(Hexagon::isub_lo,
Krzysztof Parzyszek709a6262016-06-24 21:27:17 +0000546 dl, MVT::i32, Value);
547 }
548
549 SDValue IncV = CurDAG->getTargetConstant(Inc, dl, MVT::i32);
Tony Linthicum1213a7a2011-12-12 21:14:40 +0000550 MachineSDNode::mmo_iterator MemOp = MF->allocateMemRefsArray(1);
551 MemOp[0] = ST->getMemOperand();
Tony Linthicum1213a7a2011-12-12 21:14:40 +0000552
Krzysztof Parzyszek709a6262016-06-24 21:27:17 +0000553 // Next address Chain
554 SDValue From[2] = { SDValue(ST,0), SDValue(ST,1) };
555 SDValue To[2];
556
557 if (IsValidInc) {
558 // Build post increment store.
559 SDValue Ops[] = { Base, IncV, Value, Chain };
560 MachineSDNode *S = CurDAG->getMachineNode(Opcode, dl, MVT::i32, MVT::Other,
561 Ops);
562 S->setMemRefs(MemOp, MemOp + 1);
563 To[0] = SDValue(S, 0);
564 To[1] = SDValue(S, 1);
565 } else {
566 SDValue Zero = CurDAG->getTargetConstant(0, dl, MVT::i32);
567 SDValue Ops[] = { Base, Zero, Value, Chain };
568 MachineSDNode *S = CurDAG->getMachineNode(Opcode, dl, MVT::Other, Ops);
569 S->setMemRefs(MemOp, MemOp + 1);
570 To[1] = SDValue(S, 0);
571 MachineSDNode *A = CurDAG->getMachineNode(Hexagon::A2_addi, dl, MVT::i32,
572 Base, IncV);
573 To[0] = SDValue(A, 0);
574 }
575
576 ReplaceUses(From, To, 2);
Justin Bognerdcb7a822016-05-10 20:31:53 +0000577 CurDAG->RemoveDeadNode(ST);
Tony Linthicum1213a7a2011-12-12 21:14:40 +0000578}
579
Justin Bognerec37a022016-05-12 21:46:18 +0000580void HexagonDAGToDAGISel::SelectStore(SDNode *N) {
Andrew Trickef9de2a2013-05-25 02:42:55 +0000581 SDLoc dl(N);
Tony Linthicum1213a7a2011-12-12 21:14:40 +0000582 StoreSDNode *ST = cast<StoreSDNode>(N);
583 ISD::MemIndexedMode AM = ST->getAddressingMode();
584
585 // Handle indexed stores.
586 if (AM != ISD::UNINDEXED) {
Justin Bognerec37a022016-05-12 21:46:18 +0000587 SelectIndexedStore(ST, dl);
588 return;
Tony Linthicum1213a7a2011-12-12 21:14:40 +0000589 }
Sirish Pandec92c3162012-05-03 16:18:50 +0000590
Justin Bognerec37a022016-05-12 21:46:18 +0000591 SelectCode(ST);
Tony Linthicum1213a7a2011-12-12 21:14:40 +0000592}
593
Justin Bognerec37a022016-05-12 21:46:18 +0000594void HexagonDAGToDAGISel::SelectMul(SDNode *N) {
Andrew Trickef9de2a2013-05-25 02:42:55 +0000595 SDLoc dl(N);
Tony Linthicum1213a7a2011-12-12 21:14:40 +0000596
Tony Linthicum1213a7a2011-12-12 21:14:40 +0000597 // %conv.i = sext i32 %tmp1 to i64
598 // %conv2.i = sext i32 %add to i64
599 // %mul.i = mul nsw i64 %conv2.i, %conv.i
600 //
601 // --- match with the following ---
602 //
603 // %mul.i = mpy (%tmp1, %add)
604 //
605
606 if (N->getValueType(0) == MVT::i64) {
607 // Shifting a i64 signed multiply.
608 SDValue MulOp0 = N->getOperand(0);
609 SDValue MulOp1 = N->getOperand(1);
610
611 SDValue OP0;
612 SDValue OP1;
613
614 // Handle sign_extend and sextload.
615 if (MulOp0.getOpcode() == ISD::SIGN_EXTEND) {
616 SDValue Sext0 = MulOp0.getOperand(0);
617 if (Sext0.getNode()->getValueType(0) != MVT::i32) {
Justin Bognerec37a022016-05-12 21:46:18 +0000618 SelectCode(N);
619 return;
Tony Linthicum1213a7a2011-12-12 21:14:40 +0000620 }
Tony Linthicum1213a7a2011-12-12 21:14:40 +0000621 OP0 = Sext0;
622 } else if (MulOp0.getOpcode() == ISD::LOAD) {
623 LoadSDNode *LD = cast<LoadSDNode>(MulOp0.getNode());
624 if (LD->getMemoryVT() != MVT::i32 ||
625 LD->getExtensionType() != ISD::SEXTLOAD ||
626 LD->getAddressingMode() != ISD::UNINDEXED) {
Justin Bognerec37a022016-05-12 21:46:18 +0000627 SelectCode(N);
628 return;
Tony Linthicum1213a7a2011-12-12 21:14:40 +0000629 }
Tony Linthicum1213a7a2011-12-12 21:14:40 +0000630 SDValue Chain = LD->getChain();
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +0000631 SDValue TargetConst0 = CurDAG->getTargetConstant(0, dl, MVT::i32);
Colin LeMahieu026e88d2014-12-23 20:02:16 +0000632 OP0 = SDValue(CurDAG->getMachineNode(Hexagon::L2_loadri_io, dl, MVT::i32,
Tony Linthicum1213a7a2011-12-12 21:14:40 +0000633 MVT::Other,
634 LD->getBasePtr(), TargetConst0,
635 Chain), 0);
636 } else {
Justin Bognerec37a022016-05-12 21:46:18 +0000637 SelectCode(N);
638 return;
Tony Linthicum1213a7a2011-12-12 21:14:40 +0000639 }
640
641 // Same goes for the second operand.
642 if (MulOp1.getOpcode() == ISD::SIGN_EXTEND) {
643 SDValue Sext1 = MulOp1.getOperand(0);
644 if (Sext1.getNode()->getValueType(0) != MVT::i32) {
Justin Bognerec37a022016-05-12 21:46:18 +0000645 SelectCode(N);
646 return;
Tony Linthicum1213a7a2011-12-12 21:14:40 +0000647 }
Tony Linthicum1213a7a2011-12-12 21:14:40 +0000648 OP1 = Sext1;
649 } else if (MulOp1.getOpcode() == ISD::LOAD) {
650 LoadSDNode *LD = cast<LoadSDNode>(MulOp1.getNode());
651 if (LD->getMemoryVT() != MVT::i32 ||
652 LD->getExtensionType() != ISD::SEXTLOAD ||
653 LD->getAddressingMode() != ISD::UNINDEXED) {
Justin Bognerec37a022016-05-12 21:46:18 +0000654 SelectCode(N);
655 return;
Tony Linthicum1213a7a2011-12-12 21:14:40 +0000656 }
Tony Linthicum1213a7a2011-12-12 21:14:40 +0000657 SDValue Chain = LD->getChain();
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +0000658 SDValue TargetConst0 = CurDAG->getTargetConstant(0, dl, MVT::i32);
Colin LeMahieu026e88d2014-12-23 20:02:16 +0000659 OP1 = SDValue(CurDAG->getMachineNode(Hexagon::L2_loadri_io, dl, MVT::i32,
Tony Linthicum1213a7a2011-12-12 21:14:40 +0000660 MVT::Other,
661 LD->getBasePtr(), TargetConst0,
662 Chain), 0);
663 } else {
Justin Bognerec37a022016-05-12 21:46:18 +0000664 SelectCode(N);
665 return;
Tony Linthicum1213a7a2011-12-12 21:14:40 +0000666 }
667
668 // Generate a mpy instruction.
Krzysztof Parzyszek317d42c2016-08-01 20:31:50 +0000669 SDNode *Result = CurDAG->getMachineNode(Hexagon::M2_dpmpyss_s0, dl,
670 MVT::i64, OP0, OP1);
Justin Bognerec37a022016-05-12 21:46:18 +0000671 ReplaceNode(N, Result);
672 return;
Tony Linthicum1213a7a2011-12-12 21:14:40 +0000673 }
674
Justin Bognerec37a022016-05-12 21:46:18 +0000675 SelectCode(N);
Tony Linthicum1213a7a2011-12-12 21:14:40 +0000676}
677
Justin Bognerec37a022016-05-12 21:46:18 +0000678void HexagonDAGToDAGISel::SelectSHL(SDNode *N) {
Andrew Trickef9de2a2013-05-25 02:42:55 +0000679 SDLoc dl(N);
Krzysztof Parzyszek317d42c2016-08-01 20:31:50 +0000680 SDValue Shl_0 = N->getOperand(0);
681 SDValue Shl_1 = N->getOperand(1);
Krzysztof Parzyszekd978ae22016-08-01 20:00:33 +0000682
Krzysztof Parzyszek317d42c2016-08-01 20:31:50 +0000683 auto Default = [this,N] () -> void { SelectCode(N); };
684
685 if (N->getValueType(0) != MVT::i32 || Shl_1.getOpcode() != ISD::Constant)
686 return Default();
687
688 // RHS is const.
689 int32_t ShlConst = cast<ConstantSDNode>(Shl_1)->getSExtValue();
690
691 if (Shl_0.getOpcode() == ISD::MUL) {
692 SDValue Mul_0 = Shl_0.getOperand(0); // Val
693 SDValue Mul_1 = Shl_0.getOperand(1); // Const
694 // RHS of mul is const.
695 if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(Mul_1)) {
696 int32_t ValConst = C->getSExtValue() << ShlConst;
697 if (isInt<9>(ValConst)) {
698 SDValue Val = CurDAG->getTargetConstant(ValConst, dl, MVT::i32);
699 SDNode *Result = CurDAG->getMachineNode(Hexagon::M2_mpysmi, dl,
700 MVT::i32, Mul_0, Val);
701 ReplaceNode(N, Result);
702 return;
703 }
704 }
705 return Default();
706 }
707
708 if (Shl_0.getOpcode() == ISD::SUB) {
709 SDValue Sub_0 = Shl_0.getOperand(0); // Const 0
710 SDValue Sub_1 = Shl_0.getOperand(1); // Val
711 if (ConstantSDNode *C1 = dyn_cast<ConstantSDNode>(Sub_0)) {
712 if (C1->getSExtValue() != 0 || Sub_1.getOpcode() != ISD::SHL)
713 return Default();
714 SDValue Shl2_0 = Sub_1.getOperand(0); // Val
715 SDValue Shl2_1 = Sub_1.getOperand(1); // Const
716 if (ConstantSDNode *C2 = dyn_cast<ConstantSDNode>(Shl2_1)) {
717 int32_t ValConst = 1 << (ShlConst + C2->getSExtValue());
718 if (isInt<9>(-ValConst)) {
719 SDValue Val = CurDAG->getTargetConstant(-ValConst, dl, MVT::i32);
720 SDNode *Result = CurDAG->getMachineNode(Hexagon::M2_mpysmi, dl,
721 MVT::i32, Shl2_0, Val);
722 ReplaceNode(N, Result);
723 return;
Tony Linthicum1213a7a2011-12-12 21:14:40 +0000724 }
725 }
726 }
727 }
Krzysztof Parzyszek317d42c2016-08-01 20:31:50 +0000728
729 return Default();
Tony Linthicum1213a7a2011-12-12 21:14:40 +0000730}
731
732
733//
734// If there is an zero_extend followed an intrinsic in DAG (this means - the
735// result of the intrinsic is predicate); convert the zero_extend to
736// transfer instruction.
737//
738// Zero extend -> transfer is lowered here. Otherwise, zero_extend will be
739// converted into a MUX as predicate registers defined as 1 bit in the
740// compiler. Architecture defines them as 8-bit registers.
741// We want to preserve all the lower 8-bits and, not just 1 LSB bit.
742//
Justin Bognerec37a022016-05-12 21:46:18 +0000743void HexagonDAGToDAGISel::SelectZeroExtend(SDNode *N) {
Andrew Trickef9de2a2013-05-25 02:42:55 +0000744 SDLoc dl(N);
Krzysztof Parzyszek42113342015-03-19 16:33:08 +0000745
746 SDValue Op0 = N->getOperand(0);
747 EVT OpVT = Op0.getValueType();
748 unsigned OpBW = OpVT.getSizeInBits();
749
750 // Special handling for zero-extending a vector of booleans.
751 if (OpVT.isVector() && OpVT.getVectorElementType() == MVT::i1 && OpBW <= 64) {
752 SDNode *Mask = CurDAG->getMachineNode(Hexagon::C2_mask, dl, MVT::i64, Op0);
753 unsigned NE = OpVT.getVectorNumElements();
754 EVT ExVT = N->getValueType(0);
Sanjay Patel1ed771f2016-09-14 16:37:15 +0000755 unsigned ES = ExVT.getScalarSizeInBits();
Krzysztof Parzyszek42113342015-03-19 16:33:08 +0000756 uint64_t MV = 0, Bit = 1;
757 for (unsigned i = 0; i < NE; ++i) {
758 MV |= Bit;
759 Bit <<= ES;
760 }
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +0000761 SDValue Ones = CurDAG->getTargetConstant(MV, dl, MVT::i64);
Krzysztof Parzyszeka3386502016-08-10 16:46:36 +0000762 SDNode *OnesReg = CurDAG->getMachineNode(Hexagon::CONST64, dl,
Krzysztof Parzyszek42113342015-03-19 16:33:08 +0000763 MVT::i64, Ones);
764 if (ExVT.getSizeInBits() == 32) {
765 SDNode *And = CurDAG->getMachineNode(Hexagon::A2_andp, dl, MVT::i64,
766 SDValue(Mask,0), SDValue(OnesReg,0));
Krzysztof Parzyszeka5409972016-11-09 16:19:08 +0000767 SDValue SubR = CurDAG->getTargetConstant(Hexagon::isub_lo, dl, MVT::i32);
Justin Bognerec37a022016-05-12 21:46:18 +0000768 ReplaceNode(N, CurDAG->getMachineNode(Hexagon::EXTRACT_SUBREG, dl, ExVT,
769 SDValue(And, 0), SubR));
770 return;
Krzysztof Parzyszek42113342015-03-19 16:33:08 +0000771 }
Justin Bognerec37a022016-05-12 21:46:18 +0000772 ReplaceNode(N,
773 CurDAG->getMachineNode(Hexagon::A2_andp, dl, ExVT,
774 SDValue(Mask, 0), SDValue(OnesReg, 0)));
775 return;
Krzysztof Parzyszek42113342015-03-19 16:33:08 +0000776 }
777
Krzysztof Parzyszek317d42c2016-08-01 20:31:50 +0000778 SDNode *Int = N->getOperand(0).getNode();
779 if ((Int->getOpcode() == ISD::INTRINSIC_WO_CHAIN)) {
780 unsigned ID = cast<ConstantSDNode>(Int->getOperand(0))->getZExtValue();
Tony Linthicum1213a7a2011-12-12 21:14:40 +0000781 if (doesIntrinsicReturnPredicate(ID)) {
782 // Now we need to differentiate target data types.
783 if (N->getValueType(0) == MVT::i64) {
Krzysztof Parzyszekae14e7b2015-03-17 21:47:16 +0000784 // Convert the zero_extend to Rs = Pd followed by A2_combinew(0,Rs).
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +0000785 SDValue TargetConst0 = CurDAG->getTargetConstant(0, dl, MVT::i32);
Colin LeMahieu30dcb232014-12-09 18:16:49 +0000786 SDNode *Result_1 = CurDAG->getMachineNode(Hexagon::C2_tfrpr, dl,
Krzysztof Parzyszek317d42c2016-08-01 20:31:50 +0000787 MVT::i32, SDValue(Int, 0));
Colin LeMahieu4af437f2014-12-09 20:23:30 +0000788 SDNode *Result_2 = CurDAG->getMachineNode(Hexagon::A2_tfrsi, dl,
Krzysztof Parzyszek317d42c2016-08-01 20:31:50 +0000789 MVT::i32, TargetConst0);
Colin LeMahieub580d7d2014-12-09 19:23:45 +0000790 SDNode *Result_3 = CurDAG->getMachineNode(Hexagon::A2_combinew, dl,
Tony Linthicum1213a7a2011-12-12 21:14:40 +0000791 MVT::i64, MVT::Other,
792 SDValue(Result_2, 0),
793 SDValue(Result_1, 0));
Justin Bognerec37a022016-05-12 21:46:18 +0000794 ReplaceNode(N, Result_3);
795 return;
Tony Linthicum1213a7a2011-12-12 21:14:40 +0000796 }
797 if (N->getValueType(0) == MVT::i32) {
798 // Convert the zero_extend to Rs = Pd
Colin LeMahieu30dcb232014-12-09 18:16:49 +0000799 SDNode* RsPd = CurDAG->getMachineNode(Hexagon::C2_tfrpr, dl,
Krzysztof Parzyszek317d42c2016-08-01 20:31:50 +0000800 MVT::i32, SDValue(Int, 0));
Justin Bognerec37a022016-05-12 21:46:18 +0000801 ReplaceNode(N, RsPd);
802 return;
Tony Linthicum1213a7a2011-12-12 21:14:40 +0000803 }
Craig Toppere55c5562012-02-07 02:50:20 +0000804 llvm_unreachable("Unexpected value type");
Tony Linthicum1213a7a2011-12-12 21:14:40 +0000805 }
806 }
Justin Bognerec37a022016-05-12 21:46:18 +0000807 SelectCode(N);
Tony Linthicum1213a7a2011-12-12 21:14:40 +0000808}
809
Krzysztof Parzyszek7d5b4db2016-02-12 17:01:51 +0000810
Tony Linthicum1213a7a2011-12-12 21:14:40 +0000811//
Krzysztof Parzyszek7d5b4db2016-02-12 17:01:51 +0000812// Handling intrinsics for circular load and bitreverse load.
Krzysztof Parzyszek47ab1f22015-03-18 16:23:44 +0000813//
Justin Bognerec37a022016-05-12 21:46:18 +0000814void HexagonDAGToDAGISel::SelectIntrinsicWChain(SDNode *N) {
815 if (MachineSDNode *L = LoadInstrForLoadIntrinsic(N)) {
816 StoreInstrForLoadIntrinsic(L, N);
Krzysztof Parzyszek0f791f42016-05-13 18:48:15 +0000817 CurDAG->RemoveDeadNode(N);
Justin Bognerec37a022016-05-12 21:46:18 +0000818 return;
819 }
820 SelectCode(N);
Krzysztof Parzyszek47ab1f22015-03-18 16:23:44 +0000821}
822
Justin Bognerec37a022016-05-12 21:46:18 +0000823void HexagonDAGToDAGISel::SelectIntrinsicWOChain(SDNode *N) {
Colin LeMahieu0ee02fc2015-01-19 20:31:18 +0000824 unsigned IID = cast<ConstantSDNode>(N->getOperand(0))->getZExtValue();
825 unsigned Bits;
826 switch (IID) {
827 case Intrinsic::hexagon_S2_vsplatrb:
828 Bits = 8;
829 break;
830 case Intrinsic::hexagon_S2_vsplatrh:
831 Bits = 16;
832 break;
833 default:
Justin Bognerec37a022016-05-12 21:46:18 +0000834 SelectCode(N);
835 return;
Colin LeMahieu0ee02fc2015-01-19 20:31:18 +0000836 }
Tony Linthicum1213a7a2011-12-12 21:14:40 +0000837
Krzysztof Parzyszeke60e5fe2016-05-12 17:21:40 +0000838 SDValue V = N->getOperand(1);
Colin LeMahieu0ee02fc2015-01-19 20:31:18 +0000839 SDValue U;
840 if (isValueExtension(V, Bits, U)) {
841 SDValue R = CurDAG->getNode(N->getOpcode(), SDLoc(N), N->getValueType(0),
Krzysztof Parzyszeke60e5fe2016-05-12 17:21:40 +0000842 N->getOperand(0), U);
Justin Bognerd82025b2016-05-12 21:24:23 +0000843 ReplaceNode(N, R.getNode());
Justin Bognerec37a022016-05-12 21:46:18 +0000844 SelectCode(R.getNode());
845 return;
Tony Linthicum1213a7a2011-12-12 21:14:40 +0000846 }
Justin Bognerec37a022016-05-12 21:46:18 +0000847 SelectCode(N);
Tony Linthicum1213a7a2011-12-12 21:14:40 +0000848}
849
Sirish Pande69295b82012-05-10 20:20:25 +0000850//
851// Map floating point constant values.
852//
Justin Bognerec37a022016-05-12 21:46:18 +0000853void HexagonDAGToDAGISel::SelectConstantFP(SDNode *N) {
Andrew Trickef9de2a2013-05-25 02:42:55 +0000854 SDLoc dl(N);
Sirish Pande69295b82012-05-10 20:20:25 +0000855 ConstantFPSDNode *CN = dyn_cast<ConstantFPSDNode>(N);
Krzysztof Parzyszeka3386502016-08-10 16:46:36 +0000856 APInt A = CN->getValueAPF().bitcastToAPInt();
Sirish Pande69295b82012-05-10 20:20:25 +0000857 if (N->getValueType(0) == MVT::f32) {
Krzysztof Parzyszeka3386502016-08-10 16:46:36 +0000858 SDValue V = CurDAG->getTargetConstant(A.getZExtValue(), dl, MVT::i32);
859 ReplaceNode(N, CurDAG->getMachineNode(Hexagon::A2_tfrsi, dl, MVT::f32, V));
Justin Bognerec37a022016-05-12 21:46:18 +0000860 return;
Sirish Pande69295b82012-05-10 20:20:25 +0000861 }
Krzysztof Parzyszek317d42c2016-08-01 20:31:50 +0000862 if (N->getValueType(0) == MVT::f64) {
Krzysztof Parzyszeka3386502016-08-10 16:46:36 +0000863 SDValue V = CurDAG->getTargetConstant(A.getZExtValue(), dl, MVT::i64);
864 ReplaceNode(N, CurDAG->getMachineNode(Hexagon::CONST64, dl, MVT::f64, V));
Justin Bognerec37a022016-05-12 21:46:18 +0000865 return;
Sirish Pande69295b82012-05-10 20:20:25 +0000866 }
867
Justin Bognerec37a022016-05-12 21:46:18 +0000868 SelectCode(N);
Sirish Pande69295b82012-05-10 20:20:25 +0000869}
870
Tony Linthicum1213a7a2011-12-12 21:14:40 +0000871//
Krzysztof Parzyszek1d01a792016-08-16 18:08:40 +0000872// Map boolean values.
Tony Linthicum1213a7a2011-12-12 21:14:40 +0000873//
Justin Bognerec37a022016-05-12 21:46:18 +0000874void HexagonDAGToDAGISel::SelectConstant(SDNode *N) {
Tony Linthicum1213a7a2011-12-12 21:14:40 +0000875 if (N->getValueType(0) == MVT::i1) {
Krzysztof Parzyszek1d01a792016-08-16 18:08:40 +0000876 assert(!(cast<ConstantSDNode>(N)->getZExtValue() >> 1));
877 unsigned Opc = (cast<ConstantSDNode>(N)->getSExtValue() != 0)
878 ? Hexagon::PS_true
879 : Hexagon::PS_false;
880 ReplaceNode(N, CurDAG->getMachineNode(Opc, SDLoc(N), MVT::i1));
881 return;
Tony Linthicum1213a7a2011-12-12 21:14:40 +0000882 }
883
Justin Bognerec37a022016-05-12 21:46:18 +0000884 SelectCode(N);
Tony Linthicum1213a7a2011-12-12 21:14:40 +0000885}
886
887
Justin Bognerec37a022016-05-12 21:46:18 +0000888void HexagonDAGToDAGISel::SelectFrameIndex(SDNode *N) {
Matthias Braun941a7052016-07-28 18:40:00 +0000889 MachineFrameInfo &MFI = MF->getFrameInfo();
Krzysztof Parzyszek4fa2a9f2015-04-22 16:43:53 +0000890 const HexagonFrameLowering *HFI = HST->getFrameLowering();
Krzysztof Parzyszeka29622a2015-03-12 16:44:50 +0000891 int FX = cast<FrameIndexSDNode>(N)->getIndex();
Krzysztof Parzyszek4fa2a9f2015-04-22 16:43:53 +0000892 unsigned StkA = HFI->getStackAlignment();
Matthias Braun941a7052016-07-28 18:40:00 +0000893 unsigned MaxA = MFI.getMaxAlignment();
Krzysztof Parzyszeka29622a2015-03-12 16:44:50 +0000894 SDValue FI = CurDAG->getTargetFrameIndex(FX, MVT::i32);
Krzysztof Parzyszeka29622a2015-03-12 16:44:50 +0000895 SDLoc DL(N);
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +0000896 SDValue Zero = CurDAG->getTargetConstant(0, DL, MVT::i32);
Krzysztof Parzyszek317d42c2016-08-01 20:31:50 +0000897 SDNode *R = nullptr;
Krzysztof Parzyszeka29622a2015-03-12 16:44:50 +0000898
Krzysztof Parzyszek1d01a792016-08-16 18:08:40 +0000899 // Use PS_fi when:
Krzysztof Parzyszek4fa2a9f2015-04-22 16:43:53 +0000900 // - the object is fixed, or
901 // - there are no objects with higher-than-default alignment, or
902 // - there are no dynamically allocated objects.
Krzysztof Parzyszek1d01a792016-08-16 18:08:40 +0000903 // Otherwise, use PS_fia.
Matthias Braun941a7052016-07-28 18:40:00 +0000904 if (FX < 0 || MaxA <= StkA || !MFI.hasVarSizedObjects()) {
Krzysztof Parzyszek1d01a792016-08-16 18:08:40 +0000905 R = CurDAG->getMachineNode(Hexagon::PS_fi, DL, MVT::i32, FI, Zero);
Krzysztof Parzyszek4fa2a9f2015-04-22 16:43:53 +0000906 } else {
907 auto &HMFI = *MF->getInfo<HexagonMachineFunctionInfo>();
908 unsigned AR = HMFI.getStackAlignBaseVReg();
909 SDValue CH = CurDAG->getEntryNode();
910 SDValue Ops[] = { CurDAG->getCopyFromReg(CH, DL, AR, MVT::i32), FI, Zero };
Krzysztof Parzyszek1d01a792016-08-16 18:08:40 +0000911 R = CurDAG->getMachineNode(Hexagon::PS_fia, DL, MVT::i32, Ops);
Krzysztof Parzyszek4fa2a9f2015-04-22 16:43:53 +0000912 }
Krzysztof Parzyszeka29622a2015-03-12 16:44:50 +0000913
Justin Bognerec37a022016-05-12 21:46:18 +0000914 ReplaceNode(N, R);
Krzysztof Parzyszeka29622a2015-03-12 16:44:50 +0000915}
916
Tony Linthicum1213a7a2011-12-12 21:14:40 +0000917
Krzysztof Parzyszek5da24e52016-06-27 15:08:22 +0000918void HexagonDAGToDAGISel::SelectBitcast(SDNode *N) {
919 EVT SVT = N->getOperand(0).getValueType();
920 EVT DVT = N->getValueType(0);
921 if (!SVT.isVector() || !DVT.isVector() ||
922 SVT.getVectorElementType() == MVT::i1 ||
923 DVT.getVectorElementType() == MVT::i1 ||
924 SVT.getSizeInBits() != DVT.getSizeInBits()) {
925 SelectCode(N);
926 return;
927 }
928
929 CurDAG->ReplaceAllUsesOfValueWith(SDValue(N,0), N->getOperand(0));
930 CurDAG->RemoveDeadNode(N);
931}
932
933
Justin Bognerec37a022016-05-12 21:46:18 +0000934void HexagonDAGToDAGISel::Select(SDNode *N) {
Krzysztof Parzyszekbe5028a2017-02-24 23:00:40 +0000935 if (N->isMachineOpcode())
936 return N->setNodeId(-1); // Already selected.
Tony Linthicum1213a7a2011-12-12 21:14:40 +0000937
Tony Linthicum1213a7a2011-12-12 21:14:40 +0000938 switch (N->getOpcode()) {
Krzysztof Parzyszekbe5028a2017-02-24 23:00:40 +0000939 case ISD::Constant: return SelectConstant(N);
940 case ISD::ConstantFP: return SelectConstantFP(N);
941 case ISD::FrameIndex: return SelectFrameIndex(N);
942 case ISD::BITCAST: return SelectBitcast(N);
943 case ISD::SHL: return SelectSHL(N);
944 case ISD::LOAD: return SelectLoad(N);
945 case ISD::STORE: return SelectStore(N);
946 case ISD::MUL: return SelectMul(N);
947 case ISD::ZERO_EXTEND: return SelectZeroExtend(N);
948 case ISD::INTRINSIC_W_CHAIN: return SelectIntrinsicWChain(N);
949 case ISD::INTRINSIC_WO_CHAIN: return SelectIntrinsicWOChain(N);
Tony Linthicum1213a7a2011-12-12 21:14:40 +0000950 }
951
Justin Bognerec37a022016-05-12 21:46:18 +0000952 SelectCode(N);
Tony Linthicum1213a7a2011-12-12 21:14:40 +0000953}
954
Tony Linthicum1213a7a2011-12-12 21:14:40 +0000955bool HexagonDAGToDAGISel::
Daniel Sanders60f1db02015-03-13 12:45:09 +0000956SelectInlineAsmMemoryOperand(const SDValue &Op, unsigned ConstraintID,
Tony Linthicum1213a7a2011-12-12 21:14:40 +0000957 std::vector<SDValue> &OutOps) {
Krzysztof Parzyszeka29622a2015-03-12 16:44:50 +0000958 SDValue Inp = Op, Res;
Tony Linthicum1213a7a2011-12-12 21:14:40 +0000959
Daniel Sanders60f1db02015-03-13 12:45:09 +0000960 switch (ConstraintID) {
Krzysztof Parzyszeka29622a2015-03-12 16:44:50 +0000961 default:
962 return true;
Daniel Sanders49f643c2015-03-17 14:37:39 +0000963 case InlineAsm::Constraint_i:
964 case InlineAsm::Constraint_o: // Offsetable.
965 case InlineAsm::Constraint_v: // Not offsetable.
966 case InlineAsm::Constraint_m: // Memory.
Krzysztof Parzyszeka29622a2015-03-12 16:44:50 +0000967 if (SelectAddrFI(Inp, Res))
968 OutOps.push_back(Res);
969 else
970 OutOps.push_back(Inp);
Tony Linthicum1213a7a2011-12-12 21:14:40 +0000971 break;
972 }
973
Sergey Dmitrouk842a51b2015-04-28 14:05:47 +0000974 OutOps.push_back(CurDAG->getTargetConstant(0, SDLoc(Op), MVT::i32));
Jyotsna Vermad9225242013-02-13 21:38:46 +0000975 return false;
976}
Colin LeMahieuc7522f32015-01-14 23:07:36 +0000977
Colin LeMahieu79ec0652015-06-12 19:57:32 +0000978
Krzysztof Parzyszekae14e7b2015-03-17 21:47:16 +0000979void HexagonDAGToDAGISel::PreprocessISelDAG() {
980 SelectionDAG &DAG = *CurDAG;
981 std::vector<SDNode*> Nodes;
Pete Cooper7e64ef02015-07-14 23:43:29 +0000982 for (SDNode &Node : DAG.allnodes())
983 Nodes.push_back(&Node);
Krzysztof Parzyszekae14e7b2015-03-17 21:47:16 +0000984
985 // Simplify: (or (select c x 0) z) -> (select c (or x z) z)
986 // (or (select c 0 y) z) -> (select c z (or y z))
987 // This may not be the right thing for all targets, so do it here.
Krzysztof Parzyszekf7f70682016-06-22 20:08:27 +0000988 for (auto I : Nodes) {
Krzysztof Parzyszekae14e7b2015-03-17 21:47:16 +0000989 if (I->getOpcode() != ISD::OR)
990 continue;
991
992 auto IsZero = [] (const SDValue &V) -> bool {
993 if (ConstantSDNode *SC = dyn_cast<ConstantSDNode>(V.getNode()))
994 return SC->isNullValue();
995 return false;
996 };
997 auto IsSelect0 = [IsZero] (const SDValue &Op) -> bool {
998 if (Op.getOpcode() != ISD::SELECT)
999 return false;
Krzysztof Parzyszek7d5b4db2016-02-12 17:01:51 +00001000 return IsZero(Op.getOperand(1)) || IsZero(Op.getOperand(2));
Krzysztof Parzyszekae14e7b2015-03-17 21:47:16 +00001001 };
1002
1003 SDValue N0 = I->getOperand(0), N1 = I->getOperand(1);
1004 EVT VT = I->getValueType(0);
1005 bool SelN0 = IsSelect0(N0);
1006 SDValue SOp = SelN0 ? N0 : N1;
1007 SDValue VOp = SelN0 ? N1 : N0;
1008
1009 if (SOp.getOpcode() == ISD::SELECT && SOp.getNode()->hasOneUse()) {
1010 SDValue SC = SOp.getOperand(0);
1011 SDValue SX = SOp.getOperand(1);
1012 SDValue SY = SOp.getOperand(2);
1013 SDLoc DLS = SOp;
1014 if (IsZero(SY)) {
1015 SDValue NewOr = DAG.getNode(ISD::OR, DLS, VT, SX, VOp);
1016 SDValue NewSel = DAG.getNode(ISD::SELECT, DLS, VT, SC, NewOr, VOp);
1017 DAG.ReplaceAllUsesWith(I, NewSel.getNode());
1018 } else if (IsZero(SX)) {
1019 SDValue NewOr = DAG.getNode(ISD::OR, DLS, VT, SY, VOp);
1020 SDValue NewSel = DAG.getNode(ISD::SELECT, DLS, VT, SC, VOp, NewOr);
1021 DAG.ReplaceAllUsesWith(I, NewSel.getNode());
1022 }
1023 }
1024 }
Krzysztof Parzyszekf7f70682016-06-22 20:08:27 +00001025
1026 // Transform: (store ch addr (add x (add (shl y c) e)))
1027 // to: (store ch addr (add x (shl (add y d) c))),
1028 // where e = (shl d c) for some integer d.
1029 // The purpose of this is to enable generation of loads/stores with
1030 // shifted addressing mode, i.e. mem(x+y<<#c). For that, the shift
1031 // value c must be 0, 1 or 2.
1032 for (auto I : Nodes) {
1033 if (I->getOpcode() != ISD::STORE)
1034 continue;
1035
1036 // I matched: (store ch addr Off)
1037 SDValue Off = I->getOperand(2);
1038 // Off needs to match: (add x (add (shl y c) (shl d c))))
1039 if (Off.getOpcode() != ISD::ADD)
1040 continue;
1041 // Off matched: (add x T0)
1042 SDValue T0 = Off.getOperand(1);
1043 // T0 needs to match: (add T1 T2):
1044 if (T0.getOpcode() != ISD::ADD)
1045 continue;
1046 // T0 matched: (add T1 T2)
1047 SDValue T1 = T0.getOperand(0);
1048 SDValue T2 = T0.getOperand(1);
1049 // T1 needs to match: (shl y c)
1050 if (T1.getOpcode() != ISD::SHL)
1051 continue;
1052 SDValue C = T1.getOperand(1);
1053 ConstantSDNode *CN = dyn_cast<ConstantSDNode>(C.getNode());
1054 if (CN == nullptr)
1055 continue;
1056 unsigned CV = CN->getZExtValue();
1057 if (CV > 2)
1058 continue;
1059 // T2 needs to match e, where e = (shl d c) for some d.
1060 ConstantSDNode *EN = dyn_cast<ConstantSDNode>(T2.getNode());
1061 if (EN == nullptr)
1062 continue;
1063 unsigned EV = EN->getZExtValue();
1064 if (EV % (1 << CV) != 0)
1065 continue;
1066 unsigned DV = EV / (1 << CV);
1067
1068 // Replace T0 with: (shl (add y d) c)
1069 SDLoc DL = SDLoc(I);
1070 EVT VT = T0.getValueType();
1071 SDValue D = DAG.getConstant(DV, DL, VT);
1072 // NewAdd = (add y d)
1073 SDValue NewAdd = DAG.getNode(ISD::ADD, DL, VT, T1.getOperand(0), D);
1074 // NewShl = (shl NewAdd c)
1075 SDValue NewShl = DAG.getNode(ISD::SHL, DL, VT, NewAdd, C);
1076 ReplaceNode(T0.getNode(), NewShl.getNode());
1077 }
Krzysztof Parzyszek0006e1a2016-07-29 15:15:35 +00001078
1079 if (EnableAddressRebalancing) {
1080 rebalanceAddressTrees();
1081
1082 DEBUG(
1083 dbgs() << "************* SelectionDAG after preprocessing: ***********\n";
1084 CurDAG->dump();
1085 dbgs() << "************* End SelectionDAG after preprocessing ********\n";
1086 );
1087 }
Krzysztof Parzyszekae14e7b2015-03-17 21:47:16 +00001088}
1089
Krzysztof Parzyszek4fa2a9f2015-04-22 16:43:53 +00001090void HexagonDAGToDAGISel::EmitFunctionEntryCode() {
1091 auto &HST = static_cast<const HexagonSubtarget&>(MF->getSubtarget());
1092 auto &HFI = *HST.getFrameLowering();
1093 if (!HFI.needsAligna(*MF))
1094 return;
Krzysztof Parzyszekae14e7b2015-03-17 21:47:16 +00001095
Matthias Braun941a7052016-07-28 18:40:00 +00001096 MachineFrameInfo &MFI = MF->getFrameInfo();
Duncan P. N. Exon Smitha72c6e22015-10-20 00:46:39 +00001097 MachineBasicBlock *EntryBB = &MF->front();
Krzysztof Parzyszek4fa2a9f2015-04-22 16:43:53 +00001098 unsigned AR = FuncInfo->CreateReg(MVT::i32);
Matthias Braun941a7052016-07-28 18:40:00 +00001099 unsigned MaxA = MFI.getMaxAlignment();
Krzysztof Parzyszek1d01a792016-08-16 18:08:40 +00001100 BuildMI(EntryBB, DebugLoc(), HII->get(Hexagon::PS_aligna), AR)
Krzysztof Parzyszek4fa2a9f2015-04-22 16:43:53 +00001101 .addImm(MaxA);
1102 MF->getInfo<HexagonMachineFunctionInfo>()->setStackAlignBaseVReg(AR);
1103}
1104
1105// Match a frame index that can be used in an addressing mode.
Colin LeMahieuc7522f32015-01-14 23:07:36 +00001106bool HexagonDAGToDAGISel::SelectAddrFI(SDValue& N, SDValue &R) {
1107 if (N.getOpcode() != ISD::FrameIndex)
1108 return false;
Krzysztof Parzyszek4fa2a9f2015-04-22 16:43:53 +00001109 auto &HFI = *HST->getFrameLowering();
Matthias Braun941a7052016-07-28 18:40:00 +00001110 MachineFrameInfo &MFI = MF->getFrameInfo();
Krzysztof Parzyszek4fa2a9f2015-04-22 16:43:53 +00001111 int FX = cast<FrameIndexSDNode>(N)->getIndex();
Matthias Braun941a7052016-07-28 18:40:00 +00001112 if (!MFI.isFixedObjectIndex(FX) && HFI.needsAligna(*MF))
Krzysztof Parzyszek4fa2a9f2015-04-22 16:43:53 +00001113 return false;
1114 R = CurDAG->getTargetFrameIndex(FX, MVT::i32);
Colin LeMahieuc7522f32015-01-14 23:07:36 +00001115 return true;
1116}
Colin LeMahieu0ee02fc2015-01-19 20:31:18 +00001117
Colin LeMahieu987b0942015-02-04 20:38:01 +00001118inline bool HexagonDAGToDAGISel::SelectAddrGA(SDValue &N, SDValue &R) {
1119 return SelectGlobalAddress(N, R, false);
1120}
1121
Colin LeMahieu51491352015-02-04 22:36:28 +00001122inline bool HexagonDAGToDAGISel::SelectAddrGP(SDValue &N, SDValue &R) {
1123 return SelectGlobalAddress(N, R, true);
1124}
1125
Colin LeMahieu987b0942015-02-04 20:38:01 +00001126bool HexagonDAGToDAGISel::SelectGlobalAddress(SDValue &N, SDValue &R,
1127 bool UseGP) {
1128 switch (N.getOpcode()) {
1129 case ISD::ADD: {
1130 SDValue N0 = N.getOperand(0);
1131 SDValue N1 = N.getOperand(1);
1132 unsigned GAOpc = N0.getOpcode();
1133 if (UseGP && GAOpc != HexagonISD::CONST32_GP)
1134 return false;
1135 if (!UseGP && GAOpc != HexagonISD::CONST32)
1136 return false;
1137 if (ConstantSDNode *Const = dyn_cast<ConstantSDNode>(N1)) {
1138 SDValue Addr = N0.getOperand(0);
1139 if (GlobalAddressSDNode *GA = dyn_cast<GlobalAddressSDNode>(Addr)) {
1140 if (GA->getOpcode() == ISD::TargetGlobalAddress) {
1141 uint64_t NewOff = GA->getOffset() + (uint64_t)Const->getSExtValue();
1142 R = CurDAG->getTargetGlobalAddress(GA->getGlobal(), SDLoc(Const),
1143 N.getValueType(), NewOff);
1144 return true;
1145 }
1146 }
1147 }
1148 break;
1149 }
1150 case HexagonISD::CONST32:
1151 // The operand(0) of CONST32 is TargetGlobalAddress, which is what we
1152 // want in the instruction.
1153 if (!UseGP)
1154 R = N.getOperand(0);
1155 return !UseGP;
1156 case HexagonISD::CONST32_GP:
1157 if (UseGP)
1158 R = N.getOperand(0);
1159 return UseGP;
1160 default:
1161 return false;
1162 }
1163
1164 return false;
1165}
1166
Krzysztof Parzyszeka29622a2015-03-12 16:44:50 +00001167bool HexagonDAGToDAGISel::isValueExtension(const SDValue &Val,
1168 unsigned FromBits, SDValue &Src) {
Colin LeMahieu0ee02fc2015-01-19 20:31:18 +00001169 unsigned Opc = Val.getOpcode();
1170 switch (Opc) {
1171 case ISD::SIGN_EXTEND:
1172 case ISD::ZERO_EXTEND:
1173 case ISD::ANY_EXTEND: {
1174 SDValue const &Op0 = Val.getOperand(0);
1175 EVT T = Op0.getValueType();
1176 if (T.isInteger() && T.getSizeInBits() == FromBits) {
1177 Src = Op0;
1178 return true;
1179 }
1180 break;
1181 }
1182 case ISD::SIGN_EXTEND_INREG:
1183 case ISD::AssertSext:
1184 case ISD::AssertZext:
1185 if (Val.getOperand(0).getValueType().isInteger()) {
1186 VTSDNode *T = cast<VTSDNode>(Val.getOperand(1));
1187 if (T->getVT().getSizeInBits() == FromBits) {
1188 Src = Val.getOperand(0);
1189 return true;
1190 }
1191 }
1192 break;
1193 case ISD::AND: {
1194 // Check if this is an AND with "FromBits" of lower bits set to 1.
1195 uint64_t FromMask = (1 << FromBits) - 1;
1196 if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(Val.getOperand(0))) {
1197 if (C->getZExtValue() == FromMask) {
1198 Src = Val.getOperand(1);
1199 return true;
1200 }
1201 }
1202 if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(Val.getOperand(1))) {
1203 if (C->getZExtValue() == FromMask) {
1204 Src = Val.getOperand(0);
1205 return true;
1206 }
1207 }
1208 break;
1209 }
1210 case ISD::OR:
1211 case ISD::XOR: {
1212 // OR/XOR with the lower "FromBits" bits set to 0.
1213 uint64_t FromMask = (1 << FromBits) - 1;
1214 if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(Val.getOperand(0))) {
1215 if ((C->getZExtValue() & FromMask) == 0) {
1216 Src = Val.getOperand(1);
1217 return true;
1218 }
1219 }
1220 if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(Val.getOperand(1))) {
1221 if ((C->getZExtValue() & FromMask) == 0) {
1222 Src = Val.getOperand(0);
1223 return true;
1224 }
1225 }
1226 }
1227 default:
1228 break;
1229 }
1230 return false;
1231}
Krzysztof Parzyszek2d65ea72016-03-28 15:43:03 +00001232
Krzysztof Parzyszekbba0bf72016-07-15 15:35:52 +00001233
Krzysztof Parzyszekb16a4e52016-11-14 20:53:09 +00001234bool HexagonDAGToDAGISel::isOrEquivalentToAdd(const SDNode *N) const {
Krzysztof Parzyszekbba0bf72016-07-15 15:35:52 +00001235 assert(N->getOpcode() == ISD::OR);
1236 auto *C = dyn_cast<ConstantSDNode>(N->getOperand(1));
1237 assert(C);
1238
1239 // Detect when "or" is used to add an offset to a stack object.
1240 if (auto *FN = dyn_cast<FrameIndexSDNode>(N->getOperand(0))) {
Matthias Braun941a7052016-07-28 18:40:00 +00001241 MachineFrameInfo &MFI = MF->getFrameInfo();
1242 unsigned A = MFI.getObjectAlignment(FN->getIndex());
Krzysztof Parzyszekbba0bf72016-07-15 15:35:52 +00001243 assert(isPowerOf2_32(A));
1244 int32_t Off = C->getSExtValue();
1245 // If the alleged offset fits in the zero bits guaranteed by
1246 // the alignment, then this or is really an add.
1247 return (Off >= 0) && (((A-1) & Off) == unsigned(Off));
1248 }
1249 return false;
1250}
1251
Krzysztof Parzyszek2d65ea72016-03-28 15:43:03 +00001252bool HexagonDAGToDAGISel::isAlignedMemNode(const MemSDNode *N) const {
1253 return N->getAlignment() >= N->getMemoryVT().getStoreSize();
1254}
Krzysztof Parzyszek0006e1a2016-07-29 15:15:35 +00001255
Krzysztof Parzyszek2839b292016-11-05 21:44:50 +00001256// Return true when the given node fits in a positive half word.
1257bool HexagonDAGToDAGISel::isPositiveHalfWord(const SDNode *N) const {
1258 if (const ConstantSDNode *CN = dyn_cast<const ConstantSDNode>(N)) {
1259 int64_t V = CN->getSExtValue();
1260 return V > 0 && isInt<16>(V);
1261 }
1262 if (N->getOpcode() == ISD::SIGN_EXTEND_INREG) {
1263 const VTSDNode *VN = dyn_cast<const VTSDNode>(N->getOperand(1));
1264 return VN->getVT().getSizeInBits() <= 16;
1265 }
1266 return false;
1267}
1268
Krzysztof Parzyszek0006e1a2016-07-29 15:15:35 +00001269////////////////////////////////////////////////////////////////////////////////
1270// Rebalancing of address calculation trees
1271
1272static bool isOpcodeHandled(const SDNode *N) {
1273 switch (N->getOpcode()) {
1274 case ISD::ADD:
1275 case ISD::MUL:
1276 return true;
1277 case ISD::SHL:
1278 // We only handle constant shifts because these can be easily flattened
1279 // into multiplications by 2^Op1.
1280 return isa<ConstantSDNode>(N->getOperand(1).getNode());
1281 default:
1282 return false;
1283 }
1284}
1285
1286/// \brief Return the weight of an SDNode
1287int HexagonDAGToDAGISel::getWeight(SDNode *N) {
1288 if (!isOpcodeHandled(N))
1289 return 1;
1290 assert(RootWeights.count(N) && "Cannot get weight of unseen root!");
1291 assert(RootWeights[N] != -1 && "Cannot get weight of unvisited root!");
1292 assert(RootWeights[N] != -2 && "Cannot get weight of RAWU'd root!");
1293 return RootWeights[N];
1294}
1295
1296int HexagonDAGToDAGISel::getHeight(SDNode *N) {
1297 if (!isOpcodeHandled(N))
1298 return 0;
1299 assert(RootWeights.count(N) && RootWeights[N] >= 0 &&
1300 "Cannot query height of unvisited/RAUW'd node!");
1301 return RootHeights[N];
1302}
1303
Benjamin Kramerb7d33112016-08-06 11:13:10 +00001304namespace {
Krzysztof Parzyszek0006e1a2016-07-29 15:15:35 +00001305struct WeightedLeaf {
1306 SDValue Value;
1307 int Weight;
1308 int InsertionOrder;
1309
1310 WeightedLeaf() : Value(SDValue()) { }
1311
1312 WeightedLeaf(SDValue Value, int Weight, int InsertionOrder) :
1313 Value(Value), Weight(Weight), InsertionOrder(InsertionOrder) {
1314 assert(Weight >= 0 && "Weight must be >= 0");
1315 }
1316
1317 static bool Compare(const WeightedLeaf &A, const WeightedLeaf &B) {
1318 assert(A.Value.getNode() && B.Value.getNode());
1319 return A.Weight == B.Weight ?
1320 (A.InsertionOrder > B.InsertionOrder) :
1321 (A.Weight > B.Weight);
1322 }
1323};
1324
1325/// A specialized priority queue for WeigthedLeaves. It automatically folds
1326/// constants and allows removal of non-top elements while maintaining the
1327/// priority order.
1328class LeafPrioQueue {
1329 SmallVector<WeightedLeaf, 8> Q;
1330 bool HaveConst;
1331 WeightedLeaf ConstElt;
1332 unsigned Opcode;
1333
1334public:
1335 bool empty() {
1336 return (!HaveConst && Q.empty());
1337 }
1338
1339 size_t size() {
1340 return Q.size() + HaveConst;
1341 }
1342
1343 bool hasConst() {
1344 return HaveConst;
1345 }
1346
1347 const WeightedLeaf &top() {
1348 if (HaveConst)
1349 return ConstElt;
1350 return Q.front();
1351 }
1352
1353 WeightedLeaf pop() {
1354 if (HaveConst) {
1355 HaveConst = false;
1356 return ConstElt;
1357 }
1358 std::pop_heap(Q.begin(), Q.end(), WeightedLeaf::Compare);
1359 return Q.pop_back_val();
1360 }
1361
1362 void push(WeightedLeaf L, bool SeparateConst=true) {
1363 if (!HaveConst && SeparateConst && isa<ConstantSDNode>(L.Value)) {
1364 if (Opcode == ISD::MUL &&
1365 cast<ConstantSDNode>(L.Value)->getSExtValue() == 1)
1366 return;
1367 if (Opcode == ISD::ADD &&
1368 cast<ConstantSDNode>(L.Value)->getSExtValue() == 0)
1369 return;
1370
1371 HaveConst = true;
1372 ConstElt = L;
1373 } else {
1374 Q.push_back(L);
1375 std::push_heap(Q.begin(), Q.end(), WeightedLeaf::Compare);
1376 }
1377 }
1378
1379 /// Push L to the bottom of the queue regardless of its weight. If L is
1380 /// constant, it will not be folded with other constants in the queue.
1381 void pushToBottom(WeightedLeaf L) {
1382 L.Weight = 1000;
1383 push(L, false);
1384 }
1385
1386 /// Search for a SHL(x, [<=MaxAmount]) subtree in the queue, return the one of
1387 /// lowest weight and remove it from the queue.
1388 WeightedLeaf findSHL(uint64_t MaxAmount);
1389
1390 WeightedLeaf findMULbyConst();
1391
1392 LeafPrioQueue(unsigned Opcode) :
1393 HaveConst(false), Opcode(Opcode) { }
1394};
Benjamin Kramerb7d33112016-08-06 11:13:10 +00001395} // end anonymous namespace
Krzysztof Parzyszek0006e1a2016-07-29 15:15:35 +00001396
1397WeightedLeaf LeafPrioQueue::findSHL(uint64_t MaxAmount) {
1398 int ResultPos;
1399 WeightedLeaf Result;
1400
1401 for (int Pos = 0, End = Q.size(); Pos != End; ++Pos) {
1402 const WeightedLeaf &L = Q[Pos];
1403 const SDValue &Val = L.Value;
1404 if (Val.getOpcode() != ISD::SHL ||
1405 !isa<ConstantSDNode>(Val.getOperand(1)) ||
1406 Val.getConstantOperandVal(1) > MaxAmount)
1407 continue;
1408 if (!Result.Value.getNode() || Result.Weight > L.Weight ||
1409 (Result.Weight == L.Weight && Result.InsertionOrder > L.InsertionOrder))
1410 {
1411 Result = L;
1412 ResultPos = Pos;
1413 }
1414 }
1415
1416 if (Result.Value.getNode()) {
1417 Q.erase(&Q[ResultPos]);
1418 std::make_heap(Q.begin(), Q.end(), WeightedLeaf::Compare);
1419 }
1420
1421 return Result;
1422}
1423
1424WeightedLeaf LeafPrioQueue::findMULbyConst() {
1425 int ResultPos;
1426 WeightedLeaf Result;
1427
1428 for (int Pos = 0, End = Q.size(); Pos != End; ++Pos) {
1429 const WeightedLeaf &L = Q[Pos];
1430 const SDValue &Val = L.Value;
1431 if (Val.getOpcode() != ISD::MUL ||
1432 !isa<ConstantSDNode>(Val.getOperand(1)) ||
1433 Val.getConstantOperandVal(1) > 127)
1434 continue;
1435 if (!Result.Value.getNode() || Result.Weight > L.Weight ||
1436 (Result.Weight == L.Weight && Result.InsertionOrder > L.InsertionOrder))
1437 {
1438 Result = L;
1439 ResultPos = Pos;
1440 }
1441 }
1442
1443 if (Result.Value.getNode()) {
1444 Q.erase(&Q[ResultPos]);
1445 std::make_heap(Q.begin(), Q.end(), WeightedLeaf::Compare);
1446 }
1447
1448 return Result;
1449}
1450
1451SDValue HexagonDAGToDAGISel::getMultiplierForSHL(SDNode *N) {
Simon Pilgrim7c858622016-07-29 18:43:59 +00001452 uint64_t MulFactor = 1ull << N->getConstantOperandVal(1);
Krzysztof Parzyszek0006e1a2016-07-29 15:15:35 +00001453 return CurDAG->getConstant(MulFactor, SDLoc(N),
1454 N->getOperand(1).getValueType());
1455}
1456
1457/// @returns the value x for which 2^x is a factor of Val
1458static unsigned getPowerOf2Factor(SDValue Val) {
1459 if (Val.getOpcode() == ISD::MUL) {
1460 unsigned MaxFactor = 0;
Krzysztof Parzyszek317d42c2016-08-01 20:31:50 +00001461 for (int i = 0; i < 2; ++i) {
Krzysztof Parzyszek0006e1a2016-07-29 15:15:35 +00001462 ConstantSDNode *C = dyn_cast<ConstantSDNode>(Val.getOperand(i));
1463 if (!C)
1464 continue;
1465 const APInt &CInt = C->getAPIntValue();
1466 if (CInt.getBoolValue())
1467 MaxFactor = CInt.countTrailingZeros();
1468 }
1469 return MaxFactor;
1470 }
1471 if (Val.getOpcode() == ISD::SHL) {
1472 if (!isa<ConstantSDNode>(Val.getOperand(1).getNode()))
1473 return 0;
1474 return (unsigned) Val.getConstantOperandVal(1);
1475 }
1476
1477 return 0;
1478}
1479
1480/// @returns true if V>>Amount will eliminate V's operation on its child
1481static bool willShiftRightEliminate(SDValue V, unsigned Amount) {
1482 if (V.getOpcode() == ISD::MUL) {
1483 SDValue Ops[] = { V.getOperand(0), V.getOperand(1) };
Krzysztof Parzyszek317d42c2016-08-01 20:31:50 +00001484 for (int i = 0; i < 2; ++i)
Krzysztof Parzyszek0006e1a2016-07-29 15:15:35 +00001485 if (isa<ConstantSDNode>(Ops[i].getNode()) &&
Krzysztof Parzyszek317d42c2016-08-01 20:31:50 +00001486 V.getConstantOperandVal(i) % (1ULL << Amount) == 0) {
Krzysztof Parzyszek0006e1a2016-07-29 15:15:35 +00001487 uint64_t NewConst = V.getConstantOperandVal(i) >> Amount;
1488 return (NewConst == 1);
1489 }
1490 } else if (V.getOpcode() == ISD::SHL) {
1491 return (Amount == V.getConstantOperandVal(1));
1492 }
1493
1494 return false;
1495}
1496
1497SDValue HexagonDAGToDAGISel::factorOutPowerOf2(SDValue V, unsigned Power) {
1498 SDValue Ops[] = { V.getOperand(0), V.getOperand(1) };
1499 if (V.getOpcode() == ISD::MUL) {
1500 for (int i=0; i < 2; ++i) {
1501 if (isa<ConstantSDNode>(Ops[i].getNode()) &&
1502 V.getConstantOperandVal(i) % ((uint64_t)1 << Power) == 0) {
1503 uint64_t NewConst = V.getConstantOperandVal(i) >> Power;
1504 if (NewConst == 1)
1505 return Ops[!i];
1506 Ops[i] = CurDAG->getConstant(NewConst,
1507 SDLoc(V), V.getValueType());
1508 break;
1509 }
1510 }
1511 } else if (V.getOpcode() == ISD::SHL) {
1512 uint64_t ShiftAmount = V.getConstantOperandVal(1);
1513 if (ShiftAmount == Power)
1514 return Ops[0];
1515 Ops[1] = CurDAG->getConstant(ShiftAmount - Power,
1516 SDLoc(V), V.getValueType());
1517 }
1518
1519 return CurDAG->getNode(V.getOpcode(), SDLoc(V), V.getValueType(), Ops);
1520}
1521
1522static bool isTargetConstant(const SDValue &V) {
1523 return V.getOpcode() == HexagonISD::CONST32 ||
1524 V.getOpcode() == HexagonISD::CONST32_GP;
1525}
1526
1527unsigned HexagonDAGToDAGISel::getUsesInFunction(const Value *V) {
1528 if (GAUsesInFunction.count(V))
1529 return GAUsesInFunction[V];
1530
1531 unsigned Result = 0;
1532 const Function *CurF = CurDAG->getMachineFunction().getFunction();
1533 for (const User *U : V->users()) {
1534 if (isa<Instruction>(U) &&
1535 cast<Instruction>(U)->getParent()->getParent() == CurF)
1536 ++Result;
1537 }
1538
1539 GAUsesInFunction[V] = Result;
1540
1541 return Result;
1542}
1543
1544/// Note - After calling this, N may be dead. It may have been replaced by a
1545/// new node, so always use the returned value in place of N.
1546///
1547/// @returns The SDValue taking the place of N (which could be N if it is
1548/// unchanged)
1549SDValue HexagonDAGToDAGISel::balanceSubTree(SDNode *N, bool TopLevel) {
1550 assert(RootWeights.count(N) && "Cannot balance non-root node.");
1551 assert(RootWeights[N] != -2 && "This node was RAUW'd!");
1552 assert(!TopLevel || N->getOpcode() == ISD::ADD);
1553
1554 // Return early if this node was already visited
1555 if (RootWeights[N] != -1)
1556 return SDValue(N, 0);
1557
1558 assert(isOpcodeHandled(N));
1559
1560 SDValue Op0 = N->getOperand(0);
1561 SDValue Op1 = N->getOperand(1);
1562
1563 // Return early if the operands will remain unchanged or are all roots
1564 if ((!isOpcodeHandled(Op0.getNode()) || RootWeights.count(Op0.getNode())) &&
1565 (!isOpcodeHandled(Op1.getNode()) || RootWeights.count(Op1.getNode()))) {
1566 SDNode *Op0N = Op0.getNode();
1567 int Weight;
1568 if (isOpcodeHandled(Op0N) && RootWeights[Op0N] == -1) {
1569 Weight = getWeight(balanceSubTree(Op0N).getNode());
1570 // Weight = calculateWeight(Op0N);
1571 } else
1572 Weight = getWeight(Op0N);
1573
1574 SDNode *Op1N = N->getOperand(1).getNode(); // Op1 may have been RAUWd
1575 if (isOpcodeHandled(Op1N) && RootWeights[Op1N] == -1) {
1576 Weight += getWeight(balanceSubTree(Op1N).getNode());
1577 // Weight += calculateWeight(Op1N);
1578 } else
1579 Weight += getWeight(Op1N);
1580
1581 RootWeights[N] = Weight;
1582 RootHeights[N] = std::max(getHeight(N->getOperand(0).getNode()),
1583 getHeight(N->getOperand(1).getNode())) + 1;
1584
1585 DEBUG(dbgs() << "--> No need to balance root (Weight=" << Weight
1586 << " Height=" << RootHeights[N] << "): ");
1587 DEBUG(N->dump());
1588
1589 return SDValue(N, 0);
1590 }
1591
1592 DEBUG(dbgs() << "** Balancing root node: ");
1593 DEBUG(N->dump());
1594
1595 unsigned NOpcode = N->getOpcode();
1596
1597 LeafPrioQueue Leaves(NOpcode);
1598 SmallVector<SDValue, 4> Worklist;
1599 Worklist.push_back(SDValue(N, 0));
1600
1601 // SHL nodes will be converted to MUL nodes
1602 if (NOpcode == ISD::SHL)
1603 NOpcode = ISD::MUL;
1604
1605 bool CanFactorize = false;
1606 WeightedLeaf Mul1, Mul2;
1607 unsigned MaxPowerOf2 = 0;
1608 WeightedLeaf GA;
1609
1610 // Do not try to factor out a shift if there is already a shift at the tip of
1611 // the tree.
1612 bool HaveTopLevelShift = false;
1613 if (TopLevel &&
1614 ((isOpcodeHandled(Op0.getNode()) && Op0.getOpcode() == ISD::SHL &&
1615 Op0.getConstantOperandVal(1) < 4) ||
1616 (isOpcodeHandled(Op1.getNode()) && Op1.getOpcode() == ISD::SHL &&
1617 Op1.getConstantOperandVal(1) < 4)))
1618 HaveTopLevelShift = true;
1619
1620 // Flatten the subtree into an ordered list of leaves; at the same time
1621 // determine whether the tree is already balanced.
1622 int InsertionOrder = 0;
1623 SmallDenseMap<SDValue, int> NodeHeights;
1624 bool Imbalanced = false;
1625 int CurrentWeight = 0;
1626 while (!Worklist.empty()) {
1627 SDValue Child = Worklist.pop_back_val();
1628
1629 if (Child.getNode() != N && RootWeights.count(Child.getNode())) {
1630 // CASE 1: Child is a root note
1631
1632 int Weight = RootWeights[Child.getNode()];
1633 if (Weight == -1) {
1634 Child = balanceSubTree(Child.getNode());
1635 // calculateWeight(Child.getNode());
1636 Weight = getWeight(Child.getNode());
1637 } else if (Weight == -2) {
1638 // Whoops, this node was RAUWd by one of the balanceSubTree calls we
1639 // made. Our worklist isn't up to date anymore.
1640 // Restart the whole process.
1641 DEBUG(dbgs() << "--> Subtree was RAUWd. Restarting...\n");
1642 return balanceSubTree(N, TopLevel);
1643 }
1644
1645 NodeHeights[Child] = 1;
1646 CurrentWeight += Weight;
1647
1648 unsigned PowerOf2;
1649 if (TopLevel && !CanFactorize && !HaveTopLevelShift &&
1650 (Child.getOpcode() == ISD::MUL || Child.getOpcode() == ISD::SHL) &&
1651 Child.hasOneUse() && (PowerOf2 = getPowerOf2Factor(Child))) {
1652 // Try to identify two factorizable MUL/SHL children greedily. Leave
1653 // them out of the priority queue for now so we can deal with them
1654 // after.
1655 if (!Mul1.Value.getNode()) {
1656 Mul1 = WeightedLeaf(Child, Weight, InsertionOrder++);
1657 MaxPowerOf2 = PowerOf2;
1658 } else {
1659 Mul2 = WeightedLeaf(Child, Weight, InsertionOrder++);
1660 MaxPowerOf2 = std::min(MaxPowerOf2, PowerOf2);
1661
1662 // Our addressing modes can only shift by a maximum of 3
1663 if (MaxPowerOf2 > 3)
1664 MaxPowerOf2 = 3;
1665
1666 CanFactorize = true;
1667 }
1668 } else
1669 Leaves.push(WeightedLeaf(Child, Weight, InsertionOrder++));
1670 } else if (!isOpcodeHandled(Child.getNode())) {
1671 // CASE 2: Child is an unhandled kind of node (e.g. constant)
1672 int Weight = getWeight(Child.getNode());
1673
1674 NodeHeights[Child] = getHeight(Child.getNode());
1675 CurrentWeight += Weight;
1676
1677 if (isTargetConstant(Child) && !GA.Value.getNode())
1678 GA = WeightedLeaf(Child, Weight, InsertionOrder++);
1679 else
1680 Leaves.push(WeightedLeaf(Child, Weight, InsertionOrder++));
1681 } else {
1682 // CASE 3: Child is a subtree of same opcode
1683 // Visit children first, then flatten.
1684 unsigned ChildOpcode = Child.getOpcode();
1685 assert(ChildOpcode == NOpcode ||
1686 (NOpcode == ISD::MUL && ChildOpcode == ISD::SHL));
1687
1688 // Convert SHL to MUL
1689 SDValue Op1;
1690 if (ChildOpcode == ISD::SHL)
1691 Op1 = getMultiplierForSHL(Child.getNode());
1692 else
1693 Op1 = Child->getOperand(1);
1694
1695 if (!NodeHeights.count(Op1) || !NodeHeights.count(Child->getOperand(0))) {
1696 assert(!NodeHeights.count(Child) && "Parent visited before children?");
1697 // Visit children first, then re-visit this node
1698 Worklist.push_back(Child);
1699 Worklist.push_back(Op1);
1700 Worklist.push_back(Child->getOperand(0));
1701 } else {
1702 // Back at this node after visiting the children
1703 if (std::abs(NodeHeights[Op1] - NodeHeights[Child->getOperand(0)]) > 1)
1704 Imbalanced = true;
1705
1706 NodeHeights[Child] = std::max(NodeHeights[Op1],
1707 NodeHeights[Child->getOperand(0)]) + 1;
1708 }
1709 }
1710 }
1711
1712 DEBUG(dbgs() << "--> Current height=" << NodeHeights[SDValue(N, 0)]
1713 << " weight=" << CurrentWeight << " imbalanced="
1714 << Imbalanced << "\n");
1715
1716 // Transform MUL(x, C * 2^Y) + SHL(z, Y) -> SHL(ADD(MUL(x, C), z), Y)
1717 // This factors out a shift in order to match memw(a<<Y+b).
1718 if (CanFactorize && (willShiftRightEliminate(Mul1.Value, MaxPowerOf2) ||
1719 willShiftRightEliminate(Mul2.Value, MaxPowerOf2))) {
1720 DEBUG(dbgs() << "--> Found common factor for two MUL children!\n");
1721 int Weight = Mul1.Weight + Mul2.Weight;
1722 int Height = std::max(NodeHeights[Mul1.Value], NodeHeights[Mul2.Value]) + 1;
1723 SDValue Mul1Factored = factorOutPowerOf2(Mul1.Value, MaxPowerOf2);
1724 SDValue Mul2Factored = factorOutPowerOf2(Mul2.Value, MaxPowerOf2);
1725 SDValue Sum = CurDAG->getNode(ISD::ADD, SDLoc(N), Mul1.Value.getValueType(),
1726 Mul1Factored, Mul2Factored);
1727 SDValue Const = CurDAG->getConstant(MaxPowerOf2, SDLoc(N),
1728 Mul1.Value.getValueType());
1729 SDValue New = CurDAG->getNode(ISD::SHL, SDLoc(N), Mul1.Value.getValueType(),
1730 Sum, Const);
1731 NodeHeights[New] = Height;
1732 Leaves.push(WeightedLeaf(New, Weight, Mul1.InsertionOrder));
1733 } else if (Mul1.Value.getNode()) {
1734 // We failed to factorize two MULs, so now the Muls are left outside the
1735 // queue... add them back.
1736 Leaves.push(Mul1);
1737 if (Mul2.Value.getNode())
1738 Leaves.push(Mul2);
1739 CanFactorize = false;
1740 }
1741
1742 // Combine GA + Constant -> GA+Offset, but only if GA is not used elsewhere
1743 // and the root node itself is not used more than twice. This reduces the
1744 // amount of additional constant extenders introduced by this optimization.
1745 bool CombinedGA = false;
1746 if (NOpcode == ISD::ADD && GA.Value.getNode() && Leaves.hasConst() &&
1747 GA.Value.hasOneUse() && N->use_size() < 3) {
1748 GlobalAddressSDNode *GANode =
1749 cast<GlobalAddressSDNode>(GA.Value.getOperand(0));
1750 ConstantSDNode *Offset = cast<ConstantSDNode>(Leaves.top().Value);
1751
1752 if (getUsesInFunction(GANode->getGlobal()) == 1 && Offset->hasOneUse() &&
1753 getTargetLowering()->isOffsetFoldingLegal(GANode)) {
1754 DEBUG(dbgs() << "--> Combining GA and offset (" << Offset->getSExtValue()
1755 << "): ");
1756 DEBUG(GANode->dump());
1757
1758 SDValue NewTGA =
1759 CurDAG->getTargetGlobalAddress(GANode->getGlobal(), SDLoc(GA.Value),
1760 GANode->getValueType(0),
1761 GANode->getOffset() + (uint64_t)Offset->getSExtValue());
1762 GA.Value = CurDAG->getNode(GA.Value.getOpcode(), SDLoc(GA.Value),
1763 GA.Value.getValueType(), NewTGA);
1764 GA.Weight += Leaves.top().Weight;
1765
1766 NodeHeights[GA.Value] = getHeight(GA.Value.getNode());
1767 CombinedGA = true;
1768
1769 Leaves.pop(); // Remove the offset constant from the queue
1770 }
1771 }
1772
1773 if ((RebalanceOnlyForOptimizations && !CanFactorize && !CombinedGA) ||
1774 (RebalanceOnlyImbalancedTrees && !Imbalanced)) {
1775 RootWeights[N] = CurrentWeight;
1776 RootHeights[N] = NodeHeights[SDValue(N, 0)];
1777
1778 return SDValue(N, 0);
1779 }
1780
1781 // Combine GA + SHL(x, C<=31) so we will match Rx=add(#u8,asl(Rx,#U5))
1782 if (NOpcode == ISD::ADD && GA.Value.getNode()) {
1783 WeightedLeaf SHL = Leaves.findSHL(31);
1784 if (SHL.Value.getNode()) {
1785 int Height = std::max(NodeHeights[GA.Value], NodeHeights[SHL.Value]) + 1;
1786 GA.Value = CurDAG->getNode(ISD::ADD, SDLoc(GA.Value),
1787 GA.Value.getValueType(),
1788 GA.Value, SHL.Value);
1789 GA.Weight = SHL.Weight; // Specifically ignore the GA weight here
1790 NodeHeights[GA.Value] = Height;
1791 }
1792 }
1793
1794 if (GA.Value.getNode())
1795 Leaves.push(GA);
1796
1797 // If this is the top level and we haven't factored out a shift, we should try
1798 // to move a constant to the bottom to match addressing modes like memw(rX+C)
1799 if (TopLevel && !CanFactorize && Leaves.hasConst()) {
1800 DEBUG(dbgs() << "--> Pushing constant to tip of tree.");
1801 Leaves.pushToBottom(Leaves.pop());
1802 }
1803
Krzysztof Parzyszek317d42c2016-08-01 20:31:50 +00001804 const DataLayout &DL = CurDAG->getDataLayout();
1805 const TargetLowering &TLI = *getTargetLowering();
1806
Krzysztof Parzyszek0006e1a2016-07-29 15:15:35 +00001807 // Rebuild the tree using Huffman's algorithm
1808 while (Leaves.size() > 1) {
1809 WeightedLeaf L0 = Leaves.pop();
1810
1811 // See whether we can grab a MUL to form an add(Rx,mpyi(Ry,#u6)),
1812 // otherwise just get the next leaf
1813 WeightedLeaf L1 = Leaves.findMULbyConst();
1814 if (!L1.Value.getNode())
1815 L1 = Leaves.pop();
1816
1817 assert(L0.Weight <= L1.Weight && "Priority queue is broken!");
1818
1819 SDValue V0 = L0.Value;
1820 int V0Weight = L0.Weight;
1821 SDValue V1 = L1.Value;
1822 int V1Weight = L1.Weight;
1823
1824 // Make sure that none of these nodes have been RAUW'd
1825 if ((RootWeights.count(V0.getNode()) && RootWeights[V0.getNode()] == -2) ||
1826 (RootWeights.count(V1.getNode()) && RootWeights[V1.getNode()] == -2)) {
1827 DEBUG(dbgs() << "--> Subtree was RAUWd. Restarting...\n");
1828 return balanceSubTree(N, TopLevel);
1829 }
1830
1831 ConstantSDNode *V0C = dyn_cast<ConstantSDNode>(V0);
1832 ConstantSDNode *V1C = dyn_cast<ConstantSDNode>(V1);
1833 EVT VT = N->getValueType(0);
1834 SDValue NewNode;
1835
1836 if (V0C && !V1C) {
1837 std::swap(V0, V1);
1838 std::swap(V0C, V1C);
1839 }
1840
1841 // Calculate height of this node
1842 assert(NodeHeights.count(V0) && NodeHeights.count(V1) &&
1843 "Children must have been visited before re-combining them!");
1844 int Height = std::max(NodeHeights[V0], NodeHeights[V1]) + 1;
1845
1846 // Rebuild this node (and restore SHL from MUL if needed)
1847 if (V1C && NOpcode == ISD::MUL && V1C->getAPIntValue().isPowerOf2())
1848 NewNode = CurDAG->getNode(
1849 ISD::SHL, SDLoc(V0), VT, V0,
1850 CurDAG->getConstant(
1851 V1C->getAPIntValue().logBase2(), SDLoc(N),
Krzysztof Parzyszek317d42c2016-08-01 20:31:50 +00001852 TLI.getScalarShiftAmountTy(DL, V0.getValueType())));
Krzysztof Parzyszek0006e1a2016-07-29 15:15:35 +00001853 else
1854 NewNode = CurDAG->getNode(NOpcode, SDLoc(N), VT, V0, V1);
1855
1856 NodeHeights[NewNode] = Height;
1857
1858 int Weight = V0Weight + V1Weight;
1859 Leaves.push(WeightedLeaf(NewNode, Weight, L0.InsertionOrder));
1860
1861 DEBUG(dbgs() << "--> Built new node (Weight=" << Weight << ",Height="
1862 << Height << "):\n");
1863 DEBUG(NewNode.dump());
1864 }
1865
1866 assert(Leaves.size() == 1);
1867 SDValue NewRoot = Leaves.top().Value;
1868
1869 assert(NodeHeights.count(NewRoot));
1870 int Height = NodeHeights[NewRoot];
1871
1872 // Restore SHL if we earlier converted it to a MUL
1873 if (NewRoot.getOpcode() == ISD::MUL) {
1874 ConstantSDNode *V1C = dyn_cast<ConstantSDNode>(NewRoot.getOperand(1));
1875 if (V1C && V1C->getAPIntValue().isPowerOf2()) {
1876 EVT VT = NewRoot.getValueType();
1877 SDValue V0 = NewRoot.getOperand(0);
1878 NewRoot = CurDAG->getNode(
1879 ISD::SHL, SDLoc(NewRoot), VT, V0,
Krzysztof Parzyszek317d42c2016-08-01 20:31:50 +00001880 CurDAG->getConstant(
1881 V1C->getAPIntValue().logBase2(), SDLoc(NewRoot),
1882 TLI.getScalarShiftAmountTy(DL, V0.getValueType())));
Krzysztof Parzyszek0006e1a2016-07-29 15:15:35 +00001883 }
1884 }
1885
1886 if (N != NewRoot.getNode()) {
1887 DEBUG(dbgs() << "--> Root is now: ");
1888 DEBUG(NewRoot.dump());
1889
1890 // Replace all uses of old root by new root
1891 CurDAG->ReplaceAllUsesWith(N, NewRoot.getNode());
1892 // Mark that we have RAUW'd N
1893 RootWeights[N] = -2;
1894 } else {
1895 DEBUG(dbgs() << "--> Root unchanged.\n");
1896 }
1897
1898 RootWeights[NewRoot.getNode()] = Leaves.top().Weight;
1899 RootHeights[NewRoot.getNode()] = Height;
1900
1901 return NewRoot;
1902}
1903
1904void HexagonDAGToDAGISel::rebalanceAddressTrees() {
Krzysztof Parzyszek317d42c2016-08-01 20:31:50 +00001905 for (auto I = CurDAG->allnodes_begin(), E = CurDAG->allnodes_end(); I != E;) {
Krzysztof Parzyszek0006e1a2016-07-29 15:15:35 +00001906 SDNode *N = &*I++;
1907 if (N->getOpcode() != ISD::LOAD && N->getOpcode() != ISD::STORE)
1908 continue;
1909
1910 SDValue BasePtr = cast<MemSDNode>(N)->getBasePtr();
1911 if (BasePtr.getOpcode() != ISD::ADD)
1912 continue;
1913
1914 // We've already processed this node
1915 if (RootWeights.count(BasePtr.getNode()))
1916 continue;
1917
1918 DEBUG(dbgs() << "** Rebalancing address calculation in node: ");
1919 DEBUG(N->dump());
1920
1921 // FindRoots
1922 SmallVector<SDNode *, 4> Worklist;
1923
1924 Worklist.push_back(BasePtr.getOperand(0).getNode());
1925 Worklist.push_back(BasePtr.getOperand(1).getNode());
1926
1927 while (!Worklist.empty()) {
1928 SDNode *N = Worklist.pop_back_val();
1929 unsigned Opcode = N->getOpcode();
1930
1931 if (!isOpcodeHandled(N))
1932 continue;
1933
1934 Worklist.push_back(N->getOperand(0).getNode());
1935 Worklist.push_back(N->getOperand(1).getNode());
1936
1937 // Not a root if it has only one use and same opcode as its parent
1938 if (N->hasOneUse() && Opcode == N->use_begin()->getOpcode())
1939 continue;
1940
1941 // This root node has already been processed
1942 if (RootWeights.count(N))
1943 continue;
1944
1945 RootWeights[N] = -1;
1946 }
1947
1948 // Balance node itself
1949 RootWeights[BasePtr.getNode()] = -1;
1950 SDValue NewBasePtr = balanceSubTree(BasePtr.getNode(), /*TopLevel=*/ true);
1951
1952 if (N->getOpcode() == ISD::LOAD)
1953 N = CurDAG->UpdateNodeOperands(N, N->getOperand(0),
1954 NewBasePtr, N->getOperand(2));
1955 else
1956 N = CurDAG->UpdateNodeOperands(N, N->getOperand(0), N->getOperand(1),
1957 NewBasePtr, N->getOperand(3));
1958
1959 DEBUG(dbgs() << "--> Final node: ");
1960 DEBUG(N->dump());
1961 }
1962
1963 CurDAG->RemoveDeadNodes();
1964 GAUsesInFunction.clear();
1965 RootHeights.clear();
1966 RootWeights.clear();
1967}
1968