diff options
author | Simon Peyton Jones <simonpj@microsoft.com> | 2019-10-02 12:36:44 +0300 |
---|---|---|
committer | Marge Bot <ben+marge-bot@smart-cactus.org> | 2020-02-20 21:17:57 -0500 |
commit | 74ad75e87317196c600dfabc61aee1b87d95c214 (patch) | |
tree | 37f85f608112a1372f097b4c2eea9f4c8c8f00fc /compiler/basicTypes | |
parent | 19680ee533bb95c0c5c42aca5c81197e4b233979 (diff) | |
download | haskell-74ad75e87317196c600dfabc61aee1b87d95c214.tar.gz |
Re-implement unsafe coercions in terms of unsafe equality proofs
(Commit message written by Omer, most of the code is written by Simon
and Richard)
See Note [Implementing unsafeCoerce] for how unsafe equality proofs and
the new unsafeCoerce# are implemented.
New notes added:
- [Checking for levity polymorphism] in CoreLint.hs
- [Implementing unsafeCoerce] in base/Unsafe/Coerce.hs
- [Patching magic definitions] in Desugar.hs
- [Wiring in unsafeCoerce#] in Desugar.hs
Only breaking change in this patch is unsafeCoerce# is not exported from
GHC.Exts, instead of GHC.Prim.
Fixes #17443
Fixes #16893
NoFib
-----
--------------------------------------------------------------------------------
Program Size Allocs Instrs Reads Writes
--------------------------------------------------------------------------------
CS -0.1% 0.0% -0.0% -0.0% -0.0%
CSD -0.1% 0.0% -0.0% -0.0% -0.0%
FS -0.1% 0.0% -0.0% -0.0% -0.0%
S -0.1% 0.0% -0.0% -0.0% -0.0%
VS -0.1% 0.0% -0.0% -0.0% -0.0%
VSD -0.1% 0.0% -0.0% -0.0% -0.1%
VSM -0.1% 0.0% -0.0% -0.0% -0.0%
anna -0.0% 0.0% -0.0% -0.0% -0.0%
ansi -0.1% 0.0% -0.0% -0.0% -0.0%
atom -0.1% 0.0% -0.0% -0.0% -0.0%
awards -0.1% 0.0% -0.0% -0.0% -0.0%
banner -0.1% 0.0% -0.0% -0.0% -0.0%
bernouilli -0.1% 0.0% -0.0% -0.0% -0.0%
binary-trees -0.1% 0.0% -0.0% -0.0% -0.0%
boyer -0.1% 0.0% -0.0% -0.0% -0.0%
boyer2 -0.1% 0.0% -0.0% -0.0% -0.0%
bspt -0.1% 0.0% -0.0% -0.0% -0.0%
cacheprof -0.1% 0.0% -0.0% -0.0% -0.0%
calendar -0.1% 0.0% -0.0% -0.0% -0.0%
cichelli -0.1% 0.0% -0.0% -0.0% -0.0%
circsim -0.1% 0.0% -0.0% -0.0% -0.0%
clausify -0.1% 0.0% -0.0% -0.0% -0.0%
comp_lab_zift -0.1% 0.0% -0.0% -0.0% -0.0%
compress -0.1% 0.0% -0.0% -0.0% -0.0%
compress2 -0.1% 0.0% -0.0% -0.0% -0.0%
constraints -0.1% 0.0% -0.0% -0.0% -0.0%
cryptarithm1 -0.1% 0.0% -0.0% -0.0% -0.0%
cryptarithm2 -0.1% 0.0% -0.0% -0.0% -0.0%
cse -0.1% 0.0% -0.0% -0.0% -0.0%
digits-of-e1 -0.1% 0.0% -0.0% -0.0% -0.0%
digits-of-e2 -0.1% 0.0% -0.0% -0.0% -0.0%
dom-lt -0.1% 0.0% -0.0% -0.0% -0.0%
eliza -0.1% 0.0% -0.0% -0.0% -0.0%
event -0.1% 0.0% -0.0% -0.0% -0.0%
exact-reals -0.1% 0.0% -0.0% -0.0% -0.0%
exp3_8 -0.1% 0.0% -0.0% -0.0% -0.0%
expert -0.1% 0.0% -0.0% -0.0% -0.0%
fannkuch-redux -0.1% 0.0% -0.0% -0.0% -0.0%
fasta -0.1% 0.0% -0.5% -0.3% -0.4%
fem -0.1% 0.0% -0.0% -0.0% -0.0%
fft -0.1% 0.0% -0.0% -0.0% -0.0%
fft2 -0.1% 0.0% -0.0% -0.0% -0.0%
fibheaps -0.1% 0.0% -0.0% -0.0% -0.0%
fish -0.1% 0.0% -0.0% -0.0% -0.0%
fluid -0.1% 0.0% -0.0% -0.0% -0.0%
fulsom -0.1% 0.0% +0.0% +0.0% +0.0%
gamteb -0.1% 0.0% -0.0% -0.0% -0.0%
gcd -0.1% 0.0% -0.0% -0.0% -0.0%
gen_regexps -0.1% 0.0% -0.0% -0.0% -0.0%
genfft -0.1% 0.0% -0.0% -0.0% -0.0%
gg -0.1% 0.0% -0.0% -0.0% -0.0%
grep -0.1% 0.0% -0.0% -0.0% -0.0%
hidden -0.1% 0.0% -0.0% -0.0% -0.0%
hpg -0.1% 0.0% -0.0% -0.0% -0.0%
ida -0.1% 0.0% -0.0% -0.0% -0.0%
infer -0.1% 0.0% -0.0% -0.0% -0.0%
integer -0.1% 0.0% -0.0% -0.0% -0.0%
integrate -0.1% 0.0% -0.0% -0.0% -0.0%
k-nucleotide -0.1% 0.0% -0.0% -0.0% -0.0%
kahan -0.1% 0.0% -0.0% -0.0% -0.0%
knights -0.1% 0.0% -0.0% -0.0% -0.0%
lambda -0.1% 0.0% -0.0% -0.0% -0.0%
last-piece -0.1% 0.0% -0.0% -0.0% -0.0%
lcss -0.1% 0.0% -0.0% -0.0% -0.0%
life -0.1% 0.0% -0.0% -0.0% -0.0%
lift -0.1% 0.0% -0.0% -0.0% -0.0%
linear -0.1% 0.0% -0.0% -0.0% -0.0%
listcompr -0.1% 0.0% -0.0% -0.0% -0.0%
listcopy -0.1% 0.0% -0.0% -0.0% -0.0%
maillist -0.1% 0.0% -0.0% -0.0% -0.0%
mandel -0.1% 0.0% -0.0% -0.0% -0.0%
mandel2 -0.1% 0.0% -0.0% -0.0% -0.0%
mate -0.1% 0.0% -0.0% -0.0% -0.0%
minimax -0.1% 0.0% -0.0% -0.0% -0.0%
mkhprog -0.1% 0.0% -0.0% -0.0% -0.0%
multiplier -0.1% 0.0% -0.0% -0.0% -0.0%
n-body -0.1% 0.0% -0.0% -0.0% -0.0%
nucleic2 -0.1% 0.0% -0.0% -0.0% -0.0%
para -0.1% 0.0% -0.0% -0.0% -0.0%
paraffins -0.1% 0.0% -0.0% -0.0% -0.0%
parser -0.1% 0.0% -0.0% -0.0% -0.0%
parstof -0.1% 0.0% -0.0% -0.0% -0.0%
pic -0.1% 0.0% -0.0% -0.0% -0.0%
pidigits -0.1% 0.0% -0.0% -0.0% -0.0%
power -0.1% 0.0% -0.0% -0.0% -0.0%
pretty -0.1% 0.0% -0.1% -0.1% -0.1%
primes -0.1% 0.0% -0.0% -0.0% -0.0%
primetest -0.1% 0.0% -0.0% -0.0% -0.0%
prolog -0.1% 0.0% -0.0% -0.0% -0.0%
puzzle -0.1% 0.0% -0.0% -0.0% -0.0%
queens -0.1% 0.0% -0.0% -0.0% -0.0%
reptile -0.1% 0.0% -0.0% -0.0% -0.0%
reverse-complem -0.1% 0.0% -0.0% -0.0% -0.0%
rewrite -0.1% 0.0% -0.0% -0.0% -0.0%
rfib -0.1% 0.0% -0.0% -0.0% -0.0%
rsa -0.1% 0.0% -0.0% -0.0% -0.0%
scc -0.1% 0.0% -0.1% -0.1% -0.1%
sched -0.1% 0.0% -0.0% -0.0% -0.0%
scs -0.1% 0.0% -0.0% -0.0% -0.0%
simple -0.1% 0.0% -0.0% -0.0% -0.0%
solid -0.1% 0.0% -0.0% -0.0% -0.0%
sorting -0.1% 0.0% -0.0% -0.0% -0.0%
spectral-norm -0.1% 0.0% -0.0% -0.0% -0.0%
sphere -0.1% 0.0% -0.0% -0.0% -0.0%
symalg -0.1% 0.0% -0.0% -0.0% -0.0%
tak -0.1% 0.0% -0.0% -0.0% -0.0%
transform -0.1% 0.0% -0.0% -0.0% -0.0%
treejoin -0.1% 0.0% -0.0% -0.0% -0.0%
typecheck -0.1% 0.0% -0.0% -0.0% -0.0%
veritas -0.0% 0.0% -0.0% -0.0% -0.0%
wang -0.1% 0.0% -0.0% -0.0% -0.0%
wave4main -0.1% 0.0% -0.0% -0.0% -0.0%
wheel-sieve1 -0.1% 0.0% -0.0% -0.0% -0.0%
wheel-sieve2 -0.1% 0.0% -0.0% -0.0% -0.0%
x2n1 -0.1% 0.0% -0.0% -0.0% -0.0%
--------------------------------------------------------------------------------
Min -0.1% 0.0% -0.5% -0.3% -0.4%
Max -0.0% 0.0% +0.0% +0.0% +0.0%
Geometric Mean -0.1% -0.0% -0.0% -0.0% -0.0%
Test changes
------------
- break006 is marked as broken, see #17833
- The compiler allocates less when building T14683 (an unsafeCoerce#-
heavy happy-generated code) on 64-platforms. Allocates more on 32-bit
platforms.
- Rest of the increases are tiny amounts (still enough to pass the
threshold) in micro-benchmarks. I briefly looked at each one in a
profiling build: most of the increased allocations seem to be because
of random changes in the generated code.
Metric Decrease:
T14683
Metric Increase:
T12150
T12234
T12425
T13035
T14683
T5837
T6048
Co-Authored-By: Richard Eisenberg <rae@cs.brynmawr.edu>
Co-Authored-By: Ömer Sinan Ağacan <omeragacan@gmail.com>
Diffstat (limited to 'compiler/basicTypes')
-rw-r--r-- | compiler/basicTypes/BasicTypes.hs | 3 | ||||
-rw-r--r-- | compiler/basicTypes/DataCon.hs | 43 | ||||
-rw-r--r-- | compiler/basicTypes/MkId.hs | 58 | ||||
-rw-r--r-- | compiler/basicTypes/Unique.hs | 6 |
4 files changed, 18 insertions, 92 deletions
diff --git a/compiler/basicTypes/BasicTypes.hs b/compiler/basicTypes/BasicTypes.hs index bff97a1887..83ebb67c5c 100644 --- a/compiler/basicTypes/BasicTypes.hs +++ b/compiler/basicTypes/BasicTypes.hs @@ -325,6 +325,9 @@ isPromoted :: PromotionFlag -> Bool isPromoted IsPromoted = True isPromoted NotPromoted = False +instance Outputable PromotionFlag where + ppr NotPromoted = text "NotPromoted" + ppr IsPromoted = text "IsPromoted" {- ************************************************************************ diff --git a/compiler/basicTypes/DataCon.hs b/compiler/basicTypes/DataCon.hs index 4c429ea61d..c89dab3349 100644 --- a/compiler/basicTypes/DataCon.hs +++ b/compiler/basicTypes/DataCon.hs @@ -24,7 +24,7 @@ module DataCon ( FieldLbl(..), FieldLabel, FieldLabelString, -- ** Type construction - mkDataCon, buildAlgTyCon, buildSynTyCon, fIRST_TAG, + mkDataCon, fIRST_TAG, -- ** Type deconstruction dataConRepType, dataConInstSig, dataConFullSig, @@ -65,7 +65,6 @@ import GhcPrelude import {-# SOURCE #-} MkId( DataConBoxer ) import Type -import ForeignCall ( CType ) import Coercion import Unify import TyCon @@ -75,7 +74,6 @@ import Name import PrelNames import Predicate import Var -import VarSet( emptyVarSet ) import Outputable import Util import BasicTypes @@ -1381,6 +1379,10 @@ dataConCannotMatch :: [Type] -> DataCon -> Bool -- scrutinee of type (T tys) -- where T is the dcRepTyCon for the data con dataConCannotMatch tys con + -- See (U6) in Note [Implementing unsafeCoerce] + -- in base:Unsafe.Coerce + | dataConName con == unsafeReflDataConName + = False | null inst_theta = False -- Common | all isTyVarTy tys = False -- Also common | otherwise = typesCantMatch (concatMap predEqs inst_theta) @@ -1464,38 +1466,3 @@ splitDataProductType_maybe ty | otherwise = Nothing -{- -************************************************************************ -* * - Building an algebraic data type -* * -************************************************************************ - -buildAlgTyCon is here because it is called from TysWiredIn, which can -depend on this module, but not on BuildTyCl. --} - -buildAlgTyCon :: Name - -> [TyVar] -- ^ Kind variables and type variables - -> [Role] - -> Maybe CType - -> ThetaType -- ^ Stupid theta - -> AlgTyConRhs - -> Bool -- ^ True <=> was declared in GADT syntax - -> AlgTyConFlav - -> TyCon - -buildAlgTyCon tc_name ktvs roles cType stupid_theta rhs - gadt_syn parent - = mkAlgTyCon tc_name binders liftedTypeKind roles cType stupid_theta - rhs parent gadt_syn - where - binders = mkTyConBindersPreferAnon ktvs emptyVarSet - -buildSynTyCon :: Name -> [KnotTied TyConBinder] -> Kind -- ^ /result/ kind - -> [Role] -> KnotTied Type -> TyCon -buildSynTyCon name binders res_kind roles rhs - = mkSynonymTyCon name binders res_kind roles rhs is_tau is_fam_free - where - is_tau = isTauTy rhs - is_fam_free = isFamFreeTy rhs diff --git a/compiler/basicTypes/MkId.hs b/compiler/basicTypes/MkId.hs index a0b84a6aa5..5c268d37ef 100644 --- a/compiler/basicTypes/MkId.hs +++ b/compiler/basicTypes/MkId.hs @@ -22,11 +22,12 @@ module MkId ( mkPrimOpId, mkFCallId, unwrapNewTypeBody, wrapFamInstBody, - DataConBoxer(..), mkDataConRep, mkDataConWorkId, + DataConBoxer(..), vanillaDataConBoxer, + mkDataConRep, mkDataConWorkId, -- And some particular Ids; see below for why they are wired in wiredInIds, ghcPrimIds, - unsafeCoerceName, unsafeCoerceId, realWorldPrimId, + realWorldPrimId, voidPrimId, voidArgId, nullAddrId, seqId, lazyId, lazyIdKey, coercionTokenId, magicDictId, coerceId, @@ -46,6 +47,7 @@ import TysPrim import TysWiredIn import PrelRules import Type +import TyCoRep import FamInstEnv import Coercion import TcType @@ -151,7 +153,6 @@ ghcPrimIds :: [Id] -- See Note [ghcPrimIds (aka pseudoops)] ghcPrimIds = [ realWorldPrimId , voidPrimId - , unsafeCoerceId , nullAddrId , seqId , magicDictId @@ -601,6 +602,10 @@ newtype DataConBoxer = DCB ([Type] -> [Var] -> UniqSM ([Var], [CoreBind])) -- Bind these src-level vars, returning the -- rep-level vars to bind in the pattern +vanillaDataConBoxer :: DataConBoxer +-- No transformation on arguments needed +vanillaDataConBoxer = DCB (\_tys args -> return (args, [])) + {- Note [Inline partially-applied constructor wrappers] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -666,7 +671,7 @@ mkDataConRep dflags fam_envs wrap_name mb_bangs data_con -- the strictness signature (#14290). mk_dmd str | isBanged str = evalDmd - | otherwise = topDmd + | otherwise = topDmd wrap_prag = alwaysInlinePragma `setInlinePragmaActivation` activeDuringFinal @@ -1322,19 +1327,14 @@ no curried identifier for them. That's what mkCompulsoryUnfolding does. If we had a way to get a compulsory unfolding from an interface file, we could do that, but we don't right now. -unsafeCoerce# isn't so much a PrimOp as a phantom identifier, that -just gets expanded into a type coercion wherever it occurs. Hence we -add it as a built-in Id with an unfolding here. - The type variables we use here are "open" type variables: this means they can unify with both unlifted and lifted types. Hence we provide another gun with which to shoot yourself in the foot. -} -unsafeCoerceName, nullAddrName, seqName, +nullAddrName, seqName, realWorldName, voidPrimIdName, coercionTokenName, magicDictName, coerceName, proxyName :: Name -unsafeCoerceName = mkWiredInIdName gHC_PRIM (fsLit "unsafeCoerce#") unsafeCoerceIdKey unsafeCoerceId nullAddrName = mkWiredInIdName gHC_PRIM (fsLit "nullAddr#") nullAddrIdKey nullAddrId seqName = mkWiredInIdName gHC_PRIM (fsLit "seq") seqIdKey seqId realWorldName = mkWiredInIdName gHC_PRIM (fsLit "realWorld#") realWorldPrimIdKey realWorldPrimId @@ -1366,28 +1366,6 @@ proxyHashId ty = mkInvForAllTy kv $ mkSpecForAllTy tv $ mkProxyPrimTy kv_ty tv_ty ------------------------------------------------ -unsafeCoerceId :: Id -unsafeCoerceId - = pcMiscPrelId unsafeCoerceName ty info - where - info = noCafIdInfo `setInlinePragInfo` alwaysInlinePragma - `setUnfoldingInfo` mkCompulsoryUnfolding rhs - - -- unsafeCoerce# :: forall (r1 :: RuntimeRep) (r2 :: RuntimeRep) - -- (a :: TYPE r1) (b :: TYPE r2). - -- a -> b - bndrs = mkTemplateKiTyVars [runtimeRepTy, runtimeRepTy] - (\ks -> map tYPE ks) - - [_, _, a, b] = mkTyVarTys bndrs - - ty = mkSpecForAllTys bndrs (mkVisFunTy a b) - - [x] = mkTemplateLocals [a] - rhs = mkLams (bndrs ++ [x]) $ - Cast (Var x) (mkUnsafeCo Representational a b) - ------------------------------------------------- nullAddrId :: Id -- nullAddr# :: Addr# -- The reason it is here is because we don't provide @@ -1487,22 +1465,6 @@ coerceId = pcMiscPrelId coerceName ty info [(DataAlt coercibleDataCon, [eq], Cast (Var x) (mkCoVarCo eq))] {- -Note [Unsafe coerce magic] -~~~~~~~~~~~~~~~~~~~~~~~~~~ -We define a *primitive* - GHC.Prim.unsafeCoerce# -and then in the base library we define the ordinary function - Unsafe.Coerce.unsafeCoerce :: forall (a:*) (b:*). a -> b - unsafeCoerce x = unsafeCoerce# x - -Notice that unsafeCoerce has a civilized (albeit still dangerous) -polymorphic type, whose type args have kind *. So you can't use it on -unboxed values (unsafeCoerce 3#). - -In contrast unsafeCoerce# is even more dangerous because you *can* use -it on unboxed things, (unsafeCoerce# 3#) :: Int. Its type is - forall (r1 :: RuntimeRep) (r2 :: RuntimeRep) (a: TYPE r1) (b: TYPE r2). a -> b - Note [seqId magic] ~~~~~~~~~~~~~~~~~~ 'GHC.Prim.seq' is special in several ways. diff --git a/compiler/basicTypes/Unique.hs b/compiler/basicTypes/Unique.hs index f14f22d625..f6f46914f0 100644 --- a/compiler/basicTypes/Unique.hs +++ b/compiler/basicTypes/Unique.hs @@ -394,12 +394,6 @@ mkPreludeTyConUnique i = mkUnique '3' (2*i) tyConRepNameUnique :: Unique -> Unique tyConRepNameUnique u = incrUnique u --- Data constructor keys occupy *two* slots. The first is used for the --- data constructor itself and its wrapper function (the function that --- evaluates arguments as necessary and calls the worker). The second is --- used for the worker function (the function that builds the constructor --- representation). - -------------------------------------------------- -- Wired-in data constructor keys occupy *three* slots: -- * u: the DataCon itself |