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