[GHC] #14672: Make likelyhood of branches/conditions available throughout the compiler.

GHC ghc-devs at haskell.org
Thu Apr 26 09:13:03 UTC 2018


#14672: Make likelyhood of branches/conditions available throughout the compiler.
-------------------------------------+-------------------------------------
        Reporter:  AndreasK          |                Owner:  (none)
            Type:  task              |               Status:  new
        Priority:  normal            |            Milestone:
       Component:  Compiler          |              Version:  8.2.2
      Resolution:                    |             Keywords:
Operating System:  Unknown/Multiple  |         Architecture:
                                     |  Unknown/Multiple
 Type of failure:  None/Unknown      |            Test Case:
      Blocked By:                    |             Blocking:
 Related Tickets:                    |  Differential Rev(s):  Phab:D4316
       Wiki Page:                    |  Phab:D4324 Phab:D4327
-------------------------------------+-------------------------------------

Comment (by AndreasK):

 I did some work on this for the Cmm/STG stages. But so far the results
 still don't justify the complexity. Although it's pretty clear which
 things should be tried before further judgment can be made.

 I did implement a rudimentary version which detected recursion as likely
 and bottoming branches as unlikely.
 Overall performance was underwhelming. While most nofib programs got
 slightly faster (0-1%) very few got a lot (order of ~5%) slower.

 What I did not do yet is propagte the likelyhood info into the asm passes
 which is probably required. Without this we get some awkward interactions.
 For example we might have code of the sort:

 `if checkError() then {goto panic} else {goto foo};`

 Assuming another block also jumps to `foo` there are two ways to compile
 this block:

 {{{
 check:
     cmp R1, 0
     jnz panic
     jmp foo

 check2:
     cmp R1, 0
     jz foo
     jmp panic
 }}}

 Performance of jumps to panic is essentially meaningless so we want
 variant two which saves an instruction in each loop.

 Blocklayout however turns this into a pessimization.

 We often get something like this:
 {{{
 check:
     cmp R1, 0
     jnz panic
     jmp foo
 bar: #<other block jumping to foo>
     few ins here
     #<shortcut>jmp foo
 foo:
     ins do things
 panic:
     some
     more
     instructions
 }}}
 This seems reasonable. If we are lucky bar is small enough that when we
 jump to foo we won't even miss the cache.

 But if we optimize the check block we suddenly get:
 {{{
 check2:
     cmp R1, 0
     jz foo
     #<shortcut> jmp panic #block layout assumes we will take this path
 panic:
     some
     more
     instructions
 bar: #<other block jumping to foo>
     few ins here
     #<shortcut>jmp foo
 foo:
     ins do things
 }}}
 Clearly we don't want this because it pulls check2 and foo far apart. But
 block layout assumes the last jump is the likely one so tries to place
 `panic` right after `check2`.
 If this is a loop there is a good chance that this causes a cache miss on
 each jump to foo.

 I did play around with the block layout code but without actually having
 likelyhood info I couldn't make it work better than what we have know.
 I do want to give lowering likelyhood info into the asm stage a try sooner
 or (probably) later since I would expect that to lead to much better
 code..

 However for now I ran out of steam before I came up with a good way to
 tackle this.

 Things that need to be still done.
 - Find a good layout algorithm which can make use of partial information.
 There are descriptions for algorithms which work with full information
 about block entry counts. But Implementing one which works well on partial
 information is something I couldn't find anything on yet. Rolling my own
 is not out of the question but seems like something for a few weeks and
 not a few days.
 * Chose a design for lowering likelyhood information to the asm level. How
 isn't yet clear. Annotate the instructions? Add information about blocks
 in a sidechannel? It's also not static since things like the register
 allocator also generate new blocks on the fly. Shortcutting might remove
 blocks and so on.
 * Besides block layout if we lower that information it should also be used
 by the register allocators.

-- 
Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/14672#comment:14>
GHC <http://www.haskell.org/ghc/>
The Glasgow Haskell Compiler


More information about the ghc-tickets mailing list