[ms-cxxabi] Set proper SRet flags for most functions; also handle empty struct arguments correctly

John McCall rjmccall at apple.com
Tue Apr 16 16:13:18 PDT 2013

On Apr 15, 2013, at 11:41 AM, Timur Iskhodzhanov <timurrrr at google.com> wrote:
> 2013/4/13 John McCall <rjmccall at apple.com>:
>> On Apr 12, 2013, at 12:38 PM, Timur Iskhodzhanov <timurrrr at google.com> wrote:
>>> 2013/4/12 John McCall <rjmccall at apple.com>:
>>>> On Apr 12, 2013, at 8:44 AM, Timur Iskhodzhanov <timurrrr at google.com> wrote:
>>>>> 2013/4/9 John McCall <rjmccall at apple.com>
>>>>>>> If that looks OK - I assume I should do the same for other ABIInfos ?
>>>>>>> (I hope they are covered with tests well...)
>>>>> See the attached patch where I've applied the same approach to other ABIs.
>>>>>>>> /// How should we pass a particular record type as an argument?
>>>>>>>> enum RecordArgABI {
>>>>>>>> /// Pass it using the normal C aggregate rules for the ABI, potentially
>>>>>>>> /// introducing extra copies and passing some or all of it in registers.
>>>>>>>> RAA_DirectInRegisters,
>>>>>>>> /// Pass it on the stack using its defined layout.  The argument must be
>>>>>>>> /// evaluated directly into the correct stack position in the arguments area,
>>>>>>>> /// and the call machinery must not move it or introduce extra copies.
>>>>>>>> RAA_DirectInMemory,
>>>>>>>> /// Pass it as a pointer to temporary memory.
>>>>>>>> RAA_Indirect
>>>>>>>> };
>>>>>>> I'm not sure I can effectively use the first two cases right now and
>>>>>>> there should also be RAA_IndirectByval (see what I do for Microsoft
>>>>>>> ABI), so I've created a slightly simpler enum.
>>>>>> Despite how it looks in IR, "byval" is direct in memory.
>>>>>> Just to be clear, the Itanium ABI would use RAA_Indirect if the copy constructor
>>>>>> or destructor is non-trivial and RAA_DirectInRegisters otherwise,
>>>>> OK, after re-reading the RAA_DirectInRegisters comment a few times I
>>>>> now understand it's exactly the same as I proposed for RAA_Default.
>>>>> Not sure why I had not seen that before...
>>>> RAA_Default is fine for the name, actually.  Go with that.
>>> OK, done
>>>>> I now use the same enum you've suggested, but I also explicitly set
>>>>> the RAA_DirectInRegisters's value to 0
>>>>> so now I can write like this:
>>>>> if (RecordArgABI RAA = getRecordArgABI(...))
>>>>>  ABIArgInfo::getIndirect(0, RAA == CGCXXABI::RAA_DirectInMemory);
>>>>> // continue if RAA == RAA_DirectInRegisters.
>>>>> Is it OK to do so?
>>>>>> and the MS ABI would use RAA_DirectInMemory if there's any non-trivial
>>>>>> constructor or destructor and RAA_DirectInRegisters otherwise.
>>>>> I think you've meant just "MS ABI would use RAA_DirectInMemory.",
>>>>> otherwise my tests fail.
>>>> Are you saying that the MS ABI should just *always* use RAA_DirectInMemory?
>>> Yes, at least I haven't seen counter-examples so far, though I have
>>> like 20 different tests for passing structs as arguments that actually
>>> run the code and verify it works.
>>> (plus 30 more for returning structs)
>> If that's the C ABI rule, it should be handled by the C ABI, i.e. the normal
>> ABIInfo handling for the type.
> Sounds reasonable - aaand I've found a bad test in Clang!
> See test/CodeGen/x86_32-arguments-win32.c - these structs should be
> passed via stack.
>> But, for example, it seems like X64 does not
>> follow this rule, and will happily pass structs of size 1, 2, 4, or 8 in a register.
> Good catch!
> I've tested my patch on Win64 and yeah, the small structs are passed
> in registers unless they have non-trivial copy constructors.
> Interestingly, the presence of a destructor or operator= don't seem to
> move an argrument from a register to stack (weird).
> I didn't test the "class method" part of the test much on Win64 as the
> mangling is broken right now and it's very inconvenient to verify
> stuff there.
> I'll surely get back to this when we have Win64 more working in general.
> -> Fixed both things, please review.

+  bool isReturnTypeIndirect(const CXXRecordDecl *RD) const {
+    return !RD->isPOD();
+  }

Please add a comment here explaining the exact definition of POD
being used.  That's probably the C++03 definition, although it's probably
a good idea to test around the edges of that.

+static bool isRecordReturnIndirect(QualType T, CodeGen::CodeGenTypes &CGT) {
+static CGCXXABI::RecordArgABI getRecordArgABI(QualType T,
+                                              CodeGen::CodeGenTypes &CGT) {

Please make overloads of these that take a const RecordType* and then
take advantage of that in the places that currently do so, e.g.:

@@ -664,9 +662,7 @@ ABIArgInfo X86_32ABIInfo::classifyReturnType(QualType RetTy,
   if (isAggregateTypeForABI(RetTy)) {
     if (const RecordType *RT = RetTy->getAs<RecordType>()) {
-      // Structures with either a non-trivial destructor or a non-trivial
-      // copy constructor are always indirect.
-      if (hasNonTrivialDestructorOrCopyConstructor(RT))
+      if (isRecordReturnIndirect(RetTy, CGT))

^^^ this should use the RecordType overload.

   case X87:
   case ComplexX87:
-    if (isRecordWithNonTrivialDestructorOrCopyConstructor(Ty))
+    if (getRecordArgABI(Ty, CGT))

You should only increment neededInt here for CGCXXABI::RAA_Indirect.

@@ -3728,12 +3728,10 @@ ABIArgInfo AArch64ABIInfo::classifyGenericType(QualType Ty,
     return tryUseRegs(Ty, FreeIntRegs, RegsNeeded, /*IsInt=*/ true);
-  // Structures with either a non-trivial destructor or a non-trivial
-  // copy constructor are always indirect.
-  if (isRecordWithNonTrivialDestructorOrCopyConstructor(Ty)) {
+  if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, CGT)) {
     if (FreeIntRegs > 0)
-    return ABIArgInfo::getIndirect(0, /*ByVal=*/false);
+    return ABIArgInfo::getIndirect(0, RAA == CGCXXABI::RAA_DirectInMemory);

Same thing here;  only decrement FreeIntRegs for RAA_Indirect.

Otherwise, looks good.


More information about the cfe-commits mailing list