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
32using namespace llvm;
33
34#define DEBUG_TYPE "csky-asm-printer"
35
36STATISTIC(CSKYNumInstrsCompressed,
37 "Number of C-SKY Compressed instructions emitted");
38
39CSKYAsmPrinter::CSKYAsmPrinter(llvm::TargetMachine &TM,
40 std::unique_ptr<llvm::MCStreamer> Streamer)
41 : AsmPrinter(TM, std::move(Streamer)), MCInstLowering(OutContext, *this) {}
42
43bool 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"
59void 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
71void 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
96void 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
122void 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
130void CSKYAsmPrinter::emitStartOfAsmFile(Module &M) {
131 if (TM.getTargetTriple().isOSBinFormatELF())
132 emitAttributes();
133}
134
135void CSKYAsmPrinter::emitEndOfAsmFile(Module &M) {
136 CSKYTargetStreamer &CTS =
137 static_cast<CSKYTargetStreamer &>(*OutStreamer->getTargetStreamer());
138
139 if (TM.getTargetTriple().isOSBinFormatELF())
140 CTS.finishAttributeSection();
141}
142
143void 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.
169static CSKYMCExpr::VariantKind
170getModifierVariantKind(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
192void 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
248void 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
263bool CSKYAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
264 const char *ExtraCode, 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
309bool CSKYAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,
310 unsigned OpNo, const char *ExtraCode,
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
326extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeCSKYAsmPrinter() {
327 RegisterAsmPrinter<CSKYAsmPrinter> X(getTheCSKYTarget());
328}
329

source code of llvm/lib/Target/CSKY/CSKYAsmPrinter.cpp