//===- 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/XtensaInstPrinter.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<XtensaConstantPoolValue *>(MCPV);
MCSymbol *MCSym;
if (ACPV->isBlockAddress()) {
const BlockAddress *BA =
cast<XtensaConstantPoolConstant>(ACPV)->getBlockAddress();
MCSym = GetBlockAddressSymbol(BA);
} else if (ACPV->isJumpTable()) {
unsigned Idx = cast<XtensaConstantPoolJumpTable>(ACPV)->getIndex();
MCSym = this->GetJTISymbol(Idx, false);
} else {
assert(ACPV->isExtSymbol() && "unrecognized constant pool value");
XtensaConstantPoolSymbol *XtensaSym = cast<XtensaConstantPoolSymbol>(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<XtensaTargetStreamer *>(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<XtensaConstantPoolValue *>(CPE.Val.MachineCPVal);
ACPV->setLabelId(i);
emitMachineConstantPoolValue(CPE.Val.MachineCPVal);
} else {
MCSymbol *LblSym = GetCPISymbol(i);
auto *TS =
static_cast<XtensaTargetStreamer *>(OutStreamer->getTargetStreamer());
const Constant *C = CPE.Val.ConstVal;
const MCExpr *Value = nullptr;
Type *Ty = C->getType();
if (const auto *CFP = dyn_cast<ConstantFP>(C)) {
Value = MCConstantExpr::create(
CFP->getValueAPF().bitcastToAPInt().getSExtValue(), OutContext);
} else if (const auto *CI = dyn_cast<ConstantInt>(C)) {
Value = MCConstantExpr::create(CI->getValue().getSExtValue(), OutContext);
} else if (isa<PointerType>(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<MachineConstantPoolEntry> &CP = MCP->getConstants();
if (CP.empty())
return;
OutStreamer->pushSection();
auto *TS =
static_cast<XtensaTargetStreamer *>(OutStreamer->getTargetStreamer());
MCSection *CS = getObjFileLowering().SectionForGlobal(&F, TM);
TS->startLiteralSection(CS);
int CPIdx = 0;
for (const MachineConstantPoolEntry &CPE : CP) {
emitMachineConstantPoolEntry(CPE, CPIdx++);
}
OutStreamer->popSection();
}
void XtensaAsmPrinter::printOperand(const MachineInstr *MI, int OpNo,
raw_ostream &O) {
const MachineOperand &MO = MI->getOperand(OpNo);
switch (MO.getType()) {
case MachineOperand::MO_Register:
case MachineOperand::MO_Immediate: {
MCOperand MC = lowerOperand(MI->getOperand(OpNo));
XtensaInstPrinter::printOperand(MC, O);
break;
}
default:
llvm_unreachable("unknown operand type");
}
}
bool XtensaAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
const char *ExtraCode, raw_ostream &O) {
// Print the operand if there is no operand modifier.
if (!ExtraCode || !ExtraCode[0]) {
printOperand(MI, OpNo, O);
return false;
}
// Fallback to the default implementation.
return AsmPrinter::PrintAsmOperand(MI, OpNo, ExtraCode, O);
}
bool XtensaAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,
unsigned OpNo,
const char *ExtraCode,
raw_ostream &OS) {
if (ExtraCode && ExtraCode[0])
return true; // Unknown modifier.
assert(OpNo + 1 < MI->getNumOperands() && "Insufficient operands");
const MachineOperand &Base = MI->getOperand(OpNo);
const MachineOperand &Offset = MI->getOperand(OpNo + 1);
assert(Base.isReg() &&
"Unexpected base pointer for inline asm memory operand.");
assert(Offset.isImm() && "Unexpected offset for inline asm memory operand.");
OS << XtensaInstPrinter::getRegisterName(Base.getReg());
OS << ", ";
OS << Offset.getImm();
return false;
}
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("<unknown operand type>");
}
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<XtensaAsmPrinter> A(getTheXtensaTarget());
}