From 3e6323ae7aadcb1a41332a3e3f3d358b16bc2c49 Mon Sep 17 00:00:00 2001 From: Koakuma Date: Wed, 31 Jul 2024 23:36:23 +0700 Subject: [PATCH 1/3] [SPARC] Add v8plus feature bit Implement handling for `v8plus` feature bit to allow the user to switch between V8 and V8+ mode with 32-bit code. This is done as a prerequisite for `-mv8plus` flag on clang (#98713). --- .../Sparc/MCTargetDesc/SparcAsmBackend.cpp | 4 +++- .../Sparc/MCTargetDesc/SparcELFObjectWriter.cpp | 17 ++++++++++++----- .../Sparc/MCTargetDesc/SparcMCTargetDesc.h | 6 ++++-- llvm/lib/Target/Sparc/Sparc.td | 3 +++ llvm/test/MC/Sparc/elf-sparc-machine-type.s | 9 +++++---- 5 files changed, 27 insertions(+), 12 deletions(-) diff --git a/llvm/lib/Target/Sparc/MCTargetDesc/SparcAsmBackend.cpp b/llvm/lib/Target/Sparc/MCTargetDesc/SparcAsmBackend.cpp index 29282582b82bde..c2f9111375f412 100644 --- a/llvm/lib/Target/Sparc/MCTargetDesc/SparcAsmBackend.cpp +++ b/llvm/lib/Target/Sparc/MCTargetDesc/SparcAsmBackend.cpp @@ -132,6 +132,7 @@ namespace { class SparcAsmBackend : public MCAsmBackend { protected: bool Is64Bit; + bool IsV8Plus; bool HasV9; public: @@ -140,6 +141,7 @@ namespace { ? llvm::endianness::little : llvm::endianness::big), Is64Bit(STI.getTargetTriple().isArch64Bit()), + IsV8Plus(STI.hasFeature(Sparc::FeatureV8Plus)), HasV9(STI.hasFeature(Sparc::FeatureV9)) {} unsigned getNumFixupKinds() const override { @@ -359,7 +361,7 @@ namespace { std::unique_ptr createObjectTargetWriter() const override { uint8_t OSABI = MCELFObjectTargetWriter::getOSABI(OSType); - return createSparcELFObjectWriter(Is64Bit, HasV9, OSABI); + return createSparcELFObjectWriter(Is64Bit, IsV8Plus, HasV9, OSABI); } }; diff --git a/llvm/lib/Target/Sparc/MCTargetDesc/SparcELFObjectWriter.cpp b/llvm/lib/Target/Sparc/MCTargetDesc/SparcELFObjectWriter.cpp index bfd71af736231a..87c914326fdbf1 100644 --- a/llvm/lib/Target/Sparc/MCTargetDesc/SparcELFObjectWriter.cpp +++ b/llvm/lib/Target/Sparc/MCTargetDesc/SparcELFObjectWriter.cpp @@ -21,11 +21,16 @@ using namespace llvm; namespace { class SparcELFObjectWriter : public MCELFObjectTargetWriter { public: - SparcELFObjectWriter(bool Is64Bit, bool HasV9, uint8_t OSABI) + SparcELFObjectWriter(bool Is64Bit, bool IsV8Plus, bool HasV9, uint8_t OSABI) : MCELFObjectTargetWriter( Is64Bit, OSABI, - Is64Bit ? ELF::EM_SPARCV9 - : (HasV9 ? ELF::EM_SPARC32PLUS : ELF::EM_SPARC), + Is64Bit + ? ELF::EM_SPARCV9 + // Note that we still need to emit an EM_SPARC32PLUS object + // even when V8+ isn't explicitly requested, if we're + // targeting a V9-capable CPU. This matches GAS behavior upon + // encountering any V9 instructions in its input. + : ((IsV8Plus || HasV9) ? ELF::EM_SPARC32PLUS : ELF::EM_SPARC), /*HasRelocationAddend*/ true) {} ~SparcELFObjectWriter() override = default; @@ -148,6 +153,8 @@ bool SparcELFObjectWriter::needsRelocateWithSymbol(const MCValue &, } std::unique_ptr -llvm::createSparcELFObjectWriter(bool Is64Bit, bool HasV9, uint8_t OSABI) { - return std::make_unique(Is64Bit, HasV9, OSABI); +llvm::createSparcELFObjectWriter(bool Is64Bit, bool IsV8Plus, bool HasV9, + uint8_t OSABI) { + return std::make_unique(Is64Bit, IsV8Plus, HasV9, + OSABI); } diff --git a/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCTargetDesc.h b/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCTargetDesc.h index 63419663b722c5..4d195c5130c48f 100644 --- a/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCTargetDesc.h +++ b/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCTargetDesc.h @@ -34,8 +34,10 @@ MCCodeEmitter *createSparcMCCodeEmitter(const MCInstrInfo &MCII, MCAsmBackend *createSparcAsmBackend(const Target &T, const MCSubtargetInfo &STI, const MCRegisterInfo &MRI, const MCTargetOptions &Options); -std::unique_ptr -createSparcELFObjectWriter(bool Is64Bit, bool HasV9, uint8_t OSABI); +std::unique_ptr createSparcELFObjectWriter(bool Is64Bit, + bool IsV8Plus, + bool HasV9, + uint8_t OSABI); // Defines symbolic names for Sparc v9 ASI tag names. namespace SparcASITag { diff --git a/llvm/lib/Target/Sparc/Sparc.td b/llvm/lib/Target/Sparc/Sparc.td index 65f372f4376b13..8b1122741b6616 100644 --- a/llvm/lib/Target/Sparc/Sparc.td +++ b/llvm/lib/Target/Sparc/Sparc.td @@ -34,6 +34,9 @@ def FeatureNoFMULS def FeatureV9 : SubtargetFeature<"v9", "IsV9", "true", "Enable SPARC-V9 instructions">; +def FeatureV8Plus + : SubtargetFeature<"v8plus", "IsV8Plus", "true", + "Enable V8+ mode, allowing use of 64-bit V9 instructions in 32-bit code">; def FeatureV8Deprecated : SubtargetFeature<"deprecated-v8", "UseV8DeprecatedInsts", "true", "Enable deprecated V8 instructions in V9 mode">; diff --git a/llvm/test/MC/Sparc/elf-sparc-machine-type.s b/llvm/test/MC/Sparc/elf-sparc-machine-type.s index 630812394560ca..a4bd3607e350db 100644 --- a/llvm/test/MC/Sparc/elf-sparc-machine-type.s +++ b/llvm/test/MC/Sparc/elf-sparc-machine-type.s @@ -1,11 +1,12 @@ ## Emit correct machine type depending on triple and cpu options. ## - `-triple sparc` emits an object of type EM_SPARC; -## - `-triple sparc -mcpu=v9` emits EM_SPARC32PLUS; and +## - `-triple sparc -mcpu=v9` or `-triple sparc -mattr=+v8plus` emits EM_SPARC32PLUS; and ## - `-triple sparcv9` emits EM_SPARCV9. -# RUN: llvm-mc -filetype=obj -triple sparc %s -o - | llvm-readobj -h - | FileCheck --check-prefixes=SPARC %s -# RUN: llvm-mc -filetype=obj -triple sparc -mcpu=v9 %s -o - | llvm-readobj -h - | FileCheck --check-prefixes=SPARC32PLUS %s -# RUN: llvm-mc -filetype=obj -triple sparcv9 %s -o - | llvm-readobj -h - | FileCheck --check-prefixes=SPARCV9 %s +# RUN: llvm-mc -filetype=obj -triple sparc %s -o - | llvm-readobj -h - | FileCheck --check-prefixes=SPARC %s +# RUN: llvm-mc -filetype=obj -triple sparc -mcpu=v9 %s -o - | llvm-readobj -h - | FileCheck --check-prefixes=SPARC32PLUS %s +# RUN: llvm-mc -filetype=obj -triple sparc -mattr=+v8plus %s -o - | llvm-readobj -h - | FileCheck --check-prefixes=SPARC32PLUS %s +# RUN: llvm-mc -filetype=obj -triple sparcv9 %s -o - | llvm-readobj -h - | FileCheck --check-prefixes=SPARCV9 %s # SPARC: Machine: EM_SPARC (0x2) # SPARC32PLUS: Machine: EM_SPARC32PLUS (0x12) From 1da748cc8c3a875e5a7bd25a91f9a969bee3222f Mon Sep 17 00:00:00 2001 From: Koakuma Date: Thu, 1 Aug 2024 19:07:13 +0700 Subject: [PATCH 2/3] Only emit EM_SPARC32PLUS objects on explicit request --- llvm/include/llvm/BinaryFormat/ELF.h | 13 ++++++++++ .../Sparc/MCTargetDesc/SparcAsmBackend.cpp | 6 ++--- .../MCTargetDesc/SparcELFObjectWriter.cpp | 17 ++++--------- .../Sparc/MCTargetDesc/SparcMCTargetDesc.cpp | 2 +- .../Sparc/MCTargetDesc/SparcMCTargetDesc.h | 6 ++--- .../MCTargetDesc/SparcTargetStreamer.cpp | 25 +++++++++++++++++-- .../Sparc/MCTargetDesc/SparcTargetStreamer.h | 2 +- llvm/test/MC/Sparc/elf-sparc-machine-type.s | 3 +-- 8 files changed, 48 insertions(+), 26 deletions(-) diff --git a/llvm/include/llvm/BinaryFormat/ELF.h b/llvm/include/llvm/BinaryFormat/ELF.h index 456cffff6b4a7c..fb39bb4b10b377 100644 --- a/llvm/include/llvm/BinaryFormat/ELF.h +++ b/llvm/include/llvm/BinaryFormat/ELF.h @@ -697,6 +697,19 @@ enum { #include "ELFRelocs/SystemZ.def" }; +// SPARC Specific e_flags +enum : unsigned { + EF_SPARC_EXT_MASK = 0xffff00, + EF_SPARC_32PLUS = 0x000100, + EF_SPARC_SUN_US1 = 0x000200, + EF_SPARC_HAL_R1 = 0x000400, + EF_SPARC_SUN_US3 = 0x000800, + EF_SPARCV9_MM = 0x3, + EF_SPARCV9_TSO = 0x0, + EF_SPARCV9_PSO = 0x1, + EF_SPARCV9_RMO = 0x2, +}; + // ELF Relocation type for Sparc. enum { #include "ELFRelocs/Sparc.def" diff --git a/llvm/lib/Target/Sparc/MCTargetDesc/SparcAsmBackend.cpp b/llvm/lib/Target/Sparc/MCTargetDesc/SparcAsmBackend.cpp index c2f9111375f412..66826fadddd2e3 100644 --- a/llvm/lib/Target/Sparc/MCTargetDesc/SparcAsmBackend.cpp +++ b/llvm/lib/Target/Sparc/MCTargetDesc/SparcAsmBackend.cpp @@ -133,7 +133,6 @@ namespace { protected: bool Is64Bit; bool IsV8Plus; - bool HasV9; public: SparcAsmBackend(const MCSubtargetInfo &STI) @@ -141,8 +140,7 @@ namespace { ? llvm::endianness::little : llvm::endianness::big), Is64Bit(STI.getTargetTriple().isArch64Bit()), - IsV8Plus(STI.hasFeature(Sparc::FeatureV8Plus)), - HasV9(STI.hasFeature(Sparc::FeatureV9)) {} + IsV8Plus(STI.hasFeature(Sparc::FeatureV8Plus)) {} unsigned getNumFixupKinds() const override { return Sparc::NumTargetFixupKinds; @@ -361,7 +359,7 @@ namespace { std::unique_ptr createObjectTargetWriter() const override { uint8_t OSABI = MCELFObjectTargetWriter::getOSABI(OSType); - return createSparcELFObjectWriter(Is64Bit, IsV8Plus, HasV9, OSABI); + return createSparcELFObjectWriter(Is64Bit, IsV8Plus, OSABI); } }; diff --git a/llvm/lib/Target/Sparc/MCTargetDesc/SparcELFObjectWriter.cpp b/llvm/lib/Target/Sparc/MCTargetDesc/SparcELFObjectWriter.cpp index 87c914326fdbf1..601199d7170a73 100644 --- a/llvm/lib/Target/Sparc/MCTargetDesc/SparcELFObjectWriter.cpp +++ b/llvm/lib/Target/Sparc/MCTargetDesc/SparcELFObjectWriter.cpp @@ -21,16 +21,11 @@ using namespace llvm; namespace { class SparcELFObjectWriter : public MCELFObjectTargetWriter { public: - SparcELFObjectWriter(bool Is64Bit, bool IsV8Plus, bool HasV9, uint8_t OSABI) + SparcELFObjectWriter(bool Is64Bit, bool IsV8Plus, uint8_t OSABI) : MCELFObjectTargetWriter( Is64Bit, OSABI, - Is64Bit - ? ELF::EM_SPARCV9 - // Note that we still need to emit an EM_SPARC32PLUS object - // even when V8+ isn't explicitly requested, if we're - // targeting a V9-capable CPU. This matches GAS behavior upon - // encountering any V9 instructions in its input. - : ((IsV8Plus || HasV9) ? ELF::EM_SPARC32PLUS : ELF::EM_SPARC), + Is64Bit ? ELF::EM_SPARCV9 + : (IsV8Plus ? ELF::EM_SPARC32PLUS : ELF::EM_SPARC), /*HasRelocationAddend*/ true) {} ~SparcELFObjectWriter() override = default; @@ -153,8 +148,6 @@ bool SparcELFObjectWriter::needsRelocateWithSymbol(const MCValue &, } std::unique_ptr -llvm::createSparcELFObjectWriter(bool Is64Bit, bool IsV8Plus, bool HasV9, - uint8_t OSABI) { - return std::make_unique(Is64Bit, IsV8Plus, HasV9, - OSABI); +llvm::createSparcELFObjectWriter(bool Is64Bit, bool IsV8Plus, uint8_t OSABI) { + return std::make_unique(Is64Bit, IsV8Plus, OSABI); } diff --git a/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCTargetDesc.cpp b/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCTargetDesc.cpp index 2f89bd6ad9c96d..72f9b3bcd96811 100644 --- a/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCTargetDesc.cpp +++ b/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCTargetDesc.cpp @@ -86,7 +86,7 @@ createSparcMCSubtargetInfo(const Triple &TT, StringRef CPU, StringRef FS) { static MCTargetStreamer * createObjectTargetStreamer(MCStreamer &S, const MCSubtargetInfo &STI) { - return new SparcTargetELFStreamer(S); + return new SparcTargetELFStreamer(S, STI); } static MCTargetStreamer *createTargetAsmStreamer(MCStreamer &S, diff --git a/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCTargetDesc.h b/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCTargetDesc.h index 4d195c5130c48f..a7b0538d683b66 100644 --- a/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCTargetDesc.h +++ b/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCTargetDesc.h @@ -34,10 +34,8 @@ MCCodeEmitter *createSparcMCCodeEmitter(const MCInstrInfo &MCII, MCAsmBackend *createSparcAsmBackend(const Target &T, const MCSubtargetInfo &STI, const MCRegisterInfo &MRI, const MCTargetOptions &Options); -std::unique_ptr createSparcELFObjectWriter(bool Is64Bit, - bool IsV8Plus, - bool HasV9, - uint8_t OSABI); +std::unique_ptr +createSparcELFObjectWriter(bool Is64Bit, bool IsV8Plus, uint8_t OSABI); // Defines symbolic names for Sparc v9 ASI tag names. namespace SparcASITag { diff --git a/llvm/lib/Target/Sparc/MCTargetDesc/SparcTargetStreamer.cpp b/llvm/lib/Target/Sparc/MCTargetDesc/SparcTargetStreamer.cpp index d2dcf200aef043..747bdad510e41d 100644 --- a/llvm/lib/Target/Sparc/MCTargetDesc/SparcTargetStreamer.cpp +++ b/llvm/lib/Target/Sparc/MCTargetDesc/SparcTargetStreamer.cpp @@ -12,11 +12,24 @@ #include "SparcTargetStreamer.h" #include "SparcInstPrinter.h" +#include "SparcMCTargetDesc.h" +#include "llvm/BinaryFormat/ELF.h" +#include "llvm/MC/MCAssembler.h" #include "llvm/MC/MCRegister.h" +#include "llvm/MC/MCSubtargetInfo.h" #include "llvm/Support/FormattedStream.h" using namespace llvm; +static unsigned getEFlagsForFeatureSet(const MCSubtargetInfo &STI) { + unsigned EFlags = 0; + + if (STI.hasFeature(Sparc::FeatureV8Plus)) + EFlags |= ELF::EF_SPARC_32PLUS; + + return EFlags; +} + // pin vtable to this file SparcTargetStreamer::SparcTargetStreamer(MCStreamer &S) : MCTargetStreamer(S) {} @@ -38,8 +51,16 @@ void SparcTargetAsmStreamer::emitSparcRegisterScratch(unsigned reg) { << ", #scratch\n"; } -SparcTargetELFStreamer::SparcTargetELFStreamer(MCStreamer &S) - : SparcTargetStreamer(S) {} +SparcTargetELFStreamer::SparcTargetELFStreamer(MCStreamer &S, + const MCSubtargetInfo &STI) + : SparcTargetStreamer(S) { + MCAssembler &MCA = getStreamer().getAssembler(); + unsigned EFlags = MCA.getELFHeaderEFlags(); + + EFlags |= getEFlagsForFeatureSet(STI); + + MCA.setELFHeaderEFlags(EFlags); +} MCELFStreamer &SparcTargetELFStreamer::getStreamer() { return static_cast(Streamer); diff --git a/llvm/lib/Target/Sparc/MCTargetDesc/SparcTargetStreamer.h b/llvm/lib/Target/Sparc/MCTargetDesc/SparcTargetStreamer.h index ef28afa06bffb5..bd9954ffb687bb 100644 --- a/llvm/lib/Target/Sparc/MCTargetDesc/SparcTargetStreamer.h +++ b/llvm/lib/Target/Sparc/MCTargetDesc/SparcTargetStreamer.h @@ -40,7 +40,7 @@ class SparcTargetAsmStreamer : public SparcTargetStreamer { // This part is for ELF object output class SparcTargetELFStreamer : public SparcTargetStreamer { public: - SparcTargetELFStreamer(MCStreamer &S); + SparcTargetELFStreamer(MCStreamer &S, const MCSubtargetInfo &STI); MCELFStreamer &getStreamer(); void emitSparcRegisterIgnore(unsigned reg) override {} void emitSparcRegisterScratch(unsigned reg) override {} diff --git a/llvm/test/MC/Sparc/elf-sparc-machine-type.s b/llvm/test/MC/Sparc/elf-sparc-machine-type.s index a4bd3607e350db..85edec5dbaea5d 100644 --- a/llvm/test/MC/Sparc/elf-sparc-machine-type.s +++ b/llvm/test/MC/Sparc/elf-sparc-machine-type.s @@ -1,10 +1,9 @@ ## Emit correct machine type depending on triple and cpu options. ## - `-triple sparc` emits an object of type EM_SPARC; -## - `-triple sparc -mcpu=v9` or `-triple sparc -mattr=+v8plus` emits EM_SPARC32PLUS; and +## - `-triple sparc -mattr=+v8plus` emits EM_SPARC32PLUS; and ## - `-triple sparcv9` emits EM_SPARCV9. # RUN: llvm-mc -filetype=obj -triple sparc %s -o - | llvm-readobj -h - | FileCheck --check-prefixes=SPARC %s -# RUN: llvm-mc -filetype=obj -triple sparc -mcpu=v9 %s -o - | llvm-readobj -h - | FileCheck --check-prefixes=SPARC32PLUS %s # RUN: llvm-mc -filetype=obj -triple sparc -mattr=+v8plus %s -o - | llvm-readobj -h - | FileCheck --check-prefixes=SPARC32PLUS %s # RUN: llvm-mc -filetype=obj -triple sparcv9 %s -o - | llvm-readobj -h - | FileCheck --check-prefixes=SPARCV9 %s From 3db1a6de9d184ce04a1ed253780cbfda96bdc9ca Mon Sep 17 00:00:00 2001 From: Koakuma Date: Fri, 2 Aug 2024 08:39:06 +0700 Subject: [PATCH 3/3] Adjust code after rebasing --- .../lib/Target/Sparc/MCTargetDesc/SparcTargetStreamer.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/llvm/lib/Target/Sparc/MCTargetDesc/SparcTargetStreamer.cpp b/llvm/lib/Target/Sparc/MCTargetDesc/SparcTargetStreamer.cpp index 747bdad510e41d..3205d06b295ee5 100644 --- a/llvm/lib/Target/Sparc/MCTargetDesc/SparcTargetStreamer.cpp +++ b/llvm/lib/Target/Sparc/MCTargetDesc/SparcTargetStreamer.cpp @@ -14,7 +14,7 @@ #include "SparcInstPrinter.h" #include "SparcMCTargetDesc.h" #include "llvm/BinaryFormat/ELF.h" -#include "llvm/MC/MCAssembler.h" +#include "llvm/MC/MCELFObjectWriter.h" #include "llvm/MC/MCRegister.h" #include "llvm/MC/MCSubtargetInfo.h" #include "llvm/Support/FormattedStream.h" @@ -54,12 +54,12 @@ void SparcTargetAsmStreamer::emitSparcRegisterScratch(unsigned reg) { SparcTargetELFStreamer::SparcTargetELFStreamer(MCStreamer &S, const MCSubtargetInfo &STI) : SparcTargetStreamer(S) { - MCAssembler &MCA = getStreamer().getAssembler(); - unsigned EFlags = MCA.getELFHeaderEFlags(); + ELFObjectWriter &W = getStreamer().getWriter(); + unsigned EFlags = W.getELFHeaderEFlags(); EFlags |= getEFlagsForFeatureSet(STI); - MCA.setELFHeaderEFlags(EFlags); + W.setELFHeaderEFlags(EFlags); } MCELFStreamer &SparcTargetELFStreamer::getStreamer() {