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, directive: ".jmptable32" ); |
67 | } |
68 | void printOperand(const MachineInstr *MI, int opNum, raw_ostream &O); |
69 | bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, |
70 | const char *, raw_ostream &O) override; |
71 | bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNum, |
72 | const char *, 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>(Val: GV->getValueType())) { |
93 | |
94 | MCSymbol *SymGlob = OutContext.getOrCreateSymbol( |
95 | Name: Twine(Sym->getName() + StringRef(".globound" ))); |
96 | OutStreamer->emitSymbolAttribute(Symbol: SymGlob, Attribute: MCSA_Global); |
97 | OutStreamer->emitAssignment(Symbol: SymGlob, |
98 | Value: MCConstantExpr::create(Value: ATy->getNumElements(), |
99 | Ctx&: OutContext)); |
100 | if (GV->hasWeakLinkage() || GV->hasLinkOnceLinkage() || |
101 | GV->hasCommonLinkage()) { |
102 | OutStreamer->emitSymbolAttribute(Symbol: SymGlob, Attribute: 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(Section: getObjFileLowering().SectionForGlobal(GO: GV, TM)); |
114 | |
115 | MCSymbol *GVSym = getSymbol(GV); |
116 | const Constant *C = GV->getInitializer(); |
117 | const Align Alignment = DL.getPrefTypeAlign(Ty: C->getType()); |
118 | |
119 | // Mark the start of the global |
120 | getTargetStreamer().emitCCTopData(Name: GVSym->getName()); |
121 | |
122 | switch (GV->getLinkage()) { |
123 | case GlobalValue::AppendingLinkage: |
124 | report_fatal_error(reason: "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(Sym: GVSym, GV); |
132 | OutStreamer->emitSymbolAttribute(Symbol: GVSym, Attribute: MCSA_Global); |
133 | |
134 | if (GV->hasWeakLinkage() || GV->hasLinkOnceLinkage() || |
135 | GV->hasCommonLinkage()) |
136 | OutStreamer->emitSymbolAttribute(Symbol: GVSym, Attribute: MCSA_Weak); |
137 | [[fallthrough]]; |
138 | case GlobalValue::InternalLinkage: |
139 | case GlobalValue::PrivateLinkage: |
140 | break; |
141 | default: |
142 | llvm_unreachable("Unknown linkage type!" ); |
143 | } |
144 | |
145 | emitAlignment(Alignment: std::max(a: Alignment, b: Align(4)), GV); |
146 | |
147 | if (GV->isThreadLocal()) { |
148 | report_fatal_error(reason: "TLS is not supported by this target!" ); |
149 | } |
150 | unsigned Size = DL.getTypeAllocSize(Ty: C->getType()); |
151 | if (MAI->hasDotTypeDotSizeDirective()) { |
152 | OutStreamer->emitSymbolAttribute(Symbol: GVSym, Attribute: MCSA_ELF_TypeObject); |
153 | OutStreamer->emitELFSize(Symbol: GVSym, Value: MCConstantExpr::create(Value: Size, Ctx&: OutContext)); |
154 | } |
155 | OutStreamer->emitLabel(Symbol: GVSym); |
156 | |
157 | emitGlobalConstant(DL, CV: 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(NumBytes: 4 - Size); |
162 | |
163 | // Mark the end of the global |
164 | getTargetStreamer().emitCCBottomData(Name: GVSym->getName()); |
165 | } |
166 | |
167 | void XCoreAsmPrinter::emitFunctionBodyStart() { |
168 | MCInstLowering.Initialize(C: &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(Name: CurrentFnSym->getName()); |
176 | } |
177 | |
178 | void XCoreAsmPrinter::emitFunctionEntryLabel() { |
179 | // Mark the start of the function |
180 | getTargetStreamer().emitCCTopFunction(Name: CurrentFnSym->getName()); |
181 | OutStreamer->emitLabel(Symbol: 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(i: 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(OS&: 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(i: opNum); |
205 | switch (MO.getType()) { |
206 | case MachineOperand::MO_Register: |
207 | O << XCoreInstPrinter::getRegisterName(Reg: 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(OS&: O, MAI); |
214 | break; |
215 | case MachineOperand::MO_GlobalAddress: |
216 | PrintSymbolOperand(MO, OS&: 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(BA: MO.getBlockAddress())->print(OS&: 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 *, raw_ostream &O) { |
234 | // Print the operand if there is no operand modifier. |
235 | if (!ExtraCode || !ExtraCode[0]) { |
236 | printOperand(MI, opNum: OpNo, O); |
237 | return false; |
238 | } |
239 | |
240 | // Otherwise fallback on the default implementation. |
241 | return AsmPrinter::PrintAsmOperand(MI, OpNo, ExtraCode, OS&: O); |
242 | } |
243 | |
244 | bool XCoreAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, |
245 | unsigned OpNum, |
246 | const char *, |
247 | raw_ostream &O) { |
248 | if (ExtraCode && ExtraCode[0]) { |
249 | return true; // Unknown modifier. |
250 | } |
251 | printOperand(MI, opNum: OpNum, O); |
252 | O << '['; |
253 | printOperand(MI, opNum: OpNum + 1, O); |
254 | O << ']'; |
255 | return false; |
256 | } |
257 | |
258 | void XCoreAsmPrinter::emitInstruction(const MachineInstr *MI) { |
259 | XCore_MC::verifyInstructionPredicates(Opcode: MI->getOpcode(), |
260 | Features: 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(i: 2).getImm() == 0) { |
270 | O << "\tmov " |
271 | << XCoreInstPrinter::getRegisterName(Reg: MI->getOperand(i: 0).getReg()) << ", " |
272 | << XCoreInstPrinter::getRegisterName(Reg: MI->getOperand(i: 1).getReg()); |
273 | OutStreamer->emitRawText(String: O.str()); |
274 | return; |
275 | } |
276 | break; |
277 | case XCore::BR_JT: |
278 | case XCore::BR_JT32: |
279 | O << "\tbru " |
280 | << XCoreInstPrinter::getRegisterName(Reg: MI->getOperand(i: 1).getReg()) << '\n'; |
281 | if (MI->getOpcode() == XCore::BR_JT) |
282 | printInlineJT(MI, opNum: 0, O); |
283 | else |
284 | printInlineJT32(MI, opNum: 0, O); |
285 | O << '\n'; |
286 | OutStreamer->emitRawText(String: O.str()); |
287 | return; |
288 | } |
289 | |
290 | MCInst TmpInst; |
291 | MCInstLowering.Lower(MI, OutMI&: TmpInst); |
292 | |
293 | EmitToStreamer(S&: *OutStreamer, Inst: TmpInst); |
294 | } |
295 | |
296 | // Force static initialization. |
297 | extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeXCoreAsmPrinter() { |
298 | RegisterAsmPrinter<XCoreAsmPrinter> X(getTheXCoreTarget()); |
299 | } |
300 | |