Ticket #2070 (closed bug: fixed)

Opened 5 years ago

Last modified 5 years ago

Record field selectors are not optimized

Reported by: twanvl Owned by:
Priority: normal Milestone:
Component: Compiler Version: 6.9
Keywords: Cc:
Operating System: Unknown/Multiple Architecture: Unknown/Multiple
Type of failure: Difficulty: Unknown
Test Case: Blocked By:
Blocking: Related Tickets:

Description

It seems that record field selectors are not optimized. Usually this doesn't matter, but when there are unpacked fields this leaves suboptimal code. The equivalent code using the data type constructor is optimized.

For example:

module Test where

data Test = Test { getR :: {-# UNPACK #-} !Int }
getC (Test a) = a

Generates the following core (with -O2 -ddump-simpl):

Test.getR :: Test.Test -> GHC.Base.Int
[RecSel]
[Arity 1
 NoCafRefs
 Str: DmdType U(L)m]
Test.getR =
  \ (tpl_B1 :: Test.Test) ->
    case tpl_B1 of tpl1_B2 { Test.Test rb_B4 ->
    let {
      ipv_B3 [Just S] :: GHC.Base.Int
      [Str: DmdType m]
      ipv_B3 = GHC.Base.I# rb_B4
    } in  ipv_B3
    }

Test.getC :: Test.Test -> GHC.Base.Int
[GlobalId]
[Arity 1
 NoCafRefs
 Str: DmdType U(L)m]
Test.getC =
  \ (ds_d5Q :: Test.Test) ->
    case ds_d5Q of wild_B1 { Test.Test rb_d5S -> GHC.Base.I# rb_d5S }

After further investigation, it seems that getR is not passed through the optimizer at all, earlier simplifier passes (-ddump-simpl-iterations, -ddump-cse, -ddump-occur-anal) do not include the function.

Change History

Changed 5 years ago by simonpj

  • difficulty set to Unknown

Here's another example, found by Twan van Laarhoven, in GHC itself, module Var.lhs.

When also trying to change the FastInt in Var to an unpacked Unique I ran into #2070. If I write it out varUnique manually I do get a good result, but not exactly the same. In particular I get:

   NewVar.varUnique =
     \r [ds]
        case ds of wild {
          NewVar.TyVar    ds1 rb ds2 ds3 -> GHC.Base.I# [rb];
          NewVar.TcTyVar  ds1 rb ds2 ds3 -> GHC.Base.I# [rb];
          NewVar.GlobalId ds1 rb ds2 ds3 ds4 -> GHC.Base.I# [rb];
          NewVar.LocalId  ds1 rb ds2 ds3 ds4 -> GHC.Base.I# [rb];
        };

But the automatically generated one looks like this:

   OldVar.varUnique =
     \r [var]
        case
            case var of tpl {
              OldVar.TyVar    ipv ipv1 ipv2 ipv3 -> ipv1;
              OldVar.TcTyVar  ipv ipv1 ipv2 ipv3 -> ipv1;
              OldVar.GlobalId ipv ipv1 ipv2 ipv3 ipv4 -> ipv1;
              OldVar.LocalId  ipv ipv1 ipv2 ipv3 ipv4 -> ipv1;
            }
        of
        wild
        { __DEFAULT -> GHC.Base.I# [wild];
        };

In other words, the boxing is taken out of the case branches. I don't know whether this is an improvement or not. It might reduce code size.

This function is inlined in the comparison operators, here the difference becomes larger. The new code looks like (pseudocode):

   NewVar.== a b
      = case a of
                TyVar _ c _ _ ->
                      case b of
                          TyVar    _ d _ _   -> c ==# d
                          TcTyVar  _ d _ _   -> c ==# d
                          GlobalId _ d _ _ _ -> c ==# d
                          LocalId  _ d _ _ _ -> c ==# d
                 TcTyVar _ c _ _ ->
                      etc.

Here varUnique b is inlined for each branch of varUnique a. Whereas the old code is a lot shorter, because the unique of the first parameter is first put into a variable,

  OldVar.== a b
      = case (case a of
                 TyVar    _ c _ _   -> c
                 TcTyVar  _ c _ _   -> c
                 GlobalId _ c _ _ _ -> c
                 LocalId  _ c _ _ _ -> c
             ) of
          c -> case (case b of
                 TyVar    _ d _ _   -> d
                 TcTyVar  _ d _ _   -> d
                 GlobalId _ d _ _ _ -> d
                 LocalId  _ d _ _ _ -> d
             ) of
          d -> c ==# d

Changed 5 years ago by simonpj

  • status changed from new to closed
  • resolution set to fixed

This patch should fix it

Tue Feb  5 16:55:07 GMT Standard Time 2008  simonpj@microsoft.com
  * Inject implicit bindings before the simplifier (Trac #2070)

No need to merge to the 6.8 branch.

I'm not sure how to make a decent test for this, so I'm just closing it. If someone can dream up a test, that'd be good.

Simon

Changed 5 years ago by simonmar

  • architecture changed from Unknown to Unknown/Multiple

Changed 5 years ago by simonmar

  • os changed from Unknown to Unknown/Multiple
Note: See TracTickets for help on using tickets.