<div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">On 2 November 2013 20:07, Johannes Pfau <span dir="ltr"><<a href="mailto:nospam@example.com" target="_blank">nospam@example.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
I think I finally found the root cause for one of the remaining ARM<br>
bugs (the codegen bug which only appears on -O2 or higher).<br>
<br>
What happened in the test case was that the gcc backend illegally moved<br>
a read to a memory location before the write. It turns out that GCC<br>
assumed that the read and write locations were in different alias sets<br>
and therefore could not possibly reference the same memory location. One<br>
alias set was for 'ubyte[]' and one for 'char[]'.<br>
<br>
The code that triggers this issue is in std.algorithm.find:<br>
--------<br>
R1 find(...)(R1 haystack, R2 needle) if (/* are strings*/)<br>
{<br>
    return cast(char[]) .find!(ubyte[], ubyte[])<br>
        (cast(ubyte[]) haystack, cast(ubyte[])needle);<br>
}<br>
--------<br>
(Real code:<br>
<a href="https://github.com/D-Programming-GDC/GDC/blob/master/libphobos/src/std/algorithm.d#L3555" target="_blank">https://github.com/D-Programming-GDC/GDC/blob/master/libphobos/src/std/algorithm.d#L3555</a><br>
)<br>
<br>
The generic emitted by gdc:<br>
--------<br>
return <retval> = *(struct  *) &find (*(struct  *) &haystack, *(struct<br>
*) &needle);<br>
--------<br>
<br>
Or in the raw form:<br>
@44 = ubyte[]<br>
@11 = string<br>
--------<br>
@11     record_type      name: @17      size: @18      algn: 32<br>
                         tag : struct   flds: @19<br>
@31     pointer_type     size: @15      algn: 32       ptd : @11<br>
@40     pointer_type     size: @15      algn: 32       ptd : @44<br>
@41     call_expr        type: @44      fn  : @45      0   : @46<br>
                         1   : @47<br>
@44     record_type      name: @49      size: @18      algn:<br>
                         tag : struct   flds: @50<br>
@46     indirect_ref     type: @44      op 0: @53<br>
@47     indirect_ref     type: @44      op 0: @54<br>
@53     nop_expr         type: @40      op 0: @58<br>
@54     nop_expr         type: @40      op 0: @59<br>
@58     addr_expr        type: @31      op 0: @30<br>
@59     addr_expr        type: @31      op 0: @61<br>
--------<br>
<br>
Here it's easy to see that we essentially generate this code:<br>
*(cast(ubyte[]*)(&haystack))<br>
and this is AFAIK a violation of the aliasing rules.<br>
<br>
This problem is not observed at -O1 as the function call generates a<br>
new stackframe and we therefore have two distinct memory locations. But<br>
with -O2 inlining removes this copy and we now have variables<br>
referencing the same memory location with type ubyte[] and char[].<br>
<br>
I can not provide a reduced testcase as the smallest changes in<br>
compiler codegen (gcc version, gdc commit) or the test case can hide<br>
this issue. It's always reproducible with test15.d in the test suite.<br>
(In older gdc versions the test case does not segfault but it produces<br>
wrong output at -O2. This can be a very subtle difference)<br>
<br>
But here's a working code snippet which illustrates the generic<br>
generated by GDC:<br>
<br>
-----------------<br>
void main()<br>
{<br>
        char[] in1 = "Test".dup;<br>
        char[] in2 = "Test2".dup;<br>
<br>
        char[] result = cast(char[])find(cast(ubyte[])in1,<br>
            cast(ubyte[])in2);<br>
}<br>
<br>
ubyte[] find(ubyte[] a, ubyte[] b)<br>
{<br>
    return a;<br>
}<br>
-----------------<br>
<br>
<br>
So the important question here: Is this a bug in GDC codegen or is the<br>
code in std.algorithm invalid? According to<br>
<a href="http://dlang.org/expression.html" target="_blank">http://dlang.org/expression.html</a><br>
"The cast is done as a type paint" so this could indeed be interpreted<br>
as a user mistake. But OTOH that page also talks about a runtime check<br>
of the array .lengths which is clearly missing here.<br>
<br>
I'm also wondering if that runtime check can actually fix this<br>
aliasing issue or if it can come up again if the runtime check itself<br>
is inlined?<br>
</blockquote></div><br><br></div><div class="gmail_extra">I guess D does not have any aliasing rules.  Question: does this occur when you pass -fno-strict-aliasing?<br><br></div><div class="gmail_extra">By default, GDC defines -fstrict-aliasing (which is also enabled by default in -O2 in GCC), which is nice to have, but if it's proving to be non-trivial, we can always disallow the optimisation being done in the middle-end.  See the LANG_HOOKS_GET_ALIAS_SET langhook - last time I checked, returning 0 disables aliasing rules from taking effect.<br>
</div><div class="gmail_extra"><br></div><div class="gmail_extra">Regards.<br></div><div class="gmail_extra">-- <br>Iain Buclaw<br><br>*(p < e ? p++ : p) = (c & 0x0f) + '0';
</div></div>