       Copyright (C) 1995 MetaWare Incorporated; All Rights Reserved.

          +------------------------------------------------------+
          |   Workaround for the Floating-Point Divide Problem   |
          |            in the Intel Pentium Processor            |
          +------------------------------------------------------+

This file describes the MetaWare implementation of the Intel-compliant 
software workaround for the Pentium floating-point fdiv instruction problem.


1.  The Intel Pentium Processor and Floating-Point Divide Instructions
----------------------------------------------------------------------

With the advent of the Intel Pentium processor, Intel changed the floating-
point divide algorithm to speed up the fdiv instructions. In creating the 
silicon for the chip, an error occurred that left five fields in a look-up
table uninitialized. This look-up table is essential for the new floating-
point divide algorithm to work correctly.

For the error to occur, the denominator of the fdiv instruction must have
the following characteristics:

*  The top five bits of the mantissa of the floating point number must be 
   one of the following:

       0x11        0x14        0x17        0x1a        0x1d 

   (This is when the number is loaded into a floating-point register; 
   single- and double-precision values in memory have the top four bits 
   of the mantissa set to either 0x1, 0x4, 0x7, 0xa, or 0xd).

*  The next three bits of the mantissa of the floating point number must 
   all be set to 1 (one).


2.  The Software Workaround
---------------------------

This software workaround was provided to us by Intel and meets the Intel 
requirement for all compiler vendors who supply a workaround for the problem. 
This requirement is that the compiler vendor use the core code for the 
workaround provided by Intel to the compiler vendor.  

MetaWare has, however, modified the interface suggested by Intel for their 
workaround, notably by altering or adding several compiler controls and two
new run-time library functions (see Sections 6-8).  Among the new controls 
is toggle Pentium_safe_divide_code.

If toggle Pentium_safe_divide_code is turned On, whenever the High C/C++ 
compiler encounters a floating-point divide, it generates code that calls a 
run-time library function. This function performs two operations:

1.  It checks to see if the Pentium processor is defective.

2.  If the processor is defective, it looks to see if the denominator of the 
    fdiv instruction exhibits the characteristics listed in Section 1.

    -  If the denominator exhibits these characteristics, the function 
       scales the numerator and the denominator by 15.0/16.0 to move the 
       denominator out of the bad range in the look-up table on the chip. It 
       then performs the fdiv instruction on the modified operands.

    -  If the denominator is a denormal number, the run-time function 
       multiplies the numerator and the denominator by 2^63 and then 
       rechecks the denominator to see if it exhibits the characteristics 
       listed in Section 1.

NOTE:  Source code for a program, testfdiv.c, to test for the Pentium 
       floating-point divide problem is included on your distribution.  
       This program uses the same check as the run-time library to see if
       it is safe to do a normal divide operation.


3.  Limitations to the Software Workaround
------------------------------------------

Because the software workaround requires calls to the run-time library, the 
Pentium-safe code generated is different from the code that would otherwise 
be generated.  Most notably, the allocation of registers is different.

The workaround also has an impact on how fast your code executes.  During 
compilation of demos/c/fbench.c, with and without -DINTRIG, the timings on a 
Dell Omniplex 60 Mhz Pentium machine were:

                without workaround (-586)     with workaround (-Pentium_only)
                -------------------------     -------------------------------
-DINTRIG        50 clocks                     66 clocks (1.32 times longer)
no defines      22 clocks                     28 clocks (1.27 times longer)

NOTE:  Using -DINTRIG with this benchmark forces the use of non-inlined
       floating-point intrinsics. See the code for more information about 
       this benchmark.

The compiler options used to compile the benchmark were:

    -O7 -586 -Pentium_only

and:

    -O7 -586 -Pentium_only -DINTRIG

Another test case that tests ( x / y ) * y and compares the result with x 
produced the following results, comparing an equal number of Pentium-safe
and non-Pentium-safe divides:

   =================================================================
   Divide                   Normal   Good-Safe*           Difference
   -----------------------------------------------------------------
   Single-precision     351 clocks   544 clocks    1.55 times longer
   Double-precision     374 clocks   560 clocks    1.50 times longer
   Extended-precision   390 clocks   583 clocks    1.49 times longer
   -----------------------------------------------------------------
   *Good-safe means that the Pentium chip tested bad and the check 
    therefore was done to determine the need for a safe divide.  All
    cases were checked, but none showed a bad denominator so no 
    safe-divide operation was performed.
   -----------------------------------------------------------------

   =================================================================
   Divide                   Normal   Bad-Safe*            Difference
   -----------------------------------------------------------------
   Single-precision     351 clocks   725 clocks    2.06 times longer
   Double-precision     374 clocks   747 clocks    2.00 times longer
   Extended-precision   390 clocks   763 clocks    1.95 times longer
   -----------------------------------------------------------------
   *Bad-safe means that the Pentium chip tested bad and the check 
    therefore was done to determine the need for a safe divide.  All 
    cases were checked, and all showed a bad denominator, so a safe-
    divide operation was performed.
   -----------------------------------------------------------------

   =================================================================
   Divide                   Normal   Good*                Difference
   -----------------------------------------------------------------
   Single-precision     351 clocks   374 clocks    1.07 times longer
   Double-precision     374 clocks   395 clocks    1.06 times longer
   Extended-precision   390 clocks   413 clocks    1.06 times longer
   -----------------------------------------------------------------
   *Good means that the check on the Pentium chip was done and the 
    Pentium chip tested good; therefore, the normal divide instruc-
    tion was executed inline.
   -----------------------------------------------------------------

Because the workaround always causes your code to execute more slowly, it is
not the default for High C/C++.  Any code you compile to run on a Pentium must 
be compiled with -Hon=Pentium_safe_divide_code or with the new command-line
option -Pentium_only (see Section 6). The code normally generated by the 
compiler does not use the workaround and might not always run correctly on a 
Pentium processor.

When a scale of the denominator and the numerator occurs, the result of the 
fdiv instruction can lose one unit of least precision with long double 
operands.  The result in this case will not compare exactly with the result 
of a normal fdiv instruction.  Apparently, this is acceptable to Intel, 
because they have not provided us with a workaround that provides the same 
accuracy as the normal fdiv instruction. Since we are compliant with Intel's 
workaround, we cannot do anything special to ensure that you get the same 
answer with the workaround as without.

In addition to fdiv instructions, the Intel workaround affects the fpatan, 
fptan, fpprem and fpprem1 instructions, because these instructions use the fdiv 
instruction internally:

*  The fpprem and fpprem1 instructions are not an issue for High C/C++, 
   because the High C/C++ compiler does not generate fpprem or fpprem1 
   instructions, and its run-time code does not use these instructions.  

*  High C/C++ does use the fpatan instruction in the floating-point 
   intrinsic expansions of the atan(), atan2(), acos(), and asin() run-time 
   library functions.  If you have a bad Pentium chip, the run-time function 
   called by the compiled code will always do a safe alternative to this 
   instruction.  However, because of the code supplied by Intel to replace the 
   fpatan instruction, there can be a 3-ULP (unit of least precision) 
   difference between the result of the safe code and the result of the 
   normal machine instruction.  This appears to be acceptable to Intel, 
   and since we are compliant with Intel's workaround, we cannot ensure that 
   you get the same answer with their workaround as with a normal fpatan 
   instruction.

*  High C/C++ uses the fptan instruction for inlining run-time library 
   function tan().

The MetaWare version of the workaround does not work for any memory model 
except small, because MetaWare does not provide libraries for any other 
memory model. If you need this workaround for a memory model other than 
small, contact our sales staff and discuss with them the purchase of the 
run-time library source code.


4.  For Developers of Embedded Applications
-------------------------------------------

The code generated by the workaround in High C/C++ is thread-safe and 
requires a writable data segment. It must have available 20 bytes of writable 
memory. If you need a workaround that does not use any writable data, 
please contact MetaWare Technical Support (since the compiler and libraries
will have to be modified) to discuss the contract work required to make this 
modification.


5.  If You Unmask Exceptions or Change the Precision Control
------------------------------------------------------------

If you unmask exceptions or change the precision control of the floating-
point unit:  Whenever the numerator or denominator is scaled or a denormal 
denominator/numerator pair is multiplied by 2^63, it is necessary to tempor-
arily mask all exceptions. When the scaling is complete, the floating-point 
chip's precision-control and exception fields are restored to their previous
setting.


6.  New Command-Line Options
----------------------------

-386_only -- Specify code tuned for the 386 processor
   Specifies that code generated by the High C/C++ compiler is tuned for
   for the 386 processor. Code compiled with this option runs on any 386, 
   486, or Pentium processor.

   This is the default of the compiler.

-486_only -- Specify code tuned only for the 486 processor
   Specifies that code generated by the High C/C++ compiler is tuned for
   for the 486 processor only. The compiler can generate instruction 
   sequences that are only available on the 486 processor.

-Pentium_only -- Specify code tuned only for the Pentium processor
   Specifies that code generated by the High C/C++ compiler is tuned for
   for the Pentium processor only. The compiler can generate instruction 
   sequences that are only available on the Pentium processor.

   Specifying option -Pentium_only makes toggle Pentium_safe_divide_code
   On by default.


7.  New and Modified Toggles
----------------------------

Long_double_math -- Emulate LOC spilling for floating-point values
   Default:  On

   The manual shows this toggle Off by default. The default has been 
   changed to On.

Pentium_safe_divide_code -- Generate Pentium-safe floating-point divide code
   Default:  Off

   When this toggle is turned On, the compiler generates the Intel-compliant 
   version of Pentium-safe floating-point divide code. The Intel-compliant 
   Pentium-safe divide code is safe for all representations of single-, 
   double-, and extended-precision numbers (including denormal values).

   This toggle is ON by default when compiling with the -Pentium_only command-
   line option.


8.  New Library Function
------------------------

int _pentium_bad_fdiv_count(void)

   Returns the number of times a defective floating-point denominator is 
   encountered that would have caused an inaccurate division result to occur
   if the code had not been not compiled for Pentium-safe floating-point 
   division.


Document number:  RM-4713-001