brintos

brintos / llvm-project-archived public Read only

0
0
Text · 14.3 KiB · 55bf40e Raw
406 lines · cpp
1//===-- SparcISelDAGToDAG.cpp - A dag to dag inst selector for Sparc ------===//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 SPARC target.10//11//===----------------------------------------------------------------------===//12 13#include "SparcSelectionDAGInfo.h"14#include "SparcTargetMachine.h"15#include "llvm/CodeGen/MachineRegisterInfo.h"16#include "llvm/CodeGen/SelectionDAGISel.h"17#include "llvm/Support/ErrorHandling.h"18using namespace llvm;19 20#define DEBUG_TYPE "sparc-isel"21#define PASS_NAME "SPARC DAG->DAG Pattern Instruction Selection"22 23//===----------------------------------------------------------------------===//24// Instruction Selector Implementation25//===----------------------------------------------------------------------===//26 27//===--------------------------------------------------------------------===//28/// SparcDAGToDAGISel - SPARC specific code to select SPARC machine29/// instructions for SelectionDAG operations.30///31namespace {32class SparcDAGToDAGISel : public SelectionDAGISel {33  /// Subtarget - Keep a pointer to the Sparc Subtarget around so that we can34  /// make the right decision when generating code for different targets.35  const SparcSubtarget *Subtarget = nullptr;36 37public:38  SparcDAGToDAGISel() = delete;39 40  explicit SparcDAGToDAGISel(SparcTargetMachine &tm) : SelectionDAGISel(tm) {}41 42  bool runOnMachineFunction(MachineFunction &MF) override {43    Subtarget = &MF.getSubtarget<SparcSubtarget>();44    return SelectionDAGISel::runOnMachineFunction(MF);45  }46 47  void Select(SDNode *N) override;48 49  // Complex Pattern Selectors.50  bool SelectADDRrr(SDValue N, SDValue &R1, SDValue &R2);51  bool SelectADDRri(SDValue N, SDValue &Base, SDValue &Offset);52 53  /// SelectInlineAsmMemoryOperand - Implement addressing mode selection for54  /// inline asm expressions.55  bool SelectInlineAsmMemoryOperand(const SDValue &Op,56                                    InlineAsm::ConstraintCode ConstraintID,57                                    std::vector<SDValue> &OutOps) override;58 59  // Include the pieces autogenerated from the target description.60#include "SparcGenDAGISel.inc"61 62private:63  SDNode* getGlobalBaseReg();64  bool tryInlineAsm(SDNode *N);65};66 67class SparcDAGToDAGISelLegacy : public SelectionDAGISelLegacy {68public:69  static char ID;70  explicit SparcDAGToDAGISelLegacy(SparcTargetMachine &tm)71      : SelectionDAGISelLegacy(ID, std::make_unique<SparcDAGToDAGISel>(tm)) {}72};73}  // end anonymous namespace74 75char SparcDAGToDAGISelLegacy::ID = 0;76 77INITIALIZE_PASS(SparcDAGToDAGISelLegacy, DEBUG_TYPE, PASS_NAME, false, false)78 79SDNode* SparcDAGToDAGISel::getGlobalBaseReg() {80  Register GlobalBaseReg = Subtarget->getInstrInfo()->getGlobalBaseReg(MF);81  return CurDAG->getRegister(GlobalBaseReg,82                             TLI->getPointerTy(CurDAG->getDataLayout()))83      .getNode();84}85 86bool SparcDAGToDAGISel::SelectADDRri(SDValue Addr,87                                     SDValue &Base, SDValue &Offset) {88  if (FrameIndexSDNode *FIN = dyn_cast<FrameIndexSDNode>(Addr)) {89    Base = CurDAG->getTargetFrameIndex(90        FIN->getIndex(), TLI->getPointerTy(CurDAG->getDataLayout()));91    Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32);92    return true;93  }94  if (Addr.getOpcode() == ISD::TargetExternalSymbol ||95      Addr.getOpcode() == ISD::TargetGlobalAddress ||96      Addr.getOpcode() == ISD::TargetGlobalTLSAddress)97    return false;  // direct calls.98 99  if (Addr.getOpcode() == ISD::ADD) {100    if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1))) {101      if (isInt<13>(CN->getSExtValue())) {102        if (FrameIndexSDNode *FIN =103                dyn_cast<FrameIndexSDNode>(Addr.getOperand(0))) {104          // Constant offset from frame ref.105          Base = CurDAG->getTargetFrameIndex(106              FIN->getIndex(), TLI->getPointerTy(CurDAG->getDataLayout()));107        } else {108          Base = Addr.getOperand(0);109        }110        Offset = CurDAG->getSignedTargetConstant(CN->getSExtValue(),111                                                 SDLoc(Addr), MVT::i32);112        return true;113      }114    }115    if (Addr.getOperand(0).getOpcode() == SPISD::Lo) {116      Base = Addr.getOperand(1);117      Offset = Addr.getOperand(0).getOperand(0);118      return true;119    }120    if (Addr.getOperand(1).getOpcode() == SPISD::Lo) {121      Base = Addr.getOperand(0);122      Offset = Addr.getOperand(1).getOperand(0);123      return true;124    }125  }126  Base = Addr;127  Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32);128  return true;129}130 131bool SparcDAGToDAGISel::SelectADDRrr(SDValue Addr, SDValue &R1, SDValue &R2) {132  if (Addr.getOpcode() == ISD::FrameIndex) return false;133  if (Addr.getOpcode() == ISD::TargetExternalSymbol ||134      Addr.getOpcode() == ISD::TargetGlobalAddress ||135      Addr.getOpcode() == ISD::TargetGlobalTLSAddress)136    return false;  // direct calls.137 138  if (Addr.getOpcode() == ISD::ADD) {139    if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1)))140      if (isInt<13>(CN->getSExtValue()))141        return false;  // Let the reg+imm pattern catch this!142    if (Addr.getOperand(0).getOpcode() == SPISD::Lo ||143        Addr.getOperand(1).getOpcode() == SPISD::Lo)144      return false;  // Let the reg+imm pattern catch this!145    R1 = Addr.getOperand(0);146    R2 = Addr.getOperand(1);147    return true;148  }149 150  R1 = Addr;151  R2 = CurDAG->getRegister(SP::G0, TLI->getPointerTy(CurDAG->getDataLayout()));152  return true;153}154 155 156// Re-assemble i64 arguments split up in SelectionDAGBuilder's157// visitInlineAsm / GetRegistersForValue functions.158//159// Note: This function was copied from, and is essentially identical160// to ARMISelDAGToDAG::SelectInlineAsm. It is very unfortunate that161// such hacking-up is necessary; a rethink of how inline asm operands162// are handled may be in order to make doing this more sane.163//164// TODO: fix inline asm support so I can simply tell it that 'i64'165// inputs to asm need to be allocated to the IntPair register type,166// and have that work. Then, delete this function.167bool SparcDAGToDAGISel::tryInlineAsm(SDNode *N){168  std::vector<SDValue> AsmNodeOperands;169  InlineAsm::Flag Flag;170  bool Changed = false;171  unsigned NumOps = N->getNumOperands();172 173  // Normally, i64 data is bounded to two arbitrary GPRs for "%r"174  // constraint.  However, some instructions (e.g. ldd/std) require175  // (even/even+1) GPRs.176 177  // So, here, we check for this case, and mutate the inlineasm to use178  // a single IntPair register instead, which guarantees such even/odd179  // placement.180 181  SDLoc dl(N);182  SDValue Glue = N->getGluedNode() ? N->getOperand(NumOps - 1) : SDValue();183 184  SmallVector<bool, 8> OpChanged;185  // Glue node will be appended late.186  for(unsigned i = 0, e = N->getGluedNode() ? NumOps - 1 : NumOps; i < e; ++i) {187    SDValue op = N->getOperand(i);188    AsmNodeOperands.push_back(op);189 190    if (i < InlineAsm::Op_FirstOperand)191      continue;192 193    if (const auto *C = dyn_cast<ConstantSDNode>(N->getOperand(i)))194      Flag = InlineAsm::Flag(C->getZExtValue());195    else196      continue;197 198    // Immediate operands to inline asm in the SelectionDAG are modeled with199    // two operands. The first is a constant of value InlineAsm::Kind::Imm, and200    // the second is a constant with the value of the immediate. If we get here201    // and we have a Kind::Imm, skip the next operand, and continue.202    if (Flag.isImmKind()) {203      SDValue op = N->getOperand(++i);204      AsmNodeOperands.push_back(op);205      continue;206    }207 208    const unsigned NumRegs = Flag.getNumOperandRegisters();209    if (NumRegs)210      OpChanged.push_back(false);211 212    unsigned DefIdx = 0;213    bool IsTiedToChangedOp = false;214    // If it's a use that is tied with a previous def, it has no215    // reg class constraint.216    if (Changed && Flag.isUseOperandTiedToDef(DefIdx))217      IsTiedToChangedOp = OpChanged[DefIdx];218 219    if (!Flag.isRegUseKind() && !Flag.isRegDefKind() &&220        !Flag.isRegDefEarlyClobberKind())221      continue;222 223    unsigned RC;224    const bool HasRC = Flag.hasRegClassConstraint(RC);225    if ((!IsTiedToChangedOp && (!HasRC || RC != SP::IntRegsRegClassID))226        || NumRegs != 2)227      continue;228 229    assert((i+2 < NumOps) && "Invalid number of operands in inline asm");230    SDValue V0 = N->getOperand(i+1);231    SDValue V1 = N->getOperand(i+2);232    Register Reg0 = cast<RegisterSDNode>(V0)->getReg();233    Register Reg1 = cast<RegisterSDNode>(V1)->getReg();234    SDValue PairedReg;235    MachineRegisterInfo &MRI = MF->getRegInfo();236 237    if (Flag.isRegDefKind() || Flag.isRegDefEarlyClobberKind()) {238      // Replace the two GPRs with 1 GPRPair and copy values from GPRPair to239      // the original GPRs.240 241      Register GPVR = MRI.createVirtualRegister(&SP::IntPairRegClass);242      PairedReg = CurDAG->getRegister(GPVR, MVT::v2i32);243      SDValue Chain = SDValue(N,0);244 245      SDNode *GU = N->getGluedUser();246      SDValue RegCopy = CurDAG->getCopyFromReg(Chain, dl, GPVR, MVT::v2i32,247                                               Chain.getValue(1));248 249      // Extract values from a GPRPair reg and copy to the original GPR reg.250      SDValue Sub0 = CurDAG->getTargetExtractSubreg(SP::sub_even, dl, MVT::i32,251                                                    RegCopy);252      SDValue Sub1 = CurDAG->getTargetExtractSubreg(SP::sub_odd, dl, MVT::i32,253                                                    RegCopy);254      SDValue T0 = CurDAG->getCopyToReg(Sub0, dl, Reg0, Sub0,255                                        RegCopy.getValue(1));256      SDValue T1 = CurDAG->getCopyToReg(Sub1, dl, Reg1, Sub1, T0.getValue(1));257 258      // Update the original glue user.259      std::vector<SDValue> Ops(GU->op_begin(), GU->op_end()-1);260      Ops.push_back(T1.getValue(1));261      CurDAG->UpdateNodeOperands(GU, Ops);262    } else {263      // For Kind  == InlineAsm::Kind::RegUse, we first copy two GPRs into a264      // GPRPair and then pass the GPRPair to the inline asm.265      SDValue Chain = AsmNodeOperands[InlineAsm::Op_InputChain];266 267      // As REG_SEQ doesn't take RegisterSDNode, we copy them first.268      SDValue T0 = CurDAG->getCopyFromReg(Chain, dl, Reg0, MVT::i32,269                                          Chain.getValue(1));270      SDValue T1 = CurDAG->getCopyFromReg(Chain, dl, Reg1, MVT::i32,271                                          T0.getValue(1));272      SDValue Pair = SDValue(273          CurDAG->getMachineNode(274              TargetOpcode::REG_SEQUENCE, dl, MVT::v2i32,275              {276                  CurDAG->getTargetConstant(SP::IntPairRegClassID, dl,277                                            MVT::i32),278                  T0,279                  CurDAG->getTargetConstant(SP::sub_even, dl, MVT::i32),280                  T1,281                  CurDAG->getTargetConstant(SP::sub_odd, dl, MVT::i32),282              }),283          0);284 285      // Copy REG_SEQ into a GPRPair-typed VR and replace the original two286      // i32 VRs of inline asm with it.287      Register GPVR = MRI.createVirtualRegister(&SP::IntPairRegClass);288      PairedReg = CurDAG->getRegister(GPVR, MVT::v2i32);289      Chain = CurDAG->getCopyToReg(T1, dl, GPVR, Pair, T1.getValue(1));290 291      AsmNodeOperands[InlineAsm::Op_InputChain] = Chain;292      Glue = Chain.getValue(1);293    }294 295    Changed = true;296 297    if(PairedReg.getNode()) {298      OpChanged[OpChanged.size() -1 ] = true;299      Flag = InlineAsm::Flag(Flag.getKind(), 1 /* RegNum*/);300      if (IsTiedToChangedOp)301        Flag.setMatchingOp(DefIdx);302      else303        Flag.setRegClass(SP::IntPairRegClassID);304      // Replace the current flag.305      AsmNodeOperands[AsmNodeOperands.size() -1] = CurDAG->getTargetConstant(306          Flag, dl, MVT::i32);307      // Add the new register node and skip the original two GPRs.308      AsmNodeOperands.push_back(PairedReg);309      // Skip the next two GPRs.310      i += 2;311    }312  }313 314  if (Glue.getNode())315    AsmNodeOperands.push_back(Glue);316  if (!Changed)317    return false;318 319  SelectInlineAsmMemoryOperands(AsmNodeOperands, SDLoc(N));320 321  SDValue New = CurDAG->getNode(N->getOpcode(), SDLoc(N),322      CurDAG->getVTList(MVT::Other, MVT::Glue), AsmNodeOperands);323  New->setNodeId(-1);324  ReplaceNode(N, New.getNode());325  return true;326}327 328void SparcDAGToDAGISel::Select(SDNode *N) {329  SDLoc dl(N);330  if (N->isMachineOpcode()) {331    N->setNodeId(-1);332    return;   // Already selected.333  }334 335  switch (N->getOpcode()) {336  default: break;337  case ISD::INLINEASM:338  case ISD::INLINEASM_BR: {339    if (tryInlineAsm(N))340      return;341    break;342  }343  case SPISD::GLOBAL_BASE_REG:344    ReplaceNode(N, getGlobalBaseReg());345    return;346 347  case ISD::SDIV:348  case ISD::UDIV: {349    // sdivx / udivx handle 64-bit divides.350    if (N->getValueType(0) == MVT::i64)351      break;352    // FIXME: should use a custom expander to expose the SRA to the dag.353    SDValue DivLHS = N->getOperand(0);354    SDValue DivRHS = N->getOperand(1);355 356    // Set the Y register to the high-part.357    SDValue TopPart;358    if (N->getOpcode() == ISD::SDIV) {359      TopPart = SDValue(CurDAG->getMachineNode(SP::SRAri, dl, MVT::i32, DivLHS,360                                   CurDAG->getTargetConstant(31, dl, MVT::i32)),361                        0);362    } else {363      TopPart = CurDAG->getRegister(SP::G0, MVT::i32);364    }365    TopPart = CurDAG->getCopyToReg(CurDAG->getEntryNode(), dl, SP::Y, TopPart,366                                   SDValue())367                  .getValue(1);368 369    // FIXME: Handle div by immediate.370    unsigned Opcode = N->getOpcode() == ISD::SDIV ? SP::SDIVrr : SP::UDIVrr;371    CurDAG->SelectNodeTo(N, Opcode, MVT::i32, DivLHS, DivRHS, TopPart);372    return;373  }374  }375 376  SelectCode(N);377}378 379 380/// SelectInlineAsmMemoryOperand - Implement addressing mode selection for381/// inline asm expressions.382bool SparcDAGToDAGISel::SelectInlineAsmMemoryOperand(383    const SDValue &Op, InlineAsm::ConstraintCode ConstraintID,384    std::vector<SDValue> &OutOps) {385  SDValue Op0, Op1;386  switch (ConstraintID) {387  default: return true;388  case InlineAsm::ConstraintCode::o:389  case InlineAsm::ConstraintCode::m: // memory390    if (!SelectADDRrr(Op, Op0, Op1))391      SelectADDRri(Op, Op0, Op1);392    break;393  }394 395  OutOps.push_back(Op0);396  OutOps.push_back(Op1);397  return false;398}399 400/// createSparcISelDag - This pass converts a legalized DAG into a401/// SPARC-specific DAG, ready for instruction scheduling.402///403FunctionPass *llvm::createSparcISelDag(SparcTargetMachine &TM) {404  return new SparcDAGToDAGISelLegacy(TM);405}406