10b57cec5SDimitry Andric //===-- MSP430ISelDAGToDAG.cpp - A dag to dag inst selector for MSP430 ----===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 90b57cec5SDimitry Andric // This file defines an instruction selector for the MSP430 target. 100b57cec5SDimitry Andric // 110b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 120b57cec5SDimitry Andric 130b57cec5SDimitry Andric #include "MSP430.h" 140b57cec5SDimitry Andric #include "MSP430TargetMachine.h" 150b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFrameInfo.h" 160b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunction.h" 170b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h" 180b57cec5SDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h" 190b57cec5SDimitry Andric #include "llvm/CodeGen/SelectionDAG.h" 200b57cec5SDimitry Andric #include "llvm/CodeGen/SelectionDAGISel.h" 210b57cec5SDimitry Andric #include "llvm/Config/llvm-config.h" 220b57cec5SDimitry Andric #include "llvm/IR/CallingConv.h" 230b57cec5SDimitry Andric #include "llvm/IR/Constants.h" 240b57cec5SDimitry Andric #include "llvm/IR/DerivedTypes.h" 250b57cec5SDimitry Andric #include "llvm/IR/Function.h" 260b57cec5SDimitry Andric #include "llvm/IR/Intrinsics.h" 270b57cec5SDimitry Andric #include "llvm/Support/Debug.h" 280b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h" 290b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h" 300b57cec5SDimitry Andric using namespace llvm; 310b57cec5SDimitry Andric 320b57cec5SDimitry Andric #define DEBUG_TYPE "msp430-isel" 33bdd1243dSDimitry Andric #define PASS_NAME "MSP430 DAG->DAG Pattern Instruction Selection" 340b57cec5SDimitry Andric 350b57cec5SDimitry Andric namespace { 360b57cec5SDimitry Andric struct MSP430ISelAddressMode { 370b57cec5SDimitry Andric enum { 380b57cec5SDimitry Andric RegBase, 390b57cec5SDimitry Andric FrameIndexBase 40480093f4SDimitry Andric } BaseType = RegBase; 410b57cec5SDimitry Andric 420b57cec5SDimitry Andric struct { // This is really a union, discriminated by BaseType! 430b57cec5SDimitry Andric SDValue Reg; 44480093f4SDimitry Andric int FrameIndex = 0; 450b57cec5SDimitry Andric } Base; 460b57cec5SDimitry Andric 47480093f4SDimitry Andric int16_t Disp = 0; 48480093f4SDimitry Andric const GlobalValue *GV = nullptr; 49480093f4SDimitry Andric const Constant *CP = nullptr; 50480093f4SDimitry Andric const BlockAddress *BlockAddr = nullptr; 51480093f4SDimitry Andric const char *ES = nullptr; 52480093f4SDimitry Andric int JT = -1; 535ffd83dbSDimitry Andric Align Alignment; // CP alignment. 540b57cec5SDimitry Andric 55480093f4SDimitry Andric MSP430ISelAddressMode() = default; 560b57cec5SDimitry Andric 570b57cec5SDimitry Andric bool hasSymbolicDisplacement() const { 580b57cec5SDimitry Andric return GV != nullptr || CP != nullptr || ES != nullptr || JT != -1; 590b57cec5SDimitry Andric } 600b57cec5SDimitry Andric 610b57cec5SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 620b57cec5SDimitry Andric LLVM_DUMP_METHOD void dump() { 630b57cec5SDimitry Andric errs() << "MSP430ISelAddressMode " << this << '\n'; 640b57cec5SDimitry Andric if (BaseType == RegBase && Base.Reg.getNode() != nullptr) { 650b57cec5SDimitry Andric errs() << "Base.Reg "; 660b57cec5SDimitry Andric Base.Reg.getNode()->dump(); 670b57cec5SDimitry Andric } else if (BaseType == FrameIndexBase) { 680b57cec5SDimitry Andric errs() << " Base.FrameIndex " << Base.FrameIndex << '\n'; 690b57cec5SDimitry Andric } 700b57cec5SDimitry Andric errs() << " Disp " << Disp << '\n'; 710b57cec5SDimitry Andric if (GV) { 720b57cec5SDimitry Andric errs() << "GV "; 730b57cec5SDimitry Andric GV->dump(); 740b57cec5SDimitry Andric } else if (CP) { 750b57cec5SDimitry Andric errs() << " CP "; 760b57cec5SDimitry Andric CP->dump(); 775ffd83dbSDimitry Andric errs() << " Align" << Alignment.value() << '\n'; 780b57cec5SDimitry Andric } else if (ES) { 790b57cec5SDimitry Andric errs() << "ES "; 800b57cec5SDimitry Andric errs() << ES << '\n'; 810b57cec5SDimitry Andric } else if (JT != -1) 825ffd83dbSDimitry Andric errs() << " JT" << JT << " Align" << Alignment.value() << '\n'; 830b57cec5SDimitry Andric } 840b57cec5SDimitry Andric #endif 850b57cec5SDimitry Andric }; 860b57cec5SDimitry Andric } 870b57cec5SDimitry Andric 880b57cec5SDimitry Andric /// MSP430DAGToDAGISel - MSP430 specific code to select MSP430 machine 890b57cec5SDimitry Andric /// instructions for SelectionDAG operations. 900b57cec5SDimitry Andric /// 910b57cec5SDimitry Andric namespace { 920b57cec5SDimitry Andric class MSP430DAGToDAGISel : public SelectionDAGISel { 930b57cec5SDimitry Andric public: 94bdd1243dSDimitry Andric MSP430DAGToDAGISel() = delete; 95bdd1243dSDimitry Andric 965f757f3fSDimitry Andric MSP430DAGToDAGISel(MSP430TargetMachine &TM, CodeGenOptLevel OptLevel) 97*0fca6ea1SDimitry Andric : SelectionDAGISel(TM, OptLevel) {} 980b57cec5SDimitry Andric 990b57cec5SDimitry Andric private: 1000b57cec5SDimitry Andric bool MatchAddress(SDValue N, MSP430ISelAddressMode &AM); 1010b57cec5SDimitry Andric bool MatchWrapper(SDValue N, MSP430ISelAddressMode &AM); 1020b57cec5SDimitry Andric bool MatchAddressBase(SDValue N, MSP430ISelAddressMode &AM); 1030b57cec5SDimitry Andric 1045f757f3fSDimitry Andric bool SelectInlineAsmMemoryOperand(const SDValue &Op, 1055f757f3fSDimitry Andric InlineAsm::ConstraintCode ConstraintID, 1060b57cec5SDimitry Andric std::vector<SDValue> &OutOps) override; 1070b57cec5SDimitry Andric 1080b57cec5SDimitry Andric // Include the pieces autogenerated from the target description. 1090b57cec5SDimitry Andric #include "MSP430GenDAGISel.inc" 1100b57cec5SDimitry Andric 1110b57cec5SDimitry Andric // Main method to transform nodes into machine nodes. 1120b57cec5SDimitry Andric void Select(SDNode *N) override; 1130b57cec5SDimitry Andric 1140b57cec5SDimitry Andric bool tryIndexedLoad(SDNode *Op); 1150b57cec5SDimitry Andric bool tryIndexedBinOp(SDNode *Op, SDValue N1, SDValue N2, unsigned Opc8, 1160b57cec5SDimitry Andric unsigned Opc16); 1170b57cec5SDimitry Andric 1180b57cec5SDimitry Andric bool SelectAddr(SDValue Addr, SDValue &Base, SDValue &Disp); 1190b57cec5SDimitry Andric }; 120*0fca6ea1SDimitry Andric 121*0fca6ea1SDimitry Andric class MSP430DAGToDAGISelLegacy : public SelectionDAGISelLegacy { 122*0fca6ea1SDimitry Andric public: 123*0fca6ea1SDimitry Andric static char ID; 124*0fca6ea1SDimitry Andric MSP430DAGToDAGISelLegacy(MSP430TargetMachine &TM, CodeGenOptLevel OptLevel) 125*0fca6ea1SDimitry Andric : SelectionDAGISelLegacy( 126*0fca6ea1SDimitry Andric ID, std::make_unique<MSP430DAGToDAGISel>(TM, OptLevel)) {} 127*0fca6ea1SDimitry Andric }; 1280b57cec5SDimitry Andric } // end anonymous namespace 1290b57cec5SDimitry Andric 130*0fca6ea1SDimitry Andric char MSP430DAGToDAGISelLegacy::ID; 131bdd1243dSDimitry Andric 132*0fca6ea1SDimitry Andric INITIALIZE_PASS(MSP430DAGToDAGISelLegacy, DEBUG_TYPE, PASS_NAME, false, false) 133bdd1243dSDimitry Andric 1340b57cec5SDimitry Andric /// createMSP430ISelDag - This pass converts a legalized DAG into a 1350b57cec5SDimitry Andric /// MSP430-specific DAG, ready for instruction scheduling. 1360b57cec5SDimitry Andric /// 1370b57cec5SDimitry Andric FunctionPass *llvm::createMSP430ISelDag(MSP430TargetMachine &TM, 1385f757f3fSDimitry Andric CodeGenOptLevel OptLevel) { 139*0fca6ea1SDimitry Andric return new MSP430DAGToDAGISelLegacy(TM, OptLevel); 1400b57cec5SDimitry Andric } 1410b57cec5SDimitry Andric 1420b57cec5SDimitry Andric /// MatchWrapper - Try to match MSP430ISD::Wrapper node into an addressing mode. 1430b57cec5SDimitry Andric /// These wrap things that will resolve down into a symbol reference. If no 1440b57cec5SDimitry Andric /// match is possible, this returns true, otherwise it returns false. 1450b57cec5SDimitry Andric bool MSP430DAGToDAGISel::MatchWrapper(SDValue N, MSP430ISelAddressMode &AM) { 1460b57cec5SDimitry Andric // If the addressing mode already has a symbol as the displacement, we can 1470b57cec5SDimitry Andric // never match another symbol. 1480b57cec5SDimitry Andric if (AM.hasSymbolicDisplacement()) 1490b57cec5SDimitry Andric return true; 1500b57cec5SDimitry Andric 1510b57cec5SDimitry Andric SDValue N0 = N.getOperand(0); 1520b57cec5SDimitry Andric 1530b57cec5SDimitry Andric if (GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(N0)) { 1540b57cec5SDimitry Andric AM.GV = G->getGlobal(); 1550b57cec5SDimitry Andric AM.Disp += G->getOffset(); 1560b57cec5SDimitry Andric //AM.SymbolFlags = G->getTargetFlags(); 1570b57cec5SDimitry Andric } else if (ConstantPoolSDNode *CP = dyn_cast<ConstantPoolSDNode>(N0)) { 1580b57cec5SDimitry Andric AM.CP = CP->getConstVal(); 1595ffd83dbSDimitry Andric AM.Alignment = CP->getAlign(); 1600b57cec5SDimitry Andric AM.Disp += CP->getOffset(); 1610b57cec5SDimitry Andric //AM.SymbolFlags = CP->getTargetFlags(); 1620b57cec5SDimitry Andric } else if (ExternalSymbolSDNode *S = dyn_cast<ExternalSymbolSDNode>(N0)) { 1630b57cec5SDimitry Andric AM.ES = S->getSymbol(); 1640b57cec5SDimitry Andric //AM.SymbolFlags = S->getTargetFlags(); 1650b57cec5SDimitry Andric } else if (JumpTableSDNode *J = dyn_cast<JumpTableSDNode>(N0)) { 1660b57cec5SDimitry Andric AM.JT = J->getIndex(); 1670b57cec5SDimitry Andric //AM.SymbolFlags = J->getTargetFlags(); 1680b57cec5SDimitry Andric } else { 1690b57cec5SDimitry Andric AM.BlockAddr = cast<BlockAddressSDNode>(N0)->getBlockAddress(); 1700b57cec5SDimitry Andric //AM.SymbolFlags = cast<BlockAddressSDNode>(N0)->getTargetFlags(); 1710b57cec5SDimitry Andric } 1720b57cec5SDimitry Andric return false; 1730b57cec5SDimitry Andric } 1740b57cec5SDimitry Andric 1750b57cec5SDimitry Andric /// MatchAddressBase - Helper for MatchAddress. Add the specified node to the 1760b57cec5SDimitry Andric /// specified addressing mode without any further recursion. 1770b57cec5SDimitry Andric bool MSP430DAGToDAGISel::MatchAddressBase(SDValue N, MSP430ISelAddressMode &AM) { 1780b57cec5SDimitry Andric // Is the base register already occupied? 1790b57cec5SDimitry Andric if (AM.BaseType != MSP430ISelAddressMode::RegBase || AM.Base.Reg.getNode()) { 1800b57cec5SDimitry Andric // If so, we cannot select it. 1810b57cec5SDimitry Andric return true; 1820b57cec5SDimitry Andric } 1830b57cec5SDimitry Andric 1840b57cec5SDimitry Andric // Default, generate it as a register. 1850b57cec5SDimitry Andric AM.BaseType = MSP430ISelAddressMode::RegBase; 1860b57cec5SDimitry Andric AM.Base.Reg = N; 1870b57cec5SDimitry Andric return false; 1880b57cec5SDimitry Andric } 1890b57cec5SDimitry Andric 1900b57cec5SDimitry Andric bool MSP430DAGToDAGISel::MatchAddress(SDValue N, MSP430ISelAddressMode &AM) { 1910b57cec5SDimitry Andric LLVM_DEBUG(errs() << "MatchAddress: "; AM.dump()); 1920b57cec5SDimitry Andric 1930b57cec5SDimitry Andric switch (N.getOpcode()) { 1940b57cec5SDimitry Andric default: break; 1950b57cec5SDimitry Andric case ISD::Constant: { 1960b57cec5SDimitry Andric uint64_t Val = cast<ConstantSDNode>(N)->getSExtValue(); 1970b57cec5SDimitry Andric AM.Disp += Val; 1980b57cec5SDimitry Andric return false; 1990b57cec5SDimitry Andric } 2000b57cec5SDimitry Andric 2010b57cec5SDimitry Andric case MSP430ISD::Wrapper: 2020b57cec5SDimitry Andric if (!MatchWrapper(N, AM)) 2030b57cec5SDimitry Andric return false; 2040b57cec5SDimitry Andric break; 2050b57cec5SDimitry Andric 2060b57cec5SDimitry Andric case ISD::FrameIndex: 2070b57cec5SDimitry Andric if (AM.BaseType == MSP430ISelAddressMode::RegBase 2080b57cec5SDimitry Andric && AM.Base.Reg.getNode() == nullptr) { 2090b57cec5SDimitry Andric AM.BaseType = MSP430ISelAddressMode::FrameIndexBase; 2100b57cec5SDimitry Andric AM.Base.FrameIndex = cast<FrameIndexSDNode>(N)->getIndex(); 2110b57cec5SDimitry Andric return false; 2120b57cec5SDimitry Andric } 2130b57cec5SDimitry Andric break; 2140b57cec5SDimitry Andric 2150b57cec5SDimitry Andric case ISD::ADD: { 2160b57cec5SDimitry Andric MSP430ISelAddressMode Backup = AM; 2170b57cec5SDimitry Andric if (!MatchAddress(N.getNode()->getOperand(0), AM) && 2180b57cec5SDimitry Andric !MatchAddress(N.getNode()->getOperand(1), AM)) 2190b57cec5SDimitry Andric return false; 2200b57cec5SDimitry Andric AM = Backup; 2210b57cec5SDimitry Andric if (!MatchAddress(N.getNode()->getOperand(1), AM) && 2220b57cec5SDimitry Andric !MatchAddress(N.getNode()->getOperand(0), AM)) 2230b57cec5SDimitry Andric return false; 2240b57cec5SDimitry Andric AM = Backup; 2250b57cec5SDimitry Andric 2260b57cec5SDimitry Andric break; 2270b57cec5SDimitry Andric } 2280b57cec5SDimitry Andric 2290b57cec5SDimitry Andric case ISD::OR: 2300b57cec5SDimitry Andric // Handle "X | C" as "X + C" iff X is known to have C bits clear. 2310b57cec5SDimitry Andric if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(N.getOperand(1))) { 2320b57cec5SDimitry Andric MSP430ISelAddressMode Backup = AM; 2330b57cec5SDimitry Andric uint64_t Offset = CN->getSExtValue(); 2340b57cec5SDimitry Andric // Start with the LHS as an addr mode. 2350b57cec5SDimitry Andric if (!MatchAddress(N.getOperand(0), AM) && 2360b57cec5SDimitry Andric // Address could not have picked a GV address for the displacement. 2370b57cec5SDimitry Andric AM.GV == nullptr && 2380b57cec5SDimitry Andric // Check to see if the LHS & C is zero. 2390b57cec5SDimitry Andric CurDAG->MaskedValueIsZero(N.getOperand(0), CN->getAPIntValue())) { 2400b57cec5SDimitry Andric AM.Disp += Offset; 2410b57cec5SDimitry Andric return false; 2420b57cec5SDimitry Andric } 2430b57cec5SDimitry Andric AM = Backup; 2440b57cec5SDimitry Andric } 2450b57cec5SDimitry Andric break; 2460b57cec5SDimitry Andric } 2470b57cec5SDimitry Andric 2480b57cec5SDimitry Andric return MatchAddressBase(N, AM); 2490b57cec5SDimitry Andric } 2500b57cec5SDimitry Andric 2510b57cec5SDimitry Andric /// SelectAddr - returns true if it is able pattern match an addressing mode. 2520b57cec5SDimitry Andric /// It returns the operands which make up the maximal addressing mode it can 2530b57cec5SDimitry Andric /// match by reference. 2540b57cec5SDimitry Andric bool MSP430DAGToDAGISel::SelectAddr(SDValue N, 2550b57cec5SDimitry Andric SDValue &Base, SDValue &Disp) { 2560b57cec5SDimitry Andric MSP430ISelAddressMode AM; 2570b57cec5SDimitry Andric 2580b57cec5SDimitry Andric if (MatchAddress(N, AM)) 2590b57cec5SDimitry Andric return false; 2600b57cec5SDimitry Andric 2610b57cec5SDimitry Andric if (AM.BaseType == MSP430ISelAddressMode::RegBase) 2620b57cec5SDimitry Andric if (!AM.Base.Reg.getNode()) 2630b57cec5SDimitry Andric AM.Base.Reg = CurDAG->getRegister(MSP430::SR, MVT::i16); 2640b57cec5SDimitry Andric 2650b57cec5SDimitry Andric Base = (AM.BaseType == MSP430ISelAddressMode::FrameIndexBase) 2660b57cec5SDimitry Andric ? CurDAG->getTargetFrameIndex( 2670b57cec5SDimitry Andric AM.Base.FrameIndex, 26881ad6265SDimitry Andric N.getValueType()) 2690b57cec5SDimitry Andric : AM.Base.Reg; 2700b57cec5SDimitry Andric 2710b57cec5SDimitry Andric if (AM.GV) 2720b57cec5SDimitry Andric Disp = CurDAG->getTargetGlobalAddress(AM.GV, SDLoc(N), 2730b57cec5SDimitry Andric MVT::i16, AM.Disp, 2740b57cec5SDimitry Andric 0/*AM.SymbolFlags*/); 2750b57cec5SDimitry Andric else if (AM.CP) 2765ffd83dbSDimitry Andric Disp = CurDAG->getTargetConstantPool(AM.CP, MVT::i16, AM.Alignment, AM.Disp, 2775ffd83dbSDimitry Andric 0 /*AM.SymbolFlags*/); 2780b57cec5SDimitry Andric else if (AM.ES) 2790b57cec5SDimitry Andric Disp = CurDAG->getTargetExternalSymbol(AM.ES, MVT::i16, 0/*AM.SymbolFlags*/); 2800b57cec5SDimitry Andric else if (AM.JT != -1) 2810b57cec5SDimitry Andric Disp = CurDAG->getTargetJumpTable(AM.JT, MVT::i16, 0/*AM.SymbolFlags*/); 2820b57cec5SDimitry Andric else if (AM.BlockAddr) 2830b57cec5SDimitry Andric Disp = CurDAG->getTargetBlockAddress(AM.BlockAddr, MVT::i32, 0, 2840b57cec5SDimitry Andric 0/*AM.SymbolFlags*/); 2850b57cec5SDimitry Andric else 2860b57cec5SDimitry Andric Disp = CurDAG->getTargetConstant(AM.Disp, SDLoc(N), MVT::i16); 2870b57cec5SDimitry Andric 2880b57cec5SDimitry Andric return true; 2890b57cec5SDimitry Andric } 2900b57cec5SDimitry Andric 2915f757f3fSDimitry Andric bool MSP430DAGToDAGISel::SelectInlineAsmMemoryOperand( 2925f757f3fSDimitry Andric const SDValue &Op, InlineAsm::ConstraintCode ConstraintID, 2930b57cec5SDimitry Andric std::vector<SDValue> &OutOps) { 2940b57cec5SDimitry Andric SDValue Op0, Op1; 2950b57cec5SDimitry Andric switch (ConstraintID) { 2960b57cec5SDimitry Andric default: return true; 2975f757f3fSDimitry Andric case InlineAsm::ConstraintCode::m: // memory 2980b57cec5SDimitry Andric if (!SelectAddr(Op, Op0, Op1)) 2990b57cec5SDimitry Andric return true; 3000b57cec5SDimitry Andric break; 3010b57cec5SDimitry Andric } 3020b57cec5SDimitry Andric 3030b57cec5SDimitry Andric OutOps.push_back(Op0); 3040b57cec5SDimitry Andric OutOps.push_back(Op1); 3050b57cec5SDimitry Andric return false; 3060b57cec5SDimitry Andric } 3070b57cec5SDimitry Andric 3080b57cec5SDimitry Andric static bool isValidIndexedLoad(const LoadSDNode *LD) { 3090b57cec5SDimitry Andric ISD::MemIndexedMode AM = LD->getAddressingMode(); 3100b57cec5SDimitry Andric if (AM != ISD::POST_INC || LD->getExtensionType() != ISD::NON_EXTLOAD) 3110b57cec5SDimitry Andric return false; 3120b57cec5SDimitry Andric 3130b57cec5SDimitry Andric EVT VT = LD->getMemoryVT(); 3140b57cec5SDimitry Andric 3150b57cec5SDimitry Andric switch (VT.getSimpleVT().SimpleTy) { 3160b57cec5SDimitry Andric case MVT::i8: 3171db9f3b2SDimitry Andric if (LD->getOffset()->getAsZExtVal() != 1) 3180b57cec5SDimitry Andric return false; 3190b57cec5SDimitry Andric 3200b57cec5SDimitry Andric break; 3210b57cec5SDimitry Andric case MVT::i16: 3221db9f3b2SDimitry Andric if (LD->getOffset()->getAsZExtVal() != 2) 3230b57cec5SDimitry Andric return false; 3240b57cec5SDimitry Andric 3250b57cec5SDimitry Andric break; 3260b57cec5SDimitry Andric default: 3270b57cec5SDimitry Andric return false; 3280b57cec5SDimitry Andric } 3290b57cec5SDimitry Andric 3300b57cec5SDimitry Andric return true; 3310b57cec5SDimitry Andric } 3320b57cec5SDimitry Andric 3330b57cec5SDimitry Andric bool MSP430DAGToDAGISel::tryIndexedLoad(SDNode *N) { 3340b57cec5SDimitry Andric LoadSDNode *LD = cast<LoadSDNode>(N); 3350b57cec5SDimitry Andric if (!isValidIndexedLoad(LD)) 3360b57cec5SDimitry Andric return false; 3370b57cec5SDimitry Andric 3380b57cec5SDimitry Andric MVT VT = LD->getMemoryVT().getSimpleVT(); 3390b57cec5SDimitry Andric 3400b57cec5SDimitry Andric unsigned Opcode = 0; 3410b57cec5SDimitry Andric switch (VT.SimpleTy) { 3420b57cec5SDimitry Andric case MVT::i8: 3430b57cec5SDimitry Andric Opcode = MSP430::MOV8rp; 3440b57cec5SDimitry Andric break; 3450b57cec5SDimitry Andric case MVT::i16: 3460b57cec5SDimitry Andric Opcode = MSP430::MOV16rp; 3470b57cec5SDimitry Andric break; 3480b57cec5SDimitry Andric default: 3490b57cec5SDimitry Andric return false; 3500b57cec5SDimitry Andric } 3510b57cec5SDimitry Andric 3520b57cec5SDimitry Andric ReplaceNode(N, 3530b57cec5SDimitry Andric CurDAG->getMachineNode(Opcode, SDLoc(N), VT, MVT::i16, MVT::Other, 3540b57cec5SDimitry Andric LD->getBasePtr(), LD->getChain())); 3550b57cec5SDimitry Andric return true; 3560b57cec5SDimitry Andric } 3570b57cec5SDimitry Andric 3580b57cec5SDimitry Andric bool MSP430DAGToDAGISel::tryIndexedBinOp(SDNode *Op, SDValue N1, SDValue N2, 3590b57cec5SDimitry Andric unsigned Opc8, unsigned Opc16) { 3600b57cec5SDimitry Andric if (N1.getOpcode() == ISD::LOAD && 3610b57cec5SDimitry Andric N1.hasOneUse() && 3620b57cec5SDimitry Andric IsLegalToFold(N1, Op, Op, OptLevel)) { 3630b57cec5SDimitry Andric LoadSDNode *LD = cast<LoadSDNode>(N1); 3640b57cec5SDimitry Andric if (!isValidIndexedLoad(LD)) 3650b57cec5SDimitry Andric return false; 3660b57cec5SDimitry Andric 3670b57cec5SDimitry Andric MVT VT = LD->getMemoryVT().getSimpleVT(); 3680b57cec5SDimitry Andric unsigned Opc = (VT == MVT::i16 ? Opc16 : Opc8); 3690b57cec5SDimitry Andric MachineMemOperand *MemRef = cast<MemSDNode>(N1)->getMemOperand(); 3700b57cec5SDimitry Andric SDValue Ops0[] = { N2, LD->getBasePtr(), LD->getChain() }; 3710b57cec5SDimitry Andric SDNode *ResNode = 3720b57cec5SDimitry Andric CurDAG->SelectNodeTo(Op, Opc, VT, MVT::i16, MVT::Other, Ops0); 3730b57cec5SDimitry Andric CurDAG->setNodeMemRefs(cast<MachineSDNode>(ResNode), {MemRef}); 3740b57cec5SDimitry Andric // Transfer chain. 3750b57cec5SDimitry Andric ReplaceUses(SDValue(N1.getNode(), 2), SDValue(ResNode, 2)); 3760b57cec5SDimitry Andric // Transfer writeback. 3770b57cec5SDimitry Andric ReplaceUses(SDValue(N1.getNode(), 1), SDValue(ResNode, 1)); 3780b57cec5SDimitry Andric return true; 3790b57cec5SDimitry Andric } 3800b57cec5SDimitry Andric 3810b57cec5SDimitry Andric return false; 3820b57cec5SDimitry Andric } 3830b57cec5SDimitry Andric 3840b57cec5SDimitry Andric 3850b57cec5SDimitry Andric void MSP430DAGToDAGISel::Select(SDNode *Node) { 3860b57cec5SDimitry Andric SDLoc dl(Node); 3870b57cec5SDimitry Andric 3880b57cec5SDimitry Andric // If we have a custom node, we already have selected! 3890b57cec5SDimitry Andric if (Node->isMachineOpcode()) { 3900b57cec5SDimitry Andric LLVM_DEBUG(errs() << "== "; Node->dump(CurDAG); errs() << "\n"); 3910b57cec5SDimitry Andric Node->setNodeId(-1); 3920b57cec5SDimitry Andric return; 3930b57cec5SDimitry Andric } 3940b57cec5SDimitry Andric 3950b57cec5SDimitry Andric // Few custom selection stuff. 3960b57cec5SDimitry Andric switch (Node->getOpcode()) { 3970b57cec5SDimitry Andric default: break; 3980b57cec5SDimitry Andric case ISD::FrameIndex: { 3990b57cec5SDimitry Andric assert(Node->getValueType(0) == MVT::i16); 4000b57cec5SDimitry Andric int FI = cast<FrameIndexSDNode>(Node)->getIndex(); 4010b57cec5SDimitry Andric SDValue TFI = CurDAG->getTargetFrameIndex(FI, MVT::i16); 4020b57cec5SDimitry Andric if (Node->hasOneUse()) { 4030b57cec5SDimitry Andric CurDAG->SelectNodeTo(Node, MSP430::ADDframe, MVT::i16, TFI, 4040b57cec5SDimitry Andric CurDAG->getTargetConstant(0, dl, MVT::i16)); 4050b57cec5SDimitry Andric return; 4060b57cec5SDimitry Andric } 4070b57cec5SDimitry Andric ReplaceNode(Node, CurDAG->getMachineNode( 4080b57cec5SDimitry Andric MSP430::ADDframe, dl, MVT::i16, TFI, 4090b57cec5SDimitry Andric CurDAG->getTargetConstant(0, dl, MVT::i16))); 4100b57cec5SDimitry Andric return; 4110b57cec5SDimitry Andric } 4120b57cec5SDimitry Andric case ISD::LOAD: 4130b57cec5SDimitry Andric if (tryIndexedLoad(Node)) 4140b57cec5SDimitry Andric return; 4150b57cec5SDimitry Andric // Other cases are autogenerated. 4160b57cec5SDimitry Andric break; 4170b57cec5SDimitry Andric case ISD::ADD: 4180b57cec5SDimitry Andric if (tryIndexedBinOp(Node, Node->getOperand(0), Node->getOperand(1), 4190b57cec5SDimitry Andric MSP430::ADD8rp, MSP430::ADD16rp)) 4200b57cec5SDimitry Andric return; 4210b57cec5SDimitry Andric else if (tryIndexedBinOp(Node, Node->getOperand(1), Node->getOperand(0), 4220b57cec5SDimitry Andric MSP430::ADD8rp, MSP430::ADD16rp)) 4230b57cec5SDimitry Andric return; 4240b57cec5SDimitry Andric 4250b57cec5SDimitry Andric // Other cases are autogenerated. 4260b57cec5SDimitry Andric break; 4270b57cec5SDimitry Andric case ISD::SUB: 4280b57cec5SDimitry Andric if (tryIndexedBinOp(Node, Node->getOperand(0), Node->getOperand(1), 4290b57cec5SDimitry Andric MSP430::SUB8rp, MSP430::SUB16rp)) 4300b57cec5SDimitry Andric return; 4310b57cec5SDimitry Andric 4320b57cec5SDimitry Andric // Other cases are autogenerated. 4330b57cec5SDimitry Andric break; 4340b57cec5SDimitry Andric case ISD::AND: 4350b57cec5SDimitry Andric if (tryIndexedBinOp(Node, Node->getOperand(0), Node->getOperand(1), 4360b57cec5SDimitry Andric MSP430::AND8rp, MSP430::AND16rp)) 4370b57cec5SDimitry Andric return; 4380b57cec5SDimitry Andric else if (tryIndexedBinOp(Node, Node->getOperand(1), Node->getOperand(0), 4390b57cec5SDimitry Andric MSP430::AND8rp, MSP430::AND16rp)) 4400b57cec5SDimitry Andric return; 4410b57cec5SDimitry Andric 4420b57cec5SDimitry Andric // Other cases are autogenerated. 4430b57cec5SDimitry Andric break; 4440b57cec5SDimitry Andric case ISD::OR: 4450b57cec5SDimitry Andric if (tryIndexedBinOp(Node, Node->getOperand(0), Node->getOperand(1), 4460b57cec5SDimitry Andric MSP430::BIS8rp, MSP430::BIS16rp)) 4470b57cec5SDimitry Andric return; 4480b57cec5SDimitry Andric else if (tryIndexedBinOp(Node, Node->getOperand(1), Node->getOperand(0), 4490b57cec5SDimitry Andric MSP430::BIS8rp, MSP430::BIS16rp)) 4500b57cec5SDimitry Andric return; 4510b57cec5SDimitry Andric 4520b57cec5SDimitry Andric // Other cases are autogenerated. 4530b57cec5SDimitry Andric break; 4540b57cec5SDimitry Andric case ISD::XOR: 4550b57cec5SDimitry Andric if (tryIndexedBinOp(Node, Node->getOperand(0), Node->getOperand(1), 4560b57cec5SDimitry Andric MSP430::XOR8rp, MSP430::XOR16rp)) 4570b57cec5SDimitry Andric return; 4580b57cec5SDimitry Andric else if (tryIndexedBinOp(Node, Node->getOperand(1), Node->getOperand(0), 4590b57cec5SDimitry Andric MSP430::XOR8rp, MSP430::XOR16rp)) 4600b57cec5SDimitry Andric return; 4610b57cec5SDimitry Andric 4620b57cec5SDimitry Andric // Other cases are autogenerated. 4630b57cec5SDimitry Andric break; 4640b57cec5SDimitry Andric } 4650b57cec5SDimitry Andric 4660b57cec5SDimitry Andric // Select the default instruction 4670b57cec5SDimitry Andric SelectCode(Node); 4680b57cec5SDimitry Andric } 469