[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