Skip to content

Commit c8492db

Browse files
committed
Implement and test case-of-known-constructor optimization in the inliner.
1 parent d722df2 commit c8492db

File tree

5 files changed

+54
-3
lines changed

5 files changed

+54
-3
lines changed

src/lib/CheapReduction.hs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ module CheapReduction
1515
, unwrapLeadingNewtypesType, wrapNewtypesData, liftSimpAtom, liftSimpType
1616
, liftSimpFun, makeStructRepVal, NonAtomRenamer (..), Visitor (..), VisitGeneric (..)
1717
, visitAtomPartial, visitTypePartial, visitAtomDefault, visitTypeDefault, Visitor2
18-
, visitBinders, visitPiDefault)
18+
, visitBinders, visitPiDefault, visitAlt)
1919
where
2020

2121
import Control.Applicative

src/lib/Inline.hs

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import IRVariants
1616
import Name
1717
import Subst
1818
import Occurrence hiding (Var)
19+
import Optimize
1920
import Types.Core
2021
import Types.Primitives
2122

@@ -90,7 +91,7 @@ inlineDeclsSubst = \case
9091
s <- getSubst
9192
extendSubst (b @> SubstVal (SuspEx expr s)) $ inlineDeclsSubst rest
9293
else do
93-
expr' <- inlineExpr Stop expr
94+
expr' <- inlineExpr Stop expr >>= (liftEnvReaderM . peepholeExpr)
9495
-- If the inliner starts moving effectful expressions, it may become
9596
-- necessary to query the effects of the new expression here.
9697
let presInfo = resolveWorkConservation ann expr'
@@ -248,6 +249,9 @@ data Context (from::E) (to::E) (o::S) where
248249
Stop :: Context e e o
249250
TabAppCtx :: [SAtom i] -> Subst InlineSubstVal i o
250251
-> Context SExpr e o -> Context SExpr e o
252+
CaseCtx :: [SAlt i] -> SType i -> EffectRow SimpIR i
253+
-> Subst InlineSubstVal i o
254+
-> Context SExpr e o -> Context SExpr e o
251255
EmitToAtomCtx :: Context SAtom e o -> Context SExpr e o
252256
EmitToNameCtx :: Context SAtomName e o -> Context SAtom e o
253257

@@ -271,6 +275,9 @@ inlineExpr ctx = \case
271275
TabApp tbl ixs -> do
272276
s <- getSubst
273277
inlineAtom (TabAppCtx ixs s ctx) tbl
278+
Case scrut alts resultTy effs -> do
279+
s <- getSubst
280+
inlineAtom (CaseCtx alts resultTy effs s ctx) scrut
274281
expr -> visitGeneric expr >>= reconstruct ctx
275282

276283
inlineAtom :: Emits o => Context SExpr e o -> SAtom i -> InlineM i o (e o)
@@ -340,12 +347,18 @@ instance Inlinable SBlock where
340347
effs' <- inline Stop effs -- TODO Really?
341348
reconstruct ctx $ Block (BlockAnn ty' effs') decls' ans'
342349

350+
inlineBlockEmits :: Emits o => Context SExpr e2 o -> SBlock i -> InlineM i o (e2 o)
351+
inlineBlockEmits ctx (Block _ decls ans) = do
352+
inlineDecls decls $ inlineAtom ctx ans
353+
343354
-- Still using InlineM because we may call back into inlining, and we wish to
344355
-- retain our output binding environment.
345356
reconstruct :: Emits o => Context e1 e2 o -> e1 o -> InlineM i o (e2 o)
346357
reconstruct ctx e = case ctx of
347358
Stop -> return e
348359
TabAppCtx ixs s ctx' -> withSubst s $ reconstructTabApp ctx' e ixs
360+
CaseCtx alts resultTy effs s ctx' ->
361+
withSubst s $ reconstructCase ctx' e alts resultTy effs
349362
EmitToAtomCtx ctx' -> emitExprToAtom e >>= reconstruct ctx'
350363
EmitToNameCtx ctx' -> emit (Atom e) >>= reconstruct ctx'
351364
{-# INLINE reconstruct #-}
@@ -404,5 +417,23 @@ reconstructTabApp ctx expr ixs =
404417
ixs' <- mapM (inline Stop) ixs
405418
reconstruct ctx $ TabApp array' ixs'
406419

420+
reconstructCase :: Emits o
421+
=> Context SExpr e o -> SExpr o -> [SAlt i] -> SType i -> EffectRow SimpIR i
422+
-> 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
434+
resultTy' <- inline Stop resultTy
435+
effs' <- inline Stop effs
436+
reconstruct ctx $ Case scrut alts' resultTy' effs'
437+
407438
instance Inlinable (EffectRow SimpIR)
408439
instance Inlinable (EffectAndType SimpIR)

src/lib/Optimize.hs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
{-# LANGUAGE UndecidableInstances #-}
88

99
module Optimize
10-
( optimize, peepholeOp
10+
( optimize, peepholeOp, peepholeExpr
1111
, hoistLoopInvariant, hoistLoopInvariantDest
1212
, dceTop, dceTopDest
1313
, foldCast ) where

src/lib/Types/Core.hs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -425,6 +425,7 @@ type SAtom = Atom SimpIR
425425
type SType = Type SimpIR
426426
type SExpr = Expr SimpIR
427427
type SBlock = Block SimpIR
428+
type SAlt = Alt SimpIR
428429
type SDecl = Decl SimpIR
429430
type SDecls = Decls SimpIR
430431
type SAtomName = AtomName SimpIR

tests/inline-tests.dx

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,3 +87,22 @@ def id'(x:Nat) -> Nat = x
8787
sum (for i:(Fin 2) j:(..i). ordinal j)[ix]
8888
-- CHECK: 1
8989
-- CHECK-NOT: Compiler bug
90+
91+
-- CHECK-LABEL: Inlining simplifies case-of-known-constructor
92+
"Inlining simplifies case-of-known-constructor"
93+
94+
-- Inlining xs exposes a case-of-known-constructor opportunity here;
95+
-- the first inlining pass doesn't take it (yet) because it's
96+
-- conservative about inlining `i` into the body of `xs`, but the
97+
-- second pass does.
98+
%passes inline
99+
:pp
100+
xs = for i:(Either (Fin 3) (Fin 4)).
101+
case i of
102+
Left k -> 1
103+
Right k -> 2
104+
for j:(Fin 3). xs[Left j]
105+
-- CHECK: === inline ===
106+
-- CHECK: case
107+
-- CHECK: === inline ===
108+
-- CHECK-NOT: case

0 commit comments

Comments
 (0)