1 //===-- ARMAsmPrinter.cpp - Print machine code to an ARM .s file ----------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // This file contains a printer that converts from our internal representation
11 // of machine-dependent LLVM code to GAS-format ARM assembly language.
13 //===----------------------------------------------------------------------===//
15 #define DEBUG_TYPE "asm-printer"
17 #include "ARMBuildAttrs.h"
18 #include "ARMAddressingModes.h"
19 #include "ARMConstantPoolValue.h"
20 #include "InstPrinter/ARMInstPrinter.h"
21 #include "ARMMachineFunctionInfo.h"
22 #include "ARMMCInstLower.h"
23 #include "ARMTargetMachine.h"
24 #include "ARMTargetObjectFile.h"
25 #include "llvm/Analysis/DebugInfo.h"
26 #include "llvm/Constants.h"
27 #include "llvm/Module.h"
28 #include "llvm/Type.h"
29 #include "llvm/Assembly/Writer.h"
30 #include "llvm/CodeGen/AsmPrinter.h"
31 #include "llvm/CodeGen/MachineModuleInfoImpls.h"
32 #include "llvm/CodeGen/MachineFunctionPass.h"
33 #include "llvm/CodeGen/MachineJumpTableInfo.h"
34 #include "llvm/MC/MCAsmInfo.h"
35 #include "llvm/MC/MCAssembler.h"
36 #include "llvm/MC/MCContext.h"
37 #include "llvm/MC/MCExpr.h"
38 #include "llvm/MC/MCInst.h"
39 #include "llvm/MC/MCSectionMachO.h"
40 #include "llvm/MC/MCObjectStreamer.h"
41 #include "llvm/MC/MCStreamer.h"
42 #include "llvm/MC/MCSymbol.h"
43 #include "llvm/Target/Mangler.h"
44 #include "llvm/Target/TargetData.h"
45 #include "llvm/Target/TargetMachine.h"
46 #include "llvm/Target/TargetOptions.h"
47 #include "llvm/Target/TargetRegistry.h"
48 #include "llvm/ADT/SmallPtrSet.h"
49 #include "llvm/ADT/SmallString.h"
50 #include "llvm/ADT/StringExtras.h"
51 #include "llvm/Support/CommandLine.h"
52 #include "llvm/Support/Debug.h"
53 #include "llvm/Support/ErrorHandling.h"
54 #include "llvm/Support/raw_ostream.h"
69 // Per section and per symbol attributes are not supported.
70 // To implement them we would need the ability to delay this emission
71 // until the assembly file is fully parsed/generated as only then do we
72 // know the symbol and section numbers.
73 class AttributeEmitter {
75 virtual void MaybeSwitchVendor(StringRef Vendor) = 0;
76 virtual void EmitAttribute(unsigned Attribute, unsigned Value) = 0;
77 virtual void Finish() = 0;
78 virtual ~AttributeEmitter() {}
81 class AsmAttributeEmitter : public AttributeEmitter {
85 AsmAttributeEmitter(MCStreamer &Streamer_) : Streamer(Streamer_) {}
86 void MaybeSwitchVendor(StringRef Vendor) { }
88 void EmitAttribute(unsigned Attribute, unsigned Value) {
89 Streamer.EmitRawText("\t.eabi_attribute " +
90 Twine(Attribute) + ", " + Twine(Value));
96 class ObjectAttributeEmitter : public AttributeEmitter {
97 MCObjectStreamer &Streamer;
98 StringRef CurrentVendor;
99 SmallString<64> Contents;
102 ObjectAttributeEmitter(MCObjectStreamer &Streamer_) :
103 Streamer(Streamer_), CurrentVendor("") { }
105 void MaybeSwitchVendor(StringRef Vendor) {
106 assert(!Vendor.empty() && "Vendor cannot be empty.");
108 if (CurrentVendor.empty())
109 CurrentVendor = Vendor;
110 else if (CurrentVendor == Vendor)
115 CurrentVendor = Vendor;
117 assert(Contents.size() == 0);
120 void EmitAttribute(unsigned Attribute, unsigned Value) {
121 // FIXME: should be ULEB
122 Contents += Attribute;
127 const size_t ContentsSize = Contents.size();
129 // Vendor size + Vendor name + '\0'
130 const size_t VendorHeaderSize = 4 + CurrentVendor.size() + 1;
133 const size_t TagHeaderSize = 1 + 4;
135 Streamer.EmitIntValue(VendorHeaderSize + TagHeaderSize + ContentsSize, 4);
136 Streamer.EmitBytes(CurrentVendor, 0);
137 Streamer.EmitIntValue(0, 1); // '\0'
139 Streamer.EmitIntValue(ARMBuildAttrs::File, 1);
140 Streamer.EmitIntValue(TagHeaderSize + ContentsSize, 4);
142 Streamer.EmitBytes(Contents, 0);
148 class ARMAsmPrinter : public AsmPrinter {
150 /// Subtarget - Keep a pointer to the ARMSubtarget around so that we can
151 /// make the right decision when printing asm code for different targets.
152 const ARMSubtarget *Subtarget;
154 /// AFI - Keep a pointer to ARMFunctionInfo for the current
156 ARMFunctionInfo *AFI;
158 /// MCP - Keep a pointer to constantpool entries of the current
160 const MachineConstantPool *MCP;
163 explicit ARMAsmPrinter(TargetMachine &TM, MCStreamer &Streamer)
164 : AsmPrinter(TM, Streamer), AFI(NULL), MCP(NULL) {
165 Subtarget = &TM.getSubtarget<ARMSubtarget>();
168 virtual const char *getPassName() const {
169 return "ARM Assembly Printer";
172 void printOperand(const MachineInstr *MI, int OpNum, raw_ostream &O,
173 const char *Modifier = 0);
175 virtual bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNum,
176 unsigned AsmVariant, const char *ExtraCode,
178 virtual bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNum,
180 const char *ExtraCode, raw_ostream &O);
182 void EmitJumpTable(const MachineInstr *MI);
183 void EmitJump2Table(const MachineInstr *MI);
184 virtual void EmitInstruction(const MachineInstr *MI);
185 bool runOnMachineFunction(MachineFunction &F);
187 virtual void EmitConstantPool() {} // we emit constant pools customly!
188 virtual void EmitFunctionEntryLabel();
189 void EmitStartOfAsmFile(Module &M);
190 void EmitEndOfAsmFile(Module &M);
193 // Helpers for EmitStartOfAsmFile() and EmitEndOfAsmFile()
194 void emitAttributes();
196 // Helper for ELF .o only
197 void emitARMAttributeSection();
200 void PrintDebugValueComment(const MachineInstr *MI, raw_ostream &OS);
202 MachineLocation getDebugValueLocation(const MachineInstr *MI) const {
203 MachineLocation Location;
204 assert (MI->getNumOperands() == 4 && "Invalid no. of machine operands!");
205 // Frame address. Currently handles register +- offset only.
206 if (MI->getOperand(0).isReg() && MI->getOperand(1).isImm())
207 Location.set(MI->getOperand(0).getReg(), MI->getOperand(1).getImm());
209 DEBUG(dbgs() << "DBG_VALUE instruction ignored! " << *MI << "\n");
214 virtual unsigned getISAEncoding() {
215 // ARM/Darwin adds ISA to the DWARF info for each function.
216 if (!Subtarget->isTargetDarwin())
218 return Subtarget->isThumb() ?
219 llvm::ARM::DW_ISA_ARM_thumb : llvm::ARM::DW_ISA_ARM_arm;
222 MCSymbol *GetARMSetPICJumpTableLabel2(unsigned uid, unsigned uid2,
223 const MachineBasicBlock *MBB) const;
224 MCSymbol *GetARMJTIPICJumpTableLabel2(unsigned uid, unsigned uid2) const;
226 MCSymbol *GetARMSJLJEHLabel(void) const;
228 /// EmitMachineConstantPoolValue - Print a machine constantpool value to
230 virtual void EmitMachineConstantPoolValue(MachineConstantPoolValue *MCPV) {
231 SmallString<128> Str;
232 raw_svector_ostream OS(Str);
233 EmitMachineConstantPoolValue(MCPV, OS);
234 // FIXME: non-assembly streamer support.
235 OutStreamer.EmitRawText(OS.str());
238 void EmitMachineConstantPoolValue(MachineConstantPoolValue *MCPV,
240 switch (TM.getTargetData()->getTypeAllocSize(MCPV->getType())) {
241 case 1: O << MAI->getData8bitsDirective(0); break;
242 case 2: O << MAI->getData16bitsDirective(0); break;
243 case 4: O << MAI->getData32bitsDirective(0); break;
244 default: assert(0 && "Unknown CPV size");
247 ARMConstantPoolValue *ACPV = static_cast<ARMConstantPoolValue*>(MCPV);
249 if (ACPV->isLSDA()) {
250 O << MAI->getPrivateGlobalPrefix() << "_LSDA_" << getFunctionNumber();
251 } else if (ACPV->isBlockAddress()) {
252 O << *GetBlockAddressSymbol(ACPV->getBlockAddress());
253 } else if (ACPV->isGlobalValue()) {
254 const GlobalValue *GV = ACPV->getGV();
255 bool isIndirect = Subtarget->isTargetDarwin() &&
256 Subtarget->GVIsIndirectSymbol(GV, TM.getRelocationModel());
258 O << *Mang->getSymbol(GV);
260 // FIXME: Remove this when Darwin transition to @GOT like syntax.
261 MCSymbol *Sym = GetSymbolWithGlobalValueBase(GV, "$non_lazy_ptr");
264 MachineModuleInfoMachO &MMIMachO =
265 MMI->getObjFileInfo<MachineModuleInfoMachO>();
266 MachineModuleInfoImpl::StubValueTy &StubSym =
267 GV->hasHiddenVisibility() ? MMIMachO.getHiddenGVStubEntry(Sym) :
268 MMIMachO.getGVStubEntry(Sym);
269 if (StubSym.getPointer() == 0)
270 StubSym = MachineModuleInfoImpl::
271 StubValueTy(Mang->getSymbol(GV), !GV->hasInternalLinkage());
274 assert(ACPV->isExtSymbol() && "unrecognized constant pool value");
275 O << *GetExternalSymbolSymbol(ACPV->getSymbol());
278 if (ACPV->hasModifier()) O << "(" << ACPV->getModifier() << ")";
279 if (ACPV->getPCAdjustment() != 0) {
280 O << "-(" << MAI->getPrivateGlobalPrefix() << "PC"
281 << getFunctionNumber() << "_" << ACPV->getLabelId()
282 << "+" << (unsigned)ACPV->getPCAdjustment();
283 if (ACPV->mustAddCurrentAddress())
289 } // end of anonymous namespace
291 void ARMAsmPrinter::EmitFunctionEntryLabel() {
292 if (AFI->isThumbFunction()) {
293 OutStreamer.EmitRawText(StringRef("\t.code\t16"));
294 if (!Subtarget->isTargetDarwin())
295 OutStreamer.EmitRawText(StringRef("\t.thumb_func"));
297 // This needs to emit to a temporary string to get properly quoted
298 // MCSymbols when they have spaces in them.
299 SmallString<128> Tmp;
300 raw_svector_ostream OS(Tmp);
301 OS << "\t.thumb_func\t" << *CurrentFnSym;
302 OutStreamer.EmitRawText(OS.str());
306 OutStreamer.EmitLabel(CurrentFnSym);
309 /// runOnMachineFunction - This uses the EmitInstruction()
310 /// method to print assembly for each instruction.
312 bool ARMAsmPrinter::runOnMachineFunction(MachineFunction &MF) {
313 AFI = MF.getInfo<ARMFunctionInfo>();
314 MCP = MF.getConstantPool();
316 return AsmPrinter::runOnMachineFunction(MF);
319 void ARMAsmPrinter::printOperand(const MachineInstr *MI, int OpNum,
320 raw_ostream &O, const char *Modifier) {
321 const MachineOperand &MO = MI->getOperand(OpNum);
322 unsigned TF = MO.getTargetFlags();
324 switch (MO.getType()) {
326 assert(0 && "<unknown operand type>");
327 case MachineOperand::MO_Register: {
328 unsigned Reg = MO.getReg();
329 assert(TargetRegisterInfo::isPhysicalRegister(Reg));
330 assert(!MO.getSubReg() && "Subregs should be eliminated!");
331 O << ARMInstPrinter::getRegisterName(Reg);
334 case MachineOperand::MO_Immediate: {
335 int64_t Imm = MO.getImm();
337 if ((Modifier && strcmp(Modifier, "lo16") == 0) ||
338 (TF == ARMII::MO_LO16))
340 else if ((Modifier && strcmp(Modifier, "hi16") == 0) ||
341 (TF == ARMII::MO_HI16))
346 case MachineOperand::MO_MachineBasicBlock:
347 O << *MO.getMBB()->getSymbol();
349 case MachineOperand::MO_GlobalAddress: {
350 const GlobalValue *GV = MO.getGlobal();
351 if ((Modifier && strcmp(Modifier, "lo16") == 0) ||
352 (TF & ARMII::MO_LO16))
354 else if ((Modifier && strcmp(Modifier, "hi16") == 0) ||
355 (TF & ARMII::MO_HI16))
357 O << *Mang->getSymbol(GV);
359 printOffset(MO.getOffset(), O);
360 if (TF == ARMII::MO_PLT)
364 case MachineOperand::MO_ExternalSymbol: {
365 O << *GetExternalSymbolSymbol(MO.getSymbolName());
366 if (TF == ARMII::MO_PLT)
370 case MachineOperand::MO_ConstantPoolIndex:
371 O << *GetCPISymbol(MO.getIndex());
373 case MachineOperand::MO_JumpTableIndex:
374 O << *GetJTISymbol(MO.getIndex());
379 //===--------------------------------------------------------------------===//
381 MCSymbol *ARMAsmPrinter::
382 GetARMSetPICJumpTableLabel2(unsigned uid, unsigned uid2,
383 const MachineBasicBlock *MBB) const {
384 SmallString<60> Name;
385 raw_svector_ostream(Name) << MAI->getPrivateGlobalPrefix()
386 << getFunctionNumber() << '_' << uid << '_' << uid2
387 << "_set_" << MBB->getNumber();
388 return OutContext.GetOrCreateSymbol(Name.str());
391 MCSymbol *ARMAsmPrinter::
392 GetARMJTIPICJumpTableLabel2(unsigned uid, unsigned uid2) const {
393 SmallString<60> Name;
394 raw_svector_ostream(Name) << MAI->getPrivateGlobalPrefix() << "JTI"
395 << getFunctionNumber() << '_' << uid << '_' << uid2;
396 return OutContext.GetOrCreateSymbol(Name.str());
400 MCSymbol *ARMAsmPrinter::GetARMSJLJEHLabel(void) const {
401 SmallString<60> Name;
402 raw_svector_ostream(Name) << MAI->getPrivateGlobalPrefix() << "SJLJEH"
403 << getFunctionNumber();
404 return OutContext.GetOrCreateSymbol(Name.str());
407 bool ARMAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNum,
408 unsigned AsmVariant, const char *ExtraCode,
410 // Does this asm operand have a single letter operand modifier?
411 if (ExtraCode && ExtraCode[0]) {
412 if (ExtraCode[1] != 0) return true; // Unknown modifier.
414 switch (ExtraCode[0]) {
415 default: return true; // Unknown modifier.
416 case 'a': // Print as a memory address.
417 if (MI->getOperand(OpNum).isReg()) {
419 << ARMInstPrinter::getRegisterName(MI->getOperand(OpNum).getReg())
424 case 'c': // Don't print "#" before an immediate operand.
425 if (!MI->getOperand(OpNum).isImm())
427 O << MI->getOperand(OpNum).getImm();
429 case 'P': // Print a VFP double precision register.
430 case 'q': // Print a NEON quad precision register.
431 printOperand(MI, OpNum, O);
436 report_fatal_error("llvm does not support 'Q', 'R', and 'H' modifiers!");
441 printOperand(MI, OpNum, O);
445 bool ARMAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,
446 unsigned OpNum, unsigned AsmVariant,
447 const char *ExtraCode,
449 if (ExtraCode && ExtraCode[0])
450 return true; // Unknown modifier.
452 const MachineOperand &MO = MI->getOperand(OpNum);
453 assert(MO.isReg() && "unexpected inline asm memory operand");
454 O << "[" << ARMInstPrinter::getRegisterName(MO.getReg()) << "]";
458 void ARMAsmPrinter::EmitStartOfAsmFile(Module &M) {
459 if (Subtarget->isTargetDarwin()) {
460 Reloc::Model RelocM = TM.getRelocationModel();
461 if (RelocM == Reloc::PIC_ || RelocM == Reloc::DynamicNoPIC) {
462 // Declare all the text sections up front (before the DWARF sections
463 // emitted by AsmPrinter::doInitialization) so the assembler will keep
464 // them together at the beginning of the object file. This helps
465 // avoid out-of-range branches that are due a fundamental limitation of
466 // the way symbol offsets are encoded with the current Darwin ARM
468 const TargetLoweringObjectFileMachO &TLOFMacho =
469 static_cast<const TargetLoweringObjectFileMachO &>(
470 getObjFileLowering());
471 OutStreamer.SwitchSection(TLOFMacho.getTextSection());
472 OutStreamer.SwitchSection(TLOFMacho.getTextCoalSection());
473 OutStreamer.SwitchSection(TLOFMacho.getConstTextCoalSection());
474 if (RelocM == Reloc::DynamicNoPIC) {
475 const MCSection *sect =
476 OutContext.getMachOSection("__TEXT", "__symbol_stub4",
477 MCSectionMachO::S_SYMBOL_STUBS,
478 12, SectionKind::getText());
479 OutStreamer.SwitchSection(sect);
481 const MCSection *sect =
482 OutContext.getMachOSection("__TEXT", "__picsymbolstub4",
483 MCSectionMachO::S_SYMBOL_STUBS,
484 16, SectionKind::getText());
485 OutStreamer.SwitchSection(sect);
487 const MCSection *StaticInitSect =
488 OutContext.getMachOSection("__TEXT", "__StaticInit",
489 MCSectionMachO::S_REGULAR |
490 MCSectionMachO::S_ATTR_PURE_INSTRUCTIONS,
491 SectionKind::getText());
492 OutStreamer.SwitchSection(StaticInitSect);
496 // Use unified assembler syntax.
497 OutStreamer.EmitAssemblerFlag(MCAF_SyntaxUnified);
499 // Emit ARM Build Attributes
500 if (Subtarget->isTargetELF()) {
507 void ARMAsmPrinter::EmitEndOfAsmFile(Module &M) {
508 if (Subtarget->isTargetDarwin()) {
509 // All darwin targets use mach-o.
510 const TargetLoweringObjectFileMachO &TLOFMacho =
511 static_cast<const TargetLoweringObjectFileMachO &>(getObjFileLowering());
512 MachineModuleInfoMachO &MMIMacho =
513 MMI->getObjFileInfo<MachineModuleInfoMachO>();
515 // Output non-lazy-pointers for external and common global variables.
516 MachineModuleInfoMachO::SymbolListTy Stubs = MMIMacho.GetGVStubList();
518 if (!Stubs.empty()) {
519 // Switch with ".non_lazy_symbol_pointer" directive.
520 OutStreamer.SwitchSection(TLOFMacho.getNonLazySymbolPointerSection());
522 for (unsigned i = 0, e = Stubs.size(); i != e; ++i) {
524 OutStreamer.EmitLabel(Stubs[i].first);
525 // .indirect_symbol _foo
526 MachineModuleInfoImpl::StubValueTy &MCSym = Stubs[i].second;
527 OutStreamer.EmitSymbolAttribute(MCSym.getPointer(),MCSA_IndirectSymbol);
530 // External to current translation unit.
531 OutStreamer.EmitIntValue(0, 4/*size*/, 0/*addrspace*/);
533 // Internal to current translation unit.
535 // When we place the LSDA into the TEXT section, the type info
536 // pointers need to be indirect and pc-rel. We accomplish this by
537 // using NLPs; however, sometimes the types are local to the file.
538 // We need to fill in the value for the NLP in those cases.
539 OutStreamer.EmitValue(MCSymbolRefExpr::Create(MCSym.getPointer(),
541 4/*size*/, 0/*addrspace*/);
545 OutStreamer.AddBlankLine();
548 Stubs = MMIMacho.GetHiddenGVStubList();
549 if (!Stubs.empty()) {
550 OutStreamer.SwitchSection(getObjFileLowering().getDataSection());
552 for (unsigned i = 0, e = Stubs.size(); i != e; ++i) {
554 OutStreamer.EmitLabel(Stubs[i].first);
556 OutStreamer.EmitValue(MCSymbolRefExpr::
557 Create(Stubs[i].second.getPointer(),
559 4/*size*/, 0/*addrspace*/);
563 OutStreamer.AddBlankLine();
566 // Funny Darwin hack: This flag tells the linker that no global symbols
567 // contain code that falls through to other global symbols (e.g. the obvious
568 // implementation of multiple entry points). If this doesn't occur, the
569 // linker can safely perform dead code stripping. Since LLVM never
570 // generates code that does this, it is always safe to set.
571 OutStreamer.EmitAssemblerFlag(MCAF_SubsectionsViaSymbols);
575 //===----------------------------------------------------------------------===//
576 // Helper routines for EmitStartOfAsmFile() and EmitEndOfAsmFile()
578 // The following seem like one-off assembler flags, but they actually need
579 // to appear in the .ARM.attributes section in ELF.
580 // Instead of subclassing the MCELFStreamer, we do the work here.
582 void ARMAsmPrinter::emitAttributes() {
584 emitARMAttributeSection();
586 AttributeEmitter *AttrEmitter;
587 if (OutStreamer.hasRawTextSupport())
588 AttrEmitter = new AsmAttributeEmitter(OutStreamer);
590 MCObjectStreamer &O = static_cast<MCObjectStreamer&>(OutStreamer);
591 AttrEmitter = new ObjectAttributeEmitter(O);
594 AttrEmitter->MaybeSwitchVendor("aeabi");
596 std::string CPUString = Subtarget->getCPUString();
597 if (OutStreamer.hasRawTextSupport()) {
598 if (CPUString != "generic")
599 OutStreamer.EmitRawText(StringRef("\t.cpu ") + CPUString);
601 assert(CPUString == "generic" && "Unsupported .cpu attribute for ELF/.o");
602 // FIXME: Why these defaults?
603 AttrEmitter->EmitAttribute(ARMBuildAttrs::CPU_arch, ARMBuildAttrs::v4T);
604 AttrEmitter->EmitAttribute(ARMBuildAttrs::ARM_ISA_use, 1);
605 AttrEmitter->EmitAttribute(ARMBuildAttrs::THUMB_ISA_use, 1);
608 // FIXME: Emit FPU type
609 if (Subtarget->hasVFP2())
610 AttrEmitter->EmitAttribute(ARMBuildAttrs::VFP_arch, 2);
612 // Signal various FP modes.
614 AttrEmitter->EmitAttribute(ARMBuildAttrs::ABI_FP_denormal, 1);
615 AttrEmitter->EmitAttribute(ARMBuildAttrs::ABI_FP_exceptions, 1);
618 if (NoInfsFPMath && NoNaNsFPMath)
619 AttrEmitter->EmitAttribute(ARMBuildAttrs::ABI_FP_number_model, 1);
621 AttrEmitter->EmitAttribute(ARMBuildAttrs::ABI_FP_number_model, 3);
623 // 8-bytes alignment stuff.
624 AttrEmitter->EmitAttribute(ARMBuildAttrs::ABI_align8_needed, 1);
625 AttrEmitter->EmitAttribute(ARMBuildAttrs::ABI_align8_preserved, 1);
627 // Hard float. Use both S and D registers and conform to AAPCS-VFP.
628 if (Subtarget->isAAPCS_ABI() && FloatABIType == FloatABI::Hard) {
629 AttrEmitter->EmitAttribute(ARMBuildAttrs::ABI_HardFP_use, 3);
630 AttrEmitter->EmitAttribute(ARMBuildAttrs::ABI_VFP_args, 1);
632 // FIXME: Should we signal R9 usage?
634 AttrEmitter->EmitAttribute(ARMBuildAttrs::DIV_use, 1);
636 AttrEmitter->Finish();
640 void ARMAsmPrinter::emitARMAttributeSection() {
642 // [ <section-length> "vendor-name"
643 // [ <file-tag> <size> <attribute>*
644 // | <section-tag> <size> <section-number>* 0 <attribute>*
645 // | <symbol-tag> <size> <symbol-number>* 0 <attribute>*
649 if (OutStreamer.hasRawTextSupport())
652 const ARMElfTargetObjectFile &TLOFELF =
653 static_cast<const ARMElfTargetObjectFile &>
654 (getObjFileLowering());
656 OutStreamer.SwitchSection(TLOFELF.getAttributesSection());
659 OutStreamer.EmitIntValue(0x41, 1);
662 //===----------------------------------------------------------------------===//
664 static MCSymbol *getPICLabel(const char *Prefix, unsigned FunctionNumber,
665 unsigned LabelId, MCContext &Ctx) {
667 MCSymbol *Label = Ctx.GetOrCreateSymbol(Twine(Prefix)
668 + "PC" + Twine(FunctionNumber) + "_" + Twine(LabelId));
672 void ARMAsmPrinter::EmitJumpTable(const MachineInstr *MI) {
673 unsigned Opcode = MI->getOpcode();
675 if (Opcode == ARM::BR_JTadd)
677 else if (Opcode == ARM::BR_JTm)
680 const MachineOperand &MO1 = MI->getOperand(OpNum);
681 const MachineOperand &MO2 = MI->getOperand(OpNum+1); // Unique Id
682 unsigned JTI = MO1.getIndex();
684 // Emit a label for the jump table.
685 MCSymbol *JTISymbol = GetARMJTIPICJumpTableLabel2(JTI, MO2.getImm());
686 OutStreamer.EmitLabel(JTISymbol);
688 // Emit each entry of the table.
689 const MachineJumpTableInfo *MJTI = MF->getJumpTableInfo();
690 const std::vector<MachineJumpTableEntry> &JT = MJTI->getJumpTables();
691 const std::vector<MachineBasicBlock*> &JTBBs = JT[JTI].MBBs;
693 for (unsigned i = 0, e = JTBBs.size(); i != e; ++i) {
694 MachineBasicBlock *MBB = JTBBs[i];
695 // Construct an MCExpr for the entry. We want a value of the form:
696 // (BasicBlockAddr - TableBeginAddr)
698 // For example, a table with entries jumping to basic blocks BB0 and BB1
701 // .word (LBB0 - LJTI_0_0)
702 // .word (LBB1 - LJTI_0_0)
703 const MCExpr *Expr = MCSymbolRefExpr::Create(MBB->getSymbol(), OutContext);
705 if (TM.getRelocationModel() == Reloc::PIC_)
706 Expr = MCBinaryExpr::CreateSub(Expr, MCSymbolRefExpr::Create(JTISymbol,
709 OutStreamer.EmitValue(Expr, 4);
713 void ARMAsmPrinter::EmitJump2Table(const MachineInstr *MI) {
714 unsigned Opcode = MI->getOpcode();
715 int OpNum = (Opcode == ARM::t2BR_JT) ? 2 : 1;
716 const MachineOperand &MO1 = MI->getOperand(OpNum);
717 const MachineOperand &MO2 = MI->getOperand(OpNum+1); // Unique Id
718 unsigned JTI = MO1.getIndex();
720 // Emit a label for the jump table.
721 MCSymbol *JTISymbol = GetARMJTIPICJumpTableLabel2(JTI, MO2.getImm());
722 OutStreamer.EmitLabel(JTISymbol);
724 // Emit each entry of the table.
725 const MachineJumpTableInfo *MJTI = MF->getJumpTableInfo();
726 const std::vector<MachineJumpTableEntry> &JT = MJTI->getJumpTables();
727 const std::vector<MachineBasicBlock*> &JTBBs = JT[JTI].MBBs;
728 unsigned OffsetWidth = 4;
729 if (MI->getOpcode() == ARM::t2TBB)
731 else if (MI->getOpcode() == ARM::t2TBH)
734 for (unsigned i = 0, e = JTBBs.size(); i != e; ++i) {
735 MachineBasicBlock *MBB = JTBBs[i];
736 const MCExpr *MBBSymbolExpr = MCSymbolRefExpr::Create(MBB->getSymbol(),
738 // If this isn't a TBB or TBH, the entries are direct branch instructions.
739 if (OffsetWidth == 4) {
741 BrInst.setOpcode(ARM::t2B);
742 BrInst.addOperand(MCOperand::CreateExpr(MBBSymbolExpr));
743 OutStreamer.EmitInstruction(BrInst);
746 // Otherwise it's an offset from the dispatch instruction. Construct an
747 // MCExpr for the entry. We want a value of the form:
748 // (BasicBlockAddr - TableBeginAddr) / 2
750 // For example, a TBB table with entries jumping to basic blocks BB0 and BB1
753 // .byte (LBB0 - LJTI_0_0) / 2
754 // .byte (LBB1 - LJTI_0_0) / 2
756 MCBinaryExpr::CreateSub(MBBSymbolExpr,
757 MCSymbolRefExpr::Create(JTISymbol, OutContext),
759 Expr = MCBinaryExpr::CreateDiv(Expr, MCConstantExpr::Create(2, OutContext),
761 OutStreamer.EmitValue(Expr, OffsetWidth);
764 // Make sure the instruction that follows TBB is 2-byte aligned.
765 // FIXME: Constant island pass should insert an "ALIGN" instruction instead.
766 if (MI->getOpcode() == ARM::t2TBB)
770 void ARMAsmPrinter::PrintDebugValueComment(const MachineInstr *MI,
772 unsigned NOps = MI->getNumOperands();
774 OS << '\t' << MAI->getCommentString() << "DEBUG_VALUE: ";
775 // cast away const; DIetc do not take const operands for some reason.
776 DIVariable V(const_cast<MDNode *>(MI->getOperand(NOps-1).getMetadata()));
779 // Frame address. Currently handles register +- offset only.
780 assert(MI->getOperand(0).isReg() && MI->getOperand(1).isImm());
781 OS << '['; printOperand(MI, 0, OS); OS << '+'; printOperand(MI, 1, OS);
784 printOperand(MI, NOps-2, OS);
787 void ARMAsmPrinter::EmitInstruction(const MachineInstr *MI) {
788 ARMMCInstLower MCInstLowering(OutContext, *Mang, *this);
789 switch (MI->getOpcode()) {
790 case ARM::t2MOVi32imm:
791 assert(0 && "Should be lowered by thumb2it pass");
793 case ARM::DBG_VALUE: {
794 if (isVerbose() && OutStreamer.hasRawTextSupport()) {
795 SmallString<128> TmpStr;
796 raw_svector_ostream OS(TmpStr);
797 PrintDebugValueComment(MI, OS);
798 OutStreamer.EmitRawText(StringRef(OS.str()));
803 // This is a pseudo op for a label + instruction sequence, which looks like:
806 // This adds the address of LPC0 to r0.
809 OutStreamer.EmitLabel(getPICLabel(MAI->getPrivateGlobalPrefix(),
810 getFunctionNumber(), MI->getOperand(2).getImm(),
813 // Form and emit the add.
815 AddInst.setOpcode(ARM::tADDhirr);
816 AddInst.addOperand(MCOperand::CreateReg(MI->getOperand(0).getReg()));
817 AddInst.addOperand(MCOperand::CreateReg(MI->getOperand(0).getReg()));
818 AddInst.addOperand(MCOperand::CreateReg(ARM::PC));
819 // Add predicate operands.
820 AddInst.addOperand(MCOperand::CreateImm(ARMCC::AL));
821 AddInst.addOperand(MCOperand::CreateReg(0));
822 OutStreamer.EmitInstruction(AddInst);
826 // This is a pseudo op for a label + instruction sequence, which looks like:
829 // This adds the address of LPC0 to r0.
832 OutStreamer.EmitLabel(getPICLabel(MAI->getPrivateGlobalPrefix(),
833 getFunctionNumber(), MI->getOperand(2).getImm(),
836 // Form and emit the add.
838 AddInst.setOpcode(ARM::ADDrr);
839 AddInst.addOperand(MCOperand::CreateReg(MI->getOperand(0).getReg()));
840 AddInst.addOperand(MCOperand::CreateReg(ARM::PC));
841 AddInst.addOperand(MCOperand::CreateReg(MI->getOperand(1).getReg()));
842 // Add predicate operands.
843 AddInst.addOperand(MCOperand::CreateImm(MI->getOperand(3).getImm()));
844 AddInst.addOperand(MCOperand::CreateReg(MI->getOperand(4).getReg()));
845 // Add 's' bit operand (always reg0 for this)
846 AddInst.addOperand(MCOperand::CreateReg(0));
847 OutStreamer.EmitInstruction(AddInst);
857 case ARM::PICLDRSH: {
858 // This is a pseudo op for a label + instruction sequence, which looks like:
861 // The LCP0 label is referenced by a constant pool entry in order to get
862 // a PC-relative address at the ldr instruction.
865 OutStreamer.EmitLabel(getPICLabel(MAI->getPrivateGlobalPrefix(),
866 getFunctionNumber(), MI->getOperand(2).getImm(),
869 // Form and emit the load
871 switch (MI->getOpcode()) {
873 llvm_unreachable("Unexpected opcode!");
874 case ARM::PICSTR: Opcode = ARM::STRrs; break;
875 case ARM::PICSTRB: Opcode = ARM::STRBrs; break;
876 case ARM::PICSTRH: Opcode = ARM::STRH; break;
877 case ARM::PICLDR: Opcode = ARM::LDRrs; break;
878 case ARM::PICLDRB: Opcode = ARM::LDRBrs; break;
879 case ARM::PICLDRH: Opcode = ARM::LDRH; break;
880 case ARM::PICLDRSB: Opcode = ARM::LDRSB; break;
881 case ARM::PICLDRSH: Opcode = ARM::LDRSH; break;
884 LdStInst.setOpcode(Opcode);
885 LdStInst.addOperand(MCOperand::CreateReg(MI->getOperand(0).getReg()));
886 LdStInst.addOperand(MCOperand::CreateReg(ARM::PC));
887 LdStInst.addOperand(MCOperand::CreateReg(MI->getOperand(1).getReg()));
888 LdStInst.addOperand(MCOperand::CreateImm(0));
889 // Add predicate operands.
890 LdStInst.addOperand(MCOperand::CreateImm(MI->getOperand(3).getImm()));
891 LdStInst.addOperand(MCOperand::CreateReg(MI->getOperand(4).getReg()));
892 OutStreamer.EmitInstruction(LdStInst);
896 case ARM::CONSTPOOL_ENTRY: {
897 /// CONSTPOOL_ENTRY - This instruction represents a floating constant pool
898 /// in the function. The first operand is the ID# for this instruction, the
899 /// second is the index into the MachineConstantPool that this is, the third
900 /// is the size in bytes of this constant pool entry.
901 unsigned LabelId = (unsigned)MI->getOperand(0).getImm();
902 unsigned CPIdx = (unsigned)MI->getOperand(1).getIndex();
905 OutStreamer.EmitLabel(GetCPISymbol(LabelId));
907 const MachineConstantPoolEntry &MCPE = MCP->getConstants()[CPIdx];
908 if (MCPE.isMachineConstantPoolEntry())
909 EmitMachineConstantPoolValue(MCPE.Val.MachineCPVal);
911 EmitGlobalConstant(MCPE.Val.ConstVal);
918 // Lower and emit the instruction itself, then the jump table following it.
920 MCInstLowering.Lower(MI, TmpInst);
921 OutStreamer.EmitInstruction(TmpInst);
928 case ARM::BR_JTadd: {
929 // Lower and emit the instruction itself, then the jump table following it.
931 MCInstLowering.Lower(MI, TmpInst);
932 OutStreamer.EmitInstruction(TmpInst);
937 // Non-Darwin binutils don't yet support the "trap" mnemonic.
938 // FIXME: Remove this special case when they do.
939 if (!Subtarget->isTargetDarwin()) {
940 //.long 0xe7ffdefe @ trap
941 uint32_t Val = 0xe7ffdefeUL;
942 OutStreamer.AddComment("trap");
943 OutStreamer.EmitIntValue(Val, 4);
949 // Non-Darwin binutils don't yet support the "trap" mnemonic.
950 // FIXME: Remove this special case when they do.
951 if (!Subtarget->isTargetDarwin()) {
952 //.short 57086 @ trap
953 uint16_t Val = 0xdefe;
954 OutStreamer.AddComment("trap");
955 OutStreamer.EmitIntValue(Val, 2);
960 case ARM::t2Int_eh_sjlj_setjmp:
961 case ARM::t2Int_eh_sjlj_setjmp_nofp:
962 case ARM::tInt_eh_sjlj_setjmp: {
963 // Two incoming args: GPR:$src, GPR:$val
966 // str $val, [$src, #4]
971 unsigned SrcReg = MI->getOperand(0).getReg();
972 unsigned ValReg = MI->getOperand(1).getReg();
973 MCSymbol *Label = GetARMSJLJEHLabel();
976 TmpInst.setOpcode(ARM::tMOVgpr2tgpr);
977 TmpInst.addOperand(MCOperand::CreateReg(ValReg));
978 TmpInst.addOperand(MCOperand::CreateReg(ARM::PC));
980 TmpInst.addOperand(MCOperand::CreateReg(ARM::CPSR));
981 OutStreamer.AddComment("eh_setjmp begin");
982 OutStreamer.EmitInstruction(TmpInst);
986 TmpInst.setOpcode(ARM::tADDi3);
987 TmpInst.addOperand(MCOperand::CreateReg(ValReg));
989 TmpInst.addOperand(MCOperand::CreateReg(ARM::CPSR));
990 TmpInst.addOperand(MCOperand::CreateReg(ValReg));
991 TmpInst.addOperand(MCOperand::CreateImm(7));
993 TmpInst.addOperand(MCOperand::CreateImm(ARMCC::AL));
994 TmpInst.addOperand(MCOperand::CreateReg(0));
995 OutStreamer.EmitInstruction(TmpInst);
999 TmpInst.setOpcode(ARM::tSTR);
1000 TmpInst.addOperand(MCOperand::CreateReg(ValReg));
1001 TmpInst.addOperand(MCOperand::CreateReg(SrcReg));
1002 // The offset immediate is #4. The operand value is scaled by 4 for the
1003 // tSTR instruction.
1004 TmpInst.addOperand(MCOperand::CreateImm(1));
1005 TmpInst.addOperand(MCOperand::CreateReg(0));
1007 TmpInst.addOperand(MCOperand::CreateImm(ARMCC::AL));
1008 TmpInst.addOperand(MCOperand::CreateReg(0));
1009 OutStreamer.EmitInstruction(TmpInst);
1013 TmpInst.setOpcode(ARM::tMOVi8);
1014 TmpInst.addOperand(MCOperand::CreateReg(ARM::R0));
1015 TmpInst.addOperand(MCOperand::CreateReg(ARM::CPSR));
1016 TmpInst.addOperand(MCOperand::CreateImm(0));
1018 TmpInst.addOperand(MCOperand::CreateImm(ARMCC::AL));
1019 TmpInst.addOperand(MCOperand::CreateReg(0));
1020 OutStreamer.EmitInstruction(TmpInst);
1023 const MCExpr *SymbolExpr = MCSymbolRefExpr::Create(Label, OutContext);
1025 TmpInst.setOpcode(ARM::tB);
1026 TmpInst.addOperand(MCOperand::CreateExpr(SymbolExpr));
1027 OutStreamer.EmitInstruction(TmpInst);
1031 TmpInst.setOpcode(ARM::tMOVi8);
1032 TmpInst.addOperand(MCOperand::CreateReg(ARM::R0));
1033 TmpInst.addOperand(MCOperand::CreateReg(ARM::CPSR));
1034 TmpInst.addOperand(MCOperand::CreateImm(1));
1036 TmpInst.addOperand(MCOperand::CreateImm(ARMCC::AL));
1037 TmpInst.addOperand(MCOperand::CreateReg(0));
1038 OutStreamer.AddComment("eh_setjmp end");
1039 OutStreamer.EmitInstruction(TmpInst);
1041 OutStreamer.EmitLabel(Label);
1045 case ARM::Int_eh_sjlj_setjmp_nofp:
1046 case ARM::Int_eh_sjlj_setjmp: {
1047 // Two incoming args: GPR:$src, GPR:$val
1049 // str $val, [$src, #+4]
1053 unsigned SrcReg = MI->getOperand(0).getReg();
1054 unsigned ValReg = MI->getOperand(1).getReg();
1058 TmpInst.setOpcode(ARM::ADDri);
1059 TmpInst.addOperand(MCOperand::CreateReg(ValReg));
1060 TmpInst.addOperand(MCOperand::CreateReg(ARM::PC));
1061 TmpInst.addOperand(MCOperand::CreateImm(8));
1063 TmpInst.addOperand(MCOperand::CreateImm(ARMCC::AL));
1064 TmpInst.addOperand(MCOperand::CreateReg(0));
1065 // 's' bit operand (always reg0 for this).
1066 TmpInst.addOperand(MCOperand::CreateReg(0));
1067 OutStreamer.AddComment("eh_setjmp begin");
1068 OutStreamer.EmitInstruction(TmpInst);
1072 TmpInst.setOpcode(ARM::STRi12);
1073 TmpInst.addOperand(MCOperand::CreateReg(ValReg));
1074 TmpInst.addOperand(MCOperand::CreateReg(SrcReg));
1075 TmpInst.addOperand(MCOperand::CreateImm(4));
1077 TmpInst.addOperand(MCOperand::CreateImm(ARMCC::AL));
1078 TmpInst.addOperand(MCOperand::CreateReg(0));
1079 OutStreamer.EmitInstruction(TmpInst);
1083 TmpInst.setOpcode(ARM::MOVi);
1084 TmpInst.addOperand(MCOperand::CreateReg(ARM::R0));
1085 TmpInst.addOperand(MCOperand::CreateImm(0));
1087 TmpInst.addOperand(MCOperand::CreateImm(ARMCC::AL));
1088 TmpInst.addOperand(MCOperand::CreateReg(0));
1089 // 's' bit operand (always reg0 for this).
1090 TmpInst.addOperand(MCOperand::CreateReg(0));
1091 OutStreamer.EmitInstruction(TmpInst);
1095 TmpInst.setOpcode(ARM::ADDri);
1096 TmpInst.addOperand(MCOperand::CreateReg(ARM::PC));
1097 TmpInst.addOperand(MCOperand::CreateReg(ARM::PC));
1098 TmpInst.addOperand(MCOperand::CreateImm(0));
1100 TmpInst.addOperand(MCOperand::CreateImm(ARMCC::AL));
1101 TmpInst.addOperand(MCOperand::CreateReg(0));
1102 // 's' bit operand (always reg0 for this).
1103 TmpInst.addOperand(MCOperand::CreateReg(0));
1104 OutStreamer.EmitInstruction(TmpInst);
1108 TmpInst.setOpcode(ARM::MOVi);
1109 TmpInst.addOperand(MCOperand::CreateReg(ARM::R0));
1110 TmpInst.addOperand(MCOperand::CreateImm(1));
1112 TmpInst.addOperand(MCOperand::CreateImm(ARMCC::AL));
1113 TmpInst.addOperand(MCOperand::CreateReg(0));
1114 // 's' bit operand (always reg0 for this).
1115 TmpInst.addOperand(MCOperand::CreateReg(0));
1116 OutStreamer.AddComment("eh_setjmp end");
1117 OutStreamer.EmitInstruction(TmpInst);
1121 case ARM::Int_eh_sjlj_longjmp: {
1122 // ldr sp, [$src, #8]
1123 // ldr $scratch, [$src, #4]
1126 unsigned SrcReg = MI->getOperand(0).getReg();
1127 unsigned ScratchReg = MI->getOperand(1).getReg();
1130 TmpInst.setOpcode(ARM::LDRi12);
1131 TmpInst.addOperand(MCOperand::CreateReg(ARM::SP));
1132 TmpInst.addOperand(MCOperand::CreateReg(SrcReg));
1133 TmpInst.addOperand(MCOperand::CreateImm(8));
1135 TmpInst.addOperand(MCOperand::CreateImm(ARMCC::AL));
1136 TmpInst.addOperand(MCOperand::CreateReg(0));
1137 OutStreamer.EmitInstruction(TmpInst);
1141 TmpInst.setOpcode(ARM::LDRi12);
1142 TmpInst.addOperand(MCOperand::CreateReg(ScratchReg));
1143 TmpInst.addOperand(MCOperand::CreateReg(SrcReg));
1144 TmpInst.addOperand(MCOperand::CreateImm(4));
1146 TmpInst.addOperand(MCOperand::CreateImm(ARMCC::AL));
1147 TmpInst.addOperand(MCOperand::CreateReg(0));
1148 OutStreamer.EmitInstruction(TmpInst);
1152 TmpInst.setOpcode(ARM::LDRi12);
1153 TmpInst.addOperand(MCOperand::CreateReg(ARM::R7));
1154 TmpInst.addOperand(MCOperand::CreateReg(SrcReg));
1155 TmpInst.addOperand(MCOperand::CreateImm(0));
1157 TmpInst.addOperand(MCOperand::CreateImm(ARMCC::AL));
1158 TmpInst.addOperand(MCOperand::CreateReg(0));
1159 OutStreamer.EmitInstruction(TmpInst);
1163 TmpInst.setOpcode(ARM::BRIND);
1164 TmpInst.addOperand(MCOperand::CreateReg(ScratchReg));
1166 TmpInst.addOperand(MCOperand::CreateImm(ARMCC::AL));
1167 TmpInst.addOperand(MCOperand::CreateReg(0));
1168 OutStreamer.EmitInstruction(TmpInst);
1172 case ARM::tInt_eh_sjlj_longjmp: {
1173 // ldr $scratch, [$src, #8]
1175 // ldr $scratch, [$src, #4]
1178 unsigned SrcReg = MI->getOperand(0).getReg();
1179 unsigned ScratchReg = MI->getOperand(1).getReg();
1182 TmpInst.setOpcode(ARM::tLDR);
1183 TmpInst.addOperand(MCOperand::CreateReg(ScratchReg));
1184 TmpInst.addOperand(MCOperand::CreateReg(SrcReg));
1185 // The offset immediate is #8. The operand value is scaled by 4 for the
1186 // tSTR instruction.
1187 TmpInst.addOperand(MCOperand::CreateImm(2));
1188 TmpInst.addOperand(MCOperand::CreateReg(0));
1190 TmpInst.addOperand(MCOperand::CreateImm(ARMCC::AL));
1191 TmpInst.addOperand(MCOperand::CreateReg(0));
1192 OutStreamer.EmitInstruction(TmpInst);
1196 TmpInst.setOpcode(ARM::tMOVtgpr2gpr);
1197 TmpInst.addOperand(MCOperand::CreateReg(ARM::SP));
1198 TmpInst.addOperand(MCOperand::CreateReg(ScratchReg));
1200 TmpInst.addOperand(MCOperand::CreateImm(ARMCC::AL));
1201 TmpInst.addOperand(MCOperand::CreateReg(0));
1202 OutStreamer.EmitInstruction(TmpInst);
1206 TmpInst.setOpcode(ARM::tLDR);
1207 TmpInst.addOperand(MCOperand::CreateReg(ScratchReg));
1208 TmpInst.addOperand(MCOperand::CreateReg(SrcReg));
1209 TmpInst.addOperand(MCOperand::CreateImm(1));
1210 TmpInst.addOperand(MCOperand::CreateReg(0));
1212 TmpInst.addOperand(MCOperand::CreateImm(ARMCC::AL));
1213 TmpInst.addOperand(MCOperand::CreateReg(0));
1214 OutStreamer.EmitInstruction(TmpInst);
1218 TmpInst.setOpcode(ARM::tLDR);
1219 TmpInst.addOperand(MCOperand::CreateReg(ARM::R7));
1220 TmpInst.addOperand(MCOperand::CreateReg(SrcReg));
1221 TmpInst.addOperand(MCOperand::CreateImm(0));
1222 TmpInst.addOperand(MCOperand::CreateReg(0));
1224 TmpInst.addOperand(MCOperand::CreateImm(ARMCC::AL));
1225 TmpInst.addOperand(MCOperand::CreateReg(0));
1226 OutStreamer.EmitInstruction(TmpInst);
1230 TmpInst.setOpcode(ARM::tBX_RET_vararg);
1231 TmpInst.addOperand(MCOperand::CreateReg(ScratchReg));
1233 TmpInst.addOperand(MCOperand::CreateImm(ARMCC::AL));
1234 TmpInst.addOperand(MCOperand::CreateReg(0));
1235 OutStreamer.EmitInstruction(TmpInst);
1242 MCInstLowering.Lower(MI, TmpInst);
1243 OutStreamer.EmitInstruction(TmpInst);
1246 //===----------------------------------------------------------------------===//
1247 // Target Registry Stuff
1248 //===----------------------------------------------------------------------===//
1250 static MCInstPrinter *createARMMCInstPrinter(const Target &T,
1251 unsigned SyntaxVariant,
1252 const MCAsmInfo &MAI) {
1253 if (SyntaxVariant == 0)
1254 return new ARMInstPrinter(MAI);
1258 // Force static initialization.
1259 extern "C" void LLVMInitializeARMAsmPrinter() {
1260 RegisterAsmPrinter<ARMAsmPrinter> X(TheARMTarget);
1261 RegisterAsmPrinter<ARMAsmPrinter> Y(TheThumbTarget);
1263 TargetRegistry::RegisterMCInstPrinter(TheARMTarget, createARMMCInstPrinter);
1264 TargetRegistry::RegisterMCInstPrinter(TheThumbTarget, createARMMCInstPrinter);