diff options
Diffstat (limited to 'contrib/llvm-project/llvm/lib/Target/PowerPC/MCTargetDesc')
20 files changed, 4236 insertions, 0 deletions
diff --git a/contrib/llvm-project/llvm/lib/Target/PowerPC/MCTargetDesc/PPCAsmBackend.cpp b/contrib/llvm-project/llvm/lib/Target/PowerPC/MCTargetDesc/PPCAsmBackend.cpp new file mode 100644 index 000000000000..251737ed1275 --- /dev/null +++ b/contrib/llvm-project/llvm/lib/Target/PowerPC/MCTargetDesc/PPCAsmBackend.cpp @@ -0,0 +1,300 @@ +//===-- PPCAsmBackend.cpp - PPC Assembler Backend -------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "MCTargetDesc/PPCFixupKinds.h" +#include "MCTargetDesc/PPCMCTargetDesc.h" +#include "llvm/BinaryFormat/ELF.h" +#include "llvm/BinaryFormat/MachO.h" +#include "llvm/MC/MCAsmBackend.h" +#include "llvm/MC/MCAssembler.h" +#include "llvm/MC/MCELFObjectWriter.h" +#include "llvm/MC/MCFixupKindInfo.h" +#include "llvm/MC/MCMachObjectWriter.h" +#include "llvm/MC/MCObjectWriter.h" +#include "llvm/MC/MCSectionMachO.h" +#include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/MC/MCSymbolELF.h" +#include "llvm/MC/MCSymbolXCOFF.h" +#include "llvm/MC/MCValue.h" +#include "llvm/MC/TargetRegistry.h" +#include "llvm/Support/ErrorHandling.h" +using namespace llvm; + +static uint64_t adjustFixupValue(unsigned Kind, uint64_t Value) { + switch (Kind) { + default: + llvm_unreachable("Unknown fixup kind!"); + case FK_Data_1: + case FK_Data_2: + case FK_Data_4: + case FK_Data_8: + case PPC::fixup_ppc_nofixup: + return Value; + case PPC::fixup_ppc_brcond14: + case PPC::fixup_ppc_brcond14abs: + return Value & 0xfffc; + case PPC::fixup_ppc_br24: + case PPC::fixup_ppc_br24abs: + case PPC::fixup_ppc_br24_notoc: + return Value & 0x3fffffc; + case PPC::fixup_ppc_half16: + return Value & 0xffff; + case PPC::fixup_ppc_half16ds: + case PPC::fixup_ppc_half16dq: + return Value & 0xfffc; + case PPC::fixup_ppc_pcrel34: + case PPC::fixup_ppc_imm34: + return Value & 0x3ffffffff; + } +} + +static unsigned getFixupKindNumBytes(unsigned Kind) { + switch (Kind) { + default: + llvm_unreachable("Unknown fixup kind!"); + case FK_Data_1: + return 1; + case FK_Data_2: + case PPC::fixup_ppc_half16: + case PPC::fixup_ppc_half16ds: + case PPC::fixup_ppc_half16dq: + return 2; + case FK_Data_4: + case PPC::fixup_ppc_brcond14: + case PPC::fixup_ppc_brcond14abs: + case PPC::fixup_ppc_br24: + case PPC::fixup_ppc_br24abs: + case PPC::fixup_ppc_br24_notoc: + return 4; + case PPC::fixup_ppc_pcrel34: + case PPC::fixup_ppc_imm34: + case FK_Data_8: + return 8; + case PPC::fixup_ppc_nofixup: + return 0; + } +} + +namespace { + +class PPCAsmBackend : public MCAsmBackend { +protected: + Triple TT; +public: + PPCAsmBackend(const Target &T, const Triple &TT) + : MCAsmBackend(TT.isLittleEndian() ? llvm::endianness::little + : llvm::endianness::big), + TT(TT) {} + + unsigned getNumFixupKinds() const override { + return PPC::NumTargetFixupKinds; + } + + const MCFixupKindInfo &getFixupKindInfo(MCFixupKind Kind) const override { + const static MCFixupKindInfo InfosBE[PPC::NumTargetFixupKinds] = { + // name offset bits flags + { "fixup_ppc_br24", 6, 24, MCFixupKindInfo::FKF_IsPCRel }, + { "fixup_ppc_br24_notoc", 6, 24, MCFixupKindInfo::FKF_IsPCRel }, + { "fixup_ppc_brcond14", 16, 14, MCFixupKindInfo::FKF_IsPCRel }, + { "fixup_ppc_br24abs", 6, 24, 0 }, + { "fixup_ppc_brcond14abs", 16, 14, 0 }, + { "fixup_ppc_half16", 0, 16, 0 }, + { "fixup_ppc_half16ds", 0, 14, 0 }, + { "fixup_ppc_pcrel34", 0, 34, MCFixupKindInfo::FKF_IsPCRel }, + { "fixup_ppc_imm34", 0, 34, 0 }, + { "fixup_ppc_nofixup", 0, 0, 0 } + }; + const static MCFixupKindInfo InfosLE[PPC::NumTargetFixupKinds] = { + // name offset bits flags + { "fixup_ppc_br24", 2, 24, MCFixupKindInfo::FKF_IsPCRel }, + { "fixup_ppc_br24_notoc", 2, 24, MCFixupKindInfo::FKF_IsPCRel }, + { "fixup_ppc_brcond14", 2, 14, MCFixupKindInfo::FKF_IsPCRel }, + { "fixup_ppc_br24abs", 2, 24, 0 }, + { "fixup_ppc_brcond14abs", 2, 14, 0 }, + { "fixup_ppc_half16", 0, 16, 0 }, + { "fixup_ppc_half16ds", 2, 14, 0 }, + { "fixup_ppc_pcrel34", 0, 34, MCFixupKindInfo::FKF_IsPCRel }, + { "fixup_ppc_imm34", 0, 34, 0 }, + { "fixup_ppc_nofixup", 0, 0, 0 } + }; + + // Fixup kinds from .reloc directive are like R_PPC_NONE/R_PPC64_NONE. They + // do not require any extra processing. + if (Kind >= FirstLiteralRelocationKind) + return MCAsmBackend::getFixupKindInfo(FK_NONE); + + if (Kind < FirstTargetFixupKind) + return MCAsmBackend::getFixupKindInfo(Kind); + + assert(unsigned(Kind - FirstTargetFixupKind) < getNumFixupKinds() && + "Invalid kind!"); + return (Endian == llvm::endianness::little + ? InfosLE + : InfosBE)[Kind - FirstTargetFixupKind]; + } + + void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup, + const MCValue &Target, MutableArrayRef<char> Data, + uint64_t Value, bool IsResolved, + const MCSubtargetInfo *STI) const override { + MCFixupKind Kind = Fixup.getKind(); + if (Kind >= FirstLiteralRelocationKind) + return; + Value = adjustFixupValue(Kind, Value); + if (!Value) return; // Doesn't change encoding. + + unsigned Offset = Fixup.getOffset(); + unsigned NumBytes = getFixupKindNumBytes(Kind); + + // For each byte of the fragment that the fixup touches, mask in the bits + // from the fixup value. The Value has been "split up" into the appropriate + // bitfields above. + for (unsigned i = 0; i != NumBytes; ++i) { + unsigned Idx = + Endian == llvm::endianness::little ? i : (NumBytes - 1 - i); + Data[Offset + i] |= uint8_t((Value >> (Idx * 8)) & 0xff); + } + } + + bool shouldForceRelocation(const MCAssembler &Asm, const MCFixup &Fixup, + const MCValue &Target, + const MCSubtargetInfo *STI) override { + MCFixupKind Kind = Fixup.getKind(); + switch ((unsigned)Kind) { + default: + return Kind >= FirstLiteralRelocationKind; + case PPC::fixup_ppc_br24: + case PPC::fixup_ppc_br24abs: + case PPC::fixup_ppc_br24_notoc: + // If the target symbol has a local entry point we must not attempt + // to resolve the fixup directly. Emit a relocation and leave + // resolution of the final target address to the linker. + if (const MCSymbolRefExpr *A = Target.getSymA()) { + if (const auto *S = dyn_cast<MCSymbolELF>(&A->getSymbol())) { + // The "other" values are stored in the last 6 bits of the second + // byte. The traditional defines for STO values assume the full byte + // and thus the shift to pack it. + unsigned Other = S->getOther() << 2; + if ((Other & ELF::STO_PPC64_LOCAL_MASK) != 0) + return true; + } else if (const auto *S = dyn_cast<MCSymbolXCOFF>(&A->getSymbol())) { + return !Target.isAbsolute() && S->isExternal() && + S->getStorageClass() == XCOFF::C_WEAKEXT; + } + } + return false; + } + } + + bool fixupNeedsRelaxation(const MCFixup &Fixup, + uint64_t Value, + const MCRelaxableFragment *DF, + const MCAsmLayout &Layout) const override { + // FIXME. + llvm_unreachable("relaxInstruction() unimplemented"); + } + + void relaxInstruction(MCInst &Inst, + const MCSubtargetInfo &STI) const override { + // FIXME. + llvm_unreachable("relaxInstruction() unimplemented"); + } + + bool writeNopData(raw_ostream &OS, uint64_t Count, + const MCSubtargetInfo *STI) const override { + uint64_t NumNops = Count / 4; + for (uint64_t i = 0; i != NumNops; ++i) + support::endian::write<uint32_t>(OS, 0x60000000, Endian); + + OS.write_zeros(Count % 4); + + return true; + } +}; +} // end anonymous namespace + + +// FIXME: This should be in a separate file. +namespace { + +class ELFPPCAsmBackend : public PPCAsmBackend { +public: + ELFPPCAsmBackend(const Target &T, const Triple &TT) : PPCAsmBackend(T, TT) {} + + std::unique_ptr<MCObjectTargetWriter> + createObjectTargetWriter() const override { + uint8_t OSABI = MCELFObjectTargetWriter::getOSABI(TT.getOS()); + bool Is64 = TT.isPPC64(); + return createPPCELFObjectWriter(Is64, OSABI); + } + + std::optional<MCFixupKind> getFixupKind(StringRef Name) const override; +}; + +class XCOFFPPCAsmBackend : public PPCAsmBackend { +public: + XCOFFPPCAsmBackend(const Target &T, const Triple &TT) + : PPCAsmBackend(T, TT) {} + + std::unique_ptr<MCObjectTargetWriter> + createObjectTargetWriter() const override { + return createPPCXCOFFObjectWriter(TT.isArch64Bit()); + } + + std::optional<MCFixupKind> getFixupKind(StringRef Name) const override; +}; + +} // end anonymous namespace + +std::optional<MCFixupKind> +ELFPPCAsmBackend::getFixupKind(StringRef Name) const { + if (TT.isOSBinFormatELF()) { + unsigned Type; + if (TT.isPPC64()) { + Type = llvm::StringSwitch<unsigned>(Name) +#define ELF_RELOC(X, Y) .Case(#X, Y) +#include "llvm/BinaryFormat/ELFRelocs/PowerPC64.def" +#undef ELF_RELOC + .Case("BFD_RELOC_NONE", ELF::R_PPC64_NONE) + .Case("BFD_RELOC_16", ELF::R_PPC64_ADDR16) + .Case("BFD_RELOC_32", ELF::R_PPC64_ADDR32) + .Case("BFD_RELOC_64", ELF::R_PPC64_ADDR64) + .Default(-1u); + } else { + Type = llvm::StringSwitch<unsigned>(Name) +#define ELF_RELOC(X, Y) .Case(#X, Y) +#include "llvm/BinaryFormat/ELFRelocs/PowerPC.def" +#undef ELF_RELOC + .Case("BFD_RELOC_NONE", ELF::R_PPC_NONE) + .Case("BFD_RELOC_16", ELF::R_PPC_ADDR16) + .Case("BFD_RELOC_32", ELF::R_PPC_ADDR32) + .Default(-1u); + } + if (Type != -1u) + return static_cast<MCFixupKind>(FirstLiteralRelocationKind + Type); + } + return std::nullopt; +} + +std::optional<MCFixupKind> +XCOFFPPCAsmBackend::getFixupKind(StringRef Name) const { + return StringSwitch<std::optional<MCFixupKind>>(Name) + .Case("R_REF", (MCFixupKind)PPC::fixup_ppc_nofixup) + .Default(std::nullopt); +} + +MCAsmBackend *llvm::createPPCAsmBackend(const Target &T, + const MCSubtargetInfo &STI, + const MCRegisterInfo &MRI, + const MCTargetOptions &Options) { + const Triple &TT = STI.getTargetTriple(); + if (TT.isOSBinFormatXCOFF()) + return new XCOFFPPCAsmBackend(T, TT); + + return new ELFPPCAsmBackend(T, TT); +} diff --git a/contrib/llvm-project/llvm/lib/Target/PowerPC/MCTargetDesc/PPCELFObjectWriter.cpp b/contrib/llvm-project/llvm/lib/Target/PowerPC/MCTargetDesc/PPCELFObjectWriter.cpp new file mode 100644 index 000000000000..6a72b7b9ad05 --- /dev/null +++ b/contrib/llvm-project/llvm/lib/Target/PowerPC/MCTargetDesc/PPCELFObjectWriter.cpp @@ -0,0 +1,497 @@ +//===-- PPCELFObjectWriter.cpp - PPC ELF Writer ---------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "MCTargetDesc/PPCFixupKinds.h" +#include "MCTargetDesc/PPCMCExpr.h" +#include "MCTargetDesc/PPCMCTargetDesc.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/MC/MCELFObjectWriter.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCObjectWriter.h" +#include "llvm/MC/MCSymbolELF.h" +#include "llvm/MC/MCValue.h" +#include "llvm/Support/ErrorHandling.h" + +using namespace llvm; + +namespace { + class PPCELFObjectWriter : public MCELFObjectTargetWriter { + public: + PPCELFObjectWriter(bool Is64Bit, uint8_t OSABI); + + protected: + unsigned getRelocType(MCContext &Ctx, const MCValue &Target, + const MCFixup &Fixup, bool IsPCRel) const override; + + bool needsRelocateWithSymbol(const MCValue &Val, const MCSymbol &Sym, + unsigned Type) const override; + }; +} + +PPCELFObjectWriter::PPCELFObjectWriter(bool Is64Bit, uint8_t OSABI) + : MCELFObjectTargetWriter(Is64Bit, OSABI, + Is64Bit ? ELF::EM_PPC64 : ELF::EM_PPC, + /*HasRelocationAddend*/ true) {} + +static MCSymbolRefExpr::VariantKind getAccessVariant(const MCValue &Target, + const MCFixup &Fixup) { + const MCExpr *Expr = Fixup.getValue(); + + if (Expr->getKind() != MCExpr::Target) + return Target.getAccessVariant(); + + switch (cast<PPCMCExpr>(Expr)->getKind()) { + case PPCMCExpr::VK_PPC_None: + return MCSymbolRefExpr::VK_None; + case PPCMCExpr::VK_PPC_LO: + return MCSymbolRefExpr::VK_PPC_LO; + case PPCMCExpr::VK_PPC_HI: + return MCSymbolRefExpr::VK_PPC_HI; + case PPCMCExpr::VK_PPC_HA: + return MCSymbolRefExpr::VK_PPC_HA; + case PPCMCExpr::VK_PPC_HIGH: + return MCSymbolRefExpr::VK_PPC_HIGH; + case PPCMCExpr::VK_PPC_HIGHA: + return MCSymbolRefExpr::VK_PPC_HIGHA; + case PPCMCExpr::VK_PPC_HIGHERA: + return MCSymbolRefExpr::VK_PPC_HIGHERA; + case PPCMCExpr::VK_PPC_HIGHER: + return MCSymbolRefExpr::VK_PPC_HIGHER; + case PPCMCExpr::VK_PPC_HIGHEST: + return MCSymbolRefExpr::VK_PPC_HIGHEST; + case PPCMCExpr::VK_PPC_HIGHESTA: + return MCSymbolRefExpr::VK_PPC_HIGHESTA; + } + llvm_unreachable("unknown PPCMCExpr kind"); +} + +unsigned PPCELFObjectWriter::getRelocType(MCContext &Ctx, const MCValue &Target, + const MCFixup &Fixup, + bool IsPCRel) const { + MCFixupKind Kind = Fixup.getKind(); + if (Kind >= FirstLiteralRelocationKind) + return Kind - FirstLiteralRelocationKind; + MCSymbolRefExpr::VariantKind Modifier = getAccessVariant(Target, Fixup); + + // determine the type of the relocation + unsigned Type; + if (IsPCRel) { + switch (Fixup.getTargetKind()) { + default: + llvm_unreachable("Unimplemented"); + case PPC::fixup_ppc_br24: + case PPC::fixup_ppc_br24abs: + case PPC::fixup_ppc_br24_notoc: + switch (Modifier) { + default: llvm_unreachable("Unsupported Modifier"); + case MCSymbolRefExpr::VK_None: + Type = ELF::R_PPC_REL24; + break; + case MCSymbolRefExpr::VK_PLT: + Type = ELF::R_PPC_PLTREL24; + break; + case MCSymbolRefExpr::VK_PPC_LOCAL: + Type = ELF::R_PPC_LOCAL24PC; + break; + case MCSymbolRefExpr::VK_PPC_NOTOC: + Type = ELF::R_PPC64_REL24_NOTOC; + break; + } + break; + case PPC::fixup_ppc_brcond14: + case PPC::fixup_ppc_brcond14abs: + Type = ELF::R_PPC_REL14; + break; + case PPC::fixup_ppc_half16: + switch (Modifier) { + default: llvm_unreachable("Unsupported Modifier"); + case MCSymbolRefExpr::VK_None: + Type = ELF::R_PPC_REL16; + break; + case MCSymbolRefExpr::VK_PPC_LO: + Type = ELF::R_PPC_REL16_LO; + break; + case MCSymbolRefExpr::VK_PPC_HI: + Type = ELF::R_PPC_REL16_HI; + break; + case MCSymbolRefExpr::VK_PPC_HA: + Type = ELF::R_PPC_REL16_HA; + break; + } + break; + case PPC::fixup_ppc_half16ds: + case PPC::fixup_ppc_half16dq: + Target.print(errs()); + errs() << '\n'; + report_fatal_error("Invalid PC-relative half16ds relocation"); + case PPC::fixup_ppc_pcrel34: + switch (Modifier) { + default: + llvm_unreachable("Unsupported Modifier for fixup_ppc_pcrel34"); + case MCSymbolRefExpr::VK_PCREL: + Type = ELF::R_PPC64_PCREL34; + break; + case MCSymbolRefExpr::VK_PPC_GOT_PCREL: + Type = ELF::R_PPC64_GOT_PCREL34; + break; + case MCSymbolRefExpr::VK_PPC_GOT_TLSGD_PCREL: + Type = ELF::R_PPC64_GOT_TLSGD_PCREL34; + break; + case MCSymbolRefExpr::VK_PPC_GOT_TLSLD_PCREL: + Type = ELF::R_PPC64_GOT_TLSLD_PCREL34; + break; + case MCSymbolRefExpr::VK_PPC_GOT_TPREL_PCREL: + Type = ELF::R_PPC64_GOT_TPREL_PCREL34; + break; + } + break; + case FK_Data_4: + case FK_PCRel_4: + Type = ELF::R_PPC_REL32; + break; + case FK_Data_8: + case FK_PCRel_8: + Type = ELF::R_PPC64_REL64; + break; + } + } else { + switch (Fixup.getTargetKind()) { + default: llvm_unreachable("invalid fixup kind!"); + case PPC::fixup_ppc_br24abs: + Type = ELF::R_PPC_ADDR24; + break; + case PPC::fixup_ppc_brcond14abs: + Type = ELF::R_PPC_ADDR14; // XXX: or BRNTAKEN?_ + break; + case PPC::fixup_ppc_half16: + switch (Modifier) { + default: llvm_unreachable("Unsupported Modifier"); + case MCSymbolRefExpr::VK_None: + Type = ELF::R_PPC_ADDR16; + break; + case MCSymbolRefExpr::VK_PPC_LO: + Type = ELF::R_PPC_ADDR16_LO; + break; + case MCSymbolRefExpr::VK_PPC_HI: + Type = ELF::R_PPC_ADDR16_HI; + break; + case MCSymbolRefExpr::VK_PPC_HA: + Type = ELF::R_PPC_ADDR16_HA; + break; + case MCSymbolRefExpr::VK_PPC_HIGH: + Type = ELF::R_PPC64_ADDR16_HIGH; + break; + case MCSymbolRefExpr::VK_PPC_HIGHA: + Type = ELF::R_PPC64_ADDR16_HIGHA; + break; + case MCSymbolRefExpr::VK_PPC_HIGHER: + Type = ELF::R_PPC64_ADDR16_HIGHER; + break; + case MCSymbolRefExpr::VK_PPC_HIGHERA: + Type = ELF::R_PPC64_ADDR16_HIGHERA; + break; + case MCSymbolRefExpr::VK_PPC_HIGHEST: + Type = ELF::R_PPC64_ADDR16_HIGHEST; + break; + case MCSymbolRefExpr::VK_PPC_HIGHESTA: + Type = ELF::R_PPC64_ADDR16_HIGHESTA; + break; + case MCSymbolRefExpr::VK_GOT: + Type = ELF::R_PPC_GOT16; + break; + case MCSymbolRefExpr::VK_PPC_GOT_LO: + Type = ELF::R_PPC_GOT16_LO; + break; + case MCSymbolRefExpr::VK_PPC_GOT_HI: + Type = ELF::R_PPC_GOT16_HI; + break; + case MCSymbolRefExpr::VK_PPC_GOT_HA: + Type = ELF::R_PPC_GOT16_HA; + break; + case MCSymbolRefExpr::VK_PPC_TOC: + Type = ELF::R_PPC64_TOC16; + break; + case MCSymbolRefExpr::VK_PPC_TOC_LO: + Type = ELF::R_PPC64_TOC16_LO; + break; + case MCSymbolRefExpr::VK_PPC_TOC_HI: + Type = ELF::R_PPC64_TOC16_HI; + break; + case MCSymbolRefExpr::VK_PPC_TOC_HA: + Type = ELF::R_PPC64_TOC16_HA; + break; + case MCSymbolRefExpr::VK_TPREL: + Type = ELF::R_PPC_TPREL16; + break; + case MCSymbolRefExpr::VK_PPC_TPREL_LO: + Type = ELF::R_PPC_TPREL16_LO; + break; + case MCSymbolRefExpr::VK_PPC_TPREL_HI: + Type = ELF::R_PPC_TPREL16_HI; + break; + case MCSymbolRefExpr::VK_PPC_TPREL_HA: + Type = ELF::R_PPC_TPREL16_HA; + break; + case MCSymbolRefExpr::VK_PPC_TPREL_HIGH: + Type = ELF::R_PPC64_TPREL16_HIGH; + break; + case MCSymbolRefExpr::VK_PPC_TPREL_HIGHA: + Type = ELF::R_PPC64_TPREL16_HIGHA; + break; + case MCSymbolRefExpr::VK_PPC_TPREL_HIGHER: + Type = ELF::R_PPC64_TPREL16_HIGHER; + break; + case MCSymbolRefExpr::VK_PPC_TPREL_HIGHERA: + Type = ELF::R_PPC64_TPREL16_HIGHERA; + break; + case MCSymbolRefExpr::VK_PPC_TPREL_HIGHEST: + Type = ELF::R_PPC64_TPREL16_HIGHEST; + break; + case MCSymbolRefExpr::VK_PPC_TPREL_HIGHESTA: + Type = ELF::R_PPC64_TPREL16_HIGHESTA; + break; + case MCSymbolRefExpr::VK_DTPREL: + Type = ELF::R_PPC64_DTPREL16; + break; + case MCSymbolRefExpr::VK_PPC_DTPREL_LO: + Type = ELF::R_PPC64_DTPREL16_LO; + break; + case MCSymbolRefExpr::VK_PPC_DTPREL_HI: + Type = ELF::R_PPC64_DTPREL16_HI; + break; + case MCSymbolRefExpr::VK_PPC_DTPREL_HA: + Type = ELF::R_PPC64_DTPREL16_HA; + break; + case MCSymbolRefExpr::VK_PPC_DTPREL_HIGH: + Type = ELF::R_PPC64_DTPREL16_HIGH; + break; + case MCSymbolRefExpr::VK_PPC_DTPREL_HIGHA: + Type = ELF::R_PPC64_DTPREL16_HIGHA; + break; + case MCSymbolRefExpr::VK_PPC_DTPREL_HIGHER: + Type = ELF::R_PPC64_DTPREL16_HIGHER; + break; + case MCSymbolRefExpr::VK_PPC_DTPREL_HIGHERA: + Type = ELF::R_PPC64_DTPREL16_HIGHERA; + break; + case MCSymbolRefExpr::VK_PPC_DTPREL_HIGHEST: + Type = ELF::R_PPC64_DTPREL16_HIGHEST; + break; + case MCSymbolRefExpr::VK_PPC_DTPREL_HIGHESTA: + Type = ELF::R_PPC64_DTPREL16_HIGHESTA; + break; + case MCSymbolRefExpr::VK_PPC_GOT_TLSGD: + if (is64Bit()) + Type = ELF::R_PPC64_GOT_TLSGD16; + else + Type = ELF::R_PPC_GOT_TLSGD16; + break; + case MCSymbolRefExpr::VK_PPC_GOT_TLSGD_LO: + Type = ELF::R_PPC64_GOT_TLSGD16_LO; + break; + case MCSymbolRefExpr::VK_PPC_GOT_TLSGD_HI: + Type = ELF::R_PPC64_GOT_TLSGD16_HI; + break; + case MCSymbolRefExpr::VK_PPC_GOT_TLSGD_HA: + Type = ELF::R_PPC64_GOT_TLSGD16_HA; + break; + case MCSymbolRefExpr::VK_PPC_GOT_TLSLD: + if (is64Bit()) + Type = ELF::R_PPC64_GOT_TLSLD16; + else + Type = ELF::R_PPC_GOT_TLSLD16; + break; + case MCSymbolRefExpr::VK_PPC_GOT_TLSLD_LO: + Type = ELF::R_PPC64_GOT_TLSLD16_LO; + break; + case MCSymbolRefExpr::VK_PPC_GOT_TLSLD_HI: + Type = ELF::R_PPC64_GOT_TLSLD16_HI; + break; + case MCSymbolRefExpr::VK_PPC_GOT_TLSLD_HA: + Type = ELF::R_PPC64_GOT_TLSLD16_HA; + break; + case MCSymbolRefExpr::VK_PPC_GOT_TPREL: + /* We don't have R_PPC64_GOT_TPREL16, but since GOT offsets + are always 4-aligned, we can use R_PPC64_GOT_TPREL16_DS. */ + Type = ELF::R_PPC64_GOT_TPREL16_DS; + break; + case MCSymbolRefExpr::VK_PPC_GOT_TPREL_LO: + /* We don't have R_PPC64_GOT_TPREL16_LO, but since GOT offsets + are always 4-aligned, we can use R_PPC64_GOT_TPREL16_LO_DS. */ + Type = ELF::R_PPC64_GOT_TPREL16_LO_DS; + break; + case MCSymbolRefExpr::VK_PPC_GOT_TPREL_HI: + Type = ELF::R_PPC64_GOT_TPREL16_HI; + break; + case MCSymbolRefExpr::VK_PPC_GOT_DTPREL: + /* We don't have R_PPC64_GOT_DTPREL16, but since GOT offsets + are always 4-aligned, we can use R_PPC64_GOT_DTPREL16_DS. */ + Type = ELF::R_PPC64_GOT_DTPREL16_DS; + break; + case MCSymbolRefExpr::VK_PPC_GOT_DTPREL_LO: + /* We don't have R_PPC64_GOT_DTPREL16_LO, but since GOT offsets + are always 4-aligned, we can use R_PPC64_GOT_DTPREL16_LO_DS. */ + Type = ELF::R_PPC64_GOT_DTPREL16_LO_DS; + break; + case MCSymbolRefExpr::VK_PPC_GOT_TPREL_HA: + Type = ELF::R_PPC64_GOT_TPREL16_HA; + break; + case MCSymbolRefExpr::VK_PPC_GOT_DTPREL_HI: + Type = ELF::R_PPC64_GOT_DTPREL16_HI; + break; + case MCSymbolRefExpr::VK_PPC_GOT_DTPREL_HA: + Type = ELF::R_PPC64_GOT_DTPREL16_HA; + break; + } + break; + case PPC::fixup_ppc_half16ds: + case PPC::fixup_ppc_half16dq: + switch (Modifier) { + default: llvm_unreachable("Unsupported Modifier"); + case MCSymbolRefExpr::VK_None: + Type = ELF::R_PPC64_ADDR16_DS; + break; + case MCSymbolRefExpr::VK_PPC_LO: + Type = ELF::R_PPC64_ADDR16_LO_DS; + break; + case MCSymbolRefExpr::VK_GOT: + Type = ELF::R_PPC64_GOT16_DS; + break; + case MCSymbolRefExpr::VK_PPC_GOT_LO: + Type = ELF::R_PPC64_GOT16_LO_DS; + break; + case MCSymbolRefExpr::VK_PPC_TOC: + Type = ELF::R_PPC64_TOC16_DS; + break; + case MCSymbolRefExpr::VK_PPC_TOC_LO: + Type = ELF::R_PPC64_TOC16_LO_DS; + break; + case MCSymbolRefExpr::VK_TPREL: + Type = ELF::R_PPC64_TPREL16_DS; + break; + case MCSymbolRefExpr::VK_PPC_TPREL_LO: + Type = ELF::R_PPC64_TPREL16_LO_DS; + break; + case MCSymbolRefExpr::VK_DTPREL: + Type = ELF::R_PPC64_DTPREL16_DS; + break; + case MCSymbolRefExpr::VK_PPC_DTPREL_LO: + Type = ELF::R_PPC64_DTPREL16_LO_DS; + break; + case MCSymbolRefExpr::VK_PPC_GOT_TPREL: + Type = ELF::R_PPC64_GOT_TPREL16_DS; + break; + case MCSymbolRefExpr::VK_PPC_GOT_TPREL_LO: + Type = ELF::R_PPC64_GOT_TPREL16_LO_DS; + break; + case MCSymbolRefExpr::VK_PPC_GOT_DTPREL: + Type = ELF::R_PPC64_GOT_DTPREL16_DS; + break; + case MCSymbolRefExpr::VK_PPC_GOT_DTPREL_LO: + Type = ELF::R_PPC64_GOT_DTPREL16_LO_DS; + break; + } + break; + case PPC::fixup_ppc_nofixup: + switch (Modifier) { + default: llvm_unreachable("Unsupported Modifier"); + case MCSymbolRefExpr::VK_PPC_TLSGD: + if (is64Bit()) + Type = ELF::R_PPC64_TLSGD; + else + Type = ELF::R_PPC_TLSGD; + break; + case MCSymbolRefExpr::VK_PPC_TLSLD: + if (is64Bit()) + Type = ELF::R_PPC64_TLSLD; + else + Type = ELF::R_PPC_TLSLD; + break; + case MCSymbolRefExpr::VK_PPC_TLS: + if (is64Bit()) + Type = ELF::R_PPC64_TLS; + else + Type = ELF::R_PPC_TLS; + break; + case MCSymbolRefExpr::VK_PPC_TLS_PCREL: + Type = ELF::R_PPC64_TLS; + break; + } + break; + case PPC::fixup_ppc_imm34: + switch (Modifier) { + default: + report_fatal_error("Unsupported Modifier for fixup_ppc_imm34."); + case MCSymbolRefExpr::VK_DTPREL: + Type = ELF::R_PPC64_DTPREL34; + break; + case MCSymbolRefExpr::VK_TPREL: + Type = ELF::R_PPC64_TPREL34; + break; + } + break; + case FK_Data_8: + switch (Modifier) { + default: llvm_unreachable("Unsupported Modifier"); + case MCSymbolRefExpr::VK_PPC_TOCBASE: + Type = ELF::R_PPC64_TOC; + break; + case MCSymbolRefExpr::VK_None: + Type = ELF::R_PPC64_ADDR64; + break; + case MCSymbolRefExpr::VK_PPC_DTPMOD: + Type = ELF::R_PPC64_DTPMOD64; + break; + case MCSymbolRefExpr::VK_TPREL: + Type = ELF::R_PPC64_TPREL64; + break; + case MCSymbolRefExpr::VK_DTPREL: + Type = ELF::R_PPC64_DTPREL64; + break; + } + break; + case FK_Data_4: + switch (Modifier) { + case MCSymbolRefExpr::VK_DTPREL: + Type = ELF::R_PPC_DTPREL32; + break; + default: + Type = ELF::R_PPC_ADDR32; + } + break; + case FK_Data_2: + Type = ELF::R_PPC_ADDR16; + break; + } + } + return Type; +} + +bool PPCELFObjectWriter::needsRelocateWithSymbol(const MCValue &, + const MCSymbol &Sym, + unsigned Type) const { + switch (Type) { + default: + return false; + + case ELF::R_PPC_REL24: + case ELF::R_PPC64_REL24_NOTOC: + // If the target symbol has a local entry point, we must keep the + // target symbol to preserve that information for the linker. + // The "other" values are stored in the last 6 bits of the second byte. + // The traditional defines for STO values assume the full byte and thus + // the shift to pack it. + unsigned Other = cast<MCSymbolELF>(Sym).getOther() << 2; + return (Other & ELF::STO_PPC64_LOCAL_MASK) != 0; + } +} + +std::unique_ptr<MCObjectTargetWriter> +llvm::createPPCELFObjectWriter(bool Is64Bit, uint8_t OSABI) { + return std::make_unique<PPCELFObjectWriter>(Is64Bit, OSABI); +} diff --git a/contrib/llvm-project/llvm/lib/Target/PowerPC/MCTargetDesc/PPCELFStreamer.cpp b/contrib/llvm-project/llvm/lib/Target/PowerPC/MCTargetDesc/PPCELFStreamer.cpp new file mode 100644 index 000000000000..1eaa57e16260 --- /dev/null +++ b/contrib/llvm-project/llvm/lib/Target/PowerPC/MCTargetDesc/PPCELFStreamer.cpp @@ -0,0 +1,229 @@ +//===-------- PPCELFStreamer.cpp - ELF Object Output ---------------------===// +// +// 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 is a custom MCELFStreamer for PowerPC. +// +// The purpose of the custom ELF streamer is to allow us to intercept +// instructions as they are being emitted and align all 8 byte instructions +// to a 64 byte boundary if required (by adding a 4 byte nop). This is important +// because 8 byte instructions are not allowed to cross 64 byte boundaries +// and by aliging anything that is within 4 bytes of the boundary we can +// guarantee that the 8 byte instructions do not cross that boundary. +// +//===----------------------------------------------------------------------===// + +#include "PPCELFStreamer.h" +#include "PPCFixupKinds.h" +#include "PPCMCCodeEmitter.h" +#include "PPCMCTargetDesc.h" +#include "llvm/BinaryFormat/ELF.h" +#include "llvm/MC/MCAsmBackend.h" +#include "llvm/MC/MCAssembler.h" +#include "llvm/MC/MCCodeEmitter.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCInst.h" +#include "llvm/MC/MCInstrDesc.h" +#include "llvm/MC/MCObjectWriter.h" +#include "llvm/MC/MCSymbolELF.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/SourceMgr.h" + +using namespace llvm; + +PPCELFStreamer::PPCELFStreamer(MCContext &Context, + std::unique_ptr<MCAsmBackend> MAB, + std::unique_ptr<MCObjectWriter> OW, + std::unique_ptr<MCCodeEmitter> Emitter) + : MCELFStreamer(Context, std::move(MAB), std::move(OW), std::move(Emitter)), + LastLabel(nullptr) {} + +void PPCELFStreamer::emitPrefixedInstruction(const MCInst &Inst, + const MCSubtargetInfo &STI) { + // Prefixed instructions must not cross a 64-byte boundary (i.e. prefix is + // before the boundary and the remaining 4-bytes are after the boundary). In + // order to achieve this, a nop is added prior to any such boundary-crossing + // prefixed instruction. Align to 64 bytes if possible but add a maximum of 4 + // bytes when trying to do that. If alignment requires adding more than 4 + // bytes then the instruction won't be aligned. When emitting a code alignment + // a new fragment is created for this alignment. This fragment will contain + // all of the nops required as part of the alignment operation. In the cases + // when no nops are added then The fragment is still created but it remains + // empty. + emitCodeAlignment(Align(64), &STI, 4); + + // Emit the instruction. + // Since the previous emit created a new fragment then adding this instruction + // also forces the addition of a new fragment. Inst is now the first + // instruction in that new fragment. + MCELFStreamer::emitInstruction(Inst, STI); + + // The above instruction is forced to start a new fragment because it + // comes after a code alignment fragment. Get that new fragment. + MCFragment *InstructionFragment = getCurrentFragment(); + SMLoc InstLoc = Inst.getLoc(); + // Check if there was a last label emitted. + if (LastLabel && !LastLabel->isUnset() && LastLabelLoc.isValid() && + InstLoc.isValid()) { + const SourceMgr *SourceManager = getContext().getSourceManager(); + unsigned InstLine = SourceManager->FindLineNumber(InstLoc); + unsigned LabelLine = SourceManager->FindLineNumber(LastLabelLoc); + // If the Label and the Instruction are on the same line then move the + // label to the top of the fragment containing the aligned instruction that + // was just added. + if (InstLine == LabelLine) { + assignFragment(LastLabel, InstructionFragment); + LastLabel->setOffset(0); + } + } +} + +void PPCELFStreamer::emitInstruction(const MCInst &Inst, + const MCSubtargetInfo &STI) { + PPCMCCodeEmitter *Emitter = + static_cast<PPCMCCodeEmitter*>(getAssembler().getEmitterPtr()); + + // If the instruction is a part of the GOT to PC-Rel link time optimization + // instruction pair, return a value, otherwise return std::nullopt. A true + // returned value means the instruction is the PLDpc and a false value means + // it is the user instruction. + std::optional<bool> IsPartOfGOTToPCRelPair = + isPartOfGOTToPCRelPair(Inst, STI); + + // User of the GOT-indirect address. + // For example, the load that will get the relocation as follows: + // .reloc .Lpcrel1-8,R_PPC64_PCREL_OPT,.-(.Lpcrel1-8) + // lwa 3, 4(3) + if (IsPartOfGOTToPCRelPair && !*IsPartOfGOTToPCRelPair) + emitGOTToPCRelReloc(Inst); + + // Special handling is only for prefixed instructions. + if (!Emitter->isPrefixedInstruction(Inst)) { + MCELFStreamer::emitInstruction(Inst, STI); + return; + } + emitPrefixedInstruction(Inst, STI); + + // Producer of the GOT-indirect address. + // For example, the prefixed load from the got that will get the label as + // follows: + // pld 3, vec@got@pcrel(0), 1 + // .Lpcrel1: + if (IsPartOfGOTToPCRelPair && *IsPartOfGOTToPCRelPair) + emitGOTToPCRelLabel(Inst); +} + +void PPCELFStreamer::emitLabel(MCSymbol *Symbol, SMLoc Loc) { + LastLabel = Symbol; + LastLabelLoc = Loc; + MCELFStreamer::emitLabel(Symbol); +} + +// This linker time GOT PC Relative optimization relocation will look like this: +// pld <reg> symbol@got@pcrel +// <Label###>: +// .reloc Label###-8,R_PPC64_PCREL_OPT,.-(Label###-8) +// load <loadedreg>, 0(<reg>) +// The reason we place the label after the PLDpc instruction is that there +// may be an alignment nop before it since prefixed instructions must not +// cross a 64-byte boundary (please see +// PPCELFStreamer::emitPrefixedInstruction()). When referring to the +// label, we subtract the width of a prefixed instruction (8 bytes) to ensure +// we refer to the PLDpc. +void PPCELFStreamer::emitGOTToPCRelReloc(const MCInst &Inst) { + // Get the last operand which contains the symbol. + const MCOperand &Operand = Inst.getOperand(Inst.getNumOperands() - 1); + assert(Operand.isExpr() && "Expecting an MCExpr."); + // Cast the last operand to MCSymbolRefExpr to get the symbol. + const MCExpr *Expr = Operand.getExpr(); + const MCSymbolRefExpr *SymExpr = static_cast<const MCSymbolRefExpr *>(Expr); + assert(SymExpr->getKind() == MCSymbolRefExpr::VK_PPC_PCREL_OPT && + "Expecting a symbol of type VK_PPC_PCREL_OPT"); + MCSymbol *LabelSym = + getContext().getOrCreateSymbol(SymExpr->getSymbol().getName()); + const MCExpr *LabelExpr = MCSymbolRefExpr::create(LabelSym, getContext()); + const MCExpr *Eight = MCConstantExpr::create(8, getContext()); + // SubExpr is just Label###-8 + const MCExpr *SubExpr = + MCBinaryExpr::createSub(LabelExpr, Eight, getContext()); + MCSymbol *CurrentLocation = getContext().createTempSymbol(); + const MCExpr *CurrentLocationExpr = + MCSymbolRefExpr::create(CurrentLocation, getContext()); + // SubExpr2 is .-(Label###-8) + const MCExpr *SubExpr2 = + MCBinaryExpr::createSub(CurrentLocationExpr, SubExpr, getContext()); + + MCDataFragment *DF = static_cast<MCDataFragment *>(LabelSym->getFragment()); + assert(DF && "Expecting a valid data fragment."); + MCFixupKind FixupKind = static_cast<MCFixupKind>(FirstLiteralRelocationKind + + ELF::R_PPC64_PCREL_OPT); + DF->getFixups().push_back( + MCFixup::create(LabelSym->getOffset() - 8, SubExpr2, + FixupKind, Inst.getLoc())); + emitLabel(CurrentLocation, Inst.getLoc()); +} + +// Emit the label that immediately follows the PLDpc for a link time GOT PC Rel +// optimization. +void PPCELFStreamer::emitGOTToPCRelLabel(const MCInst &Inst) { + // Get the last operand which contains the symbol. + const MCOperand &Operand = Inst.getOperand(Inst.getNumOperands() - 1); + assert(Operand.isExpr() && "Expecting an MCExpr."); + // Cast the last operand to MCSymbolRefExpr to get the symbol. + const MCExpr *Expr = Operand.getExpr(); + const MCSymbolRefExpr *SymExpr = static_cast<const MCSymbolRefExpr *>(Expr); + assert(SymExpr->getKind() == MCSymbolRefExpr::VK_PPC_PCREL_OPT && + "Expecting a symbol of type VK_PPC_PCREL_OPT"); + MCSymbol *LabelSym = + getContext().getOrCreateSymbol(SymExpr->getSymbol().getName()); + emitLabel(LabelSym, Inst.getLoc()); +} + +// This function checks if the parameter Inst is part of the setup for a link +// time GOT PC Relative optimization. For example in this situation: +// <MCInst PLDpc <MCOperand Reg:282> <MCOperand Expr:(glob_double@got@pcrel)> +// <MCOperand Imm:0> <MCOperand Expr:(.Lpcrel@<<invalid>>)>> +// <MCInst SOME_LOAD <MCOperand Reg:22> <MCOperand Imm:0> <MCOperand Reg:282> +// <MCOperand Expr:(.Lpcrel@<<invalid>>)>> +// The above is a pair of such instructions and this function will not return +// std::nullopt for either one of them. In both cases we are looking for the +// last operand <MCOperand Expr:(.Lpcrel@<<invalid>>)> which needs to be an +// MCExpr and has the flag MCSymbolRefExpr::VK_PPC_PCREL_OPT. After that we just +// look at the opcode and in the case of PLDpc we will return true. For the load +// (or store) this function will return false indicating it has found the second +// instruciton in the pair. +std::optional<bool> llvm::isPartOfGOTToPCRelPair(const MCInst &Inst, + const MCSubtargetInfo &STI) { + // Need at least two operands. + if (Inst.getNumOperands() < 2) + return std::nullopt; + + unsigned LastOp = Inst.getNumOperands() - 1; + // The last operand needs to be an MCExpr and it needs to have a variant kind + // of VK_PPC_PCREL_OPT. If it does not satisfy these conditions it is not a + // link time GOT PC Rel opt instruction and we can ignore it and return + // std::nullopt. + const MCOperand &Operand = Inst.getOperand(LastOp); + if (!Operand.isExpr()) + return std::nullopt; + + // Check for the variant kind VK_PPC_PCREL_OPT in this expression. + const MCExpr *Expr = Operand.getExpr(); + const MCSymbolRefExpr *SymExpr = static_cast<const MCSymbolRefExpr *>(Expr); + if (!SymExpr || SymExpr->getKind() != MCSymbolRefExpr::VK_PPC_PCREL_OPT) + return std::nullopt; + + return (Inst.getOpcode() == PPC::PLDpc); +} + +MCELFStreamer *llvm::createPPCELFStreamer( + MCContext &Context, std::unique_ptr<MCAsmBackend> MAB, + std::unique_ptr<MCObjectWriter> OW, + std::unique_ptr<MCCodeEmitter> Emitter) { + return new PPCELFStreamer(Context, std::move(MAB), std::move(OW), + std::move(Emitter)); +} diff --git a/contrib/llvm-project/llvm/lib/Target/PowerPC/MCTargetDesc/PPCELFStreamer.h b/contrib/llvm-project/llvm/lib/Target/PowerPC/MCTargetDesc/PPCELFStreamer.h new file mode 100644 index 000000000000..10204b184a49 --- /dev/null +++ b/contrib/llvm-project/llvm/lib/Target/PowerPC/MCTargetDesc/PPCELFStreamer.h @@ -0,0 +1,59 @@ +//===- PPCELFStreamer.h - ELF Object Output --------------------*- C++ -*-===// +// +// 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 is a custom MCELFStreamer for PowerPC. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_PPC_MCELFSTREAMER_PPCELFSTREAMER_H +#define LLVM_LIB_TARGET_PPC_MCELFSTREAMER_PPCELFSTREAMER_H + +#include "llvm/MC/MCELFStreamer.h" +#include <memory> + +namespace llvm { + +class MCAsmBackend; +class MCCodeEmitter; +class MCContext; +class MCSubtargetInfo; + +class PPCELFStreamer : public MCELFStreamer { + // We need to keep track of the last label we emitted (only one) because + // depending on whether the label is on the same line as an aligned + // instruction or not, the label may refer to the instruction or the nop. + MCSymbol *LastLabel; + SMLoc LastLabelLoc; + +public: + PPCELFStreamer(MCContext &Context, std::unique_ptr<MCAsmBackend> MAB, + std::unique_ptr<MCObjectWriter> OW, + std::unique_ptr<MCCodeEmitter> Emitter); + + void emitInstruction(const MCInst &Inst, const MCSubtargetInfo &STI) override; + + // EmitLabel updates LastLabel and LastLabelLoc when a new label is emitted. + void emitLabel(MCSymbol *Symbol, SMLoc Loc = SMLoc()) override; +private: + void emitPrefixedInstruction(const MCInst &Inst, const MCSubtargetInfo &STI); + void emitGOTToPCRelReloc(const MCInst &Inst); + void emitGOTToPCRelLabel(const MCInst &Inst); +}; + +// Check if the instruction Inst is part of a pair of instructions that make up +// a link time GOT PC Rel optimization. +std::optional<bool> isPartOfGOTToPCRelPair(const MCInst &Inst, + const MCSubtargetInfo &STI); + +MCELFStreamer *createPPCELFStreamer(MCContext &Context, + std::unique_ptr<MCAsmBackend> MAB, + std::unique_ptr<MCObjectWriter> OW, + std::unique_ptr<MCCodeEmitter> Emitter); +} // end namespace llvm + +#endif // LLVM_LIB_TARGET_PPC_MCELFSTREAMER_PPCELFSTREAMER_H diff --git a/contrib/llvm-project/llvm/lib/Target/PowerPC/MCTargetDesc/PPCFixupKinds.h b/contrib/llvm-project/llvm/lib/Target/PowerPC/MCTargetDesc/PPCFixupKinds.h new file mode 100644 index 000000000000..9e8ee9f23107 --- /dev/null +++ b/contrib/llvm-project/llvm/lib/Target/PowerPC/MCTargetDesc/PPCFixupKinds.h @@ -0,0 +1,66 @@ +//===-- PPCFixupKinds.h - PPC Specific Fixup Entries ------------*- C++ -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_POWERPC_MCTARGETDESC_PPCFIXUPKINDS_H +#define LLVM_LIB_TARGET_POWERPC_MCTARGETDESC_PPCFIXUPKINDS_H + +#include "llvm/MC/MCFixup.h" + +#undef PPC + +namespace llvm { +namespace PPC { +enum Fixups { + // 24-bit PC relative relocation for direct branches like 'b' and 'bl'. + fixup_ppc_br24 = FirstTargetFixupKind, + + // 24-bit PC relative relocation for direct branches like 'b' and 'bl' where + // the caller does not use the TOC. + fixup_ppc_br24_notoc, + + /// 14-bit PC relative relocation for conditional branches. + fixup_ppc_brcond14, + + /// 24-bit absolute relocation for direct branches like 'ba' and 'bla'. + fixup_ppc_br24abs, + + /// 14-bit absolute relocation for conditional branches. + fixup_ppc_brcond14abs, + + /// A 16-bit fixup corresponding to lo16(_foo) or ha16(_foo) for instrs like + /// 'li' or 'addis'. + fixup_ppc_half16, + + /// A 14-bit fixup corresponding to lo16(_foo) with implied 2 zero bits for + /// instrs like 'std'. + fixup_ppc_half16ds, + + // A 34-bit fixup corresponding to PC-relative paddi. + fixup_ppc_pcrel34, + + // A 34-bit fixup corresponding to Non-PC-relative paddi. + fixup_ppc_imm34, + + /// Not a true fixup, but ties a symbol to a call to __tls_get_addr for the + /// TLS general and local dynamic models, or inserts the thread-pointer + /// register number. It can also be used to tie the ref symbol to prevent it + /// from being garbage collected on AIX. + fixup_ppc_nofixup, + + /// A 16-bit fixup corresponding to lo16(_foo) with implied 3 zero bits for + /// instrs like 'lxv'. Produces the same relocation as fixup_ppc_half16ds. + fixup_ppc_half16dq, + + // Marker + LastTargetFixupKind, + NumTargetFixupKinds = LastTargetFixupKind - FirstTargetFixupKind +}; +} +} + +#endif diff --git a/contrib/llvm-project/llvm/lib/Target/PowerPC/MCTargetDesc/PPCInstPrinter.cpp b/contrib/llvm-project/llvm/lib/Target/PowerPC/MCTargetDesc/PPCInstPrinter.cpp new file mode 100644 index 000000000000..9a4291c90408 --- /dev/null +++ b/contrib/llvm-project/llvm/lib/Target/PowerPC/MCTargetDesc/PPCInstPrinter.cpp @@ -0,0 +1,675 @@ +//===-- PPCInstPrinter.cpp - Convert PPC MCInst to assembly syntax --------===// +// +// 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 class prints an PPC MCInst to a .s file. +// +//===----------------------------------------------------------------------===// + +#include "MCTargetDesc/PPCInstPrinter.h" +#include "MCTargetDesc/PPCMCTargetDesc.h" +#include "MCTargetDesc/PPCPredicates.h" +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCInst.h" +#include "llvm/MC/MCInstrInfo.h" +#include "llvm/MC/MCRegisterInfo.h" +#include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/MC/MCSymbol.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/raw_ostream.h" +using namespace llvm; + +#define DEBUG_TYPE "asm-printer" + +// FIXME: Once the integrated assembler supports full register names, tie this +// to the verbose-asm setting. +static cl::opt<bool> +FullRegNames("ppc-asm-full-reg-names", cl::Hidden, cl::init(false), + cl::desc("Use full register names when printing assembly")); + +// Useful for testing purposes. Prints vs{31-63} as v{0-31} respectively. +static cl::opt<bool> +ShowVSRNumsAsVR("ppc-vsr-nums-as-vr", cl::Hidden, cl::init(false), + cl::desc("Prints full register names with vs{31-63} as v{0-31}")); + +// Prints full register names with percent symbol. +static cl::opt<bool> +FullRegNamesWithPercent("ppc-reg-with-percent-prefix", cl::Hidden, + cl::init(false), + cl::desc("Prints full register names with percent")); + +#define PRINT_ALIAS_INSTR +#include "PPCGenAsmWriter.inc" + +void PPCInstPrinter::printRegName(raw_ostream &OS, MCRegister Reg) const { + const char *RegName = getRegisterName(Reg); + OS << RegName; +} + +void PPCInstPrinter::printInst(const MCInst *MI, uint64_t Address, + StringRef Annot, const MCSubtargetInfo &STI, + raw_ostream &O) { + // Customize printing of the addis instruction on AIX. When an operand is a + // symbol reference, the instruction syntax is changed to look like a load + // operation, i.e: + // Transform: addis $rD, $rA, $src --> addis $rD, $src($rA). + if (TT.isOSAIX() && + (MI->getOpcode() == PPC::ADDIS8 || MI->getOpcode() == PPC::ADDIS) && + MI->getOperand(2).isExpr()) { + assert((MI->getOperand(0).isReg() && MI->getOperand(1).isReg()) && + "The first and the second operand of an addis instruction" + " should be registers."); + + assert(isa<MCSymbolRefExpr>(MI->getOperand(2).getExpr()) && + "The third operand of an addis instruction should be a symbol " + "reference expression if it is an expression at all."); + + O << "\taddis "; + printOperand(MI, 0, STI, O); + O << ", "; + printOperand(MI, 2, STI, O); + O << "("; + printOperand(MI, 1, STI, O); + O << ")"; + return; + } + + // Check if the last operand is an expression with the variant kind + // VK_PPC_PCREL_OPT. If this is the case then this is a linker optimization + // relocation and the .reloc directive needs to be added. + unsigned LastOp = MI->getNumOperands() - 1; + if (MI->getNumOperands() > 1) { + const MCOperand &Operand = MI->getOperand(LastOp); + if (Operand.isExpr()) { + const MCExpr *Expr = Operand.getExpr(); + const MCSymbolRefExpr *SymExpr = + static_cast<const MCSymbolRefExpr *>(Expr); + + if (SymExpr && SymExpr->getKind() == MCSymbolRefExpr::VK_PPC_PCREL_OPT) { + const MCSymbol &Symbol = SymExpr->getSymbol(); + if (MI->getOpcode() == PPC::PLDpc) { + printInstruction(MI, Address, STI, O); + O << "\n"; + Symbol.print(O, &MAI); + O << ":"; + return; + } else { + O << "\t.reloc "; + Symbol.print(O, &MAI); + O << "-8,R_PPC64_PCREL_OPT,.-("; + Symbol.print(O, &MAI); + O << "-8)\n"; + } + } + } + } + + // Check for slwi/srwi mnemonics. + if (MI->getOpcode() == PPC::RLWINM) { + unsigned char SH = MI->getOperand(2).getImm(); + unsigned char MB = MI->getOperand(3).getImm(); + unsigned char ME = MI->getOperand(4).getImm(); + bool useSubstituteMnemonic = false; + if (SH <= 31 && MB == 0 && ME == (31-SH)) { + O << "\tslwi "; useSubstituteMnemonic = true; + } + if (SH <= 31 && MB == (32-SH) && ME == 31) { + O << "\tsrwi "; useSubstituteMnemonic = true; + SH = 32-SH; + } + if (useSubstituteMnemonic) { + printOperand(MI, 0, STI, O); + O << ", "; + printOperand(MI, 1, STI, O); + O << ", " << (unsigned int)SH; + + printAnnotation(O, Annot); + return; + } + } + + if (MI->getOpcode() == PPC::RLDICR || + MI->getOpcode() == PPC::RLDICR_32) { + unsigned char SH = MI->getOperand(2).getImm(); + unsigned char ME = MI->getOperand(3).getImm(); + // rldicr RA, RS, SH, 63-SH == sldi RA, RS, SH + if (63-SH == ME) { + O << "\tsldi "; + printOperand(MI, 0, STI, O); + O << ", "; + printOperand(MI, 1, STI, O); + O << ", " << (unsigned int)SH; + printAnnotation(O, Annot); + return; + } + } + + // dcbt[st] is printed manually here because: + // 1. The assembly syntax is different between embedded and server targets + // 2. We must print the short mnemonics for TH == 0 because the + // embedded/server syntax default will not be stable across assemblers + // The syntax for dcbt is: + // dcbt ra, rb, th [server] + // dcbt th, ra, rb [embedded] + // where th can be omitted when it is 0. dcbtst is the same. + // On AIX, only emit the extended mnemonics for dcbt and dcbtst if + // the "modern assembler" is available. + if ((MI->getOpcode() == PPC::DCBT || MI->getOpcode() == PPC::DCBTST) && + (!TT.isOSAIX() || STI.hasFeature(PPC::FeatureModernAIXAs))) { + unsigned char TH = MI->getOperand(0).getImm(); + O << "\tdcbt"; + if (MI->getOpcode() == PPC::DCBTST) + O << "st"; + if (TH == 16) + O << "t"; + O << " "; + + bool IsBookE = STI.hasFeature(PPC::FeatureBookE); + if (IsBookE && TH != 0 && TH != 16) + O << (unsigned int) TH << ", "; + + printOperand(MI, 1, STI, O); + O << ", "; + printOperand(MI, 2, STI, O); + + if (!IsBookE && TH != 0 && TH != 16) + O << ", " << (unsigned int) TH; + + printAnnotation(O, Annot); + return; + } + + if (MI->getOpcode() == PPC::DCBF) { + unsigned char L = MI->getOperand(0).getImm(); + if (!L || L == 1 || L == 3 || L == 4 || L == 6) { + O << "\tdcb"; + if (L != 6) + O << "f"; + if (L == 1) + O << "l"; + if (L == 3) + O << "lp"; + if (L == 4) + O << "ps"; + if (L == 6) + O << "stps"; + O << " "; + + printOperand(MI, 1, STI, O); + O << ", "; + printOperand(MI, 2, STI, O); + + printAnnotation(O, Annot); + return; + } + } + + if (!printAliasInstr(MI, Address, STI, O)) + printInstruction(MI, Address, STI, O); + printAnnotation(O, Annot); +} + +void PPCInstPrinter::printPredicateOperand(const MCInst *MI, unsigned OpNo, + const MCSubtargetInfo &STI, + raw_ostream &O, + const char *Modifier) { + unsigned Code = MI->getOperand(OpNo).getImm(); + + if (StringRef(Modifier) == "cc") { + switch ((PPC::Predicate)Code) { + case PPC::PRED_LT_MINUS: + case PPC::PRED_LT_PLUS: + case PPC::PRED_LT: + O << "lt"; + return; + case PPC::PRED_LE_MINUS: + case PPC::PRED_LE_PLUS: + case PPC::PRED_LE: + O << "le"; + return; + case PPC::PRED_EQ_MINUS: + case PPC::PRED_EQ_PLUS: + case PPC::PRED_EQ: + O << "eq"; + return; + case PPC::PRED_GE_MINUS: + case PPC::PRED_GE_PLUS: + case PPC::PRED_GE: + O << "ge"; + return; + case PPC::PRED_GT_MINUS: + case PPC::PRED_GT_PLUS: + case PPC::PRED_GT: + O << "gt"; + return; + case PPC::PRED_NE_MINUS: + case PPC::PRED_NE_PLUS: + case PPC::PRED_NE: + O << "ne"; + return; + case PPC::PRED_UN_MINUS: + case PPC::PRED_UN_PLUS: + case PPC::PRED_UN: + O << "un"; + return; + case PPC::PRED_NU_MINUS: + case PPC::PRED_NU_PLUS: + case PPC::PRED_NU: + O << "nu"; + return; + case PPC::PRED_BIT_SET: + case PPC::PRED_BIT_UNSET: + llvm_unreachable("Invalid use of bit predicate code"); + } + llvm_unreachable("Invalid predicate code"); + } + + if (StringRef(Modifier) == "pm") { + switch ((PPC::Predicate)Code) { + case PPC::PRED_LT: + case PPC::PRED_LE: + case PPC::PRED_EQ: + case PPC::PRED_GE: + case PPC::PRED_GT: + case PPC::PRED_NE: + case PPC::PRED_UN: + case PPC::PRED_NU: + return; + case PPC::PRED_LT_MINUS: + case PPC::PRED_LE_MINUS: + case PPC::PRED_EQ_MINUS: + case PPC::PRED_GE_MINUS: + case PPC::PRED_GT_MINUS: + case PPC::PRED_NE_MINUS: + case PPC::PRED_UN_MINUS: + case PPC::PRED_NU_MINUS: + O << "-"; + return; + case PPC::PRED_LT_PLUS: + case PPC::PRED_LE_PLUS: + case PPC::PRED_EQ_PLUS: + case PPC::PRED_GE_PLUS: + case PPC::PRED_GT_PLUS: + case PPC::PRED_NE_PLUS: + case PPC::PRED_UN_PLUS: + case PPC::PRED_NU_PLUS: + O << "+"; + return; + case PPC::PRED_BIT_SET: + case PPC::PRED_BIT_UNSET: + llvm_unreachable("Invalid use of bit predicate code"); + } + llvm_unreachable("Invalid predicate code"); + } + + assert(StringRef(Modifier) == "reg" && + "Need to specify 'cc', 'pm' or 'reg' as predicate op modifier!"); + printOperand(MI, OpNo + 1, STI, O); +} + +void PPCInstPrinter::printATBitsAsHint(const MCInst *MI, unsigned OpNo, + const MCSubtargetInfo &STI, + raw_ostream &O) { + unsigned Code = MI->getOperand(OpNo).getImm(); + if (Code == 2) + O << "-"; + else if (Code == 3) + O << "+"; +} + +void PPCInstPrinter::printU1ImmOperand(const MCInst *MI, unsigned OpNo, + const MCSubtargetInfo &STI, + raw_ostream &O) { + unsigned int Value = MI->getOperand(OpNo).getImm(); + assert(Value <= 1 && "Invalid u1imm argument!"); + O << (unsigned int)Value; +} + +void PPCInstPrinter::printU2ImmOperand(const MCInst *MI, unsigned OpNo, + const MCSubtargetInfo &STI, + raw_ostream &O) { + unsigned int Value = MI->getOperand(OpNo).getImm(); + assert(Value <= 3 && "Invalid u2imm argument!"); + O << (unsigned int)Value; +} + +void PPCInstPrinter::printU3ImmOperand(const MCInst *MI, unsigned OpNo, + const MCSubtargetInfo &STI, + raw_ostream &O) { + unsigned int Value = MI->getOperand(OpNo).getImm(); + assert(Value <= 8 && "Invalid u3imm argument!"); + O << (unsigned int)Value; +} + +void PPCInstPrinter::printU4ImmOperand(const MCInst *MI, unsigned OpNo, + const MCSubtargetInfo &STI, + raw_ostream &O) { + unsigned int Value = MI->getOperand(OpNo).getImm(); + assert(Value <= 15 && "Invalid u4imm argument!"); + O << (unsigned int)Value; +} + +void PPCInstPrinter::printS5ImmOperand(const MCInst *MI, unsigned OpNo, + const MCSubtargetInfo &STI, + raw_ostream &O) { + int Value = MI->getOperand(OpNo).getImm(); + Value = SignExtend32<5>(Value); + O << (int)Value; +} + +void PPCInstPrinter::printImmZeroOperand(const MCInst *MI, unsigned OpNo, + const MCSubtargetInfo &STI, + raw_ostream &O) { + unsigned int Value = MI->getOperand(OpNo).getImm(); + assert(Value == 0 && "Operand must be zero"); + O << (unsigned int)Value; +} + +void PPCInstPrinter::printU5ImmOperand(const MCInst *MI, unsigned OpNo, + const MCSubtargetInfo &STI, + raw_ostream &O) { + unsigned int Value = MI->getOperand(OpNo).getImm(); + assert(Value <= 31 && "Invalid u5imm argument!"); + O << (unsigned int)Value; +} + +void PPCInstPrinter::printU6ImmOperand(const MCInst *MI, unsigned OpNo, + const MCSubtargetInfo &STI, + raw_ostream &O) { + unsigned int Value = MI->getOperand(OpNo).getImm(); + assert(Value <= 63 && "Invalid u6imm argument!"); + O << (unsigned int)Value; +} + +void PPCInstPrinter::printU7ImmOperand(const MCInst *MI, unsigned OpNo, + const MCSubtargetInfo &STI, + raw_ostream &O) { + unsigned int Value = MI->getOperand(OpNo).getImm(); + assert(Value <= 127 && "Invalid u7imm argument!"); + O << (unsigned int)Value; +} + +// Operands of BUILD_VECTOR are signed and we use this to print operands +// of XXSPLTIB which are unsigned. So we simply truncate to 8 bits and +// print as unsigned. +void PPCInstPrinter::printU8ImmOperand(const MCInst *MI, unsigned OpNo, + const MCSubtargetInfo &STI, + raw_ostream &O) { + unsigned char Value = MI->getOperand(OpNo).getImm(); + O << (unsigned int)Value; +} + +void PPCInstPrinter::printU10ImmOperand(const MCInst *MI, unsigned OpNo, + const MCSubtargetInfo &STI, + raw_ostream &O) { + unsigned short Value = MI->getOperand(OpNo).getImm(); + assert(Value <= 1023 && "Invalid u10imm argument!"); + O << (unsigned short)Value; +} + +void PPCInstPrinter::printU12ImmOperand(const MCInst *MI, unsigned OpNo, + const MCSubtargetInfo &STI, + raw_ostream &O) { + unsigned short Value = MI->getOperand(OpNo).getImm(); + assert(Value <= 4095 && "Invalid u12imm argument!"); + O << (unsigned short)Value; +} + +void PPCInstPrinter::printS16ImmOperand(const MCInst *MI, unsigned OpNo, + const MCSubtargetInfo &STI, + raw_ostream &O) { + if (MI->getOperand(OpNo).isImm()) + O << (short)MI->getOperand(OpNo).getImm(); + else + printOperand(MI, OpNo, STI, O); +} + +void PPCInstPrinter::printS34ImmOperand(const MCInst *MI, unsigned OpNo, + const MCSubtargetInfo &STI, + raw_ostream &O) { + if (MI->getOperand(OpNo).isImm()) { + long long Value = MI->getOperand(OpNo).getImm(); + assert(isInt<34>(Value) && "Invalid s34imm argument!"); + O << (long long)Value; + } + else + printOperand(MI, OpNo, STI, O); +} + +void PPCInstPrinter::printU16ImmOperand(const MCInst *MI, unsigned OpNo, + const MCSubtargetInfo &STI, + raw_ostream &O) { + if (MI->getOperand(OpNo).isImm()) + O << (unsigned short)MI->getOperand(OpNo).getImm(); + else + printOperand(MI, OpNo, STI, O); +} + +void PPCInstPrinter::printBranchOperand(const MCInst *MI, uint64_t Address, + unsigned OpNo, + const MCSubtargetInfo &STI, + raw_ostream &O) { + if (!MI->getOperand(OpNo).isImm()) + return printOperand(MI, OpNo, STI, O); + int32_t Imm = SignExtend32<32>((unsigned)MI->getOperand(OpNo).getImm() << 2); + if (PrintBranchImmAsAddress) { + uint64_t Target = Address + Imm; + if (!TT.isPPC64()) + Target &= 0xffffffff; + O << formatHex(Target); + } else { + // Branches can take an immediate operand. This is used by the branch + // selection pass to print, for example `.+8` (for ELF) or `$+8` (for AIX) + // to express an eight byte displacement from the program counter. + if (!TT.isOSAIX()) + O << "."; + else + O << "$"; + + if (Imm >= 0) + O << "+"; + O << Imm; + } +} + +void PPCInstPrinter::printAbsBranchOperand(const MCInst *MI, unsigned OpNo, + const MCSubtargetInfo &STI, + raw_ostream &O) { + if (!MI->getOperand(OpNo).isImm()) + return printOperand(MI, OpNo, STI, O); + + uint64_t Imm = static_cast<uint64_t>(MI->getOperand(OpNo).getImm()) << 2; + if (!TT.isPPC64()) + Imm = static_cast<uint32_t>(Imm); + O << formatHex(Imm); +} + +void PPCInstPrinter::printcrbitm(const MCInst *MI, unsigned OpNo, + const MCSubtargetInfo &STI, raw_ostream &O) { + unsigned CCReg = MI->getOperand(OpNo).getReg(); + unsigned RegNo; + switch (CCReg) { + default: llvm_unreachable("Unknown CR register"); + case PPC::CR0: RegNo = 0; break; + case PPC::CR1: RegNo = 1; break; + case PPC::CR2: RegNo = 2; break; + case PPC::CR3: RegNo = 3; break; + case PPC::CR4: RegNo = 4; break; + case PPC::CR5: RegNo = 5; break; + case PPC::CR6: RegNo = 6; break; + case PPC::CR7: RegNo = 7; break; + } + O << (0x80 >> RegNo); +} + +void PPCInstPrinter::printMemRegImm(const MCInst *MI, unsigned OpNo, + const MCSubtargetInfo &STI, + raw_ostream &O) { + printS16ImmOperand(MI, OpNo, STI, O); + O << '('; + if (MI->getOperand(OpNo+1).getReg() == PPC::R0) + O << "0"; + else + printOperand(MI, OpNo + 1, STI, O); + O << ')'; +} + +void PPCInstPrinter::printMemRegImmHash(const MCInst *MI, unsigned OpNo, + const MCSubtargetInfo &STI, + raw_ostream &O) { + O << MI->getOperand(OpNo).getImm(); + O << '('; + printOperand(MI, OpNo + 1, STI, O); + O << ')'; +} + +void PPCInstPrinter::printMemRegImm34PCRel(const MCInst *MI, unsigned OpNo, + const MCSubtargetInfo &STI, + raw_ostream &O) { + printS34ImmOperand(MI, OpNo, STI, O); + O << '('; + printImmZeroOperand(MI, OpNo + 1, STI, O); + O << ')'; +} + +void PPCInstPrinter::printMemRegImm34(const MCInst *MI, unsigned OpNo, + const MCSubtargetInfo &STI, + raw_ostream &O) { + printS34ImmOperand(MI, OpNo, STI, O); + O << '('; + printOperand(MI, OpNo + 1, STI, O); + O << ')'; +} + +void PPCInstPrinter::printMemRegReg(const MCInst *MI, unsigned OpNo, + const MCSubtargetInfo &STI, + raw_ostream &O) { + // When used as the base register, r0 reads constant zero rather than + // the value contained in the register. For this reason, the darwin + // assembler requires that we print r0 as 0 (no r) when used as the base. + if (MI->getOperand(OpNo).getReg() == PPC::R0) + O << "0"; + else + printOperand(MI, OpNo, STI, O); + O << ", "; + printOperand(MI, OpNo + 1, STI, O); +} + +void PPCInstPrinter::printTLSCall(const MCInst *MI, unsigned OpNo, + const MCSubtargetInfo &STI, raw_ostream &O) { + // On PPC64, VariantKind is VK_None, but on PPC32, it's VK_PLT, and it must + // come at the _end_ of the expression. + const MCOperand &Op = MI->getOperand(OpNo); + const MCSymbolRefExpr *RefExp = nullptr; + const MCExpr *Rhs = nullptr; + if (const MCBinaryExpr *BinExpr = dyn_cast<MCBinaryExpr>(Op.getExpr())) { + RefExp = cast<MCSymbolRefExpr>(BinExpr->getLHS()); + Rhs = BinExpr->getRHS(); + } else + RefExp = cast<MCSymbolRefExpr>(Op.getExpr()); + + O << RefExp->getSymbol().getName(); + // The variant kind VK_PPC_NOTOC needs to be handled as a special case + // because we do not want the assembly to print out the @notoc at the + // end like __tls_get_addr(x@tlsgd)@notoc. Instead we want it to look + // like __tls_get_addr@notoc(x@tlsgd). + if (RefExp->getKind() == MCSymbolRefExpr::VK_PPC_NOTOC) + O << '@' << MCSymbolRefExpr::getVariantKindName(RefExp->getKind()); + O << '('; + printOperand(MI, OpNo + 1, STI, O); + O << ')'; + if (RefExp->getKind() != MCSymbolRefExpr::VK_None && + RefExp->getKind() != MCSymbolRefExpr::VK_PPC_NOTOC) + O << '@' << MCSymbolRefExpr::getVariantKindName(RefExp->getKind()); + if (Rhs) { + SmallString<0> Buf; + raw_svector_ostream Tmp(Buf); + Rhs->print(Tmp, &MAI); + if (isdigit(Buf[0])) + O << '+'; + O << Buf; + } +} + +/// showRegistersWithPercentPrefix - Check if this register name should be +/// printed with a percentage symbol as prefix. +bool PPCInstPrinter::showRegistersWithPercentPrefix(const char *RegName) const { + if ((!FullRegNamesWithPercent && !MAI.useFullRegisterNames()) || + TT.getOS() == Triple::AIX) + return false; + + switch (RegName[0]) { + default: + return false; + case 'r': + case 'f': + case 'q': + case 'v': + case 'c': + return true; + } +} + +/// getVerboseConditionalRegName - This method expands the condition register +/// when requested explicitly or targetting Darwin. +const char * +PPCInstPrinter::getVerboseConditionRegName(unsigned RegNum, + unsigned RegEncoding) const { + if (!FullRegNames && !MAI.useFullRegisterNames()) + return nullptr; + if (RegNum < PPC::CR0EQ || RegNum > PPC::CR7UN) + return nullptr; + const char *CRBits[] = { + "lt", "gt", "eq", "un", + "4*cr1+lt", "4*cr1+gt", "4*cr1+eq", "4*cr1+un", + "4*cr2+lt", "4*cr2+gt", "4*cr2+eq", "4*cr2+un", + "4*cr3+lt", "4*cr3+gt", "4*cr3+eq", "4*cr3+un", + "4*cr4+lt", "4*cr4+gt", "4*cr4+eq", "4*cr4+un", + "4*cr5+lt", "4*cr5+gt", "4*cr5+eq", "4*cr5+un", + "4*cr6+lt", "4*cr6+gt", "4*cr6+eq", "4*cr6+un", + "4*cr7+lt", "4*cr7+gt", "4*cr7+eq", "4*cr7+un" + }; + return CRBits[RegEncoding]; +} + +// showRegistersWithPrefix - This method determines whether registers +// should be number-only or include the prefix. +bool PPCInstPrinter::showRegistersWithPrefix() const { + return FullRegNamesWithPercent || FullRegNames || MAI.useFullRegisterNames(); +} + +void PPCInstPrinter::printOperand(const MCInst *MI, unsigned OpNo, + const MCSubtargetInfo &STI, raw_ostream &O) { + const MCOperand &Op = MI->getOperand(OpNo); + if (Op.isReg()) { + unsigned Reg = Op.getReg(); + if (!ShowVSRNumsAsVR) + Reg = PPC::getRegNumForOperand(MII.get(MI->getOpcode()), Reg, OpNo); + + const char *RegName; + RegName = getVerboseConditionRegName(Reg, MRI.getEncodingValue(Reg)); + if (RegName == nullptr) + RegName = getRegisterName(Reg); + if (showRegistersWithPercentPrefix(RegName)) + O << "%"; + if (!showRegistersWithPrefix()) + RegName = PPC::stripRegisterPrefix(RegName); + + O << RegName; + return; + } + + if (Op.isImm()) { + O << Op.getImm(); + return; + } + + assert(Op.isExpr() && "unknown operand kind in printOperand"); + Op.getExpr()->print(O, &MAI); +} diff --git a/contrib/llvm-project/llvm/lib/Target/PowerPC/MCTargetDesc/PPCInstPrinter.h b/contrib/llvm-project/llvm/lib/Target/PowerPC/MCTargetDesc/PPCInstPrinter.h new file mode 100644 index 000000000000..6ba3eb4c79dc --- /dev/null +++ b/contrib/llvm-project/llvm/lib/Target/PowerPC/MCTargetDesc/PPCInstPrinter.h @@ -0,0 +1,111 @@ +//===- PPCInstPrinter.h - Convert PPC MCInst to assembly syntax -*- C++ -*-===// +// +// 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 class prints an PPC MCInst to a .s file. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_POWERPC_MCTARGETDESC_PPCINSTPRINTER_H +#define LLVM_LIB_TARGET_POWERPC_MCTARGETDESC_PPCINSTPRINTER_H + +#include "llvm/MC/MCInstPrinter.h" +#include "llvm/TargetParser/Triple.h" + +namespace llvm { + +class PPCInstPrinter : public MCInstPrinter { + Triple TT; +private: + bool showRegistersWithPercentPrefix(const char *RegName) const; + bool showRegistersWithPrefix() const; + const char *getVerboseConditionRegName(unsigned RegNum, + unsigned RegEncoding) const; + +public: + PPCInstPrinter(const MCAsmInfo &MAI, const MCInstrInfo &MII, + const MCRegisterInfo &MRI, Triple T) + : MCInstPrinter(MAI, MII, MRI), TT(T) {} + + void printRegName(raw_ostream &OS, MCRegister Reg) const override; + void printInst(const MCInst *MI, uint64_t Address, StringRef Annot, + const MCSubtargetInfo &STI, raw_ostream &O) override; + + // Autogenerated by tblgen. + std::pair<const char *, uint64_t> getMnemonic(const MCInst *MI) override; + void printInstruction(const MCInst *MI, uint64_t Address, + const MCSubtargetInfo &STI, raw_ostream &O); + static const char *getRegisterName(MCRegister Reg); + + bool printAliasInstr(const MCInst *MI, uint64_t Address, + const MCSubtargetInfo &STI, raw_ostream &OS); + void printCustomAliasOperand(const MCInst *MI, uint64_t Address, + unsigned OpIdx, unsigned PrintMethodIdx, + const MCSubtargetInfo &STI, raw_ostream &OS); + + void printOperand(const MCInst *MI, unsigned OpNo, const MCSubtargetInfo &STI, + raw_ostream &O); + void printPredicateOperand(const MCInst *MI, unsigned OpNo, + const MCSubtargetInfo &STI, raw_ostream &O, + const char *Modifier = nullptr); + void printATBitsAsHint(const MCInst *MI, unsigned OpNo, + const MCSubtargetInfo &STI, raw_ostream &O); + + void printU1ImmOperand(const MCInst *MI, unsigned OpNo, + const MCSubtargetInfo &STI, raw_ostream &O); + void printU2ImmOperand(const MCInst *MI, unsigned OpNo, + const MCSubtargetInfo &STI, raw_ostream &O); + void printU3ImmOperand(const MCInst *MI, unsigned OpNo, + const MCSubtargetInfo &STI, raw_ostream &O); + void printU4ImmOperand(const MCInst *MI, unsigned OpNo, + const MCSubtargetInfo &STI, raw_ostream &O); + void printS5ImmOperand(const MCInst *MI, unsigned OpNo, + const MCSubtargetInfo &STI, raw_ostream &O); + void printU5ImmOperand(const MCInst *MI, unsigned OpNo, + const MCSubtargetInfo &STI, raw_ostream &O); + void printU6ImmOperand(const MCInst *MI, unsigned OpNo, + const MCSubtargetInfo &STI, raw_ostream &O); + void printU7ImmOperand(const MCInst *MI, unsigned OpNo, + const MCSubtargetInfo &STI, raw_ostream &O); + void printU8ImmOperand(const MCInst *MI, unsigned OpNo, + const MCSubtargetInfo &STI, raw_ostream &O); + void printU10ImmOperand(const MCInst *MI, unsigned OpNo, + const MCSubtargetInfo &STI, raw_ostream &O); + void printU12ImmOperand(const MCInst *MI, unsigned OpNo, + const MCSubtargetInfo &STI, raw_ostream &O); + void printS16ImmOperand(const MCInst *MI, unsigned OpNo, + const MCSubtargetInfo &STI, raw_ostream &O); + void printS34ImmOperand(const MCInst *MI, unsigned OpNo, + const MCSubtargetInfo &STI, raw_ostream &O); + void printU16ImmOperand(const MCInst *MI, unsigned OpNo, + const MCSubtargetInfo &STI, raw_ostream &O); + void printImmZeroOperand(const MCInst *MI, unsigned OpNo, + const MCSubtargetInfo &STI, raw_ostream &O); + void printBranchOperand(const MCInst *MI, uint64_t Address, unsigned OpNo, + const MCSubtargetInfo &STI, raw_ostream &O); + void printAbsBranchOperand(const MCInst *MI, unsigned OpNo, + const MCSubtargetInfo &STI, raw_ostream &O); + void printTLSCall(const MCInst *MI, unsigned OpNo, const MCSubtargetInfo &STI, + raw_ostream &O); + + void printcrbitm(const MCInst *MI, unsigned OpNo, const MCSubtargetInfo &STI, + raw_ostream &O); + + void printMemRegImm(const MCInst *MI, unsigned OpNo, + const MCSubtargetInfo &STI, raw_ostream &O); + void printMemRegImmHash(const MCInst *MI, unsigned OpNo, + const MCSubtargetInfo &STI, raw_ostream &O); + void printMemRegImm34PCRel(const MCInst *MI, unsigned OpNo, + const MCSubtargetInfo &STI, raw_ostream &O); + void printMemRegImm34(const MCInst *MI, unsigned OpNo, + const MCSubtargetInfo &STI, raw_ostream &O); + void printMemRegReg(const MCInst *MI, unsigned OpNo, + const MCSubtargetInfo &STI, raw_ostream &O); +}; +} // end namespace llvm + +#endif diff --git a/contrib/llvm-project/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCAsmInfo.cpp b/contrib/llvm-project/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCAsmInfo.cpp new file mode 100644 index 000000000000..4716e37b3443 --- /dev/null +++ b/contrib/llvm-project/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCAsmInfo.cpp @@ -0,0 +1,74 @@ +//===-- PPCMCAsmInfo.cpp - PPC asm properties -----------------------------===// +// +// 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 the declarations of the MCAsmInfoDarwin properties. +// +//===----------------------------------------------------------------------===// + +#include "PPCMCAsmInfo.h" +#include "llvm/TargetParser/Triple.h" + +using namespace llvm; + +void PPCELFMCAsmInfo::anchor() { } + +PPCELFMCAsmInfo::PPCELFMCAsmInfo(bool is64Bit, const Triple& T) { + // FIXME: This is not always needed. For example, it is not needed in the + // v2 abi. + NeedsLocalForSize = true; + + if (is64Bit) { + CodePointerSize = CalleeSaveStackSlotSize = 8; + } + IsLittleEndian = + T.getArch() == Triple::ppc64le || T.getArch() == Triple::ppcle; + + // ".comm align is in bytes but .align is pow-2." + AlignmentIsInBytes = false; + + CommentString = "#"; + + // Uses '.section' before '.bss' directive + UsesELFSectionDirectiveForBSS = true; + + // Debug Information + SupportsDebugInformation = true; + + DollarIsPC = true; + + // Set up DWARF directives + MinInstAlignment = 4; + + // Exceptions handling + ExceptionsType = ExceptionHandling::DwarfCFI; + + ZeroDirective = "\t.space\t"; + Data64bitsDirective = is64Bit ? "\t.quad\t" : nullptr; + AssemblerDialect = 1; // New-Style mnemonics. + LCOMMDirectiveAlignmentType = LCOMM::ByteAlignment; +} + +void PPCXCOFFMCAsmInfo::anchor() {} + +PPCXCOFFMCAsmInfo::PPCXCOFFMCAsmInfo(bool Is64Bit, const Triple &T) { + if (T.getArch() == Triple::ppc64le || T.getArch() == Triple::ppcle) + report_fatal_error("XCOFF is not supported for little-endian targets"); + CodePointerSize = CalleeSaveStackSlotSize = Is64Bit ? 8 : 4; + + // A size of 8 is only supported by the assembler under 64-bit. + Data64bitsDirective = Is64Bit ? "\t.vbyte\t8, " : nullptr; + + // Debug Information + SupportsDebugInformation = true; + + // Set up DWARF directives + MinInstAlignment = 4; + + // Support $ as PC in inline asm + DollarIsPC = true; +} diff --git a/contrib/llvm-project/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCAsmInfo.h b/contrib/llvm-project/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCAsmInfo.h new file mode 100644 index 000000000000..48806051f581 --- /dev/null +++ b/contrib/llvm-project/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCAsmInfo.h @@ -0,0 +1,38 @@ +//===-- PPCMCAsmInfo.h - PPC asm properties --------------------*- C++ -*--===// +// +// 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 the declarations of the PowerPC MCAsmInfo classes. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_POWERPC_MCTARGETDESC_PPCMCASMINFO_H +#define LLVM_LIB_TARGET_POWERPC_MCTARGETDESC_PPCMCASMINFO_H + +#include "llvm/MC/MCAsmInfoELF.h" +#include "llvm/MC/MCAsmInfoXCOFF.h" + +namespace llvm { +class Triple; + +class PPCELFMCAsmInfo : public MCAsmInfoELF { + void anchor() override; + +public: + explicit PPCELFMCAsmInfo(bool is64Bit, const Triple &); +}; + +class PPCXCOFFMCAsmInfo : public MCAsmInfoXCOFF { + void anchor() override; + +public: + explicit PPCXCOFFMCAsmInfo(bool is64Bit, const Triple &); +}; + +} // namespace llvm + +#endif diff --git a/contrib/llvm-project/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCCodeEmitter.cpp b/contrib/llvm-project/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCCodeEmitter.cpp new file mode 100644 index 000000000000..910b5892d033 --- /dev/null +++ b/contrib/llvm-project/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCCodeEmitter.cpp @@ -0,0 +1,543 @@ +//===-- PPCMCCodeEmitter.cpp - Convert PPC code to machine code -----------===// +// +// 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 implements the PPCMCCodeEmitter class. +// +//===----------------------------------------------------------------------===// + +#include "PPCMCCodeEmitter.h" +#include "MCTargetDesc/PPCFixupKinds.h" +#include "PPCMCTargetDesc.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/Statistic.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCFixup.h" +#include "llvm/MC/MCInstrDesc.h" +#include "llvm/MC/MCRegisterInfo.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/EndianStream.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/MathExtras.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/TargetParser/Triple.h" +#include <cassert> +#include <cstdint> + +using namespace llvm; + +#define DEBUG_TYPE "mccodeemitter" + +STATISTIC(MCNumEmitted, "Number of MC instructions emitted"); + +MCCodeEmitter *llvm::createPPCMCCodeEmitter(const MCInstrInfo &MCII, + MCContext &Ctx) { + return new PPCMCCodeEmitter(MCII, Ctx); +} + +unsigned PPCMCCodeEmitter:: +getDirectBrEncoding(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const { + const MCOperand &MO = MI.getOperand(OpNo); + + if (MO.isReg() || MO.isImm()) + return getMachineOpValue(MI, MO, Fixups, STI); + + // Add a fixup for the branch target. + Fixups.push_back(MCFixup::create(0, MO.getExpr(), + (isNoTOCCallInstr(MI) + ? (MCFixupKind)PPC::fixup_ppc_br24_notoc + : (MCFixupKind)PPC::fixup_ppc_br24))); + return 0; +} + +/// Check if Opcode corresponds to a call instruction that should be marked +/// with the NOTOC relocation. +bool PPCMCCodeEmitter::isNoTOCCallInstr(const MCInst &MI) const { + unsigned Opcode = MI.getOpcode(); + if (!MCII.get(Opcode).isCall()) + return false; + + switch (Opcode) { + default: +#ifndef NDEBUG + llvm_unreachable("Unknown call opcode"); +#endif + return false; + case PPC::BL8_NOTOC: + case PPC::BL8_NOTOC_TLS: + case PPC::BL8_NOTOC_RM: + return true; +#ifndef NDEBUG + case PPC::BL8: + case PPC::BL: + case PPC::BL8_TLS: + case PPC::BL_TLS: + case PPC::BLA8: + case PPC::BLA: + case PPC::BCCL: + case PPC::BCCLA: + case PPC::BCL: + case PPC::BCLn: + case PPC::BL8_NOP: + case PPC::BL_NOP: + case PPC::BL8_NOP_TLS: + case PPC::BLA8_NOP: + case PPC::BCTRL8: + case PPC::BCTRL: + case PPC::BCCCTRL8: + case PPC::BCCCTRL: + case PPC::BCCTRL8: + case PPC::BCCTRL: + case PPC::BCCTRL8n: + case PPC::BCCTRLn: + case PPC::BL8_RM: + case PPC::BLA8_RM: + case PPC::BL8_NOP_RM: + case PPC::BLA8_NOP_RM: + case PPC::BCTRL8_RM: + case PPC::BCTRL8_LDinto_toc: + case PPC::BCTRL8_LDinto_toc_RM: + case PPC::BL8_TLS_: + case PPC::TCRETURNdi8: + case PPC::TCRETURNai8: + case PPC::TCRETURNri8: + case PPC::TAILBCTR8: + case PPC::TAILB8: + case PPC::TAILBA8: + case PPC::BCLalways: + case PPC::BLRL: + case PPC::BCCLRL: + case PPC::BCLRL: + case PPC::BCLRLn: + case PPC::BDZL: + case PPC::BDNZL: + case PPC::BDZLA: + case PPC::BDNZLA: + case PPC::BDZLp: + case PPC::BDNZLp: + case PPC::BDZLAp: + case PPC::BDNZLAp: + case PPC::BDZLm: + case PPC::BDNZLm: + case PPC::BDZLAm: + case PPC::BDNZLAm: + case PPC::BDZLRL: + case PPC::BDNZLRL: + case PPC::BDZLRLp: + case PPC::BDNZLRLp: + case PPC::BDZLRLm: + case PPC::BDNZLRLm: + case PPC::BL_RM: + case PPC::BLA_RM: + case PPC::BL_NOP_RM: + case PPC::BCTRL_RM: + case PPC::TCRETURNdi: + case PPC::TCRETURNai: + case PPC::TCRETURNri: + case PPC::BCTRL_LWZinto_toc: + case PPC::BCTRL_LWZinto_toc_RM: + case PPC::TAILBCTR: + case PPC::TAILB: + case PPC::TAILBA: + return false; +#endif + } +} + +unsigned PPCMCCodeEmitter::getCondBrEncoding(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const { + const MCOperand &MO = MI.getOperand(OpNo); + if (MO.isReg() || MO.isImm()) return getMachineOpValue(MI, MO, Fixups, STI); + + // Add a fixup for the branch target. + Fixups.push_back(MCFixup::create(0, MO.getExpr(), + (MCFixupKind)PPC::fixup_ppc_brcond14)); + return 0; +} + +unsigned PPCMCCodeEmitter:: +getAbsDirectBrEncoding(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const { + const MCOperand &MO = MI.getOperand(OpNo); + if (MO.isReg() || MO.isImm()) return getMachineOpValue(MI, MO, Fixups, STI); + + // Add a fixup for the branch target. + Fixups.push_back(MCFixup::create(0, MO.getExpr(), + (MCFixupKind)PPC::fixup_ppc_br24abs)); + return 0; +} + +unsigned PPCMCCodeEmitter:: +getAbsCondBrEncoding(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const { + const MCOperand &MO = MI.getOperand(OpNo); + if (MO.isReg() || MO.isImm()) return getMachineOpValue(MI, MO, Fixups, STI); + + // Add a fixup for the branch target. + Fixups.push_back(MCFixup::create(0, MO.getExpr(), + (MCFixupKind)PPC::fixup_ppc_brcond14abs)); + return 0; +} + +unsigned +PPCMCCodeEmitter::getVSRpEvenEncoding(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const { + assert(MI.getOperand(OpNo).isReg() && "Operand should be a register"); + unsigned RegBits = getMachineOpValue(MI, MI.getOperand(OpNo), Fixups, STI) + << 1; + return RegBits; +} + +unsigned PPCMCCodeEmitter::getImm16Encoding(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const { + const MCOperand &MO = MI.getOperand(OpNo); + if (MO.isReg() || MO.isImm()) return getMachineOpValue(MI, MO, Fixups, STI); + + // Add a fixup for the immediate field. + Fixups.push_back(MCFixup::create(IsLittleEndian? 0 : 2, MO.getExpr(), + (MCFixupKind)PPC::fixup_ppc_half16)); + return 0; +} + +uint64_t PPCMCCodeEmitter::getImm34Encoding(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI, + MCFixupKind Fixup) const { + const MCOperand &MO = MI.getOperand(OpNo); + assert(!MO.isReg() && "Not expecting a register for this operand."); + if (MO.isImm()) + return getMachineOpValue(MI, MO, Fixups, STI); + + // Add a fixup for the immediate field. + Fixups.push_back(MCFixup::create(0, MO.getExpr(), Fixup)); + return 0; +} + +uint64_t +PPCMCCodeEmitter::getImm34EncodingNoPCRel(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const { + return getImm34Encoding(MI, OpNo, Fixups, STI, + (MCFixupKind)PPC::fixup_ppc_imm34); +} + +uint64_t +PPCMCCodeEmitter::getImm34EncodingPCRel(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const { + return getImm34Encoding(MI, OpNo, Fixups, STI, + (MCFixupKind)PPC::fixup_ppc_pcrel34); +} + +unsigned PPCMCCodeEmitter::getDispRIEncoding(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const { + const MCOperand &MO = MI.getOperand(OpNo); + if (MO.isImm()) + return getMachineOpValue(MI, MO, Fixups, STI) & 0xFFFF; + + // Add a fixup for the displacement field. + Fixups.push_back(MCFixup::create(IsLittleEndian? 0 : 2, MO.getExpr(), + (MCFixupKind)PPC::fixup_ppc_half16)); + return 0; +} + +unsigned +PPCMCCodeEmitter::getDispRIXEncoding(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const { + const MCOperand &MO = MI.getOperand(OpNo); + if (MO.isImm()) + return ((getMachineOpValue(MI, MO, Fixups, STI) >> 2) & 0x3FFF); + + // Add a fixup for the displacement field. + Fixups.push_back(MCFixup::create(IsLittleEndian? 0 : 2, MO.getExpr(), + (MCFixupKind)PPC::fixup_ppc_half16ds)); + return 0; +} + +unsigned +PPCMCCodeEmitter::getDispRIX16Encoding(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const { + const MCOperand &MO = MI.getOperand(OpNo); + if (MO.isImm()) { + assert(!(MO.getImm() % 16) && + "Expecting an immediate that is a multiple of 16"); + return ((getMachineOpValue(MI, MO, Fixups, STI) >> 4) & 0xFFF); + } + + // Otherwise add a fixup for the displacement field. + Fixups.push_back(MCFixup::create(IsLittleEndian ? 0 : 2, MO.getExpr(), + (MCFixupKind)PPC::fixup_ppc_half16dq)); + return 0; +} + +unsigned +PPCMCCodeEmitter::getDispRIHashEncoding(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const { + // Encode imm for the hash load/store to stack for the ROP Protection + // instructions. + const MCOperand &MO = MI.getOperand(OpNo); + + assert(MO.isImm() && "Expecting an immediate operand."); + assert(!(MO.getImm() % 8) && "Expecting offset to be 8 byte aligned."); + + unsigned DX = (MO.getImm() >> 3) & 0x3F; + return DX; +} + +uint64_t +PPCMCCodeEmitter::getDispRI34PCRelEncoding(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const { + // Encode the displacement part of pc-relative memri34, which is an imm34. + // The 34 bit immediate can fall into one of three cases: + // 1) It is a relocation to be filled in by the linker represented as: + // (MCExpr::SymbolRef) + // 2) It is a relocation + SignedOffset represented as: + // (MCExpr::Binary(MCExpr::SymbolRef + MCExpr::Constant)) + // 3) It is a known value at compile time. + + // If this is not a MCExpr then we are in case 3) and we are dealing with + // a value known at compile time, not a relocation. + const MCOperand &MO = MI.getOperand(OpNo); + if (!MO.isExpr()) + return (getMachineOpValue(MI, MO, Fixups, STI)) & 0x3FFFFFFFFUL; + + // At this point in the function it is known that MO is of type MCExpr. + // Therefore we are dealing with either case 1) a symbol ref or + // case 2) a symbol ref plus a constant. + const MCExpr *Expr = MO.getExpr(); + switch (Expr->getKind()) { + default: + llvm_unreachable("Unsupported MCExpr for getMemRI34PCRelEncoding."); + case MCExpr::SymbolRef: { + // Relocation alone. + const MCSymbolRefExpr *SRE = cast<MCSymbolRefExpr>(Expr); + (void)SRE; + // Currently these are the only valid PCRelative Relocations. + assert((SRE->getKind() == MCSymbolRefExpr::VK_PCREL || + SRE->getKind() == MCSymbolRefExpr::VK_PPC_GOT_PCREL || + SRE->getKind() == MCSymbolRefExpr::VK_PPC_GOT_TLSGD_PCREL || + SRE->getKind() == MCSymbolRefExpr::VK_PPC_GOT_TLSLD_PCREL || + SRE->getKind() == MCSymbolRefExpr::VK_PPC_GOT_TPREL_PCREL) && + "VariantKind must be VK_PCREL or VK_PPC_GOT_PCREL or " + "VK_PPC_GOT_TLSGD_PCREL or VK_PPC_GOT_TLSLD_PCREL or " + "VK_PPC_GOT_TPREL_PCREL."); + // Generate the fixup for the relocation. + Fixups.push_back( + MCFixup::create(0, Expr, + static_cast<MCFixupKind>(PPC::fixup_ppc_pcrel34))); + // Put zero in the location of the immediate. The linker will fill in the + // correct value based on the relocation. + return 0; + } + case MCExpr::Binary: { + // Relocation plus some offset. + const MCBinaryExpr *BE = cast<MCBinaryExpr>(Expr); + assert(BE->getOpcode() == MCBinaryExpr::Add && + "Binary expression opcode must be an add."); + + const MCExpr *LHS = BE->getLHS(); + const MCExpr *RHS = BE->getRHS(); + + // Need to check in both directions. Reloc+Offset and Offset+Reloc. + if (LHS->getKind() != MCExpr::SymbolRef) + std::swap(LHS, RHS); + + if (LHS->getKind() != MCExpr::SymbolRef || + RHS->getKind() != MCExpr::Constant) + llvm_unreachable("Expecting to have one constant and one relocation."); + + const MCSymbolRefExpr *SRE = cast<MCSymbolRefExpr>(LHS); + (void)SRE; + assert(isInt<34>(cast<MCConstantExpr>(RHS)->getValue()) && + "Value must fit in 34 bits."); + + // Currently these are the only valid PCRelative Relocations. + assert((SRE->getKind() == MCSymbolRefExpr::VK_PCREL || + SRE->getKind() == MCSymbolRefExpr::VK_PPC_GOT_PCREL) && + "VariantKind must be VK_PCREL or VK_PPC_GOT_PCREL"); + // Generate the fixup for the relocation. + Fixups.push_back( + MCFixup::create(0, Expr, + static_cast<MCFixupKind>(PPC::fixup_ppc_pcrel34))); + // Put zero in the location of the immediate. The linker will fill in the + // correct value based on the relocation. + return 0; + } + } +} + +uint64_t +PPCMCCodeEmitter::getDispRI34Encoding(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const { + // Encode the displacement part of a memri34. + const MCOperand &MO = MI.getOperand(OpNo); + return (getMachineOpValue(MI, MO, Fixups, STI)) & 0x3FFFFFFFFUL; +} + +unsigned +PPCMCCodeEmitter::getDispSPE8Encoding(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const { + // Encode imm as a dispSPE8, which has the low 5-bits of (imm / 8). + const MCOperand &MO = MI.getOperand(OpNo); + assert(MO.isImm()); + return getMachineOpValue(MI, MO, Fixups, STI) >> 3; +} + +unsigned +PPCMCCodeEmitter::getDispSPE4Encoding(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const { + // Encode imm as a dispSPE8, which has the low 5-bits of (imm / 4). + const MCOperand &MO = MI.getOperand(OpNo); + assert(MO.isImm()); + return getMachineOpValue(MI, MO, Fixups, STI) >> 2; +} + +unsigned +PPCMCCodeEmitter::getDispSPE2Encoding(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const { + // Encode imm as a dispSPE8, which has the low 5-bits of (imm / 2). + const MCOperand &MO = MI.getOperand(OpNo); + assert(MO.isImm()); + return getMachineOpValue(MI, MO, Fixups, STI) >> 1; +} + +unsigned PPCMCCodeEmitter::getTLSRegEncoding(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const { + const MCOperand &MO = MI.getOperand(OpNo); + if (MO.isReg()) return getMachineOpValue(MI, MO, Fixups, STI); + + // Add a fixup for the TLS register, which simply provides a relocation + // hint to the linker that this statement is part of a relocation sequence. + // Return the thread-pointer register's encoding. Add a one byte displacement + // if using PC relative memops. + const MCExpr *Expr = MO.getExpr(); + const MCSymbolRefExpr *SRE = cast<MCSymbolRefExpr>(Expr); + bool IsPCRel = SRE->getKind() == MCSymbolRefExpr::VK_PPC_TLS_PCREL; + Fixups.push_back(MCFixup::create(IsPCRel ? 1 : 0, Expr, + (MCFixupKind)PPC::fixup_ppc_nofixup)); + const Triple &TT = STI.getTargetTriple(); + bool isPPC64 = TT.isPPC64(); + return CTX.getRegisterInfo()->getEncodingValue(isPPC64 ? PPC::X13 : PPC::R2); +} + +unsigned PPCMCCodeEmitter::getTLSCallEncoding(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const { + // For special TLS calls, we need two fixups; one for the branch target + // (__tls_get_addr), which we create via getDirectBrEncoding as usual, + // and one for the TLSGD or TLSLD symbol, which is emitted here. + const MCOperand &MO = MI.getOperand(OpNo+1); + Fixups.push_back(MCFixup::create(0, MO.getExpr(), + (MCFixupKind)PPC::fixup_ppc_nofixup)); + return getDirectBrEncoding(MI, OpNo, Fixups, STI); +} + +unsigned PPCMCCodeEmitter:: +get_crbitm_encoding(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const { + const MCOperand &MO = MI.getOperand(OpNo); + assert((MI.getOpcode() == PPC::MTOCRF || MI.getOpcode() == PPC::MTOCRF8 || + MI.getOpcode() == PPC::MFOCRF || MI.getOpcode() == PPC::MFOCRF8) && + (MO.getReg() >= PPC::CR0 && MO.getReg() <= PPC::CR7)); + return 0x80 >> CTX.getRegisterInfo()->getEncodingValue(MO.getReg()); +} + +// Get the index for this operand in this instruction. This is needed for +// computing the register number in PPC::getRegNumForOperand() for +// any instructions that use a different numbering scheme for registers in +// different operands. +static unsigned getOpIdxForMO(const MCInst &MI, const MCOperand &MO) { + for (unsigned i = 0; i < MI.getNumOperands(); i++) { + const MCOperand &Op = MI.getOperand(i); + if (&Op == &MO) + return i; + } + llvm_unreachable("This operand is not part of this instruction"); + return ~0U; // Silence any warnings about no return. +} + +uint64_t PPCMCCodeEmitter:: +getMachineOpValue(const MCInst &MI, const MCOperand &MO, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const { + if (MO.isReg()) { + // MTOCRF/MFOCRF should go through get_crbitm_encoding for the CR operand. + // The GPR operand should come through here though. + assert((MI.getOpcode() != PPC::MTOCRF && MI.getOpcode() != PPC::MTOCRF8 && + MI.getOpcode() != PPC::MFOCRF && MI.getOpcode() != PPC::MFOCRF8) || + MO.getReg() < PPC::CR0 || MO.getReg() > PPC::CR7); + unsigned OpNo = getOpIdxForMO(MI, MO); + unsigned Reg = + PPC::getRegNumForOperand(MCII.get(MI.getOpcode()), MO.getReg(), OpNo); + return CTX.getRegisterInfo()->getEncodingValue(Reg); + } + + assert(MO.isImm() && + "Relocation required in an instruction that we cannot encode!"); + return MO.getImm(); +} + +void PPCMCCodeEmitter::encodeInstruction(const MCInst &MI, + SmallVectorImpl<char> &CB, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const { + uint64_t Bits = getBinaryCodeForInstr(MI, Fixups, STI); + + // Output the constant in big/little endian byte order. + unsigned Size = getInstSizeInBytes(MI); + llvm::endianness E = + IsLittleEndian ? llvm::endianness::little : llvm::endianness::big; + switch (Size) { + case 0: + break; + case 4: + support::endian::write<uint32_t>(CB, Bits, E); + break; + case 8: + // If we emit a pair of instructions, the first one is + // always in the top 32 bits, even on little-endian. + support::endian::write<uint32_t>(CB, Bits >> 32, E); + support::endian::write<uint32_t>(CB, Bits, E); + break; + default: + llvm_unreachable("Invalid instruction size"); + } + + ++MCNumEmitted; // Keep track of the # of mi's emitted. +} + +// Get the number of bytes used to encode the given MCInst. +unsigned PPCMCCodeEmitter::getInstSizeInBytes(const MCInst &MI) const { + unsigned Opcode = MI.getOpcode(); + const MCInstrDesc &Desc = MCII.get(Opcode); + return Desc.getSize(); +} + +bool PPCMCCodeEmitter::isPrefixedInstruction(const MCInst &MI) const { + return MCII.get(MI.getOpcode()).TSFlags & PPCII::Prefixed; +} + +#include "PPCGenMCCodeEmitter.inc" diff --git a/contrib/llvm-project/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCCodeEmitter.h b/contrib/llvm-project/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCCodeEmitter.h new file mode 100644 index 000000000000..b57455718319 --- /dev/null +++ b/contrib/llvm-project/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCCodeEmitter.h @@ -0,0 +1,132 @@ +//===-- PPCMCCodeEmitter.h - Convert PPC code to machine code -------------===// +// +// 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 implements the PPCMCCodeEmitter class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_PPC_MCCODEEMITTER_PPCCODEEMITTER_H +#define LLVM_LIB_TARGET_PPC_MCCODEEMITTER_PPCCODEEMITTER_H + +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCCodeEmitter.h" +#include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/MC/MCInstrInfo.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCInst.h" + +namespace llvm { + +class PPCMCCodeEmitter : public MCCodeEmitter { + const MCInstrInfo &MCII; + const MCContext &CTX; + bool IsLittleEndian; + +public: + PPCMCCodeEmitter(const MCInstrInfo &mcii, MCContext &ctx) + : MCII(mcii), CTX(ctx), + IsLittleEndian(ctx.getAsmInfo()->isLittleEndian()) {} + PPCMCCodeEmitter(const PPCMCCodeEmitter &) = delete; + void operator=(const PPCMCCodeEmitter &) = delete; + ~PPCMCCodeEmitter() override = default; + + unsigned getDirectBrEncoding(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const; + unsigned getCondBrEncoding(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const; + unsigned getAbsDirectBrEncoding(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const; + unsigned getAbsCondBrEncoding(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const; + unsigned getImm16Encoding(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const; + uint64_t getImm34Encoding(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI, + MCFixupKind Fixup) const; + uint64_t getImm34EncodingNoPCRel(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const; + uint64_t getImm34EncodingPCRel(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const; + unsigned getDispRIEncoding(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const; + unsigned getDispRIXEncoding(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const; + unsigned getDispRIX16Encoding(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const; + unsigned getDispRIHashEncoding(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const; + uint64_t getDispRI34PCRelEncoding(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const; + uint64_t getDispRI34Encoding(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const; + unsigned getDispSPE8Encoding(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const; + unsigned getDispSPE4Encoding(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const; + unsigned getDispSPE2Encoding(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const; + unsigned getTLSRegEncoding(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const; + unsigned getTLSCallEncoding(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const; + unsigned get_crbitm_encoding(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const; + unsigned getVSRpEvenEncoding(const MCInst &MI, unsigned OpNo, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const; + + /// getMachineOpValue - Return binary encoding of operand. If the machine + /// operand requires relocation, record the relocation and return zero. + uint64_t getMachineOpValue(const MCInst &MI, const MCOperand &MO, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const; + + // getBinaryCodeForInstr - TableGen'erated function for getting the + // binary encoding for an instruction. + uint64_t getBinaryCodeForInstr(const MCInst &MI, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const; + + void encodeInstruction(const MCInst &MI, SmallVectorImpl<char> &CB, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const override; + + // Get the number of bytes used to encode the given MCInst. + unsigned getInstSizeInBytes(const MCInst &MI) const; + + // Is this instruction a prefixed instruction. + bool isPrefixedInstruction(const MCInst &MI) const; + + /// Check if Opcode corresponds to a call instruction that should be marked + /// with the NOTOC relocation. + bool isNoTOCCallInstr(const MCInst &MI) const; +}; + +} // namespace llvm + +#endif // LLVM_LIB_TARGET_PPC_MCCODEEMITTER_PPCCODEEMITTER_H diff --git a/contrib/llvm-project/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCExpr.cpp b/contrib/llvm-project/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCExpr.cpp new file mode 100644 index 000000000000..6cd04ee018fd --- /dev/null +++ b/contrib/llvm-project/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCExpr.cpp @@ -0,0 +1,175 @@ +//===-- PPCMCExpr.cpp - PPC specific MC expression classes ----------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "PPCMCExpr.h" +#include "PPCFixupKinds.h" +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCAssembler.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCObjectStreamer.h" + +using namespace llvm; + +#define DEBUG_TYPE "ppcmcexpr" + +const PPCMCExpr *PPCMCExpr::create(VariantKind Kind, const MCExpr *Expr, + MCContext &Ctx) { + return new (Ctx) PPCMCExpr(Kind, Expr); +} + +void PPCMCExpr::printImpl(raw_ostream &OS, const MCAsmInfo *MAI) const { + getSubExpr()->print(OS, MAI); + + switch (Kind) { + default: + llvm_unreachable("Invalid kind!"); + case VK_PPC_LO: + OS << "@l"; + break; + case VK_PPC_HI: + OS << "@h"; + break; + case VK_PPC_HA: + OS << "@ha"; + break; + case VK_PPC_HIGH: + OS << "@high"; + break; + case VK_PPC_HIGHA: + OS << "@higha"; + break; + case VK_PPC_HIGHER: + OS << "@higher"; + break; + case VK_PPC_HIGHERA: + OS << "@highera"; + break; + case VK_PPC_HIGHEST: + OS << "@highest"; + break; + case VK_PPC_HIGHESTA: + OS << "@highesta"; + break; + } +} + +bool +PPCMCExpr::evaluateAsConstant(int64_t &Res) const { + MCValue Value; + + if (!getSubExpr()->evaluateAsRelocatable(Value, nullptr, nullptr)) + return false; + + if (!Value.isAbsolute()) + return false; + + Res = evaluateAsInt64(Value.getConstant()); + return true; +} + +int64_t +PPCMCExpr::evaluateAsInt64(int64_t Value) const { + switch (Kind) { + case VK_PPC_LO: + return Value & 0xffff; + case VK_PPC_HI: + return (Value >> 16) & 0xffff; + case VK_PPC_HA: + return ((Value + 0x8000) >> 16) & 0xffff; + case VK_PPC_HIGH: + return (Value >> 16) & 0xffff; + case VK_PPC_HIGHA: + return ((Value + 0x8000) >> 16) & 0xffff; + case VK_PPC_HIGHER: + return (Value >> 32) & 0xffff; + case VK_PPC_HIGHERA: + return ((Value + 0x8000) >> 32) & 0xffff; + case VK_PPC_HIGHEST: + return (Value >> 48) & 0xffff; + case VK_PPC_HIGHESTA: + return ((Value + 0x8000) >> 48) & 0xffff; + case VK_PPC_None: + break; + } + llvm_unreachable("Invalid kind!"); +} + +bool +PPCMCExpr::evaluateAsRelocatableImpl(MCValue &Res, + const MCAsmLayout *Layout, + const MCFixup *Fixup) const { + MCValue Value; + + if (!getSubExpr()->evaluateAsRelocatable(Value, Layout, Fixup)) + return false; + + if (Value.isAbsolute()) { + int64_t Result = evaluateAsInt64(Value.getConstant()); + bool IsHalf16 = Fixup && Fixup->getTargetKind() == PPC::fixup_ppc_half16; + bool IsHalf16DS = + Fixup && Fixup->getTargetKind() == PPC::fixup_ppc_half16ds; + bool IsHalf16DQ = + Fixup && Fixup->getTargetKind() == PPC::fixup_ppc_half16dq; + bool IsHalf = IsHalf16 || IsHalf16DS || IsHalf16DQ; + + if (!IsHalf && Result >= 0x8000) + return false; + if ((IsHalf16DS && (Result & 0x3)) || (IsHalf16DQ && (Result & 0xf))) + return false; + + Res = MCValue::get(Result); + } else { + if (!Layout) + return false; + + MCContext &Context = Layout->getAssembler().getContext(); + const MCSymbolRefExpr *Sym = Value.getSymA(); + MCSymbolRefExpr::VariantKind Modifier = Sym->getKind(); + if (Modifier != MCSymbolRefExpr::VK_None) + return false; + switch (Kind) { + default: + llvm_unreachable("Invalid kind!"); + case VK_PPC_LO: + Modifier = MCSymbolRefExpr::VK_PPC_LO; + break; + case VK_PPC_HI: + Modifier = MCSymbolRefExpr::VK_PPC_HI; + break; + case VK_PPC_HA: + Modifier = MCSymbolRefExpr::VK_PPC_HA; + break; + case VK_PPC_HIGH: + Modifier = MCSymbolRefExpr::VK_PPC_HIGH; + break; + case VK_PPC_HIGHA: + Modifier = MCSymbolRefExpr::VK_PPC_HIGHA; + break; + case VK_PPC_HIGHERA: + Modifier = MCSymbolRefExpr::VK_PPC_HIGHERA; + break; + case VK_PPC_HIGHER: + Modifier = MCSymbolRefExpr::VK_PPC_HIGHER; + break; + case VK_PPC_HIGHEST: + Modifier = MCSymbolRefExpr::VK_PPC_HIGHEST; + break; + case VK_PPC_HIGHESTA: + Modifier = MCSymbolRefExpr::VK_PPC_HIGHESTA; + break; + } + Sym = MCSymbolRefExpr::create(&Sym->getSymbol(), Modifier, Context); + Res = MCValue::get(Sym, Value.getSymB(), Value.getConstant()); + } + + return true; +} + +void PPCMCExpr::visitUsedExpr(MCStreamer &Streamer) const { + Streamer.visitUsedExpr(*getSubExpr()); +} diff --git a/contrib/llvm-project/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCExpr.h b/contrib/llvm-project/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCExpr.h new file mode 100644 index 000000000000..1dbc7eae63c8 --- /dev/null +++ b/contrib/llvm-project/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCExpr.h @@ -0,0 +1,93 @@ +//===-- PPCMCExpr.h - PPC specific MC expression classes --------*- C++ -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_POWERPC_MCTARGETDESC_PPCMCEXPR_H +#define LLVM_LIB_TARGET_POWERPC_MCTARGETDESC_PPCMCEXPR_H + +#include "llvm/MC/MCAsmLayout.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCValue.h" + +namespace llvm { + +class PPCMCExpr : public MCTargetExpr { +public: + enum VariantKind { + VK_PPC_None, + VK_PPC_LO, + VK_PPC_HI, + VK_PPC_HA, + VK_PPC_HIGH, + VK_PPC_HIGHA, + VK_PPC_HIGHER, + VK_PPC_HIGHERA, + VK_PPC_HIGHEST, + VK_PPC_HIGHESTA + }; + +private: + const VariantKind Kind; + const MCExpr *Expr; + + int64_t evaluateAsInt64(int64_t Value) const; + + explicit PPCMCExpr(VariantKind Kind, const MCExpr *Expr) + : Kind(Kind), Expr(Expr) {} + +public: + /// @name Construction + /// @{ + + static const PPCMCExpr *create(VariantKind Kind, const MCExpr *Expr, + MCContext &Ctx); + + static const PPCMCExpr *createLo(const MCExpr *Expr, MCContext &Ctx) { + return create(VK_PPC_LO, Expr, Ctx); + } + + static const PPCMCExpr *createHi(const MCExpr *Expr, MCContext &Ctx) { + return create(VK_PPC_HI, Expr, Ctx); + } + + static const PPCMCExpr *createHa(const MCExpr *Expr, MCContext &Ctx) { + return create(VK_PPC_HA, Expr, Ctx); + } + + /// @} + /// @name Accessors + /// @{ + + /// getOpcode - Get the kind of this expression. + VariantKind getKind() const { return Kind; } + + /// getSubExpr - Get the child of this expression. + const MCExpr *getSubExpr() const { return Expr; } + + /// @} + + void printImpl(raw_ostream &OS, const MCAsmInfo *MAI) const override; + bool evaluateAsRelocatableImpl(MCValue &Res, + const MCAsmLayout *Layout, + const MCFixup *Fixup) const override; + void visitUsedExpr(MCStreamer &Streamer) const override; + MCFragment *findAssociatedFragment() const override { + return getSubExpr()->findAssociatedFragment(); + } + + // There are no TLS PPCMCExprs at the moment. + void fixELFSymbolsInTLSFixups(MCAssembler &Asm) const override {} + + bool evaluateAsConstant(int64_t &Res) const; + + static bool classof(const MCExpr *E) { + return E->getKind() == MCExpr::Target; + } +}; +} // end namespace llvm + +#endif diff --git a/contrib/llvm-project/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCTargetDesc.cpp b/contrib/llvm-project/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCTargetDesc.cpp new file mode 100644 index 000000000000..a804dd823daa --- /dev/null +++ b/contrib/llvm-project/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCTargetDesc.cpp @@ -0,0 +1,529 @@ +//===-- PPCMCTargetDesc.cpp - PowerPC Target Descriptions -----------------===// +// +// 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 provides PowerPC specific target descriptions. +// +//===----------------------------------------------------------------------===// + +#include "MCTargetDesc/PPCMCTargetDesc.h" +#include "MCTargetDesc/PPCInstPrinter.h" +#include "MCTargetDesc/PPCMCAsmInfo.h" +#include "PPCELFStreamer.h" +#include "PPCTargetStreamer.h" +#include "PPCXCOFFStreamer.h" +#include "TargetInfo/PowerPCTargetInfo.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/BinaryFormat/ELF.h" +#include "llvm/MC/MCAsmBackend.h" +#include "llvm/MC/MCAssembler.h" +#include "llvm/MC/MCCodeEmitter.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCDwarf.h" +#include "llvm/MC/MCELFStreamer.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCInstrAnalysis.h" +#include "llvm/MC/MCInstrInfo.h" +#include "llvm/MC/MCObjectWriter.h" +#include "llvm/MC/MCRegisterInfo.h" +#include "llvm/MC/MCSectionXCOFF.h" +#include "llvm/MC/MCStreamer.h" +#include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/MC/MCSymbol.h" +#include "llvm/MC/MCSymbolELF.h" +#include "llvm/MC/MCSymbolXCOFF.h" +#include "llvm/MC/TargetRegistry.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/CodeGen.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/FormattedStream.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/TargetParser/Triple.h" + +using namespace llvm; + +#define GET_INSTRINFO_MC_DESC +#define ENABLE_INSTR_PREDICATE_VERIFIER +#include "PPCGenInstrInfo.inc" + +#define GET_SUBTARGETINFO_MC_DESC +#include "PPCGenSubtargetInfo.inc" + +#define GET_REGINFO_MC_DESC +#include "PPCGenRegisterInfo.inc" + +/// stripRegisterPrefix - This method strips the character prefix from a +/// register name so that only the number is left. Used by for linux asm. +const char *PPC::stripRegisterPrefix(const char *RegName) { + switch (RegName[0]) { + case 'a': + if (RegName[1] == 'c' && RegName[2] == 'c') + return RegName + 3; + break; + case 'f': + if (RegName[1] == 'p') + return RegName + 2; + [[fallthrough]]; + case 'r': + case 'v': + if (RegName[1] == 's') { + if (RegName[2] == 'p') + return RegName + 3; + return RegName + 2; + } + return RegName + 1; + case 'c': + if (RegName[1] == 'r') + return RegName + 2; + break; + case 'w': + // For wacc and wacc_hi + if (RegName[1] == 'a' && RegName[2] == 'c' && RegName[3] == 'c') { + if (RegName[4] == '_') + return RegName + 7; + else + return RegName + 4; + } + break; + case 'd': + // For dmr, dmrp, dmrrow, dmrrowp + if (RegName[1] == 'm' && RegName[2] == 'r') { + if (RegName[3] == 'r' && RegName[4] == 'o' && RegName[5] == 'w' && + RegName[6] == 'p') + return RegName + 7; + else if (RegName[3] == 'r' && RegName[4] == 'o' && RegName[5] == 'w') + return RegName + 6; + else if (RegName[3] == 'p') + return RegName + 4; + else + return RegName + 3; + } + break; + } + + return RegName; +} + +/// getRegNumForOperand - some operands use different numbering schemes +/// for the same registers. For example, a VSX instruction may have any of +/// vs0-vs63 allocated whereas an Altivec instruction could only have +/// vs32-vs63 allocated (numbered as v0-v31). This function returns the actual +/// register number needed for the opcode/operand number combination. +/// The operand number argument will be useful when we need to extend this +/// to instructions that use both Altivec and VSX numbering (for different +/// operands). +unsigned PPC::getRegNumForOperand(const MCInstrDesc &Desc, unsigned Reg, + unsigned OpNo) { + int16_t regClass = Desc.operands()[OpNo].RegClass; + switch (regClass) { + // We store F0-F31, VF0-VF31 in MCOperand and it should be F0-F31, + // VSX32-VSX63 during encoding/disassembling + case PPC::VSSRCRegClassID: + case PPC::VSFRCRegClassID: + if (PPC::isVFRegister(Reg)) + return PPC::VSX32 + (Reg - PPC::VF0); + break; + // We store VSL0-VSL31, V0-V31 in MCOperand and it should be VSL0-VSL31, + // VSX32-VSX63 during encoding/disassembling + case PPC::VSRCRegClassID: + if (PPC::isVRRegister(Reg)) + return PPC::VSX32 + (Reg - PPC::V0); + break; + // Other RegClass doesn't need mapping + default: + break; + } + return Reg; +} + +PPCTargetStreamer::PPCTargetStreamer(MCStreamer &S) : MCTargetStreamer(S) {} + +// Pin the vtable to this file. +PPCTargetStreamer::~PPCTargetStreamer() = default; + +static MCInstrInfo *createPPCMCInstrInfo() { + MCInstrInfo *X = new MCInstrInfo(); + InitPPCMCInstrInfo(X); + return X; +} + +static MCRegisterInfo *createPPCMCRegisterInfo(const Triple &TT) { + bool isPPC64 = + (TT.getArch() == Triple::ppc64 || TT.getArch() == Triple::ppc64le); + unsigned Flavour = isPPC64 ? 0 : 1; + unsigned RA = isPPC64 ? PPC::LR8 : PPC::LR; + + MCRegisterInfo *X = new MCRegisterInfo(); + InitPPCMCRegisterInfo(X, RA, Flavour, Flavour); + return X; +} + +static MCSubtargetInfo *createPPCMCSubtargetInfo(const Triple &TT, + StringRef CPU, StringRef FS) { + // Set some default feature to MC layer. + std::string FullFS = std::string(FS); + + if (TT.isOSAIX()) { + if (!FullFS.empty()) + FullFS = "+aix," + FullFS; + else + FullFS = "+aix"; + } + + return createPPCMCSubtargetInfoImpl(TT, CPU, /*TuneCPU*/ CPU, FullFS); +} + +static MCAsmInfo *createPPCMCAsmInfo(const MCRegisterInfo &MRI, + const Triple &TheTriple, + const MCTargetOptions &Options) { + bool isPPC64 = (TheTriple.getArch() == Triple::ppc64 || + TheTriple.getArch() == Triple::ppc64le); + + MCAsmInfo *MAI; + if (TheTriple.isOSBinFormatXCOFF()) + MAI = new PPCXCOFFMCAsmInfo(isPPC64, TheTriple); + else + MAI = new PPCELFMCAsmInfo(isPPC64, TheTriple); + + // Initial state of the frame pointer is R1. + unsigned Reg = isPPC64 ? PPC::X1 : PPC::R1; + MCCFIInstruction Inst = + MCCFIInstruction::cfiDefCfa(nullptr, MRI.getDwarfRegNum(Reg, true), 0); + MAI->addInitialFrameState(Inst); + + return MAI; +} + +static MCStreamer * +createPPCELFStreamer(const Triple &T, MCContext &Context, + std::unique_ptr<MCAsmBackend> &&MAB, + std::unique_ptr<MCObjectWriter> &&OW, + std::unique_ptr<MCCodeEmitter> &&Emitter, bool RelaxAll) { + return createPPCELFStreamer(Context, std::move(MAB), std::move(OW), + std::move(Emitter)); +} + +static MCStreamer *createPPCXCOFFStreamer( + const Triple &T, MCContext &Context, std::unique_ptr<MCAsmBackend> &&MAB, + std::unique_ptr<MCObjectWriter> &&OW, + std::unique_ptr<MCCodeEmitter> &&Emitter, bool RelaxAll) { + return createPPCXCOFFStreamer(Context, std::move(MAB), std::move(OW), + std::move(Emitter)); +} + +namespace { + +class PPCTargetAsmStreamer : public PPCTargetStreamer { + formatted_raw_ostream &OS; + +public: + PPCTargetAsmStreamer(MCStreamer &S, formatted_raw_ostream &OS) + : PPCTargetStreamer(S), OS(OS) {} + + void emitTCEntry(const MCSymbol &S, + MCSymbolRefExpr::VariantKind Kind) override { + if (const MCSymbolXCOFF *XSym = dyn_cast<MCSymbolXCOFF>(&S)) { + MCSymbolXCOFF *TCSym = + cast<MCSectionXCOFF>(Streamer.getCurrentSectionOnly()) + ->getQualNameSymbol(); + // On AIX, we have a region handle (symbol@m) and the variable offset + // (symbol@{gd|ie|le}) for TLS variables, depending on the TLS model. + if (Kind == MCSymbolRefExpr::VariantKind::VK_PPC_AIX_TLSGD || + Kind == MCSymbolRefExpr::VariantKind::VK_PPC_AIX_TLSGDM || + Kind == MCSymbolRefExpr::VariantKind::VK_PPC_AIX_TLSIE || + Kind == MCSymbolRefExpr::VariantKind::VK_PPC_AIX_TLSLE) + OS << "\t.tc " << TCSym->getName() << "," << XSym->getName() << "@" + << MCSymbolRefExpr::getVariantKindName(Kind) << '\n'; + else + OS << "\t.tc " << TCSym->getName() << "," << XSym->getName() << '\n'; + + if (TCSym->hasRename()) + Streamer.emitXCOFFRenameDirective(TCSym, TCSym->getSymbolTableName()); + return; + } + + OS << "\t.tc " << S.getName() << "[TC]," << S.getName() << '\n'; + } + + void emitMachine(StringRef CPU) override { + OS << "\t.machine " << CPU << '\n'; + } + + void emitAbiVersion(int AbiVersion) override { + OS << "\t.abiversion " << AbiVersion << '\n'; + } + + void emitLocalEntry(MCSymbolELF *S, const MCExpr *LocalOffset) override { + const MCAsmInfo *MAI = Streamer.getContext().getAsmInfo(); + + OS << "\t.localentry\t"; + S->print(OS, MAI); + OS << ", "; + LocalOffset->print(OS, MAI); + OS << '\n'; + } +}; + +class PPCTargetELFStreamer : public PPCTargetStreamer { +public: + PPCTargetELFStreamer(MCStreamer &S) : PPCTargetStreamer(S) {} + + MCELFStreamer &getStreamer() { + return static_cast<MCELFStreamer &>(Streamer); + } + + void emitTCEntry(const MCSymbol &S, + MCSymbolRefExpr::VariantKind Kind) override { + // Creates a R_PPC64_TOC relocation + Streamer.emitValueToAlignment(Align(8)); + Streamer.emitSymbolValue(&S, 8); + } + + void emitMachine(StringRef CPU) override { + // FIXME: Is there anything to do in here or does this directive only + // limit the parser? + } + + void emitAbiVersion(int AbiVersion) override { + MCAssembler &MCA = getStreamer().getAssembler(); + unsigned Flags = MCA.getELFHeaderEFlags(); + Flags &= ~ELF::EF_PPC64_ABI; + Flags |= (AbiVersion & ELF::EF_PPC64_ABI); + MCA.setELFHeaderEFlags(Flags); + } + + void emitLocalEntry(MCSymbolELF *S, const MCExpr *LocalOffset) override { + MCAssembler &MCA = getStreamer().getAssembler(); + + // encodePPC64LocalEntryOffset will report an error if it cannot + // encode LocalOffset. + unsigned Encoded = encodePPC64LocalEntryOffset(LocalOffset); + + unsigned Other = S->getOther(); + Other &= ~ELF::STO_PPC64_LOCAL_MASK; + Other |= Encoded; + S->setOther(Other); + + // For GAS compatibility, unless we already saw a .abiversion directive, + // set e_flags to indicate ELFv2 ABI. + unsigned Flags = MCA.getELFHeaderEFlags(); + if ((Flags & ELF::EF_PPC64_ABI) == 0) + MCA.setELFHeaderEFlags(Flags | 2); + } + + void emitAssignment(MCSymbol *S, const MCExpr *Value) override { + auto *Symbol = cast<MCSymbolELF>(S); + + // When encoding an assignment to set symbol A to symbol B, also copy + // the st_other bits encoding the local entry point offset. + if (copyLocalEntry(Symbol, Value)) + UpdateOther.insert(Symbol); + else + UpdateOther.erase(Symbol); + } + + void finish() override { + for (auto *Sym : UpdateOther) + if (Sym->isVariable()) + copyLocalEntry(Sym, Sym->getVariableValue()); + + // Clear the set of symbols that needs to be updated so the streamer can + // be reused without issues. + UpdateOther.clear(); + } + +private: + SmallPtrSet<MCSymbolELF *, 32> UpdateOther; + + bool copyLocalEntry(MCSymbolELF *D, const MCExpr *S) { + auto *Ref = dyn_cast<const MCSymbolRefExpr>(S); + if (!Ref) + return false; + const auto &RhsSym = cast<MCSymbolELF>(Ref->getSymbol()); + unsigned Other = D->getOther(); + Other &= ~ELF::STO_PPC64_LOCAL_MASK; + Other |= RhsSym.getOther() & ELF::STO_PPC64_LOCAL_MASK; + D->setOther(Other); + return true; + } + + unsigned encodePPC64LocalEntryOffset(const MCExpr *LocalOffset) { + MCAssembler &MCA = getStreamer().getAssembler(); + int64_t Offset; + if (!LocalOffset->evaluateAsAbsolute(Offset, MCA)) + MCA.getContext().reportError(LocalOffset->getLoc(), + ".localentry expression must be absolute"); + + switch (Offset) { + default: + MCA.getContext().reportError( + LocalOffset->getLoc(), ".localentry expression must be a power of 2"); + return 0; + case 0: + return 0; + case 1: + return 1 << ELF::STO_PPC64_LOCAL_BIT; + case 4: + case 8: + case 16: + case 32: + case 64: + return Log2_32(Offset) << ELF::STO_PPC64_LOCAL_BIT; + } + } +}; + +class PPCTargetMachOStreamer : public PPCTargetStreamer { +public: + PPCTargetMachOStreamer(MCStreamer &S) : PPCTargetStreamer(S) {} + + void emitTCEntry(const MCSymbol &S, + MCSymbolRefExpr::VariantKind Kind) override { + llvm_unreachable("Unknown pseudo-op: .tc"); + } + + void emitMachine(StringRef CPU) override { + // FIXME: We should update the CPUType, CPUSubType in the Object file if + // the new values are different from the defaults. + } + + void emitAbiVersion(int AbiVersion) override { + llvm_unreachable("Unknown pseudo-op: .abiversion"); + } + + void emitLocalEntry(MCSymbolELF *S, const MCExpr *LocalOffset) override { + llvm_unreachable("Unknown pseudo-op: .localentry"); + } +}; + +class PPCTargetXCOFFStreamer : public PPCTargetStreamer { +public: + PPCTargetXCOFFStreamer(MCStreamer &S) : PPCTargetStreamer(S) {} + + void emitTCEntry(const MCSymbol &S, + MCSymbolRefExpr::VariantKind Kind) override { + const MCAsmInfo *MAI = Streamer.getContext().getAsmInfo(); + const unsigned PointerSize = MAI->getCodePointerSize(); + Streamer.emitValueToAlignment(Align(PointerSize)); + Streamer.emitValue(MCSymbolRefExpr::create(&S, Kind, Streamer.getContext()), + PointerSize); + } + + void emitMachine(StringRef CPU) override { + llvm_unreachable("Machine pseudo-ops are invalid for XCOFF."); + } + + void emitAbiVersion(int AbiVersion) override { + llvm_unreachable("ABI-version pseudo-ops are invalid for XCOFF."); + } + + void emitLocalEntry(MCSymbolELF *S, const MCExpr *LocalOffset) override { + llvm_unreachable("Local-entry pseudo-ops are invalid for XCOFF."); + } +}; + +} // end anonymous namespace + +static MCTargetStreamer *createAsmTargetStreamer(MCStreamer &S, + formatted_raw_ostream &OS, + MCInstPrinter *InstPrint, + bool isVerboseAsm) { + return new PPCTargetAsmStreamer(S, OS); +} + +static MCTargetStreamer *createNullTargetStreamer(MCStreamer &S) { + return new PPCTargetStreamer(S); +} + +static MCTargetStreamer * +createObjectTargetStreamer(MCStreamer &S, const MCSubtargetInfo &STI) { + const Triple &TT = STI.getTargetTriple(); + if (TT.isOSBinFormatELF()) + return new PPCTargetELFStreamer(S); + if (TT.isOSBinFormatXCOFF()) + return new PPCTargetXCOFFStreamer(S); + return new PPCTargetMachOStreamer(S); +} + +static MCInstPrinter *createPPCMCInstPrinter(const Triple &T, + unsigned SyntaxVariant, + const MCAsmInfo &MAI, + const MCInstrInfo &MII, + const MCRegisterInfo &MRI) { + return new PPCInstPrinter(MAI, MII, MRI, T); +} + +namespace { + +class PPCMCInstrAnalysis : public MCInstrAnalysis { +public: + explicit PPCMCInstrAnalysis(const MCInstrInfo *Info) + : MCInstrAnalysis(Info) {} + + bool evaluateBranch(const MCInst &Inst, uint64_t Addr, uint64_t Size, + uint64_t &Target) const override { + unsigned NumOps = Inst.getNumOperands(); + if (NumOps == 0 || + Info->get(Inst.getOpcode()).operands()[NumOps - 1].OperandType != + MCOI::OPERAND_PCREL) + return false; + Target = Addr + Inst.getOperand(NumOps - 1).getImm() * Size; + return true; + } +}; + +} // end anonymous namespace + +static MCInstrAnalysis *createPPCMCInstrAnalysis(const MCInstrInfo *Info) { + return new PPCMCInstrAnalysis(Info); +} + +extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializePowerPCTargetMC() { + for (Target *T : {&getThePPC32Target(), &getThePPC32LETarget(), + &getThePPC64Target(), &getThePPC64LETarget()}) { + // Register the MC asm info. + RegisterMCAsmInfoFn C(*T, createPPCMCAsmInfo); + + // Register the MC instruction info. + TargetRegistry::RegisterMCInstrInfo(*T, createPPCMCInstrInfo); + + // Register the MC register info. + TargetRegistry::RegisterMCRegInfo(*T, createPPCMCRegisterInfo); + + // Register the MC subtarget info. + TargetRegistry::RegisterMCSubtargetInfo(*T, createPPCMCSubtargetInfo); + + // Register the MC instruction analyzer. + TargetRegistry::RegisterMCInstrAnalysis(*T, createPPCMCInstrAnalysis); + + // Register the MC Code Emitter + TargetRegistry::RegisterMCCodeEmitter(*T, createPPCMCCodeEmitter); + + // Register the asm backend. + TargetRegistry::RegisterMCAsmBackend(*T, createPPCAsmBackend); + + // Register the elf streamer. + TargetRegistry::RegisterELFStreamer(*T, createPPCELFStreamer); + + // Register the XCOFF streamer. + TargetRegistry::RegisterXCOFFStreamer(*T, createPPCXCOFFStreamer); + + // Register the object target streamer. + TargetRegistry::RegisterObjectTargetStreamer(*T, + createObjectTargetStreamer); + + // Register the asm target streamer. + TargetRegistry::RegisterAsmTargetStreamer(*T, createAsmTargetStreamer); + + // Register the null target streamer. + TargetRegistry::RegisterNullTargetStreamer(*T, createNullTargetStreamer); + + // Register the MCInstPrinter. + TargetRegistry::RegisterMCInstPrinter(*T, createPPCMCInstPrinter); + } +} diff --git a/contrib/llvm-project/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCTargetDesc.h b/contrib/llvm-project/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCTargetDesc.h new file mode 100644 index 000000000000..16777725990a --- /dev/null +++ b/contrib/llvm-project/llvm/lib/Target/PowerPC/MCTargetDesc/PPCMCTargetDesc.h @@ -0,0 +1,298 @@ +//===-- PPCMCTargetDesc.h - PowerPC Target Descriptions ---------*- C++ -*-===// +// +// 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 provides PowerPC specific target descriptions. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_POWERPC_MCTARGETDESC_PPCMCTARGETDESC_H +#define LLVM_LIB_TARGET_POWERPC_MCTARGETDESC_PPCMCTARGETDESC_H + +// GCC #defines PPC on Linux but we use it as our namespace name +#undef PPC + +#include "llvm/MC/MCRegisterInfo.h" +#include "llvm/Support/MathExtras.h" +#include <cstdint> +#include <memory> + +namespace llvm { + +class MCAsmBackend; +class MCCodeEmitter; +class MCContext; +class MCInstrDesc; +class MCInstrInfo; +class MCObjectTargetWriter; +class MCRegisterInfo; +class MCSubtargetInfo; +class MCTargetOptions; +class Target; + +namespace PPC { +/// stripRegisterPrefix - This method strips the character prefix from a +/// register name so that only the number is left. Used by for linux asm. +const char *stripRegisterPrefix(const char *RegName); + +/// getRegNumForOperand - some operands use different numbering schemes +/// for the same registers. For example, a VSX instruction may have any of +/// vs0-vs63 allocated whereas an Altivec instruction could only have +/// vs32-vs63 allocated (numbered as v0-v31). This function returns the actual +/// register number needed for the opcode/operand number combination. +/// The operand number argument will be useful when we need to extend this +/// to instructions that use both Altivec and VSX numbering (for different +/// operands). +unsigned getRegNumForOperand(const MCInstrDesc &Desc, unsigned Reg, + unsigned OpNo); + +} // namespace PPC + +MCCodeEmitter *createPPCMCCodeEmitter(const MCInstrInfo &MCII, + MCContext &Ctx); + +MCAsmBackend *createPPCAsmBackend(const Target &T, const MCSubtargetInfo &STI, + const MCRegisterInfo &MRI, + const MCTargetOptions &Options); + +/// Construct an PPC ELF object writer. +std::unique_ptr<MCObjectTargetWriter> createPPCELFObjectWriter(bool Is64Bit, + uint8_t OSABI); +/// Construct a PPC Mach-O object writer. +std::unique_ptr<MCObjectTargetWriter> +createPPCMachObjectWriter(bool Is64Bit, uint32_t CPUType, uint32_t CPUSubtype); + +/// Construct a PPC XCOFF object writer. +std::unique_ptr<MCObjectTargetWriter> createPPCXCOFFObjectWriter(bool Is64Bit); + +/// Returns true iff Val consists of one contiguous run of 1s with any number of +/// 0s on either side. The 1s are allowed to wrap from LSB to MSB, so +/// 0x000FFF0, 0x0000FFFF, and 0xFF0000FF are all runs. 0x0F0F0000 is not, +/// since all 1s are not contiguous. +static inline bool isRunOfOnes(unsigned Val, unsigned &MB, unsigned &ME) { + if (!Val) + return false; + + if (isShiftedMask_32(Val)) { + // look for the first non-zero bit + MB = llvm::countl_zero(Val); + // look for the first zero bit after the run of ones + ME = llvm::countl_zero((Val - 1) ^ Val); + return true; + } else { + Val = ~Val; // invert mask + if (isShiftedMask_32(Val)) { + // effectively look for the first zero bit + ME = llvm::countl_zero(Val) - 1; + // effectively look for the first one bit after the run of zeros + MB = llvm::countl_zero((Val - 1) ^ Val) + 1; + return true; + } + } + // no run present + return false; +} + +static inline bool isRunOfOnes64(uint64_t Val, unsigned &MB, unsigned &ME) { + if (!Val) + return false; + + if (isShiftedMask_64(Val)) { + // look for the first non-zero bit + MB = llvm::countl_zero(Val); + // look for the first zero bit after the run of ones + ME = llvm::countl_zero((Val - 1) ^ Val); + return true; + } else { + Val = ~Val; // invert mask + if (isShiftedMask_64(Val)) { + // effectively look for the first zero bit + ME = llvm::countl_zero(Val) - 1; + // effectively look for the first one bit after the run of zeros + MB = llvm::countl_zero((Val - 1) ^ Val) + 1; + return true; + } + } + // no run present + return false; +} + +/// PPCII - This namespace holds all of the PowerPC target-specific +/// per-instruction flags. These must match the corresponding definitions in +/// PPC.td and PPCInstrFormats.td. +namespace PPCII { +enum { + // PPC970 Instruction Flags. These flags describe the characteristics of the + // PowerPC 970 (aka G5) dispatch groups and how they are formed out of + // raw machine instructions. + + /// PPC970_First - This instruction starts a new dispatch group, so it will + /// always be the first one in the group. + PPC970_First = 0x1, + + /// PPC970_Single - This instruction starts a new dispatch group and + /// terminates it, so it will be the sole instruction in the group. + PPC970_Single = 0x2, + + /// PPC970_Cracked - This instruction is cracked into two pieces, requiring + /// two dispatch pipes to be available to issue. + PPC970_Cracked = 0x4, + + /// PPC970_Mask/Shift - This is a bitmask that selects the pipeline type that + /// an instruction is issued to. + PPC970_Shift = 3, + PPC970_Mask = 0x07 << PPC970_Shift +}; +enum PPC970_Unit { + /// These are the various PPC970 execution unit pipelines. Each instruction + /// is one of these. + PPC970_Pseudo = 0 << PPC970_Shift, // Pseudo instruction + PPC970_FXU = 1 << PPC970_Shift, // Fixed Point (aka Integer/ALU) Unit + PPC970_LSU = 2 << PPC970_Shift, // Load Store Unit + PPC970_FPU = 3 << PPC970_Shift, // Floating Point Unit + PPC970_CRU = 4 << PPC970_Shift, // Control Register Unit + PPC970_VALU = 5 << PPC970_Shift, // Vector ALU + PPC970_VPERM = 6 << PPC970_Shift, // Vector Permute Unit + PPC970_BRU = 7 << PPC970_Shift // Branch Unit +}; + +enum { + /// Shift count to bypass PPC970 flags + NewDef_Shift = 6, + + /// This instruction is an X-Form memory operation. + XFormMemOp = 0x1 << NewDef_Shift, + /// This instruction is prefixed. + Prefixed = 0x1 << (NewDef_Shift + 1), + /// This instruction produced a sign extended result. + SExt32To64 = 0x1 << (NewDef_Shift + 2), + /// This instruction produced a zero extended result. + ZExt32To64 = 0x1 << (NewDef_Shift + 3) +}; +} // end namespace PPCII + +} // end namespace llvm + +// Defines symbolic names for PowerPC registers. This defines a mapping from +// register name to register number. +// +#define GET_REGINFO_ENUM +#include "PPCGenRegisterInfo.inc" + +// Defines symbolic names for the PowerPC instructions. +// +#define GET_INSTRINFO_ENUM +#define GET_INSTRINFO_SCHED_ENUM +#define GET_INSTRINFO_MC_HELPER_DECLS +#include "PPCGenInstrInfo.inc" + +#define GET_SUBTARGETINFO_ENUM +#include "PPCGenSubtargetInfo.inc" + +#define PPC_REGS0_7(X) \ + { \ + X##0, X##1, X##2, X##3, X##4, X##5, X##6, X##7 \ + } + +#define PPC_REGS0_31(X) \ + { \ + X##0, X##1, X##2, X##3, X##4, X##5, X##6, X##7, X##8, X##9, X##10, X##11, \ + X##12, X##13, X##14, X##15, X##16, X##17, X##18, X##19, X##20, X##21, \ + X##22, X##23, X##24, X##25, X##26, X##27, X##28, X##29, X##30, X##31 \ + } + +#define PPC_REGS_EVEN0_30(X) \ + { \ + X##0, X##2, X##4, X##6, X##8, X##10, X##12, X##14, X##16, X##18, X##20, \ + X##22, X##24, X##26, X##28, X##30 \ + } + +#define PPC_REGS0_63(X) \ + { \ + X##0, X##1, X##2, X##3, X##4, X##5, X##6, X##7, X##8, X##9, X##10, X##11, \ + X##12, X##13, X##14, X##15, X##16, X##17, X##18, X##19, X##20, X##21, \ + X##22, X##23, X##24, X##25, X##26, X##27, X##28, X##29, X##30, X##31, \ + X##32, X##33, X##34, X##35, X##36, X##37, X##38, X##39, X##40, X##41, \ + X##42, X##43, X##44, X##45, X##46, X##47, X##48, X##49, X##50, X##51, \ + X##52, X##53, X##54, X##55, X##56, X##57, X##58, X##59, X##60, X##61, \ + X##62, X##63 \ + } + +#define PPC_REGS_NO0_31(Z, X) \ + { \ + Z, X##1, X##2, X##3, X##4, X##5, X##6, X##7, X##8, X##9, X##10, X##11, \ + X##12, X##13, X##14, X##15, X##16, X##17, X##18, X##19, X##20, X##21, \ + X##22, X##23, X##24, X##25, X##26, X##27, X##28, X##29, X##30, X##31 \ + } + +#define PPC_REGS_LO_HI(LO, HI) \ + { \ + LO##0, LO##1, LO##2, LO##3, LO##4, LO##5, LO##6, LO##7, LO##8, LO##9, \ + LO##10, LO##11, LO##12, LO##13, LO##14, LO##15, LO##16, LO##17, \ + LO##18, LO##19, LO##20, LO##21, LO##22, LO##23, LO##24, LO##25, \ + LO##26, LO##27, LO##28, LO##29, LO##30, LO##31, HI##0, HI##1, HI##2, \ + HI##3, HI##4, HI##5, HI##6, HI##7, HI##8, HI##9, HI##10, HI##11, \ + HI##12, HI##13, HI##14, HI##15, HI##16, HI##17, HI##18, HI##19, \ + HI##20, HI##21, HI##22, HI##23, HI##24, HI##25, HI##26, HI##27, \ + HI##28, HI##29, HI##30, HI##31 \ + } + +#define PPC_REGS0_7(X) \ + { \ + X##0, X##1, X##2, X##3, X##4, X##5, X##6, X##7 \ + } + +#define PPC_REGS0_3(X) \ + { \ + X##0, X##1, X##2, X##3 \ + } + +using llvm::MCPhysReg; + +#define DEFINE_PPC_REGCLASSES \ + static const MCPhysReg RRegs[32] = PPC_REGS0_31(PPC::R); \ + static const MCPhysReg XRegs[32] = PPC_REGS0_31(PPC::X); \ + static const MCPhysReg FRegs[32] = PPC_REGS0_31(PPC::F); \ + static const MCPhysReg FpRegs[16] = PPC_REGS_EVEN0_30(PPC::Fpair); \ + static const MCPhysReg VSRpRegs[32] = PPC_REGS0_31(PPC::VSRp); \ + static const MCPhysReg SPERegs[32] = PPC_REGS0_31(PPC::S); \ + static const MCPhysReg VFRegs[32] = PPC_REGS0_31(PPC::VF); \ + static const MCPhysReg VRegs[32] = PPC_REGS0_31(PPC::V); \ + static const MCPhysReg RRegsNoR0[32] = PPC_REGS_NO0_31(PPC::ZERO, PPC::R); \ + static const MCPhysReg XRegsNoX0[32] = PPC_REGS_NO0_31(PPC::ZERO8, PPC::X); \ + static const MCPhysReg VSRegs[64] = PPC_REGS_LO_HI(PPC::VSL, PPC::V); \ + static const MCPhysReg VSFRegs[64] = PPC_REGS_LO_HI(PPC::F, PPC::VF); \ + static const MCPhysReg VSSRegs[64] = PPC_REGS_LO_HI(PPC::F, PPC::VF); \ + static const MCPhysReg CRBITRegs[32] = { \ + PPC::CR0LT, PPC::CR0GT, PPC::CR0EQ, PPC::CR0UN, PPC::CR1LT, PPC::CR1GT, \ + PPC::CR1EQ, PPC::CR1UN, PPC::CR2LT, PPC::CR2GT, PPC::CR2EQ, PPC::CR2UN, \ + PPC::CR3LT, PPC::CR3GT, PPC::CR3EQ, PPC::CR3UN, PPC::CR4LT, PPC::CR4GT, \ + PPC::CR4EQ, PPC::CR4UN, PPC::CR5LT, PPC::CR5GT, PPC::CR5EQ, PPC::CR5UN, \ + PPC::CR6LT, PPC::CR6GT, PPC::CR6EQ, PPC::CR6UN, PPC::CR7LT, PPC::CR7GT, \ + PPC::CR7EQ, PPC::CR7UN}; \ + static const MCPhysReg CRRegs[8] = PPC_REGS0_7(PPC::CR); \ + static const MCPhysReg ACCRegs[8] = PPC_REGS0_7(PPC::ACC); \ + static const MCPhysReg WACCRegs[8] = PPC_REGS0_7(PPC::WACC); \ + static const MCPhysReg WACC_HIRegs[8] = PPC_REGS0_7(PPC::WACC_HI); \ + static const MCPhysReg DMRROWpRegs[32] = PPC_REGS0_31(PPC::DMRROWp); \ + static const MCPhysReg DMRROWRegs[64] = PPC_REGS0_63(PPC::DMRROW); \ + static const MCPhysReg DMRRegs[8] = PPC_REGS0_7(PPC::DMR); \ + static const MCPhysReg DMRpRegs[4] = PPC_REGS0_3(PPC::DMRp); + +namespace llvm { +namespace PPC { +static inline bool isVFRegister(unsigned Reg) { + return Reg >= PPC::VF0 && Reg <= PPC::VF31; +} + +static inline bool isVRRegister(unsigned Reg) { + return Reg >= PPC::V0 && Reg <= PPC::V31; +} +} // namespace PPC +} // namespace llvm + +#endif // LLVM_LIB_TARGET_POWERPC_MCTARGETDESC_PPCMCTARGETDESC_H diff --git a/contrib/llvm-project/llvm/lib/Target/PowerPC/MCTargetDesc/PPCPredicates.cpp b/contrib/llvm-project/llvm/lib/Target/PowerPC/MCTargetDesc/PPCPredicates.cpp new file mode 100644 index 000000000000..80c37f82bf29 --- /dev/null +++ b/contrib/llvm-project/llvm/lib/Target/PowerPC/MCTargetDesc/PPCPredicates.cpp @@ -0,0 +1,84 @@ +//===-- PPCPredicates.cpp - PPC Branch Predicate Information --------------===// +// +// 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 implements the PowerPC branch predicates. +// +//===----------------------------------------------------------------------===// + +#include "PPCPredicates.h" +#include "llvm/Support/ErrorHandling.h" +using namespace llvm; + +PPC::Predicate PPC::InvertPredicate(PPC::Predicate Opcode) { + switch (Opcode) { + case PPC::PRED_EQ: return PPC::PRED_NE; + case PPC::PRED_NE: return PPC::PRED_EQ; + case PPC::PRED_LT: return PPC::PRED_GE; + case PPC::PRED_GE: return PPC::PRED_LT; + case PPC::PRED_GT: return PPC::PRED_LE; + case PPC::PRED_LE: return PPC::PRED_GT; + case PPC::PRED_NU: return PPC::PRED_UN; + case PPC::PRED_UN: return PPC::PRED_NU; + case PPC::PRED_EQ_MINUS: return PPC::PRED_NE_PLUS; + case PPC::PRED_NE_MINUS: return PPC::PRED_EQ_PLUS; + case PPC::PRED_LT_MINUS: return PPC::PRED_GE_PLUS; + case PPC::PRED_GE_MINUS: return PPC::PRED_LT_PLUS; + case PPC::PRED_GT_MINUS: return PPC::PRED_LE_PLUS; + case PPC::PRED_LE_MINUS: return PPC::PRED_GT_PLUS; + case PPC::PRED_NU_MINUS: return PPC::PRED_UN_PLUS; + case PPC::PRED_UN_MINUS: return PPC::PRED_NU_PLUS; + case PPC::PRED_EQ_PLUS: return PPC::PRED_NE_MINUS; + case PPC::PRED_NE_PLUS: return PPC::PRED_EQ_MINUS; + case PPC::PRED_LT_PLUS: return PPC::PRED_GE_MINUS; + case PPC::PRED_GE_PLUS: return PPC::PRED_LT_MINUS; + case PPC::PRED_GT_PLUS: return PPC::PRED_LE_MINUS; + case PPC::PRED_LE_PLUS: return PPC::PRED_GT_MINUS; + case PPC::PRED_NU_PLUS: return PPC::PRED_UN_MINUS; + case PPC::PRED_UN_PLUS: return PPC::PRED_NU_MINUS; + + // Simple predicates for single condition-register bits. + case PPC::PRED_BIT_SET: return PPC::PRED_BIT_UNSET; + case PPC::PRED_BIT_UNSET: return PPC::PRED_BIT_SET; + } + llvm_unreachable("Unknown PPC branch opcode!"); +} + +PPC::Predicate PPC::getSwappedPredicate(PPC::Predicate Opcode) { + switch (Opcode) { + case PPC::PRED_EQ: return PPC::PRED_EQ; + case PPC::PRED_NE: return PPC::PRED_NE; + case PPC::PRED_LT: return PPC::PRED_GT; + case PPC::PRED_GE: return PPC::PRED_LE; + case PPC::PRED_GT: return PPC::PRED_LT; + case PPC::PRED_LE: return PPC::PRED_GE; + case PPC::PRED_NU: return PPC::PRED_NU; + case PPC::PRED_UN: return PPC::PRED_UN; + case PPC::PRED_EQ_MINUS: return PPC::PRED_EQ_MINUS; + case PPC::PRED_NE_MINUS: return PPC::PRED_NE_MINUS; + case PPC::PRED_LT_MINUS: return PPC::PRED_GT_MINUS; + case PPC::PRED_GE_MINUS: return PPC::PRED_LE_MINUS; + case PPC::PRED_GT_MINUS: return PPC::PRED_LT_MINUS; + case PPC::PRED_LE_MINUS: return PPC::PRED_GE_MINUS; + case PPC::PRED_NU_MINUS: return PPC::PRED_NU_MINUS; + case PPC::PRED_UN_MINUS: return PPC::PRED_UN_MINUS; + case PPC::PRED_EQ_PLUS: return PPC::PRED_EQ_PLUS; + case PPC::PRED_NE_PLUS: return PPC::PRED_NE_PLUS; + case PPC::PRED_LT_PLUS: return PPC::PRED_GT_PLUS; + case PPC::PRED_GE_PLUS: return PPC::PRED_LE_PLUS; + case PPC::PRED_GT_PLUS: return PPC::PRED_LT_PLUS; + case PPC::PRED_LE_PLUS: return PPC::PRED_GE_PLUS; + case PPC::PRED_NU_PLUS: return PPC::PRED_NU_PLUS; + case PPC::PRED_UN_PLUS: return PPC::PRED_UN_PLUS; + + case PPC::PRED_BIT_SET: + case PPC::PRED_BIT_UNSET: + llvm_unreachable("Invalid use of bit predicate code"); + } + llvm_unreachable("Unknown PPC branch opcode!"); +} + diff --git a/contrib/llvm-project/llvm/lib/Target/PowerPC/MCTargetDesc/PPCPredicates.h b/contrib/llvm-project/llvm/lib/Target/PowerPC/MCTargetDesc/PPCPredicates.h new file mode 100644 index 000000000000..d686a8ea2a22 --- /dev/null +++ b/contrib/llvm-project/llvm/lib/Target/PowerPC/MCTargetDesc/PPCPredicates.h @@ -0,0 +1,94 @@ +//===-- PPCPredicates.h - PPC Branch Predicate Information ------*- C++ -*-===// +// +// 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 describes the PowerPC branch predicates. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_POWERPC_MCTARGETDESC_PPCPREDICATES_H +#define LLVM_LIB_TARGET_POWERPC_MCTARGETDESC_PPCPREDICATES_H + +// GCC #defines PPC on Linux but we use it as our namespace name +#undef PPC + +// Generated files will use "namespace PPC". To avoid symbol clash, +// undefine PPC here. PPC may be predefined on some hosts. +#undef PPC + +namespace llvm { +namespace PPC { + /// Predicate - These are "(BI << 5) | BO" for various predicates. + enum Predicate { + PRED_LT = (0 << 5) | 12, + PRED_LE = (1 << 5) | 4, + PRED_EQ = (2 << 5) | 12, + PRED_GE = (0 << 5) | 4, + PRED_GT = (1 << 5) | 12, + PRED_NE = (2 << 5) | 4, + PRED_UN = (3 << 5) | 12, + PRED_NU = (3 << 5) | 4, + PRED_LT_MINUS = (0 << 5) | 14, + PRED_LE_MINUS = (1 << 5) | 6, + PRED_EQ_MINUS = (2 << 5) | 14, + PRED_GE_MINUS = (0 << 5) | 6, + PRED_GT_MINUS = (1 << 5) | 14, + PRED_NE_MINUS = (2 << 5) | 6, + PRED_UN_MINUS = (3 << 5) | 14, + PRED_NU_MINUS = (3 << 5) | 6, + PRED_LT_PLUS = (0 << 5) | 15, + PRED_LE_PLUS = (1 << 5) | 7, + PRED_EQ_PLUS = (2 << 5) | 15, + PRED_GE_PLUS = (0 << 5) | 7, + PRED_GT_PLUS = (1 << 5) | 15, + PRED_NE_PLUS = (2 << 5) | 7, + PRED_UN_PLUS = (3 << 5) | 15, + PRED_NU_PLUS = (3 << 5) | 7, + + // SPE scalar compare instructions always set the GT bit. + PRED_SPE = PRED_GT, + + // When dealing with individual condition-register bits, we have simple set + // and unset predicates. + PRED_BIT_SET = 1024, + PRED_BIT_UNSET = 1025 + }; + + // Bit for branch taken (plus) or not-taken (minus) hint + enum BranchHintBit { + BR_NO_HINT = 0x0, + BR_NONTAKEN_HINT = 0x2, + BR_TAKEN_HINT = 0x3, + BR_HINT_MASK = 0X3 + }; + + /// Invert the specified predicate. != -> ==, < -> >=. + Predicate InvertPredicate(Predicate Opcode); + + /// Assume the condition register is set by MI(a,b), return the predicate if + /// we modify the instructions such that condition register is set by MI(b,a). + Predicate getSwappedPredicate(Predicate Opcode); + + /// Return the condition without hint bits. + inline unsigned getPredicateCondition(Predicate Opcode) { + return (unsigned)(Opcode & ~BR_HINT_MASK); + } + + /// Return the hint bits of the predicate. + inline unsigned getPredicateHint(Predicate Opcode) { + return (unsigned)(Opcode & BR_HINT_MASK); + } + + /// Return predicate consisting of specified condition and hint bits. + inline Predicate getPredicate(unsigned Condition, unsigned Hint) { + return (Predicate)((Condition & ~BR_HINT_MASK) | + (Hint & BR_HINT_MASK)); + } +} +} + +#endif diff --git a/contrib/llvm-project/llvm/lib/Target/PowerPC/MCTargetDesc/PPCXCOFFObjectWriter.cpp b/contrib/llvm-project/llvm/lib/Target/PowerPC/MCTargetDesc/PPCXCOFFObjectWriter.cpp new file mode 100644 index 000000000000..065daf42fe6e --- /dev/null +++ b/contrib/llvm-project/llvm/lib/Target/PowerPC/MCTargetDesc/PPCXCOFFObjectWriter.cpp @@ -0,0 +1,123 @@ +//===-- PPCXCOFFObjectWriter.cpp - PowerPC XCOFF Writer -------------------===// +// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "MCTargetDesc/PPCFixupKinds.h" +#include "MCTargetDesc/PPCMCTargetDesc.h" +#include "llvm/BinaryFormat/XCOFF.h" +#include "llvm/MC/MCFixup.h" +#include "llvm/MC/MCFixupKindInfo.h" +#include "llvm/MC/MCValue.h" +#include "llvm/MC/MCXCOFFObjectWriter.h" + +using namespace llvm; + +namespace { +class PPCXCOFFObjectWriter : public MCXCOFFObjectTargetWriter { + static constexpr uint8_t SignBitMask = 0x80; + +public: + PPCXCOFFObjectWriter(bool Is64Bit); + + std::pair<uint8_t, uint8_t> + getRelocTypeAndSignSize(const MCValue &Target, const MCFixup &Fixup, + bool IsPCRel) const override; +}; +} // end anonymous namespace + +PPCXCOFFObjectWriter::PPCXCOFFObjectWriter(bool Is64Bit) + : MCXCOFFObjectTargetWriter(Is64Bit) {} + +std::unique_ptr<MCObjectTargetWriter> +llvm::createPPCXCOFFObjectWriter(bool Is64Bit) { + return std::make_unique<PPCXCOFFObjectWriter>(Is64Bit); +} + +std::pair<uint8_t, uint8_t> PPCXCOFFObjectWriter::getRelocTypeAndSignSize( + const MCValue &Target, const MCFixup &Fixup, bool IsPCRel) const { + const MCSymbolRefExpr::VariantKind Modifier = + Target.isAbsolute() ? MCSymbolRefExpr::VK_None + : Target.getSymA()->getKind(); + // People from AIX OS team says AIX link editor does not care about + // the sign bit in the relocation entry "most" of the time. + // The system assembler seems to set the sign bit on relocation entry + // based on similar property of IsPCRel. So we will do the same here. + // TODO: More investigation on how assembler decides to set the sign + // bit, and we might want to match that. + const uint8_t EncodedSignednessIndicator = IsPCRel ? SignBitMask : 0u; + + // The magic number we use in SignAndSize has a strong relationship with + // the corresponding MCFixupKind. In most cases, it's the MCFixupKind + // number - 1, because SignAndSize encodes the bit length being + // relocated minus 1. + switch ((unsigned)Fixup.getKind()) { + default: + report_fatal_error("Unimplemented fixup kind."); + case PPC::fixup_ppc_half16: { + const uint8_t SignAndSizeForHalf16 = EncodedSignednessIndicator | 15; + switch (Modifier) { + default: + report_fatal_error("Unsupported modifier for half16 fixup."); + case MCSymbolRefExpr::VK_None: + return {XCOFF::RelocationType::R_TOC, SignAndSizeForHalf16}; + case MCSymbolRefExpr::VK_PPC_U: + return {XCOFF::RelocationType::R_TOCU, SignAndSizeForHalf16}; + case MCSymbolRefExpr::VK_PPC_L: + return {XCOFF::RelocationType::R_TOCL, SignAndSizeForHalf16}; + case MCSymbolRefExpr::VK_PPC_AIX_TLSLE: + return {XCOFF::RelocationType::R_TLS_LE, SignAndSizeForHalf16}; + } + } break; + case PPC::fixup_ppc_half16ds: + case PPC::fixup_ppc_half16dq: { + if (IsPCRel) + report_fatal_error("Invalid PC-relative relocation."); + switch (Modifier) { + default: + llvm_unreachable("Unsupported Modifier"); + case MCSymbolRefExpr::VK_None: + return {XCOFF::RelocationType::R_TOC, 15}; + case MCSymbolRefExpr::VK_PPC_L: + return {XCOFF::RelocationType::R_TOCL, 15}; + case MCSymbolRefExpr::VK_PPC_AIX_TLSLE: + return {XCOFF::RelocationType::R_TLS_LE, 15}; + } + } break; + case PPC::fixup_ppc_br24: + // Branches are 4 byte aligned, so the 24 bits we encode in + // the instruction actually represents a 26 bit offset. + return {XCOFF::RelocationType::R_RBR, EncodedSignednessIndicator | 25}; + case PPC::fixup_ppc_br24abs: + return {XCOFF::RelocationType::R_RBA, EncodedSignednessIndicator | 25}; + case PPC::fixup_ppc_nofixup: { + if (Modifier == MCSymbolRefExpr::VK_None) + return {XCOFF::RelocationType::R_REF, 0}; + else + llvm_unreachable("Unsupported Modifier"); + } break; + case FK_Data_4: + case FK_Data_8: + const uint8_t SignAndSizeForFKData = + EncodedSignednessIndicator | + ((unsigned)Fixup.getKind() == FK_Data_4 ? 31 : 63); + switch (Modifier) { + default: + report_fatal_error("Unsupported modifier"); + case MCSymbolRefExpr::VK_PPC_AIX_TLSGD: + return {XCOFF::RelocationType::R_TLS, SignAndSizeForFKData}; + case MCSymbolRefExpr::VK_PPC_AIX_TLSGDM: + return {XCOFF::RelocationType::R_TLSM, SignAndSizeForFKData}; + case MCSymbolRefExpr::VK_PPC_AIX_TLSIE: + return {XCOFF::RelocationType::R_TLS_IE, SignAndSizeForFKData}; + case MCSymbolRefExpr::VK_PPC_AIX_TLSLE: + return {XCOFF::RelocationType::R_TLS_LE, SignAndSizeForFKData}; + case MCSymbolRefExpr::VK_None: + return {XCOFF::RelocationType::R_POS, SignAndSizeForFKData}; + } + } +} diff --git a/contrib/llvm-project/llvm/lib/Target/PowerPC/MCTargetDesc/PPCXCOFFStreamer.cpp b/contrib/llvm-project/llvm/lib/Target/PowerPC/MCTargetDesc/PPCXCOFFStreamer.cpp new file mode 100644 index 000000000000..8e685d0df758 --- /dev/null +++ b/contrib/llvm-project/llvm/lib/Target/PowerPC/MCTargetDesc/PPCXCOFFStreamer.cpp @@ -0,0 +1,78 @@ +//===-------- PPCXCOFFStreamer.cpp - XCOFF Object Output ------------------===// +// +// 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 is a custom MCXCOFFStreamer for PowerPC. +// +// The purpose of the custom XCOFF streamer is to allow us to intercept +// instructions as they are being emitted and align all 8 byte instructions +// to a 64 byte boundary if required (by adding a 4 byte nop). This is important +// because 8 byte instructions are not allowed to cross 64 byte boundaries +// and by aligning anything that is within 4 bytes of the boundary we can +// guarantee that the 8 byte instructions do not cross that boundary. +// +//===----------------------------------------------------------------------===// + +#include "PPCXCOFFStreamer.h" +#include "PPCMCCodeEmitter.h" +#include "llvm/BinaryFormat/XCOFF.h" +#include "llvm/MC/MCAsmBackend.h" +#include "llvm/MC/MCAssembler.h" +#include "llvm/MC/MCCodeEmitter.h" +#include "llvm/MC/MCDirectives.h" +#include "llvm/MC/MCObjectWriter.h" +#include "llvm/MC/MCSectionXCOFF.h" +#include "llvm/MC/MCSymbolXCOFF.h" +#include "llvm/MC/TargetRegistry.h" + +using namespace llvm; + +PPCXCOFFStreamer::PPCXCOFFStreamer(MCContext &Context, + std::unique_ptr<MCAsmBackend> MAB, + std::unique_ptr<MCObjectWriter> OW, + std::unique_ptr<MCCodeEmitter> Emitter) + : MCXCOFFStreamer(Context, std::move(MAB), std::move(OW), + std::move(Emitter)) {} + +void PPCXCOFFStreamer::emitPrefixedInstruction(const MCInst &Inst, + const MCSubtargetInfo &STI) { + // Prefixed instructions must not cross a 64-byte boundary (i.e. prefix is + // before the boundary and the remaining 4-bytes are after the boundary). In + // order to achieve this, a nop is added prior to any such boundary-crossing + // prefixed instruction. Align to 64 bytes if possible but add a maximum of 4 + // bytes when trying to do that. If alignment requires adding more than 4 + // bytes then the instruction won't be aligned. + emitCodeAlignment(Align(64), &STI, 4); + + // Emit the instruction. + // Since the previous emit created a new fragment then adding this instruction + // also forces the addition of a new fragment. Inst is now the first + // instruction in that new fragment. + MCXCOFFStreamer::emitInstruction(Inst, STI); +} + +void PPCXCOFFStreamer::emitInstruction(const MCInst &Inst, + const MCSubtargetInfo &STI) { + PPCMCCodeEmitter *Emitter = + static_cast<PPCMCCodeEmitter *>(getAssembler().getEmitterPtr()); + + // Special handling is only for prefixed instructions. + if (!Emitter->isPrefixedInstruction(Inst)) { + MCXCOFFStreamer::emitInstruction(Inst, STI); + return; + } + emitPrefixedInstruction(Inst, STI); +} + +MCXCOFFStreamer * +llvm::createPPCXCOFFStreamer(MCContext &Context, + std::unique_ptr<MCAsmBackend> MAB, + std::unique_ptr<MCObjectWriter> OW, + std::unique_ptr<MCCodeEmitter> Emitter) { + return new PPCXCOFFStreamer(Context, std::move(MAB), std::move(OW), + std::move(Emitter)); +} diff --git a/contrib/llvm-project/llvm/lib/Target/PowerPC/MCTargetDesc/PPCXCOFFStreamer.h b/contrib/llvm-project/llvm/lib/Target/PowerPC/MCTargetDesc/PPCXCOFFStreamer.h new file mode 100644 index 000000000000..5fa35127b70b --- /dev/null +++ b/contrib/llvm-project/llvm/lib/Target/PowerPC/MCTargetDesc/PPCXCOFFStreamer.h @@ -0,0 +1,38 @@ +//===- PPCXCOFFStreamer.h - XCOFF Object Output -----------------*- C++ -*-===// +// +// 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 is a custom MCXCOFFStreamer for PowerPC. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_PPC_MCXCOFFSTREAMER_PPCXCOFFSTREAMER_H +#define LLVM_LIB_TARGET_PPC_MCXCOFFSTREAMER_PPCXCOFFSTREAMER_H + +#include "llvm/MC/MCXCOFFStreamer.h" + +namespace llvm { + +class PPCXCOFFStreamer : public MCXCOFFStreamer { +public: + PPCXCOFFStreamer(MCContext &Context, std::unique_ptr<MCAsmBackend> MAB, + std::unique_ptr<MCObjectWriter> OW, + std::unique_ptr<MCCodeEmitter> Emitter); + + void emitInstruction(const MCInst &Inst, const MCSubtargetInfo &STI) override; + +private: + void emitPrefixedInstruction(const MCInst &Inst, const MCSubtargetInfo &STI); +}; + +MCXCOFFStreamer *createPPCXCOFFStreamer(MCContext &Context, + std::unique_ptr<MCAsmBackend> MAB, + std::unique_ptr<MCObjectWriter> OW, + std::unique_ptr<MCCodeEmitter> Emitter); +} // end namespace llvm + +#endif // LLVM_LIB_TARGET_PPC_MCXCOFFSTREAMER_PPCXCOFFSTREAMER_H |