<html><head><meta http-equiv="Content-Type" content="text/html; charset=us-ascii"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;" class="">Is it also C++ which will trigger the special case in <b class="">GetX86_64ByValArgumentPair</b>?<div class=""><br class=""></div><div class="">Here the comments state:</div><div class=""><br class=""></div><blockquote type="cite" class="">// In order to correctly satisfy the ABI, we need to the high part to start<br class="">// at offset 8.  If the high and low parts we inferred are both 4-byte types<br class="">// (e.g. i32 and i32) then the resultant struct type ({i32,i32}) won't have<br class="">// the second element at offset 8.  Check for this:<br class=""></blockquote><div class=""><span class=""><br class=""></span></div>Here I am suspecting that <b class="">struct Foo { int a; struct { } b; int c; }</b> will create this situation in C++ but not in C. Is that a correct assumption?<br class=""><br class=""><div class="">Christoffer<br class="">AEGIK / <a href="http://www.aegik.se" class="">www.aegik.se</a><br class=""></div><br class=""><blockquote type="cite" class="">Date: Fri, 13 Nov 2020 09:44:54 +0000<br class="">From: David Chisnall via cfe-dev <<a href="mailto:cfe-dev@lists.llvm.org" class="">cfe-dev@lists.llvm.org</a>><br class="">To: <a href="mailto:cfe-dev@lists.llvm.org" class="">cfe-dev@lists.llvm.org</a><br class="">Subject: Re: [cfe-dev] The x64 ABI lowering, direct pass of upper<br class=""><span class="Apple-tab-span" style="white-space:pre">       </span>8-bytes, can it happen?<br class="">Message-ID: <<a href="mailto:54e66ccf-58c7-263e-aa86-f5889ec1d272@cl.cam.ac.uk" class="">54e66ccf-58c7-263e-aa86-f5889ec1d272@cl.cam.ac.uk</a>><br class="">Content-Type: text/plain; charset=utf-8; format=flowed<br class=""><br class="">To give a little bit more context:<br class=""><br class="">C and C++ require that every field in a structure has a unique pointer <br class="">value (unless explicitly annotated in C++20) and C requires that a <br class="">pointer to the first field of an object is equivalent to a pointer to <br class="">the object.<br class=""><br class="">This combination of constraints first means that `s3_0` in this example <br class="">will report a size of 1, but that byte is purely padding.  When we lay <br class="">out `s3_1`, we have a first field that is one byte (purely of padding) <br class="">followed by 7 bytes of padding to correctly align `b`.  This adds up to <br class="">8 bytes of padding.<br class=""><br class="">No one would write that by hand deliberately, but you can encounter <br class="">things like this when you use std::conditional_t in a C++ class to do <br class="">something like:<br class=""><br class="">```c++<br class="">struct Placeholder {};<br class=""><br class="">template<typename T = void><br class="">struct SomeClass<br class="">{<br class=""><span class="Apple-tab-span" style="white-space:pre">       </span>std::conditional_t<std::is_same_v<T, void>, T, PlaceHolder> extra_data;<br class=""><span class="Apple-tab-span" style="white-space:pre">    </span>long unconditional_field;<br class=""><span class="Apple-tab-span" style="white-space:pre">      </span>...<br class="">};<br class="">```<br class=""><br class="">This pattern is quite useful for classes where you want to provide an <br class="">extension point for carrying some extra state but still support the case <br class="">where the instantiating code doesn't want to provide any.  Prior to <br class="">C++20 there was no standard way of ensuring that the placeholder didn't <br class="">take up any space.  If you happened to pick the first field of the <br class="">object for this field then you could end up with something equivalent to <br class="">Craig's example, where you have 8 bytes of padding at the start of <br class="">`SomeClass` before `unconditional_field`.<br class=""><br class="">In C++20, you can write this:<br class=""><br class="">```c++<br class="">struct Placeholder {};<br class=""><br class="">template<typename T = void><br class="">struct SomeClass<br class="">{<br class=""><span class="Apple-tab-span" style="white-space:pre">        </span>[[no_unique_address]]<br class=""><span class="Apple-tab-span" style="white-space:pre">  </span>std::conditional_t<std::is_same_v<T, void>, T, PlaceHolder> extra_data;<br class=""><span class="Apple-tab-span" style="white-space:pre">    </span>long unconditional_field;<br class=""><span class="Apple-tab-span" style="white-space:pre">      </span>...<br class="">};<br class="">```<br class=""><br class="">Now, if `extra_data` gets the type `PlaceHolder`, `(char*)&extra_data == <br class="">(char*)&unconditional_Field`.  That's typically what you want, because <br class="">any accesses to `extra_data` will be guarded by a `constexpr if` that <br class="">checks that `T` is not `void` and so the field will not actually be <br class="">referenced at all in instantiations where it is not used to carry extra <br class="">state.<br class=""><br class=""><br class="">David<br class=""><br class=""><br class="">On 12/11/2020 22:13, Craig Topper via cfe-dev wrote:<br class=""><blockquote type="cite" class="">Adding an assert(0) inside that if fires on this test case from <br class="">clang/test/CodeGenCXX/x86_64-arguments.cpp<br class=""><br class="">// PR5831<br class="">// CHECK-LABEL: define void @_Z2f34s3_1(i64 %x.coerce)<br class="">struct s3_0 {};<br class="">struct s3_1 { struct s3_0 a; long b; };<br class="">void f3(struct s3_1 x) {}<br class=""><br class="">~Craig<br class=""></blockquote></blockquote><br class=""></body></html>