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