summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon Peyton Jones <simonpj@microsoft.com>2022-11-03 17:16:39 +0000
committerSimon Peyton Jones <simonpj@microsoft.com>2022-11-10 12:21:13 +0000
commit2b3d0beec2668963c332b4490328aee256f07766 (patch)
tree85f68e3e40f8524d2660f6c4476a3380519c7a64
parentf9f17b68b144a7ecb91395c1e987bbf4f91c0180 (diff)
downloadhaskell-2b3d0beec2668963c332b4490328aee256f07766.tar.gz
Make indexError work better
The problem here is described at some length in Note [Boxity for bottoming functions] and Note [Reboxed crud for bottoming calls] in GHC.Core.Opt.DmdAnal. This patch adds a SPECIALISE pragma for indexError, which makes it much less vulnerable to the problem described in these Notes. (This came up in another line of work, where a small change made indexError do reboxing (in nofib/spectral/simple/table_sort) that didn't happen before my change. I've opened #22404 to document the fagility.
-rw-r--r--compiler/GHC/Core/Opt/DmdAnal.hs3
-rw-r--r--libraries/base/GHC/Ix.hs24
2 files changed, 24 insertions, 3 deletions
diff --git a/compiler/GHC/Core/Opt/DmdAnal.hs b/compiler/GHC/Core/Opt/DmdAnal.hs
index c6c5d11926..51c0ab702b 100644
--- a/compiler/GHC/Core/Opt/DmdAnal.hs
+++ b/compiler/GHC/Core/Opt/DmdAnal.hs
@@ -1520,6 +1520,9 @@ $wtheresCrud = \ ww ww1 ->
...
```
This is currently a bug that we willingly accept and it's documented in #21128.
+
+See also Note [indexError] in base:GHC.Ix, which describes how we use
+SPECIALISE to mitigate this problem for indexError.
-}
{- *********************************************************************
diff --git a/libraries/base/GHC/Ix.hs b/libraries/base/GHC/Ix.hs
index be02b568a2..abbe62c2f1 100644
--- a/libraries/base/GHC/Ix.hs
+++ b/libraries/base/GHC/Ix.hs
@@ -140,12 +140,30 @@ Note [Out-of-bounds error messages]
The default method for 'index' generates hoplelessIndexError, because
Ix doesn't have Show as a superclass. For particular base types we
can do better, so we override the default method for index.
--}
--- Abstract these errors from the relevant index functions so that
--- the guts of the function will be small enough to inline.
+Note [indexError]
+~~~~~~~~~~~~~~~~~
+We abstract the guts of constructing an out-of-bounds error into `indexError`.
+We give it a NOINLINE pragma, because we don't want to duplicate this
+cold-path code.
+
+We give it a SPECIALISE pragma because we really want it to take
+its arguments unboxed, to avoid reboxing code in the caller, and
+perhaps even some reboxing code in the hot path of a caller.
+See Note [Boxity for bottoming functions] in GHC.Core.Opt.DmdAnal.
+
+The SPECIALISE pragma means that at least the Int-indexed case
+of indexError /will/ unbox its arguments.
+The [2] phase is because if we don't give an activation we'll get
+the one from the inline pragama (i.e. never) which is a bit silly.
+See Note [Activation pragmas for SPECIALISE] in GHC.HsToCore.Binds.
+-}
+
+-- indexError: see Note [indexError]
{-# NOINLINE indexError #-}
+{-# SPECIALISE [2] indexError :: (Int,Int) -> Int -> String -> b #-}
+
indexError :: Show a => (a,a) -> a -> String -> b
indexError rng i tp
= errorWithoutStackTrace (showString "Ix{" . showString tp . showString "}.index: Index " .