[Openmcl-devel] compiler bug?

Gary Byers gb at clozure.com
Sat Sep 18 09:50:32 PDT 2004



On Sat, 18 Sep 2004, Randall Beer wrote:

>
> > can't we just make (constantp x) be (numberp x)?
> > I can't imagine a case where x would be anything else (other then
> > something that needs to be evaluated)
> > :alex
>
> This certainly works. However, it doesn't "expand away" as much of the
> computation as it could.  For example, with this definition, we get
>
> ? (macroexpand '(coerce-to-foreign-type #$NO :char))
> (LET ((#:G2043 OS::NO))
>     (IF (OR (EQ #:G2043 0) (NULL #:G2043))
>          OS::NO
>          OS::YES))
> T
>

As it happens, that LET/IF combination compiles to:

  (CMPWI RZERO 0)	; is RZERO (which always contains 0) = 0 ?
  (BEQ L28)		; yes, by definition.  but ..
  (CMPWI RZERO NIL)	; Is it EQ to NIL ?
  (BNE L36)		; no, by definition
L28
  (LI ARG_Z '0)
  (B L40)
L36
  (LI ARG_Z '1)
L40

That's kind of embarrasing; the compiler has enough information to
recognize that #:g2043 is a constant (and that it happens to be
a particular constant that's always in a register), but still generates
code to compare that constant to other constants at runtime.

People generally don't write code like the macroexpansion, but the
most straightforward expansion of a lot of macros winds up containing
things that offer lots of opportunities for simple but useful
optimizations.


> so that the test is still being done at runtime. Whereas with the EVAL
> change I made last night, we get.
>
> ? (macroexpand '(coerce-to-foreign-type #$NO :char))
> 0
> T
>
> Because these conversions have to happen for *every* argument passed
> into *every* message send, I was trying to do as much at compile-time
> as I possibly could.
>
> BTW, my earlier bug shows once again why one should NOT use macros to
> address these sorts of efficiency concerns.  Instead, one should use
> functions with appropriate compiler macros to optimize the special
> cases (such as constant object and/or foreign type). I know this, but
> unfortunately still don't always do it.
>

It's hard to so some of these things at the source level: in this case,
you'd have to walk the LET body and prove that you knew that value of
the "variable" was constant and known at the points of reference (the
simplest way to prove that is to note that there are no assignments
to the variable after it's bound.)

The OpenMCL compiler isn't the sharpest knife in the drawer, but it
doesn't have to be any smarter than it is to generate better code
than it does here.  I think that it'd be reasonable to expect it
to handle this and similar cases better.

You'd really like to see this sort of constant-folding propagate
its way up through the parse tree, so if that constant-valued LET
form was used in a context like:

(if (not (eql (let ...) #$NO))
   true
   false)

we could constant-fold this into the true clause of the IF.  This
kind of constant-folding does happen at early stages (if the constants
or constant-valued expressions are apparent in the source), but
it doesn't happen (and it'd be much harder to do than it should be)
later on.



> Randy



More information about the Openmcl-devel mailing list