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