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
runOnMachineFunction(MachineFunction & MF)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 *>
selectMULT(SDNode * N,unsigned Opc,const SDLoc & DL,EVT Ty,bool HasLo,bool HasHi)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
initGlobalBaseReg(MachineFunction & MF)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
processFunctionAfterISel(MachineFunction & MF)940b57cec5SDimitry Andric void Mips16DAGToDAGISel::processFunctionAfterISel(MachineFunction &MF) {
950b57cec5SDimitry Andric initGlobalBaseReg(MF);
960b57cec5SDimitry Andric }
970b57cec5SDimitry Andric
selectAddr(bool SPAllowed,SDValue Addr,SDValue & Base,SDValue & Offset)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
selectAddr16(SDValue Addr,SDValue & Base,SDValue & Offset)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
selectAddr16SP(SDValue Addr,SDValue & Base,SDValue & Offset)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
trySelect(SDNode * Node)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
Mips16DAGToDAGISelLegacy(MipsTargetMachine & TM,CodeGenOptLevel OL)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
createMips16ISelDag(MipsTargetMachine & TM,CodeGenOptLevel OptLevel)2260b57cec5SDimitry Andric FunctionPass *llvm::createMips16ISelDag(MipsTargetMachine &TM,
2275f757f3fSDimitry Andric CodeGenOptLevel OptLevel) {
228*0fca6ea1SDimitry Andric return new Mips16DAGToDAGISelLegacy(TM, OptLevel);
2290b57cec5SDimitry Andric }
230