<div dir="ltr">In the case of the following enum, result of coersion depends on the order of union elements, which IMHO, is counter intuitive.<div><div><br></div><div>typedef union {</div><div><span class="" style="white-space:pre">    </span>void* INT[2];</div><div><span class="" style="white-space:pre">      </span>long double X87_X87UP;</div><div><span class="" style="white-space:pre">     </span>double SSE;</div><div>} InReg;</div><div><br></div><div>InReg in_reg(InReg x) { return x; }</div><div><br></div><div>typedef union {</div><div><span class="" style="white-space:pre">       </span>long double X87_X87UP;</div><div><span class="" style="white-space:pre">     </span>double SSE;</div><div><span class="" style="white-space:pre">        </span>void* INT[2];</div><div>} InMem;</div><div><br></div><div>InMem in_mem(InMem x) { return x; }</div></div><div><br></div><div>In IR these functions have the following signatures and are binary incompatible:</div><div><div>define { i64, i64 } @in_reg(i64 %x.coerce0, i64 %x.coerce1)</div><div>define void @in_mem(%union.InMem* noalias sret %agg.result, %union.InMem* byval align 16 %x)</div></div><div><br></div><div>This does not conflict with ABI specification, because the later does not specify order in which union elements should be visited.</div><div><br></div><div>Do you think this is a real problem that is worth fixing in the ABI?</div><div><br></div><div>It is possible to fix this in the ABI by:</div><div>a) formalizing order in which fields are visited</div><div>b) changing merging and post-processing rules to have a consistent result</div><div><br></div><div>The first option is backward-compatible, the second allows to achieve better performance of argument passing (I'm not expert in this field, but I assume there are some performance concerns behind the current argument classification rules).</div><div><br></div><div>Below is proposed algorithm to perform merging with consistent result:</div><div><br></div><div>To end up with { MEMORY, MEMORY } in the end:</div><div><ul><li>Add two more classes NO_SSE and NO_X87<br></li><li>Merging INT with X87, X87_UP, COMPLEX_X87 results in NO_SSE<br></li><li>Merging INT with SSE or SSEUP results in NO_X87<br></li><li>Merging NO_SSE with SSE results in MEMORY<br></li><li>Merging NO_X87 with X87, X87_UP or COMPLEX_X87 results in MEMORY<br></li><li>Merging NO_SSE with NO_X87 cannot occur, because these classes may appear only as a result of merging - no field may have a class of NO_???<br></li><li>During post-merge phase NO_SSE and NO_X87 are replaced with INT</li></ul></div><div>To end up with { INT, INT } in the end:<br></div><div><ul><li>Add one more class MAYBE_MEMORY</li><li>Merging X87/X87_UP/COMPLEX_X87 with SSE/SSEUP results in MAYBE_MEMORY</li><li>Merging MAYBE_MEMORY with INT results in INT</li><li>During post-merge MAYBE_MEMORY is replaced with MEMORY</li></ul>Thanks,</div><div>Nickolas</div></div>