1218885Sdim//===-- SparcAsmPrinter.cpp - Sparc LLVM assembly writer ------------------===//
2218885Sdim//
3218885Sdim//                     The LLVM Compiler Infrastructure
4218885Sdim//
5218885Sdim// This file is distributed under the University of Illinois Open Source
6218885Sdim// License. See LICENSE.TXT for details.
7218885Sdim//
8218885Sdim//===----------------------------------------------------------------------===//
9218885Sdim//
10218885Sdim// This file contains a printer that converts from our internal representation
11218885Sdim// of machine-dependent LLVM code to GAS-format SPARC assembly language.
12218885Sdim//
13218885Sdim//===----------------------------------------------------------------------===//
14218885Sdim
15218885Sdim#define DEBUG_TYPE "asm-printer"
16218885Sdim#include "Sparc.h"
17218885Sdim#include "SparcInstrInfo.h"
18218885Sdim#include "SparcTargetMachine.h"
19263764Sdim#include "SparcTargetStreamer.h"
20263764Sdim#include "InstPrinter/SparcInstPrinter.h"
21263764Sdim#include "MCTargetDesc/SparcMCExpr.h"
22252723Sdim#include "llvm/ADT/SmallString.h"
23218885Sdim#include "llvm/CodeGen/AsmPrinter.h"
24218885Sdim#include "llvm/CodeGen/MachineInstr.h"
25263764Sdim#include "llvm/CodeGen/MachineModuleInfoImpls.h"
26263509Sdim#include "llvm/CodeGen/MachineRegisterInfo.h"
27263764Sdim#include "llvm/CodeGen/TargetLoweringObjectFileImpl.h"
28218885Sdim#include "llvm/MC/MCAsmInfo.h"
29263764Sdim#include "llvm/MC/MCContext.h"
30263764Sdim#include "llvm/MC/MCInst.h"
31218885Sdim#include "llvm/MC/MCStreamer.h"
32218885Sdim#include "llvm/MC/MCSymbol.h"
33226890Sdim#include "llvm/Support/TargetRegistry.h"
34218885Sdim#include "llvm/Support/raw_ostream.h"
35252723Sdim#include "llvm/Target/Mangler.h"
36218885Sdimusing namespace llvm;
37218885Sdim
38218885Sdimnamespace {
39218885Sdim  class SparcAsmPrinter : public AsmPrinter {
40263764Sdim    SparcTargetStreamer &getTargetStreamer() {
41263764Sdim      return static_cast<SparcTargetStreamer&>(OutStreamer.getTargetStreamer());
42263764Sdim    }
43218885Sdim  public:
44218885Sdim    explicit SparcAsmPrinter(TargetMachine &TM, MCStreamer &Streamer)
45218885Sdim      : AsmPrinter(TM, Streamer) {}
46218885Sdim
47218885Sdim    virtual const char *getPassName() const {
48218885Sdim      return "Sparc Assembly Printer";
49218885Sdim    }
50218885Sdim
51218885Sdim    void printOperand(const MachineInstr *MI, int opNum, raw_ostream &OS);
52218885Sdim    void printMemOperand(const MachineInstr *MI, int opNum, raw_ostream &OS,
53218885Sdim                         const char *Modifier = 0);
54218885Sdim    void printCCOperand(const MachineInstr *MI, int opNum, raw_ostream &OS);
55218885Sdim
56263509Sdim    virtual void EmitFunctionBodyStart();
57263764Sdim    virtual void EmitInstruction(const MachineInstr *MI);
58263764Sdim    virtual void EmitEndOfAsmFile(Module &M);
59263764Sdim
60263764Sdim    static const char *getRegisterName(unsigned RegNo) {
61263764Sdim      return SparcInstPrinter::getRegisterName(RegNo);
62218885Sdim    }
63218885Sdim
64218885Sdim    bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
65218885Sdim                         unsigned AsmVariant, const char *ExtraCode,
66218885Sdim                         raw_ostream &O);
67218885Sdim    bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo,
68218885Sdim                               unsigned AsmVariant, const char *ExtraCode,
69218885Sdim                               raw_ostream &O);
70218885Sdim
71263764Sdim    void LowerGETPCXAndEmitMCInsts(const MachineInstr *MI);
72263509Sdim
73218885Sdim  };
74218885Sdim} // end of anonymous namespace
75218885Sdim
76263764Sdimstatic MCOperand createSparcMCOperand(SparcMCExpr::VariantKind Kind,
77263764Sdim                                      MCSymbol *Sym, MCContext &OutContext) {
78263764Sdim  const MCSymbolRefExpr *MCSym = MCSymbolRefExpr::Create(Sym,
79263764Sdim                                                         OutContext);
80263764Sdim  const SparcMCExpr *expr = SparcMCExpr::Create(Kind, MCSym, OutContext);
81263764Sdim  return MCOperand::CreateExpr(expr);
82218885Sdim
83263764Sdim}
84263764Sdimstatic MCOperand createPCXCallOP(MCSymbol *Label,
85263764Sdim                                 MCContext &OutContext) {
86263764Sdim  return createSparcMCOperand(SparcMCExpr::VK_Sparc_None, Label, OutContext);
87263764Sdim}
88263764Sdim
89263764Sdimstatic MCOperand createPCXRelExprOp(SparcMCExpr::VariantKind Kind,
90263764Sdim                                    MCSymbol *GOTLabel, MCSymbol *StartLabel,
91263764Sdim                                    MCSymbol *CurLabel,
92263764Sdim                                    MCContext &OutContext)
93263764Sdim{
94263764Sdim  const MCSymbolRefExpr *GOT = MCSymbolRefExpr::Create(GOTLabel, OutContext);
95263764Sdim  const MCSymbolRefExpr *Start = MCSymbolRefExpr::Create(StartLabel,
96263764Sdim                                                         OutContext);
97263764Sdim  const MCSymbolRefExpr *Cur = MCSymbolRefExpr::Create(CurLabel,
98263764Sdim                                                       OutContext);
99263764Sdim
100263764Sdim  const MCBinaryExpr *Sub = MCBinaryExpr::CreateSub(Cur, Start, OutContext);
101263764Sdim  const MCBinaryExpr *Add = MCBinaryExpr::CreateAdd(GOT, Sub, OutContext);
102263764Sdim  const SparcMCExpr *expr = SparcMCExpr::Create(Kind,
103263764Sdim                                                Add, OutContext);
104263764Sdim  return MCOperand::CreateExpr(expr);
105263764Sdim}
106263764Sdim
107263764Sdimstatic void EmitCall(MCStreamer &OutStreamer,
108263764Sdim                     MCOperand &Callee)
109263764Sdim{
110263764Sdim  MCInst CallInst;
111263764Sdim  CallInst.setOpcode(SP::CALL);
112263764Sdim  CallInst.addOperand(Callee);
113263764Sdim  OutStreamer.EmitInstruction(CallInst);
114263764Sdim}
115263764Sdim
116263764Sdimstatic void EmitSETHI(MCStreamer &OutStreamer,
117263764Sdim                      MCOperand &Imm, MCOperand &RD)
118263764Sdim{
119263764Sdim  MCInst SETHIInst;
120263764Sdim  SETHIInst.setOpcode(SP::SETHIi);
121263764Sdim  SETHIInst.addOperand(RD);
122263764Sdim  SETHIInst.addOperand(Imm);
123263764Sdim  OutStreamer.EmitInstruction(SETHIInst);
124263764Sdim}
125263764Sdim
126263764Sdimstatic void EmitBinary(MCStreamer &OutStreamer, unsigned Opcode,
127263764Sdim                       MCOperand &RS1, MCOperand &Src2, MCOperand &RD)
128263764Sdim{
129263764Sdim  MCInst Inst;
130263764Sdim  Inst.setOpcode(Opcode);
131263764Sdim  Inst.addOperand(RD);
132263764Sdim  Inst.addOperand(RS1);
133263764Sdim  Inst.addOperand(Src2);
134263764Sdim  OutStreamer.EmitInstruction(Inst);
135263764Sdim}
136263764Sdim
137263764Sdimstatic void EmitOR(MCStreamer &OutStreamer,
138263764Sdim                   MCOperand &RS1, MCOperand &Imm, MCOperand &RD) {
139263764Sdim  EmitBinary(OutStreamer, SP::ORri, RS1, Imm, RD);
140263764Sdim}
141263764Sdim
142263764Sdimstatic void EmitADD(MCStreamer &OutStreamer,
143263764Sdim                    MCOperand &RS1, MCOperand &RS2, MCOperand &RD) {
144263764Sdim  EmitBinary(OutStreamer, SP::ADDrr, RS1, RS2, RD);
145263764Sdim}
146263764Sdim
147263764Sdimstatic void EmitSHL(MCStreamer &OutStreamer,
148263764Sdim                    MCOperand &RS1, MCOperand &Imm, MCOperand &RD) {
149263764Sdim  EmitBinary(OutStreamer, SP::SLLri, RS1, Imm, RD);
150263764Sdim}
151263764Sdim
152263764Sdim
153263764Sdimstatic void EmitHiLo(MCStreamer &OutStreamer,  MCSymbol *GOTSym,
154263764Sdim                     SparcMCExpr::VariantKind HiKind,
155263764Sdim                     SparcMCExpr::VariantKind LoKind,
156263764Sdim                     MCOperand &RD,
157263764Sdim                     MCContext &OutContext) {
158263764Sdim
159263764Sdim  MCOperand hi = createSparcMCOperand(HiKind, GOTSym, OutContext);
160263764Sdim  MCOperand lo = createSparcMCOperand(LoKind, GOTSym, OutContext);
161263764Sdim  EmitSETHI(OutStreamer, hi, RD);
162263764Sdim  EmitOR(OutStreamer, RD, lo, RD);
163263764Sdim}
164263764Sdim
165263764Sdimvoid SparcAsmPrinter::LowerGETPCXAndEmitMCInsts(const MachineInstr *MI)
166263764Sdim{
167263764Sdim  MCSymbol *GOTLabel   =
168263764Sdim    OutContext.GetOrCreateSymbol(Twine("_GLOBAL_OFFSET_TABLE_"));
169263764Sdim
170263764Sdim  const MachineOperand &MO = MI->getOperand(0);
171263764Sdim  assert(MO.getReg() != SP::O7 &&
172263764Sdim         "%o7 is assigned as destination for getpcx!");
173263764Sdim
174263764Sdim  MCOperand MCRegOP = MCOperand::CreateReg(MO.getReg());
175263764Sdim
176263764Sdim
177263764Sdim  if (TM.getRelocationModel() != Reloc::PIC_) {
178263764Sdim    // Just load the address of GOT to MCRegOP.
179263764Sdim    switch(TM.getCodeModel()) {
180263764Sdim    default:
181263764Sdim      llvm_unreachable("Unsupported absolute code model");
182263764Sdim    case CodeModel::Small:
183263764Sdim      EmitHiLo(OutStreamer, GOTLabel,
184263764Sdim               SparcMCExpr::VK_Sparc_HI, SparcMCExpr::VK_Sparc_LO,
185263764Sdim               MCRegOP, OutContext);
186263764Sdim      break;
187263764Sdim    case CodeModel::Medium: {
188263764Sdim      EmitHiLo(OutStreamer, GOTLabel,
189263764Sdim               SparcMCExpr::VK_Sparc_H44, SparcMCExpr::VK_Sparc_M44,
190263764Sdim               MCRegOP, OutContext);
191263764Sdim      MCOperand imm = MCOperand::CreateExpr(MCConstantExpr::Create(12,
192263764Sdim                                                                   OutContext));
193263764Sdim      EmitSHL(OutStreamer, MCRegOP, imm, MCRegOP);
194263764Sdim      MCOperand lo = createSparcMCOperand(SparcMCExpr::VK_Sparc_L44,
195263764Sdim                                          GOTLabel, OutContext);
196263764Sdim      EmitOR(OutStreamer, MCRegOP, lo, MCRegOP);
197263764Sdim      break;
198263764Sdim    }
199263764Sdim    case CodeModel::Large: {
200263764Sdim      EmitHiLo(OutStreamer, GOTLabel,
201263764Sdim               SparcMCExpr::VK_Sparc_HH, SparcMCExpr::VK_Sparc_HM,
202263764Sdim               MCRegOP, OutContext);
203263764Sdim      MCOperand imm = MCOperand::CreateExpr(MCConstantExpr::Create(32,
204263764Sdim                                                                   OutContext));
205263764Sdim      EmitSHL(OutStreamer, MCRegOP, imm, MCRegOP);
206263764Sdim      // Use register %o7 to load the lower 32 bits.
207263764Sdim      MCOperand RegO7 = MCOperand::CreateReg(SP::O7);
208263764Sdim      EmitHiLo(OutStreamer, GOTLabel,
209263764Sdim               SparcMCExpr::VK_Sparc_HI, SparcMCExpr::VK_Sparc_LO,
210263764Sdim               RegO7, OutContext);
211263764Sdim      EmitADD(OutStreamer, MCRegOP, RegO7, MCRegOP);
212263764Sdim    }
213263764Sdim    }
214263764Sdim    return;
215263764Sdim  }
216263764Sdim
217263764Sdim  MCSymbol *StartLabel = OutContext.CreateTempSymbol();
218263764Sdim  MCSymbol *EndLabel   = OutContext.CreateTempSymbol();
219263764Sdim  MCSymbol *SethiLabel = OutContext.CreateTempSymbol();
220263764Sdim
221263764Sdim  MCOperand RegO7   = MCOperand::CreateReg(SP::O7);
222263764Sdim
223263764Sdim  // <StartLabel>:
224263764Sdim  //   call <EndLabel>
225263764Sdim  // <SethiLabel>:
226263764Sdim  //     sethi %hi(_GLOBAL_OFFSET_TABLE_+(<SethiLabel>-<StartLabel>)), <MO>
227263764Sdim  // <EndLabel>:
228263764Sdim  //   or  <MO>, %lo(_GLOBAL_OFFSET_TABLE_+(<EndLabel>-<StartLabel>))), <MO>
229263764Sdim  //   add <MO>, %o7, <MO>
230263764Sdim
231263764Sdim  OutStreamer.EmitLabel(StartLabel);
232263764Sdim  MCOperand Callee =  createPCXCallOP(EndLabel, OutContext);
233263764Sdim  EmitCall(OutStreamer, Callee);
234263764Sdim  OutStreamer.EmitLabel(SethiLabel);
235263764Sdim  MCOperand hiImm = createPCXRelExprOp(SparcMCExpr::VK_Sparc_PC22,
236263764Sdim                                       GOTLabel, StartLabel, SethiLabel,
237263764Sdim                                       OutContext);
238263764Sdim  EmitSETHI(OutStreamer, hiImm, MCRegOP);
239263764Sdim  OutStreamer.EmitLabel(EndLabel);
240263764Sdim  MCOperand loImm = createPCXRelExprOp(SparcMCExpr::VK_Sparc_PC10,
241263764Sdim                                       GOTLabel, StartLabel, EndLabel,
242263764Sdim                                       OutContext);
243263764Sdim  EmitOR(OutStreamer, MCRegOP, loImm, MCRegOP);
244263764Sdim  EmitADD(OutStreamer, MCRegOP, RegO7, MCRegOP);
245263764Sdim}
246263764Sdim
247263764Sdimvoid SparcAsmPrinter::EmitInstruction(const MachineInstr *MI)
248263764Sdim{
249263764Sdim
250263764Sdim  switch (MI->getOpcode()) {
251263764Sdim  default: break;
252263764Sdim  case TargetOpcode::DBG_VALUE:
253263764Sdim    // FIXME: Debug Value.
254263764Sdim    return;
255263764Sdim  case SP::GETPCX:
256263764Sdim    LowerGETPCXAndEmitMCInsts(MI);
257263764Sdim    return;
258263764Sdim  }
259263764Sdim  MachineBasicBlock::const_instr_iterator I = MI;
260263764Sdim  MachineBasicBlock::const_instr_iterator E = MI->getParent()->instr_end();
261263764Sdim  do {
262263764Sdim    MCInst TmpInst;
263263764Sdim    LowerSparcMachineInstrToMCInst(I, TmpInst, *this);
264263764Sdim    OutStreamer.EmitInstruction(TmpInst);
265263764Sdim  } while ((++I != E) && I->isInsideBundle()); // Delay slot check.
266263764Sdim}
267263764Sdim
268263509Sdimvoid SparcAsmPrinter::EmitFunctionBodyStart() {
269263509Sdim  if (!TM.getSubtarget<SparcSubtarget>().is64Bit())
270263509Sdim    return;
271263509Sdim
272263509Sdim  const MachineRegisterInfo &MRI = MF->getRegInfo();
273263509Sdim  const unsigned globalRegs[] = { SP::G2, SP::G3, SP::G6, SP::G7, 0 };
274263509Sdim  for (unsigned i = 0; globalRegs[i] != 0; ++i) {
275263509Sdim    unsigned reg = globalRegs[i];
276263509Sdim    if (MRI.use_empty(reg))
277263509Sdim      continue;
278263764Sdim
279263764Sdim    if  (reg == SP::G6 || reg == SP::G7)
280263764Sdim      getTargetStreamer().emitSparcRegisterIgnore(reg);
281263764Sdim    else
282263764Sdim      getTargetStreamer().emitSparcRegisterScratch(reg);
283263509Sdim  }
284263509Sdim}
285263509Sdim
286218885Sdimvoid SparcAsmPrinter::printOperand(const MachineInstr *MI, int opNum,
287218885Sdim                                   raw_ostream &O) {
288218885Sdim  const MachineOperand &MO = MI->getOperand (opNum);
289263764Sdim  SparcMCExpr::VariantKind TF = (SparcMCExpr::VariantKind) MO.getTargetFlags();
290263764Sdim
291252723Sdim#ifndef NDEBUG
292252723Sdim  // Verify the target flags.
293252723Sdim  if (MO.isGlobal() || MO.isSymbol() || MO.isCPI()) {
294252723Sdim    if (MI->getOpcode() == SP::CALL)
295263764Sdim      assert(TF == SparcMCExpr::VK_Sparc_None &&
296252723Sdim             "Cannot handle target flags on call address");
297263764Sdim    else if (MI->getOpcode() == SP::SETHIi || MI->getOpcode() == SP::SETHIXi)
298263764Sdim      assert((TF == SparcMCExpr::VK_Sparc_HI
299263764Sdim              || TF == SparcMCExpr::VK_Sparc_H44
300263764Sdim              || TF == SparcMCExpr::VK_Sparc_HH
301263764Sdim              || TF == SparcMCExpr::VK_Sparc_TLS_GD_HI22
302263764Sdim              || TF == SparcMCExpr::VK_Sparc_TLS_LDM_HI22
303263764Sdim              || TF == SparcMCExpr::VK_Sparc_TLS_LDO_HIX22
304263764Sdim              || TF == SparcMCExpr::VK_Sparc_TLS_IE_HI22
305263764Sdim              || TF == SparcMCExpr::VK_Sparc_TLS_LE_HIX22) &&
306252723Sdim             "Invalid target flags for address operand on sethi");
307263509Sdim    else if (MI->getOpcode() == SP::TLS_CALL)
308263764Sdim      assert((TF == SparcMCExpr::VK_Sparc_None
309263764Sdim              || TF == SparcMCExpr::VK_Sparc_TLS_GD_CALL
310263764Sdim              || TF == SparcMCExpr::VK_Sparc_TLS_LDM_CALL) &&
311263509Sdim             "Cannot handle target flags on tls call address");
312263509Sdim    else if (MI->getOpcode() == SP::TLS_ADDrr)
313263764Sdim      assert((TF == SparcMCExpr::VK_Sparc_TLS_GD_ADD
314263764Sdim              || TF == SparcMCExpr::VK_Sparc_TLS_LDM_ADD
315263764Sdim              || TF == SparcMCExpr::VK_Sparc_TLS_LDO_ADD
316263764Sdim              || TF == SparcMCExpr::VK_Sparc_TLS_IE_ADD) &&
317263509Sdim             "Cannot handle target flags on add for TLS");
318263509Sdim    else if (MI->getOpcode() == SP::TLS_LDrr)
319263764Sdim      assert(TF == SparcMCExpr::VK_Sparc_TLS_IE_LD &&
320263509Sdim             "Cannot handle target flags on ld for TLS");
321263509Sdim    else if (MI->getOpcode() == SP::TLS_LDXrr)
322263764Sdim      assert(TF == SparcMCExpr::VK_Sparc_TLS_IE_LDX &&
323263509Sdim             "Cannot handle target flags on ldx for TLS");
324263764Sdim    else if (MI->getOpcode() == SP::XORri || MI->getOpcode() == SP::XORXri)
325263764Sdim      assert((TF == SparcMCExpr::VK_Sparc_TLS_LDO_LOX10
326263764Sdim              || TF == SparcMCExpr::VK_Sparc_TLS_LE_LOX10) &&
327263509Sdim             "Cannot handle target flags on xor for TLS");
328252723Sdim    else
329263764Sdim      assert((TF == SparcMCExpr::VK_Sparc_LO
330263764Sdim              || TF == SparcMCExpr::VK_Sparc_M44
331263764Sdim              || TF == SparcMCExpr::VK_Sparc_L44
332263764Sdim              || TF == SparcMCExpr::VK_Sparc_HM
333263764Sdim              || TF == SparcMCExpr::VK_Sparc_TLS_GD_LO10
334263764Sdim              || TF == SparcMCExpr::VK_Sparc_TLS_LDM_LO10
335263764Sdim              || TF == SparcMCExpr::VK_Sparc_TLS_IE_LO10 ) &&
336252723Sdim             "Invalid target flags for small address operand");
337218885Sdim  }
338252723Sdim#endif
339252723Sdim
340252723Sdim
341263764Sdim  bool CloseParen = SparcMCExpr::printVariantKind(O, TF);
342263764Sdim
343218885Sdim  switch (MO.getType()) {
344218885Sdim  case MachineOperand::MO_Register:
345235633Sdim    O << "%" << StringRef(getRegisterName(MO.getReg())).lower();
346218885Sdim    break;
347218885Sdim
348218885Sdim  case MachineOperand::MO_Immediate:
349218885Sdim    O << (int)MO.getImm();
350218885Sdim    break;
351218885Sdim  case MachineOperand::MO_MachineBasicBlock:
352218885Sdim    O << *MO.getMBB()->getSymbol();
353218885Sdim    return;
354218885Sdim  case MachineOperand::MO_GlobalAddress:
355263509Sdim    O << *getSymbol(MO.getGlobal());
356218885Sdim    break;
357263509Sdim  case MachineOperand::MO_BlockAddress:
358263509Sdim    O <<  GetBlockAddressSymbol(MO.getBlockAddress())->getName();
359263509Sdim    break;
360218885Sdim  case MachineOperand::MO_ExternalSymbol:
361218885Sdim    O << MO.getSymbolName();
362218885Sdim    break;
363218885Sdim  case MachineOperand::MO_ConstantPoolIndex:
364218885Sdim    O << MAI->getPrivateGlobalPrefix() << "CPI" << getFunctionNumber() << "_"
365218885Sdim      << MO.getIndex();
366218885Sdim    break;
367218885Sdim  default:
368218885Sdim    llvm_unreachable("<unknown operand type>");
369218885Sdim  }
370218885Sdim  if (CloseParen) O << ")";
371218885Sdim}
372218885Sdim
373218885Sdimvoid SparcAsmPrinter::printMemOperand(const MachineInstr *MI, int opNum,
374218885Sdim                                      raw_ostream &O, const char *Modifier) {
375218885Sdim  printOperand(MI, opNum, O);
376218885Sdim
377218885Sdim  // If this is an ADD operand, emit it like normal operands.
378218885Sdim  if (Modifier && !strcmp(Modifier, "arith")) {
379218885Sdim    O << ", ";
380218885Sdim    printOperand(MI, opNum+1, O);
381218885Sdim    return;
382218885Sdim  }
383218885Sdim
384218885Sdim  if (MI->getOperand(opNum+1).isReg() &&
385218885Sdim      MI->getOperand(opNum+1).getReg() == SP::G0)
386218885Sdim    return;   // don't print "+%g0"
387218885Sdim  if (MI->getOperand(opNum+1).isImm() &&
388218885Sdim      MI->getOperand(opNum+1).getImm() == 0)
389218885Sdim    return;   // don't print "+0"
390218885Sdim
391218885Sdim  O << "+";
392252723Sdim  printOperand(MI, opNum+1, O);
393218885Sdim}
394218885Sdim
395218885Sdim/// PrintAsmOperand - Print out an operand for an inline asm expression.
396218885Sdim///
397218885Sdimbool SparcAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
398218885Sdim                                      unsigned AsmVariant,
399218885Sdim                                      const char *ExtraCode,
400218885Sdim                                      raw_ostream &O) {
401218885Sdim  if (ExtraCode && ExtraCode[0]) {
402218885Sdim    if (ExtraCode[1] != 0) return true; // Unknown modifier.
403218885Sdim
404218885Sdim    switch (ExtraCode[0]) {
405245431Sdim    default:
406245431Sdim      // See if this is a generic print operand
407245431Sdim      return AsmPrinter::PrintAsmOperand(MI, OpNo, AsmVariant, ExtraCode, O);
408218885Sdim    case 'r':
409218885Sdim     break;
410218885Sdim    }
411218885Sdim  }
412218885Sdim
413218885Sdim  printOperand(MI, OpNo, O);
414218885Sdim
415218885Sdim  return false;
416218885Sdim}
417218885Sdim
418218885Sdimbool SparcAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,
419218885Sdim                                            unsigned OpNo, unsigned AsmVariant,
420218885Sdim                                            const char *ExtraCode,
421218885Sdim                                            raw_ostream &O) {
422218885Sdim  if (ExtraCode && ExtraCode[0])
423218885Sdim    return true;  // Unknown modifier
424218885Sdim
425218885Sdim  O << '[';
426218885Sdim  printMemOperand(MI, OpNo, O);
427218885Sdim  O << ']';
428218885Sdim
429218885Sdim  return false;
430218885Sdim}
431218885Sdim
432263764Sdimvoid SparcAsmPrinter::EmitEndOfAsmFile(Module &M) {
433263764Sdim  const TargetLoweringObjectFileELF &TLOFELF =
434263764Sdim    static_cast<const TargetLoweringObjectFileELF &>(getObjFileLowering());
435263764Sdim  MachineModuleInfoELF &MMIELF = MMI->getObjFileInfo<MachineModuleInfoELF>();
436263509Sdim
437263764Sdim  // Generate stubs for global variables.
438263764Sdim  MachineModuleInfoELF::SymbolListTy Stubs = MMIELF.GetGVStubList();
439263764Sdim  if (!Stubs.empty()) {
440263764Sdim    OutStreamer.SwitchSection(TLOFELF.getDataSection());
441263764Sdim    unsigned PtrSize = TM.getDataLayout()->getPointerSize(0);
442263764Sdim    for (unsigned i = 0, e = Stubs.size(); i != e; ++i) {
443263764Sdim      OutStreamer.EmitLabel(Stubs[i].first);
444263764Sdim      OutStreamer.EmitSymbolValue(Stubs[i].second.getPointer(), PtrSize);
445263764Sdim    }
446263764Sdim  }
447218885Sdim}
448218885Sdim
449218885Sdim// Force static initialization.
450263509Sdimextern "C" void LLVMInitializeSparcAsmPrinter() {
451218885Sdim  RegisterAsmPrinter<SparcAsmPrinter> X(TheSparcTarget);
452218885Sdim  RegisterAsmPrinter<SparcAsmPrinter> Y(TheSparcV9Target);
453218885Sdim}
454