1 //===-- XCoreAsmPrinter.cpp - XCore LLVM assembly writer ------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file contains a printer that converts from our internal representation
10 // of machine-dependent LLVM code to the XAS-format XCore assembly language.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #include "MCTargetDesc/XCoreInstPrinter.h"
15 #include "TargetInfo/XCoreTargetInfo.h"
16 #include "XCore.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/MC/TargetRegistry.h"
42 #include "llvm/Support/ErrorHandling.h"
43 #include "llvm/Support/raw_ostream.h"
44 #include "llvm/Target/TargetLoweringObjectFile.h"
45 #include <algorithm>
46 #include <cctype>
47 using namespace llvm;
48 
49 #define DEBUG_TYPE "asm-printer"
50 
51 namespace {
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     StringRef getPassName() const override { return "XCore Assembly Printer"; }
62 
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                          const char *ExtraCode, raw_ostream &O) override;
71     bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNum,
72                                const char *ExtraCode, raw_ostream &O) override;
73 
74     void emitArrayBound(MCSymbol *Sym, const GlobalVariable *GV);
75     void emitGlobalVariable(const GlobalVariable *GV) override;
76 
77     void emitFunctionEntryLabel() override;
78     void emitInstruction(const MachineInstr *MI) override;
79     void emitFunctionBodyStart() override;
80     void emitFunctionBodyEnd() override;
81   };
82 } // end of anonymous namespace
83 
84 XCoreTargetStreamer &XCoreAsmPrinter::getTargetStreamer() {
85   return static_cast<XCoreTargetStreamer&>(*OutStreamer->getTargetStreamer());
86 }
87 
88 void XCoreAsmPrinter::emitArrayBound(MCSymbol *Sym, const GlobalVariable *GV) {
89   assert( ( GV->hasExternalLinkage() || GV->hasWeakLinkage() ||
90             GV->hasLinkOnceLinkage() || GV->hasCommonLinkage() ) &&
91           "Unexpected linkage");
92   if (ArrayType *ATy = dyn_cast<ArrayType>(GV->getValueType())) {
93 
94     MCSymbol *SymGlob = OutContext.getOrCreateSymbol(
95                           Twine(Sym->getName() + StringRef(".globound")));
96     OutStreamer->emitSymbolAttribute(SymGlob, MCSA_Global);
97     OutStreamer->emitAssignment(SymGlob,
98                                 MCConstantExpr::create(ATy->getNumElements(),
99                                                        OutContext));
100     if (GV->hasWeakLinkage() || GV->hasLinkOnceLinkage() ||
101         GV->hasCommonLinkage()) {
102       OutStreamer->emitSymbolAttribute(SymGlob, MCSA_Weak);
103     }
104   }
105 }
106 
107 void XCoreAsmPrinter::emitGlobalVariable(const GlobalVariable *GV) {
108   // Check to see if this is a special global used by LLVM, if so, emit it.
109   if (!GV->hasInitializer() || emitSpecialLLVMGlobal(GV))
110     return;
111 
112   const DataLayout &DL = getDataLayout();
113   OutStreamer->switchSection(getObjFileLowering().SectionForGlobal(GV, TM));
114 
115   MCSymbol *GVSym = getSymbol(GV);
116   const Constant *C = GV->getInitializer();
117   const Align Alignment(DL.getPrefTypeAlignment(C->getType()));
118 
119   // Mark the start of the global
120   getTargetStreamer().emitCCTopData(GVSym->getName());
121 
122   switch (GV->getLinkage()) {
123   case GlobalValue::AppendingLinkage:
124     report_fatal_error("AppendingLinkage is not supported by this target!");
125   case GlobalValue::LinkOnceAnyLinkage:
126   case GlobalValue::LinkOnceODRLinkage:
127   case GlobalValue::WeakAnyLinkage:
128   case GlobalValue::WeakODRLinkage:
129   case GlobalValue::ExternalLinkage:
130   case GlobalValue::CommonLinkage:
131     emitArrayBound(GVSym, GV);
132     OutStreamer->emitSymbolAttribute(GVSym, MCSA_Global);
133 
134     if (GV->hasWeakLinkage() || GV->hasLinkOnceLinkage() ||
135         GV->hasCommonLinkage())
136       OutStreamer->emitSymbolAttribute(GVSym, MCSA_Weak);
137     LLVM_FALLTHROUGH;
138   case GlobalValue::InternalLinkage:
139   case GlobalValue::PrivateLinkage:
140     break;
141   default:
142     llvm_unreachable("Unknown linkage type!");
143   }
144 
145   emitAlignment(std::max(Alignment, Align(4)), GV);
146 
147   if (GV->isThreadLocal()) {
148     report_fatal_error("TLS is not supported by this target!");
149   }
150   unsigned Size = DL.getTypeAllocSize(C->getType());
151   if (MAI->hasDotTypeDotSizeDirective()) {
152     OutStreamer->emitSymbolAttribute(GVSym, MCSA_ELF_TypeObject);
153     OutStreamer->emitELFSize(GVSym, MCConstantExpr::create(Size, OutContext));
154   }
155   OutStreamer->emitLabel(GVSym);
156 
157   emitGlobalConstant(DL, C);
158   // The ABI requires that unsigned scalar types smaller than 32 bits
159   // are padded to 32 bits.
160   if (Size < 4)
161     OutStreamer->emitZeros(4 - Size);
162 
163   // Mark the end of the global
164   getTargetStreamer().emitCCBottomData(GVSym->getName());
165 }
166 
167 void XCoreAsmPrinter::emitFunctionBodyStart() {
168   MCInstLowering.Initialize(&MF->getContext());
169 }
170 
171 /// EmitFunctionBodyEnd - Targets can override this to emit stuff after
172 /// the last basic block in the function.
173 void XCoreAsmPrinter::emitFunctionBodyEnd() {
174   // Emit function end directives
175   getTargetStreamer().emitCCBottomFunction(CurrentFnSym->getName());
176 }
177 
178 void XCoreAsmPrinter::emitFunctionEntryLabel() {
179   // Mark the start of the function
180   getTargetStreamer().emitCCTopFunction(CurrentFnSym->getName());
181   OutStreamer->emitLabel(CurrentFnSym);
182 }
183 
184 void XCoreAsmPrinter::
185 printInlineJT(const MachineInstr *MI, int opNum, raw_ostream &O,
186               const std::string &directive) {
187   unsigned JTI = MI->getOperand(opNum).getIndex();
188   const MachineFunction *MF = MI->getParent()->getParent();
189   const MachineJumpTableInfo *MJTI = MF->getJumpTableInfo();
190   const std::vector<MachineJumpTableEntry> &JT = MJTI->getJumpTables();
191   const std::vector<MachineBasicBlock*> &JTBBs = JT[JTI].MBBs;
192   O << "\t" << directive << " ";
193   for (unsigned i = 0, e = JTBBs.size(); i != e; ++i) {
194     MachineBasicBlock *MBB = JTBBs[i];
195     if (i > 0)
196       O << ",";
197     MBB->getSymbol()->print(O, MAI);
198   }
199 }
200 
201 void XCoreAsmPrinter::printOperand(const MachineInstr *MI, int opNum,
202                                    raw_ostream &O) {
203   const DataLayout &DL = getDataLayout();
204   const MachineOperand &MO = MI->getOperand(opNum);
205   switch (MO.getType()) {
206   case MachineOperand::MO_Register:
207     O << XCoreInstPrinter::getRegisterName(MO.getReg());
208     break;
209   case MachineOperand::MO_Immediate:
210     O << MO.getImm();
211     break;
212   case MachineOperand::MO_MachineBasicBlock:
213     MO.getMBB()->getSymbol()->print(O, MAI);
214     break;
215   case MachineOperand::MO_GlobalAddress:
216     PrintSymbolOperand(MO, O);
217     break;
218   case MachineOperand::MO_ConstantPoolIndex:
219     O << DL.getPrivateGlobalPrefix() << "CPI" << getFunctionNumber() << '_'
220       << MO.getIndex();
221     break;
222   case MachineOperand::MO_BlockAddress:
223     GetBlockAddressSymbol(MO.getBlockAddress())->print(O, MAI);
224     break;
225   default:
226     llvm_unreachable("not implemented");
227   }
228 }
229 
230 /// PrintAsmOperand - Print out an operand for an inline asm expression.
231 ///
232 bool XCoreAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
233                                       const char *ExtraCode, raw_ostream &O) {
234   // Print the operand if there is no operand modifier.
235   if (!ExtraCode || !ExtraCode[0]) {
236     printOperand(MI, OpNo, O);
237     return false;
238   }
239 
240   // Otherwise fallback on the default implementation.
241   return AsmPrinter::PrintAsmOperand(MI, OpNo, ExtraCode, O);
242 }
243 
244 bool XCoreAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,
245                                             unsigned OpNum,
246                                             const char *ExtraCode,
247                                             raw_ostream &O) {
248   if (ExtraCode && ExtraCode[0]) {
249     return true; // Unknown modifier.
250   }
251   printOperand(MI, OpNum, O);
252   O << '[';
253   printOperand(MI, OpNum + 1, O);
254   O << ']';
255   return false;
256 }
257 
258 void XCoreAsmPrinter::emitInstruction(const MachineInstr *MI) {
259   XCore_MC::verifyInstructionPredicates(MI->getOpcode(),
260                                         getSubtargetInfo().getFeatureBits());
261 
262   SmallString<128> Str;
263   raw_svector_ostream O(Str);
264 
265   switch (MI->getOpcode()) {
266   case XCore::DBG_VALUE:
267     llvm_unreachable("Should be handled target independently");
268   case XCore::ADD_2rus:
269     if (MI->getOperand(2).getImm() == 0) {
270       O << "\tmov "
271         << XCoreInstPrinter::getRegisterName(MI->getOperand(0).getReg()) << ", "
272         << XCoreInstPrinter::getRegisterName(MI->getOperand(1).getReg());
273       OutStreamer->emitRawText(O.str());
274       return;
275     }
276     break;
277   case XCore::BR_JT:
278   case XCore::BR_JT32:
279     O << "\tbru "
280       << XCoreInstPrinter::getRegisterName(MI->getOperand(1).getReg()) << '\n';
281     if (MI->getOpcode() == XCore::BR_JT)
282       printInlineJT(MI, 0, O);
283     else
284       printInlineJT32(MI, 0, O);
285     O << '\n';
286     OutStreamer->emitRawText(O.str());
287     return;
288   }
289 
290   MCInst TmpInst;
291   MCInstLowering.Lower(MI, TmpInst);
292 
293   EmitToStreamer(*OutStreamer, TmpInst);
294 }
295 
296 // Force static initialization.
297 extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeXCoreAsmPrinter() {
298   RegisterAsmPrinter<XCoreAsmPrinter> X(getTheXCoreTarget());
299 }
300