xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/Mips/MipsAsmPrinter.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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"
46*0fca6ea1SDimitry Andric #include "llvm/IR/Module.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"
55349cc55cSDimitry Andric #include "llvm/MC/TargetRegistry.h"
560b57cec5SDimitry Andric #include "llvm/Support/Casting.h"
570b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h"
580b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
598bcb0991SDimitry Andric #include "llvm/Target/TargetLoweringObjectFile.h"
600b57cec5SDimitry Andric #include "llvm/Target/TargetMachine.h"
6106c3fb27SDimitry Andric #include "llvm/TargetParser/Triple.h"
620b57cec5SDimitry Andric #include <cassert>
630b57cec5SDimitry Andric #include <cstdint>
640b57cec5SDimitry Andric #include <map>
650b57cec5SDimitry Andric #include <memory>
660b57cec5SDimitry Andric #include <string>
670b57cec5SDimitry Andric #include <vector>
680b57cec5SDimitry Andric 
690b57cec5SDimitry Andric using namespace llvm;
700b57cec5SDimitry Andric 
710b57cec5SDimitry Andric #define DEBUG_TYPE "mips-asm-printer"
720b57cec5SDimitry Andric 
730b57cec5SDimitry Andric extern cl::opt<bool> EmitJalrReloc;
740b57cec5SDimitry Andric 
750b57cec5SDimitry Andric MipsTargetStreamer &MipsAsmPrinter::getTargetStreamer() const {
760b57cec5SDimitry Andric   return static_cast<MipsTargetStreamer &>(*OutStreamer->getTargetStreamer());
770b57cec5SDimitry Andric }
780b57cec5SDimitry Andric 
790b57cec5SDimitry Andric bool MipsAsmPrinter::runOnMachineFunction(MachineFunction &MF) {
800b57cec5SDimitry Andric   Subtarget = &MF.getSubtarget<MipsSubtarget>();
810b57cec5SDimitry Andric 
820b57cec5SDimitry Andric   MipsFI = MF.getInfo<MipsFunctionInfo>();
830b57cec5SDimitry Andric   if (Subtarget->inMips16Mode())
8404eeddc0SDimitry Andric     for (const auto &I : MipsFI->StubsNeeded) {
8504eeddc0SDimitry Andric       const char *Symbol = I.first;
8604eeddc0SDimitry Andric       const Mips16HardFloatInfo::FuncSignature *Signature = I.second;
870b57cec5SDimitry Andric       if (StubsNeeded.find(Symbol) == StubsNeeded.end())
880b57cec5SDimitry Andric         StubsNeeded[Symbol] = Signature;
890b57cec5SDimitry Andric     }
900b57cec5SDimitry Andric   MCP = MF.getConstantPool();
910b57cec5SDimitry Andric 
920b57cec5SDimitry Andric   // In NaCl, all indirect jump targets must be aligned to bundle size.
930b57cec5SDimitry Andric   if (Subtarget->isTargetNaCl())
940b57cec5SDimitry Andric     NaClAlignIndirectJumpTargets(MF);
950b57cec5SDimitry Andric 
960b57cec5SDimitry Andric   AsmPrinter::runOnMachineFunction(MF);
970b57cec5SDimitry Andric 
980b57cec5SDimitry Andric   emitXRayTable();
990b57cec5SDimitry Andric 
1000b57cec5SDimitry Andric   return true;
1010b57cec5SDimitry Andric }
1020b57cec5SDimitry Andric 
1030b57cec5SDimitry Andric bool MipsAsmPrinter::lowerOperand(const MachineOperand &MO, MCOperand &MCOp) {
1040b57cec5SDimitry Andric   MCOp = MCInstLowering.LowerOperand(MO);
1050b57cec5SDimitry Andric   return MCOp.isValid();
1060b57cec5SDimitry Andric }
1070b57cec5SDimitry Andric 
1080b57cec5SDimitry Andric #include "MipsGenMCPseudoLowering.inc"
1090b57cec5SDimitry Andric 
1100b57cec5SDimitry Andric // Lower PseudoReturn/PseudoIndirectBranch/PseudoIndirectBranch64 to JR, JR_MM,
1110b57cec5SDimitry Andric // JALR, or JALR64 as appropriate for the target.
1120b57cec5SDimitry Andric void MipsAsmPrinter::emitPseudoIndirectBranch(MCStreamer &OutStreamer,
1130b57cec5SDimitry Andric                                               const MachineInstr *MI) {
1140b57cec5SDimitry Andric   bool HasLinkReg = false;
1150b57cec5SDimitry Andric   bool InMicroMipsMode = Subtarget->inMicroMipsMode();
1160b57cec5SDimitry Andric   MCInst TmpInst0;
1170b57cec5SDimitry Andric 
1180b57cec5SDimitry Andric   if (Subtarget->hasMips64r6()) {
1190b57cec5SDimitry Andric     // MIPS64r6 should use (JALR64 ZERO_64, $rs)
1200b57cec5SDimitry Andric     TmpInst0.setOpcode(Mips::JALR64);
1210b57cec5SDimitry Andric     HasLinkReg = true;
1220b57cec5SDimitry Andric   } else if (Subtarget->hasMips32r6()) {
1230b57cec5SDimitry Andric     // MIPS32r6 should use (JALR ZERO, $rs)
1240b57cec5SDimitry Andric     if (InMicroMipsMode)
1250b57cec5SDimitry Andric       TmpInst0.setOpcode(Mips::JRC16_MMR6);
1260b57cec5SDimitry Andric     else {
1270b57cec5SDimitry Andric       TmpInst0.setOpcode(Mips::JALR);
1280b57cec5SDimitry Andric       HasLinkReg = true;
1290b57cec5SDimitry Andric     }
1300b57cec5SDimitry Andric   } else if (Subtarget->inMicroMipsMode())
1310b57cec5SDimitry Andric     // microMIPS should use (JR_MM $rs)
1320b57cec5SDimitry Andric     TmpInst0.setOpcode(Mips::JR_MM);
1330b57cec5SDimitry Andric   else {
1340b57cec5SDimitry Andric     // Everything else should use (JR $rs)
1350b57cec5SDimitry Andric     TmpInst0.setOpcode(Mips::JR);
1360b57cec5SDimitry Andric   }
1370b57cec5SDimitry Andric 
1380b57cec5SDimitry Andric   MCOperand MCOp;
1390b57cec5SDimitry Andric 
1400b57cec5SDimitry Andric   if (HasLinkReg) {
1410b57cec5SDimitry Andric     unsigned ZeroReg = Subtarget->isGP64bit() ? Mips::ZERO_64 : Mips::ZERO;
1420b57cec5SDimitry Andric     TmpInst0.addOperand(MCOperand::createReg(ZeroReg));
1430b57cec5SDimitry Andric   }
1440b57cec5SDimitry Andric 
1450b57cec5SDimitry Andric   lowerOperand(MI->getOperand(0), MCOp);
1460b57cec5SDimitry Andric   TmpInst0.addOperand(MCOp);
1470b57cec5SDimitry Andric 
1480b57cec5SDimitry Andric   EmitToStreamer(OutStreamer, TmpInst0);
1490b57cec5SDimitry Andric }
1500b57cec5SDimitry Andric 
1510b57cec5SDimitry Andric // If there is an MO_JALR operand, insert:
1520b57cec5SDimitry Andric //
1530b57cec5SDimitry Andric // .reloc tmplabel, R_{MICRO}MIPS_JALR, symbol
1540b57cec5SDimitry Andric // tmplabel:
1550b57cec5SDimitry Andric //
1560b57cec5SDimitry Andric // This is an optimization hint for the linker which may then replace
1570b57cec5SDimitry Andric // an indirect call with a direct branch.
1580b57cec5SDimitry Andric static void emitDirectiveRelocJalr(const MachineInstr &MI,
1590b57cec5SDimitry Andric                                    MCContext &OutContext,
1600b57cec5SDimitry Andric                                    TargetMachine &TM,
1610b57cec5SDimitry Andric                                    MCStreamer &OutStreamer,
1620b57cec5SDimitry Andric                                    const MipsSubtarget &Subtarget) {
1634824e7fdSDimitry Andric   for (const MachineOperand &MO :
1644824e7fdSDimitry Andric        llvm::drop_begin(MI.operands(), MI.getDesc().getNumOperands())) {
1650b57cec5SDimitry Andric     if (MO.isMCSymbol() && (MO.getTargetFlags() & MipsII::MO_JALR)) {
1660b57cec5SDimitry Andric       MCSymbol *Callee = MO.getMCSymbol();
1670b57cec5SDimitry Andric       if (Callee && !Callee->getName().empty()) {
1680b57cec5SDimitry Andric         MCSymbol *OffsetLabel = OutContext.createTempSymbol();
1690b57cec5SDimitry Andric         const MCExpr *OffsetExpr =
1700b57cec5SDimitry Andric             MCSymbolRefExpr::create(OffsetLabel, OutContext);
1710b57cec5SDimitry Andric         const MCExpr *CaleeExpr =
1720b57cec5SDimitry Andric             MCSymbolRefExpr::create(Callee, OutContext);
1735ffd83dbSDimitry Andric         OutStreamer.emitRelocDirective(
1745ffd83dbSDimitry Andric             *OffsetExpr,
1750b57cec5SDimitry Andric             Subtarget.inMicroMipsMode() ? "R_MICROMIPS_JALR" : "R_MIPS_JALR",
1760b57cec5SDimitry Andric             CaleeExpr, SMLoc(), *TM.getMCSubtargetInfo());
1775ffd83dbSDimitry Andric         OutStreamer.emitLabel(OffsetLabel);
1780b57cec5SDimitry Andric         return;
1790b57cec5SDimitry Andric       }
1800b57cec5SDimitry Andric     }
1810b57cec5SDimitry Andric   }
1820b57cec5SDimitry Andric }
1830b57cec5SDimitry Andric 
1845ffd83dbSDimitry Andric void MipsAsmPrinter::emitInstruction(const MachineInstr *MI) {
185753f127fSDimitry Andric   // FIXME: Enable feature predicate checks once all the test pass.
186753f127fSDimitry Andric   // Mips_MC::verifyInstructionPredicates(MI->getOpcode(),
187753f127fSDimitry Andric   //                                      getSubtargetInfo().getFeatureBits());
188753f127fSDimitry Andric 
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) {
34504eeddc0SDimitry Andric     Register 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 // Print out an operand for an inline asm expression.
4760b57cec5SDimitry Andric bool MipsAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNum,
4770b57cec5SDimitry Andric                                      const char *ExtraCode, raw_ostream &O) {
4780b57cec5SDimitry Andric   // Does this asm operand have a single letter operand modifier?
4790b57cec5SDimitry Andric   if (ExtraCode && ExtraCode[0]) {
4800b57cec5SDimitry Andric     if (ExtraCode[1] != 0) return true; // Unknown modifier.
4810b57cec5SDimitry Andric 
4820b57cec5SDimitry Andric     const MachineOperand &MO = MI->getOperand(OpNum);
4830b57cec5SDimitry Andric     switch (ExtraCode[0]) {
4840b57cec5SDimitry Andric     default:
4850b57cec5SDimitry Andric       // See if this is a generic print operand
4860b57cec5SDimitry Andric       return AsmPrinter::PrintAsmOperand(MI, OpNum, ExtraCode, O);
4870b57cec5SDimitry Andric     case 'X': // hex const int
48881ad6265SDimitry Andric       if (!MO.isImm())
4890b57cec5SDimitry Andric         return true;
4900b57cec5SDimitry Andric       O << "0x" << Twine::utohexstr(MO.getImm());
4910b57cec5SDimitry Andric       return false;
4920b57cec5SDimitry Andric     case 'x': // hex const int (low 16 bits)
49381ad6265SDimitry Andric       if (!MO.isImm())
4940b57cec5SDimitry Andric         return true;
4950b57cec5SDimitry Andric       O << "0x" << Twine::utohexstr(MO.getImm() & 0xffff);
4960b57cec5SDimitry Andric       return false;
4970b57cec5SDimitry Andric     case 'd': // decimal const int
49881ad6265SDimitry Andric       if (!MO.isImm())
4990b57cec5SDimitry Andric         return true;
5000b57cec5SDimitry Andric       O << MO.getImm();
5010b57cec5SDimitry Andric       return false;
5020b57cec5SDimitry Andric     case 'm': // decimal const int minus 1
50381ad6265SDimitry Andric       if (!MO.isImm())
5040b57cec5SDimitry Andric         return true;
5050b57cec5SDimitry Andric       O << MO.getImm() - 1;
5060b57cec5SDimitry Andric       return false;
5070b57cec5SDimitry Andric     case 'y': // exact log2
50881ad6265SDimitry Andric       if (!MO.isImm())
5090b57cec5SDimitry Andric         return true;
5100b57cec5SDimitry Andric       if (!isPowerOf2_64(MO.getImm()))
5110b57cec5SDimitry Andric         return true;
5120b57cec5SDimitry Andric       O << Log2_64(MO.getImm());
5130b57cec5SDimitry Andric       return false;
5140b57cec5SDimitry Andric     case 'z':
5150b57cec5SDimitry Andric       // $0 if zero, regular printing otherwise
51681ad6265SDimitry Andric       if (MO.isImm() && MO.getImm() == 0) {
5170b57cec5SDimitry Andric         O << "$0";
5180b57cec5SDimitry Andric         return false;
5190b57cec5SDimitry Andric       }
5200b57cec5SDimitry Andric       // If not, call printOperand as normal.
5210b57cec5SDimitry Andric       break;
5220b57cec5SDimitry Andric     case 'D': // Second part of a double word register operand
5230b57cec5SDimitry Andric     case 'L': // Low order register of a double word register operand
5240b57cec5SDimitry Andric     case 'M': // High order register of a double word register operand
5250b57cec5SDimitry Andric     {
5260b57cec5SDimitry Andric       if (OpNum == 0)
5270b57cec5SDimitry Andric         return true;
5280b57cec5SDimitry Andric       const MachineOperand &FlagsOP = MI->getOperand(OpNum - 1);
5290b57cec5SDimitry Andric       if (!FlagsOP.isImm())
5300b57cec5SDimitry Andric         return true;
5315f757f3fSDimitry Andric       const InlineAsm::Flag Flags(FlagsOP.getImm());
5325f757f3fSDimitry Andric       const unsigned NumVals = Flags.getNumOperandRegisters();
5330b57cec5SDimitry Andric       // Number of registers represented by this operand. We are looking
5340b57cec5SDimitry Andric       // for 2 for 32 bit mode and 1 for 64 bit mode.
5350b57cec5SDimitry Andric       if (NumVals != 2) {
5360b57cec5SDimitry Andric         if (Subtarget->isGP64bit() && NumVals == 1 && MO.isReg()) {
5378bcb0991SDimitry Andric           Register Reg = MO.getReg();
5380b57cec5SDimitry Andric           O << '$' << MipsInstPrinter::getRegisterName(Reg);
5390b57cec5SDimitry Andric           return false;
5400b57cec5SDimitry Andric         }
5410b57cec5SDimitry Andric         return true;
5420b57cec5SDimitry Andric       }
5430b57cec5SDimitry Andric 
5440b57cec5SDimitry Andric       unsigned RegOp = OpNum;
5450b57cec5SDimitry Andric       if (!Subtarget->isGP64bit()){
5460b57cec5SDimitry Andric         // Endianness reverses which register holds the high or low value
5470b57cec5SDimitry Andric         // between M and L.
5480b57cec5SDimitry Andric         switch(ExtraCode[0]) {
5490b57cec5SDimitry Andric         case 'M':
5500b57cec5SDimitry Andric           RegOp = (Subtarget->isLittle()) ? OpNum + 1 : OpNum;
5510b57cec5SDimitry Andric           break;
5520b57cec5SDimitry Andric         case 'L':
5530b57cec5SDimitry Andric           RegOp = (Subtarget->isLittle()) ? OpNum : OpNum + 1;
5540b57cec5SDimitry Andric           break;
5550b57cec5SDimitry Andric         case 'D': // Always the second part
5560b57cec5SDimitry Andric           RegOp = OpNum + 1;
5570b57cec5SDimitry Andric         }
5580b57cec5SDimitry Andric         if (RegOp >= MI->getNumOperands())
5590b57cec5SDimitry Andric           return true;
5600b57cec5SDimitry Andric         const MachineOperand &MO = MI->getOperand(RegOp);
5610b57cec5SDimitry Andric         if (!MO.isReg())
5620b57cec5SDimitry Andric           return true;
5638bcb0991SDimitry Andric         Register Reg = MO.getReg();
5640b57cec5SDimitry Andric         O << '$' << MipsInstPrinter::getRegisterName(Reg);
5650b57cec5SDimitry Andric         return false;
5660b57cec5SDimitry Andric       }
5670b57cec5SDimitry Andric       break;
5680b57cec5SDimitry Andric     }
569*0fca6ea1SDimitry Andric     case 'w': {
570*0fca6ea1SDimitry Andric       MCRegister w = getMSARegFromFReg(MO.getReg());
571*0fca6ea1SDimitry Andric       if (w != Mips::NoRegister) {
572*0fca6ea1SDimitry Andric         O << '$' << MipsInstPrinter::getRegisterName(w);
573*0fca6ea1SDimitry Andric         return false;
574*0fca6ea1SDimitry Andric       }
5750b57cec5SDimitry Andric       break;
5760b57cec5SDimitry Andric     }
5770b57cec5SDimitry Andric     }
578*0fca6ea1SDimitry Andric   }
5790b57cec5SDimitry Andric 
5800b57cec5SDimitry Andric   printOperand(MI, OpNum, O);
5810b57cec5SDimitry Andric   return false;
5820b57cec5SDimitry Andric }
5830b57cec5SDimitry Andric 
5840b57cec5SDimitry Andric bool MipsAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,
5850b57cec5SDimitry Andric                                            unsigned OpNum,
5860b57cec5SDimitry Andric                                            const char *ExtraCode,
5870b57cec5SDimitry Andric                                            raw_ostream &O) {
5880b57cec5SDimitry Andric   assert(OpNum + 1 < MI->getNumOperands() && "Insufficient operands");
5890b57cec5SDimitry Andric   const MachineOperand &BaseMO = MI->getOperand(OpNum);
5900b57cec5SDimitry Andric   const MachineOperand &OffsetMO = MI->getOperand(OpNum + 1);
591480093f4SDimitry Andric   assert(BaseMO.isReg() &&
592480093f4SDimitry Andric          "Unexpected base pointer for inline asm memory operand.");
593480093f4SDimitry Andric   assert(OffsetMO.isImm() &&
594480093f4SDimitry Andric          "Unexpected offset for inline asm memory operand.");
5950b57cec5SDimitry Andric   int Offset = OffsetMO.getImm();
5960b57cec5SDimitry Andric 
5970b57cec5SDimitry Andric   // Currently we are expecting either no ExtraCode or 'D','M','L'.
5980b57cec5SDimitry Andric   if (ExtraCode) {
5990b57cec5SDimitry Andric     switch (ExtraCode[0]) {
6000b57cec5SDimitry Andric     case 'D':
6010b57cec5SDimitry Andric       Offset += 4;
6020b57cec5SDimitry Andric       break;
6030b57cec5SDimitry Andric     case 'M':
6040b57cec5SDimitry Andric       if (Subtarget->isLittle())
6050b57cec5SDimitry Andric         Offset += 4;
6060b57cec5SDimitry Andric       break;
6070b57cec5SDimitry Andric     case 'L':
6080b57cec5SDimitry Andric       if (!Subtarget->isLittle())
6090b57cec5SDimitry Andric         Offset += 4;
6100b57cec5SDimitry Andric       break;
6110b57cec5SDimitry Andric     default:
6120b57cec5SDimitry Andric       return true; // Unknown modifier.
6130b57cec5SDimitry Andric     }
6140b57cec5SDimitry Andric   }
6150b57cec5SDimitry Andric 
6160b57cec5SDimitry Andric   O << Offset << "($" << MipsInstPrinter::getRegisterName(BaseMO.getReg())
6170b57cec5SDimitry Andric     << ")";
6180b57cec5SDimitry Andric 
6190b57cec5SDimitry Andric   return false;
6200b57cec5SDimitry Andric }
6210b57cec5SDimitry Andric 
6220b57cec5SDimitry Andric void MipsAsmPrinter::printOperand(const MachineInstr *MI, int opNum,
6230b57cec5SDimitry Andric                                   raw_ostream &O) {
6240b57cec5SDimitry Andric   const MachineOperand &MO = MI->getOperand(opNum);
6250b57cec5SDimitry Andric   bool closeP = false;
6260b57cec5SDimitry Andric 
6270b57cec5SDimitry Andric   if (MO.getTargetFlags())
6280b57cec5SDimitry Andric     closeP = true;
6290b57cec5SDimitry Andric 
6300b57cec5SDimitry Andric   switch(MO.getTargetFlags()) {
6310b57cec5SDimitry Andric   case MipsII::MO_GPREL:    O << "%gp_rel("; break;
6320b57cec5SDimitry Andric   case MipsII::MO_GOT_CALL: O << "%call16("; break;
6330b57cec5SDimitry Andric   case MipsII::MO_GOT:      O << "%got(";    break;
6340b57cec5SDimitry Andric   case MipsII::MO_ABS_HI:   O << "%hi(";     break;
6350b57cec5SDimitry Andric   case MipsII::MO_ABS_LO:   O << "%lo(";     break;
6360b57cec5SDimitry Andric   case MipsII::MO_HIGHER:   O << "%higher("; break;
6370b57cec5SDimitry Andric   case MipsII::MO_HIGHEST:  O << "%highest(("; break;
6380b57cec5SDimitry Andric   case MipsII::MO_TLSGD:    O << "%tlsgd(";  break;
6390b57cec5SDimitry Andric   case MipsII::MO_GOTTPREL: O << "%gottprel("; break;
6400b57cec5SDimitry Andric   case MipsII::MO_TPREL_HI: O << "%tprel_hi("; break;
6410b57cec5SDimitry Andric   case MipsII::MO_TPREL_LO: O << "%tprel_lo("; break;
6420b57cec5SDimitry Andric   case MipsII::MO_GPOFF_HI: O << "%hi(%neg(%gp_rel("; break;
6430b57cec5SDimitry Andric   case MipsII::MO_GPOFF_LO: O << "%lo(%neg(%gp_rel("; break;
6440b57cec5SDimitry Andric   case MipsII::MO_GOT_DISP: O << "%got_disp("; break;
6450b57cec5SDimitry Andric   case MipsII::MO_GOT_PAGE: O << "%got_page("; break;
6460b57cec5SDimitry Andric   case MipsII::MO_GOT_OFST: O << "%got_ofst("; break;
6470b57cec5SDimitry Andric   }
6480b57cec5SDimitry Andric 
6490b57cec5SDimitry Andric   switch (MO.getType()) {
6500b57cec5SDimitry Andric     case MachineOperand::MO_Register:
6510b57cec5SDimitry Andric       O << '$'
6520b57cec5SDimitry Andric         << StringRef(MipsInstPrinter::getRegisterName(MO.getReg())).lower();
6530b57cec5SDimitry Andric       break;
6540b57cec5SDimitry Andric 
6550b57cec5SDimitry Andric     case MachineOperand::MO_Immediate:
6560b57cec5SDimitry Andric       O << MO.getImm();
6570b57cec5SDimitry Andric       break;
6580b57cec5SDimitry Andric 
6590b57cec5SDimitry Andric     case MachineOperand::MO_MachineBasicBlock:
6600b57cec5SDimitry Andric       MO.getMBB()->getSymbol()->print(O, MAI);
6610b57cec5SDimitry Andric       return;
6620b57cec5SDimitry Andric 
6630b57cec5SDimitry Andric     case MachineOperand::MO_GlobalAddress:
6640b57cec5SDimitry Andric       PrintSymbolOperand(MO, O);
6650b57cec5SDimitry Andric       break;
6660b57cec5SDimitry Andric 
6670b57cec5SDimitry Andric     case MachineOperand::MO_BlockAddress: {
6680b57cec5SDimitry Andric       MCSymbol *BA = GetBlockAddressSymbol(MO.getBlockAddress());
6690b57cec5SDimitry Andric       O << BA->getName();
6700b57cec5SDimitry Andric       break;
6710b57cec5SDimitry Andric     }
6720b57cec5SDimitry Andric 
6730b57cec5SDimitry Andric     case MachineOperand::MO_ConstantPoolIndex:
6740b57cec5SDimitry Andric       O << getDataLayout().getPrivateGlobalPrefix() << "CPI"
6750b57cec5SDimitry Andric         << getFunctionNumber() << "_" << MO.getIndex();
6760b57cec5SDimitry Andric       if (MO.getOffset())
6770b57cec5SDimitry Andric         O << "+" << MO.getOffset();
6780b57cec5SDimitry Andric       break;
6790b57cec5SDimitry Andric 
6800b57cec5SDimitry Andric     default:
6810b57cec5SDimitry Andric       llvm_unreachable("<unknown operand type>");
6820b57cec5SDimitry Andric   }
6830b57cec5SDimitry Andric 
6840b57cec5SDimitry Andric   if (closeP) O << ")";
6850b57cec5SDimitry Andric }
6860b57cec5SDimitry Andric 
6870b57cec5SDimitry Andric void MipsAsmPrinter::
6880b57cec5SDimitry Andric printMemOperand(const MachineInstr *MI, int opNum, raw_ostream &O) {
6890b57cec5SDimitry Andric   // Load/Store memory operands -- imm($reg)
6900b57cec5SDimitry Andric   // If PIC target the target is loaded as the
6910b57cec5SDimitry Andric   // pattern lw $25,%call16($28)
6920b57cec5SDimitry Andric 
6930b57cec5SDimitry Andric   // opNum can be invalid if instruction has reglist as operand.
6940b57cec5SDimitry Andric   // MemOperand is always last operand of instruction (base + offset).
6950b57cec5SDimitry Andric   switch (MI->getOpcode()) {
6960b57cec5SDimitry Andric   default:
6970b57cec5SDimitry Andric     break;
6980b57cec5SDimitry Andric   case Mips::SWM32_MM:
6990b57cec5SDimitry Andric   case Mips::LWM32_MM:
7000b57cec5SDimitry Andric     opNum = MI->getNumOperands() - 2;
7010b57cec5SDimitry Andric     break;
7020b57cec5SDimitry Andric   }
7030b57cec5SDimitry Andric 
7040b57cec5SDimitry Andric   printOperand(MI, opNum+1, O);
7050b57cec5SDimitry Andric   O << "(";
7060b57cec5SDimitry Andric   printOperand(MI, opNum, O);
7070b57cec5SDimitry Andric   O << ")";
7080b57cec5SDimitry Andric }
7090b57cec5SDimitry Andric 
7100b57cec5SDimitry Andric void MipsAsmPrinter::
7110b57cec5SDimitry Andric printMemOperandEA(const MachineInstr *MI, int opNum, raw_ostream &O) {
7120b57cec5SDimitry Andric   // when using stack locations for not load/store instructions
7130b57cec5SDimitry Andric   // print the same way as all normal 3 operand instructions.
7140b57cec5SDimitry Andric   printOperand(MI, opNum, O);
7150b57cec5SDimitry Andric   O << ", ";
7160b57cec5SDimitry Andric   printOperand(MI, opNum+1, O);
7170b57cec5SDimitry Andric }
7180b57cec5SDimitry Andric 
7190b57cec5SDimitry Andric void MipsAsmPrinter::
7200b57cec5SDimitry Andric printFCCOperand(const MachineInstr *MI, int opNum, raw_ostream &O,
7210b57cec5SDimitry Andric                 const char *Modifier) {
7220b57cec5SDimitry Andric   const MachineOperand &MO = MI->getOperand(opNum);
7230b57cec5SDimitry Andric   O << Mips::MipsFCCToString((Mips::CondCode)MO.getImm());
7240b57cec5SDimitry Andric }
7250b57cec5SDimitry Andric 
7260b57cec5SDimitry Andric void MipsAsmPrinter::
7270b57cec5SDimitry Andric printRegisterList(const MachineInstr *MI, int opNum, raw_ostream &O) {
7280b57cec5SDimitry Andric   for (int i = opNum, e = MI->getNumOperands(); i != e; ++i) {
7290b57cec5SDimitry Andric     if (i != opNum) O << ", ";
7300b57cec5SDimitry Andric     printOperand(MI, i, O);
7310b57cec5SDimitry Andric   }
7320b57cec5SDimitry Andric }
7330b57cec5SDimitry Andric 
7345ffd83dbSDimitry Andric void MipsAsmPrinter::emitStartOfAsmFile(Module &M) {
7350b57cec5SDimitry Andric   MipsTargetStreamer &TS = getTargetStreamer();
7360b57cec5SDimitry Andric 
7370b57cec5SDimitry Andric   // MipsTargetStreamer has an initialization order problem when emitting an
7380b57cec5SDimitry Andric   // object file directly (see MipsTargetELFStreamer for full details). Work
7390b57cec5SDimitry Andric   // around it by re-initializing the PIC state here.
7400b57cec5SDimitry Andric   TS.setPic(OutContext.getObjectFileInfo()->isPositionIndependent());
7410b57cec5SDimitry Andric 
74206c3fb27SDimitry Andric   // Try to get target-features from the first function.
74306c3fb27SDimitry Andric   StringRef FS = TM.getTargetFeatureString();
74406c3fb27SDimitry Andric   Module::iterator F = M.begin();
74506c3fb27SDimitry Andric   if (FS.empty() && M.size() && F->hasFnAttribute("target-features"))
74606c3fb27SDimitry Andric     FS = F->getFnAttribute("target-features").getValueAsString();
74706c3fb27SDimitry Andric 
7480b57cec5SDimitry Andric   // Compute MIPS architecture attributes based on the default subtarget
74906c3fb27SDimitry Andric   // that we'd have constructed.
7500b57cec5SDimitry Andric   // FIXME: For ifunc related functions we could iterate over and look
7510b57cec5SDimitry Andric   // for a feature string that doesn't match the default one.
7520b57cec5SDimitry Andric   const Triple &TT = TM.getTargetTriple();
7530b57cec5SDimitry Andric   StringRef CPU = MIPS_MC::selectMipsCPU(TT, TM.getTargetCPU());
7540b57cec5SDimitry Andric   const MipsTargetMachine &MTM = static_cast<const MipsTargetMachine &>(TM);
755bdd1243dSDimitry Andric   const MipsSubtarget STI(TT, CPU, FS, MTM.isLittleEndian(), MTM, std::nullopt);
7560b57cec5SDimitry Andric 
7570b57cec5SDimitry Andric   bool IsABICalls = STI.isABICalls();
7580b57cec5SDimitry Andric   const MipsABIInfo &ABI = MTM.getABI();
7590b57cec5SDimitry Andric   if (IsABICalls) {
7600b57cec5SDimitry Andric     TS.emitDirectiveAbiCalls();
7610b57cec5SDimitry Andric     // FIXME: This condition should be a lot more complicated that it is here.
7620b57cec5SDimitry Andric     //        Ideally it should test for properties of the ABI and not the ABI
7630b57cec5SDimitry Andric     //        itself.
7640b57cec5SDimitry Andric     //        For the moment, I'm only correcting enough to make MIPS-IV work.
7650b57cec5SDimitry Andric     if (!isPositionIndependent() && STI.hasSym32())
7660b57cec5SDimitry Andric       TS.emitDirectiveOptionPic0();
7670b57cec5SDimitry Andric   }
7680b57cec5SDimitry Andric 
7690b57cec5SDimitry Andric   // Tell the assembler which ABI we are using
7700b57cec5SDimitry Andric   std::string SectionName = std::string(".mdebug.") + getCurrentABIString();
77181ad6265SDimitry Andric   OutStreamer->switchSection(
7720b57cec5SDimitry Andric       OutContext.getELFSection(SectionName, ELF::SHT_PROGBITS, 0));
7730b57cec5SDimitry Andric 
7740b57cec5SDimitry Andric   // NaN: At the moment we only support:
7750b57cec5SDimitry Andric   // 1. .nan legacy (default)
7760b57cec5SDimitry Andric   // 2. .nan 2008
7770b57cec5SDimitry Andric   STI.isNaN2008() ? TS.emitDirectiveNaN2008()
7780b57cec5SDimitry Andric                   : TS.emitDirectiveNaNLegacy();
7790b57cec5SDimitry Andric 
7800b57cec5SDimitry Andric   // TODO: handle O64 ABI
7810b57cec5SDimitry Andric 
7820b57cec5SDimitry Andric   TS.updateABIInfo(STI);
7830b57cec5SDimitry Andric 
7840b57cec5SDimitry Andric   // We should always emit a '.module fp=...' but binutils 2.24 does not accept
7850b57cec5SDimitry Andric   // it. We therefore emit it when it contradicts the ABI defaults (-mfpxx or
7860b57cec5SDimitry Andric   // -mfp64) and omit it otherwise.
7870b57cec5SDimitry Andric   if ((ABI.IsO32() && (STI.isABI_FPXX() || STI.isFP64bit())) ||
7880b57cec5SDimitry Andric       STI.useSoftFloat())
7890b57cec5SDimitry Andric     TS.emitDirectiveModuleFP();
7900b57cec5SDimitry Andric 
7910b57cec5SDimitry Andric   // We should always emit a '.module [no]oddspreg' but binutils 2.24 does not
7920b57cec5SDimitry Andric   // accept it. We therefore emit it when it contradicts the default or an
7930b57cec5SDimitry Andric   // option has changed the default (i.e. FPXX) and omit it otherwise.
7940b57cec5SDimitry Andric   if (ABI.IsO32() && (!STI.useOddSPReg() || STI.isABI_FPXX()))
7950b57cec5SDimitry Andric     TS.emitDirectiveModuleOddSPReg();
7968bcb0991SDimitry Andric 
7978bcb0991SDimitry Andric   // Switch to the .text section.
79881ad6265SDimitry Andric   OutStreamer->switchSection(getObjFileLowering().getTextSection());
7990b57cec5SDimitry Andric }
8000b57cec5SDimitry Andric 
8010b57cec5SDimitry Andric void MipsAsmPrinter::emitInlineAsmStart() const {
8020b57cec5SDimitry Andric   MipsTargetStreamer &TS = getTargetStreamer();
8030b57cec5SDimitry Andric 
8040b57cec5SDimitry Andric   // GCC's choice of assembler options for inline assembly code ('at', 'macro'
8050b57cec5SDimitry Andric   // and 'reorder') is different from LLVM's choice for generated code ('noat',
8060b57cec5SDimitry Andric   // 'nomacro' and 'noreorder').
8070b57cec5SDimitry Andric   // In order to maintain compatibility with inline assembly code which depends
8080b57cec5SDimitry Andric   // on GCC's assembler options being used, we have to switch to those options
8090b57cec5SDimitry Andric   // for the duration of the inline assembly block and then switch back.
8100b57cec5SDimitry Andric   TS.emitDirectiveSetPush();
8110b57cec5SDimitry Andric   TS.emitDirectiveSetAt();
8120b57cec5SDimitry Andric   TS.emitDirectiveSetMacro();
8130b57cec5SDimitry Andric   TS.emitDirectiveSetReorder();
81481ad6265SDimitry Andric   OutStreamer->addBlankLine();
8150b57cec5SDimitry Andric }
8160b57cec5SDimitry Andric 
8170b57cec5SDimitry Andric void MipsAsmPrinter::emitInlineAsmEnd(const MCSubtargetInfo &StartInfo,
8180b57cec5SDimitry Andric                                       const MCSubtargetInfo *EndInfo) const {
81981ad6265SDimitry Andric   OutStreamer->addBlankLine();
8200b57cec5SDimitry Andric   getTargetStreamer().emitDirectiveSetPop();
8210b57cec5SDimitry Andric }
8220b57cec5SDimitry Andric 
8230b57cec5SDimitry Andric void MipsAsmPrinter::EmitJal(const MCSubtargetInfo &STI, MCSymbol *Symbol) {
8240b57cec5SDimitry Andric   MCInst I;
8250b57cec5SDimitry Andric   I.setOpcode(Mips::JAL);
8260b57cec5SDimitry Andric   I.addOperand(
8270b57cec5SDimitry Andric       MCOperand::createExpr(MCSymbolRefExpr::create(Symbol, OutContext)));
8285ffd83dbSDimitry Andric   OutStreamer->emitInstruction(I, STI);
8290b57cec5SDimitry Andric }
8300b57cec5SDimitry Andric 
8310b57cec5SDimitry Andric void MipsAsmPrinter::EmitInstrReg(const MCSubtargetInfo &STI, unsigned Opcode,
8320b57cec5SDimitry Andric                                   unsigned Reg) {
8330b57cec5SDimitry Andric   MCInst I;
8340b57cec5SDimitry Andric   I.setOpcode(Opcode);
8350b57cec5SDimitry Andric   I.addOperand(MCOperand::createReg(Reg));
8365ffd83dbSDimitry Andric   OutStreamer->emitInstruction(I, STI);
8370b57cec5SDimitry Andric }
8380b57cec5SDimitry Andric 
8390b57cec5SDimitry Andric void MipsAsmPrinter::EmitInstrRegReg(const MCSubtargetInfo &STI,
8400b57cec5SDimitry Andric                                      unsigned Opcode, unsigned Reg1,
8410b57cec5SDimitry Andric                                      unsigned Reg2) {
8420b57cec5SDimitry Andric   MCInst I;
8430b57cec5SDimitry Andric   //
8440b57cec5SDimitry Andric   // Because of the current td files for Mips32, the operands for MTC1
8450b57cec5SDimitry Andric   // appear backwards from their normal assembly order. It's not a trivial
8460b57cec5SDimitry Andric   // change to fix this in the td file so we adjust for it here.
8470b57cec5SDimitry Andric   //
8480b57cec5SDimitry Andric   if (Opcode == Mips::MTC1) {
8490b57cec5SDimitry Andric     unsigned Temp = Reg1;
8500b57cec5SDimitry Andric     Reg1 = Reg2;
8510b57cec5SDimitry Andric     Reg2 = Temp;
8520b57cec5SDimitry Andric   }
8530b57cec5SDimitry Andric   I.setOpcode(Opcode);
8540b57cec5SDimitry Andric   I.addOperand(MCOperand::createReg(Reg1));
8550b57cec5SDimitry Andric   I.addOperand(MCOperand::createReg(Reg2));
8565ffd83dbSDimitry Andric   OutStreamer->emitInstruction(I, STI);
8570b57cec5SDimitry Andric }
8580b57cec5SDimitry Andric 
8590b57cec5SDimitry Andric void MipsAsmPrinter::EmitInstrRegRegReg(const MCSubtargetInfo &STI,
8600b57cec5SDimitry Andric                                         unsigned Opcode, unsigned Reg1,
8610b57cec5SDimitry Andric                                         unsigned Reg2, unsigned Reg3) {
8620b57cec5SDimitry Andric   MCInst I;
8630b57cec5SDimitry Andric   I.setOpcode(Opcode);
8640b57cec5SDimitry Andric   I.addOperand(MCOperand::createReg(Reg1));
8650b57cec5SDimitry Andric   I.addOperand(MCOperand::createReg(Reg2));
8660b57cec5SDimitry Andric   I.addOperand(MCOperand::createReg(Reg3));
8675ffd83dbSDimitry Andric   OutStreamer->emitInstruction(I, STI);
8680b57cec5SDimitry Andric }
8690b57cec5SDimitry Andric 
8700b57cec5SDimitry Andric void MipsAsmPrinter::EmitMovFPIntPair(const MCSubtargetInfo &STI,
8710b57cec5SDimitry Andric                                       unsigned MovOpc, unsigned Reg1,
8720b57cec5SDimitry Andric                                       unsigned Reg2, unsigned FPReg1,
8730b57cec5SDimitry Andric                                       unsigned FPReg2, bool LE) {
8740b57cec5SDimitry Andric   if (!LE) {
8750b57cec5SDimitry Andric     unsigned temp = Reg1;
8760b57cec5SDimitry Andric     Reg1 = Reg2;
8770b57cec5SDimitry Andric     Reg2 = temp;
8780b57cec5SDimitry Andric   }
8790b57cec5SDimitry Andric   EmitInstrRegReg(STI, MovOpc, Reg1, FPReg1);
8800b57cec5SDimitry Andric   EmitInstrRegReg(STI, MovOpc, Reg2, FPReg2);
8810b57cec5SDimitry Andric }
8820b57cec5SDimitry Andric 
8830b57cec5SDimitry Andric void MipsAsmPrinter::EmitSwapFPIntParams(const MCSubtargetInfo &STI,
8840b57cec5SDimitry Andric                                          Mips16HardFloatInfo::FPParamVariant PV,
8850b57cec5SDimitry Andric                                          bool LE, bool ToFP) {
8860b57cec5SDimitry Andric   using namespace Mips16HardFloatInfo;
8870b57cec5SDimitry Andric 
8880b57cec5SDimitry Andric   unsigned MovOpc = ToFP ? Mips::MTC1 : Mips::MFC1;
8890b57cec5SDimitry Andric   switch (PV) {
8900b57cec5SDimitry Andric   case FSig:
8910b57cec5SDimitry Andric     EmitInstrRegReg(STI, MovOpc, Mips::A0, Mips::F12);
8920b57cec5SDimitry Andric     break;
8930b57cec5SDimitry Andric   case FFSig:
8940b57cec5SDimitry Andric     EmitMovFPIntPair(STI, MovOpc, Mips::A0, Mips::A1, Mips::F12, Mips::F14, LE);
8950b57cec5SDimitry Andric     break;
8960b57cec5SDimitry Andric   case FDSig:
8970b57cec5SDimitry Andric     EmitInstrRegReg(STI, MovOpc, Mips::A0, Mips::F12);
8980b57cec5SDimitry Andric     EmitMovFPIntPair(STI, MovOpc, Mips::A2, Mips::A3, Mips::F14, Mips::F15, LE);
8990b57cec5SDimitry Andric     break;
9000b57cec5SDimitry Andric   case DSig:
9010b57cec5SDimitry Andric     EmitMovFPIntPair(STI, MovOpc, Mips::A0, Mips::A1, Mips::F12, Mips::F13, LE);
9020b57cec5SDimitry Andric     break;
9030b57cec5SDimitry Andric   case DDSig:
9040b57cec5SDimitry Andric     EmitMovFPIntPair(STI, MovOpc, Mips::A0, Mips::A1, Mips::F12, Mips::F13, LE);
9050b57cec5SDimitry Andric     EmitMovFPIntPair(STI, MovOpc, Mips::A2, Mips::A3, Mips::F14, Mips::F15, LE);
9060b57cec5SDimitry Andric     break;
9070b57cec5SDimitry Andric   case DFSig:
9080b57cec5SDimitry Andric     EmitMovFPIntPair(STI, MovOpc, Mips::A0, Mips::A1, Mips::F12, Mips::F13, LE);
9090b57cec5SDimitry Andric     EmitInstrRegReg(STI, MovOpc, Mips::A2, Mips::F14);
9100b57cec5SDimitry Andric     break;
9110b57cec5SDimitry Andric   case NoSig:
9120b57cec5SDimitry Andric     return;
9130b57cec5SDimitry Andric   }
9140b57cec5SDimitry Andric }
9150b57cec5SDimitry Andric 
9160b57cec5SDimitry Andric void MipsAsmPrinter::EmitSwapFPIntRetval(
9170b57cec5SDimitry Andric     const MCSubtargetInfo &STI, Mips16HardFloatInfo::FPReturnVariant RV,
9180b57cec5SDimitry Andric     bool LE) {
9190b57cec5SDimitry Andric   using namespace Mips16HardFloatInfo;
9200b57cec5SDimitry Andric 
9210b57cec5SDimitry Andric   unsigned MovOpc = Mips::MFC1;
9220b57cec5SDimitry Andric   switch (RV) {
9230b57cec5SDimitry Andric   case FRet:
9240b57cec5SDimitry Andric     EmitInstrRegReg(STI, MovOpc, Mips::V0, Mips::F0);
9250b57cec5SDimitry Andric     break;
9260b57cec5SDimitry Andric   case DRet:
9270b57cec5SDimitry Andric     EmitMovFPIntPair(STI, MovOpc, Mips::V0, Mips::V1, Mips::F0, Mips::F1, LE);
9280b57cec5SDimitry Andric     break;
9290b57cec5SDimitry Andric   case CFRet:
9300b57cec5SDimitry Andric     EmitMovFPIntPair(STI, MovOpc, Mips::V0, Mips::V1, Mips::F0, Mips::F1, LE);
9310b57cec5SDimitry Andric     break;
9320b57cec5SDimitry Andric   case CDRet:
9330b57cec5SDimitry Andric     EmitMovFPIntPair(STI, MovOpc, Mips::V0, Mips::V1, Mips::F0, Mips::F1, LE);
9340b57cec5SDimitry Andric     EmitMovFPIntPair(STI, MovOpc, Mips::A0, Mips::A1, Mips::F2, Mips::F3, LE);
9350b57cec5SDimitry Andric     break;
9360b57cec5SDimitry Andric   case NoFPRet:
9370b57cec5SDimitry Andric     break;
9380b57cec5SDimitry Andric   }
9390b57cec5SDimitry Andric }
9400b57cec5SDimitry Andric 
9410b57cec5SDimitry Andric void MipsAsmPrinter::EmitFPCallStub(
9420b57cec5SDimitry Andric     const char *Symbol, const Mips16HardFloatInfo::FuncSignature *Signature) {
9430b57cec5SDimitry Andric   using namespace Mips16HardFloatInfo;
9440b57cec5SDimitry Andric 
9450b57cec5SDimitry Andric   MCSymbol *MSymbol = OutContext.getOrCreateSymbol(StringRef(Symbol));
9460b57cec5SDimitry Andric   bool LE = getDataLayout().isLittleEndian();
9470b57cec5SDimitry Andric   // Construct a local MCSubtargetInfo here.
9480b57cec5SDimitry Andric   // This is because the MachineFunction won't exist (but have not yet been
9490b57cec5SDimitry Andric   // freed) and since we're at the global level we can use the default
9500b57cec5SDimitry Andric   // constructed subtarget.
9510b57cec5SDimitry Andric   std::unique_ptr<MCSubtargetInfo> STI(TM.getTarget().createMCSubtargetInfo(
9520b57cec5SDimitry Andric       TM.getTargetTriple().str(), TM.getTargetCPU(),
9530b57cec5SDimitry Andric       TM.getTargetFeatureString()));
9540b57cec5SDimitry Andric 
9550b57cec5SDimitry Andric   //
9560b57cec5SDimitry Andric   // .global xxxx
9570b57cec5SDimitry Andric   //
9585ffd83dbSDimitry Andric   OutStreamer->emitSymbolAttribute(MSymbol, MCSA_Global);
9590b57cec5SDimitry Andric   const char *RetType;
9600b57cec5SDimitry Andric   //
9610b57cec5SDimitry Andric   // make the comment field identifying the return and parameter
9620b57cec5SDimitry Andric   // types of the floating point stub
9630b57cec5SDimitry Andric   // # Stub function to call rettype xxxx (params)
9640b57cec5SDimitry Andric   //
9650b57cec5SDimitry Andric   switch (Signature->RetSig) {
9660b57cec5SDimitry Andric   case FRet:
9670b57cec5SDimitry Andric     RetType = "float";
9680b57cec5SDimitry Andric     break;
9690b57cec5SDimitry Andric   case DRet:
9700b57cec5SDimitry Andric     RetType = "double";
9710b57cec5SDimitry Andric     break;
9720b57cec5SDimitry Andric   case CFRet:
9730b57cec5SDimitry Andric     RetType = "complex";
9740b57cec5SDimitry Andric     break;
9750b57cec5SDimitry Andric   case CDRet:
9760b57cec5SDimitry Andric     RetType = "double complex";
9770b57cec5SDimitry Andric     break;
9780b57cec5SDimitry Andric   case NoFPRet:
9790b57cec5SDimitry Andric     RetType = "";
9800b57cec5SDimitry Andric     break;
9810b57cec5SDimitry Andric   }
9820b57cec5SDimitry Andric   const char *Parms;
9830b57cec5SDimitry Andric   switch (Signature->ParamSig) {
9840b57cec5SDimitry Andric   case FSig:
9850b57cec5SDimitry Andric     Parms = "float";
9860b57cec5SDimitry Andric     break;
9870b57cec5SDimitry Andric   case FFSig:
9880b57cec5SDimitry Andric     Parms = "float, float";
9890b57cec5SDimitry Andric     break;
9900b57cec5SDimitry Andric   case FDSig:
9910b57cec5SDimitry Andric     Parms = "float, double";
9920b57cec5SDimitry Andric     break;
9930b57cec5SDimitry Andric   case DSig:
9940b57cec5SDimitry Andric     Parms = "double";
9950b57cec5SDimitry Andric     break;
9960b57cec5SDimitry Andric   case DDSig:
9970b57cec5SDimitry Andric     Parms = "double, double";
9980b57cec5SDimitry Andric     break;
9990b57cec5SDimitry Andric   case DFSig:
10000b57cec5SDimitry Andric     Parms = "double, float";
10010b57cec5SDimitry Andric     break;
10020b57cec5SDimitry Andric   case NoSig:
10030b57cec5SDimitry Andric     Parms = "";
10040b57cec5SDimitry Andric     break;
10050b57cec5SDimitry Andric   }
10060b57cec5SDimitry Andric   OutStreamer->AddComment("\t# Stub function to call " + Twine(RetType) + " " +
10070b57cec5SDimitry Andric                           Twine(Symbol) + " (" + Twine(Parms) + ")");
10080b57cec5SDimitry Andric   //
10090b57cec5SDimitry Andric   // probably not necessary but we save and restore the current section state
10100b57cec5SDimitry Andric   //
101181ad6265SDimitry Andric   OutStreamer->pushSection();
10120b57cec5SDimitry Andric   //
10130b57cec5SDimitry Andric   // .section mips16.call.fpxxxx,"ax",@progbits
10140b57cec5SDimitry Andric   //
10150b57cec5SDimitry Andric   MCSectionELF *M = OutContext.getELFSection(
10160b57cec5SDimitry Andric       ".mips16.call.fp." + std::string(Symbol), ELF::SHT_PROGBITS,
10170b57cec5SDimitry Andric       ELF::SHF_ALLOC | ELF::SHF_EXECINSTR);
1018*0fca6ea1SDimitry Andric   OutStreamer->switchSection(M);
10190b57cec5SDimitry Andric   //
10200b57cec5SDimitry Andric   // .align 2
10210b57cec5SDimitry Andric   //
1022bdd1243dSDimitry Andric   OutStreamer->emitValueToAlignment(Align(4));
10230b57cec5SDimitry Andric   MipsTargetStreamer &TS = getTargetStreamer();
10240b57cec5SDimitry Andric   //
10250b57cec5SDimitry Andric   // .set nomips16
10260b57cec5SDimitry Andric   // .set nomicromips
10270b57cec5SDimitry Andric   //
10280b57cec5SDimitry Andric   TS.emitDirectiveSetNoMips16();
10290b57cec5SDimitry Andric   TS.emitDirectiveSetNoMicroMips();
10300b57cec5SDimitry Andric   //
10310b57cec5SDimitry Andric   // .ent __call_stub_fp_xxxx
10320b57cec5SDimitry Andric   // .type  __call_stub_fp_xxxx,@function
10330b57cec5SDimitry Andric   //  __call_stub_fp_xxxx:
10340b57cec5SDimitry Andric   //
10350b57cec5SDimitry Andric   std::string x = "__call_stub_fp_" + std::string(Symbol);
10360b57cec5SDimitry Andric   MCSymbolELF *Stub =
10370b57cec5SDimitry Andric       cast<MCSymbolELF>(OutContext.getOrCreateSymbol(StringRef(x)));
10380b57cec5SDimitry Andric   TS.emitDirectiveEnt(*Stub);
10390b57cec5SDimitry Andric   MCSymbol *MType =
10400b57cec5SDimitry Andric       OutContext.getOrCreateSymbol("__call_stub_fp_" + Twine(Symbol));
10415ffd83dbSDimitry Andric   OutStreamer->emitSymbolAttribute(MType, MCSA_ELF_TypeFunction);
10425ffd83dbSDimitry Andric   OutStreamer->emitLabel(Stub);
10430b57cec5SDimitry Andric 
10440b57cec5SDimitry Andric   // Only handle non-pic for now.
10450b57cec5SDimitry Andric   assert(!isPositionIndependent() &&
10460b57cec5SDimitry Andric          "should not be here if we are compiling pic");
10470b57cec5SDimitry Andric   TS.emitDirectiveSetReorder();
10480b57cec5SDimitry Andric   //
10490b57cec5SDimitry Andric   // We need to add a MipsMCExpr class to MCTargetDesc to fully implement
10500b57cec5SDimitry Andric   // stubs without raw text but this current patch is for compiler generated
10510b57cec5SDimitry Andric   // functions and they all return some value.
10520b57cec5SDimitry Andric   // The calling sequence for non pic is different in that case and we need
10530b57cec5SDimitry Andric   // to implement %lo and %hi in order to handle the case of no return value
10540b57cec5SDimitry Andric   // See the corresponding method in Mips16HardFloat for details.
10550b57cec5SDimitry Andric   //
10560b57cec5SDimitry Andric   // mov the return address to S2.
10570b57cec5SDimitry Andric   // we have no stack space to store it and we are about to make another call.
10580b57cec5SDimitry Andric   // We need to make sure that the enclosing function knows to save S2
10590b57cec5SDimitry Andric   // This should have already been handled.
10600b57cec5SDimitry Andric   //
10610b57cec5SDimitry Andric   // Mov $18, $31
10620b57cec5SDimitry Andric 
10630b57cec5SDimitry Andric   EmitInstrRegRegReg(*STI, Mips::OR, Mips::S2, Mips::RA, Mips::ZERO);
10640b57cec5SDimitry Andric 
10650b57cec5SDimitry Andric   EmitSwapFPIntParams(*STI, Signature->ParamSig, LE, true);
10660b57cec5SDimitry Andric 
10670b57cec5SDimitry Andric   // Jal xxxx
10680b57cec5SDimitry Andric   //
10690b57cec5SDimitry Andric   EmitJal(*STI, MSymbol);
10700b57cec5SDimitry Andric 
10710b57cec5SDimitry Andric   // fix return values
10720b57cec5SDimitry Andric   EmitSwapFPIntRetval(*STI, Signature->RetSig, LE);
10730b57cec5SDimitry Andric   //
10740b57cec5SDimitry Andric   // do the return
10750b57cec5SDimitry Andric   // if (Signature->RetSig == NoFPRet)
10760b57cec5SDimitry Andric   //  llvm_unreachable("should not be any stubs here with no return value");
10770b57cec5SDimitry Andric   // else
10780b57cec5SDimitry Andric   EmitInstrReg(*STI, Mips::JR, Mips::S2);
10790b57cec5SDimitry Andric 
10800b57cec5SDimitry Andric   MCSymbol *Tmp = OutContext.createTempSymbol();
10815ffd83dbSDimitry Andric   OutStreamer->emitLabel(Tmp);
10820b57cec5SDimitry Andric   const MCSymbolRefExpr *E = MCSymbolRefExpr::create(Stub, OutContext);
10830b57cec5SDimitry Andric   const MCSymbolRefExpr *T = MCSymbolRefExpr::create(Tmp, OutContext);
10840b57cec5SDimitry Andric   const MCExpr *T_min_E = MCBinaryExpr::createSub(T, E, OutContext);
10850b57cec5SDimitry Andric   OutStreamer->emitELFSize(Stub, T_min_E);
10860b57cec5SDimitry Andric   TS.emitDirectiveEnd(x);
108781ad6265SDimitry Andric   OutStreamer->popSection();
10880b57cec5SDimitry Andric }
10890b57cec5SDimitry Andric 
10905ffd83dbSDimitry Andric void MipsAsmPrinter::emitEndOfAsmFile(Module &M) {
10910b57cec5SDimitry Andric   // Emit needed stubs
10920b57cec5SDimitry Andric   //
10930b57cec5SDimitry Andric   for (std::map<
10940b57cec5SDimitry Andric            const char *,
10950b57cec5SDimitry Andric            const Mips16HardFloatInfo::FuncSignature *>::const_iterator
10960b57cec5SDimitry Andric            it = StubsNeeded.begin();
10970b57cec5SDimitry Andric        it != StubsNeeded.end(); ++it) {
10980b57cec5SDimitry Andric     const char *Symbol = it->first;
10990b57cec5SDimitry Andric     const Mips16HardFloatInfo::FuncSignature *Signature = it->second;
11000b57cec5SDimitry Andric     EmitFPCallStub(Symbol, Signature);
11010b57cec5SDimitry Andric   }
11020b57cec5SDimitry Andric   // return to the text section
110381ad6265SDimitry Andric   OutStreamer->switchSection(OutContext.getObjectFileInfo()->getTextSection());
11040b57cec5SDimitry Andric }
11050b57cec5SDimitry Andric 
11060b57cec5SDimitry Andric void MipsAsmPrinter::EmitSled(const MachineInstr &MI, SledKind Kind) {
11070b57cec5SDimitry Andric   const uint8_t NoopsInSledCount = Subtarget->isGP64bit() ? 15 : 11;
11080b57cec5SDimitry Andric   // For mips32 we want to emit the following pattern:
11090b57cec5SDimitry Andric   //
11100b57cec5SDimitry Andric   // .Lxray_sled_N:
11110b57cec5SDimitry Andric   //   ALIGN
11120b57cec5SDimitry Andric   //   B .tmpN
11130b57cec5SDimitry Andric   //   11 NOP instructions (44 bytes)
11140b57cec5SDimitry Andric   //   ADDIU T9, T9, 52
11150b57cec5SDimitry Andric   // .tmpN
11160b57cec5SDimitry Andric   //
11170b57cec5SDimitry Andric   // We need the 44 bytes (11 instructions) because at runtime, we'd
11180b57cec5SDimitry Andric   // be patching over the full 48 bytes (12 instructions) with the following
11190b57cec5SDimitry Andric   // pattern:
11200b57cec5SDimitry Andric   //
11210b57cec5SDimitry Andric   //   ADDIU    SP, SP, -8
11220b57cec5SDimitry Andric   //   NOP
11230b57cec5SDimitry Andric   //   SW       RA, 4(SP)
11240b57cec5SDimitry Andric   //   SW       T9, 0(SP)
11250b57cec5SDimitry Andric   //   LUI      T9, %hi(__xray_FunctionEntry/Exit)
11260b57cec5SDimitry Andric   //   ORI      T9, T9, %lo(__xray_FunctionEntry/Exit)
11270b57cec5SDimitry Andric   //   LUI      T0, %hi(function_id)
11280b57cec5SDimitry Andric   //   JALR     T9
11290b57cec5SDimitry Andric   //   ORI      T0, T0, %lo(function_id)
11300b57cec5SDimitry Andric   //   LW       T9, 0(SP)
11310b57cec5SDimitry Andric   //   LW       RA, 4(SP)
11320b57cec5SDimitry Andric   //   ADDIU    SP, SP, 8
11330b57cec5SDimitry Andric   //
11340b57cec5SDimitry Andric   // We add 52 bytes to t9 because we want to adjust the function pointer to
11350b57cec5SDimitry Andric   // the actual start of function i.e. the address just after the noop sled.
11360b57cec5SDimitry Andric   // We do this because gp displacement relocation is emitted at the start of
11370b57cec5SDimitry Andric   // of the function i.e after the nop sled and to correctly calculate the
11380b57cec5SDimitry Andric   // global offset table address, t9 must hold the address of the instruction
11390b57cec5SDimitry Andric   // containing the gp displacement relocation.
11400b57cec5SDimitry Andric   // FIXME: Is this correct for the static relocation model?
11410b57cec5SDimitry Andric   //
11420b57cec5SDimitry Andric   // For mips64 we want to emit the following pattern:
11430b57cec5SDimitry Andric   //
11440b57cec5SDimitry Andric   // .Lxray_sled_N:
11450b57cec5SDimitry Andric   //   ALIGN
11460b57cec5SDimitry Andric   //   B .tmpN
11470b57cec5SDimitry Andric   //   15 NOP instructions (60 bytes)
11480b57cec5SDimitry Andric   // .tmpN
11490b57cec5SDimitry Andric   //
11500b57cec5SDimitry Andric   // We need the 60 bytes (15 instructions) because at runtime, we'd
11510b57cec5SDimitry Andric   // be patching over the full 64 bytes (16 instructions) with the following
11520b57cec5SDimitry Andric   // pattern:
11530b57cec5SDimitry Andric   //
11540b57cec5SDimitry Andric   //   DADDIU   SP, SP, -16
11550b57cec5SDimitry Andric   //   NOP
11560b57cec5SDimitry Andric   //   SD       RA, 8(SP)
11570b57cec5SDimitry Andric   //   SD       T9, 0(SP)
11580b57cec5SDimitry Andric   //   LUI      T9, %highest(__xray_FunctionEntry/Exit)
11590b57cec5SDimitry Andric   //   ORI      T9, T9, %higher(__xray_FunctionEntry/Exit)
11600b57cec5SDimitry Andric   //   DSLL     T9, T9, 16
11610b57cec5SDimitry Andric   //   ORI      T9, T9, %hi(__xray_FunctionEntry/Exit)
11620b57cec5SDimitry Andric   //   DSLL     T9, T9, 16
11630b57cec5SDimitry Andric   //   ORI      T9, T9, %lo(__xray_FunctionEntry/Exit)
11640b57cec5SDimitry Andric   //   LUI      T0, %hi(function_id)
11650b57cec5SDimitry Andric   //   JALR     T9
11660b57cec5SDimitry Andric   //   ADDIU    T0, T0, %lo(function_id)
11670b57cec5SDimitry Andric   //   LD       T9, 0(SP)
11680b57cec5SDimitry Andric   //   LD       RA, 8(SP)
11690b57cec5SDimitry Andric   //   DADDIU   SP, SP, 16
11700b57cec5SDimitry Andric   //
1171bdd1243dSDimitry Andric   OutStreamer->emitCodeAlignment(Align(4), &getSubtargetInfo());
11720b57cec5SDimitry Andric   auto CurSled = OutContext.createTempSymbol("xray_sled_", true);
11735ffd83dbSDimitry Andric   OutStreamer->emitLabel(CurSled);
11740b57cec5SDimitry Andric   auto Target = OutContext.createTempSymbol();
11750b57cec5SDimitry Andric 
11760b57cec5SDimitry Andric   // Emit "B .tmpN" instruction, which jumps over the nop sled to the actual
11770b57cec5SDimitry Andric   // start of function
11780b57cec5SDimitry Andric   const MCExpr *TargetExpr = MCSymbolRefExpr::create(
11790b57cec5SDimitry Andric       Target, MCSymbolRefExpr::VariantKind::VK_None, OutContext);
11800b57cec5SDimitry Andric   EmitToStreamer(*OutStreamer, MCInstBuilder(Mips::BEQ)
11810b57cec5SDimitry Andric                                    .addReg(Mips::ZERO)
11820b57cec5SDimitry Andric                                    .addReg(Mips::ZERO)
11830b57cec5SDimitry Andric                                    .addExpr(TargetExpr));
11840b57cec5SDimitry Andric 
11850b57cec5SDimitry Andric   for (int8_t I = 0; I < NoopsInSledCount; I++)
11860b57cec5SDimitry Andric     EmitToStreamer(*OutStreamer, MCInstBuilder(Mips::SLL)
11870b57cec5SDimitry Andric                                      .addReg(Mips::ZERO)
11880b57cec5SDimitry Andric                                      .addReg(Mips::ZERO)
11890b57cec5SDimitry Andric                                      .addImm(0));
11900b57cec5SDimitry Andric 
11915ffd83dbSDimitry Andric   OutStreamer->emitLabel(Target);
11920b57cec5SDimitry Andric 
11930b57cec5SDimitry Andric   if (!Subtarget->isGP64bit()) {
11940b57cec5SDimitry Andric     EmitToStreamer(*OutStreamer,
11950b57cec5SDimitry Andric                    MCInstBuilder(Mips::ADDiu)
11960b57cec5SDimitry Andric                        .addReg(Mips::T9)
11970b57cec5SDimitry Andric                        .addReg(Mips::T9)
11980b57cec5SDimitry Andric                        .addImm(0x34));
11990b57cec5SDimitry Andric   }
12000b57cec5SDimitry Andric 
1201e8d8bef9SDimitry Andric   recordSled(CurSled, MI, Kind, 2);
12020b57cec5SDimitry Andric }
12030b57cec5SDimitry Andric 
12040b57cec5SDimitry Andric void MipsAsmPrinter::LowerPATCHABLE_FUNCTION_ENTER(const MachineInstr &MI) {
12050b57cec5SDimitry Andric   EmitSled(MI, SledKind::FUNCTION_ENTER);
12060b57cec5SDimitry Andric }
12070b57cec5SDimitry Andric 
12080b57cec5SDimitry Andric void MipsAsmPrinter::LowerPATCHABLE_FUNCTION_EXIT(const MachineInstr &MI) {
12090b57cec5SDimitry Andric   EmitSled(MI, SledKind::FUNCTION_EXIT);
12100b57cec5SDimitry Andric }
12110b57cec5SDimitry Andric 
12120b57cec5SDimitry Andric void MipsAsmPrinter::LowerPATCHABLE_TAIL_CALL(const MachineInstr &MI) {
12130b57cec5SDimitry Andric   EmitSled(MI, SledKind::TAIL_CALL);
12140b57cec5SDimitry Andric }
12150b57cec5SDimitry Andric 
12160b57cec5SDimitry Andric void MipsAsmPrinter::PrintDebugValueComment(const MachineInstr *MI,
12170b57cec5SDimitry Andric                                            raw_ostream &OS) {
12180b57cec5SDimitry Andric   // TODO: implement
12190b57cec5SDimitry Andric }
12200b57cec5SDimitry Andric 
12210b57cec5SDimitry Andric // Emit .dtprelword or .dtpreldword directive
12220b57cec5SDimitry Andric // and value for debug thread local expression.
12235ffd83dbSDimitry Andric void MipsAsmPrinter::emitDebugValue(const MCExpr *Value, unsigned Size) const {
12240b57cec5SDimitry Andric   if (auto *MipsExpr = dyn_cast<MipsMCExpr>(Value)) {
12250b57cec5SDimitry Andric     if (MipsExpr && MipsExpr->getKind() == MipsMCExpr::MEK_DTPREL) {
12260b57cec5SDimitry Andric       switch (Size) {
12270b57cec5SDimitry Andric       case 4:
12285ffd83dbSDimitry Andric         OutStreamer->emitDTPRel32Value(MipsExpr->getSubExpr());
12290b57cec5SDimitry Andric         break;
12300b57cec5SDimitry Andric       case 8:
12315ffd83dbSDimitry Andric         OutStreamer->emitDTPRel64Value(MipsExpr->getSubExpr());
12320b57cec5SDimitry Andric         break;
12330b57cec5SDimitry Andric       default:
12340b57cec5SDimitry Andric         llvm_unreachable("Unexpected size of expression value.");
12350b57cec5SDimitry Andric       }
12360b57cec5SDimitry Andric       return;
12370b57cec5SDimitry Andric     }
12380b57cec5SDimitry Andric   }
12395ffd83dbSDimitry Andric   AsmPrinter::emitDebugValue(Value, Size);
12400b57cec5SDimitry Andric }
12410b57cec5SDimitry Andric 
12420b57cec5SDimitry Andric // Align all targets of indirect branches on bundle size.  Used only if target
12430b57cec5SDimitry Andric // is NaCl.
12440b57cec5SDimitry Andric void MipsAsmPrinter::NaClAlignIndirectJumpTargets(MachineFunction &MF) {
12450b57cec5SDimitry Andric   // Align all blocks that are jumped to through jump table.
12460b57cec5SDimitry Andric   if (MachineJumpTableInfo *JtInfo = MF.getJumpTableInfo()) {
12470b57cec5SDimitry Andric     const std::vector<MachineJumpTableEntry> &JT = JtInfo->getJumpTables();
124804eeddc0SDimitry Andric     for (const auto &I : JT) {
124904eeddc0SDimitry Andric       const std::vector<MachineBasicBlock *> &MBBs = I.MBBs;
12500b57cec5SDimitry Andric 
125104eeddc0SDimitry Andric       for (MachineBasicBlock *MBB : MBBs)
125204eeddc0SDimitry Andric         MBB->setAlignment(MIPS_NACL_BUNDLE_ALIGN);
12530b57cec5SDimitry Andric     }
12540b57cec5SDimitry Andric   }
12550b57cec5SDimitry Andric 
12560b57cec5SDimitry Andric   // If basic block address is taken, block can be target of indirect branch.
12570b57cec5SDimitry Andric   for (auto &MBB : MF) {
12580b57cec5SDimitry Andric     if (MBB.hasAddressTaken())
12590b57cec5SDimitry Andric       MBB.setAlignment(MIPS_NACL_BUNDLE_ALIGN);
12600b57cec5SDimitry Andric   }
12610b57cec5SDimitry Andric }
12620b57cec5SDimitry Andric 
12630b57cec5SDimitry Andric bool MipsAsmPrinter::isLongBranchPseudo(int Opcode) const {
12640b57cec5SDimitry Andric   return (Opcode == Mips::LONG_BRANCH_LUi
12650b57cec5SDimitry Andric           || Opcode == Mips::LONG_BRANCH_LUi2Op
12660b57cec5SDimitry Andric           || Opcode == Mips::LONG_BRANCH_LUi2Op_64
12670b57cec5SDimitry Andric           || Opcode == Mips::LONG_BRANCH_ADDiu
12680b57cec5SDimitry Andric           || Opcode == Mips::LONG_BRANCH_ADDiu2Op
12690b57cec5SDimitry Andric           || Opcode == Mips::LONG_BRANCH_DADDiu
12700b57cec5SDimitry Andric           || Opcode == Mips::LONG_BRANCH_DADDiu2Op);
12710b57cec5SDimitry Andric }
12720b57cec5SDimitry Andric 
12730b57cec5SDimitry Andric // Force static initialization.
1274480093f4SDimitry Andric extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeMipsAsmPrinter() {
12750b57cec5SDimitry Andric   RegisterAsmPrinter<MipsAsmPrinter> X(getTheMipsTarget());
12760b57cec5SDimitry Andric   RegisterAsmPrinter<MipsAsmPrinter> Y(getTheMipselTarget());
12770b57cec5SDimitry Andric   RegisterAsmPrinter<MipsAsmPrinter> A(getTheMips64Target());
12780b57cec5SDimitry Andric   RegisterAsmPrinter<MipsAsmPrinter> B(getTheMips64elTarget());
12790b57cec5SDimitry Andric }
1280