xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/CSKY/CSKYAsmPrinter.cpp (revision 04eeddc0aa8e0a417a16eaf9d7d095207f4a8623)
1349cc55cSDimitry Andric //===-- CSKYAsmPrinter.cpp - CSKY LLVM assembly writer --------------------===//
2349cc55cSDimitry Andric //
3349cc55cSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4349cc55cSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5349cc55cSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6349cc55cSDimitry Andric //
7349cc55cSDimitry Andric //===----------------------------------------------------------------------===//
8349cc55cSDimitry Andric //
9349cc55cSDimitry Andric // This file contains a printer that converts from our internal representation
10349cc55cSDimitry Andric // of machine-dependent LLVM code to the CSKY assembly language.
11349cc55cSDimitry Andric //
12349cc55cSDimitry Andric //===----------------------------------------------------------------------===//
13349cc55cSDimitry Andric #include "CSKYAsmPrinter.h"
14349cc55cSDimitry Andric #include "CSKY.h"
15*04eeddc0SDimitry Andric #include "CSKYConstantPoolValue.h"
16349cc55cSDimitry Andric #include "CSKYTargetMachine.h"
17349cc55cSDimitry Andric #include "MCTargetDesc/CSKYInstPrinter.h"
18349cc55cSDimitry Andric #include "MCTargetDesc/CSKYMCExpr.h"
19349cc55cSDimitry Andric #include "TargetInfo/CSKYTargetInfo.h"
20349cc55cSDimitry Andric #include "llvm/ADT/Statistic.h"
21349cc55cSDimitry Andric #include "llvm/CodeGen/AsmPrinter.h"
22349cc55cSDimitry Andric #include "llvm/CodeGen/MachineConstantPool.h"
23349cc55cSDimitry Andric #include "llvm/IR/DataLayout.h"
24349cc55cSDimitry Andric #include "llvm/MC/MCAsmInfo.h"
25349cc55cSDimitry Andric #include "llvm/MC/MCContext.h"
26349cc55cSDimitry Andric #include "llvm/MC/MCInstBuilder.h"
27349cc55cSDimitry Andric #include "llvm/MC/MCStreamer.h"
28349cc55cSDimitry Andric #include "llvm/MC/TargetRegistry.h"
29349cc55cSDimitry Andric 
30349cc55cSDimitry Andric using namespace llvm;
31349cc55cSDimitry Andric 
32349cc55cSDimitry Andric #define DEBUG_TYPE "csky-asm-printer"
33349cc55cSDimitry Andric 
340eae32dcSDimitry Andric STATISTIC(CSKYNumInstrsCompressed,
350eae32dcSDimitry Andric           "Number of C-SKY Compressed instructions emitted");
360eae32dcSDimitry Andric 
37349cc55cSDimitry Andric CSKYAsmPrinter::CSKYAsmPrinter(llvm::TargetMachine &TM,
38349cc55cSDimitry Andric                                std::unique_ptr<llvm::MCStreamer> Streamer)
39349cc55cSDimitry Andric     : AsmPrinter(TM, std::move(Streamer)), MCInstLowering(OutContext, *this) {}
40349cc55cSDimitry Andric 
41349cc55cSDimitry Andric bool CSKYAsmPrinter::runOnMachineFunction(MachineFunction &MF) {
42*04eeddc0SDimitry Andric   MCP = MF.getConstantPool();
43349cc55cSDimitry Andric   Subtarget = &MF.getSubtarget<CSKYSubtarget>();
44349cc55cSDimitry Andric   return AsmPrinter::runOnMachineFunction(MF);
45349cc55cSDimitry Andric }
46349cc55cSDimitry Andric 
470eae32dcSDimitry Andric #define GEN_COMPRESS_INSTR
480eae32dcSDimitry Andric #include "CSKYGenCompressInstEmitter.inc"
490eae32dcSDimitry Andric void CSKYAsmPrinter::EmitToStreamer(MCStreamer &S, const MCInst &Inst) {
500eae32dcSDimitry Andric   MCInst CInst;
510eae32dcSDimitry Andric   bool Res = compressInst(CInst, Inst, *Subtarget, OutStreamer->getContext());
520eae32dcSDimitry Andric   if (Res)
530eae32dcSDimitry Andric     ++CSKYNumInstrsCompressed;
540eae32dcSDimitry Andric   AsmPrinter::EmitToStreamer(*OutStreamer, Res ? CInst : Inst);
550eae32dcSDimitry Andric }
560eae32dcSDimitry Andric 
57349cc55cSDimitry Andric // Simple pseudo-instructions have their lowering (with expansion to real
58349cc55cSDimitry Andric // instructions) auto-generated.
59349cc55cSDimitry Andric #include "CSKYGenMCPseudoLowering.inc"
60349cc55cSDimitry Andric 
61*04eeddc0SDimitry Andric void CSKYAsmPrinter::expandTLSLA(const MachineInstr *MI) {
62*04eeddc0SDimitry Andric   const CSKYInstrInfo *TII = Subtarget->getInstrInfo();
63*04eeddc0SDimitry Andric 
64*04eeddc0SDimitry Andric   DebugLoc DL = MI->getDebugLoc();
65*04eeddc0SDimitry Andric 
66*04eeddc0SDimitry Andric   MCSymbol *PCLabel = OutContext.getOrCreateSymbol(
67*04eeddc0SDimitry Andric       Twine(MAI->getPrivateGlobalPrefix()) + "PC" + Twine(getFunctionNumber()) +
68*04eeddc0SDimitry Andric       "_" + Twine(MI->getOperand(3).getImm()));
69*04eeddc0SDimitry Andric 
70*04eeddc0SDimitry Andric   OutStreamer->emitLabel(PCLabel);
71*04eeddc0SDimitry Andric 
72*04eeddc0SDimitry Andric   auto Instr = BuildMI(*MF, DL, TII->get(CSKY::LRW32))
73*04eeddc0SDimitry Andric                    .add(MI->getOperand(0))
74*04eeddc0SDimitry Andric                    .add(MI->getOperand(2));
75*04eeddc0SDimitry Andric   MCInst LRWInst;
76*04eeddc0SDimitry Andric   MCInstLowering.Lower(Instr, LRWInst);
77*04eeddc0SDimitry Andric   EmitToStreamer(*OutStreamer, LRWInst);
78*04eeddc0SDimitry Andric 
79*04eeddc0SDimitry Andric   Instr = BuildMI(*MF, DL, TII->get(CSKY::GRS32))
80*04eeddc0SDimitry Andric               .add(MI->getOperand(1))
81*04eeddc0SDimitry Andric               .addSym(PCLabel);
82*04eeddc0SDimitry Andric   MCInst GRSInst;
83*04eeddc0SDimitry Andric   MCInstLowering.Lower(Instr, GRSInst);
84*04eeddc0SDimitry Andric   EmitToStreamer(*OutStreamer, GRSInst);
85*04eeddc0SDimitry Andric   return;
86*04eeddc0SDimitry Andric }
87*04eeddc0SDimitry Andric 
88*04eeddc0SDimitry Andric void CSKYAsmPrinter::emitCustomConstantPool(const MachineInstr *MI) {
89*04eeddc0SDimitry Andric 
90*04eeddc0SDimitry Andric   // This instruction represents a floating constant pool in the function.
91*04eeddc0SDimitry Andric   // The first operand is the ID# for this instruction, the second is the
92*04eeddc0SDimitry Andric   // index into the MachineConstantPool that this is, the third is the size
93*04eeddc0SDimitry Andric   // in bytes of this constant pool entry.
94*04eeddc0SDimitry Andric   // The required alignment is specified on the basic block holding this MI.
95*04eeddc0SDimitry Andric   unsigned LabelId = (unsigned)MI->getOperand(0).getImm();
96*04eeddc0SDimitry Andric   unsigned CPIdx = (unsigned)MI->getOperand(1).getIndex();
97*04eeddc0SDimitry Andric 
98*04eeddc0SDimitry Andric   // If this is the first entry of the pool, mark it.
99*04eeddc0SDimitry Andric   if (!InConstantPool) {
100*04eeddc0SDimitry Andric     OutStreamer->emitValueToAlignment(4);
101*04eeddc0SDimitry Andric     InConstantPool = true;
102*04eeddc0SDimitry Andric   }
103*04eeddc0SDimitry Andric 
104*04eeddc0SDimitry Andric   OutStreamer->emitLabel(GetCPISymbol(LabelId));
105*04eeddc0SDimitry Andric 
106*04eeddc0SDimitry Andric   const MachineConstantPoolEntry &MCPE = MCP->getConstants()[CPIdx];
107*04eeddc0SDimitry Andric   if (MCPE.isMachineConstantPoolEntry())
108*04eeddc0SDimitry Andric     emitMachineConstantPoolValue(MCPE.Val.MachineCPVal);
109*04eeddc0SDimitry Andric   else
110*04eeddc0SDimitry Andric     emitGlobalConstant(MF->getDataLayout(), MCPE.Val.ConstVal);
111*04eeddc0SDimitry Andric   return;
112*04eeddc0SDimitry Andric }
113*04eeddc0SDimitry Andric 
114*04eeddc0SDimitry Andric void CSKYAsmPrinter::emitFunctionBodyEnd() {
115*04eeddc0SDimitry Andric   // Make sure to terminate any constant pools that were at the end
116*04eeddc0SDimitry Andric   // of the function.
117*04eeddc0SDimitry Andric   if (!InConstantPool)
118*04eeddc0SDimitry Andric     return;
119*04eeddc0SDimitry Andric   InConstantPool = false;
120*04eeddc0SDimitry Andric }
121*04eeddc0SDimitry Andric 
122349cc55cSDimitry Andric void CSKYAsmPrinter::emitInstruction(const MachineInstr *MI) {
123349cc55cSDimitry Andric   // Do any auto-generated pseudo lowerings.
124349cc55cSDimitry Andric   if (emitPseudoExpansionLowering(*OutStreamer, MI))
125349cc55cSDimitry Andric     return;
126349cc55cSDimitry Andric 
127*04eeddc0SDimitry Andric   // If we just ended a constant pool, mark it as such.
128*04eeddc0SDimitry Andric   if (InConstantPool && MI->getOpcode() != CSKY::CONSTPOOL_ENTRY) {
129*04eeddc0SDimitry Andric     InConstantPool = false;
130*04eeddc0SDimitry Andric   }
131*04eeddc0SDimitry Andric 
132*04eeddc0SDimitry Andric   if (MI->getOpcode() == CSKY::PseudoTLSLA32)
133*04eeddc0SDimitry Andric     return expandTLSLA(MI);
134*04eeddc0SDimitry Andric 
135*04eeddc0SDimitry Andric   if (MI->getOpcode() == CSKY::CONSTPOOL_ENTRY)
136*04eeddc0SDimitry Andric     return emitCustomConstantPool(MI);
137*04eeddc0SDimitry Andric 
138349cc55cSDimitry Andric   MCInst TmpInst;
139349cc55cSDimitry Andric   MCInstLowering.Lower(MI, TmpInst);
140349cc55cSDimitry Andric   EmitToStreamer(*OutStreamer, TmpInst);
141349cc55cSDimitry Andric }
142349cc55cSDimitry Andric 
143*04eeddc0SDimitry Andric // Convert a CSKY-specific constant pool modifier into the associated
144*04eeddc0SDimitry Andric // MCSymbolRefExpr variant kind.
145*04eeddc0SDimitry Andric static CSKYMCExpr::VariantKind
146*04eeddc0SDimitry Andric getModifierVariantKind(CSKYCP::CSKYCPModifier Modifier) {
147*04eeddc0SDimitry Andric   switch (Modifier) {
148*04eeddc0SDimitry Andric   case CSKYCP::NO_MOD:
149*04eeddc0SDimitry Andric     return CSKYMCExpr::VK_CSKY_None;
150*04eeddc0SDimitry Andric   case CSKYCP::ADDR:
151*04eeddc0SDimitry Andric     return CSKYMCExpr::VK_CSKY_ADDR;
152*04eeddc0SDimitry Andric   case CSKYCP::GOT:
153*04eeddc0SDimitry Andric     return CSKYMCExpr::VK_CSKY_GOT;
154*04eeddc0SDimitry Andric   case CSKYCP::GOTOFF:
155*04eeddc0SDimitry Andric     return CSKYMCExpr::VK_CSKY_GOTOFF;
156*04eeddc0SDimitry Andric   case CSKYCP::PLT:
157*04eeddc0SDimitry Andric     return CSKYMCExpr::VK_CSKY_PLT;
158*04eeddc0SDimitry Andric   case CSKYCP::TLSGD:
159*04eeddc0SDimitry Andric     return CSKYMCExpr::VK_CSKY_TLSGD;
160*04eeddc0SDimitry Andric   case CSKYCP::TLSLE:
161*04eeddc0SDimitry Andric     return CSKYMCExpr::VK_CSKY_TLSLE;
162*04eeddc0SDimitry Andric   case CSKYCP::TLSIE:
163*04eeddc0SDimitry Andric     return CSKYMCExpr::VK_CSKY_TLSIE;
164*04eeddc0SDimitry Andric   }
165*04eeddc0SDimitry Andric   llvm_unreachable("Invalid CSKYCPModifier!");
166*04eeddc0SDimitry Andric }
167*04eeddc0SDimitry Andric 
168*04eeddc0SDimitry Andric void CSKYAsmPrinter::emitMachineConstantPoolValue(
169*04eeddc0SDimitry Andric     MachineConstantPoolValue *MCPV) {
170*04eeddc0SDimitry Andric   int Size = getDataLayout().getTypeAllocSize(MCPV->getType());
171*04eeddc0SDimitry Andric   CSKYConstantPoolValue *CCPV = static_cast<CSKYConstantPoolValue *>(MCPV);
172*04eeddc0SDimitry Andric   MCSymbol *MCSym;
173*04eeddc0SDimitry Andric 
174*04eeddc0SDimitry Andric   if (CCPV->isBlockAddress()) {
175*04eeddc0SDimitry Andric     const BlockAddress *BA =
176*04eeddc0SDimitry Andric         cast<CSKYConstantPoolConstant>(CCPV)->getBlockAddress();
177*04eeddc0SDimitry Andric     MCSym = GetBlockAddressSymbol(BA);
178*04eeddc0SDimitry Andric   } else if (CCPV->isGlobalValue()) {
179*04eeddc0SDimitry Andric     const GlobalValue *GV = cast<CSKYConstantPoolConstant>(CCPV)->getGV();
180*04eeddc0SDimitry Andric     MCSym = getSymbol(GV);
181*04eeddc0SDimitry Andric   } else if (CCPV->isMachineBasicBlock()) {
182*04eeddc0SDimitry Andric     const MachineBasicBlock *MBB = cast<CSKYConstantPoolMBB>(CCPV)->getMBB();
183*04eeddc0SDimitry Andric     MCSym = MBB->getSymbol();
184*04eeddc0SDimitry Andric   } else if (CCPV->isJT()) {
185*04eeddc0SDimitry Andric     signed JTI = cast<CSKYConstantPoolJT>(CCPV)->getJTI();
186*04eeddc0SDimitry Andric     MCSym = GetJTISymbol(JTI);
187*04eeddc0SDimitry Andric   } else {
188*04eeddc0SDimitry Andric     assert(CCPV->isExtSymbol() && "unrecognized constant pool value");
189*04eeddc0SDimitry Andric     StringRef Sym = cast<CSKYConstantPoolSymbol>(CCPV)->getSymbol();
190*04eeddc0SDimitry Andric     MCSym = GetExternalSymbolSymbol(Sym);
191*04eeddc0SDimitry Andric   }
192*04eeddc0SDimitry Andric   // Create an MCSymbol for the reference.
193*04eeddc0SDimitry Andric   const MCExpr *Expr =
194*04eeddc0SDimitry Andric       MCSymbolRefExpr::create(MCSym, MCSymbolRefExpr::VK_None, OutContext);
195*04eeddc0SDimitry Andric 
196*04eeddc0SDimitry Andric   if (CCPV->getPCAdjustment()) {
197*04eeddc0SDimitry Andric 
198*04eeddc0SDimitry Andric     MCSymbol *PCLabel = OutContext.getOrCreateSymbol(
199*04eeddc0SDimitry Andric         Twine(MAI->getPrivateGlobalPrefix()) + "PC" +
200*04eeddc0SDimitry Andric         Twine(getFunctionNumber()) + "_" + Twine(CCPV->getLabelID()));
201*04eeddc0SDimitry Andric 
202*04eeddc0SDimitry Andric     const MCExpr *PCRelExpr = MCSymbolRefExpr::create(PCLabel, OutContext);
203*04eeddc0SDimitry Andric     if (CCPV->mustAddCurrentAddress()) {
204*04eeddc0SDimitry Andric       // We want "(<expr> - .)", but MC doesn't have a concept of the '.'
205*04eeddc0SDimitry Andric       // label, so just emit a local label end reference that instead.
206*04eeddc0SDimitry Andric       MCSymbol *DotSym = OutContext.createTempSymbol();
207*04eeddc0SDimitry Andric       OutStreamer->emitLabel(DotSym);
208*04eeddc0SDimitry Andric       const MCExpr *DotExpr = MCSymbolRefExpr::create(DotSym, OutContext);
209*04eeddc0SDimitry Andric       PCRelExpr = MCBinaryExpr::createSub(PCRelExpr, DotExpr, OutContext);
210*04eeddc0SDimitry Andric     }
211*04eeddc0SDimitry Andric     Expr = MCBinaryExpr::createSub(Expr, PCRelExpr, OutContext);
212*04eeddc0SDimitry Andric   }
213*04eeddc0SDimitry Andric 
214*04eeddc0SDimitry Andric   // Create an MCSymbol for the reference.
215*04eeddc0SDimitry Andric   Expr = CSKYMCExpr::create(Expr, getModifierVariantKind(CCPV->getModifier()),
216*04eeddc0SDimitry Andric                             OutContext);
217*04eeddc0SDimitry Andric 
218*04eeddc0SDimitry Andric   OutStreamer->emitValue(Expr, Size);
219*04eeddc0SDimitry Andric }
220*04eeddc0SDimitry Andric 
221349cc55cSDimitry Andric extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeCSKYAsmPrinter() {
222349cc55cSDimitry Andric   RegisterAsmPrinter<CSKYAsmPrinter> X(getTheCSKYTarget());
223349cc55cSDimitry Andric }
224