Skip to content

Commit 339117f

Browse files
committed
Implement and test case-of-case optimization in the inliner.
1 parent c8492db commit 339117f

File tree

3 files changed

+61
-20
lines changed

3 files changed

+61
-20
lines changed

src/lib/Builder.hs

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -768,15 +768,15 @@ injectAltResult sumTys con (Abs b body) = liftBuilder do
768768

769769
-- TODO: consider a version with nonempty list of alternatives where we figure
770770
-- out the result type from one of the alts rather than providing it explicitly
771-
buildCase :: (Emits n, ScopableBuilder r m)
772-
=> Atom r n -> Type r n
773-
-> (forall l. (Emits l, DExt n l) => Int -> Atom r l -> m l (Atom r l))
774-
-> m n (Atom r n)
775-
buildCase scrut resultTy indexedAltBody = do
771+
buildCase' :: (Emits n, ScopableBuilder r m)
772+
=> Atom r n -> Type r n
773+
-> (forall l. (Emits l, DExt n l) => Int -> Atom r l -> m l (Atom r l))
774+
-> m n (Expr r n)
775+
buildCase' scrut resultTy indexedAltBody = do
776776
case trySelectBranch scrut of
777777
Just (i, arg) -> do
778778
Distinct <- getDistinct
779-
indexedAltBody i $ sink arg
779+
Atom <$> indexedAltBody i (sink arg)
780780
Nothing -> do
781781
scrutTy <- getType scrut
782782
altBinderTys <- caseAltsBinderTys scrutTy
@@ -786,7 +786,13 @@ buildCase scrut resultTy indexedAltBody = do
786786
eff <- getEffects blk
787787
return $ blk `PairE` eff
788788
return (Abs b' body, ignoreHoistFailure $ hoist b' eff')
789-
emitExpr $ Case scrut alts resultTy $ mconcat effs
789+
return $ Case scrut alts resultTy $ mconcat effs
790+
791+
buildCase :: (Emits n, ScopableBuilder r m)
792+
=> Atom r n -> Type r n
793+
-> (forall l. (Emits l, DExt n l) => Int -> Atom r l -> m l (Atom r l))
794+
-> m n (Atom r n)
795+
buildCase s r b = emitExprToAtom =<< buildCase' s r b
790796

791797
buildEffLam
792798
:: ScopableBuilder r m

src/lib/Inline.hs

Lines changed: 28 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -420,20 +420,35 @@ reconstructTabApp ctx expr ixs =
420420
reconstructCase :: Emits o
421421
=> Context SExpr e o -> SExpr o -> [SAlt i] -> SType i -> EffectRow SimpIR i
422422
-> InlineM i o (e o)
423-
reconstructCase ctx scrutExpr alts resultTy effs = do
424-
-- TODO Opportunity here to inspect `scrutExpr` and perform case-of-case
425-
-- optimization
426-
scrut <- emitExprToAtom scrutExpr
427-
case trySelectBranch scrut of
428-
Just (i, val) -> do
429-
Abs b body <- return $ alts !! i
430-
extendSubst (b @> (SubstVal $ DoneEx $ Atom val)) do
431-
inlineBlockEmits ctx body
432-
Nothing -> do
433-
alts' <- mapM visitAlt alts
423+
reconstructCase ctx scrutExpr alts resultTy effs =
424+
case scrutExpr of
425+
Case sscrut salts _ _ -> do
426+
-- Perform case-of-case optimization
427+
-- TODO Add join points to reduce code duplication (and repeated inlining)
428+
-- of the arms of the outer case
434429
resultTy' <- inline Stop resultTy
435-
effs' <- inline Stop effs
436-
reconstruct ctx $ Case scrut alts' resultTy' effs'
430+
reconstruct ctx =<< (buildCase' sscrut resultTy' \i val -> do
431+
ans <- applyAbs (sink $ salts !! i) (SubstVal val) >>= emitBlock
432+
buildCase ans (sink resultTy') \j jval -> do
433+
Abs b body <- return $ alts !! j
434+
extendSubst (b @> (SubstVal $ DoneEx $ Atom jval)) do
435+
inlineBlockEmits Stop body >>= emitExprToAtom)
436+
_ -> do
437+
-- Attempt case-of-known-constructor optimization
438+
-- I can't use `buildCase` here because I want to propagate the incoming
439+
-- context `ctx` into the selected alternative if the optimization fires,
440+
-- but leave it around the whole reconstructed `Case` if it doesn't.
441+
scrut <- emitExprToAtom scrutExpr
442+
case trySelectBranch scrut of
443+
Just (i, val) -> do
444+
Abs b body <- return $ alts !! i
445+
extendSubst (b @> (SubstVal $ DoneEx $ Atom val)) do
446+
inlineBlockEmits ctx body
447+
Nothing -> do
448+
alts' <- mapM visitAlt alts
449+
resultTy' <- inline Stop resultTy
450+
effs' <- inline Stop effs
451+
reconstruct ctx $ Case scrut alts' resultTy' effs'
437452

438453
instance Inlinable (EffectRow SimpIR)
439454
instance Inlinable (EffectAndType SimpIR)

tests/inline-tests.dx

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,3 +106,23 @@ def id'(x:Nat) -> Nat = x
106106
-- CHECK: case
107107
-- CHECK: === inline ===
108108
-- CHECK-NOT: case
109+
110+
-- CHECK-LABEL: Inlining carries out the case-of-case optimization
111+
"Inlining carries out the case-of-case optimization"
112+
113+
-- Before inlining there are two cases, but attempting to inline `x`
114+
-- reveals a case-of-case opprtunity, which in turn exposes
115+
-- case-of-known-constructor in each branch, leading to just one case
116+
-- in the end.
117+
%passes inline
118+
:pp
119+
x = if id'(3) > 2
120+
then Just 4
121+
else Nothing
122+
case x of
123+
Just a -> a * a
124+
Nothing -> 0
125+
-- CHECK: === inline ===
126+
-- CHECK: case
127+
-- CHECK-NOT: case
128+
-- CHECK: === inline ===

0 commit comments

Comments
 (0)