xref: /llvm-project/llvm/lib/Target/CSKY/CSKYAsmPrinter.cpp (revision 7a2a36f952e5f1c0184e5de0bb8a32b5d2382427)
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(*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(*OutStreamer, 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       Twine(MAI->getPrivateGlobalPrefix()) + "PC" + Twine(getFunctionNumber()) +
76       "_" + Twine(MI->getOperand(3).getImm()));
77 
78   OutStreamer->emitLabel(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(Instr, LRWInst);
85   EmitToStreamer(*OutStreamer, 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(Instr, GRSInst);
92   EmitToStreamer(*OutStreamer, 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(0).getImm();
104   unsigned CPIdx = (unsigned)MI->getOperand(1).getIndex();
105 
106   // If this is the first entry of the pool, mark it.
107   if (!InConstantPool) {
108     OutStreamer->emitValueToAlignment(Align(4));
109     InConstantPool = true;
110   }
111 
112   OutStreamer->emitLabel(GetCPISymbol(LabelId));
113 
114   const MachineConstantPoolEntry &MCPE = MCP->getConstants()[CPIdx];
115   if (MCPE.isMachineConstantPoolEntry())
116     emitMachineConstantPoolValue(MCPE.Val.MachineCPVal);
117   else
118     emitGlobalConstant(MF->getDataLayout(), 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 (MCInst OutInst; lowerPseudoInstExpansion(MI, OutInst)) {
149     EmitToStreamer(*OutStreamer, OutInst);
150     return;
151   }
152 
153   // If we just ended a constant pool, mark it as such.
154   if (InConstantPool && MI->getOpcode() != CSKY::CONSTPOOL_ENTRY) {
155     InConstantPool = false;
156   }
157 
158   if (MI->getOpcode() == CSKY::PseudoTLSLA32)
159     return expandTLSLA(MI);
160 
161   if (MI->getOpcode() == CSKY::CONSTPOOL_ENTRY)
162     return emitCustomConstantPool(MI);
163 
164   MCInst TmpInst;
165   MCInstLowering.Lower(MI, TmpInst);
166   EmitToStreamer(*OutStreamer, TmpInst);
167 }
168 
169 // Convert a CSKY-specific constant pool modifier into the associated
170 // MCSymbolRefExpr variant kind.
171 static CSKYMCExpr::VariantKind
172 getModifierVariantKind(CSKYCP::CSKYCPModifier Modifier) {
173   switch (Modifier) {
174   case CSKYCP::NO_MOD:
175     return CSKYMCExpr::VK_CSKY_None;
176   case CSKYCP::ADDR:
177     return CSKYMCExpr::VK_CSKY_ADDR;
178   case CSKYCP::GOT:
179     return CSKYMCExpr::VK_CSKY_GOT;
180   case CSKYCP::GOTOFF:
181     return CSKYMCExpr::VK_CSKY_GOTOFF;
182   case CSKYCP::PLT:
183     return CSKYMCExpr::VK_CSKY_PLT;
184   case CSKYCP::TLSGD:
185     return CSKYMCExpr::VK_CSKY_TLSGD;
186   case CSKYCP::TLSLE:
187     return CSKYMCExpr::VK_CSKY_TLSLE;
188   case CSKYCP::TLSIE:
189     return CSKYMCExpr::VK_CSKY_TLSIE;
190   }
191   llvm_unreachable("Invalid CSKYCPModifier!");
192 }
193 
194 void CSKYAsmPrinter::emitMachineConstantPoolValue(
195     MachineConstantPoolValue *MCPV) {
196   int Size = getDataLayout().getTypeAllocSize(MCPV->getType());
197   CSKYConstantPoolValue *CCPV = static_cast<CSKYConstantPoolValue *>(MCPV);
198   MCSymbol *MCSym;
199 
200   if (CCPV->isBlockAddress()) {
201     const BlockAddress *BA =
202         cast<CSKYConstantPoolConstant>(CCPV)->getBlockAddress();
203     MCSym = GetBlockAddressSymbol(BA);
204   } else if (CCPV->isGlobalValue()) {
205     const GlobalValue *GV = cast<CSKYConstantPoolConstant>(CCPV)->getGV();
206     MCSym = getSymbol(GV);
207   } else if (CCPV->isMachineBasicBlock()) {
208     const MachineBasicBlock *MBB = cast<CSKYConstantPoolMBB>(CCPV)->getMBB();
209     MCSym = MBB->getSymbol();
210   } else if (CCPV->isJT()) {
211     signed JTI = cast<CSKYConstantPoolJT>(CCPV)->getJTI();
212     MCSym = GetJTISymbol(JTI);
213   } else if (CCPV->isConstPool()) {
214     const Constant *C = cast<CSKYConstantPoolConstant>(CCPV)->getConstantPool();
215     MCSym = GetCPISymbol(MCP->getConstantPoolIndex(C, Align(4)));
216   } else {
217     assert(CCPV->isExtSymbol() && "unrecognized constant pool value");
218     StringRef Sym = cast<CSKYConstantPoolSymbol>(CCPV)->getSymbol();
219     MCSym = GetExternalSymbolSymbol(Sym);
220   }
221   // Create an MCSymbol for the reference.
222   const MCExpr *Expr =
223       MCSymbolRefExpr::create(MCSym, MCSymbolRefExpr::VK_None, OutContext);
224 
225   if (CCPV->getPCAdjustment()) {
226 
227     MCSymbol *PCLabel = OutContext.getOrCreateSymbol(
228         Twine(MAI->getPrivateGlobalPrefix()) + "PC" +
229         Twine(getFunctionNumber()) + "_" + Twine(CCPV->getLabelID()));
230 
231     const MCExpr *PCRelExpr = MCSymbolRefExpr::create(PCLabel, OutContext);
232     if (CCPV->mustAddCurrentAddress()) {
233       // We want "(<expr> - .)", but MC doesn't have a concept of the '.'
234       // label, so just emit a local label end reference that instead.
235       MCSymbol *DotSym = OutContext.createTempSymbol();
236       OutStreamer->emitLabel(DotSym);
237       const MCExpr *DotExpr = MCSymbolRefExpr::create(DotSym, OutContext);
238       PCRelExpr = MCBinaryExpr::createSub(PCRelExpr, DotExpr, OutContext);
239     }
240     Expr = MCBinaryExpr::createSub(Expr, PCRelExpr, OutContext);
241   }
242 
243   // Create an MCSymbol for the reference.
244   Expr = CSKYMCExpr::create(Expr, getModifierVariantKind(CCPV->getModifier()),
245                             OutContext);
246 
247   OutStreamer->emitValue(Expr, Size);
248 }
249 
250 void CSKYAsmPrinter::emitAttributes() {
251   CSKYTargetStreamer &CTS =
252       static_cast<CSKYTargetStreamer &>(*OutStreamer->getTargetStreamer());
253 
254   const Triple &TT = TM.getTargetTriple();
255   StringRef CPU = TM.getTargetCPU();
256   StringRef FS = TM.getTargetFeatureString();
257   const CSKYTargetMachine &CTM = static_cast<const CSKYTargetMachine &>(TM);
258   /* TuneCPU doesn't impact emission of ELF attributes, ELF attributes only
259      care about arch related features, so we can set TuneCPU as CPU.  */
260   const CSKYSubtarget STI(TT, CPU, /*TuneCPU=*/CPU, FS, CTM);
261 
262   CTS.emitTargetAttributes(STI);
263 }
264 
265 bool CSKYAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
266                                      const char *ExtraCode, raw_ostream &OS) {
267   // First try the generic code, which knows about modifiers like 'c' and 'n'.
268   if (!AsmPrinter::PrintAsmOperand(MI, OpNo, ExtraCode, OS))
269     return false;
270 
271   const MachineOperand &MO = MI->getOperand(OpNo);
272   if (ExtraCode && ExtraCode[0]) {
273     if (ExtraCode[1] != 0)
274       return true; // Unknown modifier.
275 
276     switch (ExtraCode[0]) {
277     default:
278       return true; // Unknown modifier.
279     case 'R':
280       if (MO.getType() == MachineOperand::MO_Register) {
281         OS << CSKYInstPrinter::getRegisterName(MO.getReg() + 1);
282         return false;
283       }
284     }
285   }
286 
287   switch (MO.getType()) {
288   case MachineOperand::MO_Immediate:
289     OS << MO.getImm();
290     return false;
291   case MachineOperand::MO_Register:
292     if (MO.getReg() == CSKY::C)
293       return false;
294     OS << CSKYInstPrinter::getRegisterName(MO.getReg());
295     return false;
296   case MachineOperand::MO_GlobalAddress:
297     PrintSymbolOperand(MO, OS);
298     return false;
299   case MachineOperand::MO_BlockAddress: {
300     MCSymbol *Sym = GetBlockAddressSymbol(MO.getBlockAddress());
301     Sym->print(OS, MAI);
302     return false;
303   }
304   default:
305     break;
306   }
307 
308   return true;
309 }
310 
311 bool CSKYAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,
312                                            unsigned OpNo, const char *ExtraCode,
313                                            raw_ostream &OS) {
314   if (!ExtraCode) {
315     const MachineOperand &MO = MI->getOperand(OpNo);
316     // For now, we only support register memory operands in registers and
317     // assume there is no addend
318     if (!MO.isReg())
319       return true;
320 
321     OS << "(" << CSKYInstPrinter::getRegisterName(MO.getReg()) << ", 0)";
322     return false;
323   }
324 
325   return AsmPrinter::PrintAsmMemoryOperand(MI, OpNo, ExtraCode, OS);
326 }
327 
328 extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeCSKYAsmPrinter() {
329   RegisterAsmPrinter<CSKYAsmPrinter> X(getTheCSKYTarget());
330 }
331