<div dir="auto">In this example: why would it stop being a join point ? </div><div dir="auto"><br></div><div dir="auto">Admittedly, my intuition might be skewed by my own ideas about how join points are sortah a semantic special case of other constructs.  </div><div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Sat, Nov 20, 2021 at 4:17 PM Simon Peyton Jones via ghc-devs <<a href="mailto:ghc-devs@haskell.org">ghc-devs@haskell.org</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;padding-left:1ex;border-left-color:rgb(204,204,204)">There is absolutely no reason not to common-up those to join points.  But we can't common up some join points when we could if they were let's.  Consider<br>
<br>
join j1 x = x+1<br>
in case v of<br>
      A -> f (join j2 x = x+1 in ...j2...)<br>
      B -> ....j1...<br>
      C -> ....j1...<br>
<br>
Even though j2 is identical to j1's, we can't eliminate j2 in favour of j1 because then j1 wouldn't be a join point any more.<br>
<br>
GHC.Core.Opt.CSE is conservative at the moment, and never CSE's *any* join point.  It would not be hard to make it clever enough to CSE join points, but no one has yet done it.<br>
<br>
Do open a ticket!<br>
<br>
Simon<br>
<br>
PS: I am leaving Microsoft at the end of November 2021, at which point <a href="mailto:simonpj@microsoft.com" target="_blank">simonpj@microsoft.com</a> will cease to work.  Use <a href="mailto:simon.peytonjones@gmail.com" target="_blank">simon.peytonjones@gmail.com</a> instead.  (For now, it just forwards to <a href="mailto:simonpj@microsoft.com" target="_blank">simonpj@microsoft.com</a>.)<br>
<br>
| -----Original Message-----<br>
| From: ghc-devs <<a href="mailto:ghc-devs-bounces@haskell.org" target="_blank">ghc-devs-bounces@haskell.org</a>> On Behalf Of Viktor<br>
| Dukhovni<br>
| Sent: 20 November 2021 00:57<br>
| To: <a href="mailto:ghc-devs@haskell.org" target="_blank">ghc-devs@haskell.org</a><br>
| Subject: [EXTERNAL] Unexpected duplicate join points in "Core" output?<br>
| <br>
| The below "Core" output from "ghc -O2" (9.2/8.10) for the attached<br>
| program shows seemingly rendundant join points:<br>
| <br>
|       join {<br>
|         exit :: State# RealWorld -> (# State# RealWorld, () #)<br>
|         exit (ipv :: State# RealWorld) = jump $s$j ipv } in<br>
| <br>
|       join {<br>
|         exit1 :: State# RealWorld -> (# State# RealWorld, () #)<br>
|         exit1 (ipv :: State# RealWorld) = jump $s$j ipv } in<br>
| <br>
| that are identical in all but name.  These correspond to fallthrough to<br>
| the "otherwise" case in:<br>
| <br>
|            ...<br>
|            | acc < q || (acc == q && d <= 5)<br>
|              -> loop (ptr `plusPtr` 1) (acc * 10 + d)<br>
|            | otherwise -> return Nothing<br>
| <br>
| but it seems that the generated X86_64 code (also below) ultimately<br>
| consolidates these into a single target... Is that why it is harmless<br>
| to leave these duplicated in the generated "Core"?<br>
| <br>
| [ Separately, in the generated machine code, it'd also be nice to avoid<br>
|   comparing the same "q" with the accumulator twice.  A single load and<br>
|   compare should I think be enough, as I'd expect the status flags to<br>
|   persist across the jump the second test.<br>
| <br>
|   This happens to not be performance critical in my case, because most<br>
|   calls should satisfy the first test, but generally I think that 3-way<br>
|   "a < b", "a == b", "a > b" branches ideally avoid comparing twice...<br>
| ]<br>
| <br>
| ======== Associated Core output<br>
| <br>
|     -- RHS size: {terms: 1, types: 0, coercions: 0, joins: 0/0}<br>
|     main2 :: Addr#<br>
|     main2 = "12345678901234567890 junk"#<br>
| <br>
|     -- RHS size: {terms: 129, types: 114, coercions: 0, joins: 6/8}<br>
|     main1 :: State# RealWorld -> (# State# RealWorld, () #)<br>
|     main1<br>
|       = \ (eta :: State# RealWorld) -><br>
|           let {<br>
|             end :: Addr#<br>
|             end = plusAddr# main2 25# } in<br>
|           join {<br>
|             $s$j :: State# RealWorld -> (# State# RealWorld, () #)<br>
|             $s$j _ = hPutStr2 stdout $fShowMaybe4 True eta } in<br>
|           join {<br>
|             exit :: State# RealWorld -> (# State# RealWorld, () #)<br>
|             exit (ipv :: State# RealWorld) = jump $s$j ipv } in<br>
|           join {<br>
|             exit1 :: State# RealWorld -> (# State# RealWorld, () #)<br>
|             exit1 (ipv :: State# RealWorld) = jump $s$j ipv } in<br>
|           join {<br>
|             exit2<br>
|               :: Addr# -> Word# -> State# RealWorld -> (# State#<br>
| RealWorld, () #)<br>
|             exit2 (ww :: Addr#) (ww1 :: Word#) (ipv :: State#<br>
| RealWorld)<br>
|               = case eqAddr# ww main2 of {<br>
|                   __DEFAULT -><br>
|                     hPutStr2<br>
|                       stdout<br>
|                       (++<br>
|                          $fShowMaybe1<br>
|                          (case $w$cshowsPrec3 11# (integerFromWord#<br>
| ww1) [] of<br>
|                           { (# ww3, ww4 #) -><br>
|                           : ww3 ww4<br>
|                           }))<br>
|                       True<br>
|                       eta;<br>
|                   1# -> jump $s$j ipv<br>
|                 } } in<br>
|           joinrec {<br>
|             $wloop<br>
|               :: Addr# -> Word# -> State# RealWorld -> (# State#<br>
| RealWorld, () #)<br>
|             $wloop (ww :: Addr#) (ww1 :: Word#) (w :: State# RealWorld)<br>
|               = join {<br>
|                   getDigit :: State# RealWorld -> (# State# RealWorld,<br>
| () #)<br>
|                   getDigit (eta1 :: State# RealWorld)<br>
|                     = case eqAddr# ww end of {<br>
|                         __DEFAULT -><br>
|                           case readWord8OffAddr# ww 0# eta1 of { (#<br>
| ipv, ipv1 #) -><br>
|                           let {<br>
|                             ipv2 :: Word#<br>
|                             ipv2 = minusWord# (word8ToWord# ipv1) 48##<br>
| } in<br>
|                           case gtWord# ipv2 9## of {<br>
|                             __DEFAULT -><br>
|                               case ltWord# ww1 1844674407370955161## of<br>
| {<br>
|                                 __DEFAULT -><br>
|                                   case ww1 of {<br>
|                                     __DEFAULT -> jump exit ipv;<br>
|                                     1844674407370955161## -><br>
|                                       case leWord# ipv2 5## of {<br>
|                                         __DEFAULT -> jump exit1 ipv;<br>
|                                         1# -><br>
|                                           jump $wloop<br>
|                                             (plusAddr# ww 1#)<br>
|                                             (plusWord#<br>
| 18446744073709551610## ipv2)<br>
|                                             ipv<br>
|                                       }<br>
|                                   };<br>
|                                 1# -><br>
|                                   jump $wloop<br>
|                                     (plusAddr# ww 1#) (plusWord#<br>
| (timesWord# ww1 10##) ipv2) ipv<br>
|                               };<br>
|                             1# -> jump exit2 ww ww1 ipv<br>
|                           }<br>
|                           };<br>
|                         1# -> jump exit2 ww ww1 eta1<br>
|                       } } in<br>
|                 jump getDigit w; } in<br>
|           jump $wloop main2 0## realWorld#<br>
| <br>
| ======== Executable disassembly<br>
| <br>
| The jumps at "-1->" and "-2->" that correspond that "otherwise" have<br>
| the same target.  The duplicate "load+cmp" with "q" is at "-3->" and "-<br>
| 4->":<br>
| <br>
|     0000000000408de8 <Main_main1_info>:<br>
|       408de8:       48 8d 45 e8             lea    -0x18(%rbp),%rax<br>
|       408dec:       4c 39 f8                cmp    %r15,%rax<br>
|       408def:       0f 82 c8 00 00 00       jb     408ebd<br>
| <Main_main1_info+0xd5><br>
|       408df5:       b8 79 dd 77 00          mov    $0x77dd79,%eax<br>
|       408dfa:       31 db                   xor    %ebx,%ebx<br>
|       408dfc:       b9 60 dd 77 00          mov    $0x77dd60,%ecx<br>
|       408e01:       48 39 c1                cmp    %rax,%rcx<br>
|       408e04:       74 66                   je     408e6c<br>
| <Main_main1_info+0x84><br>
|       408e06:       0f b6 11                movzbl (%rcx),%edx<br>
|       408e09:       48 83 c2 d0             add<br>
| $0xffffffffffffffd0,%rdx<br>
|       408e0d:       48 83 fa 09             cmp    $0x9,%rdx<br>
|       408e11:       77 59                   ja     408e6c<br>
| <Main_main1_info+0x84><br>
| -3->  408e13:       48 be 99 99 99 99 99    mov<br>
| $0x1999999999999999,%rsi<br>
|       408e1a:       99 99 19<br>
|       408e1d:       48 39 f3                cmp    %rsi,%rbx<br>
|       408e20:       73 0c                   jae    408e2e<br>
| <Main_main1_info+0x46><br>
|       408e22:       48 6b db 0a             imul   $0xa,%rbx,%rbx<br>
|       408e26:       48 01 d3                add    %rdx,%rbx<br>
|       408e29:       48 ff c1                inc    %rcx<br>
|       408e2c:       eb d3                   jmp    408e01<br>
| <Main_main1_info+0x19><br>
| -4->  408e2e:       48 be 99 99 99 99 99    mov<br>
| $0x1999999999999999,%rsi<br>
|       408e35:       99 99 19<br>
|       408e38:       48 39 f3                cmp    %rsi,%rbx<br>
| -1->  408e3b:       75 49                   jne    408e86<br>
| <Main_main1_info+0x9e><br>
|       408e3d:       48 83 fa 05             cmp    $0x5,%rdx<br>
| -2->  408e41:       77 43                   ja     408e86<br>
| <Main_main1_info+0x9e><br>
|       408e43:       48 8d 5a fa             lea    -0x6(%rdx),%rbx<br>
|       408e47:       48 ff c1                inc    %rcx<br>
|       408e4a:       eb b5                   jmp    408e01<br>
| <Main_main1_info+0x19><br>
|       408e4c:       0f 1f 40 00             nopl   0x0(%rax)<br>
|       408e50:       c2 00 00                retq   $0x0<br>
| <br>
| --<br>
|     Viktor.<br>
_______________________________________________<br>
ghc-devs mailing list<br>
<a href="mailto:ghc-devs@haskell.org" target="_blank">ghc-devs@haskell.org</a><br>
<a href="http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs" rel="noreferrer" target="_blank">http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs</a><br>
</blockquote></div></div>