10b57cec5SDimitry Andric //===-- Mips16ISelDAGToDAG.cpp - A Dag to Dag Inst Selector for Mips16 ----===// 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 // Subclass of MipsDAGToDAGISel specialized for mips16. 100b57cec5SDimitry Andric // 110b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 120b57cec5SDimitry Andric 130b57cec5SDimitry Andric #include "Mips16ISelDAGToDAG.h" 140b57cec5SDimitry Andric #include "MCTargetDesc/MipsBaseInfo.h" 150b57cec5SDimitry Andric #include "Mips.h" 160b57cec5SDimitry Andric #include "MipsMachineFunction.h" 170b57cec5SDimitry Andric #include "MipsRegisterInfo.h" 180b57cec5SDimitry Andric #include "llvm/CodeGen/MachineConstantPool.h" 190b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFrameInfo.h" 200b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunction.h" 210b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h" 220b57cec5SDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h" 230b57cec5SDimitry Andric #include "llvm/CodeGen/SelectionDAGNodes.h" 240b57cec5SDimitry Andric #include "llvm/IR/CFG.h" 250b57cec5SDimitry Andric #include "llvm/IR/GlobalValue.h" 260b57cec5SDimitry Andric #include "llvm/IR/Instructions.h" 270b57cec5SDimitry Andric #include "llvm/IR/Intrinsics.h" 280b57cec5SDimitry Andric #include "llvm/IR/Type.h" 290b57cec5SDimitry Andric #include "llvm/Support/Debug.h" 300b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h" 310b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h" 320b57cec5SDimitry Andric #include "llvm/Target/TargetMachine.h" 330b57cec5SDimitry Andric using namespace llvm; 340b57cec5SDimitry Andric 350b57cec5SDimitry Andric #define DEBUG_TYPE "mips-isel" 360b57cec5SDimitry Andric 370b57cec5SDimitry Andric bool Mips16DAGToDAGISel::runOnMachineFunction(MachineFunction &MF) { 3881ad6265SDimitry Andric Subtarget = &MF.getSubtarget<MipsSubtarget>(); 390b57cec5SDimitry Andric if (!Subtarget->inMips16Mode()) 400b57cec5SDimitry Andric return false; 410b57cec5SDimitry Andric return MipsDAGToDAGISel::runOnMachineFunction(MF); 420b57cec5SDimitry Andric } 430b57cec5SDimitry Andric /// Select multiply instructions. 440b57cec5SDimitry Andric std::pair<SDNode *, SDNode *> 450b57cec5SDimitry Andric Mips16DAGToDAGISel::selectMULT(SDNode *N, unsigned Opc, const SDLoc &DL, EVT Ty, 460b57cec5SDimitry Andric bool HasLo, bool HasHi) { 470b57cec5SDimitry Andric SDNode *Lo = nullptr, *Hi = nullptr; 480b57cec5SDimitry Andric SDNode *Mul = CurDAG->getMachineNode(Opc, DL, MVT::Glue, N->getOperand(0), 490b57cec5SDimitry Andric N->getOperand(1)); 5006c3fb27SDimitry Andric SDValue InGlue = SDValue(Mul, 0); 510b57cec5SDimitry Andric 520b57cec5SDimitry Andric if (HasLo) { 530b57cec5SDimitry Andric unsigned Opcode = Mips::Mflo16; 5406c3fb27SDimitry Andric Lo = CurDAG->getMachineNode(Opcode, DL, Ty, MVT::Glue, InGlue); 5506c3fb27SDimitry Andric InGlue = SDValue(Lo, 1); 560b57cec5SDimitry Andric } 570b57cec5SDimitry Andric if (HasHi) { 580b57cec5SDimitry Andric unsigned Opcode = Mips::Mfhi16; 5906c3fb27SDimitry Andric Hi = CurDAG->getMachineNode(Opcode, DL, Ty, InGlue); 600b57cec5SDimitry Andric } 610b57cec5SDimitry Andric return std::make_pair(Lo, Hi); 620b57cec5SDimitry Andric } 630b57cec5SDimitry Andric 640b57cec5SDimitry Andric void Mips16DAGToDAGISel::initGlobalBaseReg(MachineFunction &MF) { 650b57cec5SDimitry Andric MipsFunctionInfo *MipsFI = MF.getInfo<MipsFunctionInfo>(); 660b57cec5SDimitry Andric 670b57cec5SDimitry Andric if (!MipsFI->globalBaseRegSet()) 680b57cec5SDimitry Andric return; 690b57cec5SDimitry Andric 700b57cec5SDimitry Andric MachineBasicBlock &MBB = MF.front(); 710b57cec5SDimitry Andric MachineBasicBlock::iterator I = MBB.begin(); 720b57cec5SDimitry Andric MachineRegisterInfo &RegInfo = MF.getRegInfo(); 730b57cec5SDimitry Andric const TargetInstrInfo &TII = *Subtarget->getInstrInfo(); 740b57cec5SDimitry Andric DebugLoc DL; 755ffd83dbSDimitry Andric Register V0, V1, V2, GlobalBaseReg = MipsFI->getGlobalBaseReg(MF); 760b57cec5SDimitry Andric const TargetRegisterClass *RC = &Mips::CPU16RegsRegClass; 770b57cec5SDimitry Andric 780b57cec5SDimitry Andric V0 = RegInfo.createVirtualRegister(RC); 790b57cec5SDimitry Andric V1 = RegInfo.createVirtualRegister(RC); 800b57cec5SDimitry Andric V2 = RegInfo.createVirtualRegister(RC); 810b57cec5SDimitry Andric 820b57cec5SDimitry Andric 830b57cec5SDimitry Andric BuildMI(MBB, I, DL, TII.get(Mips::LiRxImmX16), V0) 840b57cec5SDimitry Andric .addExternalSymbol("_gp_disp", MipsII::MO_ABS_HI); 850b57cec5SDimitry Andric BuildMI(MBB, I, DL, TII.get(Mips::AddiuRxPcImmX16), V1) 860b57cec5SDimitry Andric .addExternalSymbol("_gp_disp", MipsII::MO_ABS_LO); 870b57cec5SDimitry Andric 880b57cec5SDimitry Andric BuildMI(MBB, I, DL, TII.get(Mips::SllX16), V2).addReg(V0).addImm(16); 890b57cec5SDimitry Andric BuildMI(MBB, I, DL, TII.get(Mips::AdduRxRyRz16), GlobalBaseReg) 900b57cec5SDimitry Andric .addReg(V1) 910b57cec5SDimitry Andric .addReg(V2); 920b57cec5SDimitry Andric } 930b57cec5SDimitry Andric 940b57cec5SDimitry Andric void Mips16DAGToDAGISel::processFunctionAfterISel(MachineFunction &MF) { 950b57cec5SDimitry Andric initGlobalBaseReg(MF); 960b57cec5SDimitry Andric } 970b57cec5SDimitry Andric 980b57cec5SDimitry Andric bool Mips16DAGToDAGISel::selectAddr(bool SPAllowed, SDValue Addr, SDValue &Base, 990b57cec5SDimitry Andric SDValue &Offset) { 1000b57cec5SDimitry Andric SDLoc DL(Addr); 1010b57cec5SDimitry Andric EVT ValTy = Addr.getValueType(); 1020b57cec5SDimitry Andric 1030b57cec5SDimitry Andric // if Address is FI, get the TargetFrameIndex. 1040b57cec5SDimitry Andric if (SPAllowed) { 1050b57cec5SDimitry Andric if (FrameIndexSDNode *FIN = dyn_cast<FrameIndexSDNode>(Addr)) { 1060b57cec5SDimitry Andric Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), ValTy); 1070b57cec5SDimitry Andric Offset = CurDAG->getTargetConstant(0, DL, ValTy); 1080b57cec5SDimitry Andric return true; 1090b57cec5SDimitry Andric } 1100b57cec5SDimitry Andric } 1110b57cec5SDimitry Andric // on PIC code Load GA 1120b57cec5SDimitry Andric if (Addr.getOpcode() == MipsISD::Wrapper) { 1130b57cec5SDimitry Andric Base = Addr.getOperand(0); 1140b57cec5SDimitry Andric Offset = Addr.getOperand(1); 1150b57cec5SDimitry Andric return true; 1160b57cec5SDimitry Andric } 1170b57cec5SDimitry Andric if (!TM.isPositionIndependent()) { 1180b57cec5SDimitry Andric if ((Addr.getOpcode() == ISD::TargetExternalSymbol || 1190b57cec5SDimitry Andric Addr.getOpcode() == ISD::TargetGlobalAddress)) 1200b57cec5SDimitry Andric return false; 1210b57cec5SDimitry Andric } 1220b57cec5SDimitry Andric // Addresses of the form FI+const or FI|const 1230b57cec5SDimitry Andric if (CurDAG->isBaseWithConstantOffset(Addr)) { 12404eeddc0SDimitry Andric auto *CN = cast<ConstantSDNode>(Addr.getOperand(1)); 1250b57cec5SDimitry Andric if (isInt<16>(CN->getSExtValue())) { 1260b57cec5SDimitry Andric // If the first operand is a FI, get the TargetFI Node 1270b57cec5SDimitry Andric if (SPAllowed) { 1280b57cec5SDimitry Andric if (FrameIndexSDNode *FIN = 1290b57cec5SDimitry Andric dyn_cast<FrameIndexSDNode>(Addr.getOperand(0))) { 1300b57cec5SDimitry Andric Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), ValTy); 1310b57cec5SDimitry Andric Offset = CurDAG->getTargetConstant(CN->getZExtValue(), DL, ValTy); 1320b57cec5SDimitry Andric return true; 1330b57cec5SDimitry Andric } 1340b57cec5SDimitry Andric } 1350b57cec5SDimitry Andric 1360b57cec5SDimitry Andric Base = Addr.getOperand(0); 1370b57cec5SDimitry Andric Offset = CurDAG->getTargetConstant(CN->getZExtValue(), DL, ValTy); 1380b57cec5SDimitry Andric return true; 1390b57cec5SDimitry Andric } 1400b57cec5SDimitry Andric } 1410b57cec5SDimitry Andric // Operand is a result from an ADD. 1420b57cec5SDimitry Andric if (Addr.getOpcode() == ISD::ADD) { 1430b57cec5SDimitry Andric // When loading from constant pools, load the lower address part in 1440b57cec5SDimitry Andric // the instruction itself. Example, instead of: 1450b57cec5SDimitry Andric // lui $2, %hi($CPI1_0) 1460b57cec5SDimitry Andric // addiu $2, $2, %lo($CPI1_0) 1470b57cec5SDimitry Andric // lwc1 $f0, 0($2) 1480b57cec5SDimitry Andric // Generate: 1490b57cec5SDimitry Andric // lui $2, %hi($CPI1_0) 1500b57cec5SDimitry Andric // lwc1 $f0, %lo($CPI1_0)($2) 1510b57cec5SDimitry Andric if (Addr.getOperand(1).getOpcode() == MipsISD::Lo || 1520b57cec5SDimitry Andric Addr.getOperand(1).getOpcode() == MipsISD::GPRel) { 1530b57cec5SDimitry Andric SDValue Opnd0 = Addr.getOperand(1).getOperand(0); 1540b57cec5SDimitry Andric if (isa<ConstantPoolSDNode>(Opnd0) || isa<GlobalAddressSDNode>(Opnd0) || 1550b57cec5SDimitry Andric isa<JumpTableSDNode>(Opnd0)) { 1560b57cec5SDimitry Andric Base = Addr.getOperand(0); 1570b57cec5SDimitry Andric Offset = Opnd0; 1580b57cec5SDimitry Andric return true; 1590b57cec5SDimitry Andric } 1600b57cec5SDimitry Andric } 1610b57cec5SDimitry Andric } 1620b57cec5SDimitry Andric Base = Addr; 1630b57cec5SDimitry Andric Offset = CurDAG->getTargetConstant(0, DL, ValTy); 1640b57cec5SDimitry Andric return true; 1650b57cec5SDimitry Andric } 1660b57cec5SDimitry Andric 1670b57cec5SDimitry Andric bool Mips16DAGToDAGISel::selectAddr16(SDValue Addr, SDValue &Base, 1680b57cec5SDimitry Andric SDValue &Offset) { 1690b57cec5SDimitry Andric return selectAddr(false, Addr, Base, Offset); 1700b57cec5SDimitry Andric } 1710b57cec5SDimitry Andric 1720b57cec5SDimitry Andric bool Mips16DAGToDAGISel::selectAddr16SP(SDValue Addr, SDValue &Base, 1730b57cec5SDimitry Andric SDValue &Offset) { 1740b57cec5SDimitry Andric return selectAddr(true, Addr, Base, Offset); 1750b57cec5SDimitry Andric } 1760b57cec5SDimitry Andric 1770b57cec5SDimitry Andric /// Select instructions not customized! Used for 1780b57cec5SDimitry Andric /// expanded, promoted and normal instructions 1790b57cec5SDimitry Andric bool Mips16DAGToDAGISel::trySelect(SDNode *Node) { 1800b57cec5SDimitry Andric unsigned Opcode = Node->getOpcode(); 1810b57cec5SDimitry Andric SDLoc DL(Node); 1820b57cec5SDimitry Andric 1830b57cec5SDimitry Andric /// 1840b57cec5SDimitry Andric // Instruction Selection not handled by the auto-generated 1850b57cec5SDimitry Andric // tablegen selection should be handled here. 1860b57cec5SDimitry Andric /// 1870b57cec5SDimitry Andric EVT NodeTy = Node->getValueType(0); 1880b57cec5SDimitry Andric unsigned MultOpc; 1890b57cec5SDimitry Andric 1900b57cec5SDimitry Andric switch (Opcode) { 1910b57cec5SDimitry Andric default: 1920b57cec5SDimitry Andric break; 1930b57cec5SDimitry Andric 1940b57cec5SDimitry Andric /// Mul with two results 1950b57cec5SDimitry Andric case ISD::SMUL_LOHI: 1960b57cec5SDimitry Andric case ISD::UMUL_LOHI: { 1970b57cec5SDimitry Andric MultOpc = (Opcode == ISD::UMUL_LOHI ? Mips::MultuRxRy16 : Mips::MultRxRy16); 1980b57cec5SDimitry Andric std::pair<SDNode *, SDNode *> LoHi = 1990b57cec5SDimitry Andric selectMULT(Node, MultOpc, DL, NodeTy, true, true); 2000b57cec5SDimitry Andric if (!SDValue(Node, 0).use_empty()) 2010b57cec5SDimitry Andric ReplaceUses(SDValue(Node, 0), SDValue(LoHi.first, 0)); 2020b57cec5SDimitry Andric 2030b57cec5SDimitry Andric if (!SDValue(Node, 1).use_empty()) 2040b57cec5SDimitry Andric ReplaceUses(SDValue(Node, 1), SDValue(LoHi.second, 0)); 2050b57cec5SDimitry Andric 2060b57cec5SDimitry Andric CurDAG->RemoveDeadNode(Node); 2070b57cec5SDimitry Andric return true; 2080b57cec5SDimitry Andric } 2090b57cec5SDimitry Andric 2100b57cec5SDimitry Andric case ISD::MULHS: 2110b57cec5SDimitry Andric case ISD::MULHU: { 2120b57cec5SDimitry Andric MultOpc = (Opcode == ISD::MULHU ? Mips::MultuRxRy16 : Mips::MultRxRy16); 2130b57cec5SDimitry Andric auto LoHi = selectMULT(Node, MultOpc, DL, NodeTy, false, true); 2140b57cec5SDimitry Andric ReplaceNode(Node, LoHi.second); 2150b57cec5SDimitry Andric return true; 2160b57cec5SDimitry Andric } 2170b57cec5SDimitry Andric } 2180b57cec5SDimitry Andric 2190b57cec5SDimitry Andric return false; 2200b57cec5SDimitry Andric } 2210b57cec5SDimitry Andric 222*0fca6ea1SDimitry Andric Mips16DAGToDAGISelLegacy::Mips16DAGToDAGISelLegacy(MipsTargetMachine &TM, 223*0fca6ea1SDimitry Andric CodeGenOptLevel OL) 224*0fca6ea1SDimitry Andric : MipsDAGToDAGISelLegacy(std::make_unique<Mips16DAGToDAGISel>(TM, OL)) {} 225*0fca6ea1SDimitry Andric 2260b57cec5SDimitry Andric FunctionPass *llvm::createMips16ISelDag(MipsTargetMachine &TM, 2275f757f3fSDimitry Andric CodeGenOptLevel OptLevel) { 228*0fca6ea1SDimitry Andric return new Mips16DAGToDAGISelLegacy(TM, OptLevel); 2290b57cec5SDimitry Andric } 230