X-Git-Url: http://demsky.eecs.uci.edu/git/?a=blobdiff_plain;f=lib%2FTarget%2FARM%2FARMAsmPrinter.cpp;h=003de2b0263b7a4ca3ea3c9266d525795ab5f547;hb=5d42c567c901508e80ab10ddba1bb30a5007d742;hp=0f0a5419dd68ec8883072619c7f911f32af66626;hpb=42d712b3067ec14170f80d8adfc7e5ad5878132b;p=oota-llvm.git diff --git a/lib/Target/ARM/ARMAsmPrinter.cpp b/lib/Target/ARM/ARMAsmPrinter.cpp index 0f0a5419dd6..003de2b0263 100644 --- a/lib/Target/ARM/ARMAsmPrinter.cpp +++ b/lib/Target/ARM/ARMAsmPrinter.cpp @@ -1,9 +1,8 @@ -//===-- ARMAsmPrinter.cpp - ARM LLVM assembly writer ----------------------===// +//===-- ARMAsmPrinter.cpp - Print machine code to an ARM .s file ----------===// // // The LLVM Compiler Infrastructure // -// This file was developed by the "Instituto Nokia de Tecnologia" and -// is distributed under the University of Illinois Open Source +// This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// @@ -15,158 +14,312 @@ #define DEBUG_TYPE "asm-printer" #include "ARM.h" -#include "ARMTargetMachine.h" +#include "ARMBuildAttrs.h" #include "ARMAddressingModes.h" #include "ARMConstantPoolValue.h" +#include "AsmPrinter/ARMInstPrinter.h" #include "ARMMachineFunctionInfo.h" +#include "ARMMCInstLower.h" +#include "ARMTargetMachine.h" +#include "llvm/Analysis/DebugInfo.h" #include "llvm/Constants.h" #include "llvm/Module.h" +#include "llvm/Type.h" +#include "llvm/Assembly/Writer.h" #include "llvm/CodeGen/AsmPrinter.h" -#include "llvm/CodeGen/DwarfWriter.h" -#include "llvm/CodeGen/MachineModuleInfo.h" +#include "llvm/CodeGen/MachineModuleInfoImpls.h" #include "llvm/CodeGen/MachineFunctionPass.h" #include "llvm/CodeGen/MachineJumpTableInfo.h" -#include "llvm/Target/TargetAsmInfo.h" +#include "llvm/CodeGen/TargetLoweringObjectFileImpl.h" +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCInst.h" +#include "llvm/MC/MCSectionMachO.h" +#include "llvm/MC/MCStreamer.h" +#include "llvm/MC/MCSymbol.h" +#include "llvm/Target/Mangler.h" #include "llvm/Target/TargetData.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetOptions.h" -#include "llvm/ADT/Statistic.h" +#include "llvm/Target/TargetRegistry.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringExtras.h" -#include "llvm/Support/Compiler.h" -#include "llvm/Support/Mangler.h" -#include "llvm/Support/MathExtras.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" #include using namespace llvm; -STATISTIC(EmittedInsts, "Number of machine instrs printed"); +static cl::opt +EnableMCInst("enable-arm-mcinst-printer", cl::Hidden, cl::init(true), + cl::desc("enable experimental asmprinter gunk in the arm backend")); -namespace { - struct VISIBILITY_HIDDEN ARMAsmPrinter : public AsmPrinter { - ARMAsmPrinter(std::ostream &O, TargetMachine &TM, const TargetAsmInfo *T) - : AsmPrinter(O, TM, T), DW(O, this, T), AFI(NULL), InCPMode(false) { - Subtarget = &TM.getSubtarget(); - } +namespace llvm { + namespace ARM { + enum DW_ISA { + DW_ISA_ARM_thumb = 1, + DW_ISA_ARM_arm = 2 + }; + } +} - DwarfWriter DW; +namespace { + class ARMAsmPrinter : public AsmPrinter { /// Subtarget - Keep a pointer to the ARMSubtarget around so that we can /// make the right decision when printing asm code for different targets. const ARMSubtarget *Subtarget; /// AFI - Keep a pointer to ARMFunctionInfo for the current - /// MachineFunction + /// MachineFunction. ARMFunctionInfo *AFI; - /// We name each basic block in a Function with a unique number, so - /// that we can consistently refer to them later. This is cleared - /// at the beginning of each call to runOnMachineFunction(). - /// - typedef std::map ValueMapTy; - ValueMapTy NumberForBB; - - /// Keeps the set of GlobalValues that require non-lazy-pointers for - /// indirect access. - std::set GVNonLazyPtrs; + /// MCP - Keep a pointer to constantpool entries of the current + /// MachineFunction. + const MachineConstantPool *MCP; - /// Keeps the set of external function GlobalAddresses that the asm - /// printer should generate stubs for. - std::set FnStubs; + public: + explicit ARMAsmPrinter(TargetMachine &TM, MCStreamer &Streamer) + : AsmPrinter(TM, Streamer), AFI(NULL), MCP(NULL) { + Subtarget = &TM.getSubtarget(); + } - /// True if asm printer is printing a series of CONSTPOOL_ENTRY. - bool InCPMode; - virtual const char *getPassName() const { return "ARM Assembly Printer"; } - void printOperand(const MachineInstr *MI, int opNum, + void EmitJumpTable(const MachineInstr *MI); + void EmitJump2Table(const MachineInstr *MI); + void printInstructionThroughMCStreamer(const MachineInstr *MI); + + + void printOperand(const MachineInstr *MI, int OpNum, raw_ostream &O, const char *Modifier = 0); - void printSOImmOperand(const MachineInstr *MI, int opNum); - void printSOImm2PartOperand(const MachineInstr *MI, int opNum); - void printSORegOperand(const MachineInstr *MI, int opNum); - void printAddrMode2Operand(const MachineInstr *MI, int OpNo); - void printAddrMode2OffsetOperand(const MachineInstr *MI, int OpNo); - void printAddrMode3Operand(const MachineInstr *MI, int OpNo); - void printAddrMode3OffsetOperand(const MachineInstr *MI, int OpNo); - void printAddrMode4Operand(const MachineInstr *MI, int OpNo, + void printSOImmOperand(const MachineInstr *MI, int OpNum, raw_ostream &O); + void printSOImm2PartOperand(const MachineInstr *MI, int OpNum, + raw_ostream &O); + void printSORegOperand(const MachineInstr *MI, int OpNum, + raw_ostream &O); + void printAddrMode2Operand(const MachineInstr *MI, int OpNum, + raw_ostream &O); + void printAddrMode2OffsetOperand(const MachineInstr *MI, int OpNum, + raw_ostream &O); + void printAddrMode3Operand(const MachineInstr *MI, int OpNum, + raw_ostream &O); + void printAddrMode3OffsetOperand(const MachineInstr *MI, int OpNum, + raw_ostream &O); + void printAddrMode4Operand(const MachineInstr *MI, int OpNum,raw_ostream &O, const char *Modifier = 0); - void printAddrMode5Operand(const MachineInstr *MI, int OpNo, + void printAddrMode5Operand(const MachineInstr *MI, int OpNum,raw_ostream &O, const char *Modifier = 0); - void printAddrModePCOperand(const MachineInstr *MI, int OpNo, + void printAddrMode6Operand(const MachineInstr *MI, int OpNum, + raw_ostream &O); + void printAddrMode6OffsetOperand(const MachineInstr *MI, int OpNum, + raw_ostream &O); + void printAddrModePCOperand(const MachineInstr *MI, int OpNum, + raw_ostream &O, const char *Modifier = 0); - void printThumbAddrModeRROperand(const MachineInstr *MI, int OpNo); - void printThumbAddrModeRI5Operand(const MachineInstr *MI, int OpNo, + void printBitfieldInvMaskImmOperand(const MachineInstr *MI, int OpNum, + raw_ostream &O); + void printMemBOption(const MachineInstr *MI, int OpNum, + raw_ostream &O); + void printShiftImmOperand(const MachineInstr *MI, int OpNum, + raw_ostream &O); + + void printThumbS4ImmOperand(const MachineInstr *MI, int OpNum, + raw_ostream &O); + void printThumbITMask(const MachineInstr *MI, int OpNum, raw_ostream &O); + void printThumbAddrModeRROperand(const MachineInstr *MI, int OpNum, + raw_ostream &O); + void printThumbAddrModeRI5Operand(const MachineInstr *MI, int OpNum, + raw_ostream &O, unsigned Scale); - void printThumbAddrModeS1Operand(const MachineInstr *MI, int OpNo); - void printThumbAddrModeS2Operand(const MachineInstr *MI, int OpNo); - void printThumbAddrModeS4Operand(const MachineInstr *MI, int OpNo); - void printThumbAddrModeSPOperand(const MachineInstr *MI, int OpNo); - void printPredicateOperand(const MachineInstr *MI, int opNum); - void printPCLabel(const MachineInstr *MI, int opNum); - void printRegisterList(const MachineInstr *MI, int opNum); - void printCPInstOperand(const MachineInstr *MI, int opNum, + void printThumbAddrModeS1Operand(const MachineInstr *MI, int OpNum, + raw_ostream &O); + void printThumbAddrModeS2Operand(const MachineInstr *MI, int OpNum, + raw_ostream &O); + void printThumbAddrModeS4Operand(const MachineInstr *MI, int OpNum, + raw_ostream &O); + void printThumbAddrModeSPOperand(const MachineInstr *MI, int OpNum, + raw_ostream &O); + + void printT2SOOperand(const MachineInstr *MI, int OpNum, raw_ostream &O); + void printT2AddrModeImm12Operand(const MachineInstr *MI, int OpNum, + raw_ostream &O); + void printT2AddrModeImm8Operand(const MachineInstr *MI, int OpNum, + raw_ostream &O); + void printT2AddrModeImm8s4Operand(const MachineInstr *MI, int OpNum, + raw_ostream &O); + void printT2AddrModeImm8OffsetOperand(const MachineInstr *MI, int OpNum, + raw_ostream &O); + void printT2AddrModeImm8s4OffsetOperand(const MachineInstr *MI, int OpNum, + raw_ostream &O) {} + void printT2AddrModeSoRegOperand(const MachineInstr *MI, int OpNum, + raw_ostream &O); + + void printCPSOptionOperand(const MachineInstr *MI, int OpNum, + raw_ostream &O) {} + void printMSRMaskOperand(const MachineInstr *MI, int OpNum, + raw_ostream &O) {} + void printNegZeroOperand(const MachineInstr *MI, int OpNum, + raw_ostream &O) {} + void printPredicateOperand(const MachineInstr *MI, int OpNum, + raw_ostream &O); + void printMandatoryPredicateOperand(const MachineInstr *MI, int OpNum, + raw_ostream &O); + void printSBitModifierOperand(const MachineInstr *MI, int OpNum, + raw_ostream &O); + void printPCLabel(const MachineInstr *MI, int OpNum, + raw_ostream &O); + void printRegisterList(const MachineInstr *MI, int OpNum, + raw_ostream &O); + void printCPInstOperand(const MachineInstr *MI, int OpNum, + raw_ostream &O, const char *Modifier); - void printJTBlockOperand(const MachineInstr *MI, int opNum); + void printJTBlockOperand(const MachineInstr *MI, int OpNum, + raw_ostream &O); + void printJT2BlockOperand(const MachineInstr *MI, int OpNum, + raw_ostream &O); + void printTBAddrMode(const MachineInstr *MI, int OpNum, + raw_ostream &O); + void printNoHashImmediate(const MachineInstr *MI, int OpNum, + raw_ostream &O); + void printVFPf32ImmOperand(const MachineInstr *MI, int OpNum, + raw_ostream &O); + void printVFPf64ImmOperand(const MachineInstr *MI, int OpNum, + raw_ostream &O); + void printNEONModImmOperand(const MachineInstr *MI, int OpNum, + raw_ostream &O); + + virtual bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNum, + unsigned AsmVariant, const char *ExtraCode, + raw_ostream &O); + virtual bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNum, + unsigned AsmVariant, + const char *ExtraCode, raw_ostream &O); + + void printInstruction(const MachineInstr *MI, raw_ostream &O); // autogen + static const char *getRegisterName(unsigned RegNo); + + virtual void EmitInstruction(const MachineInstr *MI); + bool runOnMachineFunction(MachineFunction &F); - virtual bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, - unsigned AsmVariant, const char *ExtraCode); + virtual void EmitConstantPool() {} // we emit constant pools customly! + virtual void EmitFunctionEntryLabel(); + void EmitStartOfAsmFile(Module &M); + void EmitEndOfAsmFile(Module &M); + + void PrintDebugValueComment(const MachineInstr *MI, raw_ostream &OS); + + MachineLocation getDebugValueLocation(const MachineInstr *MI) const { + MachineLocation Location; + assert (MI->getNumOperands() == 4 && "Invalid no. of machine operands!"); + // Frame address. Currently handles register +- offset only. + if (MI->getOperand(0).isReg() && MI->getOperand(1).isImm()) + Location.set(MI->getOperand(0).getReg(), MI->getOperand(1).getImm()); + else { + DEBUG(dbgs() << "DBG_VALUE instruction ignored! " << *MI << "\n"); + } + return Location; + } - bool printInstruction(const MachineInstr *MI); // autogenerated. - void printMachineInstruction(const MachineInstr *MI); - bool runOnMachineFunction(MachineFunction &F); - bool doInitialization(Module &M); - bool doFinalization(Module &M); + virtual unsigned getISAEncoding() { + // ARM/Darwin adds ISA to the DWARF info for each function. + if (!Subtarget->isTargetDarwin()) + return 0; + return Subtarget->isThumb() ? + llvm::ARM::DW_ISA_ARM_thumb : llvm::ARM::DW_ISA_ARM_arm; + } + MCSymbol *GetARMSetPICJumpTableLabel2(unsigned uid, unsigned uid2, + const MachineBasicBlock *MBB) const; + MCSymbol *GetARMJTIPICJumpTableLabel2(unsigned uid, unsigned uid2) const; + + MCSymbol *GetARMSJLJEHLabel(void) const; + + /// EmitMachineConstantPoolValue - Print a machine constantpool value to + /// the .s file. virtual void EmitMachineConstantPoolValue(MachineConstantPoolValue *MCPV) { - printDataDirective(MCPV->getType()); - - ARMConstantPoolValue *ACPV = (ARMConstantPoolValue*)MCPV; - GlobalValue *GV = ACPV->getGV(); - std::string Name = GV ? Mang->getValueName(GV) : TAI->getGlobalPrefix(); - if (!GV) - Name += ACPV->getSymbol(); - if (ACPV->isNonLazyPointer()) { - GVNonLazyPtrs.insert(Name); - O << TAI->getPrivateGlobalPrefix() << Name << "$non_lazy_ptr"; - } else if (ACPV->isStub()) { - FnStubs.insert(Name); - O << TAI->getPrivateGlobalPrefix() << Name << "$stub"; - } else - O << Name; + SmallString<128> Str; + raw_svector_ostream OS(Str); + EmitMachineConstantPoolValue(MCPV, OS); + OutStreamer.EmitRawText(OS.str()); + } + + void EmitMachineConstantPoolValue(MachineConstantPoolValue *MCPV, + raw_ostream &O) { + switch (TM.getTargetData()->getTypeAllocSize(MCPV->getType())) { + case 1: O << MAI->getData8bitsDirective(0); break; + case 2: O << MAI->getData16bitsDirective(0); break; + case 4: O << MAI->getData32bitsDirective(0); break; + default: assert(0 && "Unknown CPV size"); + } + + ARMConstantPoolValue *ACPV = static_cast(MCPV); + + if (ACPV->isLSDA()) { + O << MAI->getPrivateGlobalPrefix() << "_LSDA_" << getFunctionNumber(); + } else if (ACPV->isBlockAddress()) { + O << *GetBlockAddressSymbol(ACPV->getBlockAddress()); + } else if (ACPV->isGlobalValue()) { + const GlobalValue *GV = ACPV->getGV(); + bool isIndirect = Subtarget->isTargetDarwin() && + Subtarget->GVIsIndirectSymbol(GV, TM.getRelocationModel()); + if (!isIndirect) + O << *Mang->getSymbol(GV); + else { + // FIXME: Remove this when Darwin transition to @GOT like syntax. + MCSymbol *Sym = GetSymbolWithGlobalValueBase(GV, "$non_lazy_ptr"); + O << *Sym; + + MachineModuleInfoMachO &MMIMachO = + MMI->getObjFileInfo(); + MachineModuleInfoImpl::StubValueTy &StubSym = + GV->hasHiddenVisibility() ? MMIMachO.getHiddenGVStubEntry(Sym) : + MMIMachO.getGVStubEntry(Sym); + if (StubSym.getPointer() == 0) + StubSym = MachineModuleInfoImpl:: + StubValueTy(Mang->getSymbol(GV), !GV->hasInternalLinkage()); + } + } else { + assert(ACPV->isExtSymbol() && "unrecognized constant pool value"); + O << *GetExternalSymbolSymbol(ACPV->getSymbol()); + } + if (ACPV->hasModifier()) O << "(" << ACPV->getModifier() << ")"; if (ACPV->getPCAdjustment() != 0) { - O << "-(" << TAI->getPrivateGlobalPrefix() << "PC" - << utostr(ACPV->getLabelId()) + O << "-(" << MAI->getPrivateGlobalPrefix() << "PC" + << getFunctionNumber() << "_" << ACPV->getLabelId() << "+" << (unsigned)ACPV->getPCAdjustment(); if (ACPV->mustAddCurrentAddress()) O << "-."; - O << ")"; + O << ')'; } - O << "\n"; - - // If the constant pool value is a extern weak symbol, remember to emit - // the weak reference. - if (GV && GV->hasExternalWeakLinkage()) - ExtWeakSymbols.insert(GV); - } - - void getAnalysisUsage(AnalysisUsage &AU) const { - AU.setPreservesAll(); - AU.addRequired(); } }; } // end of anonymous namespace #include "ARMGenAsmWriter.inc" -/// createARMCodePrinterPass - Returns a pass that prints the ARM -/// 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::createARMCodePrinterPass(std::ostream &o, - ARMTargetMachine &tm) { - return new ARMAsmPrinter(o, tm, tm.getTargetAsmInfo()); +void ARMAsmPrinter::EmitFunctionEntryLabel() { + if (AFI->isThumbFunction()) { + OutStreamer.EmitRawText(StringRef("\t.code\t16")); + if (!Subtarget->isTargetDarwin()) + OutStreamer.EmitRawText(StringRef("\t.thumb_func")); + else { + // This needs to emit to a temporary string to get properly quoted + // MCSymbols when they have spaces in them. + SmallString<128> Tmp; + raw_svector_ostream OS(Tmp); + OS << "\t.thumb_func\t" << *CurrentFnSym; + OutStreamer.EmitRawText(OS.str()); + } + } + + OutStreamer.EmitLabel(CurrentFnSym); } /// runOnMachineFunction - This uses the printInstruction() @@ -174,172 +327,104 @@ FunctionPass *llvm::createARMCodePrinterPass(std::ostream &o, /// bool ARMAsmPrinter::runOnMachineFunction(MachineFunction &MF) { AFI = MF.getInfo(); + MCP = MF.getConstantPool(); - DW.SetModuleInfo(&getAnalysis()); - - SetupMachineFunction(MF); - O << "\n"; + return AsmPrinter::runOnMachineFunction(MF); +} - // NOTE: we don't print out constant pools here, they are handled as - // instructions. +void ARMAsmPrinter::printOperand(const MachineInstr *MI, int OpNum, + raw_ostream &O, const char *Modifier) { + const MachineOperand &MO = MI->getOperand(OpNum); + unsigned TF = MO.getTargetFlags(); - O << "\n"; - // Print out labels for the function. - const Function *F = MF.getFunction(); - switch (F->getLinkage()) { - default: assert(0 && "Unknown linkage type!"); - case Function::InternalLinkage: - SwitchToTextSection("\t.text", F); - break; - case Function::ExternalLinkage: - SwitchToTextSection("\t.text", F); - O << "\t.globl\t" << CurrentFnName << "\n"; - break; - case Function::WeakLinkage: - case Function::LinkOnceLinkage: - if (Subtarget->isTargetDarwin()) { - SwitchToTextSection( - ".section __TEXT,__textcoal_nt,coalesced,pure_instructions", F); - O << "\t.globl\t" << CurrentFnName << "\n"; - O << "\t.weak_definition\t" << CurrentFnName << "\n"; + switch (MO.getType()) { + default: + assert(0 && ""); + case MachineOperand::MO_Register: { + unsigned Reg = MO.getReg(); + assert(TargetRegisterInfo::isPhysicalRegister(Reg)); + if (Modifier && strcmp(Modifier, "lane") == 0) { + unsigned RegNum = getARMRegisterNumbering(Reg); + unsigned DReg = + TM.getRegisterInfo()->getMatchingSuperReg(Reg, + RegNum & 1 ? ARM::ssub_1 : ARM::ssub_0, &ARM::DPR_VFP2RegClass); + O << getRegisterName(DReg) << '[' << (RegNum & 1) << ']'; } else { - O << TAI->getWeakRefDirective() << CurrentFnName << "\n"; + assert(!MO.getSubReg() && "Subregs should be eliminated!"); + O << getRegisterName(Reg); } break; } - - const char *VisibilityDirective = NULL; - if (F->hasHiddenVisibility()) - VisibilityDirective = TAI->getHiddenDirective(); - else if (F->hasProtectedVisibility()) - VisibilityDirective = TAI->getProtectedDirective(); - - if (VisibilityDirective) - O << VisibilityDirective << CurrentFnName << "\n"; - - if (AFI->isThumbFunction()) { - EmitAlignment(AFI->getAlign(), F); - O << "\t.code\t16\n"; - O << "\t.thumb_func"; - if (Subtarget->isTargetDarwin()) - O << "\t" << CurrentFnName; - O << "\n"; - InCPMode = false; - } else - EmitAlignment(2, F); - - O << CurrentFnName << ":\n"; - // Emit pre-function debug information. - DW.BeginFunction(&MF); - - // Print out code for the function. - for (MachineFunction::const_iterator I = MF.begin(), E = MF.end(); - I != E; ++I) { - // Print a label for the basic block. - if (I != MF.begin()) { - printBasicBlockLabel(I, true); - O << '\n'; - } - for (MachineBasicBlock::const_iterator II = I->begin(), E = I->end(); - II != E; ++II) { - // Print the assembly for the instruction. - printMachineInstruction(II); - } - } - - if (TAI->hasDotTypeDotSizeDirective()) - O << "\t.size " << CurrentFnName << ", .-" << CurrentFnName << "\n"; - - // Emit post-function debug information. - DW.EndFunction(); - - return false; -} - -void ARMAsmPrinter::printOperand(const MachineInstr *MI, int opNum, - const char *Modifier) { - const MachineOperand &MO = MI->getOperand(opNum); - switch (MO.getType()) { - case MachineOperand::MO_Register: - if (MRegisterInfo::isPhysicalRegister(MO.getReg())) - O << TM.getRegisterInfo()->get(MO.getReg()).Name; - else - assert(0 && "not implemented"); - break; case MachineOperand::MO_Immediate: { - if (!Modifier || strcmp(Modifier, "no_hash") != 0) - O << "#"; - - O << (int)MO.getImmedValue(); + int64_t Imm = MO.getImm(); + O << '#'; + if ((Modifier && strcmp(Modifier, "lo16") == 0) || + (TF & ARMII::MO_LO16)) + O << ":lower16:"; + else if ((Modifier && strcmp(Modifier, "hi16") == 0) || + (TF & ARMII::MO_HI16)) + O << ":upper16:"; + O << Imm; break; } case MachineOperand::MO_MachineBasicBlock: - printBasicBlockLabel(MO.getMachineBasicBlock()); + O << *MO.getMBB()->getSymbol(); return; case MachineOperand::MO_GlobalAddress: { bool isCallOp = Modifier && !strcmp(Modifier, "call"); - GlobalValue *GV = MO.getGlobal(); - std::string Name = Mang->getValueName(GV); - bool isExt = (GV->isDeclaration() || GV->hasWeakLinkage() || - GV->hasLinkOnceLinkage()); - if (isExt && isCallOp && Subtarget->isTargetDarwin() && - TM.getRelocationModel() != Reloc::Static) { - O << TAI->getPrivateGlobalPrefix() << Name << "$stub"; - FnStubs.insert(Name); - } else - O << Name; - - if (MO.getOffset() > 0) - O << '+' << MO.getOffset(); - else if (MO.getOffset() < 0) - O << MO.getOffset(); - + const GlobalValue *GV = MO.getGlobal(); + + if ((Modifier && strcmp(Modifier, "lo16") == 0) || + (TF & ARMII::MO_LO16)) + O << ":lower16:"; + else if ((Modifier && strcmp(Modifier, "hi16") == 0) || + (TF & ARMII::MO_HI16)) + O << ":upper16:"; + O << *Mang->getSymbol(GV); + + printOffset(MO.getOffset(), O); + if (isCallOp && Subtarget->isTargetELF() && TM.getRelocationModel() == Reloc::PIC_) O << "(PLT)"; - if (GV->hasExternalWeakLinkage()) - ExtWeakSymbols.insert(GV); break; } case MachineOperand::MO_ExternalSymbol: { bool isCallOp = Modifier && !strcmp(Modifier, "call"); - std::string Name(TAI->getGlobalPrefix()); - Name += MO.getSymbolName(); - if (isCallOp && Subtarget->isTargetDarwin() && - TM.getRelocationModel() != Reloc::Static) { - O << TAI->getPrivateGlobalPrefix() << Name << "$stub"; - FnStubs.insert(Name); - } else - O << Name; + O << *GetExternalSymbolSymbol(MO.getSymbolName()); + if (isCallOp && Subtarget->isTargetELF() && TM.getRelocationModel() == Reloc::PIC_) O << "(PLT)"; break; } case MachineOperand::MO_ConstantPoolIndex: - O << TAI->getPrivateGlobalPrefix() << "CPI" << getFunctionNumber() - << '_' << MO.getConstantPoolIndex(); + O << *GetCPISymbol(MO.getIndex()); break; case MachineOperand::MO_JumpTableIndex: - O << TAI->getPrivateGlobalPrefix() << "JTI" << getFunctionNumber() - << '_' << MO.getJumpTableIndex(); + O << *GetJTISymbol(MO.getIndex()); break; - default: - O << ""; abort (); break; } } -static void printSOImm(std::ostream &O, int64_t V, const TargetAsmInfo *TAI) { - assert(V < (1 << 12) && "Not a valid so_imm value!"); +static void printSOImm(raw_ostream &O, int64_t V, bool VerboseAsm, + const MCAsmInfo *MAI) { + // Break it up into two parts that make up a shifter immediate. + V = ARM_AM::getSOImmVal(V); + assert(V != -1 && "Not a valid so_imm value!"); + unsigned Imm = ARM_AM::getSOImmValImm(V); unsigned Rot = ARM_AM::getSOImmValRot(V); - + // Print low-level immediate formation info, per // A5.1.3: "Data-processing operands - Immediate". if (Rot) { O << "#" << Imm << ", " << Rot; // Pretty printed version. - O << ' ' << TAI->getCommentString() << ' ' << (int)ARM_AM::rotr32(Imm, Rot); + if (VerboseAsm) { + O << "\t" << MAI->getCommentString() << ' '; + O << (int)ARM_AM::rotr32(Imm, Rot); + } } else { O << "#" << Imm; } @@ -347,656 +432,1656 @@ static void printSOImm(std::ostream &O, int64_t V, const TargetAsmInfo *TAI) { /// printSOImmOperand - SOImm is 4-bit rotate amount in bits 8-11 with 8-bit /// immediate in bits 0-7. -void ARMAsmPrinter::printSOImmOperand(const MachineInstr *MI, int OpNum) { +void ARMAsmPrinter::printSOImmOperand(const MachineInstr *MI, int OpNum, + raw_ostream &O) { const MachineOperand &MO = MI->getOperand(OpNum); - assert(MO.isImmediate() && "Not a valid so_imm value!"); - printSOImm(O, MO.getImmedValue(), TAI); + assert(MO.isImm() && "Not a valid so_imm value!"); + printSOImm(O, MO.getImm(), isVerbose(), MAI); } -/// printSOImm2PartOperand - SOImm is broken into two pieces using a mov -/// followed by a or to materialize. -void ARMAsmPrinter::printSOImm2PartOperand(const MachineInstr *MI, int OpNum) { +/// printSOImm2PartOperand - SOImm is broken into two pieces using a 'mov' +/// followed by an 'orr' to materialize. +void ARMAsmPrinter::printSOImm2PartOperand(const MachineInstr *MI, int OpNum, + raw_ostream &O) { const MachineOperand &MO = MI->getOperand(OpNum); - assert(MO.isImmediate() && "Not a valid so_imm value!"); - unsigned V1 = ARM_AM::getSOImmTwoPartFirst(MO.getImmedValue()); - unsigned V2 = ARM_AM::getSOImmTwoPartSecond(MO.getImmedValue()); - printSOImm(O, ARM_AM::getSOImmVal(V1), TAI); - O << "\n\torr "; - printOperand(MI, 0); + assert(MO.isImm() && "Not a valid so_imm value!"); + unsigned V1 = ARM_AM::getSOImmTwoPartFirst(MO.getImm()); + unsigned V2 = ARM_AM::getSOImmTwoPartSecond(MO.getImm()); + printSOImm(O, V1, isVerbose(), MAI); + O << "\n\torr"; + printPredicateOperand(MI, 2, O); + O << "\t"; + printOperand(MI, 0, O); O << ", "; - printOperand(MI, 0); + printOperand(MI, 0, O); O << ", "; - printSOImm(O, ARM_AM::getSOImmVal(V2), TAI); + printSOImm(O, V2, isVerbose(), MAI); } // so_reg is a 4-operand unit corresponding to register forms of the A5.1 // "Addressing Mode 1 - Data-processing operands" forms. This includes: -// REG 0 0 - e.g. R5 -// REG REG 0,SH_OPC - e.g. R5, ROR R3 +// REG 0 0 - e.g. R5 +// REG REG 0,SH_OPC - e.g. R5, ROR R3 // REG 0 IMM,SH_OPC - e.g. R5, LSL #3 -void ARMAsmPrinter::printSORegOperand(const MachineInstr *MI, int Op) { +void ARMAsmPrinter::printSORegOperand(const MachineInstr *MI, int Op, + raw_ostream &O) { const MachineOperand &MO1 = MI->getOperand(Op); const MachineOperand &MO2 = MI->getOperand(Op+1); const MachineOperand &MO3 = MI->getOperand(Op+2); - assert(MRegisterInfo::isPhysicalRegister(MO1.getReg())); - O << TM.getRegisterInfo()->get(MO1.getReg()).Name; + O << getRegisterName(MO1.getReg()); // Print the shift opc. - O << ", " - << ARM_AM::getShiftOpcStr(ARM_AM::getSORegShOp(MO3.getImmedValue())) - << " "; - + ARM_AM::ShiftOpc ShOpc = ARM_AM::getSORegShOp(MO3.getImm()); + O << ", " << ARM_AM::getShiftOpcStr(ShOpc); if (MO2.getReg()) { - assert(MRegisterInfo::isPhysicalRegister(MO2.getReg())); - O << TM.getRegisterInfo()->get(MO2.getReg()).Name; + O << ' ' << getRegisterName(MO2.getReg()); assert(ARM_AM::getSORegOffset(MO3.getImm()) == 0); - } else { - O << "#" << ARM_AM::getSORegOffset(MO3.getImm()); + } else if (ShOpc != ARM_AM::rrx) { + O << " #" << ARM_AM::getSORegOffset(MO3.getImm()); } } -void ARMAsmPrinter::printAddrMode2Operand(const MachineInstr *MI, int Op) { +void ARMAsmPrinter::printAddrMode2Operand(const MachineInstr *MI, int Op, + raw_ostream &O) { const MachineOperand &MO1 = MI->getOperand(Op); const MachineOperand &MO2 = MI->getOperand(Op+1); const MachineOperand &MO3 = MI->getOperand(Op+2); - if (!MO1.isRegister()) { // FIXME: This is for CP entries, but isn't right. - printOperand(MI, Op); + if (!MO1.isReg()) { // FIXME: This is for CP entries, but isn't right. + printOperand(MI, Op, O); return; } - O << "[" << TM.getRegisterInfo()->get(MO1.getReg()).Name; + O << "[" << getRegisterName(MO1.getReg()); if (!MO2.getReg()) { - if (ARM_AM::getAM2Offset(MO3.getImm())) // Don't print +0. + if (ARM_AM::getAM2Offset(MO3.getImm())) // Don't print +0. O << ", #" - << (char)ARM_AM::getAM2Op(MO3.getImm()) + << ARM_AM::getAddrOpcStr(ARM_AM::getAM2Op(MO3.getImm())) << ARM_AM::getAM2Offset(MO3.getImm()); O << "]"; return; } O << ", " - << (char)ARM_AM::getAM2Op(MO3.getImm()) - << TM.getRegisterInfo()->get(MO2.getReg()).Name; - + << ARM_AM::getAddrOpcStr(ARM_AM::getAM2Op(MO3.getImm())) + << getRegisterName(MO2.getReg()); + if (unsigned ShImm = ARM_AM::getAM2Offset(MO3.getImm())) O << ", " - << ARM_AM::getShiftOpcStr(ARM_AM::getAM2ShiftOpc(MO3.getImmedValue())) + << ARM_AM::getShiftOpcStr(ARM_AM::getAM2ShiftOpc(MO3.getImm())) << " #" << ShImm; O << "]"; } -void ARMAsmPrinter::printAddrMode2OffsetOperand(const MachineInstr *MI, int Op){ +void ARMAsmPrinter::printAddrMode2OffsetOperand(const MachineInstr *MI, int Op, + raw_ostream &O) { const MachineOperand &MO1 = MI->getOperand(Op); const MachineOperand &MO2 = MI->getOperand(Op+1); if (!MO1.getReg()) { unsigned ImmOffs = ARM_AM::getAM2Offset(MO2.getImm()); - assert(ImmOffs && "Malformed indexed load / store!"); O << "#" - << (char)ARM_AM::getAM2Op(MO2.getImm()) + << ARM_AM::getAddrOpcStr(ARM_AM::getAM2Op(MO2.getImm())) << ImmOffs; return; } - O << (char)ARM_AM::getAM2Op(MO2.getImm()) - << TM.getRegisterInfo()->get(MO1.getReg()).Name; - + O << ARM_AM::getAddrOpcStr(ARM_AM::getAM2Op(MO2.getImm())) + << getRegisterName(MO1.getReg()); + if (unsigned ShImm = ARM_AM::getAM2Offset(MO2.getImm())) O << ", " - << ARM_AM::getShiftOpcStr(ARM_AM::getAM2ShiftOpc(MO2.getImmedValue())) + << ARM_AM::getShiftOpcStr(ARM_AM::getAM2ShiftOpc(MO2.getImm())) << " #" << ShImm; } -void ARMAsmPrinter::printAddrMode3Operand(const MachineInstr *MI, int Op) { +void ARMAsmPrinter::printAddrMode3Operand(const MachineInstr *MI, int Op, + raw_ostream &O) { const MachineOperand &MO1 = MI->getOperand(Op); const MachineOperand &MO2 = MI->getOperand(Op+1); const MachineOperand &MO3 = MI->getOperand(Op+2); - - assert(MRegisterInfo::isPhysicalRegister(MO1.getReg())); - O << "[" << TM.getRegisterInfo()->get(MO1.getReg()).Name; + + assert(TargetRegisterInfo::isPhysicalRegister(MO1.getReg())); + O << "[" << getRegisterName(MO1.getReg()); if (MO2.getReg()) { O << ", " << (char)ARM_AM::getAM3Op(MO3.getImm()) - << TM.getRegisterInfo()->get(MO2.getReg()).Name + << getRegisterName(MO2.getReg()) << "]"; return; } - + if (unsigned ImmOffs = ARM_AM::getAM3Offset(MO3.getImm())) O << ", #" - << (char)ARM_AM::getAM3Op(MO3.getImm()) + << ARM_AM::getAddrOpcStr(ARM_AM::getAM3Op(MO3.getImm())) << ImmOffs; O << "]"; } -void ARMAsmPrinter::printAddrMode3OffsetOperand(const MachineInstr *MI, int Op){ +void ARMAsmPrinter::printAddrMode3OffsetOperand(const MachineInstr *MI, int Op, + raw_ostream &O){ const MachineOperand &MO1 = MI->getOperand(Op); const MachineOperand &MO2 = MI->getOperand(Op+1); if (MO1.getReg()) { O << (char)ARM_AM::getAM3Op(MO2.getImm()) - << TM.getRegisterInfo()->get(MO1.getReg()).Name; + << getRegisterName(MO1.getReg()); return; } unsigned ImmOffs = ARM_AM::getAM3Offset(MO2.getImm()); - assert(ImmOffs && "Malformed indexed load / store!"); O << "#" - << (char)ARM_AM::getAM3Op(MO2.getImm()) + << ARM_AM::getAddrOpcStr(ARM_AM::getAM3Op(MO2.getImm())) << ImmOffs; } - + void ARMAsmPrinter::printAddrMode4Operand(const MachineInstr *MI, int Op, + raw_ostream &O, const char *Modifier) { - const MachineOperand &MO1 = MI->getOperand(Op); const MachineOperand &MO2 = MI->getOperand(Op+1); ARM_AM::AMSubMode Mode = ARM_AM::getAM4SubMode(MO2.getImm()); if (Modifier && strcmp(Modifier, "submode") == 0) { - if (MO1.getReg() == ARM::SP) { - bool isLDM = (MI->getOpcode() == ARM::LDM || - MI->getOpcode() == ARM::LDM_RET); - O << ARM_AM::getAMSubModeAltStr(Mode, isLDM); - } else - O << ARM_AM::getAMSubModeStr(Mode); + O << ARM_AM::getAMSubModeStr(Mode); + } else if (Modifier && strcmp(Modifier, "wide") == 0) { + ARM_AM::AMSubMode Mode = ARM_AM::getAM4SubMode(MO2.getImm()); + if (Mode == ARM_AM::ia) + O << ".w"; } else { - printOperand(MI, Op); - if (ARM_AM::getAM4WBFlag(MO2.getImm())) - O << "!"; + printOperand(MI, Op, O); } } void ARMAsmPrinter::printAddrMode5Operand(const MachineInstr *MI, int Op, + raw_ostream &O, const char *Modifier) { const MachineOperand &MO1 = MI->getOperand(Op); const MachineOperand &MO2 = MI->getOperand(Op+1); - if (!MO1.isRegister()) { // FIXME: This is for CP entries, but isn't right. - printOperand(MI, Op); + if (!MO1.isReg()) { // FIXME: This is for CP entries, but isn't right. + printOperand(MI, Op, O); return; } - - assert(MRegisterInfo::isPhysicalRegister(MO1.getReg())); - if (Modifier && strcmp(Modifier, "submode") == 0) { - ARM_AM::AMSubMode Mode = ARM_AM::getAM5SubMode(MO2.getImm()); - if (MO1.getReg() == ARM::SP) { - bool isFLDM = (MI->getOpcode() == ARM::FLDMD || - MI->getOpcode() == ARM::FLDMS); - O << ARM_AM::getAMSubModeAltStr(Mode, isFLDM); - } else - O << ARM_AM::getAMSubModeStr(Mode); - return; - } else if (Modifier && strcmp(Modifier, "base") == 0) { - // Used for FSTM{D|S} and LSTM{D|S} operations. - O << TM.getRegisterInfo()->get(MO1.getReg()).Name; - if (ARM_AM::getAM5WBFlag(MO2.getImm())) - O << "!"; - return; - } - - O << "[" << TM.getRegisterInfo()->get(MO1.getReg()).Name; - + assert(TargetRegisterInfo::isPhysicalRegister(MO1.getReg())); + + O << "[" << getRegisterName(MO1.getReg()); + if (unsigned ImmOffs = ARM_AM::getAM5Offset(MO2.getImm())) { O << ", #" - << (char)ARM_AM::getAM5Op(MO2.getImm()) + << ARM_AM::getAddrOpcStr(ARM_AM::getAM5Op(MO2.getImm())) << ImmOffs*4; } O << "]"; } +void ARMAsmPrinter::printAddrMode6Operand(const MachineInstr *MI, int Op, + raw_ostream &O) { + const MachineOperand &MO1 = MI->getOperand(Op); + const MachineOperand &MO2 = MI->getOperand(Op+1); + + O << "[" << getRegisterName(MO1.getReg()); + if (MO2.getImm()) { + // FIXME: Both darwin as and GNU as violate ARM docs here. + O << ", :" << (MO2.getImm() << 3); + } + O << "]"; +} + +void ARMAsmPrinter::printAddrMode6OffsetOperand(const MachineInstr *MI, int Op, + raw_ostream &O){ + const MachineOperand &MO = MI->getOperand(Op); + if (MO.getReg() == 0) + O << "!"; + else + O << ", " << getRegisterName(MO.getReg()); +} + void ARMAsmPrinter::printAddrModePCOperand(const MachineInstr *MI, int Op, + raw_ostream &O, const char *Modifier) { if (Modifier && strcmp(Modifier, "label") == 0) { - printPCLabel(MI, Op+1); + printPCLabel(MI, Op+1, O); return; } const MachineOperand &MO1 = MI->getOperand(Op); - assert(MRegisterInfo::isPhysicalRegister(MO1.getReg())); - O << "[pc, +" << TM.getRegisterInfo()->get(MO1.getReg()).Name << "]"; + assert(TargetRegisterInfo::isPhysicalRegister(MO1.getReg())); + O << "[pc, " << getRegisterName(MO1.getReg()) << "]"; } void -ARMAsmPrinter::printThumbAddrModeRROperand(const MachineInstr *MI, int Op) { +ARMAsmPrinter::printBitfieldInvMaskImmOperand(const MachineInstr *MI, int Op, + raw_ostream &O) { + const MachineOperand &MO = MI->getOperand(Op); + uint32_t v = ~MO.getImm(); + int32_t lsb = CountTrailingZeros_32(v); + int32_t width = (32 - CountLeadingZeros_32 (v)) - lsb; + assert(MO.isImm() && "Not a valid bf_inv_mask_imm value!"); + O << "#" << lsb << ", #" << width; +} + +void +ARMAsmPrinter::printMemBOption(const MachineInstr *MI, int OpNum, + raw_ostream &O) { + unsigned val = MI->getOperand(OpNum).getImm(); + O << ARM_MB::MemBOptToString(val); +} + +void ARMAsmPrinter::printShiftImmOperand(const MachineInstr *MI, int OpNum, + raw_ostream &O) { + unsigned ShiftOp = MI->getOperand(OpNum).getImm(); + ARM_AM::ShiftOpc Opc = ARM_AM::getSORegShOp(ShiftOp); + switch (Opc) { + case ARM_AM::no_shift: + return; + case ARM_AM::lsl: + O << ", lsl #"; + break; + case ARM_AM::asr: + O << ", asr #"; + break; + default: + assert(0 && "unexpected shift opcode for shift immediate operand"); + } + O << ARM_AM::getSORegOffset(ShiftOp); +} + +//===--------------------------------------------------------------------===// + +void ARMAsmPrinter::printThumbS4ImmOperand(const MachineInstr *MI, int Op, + raw_ostream &O) { + O << "#" << MI->getOperand(Op).getImm() * 4; +} + +void +ARMAsmPrinter::printThumbITMask(const MachineInstr *MI, int Op, + raw_ostream &O) { + // (3 - the number of trailing zeros) is the number of then / else. + unsigned Mask = MI->getOperand(Op).getImm(); + unsigned CondBit0 = Mask >> 4 & 1; + unsigned NumTZ = CountTrailingZeros_32(Mask); + assert(NumTZ <= 3 && "Invalid IT mask!"); + for (unsigned Pos = 3, e = NumTZ; Pos > e; --Pos) { + bool T = ((Mask >> Pos) & 1) == CondBit0; + if (T) + O << 't'; + else + O << 'e'; + } +} + +void +ARMAsmPrinter::printThumbAddrModeRROperand(const MachineInstr *MI, int Op, + raw_ostream &O) { const MachineOperand &MO1 = MI->getOperand(Op); const MachineOperand &MO2 = MI->getOperand(Op+1); - O << "[" << TM.getRegisterInfo()->get(MO1.getReg()).Name; - O << ", " << TM.getRegisterInfo()->get(MO2.getReg()).Name << "]"; + O << "[" << getRegisterName(MO1.getReg()); + O << ", " << getRegisterName(MO2.getReg()) << "]"; } void ARMAsmPrinter::printThumbAddrModeRI5Operand(const MachineInstr *MI, int Op, + raw_ostream &O, unsigned Scale) { const MachineOperand &MO1 = MI->getOperand(Op); const MachineOperand &MO2 = MI->getOperand(Op+1); const MachineOperand &MO3 = MI->getOperand(Op+2); - if (!MO1.isRegister()) { // FIXME: This is for CP entries, but isn't right. - printOperand(MI, Op); + if (!MO1.isReg()) { // FIXME: This is for CP entries, but isn't right. + printOperand(MI, Op, O); return; } - O << "[" << TM.getRegisterInfo()->get(MO1.getReg()).Name; + O << "[" << getRegisterName(MO1.getReg()); if (MO3.getReg()) - O << ", " << TM.getRegisterInfo()->get(MO3.getReg()).Name; - else if (unsigned ImmOffs = MO2.getImm()) { - O << ", #" << ImmOffs; - if (Scale > 1) - O << " * " << Scale; - } + O << ", " << getRegisterName(MO3.getReg()); + else if (unsigned ImmOffs = MO2.getImm()) + O << ", #" << ImmOffs * Scale; O << "]"; } void -ARMAsmPrinter::printThumbAddrModeS1Operand(const MachineInstr *MI, int Op) { - printThumbAddrModeRI5Operand(MI, Op, 1); +ARMAsmPrinter::printThumbAddrModeS1Operand(const MachineInstr *MI, int Op, + raw_ostream &O) { + printThumbAddrModeRI5Operand(MI, Op, O, 1); } void -ARMAsmPrinter::printThumbAddrModeS2Operand(const MachineInstr *MI, int Op) { - printThumbAddrModeRI5Operand(MI, Op, 2); +ARMAsmPrinter::printThumbAddrModeS2Operand(const MachineInstr *MI, int Op, + raw_ostream &O) { + printThumbAddrModeRI5Operand(MI, Op, O, 2); } void -ARMAsmPrinter::printThumbAddrModeS4Operand(const MachineInstr *MI, int Op) { - printThumbAddrModeRI5Operand(MI, Op, 4); +ARMAsmPrinter::printThumbAddrModeS4Operand(const MachineInstr *MI, int Op, + raw_ostream &O) { + printThumbAddrModeRI5Operand(MI, Op, O, 4); } -void ARMAsmPrinter::printThumbAddrModeSPOperand(const MachineInstr *MI,int Op) { +void ARMAsmPrinter::printThumbAddrModeSPOperand(const MachineInstr *MI,int Op, + raw_ostream &O) { const MachineOperand &MO1 = MI->getOperand(Op); const MachineOperand &MO2 = MI->getOperand(Op+1); - O << "[" << TM.getRegisterInfo()->get(MO1.getReg()).Name; + O << "[" << getRegisterName(MO1.getReg()); if (unsigned ImmOffs = MO2.getImm()) - O << ", #" << ImmOffs << " * 4"; + O << ", #" << ImmOffs*4; + O << "]"; +} + +//===--------------------------------------------------------------------===// + +// Constant shifts t2_so_reg is a 2-operand unit corresponding to the Thumb2 +// register with shift forms. +// REG 0 0 - e.g. R5 +// REG IMM, SH_OPC - e.g. R5, LSL #3 +void ARMAsmPrinter::printT2SOOperand(const MachineInstr *MI, int OpNum, + raw_ostream &O) { + const MachineOperand &MO1 = MI->getOperand(OpNum); + const MachineOperand &MO2 = MI->getOperand(OpNum+1); + + unsigned Reg = MO1.getReg(); + assert(TargetRegisterInfo::isPhysicalRegister(Reg)); + O << getRegisterName(Reg); + + // Print the shift opc. + assert(MO2.isImm() && "Not a valid t2_so_reg value!"); + ARM_AM::ShiftOpc ShOpc = ARM_AM::getSORegShOp(MO2.getImm()); + O << ", " << ARM_AM::getShiftOpcStr(ShOpc); + if (ShOpc != ARM_AM::rrx) + O << " #" << ARM_AM::getSORegOffset(MO2.getImm()); +} + +void ARMAsmPrinter::printT2AddrModeImm12Operand(const MachineInstr *MI, + int OpNum, + raw_ostream &O) { + const MachineOperand &MO1 = MI->getOperand(OpNum); + const MachineOperand &MO2 = MI->getOperand(OpNum+1); + + O << "[" << getRegisterName(MO1.getReg()); + + unsigned OffImm = MO2.getImm(); + if (OffImm) // Don't print +0. + O << ", #" << OffImm; + O << "]"; +} + +void ARMAsmPrinter::printT2AddrModeImm8Operand(const MachineInstr *MI, + int OpNum, + raw_ostream &O) { + const MachineOperand &MO1 = MI->getOperand(OpNum); + const MachineOperand &MO2 = MI->getOperand(OpNum+1); + + O << "[" << getRegisterName(MO1.getReg()); + + int32_t OffImm = (int32_t)MO2.getImm(); + // Don't print +0. + if (OffImm < 0) + O << ", #-" << -OffImm; + else if (OffImm > 0) + O << ", #" << OffImm; + O << "]"; +} + +void ARMAsmPrinter::printT2AddrModeImm8s4Operand(const MachineInstr *MI, + int OpNum, + raw_ostream &O) { + const MachineOperand &MO1 = MI->getOperand(OpNum); + const MachineOperand &MO2 = MI->getOperand(OpNum+1); + + O << "[" << getRegisterName(MO1.getReg()); + + int32_t OffImm = (int32_t)MO2.getImm() / 4; + // Don't print +0. + if (OffImm < 0) + O << ", #-" << -OffImm * 4; + else if (OffImm > 0) + O << ", #" << OffImm * 4; + O << "]"; +} + +void ARMAsmPrinter::printT2AddrModeImm8OffsetOperand(const MachineInstr *MI, + int OpNum, + raw_ostream &O) { + const MachineOperand &MO1 = MI->getOperand(OpNum); + int32_t OffImm = (int32_t)MO1.getImm(); + // Don't print +0. + if (OffImm < 0) + O << "#-" << -OffImm; + else if (OffImm > 0) + O << "#" << OffImm; +} + +void ARMAsmPrinter::printT2AddrModeSoRegOperand(const MachineInstr *MI, + int OpNum, + raw_ostream &O) { + const MachineOperand &MO1 = MI->getOperand(OpNum); + const MachineOperand &MO2 = MI->getOperand(OpNum+1); + const MachineOperand &MO3 = MI->getOperand(OpNum+2); + + O << "[" << getRegisterName(MO1.getReg()); + + assert(MO2.getReg() && "Invalid so_reg load / store address!"); + O << ", " << getRegisterName(MO2.getReg()); + + unsigned ShAmt = MO3.getImm(); + if (ShAmt) { + assert(ShAmt <= 3 && "Not a valid Thumb2 addressing mode!"); + O << ", lsl #" << ShAmt; + } O << "]"; } -void ARMAsmPrinter::printPredicateOperand(const MachineInstr *MI, int opNum) { - int CC = (int)MI->getOperand(opNum).getImmedValue(); - O << ARMCondCodeToString((ARMCC::CondCodes)CC); + +//===--------------------------------------------------------------------===// + +void ARMAsmPrinter::printPredicateOperand(const MachineInstr *MI, int OpNum, + raw_ostream &O) { + ARMCC::CondCodes CC = (ARMCC::CondCodes)MI->getOperand(OpNum).getImm(); + if (CC != ARMCC::AL) + O << ARMCondCodeToString(CC); +} + +void ARMAsmPrinter::printMandatoryPredicateOperand(const MachineInstr *MI, + int OpNum, + raw_ostream &O) { + ARMCC::CondCodes CC = (ARMCC::CondCodes)MI->getOperand(OpNum).getImm(); + O << ARMCondCodeToString(CC); +} + +void ARMAsmPrinter::printSBitModifierOperand(const MachineInstr *MI, int OpNum, + raw_ostream &O){ + unsigned Reg = MI->getOperand(OpNum).getReg(); + if (Reg) { + assert(Reg == ARM::CPSR && "Expect ARM CPSR register!"); + O << 's'; + } } -void ARMAsmPrinter::printPCLabel(const MachineInstr *MI, int opNum) { - int Id = (int)MI->getOperand(opNum).getImmedValue(); - O << TAI->getPrivateGlobalPrefix() << "PC" << Id; +void ARMAsmPrinter::printPCLabel(const MachineInstr *MI, int OpNum, + raw_ostream &O) { + int Id = (int)MI->getOperand(OpNum).getImm(); + O << MAI->getPrivateGlobalPrefix() + << "PC" << getFunctionNumber() << "_" << Id; } -void ARMAsmPrinter::printRegisterList(const MachineInstr *MI, int opNum) { +void ARMAsmPrinter::printRegisterList(const MachineInstr *MI, int OpNum, + raw_ostream &O) { O << "{"; - for (unsigned i = opNum, e = MI->getNumOperands(); i != e; ++i) { - printOperand(MI, i); - if (i != e-1) O << ", "; + for (unsigned i = OpNum, e = MI->getNumOperands(); i != e; ++i) { + if (MI->getOperand(i).isImplicit()) + continue; + if ((int)i != OpNum) O << ", "; + printOperand(MI, i, O); } O << "}"; } -void ARMAsmPrinter::printCPInstOperand(const MachineInstr *MI, int OpNo, - const char *Modifier) { +void ARMAsmPrinter::printCPInstOperand(const MachineInstr *MI, int OpNum, + raw_ostream &O, const char *Modifier) { assert(Modifier && "This operand only works with a modifier!"); // There are two aspects to a CONSTANTPOOL_ENTRY operand, the label and the // data itself. if (!strcmp(Modifier, "label")) { - unsigned ID = MI->getOperand(OpNo).getImm(); - O << TAI->getPrivateGlobalPrefix() << "CPI" << getFunctionNumber() - << '_' << ID << ":\n"; + unsigned ID = MI->getOperand(OpNum).getImm(); + OutStreamer.EmitLabel(GetCPISymbol(ID)); } else { assert(!strcmp(Modifier, "cpentry") && "Unknown modifier for CPE"); - unsigned CPI = MI->getOperand(OpNo).getConstantPoolIndex(); + unsigned CPI = MI->getOperand(OpNum).getIndex(); - const MachineConstantPoolEntry &MCPE = // Chasing pointers is fun? - MI->getParent()->getParent()->getConstantPool()->getConstants()[CPI]; - - if (MCPE.isMachineConstantPoolEntry()) + const MachineConstantPoolEntry &MCPE = MCP->getConstants()[CPI]; + + if (MCPE.isMachineConstantPoolEntry()) { EmitMachineConstantPoolValue(MCPE.Val.MachineCPVal); - else { + } else { EmitGlobalConstant(MCPE.Val.ConstVal); - // remember to emit the weak reference - if (const GlobalValue *GV = dyn_cast(MCPE.Val.ConstVal)) - if (GV->hasExternalWeakLinkage()) - ExtWeakSymbols.insert(GV); } } } -void ARMAsmPrinter::printJTBlockOperand(const MachineInstr *MI, int OpNo) { - const MachineOperand &MO1 = MI->getOperand(OpNo); - const MachineOperand &MO2 = MI->getOperand(OpNo+1); // Unique Id - unsigned JTI = MO1.getJumpTableIndex(); - O << TAI->getPrivateGlobalPrefix() << "JTI" << getFunctionNumber() - << '_' << JTI << '_' << MO2.getImmedValue() << ":\n"; +MCSymbol *ARMAsmPrinter:: +GetARMSetPICJumpTableLabel2(unsigned uid, unsigned uid2, + const MachineBasicBlock *MBB) const { + SmallString<60> Name; + raw_svector_ostream(Name) << MAI->getPrivateGlobalPrefix() + << getFunctionNumber() << '_' << uid << '_' << uid2 + << "_set_" << MBB->getNumber(); + return OutContext.GetOrCreateSymbol(Name.str()); +} + +MCSymbol *ARMAsmPrinter:: +GetARMJTIPICJumpTableLabel2(unsigned uid, unsigned uid2) const { + SmallString<60> Name; + raw_svector_ostream(Name) << MAI->getPrivateGlobalPrefix() << "JTI" + << getFunctionNumber() << '_' << uid << '_' << uid2; + return OutContext.GetOrCreateSymbol(Name.str()); +} + + +MCSymbol *ARMAsmPrinter::GetARMSJLJEHLabel(void) const { + SmallString<60> Name; + raw_svector_ostream(Name) << MAI->getPrivateGlobalPrefix() << "SJLJEH" + << getFunctionNumber(); + return OutContext.GetOrCreateSymbol(Name.str()); +} + +void ARMAsmPrinter::printJTBlockOperand(const MachineInstr *MI, int OpNum, + raw_ostream &O) { + assert(!Subtarget->isThumb2() && "Thumb2 should use double-jump jumptables!"); - const char *JTEntryDirective = TAI->getJumpTableDirective(); - if (!JTEntryDirective) - JTEntryDirective = TAI->getData32bitsDirective(); + const MachineOperand &MO1 = MI->getOperand(OpNum); + const MachineOperand &MO2 = MI->getOperand(OpNum+1); // Unique Id - const MachineFunction *MF = MI->getParent()->getParent(); - MachineJumpTableInfo *MJTI = MF->getJumpTableInfo(); + unsigned JTI = MO1.getIndex(); + MCSymbol *JTISymbol = GetARMJTIPICJumpTableLabel2(JTI, MO2.getImm()); + // Can't use EmitLabel until instprinter happens, label comes out in the wrong + // order. + O << "\n" << *JTISymbol << ":\n"; + + const char *JTEntryDirective = MAI->getData32bitsDirective(); + + const MachineJumpTableInfo *MJTI = MF->getJumpTableInfo(); const std::vector &JT = MJTI->getJumpTables(); const std::vector &JTBBs = JT[JTI].MBBs; - bool UseSet= TAI->getSetDirective() && TM.getRelocationModel() == Reloc::PIC_; - std::set JTSets; + bool UseSet= MAI->hasSetDirective() && TM.getRelocationModel() == Reloc::PIC_; + SmallPtrSet JTSets; for (unsigned i = 0, e = JTBBs.size(); i != e; ++i) { MachineBasicBlock *MBB = JTBBs[i]; - if (UseSet && JTSets.insert(MBB).second) - printSetLabel(JTI, MO2.getImmedValue(), MBB); + bool isNew = JTSets.insert(MBB); + + if (UseSet && isNew) { + O << "\t.set\t" + << *GetARMSetPICJumpTableLabel2(JTI, MO2.getImm(), MBB) << ',' + << *MBB->getSymbol() << '-' << *JTISymbol << '\n'; + } O << JTEntryDirective << ' '; if (UseSet) - O << TAI->getPrivateGlobalPrefix() << getFunctionNumber() - << '_' << JTI << '_' << MO2.getImmedValue() - << "_set_" << MBB->getNumber(); - else if (TM.getRelocationModel() == Reloc::PIC_) { - printBasicBlockLabel(MBB, false, false); - // If the arch uses custom Jump Table directives, don't calc relative to JT - if (!TAI->getJumpTableDirective()) - O << '-' << TAI->getPrivateGlobalPrefix() << "JTI" - << getFunctionNumber() << '_' << JTI << '_' << MO2.getImmedValue(); - } else - printBasicBlockLabel(MBB, false, false); + O << *GetARMSetPICJumpTableLabel2(JTI, MO2.getImm(), MBB); + else if (TM.getRelocationModel() == Reloc::PIC_) + O << *MBB->getSymbol() << '-' << *JTISymbol; + else + O << *MBB->getSymbol(); + + if (i != e-1) + O << '\n'; + } +} + +void ARMAsmPrinter::printJT2BlockOperand(const MachineInstr *MI, int OpNum, + raw_ostream &O) { + const MachineOperand &MO1 = MI->getOperand(OpNum); + const MachineOperand &MO2 = MI->getOperand(OpNum+1); // Unique Id + unsigned JTI = MO1.getIndex(); + + MCSymbol *JTISymbol = GetARMJTIPICJumpTableLabel2(JTI, MO2.getImm()); + + // Can't use EmitLabel until instprinter happens, label comes out in the wrong + // order. + O << "\n" << *JTISymbol << ":\n"; + + const MachineJumpTableInfo *MJTI = MF->getJumpTableInfo(); + const std::vector &JT = MJTI->getJumpTables(); + const std::vector &JTBBs = JT[JTI].MBBs; + bool ByteOffset = false, HalfWordOffset = false; + if (MI->getOpcode() == ARM::t2TBB) + ByteOffset = true; + else if (MI->getOpcode() == ARM::t2TBH) + HalfWordOffset = true; + + for (unsigned i = 0, e = JTBBs.size(); i != e; ++i) { + MachineBasicBlock *MBB = JTBBs[i]; + if (ByteOffset) + O << MAI->getData8bitsDirective(); + else if (HalfWordOffset) + O << MAI->getData16bitsDirective(); + + if (ByteOffset || HalfWordOffset) + O << '(' << *MBB->getSymbol() << "-" << *JTISymbol << ")/2"; + else + O << "\tb.w " << *MBB->getSymbol(); + if (i != e-1) O << '\n'; } } +void ARMAsmPrinter::printTBAddrMode(const MachineInstr *MI, int OpNum, + raw_ostream &O) { + O << "[pc, " << getRegisterName(MI->getOperand(OpNum).getReg()); + if (MI->getOpcode() == ARM::t2TBH) + O << ", lsl #1"; + O << ']'; +} + +void ARMAsmPrinter::printNoHashImmediate(const MachineInstr *MI, int OpNum, + raw_ostream &O) { + O << MI->getOperand(OpNum).getImm(); +} + +void ARMAsmPrinter::printVFPf32ImmOperand(const MachineInstr *MI, int OpNum, + raw_ostream &O) { + const ConstantFP *FP = MI->getOperand(OpNum).getFPImm(); + O << '#' << FP->getValueAPF().convertToFloat(); + if (isVerbose()) { + O << "\t\t" << MAI->getCommentString() << ' '; + WriteAsOperand(O, FP, /*PrintType=*/false); + } +} + +void ARMAsmPrinter::printVFPf64ImmOperand(const MachineInstr *MI, int OpNum, + raw_ostream &O) { + const ConstantFP *FP = MI->getOperand(OpNum).getFPImm(); + O << '#' << FP->getValueAPF().convertToDouble(); + if (isVerbose()) { + O << "\t\t" << MAI->getCommentString() << ' '; + WriteAsOperand(O, FP, /*PrintType=*/false); + } +} + +void ARMAsmPrinter::printNEONModImmOperand(const MachineInstr *MI, int OpNum, + raw_ostream &O) { + unsigned EncodedImm = MI->getOperand(OpNum).getImm(); + unsigned EltBits; + uint64_t Val = ARM_AM::decodeNEONModImm(EncodedImm, EltBits); + O << "#0x" << utohexstr(Val); +} -bool ARMAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, - unsigned AsmVariant, const char *ExtraCode){ +bool ARMAsmPrinter::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. - + switch (ExtraCode[0]) { default: return true; // Unknown modifier. - case 'c': // Don't print "$" before a global var name or constant. + case 'a': // Print as a memory address. + if (MI->getOperand(OpNum).isReg()) { + O << "[" << getRegisterName(MI->getOperand(OpNum).getReg()) << "]"; + return false; + } + // Fallthrough + case 'c': // Don't print "#" before an immediate operand. + if (!MI->getOperand(OpNum).isImm()) + return true; + printNoHashImmediate(MI, OpNum, O); + return false; case 'P': // Print a VFP double precision register. - printOperand(MI, OpNo); + case 'q': // Print a NEON quad precision register. + printOperand(MI, OpNum, O); return false; case 'Q': - if (TM.getTargetData()->isLittleEndian()) - break; - // Fallthrough case 'R': - if (TM.getTargetData()->isBigEndian()) - break; - // Fallthrough - case 'H': // Write second word of DI / DF reference. - // Verify that this operand has two consecutive registers. - if (!MI->getOperand(OpNo).isRegister() || - OpNo+1 == MI->getNumOperands() || - !MI->getOperand(OpNo+1).isRegister()) - return true; - ++OpNo; // Return the high-part. + case 'H': + report_fatal_error("llvm does not support 'Q', 'R', and 'H' modifiers!"); + return true; } } - - printOperand(MI, OpNo); + + printOperand(MI, OpNum, O); return false; } -void ARMAsmPrinter::printMachineInstruction(const MachineInstr *MI) { - ++EmittedInsts; - - int Opc = MI->getOpcode(); - switch (Opc) { - case ARM::CONSTPOOL_ENTRY: - if (!InCPMode && AFI->isThumbFunction()) { - EmitAlignment(2); - InCPMode = true; - } - break; - default: { - if (InCPMode && AFI->isThumbFunction()) - InCPMode = false; - switch (Opc) { - case ARM::PICADD: - case ARM::PICLD: - case ARM::tPICADD: - break; - default: - O << "\t"; - break; - } - }} - - // Call the autogenerated instruction printer routines. - printInstruction(MI); -} +bool ARMAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, + unsigned OpNum, unsigned AsmVariant, + const char *ExtraCode, + raw_ostream &O) { + if (ExtraCode && ExtraCode[0]) + return true; // Unknown modifier. -bool ARMAsmPrinter::doInitialization(Module &M) { - // Emit initial debug information. - DW.BeginModule(&M); - - return AsmPrinter::doInitialization(M); + const MachineOperand &MO = MI->getOperand(OpNum); + assert(MO.isReg() && "unexpected inline asm memory operand"); + O << "[" << getRegisterName(MO.getReg()) << "]"; + return false; } -bool ARMAsmPrinter::doFinalization(Module &M) { - const TargetData *TD = TM.getTargetData(); - - for (Module::const_global_iterator I = M.global_begin(), E = M.global_end(); - I != E; ++I) { - if (!I->hasInitializer()) // External global require no code - continue; +void ARMAsmPrinter::EmitInstruction(const MachineInstr *MI) { + if (EnableMCInst) { + printInstructionThroughMCStreamer(MI); + return; + } - if (EmitSpecialLLVMGlobal(I)) { - if (Subtarget->isTargetDarwin() && - TM.getRelocationModel() == Reloc::Static) { - if (I->getName() == "llvm.global_ctors") - O << ".reference .constructors_used\n"; - else if (I->getName() == "llvm.global_dtors") - O << ".reference .destructors_used\n"; + if (MI->getOpcode() == ARM::CONSTPOOL_ENTRY) + EmitAlignment(2); + + SmallString<128> Str; + raw_svector_ostream OS(Str); + if (MI->getOpcode() == ARM::DBG_VALUE) { + PrintDebugValueComment(MI, OS); + } else if (MI->getOpcode() == ARM::MOVs) { + // FIXME: Thumb variants? + const MachineOperand &Dst = MI->getOperand(0); + const MachineOperand &MO1 = MI->getOperand(1); + const MachineOperand &MO2 = MI->getOperand(2); + const MachineOperand &MO3 = MI->getOperand(3); + + OS << '\t' << ARM_AM::getShiftOpcStr(ARM_AM::getSORegShOp(MO3.getImm())); + printSBitModifierOperand(MI, 6, OS); + printPredicateOperand(MI, 4, OS); + + OS << '\t' << getRegisterName(Dst.getReg()) + << ", " << getRegisterName(MO1.getReg()); + + if (ARM_AM::getSORegShOp(MO3.getImm()) != ARM_AM::rrx) { + OS << ", "; + + if (MO2.getReg()) { + OS << getRegisterName(MO2.getReg()); + assert(ARM_AM::getSORegOffset(MO3.getImm()) == 0); + } else { + OS << "#" << ARM_AM::getSORegOffset(MO3.getImm()); } - continue; } + } else + // A8.6.123 PUSH + if ((MI->getOpcode() == ARM::STM_UPD || MI->getOpcode() == ARM::t2STM_UPD) && + MI->getOperand(0).getReg() == ARM::SP && + ARM_AM::getAM4SubMode(MI->getOperand(2).getImm()) == ARM_AM::db) { + OS << '\t' << "push"; + printPredicateOperand(MI, 3, OS); + OS << '\t'; + printRegisterList(MI, 5, OS); + } else + // A8.6.122 POP + if ((MI->getOpcode() == ARM::LDM_UPD || MI->getOpcode() == ARM::t2LDM_UPD) && + MI->getOperand(0).getReg() == ARM::SP && + ARM_AM::getAM4SubMode(MI->getOperand(2).getImm()) == ARM_AM::ia) { + OS << '\t' << "pop"; + printPredicateOperand(MI, 3, OS); + OS << '\t'; + printRegisterList(MI, 5, OS); + } else + // A8.6.355 VPUSH + if ((MI->getOpcode() == ARM::VSTMS_UPD || MI->getOpcode() ==ARM::VSTMD_UPD) && + MI->getOperand(0).getReg() == ARM::SP && + ARM_AM::getAM4SubMode(MI->getOperand(2).getImm()) == ARM_AM::db) { + OS << '\t' << "vpush"; + printPredicateOperand(MI, 3, OS); + OS << '\t'; + printRegisterList(MI, 5, OS); + } else + // A8.6.354 VPOP + if ((MI->getOpcode() == ARM::VLDMS_UPD || MI->getOpcode() ==ARM::VLDMD_UPD) && + MI->getOperand(0).getReg() == ARM::SP && + ARM_AM::getAM4SubMode(MI->getOperand(2).getImm()) == ARM_AM::ia) { + OS << '\t' << "vpop"; + printPredicateOperand(MI, 3, OS); + OS << '\t'; + printRegisterList(MI, 5, OS); + } else + // TRAP and tTRAP need special handling for non-Darwin. The GNU binutils + // don't (yet) support the 'trap' mnemonic. (Use decimal, not hex, to + // be consistent with the MC instruction printer.) + // FIXME: This really should be in AsmPrinter/ARMInstPrinter.cpp, not here. + // Need a way to ask "isTargetDarwin()" there, first, though. + if (MI->getOpcode() == ARM::TRAP && !Subtarget->isTargetDarwin()) { + OS << "\t.long\t3892305662\t\t" << MAI->getCommentString() << "trap"; + } else if (MI->getOpcode() == ARM::tTRAP && !Subtarget->isTargetDarwin()) { + OS << "\t.short\t57086\t\t\t" << MAI->getCommentString() << " trap"; + } else + printInstruction(MI, OS); - std::string name = Mang->getValueName(I); - Constant *C = I->getInitializer(); - const Type *Type = C->getType(); - unsigned Size = TD->getTypeSize(Type); - unsigned Align = TD->getPreferredAlignmentLog(I); - - const char *VisibilityDirective = NULL; - if (I->hasHiddenVisibility()) - VisibilityDirective = TAI->getHiddenDirective(); - else if (I->hasProtectedVisibility()) - VisibilityDirective = TAI->getProtectedDirective(); - - if (VisibilityDirective) - O << VisibilityDirective << name << "\n"; - - if (Subtarget->isTargetELF()) - O << "\t.type " << name << ",%object\n"; - - if (C->isNullValue()) { - if (I->hasExternalLinkage()) { - if (const char *Directive = TAI->getZeroFillDirective()) { - O << "\t.globl\t" << name << "\n"; - O << Directive << "__DATA__, __common, " << name << ", " - << Size << ", " << Align << "\n"; - continue; - } - } + // Output the instruction to the stream + OutStreamer.EmitRawText(OS.str()); - if (!I->hasSection() && - (I->hasInternalLinkage() || I->hasWeakLinkage() || - I->hasLinkOnceLinkage())) { - 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 (TAI->getLCOMMDirective() != NULL) { - if (I->hasInternalLinkage()) { - O << TAI->getLCOMMDirective() << name << "," << Size; - if (Subtarget->isTargetDarwin()) - O << "," << Align; - } else - O << TAI->getCOMMDirective() << name << "," << Size; - } else { - if (I->hasInternalLinkage()) - O << "\t.local\t" << name << "\n"; - O << TAI->getCOMMDirective() << name << "," << Size; - if (TAI->getCOMMDirectiveTakesAlignment()) - O << "," << (TAI->getAlignmentIsInBytes() ? (1 << Align) : Align); - } - O << "\t\t" << TAI->getCommentString() << " " << I->getName() << "\n"; - continue; - } - } + // Make sure the instruction that follows TBB is 2-byte aligned. + // FIXME: Constant island pass should insert an "ALIGN" instruction instead. + if (MI->getOpcode() == ARM::t2TBB) + EmitAlignment(1); +} - switch (I->getLinkage()) { - case GlobalValue::LinkOnceLinkage: - case GlobalValue::WeakLinkage: - if (Subtarget->isTargetDarwin()) { - O << "\t.globl " << name << "\n" - << "\t.weak_definition " << name << "\n"; - SwitchToDataSection("\t.section __DATA,__const_coal,coalesced", I); - } else { - std::string SectionName("\t.section\t.llvm.linkonce.d." + - name + - ",\"aw\",%progbits"); - SwitchToDataSection(SectionName.c_str(), I); - O << "\t.weak " << name << "\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: - O << "\t.globl " << name << "\n"; - // FALL THROUGH - case GlobalValue::InternalLinkage: { - if (I->isConstant()) { - const ConstantArray *CVA = dyn_cast(C); - if (TAI->getCStringSection() && CVA && CVA->isCString()) { - SwitchToDataSection(TAI->getCStringSection(), I); - break; - } - } - // FIXME: special handling for ".ctors" & ".dtors" sections - if (I->hasSection() && - (I->getSection() == ".ctors" || - I->getSection() == ".dtors")) { - assert(!Subtarget->isTargetDarwin()); - std::string SectionName = ".section " + I->getSection(); - SectionName += ",\"aw\",%progbits"; - SwitchToDataSection(SectionName.c_str()); +void ARMAsmPrinter::EmitStartOfAsmFile(Module &M) { + if (Subtarget->isTargetDarwin()) { + Reloc::Model RelocM = TM.getRelocationModel(); + if (RelocM == Reloc::PIC_ || RelocM == Reloc::DynamicNoPIC) { + // Declare all the text sections up front (before the DWARF sections + // emitted by AsmPrinter::doInitialization) so the assembler will keep + // them together at the beginning of the object file. This helps + // avoid out-of-range branches that are due a fundamental limitation of + // the way symbol offsets are encoded with the current Darwin ARM + // relocations. + const TargetLoweringObjectFileMachO &TLOFMacho = + static_cast( + getObjFileLowering()); + OutStreamer.SwitchSection(TLOFMacho.getTextSection()); + OutStreamer.SwitchSection(TLOFMacho.getTextCoalSection()); + OutStreamer.SwitchSection(TLOFMacho.getConstTextCoalSection()); + if (RelocM == Reloc::DynamicNoPIC) { + const MCSection *sect = + OutContext.getMachOSection("__TEXT", "__symbol_stub4", + MCSectionMachO::S_SYMBOL_STUBS, + 12, SectionKind::getText()); + OutStreamer.SwitchSection(sect); } else { - if (C->isNullValue() && !NoZerosInBSS && TAI->getBSSSection()) - SwitchToDataSection(I->isThreadLocal() ? TAI->getTLSBSSSection() : - TAI->getBSSSection(), I); - else if (!I->isConstant()) - SwitchToDataSection(I->isThreadLocal() ? TAI->getTLSDataSection() : - TAI->getDataSection(), I); - else if (I->isThreadLocal()) - SwitchToDataSection(TAI->getTLSDataSection()); - else { - // Read-only data. - bool HasReloc = C->ContainsRelocations(); - if (HasReloc && - Subtarget->isTargetDarwin() && - TM.getRelocationModel() != Reloc::Static) - SwitchToDataSection("\t.const_data\n"); - else if (!HasReloc && Size == 4 && - TAI->getFourByteConstantSection()) - SwitchToDataSection(TAI->getFourByteConstantSection(), I); - else if (!HasReloc && Size == 8 && - TAI->getEightByteConstantSection()) - SwitchToDataSection(TAI->getEightByteConstantSection(), I); - else if (!HasReloc && Size == 16 && - TAI->getSixteenByteConstantSection()) - SwitchToDataSection(TAI->getSixteenByteConstantSection(), I); - else if (TAI->getReadOnlySection()) - SwitchToDataSection(TAI->getReadOnlySection(), I); - else - SwitchToDataSection(TAI->getDataSection(), I); - } + const MCSection *sect = + OutContext.getMachOSection("__TEXT", "__picsymbolstub4", + MCSectionMachO::S_SYMBOL_STUBS, + 16, SectionKind::getText()); + OutStreamer.SwitchSection(sect); } - - break; - } - default: - assert(0 && "Unknown linkage type!"); - break; + const MCSection *StaticInitSect = + OutContext.getMachOSection("__TEXT", "__StaticInit", + MCSectionMachO::S_REGULAR | + MCSectionMachO::S_ATTR_PURE_INSTRUCTIONS, + SectionKind::getText()); + OutStreamer.SwitchSection(StaticInitSect); } + } - EmitAlignment(Align, I); - O << name << ":\t\t\t\t" << TAI->getCommentString() << " " << I->getName() - << "\n"; - if (TAI->hasDotTypeDotSizeDirective()) - O << "\t.size " << name << ", " << Size << "\n"; - // If the initializer is a extern weak symbol, remember to emit the weak - // reference! - if (const GlobalValue *GV = dyn_cast(C)) - if (GV->hasExternalWeakLinkage()) - ExtWeakSymbols.insert(GV); + // Use unified assembler syntax. + OutStreamer.EmitRawText(StringRef("\t.syntax unified")); + + // Emit ARM Build Attributes + if (Subtarget->isTargetELF()) { + // CPU Type + std::string CPUString = Subtarget->getCPUString(); + if (CPUString != "generic") + OutStreamer.EmitRawText("\t.cpu " + Twine(CPUString)); + + // FIXME: Emit FPU type + if (Subtarget->hasVFP2()) + OutStreamer.EmitRawText("\t.eabi_attribute " + + Twine(ARMBuildAttrs::VFP_arch) + ", 2"); + + // Signal various FP modes. + if (!UnsafeFPMath) { + OutStreamer.EmitRawText("\t.eabi_attribute " + + Twine(ARMBuildAttrs::ABI_FP_denormal) + ", 1"); + OutStreamer.EmitRawText("\t.eabi_attribute " + + Twine(ARMBuildAttrs::ABI_FP_exceptions) + ", 1"); + } - EmitGlobalConstant(C); - O << '\n'; + if (NoInfsFPMath && NoNaNsFPMath) + OutStreamer.EmitRawText("\t.eabi_attribute " + + Twine(ARMBuildAttrs::ABI_FP_number_model)+ ", 1"); + else + OutStreamer.EmitRawText("\t.eabi_attribute " + + Twine(ARMBuildAttrs::ABI_FP_number_model)+ ", 3"); + + // 8-bytes alignment stuff. + OutStreamer.EmitRawText("\t.eabi_attribute " + + Twine(ARMBuildAttrs::ABI_align8_needed) + ", 1"); + OutStreamer.EmitRawText("\t.eabi_attribute " + + Twine(ARMBuildAttrs::ABI_align8_preserved) + ", 1"); + + // Hard float. Use both S and D registers and conform to AAPCS-VFP. + if (Subtarget->isAAPCS_ABI() && FloatABIType == FloatABI::Hard) { + OutStreamer.EmitRawText("\t.eabi_attribute " + + Twine(ARMBuildAttrs::ABI_HardFP_use) + ", 3"); + OutStreamer.EmitRawText("\t.eabi_attribute " + + Twine(ARMBuildAttrs::ABI_VFP_args) + ", 1"); + } + // FIXME: Should we signal R9 usage? } +} + +void ARMAsmPrinter::EmitEndOfAsmFile(Module &M) { if (Subtarget->isTargetDarwin()) { - SwitchToDataSection(""); - - // Output stubs for dynamically-linked functions - unsigned j = 1; - for (std::set::iterator i = FnStubs.begin(), e = FnStubs.end(); - i != e; ++i, ++j) { - if (TM.getRelocationModel() == Reloc::PIC_) - SwitchToTextSection(".section __TEXT,__picsymbolstub4,symbol_stubs," - "none,16", 0); - else - SwitchToTextSection(".section __TEXT,__symbol_stub4,symbol_stubs," - "none,12", 0); + // All darwin targets use mach-o. + const TargetLoweringObjectFileMachO &TLOFMacho = + static_cast(getObjFileLowering()); + MachineModuleInfoMachO &MMIMacho = + MMI->getObjFileInfo(); + + // Output non-lazy-pointers for external and common global variables. + MachineModuleInfoMachO::SymbolListTy Stubs = MMIMacho.GetGVStubList(); + if (!Stubs.empty()) { + // Switch with ".non_lazy_symbol_pointer" directive. + OutStreamer.SwitchSection(TLOFMacho.getNonLazySymbolPointerSection()); EmitAlignment(2); - O << "\t.code\t32\n"; - - O << "L" << *i << "$stub:\n"; - O << "\t.indirect_symbol " << *i << "\n"; - O << "\tldr ip, L" << *i << "$slp\n"; - if (TM.getRelocationModel() == Reloc::PIC_) { - O << "L" << *i << "$scv:\n"; - O << "\tadd ip, pc, ip\n"; + for (unsigned i = 0, e = Stubs.size(); i != e; ++i) { + // L_foo$stub: + OutStreamer.EmitLabel(Stubs[i].first); + // .indirect_symbol _foo + MachineModuleInfoImpl::StubValueTy &MCSym = Stubs[i].second; + OutStreamer.EmitSymbolAttribute(MCSym.getPointer(),MCSA_IndirectSymbol); + + if (MCSym.getInt()) + // External to current translation unit. + OutStreamer.EmitIntValue(0, 4/*size*/, 0/*addrspace*/); + else + // Internal to current translation unit. + // + // When we place the LSDA into the TEXT section, the type info + // pointers need to be indirect and pc-rel. We accomplish this by + // using NLPs; however, sometimes the types are local to the file. + // We need to fill in the value for the NLP in those cases. + OutStreamer.EmitValue(MCSymbolRefExpr::Create(MCSym.getPointer(), + OutContext), + 4/*size*/, 0/*addrspace*/); } - O << "\tldr pc, [ip, #0]\n"; - O << "L" << *i << "$slp:\n"; - if (TM.getRelocationModel() == Reloc::PIC_) - O << "\t.long\tL" << *i << "$lazy_ptr-(L" << *i << "$scv+8)\n"; - else - O << "\t.long\tL" << *i << "$lazy_ptr\n"; - SwitchToDataSection(".lazy_symbol_pointer", 0); - O << "L" << *i << "$lazy_ptr:\n"; - O << "\t.indirect_symbol " << *i << "\n"; - O << "\t.long\tdyld_stub_binding_helper\n"; - } - O << "\n"; - // Output non-lazy-pointers for external and common global variables. - if (GVNonLazyPtrs.begin() != GVNonLazyPtrs.end()) - SwitchToDataSection(".non_lazy_symbol_pointer", 0); - for (std::set::iterator i = GVNonLazyPtrs.begin(), - e = GVNonLazyPtrs.end(); i != e; ++i) { - O << "L" << *i << "$non_lazy_ptr:\n"; - O << "\t.indirect_symbol " << *i << "\n"; - O << "\t.long\t0\n"; + Stubs.clear(); + OutStreamer.AddBlankLine(); } - // Emit initial debug information. - DW.EndModule(); + Stubs = MMIMacho.GetHiddenGVStubList(); + if (!Stubs.empty()) { + OutStreamer.SwitchSection(getObjFileLowering().getDataSection()); + EmitAlignment(2); + for (unsigned i = 0, e = Stubs.size(); i != e; ++i) { + // L_foo$stub: + OutStreamer.EmitLabel(Stubs[i].first); + // .long _foo + OutStreamer.EmitValue(MCSymbolRefExpr:: + Create(Stubs[i].second.getPointer(), + OutContext), + 4/*size*/, 0/*addrspace*/); + } + + Stubs.clear(); + OutStreamer.AddBlankLine(); + } // Funny Darwin hack: This flag tells the linker that no global symbols // contain code that falls through to other global symbols (e.g. the obvious // implementation of multiple entry points). If this doesn't occur, the // linker can safely perform dead code stripping. Since LLVM never // generates code that does this, it is always safe to set. - O << "\t.subsections_via_symbols\n"; - } else { - // Emit final debug information for ELF. - DW.EndModule(); + OutStreamer.EmitAssemblerFlag(MCAF_SubsectionsViaSymbols); + } +} + +//===----------------------------------------------------------------------===// + +static MCSymbol *getPICLabel(const char *Prefix, unsigned FunctionNumber, + unsigned LabelId, MCContext &Ctx) { + + MCSymbol *Label = Ctx.GetOrCreateSymbol(Twine(Prefix) + + "PC" + Twine(FunctionNumber) + "_" + Twine(LabelId)); + return Label; +} + +void ARMAsmPrinter::EmitJumpTable(const MachineInstr *MI) { + unsigned Opcode = MI->getOpcode(); + int OpNum = 1; + if (Opcode == ARM::BR_JTadd) + OpNum = 2; + else if (Opcode == ARM::BR_JTm) + OpNum = 3; + + const MachineOperand &MO1 = MI->getOperand(OpNum); + const MachineOperand &MO2 = MI->getOperand(OpNum+1); // Unique Id + unsigned JTI = MO1.getIndex(); + + // Emit a label for the jump table. + MCSymbol *JTISymbol = GetARMJTIPICJumpTableLabel2(JTI, MO2.getImm()); + OutStreamer.EmitLabel(JTISymbol); + + // Emit each entry of the table. + const MachineJumpTableInfo *MJTI = MF->getJumpTableInfo(); + const std::vector &JT = MJTI->getJumpTables(); + const std::vector &JTBBs = JT[JTI].MBBs; + + for (unsigned i = 0, e = JTBBs.size(); i != e; ++i) { + MachineBasicBlock *MBB = JTBBs[i]; + // Construct an MCExpr for the entry. We want a value of the form: + // (BasicBlockAddr - TableBeginAddr) + // + // For example, a table with entries jumping to basic blocks BB0 and BB1 + // would look like: + // LJTI_0_0: + // .word (LBB0 - LJTI_0_0) + // .word (LBB1 - LJTI_0_0) + const MCExpr *Expr = MCSymbolRefExpr::Create(MBB->getSymbol(), OutContext); + + if (TM.getRelocationModel() == Reloc::PIC_) + Expr = MCBinaryExpr::CreateSub(Expr, MCSymbolRefExpr::Create(JTISymbol, + OutContext), + OutContext); + OutStreamer.EmitValue(Expr, 4); + } +} + +void ARMAsmPrinter::EmitJump2Table(const MachineInstr *MI) { + unsigned Opcode = MI->getOpcode(); + int OpNum = (Opcode == ARM::t2BR_JT) ? 2 : 1; + const MachineOperand &MO1 = MI->getOperand(OpNum); + const MachineOperand &MO2 = MI->getOperand(OpNum+1); // Unique Id + unsigned JTI = MO1.getIndex(); + + // Emit a label for the jump table. + MCSymbol *JTISymbol = GetARMJTIPICJumpTableLabel2(JTI, MO2.getImm()); + OutStreamer.EmitLabel(JTISymbol); + + // Emit each entry of the table. + const MachineJumpTableInfo *MJTI = MF->getJumpTableInfo(); + const std::vector &JT = MJTI->getJumpTables(); + const std::vector &JTBBs = JT[JTI].MBBs; + unsigned OffsetWidth = 4; + if (MI->getOpcode() == ARM::t2TBB) + OffsetWidth = 1; + else if (MI->getOpcode() == ARM::t2TBH) + OffsetWidth = 2; + + for (unsigned i = 0, e = JTBBs.size(); i != e; ++i) { + MachineBasicBlock *MBB = JTBBs[i]; + const MCExpr *MBBSymbolExpr = MCSymbolRefExpr::Create(MBB->getSymbol(), + OutContext); + // If this isn't a TBB or TBH, the entries are direct branch instructions. + if (OffsetWidth == 4) { + MCInst BrInst; + BrInst.setOpcode(ARM::t2B); + BrInst.addOperand(MCOperand::CreateExpr(MBBSymbolExpr)); + OutStreamer.EmitInstruction(BrInst); + continue; + } + // Otherwise it's an offset from the dispatch instruction. Construct an + // MCExpr for the entry. We want a value of the form: + // (BasicBlockAddr - TableBeginAddr) / 2 + // + // For example, a TBB table with entries jumping to basic blocks BB0 and BB1 + // would look like: + // LJTI_0_0: + // .byte (LBB0 - LJTI_0_0) / 2 + // .byte (LBB1 - LJTI_0_0) / 2 + const MCExpr *Expr = + MCBinaryExpr::CreateSub(MBBSymbolExpr, + MCSymbolRefExpr::Create(JTISymbol, OutContext), + OutContext); + Expr = MCBinaryExpr::CreateDiv(Expr, MCConstantExpr::Create(2, OutContext), + OutContext); + OutStreamer.EmitValue(Expr, OffsetWidth); + } + + // Make sure the instruction that follows TBB is 2-byte aligned. + // FIXME: Constant island pass should insert an "ALIGN" instruction instead. + if (MI->getOpcode() == ARM::t2TBB) + EmitAlignment(1); +} + +void ARMAsmPrinter::PrintDebugValueComment(const MachineInstr *MI, + raw_ostream &OS) { + unsigned NOps = MI->getNumOperands(); + assert(NOps==4); + OS << '\t' << MAI->getCommentString() << "DEBUG_VALUE: "; + // cast away const; DIetc do not take const operands for some reason. + DIVariable V(const_cast(MI->getOperand(NOps-1).getMetadata())); + OS << V.getName(); + OS << " <- "; + // Frame address. Currently handles register +- offset only. + assert(MI->getOperand(0).isReg() && MI->getOperand(1).isImm()); + OS << '['; printOperand(MI, 0, OS); OS << '+'; printOperand(MI, 1, OS); + OS << ']'; + OS << "+"; + printOperand(MI, NOps-2, OS); +} + +void ARMAsmPrinter::printInstructionThroughMCStreamer(const MachineInstr *MI) { + ARMMCInstLower MCInstLowering(OutContext, *Mang, *this); + switch (MI->getOpcode()) { + case ARM::t2MOVi32imm: + assert(0 && "Should be lowered by thumb2it pass"); + default: break; + case ARM::DBG_VALUE: { + if (isVerbose() && OutStreamer.hasRawTextSupport()) { + SmallString<128> TmpStr; + raw_svector_ostream OS(TmpStr); + PrintDebugValueComment(MI, OS); + OutStreamer.EmitRawText(StringRef(OS.str())); + } + return; + } + case ARM::tPICADD: { + // This is a pseudo op for a label + instruction sequence, which looks like: + // LPC0: + // add r0, pc + // This adds the address of LPC0 to r0. + + // Emit the label. + OutStreamer.EmitLabel(getPICLabel(MAI->getPrivateGlobalPrefix(), + getFunctionNumber(), MI->getOperand(2).getImm(), + OutContext)); + + // Form and emit the add. + MCInst AddInst; + AddInst.setOpcode(ARM::tADDhirr); + AddInst.addOperand(MCOperand::CreateReg(MI->getOperand(0).getReg())); + AddInst.addOperand(MCOperand::CreateReg(MI->getOperand(0).getReg())); + AddInst.addOperand(MCOperand::CreateReg(ARM::PC)); + // Add predicate operands. + AddInst.addOperand(MCOperand::CreateImm(ARMCC::AL)); + AddInst.addOperand(MCOperand::CreateReg(0)); + OutStreamer.EmitInstruction(AddInst); + return; + } + case ARM::PICADD: { // FIXME: Remove asm string from td file. + // This is a pseudo op for a label + instruction sequence, which looks like: + // LPC0: + // add r0, pc, r0 + // This adds the address of LPC0 to r0. + + // Emit the label. + OutStreamer.EmitLabel(getPICLabel(MAI->getPrivateGlobalPrefix(), + getFunctionNumber(), MI->getOperand(2).getImm(), + OutContext)); + + // Form and emit the add. + MCInst AddInst; + AddInst.setOpcode(ARM::ADDrr); + AddInst.addOperand(MCOperand::CreateReg(MI->getOperand(0).getReg())); + AddInst.addOperand(MCOperand::CreateReg(ARM::PC)); + AddInst.addOperand(MCOperand::CreateReg(MI->getOperand(1).getReg())); + // Add predicate operands. + AddInst.addOperand(MCOperand::CreateImm(MI->getOperand(3).getImm())); + AddInst.addOperand(MCOperand::CreateReg(MI->getOperand(4).getReg())); + // Add 's' bit operand (always reg0 for this) + AddInst.addOperand(MCOperand::CreateReg(0)); + OutStreamer.EmitInstruction(AddInst); + return; + } + case ARM::PICSTR: + case ARM::PICSTRB: + case ARM::PICSTRH: + case ARM::PICLDR: + case ARM::PICLDRB: + case ARM::PICLDRH: + case ARM::PICLDRSB: + case ARM::PICLDRSH: { + // This is a pseudo op for a label + instruction sequence, which looks like: + // LPC0: + // OP r0, [pc, r0] + // The LCP0 label is referenced by a constant pool entry in order to get + // a PC-relative address at the ldr instruction. + + // Emit the label. + OutStreamer.EmitLabel(getPICLabel(MAI->getPrivateGlobalPrefix(), + getFunctionNumber(), MI->getOperand(2).getImm(), + OutContext)); + + // Form and emit the load + unsigned Opcode; + switch (MI->getOpcode()) { + default: + llvm_unreachable("Unexpected opcode!"); + case ARM::PICSTR: Opcode = ARM::STR; break; + case ARM::PICSTRB: Opcode = ARM::STRB; break; + case ARM::PICSTRH: Opcode = ARM::STRH; break; + case ARM::PICLDR: Opcode = ARM::LDR; break; + case ARM::PICLDRB: Opcode = ARM::LDRB; break; + case ARM::PICLDRH: Opcode = ARM::LDRH; break; + case ARM::PICLDRSB: Opcode = ARM::LDRSB; break; + case ARM::PICLDRSH: Opcode = ARM::LDRSH; break; + } + MCInst LdStInst; + LdStInst.setOpcode(Opcode); + LdStInst.addOperand(MCOperand::CreateReg(MI->getOperand(0).getReg())); + LdStInst.addOperand(MCOperand::CreateReg(ARM::PC)); + LdStInst.addOperand(MCOperand::CreateReg(MI->getOperand(1).getReg())); + LdStInst.addOperand(MCOperand::CreateImm(0)); + // Add predicate operands. + LdStInst.addOperand(MCOperand::CreateImm(MI->getOperand(3).getImm())); + LdStInst.addOperand(MCOperand::CreateReg(MI->getOperand(4).getReg())); + OutStreamer.EmitInstruction(LdStInst); + + return; + } + case ARM::CONSTPOOL_ENTRY: { // FIXME: Remove asm string from td file. + /// 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. + unsigned LabelId = (unsigned)MI->getOperand(0).getImm(); + unsigned CPIdx = (unsigned)MI->getOperand(1).getIndex(); + + EmitAlignment(2); + OutStreamer.EmitLabel(GetCPISymbol(LabelId)); + + const MachineConstantPoolEntry &MCPE = MCP->getConstants()[CPIdx]; + if (MCPE.isMachineConstantPoolEntry()) + EmitMachineConstantPoolValue(MCPE.Val.MachineCPVal); + else + EmitGlobalConstant(MCPE.Val.ConstVal); + + return; + } + case ARM::MOVi2pieces: { // FIXME: Remove asmstring from td file. + // This is a hack that lowers as a two instruction sequence. + unsigned DstReg = MI->getOperand(0).getReg(); + unsigned ImmVal = (unsigned)MI->getOperand(1).getImm(); + + unsigned SOImmValV1 = ARM_AM::getSOImmTwoPartFirst(ImmVal); + unsigned SOImmValV2 = ARM_AM::getSOImmTwoPartSecond(ImmVal); + + { + MCInst TmpInst; + TmpInst.setOpcode(ARM::MOVi); + TmpInst.addOperand(MCOperand::CreateReg(DstReg)); + TmpInst.addOperand(MCOperand::CreateImm(SOImmValV1)); + + // Predicate. + TmpInst.addOperand(MCOperand::CreateImm(MI->getOperand(2).getImm())); + TmpInst.addOperand(MCOperand::CreateReg(MI->getOperand(3).getReg())); + + TmpInst.addOperand(MCOperand::CreateReg(0)); // cc_out + OutStreamer.EmitInstruction(TmpInst); + } + + { + MCInst TmpInst; + TmpInst.setOpcode(ARM::ORRri); + TmpInst.addOperand(MCOperand::CreateReg(DstReg)); // dstreg + TmpInst.addOperand(MCOperand::CreateReg(DstReg)); // inreg + TmpInst.addOperand(MCOperand::CreateImm(SOImmValV2)); // so_imm + // Predicate. + TmpInst.addOperand(MCOperand::CreateImm(MI->getOperand(2).getImm())); + TmpInst.addOperand(MCOperand::CreateReg(MI->getOperand(3).getReg())); + + TmpInst.addOperand(MCOperand::CreateReg(0)); // cc_out + OutStreamer.EmitInstruction(TmpInst); + } + return; + } + case ARM::MOVi32imm: { // FIXME: Remove asmstring from td file. + // This is a hack that lowers as a two instruction sequence. + unsigned DstReg = MI->getOperand(0).getReg(); + const MachineOperand &MO = MI->getOperand(1); + MCOperand V1, V2; + if (MO.isImm()) { + unsigned ImmVal = (unsigned)MI->getOperand(1).getImm(); + V1 = MCOperand::CreateImm(ImmVal & 65535); + V2 = MCOperand::CreateImm(ImmVal >> 16); + } else if (MO.isGlobal()) { + MCSymbol *Symbol = MCInstLowering.GetGlobalAddressSymbol(MO.getGlobal()); + const MCSymbolRefExpr *SymRef1 = + MCSymbolRefExpr::Create(Symbol, + MCSymbolRefExpr::VK_ARM_LO16, OutContext); + const MCSymbolRefExpr *SymRef2 = + MCSymbolRefExpr::Create(Symbol, + MCSymbolRefExpr::VK_ARM_HI16, OutContext); + V1 = MCOperand::CreateExpr(SymRef1); + V2 = MCOperand::CreateExpr(SymRef2); + } else { + // FIXME: External symbol? + MI->dump(); + llvm_unreachable("cannot handle this operand"); + } + + { + MCInst TmpInst; + TmpInst.setOpcode(ARM::MOVi16); + TmpInst.addOperand(MCOperand::CreateReg(DstReg)); // dstreg + TmpInst.addOperand(V1); // lower16(imm) + + // Predicate. + TmpInst.addOperand(MCOperand::CreateImm(MI->getOperand(2).getImm())); + TmpInst.addOperand(MCOperand::CreateReg(MI->getOperand(3).getReg())); + + OutStreamer.EmitInstruction(TmpInst); + } + + { + MCInst TmpInst; + TmpInst.setOpcode(ARM::MOVTi16); + TmpInst.addOperand(MCOperand::CreateReg(DstReg)); // dstreg + TmpInst.addOperand(MCOperand::CreateReg(DstReg)); // srcreg + TmpInst.addOperand(V2); // upper16(imm) + + // Predicate. + TmpInst.addOperand(MCOperand::CreateImm(MI->getOperand(2).getImm())); + TmpInst.addOperand(MCOperand::CreateReg(MI->getOperand(3).getReg())); + + OutStreamer.EmitInstruction(TmpInst); + } + + return; + } + case ARM::t2TBB: + case ARM::t2TBH: + case ARM::t2BR_JT: { + // Lower and emit the instruction itself, then the jump table following it. + MCInst TmpInst; + MCInstLowering.Lower(MI, TmpInst); + OutStreamer.EmitInstruction(TmpInst); + EmitJump2Table(MI); + return; + } + case ARM::tBR_JTr: + case ARM::BR_JTr: + case ARM::BR_JTm: + case ARM::BR_JTadd: { + // Lower and emit the instruction itself, then the jump table following it. + MCInst TmpInst; + MCInstLowering.Lower(MI, TmpInst); + OutStreamer.EmitInstruction(TmpInst); + EmitJumpTable(MI); + return; + } + case ARM::TRAP: { + // Non-Darwin binutils don't yet support the "trap" mnemonic. + // FIXME: Remove this special case when they do. + if (!Subtarget->isTargetDarwin()) { + //.long 0xe7ffdefe ${:comment} trap + uint32_t Val = 0xe7ffdefeUL; + OutStreamer.AddComment("trap"); + OutStreamer.EmitIntValue(Val, 4); + return; + } + break; + } + case ARM::tTRAP: { + // Non-Darwin binutils don't yet support the "trap" mnemonic. + // FIXME: Remove this special case when they do. + if (!Subtarget->isTargetDarwin()) { + //.short 57086 ${:comment} trap + uint16_t Val = 0xdefe; + OutStreamer.AddComment("trap"); + OutStreamer.EmitIntValue(Val, 2); + return; + } + break; + } + case ARM::t2Int_eh_sjlj_setjmp: + case ARM::t2Int_eh_sjlj_setjmp_nofp: + case ARM::tInt_eh_sjlj_setjmp: { // FIXME: Remove asmstring from td file. + // Two incoming args: GPR:$src, GPR:$val + // mov $val, pc + // adds $val, #7 + // str $val, [$src, #4] + // movs r0, #0 + // b 1f + // movs r0, #1 + // 1: + unsigned SrcReg = MI->getOperand(0).getReg(); + unsigned ValReg = MI->getOperand(1).getReg(); + MCSymbol *Label = GetARMSJLJEHLabel(); + { + MCInst TmpInst; + TmpInst.setOpcode(ARM::tMOVgpr2tgpr); + TmpInst.addOperand(MCOperand::CreateReg(ValReg)); + TmpInst.addOperand(MCOperand::CreateReg(ARM::PC)); + // 's' bit operand + TmpInst.addOperand(MCOperand::CreateReg(ARM::CPSR)); + OutStreamer.AddComment("eh_setjmp begin"); + OutStreamer.EmitInstruction(TmpInst); + } + { + MCInst TmpInst; + TmpInst.setOpcode(ARM::tADDi3); + TmpInst.addOperand(MCOperand::CreateReg(ValReg)); + // 's' bit operand + TmpInst.addOperand(MCOperand::CreateReg(ARM::CPSR)); + TmpInst.addOperand(MCOperand::CreateReg(ValReg)); + TmpInst.addOperand(MCOperand::CreateImm(7)); + // Predicate. + TmpInst.addOperand(MCOperand::CreateImm(ARMCC::AL)); + TmpInst.addOperand(MCOperand::CreateReg(0)); + OutStreamer.EmitInstruction(TmpInst); + } + { + MCInst TmpInst; + TmpInst.setOpcode(ARM::tSTR); + TmpInst.addOperand(MCOperand::CreateReg(ValReg)); + TmpInst.addOperand(MCOperand::CreateReg(SrcReg)); + // The offset immediate is #4. The operand value is scaled by 4 for the + // tSTR instruction. + TmpInst.addOperand(MCOperand::CreateImm(1)); + TmpInst.addOperand(MCOperand::CreateReg(0)); + // Predicate. + TmpInst.addOperand(MCOperand::CreateImm(ARMCC::AL)); + TmpInst.addOperand(MCOperand::CreateReg(0)); + OutStreamer.EmitInstruction(TmpInst); + } + { + MCInst TmpInst; + TmpInst.setOpcode(ARM::tMOVi8); + TmpInst.addOperand(MCOperand::CreateReg(ARM::R0)); + TmpInst.addOperand(MCOperand::CreateReg(ARM::CPSR)); + TmpInst.addOperand(MCOperand::CreateImm(0)); + // Predicate. + TmpInst.addOperand(MCOperand::CreateImm(ARMCC::AL)); + TmpInst.addOperand(MCOperand::CreateReg(0)); + OutStreamer.EmitInstruction(TmpInst); + } + { + const MCExpr *SymbolExpr = MCSymbolRefExpr::Create(Label, OutContext); + MCInst TmpInst; + TmpInst.setOpcode(ARM::tB); + TmpInst.addOperand(MCOperand::CreateExpr(SymbolExpr)); + OutStreamer.EmitInstruction(TmpInst); + } + { + MCInst TmpInst; + TmpInst.setOpcode(ARM::tMOVi8); + TmpInst.addOperand(MCOperand::CreateReg(ARM::R0)); + TmpInst.addOperand(MCOperand::CreateReg(ARM::CPSR)); + TmpInst.addOperand(MCOperand::CreateImm(1)); + // Predicate. + TmpInst.addOperand(MCOperand::CreateImm(ARMCC::AL)); + TmpInst.addOperand(MCOperand::CreateReg(0)); + OutStreamer.AddComment("eh_setjmp end"); + OutStreamer.EmitInstruction(TmpInst); + } + OutStreamer.EmitLabel(Label); + return; + } + + case ARM::Int_eh_sjlj_setjmp_nofp: + case ARM::Int_eh_sjlj_setjmp: { // FIXME: Remove asmstring from td file. + // Two incoming args: GPR:$src, GPR:$val + // add $val, pc, #8 + // str $val, [$src, #+4] + // mov r0, #0 + // add pc, pc, #0 + // mov r0, #1 + unsigned SrcReg = MI->getOperand(0).getReg(); + unsigned ValReg = MI->getOperand(1).getReg(); + + { + MCInst TmpInst; + TmpInst.setOpcode(ARM::ADDri); + TmpInst.addOperand(MCOperand::CreateReg(ValReg)); + TmpInst.addOperand(MCOperand::CreateReg(ARM::PC)); + TmpInst.addOperand(MCOperand::CreateImm(8)); + // Predicate. + TmpInst.addOperand(MCOperand::CreateImm(ARMCC::AL)); + TmpInst.addOperand(MCOperand::CreateReg(0)); + // 's' bit operand (always reg0 for this). + TmpInst.addOperand(MCOperand::CreateReg(0)); + OutStreamer.AddComment("eh_setjmp begin"); + OutStreamer.EmitInstruction(TmpInst); + } + { + MCInst TmpInst; + TmpInst.setOpcode(ARM::STR); + TmpInst.addOperand(MCOperand::CreateReg(ValReg)); + TmpInst.addOperand(MCOperand::CreateReg(SrcReg)); + TmpInst.addOperand(MCOperand::CreateReg(0)); + TmpInst.addOperand(MCOperand::CreateImm(4)); + // Predicate. + TmpInst.addOperand(MCOperand::CreateImm(ARMCC::AL)); + TmpInst.addOperand(MCOperand::CreateReg(0)); + OutStreamer.EmitInstruction(TmpInst); + } + { + MCInst TmpInst; + TmpInst.setOpcode(ARM::MOVi); + TmpInst.addOperand(MCOperand::CreateReg(ARM::R0)); + TmpInst.addOperand(MCOperand::CreateImm(0)); + // Predicate. + TmpInst.addOperand(MCOperand::CreateImm(ARMCC::AL)); + TmpInst.addOperand(MCOperand::CreateReg(0)); + // 's' bit operand (always reg0 for this). + TmpInst.addOperand(MCOperand::CreateReg(0)); + OutStreamer.EmitInstruction(TmpInst); + } + { + MCInst TmpInst; + TmpInst.setOpcode(ARM::ADDri); + TmpInst.addOperand(MCOperand::CreateReg(ARM::PC)); + TmpInst.addOperand(MCOperand::CreateReg(ARM::PC)); + TmpInst.addOperand(MCOperand::CreateImm(0)); + // Predicate. + TmpInst.addOperand(MCOperand::CreateImm(ARMCC::AL)); + TmpInst.addOperand(MCOperand::CreateReg(0)); + // 's' bit operand (always reg0 for this). + TmpInst.addOperand(MCOperand::CreateReg(0)); + OutStreamer.EmitInstruction(TmpInst); + } + { + MCInst TmpInst; + TmpInst.setOpcode(ARM::MOVi); + TmpInst.addOperand(MCOperand::CreateReg(ARM::R0)); + TmpInst.addOperand(MCOperand::CreateImm(1)); + // Predicate. + TmpInst.addOperand(MCOperand::CreateImm(ARMCC::AL)); + TmpInst.addOperand(MCOperand::CreateReg(0)); + // 's' bit operand (always reg0 for this). + TmpInst.addOperand(MCOperand::CreateReg(0)); + OutStreamer.AddComment("eh_setjmp end"); + OutStreamer.EmitInstruction(TmpInst); + } + return; + } + case ARM::Int_eh_sjlj_longjmp: { + // ldr sp, [$src, #8] + // ldr $scratch, [$src, #4] + // ldr r7, [$src] + // bx $scratch + unsigned SrcReg = MI->getOperand(0).getReg(); + unsigned ScratchReg = MI->getOperand(1).getReg(); + { + MCInst TmpInst; + TmpInst.setOpcode(ARM::LDR); + TmpInst.addOperand(MCOperand::CreateReg(ARM::SP)); + TmpInst.addOperand(MCOperand::CreateReg(SrcReg)); + TmpInst.addOperand(MCOperand::CreateReg(0)); + TmpInst.addOperand(MCOperand::CreateImm(8)); + // Predicate. + TmpInst.addOperand(MCOperand::CreateImm(ARMCC::AL)); + TmpInst.addOperand(MCOperand::CreateReg(0)); + OutStreamer.EmitInstruction(TmpInst); + } + { + MCInst TmpInst; + TmpInst.setOpcode(ARM::LDR); + TmpInst.addOperand(MCOperand::CreateReg(ScratchReg)); + TmpInst.addOperand(MCOperand::CreateReg(SrcReg)); + TmpInst.addOperand(MCOperand::CreateReg(0)); + TmpInst.addOperand(MCOperand::CreateImm(4)); + // Predicate. + TmpInst.addOperand(MCOperand::CreateImm(ARMCC::AL)); + TmpInst.addOperand(MCOperand::CreateReg(0)); + OutStreamer.EmitInstruction(TmpInst); + } + { + MCInst TmpInst; + TmpInst.setOpcode(ARM::LDR); + TmpInst.addOperand(MCOperand::CreateReg(ARM::R7)); + TmpInst.addOperand(MCOperand::CreateReg(SrcReg)); + TmpInst.addOperand(MCOperand::CreateReg(0)); + TmpInst.addOperand(MCOperand::CreateImm(0)); + // Predicate. + TmpInst.addOperand(MCOperand::CreateImm(ARMCC::AL)); + TmpInst.addOperand(MCOperand::CreateReg(0)); + OutStreamer.EmitInstruction(TmpInst); + } + { + MCInst TmpInst; + TmpInst.setOpcode(ARM::BRIND); + TmpInst.addOperand(MCOperand::CreateReg(ScratchReg)); + // Predicate. + TmpInst.addOperand(MCOperand::CreateImm(ARMCC::AL)); + TmpInst.addOperand(MCOperand::CreateReg(0)); + OutStreamer.EmitInstruction(TmpInst); + } + return; + } + case ARM::tInt_eh_sjlj_longjmp: { + // ldr $scratch, [$src, #8] + // mov sp, $scratch + // ldr $scratch, [$src, #4] + // ldr r7, [$src] + // bx $scratch + unsigned SrcReg = MI->getOperand(0).getReg(); + unsigned ScratchReg = MI->getOperand(1).getReg(); + { + MCInst TmpInst; + TmpInst.setOpcode(ARM::tLDR); + TmpInst.addOperand(MCOperand::CreateReg(ScratchReg)); + TmpInst.addOperand(MCOperand::CreateReg(SrcReg)); + // The offset immediate is #8. The operand value is scaled by 4 for the + // tSTR instruction. + TmpInst.addOperand(MCOperand::CreateImm(2)); + TmpInst.addOperand(MCOperand::CreateReg(0)); + // Predicate. + TmpInst.addOperand(MCOperand::CreateImm(ARMCC::AL)); + TmpInst.addOperand(MCOperand::CreateReg(0)); + OutStreamer.EmitInstruction(TmpInst); + } + { + MCInst TmpInst; + TmpInst.setOpcode(ARM::tMOVtgpr2gpr); + TmpInst.addOperand(MCOperand::CreateReg(ARM::SP)); + TmpInst.addOperand(MCOperand::CreateReg(ScratchReg)); + // Predicate. + TmpInst.addOperand(MCOperand::CreateImm(ARMCC::AL)); + TmpInst.addOperand(MCOperand::CreateReg(0)); + OutStreamer.EmitInstruction(TmpInst); + } + { + MCInst TmpInst; + TmpInst.setOpcode(ARM::tLDR); + TmpInst.addOperand(MCOperand::CreateReg(ScratchReg)); + TmpInst.addOperand(MCOperand::CreateReg(SrcReg)); + TmpInst.addOperand(MCOperand::CreateImm(1)); + TmpInst.addOperand(MCOperand::CreateReg(0)); + // Predicate. + TmpInst.addOperand(MCOperand::CreateImm(ARMCC::AL)); + TmpInst.addOperand(MCOperand::CreateReg(0)); + OutStreamer.EmitInstruction(TmpInst); + } + { + MCInst TmpInst; + TmpInst.setOpcode(ARM::tLDR); + TmpInst.addOperand(MCOperand::CreateReg(ARM::R7)); + TmpInst.addOperand(MCOperand::CreateReg(SrcReg)); + TmpInst.addOperand(MCOperand::CreateImm(0)); + TmpInst.addOperand(MCOperand::CreateReg(0)); + // Predicate. + TmpInst.addOperand(MCOperand::CreateImm(ARMCC::AL)); + TmpInst.addOperand(MCOperand::CreateReg(0)); + OutStreamer.EmitInstruction(TmpInst); + } + { + MCInst TmpInst; + TmpInst.setOpcode(ARM::tBX_RET_vararg); + TmpInst.addOperand(MCOperand::CreateReg(ScratchReg)); + // Predicate. + TmpInst.addOperand(MCOperand::CreateImm(ARMCC::AL)); + TmpInst.addOperand(MCOperand::CreateReg(0)); + OutStreamer.EmitInstruction(TmpInst); + } + return; + } } - AsmPrinter::doFinalization(M); - return false; // success + MCInst TmpInst; + MCInstLowering.Lower(MI, TmpInst); + OutStreamer.EmitInstruction(TmpInst); +} + +//===----------------------------------------------------------------------===// +// Target Registry Stuff +//===----------------------------------------------------------------------===// + +static MCInstPrinter *createARMMCInstPrinter(const Target &T, + unsigned SyntaxVariant, + const MCAsmInfo &MAI) { + if (SyntaxVariant == 0) + return new ARMInstPrinter(MAI); + return 0; +} + +// Force static initialization. +extern "C" void LLVMInitializeARMAsmPrinter() { + RegisterAsmPrinter X(TheARMTarget); + RegisterAsmPrinter Y(TheThumbTarget); + + TargetRegistry::RegisterMCInstPrinter(TheARMTarget, createARMMCInstPrinter); + TargetRegistry::RegisterMCInstPrinter(TheThumbTarget, createARMMCInstPrinter); } +