xref: /freebsd/contrib/llvm-project/llvm/lib/Target/PowerPC/MCTargetDesc/PPCAsmBackend.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
10b57cec5SDimitry Andric //===-- PPCAsmBackend.cpp - PPC Assembler Backend -------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric 
90b57cec5SDimitry Andric #include "MCTargetDesc/PPCFixupKinds.h"
100b57cec5SDimitry Andric #include "MCTargetDesc/PPCMCTargetDesc.h"
110b57cec5SDimitry Andric #include "llvm/BinaryFormat/ELF.h"
120b57cec5SDimitry Andric #include "llvm/BinaryFormat/MachO.h"
130b57cec5SDimitry Andric #include "llvm/MC/MCAsmBackend.h"
140b57cec5SDimitry Andric #include "llvm/MC/MCAssembler.h"
150b57cec5SDimitry Andric #include "llvm/MC/MCELFObjectWriter.h"
160b57cec5SDimitry Andric #include "llvm/MC/MCFixupKindInfo.h"
170b57cec5SDimitry Andric #include "llvm/MC/MCMachObjectWriter.h"
180b57cec5SDimitry Andric #include "llvm/MC/MCObjectWriter.h"
190b57cec5SDimitry Andric #include "llvm/MC/MCSectionMachO.h"
200b57cec5SDimitry Andric #include "llvm/MC/MCSubtargetInfo.h"
210b57cec5SDimitry Andric #include "llvm/MC/MCSymbolELF.h"
2206c3fb27SDimitry Andric #include "llvm/MC/MCSymbolXCOFF.h"
230b57cec5SDimitry Andric #include "llvm/MC/MCValue.h"
24349cc55cSDimitry Andric #include "llvm/MC/TargetRegistry.h"
250b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h"
260b57cec5SDimitry Andric using namespace llvm;
270b57cec5SDimitry Andric 
adjustFixupValue(unsigned Kind,uint64_t Value)280b57cec5SDimitry Andric static uint64_t adjustFixupValue(unsigned Kind, uint64_t Value) {
290b57cec5SDimitry Andric   switch (Kind) {
300b57cec5SDimitry Andric   default:
310b57cec5SDimitry Andric     llvm_unreachable("Unknown fixup kind!");
320b57cec5SDimitry Andric   case FK_Data_1:
330b57cec5SDimitry Andric   case FK_Data_2:
340b57cec5SDimitry Andric   case FK_Data_4:
350b57cec5SDimitry Andric   case FK_Data_8:
360b57cec5SDimitry Andric   case PPC::fixup_ppc_nofixup:
370b57cec5SDimitry Andric     return Value;
380b57cec5SDimitry Andric   case PPC::fixup_ppc_brcond14:
390b57cec5SDimitry Andric   case PPC::fixup_ppc_brcond14abs:
400b57cec5SDimitry Andric     return Value & 0xfffc;
410b57cec5SDimitry Andric   case PPC::fixup_ppc_br24:
420b57cec5SDimitry Andric   case PPC::fixup_ppc_br24abs:
435ffd83dbSDimitry Andric   case PPC::fixup_ppc_br24_notoc:
440b57cec5SDimitry Andric     return Value & 0x3fffffc;
450b57cec5SDimitry Andric   case PPC::fixup_ppc_half16:
460b57cec5SDimitry Andric     return Value & 0xffff;
470b57cec5SDimitry Andric   case PPC::fixup_ppc_half16ds:
483a9a9c0cSDimitry Andric   case PPC::fixup_ppc_half16dq:
490b57cec5SDimitry Andric     return Value & 0xfffc;
505ffd83dbSDimitry Andric   case PPC::fixup_ppc_pcrel34:
51e8d8bef9SDimitry Andric   case PPC::fixup_ppc_imm34:
525ffd83dbSDimitry Andric     return Value & 0x3ffffffff;
530b57cec5SDimitry Andric   }
540b57cec5SDimitry Andric }
550b57cec5SDimitry Andric 
getFixupKindNumBytes(unsigned Kind)560b57cec5SDimitry Andric static unsigned getFixupKindNumBytes(unsigned Kind) {
570b57cec5SDimitry Andric   switch (Kind) {
580b57cec5SDimitry Andric   default:
590b57cec5SDimitry Andric     llvm_unreachable("Unknown fixup kind!");
600b57cec5SDimitry Andric   case FK_Data_1:
610b57cec5SDimitry Andric     return 1;
620b57cec5SDimitry Andric   case FK_Data_2:
630b57cec5SDimitry Andric   case PPC::fixup_ppc_half16:
640b57cec5SDimitry Andric   case PPC::fixup_ppc_half16ds:
653a9a9c0cSDimitry Andric   case PPC::fixup_ppc_half16dq:
660b57cec5SDimitry Andric     return 2;
670b57cec5SDimitry Andric   case FK_Data_4:
680b57cec5SDimitry Andric   case PPC::fixup_ppc_brcond14:
690b57cec5SDimitry Andric   case PPC::fixup_ppc_brcond14abs:
700b57cec5SDimitry Andric   case PPC::fixup_ppc_br24:
710b57cec5SDimitry Andric   case PPC::fixup_ppc_br24abs:
725ffd83dbSDimitry Andric   case PPC::fixup_ppc_br24_notoc:
730b57cec5SDimitry Andric     return 4;
745ffd83dbSDimitry Andric   case PPC::fixup_ppc_pcrel34:
75e8d8bef9SDimitry Andric   case PPC::fixup_ppc_imm34:
760b57cec5SDimitry Andric   case FK_Data_8:
770b57cec5SDimitry Andric     return 8;
780b57cec5SDimitry Andric   case PPC::fixup_ppc_nofixup:
790b57cec5SDimitry Andric     return 0;
800b57cec5SDimitry Andric   }
810b57cec5SDimitry Andric }
820b57cec5SDimitry Andric 
830b57cec5SDimitry Andric namespace {
840b57cec5SDimitry Andric 
850b57cec5SDimitry Andric class PPCAsmBackend : public MCAsmBackend {
860b57cec5SDimitry Andric protected:
870b57cec5SDimitry Andric   Triple TT;
880b57cec5SDimitry Andric public:
PPCAsmBackend(const Target & T,const Triple & TT)890b57cec5SDimitry Andric   PPCAsmBackend(const Target &T, const Triple &TT)
90*5f757f3fSDimitry Andric       : MCAsmBackend(TT.isLittleEndian() ? llvm::endianness::little
91*5f757f3fSDimitry Andric                                          : llvm::endianness::big),
920b57cec5SDimitry Andric         TT(TT) {}
930b57cec5SDimitry Andric 
getNumFixupKinds() const940b57cec5SDimitry Andric   unsigned getNumFixupKinds() const override {
950b57cec5SDimitry Andric     return PPC::NumTargetFixupKinds;
960b57cec5SDimitry Andric   }
970b57cec5SDimitry Andric 
getFixupKindInfo(MCFixupKind Kind) const980b57cec5SDimitry Andric   const MCFixupKindInfo &getFixupKindInfo(MCFixupKind Kind) const override {
990b57cec5SDimitry Andric     const static MCFixupKindInfo InfosBE[PPC::NumTargetFixupKinds] = {
1000b57cec5SDimitry Andric       // name                    offset  bits  flags
1010b57cec5SDimitry Andric       { "fixup_ppc_br24",        6,      24,   MCFixupKindInfo::FKF_IsPCRel },
1025ffd83dbSDimitry Andric       { "fixup_ppc_br24_notoc",  6,      24,   MCFixupKindInfo::FKF_IsPCRel },
1030b57cec5SDimitry Andric       { "fixup_ppc_brcond14",    16,     14,   MCFixupKindInfo::FKF_IsPCRel },
1040b57cec5SDimitry Andric       { "fixup_ppc_br24abs",     6,      24,   0 },
1050b57cec5SDimitry Andric       { "fixup_ppc_brcond14abs", 16,     14,   0 },
1060b57cec5SDimitry Andric       { "fixup_ppc_half16",       0,     16,   0 },
1070b57cec5SDimitry Andric       { "fixup_ppc_half16ds",     0,     14,   0 },
1085ffd83dbSDimitry Andric       { "fixup_ppc_pcrel34",     0,      34,   MCFixupKindInfo::FKF_IsPCRel },
109e8d8bef9SDimitry Andric       { "fixup_ppc_imm34",       0,      34,   0 },
1100b57cec5SDimitry Andric       { "fixup_ppc_nofixup",      0,      0,   0 }
1110b57cec5SDimitry Andric     };
1120b57cec5SDimitry Andric     const static MCFixupKindInfo InfosLE[PPC::NumTargetFixupKinds] = {
1130b57cec5SDimitry Andric       // name                    offset  bits  flags
1140b57cec5SDimitry Andric       { "fixup_ppc_br24",        2,      24,   MCFixupKindInfo::FKF_IsPCRel },
1155ffd83dbSDimitry Andric       { "fixup_ppc_br24_notoc",  2,      24,   MCFixupKindInfo::FKF_IsPCRel },
1160b57cec5SDimitry Andric       { "fixup_ppc_brcond14",    2,      14,   MCFixupKindInfo::FKF_IsPCRel },
1170b57cec5SDimitry Andric       { "fixup_ppc_br24abs",     2,      24,   0 },
1180b57cec5SDimitry Andric       { "fixup_ppc_brcond14abs", 2,      14,   0 },
1190b57cec5SDimitry Andric       { "fixup_ppc_half16",      0,      16,   0 },
1200b57cec5SDimitry Andric       { "fixup_ppc_half16ds",    2,      14,   0 },
1215ffd83dbSDimitry Andric       { "fixup_ppc_pcrel34",     0,      34,   MCFixupKindInfo::FKF_IsPCRel },
122e8d8bef9SDimitry Andric       { "fixup_ppc_imm34",       0,      34,   0 },
1230b57cec5SDimitry Andric       { "fixup_ppc_nofixup",     0,       0,   0 }
1240b57cec5SDimitry Andric     };
1250b57cec5SDimitry Andric 
1265ffd83dbSDimitry Andric     // Fixup kinds from .reloc directive are like R_PPC_NONE/R_PPC64_NONE. They
1275ffd83dbSDimitry Andric     // do not require any extra processing.
1285ffd83dbSDimitry Andric     if (Kind >= FirstLiteralRelocationKind)
1295ffd83dbSDimitry Andric       return MCAsmBackend::getFixupKindInfo(FK_NONE);
1305ffd83dbSDimitry Andric 
1310b57cec5SDimitry Andric     if (Kind < FirstTargetFixupKind)
1320b57cec5SDimitry Andric       return MCAsmBackend::getFixupKindInfo(Kind);
1330b57cec5SDimitry Andric 
1340b57cec5SDimitry Andric     assert(unsigned(Kind - FirstTargetFixupKind) < getNumFixupKinds() &&
1350b57cec5SDimitry Andric            "Invalid kind!");
136*5f757f3fSDimitry Andric     return (Endian == llvm::endianness::little
1370b57cec5SDimitry Andric                 ? InfosLE
1380b57cec5SDimitry Andric                 : InfosBE)[Kind - FirstTargetFixupKind];
1390b57cec5SDimitry Andric   }
1400b57cec5SDimitry Andric 
applyFixup(const MCAssembler & Asm,const MCFixup & Fixup,const MCValue & Target,MutableArrayRef<char> Data,uint64_t Value,bool IsResolved,const MCSubtargetInfo * STI) const1410b57cec5SDimitry Andric   void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
1420b57cec5SDimitry Andric                   const MCValue &Target, MutableArrayRef<char> Data,
1430b57cec5SDimitry Andric                   uint64_t Value, bool IsResolved,
1440b57cec5SDimitry Andric                   const MCSubtargetInfo *STI) const override {
1455ffd83dbSDimitry Andric     MCFixupKind Kind = Fixup.getKind();
1465ffd83dbSDimitry Andric     if (Kind >= FirstLiteralRelocationKind)
1475ffd83dbSDimitry Andric       return;
1485ffd83dbSDimitry Andric     Value = adjustFixupValue(Kind, Value);
1490b57cec5SDimitry Andric     if (!Value) return;           // Doesn't change encoding.
1500b57cec5SDimitry Andric 
1510b57cec5SDimitry Andric     unsigned Offset = Fixup.getOffset();
1525ffd83dbSDimitry Andric     unsigned NumBytes = getFixupKindNumBytes(Kind);
1530b57cec5SDimitry Andric 
1540b57cec5SDimitry Andric     // For each byte of the fragment that the fixup touches, mask in the bits
1550b57cec5SDimitry Andric     // from the fixup value. The Value has been "split up" into the appropriate
1560b57cec5SDimitry Andric     // bitfields above.
1570b57cec5SDimitry Andric     for (unsigned i = 0; i != NumBytes; ++i) {
158*5f757f3fSDimitry Andric       unsigned Idx =
159*5f757f3fSDimitry Andric           Endian == llvm::endianness::little ? i : (NumBytes - 1 - i);
1600b57cec5SDimitry Andric       Data[Offset + i] |= uint8_t((Value >> (Idx * 8)) & 0xff);
1610b57cec5SDimitry Andric     }
1620b57cec5SDimitry Andric   }
1630b57cec5SDimitry Andric 
shouldForceRelocation(const MCAssembler & Asm,const MCFixup & Fixup,const MCValue & Target,const MCSubtargetInfo * STI)1640b57cec5SDimitry Andric   bool shouldForceRelocation(const MCAssembler &Asm, const MCFixup &Fixup,
165*5f757f3fSDimitry Andric                              const MCValue &Target,
166*5f757f3fSDimitry Andric                              const MCSubtargetInfo *STI) override {
1675ffd83dbSDimitry Andric     MCFixupKind Kind = Fixup.getKind();
1685ffd83dbSDimitry Andric     switch ((unsigned)Kind) {
1690b57cec5SDimitry Andric     default:
1705ffd83dbSDimitry Andric       return Kind >= FirstLiteralRelocationKind;
1710b57cec5SDimitry Andric     case PPC::fixup_ppc_br24:
1720b57cec5SDimitry Andric     case PPC::fixup_ppc_br24abs:
1735ffd83dbSDimitry Andric     case PPC::fixup_ppc_br24_notoc:
1740b57cec5SDimitry Andric       // If the target symbol has a local entry point we must not attempt
1750b57cec5SDimitry Andric       // to resolve the fixup directly.  Emit a relocation and leave
1760b57cec5SDimitry Andric       // resolution of the final target address to the linker.
1770b57cec5SDimitry Andric       if (const MCSymbolRefExpr *A = Target.getSymA()) {
1780b57cec5SDimitry Andric         if (const auto *S = dyn_cast<MCSymbolELF>(&A->getSymbol())) {
1790b57cec5SDimitry Andric           // The "other" values are stored in the last 6 bits of the second
1800b57cec5SDimitry Andric           // byte. The traditional defines for STO values assume the full byte
1810b57cec5SDimitry Andric           // and thus the shift to pack it.
1820b57cec5SDimitry Andric           unsigned Other = S->getOther() << 2;
1830b57cec5SDimitry Andric           if ((Other & ELF::STO_PPC64_LOCAL_MASK) != 0)
1840b57cec5SDimitry Andric             return true;
18506c3fb27SDimitry Andric         } else if (const auto *S = dyn_cast<MCSymbolXCOFF>(&A->getSymbol())) {
18606c3fb27SDimitry Andric           return !Target.isAbsolute() && S->isExternal() &&
18706c3fb27SDimitry Andric                  S->getStorageClass() == XCOFF::C_WEAKEXT;
1880b57cec5SDimitry Andric        }
1890b57cec5SDimitry Andric       }
1900b57cec5SDimitry Andric       return false;
1910b57cec5SDimitry Andric     }
1920b57cec5SDimitry Andric   }
1930b57cec5SDimitry Andric 
relaxInstruction(MCInst & Inst,const MCSubtargetInfo & STI) const1945ffd83dbSDimitry Andric   void relaxInstruction(MCInst &Inst,
1955ffd83dbSDimitry Andric                         const MCSubtargetInfo &STI) const override {
1960b57cec5SDimitry Andric     // FIXME.
1970b57cec5SDimitry Andric     llvm_unreachable("relaxInstruction() unimplemented");
1980b57cec5SDimitry Andric   }
1990b57cec5SDimitry Andric 
writeNopData(raw_ostream & OS,uint64_t Count,const MCSubtargetInfo * STI) const200349cc55cSDimitry Andric   bool writeNopData(raw_ostream &OS, uint64_t Count,
201349cc55cSDimitry Andric                     const MCSubtargetInfo *STI) const override {
2020b57cec5SDimitry Andric     uint64_t NumNops = Count / 4;
2030b57cec5SDimitry Andric     for (uint64_t i = 0; i != NumNops; ++i)
2040b57cec5SDimitry Andric       support::endian::write<uint32_t>(OS, 0x60000000, Endian);
2050b57cec5SDimitry Andric 
2060b57cec5SDimitry Andric     OS.write_zeros(Count % 4);
2070b57cec5SDimitry Andric 
2080b57cec5SDimitry Andric     return true;
2090b57cec5SDimitry Andric   }
2100b57cec5SDimitry Andric };
2110b57cec5SDimitry Andric } // end anonymous namespace
2120b57cec5SDimitry Andric 
2130b57cec5SDimitry Andric 
2140b57cec5SDimitry Andric // FIXME: This should be in a separate file.
2150b57cec5SDimitry Andric namespace {
2160b57cec5SDimitry Andric 
2170b57cec5SDimitry Andric class ELFPPCAsmBackend : public PPCAsmBackend {
2180b57cec5SDimitry Andric public:
ELFPPCAsmBackend(const Target & T,const Triple & TT)2190b57cec5SDimitry Andric   ELFPPCAsmBackend(const Target &T, const Triple &TT) : PPCAsmBackend(T, TT) {}
2200b57cec5SDimitry Andric 
2210b57cec5SDimitry Andric   std::unique_ptr<MCObjectTargetWriter>
createObjectTargetWriter() const2220b57cec5SDimitry Andric   createObjectTargetWriter() const override {
2230b57cec5SDimitry Andric     uint8_t OSABI = MCELFObjectTargetWriter::getOSABI(TT.getOS());
2240b57cec5SDimitry Andric     bool Is64 = TT.isPPC64();
2250b57cec5SDimitry Andric     return createPPCELFObjectWriter(Is64, OSABI);
2260b57cec5SDimitry Andric   }
2270b57cec5SDimitry Andric 
228bdd1243dSDimitry Andric   std::optional<MCFixupKind> getFixupKind(StringRef Name) const override;
2290b57cec5SDimitry Andric };
2300b57cec5SDimitry Andric 
2310b57cec5SDimitry Andric class XCOFFPPCAsmBackend : public PPCAsmBackend {
2320b57cec5SDimitry Andric public:
XCOFFPPCAsmBackend(const Target & T,const Triple & TT)2330b57cec5SDimitry Andric   XCOFFPPCAsmBackend(const Target &T, const Triple &TT)
2340b57cec5SDimitry Andric       : PPCAsmBackend(T, TT) {}
2350b57cec5SDimitry Andric 
2360b57cec5SDimitry Andric   std::unique_ptr<MCObjectTargetWriter>
createObjectTargetWriter() const2370b57cec5SDimitry Andric   createObjectTargetWriter() const override {
2380b57cec5SDimitry Andric     return createPPCXCOFFObjectWriter(TT.isArch64Bit());
2390b57cec5SDimitry Andric   }
24006c3fb27SDimitry Andric 
24106c3fb27SDimitry Andric   std::optional<MCFixupKind> getFixupKind(StringRef Name) const override;
2420b57cec5SDimitry Andric };
2430b57cec5SDimitry Andric 
2440b57cec5SDimitry Andric } // end anonymous namespace
2450b57cec5SDimitry Andric 
246bdd1243dSDimitry Andric std::optional<MCFixupKind>
getFixupKind(StringRef Name) const247bdd1243dSDimitry Andric ELFPPCAsmBackend::getFixupKind(StringRef Name) const {
2485ffd83dbSDimitry Andric   if (TT.isOSBinFormatELF()) {
2495ffd83dbSDimitry Andric     unsigned Type;
2500b57cec5SDimitry Andric     if (TT.isPPC64()) {
2515ffd83dbSDimitry Andric       Type = llvm::StringSwitch<unsigned>(Name)
2525ffd83dbSDimitry Andric #define ELF_RELOC(X, Y) .Case(#X, Y)
2535ffd83dbSDimitry Andric #include "llvm/BinaryFormat/ELFRelocs/PowerPC64.def"
2545ffd83dbSDimitry Andric #undef ELF_RELOC
255fe6060f1SDimitry Andric                  .Case("BFD_RELOC_NONE", ELF::R_PPC64_NONE)
256fe6060f1SDimitry Andric                  .Case("BFD_RELOC_16", ELF::R_PPC64_ADDR16)
257fe6060f1SDimitry Andric                  .Case("BFD_RELOC_32", ELF::R_PPC64_ADDR32)
258fe6060f1SDimitry Andric                  .Case("BFD_RELOC_64", ELF::R_PPC64_ADDR64)
2595ffd83dbSDimitry Andric                  .Default(-1u);
2600b57cec5SDimitry Andric     } else {
2615ffd83dbSDimitry Andric       Type = llvm::StringSwitch<unsigned>(Name)
2625ffd83dbSDimitry Andric #define ELF_RELOC(X, Y) .Case(#X, Y)
2635ffd83dbSDimitry Andric #include "llvm/BinaryFormat/ELFRelocs/PowerPC.def"
2645ffd83dbSDimitry Andric #undef ELF_RELOC
265fe6060f1SDimitry Andric                  .Case("BFD_RELOC_NONE", ELF::R_PPC_NONE)
266fe6060f1SDimitry Andric                  .Case("BFD_RELOC_16", ELF::R_PPC_ADDR16)
267fe6060f1SDimitry Andric                  .Case("BFD_RELOC_32", ELF::R_PPC_ADDR32)
2685ffd83dbSDimitry Andric                  .Default(-1u);
2690b57cec5SDimitry Andric     }
2705ffd83dbSDimitry Andric     if (Type != -1u)
2715ffd83dbSDimitry Andric       return static_cast<MCFixupKind>(FirstLiteralRelocationKind + Type);
2725ffd83dbSDimitry Andric   }
273bdd1243dSDimitry Andric   return std::nullopt;
2740b57cec5SDimitry Andric }
2750b57cec5SDimitry Andric 
27606c3fb27SDimitry Andric std::optional<MCFixupKind>
getFixupKind(StringRef Name) const27706c3fb27SDimitry Andric XCOFFPPCAsmBackend::getFixupKind(StringRef Name) const {
27806c3fb27SDimitry Andric   return StringSwitch<std::optional<MCFixupKind>>(Name)
27906c3fb27SDimitry Andric       .Case("R_REF", (MCFixupKind)PPC::fixup_ppc_nofixup)
28006c3fb27SDimitry Andric       .Default(std::nullopt);
28106c3fb27SDimitry Andric }
28206c3fb27SDimitry Andric 
createPPCAsmBackend(const Target & T,const MCSubtargetInfo & STI,const MCRegisterInfo & MRI,const MCTargetOptions & Options)2830b57cec5SDimitry Andric MCAsmBackend *llvm::createPPCAsmBackend(const Target &T,
2840b57cec5SDimitry Andric                                         const MCSubtargetInfo &STI,
2850b57cec5SDimitry Andric                                         const MCRegisterInfo &MRI,
2860b57cec5SDimitry Andric                                         const MCTargetOptions &Options) {
2870b57cec5SDimitry Andric   const Triple &TT = STI.getTargetTriple();
2880b57cec5SDimitry Andric   if (TT.isOSBinFormatXCOFF())
2890b57cec5SDimitry Andric     return new XCOFFPPCAsmBackend(T, TT);
2900b57cec5SDimitry Andric 
2910b57cec5SDimitry Andric   return new ELFPPCAsmBackend(T, TT);
2920b57cec5SDimitry Andric }
293