465 lines · cpp
1//===-- MSP430ISelDAGToDAG.cpp - A dag to dag inst selector for MSP430 ----===//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 MSP430 target.10//11//===----------------------------------------------------------------------===//12 13#include "MSP430.h"14#include "MSP430SelectionDAGInfo.h"15#include "MSP430TargetMachine.h"16#include "llvm/CodeGen/MachineFrameInfo.h"17#include "llvm/CodeGen/MachineFunction.h"18#include "llvm/CodeGen/SelectionDAG.h"19#include "llvm/CodeGen/SelectionDAGISel.h"20#include "llvm/Config/llvm-config.h"21#include "llvm/IR/Constants.h"22#include "llvm/IR/Function.h"23#include "llvm/Support/Debug.h"24#include "llvm/Support/ErrorHandling.h"25#include "llvm/Support/raw_ostream.h"26using namespace llvm;27 28#define DEBUG_TYPE "msp430-isel"29#define PASS_NAME "MSP430 DAG->DAG Pattern Instruction Selection"30 31namespace {32 struct MSP430ISelAddressMode {33 enum {34 RegBase,35 FrameIndexBase36 } BaseType = RegBase;37 38 struct { // This is really a union, discriminated by BaseType!39 SDValue Reg;40 int FrameIndex = 0;41 } Base;42 43 int16_t Disp = 0;44 const GlobalValue *GV = nullptr;45 const Constant *CP = nullptr;46 const BlockAddress *BlockAddr = nullptr;47 const char *ES = nullptr;48 int JT = -1;49 Align Alignment; // CP alignment.50 51 MSP430ISelAddressMode() = default;52 53 bool hasSymbolicDisplacement() const {54 return GV != nullptr || CP != nullptr || ES != nullptr || JT != -1;55 }56 57#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)58 LLVM_DUMP_METHOD void dump() {59 errs() << "MSP430ISelAddressMode " << this << '\n';60 if (BaseType == RegBase && Base.Reg.getNode() != nullptr) {61 errs() << "Base.Reg ";62 Base.Reg.getNode()->dump();63 } else if (BaseType == FrameIndexBase) {64 errs() << " Base.FrameIndex " << Base.FrameIndex << '\n';65 }66 errs() << " Disp " << Disp << '\n';67 if (GV) {68 errs() << "GV ";69 GV->dump();70 } else if (CP) {71 errs() << " CP ";72 CP->dump();73 errs() << " Align" << Alignment.value() << '\n';74 } else if (ES) {75 errs() << "ES ";76 errs() << ES << '\n';77 } else if (JT != -1)78 errs() << " JT" << JT << " Align" << Alignment.value() << '\n';79 }80#endif81 };82}83 84/// MSP430DAGToDAGISel - MSP430 specific code to select MSP430 machine85/// instructions for SelectionDAG operations.86///87namespace {88 class MSP430DAGToDAGISel : public SelectionDAGISel {89 public:90 MSP430DAGToDAGISel() = delete;91 92 MSP430DAGToDAGISel(MSP430TargetMachine &TM, CodeGenOptLevel OptLevel)93 : SelectionDAGISel(TM, OptLevel) {}94 95 private:96 bool MatchAddress(SDValue N, MSP430ISelAddressMode &AM);97 bool MatchWrapper(SDValue N, MSP430ISelAddressMode &AM);98 bool MatchAddressBase(SDValue N, MSP430ISelAddressMode &AM);99 100 bool SelectInlineAsmMemoryOperand(const SDValue &Op,101 InlineAsm::ConstraintCode ConstraintID,102 std::vector<SDValue> &OutOps) override;103 104 // Include the pieces autogenerated from the target description.105 #include "MSP430GenDAGISel.inc"106 107 // Main method to transform nodes into machine nodes.108 void Select(SDNode *N) override;109 110 bool tryIndexedLoad(SDNode *Op);111 bool tryIndexedBinOp(SDNode *Op, SDValue N1, SDValue N2, unsigned Opc8,112 unsigned Opc16);113 114 bool SelectAddr(SDValue Addr, SDValue &Base, SDValue &Disp);115 };116 117 class MSP430DAGToDAGISelLegacy : public SelectionDAGISelLegacy {118 public:119 static char ID;120 MSP430DAGToDAGISelLegacy(MSP430TargetMachine &TM, CodeGenOptLevel OptLevel)121 : SelectionDAGISelLegacy(122 ID, std::make_unique<MSP430DAGToDAGISel>(TM, OptLevel)) {}123 };124} // end anonymous namespace125 126char MSP430DAGToDAGISelLegacy::ID;127 128INITIALIZE_PASS(MSP430DAGToDAGISelLegacy, DEBUG_TYPE, PASS_NAME, false, false)129 130/// createMSP430ISelDag - This pass converts a legalized DAG into a131/// MSP430-specific DAG, ready for instruction scheduling.132///133FunctionPass *llvm::createMSP430ISelDag(MSP430TargetMachine &TM,134 CodeGenOptLevel OptLevel) {135 return new MSP430DAGToDAGISelLegacy(TM, OptLevel);136}137 138/// MatchWrapper - Try to match MSP430ISD::Wrapper node into an addressing mode.139/// These wrap things that will resolve down into a symbol reference. If no140/// match is possible, this returns true, otherwise it returns false.141bool MSP430DAGToDAGISel::MatchWrapper(SDValue N, MSP430ISelAddressMode &AM) {142 // If the addressing mode already has a symbol as the displacement, we can143 // never match another symbol.144 if (AM.hasSymbolicDisplacement())145 return true;146 147 SDValue N0 = N.getOperand(0);148 149 if (GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(N0)) {150 AM.GV = G->getGlobal();151 AM.Disp += G->getOffset();152 //AM.SymbolFlags = G->getTargetFlags();153 } else if (ConstantPoolSDNode *CP = dyn_cast<ConstantPoolSDNode>(N0)) {154 AM.CP = CP->getConstVal();155 AM.Alignment = CP->getAlign();156 AM.Disp += CP->getOffset();157 //AM.SymbolFlags = CP->getTargetFlags();158 } else if (ExternalSymbolSDNode *S = dyn_cast<ExternalSymbolSDNode>(N0)) {159 AM.ES = S->getSymbol();160 //AM.SymbolFlags = S->getTargetFlags();161 } else if (JumpTableSDNode *J = dyn_cast<JumpTableSDNode>(N0)) {162 AM.JT = J->getIndex();163 //AM.SymbolFlags = J->getTargetFlags();164 } else {165 AM.BlockAddr = cast<BlockAddressSDNode>(N0)->getBlockAddress();166 //AM.SymbolFlags = cast<BlockAddressSDNode>(N0)->getTargetFlags();167 }168 return false;169}170 171/// MatchAddressBase - Helper for MatchAddress. Add the specified node to the172/// specified addressing mode without any further recursion.173bool MSP430DAGToDAGISel::MatchAddressBase(SDValue N, MSP430ISelAddressMode &AM) {174 // Is the base register already occupied?175 if (AM.BaseType != MSP430ISelAddressMode::RegBase || AM.Base.Reg.getNode()) {176 // If so, we cannot select it.177 return true;178 }179 180 // Default, generate it as a register.181 AM.BaseType = MSP430ISelAddressMode::RegBase;182 AM.Base.Reg = N;183 return false;184}185 186bool MSP430DAGToDAGISel::MatchAddress(SDValue N, MSP430ISelAddressMode &AM) {187 LLVM_DEBUG(errs() << "MatchAddress: "; AM.dump());188 189 switch (N.getOpcode()) {190 default: break;191 case ISD::Constant: {192 uint64_t Val = cast<ConstantSDNode>(N)->getSExtValue();193 AM.Disp += Val;194 return false;195 }196 197 case MSP430ISD::Wrapper:198 if (!MatchWrapper(N, AM))199 return false;200 break;201 202 case ISD::FrameIndex:203 if (AM.BaseType == MSP430ISelAddressMode::RegBase204 && AM.Base.Reg.getNode() == nullptr) {205 AM.BaseType = MSP430ISelAddressMode::FrameIndexBase;206 AM.Base.FrameIndex = cast<FrameIndexSDNode>(N)->getIndex();207 return false;208 }209 break;210 211 case ISD::ADD: {212 MSP430ISelAddressMode Backup = AM;213 if (!MatchAddress(N.getNode()->getOperand(0), AM) &&214 !MatchAddress(N.getNode()->getOperand(1), AM))215 return false;216 AM = Backup;217 if (!MatchAddress(N.getNode()->getOperand(1), AM) &&218 !MatchAddress(N.getNode()->getOperand(0), AM))219 return false;220 AM = Backup;221 222 break;223 }224 225 case ISD::OR:226 // Handle "X | C" as "X + C" iff X is known to have C bits clear.227 if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(N.getOperand(1))) {228 MSP430ISelAddressMode Backup = AM;229 uint64_t Offset = CN->getSExtValue();230 // Start with the LHS as an addr mode.231 if (!MatchAddress(N.getOperand(0), AM) &&232 // Address could not have picked a GV address for the displacement.233 AM.GV == nullptr &&234 // Check to see if the LHS & C is zero.235 CurDAG->MaskedValueIsZero(N.getOperand(0), CN->getAPIntValue())) {236 AM.Disp += Offset;237 return false;238 }239 AM = Backup;240 }241 break;242 }243 244 return MatchAddressBase(N, AM);245}246 247/// SelectAddr - returns true if it is able pattern match an addressing mode.248/// It returns the operands which make up the maximal addressing mode it can249/// match by reference.250bool MSP430DAGToDAGISel::SelectAddr(SDValue N,251 SDValue &Base, SDValue &Disp) {252 MSP430ISelAddressMode AM;253 254 if (MatchAddress(N, AM))255 return false;256 257 if (AM.BaseType == MSP430ISelAddressMode::RegBase)258 if (!AM.Base.Reg.getNode())259 AM.Base.Reg = CurDAG->getRegister(MSP430::SR, MVT::i16);260 261 Base = (AM.BaseType == MSP430ISelAddressMode::FrameIndexBase)262 ? CurDAG->getTargetFrameIndex(263 AM.Base.FrameIndex,264 N.getValueType())265 : AM.Base.Reg;266 267 if (AM.GV)268 Disp = CurDAG->getTargetGlobalAddress(AM.GV, SDLoc(N),269 MVT::i16, AM.Disp,270 0/*AM.SymbolFlags*/);271 else if (AM.CP)272 Disp = CurDAG->getTargetConstantPool(AM.CP, MVT::i16, AM.Alignment, AM.Disp,273 0 /*AM.SymbolFlags*/);274 else if (AM.ES)275 Disp = CurDAG->getTargetExternalSymbol(AM.ES, MVT::i16, 0/*AM.SymbolFlags*/);276 else if (AM.JT != -1)277 Disp = CurDAG->getTargetJumpTable(AM.JT, MVT::i16, 0/*AM.SymbolFlags*/);278 else if (AM.BlockAddr)279 Disp = CurDAG->getTargetBlockAddress(AM.BlockAddr, MVT::i32, 0,280 0/*AM.SymbolFlags*/);281 else282 Disp = CurDAG->getSignedTargetConstant(AM.Disp, SDLoc(N), MVT::i16);283 284 return true;285}286 287bool MSP430DAGToDAGISel::SelectInlineAsmMemoryOperand(288 const SDValue &Op, InlineAsm::ConstraintCode ConstraintID,289 std::vector<SDValue> &OutOps) {290 SDValue Op0, Op1;291 switch (ConstraintID) {292 default: return true;293 case InlineAsm::ConstraintCode::m: // memory294 if (!SelectAddr(Op, Op0, Op1))295 return true;296 break;297 }298 299 OutOps.push_back(Op0);300 OutOps.push_back(Op1);301 return false;302}303 304static bool isValidIndexedLoad(const LoadSDNode *LD) {305 ISD::MemIndexedMode AM = LD->getAddressingMode();306 if (AM != ISD::POST_INC || LD->getExtensionType() != ISD::NON_EXTLOAD)307 return false;308 309 EVT VT = LD->getMemoryVT();310 311 switch (VT.getSimpleVT().SimpleTy) {312 case MVT::i8:313 if (LD->getOffset()->getAsZExtVal() != 1)314 return false;315 316 break;317 case MVT::i16:318 if (LD->getOffset()->getAsZExtVal() != 2)319 return false;320 321 break;322 default:323 return false;324 }325 326 return true;327}328 329bool MSP430DAGToDAGISel::tryIndexedLoad(SDNode *N) {330 LoadSDNode *LD = cast<LoadSDNode>(N);331 if (!isValidIndexedLoad(LD))332 return false;333 334 MVT VT = LD->getMemoryVT().getSimpleVT();335 336 unsigned Opcode = 0;337 switch (VT.SimpleTy) {338 case MVT::i8:339 Opcode = MSP430::MOV8rp;340 break;341 case MVT::i16:342 Opcode = MSP430::MOV16rp;343 break;344 default:345 return false;346 }347 348 ReplaceNode(N,349 CurDAG->getMachineNode(Opcode, SDLoc(N), VT, MVT::i16, MVT::Other,350 LD->getBasePtr(), LD->getChain()));351 return true;352}353 354bool MSP430DAGToDAGISel::tryIndexedBinOp(SDNode *Op, SDValue N1, SDValue N2,355 unsigned Opc8, unsigned Opc16) {356 if (N1.getOpcode() == ISD::LOAD &&357 N1.hasOneUse() &&358 IsLegalToFold(N1, Op, Op, OptLevel)) {359 LoadSDNode *LD = cast<LoadSDNode>(N1);360 if (!isValidIndexedLoad(LD))361 return false;362 363 MVT VT = LD->getMemoryVT().getSimpleVT();364 unsigned Opc = (VT == MVT::i16 ? Opc16 : Opc8);365 MachineMemOperand *MemRef = cast<MemSDNode>(N1)->getMemOperand();366 SDValue Ops0[] = { N2, LD->getBasePtr(), LD->getChain() };367 SDNode *ResNode =368 CurDAG->SelectNodeTo(Op, Opc, VT, MVT::i16, MVT::Other, Ops0);369 CurDAG->setNodeMemRefs(cast<MachineSDNode>(ResNode), {MemRef});370 // Transfer chain.371 ReplaceUses(SDValue(N1.getNode(), 2), SDValue(ResNode, 2));372 // Transfer writeback.373 ReplaceUses(SDValue(N1.getNode(), 1), SDValue(ResNode, 1));374 return true;375 }376 377 return false;378}379 380 381void MSP430DAGToDAGISel::Select(SDNode *Node) {382 SDLoc dl(Node);383 384 // If we have a custom node, we already have selected!385 if (Node->isMachineOpcode()) {386 LLVM_DEBUG(errs() << "== "; Node->dump(CurDAG); errs() << "\n");387 Node->setNodeId(-1);388 return;389 }390 391 // Few custom selection stuff.392 switch (Node->getOpcode()) {393 default: break;394 case ISD::FrameIndex: {395 assert(Node->getValueType(0) == MVT::i16);396 int FI = cast<FrameIndexSDNode>(Node)->getIndex();397 SDValue TFI = CurDAG->getTargetFrameIndex(FI, MVT::i16);398 if (Node->hasOneUse()) {399 CurDAG->SelectNodeTo(Node, MSP430::ADDframe, MVT::i16, TFI,400 CurDAG->getTargetConstant(0, dl, MVT::i16));401 return;402 }403 ReplaceNode(Node, CurDAG->getMachineNode(404 MSP430::ADDframe, dl, MVT::i16, TFI,405 CurDAG->getTargetConstant(0, dl, MVT::i16)));406 return;407 }408 case ISD::LOAD:409 if (tryIndexedLoad(Node))410 return;411 // Other cases are autogenerated.412 break;413 case ISD::ADD:414 if (tryIndexedBinOp(Node, Node->getOperand(0), Node->getOperand(1),415 MSP430::ADD8rp, MSP430::ADD16rp))416 return;417 else if (tryIndexedBinOp(Node, Node->getOperand(1), Node->getOperand(0),418 MSP430::ADD8rp, MSP430::ADD16rp))419 return;420 421 // Other cases are autogenerated.422 break;423 case ISD::SUB:424 if (tryIndexedBinOp(Node, Node->getOperand(0), Node->getOperand(1),425 MSP430::SUB8rp, MSP430::SUB16rp))426 return;427 428 // Other cases are autogenerated.429 break;430 case ISD::AND:431 if (tryIndexedBinOp(Node, Node->getOperand(0), Node->getOperand(1),432 MSP430::AND8rp, MSP430::AND16rp))433 return;434 else if (tryIndexedBinOp(Node, Node->getOperand(1), Node->getOperand(0),435 MSP430::AND8rp, MSP430::AND16rp))436 return;437 438 // Other cases are autogenerated.439 break;440 case ISD::OR:441 if (tryIndexedBinOp(Node, Node->getOperand(0), Node->getOperand(1),442 MSP430::BIS8rp, MSP430::BIS16rp))443 return;444 else if (tryIndexedBinOp(Node, Node->getOperand(1), Node->getOperand(0),445 MSP430::BIS8rp, MSP430::BIS16rp))446 return;447 448 // Other cases are autogenerated.449 break;450 case ISD::XOR:451 if (tryIndexedBinOp(Node, Node->getOperand(0), Node->getOperand(1),452 MSP430::XOR8rp, MSP430::XOR16rp))453 return;454 else if (tryIndexedBinOp(Node, Node->getOperand(1), Node->getOperand(0),455 MSP430::XOR8rp, MSP430::XOR16rp))456 return;457 458 // Other cases are autogenerated.459 break;460 }461 462 // Select the default instruction463 SelectCode(Node);464}465