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