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