brintos

brintos / llvm-project-archived public Read only

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