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#include "XCore.h"
16#include "InstPrinter/XCoreInstPrinter.h"
17#include "XCoreInstrInfo.h"
18#include "XCoreMCInstLower.h"
19#include "XCoreSubtarget.h"
20#include "XCoreTargetMachine.h"
21#include "XCoreTargetStreamer.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/IR/Constants.h"
31#include "llvm/IR/DataLayout.h"
32#include "llvm/IR/DebugInfo.h"
33#include "llvm/IR/DerivedTypes.h"
34#include "llvm/IR/Mangler.h"
35#include "llvm/IR/Module.h"
36#include "llvm/MC/MCAsmInfo.h"
37#include "llvm/MC/MCExpr.h"
38#include "llvm/MC/MCInst.h"
39#include "llvm/MC/MCStreamer.h"
40#include "llvm/MC/MCSymbol.h"
41#include "llvm/Support/ErrorHandling.h"
42#include "llvm/Support/TargetRegistry.h"
43#include "llvm/Support/raw_ostream.h"
44#include "llvm/Target/TargetLoweringObjectFile.h"
45#include <algorithm>
46#include <cctype>
47using namespace llvm;
48
49#define DEBUG_TYPE "asm-printer"
50
51namespace {
52  class XCoreAsmPrinter : public AsmPrinter {
53    const XCoreSubtarget &Subtarget;
54    XCoreMCInstLower MCInstLowering;
55    XCoreTargetStreamer &getTargetStreamer();
56
57  public:
58    explicit XCoreAsmPrinter(TargetMachine &TM, MCStreamer &Streamer)
59      : AsmPrinter(TM, Streamer), Subtarget(TM.getSubtarget<XCoreSubtarget>()),
60        MCInstLowering(*this) {}
61
62    const char *getPassName() const override {
63      return "XCore Assembly Printer";
64    }
65
66    void printInlineJT(const MachineInstr *MI, int opNum, raw_ostream &O,
67                       const std::string &directive = ".jmptable");
68    void printInlineJT32(const MachineInstr *MI, int opNum, raw_ostream &O) {
69      printInlineJT(MI, opNum, O, ".jmptable32");
70    }
71    void printOperand(const MachineInstr *MI, int opNum, raw_ostream &O);
72    bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
73                         unsigned AsmVariant, const char *ExtraCode,
74                         raw_ostream &O) override;
75    bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNum,
76                               unsigned AsmVariant, const char *ExtraCode,
77                               raw_ostream &O) override;
78
79    void emitArrayBound(MCSymbol *Sym, const GlobalVariable *GV);
80    void EmitGlobalVariable(const GlobalVariable *GV) override;
81
82    void EmitFunctionEntryLabel() override;
83    void EmitInstruction(const MachineInstr *MI) override;
84    void EmitFunctionBodyStart() override;
85    void EmitFunctionBodyEnd() override;
86  };
87} // end of anonymous namespace
88
89XCoreTargetStreamer &XCoreAsmPrinter::getTargetStreamer() {
90  return static_cast<XCoreTargetStreamer&>(*OutStreamer.getTargetStreamer());
91}
92
93void XCoreAsmPrinter::emitArrayBound(MCSymbol *Sym, const GlobalVariable *GV) {
94  assert( ( GV->hasExternalLinkage() || GV->hasWeakLinkage() ||
95            GV->hasLinkOnceLinkage() || GV->hasCommonLinkage() ) &&
96          "Unexpected linkage");
97  if (ArrayType *ATy = dyn_cast<ArrayType>(
98                        cast<PointerType>(GV->getType())->getElementType())) {
99
100    MCSymbol *SymGlob = OutContext.GetOrCreateSymbol(
101                          Twine(Sym->getName() + StringRef(".globound")));
102    OutStreamer.EmitSymbolAttribute(SymGlob, MCSA_Global);
103    OutStreamer.EmitAssignment(SymGlob,
104                               MCConstantExpr::Create(ATy->getNumElements(),
105                                                      OutContext));
106    if (GV->hasWeakLinkage() || GV->hasLinkOnceLinkage() ||
107        GV->hasCommonLinkage()) {
108      // TODO Use COMDAT groups for LinkOnceLinkage
109      OutStreamer.EmitSymbolAttribute(SymGlob, MCSA_Weak);
110    }
111  }
112}
113
114void XCoreAsmPrinter::EmitGlobalVariable(const GlobalVariable *GV) {
115  // Check to see if this is a special global used by LLVM, if so, emit it.
116  if (!GV->hasInitializer() ||
117      EmitSpecialLLVMGlobal(GV))
118    return;
119
120  const DataLayout *TD = TM.getDataLayout();
121  OutStreamer.SwitchSection(
122      getObjFileLowering().SectionForGlobal(GV, *Mang, TM));
123
124  MCSymbol *GVSym = getSymbol(GV);
125  const Constant *C = GV->getInitializer();
126  unsigned Align = (unsigned)TD->getPreferredTypeAlignmentShift(C->getType());
127
128  // Mark the start of the global
129  getTargetStreamer().emitCCTopData(GVSym->getName());
130
131  switch (GV->getLinkage()) {
132  case GlobalValue::AppendingLinkage:
133    report_fatal_error("AppendingLinkage is not supported by this target!");
134  case GlobalValue::LinkOnceAnyLinkage:
135  case GlobalValue::LinkOnceODRLinkage:
136  case GlobalValue::WeakAnyLinkage:
137  case GlobalValue::WeakODRLinkage:
138  case GlobalValue::ExternalLinkage:
139  case GlobalValue::CommonLinkage:
140    emitArrayBound(GVSym, GV);
141    OutStreamer.EmitSymbolAttribute(GVSym, MCSA_Global);
142
143    // TODO Use COMDAT groups for LinkOnceLinkage
144    if (GV->hasWeakLinkage() || GV->hasLinkOnceLinkage() ||
145        GV->hasCommonLinkage())
146      OutStreamer.EmitSymbolAttribute(GVSym, MCSA_Weak);
147    // FALL THROUGH
148  case GlobalValue::InternalLinkage:
149  case GlobalValue::PrivateLinkage:
150    break;
151  default:
152    llvm_unreachable("Unknown linkage type!");
153  }
154
155  EmitAlignment(Align > 2 ? Align : 2, GV);
156
157  if (GV->isThreadLocal()) {
158    report_fatal_error("TLS is not supported by this target!");
159  }
160  unsigned Size = TD->getTypeAllocSize(C->getType());
161  if (MAI->hasDotTypeDotSizeDirective()) {
162    OutStreamer.EmitSymbolAttribute(GVSym, MCSA_ELF_TypeObject);
163    OutStreamer.EmitELFSize(GVSym, MCConstantExpr::Create(Size, OutContext));
164  }
165  OutStreamer.EmitLabel(GVSym);
166
167  EmitGlobalConstant(C);
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);
172
173  // Mark the end of the global
174  getTargetStreamer().emitCCBottomData(GVSym->getName());
175}
176
177void XCoreAsmPrinter::EmitFunctionBodyStart() {
178  MCInstLowering.Initialize(Mang, &MF->getContext());
179}
180
181/// EmitFunctionBodyEnd - Targets can override this to emit stuff after
182/// the last basic block in the function.
183void XCoreAsmPrinter::EmitFunctionBodyEnd() {
184  // Emit function end directives
185  getTargetStreamer().emitCCBottomFunction(CurrentFnSym->getName());
186}
187
188void XCoreAsmPrinter::EmitFunctionEntryLabel() {
189  // Mark the start of the function
190  getTargetStreamer().emitCCTopFunction(CurrentFnSym->getName());
191  OutStreamer.EmitLabel(CurrentFnSym);
192}
193
194void XCoreAsmPrinter::
195printInlineJT(const MachineInstr *MI, int opNum, raw_ostream &O,
196              const std::string &directive) {
197  unsigned JTI = MI->getOperand(opNum).getIndex();
198  const MachineFunction *MF = MI->getParent()->getParent();
199  const MachineJumpTableInfo *MJTI = MF->getJumpTableInfo();
200  const std::vector<MachineJumpTableEntry> &JT = MJTI->getJumpTables();
201  const std::vector<MachineBasicBlock*> &JTBBs = JT[JTI].MBBs;
202  O << "\t" << directive << " ";
203  for (unsigned i = 0, e = JTBBs.size(); i != e; ++i) {
204    MachineBasicBlock *MBB = JTBBs[i];
205    if (i > 0)
206      O << ",";
207    O << *MBB->getSymbol();
208  }
209}
210
211void XCoreAsmPrinter::printOperand(const MachineInstr *MI, int opNum,
212                                   raw_ostream &O) {
213  const DataLayout *DL = TM.getDataLayout();
214  const MachineOperand &MO = MI->getOperand(opNum);
215  switch (MO.getType()) {
216  case MachineOperand::MO_Register:
217    O << XCoreInstPrinter::getRegisterName(MO.getReg());
218    break;
219  case MachineOperand::MO_Immediate:
220    O << MO.getImm();
221    break;
222  case MachineOperand::MO_MachineBasicBlock:
223    O << *MO.getMBB()->getSymbol();
224    break;
225  case MachineOperand::MO_GlobalAddress:
226    O << *getSymbol(MO.getGlobal());
227    break;
228  case MachineOperand::MO_ConstantPoolIndex:
229    O << DL->getPrivateGlobalPrefix() << "CPI" << 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
255bool XCoreAsmPrinter::
256PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNum,
257                      unsigned AsmVariant, const char *ExtraCode,
258                      raw_ostream &O) {
259  if (ExtraCode && ExtraCode[0]) {
260    return true; // Unknown modifier.
261  }
262  printOperand(MI, OpNum, O);
263  O << '[';
264  printOperand(MI, OpNum + 1, O);
265  O << ']';
266  return false;
267}
268
269void XCoreAsmPrinter::EmitInstruction(const MachineInstr *MI) {
270  SmallString<128> Str;
271  raw_svector_ostream O(Str);
272
273  switch (MI->getOpcode()) {
274  case XCore::DBG_VALUE:
275    llvm_unreachable("Should be handled target independently");
276  case XCore::ADD_2rus:
277    if (MI->getOperand(2).getImm() == 0) {
278      O << "\tmov "
279        << XCoreInstPrinter::getRegisterName(MI->getOperand(0).getReg()) << ", "
280        << XCoreInstPrinter::getRegisterName(MI->getOperand(1).getReg());
281      OutStreamer.EmitRawText(O.str());
282      return;
283    }
284    break;
285  case XCore::BR_JT:
286  case XCore::BR_JT32:
287    O << "\tbru "
288      << XCoreInstPrinter::getRegisterName(MI->getOperand(1).getReg()) << '\n';
289    if (MI->getOpcode() == XCore::BR_JT)
290      printInlineJT(MI, 0, O);
291    else
292      printInlineJT32(MI, 0, O);
293    O << '\n';
294    OutStreamer.EmitRawText(O.str());
295    return;
296  }
297
298  MCInst TmpInst;
299  MCInstLowering.Lower(MI, TmpInst);
300
301  EmitToStreamer(OutStreamer, TmpInst);
302}
303
304// Force static initialization.
305extern "C" void LLVMInitializeXCoreAsmPrinter() {
306  RegisterAsmPrinter<XCoreAsmPrinter> X(TheXCoreTarget);
307}
308