New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix Issue 22082 - Static float array comparison now lowered to __equals #13320
Conversation
Thanks for your pull request and interest in making D better, @ryuukk! We are looking forward to reviewing it, and you should be hearing from a maintainer soon.
Please see CONTRIBUTING.md for more information. If you have addressed all reviews or aren't sure how to proceed, don't hesitate to ping us with a simple comment. Bugzilla references
Testing this PR locallyIf you don't have a local development environment setup, you can use Digger to test this PR: dub run digger -- build "master + dmd#13320" |
Solve this: ```D struct VertexB { float[2] pos; } struct Hold { VertexB v; } extern(C) int main() { Hold[1] h_a; Hold[1] h_b; assert(h_a != h_b); }
test/compilable/b22082.d
Outdated
|
||
struct VertexA | ||
{ | ||
float pos; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All floating point types should be tested, not only float
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i tried to update the test but i'm getting the following:
test.obj : error LNK2019: unresolved external symbol _memset80 referenced in function _D4test__TQiTeZQnFNaNbNiNfZv
test.exe : fatal error LNK1120: 1 unresolved externals
Error: linker exited with status 1120
updated test:
// PERMUTE_ARGS:
// REQUIRED_ARGS: -betterC
struct VertexA(T)
{
T pos;
}
struct VertexB(T)
{
T[2] pos;
}
void test(T)()
{
T f_a;
T f_b;
assert(f_a != f_b);
f_a = 0;
assert(f_a != f_b);
f_b = 0;
assert(f_a == f_b);
VertexA!T a_a;
VertexA!T a_b;
assert(a_a != a_b);
a_a.pos = 0;
assert(a_a != a_b);
a_b.pos = 0;
assert(a_a == a_b);
VertexB!T b_a;
VertexB!T b_b;
assert(b_a != b_b);
b_a.pos = 0;
assert(b_a != b_b);
b_b.pos = 0;
assert(b_a == b_b);
}
extern(C) int main()
{
test!(float)();
test!(double)();
test!(real)();
return 0;
}
@@ -11486,6 +11486,10 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor | |||
{ | |||
return false; | |||
} | |||
|
|||
if (t1n.isfloating() && t2n.isfloating()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I find this a bit arbitrary... shouldn't there be a test whether it's a scalar or not? Why is there no test needed here for int
for example?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
because for integral types it already get optimized to use mem_cmp
for floating points it can't, and fallsback to using TypeInfo, wich is not available in betterC / wasm
Line 1865 in 831d407
if ((telement.isintegral() || telement.ty == Tvoid) && telement.ty == telement2.ty) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added the definition of the missing symbol, i suspect it's simply because betterC doesn't link with the runtime, so we need to add it ourselves, ideally this shouldn't be needed, but i don't know where to put it in dmd?
test/compilable/b22082.d
Outdated
|
||
struct VertexA | ||
{ | ||
float pos; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i tried to update the test but i'm getting the following:
test.obj : error LNK2019: unresolved external symbol _memset80 referenced in function _D4test__TQiTeZQnFNaNbNiNfZv
test.exe : fatal error LNK1120: 1 unresolved externals
Error: linker exited with status 1120
updated test:
// PERMUTE_ARGS:
// REQUIRED_ARGS: -betterC
struct VertexA(T)
{
T pos;
}
struct VertexB(T)
{
T[2] pos;
}
void test(T)()
{
T f_a;
T f_b;
assert(f_a != f_b);
f_a = 0;
assert(f_a != f_b);
f_b = 0;
assert(f_a == f_b);
VertexA!T a_a;
VertexA!T a_b;
assert(a_a != a_b);
a_a.pos = 0;
assert(a_a != a_b);
a_b.pos = 0;
assert(a_a == a_b);
VertexB!T b_a;
VertexB!T b_b;
assert(b_a != b_b);
b_a.pos = 0;
assert(b_a != b_b);
b_b.pos = 0;
assert(b_a == b_b);
}
extern(C) int main()
{
test!(float)();
test!(double)();
test!(real)();
return 0;
}
@@ -11542,7 +11546,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor | |||
} | |||
|
|||
// lower some array comparisons to object.__equals(e1, e2) | |||
if (needsArrayLowering || (t1.ty == Tarray && t2.ty == Tarray)) | |||
if (needsArrayLowering || (t1.ty == Tarray && t2.ty == Tarray) || (t1.ty == Tsarray && t2.ty == Tsarray)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is most likely too much, lowering all equality comparisons of static array pairs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's because this test otherwise doesn't work:
struct VertexB
{
float[2] pos;
}
struct Hold
{
VertexB v;
}
extern(C) int main()
{
Hold[1] h_a;
Hold[1] h_b;
assert(h_a != h_b);
}
IIRC, I've at point tried to lower all array equality comparisons to the template, but that didn't work due to string special cases. In general, https://github.com/dlang/druntime/blob/master/src/core/internal/array/equality.d should be able to handle all array pairs, and use memcmp if possible. For static array pairs, it would probably add a superfluous length check, but that's probably negligible, incl. the static-array-to-slice promotion. Currently, the lowering is avoided in some cases, especially for matching integral elements with memcmp-ability, and the equality expression forwarded to the glue layer, where each compiler has its own checks for memcmp-ability and tries to do that, otherwise falling back to the slow, TypeInfo-based |
Well all i wanted was to make static float array to work.. that's blocking my project right now.. and i have no idea what is good/bad :p So what should be done? i can't really give up on static float arrays |
I think the memcmp-ability should be checked in the frontend, and only such equality expressions be forwarded to the glue layer, the other ones lowered to the Edit: Pinging @ibuclaw. |
Seems reasonable to me. |
Is that an easy change to do? should this PR be closed? since it's blocking me, i would like to speed up the fix, maybe i can do it if you can point me to the right direction (if the change is relatively easy to do) |
@ryuukk I would say it is not simple, but it's not extremely complicated also. Here are some pointers:
You already know where in the frontend the checks for array equality are performed ( What needs to be done is to add the proper checks in [1] https://github.com/dlang/dmd/blob/master/src/dmd/e2ir.d#L1860 |
No description provided.