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