xref: /freebsd/contrib/llvm-project/llvm/lib/Target/Sparc/SparcAsmPrinter.cpp (revision 700637cbb5e582861067a11aaca4d053546871d2)
1 //===-- SparcAsmPrinter.cpp - Sparc LLVM assembly writer ------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file contains a printer that converts from our internal representation
10 // of machine-dependent LLVM code to GAS-format SPARC assembly language.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #include "MCTargetDesc/SparcInstPrinter.h"
15 #include "MCTargetDesc/SparcMCAsmInfo.h"
16 #include "MCTargetDesc/SparcMCTargetDesc.h"
17 #include "MCTargetDesc/SparcTargetStreamer.h"
18 #include "Sparc.h"
19 #include "SparcInstrInfo.h"
20 #include "SparcTargetMachine.h"
21 #include "TargetInfo/SparcTargetInfo.h"
22 #include "llvm/BinaryFormat/ELF.h"
23 #include "llvm/CodeGen/AsmPrinter.h"
24 #include "llvm/CodeGen/MachineInstr.h"
25 #include "llvm/CodeGen/MachineModuleInfoImpls.h"
26 #include "llvm/CodeGen/MachineRegisterInfo.h"
27 #include "llvm/CodeGen/TargetLoweringObjectFileImpl.h"
28 #include "llvm/IR/Mangler.h"
29 #include "llvm/MC/MCAsmInfo.h"
30 #include "llvm/MC/MCContext.h"
31 #include "llvm/MC/MCInst.h"
32 #include "llvm/MC/MCStreamer.h"
33 #include "llvm/MC/MCSymbol.h"
34 #include "llvm/MC/TargetRegistry.h"
35 #include "llvm/Support/Compiler.h"
36 #include "llvm/Support/raw_ostream.h"
37 using namespace llvm;
38 
39 #define DEBUG_TYPE "asm-printer"
40 
41 namespace {
42 class SparcAsmPrinter : public AsmPrinter {
getTargetStreamer()43   SparcTargetStreamer &getTargetStreamer() {
44     return static_cast<SparcTargetStreamer &>(
45         *OutStreamer->getTargetStreamer());
46   }
47 
48 public:
SparcAsmPrinter(TargetMachine & TM,std::unique_ptr<MCStreamer> Streamer)49   explicit SparcAsmPrinter(TargetMachine &TM,
50                            std::unique_ptr<MCStreamer> Streamer)
51       : AsmPrinter(TM, std::move(Streamer), ID) {}
52 
getPassName() const53   StringRef getPassName() const override { return "Sparc Assembly Printer"; }
54 
55   void printOperand(const MachineInstr *MI, int opNum, raw_ostream &OS);
56   void printMemOperand(const MachineInstr *MI, int opNum, raw_ostream &OS);
57 
58   void emitFunctionBodyStart() override;
59   void emitInstruction(const MachineInstr *MI) override;
60 
getRegisterName(MCRegister Reg)61   static const char *getRegisterName(MCRegister Reg) {
62     return SparcInstPrinter::getRegisterName(Reg);
63   }
64 
65   bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
66                        const char *ExtraCode, raw_ostream &O) override;
67   bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo,
68                              const char *ExtraCode, raw_ostream &O) override;
69 
70   void LowerGETPCXAndEmitMCInsts(const MachineInstr *MI,
71                                  const MCSubtargetInfo &STI);
72 
73   MCOperand lowerOperand(const MachineOperand &MO) const;
74 
75 private:
76   void lowerToMCInst(const MachineInstr *MI, MCInst &OutMI);
77 
78 public:
79   static char ID;
80 };
81 } // end of anonymous namespace
82 
createSparcMCOperand(uint16_t Kind,MCSymbol * Sym,MCContext & OutContext)83 static MCOperand createSparcMCOperand(uint16_t Kind, MCSymbol *Sym,
84                                       MCContext &OutContext) {
85   const MCSymbolRefExpr *MCSym = MCSymbolRefExpr::create(Sym, OutContext);
86   auto *expr = MCSpecifierExpr::create(MCSym, Kind, OutContext);
87   return MCOperand::createExpr(expr);
88 }
createPCXCallOP(MCSymbol * Label,MCContext & OutContext)89 static MCOperand createPCXCallOP(MCSymbol *Label,
90                                  MCContext &OutContext) {
91   return MCOperand::createExpr(MCSymbolRefExpr::create(Label, OutContext));
92 }
93 
createPCXRelExprOp(uint16_t Spec,MCSymbol * GOTLabel,MCSymbol * StartLabel,MCSymbol * CurLabel,MCContext & OutContext)94 static MCOperand createPCXRelExprOp(uint16_t Spec, MCSymbol *GOTLabel,
95                                     MCSymbol *StartLabel, MCSymbol *CurLabel,
96                                     MCContext &OutContext) {
97   const MCSymbolRefExpr *GOT = MCSymbolRefExpr::create(GOTLabel, OutContext);
98   const MCSymbolRefExpr *Start = MCSymbolRefExpr::create(StartLabel,
99                                                          OutContext);
100   const MCSymbolRefExpr *Cur = MCSymbolRefExpr::create(CurLabel,
101                                                        OutContext);
102 
103   const MCBinaryExpr *Sub = MCBinaryExpr::createSub(Cur, Start, OutContext);
104   const MCBinaryExpr *Add = MCBinaryExpr::createAdd(GOT, Sub, OutContext);
105   auto *expr = MCSpecifierExpr::create(Add, Spec, OutContext);
106   return MCOperand::createExpr(expr);
107 }
108 
EmitCall(MCStreamer & OutStreamer,MCOperand & Callee,const MCSubtargetInfo & STI)109 static void EmitCall(MCStreamer &OutStreamer,
110                      MCOperand &Callee,
111                      const MCSubtargetInfo &STI)
112 {
113   MCInst CallInst;
114   CallInst.setOpcode(SP::CALL);
115   CallInst.addOperand(Callee);
116   OutStreamer.emitInstruction(CallInst, STI);
117 }
118 
EmitRDPC(MCStreamer & OutStreamer,MCOperand & RD,const MCSubtargetInfo & STI)119 static void EmitRDPC(MCStreamer &OutStreamer, MCOperand &RD,
120                      const MCSubtargetInfo &STI) {
121   MCInst RDPCInst;
122   RDPCInst.setOpcode(SP::RDASR);
123   RDPCInst.addOperand(RD);
124   RDPCInst.addOperand(MCOperand::createReg(SP::ASR5));
125   OutStreamer.emitInstruction(RDPCInst, STI);
126 }
127 
EmitSETHI(MCStreamer & OutStreamer,MCOperand & Imm,MCOperand & RD,const MCSubtargetInfo & STI)128 static void EmitSETHI(MCStreamer &OutStreamer,
129                       MCOperand &Imm, MCOperand &RD,
130                       const MCSubtargetInfo &STI)
131 {
132   MCInst SETHIInst;
133   SETHIInst.setOpcode(SP::SETHIi);
134   SETHIInst.addOperand(RD);
135   SETHIInst.addOperand(Imm);
136   OutStreamer.emitInstruction(SETHIInst, STI);
137 }
138 
EmitBinary(MCStreamer & OutStreamer,unsigned Opcode,MCOperand & RS1,MCOperand & Src2,MCOperand & RD,const MCSubtargetInfo & STI)139 static void EmitBinary(MCStreamer &OutStreamer, unsigned Opcode,
140                        MCOperand &RS1, MCOperand &Src2, MCOperand &RD,
141                        const MCSubtargetInfo &STI)
142 {
143   MCInst Inst;
144   Inst.setOpcode(Opcode);
145   Inst.addOperand(RD);
146   Inst.addOperand(RS1);
147   Inst.addOperand(Src2);
148   OutStreamer.emitInstruction(Inst, STI);
149 }
150 
EmitOR(MCStreamer & OutStreamer,MCOperand & RS1,MCOperand & Imm,MCOperand & RD,const MCSubtargetInfo & STI)151 static void EmitOR(MCStreamer &OutStreamer,
152                    MCOperand &RS1, MCOperand &Imm, MCOperand &RD,
153                    const MCSubtargetInfo &STI) {
154   EmitBinary(OutStreamer, SP::ORri, RS1, Imm, RD, STI);
155 }
156 
EmitADD(MCStreamer & OutStreamer,MCOperand & RS1,MCOperand & RS2,MCOperand & RD,const MCSubtargetInfo & STI)157 static void EmitADD(MCStreamer &OutStreamer,
158                     MCOperand &RS1, MCOperand &RS2, MCOperand &RD,
159                     const MCSubtargetInfo &STI) {
160   EmitBinary(OutStreamer, SP::ADDrr, RS1, RS2, RD, STI);
161 }
162 
EmitSHL(MCStreamer & OutStreamer,MCOperand & RS1,MCOperand & Imm,MCOperand & RD,const MCSubtargetInfo & STI)163 static void EmitSHL(MCStreamer &OutStreamer,
164                     MCOperand &RS1, MCOperand &Imm, MCOperand &RD,
165                     const MCSubtargetInfo &STI) {
166   EmitBinary(OutStreamer, SP::SLLri, RS1, Imm, RD, STI);
167 }
168 
emitHiLo(MCStreamer & OutStreamer,MCSymbol * GOTSym,uint16_t HiKind,uint16_t LoKind,MCOperand & RD,MCContext & OutContext,const MCSubtargetInfo & STI)169 static void emitHiLo(MCStreamer &OutStreamer, MCSymbol *GOTSym, uint16_t HiKind,
170                      uint16_t LoKind, MCOperand &RD, MCContext &OutContext,
171                      const MCSubtargetInfo &STI) {
172   MCOperand hi = createSparcMCOperand(HiKind, GOTSym, OutContext);
173   MCOperand lo = createSparcMCOperand(LoKind, GOTSym, OutContext);
174   EmitSETHI(OutStreamer, hi, RD, STI);
175   EmitOR(OutStreamer, RD, lo, RD, STI);
176 }
177 
LowerGETPCXAndEmitMCInsts(const MachineInstr * MI,const MCSubtargetInfo & STI)178 void SparcAsmPrinter::LowerGETPCXAndEmitMCInsts(const MachineInstr *MI,
179                                                 const MCSubtargetInfo &STI)
180 {
181   MCSymbol *GOTLabel   =
182     OutContext.getOrCreateSymbol(Twine("_GLOBAL_OFFSET_TABLE_"));
183 
184   const MachineOperand &MO = MI->getOperand(0);
185   assert(MO.getReg() != SP::O7 &&
186          "%o7 is assigned as destination for getpcx!");
187 
188   MCOperand MCRegOP = MCOperand::createReg(MO.getReg());
189 
190 
191   if (!isPositionIndependent()) {
192     // Just load the address of GOT to MCRegOP.
193     switch(TM.getCodeModel()) {
194     default:
195       llvm_unreachable("Unsupported absolute code model");
196     case CodeModel::Small:
197       emitHiLo(*OutStreamer, GOTLabel, ELF::R_SPARC_HI22, ELF::R_SPARC_LO10,
198                MCRegOP, OutContext, STI);
199       break;
200     case CodeModel::Medium: {
201       emitHiLo(*OutStreamer, GOTLabel, ELF::R_SPARC_H44, ELF::R_SPARC_M44,
202                MCRegOP, OutContext, STI);
203       MCOperand imm = MCOperand::createExpr(MCConstantExpr::create(12,
204                                                                    OutContext));
205       EmitSHL(*OutStreamer, MCRegOP, imm, MCRegOP, STI);
206       MCOperand lo =
207           createSparcMCOperand(ELF::R_SPARC_L44, GOTLabel, OutContext);
208       EmitOR(*OutStreamer, MCRegOP, lo, MCRegOP, STI);
209       break;
210     }
211     case CodeModel::Large: {
212       emitHiLo(*OutStreamer, GOTLabel, ELF::R_SPARC_HH22, ELF::R_SPARC_HM10,
213                MCRegOP, OutContext, STI);
214       MCOperand imm = MCOperand::createExpr(MCConstantExpr::create(32,
215                                                                    OutContext));
216       EmitSHL(*OutStreamer, MCRegOP, imm, MCRegOP, STI);
217       // Use register %o7 to load the lower 32 bits.
218       MCOperand RegO7 = MCOperand::createReg(SP::O7);
219       emitHiLo(*OutStreamer, GOTLabel, ELF::R_SPARC_HI22, ELF::R_SPARC_LO10,
220                RegO7, OutContext, STI);
221       EmitADD(*OutStreamer, MCRegOP, RegO7, MCRegOP, STI);
222     }
223     }
224     return;
225   }
226 
227   MCSymbol *StartLabel = OutContext.createTempSymbol();
228   MCSymbol *EndLabel   = OutContext.createTempSymbol();
229   MCSymbol *SethiLabel = OutContext.createTempSymbol();
230 
231   MCOperand RegO7   = MCOperand::createReg(SP::O7);
232 
233   // <StartLabel>:
234   //   <GET-PC> // This will be either `call <EndLabel>` or `rd %pc, %o7`.
235   // <SethiLabel>:
236   //     sethi %hi(_GLOBAL_OFFSET_TABLE_+(<SethiLabel>-<StartLabel>)), <MO>
237   // <EndLabel>:
238   //   or  <MO>, %lo(_GLOBAL_OFFSET_TABLE_+(<EndLabel>-<StartLabel>))), <MO>
239   //   add <MO>, %o7, <MO>
240 
241   OutStreamer->emitLabel(StartLabel);
242   if (!STI.getTargetTriple().isSPARC64() ||
243       STI.hasFeature(Sparc::TuneSlowRDPC)) {
244     MCOperand Callee = createPCXCallOP(EndLabel, OutContext);
245     EmitCall(*OutStreamer, Callee, STI);
246   } else {
247     // TODO find out whether it is possible to store PC
248     // in other registers, to enable leaf function optimization.
249     // (On the other hand, approx. over 97.8% of GETPCXes happen
250     // in non-leaf functions, so would this be worth the effort?)
251     EmitRDPC(*OutStreamer, RegO7, STI);
252   }
253   OutStreamer->emitLabel(SethiLabel);
254   MCOperand hiImm = createPCXRelExprOp(ELF::R_SPARC_PC22, GOTLabel, StartLabel,
255                                        SethiLabel, OutContext);
256   EmitSETHI(*OutStreamer, hiImm, MCRegOP, STI);
257   OutStreamer->emitLabel(EndLabel);
258   MCOperand loImm = createPCXRelExprOp(ELF::R_SPARC_PC10, GOTLabel, StartLabel,
259                                        EndLabel, OutContext);
260   EmitOR(*OutStreamer, MCRegOP, loImm, MCRegOP, STI);
261   EmitADD(*OutStreamer, MCRegOP, RegO7, MCRegOP, STI);
262 }
263 
lowerOperand(const MachineOperand & MO) const264 MCOperand SparcAsmPrinter::lowerOperand(const MachineOperand &MO) const {
265   switch (MO.getType()) {
266   default:
267     llvm_unreachable("unknown operand type");
268     break;
269   case MachineOperand::MO_Register:
270     if (MO.isImplicit())
271       break;
272     return MCOperand::createReg(MO.getReg());
273 
274   case MachineOperand::MO_Immediate:
275     return MCOperand::createImm(MO.getImm());
276 
277   case MachineOperand::MO_MachineBasicBlock:
278   case MachineOperand::MO_GlobalAddress:
279   case MachineOperand::MO_BlockAddress:
280   case MachineOperand::MO_ExternalSymbol:
281   case MachineOperand::MO_ConstantPoolIndex: {
282     auto RelType = MO.getTargetFlags();
283     const MCSymbol *Symbol = nullptr;
284     switch (MO.getType()) {
285     default:
286       llvm_unreachable("");
287     case MachineOperand::MO_MachineBasicBlock:
288       Symbol = MO.getMBB()->getSymbol();
289       break;
290     case MachineOperand::MO_GlobalAddress:
291       Symbol = getSymbol(MO.getGlobal());
292       break;
293     case MachineOperand::MO_BlockAddress:
294       Symbol = GetBlockAddressSymbol(MO.getBlockAddress());
295       break;
296     case MachineOperand::MO_ExternalSymbol:
297       Symbol = GetExternalSymbolSymbol(MO.getSymbolName());
298       break;
299     case MachineOperand::MO_ConstantPoolIndex:
300       Symbol = GetCPISymbol(MO.getIndex());
301       break;
302     }
303 
304     const MCExpr *expr = MCSymbolRefExpr::create(Symbol, OutContext);
305     if (RelType)
306       expr = MCSpecifierExpr::create(expr, RelType, OutContext);
307     return MCOperand::createExpr(expr);
308   }
309 
310   case MachineOperand::MO_RegisterMask:
311     break;
312   }
313   return MCOperand();
314 }
315 
lowerToMCInst(const MachineInstr * MI,MCInst & OutMI)316 void SparcAsmPrinter::lowerToMCInst(const MachineInstr *MI, MCInst &OutMI) {
317   OutMI.setOpcode(MI->getOpcode());
318 
319   for (const MachineOperand &MO : MI->operands()) {
320     MCOperand MCOp = lowerOperand(MO);
321     if (MCOp.isValid())
322       OutMI.addOperand(MCOp);
323   }
324 }
325 
emitInstruction(const MachineInstr * MI)326 void SparcAsmPrinter::emitInstruction(const MachineInstr *MI) {
327   Sparc_MC::verifyInstructionPredicates(MI->getOpcode(),
328                                         getSubtargetInfo().getFeatureBits());
329 
330   switch (MI->getOpcode()) {
331   default: break;
332   case TargetOpcode::DBG_VALUE:
333     // FIXME: Debug Value.
334     return;
335   case SP::CASArr:
336   case SP::SWAPrr:
337   case SP::SWAPri:
338     if (MF->getSubtarget<SparcSubtarget>().fixTN0011())
339       OutStreamer->emitCodeAlignment(Align(16), &getSubtargetInfo());
340     break;
341   case SP::GETPCX:
342     LowerGETPCXAndEmitMCInsts(MI, getSubtargetInfo());
343     return;
344   }
345   MachineBasicBlock::const_instr_iterator I = MI->getIterator();
346   MachineBasicBlock::const_instr_iterator E = MI->getParent()->instr_end();
347   do {
348     MCInst TmpInst;
349     lowerToMCInst(&*I, TmpInst);
350     EmitToStreamer(*OutStreamer, TmpInst);
351   } while ((++I != E) && I->isInsideBundle()); // Delay slot check.
352 }
353 
emitFunctionBodyStart()354 void SparcAsmPrinter::emitFunctionBodyStart() {
355   if (!MF->getSubtarget<SparcSubtarget>().is64Bit())
356     return;
357 
358   const MachineRegisterInfo &MRI = MF->getRegInfo();
359   const unsigned globalRegs[] = { SP::G2, SP::G3, SP::G6, SP::G7, 0 };
360   for (unsigned i = 0; globalRegs[i] != 0; ++i) {
361     unsigned reg = globalRegs[i];
362     if (MRI.use_empty(reg))
363       continue;
364 
365     if  (reg == SP::G6 || reg == SP::G7)
366       getTargetStreamer().emitSparcRegisterIgnore(reg);
367     else
368       getTargetStreamer().emitSparcRegisterScratch(reg);
369   }
370 }
371 
printOperand(const MachineInstr * MI,int opNum,raw_ostream & O)372 void SparcAsmPrinter::printOperand(const MachineInstr *MI, int opNum,
373                                    raw_ostream &O) {
374   const DataLayout &DL = getDataLayout();
375   const MachineOperand &MO = MI->getOperand(opNum);
376   switch (MO.getType()) {
377   case MachineOperand::MO_Register:
378     O << "%" << StringRef(getRegisterName(MO.getReg())).lower();
379     break;
380 
381   case MachineOperand::MO_Immediate:
382     O << MO.getImm();
383     break;
384   case MachineOperand::MO_MachineBasicBlock:
385     MO.getMBB()->getSymbol()->print(O, MAI);
386     return;
387   case MachineOperand::MO_GlobalAddress:
388     PrintSymbolOperand(MO, O);
389     break;
390   case MachineOperand::MO_BlockAddress:
391     O <<  GetBlockAddressSymbol(MO.getBlockAddress())->getName();
392     break;
393   case MachineOperand::MO_ExternalSymbol:
394     O << MO.getSymbolName();
395     break;
396   case MachineOperand::MO_ConstantPoolIndex:
397     O << DL.getPrivateGlobalPrefix() << "CPI" << getFunctionNumber() << "_"
398       << MO.getIndex();
399     break;
400   case MachineOperand::MO_Metadata:
401     MO.getMetadata()->printAsOperand(O, MMI->getModule());
402     break;
403   default:
404     llvm_unreachable("<unknown operand type>");
405   }
406 }
407 
printMemOperand(const MachineInstr * MI,int opNum,raw_ostream & O)408 void SparcAsmPrinter::printMemOperand(const MachineInstr *MI, int opNum,
409                                       raw_ostream &O) {
410   printOperand(MI, opNum, O);
411 
412   if (MI->getOperand(opNum+1).isReg() &&
413       MI->getOperand(opNum+1).getReg() == SP::G0)
414     return;   // don't print "+%g0"
415   if (MI->getOperand(opNum+1).isImm() &&
416       MI->getOperand(opNum+1).getImm() == 0)
417     return;   // don't print "+0"
418 
419   O << "+";
420   printOperand(MI, opNum+1, O);
421 }
422 
423 /// PrintAsmOperand - Print out an operand for an inline asm expression.
424 ///
PrintAsmOperand(const MachineInstr * MI,unsigned OpNo,const char * ExtraCode,raw_ostream & O)425 bool SparcAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
426                                       const char *ExtraCode,
427                                       raw_ostream &O) {
428   if (ExtraCode && ExtraCode[0]) {
429     if (ExtraCode[1] != 0) return true; // Unknown modifier.
430 
431     switch (ExtraCode[0]) {
432     default:
433       // See if this is a generic print operand
434       return AsmPrinter::PrintAsmOperand(MI, OpNo, ExtraCode, O);
435     case 'L': // Low order register of a twin word register operand
436     case 'H': // High order register of a twin word register operand
437     {
438       const SparcSubtarget &Subtarget = MF->getSubtarget<SparcSubtarget>();
439       const MachineOperand &MO = MI->getOperand(OpNo);
440       const SparcRegisterInfo *RegisterInfo = Subtarget.getRegisterInfo();
441       Register MOReg = MO.getReg();
442 
443       Register HiReg, LoReg;
444       if (!SP::IntPairRegClass.contains(MOReg)) {
445         // If we aren't given a register pair already, find out which pair it
446         // belongs to. Note that here, the specified register operand, which
447         // refers to the high part of the twinword, needs to be an even-numbered
448         // register.
449         MOReg = RegisterInfo->getMatchingSuperReg(MOReg, SP::sub_even,
450                                                   &SP::IntPairRegClass);
451         if (!MOReg) {
452           SMLoc Loc;
453           OutContext.reportError(
454               Loc, "Hi part of pair should point to an even-numbered register");
455           OutContext.reportError(
456               Loc, "(note that in some cases it might be necessary to manually "
457                    "bind the input/output registers instead of relying on "
458                    "automatic allocation)");
459           return true;
460         }
461       }
462 
463       HiReg = RegisterInfo->getSubReg(MOReg, SP::sub_even);
464       LoReg = RegisterInfo->getSubReg(MOReg, SP::sub_odd);
465 
466       Register Reg;
467       switch (ExtraCode[0]) {
468       case 'L':
469         Reg = LoReg;
470         break;
471       case 'H':
472         Reg = HiReg;
473         break;
474       }
475 
476       O << '%' << SparcInstPrinter::getRegisterName(Reg);
477       return false;
478     }
479     case 'f':
480     case 'r':
481      break;
482     }
483   }
484 
485   printOperand(MI, OpNo, O);
486 
487   return false;
488 }
489 
PrintAsmMemoryOperand(const MachineInstr * MI,unsigned OpNo,const char * ExtraCode,raw_ostream & O)490 bool SparcAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,
491                                             unsigned OpNo,
492                                             const char *ExtraCode,
493                                             raw_ostream &O) {
494   if (ExtraCode && ExtraCode[0])
495     return true;  // Unknown modifier
496 
497   O << '[';
498   printMemOperand(MI, OpNo, O);
499   O << ']';
500 
501   return false;
502 }
503 
504 char SparcAsmPrinter::ID = 0;
505 
506 INITIALIZE_PASS(SparcAsmPrinter, "sparc-asm-printer", "Sparc Assembly Printer",
507                 false, false)
508 
509 // Force static initialization.
510 extern "C" LLVM_ABI LLVM_EXTERNAL_VISIBILITY void
LLVMInitializeSparcAsmPrinter()511 LLVMInitializeSparcAsmPrinter() {
512   RegisterAsmPrinter<SparcAsmPrinter> X(getTheSparcTarget());
513   RegisterAsmPrinter<SparcAsmPrinter> Y(getTheSparcV9Target());
514   RegisterAsmPrinter<SparcAsmPrinter> Z(getTheSparcelTarget());
515 }
516