Bug 14480 – dmd 2.067 x64 release codegen

Status
RESOLVED
Resolution
FIXED
Severity
regression
Priority
P1
Component
dmd
Product
D
Version
D2
Platform
x86_64
OS
Windows
Creation time
2015-04-22T10:22:00Z
Last change time
2015-06-27T07:38:10Z
Keywords
wrong-code
Assigned to
nobody
Creator
fengli
See also
https://issues.dlang.org/show_bug.cgi?id=14510

Attachments

IDFilenameSummaryContent-TypeSize
1515x64.pngbad renderingimage/png921630

Comments

Comment #0 by fengli — 2015-04-22T10:22:24Z
Created attachment 1515 bad rendering Something very weird happened to my 2D vector graphics library since upgrading to 2.067. I'm not 100% sure but it looks more like a codegen issue than a program error. This is because both 32 bit debug and release builds are good, 64 bit debug build is good, but 64 bit release build is broken. good rendering https://onedrive.live.com/redir?resid=FDD337136ADE2BCF!11348&authkey=!AHIhJQXNT77Ewg8&v=3&ithint=photo%2cpng bad rendering https://onedrive.live.com/redir?resid=FDD337136ADE2BCF!11349&authkey=!ALVOTsEIN6qFvJs&v=3&ithint=photo%2cpng I tracked down this issue to the bezier curve division routine: void bezier(T)(in T p1, in T p2, in T p3, in T p4) { auto p12 = (p1 + p2) / 2; auto p23 = (p2 + p3) / 2; auto p34 = (p3 + p4) / 2; auto p123 = (p12 + p23) / 2; auto p234 = (p23 + p34) / 2; auto p1234 = (p123 + p234) / 2; auto d = p4-p1; auto d2 = fabs(((p2.x - p4.x) * d.y - (p2.y - p4.y) * d.x)); auto d3 = fabs(((p3.x - p4.x) * d.y - (p3.y - p4.y) * d.x)); if((d2 + d3)*(d2 + d3) < 0.25 * dot(d, d)) { m_appender ~= [PathVertex(p1234, VertexAttr.LineTo)]; return; } bezier(p1, p12, p123, p1234); bezier(p1234, p234, p34, p4); } It's pretty straightforward, if the curve is flat enough then return, otherwise divide the curve into 2 shorter curves. Below is a trace of the recursive division of one of the curves: good: [563.022, 319.849] [534.772, 266.534] [551.44, 365.862] [551.44, 365.862] [563.022, 319.849] [548.897, 293.192] [546.001, 304.695] [546.637, 322.862] [563.022, 319.849] [555.96, 306.52] [551.704, 302.732] [549.294, 304.546] [563.022, 319.849] [559.491, 313.185] [556.661, 308.905] [554.414, 306.519] [563.022, 319.849] [561.257, 316.517] [559.666, 313.781] [558.237, 311.58] [558.237, 311.58] [556.807, 309.379] [555.538, 307.712] [554.414, 306.519] ... bad: [563.022, 319.849] [534.772, 266.534] [551.44, 365.862] [551.44, 365.862] [563.022, 319.849] [548.897, 293.192] [546.001, 304.695] [546.637, 322.862] [563.022, 319.849] [555.96, 306.52] [551.704, 302.732] [549.294, 304.546] [563.022, 319.849] [559.491, 313.185] [556.661, 308.905] [554.414, 306.519] [563.022, 319.849] [561.257, 316.517] [559.666, 313.781] [558.237, 311.58] [558.237, 311.58] [556.807, 309.379] [555.538, 307.712] [9.0195e-318, 9.02709e-318] <-- WTF? ... As you can see the last point becomes a very small number. Consider this is the 'p4' argument which is not calculated but directly passed down, how can this be? If you want to see the full code, here it is https://github.com/finalpatch/dagger And the broken program is demo/svg
Comment #1 by fengli — 2015-04-22T11:59:48Z
still broken in 2.067.1 b1
Comment #2 by fengli — 2015-04-22T23:59:07Z
On OSX with 2.067 this does not happen.
Comment #3 by r9shackleford — 2015-04-23T02:59:50Z
I'm unable to reproduce this on Linux, dmd 2.067. Windows only issue?
Comment #4 by fengli — 2015-04-23T04:34:57Z
It's probably a windows only issue (in fact windows 64 bit release mode only).
Comment #5 by yebblies — 2015-04-23T10:39:44Z
A reduced test case would be helpful
Comment #6 by fengli — 2015-04-24T13:03:27Z
Here's a reduced test case // compile on windows with "dmd -m64 -O test.d" => BAD import std.stdio; import std.array; import std.math; import std.algorithm; import std.range; struct Vector(T, alias N) { enum size = N; alias T ValueType; alias v this; this (T...) (T args) { static if(args.length == 1) v[] = args[0]; else static if(args.length == N) v[] = [args]; else static assert("wrong number of arguments"); } Vector opUnary(string op)() const if( op =="-" ) { mixin("return Vector(" ~ Unroll!("v[%] * (-1)", N, ",") ~ ");"); } Vector opBinary(string op)(auto ref in T rhs) const if( op == "+" || op =="-" || op=="*" || op=="/" ) { mixin("return Vector(" ~ Unroll!("v[%]"~op~"rhs", N, ",") ~ ");"); } Vector opBinary(string op)(auto ref in Vector rhs) const if( op == "+" || op =="-" || op=="*" || op=="/" ) { mixin("return Vector(" ~ Unroll!("v[%]"~op~"rhs.v[%]", N, ",") ~ ");"); } ref Vector opOpAssign(string op)(auto ref in Vector rhs) if( op == "+" || op =="-" || op=="*" || op=="/" ) { mixin("v[]"~op~"=rhs.v[];"); return this; } static if (N >= 1) { T x() const { return v[0]; } ref T x() { return v[0]; } } static if (N >= 2) { T y() const { return v[1]; } ref T y() { return v[1]; } } static if (N >= 3) { T z() const { return v[2]; } ref T z() { return v[2]; } } alias v this; T[N] v; } protected template Unroll(alias CODE, alias N, alias SEP="") { import std.string; enum t = replace(CODE, "%", "%1$d"); enum Unroll = iota(N).map!(i => format(t, i)).join(SEP); } V.ValueType dot(V, V2)(auto ref in V v1, auto ref in V2 v2) if( is(V.ValueType == V2.ValueType) ) { return mixin(Unroll!("v1[%]*v2[%]", V.size, "+")); } void bezier(T)(in T p1, in T p2, in T p3, in T p4, int indent) { writefln("%s%s %s %s %s", replicate(" ", indent), p1, p2, p3, p4); auto p12 = (p1 + p2) / 2; auto p23 = (p2 + p3) / 2; auto p34 = (p3 + p4) / 2; auto p123 = (p12 + p23) / 2; auto p234 = (p23 + p34) / 2; auto p1234 = (p123 + p234) / 2; auto d = p4 - p1; auto d2 = fabs(((p2.x - p4.x) * d.y - (p2.y - p4.y) * d.x)); auto d3 = fabs(((p3.x - p4.x) * d.y - (p3.y - p4.y) * d.x)); if((d2 + d3)*(d2 + d3) < 0.25 * dot(d, d)) { return; } bezier(p1, p12, p123, p1234, indent+2); bezier(p1234, p234, p34, p4, indent+2); } int main(string[] args) { alias Vector!(double, 2) VEC; auto p1 = VEC(563.022, 319.849); auto p2 = VEC(534.772, 266.534); auto p3 = VEC(551.44, 365.862); auto p4 = VEC(551.44, 365.862); bezier(p1,p2,p3,p4,0); return 0; }
Comment #7 by dlang-bugzilla — 2015-04-27T03:03:20Z
(In reply to fengli from comment #6) > Here's a reduced test case > > // compile on windows with "dmd -m64 -O test.d" => BAD This program will give different output every time it's run, regardless of the compiler I tested.
Comment #8 by fengli — 2015-04-27T03:40:10Z
Hi Vladimir, Are you saying the program producing different output even without -O -m64? In my tests this function produces identical and correct output on windows without -O -m64 and on OSX with any arguments. The expected output is [563.022, 319.849] [534.772, 266.534] [551.44, 365.862] [551.44, 365.862] [563.022, 319.849] [548.897, 293.192] [546.002, 304.695] [546.637, 322.862] [563.022, 319.849] [555.96, 306.52] [551.704, 302.732] [549.294, 304.546] [563.022, 319.849] [559.491, 313.185] [556.661, 308.905] [554.413, 306.519] [563.022, 319.849] [561.256, 316.517] [559.666, 313.781] [558.236, 311.58] [558.236, 311.58] [556.807, 309.379] [555.537, 307.712] [554.413, 306.519] [554.413, 306.519] [552.166, 304.132] [550.499, 303.639] [549.294, 304.546] [554.413, 306.519] [553.29, 305.326] [552.311, 304.606] [551.463, 304.297] [554.413, 306.519] [553.852, 305.922] [553.326, 305.444] [552.835, 305.076] [552.835, 305.076] [552.344, 304.709] [551.887, 304.452] [551.463, 304.297] [551.463, 304.297] [550.615, 303.989] [549.897, 304.093] [549.294, 304.546] [551.463, 304.297] [551.039, 304.143] [550.647, 304.092] [550.286, 304.136] [550.286, 304.136] [549.926, 304.18] [549.596, 304.319] [549.294, 304.546] [549.294, 304.546] [546.884, 306.361] [546.319, 313.779] [546.637, 322.862] [549.294, 304.546] [548.089, 305.454] [547.346, 307.762] [546.943, 310.978] [549.294, 304.546] [548.692, 305] [548.205, 305.804] [547.818, 306.896] [549.294, 304.546] [548.993, 304.773] [548.721, 305.087] [548.475, 305.482] [548.475, 305.482] [548.23, 305.876] [548.011, 306.35] [547.818, 306.896] [547.818, 306.896] [547.431, 307.989] [547.144, 309.37] [546.943, 310.978] [546.943, 310.978] [546.54, 314.195] [546.478, 318.32] [546.637, 322.862] [546.943, 310.978] [546.741, 312.587] [546.625, 314.422] [546.579, 316.423] [546.579, 316.423] [546.533, 318.425] [546.558, 320.591] [546.637, 322.862] [546.637, 322.862] [547.273, 341.03] [551.44, 365.862] [551.44, 365.862] [546.637, 322.862] [546.955, 331.946] [548.156, 342.696] [549.277, 351.175] [546.637, 322.862] [546.796, 327.404] [547.176, 332.363] [547.656, 337.246] [547.656, 337.246] [548.136, 342.128] [548.716, 346.936] [549.277, 351.175] [549.277, 351.175] [550.398, 359.654] [551.44, 365.862] [551.44, 365.862]
Comment #9 by dlang-bugzilla — 2015-04-27T03:40:17Z
(In reply to Vladimir Panteleev from comment #7) > This program will give different output every time it's run, regardless of > the compiler I tested. I reduced this behavior, but did not find this to be a regression, so I filed it as a new bug: https://issues.dlang.org/show_bug.cgi?id=14510
Comment #10 by dlang-bugzilla — 2015-04-27T03:56:00Z
(In reply to fengli from comment #8) > Hi Vladimir, > > Are you saying the program producing different output even without -O -m64? No, I meant with -O -m64.
Comment #11 by aliloko — 2015-06-24T16:39:43Z
I've also encountered this bug many times already, also some code which does Bezier curve recursive split! Lost many hours trying to remove/reduce it.
Comment #12 by aliloko — 2015-06-24T16:45:00Z
Comment #13 by code — 2015-06-26T06:59:49Z
(In reply to ponce from comment #12) > For more images: https://github.com/p0nce/dplug/issues/35 Images don't really help. From similar issues with https://github.com/MartinNowak/graphics I'd guess that you either hit a codegen bug trashing a register (often during argument passing) or reference dead memory. Have you tried gdc/ldc? Have you tried to use dustmite?
Comment #14 by fengli — 2015-06-26T07:54:19Z
(In reply to Martin Nowak from comment #13) > (In reply to ponce from comment #12) > > For more images: https://github.com/p0nce/dplug/issues/35 > > Images don't really help. > From similar issues with https://github.com/MartinNowak/graphics I'd guess > that you either hit a codegen bug trashing a register (often during argument > passing) or reference dead memory. > > Have you tried gdc/ldc? > Have you tried to use dustmite? There is no way to try GDC/LDC because this is a 64-bit Windows only bug. GDC/LDC do not have 64-bit Windows support at this moment.
Comment #15 by aliloko — 2015-06-26T08:37:06Z
> Have you tried gdc/ldc? I'm sorry I've tried it all and this is way beyond me. GDC doesn't build my code on Windows (bug reported). LDC doesn't build my code either (bugs reported). I've tried to build LDC because I was told to, and LLVM itself doesn't build here despite following the instructions. > Have you tried to use dust mite? I also haven't tried to reduce it more because this bug has already been reduced by Vladimir. I guess isolating the bezier subdivision function would work though. It's not easy because the program I work on isn't standalone. I'm pretty hopeful the reduced case by Vladimir will fix other cases here.
Comment #16 by bugzilla — 2015-06-27T04:41:54Z
Comment #17 by k.hara.pg — 2015-06-27T07:26:26Z
(In reply to Walter Bright from comment #16) > This may fix it: > > https://github.com/D-Programming-Language/dmd/pull/4778 On win64, I confirmed that the result of reduced case in comment #6 is fixed. The fix will be released in 2.068-beta2. If the issue still happens in the original project, please reopen this.
Comment #18 by bugzilla — 2015-06-27T07:38:10Z
Thanks, everyone, for your help with this.