1*0b57cec5SDimitry Andric //===- MipsAsmPrinter.cpp - Mips LLVM Assembly Printer --------------------===// 2*0b57cec5SDimitry Andric // 3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*0b57cec5SDimitry Andric // 7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 8*0b57cec5SDimitry Andric // 9*0b57cec5SDimitry Andric // This file contains a printer that converts from our internal representation 10*0b57cec5SDimitry Andric // of machine-dependent LLVM code to GAS-format MIPS assembly language. 11*0b57cec5SDimitry Andric // 12*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 13*0b57cec5SDimitry Andric 14*0b57cec5SDimitry Andric #include "MipsAsmPrinter.h" 15*0b57cec5SDimitry Andric #include "MCTargetDesc/MipsABIInfo.h" 16*0b57cec5SDimitry Andric #include "MCTargetDesc/MipsBaseInfo.h" 17*0b57cec5SDimitry Andric #include "MCTargetDesc/MipsInstPrinter.h" 18*0b57cec5SDimitry Andric #include "MCTargetDesc/MipsMCNaCl.h" 19*0b57cec5SDimitry Andric #include "MCTargetDesc/MipsMCTargetDesc.h" 20*0b57cec5SDimitry Andric #include "Mips.h" 21*0b57cec5SDimitry Andric #include "MipsMCInstLower.h" 22*0b57cec5SDimitry Andric #include "MipsMachineFunction.h" 23*0b57cec5SDimitry Andric #include "MipsSubtarget.h" 24*0b57cec5SDimitry Andric #include "MipsTargetMachine.h" 25*0b57cec5SDimitry Andric #include "MipsTargetStreamer.h" 26*0b57cec5SDimitry Andric #include "TargetInfo/MipsTargetInfo.h" 27*0b57cec5SDimitry Andric #include "llvm/ADT/SmallString.h" 28*0b57cec5SDimitry Andric #include "llvm/ADT/StringRef.h" 29*0b57cec5SDimitry Andric #include "llvm/ADT/Triple.h" 30*0b57cec5SDimitry Andric #include "llvm/ADT/Twine.h" 31*0b57cec5SDimitry Andric #include "llvm/BinaryFormat/ELF.h" 32*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineBasicBlock.h" 33*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineConstantPool.h" 34*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFrameInfo.h" 35*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunction.h" 36*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstr.h" 37*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineJumpTableInfo.h" 38*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineOperand.h" 39*0b57cec5SDimitry Andric #include "llvm/CodeGen/TargetRegisterInfo.h" 40*0b57cec5SDimitry Andric #include "llvm/CodeGen/TargetSubtargetInfo.h" 41*0b57cec5SDimitry Andric #include "llvm/IR/Attributes.h" 42*0b57cec5SDimitry Andric #include "llvm/IR/BasicBlock.h" 43*0b57cec5SDimitry Andric #include "llvm/IR/DataLayout.h" 44*0b57cec5SDimitry Andric #include "llvm/IR/Function.h" 45*0b57cec5SDimitry Andric #include "llvm/IR/InlineAsm.h" 46*0b57cec5SDimitry Andric #include "llvm/IR/Instructions.h" 47*0b57cec5SDimitry Andric #include "llvm/MC/MCContext.h" 48*0b57cec5SDimitry Andric #include "llvm/MC/MCExpr.h" 49*0b57cec5SDimitry Andric #include "llvm/MC/MCInst.h" 50*0b57cec5SDimitry Andric #include "llvm/MC/MCInstBuilder.h" 51*0b57cec5SDimitry Andric #include "llvm/MC/MCObjectFileInfo.h" 52*0b57cec5SDimitry Andric #include "llvm/MC/MCSectionELF.h" 53*0b57cec5SDimitry Andric #include "llvm/MC/MCSymbol.h" 54*0b57cec5SDimitry Andric #include "llvm/MC/MCSymbolELF.h" 55*0b57cec5SDimitry Andric #include "llvm/Support/Casting.h" 56*0b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h" 57*0b57cec5SDimitry Andric #include "llvm/Support/TargetRegistry.h" 58*0b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h" 59*0b57cec5SDimitry Andric #include "llvm/Target/TargetMachine.h" 60*0b57cec5SDimitry Andric #include <cassert> 61*0b57cec5SDimitry Andric #include <cstdint> 62*0b57cec5SDimitry Andric #include <map> 63*0b57cec5SDimitry Andric #include <memory> 64*0b57cec5SDimitry Andric #include <string> 65*0b57cec5SDimitry Andric #include <vector> 66*0b57cec5SDimitry Andric 67*0b57cec5SDimitry Andric using namespace llvm; 68*0b57cec5SDimitry Andric 69*0b57cec5SDimitry Andric #define DEBUG_TYPE "mips-asm-printer" 70*0b57cec5SDimitry Andric 71*0b57cec5SDimitry Andric extern cl::opt<bool> EmitJalrReloc; 72*0b57cec5SDimitry Andric 73*0b57cec5SDimitry Andric MipsTargetStreamer &MipsAsmPrinter::getTargetStreamer() const { 74*0b57cec5SDimitry Andric return static_cast<MipsTargetStreamer &>(*OutStreamer->getTargetStreamer()); 75*0b57cec5SDimitry Andric } 76*0b57cec5SDimitry Andric 77*0b57cec5SDimitry Andric bool MipsAsmPrinter::runOnMachineFunction(MachineFunction &MF) { 78*0b57cec5SDimitry Andric Subtarget = &MF.getSubtarget<MipsSubtarget>(); 79*0b57cec5SDimitry Andric 80*0b57cec5SDimitry Andric MipsFI = MF.getInfo<MipsFunctionInfo>(); 81*0b57cec5SDimitry Andric if (Subtarget->inMips16Mode()) 82*0b57cec5SDimitry Andric for (std::map< 83*0b57cec5SDimitry Andric const char *, 84*0b57cec5SDimitry Andric const Mips16HardFloatInfo::FuncSignature *>::const_iterator 85*0b57cec5SDimitry Andric it = MipsFI->StubsNeeded.begin(); 86*0b57cec5SDimitry Andric it != MipsFI->StubsNeeded.end(); ++it) { 87*0b57cec5SDimitry Andric const char *Symbol = it->first; 88*0b57cec5SDimitry Andric const Mips16HardFloatInfo::FuncSignature *Signature = it->second; 89*0b57cec5SDimitry Andric if (StubsNeeded.find(Symbol) == StubsNeeded.end()) 90*0b57cec5SDimitry Andric StubsNeeded[Symbol] = Signature; 91*0b57cec5SDimitry Andric } 92*0b57cec5SDimitry Andric MCP = MF.getConstantPool(); 93*0b57cec5SDimitry Andric 94*0b57cec5SDimitry Andric // In NaCl, all indirect jump targets must be aligned to bundle size. 95*0b57cec5SDimitry Andric if (Subtarget->isTargetNaCl()) 96*0b57cec5SDimitry Andric NaClAlignIndirectJumpTargets(MF); 97*0b57cec5SDimitry Andric 98*0b57cec5SDimitry Andric AsmPrinter::runOnMachineFunction(MF); 99*0b57cec5SDimitry Andric 100*0b57cec5SDimitry Andric emitXRayTable(); 101*0b57cec5SDimitry Andric 102*0b57cec5SDimitry Andric return true; 103*0b57cec5SDimitry Andric } 104*0b57cec5SDimitry Andric 105*0b57cec5SDimitry Andric bool MipsAsmPrinter::lowerOperand(const MachineOperand &MO, MCOperand &MCOp) { 106*0b57cec5SDimitry Andric MCOp = MCInstLowering.LowerOperand(MO); 107*0b57cec5SDimitry Andric return MCOp.isValid(); 108*0b57cec5SDimitry Andric } 109*0b57cec5SDimitry Andric 110*0b57cec5SDimitry Andric #include "MipsGenMCPseudoLowering.inc" 111*0b57cec5SDimitry Andric 112*0b57cec5SDimitry Andric // Lower PseudoReturn/PseudoIndirectBranch/PseudoIndirectBranch64 to JR, JR_MM, 113*0b57cec5SDimitry Andric // JALR, or JALR64 as appropriate for the target. 114*0b57cec5SDimitry Andric void MipsAsmPrinter::emitPseudoIndirectBranch(MCStreamer &OutStreamer, 115*0b57cec5SDimitry Andric const MachineInstr *MI) { 116*0b57cec5SDimitry Andric bool HasLinkReg = false; 117*0b57cec5SDimitry Andric bool InMicroMipsMode = Subtarget->inMicroMipsMode(); 118*0b57cec5SDimitry Andric MCInst TmpInst0; 119*0b57cec5SDimitry Andric 120*0b57cec5SDimitry Andric if (Subtarget->hasMips64r6()) { 121*0b57cec5SDimitry Andric // MIPS64r6 should use (JALR64 ZERO_64, $rs) 122*0b57cec5SDimitry Andric TmpInst0.setOpcode(Mips::JALR64); 123*0b57cec5SDimitry Andric HasLinkReg = true; 124*0b57cec5SDimitry Andric } else if (Subtarget->hasMips32r6()) { 125*0b57cec5SDimitry Andric // MIPS32r6 should use (JALR ZERO, $rs) 126*0b57cec5SDimitry Andric if (InMicroMipsMode) 127*0b57cec5SDimitry Andric TmpInst0.setOpcode(Mips::JRC16_MMR6); 128*0b57cec5SDimitry Andric else { 129*0b57cec5SDimitry Andric TmpInst0.setOpcode(Mips::JALR); 130*0b57cec5SDimitry Andric HasLinkReg = true; 131*0b57cec5SDimitry Andric } 132*0b57cec5SDimitry Andric } else if (Subtarget->inMicroMipsMode()) 133*0b57cec5SDimitry Andric // microMIPS should use (JR_MM $rs) 134*0b57cec5SDimitry Andric TmpInst0.setOpcode(Mips::JR_MM); 135*0b57cec5SDimitry Andric else { 136*0b57cec5SDimitry Andric // Everything else should use (JR $rs) 137*0b57cec5SDimitry Andric TmpInst0.setOpcode(Mips::JR); 138*0b57cec5SDimitry Andric } 139*0b57cec5SDimitry Andric 140*0b57cec5SDimitry Andric MCOperand MCOp; 141*0b57cec5SDimitry Andric 142*0b57cec5SDimitry Andric if (HasLinkReg) { 143*0b57cec5SDimitry Andric unsigned ZeroReg = Subtarget->isGP64bit() ? Mips::ZERO_64 : Mips::ZERO; 144*0b57cec5SDimitry Andric TmpInst0.addOperand(MCOperand::createReg(ZeroReg)); 145*0b57cec5SDimitry Andric } 146*0b57cec5SDimitry Andric 147*0b57cec5SDimitry Andric lowerOperand(MI->getOperand(0), MCOp); 148*0b57cec5SDimitry Andric TmpInst0.addOperand(MCOp); 149*0b57cec5SDimitry Andric 150*0b57cec5SDimitry Andric EmitToStreamer(OutStreamer, TmpInst0); 151*0b57cec5SDimitry Andric } 152*0b57cec5SDimitry Andric 153*0b57cec5SDimitry Andric // If there is an MO_JALR operand, insert: 154*0b57cec5SDimitry Andric // 155*0b57cec5SDimitry Andric // .reloc tmplabel, R_{MICRO}MIPS_JALR, symbol 156*0b57cec5SDimitry Andric // tmplabel: 157*0b57cec5SDimitry Andric // 158*0b57cec5SDimitry Andric // This is an optimization hint for the linker which may then replace 159*0b57cec5SDimitry Andric // an indirect call with a direct branch. 160*0b57cec5SDimitry Andric static void emitDirectiveRelocJalr(const MachineInstr &MI, 161*0b57cec5SDimitry Andric MCContext &OutContext, 162*0b57cec5SDimitry Andric TargetMachine &TM, 163*0b57cec5SDimitry Andric MCStreamer &OutStreamer, 164*0b57cec5SDimitry Andric const MipsSubtarget &Subtarget) { 165*0b57cec5SDimitry Andric for (unsigned int I = MI.getDesc().getNumOperands(), E = MI.getNumOperands(); 166*0b57cec5SDimitry Andric I < E; ++I) { 167*0b57cec5SDimitry Andric MachineOperand MO = MI.getOperand(I); 168*0b57cec5SDimitry Andric if (MO.isMCSymbol() && (MO.getTargetFlags() & MipsII::MO_JALR)) { 169*0b57cec5SDimitry Andric MCSymbol *Callee = MO.getMCSymbol(); 170*0b57cec5SDimitry Andric if (Callee && !Callee->getName().empty()) { 171*0b57cec5SDimitry Andric MCSymbol *OffsetLabel = OutContext.createTempSymbol(); 172*0b57cec5SDimitry Andric const MCExpr *OffsetExpr = 173*0b57cec5SDimitry Andric MCSymbolRefExpr::create(OffsetLabel, OutContext); 174*0b57cec5SDimitry Andric const MCExpr *CaleeExpr = 175*0b57cec5SDimitry Andric MCSymbolRefExpr::create(Callee, OutContext); 176*0b57cec5SDimitry Andric OutStreamer.EmitRelocDirective 177*0b57cec5SDimitry Andric (*OffsetExpr, 178*0b57cec5SDimitry Andric Subtarget.inMicroMipsMode() ? "R_MICROMIPS_JALR" : "R_MIPS_JALR", 179*0b57cec5SDimitry Andric CaleeExpr, SMLoc(), *TM.getMCSubtargetInfo()); 180*0b57cec5SDimitry Andric OutStreamer.EmitLabel(OffsetLabel); 181*0b57cec5SDimitry Andric return; 182*0b57cec5SDimitry Andric } 183*0b57cec5SDimitry Andric } 184*0b57cec5SDimitry Andric } 185*0b57cec5SDimitry Andric } 186*0b57cec5SDimitry Andric 187*0b57cec5SDimitry Andric void MipsAsmPrinter::EmitInstruction(const MachineInstr *MI) { 188*0b57cec5SDimitry Andric MipsTargetStreamer &TS = getTargetStreamer(); 189*0b57cec5SDimitry Andric unsigned Opc = MI->getOpcode(); 190*0b57cec5SDimitry Andric TS.forbidModuleDirective(); 191*0b57cec5SDimitry Andric 192*0b57cec5SDimitry Andric if (MI->isDebugValue()) { 193*0b57cec5SDimitry Andric SmallString<128> Str; 194*0b57cec5SDimitry Andric raw_svector_ostream OS(Str); 195*0b57cec5SDimitry Andric 196*0b57cec5SDimitry Andric PrintDebugValueComment(MI, OS); 197*0b57cec5SDimitry Andric return; 198*0b57cec5SDimitry Andric } 199*0b57cec5SDimitry Andric if (MI->isDebugLabel()) 200*0b57cec5SDimitry Andric return; 201*0b57cec5SDimitry Andric 202*0b57cec5SDimitry Andric // If we just ended a constant pool, mark it as such. 203*0b57cec5SDimitry Andric if (InConstantPool && Opc != Mips::CONSTPOOL_ENTRY) { 204*0b57cec5SDimitry Andric OutStreamer->EmitDataRegion(MCDR_DataRegionEnd); 205*0b57cec5SDimitry Andric InConstantPool = false; 206*0b57cec5SDimitry Andric } 207*0b57cec5SDimitry Andric if (Opc == Mips::CONSTPOOL_ENTRY) { 208*0b57cec5SDimitry Andric // CONSTPOOL_ENTRY - This instruction represents a floating 209*0b57cec5SDimitry Andric // constant pool in the function. The first operand is the ID# 210*0b57cec5SDimitry Andric // for this instruction, the second is the index into the 211*0b57cec5SDimitry Andric // MachineConstantPool that this is, the third is the size in 212*0b57cec5SDimitry Andric // bytes of this constant pool entry. 213*0b57cec5SDimitry Andric // The required alignment is specified on the basic block holding this MI. 214*0b57cec5SDimitry Andric // 215*0b57cec5SDimitry Andric unsigned LabelId = (unsigned)MI->getOperand(0).getImm(); 216*0b57cec5SDimitry Andric unsigned CPIdx = (unsigned)MI->getOperand(1).getIndex(); 217*0b57cec5SDimitry Andric 218*0b57cec5SDimitry Andric // If this is the first entry of the pool, mark it. 219*0b57cec5SDimitry Andric if (!InConstantPool) { 220*0b57cec5SDimitry Andric OutStreamer->EmitDataRegion(MCDR_DataRegion); 221*0b57cec5SDimitry Andric InConstantPool = true; 222*0b57cec5SDimitry Andric } 223*0b57cec5SDimitry Andric 224*0b57cec5SDimitry Andric OutStreamer->EmitLabel(GetCPISymbol(LabelId)); 225*0b57cec5SDimitry Andric 226*0b57cec5SDimitry Andric const MachineConstantPoolEntry &MCPE = MCP->getConstants()[CPIdx]; 227*0b57cec5SDimitry Andric if (MCPE.isMachineConstantPoolEntry()) 228*0b57cec5SDimitry Andric EmitMachineConstantPoolValue(MCPE.Val.MachineCPVal); 229*0b57cec5SDimitry Andric else 230*0b57cec5SDimitry Andric EmitGlobalConstant(MF->getDataLayout(), MCPE.Val.ConstVal); 231*0b57cec5SDimitry Andric return; 232*0b57cec5SDimitry Andric } 233*0b57cec5SDimitry Andric 234*0b57cec5SDimitry Andric switch (Opc) { 235*0b57cec5SDimitry Andric case Mips::PATCHABLE_FUNCTION_ENTER: 236*0b57cec5SDimitry Andric LowerPATCHABLE_FUNCTION_ENTER(*MI); 237*0b57cec5SDimitry Andric return; 238*0b57cec5SDimitry Andric case Mips::PATCHABLE_FUNCTION_EXIT: 239*0b57cec5SDimitry Andric LowerPATCHABLE_FUNCTION_EXIT(*MI); 240*0b57cec5SDimitry Andric return; 241*0b57cec5SDimitry Andric case Mips::PATCHABLE_TAIL_CALL: 242*0b57cec5SDimitry Andric LowerPATCHABLE_TAIL_CALL(*MI); 243*0b57cec5SDimitry Andric return; 244*0b57cec5SDimitry Andric } 245*0b57cec5SDimitry Andric 246*0b57cec5SDimitry Andric if (EmitJalrReloc && 247*0b57cec5SDimitry Andric (MI->isReturn() || MI->isCall() || MI->isIndirectBranch())) { 248*0b57cec5SDimitry Andric emitDirectiveRelocJalr(*MI, OutContext, TM, *OutStreamer, *Subtarget); 249*0b57cec5SDimitry Andric } 250*0b57cec5SDimitry Andric 251*0b57cec5SDimitry Andric MachineBasicBlock::const_instr_iterator I = MI->getIterator(); 252*0b57cec5SDimitry Andric MachineBasicBlock::const_instr_iterator E = MI->getParent()->instr_end(); 253*0b57cec5SDimitry Andric 254*0b57cec5SDimitry Andric do { 255*0b57cec5SDimitry Andric // Do any auto-generated pseudo lowerings. 256*0b57cec5SDimitry Andric if (emitPseudoExpansionLowering(*OutStreamer, &*I)) 257*0b57cec5SDimitry Andric continue; 258*0b57cec5SDimitry Andric 259*0b57cec5SDimitry Andric if (I->getOpcode() == Mips::PseudoReturn || 260*0b57cec5SDimitry Andric I->getOpcode() == Mips::PseudoReturn64 || 261*0b57cec5SDimitry Andric I->getOpcode() == Mips::PseudoIndirectBranch || 262*0b57cec5SDimitry Andric I->getOpcode() == Mips::PseudoIndirectBranch64 || 263*0b57cec5SDimitry Andric I->getOpcode() == Mips::TAILCALLREG || 264*0b57cec5SDimitry Andric I->getOpcode() == Mips::TAILCALLREG64) { 265*0b57cec5SDimitry Andric emitPseudoIndirectBranch(*OutStreamer, &*I); 266*0b57cec5SDimitry Andric continue; 267*0b57cec5SDimitry Andric } 268*0b57cec5SDimitry Andric 269*0b57cec5SDimitry Andric // The inMips16Mode() test is not permanent. 270*0b57cec5SDimitry Andric // Some instructions are marked as pseudo right now which 271*0b57cec5SDimitry Andric // would make the test fail for the wrong reason but 272*0b57cec5SDimitry Andric // that will be fixed soon. We need this here because we are 273*0b57cec5SDimitry Andric // removing another test for this situation downstream in the 274*0b57cec5SDimitry Andric // callchain. 275*0b57cec5SDimitry Andric // 276*0b57cec5SDimitry Andric if (I->isPseudo() && !Subtarget->inMips16Mode() 277*0b57cec5SDimitry Andric && !isLongBranchPseudo(I->getOpcode())) 278*0b57cec5SDimitry Andric llvm_unreachable("Pseudo opcode found in EmitInstruction()"); 279*0b57cec5SDimitry Andric 280*0b57cec5SDimitry Andric MCInst TmpInst0; 281*0b57cec5SDimitry Andric MCInstLowering.Lower(&*I, TmpInst0); 282*0b57cec5SDimitry Andric EmitToStreamer(*OutStreamer, TmpInst0); 283*0b57cec5SDimitry Andric } while ((++I != E) && I->isInsideBundle()); // Delay slot check 284*0b57cec5SDimitry Andric } 285*0b57cec5SDimitry Andric 286*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 287*0b57cec5SDimitry Andric // 288*0b57cec5SDimitry Andric // Mips Asm Directives 289*0b57cec5SDimitry Andric // 290*0b57cec5SDimitry Andric // -- Frame directive "frame Stackpointer, Stacksize, RARegister" 291*0b57cec5SDimitry Andric // Describe the stack frame. 292*0b57cec5SDimitry Andric // 293*0b57cec5SDimitry Andric // -- Mask directives "(f)mask bitmask, offset" 294*0b57cec5SDimitry Andric // Tells the assembler which registers are saved and where. 295*0b57cec5SDimitry Andric // bitmask - contain a little endian bitset indicating which registers are 296*0b57cec5SDimitry Andric // saved on function prologue (e.g. with a 0x80000000 mask, the 297*0b57cec5SDimitry Andric // assembler knows the register 31 (RA) is saved at prologue. 298*0b57cec5SDimitry Andric // offset - the position before stack pointer subtraction indicating where 299*0b57cec5SDimitry Andric // the first saved register on prologue is located. (e.g. with a 300*0b57cec5SDimitry Andric // 301*0b57cec5SDimitry Andric // Consider the following function prologue: 302*0b57cec5SDimitry Andric // 303*0b57cec5SDimitry Andric // .frame $fp,48,$ra 304*0b57cec5SDimitry Andric // .mask 0xc0000000,-8 305*0b57cec5SDimitry Andric // addiu $sp, $sp, -48 306*0b57cec5SDimitry Andric // sw $ra, 40($sp) 307*0b57cec5SDimitry Andric // sw $fp, 36($sp) 308*0b57cec5SDimitry Andric // 309*0b57cec5SDimitry Andric // With a 0xc0000000 mask, the assembler knows the register 31 (RA) and 310*0b57cec5SDimitry Andric // 30 (FP) are saved at prologue. As the save order on prologue is from 311*0b57cec5SDimitry Andric // left to right, RA is saved first. A -8 offset means that after the 312*0b57cec5SDimitry Andric // stack pointer subtration, the first register in the mask (RA) will be 313*0b57cec5SDimitry Andric // saved at address 48-8=40. 314*0b57cec5SDimitry Andric // 315*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 316*0b57cec5SDimitry Andric 317*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 318*0b57cec5SDimitry Andric // Mask directives 319*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 320*0b57cec5SDimitry Andric 321*0b57cec5SDimitry Andric // Create a bitmask with all callee saved registers for CPU or Floating Point 322*0b57cec5SDimitry Andric // registers. For CPU registers consider RA, GP and FP for saving if necessary. 323*0b57cec5SDimitry Andric void MipsAsmPrinter::printSavedRegsBitmask() { 324*0b57cec5SDimitry Andric // CPU and FPU Saved Registers Bitmasks 325*0b57cec5SDimitry Andric unsigned CPUBitmask = 0, FPUBitmask = 0; 326*0b57cec5SDimitry Andric int CPUTopSavedRegOff, FPUTopSavedRegOff; 327*0b57cec5SDimitry Andric 328*0b57cec5SDimitry Andric // Set the CPU and FPU Bitmasks 329*0b57cec5SDimitry Andric const MachineFrameInfo &MFI = MF->getFrameInfo(); 330*0b57cec5SDimitry Andric const TargetRegisterInfo *TRI = MF->getSubtarget().getRegisterInfo(); 331*0b57cec5SDimitry Andric const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo(); 332*0b57cec5SDimitry Andric // size of stack area to which FP callee-saved regs are saved. 333*0b57cec5SDimitry Andric unsigned CPURegSize = TRI->getRegSizeInBits(Mips::GPR32RegClass) / 8; 334*0b57cec5SDimitry Andric unsigned FGR32RegSize = TRI->getRegSizeInBits(Mips::FGR32RegClass) / 8; 335*0b57cec5SDimitry Andric unsigned AFGR64RegSize = TRI->getRegSizeInBits(Mips::AFGR64RegClass) / 8; 336*0b57cec5SDimitry Andric bool HasAFGR64Reg = false; 337*0b57cec5SDimitry Andric unsigned CSFPRegsSize = 0; 338*0b57cec5SDimitry Andric 339*0b57cec5SDimitry Andric for (const auto &I : CSI) { 340*0b57cec5SDimitry Andric unsigned Reg = I.getReg(); 341*0b57cec5SDimitry Andric unsigned RegNum = TRI->getEncodingValue(Reg); 342*0b57cec5SDimitry Andric 343*0b57cec5SDimitry Andric // If it's a floating point register, set the FPU Bitmask. 344*0b57cec5SDimitry Andric // If it's a general purpose register, set the CPU Bitmask. 345*0b57cec5SDimitry Andric if (Mips::FGR32RegClass.contains(Reg)) { 346*0b57cec5SDimitry Andric FPUBitmask |= (1 << RegNum); 347*0b57cec5SDimitry Andric CSFPRegsSize += FGR32RegSize; 348*0b57cec5SDimitry Andric } else if (Mips::AFGR64RegClass.contains(Reg)) { 349*0b57cec5SDimitry Andric FPUBitmask |= (3 << RegNum); 350*0b57cec5SDimitry Andric CSFPRegsSize += AFGR64RegSize; 351*0b57cec5SDimitry Andric HasAFGR64Reg = true; 352*0b57cec5SDimitry Andric } else if (Mips::GPR32RegClass.contains(Reg)) 353*0b57cec5SDimitry Andric CPUBitmask |= (1 << RegNum); 354*0b57cec5SDimitry Andric } 355*0b57cec5SDimitry Andric 356*0b57cec5SDimitry Andric // FP Regs are saved right below where the virtual frame pointer points to. 357*0b57cec5SDimitry Andric FPUTopSavedRegOff = FPUBitmask ? 358*0b57cec5SDimitry Andric (HasAFGR64Reg ? -AFGR64RegSize : -FGR32RegSize) : 0; 359*0b57cec5SDimitry Andric 360*0b57cec5SDimitry Andric // CPU Regs are saved below FP Regs. 361*0b57cec5SDimitry Andric CPUTopSavedRegOff = CPUBitmask ? -CSFPRegsSize - CPURegSize : 0; 362*0b57cec5SDimitry Andric 363*0b57cec5SDimitry Andric MipsTargetStreamer &TS = getTargetStreamer(); 364*0b57cec5SDimitry Andric // Print CPUBitmask 365*0b57cec5SDimitry Andric TS.emitMask(CPUBitmask, CPUTopSavedRegOff); 366*0b57cec5SDimitry Andric 367*0b57cec5SDimitry Andric // Print FPUBitmask 368*0b57cec5SDimitry Andric TS.emitFMask(FPUBitmask, FPUTopSavedRegOff); 369*0b57cec5SDimitry Andric } 370*0b57cec5SDimitry Andric 371*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 372*0b57cec5SDimitry Andric // Frame and Set directives 373*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 374*0b57cec5SDimitry Andric 375*0b57cec5SDimitry Andric /// Frame Directive 376*0b57cec5SDimitry Andric void MipsAsmPrinter::emitFrameDirective() { 377*0b57cec5SDimitry Andric const TargetRegisterInfo &RI = *MF->getSubtarget().getRegisterInfo(); 378*0b57cec5SDimitry Andric 379*0b57cec5SDimitry Andric unsigned stackReg = RI.getFrameRegister(*MF); 380*0b57cec5SDimitry Andric unsigned returnReg = RI.getRARegister(); 381*0b57cec5SDimitry Andric unsigned stackSize = MF->getFrameInfo().getStackSize(); 382*0b57cec5SDimitry Andric 383*0b57cec5SDimitry Andric getTargetStreamer().emitFrame(stackReg, stackSize, returnReg); 384*0b57cec5SDimitry Andric } 385*0b57cec5SDimitry Andric 386*0b57cec5SDimitry Andric /// Emit Set directives. 387*0b57cec5SDimitry Andric const char *MipsAsmPrinter::getCurrentABIString() const { 388*0b57cec5SDimitry Andric switch (static_cast<MipsTargetMachine &>(TM).getABI().GetEnumValue()) { 389*0b57cec5SDimitry Andric case MipsABIInfo::ABI::O32: return "abi32"; 390*0b57cec5SDimitry Andric case MipsABIInfo::ABI::N32: return "abiN32"; 391*0b57cec5SDimitry Andric case MipsABIInfo::ABI::N64: return "abi64"; 392*0b57cec5SDimitry Andric default: llvm_unreachable("Unknown Mips ABI"); 393*0b57cec5SDimitry Andric } 394*0b57cec5SDimitry Andric } 395*0b57cec5SDimitry Andric 396*0b57cec5SDimitry Andric void MipsAsmPrinter::EmitFunctionEntryLabel() { 397*0b57cec5SDimitry Andric MipsTargetStreamer &TS = getTargetStreamer(); 398*0b57cec5SDimitry Andric 399*0b57cec5SDimitry Andric // NaCl sandboxing requires that indirect call instructions are masked. 400*0b57cec5SDimitry Andric // This means that function entry points should be bundle-aligned. 401*0b57cec5SDimitry Andric if (Subtarget->isTargetNaCl()) 402*0b57cec5SDimitry Andric EmitAlignment(std::max(MF->getAlignment(), MIPS_NACL_BUNDLE_ALIGN)); 403*0b57cec5SDimitry Andric 404*0b57cec5SDimitry Andric if (Subtarget->inMicroMipsMode()) { 405*0b57cec5SDimitry Andric TS.emitDirectiveSetMicroMips(); 406*0b57cec5SDimitry Andric TS.setUsesMicroMips(); 407*0b57cec5SDimitry Andric TS.updateABIInfo(*Subtarget); 408*0b57cec5SDimitry Andric } else 409*0b57cec5SDimitry Andric TS.emitDirectiveSetNoMicroMips(); 410*0b57cec5SDimitry Andric 411*0b57cec5SDimitry Andric if (Subtarget->inMips16Mode()) 412*0b57cec5SDimitry Andric TS.emitDirectiveSetMips16(); 413*0b57cec5SDimitry Andric else 414*0b57cec5SDimitry Andric TS.emitDirectiveSetNoMips16(); 415*0b57cec5SDimitry Andric 416*0b57cec5SDimitry Andric TS.emitDirectiveEnt(*CurrentFnSym); 417*0b57cec5SDimitry Andric OutStreamer->EmitLabel(CurrentFnSym); 418*0b57cec5SDimitry Andric } 419*0b57cec5SDimitry Andric 420*0b57cec5SDimitry Andric /// EmitFunctionBodyStart - Targets can override this to emit stuff before 421*0b57cec5SDimitry Andric /// the first basic block in the function. 422*0b57cec5SDimitry Andric void MipsAsmPrinter::EmitFunctionBodyStart() { 423*0b57cec5SDimitry Andric MipsTargetStreamer &TS = getTargetStreamer(); 424*0b57cec5SDimitry Andric 425*0b57cec5SDimitry Andric MCInstLowering.Initialize(&MF->getContext()); 426*0b57cec5SDimitry Andric 427*0b57cec5SDimitry Andric bool IsNakedFunction = MF->getFunction().hasFnAttribute(Attribute::Naked); 428*0b57cec5SDimitry Andric if (!IsNakedFunction) 429*0b57cec5SDimitry Andric emitFrameDirective(); 430*0b57cec5SDimitry Andric 431*0b57cec5SDimitry Andric if (!IsNakedFunction) 432*0b57cec5SDimitry Andric printSavedRegsBitmask(); 433*0b57cec5SDimitry Andric 434*0b57cec5SDimitry Andric if (!Subtarget->inMips16Mode()) { 435*0b57cec5SDimitry Andric TS.emitDirectiveSetNoReorder(); 436*0b57cec5SDimitry Andric TS.emitDirectiveSetNoMacro(); 437*0b57cec5SDimitry Andric TS.emitDirectiveSetNoAt(); 438*0b57cec5SDimitry Andric } 439*0b57cec5SDimitry Andric } 440*0b57cec5SDimitry Andric 441*0b57cec5SDimitry Andric /// EmitFunctionBodyEnd - Targets can override this to emit stuff after 442*0b57cec5SDimitry Andric /// the last basic block in the function. 443*0b57cec5SDimitry Andric void MipsAsmPrinter::EmitFunctionBodyEnd() { 444*0b57cec5SDimitry Andric MipsTargetStreamer &TS = getTargetStreamer(); 445*0b57cec5SDimitry Andric 446*0b57cec5SDimitry Andric // There are instruction for this macros, but they must 447*0b57cec5SDimitry Andric // always be at the function end, and we can't emit and 448*0b57cec5SDimitry Andric // break with BB logic. 449*0b57cec5SDimitry Andric if (!Subtarget->inMips16Mode()) { 450*0b57cec5SDimitry Andric TS.emitDirectiveSetAt(); 451*0b57cec5SDimitry Andric TS.emitDirectiveSetMacro(); 452*0b57cec5SDimitry Andric TS.emitDirectiveSetReorder(); 453*0b57cec5SDimitry Andric } 454*0b57cec5SDimitry Andric TS.emitDirectiveEnd(CurrentFnSym->getName()); 455*0b57cec5SDimitry Andric // Make sure to terminate any constant pools that were at the end 456*0b57cec5SDimitry Andric // of the function. 457*0b57cec5SDimitry Andric if (!InConstantPool) 458*0b57cec5SDimitry Andric return; 459*0b57cec5SDimitry Andric InConstantPool = false; 460*0b57cec5SDimitry Andric OutStreamer->EmitDataRegion(MCDR_DataRegionEnd); 461*0b57cec5SDimitry Andric } 462*0b57cec5SDimitry Andric 463*0b57cec5SDimitry Andric void MipsAsmPrinter::EmitBasicBlockEnd(const MachineBasicBlock &MBB) { 464*0b57cec5SDimitry Andric AsmPrinter::EmitBasicBlockEnd(MBB); 465*0b57cec5SDimitry Andric MipsTargetStreamer &TS = getTargetStreamer(); 466*0b57cec5SDimitry Andric if (MBB.empty()) 467*0b57cec5SDimitry Andric TS.emitDirectiveInsn(); 468*0b57cec5SDimitry Andric } 469*0b57cec5SDimitry Andric 470*0b57cec5SDimitry Andric /// isBlockOnlyReachableByFallthough - Return true if the basic block has 471*0b57cec5SDimitry Andric /// exactly one predecessor and the control transfer mechanism between 472*0b57cec5SDimitry Andric /// the predecessor and this block is a fall-through. 473*0b57cec5SDimitry Andric bool MipsAsmPrinter::isBlockOnlyReachableByFallthrough(const MachineBasicBlock* 474*0b57cec5SDimitry Andric MBB) const { 475*0b57cec5SDimitry Andric // The predecessor has to be immediately before this block. 476*0b57cec5SDimitry Andric const MachineBasicBlock *Pred = *MBB->pred_begin(); 477*0b57cec5SDimitry Andric 478*0b57cec5SDimitry Andric // If the predecessor is a switch statement, assume a jump table 479*0b57cec5SDimitry Andric // implementation, so it is not a fall through. 480*0b57cec5SDimitry Andric if (const BasicBlock *bb = Pred->getBasicBlock()) 481*0b57cec5SDimitry Andric if (isa<SwitchInst>(bb->getTerminator())) 482*0b57cec5SDimitry Andric return false; 483*0b57cec5SDimitry Andric 484*0b57cec5SDimitry Andric // If this is a landing pad, it isn't a fall through. If it has no preds, 485*0b57cec5SDimitry Andric // then nothing falls through to it. 486*0b57cec5SDimitry Andric if (MBB->isEHPad() || MBB->pred_empty()) 487*0b57cec5SDimitry Andric return false; 488*0b57cec5SDimitry Andric 489*0b57cec5SDimitry Andric // If there isn't exactly one predecessor, it can't be a fall through. 490*0b57cec5SDimitry Andric MachineBasicBlock::const_pred_iterator PI = MBB->pred_begin(), PI2 = PI; 491*0b57cec5SDimitry Andric ++PI2; 492*0b57cec5SDimitry Andric 493*0b57cec5SDimitry Andric if (PI2 != MBB->pred_end()) 494*0b57cec5SDimitry Andric return false; 495*0b57cec5SDimitry Andric 496*0b57cec5SDimitry Andric // The predecessor has to be immediately before this block. 497*0b57cec5SDimitry Andric if (!Pred->isLayoutSuccessor(MBB)) 498*0b57cec5SDimitry Andric return false; 499*0b57cec5SDimitry Andric 500*0b57cec5SDimitry Andric // If the block is completely empty, then it definitely does fall through. 501*0b57cec5SDimitry Andric if (Pred->empty()) 502*0b57cec5SDimitry Andric return true; 503*0b57cec5SDimitry Andric 504*0b57cec5SDimitry Andric // Otherwise, check the last instruction. 505*0b57cec5SDimitry Andric // Check if the last terminator is an unconditional branch. 506*0b57cec5SDimitry Andric MachineBasicBlock::const_iterator I = Pred->end(); 507*0b57cec5SDimitry Andric while (I != Pred->begin() && !(--I)->isTerminator()) ; 508*0b57cec5SDimitry Andric 509*0b57cec5SDimitry Andric return !I->isBarrier(); 510*0b57cec5SDimitry Andric } 511*0b57cec5SDimitry Andric 512*0b57cec5SDimitry Andric // Print out an operand for an inline asm expression. 513*0b57cec5SDimitry Andric bool MipsAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNum, 514*0b57cec5SDimitry Andric const char *ExtraCode, raw_ostream &O) { 515*0b57cec5SDimitry Andric // Does this asm operand have a single letter operand modifier? 516*0b57cec5SDimitry Andric if (ExtraCode && ExtraCode[0]) { 517*0b57cec5SDimitry Andric if (ExtraCode[1] != 0) return true; // Unknown modifier. 518*0b57cec5SDimitry Andric 519*0b57cec5SDimitry Andric const MachineOperand &MO = MI->getOperand(OpNum); 520*0b57cec5SDimitry Andric switch (ExtraCode[0]) { 521*0b57cec5SDimitry Andric default: 522*0b57cec5SDimitry Andric // See if this is a generic print operand 523*0b57cec5SDimitry Andric return AsmPrinter::PrintAsmOperand(MI, OpNum, ExtraCode, O); 524*0b57cec5SDimitry Andric case 'X': // hex const int 525*0b57cec5SDimitry Andric if ((MO.getType()) != MachineOperand::MO_Immediate) 526*0b57cec5SDimitry Andric return true; 527*0b57cec5SDimitry Andric O << "0x" << Twine::utohexstr(MO.getImm()); 528*0b57cec5SDimitry Andric return false; 529*0b57cec5SDimitry Andric case 'x': // hex const int (low 16 bits) 530*0b57cec5SDimitry Andric if ((MO.getType()) != MachineOperand::MO_Immediate) 531*0b57cec5SDimitry Andric return true; 532*0b57cec5SDimitry Andric O << "0x" << Twine::utohexstr(MO.getImm() & 0xffff); 533*0b57cec5SDimitry Andric return false; 534*0b57cec5SDimitry Andric case 'd': // decimal const int 535*0b57cec5SDimitry Andric if ((MO.getType()) != MachineOperand::MO_Immediate) 536*0b57cec5SDimitry Andric return true; 537*0b57cec5SDimitry Andric O << MO.getImm(); 538*0b57cec5SDimitry Andric return false; 539*0b57cec5SDimitry Andric case 'm': // decimal const int minus 1 540*0b57cec5SDimitry Andric if ((MO.getType()) != MachineOperand::MO_Immediate) 541*0b57cec5SDimitry Andric return true; 542*0b57cec5SDimitry Andric O << MO.getImm() - 1; 543*0b57cec5SDimitry Andric return false; 544*0b57cec5SDimitry Andric case 'y': // exact log2 545*0b57cec5SDimitry Andric if ((MO.getType()) != MachineOperand::MO_Immediate) 546*0b57cec5SDimitry Andric return true; 547*0b57cec5SDimitry Andric if (!isPowerOf2_64(MO.getImm())) 548*0b57cec5SDimitry Andric return true; 549*0b57cec5SDimitry Andric O << Log2_64(MO.getImm()); 550*0b57cec5SDimitry Andric return false; 551*0b57cec5SDimitry Andric case 'z': 552*0b57cec5SDimitry Andric // $0 if zero, regular printing otherwise 553*0b57cec5SDimitry Andric if (MO.getType() == MachineOperand::MO_Immediate && MO.getImm() == 0) { 554*0b57cec5SDimitry Andric O << "$0"; 555*0b57cec5SDimitry Andric return false; 556*0b57cec5SDimitry Andric } 557*0b57cec5SDimitry Andric // If not, call printOperand as normal. 558*0b57cec5SDimitry Andric break; 559*0b57cec5SDimitry Andric case 'D': // Second part of a double word register operand 560*0b57cec5SDimitry Andric case 'L': // Low order register of a double word register operand 561*0b57cec5SDimitry Andric case 'M': // High order register of a double word register operand 562*0b57cec5SDimitry Andric { 563*0b57cec5SDimitry Andric if (OpNum == 0) 564*0b57cec5SDimitry Andric return true; 565*0b57cec5SDimitry Andric const MachineOperand &FlagsOP = MI->getOperand(OpNum - 1); 566*0b57cec5SDimitry Andric if (!FlagsOP.isImm()) 567*0b57cec5SDimitry Andric return true; 568*0b57cec5SDimitry Andric unsigned Flags = FlagsOP.getImm(); 569*0b57cec5SDimitry Andric unsigned NumVals = InlineAsm::getNumOperandRegisters(Flags); 570*0b57cec5SDimitry Andric // Number of registers represented by this operand. We are looking 571*0b57cec5SDimitry Andric // for 2 for 32 bit mode and 1 for 64 bit mode. 572*0b57cec5SDimitry Andric if (NumVals != 2) { 573*0b57cec5SDimitry Andric if (Subtarget->isGP64bit() && NumVals == 1 && MO.isReg()) { 574*0b57cec5SDimitry Andric unsigned Reg = MO.getReg(); 575*0b57cec5SDimitry Andric O << '$' << MipsInstPrinter::getRegisterName(Reg); 576*0b57cec5SDimitry Andric return false; 577*0b57cec5SDimitry Andric } 578*0b57cec5SDimitry Andric return true; 579*0b57cec5SDimitry Andric } 580*0b57cec5SDimitry Andric 581*0b57cec5SDimitry Andric unsigned RegOp = OpNum; 582*0b57cec5SDimitry Andric if (!Subtarget->isGP64bit()){ 583*0b57cec5SDimitry Andric // Endianness reverses which register holds the high or low value 584*0b57cec5SDimitry Andric // between M and L. 585*0b57cec5SDimitry Andric switch(ExtraCode[0]) { 586*0b57cec5SDimitry Andric case 'M': 587*0b57cec5SDimitry Andric RegOp = (Subtarget->isLittle()) ? OpNum + 1 : OpNum; 588*0b57cec5SDimitry Andric break; 589*0b57cec5SDimitry Andric case 'L': 590*0b57cec5SDimitry Andric RegOp = (Subtarget->isLittle()) ? OpNum : OpNum + 1; 591*0b57cec5SDimitry Andric break; 592*0b57cec5SDimitry Andric case 'D': // Always the second part 593*0b57cec5SDimitry Andric RegOp = OpNum + 1; 594*0b57cec5SDimitry Andric } 595*0b57cec5SDimitry Andric if (RegOp >= MI->getNumOperands()) 596*0b57cec5SDimitry Andric return true; 597*0b57cec5SDimitry Andric const MachineOperand &MO = MI->getOperand(RegOp); 598*0b57cec5SDimitry Andric if (!MO.isReg()) 599*0b57cec5SDimitry Andric return true; 600*0b57cec5SDimitry Andric unsigned Reg = MO.getReg(); 601*0b57cec5SDimitry Andric O << '$' << MipsInstPrinter::getRegisterName(Reg); 602*0b57cec5SDimitry Andric return false; 603*0b57cec5SDimitry Andric } 604*0b57cec5SDimitry Andric break; 605*0b57cec5SDimitry Andric } 606*0b57cec5SDimitry Andric case 'w': 607*0b57cec5SDimitry Andric // Print MSA registers for the 'f' constraint 608*0b57cec5SDimitry Andric // In LLVM, the 'w' modifier doesn't need to do anything. 609*0b57cec5SDimitry Andric // We can just call printOperand as normal. 610*0b57cec5SDimitry Andric break; 611*0b57cec5SDimitry Andric } 612*0b57cec5SDimitry Andric } 613*0b57cec5SDimitry Andric 614*0b57cec5SDimitry Andric printOperand(MI, OpNum, O); 615*0b57cec5SDimitry Andric return false; 616*0b57cec5SDimitry Andric } 617*0b57cec5SDimitry Andric 618*0b57cec5SDimitry Andric bool MipsAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, 619*0b57cec5SDimitry Andric unsigned OpNum, 620*0b57cec5SDimitry Andric const char *ExtraCode, 621*0b57cec5SDimitry Andric raw_ostream &O) { 622*0b57cec5SDimitry Andric assert(OpNum + 1 < MI->getNumOperands() && "Insufficient operands"); 623*0b57cec5SDimitry Andric const MachineOperand &BaseMO = MI->getOperand(OpNum); 624*0b57cec5SDimitry Andric const MachineOperand &OffsetMO = MI->getOperand(OpNum + 1); 625*0b57cec5SDimitry Andric assert(BaseMO.isReg() && "Unexpected base pointer for inline asm memory operand."); 626*0b57cec5SDimitry Andric assert(OffsetMO.isImm() && "Unexpected offset for inline asm memory operand."); 627*0b57cec5SDimitry Andric int Offset = OffsetMO.getImm(); 628*0b57cec5SDimitry Andric 629*0b57cec5SDimitry Andric // Currently we are expecting either no ExtraCode or 'D','M','L'. 630*0b57cec5SDimitry Andric if (ExtraCode) { 631*0b57cec5SDimitry Andric switch (ExtraCode[0]) { 632*0b57cec5SDimitry Andric case 'D': 633*0b57cec5SDimitry Andric Offset += 4; 634*0b57cec5SDimitry Andric break; 635*0b57cec5SDimitry Andric case 'M': 636*0b57cec5SDimitry Andric if (Subtarget->isLittle()) 637*0b57cec5SDimitry Andric Offset += 4; 638*0b57cec5SDimitry Andric break; 639*0b57cec5SDimitry Andric case 'L': 640*0b57cec5SDimitry Andric if (!Subtarget->isLittle()) 641*0b57cec5SDimitry Andric Offset += 4; 642*0b57cec5SDimitry Andric break; 643*0b57cec5SDimitry Andric default: 644*0b57cec5SDimitry Andric return true; // Unknown modifier. 645*0b57cec5SDimitry Andric } 646*0b57cec5SDimitry Andric } 647*0b57cec5SDimitry Andric 648*0b57cec5SDimitry Andric O << Offset << "($" << MipsInstPrinter::getRegisterName(BaseMO.getReg()) 649*0b57cec5SDimitry Andric << ")"; 650*0b57cec5SDimitry Andric 651*0b57cec5SDimitry Andric return false; 652*0b57cec5SDimitry Andric } 653*0b57cec5SDimitry Andric 654*0b57cec5SDimitry Andric void MipsAsmPrinter::printOperand(const MachineInstr *MI, int opNum, 655*0b57cec5SDimitry Andric raw_ostream &O) { 656*0b57cec5SDimitry Andric const MachineOperand &MO = MI->getOperand(opNum); 657*0b57cec5SDimitry Andric bool closeP = false; 658*0b57cec5SDimitry Andric 659*0b57cec5SDimitry Andric if (MO.getTargetFlags()) 660*0b57cec5SDimitry Andric closeP = true; 661*0b57cec5SDimitry Andric 662*0b57cec5SDimitry Andric switch(MO.getTargetFlags()) { 663*0b57cec5SDimitry Andric case MipsII::MO_GPREL: O << "%gp_rel("; break; 664*0b57cec5SDimitry Andric case MipsII::MO_GOT_CALL: O << "%call16("; break; 665*0b57cec5SDimitry Andric case MipsII::MO_GOT: O << "%got("; break; 666*0b57cec5SDimitry Andric case MipsII::MO_ABS_HI: O << "%hi("; break; 667*0b57cec5SDimitry Andric case MipsII::MO_ABS_LO: O << "%lo("; break; 668*0b57cec5SDimitry Andric case MipsII::MO_HIGHER: O << "%higher("; break; 669*0b57cec5SDimitry Andric case MipsII::MO_HIGHEST: O << "%highest(("; break; 670*0b57cec5SDimitry Andric case MipsII::MO_TLSGD: O << "%tlsgd("; break; 671*0b57cec5SDimitry Andric case MipsII::MO_GOTTPREL: O << "%gottprel("; break; 672*0b57cec5SDimitry Andric case MipsII::MO_TPREL_HI: O << "%tprel_hi("; break; 673*0b57cec5SDimitry Andric case MipsII::MO_TPREL_LO: O << "%tprel_lo("; break; 674*0b57cec5SDimitry Andric case MipsII::MO_GPOFF_HI: O << "%hi(%neg(%gp_rel("; break; 675*0b57cec5SDimitry Andric case MipsII::MO_GPOFF_LO: O << "%lo(%neg(%gp_rel("; break; 676*0b57cec5SDimitry Andric case MipsII::MO_GOT_DISP: O << "%got_disp("; break; 677*0b57cec5SDimitry Andric case MipsII::MO_GOT_PAGE: O << "%got_page("; break; 678*0b57cec5SDimitry Andric case MipsII::MO_GOT_OFST: O << "%got_ofst("; break; 679*0b57cec5SDimitry Andric } 680*0b57cec5SDimitry Andric 681*0b57cec5SDimitry Andric switch (MO.getType()) { 682*0b57cec5SDimitry Andric case MachineOperand::MO_Register: 683*0b57cec5SDimitry Andric O << '$' 684*0b57cec5SDimitry Andric << StringRef(MipsInstPrinter::getRegisterName(MO.getReg())).lower(); 685*0b57cec5SDimitry Andric break; 686*0b57cec5SDimitry Andric 687*0b57cec5SDimitry Andric case MachineOperand::MO_Immediate: 688*0b57cec5SDimitry Andric O << MO.getImm(); 689*0b57cec5SDimitry Andric break; 690*0b57cec5SDimitry Andric 691*0b57cec5SDimitry Andric case MachineOperand::MO_MachineBasicBlock: 692*0b57cec5SDimitry Andric MO.getMBB()->getSymbol()->print(O, MAI); 693*0b57cec5SDimitry Andric return; 694*0b57cec5SDimitry Andric 695*0b57cec5SDimitry Andric case MachineOperand::MO_GlobalAddress: 696*0b57cec5SDimitry Andric PrintSymbolOperand(MO, O); 697*0b57cec5SDimitry Andric break; 698*0b57cec5SDimitry Andric 699*0b57cec5SDimitry Andric case MachineOperand::MO_BlockAddress: { 700*0b57cec5SDimitry Andric MCSymbol *BA = GetBlockAddressSymbol(MO.getBlockAddress()); 701*0b57cec5SDimitry Andric O << BA->getName(); 702*0b57cec5SDimitry Andric break; 703*0b57cec5SDimitry Andric } 704*0b57cec5SDimitry Andric 705*0b57cec5SDimitry Andric case MachineOperand::MO_ConstantPoolIndex: 706*0b57cec5SDimitry Andric O << getDataLayout().getPrivateGlobalPrefix() << "CPI" 707*0b57cec5SDimitry Andric << getFunctionNumber() << "_" << MO.getIndex(); 708*0b57cec5SDimitry Andric if (MO.getOffset()) 709*0b57cec5SDimitry Andric O << "+" << MO.getOffset(); 710*0b57cec5SDimitry Andric break; 711*0b57cec5SDimitry Andric 712*0b57cec5SDimitry Andric default: 713*0b57cec5SDimitry Andric llvm_unreachable("<unknown operand type>"); 714*0b57cec5SDimitry Andric } 715*0b57cec5SDimitry Andric 716*0b57cec5SDimitry Andric if (closeP) O << ")"; 717*0b57cec5SDimitry Andric } 718*0b57cec5SDimitry Andric 719*0b57cec5SDimitry Andric void MipsAsmPrinter:: 720*0b57cec5SDimitry Andric printMemOperand(const MachineInstr *MI, int opNum, raw_ostream &O) { 721*0b57cec5SDimitry Andric // Load/Store memory operands -- imm($reg) 722*0b57cec5SDimitry Andric // If PIC target the target is loaded as the 723*0b57cec5SDimitry Andric // pattern lw $25,%call16($28) 724*0b57cec5SDimitry Andric 725*0b57cec5SDimitry Andric // opNum can be invalid if instruction has reglist as operand. 726*0b57cec5SDimitry Andric // MemOperand is always last operand of instruction (base + offset). 727*0b57cec5SDimitry Andric switch (MI->getOpcode()) { 728*0b57cec5SDimitry Andric default: 729*0b57cec5SDimitry Andric break; 730*0b57cec5SDimitry Andric case Mips::SWM32_MM: 731*0b57cec5SDimitry Andric case Mips::LWM32_MM: 732*0b57cec5SDimitry Andric opNum = MI->getNumOperands() - 2; 733*0b57cec5SDimitry Andric break; 734*0b57cec5SDimitry Andric } 735*0b57cec5SDimitry Andric 736*0b57cec5SDimitry Andric printOperand(MI, opNum+1, O); 737*0b57cec5SDimitry Andric O << "("; 738*0b57cec5SDimitry Andric printOperand(MI, opNum, O); 739*0b57cec5SDimitry Andric O << ")"; 740*0b57cec5SDimitry Andric } 741*0b57cec5SDimitry Andric 742*0b57cec5SDimitry Andric void MipsAsmPrinter:: 743*0b57cec5SDimitry Andric printMemOperandEA(const MachineInstr *MI, int opNum, raw_ostream &O) { 744*0b57cec5SDimitry Andric // when using stack locations for not load/store instructions 745*0b57cec5SDimitry Andric // print the same way as all normal 3 operand instructions. 746*0b57cec5SDimitry Andric printOperand(MI, opNum, O); 747*0b57cec5SDimitry Andric O << ", "; 748*0b57cec5SDimitry Andric printOperand(MI, opNum+1, O); 749*0b57cec5SDimitry Andric } 750*0b57cec5SDimitry Andric 751*0b57cec5SDimitry Andric void MipsAsmPrinter:: 752*0b57cec5SDimitry Andric printFCCOperand(const MachineInstr *MI, int opNum, raw_ostream &O, 753*0b57cec5SDimitry Andric const char *Modifier) { 754*0b57cec5SDimitry Andric const MachineOperand &MO = MI->getOperand(opNum); 755*0b57cec5SDimitry Andric O << Mips::MipsFCCToString((Mips::CondCode)MO.getImm()); 756*0b57cec5SDimitry Andric } 757*0b57cec5SDimitry Andric 758*0b57cec5SDimitry Andric void MipsAsmPrinter:: 759*0b57cec5SDimitry Andric printRegisterList(const MachineInstr *MI, int opNum, raw_ostream &O) { 760*0b57cec5SDimitry Andric for (int i = opNum, e = MI->getNumOperands(); i != e; ++i) { 761*0b57cec5SDimitry Andric if (i != opNum) O << ", "; 762*0b57cec5SDimitry Andric printOperand(MI, i, O); 763*0b57cec5SDimitry Andric } 764*0b57cec5SDimitry Andric } 765*0b57cec5SDimitry Andric 766*0b57cec5SDimitry Andric void MipsAsmPrinter::EmitStartOfAsmFile(Module &M) { 767*0b57cec5SDimitry Andric MipsTargetStreamer &TS = getTargetStreamer(); 768*0b57cec5SDimitry Andric 769*0b57cec5SDimitry Andric // MipsTargetStreamer has an initialization order problem when emitting an 770*0b57cec5SDimitry Andric // object file directly (see MipsTargetELFStreamer for full details). Work 771*0b57cec5SDimitry Andric // around it by re-initializing the PIC state here. 772*0b57cec5SDimitry Andric TS.setPic(OutContext.getObjectFileInfo()->isPositionIndependent()); 773*0b57cec5SDimitry Andric 774*0b57cec5SDimitry Andric // Compute MIPS architecture attributes based on the default subtarget 775*0b57cec5SDimitry Andric // that we'd have constructed. Module level directives aren't LTO 776*0b57cec5SDimitry Andric // clean anyhow. 777*0b57cec5SDimitry Andric // FIXME: For ifunc related functions we could iterate over and look 778*0b57cec5SDimitry Andric // for a feature string that doesn't match the default one. 779*0b57cec5SDimitry Andric const Triple &TT = TM.getTargetTriple(); 780*0b57cec5SDimitry Andric StringRef CPU = MIPS_MC::selectMipsCPU(TT, TM.getTargetCPU()); 781*0b57cec5SDimitry Andric StringRef FS = TM.getTargetFeatureString(); 782*0b57cec5SDimitry Andric const MipsTargetMachine &MTM = static_cast<const MipsTargetMachine &>(TM); 783*0b57cec5SDimitry Andric const MipsSubtarget STI(TT, CPU, FS, MTM.isLittleEndian(), MTM, 0); 784*0b57cec5SDimitry Andric 785*0b57cec5SDimitry Andric bool IsABICalls = STI.isABICalls(); 786*0b57cec5SDimitry Andric const MipsABIInfo &ABI = MTM.getABI(); 787*0b57cec5SDimitry Andric if (IsABICalls) { 788*0b57cec5SDimitry Andric TS.emitDirectiveAbiCalls(); 789*0b57cec5SDimitry Andric // FIXME: This condition should be a lot more complicated that it is here. 790*0b57cec5SDimitry Andric // Ideally it should test for properties of the ABI and not the ABI 791*0b57cec5SDimitry Andric // itself. 792*0b57cec5SDimitry Andric // For the moment, I'm only correcting enough to make MIPS-IV work. 793*0b57cec5SDimitry Andric if (!isPositionIndependent() && STI.hasSym32()) 794*0b57cec5SDimitry Andric TS.emitDirectiveOptionPic0(); 795*0b57cec5SDimitry Andric } 796*0b57cec5SDimitry Andric 797*0b57cec5SDimitry Andric // Tell the assembler which ABI we are using 798*0b57cec5SDimitry Andric std::string SectionName = std::string(".mdebug.") + getCurrentABIString(); 799*0b57cec5SDimitry Andric OutStreamer->SwitchSection( 800*0b57cec5SDimitry Andric OutContext.getELFSection(SectionName, ELF::SHT_PROGBITS, 0)); 801*0b57cec5SDimitry Andric 802*0b57cec5SDimitry Andric // NaN: At the moment we only support: 803*0b57cec5SDimitry Andric // 1. .nan legacy (default) 804*0b57cec5SDimitry Andric // 2. .nan 2008 805*0b57cec5SDimitry Andric STI.isNaN2008() ? TS.emitDirectiveNaN2008() 806*0b57cec5SDimitry Andric : TS.emitDirectiveNaNLegacy(); 807*0b57cec5SDimitry Andric 808*0b57cec5SDimitry Andric // TODO: handle O64 ABI 809*0b57cec5SDimitry Andric 810*0b57cec5SDimitry Andric TS.updateABIInfo(STI); 811*0b57cec5SDimitry Andric 812*0b57cec5SDimitry Andric // We should always emit a '.module fp=...' but binutils 2.24 does not accept 813*0b57cec5SDimitry Andric // it. We therefore emit it when it contradicts the ABI defaults (-mfpxx or 814*0b57cec5SDimitry Andric // -mfp64) and omit it otherwise. 815*0b57cec5SDimitry Andric if ((ABI.IsO32() && (STI.isABI_FPXX() || STI.isFP64bit())) || 816*0b57cec5SDimitry Andric STI.useSoftFloat()) 817*0b57cec5SDimitry Andric TS.emitDirectiveModuleFP(); 818*0b57cec5SDimitry Andric 819*0b57cec5SDimitry Andric // We should always emit a '.module [no]oddspreg' but binutils 2.24 does not 820*0b57cec5SDimitry Andric // accept it. We therefore emit it when it contradicts the default or an 821*0b57cec5SDimitry Andric // option has changed the default (i.e. FPXX) and omit it otherwise. 822*0b57cec5SDimitry Andric if (ABI.IsO32() && (!STI.useOddSPReg() || STI.isABI_FPXX())) 823*0b57cec5SDimitry Andric TS.emitDirectiveModuleOddSPReg(); 824*0b57cec5SDimitry Andric } 825*0b57cec5SDimitry Andric 826*0b57cec5SDimitry Andric void MipsAsmPrinter::emitInlineAsmStart() const { 827*0b57cec5SDimitry Andric MipsTargetStreamer &TS = getTargetStreamer(); 828*0b57cec5SDimitry Andric 829*0b57cec5SDimitry Andric // GCC's choice of assembler options for inline assembly code ('at', 'macro' 830*0b57cec5SDimitry Andric // and 'reorder') is different from LLVM's choice for generated code ('noat', 831*0b57cec5SDimitry Andric // 'nomacro' and 'noreorder'). 832*0b57cec5SDimitry Andric // In order to maintain compatibility with inline assembly code which depends 833*0b57cec5SDimitry Andric // on GCC's assembler options being used, we have to switch to those options 834*0b57cec5SDimitry Andric // for the duration of the inline assembly block and then switch back. 835*0b57cec5SDimitry Andric TS.emitDirectiveSetPush(); 836*0b57cec5SDimitry Andric TS.emitDirectiveSetAt(); 837*0b57cec5SDimitry Andric TS.emitDirectiveSetMacro(); 838*0b57cec5SDimitry Andric TS.emitDirectiveSetReorder(); 839*0b57cec5SDimitry Andric OutStreamer->AddBlankLine(); 840*0b57cec5SDimitry Andric } 841*0b57cec5SDimitry Andric 842*0b57cec5SDimitry Andric void MipsAsmPrinter::emitInlineAsmEnd(const MCSubtargetInfo &StartInfo, 843*0b57cec5SDimitry Andric const MCSubtargetInfo *EndInfo) const { 844*0b57cec5SDimitry Andric OutStreamer->AddBlankLine(); 845*0b57cec5SDimitry Andric getTargetStreamer().emitDirectiveSetPop(); 846*0b57cec5SDimitry Andric } 847*0b57cec5SDimitry Andric 848*0b57cec5SDimitry Andric void MipsAsmPrinter::EmitJal(const MCSubtargetInfo &STI, MCSymbol *Symbol) { 849*0b57cec5SDimitry Andric MCInst I; 850*0b57cec5SDimitry Andric I.setOpcode(Mips::JAL); 851*0b57cec5SDimitry Andric I.addOperand( 852*0b57cec5SDimitry Andric MCOperand::createExpr(MCSymbolRefExpr::create(Symbol, OutContext))); 853*0b57cec5SDimitry Andric OutStreamer->EmitInstruction(I, STI); 854*0b57cec5SDimitry Andric } 855*0b57cec5SDimitry Andric 856*0b57cec5SDimitry Andric void MipsAsmPrinter::EmitInstrReg(const MCSubtargetInfo &STI, unsigned Opcode, 857*0b57cec5SDimitry Andric unsigned Reg) { 858*0b57cec5SDimitry Andric MCInst I; 859*0b57cec5SDimitry Andric I.setOpcode(Opcode); 860*0b57cec5SDimitry Andric I.addOperand(MCOperand::createReg(Reg)); 861*0b57cec5SDimitry Andric OutStreamer->EmitInstruction(I, STI); 862*0b57cec5SDimitry Andric } 863*0b57cec5SDimitry Andric 864*0b57cec5SDimitry Andric void MipsAsmPrinter::EmitInstrRegReg(const MCSubtargetInfo &STI, 865*0b57cec5SDimitry Andric unsigned Opcode, unsigned Reg1, 866*0b57cec5SDimitry Andric unsigned Reg2) { 867*0b57cec5SDimitry Andric MCInst I; 868*0b57cec5SDimitry Andric // 869*0b57cec5SDimitry Andric // Because of the current td files for Mips32, the operands for MTC1 870*0b57cec5SDimitry Andric // appear backwards from their normal assembly order. It's not a trivial 871*0b57cec5SDimitry Andric // change to fix this in the td file so we adjust for it here. 872*0b57cec5SDimitry Andric // 873*0b57cec5SDimitry Andric if (Opcode == Mips::MTC1) { 874*0b57cec5SDimitry Andric unsigned Temp = Reg1; 875*0b57cec5SDimitry Andric Reg1 = Reg2; 876*0b57cec5SDimitry Andric Reg2 = Temp; 877*0b57cec5SDimitry Andric } 878*0b57cec5SDimitry Andric I.setOpcode(Opcode); 879*0b57cec5SDimitry Andric I.addOperand(MCOperand::createReg(Reg1)); 880*0b57cec5SDimitry Andric I.addOperand(MCOperand::createReg(Reg2)); 881*0b57cec5SDimitry Andric OutStreamer->EmitInstruction(I, STI); 882*0b57cec5SDimitry Andric } 883*0b57cec5SDimitry Andric 884*0b57cec5SDimitry Andric void MipsAsmPrinter::EmitInstrRegRegReg(const MCSubtargetInfo &STI, 885*0b57cec5SDimitry Andric unsigned Opcode, unsigned Reg1, 886*0b57cec5SDimitry Andric unsigned Reg2, unsigned Reg3) { 887*0b57cec5SDimitry Andric MCInst I; 888*0b57cec5SDimitry Andric I.setOpcode(Opcode); 889*0b57cec5SDimitry Andric I.addOperand(MCOperand::createReg(Reg1)); 890*0b57cec5SDimitry Andric I.addOperand(MCOperand::createReg(Reg2)); 891*0b57cec5SDimitry Andric I.addOperand(MCOperand::createReg(Reg3)); 892*0b57cec5SDimitry Andric OutStreamer->EmitInstruction(I, STI); 893*0b57cec5SDimitry Andric } 894*0b57cec5SDimitry Andric 895*0b57cec5SDimitry Andric void MipsAsmPrinter::EmitMovFPIntPair(const MCSubtargetInfo &STI, 896*0b57cec5SDimitry Andric unsigned MovOpc, unsigned Reg1, 897*0b57cec5SDimitry Andric unsigned Reg2, unsigned FPReg1, 898*0b57cec5SDimitry Andric unsigned FPReg2, bool LE) { 899*0b57cec5SDimitry Andric if (!LE) { 900*0b57cec5SDimitry Andric unsigned temp = Reg1; 901*0b57cec5SDimitry Andric Reg1 = Reg2; 902*0b57cec5SDimitry Andric Reg2 = temp; 903*0b57cec5SDimitry Andric } 904*0b57cec5SDimitry Andric EmitInstrRegReg(STI, MovOpc, Reg1, FPReg1); 905*0b57cec5SDimitry Andric EmitInstrRegReg(STI, MovOpc, Reg2, FPReg2); 906*0b57cec5SDimitry Andric } 907*0b57cec5SDimitry Andric 908*0b57cec5SDimitry Andric void MipsAsmPrinter::EmitSwapFPIntParams(const MCSubtargetInfo &STI, 909*0b57cec5SDimitry Andric Mips16HardFloatInfo::FPParamVariant PV, 910*0b57cec5SDimitry Andric bool LE, bool ToFP) { 911*0b57cec5SDimitry Andric using namespace Mips16HardFloatInfo; 912*0b57cec5SDimitry Andric 913*0b57cec5SDimitry Andric unsigned MovOpc = ToFP ? Mips::MTC1 : Mips::MFC1; 914*0b57cec5SDimitry Andric switch (PV) { 915*0b57cec5SDimitry Andric case FSig: 916*0b57cec5SDimitry Andric EmitInstrRegReg(STI, MovOpc, Mips::A0, Mips::F12); 917*0b57cec5SDimitry Andric break; 918*0b57cec5SDimitry Andric case FFSig: 919*0b57cec5SDimitry Andric EmitMovFPIntPair(STI, MovOpc, Mips::A0, Mips::A1, Mips::F12, Mips::F14, LE); 920*0b57cec5SDimitry Andric break; 921*0b57cec5SDimitry Andric case FDSig: 922*0b57cec5SDimitry Andric EmitInstrRegReg(STI, MovOpc, Mips::A0, Mips::F12); 923*0b57cec5SDimitry Andric EmitMovFPIntPair(STI, MovOpc, Mips::A2, Mips::A3, Mips::F14, Mips::F15, LE); 924*0b57cec5SDimitry Andric break; 925*0b57cec5SDimitry Andric case DSig: 926*0b57cec5SDimitry Andric EmitMovFPIntPair(STI, MovOpc, Mips::A0, Mips::A1, Mips::F12, Mips::F13, LE); 927*0b57cec5SDimitry Andric break; 928*0b57cec5SDimitry Andric case DDSig: 929*0b57cec5SDimitry Andric EmitMovFPIntPair(STI, MovOpc, Mips::A0, Mips::A1, Mips::F12, Mips::F13, LE); 930*0b57cec5SDimitry Andric EmitMovFPIntPair(STI, MovOpc, Mips::A2, Mips::A3, Mips::F14, Mips::F15, LE); 931*0b57cec5SDimitry Andric break; 932*0b57cec5SDimitry Andric case DFSig: 933*0b57cec5SDimitry Andric EmitMovFPIntPair(STI, MovOpc, Mips::A0, Mips::A1, Mips::F12, Mips::F13, LE); 934*0b57cec5SDimitry Andric EmitInstrRegReg(STI, MovOpc, Mips::A2, Mips::F14); 935*0b57cec5SDimitry Andric break; 936*0b57cec5SDimitry Andric case NoSig: 937*0b57cec5SDimitry Andric return; 938*0b57cec5SDimitry Andric } 939*0b57cec5SDimitry Andric } 940*0b57cec5SDimitry Andric 941*0b57cec5SDimitry Andric void MipsAsmPrinter::EmitSwapFPIntRetval( 942*0b57cec5SDimitry Andric const MCSubtargetInfo &STI, Mips16HardFloatInfo::FPReturnVariant RV, 943*0b57cec5SDimitry Andric bool LE) { 944*0b57cec5SDimitry Andric using namespace Mips16HardFloatInfo; 945*0b57cec5SDimitry Andric 946*0b57cec5SDimitry Andric unsigned MovOpc = Mips::MFC1; 947*0b57cec5SDimitry Andric switch (RV) { 948*0b57cec5SDimitry Andric case FRet: 949*0b57cec5SDimitry Andric EmitInstrRegReg(STI, MovOpc, Mips::V0, Mips::F0); 950*0b57cec5SDimitry Andric break; 951*0b57cec5SDimitry Andric case DRet: 952*0b57cec5SDimitry Andric EmitMovFPIntPair(STI, MovOpc, Mips::V0, Mips::V1, Mips::F0, Mips::F1, LE); 953*0b57cec5SDimitry Andric break; 954*0b57cec5SDimitry Andric case CFRet: 955*0b57cec5SDimitry Andric EmitMovFPIntPair(STI, MovOpc, Mips::V0, Mips::V1, Mips::F0, Mips::F1, LE); 956*0b57cec5SDimitry Andric break; 957*0b57cec5SDimitry Andric case CDRet: 958*0b57cec5SDimitry Andric EmitMovFPIntPair(STI, MovOpc, Mips::V0, Mips::V1, Mips::F0, Mips::F1, LE); 959*0b57cec5SDimitry Andric EmitMovFPIntPair(STI, MovOpc, Mips::A0, Mips::A1, Mips::F2, Mips::F3, LE); 960*0b57cec5SDimitry Andric break; 961*0b57cec5SDimitry Andric case NoFPRet: 962*0b57cec5SDimitry Andric break; 963*0b57cec5SDimitry Andric } 964*0b57cec5SDimitry Andric } 965*0b57cec5SDimitry Andric 966*0b57cec5SDimitry Andric void MipsAsmPrinter::EmitFPCallStub( 967*0b57cec5SDimitry Andric const char *Symbol, const Mips16HardFloatInfo::FuncSignature *Signature) { 968*0b57cec5SDimitry Andric using namespace Mips16HardFloatInfo; 969*0b57cec5SDimitry Andric 970*0b57cec5SDimitry Andric MCSymbol *MSymbol = OutContext.getOrCreateSymbol(StringRef(Symbol)); 971*0b57cec5SDimitry Andric bool LE = getDataLayout().isLittleEndian(); 972*0b57cec5SDimitry Andric // Construct a local MCSubtargetInfo here. 973*0b57cec5SDimitry Andric // This is because the MachineFunction won't exist (but have not yet been 974*0b57cec5SDimitry Andric // freed) and since we're at the global level we can use the default 975*0b57cec5SDimitry Andric // constructed subtarget. 976*0b57cec5SDimitry Andric std::unique_ptr<MCSubtargetInfo> STI(TM.getTarget().createMCSubtargetInfo( 977*0b57cec5SDimitry Andric TM.getTargetTriple().str(), TM.getTargetCPU(), 978*0b57cec5SDimitry Andric TM.getTargetFeatureString())); 979*0b57cec5SDimitry Andric 980*0b57cec5SDimitry Andric // 981*0b57cec5SDimitry Andric // .global xxxx 982*0b57cec5SDimitry Andric // 983*0b57cec5SDimitry Andric OutStreamer->EmitSymbolAttribute(MSymbol, MCSA_Global); 984*0b57cec5SDimitry Andric const char *RetType; 985*0b57cec5SDimitry Andric // 986*0b57cec5SDimitry Andric // make the comment field identifying the return and parameter 987*0b57cec5SDimitry Andric // types of the floating point stub 988*0b57cec5SDimitry Andric // # Stub function to call rettype xxxx (params) 989*0b57cec5SDimitry Andric // 990*0b57cec5SDimitry Andric switch (Signature->RetSig) { 991*0b57cec5SDimitry Andric case FRet: 992*0b57cec5SDimitry Andric RetType = "float"; 993*0b57cec5SDimitry Andric break; 994*0b57cec5SDimitry Andric case DRet: 995*0b57cec5SDimitry Andric RetType = "double"; 996*0b57cec5SDimitry Andric break; 997*0b57cec5SDimitry Andric case CFRet: 998*0b57cec5SDimitry Andric RetType = "complex"; 999*0b57cec5SDimitry Andric break; 1000*0b57cec5SDimitry Andric case CDRet: 1001*0b57cec5SDimitry Andric RetType = "double complex"; 1002*0b57cec5SDimitry Andric break; 1003*0b57cec5SDimitry Andric case NoFPRet: 1004*0b57cec5SDimitry Andric RetType = ""; 1005*0b57cec5SDimitry Andric break; 1006*0b57cec5SDimitry Andric } 1007*0b57cec5SDimitry Andric const char *Parms; 1008*0b57cec5SDimitry Andric switch (Signature->ParamSig) { 1009*0b57cec5SDimitry Andric case FSig: 1010*0b57cec5SDimitry Andric Parms = "float"; 1011*0b57cec5SDimitry Andric break; 1012*0b57cec5SDimitry Andric case FFSig: 1013*0b57cec5SDimitry Andric Parms = "float, float"; 1014*0b57cec5SDimitry Andric break; 1015*0b57cec5SDimitry Andric case FDSig: 1016*0b57cec5SDimitry Andric Parms = "float, double"; 1017*0b57cec5SDimitry Andric break; 1018*0b57cec5SDimitry Andric case DSig: 1019*0b57cec5SDimitry Andric Parms = "double"; 1020*0b57cec5SDimitry Andric break; 1021*0b57cec5SDimitry Andric case DDSig: 1022*0b57cec5SDimitry Andric Parms = "double, double"; 1023*0b57cec5SDimitry Andric break; 1024*0b57cec5SDimitry Andric case DFSig: 1025*0b57cec5SDimitry Andric Parms = "double, float"; 1026*0b57cec5SDimitry Andric break; 1027*0b57cec5SDimitry Andric case NoSig: 1028*0b57cec5SDimitry Andric Parms = ""; 1029*0b57cec5SDimitry Andric break; 1030*0b57cec5SDimitry Andric } 1031*0b57cec5SDimitry Andric OutStreamer->AddComment("\t# Stub function to call " + Twine(RetType) + " " + 1032*0b57cec5SDimitry Andric Twine(Symbol) + " (" + Twine(Parms) + ")"); 1033*0b57cec5SDimitry Andric // 1034*0b57cec5SDimitry Andric // probably not necessary but we save and restore the current section state 1035*0b57cec5SDimitry Andric // 1036*0b57cec5SDimitry Andric OutStreamer->PushSection(); 1037*0b57cec5SDimitry Andric // 1038*0b57cec5SDimitry Andric // .section mips16.call.fpxxxx,"ax",@progbits 1039*0b57cec5SDimitry Andric // 1040*0b57cec5SDimitry Andric MCSectionELF *M = OutContext.getELFSection( 1041*0b57cec5SDimitry Andric ".mips16.call.fp." + std::string(Symbol), ELF::SHT_PROGBITS, 1042*0b57cec5SDimitry Andric ELF::SHF_ALLOC | ELF::SHF_EXECINSTR); 1043*0b57cec5SDimitry Andric OutStreamer->SwitchSection(M, nullptr); 1044*0b57cec5SDimitry Andric // 1045*0b57cec5SDimitry Andric // .align 2 1046*0b57cec5SDimitry Andric // 1047*0b57cec5SDimitry Andric OutStreamer->EmitValueToAlignment(4); 1048*0b57cec5SDimitry Andric MipsTargetStreamer &TS = getTargetStreamer(); 1049*0b57cec5SDimitry Andric // 1050*0b57cec5SDimitry Andric // .set nomips16 1051*0b57cec5SDimitry Andric // .set nomicromips 1052*0b57cec5SDimitry Andric // 1053*0b57cec5SDimitry Andric TS.emitDirectiveSetNoMips16(); 1054*0b57cec5SDimitry Andric TS.emitDirectiveSetNoMicroMips(); 1055*0b57cec5SDimitry Andric // 1056*0b57cec5SDimitry Andric // .ent __call_stub_fp_xxxx 1057*0b57cec5SDimitry Andric // .type __call_stub_fp_xxxx,@function 1058*0b57cec5SDimitry Andric // __call_stub_fp_xxxx: 1059*0b57cec5SDimitry Andric // 1060*0b57cec5SDimitry Andric std::string x = "__call_stub_fp_" + std::string(Symbol); 1061*0b57cec5SDimitry Andric MCSymbolELF *Stub = 1062*0b57cec5SDimitry Andric cast<MCSymbolELF>(OutContext.getOrCreateSymbol(StringRef(x))); 1063*0b57cec5SDimitry Andric TS.emitDirectiveEnt(*Stub); 1064*0b57cec5SDimitry Andric MCSymbol *MType = 1065*0b57cec5SDimitry Andric OutContext.getOrCreateSymbol("__call_stub_fp_" + Twine(Symbol)); 1066*0b57cec5SDimitry Andric OutStreamer->EmitSymbolAttribute(MType, MCSA_ELF_TypeFunction); 1067*0b57cec5SDimitry Andric OutStreamer->EmitLabel(Stub); 1068*0b57cec5SDimitry Andric 1069*0b57cec5SDimitry Andric // Only handle non-pic for now. 1070*0b57cec5SDimitry Andric assert(!isPositionIndependent() && 1071*0b57cec5SDimitry Andric "should not be here if we are compiling pic"); 1072*0b57cec5SDimitry Andric TS.emitDirectiveSetReorder(); 1073*0b57cec5SDimitry Andric // 1074*0b57cec5SDimitry Andric // We need to add a MipsMCExpr class to MCTargetDesc to fully implement 1075*0b57cec5SDimitry Andric // stubs without raw text but this current patch is for compiler generated 1076*0b57cec5SDimitry Andric // functions and they all return some value. 1077*0b57cec5SDimitry Andric // The calling sequence for non pic is different in that case and we need 1078*0b57cec5SDimitry Andric // to implement %lo and %hi in order to handle the case of no return value 1079*0b57cec5SDimitry Andric // See the corresponding method in Mips16HardFloat for details. 1080*0b57cec5SDimitry Andric // 1081*0b57cec5SDimitry Andric // mov the return address to S2. 1082*0b57cec5SDimitry Andric // we have no stack space to store it and we are about to make another call. 1083*0b57cec5SDimitry Andric // We need to make sure that the enclosing function knows to save S2 1084*0b57cec5SDimitry Andric // This should have already been handled. 1085*0b57cec5SDimitry Andric // 1086*0b57cec5SDimitry Andric // Mov $18, $31 1087*0b57cec5SDimitry Andric 1088*0b57cec5SDimitry Andric EmitInstrRegRegReg(*STI, Mips::OR, Mips::S2, Mips::RA, Mips::ZERO); 1089*0b57cec5SDimitry Andric 1090*0b57cec5SDimitry Andric EmitSwapFPIntParams(*STI, Signature->ParamSig, LE, true); 1091*0b57cec5SDimitry Andric 1092*0b57cec5SDimitry Andric // Jal xxxx 1093*0b57cec5SDimitry Andric // 1094*0b57cec5SDimitry Andric EmitJal(*STI, MSymbol); 1095*0b57cec5SDimitry Andric 1096*0b57cec5SDimitry Andric // fix return values 1097*0b57cec5SDimitry Andric EmitSwapFPIntRetval(*STI, Signature->RetSig, LE); 1098*0b57cec5SDimitry Andric // 1099*0b57cec5SDimitry Andric // do the return 1100*0b57cec5SDimitry Andric // if (Signature->RetSig == NoFPRet) 1101*0b57cec5SDimitry Andric // llvm_unreachable("should not be any stubs here with no return value"); 1102*0b57cec5SDimitry Andric // else 1103*0b57cec5SDimitry Andric EmitInstrReg(*STI, Mips::JR, Mips::S2); 1104*0b57cec5SDimitry Andric 1105*0b57cec5SDimitry Andric MCSymbol *Tmp = OutContext.createTempSymbol(); 1106*0b57cec5SDimitry Andric OutStreamer->EmitLabel(Tmp); 1107*0b57cec5SDimitry Andric const MCSymbolRefExpr *E = MCSymbolRefExpr::create(Stub, OutContext); 1108*0b57cec5SDimitry Andric const MCSymbolRefExpr *T = MCSymbolRefExpr::create(Tmp, OutContext); 1109*0b57cec5SDimitry Andric const MCExpr *T_min_E = MCBinaryExpr::createSub(T, E, OutContext); 1110*0b57cec5SDimitry Andric OutStreamer->emitELFSize(Stub, T_min_E); 1111*0b57cec5SDimitry Andric TS.emitDirectiveEnd(x); 1112*0b57cec5SDimitry Andric OutStreamer->PopSection(); 1113*0b57cec5SDimitry Andric } 1114*0b57cec5SDimitry Andric 1115*0b57cec5SDimitry Andric void MipsAsmPrinter::EmitEndOfAsmFile(Module &M) { 1116*0b57cec5SDimitry Andric // Emit needed stubs 1117*0b57cec5SDimitry Andric // 1118*0b57cec5SDimitry Andric for (std::map< 1119*0b57cec5SDimitry Andric const char *, 1120*0b57cec5SDimitry Andric const Mips16HardFloatInfo::FuncSignature *>::const_iterator 1121*0b57cec5SDimitry Andric it = StubsNeeded.begin(); 1122*0b57cec5SDimitry Andric it != StubsNeeded.end(); ++it) { 1123*0b57cec5SDimitry Andric const char *Symbol = it->first; 1124*0b57cec5SDimitry Andric const Mips16HardFloatInfo::FuncSignature *Signature = it->second; 1125*0b57cec5SDimitry Andric EmitFPCallStub(Symbol, Signature); 1126*0b57cec5SDimitry Andric } 1127*0b57cec5SDimitry Andric // return to the text section 1128*0b57cec5SDimitry Andric OutStreamer->SwitchSection(OutContext.getObjectFileInfo()->getTextSection()); 1129*0b57cec5SDimitry Andric } 1130*0b57cec5SDimitry Andric 1131*0b57cec5SDimitry Andric void MipsAsmPrinter::EmitSled(const MachineInstr &MI, SledKind Kind) { 1132*0b57cec5SDimitry Andric const uint8_t NoopsInSledCount = Subtarget->isGP64bit() ? 15 : 11; 1133*0b57cec5SDimitry Andric // For mips32 we want to emit the following pattern: 1134*0b57cec5SDimitry Andric // 1135*0b57cec5SDimitry Andric // .Lxray_sled_N: 1136*0b57cec5SDimitry Andric // ALIGN 1137*0b57cec5SDimitry Andric // B .tmpN 1138*0b57cec5SDimitry Andric // 11 NOP instructions (44 bytes) 1139*0b57cec5SDimitry Andric // ADDIU T9, T9, 52 1140*0b57cec5SDimitry Andric // .tmpN 1141*0b57cec5SDimitry Andric // 1142*0b57cec5SDimitry Andric // We need the 44 bytes (11 instructions) because at runtime, we'd 1143*0b57cec5SDimitry Andric // be patching over the full 48 bytes (12 instructions) with the following 1144*0b57cec5SDimitry Andric // pattern: 1145*0b57cec5SDimitry Andric // 1146*0b57cec5SDimitry Andric // ADDIU SP, SP, -8 1147*0b57cec5SDimitry Andric // NOP 1148*0b57cec5SDimitry Andric // SW RA, 4(SP) 1149*0b57cec5SDimitry Andric // SW T9, 0(SP) 1150*0b57cec5SDimitry Andric // LUI T9, %hi(__xray_FunctionEntry/Exit) 1151*0b57cec5SDimitry Andric // ORI T9, T9, %lo(__xray_FunctionEntry/Exit) 1152*0b57cec5SDimitry Andric // LUI T0, %hi(function_id) 1153*0b57cec5SDimitry Andric // JALR T9 1154*0b57cec5SDimitry Andric // ORI T0, T0, %lo(function_id) 1155*0b57cec5SDimitry Andric // LW T9, 0(SP) 1156*0b57cec5SDimitry Andric // LW RA, 4(SP) 1157*0b57cec5SDimitry Andric // ADDIU SP, SP, 8 1158*0b57cec5SDimitry Andric // 1159*0b57cec5SDimitry Andric // We add 52 bytes to t9 because we want to adjust the function pointer to 1160*0b57cec5SDimitry Andric // the actual start of function i.e. the address just after the noop sled. 1161*0b57cec5SDimitry Andric // We do this because gp displacement relocation is emitted at the start of 1162*0b57cec5SDimitry Andric // of the function i.e after the nop sled and to correctly calculate the 1163*0b57cec5SDimitry Andric // global offset table address, t9 must hold the address of the instruction 1164*0b57cec5SDimitry Andric // containing the gp displacement relocation. 1165*0b57cec5SDimitry Andric // FIXME: Is this correct for the static relocation model? 1166*0b57cec5SDimitry Andric // 1167*0b57cec5SDimitry Andric // For mips64 we want to emit the following pattern: 1168*0b57cec5SDimitry Andric // 1169*0b57cec5SDimitry Andric // .Lxray_sled_N: 1170*0b57cec5SDimitry Andric // ALIGN 1171*0b57cec5SDimitry Andric // B .tmpN 1172*0b57cec5SDimitry Andric // 15 NOP instructions (60 bytes) 1173*0b57cec5SDimitry Andric // .tmpN 1174*0b57cec5SDimitry Andric // 1175*0b57cec5SDimitry Andric // We need the 60 bytes (15 instructions) because at runtime, we'd 1176*0b57cec5SDimitry Andric // be patching over the full 64 bytes (16 instructions) with the following 1177*0b57cec5SDimitry Andric // pattern: 1178*0b57cec5SDimitry Andric // 1179*0b57cec5SDimitry Andric // DADDIU SP, SP, -16 1180*0b57cec5SDimitry Andric // NOP 1181*0b57cec5SDimitry Andric // SD RA, 8(SP) 1182*0b57cec5SDimitry Andric // SD T9, 0(SP) 1183*0b57cec5SDimitry Andric // LUI T9, %highest(__xray_FunctionEntry/Exit) 1184*0b57cec5SDimitry Andric // ORI T9, T9, %higher(__xray_FunctionEntry/Exit) 1185*0b57cec5SDimitry Andric // DSLL T9, T9, 16 1186*0b57cec5SDimitry Andric // ORI T9, T9, %hi(__xray_FunctionEntry/Exit) 1187*0b57cec5SDimitry Andric // DSLL T9, T9, 16 1188*0b57cec5SDimitry Andric // ORI T9, T9, %lo(__xray_FunctionEntry/Exit) 1189*0b57cec5SDimitry Andric // LUI T0, %hi(function_id) 1190*0b57cec5SDimitry Andric // JALR T9 1191*0b57cec5SDimitry Andric // ADDIU T0, T0, %lo(function_id) 1192*0b57cec5SDimitry Andric // LD T9, 0(SP) 1193*0b57cec5SDimitry Andric // LD RA, 8(SP) 1194*0b57cec5SDimitry Andric // DADDIU SP, SP, 16 1195*0b57cec5SDimitry Andric // 1196*0b57cec5SDimitry Andric OutStreamer->EmitCodeAlignment(4); 1197*0b57cec5SDimitry Andric auto CurSled = OutContext.createTempSymbol("xray_sled_", true); 1198*0b57cec5SDimitry Andric OutStreamer->EmitLabel(CurSled); 1199*0b57cec5SDimitry Andric auto Target = OutContext.createTempSymbol(); 1200*0b57cec5SDimitry Andric 1201*0b57cec5SDimitry Andric // Emit "B .tmpN" instruction, which jumps over the nop sled to the actual 1202*0b57cec5SDimitry Andric // start of function 1203*0b57cec5SDimitry Andric const MCExpr *TargetExpr = MCSymbolRefExpr::create( 1204*0b57cec5SDimitry Andric Target, MCSymbolRefExpr::VariantKind::VK_None, OutContext); 1205*0b57cec5SDimitry Andric EmitToStreamer(*OutStreamer, MCInstBuilder(Mips::BEQ) 1206*0b57cec5SDimitry Andric .addReg(Mips::ZERO) 1207*0b57cec5SDimitry Andric .addReg(Mips::ZERO) 1208*0b57cec5SDimitry Andric .addExpr(TargetExpr)); 1209*0b57cec5SDimitry Andric 1210*0b57cec5SDimitry Andric for (int8_t I = 0; I < NoopsInSledCount; I++) 1211*0b57cec5SDimitry Andric EmitToStreamer(*OutStreamer, MCInstBuilder(Mips::SLL) 1212*0b57cec5SDimitry Andric .addReg(Mips::ZERO) 1213*0b57cec5SDimitry Andric .addReg(Mips::ZERO) 1214*0b57cec5SDimitry Andric .addImm(0)); 1215*0b57cec5SDimitry Andric 1216*0b57cec5SDimitry Andric OutStreamer->EmitLabel(Target); 1217*0b57cec5SDimitry Andric 1218*0b57cec5SDimitry Andric if (!Subtarget->isGP64bit()) { 1219*0b57cec5SDimitry Andric EmitToStreamer(*OutStreamer, 1220*0b57cec5SDimitry Andric MCInstBuilder(Mips::ADDiu) 1221*0b57cec5SDimitry Andric .addReg(Mips::T9) 1222*0b57cec5SDimitry Andric .addReg(Mips::T9) 1223*0b57cec5SDimitry Andric .addImm(0x34)); 1224*0b57cec5SDimitry Andric } 1225*0b57cec5SDimitry Andric 1226*0b57cec5SDimitry Andric recordSled(CurSled, MI, Kind); 1227*0b57cec5SDimitry Andric } 1228*0b57cec5SDimitry Andric 1229*0b57cec5SDimitry Andric void MipsAsmPrinter::LowerPATCHABLE_FUNCTION_ENTER(const MachineInstr &MI) { 1230*0b57cec5SDimitry Andric EmitSled(MI, SledKind::FUNCTION_ENTER); 1231*0b57cec5SDimitry Andric } 1232*0b57cec5SDimitry Andric 1233*0b57cec5SDimitry Andric void MipsAsmPrinter::LowerPATCHABLE_FUNCTION_EXIT(const MachineInstr &MI) { 1234*0b57cec5SDimitry Andric EmitSled(MI, SledKind::FUNCTION_EXIT); 1235*0b57cec5SDimitry Andric } 1236*0b57cec5SDimitry Andric 1237*0b57cec5SDimitry Andric void MipsAsmPrinter::LowerPATCHABLE_TAIL_CALL(const MachineInstr &MI) { 1238*0b57cec5SDimitry Andric EmitSled(MI, SledKind::TAIL_CALL); 1239*0b57cec5SDimitry Andric } 1240*0b57cec5SDimitry Andric 1241*0b57cec5SDimitry Andric void MipsAsmPrinter::PrintDebugValueComment(const MachineInstr *MI, 1242*0b57cec5SDimitry Andric raw_ostream &OS) { 1243*0b57cec5SDimitry Andric // TODO: implement 1244*0b57cec5SDimitry Andric } 1245*0b57cec5SDimitry Andric 1246*0b57cec5SDimitry Andric // Emit .dtprelword or .dtpreldword directive 1247*0b57cec5SDimitry Andric // and value for debug thread local expression. 1248*0b57cec5SDimitry Andric void MipsAsmPrinter::EmitDebugValue(const MCExpr *Value, unsigned Size) const { 1249*0b57cec5SDimitry Andric if (auto *MipsExpr = dyn_cast<MipsMCExpr>(Value)) { 1250*0b57cec5SDimitry Andric if (MipsExpr && MipsExpr->getKind() == MipsMCExpr::MEK_DTPREL) { 1251*0b57cec5SDimitry Andric switch (Size) { 1252*0b57cec5SDimitry Andric case 4: 1253*0b57cec5SDimitry Andric OutStreamer->EmitDTPRel32Value(MipsExpr->getSubExpr()); 1254*0b57cec5SDimitry Andric break; 1255*0b57cec5SDimitry Andric case 8: 1256*0b57cec5SDimitry Andric OutStreamer->EmitDTPRel64Value(MipsExpr->getSubExpr()); 1257*0b57cec5SDimitry Andric break; 1258*0b57cec5SDimitry Andric default: 1259*0b57cec5SDimitry Andric llvm_unreachable("Unexpected size of expression value."); 1260*0b57cec5SDimitry Andric } 1261*0b57cec5SDimitry Andric return; 1262*0b57cec5SDimitry Andric } 1263*0b57cec5SDimitry Andric } 1264*0b57cec5SDimitry Andric AsmPrinter::EmitDebugValue(Value, Size); 1265*0b57cec5SDimitry Andric } 1266*0b57cec5SDimitry Andric 1267*0b57cec5SDimitry Andric // Align all targets of indirect branches on bundle size. Used only if target 1268*0b57cec5SDimitry Andric // is NaCl. 1269*0b57cec5SDimitry Andric void MipsAsmPrinter::NaClAlignIndirectJumpTargets(MachineFunction &MF) { 1270*0b57cec5SDimitry Andric // Align all blocks that are jumped to through jump table. 1271*0b57cec5SDimitry Andric if (MachineJumpTableInfo *JtInfo = MF.getJumpTableInfo()) { 1272*0b57cec5SDimitry Andric const std::vector<MachineJumpTableEntry> &JT = JtInfo->getJumpTables(); 1273*0b57cec5SDimitry Andric for (unsigned I = 0; I < JT.size(); ++I) { 1274*0b57cec5SDimitry Andric const std::vector<MachineBasicBlock*> &MBBs = JT[I].MBBs; 1275*0b57cec5SDimitry Andric 1276*0b57cec5SDimitry Andric for (unsigned J = 0; J < MBBs.size(); ++J) 1277*0b57cec5SDimitry Andric MBBs[J]->setAlignment(MIPS_NACL_BUNDLE_ALIGN); 1278*0b57cec5SDimitry Andric } 1279*0b57cec5SDimitry Andric } 1280*0b57cec5SDimitry Andric 1281*0b57cec5SDimitry Andric // If basic block address is taken, block can be target of indirect branch. 1282*0b57cec5SDimitry Andric for (auto &MBB : MF) { 1283*0b57cec5SDimitry Andric if (MBB.hasAddressTaken()) 1284*0b57cec5SDimitry Andric MBB.setAlignment(MIPS_NACL_BUNDLE_ALIGN); 1285*0b57cec5SDimitry Andric } 1286*0b57cec5SDimitry Andric } 1287*0b57cec5SDimitry Andric 1288*0b57cec5SDimitry Andric bool MipsAsmPrinter::isLongBranchPseudo(int Opcode) const { 1289*0b57cec5SDimitry Andric return (Opcode == Mips::LONG_BRANCH_LUi 1290*0b57cec5SDimitry Andric || Opcode == Mips::LONG_BRANCH_LUi2Op 1291*0b57cec5SDimitry Andric || Opcode == Mips::LONG_BRANCH_LUi2Op_64 1292*0b57cec5SDimitry Andric || Opcode == Mips::LONG_BRANCH_ADDiu 1293*0b57cec5SDimitry Andric || Opcode == Mips::LONG_BRANCH_ADDiu2Op 1294*0b57cec5SDimitry Andric || Opcode == Mips::LONG_BRANCH_DADDiu 1295*0b57cec5SDimitry Andric || Opcode == Mips::LONG_BRANCH_DADDiu2Op); 1296*0b57cec5SDimitry Andric } 1297*0b57cec5SDimitry Andric 1298*0b57cec5SDimitry Andric // Force static initialization. 1299*0b57cec5SDimitry Andric extern "C" void LLVMInitializeMipsAsmPrinter() { 1300*0b57cec5SDimitry Andric RegisterAsmPrinter<MipsAsmPrinter> X(getTheMipsTarget()); 1301*0b57cec5SDimitry Andric RegisterAsmPrinter<MipsAsmPrinter> Y(getTheMipselTarget()); 1302*0b57cec5SDimitry Andric RegisterAsmPrinter<MipsAsmPrinter> A(getTheMips64Target()); 1303*0b57cec5SDimitry Andric RegisterAsmPrinter<MipsAsmPrinter> B(getTheMips64elTarget()); 1304*0b57cec5SDimitry Andric } 1305