Skip to content
Merged
Show file tree
Hide file tree
Changes from 20 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
4b8024c
Fix missing parameter info in regions
marvinborner Mar 13, 2025
07efcfd
Fill extern LLVM hole
marvinborner Mar 13, 2025
d858627
Substitute unknown blocks
phischu Mar 28, 2025
9f1b9f9
Also note name of substituted block
phischu Mar 28, 2025
7ecdfd0
Merge branch 'master' into fix/failing-tests-without-optimization
marvinborner Mar 28, 2025
bb7b433
Update tour
marvinborner Mar 28, 2025
b7c7df5
Update tests
phischu Mar 28, 2025
7a85be4
Remove global symbol
marvinborner Mar 28, 2025
83c5c3b
Deglobalify queue
marvinborner Mar 28, 2025
fd0417c
Deglobalify buffer
marvinborner Mar 28, 2025
2612a44
Remove other special casing of global
phischu Mar 28, 2025
302f8d8
Add queue check file
marvinborner Mar 28, 2025
95a776a
Delete global region from runtimes
phischu Mar 28, 2025
707d098
Use val for refs
marvinborner Mar 28, 2025
5f0a9d9
Update vm tests
marvinborner Mar 28, 2025
7b5ee5c
Merge branch 'fix/global' into fix/failing-tests-without-optimization
marvinborner Mar 28, 2025
0b1e139
Uncomment tests without optimization
marvinborner Mar 28, 2025
4839ef3
Merge branch 'master' into fix/failing-tests-without-optimization
marvinborner Mar 28, 2025
042ce6d
Fix js runtime merge
marvinborner Mar 28, 2025
b3d110c
Move stdlib char tests
marvinborner Mar 28, 2025
a6b1cae
Toplevel object definitions
phischu Mar 28, 2025
b865ef9
Merge branch 'fix/llvm-toplevel-objects' into fix/failing-tests-witho…
marvinborner Mar 28, 2025
52fb6ff
Also run top level object definition tests
marvinborner Mar 28, 2025
e9ccf5a
Force toplevel to receive block parameter
phischu Mar 28, 2025
270a261
Merge branch 'fix/llvm-toplevel-objects' into fix/failing-tests-witho…
marvinborner Mar 28, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 4 additions & 6 deletions effekt/jvm/src/test/scala/effekt/JavaScriptTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,12 @@ class JavaScriptTests extends EffektTests {

override lazy val withoutOptimizations: List[File] = List(
// contifying under reset
//examplesDir / "pos" / "issue842.effekt",
//examplesDir / "pos" / "issue861.effekt",
examplesDir / "pos" / "issue842.effekt",
examplesDir / "pos" / "issue861.effekt",

// syntax error (multiple declaration)
//examplesDir / "char" / "ascii_isalphanumeric.effekt",
//examplesDir / "char" / "ascii_iswhitespace.effekt",
//examplesDir / "pos" / "parser.effekt",
//examplesDir / "pos" / "probabilistic.effekt",
examplesDir / "pos" / "parser.effekt",
examplesDir / "pos" / "probabilistic.effekt",
)

override def ignored: List[File] = List(
Expand Down
23 changes: 9 additions & 14 deletions effekt/jvm/src/test/scala/effekt/LLVMTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,15 @@ class LLVMTests extends EffektTests {

override lazy val withoutOptimizations: List[File] = List(
// contifying under reset
//examplesDir / "pos" / "issue842.effekt",
//examplesDir / "pos" / "issue861.effekt",
examplesDir / "pos" / "issue842.effekt",
examplesDir / "pos" / "issue861.effekt",

examplesDir / "pos" / "capture" / "regions.effekt",
examplesDir / "pos" / "capture" / "selfregion.effekt",
examplesDir / "benchmarks" / "other" / "generator.effekt",
examplesDir / "pos" / "bidirectional" / "typeparametric.effekt",
examplesDir / "benchmarks" / "are_we_fast_yet" / "permute.effekt",
examplesDir / "benchmarks" / "are_we_fast_yet" / "storage.effekt",

// top-level object definition
//examplesDir / "pos" / "object" / "if_control_effect.effekt",
Expand All @@ -65,18 +72,6 @@ class LLVMTests extends EffektTests {
//examplesDir / "pos" / "bidirectional" / "higherorderobject.effekt",
//examplesDir / "pos" / "bidirectional" / "res_obj_boxed.effekt",
//examplesDir / "pos" / "bidirectional" / "effectfulobject.effekt",

// no block info
//examplesDir / "pos" / "capture" / "regions.effekt",
//examplesDir / "pos" / "capture" / "selfregion.effekt",
//examplesDir / "benchmarks" / "other" / "generator.effekt",

// hole
//examplesDir / "pos" / "bidirectional" / "typeparametric.effekt",

// segfault
//examplesDir / "benchmarks" / "are_we_fast_yet" / "permute.effekt",
//examplesDir / "benchmarks" / "are_we_fast_yet" / "storage.effekt",
)

override lazy val ignored: List[File] = missingFeatures ++ noValgrind(examplesDir)
Expand Down
23 changes: 10 additions & 13 deletions effekt/jvm/src/test/scala/effekt/StdlibTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -21,19 +21,16 @@ class StdlibJavaScriptTests extends StdlibTests {

override def withoutOptimizations: List[File] = List(
examplesDir / "stdlib" / "acme.effekt",

//examplesDir / "stdlib" / "json.effekt",
//examplesDir / "stdlib" / "exception" / "combinators.effekt",

// reference error (k is not defined)
//examplesDir / "stdlib" / "stream" / "fibonacci.effekt",
//examplesDir / "stdlib" / "list" / "flatmap.effekt",
//examplesDir / "stdlib" / "list" / "sortBy.effekt",
//examplesDir / "stdlib" / "stream" / "zip.effekt",
//examplesDir / "stdlib" / "stream" / "characters.effekt",

// oom
//examplesDir / "stdlib" / "list" / "deleteat.effekt",
examplesDir / "stdlib" / "json.effekt",
examplesDir / "stdlib" / "exception" / "combinators.effekt",
examplesDir / "stdlib" / "stream" / "fibonacci.effekt",
examplesDir / "stdlib" / "list" / "flatmap.effekt",
examplesDir / "stdlib" / "list" / "sortBy.effekt",
examplesDir / "stdlib" / "stream" / "zip.effekt",
examplesDir / "stdlib" / "stream" / "characters.effekt",
examplesDir / "stdlib" / "list" / "deleteat.effekt",
examplesDir / "stdlib" / "char" / "ascii_isalphanumeric.effekt",
examplesDir / "stdlib" / "char" / "ascii_iswhitespace.effekt",
)

override def ignored: List[File] = List()
Expand Down
2 changes: 1 addition & 1 deletion effekt/jvm/src/test/scala/effekt/core/CoreTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import effekt.PhaseResult.CoreTransformed
*/
trait CoreTests extends munit.FunSuite {

protected def defaultNames = symbols.builtins.rootTypes ++ symbols.builtins.rootTerms ++ symbols.builtins.rootCaptures
protected def defaultNames: Map[String, _root_.effekt.symbols.Symbol] = symbols.builtins.rootTypes ++ symbols.builtins.rootCaptures

def shouldBeEqual(obtained: ModuleDecl, expected: ModuleDecl, clue: => Any)(using Location) =
assertEquals(obtained, expected, {
Expand Down
8 changes: 4 additions & 4 deletions effekt/jvm/src/test/scala/effekt/core/VMTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -357,8 +357,8 @@ class VMTests extends munit.FunSuite {
poppedFrames = 8661,
allocations = 0,
closures = 0,
variableReads = 32437,
variableWrites = 13699,
variableReads = 23776,
variableWrites = 5039,
resets = 0,
shifts = 0,
resumes = 0
Expand All @@ -373,8 +373,8 @@ class VMTests extends munit.FunSuite {
poppedFrames = 5462,
allocations = 5461,
closures = 0,
variableReads = 13654,
variableWrites = 9557,
variableReads = 8192,
variableWrites = 4096,
resets = 0,
shifts = 0,
resumes = 0
Expand Down
15 changes: 0 additions & 15 deletions effekt/shared/src/main/scala/effekt/Typer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -54,21 +54,6 @@ object Typer extends Phase[NameResolved, Typechecked] {
Context in {
Context.withUnificationScope {
flowingInto(builtins.toplevelCaptures) {
// bring builtins into scope
builtins.rootTerms.values.foreach {
case term: BlockParam =>
Context.bind(term, term.tpe.getOrElse {
INTERNAL_ERROR("Builtins should always be annotated with their types.")
})
Context.bind(term, CaptureSet(term.capture))
case term: ExternResource =>
Context.bind(term, term.tpe)
Context.bind(term, CaptureSet(term.capture))
case term: Callable =>
Context.bind(term, term.toType)
case term => Context.panic(s"Cannot bind builtin term: ${term}")
}

// We split the type-checking of definitions into "pre-check" and "check"
// to allow mutually recursive defs
tree.defs.foreach { d => precheckDef(d) }
Expand Down
5 changes: 0 additions & 5 deletions effekt/shared/src/main/scala/effekt/core/vm/VM.scala
Original file line number Diff line number Diff line change
Expand Up @@ -331,11 +331,6 @@ class Interpreter(instrumentation: Instrumentation, runtime: Runtime) {
// TODO make the type of Region more precise...
case Stmt.Region(_) => ???

case Stmt.Alloc(id, init, region, body) if region == symbols.builtins.globalRegion =>
val value = eval(init, env)
val address = freshAddress()
State.Step(body, env.bind(id, Computation.Reference(address)), stack, heap.updated(address, value))

case Stmt.Alloc(id, init, region, body) =>
val value = eval(init, env)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,9 +95,6 @@ trait Transformer {
case Var(ref, init, capt, body) =>
state(nameDef(ref), toChez(init), toChez(body))

case Alloc(id, init, region, body) if region == symbols.builtins.globalRegion =>
chez.Let(List(Binding(nameDef(id), chez.Builtin("box", toChez(init)))), toChez(body))

case Alloc(id, init, region, body) =>
chez.Let(List(Binding(nameDef(id), chez.Builtin("fresh", chez.Variable(nameRef(region)), toChez(init)))), toChez(body))

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,12 +70,7 @@ object TransformerCps extends Transformer {
val jsDecls = module.declarations.flatMap(toJS)
val stmts = module.definitions.map(toJS)

val state = js.Const(
nameDef(symbols.builtins.globalRegion),
js.Variable(JSName("global"))
) :: Nil

js.Module(name, Nil, exports, jsDecls ++ jsExterns ++ state ++ stmts)
js.Module(name, Nil, exports, jsDecls ++ jsExterns ++ stmts)
}

def compileLSP(input: cps.ModuleDecl, coreModule: core.ModuleDecl)(using C: Context): List[js.Stmt] =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -378,8 +378,6 @@ object Transformer {

def transform(value: machine.Variable)(using FunctionContext): Operand =
substitute(value) match {
// TODO rethink existence of global
case machine.Variable("global", machine.Type.Prompt()) => ConstantGlobal("global")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:D

case machine.Variable(name, tpe) => LocalReference(transform(tpe), name)
}

Expand Down
44 changes: 16 additions & 28 deletions effekt/shared/src/main/scala/effekt/machine/Transformer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -89,9 +89,7 @@ object Transformer {

// Regions are blocks and can be free, but do not have info.
case core.Variable.Block(id, core.Type.TRegion, capt) =>
if id == symbols.builtins.globalRegion
then Set.empty
else Set(Variable(transform(id), Type.Prompt()))
Set(Variable(transform(id), Type.Prompt()))

case core.Variable.Block(pid, tpe, capt) if pid != id => BPC.info.get(pid) match {
// For each known free block we have to add its free variables to this one (flat closure)
Expand Down Expand Up @@ -120,13 +118,16 @@ object Transformer {
noteParameter(id, block.tpe)
New(Variable(transform(id), transform(impl.interface)), transform(impl), transform(rest))

case core.Def(id, block @ core.BlockVar(alias, tpe, _), rest) =>
getDefinition(alias) match {
case core.Def(id, core.BlockVar(other, tpe, capt), rest) =>
getBlockInfo(other) match {
case BlockInfo.Definition(free, params) =>
noteDefinition(id, free, params)
emitDefinition(transformLabel(id), Jump(transformLabel(other)))
transform(rest)
case BlockInfo.Parameter(_) =>
noteParameter(id, tpe)
Substitute(List(Variable(transform(id), transform(tpe)) -> Variable(transform(other), transform(tpe))), transform(rest))
}
emitDefinition(transformLabel(id), Jump(transformLabel(alias)))
transform(rest)

case core.Def(id, block @ core.Unbox(pure), rest) =>
noteParameter(id, block.tpe)
Expand Down Expand Up @@ -246,6 +247,8 @@ object Transformer {
Resume(Variable(transform(k.id), Type.Stack()), transform(body))

case core.Region(core.BlockLit(tparams, cparams, vparams, List(region), body)) =>
noteParameters(List(region))

val variable = Variable(freshName("returned"), transform(body.tpe))
val returnClause = Clause(List(variable), Return(List(variable)))
val prompt = transform(region)
Expand All @@ -254,24 +257,13 @@ object Transformer {

case core.Alloc(id, init, region, body) =>
transform(init).run { value =>
val tpe = value.tpe;
val name = transform(id)
val variable = Variable(name, tpe)
val reference = Variable(transform(id), Type.Reference(tpe))
val reference = Variable(transform(id), Type.Reference(value.tpe))
val prompt = Variable(transform(region), Type.Prompt())
val temporary = Variable(freshName("temporaryStack"), Type.Stack())

region match {
case symbols.builtins.globalRegion =>
val globalPrompt = Variable("global", Type.Prompt())
Shift(temporary, globalPrompt,
Var(reference, value, Type.Positive(),
Resume(temporary, transform(body))))
case _ =>
Shift(temporary, prompt,
Var(reference, value, Type.Positive(),
Resume(temporary, transform(body))))
}
Shift(temporary, prompt,
Var(reference, value, Type.Positive(),
Resume(temporary, transform(body))))
}

case core.Var(ref, init, capture, body) =>
Expand Down Expand Up @@ -486,8 +478,9 @@ object Transformer {
case core.BlockType.Interface(symbol, targs) => Negative()
}

def transformLabel(id: Id)(using BPC: BlocksParamsContext): Label = getDefinition(id) match {
def transformLabel(id: Id)(using BPC: BlocksParamsContext): Label = getBlockInfo(id) match {
case BlockInfo.Definition(freeParams, boundParams) => Label(transform(id), boundParams ++ freeParams)
case BlockInfo.Parameter(_) => sys error s"Expected a function definition, but got a block parameter: ${id}"
}

def transform(id: Id): String =
Expand Down Expand Up @@ -554,11 +547,6 @@ object Transformer {
def getBlockInfo(id: Id)(using BPC: BlocksParamsContext): BlockInfo =
BPC.info.getOrElse(id, sys error s"No block info for ${util.show(id)}")

def getDefinition(id: Id)(using BPC: BlocksParamsContext): BlockInfo.Definition = getBlockInfo(id) match {
case d : BlockInfo.Definition => d
case BlockInfo.Parameter(tpe) => sys error s"Expected a function getDefinition, but got a block parameter: ${id}"
}

case class Binding[A](run: (A => Statement) => Statement) {
def flatMap[B](rest: A => Binding[B]): Binding[B] = {
Binding(k => run(a => rest(a).run(k)))
Expand Down
16 changes: 6 additions & 10 deletions effekt/shared/src/main/scala/effekt/symbols/builtins.scala
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@ object builtins {
val AsyncSymbol = Interface(Name.local("Async"), Nil, Nil)
val AsyncCapability = ExternResource(name("async"), InterfaceType(AsyncSymbol, Nil))

val GlobalSymbol = Interface(Name.local("Global"), Nil, Nil)
val GlobalCapability = ExternResource(name("global"), InterfaceType(GlobalSymbol, Nil))

object TState {
val S: TypeParam = TypeParam(Name.local("S"))
val interface: Interface = Interface(Name.local("Ref"), List(S), Nil)
Expand Down Expand Up @@ -86,23 +89,16 @@ object builtins {
"Region" -> RegionSymbol
)

lazy val globalRegion = ExternResource(name("global"), TRegion)

val rootTerms: Map[String, TermSymbol] = Map(
"global" -> globalRegion
)

val rootCaptures: Map[String, Capture] = Map(
"io" -> IOCapability.capture,
"async" -> AsyncCapability.capture,
"global" -> globalRegion.capture
"global" -> GlobalCapability.capture
)

// captures which are allowed on the toplevel
val toplevelCaptures: CaptureSet = CaptureSet() // CaptureSet(IOCapability.capture, globalRegion.capture)
val toplevelCaptures: CaptureSet = CaptureSet() // CaptureSet(IOCapability.capture, GlobalCapability.capture)

lazy val rootBindings: Bindings =
Bindings(rootTerms.map { case (k, v) => (k, Set(v)) }, rootTypes, rootCaptures,
Map("effekt" -> Bindings(rootTerms.map { case (k, v) => (k, Set(v)) }, rootTypes, rootCaptures, Map.empty)))
Bindings(Map.empty, rootTypes, rootCaptures, Map("effekt" -> Bindings(Map.empty, rootTypes, rootCaptures, Map.empty)))

}
7 changes: 4 additions & 3 deletions examples/benchmarks/are_we_fast_yet/permute.effekt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import examples/benchmarks/runner

import ref
import array

def swap(arr: Array[Int], i: Int, j: Int) = {
Expand All @@ -9,10 +10,10 @@ def swap(arr: Array[Int], i: Int, j: Int) = {
}

def run(n: Int) = {
var count in global = 0;
val count = ref(0);

def permute(arr: Array[Int], n: Int): Unit = {
count = count + 1;
count.set(count.get + 1);
if (n != 0) {
val n1 = n - 1;
permute(arr, n1);
Expand All @@ -28,7 +29,7 @@ def run(n: Int) = {

array(n, 1).permute(n);

count
count.get
}

def main() = benchmark(6){run}
Expand Down
7 changes: 4 additions & 3 deletions examples/benchmarks/are_we_fast_yet/storage.effekt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import examples/benchmarks/runner

import ref
import array

type Tree {
Expand All @@ -25,10 +26,10 @@ def withRandom[R]{ program: { Random } => R }: R = {
}

def run(n: Int) = {
var count in global = 0;
val count = ref(0);

def buildTreeDepth(depth: Int) { rand: Random }: Tree = {
count = count + 1;
count.set(count.get + 1);
if (depth == 1) {
Leaf(allocate(mod(rand.next, 10) + 1))
} else {
Expand All @@ -44,7 +45,7 @@ def run(n: Int) = {
withRandom { { rand: Random } => buildTreeDepth(7) {rand}; () }
}

count
count.get
}

def main() = benchmark(1){run}
1 change: 1 addition & 0 deletions examples/pos/bidirectional/typeparametric.effekt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ extern interface Cap[U, V]
extern pure def cap[U, V](): Cap[U, V] at {} =
js "42"
chez "42"
llvm "ret %Pos undef"

interface Foo[S] {
def op[A]() {f: Cap[S, A]}: Cap[S, A] at {f} / { Exception[S] }
Expand Down
4 changes: 2 additions & 2 deletions examples/pos/capture/selfregion.effekt
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@ def ex5() =


def ex6() = {
var x in global = 42;
println(x + x)
val x = ref(42);
println(x.get + x.get)
}

def main() = {
Expand Down
Loading