3521 – Optimized code access popped register

D issues are now tracked on GitHub. This Bugzilla instance remains as a read-only archive.
Issue 3521 - Optimized code access popped register
Summary: Optimized code access popped register
Status: RESOLVED FIXED
Alias: None
Product: D
Classification: Unclassified
Component: dmd (show other issues)
Version: D1 (retired)
Hardware: x86 Linux
: P2 normal
Assignee: No Owner
URL:
Keywords: wrong-code
Depends on:
Blocks:
Reported: 2009年11月16日 22:53 UTC by lifc0@yahoo.com.cn
Modified: 2014年04月18日 09:12 UTC (History)
3 users (show)

See Also:


Attachments
Add an attachment (proposed patch, testcase, etc.)

Note You need to log in before you can comment on or make changes to this issue.
Description lifc0@yahoo.com.cn 2009年11月16日 22:53:09 UTC
DMD compiler(seems from 1.029) produces bad optimized opcode which access a popped register.
$cat test.d
class foo {
 uint a, b;
}
void main () {
 foo f = new foo;
 uint c;
 with (f) {
 c = 0;
 b = 0;
 a = 0;
 if (a == b && (a + (c = 66)) <= 66)
 assert(c == 66);
 }
}
$dmd -O test.d
$./test
Error: AssertError Failure test.d(13)
$objdump -d test.o
 ...
 ...
 25: 53 push %ebx
 26: bb 42 00 00 00 mov 0ドルx42,%ebx
 2b: 89 d9 mov %ebx,%ecx
 2d: 5b pop %ebx <----------- here
 2e: 8d 14 0b lea (%ebx,%ecx,1),%edx
 31: 3b d6 cmp %esi,%edx
 33: 77 0f ja 44 <_Dmain+0x44>
 35: 83 fb 42 cmp 0ドルx42,%ebx <---------- and here
 38: 74 0a je 44 <_Dmain+0x44>
 ...
 ...
Comment 1 Don 2009年11月23日 01:57:30 UTC
Reduced test case shows that this is very low level. It's very specific, changing the expression order slightly will make the problem go away.
The assignment to c gets optimised away, so that it remains as 0.
-------------------------
void bug3521(int *a)
{
 int c = 0;
 *a = 0;
 if (*a == 0 && (*a + (c = 2)) == 2)
 assert(c == 2);
}
void main ()
{
 int x;
 bug3521(&x);
}
Comment 2 Don 2009年11月27日 00:15:10 UTC
I investigated this a bit, so far without success. I'm writing notes here for when I come back to it.
It's something to do with the register allocation. The compiler is somehow forgetting that it already assigned a register for c when doing the assignment. I removed the assert to make disassembly even easier: this hits a breakpoint only when compiled with -O. It only happens if c is zero. You can change the != into any kind of comparison, and the c=200 into c+=200, without affecting the bug. However, changing it into ((c = 200)!=*a) avoids the bug.
void crash(int x)
{
 if (x==200) return;
 asm { int 3; }
}
void bug3521(int *a){
 int c = 0;
 *a = 0;
 if ( *a || (*a != (c = 200)) ) 
 crash(c);
}
void main (){
 int x;
 bug3521(&x);
}
Comment 3 Walter Bright 2009年11月30日 14:16:29 UTC
I've found the cause of the problem; it's when a registered variable is on both sides of an operator and the right side tries to modify the variable. The fix isn't easy, I'll work on it.
Comment 4 Walter Bright 2009年11月30日 17:39:56 UTC
Fixed changeset 272.
Comment 5 Walter Bright 2009年12月06日 00:48:12 UTC
Fixed dmd 1.053 and 2.037


AltStyle によって変換されたページ (->オリジナル) /