[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: truth of %nil
From: |
Mark H Weaver |
Subject: |
Re: truth of %nil |
Date: |
Sat, 4 Jul 2009 22:41:35 -0400 |
Below is a proposal for how to make boolean tests and end-of-list
tests faster and more compact, by renumbering the representations for
SCM_ELISP_NIL, SCM_EOL, SCM_UNDEFINED, and SCM_EOF_VAL.
But first, I decided to quantify the increase in code size testing
against two constants instead of one, by compiling the following short
test program with gcc -Os on three architectures: x86-32, arm, and
sparc:
(specifically, I did "gcc -Os -S foo.c" and then "as -a foo.s")
loop1(int *p)
{
while (*p != 0x004)
p++;
}
loop2(int *p)
{
while ((*p & ~0x200) != 0x004)
p++;
}
The size of the resulting loop bodies, in bytes, are as follows:
arch loop1 loop2
--------------------
x86-32 8 13
arm 12 16
sparc 16 20
--------------------
I guess this is not too bad.
The constants chosen above are based on the following proposal on how
best to make SCM_BOOL_F and SCM_ELISP_NIL differ by only one bit, and
the same for SCM_EOL and SCM_ELISP_NIL.
This can be accomplished by making:
SCM_ELISP_NIL equal to SCM_MAKIFLAG (2) i.e. 0x204, and
SCM_EOL equal to SCM_MAKIFLAG (3) i.e. 0x304.
These values are currently used by SCM_UNDEFINED and SCM_EOF_VAL, but
I'm hoping it won't be too disruptive to renumber those, especially if
it's done before the release of 2.0.
Then, testing for boolean truth becomes:
if ((x & ~0x200) != 0x004)
and testing for end-of-list becomes:
if ((x & ~0x100) == 0x204)
These should of course be written differently, perhaps as follows:
if ((x & ~(SCM_ELISP_NIL ^ SCM_BOOL_F)) != (SCM_ELISP_NIL & SCM_BOOL_F))
and for end-of-list:
if ((x & ~(SCM_ELISP_NIL ^ SCM_EOL)) == (SCM_ELISP_NIL & SCM_EOL))
along with a regression test somewhere to complain unless both of the
XOR subexpressions above are powers of two:
#define IS_POWER_OF_TWO(x) ((x) & ((x)-1) == 0)
#define DIFFER_BY_ONLY_ONE_BIT(x, y) IS_POWER_OF_TWO((x)^(y))
if ( ! DIFFER_BY_ONLY_ONE_BIT(SCM_ELISP_NIL, SCM_BOOL_F) )
complain();
if ( ! DIFFER_BY_ONLY_ONE_BIT(SCM_ELISP_NIL, SCM_EOL) )
complain();
What do you think?
Mark