@@ -289,18 +289,17 @@ occNest a (Abs decls ans) = case decls of
289289 \ d'@ (Let b' (DeclBinding _ expr')) rest -> do
290290 exprIx <- summaryExpr $ sink expr'
291291 extend b' exprIx do
292- below <- occNest (sink a) rest
293- checkAllFreeVariablesMentioned below
292+ (below, belowfvs) <- isolated do
293+ occNest (sink a) rest >>= wrapWithCachedFVs
294+ modify (<> belowfvs)
294295 accessInfo <- getAccessInfo $ binderName d'
295296 let usage = usageInfo accessInfo
296297 let dceAttempt = case isPureDecl of
297- False -> ElimFailure d' usage below
298+ False -> ElimFailure d' usage $ fromCachedFVs below
298299 True ->
299- -- Or hoistUsingCachedFVs in the monad, if we decide to do
300- -- that optimization
301- case hoist d' below of
300+ case hoistViaCachedFVs d' below of
302301 HoistSuccess below' -> ElimSuccess below'
303- HoistFailure _ -> ElimFailure d' usage below
302+ HoistFailure _ -> ElimFailure d' usage $ fromCachedFVs below
304303 return dceAttempt
305304 case dceAttempt of
306305 ElimSuccess below' -> return below'
@@ -320,19 +319,21 @@ occNest a (Abs decls ans) = case decls of
320319 let binding'' = DeclBinding ann expr
321320 return $ Abs (Nest (Let b' binding'') ds'') ans''
322321
323- checkAllFreeVariablesMentioned :: HoistableE e => e n -> OCCM n ()
324- checkAllFreeVariablesMentioned e = do
322+ wrapWithCachedFVs :: forall e n . HoistableE e => e n -> OCCM n (CachedFVs e n )
323+ wrapWithCachedFVs e = do
324+ FV fvMap <- get
325+ let fvs = keySetNameMapE fvMap
325326#ifdef DEX_DEBUG
326- FV fvs <- get
327- forM_ (nameSetToList (freeVarsE e)) \ name ->
328- case lookupNameMapE name fvs of
329- Just _ -> return ()
330- Nothing -> error $ " Free variable map missing free variable " ++ show name
327+ let fvsOk = map getRawName (freeVarsList e :: [SAtomName n ]) == nameSetRawNames fvs
331328#else
332- void $ return e -- Refer to `e` in this branch to avoid a GHC warning
333- return ()
334- {-# INLINE checkAllFreeVariablesMentioned #-}
329+ -- Verification of this invariant defeats the performance benefits of
330+ -- avoiding the extra traversal (e.g. actually having linear complexity),
331+ -- so we only do that in debug builds.
332+ let fvsOk = True
335333#endif
334+ case fvsOk of
335+ True -> return $ UnsafeCachedFVs fvs e
336+ False -> error $ " Free variables were computed incorrectly."
336337
337338instance HasOCC (DeclBinding SimpIR ) where
338339 occ a (DeclBinding ann expr) = do
@@ -407,14 +408,11 @@ instance HasOCC (Hof SimpIR) where
407408 modify (<> useManyTimes bodyFV)
408409 return body'
409410 RunReader ini bd -> do
410- ini' <- occ accessOnce ini
411411 iniIx <- summary ini
412- bd' <- oneShot a [Deterministic [] , iniIx]bd
412+ bd' <- oneShot a [Deterministic [] , iniIx] bd
413+ ini' <- occ accessOnce ini
413414 return $ RunReader ini' bd'
414415 RunWriter Nothing (BaseMonoid empty combine) bd -> do
415- -- We will process the combining function when we meet it in MExtend ops
416- -- (but we won't attempt to eliminate dead code in it).
417- empty' <- occ accessOnce empty
418416 -- There is no way to read from the reference in a Writer, so the only way
419417 -- an indexing expression can depend on it is by referring to the
420418 -- reference itself. One way to so refer that is opaque to occurrence
@@ -428,17 +426,20 @@ instance HasOCC (Hof SimpIR) where
428426 -- different references across loop iterations are not distinguishable.
429427 -- The same argument holds for the heap parameter.
430428 bd' <- oneShot a [Deterministic [] , Deterministic [] ] bd
429+ -- We will process the combining function when we meet it in MExtend ops
430+ -- (but we won't attempt to eliminate dead code in it).
431+ empty' <- occ accessOnce empty
431432 return $ RunWriter Nothing (BaseMonoid empty' combine) bd'
432433 RunWriter (Just _) _ _ ->
433434 error " Expecting to do occurrence analysis before destination passing."
434435 RunState Nothing ini bd -> do
435- ini' <- occ accessOnce ini
436436 -- If we wanted to be more precise, the summary for the reference should
437437 -- be something about the stuff that might flow into the `put` operations
438438 -- affecting that reference. Using `IxAll` is a conservative
439439 -- approximation (in downstream analysis it means "assume I touch every
440440 -- value").
441- bd' <- oneShot a [Deterministic [] , IxAll ]bd
441+ bd' <- oneShot a [Deterministic [] , IxAll ] bd
442+ ini' <- occ accessOnce ini
442443 return $ RunState Nothing ini' bd'
443444 RunState (Just _) _ _ ->
444445 error " Expecting to do occurrence analysis before destination passing."
@@ -465,23 +466,25 @@ occWithBinder
465466 -> (forall l . DExt n l => Binder SimpIR n l -> e l -> OCCM l a )
466467 -> OCCM n a
467468occWithBinder (Abs (b:> ty) body) cont = do
468- ty' <- occTy ty
469- refreshAbs (Abs (b:> ty') body) cont
469+ (ty', fvs) <- isolated $ occTy ty
470+ ans <- refreshAbs (Abs (b:> ty') body) cont
471+ modify (<> fvs)
472+ return ans
470473{-# INLINE occWithBinder #-}
471474
472475instance HasOCC (RefOp SimpIR ) where
473476 occ _ = \ case
474477 MExtend (BaseMonoid empty combine) val -> do
478+ valIx <- summary val
479+ -- Treat the combining function as inlined here and called once
480+ combine' <- oneShot accessOnce [Deterministic [] , valIx] combine
475481 val' <- occ accessOnce val
476- valIx <- summary val'
477482 -- TODO(precision) The empty value of the monoid is presumably dead here,
478483 -- but we pretend like it's not to make sure that occurrence analysis
479484 -- results mention every free variable in the traversed expression. This
480485 -- may lead to missing an opportunity to inline something into the empty
481486 -- value of the given monoid, since references thereto will be overcounted.
482487 empty' <- occ accessOnce empty
483- -- Treat the combining function as inlined here and called once
484- combine' <- oneShot accessOnce [Deterministic [] , valIx] combine
485488 return $ MExtend (BaseMonoid empty' combine') val'
486489 -- I'm pretty sure the others are all strict, and not usefully analyzable
487490 -- for what they do to the incoming access pattern.
0 commit comments