brintos

brintos / llvm-project-archived public Read only

0
0
Text · 8.9 KiB · 931f595 Raw
250 lines · cpp
1//===-- XCoreISelDAGToDAG.cpp - A dag to dag inst selector for XCore ------===//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 XCore target.10//11//===----------------------------------------------------------------------===//12 13#include "XCore.h"14#include "XCoreTargetMachine.h"15#include "llvm/CodeGen/MachineFrameInfo.h"16#include "llvm/CodeGen/MachineFunction.h"17#include "llvm/CodeGen/SelectionDAG.h"18#include "llvm/CodeGen/SelectionDAGISel.h"19#include "llvm/CodeGen/TargetLowering.h"20#include "llvm/IR/Constants.h"21#include "llvm/IR/Function.h"22#include "llvm/IR/Intrinsics.h"23#include "llvm/IR/IntrinsicsXCore.h"24#include "llvm/IR/LLVMContext.h"25#include "llvm/Support/ErrorHandling.h"26using namespace llvm;27 28#define DEBUG_TYPE "xcore-isel"29#define PASS_NAME "XCore DAG->DAG Pattern Instruction Selection"30 31/// XCoreDAGToDAGISel - XCore specific code to select XCore machine32/// instructions for SelectionDAG operations.33///34namespace {35  class XCoreDAGToDAGISel : public SelectionDAGISel {36 37  public:38    XCoreDAGToDAGISel() = delete;39 40    XCoreDAGToDAGISel(XCoreTargetMachine &TM, CodeGenOptLevel OptLevel)41        : SelectionDAGISel(TM, OptLevel) {}42 43    void Select(SDNode *N) override;44    bool tryBRIND(SDNode *N);45 46    /// getI32Imm - Return a target constant with the specified value, of type47    /// i32.48    inline SDValue getI32Imm(unsigned Imm, const SDLoc &dl) {49      return CurDAG->getTargetConstant(Imm, dl, MVT::i32);50    }51 52    inline bool immMskBitp(SDNode *inN) const {53      ConstantSDNode *N = cast<ConstantSDNode>(inN);54      uint32_t value = (uint32_t)N->getZExtValue();55      if (!isMask_32(value)) {56        return false;57      }58      int msksize = llvm::bit_width(value);59      return (msksize >= 1 && msksize <= 8) ||60              msksize == 16 || msksize == 24 || msksize == 32;61    }62 63    // Complex Pattern Selectors.64    bool SelectADDRspii(SDValue Addr, SDValue &Base, SDValue &Offset);65 66    bool SelectInlineAsmMemoryOperand(const SDValue &Op,67                                      InlineAsm::ConstraintCode ConstraintID,68                                      std::vector<SDValue> &OutOps) override;69 70    // Include the pieces autogenerated from the target description.71  #include "XCoreGenDAGISel.inc"72  };73 74  class XCoreDAGToDAGISelLegacy : public SelectionDAGISelLegacy {75  public:76    static char ID;77    explicit XCoreDAGToDAGISelLegacy(XCoreTargetMachine &TM,78                                     CodeGenOptLevel OptLevel)79        : SelectionDAGISelLegacy(80              ID, std::make_unique<XCoreDAGToDAGISel>(TM, OptLevel)) {}81  };82}  // end anonymous namespace83 84char XCoreDAGToDAGISelLegacy::ID = 0;85 86INITIALIZE_PASS(XCoreDAGToDAGISelLegacy, DEBUG_TYPE, PASS_NAME, false, false)87 88/// createXCoreISelDag - This pass converts a legalized DAG into a89/// XCore-specific DAG, ready for instruction scheduling.90///91FunctionPass *llvm::createXCoreISelDag(XCoreTargetMachine &TM,92                                       CodeGenOptLevel OptLevel) {93  return new XCoreDAGToDAGISelLegacy(TM, OptLevel);94}95 96bool XCoreDAGToDAGISel::SelectADDRspii(SDValue Addr, SDValue &Base,97                                       SDValue &Offset) {98  FrameIndexSDNode *FIN = nullptr;99  if ((FIN = dyn_cast<FrameIndexSDNode>(Addr))) {100    Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i32);101    Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32);102    return true;103  }104  if (Addr.getOpcode() == ISD::ADD) {105    ConstantSDNode *CN = nullptr;106    if ((FIN = dyn_cast<FrameIndexSDNode>(Addr.getOperand(0)))107      && (CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1)))108      && (CN->getSExtValue() % 4 == 0 && CN->getSExtValue() >= 0)) {109      // Constant positive word offset from frame index110      Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i32);111      Offset = CurDAG->getTargetConstant(CN->getSExtValue(), SDLoc(Addr),112                                         MVT::i32);113      return true;114    }115  }116  return false;117}118 119bool XCoreDAGToDAGISel::SelectInlineAsmMemoryOperand(120    const SDValue &Op, InlineAsm::ConstraintCode ConstraintID,121    std::vector<SDValue> &OutOps) {122  SDValue Reg;123  switch (ConstraintID) {124  default: return true;125  case InlineAsm::ConstraintCode::m: // Memory.126    switch (Op.getOpcode()) {127    default: return true;128    case XCoreISD::CPRelativeWrapper:129      Reg = CurDAG->getRegister(XCore::CP, MVT::i32);130      break;131    case XCoreISD::DPRelativeWrapper:132      Reg = CurDAG->getRegister(XCore::DP, MVT::i32);133      break;134    }135  }136  OutOps.push_back(Reg);137  OutOps.push_back(Op.getOperand(0));138  return false;139}140 141void XCoreDAGToDAGISel::Select(SDNode *N) {142  SDLoc dl(N);143  switch (N->getOpcode()) {144  default: break;145  case ISD::Constant: {146    uint64_t Val = N->getAsZExtVal();147    if (immMskBitp(N)) {148      // Transformation function: get the size of a mask149      // Look for the first non-zero bit150      SDValue MskSize = getI32Imm(llvm::bit_width((uint32_t)Val), dl);151      ReplaceNode(152          N, CurDAG->getMachineNode(XCore::MKMSK_rus, dl, MVT::i32, MskSize));153      return;154    }155    else if (!isUInt<16>(Val)) {156      SDValue CPIdx = CurDAG->getTargetConstantPool(157          ConstantInt::get(Type::getInt32Ty(*CurDAG->getContext()), Val),158          getTargetLowering()->getPointerTy(CurDAG->getDataLayout()));159      SDNode *node = CurDAG->getMachineNode(XCore::LDWCP_lru6, dl, MVT::i32,160                                            MVT::Other, CPIdx,161                                            CurDAG->getEntryNode());162      MachineMemOperand *MemOp =163          MF->getMachineMemOperand(MachinePointerInfo::getConstantPool(*MF),164                                   MachineMemOperand::MOLoad, 4, Align(4));165      CurDAG->setNodeMemRefs(cast<MachineSDNode>(node), {MemOp});166      ReplaceNode(N, node);167      return;168    }169    break;170  }171  case ISD::BRIND:172    if (tryBRIND(N))173      return;174    break;175  // Other cases are autogenerated.176  }177  SelectCode(N);178}179 180/// Given a chain return a new chain where any appearance of Old is replaced181/// by New. There must be at most one instruction between Old and Chain and182/// this instruction must be a TokenFactor. Returns an empty SDValue if183/// these conditions don't hold.184static SDValue185replaceInChain(SelectionDAG *CurDAG, SDValue Chain, SDValue Old, SDValue New)186{187  if (Chain == Old)188    return New;189  if (Chain->getOpcode() != ISD::TokenFactor)190    return SDValue();191  SmallVector<SDValue, 8> Ops;192  bool found = false;193  for (unsigned i = 0, e = Chain->getNumOperands(); i != e; ++i) {194    if (Chain->getOperand(i) == Old) {195      Ops.push_back(New);196      found = true;197    } else {198      Ops.push_back(Chain->getOperand(i));199    }200  }201  if (!found)202    return SDValue();203  return CurDAG->getNode(ISD::TokenFactor, SDLoc(Chain), MVT::Other, Ops);204}205 206bool XCoreDAGToDAGISel::tryBRIND(SDNode *N) {207  SDLoc dl(N);208  // (brind (int_xcore_checkevent (addr)))209  SDValue Chain = N->getOperand(0);210  SDValue Addr = N->getOperand(1);211  if (Addr->getOpcode() != ISD::INTRINSIC_W_CHAIN)212    return false;213  unsigned IntNo = Addr->getConstantOperandVal(1);214  if (IntNo != Intrinsic::xcore_checkevent)215    return false;216  SDValue nextAddr = Addr->getOperand(2);217  SDValue CheckEventChainOut(Addr.getNode(), 1);218  if (!CheckEventChainOut.use_empty()) {219    // If the chain out of the checkevent intrinsic is an operand of the220    // indirect branch or used in a TokenFactor which is the operand of the221    // indirect branch then build a new chain which uses the chain coming into222    // the checkevent intrinsic instead.223    SDValue CheckEventChainIn = Addr->getOperand(0);224    SDValue NewChain = replaceInChain(CurDAG, Chain, CheckEventChainOut,225                                      CheckEventChainIn);226    if (!NewChain.getNode())227      return false;228    Chain = NewChain;229  }230  // Enable events on the thread using setsr 1 and then disable them immediately231  // after with clrsr 1. If any resources owned by the thread are ready an event232  // will be taken. If no resource is ready we branch to the address which was233  // the operand to the checkevent intrinsic.234  SDValue constOne = getI32Imm(1, dl);235  SDValue Glue =236    SDValue(CurDAG->getMachineNode(XCore::SETSR_branch_u6, dl, MVT::Glue,237                                   constOne, Chain), 0);238  Glue =239    SDValue(CurDAG->getMachineNode(XCore::CLRSR_branch_u6, dl, MVT::Glue,240                                   constOne, Glue), 0);241  if (nextAddr->getOpcode() == XCoreISD::PCRelativeWrapper &&242      nextAddr->getOperand(0)->getOpcode() == ISD::TargetBlockAddress) {243    CurDAG->SelectNodeTo(N, XCore::BRFU_lu6, MVT::Other,244                         nextAddr->getOperand(0), Glue);245    return true;246  }247  CurDAG->SelectNodeTo(N, XCore::BAU_1r, MVT::Other, nextAddr, Glue);248  return true;249}250