Changes between Version 10 and Version 11 of PrimBool


Ignore:
Timestamp:
Mar 14, 2013 9:33:58 AM (2 years ago)
Author:
jstolarek
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • PrimBool

    v10 v11  
    233233Another problem with this approach is that it would introduce primitive logical operations `||#` and `&&#` with type `Int# -> Int# -> Int#` - it is questionable whether anyone would want such operations available to the programmer. I think it is desirable to have primitive logical operators of type `Bool# -> Bool# -> Bool#`.
    234234
    235 == Places of interest in the source code ==
    236 
    237 The file [[GhcFile(prelude/primops.txt.pp)]] defines !PrimOps and their type signatures. An example definition looks like this:
    238 
    239 {{{
    240 primop   IntGtOp  ">#"   Compare   Int# -> Int# -> Bool
    241    with fixity = infix 4
    242 }}}
    243 
    244 Existing definitions should remain unchanged or the code using them would break and that is a Very Bad Thing. This would require creating new !PrimOps:
    245 
    246 {{{
    247 primop   IntGtOpB  ".>#"   Compare   Int# -> Int# -> Bool#
    248    with fixity = infix 4
    249 }}}
    250 
    251 The tricky part here is `Compare`. This a value constructor of `PrimOpInfo` data type defined in [[GhcFile(prelude/PrimOp.lhs)]]:
    252 
    253 {{{
    254 data PrimOpInfo
    255   = Dyadic      OccName         -- string :: T -> T -> T
    256                 Type
    257   | Monadic     OccName         -- string :: T -> T
    258                 Type
    259   | Compare     OccName         -- string :: T -> T -> Bool
    260                 Type
    261   | GenPrimOp   OccName         -- string :: \/a1..an . T1 -> .. -> Tk -> T
    262                 [TyVar]
    263                 [Type]
    264                 Type
    265 }}}
    266 
    267 We would need new `PrimOpInfo` value to denote !PrimOps of type `T -> T -> Bool#`. Appropriate functions like `primOpSig` and `getPrimOpResultInfo` would have to be adjusted accordingly.
     235== Proposed patch (13/03/2013) ==
     236
     237The prototype patch posted on the trac implements six new prototype comparison primops:
     238
     239{{{
     240.>#  :: Int# -> Int# -> Int#
     241.<#  :: Int# -> Int# -> Int#
     242.>=# :: Int# -> Int# -> Int#
     243.<=# :: Int# -> Int# -> Int#
     244.==# :: Int# -> Int# -> Int#
     245./=# :: Int# -> Int# -> Int#
     246}}}
     247
     248Each of these new primops takes two `Int#`s that are to be compared. The result is also an `Int#`: `0#` if the relation between the operands does not hold and `1#` when it does hold. For example `5# .># 3#` returns `1#` and `3# .># 3#` returns `0#`. With the new primops we can rewrite the original expression that motivated the problem:
     249
     250{{{
     251case (x <# 0#) || (x >=# width) || (y <# 0#) || (y >=# height) of
     252  True  -> E1
     253  False -> E2
     254}}}
     255
     256as
     257
     258{{{
     259case (x .<# 0#) `orI#` (x .>=# width) `orI#` (y .<# 0#) `orI#` (y .>=# height) of
     260  True  -> E1
     261  False -> E2
     262}}}
     263
     264(Note: `orI#` is a bitwise OR operation on operands of type `Int#`. It was introduced together with `andI#`, `notI#` and `xor#` in #7689). Using the LLVM backend this compiles to:
     265
     266{{{
     267# BB#0:                                 # %c1nK
     268        movq    %rsi, %rax
     269        orq     %r14, %rax
     270        shrq    $63, %rax
     271        cmpq    %rdi, %r14
     272        setge   %cl
     273        movzbl  %cl, %ecx
     274        orq     %rax, %rcx
     275        cmpq    %r8, %rsi
     276        setge   %al
     277        movzbl  %al, %eax
     278        orq     %rcx, %rax
     279        jne     .LBB2_1
     280# BB#3:                                 # %c1ol
     281        movq    (%rbp), %rax
     282        movl    $r1m6_closure+1, %ebx
     283        jmpq    *%rax  # TAILCALL
     284.LBB2_1:                                # %c1nK
     285        cmpq    $1, %rax
     286        jne     .LBB2_2
     287# BB#4:                                 # %c1ov
     288        movq    (%rbp), %rax
     289        movl    $r1m7_closure+1, %ebx
     290        jmpq    *%rax  # TAILCALL
     291.LBB2_2:                                # %c1ob
     292        movq    r1m5_closure(%rip), %rax
     293        movl    $r1m5_closure, %ebx
     294        jmpq    *%rax  # TAILCALL
     295}}}
     296
     297The assembly does not contain comparisons and jumps in the scrutinee of the case expression, but still does jumps for selecting an appropriate branch of the case expression.
     298
     299An alternative design decision is to make the new primops return a `Word#`. I decided to use `Int#` because `Int` is used more often than `Word`. If new primops returned a `Word#` the user would have to use `int2Word#`/`word2Int#` primops to do conversions if she ever wished to box the result.
     300
     301Comparisons for `Word#`, `Float#` and `Double#` will be implemented once we make sure that the prototype implementation is correct.
     302
     303Some concerns:
     304  - should the primops return an `Int#` or `Word#` as their result?
     305  - what names should the new primops have? I planned to use names with a dot preceeding the operator for `Int#` and `Double#` comparisons (e.g. `./=#`, `.>##`) and names with "St" suffix for `Word#` and `Float#`, e.g. `gtWordSt#`, `gtFloatSt#` (`St` stands for 'strict' because the result can be used with the strict bitwise logical operators).
     306  - how to remove the old `Compare` primops (ones of type `T -> T -> Bool`)?
     307  - once we have the new primops do we really care about the unboxed `Bool#`?