Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 23 Feb 1998 10:19:26 -0600
From:      Jon Loeliger <jdl@jdl.com>
To:        hackers@FreeBSD.ORG
Subject:   My Compiler Confusion
Message-ID:  <199802231619.KAA01344@chrome.jdl.com>

next in thread | raw e-mail | index | archive | help
Hackers,

I confess, I need some help in figuring out just what is
really going on during the compilation of a trivial routine.
I suspect that I have an odd floating point mode set on
my FreeBSD box, but I'm not sure.  It's a sordid tale of
multiple compilers and different behavior, so I'm going
to just toss out a stack of perhaps useful facts and see
if someone can shed some insight for me.  Admitedly, there
are parts of this that are not FreeBSD related at all, but I
do get the strangest, unique behavior from my FreebSD box.

Here are the players:

My FreeBSD System (don't laugh):
    chrome 2779 % uname -a
    FreeBSD chrome.jdl.com 2.2-BETA_A FreeBSD 2.2-BETA_A #0: Tue Dec 24
    03:41:49  1996     jkh@time.cdrom.com:/usr/src/sys/compile/GENERIC  i386

My gcc under FreeBSD:
    chrome 2780 % gcc -v
    gcc version 2.7.2.1


A sparc box:
    blowtorch 212 % uname -a
    SunOS blowtorch 5.5.1 Generic sun4u sparc SUNW,Ultra-1

Its gcc:
    blowtorch 213 % gcc -v
    Reading specs from /usr/local/lib/gcc-lib/sparc-sun-solaris2.5/2.7.2/specs
    gcc version 2.7.2


Some damn Windows 95 box.


And a C/C++ compiler which I unfortunately must present to you folks
as the "Black Box compiler", bbc, available under (my) FreeBSD,
the sparc box, and Windows 95.  Naturally, The Problem is in this
compiler. :-)


OK, here's the whittled-down stupid code that cause us grief:

    int k;

    #define FLT_MAX 3.40282347e+38

    main()
    {
        k = FLT_MAX;
    }

Yep, that's supposed to be FLT_MAX from /usr/include land.
On the sparc it is:

    #define FLT_MAX    3.402823466E+38F  /* max decimal value of a "float" */

Anyway, it's precise value isn't too critical as any really big
float seems to be a problem here.  In fact, the point of The Problem
here is that any floating point number larger than an int will
be a problem here.  I just happen to be trying to compile a math
library that uses FLT_MAX in it.


OK, observed behavior:

On the sparc box with "gcc -S bug1.c":
    - No warnings
    - Silently generates bad code, using 0 instead of the constant:

    main:
            !#PROLOGUE# 0
            save %sp,-112,%sp
            !#PROLOGUE# 1
            sethi %hi(k),%o0
            st %g0,[%o0+%lo(k)]
    .LL1:
            ret


On the same sparc box using the Black Box Compiler:
    - The obvious warning:
        "bug1.c", line 7: warning: floating-point value does not fit in
         required integral type
    - Essentially correct code?:

    _main:
            ld.lower	r1,65535
            ld.upper	r1,32767
            addrhi	r2,%addrhi(_k)
            st.32	r1,(r2+%addrlo(_k))


Using the same Black Box Compiler under Windows:
    - Same warning
    - Bad code:

            addrhi	r2,%addrhi(_k)
            st.32	r0,(r2+%addrlo(_k))	; r0 :- 0


Under FreeBSD now, gcc gives:
    - Warning:
        bug1.c:7: warning: overflow in implicit constant conversion
    - Bad code:

    _main:
            pushl %ebp
            movl %esp,%ebp
            call ___main
            movl $0,_k

Now here's the cool one.  Under FreeBSD, the Black Box Compiler:
    - Warning:
        "bug1.c", line 7: warning: floating-point value does not fit in
	 required integral type

        Signal: SIGFPE in <some compiler file>. line 7

    - Naturally, no code generated.


That's the raw data so far.  It is true that the floating point
value doesn't fit in an integer, directly represented.

The code that the compiler is executing when this woofing happens
looks, in part, like this:

    typedef struct { 
	int tc_type;
	union {		/* Whole buncha irrelevant fields in here too. */
	    struct {
		int v0, v1, v2, v3;
	    } ival;
	    float fval;
	} vals;
    } TC;

    BOOL
    is_full_number(TC tc, int *i)
    {
        int k;
        float s;

        switch (tc.type) {

        case TC_R4:
            k = tc.vals.fval;
            s = k;
            if (s == tc.vals.fval) {
                *i = k;
                return TRUE;
            }
            return FALSE;

OK, clearly, the intent here is to somehow determine if the float
and integer representation of a number in TC look the same after
being converted from float, to integer, and back to a float.
We lose it on that k = tc.vals.fval statement, as that is where
the implicit cast to integer happens.


The questions now...

Why is the Floating point exception happening only on my FreebSD system?
Is there some FP mode somewhere that I don't know about or don't
know how to set for the system or a specific process?  And which I
might then set to a specific mode near the bbc's startup under FreeBSD?

What are they(*) _really_ trying to do with that cast-cast-compare code?
((*) I am not the original author of this Work of Art...)

Given that the constant really _doesn't_ fit in the integer, I think
the intent of this code is to essentially determine that fact and
then cause the compiler to do something else (more correct), than
silently substitute 0 in the generated code, as it does on the Solaris
box using the bbc or gcc.

How _should_ this cast-cast-compare test really be written to be
more correct?  As a range test?  Invert the test by taking max-int
and placing it in a float for the compare, which must be done
using a floating compare?

Any insight someone might shed here would be greately appreciated.
I am currently not subscribed to "hackers", so keeping me in the
mail-headers would also be, um, appreciated!

Thanks,
jdl

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-hackers" in the body of the message



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199802231619.KAA01344>