Small poll

Richard A. O'Keefe ok@REDACTED
Fri Dec 12 03:01:16 CET 2003


Kostis Sagonas <kostis@REDACTED> wrote:
	Option 2 on the surface seems a reasonable choice, but is it really ?
	I claim that at least 90% of all such cases are programming errors.

And a warning from the compiler tells the programmer about it.

	  In the context of generating native code, it is really a nuisance
	  to have to handle all sorts of illegal combinations of arguments
	  to "basic" primitives like "+".

But choosing option 3 does not remove this requirement.

    -module(foo).
    -export(bar/1).
    bar(X) -> X + 42.

a+42 is *not* the typical case.  This is.  And it is precisely in this
case that you have no idea what X is going to be.

The following cases are surely legal:
    fixnum + fixnum  -- add, may overflow and generate bignum
    fixnum + bignum  -- call out-of-line code
    fixnum + flonum  -- convert, add, box (lazily)
    bignum + fixnum  -- call out-of-line code
    bignum + bignum  -- call out-of-line code
    bignum + flonum  -- call out-of-line code
    flonum + fixnum  -- convert, add, box (lazily)
    flonum + bignum  -- call out-of-line code
    flonum + flonum  -- add, box (lazily)

By box (lazily) I mean that the compiler may leave the result in a
floating-point register and only box it when/if it is returned or
included in a data structure.

With 9 legal cases, surely handling one more ("none of the above") is
no big deal.  There would appear to be the following interesting cases:
(1) The compiler can prove that X and Y are fixnums:
	addcc X, Y, result
	bpvs,pn %icc,overflow_handler
	nop
(2) The compiler can prove that X is a fixnum and Y a flonum:
	(get X into an fp register as 32-bit integer; get Y into an fp reg.)
	fitod fX, fX
	fadd fX, fY, fresult
(3) The compiler can prove that X is a flonum and Y a fixnum:
	(get Y into fp reg as 32-bit integer; get X into fp reg.)
	fitod fY, fY	
	fadd fX, fY, fresult
(4) The compiler can prove that X and Y are both flonums
	fadd fX, fY, fresult
(5) None of the above
	taddcc X, Y, result
	bpvc,pt %icc,1f
	nop
	call general_case
	nop
    1:
    Or, on a machine without tagged add,
        or X, Y, result
	andcc result, 3, %g0
	bpnz,pn 1f
	add X, Y, result
	bpvc,pt %icc,2f
        nop
    1:  call general_case
        nop
    2:

This can be simplified a bit.  Suppose Y, for example, is a constant
which will bit as an immediate operand.  Then

	andcc X, 3, %g0
	bpnz,pn 1f
	add X, immedY, result
	bpvc,pt %icc,2f
	nop
    1:  call general_case
	set immedY, Y
    2:

But it really can't be simplified _much_.

The problem with (1), of course, is that just because the operands
of + are both fixnums doesn't mean the result is; the result could be
a fixnum or a bignum, so when you do X+X+X the second add has to be
the general case (simplified because we don't need the 'or'; we know
X is still fixnum, but we _don't_ know that X+X is).

There are only three ways I can think of to get an integer calculation
down to a single instruction:

(1) Use taddcctv, which traps on overflow, and put the general case in
    the trap handler.  However, that does nasty things to an Ultra's
    pipeline and is now a deprecated instruction.  Keeps the code short,
    though.  This only works for add, subtract, and compare, of course,
    and isn't available for most machines.

(2) Use some really amazing interval analysis as well as type inference.
    Erlang doesn't give you much to get started with, though.  About the
    only thing I can think of is that starting with size(_) and counting
    down towards 0 should be safe.

(3) Stop supporting Erlang, and implement a related language in which
    only fixnums exist, no bignums.  (There was some discussion at one
    time about having the Erlang standard only require 64-bit integers,
    but even those would count as bignums on a 32-bit machine.)  Of
    course this would cause great problems interoperating with C, Java,
    CORBA, and so on (C99, Java, and CORBA all require 64-bit integers,
    don't they?), so that won't do.

	  Moreover, in the case of HiPE,
	  because the compiler is (much) more sophisticated than the BEAM
	  one, it actually discovers quite a lot more cases of such errors.

That's great.  So issue a lot more warnings.  The BEAM and HiPE compilers
should accept *exactly* the same language.  (Although HiPE could "accept"
some files in the sense of giving up and leaving them as BEAM.)
But "accept" is not the same as "not warn about".

	  I keep wondering
	  whether there should really be a limit to the level of naivety
	  one pretends to show, or shouldn't there be?
	
This is an argument against option 1.  It is NOT an argument for option 3.
Option 2 (complain loudly but accept, compatibly with BEAM, and generate
code which generates compatible run-time behaviour) is also non-naive.




More information about the erlang-questions mailing list