AVRISelDAGToDAG.cpp revision 311833
1//===-- 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 assert((ConstraintCode == InlineAsm::Constraint_m || 207 ConstraintCode == InlineAsm::Constraint_Q) && 208 "Unexpected asm memory constraint"); 209 210 MachineRegisterInfo &RI = MF->getRegInfo(); 211 const AVRSubtarget &STI = MF->getSubtarget<AVRSubtarget>(); 212 const TargetLowering &TL = *STI.getTargetLowering(); 213 SDLoc dl(Op); 214 auto DL = CurDAG->getDataLayout(); 215 216 const RegisterSDNode *RegNode = dyn_cast<RegisterSDNode>(Op); 217 218 // If address operand is of PTRDISPREGS class, all is OK, then. 219 if (RegNode && 220 RI.getRegClass(RegNode->getReg()) == &AVR::PTRDISPREGSRegClass) { 221 OutOps.push_back(Op); 222 return false; 223 } 224 225 if (Op->getOpcode() == ISD::FrameIndex) { 226 SDValue Base, Disp; 227 228 if (SelectAddr(Op.getNode(), Op, Base, Disp)) { 229 OutOps.push_back(Base); 230 OutOps.push_back(Disp); 231 232 return false; 233 } 234 235 return true; 236 } 237 238 // If Op is add 'register, immediate' and 239 // register is either virtual register or register of PTRDISPREGSRegClass 240 if (Op->getOpcode() == ISD::ADD || Op->getOpcode() == ISD::SUB) { 241 SDValue CopyFromRegOp = Op->getOperand(0); 242 SDValue ImmOp = Op->getOperand(1); 243 ConstantSDNode *ImmNode = dyn_cast<ConstantSDNode>(ImmOp); 244 245 unsigned Reg; 246 bool CanHandleRegImmOpt = true; 247 248 CanHandleRegImmOpt &= ImmNode != 0; 249 CanHandleRegImmOpt &= ImmNode->getAPIntValue().getZExtValue() < 64; 250 251 if (CopyFromRegOp->getOpcode() == ISD::CopyFromReg) { 252 RegisterSDNode *RegNode = 253 cast<RegisterSDNode>(CopyFromRegOp->getOperand(1)); 254 Reg = RegNode->getReg(); 255 CanHandleRegImmOpt &= (TargetRegisterInfo::isVirtualRegister(Reg) || 256 AVR::PTRDISPREGSRegClass.contains(Reg)); 257 } else { 258 CanHandleRegImmOpt = false; 259 } 260 261 // If we detect proper case - correct virtual register class 262 // if needed and go to another inlineasm operand. 263 if (CanHandleRegImmOpt) { 264 SDValue Base, Disp; 265 266 if (RI.getRegClass(Reg) != &AVR::PTRDISPREGSRegClass) { 267 SDLoc dl(CopyFromRegOp); 268 269 unsigned VReg = RI.createVirtualRegister(&AVR::PTRDISPREGSRegClass); 270 271 SDValue CopyToReg = 272 CurDAG->getCopyToReg(CopyFromRegOp, dl, VReg, CopyFromRegOp); 273 274 SDValue NewCopyFromRegOp = 275 CurDAG->getCopyFromReg(CopyToReg, dl, VReg, TL.getPointerTy(DL)); 276 277 Base = NewCopyFromRegOp; 278 } else { 279 Base = CopyFromRegOp; 280 } 281 282 if (ImmNode->getValueType(0) != MVT::i8) { 283 Disp = CurDAG->getTargetConstant(ImmNode->getAPIntValue().getZExtValue(), dl, MVT::i8); 284 } else { 285 Disp = ImmOp; 286 } 287 288 OutOps.push_back(Base); 289 OutOps.push_back(Disp); 290 291 return false; 292 } 293 } 294 295 // More generic case. 296 // Create chain that puts Op into pointer register 297 // and return that register. 298 unsigned VReg = RI.createVirtualRegister(&AVR::PTRDISPREGSRegClass); 299 300 SDValue CopyToReg = CurDAG->getCopyToReg(Op, dl, VReg, Op); 301 SDValue CopyFromReg = 302 CurDAG->getCopyFromReg(CopyToReg, dl, VReg, TL.getPointerTy(DL)); 303 304 OutOps.push_back(CopyFromReg); 305 306 return false; 307} 308 309template <> bool AVRDAGToDAGISel::select<ISD::FrameIndex>(SDNode *N) { 310 auto DL = CurDAG->getDataLayout(); 311 312 // Convert the frameindex into a temp instruction that will hold the 313 // effective address of the final stack slot. 314 int FI = cast<FrameIndexSDNode>(N)->getIndex(); 315 SDValue TFI = 316 CurDAG->getTargetFrameIndex(FI, getTargetLowering()->getPointerTy(DL)); 317 318 CurDAG->SelectNodeTo(N, AVR::FRMIDX, 319 getTargetLowering()->getPointerTy(DL), TFI, 320 CurDAG->getTargetConstant(0, SDLoc(N), MVT::i16)); 321 return true; 322} 323 324template <> bool AVRDAGToDAGISel::select<ISD::STORE>(SDNode *N) { 325 // Use the STD{W}SPQRr pseudo instruction when passing arguments through 326 // the stack on function calls for further expansion during the PEI phase. 327 const StoreSDNode *ST = cast<StoreSDNode>(N); 328 SDValue BasePtr = ST->getBasePtr(); 329 330 // Early exit when the base pointer is a frame index node or a constant. 331 if (isa<FrameIndexSDNode>(BasePtr) || isa<ConstantSDNode>(BasePtr) || 332 BasePtr.isUndef()) { 333 return false; 334 } 335 336 const RegisterSDNode *RN = dyn_cast<RegisterSDNode>(BasePtr.getOperand(0)); 337 // Only stores where SP is the base pointer are valid. 338 if (!RN || (RN->getReg() != AVR::SP)) { 339 return false; 340 } 341 342 int CST = (int)cast<ConstantSDNode>(BasePtr.getOperand(1))->getZExtValue(); 343 SDValue Chain = ST->getChain(); 344 EVT VT = ST->getValue().getValueType(); 345 SDLoc DL(N); 346 SDValue Offset = CurDAG->getTargetConstant(CST, DL, MVT::i16); 347 SDValue Ops[] = {BasePtr.getOperand(0), Offset, ST->getValue(), Chain}; 348 unsigned Opc = (VT == MVT::i16) ? AVR::STDWSPQRr : AVR::STDSPQRr; 349 350 SDNode *ResNode = CurDAG->getMachineNode(Opc, DL, MVT::Other, Ops); 351 352 // Transfer memory operands. 353 MachineSDNode::mmo_iterator MemOp = MF->allocateMemRefsArray(1); 354 MemOp[0] = ST->getMemOperand(); 355 cast<MachineSDNode>(ResNode)->setMemRefs(MemOp, MemOp + 1); 356 357 ReplaceUses(SDValue(N, 0), SDValue(ResNode, 0)); 358 CurDAG->RemoveDeadNode(N); 359 360 return true; 361} 362 363template <> bool AVRDAGToDAGISel::select<ISD::LOAD>(SDNode *N) { 364 const LoadSDNode *LD = cast<LoadSDNode>(N); 365 if (!AVR::isProgramMemoryAccess(LD)) { 366 // Check if the opcode can be converted into an indexed load. 367 return selectIndexedLoad(N); 368 } 369 370 assert(Subtarget->hasLPM() && "cannot load from program memory on this mcu"); 371 372 // This is a flash memory load, move the pointer into R31R30 and emit 373 // the lpm instruction. 374 MVT VT = LD->getMemoryVT().getSimpleVT(); 375 SDValue Chain = LD->getChain(); 376 SDValue Ptr = LD->getBasePtr(); 377 SDNode *ResNode; 378 SDLoc DL(N); 379 380 Chain = CurDAG->getCopyToReg(Chain, DL, AVR::R31R30, Ptr, SDValue()); 381 Ptr = CurDAG->getCopyFromReg(Chain, DL, AVR::R31R30, MVT::i16, 382 Chain.getValue(1)); 383 384 SDValue RegZ = CurDAG->getRegister(AVR::R31R30, MVT::i16); 385 386 // Check if the opcode can be converted into an indexed load. 387 if (unsigned LPMOpc = selectIndexedProgMemLoad(LD, VT)) { 388 // It is legal to fold the load into an indexed load. 389 ResNode = CurDAG->getMachineNode(LPMOpc, DL, VT, MVT::i16, MVT::Other, Ptr, 390 RegZ); 391 ReplaceUses(SDValue(N, 1), SDValue(ResNode, 1)); 392 } else { 393 // Selecting an indexed load is not legal, fallback to a normal load. 394 switch (VT.SimpleTy) { 395 case MVT::i8: 396 ResNode = CurDAG->getMachineNode(AVR::LPMRdZ, DL, MVT::i8, MVT::Other, 397 Ptr, RegZ); 398 break; 399 case MVT::i16: 400 ResNode = CurDAG->getMachineNode(AVR::LPMWRdZ, DL, MVT::i16, 401 MVT::Other, Ptr, RegZ); 402 ReplaceUses(SDValue(N, 1), SDValue(ResNode, 1)); 403 break; 404 default: 405 llvm_unreachable("Unsupported VT!"); 406 } 407 } 408 409 // Transfer memory operands. 410 MachineSDNode::mmo_iterator MemOp = MF->allocateMemRefsArray(1); 411 MemOp[0] = LD->getMemOperand(); 412 cast<MachineSDNode>(ResNode)->setMemRefs(MemOp, MemOp + 1); 413 414 ReplaceUses(SDValue(N, 0), SDValue(ResNode, 0)); 415 ReplaceUses(SDValue(N, 1), SDValue(ResNode, 1)); 416 CurDAG->RemoveDeadNode(N); 417 418 return true; 419} 420 421template <> bool AVRDAGToDAGISel::select<AVRISD::CALL>(SDNode *N) { 422 SDValue InFlag; 423 SDValue Chain = N->getOperand(0); 424 SDValue Callee = N->getOperand(1); 425 unsigned LastOpNum = N->getNumOperands() - 1; 426 427 // Direct calls are autogenerated. 428 unsigned Op = Callee.getOpcode(); 429 if (Op == ISD::TargetGlobalAddress || Op == ISD::TargetExternalSymbol) { 430 return false; 431 } 432 433 // Skip the incoming flag if present 434 if (N->getOperand(LastOpNum).getValueType() == MVT::Glue) { 435 --LastOpNum; 436 } 437 438 SDLoc DL(N); 439 Chain = CurDAG->getCopyToReg(Chain, DL, AVR::R31R30, Callee, InFlag); 440 SmallVector<SDValue, 8> Ops; 441 Ops.push_back(CurDAG->getRegister(AVR::R31R30, MVT::i16)); 442 443 // Map all operands into the new node. 444 for (unsigned i = 2, e = LastOpNum + 1; i != e; ++i) { 445 Ops.push_back(N->getOperand(i)); 446 } 447 448 Ops.push_back(Chain); 449 Ops.push_back(Chain.getValue(1)); 450 451 SDNode *ResNode = 452 CurDAG->getMachineNode(AVR::ICALL, DL, MVT::Other, MVT::Glue, Ops); 453 454 ReplaceUses(SDValue(N, 0), SDValue(ResNode, 0)); 455 ReplaceUses(SDValue(N, 1), SDValue(ResNode, 1)); 456 CurDAG->RemoveDeadNode(N); 457 458 return true; 459} 460 461template <> bool AVRDAGToDAGISel::select<ISD::BRIND>(SDNode *N) { 462 SDValue Chain = N->getOperand(0); 463 SDValue JmpAddr = N->getOperand(1); 464 465 SDLoc DL(N); 466 // Move the destination address of the indirect branch into R31R30. 467 Chain = CurDAG->getCopyToReg(Chain, DL, AVR::R31R30, JmpAddr); 468 SDNode *ResNode = CurDAG->getMachineNode(AVR::IJMP, DL, MVT::Other, Chain); 469 470 ReplaceUses(SDValue(N, 0), SDValue(ResNode, 0)); 471 CurDAG->RemoveDeadNode(N); 472 473 return true; 474} 475 476bool AVRDAGToDAGISel::selectMultiplication(llvm::SDNode *N) { 477 SDLoc DL(N); 478 MVT Type = N->getSimpleValueType(0); 479 480 assert(Type == MVT::i8 && "unexpected value type"); 481 482 bool isSigned = N->getOpcode() == ISD::SMUL_LOHI; 483 unsigned MachineOp = isSigned ? AVR::MULSRdRr : AVR::MULRdRr; 484 485 SDValue Lhs = N->getOperand(0); 486 SDValue Rhs = N->getOperand(1); 487 SDNode *Mul = CurDAG->getMachineNode(MachineOp, DL, MVT::Glue, Lhs, Rhs); 488 SDValue InChain = CurDAG->getEntryNode(); 489 SDValue InGlue = SDValue(Mul, 0); 490 491 // Copy the low half of the result, if it is needed. 492 if (N->hasAnyUseOfValue(0)) { 493 SDValue CopyFromLo = 494 CurDAG->getCopyFromReg(InChain, DL, AVR::R0, Type, InGlue); 495 496 ReplaceUses(SDValue(N, 0), CopyFromLo); 497 498 InChain = CopyFromLo.getValue(1); 499 InGlue = CopyFromLo.getValue(2); 500 } 501 502 // Copy the high half of the result, if it is needed. 503 if (N->hasAnyUseOfValue(1)) { 504 SDValue CopyFromHi = 505 CurDAG->getCopyFromReg(InChain, DL, AVR::R1, Type, InGlue); 506 507 ReplaceUses(SDValue(N, 1), CopyFromHi); 508 509 InChain = CopyFromHi.getValue(1); 510 InGlue = CopyFromHi.getValue(2); 511 } 512 513 CurDAG->RemoveDeadNode(N); 514 515 // We need to clear R1. This is currently done (dirtily) 516 // using a custom inserter. 517 518 return true; 519} 520 521void AVRDAGToDAGISel::Select(SDNode *N) { 522 // Dump information about the Node being selected 523 DEBUG(errs() << "Selecting: "; N->dump(CurDAG); errs() << "\n"); 524 525 // If we have a custom node, we already have selected! 526 if (N->isMachineOpcode()) { 527 DEBUG(errs() << "== "; N->dump(CurDAG); errs() << "\n"); 528 N->setNodeId(-1); 529 return; 530 } 531 532 // See if subclasses can handle this node. 533 if (trySelect(N)) 534 return; 535 536 // Select the default instruction 537 SelectCode(N); 538} 539 540bool AVRDAGToDAGISel::trySelect(SDNode *N) { 541 unsigned Opcode = N->getOpcode(); 542 SDLoc DL(N); 543 544 switch (Opcode) { 545 // Nodes we fully handle. 546 case ISD::FrameIndex: return select<ISD::FrameIndex>(N); 547 case ISD::BRIND: return select<ISD::BRIND>(N); 548 case ISD::UMUL_LOHI: 549 case ISD::SMUL_LOHI: return selectMultiplication(N); 550 551 // Nodes we handle partially. Other cases are autogenerated 552 case ISD::STORE: return select<ISD::STORE>(N); 553 case ISD::LOAD: return select<ISD::LOAD>(N); 554 case AVRISD::CALL: return select<AVRISD::CALL>(N); 555 default: return false; 556 } 557} 558 559FunctionPass *createAVRISelDag(AVRTargetMachine &TM, 560 CodeGenOpt::Level OptLevel) { 561 return new AVRDAGToDAGISel(TM, OptLevel); 562} 563 564} // end of namespace llvm 565 566