Changes between Version 7 and Version 9 of Commentary/CmmExceptions


Ignore:
Timestamp:
Jan 16, 2007 7:28:27 PM (7 years ago)
Author:
p_tanski
Comment:

add notes on #1042 as an instructive example; add subheadings

Legend:

Unmodified
Added
Removed
Modified
  • Commentary/CmmExceptions

    v7 v9  
    1515 * FPU exceptions may be unavoidable, especially if several FPU operations are serially performed at the machine level so the higher level software has no opportunity to check the results in between operations.  
    1616 
    17 There has been at least one problem in GHC that would benefit from exception handling--in some cases, for `Integral`s.  See bug ticket #1042.  The bug occurs in `show`ing the number, in [GhcFile(libraries/base/GHC/Show.lhs) GHC.Show], `showSignedInt`, before conversion from base_2 to base_10, where a negative `Int` (always `Int32`) is negated in order to process it as a positive value when converting it to a string, base_10, causing an overflow error on some architectures.  Note that the exception example in #1042 does not occur on PowerPC machines, which dutifully print the two's complement of {{{(-2147483648::Int) `div` (-1::Int)}}}: `0`.  (`-2147483648` is the minimum bound for signed Ints, so negating it should properly become, bitwise, a positive `2147483647` (all but bit 31 set); once negated again when divided by `-1` this would be `0`; `-0` is converted to `0`.)  On some architectures such as Intel 64 and IA-32, negating the minimum bound does not wrap around to `0` but overflows, which is reported as a floating point "overflow" (`#O`) exception.  The workaround was to avoid negating `minBound` `Int`s.   
     17==== An Integral Exception Example ==== 
     18 
     19There has been at least one problem in GHC that would benefit from exception handling--in some cases, for `Integral`s.  See bug ticket #1042.  The bug occurs in `show`ing the number, in [GhcFile(libraries/base/GHC/Show.lhs) GHC.Show], `showSignedInt`, before conversion from base_2 to base_10, where a negative `Int` (always `Int32`) is negated in order to process it as a positive value when converting it to a string, base_10, causing an overflow error on some architectures.  (Bear in mind that it would show up here in the example for #1042 because the function would be evaluated in GHCi here; the negation is the problem and the exception shows up in the ''next'' instruction on that operand, here `DIV`.)   
     20 
     21The exception example in #1042 does not occur on PowerPC machines, which dutifully print the two's complement of {{{(-2147483648::Int) `div` (-1::Int)}}}: `0`.  (`-2147483648` is the minimum bound for signed Ints, so negating it should properly become, bitwise, a positive `2147483647` (all but bit 31 set); once negated again when divided by `-1` this would be `0`; `-0` is converted to `0`.)  On some architectures such as Intel 64 and IA-32, negating the minimum bound does not wrap around to `0` but overflows, which is reported as a floating point "overflow" (`#O`) exception: the `NEG` instruction modifies the `OF` flag (bit 11) in the `EFLAGS` register--curiously enough, the `DIV` and `IDIV` instructions have ''undefined'' effects on the `OF` flag.   
     22 
     23The workaround was to avoid negating `minBound` `Int`s; note that no Intel instructions allow one to modify the `OF` flag directly.  Alternative solutions might be to 
     24 1. mask the "exception" by clearing the interrupt flag, `IF`, using the `CLI` instruction; or,  
     25 1. conditionally unset the flag by using the `PUSHF` instruction on the `EFLAGS` register to push its lower word (bits 15-0, including the offending bit 11 (`OF`)) onto the stack, reset the `OF` bit, then push that back onto the stack and pop it into EFLAGS with `POPF`.  Depending on variable register used, the assembler output would look similar to: 
     26{{{ 
     27        ; after NEG, MUL, other potential overflow operation ... 
     28        jo      _reset_OF_flag  ; jump near if overflow (OF=1) 
     29        ; continue rest of operation 
     30        jmp     _continue_operation_on_int: 
     31_reset_OF_flag: 
     32        pushf   %eflags         ; push low 16 bits of %eflags onto stack 
     33        pop     %ax             ; pop top of stack into low 16 bits of %eax 
     34        and     $0xF7FF, %ax    ; %ax = %ax & 0xF7FF 
     35        push    %ax             ; push %ax value (with bit 11 set to 0) onto stack 
     36        popf                    ; pop top of stack into lower 16 bits of %eflags 
     37                                ; OF bit now reset 
     38        jmp     _continue_operation_on_int: 
     39         
     40_continue_operation_on_int:     ; this is a 32-bit address (also works in 64-bit mode) 
     41        ;... 
     42}}} 
     43 
     44==== A Floating Point Exception Example ==== 
    1845 
    1946There was a long message thread on the Haskell-prime mailing list, "realToFrac Issues," beginning with [http://www.haskell.org/pipermail/haskell-prime/2006-February/000791.html John Meacham's message] and ending with [http://www.haskell.org/pipermail/haskell-prime/2006-March/000840.html Simon Marlow's message].  The following code for converting a Float to a Double will ''fail'' to produce a floating point exception or NaN on x86 machines (recall that 0.0/0.0 is NaN ''and'' a definite FPU exception):