xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/Xtensa/XtensaAsmPrinter.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
1*0fca6ea1SDimitry Andric //===- XtensaAsmPrinter.cpp Xtensa LLVM Assembly Printer ------------------===//
2*0fca6ea1SDimitry Andric //
3*0fca6ea1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*0fca6ea1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*0fca6ea1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*0fca6ea1SDimitry Andric //
7*0fca6ea1SDimitry Andric //===----------------------------------------------------------------------===//
8*0fca6ea1SDimitry Andric //
9*0fca6ea1SDimitry Andric // This file contains a printer that converts from our internal representation
10*0fca6ea1SDimitry Andric // of machine-dependent LLVM code to GAS-format Xtensa assembly language.
11*0fca6ea1SDimitry Andric //
12*0fca6ea1SDimitry Andric //===----------------------------------------------------------------------===//
13*0fca6ea1SDimitry Andric 
14*0fca6ea1SDimitry Andric #include "XtensaAsmPrinter.h"
15*0fca6ea1SDimitry Andric #include "MCTargetDesc/XtensaMCExpr.h"
16*0fca6ea1SDimitry Andric #include "MCTargetDesc/XtensaTargetStreamer.h"
17*0fca6ea1SDimitry Andric #include "TargetInfo/XtensaTargetInfo.h"
18*0fca6ea1SDimitry Andric #include "XtensaConstantPoolValue.h"
19*0fca6ea1SDimitry Andric #include "llvm/ADT/StringExtras.h"
20*0fca6ea1SDimitry Andric #include "llvm/BinaryFormat/ELF.h"
21*0fca6ea1SDimitry Andric #include "llvm/CodeGen/MachineConstantPool.h"
22*0fca6ea1SDimitry Andric #include "llvm/CodeGen/MachineModuleInfoImpls.h"
23*0fca6ea1SDimitry Andric #include "llvm/CodeGen/TargetLoweringObjectFileImpl.h"
24*0fca6ea1SDimitry Andric #include "llvm/MC/MCExpr.h"
25*0fca6ea1SDimitry Andric #include "llvm/MC/MCInstBuilder.h"
26*0fca6ea1SDimitry Andric #include "llvm/MC/MCSectionELF.h"
27*0fca6ea1SDimitry Andric #include "llvm/MC/MCStreamer.h"
28*0fca6ea1SDimitry Andric #include "llvm/MC/MCSymbol.h"
29*0fca6ea1SDimitry Andric #include "llvm/MC/MCSymbolELF.h"
30*0fca6ea1SDimitry Andric #include "llvm/MC/TargetRegistry.h"
31*0fca6ea1SDimitry Andric 
32*0fca6ea1SDimitry Andric using namespace llvm;
33*0fca6ea1SDimitry Andric 
34*0fca6ea1SDimitry Andric static MCSymbolRefExpr::VariantKind
35*0fca6ea1SDimitry Andric getModifierVariantKind(XtensaCP::XtensaCPModifier Modifier) {
36*0fca6ea1SDimitry Andric   switch (Modifier) {
37*0fca6ea1SDimitry Andric   case XtensaCP::no_modifier:
38*0fca6ea1SDimitry Andric     return MCSymbolRefExpr::VK_None;
39*0fca6ea1SDimitry Andric   case XtensaCP::TPOFF:
40*0fca6ea1SDimitry Andric     return MCSymbolRefExpr::VK_TPOFF;
41*0fca6ea1SDimitry Andric   }
42*0fca6ea1SDimitry Andric   report_fatal_error("Invalid XtensaCPModifier!");
43*0fca6ea1SDimitry Andric }
44*0fca6ea1SDimitry Andric 
45*0fca6ea1SDimitry Andric void XtensaAsmPrinter::emitInstruction(const MachineInstr *MI) {
46*0fca6ea1SDimitry Andric   unsigned Opc = MI->getOpcode();
47*0fca6ea1SDimitry Andric 
48*0fca6ea1SDimitry Andric   switch (Opc) {
49*0fca6ea1SDimitry Andric   case Xtensa::BR_JT:
50*0fca6ea1SDimitry Andric     EmitToStreamer(
51*0fca6ea1SDimitry Andric         *OutStreamer,
52*0fca6ea1SDimitry Andric         MCInstBuilder(Xtensa::JX).addReg(MI->getOperand(0).getReg()));
53*0fca6ea1SDimitry Andric     return;
54*0fca6ea1SDimitry Andric   default:
55*0fca6ea1SDimitry Andric     MCInst LoweredMI;
56*0fca6ea1SDimitry Andric     lowerToMCInst(MI, LoweredMI);
57*0fca6ea1SDimitry Andric     EmitToStreamer(*OutStreamer, LoweredMI);
58*0fca6ea1SDimitry Andric     return;
59*0fca6ea1SDimitry Andric   }
60*0fca6ea1SDimitry Andric }
61*0fca6ea1SDimitry Andric 
62*0fca6ea1SDimitry Andric void XtensaAsmPrinter::emitMachineConstantPoolValue(
63*0fca6ea1SDimitry Andric     MachineConstantPoolValue *MCPV) {
64*0fca6ea1SDimitry Andric   XtensaConstantPoolValue *ACPV = static_cast<XtensaConstantPoolValue *>(MCPV);
65*0fca6ea1SDimitry Andric   MCSymbol *MCSym;
66*0fca6ea1SDimitry Andric 
67*0fca6ea1SDimitry Andric   if (ACPV->isBlockAddress()) {
68*0fca6ea1SDimitry Andric     const BlockAddress *BA =
69*0fca6ea1SDimitry Andric         cast<XtensaConstantPoolConstant>(ACPV)->getBlockAddress();
70*0fca6ea1SDimitry Andric     MCSym = GetBlockAddressSymbol(BA);
71*0fca6ea1SDimitry Andric   } else if (ACPV->isJumpTable()) {
72*0fca6ea1SDimitry Andric     unsigned Idx = cast<XtensaConstantPoolJumpTable>(ACPV)->getIndex();
73*0fca6ea1SDimitry Andric     MCSym = this->GetJTISymbol(Idx, false);
74*0fca6ea1SDimitry Andric   } else {
75*0fca6ea1SDimitry Andric     assert(ACPV->isExtSymbol() && "unrecognized constant pool value");
76*0fca6ea1SDimitry Andric     XtensaConstantPoolSymbol *XtensaSym = cast<XtensaConstantPoolSymbol>(ACPV);
77*0fca6ea1SDimitry Andric     const char *SymName = XtensaSym->getSymbol();
78*0fca6ea1SDimitry Andric 
79*0fca6ea1SDimitry Andric     if (XtensaSym->isPrivateLinkage()) {
80*0fca6ea1SDimitry Andric       const DataLayout &DL = getDataLayout();
81*0fca6ea1SDimitry Andric       MCSym = OutContext.getOrCreateSymbol(Twine(DL.getPrivateGlobalPrefix()) +
82*0fca6ea1SDimitry Andric                                            SymName);
83*0fca6ea1SDimitry Andric     } else {
84*0fca6ea1SDimitry Andric       MCSym = OutContext.getOrCreateSymbol(SymName);
85*0fca6ea1SDimitry Andric     }
86*0fca6ea1SDimitry Andric   }
87*0fca6ea1SDimitry Andric 
88*0fca6ea1SDimitry Andric   MCSymbol *LblSym = GetCPISymbol(ACPV->getLabelId());
89*0fca6ea1SDimitry Andric   auto *TS =
90*0fca6ea1SDimitry Andric       static_cast<XtensaTargetStreamer *>(OutStreamer->getTargetStreamer());
91*0fca6ea1SDimitry Andric   MCSymbolRefExpr::VariantKind VK = getModifierVariantKind(ACPV->getModifier());
92*0fca6ea1SDimitry Andric 
93*0fca6ea1SDimitry Andric   if (ACPV->getModifier() != XtensaCP::no_modifier) {
94*0fca6ea1SDimitry Andric     std::string SymName(MCSym->getName());
95*0fca6ea1SDimitry Andric     StringRef Modifier = ACPV->getModifierText();
96*0fca6ea1SDimitry Andric     SymName += Modifier;
97*0fca6ea1SDimitry Andric     MCSym = OutContext.getOrCreateSymbol(SymName);
98*0fca6ea1SDimitry Andric   }
99*0fca6ea1SDimitry Andric 
100*0fca6ea1SDimitry Andric   const MCExpr *Expr = MCSymbolRefExpr::create(MCSym, VK, OutContext);
101*0fca6ea1SDimitry Andric   TS->emitLiteral(LblSym, Expr, false);
102*0fca6ea1SDimitry Andric }
103*0fca6ea1SDimitry Andric 
104*0fca6ea1SDimitry Andric void XtensaAsmPrinter::emitMachineConstantPoolEntry(
105*0fca6ea1SDimitry Andric     const MachineConstantPoolEntry &CPE, int i) {
106*0fca6ea1SDimitry Andric   if (CPE.isMachineConstantPoolEntry()) {
107*0fca6ea1SDimitry Andric     XtensaConstantPoolValue *ACPV =
108*0fca6ea1SDimitry Andric         static_cast<XtensaConstantPoolValue *>(CPE.Val.MachineCPVal);
109*0fca6ea1SDimitry Andric     ACPV->setLabelId(i);
110*0fca6ea1SDimitry Andric     emitMachineConstantPoolValue(CPE.Val.MachineCPVal);
111*0fca6ea1SDimitry Andric   } else {
112*0fca6ea1SDimitry Andric     MCSymbol *LblSym = GetCPISymbol(i);
113*0fca6ea1SDimitry Andric     auto *TS =
114*0fca6ea1SDimitry Andric         static_cast<XtensaTargetStreamer *>(OutStreamer->getTargetStreamer());
115*0fca6ea1SDimitry Andric     const Constant *C = CPE.Val.ConstVal;
116*0fca6ea1SDimitry Andric     const MCExpr *Value = nullptr;
117*0fca6ea1SDimitry Andric 
118*0fca6ea1SDimitry Andric     Type *Ty = C->getType();
119*0fca6ea1SDimitry Andric     if (const auto *CFP = dyn_cast<ConstantFP>(C)) {
120*0fca6ea1SDimitry Andric       Value = MCConstantExpr::create(
121*0fca6ea1SDimitry Andric           CFP->getValueAPF().bitcastToAPInt().getSExtValue(), OutContext);
122*0fca6ea1SDimitry Andric     } else if (const auto *CI = dyn_cast<ConstantInt>(C)) {
123*0fca6ea1SDimitry Andric       Value = MCConstantExpr::create(CI->getValue().getSExtValue(), OutContext);
124*0fca6ea1SDimitry Andric     } else if (isa<PointerType>(Ty)) {
125*0fca6ea1SDimitry Andric       Value = lowerConstant(C);
126*0fca6ea1SDimitry Andric     } else {
127*0fca6ea1SDimitry Andric       llvm_unreachable("unexpected constant pool entry type");
128*0fca6ea1SDimitry Andric     }
129*0fca6ea1SDimitry Andric 
130*0fca6ea1SDimitry Andric     TS->emitLiteral(LblSym, Value, false);
131*0fca6ea1SDimitry Andric   }
132*0fca6ea1SDimitry Andric }
133*0fca6ea1SDimitry Andric 
134*0fca6ea1SDimitry Andric // EmitConstantPool - Print to the current output stream assembly
135*0fca6ea1SDimitry Andric // representations of the constants in the constant pool MCP. This is
136*0fca6ea1SDimitry Andric // used to print out constants which have been "spilled to memory" by
137*0fca6ea1SDimitry Andric // the code generator.
138*0fca6ea1SDimitry Andric void XtensaAsmPrinter::emitConstantPool() {
139*0fca6ea1SDimitry Andric   const Function &F = MF->getFunction();
140*0fca6ea1SDimitry Andric   const MachineConstantPool *MCP = MF->getConstantPool();
141*0fca6ea1SDimitry Andric   const std::vector<MachineConstantPoolEntry> &CP = MCP->getConstants();
142*0fca6ea1SDimitry Andric   if (CP.empty())
143*0fca6ea1SDimitry Andric     return;
144*0fca6ea1SDimitry Andric 
145*0fca6ea1SDimitry Andric   OutStreamer->pushSection();
146*0fca6ea1SDimitry Andric 
147*0fca6ea1SDimitry Andric   auto *TS =
148*0fca6ea1SDimitry Andric       static_cast<XtensaTargetStreamer *>(OutStreamer->getTargetStreamer());
149*0fca6ea1SDimitry Andric   MCSection *CS = getObjFileLowering().SectionForGlobal(&F, TM);
150*0fca6ea1SDimitry Andric   TS->startLiteralSection(CS);
151*0fca6ea1SDimitry Andric 
152*0fca6ea1SDimitry Andric   int CPIdx = 0;
153*0fca6ea1SDimitry Andric   for (const MachineConstantPoolEntry &CPE : CP) {
154*0fca6ea1SDimitry Andric     emitMachineConstantPoolEntry(CPE, CPIdx++);
155*0fca6ea1SDimitry Andric   }
156*0fca6ea1SDimitry Andric 
157*0fca6ea1SDimitry Andric   OutStreamer->popSection();
158*0fca6ea1SDimitry Andric }
159*0fca6ea1SDimitry Andric 
160*0fca6ea1SDimitry Andric MCSymbol *
161*0fca6ea1SDimitry Andric XtensaAsmPrinter::GetConstantPoolIndexSymbol(const MachineOperand &MO) const {
162*0fca6ea1SDimitry Andric   // Create a symbol for the name.
163*0fca6ea1SDimitry Andric   return GetCPISymbol(MO.getIndex());
164*0fca6ea1SDimitry Andric }
165*0fca6ea1SDimitry Andric 
166*0fca6ea1SDimitry Andric MCSymbol *XtensaAsmPrinter::GetJumpTableSymbol(const MachineOperand &MO) const {
167*0fca6ea1SDimitry Andric   return GetJTISymbol(MO.getIndex());
168*0fca6ea1SDimitry Andric }
169*0fca6ea1SDimitry Andric 
170*0fca6ea1SDimitry Andric MCOperand
171*0fca6ea1SDimitry Andric XtensaAsmPrinter::LowerSymbolOperand(const MachineOperand &MO,
172*0fca6ea1SDimitry Andric                                      MachineOperand::MachineOperandType MOTy,
173*0fca6ea1SDimitry Andric                                      unsigned Offset) const {
174*0fca6ea1SDimitry Andric   const MCSymbol *Symbol;
175*0fca6ea1SDimitry Andric   XtensaMCExpr::VariantKind Kind = XtensaMCExpr::VK_Xtensa_None;
176*0fca6ea1SDimitry Andric 
177*0fca6ea1SDimitry Andric   switch (MOTy) {
178*0fca6ea1SDimitry Andric   case MachineOperand::MO_GlobalAddress:
179*0fca6ea1SDimitry Andric     Symbol = getSymbol(MO.getGlobal());
180*0fca6ea1SDimitry Andric     Offset += MO.getOffset();
181*0fca6ea1SDimitry Andric     break;
182*0fca6ea1SDimitry Andric   case MachineOperand::MO_MachineBasicBlock:
183*0fca6ea1SDimitry Andric     Symbol = MO.getMBB()->getSymbol();
184*0fca6ea1SDimitry Andric     break;
185*0fca6ea1SDimitry Andric   case MachineOperand::MO_BlockAddress:
186*0fca6ea1SDimitry Andric     Symbol = GetBlockAddressSymbol(MO.getBlockAddress());
187*0fca6ea1SDimitry Andric     Offset += MO.getOffset();
188*0fca6ea1SDimitry Andric     break;
189*0fca6ea1SDimitry Andric   case MachineOperand::MO_ExternalSymbol:
190*0fca6ea1SDimitry Andric     Symbol = GetExternalSymbolSymbol(MO.getSymbolName());
191*0fca6ea1SDimitry Andric     Offset += MO.getOffset();
192*0fca6ea1SDimitry Andric     break;
193*0fca6ea1SDimitry Andric   case MachineOperand::MO_JumpTableIndex:
194*0fca6ea1SDimitry Andric     Symbol = GetJumpTableSymbol(MO);
195*0fca6ea1SDimitry Andric     break;
196*0fca6ea1SDimitry Andric   case MachineOperand::MO_ConstantPoolIndex:
197*0fca6ea1SDimitry Andric     Symbol = GetConstantPoolIndexSymbol(MO);
198*0fca6ea1SDimitry Andric     Offset += MO.getOffset();
199*0fca6ea1SDimitry Andric     break;
200*0fca6ea1SDimitry Andric   default:
201*0fca6ea1SDimitry Andric     report_fatal_error("<unknown operand type>");
202*0fca6ea1SDimitry Andric   }
203*0fca6ea1SDimitry Andric 
204*0fca6ea1SDimitry Andric   const MCExpr *ME =
205*0fca6ea1SDimitry Andric       MCSymbolRefExpr::create(Symbol, MCSymbolRefExpr::VK_None, OutContext);
206*0fca6ea1SDimitry Andric   ME = XtensaMCExpr::create(ME, Kind, OutContext);
207*0fca6ea1SDimitry Andric 
208*0fca6ea1SDimitry Andric   if (Offset) {
209*0fca6ea1SDimitry Andric     // Assume offset is never negative.
210*0fca6ea1SDimitry Andric     assert(Offset > 0);
211*0fca6ea1SDimitry Andric 
212*0fca6ea1SDimitry Andric     const MCConstantExpr *OffsetExpr =
213*0fca6ea1SDimitry Andric         MCConstantExpr::create(Offset, OutContext);
214*0fca6ea1SDimitry Andric     ME = MCBinaryExpr::createAdd(ME, OffsetExpr, OutContext);
215*0fca6ea1SDimitry Andric   }
216*0fca6ea1SDimitry Andric 
217*0fca6ea1SDimitry Andric   return MCOperand::createExpr(ME);
218*0fca6ea1SDimitry Andric }
219*0fca6ea1SDimitry Andric 
220*0fca6ea1SDimitry Andric MCOperand XtensaAsmPrinter::lowerOperand(const MachineOperand &MO,
221*0fca6ea1SDimitry Andric                                          unsigned Offset) const {
222*0fca6ea1SDimitry Andric   MachineOperand::MachineOperandType MOTy = MO.getType();
223*0fca6ea1SDimitry Andric 
224*0fca6ea1SDimitry Andric   switch (MOTy) {
225*0fca6ea1SDimitry Andric   case MachineOperand::MO_Register:
226*0fca6ea1SDimitry Andric     // Ignore all implicit register operands.
227*0fca6ea1SDimitry Andric     if (MO.isImplicit())
228*0fca6ea1SDimitry Andric       break;
229*0fca6ea1SDimitry Andric     return MCOperand::createReg(MO.getReg());
230*0fca6ea1SDimitry Andric   case MachineOperand::MO_Immediate:
231*0fca6ea1SDimitry Andric     return MCOperand::createImm(MO.getImm() + Offset);
232*0fca6ea1SDimitry Andric   case MachineOperand::MO_RegisterMask:
233*0fca6ea1SDimitry Andric     break;
234*0fca6ea1SDimitry Andric   case MachineOperand::MO_GlobalAddress:
235*0fca6ea1SDimitry Andric   case MachineOperand::MO_MachineBasicBlock:
236*0fca6ea1SDimitry Andric   case MachineOperand::MO_BlockAddress:
237*0fca6ea1SDimitry Andric   case MachineOperand::MO_ExternalSymbol:
238*0fca6ea1SDimitry Andric   case MachineOperand::MO_JumpTableIndex:
239*0fca6ea1SDimitry Andric   case MachineOperand::MO_ConstantPoolIndex:
240*0fca6ea1SDimitry Andric     return LowerSymbolOperand(MO, MOTy, Offset);
241*0fca6ea1SDimitry Andric   default:
242*0fca6ea1SDimitry Andric     report_fatal_error("unknown operand type");
243*0fca6ea1SDimitry Andric   }
244*0fca6ea1SDimitry Andric 
245*0fca6ea1SDimitry Andric   return MCOperand();
246*0fca6ea1SDimitry Andric }
247*0fca6ea1SDimitry Andric 
248*0fca6ea1SDimitry Andric void XtensaAsmPrinter::lowerToMCInst(const MachineInstr *MI,
249*0fca6ea1SDimitry Andric                                      MCInst &OutMI) const {
250*0fca6ea1SDimitry Andric   OutMI.setOpcode(MI->getOpcode());
251*0fca6ea1SDimitry Andric 
252*0fca6ea1SDimitry Andric   for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
253*0fca6ea1SDimitry Andric     const MachineOperand &MO = MI->getOperand(i);
254*0fca6ea1SDimitry Andric     MCOperand MCOp = lowerOperand(MO);
255*0fca6ea1SDimitry Andric 
256*0fca6ea1SDimitry Andric     if (MCOp.isValid())
257*0fca6ea1SDimitry Andric       OutMI.addOperand(MCOp);
258*0fca6ea1SDimitry Andric   }
259*0fca6ea1SDimitry Andric }
260*0fca6ea1SDimitry Andric 
261*0fca6ea1SDimitry Andric extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeXtensaAsmPrinter() {
262*0fca6ea1SDimitry Andric   RegisterAsmPrinter<XtensaAsmPrinter> A(getTheXtensaTarget());
263*0fca6ea1SDimitry Andric }
264