[clang] 3b3a165 - [MS] On x86_32, pass overaligned, non-copyable arguments indirectly
Reid Kleckner via cfe-commits
cfe-commits at lists.llvm.org
Mon Sep 21 11:49:24 PDT 2020
Author: Reid Kleckner
Date: 2020-09-21T11:49:17-07:00
New Revision: 3b3a16548568f5b6c4146ca5129eb6af5000e4ff
URL: https://github.com/llvm/llvm-project/commit/3b3a16548568f5b6c4146ca5129eb6af5000e4ff
DIFF: https://github.com/llvm/llvm-project/commit/3b3a16548568f5b6c4146ca5129eb6af5000e4ff.diff
LOG: [MS] On x86_32, pass overaligned, non-copyable arguments indirectly
This updates the C++ ABI argument classification code to use the logic
from D72114, fixing an ABI incompatibility with MSVC.
Part of PR44395.
Differential Revision: https://reviews.llvm.org/D87923
Added:
Modified:
clang/lib/CodeGen/MicrosoftCXXABI.cpp
clang/test/CodeGenCXX/inalloca-overaligned.cpp
Removed:
################################################################################
diff --git a/clang/lib/CodeGen/MicrosoftCXXABI.cpp b/clang/lib/CodeGen/MicrosoftCXXABI.cpp
index 45c6cb6b2e0d..4f725793cb94 100644
--- a/clang/lib/CodeGen/MicrosoftCXXABI.cpp
+++ b/clang/lib/CodeGen/MicrosoftCXXABI.cpp
@@ -827,10 +827,14 @@ MicrosoftCXXABI::getRecordArgABI(const CXXRecordDecl *RD) const {
// copy ctor.
return !RD->canPassInRegisters() ? RAA_Indirect : RAA_Default;
- case llvm::Triple::x86:
- // All record arguments are passed in memory on x86. Decide whether to
- // construct the object directly in argument memory, or to construct the
- // argument elsewhere and copy the bytes during the call.
+ case llvm::Triple::x86: {
+ // If the argument has *required* alignment greater than four bytes, pass
+ // it indirectly. Prior to MSVC version 19.14, passing overaligned
+ // arguments was not supported and resulted in a compiler error. In 19.14
+ // and later versions, such arguments are now passed indirectly.
+ TypeInfo Info = getContext().getTypeInfo(RD->getTypeForDecl());
+ if (Info.AlignIsRequired && Info.Align > 4)
+ return RAA_Indirect;
// If C++ prohibits us from making a copy, construct the arguments directly
// into argument memory.
@@ -840,6 +844,7 @@ MicrosoftCXXABI::getRecordArgABI(const CXXRecordDecl *RD) const {
// Otherwise, construct the argument into a temporary and copy the bytes
// into the outgoing argument memory.
return RAA_Default;
+ }
case llvm::Triple::x86_64:
case llvm::Triple::aarch64:
diff --git a/clang/test/CodeGenCXX/inalloca-overaligned.cpp b/clang/test/CodeGenCXX/inalloca-overaligned.cpp
index 910f0d92895e..83eb4d1c61a4 100644
--- a/clang/test/CodeGenCXX/inalloca-overaligned.cpp
+++ b/clang/test/CodeGenCXX/inalloca-overaligned.cpp
@@ -4,11 +4,6 @@
// MSVC passes overaligned types indirectly since MSVC 2015. Make sure that
// works with inalloca.
-// FIXME: Pass non-trivial *and* overaligned types indirectly. Right now the C++
-// ABI rules say to use inalloca, and they take precedence, so it's not easy to
-// implement this.
-
-
struct NonTrivial {
NonTrivial();
NonTrivial(const NonTrivial &o);
@@ -20,6 +15,12 @@ struct __declspec(align(64)) OverAligned {
int buf[16];
};
+struct __declspec(align(8)) Both {
+ Both();
+ Both(const Both &o);
+ int x, y;
+};
+
extern int gvi32;
int receive_inalloca_overaligned(NonTrivial nt, OverAligned o) {
@@ -50,3 +51,37 @@ int pass_inalloca_overaligned() {
// CHECK: getelementptr inbounds <{ %struct.NonTrivial, %struct.OverAligned* }>, <{ %struct.NonTrivial, %struct.OverAligned* }>* %{{.*}}, i32 0, i32 1
// CHECK: store %struct.OverAligned* [[TMP]], %struct.OverAligned** %{{.*}}, align 4
// CHECK: call i32 @"?receive_inalloca_overaligned@@Y{{.*}}"(<{ %struct.NonTrivial, %struct.OverAligned* }>* inalloca %argmem)
+
+int receive_both(Both o) {
+ return o.x + o.y;
+}
+
+// CHECK-LABEL: define dso_local i32 @"?receive_both@@Y{{.*}}"
+// CHECK-SAME: (%struct.Both* %o)
+
+int pass_both() {
+ gvi32 = receive_both(Both());
+ return gvi32;
+}
+
+// CHECK-LABEL: define dso_local i32 @"?pass_both@@Y{{.*}}"
+// CHECK: [[TMP:%[^ ]*]] = alloca %struct.Both, align 8
+// CHECK: call x86_thiscallcc %struct.Both* @"??0Both@@QAE at XZ"(%struct.Both* [[TMP]])
+// CHECK: call i32 @"?receive_both@@Y{{.*}}"(%struct.Both* [[TMP]])
+
+int receive_inalloca_both(NonTrivial nt, Both o) {
+ return nt.x + o.x + o.y;
+}
+
+// CHECK-LABEL: define dso_local i32 @"?receive_inalloca_both@@Y{{.*}}"
+// CHECK-SAME: (<{ %struct.NonTrivial, %struct.Both* }>* inalloca %0)
+
+int pass_inalloca_both() {
+ gvi32 = receive_inalloca_both(NonTrivial(), Both());
+ return gvi32;
+}
+
+// CHECK-LABEL: define dso_local i32 @"?pass_inalloca_both@@Y{{.*}}"
+// CHECK: [[TMP:%[^ ]*]] = alloca %struct.Both, align 8
+// CHECK: call x86_thiscallcc %struct.Both* @"??0Both@@QAE at XZ"(%struct.Both* [[TMP]])
+// CHECK: call i32 @"?receive_inalloca_both@@Y{{.*}}"(<{ %struct.NonTrivial, %struct.Both* }>* inalloca %argmem)
More information about the cfe-commits
mailing list