diff --git a/clang/lib/CodeGen/MicrosoftCXXABI.cpp b/clang/lib/CodeGen/MicrosoftCXXABI.cpp --- a/clang/lib/CodeGen/MicrosoftCXXABI.cpp +++ b/clang/lib/CodeGen/MicrosoftCXXABI.cpp @@ -821,18 +821,19 @@ 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. - - // If C++ prohibits us from making a copy, construct the arguments directly - // into argument memory. - if (!RD->canPassInRegisters()) - return RAA_DirectInMemory; - - // Otherwise, construct the argument into a temporary and copy the bytes - // into the outgoing argument memory. - return RAA_Default; + // If C++ allows us to copy the struct bytes, use the normal C convention + // rules. + if (RD->canPassInRegisters()) + return RAA_Default; + + // If the type has a required alignment (alignas, __declspec(align)), MSVC + // passes it indirectly. + if (getContext().isAlignmentRequired(getContext().getTypeDeclType(RD))) + return RAA_Indirect; + + // In the worst case, the argument must be constructed directly into the + // outgoing argument memory slots. + return RAA_DirectInMemory; 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 --- a/clang/test/CodeGenCXX/inalloca-overaligned.cpp +++ b/clang/test/CodeGenCXX/inalloca-overaligned.cpp @@ -4,10 +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(); @@ -50,3 +46,27 @@ // 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) + +struct __declspec(align(64)) Both { + Both(); + Both(const Both &o); + int x; +}; + +int receive_both1(Both b) { + return b.x; +} +// CHECK-LABEL: define dso_local i32 @"?receive_both1@@Y{{.*}}" +// CHECK-SAME: (%struct.Both* %b) + +int receive_both2(Both x, Both y) { + return x.x + y.x; +} +// CHECK-LABEL: define dso_local i32 @"?receive_both2@@Y{{.*}}" +// CHECK-SAME: (%struct.Both* %x, %struct.Both* %y) + +int receive_nt_and_both(NonTrivial x, Both y) { + return x.x + y.x; +} +// CHECK-LABEL: define dso_local i32 @"?receive_nt_and_both@@Y{{.*}}" +// CHECK-SAME: (<{ %struct.NonTrivial, %struct.Both* }>* inalloca %0)