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 "MCTargetDesc/XCoreTargetStreamer.h" |
16 | #include "TargetInfo/XCoreTargetInfo.h" |
17 | #include "XCore.h" |
18 | #include "XCoreMCInstLower.h" |
19 | #include "XCoreSubtarget.h" |
20 | #include "XCoreTargetMachine.h" |
21 | #include "llvm/ADT/SmallString.h" |
22 | #include "llvm/ADT/StringExtras.h" |
23 | #include "llvm/CodeGen/AsmPrinter.h" |
24 | #include "llvm/CodeGen/MachineConstantPool.h" |
25 | #include "llvm/CodeGen/MachineInstr.h" |
26 | #include "llvm/CodeGen/MachineJumpTableInfo.h" |
27 | #include "llvm/CodeGen/MachineModuleInfo.h" |
28 | #include "llvm/IR/DataLayout.h" |
29 | #include "llvm/IR/DerivedTypes.h" |
30 | #include "llvm/IR/Mangler.h" |
31 | #include "llvm/MC/MCAsmInfo.h" |
32 | #include "llvm/MC/MCExpr.h" |
33 | #include "llvm/MC/MCInst.h" |
34 | #include "llvm/MC/MCStreamer.h" |
35 | #include "llvm/MC/TargetRegistry.h" |
36 | #include "llvm/Support/Compiler.h" |
37 | #include "llvm/Support/ErrorHandling.h" |
38 | #include "llvm/Support/raw_ostream.h" |
39 | #include "llvm/Target/TargetLoweringObjectFile.h" |
40 | #include <algorithm> |
41 | #include <cctype> |
42 | using namespace llvm; |
43 | |
44 | #define DEBUG_TYPE "asm-printer" |
45 | |
46 | namespace { |
47 | class XCoreAsmPrinter : public AsmPrinter { |
48 | XCoreMCInstLower MCInstLowering; |
49 | XCoreTargetStreamer &getTargetStreamer(); |
50 | |
51 | public: |
52 | static char ID; |
53 | |
54 | explicit XCoreAsmPrinter(TargetMachine &TM, |
55 | std::unique_ptr<MCStreamer> Streamer) |
56 | : AsmPrinter(TM, std::move(Streamer), ID), MCInstLowering(*this) {} |
57 | |
58 | StringRef getPassName() const override { return "XCore Assembly Printer" ; } |
59 | |
60 | void printInlineJT(const MachineInstr *MI, int opNum, raw_ostream &O, |
61 | const std::string &directive = ".jmptable" ); |
62 | void printInlineJT32(const MachineInstr *MI, int opNum, raw_ostream &O) { |
63 | printInlineJT(MI, opNum, O, directive: ".jmptable32" ); |
64 | } |
65 | void printOperand(const MachineInstr *MI, int opNum, raw_ostream &O); |
66 | bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, |
67 | const char *, raw_ostream &O) override; |
68 | bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNum, |
69 | const char *, raw_ostream &O) override; |
70 | |
71 | void emitArrayBound(MCSymbol *Sym, const GlobalVariable *GV); |
72 | void emitGlobalVariable(const GlobalVariable *GV) override; |
73 | |
74 | void emitFunctionEntryLabel() override; |
75 | void emitInstruction(const MachineInstr *MI) override; |
76 | void emitFunctionBodyStart() override; |
77 | void emitFunctionBodyEnd() override; |
78 | }; |
79 | } // end of anonymous namespace |
80 | |
81 | XCoreTargetStreamer &XCoreAsmPrinter::getTargetStreamer() { |
82 | return static_cast<XCoreTargetStreamer&>(*OutStreamer->getTargetStreamer()); |
83 | } |
84 | |
85 | void XCoreAsmPrinter::emitArrayBound(MCSymbol *Sym, const GlobalVariable *GV) { |
86 | assert( ( GV->hasExternalLinkage() || GV->hasWeakLinkage() || |
87 | GV->hasLinkOnceLinkage() || GV->hasCommonLinkage() ) && |
88 | "Unexpected linkage" ); |
89 | if (ArrayType *ATy = dyn_cast<ArrayType>(Val: GV->getValueType())) { |
90 | |
91 | MCSymbol *SymGlob = OutContext.getOrCreateSymbol( |
92 | Name: Twine(Sym->getName() + StringRef(".globound" ))); |
93 | OutStreamer->emitSymbolAttribute(Symbol: SymGlob, Attribute: MCSA_Global); |
94 | OutStreamer->emitAssignment(Symbol: SymGlob, |
95 | Value: MCConstantExpr::create(Value: ATy->getNumElements(), |
96 | Ctx&: OutContext)); |
97 | if (GV->hasWeakLinkage() || GV->hasLinkOnceLinkage() || |
98 | GV->hasCommonLinkage()) { |
99 | OutStreamer->emitSymbolAttribute(Symbol: SymGlob, Attribute: MCSA_Weak); |
100 | } |
101 | } |
102 | } |
103 | |
104 | void XCoreAsmPrinter::emitGlobalVariable(const GlobalVariable *GV) { |
105 | // Check to see if this is a special global used by LLVM, if so, emit it. |
106 | if (!GV->hasInitializer() || emitSpecialLLVMGlobal(GV)) |
107 | return; |
108 | |
109 | const DataLayout &DL = getDataLayout(); |
110 | OutStreamer->switchSection(Section: getObjFileLowering().SectionForGlobal(GO: GV, TM)); |
111 | |
112 | MCSymbol *GVSym = getSymbol(GV); |
113 | const Constant *C = GV->getInitializer(); |
114 | const Align Alignment = DL.getPrefTypeAlign(Ty: C->getType()); |
115 | |
116 | // Mark the start of the global |
117 | getTargetStreamer().emitCCTopData(Name: GVSym->getName()); |
118 | |
119 | switch (GV->getLinkage()) { |
120 | case GlobalValue::AppendingLinkage: |
121 | report_fatal_error(reason: "AppendingLinkage is not supported by this target!" ); |
122 | case GlobalValue::LinkOnceAnyLinkage: |
123 | case GlobalValue::LinkOnceODRLinkage: |
124 | case GlobalValue::WeakAnyLinkage: |
125 | case GlobalValue::WeakODRLinkage: |
126 | case GlobalValue::ExternalLinkage: |
127 | case GlobalValue::CommonLinkage: |
128 | emitArrayBound(Sym: GVSym, GV); |
129 | OutStreamer->emitSymbolAttribute(Symbol: GVSym, Attribute: MCSA_Global); |
130 | |
131 | if (GV->hasWeakLinkage() || GV->hasLinkOnceLinkage() || |
132 | GV->hasCommonLinkage()) |
133 | OutStreamer->emitSymbolAttribute(Symbol: GVSym, Attribute: MCSA_Weak); |
134 | [[fallthrough]]; |
135 | case GlobalValue::InternalLinkage: |
136 | case GlobalValue::PrivateLinkage: |
137 | break; |
138 | default: |
139 | llvm_unreachable("Unknown linkage type!" ); |
140 | } |
141 | |
142 | emitAlignment(Alignment: std::max(a: Alignment, b: Align(4)), GV); |
143 | |
144 | if (GV->isThreadLocal()) { |
145 | report_fatal_error(reason: "TLS is not supported by this target!" ); |
146 | } |
147 | unsigned Size = DL.getTypeAllocSize(Ty: C->getType()); |
148 | if (MAI->hasDotTypeDotSizeDirective()) { |
149 | OutStreamer->emitSymbolAttribute(Symbol: GVSym, Attribute: MCSA_ELF_TypeObject); |
150 | OutStreamer->emitELFSize(Symbol: GVSym, Value: MCConstantExpr::create(Value: Size, Ctx&: OutContext)); |
151 | } |
152 | OutStreamer->emitLabel(Symbol: GVSym); |
153 | |
154 | emitGlobalConstant(DL, CV: C); |
155 | // The ABI requires that unsigned scalar types smaller than 32 bits |
156 | // are padded to 32 bits. |
157 | if (Size < 4) |
158 | OutStreamer->emitZeros(NumBytes: 4 - Size); |
159 | |
160 | // Mark the end of the global |
161 | getTargetStreamer().emitCCBottomData(Name: GVSym->getName()); |
162 | } |
163 | |
164 | void XCoreAsmPrinter::emitFunctionBodyStart() { |
165 | MCInstLowering.Initialize(C: &MF->getContext()); |
166 | } |
167 | |
168 | /// EmitFunctionBodyEnd - Targets can override this to emit stuff after |
169 | /// the last basic block in the function. |
170 | void XCoreAsmPrinter::emitFunctionBodyEnd() { |
171 | // Emit function end directives |
172 | getTargetStreamer().emitCCBottomFunction(Name: CurrentFnSym->getName()); |
173 | } |
174 | |
175 | void XCoreAsmPrinter::emitFunctionEntryLabel() { |
176 | // Mark the start of the function |
177 | getTargetStreamer().emitCCTopFunction(Name: CurrentFnSym->getName()); |
178 | OutStreamer->emitLabel(Symbol: CurrentFnSym); |
179 | } |
180 | |
181 | void XCoreAsmPrinter:: |
182 | printInlineJT(const MachineInstr *MI, int opNum, raw_ostream &O, |
183 | const std::string &directive) { |
184 | unsigned JTI = MI->getOperand(i: opNum).getIndex(); |
185 | const MachineFunction *MF = MI->getParent()->getParent(); |
186 | const MachineJumpTableInfo *MJTI = MF->getJumpTableInfo(); |
187 | const std::vector<MachineJumpTableEntry> &JT = MJTI->getJumpTables(); |
188 | const std::vector<MachineBasicBlock*> &JTBBs = JT[JTI].MBBs; |
189 | O << "\t" << directive << " " ; |
190 | for (unsigned i = 0, e = JTBBs.size(); i != e; ++i) { |
191 | MachineBasicBlock *MBB = JTBBs[i]; |
192 | if (i > 0) |
193 | O << "," ; |
194 | MBB->getSymbol()->print(OS&: O, MAI); |
195 | } |
196 | } |
197 | |
198 | void XCoreAsmPrinter::printOperand(const MachineInstr *MI, int opNum, |
199 | raw_ostream &O) { |
200 | const DataLayout &DL = getDataLayout(); |
201 | const MachineOperand &MO = MI->getOperand(i: opNum); |
202 | switch (MO.getType()) { |
203 | case MachineOperand::MO_Register: |
204 | O << XCoreInstPrinter::getRegisterName(Reg: MO.getReg()); |
205 | break; |
206 | case MachineOperand::MO_Immediate: |
207 | O << MO.getImm(); |
208 | break; |
209 | case MachineOperand::MO_MachineBasicBlock: |
210 | MO.getMBB()->getSymbol()->print(OS&: O, MAI); |
211 | break; |
212 | case MachineOperand::MO_GlobalAddress: |
213 | PrintSymbolOperand(MO, OS&: O); |
214 | break; |
215 | case MachineOperand::MO_ConstantPoolIndex: |
216 | O << DL.getPrivateGlobalPrefix() << "CPI" << getFunctionNumber() << '_' |
217 | << MO.getIndex(); |
218 | break; |
219 | case MachineOperand::MO_BlockAddress: |
220 | GetBlockAddressSymbol(BA: MO.getBlockAddress())->print(OS&: O, MAI); |
221 | break; |
222 | default: |
223 | llvm_unreachable("not implemented" ); |
224 | } |
225 | } |
226 | |
227 | /// PrintAsmOperand - Print out an operand for an inline asm expression. |
228 | /// |
229 | bool XCoreAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, |
230 | const char *, raw_ostream &O) { |
231 | // Print the operand if there is no operand modifier. |
232 | if (!ExtraCode || !ExtraCode[0]) { |
233 | printOperand(MI, opNum: OpNo, O); |
234 | return false; |
235 | } |
236 | |
237 | // Otherwise fallback on the default implementation. |
238 | return AsmPrinter::PrintAsmOperand(MI, OpNo, ExtraCode, OS&: O); |
239 | } |
240 | |
241 | bool XCoreAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, |
242 | unsigned OpNum, |
243 | const char *, |
244 | raw_ostream &O) { |
245 | if (ExtraCode && ExtraCode[0]) { |
246 | return true; // Unknown modifier. |
247 | } |
248 | printOperand(MI, opNum: OpNum, O); |
249 | O << '['; |
250 | printOperand(MI, opNum: OpNum + 1, O); |
251 | O << ']'; |
252 | return false; |
253 | } |
254 | |
255 | void XCoreAsmPrinter::emitInstruction(const MachineInstr *MI) { |
256 | XCore_MC::verifyInstructionPredicates(Opcode: MI->getOpcode(), |
257 | Features: getSubtargetInfo().getFeatureBits()); |
258 | |
259 | SmallString<128> Str; |
260 | raw_svector_ostream O(Str); |
261 | |
262 | switch (MI->getOpcode()) { |
263 | case XCore::DBG_VALUE: |
264 | llvm_unreachable("Should be handled target independently" ); |
265 | case XCore::ADD_2rus: |
266 | if (MI->getOperand(i: 2).getImm() == 0) { |
267 | O << "\tmov " |
268 | << XCoreInstPrinter::getRegisterName(Reg: MI->getOperand(i: 0).getReg()) << ", " |
269 | << XCoreInstPrinter::getRegisterName(Reg: MI->getOperand(i: 1).getReg()); |
270 | OutStreamer->emitRawText(String: O.str()); |
271 | return; |
272 | } |
273 | break; |
274 | case XCore::BR_JT: |
275 | case XCore::BR_JT32: |
276 | O << "\tbru " |
277 | << XCoreInstPrinter::getRegisterName(Reg: MI->getOperand(i: 1).getReg()) << '\n'; |
278 | if (MI->getOpcode() == XCore::BR_JT) |
279 | printInlineJT(MI, opNum: 0, O); |
280 | else |
281 | printInlineJT32(MI, opNum: 0, O); |
282 | O << '\n'; |
283 | OutStreamer->emitRawText(String: O.str()); |
284 | return; |
285 | } |
286 | |
287 | MCInst TmpInst; |
288 | MCInstLowering.Lower(MI, OutMI&: TmpInst); |
289 | |
290 | EmitToStreamer(S&: *OutStreamer, Inst: TmpInst); |
291 | } |
292 | |
293 | char XCoreAsmPrinter::ID = 0; |
294 | |
295 | INITIALIZE_PASS(XCoreAsmPrinter, "xcore-asm-printer" , "XCore Assembly Printer" , |
296 | false, false) |
297 | |
298 | // Force static initialization. |
299 | extern "C" LLVM_ABI LLVM_EXTERNAL_VISIBILITY void |
300 | LLVMInitializeXCoreAsmPrinter() { |
301 | RegisterAsmPrinter<XCoreAsmPrinter> X(getTheXCoreTarget()); |
302 | } |
303 | |