Topic: BOUNCE mercury-users@cs.mu.OZ.AU: Non-member submission from [Warwick Harvey <wharvey@cs.monash.edu.au>]
Author: owner-mercury-users@cs.mu.OZ.AU
Date: 1999/05/06 Raw View
>From mercury@mulga.cs.mu.OZ.AU Fri Apr 30 11:10:20 1999
Received: from beddoe.cs.monash.edu.au (beddoe.cs.monash.edu.au [130.194.67.171]) by mulga.cs.mu.OZ.AU with ESMTP
id LAA06715 for <mercury-users@cs.mu.oz.au>; Fri, 30 Apr 1999 11:10:19 +1000 (EST)
Received: from beddoe.cs.monash.edu.au (localhost [127.0.0.1])
by beddoe.cs.monash.edu.au (8.9.1b+Sun/8.9.1) with ESMTP id LAA29850;
Fri, 30 Apr 1999 11:10:18 +1000 (EST)
Message-Id: <199904300110.LAA29850@beddoe.cs.monash.edu.au>
X-Mailer: exmh version 2.0.2 2/24/98
To: mercury-users@cs.mu.OZ.AU
cc: wharvey@cs.monash.edu.au (Warwick Harvey)
Subject: Intel x86 code generation
Date: Fri, 30 Apr 1999 11:10:17 +1000
From: Warwick Harvey <wharvey@cs.monash.edu.au>
Hi all,
As part of my work on HAL (a constraint logic programming language we're
building on top of Mercury), I've been looking at some of the low-level code
generated by the Mercury compiler. I was quite surprised when I came across
the following snippet from code which constructs a term. (I know the
following code shows signs of being a hacked version of Mercury, but
rotd-1999-04-29 shows similar symptoms).
The C code looked like this:
tag_incr_hp_msg(r4, mktag(2), (Integer) 3,
mercury__foo__deconstruct_foo_0_d_2_3_0, "foo:foo/0");
field(mktag(2), r4, (Integer) 0) = (Integer) 1;
field(mktag(2), r4, (Integer) 1) = r1;
field(mktag(2), r4, (Integer) 2) = r3;
The x86 assembler it generated looked like this:
call GC_malloc
addl $4,%esp
addl $2,%eax
movl %eax,MR_engine_base+24
movl $1,-2(%eax)
movl MR_engine_base+24,%eax
movl %ebx,2(%eax)
movl MR_engine_base+16,%eax
movl MR_engine_base+24,%edx
movl %eax,6(%edx)
I was flummoxed for a while, because I could not imagine that GCC would
generate such bad code, reloading `r4' from `MR_engine_base+24' several
times, apparently unnecessarily. Then one of my office mates, Greg Badros,
pointed out that GCC wouldn't know for sure that the value of r4 was not
going to be overwritten by the other writes to memory, and so had to
generate this kind of code to guarantee correctness.
He then suggested that a possible way to fix this would be to tell GCC that
r4 was a constant. Since that didn't seem practical, I instead introduced a
new variable:
{ const Word fooey = r4;
field(mktag(2), fooey, (Integer) 0) = (Integer) 1;
field(mktag(2), fooey, (Integer) 1) = r1;
field(mktag(2), fooey, (Integer) 2) = r3;
}
This resulted in the following assembler:
call GC_malloc
addl $4,%esp
addl $2,%eax
movl %eax,MR_engine_base+24
movl $1,-2(%eax)
movl %ebx,2(%eax)
movl MR_engine_base+16,%edx
movl %edx,6(%eax)
Much better! :-)
Now it seems to me that this is something of an Intel-specific thing. If
the x86 architecture happened to have a few more registers, r4 would never
have ended up in memory. I guess I have several questions:
1) Have you done much looking at the generated assembler for x86, as
opposed to, say, SPARC (which is what I guess you started on?)?
2) Would it be much work to change the Mercury code generator to improve
this situation? I guess there are several levels to this: a quick hack to
fix this particular example, versus a more general/complete solution.
3) Is it likely to yield much benefit?
4) Is it worth doing if it only benefits x86 architectures? ;-)
Warwick
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]