XCoreAsmPrinter.cpp revision 3d10a5a75794356a0a568ce283713adc3a963200
1//===-- XCoreAsmPrinter.cpp - XCore LLVM assembly writer ------------------===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file contains a printer that converts from our internal representation
11// of machine-dependent LLVM code to the XAS-format XCore assembly language.
12//
13//===----------------------------------------------------------------------===//
14
15#define DEBUG_TYPE "asm-printer"
16#include "XCore.h"
17#include "XCoreInstrInfo.h"
18#include "XCoreSubtarget.h"
19#include "XCoreTargetMachine.h"
20#include "llvm/Constants.h"
21#include "llvm/DerivedTypes.h"
22#include "llvm/Module.h"
23#include "llvm/CodeGen/AsmPrinter.h"
24#include "llvm/CodeGen/DwarfWriter.h"
25#include "llvm/CodeGen/MachineModuleInfo.h"
26#include "llvm/CodeGen/MachineFunctionPass.h"
27#include "llvm/CodeGen/MachineConstantPool.h"
28#include "llvm/CodeGen/MachineInstr.h"
29#include "llvm/Target/TargetAsmInfo.h"
30#include "llvm/Target/TargetData.h"
31#include "llvm/Support/Mangler.h"
32#include "llvm/ADT/Statistic.h"
33#include "llvm/ADT/StringExtras.h"
34#include "llvm/Support/CommandLine.h"
35#include "llvm/Support/ErrorHandling.h"
36#include "llvm/Support/FormattedStream.h"
37#include "llvm/Support/MathExtras.h"
38#include <algorithm>
39#include <cctype>
40using namespace llvm;
41
42STATISTIC(EmittedInsts, "Number of machine instrs printed");
43
44static cl::opt<unsigned> MaxThreads("xcore-max-threads", cl::Optional,
45  cl::desc("Maximum number of threads (for emulation thread-local storage)"),
46  cl::Hidden,
47  cl::value_desc("number"),
48  cl::init(8));
49
50namespace {
51  class VISIBILITY_HIDDEN XCoreAsmPrinter : public AsmPrinter {
52    DwarfWriter *DW;
53    const XCoreSubtarget &Subtarget;
54  public:
55    explicit XCoreAsmPrinter(formatted_raw_ostream &O, TargetMachine &TM,
56                             const TargetAsmInfo *T, bool V)
57      : AsmPrinter(O, TM, T, V), DW(0),
58      Subtarget(TM.getSubtarget<XCoreSubtarget>()) {}
59
60    virtual const char *getPassName() const {
61      return "XCore Assembly Printer";
62    }
63
64    void printMemOperand(const MachineInstr *MI, int opNum);
65    void printOperand(const MachineInstr *MI, int opNum);
66    bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
67                        unsigned AsmVariant, const char *ExtraCode);
68
69    void emitGlobalDirective(const std::string &name);
70    void emitExternDirective(const std::string &name);
71
72    void emitArrayBound(const std::string &name, const GlobalVariable *GV);
73    void emitGlobal(const GlobalVariable *GV);
74
75    void emitFunctionStart(MachineFunction &MF);
76    void emitFunctionEnd(MachineFunction &MF);
77
78    bool printInstruction(const MachineInstr *MI);  // autogenerated.
79    void printMachineInstruction(const MachineInstr *MI);
80    bool runOnMachineFunction(MachineFunction &F);
81    bool doInitialization(Module &M);
82    bool doFinalization(Module &M);
83
84    void getAnalysisUsage(AnalysisUsage &AU) const {
85      AsmPrinter::getAnalysisUsage(AU);
86      AU.setPreservesAll();
87      AU.addRequired<MachineModuleInfo>();
88      AU.addRequired<DwarfWriter>();
89    }
90  };
91} // end of anonymous namespace
92
93#include "XCoreGenAsmWriter.inc"
94
95/// createXCoreCodePrinterPass - Returns a pass that prints the XCore
96/// assembly code for a MachineFunction to the given output stream,
97/// using the given target machine description.  This should work
98/// regardless of whether the function is in SSA form.
99///
100FunctionPass *llvm::createXCoreCodePrinterPass(formatted_raw_ostream &o,
101                                               TargetMachine &tm,
102                                               bool verbose) {
103  return new XCoreAsmPrinter(o, tm, tm.getTargetAsmInfo(), verbose);
104}
105
106void XCoreAsmPrinter::
107emitGlobalDirective(const std::string &name)
108{
109  O << TAI->getGlobalDirective() << name;
110  O << "\n";
111}
112
113void XCoreAsmPrinter::
114emitExternDirective(const std::string &name)
115{
116  O << "\t.extern\t" << name;
117  O << '\n';
118}
119
120void XCoreAsmPrinter::
121emitArrayBound(const std::string &name, const GlobalVariable *GV)
122{
123  assert(((GV->hasExternalLinkage() ||
124    GV->hasWeakLinkage()) ||
125    GV->hasLinkOnceLinkage()) && "Unexpected linkage");
126  if (const ArrayType *ATy = dyn_cast<ArrayType>(
127    cast<PointerType>(GV->getType())->getElementType()))
128  {
129    O << TAI->getGlobalDirective() << name << ".globound" << "\n";
130    O << TAI->getSetDirective() << name << ".globound" << ","
131      << ATy->getNumElements() << "\n";
132    if (GV->hasWeakLinkage() || GV->hasLinkOnceLinkage()) {
133      // TODO Use COMDAT groups for LinkOnceLinkage
134      O << TAI->getWeakDefDirective() << name << ".globound" << "\n";
135    }
136  }
137}
138
139void XCoreAsmPrinter::
140emitGlobal(const GlobalVariable *GV)
141{
142  const TargetData *TD = TM.getTargetData();
143
144  if (GV->hasInitializer()) {
145    // Check to see if this is a special global used by LLVM, if so, emit it.
146    if (EmitSpecialLLVMGlobal(GV))
147      return;
148
149    SwitchToSection(TAI->SectionForGlobal(GV));
150
151    std::string name = Mang->getMangledName(GV);
152    Constant *C = GV->getInitializer();
153    unsigned Align = (unsigned)TD->getPreferredTypeAlignmentShift(C->getType());
154
155    // Mark the start of the global
156    O << "\t.cc_top " << name << ".data," << name << "\n";
157
158    switch (GV->getLinkage()) {
159    case GlobalValue::AppendingLinkage:
160      llvm_report_error("AppendingLinkage is not supported by this target!");
161    case GlobalValue::LinkOnceAnyLinkage:
162    case GlobalValue::LinkOnceODRLinkage:
163    case GlobalValue::WeakAnyLinkage:
164    case GlobalValue::WeakODRLinkage:
165    case GlobalValue::ExternalLinkage:
166      emitArrayBound(name, GV);
167      emitGlobalDirective(name);
168      // TODO Use COMDAT groups for LinkOnceLinkage
169      if (GV->hasWeakLinkage() || GV->hasLinkOnceLinkage()) {
170        O << TAI->getWeakDefDirective() << name << "\n";
171      }
172      // FALL THROUGH
173    case GlobalValue::InternalLinkage:
174    case GlobalValue::PrivateLinkage:
175    case GlobalValue::LinkerPrivateLinkage:
176      break;
177    case GlobalValue::GhostLinkage:
178      llvm_unreachable("Should not have any unmaterialized functions!");
179    case GlobalValue::DLLImportLinkage:
180      llvm_unreachable("DLLImport linkage is not supported by this target!");
181    case GlobalValue::DLLExportLinkage:
182      llvm_unreachable("DLLExport linkage is not supported by this target!");
183    default:
184      llvm_unreachable("Unknown linkage type!");
185    }
186
187    EmitAlignment(Align, GV, 2);
188
189    unsigned Size = TD->getTypeAllocSize(C->getType());
190    if (GV->isThreadLocal()) {
191      Size *= MaxThreads;
192    }
193    if (TAI->hasDotTypeDotSizeDirective()) {
194      O << "\t.type " << name << ",@object\n";
195      O << "\t.size " << name << "," << Size << "\n";
196    }
197    O << name << ":\n";
198
199    EmitGlobalConstant(C);
200    if (GV->isThreadLocal()) {
201      for (unsigned i = 1; i < MaxThreads; ++i) {
202        EmitGlobalConstant(C);
203      }
204    }
205    if (Size < 4) {
206      // The ABI requires that unsigned scalar types smaller than 32 bits
207      // are are padded to 32 bits.
208      EmitZeros(4 - Size);
209    }
210
211    // Mark the end of the global
212    O << "\t.cc_bottom " << name << ".data\n";
213  }
214}
215
216/// Emit the directives on the start of functions
217void XCoreAsmPrinter::
218emitFunctionStart(MachineFunction &MF)
219{
220  // Print out the label for the function.
221  const Function *F = MF.getFunction();
222
223  SwitchToSection(TAI->SectionForGlobal(F));
224
225  // Mark the start of the function
226  O << "\t.cc_top " << CurrentFnName << ".function," << CurrentFnName << "\n";
227
228  switch (F->getLinkage()) {
229  default: llvm_unreachable("Unknown linkage type!");
230  case Function::InternalLinkage:  // Symbols default to internal.
231  case Function::PrivateLinkage:
232  case Function::LinkerPrivateLinkage:
233    break;
234  case Function::ExternalLinkage:
235    emitGlobalDirective(CurrentFnName);
236    break;
237  case Function::LinkOnceAnyLinkage:
238  case Function::LinkOnceODRLinkage:
239  case Function::WeakAnyLinkage:
240  case Function::WeakODRLinkage:
241    // TODO Use COMDAT groups for LinkOnceLinkage
242    O << TAI->getGlobalDirective() << CurrentFnName << "\n";
243    O << TAI->getWeakDefDirective() << CurrentFnName << "\n";
244    break;
245  }
246  // (1 << 1) byte aligned
247  EmitAlignment(MF.getAlignment(), F, 1);
248  if (TAI->hasDotTypeDotSizeDirective()) {
249    O << "\t.type " << CurrentFnName << ",@function\n";
250  }
251  O << CurrentFnName << ":\n";
252}
253
254/// Emit the directives on the end of functions
255void XCoreAsmPrinter::
256emitFunctionEnd(MachineFunction &MF)
257{
258  // Mark the end of the function
259  O << "\t.cc_bottom " << CurrentFnName << ".function\n";
260}
261
262/// runOnMachineFunction - This uses the printMachineInstruction()
263/// method to print assembly for each instruction.
264///
265bool XCoreAsmPrinter::runOnMachineFunction(MachineFunction &MF)
266{
267  this->MF = &MF;
268
269  SetupMachineFunction(MF);
270
271  // Print out constants referenced by the function
272  EmitConstantPool(MF.getConstantPool());
273
274  // Print out jump tables referenced by the function
275  EmitJumpTableInfo(MF.getJumpTableInfo(), MF);
276
277  // Emit the function start directives
278  emitFunctionStart(MF);
279
280  // Emit pre-function debug information.
281  DW->BeginFunction(&MF);
282
283  // Print out code for the function.
284  for (MachineFunction::const_iterator I = MF.begin(), E = MF.end();
285       I != E; ++I) {
286
287    // Print a label for the basic block.
288    if (I != MF.begin()) {
289      printBasicBlockLabel(I, true , true);
290      O << '\n';
291    }
292
293    for (MachineBasicBlock::const_iterator II = I->begin(), E = I->end();
294         II != E; ++II) {
295      // Print the assembly for the instruction.
296      O << "\t";
297      printMachineInstruction(II);
298    }
299
300    // Each Basic Block is separated by a newline
301    O << '\n';
302  }
303
304  // Emit function end directives
305  emitFunctionEnd(MF);
306
307  // Emit post-function debug information.
308  DW->EndFunction(&MF);
309
310  // We didn't modify anything.
311  return false;
312}
313
314void XCoreAsmPrinter::printMemOperand(const MachineInstr *MI, int opNum)
315{
316  printOperand(MI, opNum);
317
318  if (MI->getOperand(opNum+1).isImm()
319    && MI->getOperand(opNum+1).getImm() == 0)
320    return;
321
322  O << "+";
323  printOperand(MI, opNum+1);
324}
325
326void XCoreAsmPrinter::printOperand(const MachineInstr *MI, int opNum) {
327  const MachineOperand &MO = MI->getOperand(opNum);
328  switch (MO.getType()) {
329  case MachineOperand::MO_Register:
330    if (TargetRegisterInfo::isPhysicalRegister(MO.getReg()))
331      O << TM.getRegisterInfo()->get(MO.getReg()).AsmName;
332    else
333      llvm_unreachable("not implemented");
334    break;
335  case MachineOperand::MO_Immediate:
336    O << MO.getImm();
337    break;
338  case MachineOperand::MO_MachineBasicBlock:
339    printBasicBlockLabel(MO.getMBB());
340    break;
341  case MachineOperand::MO_GlobalAddress:
342    O << Mang->getMangledName(MO.getGlobal());
343    break;
344  case MachineOperand::MO_ExternalSymbol:
345    O << MO.getSymbolName();
346    break;
347  case MachineOperand::MO_ConstantPoolIndex:
348    O << TAI->getPrivateGlobalPrefix() << "CPI" << getFunctionNumber()
349      << '_' << MO.getIndex();
350    break;
351  case MachineOperand::MO_JumpTableIndex:
352    O << TAI->getPrivateGlobalPrefix() << "JTI" << getFunctionNumber()
353      << '_' << MO.getIndex();
354    break;
355  default:
356    llvm_unreachable("not implemented");
357  }
358}
359
360/// PrintAsmOperand - Print out an operand for an inline asm expression.
361///
362bool XCoreAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
363                                      unsigned AsmVariant,
364                                      const char *ExtraCode) {
365  printOperand(MI, OpNo);
366  return false;
367}
368
369void XCoreAsmPrinter::printMachineInstruction(const MachineInstr *MI) {
370  ++EmittedInsts;
371
372  // Check for mov mnemonic
373  unsigned src, dst, srcSR, dstSR;
374  if (TM.getInstrInfo()->isMoveInstr(*MI, src, dst, srcSR, dstSR)) {
375    O << "\tmov ";
376    O << TM.getRegisterInfo()->get(dst).AsmName;
377    O << ", ";
378    O << TM.getRegisterInfo()->get(src).AsmName;
379    O << "\n";
380    return;
381  }
382  if (printInstruction(MI)) {
383    return;
384  }
385  llvm_unreachable("Unhandled instruction in asm writer!");
386}
387
388bool XCoreAsmPrinter::doInitialization(Module &M) {
389  bool Result = AsmPrinter::doInitialization(M);
390  DW = getAnalysisIfAvailable<DwarfWriter>();
391
392  return Result;
393}
394
395bool XCoreAsmPrinter::doFinalization(Module &M) {
396
397  // Print out module-level global variables.
398  for (Module::const_global_iterator I = M.global_begin(), E = M.global_end();
399       I != E; ++I) {
400    emitGlobal(I);
401  }
402
403  return AsmPrinter::doFinalization(M);
404}
405