| 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 | |
| | 19 | 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. (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 | |
| | 21 | 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 `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 | |
| | 23 | The 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 ==== |