Skip to content

Commit

Permalink
Experimental change discarding the continuation for pushes with Nothing
Browse files Browse the repository at this point in the history
  • Loading branch information
b-studios committed Jan 22, 2025
1 parent 19042d4 commit eeedccc
Show file tree
Hide file tree
Showing 6 changed files with 52 additions and 34 deletions.
2 changes: 1 addition & 1 deletion effekt/jvm/src/test/scala/effekt/core/OptimizerTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ class OptimizerTests extends CoreTests {
def normalize(input: String, expected: String)(using munit.Location) =
assertTransformsTo(input, expected) { tree =>
val anfed = BindSubexpressions.transform(tree)
val normalized = Normalizer.normalize(Set(mainSymbol), anfed, 50)
val normalized = Normalizer.normalize(Set(mainSymbol), anfed, 50, false)
Deadcode.remove(mainSymbol, normalized)
}

Expand Down
52 changes: 26 additions & 26 deletions effekt/jvm/src/test/scala/effekt/core/VMTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -533,7 +533,7 @@ class VMTests extends munit.FunSuite {
dynamicDispatches = 0,
patternMatches = 400,
branches = 1487,
pushedFrames = 1352,
pushedFrames = 1185,
poppedFrames = 1409,
allocations = 54,
closures = 0,
Expand All @@ -549,7 +549,7 @@ class VMTests extends munit.FunSuite {
dynamicDispatches = 0,
patternMatches = 0,
branches = 210,
pushedFrames = 379,
pushedFrames = 378,
poppedFrames = 377,
allocations = 0,
closures = 0,
Expand Down Expand Up @@ -613,7 +613,7 @@ class VMTests extends munit.FunSuite {
dynamicDispatches = 0,
patternMatches = 4,
branches = 701,
pushedFrames = 874,
pushedFrames = 702,
poppedFrames = 880,
allocations = 4,
closures = 0,
Expand Down Expand Up @@ -660,13 +660,13 @@ class VMTests extends munit.FunSuite {

examplesDir / "casestudies" / "scheduler.effekt.md" -> Some(Summary(
staticDispatches = 60,
dynamicDispatches = 8,
dynamicDispatches = 7,
patternMatches = 95,
branches = 41,
pushedFrames = 106,
poppedFrames = 106,
allocations = 73,
closures = 8,
closures = 7,
variableReads = 29,
variableWrites = 18,
resets = 1,
Expand Down Expand Up @@ -695,40 +695,40 @@ class VMTests extends munit.FunSuite {
dynamicDispatches = 783,
patternMatches = 13502,
branches = 14892,
pushedFrames = 28523,
poppedFrames = 28499,
pushedFrames = 28210,
poppedFrames = 28186,
allocations = 7923,
closures = 521,
variableReads = 6742,
variableWrites = 1901,
resets = 806,
shifts = 855,
resumes = 839
resets = 778,
shifts = 229,
resumes = 213
)),

examplesDir / "casestudies" / "anf.effekt.md" -> Some(Summary(
staticDispatches = 4775,
dynamicDispatches = 443,
patternMatches = 7272,
branches = 8110,
pushedFrames = 16275,
poppedFrames = 16260,
pushedFrames = 16101,
poppedFrames = 16088,
allocations = 4317,
closures = 358,
variableReads = 4080,
variableWrites = 1343,
resets = 481,
shifts = 660,
resumes = 644
resets = 458,
shifts = 322,
resumes = 306
)),

examplesDir / "casestudies" / "inference.effekt.md" -> Some(Summary(
staticDispatches = 1457444,
dynamicDispatches = 3201452,
patternMatches = 1474290,
branches = 303298,
pushedFrames = 7574480,
poppedFrames = 6709185,
pushedFrames = 7574476,
poppedFrames = 6709181,
allocations = 4626007,
closures = 865541,
variableReads = 2908620,
Expand All @@ -741,11 +741,11 @@ class VMTests extends munit.FunSuite {
examplesDir / "pos" / "raytracer.effekt" -> Some(Summary(
staticDispatches = 79696,
dynamicDispatches = 0,
patternMatches = 1014772,
patternMatches = 795964,
branches = 71995,
pushedFrames = 223269,
poppedFrames = 223269,
allocations = 127533,
allocations = 103221,
closures = 0,
variableReads = 77886,
variableWrites = 26904,
Expand All @@ -761,26 +761,26 @@ class VMTests extends munit.FunSuite {
dynamicDispatches = 0,
patternMatches = 0,
branches = 11,
pushedFrames = 102,
poppedFrames = 102,
pushedFrames = 92,
poppedFrames = 92,
allocations = 0,
closures = 0,
variableReads = 61,
variableWrites = 30,
resets = 1,
shifts = 10,
resumes = 10
resets = 0,
shifts = 0,
resumes = 0
)),

examplesDir / "benchmarks" / "other" / "church_exponentiation.effekt" -> Some(Summary(
staticDispatches = 7,
dynamicDispatches = 1062912,
dynamicDispatches = 797188,
patternMatches = 0,
branches = 5,
pushedFrames = 531467,
poppedFrames = 531467,
allocations = 0,
closures = 265750,
closures = 26,
variableReads = 0,
variableWrites = 0,
resets = 0,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ object Normalizer { normal =>
exprs: Map[Id, Expr],
decls: DeclarationContext, // for field selection
usage: mutable.Map[Id, Usage], // mutable in order to add new information after renaming
maxInlineSize: Int // to control inlining and avoid code bloat
maxInlineSize: Int, // to control inlining and avoid code bloat
preserveBoxing: Boolean // for LLVM, prevents some optimizations
) {
def bind(id: Id, expr: Expr): Context = copy(exprs = exprs + (id -> expr))
def bind(id: Id, block: Block): Context = copy(blocks = blocks + (id -> block))
Expand Down Expand Up @@ -65,14 +66,14 @@ object Normalizer { normal =>
case None => false
}

def normalize(entrypoints: Set[Id], m: ModuleDecl, maxInlineSize: Int): ModuleDecl = {
def normalize(entrypoints: Set[Id], m: ModuleDecl, maxInlineSize: Int, preserveBoxing: Boolean): ModuleDecl = {
// usage information is used to detect recursive functions (and not inline them)
val usage = Reachable(entrypoints, m)

val defs = m.definitions.collect {
case Toplevel.Def(id, block) => id -> block
}.toMap
val context = Context(defs, Map.empty, DeclarationContext(m.declarations, m.externs), mutable.Map.from(usage), maxInlineSize)
val context = Context(defs, Map.empty, DeclarationContext(m.declarations, m.externs), mutable.Map.from(usage), maxInlineSize, preserveBoxing)

val (normalizedDefs, _) = normalizeToplevel(m.definitions)(using context)
m.copy(definitions = normalizedDefs)
Expand Down Expand Up @@ -213,6 +214,9 @@ object Normalizer { normal =>

def normalizeVal(id: Id, tpe: ValueType, binding: Stmt, body: Stmt): Stmt = normalize(binding) match {

// [[ val x = ABORT; body ]] = ABORT
case s if !C.preserveBoxing && s.tpe == Type.TBottom => s

// [[ val x = sc match { case id(ps) => body2 }; body ]] = sc match { case id(ps) => val x = body2; body }
case Stmt.Match(sc, List((id2, BlockLit(tparams2, cparams2, vparams2, bparams2, body2))), None) =>
Stmt.Match(sc, List((id2, BlockLit(tparams2, cparams2, vparams2, bparams2,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ object Optimizer extends Phase[CoreTransformed, CoreTransformed] {

def optimize(source: Source, mainSymbol: symbols.Symbol, core: ModuleDecl)(using Context): ModuleDecl =

val isLLVM = Context.config.backend().name == "llvm"

var tree = core

// (1) first thing we do is simply remove unused definitions (this speeds up all following analysis and rewrites)
Expand All @@ -37,9 +39,10 @@ object Optimizer extends Phase[CoreTransformed, CoreTransformed] {

def normalize(m: ModuleDecl) = {
val anfed = BindSubexpressions.transform(m)
val normalized = Normalizer.normalize(Set(mainSymbol), anfed, Context.config.maxInlineSize().toInt)
val normalized = Normalizer.normalize(Set(mainSymbol), anfed, Context.config.maxInlineSize().toInt, isLLVM)
val live = Deadcode.remove(mainSymbol, normalized)
RemoveTailResumptions(live)
val tailRemoved = RemoveTailResumptions(live)
tailRemoved
}

// (3) normalize a few times (since tail resumptions might only surface after normalization and leave dead Resets)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ object RemoveTailResumptions {
case Stmt.Get(id, annotatedCapt, annotatedTpe) => false
case Stmt.Put(id, annotatedCapt, value) => false
case Stmt.Reset(BlockLit(tparams, cparams, vparams, bparams, body)) => tailResumptive(k, body) // is this correct?
case Stmt.Shift(prompt, body) => false
case Stmt.Shift(prompt, body) => stmt.tpe == Type.TBottom
case Stmt.Resume(k2, body) => k2.id == k // what if k is free in body?
case Stmt.Hole() => true
}
Expand Down
13 changes: 12 additions & 1 deletion effekt/shared/src/main/scala/effekt/cps/Transformer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,9 @@ object Transformer {
case core.Stmt.App(callee, targs, vargs, bargs) =>
App(transform(callee), vargs.map(transform), bargs.map(transform), MetaCont(ks), k.reify)

case core.Stmt.Invoke(callee, method, tpe, targs, vargs, bargs) if stmt.tpe == core.Type.TBottom =>
Invoke(transform(callee), method, vargs.map(transform), bargs.map(transform), MetaCont(ks), Continuation.Empty)

case core.Stmt.Invoke(callee, method, tpe, targs, vargs, bargs) =>
Invoke(transform(callee), method, vargs.map(transform), bargs.map(transform), MetaCont(ks), k.reify)

Expand Down Expand Up @@ -119,7 +122,10 @@ object Transformer {
val translatedBody: BlockLit = BlockLit(vparams.map { p => p.id }, List(resume.id), ks2, k2,
transform(body, ks2, Continuation.Dynamic(k2)))

Shift(prompt.id, translatedBody, MetaCont(ks), k.reify)
// if the answer type is Nothing, then the continuation is discarded anyways...
val continuation = if (stmt.tpe == core.Type.TBottom) Continuation.Empty else k.reify

Shift(prompt.id, translatedBody, MetaCont(ks), continuation)

case core.Stmt.Shift(prompt, body) => sys error "Shouldn't happen"

Expand Down Expand Up @@ -234,4 +240,9 @@ enum Continuation {
object Continuation {
def Static(hint: Id)(k: (Pure, Id) => Stmt): Continuation.Static = Continuation.Static(hint, k)

val Empty: Cont = {
val a = Id("a")
val ks = Id("ks")
cps.Cont.ContLam(a, ks, cps.Hole())
}
}

0 comments on commit eeedccc

Please sign in to comment.