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 @@ -827,10 +827,14 @@ // 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 @@ // 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 --- 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 @@ 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 @@ // 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@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@XZ"(%struct.Both* [[TMP]]) +// CHECK: call i32 @"?receive_inalloca_both@@Y{{.*}}"(<{ %struct.NonTrivial, %struct.Both* }>* inalloca %argmem)