X-Git-Url: http://plrg.eecs.uci.edu/git/?a=blobdiff_plain;f=lib%2FTarget%2FMips%2FMipsAsmPrinter.cpp;h=9b7e191401305535c8a304d8511f2604541b47f5;hb=4396f5d9d2c215988f9368e94bfd5e1eb1cced58;hp=b60729a80f0b163b4e279fca285fa6b7ec16ed3d;hpb=d2947ee33e810b24a016b944b375d34910f8f5dd;p=oota-llvm.git diff --git a/lib/Target/Mips/MipsAsmPrinter.cpp b/lib/Target/Mips/MipsAsmPrinter.cpp index b60729a80f0..a5ac2ab8bc4 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,84 +13,126 @@ //===----------------------------------------------------------------------===// #define DEBUG_TYPE "mips-asm-printer" - +#include "InstPrinter/MipsInstPrinter.h" +#include "MCTargetDesc/MipsBaseInfo.h" #include "Mips.h" +#include "MipsAsmPrinter.h" #include "MipsInstrInfo.h" -#include "MipsTargetMachine.h" -#include "MipsMachineFunction.h" -#include "llvm/Constants.h" -#include "llvm/DerivedTypes.h" -#include "llvm/Module.h" -#include "llvm/CodeGen/AsmPrinter.h" -#include "llvm/CodeGen/MachineFunctionPass.h" +#include "MipsMCInstLower.h" +#include "MipsTargetStreamer.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/Twine.h" #include "llvm/CodeGen/MachineConstantPool.h" #include "llvm/CodeGen/MachineFrameInfo.h" +#include "llvm/CodeGen/MachineFunctionPass.h" #include "llvm/CodeGen/MachineInstr.h" -#include "llvm/Target/TargetAsmInfo.h" -#include "llvm/Target/TargetData.h" -#include "llvm/Target/TargetMachine.h" +#include "llvm/CodeGen/MachineMemOperand.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/MCInst.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/TargetLoweringObjectFile.h" #include "llvm/Target/TargetOptions.h" -#include "llvm/Support/Mangler.h" -#include "llvm/ADT/Statistic.h" -#include "llvm/ADT/SetVector.h" -#include "llvm/ADT/StringExtras.h" -#include "llvm/Support/Debug.h" -#include "llvm/Support/CommandLine.h" -#include "llvm/Support/MathExtras.h" -#include using namespace llvm; -STATISTIC(EmittedInsts, "Number of machine instrs printed"); +MipsTargetStreamer &MipsAsmPrinter::getTargetStreamer() { + return static_cast(*OutStreamer.getTargetStreamer()); +} -namespace { - struct VISIBILITY_HIDDEN MipsAsmPrinter : public AsmPrinter { - MipsAsmPrinter(std::ostream &O, MipsTargetMachine &TM, - const TargetAsmInfo *T): - AsmPrinter(O, TM, T) {} +bool MipsAsmPrinter::runOnMachineFunction(MachineFunction &MF) { + // Initialize TargetLoweringObjectFile. + if (Subtarget->allowMixed16_32()) + const_cast(getObjFileLowering()) + .Initialize(OutContext, TM); + MipsFI = MF.getInfo(); + MCP = MF.getConstantPool(); + AsmPrinter::runOnMachineFunction(MF); + return true; +} - virtual const char *getPassName() const { - return "Mips Assembly Printer"; +bool MipsAsmPrinter::lowerOperand(const MachineOperand &MO, MCOperand &MCOp) { + MCOp = MCInstLowering.LowerOperand(MO); + return MCOp.isValid(); +} + +#include "MipsGenMCPseudoLowering.inc" + +void MipsAsmPrinter::EmitInstruction(const MachineInstr *MI) { + if (MI->isDebugValue()) { + SmallString<128> Str; + raw_svector_ostream OS(Str); + + PrintDebugValueComment(MI, OS); + return; + } + + // 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; } - enum SetDirectiveFlags { - REORDER, // enables instruction reordering. - NOREORDER, // disables instruction reordering. - MACRO, // enables GAS macros. - NOMACRO // disables GAS macros. - }; - - void printOperand(const MachineInstr *MI, int opNum); - void printMemOperand(const MachineInstr *MI, int opNum, - const char *Modifier = 0); - - unsigned int getSavedRegsBitmask(bool isFloat, MachineFunction &MF); - void printHex32(unsigned int Value); - - void emitFunctionStart(MachineFunction &MF); - void emitFunctionEnd(MachineFunction &MF); - void emitFrameDirective(MachineFunction &MF); - void emitMaskDirective(MachineFunction &MF); - void emitFMaskDirective(MachineFunction &MF); - void emitSetDirective(SetDirectiveFlags Flag); - - bool printInstruction(const MachineInstr *MI); // autogenerated. - bool runOnMachineFunction(MachineFunction &F); - bool doInitialization(Module &M); - bool doFinalization(Module &M); - }; -} // end of anonymous namespace - -#include "MipsGenAsmWriter.inc" - -/// createMipsCodePrinterPass - Returns a pass that prints the MIPS -/// assembly code for a MachineFunction to the given output stream, -/// using the given target machine description. This should work -/// regardless of whether the function is in SSA form. -FunctionPass *llvm::createMipsCodePrinterPass(std::ostream &o, - MipsTargetMachine &tm) -{ - return new MipsAsmPrinter(o, tm, tm.getTargetAsmInfo()); + OutStreamer.EmitLabel(GetCPISymbol(LabelId)); + + const MachineConstantPoolEntry &MCPE = MCP->getConstants()[CPIdx]; + if (MCPE.isMachineConstantPoolEntry()) + EmitMachineConstantPoolValue(MCPE.Val.MachineCPVal); + else + EmitGlobalConstant(MCPE.Val.ConstVal); + return; + } + + + 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 } //===----------------------------------------------------------------------===// @@ -100,12 +142,12 @@ FunctionPass *llvm::createMipsCodePrinterPass(std::ostream &o, // -- Frame directive "frame Stackpointer, Stacksize, RARegister" // Describe the stack frame. // -// -- Mask directives "(f)mask bitmask, offset" +// -- Mask directives "(f)mask bitmask, offset" // Tells the assembler which registers are saved and where. -// bitmask - contain a little endian bitset indicating which registers are -// saved on function prologue (e.g. with a 0x80000000 mask, the +// bitmask - contain a little endian bitset indicating which registers are +// saved on function prologue (e.g. with a 0x80000000 mask, the // assembler knows the register 31 (RA) is saved at prologue. -// offset - the position before stack pointer subtraction indicating where +// offset - the position before stack pointer subtraction indicating where // the first saved register on prologue is located. (e.g. with a // // Consider the following function prologue: @@ -116,438 +158,484 @@ FunctionPass *llvm::createMipsCodePrinterPass(std::ostream &o, // sw $ra, 40($sp) // sw $fp, 36($sp) // -// With a 0xc0000000 mask, the assembler knows the register 31 (RA) and -// 30 (FP) are saved at prologue. As the save order on prologue is from -// left to right, RA is saved first. A -8 offset means that after the +// With a 0xc0000000 mask, the assembler knows the register 31 (RA) and +// 30 (FP) are saved at prologue. As the save order on prologue is from +// left to right, RA is saved first. A -8 offset means that after the // stack pointer subtration, the first register in the mask (RA) will be // saved at address 48-8=40. // //===----------------------------------------------------------------------===// -/// Mask directive for GPR -void MipsAsmPrinter:: -emitMaskDirective(MachineFunction &MF) -{ - MipsFunctionInfo *MipsFI = MF.getInfo(); - - int StackSize = MF.getFrameInfo()->getStackSize(); - int Offset = (!MipsFI->getTopSavedRegOffset()) ? 0 : - (-(StackSize-MipsFI->getTopSavedRegOffset())); - - #ifndef NDEBUG - DOUT << "--> emitMaskDirective" << "\n"; - DOUT << "StackSize : " << StackSize << "\n"; - DOUT << "getTopSavedReg : " << MipsFI->getTopSavedRegOffset() << "\n"; - DOUT << "Offset : " << Offset << "\n\n"; - #endif - - unsigned int Bitmask = getSavedRegsBitmask(false, MF); - O << "\t.mask \t"; - printHex32(Bitmask); - O << "," << Offset << "\n"; -} +//===----------------------------------------------------------------------===// +// Mask directives +//===----------------------------------------------------------------------===// -/// TODO: Mask Directive for Float Point -void MipsAsmPrinter:: -emitFMaskDirective(MachineFunction &MF) -{ - unsigned int Bitmask = getSavedRegsBitmask(true, MF); +// 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() { + // CPU and FPU Saved Registers Bitmasks + unsigned CPUBitmask = 0, FPUBitmask = 0; + int CPUTopSavedRegOff, FPUTopSavedRegOff; - O << "\t.fmask\t"; - printHex32(Bitmask); - O << ",0" << "\n"; -} + // Set the CPU and FPU Bitmasks + 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::GPR32RegClass.getSize(); + unsigned FGR32RegSize = Mips::FGR32RegClass.getSize(); + unsigned AFGR64RegSize = Mips::AFGR64RegClass.getSize(); + bool HasAFGR64Reg = false; + unsigned CSFPRegsSize = 0; + unsigned i, e = CSI.size(); + + // Set FPU Bitmask. + for (i = 0; i != e; ++i) { + unsigned Reg = CSI[i].getReg(); + if (Mips::GPR32RegClass.contains(Reg)) + break; -/// Frame Directive -void MipsAsmPrinter:: -emitFrameDirective(MachineFunction &MF) -{ - const TargetRegisterInfo &RI = *TM.getRegisterInfo(); + unsigned RegNum = TM.getRegisterInfo()->getEncodingValue(Reg); + if (Mips::AFGR64RegClass.contains(Reg)) { + FPUBitmask |= (3 << RegNum); + CSFPRegsSize += AFGR64RegSize; + HasAFGR64Reg = true; + continue; + } - unsigned stackReg = RI.getFrameRegister(MF); - unsigned returnReg = RI.getRARegister(); - unsigned stackSize = MF.getFrameInfo()->getStackSize(); + FPUBitmask |= (1 << RegNum); + CSFPRegsSize += FGR32RegSize; + } + // Set CPU Bitmask. + for (; i != e; ++i) { + unsigned Reg = CSI[i].getReg(); + unsigned RegNum = TM.getRegisterInfo()->getEncodingValue(Reg); + CPUBitmask |= (1 << RegNum); + } - O << "\t.frame\t" << "$" << LowercaseString(RI.get(stackReg).AsmName) - << "," << stackSize << "," - << "$" << LowercaseString(RI.get(returnReg).AsmName) - << "\n"; -} + // FP Regs are saved right below where the virtual frame pointer points to. + FPUTopSavedRegOff = FPUBitmask ? + (HasAFGR64Reg ? -AFGR64RegSize : -FGR32RegSize) : 0; -/// Emit Set directives. -void MipsAsmPrinter:: -emitSetDirective(SetDirectiveFlags Flag) -{ - O << "\t.set\t"; - switch(Flag) { - case REORDER: O << "reorder" << "\n"; break; - case NOREORDER: O << "noreorder" << "\n"; break; - case MACRO: O << "macro" << "\n"; break; - case NOMACRO: O << "nomacro" << "\n"; break; - default: break; - } -} - -// Create a bitmask with all callee saved registers for CPU -// or Float Point registers. For CPU registers consider RA, -// GP and FP for saving if necessary. -unsigned int MipsAsmPrinter:: -getSavedRegsBitmask(bool isFloat, MachineFunction &MF) -{ - const TargetRegisterInfo &RI = *TM.getRegisterInfo(); - - // Float Point Registers, TODO - if (isFloat) - return 0; + // CPU Regs are saved below FP Regs. + CPUTopSavedRegOff = CPUBitmask ? -CSFPRegsSize - CPURegSize : 0; - // CPU Registers - unsigned int Bitmask = 0; + MipsTargetStreamer &TS = getTargetStreamer(); + // Print CPUBitmask + TS.emitMask(CPUBitmask, CPUTopSavedRegOff); - MachineFrameInfo *MFI = MF.getFrameInfo(); - const std::vector &CSI = MFI->getCalleeSavedInfo(); - for (unsigned i = 0, e = CSI.size(); i != e; ++i) - Bitmask |= (1 << MipsRegisterInfo::getRegisterNumbering(CSI[i].getReg())); - - if (RI.hasFP(MF)) - Bitmask |= (1 << MipsRegisterInfo:: - getRegisterNumbering(RI.getFrameRegister(MF))); - - if (MF.getFrameInfo()->hasCalls()) - Bitmask |= (1 << MipsRegisterInfo:: - getRegisterNumbering(RI.getRARegister())); - - return Bitmask; + // Print FPUBitmask + TS.emitFMask(FPUBitmask, FPUTopSavedRegOff); } -// Print a 32 bit hex number with all numbers. -void MipsAsmPrinter:: -printHex32(unsigned int Value) -{ - O << "0x" << std::hex; - for (int i = 7; i >= 0; i--) - O << std::hex << ( (Value & (0xF << (i*4))) >> (i*4) ); - O << std::dec; +//===----------------------------------------------------------------------===// +// Frame and Set directives +//===----------------------------------------------------------------------===// + +/// Frame Directive +void MipsAsmPrinter::emitFrameDirective() { + const TargetRegisterInfo &RI = *TM.getRegisterInfo(); + + unsigned stackReg = RI.getFrameRegister(*MF); + unsigned returnReg = RI.getRARegister(); + unsigned stackSize = MF->getFrameInfo()->getStackSize(); + + getTargetStreamer().emitFrame(stackReg, stackSize, returnReg); } -/// Emit the directives used by GAS on the start of functions -void MipsAsmPrinter:: -emitFunctionStart(MachineFunction &MF) -{ - // Print out the label for the function. - const Function *F = MF.getFunction(); - SwitchToTextSection(getSectionForFunction(*F).c_str(), F); - - // 2 bits aligned - EmitAlignment(2, F); - - O << "\t.globl\t" << CurrentFnName << "\n"; - O << "\t.ent\t" << CurrentFnName << "\n"; - O << "\t.type\t" << CurrentFnName << ", @function\n"; - O << CurrentFnName << ":\n"; - - emitFrameDirective(MF); - emitMaskDirective(MF); - emitFMaskDirective(MF); - - if (TM.getRelocationModel() == Reloc::Static) { - emitSetDirective(NOREORDER); - emitSetDirective(NOMACRO); +/// Emit Set directives. +const char *MipsAsmPrinter::getCurrentABIString() const { + switch (Subtarget->getTargetABI()) { + case MipsSubtarget::O32: return "abi32"; + case MipsSubtarget::N32: return "abiN32"; + case MipsSubtarget::N64: return "abi64"; + case MipsSubtarget::EABI: return "eabi32"; // TODO: handle eabi64 + default: llvm_unreachable("Unknown Mips ABI"); } - - O << "\n"; } -/// Emit the directives used by GAS on the end of functions -void MipsAsmPrinter:: -emitFunctionEnd(MachineFunction &MF) -{ - if (TM.getRelocationModel() == Reloc::Static) { - emitSetDirective(MACRO); - emitSetDirective(REORDER); - } - - O << "\t.end\t" << CurrentFnName << "\n"; +void MipsAsmPrinter::EmitFunctionEntryLabel() { + MipsTargetStreamer &TS = getTargetStreamer(); + if (Subtarget->inMicroMipsMode()) + TS.emitDirectiveSetMicroMips(); + // leave out until FSF available gas has micromips changes + // else + // TS.emitDirectiveSetNoMicroMips(); + + if (Subtarget->inMips16Mode()) + TS.emitDirectiveSetMips16(); + else + TS.emitDirectiveSetNoMips16(); + + TS.emitDirectiveEnt(*CurrentFnSym); + OutStreamer.EmitLabel(CurrentFnSym); } -/// runOnMachineFunction - This uses the printMachineInstruction() -/// method to print assembly for each instruction. -bool MipsAsmPrinter:: -runOnMachineFunction(MachineFunction &MF) -{ - SetupMachineFunction(MF); +/// EmitFunctionBodyStart - Targets can override this to emit stuff before +/// the first basic block in the function. +void MipsAsmPrinter::EmitFunctionBodyStart() { + MipsTargetStreamer &TS = getTargetStreamer(); + + MCInstLowering.Initialize(&MF->getContext()); - // Print out constants referenced by the function - EmitConstantPool(MF.getConstantPool()); + bool IsNakedFunction = + MF->getFunction()-> + getAttributes().hasAttribute(AttributeSet::FunctionIndex, + Attribute::Naked); + if (!IsNakedFunction) + emitFrameDirective(); - // Print out jump tables referenced by the function - EmitJumpTableInfo(MF.getJumpTableInfo(), MF); + if (!IsNakedFunction) + printSavedRegsBitmask(); - O << "\n\n"; + if (!Subtarget->inMips16Mode()) { + TS.emitDirectiveSetNoReorder(); + TS.emitDirectiveSetNoMacro(); + TS.emitDirectiveSetNoAt(); + } +} - // What's my mangled name? - CurrentFnName = Mang->getValueName(MF.getFunction()); +/// 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 (!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); +} - // Emit the function start directives - emitFunctionStart(MF); +/// isBlockOnlyReachableByFallthough - Return true if the basic block has +/// exactly one predecessor and the control transfer mechanism between +/// the predecessor and this block is a fall-through. +bool MipsAsmPrinter::isBlockOnlyReachableByFallthrough(const MachineBasicBlock* + MBB) const { + // The predecessor has to be immediately before this block. + const MachineBasicBlock *Pred = *MBB->pred_begin(); + + // If the predecessor is a switch statement, assume a jump table + // implementation, so it is not a fall through. + if (const BasicBlock *bb = Pred->getBasicBlock()) + if (isa(bb->getTerminator())) + return false; + + // If this is a landing pad, it isn't a fall through. If it has no preds, + // then nothing falls through to it. + if (MBB->isLandingPad() || MBB->pred_empty()) + return false; + + // 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; + + // 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(); + while (I != Pred->begin() && !(--I)->isTerminator()) ; + + return !I->isBarrier(); +} - // Print out code for the function. - for (MachineFunction::const_iterator I = MF.begin(), E = MF.end(); - I != E; ++I) { +// Print out an operand for an inline asm expression. +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]) { + if (ExtraCode[1] != 0) return true; // Unknown modifier. - // Print a label for the basic block. - if (I != MF.begin()) { - printBasicBlockLabel(I, true, true); - O << '\n'; + 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; } - - for (MachineBasicBlock::const_iterator II = I->begin(), E = I->end(); - II != E; ++II) { - // Print the assembly for the instruction. - printInstruction(II); - ++EmittedInsts; + 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; } + } - // Each Basic Block is separated by a newline - O << '\n'; + printOperand(MI, OpNum, O); + return false; +} + +bool MipsAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, + unsigned OpNum, unsigned AsmVariant, + const char *ExtraCode, + raw_ostream &O) { + 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. } - // Emit function end directives - emitFunctionEnd(MF); + const MachineOperand &MO = MI->getOperand(OpNum); + assert(MO.isReg() && "unexpected inline asm memory operand"); + O << Offset << "($" << MipsInstPrinter::getRegisterName(MO.getReg()) << ")"; - // We didn't modify anything. return false; } -void MipsAsmPrinter:: -printOperand(const MachineInstr *MI, int opNum) -{ +void MipsAsmPrinter::printOperand(const MachineInstr *MI, int opNum, + raw_ostream &O) { + const DataLayout *DL = TM.getDataLayout(); const MachineOperand &MO = MI->getOperand(opNum); - const TargetRegisterInfo &RI = *TM.getRegisterInfo(); bool closeP = false; - bool isPIC = (TM.getRelocationModel() == Reloc::PIC_); - bool isCodeLarge = (TM.getCodeModel() == CodeModel::Large); - - // %hi and %lo used on mips gas to load global addresses on - // static code. %got is used to load global addresses when - // using PIC_. %call16 is used to load direct call targets - // on PIC_ and small code size. %call_lo and %call_hi load - // direct call targets on PIC_ and large code size. - if (MI->getOpcode() == Mips::LUi && !MO.isRegister() - && !MO.isImmediate()) { - if ((isPIC) && (isCodeLarge)) - O << "%call_hi("; - else - O << "%hi("; - closeP = true; - } else if ((MI->getOpcode() == Mips::ADDiu) && !MO.isRegister() - && !MO.isImmediate()) { - O << "%lo("; + + if (MO.getTargetFlags()) closeP = true; - } else if ((isPIC) && (MI->getOpcode() == Mips::LW) - && (!MO.isRegister()) && (!MO.isImmediate())) { - const MachineOperand &firstMO = MI->getOperand(opNum-1); - const MachineOperand &lastMO = MI->getOperand(opNum+1); - if ((firstMO.isRegister()) && (lastMO.isRegister())) { - if ((firstMO.getReg() == Mips::T9) && (lastMO.getReg() == Mips::GP) - && (!isCodeLarge)) - O << "%call16("; - else if ((firstMO.getReg() != Mips::T9) && (lastMO.getReg() == Mips::GP)) - O << "%got("; - else if ((firstMO.getReg() == Mips::T9) && (lastMO.getReg() != Mips::GP) - && (isCodeLarge)) - O << "%call_lo("; - closeP = true; - } + + switch(MO.getTargetFlags()) { + case MipsII::MO_GPREL: O << "%gp_rel("; break; + case MipsII::MO_GOT_CALL: O << "%call16("; break; + case MipsII::MO_GOT: O << "%got("; break; + case MipsII::MO_ABS_HI: O << "%hi("; break; + case MipsII::MO_ABS_LO: O << "%lo("; break; + case MipsII::MO_TLSGD: O << "%tlsgd("; break; + case MipsII::MO_GOTTPREL: O << "%gottprel("; break; + case MipsII::MO_TPREL_HI: O << "%tprel_hi("; break; + case MipsII::MO_TPREL_LO: O << "%tprel_lo("; break; + case MipsII::MO_GPOFF_HI: O << "%hi(%neg(%gp_rel("; break; + case MipsII::MO_GPOFF_LO: O << "%lo(%neg(%gp_rel("; break; + case MipsII::MO_GOT_DISP: O << "%got_disp("; break; + case MipsII::MO_GOT_PAGE: O << "%got_page("; break; + case MipsII::MO_GOT_OFST: O << "%got_ofst("; break; } - - switch (MO.getType()) - { + + switch (MO.getType()) { case MachineOperand::MO_Register: - if (TargetRegisterInfo::isPhysicalRegister(MO.getReg())) - O << "$" << LowercaseString (RI.get(MO.getReg()).AsmName); - else - O << "$" << MO.getReg(); + O << '$' + << StringRef(MipsInstPrinter::getRegisterName(MO.getReg())).lower(); break; case MachineOperand::MO_Immediate: - if ((MI->getOpcode() == Mips::SLTiu) || (MI->getOpcode() == Mips::ORi) || - (MI->getOpcode() == Mips::LUi) || (MI->getOpcode() == Mips::ANDi)) - O << (unsigned short int)MO.getImm(); - else - O << (short int)MO.getImm(); + O << MO.getImm(); break; case MachineOperand::MO_MachineBasicBlock: - printBasicBlockLabel(MO.getMBB()); + O << *MO.getMBB()->getSymbol(); return; case MachineOperand::MO_GlobalAddress: - O << Mang->getValueName(MO.getGlobal()); + O << *getSymbol(MO.getGlobal()); break; - case MachineOperand::MO_ExternalSymbol: - O << MO.getSymbolName(); - break; - - case MachineOperand::MO_JumpTableIndex: - O << TAI->getPrivateGlobalPrefix() << "JTI" << getFunctionNumber() - << '_' << MO.getIndex(); + case MachineOperand::MO_BlockAddress: { + MCSymbol *BA = GetBlockAddressSymbol(MO.getBlockAddress()); + O << BA->getName(); break; + } - // FIXME: Verify correct case MachineOperand::MO_ConstantPoolIndex: - O << TAI->getPrivateGlobalPrefix() << "CPI" + O << DL->getPrivateGlobalPrefix() << "CPI" << getFunctionNumber() << "_" << MO.getIndex(); + if (MO.getOffset()) + O << "+" << MO.getOffset(); break; - + default: - O << ""; abort (); break; + llvm_unreachable(""); } if (closeP) O << ")"; } -void MipsAsmPrinter:: -printMemOperand(const MachineInstr *MI, int opNum, const char *Modifier) -{ - // when using stack locations for not load/store instructions - // print the same way as all normal 3 operand instructions. - if (Modifier && !strcmp(Modifier, "stackloc")) { - printOperand(MI, opNum+1); - O << ", "; - printOperand(MI, opNum); - return; - } +void MipsAsmPrinter::printUnsignedImm(const MachineInstr *MI, int opNum, + raw_ostream &O) { + const MachineOperand &MO = MI->getOperand(opNum); + if (MO.isImm()) + O << (unsigned short int)MO.getImm(); + else + 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); +} - // Load/Store memory operands -- imm($reg) - // If PIC target the target is loaded as the +void MipsAsmPrinter:: +printMemOperand(const MachineInstr *MI, int opNum, raw_ostream &O) { + // Load/Store memory operands -- imm($reg) + // If PIC target the target is loaded as the // pattern lw $25,%call16($28) - printOperand(MI, opNum); + printOperand(MI, opNum+1, O); O << "("; - printOperand(MI, opNum+1); + printOperand(MI, opNum, O); O << ")"; } -bool MipsAsmPrinter:: -doInitialization(Module &M) -{ - Mang = new Mangler(M); - return false; // success +void MipsAsmPrinter:: +printMemOperandEA(const MachineInstr *MI, int opNum, raw_ostream &O) { + // when using stack locations for not load/store instructions + // print the same way as all normal 3 operand instructions. + printOperand(MI, opNum, O); + O << ", "; + printOperand(MI, opNum+1, O); + return; +} + +void MipsAsmPrinter:: +printFCCOperand(const MachineInstr *MI, int opNum, raw_ostream &O, + const char *Modifier) { + const MachineOperand &MO = MI->getOperand(opNum); + O << Mips::MipsFCCToString((Mips::CondCode)MO.getImm()); } -bool MipsAsmPrinter:: -doFinalization(Module &M) -{ - const TargetData *TD = TM.getTargetData(); - - // Print out module-level global variables here. - for (Module::const_global_iterator I = M.global_begin(), - E = M.global_end(); I != E; ++I) - - // External global require no code - if (I->hasInitializer()) { - - // Check to see if this is a special global - // used by LLVM, if so, emit it. - if (EmitSpecialLLVMGlobal(I)) - continue; - - O << "\n\n"; - std::string name = Mang->getValueName(I); - Constant *C = I->getInitializer(); - unsigned Size = TD->getABITypeSize(C->getType()); - unsigned Align = TD->getPreferredAlignmentLog(I); - - // Is this correct ? - if (C->isNullValue() && (I->hasLinkOnceLinkage() || - I->hasInternalLinkage() || I->hasWeakLinkage() || - I->hasCommonLinkage())) - { - if (Size == 0) Size = 1; // .comm Foo, 0 is undefined, avoid it. - - if (!NoZerosInBSS && TAI->getBSSSection()) - SwitchToDataSection(TAI->getBSSSection(), I); - else - SwitchToDataSection(TAI->getDataSection(), I); - - if (I->hasInternalLinkage()) { - if (TAI->getLCOMMDirective()) - O << TAI->getLCOMMDirective() << name << "," << Size; - else - O << "\t.local\t" << name << "\n"; - } else { - O << TAI->getCOMMDirective() << name << "," << Size; - // The .comm alignment in bytes. - if (TAI->getCOMMDirectiveTakesAlignment()) - O << "," << (1 << Align); - } +void MipsAsmPrinter::EmitStartOfAsmFile(Module &M) { + // TODO: Need to add -mabicalls and -mno-abicalls flags. + // Currently we assume that -mabicalls is the default. + getTargetStreamer().emitDirectiveAbiCalls(); + Reloc::Model RM = Subtarget->getRelocationModel(); + if (RM == Reloc::Static && !Subtarget->hasMips64()) + getTargetStreamer().emitDirectiveOptionPic0(); + + // Tell the assembler which ABI we are using + std::string SectionName = std::string(".mdebug.") + getCurrentABIString(); + OutStreamer.SwitchSection(OutContext.getELFSection( + SectionName, ELF::SHT_PROGBITS, 0, SectionKind::getDataRel())); + + // TODO: handle O64 ABI + + 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())); + } - } else { - - switch (I->getLinkage()) - { - case GlobalValue::LinkOnceLinkage: - case GlobalValue::CommonLinkage: - case GlobalValue::WeakLinkage: - // FIXME: Verify correct for weak. - // Nonnull linkonce -> weak - O << "\t.weak " << name << "\n"; - SwitchToDataSection("", I); - O << "\t.section\t\".llvm.linkonce.d." << name - << "\",\"aw\",@progbits\n"; - break; - case GlobalValue::AppendingLinkage: - // FIXME: appending linkage variables - // should go into a section of their name or - // something. For now, just emit them as external. - case GlobalValue::ExternalLinkage: - // If external or appending, declare as a global symbol - O << TAI->getGlobalDirective() << name << "\n"; - // Fall Through - case GlobalValue::InternalLinkage: - // FIXME: special handling for ".ctors" & ".dtors" sections - if (I->hasSection() && (I->getSection() == ".ctors" || - I->getSection() == ".dtors")) { - std::string SectionName = ".section " + I->getSection(); - SectionName += ",\"aw\",%progbits"; - SwitchToDataSection(SectionName.c_str()); - } else { - if (C->isNullValue() && !NoZerosInBSS && TAI->getBSSSection()) - SwitchToDataSection(TAI->getBSSSection(), I); - else if (!I->isConstant()) - SwitchToDataSection(TAI->getDataSection(), I); - else { - // Read-only data. - if (TAI->getReadOnlySection()) - SwitchToDataSection(TAI->getReadOnlySection(), I); - else - SwitchToDataSection(TAI->getDataSection(), I); - } - } - break; - case GlobalValue::GhostLinkage: - cerr << "Should not have any unmaterialized functions!\n"; - abort(); - case GlobalValue::DLLImportLinkage: - cerr << "DLLImport linkage is not supported by this target!\n"; - abort(); - case GlobalValue::DLLExportLinkage: - cerr << "DLLExport linkage is not supported by this target!\n"; - abort(); - default: - assert(0 && "Unknown linkage type!"); - } + // return to the text section + OutStreamer.SwitchSection(OutContext.getObjectFileInfo()->getTextSection()); +} - O << "\t.align " << Align << "\n"; - O << "\t.type " << name << ",@object\n"; - O << "\t.size " << name << "," << Size << "\n"; - O << name << ":\n"; - EmitGlobalConstant(C); - } - } +void MipsAsmPrinter::EmitEndOfAsmFile(Module &M) { + // Emit Mips ELF register info + Subtarget->getMReginfo().emitMipsReginfoSectionCG( + OutStreamer, getObjFileLowering(), *Subtarget); +} - O << "\n"; +void MipsAsmPrinter::PrintDebugValueComment(const MachineInstr *MI, + raw_ostream &OS) { + // TODO: implement +} - return AsmPrinter::doFinalization(M); +// Force static initialization. +extern "C" void LLVMInitializeMipsAsmPrinter() { + RegisterAsmPrinter X(TheMipsTarget); + RegisterAsmPrinter Y(TheMipselTarget); + RegisterAsmPrinter A(TheMips64Target); + RegisterAsmPrinter B(TheMips64elTarget); }