blob: cb1552104049f838221d8a0e7c9d935666c8e9e7 [file] [log] [blame]
Dylan McKayec470652016-10-27 07:03:47 +00001//===-- AVRISelDAGToDAG.cpp - A dag to dag inst selector for AVR ----------===//
2//
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 AVR target.
11//
12//===----------------------------------------------------------------------===//
13
14#include "AVR.h"
15#include "AVRTargetMachine.h"
16#include "MCTargetDesc/AVRMCTargetDesc.h"
17
18#include "llvm/CodeGen/MachineRegisterInfo.h"
19#include "llvm/CodeGen/SelectionDAGISel.h"
20#include "llvm/Support/Debug.h"
21#include "llvm/Support/raw_ostream.h"
22
23#define DEBUG_TYPE "avr-isel"
24
25namespace llvm {
26
27/// Lowers LLVM IR (in DAG form) to AVR MC instructions (in DAG form).
28class AVRDAGToDAGISel : public SelectionDAGISel {
29public:
30 AVRDAGToDAGISel(AVRTargetMachine &TM, CodeGenOpt::Level OptLevel)
31 : SelectionDAGISel(TM, OptLevel), Subtarget(nullptr) {}
32
33 StringRef getPassName() const override {
34 return "AVR DAG->DAG Instruction Selection";
35 }
36
37 bool runOnMachineFunction(MachineFunction &MF) override;
38
39 bool SelectAddr(SDNode *Op, SDValue N, SDValue &Base, SDValue &Disp);
40
41 bool selectIndexedLoad(SDNode *N);
42 unsigned selectIndexedProgMemLoad(const LoadSDNode *LD, MVT VT);
43
44 bool SelectInlineAsmMemoryOperand(const SDValue &Op, unsigned ConstraintCode,
45 std::vector<SDValue> &OutOps) override;
46
47// Include the pieces autogenerated from the target description.
48#include "AVRGenDAGISel.inc"
49
50private:
51 void Select(SDNode *N) override;
52 bool trySelect(SDNode *N);
53
54 template <unsigned NodeType> bool select(SDNode *N);
55 bool selectMultiplication(SDNode *N);
56
57 const AVRSubtarget *Subtarget;
58};
59
60bool AVRDAGToDAGISel::runOnMachineFunction(MachineFunction &MF) {
61 Subtarget = &MF.getSubtarget<AVRSubtarget>();
62 return SelectionDAGISel::runOnMachineFunction(MF);
63}
64
65bool AVRDAGToDAGISel::SelectAddr(SDNode *Op, SDValue N, SDValue &Base,
66 SDValue &Disp) {
67 SDLoc dl(Op);
68 auto DL = CurDAG->getDataLayout();
69 MVT PtrVT = getTargetLowering()->getPointerTy(DL);
70
71 // if the address is a frame index get the TargetFrameIndex.
72 if (const FrameIndexSDNode *FIN = dyn_cast<FrameIndexSDNode>(N)) {
73 Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), PtrVT);
74 Disp = CurDAG->getTargetConstant(0, dl, MVT::i8);
75
76 return true;
77 }
78
79 // Match simple Reg + uimm6 operands.
80 if (N.getOpcode() != ISD::ADD && N.getOpcode() != ISD::SUB &&
81 !CurDAG->isBaseWithConstantOffset(N)) {
82 return false;
83 }
84
85 if (const ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(N.getOperand(1))) {
86 int RHSC = (int)RHS->getZExtValue();
87
88 // Convert negative offsets into positives ones.
89 if (N.getOpcode() == ISD::SUB) {
90 RHSC = -RHSC;
91 }
92
93 // <#Frame index + const>
94 // Allow folding offsets bigger than 63 so the frame pointer can be used
95 // directly instead of copying it around by adjusting and restoring it for
96 // each access.
97 if (N.getOperand(0).getOpcode() == ISD::FrameIndex) {
98 int FI = cast<FrameIndexSDNode>(N.getOperand(0))->getIndex();
99
100 Base = CurDAG->getTargetFrameIndex(FI, PtrVT);
101 Disp = CurDAG->getTargetConstant(RHSC, dl, MVT::i16);
102
103 return true;
104 }
105
106 // The value type of the memory instruction determines what is the maximum
107 // offset allowed.
108 MVT VT = cast<MemSDNode>(Op)->getMemoryVT().getSimpleVT();
109
110 // We only accept offsets that fit in 6 bits (unsigned).
111 if (isUInt<6>(RHSC) && (VT == MVT::i8 || VT == MVT::i16)) {
112 Base = N.getOperand(0);
113 Disp = CurDAG->getTargetConstant(RHSC, dl, MVT::i8);
114
115 return true;
116 }
117 }
118
119 return false;
120}
121
122bool AVRDAGToDAGISel::selectIndexedLoad(SDNode *N) {
123 const LoadSDNode *LD = cast<LoadSDNode>(N);
124 ISD::MemIndexedMode AM = LD->getAddressingMode();
125 MVT VT = LD->getMemoryVT().getSimpleVT();
126 auto PtrVT = getTargetLowering()->getPointerTy(CurDAG->getDataLayout());
127
128 // We only care if this load uses a POSTINC or PREDEC mode.
129 if ((LD->getExtensionType() != ISD::NON_EXTLOAD) ||
130 (AM != ISD::POST_INC && AM != ISD::PRE_DEC)) {
131
132 return false;
133 }
134
135 unsigned Opcode = 0;
136 bool isPre = (AM == ISD::PRE_DEC);
137 int Offs = cast<ConstantSDNode>(LD->getOffset())->getSExtValue();
138
139 switch (VT.SimpleTy) {
140 case MVT::i8: {
141 if ((!isPre && Offs != 1) || (isPre && Offs != -1)) {
142 return false;
143 }
144
145 Opcode = (isPre) ? AVR::LDRdPtrPd : AVR::LDRdPtrPi;
146 break;
147 }
148 case MVT::i16: {
149 if ((!isPre && Offs != 2) || (isPre && Offs != -2)) {
150 return false;
151 }
152
153 Opcode = (isPre) ? AVR::LDWRdPtrPd : AVR::LDWRdPtrPi;
154 break;
155 }
156 default:
157 return false;
158 }
159
160 SDNode *ResNode = CurDAG->getMachineNode(Opcode, SDLoc(N), VT,
161 PtrVT, MVT::Other,
162 LD->getBasePtr(), LD->getChain());
163 ReplaceUses(N, ResNode);
164 CurDAG->RemoveDeadNode(N);
165
166 return true;
167}
168
169unsigned AVRDAGToDAGISel::selectIndexedProgMemLoad(const LoadSDNode *LD,
170 MVT VT) {
171 ISD::MemIndexedMode AM = LD->getAddressingMode();
172
173 // Progmem indexed loads only work in POSTINC mode.
174 if (LD->getExtensionType() != ISD::NON_EXTLOAD || AM != ISD::POST_INC) {
175 return 0;
176 }
177
178 unsigned Opcode = 0;
179 int Offs = cast<ConstantSDNode>(LD->getOffset())->getSExtValue();
180
181 switch (VT.SimpleTy) {
182 case MVT::i8: {
183 if (Offs != 1) {
184 return 0;
185 }
186 Opcode = AVR::LPMRdZPi;
187 break;
188 }
189 case MVT::i16: {
190 if (Offs != 2) {
191 return 0;
192 }
193 Opcode = AVR::LPMWRdZPi;
194 break;
195 }
196 default:
197 return 0;
198 }
199
200 return Opcode;
201}
202
203bool AVRDAGToDAGISel::SelectInlineAsmMemoryOperand(const SDValue &Op,
204 unsigned ConstraintCode,
205 std::vector<SDValue> &OutOps) {
206 // Yes hardcoded 'm' symbol. Just because it also has been hardcoded in
207 // SelectionDAGISel (callee for this method).
Dylan McKayd8a603c2016-12-10 11:49:07 +0000208 assert(ConstraintCode == InlineAsm::Constraint_m ||
209 ConstraintCode == InlineAsm::Constraint_Q &&
210 "Unexpected asm memory constraint");
Dylan McKayec470652016-10-27 07:03:47 +0000211
212 MachineRegisterInfo &RI = MF->getRegInfo();
213 const AVRSubtarget &STI = MF->getSubtarget<AVRSubtarget>();
214 const TargetLowering &TL = *STI.getTargetLowering();
215 SDLoc dl(Op);
216 auto DL = CurDAG->getDataLayout();
217
218 const RegisterSDNode *RegNode = dyn_cast<RegisterSDNode>(Op);
219
220 // If address operand is of PTRDISPREGS class, all is OK, then.
221 if (RegNode &&
222 RI.getRegClass(RegNode->getReg()) == &AVR::PTRDISPREGSRegClass) {
223 OutOps.push_back(Op);
224 return false;
225 }
226
227 if (Op->getOpcode() == ISD::FrameIndex) {
228 SDValue Base, Disp;
229
230 if (SelectAddr(Op.getNode(), Op, Base, Disp)) {
231 OutOps.push_back(Base);
232 OutOps.push_back(Disp);
233
234 return false;
235 }
236
237 return true;
238 }
239
240 // If Op is add 'register, immediate' and
241 // register is either virtual register or register of PTRDISPREGSRegClass
242 if (Op->getOpcode() == ISD::ADD || Op->getOpcode() == ISD::SUB) {
243 SDValue CopyFromRegOp = Op->getOperand(0);
244 SDValue ImmOp = Op->getOperand(1);
245 ConstantSDNode *ImmNode = dyn_cast<ConstantSDNode>(ImmOp);
246
247 unsigned Reg;
248 bool CanHandleRegImmOpt = true;
249
250 CanHandleRegImmOpt &= ImmNode != 0;
251 CanHandleRegImmOpt &= ImmNode->getAPIntValue().getZExtValue() < 64;
252
253 if (CopyFromRegOp->getOpcode() == ISD::CopyFromReg) {
254 RegisterSDNode *RegNode =
255 cast<RegisterSDNode>(CopyFromRegOp->getOperand(1));
256 Reg = RegNode->getReg();
257 CanHandleRegImmOpt &= (TargetRegisterInfo::isVirtualRegister(Reg) ||
258 AVR::PTRDISPREGSRegClass.contains(Reg));
259 } else {
260 CanHandleRegImmOpt = false;
261 }
262
263 // If we detect proper case - correct virtual register class
264 // if needed and go to another inlineasm operand.
265 if (CanHandleRegImmOpt) {
266 SDValue Base, Disp;
267
268 if (RI.getRegClass(Reg) != &AVR::PTRDISPREGSRegClass) {
269 SDLoc dl(CopyFromRegOp);
270
271 unsigned VReg = RI.createVirtualRegister(&AVR::PTRDISPREGSRegClass);
272
273 SDValue CopyToReg =
274 CurDAG->getCopyToReg(CopyFromRegOp, dl, VReg, CopyFromRegOp);
275
276 SDValue NewCopyFromRegOp =
277 CurDAG->getCopyFromReg(CopyToReg, dl, VReg, TL.getPointerTy(DL));
278
279 Base = NewCopyFromRegOp;
280 } else {
281 Base = CopyFromRegOp;
282 }
283
284 if (ImmNode->getValueType(0) != MVT::i8) {
285 Disp = CurDAG->getTargetConstant(ImmNode->getAPIntValue().getZExtValue(), dl, MVT::i8);
286 } else {
287 Disp = ImmOp;
288 }
289
290 OutOps.push_back(Base);
291 OutOps.push_back(Disp);
292
293 return false;
294 }
295 }
296
297 // More generic case.
298 // Create chain that puts Op into pointer register
299 // and return that register.
300 unsigned VReg = RI.createVirtualRegister(&AVR::PTRDISPREGSRegClass);
301
302 SDValue CopyToReg = CurDAG->getCopyToReg(Op, dl, VReg, Op);
303 SDValue CopyFromReg =
304 CurDAG->getCopyFromReg(CopyToReg, dl, VReg, TL.getPointerTy(DL));
305
306 OutOps.push_back(CopyFromReg);
307
308 return false;
309}
310
311template <> bool AVRDAGToDAGISel::select<ISD::FrameIndex>(SDNode *N) {
312 auto DL = CurDAG->getDataLayout();
313
314 // Convert the frameindex into a temp instruction that will hold the
315 // effective address of the final stack slot.
316 int FI = cast<FrameIndexSDNode>(N)->getIndex();
317 SDValue TFI =
318 CurDAG->getTargetFrameIndex(FI, getTargetLowering()->getPointerTy(DL));
319
320 CurDAG->SelectNodeTo(N, AVR::FRMIDX,
321 getTargetLowering()->getPointerTy(DL), TFI,
322 CurDAG->getTargetConstant(0, SDLoc(N), MVT::i16));
323 return true;
324}
325
326template <> bool AVRDAGToDAGISel::select<ISD::STORE>(SDNode *N) {
327 // Use the STD{W}SPQRr pseudo instruction when passing arguments through
328 // the stack on function calls for further expansion during the PEI phase.
329 const StoreSDNode *ST = cast<StoreSDNode>(N);
330 SDValue BasePtr = ST->getBasePtr();
331
332 // Early exit when the base pointer is a frame index node or a constant.
Dylan McKay5d0233b2016-12-10 10:16:13 +0000333 if (isa<FrameIndexSDNode>(BasePtr) || isa<ConstantSDNode>(BasePtr) ||
334 BasePtr.isUndef()) {
Dylan McKayec470652016-10-27 07:03:47 +0000335 return false;
336 }
337
338 const RegisterSDNode *RN = dyn_cast<RegisterSDNode>(BasePtr.getOperand(0));
339 // Only stores where SP is the base pointer are valid.
340 if (!RN || (RN->getReg() != AVR::SP)) {
341 return false;
342 }
343
344 int CST = (int)cast<ConstantSDNode>(BasePtr.getOperand(1))->getZExtValue();
345 SDValue Chain = ST->getChain();
346 EVT VT = ST->getValue().getValueType();
347 SDLoc DL(N);
348 SDValue Offset = CurDAG->getTargetConstant(CST, DL, MVT::i16);
349 SDValue Ops[] = {BasePtr.getOperand(0), Offset, ST->getValue(), Chain};
350 unsigned Opc = (VT == MVT::i16) ? AVR::STDWSPQRr : AVR::STDSPQRr;
351
352 SDNode *ResNode = CurDAG->getMachineNode(Opc, DL, MVT::Other, Ops);
353
354 // Transfer memory operands.
355 MachineSDNode::mmo_iterator MemOp = MF->allocateMemRefsArray(1);
356 MemOp[0] = ST->getMemOperand();
357 cast<MachineSDNode>(ResNode)->setMemRefs(MemOp, MemOp + 1);
358
359 ReplaceUses(SDValue(N, 0), SDValue(ResNode, 0));
360 CurDAG->RemoveDeadNode(N);
361
362 return true;
363}
364
365template <> bool AVRDAGToDAGISel::select<ISD::LOAD>(SDNode *N) {
366 const LoadSDNode *LD = cast<LoadSDNode>(N);
367 if (!AVR::isProgramMemoryAccess(LD)) {
368 // Check if the opcode can be converted into an indexed load.
369 return selectIndexedLoad(N);
370 }
371
Dylan McKayfac9ce52016-12-08 08:34:13 +0000372 assert(Subtarget->hasLPM() && "cannot load from program memory on this mcu");
373
Dylan McKayec470652016-10-27 07:03:47 +0000374 // This is a flash memory load, move the pointer into R31R30 and emit
375 // the lpm instruction.
376 MVT VT = LD->getMemoryVT().getSimpleVT();
377 SDValue Chain = LD->getChain();
378 SDValue Ptr = LD->getBasePtr();
379 SDNode *ResNode;
380 SDLoc DL(N);
381
382 Chain = CurDAG->getCopyToReg(Chain, DL, AVR::R31R30, Ptr, SDValue());
383 Ptr = CurDAG->getCopyFromReg(Chain, DL, AVR::R31R30, MVT::i16,
384 Chain.getValue(1));
385
386 SDValue RegZ = CurDAG->getRegister(AVR::R31R30, MVT::i16);
387
388 // Check if the opcode can be converted into an indexed load.
389 if (unsigned LPMOpc = selectIndexedProgMemLoad(LD, VT)) {
390 // It is legal to fold the load into an indexed load.
391 ResNode = CurDAG->getMachineNode(LPMOpc, DL, VT, MVT::i16, MVT::Other, Ptr,
392 RegZ);
393 ReplaceUses(SDValue(N, 1), SDValue(ResNode, 1));
394 } else {
395 // Selecting an indexed load is not legal, fallback to a normal load.
396 switch (VT.SimpleTy) {
397 case MVT::i8:
398 ResNode = CurDAG->getMachineNode(AVR::LPMRdZ, DL, MVT::i8, MVT::Other,
399 Ptr, RegZ);
400 break;
401 case MVT::i16:
402 ResNode = CurDAG->getMachineNode(AVR::LPMWRdZ, DL, MVT::i16,
403 MVT::Other, Ptr, RegZ);
404 ReplaceUses(SDValue(N, 1), SDValue(ResNode, 1));
405 break;
406 default:
407 llvm_unreachable("Unsupported VT!");
408 }
409 }
410
411 // Transfer memory operands.
412 MachineSDNode::mmo_iterator MemOp = MF->allocateMemRefsArray(1);
413 MemOp[0] = LD->getMemOperand();
414 cast<MachineSDNode>(ResNode)->setMemRefs(MemOp, MemOp + 1);
415
416 ReplaceUses(SDValue(N, 0), SDValue(ResNode, 0));
417 ReplaceUses(SDValue(N, 1), SDValue(ResNode, 1));
418 CurDAG->RemoveDeadNode(N);
419
420 return true;
421}
422
423template <> bool AVRDAGToDAGISel::select<AVRISD::CALL>(SDNode *N) {
424 SDValue InFlag;
425 SDValue Chain = N->getOperand(0);
426 SDValue Callee = N->getOperand(1);
427 unsigned LastOpNum = N->getNumOperands() - 1;
428
429 // Direct calls are autogenerated.
430 unsigned Op = Callee.getOpcode();
431 if (Op == ISD::TargetGlobalAddress || Op == ISD::TargetExternalSymbol) {
432 return false;
433 }
434
435 // Skip the incoming flag if present
436 if (N->getOperand(LastOpNum).getValueType() == MVT::Glue) {
437 --LastOpNum;
438 }
439
440 SDLoc DL(N);
441 Chain = CurDAG->getCopyToReg(Chain, DL, AVR::R31R30, Callee, InFlag);
442 SmallVector<SDValue, 8> Ops;
443 Ops.push_back(CurDAG->getRegister(AVR::R31R30, MVT::i16));
444
445 // Map all operands into the new node.
446 for (unsigned i = 2, e = LastOpNum + 1; i != e; ++i) {
447 Ops.push_back(N->getOperand(i));
448 }
449
450 Ops.push_back(Chain);
451 Ops.push_back(Chain.getValue(1));
452
453 SDNode *ResNode =
454 CurDAG->getMachineNode(AVR::ICALL, DL, MVT::Other, MVT::Glue, Ops);
455
456 ReplaceUses(SDValue(N, 0), SDValue(ResNode, 0));
457 ReplaceUses(SDValue(N, 1), SDValue(ResNode, 1));
458 CurDAG->RemoveDeadNode(N);
459
460 return true;
461}
462
463template <> bool AVRDAGToDAGISel::select<ISD::BRIND>(SDNode *N) {
464 SDValue Chain = N->getOperand(0);
465 SDValue JmpAddr = N->getOperand(1);
466
467 SDLoc DL(N);
468 // Move the destination address of the indirect branch into R31R30.
469 Chain = CurDAG->getCopyToReg(Chain, DL, AVR::R31R30, JmpAddr);
470 SDNode *ResNode = CurDAG->getMachineNode(AVR::IJMP, DL, MVT::Other, Chain);
471
472 ReplaceUses(SDValue(N, 0), SDValue(ResNode, 0));
473 CurDAG->RemoveDeadNode(N);
474
475 return true;
476}
477
478bool AVRDAGToDAGISel::selectMultiplication(llvm::SDNode *N) {
479 SDLoc DL(N);
480 MVT Type = N->getSimpleValueType(0);
481
482 assert(Type == MVT::i8 && "unexpected value type");
483
484 bool isSigned = N->getOpcode() == ISD::SMUL_LOHI;
485 unsigned MachineOp = isSigned ? AVR::MULSRdRr : AVR::MULRdRr;
486
487 SDValue Lhs = N->getOperand(0);
488 SDValue Rhs = N->getOperand(1);
489 SDNode *Mul = CurDAG->getMachineNode(MachineOp, DL, MVT::Glue, Lhs, Rhs);
490 SDValue InChain = CurDAG->getEntryNode();
491 SDValue InGlue = SDValue(Mul, 0);
492
493 // Copy the low half of the result, if it is needed.
494 if (N->hasAnyUseOfValue(0)) {
495 SDValue CopyFromLo =
496 CurDAG->getCopyFromReg(InChain, DL, AVR::R0, Type, InGlue);
497
498 ReplaceUses(SDValue(N, 0), CopyFromLo);
499
500 InChain = CopyFromLo.getValue(1);
501 InGlue = CopyFromLo.getValue(2);
502 }
503
504 // Copy the high half of the result, if it is needed.
505 if (N->hasAnyUseOfValue(1)) {
506 SDValue CopyFromHi =
507 CurDAG->getCopyFromReg(InChain, DL, AVR::R1, Type, InGlue);
508
509 ReplaceUses(SDValue(N, 1), CopyFromHi);
510
511 InChain = CopyFromHi.getValue(1);
512 InGlue = CopyFromHi.getValue(2);
513 }
514
515 CurDAG->RemoveDeadNode(N);
516
517 // We need to clear R1. This is currently done (dirtily)
518 // using a custom inserter.
519
520 return true;
521}
522
523void AVRDAGToDAGISel::Select(SDNode *N) {
524 // Dump information about the Node being selected
525 DEBUG(errs() << "Selecting: "; N->dump(CurDAG); errs() << "\n");
526
527 // If we have a custom node, we already have selected!
528 if (N->isMachineOpcode()) {
529 DEBUG(errs() << "== "; N->dump(CurDAG); errs() << "\n");
530 N->setNodeId(-1);
531 return;
532 }
533
534 // See if subclasses can handle this node.
535 if (trySelect(N))
536 return;
537
538 // Select the default instruction
539 SelectCode(N);
540}
541
542bool AVRDAGToDAGISel::trySelect(SDNode *N) {
543 unsigned Opcode = N->getOpcode();
544 SDLoc DL(N);
545
546 switch (Opcode) {
547 // Nodes we fully handle.
548 case ISD::FrameIndex: return select<ISD::FrameIndex>(N);
549 case ISD::BRIND: return select<ISD::BRIND>(N);
550 case ISD::UMUL_LOHI:
551 case ISD::SMUL_LOHI: return selectMultiplication(N);
552
553 // Nodes we handle partially. Other cases are autogenerated
554 case ISD::STORE: return select<ISD::STORE>(N);
555 case ISD::LOAD: return select<ISD::LOAD>(N);
556 case AVRISD::CALL: return select<AVRISD::CALL>(N);
557 default: return false;
558 }
559}
560
561FunctionPass *createAVRISelDag(AVRTargetMachine &TM,
562 CodeGenOpt::Level OptLevel) {
563 return new AVRDAGToDAGISel(TM, OptLevel);
564}
565
566} // end of namespace llvm
567