Skip to content

[clang] Return larger CXX records in memory #120670

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 2 commits into from
Feb 4, 2025
Merged

[clang] Return larger CXX records in memory #120670

merged 2 commits into from
Feb 4, 2025

Conversation

pranavk
Copy link
Contributor

@pranavk pranavk commented Dec 20, 2024

We incorrectly return CXX records in AVX registers when they should be returned in memory. This is violation of x86-64 psABI.

Detailed discussion is here: https://groups.google.com/g/x86-64-abi/c/BjOOyihHuqg/m/KurXdUcWAgAJ

@llvmbot llvmbot added clang Clang issues not falling into any other category backend:X86 clang:frontend Language frontend issues, e.g. anything involving "Sema" clang:codegen IR generation bugs: mangling, exceptions, etc. labels Dec 20, 2024
@llvmbot
Copy link
Member

llvmbot commented Dec 20, 2024

@llvm/pr-subscribers-clang
@llvm/pr-subscribers-clang-codegen

@llvm/pr-subscribers-backend-x86

Author: Pranav Kant (pranavk)

Changes

We incorrectly return CXX records in AVX registers when they should be returned in memory. This is violation of x86-64 psABI.

Detailed discussion is here: https://groups.google.com/g/x86-64-abi/c/BjOOyihHuqg/m/KurXdUcWAgAJ


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

2 Files Affected:

  • (modified) clang/include/clang/Basic/LangOptions.h (+1)
  • (modified) clang/lib/CodeGen/Targets/X86.cpp (+18)
diff --git a/clang/include/clang/Basic/LangOptions.h b/clang/include/clang/Basic/LangOptions.h
index 949c8f5d448bcf..0dd644eba559b9 100644
--- a/clang/include/clang/Basic/LangOptions.h
+++ b/clang/include/clang/Basic/LangOptions.h
@@ -245,6 +245,7 @@ class LangOptionsBase {
     ///   construction vtable because it hasn't added 'type' as a substitution.
     ///   - Skip mangling enclosing class templates of member-like friend
     ///   function templates.
+    ///   - Incorrectly return C++ records in AVX registers.
     Ver19,
 
     /// Conform to the underlying platform's C and C++ ABIs as closely
diff --git a/clang/lib/CodeGen/Targets/X86.cpp b/clang/lib/CodeGen/Targets/X86.cpp
index 7f73bf2a65266e..70d812057d0b01 100644
--- a/clang/lib/CodeGen/Targets/X86.cpp
+++ b/clang/lib/CodeGen/Targets/X86.cpp
@@ -1334,6 +1334,20 @@ class X86_64ABIInfo : public ABIInfo {
     return T.isOSLinux() || T.isOSNetBSD();
   }
 
+  bool returnCXXRecordGreaterThan128InMem(unsigned Size, unsigned TypeSize,
+                                          unsigned NativeSize) const {
+    // Clang <= 19.0 did not do this.
+    if (getContext().getLangOpts().getClangABICompat() <=
+        LangOptions::ClangABI::Ver19)
+      return false;
+
+    // The only case a 256(or 512)-bit wide vector could be used to return
+    // is when CXX record contains a single 256(or 512)-bit element.
+    if (Size > 128 && (Size != TypeSize || Size > NativeSize))
+      return true;
+    return false;
+  }
+
   X86AVXABILevel AVXLevel;
   // Some ABIs (e.g. X32 ABI and Native Client OS) use 32 bit pointers on
   // 64-bit hardware.
@@ -2067,6 +2081,10 @@ void X86_64ABIInfo::classify(QualType Ty, uint64_t OffsetBase, Class &Lo,
         classify(I.getType(), Offset, FieldLo, FieldHi, isNamedArg);
         Lo = merge(Lo, FieldLo);
         Hi = merge(Hi, FieldHi);
+        if (returnCXXRecordGreaterThan128InMem(
+                Size, getContext().getTypeSize(I.getType()),
+                getNativeVectorSizeForAVXABI(AVXLevel)))
+          Lo = Memory;
         if (Lo == Memory || Hi == Memory) {
           postMerge(Size, Lo, Hi);
           return;

@efriedma-quic
Copy link
Collaborator

Missing regression test in clang/test/CodeGen.

We probably want a release note for this (clang/docs/ReleaseNotes.rst).

(If you're interested, there's another x86-64 ABI bug which nobody got around to fixing: #76017.)

@@ -245,6 +245,7 @@ class LangOptionsBase {
/// construction vtable because it hasn't added 'type' as a substitution.
/// - Skip mangling enclosing class templates of member-like friend
/// function templates.
/// - Incorrectly return C++ records in AVX registers.
Copy link
Contributor

Choose a reason for hiding this comment

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

in AVX registers on x86_64.

Comment on lines 2084 to 2085
if (returnCXXRecordGreaterThan128InMem(
Size, getContext().getTypeSize(I.getType()),
getNativeVectorSizeForAVXABI(AVXLevel)))
Lo = Memory;
Copy link
Contributor

Choose a reason for hiding this comment

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

Why don't do early check and return like line 2022? IIRC, the default value of Lo/Hi is Memory.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This seemed like the most appropriate location for such a check as I only want to do it for CXXRecords (if dyn_cast<CXXRecordDecl> ...) which is already being checked here.

Copy link
Contributor

@phoebewang phoebewang left a comment

Choose a reason for hiding this comment

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

LGTM.

@@ -0,0 +1,23 @@
// RUN: %clang %s -S --target=x86_64-unknown-linux-gnu -emit-llvm -O2 -march=x86-64-v3 -o - | FileCheck %s
Copy link
Contributor

Choose a reason for hiding this comment

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

Add a RUN line for BSD.

Copy link
Collaborator

@shafik shafik left a comment

Choose a reason for hiding this comment

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

Shouldn't this have some sort of Release not maybe under the X86 section?

@pranavk
Copy link
Contributor Author

pranavk commented Jan 24, 2025

Shouldn't this have some sort of Release not maybe under the X86 section?

you mean mention this in release section? I plan to add a note in clang/docs/ReleaseNotes.rst. Next week.

@pranavk
Copy link
Contributor Author

pranavk commented Jan 28, 2025

Shouldn't this have some sort of Release not maybe under the X86 section?

there's no x86 section in the release notes. So I added it in ABI section.

@phoebewang
Copy link
Contributor

Shouldn't this have some sort of Release not maybe under the X86 section?

there's no x86 section in the release notes. So I added it in ABI section.

There is a X86 Support section. Note, the ReleaseNotes was updated since LLVM 20 branch created. You need to merge the main and update it.

We incorrectly return CXX records in AVX registers when they should be
returned in memory. This is violation of x86-64 psABI.

Detailed discussion is here: https://groups.google.com/g/x86-64-abi/c/BjOOyihHuqg/m/KurXdUcWAgAJ
@pranavk
Copy link
Contributor Author

pranavk commented Jan 29, 2025

Oops. Too bad. I didn't realize we branched off release/20.x

Anyhow, I made necessary tweaks to now make it a LLVM 21 feature.

There is a X86 Support section

It feels more appropriate to put this in "ABI changes section" than "X86 support" since it's not a "support". But I am happy to move that over if that's the precedence for these kind of changes. Let me know.

@efriedma-quic
Copy link
Collaborator

You can cherry-pick this to the 20.x branch if you want; we can still land fixes like this for a few weeks after the branch is created.

@pranavk
Copy link
Contributor Author

pranavk commented Jan 29, 2025

We don't need this urgently. I am fine just keeping it like this.

return false;

const llvm::Triple &T = getTarget().getTriple();
return T.isOSLinux() || T.isOSNetBSD();
Copy link
Collaborator

Choose a reason for hiding this comment

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

Please make this apply to all targets by default. Almost all targets will want to be consistent with the spec and gcc. If you think you need to exclude some target for some reason, please list it explicitly.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

@pranavk pranavk merged commit e8a486e into llvm:main Feb 4, 2025
9 checks passed
@kazutakahirata
Copy link
Contributor

I've checked in 560e372 to fix the build.

@pranavk
Copy link
Contributor Author

pranavk commented Feb 4, 2025

Thank you

@dyung
Copy link
Collaborator

dyung commented Feb 4, 2025

@pranavk the test you added seems to fail in a release build without asserts enabled. Can you take a look?

https://lab.llvm.org/staging/#/builders/202/builds/857/steps/6/logs/FAIL__Clang__avx-cxx-record_cpp

@pranavk
Copy link
Contributor Author

pranavk commented Feb 4, 2025

Checking ...

@pranavk
Copy link
Contributor Author

pranavk commented Feb 5, 2025

I fixed this in #125787

Icohedron pushed a commit to Icohedron/llvm-project that referenced this pull request Feb 11, 2025
We incorrectly return CXX records in AVX registers when they should be
returned in memory. This is violation of x86-64 psABI.

Detailed discussion is here:
https://groups.google.com/g/x86-64-abi/c/BjOOyihHuqg/m/KurXdUcWAgAJ
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
backend:X86 clang:codegen IR generation bugs: mangling, exceptions, etc. clang:frontend Language frontend issues, e.g. anything involving "Sema" clang Clang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants