Simon Peyton Jones pushed to branch wip/T27724 at Glasgow Haskell Compiler / GHC

Commits:

2 changed files:

Changes:

  • compiler/GHC/Builtin/WiredIn/Ids.hs
    ... ... @@ -602,7 +602,13 @@ Note [noinlineId magic]
    602 602
     'noinline' is used to make sure that a function f is never inlined, e.g
    
    603 603
        noinline f x
    
    604 604
        noinline (f x)
    
    605
    -Both of these will work.  Here are the moving parts:
    
    605
    +Both of these will work.  The specification is this:
    
    606
    +   - Given (noinline (f e1 .. en)) where `f` is a variable, we do not
    
    607
    +     inline f, but we optimise e1..en freely.
    
    608
    +   - If instead we have (noinline e) where `e` is not an application headed
    
    609
    +     by a variable, we switch off inlining throughout `e`.
    
    610
    +
    
    611
    +Here are the moving parts:
    
    606 612
     
    
    607 613
     * `noinline` is magic Id (see Note [magicIds]), whose wired-in behaviour is
    
    608 614
       defined in this module,  GHC.Builtin.WiredIn.Ids.
    
    ... ... @@ -679,6 +685,19 @@ Wrinkles
    679 685
        so for now we simply disable (NOI1) magic if pushing arguments inward would result
    
    680 686
        in an argument that doesn't have a fixed runtime rep.
    
    681 687
     
    
    688
    +(NOI7) Consider
    
    689
    +            noinline (case x of ...) arg
    
    690
    +            noinline (let .. in ..)  arg
    
    691
    +  We switch off inlining throughout the let/case, but we do not want to move
    
    692
    +  `arg` under the `noinline` because then we'll end up switching off inlining in
    
    693
    +  `arg` too.  So don't move anything inside the `noinline`.
    
    694
    +
    
    695
    +  Less happily, the same happens for SCC ticks:
    
    696
    +     noinline ({-# SCC "foo" #-} f arg1) arg2
    
    697
    +  The bit inside the `noinline` isn't a plain variable-headed application, so
    
    698
    +  we just simplify the whole `noinline` argument with inlining switched off,
    
    699
    +  like let/case.
    
    700
    +
    
    682 701
     Note [nospecId magic]
    
    683 702
     ~~~~~~~~~~~~~~~~~~~~~
    
    684 703
     The 'nospec' magic Id is used to ensure to make a value opaque to the typeclass
    

  • compiler/GHC/Core/Opt/Simplify/Iteration.hs
    ... ... @@ -2375,28 +2375,26 @@ simplOutId env fun cont
    2375 2375
     simplOutId env noinline_fun cont
    
    2376 2376
       | isNoinlineId noinline_fun
    
    2377 2377
       , ApplyToTy  { sc_cont = cont1 } <- cont
    
    2378
    -  , ApplyToTy  { sc_cont = cont2 } <- cont1
    
    2379
    -  , ApplyToVal { sc_cont = cont3, sc_arg = the_call, sc_cast = arg_mco
    
    2378
    +  , ApplyToTy  { sc_cont = cont2, sc_arg_ty = call_ty } <- cont1
    
    2379
    +  , ApplyToVal { sc_cont = cont3, sc_arg = the_call, sc_cast = call_mco
    
    2380 2380
                    , sc_env = UnSimplified arg_se } <- cont2
    
    2381 2381
       , let -- encl_app_cont collects any /arguments/ from `cont3`
    
    2382 2382
             (encl_app_cont, rest_cont) = splitContArgs cont3
    
    2383 2383
             new_call_ty                = contHoleType rest_cont
    
    2384
    -  , typeHasFixedRuntimeRep new_call_ty  -- See (NOI6) in Note [noinlineId magic]
    
    2385
    -  = do { -- Push any arguments in `the_call` onto `encl_app_cont`
    
    2386
    -         let push_args :: InExpr -> SimplCont -> SimplM (InExpr, SimplCont)
    
    2387
    -             -- push_args just pushes multiple arguments onto the continuation
    
    2388
    -             push_args (Cast f co) cont = do { cont' <- pushInCast arg_se co cont
    
    2389
    -                                             ; push_args f cont' }
    
    2390
    -             push_args (App f a)   cont = do { cont' <- pushAppCont arg_se f a cont
    
    2391
    -                                             ; push_args f cont' }
    
    2392
    -             push_args fun         cont = return (fun, cont)
    
    2393
    -       ;  (inner_fun, call_cont) <- push_args the_call $
    
    2394
    -                                    addCastMCo arg_mco $
    
    2395
    -                                    encl_app_cont
    
    2396
    -
    
    2397
    -       -- Now simplify the function itself, crucially setting sm_inline = False
    
    2398
    -       -- The /arguments/, in `call_cont` will be simplified with their own
    
    2399
    -       -- flags, captured in `arg_se`
    
    2384
    +  = do { (inner_fun, call_cont, outer_cont)
    
    2385
    +             <- -- See Note [noinlineId magic]...
    
    2386
    +                if var_at_head the_call &&             -- (NOI7)
    
    2387
    +                   typeHasFixedRuntimeRep new_call_ty  -- (NOI6)
    
    2388
    +                then do { (inner_fun, call_cont) <- push_args arg_se the_call $
    
    2389
    +                                                    addCastMCo call_mco       $
    
    2390
    +                                                    encl_app_cont
    
    2391
    +                        ; return (inner_fun, call_cont, rest_cont) }
    
    2392
    +                else do { let call_stop = addCastMCo call_mco (mkBoringStop call_ty)
    
    2393
    +                        ; return (the_call, call_stop, cont3) }
    
    2394
    +
    
    2395
    +       -- Now simplify the function itself, in call_cont, crucially setting
    
    2396
    +       -- sm_inline = False. The /arguments/ in `call_cont` will be simplified
    
    2397
    +       -- with their own flags, captured in `arg_se`
    
    2400 2398
            ; let call_env = updMode updModeForNoInline $
    
    2401 2399
                             arg_se `setInScopeFromE` env
    
    2402 2400
            ; (floats1, call1) <- wrapJoinFloatsX $
    
    ... ... @@ -2404,16 +2402,29 @@ simplOutId env noinline_fun cont
    2404 2402
                  -- wrapJoinFloatsX: any floating join bindings must stay
    
    2405 2403
                  --                  around the call, not be floated out
    
    2406 2404
     
    
    2407
    -       -- Now `rebuild` does the rest
    
    2405
    +       -- Now `rebuild` does the rest, wrapping in outer_cont
    
    2408 2406
            ; let (new_noinline_fun, rep) = getNoinlineId new_call_ty
    
    2409 2407
                  noinline_expr = Var new_noinline_fun
    
    2410 2408
                                  `App` Type rep
    
    2411 2409
                                  `App` Type new_call_ty
    
    2412 2410
                                  `App` call1
    
    2413 2411
            ; (floats2, res) <- rebuild (env `setInScopeFromF` floats1)
    
    2414
    -                                   noinline_expr rest_cont
    
    2412
    +                                   noinline_expr outer_cont
    
    2415 2413
            ; return (floats1 `addFloats` floats2 , res) }
    
    2416 2414
       where
    
    2415
    +    var_at_head :: CoreExpr -> Bool
    
    2416
    +    var_at_head (Var {})   = True
    
    2417
    +    var_at_head (App f _)  = var_at_head f
    
    2418
    +    var_at_head (Cast f _) = var_at_head f
    
    2419
    +    var_at_head _          = False
    
    2420
    +
    
    2421
    +    push_args :: SimplEnv -> InExpr -> SimplCont -> SimplM (InExpr, SimplCont)
    
    2422
    +    -- push_args just pushes multiple arguments onto the continuation
    
    2423
    +    push_args arg_se (Cast f co) cont = do { cont' <- pushInCast arg_se co cont
    
    2424
    +                                           ; push_args arg_se f cont' }
    
    2425
    +    push_args arg_se (App f a)   cont = do { cont' <- pushAppCont arg_se f a cont
    
    2426
    +                                           ; push_args arg_se f cont' }
    
    2427
    +    push_args _      fun         cont = return (fun, cont)
    
    2417 2428
     
    
    2418 2429
     -----------------------
    
    2419 2430
     -- General fall-through case for (f e1 .. en)