Florian Ragwitz pushed to branch wip/rafl/hpc-instances at Glasgow Haskell Compiler / GHC
Commits:
-
2908ab36
by Simon Jakobi at 2026-09-05T07:22:17-04:00
-
c673ecf0
by Simon Peyton Jones at 2026-09-05T07:22:59-04:00
-
e25a36da
by Florian Ragwitz at 2026-09-05T09:41:05-07:00
-
0c833d17
by Florian Ragwitz at 2026-09-05T09:41:06-07:00
-
ee6519e6
by Florian Ragwitz at 2026-09-05T09:41:06-07:00
-
3a176ec9
by Florian Ragwitz at 2026-09-05T09:41:06-07:00
-
97292cee
by Florian Ragwitz at 2026-09-05T09:41:06-07:00
-
6317c95a
by Florian Ragwitz at 2026-09-05T09:41:06-07:00
28 changed files:
- + changelog.d/T27764
- + changelog.d/hpc-classinsts
- + changelog.d/ncg-x86-bit-test-instructions
- compiler/GHC/CmmToAsm/X86/CodeGen.hs
- compiler/GHC/CmmToAsm/X86/Instr.hs
- compiler/GHC/CmmToAsm/X86/Ppr.hs
- compiler/GHC/Hs/Expr.hs
- compiler/GHC/HsToCore.hs
- compiler/GHC/HsToCore/Ticks.hs
- compiler/GHC/Rename/Expr.hs
- compiler/GHC/Tc/Gen/Expr.hs
- compiler/GHC/Tc/Module.hs
- compiler/GHC/Tc/TyCl/Instance.hs
- compiler/GHC/Tc/Types.hs
- compiler/GHC/Tc/Utils/Monad.hs
- + testsuite/tests/codeGen/should_gen_asm/T25233.asm
- + testsuite/tests/codeGen/should_gen_asm/T25233.hs
- + testsuite/tests/codeGen/should_gen_asm/T25233b.asm
- + testsuite/tests/codeGen/should_gen_asm/T25233b.cmm
- testsuite/tests/codeGen/should_gen_asm/all.T
- + testsuite/tests/hpc/instmeths/instmeths.hs
- + testsuite/tests/hpc/instmeths/instmeths.stdout
- + testsuite/tests/hpc/instmeths/test.T
- testsuite/tests/rename/should_fail/RnStaticPointersFail01.stderr
- testsuite/tests/rename/should_fail/RnStaticPointersFail03.stderr
- testsuite/tests/rename/should_fail/T26545.stderr
- + testsuite/tests/typecheck/should_compile/T27664.hs
- testsuite/tests/typecheck/should_compile/all.T
Changes:
| 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. |
| 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 |
| 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 |
| ... | ... | @@ -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)
|
| ... | ... | @@ -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
|
| ... | ... | @@ -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
|
| ... | ... | @@ -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
|
| ... | ... | @@ -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
|
| ... | ... | @@ -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)
|
| ... | ... | @@ -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 | ************************************************************************
|
| ... | ... | @@ -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)
|
| ... | ... | @@ -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) ;
|
| ... | ... | @@ -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
|
| ... | ... | @@ -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;
|
| ... | ... | @@ -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 = []
|
| 1 | +btrq
|
|
| 2 | +btsq
|
|
| 3 | +btcq
|
|
| 4 | +btrl
|
|
| 5 | +btsl
|
|
| 6 | +btcl
|
|
| 7 | +btrq $40,
|
|
| 8 | +btsq $40,
|
|
| 9 | +btcq $40, |
| 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#) |
| 1 | +btrq %
|
|
| 2 | +btsq %
|
|
| 3 | +btcq %
|
|
| 4 | +btrq $40,
|
|
| 5 | +btsq $40,
|
|
| 6 | +btcq $40, |
| 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 | +} |
| ... | ... | @@ -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),
|
| 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 ] |
| 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\"") |
| 1 | +setTestOpts([omit_ghci, when(fast(), skip), js_skip])
|
|
| 2 | + |
|
| 3 | +test('instmeths',
|
|
| 4 | + [ignore_extension],
|
|
| 5 | + compile_and_run, ['-fhpc']) |
| 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 |
| 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 |
| 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 |
| 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) |
| ... | ... | @@ -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, ['']) |