X-Git-Url: http://plrg.eecs.uci.edu/git/?a=blobdiff_plain;f=lib%2FTarget%2FMips%2FMipsAsmPrinter.cpp;h=1ad7e00fdc1715c891c5ebe7e6f98c00ee2f83a4;hb=c308f165a0e981280a6e35d81282aad533b29684;hp=a5505d36937f868750efb00ae6712429eed1c3fa;hpb=044a784fa586cf92bb712c6dc54f925f539e19d1;p=oota-llvm.git diff --git a/lib/Target/Mips/MipsAsmPrinter.cpp b/lib/Target/Mips/MipsAsmPrinter.cpp index a5505d36937..1ad7e00fdc1 100644 --- a/lib/Target/Mips/MipsAsmPrinter.cpp +++ b/lib/Target/Mips/MipsAsmPrinter.cpp @@ -1,4 +1,4 @@ -//===-- MipsAsmPrinter.cpp - Mips LLVM assembly writer --------------------===// +//===-- MipsAsmPrinter.cpp - Mips LLVM Assembly Printer -------------------===// // // The LLVM Compiler Infrastructure // @@ -13,103 +13,147 @@ //===----------------------------------------------------------------------===// #define DEBUG_TYPE "mips-asm-printer" +#include "InstPrinter/MipsInstPrinter.h" +#include "MCTargetDesc/MipsBaseInfo.h" +#include "MCTargetDesc/MipsMCNaCl.h" #include "Mips.h" #include "MipsAsmPrinter.h" #include "MipsInstrInfo.h" -#include "MipsMachineFunction.h" #include "MipsMCInstLower.h" -#include "InstPrinter/MipsInstPrinter.h" -#include "MCTargetDesc/MipsBaseInfo.h" +#include "MipsTargetStreamer.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/Twine.h" -#include "llvm/Analysis/DebugInfo.h" -#include "llvm/BasicBlock.h" -#include "llvm/Instructions.h" -#include "llvm/CodeGen/MachineFunctionPass.h" #include "llvm/CodeGen/MachineConstantPool.h" #include "llvm/CodeGen/MachineFrameInfo.h" +#include "llvm/CodeGen/MachineFunctionPass.h" #include "llvm/CodeGen/MachineInstr.h" +#include "llvm/CodeGen/MachineJumpTableInfo.h" #include "llvm/CodeGen/MachineMemOperand.h" -#include "llvm/Instructions.h" -#include "llvm/MC/MCStreamer.h" +#include "llvm/IR/BasicBlock.h" +#include "llvm/IR/DataLayout.h" +#include "llvm/IR/InlineAsm.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/Mangler.h" #include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCELFStreamer.h" +#include "llvm/MC/MCExpr.h" #include "llvm/MC/MCInst.h" +#include "llvm/MC/MCSection.h" +#include "llvm/MC/MCSectionELF.h" #include "llvm/MC/MCSymbol.h" +#include "llvm/Support/ELF.h" #include "llvm/Support/TargetRegistry.h" #include "llvm/Support/raw_ostream.h" -#include "llvm/Target/Mangler.h" -#include "llvm/Target/TargetData.h" #include "llvm/Target/TargetLoweringObjectFile.h" #include "llvm/Target/TargetOptions.h" +#include using namespace llvm; -static bool isUnalignedLoadStore(unsigned Opc) { - return Opc == Mips::ULW || Opc == Mips::ULH || Opc == Mips::ULHu || - Opc == Mips::USW || Opc == Mips::USH || - Opc == Mips::ULW_P8 || Opc == Mips::ULH_P8 || Opc == Mips::ULHu_P8 || - Opc == Mips::USW_P8 || Opc == Mips::USH_P8; +MipsTargetStreamer &MipsAsmPrinter::getTargetStreamer() { + return static_cast(*OutStreamer.getTargetStreamer()); +} + +bool MipsAsmPrinter::runOnMachineFunction(MachineFunction &MF) { + // Initialize TargetLoweringObjectFile. + if (Subtarget->allowMixed16_32()) + const_cast(getObjFileLowering()) + .Initialize(OutContext, TM); + MipsFI = MF.getInfo(); + if (Subtarget->inMips16Mode()) + for (std::map< + const char *, + const llvm::Mips16HardFloatInfo::FuncSignature *>::const_iterator + it = MipsFI->StubsNeeded.begin(); + it != MipsFI->StubsNeeded.end(); ++it) { + const char *Symbol = it->first; + const llvm::Mips16HardFloatInfo::FuncSignature *Signature = it->second; + if (StubsNeeded.find(Symbol) == StubsNeeded.end()) + StubsNeeded[Symbol] = Signature; + } + MCP = MF.getConstantPool(); + + // In NaCl, all indirect jump targets must be aligned to bundle size. + if (Subtarget->isTargetNaCl()) + NaClAlignIndirectJumpTargets(MF); + + AsmPrinter::runOnMachineFunction(MF); + return true; } -static bool isDirective(unsigned Opc) { - return Opc == Mips::MACRO || Opc == Mips::NOMACRO || - Opc == Mips::REORDER || Opc == Mips::NOREORDER || - Opc == Mips::ATMACRO || Opc == Mips::NOAT; +bool MipsAsmPrinter::lowerOperand(const MachineOperand &MO, MCOperand &MCOp) { + MCOp = MCInstLowering.LowerOperand(MO); + return MCOp.isValid(); } -void MipsAsmPrinter::EmitInstruction(const MachineInstr *MI) { - SmallString<128> Str; - raw_svector_ostream OS(Str); +#include "MipsGenMCPseudoLowering.inc" +void MipsAsmPrinter::EmitInstruction(const MachineInstr *MI) { if (MI->isDebugValue()) { + SmallString<128> Str; + raw_svector_ostream OS(Str); + PrintDebugValueComment(MI, OS); return; } - MipsMCInstLower MCInstLowering(Mang, *MF, *this); - unsigned Opc = MI->getOpcode(); - MCInst TmpInst0; - SmallVector MCInsts; - MCInstLowering.Lower(MI, TmpInst0); + // If we just ended a constant pool, mark it as such. + if (InConstantPool && MI->getOpcode() != Mips::CONSTPOOL_ENTRY) { + OutStreamer.EmitDataRegion(MCDR_DataRegionEnd); + InConstantPool = false; + } + if (MI->getOpcode() == Mips::CONSTPOOL_ENTRY) { + // CONSTPOOL_ENTRY - This instruction represents a floating + //constant pool in the function. The first operand is the ID# + // for this instruction, the second is the index into the + // MachineConstantPool that this is, the third is the size in + // bytes of this constant pool entry. + // The required alignment is specified on the basic block holding this MI. + // + unsigned LabelId = (unsigned)MI->getOperand(0).getImm(); + unsigned CPIdx = (unsigned)MI->getOperand(1).getIndex(); + + // If this is the first entry of the pool, mark it. + if (!InConstantPool) { + OutStreamer.EmitDataRegion(MCDR_DataRegion); + InConstantPool = true; + } - if (!OutStreamer.hasRawTextSupport() && isDirective(Opc)) - return; + OutStreamer.EmitLabel(GetCPISymbol(LabelId)); - // Enclose unaligned load or store with .macro & .nomacro directives. - if (isUnalignedLoadStore(Opc)) { - if (OutStreamer.hasRawTextSupport()) { - MCInst Directive; - Directive.setOpcode(Mips::MACRO); - OutStreamer.EmitInstruction(Directive); - OutStreamer.EmitInstruction(TmpInst0); - Directive.setOpcode(Mips::NOMACRO); - OutStreamer.EmitInstruction(Directive); - } else { - MCInstLowering.LowerUnalignedLoadStore(MI, MCInsts); - for (SmallVector::iterator I = MCInsts.begin(); I - != MCInsts.end(); ++I) - OutStreamer.EmitInstruction(*I); - } + const MachineConstantPoolEntry &MCPE = MCP->getConstants()[CPIdx]; + if (MCPE.isMachineConstantPoolEntry()) + EmitMachineConstantPoolValue(MCPE.Val.MachineCPVal); + else + EmitGlobalConstant(MCPE.Val.ConstVal); return; } - if (!OutStreamer.hasRawTextSupport()) { - // Lower CPLOAD and CPRESTORE - if (Opc == Mips::CPLOAD) - MCInstLowering.LowerCPLOAD(MI, MCInsts); - else if (Opc == Mips::CPRESTORE) - MCInstLowering.LowerCPRESTORE(MI, MCInsts); - - if (!MCInsts.empty()) { - for (SmallVector::iterator I = MCInsts.begin(); - I != MCInsts.end(); ++I) - OutStreamer.EmitInstruction(*I); - return; - } - } - OutStreamer.EmitInstruction(TmpInst0); + MachineBasicBlock::const_instr_iterator I = MI; + MachineBasicBlock::const_instr_iterator E = MI->getParent()->instr_end(); + + do { + // Do any auto-generated pseudo lowerings. + if (emitPseudoExpansionLowering(OutStreamer, &*I)) + continue; + + // The inMips16Mode() test is not permanent. + // Some instructions are marked as pseudo right now which + // would make the test fail for the wrong reason but + // that will be fixed soon. We need this here because we are + // removing another test for this situation downstream in the + // callchain. + // + if (I->isPseudo() && !Subtarget->inMips16Mode()) + llvm_unreachable("Pseudo opcode found in EmitInstruction()"); + + MCInst TmpInst0; + MCInstLowering.Lower(I, TmpInst0); + EmitToStreamer(OutStreamer, TmpInst0); + } while ((++I != E) && I->isInsideBundle()); // Delay slot check } //===----------------------------------------------------------------------===// @@ -149,7 +193,7 @@ void MipsAsmPrinter::EmitInstruction(const MachineInstr *MI) { // Create a bitmask with all callee saved registers for CPU or Floating Point // registers. For CPU registers consider RA, GP and FP for saving if necessary. -void MipsAsmPrinter::printSavedRegsBitmask(raw_ostream &O) { +void MipsAsmPrinter::printSavedRegsBitmask() { // CPU and FPU Saved Registers Bitmasks unsigned CPUBitmask = 0, FPUBitmask = 0; int CPUTopSavedRegOff, FPUTopSavedRegOff; @@ -158,9 +202,9 @@ void MipsAsmPrinter::printSavedRegsBitmask(raw_ostream &O) { const MachineFrameInfo *MFI = MF->getFrameInfo(); const std::vector &CSI = MFI->getCalleeSavedInfo(); // size of stack area to which FP callee-saved regs are saved. - unsigned CPURegSize = Mips::CPURegsRegisterClass->getSize(); - unsigned FGR32RegSize = Mips::FGR32RegisterClass->getSize(); - unsigned AFGR64RegSize = Mips::AFGR64RegisterClass->getSize(); + unsigned CPURegSize = Mips::GPR32RegClass.getSize(); + unsigned FGR32RegSize = Mips::FGR32RegClass.getSize(); + unsigned AFGR64RegSize = Mips::AFGR64RegClass.getSize(); bool HasAFGR64Reg = false; unsigned CSFPRegsSize = 0; unsigned i, e = CSI.size(); @@ -168,11 +212,11 @@ void MipsAsmPrinter::printSavedRegsBitmask(raw_ostream &O) { // Set FPU Bitmask. for (i = 0; i != e; ++i) { unsigned Reg = CSI[i].getReg(); - if (Mips::CPURegsRegisterClass->contains(Reg)) + if (Mips::GPR32RegClass.contains(Reg)) break; - unsigned RegNum = MipsRegisterInfo::getRegisterNumbering(Reg); - if (Mips::AFGR64RegisterClass->contains(Reg)) { + unsigned RegNum = TM.getRegisterInfo()->getEncodingValue(Reg); + if (Mips::AFGR64RegClass.contains(Reg)) { FPUBitmask |= (3 << RegNum); CSFPRegsSize += AFGR64RegSize; HasAFGR64Reg = true; @@ -186,7 +230,7 @@ void MipsAsmPrinter::printSavedRegsBitmask(raw_ostream &O) { // Set CPU Bitmask. for (; i != e; ++i) { unsigned Reg = CSI[i].getReg(); - unsigned RegNum = MipsRegisterInfo::getRegisterNumbering(Reg); + unsigned RegNum = TM.getRegisterInfo()->getEncodingValue(Reg); CPUBitmask |= (1 << RegNum); } @@ -197,20 +241,12 @@ void MipsAsmPrinter::printSavedRegsBitmask(raw_ostream &O) { // CPU Regs are saved below FP Regs. CPUTopSavedRegOff = CPUBitmask ? -CSFPRegsSize - CPURegSize : 0; + MipsTargetStreamer &TS = getTargetStreamer(); // Print CPUBitmask - O << "\t.mask \t"; printHex32(CPUBitmask, O); - O << ',' << CPUTopSavedRegOff << '\n'; + TS.emitMask(CPUBitmask, CPUTopSavedRegOff); // Print FPUBitmask - O << "\t.fmask\t"; printHex32(FPUBitmask, O); - O << "," << FPUTopSavedRegOff << '\n'; -} - -// Print a 32 bit hex number with all numbers. -void MipsAsmPrinter::printHex32(unsigned Value, raw_ostream &O) { - O << "0x"; - for (int i = 7; i >= 0; i--) - O.write_hex((Value & (0xF << (i*4))) >> (i*4)); + TS.emitFMask(FPUBitmask, FPUTopSavedRegOff); } //===----------------------------------------------------------------------===// @@ -225,11 +261,7 @@ void MipsAsmPrinter::emitFrameDirective() { unsigned returnReg = RI.getRARegister(); unsigned stackSize = MF->getFrameInfo()->getStackSize(); - if (OutStreamer.hasRawTextSupport()) - OutStreamer.EmitRawText("\t.frame\t$" + - StringRef(MipsInstPrinter::getRegisterName(stackReg)).lower() + - "," + Twine(stackSize) + ",$" + - StringRef(MipsInstPrinter::getRegisterName(returnReg)).lower()); + getTargetStreamer().emitFrame(stackReg, stackSize, returnReg); } /// Emit Set directives. @@ -239,43 +271,76 @@ const char *MipsAsmPrinter::getCurrentABIString() const { case MipsSubtarget::N32: return "abiN32"; case MipsSubtarget::N64: return "abi64"; case MipsSubtarget::EABI: return "eabi32"; // TODO: handle eabi64 - default: break; + default: llvm_unreachable("Unknown Mips ABI"); } - - llvm_unreachable("Unknown Mips ABI"); - return NULL; } void MipsAsmPrinter::EmitFunctionEntryLabel() { - if (OutStreamer.hasRawTextSupport()) - OutStreamer.EmitRawText("\t.ent\t" + Twine(CurrentFnSym->getName())); + MipsTargetStreamer &TS = getTargetStreamer(); + + // NaCl sandboxing requires that indirect call instructions are masked. + // This means that function entry points should be bundle-aligned. + if (Subtarget->isTargetNaCl()) + EmitAlignment(std::max(MF->getAlignment(), MIPS_NACL_BUNDLE_ALIGN)); + + if (Subtarget->inMicroMipsMode()) + TS.emitDirectiveSetMicroMips(); + else + TS.emitDirectiveSetNoMicroMips(); + + if (Subtarget->inMips16Mode()) + TS.emitDirectiveSetMips16(); + else + TS.emitDirectiveSetNoMips16(); + + TS.emitDirectiveEnt(*CurrentFnSym); OutStreamer.EmitLabel(CurrentFnSym); } /// EmitFunctionBodyStart - Targets can override this to emit stuff before /// the first basic block in the function. void MipsAsmPrinter::EmitFunctionBodyStart() { - emitFrameDirective(); + MipsTargetStreamer &TS = getTargetStreamer(); - if (OutStreamer.hasRawTextSupport()) { - SmallString<128> Str; - raw_svector_ostream OS(Str); - printSavedRegsBitmask(OS); - OutStreamer.EmitRawText(OS.str()); + MCInstLowering.Initialize(&MF->getContext()); + + bool IsNakedFunction = + MF->getFunction()-> + getAttributes().hasAttribute(AttributeSet::FunctionIndex, + Attribute::Naked); + if (!IsNakedFunction) + emitFrameDirective(); + + if (!IsNakedFunction) + printSavedRegsBitmask(); + + if (!Subtarget->inMips16Mode()) { + TS.emitDirectiveSetNoReorder(); + TS.emitDirectiveSetNoMacro(); + TS.emitDirectiveSetNoAt(); } } /// EmitFunctionBodyEnd - Targets can override this to emit stuff after /// the last basic block in the function. void MipsAsmPrinter::EmitFunctionBodyEnd() { + MipsTargetStreamer &TS = getTargetStreamer(); + // There are instruction for this macros, but they must // always be at the function end, and we can't emit and // break with BB logic. - if (OutStreamer.hasRawTextSupport()) { - OutStreamer.EmitRawText(StringRef("\t.set\tmacro")); - OutStreamer.EmitRawText(StringRef("\t.set\treorder")); - OutStreamer.EmitRawText("\t.end\t" + Twine(CurrentFnSym->getName())); + if (!Subtarget->inMips16Mode()) { + TS.emitDirectiveSetAt(); + TS.emitDirectiveSetMacro(); + TS.emitDirectiveSetReorder(); } + TS.emitDirectiveEnd(CurrentFnSym->getName()); + // Make sure to terminate any constant pools that were at the end + // of the function. + if (!InConstantPool) + return; + InConstantPool = false; + OutStreamer.EmitDataRegion(MCDR_DataRegionEnd); } /// isBlockOnlyReachableByFallthough - Return true if the basic block has @@ -300,18 +365,18 @@ bool MipsAsmPrinter::isBlockOnlyReachableByFallthrough(const MachineBasicBlock* // If there isn't exactly one predecessor, it can't be a fall through. MachineBasicBlock::const_pred_iterator PI = MBB->pred_begin(), PI2 = PI; ++PI2; - + if (PI2 != MBB->pred_end()) - return false; + return false; // The predecessor has to be immediately before this block. if (!Pred->isLayoutSuccessor(MBB)) return false; - + // If the block is completely empty, then it definitely does fall through. if (Pred->empty()) return true; - + // Otherwise, check the last instruction. // Check if the last terminator is an unconditional branch. MachineBasicBlock::const_iterator I = Pred->end(); @@ -321,14 +386,104 @@ bool MipsAsmPrinter::isBlockOnlyReachableByFallthrough(const MachineBasicBlock* } // Print out an operand for an inline asm expression. -bool MipsAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, +bool MipsAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNum, unsigned AsmVariant,const char *ExtraCode, raw_ostream &O) { // Does this asm operand have a single letter operand modifier? - if (ExtraCode && ExtraCode[0]) - return true; // Unknown modifier. + if (ExtraCode && ExtraCode[0]) { + if (ExtraCode[1] != 0) return true; // Unknown modifier. + + const MachineOperand &MO = MI->getOperand(OpNum); + switch (ExtraCode[0]) { + default: + // See if this is a generic print operand + return AsmPrinter::PrintAsmOperand(MI,OpNum,AsmVariant,ExtraCode,O); + case 'X': // hex const int + if ((MO.getType()) != MachineOperand::MO_Immediate) + return true; + O << "0x" << StringRef(utohexstr(MO.getImm())).lower(); + return false; + case 'x': // hex const int (low 16 bits) + if ((MO.getType()) != MachineOperand::MO_Immediate) + return true; + O << "0x" << StringRef(utohexstr(MO.getImm() & 0xffff)).lower(); + return false; + case 'd': // decimal const int + if ((MO.getType()) != MachineOperand::MO_Immediate) + return true; + O << MO.getImm(); + return false; + case 'm': // decimal const int minus 1 + if ((MO.getType()) != MachineOperand::MO_Immediate) + return true; + O << MO.getImm() - 1; + return false; + case 'z': { + // $0 if zero, regular printing otherwise + if (MO.getType() != MachineOperand::MO_Immediate) + return true; + int64_t Val = MO.getImm(); + if (Val) + O << Val; + else + O << "$0"; + return false; + } + case 'D': // Second part of a double word register operand + case 'L': // Low order register of a double word register operand + case 'M': // High order register of a double word register operand + { + if (OpNum == 0) + return true; + const MachineOperand &FlagsOP = MI->getOperand(OpNum - 1); + if (!FlagsOP.isImm()) + return true; + unsigned Flags = FlagsOP.getImm(); + unsigned NumVals = InlineAsm::getNumOperandRegisters(Flags); + // Number of registers represented by this operand. We are looking + // for 2 for 32 bit mode and 1 for 64 bit mode. + if (NumVals != 2) { + if (Subtarget->isGP64bit() && NumVals == 1 && MO.isReg()) { + unsigned Reg = MO.getReg(); + O << '$' << MipsInstPrinter::getRegisterName(Reg); + return false; + } + return true; + } + + unsigned RegOp = OpNum; + if (!Subtarget->isGP64bit()){ + // Endianess reverses which register holds the high or low value + // between M and L. + switch(ExtraCode[0]) { + case 'M': + RegOp = (Subtarget->isLittle()) ? OpNum + 1 : OpNum; + break; + case 'L': + RegOp = (Subtarget->isLittle()) ? OpNum : OpNum + 1; + break; + case 'D': // Always the second part + RegOp = OpNum + 1; + } + if (RegOp >= MI->getNumOperands()) + return true; + const MachineOperand &MO = MI->getOperand(RegOp); + if (!MO.isReg()) + return true; + unsigned Reg = MO.getReg(); + O << '$' << MipsInstPrinter::getRegisterName(Reg); + return false; + } + } + case 'w': + // Print MSA registers for the 'f' constraint + // In LLVM, the 'w' modifier doesn't need to do anything. + // We can just call printOperand as normal. + break; + } + } - printOperand(MI, OpNo, O); + printOperand(MI, OpNum, O); return false; } @@ -336,17 +491,25 @@ bool MipsAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNum, unsigned AsmVariant, const char *ExtraCode, raw_ostream &O) { - if (ExtraCode && ExtraCode[0]) - return true; // Unknown modifier. - + int Offset = 0; + // Currently we are expecting either no ExtraCode or 'D' + if (ExtraCode) { + if (ExtraCode[0] == 'D') + Offset = 4; + else + return true; // Unknown modifier. + } + const MachineOperand &MO = MI->getOperand(OpNum); assert(MO.isReg() && "unexpected inline asm memory operand"); - O << "0($" << MipsInstPrinter::getRegisterName(MO.getReg()) << ")"; + O << Offset << "($" << MipsInstPrinter::getRegisterName(MO.getReg()) << ")"; + return false; } void MipsAsmPrinter::printOperand(const MachineInstr *MI, int opNum, raw_ostream &O) { + const DataLayout *DL = TM.getDataLayout(); const MachineOperand &MO = MI->getOperand(opNum); bool closeP = false; @@ -385,26 +548,17 @@ void MipsAsmPrinter::printOperand(const MachineInstr *MI, int opNum, return; case MachineOperand::MO_GlobalAddress: - O << *Mang->getSymbol(MO.getGlobal()); + O << *getSymbol(MO.getGlobal()); break; case MachineOperand::MO_BlockAddress: { - MCSymbol* BA = GetBlockAddressSymbol(MO.getBlockAddress()); + MCSymbol *BA = GetBlockAddressSymbol(MO.getBlockAddress()); O << BA->getName(); break; } - case MachineOperand::MO_ExternalSymbol: - O << *GetExternalSymbolSymbol(MO.getSymbolName()); - break; - - case MachineOperand::MO_JumpTableIndex: - O << MAI->getPrivateGlobalPrefix() << "JTI" << getFunctionNumber() - << '_' << MO.getIndex(); - break; - case MachineOperand::MO_ConstantPoolIndex: - O << MAI->getPrivateGlobalPrefix() << "CPI" + O << DL->getPrivateGlobalPrefix() << "CPI" << getFunctionNumber() << "_" << MO.getIndex(); if (MO.getOffset()) O << "+" << MO.getOffset(); @@ -426,6 +580,15 @@ void MipsAsmPrinter::printUnsignedImm(const MachineInstr *MI, int opNum, printOperand(MI, opNum, O); } +void MipsAsmPrinter::printUnsignedImm8(const MachineInstr *MI, int opNum, + raw_ostream &O) { + const MachineOperand &MO = MI->getOperand(opNum); + if (MO.isImm()) + O << (unsigned short int)(unsigned char)MO.getImm(); + else + printOperand(MI, opNum, O); +} + void MipsAsmPrinter:: printMemOperand(const MachineInstr *MI, int opNum, raw_ostream &O) { // Load/Store memory operands -- imm($reg) @@ -450,40 +613,317 @@ printMemOperandEA(const MachineInstr *MI, int opNum, raw_ostream &O) { void MipsAsmPrinter:: printFCCOperand(const MachineInstr *MI, int opNum, raw_ostream &O, const char *Modifier) { - const MachineOperand& MO = MI->getOperand(opNum); + const MachineOperand &MO = MI->getOperand(opNum); O << Mips::MipsFCCToString((Mips::CondCode)MO.getImm()); } void MipsAsmPrinter::EmitStartOfAsmFile(Module &M) { - // FIXME: Use SwitchSection. + // TODO: Need to add -mabicalls and -mno-abicalls flags. + // Currently we assume that -mabicalls is the default. + bool IsABICalls = true; + if (IsABICalls) { + getTargetStreamer().emitDirectiveAbiCalls(); + Reloc::Model RM = Subtarget->getRelocationModel(); + // FIXME: This condition should be a lot more complicated that it is here. + // Ideally it should test for properties of the ABI and not the ABI + // itself. + // For the moment, I'm only correcting enough to make MIPS-IV work. + if (RM == Reloc::Static && !Subtarget->isABI_N64()) + getTargetStreamer().emitDirectiveOptionPic0(); + } // Tell the assembler which ABI we are using - if (OutStreamer.hasRawTextSupport()) - OutStreamer.EmitRawText("\t.section .mdebug." + Twine(getCurrentABIString())); + std::string SectionName = std::string(".mdebug.") + getCurrentABIString(); + OutStreamer.SwitchSection(OutContext.getELFSection( + SectionName, ELF::SHT_PROGBITS, 0, SectionKind::getDataRel())); + + // NaN: At the moment we only support: + // 1. .nan legacy (default) + // 2. .nan 2008 + Subtarget->isNaN2008() ? getTargetStreamer().emitDirectiveNaN2008() + : getTargetStreamer().emitDirectiveNaNLegacy(); // TODO: handle O64 ABI - if (OutStreamer.hasRawTextSupport()) { - if (Subtarget->isABI_EABI()) { - if (Subtarget->isGP32bit()) - OutStreamer.EmitRawText(StringRef("\t.section .gcc_compiled_long32")); - else - OutStreamer.EmitRawText(StringRef("\t.section .gcc_compiled_long64")); - } + + if (Subtarget->isABI_EABI()) { + if (Subtarget->isGP32bit()) + OutStreamer.SwitchSection( + OutContext.getELFSection(".gcc_compiled_long32", ELF::SHT_PROGBITS, 0, + SectionKind::getDataRel())); + else + OutStreamer.SwitchSection( + OutContext.getELFSection(".gcc_compiled_long64", ELF::SHT_PROGBITS, 0, + SectionKind::getDataRel())); + } +} + +void MipsAsmPrinter::EmitJal(MCSymbol *Symbol) { + MCInst I; + I.setOpcode(Mips::JAL); + I.addOperand( + MCOperand::CreateExpr(MCSymbolRefExpr::Create(Symbol, OutContext))); + OutStreamer.EmitInstruction(I, getSubtargetInfo()); +} + +void MipsAsmPrinter::EmitInstrReg(unsigned Opcode, unsigned Reg) { + MCInst I; + I.setOpcode(Opcode); + I.addOperand(MCOperand::CreateReg(Reg)); + OutStreamer.EmitInstruction(I, getSubtargetInfo()); +} + +void MipsAsmPrinter::EmitInstrRegReg(unsigned Opcode, unsigned Reg1, + unsigned Reg2) { + MCInst I; + // + // Because of the current td files for Mips32, the operands for MTC1 + // appear backwards from their normal assembly order. It's not a trivial + // change to fix this in the td file so we adjust for it here. + // + if (Opcode == Mips::MTC1) { + unsigned Temp = Reg1; + Reg1 = Reg2; + Reg2 = Temp; + } + I.setOpcode(Opcode); + I.addOperand(MCOperand::CreateReg(Reg1)); + I.addOperand(MCOperand::CreateReg(Reg2)); + OutStreamer.EmitInstruction(I, getSubtargetInfo()); +} + +void MipsAsmPrinter::EmitInstrRegRegReg(unsigned Opcode, unsigned Reg1, + unsigned Reg2, unsigned Reg3) { + MCInst I; + I.setOpcode(Opcode); + I.addOperand(MCOperand::CreateReg(Reg1)); + I.addOperand(MCOperand::CreateReg(Reg2)); + I.addOperand(MCOperand::CreateReg(Reg3)); + OutStreamer.EmitInstruction(I, getSubtargetInfo()); +} + +void MipsAsmPrinter::EmitMovFPIntPair(unsigned MovOpc, unsigned Reg1, + unsigned Reg2, unsigned FPReg1, + unsigned FPReg2, bool LE) { + if (!LE) { + unsigned temp = Reg1; + Reg1 = Reg2; + Reg2 = temp; } + EmitInstrRegReg(MovOpc, Reg1, FPReg1); + EmitInstrRegReg(MovOpc, Reg2, FPReg2); +} - // return to previous section - if (OutStreamer.hasRawTextSupport()) - OutStreamer.EmitRawText(StringRef("\t.previous")); +void MipsAsmPrinter::EmitSwapFPIntParams(Mips16HardFloatInfo::FPParamVariant PV, + bool LE, bool ToFP) { + using namespace Mips16HardFloatInfo; + unsigned MovOpc = ToFP ? Mips::MTC1 : Mips::MFC1; + switch (PV) { + case FSig: + EmitInstrRegReg(MovOpc, Mips::A0, Mips::F12); + break; + case FFSig: + EmitMovFPIntPair(MovOpc, Mips::A0, Mips::A1, Mips::F12, Mips::F14, LE); + break; + case FDSig: + EmitInstrRegReg(MovOpc, Mips::A0, Mips::F12); + EmitMovFPIntPair(MovOpc, Mips::A2, Mips::A3, Mips::F14, Mips::F15, LE); + break; + case DSig: + EmitMovFPIntPair(MovOpc, Mips::A0, Mips::A1, Mips::F12, Mips::F13, LE); + break; + case DDSig: + EmitMovFPIntPair(MovOpc, Mips::A0, Mips::A1, Mips::F12, Mips::F13, LE); + EmitMovFPIntPair(MovOpc, Mips::A2, Mips::A3, Mips::F14, Mips::F15, LE); + break; + case DFSig: + EmitMovFPIntPair(MovOpc, Mips::A0, Mips::A1, Mips::F12, Mips::F13, LE); + EmitInstrRegReg(MovOpc, Mips::A2, Mips::F14); + break; + case NoSig: + return; + } } -MachineLocation -MipsAsmPrinter::getDebugValueLocation(const MachineInstr *MI) const { - // Handles frame addresses emitted in MipsInstrInfo::emitFrameIndexDebugValue. - assert(MI->getNumOperands() == 4 && "Invalid no. of machine operands!"); - assert(MI->getOperand(0).isReg() && MI->getOperand(1).isImm() && - "Unexpected MachineOperand types"); - return MachineLocation(MI->getOperand(0).getReg(), - MI->getOperand(1).getImm()); +void +MipsAsmPrinter::EmitSwapFPIntRetval(Mips16HardFloatInfo::FPReturnVariant RV, + bool LE) { + using namespace Mips16HardFloatInfo; + unsigned MovOpc = Mips::MFC1; + switch (RV) { + case FRet: + EmitInstrRegReg(MovOpc, Mips::V0, Mips::F0); + break; + case DRet: + EmitMovFPIntPair(MovOpc, Mips::V0, Mips::V1, Mips::F0, Mips::F1, LE); + break; + case CFRet: + EmitMovFPIntPair(MovOpc, Mips::V0, Mips::V1, Mips::F0, Mips::F1, LE); + break; + case CDRet: + EmitMovFPIntPair(MovOpc, Mips::V0, Mips::V1, Mips::F0, Mips::F1, LE); + EmitMovFPIntPair(MovOpc, Mips::A0, Mips::A1, Mips::F2, Mips::F3, LE); + break; + case NoFPRet: + break; + } +} + +void MipsAsmPrinter::EmitFPCallStub( + const char *Symbol, const Mips16HardFloatInfo::FuncSignature *Signature) { + MCSymbol *MSymbol = OutContext.GetOrCreateSymbol(StringRef(Symbol)); + using namespace Mips16HardFloatInfo; + bool LE = Subtarget->isLittle(); + // + // .global xxxx + // + OutStreamer.EmitSymbolAttribute(MSymbol, MCSA_Global); + const char *RetType; + // + // make the comment field identifying the return and parameter + // types of the floating point stub + // # Stub function to call rettype xxxx (params) + // + switch (Signature->RetSig) { + case FRet: + RetType = "float"; + break; + case DRet: + RetType = "double"; + break; + case CFRet: + RetType = "complex"; + break; + case CDRet: + RetType = "double complex"; + break; + case NoFPRet: + RetType = ""; + break; + } + const char *Parms; + switch (Signature->ParamSig) { + case FSig: + Parms = "float"; + break; + case FFSig: + Parms = "float, float"; + break; + case FDSig: + Parms = "float, double"; + break; + case DSig: + Parms = "double"; + break; + case DDSig: + Parms = "double, double"; + break; + case DFSig: + Parms = "double, float"; + break; + case NoSig: + Parms = ""; + break; + } + OutStreamer.AddComment("\t# Stub function to call " + Twine(RetType) + " " + + Twine(Symbol) + " (" + Twine(Parms) + ")"); + // + // probably not necessary but we save and restore the current section state + // + OutStreamer.PushSection(); + // + // .section mips16.call.fpxxxx,"ax",@progbits + // + const MCSectionELF *M = OutContext.getELFSection( + ".mips16.call.fp." + std::string(Symbol), ELF::SHT_PROGBITS, + ELF::SHF_ALLOC | ELF::SHF_EXECINSTR, SectionKind::getText()); + OutStreamer.SwitchSection(M, 0); + // + // .align 2 + // + OutStreamer.EmitValueToAlignment(4); + MipsTargetStreamer &TS = getTargetStreamer(); + // + // .set nomips16 + // .set nomicromips + // + TS.emitDirectiveSetNoMips16(); + TS.emitDirectiveSetNoMicroMips(); + // + // .ent __call_stub_fp_xxxx + // .type __call_stub_fp_xxxx,@function + // __call_stub_fp_xxxx: + // + std::string x = "__call_stub_fp_" + std::string(Symbol); + MCSymbol *Stub = OutContext.GetOrCreateSymbol(StringRef(x)); + TS.emitDirectiveEnt(*Stub); + MCSymbol *MType = + OutContext.GetOrCreateSymbol("__call_stub_fp_" + Twine(Symbol)); + OutStreamer.EmitSymbolAttribute(MType, MCSA_ELF_TypeFunction); + OutStreamer.EmitLabel(Stub); + // + // we just handle non pic for now. these function will not be + // called otherwise. when the full stub generation is moved here + // we need to deal with pic. + // + if (Subtarget->getRelocationModel() == Reloc::PIC_) + llvm_unreachable("should not be here if we are compiling pic"); + TS.emitDirectiveSetReorder(); + // + // We need to add a MipsMCExpr class to MCTargetDesc to fully implement + // stubs without raw text but this current patch is for compiler generated + // functions and they all return some value. + // The calling sequence for non pic is different in that case and we need + // to implement %lo and %hi in order to handle the case of no return value + // See the corresponding method in Mips16HardFloat for details. + // + // mov the return address to S2. + // we have no stack space to store it and we are about to make another call. + // We need to make sure that the enclosing function knows to save S2 + // This should have already been handled. + // + // Mov $18, $31 + + EmitInstrRegRegReg(Mips::ADDu, Mips::S2, Mips::RA, Mips::ZERO); + + EmitSwapFPIntParams(Signature->ParamSig, LE, true); + + // Jal xxxx + // + EmitJal(MSymbol); + + // fix return values + EmitSwapFPIntRetval(Signature->RetSig, LE); + // + // do the return + // if (Signature->RetSig == NoFPRet) + // llvm_unreachable("should not be any stubs here with no return value"); + // else + EmitInstrReg(Mips::JR, Mips::S2); + + MCSymbol *Tmp = OutContext.CreateTempSymbol(); + OutStreamer.EmitLabel(Tmp); + const MCSymbolRefExpr *E = MCSymbolRefExpr::Create(Stub, OutContext); + const MCSymbolRefExpr *T = MCSymbolRefExpr::Create(Tmp, OutContext); + const MCExpr *T_min_E = MCBinaryExpr::CreateSub(T, E, OutContext); + OutStreamer.EmitELFSize(Stub, T_min_E); + TS.emitDirectiveEnd(x); + OutStreamer.PopSection(); +} + +void MipsAsmPrinter::EmitEndOfAsmFile(Module &M) { + // Emit needed stubs + // + for (std::map< + const char *, + const llvm::Mips16HardFloatInfo::FuncSignature *>::const_iterator + it = StubsNeeded.begin(); + it != StubsNeeded.end(); ++it) { + const char *Symbol = it->first; + const llvm::Mips16HardFloatInfo::FuncSignature *Signature = it->second; + EmitFPCallStub(Symbol, Signature); + } + // return to the text section + OutStreamer.SwitchSection(OutContext.getObjectFileInfo()->getTextSection()); } void MipsAsmPrinter::PrintDebugValueComment(const MachineInstr *MI, @@ -491,6 +931,28 @@ void MipsAsmPrinter::PrintDebugValueComment(const MachineInstr *MI, // TODO: implement } +// Align all targets of indirect branches on bundle size. Used only if target +// is NaCl. +void MipsAsmPrinter::NaClAlignIndirectJumpTargets(MachineFunction &MF) { + // Align all blocks that are jumped to through jump table. + if (MachineJumpTableInfo *JtInfo = MF.getJumpTableInfo()) { + const std::vector &JT = JtInfo->getJumpTables(); + for (unsigned I = 0; I < JT.size(); ++I) { + const std::vector &MBBs = JT[I].MBBs; + + for (unsigned J = 0; J < MBBs.size(); ++J) + MBBs[J]->setAlignment(MIPS_NACL_BUNDLE_ALIGN); + } + } + + // If basic block address is taken, block can be target of indirect branch. + for (MachineFunction::iterator MBB = MF.begin(), E = MF.end(); + MBB != E; ++MBB) { + if (MBB->hasAddressTaken()) + MBB->setAlignment(MIPS_NACL_BUNDLE_ALIGN); + } +} + // Force static initialization. extern "C" void LLVMInitializeMipsAsmPrinter() { RegisterAsmPrinter X(TheMipsTarget);