-
Notifications
You must be signed in to change notification settings - Fork 13.6k
[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
Conversation
@llvm/pr-subscribers-clang @llvm/pr-subscribers-backend-x86 Author: Pranav Kant (pranavk) ChangesWe 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:
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;
|
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. |
There was a problem hiding this comment.
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.
clang/lib/CodeGen/Targets/X86.cpp
Outdated
if (returnCXXRecordGreaterThan128InMem( | ||
Size, getContext().getTypeSize(I.getType()), | ||
getNativeVectorSizeForAVXABI(AVXLevel))) | ||
Lo = Memory; |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this 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 |
There was a problem hiding this comment.
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.
There was a problem hiding this 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?
you mean mention this in release section? I plan to add a note in clang/docs/ReleaseNotes.rst. Next week. |
there's no x86 section in the release notes. So I added it in ABI section. |
There is a |
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
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.
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. |
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. |
We don't need this urgently. I am fine just keeping it like this. |
clang/lib/CodeGen/Targets/X86.cpp
Outdated
return false; | ||
|
||
const llvm::Triple &T = getTarget().getTriple(); | ||
return T.isOSLinux() || T.isOSNetBSD(); |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
I've checked in 560e372 to fix the build. |
Thank you |
@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 |
Checking ... |
I fixed this in #125787 |
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
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