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