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