XCoreAsmPrinter.cpp revision 3e74d6fdd248e20a280f1dff3da9a6c689c2c4c3
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/MachineModuleInfo.h"
25#include "llvm/CodeGen/MachineFunctionPass.h"
26#include "llvm/CodeGen/MachineConstantPool.h"
27#include "llvm/CodeGen/MachineInstr.h"
28#include "llvm/CodeGen/MachineJumpTableInfo.h"
29#include "llvm/MC/MCAsmInfo.h"
30#include "llvm/MC/MCStreamer.h"
31#include "llvm/MC/MCSymbol.h"
32#include "llvm/Target/Mangler.h"
33#include "llvm/Target/TargetData.h"
34#include "llvm/Target/TargetLoweringObjectFile.h"
35#include "llvm/ADT/SmallString.h"
36#include "llvm/ADT/StringExtras.h"
37#include "llvm/Support/CommandLine.h"
38#include "llvm/Support/ErrorHandling.h"
39#include "llvm/Support/TargetRegistry.h"
40#include "llvm/Support/raw_ostream.h"
41#include <algorithm>
42#include <cctype>
43using namespace llvm;
44
45static cl::opt<unsigned> MaxThreads("xcore-max-threads", cl::Optional,
46  cl::desc("Maximum number of threads (for emulation thread-local storage)"),
47  cl::Hidden,
48  cl::value_desc("number"),
49  cl::init(8));
50
51namespace {
52  class XCoreAsmPrinter : public AsmPrinter {
53    const XCoreSubtarget &Subtarget;
54  public:
55    explicit XCoreAsmPrinter(TargetMachine &TM, MCStreamer &Streamer)
56      : AsmPrinter(TM, Streamer), Subtarget(TM.getSubtarget<XCoreSubtarget>()){}
57
58    virtual const char *getPassName() const {
59      return "XCore Assembly Printer";
60    }
61
62    void printMemOperand(const MachineInstr *MI, int opNum, raw_ostream &O);
63    void printInlineJT(const MachineInstr *MI, int opNum, raw_ostream &O,
64                       const std::string &directive = ".jmptable");
65    void printInlineJT32(const MachineInstr *MI, int opNum, raw_ostream &O) {
66      printInlineJT(MI, opNum, O, ".jmptable32");
67    }
68    void printOperand(const MachineInstr *MI, int opNum, raw_ostream &O);
69    bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
70                         unsigned AsmVariant, const char *ExtraCode,
71                         raw_ostream &O);
72
73    void emitArrayBound(MCSymbol *Sym, const GlobalVariable *GV);
74    virtual void EmitGlobalVariable(const GlobalVariable *GV);
75
76    void printInstruction(const MachineInstr *MI, raw_ostream &O); // autogen'd.
77    static const char *getRegisterName(unsigned RegNo);
78
79    void EmitFunctionEntryLabel();
80    void EmitInstruction(const MachineInstr *MI);
81    void EmitFunctionBodyEnd();
82  };
83} // end of anonymous namespace
84
85#include "XCoreGenAsmWriter.inc"
86
87void XCoreAsmPrinter::emitArrayBound(MCSymbol *Sym, const GlobalVariable *GV) {
88  assert(((GV->hasExternalLinkage() ||
89    GV->hasWeakLinkage()) ||
90    GV->hasLinkOnceLinkage()) && "Unexpected linkage");
91  if (ArrayType *ATy = dyn_cast<ArrayType>(
92    cast<PointerType>(GV->getType())->getElementType())) {
93    OutStreamer.EmitSymbolAttribute(Sym, MCSA_Global);
94    // FIXME: MCStreamerize.
95    OutStreamer.EmitRawText(StringRef(".globound"));
96    OutStreamer.EmitRawText("\t.set\t" + Twine(Sym->getName()));
97    OutStreamer.EmitRawText(".globound," + Twine(ATy->getNumElements()));
98    if (GV->hasWeakLinkage() || GV->hasLinkOnceLinkage()) {
99      // TODO Use COMDAT groups for LinkOnceLinkage
100      OutStreamer.EmitRawText(MAI->getWeakDefDirective() +Twine(Sym->getName())+
101                              ".globound");
102    }
103  }
104}
105
106void XCoreAsmPrinter::EmitGlobalVariable(const GlobalVariable *GV) {
107  // Check to see if this is a special global used by LLVM, if so, emit it.
108  if (!GV->hasInitializer() ||
109      EmitSpecialLLVMGlobal(GV))
110    return;
111
112  const TargetData *TD = TM.getTargetData();
113  OutStreamer.SwitchSection(getObjFileLowering().SectionForGlobal(GV, Mang,TM));
114
115
116  MCSymbol *GVSym = Mang->getSymbol(GV);
117  const Constant *C = GV->getInitializer();
118  unsigned Align = (unsigned)TD->getPreferredTypeAlignmentShift(C->getType());
119
120  // Mark the start of the global
121  OutStreamer.EmitRawText("\t.cc_top " + Twine(GVSym->getName()) + ".data," +
122                          GVSym->getName());
123
124  switch (GV->getLinkage()) {
125  case GlobalValue::AppendingLinkage:
126    report_fatal_error("AppendingLinkage is not supported by this target!");
127  case GlobalValue::LinkOnceAnyLinkage:
128  case GlobalValue::LinkOnceODRLinkage:
129  case GlobalValue::WeakAnyLinkage:
130  case GlobalValue::WeakODRLinkage:
131  case GlobalValue::ExternalLinkage:
132    emitArrayBound(GVSym, GV);
133    OutStreamer.EmitSymbolAttribute(GVSym, MCSA_Global);
134
135    // TODO Use COMDAT groups for LinkOnceLinkage
136    if (GV->hasWeakLinkage() || GV->hasLinkOnceLinkage())
137      OutStreamer.EmitSymbolAttribute(GVSym, MCSA_Weak);
138    // FALL THROUGH
139  case GlobalValue::InternalLinkage:
140  case GlobalValue::PrivateLinkage:
141    break;
142  case GlobalValue::DLLImportLinkage:
143    llvm_unreachable("DLLImport linkage is not supported by this target!");
144  case GlobalValue::DLLExportLinkage:
145    llvm_unreachable("DLLExport linkage is not supported by this target!");
146  default:
147    llvm_unreachable("Unknown linkage type!");
148  }
149
150  EmitAlignment(Align > 2 ? Align : 2, GV);
151
152  unsigned Size = TD->getTypeAllocSize(C->getType());
153  if (GV->isThreadLocal()) {
154    Size *= MaxThreads;
155  }
156  if (MAI->hasDotTypeDotSizeDirective()) {
157    OutStreamer.EmitSymbolAttribute(GVSym, MCSA_ELF_TypeObject);
158    OutStreamer.EmitRawText("\t.size " + Twine(GVSym->getName()) + "," +
159                            Twine(Size));
160  }
161  OutStreamer.EmitLabel(GVSym);
162
163  EmitGlobalConstant(C);
164  if (GV->isThreadLocal()) {
165    for (unsigned i = 1; i < MaxThreads; ++i)
166      EmitGlobalConstant(C);
167  }
168  // The ABI requires that unsigned scalar types smaller than 32 bits
169  // are padded to 32 bits.
170  if (Size < 4)
171    OutStreamer.EmitZeros(4 - Size, 0);
172
173  // Mark the end of the global
174  OutStreamer.EmitRawText("\t.cc_bottom " + Twine(GVSym->getName()) + ".data");
175}
176
177/// EmitFunctionBodyEnd - Targets can override this to emit stuff after
178/// the last basic block in the function.
179void XCoreAsmPrinter::EmitFunctionBodyEnd() {
180  // Emit function end directives
181  OutStreamer.EmitRawText("\t.cc_bottom " + Twine(CurrentFnSym->getName()) +
182                          ".function");
183}
184
185void XCoreAsmPrinter::EmitFunctionEntryLabel() {
186  // Mark the start of the function
187  OutStreamer.EmitRawText("\t.cc_top " + Twine(CurrentFnSym->getName()) +
188                          ".function," + CurrentFnSym->getName());
189  OutStreamer.EmitLabel(CurrentFnSym);
190}
191
192void XCoreAsmPrinter::printMemOperand(const MachineInstr *MI, int opNum,
193                                      raw_ostream &O) {
194  printOperand(MI, opNum, O);
195
196  if (MI->getOperand(opNum+1).isImm() && MI->getOperand(opNum+1).getImm() == 0)
197    return;
198
199  O << "+";
200  printOperand(MI, opNum+1, O);
201}
202
203void XCoreAsmPrinter::
204printInlineJT(const MachineInstr *MI, int opNum, raw_ostream &O,
205              const std::string &directive) {
206  unsigned JTI = MI->getOperand(opNum).getIndex();
207  const MachineFunction *MF = MI->getParent()->getParent();
208  const MachineJumpTableInfo *MJTI = MF->getJumpTableInfo();
209  const std::vector<MachineJumpTableEntry> &JT = MJTI->getJumpTables();
210  const std::vector<MachineBasicBlock*> &JTBBs = JT[JTI].MBBs;
211  O << "\t" << directive << " ";
212  for (unsigned i = 0, e = JTBBs.size(); i != e; ++i) {
213    MachineBasicBlock *MBB = JTBBs[i];
214    if (i > 0)
215      O << ",";
216    O << *MBB->getSymbol();
217  }
218}
219
220void XCoreAsmPrinter::printOperand(const MachineInstr *MI, int opNum,
221                                   raw_ostream &O) {
222  const MachineOperand &MO = MI->getOperand(opNum);
223  switch (MO.getType()) {
224  case MachineOperand::MO_Register:
225    O << getRegisterName(MO.getReg());
226    break;
227  case MachineOperand::MO_Immediate:
228    O << MO.getImm();
229    break;
230  case MachineOperand::MO_MachineBasicBlock:
231    O << *MO.getMBB()->getSymbol();
232    break;
233  case MachineOperand::MO_GlobalAddress:
234    O << *Mang->getSymbol(MO.getGlobal());
235    break;
236  case MachineOperand::MO_ExternalSymbol:
237    O << MO.getSymbolName();
238    break;
239  case MachineOperand::MO_ConstantPoolIndex:
240    O << MAI->getPrivateGlobalPrefix() << "CPI" << getFunctionNumber()
241      << '_' << MO.getIndex();
242    break;
243  case MachineOperand::MO_JumpTableIndex:
244    O << MAI->getPrivateGlobalPrefix() << "JTI" << getFunctionNumber()
245      << '_' << MO.getIndex();
246    break;
247  case MachineOperand::MO_BlockAddress:
248    O << *GetBlockAddressSymbol(MO.getBlockAddress());
249    break;
250  default:
251    llvm_unreachable("not implemented");
252  }
253}
254
255/// PrintAsmOperand - Print out an operand for an inline asm expression.
256///
257bool XCoreAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
258                                      unsigned AsmVariant,const char *ExtraCode,
259                                      raw_ostream &O) {
260  printOperand(MI, OpNo, O);
261  return false;
262}
263
264void XCoreAsmPrinter::EmitInstruction(const MachineInstr *MI) {
265  SmallString<128> Str;
266  raw_svector_ostream O(Str);
267
268  // Check for mov mnemonic
269  if (MI->getOpcode() == XCore::ADD_2rus && !MI->getOperand(2).getImm())
270    O << "\tmov " << getRegisterName(MI->getOperand(0).getReg()) << ", "
271      << getRegisterName(MI->getOperand(1).getReg());
272  else
273    printInstruction(MI, O);
274  OutStreamer.EmitRawText(O.str());
275}
276
277// Force static initialization.
278extern "C" void LLVMInitializeXCoreAsmPrinter() {
279  RegisterAsmPrinter<XCoreAsmPrinter> X(TheXCoreTarget);
280}
281