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 "TargetInfo/CSKYTargetInfo.h"
20 #include "llvm/ADT/Statistic.h"
21 #include "llvm/CodeGen/AsmPrinter.h"
22 #include "llvm/CodeGen/MachineConstantPool.h"
23 #include "llvm/IR/DataLayout.h"
24 #include "llvm/MC/MCAsmInfo.h"
25 #include "llvm/MC/MCContext.h"
26 #include "llvm/MC/MCInstBuilder.h"
27 #include "llvm/MC/MCStreamer.h"
28 #include "llvm/MC/TargetRegistry.h"
29 
30 using namespace llvm;
31 
32 #define DEBUG_TYPE "csky-asm-printer"
33 
34 STATISTIC(CSKYNumInstrsCompressed,
35           "Number of C-SKY Compressed instructions emitted");
36 
37 CSKYAsmPrinter::CSKYAsmPrinter(llvm::TargetMachine &TM,
38                                std::unique_ptr<llvm::MCStreamer> Streamer)
39     : AsmPrinter(TM, std::move(Streamer)), MCInstLowering(OutContext, *this) {}
40 
41 bool CSKYAsmPrinter::runOnMachineFunction(MachineFunction &MF) {
42   MCP = MF.getConstantPool();
43   Subtarget = &MF.getSubtarget<CSKYSubtarget>();
44   return AsmPrinter::runOnMachineFunction(MF);
45 }
46 
47 #define GEN_COMPRESS_INSTR
48 #include "CSKYGenCompressInstEmitter.inc"
49 void CSKYAsmPrinter::EmitToStreamer(MCStreamer &S, const MCInst &Inst) {
50   MCInst CInst;
51   bool Res = compressInst(CInst, Inst, *Subtarget, OutStreamer->getContext());
52   if (Res)
53     ++CSKYNumInstrsCompressed;
54   AsmPrinter::EmitToStreamer(*OutStreamer, Res ? CInst : Inst);
55 }
56 
57 // Simple pseudo-instructions have their lowering (with expansion to real
58 // instructions) auto-generated.
59 #include "CSKYGenMCPseudoLowering.inc"
60 
61 void CSKYAsmPrinter::emitCustomConstantPool(const MachineInstr *MI) {
62 
63   // This instruction represents a floating constant pool in the function.
64   // The first operand is the ID# for this instruction, the second is the
65   // index into the MachineConstantPool that this is, the third is the size
66   // in bytes of this constant pool entry.
67   // The required alignment is specified on the basic block holding this MI.
68   unsigned LabelId = (unsigned)MI->getOperand(0).getImm();
69   unsigned CPIdx = (unsigned)MI->getOperand(1).getIndex();
70 
71   // If this is the first entry of the pool, mark it.
72   if (!InConstantPool) {
73     OutStreamer->emitValueToAlignment(4);
74     InConstantPool = true;
75   }
76 
77   OutStreamer->emitLabel(GetCPISymbol(LabelId));
78 
79   const MachineConstantPoolEntry &MCPE = MCP->getConstants()[CPIdx];
80   if (MCPE.isMachineConstantPoolEntry())
81     emitMachineConstantPoolValue(MCPE.Val.MachineCPVal);
82   else
83     emitGlobalConstant(MF->getDataLayout(), MCPE.Val.ConstVal);
84   return;
85 }
86 
87 void CSKYAsmPrinter::emitFunctionBodyEnd() {
88   // Make sure to terminate any constant pools that were at the end
89   // of the function.
90   if (!InConstantPool)
91     return;
92   InConstantPool = false;
93 }
94 
95 void CSKYAsmPrinter::emitInstruction(const MachineInstr *MI) {
96   // Do any auto-generated pseudo lowerings.
97   if (emitPseudoExpansionLowering(*OutStreamer, MI))
98     return;
99 
100   // If we just ended a constant pool, mark it as such.
101   if (InConstantPool && MI->getOpcode() != CSKY::CONSTPOOL_ENTRY) {
102     InConstantPool = false;
103   }
104 
105   if (MI->getOpcode() == CSKY::CONSTPOOL_ENTRY)
106     return emitCustomConstantPool(MI);
107 
108   MCInst TmpInst;
109   MCInstLowering.Lower(MI, TmpInst);
110   EmitToStreamer(*OutStreamer, TmpInst);
111 }
112 
113 // Convert a CSKY-specific constant pool modifier into the associated
114 // MCSymbolRefExpr variant kind.
115 static CSKYMCExpr::VariantKind
116 getModifierVariantKind(CSKYCP::CSKYCPModifier Modifier) {
117   switch (Modifier) {
118   case CSKYCP::NO_MOD:
119     return CSKYMCExpr::VK_CSKY_None;
120   case CSKYCP::ADDR:
121     return CSKYMCExpr::VK_CSKY_ADDR;
122   case CSKYCP::GOT:
123     return CSKYMCExpr::VK_CSKY_GOT;
124   case CSKYCP::GOTOFF:
125     return CSKYMCExpr::VK_CSKY_GOTOFF;
126   case CSKYCP::PLT:
127     return CSKYMCExpr::VK_CSKY_PLT;
128   case CSKYCP::TLSGD:
129     return CSKYMCExpr::VK_CSKY_TLSGD;
130   case CSKYCP::TLSLE:
131     return CSKYMCExpr::VK_CSKY_TLSLE;
132   case CSKYCP::TLSIE:
133     return CSKYMCExpr::VK_CSKY_TLSIE;
134   }
135   llvm_unreachable("Invalid CSKYCPModifier!");
136 }
137 
138 void CSKYAsmPrinter::emitMachineConstantPoolValue(
139     MachineConstantPoolValue *MCPV) {
140   int Size = getDataLayout().getTypeAllocSize(MCPV->getType());
141   CSKYConstantPoolValue *CCPV = static_cast<CSKYConstantPoolValue *>(MCPV);
142   MCSymbol *MCSym;
143 
144   if (CCPV->isBlockAddress()) {
145     const BlockAddress *BA =
146         cast<CSKYConstantPoolConstant>(CCPV)->getBlockAddress();
147     MCSym = GetBlockAddressSymbol(BA);
148   } else if (CCPV->isGlobalValue()) {
149     const GlobalValue *GV = cast<CSKYConstantPoolConstant>(CCPV)->getGV();
150     MCSym = getSymbol(GV);
151   } else if (CCPV->isMachineBasicBlock()) {
152     const MachineBasicBlock *MBB = cast<CSKYConstantPoolMBB>(CCPV)->getMBB();
153     MCSym = MBB->getSymbol();
154   } else if (CCPV->isJT()) {
155     signed JTI = cast<CSKYConstantPoolJT>(CCPV)->getJTI();
156     MCSym = GetJTISymbol(JTI);
157   } else {
158     assert(CCPV->isExtSymbol() && "unrecognized constant pool value");
159     StringRef Sym = cast<CSKYConstantPoolSymbol>(CCPV)->getSymbol();
160     MCSym = GetExternalSymbolSymbol(Sym);
161   }
162   // Create an MCSymbol for the reference.
163   const MCExpr *Expr =
164       MCSymbolRefExpr::create(MCSym, MCSymbolRefExpr::VK_None, OutContext);
165 
166   if (CCPV->getPCAdjustment()) {
167 
168     MCSymbol *PCLabel = OutContext.getOrCreateSymbol(
169         Twine(MAI->getPrivateGlobalPrefix()) + "PC" +
170         Twine(getFunctionNumber()) + "_" + Twine(CCPV->getLabelID()));
171 
172     const MCExpr *PCRelExpr = MCSymbolRefExpr::create(PCLabel, OutContext);
173     if (CCPV->mustAddCurrentAddress()) {
174       // We want "(<expr> - .)", but MC doesn't have a concept of the '.'
175       // label, so just emit a local label end reference that instead.
176       MCSymbol *DotSym = OutContext.createTempSymbol();
177       OutStreamer->emitLabel(DotSym);
178       const MCExpr *DotExpr = MCSymbolRefExpr::create(DotSym, OutContext);
179       PCRelExpr = MCBinaryExpr::createSub(PCRelExpr, DotExpr, OutContext);
180     }
181     Expr = MCBinaryExpr::createSub(Expr, PCRelExpr, OutContext);
182   }
183 
184   // Create an MCSymbol for the reference.
185   Expr = CSKYMCExpr::create(Expr, getModifierVariantKind(CCPV->getModifier()),
186                             OutContext);
187 
188   OutStreamer->emitValue(Expr, Size);
189 }
190 
191 extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeCSKYAsmPrinter() {
192   RegisterAsmPrinter<CSKYAsmPrinter> X(getTheCSKYTarget());
193 }
194