Changes between Version 10 and Version 11 of PrimBool


Ignore:
Timestamp:
Mar 14, 2013 9:33:58 AM (14 months 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#`?