10b57cec5SDimitry Andric //===- MipsAsmPrinter.cpp - Mips LLVM Assembly Printer --------------------===//
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 contains a printer that converts from our internal representation
100b57cec5SDimitry Andric // of machine-dependent LLVM code to GAS-format MIPS assembly language.
110b57cec5SDimitry Andric //
120b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
130b57cec5SDimitry Andric 
140b57cec5SDimitry Andric #include "MipsAsmPrinter.h"
150b57cec5SDimitry Andric #include "MCTargetDesc/MipsABIInfo.h"
160b57cec5SDimitry Andric #include "MCTargetDesc/MipsBaseInfo.h"
170b57cec5SDimitry Andric #include "MCTargetDesc/MipsInstPrinter.h"
180b57cec5SDimitry Andric #include "MCTargetDesc/MipsMCNaCl.h"
190b57cec5SDimitry Andric #include "MCTargetDesc/MipsMCTargetDesc.h"
200b57cec5SDimitry Andric #include "Mips.h"
210b57cec5SDimitry Andric #include "MipsMCInstLower.h"
220b57cec5SDimitry Andric #include "MipsMachineFunction.h"
230b57cec5SDimitry Andric #include "MipsSubtarget.h"
240b57cec5SDimitry Andric #include "MipsTargetMachine.h"
250b57cec5SDimitry Andric #include "MipsTargetStreamer.h"
260b57cec5SDimitry Andric #include "TargetInfo/MipsTargetInfo.h"
270b57cec5SDimitry Andric #include "llvm/ADT/SmallString.h"
280b57cec5SDimitry Andric #include "llvm/ADT/StringRef.h"
290b57cec5SDimitry Andric #include "llvm/ADT/Twine.h"
300b57cec5SDimitry Andric #include "llvm/BinaryFormat/ELF.h"
310b57cec5SDimitry Andric #include "llvm/CodeGen/MachineBasicBlock.h"
320b57cec5SDimitry Andric #include "llvm/CodeGen/MachineConstantPool.h"
330b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFrameInfo.h"
340b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunction.h"
350b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstr.h"
360b57cec5SDimitry Andric #include "llvm/CodeGen/MachineJumpTableInfo.h"
370b57cec5SDimitry Andric #include "llvm/CodeGen/MachineOperand.h"
380b57cec5SDimitry Andric #include "llvm/CodeGen/TargetRegisterInfo.h"
390b57cec5SDimitry Andric #include "llvm/CodeGen/TargetSubtargetInfo.h"
400b57cec5SDimitry Andric #include "llvm/IR/Attributes.h"
410b57cec5SDimitry Andric #include "llvm/IR/BasicBlock.h"
420b57cec5SDimitry Andric #include "llvm/IR/DataLayout.h"
430b57cec5SDimitry Andric #include "llvm/IR/Function.h"
440b57cec5SDimitry Andric #include "llvm/IR/InlineAsm.h"
450b57cec5SDimitry Andric #include "llvm/IR/Instructions.h"
460b57cec5SDimitry Andric #include "llvm/MC/MCContext.h"
470b57cec5SDimitry Andric #include "llvm/MC/MCExpr.h"
480b57cec5SDimitry Andric #include "llvm/MC/MCInst.h"
490b57cec5SDimitry Andric #include "llvm/MC/MCInstBuilder.h"
500b57cec5SDimitry Andric #include "llvm/MC/MCObjectFileInfo.h"
510b57cec5SDimitry Andric #include "llvm/MC/MCSectionELF.h"
520b57cec5SDimitry Andric #include "llvm/MC/MCSymbol.h"
530b57cec5SDimitry Andric #include "llvm/MC/MCSymbolELF.h"
54349cc55cSDimitry Andric #include "llvm/MC/TargetRegistry.h"
550b57cec5SDimitry Andric #include "llvm/Support/Casting.h"
560b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h"
570b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
588bcb0991SDimitry Andric #include "llvm/Target/TargetLoweringObjectFile.h"
590b57cec5SDimitry Andric #include "llvm/Target/TargetMachine.h"
6006c3fb27SDimitry Andric #include "llvm/TargetParser/Triple.h"
610b57cec5SDimitry Andric #include <cassert>
620b57cec5SDimitry Andric #include <cstdint>
630b57cec5SDimitry Andric #include <map>
640b57cec5SDimitry Andric #include <memory>
650b57cec5SDimitry Andric #include <string>
660b57cec5SDimitry Andric #include <vector>
670b57cec5SDimitry Andric 
680b57cec5SDimitry Andric using namespace llvm;
690b57cec5SDimitry Andric 
700b57cec5SDimitry Andric #define DEBUG_TYPE "mips-asm-printer"
710b57cec5SDimitry Andric 
720b57cec5SDimitry Andric extern cl::opt<bool> EmitJalrReloc;
730b57cec5SDimitry Andric 
getTargetStreamer() const740b57cec5SDimitry Andric MipsTargetStreamer &MipsAsmPrinter::getTargetStreamer() const {
750b57cec5SDimitry Andric   return static_cast<MipsTargetStreamer &>(*OutStreamer->getTargetStreamer());
760b57cec5SDimitry Andric }
770b57cec5SDimitry Andric 
runOnMachineFunction(MachineFunction & MF)780b57cec5SDimitry Andric bool MipsAsmPrinter::runOnMachineFunction(MachineFunction &MF) {
790b57cec5SDimitry Andric   Subtarget = &MF.getSubtarget<MipsSubtarget>();
800b57cec5SDimitry Andric 
810b57cec5SDimitry Andric   MipsFI = MF.getInfo<MipsFunctionInfo>();
820b57cec5SDimitry Andric   if (Subtarget->inMips16Mode())
8304eeddc0SDimitry Andric     for (const auto &I : MipsFI->StubsNeeded) {
8404eeddc0SDimitry Andric       const char *Symbol = I.first;
8504eeddc0SDimitry Andric       const Mips16HardFloatInfo::FuncSignature *Signature = I.second;
860b57cec5SDimitry Andric       if (StubsNeeded.find(Symbol) == StubsNeeded.end())
870b57cec5SDimitry Andric         StubsNeeded[Symbol] = Signature;
880b57cec5SDimitry Andric     }
890b57cec5SDimitry Andric   MCP = MF.getConstantPool();
900b57cec5SDimitry Andric 
910b57cec5SDimitry Andric   // In NaCl, all indirect jump targets must be aligned to bundle size.
920b57cec5SDimitry Andric   if (Subtarget->isTargetNaCl())
930b57cec5SDimitry Andric     NaClAlignIndirectJumpTargets(MF);
940b57cec5SDimitry Andric 
950b57cec5SDimitry Andric   AsmPrinter::runOnMachineFunction(MF);
960b57cec5SDimitry Andric 
970b57cec5SDimitry Andric   emitXRayTable();
980b57cec5SDimitry Andric 
990b57cec5SDimitry Andric   return true;
1000b57cec5SDimitry Andric }
1010b57cec5SDimitry Andric 
lowerOperand(const MachineOperand & MO,MCOperand & MCOp)1020b57cec5SDimitry Andric bool MipsAsmPrinter::lowerOperand(const MachineOperand &MO, MCOperand &MCOp) {
1030b57cec5SDimitry Andric   MCOp = MCInstLowering.LowerOperand(MO);
1040b57cec5SDimitry Andric   return MCOp.isValid();
1050b57cec5SDimitry Andric }
1060b57cec5SDimitry Andric 
1070b57cec5SDimitry Andric #include "MipsGenMCPseudoLowering.inc"
1080b57cec5SDimitry Andric 
1090b57cec5SDimitry Andric // Lower PseudoReturn/PseudoIndirectBranch/PseudoIndirectBranch64 to JR, JR_MM,
1100b57cec5SDimitry Andric // JALR, or JALR64 as appropriate for the target.
emitPseudoIndirectBranch(MCStreamer & OutStreamer,const MachineInstr * MI)1110b57cec5SDimitry Andric void MipsAsmPrinter::emitPseudoIndirectBranch(MCStreamer &OutStreamer,
1120b57cec5SDimitry Andric                                               const MachineInstr *MI) {
1130b57cec5SDimitry Andric   bool HasLinkReg = false;
1140b57cec5SDimitry Andric   bool InMicroMipsMode = Subtarget->inMicroMipsMode();
1150b57cec5SDimitry Andric   MCInst TmpInst0;
1160b57cec5SDimitry Andric 
1170b57cec5SDimitry Andric   if (Subtarget->hasMips64r6()) {
1180b57cec5SDimitry Andric     // MIPS64r6 should use (JALR64 ZERO_64, $rs)
1190b57cec5SDimitry Andric     TmpInst0.setOpcode(Mips::JALR64);
1200b57cec5SDimitry Andric     HasLinkReg = true;
1210b57cec5SDimitry Andric   } else if (Subtarget->hasMips32r6()) {
1220b57cec5SDimitry Andric     // MIPS32r6 should use (JALR ZERO, $rs)
1230b57cec5SDimitry Andric     if (InMicroMipsMode)
1240b57cec5SDimitry Andric       TmpInst0.setOpcode(Mips::JRC16_MMR6);
1250b57cec5SDimitry Andric     else {
1260b57cec5SDimitry Andric       TmpInst0.setOpcode(Mips::JALR);
1270b57cec5SDimitry Andric       HasLinkReg = true;
1280b57cec5SDimitry Andric     }
1290b57cec5SDimitry Andric   } else if (Subtarget->inMicroMipsMode())
1300b57cec5SDimitry Andric     // microMIPS should use (JR_MM $rs)
1310b57cec5SDimitry Andric     TmpInst0.setOpcode(Mips::JR_MM);
1320b57cec5SDimitry Andric   else {
1330b57cec5SDimitry Andric     // Everything else should use (JR $rs)
1340b57cec5SDimitry Andric     TmpInst0.setOpcode(Mips::JR);
1350b57cec5SDimitry Andric   }
1360b57cec5SDimitry Andric 
1370b57cec5SDimitry Andric   MCOperand MCOp;
1380b57cec5SDimitry Andric 
1390b57cec5SDimitry Andric   if (HasLinkReg) {
1400b57cec5SDimitry Andric     unsigned ZeroReg = Subtarget->isGP64bit() ? Mips::ZERO_64 : Mips::ZERO;
1410b57cec5SDimitry Andric     TmpInst0.addOperand(MCOperand::createReg(ZeroReg));
1420b57cec5SDimitry Andric   }
1430b57cec5SDimitry Andric 
1440b57cec5SDimitry Andric   lowerOperand(MI->getOperand(0), MCOp);
1450b57cec5SDimitry Andric   TmpInst0.addOperand(MCOp);
1460b57cec5SDimitry Andric 
1470b57cec5SDimitry Andric   EmitToStreamer(OutStreamer, TmpInst0);
1480b57cec5SDimitry Andric }
1490b57cec5SDimitry Andric 
1500b57cec5SDimitry Andric // If there is an MO_JALR operand, insert:
1510b57cec5SDimitry Andric //
1520b57cec5SDimitry Andric // .reloc tmplabel, R_{MICRO}MIPS_JALR, symbol
1530b57cec5SDimitry Andric // tmplabel:
1540b57cec5SDimitry Andric //
1550b57cec5SDimitry Andric // This is an optimization hint for the linker which may then replace
1560b57cec5SDimitry Andric // an indirect call with a direct branch.
emitDirectiveRelocJalr(const MachineInstr & MI,MCContext & OutContext,TargetMachine & TM,MCStreamer & OutStreamer,const MipsSubtarget & Subtarget)1570b57cec5SDimitry Andric static void emitDirectiveRelocJalr(const MachineInstr &MI,
1580b57cec5SDimitry Andric                                    MCContext &OutContext,
1590b57cec5SDimitry Andric                                    TargetMachine &TM,
1600b57cec5SDimitry Andric                                    MCStreamer &OutStreamer,
1610b57cec5SDimitry Andric                                    const MipsSubtarget &Subtarget) {
1624824e7fdSDimitry Andric   for (const MachineOperand &MO :
1634824e7fdSDimitry Andric        llvm::drop_begin(MI.operands(), MI.getDesc().getNumOperands())) {
1640b57cec5SDimitry Andric     if (MO.isMCSymbol() && (MO.getTargetFlags() & MipsII::MO_JALR)) {
1650b57cec5SDimitry Andric       MCSymbol *Callee = MO.getMCSymbol();
1660b57cec5SDimitry Andric       if (Callee && !Callee->getName().empty()) {
1670b57cec5SDimitry Andric         MCSymbol *OffsetLabel = OutContext.createTempSymbol();
1680b57cec5SDimitry Andric         const MCExpr *OffsetExpr =
1690b57cec5SDimitry Andric             MCSymbolRefExpr::create(OffsetLabel, OutContext);
1700b57cec5SDimitry Andric         const MCExpr *CaleeExpr =
1710b57cec5SDimitry Andric             MCSymbolRefExpr::create(Callee, OutContext);
1725ffd83dbSDimitry Andric         OutStreamer.emitRelocDirective(
1735ffd83dbSDimitry Andric             *OffsetExpr,
1740b57cec5SDimitry Andric             Subtarget.inMicroMipsMode() ? "R_MICROMIPS_JALR" : "R_MIPS_JALR",
1750b57cec5SDimitry Andric             CaleeExpr, SMLoc(), *TM.getMCSubtargetInfo());
1765ffd83dbSDimitry Andric         OutStreamer.emitLabel(OffsetLabel);
1770b57cec5SDimitry Andric         return;
1780b57cec5SDimitry Andric       }
1790b57cec5SDimitry Andric     }
1800b57cec5SDimitry Andric   }
1810b57cec5SDimitry Andric }
1820b57cec5SDimitry Andric 
emitInstruction(const MachineInstr * MI)1835ffd83dbSDimitry Andric void MipsAsmPrinter::emitInstruction(const MachineInstr *MI) {
184753f127fSDimitry Andric   // FIXME: Enable feature predicate checks once all the test pass.
185753f127fSDimitry Andric   // Mips_MC::verifyInstructionPredicates(MI->getOpcode(),
186753f127fSDimitry Andric   //                                      getSubtargetInfo().getFeatureBits());
187753f127fSDimitry Andric 
1880b57cec5SDimitry Andric   MipsTargetStreamer &TS = getTargetStreamer();
1890b57cec5SDimitry Andric   unsigned Opc = MI->getOpcode();
1900b57cec5SDimitry Andric   TS.forbidModuleDirective();
1910b57cec5SDimitry Andric 
1920b57cec5SDimitry Andric   if (MI->isDebugValue()) {
1930b57cec5SDimitry Andric     SmallString<128> Str;
1940b57cec5SDimitry Andric     raw_svector_ostream OS(Str);
1950b57cec5SDimitry Andric 
1960b57cec5SDimitry Andric     PrintDebugValueComment(MI, OS);
1970b57cec5SDimitry Andric     return;
1980b57cec5SDimitry Andric   }
1990b57cec5SDimitry Andric   if (MI->isDebugLabel())
2000b57cec5SDimitry Andric     return;
2010b57cec5SDimitry Andric 
2020b57cec5SDimitry Andric   // If we just ended a constant pool, mark it as such.
2030b57cec5SDimitry Andric   if (InConstantPool && Opc != Mips::CONSTPOOL_ENTRY) {
2045ffd83dbSDimitry Andric     OutStreamer->emitDataRegion(MCDR_DataRegionEnd);
2050b57cec5SDimitry Andric     InConstantPool = false;
2060b57cec5SDimitry Andric   }
2070b57cec5SDimitry Andric   if (Opc == Mips::CONSTPOOL_ENTRY) {
2080b57cec5SDimitry Andric     // CONSTPOOL_ENTRY - This instruction represents a floating
2090b57cec5SDimitry Andric     // constant pool in the function.  The first operand is the ID#
2100b57cec5SDimitry Andric     // for this instruction, the second is the index into the
2110b57cec5SDimitry Andric     // MachineConstantPool that this is, the third is the size in
2120b57cec5SDimitry Andric     // bytes of this constant pool entry.
2130b57cec5SDimitry Andric     // The required alignment is specified on the basic block holding this MI.
2140b57cec5SDimitry Andric     //
2150b57cec5SDimitry Andric     unsigned LabelId = (unsigned)MI->getOperand(0).getImm();
2160b57cec5SDimitry Andric     unsigned CPIdx = (unsigned)MI->getOperand(1).getIndex();
2170b57cec5SDimitry Andric 
2180b57cec5SDimitry Andric     // If this is the first entry of the pool, mark it.
2190b57cec5SDimitry Andric     if (!InConstantPool) {
2205ffd83dbSDimitry Andric       OutStreamer->emitDataRegion(MCDR_DataRegion);
2210b57cec5SDimitry Andric       InConstantPool = true;
2220b57cec5SDimitry Andric     }
2230b57cec5SDimitry Andric 
2245ffd83dbSDimitry Andric     OutStreamer->emitLabel(GetCPISymbol(LabelId));
2250b57cec5SDimitry Andric 
2260b57cec5SDimitry Andric     const MachineConstantPoolEntry &MCPE = MCP->getConstants()[CPIdx];
2270b57cec5SDimitry Andric     if (MCPE.isMachineConstantPoolEntry())
2285ffd83dbSDimitry Andric       emitMachineConstantPoolValue(MCPE.Val.MachineCPVal);
2290b57cec5SDimitry Andric     else
2305ffd83dbSDimitry Andric       emitGlobalConstant(MF->getDataLayout(), MCPE.Val.ConstVal);
2310b57cec5SDimitry Andric     return;
2320b57cec5SDimitry Andric   }
2330b57cec5SDimitry Andric 
2340b57cec5SDimitry Andric   switch (Opc) {
2350b57cec5SDimitry Andric   case Mips::PATCHABLE_FUNCTION_ENTER:
2360b57cec5SDimitry Andric     LowerPATCHABLE_FUNCTION_ENTER(*MI);
2370b57cec5SDimitry Andric     return;
2380b57cec5SDimitry Andric   case Mips::PATCHABLE_FUNCTION_EXIT:
2390b57cec5SDimitry Andric     LowerPATCHABLE_FUNCTION_EXIT(*MI);
2400b57cec5SDimitry Andric     return;
2410b57cec5SDimitry Andric   case Mips::PATCHABLE_TAIL_CALL:
2420b57cec5SDimitry Andric     LowerPATCHABLE_TAIL_CALL(*MI);
2430b57cec5SDimitry Andric     return;
2440b57cec5SDimitry Andric   }
2450b57cec5SDimitry Andric 
2460b57cec5SDimitry Andric   if (EmitJalrReloc &&
2470b57cec5SDimitry Andric       (MI->isReturn() || MI->isCall() || MI->isIndirectBranch())) {
2480b57cec5SDimitry Andric     emitDirectiveRelocJalr(*MI, OutContext, TM, *OutStreamer, *Subtarget);
2490b57cec5SDimitry Andric   }
2500b57cec5SDimitry Andric 
2510b57cec5SDimitry Andric   MachineBasicBlock::const_instr_iterator I = MI->getIterator();
2520b57cec5SDimitry Andric   MachineBasicBlock::const_instr_iterator E = MI->getParent()->instr_end();
2530b57cec5SDimitry Andric 
2540b57cec5SDimitry Andric   do {
2550b57cec5SDimitry Andric     // Do any auto-generated pseudo lowerings.
2560b57cec5SDimitry Andric     if (emitPseudoExpansionLowering(*OutStreamer, &*I))
2570b57cec5SDimitry Andric       continue;
2580b57cec5SDimitry Andric 
259480093f4SDimitry Andric     // Skip the BUNDLE pseudo instruction and lower the contents
260480093f4SDimitry Andric     if (I->isBundle())
261480093f4SDimitry Andric       continue;
262480093f4SDimitry Andric 
2630b57cec5SDimitry Andric     if (I->getOpcode() == Mips::PseudoReturn ||
2640b57cec5SDimitry Andric         I->getOpcode() == Mips::PseudoReturn64 ||
2650b57cec5SDimitry Andric         I->getOpcode() == Mips::PseudoIndirectBranch ||
2660b57cec5SDimitry Andric         I->getOpcode() == Mips::PseudoIndirectBranch64 ||
2670b57cec5SDimitry Andric         I->getOpcode() == Mips::TAILCALLREG ||
2680b57cec5SDimitry Andric         I->getOpcode() == Mips::TAILCALLREG64) {
2690b57cec5SDimitry Andric       emitPseudoIndirectBranch(*OutStreamer, &*I);
2700b57cec5SDimitry Andric       continue;
2710b57cec5SDimitry Andric     }
2720b57cec5SDimitry Andric 
2730b57cec5SDimitry Andric     // The inMips16Mode() test is not permanent.
2740b57cec5SDimitry Andric     // Some instructions are marked as pseudo right now which
2750b57cec5SDimitry Andric     // would make the test fail for the wrong reason but
2760b57cec5SDimitry Andric     // that will be fixed soon. We need this here because we are
2770b57cec5SDimitry Andric     // removing another test for this situation downstream in the
2780b57cec5SDimitry Andric     // callchain.
2790b57cec5SDimitry Andric     //
2800b57cec5SDimitry Andric     if (I->isPseudo() && !Subtarget->inMips16Mode()
2810b57cec5SDimitry Andric         && !isLongBranchPseudo(I->getOpcode()))
2825ffd83dbSDimitry Andric       llvm_unreachable("Pseudo opcode found in emitInstruction()");
2830b57cec5SDimitry Andric 
2840b57cec5SDimitry Andric     MCInst TmpInst0;
2850b57cec5SDimitry Andric     MCInstLowering.Lower(&*I, TmpInst0);
2860b57cec5SDimitry Andric     EmitToStreamer(*OutStreamer, TmpInst0);
2870b57cec5SDimitry Andric   } while ((++I != E) && I->isInsideBundle()); // Delay slot check
2880b57cec5SDimitry Andric }
2890b57cec5SDimitry Andric 
2900b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
2910b57cec5SDimitry Andric //
2920b57cec5SDimitry Andric //  Mips Asm Directives
2930b57cec5SDimitry Andric //
2940b57cec5SDimitry Andric //  -- Frame directive "frame Stackpointer, Stacksize, RARegister"
2950b57cec5SDimitry Andric //  Describe the stack frame.
2960b57cec5SDimitry Andric //
2970b57cec5SDimitry Andric //  -- Mask directives "(f)mask  bitmask, offset"
2980b57cec5SDimitry Andric //  Tells the assembler which registers are saved and where.
2990b57cec5SDimitry Andric //  bitmask - contain a little endian bitset indicating which registers are
3000b57cec5SDimitry Andric //            saved on function prologue (e.g. with a 0x80000000 mask, the
3010b57cec5SDimitry Andric //            assembler knows the register 31 (RA) is saved at prologue.
3020b57cec5SDimitry Andric //  offset  - the position before stack pointer subtraction indicating where
3030b57cec5SDimitry Andric //            the first saved register on prologue is located. (e.g. with a
3040b57cec5SDimitry Andric //
3050b57cec5SDimitry Andric //  Consider the following function prologue:
3060b57cec5SDimitry Andric //
3070b57cec5SDimitry Andric //    .frame  $fp,48,$ra
3080b57cec5SDimitry Andric //    .mask   0xc0000000,-8
3090b57cec5SDimitry Andric //       addiu $sp, $sp, -48
3100b57cec5SDimitry Andric //       sw $ra, 40($sp)
3110b57cec5SDimitry Andric //       sw $fp, 36($sp)
3120b57cec5SDimitry Andric //
3130b57cec5SDimitry Andric //    With a 0xc0000000 mask, the assembler knows the register 31 (RA) and
3140b57cec5SDimitry Andric //    30 (FP) are saved at prologue. As the save order on prologue is from
3150b57cec5SDimitry Andric //    left to right, RA is saved first. A -8 offset means that after the
3160b57cec5SDimitry Andric //    stack pointer subtration, the first register in the mask (RA) will be
3170b57cec5SDimitry Andric //    saved at address 48-8=40.
3180b57cec5SDimitry Andric //
3190b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
3200b57cec5SDimitry Andric 
3210b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
3220b57cec5SDimitry Andric // Mask directives
3230b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
3240b57cec5SDimitry Andric 
3250b57cec5SDimitry Andric // Create a bitmask with all callee saved registers for CPU or Floating Point
3260b57cec5SDimitry Andric // registers. For CPU registers consider RA, GP and FP for saving if necessary.
printSavedRegsBitmask()3270b57cec5SDimitry Andric void MipsAsmPrinter::printSavedRegsBitmask() {
3280b57cec5SDimitry Andric   // CPU and FPU Saved Registers Bitmasks
3290b57cec5SDimitry Andric   unsigned CPUBitmask = 0, FPUBitmask = 0;
3300b57cec5SDimitry Andric   int CPUTopSavedRegOff, FPUTopSavedRegOff;
3310b57cec5SDimitry Andric 
3320b57cec5SDimitry Andric   // Set the CPU and FPU Bitmasks
3330b57cec5SDimitry Andric   const MachineFrameInfo &MFI = MF->getFrameInfo();
3340b57cec5SDimitry Andric   const TargetRegisterInfo *TRI = MF->getSubtarget().getRegisterInfo();
3350b57cec5SDimitry Andric   const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo();
3360b57cec5SDimitry Andric   // size of stack area to which FP callee-saved regs are saved.
3370b57cec5SDimitry Andric   unsigned CPURegSize = TRI->getRegSizeInBits(Mips::GPR32RegClass) / 8;
3380b57cec5SDimitry Andric   unsigned FGR32RegSize = TRI->getRegSizeInBits(Mips::FGR32RegClass) / 8;
3390b57cec5SDimitry Andric   unsigned AFGR64RegSize = TRI->getRegSizeInBits(Mips::AFGR64RegClass) / 8;
3400b57cec5SDimitry Andric   bool HasAFGR64Reg = false;
3410b57cec5SDimitry Andric   unsigned CSFPRegsSize = 0;
3420b57cec5SDimitry Andric 
3430b57cec5SDimitry Andric   for (const auto &I : CSI) {
34404eeddc0SDimitry Andric     Register Reg = I.getReg();
3450b57cec5SDimitry Andric     unsigned RegNum = TRI->getEncodingValue(Reg);
3460b57cec5SDimitry Andric 
3470b57cec5SDimitry Andric     // If it's a floating point register, set the FPU Bitmask.
3480b57cec5SDimitry Andric     // If it's a general purpose register, set the CPU Bitmask.
3490b57cec5SDimitry Andric     if (Mips::FGR32RegClass.contains(Reg)) {
3500b57cec5SDimitry Andric       FPUBitmask |= (1 << RegNum);
3510b57cec5SDimitry Andric       CSFPRegsSize += FGR32RegSize;
3520b57cec5SDimitry Andric     } else if (Mips::AFGR64RegClass.contains(Reg)) {
3530b57cec5SDimitry Andric       FPUBitmask |= (3 << RegNum);
3540b57cec5SDimitry Andric       CSFPRegsSize += AFGR64RegSize;
3550b57cec5SDimitry Andric       HasAFGR64Reg = true;
3560b57cec5SDimitry Andric     } else if (Mips::GPR32RegClass.contains(Reg))
3570b57cec5SDimitry Andric       CPUBitmask |= (1 << RegNum);
3580b57cec5SDimitry Andric   }
3590b57cec5SDimitry Andric 
3600b57cec5SDimitry Andric   // FP Regs are saved right below where the virtual frame pointer points to.
3610b57cec5SDimitry Andric   FPUTopSavedRegOff = FPUBitmask ?
3620b57cec5SDimitry Andric     (HasAFGR64Reg ? -AFGR64RegSize : -FGR32RegSize) : 0;
3630b57cec5SDimitry Andric 
3640b57cec5SDimitry Andric   // CPU Regs are saved below FP Regs.
3650b57cec5SDimitry Andric   CPUTopSavedRegOff = CPUBitmask ? -CSFPRegsSize - CPURegSize : 0;
3660b57cec5SDimitry Andric 
3670b57cec5SDimitry Andric   MipsTargetStreamer &TS = getTargetStreamer();
3680b57cec5SDimitry Andric   // Print CPUBitmask
3690b57cec5SDimitry Andric   TS.emitMask(CPUBitmask, CPUTopSavedRegOff);
3700b57cec5SDimitry Andric 
3710b57cec5SDimitry Andric   // Print FPUBitmask
3720b57cec5SDimitry Andric   TS.emitFMask(FPUBitmask, FPUTopSavedRegOff);
3730b57cec5SDimitry Andric }
3740b57cec5SDimitry Andric 
3750b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
3760b57cec5SDimitry Andric // Frame and Set directives
3770b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
3780b57cec5SDimitry Andric 
3790b57cec5SDimitry Andric /// Frame Directive
emitFrameDirective()3800b57cec5SDimitry Andric void MipsAsmPrinter::emitFrameDirective() {
3810b57cec5SDimitry Andric   const TargetRegisterInfo &RI = *MF->getSubtarget().getRegisterInfo();
3820b57cec5SDimitry Andric 
3838bcb0991SDimitry Andric   Register stackReg = RI.getFrameRegister(*MF);
3840b57cec5SDimitry Andric   unsigned returnReg = RI.getRARegister();
3850b57cec5SDimitry Andric   unsigned stackSize = MF->getFrameInfo().getStackSize();
3860b57cec5SDimitry Andric 
3870b57cec5SDimitry Andric   getTargetStreamer().emitFrame(stackReg, stackSize, returnReg);
3880b57cec5SDimitry Andric }
3890b57cec5SDimitry Andric 
3900b57cec5SDimitry Andric /// Emit Set directives.
getCurrentABIString() const3910b57cec5SDimitry Andric const char *MipsAsmPrinter::getCurrentABIString() const {
3920b57cec5SDimitry Andric   switch (static_cast<MipsTargetMachine &>(TM).getABI().GetEnumValue()) {
3930b57cec5SDimitry Andric   case MipsABIInfo::ABI::O32:  return "abi32";
3940b57cec5SDimitry Andric   case MipsABIInfo::ABI::N32:  return "abiN32";
3950b57cec5SDimitry Andric   case MipsABIInfo::ABI::N64:  return "abi64";
3960b57cec5SDimitry Andric   default: llvm_unreachable("Unknown Mips ABI");
3970b57cec5SDimitry Andric   }
3980b57cec5SDimitry Andric }
3990b57cec5SDimitry Andric 
emitFunctionEntryLabel()4005ffd83dbSDimitry Andric void MipsAsmPrinter::emitFunctionEntryLabel() {
4010b57cec5SDimitry Andric   MipsTargetStreamer &TS = getTargetStreamer();
4020b57cec5SDimitry Andric 
4030b57cec5SDimitry Andric   // NaCl sandboxing requires that indirect call instructions are masked.
4040b57cec5SDimitry Andric   // This means that function entry points should be bundle-aligned.
4050b57cec5SDimitry Andric   if (Subtarget->isTargetNaCl())
4065ffd83dbSDimitry Andric     emitAlignment(std::max(MF->getAlignment(), MIPS_NACL_BUNDLE_ALIGN));
4070b57cec5SDimitry Andric 
4080b57cec5SDimitry Andric   if (Subtarget->inMicroMipsMode()) {
4090b57cec5SDimitry Andric     TS.emitDirectiveSetMicroMips();
4100b57cec5SDimitry Andric     TS.setUsesMicroMips();
4110b57cec5SDimitry Andric     TS.updateABIInfo(*Subtarget);
4120b57cec5SDimitry Andric   } else
4130b57cec5SDimitry Andric     TS.emitDirectiveSetNoMicroMips();
4140b57cec5SDimitry Andric 
4150b57cec5SDimitry Andric   if (Subtarget->inMips16Mode())
4160b57cec5SDimitry Andric     TS.emitDirectiveSetMips16();
4170b57cec5SDimitry Andric   else
4180b57cec5SDimitry Andric     TS.emitDirectiveSetNoMips16();
4190b57cec5SDimitry Andric 
4200b57cec5SDimitry Andric   TS.emitDirectiveEnt(*CurrentFnSym);
4215ffd83dbSDimitry Andric   OutStreamer->emitLabel(CurrentFnSym);
4220b57cec5SDimitry Andric }
4230b57cec5SDimitry Andric 
4240b57cec5SDimitry Andric /// EmitFunctionBodyStart - Targets can override this to emit stuff before
4250b57cec5SDimitry Andric /// the first basic block in the function.
emitFunctionBodyStart()4265ffd83dbSDimitry Andric void MipsAsmPrinter::emitFunctionBodyStart() {
4270b57cec5SDimitry Andric   MipsTargetStreamer &TS = getTargetStreamer();
4280b57cec5SDimitry Andric 
4290b57cec5SDimitry Andric   MCInstLowering.Initialize(&MF->getContext());
4300b57cec5SDimitry Andric 
4310b57cec5SDimitry Andric   bool IsNakedFunction = MF->getFunction().hasFnAttribute(Attribute::Naked);
4320b57cec5SDimitry Andric   if (!IsNakedFunction)
4330b57cec5SDimitry Andric     emitFrameDirective();
4340b57cec5SDimitry Andric 
4350b57cec5SDimitry Andric   if (!IsNakedFunction)
4360b57cec5SDimitry Andric     printSavedRegsBitmask();
4370b57cec5SDimitry Andric 
4380b57cec5SDimitry Andric   if (!Subtarget->inMips16Mode()) {
4390b57cec5SDimitry Andric     TS.emitDirectiveSetNoReorder();
4400b57cec5SDimitry Andric     TS.emitDirectiveSetNoMacro();
4410b57cec5SDimitry Andric     TS.emitDirectiveSetNoAt();
4420b57cec5SDimitry Andric   }
4430b57cec5SDimitry Andric }
4440b57cec5SDimitry Andric 
4450b57cec5SDimitry Andric /// EmitFunctionBodyEnd - Targets can override this to emit stuff after
4460b57cec5SDimitry Andric /// the last basic block in the function.
emitFunctionBodyEnd()4475ffd83dbSDimitry Andric void MipsAsmPrinter::emitFunctionBodyEnd() {
4480b57cec5SDimitry Andric   MipsTargetStreamer &TS = getTargetStreamer();
4490b57cec5SDimitry Andric 
4500b57cec5SDimitry Andric   // There are instruction for this macros, but they must
4510b57cec5SDimitry Andric   // always be at the function end, and we can't emit and
4520b57cec5SDimitry Andric   // break with BB logic.
4530b57cec5SDimitry Andric   if (!Subtarget->inMips16Mode()) {
4540b57cec5SDimitry Andric     TS.emitDirectiveSetAt();
4550b57cec5SDimitry Andric     TS.emitDirectiveSetMacro();
4560b57cec5SDimitry Andric     TS.emitDirectiveSetReorder();
4570b57cec5SDimitry Andric   }
4580b57cec5SDimitry Andric   TS.emitDirectiveEnd(CurrentFnSym->getName());
4590b57cec5SDimitry Andric   // Make sure to terminate any constant pools that were at the end
4600b57cec5SDimitry Andric   // of the function.
4610b57cec5SDimitry Andric   if (!InConstantPool)
4620b57cec5SDimitry Andric     return;
4630b57cec5SDimitry Andric   InConstantPool = false;
4645ffd83dbSDimitry Andric   OutStreamer->emitDataRegion(MCDR_DataRegionEnd);
4650b57cec5SDimitry Andric }
4660b57cec5SDimitry Andric 
emitBasicBlockEnd(const MachineBasicBlock & MBB)4675ffd83dbSDimitry Andric void MipsAsmPrinter::emitBasicBlockEnd(const MachineBasicBlock &MBB) {
4685ffd83dbSDimitry Andric   AsmPrinter::emitBasicBlockEnd(MBB);
4690b57cec5SDimitry Andric   MipsTargetStreamer &TS = getTargetStreamer();
4700b57cec5SDimitry Andric   if (MBB.empty())
4710b57cec5SDimitry Andric     TS.emitDirectiveInsn();
4720b57cec5SDimitry Andric }
4730b57cec5SDimitry Andric 
4740b57cec5SDimitry Andric // Print out an operand for an inline asm expression.
PrintAsmOperand(const MachineInstr * MI,unsigned OpNum,const char * ExtraCode,raw_ostream & O)4750b57cec5SDimitry Andric bool MipsAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNum,
4760b57cec5SDimitry Andric                                      const char *ExtraCode, raw_ostream &O) {
4770b57cec5SDimitry Andric   // Does this asm operand have a single letter operand modifier?
4780b57cec5SDimitry Andric   if (ExtraCode && ExtraCode[0]) {
4790b57cec5SDimitry Andric     if (ExtraCode[1] != 0) return true; // Unknown modifier.
4800b57cec5SDimitry Andric 
4810b57cec5SDimitry Andric     const MachineOperand &MO = MI->getOperand(OpNum);
4820b57cec5SDimitry Andric     switch (ExtraCode[0]) {
4830b57cec5SDimitry Andric     default:
4840b57cec5SDimitry Andric       // See if this is a generic print operand
4850b57cec5SDimitry Andric       return AsmPrinter::PrintAsmOperand(MI, OpNum, ExtraCode, O);
4860b57cec5SDimitry Andric     case 'X': // hex const int
48781ad6265SDimitry Andric       if (!MO.isImm())
4880b57cec5SDimitry Andric         return true;
4890b57cec5SDimitry Andric       O << "0x" << Twine::utohexstr(MO.getImm());
4900b57cec5SDimitry Andric       return false;
4910b57cec5SDimitry Andric     case 'x': // hex const int (low 16 bits)
49281ad6265SDimitry Andric       if (!MO.isImm())
4930b57cec5SDimitry Andric         return true;
4940b57cec5SDimitry Andric       O << "0x" << Twine::utohexstr(MO.getImm() & 0xffff);
4950b57cec5SDimitry Andric       return false;
4960b57cec5SDimitry Andric     case 'd': // decimal const int
49781ad6265SDimitry Andric       if (!MO.isImm())
4980b57cec5SDimitry Andric         return true;
4990b57cec5SDimitry Andric       O << MO.getImm();
5000b57cec5SDimitry Andric       return false;
5010b57cec5SDimitry Andric     case 'm': // decimal const int minus 1
50281ad6265SDimitry Andric       if (!MO.isImm())
5030b57cec5SDimitry Andric         return true;
5040b57cec5SDimitry Andric       O << MO.getImm() - 1;
5050b57cec5SDimitry Andric       return false;
5060b57cec5SDimitry Andric     case 'y': // exact log2
50781ad6265SDimitry Andric       if (!MO.isImm())
5080b57cec5SDimitry Andric         return true;
5090b57cec5SDimitry Andric       if (!isPowerOf2_64(MO.getImm()))
5100b57cec5SDimitry Andric         return true;
5110b57cec5SDimitry Andric       O << Log2_64(MO.getImm());
5120b57cec5SDimitry Andric       return false;
5130b57cec5SDimitry Andric     case 'z':
5140b57cec5SDimitry Andric       // $0 if zero, regular printing otherwise
51581ad6265SDimitry Andric       if (MO.isImm() && MO.getImm() == 0) {
5160b57cec5SDimitry Andric         O << "$0";
5170b57cec5SDimitry Andric         return false;
5180b57cec5SDimitry Andric       }
5190b57cec5SDimitry Andric       // If not, call printOperand as normal.
5200b57cec5SDimitry Andric       break;
5210b57cec5SDimitry Andric     case 'D': // Second part of a double word register operand
5220b57cec5SDimitry Andric     case 'L': // Low order register of a double word register operand
5230b57cec5SDimitry Andric     case 'M': // High order register of a double word register operand
5240b57cec5SDimitry Andric     {
5250b57cec5SDimitry Andric       if (OpNum == 0)
5260b57cec5SDimitry Andric         return true;
5270b57cec5SDimitry Andric       const MachineOperand &FlagsOP = MI->getOperand(OpNum - 1);
5280b57cec5SDimitry Andric       if (!FlagsOP.isImm())
5290b57cec5SDimitry Andric         return true;
5305f757f3fSDimitry Andric       const InlineAsm::Flag Flags(FlagsOP.getImm());
5315f757f3fSDimitry Andric       const unsigned NumVals = Flags.getNumOperandRegisters();
5320b57cec5SDimitry Andric       // Number of registers represented by this operand. We are looking
5330b57cec5SDimitry Andric       // for 2 for 32 bit mode and 1 for 64 bit mode.
5340b57cec5SDimitry Andric       if (NumVals != 2) {
5350b57cec5SDimitry Andric         if (Subtarget->isGP64bit() && NumVals == 1 && MO.isReg()) {
5368bcb0991SDimitry Andric           Register Reg = MO.getReg();
5370b57cec5SDimitry Andric           O << '$' << MipsInstPrinter::getRegisterName(Reg);
5380b57cec5SDimitry Andric           return false;
5390b57cec5SDimitry Andric         }
5400b57cec5SDimitry Andric         return true;
5410b57cec5SDimitry Andric       }
5420b57cec5SDimitry Andric 
5430b57cec5SDimitry Andric       unsigned RegOp = OpNum;
5440b57cec5SDimitry Andric       if (!Subtarget->isGP64bit()){
5450b57cec5SDimitry Andric         // Endianness reverses which register holds the high or low value
5460b57cec5SDimitry Andric         // between M and L.
5470b57cec5SDimitry Andric         switch(ExtraCode[0]) {
5480b57cec5SDimitry Andric         case 'M':
5490b57cec5SDimitry Andric           RegOp = (Subtarget->isLittle()) ? OpNum + 1 : OpNum;
5500b57cec5SDimitry Andric           break;
5510b57cec5SDimitry Andric         case 'L':
5520b57cec5SDimitry Andric           RegOp = (Subtarget->isLittle()) ? OpNum : OpNum + 1;
5530b57cec5SDimitry Andric           break;
5540b57cec5SDimitry Andric         case 'D': // Always the second part
5550b57cec5SDimitry Andric           RegOp = OpNum + 1;
5560b57cec5SDimitry Andric         }
5570b57cec5SDimitry Andric         if (RegOp >= MI->getNumOperands())
5580b57cec5SDimitry Andric           return true;
5590b57cec5SDimitry Andric         const MachineOperand &MO = MI->getOperand(RegOp);
5600b57cec5SDimitry Andric         if (!MO.isReg())
5610b57cec5SDimitry Andric           return true;
5628bcb0991SDimitry Andric         Register Reg = MO.getReg();
5630b57cec5SDimitry Andric         O << '$' << MipsInstPrinter::getRegisterName(Reg);
5640b57cec5SDimitry Andric         return false;
5650b57cec5SDimitry Andric       }
5660b57cec5SDimitry Andric       break;
5670b57cec5SDimitry Andric     }
5680b57cec5SDimitry Andric     case 'w':
5690b57cec5SDimitry Andric       // Print MSA registers for the 'f' constraint
5700b57cec5SDimitry Andric       // In LLVM, the 'w' modifier doesn't need to do anything.
5710b57cec5SDimitry Andric       // We can just call printOperand as normal.
5720b57cec5SDimitry Andric       break;
5730b57cec5SDimitry Andric     }
5740b57cec5SDimitry Andric   }
5750b57cec5SDimitry Andric 
5760b57cec5SDimitry Andric   printOperand(MI, OpNum, O);
5770b57cec5SDimitry Andric   return false;
5780b57cec5SDimitry Andric }
5790b57cec5SDimitry Andric 
PrintAsmMemoryOperand(const MachineInstr * MI,unsigned OpNum,const char * ExtraCode,raw_ostream & O)5800b57cec5SDimitry Andric bool MipsAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,
5810b57cec5SDimitry Andric                                            unsigned OpNum,
5820b57cec5SDimitry Andric                                            const char *ExtraCode,
5830b57cec5SDimitry Andric                                            raw_ostream &O) {
5840b57cec5SDimitry Andric   assert(OpNum + 1 < MI->getNumOperands() && "Insufficient operands");
5850b57cec5SDimitry Andric   const MachineOperand &BaseMO = MI->getOperand(OpNum);
5860b57cec5SDimitry Andric   const MachineOperand &OffsetMO = MI->getOperand(OpNum + 1);
587480093f4SDimitry Andric   assert(BaseMO.isReg() &&
588480093f4SDimitry Andric          "Unexpected base pointer for inline asm memory operand.");
589480093f4SDimitry Andric   assert(OffsetMO.isImm() &&
590480093f4SDimitry Andric          "Unexpected offset for inline asm memory operand.");
5910b57cec5SDimitry Andric   int Offset = OffsetMO.getImm();
5920b57cec5SDimitry Andric 
5930b57cec5SDimitry Andric   // Currently we are expecting either no ExtraCode or 'D','M','L'.
5940b57cec5SDimitry Andric   if (ExtraCode) {
5950b57cec5SDimitry Andric     switch (ExtraCode[0]) {
5960b57cec5SDimitry Andric     case 'D':
5970b57cec5SDimitry Andric       Offset += 4;
5980b57cec5SDimitry Andric       break;
5990b57cec5SDimitry Andric     case 'M':
6000b57cec5SDimitry Andric       if (Subtarget->isLittle())
6010b57cec5SDimitry Andric         Offset += 4;
6020b57cec5SDimitry Andric       break;
6030b57cec5SDimitry Andric     case 'L':
6040b57cec5SDimitry Andric       if (!Subtarget->isLittle())
6050b57cec5SDimitry Andric         Offset += 4;
6060b57cec5SDimitry Andric       break;
6070b57cec5SDimitry Andric     default:
6080b57cec5SDimitry Andric       return true; // Unknown modifier.
6090b57cec5SDimitry Andric     }
6100b57cec5SDimitry Andric   }
6110b57cec5SDimitry Andric 
6120b57cec5SDimitry Andric   O << Offset << "($" << MipsInstPrinter::getRegisterName(BaseMO.getReg())
6130b57cec5SDimitry Andric     << ")";
6140b57cec5SDimitry Andric 
6150b57cec5SDimitry Andric   return false;
6160b57cec5SDimitry Andric }
6170b57cec5SDimitry Andric 
printOperand(const MachineInstr * MI,int opNum,raw_ostream & O)6180b57cec5SDimitry Andric void MipsAsmPrinter::printOperand(const MachineInstr *MI, int opNum,
6190b57cec5SDimitry Andric                                   raw_ostream &O) {
6200b57cec5SDimitry Andric   const MachineOperand &MO = MI->getOperand(opNum);
6210b57cec5SDimitry Andric   bool closeP = false;
6220b57cec5SDimitry Andric 
6230b57cec5SDimitry Andric   if (MO.getTargetFlags())
6240b57cec5SDimitry Andric     closeP = true;
6250b57cec5SDimitry Andric 
6260b57cec5SDimitry Andric   switch(MO.getTargetFlags()) {
6270b57cec5SDimitry Andric   case MipsII::MO_GPREL:    O << "%gp_rel("; break;
6280b57cec5SDimitry Andric   case MipsII::MO_GOT_CALL: O << "%call16("; break;
6290b57cec5SDimitry Andric   case MipsII::MO_GOT:      O << "%got(";    break;
6300b57cec5SDimitry Andric   case MipsII::MO_ABS_HI:   O << "%hi(";     break;
6310b57cec5SDimitry Andric   case MipsII::MO_ABS_LO:   O << "%lo(";     break;
6320b57cec5SDimitry Andric   case MipsII::MO_HIGHER:   O << "%higher("; break;
6330b57cec5SDimitry Andric   case MipsII::MO_HIGHEST:  O << "%highest(("; break;
6340b57cec5SDimitry Andric   case MipsII::MO_TLSGD:    O << "%tlsgd(";  break;
6350b57cec5SDimitry Andric   case MipsII::MO_GOTTPREL: O << "%gottprel("; break;
6360b57cec5SDimitry Andric   case MipsII::MO_TPREL_HI: O << "%tprel_hi("; break;
6370b57cec5SDimitry Andric   case MipsII::MO_TPREL_LO: O << "%tprel_lo("; break;
6380b57cec5SDimitry Andric   case MipsII::MO_GPOFF_HI: O << "%hi(%neg(%gp_rel("; break;
6390b57cec5SDimitry Andric   case MipsII::MO_GPOFF_LO: O << "%lo(%neg(%gp_rel("; break;
6400b57cec5SDimitry Andric   case MipsII::MO_GOT_DISP: O << "%got_disp("; break;
6410b57cec5SDimitry Andric   case MipsII::MO_GOT_PAGE: O << "%got_page("; break;
6420b57cec5SDimitry Andric   case MipsII::MO_GOT_OFST: O << "%got_ofst("; break;
6430b57cec5SDimitry Andric   }
6440b57cec5SDimitry Andric 
6450b57cec5SDimitry Andric   switch (MO.getType()) {
6460b57cec5SDimitry Andric     case MachineOperand::MO_Register:
6470b57cec5SDimitry Andric       O << '$'
6480b57cec5SDimitry Andric         << StringRef(MipsInstPrinter::getRegisterName(MO.getReg())).lower();
6490b57cec5SDimitry Andric       break;
6500b57cec5SDimitry Andric 
6510b57cec5SDimitry Andric     case MachineOperand::MO_Immediate:
6520b57cec5SDimitry Andric       O << MO.getImm();
6530b57cec5SDimitry Andric       break;
6540b57cec5SDimitry Andric 
6550b57cec5SDimitry Andric     case MachineOperand::MO_MachineBasicBlock:
6560b57cec5SDimitry Andric       MO.getMBB()->getSymbol()->print(O, MAI);
6570b57cec5SDimitry Andric       return;
6580b57cec5SDimitry Andric 
6590b57cec5SDimitry Andric     case MachineOperand::MO_GlobalAddress:
6600b57cec5SDimitry Andric       PrintSymbolOperand(MO, O);
6610b57cec5SDimitry Andric       break;
6620b57cec5SDimitry Andric 
6630b57cec5SDimitry Andric     case MachineOperand::MO_BlockAddress: {
6640b57cec5SDimitry Andric       MCSymbol *BA = GetBlockAddressSymbol(MO.getBlockAddress());
6650b57cec5SDimitry Andric       O << BA->getName();
6660b57cec5SDimitry Andric       break;
6670b57cec5SDimitry Andric     }
6680b57cec5SDimitry Andric 
6690b57cec5SDimitry Andric     case MachineOperand::MO_ConstantPoolIndex:
6700b57cec5SDimitry Andric       O << getDataLayout().getPrivateGlobalPrefix() << "CPI"
6710b57cec5SDimitry Andric         << getFunctionNumber() << "_" << MO.getIndex();
6720b57cec5SDimitry Andric       if (MO.getOffset())
6730b57cec5SDimitry Andric         O << "+" << MO.getOffset();
6740b57cec5SDimitry Andric       break;
6750b57cec5SDimitry Andric 
6760b57cec5SDimitry Andric     default:
6770b57cec5SDimitry Andric       llvm_unreachable("<unknown operand type>");
6780b57cec5SDimitry Andric   }
6790b57cec5SDimitry Andric 
6800b57cec5SDimitry Andric   if (closeP) O << ")";
6810b57cec5SDimitry Andric }
6820b57cec5SDimitry Andric 
6830b57cec5SDimitry Andric void MipsAsmPrinter::
printMemOperand(const MachineInstr * MI,int opNum,raw_ostream & O)6840b57cec5SDimitry Andric printMemOperand(const MachineInstr *MI, int opNum, raw_ostream &O) {
6850b57cec5SDimitry Andric   // Load/Store memory operands -- imm($reg)
6860b57cec5SDimitry Andric   // If PIC target the target is loaded as the
6870b57cec5SDimitry Andric   // pattern lw $25,%call16($28)
6880b57cec5SDimitry Andric 
6890b57cec5SDimitry Andric   // opNum can be invalid if instruction has reglist as operand.
6900b57cec5SDimitry Andric   // MemOperand is always last operand of instruction (base + offset).
6910b57cec5SDimitry Andric   switch (MI->getOpcode()) {
6920b57cec5SDimitry Andric   default:
6930b57cec5SDimitry Andric     break;
6940b57cec5SDimitry Andric   case Mips::SWM32_MM:
6950b57cec5SDimitry Andric   case Mips::LWM32_MM:
6960b57cec5SDimitry Andric     opNum = MI->getNumOperands() - 2;
6970b57cec5SDimitry Andric     break;
6980b57cec5SDimitry Andric   }
6990b57cec5SDimitry Andric 
7000b57cec5SDimitry Andric   printOperand(MI, opNum+1, O);
7010b57cec5SDimitry Andric   O << "(";
7020b57cec5SDimitry Andric   printOperand(MI, opNum, O);
7030b57cec5SDimitry Andric   O << ")";
7040b57cec5SDimitry Andric }
7050b57cec5SDimitry Andric 
7060b57cec5SDimitry Andric void MipsAsmPrinter::
printMemOperandEA(const MachineInstr * MI,int opNum,raw_ostream & O)7070b57cec5SDimitry Andric printMemOperandEA(const MachineInstr *MI, int opNum, raw_ostream &O) {
7080b57cec5SDimitry Andric   // when using stack locations for not load/store instructions
7090b57cec5SDimitry Andric   // print the same way as all normal 3 operand instructions.
7100b57cec5SDimitry Andric   printOperand(MI, opNum, O);
7110b57cec5SDimitry Andric   O << ", ";
7120b57cec5SDimitry Andric   printOperand(MI, opNum+1, O);
7130b57cec5SDimitry Andric }
7140b57cec5SDimitry Andric 
7150b57cec5SDimitry Andric void MipsAsmPrinter::
printFCCOperand(const MachineInstr * MI,int opNum,raw_ostream & O,const char * Modifier)7160b57cec5SDimitry Andric printFCCOperand(const MachineInstr *MI, int opNum, raw_ostream &O,
7170b57cec5SDimitry Andric                 const char *Modifier) {
7180b57cec5SDimitry Andric   const MachineOperand &MO = MI->getOperand(opNum);
7190b57cec5SDimitry Andric   O << Mips::MipsFCCToString((Mips::CondCode)MO.getImm());
7200b57cec5SDimitry Andric }
7210b57cec5SDimitry Andric 
7220b57cec5SDimitry Andric void MipsAsmPrinter::
printRegisterList(const MachineInstr * MI,int opNum,raw_ostream & O)7230b57cec5SDimitry Andric printRegisterList(const MachineInstr *MI, int opNum, raw_ostream &O) {
7240b57cec5SDimitry Andric   for (int i = opNum, e = MI->getNumOperands(); i != e; ++i) {
7250b57cec5SDimitry Andric     if (i != opNum) O << ", ";
7260b57cec5SDimitry Andric     printOperand(MI, i, O);
7270b57cec5SDimitry Andric   }
7280b57cec5SDimitry Andric }
7290b57cec5SDimitry Andric 
emitStartOfAsmFile(Module & M)7305ffd83dbSDimitry Andric void MipsAsmPrinter::emitStartOfAsmFile(Module &M) {
7310b57cec5SDimitry Andric   MipsTargetStreamer &TS = getTargetStreamer();
7320b57cec5SDimitry Andric 
7330b57cec5SDimitry Andric   // MipsTargetStreamer has an initialization order problem when emitting an
7340b57cec5SDimitry Andric   // object file directly (see MipsTargetELFStreamer for full details). Work
7350b57cec5SDimitry Andric   // around it by re-initializing the PIC state here.
7360b57cec5SDimitry Andric   TS.setPic(OutContext.getObjectFileInfo()->isPositionIndependent());
7370b57cec5SDimitry Andric 
73806c3fb27SDimitry Andric   // Try to get target-features from the first function.
73906c3fb27SDimitry Andric   StringRef FS = TM.getTargetFeatureString();
74006c3fb27SDimitry Andric   Module::iterator F = M.begin();
74106c3fb27SDimitry Andric   if (FS.empty() && M.size() && F->hasFnAttribute("target-features"))
74206c3fb27SDimitry Andric     FS = F->getFnAttribute("target-features").getValueAsString();
74306c3fb27SDimitry Andric 
7440b57cec5SDimitry Andric   // Compute MIPS architecture attributes based on the default subtarget
74506c3fb27SDimitry Andric   // that we'd have constructed.
7460b57cec5SDimitry Andric   // FIXME: For ifunc related functions we could iterate over and look
7470b57cec5SDimitry Andric   // for a feature string that doesn't match the default one.
7480b57cec5SDimitry Andric   const Triple &TT = TM.getTargetTriple();
7490b57cec5SDimitry Andric   StringRef CPU = MIPS_MC::selectMipsCPU(TT, TM.getTargetCPU());
7500b57cec5SDimitry Andric   const MipsTargetMachine &MTM = static_cast<const MipsTargetMachine &>(TM);
751bdd1243dSDimitry Andric   const MipsSubtarget STI(TT, CPU, FS, MTM.isLittleEndian(), MTM, std::nullopt);
7520b57cec5SDimitry Andric 
7530b57cec5SDimitry Andric   bool IsABICalls = STI.isABICalls();
7540b57cec5SDimitry Andric   const MipsABIInfo &ABI = MTM.getABI();
7550b57cec5SDimitry Andric   if (IsABICalls) {
7560b57cec5SDimitry Andric     TS.emitDirectiveAbiCalls();
7570b57cec5SDimitry Andric     // FIXME: This condition should be a lot more complicated that it is here.
7580b57cec5SDimitry Andric     //        Ideally it should test for properties of the ABI and not the ABI
7590b57cec5SDimitry Andric     //        itself.
7600b57cec5SDimitry Andric     //        For the moment, I'm only correcting enough to make MIPS-IV work.
7610b57cec5SDimitry Andric     if (!isPositionIndependent() && STI.hasSym32())
7620b57cec5SDimitry Andric       TS.emitDirectiveOptionPic0();
7630b57cec5SDimitry Andric   }
7640b57cec5SDimitry Andric 
7650b57cec5SDimitry Andric   // Tell the assembler which ABI we are using
7660b57cec5SDimitry Andric   std::string SectionName = std::string(".mdebug.") + getCurrentABIString();
76781ad6265SDimitry Andric   OutStreamer->switchSection(
7680b57cec5SDimitry Andric       OutContext.getELFSection(SectionName, ELF::SHT_PROGBITS, 0));
7690b57cec5SDimitry Andric 
7700b57cec5SDimitry Andric   // NaN: At the moment we only support:
7710b57cec5SDimitry Andric   // 1. .nan legacy (default)
7720b57cec5SDimitry Andric   // 2. .nan 2008
7730b57cec5SDimitry Andric   STI.isNaN2008() ? TS.emitDirectiveNaN2008()
7740b57cec5SDimitry Andric                   : TS.emitDirectiveNaNLegacy();
7750b57cec5SDimitry Andric 
7760b57cec5SDimitry Andric   // TODO: handle O64 ABI
7770b57cec5SDimitry Andric 
7780b57cec5SDimitry Andric   TS.updateABIInfo(STI);
7790b57cec5SDimitry Andric 
7800b57cec5SDimitry Andric   // We should always emit a '.module fp=...' but binutils 2.24 does not accept
7810b57cec5SDimitry Andric   // it. We therefore emit it when it contradicts the ABI defaults (-mfpxx or
7820b57cec5SDimitry Andric   // -mfp64) and omit it otherwise.
7830b57cec5SDimitry Andric   if ((ABI.IsO32() && (STI.isABI_FPXX() || STI.isFP64bit())) ||
7840b57cec5SDimitry Andric       STI.useSoftFloat())
7850b57cec5SDimitry Andric     TS.emitDirectiveModuleFP();
7860b57cec5SDimitry Andric 
7870b57cec5SDimitry Andric   // We should always emit a '.module [no]oddspreg' but binutils 2.24 does not
7880b57cec5SDimitry Andric   // accept it. We therefore emit it when it contradicts the default or an
7890b57cec5SDimitry Andric   // option has changed the default (i.e. FPXX) and omit it otherwise.
7900b57cec5SDimitry Andric   if (ABI.IsO32() && (!STI.useOddSPReg() || STI.isABI_FPXX()))
7910b57cec5SDimitry Andric     TS.emitDirectiveModuleOddSPReg();
7928bcb0991SDimitry Andric 
7938bcb0991SDimitry Andric   // Switch to the .text section.
79481ad6265SDimitry Andric   OutStreamer->switchSection(getObjFileLowering().getTextSection());
7950b57cec5SDimitry Andric }
7960b57cec5SDimitry Andric 
emitInlineAsmStart() const7970b57cec5SDimitry Andric void MipsAsmPrinter::emitInlineAsmStart() const {
7980b57cec5SDimitry Andric   MipsTargetStreamer &TS = getTargetStreamer();
7990b57cec5SDimitry Andric 
8000b57cec5SDimitry Andric   // GCC's choice of assembler options for inline assembly code ('at', 'macro'
8010b57cec5SDimitry Andric   // and 'reorder') is different from LLVM's choice for generated code ('noat',
8020b57cec5SDimitry Andric   // 'nomacro' and 'noreorder').
8030b57cec5SDimitry Andric   // In order to maintain compatibility with inline assembly code which depends
8040b57cec5SDimitry Andric   // on GCC's assembler options being used, we have to switch to those options
8050b57cec5SDimitry Andric   // for the duration of the inline assembly block and then switch back.
8060b57cec5SDimitry Andric   TS.emitDirectiveSetPush();
8070b57cec5SDimitry Andric   TS.emitDirectiveSetAt();
8080b57cec5SDimitry Andric   TS.emitDirectiveSetMacro();
8090b57cec5SDimitry Andric   TS.emitDirectiveSetReorder();
81081ad6265SDimitry Andric   OutStreamer->addBlankLine();
8110b57cec5SDimitry Andric }
8120b57cec5SDimitry Andric 
emitInlineAsmEnd(const MCSubtargetInfo & StartInfo,const MCSubtargetInfo * EndInfo) const8130b57cec5SDimitry Andric void MipsAsmPrinter::emitInlineAsmEnd(const MCSubtargetInfo &StartInfo,
8140b57cec5SDimitry Andric                                       const MCSubtargetInfo *EndInfo) const {
81581ad6265SDimitry Andric   OutStreamer->addBlankLine();
8160b57cec5SDimitry Andric   getTargetStreamer().emitDirectiveSetPop();
8170b57cec5SDimitry Andric }
8180b57cec5SDimitry Andric 
EmitJal(const MCSubtargetInfo & STI,MCSymbol * Symbol)8190b57cec5SDimitry Andric void MipsAsmPrinter::EmitJal(const MCSubtargetInfo &STI, MCSymbol *Symbol) {
8200b57cec5SDimitry Andric   MCInst I;
8210b57cec5SDimitry Andric   I.setOpcode(Mips::JAL);
8220b57cec5SDimitry Andric   I.addOperand(
8230b57cec5SDimitry Andric       MCOperand::createExpr(MCSymbolRefExpr::create(Symbol, OutContext)));
8245ffd83dbSDimitry Andric   OutStreamer->emitInstruction(I, STI);
8250b57cec5SDimitry Andric }
8260b57cec5SDimitry Andric 
EmitInstrReg(const MCSubtargetInfo & STI,unsigned Opcode,unsigned Reg)8270b57cec5SDimitry Andric void MipsAsmPrinter::EmitInstrReg(const MCSubtargetInfo &STI, unsigned Opcode,
8280b57cec5SDimitry Andric                                   unsigned Reg) {
8290b57cec5SDimitry Andric   MCInst I;
8300b57cec5SDimitry Andric   I.setOpcode(Opcode);
8310b57cec5SDimitry Andric   I.addOperand(MCOperand::createReg(Reg));
8325ffd83dbSDimitry Andric   OutStreamer->emitInstruction(I, STI);
8330b57cec5SDimitry Andric }
8340b57cec5SDimitry Andric 
EmitInstrRegReg(const MCSubtargetInfo & STI,unsigned Opcode,unsigned Reg1,unsigned Reg2)8350b57cec5SDimitry Andric void MipsAsmPrinter::EmitInstrRegReg(const MCSubtargetInfo &STI,
8360b57cec5SDimitry Andric                                      unsigned Opcode, unsigned Reg1,
8370b57cec5SDimitry Andric                                      unsigned Reg2) {
8380b57cec5SDimitry Andric   MCInst I;
8390b57cec5SDimitry Andric   //
8400b57cec5SDimitry Andric   // Because of the current td files for Mips32, the operands for MTC1
8410b57cec5SDimitry Andric   // appear backwards from their normal assembly order. It's not a trivial
8420b57cec5SDimitry Andric   // change to fix this in the td file so we adjust for it here.
8430b57cec5SDimitry Andric   //
8440b57cec5SDimitry Andric   if (Opcode == Mips::MTC1) {
8450b57cec5SDimitry Andric     unsigned Temp = Reg1;
8460b57cec5SDimitry Andric     Reg1 = Reg2;
8470b57cec5SDimitry Andric     Reg2 = Temp;
8480b57cec5SDimitry Andric   }
8490b57cec5SDimitry Andric   I.setOpcode(Opcode);
8500b57cec5SDimitry Andric   I.addOperand(MCOperand::createReg(Reg1));
8510b57cec5SDimitry Andric   I.addOperand(MCOperand::createReg(Reg2));
8525ffd83dbSDimitry Andric   OutStreamer->emitInstruction(I, STI);
8530b57cec5SDimitry Andric }
8540b57cec5SDimitry Andric 
EmitInstrRegRegReg(const MCSubtargetInfo & STI,unsigned Opcode,unsigned Reg1,unsigned Reg2,unsigned Reg3)8550b57cec5SDimitry Andric void MipsAsmPrinter::EmitInstrRegRegReg(const MCSubtargetInfo &STI,
8560b57cec5SDimitry Andric                                         unsigned Opcode, unsigned Reg1,
8570b57cec5SDimitry Andric                                         unsigned Reg2, unsigned Reg3) {
8580b57cec5SDimitry Andric   MCInst I;
8590b57cec5SDimitry Andric   I.setOpcode(Opcode);
8600b57cec5SDimitry Andric   I.addOperand(MCOperand::createReg(Reg1));
8610b57cec5SDimitry Andric   I.addOperand(MCOperand::createReg(Reg2));
8620b57cec5SDimitry Andric   I.addOperand(MCOperand::createReg(Reg3));
8635ffd83dbSDimitry Andric   OutStreamer->emitInstruction(I, STI);
8640b57cec5SDimitry Andric }
8650b57cec5SDimitry Andric 
EmitMovFPIntPair(const MCSubtargetInfo & STI,unsigned MovOpc,unsigned Reg1,unsigned Reg2,unsigned FPReg1,unsigned FPReg2,bool LE)8660b57cec5SDimitry Andric void MipsAsmPrinter::EmitMovFPIntPair(const MCSubtargetInfo &STI,
8670b57cec5SDimitry Andric                                       unsigned MovOpc, unsigned Reg1,
8680b57cec5SDimitry Andric                                       unsigned Reg2, unsigned FPReg1,
8690b57cec5SDimitry Andric                                       unsigned FPReg2, bool LE) {
8700b57cec5SDimitry Andric   if (!LE) {
8710b57cec5SDimitry Andric     unsigned temp = Reg1;
8720b57cec5SDimitry Andric     Reg1 = Reg2;
8730b57cec5SDimitry Andric     Reg2 = temp;
8740b57cec5SDimitry Andric   }
8750b57cec5SDimitry Andric   EmitInstrRegReg(STI, MovOpc, Reg1, FPReg1);
8760b57cec5SDimitry Andric   EmitInstrRegReg(STI, MovOpc, Reg2, FPReg2);
8770b57cec5SDimitry Andric }
8780b57cec5SDimitry Andric 
EmitSwapFPIntParams(const MCSubtargetInfo & STI,Mips16HardFloatInfo::FPParamVariant PV,bool LE,bool ToFP)8790b57cec5SDimitry Andric void MipsAsmPrinter::EmitSwapFPIntParams(const MCSubtargetInfo &STI,
8800b57cec5SDimitry Andric                                          Mips16HardFloatInfo::FPParamVariant PV,
8810b57cec5SDimitry Andric                                          bool LE, bool ToFP) {
8820b57cec5SDimitry Andric   using namespace Mips16HardFloatInfo;
8830b57cec5SDimitry Andric 
8840b57cec5SDimitry Andric   unsigned MovOpc = ToFP ? Mips::MTC1 : Mips::MFC1;
8850b57cec5SDimitry Andric   switch (PV) {
8860b57cec5SDimitry Andric   case FSig:
8870b57cec5SDimitry Andric     EmitInstrRegReg(STI, MovOpc, Mips::A0, Mips::F12);
8880b57cec5SDimitry Andric     break;
8890b57cec5SDimitry Andric   case FFSig:
8900b57cec5SDimitry Andric     EmitMovFPIntPair(STI, MovOpc, Mips::A0, Mips::A1, Mips::F12, Mips::F14, LE);
8910b57cec5SDimitry Andric     break;
8920b57cec5SDimitry Andric   case FDSig:
8930b57cec5SDimitry Andric     EmitInstrRegReg(STI, MovOpc, Mips::A0, Mips::F12);
8940b57cec5SDimitry Andric     EmitMovFPIntPair(STI, MovOpc, Mips::A2, Mips::A3, Mips::F14, Mips::F15, LE);
8950b57cec5SDimitry Andric     break;
8960b57cec5SDimitry Andric   case DSig:
8970b57cec5SDimitry Andric     EmitMovFPIntPair(STI, MovOpc, Mips::A0, Mips::A1, Mips::F12, Mips::F13, LE);
8980b57cec5SDimitry Andric     break;
8990b57cec5SDimitry Andric   case DDSig:
9000b57cec5SDimitry Andric     EmitMovFPIntPair(STI, MovOpc, Mips::A0, Mips::A1, Mips::F12, Mips::F13, LE);
9010b57cec5SDimitry Andric     EmitMovFPIntPair(STI, MovOpc, Mips::A2, Mips::A3, Mips::F14, Mips::F15, LE);
9020b57cec5SDimitry Andric     break;
9030b57cec5SDimitry Andric   case DFSig:
9040b57cec5SDimitry Andric     EmitMovFPIntPair(STI, MovOpc, Mips::A0, Mips::A1, Mips::F12, Mips::F13, LE);
9050b57cec5SDimitry Andric     EmitInstrRegReg(STI, MovOpc, Mips::A2, Mips::F14);
9060b57cec5SDimitry Andric     break;
9070b57cec5SDimitry Andric   case NoSig:
9080b57cec5SDimitry Andric     return;
9090b57cec5SDimitry Andric   }
9100b57cec5SDimitry Andric }
9110b57cec5SDimitry Andric 
EmitSwapFPIntRetval(const MCSubtargetInfo & STI,Mips16HardFloatInfo::FPReturnVariant RV,bool LE)9120b57cec5SDimitry Andric void MipsAsmPrinter::EmitSwapFPIntRetval(
9130b57cec5SDimitry Andric     const MCSubtargetInfo &STI, Mips16HardFloatInfo::FPReturnVariant RV,
9140b57cec5SDimitry Andric     bool LE) {
9150b57cec5SDimitry Andric   using namespace Mips16HardFloatInfo;
9160b57cec5SDimitry Andric 
9170b57cec5SDimitry Andric   unsigned MovOpc = Mips::MFC1;
9180b57cec5SDimitry Andric   switch (RV) {
9190b57cec5SDimitry Andric   case FRet:
9200b57cec5SDimitry Andric     EmitInstrRegReg(STI, MovOpc, Mips::V0, Mips::F0);
9210b57cec5SDimitry Andric     break;
9220b57cec5SDimitry Andric   case DRet:
9230b57cec5SDimitry Andric     EmitMovFPIntPair(STI, MovOpc, Mips::V0, Mips::V1, Mips::F0, Mips::F1, LE);
9240b57cec5SDimitry Andric     break;
9250b57cec5SDimitry Andric   case CFRet:
9260b57cec5SDimitry Andric     EmitMovFPIntPair(STI, MovOpc, Mips::V0, Mips::V1, Mips::F0, Mips::F1, LE);
9270b57cec5SDimitry Andric     break;
9280b57cec5SDimitry Andric   case CDRet:
9290b57cec5SDimitry Andric     EmitMovFPIntPair(STI, MovOpc, Mips::V0, Mips::V1, Mips::F0, Mips::F1, LE);
9300b57cec5SDimitry Andric     EmitMovFPIntPair(STI, MovOpc, Mips::A0, Mips::A1, Mips::F2, Mips::F3, LE);
9310b57cec5SDimitry Andric     break;
9320b57cec5SDimitry Andric   case NoFPRet:
9330b57cec5SDimitry Andric     break;
9340b57cec5SDimitry Andric   }
9350b57cec5SDimitry Andric }
9360b57cec5SDimitry Andric 
EmitFPCallStub(const char * Symbol,const Mips16HardFloatInfo::FuncSignature * Signature)9370b57cec5SDimitry Andric void MipsAsmPrinter::EmitFPCallStub(
9380b57cec5SDimitry Andric     const char *Symbol, const Mips16HardFloatInfo::FuncSignature *Signature) {
9390b57cec5SDimitry Andric   using namespace Mips16HardFloatInfo;
9400b57cec5SDimitry Andric 
9410b57cec5SDimitry Andric   MCSymbol *MSymbol = OutContext.getOrCreateSymbol(StringRef(Symbol));
9420b57cec5SDimitry Andric   bool LE = getDataLayout().isLittleEndian();
9430b57cec5SDimitry Andric   // Construct a local MCSubtargetInfo here.
9440b57cec5SDimitry Andric   // This is because the MachineFunction won't exist (but have not yet been
9450b57cec5SDimitry Andric   // freed) and since we're at the global level we can use the default
9460b57cec5SDimitry Andric   // constructed subtarget.
9470b57cec5SDimitry Andric   std::unique_ptr<MCSubtargetInfo> STI(TM.getTarget().createMCSubtargetInfo(
9480b57cec5SDimitry Andric       TM.getTargetTriple().str(), TM.getTargetCPU(),
9490b57cec5SDimitry Andric       TM.getTargetFeatureString()));
9500b57cec5SDimitry Andric 
9510b57cec5SDimitry Andric   //
9520b57cec5SDimitry Andric   // .global xxxx
9530b57cec5SDimitry Andric   //
9545ffd83dbSDimitry Andric   OutStreamer->emitSymbolAttribute(MSymbol, MCSA_Global);
9550b57cec5SDimitry Andric   const char *RetType;
9560b57cec5SDimitry Andric   //
9570b57cec5SDimitry Andric   // make the comment field identifying the return and parameter
9580b57cec5SDimitry Andric   // types of the floating point stub
9590b57cec5SDimitry Andric   // # Stub function to call rettype xxxx (params)
9600b57cec5SDimitry Andric   //
9610b57cec5SDimitry Andric   switch (Signature->RetSig) {
9620b57cec5SDimitry Andric   case FRet:
9630b57cec5SDimitry Andric     RetType = "float";
9640b57cec5SDimitry Andric     break;
9650b57cec5SDimitry Andric   case DRet:
9660b57cec5SDimitry Andric     RetType = "double";
9670b57cec5SDimitry Andric     break;
9680b57cec5SDimitry Andric   case CFRet:
9690b57cec5SDimitry Andric     RetType = "complex";
9700b57cec5SDimitry Andric     break;
9710b57cec5SDimitry Andric   case CDRet:
9720b57cec5SDimitry Andric     RetType = "double complex";
9730b57cec5SDimitry Andric     break;
9740b57cec5SDimitry Andric   case NoFPRet:
9750b57cec5SDimitry Andric     RetType = "";
9760b57cec5SDimitry Andric     break;
9770b57cec5SDimitry Andric   }
9780b57cec5SDimitry Andric   const char *Parms;
9790b57cec5SDimitry Andric   switch (Signature->ParamSig) {
9800b57cec5SDimitry Andric   case FSig:
9810b57cec5SDimitry Andric     Parms = "float";
9820b57cec5SDimitry Andric     break;
9830b57cec5SDimitry Andric   case FFSig:
9840b57cec5SDimitry Andric     Parms = "float, float";
9850b57cec5SDimitry Andric     break;
9860b57cec5SDimitry Andric   case FDSig:
9870b57cec5SDimitry Andric     Parms = "float, double";
9880b57cec5SDimitry Andric     break;
9890b57cec5SDimitry Andric   case DSig:
9900b57cec5SDimitry Andric     Parms = "double";
9910b57cec5SDimitry Andric     break;
9920b57cec5SDimitry Andric   case DDSig:
9930b57cec5SDimitry Andric     Parms = "double, double";
9940b57cec5SDimitry Andric     break;
9950b57cec5SDimitry Andric   case DFSig:
9960b57cec5SDimitry Andric     Parms = "double, float";
9970b57cec5SDimitry Andric     break;
9980b57cec5SDimitry Andric   case NoSig:
9990b57cec5SDimitry Andric     Parms = "";
10000b57cec5SDimitry Andric     break;
10010b57cec5SDimitry Andric   }
10020b57cec5SDimitry Andric   OutStreamer->AddComment("\t# Stub function to call " + Twine(RetType) + " " +
10030b57cec5SDimitry Andric                           Twine(Symbol) + " (" + Twine(Parms) + ")");
10040b57cec5SDimitry Andric   //
10050b57cec5SDimitry Andric   // probably not necessary but we save and restore the current section state
10060b57cec5SDimitry Andric   //
100781ad6265SDimitry Andric   OutStreamer->pushSection();
10080b57cec5SDimitry Andric   //
10090b57cec5SDimitry Andric   // .section mips16.call.fpxxxx,"ax",@progbits
10100b57cec5SDimitry Andric   //
10110b57cec5SDimitry Andric   MCSectionELF *M = OutContext.getELFSection(
10120b57cec5SDimitry Andric       ".mips16.call.fp." + std::string(Symbol), ELF::SHT_PROGBITS,
10130b57cec5SDimitry Andric       ELF::SHF_ALLOC | ELF::SHF_EXECINSTR);
101481ad6265SDimitry Andric   OutStreamer->switchSection(M, nullptr);
10150b57cec5SDimitry Andric   //
10160b57cec5SDimitry Andric   // .align 2
10170b57cec5SDimitry Andric   //
1018bdd1243dSDimitry Andric   OutStreamer->emitValueToAlignment(Align(4));
10190b57cec5SDimitry Andric   MipsTargetStreamer &TS = getTargetStreamer();
10200b57cec5SDimitry Andric   //
10210b57cec5SDimitry Andric   // .set nomips16
10220b57cec5SDimitry Andric   // .set nomicromips
10230b57cec5SDimitry Andric   //
10240b57cec5SDimitry Andric   TS.emitDirectiveSetNoMips16();
10250b57cec5SDimitry Andric   TS.emitDirectiveSetNoMicroMips();
10260b57cec5SDimitry Andric   //
10270b57cec5SDimitry Andric   // .ent __call_stub_fp_xxxx
10280b57cec5SDimitry Andric   // .type  __call_stub_fp_xxxx,@function
10290b57cec5SDimitry Andric   //  __call_stub_fp_xxxx:
10300b57cec5SDimitry Andric   //
10310b57cec5SDimitry Andric   std::string x = "__call_stub_fp_" + std::string(Symbol);
10320b57cec5SDimitry Andric   MCSymbolELF *Stub =
10330b57cec5SDimitry Andric       cast<MCSymbolELF>(OutContext.getOrCreateSymbol(StringRef(x)));
10340b57cec5SDimitry Andric   TS.emitDirectiveEnt(*Stub);
10350b57cec5SDimitry Andric   MCSymbol *MType =
10360b57cec5SDimitry Andric       OutContext.getOrCreateSymbol("__call_stub_fp_" + Twine(Symbol));
10375ffd83dbSDimitry Andric   OutStreamer->emitSymbolAttribute(MType, MCSA_ELF_TypeFunction);
10385ffd83dbSDimitry Andric   OutStreamer->emitLabel(Stub);
10390b57cec5SDimitry Andric 
10400b57cec5SDimitry Andric   // Only handle non-pic for now.
10410b57cec5SDimitry Andric   assert(!isPositionIndependent() &&
10420b57cec5SDimitry Andric          "should not be here if we are compiling pic");
10430b57cec5SDimitry Andric   TS.emitDirectiveSetReorder();
10440b57cec5SDimitry Andric   //
10450b57cec5SDimitry Andric   // We need to add a MipsMCExpr class to MCTargetDesc to fully implement
10460b57cec5SDimitry Andric   // stubs without raw text but this current patch is for compiler generated
10470b57cec5SDimitry Andric   // functions and they all return some value.
10480b57cec5SDimitry Andric   // The calling sequence for non pic is different in that case and we need
10490b57cec5SDimitry Andric   // to implement %lo and %hi in order to handle the case of no return value
10500b57cec5SDimitry Andric   // See the corresponding method in Mips16HardFloat for details.
10510b57cec5SDimitry Andric   //
10520b57cec5SDimitry Andric   // mov the return address to S2.
10530b57cec5SDimitry Andric   // we have no stack space to store it and we are about to make another call.
10540b57cec5SDimitry Andric   // We need to make sure that the enclosing function knows to save S2
10550b57cec5SDimitry Andric   // This should have already been handled.
10560b57cec5SDimitry Andric   //
10570b57cec5SDimitry Andric   // Mov $18, $31
10580b57cec5SDimitry Andric 
10590b57cec5SDimitry Andric   EmitInstrRegRegReg(*STI, Mips::OR, Mips::S2, Mips::RA, Mips::ZERO);
10600b57cec5SDimitry Andric 
10610b57cec5SDimitry Andric   EmitSwapFPIntParams(*STI, Signature->ParamSig, LE, true);
10620b57cec5SDimitry Andric 
10630b57cec5SDimitry Andric   // Jal xxxx
10640b57cec5SDimitry Andric   //
10650b57cec5SDimitry Andric   EmitJal(*STI, MSymbol);
10660b57cec5SDimitry Andric 
10670b57cec5SDimitry Andric   // fix return values
10680b57cec5SDimitry Andric   EmitSwapFPIntRetval(*STI, Signature->RetSig, LE);
10690b57cec5SDimitry Andric   //
10700b57cec5SDimitry Andric   // do the return
10710b57cec5SDimitry Andric   // if (Signature->RetSig == NoFPRet)
10720b57cec5SDimitry Andric   //  llvm_unreachable("should not be any stubs here with no return value");
10730b57cec5SDimitry Andric   // else
10740b57cec5SDimitry Andric   EmitInstrReg(*STI, Mips::JR, Mips::S2);
10750b57cec5SDimitry Andric 
10760b57cec5SDimitry Andric   MCSymbol *Tmp = OutContext.createTempSymbol();
10775ffd83dbSDimitry Andric   OutStreamer->emitLabel(Tmp);
10780b57cec5SDimitry Andric   const MCSymbolRefExpr *E = MCSymbolRefExpr::create(Stub, OutContext);
10790b57cec5SDimitry Andric   const MCSymbolRefExpr *T = MCSymbolRefExpr::create(Tmp, OutContext);
10800b57cec5SDimitry Andric   const MCExpr *T_min_E = MCBinaryExpr::createSub(T, E, OutContext);
10810b57cec5SDimitry Andric   OutStreamer->emitELFSize(Stub, T_min_E);
10820b57cec5SDimitry Andric   TS.emitDirectiveEnd(x);
108381ad6265SDimitry Andric   OutStreamer->popSection();
10840b57cec5SDimitry Andric }
10850b57cec5SDimitry Andric 
emitEndOfAsmFile(Module & M)10865ffd83dbSDimitry Andric void MipsAsmPrinter::emitEndOfAsmFile(Module &M) {
10870b57cec5SDimitry Andric   // Emit needed stubs
10880b57cec5SDimitry Andric   //
10890b57cec5SDimitry Andric   for (std::map<
10900b57cec5SDimitry Andric            const char *,
10910b57cec5SDimitry Andric            const Mips16HardFloatInfo::FuncSignature *>::const_iterator
10920b57cec5SDimitry Andric            it = StubsNeeded.begin();
10930b57cec5SDimitry Andric        it != StubsNeeded.end(); ++it) {
10940b57cec5SDimitry Andric     const char *Symbol = it->first;
10950b57cec5SDimitry Andric     const Mips16HardFloatInfo::FuncSignature *Signature = it->second;
10960b57cec5SDimitry Andric     EmitFPCallStub(Symbol, Signature);
10970b57cec5SDimitry Andric   }
10980b57cec5SDimitry Andric   // return to the text section
109981ad6265SDimitry Andric   OutStreamer->switchSection(OutContext.getObjectFileInfo()->getTextSection());
11000b57cec5SDimitry Andric }
11010b57cec5SDimitry Andric 
EmitSled(const MachineInstr & MI,SledKind Kind)11020b57cec5SDimitry Andric void MipsAsmPrinter::EmitSled(const MachineInstr &MI, SledKind Kind) {
11030b57cec5SDimitry Andric   const uint8_t NoopsInSledCount = Subtarget->isGP64bit() ? 15 : 11;
11040b57cec5SDimitry Andric   // For mips32 we want to emit the following pattern:
11050b57cec5SDimitry Andric   //
11060b57cec5SDimitry Andric   // .Lxray_sled_N:
11070b57cec5SDimitry Andric   //   ALIGN
11080b57cec5SDimitry Andric   //   B .tmpN
11090b57cec5SDimitry Andric   //   11 NOP instructions (44 bytes)
11100b57cec5SDimitry Andric   //   ADDIU T9, T9, 52
11110b57cec5SDimitry Andric   // .tmpN
11120b57cec5SDimitry Andric   //
11130b57cec5SDimitry Andric   // We need the 44 bytes (11 instructions) because at runtime, we'd
11140b57cec5SDimitry Andric   // be patching over the full 48 bytes (12 instructions) with the following
11150b57cec5SDimitry Andric   // pattern:
11160b57cec5SDimitry Andric   //
11170b57cec5SDimitry Andric   //   ADDIU    SP, SP, -8
11180b57cec5SDimitry Andric   //   NOP
11190b57cec5SDimitry Andric   //   SW       RA, 4(SP)
11200b57cec5SDimitry Andric   //   SW       T9, 0(SP)
11210b57cec5SDimitry Andric   //   LUI      T9, %hi(__xray_FunctionEntry/Exit)
11220b57cec5SDimitry Andric   //   ORI      T9, T9, %lo(__xray_FunctionEntry/Exit)
11230b57cec5SDimitry Andric   //   LUI      T0, %hi(function_id)
11240b57cec5SDimitry Andric   //   JALR     T9
11250b57cec5SDimitry Andric   //   ORI      T0, T0, %lo(function_id)
11260b57cec5SDimitry Andric   //   LW       T9, 0(SP)
11270b57cec5SDimitry Andric   //   LW       RA, 4(SP)
11280b57cec5SDimitry Andric   //   ADDIU    SP, SP, 8
11290b57cec5SDimitry Andric   //
11300b57cec5SDimitry Andric   // We add 52 bytes to t9 because we want to adjust the function pointer to
11310b57cec5SDimitry Andric   // the actual start of function i.e. the address just after the noop sled.
11320b57cec5SDimitry Andric   // We do this because gp displacement relocation is emitted at the start of
11330b57cec5SDimitry Andric   // of the function i.e after the nop sled and to correctly calculate the
11340b57cec5SDimitry Andric   // global offset table address, t9 must hold the address of the instruction
11350b57cec5SDimitry Andric   // containing the gp displacement relocation.
11360b57cec5SDimitry Andric   // FIXME: Is this correct for the static relocation model?
11370b57cec5SDimitry Andric   //
11380b57cec5SDimitry Andric   // For mips64 we want to emit the following pattern:
11390b57cec5SDimitry Andric   //
11400b57cec5SDimitry Andric   // .Lxray_sled_N:
11410b57cec5SDimitry Andric   //   ALIGN
11420b57cec5SDimitry Andric   //   B .tmpN
11430b57cec5SDimitry Andric   //   15 NOP instructions (60 bytes)
11440b57cec5SDimitry Andric   // .tmpN
11450b57cec5SDimitry Andric   //
11460b57cec5SDimitry Andric   // We need the 60 bytes (15 instructions) because at runtime, we'd
11470b57cec5SDimitry Andric   // be patching over the full 64 bytes (16 instructions) with the following
11480b57cec5SDimitry Andric   // pattern:
11490b57cec5SDimitry Andric   //
11500b57cec5SDimitry Andric   //   DADDIU   SP, SP, -16
11510b57cec5SDimitry Andric   //   NOP
11520b57cec5SDimitry Andric   //   SD       RA, 8(SP)
11530b57cec5SDimitry Andric   //   SD       T9, 0(SP)
11540b57cec5SDimitry Andric   //   LUI      T9, %highest(__xray_FunctionEntry/Exit)
11550b57cec5SDimitry Andric   //   ORI      T9, T9, %higher(__xray_FunctionEntry/Exit)
11560b57cec5SDimitry Andric   //   DSLL     T9, T9, 16
11570b57cec5SDimitry Andric   //   ORI      T9, T9, %hi(__xray_FunctionEntry/Exit)
11580b57cec5SDimitry Andric   //   DSLL     T9, T9, 16
11590b57cec5SDimitry Andric   //   ORI      T9, T9, %lo(__xray_FunctionEntry/Exit)
11600b57cec5SDimitry Andric   //   LUI      T0, %hi(function_id)
11610b57cec5SDimitry Andric   //   JALR     T9
11620b57cec5SDimitry Andric   //   ADDIU    T0, T0, %lo(function_id)
11630b57cec5SDimitry Andric   //   LD       T9, 0(SP)
11640b57cec5SDimitry Andric   //   LD       RA, 8(SP)
11650b57cec5SDimitry Andric   //   DADDIU   SP, SP, 16
11660b57cec5SDimitry Andric   //
1167bdd1243dSDimitry Andric   OutStreamer->emitCodeAlignment(Align(4), &getSubtargetInfo());
11680b57cec5SDimitry Andric   auto CurSled = OutContext.createTempSymbol("xray_sled_", true);
11695ffd83dbSDimitry Andric   OutStreamer->emitLabel(CurSled);
11700b57cec5SDimitry Andric   auto Target = OutContext.createTempSymbol();
11710b57cec5SDimitry Andric 
11720b57cec5SDimitry Andric   // Emit "B .tmpN" instruction, which jumps over the nop sled to the actual
11730b57cec5SDimitry Andric   // start of function
11740b57cec5SDimitry Andric   const MCExpr *TargetExpr = MCSymbolRefExpr::create(
11750b57cec5SDimitry Andric       Target, MCSymbolRefExpr::VariantKind::VK_None, OutContext);
11760b57cec5SDimitry Andric   EmitToStreamer(*OutStreamer, MCInstBuilder(Mips::BEQ)
11770b57cec5SDimitry Andric                                    .addReg(Mips::ZERO)
11780b57cec5SDimitry Andric                                    .addReg(Mips::ZERO)
11790b57cec5SDimitry Andric                                    .addExpr(TargetExpr));
11800b57cec5SDimitry Andric 
11810b57cec5SDimitry Andric   for (int8_t I = 0; I < NoopsInSledCount; I++)
11820b57cec5SDimitry Andric     EmitToStreamer(*OutStreamer, MCInstBuilder(Mips::SLL)
11830b57cec5SDimitry Andric                                      .addReg(Mips::ZERO)
11840b57cec5SDimitry Andric                                      .addReg(Mips::ZERO)
11850b57cec5SDimitry Andric                                      .addImm(0));
11860b57cec5SDimitry Andric 
11875ffd83dbSDimitry Andric   OutStreamer->emitLabel(Target);
11880b57cec5SDimitry Andric 
11890b57cec5SDimitry Andric   if (!Subtarget->isGP64bit()) {
11900b57cec5SDimitry Andric     EmitToStreamer(*OutStreamer,
11910b57cec5SDimitry Andric                    MCInstBuilder(Mips::ADDiu)
11920b57cec5SDimitry Andric                        .addReg(Mips::T9)
11930b57cec5SDimitry Andric                        .addReg(Mips::T9)
11940b57cec5SDimitry Andric                        .addImm(0x34));
11950b57cec5SDimitry Andric   }
11960b57cec5SDimitry Andric 
1197e8d8bef9SDimitry Andric   recordSled(CurSled, MI, Kind, 2);
11980b57cec5SDimitry Andric }
11990b57cec5SDimitry Andric 
LowerPATCHABLE_FUNCTION_ENTER(const MachineInstr & MI)12000b57cec5SDimitry Andric void MipsAsmPrinter::LowerPATCHABLE_FUNCTION_ENTER(const MachineInstr &MI) {
12010b57cec5SDimitry Andric   EmitSled(MI, SledKind::FUNCTION_ENTER);
12020b57cec5SDimitry Andric }
12030b57cec5SDimitry Andric 
LowerPATCHABLE_FUNCTION_EXIT(const MachineInstr & MI)12040b57cec5SDimitry Andric void MipsAsmPrinter::LowerPATCHABLE_FUNCTION_EXIT(const MachineInstr &MI) {
12050b57cec5SDimitry Andric   EmitSled(MI, SledKind::FUNCTION_EXIT);
12060b57cec5SDimitry Andric }
12070b57cec5SDimitry Andric 
LowerPATCHABLE_TAIL_CALL(const MachineInstr & MI)12080b57cec5SDimitry Andric void MipsAsmPrinter::LowerPATCHABLE_TAIL_CALL(const MachineInstr &MI) {
12090b57cec5SDimitry Andric   EmitSled(MI, SledKind::TAIL_CALL);
12100b57cec5SDimitry Andric }
12110b57cec5SDimitry Andric 
PrintDebugValueComment(const MachineInstr * MI,raw_ostream & OS)12120b57cec5SDimitry Andric void MipsAsmPrinter::PrintDebugValueComment(const MachineInstr *MI,
12130b57cec5SDimitry Andric                                            raw_ostream &OS) {
12140b57cec5SDimitry Andric   // TODO: implement
12150b57cec5SDimitry Andric }
12160b57cec5SDimitry Andric 
12170b57cec5SDimitry Andric // Emit .dtprelword or .dtpreldword directive
12180b57cec5SDimitry Andric // and value for debug thread local expression.
emitDebugValue(const MCExpr * Value,unsigned Size) const12195ffd83dbSDimitry Andric void MipsAsmPrinter::emitDebugValue(const MCExpr *Value, unsigned Size) const {
12200b57cec5SDimitry Andric   if (auto *MipsExpr = dyn_cast<MipsMCExpr>(Value)) {
12210b57cec5SDimitry Andric     if (MipsExpr && MipsExpr->getKind() == MipsMCExpr::MEK_DTPREL) {
12220b57cec5SDimitry Andric       switch (Size) {
12230b57cec5SDimitry Andric       case 4:
12245ffd83dbSDimitry Andric         OutStreamer->emitDTPRel32Value(MipsExpr->getSubExpr());
12250b57cec5SDimitry Andric         break;
12260b57cec5SDimitry Andric       case 8:
12275ffd83dbSDimitry Andric         OutStreamer->emitDTPRel64Value(MipsExpr->getSubExpr());
12280b57cec5SDimitry Andric         break;
12290b57cec5SDimitry Andric       default:
12300b57cec5SDimitry Andric         llvm_unreachable("Unexpected size of expression value.");
12310b57cec5SDimitry Andric       }
12320b57cec5SDimitry Andric       return;
12330b57cec5SDimitry Andric     }
12340b57cec5SDimitry Andric   }
12355ffd83dbSDimitry Andric   AsmPrinter::emitDebugValue(Value, Size);
12360b57cec5SDimitry Andric }
12370b57cec5SDimitry Andric 
12380b57cec5SDimitry Andric // Align all targets of indirect branches on bundle size.  Used only if target
12390b57cec5SDimitry Andric // is NaCl.
NaClAlignIndirectJumpTargets(MachineFunction & MF)12400b57cec5SDimitry Andric void MipsAsmPrinter::NaClAlignIndirectJumpTargets(MachineFunction &MF) {
12410b57cec5SDimitry Andric   // Align all blocks that are jumped to through jump table.
12420b57cec5SDimitry Andric   if (MachineJumpTableInfo *JtInfo = MF.getJumpTableInfo()) {
12430b57cec5SDimitry Andric     const std::vector<MachineJumpTableEntry> &JT = JtInfo->getJumpTables();
124404eeddc0SDimitry Andric     for (const auto &I : JT) {
124504eeddc0SDimitry Andric       const std::vector<MachineBasicBlock *> &MBBs = I.MBBs;
12460b57cec5SDimitry Andric 
124704eeddc0SDimitry Andric       for (MachineBasicBlock *MBB : MBBs)
124804eeddc0SDimitry Andric         MBB->setAlignment(MIPS_NACL_BUNDLE_ALIGN);
12490b57cec5SDimitry Andric     }
12500b57cec5SDimitry Andric   }
12510b57cec5SDimitry Andric 
12520b57cec5SDimitry Andric   // If basic block address is taken, block can be target of indirect branch.
12530b57cec5SDimitry Andric   for (auto &MBB : MF) {
12540b57cec5SDimitry Andric     if (MBB.hasAddressTaken())
12550b57cec5SDimitry Andric       MBB.setAlignment(MIPS_NACL_BUNDLE_ALIGN);
12560b57cec5SDimitry Andric   }
12570b57cec5SDimitry Andric }
12580b57cec5SDimitry Andric 
isLongBranchPseudo(int Opcode) const12590b57cec5SDimitry Andric bool MipsAsmPrinter::isLongBranchPseudo(int Opcode) const {
12600b57cec5SDimitry Andric   return (Opcode == Mips::LONG_BRANCH_LUi
12610b57cec5SDimitry Andric           || Opcode == Mips::LONG_BRANCH_LUi2Op
12620b57cec5SDimitry Andric           || Opcode == Mips::LONG_BRANCH_LUi2Op_64
12630b57cec5SDimitry Andric           || Opcode == Mips::LONG_BRANCH_ADDiu
12640b57cec5SDimitry Andric           || Opcode == Mips::LONG_BRANCH_ADDiu2Op
12650b57cec5SDimitry Andric           || Opcode == Mips::LONG_BRANCH_DADDiu
12660b57cec5SDimitry Andric           || Opcode == Mips::LONG_BRANCH_DADDiu2Op);
12670b57cec5SDimitry Andric }
12680b57cec5SDimitry Andric 
12690b57cec5SDimitry Andric // Force static initialization.
LLVMInitializeMipsAsmPrinter()1270480093f4SDimitry Andric extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeMipsAsmPrinter() {
12710b57cec5SDimitry Andric   RegisterAsmPrinter<MipsAsmPrinter> X(getTheMipsTarget());
12720b57cec5SDimitry Andric   RegisterAsmPrinter<MipsAsmPrinter> Y(getTheMipselTarget());
12730b57cec5SDimitry Andric   RegisterAsmPrinter<MipsAsmPrinter> A(getTheMips64Target());
12740b57cec5SDimitry Andric   RegisterAsmPrinter<MipsAsmPrinter> B(getTheMips64elTarget());
12750b57cec5SDimitry Andric }
1276