Valdis.Kletnieks(a)vt.edu wrote:
On Fri, 19 Jul 2002 07:25:54 PDT, Kyle Jones said:
> Interesting. The gu part of the union apparently has separate
> storage space. Could you "print sizeof(var)"?
I get this:
(gdb) print var
$1 = {gu = {val = 0, type = Lisp_Type_Int_Even}, s = {val = 0, bits = 1}, u = {
val = 0, bits = 1}, ui = 1, i = 1, v = 0x1, cv = 0x1}
(gdb) print sizeof(var)
$2 = 4
which looks normal. But it crashes anyway.
I'm wondering if this is related to the fact that for most gcc
variants, -O2
implies -fstrict-aliasing as well. Sean found that adding an apparently
gratuitous 'sam = var.gu.type' "fixed" the problem - this may be
because
the assignment to 'sam' may be itself gratuitous, but some CSE code then
re-used the assigned value later.
Stict aliasing was turned off by default for 2.95.2:
<
URL:http://gcc.gnu.org/gcc-2.95/features.html>. In any case, compiling
with -fno-strict-aliasing produced identical binary code.
This is interesting. Here is the preprocessed version of the current
code:
Lisp_Object *value = &temps[idx++];
if ((var.gu.type == Lisp_Type_Record &&
(unsigned int)(((struct lrecord_header *)
((void *)var.ui))->type) ==
(unsigned int)lrecord_type_symbol))
*value = Qnil;
Given what GDB said about the value of var above, the if test definitely
should have failed. Here is the preprocessed version with Sean's
change:
Lisp_Object *value = &temps[idx++];
volatile unsigned int sam = var.gu.type;
if ((var.gu.type == Lisp_Type_Record &&
(unsigned int)(((struct lrecord_header *)
((void *)var.ui))->type) ==
(unsigned int)lrecord_type_symbol))
*value = Qnil;
Now look what gcc did. The register allocation is slightly different,
but don't let that confuse you. The assembly for the original is on the
left. The assembly for Sean's version is on the right. The
correspondence isn't perfect, but I tried to match up equivalent parts.
.LL348: .LL348:
.stabn 68,0,910,.LLM418-Flet .stabn 68,0,910,.LLM418-Flet
.LLM418: .LLM418:
.LLBB32: .LLBB32:
.stabn 68,0,911,.LLM419-Flet .stabn 68,0,911,.LLM419-Flet
.LLM419: .LLM419:
andcc %l0, 3, %o0 and %l0, 3, %o0
.stabn 68,0,910,.LLM420-Flet .stabn 68,0,910,.LLM420-Flet
.LLM420: .LLM420:
add %l1, 4, %l1 add %l1, 4, %l1
.stabn 68,0,911,.LLM421-Flet .stabn 68,0,912,.LLM421-Flet
.LLM421: .LLM421:
ldub [%l0], %o1 mov %o0, %o1
.stabn 68,0,910,.LLM422-Flet
.LLM422:
add %l6, 1, %l6
.stabn 68,0,911,.LLM423-Flet
.LLM423:
st %o0, [%fp-36]
.stabn 68,0,911,.LLM422-Flet .stabn 68,0,912,.LLM424-Flet
.LLM422: .LLM424:
cmp %o0, 0
bne,pt %icc, .LL351 bne,pt %icc, .LL382
cmp %o1, 0
add %l6, 1, %l6 ldub [%l0], %o0
cmp %o1, 4 cmp %o0, 4
bne,pt %icc, .LL382 bne,pt %icc, .LL351
cmp %o0, 0 cmp %o1, 0
.stabn 68,0,912,.LLM423-Flet .stabn 68,0,913,.LLM425-Flet
.LLM423: .LLM425:
ld [%l4+%lo(Qnil)], %o0 ld [%l4+%lo(Qnil)], %o0
ba,pt %xcc, .LL347 ba,pt %xcc, .LL347
st %o0, [%l1-4] st %o0, [%l1-4]
Gazing into my crystal ball, I see that var is stored in %l0 in both
cases. The first and, with 3, is to extract var.gu.type. I don't get
the addition of 4 to %l1. But now look! The code on the left
next tries to dereference %l0 (var), and read the byte it points to into
%o1! It is trying to do the right hand side of the && expression
*before* doing the left hand side, which is the next chunk of code.
This is just wrong. I don't know why Sean's addition made gcc behave,
but you'll see that the right hand side does it in the correct order.
It next copies %o0 (var.gu.type) into %o1 for later use. Then it adds 1
to %l6 (idx). Then it stores %o0 into a stack slot (sam). Then it
compares %o0 (var.gu.type) to 0 (Lisp_Type_Record). If they are
unequal, it jumps right out of this section of code, like it is supposed
to do. Otherwise, it does a useless comparison of %o1 (also
var.gu.type) to 0 (Lisp_Type_Record) and ignores the result. Only then
does it dereference %l0 (var), unlike the left side.
Anyway, it looks to me like the ldub instruction was inserted into the
instruction stream way too early on the left side. It should have been
right before LLM423. I really don't think the XEmacs code can be blamed
for this.
--
Jerry James
http://www.ittc.ku.edu/~james/