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>
