[cfe-dev] The x64 ABI lowering, direct pass of upper 8-bytes, can it happen?

David Chisnall via cfe-dev cfe-dev at lists.llvm.org
Fri Nov 13 01:44:54 PST 2020


To give a little bit more context:

C and C++ require that every field in a structure has a unique pointer 
value (unless explicitly annotated in C++20) and C requires that a 
pointer to the first field of an object is equivalent to a pointer to 
the object.

This combination of constraints first means that `s3_0` in this example 
will report a size of 1, but that byte is purely padding.  When we lay 
out `s3_1`, we have a first field that is one byte (purely of padding) 
followed by 7 bytes of padding to correctly align `b`.  This adds up to 
8 bytes of padding.

No one would write that by hand deliberately, but you can encounter 
things like this when you use std::conditional_t in a C++ class to do 
something like:

```c++
struct Placeholder {};

template<typename T = void>
struct SomeClass
{
	std::conditional_t<std::is_same_v<T, void>, T, PlaceHolder> extra_data;
	long unconditional_field;
	...
};
```

This pattern is quite useful for classes where you want to provide an 
extension point for carrying some extra state but still support the case 
where the instantiating code doesn't want to provide any.  Prior to 
C++20 there was no standard way of ensuring that the placeholder didn't 
take up any space.  If you happened to pick the first field of the 
object for this field then you could end up with something equivalent to 
Craig's example, where you have 8 bytes of padding at the start of 
`SomeClass` before `unconditional_field`.

In C++20, you can write this:

```c++
struct Placeholder {};

template<typename T = void>
struct SomeClass
{
	[[no_unique_address]]
	std::conditional_t<std::is_same_v<T, void>, T, PlaceHolder> extra_data;
	long unconditional_field;
	...
};
```

Now, if `extra_data` gets the type `PlaceHolder`, `(char*)&extra_data == 
(char*)&unconditional_Field`.  That's typically what you want, because 
any accesses to `extra_data` will be guarded by a `constexpr if` that 
checks that `T` is not `void` and so the field will not actually be 
referenced at all in instantiations where it is not used to carry extra 
state.


David


On 12/11/2020 22:13, Craig Topper via cfe-dev wrote:
> Adding an assert(0) inside that if fires on this test case from 
> clang/test/CodeGenCXX/x86_64-arguments.cpp
> 
> // PR5831
> // CHECK-LABEL: define void @_Z2f34s3_1(i64 %x.coerce)
> struct s3_0 {};
> struct s3_1 { struct s3_0 a; long b; };
> void f3(struct s3_1 x) {}
> 
> ~Craig
> 
> 
> On Thu, Nov 12, 2020 at 1:06 PM Christoffer Lernö via cfe-dev 
> <cfe-dev at lists.llvm.org <mailto:cfe-dev at lists.llvm.org>> wrote:
> 
>     I apologize for spamming with so many questions, but this really
>     confusing me.
> 
>     In X86_64ABIInfo::classifyArgumentType we have this code:
> 
>      >   case Integer:
>      >     ++neededInt;
>      >     // Pick an 8-byte type based on the preferred type.
>      >     HighPart = GetINTEGERTypeAtOffset(CGT.ConvertType(Ty), 8, Ty, 8);
>      >
>      >     if (Lo == NoClass)  // Pass HighPart at offset 8 in memory.
>      >       return ABIArgInfo::getDirect(HighPart, 8);
>      >     break;
> 
>     Zooming in on the ”Lo == NoClass”. As far as I can tell this can
>     only happen in the case where a struct has padding in front, and the
>     first real integer parameter is actually 64 bits in.
> 
>     I admit I have no idea how to construct such a type in C to trigger
>     this. Since Clang has a non-trivial amount of code to handle this I
>     am wondering what I’m missing. (I’ve looked through the x86 test
>     cases as well but was unable to find a test case for this particular
>     situation. I might have overlooked something though)
> 
> 
>     /Christoffer
>     _______________________________________________
>     cfe-dev mailing list
>     cfe-dev at lists.llvm.org <mailto:cfe-dev at lists.llvm.org>
>     https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
>     <https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev>
> 
> 
> _______________________________________________
> cfe-dev mailing list
> cfe-dev at lists.llvm.org
> https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
> 


More information about the cfe-dev mailing list