Opened 21 months ago

Last modified 18 months ago

#7114 new bug

Cannot recover (good) inlining behaviour from 7.0.2 in 7.4.1

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

Description

(I'm sorry that this test case is so large.)

The attached module Code3.hs is a highly simplified version of a generic implementation of enumeration, followed by its instantiation to a datatype of lists of integers. The goal is to drive the simplifier to fully specialise the generic version to an optimised version for lists, without any reference to the generic representation constructors.

With GHC 7.0.2, the (interesting part of the) attached module compiles to the following core code (my renaming):

enumNil :: [Code2.List]
[GblId, Caf=NoCafRefs]
enumNil =
  GHC.Types.: @ Code2.List Code2.Nil (GHC.Types.[] @ Code2.List)

Rec {
lvl1_roO :: GHC.Types.Int -> [Code2.List]
[GblId, Arity=1]
lvl1_roO =
  \ (x_XnO :: GHC.Types.Int) ->
    GHC.Base.map
      @ Code2.List
      @ Code2.List
      (\ (x1_XnN :: Code2.List) -> Code2.Cons x_XnO x1_XnN)
      enumList

lvl2_roR :: [[Code2.List]]
[GblId]
lvl2_roR =
  GHC.Base.map
    @ GHC.Types.Int @ [Code2.List] lvl1_roO enumInt

enumCons :: [Code2.List]
[GblId]
enumCons = Code2.diag @ Code2.List lvl2_roR

enumList [Occ=LoopBreaker] :: [Code2.List]
[GblId, Str=DmdType]
enumList = Code2.||| @ Code2.List enumNil enumCons
end Rec }

This is exactly what is intended: no more generic representation stuff. GHC 7.4.1, however, doesn't quite achieve this, instead leaving us with the following:

enumNil :: [Code2.List]
[GblId, Caf=NoCafRefs]
enumNil =
  GHC.Types.: @ Code2.List Code2.Nil (GHC.Types.[] @ Code2.List)

Rec {
a_rme :: [Code2.K1 Code2.List]
[GblId, Str=DmdType]
a_rme =
  GHC.Base.map
    @ Code2.List
    @ (Code2.K1 Code2.List)
    (Code2.K1 @ Code2.List)
    enumList

lvl1_rmf :: GHC.Types.Int -> [Code2.List]
[GblId, Arity=1]
lvl1_rmf =
  \ (x_Xmk :: GHC.Types.Int) ->
    GHC.Base.map
      @ (Code2.K1 Code2.List)
      @ Code2.List
      (\ (x1_Xn9 :: Code2.K1 Code2.List) ->
         case x1_Xn9 of _ { Code2.K1 b_aaM -> Code2.Cons x_Xmk b_aaM })
      a_rme

lvl2_rmg :: [[Code2.List]]
[GblId]
lvl2_rmg =
  GHC.Base.map
    @ GHC.Types.Int @ [Code2.List] lvl1_rmf enumInt

enumCons :: [Code2.List]
[GblId]
enumCons = Code2.diag @ Code2.List lvl2_rmg

enumList [Occ=LoopBreaker] :: [Code2.List]
[GblId, Str=DmdType]
enumList = Code2.||| @ Code2.List enumNil enumCons
end Rec }

The strange part is the interaction between the lvl1_rmf and a_rme functions: basically a_rme maps K1 over a list, and lvl1_rmf maps a function that takes this K1 away.

I have no idea why 7.4.1 leaves this residue around. I have played with different inline pragmas and rewrite rules, but so far have been unable to convince GHC 7.4.1 to just do what 7.0.2 did. Turning K1 into a newtype doesn't help (we're left with a newtype coercion instead).

Attachments (1)

Code3.hs (2.7 KB) - added by dreixel 21 months ago.

Download all attachments as: .zip

Change History (3)

Changed 21 months ago by dreixel

comment:1 Changed 20 months ago by nfrisby

  • Cc nfrisby added

comment:2 Changed 18 months ago by igloo

  • Difficulty set to Unknown
  • Milestone set to 7.8.1

Thanks for the report

Note: See TracTickets for help on using tickets.