Florian Ragwitz pushed to branch wip/rafl/hpc-instances at Glasgow Haskell Compiler / GHC

Commits:

28 changed files:

Changes:

  • changelog.d/T27764
    1
    +section: compiler
    
    2
    +synopsis: Fix bug in ``static`` forms
    
    3
    +issues: #27664
    
    4
    +mrs: !16624
    
    5
    +description: A ``static`` form should have no free *term* variables, but it
    
    6
    +  can have free *type* variables.  Alas, the renamer does not really know what
    
    7
    +  is a term variable and what is a type variable, because of required type
    
    8
    +  arguments. This patch moves the test to the typechecker, which does know.

  • changelog.d/hpc-classinsts
    1
    +section: compiler
    
    2
    +synopsis: Improve coverage reporting for class instances and their methods
    
    3
    +description:
    
    4
    +
    
    5
    +  Coverage reporting (:ghc-flag:`-fhpc`) now treats class instances more
    
    6
    +  naturally.
    
    7
    +
    
    8
    +  Compiler-generated instance methods, such as inherited default methods, no
    
    9
    +  longer receive separate top-level coverage boxes. Explicitly implemented
    
    10
    +  instance methods retain their own declaration coverage.
    
    11
    +
    
    12
    +  This means that it is no longer necessary to exercise all of a class' methods
    
    13
    +  in order for it to appear "covered".
    
    14
    +
    
    15
    +  Additionally, top-level coverage boxes are now created for all instances of
    
    16
    +  classes with methods, and ticked by the use of *any* of the class' methods.
    
    17
    +  This indicates that an instance was in fact used at run-time.
    
    18
    +
    
    19
    +  Note that classes without any instance methods are currently excluded from
    
    20
    +  this, and won't have any coverage boxes created.
    
    21
    +
    
    22
    +mrs: !16632
    
    23
    +issues: #17155

  • changelog.d/ncg-x86-bit-test-instructions
    1
    +section: compiler
    
    2
    +synopsis: The x86 native code generator now uses the bit-test instructions
    
    3
    +  ``btr``/``bts``/``btc`` to clear, set or complement a single bit
    
    4
    +description:
    
    5
    +  Cmm patterns such as ``x & ~(1 << i)``, ``x | (1 << i)`` and
    
    6
    +  ``x ^ (1 << i)`` now compile to a single ``btr``/``bts``/``btc``
    
    7
    +  instruction instead of a mov/shl/not/and-style sequence, matching what C
    
    8
    +  compilers produce. The same applies to the literal masks that constant
    
    9
    +  folding produces from these patterns when ``i`` is constant, in the cases
    
    10
    +  where the mask doesn't fit in an imm32 operand.
    
    11
    +
    
    12
    +  For a variable bit index this applies only when the shift is unchecked,
    
    13
    +  as with ``uncheckedShiftL#`` or ``Data.Bits.unsafeShiftL``. The
    
    14
    +  bounds-checked ``shiftL`` — used, for example, by the default
    
    15
    +  implementations of ``clearBit``, ``setBit`` and ``complementBit`` —
    
    16
    +  wraps the shift in a bounds mask that this optimisation does not see
    
    17
    +  through. With a literal index, the bounds mask is constant-folded away,
    
    18
    +  so the checked operations benefit too.
    
    19
    +mrs: !16311
    
    20
    +issues: #25233

  • compiler/GHC/CmmToAsm/X86/CodeGen.hs
    ... ... @@ -1442,6 +1442,22 @@ getRegister' platform is32Bit (CmmMachOp mop [x]) = do -- unary MachOps
    1442 1442
                                         (PUNPCKLQDQ fmt (OpReg dst) dst)
    
    1443 1443
                                         )
    
    1444 1444
     
    
    1445
    +-- Use the bit-test instructions btr/bts/btc for clearing, setting and
    
    1446
    +-- complementing a single bit: e.g. x .&. complement (1 `shiftL` i) is btr.
    
    1447
    +-- See Note [Bit-test instructions].
    
    1448
    +getRegister' platform is32Bit (CmmMachOp (MO_And w) [x, y])
    
    1449
    +  | bitTestOpWidthOK is32Bit w
    
    1450
    +  , Just (opnd, ix) <- clearBitArgs_maybe platform w x y
    
    1451
    +  = genBitTestCode (intFormat w) BTR opnd ix
    
    1452
    +getRegister' platform is32Bit (CmmMachOp (MO_Or w) [x, y])
    
    1453
    +  | bitTestOpWidthOK is32Bit w
    
    1454
    +  , Just (opnd, ix) <- setBitArgs_maybe platform w x y
    
    1455
    +  = genBitTestCode (intFormat w) BTS opnd ix
    
    1456
    +getRegister' platform is32Bit (CmmMachOp (MO_Xor w) [x, y])
    
    1457
    +  | bitTestOpWidthOK is32Bit w
    
    1458
    +  , Just (opnd, ix) <- setBitArgs_maybe platform w x y
    
    1459
    +  = genBitTestCode (intFormat w) BTC opnd ix
    
    1460
    +
    
    1445 1461
     getRegister' platform is32Bit (CmmMachOp mop [x, y]) = do -- dyadic MachOps
    
    1446 1462
       sse4_1 <- sse4_1Enabled
    
    1447 1463
       sse4_2 <- sse4_2Enabled
    
    ... ... @@ -5883,6 +5899,138 @@ genTrivialCode rep instr a b = do
    5883 5899
                     instr b_op dst
    
    5884 5900
       return (Any rep code)
    
    5885 5901
     
    
    5902
    +{- Note [Bit-test instructions]
    
    5903
    +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    5904
    +x86 has dedicated instructions for clearing (btr), setting (bts) and
    
    5905
    +complementing (btc) a single bit whose index is given in a register.  We use
    
    5906
    +them for Cmm patterns such as
    
    5907
    +
    
    5908
    +  x & ~(1 << i)     ==>     btr i, x       (#25233)
    
    5909
    +
    
    5910
    +replacing a mov/shl/not/and sequence with a single instruction.  The
    
    5911
    +shift-count register operand of shl is masked modulo the operand width, and
    
    5912
    +the bit-offset register operand of btr/bts/btc is masked the same way, so
    
    5913
    +the replacement is faithful even for out-of-range i (where the Cmm shift is
    
    5914
    +in any case undefined).
    
    5915
    +
    
    5916
    +The bit-offset operand of these instructions must be an immediate or a
    
    5917
    +register.  When the bit index is a literal, no shift reaches the NCG:
    
    5918
    +constant folding has already turned the whole mask into a literal.  If that
    
    5919
    +mask fits in an imm32, we keep the ordinary and/or/xor with an immediate:
    
    5920
    +it has the same latency and better throughput (more execution ports) than
    
    5921
    +the bit-test instructions,  and at worst two bytes of extra code size for bit
    
    5922
    +indices 7..30.
    
    5923
    +But a W64 mask touching the upper bits, e.g. ~(1 << 40), would have to be moved
    
    5924
    +into a register first.  For such masks we recognise the folded literal itself
    
    5925
    +(exactly one bit clear resp. set) and emit btr/bts/btc with an immediate
    
    5926
    +bit offset.
    
    5927
    +
    
    5928
    +We restrict the pattern to W32 and native-width W64: the instructions do not
    
    5929
    +exist at width 8, and sub-word Cmm operations at W8/W16 are rare enough that
    
    5930
    +they are not worth the extra care.
    
    5931
    +-}
    
    5932
    +
    
    5933
    +-- | Match @1 << i@, returning @i@.
    
    5934
    +--
    
    5935
    +-- The returned expression is always at word width ('machOpArgReps' fixes
    
    5936
    +-- shift amounts at 'wordWidth'). See Note [Bit-test instructions].
    
    5937
    +singleBit_maybe :: CmmExpr -> Maybe CmmExpr
    
    5938
    +singleBit_maybe (CmmMachOp (MO_Shl _) [CmmLit (CmmInt 1 _), i]) = Just i
    
    5939
    +singleBit_maybe _ = Nothing
    
    5940
    +
    
    5941
    +-- | If exactly one bit of @m@, taken at width @w@, is set, return its index.
    
    5942
    +--
    
    5943
    +-- See Note [Bit-test instructions].
    
    5944
    +setBitLit_maybe :: Width -> Integer -> Maybe Int
    
    5945
    +setBitLit_maybe w m
    
    5946
    +  | popCount m' == 1 = Just (countTrailingZeros m')
    
    5947
    +  | otherwise        = Nothing
    
    5948
    +  where
    
    5949
    +    -- w <= W64 in this X86-specific code, so a Word64 suffices.
    
    5950
    +    m' = fromInteger (narrowU w m) :: Word64
    
    5951
    +
    
    5952
    +-- | If exactly one bit of @m@, taken at width @w@, is clear, return its
    
    5953
    +-- index.
    
    5954
    +--
    
    5955
    +-- See Note [Bit-test instructions].
    
    5956
    +clearBitLit_maybe :: Width -> Integer -> Maybe Int
    
    5957
    +clearBitLit_maybe w m = setBitLit_maybe w (complement m)
    
    5958
    +
    
    5959
    +bitTestOpWidthOK :: Bool -> Width -> Bool
    
    5960
    +bitTestOpWidthOK is32Bit w = w == W32 || (w == W64 && not is32Bit)
    
    5961
    +
    
    5962
    +-- | The bit-offset operand of a bit-test instruction (btr/bts/btc).
    
    5963
    +data BitIndex
    
    5964
    +  = BitIndexReg CmmExpr  -- ^ variable index, computed into a register
    
    5965
    +  | BitIndexImm Int      -- ^ literal index, emitted as an immediate
    
    5966
    +
    
    5967
    +-- | Match the operands of a single-bit set or complement operation: one
    
    5968
    +-- operand is a mask @1 << i@, or a literal with exactly one bit set that
    
    5969
    +-- does not fit in an imm32. Returns the other operand and the bit index.
    
    5970
    +--
    
    5971
    +-- Both operand orders are matched, e.g. @x | (1 << i)@ and @(1 << i) | x@.
    
    5972
    +--
    
    5973
    +-- See Note [Bit-test instructions].
    
    5974
    +setBitArgs_maybe :: Platform -> Width -> CmmExpr -> CmmExpr
    
    5975
    +                 -> Maybe (CmmExpr, BitIndex)
    
    5976
    +setBitArgs_maybe platform w x y = go x y `mplus` go y x
    
    5977
    +  where
    
    5978
    +    go opnd mask
    
    5979
    +      | Just i <- singleBit_maybe mask
    
    5980
    +      = Just (opnd, BitIndexReg i)
    
    5981
    +      | CmmLit lit@(CmmInt m _) <- mask
    
    5982
    +      , Just i <- setBitLit_maybe w m
    
    5983
    +      , not (is32BitLit platform lit)
    
    5984
    +      = Just (opnd, BitIndexImm i)
    
    5985
    +      | otherwise
    
    5986
    +      = Nothing
    
    5987
    +
    
    5988
    +-- | As 'setBitArgs_maybe', for a single-bit clear operation: the mask is
    
    5989
    +-- @~(1 << i)@, or a literal with exactly one bit clear.
    
    5990
    +clearBitArgs_maybe :: Platform -> Width -> CmmExpr -> CmmExpr
    
    5991
    +                   -> Maybe (CmmExpr, BitIndex)
    
    5992
    +clearBitArgs_maybe platform w x y = go x y `mplus` go y x
    
    5993
    +  where
    
    5994
    +    go opnd mask
    
    5995
    +      | CmmMachOp (MO_Not _) [b] <- mask
    
    5996
    +      , Just i <- singleBit_maybe b
    
    5997
    +      = Just (opnd, BitIndexReg i)
    
    5998
    +      | CmmLit lit@(CmmInt m _) <- mask
    
    5999
    +      , Just i <- clearBitLit_maybe w m
    
    6000
    +      , not (is32BitLit platform lit)
    
    6001
    +      = Just (opnd, BitIndexImm i)
    
    6002
    +      | otherwise
    
    6003
    +      = Nothing
    
    6004
    +
    
    6005
    +-- | Generate code for @dst := x@ followed by a bit-test instruction
    
    6006
    +-- (btr/bts/btc).
    
    6007
    +--
    
    6008
    +-- See Note [Bit-test instructions].
    
    6009
    +genBitTestCode :: Format -> (Format -> Operand -> Operand -> Instr)
    
    6010
    +               -> CmmExpr -> BitIndex -> NatM Register
    
    6011
    +genBitTestCode rep instr x (BitIndexImm i) = do
    
    6012
    +  x_code <- getAnyReg x
    
    6013
    +  let code dst = x_code dst `snocOL` instr rep (OpImm (ImmInt i)) (OpReg dst)
    
    6014
    +  return (Any rep code)
    
    6015
    +genBitTestCode rep instr x (BitIndexReg i) = do
    
    6016
    +  (i_reg, i_code) <- getNonClobberedReg i
    
    6017
    +  x_code <- getAnyReg x
    
    6018
    +  tmp <- getNewRegNat rep
    
    6019
    +  let
    
    6020
    +     -- As in genTrivialCode, 'i' must stay alive across the computation of
    
    6021
    +     -- 'x' into dst, so save it in a temporary if dst holds 'i'.
    
    6022
    +     code dst
    
    6023
    +        | dst == i_reg =
    
    6024
    +                i_code `appOL`
    
    6025
    +                unitOL (MOV rep (OpReg i_reg) (OpReg tmp)) `appOL`
    
    6026
    +                x_code dst `snocOL`
    
    6027
    +                instr rep (OpReg tmp) (OpReg dst)
    
    6028
    +        | otherwise =
    
    6029
    +                i_code `appOL`
    
    6030
    +                x_code dst `snocOL`
    
    6031
    +                instr rep (OpReg i_reg) (OpReg dst)
    
    6032
    +  return (Any rep code)
    
    6033
    +
    
    5886 6034
     regClashesWithOp :: Reg -> Operand -> Bool
    
    5887 6035
     reg `regClashesWithOp` OpReg reg2   = reg == reg2
    
    5888 6036
     reg `regClashesWithOp` OpAddr amode = any (==reg) (addrModeRegs amode)
    

  • compiler/GHC/CmmToAsm/X86/Instr.hs
    ... ... @@ -193,6 +193,12 @@ data Instr
    193 193
             | SHLD        Format Operand{-amount-} Operand Operand
    
    194 194
     
    
    195 195
             | BT          Format Imm Operand
    
    196
    +        -- | Bit test-and-reset
    
    197
    +        | BTR         Format Operand{- ^ bit offset (imm/reg) -} Operand
    
    198
    +        -- | Bit set
    
    199
    +        | BTS         Format Operand{- ^ bit offset (imm/reg) -} Operand
    
    200
    +        -- | Bit complement
    
    201
    +        | BTC         Format Operand{- ^ bit offset (imm/reg) -} Operand
    
    196 202
             | NOP
    
    197 203
     
    
    198 204
     
    
    ... ... @@ -496,6 +502,9 @@ regUsageOfInstr platform instr
    496 502
         SHLD   fmt imm dst1 dst2 -> usageRMM fmt imm dst1 dst2
    
    497 503
         SHRD   fmt imm dst1 dst2 -> usageRMM fmt imm dst1 dst2
    
    498 504
         BT     fmt _   src    -> mkRUR (use_R fmt src [])
    
    505
    +    BTR    fmt off dst    -> usageRM fmt off dst
    
    506
    +    BTS    fmt off dst    -> usageRM fmt off dst
    
    507
    +    BTC    fmt off dst    -> usageRM fmt off dst
    
    499 508
     
    
    500 509
         PUSH   fmt op         -> mkRUR (use_R fmt op [])
    
    501 510
         POP    fmt op         -> mkRU [] (def_W fmt op)
    
    ... ... @@ -830,6 +839,9 @@ patchRegsOfInstr platform instr env
    830 839
         SHLD fmt imm dst1 dst2 -> patch2 (SHLD fmt imm) dst1 dst2
    
    831 840
         SHRD fmt imm dst1 dst2 -> patch2 (SHRD fmt imm) dst1 dst2
    
    832 841
         BT   fmt imm src     -> patch1 (BT  fmt imm) src
    
    842
    +    BTR  fmt off dst     -> patch2 (BTR fmt) off dst
    
    843
    +    BTS  fmt off dst     -> patch2 (BTS fmt) off dst
    
    844
    +    BTC  fmt off dst     -> patch2 (BTC fmt) off dst
    
    833 845
         TEST fmt src dst     -> patch2 (TEST fmt) src dst
    
    834 846
         CMP  fmt src dst     -> patch2 (CMP  fmt) src dst
    
    835 847
         PUSH fmt op          -> patch1 (PUSH fmt) op
    

  • compiler/GHC/CmmToAsm/X86/Ppr.hs
    ... ... @@ -862,6 +862,15 @@ pprInstr platform i = case i of
    862 862
        BT format imm src
    
    863 863
           -> pprFormatImmOp (text "bt") format imm src
    
    864 864
     
    
    865
    +   BTR format off dst
    
    866
    +      -> pprFormatOpOp (text "btr") format off dst
    
    867
    +
    
    868
    +   BTS format off dst
    
    869
    +      -> pprFormatOpOp (text "bts") format off dst
    
    870
    +
    
    871
    +   BTC format off dst
    
    872
    +      -> pprFormatOpOp (text "btc") format off dst
    
    873
    +
    
    865 874
        CMP format src dst
    
    866 875
          | isFloatFormat format -> pprFormatOpOp (text "ucomi") format src dst -- SSE2
    
    867 876
          | otherwise            -> pprFormatOpOp (text "cmp")   format src dst
    

  • compiler/GHC/Hs/Expr.hs
    ... ... @@ -39,6 +39,7 @@ import GHC.Tc.Types.ErrCtxt
    39 39
     import GHC.Types.Id.Info ( RecSelParent )
    
    40 40
     import GHC.Types.Name
    
    41 41
     import GHC.Types.Name.Reader
    
    42
    +import GHC.Types.Name.Set( FreeNames )
    
    42 43
     import GHC.Types.Basic
    
    43 44
     import GHC.Types.Fixity
    
    44 45
     import GHC.Types.SourceText
    
    ... ... @@ -363,7 +364,9 @@ type instance XArithSeq GhcTc = PostTcExpr
    363 364
     type instance XProc          (GhcPass _) = (EpToken "proc", TokRarrow)
    
    364 365
     
    
    365 366
     type instance XStatic        GhcPs = EpToken "static"
    
    366
    -type instance XStatic        GhcRn = NoExtField
    
    367
    +type instance XStatic        GhcRn = FreeNames
    
    368
    +  -- Free variables of the body; we can't tell if they are
    
    369
    +  -- type or term variables until we are typechecking
    
    367 370
     type instance XStatic        GhcTc = (Type, HsExpr GhcTc)
    
    368 371
       -- Type of expression, and the (fromStaticPtr function)
    
    369 372
       -- These are stored for convenience as the wiring in
    

  • compiler/GHC/HsToCore.hs
    ... ... @@ -147,6 +147,7 @@ deSugar hsc_env
    147 147
                                 tcg_tcs          = tcs,
    
    148 148
                                 tcg_default_exports = defaults,
    
    149 149
                                 tcg_insts        = insts,
    
    150
    +                            tcg_inst_meths   = inst_meths,
    
    150 151
                                 tcg_fam_insts    = fam_insts,
    
    151 152
                                 tcg_complete_matches = complete_matches,
    
    152 153
                                 tcg_self_boot    = self_boot
    
    ... ... @@ -170,7 +171,8 @@ deSugar hsc_env
    170 171
                                            (hsc_logger hsc_env)
    
    171 172
                                            (initTicksConfig (hsc_dflags hsc_env))
    
    172 173
                                            mod mod_loc
    
    173
    -                                       export_set (typeEnvTyCons type_env) binds
    
    174
    +                                       export_set (typeEnvTyCons type_env)
    
    175
    +                                       insts inst_meths binds
    
    174 176
                                   else return (binds, Nothing)
    
    175 177
             ; let modBreaks
    
    176 178
                     | Just (_, _, breakpointSpecs) <- m_tickInfo
    

  • compiler/GHC/HsToCore/Ticks.hs
    ... ... @@ -5,7 +5,7 @@
    5 5
     {-
    
    6 6
     (c) Galois, 2006
    
    7 7
     (c) University of Glasgow, 2007
    
    8
    -(c) Florian Ragwitz, 2025
    
    8
    +(c) Florian Ragwitz, 2025-2026
    
    9 9
     -}
    
    10 10
     
    
    11 11
     module GHC.HsToCore.Ticks
    
    ... ... @@ -24,6 +24,8 @@ import GHC.Unit
    24 24
     
    
    25 25
     import GHC.Core.Type
    
    26 26
     import GHC.Core.TyCon
    
    27
    +import GHC.Core.InstEnv
    
    28
    +import GHC.Core.Class
    
    27 29
     
    
    28 30
     import GHC.Data.Maybe
    
    29 31
     import GHC.Data.FastString
    
    ... ... @@ -56,6 +58,7 @@ import Data.Foldable (toList)
    56 58
     import Trace.Hpc.Mix
    
    57 59
     
    
    58 60
     import Data.Bifunctor (second)
    
    61
    +import Data.Functor
    
    59 62
     import Data.List.NonEmpty (NonEmpty (..))
    
    60 63
     import Data.Set (Set)
    
    61 64
     import qualified Data.Set as Set
    
    ... ... @@ -100,11 +103,13 @@ addTicksToBinds
    100 103
                                     -- isExportedId doesn't work yet (the desugarer
    
    101 104
                                     -- hasn't set it), so we have to work from this set.
    
    102 105
             -> [TyCon]              -- ^ Type constructors in this module
    
    106
    +        -> [ClsInst]
    
    107
    +        -> IdEnv DFunId
    
    103 108
             -> LHsBinds GhcTc
    
    104 109
             -> IO (LHsBinds GhcTc, Maybe (FilePath, SizedSeq Tick, SizedSeq Tick))
    
    105 110
     
    
    106 111
     addTicksToBinds logger cfg
    
    107
    -                mod mod_loc exports tyCons binds
    
    112
    +                mod mod_loc exports tyCons insts inst_meths binds
    
    108 113
       | let passes = ticks_passes cfg
    
    109 114
       , not (null passes)
    
    110 115
       , Just orig_file <- ml_hs_file mod_loc = do
    
    ... ... @@ -129,8 +134,13 @@ addTicksToBinds logger cfg
    129 134
                           , this_mod     = mod
    
    130 135
                           , tickishType  = tickish
    
    131 136
                           , recSelBinds  = emptyVarEnv
    
    137
    +                      , instMeths    = inst_meths
    
    138
    +                      , instTicks    = emptyVarEnv
    
    132 139
                           }
    
    133
    -                (binds',_,st') = unTM (addTickLHsBinds binds) env st
    
    140
    +                addTick = do
    
    141
    +                  instTicks <- allocInstTicks insts
    
    142
    +                  withEnv (\e -> e{ instTicks }) $ addTickLHsBinds binds
    
    143
    +                (binds',_,st') = unTM addTick env st
    
    134 144
                 in (binds', st')
    
    135 145
     
    
    136 146
               (binds1,st) = foldr tickPass (binds, initTTState) passes
    
    ... ... @@ -231,7 +241,7 @@ addTickLHsBind :: LHsBind GhcTc -> TM (LHsBind GhcTc)
    231 241
     addTickLHsBind (L pos (XHsBindsLR bind@(AbsBinds { abs_binds = binds
    
    232 242
                                                      , abs_exports = abs_exports
    
    233 243
                                                      }))) =
    
    234
    -  withEnv (add_rec_sels . add_inlines . add_exports) $ do
    
    244
    +  withEnv (add_inst_meths . add_rec_sels . add_inlines . add_exports) $ do
    
    235 245
           binds' <- addTickLHsBinds binds
    
    236 246
           return $ L pos $ XHsBindsLR $ bind { abs_binds = binds' }
    
    237 247
       where
    
    ... ... @@ -259,19 +269,24 @@ addTickLHsBind (L pos (XHsBindsLR bind@(AbsBinds { abs_binds = binds
    259 269
                               | ABE{ abe_poly, abe_mono } <- abs_exports
    
    260 270
                               , RecSelId{} <- [idDetails abe_poly] ] }
    
    261 271
     
    
    272
    +   add_inst_meths env =
    
    273
    +     env{ instMeths = instMeths env `extendVarEnvList`
    
    274
    +                        [ (abe_mono, dfun)
    
    275
    +                        | ABE{ abe_poly, abe_mono } <- abs_exports
    
    276
    +                        , Just dfun <- [lookupVarEnv (instMeths env) abe_poly] ] }
    
    277
    +
    
    262 278
     addTickLHsBind (L pos (funBind@(FunBind { fun_id = L _ id, fun_matches = matches }))) = do
    
    263 279
       let name = getOccString id
    
    264 280
       decl_path <- getPathEntry
    
    265 281
       density <- getDensity
    
    282
    +  env <- getEnv
    
    266 283
     
    
    267
    -  inline_ids <- liftM inlines getEnv
    
    268 284
       -- See Note [inline sccs]
    
    269 285
       let inline   = isInlinePragma (idInlinePragma id)
    
    270
    -                 || id `elemVarSet` inline_ids
    
    286
    +                 || id `elemVarSet` inlines env
    
    271 287
     
    
    272 288
       -- See Note [inline sccs]
    
    273
    -  tickish <- tickishType `liftM` getEnv
    
    274
    -  case tickish of { ProfNotes | inline -> return (L pos funBind); _ -> do
    
    289
    +  case tickishType env of { ProfNotes | inline -> return (L pos funBind); _ -> do
    
    275 290
     
    
    276 291
       -- See Note [Record-selector ticks]
    
    277 292
       selTicks <- recSelTick id
    
    ... ... @@ -294,16 +309,24 @@ addTickLHsBind (L pos (funBind@(FunBind { fun_id = L _ id, fun_matches = matches
    294 309
           toplev = null decl_path
    
    295 310
           exported = idName id `elemNameSet` exported_names
    
    296 311
     
    
    297
    -  tick <- if not blackListed &&
    
    298
    -               shouldTickBind density toplev exported simple inline
    
    312
    +  let generatedInstMeth = density == TickForCoverage
    
    313
    +        && id `elemVarEnv` instMeths env
    
    314
    +        && isGenerated (mg_origin (mg_ext matches))
    
    315
    +
    
    316
    +  tick <- if not generatedInstMeth
    
    317
    +               && not blackListed
    
    318
    +               && shouldTickBind density toplev exported simple inline
    
    299 319
                  then
    
    300 320
                     bindTick density name (locA pos) fvs
    
    301 321
                  else
    
    302 322
                     return Nothing
    
    303 323
     
    
    324
    +  instTick <- instMethTick id
    
    325
    +
    
    304 326
       let mbCons = maybe Prelude.id (:)
    
    305 327
       return $ L pos $ funBind { fun_matches = mg
    
    306
    -                           , fun_ext = second (tick `mbCons`) (fun_ext funBind) }
    
    328
    +                           , fun_ext = second ((instTick `mbCons`) . (tick `mbCons`))
    
    329
    +                                              (fun_ext funBind) }
    
    307 330
       } }
    
    308 331
       where
    
    309 332
         -- See Note [Record-selector ticks]
    
    ... ... @@ -1098,6 +1121,8 @@ data TickTransEnv = TTE { fileName :: FastString
    1098 1121
                             , this_mod     :: Module
    
    1099 1122
                             , tickishType  :: TickishType
    
    1100 1123
                             , recSelBinds  :: IdEnv DVarSet
    
    1124
    +                        , instMeths    :: IdEnv DFunId
    
    1125
    +                        , instTicks    :: IdEnv CoreTickish
    
    1101 1126
                             }
    
    1102 1127
     
    
    1103 1128
     --      deriving Show
    
    ... ... @@ -1238,6 +1263,18 @@ isBlackListed (RealSrcSpan pos _) = TM $ \ env st -> (Set.member pos (blackList
    1238 1263
     isBlackListed GeneratedSrcSpan{} = return False
    
    1239 1264
     isBlackListed UnhelpfulSpan{} = return False
    
    1240 1265
     
    
    1266
    +allocInstTicks :: [ClsInst] -> TM (IdEnv CoreTickish)
    
    1267
    +allocInstTicks insts =
    
    1268
    +    ifDensity TickForCoverage (mkVarEnv . catMaybes <$> mapM alloc insts) (pure emptyVarEnv)
    
    1269
    +  where
    
    1270
    +    alloc ClsInst{ is_dfun, is_cls }
    
    1271
    +      | null (classMethods is_cls) = pure Nothing
    
    1272
    +      | otherwise = fmap (is_dfun,) <$> allocATickBox (TopLevelBox [getOccString is_dfun])
    
    1273
    +                                                      False True (getSrcSpan is_dfun) noFVs
    
    1274
    +
    
    1275
    +instMethTick :: Id -> TM (Maybe CoreTickish)
    
    1276
    +instMethTick id = getEnv <&> \e -> lookupVarEnv (instMeths e) id >>= lookupVarEnv (instTicks e)
    
    1277
    +
    
    1241 1278
     -- the tick application inherits the source position of its
    
    1242 1279
     -- expression argument to support nested box allocations
    
    1243 1280
     allocTickBox :: BoxLabel -> Bool -> Bool -> SrcSpan -> TM (HsExpr GhcTc)
    

  • compiler/GHC/Rename/Expr.hs
    ... ... @@ -667,18 +667,7 @@ rnExpr e@(HsStatic _ expr)
    667 667
            -- Rename the payload
    
    668 668
            ; (expr',fvs) <- rnLExpr expr
    
    669 669
     
    
    670
    -       -- Check that the free variables of the static form are top-level defined
    
    671
    -       -- It's OK to use nonDetEltsUniqSet here as the only side effects of
    
    672
    -       -- checkClosedInStaticForm are error messages.
    
    673
    -       -- See (SF2) Note [Grand plan for static forms] in GHC.Iface.Tidy.StaticPtrTable
    
    674
    -       ; mapM_ check_fv (nonDetEltsUniqSet fvs)
    
    675
    -
    
    676
    -       ; return (HsStatic noExtField expr', fvs) }
    
    677
    -  where
    
    678
    -    check_fv :: Name -> RnM ()
    
    679
    -    -- Check for free vars not defined at top level
    
    680
    -    check_fv n = unless (isExternalName n) $
    
    681
    -                 addErrTc (TcRnStaticFormNotClosed n)
    
    670
    +       ; return (HsStatic fvs expr', fvs) }
    
    682 671
     
    
    683 672
     {-
    
    684 673
     ************************************************************************
    

  • compiler/GHC/Tc/Gen/Expr.hs
    ... ... @@ -602,13 +602,19 @@ tcExpr (HsProc x pat cmd) res_ty
    602 602
     -- and wrap (static e) in a call to
    
    603 603
     --    fromStaticPtr :: IsStatic p => StaticPtr a -> p a
    
    604 604
     
    
    605
    -tcExpr (HsStatic _ expr) res_ty
    
    605
    +tcExpr (HsStatic free_names expr) res_ty
    
    606 606
       = do  { res_ty          <- expTypeToType res_ty
    
    607 607
             ; (co, (p_ty, expr_ty)) <- matchExpectedAppTy res_ty
    
    608 608
             ; (expr', lie) <- captureConstraints $
    
    609 609
                               addErrCtxt (StaticFormCtxt expr) $
    
    610 610
                               tcCheckPolyExprNC expr expr_ty
    
    611 611
     
    
    612
    +        -- Check that the free variables of the static form are top-level defined
    
    613
    +        -- It's OK to use nonDetEltsUniqSet here as the only side effects of
    
    614
    +        -- checkClosedInStaticForm are error messages.
    
    615
    +        -- See (SF2) Note [Grand plan for static forms] in GHC.Iface.Tidy.StaticPtrTable
    
    616
    +        ; mapM_ check_free_name (nonDetEltsUniqSet free_names)
    
    617
    +
    
    612 618
             -- Emit an implication that captures the constraints of `expr`,
    
    613 619
             -- but with a `ic_info` of StaticFormSkol
    
    614 620
             -- See #13499 for an explanation of why this is the right thing to do:
    
    ... ... @@ -637,6 +643,24 @@ tcExpr (HsStatic _ expr) res_ty
    637 643
               HsStatic (static_expr_ty, mkHsWrap wrap fromStaticPtr)
    
    638 644
                        expr''
    
    639 645
             }
    
    646
    +  where
    
    647
    +    check_free_name :: Name -> TcM ()
    
    648
    +    -- Check for free /term/ vars not defined at top level
    
    649
    +    -- We use isExternalName as a proxy for top-level-defined
    
    650
    +    check_free_name n
    
    651
    +      = do { mb_thing <- tcLookupLcl_maybe n
    
    652
    +           ; case mb_thing of
    
    653
    +               Nothing  -> return ()  -- Imports, tycons, classes allowed
    
    654
    +               Just (ATcId {})  -> unless (isExternalName n) $
    
    655
    +                                   addErrTc (TcRnStaticFormNotClosed n)
    
    656
    +
    
    657
    +               Just (ATyVar {}) -> return ()  -- Free type variables are allowed
    
    658
    +
    
    659
    +                   -- Not really expecting these, but we'll get an error from
    
    660
    +                   -- elsewhere, so don't produce an error here
    
    661
    +               Just (ATcTyCon {})      -> return ()
    
    662
    +               Just (APromotionErr {}) -> return ()
    
    663
    +               Just (AGlobal {})       -> return () }
    
    640 664
     
    
    641 665
     tcExpr (HsEmbTy _ _)      _ = failWith (TcRnIllegalTypeExpr TypeKeywordSyntax)
    
    642 666
     tcExpr (HsQual _ _ _)     _ = failWith (TcRnIllegalTypeExpr ContextArrowSyntax)
    

  • compiler/GHC/Tc/Module.hs
    ... ... @@ -1770,7 +1770,7 @@ tcTopSrcDecls (HsGroup { hs_tyclds = tycl_decls,
    1770 1770
                     -- Second pass over class and instance declarations,
    
    1771 1771
                     -- now using the kind-checked decls
    
    1772 1772
             traceTc "Tc6" empty ;
    
    1773
    -        inst_binds <- tcInstDecls2 (tyClGroupTyClDecls tycl_decls) inst_infos ;
    
    1773
    +        (inst_binds, inst_meths) <- tcInstDecls2 (tyClGroupTyClDecls tycl_decls) inst_infos ;
    
    1774 1774
     
    
    1775 1775
                     -- Foreign exports
    
    1776 1776
             traceTc "Tc7" empty ;
    
    ... ... @@ -1802,8 +1802,9 @@ tcTopSrcDecls (HsGroup { hs_tyclds = tycl_decls,
    1802 1802
                                      , tcg_anns    = tcg_anns tcg_env ++ annotations
    
    1803 1803
                                      , tcg_ann_env = extendAnnEnvList (tcg_ann_env tcg_env) annotations
    
    1804 1804
                                      , tcg_fords   = tcg_fords tcg_env ++ foe_decls ++ fi_decls
    
    1805
    -                                 , tcg_dus     = tcg_dus tcg_env `plusDU` usesOnly fo_fvs } } ;
    
    1805
    +                                 , tcg_dus     = tcg_dus tcg_env `plusDU` usesOnly fo_fvs
    
    1806 1806
                                      -- tcg_dus: see Note [Newtype constructor usage in foreign declarations]
    
    1807
    +                                 , tcg_inst_meths = tcg_inst_meths tcg_env `plusVarEnv` inst_meths } } ;
    
    1807 1808
     
    
    1808 1809
             -- See Note [Newtype constructor usage in foreign declarations]
    
    1809 1810
             addUsedGREs NoDeprecationWarnings (bagToList fo_gres) ;
    

  • compiler/GHC/Tc/TyCl/Instance.hs
    ... ... @@ -1282,7 +1282,7 @@ takes a slightly different approach.
    1282 1282
     ********************************************************************* -}
    
    1283 1283
     
    
    1284 1284
     tcInstDecls2 :: [LTyClDecl GhcRn] -> [InstInfo GhcRn]
    
    1285
    -             -> TcM (LHsBinds GhcTc)
    
    1285
    +             -> TcM (LHsBinds GhcTc, IdEnv DFunId)
    
    1286 1286
     -- (a) From each class declaration,
    
    1287 1287
     --      generate any default-method bindings
    
    1288 1288
     -- (b) From each instance decl
    
    ... ... @@ -1299,11 +1299,11 @@ tcInstDecls2 tycl_decls inst_decls
    1299 1299
                   -- Add the default method Ids (again)
    
    1300 1300
                   -- (they were already added in GHC.Tc.TyCl.Utils.tcAddImplicits)
    
    1301 1301
                   -- See Note [Default methods in the type environment]
    
    1302
    -        ; inst_binds_s <- tcExtendGlobalValEnv dm_ids $
    
    1303
    -                          mapM tcInstDecl2 inst_decls
    
    1302
    +        ; (inst_binds_s, inst_meths_s) <- unzip <$> (tcExtendGlobalValEnv dm_ids $
    
    1303
    +                                                     mapM tcInstDecl2 inst_decls)
    
    1304 1304
     
    
    1305 1305
               -- Done
    
    1306
    -        ; return (dm_binds ++ concat inst_binds_s) }
    
    1306
    +        ; return (dm_binds ++ concat inst_binds_s, plusVarEnvList inst_meths_s) }
    
    1307 1307
     
    
    1308 1308
     {- Note [Default methods in the type environment]
    
    1309 1309
     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    ... ... @@ -1319,12 +1319,12 @@ So right here in tcInstDecls2 we must re-extend the type envt with
    1319 1319
     the default method Ids replete with their INLINE pragmas.  Urk.
    
    1320 1320
     -}
    
    1321 1321
     
    
    1322
    -tcInstDecl2 :: InstInfo GhcRn -> TcM (LHsBinds GhcTc)
    
    1322
    +tcInstDecl2 :: InstInfo GhcRn -> TcM (LHsBinds GhcTc, IdEnv DFunId)
    
    1323 1323
                 -- Returns a binding for the dfun
    
    1324 1324
     tcInstDecl2 (InstInfo { iSpec = ispec, iBinds = ibinds })
    
    1325
    -  = recoverM (return emptyLHsBinds)    $
    
    1326
    -    setSrcSpan loc                     $
    
    1327
    -    addErrCtxt (instDeclCtxt2 dfun_ty) $
    
    1325
    +  = recoverM (return (emptyLHsBinds, emptyVarEnv)) $
    
    1326
    +    setSrcSpan loc                                 $
    
    1327
    +    addErrCtxt (instDeclCtxt2 dfun_ty)             $
    
    1328 1328
         do {  -- Instantiate the instance decl with skolem constants
    
    1329 1329
              (skol_info, inst_tyvars, dfun_theta, clas, inst_tys) <- tcSkolDFunType dfun_ty
    
    1330 1330
            ; dfun_ev_vars <- newEvVars dfun_theta
    
    ... ... @@ -1342,7 +1342,7 @@ tcInstDecl2 (InstInfo { iSpec = ispec, iBinds = ibinds })
    1342 1342
              -- See Note [Typechecking plan for instance declarations]
    
    1343 1343
            ; dfun_ev_binds_var <- newTcEvBinds
    
    1344 1344
            ; let dfun_ev_binds = TcEvBinds dfun_ev_binds_var
    
    1345
    -       ; (tclvl, (sc_meth_ids, sc_meth_binds, sc_meth_implics))
    
    1345
    +       ; (tclvl, (sc_meth_ids, sc_meth_binds, sc_meth_implics, meth_ids))
    
    1346 1346
                  <- pushTcLevelM $
    
    1347 1347
                     do { (sc_ids, sc_binds, sc_implics)
    
    1348 1348
                             <- tcSuperClasses skol_info dfun_id clas inst_tyvars
    
    ... ... @@ -1356,7 +1356,8 @@ tcInstDecl2 (InstInfo { iSpec = ispec, iBinds = ibinds })
    1356 1356
     
    
    1357 1357
                        ; return ( sc_ids     ++          meth_ids
    
    1358 1358
                                 , sc_binds   ++ meth_binds
    
    1359
    -                            , sc_implics `unionBags` meth_implics ) }
    
    1359
    +                            , sc_implics `unionBags` meth_implics
    
    1360
    +                            , meth_ids ) }
    
    1360 1361
     
    
    1361 1362
            ; imp <- newImplication
    
    1362 1363
            ; emitImplication $
    
    ... ... @@ -1413,7 +1414,7 @@ tcInstDecl2 (InstInfo { iSpec = ispec, iBinds = ibinds })
    1413 1414
                                       , abs_binds = [dict_bind]
    
    1414 1415
                                       , abs_sig = True }
    
    1415 1416
     
    
    1416
    -       ; return (L loc' main_bind : sc_meth_binds)
    
    1417
    +       ; return (L loc' main_bind : sc_meth_binds, mkVarEnv $ (,dfun_id) <$> meth_ids)
    
    1417 1418
            }
    
    1418 1419
      where
    
    1419 1420
        dfun_id = instanceDFunId ispec
    

  • compiler/GHC/Tc/Types.hs
    ... ... @@ -157,6 +157,7 @@ import GHC.Types.Name.Env
    157 157
     import GHC.Types.Name.Set
    
    158 158
     import GHC.Types.Avail
    
    159 159
     import GHC.Types.Var
    
    160
    +import GHC.Types.Var.Env
    
    160 161
     import GHC.Types.TypeEnv
    
    161 162
     import GHC.Types.SourceFile
    
    162 163
     import GHC.Types.SrcLoc
    
    ... ... @@ -530,6 +531,8 @@ data TcGblEnv
    530 531
               -- NB. BangPattern is to fix a leak, see #15111
    
    531 532
             tcg_fam_inst_env :: !FamInstEnv, -- ^ Ditto for family instances
    
    532 533
               -- NB. BangPattern is to fix a leak, see #15111
    
    534
    +        tcg_inst_meths   :: IdEnv DFunId,
    
    535
    +          -- ^ Maps instance method Ids to the DFunId of the instance they belong to.
    
    533 536
             tcg_ann_env      :: AnnEnv,     -- ^ And for annotations
    
    534 537
             tcg_complete_match_env :: CompleteMatches,
    
    535 538
             -- ^ The complete matches for all /home-package/ modules;
    

  • compiler/GHC/Tc/Utils/Monad.hs
    ... ... @@ -409,6 +409,7 @@ initTcGblEnv hsc_env hsc_src keep_rn_syntax mod loc =
    409 409
               , tcg_knot_vars          = hsc_type_env_vars hsc_env
    
    410 410
               , tcg_known_key_maps     = known_key_maps_var
    
    411 411
               , tcg_inst_env           = emptyInstEnv
    
    412
    +          , tcg_inst_meths         = emptyVarEnv
    
    412 413
               , tcg_fam_inst_env       = emptyFamInstEnv
    
    413 414
               , tcg_ann_env            = emptyAnnEnv
    
    414 415
               , tcg_complete_match_env = []
    

  • testsuite/tests/codeGen/should_gen_asm/T25233.asm
    1
    +btrq
    
    2
    +btsq
    
    3
    +btcq
    
    4
    +btrl
    
    5
    +btsl
    
    6
    +btcl
    
    7
    +btrq $40,
    
    8
    +btsq $40,
    
    9
    +btcq $40,

  • testsuite/tests/codeGen/should_gen_asm/T25233.hs
    1
    +{-# LANGUAGE MagicHash #-}
    
    2
    +
    
    3
    +-- Check that clearing/setting/complementing a single, variable bit
    
    4
    +-- uses the btr/bts/btc instructions (#25233).
    
    5
    +module T25233 where
    
    6
    +
    
    7
    +import GHC.Exts
    
    8
    +
    
    9
    +myClearBit :: Word# -> Int# -> Word#
    
    10
    +myClearBit x i = x `and#` not# (1## `uncheckedShiftL#` i)
    
    11
    +
    
    12
    +mySetBit :: Word# -> Int# -> Word#
    
    13
    +mySetBit x i = x `or#` (1## `uncheckedShiftL#` i)
    
    14
    +
    
    15
    +myComplementBit :: Word# -> Int# -> Word#
    
    16
    +myComplementBit x i = x `xor#` (1## `uncheckedShiftL#` i)
    
    17
    +
    
    18
    +myClearBit32 :: Word32# -> Int# -> Word32#
    
    19
    +myClearBit32 x i =
    
    20
    +  x `andWord32#` notWord32# (wordToWord32# 1## `uncheckedShiftLWord32#` i)
    
    21
    +
    
    22
    +mySetBit32 :: Word32# -> Int# -> Word32#
    
    23
    +mySetBit32 x i = x `orWord32#` (wordToWord32# 1## `uncheckedShiftLWord32#` i)
    
    24
    +
    
    25
    +myComplementBit32 :: Word32# -> Int# -> Word32#
    
    26
    +myComplementBit32 x i =
    
    27
    +  x `xorWord32#` (wordToWord32# 1## `uncheckedShiftLWord32#` i)
    
    28
    +
    
    29
    +-- With a constant bit index >= 32, the mask constant-folds to a literal
    
    30
    +-- that does not fit in an imm32, so a bit-test instruction with an
    
    31
    +-- immediate offset is used.
    
    32
    +myClearBit40 :: Word# -> Word#
    
    33
    +myClearBit40 x = x `and#` not# (1## `uncheckedShiftL#` 40#)
    
    34
    +
    
    35
    +mySetBit40 :: Word# -> Word#
    
    36
    +mySetBit40 x = x `or#` (1## `uncheckedShiftL#` 40#)
    
    37
    +
    
    38
    +myComplementBit40 :: Word# -> Word#
    
    39
    +myComplementBit40 x = x `xor#` (1## `uncheckedShiftL#` 40#)

  • testsuite/tests/codeGen/should_gen_asm/T25233b.asm
    1
    +btrq %
    
    2
    +btsq %
    
    3
    +btcq %
    
    4
    +btrq $40,
    
    5
    +btsq $40,
    
    6
    +btcq $40,

  • testsuite/tests/codeGen/should_gen_asm/T25233b.cmm
    1
    +#include "Cmm.h"
    
    2
    +
    
    3
    +// Single-bit masks written on the left of the operator (#25233).
    
    4
    +
    
    5
    +clearBitVar (W_ x, W_ i) {
    
    6
    +    return ((~((1 :: bits64) << i)) & x);
    
    7
    +}
    
    8
    +
    
    9
    +setBitVar (W_ x, W_ i) {
    
    10
    +    return (((1 :: bits64) << i) | x);
    
    11
    +}
    
    12
    +
    
    13
    +complementBitVar (W_ x, W_ i) {
    
    14
    +    return (((1 :: bits64) << i) ^ x);
    
    15
    +}
    
    16
    +
    
    17
    +clearBit40 (W_ x) {
    
    18
    +    return ((0xFFFFFEFFFFFFFFFF :: bits64) & x);
    
    19
    +}
    
    20
    +
    
    21
    +setBit40 (W_ x) {
    
    22
    +    return ((0x10000000000 :: bits64) | x);
    
    23
    +}
    
    24
    +
    
    25
    +complementBit40 (W_ x) {
    
    26
    +    return ((0x10000000000 :: bits64) ^ x);
    
    27
    +}

  • testsuite/tests/codeGen/should_gen_asm/all.T
    ... ... @@ -23,6 +23,10 @@ test('avx512-int64-minmax', [unless(arch('x86_64'), skip),
    23 23
                                  when(unregisterised(), skip)], compile_grep_asm, ['hs', True, '-mavx512vl'])
    
    24 24
     test('avx512-word64-minmax', [unless(arch('x86_64'), skip),
    
    25 25
                                   when(unregisterised(), skip)], compile_grep_asm, ['hs', True, '-mavx512vl'])
    
    26
    +test('T25233', [unless(arch('x86_64'), skip),
    
    27
    +                when(unregisterised(), skip)], compile_grep_asm, ['hs', True, '-O'])
    
    28
    +test('T25233b', [unless(arch('x86_64'), skip),
    
    29
    +                 when(unregisterised(), skip)], compile_grep_asm, ['cmm', True, ''])
    
    26 30
     is_aarch64_codegen = [
    
    27 31
         unless(arch('aarch64'), skip),
    
    28 32
         when(unregisterised(), skip),
    

  • testsuite/tests/hpc/instmeths/instmeths.hs
    1
    +import Data.List
    
    2
    +import Data.Maybe
    
    3
    +import Trace.Hpc.Mix
    
    4
    +import Trace.Hpc.Reflect
    
    5
    +import Trace.Hpc.Tix
    
    6
    +import Trace.Hpc.Util
    
    7
    +
    
    8
    +class Foo a where
    
    9
    +  defMeth, defMeth', reqMeth :: a -> String
    
    10
    +  defMeth = const "class default"
    
    11
    +  defMeth' = const "class default"
    
    12
    +
    
    13
    +newtype T a = T a deriving (Show, Eq, Functor)
    
    14
    +instance Foo (T a) where
    
    15
    +  reqMeth = const "Foo (T a) instance"
    
    16
    +
    
    17
    +newtype T' a = T' a
    
    18
    +
    
    19
    +instance Foo (T' a) where
    
    20
    +  reqMeth = const "Foo (T' a) instance"
    
    21
    +  defMeth = const "Foo (T' a) instance"
    
    22
    +
    
    23
    +-- no method use could "cover" this instance, so we (for now) omit the top-level box for it
    
    24
    +class Marker a
    
    25
    +instance Marker (T Bool)
    
    26
    +
    
    27
    +interesting :: (Int, MixEntry) -> Maybe (Int, HpcPos, String)
    
    28
    +interesting (n, (pos, TopLevelBox [name])) | isInteresting name = Just (n, pos, name)
    
    29
    +  where isInteresting = (||) <$> isInst <*> isMeth
    
    30
    +        isInst = ("$f" `isPrefixOf`)
    
    31
    +        isMeth = (||) <$> (`elem` ["(==)", "(/=)", "show", "showList", "showsPrec", "fmap", "(<$)"])
    
    32
    +                      <*> ("Meth" `isSubsequenceOf`)
    
    33
    +interesting _ = Nothing
    
    34
    +
    
    35
    +-- candidate for HPC.Utils, maybe?
    
    36
    +sourceAt :: String -> HpcPos -> String
    
    37
    +sourceAt src pos
    
    38
    +  | l1 == l2 = take (c2 - c1 + 1) . drop (c1 - 1) $ ls !! (l1 - 1)
    
    39
    +  | otherwise = intercalate "\n" $ first : (middle ++ [last])
    
    40
    +  where
    
    41
    +    (l1, c1, l2, c2) = fromHpcPos pos
    
    42
    +    ls = lines src
    
    43
    +    first = drop (c1 - 1) $ ls !! (l1 - 1)
    
    44
    +    middle = take (l2 - l1 - 1) $ drop l1 ls
    
    45
    +    last = take c2 $ ls !! (l2 - 1)
    
    46
    +
    
    47
    +main :: IO ()
    
    48
    +main = do
    
    49
    +  print (T 23 == (succ <$> T 22)) -- tick Eq and Functor by using any of their methods
    
    50
    +  print (reqMeth (T' 1)) -- tick `Foo (T' a)` and that instance's `reqMeth`
    
    51
    +
    
    52
    +  Mix source _ _ _ mixEntries <- readMix [".hpc"] (Left "Main")
    
    53
    +  src <- readFileUtf8 source
    
    54
    +  let boxes = mapMaybe interesting $ zip [0 ..] mixEntries
    
    55
    +  Tix [TixModule "Main" _ _ counts] <- examineTix
    
    56
    +  mapM_ print [ (counts !! n, path, sourceAt src pos)
    
    57
    +              | (n, pos, path) <- sortOn (\(_, _, s) -> s) boxes ]

  • testsuite/tests/hpc/instmeths/instmeths.stdout
    1
    +True
    
    2
    +"Foo (T' a) instance"
    
    3
    +(1,"$fEqT","Eq")
    
    4
    +(0,"$fFooT","Foo (T a)")
    
    5
    +(1,"$fFooT'","Foo (T' a)")
    
    6
    +(1,"$fFunctorT","Functor")
    
    7
    +(0,"$fShowT","Show")
    
    8
    +(0,"defMeth","defMeth = const \"class default\"")
    
    9
    +(0,"defMeth","defMeth = const \"Foo (T' a) instance\"")
    
    10
    +(0,"defMeth'","defMeth' = const \"class default\"")
    
    11
    +(0,"reqMeth","reqMeth = const \"Foo (T a) instance\"")
    
    12
    +(1,"reqMeth","reqMeth = const \"Foo (T' a) instance\"")

  • testsuite/tests/hpc/instmeths/test.T
    1
    +setTestOpts([omit_ghci, when(fast(), skip), js_skip])
    
    2
    +
    
    3
    +test('instmeths',
    
    4
    +     [ignore_extension],
    
    5
    +     compile_and_run, ['-fhpc'])

  • testsuite/tests/rename/should_fail/RnStaticPointersFail01.stderr
    1 1
     RnStaticPointersFail01.hs:5:7: error: [GHC-88431]
    
    2
    -    ‘x’ is used in a static form but it is not defined at top level
    
    2
    +    • ‘x’ is used in a static form but it is not defined at top level
    
    3
    +    • In the expression: static x
    
    4
    +      In an equation for ‘f’: f x = static x
    
    3 5
     

  • testsuite/tests/rename/should_fail/RnStaticPointersFail03.stderr
    1 1
     RnStaticPointersFail03.hs:8:7: error: [GHC-88431]
    
    2
    -    ‘x’ is used in a static form but it is not defined at top level
    
    2
    +    • ‘x’ is used in a static form but it is not defined at top level
    
    3
    +    • In the expression: static (x . id)
    
    4
    +      In an equation for ‘f’: f x = static (x . id)
    
    3 5
     
    
    4 6
     RnStaticPointersFail03.hs:10:8: error: [GHC-88431]
    
    5
    -    ‘k’ is used in a static form but it is not defined at top level
    
    7
    +    • ‘k’ is used in a static form but it is not defined at top level
    
    8
    +    • In the expression: static (k . id)
    
    9
    +      In an equation for ‘f0’:
    
    10
    +          f0 x
    
    11
    +            = static (k . id)
    
    12
    +            where
    
    13
    +                k = const (const () x)
    
    6 14
     
    
    7 15
     RnStaticPointersFail03.hs:14:8: error: [GHC-88431]
    
    8
    -    ‘k’ is used in a static form but it is not defined at top level
    
    16
    +    • ‘k’ is used in a static form but it is not defined at top level
    
    17
    +    • In the expression: static (k . id)
    
    18
    +      In an equation for ‘f1’:
    
    19
    +          f1 x
    
    20
    +            = static (k . id)
    
    21
    +            where
    
    22
    +                k = id
    
    9 23
     
    
    10 24
     RnStaticPointersFail03.hs:19:15: error: [GHC-88431]
    
    11
    -    ‘g’ is used in a static form but it is not defined at top level
    
    25
    +    • ‘g’ is used in a static form but it is not defined at top level
    
    26
    +    • In the first argument of ‘const’, namely ‘(static (g undefined))’
    
    27
    +      In the expression: const (static (g undefined)) (h x)
    
    28
    +      In an equation for ‘f2’:
    
    29
    +          f2 x
    
    30
    +            = const (static (g undefined)) (h x)
    
    31
    +            where
    
    32
    +                g = h
    
    33
    +                h = typeOf
    
    12 34
     

  • testsuite/tests/rename/should_fail/T26545.stderr
    1 1
     T26545.hs:12:23: error: [GHC-88431]
    
    2
    -    ‘v’ is used in a static form but it is not defined at top level
    
    2
    +    • ‘v’ is used in a static form but it is not defined at top level
    
    3
    +    • In the expression: static (I# (v +# 1#))
    
    4
    +      In the expression: let v = f 3# in static (I# (v +# 1#))
    
    5
    +      In an equation for ‘h’: h x = let v = f 3# in static (I# (v +# 1#))
    
    3 6
     

  • testsuite/tests/typecheck/should_compile/T27664.hs
    1
    +{-# LANGUAGE StaticPointers, ScopedTypeVariables #-}
    
    2
    +module Repro where
    
    3
    +
    
    4
    +import Data.Typeable
    
    5
    +import GHC.StaticPtr
    
    6
    +
    
    7
    +f1 :: forall a. Typeable a => StaticPtr (a -> a)
    
    8
    +f1 = static (id :: a -> a)
    
    9
    +
    
    10
    +f2 :: forall a. Typeable a => StaticPtr (a -> a)
    
    11
    +f2 = static (id) :: StaticPtr (a->a)

  • testsuite/tests/typecheck/should_compile/all.T
    ... ... @@ -969,3 +969,4 @@ test('ExpansionQLIm', normal, compile, [''])
    969 969
     test('T23135', normal, compile, [''])
    
    970 970
     test('LazyFieldAnnotations', normal, compile, [''])
    
    971 971
     test('T27557', normal, compile, [''])
    
    972
    +test('T27664', normal, compile, [''])