//===- XtensaAsmPrinter.cpp Xtensa LLVM Assembly Printer ------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This file contains a printer that converts from our internal representation // of machine-dependent LLVM code to GAS-format Xtensa assembly language. // //===----------------------------------------------------------------------===// #include "XtensaAsmPrinter.h" #include "MCTargetDesc/XtensaMCExpr.h" #include "MCTargetDesc/XtensaTargetStreamer.h" #include "TargetInfo/XtensaTargetInfo.h" #include "XtensaConstantPoolValue.h" #include "llvm/ADT/StringExtras.h" #include "llvm/BinaryFormat/ELF.h" #include "llvm/CodeGen/MachineConstantPool.h" #include "llvm/CodeGen/MachineModuleInfoImpls.h" #include "llvm/CodeGen/TargetLoweringObjectFileImpl.h" #include "llvm/MC/MCExpr.h" #include "llvm/MC/MCInstBuilder.h" #include "llvm/MC/MCSectionELF.h" #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCSymbol.h" #include "llvm/MC/MCSymbolELF.h" #include "llvm/MC/TargetRegistry.h" using namespace llvm; static MCSymbolRefExpr::VariantKind getModifierVariantKind(XtensaCP::XtensaCPModifier Modifier) { switch (Modifier) { case XtensaCP::no_modifier: return MCSymbolRefExpr::VK_None; case XtensaCP::TPOFF: return MCSymbolRefExpr::VK_TPOFF; } report_fatal_error("Invalid XtensaCPModifier!"); } void XtensaAsmPrinter::emitInstruction(const MachineInstr *MI) { unsigned Opc = MI->getOpcode(); switch (Opc) { case Xtensa::BR_JT: EmitToStreamer( *OutStreamer, MCInstBuilder(Xtensa::JX).addReg(MI->getOperand(0).getReg())); return; default: MCInst LoweredMI; lowerToMCInst(MI, LoweredMI); EmitToStreamer(*OutStreamer, LoweredMI); return; } } void XtensaAsmPrinter::emitMachineConstantPoolValue( MachineConstantPoolValue *MCPV) { XtensaConstantPoolValue *ACPV = static_cast(MCPV); MCSymbol *MCSym; if (ACPV->isBlockAddress()) { const BlockAddress *BA = cast(ACPV)->getBlockAddress(); MCSym = GetBlockAddressSymbol(BA); } else if (ACPV->isJumpTable()) { unsigned Idx = cast(ACPV)->getIndex(); MCSym = this->GetJTISymbol(Idx, false); } else { assert(ACPV->isExtSymbol() && "unrecognized constant pool value"); XtensaConstantPoolSymbol *XtensaSym = cast(ACPV); const char *SymName = XtensaSym->getSymbol(); if (XtensaSym->isPrivateLinkage()) { const DataLayout &DL = getDataLayout(); MCSym = OutContext.getOrCreateSymbol(Twine(DL.getPrivateGlobalPrefix()) + SymName); } else { MCSym = OutContext.getOrCreateSymbol(SymName); } } MCSymbol *LblSym = GetCPISymbol(ACPV->getLabelId()); auto *TS = static_cast(OutStreamer->getTargetStreamer()); MCSymbolRefExpr::VariantKind VK = getModifierVariantKind(ACPV->getModifier()); if (ACPV->getModifier() != XtensaCP::no_modifier) { std::string SymName(MCSym->getName()); StringRef Modifier = ACPV->getModifierText(); SymName += Modifier; MCSym = OutContext.getOrCreateSymbol(SymName); } const MCExpr *Expr = MCSymbolRefExpr::create(MCSym, VK, OutContext); TS->emitLiteral(LblSym, Expr, false); } void XtensaAsmPrinter::emitMachineConstantPoolEntry( const MachineConstantPoolEntry &CPE, int i) { if (CPE.isMachineConstantPoolEntry()) { XtensaConstantPoolValue *ACPV = static_cast(CPE.Val.MachineCPVal); ACPV->setLabelId(i); emitMachineConstantPoolValue(CPE.Val.MachineCPVal); } else { MCSymbol *LblSym = GetCPISymbol(i); auto *TS = static_cast(OutStreamer->getTargetStreamer()); const Constant *C = CPE.Val.ConstVal; const MCExpr *Value = nullptr; Type *Ty = C->getType(); if (const auto *CFP = dyn_cast(C)) { Value = MCConstantExpr::create( CFP->getValueAPF().bitcastToAPInt().getSExtValue(), OutContext); } else if (const auto *CI = dyn_cast(C)) { Value = MCConstantExpr::create(CI->getValue().getSExtValue(), OutContext); } else if (isa(Ty)) { Value = lowerConstant(C); } else { llvm_unreachable("unexpected constant pool entry type"); } TS->emitLiteral(LblSym, Value, false); } } // EmitConstantPool - Print to the current output stream assembly // representations of the constants in the constant pool MCP. This is // used to print out constants which have been "spilled to memory" by // the code generator. void XtensaAsmPrinter::emitConstantPool() { const Function &F = MF->getFunction(); const MachineConstantPool *MCP = MF->getConstantPool(); const std::vector &CP = MCP->getConstants(); if (CP.empty()) return; OutStreamer->pushSection(); auto *TS = static_cast(OutStreamer->getTargetStreamer()); MCSection *CS = getObjFileLowering().SectionForGlobal(&F, TM); TS->startLiteralSection(CS); int CPIdx = 0; for (const MachineConstantPoolEntry &CPE : CP) { emitMachineConstantPoolEntry(CPE, CPIdx++); } OutStreamer->popSection(); } MCSymbol * XtensaAsmPrinter::GetConstantPoolIndexSymbol(const MachineOperand &MO) const { // Create a symbol for the name. return GetCPISymbol(MO.getIndex()); } MCSymbol *XtensaAsmPrinter::GetJumpTableSymbol(const MachineOperand &MO) const { return GetJTISymbol(MO.getIndex()); } MCOperand XtensaAsmPrinter::LowerSymbolOperand(const MachineOperand &MO, MachineOperand::MachineOperandType MOTy, unsigned Offset) const { const MCSymbol *Symbol; XtensaMCExpr::VariantKind Kind = XtensaMCExpr::VK_Xtensa_None; switch (MOTy) { case MachineOperand::MO_GlobalAddress: Symbol = getSymbol(MO.getGlobal()); Offset += MO.getOffset(); break; case MachineOperand::MO_MachineBasicBlock: Symbol = MO.getMBB()->getSymbol(); break; case MachineOperand::MO_BlockAddress: Symbol = GetBlockAddressSymbol(MO.getBlockAddress()); Offset += MO.getOffset(); break; case MachineOperand::MO_ExternalSymbol: Symbol = GetExternalSymbolSymbol(MO.getSymbolName()); Offset += MO.getOffset(); break; case MachineOperand::MO_JumpTableIndex: Symbol = GetJumpTableSymbol(MO); break; case MachineOperand::MO_ConstantPoolIndex: Symbol = GetConstantPoolIndexSymbol(MO); Offset += MO.getOffset(); break; default: report_fatal_error(""); } const MCExpr *ME = MCSymbolRefExpr::create(Symbol, MCSymbolRefExpr::VK_None, OutContext); ME = XtensaMCExpr::create(ME, Kind, OutContext); if (Offset) { // Assume offset is never negative. assert(Offset > 0); const MCConstantExpr *OffsetExpr = MCConstantExpr::create(Offset, OutContext); ME = MCBinaryExpr::createAdd(ME, OffsetExpr, OutContext); } return MCOperand::createExpr(ME); } MCOperand XtensaAsmPrinter::lowerOperand(const MachineOperand &MO, unsigned Offset) const { MachineOperand::MachineOperandType MOTy = MO.getType(); switch (MOTy) { case MachineOperand::MO_Register: // Ignore all implicit register operands. if (MO.isImplicit()) break; return MCOperand::createReg(MO.getReg()); case MachineOperand::MO_Immediate: return MCOperand::createImm(MO.getImm() + Offset); case MachineOperand::MO_RegisterMask: break; case MachineOperand::MO_GlobalAddress: case MachineOperand::MO_MachineBasicBlock: case MachineOperand::MO_BlockAddress: case MachineOperand::MO_ExternalSymbol: case MachineOperand::MO_JumpTableIndex: case MachineOperand::MO_ConstantPoolIndex: return LowerSymbolOperand(MO, MOTy, Offset); default: report_fatal_error("unknown operand type"); } return MCOperand(); } void XtensaAsmPrinter::lowerToMCInst(const MachineInstr *MI, MCInst &OutMI) const { OutMI.setOpcode(MI->getOpcode()); for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) { const MachineOperand &MO = MI->getOperand(i); MCOperand MCOp = lowerOperand(MO); if (MCOp.isValid()) OutMI.addOperand(MCOp); } } extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeXtensaAsmPrinter() { RegisterAsmPrinter A(getTheXtensaTarget()); }