Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor/multiprompt llvm #456

Draft
wants to merge 4 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
7 changes: 7 additions & 0 deletions effekt/jvm/src/main/scala/effekt/EffektConfig.scala
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,13 @@ class EffektConfig(args: Seq[String]) extends REPLConfig(args) {
noshort = true
)

val llvmPrompt: ScallopOption[Boolean] = toggle(
"llvm-prompt",
descrYes = "Enable the prompt-based implementation",
default = Some(false),
noshort = true
)

val preludePath: ScallopOption[List[String]] = opt[List[String]](
"prelude",
descr = "Modules to be automatically imported in every file",
Expand Down
2 changes: 1 addition & 1 deletion effekt/jvm/src/main/scala/effekt/Runner.scala
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ object LLVMRunner extends Runner[String] {

val extension = "ll"

def standardLibraryPath(root: File): File = root / "libraries" / "llvm"
def standardLibraryPath(root: File): File = root / "libraries" / "llvm2"

lazy val gccCmd = discoverExecutable(List("cc", "clang", "gcc"), List("--version"))
lazy val llcCmd = discoverExecutable(List("llc", "llc-15", "llc-16"), List("--version"))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -282,8 +282,8 @@ object Transformer {
emit(TailCall(LocalReference(returnAddressType, returnAddress), List(initialEnvironmentPointer, getStackPointer())));
RetVoid()

case machine.NewStack(variable, frame, rest) =>
emit(Call(variable.name, transform(variable.tpe), newStack, List()));
case machine.NewStack(variable, prompt, frame, rest) =>
emit(Call(variable.name, transform(variable.tpe), newStack, List(transform(prompt))));

val frameEnvironment = freeVariables(frame).toList;

Expand Down Expand Up @@ -353,6 +353,22 @@ object Transformer {
eraseValues(List(variable), freeVariables(rest));
transform(rest)

case machine.PopStacksPrompt(variable, prompt, rest) =>
val newStackPointerName = freshName("sp");
val tmpName = freshName("tmp");
val tmpReference = LocalReference(StructureType(List(stkType, spType)), tmpName);
emit(Call(tmpName, StructureType(List(stkType, spType)), popStacksPrompt, List(getStackPointer(), transform(prompt))));
emit(ExtractValue(variable.name, tmpReference, 0));
emit(ExtractValue(newStackPointerName, tmpReference, 1));
setStackPointer(LocalReference(spType, newStackPointerName));

eraseValues(List(variable), freeVariables(rest));
transform(rest)

case machine.FreshPrompt(machine.Variable(name, _), rest) =>
emit(Call(name, IntegerType64(), freshPrompt, Nil));
transform(rest)

case machine.ComposeEvidence(machine.Variable(name, _), ev1, ev2, rest) =>
emit(Add(name, transform(ev1), transform(ev2)))
transform(rest)
Expand Down Expand Up @@ -713,9 +729,12 @@ object Transformer {
def newStack = ConstantGlobal(PointerType(), "newStack");
def pushStack = ConstantGlobal(PointerType(), "pushStack");
def popStacks = ConstantGlobal(PointerType(), "popStacks");
def popStacksPrompt = ConstantGlobal(PointerType(), "popStacksPrompt");
def underflowStack = ConstantGlobal(PointerType(), "underflowStack");
def uniqueStack = ConstantGlobal(PointerType(), "uniqueStack");

def freshPrompt = ConstantGlobal(PointerType(), "freshPrompt");


/**
* Extra info in context
Expand Down
8 changes: 6 additions & 2 deletions effekt/shared/src/main/scala/effekt/machine/Analysis.scala
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,16 @@ def freeVariables(statement: Statement): Set[Variable] =
freeVariables(frame) ++ freeVariables(rest)
case Return(values) =>
Set.from(values)
case NewStack(name, frame, rest) =>
freeVariables(frame) ++ (freeVariables(rest) -- Set(name))
case NewStack(name, prompt, frame, rest) =>
freeVariables(frame) ++ (freeVariables(rest) -- Set(name)) ++ Set(prompt)
case PushStack(value, rest) =>
Set(value) ++ freeVariables(rest)
case PopStacks(name, n, rest) =>
freeVariables(rest) -- Set(name) ++ Set(n)
case PopStacksPrompt(name, prompt, rest) =>
freeVariables(rest) -- Set(name) ++ Set(prompt)
case FreshPrompt(name, rest) =>
freeVariables(rest) -- Set(name)
case ComposeEvidence(name, ev1, ev2, rest) =>
freeVariables(rest) -- Set(name) ++ Set(ev1, ev2)
case LiteralInt(name, value, rest) =>
Expand Down
10 changes: 8 additions & 2 deletions effekt/shared/src/main/scala/effekt/machine/PrettyPrinter.scala
Original file line number Diff line number Diff line change
Expand Up @@ -79,18 +79,24 @@ object PrettyPrinter extends ParenPrettyPrinter {
case Return(arguments) =>
"return" <+> hsep(arguments map toDoc, ",")

case NewStack(name, frame, rest) =>
"let" <+> name <+> "=" <+> "stack" <+> toDoc(frame) <> ";" <> line <> toDoc(rest)
case NewStack(name, prompt, frame, rest) =>
"let" <+> name <+> "=" <+> "stack" <> parens(toDoc(prompt)) <+> toDoc(frame) <> ";" <> line <> toDoc(rest)

case PushStack(stack, rest) =>
"push stack" <+> stack <> ";" <> line <> toDoc(rest)

case PopStacks(name, n, rest) =>
"let" <+> name <+> "=" <+> "shift0" <+> n <> ";" <> line <> toDoc(rest)

case PopStacksPrompt(name, prompt, rest) =>
"let" <+> name <+> "=" <+> "shift0p" <+> prompt <> ";" <> line <> toDoc(rest)

case ComposeEvidence(name, ev1, ev2, rest) =>
"let" <+> name <+> "=" <+> ev1 <+> "+" <+> ev2 <> ";" <> line <> toDoc(rest)

case FreshPrompt(name, rest) =>
"let" <+> name <+> "=" <+> "freshPrompt" <> ";" <> line <> toDoc(rest)

case ForeignCall(name, builtin, arguments, rest) =>
"let" <+> name <+> "=" <+> builtin <> parens(arguments map toDoc) <> ";" <> line <> toDoc(rest)

Expand Down
39 changes: 28 additions & 11 deletions effekt/shared/src/main/scala/effekt/machine/Transformer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -242,14 +242,16 @@ object Transformer {
val variable = Variable(freshName("a"), transform(body.tpe))
val returnClause = Clause(List(variable), Return(List(variable)))
val delimiter = Variable(freshName("returnClause"), Type.Stack())
val prompt = Variable(freshName("p"), builtins.Evidence)

LiteralEvidence(transform(ev), builtins.There,
NewStack(delimiter, returnClause,
PushStack(delimiter,
(ids zip handlers).foldRight(transform(body)){
case ((id, handler), body) =>
New(transform(id), transform(handler), body)
})))
FreshPrompt(prompt,
NewStack(delimiter, prompt, returnClause,
PushStack(delimiter,
(ids zip handlers).foldRight(transform(body)){
case ((id, handler), body) =>
New(transform(id), transform(handler, prompt), body)
}))))

// TODO what about the evidence passed to resume?
case lifted.Shift(ev, lifted.Block.BlockLit(tparams, List(kparam), body)) =>
Expand All @@ -263,10 +265,12 @@ object Transformer {
val variable = Variable(freshName("a"), transform(body.tpe))
val returnClause = Clause(List(variable), Return(List(variable)))
val delimiter = Variable(freshName("returnClause"), Type.Stack())
val prompt = Variable(freshName("p"), builtins.Evidence)

LiteralEvidence(transform(ev), builtins.There,
NewStack(delimiter, returnClause,
PushStack(delimiter, transform(body))))
FreshPrompt(prompt,
NewStack(delimiter, prompt, returnClause,
PushStack(delimiter, transform(body)))))

case lifted.Alloc(id, init, region, ev, body) =>
transform(init).run { value =>
Expand Down Expand Up @@ -471,17 +475,30 @@ object Transformer {
case arg :: args => transform(arg).flatMap { value => transform(args).flatMap { values => pure(value :: values) } }
}

def transform(handler: lifted.Implementation)(using BlocksParamsContext, DeclarationContext, ErrorReporter): List[Clause] =
def transform(handler: lifted.Implementation, prompt: Variable)(using BlocksParamsContext, DeclarationContext, ErrorReporter): List[Clause] =
handler.operations.sortBy {
case lifted.Operation(operationName, _) =>
DeclarationContext.getInterface(handler.interface.name).properties.indexWhere(_.id == operationName)
}.map(transform)
}.map(op => transform(op, prompt))

def transform(op: lifted.Operation)(using BlocksParamsContext, DeclarationContext, ErrorReporter): Clause = op match {
def transform(op: lifted.Operation, prompt: Variable)(using BlocksParamsContext, DeclarationContext, ErrorReporter): Clause = op match {
// Since at the moment shift is evidence and not prompt based, here we inline the implementation of shift
case lifted.Operation(name, lifted.BlockLit(tparams, params, lifted.Shift(ev, lifted.Block.BlockLit(tparams2, List(kparam), body))))
if unsafeContext.config.llvmPrompt() =>
noteResumption(kparam.id)

Clause(params.map(transform),
PopStacksPrompt(Variable(transform(kparam).name, Type.Stack()), prompt,
transform(body)))

// fall back to evidence based solution, this makes it easier to comment out the above line and check whether the evidence
// version still works.
case lifted.Operation(name, lifted.BlockLit(tparams, params, body)) =>
Clause(params.map(transform), transform(body))
}

def unsafeContext(using C: ErrorReporter): Context = C.asInstanceOf[Context]

def transform(param: lifted.Param)(using BlocksParamsContext, ErrorReporter): Variable =
param match {
case lifted.ValueParam(name, tpe) =>
Expand Down
19 changes: 18 additions & 1 deletion effekt/shared/src/main/scala/effekt/machine/Tree.scala
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ enum Statement {
/**
* e.g. let k = stack { (x, ...) => s }; s
*/
case NewStack(name: Variable, frame: Clause, rest: Statement)
case NewStack(name: Variable, prompt: Variable, frame: Clause, rest: Statement)

/**
* e.g. push k; s
Expand All @@ -186,6 +186,11 @@ enum Statement {
*/
case PopStacks(name: Variable, n: Variable, rest: Statement)

/**
* Pops stacks until it finds one labeled with `prompt`
*/
case PopStacksPrompt(name: Variable, prompt: Variable, rest: Statement)

/**
* let x = #infix_add(v1, ...); s
*/
Expand All @@ -197,6 +202,12 @@ enum Statement {
*/
case ComposeEvidence(name: Variable, ev1: Variable, ev2: Variable, rest: Statement)

/**
* Creates a fresh prompt
* let p = freshPrompt; s
*/
case FreshPrompt(name: Variable, rest: Statement)

/**
* let x = 42; s
*/
Expand Down Expand Up @@ -229,9 +240,15 @@ enum Type {
export Type.{ Positive, Negative }

type Evidence = Int
type Prompt = Int

object builtins {

val Evidence = Type.Int()
val Prompt = Type.Int()

val Global: Prompt = 0

val Here: Evidence = 0
val There: Evidence = 1

Expand Down
Loading
Loading