Skip to content

[SPARC][IAS] Emit the correct 32-bit ELF machine type #96583

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Jul 3, 2024

Conversation

koachan
Copy link
Contributor

@koachan koachan commented Jun 25, 2024

Emit the correct machine type when writing out 32-bit ELF objects. This patch is modeled on GCC's behavior:

  • -m32 emits an object of type EM_SPARC;
  • -m32 -mcpu=v9 emits EM_SPARC32PLUS (however, see below); and
  • -m64 emits EM_SPARCV9.

Note:
GNU as doesn't actually support user control of emitted machine type. It will always autodetect the type based on the instruction mix:

  • If there's a V9 instruction inside, then use EM_SPARC32PLUS; and
  • Emit EM_SPARC otherwise.

GCC simply happens to try to emit V9 instructions whenever possible with -m32 -mcpu=v9, so there's a high chance that the resulting object file will be of a EM_SPARC32PLUS type, however it is not a guaranteed behavior.

For this patch, I opt for deterministic behavior for simplicity.

Emit the correct machine type when writing out 32-bit ELF objects.
This patch is modeled on GCC's behavior:
- `-m32` emits an object of type EM_SPARC;
- `-m32 -mcpu=v9` emits EM_SPARC32PLUS (however, see below); and
- `-m64` emits EM_SPARCV9.

Note:
GNU as doesn't actually support user control of emitted machine type.
It will always autodetect the type based on the instruction mix:
- If there's a V9 instruction inside, then use EM_SPARC32PLUS; and
- Emit EM_SPARC otherwise.

GCC simply happens to try to emit V9 instructions whenever possible
with `-m32 -mcpu=v9`, so there's a high chance that the resulting
object file will be of a EM_SPARC32PLUS type, however it is not
a guaranteed behavior.

For this patch, I opt for deterministic behavior for simplicity.
@koachan
Copy link
Contributor Author

koachan commented Jun 25, 2024

CC @glaubitz

@llvmbot
Copy link
Member

llvmbot commented Jun 25, 2024

@llvm/pr-subscribers-mc

@llvm/pr-subscribers-backend-sparc

Author: Koakuma (koachan)

Changes

Emit the correct machine type when writing out 32-bit ELF objects. This patch is modeled on GCC's behavior:

  • -m32 emits an object of type EM_SPARC;
  • -m32 -mcpu=v9 emits EM_SPARC32PLUS (however, see below); and
  • -m64 emits EM_SPARCV9.

Note:
GNU as doesn't actually support user control of emitted machine type. It will always autodetect the type based on the instruction mix:

  • If there's a V9 instruction inside, then use EM_SPARC32PLUS; and
  • Emit EM_SPARC otherwise.

GCC simply happens to try to emit V9 instructions whenever possible with -m32 -mcpu=v9, so there's a high chance that the resulting object file will be of a EM_SPARC32PLUS type, however it is not a guaranteed behavior.

For this patch, I opt for deterministic behavior for simplicity.


Full diff: https://github.com/llvm/llvm-project/pull/96583.diff

3 Files Affected:

  • (modified) llvm/lib/Target/Sparc/MCTargetDesc/SparcAsmBackend.cpp (+11-6)
  • (modified) llvm/lib/Target/Sparc/MCTargetDesc/SparcELFObjectWriter.cpp (+8-6)
  • (modified) llvm/lib/Target/Sparc/MCTargetDesc/SparcMCTargetDesc.h (+2-2)
diff --git a/llvm/lib/Target/Sparc/MCTargetDesc/SparcAsmBackend.cpp b/llvm/lib/Target/Sparc/MCTargetDesc/SparcAsmBackend.cpp
index cb7414fddd29f..046f81363d294 100644
--- a/llvm/lib/Target/Sparc/MCTargetDesc/SparcAsmBackend.cpp
+++ b/llvm/lib/Target/Sparc/MCTargetDesc/SparcAsmBackend.cpp
@@ -132,14 +132,18 @@ namespace {
   class SparcAsmBackend : public MCAsmBackend {
   protected:
     const Target &TheTarget;
+    const MCSubtargetInfo &TheSTI;
     bool Is64Bit;
+    bool HasV9;
 
   public:
-    SparcAsmBackend(const Target &T)
+    SparcAsmBackend(const Target &T, const MCSubtargetInfo &STI)
         : MCAsmBackend(StringRef(T.getName()) == "sparcel"
                            ? llvm::endianness::little
                            : llvm::endianness::big),
-          TheTarget(T), Is64Bit(StringRef(TheTarget.getName()) == "sparcv9") {}
+          TheTarget(T), TheSTI(STI),
+          Is64Bit(StringRef(TheTarget.getName()) == "sparcv9"),
+          HasV9(TheSTI.hasFeature(Sparc::FeatureV9)) {}
 
     unsigned getNumFixupKinds() const override {
       return Sparc::NumTargetFixupKinds;
@@ -340,8 +344,9 @@ namespace {
   class ELFSparcAsmBackend : public SparcAsmBackend {
     Triple::OSType OSType;
   public:
-    ELFSparcAsmBackend(const Target &T, Triple::OSType OSType) :
-      SparcAsmBackend(T), OSType(OSType) { }
+    ELFSparcAsmBackend(const Target &T, const MCSubtargetInfo &STI,
+                       Triple::OSType OSType)
+        : SparcAsmBackend(T, STI), OSType(OSType) {}
 
     void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
                     const MCValue &Target, MutableArrayRef<char> Data,
@@ -368,7 +373,7 @@ namespace {
     std::unique_ptr<MCObjectTargetWriter>
     createObjectTargetWriter() const override {
       uint8_t OSABI = MCELFObjectTargetWriter::getOSABI(OSType);
-      return createSparcELFObjectWriter(Is64Bit, OSABI);
+      return createSparcELFObjectWriter(Is64Bit, HasV9, OSABI);
     }
   };
 
@@ -378,5 +383,5 @@ MCAsmBackend *llvm::createSparcAsmBackend(const Target &T,
                                           const MCSubtargetInfo &STI,
                                           const MCRegisterInfo &MRI,
                                           const MCTargetOptions &Options) {
-  return new ELFSparcAsmBackend(T, STI.getTargetTriple().getOS());
+  return new ELFSparcAsmBackend(T, STI, STI.getTargetTriple().getOS());
 }
diff --git a/llvm/lib/Target/Sparc/MCTargetDesc/SparcELFObjectWriter.cpp b/llvm/lib/Target/Sparc/MCTargetDesc/SparcELFObjectWriter.cpp
index f17d3e997452d..bfd71af736231 100644
--- a/llvm/lib/Target/Sparc/MCTargetDesc/SparcELFObjectWriter.cpp
+++ b/llvm/lib/Target/Sparc/MCTargetDesc/SparcELFObjectWriter.cpp
@@ -21,10 +21,12 @@ using namespace llvm;
 namespace {
   class SparcELFObjectWriter : public MCELFObjectTargetWriter {
   public:
-    SparcELFObjectWriter(bool Is64Bit, uint8_t OSABI)
-      : MCELFObjectTargetWriter(Is64Bit, OSABI,
-                                Is64Bit ?  ELF::EM_SPARCV9 : ELF::EM_SPARC,
-                                /*HasRelocationAddend*/ true) {}
+    SparcELFObjectWriter(bool Is64Bit, bool HasV9, uint8_t OSABI)
+        : MCELFObjectTargetWriter(
+              Is64Bit, OSABI,
+              Is64Bit ? ELF::EM_SPARCV9
+                      : (HasV9 ? ELF::EM_SPARC32PLUS : ELF::EM_SPARC),
+              /*HasRelocationAddend*/ true) {}
 
     ~SparcELFObjectWriter() override = default;
 
@@ -146,6 +148,6 @@ bool SparcELFObjectWriter::needsRelocateWithSymbol(const MCValue &,
 }
 
 std::unique_ptr<MCObjectTargetWriter>
-llvm::createSparcELFObjectWriter(bool Is64Bit, uint8_t OSABI) {
-  return std::make_unique<SparcELFObjectWriter>(Is64Bit, OSABI);
+llvm::createSparcELFObjectWriter(bool Is64Bit, bool HasV9, uint8_t OSABI) {
+  return std::make_unique<SparcELFObjectWriter>(Is64Bit, HasV9, OSABI);
 }
diff --git a/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCTargetDesc.h b/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCTargetDesc.h
index a2a9f7474c3f9..63419663b722c 100644
--- a/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCTargetDesc.h
+++ b/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCTargetDesc.h
@@ -34,8 +34,8 @@ MCCodeEmitter *createSparcMCCodeEmitter(const MCInstrInfo &MCII,
 MCAsmBackend *createSparcAsmBackend(const Target &T, const MCSubtargetInfo &STI,
                                     const MCRegisterInfo &MRI,
                                     const MCTargetOptions &Options);
-std::unique_ptr<MCObjectTargetWriter> createSparcELFObjectWriter(bool Is64Bit,
-                                                                 uint8_t OSABI);
+std::unique_ptr<MCObjectTargetWriter>
+createSparcELFObjectWriter(bool Is64Bit, bool HasV9, uint8_t OSABI);
 
 // Defines symbolic names for Sparc v9 ASI tag names.
 namespace SparcASITag {

@koachan
Copy link
Contributor Author

koachan commented Jun 25, 2024

Also, any ideas on how should I go to unit test this change?

: MCAsmBackend(StringRef(T.getName()) == "sparcel"
? llvm::endianness::little
: llvm::endianness::big),
TheTarget(T), Is64Bit(StringRef(TheTarget.getName()) == "sparcv9") {}
TheTarget(T), TheSTI(STI),
Is64Bit(StringRef(TheTarget.getName()) == "sparcv9"),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unrelated to your change, but I wonder whether checking for the target name being sparcv9 is the proper and robust way to check whether we're on 64-bit SPARC. On Linux, the 64-bit SPARC target is called sparc64 and not sparcv9.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems so. In Triple.cpp both sparcv9 and sparc64 resolves to Triple::sparcv9, then in SparcTargetInfo.cpp said triple is registered under the "sparcv9" name.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now you have STI, you can just get the triple and avoid ugly string comparisons for all these (isArch64Bit and isLittleEndian)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, thanks for the clarification. We're good then. ;-)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now you have STI, you can just get the triple and avoid ugly string comparisons for all these (isArch64Bit and isLittleEndian)

Whoops, I missed this comment, but fixed too, thanks!

@glaubitz
Copy link
Contributor

Looks good to me. Thanks for fixing this!

@glaubitz
Copy link
Contributor

Also, any ideas on how should I go to unit test this change?

Maybe using the file command to test for the machine type of a generated object file?

@s-barannikov
Copy link
Contributor

s-barannikov commented Jun 28, 2024

Also, any ideas on how should I go to unit test this change?

Look for existing MC tests using llvm-readobj -h.

@llvmbot llvmbot added the mc Machine (object) code label Jul 1, 2024
@@ -132,14 +132,18 @@ namespace {
class SparcAsmBackend : public MCAsmBackend {
protected:
const Target &TheTarget;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems unused beyond in the constructor?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, yeah. Lemme remove it.

@glaubitz
Copy link
Contributor

glaubitz commented Jul 1, 2024

Unit test looks good to me as well. I would prefer squashing the two additional commits into the original commits though since the test belongs to the change.

@koachan
Copy link
Contributor Author

koachan commented Jul 2, 2024

Unit test looks good to me as well. I would prefer squashing the two additional commits into the original commits though since the test belongs to the change.

Yep, it'll be squashed automatically during the merge :)

@glaubitz
Copy link
Contributor

glaubitz commented Jul 2, 2024

Unit test looks good to me as well. I would prefer squashing the two additional commits into the original commits though since the test belongs to the change.

Yep, it'll be squashed automatically during the merge :)

OK, I wasn't aware of that.

Copy link
Contributor

@s-barannikov s-barannikov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The changes LGTM as a step towards supporting V8+


public:
SparcAsmBackend(const Target &T)
: MCAsmBackend(StringRef(T.getName()) == "sparcel"
SparcAsmBackend(const Target &T, const MCSubtargetInfo &STI)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

T is unused

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed, but I guess the one in createSparcAsmBackend should be left as it is?
RegisterMCAsmBackend seems to require a Target parameter present in there...

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that's normal, you just take what you need

@koachan
Copy link
Contributor Author

koachan commented Jul 2, 2024

Git checkout failed as commit a168c9d could not be found in branch koachan:sparc64-v8plus.

Hmm, so how do I rerun the tests? Seems like it cannot find the commit I just pushed?
Or would it be okay if I merge it as it is now?

@jrtc27
Copy link
Collaborator

jrtc27 commented Jul 2, 2024

Looks like it got a stale view of the repo for some reason. Probably will work again if you push a dummy commit (git commit --allow-empty?). Buildkite has a Rebuild button but I don't know how you get permission to actually use it.

@s-barannikov
Copy link
Contributor

Hmm, so how do I rerun the tests?

Try force pushing or updating the branch (there is a button below CI checks).

@koachan koachan requested a review from jrtc27 July 3, 2024 03:40
@koachan koachan requested a review from s-barannikov July 3, 2024 03:40
@koachan koachan merged commit fb7f65b into llvm:main Jul 3, 2024
7 checks passed
@koachan koachan deleted the sparc64-v8plus branch July 3, 2024 12:14
lravenclaw pushed a commit to lravenclaw/llvm-project that referenced this pull request Jul 3, 2024
Emit the correct machine type when writing out ELF objects.
This patch is modeled on GCC's behavior:
- `-m32` emits an object of type EM_SPARC;
- `-m32 -mcpu=v9` emits EM_SPARC32PLUS (however, see below); and
- `-m64` emits EM_SPARCV9.

Note that GCC does not guarantee emission of EM_SPARC32PLUS objects,
since GNU as doesn't support user control of emitted machine type.
It will always autodetect the type based on the instruction mix:
- If there's a V9 instruction inside, then emit EM_SPARC32PLUS; and
- Emit EM_SPARC otherwise.

For LLVM we choose deterministic behavior instead for simplicity.
kbluck pushed a commit to kbluck/llvm-project that referenced this pull request Jul 6, 2024
Emit the correct machine type when writing out ELF objects.
This patch is modeled on GCC's behavior:
- `-m32` emits an object of type EM_SPARC;
- `-m32 -mcpu=v9` emits EM_SPARC32PLUS (however, see below); and
- `-m64` emits EM_SPARCV9.

Note that GCC does not guarantee emission of EM_SPARC32PLUS objects,
since GNU as doesn't support user control of emitted machine type.
It will always autodetect the type based on the instruction mix:
- If there's a V9 instruction inside, then emit EM_SPARC32PLUS; and
- Emit EM_SPARC otherwise.

For LLVM we choose deterministic behavior instead for simplicity.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
backend:Sparc mc Machine (object) code
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants