Changes between Version 33 and Version 34 of PrimBool


Ignore:
Timestamp:
Sep 19, 2013 10:04:09 AM (7 months ago)
Author:
jstolarek
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • PrimBool

    v33 v34  
    2121}}} 
    2222 
    23 in GHC.Classes (ghc-prim library) which is equivalent of: 
     23in GHC.Classes (ghc-prim library). This definition is equivalent of: 
    2424 
    2525{{{ 
     
    2929}}} 
    3030 
    31 During the compilation process (assuming the optimizations are turned on) the definition of `(||)` gets inlined and then case-of-case transform is performed successively. This results in following Core (cleaned up for clarity): 
     31During compilation definition of `(||)` gets inlined (assuming the optimizations are turned on) and then case-of-case transform is performed successively. This results in following Core (cleaned up for clarity): 
    3232 
    3333{{{ 
     
    5050}}} 
    5151 
    52 and in following assembler code: 
     52and in following assembly code: 
    5353{{{ 
    5454.Lc1rf: 
     
    8383== Solution == 
    8484 
    85 This problem was solved by modifying comparison primops to return unboxed unlifted `Int#` instead of `Bool` (which is lifted and thus is returned as a thunk that needs to be evaluated). Having `Int#` returned as a result of logical comparison will allow to use branchless bitwise logical operators instead of branching logical operators defined by Haskell. 
    86  
    87 == Implementation details == 
    88  
    89 Below is a summary of implementation details and decisions: 
    90  
    91   * The new comparison primops return a value of type `Int#`: `1#` represents `True` and `0#` represents `False`. The `Int#` type was chosen because on Haskell it is more common to use signed Int type insetad of unsigned Word. By using `Int#` the users can easily convert unboxed result into a boxed value, without need to use `word2Int#` and `int2word#` primops. 
    92  
    93   * Unlike C, `2#` or `-3#` don't represent a Boolean value.  More concretely, you can use `tagToEnum#` to convert one of these `Int#` values to a `Bool`, but `tagToEnum#` does no error checking, so it would be Very Very Bad to call it on `2#`. 
    94  
    95   * As a small side-task, four new logical bitwise primops have been implemented: `andI#`, `orI#`, `xorI#` and `negI#` (#7689). These operate on values of type `Int#`. Earlier we had only bitwise logical primops operating on values of type `Word#`. 
    96  
    97   * Names of the existing comparison primops were changed. Operators had `$` added before `#`, others had `I` added before the `#` (this is a mnemonic denoting that this primop returns and `Int#`). Examples: 
    98  
    99 {{{ 
    100 >=$#      :: Int#    -> Int#    -> Int# 
    101 /=$##     :: Double# -> Double# -> Int# 
    102 gtCharI#  :: Char#   -> Char#   -> Int# 
    103 eqWordI#  :: Word#   -> Word#   -> Int# 
    104 ltFloatI# :: Float#  -> Float#  -> Int# 
    105 leAddrI#  :: Addr#   -> Addr#   -> Int# 
    106 }}} 
    107  
    108   * A new module `GHC.PrimWrappers` was added to ghc-prim library. This module contains wrappers for comparison primops. These wrappers have names identical to removed primops and return a `Bool`. Examples: 
    109  
    110 {{{ 
    111 gtChar# :: Char# -> Char# -> Bool 
    112 gtChar# a b = tagToEnum# (a `gtCharI#` b) 
    113  
    114 (>=#) :: Int# -> Int# -> Bool 
    115 (>=#) a b = tagToEnum# (a >=$# b) 
    116  
    117 eqWord# :: Word# -> Word# -> Bool 
    118 eqWord# a b = tagToEnum# (a `eqWordI#` b) 
    119  
    120 (/=##) :: Double# -> Double# -> Bool 
    121 (/=##) a b = tagToEnum# (a /=$## b) 
    122  
    123 ltFloat# :: Float# -> Float# -> Bool 
    124 ltFloat# a b = tagToEnum# (a `ltFloatI#` b) 
    125  
    126 leAddr# :: Addr# -> Addr# -> Bool 
    127 leAddr# a b = tagToEnum# (a `leAddrI#` b) 
    128 }}} 
    129  
    130 Thanks to these wrappers the change is almost backwards compatible. '''The only thing primop users need to change in their existing code to make it work again is adding import of GHC.!PrimWrappers module.''' 
    131  
    132   * Functions for comparing `Integer` type, implemented in integer-gmp and integer-simple libraries, received a similar treatment. Technically they are not primops, because they are implemented in Haskell (in case of integer-gmp also with FFI), but they pretend to be ones. There are six primops for comparing `Integer` values: 
    133 {{{ 
    134 eqInteger#  :: Integer -> Integer -> Int# 
    135 neqInteger# :: Integer -> Integer -> Int# 
    136 leInteger#  :: Integer -> Integer -> Int# 
    137 ltInteger#  :: Integer -> Integer -> Int# 
    138 gtInteger#  :: Integer -> Integer -> Int# 
    139 geInteger#  :: Integer -> Integer -> Int# 
    140 }}} 
    141 Each of these functions has a wrapper that calls `tagToEnum#` and returns a `Bool`. These wrappers are: `eqInteger`, `neqInteger`, `leInteger`, `ltInteger`, `gtInteger` and `geInteger`. 
    142  
    143   * Six primops are an exception to the rules above: `sameMutableArray#`, `sameMutableByteArray#`, `sameMutableArrayArray#`, `sameMutVar#`, `sameMVar#` and `sameTVar#`. Their names have remained the same as before and new wrappers created for them lack `#` at the end of their name. We made that decission because this naming feels more consistent and these primops are rarely used so we expect that they won't break a lot of existing code. 
    144  
    145   * Other libraries that were modified to work with the new primops are: base, ghc-prim and primitive. The only required modifications were imports of the GHC.!PrimWrappers module in modules that use the primops. 
     85This problem was solved by modifying comparison primops to return unboxed unlifted `Int#` instead of `Bool`, which is lifted and thus must be inspected with a `case` expression. Having `Int#` returned as a result of logical comparison allows to use branchless bitwise logical operators instead of branching logical operators defined by Haskell. 
    14686 
    14787== Eliminating branches using new primops == 
     
    279219The assembly does not contain comparisons and branches in the scrutinee of the case expression, but still uses jumps to select an appropriate branch of the case expression.  
    280220 
     221== Implementation details == 
     222 
     223Below is a summary of implementation details and decisions: 
     224 
     225  * The new comparison primops return a value of type `Int#`: `1#` represents `True` and `0#` represents `False`. The `Int#` type was chosen because on Haskell it is more common to use signed Int type insetad of unsigned Word. By using `Int#` the users can easily convert unboxed result into a boxed value, without need to use `word2Int#` and `int2word#` primops. 
     226 
     227  * Unlike C, `2#` or `-3#` don't represent a Boolean value.  More concretely, you can use `tagToEnum#` to convert one of these `Int#` values to a `Bool`, but `tagToEnum#` does no error checking, so it would be Very Very Bad to call it on `2#`. 
     228 
     229  * As a small side-task, four new logical bitwise primops have been implemented: `andI#`, `orI#`, `xorI#` and `negI#` (#7689). These operate on values of type `Int#`. Earlier we had only bitwise logical primops operating on values of type `Word#`. 
     230 
     231  * Names of the existing comparison primops were changed. Operators had `$` added before `#`, others had `I` added before the `#` (this is a mnemonic denoting that this primop returns and `Int#`). Examples: 
     232 
     233{{{ 
     234>=$#      :: Int#    -> Int#    -> Int# 
     235/=$##     :: Double# -> Double# -> Int# 
     236gtCharI#  :: Char#   -> Char#   -> Int# 
     237eqWordI#  :: Word#   -> Word#   -> Int# 
     238ltFloatI# :: Float#  -> Float#  -> Int# 
     239leAddrI#  :: Addr#   -> Addr#   -> Int# 
     240}}} 
     241 
     242  * A new module `GHC.PrimWrappers` was added to ghc-prim library. This module contains wrappers for comparison primops. These wrappers have names identical to removed primops and return a `Bool`. Examples: 
     243 
     244{{{ 
     245gtChar# :: Char# -> Char# -> Bool 
     246gtChar# a b = tagToEnum# (a `gtCharI#` b) 
     247 
     248(>=#) :: Int# -> Int# -> Bool 
     249(>=#) a b = tagToEnum# (a >=$# b) 
     250 
     251eqWord# :: Word# -> Word# -> Bool 
     252eqWord# a b = tagToEnum# (a `eqWordI#` b) 
     253 
     254(/=##) :: Double# -> Double# -> Bool 
     255(/=##) a b = tagToEnum# (a /=$## b) 
     256 
     257ltFloat# :: Float# -> Float# -> Bool 
     258ltFloat# a b = tagToEnum# (a `ltFloatI#` b) 
     259 
     260leAddr# :: Addr# -> Addr# -> Bool 
     261leAddr# a b = tagToEnum# (a `leAddrI#` b) 
     262}}} 
     263 
     264Thanks to these wrappers the change is almost backwards compatible. '''The only thing primop users need to change in their existing code to make it work again is adding import of GHC.!PrimWrappers module.''' 
     265 
     266  * Functions for comparing `Integer` type, implemented in integer-gmp and integer-simple libraries, received a similar treatment. Technically they are not primops, because they are implemented in Haskell (in case of integer-gmp also with FFI), but they pretend to be ones. There are six primops for comparing `Integer` values: 
     267{{{ 
     268eqInteger#  :: Integer -> Integer -> Int# 
     269neqInteger# :: Integer -> Integer -> Int# 
     270leInteger#  :: Integer -> Integer -> Int# 
     271ltInteger#  :: Integer -> Integer -> Int# 
     272gtInteger#  :: Integer -> Integer -> Int# 
     273geInteger#  :: Integer -> Integer -> Int# 
     274}}} 
     275Each of these functions has a wrapper that calls `tagToEnum#` and returns a `Bool`. These wrappers are: `eqInteger`, `neqInteger`, `leInteger`, `ltInteger`, `gtInteger` and `geInteger`. 
     276 
     277  * Six primops are an exception to the rules above: `sameMutableArray#`, `sameMutableByteArray#`, `sameMutableArrayArray#`, `sameMutVar#`, `sameMVar#` and `sameTVar#`. Their names have remained the same as before and new wrappers created for them lack `#` at the end of their name. We made that decission because this naming feels more consistent and these primops are rarely used so we expect that they won't break a lot of existing code. 
     278 
     279  * Other libraries that were modified to work with the new primops are: base, ghc-prim and primitive. The only required modifications were imports of the GHC.!PrimWrappers module in modules that use the primops. 
    281280 
    282281=== Benchmarks ===