xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/Mips/Mips16ISelDAGToDAG.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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