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>