XCoreAsmPrinter.cpp revision 249423
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 "InstPrinter/XCoreInstPrinter.h"
18#include "XCoreInstrInfo.h"
19#include "XCoreMCInstLower.h"
20#include "XCoreSubtarget.h"
21#include "XCoreTargetMachine.h"
22#include "llvm/ADT/SmallString.h"
23#include "llvm/ADT/StringExtras.h"
24#include "llvm/CodeGen/AsmPrinter.h"
25#include "llvm/CodeGen/MachineConstantPool.h"
26#include "llvm/CodeGen/MachineFunctionPass.h"
27#include "llvm/CodeGen/MachineInstr.h"
28#include "llvm/CodeGen/MachineJumpTableInfo.h"
29#include "llvm/CodeGen/MachineModuleInfo.h"
30#include "llvm/DebugInfo.h"
31#include "llvm/IR/Constants.h"
32#include "llvm/IR/DataLayout.h"
33#include "llvm/IR/DerivedTypes.h"
34#include "llvm/IR/Module.h"
35#include "llvm/MC/MCAsmInfo.h"
36#include "llvm/MC/MCInst.h"
37#include "llvm/MC/MCStreamer.h"
38#include "llvm/MC/MCSymbol.h"
39#include "llvm/Support/CommandLine.h"
40#include "llvm/Support/ErrorHandling.h"
41#include "llvm/Support/TargetRegistry.h"
42#include "llvm/Support/raw_ostream.h"
43#include "llvm/Target/Mangler.h"
44#include "llvm/Target/TargetLoweringObjectFile.h"
45#include <algorithm>
46#include <cctype>
47using namespace llvm;
48
49static cl::opt<unsigned> MaxThreads("xcore-max-threads", cl::Optional,
50  cl::desc("Maximum number of threads (for emulation thread-local storage)"),
51  cl::Hidden,
52  cl::value_desc("number"),
53  cl::init(8));
54
55namespace {
56  class XCoreAsmPrinter : public AsmPrinter {
57    const XCoreSubtarget &Subtarget;
58    XCoreMCInstLower MCInstLowering;
59    void PrintDebugValueComment(const MachineInstr *MI, raw_ostream &OS);
60  public:
61    explicit XCoreAsmPrinter(TargetMachine &TM, MCStreamer &Streamer)
62      : AsmPrinter(TM, Streamer), Subtarget(TM.getSubtarget<XCoreSubtarget>()),
63        MCInstLowering(*this) {}
64
65    virtual const char *getPassName() const {
66      return "XCore Assembly Printer";
67    }
68
69    void printInlineJT(const MachineInstr *MI, int opNum, raw_ostream &O,
70                       const std::string &directive = ".jmptable");
71    void printInlineJT32(const MachineInstr *MI, int opNum, raw_ostream &O) {
72      printInlineJT(MI, opNum, O, ".jmptable32");
73    }
74    void printOperand(const MachineInstr *MI, int opNum, raw_ostream &O);
75    bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
76                         unsigned AsmVariant, const char *ExtraCode,
77                         raw_ostream &O);
78
79    void emitArrayBound(MCSymbol *Sym, const GlobalVariable *GV);
80    virtual void EmitGlobalVariable(const GlobalVariable *GV);
81
82    void EmitFunctionEntryLabel();
83    void EmitInstruction(const MachineInstr *MI);
84    void EmitFunctionBodyStart();
85    void EmitFunctionBodyEnd();
86    virtual MachineLocation getDebugValueLocation(const MachineInstr *MI) const;
87  };
88} // end of anonymous namespace
89
90void XCoreAsmPrinter::emitArrayBound(MCSymbol *Sym, const GlobalVariable *GV) {
91  assert(((GV->hasExternalLinkage() ||
92    GV->hasWeakLinkage()) ||
93    GV->hasLinkOnceLinkage()) && "Unexpected linkage");
94  if (ArrayType *ATy = dyn_cast<ArrayType>(
95    cast<PointerType>(GV->getType())->getElementType())) {
96    OutStreamer.EmitSymbolAttribute(Sym, MCSA_Global);
97    // FIXME: MCStreamerize.
98    OutStreamer.EmitRawText(StringRef(".globound"));
99    OutStreamer.EmitRawText("\t.set\t" + Twine(Sym->getName()));
100    OutStreamer.EmitRawText(".globound," + Twine(ATy->getNumElements()));
101    if (GV->hasWeakLinkage() || GV->hasLinkOnceLinkage()) {
102      // TODO Use COMDAT groups for LinkOnceLinkage
103      OutStreamer.EmitRawText(MAI->getWeakDefDirective() +Twine(Sym->getName())+
104                              ".globound");
105    }
106  }
107}
108
109void XCoreAsmPrinter::EmitGlobalVariable(const GlobalVariable *GV) {
110  // Check to see if this is a special global used by LLVM, if so, emit it.
111  if (!GV->hasInitializer() ||
112      EmitSpecialLLVMGlobal(GV))
113    return;
114
115  const DataLayout *TD = TM.getDataLayout();
116  OutStreamer.SwitchSection(getObjFileLowering().SectionForGlobal(GV, Mang,TM));
117
118
119  MCSymbol *GVSym = Mang->getSymbol(GV);
120  const Constant *C = GV->getInitializer();
121  unsigned Align = (unsigned)TD->getPreferredTypeAlignmentShift(C->getType());
122
123  // Mark the start of the global
124  OutStreamer.EmitRawText("\t.cc_top " + Twine(GVSym->getName()) + ".data," +
125                          GVSym->getName());
126
127  switch (GV->getLinkage()) {
128  case GlobalValue::AppendingLinkage:
129    report_fatal_error("AppendingLinkage is not supported by this target!");
130  case GlobalValue::LinkOnceAnyLinkage:
131  case GlobalValue::LinkOnceODRLinkage:
132  case GlobalValue::WeakAnyLinkage:
133  case GlobalValue::WeakODRLinkage:
134  case GlobalValue::ExternalLinkage:
135    emitArrayBound(GVSym, GV);
136    OutStreamer.EmitSymbolAttribute(GVSym, MCSA_Global);
137
138    // TODO Use COMDAT groups for LinkOnceLinkage
139    if (GV->hasWeakLinkage() || GV->hasLinkOnceLinkage())
140      OutStreamer.EmitSymbolAttribute(GVSym, MCSA_Weak);
141    // FALL THROUGH
142  case GlobalValue::InternalLinkage:
143  case GlobalValue::PrivateLinkage:
144    break;
145  case GlobalValue::DLLImportLinkage:
146    llvm_unreachable("DLLImport linkage is not supported by this target!");
147  case GlobalValue::DLLExportLinkage:
148    llvm_unreachable("DLLExport linkage is not supported by this target!");
149  default:
150    llvm_unreachable("Unknown linkage type!");
151  }
152
153  EmitAlignment(Align > 2 ? Align : 2, GV);
154
155  unsigned Size = TD->getTypeAllocSize(C->getType());
156  if (GV->isThreadLocal()) {
157    Size *= MaxThreads;
158  }
159  if (MAI->hasDotTypeDotSizeDirective()) {
160    OutStreamer.EmitSymbolAttribute(GVSym, MCSA_ELF_TypeObject);
161    OutStreamer.EmitRawText("\t.size " + Twine(GVSym->getName()) + "," +
162                            Twine(Size));
163  }
164  OutStreamer.EmitLabel(GVSym);
165
166  EmitGlobalConstant(C);
167  if (GV->isThreadLocal()) {
168    for (unsigned i = 1; i < MaxThreads; ++i)
169      EmitGlobalConstant(C);
170  }
171  // The ABI requires that unsigned scalar types smaller than 32 bits
172  // are padded to 32 bits.
173  if (Size < 4)
174    OutStreamer.EmitZeros(4 - Size);
175
176  // Mark the end of the global
177  OutStreamer.EmitRawText("\t.cc_bottom " + Twine(GVSym->getName()) + ".data");
178}
179
180void XCoreAsmPrinter::EmitFunctionBodyStart() {
181  MCInstLowering.Initialize(Mang, &MF->getContext());
182}
183
184/// EmitFunctionBodyEnd - Targets can override this to emit stuff after
185/// the last basic block in the function.
186void XCoreAsmPrinter::EmitFunctionBodyEnd() {
187  // Emit function end directives
188  OutStreamer.EmitRawText("\t.cc_bottom " + Twine(CurrentFnSym->getName()) +
189                          ".function");
190}
191
192void XCoreAsmPrinter::EmitFunctionEntryLabel() {
193  // Mark the start of the function
194  OutStreamer.EmitRawText("\t.cc_top " + Twine(CurrentFnSym->getName()) +
195                          ".function," + CurrentFnSym->getName());
196  OutStreamer.EmitLabel(CurrentFnSym);
197}
198
199void XCoreAsmPrinter::
200printInlineJT(const MachineInstr *MI, int opNum, raw_ostream &O,
201              const std::string &directive) {
202  unsigned JTI = MI->getOperand(opNum).getIndex();
203  const MachineFunction *MF = MI->getParent()->getParent();
204  const MachineJumpTableInfo *MJTI = MF->getJumpTableInfo();
205  const std::vector<MachineJumpTableEntry> &JT = MJTI->getJumpTables();
206  const std::vector<MachineBasicBlock*> &JTBBs = JT[JTI].MBBs;
207  O << "\t" << directive << " ";
208  for (unsigned i = 0, e = JTBBs.size(); i != e; ++i) {
209    MachineBasicBlock *MBB = JTBBs[i];
210    if (i > 0)
211      O << ",";
212    O << *MBB->getSymbol();
213  }
214}
215
216void XCoreAsmPrinter::printOperand(const MachineInstr *MI, int opNum,
217                                   raw_ostream &O) {
218  const MachineOperand &MO = MI->getOperand(opNum);
219  switch (MO.getType()) {
220  case MachineOperand::MO_Register:
221    O << XCoreInstPrinter::getRegisterName(MO.getReg());
222    break;
223  case MachineOperand::MO_Immediate:
224    O << MO.getImm();
225    break;
226  case MachineOperand::MO_MachineBasicBlock:
227    O << *MO.getMBB()->getSymbol();
228    break;
229  case MachineOperand::MO_GlobalAddress:
230    O << *Mang->getSymbol(MO.getGlobal());
231    break;
232  case MachineOperand::MO_ExternalSymbol:
233    O << MO.getSymbolName();
234    break;
235  case MachineOperand::MO_ConstantPoolIndex:
236    O << MAI->getPrivateGlobalPrefix() << "CPI" << getFunctionNumber()
237      << '_' << MO.getIndex();
238    break;
239  case MachineOperand::MO_JumpTableIndex:
240    O << MAI->getPrivateGlobalPrefix() << "JTI" << getFunctionNumber()
241      << '_' << MO.getIndex();
242    break;
243  case MachineOperand::MO_BlockAddress:
244    O << *GetBlockAddressSymbol(MO.getBlockAddress());
245    break;
246  default:
247    llvm_unreachable("not implemented");
248  }
249}
250
251/// PrintAsmOperand - Print out an operand for an inline asm expression.
252///
253bool XCoreAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
254                                      unsigned AsmVariant,const char *ExtraCode,
255                                      raw_ostream &O) {
256  // Does this asm operand have a single letter operand modifier?
257  if (ExtraCode && ExtraCode[0])
258    if (ExtraCode[1] != 0) return true; // Unknown modifier.
259
260    switch (ExtraCode[0]) {
261    default:
262      // See if this is a generic print operand
263      return AsmPrinter::PrintAsmOperand(MI, OpNo, AsmVariant, ExtraCode, O);
264    }
265
266  printOperand(MI, OpNo, O);
267  return false;
268}
269
270void XCoreAsmPrinter::PrintDebugValueComment(const MachineInstr *MI,
271                                             raw_ostream &OS) {
272  unsigned NOps = MI->getNumOperands();
273  assert(NOps == 4);
274  OS << '\t' << MAI->getCommentString() << "DEBUG_VALUE: ";
275  // cast away const; DIetc do not take const operands for some reason.
276  DIVariable V(const_cast<MDNode *>(MI->getOperand(NOps-1).getMetadata()));
277  OS << V.getName();
278  OS << " <- ";
279  // Frame address.  Currently handles register +- offset only.
280  assert(MI->getOperand(0).isReg() && MI->getOperand(1).isImm());
281  OS << '['; printOperand(MI, 0, OS); OS << '+'; printOperand(MI, 1, OS);
282  OS << ']';
283  OS << "+";
284  printOperand(MI, NOps-2, OS);
285}
286
287MachineLocation XCoreAsmPrinter::
288getDebugValueLocation(const MachineInstr *MI) const {
289  // Handles frame addresses emitted in XCoreInstrInfo::emitFrameIndexDebugValue.
290  assert(MI->getNumOperands() == 4 && "Invalid no. of machine operands!");
291  assert(MI->getOperand(0).isReg() && MI->getOperand(1).isImm() &&
292         "Unexpected MachineOperand types");
293  return MachineLocation(MI->getOperand(0).getReg(),
294                         MI->getOperand(1).getImm());
295}
296
297void XCoreAsmPrinter::EmitInstruction(const MachineInstr *MI) {
298  SmallString<128> Str;
299  raw_svector_ostream O(Str);
300
301  switch (MI->getOpcode()) {
302  case XCore::DBG_VALUE: {
303    if (isVerbose() && OutStreamer.hasRawTextSupport()) {
304      SmallString<128> TmpStr;
305      raw_svector_ostream OS(TmpStr);
306      PrintDebugValueComment(MI, OS);
307      OutStreamer.EmitRawText(StringRef(OS.str()));
308    }
309    return;
310  }
311  case XCore::ADD_2rus:
312    if (MI->getOperand(2).getImm() == 0) {
313      O << "\tmov "
314        << XCoreInstPrinter::getRegisterName(MI->getOperand(0).getReg()) << ", "
315        << XCoreInstPrinter::getRegisterName(MI->getOperand(1).getReg());
316      OutStreamer.EmitRawText(O.str());
317      return;
318    }
319    break;
320  case XCore::BR_JT:
321  case XCore::BR_JT32:
322    O << "\tbru "
323      << XCoreInstPrinter::getRegisterName(MI->getOperand(1).getReg()) << '\n';
324    if (MI->getOpcode() == XCore::BR_JT)
325      printInlineJT(MI, 0, O);
326    else
327      printInlineJT32(MI, 0, O);
328    O << '\n';
329    OutStreamer.EmitRawText(O.str());
330    return;
331  }
332
333  MCInst TmpInst;
334  MCInstLowering.Lower(MI, TmpInst);
335
336  OutStreamer.EmitInstruction(TmpInst);
337}
338
339// Force static initialization.
340extern "C" void LLVMInitializeXCoreAsmPrinter() {
341  RegisterAsmPrinter<XCoreAsmPrinter> X(TheXCoreTarget);
342}
343