I'm going to change the subject line to something more relevant.
Sean MacLennan <seanm(a)seanm.ca> wrote:
I agree with Jerry. On the Arm it is prefetching the pointer before
doing the branch not equal. It has *something* to do with the
casts.
If you take the gcc output and remove all the silly casts and brackets
you get the following:
[snip]
However, remove the struct cast and replace it with a simple
unsigned:
[snip]
And it works :-) Notice that the indirect load is now after the
branch.
Note this also explains why the use_union_type flag is irrelevant
here. It only affects the first part of the if, not the casting part.
I don't know where to go from here. I suppose RECORD_TYPEP could be
modified to do the above cast but I am way out of my depth here.
I wondered about this myself while trying to chase down this problem.
Here is the definition of RECORD_TYPEP (from lrecord.h):
#define RECORD_TYPEP(x, ty) \
(LRECORDP (x) && (XRECORD_LHEADER (x)->type == (unsigned int) (ty)))
Okay, I certainly want to be sure that x is an lrecord before pulling
the type out of the header (in spite of what gcc is doing on the Sparc
and the ARM, eh?). And since XRECORD_LHEADER(x)->type has type unsigned
int, I can understand casting ty (which has type "enum lrecord_type" in
every place that it is used) to unsigned int. The definition of
LRECORDP is pretty understandable, and I can see why all the casts it
uses are required. On the other hand, here is XRECORD_LHEADER, also
from lrecord.h:
#define XRECORD_LHEADER(a) ((struct lrecord_header *) XPNTR (a))
Okay, that cast is clear enough. But then we get to XPNTR. It is
declared in lisp.h:
#define XPNTR(x) ((void *) XPNTRVAL(x))
and XPNTRVAL is declared in lisp-disunion.h:
#define XPNTRVAL(x) (x) /* This depends on Lisp_Type_Record == 0 */
and lisp-union.h:
#define XPNTRVAL(x) ((x).ui)
This is where it starts to get funny. Grepping on the sources again
shows that, with one exception, everywhere that XPNTR is used, its type
is immediately cast to some kind of pointer. The one exception is in
alloc.c (in alloc_automanaged_lcrecord), where the value of XPNTR is
returned from a function declared as returning "void *", so any type of
pointer can be returned. So the cast to (void *) in XPNTR is
superfluous. Also, in the lisp-union case, we are taking x *as an
unsigned int*, not as a pointer (that would be x.v)! And finally,
XPNTRVAL is only used in the definition of XPNTR. So wouldn't it make
more sense to require users of XPNTR to give the type of pointer wanted,
and define them like this?
#define XPNTR(ty,x) ((ty *) XPNTRVAL(x))
lisp-disunion.h:
#define XPNTRVAL(x) (x)
lisp-union.h:
#define XPNTRVAL(x) ((x).v)
The only cases where this would not work is the uses of XPNTR in
print_symbol_value_magic (in symbols.c) and internal_object_printer
(print.c). But there, the format strings should be using %p instead of
%lx, in which case the casts to (long) and (unsigned long) would be
unnecessary anyway. The (unsigned long) cast in internal_object_printer
should be (long), anyway, to match the format string.
I just tried that on a Sparc machine. It compiles without complaint but
(*sigh*) doesn't solve the crash we've been discussing to death.
--
Jerry "C-u 3 M-x work-avoidance-mode" James
http://www.ittc.ku.edu/~james/
"It's like an Alcatraz around my neck."
-- Boston mayor Menino on the shortage of city parking spaces