brintos

brintos / llvm-project-archived public Read only

0
0
Text · 14.1 KiB · 22da80b Raw
413 lines · cpp
1//===-- CSKYISelDAGToDAG.cpp - A dag to dag inst selector for CSKY---------===//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 CSKY target.10//11//===----------------------------------------------------------------------===//12 13#include "CSKY.h"14#include "CSKYSubtarget.h"15#include "CSKYTargetMachine.h"16#include "MCTargetDesc/CSKYMCTargetDesc.h"17#include "llvm/CodeGen/MachineFrameInfo.h"18#include "llvm/CodeGen/SelectionDAG.h"19#include "llvm/CodeGen/SelectionDAGISel.h"20 21using namespace llvm;22 23#define DEBUG_TYPE "csky-isel"24#define PASS_NAME "CSKY DAG->DAG Pattern Instruction Selection"25 26namespace {27class CSKYDAGToDAGISel : public SelectionDAGISel {28  const CSKYSubtarget *Subtarget;29 30public:31  explicit CSKYDAGToDAGISel(CSKYTargetMachine &TM, CodeGenOptLevel OptLevel)32      : SelectionDAGISel(TM, OptLevel) {}33 34  bool runOnMachineFunction(MachineFunction &MF) override {35    // Reset the subtarget each time through.36    Subtarget = &MF.getSubtarget<CSKYSubtarget>();37    SelectionDAGISel::runOnMachineFunction(MF);38    return true;39  }40 41  void Select(SDNode *N) override;42  bool selectAddCarry(SDNode *N);43  bool selectSubCarry(SDNode *N);44  bool selectBITCAST_TO_LOHI(SDNode *N);45  bool selectInlineAsm(SDNode *N);46 47  SDNode *createGPRPairNode(EVT VT, SDValue V0, SDValue V1);48 49  bool SelectInlineAsmMemoryOperand(const SDValue &Op,50                                    InlineAsm::ConstraintCode ConstraintID,51                                    std::vector<SDValue> &OutOps) override;52 53#include "CSKYGenDAGISel.inc"54};55 56class CSKYDAGToDAGISelLegacy : public SelectionDAGISelLegacy {57public:58  static char ID;59  explicit CSKYDAGToDAGISelLegacy(CSKYTargetMachine &TM,60                                  CodeGenOptLevel OptLevel)61      : SelectionDAGISelLegacy(62            ID, std::make_unique<CSKYDAGToDAGISel>(TM, OptLevel)) {}63};64} // namespace65 66char CSKYDAGToDAGISelLegacy::ID = 0;67 68INITIALIZE_PASS(CSKYDAGToDAGISelLegacy, DEBUG_TYPE, PASS_NAME, false, false)69 70void CSKYDAGToDAGISel::Select(SDNode *N) {71  // If we have a custom node, we have already selected72  if (N->isMachineOpcode()) {73    LLVM_DEBUG(dbgs() << "== "; N->dump(CurDAG); dbgs() << "\n");74    N->setNodeId(-1);75    return;76  }77 78  SDLoc Dl(N);79  unsigned Opcode = N->getOpcode();80  bool IsSelected = false;81 82  switch (Opcode) {83  default:84    break;85  case ISD::UADDO_CARRY:86    IsSelected = selectAddCarry(N);87    break;88  case ISD::USUBO_CARRY:89    IsSelected = selectSubCarry(N);90    break;91  case ISD::GLOBAL_OFFSET_TABLE: {92    Register GP = Subtarget->getInstrInfo()->getGlobalBaseReg(*MF);93    ReplaceNode(N, CurDAG->getRegister(GP, N->getValueType(0)).getNode());94 95    IsSelected = true;96    break;97  }98  case ISD::FrameIndex: {99    SDValue Imm = CurDAG->getTargetConstant(0, Dl, MVT::i32);100    int FI = cast<FrameIndexSDNode>(N)->getIndex();101    SDValue TFI = CurDAG->getTargetFrameIndex(FI, MVT::i32);102    ReplaceNode(N, CurDAG->getMachineNode(Subtarget->hasE2() ? CSKY::ADDI32103                                                             : CSKY::ADDI16XZ,104                                          Dl, MVT::i32, TFI, Imm));105 106    IsSelected = true;107    break;108  }109  case CSKYISD::BITCAST_TO_LOHI:110    IsSelected = selectBITCAST_TO_LOHI(N);111    break;112  case ISD::INLINEASM:113  case ISD::INLINEASM_BR:114    IsSelected = selectInlineAsm(N);115    break;116  }117 118  if (IsSelected)119    return;120 121  // Select the default instruction.122  SelectCode(N);123}124 125bool CSKYDAGToDAGISel::selectInlineAsm(SDNode *N) {126  std::vector<SDValue> AsmNodeOperands;127  InlineAsm::Flag Flag;128  bool Changed = false;129  unsigned NumOps = N->getNumOperands();130 131  // Normally, i64 data is bounded to two arbitrary GRPs for "%r" constraint.132  // However, some instructions (e.g. mula.s32) require GPR pair.133  // Since there is no constraint to explicitly specify a134  // reg pair, we use GPRPair reg class for "%r" for 64-bit data.135 136  SDLoc dl(N);137  SDValue Glue =138      N->getGluedNode() ? N->getOperand(NumOps - 1) : SDValue(nullptr, 0);139 140  SmallVector<bool, 8> OpChanged;141  // Glue node will be appended late.142  for (unsigned i = 0, e = N->getGluedNode() ? NumOps - 1 : NumOps; i < e;143       ++i) {144    SDValue op = N->getOperand(i);145    AsmNodeOperands.push_back(op);146 147    if (i < InlineAsm::Op_FirstOperand)148      continue;149 150    if (const auto *C = dyn_cast<ConstantSDNode>(N->getOperand(i)))151      Flag = InlineAsm::Flag(C->getZExtValue());152    else153      continue;154 155    // Immediate operands to inline asm in the SelectionDAG are modeled with156    // two operands. The first is a constant of value InlineAsm::Kind::Imm, and157    // the second is a constant with the value of the immediate. If we get here158    // and we have a Kind::Imm, skip the next operand, and continue.159    if (Flag.isImmKind()) {160      SDValue op = N->getOperand(++i);161      AsmNodeOperands.push_back(op);162      continue;163    }164 165    const unsigned NumRegs = Flag.getNumOperandRegisters();166    if (NumRegs)167      OpChanged.push_back(false);168 169    unsigned DefIdx = 0;170    bool IsTiedToChangedOp = false;171    // If it's a use that is tied with a previous def, it has no172    // reg class constraint.173    if (Changed && Flag.isUseOperandTiedToDef(DefIdx))174      IsTiedToChangedOp = OpChanged[DefIdx];175 176    // Memory operands to inline asm in the SelectionDAG are modeled with two177    // operands: a constant of value InlineAsm::Kind::Mem followed by the input178    // operand. If we get here and we have a Kind::Mem, skip the next operand179    // (so it doesn't get misinterpreted), and continue. We do this here because180    // it's important to update the OpChanged array correctly before moving on.181    if (Flag.isMemKind()) {182      SDValue op = N->getOperand(++i);183      AsmNodeOperands.push_back(op);184      continue;185    }186 187    if (!Flag.isRegUseKind() && !Flag.isRegDefKind() &&188        !Flag.isRegDefEarlyClobberKind())189      continue;190 191    unsigned RC;192    const bool HasRC = Flag.hasRegClassConstraint(RC);193    if ((!IsTiedToChangedOp && (!HasRC || RC != CSKY::GPRRegClassID)) ||194        NumRegs != 2)195      continue;196 197    assert((i + 2 < NumOps) && "Invalid number of operands in inline asm");198    SDValue V0 = N->getOperand(i + 1);199    SDValue V1 = N->getOperand(i + 2);200    unsigned Reg0 = cast<RegisterSDNode>(V0)->getReg();201    unsigned Reg1 = cast<RegisterSDNode>(V1)->getReg();202    SDValue PairedReg;203    MachineRegisterInfo &MRI = MF->getRegInfo();204 205    if (Flag.isRegDefKind() || Flag.isRegDefEarlyClobberKind()) {206      // Replace the two GPRs with 1 GPRPair and copy values from GPRPair to207      // the original GPRs.208 209      Register GPVR = MRI.createVirtualRegister(&CSKY::GPRPairRegClass);210      PairedReg = CurDAG->getRegister(GPVR, MVT::i64);211      SDValue Chain = SDValue(N, 0);212 213      SDNode *GU = N->getGluedUser();214      SDValue RegCopy =215          CurDAG->getCopyFromReg(Chain, dl, GPVR, MVT::i64, Chain.getValue(1));216 217      // Extract values from a GPRPair reg and copy to the original GPR reg.218      SDValue Sub0 =219          CurDAG->getTargetExtractSubreg(CSKY::sub32_0, dl, MVT::i32, RegCopy);220      SDValue Sub1 =221          CurDAG->getTargetExtractSubreg(CSKY::sub32_32, dl, MVT::i32, RegCopy);222      SDValue T0 =223          CurDAG->getCopyToReg(Sub0, dl, Reg0, Sub0, RegCopy.getValue(1));224      SDValue T1 = CurDAG->getCopyToReg(Sub1, dl, Reg1, Sub1, T0.getValue(1));225 226      // Update the original glue user.227      std::vector<SDValue> Ops(GU->op_begin(), GU->op_end() - 1);228      Ops.push_back(T1.getValue(1));229      CurDAG->UpdateNodeOperands(GU, Ops);230    } else {231      // For Kind  == InlineAsm::Kind::RegUse, we first copy two GPRs into a232      // GPRPair and then pass the GPRPair to the inline asm.233      SDValue Chain = AsmNodeOperands[InlineAsm::Op_InputChain];234 235      // As REG_SEQ doesn't take RegisterSDNode, we copy them first.236      SDValue T0 =237          CurDAG->getCopyFromReg(Chain, dl, Reg0, MVT::i32, Chain.getValue(1));238      SDValue T1 =239          CurDAG->getCopyFromReg(Chain, dl, Reg1, MVT::i32, T0.getValue(1));240      SDValue Pair = SDValue(createGPRPairNode(MVT::i64, T0, T1), 0);241 242      // Copy REG_SEQ into a GPRPair-typed VR and replace the original two243      // i32 VRs of inline asm with it.244      Register GPVR = MRI.createVirtualRegister(&CSKY::GPRPairRegClass);245      PairedReg = CurDAG->getRegister(GPVR, MVT::i64);246      Chain = CurDAG->getCopyToReg(T1, dl, GPVR, Pair, T1.getValue(1));247 248      AsmNodeOperands[InlineAsm::Op_InputChain] = Chain;249      Glue = Chain.getValue(1);250    }251 252    Changed = true;253 254    if (PairedReg.getNode()) {255      OpChanged[OpChanged.size() - 1] = true;256      // TODO: maybe a setter for getNumOperandRegisters?257      Flag = InlineAsm::Flag(Flag.getKind(), 1 /* RegNum*/);258      if (IsTiedToChangedOp)259        Flag.setMatchingOp(DefIdx);260      else261        Flag.setRegClass(CSKY::GPRPairRegClassID);262      // Replace the current flag.263      AsmNodeOperands[AsmNodeOperands.size() - 1] =264          CurDAG->getTargetConstant(Flag, dl, MVT::i32);265      // Add the new register node and skip the original two GPRs.266      AsmNodeOperands.push_back(PairedReg);267      // Skip the next two GPRs.268      i += 2;269    }270  }271 272  if (Glue.getNode())273    AsmNodeOperands.push_back(Glue);274  if (!Changed)275    return false;276 277  SDValue New = CurDAG->getNode(N->getOpcode(), SDLoc(N),278                                CurDAG->getVTList(MVT::Other, MVT::Glue),279                                AsmNodeOperands);280  New->setNodeId(-1);281  ReplaceNode(N, New.getNode());282  return true;283}284 285bool CSKYDAGToDAGISel::selectBITCAST_TO_LOHI(SDNode *N) {286  SDLoc Dl(N);287  auto VT = N->getValueType(0);288  auto V = N->getOperand(0);289 290  if (!Subtarget->hasFPUv2DoubleFloat())291    return false;292 293  SDValue V1 = SDValue(CurDAG->getMachineNode(CSKY::FMFVRL_D, Dl, VT, V), 0);294  SDValue V2 = SDValue(CurDAG->getMachineNode(CSKY::FMFVRH_D, Dl, VT, V), 0);295 296  ReplaceUses(SDValue(N, 0), V1);297  ReplaceUses(SDValue(N, 1), V2);298  CurDAG->RemoveDeadNode(N);299 300  return true;301}302 303bool CSKYDAGToDAGISel::selectAddCarry(SDNode *N) {304  MachineSDNode *NewNode = nullptr;305  auto Type0 = N->getValueType(0);306  auto Type1 = N->getValueType(1);307  auto Op0 = N->getOperand(0);308  auto Op1 = N->getOperand(1);309  auto Op2 = N->getOperand(2);310 311  SDLoc Dl(N);312 313  if (isNullConstant(Op2)) {314    auto *CA = CurDAG->getMachineNode(315        Subtarget->has2E3() ? CSKY::CLRC32 : CSKY::CLRC16, Dl, Type1);316    NewNode = CurDAG->getMachineNode(317        Subtarget->has2E3() ? CSKY::ADDC32 : CSKY::ADDC16, Dl, {Type0, Type1},318        {Op0, Op1, SDValue(CA, 0)});319  } else if (isOneConstant(Op2)) {320    auto *CA = CurDAG->getMachineNode(321        Subtarget->has2E3() ? CSKY::SETC32 : CSKY::SETC16, Dl, Type1);322    NewNode = CurDAG->getMachineNode(323        Subtarget->has2E3() ? CSKY::ADDC32 : CSKY::ADDC16, Dl, {Type0, Type1},324        {Op0, Op1, SDValue(CA, 0)});325  } else {326    NewNode = CurDAG->getMachineNode(Subtarget->has2E3() ? CSKY::ADDC32327                                                         : CSKY::ADDC16,328                                     Dl, {Type0, Type1}, {Op0, Op1, Op2});329  }330  ReplaceNode(N, NewNode);331  return true;332}333 334static SDValue InvertCarryFlag(const CSKYSubtarget *Subtarget,335                               SelectionDAG *DAG, SDLoc Dl, SDValue OldCarry) {336  auto NewCarryReg =337      DAG->getMachineNode(Subtarget->has2E3() ? CSKY::MVCV32 : CSKY::MVCV16, Dl,338                          MVT::i32, OldCarry);339  auto NewCarry =340      DAG->getMachineNode(Subtarget->hasE2() ? CSKY::BTSTI32 : CSKY::BTSTI16,341                          Dl, OldCarry.getValueType(), SDValue(NewCarryReg, 0),342                          DAG->getTargetConstant(0, Dl, MVT::i32));343  return SDValue(NewCarry, 0);344}345 346bool CSKYDAGToDAGISel::selectSubCarry(SDNode *N) {347  MachineSDNode *NewNode = nullptr;348  auto Type0 = N->getValueType(0);349  auto Type1 = N->getValueType(1);350  auto Op0 = N->getOperand(0);351  auto Op1 = N->getOperand(1);352  auto Op2 = N->getOperand(2);353 354  SDLoc Dl(N);355 356  if (isNullConstant(Op2)) {357    auto *CA = CurDAG->getMachineNode(358        Subtarget->has2E3() ? CSKY::SETC32 : CSKY::SETC16, Dl, Type1);359    NewNode = CurDAG->getMachineNode(360        Subtarget->has2E3() ? CSKY::SUBC32 : CSKY::SUBC16, Dl, {Type0, Type1},361        {Op0, Op1, SDValue(CA, 0)});362  } else if (isOneConstant(Op2)) {363    auto *CA = CurDAG->getMachineNode(364        Subtarget->has2E3() ? CSKY::CLRC32 : CSKY::CLRC16, Dl, Type1);365    NewNode = CurDAG->getMachineNode(366        Subtarget->has2E3() ? CSKY::SUBC32 : CSKY::SUBC16, Dl, {Type0, Type1},367        {Op0, Op1, SDValue(CA, 0)});368  } else {369    auto CarryIn = InvertCarryFlag(Subtarget, CurDAG, Dl, Op2);370    NewNode = CurDAG->getMachineNode(Subtarget->has2E3() ? CSKY::SUBC32371                                                         : CSKY::SUBC16,372                                     Dl, {Type0, Type1}, {Op0, Op1, CarryIn});373  }374  auto CarryOut = InvertCarryFlag(Subtarget, CurDAG, Dl, SDValue(NewNode, 1));375 376  ReplaceUses(SDValue(N, 0), SDValue(NewNode, 0));377  ReplaceUses(SDValue(N, 1), CarryOut);378  CurDAG->RemoveDeadNode(N);379 380  return true;381}382 383SDNode *CSKYDAGToDAGISel::createGPRPairNode(EVT VT, SDValue V0, SDValue V1) {384  SDLoc dl(V0.getNode());385  SDValue RegClass =386      CurDAG->getTargetConstant(CSKY::GPRPairRegClassID, dl, MVT::i32);387  SDValue SubReg0 = CurDAG->getTargetConstant(CSKY::sub32_0, dl, MVT::i32);388  SDValue SubReg1 = CurDAG->getTargetConstant(CSKY::sub32_32, dl, MVT::i32);389  const SDValue Ops[] = {RegClass, V0, SubReg0, V1, SubReg1};390  return CurDAG->getMachineNode(TargetOpcode::REG_SEQUENCE, dl, VT, Ops);391}392 393bool CSKYDAGToDAGISel::SelectInlineAsmMemoryOperand(394    const SDValue &Op, const InlineAsm::ConstraintCode ConstraintID,395    std::vector<SDValue> &OutOps) {396  switch (ConstraintID) {397  case InlineAsm::ConstraintCode::m:398    // We just support simple memory operands that have a single address399    // operand and need no special handling.400    OutOps.push_back(Op);401    return false;402  default:403    break;404  }405 406  return true;407}408 409FunctionPass *llvm::createCSKYISelDag(CSKYTargetMachine &TM,410                                      CodeGenOptLevel OptLevel) {411  return new CSKYDAGToDAGISelLegacy(TM, OptLevel);412}413