fix issue 18315 - wrong code for int.min > 0#7841
Conversation
|
Thanks for your pull request, @aG0aep6G! We are looking forward to reviewing it, and you should be hearing from a maintainer soon. Some tips to help speed things up:
Bear in mind that large or tricky changes may require multiple rounds of review and revision. Please see CONTRIBUTING.md for more information. Bugzilla references
|
|
I think a benchmark showing effect on performance would be nice to know how much this affects dmd. |
For this D code: bool f(int i) { return i > 0; }dmd 2.078.0 generates this: 0: push rbp
1: mov rbp,rsp
4: mov rax,rdi
7: neg eax
9: shr eax,0x1f
c: pop rbp
d: retwith this PR: 0: push rbp
1: mov rbp,rsp
4: sub rsp,0x10
8: mov DWORD PTR [rbp-0x8],edi
b: cmp DWORD PTR [rbp-0x8],0x0
f: setg al
12: mov rsp,rbp
15: pop rbp
16: retLDC: 0: test edi,edi
2: setg al
5: ret(All with I'm not sure if a fair comparison includes the prologue/epilogue in this case. Anyway, here are some times with function calls: # Compile old version.
echo 'bool f_old(int i) { return i > 0; }' | dmd2.078 - -c -ofold.o -O -betterC
# Compile new version.
echo 'bool f_new(int i) { return i > 0; }' | dmd2.git - -c -ofnew.o -O -betterC
# Try LDC too, for reference.
echo 'bool f_ldc(int i) { return i > 0; }' | ldc2 - -c -ofldc.o -O -betterC
# Compile timing code, link, run.
dmd -O old.o new.o ldc.o -run - <<EOF
bool f_old(int);
bool f_new(int);
bool f_ldc(int);
void main()
{
import std.conv;
import std.datetime;
import std.datetime.stopwatch: benchmark; /* Really? */
import std.stdio;
auto ts = benchmark!(
() { f_old(int.min); },
() { f_new(int.min); },
() { f_ldc(int.min); },
)(10_000_000);
writeln("old: ", ts[0].to!Duration);
writeln("new: ", ts[1].to!Duration);
writeln("LDC: ", ts[2].to!Duration);
}
EOFTypical output:
The bug exists with void main(string[] args)
{
int i = args.length != 0 ? int.min : 1;
bool* b = new bool(i > 0);
if (*b) assert(false);
} |
|
IMO, the performance loss is irrelevant (well, if it was like 10x slower, maybe we could work on it a bit). A compiler should never emit code that doesn't do what the source is telling it to do. |
wilzbach
left a comment
There was a problem hiding this comment.
Thanks a lot. I absolutely agree that DMD shouldn't emit the optimization until its bugs have been fixed.
|
(The Travis failure can be safely ignored - we have disabled it for |
|
Don't pull this until I have a chance to work on it. |
| // lower INT_MIN by 1? See test exe9.c | ||
| // BUG: fix later | ||
| code_orflag(cdb.last(), CFpsw); | ||
| cdb.genc2(0x81,grex | modregrmx(3,3,reg),0); // SBB reg,0 |
There was a problem hiding this comment.
I don't know why this section was #if'd only for Windows. The SBB instruction makes it work. No need to disable the optimization.
src/dmd/backend/cod4.c
Outdated
| /*NOTE: OPgt is left out because there is currently no | ||
| optimization implemented for it. There used to be one but it | ||
| was wrong. | ||
| https://issues.dlang.org/show_bug.cgi?id=18315 */ |
test/runnable/test18315.d
Outdated
| assert(!b); | ||
| b = 0 < i; | ||
| assert(!b); | ||
| } |
There was a problem hiding this comment.
Please just add this test case to test/runnable/mars1.d, instead of putting it in its own file. The autotester runs faster with fewer files.
`SBB reg,0` is needed to make this work. There's nothing platform specific about it. Also add comments explaining how this works.
|
Followed @WalterBright's advice and fixed the optimization by enabling the |
|
Why don't we just implement the |
i > 0int.min > 0
Great question.
|
Removing the wrong optimization, falling back to cmp instruction.I have no idea what I'm doing when it comes to dmd code, and this seems like a place where one can introduce subtle bugs. Please review carefully.