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/DebugInfo.h"
22#include "llvm/DerivedTypes.h"
23#include "llvm/Module.h"
24#include "llvm/CodeGen/AsmPrinter.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/CodeGen/MachineJumpTableInfo.h"
30#include "llvm/MC/MCAsmInfo.h"
31#include "llvm/MC/MCStreamer.h"
32#include "llvm/MC/MCSymbol.h"
33#include "llvm/Target/Mangler.h"
34#include "llvm/Target/TargetData.h"
35#include "llvm/Target/TargetLoweringObjectFile.h"
36#include "llvm/ADT/SmallString.h"
37#include "llvm/ADT/StringExtras.h"
38#include "llvm/Support/CommandLine.h"
39#include "llvm/Support/ErrorHandling.h"
40#include "llvm/Support/TargetRegistry.h"
41#include "llvm/Support/raw_ostream.h"
42#include <algorithm>
43#include <cctype>
44using namespace llvm;
45
46static cl::opt<unsigned> MaxThreads("xcore-max-threads", cl::Optional,
47  cl::desc("Maximum number of threads (for emulation thread-local storage)"),
48  cl::Hidden,
49  cl::value_desc("number"),
50  cl::init(8));
51
52namespace {
53  class XCoreAsmPrinter : public AsmPrinter {
54    const XCoreSubtarget &Subtarget;
55    void PrintDebugValueComment(const MachineInstr *MI, raw_ostream &OS);
56  public:
57    explicit XCoreAsmPrinter(TargetMachine &TM, MCStreamer &Streamer)
58      : AsmPrinter(TM, Streamer), 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, raw_ostream &O);
65    void printInlineJT(const MachineInstr *MI, int opNum, raw_ostream &O,
66                       const std::string &directive = ".jmptable");
67    void printInlineJT32(const MachineInstr *MI, int opNum, raw_ostream &O) {
68      printInlineJT(MI, opNum, O, ".jmptable32");
69    }
70    void printOperand(const MachineInstr *MI, int opNum, raw_ostream &O);
71    bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
72                         unsigned AsmVariant, const char *ExtraCode,
73                         raw_ostream &O);
74
75    void emitArrayBound(MCSymbol *Sym, const GlobalVariable *GV);
76    virtual void EmitGlobalVariable(const GlobalVariable *GV);
77
78    void printInstruction(const MachineInstr *MI, raw_ostream &O); // autogen'd.
79    static const char *getRegisterName(unsigned RegNo);
80
81    void EmitFunctionEntryLabel();
82    void EmitInstruction(const MachineInstr *MI);
83    void EmitFunctionBodyEnd();
84    virtual MachineLocation getDebugValueLocation(const MachineInstr *MI) const;
85  };
86} // end of anonymous namespace
87
88#include "XCoreGenAsmWriter.inc"
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 TargetData *TD = TM.getTargetData();
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, 0);
175
176  // Mark the end of the global
177  OutStreamer.EmitRawText("\t.cc_bottom " + Twine(GVSym->getName()) + ".data");
178}
179
180/// EmitFunctionBodyEnd - Targets can override this to emit stuff after
181/// the last basic block in the function.
182void XCoreAsmPrinter::EmitFunctionBodyEnd() {
183  // Emit function end directives
184  OutStreamer.EmitRawText("\t.cc_bottom " + Twine(CurrentFnSym->getName()) +
185                          ".function");
186}
187
188void XCoreAsmPrinter::EmitFunctionEntryLabel() {
189  // Mark the start of the function
190  OutStreamer.EmitRawText("\t.cc_top " + Twine(CurrentFnSym->getName()) +
191                          ".function," + CurrentFnSym->getName());
192  OutStreamer.EmitLabel(CurrentFnSym);
193}
194
195void XCoreAsmPrinter::printMemOperand(const MachineInstr *MI, int opNum,
196                                      raw_ostream &O) {
197  printOperand(MI, opNum, O);
198
199  if (MI->getOperand(opNum+1).isImm() && MI->getOperand(opNum+1).getImm() == 0)
200    return;
201
202  O << "+";
203  printOperand(MI, opNum+1, O);
204}
205
206void XCoreAsmPrinter::
207printInlineJT(const MachineInstr *MI, int opNum, raw_ostream &O,
208              const std::string &directive) {
209  unsigned JTI = MI->getOperand(opNum).getIndex();
210  const MachineFunction *MF = MI->getParent()->getParent();
211  const MachineJumpTableInfo *MJTI = MF->getJumpTableInfo();
212  const std::vector<MachineJumpTableEntry> &JT = MJTI->getJumpTables();
213  const std::vector<MachineBasicBlock*> &JTBBs = JT[JTI].MBBs;
214  O << "\t" << directive << " ";
215  for (unsigned i = 0, e = JTBBs.size(); i != e; ++i) {
216    MachineBasicBlock *MBB = JTBBs[i];
217    if (i > 0)
218      O << ",";
219    O << *MBB->getSymbol();
220  }
221}
222
223void XCoreAsmPrinter::printOperand(const MachineInstr *MI, int opNum,
224                                   raw_ostream &O) {
225  const MachineOperand &MO = MI->getOperand(opNum);
226  switch (MO.getType()) {
227  case MachineOperand::MO_Register:
228    O << getRegisterName(MO.getReg());
229    break;
230  case MachineOperand::MO_Immediate:
231    O << MO.getImm();
232    break;
233  case MachineOperand::MO_MachineBasicBlock:
234    O << *MO.getMBB()->getSymbol();
235    break;
236  case MachineOperand::MO_GlobalAddress:
237    O << *Mang->getSymbol(MO.getGlobal());
238    break;
239  case MachineOperand::MO_ExternalSymbol:
240    O << MO.getSymbolName();
241    break;
242  case MachineOperand::MO_ConstantPoolIndex:
243    O << MAI->getPrivateGlobalPrefix() << "CPI" << getFunctionNumber()
244      << '_' << MO.getIndex();
245    break;
246  case MachineOperand::MO_JumpTableIndex:
247    O << MAI->getPrivateGlobalPrefix() << "JTI" << getFunctionNumber()
248      << '_' << MO.getIndex();
249    break;
250  case MachineOperand::MO_BlockAddress:
251    O << *GetBlockAddressSymbol(MO.getBlockAddress());
252    break;
253  default:
254    llvm_unreachable("not implemented");
255  }
256}
257
258/// PrintAsmOperand - Print out an operand for an inline asm expression.
259///
260bool XCoreAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
261                                      unsigned AsmVariant,const char *ExtraCode,
262                                      raw_ostream &O) {
263  // Does this asm operand have a single letter operand modifier?
264  if (ExtraCode && ExtraCode[0])
265    if (ExtraCode[1] != 0) return true; // Unknown modifier.
266
267    switch (ExtraCode[0]) {
268    default:
269      // See if this is a generic print operand
270      return AsmPrinter::PrintAsmOperand(MI, OpNo, AsmVariant, ExtraCode, O);
271    }
272
273printOperand(MI, OpNo, O);
274  return false;
275}
276
277void XCoreAsmPrinter::PrintDebugValueComment(const MachineInstr *MI,
278                                             raw_ostream &OS) {
279  unsigned NOps = MI->getNumOperands();
280  assert(NOps == 4);
281  OS << '\t' << MAI->getCommentString() << "DEBUG_VALUE: ";
282  // cast away const; DIetc do not take const operands for some reason.
283  DIVariable V(const_cast<MDNode *>(MI->getOperand(NOps-1).getMetadata()));
284  OS << V.getName();
285  OS << " <- ";
286  // Frame address.  Currently handles register +- offset only.
287  assert(MI->getOperand(0).isReg() && MI->getOperand(1).isImm());
288  OS << '['; printOperand(MI, 0, OS); OS << '+'; printOperand(MI, 1, OS);
289  OS << ']';
290  OS << "+";
291  printOperand(MI, NOps-2, OS);
292}
293
294MachineLocation XCoreAsmPrinter::
295getDebugValueLocation(const MachineInstr *MI) const {
296  // Handles frame addresses emitted in XCoreInstrInfo::emitFrameIndexDebugValue.
297  assert(MI->getNumOperands() == 4 && "Invalid no. of machine operands!");
298  assert(MI->getOperand(0).isReg() && MI->getOperand(1).isImm() &&
299         "Unexpected MachineOperand types");
300  return MachineLocation(MI->getOperand(0).getReg(),
301                         MI->getOperand(1).getImm());
302}
303
304void XCoreAsmPrinter::EmitInstruction(const MachineInstr *MI) {
305  SmallString<128> Str;
306  raw_svector_ostream O(Str);
307
308  switch (MI->getOpcode()) {
309  case XCore::DBG_VALUE: {
310    if (isVerbose() && OutStreamer.hasRawTextSupport()) {
311      SmallString<128> TmpStr;
312      raw_svector_ostream OS(TmpStr);
313      PrintDebugValueComment(MI, OS);
314      OutStreamer.EmitRawText(StringRef(OS.str()));
315    }
316    return;
317  }
318  case XCore::ADD_2rus:
319    if (MI->getOperand(2).getImm() == 0) {
320      O << "\tmov " << getRegisterName(MI->getOperand(0).getReg()) << ", "
321        << getRegisterName(MI->getOperand(1).getReg());
322      OutStreamer.EmitRawText(O.str());
323      return;
324    }
325    break;
326  }
327  printInstruction(MI, O);
328  OutStreamer.EmitRawText(O.str());
329}
330
331// Force static initialization.
332extern "C" void LLVMInitializeXCoreAsmPrinter() {
333  RegisterAsmPrinter<XCoreAsmPrinter> X(TheXCoreTarget);
334}
335