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