1 | //===-- CSKYAsmPrinter.cpp - CSKY 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 CSKY assembly language. |
11 | // |
12 | //===----------------------------------------------------------------------===// |
13 | #include "CSKYAsmPrinter.h" |
14 | #include "CSKY.h" |
15 | #include "CSKYConstantPoolValue.h" |
16 | #include "CSKYTargetMachine.h" |
17 | #include "MCTargetDesc/CSKYInstPrinter.h" |
18 | #include "MCTargetDesc/CSKYMCExpr.h" |
19 | #include "MCTargetDesc/CSKYTargetStreamer.h" |
20 | #include "TargetInfo/CSKYTargetInfo.h" |
21 | #include "llvm/ADT/Statistic.h" |
22 | #include "llvm/CodeGen/AsmPrinter.h" |
23 | #include "llvm/CodeGen/MachineConstantPool.h" |
24 | #include "llvm/CodeGen/MachineFrameInfo.h" |
25 | #include "llvm/IR/DataLayout.h" |
26 | #include "llvm/MC/MCAsmInfo.h" |
27 | #include "llvm/MC/MCContext.h" |
28 | #include "llvm/MC/MCInstBuilder.h" |
29 | #include "llvm/MC/MCStreamer.h" |
30 | #include "llvm/MC/TargetRegistry.h" |
31 | |
32 | using namespace llvm; |
33 | |
34 | #define DEBUG_TYPE "csky-asm-printer" |
35 | |
36 | STATISTIC(CSKYNumInstrsCompressed, |
37 | "Number of C-SKY Compressed instructions emitted" ); |
38 | |
39 | CSKYAsmPrinter::CSKYAsmPrinter(llvm::TargetMachine &TM, |
40 | std::unique_ptr<llvm::MCStreamer> Streamer) |
41 | : AsmPrinter(TM, std::move(Streamer)), MCInstLowering(OutContext, *this) {} |
42 | |
43 | bool CSKYAsmPrinter::runOnMachineFunction(MachineFunction &MF) { |
44 | MCP = MF.getConstantPool(); |
45 | TII = MF.getSubtarget().getInstrInfo(); |
46 | |
47 | // Set the current MCSubtargetInfo to a copy which has the correct |
48 | // feature bits for the current MachineFunction |
49 | MCSubtargetInfo &NewSTI = |
50 | OutStreamer->getContext().getSubtargetCopy(STI: *TM.getMCSubtargetInfo()); |
51 | NewSTI.setFeatureBits(MF.getSubtarget().getFeatureBits()); |
52 | Subtarget = &NewSTI; |
53 | |
54 | return AsmPrinter::runOnMachineFunction(MF); |
55 | } |
56 | |
57 | #define GEN_COMPRESS_INSTR |
58 | #include "CSKYGenCompressInstEmitter.inc" |
59 | void CSKYAsmPrinter::EmitToStreamer(MCStreamer &S, const MCInst &Inst) { |
60 | MCInst CInst; |
61 | bool Res = compressInst(CInst, Inst, *Subtarget); |
62 | if (Res) |
63 | ++CSKYNumInstrsCompressed; |
64 | AsmPrinter::EmitToStreamer(S&: *OutStreamer, Inst: Res ? CInst : Inst); |
65 | } |
66 | |
67 | // Simple pseudo-instructions have their lowering (with expansion to real |
68 | // instructions) auto-generated. |
69 | #include "CSKYGenMCPseudoLowering.inc" |
70 | |
71 | void CSKYAsmPrinter::expandTLSLA(const MachineInstr *MI) { |
72 | DebugLoc DL = MI->getDebugLoc(); |
73 | |
74 | MCSymbol *PCLabel = OutContext.getOrCreateSymbol( |
75 | Name: Twine(MAI->getPrivateGlobalPrefix()) + "PC" + Twine(getFunctionNumber()) + |
76 | "_" + Twine(MI->getOperand(i: 3).getImm())); |
77 | |
78 | OutStreamer->emitLabel(Symbol: PCLabel); |
79 | |
80 | auto Instr = BuildMI(*MF, DL, TII->get(CSKY::LRW32)) |
81 | .add(MI->getOperand(0)) |
82 | .add(MI->getOperand(2)); |
83 | MCInst LRWInst; |
84 | MCInstLowering.Lower(MI: Instr, OutMI&: LRWInst); |
85 | EmitToStreamer(S&: *OutStreamer, Inst: LRWInst); |
86 | |
87 | Instr = BuildMI(*MF, DL, TII->get(CSKY::GRS32)) |
88 | .add(MI->getOperand(1)) |
89 | .addSym(PCLabel); |
90 | MCInst GRSInst; |
91 | MCInstLowering.Lower(MI: Instr, OutMI&: GRSInst); |
92 | EmitToStreamer(S&: *OutStreamer, Inst: GRSInst); |
93 | return; |
94 | } |
95 | |
96 | void CSKYAsmPrinter::emitCustomConstantPool(const MachineInstr *MI) { |
97 | |
98 | // This instruction represents a floating constant pool in the function. |
99 | // The first operand is the ID# for this instruction, the second is the |
100 | // index into the MachineConstantPool that this is, the third is the size |
101 | // in bytes of this constant pool entry. |
102 | // The required alignment is specified on the basic block holding this MI. |
103 | unsigned LabelId = (unsigned)MI->getOperand(i: 0).getImm(); |
104 | unsigned CPIdx = (unsigned)MI->getOperand(i: 1).getIndex(); |
105 | |
106 | // If this is the first entry of the pool, mark it. |
107 | if (!InConstantPool) { |
108 | OutStreamer->emitValueToAlignment(Alignment: Align(4)); |
109 | InConstantPool = true; |
110 | } |
111 | |
112 | OutStreamer->emitLabel(Symbol: GetCPISymbol(CPID: LabelId)); |
113 | |
114 | const MachineConstantPoolEntry &MCPE = MCP->getConstants()[CPIdx]; |
115 | if (MCPE.isMachineConstantPoolEntry()) |
116 | emitMachineConstantPoolValue(MCPV: MCPE.Val.MachineCPVal); |
117 | else |
118 | emitGlobalConstant(DL: MF->getDataLayout(), CV: MCPE.Val.ConstVal); |
119 | return; |
120 | } |
121 | |
122 | void CSKYAsmPrinter::emitFunctionBodyEnd() { |
123 | // Make sure to terminate any constant pools that were at the end |
124 | // of the function. |
125 | if (!InConstantPool) |
126 | return; |
127 | InConstantPool = false; |
128 | } |
129 | |
130 | void CSKYAsmPrinter::emitStartOfAsmFile(Module &M) { |
131 | if (TM.getTargetTriple().isOSBinFormatELF()) |
132 | emitAttributes(); |
133 | } |
134 | |
135 | void CSKYAsmPrinter::emitEndOfAsmFile(Module &M) { |
136 | CSKYTargetStreamer &CTS = |
137 | static_cast<CSKYTargetStreamer &>(*OutStreamer->getTargetStreamer()); |
138 | |
139 | if (TM.getTargetTriple().isOSBinFormatELF()) |
140 | CTS.finishAttributeSection(); |
141 | } |
142 | |
143 | void CSKYAsmPrinter::emitInstruction(const MachineInstr *MI) { |
144 | CSKY_MC::verifyInstructionPredicates(MI->getOpcode(), |
145 | getSubtargetInfo().getFeatureBits()); |
146 | |
147 | // Do any auto-generated pseudo lowerings. |
148 | if (emitPseudoExpansionLowering(OutStreamer&: *OutStreamer, MI)) |
149 | return; |
150 | |
151 | // If we just ended a constant pool, mark it as such. |
152 | if (InConstantPool && MI->getOpcode() != CSKY::CONSTPOOL_ENTRY) { |
153 | InConstantPool = false; |
154 | } |
155 | |
156 | if (MI->getOpcode() == CSKY::PseudoTLSLA32) |
157 | return expandTLSLA(MI); |
158 | |
159 | if (MI->getOpcode() == CSKY::CONSTPOOL_ENTRY) |
160 | return emitCustomConstantPool(MI); |
161 | |
162 | MCInst TmpInst; |
163 | MCInstLowering.Lower(MI, OutMI&: TmpInst); |
164 | EmitToStreamer(S&: *OutStreamer, Inst: TmpInst); |
165 | } |
166 | |
167 | // Convert a CSKY-specific constant pool modifier into the associated |
168 | // MCSymbolRefExpr variant kind. |
169 | static CSKYMCExpr::VariantKind |
170 | getModifierVariantKind(CSKYCP::CSKYCPModifier Modifier) { |
171 | switch (Modifier) { |
172 | case CSKYCP::NO_MOD: |
173 | return CSKYMCExpr::VK_CSKY_None; |
174 | case CSKYCP::ADDR: |
175 | return CSKYMCExpr::VK_CSKY_ADDR; |
176 | case CSKYCP::GOT: |
177 | return CSKYMCExpr::VK_CSKY_GOT; |
178 | case CSKYCP::GOTOFF: |
179 | return CSKYMCExpr::VK_CSKY_GOTOFF; |
180 | case CSKYCP::PLT: |
181 | return CSKYMCExpr::VK_CSKY_PLT; |
182 | case CSKYCP::TLSGD: |
183 | return CSKYMCExpr::VK_CSKY_TLSGD; |
184 | case CSKYCP::TLSLE: |
185 | return CSKYMCExpr::VK_CSKY_TLSLE; |
186 | case CSKYCP::TLSIE: |
187 | return CSKYMCExpr::VK_CSKY_TLSIE; |
188 | } |
189 | llvm_unreachable("Invalid CSKYCPModifier!" ); |
190 | } |
191 | |
192 | void CSKYAsmPrinter::emitMachineConstantPoolValue( |
193 | MachineConstantPoolValue *MCPV) { |
194 | int Size = getDataLayout().getTypeAllocSize(Ty: MCPV->getType()); |
195 | CSKYConstantPoolValue *CCPV = static_cast<CSKYConstantPoolValue *>(MCPV); |
196 | MCSymbol *MCSym; |
197 | |
198 | if (CCPV->isBlockAddress()) { |
199 | const BlockAddress *BA = |
200 | cast<CSKYConstantPoolConstant>(Val: CCPV)->getBlockAddress(); |
201 | MCSym = GetBlockAddressSymbol(BA); |
202 | } else if (CCPV->isGlobalValue()) { |
203 | const GlobalValue *GV = cast<CSKYConstantPoolConstant>(Val: CCPV)->getGV(); |
204 | MCSym = getSymbol(GV); |
205 | } else if (CCPV->isMachineBasicBlock()) { |
206 | const MachineBasicBlock *MBB = cast<CSKYConstantPoolMBB>(Val: CCPV)->getMBB(); |
207 | MCSym = MBB->getSymbol(); |
208 | } else if (CCPV->isJT()) { |
209 | signed JTI = cast<CSKYConstantPoolJT>(Val: CCPV)->getJTI(); |
210 | MCSym = GetJTISymbol(JTID: JTI); |
211 | } else if (CCPV->isConstPool()) { |
212 | const Constant *C = cast<CSKYConstantPoolConstant>(Val: CCPV)->getConstantPool(); |
213 | MCSym = GetCPISymbol(CPID: MCP->getConstantPoolIndex(C, Alignment: Align(4))); |
214 | } else { |
215 | assert(CCPV->isExtSymbol() && "unrecognized constant pool value" ); |
216 | StringRef Sym = cast<CSKYConstantPoolSymbol>(Val: CCPV)->getSymbol(); |
217 | MCSym = GetExternalSymbolSymbol(Sym); |
218 | } |
219 | // Create an MCSymbol for the reference. |
220 | const MCExpr *Expr = |
221 | MCSymbolRefExpr::create(Symbol: MCSym, Kind: MCSymbolRefExpr::VK_None, Ctx&: OutContext); |
222 | |
223 | if (CCPV->getPCAdjustment()) { |
224 | |
225 | MCSymbol *PCLabel = OutContext.getOrCreateSymbol( |
226 | Name: Twine(MAI->getPrivateGlobalPrefix()) + "PC" + |
227 | Twine(getFunctionNumber()) + "_" + Twine(CCPV->getLabelID())); |
228 | |
229 | const MCExpr *PCRelExpr = MCSymbolRefExpr::create(Symbol: PCLabel, Ctx&: OutContext); |
230 | if (CCPV->mustAddCurrentAddress()) { |
231 | // We want "(<expr> - .)", but MC doesn't have a concept of the '.' |
232 | // label, so just emit a local label end reference that instead. |
233 | MCSymbol *DotSym = OutContext.createTempSymbol(); |
234 | OutStreamer->emitLabel(Symbol: DotSym); |
235 | const MCExpr *DotExpr = MCSymbolRefExpr::create(Symbol: DotSym, Ctx&: OutContext); |
236 | PCRelExpr = MCBinaryExpr::createSub(LHS: PCRelExpr, RHS: DotExpr, Ctx&: OutContext); |
237 | } |
238 | Expr = MCBinaryExpr::createSub(LHS: Expr, RHS: PCRelExpr, Ctx&: OutContext); |
239 | } |
240 | |
241 | // Create an MCSymbol for the reference. |
242 | Expr = CSKYMCExpr::create(Expr, Kind: getModifierVariantKind(Modifier: CCPV->getModifier()), |
243 | Ctx&: OutContext); |
244 | |
245 | OutStreamer->emitValue(Value: Expr, Size); |
246 | } |
247 | |
248 | void CSKYAsmPrinter::emitAttributes() { |
249 | CSKYTargetStreamer &CTS = |
250 | static_cast<CSKYTargetStreamer &>(*OutStreamer->getTargetStreamer()); |
251 | |
252 | const Triple &TT = TM.getTargetTriple(); |
253 | StringRef CPU = TM.getTargetCPU(); |
254 | StringRef FS = TM.getTargetFeatureString(); |
255 | const CSKYTargetMachine &CTM = static_cast<const CSKYTargetMachine &>(TM); |
256 | /* TuneCPU doesn't impact emission of ELF attributes, ELF attributes only |
257 | care about arch related features, so we can set TuneCPU as CPU. */ |
258 | const CSKYSubtarget STI(TT, CPU, /*TuneCPU=*/CPU, FS, CTM); |
259 | |
260 | CTS.emitTargetAttributes(STI); |
261 | } |
262 | |
263 | bool CSKYAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, |
264 | const char *, raw_ostream &OS) { |
265 | // First try the generic code, which knows about modifiers like 'c' and 'n'. |
266 | if (!AsmPrinter::PrintAsmOperand(MI, OpNo, ExtraCode, OS)) |
267 | return false; |
268 | |
269 | const MachineOperand &MO = MI->getOperand(i: OpNo); |
270 | if (ExtraCode && ExtraCode[0]) { |
271 | if (ExtraCode[1] != 0) |
272 | return true; // Unknown modifier. |
273 | |
274 | switch (ExtraCode[0]) { |
275 | default: |
276 | return true; // Unknown modifier. |
277 | case 'R': |
278 | if (MO.getType() == MachineOperand::MO_Register) { |
279 | OS << CSKYInstPrinter::getRegisterName(Reg: MO.getReg() + 1); |
280 | return false; |
281 | } |
282 | } |
283 | } |
284 | |
285 | switch (MO.getType()) { |
286 | case MachineOperand::MO_Immediate: |
287 | OS << MO.getImm(); |
288 | return false; |
289 | case MachineOperand::MO_Register: |
290 | if (MO.getReg() == CSKY::C) |
291 | return false; |
292 | OS << CSKYInstPrinter::getRegisterName(Reg: MO.getReg()); |
293 | return false; |
294 | case MachineOperand::MO_GlobalAddress: |
295 | PrintSymbolOperand(MO, OS); |
296 | return false; |
297 | case MachineOperand::MO_BlockAddress: { |
298 | MCSymbol *Sym = GetBlockAddressSymbol(BA: MO.getBlockAddress()); |
299 | Sym->print(OS, MAI); |
300 | return false; |
301 | } |
302 | default: |
303 | break; |
304 | } |
305 | |
306 | return true; |
307 | } |
308 | |
309 | bool CSKYAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, |
310 | unsigned OpNo, const char *, |
311 | raw_ostream &OS) { |
312 | if (!ExtraCode) { |
313 | const MachineOperand &MO = MI->getOperand(i: OpNo); |
314 | // For now, we only support register memory operands in registers and |
315 | // assume there is no addend |
316 | if (!MO.isReg()) |
317 | return true; |
318 | |
319 | OS << "(" << CSKYInstPrinter::getRegisterName(Reg: MO.getReg()) << ", 0)" ; |
320 | return false; |
321 | } |
322 | |
323 | return AsmPrinter::PrintAsmMemoryOperand(MI, OpNo, ExtraCode, OS); |
324 | } |
325 | |
326 | extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeCSKYAsmPrinter() { |
327 | RegisterAsmPrinter<CSKYAsmPrinter> X(getTheCSKYTarget()); |
328 | } |
329 | |