Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Posting-Version: version B 2.10.2 (Tek) 9/28/84 based on 9/17/84; site tekcrl.UUCP Path: utzoo!watmath!clyde!burl!ulysses!mhuxr!mhuxt!houxm!vax135!cornell!uw-beaver!tektronix!tekcrl!toddb From: toddb@tekcrl.UUCP (Todd Brunhoff) Newsgroups: net.bugs,net.bugs.4bsd Subject: BSD C floating point bug affecting code everywhere (Really awful) Message-ID: <385@tekcrl.UUCP> Date: Wed, 20-Nov-85 14:57:37 EST Article-I.D.: tekcrl.385 Posted: Wed Nov 20 14:57:37 1985 Date-Received: Sat, 23-Nov-85 01:16:07 EST Organization: Tektronix, Beaverton OR Lines: 67 Xref: watmath net.bugs:716 net.bugs.4bsd:1849 The following program seems innocuous enough: int tst[1],i; main() { tst[0] = 0x20000020; i = 0; tst[i] += 0.0 * i; } However, the code generated for the "tst[i] += 0.0 * i;" is incorrect and even causes a core dump, which is how we came to notice this. The problem is based on the fact that if a destination operand for a D-format floating point operation is a register, say n, then the vax cpu uses register n and register n+1 for the result. Here's the code generated: ... L18: .double 0d0.00000000000000000000e+00 .text cvtld _i,r0 /* convert i to D-format floating point, * putting result in r0 and r1. I believe it * is only an accident that something is not * in r1 to get clobbered. */ muld3 r0,L18,r2 /* put "0.0 * i" into r2 ... and r3 as well */ movl _i,r0 cvtld _tst[r0],r1 /* convert long to D-format. The result * goes into r1 AND r2 thus clobbering the * current value of r2 which was half of * the expression "0.0 * i". */ addd2 r2,r1 /* Here's the worst. We are actually adding * the top half of the previous result to its * bottom half (although the intent was * different). And with the particular * constant 0x20000020, the result of the * previous instruction put a 0x000080000 * in r2. It just happens that this is a * reserved operand (sign bit 15 = 1, exponent * bits 14-7 = 0), and so we got a reserved * operand fault. */ We never would have known about this except for the reserved operand fault caused by this particular constant, which means that vaxes running 4.2BSD unix everywhere are just doing calculations flat wrong and no one knows it. But if they get them right, it is purely by accident. The correct code should be: .double 0d0.00000000000000000000e+00 .text cvtld _i,r0 /* convert i to D-format (r0,r1) */ muld3 r0,L18,r3 /* put "0.0 * i" into r3 and r4 */ movl _i,r0 cvtld _tst[r0],r1 /* convert long to D-format. The result * goes into r1 AND r2. */ addd2 r3,r1 /* add D-format (r3-r4) + (r1-r2) */ I haven't looked at the code generation modules, so it may be that only the conversion operations forget about allocating register pairs. How about system V and Tartan's C-compiler? It is not a well-known problem here; is it known elsewhere? This is awful! Blech!