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