From 986a3cfeb9cba0d5cedb6c297f1f3704de2db111 Mon Sep 17 00:00:00 2001 From: waterlens Date: Fri, 15 Nov 2024 18:41:30 +0800 Subject: [PATCH 01/88] Copy files to new sub project --- .../main/scala/hkmc2/codegen/cpp/Ast.scala | 212 +++++++++++++++ .../scala/hkmc2/codegen/cpp/CodeGen.scala | 238 ++++++++++++++++ .../hkmc2/codegen/cpp/CompilerHost.scala | 44 +++ .../main/scala/hkmc2/codegen/llir/Fresh.scala | 28 ++ .../main/scala/hkmc2/codegen/llir/Llir.scala | 255 ++++++++++++++++++ .../hkmc2/codegen/llir/RefResolver.scala | 55 ++++ .../scala/hkmc2/codegen/llir/Validator.scala | 44 +++ .../hkmc2/utils/document/LegacyDocument.scala | 52 ++++ 8 files changed, 928 insertions(+) create mode 100644 hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/Ast.scala create mode 100644 hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/CodeGen.scala create mode 100644 hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/CompilerHost.scala create mode 100644 hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Fresh.scala create mode 100644 hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Llir.scala create mode 100644 hkmc2/shared/src/main/scala/hkmc2/codegen/llir/RefResolver.scala create mode 100644 hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Validator.scala create mode 100644 hkmc2/shared/src/main/scala/hkmc2/utils/document/LegacyDocument.scala diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/Ast.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/Ast.scala new file mode 100644 index 0000000000..94787c2fa0 --- /dev/null +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/Ast.scala @@ -0,0 +1,212 @@ +package hkmc2.codegen.cpp + +import mlscript._ +import mlscript.utils._ +import mlscript.utils.shorthands._ + +import hkmc2.utils.legacy_document._ + +import scala.language.implicitConversions + +given Conversion[String, Document] = raw + +enum Specifier: + case Extern + case Static + case Inline + + def toDocument = raw( + this match + case Extern => "extern" + case Static => "static" + case Inline => "inline" + ) + + override def toString: Str = toDocument.print + +object Type: + def toDocuments(args: Ls[Type], sep: Document, extraTypename: Bool = false): Document = + args.iterator.zipWithIndex.map { + case (x, 0) => + x.toDocument(extraTypename) + case (x, _) => + sep <#> x.toDocument(extraTypename) + }.fold(raw(""))(_ <#> _) + + def toDocuments(args: Ls[(Str, Type)], sep: Document): Document = + args.iterator.zipWithIndex.map { + case (x, 0) => + x._2.toDocument() <:> raw(x._1) + case (x, _) => + sep <#> x._2.toDocument() <:> raw(x._1) + }.fold(raw(""))(_ <#> _) + +enum Type: + case Prim(name: Str) + case Ptr(inner: Type) + case Ref(inner: Type) + case Array(inner: Type, size: Opt[Int]) + case FuncPtr(ret: Type, args: List[Type]) + case Struct(name: Str) + case Enum(name: Str) + case Template(name: Str, args: List[Type]) + case Var(name: Str) + case Qualifier(inner: Type, qual: Str) + + def toDocument(extraTypename: Bool = false): Document = + def aux(x: Type): Document = x match + case Prim(name) => name + case Ptr(inner) => aux(inner) <#> "*" + case Ref(inner) => aux(inner) <#> "&" + case Array(inner, size) => aux(inner) <#> "[" <#> size.fold(raw(""))(x => x.toString) <#> "]" + case FuncPtr(ret, args) => aux(ret) <#> "(" <#> Type.toDocuments(args, sep = ", ") <#> ")" + case Struct(name) => s"struct $name" + case Enum(name) => s"enum $name" + case Template(name, args) => s"$name" <#> "<" <#> Type.toDocuments(args, sep = ", ") <#> ">" + case Var(name) => name + case Qualifier(inner, qual) => aux(inner) <:> qual + aux(this) + + override def toString: Str = toDocument().print + +object Stmt: + def toDocuments(decl: Ls[Decl], stmts: Ls[Stmt]): Document = + stack_list(decl.map(_.toDocument) ++ stmts.map(_.toDocument)) + +enum Stmt: + case AutoBind(lhs: Ls[Str], rhs: Expr) + case Assign(lhs: Str, rhs: Expr) + case Return(expr: Expr) + case If(cond: Expr, thenStmt: Stmt, elseStmt: Opt[Stmt]) + case While(cond: Expr, body: Stmt) + case For(init: Stmt, cond: Expr, update: Stmt, body: Stmt) + case ExprStmt(expr: Expr) + case Break + case Continue + case Block(decl: Ls[Decl], stmts: Ls[Stmt]) + case Switch(expr: Expr, cases: Ls[(Expr, Stmt)]) + case Raw(stmt: Str) + + def toDocument: Document = + def aux(x: Stmt): Document = x match + case AutoBind(lhs, rhs) => + lhs match + case Nil => rhs.toDocument + case x :: Nil => "auto" <:> x <:> "=" <:> rhs.toDocument <#> ";" + case _ => "auto" <:> lhs.mkString("[", ",", "]") <:> "=" <:> rhs.toDocument <#> ";" + case Assign(lhs, rhs) => lhs <#> " = " <#> rhs.toDocument <#> ";" + case Return(expr) => "return " <#> expr.toDocument <#> ";" + case If(cond, thenStmt, elseStmt) => + "if (" <#> cond.toDocument <#> ")" <#> thenStmt.toDocument <:> elseStmt.fold(raw(""))(x => "else" <:> x.toDocument) + case While(cond, body) => + "while (" <#> cond.toDocument <#> ")" <#> body.toDocument + case For(init, cond, update, body) => + "for (" <#> init.toDocument <#> "; " <#> cond.toDocument <#> "; " <#> update.toDocument <#> ")" <#> body.toDocument + case ExprStmt(expr) => expr.toDocument <#> ";" + case Break => "break;" + case Continue => "continue;" + case Block(decl, stmts) => + stack( + "{", + Stmt.toDocuments(decl, stmts) |> indent, + "}") + case Switch(expr, cases) => + "switch (" <#> expr.toDocument <#> ")" <#> "{" <#> stack_list(cases.map { + case (cond, stmt) => "case " <#> cond.toDocument <#> ":" <#> stmt.toDocument + }) <#> "}" + case Raw(stmt) => stmt + aux(this) + +object Expr: + def toDocuments(args: Ls[Expr], sep: Document): Document = + args.zipWithIndex.map { + case (x, i) => + if i == 0 then x.toDocument + else sep <#> x.toDocument + }.fold(raw(""))(_ <#> _) + +enum Expr: + case Var(name: Str) + case IntLit(value: BigInt) + case DoubleLit(value: Double) + case StrLit(value: Str) + case CharLit(value: Char) + case Call(func: Expr, args: Ls[Expr]) + case Member(expr: Expr, member: Str) + case Index(expr: Expr, index: Expr) + case Unary(op: Str, expr: Expr) + case Binary(op: Str, lhs: Expr, rhs: Expr) + case Initializer(exprs: Ls[Expr]) + case Constructor(name: Str, init: Expr) + + def toDocument: Document = + def aux(x: Expr): Document = x match + case Var(name) => name + case IntLit(value) => value.toString + case DoubleLit(value) => value.toString + case StrLit(value) => s"\"$value\"" // need more reliable escape utils + case CharLit(value) => value.toInt.toString + case Call(func, args) => aux(func) <#> "(" <#> Expr.toDocuments(args, sep = ", ") <#> ")" + case Member(expr, member) => aux(expr) <#> "->" <#> member + case Index(expr, index) => aux(expr) <#> "[" <#> aux(index) <#> "]" + case Unary(op, expr) => "(" <#> op <#> aux(expr) <#> ")" + case Binary(op, lhs, rhs) => "(" <#> aux(lhs) <#> op <#> aux(rhs) <#> ")" + case Initializer(exprs) => "{" <#> Expr.toDocuments(exprs, sep = ", ") <#> "}" + case Constructor(name, init) => name <#> init.toDocument + aux(this) + +case class CompilationUnit(includes: Ls[Str], decls: Ls[Decl], defs: Ls[Def]): + def toDocument: Document = + stack_list(includes.map(x => raw(x)) ++ decls.map(_.toDocument) ++ defs.map(_.toDocument)) + def toDocumentWithoutHidden: Document = + val hiddenNames = Set( + "HiddenTheseEntities", "True", "False", "Callable", "List", "Cons", "Nil", "Option", "Some", "None", "Pair", "Tuple2", "Tuple3", "Nat", "S", "O" + ) + stack_list(defs.filterNot { + case Def.StructDef(name, _, _, _) => hiddenNames.contains(name.stripPrefix("_mls_")) + case _ => false + }.map(_.toDocument)) + +enum Decl: + case StructDecl(name: Str) + case EnumDecl(name: Str) + case FuncDecl(ret: Type, name: Str, args: Ls[Type]) + case VarDecl(name: Str, typ: Type) + + def toDocument: Document = + def aux(x: Decl): Document = x match + case StructDecl(name) => s"struct $name;" + case EnumDecl(name) => s"enum $name;" + case FuncDecl(ret, name, args) => ret.toDocument() <#> s" $name(" <#> Type.toDocuments(args, sep = ", ") <#> ");" + case VarDecl(name, typ) => typ.toDocument() <#> s" $name;" + aux(this) + +enum Def: + case StructDef(name: Str, fields: Ls[(Str, Type)], inherit: Opt[Ls[Str]], methods: Ls[Def] = Ls.empty) + case EnumDef(name: Str, fields: Ls[(Str, Opt[Int])]) + case FuncDef(specret: Type, name: Str, args: Ls[(Str, Type)], body: Stmt.Block, or: Bool = false, virt: Bool = false) + case VarDef(typ: Type, name: Str, init: Opt[Expr]) + case RawDef(raw: Str) + + def toDocument: Document = + def aux(x: Def): Document = x match + case StructDef(name, fields, inherit, defs) => + stack( + s"struct $name" <#> (if inherit.nonEmpty then ": public" <:> inherit.get.mkString(", ") else "" ) <:> "{", + stack_list(fields.map { + case (name, typ) => typ.toDocument() <#> " " <#> name <#> ";" + }) |> indent, + stack_list(defs.map(_.toDocument)) |> indent, + "};" + ) + case EnumDef(name, fields) => + s"enum $name" <:> "{" <#> stack_list(fields.map { + case (name, value) => value.fold(s"$name")(x => s"$name = $x") + }) <#> "};" + case FuncDef(specret, name, args, body, or, virt) => + (if virt then "virtual " else "") + <#> specret.toDocument() <#> s" $name(" <#> Type.toDocuments(args, sep = ", ") <#> ")" <#> (if or then " override" else "") <#> body.toDocument + case VarDef(typ, name, init) => + typ.toDocument() <#> s" $name" <#> init.fold(raw(""))(x => " = " <#> x.toDocument) <#> raw(";") + case RawDef(x) => x + aux(this) \ No newline at end of file diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/CodeGen.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/CodeGen.scala new file mode 100644 index 0000000000..2ed12302e9 --- /dev/null +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/CodeGen.scala @@ -0,0 +1,238 @@ +package hkmc2.codegen.cpp + +import mlscript.utils._ +import mlscript.utils.shorthands._ +import scala.collection.mutable.ListBuffer + +import hkmc2.codegen.llir.{Expr => IExpr, _} +import hkmc2.codegen.cpp._ + +def codegen(prog: Program): CompilationUnit = + val codegen = CppCodeGen() + codegen.codegen(prog) + +private class CppCodeGen: + def mapName(name: Name): Str = "_mls_" + name.str.replace('$', '_').replace('\'', '_') + def mapName(name: Str): Str = "_mls_" + name.replace('$', '_').replace('\'', '_') + val freshName = Fresh(div = '_'); + val mlsValType = Type.Prim("_mlsValue") + val mlsUnitValue = Expr.Call(Expr.Var("_mlsValue::create<_mls_Unit>"), Ls()); + val mlsRetValue = "_mls_retval" + val mlsRetValueDecl = Decl.VarDecl(mlsRetValue, mlsValType) + val mlsMainName = "_mlsMain" + val mlsPrelude = "#include \"mlsprelude.h\"" + val mlsPreludeImpl = "#include \"mlsprelude.cpp\"" + val mlsInternalClass = Set("True", "False", "Boolean", "Callable") + val mlsObject = "_mlsObject" + val mlsBuiltin = "builtin" + val mlsEntryPoint = s"int main() { return _mlsLargeStack(_mlsMainWrapper); }"; + def mlsIntLit(x: BigInt) = Expr.Call(Expr.Var("_mlsValue::fromIntLit"), Ls(Expr.IntLit(x))) + def mlsStrLit(x: Str) = Expr.Call(Expr.Var("_mlsValue::fromStrLit"), Ls(Expr.StrLit(x))) + def mlsCharLit(x: Char) = Expr.Call(Expr.Var("_mlsValue::fromIntLit"), Ls(Expr.CharLit(x))) + def mlsNewValue(cls: Str, args: Ls[Expr]) = Expr.Call(Expr.Var(s"_mlsValue::create<$cls>"), args) + def mlsIsValueOf(cls: Str, scrut: Expr) = Expr.Call(Expr.Var(s"_mlsValue::isValueOf<$cls>"), Ls(scrut)) + def mlsIsIntLit(scrut: Expr, lit: hkmc2.syntax.Tree.IntLit) = Expr.Call(Expr.Var("_mlsValue::isIntLit"), Ls(scrut, Expr.IntLit(lit.value))) + def mlsDebugPrint(x: Expr) = Expr.Call(Expr.Var("_mlsValue::print"), Ls(x)) + def mlsTupleValue(init: Expr) = Expr.Constructor("_mlsValue::tuple", init) + def mlsAs(name: Str, cls: Str) = Expr.Var(s"_mlsValue::as<$cls>($name)") + def mlsAsUnchecked(name: Str, cls: Str) = Expr.Var(s"_mlsValue::cast<$cls>($name)") + def mlsObjectNameMethod(name: Str) = s"constexpr static inline const char *typeName = \"${name}\";" + def mlsTypeTag() = s"constexpr static inline uint32_t typeTag = nextTypeTag();" + def mlsTypeTag(n: Int) = s"constexpr static inline uint32_t typeTag = $n;" + def mlsCommonCreateMethod(cls: Str, fields: Ls[Str], id: Int) = + val parameters = fields.map{x => s"_mlsValue $x"}.mkString(", ") + val fieldsAssignment = fields.map{x => s"_mlsVal->$x = $x; "}.mkString + s"static _mlsValue create($parameters) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) $cls; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; $fieldsAssignment return _mlsValue(_mlsVal); }" + def mlsCommonPrintMethod(fields: Ls[Str]) = + if fields.isEmpty then s"virtual void print() const override { std::printf(\"%s\", typeName); }" + else + val fieldsPrint = fields.map{x => s"this->$x.print(); "}.mkString("std::printf(\", \"); ") + s"virtual void print() const override { std::printf(\"%s\", typeName); std::printf(\"(\"); $fieldsPrint std::printf(\")\"); }" + def mlsCommonDestructorMethod(cls: Str, fields: Ls[Str]) = + val fieldsDeletion = fields.map{x => s"_mlsValue::destroy(this->$x); "}.mkString + s"virtual void destroy() override { $fieldsDeletion operator delete (this, std::align_val_t(_mlsAlignment)); }" + def mlsThrowNonExhaustiveMatch = Stmt.Raw("_mlsNonExhaustiveMatch();"); + def mlsCall(fn: Str, args: Ls[Expr]) = Expr.Call(Expr.Var("_mlsCall"), Expr.Var(fn) :: args) + def mlsMethodCall(cls: ClassRef, method: Str, args: Ls[Expr]) = + Expr.Call(Expr.Member(Expr.Call(Expr.Var(s"_mlsMethodCall<${cls.name |> mapName}>"), Ls(args.head)), method), args.tail) + def mlsFnWrapperName(fn: Str) = s"_mlsFn_$fn" + def mlsFnCreateMethod(fn: Str) = s"static _mlsValue create() { static _mlsFn_$fn mlsFn alignas(_mlsAlignment); mlsFn.refCount = stickyRefCount; mlsFn.tag = typeTag; return _mlsValue(&mlsFn); }" + def mlsNeverValue(n: Int) = if (n <= 1) then Expr.Call(Expr.Var(s"_mlsValue::never"), Ls()) else Expr.Call(Expr.Var(s"_mlsValue::never<$n>"), Ls()) + + case class Ctx( + defnCtx: Set[Str], + ) + + def codegenClassInfo(using ctx: Ctx)(cls: ClassInfo): (Opt[Def], Decl) = + val fields = cls.fields.map{x => (x |> mapName, mlsValType)} + val parents = if cls.parents.nonEmpty then cls.parents.toList.map(mapName) else mlsObject :: Nil + val decl = Decl.StructDecl(cls.name |> mapName) + if mlsInternalClass.contains(cls.name) then return (None, decl) + val theDef = Def.StructDef( + cls.name |> mapName, fields, + if parents.nonEmpty then Some(parents) else None, + Ls(Def.RawDef(mlsObjectNameMethod(cls.name)), + Def.RawDef(mlsTypeTag()), + Def.RawDef(mlsCommonPrintMethod(cls.fields.map(mapName))), + Def.RawDef(mlsCommonDestructorMethod(cls.name |> mapName, cls.fields.map(mapName))), + Def.RawDef(mlsCommonCreateMethod(cls.name |> mapName, cls.fields.map(mapName), cls.id))) + ++ cls.methods.map{case (name, defn) => { + val (theDef, decl) = codegenDefn(using Ctx(ctx.defnCtx + cls.name))(defn) + theDef match + case x @ Def.FuncDef(_, name, _, _, _, _) => x.copy(virt = true) + case _ => theDef + }} + ) + (S(theDef), decl) + + def toExpr(texpr: TrivialExpr, reifyUnit: Bool = false)(using ctx: Ctx): Opt[Expr] = texpr match + case IExpr.Ref(name) => S(Expr.Var(name |> mapName)) + case IExpr.Literal(hkmc2.syntax.Tree.BoolLit(x)) => S(mlsIntLit(if x then 1 else 0)) + case IExpr.Literal(hkmc2.syntax.Tree.IntLit(x)) => S(mlsIntLit(x)) + case IExpr.Literal(hkmc2.syntax.Tree.DecLit(x)) => S(mlsIntLit(x.toBigInt)) + case IExpr.Literal(hkmc2.syntax.Tree.StrLit(x)) => S(mlsStrLit(x)) + case IExpr.Literal(hkmc2.syntax.Tree.UnitLit(_)) => if reifyUnit then S(mlsUnitValue) else None + + def toExpr(texpr: TrivialExpr)(using ctx: Ctx): Expr = texpr match + case IExpr.Ref(name) => Expr.Var(name |> mapName) + case IExpr.Literal(hkmc2.syntax.Tree.BoolLit(x)) => mlsIntLit(if x then 1 else 0) + case IExpr.Literal(hkmc2.syntax.Tree.IntLit(x)) => mlsIntLit(x) + case IExpr.Literal(hkmc2.syntax.Tree.DecLit(x)) => mlsIntLit(x.toBigInt) + case IExpr.Literal(hkmc2.syntax.Tree.StrLit(x)) => mlsStrLit(x) + case IExpr.Literal(hkmc2.syntax.Tree.UnitLit(_)) => mlsUnitValue + + + def wrapMultiValues(exprs: Ls[TrivialExpr])(using ctx: Ctx): Expr = exprs match + case x :: Nil => toExpr(x, reifyUnit = true).get + case _ => + val init = Expr.Initializer(exprs.map{x => toExpr(x)}) + mlsTupleValue(init) + + def codegenCaseWithIfs(scrut: Name, cases: Ls[(Pat, Node)], default: Opt[Node], storeInto: Str)(using decls: Ls[Decl], stmts: Ls[Stmt])(using ctx: Ctx): (Ls[Decl], Ls[Stmt]) = + val scrutName = mapName(scrut) + val init: Stmt = + default.fold(mlsThrowNonExhaustiveMatch)(x => { + val (decls2, stmts2) = codegen(x, storeInto)(using Ls.empty, Ls.empty[Stmt]) + Stmt.Block(decls2, stmts2) + }) + val stmt = cases.foldRight(S(init)) { + case ((Pat.Class(cls), arm), nextarm) => + val (decls2, stmts2) = codegen(arm, storeInto)(using Ls.empty, Ls.empty[Stmt]) + val stmt = Stmt.If(mlsIsValueOf(cls.name |> mapName, Expr.Var(scrutName)), Stmt.Block(decls2, stmts2), nextarm) + S(stmt) + case ((Pat.Lit(i @ hkmc2.syntax.Tree.IntLit(_)), arm), nextarm) => + val (decls2, stmts2) = codegen(arm, storeInto)(using Ls.empty, Ls.empty[Stmt]) + val stmt = Stmt.If(mlsIsIntLit(Expr.Var(scrutName), i), Stmt.Block(decls2, stmts2), nextarm) + S(stmt) + case _ => ??? + } + (decls, stmt.fold(stmts)(x => stmts :+ x)) + + def codegenJumpWithCall(func: FuncRef, args: Ls[TrivialExpr], storeInto: Opt[Str])(using decls: Ls[Decl], stmts: Ls[Stmt])(using ctx: Ctx): (Ls[Decl], Ls[Stmt]) = + val call = Expr.Call(Expr.Var(func.name |> mapName), args.map(toExpr)) + val stmts2 = stmts ++ Ls(storeInto.fold(Stmt.Return(call))(x => Stmt.Assign(x, call))) + (decls, stmts2) + + def codegenOps(op: Str, args: Ls[TrivialExpr])(using ctx: Ctx) = op match + case "+" => Expr.Binary("+", toExpr(args(0)), toExpr(args(1))) + case "-" => Expr.Binary("-", toExpr(args(0)), toExpr(args(1))) + case "*" => Expr.Binary("*", toExpr(args(0)), toExpr(args(1))) + case "/" => Expr.Binary("/", toExpr(args(0)), toExpr(args(1))) + case "%" => Expr.Binary("%", toExpr(args(0)), toExpr(args(1))) + case "==" => Expr.Binary("==", toExpr(args(0)), toExpr(args(1))) + case "!=" => Expr.Binary("!=", toExpr(args(0)), toExpr(args(1))) + case "<" => Expr.Binary("<", toExpr(args(0)), toExpr(args(1))) + case "<=" => Expr.Binary("<=", toExpr(args(0)), toExpr(args(1))) + case ">" => Expr.Binary(">", toExpr(args(0)), toExpr(args(1))) + case ">=" => Expr.Binary(">=", toExpr(args(0)), toExpr(args(1))) + case "&&" => Expr.Binary("&&", toExpr(args(0)), toExpr(args(1))) + case "||" => Expr.Binary("||", toExpr(args(0)), toExpr(args(1))) + case "!" => Expr.Unary("!", toExpr(args(0))) + case _ => TODO("codegenOps") + + + def codegen(expr: IExpr)(using ctx: Ctx): Expr = expr match + case x @ (IExpr.Ref(_) | IExpr.Literal(_)) => toExpr(x, reifyUnit = true).get + case IExpr.CtorApp(cls, args) => mlsNewValue(cls.name |> mapName, args.map(toExpr)) + case IExpr.Select(name, cls, field) => Expr.Member(mlsAsUnchecked(name |> mapName, cls.name |> mapName), field |> mapName) + case IExpr.BasicOp(name, args) => codegenOps(name, args) + case IExpr.AssignField(assignee, cls, field, value) => TODO("codegen assign field") + + def codegenBuiltin(names: Ls[Name], builtin: Str, args: Ls[TrivialExpr])(using ctx: Ctx): Ls[Stmt] = builtin match + case "error" => Ls(Stmt.Raw("throw std::runtime_error(\"Error\");"), Stmt.AutoBind(names.map(mapName), mlsNeverValue(names.size))) + case _ => Ls(Stmt.AutoBind(names.map(mapName), Expr.Call(Expr.Var("_mls_builtin_" + builtin), args.map(toExpr)))) + + def codegen(body: Node, storeInto: Str)(using decls: Ls[Decl], stmts: Ls[Stmt])(using ctx: Ctx): (Ls[Decl], Ls[Stmt]) = body match + case Node.Result(res) => + val expr = wrapMultiValues(res) + val stmts2 = stmts ++ Ls(Stmt.Assign(storeInto, expr)) + (decls, stmts2) + case Node.Jump(defn, args) => + codegenJumpWithCall(defn, args, S(storeInto)) + case Node.LetExpr(name, expr, body) => + val stmts2 = stmts ++ Ls(Stmt.AutoBind(Ls(name |> mapName), codegen(expr))) + codegen(body, storeInto)(using decls, stmts2) + case Node.LetMethodCall(names, cls, method, IExpr.Ref(Name("builtin")) :: args, body) => + val stmts2 = stmts ++ codegenBuiltin(names, args.head.toString.replace("\"", ""), args.tail) + codegen(body, storeInto)(using decls, stmts2) + case Node.LetMethodCall(names, cls, method, args, body) => + val call = mlsMethodCall(cls, method.str |> mapName, args.map(toExpr)) + val stmts2 = stmts ++ Ls(Stmt.AutoBind(names.map(mapName), call)) + codegen(body, storeInto)(using decls, stmts2) + case Node.LetCall(names, defn, args, body) => + val call = Expr.Call(Expr.Var(defn.name |> mapName), args.map(toExpr)) + val stmts2 = stmts ++ Ls(Stmt.AutoBind(names.map(mapName), call)) + codegen(body, storeInto)(using decls, stmts2) + case Node.Case(scrut, cases, default) => + codegenCaseWithIfs(scrut, cases, default, storeInto) + + def codegenDefn(using ctx: Ctx)(defn: Func): (Def, Decl) = defn match + case Func(id, name, params, resultNum, body) => + val decls = Ls(mlsRetValueDecl) + val stmts = Ls.empty[Stmt] + val (decls2, stmts2) = codegen(body, mlsRetValue)(using decls, stmts) + val stmtsWithReturn = stmts2 :+ Stmt.Return(Expr.Var(mlsRetValue)) + val theDef = Def.FuncDef(mlsValType, name |> mapName, params.map(x => (x |> mapName, mlsValType)), Stmt.Block(decls2, stmtsWithReturn)) + val decl = Decl.FuncDecl(mlsValType, name |> mapName, params.map(x => mlsValType)) + (theDef, decl) + + def codegenTopNode(node: Node)(using ctx: Ctx): (Def, Decl) = + val decls = Ls(mlsRetValueDecl) + val stmts = Ls.empty[Stmt] + val (decls2, stmts2) = codegen(node, mlsRetValue)(using decls, stmts) + val stmtsWithReturn = stmts2 :+ Stmt.Return(Expr.Var(mlsRetValue)) + val theDef = Def.FuncDef(mlsValType, mlsMainName, Ls(), Stmt.Block(decls2, stmtsWithReturn)) + val decl = Decl.FuncDecl(mlsValType, mlsMainName, Ls()) + (theDef, decl) + + // Topological sort of classes based on inheritance relationships + def sortClasses(prog: Program): Ls[ClassInfo] = + var depgraph = prog.classes.map(x => (x.name, x.parents)).toMap + var degree = depgraph.view.mapValues(_.size).toMap + def removeNode(node: Str) = + degree -= node + depgraph -= node + depgraph = depgraph.view.mapValues(_.filter(_ != node)).toMap + degree = depgraph.view.mapValues(_.size).toMap + val sorted = ListBuffer.empty[ClassInfo] + var work = degree.filter(_._2 == 0).keys.toSet + while work.nonEmpty do + val node = work.head + work -= node + sorted.addOne(prog.classes.find(_.name == node).get) + removeNode(node) + val next = degree.filter(_._2 == 0).keys + work ++= next + if depgraph.nonEmpty then + val cycle = depgraph.keys.mkString(", ") + throw new Exception(s"Cycle detected in class hierarchy: $cycle") + sorted.toList + + def codegen(prog: Program): CompilationUnit = + val sortedClasses = sortClasses(prog) + val defnCtx = prog.defs.map(_.name) + val (defs, decls) = sortedClasses.map(codegenClassInfo(using Ctx(defnCtx))).unzip + val (defs2, decls2) = prog.defs.map(codegenDefn(using Ctx(defnCtx))).unzip + val (defMain, declMain) = codegenTopNode(prog.main)(using Ctx(defnCtx)) + CompilationUnit(Ls(mlsPrelude), decls ++ decls2 :+ declMain, defs.flatten ++ defs2 :+ defMain :+ Def.RawDef(mlsEntryPoint)) + diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/CompilerHost.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/CompilerHost.scala new file mode 100644 index 0000000000..291f5a0c4a --- /dev/null +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/CompilerHost.scala @@ -0,0 +1,44 @@ +package hkmc2.codegen.cpp + +import mlscript._ +import mlscript.utils.shorthands._ +import scala.collection.mutable.ListBuffer + +final class CppCompilerHost(val auxPath: Str): + import scala.sys.process._ + private def ifAnyCppCompilerExists(): Boolean = + Seq("g++", "--version").! == 0 || Seq("clang++", "--version").! == 0 + + private def isMakeExists(): Boolean = + import scala.sys.process._ + Seq("make", "--version").! == 0 + + val ready = ifAnyCppCompilerExists() && isMakeExists() + + def compileAndRun(src: Str, output: Str => Unit): Unit = + if !ready then + return + val srcPath = os.temp(contents = src, suffix = ".cpp") + val binPath = os.temp(suffix = ".mls.out") + var stdout = ListBuffer[Str]() + var stderr = ListBuffer[Str]() + val buildLogger = ProcessLogger(stdout :+= _, stderr :+= _) + val buildResult = Seq("make", "-B", "-C", auxPath, "auto", s"SRC=$srcPath", s"DST=$binPath") ! buildLogger + if buildResult != 0 then + output("Compilation failed: ") + for line <- stdout do output(line) + for line <- stderr do output(line) + return + + stdout.clear() + stderr.clear() + val runCmd = Seq(binPath.toString) + val runResult = runCmd ! buildLogger + if runResult != 0 then + output("Execution failed: ") + for line <- stdout do output(line) + for line <- stderr do output(line) + return + + output("Execution succeeded: ") + for line <- stdout do output(line) \ No newline at end of file diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Fresh.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Fresh.scala new file mode 100644 index 0000000000..0c5688eab6 --- /dev/null +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Fresh.scala @@ -0,0 +1,28 @@ +package hkmc2.codegen.llir + +import collection.mutable.{HashMap => MutHMap} +import mlscript.utils.shorthands._ + +final class Fresh(div : Char = '$'): + private val counter = MutHMap[Str, Int]() + private def gensym(s: Str) = { + val n = s.lastIndexOf(div) + val (ts, suffix) = s.splitAt(if n == -1 then s.length() else n) + var x = if suffix.stripPrefix(div.toString).forall(_.isDigit) then ts else s + val count = counter.getOrElse(x, 0) + val tmp = s"$x$div$count" + counter.update(x, count + 1) + Name(tmp) + } + + def make(s: Str) = gensym(s) + def make = gensym("x") + +final class FreshInt: + private var counter = 0 + def make: Int = { + val tmp = counter + counter += 1 + tmp + } + diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Llir.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Llir.scala new file mode 100644 index 0000000000..bfa2fbe713 --- /dev/null +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Llir.scala @@ -0,0 +1,255 @@ +package hkmc2.codegen.llir + +import mlscript._ +import mlscript.utils._ +import mlscript.utils.shorthands._ + +import hkmc2.utils.legacy_document._ +import hkmc2.syntax._ + +import util.Sorting +import collection.immutable.SortedSet +import language.implicitConversions +import collection.mutable.{Map as MutMap, Set as MutSet, HashMap, ListBuffer} + +final case class LowLevelIRError(message: String) extends Exception(message) + +case class Program( + classes: Set[ClassInfo], + defs: Set[Func], + main: Node, +): + override def toString: String = + val t1 = classes.toArray + val t2 = defs.toArray + Sorting.quickSort(t1) + Sorting.quickSort(t2) + s"Program({${t1.mkString(",\n")}}, {\n${t2.mkString("\n")}\n},\n$main)" + + def show(hiddenNames: Set[Str] = Set.empty) = toDocument(hiddenNames).print + def toDocument(hiddenNames: Set[Str] = Set.empty) : Document = + val t1 = classes.toArray + val t2 = defs.toArray + Sorting.quickSort(t1) + Sorting.quickSort(t2) + given Conversion[String, Document] = raw + stack( + "Program:", + stack_list(t1.filter(x => !hiddenNames.contains(x.name)).map(_.toDocument).toList) |> indent, + stack_list(t2.map(_.toDocument).toList) |> indent, + main.toDocument |> indent + ) + +implicit object ClassInfoOrdering extends Ordering[ClassInfo] { + def compare(a: ClassInfo, b: ClassInfo) = a.id.compare(b.id) +} + +case class ClassInfo( + id: Int, + name: Str, + fields: Ls[Str], +): + var parents: Set[Str] = Set.empty + var methods: Map[Str, Func] = Map.empty + override def hashCode: Int = id + override def toString: String = + s"ClassInfo($id, $name, [${fields mkString ","}], parents: ${parents mkString ","}, methods:\n${methods mkString ",\n"})" + + def show = toDocument.print + def toDocument: Document = + given Conversion[String, Document] = raw + val extension = if parents.isEmpty then "" else " extends " + parents.mkString(", ") + if methods.isEmpty then + "class" <:> name <#> "(" <#> fields.mkString(",") <#> ")" <#> extension + else + stack( + "class" <:> name <#> "(" <#> fields.mkString(",") <#> ")" <#> extension <:> "{", + stack_list( methods.map { (_, func) => func.toDocument |> indent }.toList), + "}" + ) + +case class Name(str: Str): + def trySubst(map: Map[Str, Name]) = map.getOrElse(str, this) + override def toString: String = str + +class FuncRef(var func: Either[Func, Str]): + def name: String = func.fold(_.name, x => x) + def expectFn: Func = func.fold(identity, x => throw Exception(s"Expected a def, but got $x")) + def getFunc: Opt[Func] = func.left.toOption + override def equals(o: Any): Bool = o match { + case o: FuncRef => o.name == this.name + case _ => false + } + +class ClassRef(var cls: Either[ClassInfo, Str]): + def name: String = cls.fold(_.name, x => x) + def expectCls: ClassInfo = cls.fold(identity, x => throw Exception(s"Expected a class, but got $x")) + def getClass: Opt[ClassInfo] = cls.left.toOption + override def equals(o: Any): Bool = o match { + case o: ClassRef => o.name == this.name + case _ => false + } + +implicit object FuncOrdering extends Ordering[Func] { + def compare(a: Func, b: Func) = a.id.compare(b.id) +} + +case class Func( + id: Int, + name: Str, + params: Ls[Name], + resultNum: Int, + body: Node +): + var recBoundary: Opt[Int] = None + override def hashCode: Int = id + + override def toString: String = + val ps = params.map(_.toString).mkString("[", ",", "]") + s"Def($id, $name, $ps, \n$resultNum, \n$body\n)" + + def show = toDocument.print + def toDocument: Document = + given Conversion[String, Document] = raw + stack( + "def" <:> name <#> "(" <#> params.map(_.toString).mkString(",") <#> ")" <:> "=", + body.toDocument |> indent + ) + +sealed trait TrivialExpr: + import Expr._ + override def toString: String + def show: String + def toDocument: Document + def toExpr: Expr = this match { case x: Expr => x } + +private def showArguments(args: Ls[TrivialExpr]) = args map (_.show) mkString "," + +enum Expr: + case Ref(name: Name) extends Expr, TrivialExpr + case Literal(lit: hkmc2.syntax.Literal) extends Expr, TrivialExpr + case CtorApp(cls: ClassRef, args: Ls[TrivialExpr]) + case Select(name: Name, cls: ClassRef, field: Str) + case BasicOp(name: Str, args: Ls[TrivialExpr]) + case AssignField(assignee: Name, cls: ClassRef, field: Str, value: TrivialExpr) + + override def toString: String = show + + def show: String = + toDocument.print + + def toDocument: Document = + given Conversion[String, Document] = raw + this match + case Ref(s) => s.toString + case Literal(Tree.BoolLit(lit)) => s"$lit" + case Literal(Tree.IntLit(lit)) => s"$lit" + case Literal(Tree.DecLit(lit)) => s"$lit" + case Literal(Tree.StrLit(lit)) => s"$lit" + case Literal(Tree.UnitLit(undefinedOrNull)) => if undefinedOrNull then "undefined" else "null" + case CtorApp(cls, args) => + cls.name <#> "(" <#> (args |> showArguments) <#> ")" + case Select(s, cls, fld) => + cls.name <#> "." <#> fld <#> "(" <#> s.toString <#> ")" + case BasicOp(name: Str, args) => + name <#> "(" <#> (args |> showArguments) <#> ")" + case AssignField(assignee, clsInfo, fieldName, value) => + stack( + "assign" + <:> (assignee.toString + "." + fieldName) + <:> ":=" + <:> value.toDocument + ) + +enum Pat: + case Lit(lit: hkmc2.syntax.Literal) + case Class(cls: ClassRef) + + def isTrue = this match + case Class(cls) => cls.name == "True" + case _ => false + + def isFalse = this match + case Class(cls) => cls.name == "False" + case _ => false + + override def toString: String = this match + case Lit(lit) => s"$lit" + case Class(cls) => s"${cls.name}" + +enum Node: + // Terminal forms: + case Result(res: Ls[TrivialExpr]) + case Jump(func: FuncRef, args: Ls[TrivialExpr]) + case Case(scrutinee: Name, cases: Ls[(Pat, Node)], default: Opt[Node]) + // Intermediate forms: + case LetExpr(name: Name, expr: Expr, body: Node) + case LetMethodCall(names: Ls[Name], cls: ClassRef, method: Name, args: Ls[TrivialExpr], body: Node) + case LetCall(names: Ls[Name], func: FuncRef, args: Ls[TrivialExpr], body: Node) + + override def toString: String = show + + def show: String = + toDocument.print + + def toDocument: Document = + given Conversion[String, Document] = raw + this match + case Result(res) => (res |> showArguments) + case Jump(jp, args) => + "jump" + <:> jp.name + <#> "(" + <#> (args |> showArguments) + <#> ")" + case Case(x, Ls((true_pat, tru), (false_pat, fls)), N) if true_pat.isTrue && false_pat.isFalse => + val first = "if" <:> x.toString + val tru2 = indent(stack("true" <:> "=>", tru.toDocument |> indent)) + val fls2 = indent(stack("false" <:> "=>", fls.toDocument |> indent)) + Document.Stacked(Ls(first, tru2, fls2)) + case Case(x, cases, default) => + val first = "case" <:> x.toString <:> "of" + val other = cases flatMap { + case (pat, node) => + Ls(pat.toString <:> "=>", node.toDocument |> indent) + } + default match + case N => stack(first, (Document.Stacked(other) |> indent)) + case S(dc) => + val default = Ls("_" <:> "=>", dc.toDocument |> indent) + stack(first, (Document.Stacked(other ++ default) |> indent)) + case LetExpr(x, expr, body) => + stack( + "let" + <:> x.toString + <:> "=" + <:> expr.toDocument + <:> "in", + body.toDocument) + case LetMethodCall(xs, cls, method, args, body) => + stack( + "let" + <:> xs.map(_.toString).mkString(",") + <:> "=" + <:> cls.name + <#> "." + <#> method.toString + <#> "(" + <#> args.map{ x => x.toString }.mkString(",") + <#> ")" + <:> "in", + body.toDocument) + case LetCall(xs, func, args, body) => + stack( + "let*" + <:> "(" + <#> xs.map(_.toString).mkString(",") + <#> ")" + <:> "=" + <:> func.name + <#> "(" + <#> args.map{ x => x.toString }.mkString(",") + <#> ")" + <:> "in", + body.toDocument) + diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/RefResolver.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/RefResolver.scala new file mode 100644 index 0000000000..54f0df95b2 --- /dev/null +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/RefResolver.scala @@ -0,0 +1,55 @@ +package hkmc2.codegen.llir + +import mlscript.utils.shorthands._ + +import Node._ + +// Resolves the definition references by turning them from Right(name) to Left(Func). +private final class RefResolver(defs: Map[Str, Func], classes: Map[Str, ClassInfo], allowInlineJp: Bool): + private def f(x: Expr): Unit = x match + case Expr.Ref(name) => + case Expr.Literal(lit) => + case Expr.CtorApp(cls, args) => classes.get(cls.name) match + case None => throw LowLevelIRError(f"unknown class ${cls.name} in ${classes.keySet.mkString(",")}") + case Some(value) => cls.cls = Left(value) + case Expr.Select(name, cls, field) => classes.get(cls.name) match + case None => throw LowLevelIRError(f"unknown class ${cls.name} in ${classes.keySet.mkString(",")}") + case Some(value) => cls.cls = Left(value) + case Expr.BasicOp(name, args) => + case Expr.AssignField(name, cls, field, value) => classes.get(cls.name) match + case None => throw LowLevelIRError(f"unknown class ${cls.name} in ${classes.keySet.mkString(",")}") + case Some(value) => cls.cls = Left(value) + + private def f(x: Pat): Unit = x match + case Pat.Lit(lit) => + case Pat.Class(cls) => classes.get(cls.name) match + case None => throw LowLevelIRError(f"unknown class ${cls.name} in ${classes.keySet.mkString(",")}") + case Some(value) => cls.cls = Left(value) + + private def f(x: Node): Unit = x match + case Result(res) => + case Case(scrut, cases, default) => cases foreach { (_, body) => f(body) }; default foreach f + case LetExpr(name, expr, body) => f(expr); f(body) + case LetMethodCall(names, cls, method, args, body) => f(body) + case LetCall(resultNames, defnref, args, body) => + defs.get(defnref.name) match + case Some(defn) => defnref.func = Left(defn) + case None => throw LowLevelIRError(f"unknown function ${defnref.name} in ${defs.keySet.mkString(",")}") + f(body) + case Jump(defnref, _) => + // maybe not promoted yet + defs.get(defnref.name) match + case Some(defn) => defnref.func = Left(defn) + case None => + if !allowInlineJp then + throw LowLevelIRError(f"unknown function ${defnref.name} in ${defs.keySet.mkString(",")}") + def run(node: Node) = f(node) + def run(node: Func) = f(node.body) + +def resolveRef(entry: Node, defs: Set[Func], classes: Set[ClassInfo], allowInlineJp: Bool = false): Unit = + val defsMap = defs.map(x => x.name -> x).toMap + val classesMap = classes.map(x => x.name -> x).toMap + val rl = RefResolver(defsMap, classesMap, allowInlineJp) + rl.run(entry) + defs.foreach(rl.run(_)) + diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Validator.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Validator.scala new file mode 100644 index 0000000000..ee1459344e --- /dev/null +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Validator.scala @@ -0,0 +1,44 @@ +package hkmc2.codegen.llir + +import hkmc2.utils._ + +private final class FuncRefInSet(defs: Set[Func], classes: Set[ClassInfo]): + import Node._ + import Expr._ + + private def f(x: Expr): Unit = x match + case Ref(name) => + case Literal(lit) => + case CtorApp(name, args) => + case Select(name, ref, field) => ref.getClass match { + case Some(real_class) => if !classes.exists(_ eq real_class) then throw LowLevelIRError("ref is not in the set") + case _ => + } + case BasicOp(name, args) => + case AssignField(assignee, ref, _, value) => ref.getClass match { + case Some(real_class) => if !classes.exists(_ eq real_class) then throw LowLevelIRError("ref is not in the set") + case _ => + } + + private def f(x: Node): Unit = x match + case Result(res) => + case Jump(func, args) => + case Case(x, cases, default) => cases foreach { (_, body) => f(body) }; default foreach f + case LetExpr(name, expr, body) => f(body) + case LetMethodCall(names, cls, method, args, body) => f(body) + case LetCall(res, ref, args, body) => + ref.getFunc match { + case Some(real_func) => if !defs.exists(_ eq real_func) then throw LowLevelIRError("ref is not in the set") + case _ => + } + f(body) + def run(node: Node) = f(node) + def run(func: Func) = f(func.body) + +def validateRefInSet(entry: Node, defs: Set[Func], classes: Set[ClassInfo]): Unit = + val funcRefInSet = FuncRefInSet(defs, classes) + defs.foreach(funcRefInSet.run(_)) + +def validate(entry: Node, defs: Set[Func], classes: Set[ClassInfo]): Unit = + validateRefInSet(entry, defs, classes) + diff --git a/hkmc2/shared/src/main/scala/hkmc2/utils/document/LegacyDocument.scala b/hkmc2/shared/src/main/scala/hkmc2/utils/document/LegacyDocument.scala new file mode 100644 index 0000000000..eec3b867f2 --- /dev/null +++ b/hkmc2/shared/src/main/scala/hkmc2/utils/document/LegacyDocument.scala @@ -0,0 +1,52 @@ +package hkmc2.utils.legacy_document + +enum Document: + case Indented(content: Document) + case Unindented(content: Document) + case Stacked(docs: List[Document], emptyLines: Boolean = false) + case Lined(docs: List[Document], separator: Document) + case Raw(s: String) + + def <:>(other: Document) = line(List(this, other)) + def <#>(other: Document) = line(List(this, other), sep = "") + + override def toString: String = print + + def print: String = { + val sb = StringBuffer() + + def rec(d: Document)(implicit ind: Int, first: Boolean): Unit = d match { + case Raw(s) => + if first && s.nonEmpty then sb append (" " * ind) + sb append s + case Indented(doc) => + rec(doc)(ind + 1, first) + case Unindented(doc) => + assume(ind > 0) + rec(doc)(ind - 1, first) + case Lined(Nil, _) => // skip + case Lined(docs, sep) => + rec(docs.head) + docs.tail foreach { doc => + rec(sep)(ind, false) + rec(doc)(ind, false) + } + case Stacked(Nil, _) => // skip + case Stacked(docs, emptyLines) => + rec(docs.head) + docs.tail foreach { doc => + sb append "\n" + if emptyLines then sb append "\n" + rec(doc)(ind, true) + } + } + + rec(this)(0, true) + sb.toString + } + +def stack(docs: Document*) = Document.Stacked(docs.toList) +def stack_list(docs: List[Document]) = Document.Stacked(docs) +def line(docs: List[Document], sep: String = " ") = Document.Lined(docs, Document.Raw(sep)) +def raw(s: String) = Document.Raw(s) +def indent(doc: Document) = Document.Indented(doc) From 92443254230aa43dcb7d150170f54613d7b18a1b Mon Sep 17 00:00:00 2001 From: waterlens Date: Tue, 7 Jan 2025 20:41:59 +0800 Subject: [PATCH 02/88] Initial Llir builder for `Block` --- .../src/test/scala/hkmc2/DiffTestRunner.scala | 4 +- .../src/test/scala/hkmc2/LlirDiffMaker.scala | 35 +++ .../scala/hkmc2/codegen/cpp/CodeGen.scala | 9 +- .../scala/hkmc2/codegen/llir/Analysis.scala | 125 ++++++++++ .../scala/hkmc2/codegen/llir/Builder.scala | 231 ++++++++++++++++++ .../main/scala/hkmc2/codegen/llir/Llir.scala | 15 +- .../hkmc2/codegen/llir/RefResolver.scala | 1 + .../scala/hkmc2/codegen/llir/Validator.scala | 1 + .../src/test/mlscript/llir/Playground.mls | 164 +++++++++++++ 9 files changed, 576 insertions(+), 9 deletions(-) create mode 100644 hkmc2/jvm/src/test/scala/hkmc2/LlirDiffMaker.scala create mode 100644 hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Analysis.scala create mode 100644 hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala create mode 100644 hkmc2/shared/src/test/mlscript/llir/Playground.mls diff --git a/hkmc2/jvm/src/test/scala/hkmc2/DiffTestRunner.scala b/hkmc2/jvm/src/test/scala/hkmc2/DiffTestRunner.scala index 6390cf3c3e..8f3c28405e 100644 --- a/hkmc2/jvm/src/test/scala/hkmc2/DiffTestRunner.scala +++ b/hkmc2/jvm/src/test/scala/hkmc2/DiffTestRunner.scala @@ -10,9 +10,7 @@ import mlscript.utils._, shorthands._ class MainDiffMaker(val rootPath: Str, val file: os.Path, val preludeFile: os.Path, val predefFile: os.Path, val relativeName: Str) - extends BbmlDiffMaker - - + extends LlirDiffMaker class AllTests extends org.scalatest.Suites( new CompileTestRunner(DiffTestRunner.State){}, diff --git a/hkmc2/jvm/src/test/scala/hkmc2/LlirDiffMaker.scala b/hkmc2/jvm/src/test/scala/hkmc2/LlirDiffMaker.scala new file mode 100644 index 0000000000..c639bede80 --- /dev/null +++ b/hkmc2/jvm/src/test/scala/hkmc2/LlirDiffMaker.scala @@ -0,0 +1,35 @@ +package hkmc2 + +import scala.collection.mutable + +import mlscript.utils.*, shorthands.* +import utils.* + +import document.* +import codegen.Block +import codegen.llir.LlirBuilder +import hkmc2.syntax.Tree.Ident +import hkmc2.codegen.Path +import hkmc2.semantics.Term.Blk +import hkmc2.codegen.llir.Fresh +import hkmc2.codegen.js.Scope +import hkmc2.codegen.llir.Ctx +import hkmc2.codegen.llir._ + +abstract class LlirDiffMaker extends BbmlDiffMaker: + val llir = NullaryCommand("llir") + + override def processTerm(trm: Blk, inImport: Bool)(using Raise): Unit = + super.processTerm(trm, inImport) + if llir.isSet then + val low = ltl.givenIn: + codegen.Lowering() + val le = low.program(trm) + given Scope = Scope.empty + val fresh = Fresh() + val fuid = FreshInt() + val llb = LlirBuilder(tl)(fresh, fuid) + given Ctx = Ctx.empty + val llirProg = llb.bProg(le) + output(llirProg.show()) + \ No newline at end of file diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/CodeGen.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/CodeGen.scala index 2ed12302e9..81501fe2df 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/CodeGen.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/CodeGen.scala @@ -108,8 +108,8 @@ private class CppCodeGen: val init = Expr.Initializer(exprs.map{x => toExpr(x)}) mlsTupleValue(init) - def codegenCaseWithIfs(scrut: Name, cases: Ls[(Pat, Node)], default: Opt[Node], storeInto: Str)(using decls: Ls[Decl], stmts: Ls[Stmt])(using ctx: Ctx): (Ls[Decl], Ls[Stmt]) = - val scrutName = mapName(scrut) + def codegenCaseWithIfs(scrut: TrivialExpr, cases: Ls[(Pat, Node)], default: Opt[Node], storeInto: Str)(using decls: Ls[Decl], stmts: Ls[Stmt])(using ctx: Ctx): (Ls[Decl], Ls[Stmt]) = + val scrut2 = toExpr(scrut) val init: Stmt = default.fold(mlsThrowNonExhaustiveMatch)(x => { val (decls2, stmts2) = codegen(x, storeInto)(using Ls.empty, Ls.empty[Stmt]) @@ -118,11 +118,11 @@ private class CppCodeGen: val stmt = cases.foldRight(S(init)) { case ((Pat.Class(cls), arm), nextarm) => val (decls2, stmts2) = codegen(arm, storeInto)(using Ls.empty, Ls.empty[Stmt]) - val stmt = Stmt.If(mlsIsValueOf(cls.name |> mapName, Expr.Var(scrutName)), Stmt.Block(decls2, stmts2), nextarm) + val stmt = Stmt.If(mlsIsValueOf(cls.name |> mapName, scrut2), Stmt.Block(decls2, stmts2), nextarm) S(stmt) case ((Pat.Lit(i @ hkmc2.syntax.Tree.IntLit(_)), arm), nextarm) => val (decls2, stmts2) = codegen(arm, storeInto)(using Ls.empty, Ls.empty[Stmt]) - val stmt = Stmt.If(mlsIsIntLit(Expr.Var(scrutName), i), Stmt.Block(decls2, stmts2), nextarm) + val stmt = Stmt.If(mlsIsIntLit(scrut2, i), Stmt.Block(decls2, stmts2), nextarm) S(stmt) case _ => ??? } @@ -169,6 +169,7 @@ private class CppCodeGen: (decls, stmts2) case Node.Jump(defn, args) => codegenJumpWithCall(defn, args, S(storeInto)) + case Node.Panic => (decls, stmts :+ Stmt.Raw("throw std::runtime_error(\"Panic\");")) case Node.LetExpr(name, expr, body) => val stmts2 = stmts ++ Ls(Stmt.AutoBind(Ls(name |> mapName), codegen(expr))) codegen(body, storeInto)(using decls, stmts2) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Analysis.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Analysis.scala new file mode 100644 index 0000000000..042295874a --- /dev/null +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Analysis.scala @@ -0,0 +1,125 @@ +package hkmc2.codegen.llir + +import mlscript._ +import hkmc2.codegen._ +import hkmc2.codegen.llir.{ Program => LlirProgram, Node, Func } +import mlscript.utils._ +import mlscript.utils.shorthands._ +import hkmc2.semantics.BuiltinSymbol +import hkmc2.syntax.Tree.UnitLit +import hkmc2.{Raise, raise, Diagnostic, ErrorReport, Message} +import hkmc2.Message.MessageContext +import hkmc2.semantics.InnerSymbol +import hkmc2.codegen.llir.FuncRef.fromName +import scala.collection.mutable.ListBuffer + +import scala.annotation.tailrec +import scala.collection.immutable.* +import scala.collection.mutable.{HashMap => MutHMap} +import scala.collection.mutable.{HashSet => MutHSet, Set => MutSet} + +class UsefulnessAnalysis(verbose: Bool = false): + import Expr._ + import Node._ + + def log(x: Any) = if verbose then println(x) + + val uses = MutHMap[(Name, Int), Int]() + val defs = MutHMap[Name, Int]() + + private def addDef(x: Name) = + defs.update(x, defs.getOrElse(x, 0) + 1) + + private def addUse(x: Name) = + val def_count = defs.get(x) match + case None => throw Exception(s"Use of undefined variable $x") + case Some(value) => value + val key = (x, defs(x)) + uses.update(key, uses.getOrElse(key, 0) + 1) + + private def f(x: TrivialExpr): Unit = x match + case Ref(name) => addUse(name) + case _ => () + + private def f(x: Expr): Unit = x match + case Ref(name) => addUse(name) + case Literal(lit) => + case CtorApp(name, args) => args.foreach(f) + case Select(name, cls, field) => addUse(name) + case BasicOp(name, args) => args.foreach(f) + case AssignField(assignee, _, _, value) => + addUse(assignee) + f(value) + + private def f(x: Node): Unit = x match + case Result(res) => res.foreach(f) + case Jump(defn, args) => args.foreach(f) + case Case(scrut, cases, default) => + scrut match + case Ref(name) => addUse(name) + case _ => () + cases.foreach { case (cls, body) => f(body) }; default.foreach(f) + case LetMethodCall(names, cls, method, args, body) => addUse(method); args.foreach(f); names.foreach(addDef); f(body) + case LetExpr(name, expr, body) => f(expr); addDef(name); f(body) + case LetCall(names, defn, args, body) => args.foreach(f); names.foreach(addDef); f(body) + + def run(x: Func) = + x.params.foreach(addDef) + f(x.body) + uses.toMap + +class FreeVarAnalysis(extended_scope: Bool = true, verbose: Bool = false): + import Expr._ + import Node._ + + private val visited = MutHSet[Str]() + private def f(using defined: Set[Str])(defn: Func, fv: Set[Str]): Set[Str] = + val defined2 = defn.params.foldLeft(defined)((acc, param) => acc + param.str) + f(using defined2)(defn.body, fv) + private def f(using defined: Set[Str])(expr: Expr, fv: Set[Str]): Set[Str] = expr match + case Ref(name) => if defined.contains(name.str) then fv else fv + name.str + case Literal(lit) => fv + case CtorApp(name, args) => args.foldLeft(fv)((acc, arg) => f(using defined)(arg.toExpr, acc)) + case Select(name, cls, field) => if defined.contains(name.str) then fv else fv + name.str + case BasicOp(name, args) => args.foldLeft(fv)((acc, arg) => f(using defined)(arg.toExpr, acc)) + case AssignField(assignee, _, _, value) => f(using defined)( + value.toExpr, + if defined.contains(assignee.str) then fv + assignee.str else fv + ) + private def f(using defined: Set[Str])(node: Node, fv: Set[Str]): Set[Str] = node match + case Result(res) => res.foldLeft(fv)((acc, arg) => f(using defined)(arg.toExpr, acc)) + case Jump(defnref, args) => + var fv2 = args.foldLeft(fv)((acc, arg) => f(using defined)(arg.toExpr, acc)) + if extended_scope && !visited.contains(defnref.name) then + val defn = defnref.expectFn + visited.add(defn.name) + val defined2 = defn.params.foldLeft(defined)((acc, param) => acc + param.str) + fv2 = f(using defined2)(defn, fv2) + fv2 + case Case(scrut, cases, default) => + val fv2 = scrut match + case Ref(name) => if defined.contains(name.str) then fv else fv + name.str + case _ => fv + val fv3 = cases.foldLeft(fv2) { + case (acc, (cls, body)) => f(using defined)(body, acc) + } + fv3 + case LetMethodCall(resultNames, cls, method, args, body) => + var fv2 = args.foldLeft(fv)((acc, arg) => f(using defined)(arg.toExpr, acc)) + val defined2 = resultNames.foldLeft(defined)((acc, name) => acc + name.str) + f(using defined2)(body, fv2) + case LetExpr(name, expr, body) => + val fv2 = f(using defined)(expr, fv) + val defined2 = defined + name.str + f(using defined2)(body, fv2) + case LetCall(resultNames, defnref, args, body) => + var fv2 = args.foldLeft(fv)((acc, arg) => f(using defined)(arg.toExpr, acc)) + val defined2 = resultNames.foldLeft(defined)((acc, name) => acc + name.str) + if extended_scope && !visited.contains(defnref.name) then + val defn = defnref.expectFn + visited.add(defn.name) + val defined2 = defn.params.foldLeft(defined)((acc, param) => acc + param.str) + fv2 = f(using defined2)(defn, fv2) + f(using defined2)(body, fv2) + def run(node: Node) = f(using Set.empty)(node, Set.empty) + def run_with(node: Node, defined: Set[Str]) = f(using defined)(node, Set.empty) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala new file mode 100644 index 0000000000..32a57a1382 --- /dev/null +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala @@ -0,0 +1,231 @@ +package hkmc2 +package codegen.llir + +import hkmc2.codegen._ +import hkmc2.codegen.llir.{ Program => LlirProgram, Node, Func } +import mlscript.utils._ +import mlscript.utils.shorthands._ +import hkmc2.semantics.BuiltinSymbol +import hkmc2.syntax.Tree.UnitLit +import hkmc2.{Raise, raise, Diagnostic, ErrorReport, Message} +import hkmc2.Message.MessageContext +import hkmc2.codegen.llir.FuncRef.fromName +import scala.collection.mutable.ListBuffer +import hkmc2.codegen.js.Scope +import hkmc2._ +import hkmc2.document._ +import hkmc2.semantics.Elaborator.State +import hkmc2.codegen.Program +import hkmc2.utils.TraceLogger + + +def err(msg: Message)(using Raise): Unit = + raise(ErrorReport(msg -> N :: Nil, + source = Diagnostic.Source.Compilation)) + +final case class Ctx( + symbol_ctx: Map[Str, Name] = Map.empty, + fn_ctx: Map[Local, Name] = Map.empty, // is a known function + closure_ctx: Map[Local, Name] = Map.empty, // closure name + class_ctx: Map[Local, Name] = Map.empty, + block_ctx: Map[Local, Name] = Map.empty, + def_acc: ListBuffer[Func] = ListBuffer.empty, +): + def addName(n: Str, m: Name) = copy(symbol_ctx = symbol_ctx + (n -> m)) + def findName(n: Str)(using Raise): Name = symbol_ctx.get(n) match + case None => + err(msg"Name not found: $n") + Name("error") + case Some(value) => value + +object Ctx: + val empty = Ctx() + + +final class LlirBuilder(tl: TraceLogger)(fresh: Fresh, fnUid: FreshInt): + import tl.{trace, log} + def er = Expr.Ref + def nr = Node.Result + def nme(x: Str) = Name(x) + def sr(x: Str) = er(Name(x)) + def sr(x: Name) = er(x) + def nsr(xs: Ls[Name]) = xs.map(er(_)) + + private def allocIfNew(l: Local)(using Raise, Scope): String = + trace[Str](s"allocIfNew begin: $l", x => s"allocIfNew end: $x"): + if summon[Scope].lookup(l).isDefined then + getVar_!(l) + else + summon[Scope].allocateName(l) + + private def getVar_!(l: Local)(using Raise, Scope): String = + trace[Str](s"getVar_! begin", x => s"getVar_! end: $x"): + l match + case ts: semantics.TermSymbol => + ts.owner match + case S(owner) => ts.id.name + case N => + ts.id.name + case ts: semantics.BlockMemberSymbol => // this means it's a locally-defined member + ts.nme + // ts.trmTree + case ts: semantics.InnerSymbol => + summon[Scope].findThis_!(ts) + case _ => summon[Scope].lookup_!(l) + + private def bBind(name: Opt[Str], e: Result, body: Block)(k: TrivialExpr => Ctx ?=> Node)(using ctx: Ctx)(using Raise, Scope): Node = + trace[Node](s"bBind begin: $name", x => s"bBind end: ${x.show}"): + bResult(e): + case r: Expr.Ref => + given Ctx = ctx.addName(name.getOrElse(fresh.make.str), r.name) + log(s"bBind ref: $name -> $r") + bBlock(body)(k) + case l: Expr.Literal => + val v = fresh.make + given Ctx = ctx.addName(name.getOrElse(fresh.make.str), v) + log(s"bBind lit: $name -> $v") + Node.LetExpr(v, l, bBlock(body)(k)) + + private def bArgs(e: Ls[Arg])(k: Ls[TrivialExpr] => Ctx ?=> Node)(using ctx: Ctx)(using Raise, Scope): Node = + trace[Node](s"bArgs begin", x => s"bArgs end: ${x.show}"): + e match + case Nil => k(Nil) + case Arg(spread, x) :: xs => bPath(x): + case r: TrivialExpr => bArgs(xs): + case rs: Ls[TrivialExpr] => k(r :: rs) + + private def bFunDef(e: FunDefn)(using ctx: Ctx)(using Raise, Scope): Func = + val FunDefn(sym, params, body) = e + if params.length != 1 then + err(msg"Unsupported number of parameters: ${params.length.toString}") + val paramsList = params.head.params.map(x => summon[Scope].allocateName(x.sym)).map(Name(_)) + Func( + fnUid.make, + sym.nme, + params = paramsList, + resultNum = 1, + body = bBlock(body)(x => Node.Result(Ls(x))) + ) + + private def bValue(v: Value)(k: TrivialExpr => Ctx ?=> Node)(using ctx: Ctx)(using Raise, Scope) : Node = + trace[Node](s"bValue begin", x => s"bValue end: ${x.show}"): + v match + case Value.Ref(l) => k(ctx.findName(getVar_!(l)) |> sr) + case Value.This(sym) => err(msg"Unsupported value: This"); Node.Result(Ls()) + case Value.Lit(lit) => k(Expr.Literal(lit)) + case Value.Lam(params, body) => err(msg"Unsupported value: Lam"); Node.Result(Ls()) + case Value.Arr(elems) => err(msg"Unsupported value: Arr"); Node.Result(Ls()) + + private def bPath(p: Path)(k: TrivialExpr => Ctx ?=> Node)(using ctx: Ctx)(using Raise, Scope) : Node = + trace[Node](s"bPath begin", x => s"bPath end: ${x.show}"): + p match + case Select(qual, name) => err(msg"Unsupported path: Select"); Node.Result(Ls()) + case x: Value => bValue(x)(k) + + private def bResult(r: Result)(k: TrivialExpr => Ctx ?=> Node)(using ctx: Ctx)(using Raise, Scope) : Node = + trace[Node](s"bResult begin", x => s"bResult end: ${x.show}"): + r match + case Call(Value.Ref(sym: BuiltinSymbol), args) => + bArgs(args): + case args: Ls[TrivialExpr] => + val v = fresh.make + Node.LetExpr(v, Expr.BasicOp(sym.nme, args), k(v |> sr)) + case Call(Select(Value.Ref(sym: BuiltinSymbol), name), args) => + bArgs(args): + case args: Ls[TrivialExpr] => + val v = fresh.make + Node.LetExpr(v, Expr.CtorApp(ClassRef.fromName(name.name), args), k(v |> sr)) + case Call(Value.Ref(name), args) if ctx.fn_ctx.contains(name) => + bArgs(args): + case args: Ls[TrivialExpr] => + val v = fresh.make + val fn = ctx.fn_ctx.get(name).get + Node.LetCall(Ls(v), FuncRef.fromName(fn), args, k(v |> sr)) + case Call(fn, args) => + bPath(fn): + case f: TrivialExpr => + bArgs(args): + case args: Ls[TrivialExpr] => + val v = fresh.make + Node.LetMethodCall(Ls(v), ClassRef(R("Callable")), Name("apply" + args.length), f :: args, k(v |> sr)) + case Instantiate(cls, args) => ??? + case x: Path => bPath(x)(k) + + private def bBlock(blk: Block)(k: TrivialExpr => Ctx ?=> Node)(using ctx: Ctx)(using Raise, Scope) : Node = + trace[Node](s"bBlock begin", x => s"bBlock end: ${x.show}"): + blk match + case Match(scrut, arms, dflt, rest) => + bPath(scrut): + case e: TrivialExpr => + val jp = fresh.make("j") + // guess: the value of Match itself in Block is useless + // val res = fresh.make + val fvset = (rest.freeVars -- rest.definedVars).map(allocIfNew) + val fvs1 = fvset.toList + val new_ctx = fvs1.foldLeft(ctx)((acc, x) => acc.addName(x, fresh.make)) + val fvs = fvs1.map(new_ctx.findName(_)) + def cont(x: TrivialExpr)(using Ctx) = Node.Jump( + FuncRef.fromName(jp), + /* x :: */ fvs1.map(x => summon[Ctx].findName(x)).map(sr) + ) + given Ctx = new_ctx + val casesList: Ls[(Pat, Node)] = arms.map: + case (Case.Lit(lit), body) => + (Pat.Lit(lit), bBlock(body)(cont)) + case (Case.Cls(cls, _), body) => + (Pat.Class(ClassRef.fromName(cls.nme)), bBlock(body)(cont)) + case (Case.Tup(len, inf), body) => + (Pat.Class(ClassRef.fromName("Tuple" + len.toString())), bBlock(body)(cont)) + val defaultCase = dflt.map(bBlock(_)(cont)) + val jpdef = Func( + fnUid.make, + jp.str, + params = /* res :: */ fvs, + resultNum = 1, + bBlock(rest)(k), + ) + summon[Ctx].def_acc += jpdef + Node.Case(e, casesList, defaultCase) + case Return(res, implct) => bResult(res)(x => Node.Result(Ls(x))) + case Throw(exc) => TODO("Throw not supported") + case Label(label, body, rest) => ??? + case Break(label) => TODO("Break not supported") + case Continue(label) => TODO("Continue not supported") + case Begin(sub, rest) => + // re-associate rest blocks to correctly handle the continuation + sub match + case _: BlockTail => + val definedVars = sub.definedVars + definedVars.foreach(allocIfNew) + bBlock(sub): + x => bBlock(rest)(k) + case Assign(lhs, rhs, rest2) => + bBlock(Assign(lhs, rhs, Begin(rest2, rest)))(k) + case Begin(sub, rest2) => + bBlock(Begin(sub, Begin(rest2, rest)))(k) + case Define(defn, rest2) => + bBlock(Define(defn, Begin(rest2, rest)))(k) + case Match(scrut, arms, dflt, rest2) => + bBlock(Match(scrut, arms, dflt, Begin(rest2, rest)))(k) + case _ => TODO(s"Other non-tail sub components of Begin not supported $sub") + case TryBlock(sub, finallyDo, rest) => TODO("TryBlock not supported") + case Assign(lhs, rhs, rest) => + val name = allocIfNew(lhs) + bBind(S(name), rhs, rest)(k) + case AssignField(lhs, nme, rhs, rest) => TODO("AssignField not supported") + case Define(FunDefn(sym, params, body), rest) => + val f = bFunDef(FunDefn(sym, params, body)) + ctx.def_acc += f + bBlock(rest)(k) + case End(msg) => k(Expr.Literal(UnitLit(false))) + case _: Block => + val docBlock = blk.showAsTree + err(msg"Unsupported block: $docBlock") + Node.Result(Ls()) + + def bProg(e: Program)(using Raise, Scope): LlirProgram = + val ctx = Ctx.empty + given Ctx = ctx + ctx.def_acc.clear() + val entry = bBlock(e.main)(x => Node.Result(Ls(x))) + LlirProgram(Set.empty, ctx.def_acc.toSet, entry) \ No newline at end of file diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Llir.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Llir.scala index bfa2fbe713..0d3a6c3d2f 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Llir.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Llir.scala @@ -34,7 +34,6 @@ case class Program( Sorting.quickSort(t2) given Conversion[String, Document] = raw stack( - "Program:", stack_list(t1.filter(x => !hiddenNames.contains(x.name)).map(_.toDocument).toList) |> indent, stack_list(t2.map(_.toDocument).toList) |> indent, main.toDocument |> indent @@ -72,6 +71,11 @@ case class Name(str: Str): def trySubst(map: Map[Str, Name]) = map.getOrElse(str, this) override def toString: String = str +object FuncRef: + def fromName(name: Str) = FuncRef(Right(name)) + def fromName(name: Name) = FuncRef(Right(name.str)) + def fromFunc(func: Func) = FuncRef(Left(func)) + class FuncRef(var func: Either[Func, Str]): def name: String = func.fold(_.name, x => x) def expectFn: Func = func.fold(identity, x => throw Exception(s"Expected a def, but got $x")) @@ -81,6 +85,11 @@ class FuncRef(var func: Either[Func, Str]): case _ => false } +object ClassRef: + def fromName(name: Str) = ClassRef(Right(name)) + def fromName(name: Name) = ClassRef(Right(name.str)) + def fromClass(cls: ClassInfo) = ClassRef(Left(cls)) + class ClassRef(var cls: Either[ClassInfo, Str]): def name: String = cls.fold(_.name, x => x) def expectCls: ClassInfo = cls.fold(identity, x => throw Exception(s"Expected a class, but got $x")) @@ -181,7 +190,8 @@ enum Node: // Terminal forms: case Result(res: Ls[TrivialExpr]) case Jump(func: FuncRef, args: Ls[TrivialExpr]) - case Case(scrutinee: Name, cases: Ls[(Pat, Node)], default: Opt[Node]) + case Case(scrutinee: TrivialExpr, cases: Ls[(Pat, Node)], default: Opt[Node]) + case Panic // Intermediate forms: case LetExpr(name: Name, expr: Expr, body: Node) case LetMethodCall(names: Ls[Name], cls: ClassRef, method: Name, args: Ls[TrivialExpr], body: Node) @@ -218,6 +228,7 @@ enum Node: case S(dc) => val default = Ls("_" <:> "=>", dc.toDocument |> indent) stack(first, (Document.Stacked(other ++ default) |> indent)) + case Panic => "panic" case LetExpr(x, expr, body) => stack( "let" diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/RefResolver.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/RefResolver.scala index 54f0df95b2..403d210b23 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/RefResolver.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/RefResolver.scala @@ -43,6 +43,7 @@ private final class RefResolver(defs: Map[Str, Func], classes: Map[Str, ClassInf case None => if !allowInlineJp then throw LowLevelIRError(f"unknown function ${defnref.name} in ${defs.keySet.mkString(",")}") + case Panic => def run(node: Node) = f(node) def run(node: Func) = f(node.body) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Validator.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Validator.scala index ee1459344e..9986835ff4 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Validator.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Validator.scala @@ -24,6 +24,7 @@ private final class FuncRefInSet(defs: Set[Func], classes: Set[ClassInfo]): case Result(res) => case Jump(func, args) => case Case(x, cases, default) => cases foreach { (_, body) => f(body) }; default foreach f + case Panic => case LetExpr(name, expr, body) => f(body) case LetMethodCall(names, cls, method, args, body) => f(body) case LetCall(res, ref, args, body) => diff --git a/hkmc2/shared/src/test/mlscript/llir/Playground.mls b/hkmc2/shared/src/test/mlscript/llir/Playground.mls new file mode 100644 index 0000000000..21519bd151 --- /dev/null +++ b/hkmc2/shared/src/test/mlscript/llir/Playground.mls @@ -0,0 +1,164 @@ +:js + + +:llir +fun f1() = + let x = 1 + let x = 2 + x +//│ +//│ def f1() = +//│ let x$0 = 1 in +//│ let x$1 = 2 in +//│ x$1 +//│ undefined + +:slot +:llir +fun f2() = + let x = 0 + if x == 1 then 2 else 3 +//│ Pretty Lowered: +//│ define fun f2() { set x = 0 in set scrut = ==(x, 1) in match scrut true => return 2 else return 3 } in return null +//│ +//│ def f2() = +//│ let x$0 = 0 in +//│ let x$1 = ==(x$0,1) in +//│ case x$1 of +//│ BoolLit(true) => +//│ 2 +//│ _ => +//│ 3 +//│ def j$0() = +//│ null +//│ undefined + +:llir +:slot +fun f3() = + let x1 = 0 + let x2 = 1 + if true then x1 else x2 +//│ Pretty Lowered: +//│ +//│ define fun f3() { +//│ set x1 = 0 in +//│ set x2 = 1 in +//│ set scrut = true in +//│ match scrut +//│ true => +//│ return x1 +//│ else +//│ return x2 +//│ } in +//│ return null +//│ +//│ def f3() = +//│ let x$0 = 0 in +//│ let x$1 = 1 in +//│ let x$2 = true in +//│ case x$2 of +//│ BoolLit(true) => +//│ x$0 +//│ _ => +//│ x$1 +//│ def j$0() = +//│ null +//│ undefined + + +:slot +:llir +fun f4() = + let x = 0 + let x = if x == 1 then 2 else 3 + x +//│ Pretty Lowered: +//│ +//│ define fun f4() { +//│ set x = 0 in +//│ begin +//│ set scrut = ==(x, 1) in +//│ match scrut +//│ true => +//│ set tmp = 2 in +//│ end +//│ else +//│ set tmp = 3 in +//│ end; +//│ set x1 = tmp in +//│ return x1 +//│ } in +//│ return null +//│ +//│ def f4() = +//│ let x$0 = 0 in +//│ let x$1 = ==(x$0,1) in +//│ case x$1 of +//│ BoolLit(true) => +//│ let x$3 = 2 in +//│ jump j$0(x$3) +//│ _ => +//│ let x$4 = 3 in +//│ jump j$0(x$4) +//│ def j$0(x$2) = +//│ x$2 +//│ undefined + +:slot +:llir +fun f5() = + let x = 0 + let x = if x == 1 then 2 else 3 + let x = if x == 2 then 4 else 5 + x +//│ Pretty Lowered: +//│ +//│ define fun f5() { +//│ set x = 0 in +//│ begin +//│ set scrut = ==(x, 1) in +//│ match scrut +//│ true => +//│ set tmp = 2 in +//│ end +//│ else +//│ set tmp = 3 in +//│ end; +//│ set x1 = tmp in +//│ begin +//│ set scrut1 = ==(x1, 2) in +//│ match scrut1 +//│ true => +//│ set tmp1 = 4 in +//│ end +//│ else +//│ set tmp1 = 5 in +//│ end; +//│ set x2 = tmp1 in +//│ return x2 +//│ } in +//│ return null +//│ +//│ def f5() = +//│ let x$0 = 0 in +//│ let x$1 = ==(x$0,1) in +//│ case x$1 of +//│ BoolLit(true) => +//│ let x$3 = 2 in +//│ jump j$0(x$3) +//│ _ => +//│ let x$4 = 3 in +//│ jump j$0(x$4) +//│ def j$0(x$2) = +//│ let x$5 = ==(x$2,2) in +//│ case x$5 of +//│ BoolLit(true) => +//│ let x$7 = 4 in +//│ jump j$1(x$7) +//│ _ => +//│ let x$8 = 5 in +//│ jump j$1(x$8) +//│ def j$1(x$6) = +//│ x$6 +//│ undefined From 78c9ab5882d63192107a1869f4e8de439b06ef44 Mon Sep 17 00:00:00 2001 From: waterlens Date: Wed, 8 Jan 2025 16:17:01 +0800 Subject: [PATCH 03/88] Resolve classes without methods --- .../src/test/scala/hkmc2/LlirDiffMaker.scala | 3 +- .../scala/hkmc2/codegen/llir/Builder.scala | 106 ++++++++++++++---- .../main/scala/hkmc2/codegen/llir/Llir.scala | 6 +- .../hkmc2/codegen/llir/RefResolver.scala | 2 +- .../scala/hkmc2/codegen/llir/Validator.scala | 2 +- .../src/test/mlscript/llir/Playground.mls | 35 ++++++ 6 files changed, 124 insertions(+), 30 deletions(-) diff --git a/hkmc2/jvm/src/test/scala/hkmc2/LlirDiffMaker.scala b/hkmc2/jvm/src/test/scala/hkmc2/LlirDiffMaker.scala index c639bede80..6323c3d1a0 100644 --- a/hkmc2/jvm/src/test/scala/hkmc2/LlirDiffMaker.scala +++ b/hkmc2/jvm/src/test/scala/hkmc2/LlirDiffMaker.scala @@ -28,7 +28,8 @@ abstract class LlirDiffMaker extends BbmlDiffMaker: given Scope = Scope.empty val fresh = Fresh() val fuid = FreshInt() - val llb = LlirBuilder(tl)(fresh, fuid) + val cuid = FreshInt() + val llb = LlirBuilder(tl)(fresh, fuid, cuid) given Ctx = Ctx.empty val llirProg = llb.bProg(le) output(llirProg.show()) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala index 32a57a1382..33b22034d7 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala @@ -6,7 +6,7 @@ import hkmc2.codegen.llir.{ Program => LlirProgram, Node, Func } import mlscript.utils._ import mlscript.utils.shorthands._ import hkmc2.semantics.BuiltinSymbol -import hkmc2.syntax.Tree.UnitLit +import hkmc2.syntax.Tree import hkmc2.{Raise, raise, Diagnostic, ErrorReport, Message} import hkmc2.Message.MessageContext import hkmc2.codegen.llir.FuncRef.fromName @@ -17,6 +17,9 @@ import hkmc2.document._ import hkmc2.semantics.Elaborator.State import hkmc2.codegen.Program import hkmc2.utils.TraceLogger +import hkmc2.semantics.TermSymbol +import hkmc2.semantics.MemberSymbol +import hkmc2.semantics.FieldSymbol def err(msg: Message)(using Raise): Unit = @@ -24,25 +27,41 @@ def err(msg: Message)(using Raise): Unit = source = Diagnostic.Source.Compilation)) final case class Ctx( + def_acc: ListBuffer[Func], + class_acc: ListBuffer[ClassInfo], symbol_ctx: Map[Str, Name] = Map.empty, fn_ctx: Map[Local, Name] = Map.empty, // is a known function closure_ctx: Map[Local, Name] = Map.empty, // closure name class_ctx: Map[Local, Name] = Map.empty, block_ctx: Map[Local, Name] = Map.empty, - def_acc: ListBuffer[Func] = ListBuffer.empty, ): + def addFuncName(n: Local, m: Name) = copy(fn_ctx = fn_ctx + (n -> m)) + def findFuncName(n: Local)(using Raise) = fn_ctx.get(n) match + case None => + err(msg"Function name not found: ${n.toString()}") + Name("error") + case Some(value) => value + def addClassName(n: Local, m: Name) = copy(class_ctx = class_ctx + (n -> m)) + def findClassName(n: Local)(using Raise) = class_ctx.get(n) match + case None => + err(msg"Class name not found: ${n.toString()}") + Name("error") + case Some(value) => value def addName(n: Str, m: Name) = copy(symbol_ctx = symbol_ctx + (n -> m)) def findName(n: Str)(using Raise): Name = symbol_ctx.get(n) match case None => err(msg"Name not found: $n") Name("error") case Some(value) => value + def reset = + def_acc.clear() + class_acc.clear() object Ctx: - val empty = Ctx() + val empty = Ctx(ListBuffer.empty, ListBuffer.empty) -final class LlirBuilder(tl: TraceLogger)(fresh: Fresh, fnUid: FreshInt): +final class LlirBuilder(tl: TraceLogger)(fresh: Fresh, fnUid: FreshInt, clsUid: FreshInt): import tl.{trace, log} def er = Expr.Ref def nr = Node.Result @@ -95,17 +114,31 @@ final class LlirBuilder(tl: TraceLogger)(fresh: Fresh, fnUid: FreshInt): case rs: Ls[TrivialExpr] => k(r :: rs) private def bFunDef(e: FunDefn)(using ctx: Ctx)(using Raise, Scope): Func = - val FunDefn(sym, params, body) = e - if params.length != 1 then - err(msg"Unsupported number of parameters: ${params.length.toString}") - val paramsList = params.head.params.map(x => summon[Scope].allocateName(x.sym)).map(Name(_)) - Func( - fnUid.make, - sym.nme, - params = paramsList, - resultNum = 1, - body = bBlock(body)(x => Node.Result(Ls(x))) - ) + trace[Func](s"bFunDef begin", x => s"bFunDef end: ${x.show}"): + val FunDefn(sym, params, body) = e + if params.length != 1 then + err(msg"Curried function not supported: ${params.length.toString}") + val paramsList = params.head.params.map(x => x -> summon[Scope].allocateName(x.sym)) + val new_ctx = paramsList.foldLeft(ctx)((acc, x) => acc.addName(getVar_!(x._1.sym), x._2 |> nme)) + val pl = paramsList.map(_._2).map(nme) + Func( + fnUid.make, + sym.nme, + params = pl, + resultNum = 1, + body = bBlock(body)(x => Node.Result(Ls(x)))(using new_ctx) + ) + + private def bClsLikeDef(e: ClsLikeDefn)(using ctx: Ctx)(using Raise, Scope): ClassInfo = + trace[ClassInfo](s"bClsLikeDef begin", x => s"bClsLikeDef end: ${x.show}"): + val ClsLikeDefn(sym, kind, methods, privateFields, publicFields, ctor) = e + val clsDefn = sym.defn.getOrElse(die) + val clsParams = clsDefn.paramsOpt.fold(Nil)(_.paramSyms) + ClassInfo( + clsUid.make, + sym.nme, + clsParams.map(_.nme) + ) private def bValue(v: Value)(k: TrivialExpr => Ctx ?=> Node)(using ctx: Ctx)(using Raise, Scope) : Node = trace[Node](s"bValue begin", x => s"bValue end: ${x.show}"): @@ -116,10 +149,26 @@ final class LlirBuilder(tl: TraceLogger)(fresh: Fresh, fnUid: FreshInt): case Value.Lam(params, body) => err(msg"Unsupported value: Lam"); Node.Result(Ls()) case Value.Arr(elems) => err(msg"Unsupported value: Arr"); Node.Result(Ls()) + private def getClassOfMem(p: FieldSymbol)(using ctx: Ctx)(using Raise, Scope): Local = + trace[Local](s"bMemSym begin", x => s"bMemSym end: $x"): + p match + case ts: TermSymbol => ts.owner.get + case ms: MemberSymbol[?] => ms.defn.get.sym + private def bPath(p: Path)(k: TrivialExpr => Ctx ?=> Node)(using ctx: Ctx)(using Raise, Scope) : Node = trace[Node](s"bPath begin", x => s"bPath end: ${x.show}"): p match - case Select(qual, name) => err(msg"Unsupported path: Select"); Node.Result(Ls()) + case s @ Select(qual, name) => + log(s"bPath Select: $qual.$name with ${s.symbol.get}") + bPath(qual): + case q: Expr.Ref => + val v = fresh.make + val cls = ClassRef.fromName(ctx.findClassName(getClassOfMem(s.symbol.get))) + val field = name.name + Node.LetExpr(v, Expr.Select(q.name, cls, field), k(v |> sr)) + case q: Expr.Literal => + err(msg"Unsupported select on literal") + Node.Result(Ls()) case x: Value => bValue(x)(k) private def bResult(r: Result)(k: TrivialExpr => Ctx ?=> Node)(using ctx: Ctx)(using Raise, Scope) : Node = @@ -148,7 +197,9 @@ final class LlirBuilder(tl: TraceLogger)(fresh: Fresh, fnUid: FreshInt): case args: Ls[TrivialExpr] => val v = fresh.make Node.LetMethodCall(Ls(v), ClassRef(R("Callable")), Name("apply" + args.length), f :: args, k(v |> sr)) - case Instantiate(cls, args) => ??? + case Instantiate(cls, args) => + err(msg"Unsupported result: Instantiate") + Node.Result(Ls()) case x: Path => bPath(x)(k) private def bBlock(blk: Block)(k: TrivialExpr => Ctx ?=> Node)(using ctx: Ctx)(using Raise, Scope) : Node = @@ -187,7 +238,8 @@ final class LlirBuilder(tl: TraceLogger)(fresh: Fresh, fnUid: FreshInt): summon[Ctx].def_acc += jpdef Node.Case(e, casesList, defaultCase) case Return(res, implct) => bResult(res)(x => Node.Result(Ls(x))) - case Throw(exc) => TODO("Throw not supported") + case Throw(Instantiate(Select(Value.Ref(globalThis), ident), Ls(Value.Lit(Tree.StrLit(e))))) if ident.name == "Error" => + Node.Panic(e) case Label(label, body, rest) => ??? case Break(label) => TODO("Break not supported") case Continue(label) => TODO("Continue not supported") @@ -213,11 +265,17 @@ final class LlirBuilder(tl: TraceLogger)(fresh: Fresh, fnUid: FreshInt): val name = allocIfNew(lhs) bBind(S(name), rhs, rest)(k) case AssignField(lhs, nme, rhs, rest) => TODO("AssignField not supported") - case Define(FunDefn(sym, params, body), rest) => - val f = bFunDef(FunDefn(sym, params, body)) + case Define(fd @ FunDefn(sym, params, body), rest) => + val f = bFunDef(fd) ctx.def_acc += f - bBlock(rest)(k) - case End(msg) => k(Expr.Literal(UnitLit(false))) + val new_ctx = ctx.addFuncName(sym, Name(f.name)) + bBlock(rest)(k)(using new_ctx) + case Define(cd @ ClsLikeDefn(sym, kind, methods, privateFields, publicFields, ctor), rest) => + val c = bClsLikeDef(cd) + ctx.class_acc += c + val new_ctx = ctx.addClassName(sym, Name(c.name)) + bBlock(rest)(k)(using new_ctx) + case End(msg) => k(Expr.Literal(Tree.UnitLit(false))) case _: Block => val docBlock = blk.showAsTree err(msg"Unsupported block: $docBlock") @@ -226,6 +284,6 @@ final class LlirBuilder(tl: TraceLogger)(fresh: Fresh, fnUid: FreshInt): def bProg(e: Program)(using Raise, Scope): LlirProgram = val ctx = Ctx.empty given Ctx = ctx - ctx.def_acc.clear() + ctx.reset val entry = bBlock(e.main)(x => Node.Result(Ls(x))) - LlirProgram(Set.empty, ctx.def_acc.toSet, entry) \ No newline at end of file + LlirProgram(ctx.class_acc.toSet, ctx.def_acc.toSet, entry) \ No newline at end of file diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Llir.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Llir.scala index 0d3a6c3d2f..41606f64d7 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Llir.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Llir.scala @@ -159,7 +159,7 @@ enum Expr: case CtorApp(cls, args) => cls.name <#> "(" <#> (args |> showArguments) <#> ")" case Select(s, cls, fld) => - cls.name <#> "." <#> fld <#> "(" <#> s.toString <#> ")" + s.toString <#> ".<" <#> cls.name <#> ":" <#> fld <#> ">" case BasicOp(name: Str, args) => name <#> "(" <#> (args |> showArguments) <#> ")" case AssignField(assignee, clsInfo, fieldName, value) => @@ -191,7 +191,7 @@ enum Node: case Result(res: Ls[TrivialExpr]) case Jump(func: FuncRef, args: Ls[TrivialExpr]) case Case(scrutinee: TrivialExpr, cases: Ls[(Pat, Node)], default: Opt[Node]) - case Panic + case Panic(msg: Str) // Intermediate forms: case LetExpr(name: Name, expr: Expr, body: Node) case LetMethodCall(names: Ls[Name], cls: ClassRef, method: Name, args: Ls[TrivialExpr], body: Node) @@ -228,7 +228,7 @@ enum Node: case S(dc) => val default = Ls("_" <:> "=>", dc.toDocument |> indent) stack(first, (Document.Stacked(other ++ default) |> indent)) - case Panic => "panic" + case Panic(msg) => "panic" <:> "\"" <#> msg <#> "\"" case LetExpr(x, expr, body) => stack( "let" diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/RefResolver.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/RefResolver.scala index 403d210b23..5b6da3eab9 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/RefResolver.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/RefResolver.scala @@ -43,7 +43,7 @@ private final class RefResolver(defs: Map[Str, Func], classes: Map[Str, ClassInf case None => if !allowInlineJp then throw LowLevelIRError(f"unknown function ${defnref.name} in ${defs.keySet.mkString(",")}") - case Panic => + case Panic(_) => def run(node: Node) = f(node) def run(node: Func) = f(node.body) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Validator.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Validator.scala index 9986835ff4..a660f9f078 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Validator.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Validator.scala @@ -24,7 +24,7 @@ private final class FuncRefInSet(defs: Set[Func], classes: Set[ClassInfo]): case Result(res) => case Jump(func, args) => case Case(x, cases, default) => cases foreach { (_, body) => f(body) }; default foreach f - case Panic => + case Panic(_) => case LetExpr(name, expr, body) => f(body) case LetMethodCall(names, cls, method, args, body) => f(body) case LetCall(res, ref, args, body) => diff --git a/hkmc2/shared/src/test/mlscript/llir/Playground.mls b/hkmc2/shared/src/test/mlscript/llir/Playground.mls index 21519bd151..3126c123e1 100644 --- a/hkmc2/shared/src/test/mlscript/llir/Playground.mls +++ b/hkmc2/shared/src/test/mlscript/llir/Playground.mls @@ -1,5 +1,40 @@ :js +:slot +:llir +abstract class Option[out T]: Some[T] | None +class Some[out T](x: T) extends Option[T] +object None extends Option +fun fromSome(s) = if s is Some(x) then x +//│ Pretty Lowered: +//│ +//│ define class Option in +//│ define class Some in +//│ define class None in +//│ define fun fromSome(s) { +//│ match s +//│ Some => +//│ set param0 = s.x in +//│ set x = param0 in +//│ return x +//│ else +//│ throw new globalThis.Error("match error") +//│ } in +//│ return null +//│ class Option() +//│ class Some(x) +//│ class None() +//│ def fromSome(s) = +//│ case s of +//│ Some => +//│ let x$0 = s. in +//│ x$0 +//│ _ => +//│ panic "match error" +//│ def j$0() = +//│ null +//│ undefined + :llir fun f1() = From c39293de2f70aaf4e2da2a74f05aa0891d59bc5b Mon Sep 17 00:00:00 2001 From: waterlens Date: Wed, 8 Jan 2025 19:06:46 +0800 Subject: [PATCH 04/88] Improve pretty printer --- .../jvm/src/test/scala/hkmc2/LlirDiffMaker.scala | 2 +- .../src/main/scala/hkmc2/codegen/Printer.scala | 15 ++++++++++++++- .../main/scala/hkmc2/codegen/llir/Builder.scala | 6 +++--- .../shared/src/test/mlscript/llir/Playground.mls | 6 +++--- 4 files changed, 21 insertions(+), 8 deletions(-) diff --git a/hkmc2/jvm/src/test/scala/hkmc2/LlirDiffMaker.scala b/hkmc2/jvm/src/test/scala/hkmc2/LlirDiffMaker.scala index 6323c3d1a0..1dd115f2ba 100644 --- a/hkmc2/jvm/src/test/scala/hkmc2/LlirDiffMaker.scala +++ b/hkmc2/jvm/src/test/scala/hkmc2/LlirDiffMaker.scala @@ -12,7 +12,7 @@ import hkmc2.syntax.Tree.Ident import hkmc2.codegen.Path import hkmc2.semantics.Term.Blk import hkmc2.codegen.llir.Fresh -import hkmc2.codegen.js.Scope +import hkmc2.utils.Scope import hkmc2.codegen.llir.Ctx import hkmc2.codegen.llir._ diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Printer.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Printer.scala index b86f008df9..2015624b40 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Printer.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Printer.scala @@ -64,7 +64,20 @@ object Printer: case ValDefn(owner, k, sym, rhs) => doc"val ${sym.nme} = ${mkDocument(rhs)}" case ClsLikeDefn(sym, k, parentSym, methods, privateFields, publicFields, preCtor, ctor) => - doc"class ${sym.nme} #{ #} " + def optFldBody(t: semantics.TermDefinition) = + t.body match + case Some(x) => doc" = ..." + case None => doc"" + val clsDefn = sym.defn.getOrElse(die) + val clsParams = clsDefn.paramsOpt.fold(Nil)(_.paramSyms) + val ctorParams = clsParams.map(p => summon[Scope].allocateName(p)) + val privFields = privateFields.map(x => doc"let ${x.id.name} = ...").mkDocument(sep = doc" # ") + val pubFields = publicFields.map(x => doc"${x.k.str} ${x.sym.nme}${optFldBody(x)}").mkDocument(sep = doc" # ") + val docPrivFlds = if privateFields.isEmpty then doc"" else doc" # ${privFields}" + val docPubFlds = if publicFields.isEmpty then doc"" else doc" # ${pubFields}" + val docBody = if publicFields.isEmpty && privateFields.isEmpty then doc"" else doc" { #{ ${docPrivFlds}${docPubFlds} #} # }" + val docCtorParams = if clsParams.isEmpty then doc"" else doc"(${ctorParams.mkString(", ")})" + doc"class ${sym.nme}${docCtorParams}${docBody}" def mkDocument(arg: Arg)(using Raise, Scope): Document = val doc = mkDocument(arg.value) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala index 33b22034d7..76759b429c 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala @@ -11,7 +11,7 @@ import hkmc2.{Raise, raise, Diagnostic, ErrorReport, Message} import hkmc2.Message.MessageContext import hkmc2.codegen.llir.FuncRef.fromName import scala.collection.mutable.ListBuffer -import hkmc2.codegen.js.Scope +import hkmc2.utils.Scope import hkmc2._ import hkmc2.document._ import hkmc2.semantics.Elaborator.State @@ -131,7 +131,7 @@ final class LlirBuilder(tl: TraceLogger)(fresh: Fresh, fnUid: FreshInt, clsUid: private def bClsLikeDef(e: ClsLikeDefn)(using ctx: Ctx)(using Raise, Scope): ClassInfo = trace[ClassInfo](s"bClsLikeDef begin", x => s"bClsLikeDef end: ${x.show}"): - val ClsLikeDefn(sym, kind, methods, privateFields, publicFields, ctor) = e + val ClsLikeDefn(sym, kind, parentSym, methods, privateFields, publicFields, preCtor, ctor) = e val clsDefn = sym.defn.getOrElse(die) val clsParams = clsDefn.paramsOpt.fold(Nil)(_.paramSyms) ClassInfo( @@ -270,7 +270,7 @@ final class LlirBuilder(tl: TraceLogger)(fresh: Fresh, fnUid: FreshInt, clsUid: ctx.def_acc += f val new_ctx = ctx.addFuncName(sym, Name(f.name)) bBlock(rest)(k)(using new_ctx) - case Define(cd @ ClsLikeDefn(sym, kind, methods, privateFields, publicFields, ctor), rest) => + case Define(cd @ ClsLikeDefn(sym, kind, parentSym, methods, privateFields, publicFields, preCtor, ctor), rest) => val c = bClsLikeDef(cd) ctx.class_acc += c val new_ctx = ctx.addClassName(sym, Name(c.name)) diff --git a/hkmc2/shared/src/test/mlscript/llir/Playground.mls b/hkmc2/shared/src/test/mlscript/llir/Playground.mls index 3126c123e1..667678dad7 100644 --- a/hkmc2/shared/src/test/mlscript/llir/Playground.mls +++ b/hkmc2/shared/src/test/mlscript/llir/Playground.mls @@ -9,14 +9,14 @@ fun fromSome(s) = if s is Some(x) then x //│ Pretty Lowered: //│ //│ define class Option in -//│ define class Some in +//│ define class Some(x) in //│ define class None in //│ define fun fromSome(s) { //│ match s //│ Some => //│ set param0 = s.x in -//│ set x = param0 in -//│ return x +//│ set x1 = param0 in +//│ return x1 //│ else //│ throw new globalThis.Error("match error") //│ } in From a571f82bb268e78fa63d7f9e9004aa47878d46ec Mon Sep 17 00:00:00 2001 From: waterlens Date: Wed, 8 Jan 2025 20:02:41 +0800 Subject: [PATCH 05/88] Add support for ctor app and public fields in the class --- .../scala/hkmc2/codegen/llir/Builder.scala | 24 +++- .../src/test/mlscript/llir/Playground.mls | 121 +++++++++++++++--- 2 files changed, 125 insertions(+), 20 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala index 76759b429c..6602f5845e 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala @@ -20,6 +20,7 @@ import hkmc2.utils.TraceLogger import hkmc2.semantics.TermSymbol import hkmc2.semantics.MemberSymbol import hkmc2.semantics.FieldSymbol +import hkmc2.semantics.TopLevelSymbol def err(msg: Message)(using Raise): Unit = @@ -114,7 +115,7 @@ final class LlirBuilder(tl: TraceLogger)(fresh: Fresh, fnUid: FreshInt, clsUid: case rs: Ls[TrivialExpr] => k(r :: rs) private def bFunDef(e: FunDefn)(using ctx: Ctx)(using Raise, Scope): Func = - trace[Func](s"bFunDef begin", x => s"bFunDef end: ${x.show}"): + trace[Func](s"bFunDef begin: ${e.sym}", x => s"bFunDef end: ${x.show}"): val FunDefn(sym, params, body) = e if params.length != 1 then err(msg"Curried function not supported: ${params.length.toString}") @@ -134,10 +135,11 @@ final class LlirBuilder(tl: TraceLogger)(fresh: Fresh, fnUid: FreshInt, clsUid: val ClsLikeDefn(sym, kind, parentSym, methods, privateFields, publicFields, preCtor, ctor) = e val clsDefn = sym.defn.getOrElse(die) val clsParams = clsDefn.paramsOpt.fold(Nil)(_.paramSyms) + val clsFields = publicFields.map(_.sym) ClassInfo( clsUid.make, sym.nme, - clsParams.map(_.nme) + clsParams.map(_.nme) ++ clsFields.map(_.nme), ) private def bValue(v: Value)(k: TrivialExpr => Ctx ?=> Node)(using ctx: Ctx)(using Raise, Scope) : Node = @@ -158,8 +160,12 @@ final class LlirBuilder(tl: TraceLogger)(fresh: Fresh, fnUid: FreshInt, clsUid: private def bPath(p: Path)(k: TrivialExpr => Ctx ?=> Node)(using ctx: Ctx)(using Raise, Scope) : Node = trace[Node](s"bPath begin", x => s"bPath end: ${x.show}"): p match + case Select(Value.Ref(_: TopLevelSymbol), name) if name.name.head.isUpper => + val v = fresh.make + Node.LetExpr(v, Expr.CtorApp(ClassRef.fromName(name.name), Ls()), k(v |> sr)) + // field selection case s @ Select(qual, name) => - log(s"bPath Select: $qual.$name with ${s.symbol.get}") + log(s"bPath Select: $qual.$name with ${s.symbol}") bPath(qual): case q: Expr.Ref => val v = fresh.make @@ -179,7 +185,17 @@ final class LlirBuilder(tl: TraceLogger)(fresh: Fresh, fnUid: FreshInt, clsUid: case args: Ls[TrivialExpr] => val v = fresh.make Node.LetExpr(v, Expr.BasicOp(sym.nme, args), k(v |> sr)) - case Call(Select(Value.Ref(sym: BuiltinSymbol), name), args) => + case Call(Select(Value.Ref(_: TopLevelSymbol), name), args) if name.name.head.isUpper => + bArgs(args): + case args: Ls[TrivialExpr] => + val v = fresh.make + Node.LetExpr(v, Expr.CtorApp(ClassRef.fromName(name.name), args), k(v |> sr)) + case Call(Select(Value.Ref(_: TopLevelSymbol), name), args) => + bArgs(args): + case args: Ls[TrivialExpr] => + val v = fresh.make + Node.LetCall(Ls(v), FuncRef.fromName(name.name), args, k(v |> sr)) + case Call(Select(Value.Ref(_: BuiltinSymbol), name), args) => bArgs(args): case args: Ls[TrivialExpr] => val v = fresh.make diff --git a/hkmc2/shared/src/test/mlscript/llir/Playground.mls b/hkmc2/shared/src/test/mlscript/llir/Playground.mls index 667678dad7..98709105ef 100644 --- a/hkmc2/shared/src/test/mlscript/llir/Playground.mls +++ b/hkmc2/shared/src/test/mlscript/llir/Playground.mls @@ -1,29 +1,17 @@ :js -:slot :llir abstract class Option[out T]: Some[T] | None class Some[out T](x: T) extends Option[T] object None extends Option fun fromSome(s) = if s is Some(x) then x -//│ Pretty Lowered: -//│ -//│ define class Option in -//│ define class Some(x) in -//│ define class None in -//│ define fun fromSome(s) { -//│ match s -//│ Some => -//│ set param0 = s.x in -//│ set x1 = param0 in -//│ return x1 -//│ else -//│ throw new globalThis.Error("match error") -//│ } in -//│ return null +class Lazy[out A](init: () -> A) with + mut val cache: Option[A] = None +fun lazy(x) = Lazy(x) //│ class Option() //│ class Some(x) //│ class None() +//│ class Lazy(init,cache) //│ def fromSome(s) = //│ case s of //│ Some => @@ -33,8 +21,109 @@ fun fromSome(s) = if s is Some(x) then x //│ panic "match error" //│ def j$0() = //│ null +//│ def lazy(x1) = +//│ let x$1 = Lazy(x1) in +//│ x$1 //│ undefined +:llir +abstract class Option[out T]: Some[T] | None +class Some[out T](x: T) extends Option[T] +object None extends Option +fun fromSome(s) = if s is Some(x) then x +abstract class Nat: S[Nat] | O +class S(s: Nat) extends Nat +object O extends Nat +fun aaa() = + let m = 1 + let n = 2 + let p = 3 + let q = 4 + m + n - p + q +fun bbb() = + let x = aaa() + x * 100 + 4 +fun not(x) = + if x then false else true +fun foo(x) = + if x then None + else Some(foo(not(x))) +fun main() = + let x = foo(false) + if x is + None then aaa() + Some(b1) then bbb() +main() +//│ = 404 +//│ class Option() +//│ class Some(x) +//│ class None() +//│ class Nat() +//│ class S(s) +//│ class O() +//│ def fromSome(s) = +//│ case s of +//│ Some => +//│ let x$0 = s. in +//│ x$0 +//│ _ => +//│ panic "match error" +//│ def j$0() = +//│ null +//│ def aaa() = +//│ let x$1 = 1 in +//│ let x$2 = 2 in +//│ let x$3 = 3 in +//│ let x$4 = 4 in +//│ let x$5 = +(x$1,x$2) in +//│ let x$6 = -(x$5,x$3) in +//│ let x$7 = +(x$6,x$4) in +//│ x$7 +//│ def bbb() = +//│ let* (x$8) = aaa() in +//│ let x$9 = *(x$8,100) in +//│ let x$10 = +(x$9,4) in +//│ x$10 +//│ def not(x2) = +//│ case x2 of +//│ BoolLit(true) => +//│ false +//│ _ => +//│ true +//│ def j$1() = +//│ null +//│ def foo(x3) = +//│ case x3 of +//│ BoolLit(true) => +//│ let x$11 = None() in +//│ x$11 +//│ _ => +//│ let* (x$12) = not(x3) in +//│ let* (x$13) = foo(x$12) in +//│ let x$14 = Some(x$13) in +//│ x$14 +//│ def j$2() = +//│ null +//│ def main() = +//│ let* (x$15) = foo(false) in +//│ case x$15 of +//│ None => +//│ let* (x$16) = aaa() in +//│ x$16 +//│ _ => +//│ case x$15 of +//│ Some => +//│ let x$17 = x$15. in +//│ let* (x$18) = bbb() in +//│ x$18 +//│ _ => +//│ panic "match error" +//│ def j$4() = +//│ jump j$3() +//│ def j$3() = +//│ null +//│ let* (x$19) = main() in +//│ x$19 :llir fun f1() = From b1896825d729d3cb130c18515ef9cc5c42476ebc Mon Sep 17 00:00:00 2001 From: waterlens Date: Thu, 9 Jan 2025 20:11:04 +0800 Subject: [PATCH 06/88] Add options for cpp backend --- hkmc2/jvm/src/test/scala/hkmc2/LlirDiffMaker.scala | 7 ++++++- .../src/main/scala/hkmc2/codegen/cpp/CodeGen.scala | 13 +++++++------ hkmc2/shared/src/test/mlscript/llir/Playground.mls | 7 +++++++ 3 files changed, 20 insertions(+), 7 deletions(-) diff --git a/hkmc2/jvm/src/test/scala/hkmc2/LlirDiffMaker.scala b/hkmc2/jvm/src/test/scala/hkmc2/LlirDiffMaker.scala index 1dd115f2ba..0f02bd2550 100644 --- a/hkmc2/jvm/src/test/scala/hkmc2/LlirDiffMaker.scala +++ b/hkmc2/jvm/src/test/scala/hkmc2/LlirDiffMaker.scala @@ -18,6 +18,7 @@ import hkmc2.codegen.llir._ abstract class LlirDiffMaker extends BbmlDiffMaker: val llir = NullaryCommand("llir") + val scpp = NullaryCommand("scpp") override def processTerm(trm: Blk, inImport: Bool)(using Raise): Unit = super.processTerm(trm, inImport) @@ -32,5 +33,9 @@ abstract class LlirDiffMaker extends BbmlDiffMaker: val llb = LlirBuilder(tl)(fresh, fuid, cuid) given Ctx = Ctx.empty val llirProg = llb.bProg(le) + output("LLIR:") output(llirProg.show()) - \ No newline at end of file + if scpp.isSet then + val cpp = codegen.cpp.CppCodeGen.codegen(llirProg) + output("\nCpp:") + output(cpp.toDocument.print) \ No newline at end of file diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/CodeGen.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/CodeGen.scala index 81501fe2df..80f83ae7c3 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/CodeGen.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/CodeGen.scala @@ -7,11 +7,7 @@ import scala.collection.mutable.ListBuffer import hkmc2.codegen.llir.{Expr => IExpr, _} import hkmc2.codegen.cpp._ -def codegen(prog: Program): CompilationUnit = - val codegen = CppCodeGen() - codegen.codegen(prog) - -private class CppCodeGen: +object CppCodeGen: def mapName(name: Name): Str = "_mls_" + name.str.replace('$', '_').replace('\'', '_') def mapName(name: Str): Str = "_mls_" + name.replace('$', '_').replace('\'', '_') val freshName = Fresh(div = '_'); @@ -31,6 +27,7 @@ private class CppCodeGen: def mlsCharLit(x: Char) = Expr.Call(Expr.Var("_mlsValue::fromIntLit"), Ls(Expr.CharLit(x))) def mlsNewValue(cls: Str, args: Ls[Expr]) = Expr.Call(Expr.Var(s"_mlsValue::create<$cls>"), args) def mlsIsValueOf(cls: Str, scrut: Expr) = Expr.Call(Expr.Var(s"_mlsValue::isValueOf<$cls>"), Ls(scrut)) + def mlsIsBoolLit(scrut: Expr, lit: hkmc2.syntax.Tree.BoolLit) = Expr.Call(Expr.Var("_mlsValue::isIntLit"), Ls(scrut, Expr.IntLit(if lit.value then 1 else 0))) def mlsIsIntLit(scrut: Expr, lit: hkmc2.syntax.Tree.IntLit) = Expr.Call(Expr.Var("_mlsValue::isIntLit"), Ls(scrut, Expr.IntLit(lit.value))) def mlsDebugPrint(x: Expr) = Expr.Call(Expr.Var("_mlsValue::print"), Ls(x)) def mlsTupleValue(init: Expr) = Expr.Constructor("_mlsValue::tuple", init) @@ -124,6 +121,10 @@ private class CppCodeGen: val (decls2, stmts2) = codegen(arm, storeInto)(using Ls.empty, Ls.empty[Stmt]) val stmt = Stmt.If(mlsIsIntLit(scrut2, i), Stmt.Block(decls2, stmts2), nextarm) S(stmt) + case ((Pat.Lit(i @ hkmc2.syntax.Tree.BoolLit(_)), arm), nextarm) => + val (decls2, stmts2) = codegen(arm, storeInto)(using Ls.empty, Ls.empty[Stmt]) + val stmt = Stmt.If(mlsIsBoolLit(scrut2, i), Stmt.Block(decls2, stmts2), nextarm) + S(stmt) case _ => ??? } (decls, stmt.fold(stmts)(x => stmts :+ x)) @@ -169,7 +170,7 @@ private class CppCodeGen: (decls, stmts2) case Node.Jump(defn, args) => codegenJumpWithCall(defn, args, S(storeInto)) - case Node.Panic => (decls, stmts :+ Stmt.Raw("throw std::runtime_error(\"Panic\");")) + case Node.Panic(msg) => (decls, stmts :+ Stmt.Raw(s"throw std::runtime_error(\"$msg\");")) case Node.LetExpr(name, expr, body) => val stmts2 = stmts ++ Ls(Stmt.AutoBind(Ls(name |> mapName), codegen(expr))) codegen(body, storeInto)(using decls, stmts2) diff --git a/hkmc2/shared/src/test/mlscript/llir/Playground.mls b/hkmc2/shared/src/test/mlscript/llir/Playground.mls index 98709105ef..f10edeb6e4 100644 --- a/hkmc2/shared/src/test/mlscript/llir/Playground.mls +++ b/hkmc2/shared/src/test/mlscript/llir/Playground.mls @@ -8,6 +8,7 @@ fun fromSome(s) = if s is Some(x) then x class Lazy[out A](init: () -> A) with mut val cache: Option[A] = None fun lazy(x) = Lazy(x) +//│ LLIR: //│ class Option() //│ class Some(x) //│ class None() @@ -55,6 +56,7 @@ fun main() = Some(b1) then bbb() main() //│ = 404 +//│ LLIR: //│ class Option() //│ class Some(x) //│ class None() @@ -130,6 +132,7 @@ fun f1() = let x = 1 let x = 2 x +//│ LLIR: //│ //│ def f1() = //│ let x$0 = 1 in @@ -144,6 +147,7 @@ fun f2() = if x == 1 then 2 else 3 //│ Pretty Lowered: //│ define fun f2() { set x = 0 in set scrut = ==(x, 1) in match scrut true => return 2 else return 3 } in return null +//│ LLIR: //│ //│ def f2() = //│ let x$0 = 0 in @@ -176,6 +180,7 @@ fun f3() = //│ return x2 //│ } in //│ return null +//│ LLIR: //│ //│ def f3() = //│ let x$0 = 0 in @@ -214,6 +219,7 @@ fun f4() = //│ return x1 //│ } in //│ return null +//│ LLIR: //│ //│ def f4() = //│ let x$0 = 0 in @@ -263,6 +269,7 @@ fun f5() = //│ return x2 //│ } in //│ return null +//│ LLIR: //│ //│ def f5() = //│ let x$0 = 0 in From b124738be4ad21c7dc9f82e32f8d7027afef1afb Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Fri, 10 Jan 2025 12:31:44 +0800 Subject: [PATCH 07/88] Minor improvements from meeting --- .../scala/hkmc2/codegen/llir/Builder.scala | 35 ++++++------- .../src/test/mlscript/llir/BadPrograms.mls | 50 +++++++++++++++++++ .../src/test/mlscript/llir/Playground.mls | 36 +++++++++++++ 3 files changed, 101 insertions(+), 20 deletions(-) create mode 100644 hkmc2/shared/src/test/mlscript/llir/BadPrograms.mls diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala index 6602f5845e..8c55ea6d4e 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala @@ -1,38 +1,33 @@ package hkmc2 -package codegen.llir +package codegen +package llir -import hkmc2.codegen._ -import hkmc2.codegen.llir.{ Program => LlirProgram, Node, Func } -import mlscript.utils._ -import mlscript.utils.shorthands._ -import hkmc2.semantics.BuiltinSymbol -import hkmc2.syntax.Tree -import hkmc2.{Raise, raise, Diagnostic, ErrorReport, Message} -import hkmc2.Message.MessageContext -import hkmc2.codegen.llir.FuncRef.fromName import scala.collection.mutable.ListBuffer + +import mlscript.utils.* +import mlscript.utils.shorthands.* +import hkmc2.document.* import hkmc2.utils.Scope -import hkmc2._ -import hkmc2.document._ -import hkmc2.semantics.Elaborator.State -import hkmc2.codegen.Program import hkmc2.utils.TraceLogger -import hkmc2.semantics.TermSymbol -import hkmc2.semantics.MemberSymbol -import hkmc2.semantics.FieldSymbol -import hkmc2.semantics.TopLevelSymbol +import hkmc2.Message.MessageContext + +import hkmc2.syntax.Tree +import hkmc2.semantics.* +import hkmc2.codegen.llir.{ Program => LlirProgram, Node, Func } +import FuncRef.fromName +import hkmc2.codegen.Program def err(msg: Message)(using Raise): Unit = raise(ErrorReport(msg -> N :: Nil, - source = Diagnostic.Source.Compilation)) + source = Diagnostic.Source.Compilation)) final case class Ctx( def_acc: ListBuffer[Func], class_acc: ListBuffer[ClassInfo], symbol_ctx: Map[Str, Name] = Map.empty, fn_ctx: Map[Local, Name] = Map.empty, // is a known function - closure_ctx: Map[Local, Name] = Map.empty, // closure name + closure_ctx: Map[Local, Name] = Map.empty, // closure name // TODO remove – not needed? class_ctx: Map[Local, Name] = Map.empty, block_ctx: Map[Local, Name] = Map.empty, ): diff --git a/hkmc2/shared/src/test/mlscript/llir/BadPrograms.mls b/hkmc2/shared/src/test/mlscript/llir/BadPrograms.mls new file mode 100644 index 0000000000..1424a04f4b --- /dev/null +++ b/hkmc2/shared/src/test/mlscript/llir/BadPrograms.mls @@ -0,0 +1,50 @@ + +:global +:llir +:scpp + + +// TODO should be rejected +fun oops(a) = + class A with + fun m = a + let x = 1 +//│ LLIR: +//│ class A() +//│ def oops(a) = +//│ let x$0 = 1 in +//│ undefined +//│ undefined +//│ +//│ Cpp: +//│ #include "mlsprelude.h" +//│ struct _mls_A; +//│ _mlsValue _mls_oops(_mlsValue); +//│ _mlsValue _mlsMain(); +//│ struct _mls_A: public _mlsObject { +//│ +//│ constexpr static inline const char *typeName = "A"; +//│ constexpr static inline uint32_t typeTag = nextTypeTag(); +//│ virtual void print() const override { std::printf("%s", typeName); } +//│ virtual void destroy() override { operator delete (this, std::align_val_t(_mlsAlignment)); } +//│ static _mlsValue create() { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) _mls_A; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; return _mlsValue(_mlsVal); } +//│ }; +//│ _mlsValue _mls_oops(_mlsValue _mls_a){ +//│ _mlsValue _mls_retval; +//│ auto _mls_x_0 = _mlsValue::fromIntLit(1); +//│ _mls_retval = _mlsValue::create<_mls_Unit>(); +//│ return _mls_retval; +//│ } +//│ _mlsValue _mlsMain(){ +//│ _mlsValue _mls_retval; +//│ _mls_retval = _mlsValue::create<_mls_Unit>(); +//│ return _mls_retval; +//│ } +//│ int main() { return _mlsLargeStack(_mlsMainWrapper); } + +:todo // Properly reject +let x = "oops" +x.m +//│ /!!!\ Uncaught error: java.util.NoSuchElementException: None.get + + diff --git a/hkmc2/shared/src/test/mlscript/llir/Playground.mls b/hkmc2/shared/src/test/mlscript/llir/Playground.mls index f10edeb6e4..7c3e50a951 100644 --- a/hkmc2/shared/src/test/mlscript/llir/Playground.mls +++ b/hkmc2/shared/src/test/mlscript/llir/Playground.mls @@ -293,3 +293,39 @@ fun f5() = //│ def j$1(x$6) = //│ x$6 //│ undefined + +:llir +fun test() = + if true do test() +//│ LLIR: +//│ +//│ def test() = +//│ let x$0 = true in +//│ case x$0 of +//│ BoolLit(true) => +//│ let* (x$1) = test() in +//│ x$1 +//│ _ => +//│ undefined +//│ def j$0() = +//│ null +//│ undefined + +:llir +fun test() = + (if true then test()) + 1 +//│ LLIR: +//│ +//│ def test() = +//│ let x$0 = true in +//│ case x$0 of +//│ BoolLit(true) => +//│ let* (x$2) = test() in +//│ jump j$0(x$2) +//│ _ => +//│ panic "match error" +//│ def j$0(x$1) = +//│ let x$3 = +(x$1,1) in +//│ x$3 +//│ undefined + From 2501860eb20142252713cb5761496a4c3d5fc86b Mon Sep 17 00:00:00 2001 From: waterlens Date: Tue, 14 Jan 2025 14:17:04 +0800 Subject: [PATCH 08/88] Fill blank lines --- hkmc2/jvm/src/test/scala/hkmc2/DiffTestRunner.scala | 3 +++ 1 file changed, 3 insertions(+) diff --git a/hkmc2/jvm/src/test/scala/hkmc2/DiffTestRunner.scala b/hkmc2/jvm/src/test/scala/hkmc2/DiffTestRunner.scala index 8f3c28405e..9dcc0d903f 100644 --- a/hkmc2/jvm/src/test/scala/hkmc2/DiffTestRunner.scala +++ b/hkmc2/jvm/src/test/scala/hkmc2/DiffTestRunner.scala @@ -12,6 +12,9 @@ import mlscript.utils._, shorthands._ class MainDiffMaker(val rootPath: Str, val file: os.Path, val preludeFile: os.Path, val predefFile: os.Path, val relativeName: Str) extends LlirDiffMaker + + + class AllTests extends org.scalatest.Suites( new CompileTestRunner(DiffTestRunner.State){}, new DiffTestRunner(DiffTestRunner.State){}, From 42cffaa5d0abaf0a432bb10e50d902be64ab456b Mon Sep 17 00:00:00 2001 From: waterlens Date: Tue, 14 Jan 2025 14:18:02 +0800 Subject: [PATCH 09/88] Remove the extra blank line --- hkmc2/jvm/src/test/scala/hkmc2/DiffTestRunner.scala | 1 - 1 file changed, 1 deletion(-) diff --git a/hkmc2/jvm/src/test/scala/hkmc2/DiffTestRunner.scala b/hkmc2/jvm/src/test/scala/hkmc2/DiffTestRunner.scala index 9dcc0d903f..5d770db337 100644 --- a/hkmc2/jvm/src/test/scala/hkmc2/DiffTestRunner.scala +++ b/hkmc2/jvm/src/test/scala/hkmc2/DiffTestRunner.scala @@ -14,7 +14,6 @@ class MainDiffMaker(val rootPath: Str, val file: os.Path, val preludeFile: os.Pa - class AllTests extends org.scalatest.Suites( new CompileTestRunner(DiffTestRunner.State){}, new DiffTestRunner(DiffTestRunner.State){}, From 8ba879e05b2c1e38f538a17dfa8764a8ab5e7849 Mon Sep 17 00:00:00 2001 From: waterlens Date: Tue, 14 Jan 2025 14:23:20 +0800 Subject: [PATCH 10/88] Remove unused context --- hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala | 1 - 1 file changed, 1 deletion(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala index 8c55ea6d4e..3dcf41e476 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala @@ -27,7 +27,6 @@ final case class Ctx( class_acc: ListBuffer[ClassInfo], symbol_ctx: Map[Str, Name] = Map.empty, fn_ctx: Map[Local, Name] = Map.empty, // is a known function - closure_ctx: Map[Local, Name] = Map.empty, // closure name // TODO remove – not needed? class_ctx: Map[Local, Name] = Map.empty, block_ctx: Map[Local, Name] = Map.empty, ): From f577445a09a0f28a0fc84ab22fe24fbdc7710fa9 Mon Sep 17 00:00:00 2001 From: waterlens Date: Tue, 14 Jan 2025 14:32:40 +0800 Subject: [PATCH 11/88] Add trailing newlines at the end of files --- hkmc2/jvm/src/test/scala/hkmc2/LlirDiffMaker.scala | 2 +- hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/Ast.scala | 2 +- hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/hkmc2/jvm/src/test/scala/hkmc2/LlirDiffMaker.scala b/hkmc2/jvm/src/test/scala/hkmc2/LlirDiffMaker.scala index 0f02bd2550..858b307024 100644 --- a/hkmc2/jvm/src/test/scala/hkmc2/LlirDiffMaker.scala +++ b/hkmc2/jvm/src/test/scala/hkmc2/LlirDiffMaker.scala @@ -38,4 +38,4 @@ abstract class LlirDiffMaker extends BbmlDiffMaker: if scpp.isSet then val cpp = codegen.cpp.CppCodeGen.codegen(llirProg) output("\nCpp:") - output(cpp.toDocument.print) \ No newline at end of file + output(cpp.toDocument.print) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/Ast.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/Ast.scala index 94787c2fa0..ea46ea07b4 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/Ast.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/Ast.scala @@ -209,4 +209,4 @@ enum Def: case VarDef(typ, name, init) => typ.toDocument() <#> s" $name" <#> init.fold(raw(""))(x => " = " <#> x.toDocument) <#> raw(";") case RawDef(x) => x - aux(this) \ No newline at end of file + aux(this) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala index 3dcf41e476..4153065fa5 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala @@ -296,4 +296,4 @@ final class LlirBuilder(tl: TraceLogger)(fresh: Fresh, fnUid: FreshInt, clsUid: given Ctx = ctx ctx.reset val entry = bBlock(e.main)(x => Node.Result(Ls(x))) - LlirProgram(ctx.class_acc.toSet, ctx.def_acc.toSet, entry) \ No newline at end of file + LlirProgram(ctx.class_acc.toSet, ctx.def_acc.toSet, entry) From 6dc013031ab5819c20db32d3ffa54c7c64f22138 Mon Sep 17 00:00:00 2001 From: waterlens Date: Tue, 14 Jan 2025 16:45:55 +0800 Subject: [PATCH 12/88] Use new pretty printer --- .../src/test/scala/hkmc2/LlirDiffMaker.scala | 2 +- .../main/scala/hkmc2/codegen/cpp/Ast.scala | 162 +++++++++--------- .../main/scala/hkmc2/codegen/llir/Llir.scala | 130 +++++--------- .../hkmc2/utils/document/LegacyDocument.scala | 52 ------ .../src/test/mlscript/llir/BadPrograms.mls | 6 +- .../src/test/mlscript/llir/Playground.mls | 14 +- 6 files changed, 135 insertions(+), 231 deletions(-) delete mode 100644 hkmc2/shared/src/main/scala/hkmc2/utils/document/LegacyDocument.scala diff --git a/hkmc2/jvm/src/test/scala/hkmc2/LlirDiffMaker.scala b/hkmc2/jvm/src/test/scala/hkmc2/LlirDiffMaker.scala index 858b307024..08c480cf78 100644 --- a/hkmc2/jvm/src/test/scala/hkmc2/LlirDiffMaker.scala +++ b/hkmc2/jvm/src/test/scala/hkmc2/LlirDiffMaker.scala @@ -38,4 +38,4 @@ abstract class LlirDiffMaker extends BbmlDiffMaker: if scpp.isSet then val cpp = codegen.cpp.CppCodeGen.codegen(llirProg) output("\nCpp:") - output(cpp.toDocument.print) + output(cpp.toDocument.toString) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/Ast.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/Ast.scala index ea46ea07b4..c05e4f1d3e 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/Ast.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/Ast.scala @@ -4,42 +4,33 @@ import mlscript._ import mlscript.utils._ import mlscript.utils.shorthands._ -import hkmc2.utils.legacy_document._ +import hkmc2.Message.MessageContext +import hkmc2.document._ import scala.language.implicitConversions -given Conversion[String, Document] = raw +private def raw(x: String): Document = doc"$x" +given Conversion[String, Document] = x => doc"$x" enum Specifier: case Extern case Static case Inline - def toDocument = raw( + def toDocument = this match case Extern => "extern" case Static => "static" case Inline => "inline" - ) - override def toString: Str = toDocument.print + override def toString: Str = toDocument object Type: def toDocuments(args: Ls[Type], sep: Document, extraTypename: Bool = false): Document = - args.iterator.zipWithIndex.map { - case (x, 0) => - x.toDocument(extraTypename) - case (x, _) => - sep <#> x.toDocument(extraTypename) - }.fold(raw(""))(_ <#> _) + args.map(_.toDocument(extraTypename)).mkDocument(sep) def toDocuments(args: Ls[(Str, Type)], sep: Document): Document = - args.iterator.zipWithIndex.map { - case (x, 0) => - x._2.toDocument() <:> raw(x._1) - case (x, _) => - sep <#> x._2.toDocument() <:> raw(x._1) - }.fold(raw(""))(_ <#> _) + args.map(x => doc"${x._2.toDocument()} ${x._1}").mkDocument(sep) enum Type: case Prim(name: Str) @@ -56,22 +47,25 @@ enum Type: def toDocument(extraTypename: Bool = false): Document = def aux(x: Type): Document = x match case Prim(name) => name - case Ptr(inner) => aux(inner) <#> "*" - case Ref(inner) => aux(inner) <#> "&" - case Array(inner, size) => aux(inner) <#> "[" <#> size.fold(raw(""))(x => x.toString) <#> "]" - case FuncPtr(ret, args) => aux(ret) <#> "(" <#> Type.toDocuments(args, sep = ", ") <#> ")" - case Struct(name) => s"struct $name" - case Enum(name) => s"enum $name" - case Template(name, args) => s"$name" <#> "<" <#> Type.toDocuments(args, sep = ", ") <#> ">" + case Ptr(inner) => doc"${aux(inner)}*" + case Ref(inner) => doc"${aux(inner)}&" + case Array(inner, size) => + doc"${aux(inner)}[${size.fold("")(x => x.toString)}]" + case FuncPtr(ret, args) => + doc"${aux(ret)}(${Type.toDocuments(args, sep = ", ")})" + case Struct(name) => doc"struct $name" + case Enum(name) => doc"enum $name" + case Template(name, args) => + doc"$name<${Type.toDocuments(args, sep = ", ")}>" case Var(name) => name - case Qualifier(inner, qual) => aux(inner) <:> qual + case Qualifier(inner, qual) => doc"${aux(inner)} $qual" aux(this) - override def toString: Str = toDocument().print + override def toString: Str = toDocument().toString object Stmt: def toDocuments(decl: Ls[Decl], stmts: Ls[Stmt]): Document = - stack_list(decl.map(_.toDocument) ++ stmts.map(_.toDocument)) + (decl.map(_.toDocument) ++ stmts.map(_.toDocument)).mkDocument(doc" # ") enum Stmt: case AutoBind(lhs: Ls[Str], rhs: Expr) @@ -92,38 +86,37 @@ enum Stmt: case AutoBind(lhs, rhs) => lhs match case Nil => rhs.toDocument - case x :: Nil => "auto" <:> x <:> "=" <:> rhs.toDocument <#> ";" - case _ => "auto" <:> lhs.mkString("[", ",", "]") <:> "=" <:> rhs.toDocument <#> ";" - case Assign(lhs, rhs) => lhs <#> " = " <#> rhs.toDocument <#> ";" - case Return(expr) => "return " <#> expr.toDocument <#> ";" + case x :: Nil => + doc"auto $x = ${rhs.toDocument};" + case _ => + doc"auto [${lhs.mkDocument(", ")}] = ${rhs.toDocument};" + case Assign(lhs, rhs) => + doc"$lhs = ${rhs.toDocument};" + case Return(expr) => + doc"return ${expr.toDocument};" case If(cond, thenStmt, elseStmt) => - "if (" <#> cond.toDocument <#> ")" <#> thenStmt.toDocument <:> elseStmt.fold(raw(""))(x => "else" <:> x.toDocument) + doc"if (${cond.toDocument}) ${thenStmt.toDocument}${elseStmt.fold(doc" ")(x => doc" else ${x.toDocument}")}" case While(cond, body) => - "while (" <#> cond.toDocument <#> ")" <#> body.toDocument + doc"while (${cond.toDocument}) ${body.toDocument}" case For(init, cond, update, body) => - "for (" <#> init.toDocument <#> "; " <#> cond.toDocument <#> "; " <#> update.toDocument <#> ")" <#> body.toDocument - case ExprStmt(expr) => expr.toDocument <#> ";" + doc"for (${init.toDocument}; ${cond.toDocument}; ${update.toDocument}) ${body.toDocument}" + case ExprStmt(expr) => + doc"${expr.toDocument};" case Break => "break;" case Continue => "continue;" case Block(decl, stmts) => - stack( - "{", - Stmt.toDocuments(decl, stmts) |> indent, - "}") + doc"{ #{ # ${Stmt.toDocuments(decl, stmts)} #} # }" case Switch(expr, cases) => - "switch (" <#> expr.toDocument <#> ")" <#> "{" <#> stack_list(cases.map { - case (cond, stmt) => "case " <#> cond.toDocument <#> ":" <#> stmt.toDocument - }) <#> "}" + val docCases = cases.map { + case (cond, stmt) => doc"case ${cond.toDocument}: ${stmt.toDocument}" + }.mkDocument(doc" # ") + doc"switch (${expr.toDocument}) { #{ # ${docCases} #} # }" case Raw(stmt) => stmt aux(this) object Expr: def toDocuments(args: Ls[Expr], sep: Document): Document = - args.zipWithIndex.map { - case (x, i) => - if i == 0 then x.toDocument - else sep <#> x.toDocument - }.fold(raw(""))(_ <#> _) + args.map(_.toDocument).mkDocument(sep) enum Expr: case Var(name: Str) @@ -146,26 +139,31 @@ enum Expr: case DoubleLit(value) => value.toString case StrLit(value) => s"\"$value\"" // need more reliable escape utils case CharLit(value) => value.toInt.toString - case Call(func, args) => aux(func) <#> "(" <#> Expr.toDocuments(args, sep = ", ") <#> ")" - case Member(expr, member) => aux(expr) <#> "->" <#> member - case Index(expr, index) => aux(expr) <#> "[" <#> aux(index) <#> "]" - case Unary(op, expr) => "(" <#> op <#> aux(expr) <#> ")" - case Binary(op, lhs, rhs) => "(" <#> aux(lhs) <#> op <#> aux(rhs) <#> ")" - case Initializer(exprs) => "{" <#> Expr.toDocuments(exprs, sep = ", ") <#> "}" - case Constructor(name, init) => name <#> init.toDocument + case Call(func, args) => + doc"${func.toDocument}(${Expr.toDocuments(args, sep = ", ")})" + case Member(expr, member) => + doc"${expr.toDocument}->$member" + case Index(expr, index) => + doc"${expr.toDocument}[${index.toDocument}]" + case Unary(op, expr) => + doc"($op${expr.toDocument})" + case Binary(op, lhs, rhs) => + doc"(${lhs.toDocument} $op ${rhs.toDocument})" + case Initializer(exprs) => + doc"{${Expr.toDocuments(exprs, sep = ", ")}}" + case Constructor(name, init) => + doc"$name(${init.toDocument})" aux(this) case class CompilationUnit(includes: Ls[Str], decls: Ls[Decl], defs: Ls[Def]): def toDocument: Document = - stack_list(includes.map(x => raw(x)) ++ decls.map(_.toDocument) ++ defs.map(_.toDocument)) + (includes.map(raw) ++ decls.map(_.toDocument) ++ defs.map(_.toDocument)).mkDocument(doc" # ") def toDocumentWithoutHidden: Document = - val hiddenNames = Set( - "HiddenTheseEntities", "True", "False", "Callable", "List", "Cons", "Nil", "Option", "Some", "None", "Pair", "Tuple2", "Tuple3", "Nat", "S", "O" - ) - stack_list(defs.filterNot { + val hiddenNames: Set[Str] = Set() + defs.filterNot { case Def.StructDef(name, _, _, _) => hiddenNames.contains(name.stripPrefix("_mls_")) case _ => false - }.map(_.toDocument)) + }.map(_.toDocument).mkDocument(doc" # ") enum Decl: case StructDecl(name: Str) @@ -175,10 +173,12 @@ enum Decl: def toDocument: Document = def aux(x: Decl): Document = x match - case StructDecl(name) => s"struct $name;" - case EnumDecl(name) => s"enum $name;" - case FuncDecl(ret, name, args) => ret.toDocument() <#> s" $name(" <#> Type.toDocuments(args, sep = ", ") <#> ");" - case VarDecl(name, typ) => typ.toDocument() <#> s" $name;" + case StructDecl(name) => doc"struct $name;" + case EnumDecl(name) => doc"enum $name;" + case FuncDecl(ret, name, args) => + doc"${ret.toDocument()} $name(${Type.toDocuments(args, sep = ", ")});" + case VarDecl(name, typ) => + doc"${typ.toDocument()} $name;" aux(this) enum Def: @@ -191,22 +191,30 @@ enum Def: def toDocument: Document = def aux(x: Def): Document = x match case StructDef(name, fields, inherit, defs) => - stack( - s"struct $name" <#> (if inherit.nonEmpty then ": public" <:> inherit.get.mkString(", ") else "" ) <:> "{", - stack_list(fields.map { - case (name, typ) => typ.toDocument() <#> " " <#> name <#> ";" - }) |> indent, - stack_list(defs.map(_.toDocument)) |> indent, - "};" - ) + val docFirst = doc"struct $name${inherit.fold(doc"")(x => doc": public ${x.mkDocument(doc", ")}")} {" + val docFields = fields.map { + case (name, typ) => doc"${typ.toDocument()} $name;" + }.mkDocument(doc" # ") + val docDefs = defs.map(_.toDocument).mkDocument(doc" # ") + val docLast = "};" + doc"$docFirst #{ # $docFields # $docDefs #} # $docLast" case EnumDef(name, fields) => - s"enum $name" <:> "{" <#> stack_list(fields.map { + val docFirst = doc"enum $name {" + val docFields = fields.map { case (name, value) => value.fold(s"$name")(x => s"$name = $x") - }) <#> "};" + }.mkDocument(doc" # ") + val docLast = "};" + doc"$docFirst #{ # $docFields #} # $docLast" case FuncDef(specret, name, args, body, or, virt) => - (if virt then "virtual " else "") - <#> specret.toDocument() <#> s" $name(" <#> Type.toDocuments(args, sep = ", ") <#> ")" <#> (if or then " override" else "") <#> body.toDocument + val docVirt = (if virt then doc"virtual " else doc"") + val docSpecRet = specret.toDocument() + val docArgs = Type.toDocuments(args, sep = ", ") + val docOverride = if or then doc" override" else doc"" + val docBody = body.toDocument + doc"$docVirt$docSpecRet $name($docArgs)$docOverride ${body.toDocument}" case VarDef(typ, name, init) => - typ.toDocument() <#> s" $name" <#> init.fold(raw(""))(x => " = " <#> x.toDocument) <#> raw(";") + val docTyp = typ.toDocument() + val docInit = init.fold(raw(""))(x => doc" = ${x.toDocument}") + doc"$docTyp $name$docInit;" case RawDef(x) => x aux(this) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Llir.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Llir.scala index 41606f64d7..72be21209b 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Llir.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Llir.scala @@ -4,14 +4,17 @@ import mlscript._ import mlscript.utils._ import mlscript.utils.shorthands._ -import hkmc2.utils.legacy_document._ import hkmc2.syntax._ +import hkmc2.Message.MessageContext +import hkmc2.document._ import util.Sorting import collection.immutable.SortedSet import language.implicitConversions import collection.mutable.{Map as MutMap, Set as MutSet, HashMap, ListBuffer} +private def raw(x: String): Document = doc"$x" + final case class LowLevelIRError(message: String) extends Exception(message) case class Program( @@ -26,18 +29,17 @@ case class Program( Sorting.quickSort(t2) s"Program({${t1.mkString(",\n")}}, {\n${t2.mkString("\n")}\n},\n$main)" - def show(hiddenNames: Set[Str] = Set.empty) = toDocument(hiddenNames).print + def show(hiddenNames: Set[Str] = Set.empty) = toDocument(hiddenNames).toString def toDocument(hiddenNames: Set[Str] = Set.empty) : Document = val t1 = classes.toArray val t2 = defs.toArray Sorting.quickSort(t1) Sorting.quickSort(t2) given Conversion[String, Document] = raw - stack( - stack_list(t1.filter(x => !hiddenNames.contains(x.name)).map(_.toDocument).toList) |> indent, - stack_list(t2.map(_.toDocument).toList) |> indent, - main.toDocument |> indent - ) + val docClasses = t1.filter(x => !hiddenNames.contains(x.name)).map(_.toDocument).toList.mkDocument(doc" # ") + val docDefs = t2.map(_.toDocument).toList.mkDocument(doc" # ") + val docMain = main.toDocument + doc" #{ $docClasses\n$docDefs\n$docMain #} " implicit object ClassInfoOrdering extends Ordering[ClassInfo] { def compare(a: ClassInfo, b: ClassInfo) = a.id.compare(b.id) @@ -54,18 +56,17 @@ case class ClassInfo( override def toString: String = s"ClassInfo($id, $name, [${fields mkString ","}], parents: ${parents mkString ","}, methods:\n${methods mkString ",\n"})" - def show = toDocument.print + def show = toDocument.toString def toDocument: Document = given Conversion[String, Document] = raw - val extension = if parents.isEmpty then "" else " extends " + parents.mkString(", ") + val ext = if parents.isEmpty then "" else " extends " + parents.mkString(", ") if methods.isEmpty then - "class" <:> name <#> "(" <#> fields.mkString(",") <#> ")" <#> extension + doc"class $name(${fields.mkString(",")})$ext" else - stack( - "class" <:> name <#> "(" <#> fields.mkString(",") <#> ")" <#> extension <:> "{", - stack_list( methods.map { (_, func) => func.toDocument |> indent }.toList), - "}" - ) + val docFirst = doc"class $name (${fields.mkString(",")})$ext {" + val docMethods = methods.map { (_, func) => func.toDocument }.toList.mkDocument(doc" # ") + val docLast = doc"}" + doc"$docFirst #{ # $docMethods # #} $docLast" case class Name(str: Str): def trySubst(map: Map[Str, Name]) = map.getOrElse(str, this) @@ -117,13 +118,12 @@ case class Func( val ps = params.map(_.toString).mkString("[", ",", "]") s"Def($id, $name, $ps, \n$resultNum, \n$body\n)" - def show = toDocument.print + def show = toDocument def toDocument: Document = given Conversion[String, Document] = raw - stack( - "def" <:> name <#> "(" <#> params.map(_.toString).mkString(",") <#> ")" <:> "=", - body.toDocument |> indent - ) + val docFirst = doc"def $name(${params.map(_.toString).mkString(",")}) =" + val docBody = body.toDocument + doc"$docFirst #{ # $docBody #} " sealed trait TrivialExpr: import Expr._ @@ -144,8 +144,7 @@ enum Expr: override def toString: String = show - def show: String = - toDocument.print + def show: String = toDocument.toString def toDocument: Document = given Conversion[String, Document] = raw @@ -157,31 +156,18 @@ enum Expr: case Literal(Tree.StrLit(lit)) => s"$lit" case Literal(Tree.UnitLit(undefinedOrNull)) => if undefinedOrNull then "undefined" else "null" case CtorApp(cls, args) => - cls.name <#> "(" <#> (args |> showArguments) <#> ")" + doc"${cls.name}(${args.map(_.toString).mkString(",")})" case Select(s, cls, fld) => - s.toString <#> ".<" <#> cls.name <#> ":" <#> fld <#> ">" + doc"${s.toString}.<${cls.name}:$fld>" case BasicOp(name: Str, args) => - name <#> "(" <#> (args |> showArguments) <#> ")" + doc"$name(${args.map(_.toString).mkString(",")})" case AssignField(assignee, clsInfo, fieldName, value) => - stack( - "assign" - <:> (assignee.toString + "." + fieldName) - <:> ":=" - <:> value.toDocument - ) + doc"${assignee.toString}.${fieldName} := ${value.toString}" enum Pat: case Lit(lit: hkmc2.syntax.Literal) case Class(cls: ClassRef) - def isTrue = this match - case Class(cls) => cls.name == "True" - case _ => false - - def isFalse = this match - case Class(cls) => cls.name == "False" - case _ => false - override def toString: String = this match case Lit(lit) => s"$lit" case Class(cls) => s"${cls.name}" @@ -199,68 +185,30 @@ enum Node: override def toString: String = show - def show: String = - toDocument.print + def show: String = toDocument.toString def toDocument: Document = given Conversion[String, Document] = raw this match case Result(res) => (res |> showArguments) case Jump(jp, args) => - "jump" - <:> jp.name - <#> "(" - <#> (args |> showArguments) - <#> ")" - case Case(x, Ls((true_pat, tru), (false_pat, fls)), N) if true_pat.isTrue && false_pat.isFalse => - val first = "if" <:> x.toString - val tru2 = indent(stack("true" <:> "=>", tru.toDocument |> indent)) - val fls2 = indent(stack("false" <:> "=>", fls.toDocument |> indent)) - Document.Stacked(Ls(first, tru2, fls2)) + doc"jump ${jp.name}(${args |> showArguments})" case Case(x, cases, default) => - val first = "case" <:> x.toString <:> "of" - val other = cases flatMap { - case (pat, node) => - Ls(pat.toString <:> "=>", node.toDocument |> indent) - } + val docFirst = doc"case ${x.toString} of" + val docCases = cases.map { + case (pat, node) => doc"${pat.toString} => #{ # ${node.toDocument} #} " + }.mkDocument(doc" # ") default match - case N => stack(first, (Document.Stacked(other) |> indent)) + case N => doc"$docFirst #{ # $docCases #} " case S(dc) => - val default = Ls("_" <:> "=>", dc.toDocument |> indent) - stack(first, (Document.Stacked(other ++ default) |> indent)) - case Panic(msg) => "panic" <:> "\"" <#> msg <#> "\"" + val docDeft = doc"_ => #{ # ${dc.toDocument} #} " + doc"$docFirst #{ # $docCases # $docDeft #} " + case Panic(msg) => + doc"panic ${s"\"$msg\""}" case LetExpr(x, expr, body) => - stack( - "let" - <:> x.toString - <:> "=" - <:> expr.toDocument - <:> "in", - body.toDocument) + doc"let ${x.toString} = ${expr.toString} in # ${body.toDocument}" case LetMethodCall(xs, cls, method, args, body) => - stack( - "let" - <:> xs.map(_.toString).mkString(",") - <:> "=" - <:> cls.name - <#> "." - <#> method.toString - <#> "(" - <#> args.map{ x => x.toString }.mkString(",") - <#> ")" - <:> "in", - body.toDocument) + doc"let ${xs.map(_.toString).mkString(",")} = ${cls.name}.${method.toString}(${args.map(_.toString).mkString(",")}) in # ${body.toDocument}" case LetCall(xs, func, args, body) => - stack( - "let*" - <:> "(" - <#> xs.map(_.toString).mkString(",") - <#> ")" - <:> "=" - <:> func.name - <#> "(" - <#> args.map{ x => x.toString }.mkString(",") - <#> ")" - <:> "in", - body.toDocument) + doc"let* (${xs.map(_.toString).mkString(",")}) = ${func.name}(${args.map(_.toString).mkString(",")}) in # ${body.toDocument}" diff --git a/hkmc2/shared/src/main/scala/hkmc2/utils/document/LegacyDocument.scala b/hkmc2/shared/src/main/scala/hkmc2/utils/document/LegacyDocument.scala deleted file mode 100644 index eec3b867f2..0000000000 --- a/hkmc2/shared/src/main/scala/hkmc2/utils/document/LegacyDocument.scala +++ /dev/null @@ -1,52 +0,0 @@ -package hkmc2.utils.legacy_document - -enum Document: - case Indented(content: Document) - case Unindented(content: Document) - case Stacked(docs: List[Document], emptyLines: Boolean = false) - case Lined(docs: List[Document], separator: Document) - case Raw(s: String) - - def <:>(other: Document) = line(List(this, other)) - def <#>(other: Document) = line(List(this, other), sep = "") - - override def toString: String = print - - def print: String = { - val sb = StringBuffer() - - def rec(d: Document)(implicit ind: Int, first: Boolean): Unit = d match { - case Raw(s) => - if first && s.nonEmpty then sb append (" " * ind) - sb append s - case Indented(doc) => - rec(doc)(ind + 1, first) - case Unindented(doc) => - assume(ind > 0) - rec(doc)(ind - 1, first) - case Lined(Nil, _) => // skip - case Lined(docs, sep) => - rec(docs.head) - docs.tail foreach { doc => - rec(sep)(ind, false) - rec(doc)(ind, false) - } - case Stacked(Nil, _) => // skip - case Stacked(docs, emptyLines) => - rec(docs.head) - docs.tail foreach { doc => - sb append "\n" - if emptyLines then sb append "\n" - rec(doc)(ind, true) - } - } - - rec(this)(0, true) - sb.toString - } - -def stack(docs: Document*) = Document.Stacked(docs.toList) -def stack_list(docs: List[Document]) = Document.Stacked(docs) -def line(docs: List[Document], sep: String = " ") = Document.Lined(docs, Document.Raw(sep)) -def raw(s: String) = Document.Raw(s) -def indent(doc: Document) = Document.Indented(doc) diff --git a/hkmc2/shared/src/test/mlscript/llir/BadPrograms.mls b/hkmc2/shared/src/test/mlscript/llir/BadPrograms.mls index 1424a04f4b..185eba3478 100644 --- a/hkmc2/shared/src/test/mlscript/llir/BadPrograms.mls +++ b/hkmc2/shared/src/test/mlscript/llir/BadPrograms.mls @@ -22,20 +22,20 @@ fun oops(a) = //│ _mlsValue _mls_oops(_mlsValue); //│ _mlsValue _mlsMain(); //│ struct _mls_A: public _mlsObject { -//│ +//│ //│ constexpr static inline const char *typeName = "A"; //│ constexpr static inline uint32_t typeTag = nextTypeTag(); //│ virtual void print() const override { std::printf("%s", typeName); } //│ virtual void destroy() override { operator delete (this, std::align_val_t(_mlsAlignment)); } //│ static _mlsValue create() { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) _mls_A; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; return _mlsValue(_mlsVal); } //│ }; -//│ _mlsValue _mls_oops(_mlsValue _mls_a){ +//│ _mlsValue _mls_oops(_mlsValue _mls_a) { //│ _mlsValue _mls_retval; //│ auto _mls_x_0 = _mlsValue::fromIntLit(1); //│ _mls_retval = _mlsValue::create<_mls_Unit>(); //│ return _mls_retval; //│ } -//│ _mlsValue _mlsMain(){ +//│ _mlsValue _mlsMain() { //│ _mlsValue _mls_retval; //│ _mls_retval = _mlsValue::create<_mls_Unit>(); //│ return _mls_retval; diff --git a/hkmc2/shared/src/test/mlscript/llir/Playground.mls b/hkmc2/shared/src/test/mlscript/llir/Playground.mls index 7c3e50a951..81faaddcf2 100644 --- a/hkmc2/shared/src/test/mlscript/llir/Playground.mls +++ b/hkmc2/shared/src/test/mlscript/llir/Playground.mls @@ -133,7 +133,7 @@ fun f1() = let x = 2 x //│ LLIR: -//│ +//│ //│ def f1() = //│ let x$0 = 1 in //│ let x$1 = 2 in @@ -148,7 +148,7 @@ fun f2() = //│ Pretty Lowered: //│ define fun f2() { set x = 0 in set scrut = ==(x, 1) in match scrut true => return 2 else return 3 } in return null //│ LLIR: -//│ +//│ //│ def f2() = //│ let x$0 = 0 in //│ let x$1 = ==(x$0,1) in @@ -181,7 +181,7 @@ fun f3() = //│ } in //│ return null //│ LLIR: -//│ +//│ //│ def f3() = //│ let x$0 = 0 in //│ let x$1 = 1 in @@ -220,7 +220,7 @@ fun f4() = //│ } in //│ return null //│ LLIR: -//│ +//│ //│ def f4() = //│ let x$0 = 0 in //│ let x$1 = ==(x$0,1) in @@ -270,7 +270,7 @@ fun f5() = //│ } in //│ return null //│ LLIR: -//│ +//│ //│ def f5() = //│ let x$0 = 0 in //│ let x$1 = ==(x$0,1) in @@ -298,7 +298,7 @@ fun f5() = fun test() = if true do test() //│ LLIR: -//│ +//│ //│ def test() = //│ let x$0 = true in //│ case x$0 of @@ -315,7 +315,7 @@ fun test() = fun test() = (if true then test()) + 1 //│ LLIR: -//│ +//│ //│ def test() = //│ let x$0 = true in //│ case x$0 of From 63bada9565ed0a4c8fd3a606b88e3d3ad5aacfba Mon Sep 17 00:00:00 2001 From: waterlens Date: Tue, 14 Jan 2025 20:51:26 +0800 Subject: [PATCH 13/88] Support instantiate --- .../scala/hkmc2/codegen/llir/Builder.scala | 18 ++++++++++++++++-- .../src/test/mlscript/llir/Playground.mls | 13 +++++++++++++ 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala index 4153065fa5..1c57d81040 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala @@ -108,6 +108,14 @@ final class LlirBuilder(tl: TraceLogger)(fresh: Fresh, fnUid: FreshInt, clsUid: case r: TrivialExpr => bArgs(xs): case rs: Ls[TrivialExpr] => k(r :: rs) + private def bPaths(e: Ls[Path])(k: Ls[TrivialExpr] => Ctx ?=> Node)(using ctx: Ctx)(using Raise, Scope): Node = + trace[Node](s"bArgs begin", x => s"bArgs end: ${x.show}"): + e match + case Nil => k(Nil) + case x :: xs => bPath(x): + case r: TrivialExpr => bPaths(xs): + case rs: Ls[TrivialExpr] => k(r :: rs) + private def bFunDef(e: FunDefn)(using ctx: Ctx)(using Raise, Scope): Func = trace[Func](s"bFunDef begin: ${e.sym}", x => s"bFunDef end: ${x.show}"): val FunDefn(sym, params, body) = e @@ -207,8 +215,14 @@ final class LlirBuilder(tl: TraceLogger)(fresh: Fresh, fnUid: FreshInt, clsUid: case args: Ls[TrivialExpr] => val v = fresh.make Node.LetMethodCall(Ls(v), ClassRef(R("Callable")), Name("apply" + args.length), f :: args, k(v |> sr)) + case Instantiate( + Select(Select(Value.Ref(_: TopLevelSymbol), name), Tree.Ident("class")), args) => + bPaths(args): + case args: Ls[TrivialExpr] => + val v = fresh.make + Node.LetExpr(v, Expr.CtorApp(ClassRef.fromName(name.name), args), k(v |> sr)) case Instantiate(cls, args) => - err(msg"Unsupported result: Instantiate") + err(msg"Unsupported kind of Instantiate") Node.Result(Ls()) case x: Path => bPath(x)(k) @@ -248,7 +262,7 @@ final class LlirBuilder(tl: TraceLogger)(fresh: Fresh, fnUid: FreshInt, clsUid: summon[Ctx].def_acc += jpdef Node.Case(e, casesList, defaultCase) case Return(res, implct) => bResult(res)(x => Node.Result(Ls(x))) - case Throw(Instantiate(Select(Value.Ref(globalThis), ident), Ls(Value.Lit(Tree.StrLit(e))))) if ident.name == "Error" => + case Throw(Instantiate(Select(Value.Ref(_), ident), Ls(Value.Lit(Tree.StrLit(e))))) if ident.name == "Error" => Node.Panic(e) case Label(label, body, rest) => ??? case Break(label) => TODO("Break not supported") diff --git a/hkmc2/shared/src/test/mlscript/llir/Playground.mls b/hkmc2/shared/src/test/mlscript/llir/Playground.mls index 81faaddcf2..4025dfb651 100644 --- a/hkmc2/shared/src/test/mlscript/llir/Playground.mls +++ b/hkmc2/shared/src/test/mlscript/llir/Playground.mls @@ -27,6 +27,19 @@ fun lazy(x) = Lazy(x) //│ x$1 //│ undefined +:llir +fun testCtor1() = None +fun testCtor2() = new None +//│ LLIR: +//│ +//│ def testCtor1() = +//│ let x$0 = None() in +//│ x$0 +//│ def testCtor2() = +//│ let x$1 = None() in +//│ x$1 +//│ undefined + :llir abstract class Option[out T]: Some[T] | None class Some[out T](x: T) extends Option[T] From 1c267a5b38822ce235ebfc370f89eda690031b95 Mon Sep 17 00:00:00 2001 From: waterlens Date: Wed, 15 Jan 2025 20:42:55 +0800 Subject: [PATCH 14/88] Generate necessary errors --- .../src/test/scala/hkmc2/LlirDiffMaker.scala | 19 +++-- .../scala/hkmc2/codegen/llir/Builder.scala | 77 +++++++++++-------- .../src/test/mlscript/llir/BadPrograms.mls | 38 ++------- 3 files changed, 64 insertions(+), 70 deletions(-) diff --git a/hkmc2/jvm/src/test/scala/hkmc2/LlirDiffMaker.scala b/hkmc2/jvm/src/test/scala/hkmc2/LlirDiffMaker.scala index 08c480cf78..eb6ffaf449 100644 --- a/hkmc2/jvm/src/test/scala/hkmc2/LlirDiffMaker.scala +++ b/hkmc2/jvm/src/test/scala/hkmc2/LlirDiffMaker.scala @@ -32,10 +32,15 @@ abstract class LlirDiffMaker extends BbmlDiffMaker: val cuid = FreshInt() val llb = LlirBuilder(tl)(fresh, fuid, cuid) given Ctx = Ctx.empty - val llirProg = llb.bProg(le) - output("LLIR:") - output(llirProg.show()) - if scpp.isSet then - val cpp = codegen.cpp.CppCodeGen.codegen(llirProg) - output("\nCpp:") - output(cpp.toDocument.toString) + try + val llirProg = llb.bProg(le) + output("LLIR:") + output(llirProg.show()) + if scpp.isSet then + val cpp = codegen.cpp.CppCodeGen.codegen(llirProg) + output("\nCpp:") + output(cpp.toDocument.toString) + catch + case e: LowLevelIRError => + output("Stopped due to an error during the Llir generation") + diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala index 1c57d81040..6a73759917 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala @@ -22,6 +22,10 @@ def err(msg: Message)(using Raise): Unit = raise(ErrorReport(msg -> N :: Nil, source = Diagnostic.Source.Compilation)) +def errStop(msg: Message)(using Raise) = + err(msg) + throw LowLevelIRError("stopped") + final case class Ctx( def_acc: ListBuffer[Func], class_acc: ListBuffer[ClassInfo], @@ -29,6 +33,7 @@ final case class Ctx( fn_ctx: Map[Local, Name] = Map.empty, // is a known function class_ctx: Map[Local, Name] = Map.empty, block_ctx: Map[Local, Name] = Map.empty, + is_top_level: Bool = true, ): def addFuncName(n: Local, m: Name) = copy(fn_ctx = fn_ctx + (n -> m)) def findFuncName(n: Local)(using Raise) = fn_ctx.get(n) match @@ -51,6 +56,7 @@ final case class Ctx( def reset = def_acc.clear() class_acc.clear() + def nonTopLevel = copy(is_top_level = false) object Ctx: val empty = Ctx(ListBuffer.empty, ListBuffer.empty) @@ -119,30 +125,37 @@ final class LlirBuilder(tl: TraceLogger)(fresh: Fresh, fnUid: FreshInt, clsUid: private def bFunDef(e: FunDefn)(using ctx: Ctx)(using Raise, Scope): Func = trace[Func](s"bFunDef begin: ${e.sym}", x => s"bFunDef end: ${x.show}"): val FunDefn(sym, params, body) = e - if params.length != 1 then - err(msg"Curried function not supported: ${params.length.toString}") - val paramsList = params.head.params.map(x => x -> summon[Scope].allocateName(x.sym)) - val new_ctx = paramsList.foldLeft(ctx)((acc, x) => acc.addName(getVar_!(x._1.sym), x._2 |> nme)) - val pl = paramsList.map(_._2).map(nme) - Func( - fnUid.make, - sym.nme, - params = pl, - resultNum = 1, - body = bBlock(body)(x => Node.Result(Ls(x)))(using new_ctx) - ) + if !ctx.is_top_level then + errStop(msg"Non top-level definition ${sym.nme} not supported") + else if params.length != 1 then + errStop(msg"Curried function or zero arguments function not supported: ${params.length.toString}") + else + val paramsList = params.head.params.map(x => x -> summon[Scope].allocateName(x.sym)) + val ctx2 = paramsList.foldLeft(ctx)((acc, x) => acc.addName(getVar_!(x._1.sym), x._2 |> nme)) + val ctx3 = ctx2.nonTopLevel + val pl = paramsList.map(_._2).map(nme) + Func( + fnUid.make, + sym.nme, + params = pl, + resultNum = 1, + body = bBlock(body)(x => Node.Result(Ls(x)))(using ctx3) + ) private def bClsLikeDef(e: ClsLikeDefn)(using ctx: Ctx)(using Raise, Scope): ClassInfo = trace[ClassInfo](s"bClsLikeDef begin", x => s"bClsLikeDef end: ${x.show}"): val ClsLikeDefn(sym, kind, parentSym, methods, privateFields, publicFields, preCtor, ctor) = e - val clsDefn = sym.defn.getOrElse(die) - val clsParams = clsDefn.paramsOpt.fold(Nil)(_.paramSyms) - val clsFields = publicFields.map(_.sym) - ClassInfo( - clsUid.make, - sym.nme, - clsParams.map(_.nme) ++ clsFields.map(_.nme), - ) + if !ctx.is_top_level then + errStop(msg"Non top-level definition ${sym.nme} not supported") + else + val clsDefn = sym.defn.getOrElse(die) + val clsParams = clsDefn.paramsOpt.fold(Nil)(_.paramSyms) + val clsFields = publicFields.map(_.sym) + ClassInfo( + clsUid.make, + sym.nme, + clsParams.map(_.nme) ++ clsFields.map(_.nme), + ) private def bValue(v: Value)(k: TrivialExpr => Ctx ?=> Node)(using ctx: Ctx)(using Raise, Scope) : Node = trace[Node](s"bValue begin", x => s"bValue end: ${x.show}"): @@ -166,17 +179,21 @@ final class LlirBuilder(tl: TraceLogger)(fresh: Fresh, fnUid: FreshInt, clsUid: val v = fresh.make Node.LetExpr(v, Expr.CtorApp(ClassRef.fromName(name.name), Ls()), k(v |> sr)) // field selection - case s @ Select(qual, name) => + case s @ Select(qual, name) => log(s"bPath Select: $qual.$name with ${s.symbol}") - bPath(qual): - case q: Expr.Ref => - val v = fresh.make - val cls = ClassRef.fromName(ctx.findClassName(getClassOfMem(s.symbol.get))) - val field = name.name - Node.LetExpr(v, Expr.Select(q.name, cls, field), k(v |> sr)) - case q: Expr.Literal => - err(msg"Unsupported select on literal") - Node.Result(Ls()) + s.symbol match + case None => + errStop(msg"Unsupported selection by users") + case Some(value) => + bPath(qual): + case q: Expr.Ref => + val v = fresh.make + val cls = ClassRef.fromName(ctx.findClassName(getClassOfMem(s.symbol.get))) + val field = name.name + Node.LetExpr(v, Expr.Select(q.name, cls, field), k(v |> sr)) + case q: Expr.Literal => + err(msg"Unsupported select on literal") + Node.Result(Ls()) case x: Value => bValue(x)(k) private def bResult(r: Result)(k: TrivialExpr => Ctx ?=> Node)(using ctx: Ctx)(using Raise, Scope) : Node = diff --git a/hkmc2/shared/src/test/mlscript/llir/BadPrograms.mls b/hkmc2/shared/src/test/mlscript/llir/BadPrograms.mls index 185eba3478..8bd7372502 100644 --- a/hkmc2/shared/src/test/mlscript/llir/BadPrograms.mls +++ b/hkmc2/shared/src/test/mlscript/llir/BadPrograms.mls @@ -9,42 +9,14 @@ fun oops(a) = class A with fun m = a let x = 1 -//│ LLIR: -//│ class A() -//│ def oops(a) = -//│ let x$0 = 1 in -//│ undefined -//│ undefined -//│ -//│ Cpp: -//│ #include "mlsprelude.h" -//│ struct _mls_A; -//│ _mlsValue _mls_oops(_mlsValue); -//│ _mlsValue _mlsMain(); -//│ struct _mls_A: public _mlsObject { -//│ -//│ constexpr static inline const char *typeName = "A"; -//│ constexpr static inline uint32_t typeTag = nextTypeTag(); -//│ virtual void print() const override { std::printf("%s", typeName); } -//│ virtual void destroy() override { operator delete (this, std::align_val_t(_mlsAlignment)); } -//│ static _mlsValue create() { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) _mls_A; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; return _mlsValue(_mlsVal); } -//│ }; -//│ _mlsValue _mls_oops(_mlsValue _mls_a) { -//│ _mlsValue _mls_retval; -//│ auto _mls_x_0 = _mlsValue::fromIntLit(1); -//│ _mls_retval = _mlsValue::create<_mls_Unit>(); -//│ return _mls_retval; -//│ } -//│ _mlsValue _mlsMain() { -//│ _mlsValue _mls_retval; -//│ _mls_retval = _mlsValue::create<_mls_Unit>(); -//│ return _mls_retval; -//│ } -//│ int main() { return _mlsLargeStack(_mlsMainWrapper); } +//│ FAILURE: Unexpected runtime error +//│ ═══[COMPILATION ERROR] Non top-level definition A not supported +//│ Stopped due to an error during the Llir generation :todo // Properly reject let x = "oops" x.m -//│ /!!!\ Uncaught error: java.util.NoSuchElementException: None.get +//│ ═══[COMPILATION ERROR] Unsupported selection by users +//│ Stopped due to an error during the Llir generation From f243486a43b2ac2025d9aebaee536fad6abebb48 Mon Sep 17 00:00:00 2001 From: waterlens Date: Wed, 15 Jan 2025 20:53:38 +0800 Subject: [PATCH 15/88] Update names of the flags --- .../src/test/scala/hkmc2/LlirDiffMaker.scala | 14 +-- .../src/test/mlscript/llir/BadPrograms.mls | 6 +- .../src/test/mlscript/llir/Playground.mls | 88 ++++--------------- 3 files changed, 26 insertions(+), 82 deletions(-) diff --git a/hkmc2/jvm/src/test/scala/hkmc2/LlirDiffMaker.scala b/hkmc2/jvm/src/test/scala/hkmc2/LlirDiffMaker.scala index eb6ffaf449..21a5bfa083 100644 --- a/hkmc2/jvm/src/test/scala/hkmc2/LlirDiffMaker.scala +++ b/hkmc2/jvm/src/test/scala/hkmc2/LlirDiffMaker.scala @@ -18,6 +18,8 @@ import hkmc2.codegen.llir._ abstract class LlirDiffMaker extends BbmlDiffMaker: val llir = NullaryCommand("llir") + val cpp = NullaryCommand("cpp") + val sllir = NullaryCommand("sllir") val scpp = NullaryCommand("scpp") override def processTerm(trm: Blk, inImport: Bool)(using Raise): Unit = @@ -34,12 +36,14 @@ abstract class LlirDiffMaker extends BbmlDiffMaker: given Ctx = Ctx.empty try val llirProg = llb.bProg(le) - output("LLIR:") - output(llirProg.show()) - if scpp.isSet then + if sllir.isSet then + output("LLIR:") + output(llirProg.show()) + if cpp.isSet then val cpp = codegen.cpp.CppCodeGen.codegen(llirProg) - output("\nCpp:") - output(cpp.toDocument.toString) + if scpp.isSet then + output("\nCpp:") + output(cpp.toDocument.toString) catch case e: LowLevelIRError => output("Stopped due to an error during the Llir generation") diff --git a/hkmc2/shared/src/test/mlscript/llir/BadPrograms.mls b/hkmc2/shared/src/test/mlscript/llir/BadPrograms.mls index 8bd7372502..0cd5a8212d 100644 --- a/hkmc2/shared/src/test/mlscript/llir/BadPrograms.mls +++ b/hkmc2/shared/src/test/mlscript/llir/BadPrograms.mls @@ -1,10 +1,8 @@ :global :llir -:scpp +:cpp - -// TODO should be rejected fun oops(a) = class A with fun m = a @@ -13,9 +11,9 @@ fun oops(a) = //│ ═══[COMPILATION ERROR] Non top-level definition A not supported //│ Stopped due to an error during the Llir generation -:todo // Properly reject let x = "oops" x.m +//│ FAILURE: Unexpected runtime error //│ ═══[COMPILATION ERROR] Unsupported selection by users //│ Stopped due to an error during the Llir generation diff --git a/hkmc2/shared/src/test/mlscript/llir/Playground.mls b/hkmc2/shared/src/test/mlscript/llir/Playground.mls index 4025dfb651..c2e170470a 100644 --- a/hkmc2/shared/src/test/mlscript/llir/Playground.mls +++ b/hkmc2/shared/src/test/mlscript/llir/Playground.mls @@ -1,6 +1,7 @@ :js - :llir + +:sllir abstract class Option[out T]: Some[T] | None class Some[out T](x: T) extends Option[T] object None extends Option @@ -27,7 +28,7 @@ fun lazy(x) = Lazy(x) //│ x$1 //│ undefined -:llir +:sllir fun testCtor1() = None fun testCtor2() = new None //│ LLIR: @@ -40,7 +41,7 @@ fun testCtor2() = new None //│ x$1 //│ undefined -:llir +:sllir abstract class Option[out T]: Some[T] | None class Some[out T](x: T) extends Option[T] object None extends Option @@ -140,7 +141,7 @@ main() //│ let* (x$19) = main() in //│ x$19 -:llir +:sllir fun f1() = let x = 1 let x = 2 @@ -153,13 +154,10 @@ fun f1() = //│ x$1 //│ undefined -:slot -:llir +:sllir fun f2() = let x = 0 if x == 1 then 2 else 3 -//│ Pretty Lowered: -//│ define fun f2() { set x = 0 in set scrut = ==(x, 1) in match scrut true => return 2 else return 3 } in return null //│ LLIR: //│ //│ def f2() = @@ -174,25 +172,12 @@ fun f2() = //│ null //│ undefined -:llir -:slot + +:sllir fun f3() = let x1 = 0 let x2 = 1 if true then x1 else x2 -//│ Pretty Lowered: -//│ -//│ define fun f3() { -//│ set x1 = 0 in -//│ set x2 = 1 in -//│ set scrut = true in -//│ match scrut -//│ true => -//│ return x1 -//│ else -//│ return x2 -//│ } in -//│ return null //│ LLIR: //│ //│ def f3() = @@ -209,29 +194,11 @@ fun f3() = //│ undefined -:slot -:llir +:sllir fun f4() = let x = 0 let x = if x == 1 then 2 else 3 x -//│ Pretty Lowered: -//│ -//│ define fun f4() { -//│ set x = 0 in -//│ begin -//│ set scrut = ==(x, 1) in -//│ match scrut -//│ true => -//│ set tmp = 2 in -//│ end -//│ else -//│ set tmp = 3 in -//│ end; -//│ set x1 = tmp in -//│ return x1 -//│ } in -//│ return null //│ LLIR: //│ //│ def f4() = @@ -248,40 +215,13 @@ fun f4() = //│ x$2 //│ undefined -:slot -:llir +:sllir +:scpp fun f5() = let x = 0 let x = if x == 1 then 2 else 3 let x = if x == 2 then 4 else 5 x -//│ Pretty Lowered: -//│ -//│ define fun f5() { -//│ set x = 0 in -//│ begin -//│ set scrut = ==(x, 1) in -//│ match scrut -//│ true => -//│ set tmp = 2 in -//│ end -//│ else -//│ set tmp = 3 in -//│ end; -//│ set x1 = tmp in -//│ begin -//│ set scrut1 = ==(x1, 2) in -//│ match scrut1 -//│ true => -//│ set tmp1 = 4 in -//│ end -//│ else -//│ set tmp1 = 5 in -//│ end; -//│ set x2 = tmp1 in -//│ return x2 -//│ } in -//│ return null //│ LLIR: //│ //│ def f5() = @@ -307,7 +247,8 @@ fun f5() = //│ x$6 //│ undefined -:llir +:sllir +:scpp fun test() = if true do test() //│ LLIR: @@ -324,7 +265,8 @@ fun test() = //│ null //│ undefined -:llir +:sllir +:scpp fun test() = (if true then test()) + 1 //│ LLIR: From 8f57a4e651a7fa379ddd2f526fc8d913f459f452 Mon Sep 17 00:00:00 2001 From: waterlens Date: Wed, 15 Jan 2025 21:06:58 +0800 Subject: [PATCH 16/88] Add the interpreter --- .../src/test/scala/hkmc2/LlirDiffMaker.scala | 7 +- .../scala/hkmc2/codegen/llir/Interp.scala | 212 ++++++++++++++++++ .../src/test/mlscript/llir/Playground.mls | 103 ++++++++- 3 files changed, 315 insertions(+), 7 deletions(-) create mode 100644 hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Interp.scala diff --git a/hkmc2/jvm/src/test/scala/hkmc2/LlirDiffMaker.scala b/hkmc2/jvm/src/test/scala/hkmc2/LlirDiffMaker.scala index 21a5bfa083..505ceadf1c 100644 --- a/hkmc2/jvm/src/test/scala/hkmc2/LlirDiffMaker.scala +++ b/hkmc2/jvm/src/test/scala/hkmc2/LlirDiffMaker.scala @@ -21,6 +21,7 @@ abstract class LlirDiffMaker extends BbmlDiffMaker: val cpp = NullaryCommand("cpp") val sllir = NullaryCommand("sllir") val scpp = NullaryCommand("scpp") + val intl = NullaryCommand("intl") override def processTerm(trm: Blk, inImport: Bool)(using Raise): Unit = super.processTerm(trm, inImport) @@ -39,11 +40,15 @@ abstract class LlirDiffMaker extends BbmlDiffMaker: if sllir.isSet then output("LLIR:") output(llirProg.show()) - if cpp.isSet then + if cpp.isSet || scpp.isSet then val cpp = codegen.cpp.CppCodeGen.codegen(llirProg) if scpp.isSet then output("\nCpp:") output(cpp.toDocument.toString) + if intl.isSet then + val intr = codegen.llir.Interpreter(verbose = true) + output("\nInterpreted:") + output(intr.interpret(llirProg)) catch case e: LowLevelIRError => output("Stopped due to an error during the Llir generation") diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Interp.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Interp.scala new file mode 100644 index 0000000000..60ab4cca16 --- /dev/null +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Interp.scala @@ -0,0 +1,212 @@ +package hkmc2.codegen.llir + +import mlscript.* +import mlscript.utils.* +import scala.collection.immutable.* +import scala.collection.mutable.ListBuffer +import shorthands.* +import scala.util.boundary, boundary.break + +import hkmc2.codegen.llir.* +import hkmc2.syntax.Tree + +enum Stuck: + case StuckExpr(expr: Expr, msg: Str) + case StuckNode(node: Node, msg: Str) + + override def toString: String = + this match + case StuckExpr(expr, msg) => s"StuckExpr(${expr.show}, $msg)" + case StuckNode(node, msg) => s"StuckNode(${node.show}, $msg)" + +final case class InterpreterError(message: String) extends Exception(message) + +class Interpreter(verbose: Bool): + private def log(x: Any) = if verbose then println(x) + import Stuck._ + + private case class Configuration( + var context: Ctx + ) + + private type Result[T] = Either[Stuck, T] + + private enum Value: + case Class(cls: ClassInfo, var fields: Ls[Value]) + case Literal(lit: hkmc2.syntax.Literal) + + override def toString: String = + import hkmc2.syntax.Tree.* + this match + case Class(cls, fields) => s"${cls.name}(${fields.mkString(",")})" + case Literal(IntLit(lit)) => lit.toString + case Literal(BoolLit(lit)) => lit.toString + case Literal(DecLit(lit)) => lit.toString + case Literal(StrLit(lit)) => lit.toString + case Literal(UnitLit(undefinedOrNull)) => if undefinedOrNull then "undefined" else "null" + + private final case class Ctx( + bindingCtx: Map[Str, Value], + classCtx: Map[Str, ClassInfo], + funcCtx: Map[Str, Func], + ) + + import Node._ + import Expr._ + + private def getTrue(using ctx: Ctx) = Value.Literal(hkmc2.syntax.Tree.BoolLit(true)) + private def getFalse(using ctx: Ctx) = Value.Literal(hkmc2.syntax.Tree.BoolLit(false)) + + private def eval(op: Str, x1: Value, x2: Value)(using ctx: Ctx): Opt[Value] = + import Value.{Literal => Li} + import hkmc2.syntax.Tree.* + (op, x1, x2) match + case ("+", Li(IntLit(x)), Li(IntLit(y))) => S(Li(IntLit(x + y))) + case ("-", Li(IntLit(x)), Li(IntLit(y))) => S(Li(IntLit(x - y))) + case ("*", Li(IntLit(x)), Li(IntLit(y))) => S(Li(IntLit(x * y))) + case ("/", Li(IntLit(x)), Li(IntLit(y))) => S(Li(IntLit(x / y))) + case ("==", Li(IntLit(x)), Li(IntLit(y))) => S(if x == y then getTrue else getFalse) + case ("!=", Li(IntLit(x)), Li(IntLit(y))) => S(if x != y then getTrue else getFalse) + case ("<=", Li(IntLit(x)), Li(IntLit(y))) => S(if x <= y then getTrue else getFalse) + case (">=", Li(IntLit(x)), Li(IntLit(y))) => S(if x >= y then getTrue else getFalse) + case (">", Li(IntLit(x)), Li(IntLit(y))) => S(if x > y then getTrue else getFalse) + case ("<", Li(IntLit(x)), Li(IntLit(y))) => S(if x < y then getTrue else getFalse) + case _ => N + + private def evalArgs(using ctx: Ctx)(exprs: Ls[TrivialExpr]): Result[Ls[Value]] = + var values = ListBuffer.empty[Value] + var stuck: Opt[Stuck] = None + exprs foreach { expr => + stuck match + case None => eval(expr) match + case L(x) => stuck = Some(x) + case R(x) => values += x + case _ => () + } + stuck.toLeft(values.toList) + + private def eval(expr: TrivialExpr)(using ctx: Ctx): Result[Value] = expr match + case e @ Ref(name) => ctx.bindingCtx.get(name.str).toRight(StuckExpr(e, s"undefined variable $name")) + case Literal(lit) => R(Value.Literal(lit)) + + private def eval(expr: Expr)(using ctx: Ctx): Result[Value] = expr match + case Ref(Name(x)) => ctx.bindingCtx.get(x).toRight(StuckExpr(expr, s"undefined variable $x")) + case Literal(x) => R(Value.Literal(x)) + case CtorApp(cls, args) => + for + xs <- evalArgs(args) + cls <- ctx.classCtx.get(cls.name).toRight(StuckExpr(expr, s"undefined class ${cls.name}")) + yield Value.Class(cls, xs) + case Select(name, cls, field) => + ctx.bindingCtx.get(name.str).toRight(StuckExpr(expr, s"undefined variable $name")).flatMap { + case Value.Class(cls2, xs) if cls.name == cls2.name => + xs.zip(cls2.fields).find{_._2 == field} match + case Some((x, _)) => R(x) + case None => L(StuckExpr(expr, s"unable to find selected field $field")) + case Value.Class(cls2, xs) => L(StuckExpr(expr, s"unexpected class $cls2")) + case x => L(StuckExpr(expr, s"unexpected value $x")) + } + case BasicOp(name, args) => boundary: + evalArgs(args).flatMap( + xs => + name match + case "+" | "-" | "*" | "/" | "==" | "!=" | "<=" | ">=" | "<" | ">" => + if xs.length < 2 then break: + L(StuckExpr(expr, s"not enough arguments for basic operation $name")) + else eval(name, xs.head, xs.tail.head).toRight(StuckExpr(expr, s"unable to evaluate basic operation")) + case _ => L(StuckExpr(expr, s"unexpected basic operation $name"))) + case AssignField(assignee, cls, field, value) => + for + x <- eval(Ref(assignee): TrivialExpr) + y <- eval(value) + res <- x match + case obj @ Value.Class(cls2, xs) if cls.name == cls2.name => + xs.zip(cls2.fields).find{_._2 == field} match + case Some((_, _)) => + obj.fields = xs.map(x => if x == obj then y else x) + // Ideally, we should return a unit value here, but here we return the assignee value for simplicity. + R(obj) + case None => L(StuckExpr(expr, s"unable to find selected field $field")) + case Value.Class(cls2, xs) => L(StuckExpr(expr, s"unexpected class $cls2")) + case x => L(StuckExpr(expr, s"unexpected value $x")) + yield res + + private def eval(node: Node)(using ctx: Ctx): Result[Ls[Value]] = node match + case Result(res) => evalArgs(res) + case Jump(func, args) => + for + xs <- evalArgs(args) + func <- ctx.funcCtx.get(func.name).toRight(StuckNode(node, s"undefined function ${func.name}")) + ctx1 = ctx.copy(bindingCtx = ctx.bindingCtx ++ func.params.map{_.str}.zip(xs)) + res <- eval(func.body)(using ctx1) + yield res + case Case(scrut, cases, default) => + eval(scrut) flatMap { + case Value.Class(cls, fields) => + cases.find { + case (Pat.Class(cls2), _) => cls.name == cls2.name + case _ => false + } match { + case Some((_, x)) => eval(x) + case None => + default match + case S(x) => eval(x) + case N => L(StuckNode(node, s"can not find the matched case, ${cls.name} expected")) + } + case Value.Literal(lit) => + cases.find { + case (Pat.Lit(lit2), _) => lit == lit2 + case _ => false + } match { + case Some((_, x)) => eval(x) + case None => + default match + case S(x) => eval(x) + case N => L(StuckNode(node, s"can not find the matched case, $lit expected")) + } + } + case LetExpr(name, expr, body) => + for + x <- eval(expr) + ctx1 = ctx.copy(bindingCtx = ctx.bindingCtx + (name.str -> x)) + res <- eval(body)(using ctx1) + yield res + case LetMethodCall(names, cls, method, args, body) => + for + ys <- evalArgs(args).flatMap { + case Value.Class(cls2, xs) :: args => + cls2.methods.get(method.str).toRight(StuckNode(node, s"undefined method ${method.str}")).flatMap { method => + val ctx1 = ctx.copy(bindingCtx = ctx.bindingCtx ++ cls2.fields.zip(xs) ++ method.params.map{_.str}.zip(args)) + eval(method.body)(using ctx1) + } + case _ => L(StuckNode(node, s"not enough arguments for method call, or the first argument is not a class")) + } + ctx2 = ctx.copy(bindingCtx = ctx.bindingCtx ++ names.map{_.str}.zip(ys)) + res <- eval(body)(using ctx2) + yield res + // case LetApply(names, fn, args, body) => eval(LetMethodCall(names, ClassRef(R("Callable")), Name("apply" + args.length), (Ref(fn): TrivialExpr) :: args, body)) + case LetCall(names, func, args, body) => + for + xs <- evalArgs(args) + func <- ctx.funcCtx.get(func.name).toRight(StuckNode(node, s"undefined function ${func.name}")) + ctx1 = ctx.copy(bindingCtx = ctx.bindingCtx ++ func.params.map{_.str}.zip(xs)) + ys <- eval(func.body)(using ctx1) + ctx2 = ctx.copy(bindingCtx = ctx.bindingCtx ++ names.map{_.str}.zip(ys)) + res <- eval(body)(using ctx2) + yield res + case Panic(msg) => L(StuckNode(node, msg)) + + private def f(prog: Program): Ls[Value] = + val Program(classes, defs, main) = prog + given Ctx = Ctx( + bindingCtx = Map.empty, + classCtx = classes.map{cls => cls.name -> cls}.toMap, + funcCtx = defs.map{func => func.name -> func}.toMap, + ) + eval(main) match + case R(x) => x + case L(x) => throw InterpreterError("Stuck evaluation: " + x.toString) + + def interpret(prog: Program): Str = + val node = f(prog) + node.map(_.toString).mkString(",") diff --git a/hkmc2/shared/src/test/mlscript/llir/Playground.mls b/hkmc2/shared/src/test/mlscript/llir/Playground.mls index c2e170470a..4a4a1f3083 100644 --- a/hkmc2/shared/src/test/mlscript/llir/Playground.mls +++ b/hkmc2/shared/src/test/mlscript/llir/Playground.mls @@ -42,6 +42,7 @@ fun testCtor2() = new None //│ undefined :sllir +:intl abstract class Option[out T]: Some[T] | None class Some[out T](x: T) extends Option[T] object None extends Option @@ -140,24 +141,37 @@ main() //│ null //│ let* (x$19) = main() in //│ x$19 +//│ +//│ Interpreted: +//│ 404 :sllir +:intl fun f1() = let x = 1 let x = 2 x +f1() +//│ = 2 //│ LLIR: //│ //│ def f1() = //│ let x$0 = 1 in //│ let x$1 = 2 in //│ x$1 -//│ undefined +//│ let* (x$2) = f1() in +//│ x$2 +//│ +//│ Interpreted: +//│ 2 :sllir +:intl fun f2() = let x = 0 if x == 1 then 2 else 3 +f2() +//│ = 3 //│ LLIR: //│ //│ def f2() = @@ -170,7 +184,11 @@ fun f2() = //│ 3 //│ def j$0() = //│ null -//│ undefined +//│ let* (x$2) = f2() in +//│ x$2 +//│ +//│ Interpreted: +//│ 3 :sllir @@ -178,6 +196,8 @@ fun f3() = let x1 = 0 let x2 = 1 if true then x1 else x2 +f3() +//│ = 0 //│ LLIR: //│ //│ def f3() = @@ -191,14 +211,18 @@ fun f3() = //│ x$1 //│ def j$0() = //│ null -//│ undefined +//│ let* (x$3) = f3() in +//│ x$3 :sllir +:intl fun f4() = let x = 0 let x = if x == 1 then 2 else 3 x +f4() +//│ = 3 //│ LLIR: //│ //│ def f4() = @@ -213,15 +237,21 @@ fun f4() = //│ jump j$0(x$4) //│ def j$0(x$2) = //│ x$2 -//│ undefined +//│ let* (x$5) = f4() in +//│ x$5 +//│ +//│ Interpreted: +//│ 3 :sllir -:scpp +:intl fun f5() = let x = 0 let x = if x == 1 then 2 else 3 let x = if x == 2 then 4 else 5 x +f5() +//│ = 5 //│ LLIR: //│ //│ def f5() = @@ -245,7 +275,11 @@ fun f5() = //│ jump j$1(x$8) //│ def j$1(x$6) = //│ x$6 -//│ undefined +//│ let* (x$9) = f5() in +//│ x$9 +//│ +//│ Interpreted: +//│ 5 :sllir :scpp @@ -264,6 +298,34 @@ fun test() = //│ def j$0() = //│ null //│ undefined +//│ +//│ Cpp: +//│ #include "mlsprelude.h" +//│ _mlsValue _mls_j_0(); +//│ _mlsValue _mls_test(); +//│ _mlsValue _mlsMain(); +//│ _mlsValue _mls_j_0() { +//│ _mlsValue _mls_retval; +//│ _mls_retval = _mlsValue::create<_mls_Unit>(); +//│ return _mls_retval; +//│ } +//│ _mlsValue _mls_test() { +//│ _mlsValue _mls_retval; +//│ auto _mls_x_0 = _mlsValue::fromIntLit(1); +//│ if (_mlsValue::isIntLit(_mls_x_0, 1)) { +//│ auto _mls_x_1 = _mls_test(); +//│ _mls_retval = _mls_x_1; +//│ } else { +//│ _mls_retval = _mlsValue::create<_mls_Unit>(); +//│ } +//│ return _mls_retval; +//│ } +//│ _mlsValue _mlsMain() { +//│ _mlsValue _mls_retval; +//│ _mls_retval = _mlsValue::create<_mls_Unit>(); +//│ return _mls_retval; +//│ } +//│ int main() { return _mlsLargeStack(_mlsMainWrapper); } :sllir :scpp @@ -283,4 +345,33 @@ fun test() = //│ let x$3 = +(x$1,1) in //│ x$3 //│ undefined +//│ +//│ Cpp: +//│ #include "mlsprelude.h" +//│ _mlsValue _mls_j_0(_mlsValue); +//│ _mlsValue _mls_test(); +//│ _mlsValue _mlsMain(); +//│ _mlsValue _mls_j_0(_mlsValue _mls_x_1) { +//│ _mlsValue _mls_retval; +//│ auto _mls_x_3 = (_mls_x_1 + _mlsValue::fromIntLit(1)); +//│ _mls_retval = _mls_x_3; +//│ return _mls_retval; +//│ } +//│ _mlsValue _mls_test() { +//│ _mlsValue _mls_retval; +//│ auto _mls_x_0 = _mlsValue::fromIntLit(1); +//│ if (_mlsValue::isIntLit(_mls_x_0, 1)) { +//│ auto _mls_x_2 = _mls_test(); +//│ _mls_retval = _mls_j_0(_mls_x_2); +//│ } else { +//│ throw std::runtime_error("match error"); +//│ } +//│ return _mls_retval; +//│ } +//│ _mlsValue _mlsMain() { +//│ _mlsValue _mls_retval; +//│ _mls_retval = _mlsValue::create<_mls_Unit>(); +//│ return _mls_retval; +//│ } +//│ int main() { return _mlsLargeStack(_mlsMainWrapper); } From 72f817d717d1502248bb073bb2244c170317c8ee Mon Sep 17 00:00:00 2001 From: waterlens Date: Wed, 15 Jan 2025 21:45:17 +0800 Subject: [PATCH 17/88] Add the compiler host --- .../src/test/scala/hkmc2/LlirDiffMaker.scala | 14 +- .../hkmc2/codegen/cpp/CompilerHost.scala | 4 +- .../src/test/mlscript-compile/cpp/Makefile | 27 + .../test/mlscript-compile/cpp/mlsprelude.h | 568 ++++++++++++++++++ .../src/test/mlscript/llir/Playground.mls | 8 + 5 files changed, 617 insertions(+), 4 deletions(-) create mode 100644 hkmc2/shared/src/test/mlscript-compile/cpp/Makefile create mode 100644 hkmc2/shared/src/test/mlscript-compile/cpp/mlsprelude.h diff --git a/hkmc2/jvm/src/test/scala/hkmc2/LlirDiffMaker.scala b/hkmc2/jvm/src/test/scala/hkmc2/LlirDiffMaker.scala index 505ceadf1c..db6ae399ff 100644 --- a/hkmc2/jvm/src/test/scala/hkmc2/LlirDiffMaker.scala +++ b/hkmc2/jvm/src/test/scala/hkmc2/LlirDiffMaker.scala @@ -7,7 +7,8 @@ import utils.* import document.* import codegen.Block -import codegen.llir.LlirBuilder +import codegen.llir.* +import codegen.cpp.* import hkmc2.syntax.Tree.Ident import hkmc2.codegen.Path import hkmc2.semantics.Term.Blk @@ -21,6 +22,7 @@ abstract class LlirDiffMaker extends BbmlDiffMaker: val cpp = NullaryCommand("cpp") val sllir = NullaryCommand("sllir") val scpp = NullaryCommand("scpp") + val rcpp = NullaryCommand("rcpp") val intl = NullaryCommand("intl") override def processTerm(trm: Blk, inImport: Bool)(using Raise): Unit = @@ -40,11 +42,19 @@ abstract class LlirDiffMaker extends BbmlDiffMaker: if sllir.isSet then output("LLIR:") output(llirProg.show()) - if cpp.isSet || scpp.isSet then + if cpp.isSet || scpp.isSet || rcpp.isSet then val cpp = codegen.cpp.CppCodeGen.codegen(llirProg) if scpp.isSet then output("\nCpp:") output(cpp.toDocument.toString) + if rcpp.isSet then + val auxPath = os.pwd/os.up/"shared"/"src"/"test"/"mlscript-compile"/"cpp" + val cppHost = CppCompilerHost(auxPath.toString, output.apply) + if !cppHost.ready then + output("\nCpp Compilation Failed: Cpp compiler or GNU Make not found") + else + output("\n") + cppHost.compileAndRun(cpp.toDocument.toString) if intl.isSet then val intr = codegen.llir.Interpreter(verbose = true) output("\nInterpreted:") diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/CompilerHost.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/CompilerHost.scala index 291f5a0c4a..867ffe4e65 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/CompilerHost.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/CompilerHost.scala @@ -4,7 +4,7 @@ import mlscript._ import mlscript.utils.shorthands._ import scala.collection.mutable.ListBuffer -final class CppCompilerHost(val auxPath: Str): +final class CppCompilerHost(val auxPath: Str, val output: Str => Unit): import scala.sys.process._ private def ifAnyCppCompilerExists(): Boolean = Seq("g++", "--version").! == 0 || Seq("clang++", "--version").! == 0 @@ -15,7 +15,7 @@ final class CppCompilerHost(val auxPath: Str): val ready = ifAnyCppCompilerExists() && isMakeExists() - def compileAndRun(src: Str, output: Str => Unit): Unit = + def compileAndRun(src: Str): Unit = if !ready then return val srcPath = os.temp(contents = src, suffix = ".cpp") diff --git a/hkmc2/shared/src/test/mlscript-compile/cpp/Makefile b/hkmc2/shared/src/test/mlscript-compile/cpp/Makefile new file mode 100644 index 0000000000..45aae4802c --- /dev/null +++ b/hkmc2/shared/src/test/mlscript-compile/cpp/Makefile @@ -0,0 +1,27 @@ +CXX := g++ +CFLAGS += -O3 -Wall -Wextra -std=c++20 -I. -Wno-inconsistent-missing-override -I/opt/homebrew/include +LDFLAGS += -L/opt/homebrew/lib +LDLIBS := -lmimalloc -lgmp +SRC := +INCLUDES := mlsprelude.h +DST := +DEFAULT_TARGET := mls +TARGET := $(or $(DST),$(DEFAULT_TARGET)) + +.PHONY: pre all run clean auto + +all: $(TARGET) + +run: $(TARGET) + ./$(TARGET) + +pre: $(SRC) + sed -i '' 's#^//│ ##g' $(SRC) + +clean: + rm -r $(TARGET) $(TARGET).dSYM + +auto: $(TARGET) + +$(TARGET): $(SRC) $(INCLUDES) + $(CXX) $(CFLAGS) $(LDFLAGS) $(SRC) $(LDLIBS) -o $(TARGET) diff --git a/hkmc2/shared/src/test/mlscript-compile/cpp/mlsprelude.h b/hkmc2/shared/src/test/mlscript-compile/cpp/mlsprelude.h new file mode 100644 index 0000000000..8415951c93 --- /dev/null +++ b/hkmc2/shared/src/test/mlscript-compile/cpp/mlsprelude.h @@ -0,0 +1,568 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +constexpr std::size_t _mlsAlignment = 8; + +template class tuple_type { + template > struct impl; + template struct impl> { + template using wrap = T; + using type = std::tuple...>; + }; + +public: + using type = typename impl<>::type; +}; +template struct counter { + using tag = counter; + + struct generator { + friend consteval auto is_defined(tag) { return true; } + }; + friend consteval auto is_defined(tag); + + template + static consteval auto exists(auto) { + return true; + } + + static consteval auto exists(...) { return generator(), false; } +}; + +template +consteval auto nextTypeTag() { + if constexpr (not counter::exists(Id)) + return Id; + else + return nextTypeTag(); +} + +struct _mlsObject { + uint32_t refCount; + uint32_t tag; + constexpr static inline uint32_t stickyRefCount = + std::numeric_limits::max(); + + void incRef() { + if (refCount != stickyRefCount) + ++refCount; + } + bool decRef() { + if (refCount != stickyRefCount && --refCount == 0) + return true; + return false; + } + + virtual void print() const = 0; + virtual void destroy() = 0; +}; + +struct _mls_True; +struct _mls_False; + +class _mlsValue { + using uintptr_t = std::uintptr_t; + using uint64_t = std::uint64_t; + + void *value alignas(_mlsAlignment); + + bool isInt63() const { return (reinterpret_cast(value) & 1) == 1; } + + bool isPtr() const { return (reinterpret_cast(value) & 1) == 0; } + + uint64_t asInt63() const { return reinterpret_cast(value) >> 1; } + + uintptr_t asRawInt() const { return reinterpret_cast(value); } + + static _mlsValue fromRawInt(uintptr_t i) { + return _mlsValue(reinterpret_cast(i)); + } + + static _mlsValue fromInt63(uint64_t i) { + return _mlsValue(reinterpret_cast((i << 1) | 1)); + } + + void *asPtr() const { + assert(!isInt63()); + return value; + } + + _mlsObject *asObject() const { + assert(isPtr()); + return static_cast<_mlsObject *>(value); + } + + bool eqInt63(const _mlsValue &other) const { + return asRawInt() == other.asRawInt(); + } + + _mlsValue addInt63(const _mlsValue &other) const { + return fromRawInt(asRawInt() + other.asRawInt() - 1); + } + + _mlsValue subInt63(const _mlsValue &other) const { + return fromRawInt(asRawInt() - other.asRawInt() + 1); + } + + _mlsValue mulInt63(const _mlsValue &other) const { + return fromInt63(asInt63() * other.asInt63()); + } + + _mlsValue divInt63(const _mlsValue &other) const { + return fromInt63(asInt63() / other.asInt63()); + } + + _mlsValue gtInt63(const _mlsValue &other) const { + return asInt63() > other.asInt63() ? _mlsValue::create<_mls_True>() + : _mlsValue::create<_mls_False>(); + } + + _mlsValue ltInt63(const _mlsValue &other) const { + return asInt63() < other.asInt63() ? _mlsValue::create<_mls_True>() + : _mlsValue::create<_mls_False>(); + } + + _mlsValue geInt63(const _mlsValue &other) const { + return asInt63() >= other.asInt63() ? _mlsValue::create<_mls_True>() + : _mlsValue::create<_mls_False>(); + } + + _mlsValue leInt63(const _mlsValue &other) const { + return asInt63() <= other.asInt63() ? _mlsValue::create<_mls_True>() + : _mlsValue::create<_mls_False>(); + } + +public: + explicit _mlsValue() : value(nullptr) {} + explicit _mlsValue(void *value) : value(value) {} + _mlsValue(const _mlsValue &other) : value(other.value) { + if (isPtr()) + asObject()->incRef(); + } + + _mlsValue &operator=(const _mlsValue &other) { + if (value != nullptr && isPtr()) + asObject()->decRef(); + value = other.value; + if (isPtr()) + asObject()->incRef(); + return *this; + } + + ~_mlsValue() { + if (isPtr()) + if (asObject()->decRef()) { + asObject()->destroy(); + value = nullptr; + } + } + + uint64_t asInt() const { + assert(isInt63()); + return asInt63(); + } + + static _mlsValue fromIntLit(uint64_t i) { return fromInt63(i); } + + template static tuple_type<_mlsValue, N> never() { + __builtin_unreachable(); + } + static _mlsValue never() { __builtin_unreachable(); } + + template static _mlsValue create(U... args) { + return _mlsValue(T::create(args...)); + } + + static void destroy(_mlsValue &v) { v.~_mlsValue(); } + + template static bool isValueOf(const _mlsValue &v) { + return v.asObject()->tag == T::typeTag; + } + + static bool isIntLit(const _mlsValue &v, uint64_t n) { + return v.asInt63() == n; + } + + static bool isIntLit(const _mlsValue &v) { return v.isInt63(); } + + template static T *as(const _mlsValue &v) { + return dynamic_cast(v.asObject()); + } + + template static T *cast(_mlsValue &v) { + return static_cast(v.asObject()); + } + + // Operators + + _mlsValue operator==(const _mlsValue &other) const { + if (isInt63() && other.isInt63()) + return eqInt63(other) ? _mlsValue::create<_mls_True>() + : _mlsValue::create<_mls_False>(); + assert(false); + } + + _mlsValue operator+(const _mlsValue &other) const { + if (isInt63() && other.isInt63()) + return addInt63(other); + assert(false); + } + + _mlsValue operator-(const _mlsValue &other) const { + if (isInt63() && other.isInt63()) + return subInt63(other); + assert(false); + } + + _mlsValue operator*(const _mlsValue &other) const { + if (isInt63() && other.isInt63()) + return mulInt63(other); + assert(false); + } + + _mlsValue operator/(const _mlsValue &other) const { + if (isInt63() && other.isInt63()) + return divInt63(other); + assert(false); + } + + _mlsValue operator>(const _mlsValue &other) const { + if (isInt63() && other.isInt63()) + return gtInt63(other); + assert(false); + } + + _mlsValue operator<(const _mlsValue &other) const { + if (isInt63() && other.isInt63()) + return ltInt63(other); + assert(false); + } + + _mlsValue operator>=(const _mlsValue &other) const { + if (isInt63() && other.isInt63()) + return geInt63(other); + assert(false); + } + + _mlsValue operator<=(const _mlsValue &other) const { + if (isInt63() && other.isInt63()) + return leInt63(other); + assert(false); + } + + // Auxiliary functions + + void print() const { + if (isInt63()) + std::printf("%" PRIu64, asInt63()); + else if (isPtr() && asObject()) + asObject()->print(); + } +}; + +struct _mls_Callable : public _mlsObject { + virtual _mlsValue _mls_apply0() { throw std::runtime_error("Not implemented"); } + virtual _mlsValue _mls_apply1(_mlsValue) { + throw std::runtime_error("Not implemented"); + } + virtual _mlsValue _mls_apply2(_mlsValue, _mlsValue) { + throw std::runtime_error("Not implemented"); + } + virtual _mlsValue _mls_apply3(_mlsValue, _mlsValue, _mlsValue) { + throw std::runtime_error("Not implemented"); + } + virtual _mlsValue _mls_apply4(_mlsValue, _mlsValue, _mlsValue, _mlsValue) { + throw std::runtime_error("Not implemented"); + } + virtual void destroy() override {} +}; + +inline static _mls_Callable *_mlsToCallable(_mlsValue fn) { + auto *ptr = _mlsValue::as<_mls_Callable>(fn); + if (!ptr) + throw std::runtime_error("Not a callable object"); + return ptr; +} + +template +inline static _mlsValue _mlsCall(_mlsValue f, U... args) { + static_assert(sizeof...(U) <= 4, "Too many arguments"); + if constexpr (sizeof...(U) == 0) + return _mlsToCallable(f)->_mls_apply0(); + else if constexpr (sizeof...(U) == 1) + return _mlsToCallable(f)->_mls_apply1(args...); + else if constexpr (sizeof...(U) == 2) + return _mlsToCallable(f)->_mls_apply2(args...); + else if constexpr (sizeof...(U) == 3) + return _mlsToCallable(f)->_mls_apply3(args...); + else if constexpr (sizeof...(U) == 4) + return _mlsToCallable(f)->_mls_apply4(args...); +} + +template +inline static T *_mlsMethodCall(_mlsValue self) { + auto *ptr = _mlsValue::as(self); + if (!ptr) + throw std::runtime_error("unable to convert object for method calls"); + return ptr; +} + +inline int _mlsLargeStack(void *(*fn)(void *)) { + pthread_t thread; + pthread_attr_t attr; + + size_t stacksize = 512 * 1024 * 1024; + pthread_attr_init(&attr); + pthread_attr_setstacksize(&attr, stacksize); + + int rc = pthread_create(&thread, &attr, fn, nullptr); + if (rc) { + printf("ERROR: return code from pthread_create() is %d\n", rc); + return 1; + } + pthread_join(thread, NULL); + return 0; +} + +_mlsValue _mlsMain(); + +inline void *_mlsMainWrapper(void *) { + _mlsValue res = _mlsMain(); + res.print(); + return nullptr; +} + +struct _mls_Unit final : public _mlsObject { + constexpr static inline const char *typeName = "Unit"; + constexpr static inline uint32_t typeTag = nextTypeTag(); + virtual void print() const override { std::printf(typeName); } + static _mlsValue create() { + static _mls_Unit mlsUnit alignas(_mlsAlignment); + mlsUnit.refCount = stickyRefCount; + mlsUnit.tag = typeTag; + return _mlsValue(&mlsUnit); + } + virtual void destroy() override {} +}; + +struct _mls_Boolean : public _mlsObject {}; + +struct _mls_True final : public _mls_Boolean { + constexpr static inline const char *typeName = "True"; + constexpr static inline uint32_t typeTag = nextTypeTag(); + virtual void print() const override { std::printf(typeName); } + static _mlsValue create() { + static _mls_True mlsTrue alignas(_mlsAlignment); + mlsTrue.refCount = stickyRefCount; + mlsTrue.tag = typeTag; + return _mlsValue(&mlsTrue); + } + virtual void destroy() override {} +}; + +struct _mls_False final : public _mls_Boolean { + constexpr static inline const char *typeName = "False"; + constexpr static inline uint32_t typeTag = nextTypeTag(); + virtual void print() const override { std::printf(typeName); } + static _mlsValue create() { + static _mls_False mlsFalse alignas(_mlsAlignment); + mlsFalse.refCount = stickyRefCount; + mlsFalse.tag = typeTag; + return _mlsValue(&mlsFalse); + } + virtual void destroy() override {} +}; + +#include + +struct _mls_ZInt final : public _mlsObject { + boost::multiprecision::mpz_int z; + constexpr static inline const char *typeName = "Z"; + constexpr static inline uint32_t typeTag = nextTypeTag(); + virtual void print() const override { + std::printf(typeName); + std::printf("("); + std::printf("%s", z.str().c_str()); + std::printf(")"); + } + virtual void destroy() override { + z.~number(); + operator delete(this, std::align_val_t(_mlsAlignment)); + } + static _mlsValue create() { + auto _mlsVal = new (std::align_val_t(_mlsAlignment)) _mls_ZInt; + _mlsVal->refCount = 1; + _mlsVal->tag = typeTag; + return _mlsValue(_mlsVal); + } + static _mlsValue create(_mlsValue z) { + auto _mlsVal = new (std::align_val_t(_mlsAlignment)) _mls_ZInt; + _mlsVal->z = z.asInt(); + _mlsVal->refCount = 1; + _mlsVal->tag = typeTag; + return _mlsValue(_mlsVal); + } + _mlsValue operator+(const _mls_ZInt &other) const { + auto _mlsVal = _mlsValue::create<_mls_ZInt>(); + _mlsValue::cast<_mls_ZInt>(_mlsVal)->z = z + other.z; + return _mlsVal; + } + + _mlsValue operator-(const _mls_ZInt &other) const { + auto _mlsVal = _mlsValue::create<_mls_ZInt>(); + _mlsValue::cast<_mls_ZInt>(_mlsVal)->z = z - other.z; + return _mlsVal; + } + + _mlsValue operator*(const _mls_ZInt &other) const { + auto _mlsVal = _mlsValue::create<_mls_ZInt>(); + _mlsValue::cast<_mls_ZInt>(_mlsVal)->z = z * other.z; + return _mlsVal; + } + + _mlsValue operator/(const _mls_ZInt &other) const { + auto _mlsVal = _mlsValue::create<_mls_ZInt>(); + _mlsValue::cast<_mls_ZInt>(_mlsVal)->z = z / other.z; + return _mlsVal; + } + + _mlsValue operator%(const _mls_ZInt &other) const { + auto _mlsVal = _mlsValue::create<_mls_ZInt>(); + _mlsValue::cast<_mls_ZInt>(_mlsVal)->z = z % other.z; + return _mlsVal; + } + + _mlsValue operator==(const _mls_ZInt &other) const { + return z == other.z ? _mlsValue::create<_mls_True>() + : _mlsValue::create<_mls_False>(); + } + + _mlsValue operator>(const _mls_ZInt &other) const { + return z > other.z ? _mlsValue::create<_mls_True>() + : _mlsValue::create<_mls_False>(); + } + + _mlsValue operator<(const _mls_ZInt &other) const { + return z < other.z ? _mlsValue::create<_mls_True>() + : _mlsValue::create<_mls_False>(); + } + + _mlsValue operator>=(const _mls_ZInt &other) const { + return z >= other.z ? _mlsValue::create<_mls_True>() + : _mlsValue::create<_mls_False>(); + } + + _mlsValue operator<=(const _mls_ZInt &other) const { + return z <= other.z ? _mlsValue::create<_mls_True>() + : _mlsValue::create<_mls_False>(); + } + + _mlsValue toInt() const { + return _mlsValue::fromIntLit(z.convert_to()); + } + + static _mlsValue fromInt(uint64_t i) { + return _mlsValue::create<_mls_ZInt>(_mlsValue::fromIntLit(i)); + } +}; + +__attribute__((noinline)) inline void _mlsNonExhaustiveMatch() { + throw std::runtime_error("Non-exhaustive match"); +} + +inline _mlsValue _mls_builtin_z_add(_mlsValue a, _mlsValue b) { + assert(_mlsValue::isValueOf<_mls_ZInt>(a)); + assert(_mlsValue::isValueOf<_mls_ZInt>(b)); + return *_mlsValue::cast<_mls_ZInt>(a) + *_mlsValue::cast<_mls_ZInt>(b); +} + +inline _mlsValue _mls_builtin_z_sub(_mlsValue a, _mlsValue b) { + assert(_mlsValue::isValueOf<_mls_ZInt>(a)); + assert(_mlsValue::isValueOf<_mls_ZInt>(b)); + return *_mlsValue::cast<_mls_ZInt>(a) - *_mlsValue::cast<_mls_ZInt>(b); +} + +inline _mlsValue _mls_builtin_z_mul(_mlsValue a, _mlsValue b) { + assert(_mlsValue::isValueOf<_mls_ZInt>(a)); + assert(_mlsValue::isValueOf<_mls_ZInt>(b)); + return *_mlsValue::cast<_mls_ZInt>(a) * *_mlsValue::cast<_mls_ZInt>(b); +} + +inline _mlsValue _mls_builtin_z_div(_mlsValue a, _mlsValue b) { + assert(_mlsValue::isValueOf<_mls_ZInt>(a)); + assert(_mlsValue::isValueOf<_mls_ZInt>(b)); + return *_mlsValue::cast<_mls_ZInt>(a) / *_mlsValue::cast<_mls_ZInt>(b); +} + +inline _mlsValue _mls_builtin_z_mod(_mlsValue a, _mlsValue b) { + assert(_mlsValue::isValueOf<_mls_ZInt>(a)); + assert(_mlsValue::isValueOf<_mls_ZInt>(b)); + return *_mlsValue::cast<_mls_ZInt>(a) % *_mlsValue::cast<_mls_ZInt>(b); +} + +inline _mlsValue _mls_builtin_z_equal(_mlsValue a, _mlsValue b) { + assert(_mlsValue::isValueOf<_mls_ZInt>(a)); + assert(_mlsValue::isValueOf<_mls_ZInt>(b)); + return *_mlsValue::cast<_mls_ZInt>(a) == *_mlsValue::cast<_mls_ZInt>(b); +} + +inline _mlsValue _mls_builtin_z_gt(_mlsValue a, _mlsValue b) { + assert(_mlsValue::isValueOf<_mls_ZInt>(a)); + assert(_mlsValue::isValueOf<_mls_ZInt>(b)); + return *_mlsValue::cast<_mls_ZInt>(a) > *_mlsValue::cast<_mls_ZInt>(b); +} + +inline _mlsValue _mls_builtin_z_lt(_mlsValue a, _mlsValue b) { + assert(_mlsValue::isValueOf<_mls_ZInt>(a)); + assert(_mlsValue::isValueOf<_mls_ZInt>(b)); + return *_mlsValue::cast<_mls_ZInt>(a) < *_mlsValue::cast<_mls_ZInt>(b); +} + +inline _mlsValue _mls_builtin_z_geq(_mlsValue a, _mlsValue b) { + assert(_mlsValue::isValueOf<_mls_ZInt>(a)); + assert(_mlsValue::isValueOf<_mls_ZInt>(b)); + return *_mlsValue::cast<_mls_ZInt>(a) >= *_mlsValue::cast<_mls_ZInt>(b); +} + +inline _mlsValue _mls_builtin_z_leq(_mlsValue a, _mlsValue b) { + assert(_mlsValue::isValueOf<_mls_ZInt>(a)); + assert(_mlsValue::isValueOf<_mls_ZInt>(b)); + return *_mlsValue::cast<_mls_ZInt>(a) <= *_mlsValue::cast<_mls_ZInt>(b); +} + +inline _mlsValue _mls_builtin_z_to_int(_mlsValue a) { + assert(_mlsValue::isValueOf<_mls_ZInt>(a)); + return _mlsValue::cast<_mls_ZInt>(a)->toInt(); +} + +inline _mlsValue _mls_builtin_z_of_int(_mlsValue a) { + assert(_mlsValue::isIntLit(a)); + return _mlsValue::create<_mls_ZInt>(a); +} + +inline _mlsValue _mls_builtin_print(_mlsValue a) { + a.print(); + return _mlsValue::create<_mls_Unit>(); +} + +inline _mlsValue _mls_builtin_println(_mlsValue a) { + a.print(); + std::puts(""); + return _mlsValue::create<_mls_Unit>(); +} + +inline _mlsValue _mls_builtin_debug(_mlsValue a) { + a.print(); + std::puts(""); + return a; +} diff --git a/hkmc2/shared/src/test/mlscript/llir/Playground.mls b/hkmc2/shared/src/test/mlscript/llir/Playground.mls index 4a4a1f3083..ae496abdc8 100644 --- a/hkmc2/shared/src/test/mlscript/llir/Playground.mls +++ b/hkmc2/shared/src/test/mlscript/llir/Playground.mls @@ -281,6 +281,14 @@ f5() //│ Interpreted: //│ 5 +:rcpp +1 +//│ = 1 +//│ +//│ +//│ Execution succeeded: +//│ 1 + :sllir :scpp fun test() = From 35f734637cec3b453712a044720cf756b4fd3abd Mon Sep 17 00:00:00 2001 From: waterlens Date: Wed, 15 Jan 2025 21:55:51 +0800 Subject: [PATCH 18/88] Fix --- hkmc2/jvm/src/test/scala/hkmc2/LlirDiffMaker.scala | 4 ++-- hkmc2/shared/src/test/mlscript/llir/BadPrograms.mls | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/hkmc2/jvm/src/test/scala/hkmc2/LlirDiffMaker.scala b/hkmc2/jvm/src/test/scala/hkmc2/LlirDiffMaker.scala index db6ae399ff..d5f3578c95 100644 --- a/hkmc2/jvm/src/test/scala/hkmc2/LlirDiffMaker.scala +++ b/hkmc2/jvm/src/test/scala/hkmc2/LlirDiffMaker.scala @@ -48,7 +48,7 @@ abstract class LlirDiffMaker extends BbmlDiffMaker: output("\nCpp:") output(cpp.toDocument.toString) if rcpp.isSet then - val auxPath = os.pwd/os.up/"shared"/"src"/"test"/"mlscript-compile"/"cpp" + val auxPath = os.pwd/"hkmc2"/"shared"/"src"/"test"/"mlscript-compile"/"cpp" val cppHost = CppCompilerHost(auxPath.toString, output.apply) if !cppHost.ready then output("\nCpp Compilation Failed: Cpp compiler or GNU Make not found") @@ -62,4 +62,4 @@ abstract class LlirDiffMaker extends BbmlDiffMaker: catch case e: LowLevelIRError => output("Stopped due to an error during the Llir generation") - + diff --git a/hkmc2/shared/src/test/mlscript/llir/BadPrograms.mls b/hkmc2/shared/src/test/mlscript/llir/BadPrograms.mls index 0cd5a8212d..5aa3264fc7 100644 --- a/hkmc2/shared/src/test/mlscript/llir/BadPrograms.mls +++ b/hkmc2/shared/src/test/mlscript/llir/BadPrograms.mls @@ -3,17 +3,17 @@ :llir :cpp +:ge fun oops(a) = class A with fun m = a let x = 1 -//│ FAILURE: Unexpected runtime error //│ ═══[COMPILATION ERROR] Non top-level definition A not supported //│ Stopped due to an error during the Llir generation +:ge let x = "oops" x.m -//│ FAILURE: Unexpected runtime error //│ ═══[COMPILATION ERROR] Unsupported selection by users //│ Stopped due to an error during the Llir generation From 7ff48a7c4caf896542d45f7599274498723b4aed Mon Sep 17 00:00:00 2001 From: waterlens Date: Thu, 16 Jan 2025 14:18:27 +0800 Subject: [PATCH 19/88] Add wcpp option; Change bool implementation --- .../src/test/scala/hkmc2/LlirDiffMaker.scala | 12 +++- .../test/mlscript-compile/cpp/mlsprelude.h | 65 ++++--------------- 2 files changed, 24 insertions(+), 53 deletions(-) diff --git a/hkmc2/jvm/src/test/scala/hkmc2/LlirDiffMaker.scala b/hkmc2/jvm/src/test/scala/hkmc2/LlirDiffMaker.scala index d5f3578c95..01462854e6 100644 --- a/hkmc2/jvm/src/test/scala/hkmc2/LlirDiffMaker.scala +++ b/hkmc2/jvm/src/test/scala/hkmc2/LlirDiffMaker.scala @@ -24,6 +24,12 @@ abstract class LlirDiffMaker extends BbmlDiffMaker: val scpp = NullaryCommand("scpp") val rcpp = NullaryCommand("rcpp") val intl = NullaryCommand("intl") + val wcpp = Command[Str]("wcpp", false)(x => x.stripLeading()) + + def printToFile(f: java.io.File)(op: java.io.PrintWriter => Unit) = { + val p = new java.io.PrintWriter(f) + try { op(p) } finally { p.close() } + } override def processTerm(trm: Blk, inImport: Bool)(using Raise): Unit = super.processTerm(trm, inImport) @@ -42,11 +48,15 @@ abstract class LlirDiffMaker extends BbmlDiffMaker: if sllir.isSet then output("LLIR:") output(llirProg.show()) - if cpp.isSet || scpp.isSet || rcpp.isSet then + if cpp.isSet || scpp.isSet || rcpp.isSet || wcpp.isSet then val cpp = codegen.cpp.CppCodeGen.codegen(llirProg) if scpp.isSet then output("\nCpp:") output(cpp.toDocument.toString) + if wcpp.isSet then + printToFile(java.io.File(s"hkmc2/shared/src/test/mlscript-compile/cpp/${wcpp.get.get}.cpp")) { p => + p.println(cpp.toDocument.toString) + } if rcpp.isSet then val auxPath = os.pwd/"hkmc2"/"shared"/"src"/"test"/"mlscript-compile"/"cpp" val cppHost = CppCompilerHost(auxPath.toString, output.apply) diff --git a/hkmc2/shared/src/test/mlscript-compile/cpp/mlsprelude.h b/hkmc2/shared/src/test/mlscript-compile/cpp/mlsprelude.h index 8415951c93..fed52549bb 100644 --- a/hkmc2/shared/src/test/mlscript-compile/cpp/mlsprelude.h +++ b/hkmc2/shared/src/test/mlscript-compile/cpp/mlsprelude.h @@ -67,9 +67,6 @@ struct _mlsObject { virtual void destroy() = 0; }; -struct _mls_True; -struct _mls_False; - class _mlsValue { using uintptr_t = std::uintptr_t; using uint64_t = std::uint64_t; @@ -123,23 +120,19 @@ class _mlsValue { } _mlsValue gtInt63(const _mlsValue &other) const { - return asInt63() > other.asInt63() ? _mlsValue::create<_mls_True>() - : _mlsValue::create<_mls_False>(); + return _mlsValue::fromBoolLit(asInt63() > other.asInt63()); } _mlsValue ltInt63(const _mlsValue &other) const { - return asInt63() < other.asInt63() ? _mlsValue::create<_mls_True>() - : _mlsValue::create<_mls_False>(); + return _mlsValue::fromBoolLit(asInt63() < other.asInt63()); } _mlsValue geInt63(const _mlsValue &other) const { - return asInt63() >= other.asInt63() ? _mlsValue::create<_mls_True>() - : _mlsValue::create<_mls_False>(); + return _mlsValue::fromBoolLit(asInt63() >= other.asInt63()); } _mlsValue leInt63(const _mlsValue &other) const { - return asInt63() <= other.asInt63() ? _mlsValue::create<_mls_True>() - : _mlsValue::create<_mls_False>(); + return _mlsValue::fromBoolLit(asInt63() <= other.asInt63()); } public: @@ -174,6 +167,8 @@ class _mlsValue { static _mlsValue fromIntLit(uint64_t i) { return fromInt63(i); } + static _mlsValue fromBoolLit(bool b) { return fromInt63(b); } + template static tuple_type<_mlsValue, N> never() { __builtin_unreachable(); } @@ -207,8 +202,7 @@ class _mlsValue { _mlsValue operator==(const _mlsValue &other) const { if (isInt63() && other.isInt63()) - return eqInt63(other) ? _mlsValue::create<_mls_True>() - : _mlsValue::create<_mls_False>(); + return _mlsValue::fromBoolLit(eqInt63(other)); assert(false); } @@ -355,34 +349,6 @@ struct _mls_Unit final : public _mlsObject { virtual void destroy() override {} }; -struct _mls_Boolean : public _mlsObject {}; - -struct _mls_True final : public _mls_Boolean { - constexpr static inline const char *typeName = "True"; - constexpr static inline uint32_t typeTag = nextTypeTag(); - virtual void print() const override { std::printf(typeName); } - static _mlsValue create() { - static _mls_True mlsTrue alignas(_mlsAlignment); - mlsTrue.refCount = stickyRefCount; - mlsTrue.tag = typeTag; - return _mlsValue(&mlsTrue); - } - virtual void destroy() override {} -}; - -struct _mls_False final : public _mls_Boolean { - constexpr static inline const char *typeName = "False"; - constexpr static inline uint32_t typeTag = nextTypeTag(); - virtual void print() const override { std::printf(typeName); } - static _mlsValue create() { - static _mls_False mlsFalse alignas(_mlsAlignment); - mlsFalse.refCount = stickyRefCount; - mlsFalse.tag = typeTag; - return _mlsValue(&mlsFalse); - } - virtual void destroy() override {} -}; - #include struct _mls_ZInt final : public _mlsObject { @@ -402,7 +368,7 @@ struct _mls_ZInt final : public _mlsObject { static _mlsValue create() { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) _mls_ZInt; _mlsVal->refCount = 1; - _mlsVal->tag = typeTag; + _mlsVal->tag = typeTag; return _mlsValue(_mlsVal); } static _mlsValue create(_mlsValue z) { @@ -443,28 +409,23 @@ struct _mls_ZInt final : public _mlsObject { } _mlsValue operator==(const _mls_ZInt &other) const { - return z == other.z ? _mlsValue::create<_mls_True>() - : _mlsValue::create<_mls_False>(); + return _mlsValue::fromBoolLit(z == other.z); } _mlsValue operator>(const _mls_ZInt &other) const { - return z > other.z ? _mlsValue::create<_mls_True>() - : _mlsValue::create<_mls_False>(); + return _mlsValue::fromBoolLit(z > other.z); } _mlsValue operator<(const _mls_ZInt &other) const { - return z < other.z ? _mlsValue::create<_mls_True>() - : _mlsValue::create<_mls_False>(); + return _mlsValue::fromBoolLit(z < other.z); } _mlsValue operator>=(const _mls_ZInt &other) const { - return z >= other.z ? _mlsValue::create<_mls_True>() - : _mlsValue::create<_mls_False>(); + return _mlsValue::fromBoolLit(z >= other.z); } _mlsValue operator<=(const _mls_ZInt &other) const { - return z <= other.z ? _mlsValue::create<_mls_True>() - : _mlsValue::create<_mls_False>(); + return _mlsValue::fromBoolLit(z <= other.z); } _mlsValue toInt() const { From 9a41b6a94d537e46f0a60046292ae24024b773c4 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Thu, 16 Jan 2025 14:48:10 +0800 Subject: [PATCH 20/88] Try with new CI/nix versions --- .github/workflows/nix.yml | 2 +- flake.nix | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/nix.yml b/.github/workflows/nix.yml index 044e4df66e..6700307686 100644 --- a/.github/workflows/nix.yml +++ b/.github/workflows/nix.yml @@ -18,7 +18,7 @@ jobs: - name: Install TypeScript run: npm ci - name: Run test - run: sbt -J-Xmx4096M -J-Xss4M test + run: sbt -J-Xmx4096M -J-Xss8M test - name: Check no changes run: | git update-index -q --refresh diff --git a/flake.nix b/flake.nix index 5f81da24a5..8e657face9 100644 --- a/flake.nix +++ b/flake.nix @@ -11,7 +11,7 @@ (system: let sbtOverlay = self: super: { - sbt = super.sbt.override { jre = super.jdk8_headless; }; + sbt = super.sbt.override { jre = super.jdk11_headless; }; }; pkgs = import nixpkgs { inherit system; From b6eb77e0fad04da970de1cb4f721262455a9f0e3 Mon Sep 17 00:00:00 2001 From: waterlens Date: Thu, 16 Jan 2025 15:54:04 +0800 Subject: [PATCH 21/88] Fix silly path --- hkmc2/jvm/src/test/scala/hkmc2/LlirDiffMaker.scala | 10 ++++------ hkmc2/shared/src/test/mlscript/llir/Playground.mls | 8 -------- 2 files changed, 4 insertions(+), 14 deletions(-) diff --git a/hkmc2/jvm/src/test/scala/hkmc2/LlirDiffMaker.scala b/hkmc2/jvm/src/test/scala/hkmc2/LlirDiffMaker.scala index 01462854e6..ef93178282 100644 --- a/hkmc2/jvm/src/test/scala/hkmc2/LlirDiffMaker.scala +++ b/hkmc2/jvm/src/test/scala/hkmc2/LlirDiffMaker.scala @@ -26,10 +26,9 @@ abstract class LlirDiffMaker extends BbmlDiffMaker: val intl = NullaryCommand("intl") val wcpp = Command[Str]("wcpp", false)(x => x.stripLeading()) - def printToFile(f: java.io.File)(op: java.io.PrintWriter => Unit) = { + def printToFile(f: java.io.File)(op: java.io.PrintWriter => Unit) = val p = new java.io.PrintWriter(f) try { op(p) } finally { p.close() } - } override def processTerm(trm: Blk, inImport: Bool)(using Raise): Unit = super.processTerm(trm, inImport) @@ -53,12 +52,11 @@ abstract class LlirDiffMaker extends BbmlDiffMaker: if scpp.isSet then output("\nCpp:") output(cpp.toDocument.toString) + val auxPath = os.Path(rootPath) / "hkmc2"/"shared"/"src"/"test"/"mlscript-compile"/"cpp" if wcpp.isSet then - printToFile(java.io.File(s"hkmc2/shared/src/test/mlscript-compile/cpp/${wcpp.get.get}.cpp")) { p => - p.println(cpp.toDocument.toString) - } + printToFile(java.io.File((auxPath / s"${wcpp.get.get}.cpp").toString)): + p => p.println(cpp.toDocument.toString) if rcpp.isSet then - val auxPath = os.pwd/"hkmc2"/"shared"/"src"/"test"/"mlscript-compile"/"cpp" val cppHost = CppCompilerHost(auxPath.toString, output.apply) if !cppHost.ready then output("\nCpp Compilation Failed: Cpp compiler or GNU Make not found") diff --git a/hkmc2/shared/src/test/mlscript/llir/Playground.mls b/hkmc2/shared/src/test/mlscript/llir/Playground.mls index ae496abdc8..4a4a1f3083 100644 --- a/hkmc2/shared/src/test/mlscript/llir/Playground.mls +++ b/hkmc2/shared/src/test/mlscript/llir/Playground.mls @@ -281,14 +281,6 @@ f5() //│ Interpreted: //│ 5 -:rcpp -1 -//│ = 1 -//│ -//│ -//│ Execution succeeded: -//│ 1 - :sllir :scpp fun test() = From 376ad91b8f8fc93ede0fb33ebe4b44227084800d Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Thu, 16 Jan 2025 17:03:32 +0800 Subject: [PATCH 22/88] Add some problematic examples --- .../src/test/mlscript/llir/Playground.mls | 111 ++++++++++++++++++ 1 file changed, 111 insertions(+) diff --git a/hkmc2/shared/src/test/mlscript/llir/Playground.mls b/hkmc2/shared/src/test/mlscript/llir/Playground.mls index 4a4a1f3083..ed8f150528 100644 --- a/hkmc2/shared/src/test/mlscript/llir/Playground.mls +++ b/hkmc2/shared/src/test/mlscript/llir/Playground.mls @@ -1,6 +1,7 @@ :js :llir + :sllir abstract class Option[out T]: Some[T] | None class Some[out T](x: T) extends Option[T] @@ -375,3 +376,113 @@ fun test() = //│ } //│ int main() { return _mlsLargeStack(_mlsMainWrapper); } + +// FIXME: this fails C++ compilation +// :rcpp +:sllir +:scpp +let x = 10 +if true do + set x += 1 +x +//│ = 11 +//│ x = 11 +//│ LLIR: +//│ +//│ def j$0(x$2) = +//│ x$2 +//│ let x$0 = 10 in +//│ let x$1 = true in +//│ case x$1 of +//│ BoolLit(true) => +//│ let x$3 = +(x$2,1) in +//│ let x$4 = undefined in +//│ jump j$0(x$3) +//│ _ => +//│ let x$5 = undefined in +//│ jump j$0(x$2) +//│ +//│ Cpp: +//│ #include "mlsprelude.h" +//│ _mlsValue _mls_j_0(_mlsValue); +//│ _mlsValue _mlsMain(); +//│ _mlsValue _mls_j_0(_mlsValue _mls_x_2) { +//│ _mlsValue _mls_retval; +//│ _mls_retval = _mls_x_2; +//│ return _mls_retval; +//│ } +//│ _mlsValue _mlsMain() { +//│ _mlsValue _mls_retval; +//│ auto _mls_x_0 = _mlsValue::fromIntLit(10); +//│ auto _mls_x_1 = _mlsValue::fromIntLit(1); +//│ if (_mlsValue::isIntLit(_mls_x_1, 1)) { +//│ auto _mls_x_3 = (_mls_x_2 + _mlsValue::fromIntLit(1)); +//│ auto _mls_x_4 = _mlsValue::create<_mls_Unit>(); +//│ _mls_retval = _mls_j_0(_mls_x_3); +//│ } else { +//│ auto _mls_x_5 = _mlsValue::create<_mls_Unit>(); +//│ _mls_retval = _mls_j_0(_mls_x_2); +//│ } +//│ return _mls_retval; +//│ } +//│ int main() { return _mlsLargeStack(_mlsMainWrapper); } + + +// TODO: catch this early in the pipeline (currently it fails the C++ compilation) +// :rcpp +:sllir +:scpp +fun foo(a) = + let x + if a > 0 do + x = 1 + x + 1 +//│ LLIR: +//│ +//│ def foo(a) = +//│ let x$0 = >(a,0) in +//│ case x$0 of +//│ BoolLit(true) => +//│ let x$2 = 1 in +//│ let x$3 = undefined in +//│ jump j$0(x$2) +//│ _ => +//│ let x$4 = undefined in +//│ jump j$0(x$1) +//│ def j$0(x$1) = +//│ let x$5 = +(x$1,1) in +//│ x$5 +//│ undefined +//│ +//│ Cpp: +//│ #include "mlsprelude.h" +//│ _mlsValue _mls_j_0(_mlsValue); +//│ _mlsValue _mls_foo(_mlsValue); +//│ _mlsValue _mlsMain(); +//│ _mlsValue _mls_j_0(_mlsValue _mls_x_1) { +//│ _mlsValue _mls_retval; +//│ auto _mls_x_5 = (_mls_x_1 + _mlsValue::fromIntLit(1)); +//│ _mls_retval = _mls_x_5; +//│ return _mls_retval; +//│ } +//│ _mlsValue _mls_foo(_mlsValue _mls_a) { +//│ _mlsValue _mls_retval; +//│ auto _mls_x_0 = (_mls_a > _mlsValue::fromIntLit(0)); +//│ if (_mlsValue::isIntLit(_mls_x_0, 1)) { +//│ auto _mls_x_2 = _mlsValue::fromIntLit(1); +//│ auto _mls_x_3 = _mlsValue::create<_mls_Unit>(); +//│ _mls_retval = _mls_j_0(_mls_x_2); +//│ } else { +//│ auto _mls_x_4 = _mlsValue::create<_mls_Unit>(); +//│ _mls_retval = _mls_j_0(_mls_x_1); +//│ } +//│ return _mls_retval; +//│ } +//│ _mlsValue _mlsMain() { +//│ _mlsValue _mls_retval; +//│ _mls_retval = _mlsValue::create<_mls_Unit>(); +//│ return _mls_retval; +//│ } +//│ int main() { return _mlsLargeStack(_mlsMainWrapper); } + + From a46ba4ee6f7b3bd099973dc166f4bfbbd6d24411 Mon Sep 17 00:00:00 2001 From: waterlens Date: Thu, 16 Jan 2025 18:52:22 +0800 Subject: [PATCH 23/88] stop early; fix wrong ctx passing --- .../scala/hkmc2/codegen/llir/Builder.scala | 36 +++--- .../scala/hkmc2/codegen/llir/Interp.scala | 1 - .../src/test/mlscript/llir/BadPrograms.mls | 9 +- .../src/test/mlscript/llir/Playground.mls | 104 +++++------------- 4 files changed, 53 insertions(+), 97 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala index 6a73759917..06caaffced 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala @@ -38,19 +38,19 @@ final case class Ctx( def addFuncName(n: Local, m: Name) = copy(fn_ctx = fn_ctx + (n -> m)) def findFuncName(n: Local)(using Raise) = fn_ctx.get(n) match case None => - err(msg"Function name not found: ${n.toString()}") + errStop(msg"Function name not found: ${n.toString()}") Name("error") case Some(value) => value def addClassName(n: Local, m: Name) = copy(class_ctx = class_ctx + (n -> m)) def findClassName(n: Local)(using Raise) = class_ctx.get(n) match case None => - err(msg"Class name not found: ${n.toString()}") + errStop(msg"Class name not found: ${n.toString()}") Name("error") case Some(value) => value def addName(n: Str, m: Name) = copy(symbol_ctx = symbol_ctx + (n -> m)) def findName(n: Str)(using Raise): Name = symbol_ctx.get(n) match case None => - err(msg"Name not found: $n") + errStop(msg"Name not found: $n") Name("error") case Some(value) => value def reset = @@ -88,7 +88,6 @@ final class LlirBuilder(tl: TraceLogger)(fresh: Fresh, fnUid: FreshInt, clsUid: ts.id.name case ts: semantics.BlockMemberSymbol => // this means it's a locally-defined member ts.nme - // ts.trmTree case ts: semantics.InnerSymbol => summon[Scope].findThis_!(ts) case _ => summon[Scope].lookup_!(l) @@ -161,10 +160,10 @@ final class LlirBuilder(tl: TraceLogger)(fresh: Fresh, fnUid: FreshInt, clsUid: trace[Node](s"bValue begin", x => s"bValue end: ${x.show}"): v match case Value.Ref(l) => k(ctx.findName(getVar_!(l)) |> sr) - case Value.This(sym) => err(msg"Unsupported value: This"); Node.Result(Ls()) + case Value.This(sym) => errStop(msg"Unsupported value: This"); Node.Result(Ls()) case Value.Lit(lit) => k(Expr.Literal(lit)) - case Value.Lam(params, body) => err(msg"Unsupported value: Lam"); Node.Result(Ls()) - case Value.Arr(elems) => err(msg"Unsupported value: Arr"); Node.Result(Ls()) + case Value.Lam(params, body) => errStop(msg"Unsupported value: Lam"); Node.Result(Ls()) + case Value.Arr(elems) => errStop(msg"Unsupported value: Arr"); Node.Result(Ls()) private def getClassOfMem(p: FieldSymbol)(using ctx: Ctx)(using Raise, Scope): Local = trace[Local](s"bMemSym begin", x => s"bMemSym end: $x"): @@ -192,7 +191,7 @@ final class LlirBuilder(tl: TraceLogger)(fresh: Fresh, fnUid: FreshInt, clsUid: val field = name.name Node.LetExpr(v, Expr.Select(q.name, cls, field), k(v |> sr)) case q: Expr.Literal => - err(msg"Unsupported select on literal") + errStop(msg"Unsupported select on literal") Node.Result(Ls()) case x: Value => bValue(x)(k) @@ -239,7 +238,7 @@ final class LlirBuilder(tl: TraceLogger)(fresh: Fresh, fnUid: FreshInt, clsUid: val v = fresh.make Node.LetExpr(v, Expr.CtorApp(ClassRef.fromName(name.name), args), k(v |> sr)) case Instantiate(cls, args) => - err(msg"Unsupported kind of Instantiate") + errStop(msg"Unsupported kind of Instantiate") Node.Result(Ls()) case x: Path => bPath(x)(k) @@ -250,31 +249,28 @@ final class LlirBuilder(tl: TraceLogger)(fresh: Fresh, fnUid: FreshInt, clsUid: bPath(scrut): case e: TrivialExpr => val jp = fresh.make("j") - // guess: the value of Match itself in Block is useless - // val res = fresh.make val fvset = (rest.freeVars -- rest.definedVars).map(allocIfNew) val fvs1 = fvset.toList val new_ctx = fvs1.foldLeft(ctx)((acc, x) => acc.addName(x, fresh.make)) val fvs = fvs1.map(new_ctx.findName(_)) - def cont(x: TrivialExpr)(using Ctx) = Node.Jump( + def cont(x: TrivialExpr)(using ctx: Ctx) = Node.Jump( FuncRef.fromName(jp), - /* x :: */ fvs1.map(x => summon[Ctx].findName(x)).map(sr) + fvs1.map(x => ctx.findName(x)).map(sr) ) - given Ctx = new_ctx val casesList: Ls[(Pat, Node)] = arms.map: case (Case.Lit(lit), body) => - (Pat.Lit(lit), bBlock(body)(cont)) + (Pat.Lit(lit), bBlock(body)(cont)(using ctx)) case (Case.Cls(cls, _), body) => - (Pat.Class(ClassRef.fromName(cls.nme)), bBlock(body)(cont)) + (Pat.Class(ClassRef.fromName(cls.nme)), bBlock(body)(cont)(using ctx)) case (Case.Tup(len, inf), body) => - (Pat.Class(ClassRef.fromName("Tuple" + len.toString())), bBlock(body)(cont)) + (Pat.Class(ClassRef.fromName("Tuple" + len.toString())), bBlock(body)(cont)(using ctx)) val defaultCase = dflt.map(bBlock(_)(cont)) val jpdef = Func( fnUid.make, jp.str, - params = /* res :: */ fvs, + params = fvs, resultNum = 1, - bBlock(rest)(k), + bBlock(rest)(k)(using new_ctx), ) summon[Ctx].def_acc += jpdef Node.Case(e, casesList, defaultCase) @@ -319,7 +315,7 @@ final class LlirBuilder(tl: TraceLogger)(fresh: Fresh, fnUid: FreshInt, clsUid: case End(msg) => k(Expr.Literal(Tree.UnitLit(false))) case _: Block => val docBlock = blk.showAsTree - err(msg"Unsupported block: $docBlock") + errStop(msg"Unsupported block: $docBlock") Node.Result(Ls()) def bProg(e: Program)(using Raise, Scope): LlirProgram = diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Interp.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Interp.scala index 60ab4cca16..4f5416d1f3 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Interp.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Interp.scala @@ -184,7 +184,6 @@ class Interpreter(verbose: Bool): ctx2 = ctx.copy(bindingCtx = ctx.bindingCtx ++ names.map{_.str}.zip(ys)) res <- eval(body)(using ctx2) yield res - // case LetApply(names, fn, args, body) => eval(LetMethodCall(names, ClassRef(R("Callable")), Name("apply" + args.length), (Ref(fn): TrivialExpr) :: args, body)) case LetCall(names, func, args, body) => for xs <- evalArgs(args) diff --git a/hkmc2/shared/src/test/mlscript/llir/BadPrograms.mls b/hkmc2/shared/src/test/mlscript/llir/BadPrograms.mls index 5aa3264fc7..ec2a852a72 100644 --- a/hkmc2/shared/src/test/mlscript/llir/BadPrograms.mls +++ b/hkmc2/shared/src/test/mlscript/llir/BadPrograms.mls @@ -17,4 +17,11 @@ x.m //│ ═══[COMPILATION ERROR] Unsupported selection by users //│ Stopped due to an error during the Llir generation - +:ge +fun foo(a) = + let x + if a > 0 do + x = 1 + x + 1 +//│ ═══[COMPILATION ERROR] Name not found: x +//│ Stopped due to an error during the Llir generation diff --git a/hkmc2/shared/src/test/mlscript/llir/Playground.mls b/hkmc2/shared/src/test/mlscript/llir/Playground.mls index ed8f150528..a0bce1b917 100644 --- a/hkmc2/shared/src/test/mlscript/llir/Playground.mls +++ b/hkmc2/shared/src/test/mlscript/llir/Playground.mls @@ -377,112 +377,66 @@ fun test() = //│ int main() { return _mlsLargeStack(_mlsMainWrapper); } -// FIXME: this fails C++ compilation -// :rcpp :sllir +:intl :scpp -let x = 10 -if true do - set x += 1 -x +fun f() = + let x = 10 + if true do + set x += 1 + x +f() //│ = 11 -//│ x = 11 //│ LLIR: //│ +//│ def f() = +//│ let x$0 = 10 in +//│ let x$1 = true in +//│ case x$1 of +//│ BoolLit(true) => +//│ let x$3 = +(x$0,1) in +//│ let x$4 = undefined in +//│ jump j$0(x$3) +//│ _ => +//│ let x$5 = undefined in +//│ jump j$0(x$0) //│ def j$0(x$2) = //│ x$2 -//│ let x$0 = 10 in -//│ let x$1 = true in -//│ case x$1 of -//│ BoolLit(true) => -//│ let x$3 = +(x$2,1) in -//│ let x$4 = undefined in -//│ jump j$0(x$3) -//│ _ => -//│ let x$5 = undefined in -//│ jump j$0(x$2) +//│ let* (x$6) = f() in +//│ x$6 //│ //│ Cpp: //│ #include "mlsprelude.h" //│ _mlsValue _mls_j_0(_mlsValue); +//│ _mlsValue _mls_f(); //│ _mlsValue _mlsMain(); //│ _mlsValue _mls_j_0(_mlsValue _mls_x_2) { //│ _mlsValue _mls_retval; //│ _mls_retval = _mls_x_2; //│ return _mls_retval; //│ } -//│ _mlsValue _mlsMain() { +//│ _mlsValue _mls_f() { //│ _mlsValue _mls_retval; //│ auto _mls_x_0 = _mlsValue::fromIntLit(10); //│ auto _mls_x_1 = _mlsValue::fromIntLit(1); //│ if (_mlsValue::isIntLit(_mls_x_1, 1)) { -//│ auto _mls_x_3 = (_mls_x_2 + _mlsValue::fromIntLit(1)); +//│ auto _mls_x_3 = (_mls_x_0 + _mlsValue::fromIntLit(1)); //│ auto _mls_x_4 = _mlsValue::create<_mls_Unit>(); //│ _mls_retval = _mls_j_0(_mls_x_3); //│ } else { //│ auto _mls_x_5 = _mlsValue::create<_mls_Unit>(); -//│ _mls_retval = _mls_j_0(_mls_x_2); -//│ } -//│ return _mls_retval; -//│ } -//│ int main() { return _mlsLargeStack(_mlsMainWrapper); } - - -// TODO: catch this early in the pipeline (currently it fails the C++ compilation) -// :rcpp -:sllir -:scpp -fun foo(a) = - let x - if a > 0 do - x = 1 - x + 1 -//│ LLIR: -//│ -//│ def foo(a) = -//│ let x$0 = >(a,0) in -//│ case x$0 of -//│ BoolLit(true) => -//│ let x$2 = 1 in -//│ let x$3 = undefined in -//│ jump j$0(x$2) -//│ _ => -//│ let x$4 = undefined in -//│ jump j$0(x$1) -//│ def j$0(x$1) = -//│ let x$5 = +(x$1,1) in -//│ x$5 -//│ undefined -//│ -//│ Cpp: -//│ #include "mlsprelude.h" -//│ _mlsValue _mls_j_0(_mlsValue); -//│ _mlsValue _mls_foo(_mlsValue); -//│ _mlsValue _mlsMain(); -//│ _mlsValue _mls_j_0(_mlsValue _mls_x_1) { -//│ _mlsValue _mls_retval; -//│ auto _mls_x_5 = (_mls_x_1 + _mlsValue::fromIntLit(1)); -//│ _mls_retval = _mls_x_5; -//│ return _mls_retval; -//│ } -//│ _mlsValue _mls_foo(_mlsValue _mls_a) { -//│ _mlsValue _mls_retval; -//│ auto _mls_x_0 = (_mls_a > _mlsValue::fromIntLit(0)); -//│ if (_mlsValue::isIntLit(_mls_x_0, 1)) { -//│ auto _mls_x_2 = _mlsValue::fromIntLit(1); -//│ auto _mls_x_3 = _mlsValue::create<_mls_Unit>(); -//│ _mls_retval = _mls_j_0(_mls_x_2); -//│ } else { -//│ auto _mls_x_4 = _mlsValue::create<_mls_Unit>(); -//│ _mls_retval = _mls_j_0(_mls_x_1); +//│ _mls_retval = _mls_j_0(_mls_x_0); //│ } //│ return _mls_retval; //│ } //│ _mlsValue _mlsMain() { //│ _mlsValue _mls_retval; -//│ _mls_retval = _mlsValue::create<_mls_Unit>(); +//│ auto _mls_x_6 = _mls_f(); +//│ _mls_retval = _mls_x_6; //│ return _mls_retval; //│ } //│ int main() { return _mlsLargeStack(_mlsMainWrapper); } - +//│ +//│ Interpreted: +//│ 11 From ebdaa5bd95d4667b2fcec4b680bc9c535506b0ff Mon Sep 17 00:00:00 2001 From: waterlens Date: Wed, 22 Jan 2025 00:07:33 +0800 Subject: [PATCH 24/88] Save --- .../src/test/scala/hkmc2/LlirDiffMaker.scala | 73 ------------------- 1 file changed, 73 deletions(-) delete mode 100644 hkmc2/jvm/src/test/scala/hkmc2/LlirDiffMaker.scala diff --git a/hkmc2/jvm/src/test/scala/hkmc2/LlirDiffMaker.scala b/hkmc2/jvm/src/test/scala/hkmc2/LlirDiffMaker.scala deleted file mode 100644 index ef93178282..0000000000 --- a/hkmc2/jvm/src/test/scala/hkmc2/LlirDiffMaker.scala +++ /dev/null @@ -1,73 +0,0 @@ -package hkmc2 - -import scala.collection.mutable - -import mlscript.utils.*, shorthands.* -import utils.* - -import document.* -import codegen.Block -import codegen.llir.* -import codegen.cpp.* -import hkmc2.syntax.Tree.Ident -import hkmc2.codegen.Path -import hkmc2.semantics.Term.Blk -import hkmc2.codegen.llir.Fresh -import hkmc2.utils.Scope -import hkmc2.codegen.llir.Ctx -import hkmc2.codegen.llir._ - -abstract class LlirDiffMaker extends BbmlDiffMaker: - val llir = NullaryCommand("llir") - val cpp = NullaryCommand("cpp") - val sllir = NullaryCommand("sllir") - val scpp = NullaryCommand("scpp") - val rcpp = NullaryCommand("rcpp") - val intl = NullaryCommand("intl") - val wcpp = Command[Str]("wcpp", false)(x => x.stripLeading()) - - def printToFile(f: java.io.File)(op: java.io.PrintWriter => Unit) = - val p = new java.io.PrintWriter(f) - try { op(p) } finally { p.close() } - - override def processTerm(trm: Blk, inImport: Bool)(using Raise): Unit = - super.processTerm(trm, inImport) - if llir.isSet then - val low = ltl.givenIn: - codegen.Lowering() - val le = low.program(trm) - given Scope = Scope.empty - val fresh = Fresh() - val fuid = FreshInt() - val cuid = FreshInt() - val llb = LlirBuilder(tl)(fresh, fuid, cuid) - given Ctx = Ctx.empty - try - val llirProg = llb.bProg(le) - if sllir.isSet then - output("LLIR:") - output(llirProg.show()) - if cpp.isSet || scpp.isSet || rcpp.isSet || wcpp.isSet then - val cpp = codegen.cpp.CppCodeGen.codegen(llirProg) - if scpp.isSet then - output("\nCpp:") - output(cpp.toDocument.toString) - val auxPath = os.Path(rootPath) / "hkmc2"/"shared"/"src"/"test"/"mlscript-compile"/"cpp" - if wcpp.isSet then - printToFile(java.io.File((auxPath / s"${wcpp.get.get}.cpp").toString)): - p => p.println(cpp.toDocument.toString) - if rcpp.isSet then - val cppHost = CppCompilerHost(auxPath.toString, output.apply) - if !cppHost.ready then - output("\nCpp Compilation Failed: Cpp compiler or GNU Make not found") - else - output("\n") - cppHost.compileAndRun(cpp.toDocument.toString) - if intl.isSet then - val intr = codegen.llir.Interpreter(verbose = true) - output("\nInterpreted:") - output(intr.interpret(llirProg)) - catch - case e: LowLevelIRError => - output("Stopped due to an error during the Llir generation") - From 6f3fca35f986fcf1db2d309fbad7a1cff14066f5 Mon Sep 17 00:00:00 2001 From: waterlens Date: Tue, 4 Feb 2025 20:57:40 +0800 Subject: [PATCH 25/88] fixed freeVars; prototype support of methods --- .../src/main/scala/hkmc2/codegen/Block.scala | 4 +- .../scala/hkmc2/codegen/llir/Builder.scala | 40 ++++++++++++++++++- .../shared/src/test/mlscript/llir/Method.mls | 17 ++++++++ 3 files changed, 58 insertions(+), 3 deletions(-) create mode 100644 hkmc2/shared/src/test/mlscript/llir/Method.mls diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Block.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Block.scala index 8bd6d3b6d6..484a9cb224 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Block.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Block.scala @@ -182,8 +182,8 @@ enum Case: sealed abstract class Result: lazy val freeVars: Set[Local] = this match - case Call(fun, args) => args.flatMap(_.value.freeVars).toSet - case Instantiate(cls, args) => args.flatMap(_.freeVars).toSet + case Call(fun, args) => fun.freeVars ++ args.flatMap(_.value.freeVars).toSet + case Instantiate(cls, args) => cls.freeVars ++ args.flatMap(_.freeVars).toSet case Select(qual, name) => qual.freeVars case Value.Ref(l) => Set(l) case Value.This(sym) => Set.empty diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala index 06caaffced..a6276684fe 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala @@ -34,6 +34,8 @@ final case class Ctx( class_ctx: Map[Local, Name] = Map.empty, block_ctx: Map[Local, Name] = Map.empty, is_top_level: Bool = true, + method_class: Opt[Symbol] = None, + this_name: Opt[Name] = None, ): def addFuncName(n: Local, m: Name) = copy(fn_ctx = fn_ctx + (n -> m)) def findFuncName(n: Local)(using Raise) = fn_ctx.get(n) match @@ -53,6 +55,8 @@ final case class Ctx( errStop(msg"Name not found: $n") Name("error") case Some(value) => value + def setClass(c: Symbol) = copy(method_class = Some(c)) + def setThis(n: Name) = copy(this_name = Some(n)) def reset = def_acc.clear() class_acc.clear() @@ -141,6 +145,26 @@ final class LlirBuilder(tl: TraceLogger)(fresh: Fresh, fnUid: FreshInt, clsUid: body = bBlock(body)(x => Node.Result(Ls(x)))(using ctx3) ) + private def bMethodDef(e: FunDefn)(using ctx: Ctx)(using Raise, Scope): Func = + trace[Func](s"bFunDef begin: ${e.sym}", x => s"bFunDef end: ${x.show}"): + val FunDefn(sym, params, body) = e + if !ctx.is_top_level then + errStop(msg"Non top-level definition ${sym.nme} not supported") + else if params.length != 1 then + errStop(msg"Curried function or zero arguments function not supported: ${params.length.toString}") + else + val paramsList = params.head.params.map(x => x -> summon[Scope].allocateName(x.sym)) + val ctx2 = paramsList.foldLeft(ctx)((acc, x) => acc.addName(getVar_!(x._1.sym), x._2 |> nme)) + val ctx3 = ctx2.nonTopLevel + val pl = ctx.this_name.getOrElse(errStop(msg"Not in a class")) :: paramsList.map(_._2).map(nme) + Func( + fnUid.make, + sym.nme, + params = pl, + resultNum = 1, + body = bBlock(body)(x => Node.Result(Ls(x)))(using ctx3) + ) + private def bClsLikeDef(e: ClsLikeDefn)(using ctx: Ctx)(using Raise, Scope): ClassInfo = trace[ClassInfo](s"bClsLikeDef begin", x => s"bClsLikeDef end: ${x.show}"): val ClsLikeDefn(sym, kind, parentSym, methods, privateFields, publicFields, preCtor, ctor) = e @@ -150,6 +174,9 @@ final class LlirBuilder(tl: TraceLogger)(fresh: Fresh, fnUid: FreshInt, clsUid: val clsDefn = sym.defn.getOrElse(die) val clsParams = clsDefn.paramsOpt.fold(Nil)(_.paramSyms) val clsFields = publicFields.map(_.sym) + given Ctx = ctx.setClass(sym).setThis(fresh.make("this")) + val funcs = methods.map(bMethodDef) + ctx.def_acc ++= funcs ClassInfo( clsUid.make, sym.nme, @@ -159,6 +186,10 @@ final class LlirBuilder(tl: TraceLogger)(fresh: Fresh, fnUid: FreshInt, clsUid: private def bValue(v: Value)(k: TrivialExpr => Ctx ?=> Node)(using ctx: Ctx)(using Raise, Scope) : Node = trace[Node](s"bValue begin", x => s"bValue end: ${x.show}"): v match + case Value.Ref(l: TermSymbol) if l.owner.nonEmpty => + val v = fresh.make + Node.LetExpr(v, + Expr.Select(ctx.this_name.getOrElse(errStop(msg"Not in a class")), ClassRef.fromName(l.owner.get.nme), l.name), k(v |> sr)) case Value.Ref(l) => k(ctx.findName(getVar_!(l)) |> sr) case Value.This(sym) => errStop(msg"Unsupported value: This"); Node.Result(Ls()) case Value.Lit(lit) => k(Expr.Literal(lit)) @@ -178,6 +209,10 @@ final class LlirBuilder(tl: TraceLogger)(fresh: Fresh, fnUid: FreshInt, clsUid: val v = fresh.make Node.LetExpr(v, Expr.CtorApp(ClassRef.fromName(name.name), Ls()), k(v |> sr)) // field selection + case Select(Value.Ref(cls: ClassSymbol), name) if ctx.method_class.contains(cls) => + val v = fresh.make + val _ = Node.LetExpr(v, Expr.Select(ctx.this_name.getOrElse(errStop(msg"Not in a class")), ClassRef.fromName(cls.nme), name.name), k(v |> sr)) + errStop(msg"Unsupported field in the class") case s @ Select(qual, name) => log(s"bPath Select: $qual.$name with ${s.symbol}") s.symbol match @@ -249,7 +284,10 @@ final class LlirBuilder(tl: TraceLogger)(fresh: Fresh, fnUid: FreshInt, clsUid: bPath(scrut): case e: TrivialExpr => val jp = fresh.make("j") - val fvset = (rest.freeVars -- rest.definedVars).map(allocIfNew) + val fvset = (rest.freeVars -- rest.definedVars).filter{ + case s: BuiltinSymbol => false + case _ => true + }.map(allocIfNew) val fvs1 = fvset.toList val new_ctx = fvs1.foldLeft(ctx)((acc, x) => acc.addName(x, fresh.make)) val fvs = fvs1.map(new_ctx.findName(_)) diff --git a/hkmc2/shared/src/test/mlscript/llir/Method.mls b/hkmc2/shared/src/test/mlscript/llir/Method.mls new file mode 100644 index 0000000000..fc6c0e68de --- /dev/null +++ b/hkmc2/shared/src/test/mlscript/llir/Method.mls @@ -0,0 +1,17 @@ + +:global +:llir +:cpp + + +:sllir +:lot +class A(m) with + fun f() = m +//│ LLIR: +//│ class A(m) +//│ def f(this$0) = +//│ let x$0 = this$0. in +//│ x$0 +//│ undefined + From 3c580d32818f7674646e595c66fd45541fe553ee Mon Sep 17 00:00:00 2001 From: waterlens Date: Wed, 5 Feb 2025 20:12:47 +0800 Subject: [PATCH 26/88] Add methods and higher order functions support --- .../scala/hkmc2/codegen/llir/Builder.scala | 117 ++++++++++++----- .../main/scala/hkmc2/codegen/llir/Llir.scala | 8 +- .../src/test/mlscript/llir/HigherOrder.mls | 122 ++++++++++++++++++ .../shared/src/test/mlscript/llir/Method.mls | 9 +- 4 files changed, 213 insertions(+), 43 deletions(-) create mode 100644 hkmc2/shared/src/test/mlscript/llir/HigherOrder.mls diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala index 1e95d36c19..3280bdbc26 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala @@ -24,23 +24,26 @@ def errStop(msg: Message)(using Raise) = err(msg) throw LowLevelIRError("stopped") +final case class FuncInfo ( + name: Name, + paramsSize: Int, +) final case class Ctx( def_acc: ListBuffer[Func], class_acc: ListBuffer[ClassInfo], symbol_ctx: Map[Str, Name] = Map.empty, - fn_ctx: Map[Local, Name] = Map.empty, // is a known function + fn_ctx: Map[Local, FuncInfo] = Map.empty, // is a known function class_ctx: Map[Local, Name] = Map.empty, block_ctx: Map[Local, Name] = Map.empty, is_top_level: Bool = true, method_class: Opt[Symbol] = None, - this_name: Opt[Name] = None, + free_vars: Set[Local] = Set.empty, ): - def addFuncName(n: Local, m: Name) = copy(fn_ctx = fn_ctx + (n -> m)) + def addFuncName(n: Local, m: Name, paramsSize: Int) = copy(fn_ctx = fn_ctx + (n -> FuncInfo(m, paramsSize))) def findFuncName(n: Local)(using Raise) = fn_ctx.get(n) match case None => errStop(msg"Function name not found: ${n.toString()}") - Name("error") case Some(value) => value def addClassName(n: Local, m: Name) = copy(class_ctx = class_ctx + (n -> m)) def findClassName(n: Local)(using Raise) = class_ctx.get(n) match @@ -53,14 +56,14 @@ final case class Ctx( errStop(msg"Name not found: $n") case Some(value) => value def setClass(c: Symbol) = copy(method_class = Some(c)) - def setThis(n: Name) = copy(this_name = Some(n)) + def setFreeVars(n: Set[Local]) = copy(free_vars = free_vars) def nonTopLevel = copy(is_top_level = false) object Ctx: def empty = Ctx(ListBuffer.empty, ListBuffer.empty) -final class LlirBuilder(tl: TraceLogger)(fresh: Fresh, fnUid: FreshInt, clsUid: FreshInt): +final class LlirBuilder(using Elaborator.State)(tl: TraceLogger)(fresh: Fresh, fnUid: FreshInt, clsUid: FreshInt): import tl.{trace, log, logs} def er = Expr.Ref @@ -91,6 +94,11 @@ final class LlirBuilder(tl: TraceLogger)(fresh: Fresh, fnUid: FreshInt, clsUid: summon[Scope].findThis_!(ts) case _ => summon[Scope].lookup_!(l) + private def freeVarsFilter(fvs: Set[Local]) = + fvs.filter: + case s: BuiltinSymbol => false + case _ => true + private def bBind(name: Opt[Str], e: Result, body: Block)(k: TrivialExpr => Ctx ?=> Node)(using ctx: Ctx)(using Raise, Scope): Node = trace[Node](s"bBind begin: $name", x => s"bBind end: ${x.show}"): bResult(e): @@ -151,7 +159,7 @@ final class LlirBuilder(tl: TraceLogger)(fresh: Fresh, fnUid: FreshInt, clsUid: val paramsList = params.head.params.map(x => x -> summon[Scope].allocateName(x.sym)) val ctx2 = paramsList.foldLeft(ctx)((acc, x) => acc.addName(getVar_!(x._1.sym), x._2 |> nme)) val ctx3 = ctx2.nonTopLevel - val pl = ctx.this_name.getOrElse(errStop(msg"Not in a class")) :: paramsList.map(_._2).map(nme) + val pl = paramsList.map(_._2).map(nme) Func( fnUid.make, sym.nme, @@ -170,30 +178,70 @@ final class LlirBuilder(tl: TraceLogger)(fresh: Fresh, fnUid: FreshInt, clsUid: val clsDefn = sym.defn.getOrElse(die) val clsParams = paramsOpt.fold(Nil)(_.paramSyms) val clsFields = publicFields.map(_.sym) - given Ctx = ctx.setClass(sym).setThis(fresh.make("this")) + given Ctx = ctx.setClass(sym) val funcs = methods.map(bMethodDef) - ctx.def_acc ++= funcs + def parentFromPath(p: Path): Set[Str] = p match + case Value.Ref(l) => Set(l.nme) + case _ => errStop(msg"Unsupported parent path") ClassInfo( clsUid.make, sym.nme, clsParams.map(_.nme) ++ clsFields.map(_.nme), + parentSym.fold(Set.empty)(parentFromPath), + funcs.map(f => f.name -> f).toMap, ) + private def bLam(lam: Value.Lam)(k: TrivialExpr => Ctx ?=> Node)(using ctx: Ctx)(using Raise, Scope) : Node = + trace[Node](s"bLam begin", x => s"bLam end: ${x.show}"): + val Value.Lam(params, body) = lam + // Generate an auxiliary class inheriting from Callable + val freeVars = freeVarsFilter(lam.freeVars -- lam.body.definedVars -- ctx.fn_ctx.keySet) + val name = fresh.make("Lambda") + val clsParams = freeVars.toList.map(_.nme) + val args = freeVars.toList.map(allocIfNew) + val ctx2 = ctx.setFreeVars(freeVars) + val applyParams = params.params.map(x => x -> summon[Scope].allocateName(x.sym)) + val ctx3 = applyParams.foldLeft(ctx2)((acc, x) => acc.addName(getVar_!(x._1.sym), x._2 |> nme)).nonTopLevel + val pl = applyParams.map(_._2).map(nme) + val method = Func( + fnUid.make, + s"apply${params.params.length}", + params = pl, + resultNum = 1, + body = bBlock(body)(x => Node.Result(Ls(x)))(using ctx3) + ) + ctx.class_acc += ClassInfo( + clsUid.make, + name.str, + clsParams, + Set("Callable"), + Map(method.name -> method), + ) + val v = fresh.make + Node.LetExpr(v, Expr.CtorApp(ClassRef.fromName(name), args.map(sr)), k(v |> sr)(using ctx)) + private def bValue(v: Value)(k: TrivialExpr => Ctx ?=> Node)(using ctx: Ctx)(using Raise, Scope) : Node = trace[Node](s"bValue { $v } begin", x => s"bValue end: ${x.show}"): v match case Value.Ref(l: TermSymbol) if l.owner.nonEmpty => - val v = fresh.make - Node.LetExpr(v, - Expr.Select(ctx.this_name.getOrElse(errStop(msg"Not in a class")), ClassRef.fromName(l.owner.get.nme), l.name), k(v |> sr)) + k(Name(l.name) |> sr) case Value.Ref(sym) if sym.nme.isCapitalized => val v = fresh.make Node.LetExpr(v, Expr.CtorApp(ClassRef.fromName(sym.nme), Ls()), k(v |> sr)) - case Value.Ref(l) => k(ctx.findName(getVar_!(l)) |> sr) - case Value.This(sym) => errStop(msg"Unsupported value: This"); Node.Result(Ls()) + case Value.Ref(l) => + val x = getVar_!(l) + ctx.fn_ctx.get(l) match + case Some(f) => + val tempSymbols = (0 until f.paramsSize).map(_ => VarSymbol(Tree.Ident("lam_arg"))) + val paramsList = PlainParamList((0 until f.paramsSize).zip(tempSymbols).map((_n, sym) => Param(FldFlags.empty, sym, N)).toList) + val app = Call(v, tempSymbols.map(x => Arg(false, Value.Ref(x))).toList)(true, false) + bLam(Value.Lam(paramsList, Return(app, false)))(k) + case None => + k(ctx.findName(x) |> sr) + case Value.This(sym) => errStop(msg"Unsupported value: This") case Value.Lit(lit) => k(Expr.Literal(lit)) - case Value.Lam(params, body) => errStop(msg"Unsupported value: Lam"); Node.Result(Ls()) - case Value.Arr(elems) => errStop(msg"Unsupported value: Arr"); Node.Result(Ls()) + case lam @ Value.Lam(params, body) => bLam(lam)(k) + case Value.Arr(elems) => errStop(msg"Unsupported value: Arr") private def getClassOfMem(p: FieldSymbol)(using ctx: Ctx)(using Raise, Scope): Local = trace[Local](s"bMemSym { $p } begin", x => s"bMemSym end: $x"): @@ -205,9 +253,9 @@ final class LlirBuilder(tl: TraceLogger)(fresh: Fresh, fnUid: FreshInt, clsUid: trace[Node](s"bPath { $p } begin", x => s"bPath end: ${x.show}"): p match case Select(Value.Ref(cls: ClassSymbol), name) if ctx.method_class.contains(cls) => - val v = fresh.make - val _ = Node.LetExpr(v, Expr.Select(ctx.this_name.getOrElse(errStop(msg"Not in a class")), ClassRef.fromName(cls.nme), name.name), k(v |> sr)) - errStop(msg"Unsupported field in the class") + k(Name(name.name) |> sr) + case s @ DynSelect(qual, fld, arrayIdx) => + errStop(msg"Unsupported dynamic selection") case s @ Select(qual, name) => log(s"bPath Select: $qual.$name with ${s.symbol}") s.symbol match @@ -238,18 +286,18 @@ final class LlirBuilder(tl: TraceLogger)(fresh: Fresh, fnUid: FreshInt, clsUid: case args: Ls[TrivialExpr] => val v = fresh.make Node.LetExpr(v, Expr.CtorApp(ClassRef.fromName(sym.nme), args), k(v |> sr)) - case Call(Value.Ref(sym), args) => + case Call(s @ Value.Ref(sym), args) => bArgs(args): case args: Ls[TrivialExpr] => val v = fresh.make - Node.LetCall(Ls(v), FuncRef.fromName(sym.nme), args, k(v |> sr)) - case Call(fn, args) => - bPath(fn): - case f: TrivialExpr => - bArgs(args): - case args: Ls[TrivialExpr] => - val v = fresh.make - Node.LetMethodCall(Ls(v), ClassRef(R("Callable")), Name("apply" + args.length), f :: args, k(v |> sr)) + ctx.fn_ctx.get(sym) match + case Some(f) => + Node.LetCall(Ls(v), FuncRef.fromName(f.name), args, k(v |> sr)) + case None => + bPath(s): + case f: TrivialExpr => + Node.LetMethodCall(Ls(v), ClassRef(R("Callable")), Name("apply" + args.length), f :: args, k(v |> sr)) + case Call(_, _) => errStop(msg"Unsupported kind of Call") case Instantiate( Select(Value.Ref(sym), Tree.Ident("class")), args) => bPaths(args): @@ -268,10 +316,7 @@ final class LlirBuilder(tl: TraceLogger)(fresh: Fresh, fnUid: FreshInt, clsUid: bPath(scrut): case e: TrivialExpr => val jp = fresh.make("j") - val fvset = (rest.freeVars -- rest.definedVars).filter{ - case s: BuiltinSymbol => false - case _ => true - }.map(allocIfNew) + val fvset = freeVarsFilter(rest.freeVars -- rest.definedVars).map(allocIfNew) val fvs1 = fvset.toList val new_ctx = fvs1.foldLeft(ctx)((acc, x) => acc.addName(x, fresh.make)) val fvs = fvs1.map(new_ctx.findName(_)) @@ -325,10 +370,12 @@ final class LlirBuilder(tl: TraceLogger)(fresh: Fresh, fnUid: FreshInt, clsUid: bBind(S(name), rhs, rest)(k) case AssignField(lhs, nme, rhs, rest) => TODO("AssignField not supported") case Define(fd @ FunDefn(_own, sym, params, body), rest) => - val f = bFunDef(fd) + if params.length != 1 then + errStop(msg"Curried function or zero arguments function not supported: ${params.length.toString}") + val ctx2 = ctx.addFuncName(sym, Name(sym.nme), params.head.params.length) + val f = bFunDef(fd)(using ctx2) ctx.def_acc += f - val new_ctx = ctx.addFuncName(sym, Name(f.name)) - bBlock(rest)(k)(using new_ctx) + bBlock(rest)(k)(using ctx2) case Define(_: ClsLikeDefn, rest) => bBlock(rest)(k) case End(msg) => k(Expr.Literal(Tree.UnitLit(false))) case _: Block => diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Llir.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Llir.scala index 72be21209b..36971ad982 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Llir.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Llir.scala @@ -49,9 +49,9 @@ case class ClassInfo( id: Int, name: Str, fields: Ls[Str], + parents: Set[Str], + methods: Map[Str, Func], ): - var parents: Set[Str] = Set.empty - var methods: Map[Str, Func] = Map.empty override def hashCode: Int = id override def toString: String = s"ClassInfo($id, $name, [${fields mkString ","}], parents: ${parents mkString ","}, methods:\n${methods mkString ",\n"})" @@ -63,10 +63,10 @@ case class ClassInfo( if methods.isEmpty then doc"class $name(${fields.mkString(",")})$ext" else - val docFirst = doc"class $name (${fields.mkString(",")})$ext {" + val docFirst = doc"class $name(${fields.mkString(",")})$ext {" val docMethods = methods.map { (_, func) => func.toDocument }.toList.mkDocument(doc" # ") val docLast = doc"}" - doc"$docFirst #{ # $docMethods # #} $docLast" + doc"$docFirst #{ # $docMethods #} # $docLast" case class Name(str: Str): def trySubst(map: Map[Str, Name]) = map.getOrElse(str, this) diff --git a/hkmc2/shared/src/test/mlscript/llir/HigherOrder.mls b/hkmc2/shared/src/test/mlscript/llir/HigherOrder.mls new file mode 100644 index 0000000000..b744a2978e --- /dev/null +++ b/hkmc2/shared/src/test/mlscript/llir/HigherOrder.mls @@ -0,0 +1,122 @@ +:js +:llir + +:global + +:sllir +:intl +fun add(x) = y => x + y +add(1)(2) +//│ = 3 +//│ LLIR: +//│ class Lambda$0(x) extends Callable { +//│ def apply1(y) = +//│ let x$0 = +(x,y) in +//│ x$0 +//│ } +//│ def add(x) = +//│ let x$1 = Lambda$0(x) in +//│ x$1 +//│ let* (x$2) = add(1) in +//│ let x$3 = Callable.apply1(x$2,2) in +//│ x$3 +//│ +//│ Interpreted: +//│ 3 + +:sllir +:intl +fun add4(a, b) = (c, d) => a + b + c + d +add4(1, 2)(3, 4) +//│ = 10 +//│ LLIR: +//│ class Lambda$0(a,b) extends Callable { +//│ def apply2(c,d) = +//│ let x$0 = +(a,b) in +//│ let x$1 = +(x$0,c) in +//│ let x$2 = +(x$1,d) in +//│ x$2 +//│ } +//│ def add4(a,b) = +//│ let x$3 = Lambda$0(a,b) in +//│ x$3 +//│ let* (x$4) = add4(1,2) in +//│ let x$5 = Callable.apply2(x$4,3,4) in +//│ x$5 +//│ +//│ Interpreted: +//│ 10 + + +:sllir +:intl +abstract class List[out T]: Cons[T] | Nil +class (::) Cons[out T](head: T, tail: List[T]) extends List[T] +object Nil extends List +fun map(f, l) = + if l is + Cons(h, t) then Cons(f(h), map(f, t)) + Nil then Nil +fun inc(x) = x + 1 +fun main() = + map(x => inc(x), 1 :: 2 :: 3 :: Nil) + map(inc, 1 :: 2 :: 3 :: Nil) +main() +//│ = Cons(2, Cons(3, Cons(4, Nil))) +//│ LLIR: +//│ class List() +//│ class Cons(head,tail) extends List +//│ class Nil() extends List +//│ class Lambda$0() extends Callable { +//│ def apply1(x1) = +//│ let* (x$11) = inc(x1) in +//│ x$11 +//│ } +//│ class Lambda$1() extends Callable { +//│ def apply1(lam_arg) = +//│ let* (x$18) = inc(lam_arg) in +//│ x$18 +//│ } +//│ def map(f,l) = +//│ case l of +//│ Cons => +//│ let x$0 = l. in +//│ let x$1 = l. in +//│ let x$2 = Callable.apply1(f,x$0) in +//│ let* (x$3) = map(f,x$1) in +//│ let x$4 = Cons(x$2,x$3) in +//│ x$4 +//│ _ => +//│ case l of +//│ Nil => +//│ let x$5 = Nil() in +//│ x$5 +//│ _ => +//│ panic "match error" +//│ def j$1() = +//│ jump j$0() +//│ def j$0() = +//│ null +//│ def inc(x) = +//│ let x$6 = +(x,1) in +//│ x$6 +//│ def main() = +//│ let x$7 = Nil() in +//│ let x$8 = Cons(3,x$7) in +//│ let x$9 = Cons(2,x$8) in +//│ let x$10 = Cons(1,x$9) in +//│ let x$12 = Lambda$0() in +//│ let* (x$13) = map(x$12,x$10) in +//│ let x$14 = Nil() in +//│ let x$15 = Cons(3,x$14) in +//│ let x$16 = Cons(2,x$15) in +//│ let x$17 = Cons(1,x$16) in +//│ let x$19 = Lambda$1() in +//│ let* (x$20) = map(x$19,x$17) in +//│ x$20 +//│ let* (x$21) = main() in +//│ x$21 +//│ +//│ Interpreted: +//│ Cons(2,Cons(3,Cons(4,Nil()))) + diff --git a/hkmc2/shared/src/test/mlscript/llir/Method.mls b/hkmc2/shared/src/test/mlscript/llir/Method.mls index fc6c0e68de..89cce0a7ef 100644 --- a/hkmc2/shared/src/test/mlscript/llir/Method.mls +++ b/hkmc2/shared/src/test/mlscript/llir/Method.mls @@ -9,9 +9,10 @@ class A(m) with fun f() = m //│ LLIR: -//│ class A(m) -//│ def f(this$0) = -//│ let x$0 = this$0. in -//│ x$0 +//│ class A(m) { +//│ def f() = +//│ m +//│ } +//│ //│ undefined From 8538d7c655a5c09720af8440c52c21e21fc1c6f3 Mon Sep 17 00:00:00 2001 From: waterlens Date: Wed, 5 Feb 2025 20:40:32 +0800 Subject: [PATCH 27/88] support higher order functions with virtual methods --- .../scala/hkmc2/codegen/cpp/CodeGen.scala | 4 +- .../scala/hkmc2/codegen/llir/Builder.scala | 2 +- .../src/test/mlscript/llir/HigherOrder.mls | 181 +++++++++++++++--- .../src/test/mlscript/llir/Playground.mls | 12 +- 4 files changed, 169 insertions(+), 30 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/CodeGen.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/CodeGen.scala index 80f83ae7c3..d9916711b9 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/CodeGen.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/CodeGen.scala @@ -209,7 +209,9 @@ object CppCodeGen: // Topological sort of classes based on inheritance relationships def sortClasses(prog: Program): Ls[ClassInfo] = + val builtinClasses = Set("Callable") var depgraph = prog.classes.map(x => (x.name, x.parents)).toMap + ++ builtinClasses.map(x => (x, Set.empty[Str])) var degree = depgraph.view.mapValues(_.size).toMap def removeNode(node: Str) = degree -= node @@ -221,7 +223,7 @@ object CppCodeGen: while work.nonEmpty do val node = work.head work -= node - sorted.addOne(prog.classes.find(_.name == node).get) + prog.classes.find(_.name == node).fold(())(sorted.addOne) removeNode(node) val next = degree.filter(_._2 == 0).keys work ++= next diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala index 3280bdbc26..032207c20b 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala @@ -232,7 +232,7 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger)(fresh: Fresh, f val x = getVar_!(l) ctx.fn_ctx.get(l) match case Some(f) => - val tempSymbols = (0 until f.paramsSize).map(_ => VarSymbol(Tree.Ident("lam_arg"))) + val tempSymbols = (0 until f.paramsSize).map(x => VarSymbol(Tree.Ident(fresh.make("arg").str))) val paramsList = PlainParamList((0 until f.paramsSize).zip(tempSymbols).map((_n, sym) => Param(FldFlags.empty, sym, N)).toList) val app = Call(v, tempSymbols.map(x => Arg(false, Value.Ref(x))).toList)(true, false) bLam(Value.Lam(paramsList, Return(app, false)))(k) diff --git a/hkmc2/shared/src/test/mlscript/llir/HigherOrder.mls b/hkmc2/shared/src/test/mlscript/llir/HigherOrder.mls index b744a2978e..6a7307cff2 100644 --- a/hkmc2/shared/src/test/mlscript/llir/HigherOrder.mls +++ b/hkmc2/shared/src/test/mlscript/llir/HigherOrder.mls @@ -5,6 +5,7 @@ :sllir :intl +:scpp fun add(x) = y => x + y add(1)(2) //│ = 3 @@ -21,11 +22,46 @@ add(1)(2) //│ let x$3 = Callable.apply1(x$2,2) in //│ x$3 //│ +//│ Cpp: +//│ #include "mlsprelude.h" +//│ struct _mls_Lambda_0; +//│ _mlsValue _mls_add(_mlsValue); +//│ _mlsValue _mlsMain(); +//│ struct _mls_Lambda_0: public _mls_Callable { +//│ _mlsValue _mls_x; +//│ constexpr static inline const char *typeName = "Lambda$0"; +//│ constexpr static inline uint32_t typeTag = nextTypeTag(); +//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->_mls_x.print(); std::printf(")"); } +//│ virtual void destroy() override { _mlsValue::destroy(this->_mls_x); operator delete (this, std::align_val_t(_mlsAlignment)); } +//│ static _mlsValue create(_mlsValue _mls_x) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) _mls_Lambda_0; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->_mls_x = _mls_x; return _mlsValue(_mlsVal); } +//│ virtual _mlsValue _mls_apply1(_mlsValue _mls_y) { +//│ _mlsValue _mls_retval; +//│ auto _mls_x_0 = (_mls_x + _mls_y); +//│ _mls_retval = _mls_x_0; +//│ return _mls_retval; +//│ } +//│ }; +//│ _mlsValue _mls_add(_mlsValue _mls_x) { +//│ _mlsValue _mls_retval; +//│ auto _mls_x_1 = _mlsValue::create<_mls_Lambda_0>(_mls_x); +//│ _mls_retval = _mls_x_1; +//│ return _mls_retval; +//│ } +//│ _mlsValue _mlsMain() { +//│ _mlsValue _mls_retval; +//│ auto _mls_x_2 = _mls_add(_mlsValue::fromIntLit(1)); +//│ auto _mls_x_3 = _mlsMethodCall<_mls_Callable>(_mls_x_2)->_mls_apply1(_mlsValue::fromIntLit(2)); +//│ _mls_retval = _mls_x_3; +//│ return _mls_retval; +//│ } +//│ int main() { return _mlsLargeStack(_mlsMainWrapper); } +//│ //│ Interpreted: //│ 3 :sllir :intl +:scpp fun add4(a, b) = (c, d) => a + b + c + d add4(1, 2)(3, 4) //│ = 10 @@ -44,9 +80,112 @@ add4(1, 2)(3, 4) //│ let x$5 = Callable.apply2(x$4,3,4) in //│ x$5 //│ +//│ Cpp: +//│ #include "mlsprelude.h" +//│ struct _mls_Lambda_0; +//│ _mlsValue _mls_add4(_mlsValue, _mlsValue); +//│ _mlsValue _mlsMain(); +//│ struct _mls_Lambda_0: public _mls_Callable { +//│ _mlsValue _mls_a; +//│ _mlsValue _mls_b; +//│ constexpr static inline const char *typeName = "Lambda$0"; +//│ constexpr static inline uint32_t typeTag = nextTypeTag(); +//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->_mls_a.print(); std::printf(", "); this->_mls_b.print(); std::printf(")"); } +//│ virtual void destroy() override { _mlsValue::destroy(this->_mls_a); _mlsValue::destroy(this->_mls_b); operator delete (this, std::align_val_t(_mlsAlignment)); } +//│ static _mlsValue create(_mlsValue _mls_a, _mlsValue _mls_b) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) _mls_Lambda_0; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->_mls_a = _mls_a; _mlsVal->_mls_b = _mls_b; return _mlsValue(_mlsVal); } +//│ virtual _mlsValue _mls_apply2(_mlsValue _mls_c, _mlsValue _mls_d) { +//│ _mlsValue _mls_retval; +//│ auto _mls_x_0 = (_mls_a + _mls_b); +//│ auto _mls_x_1 = (_mls_x_0 + _mls_c); +//│ auto _mls_x_2 = (_mls_x_1 + _mls_d); +//│ _mls_retval = _mls_x_2; +//│ return _mls_retval; +//│ } +//│ }; +//│ _mlsValue _mls_add4(_mlsValue _mls_a, _mlsValue _mls_b) { +//│ _mlsValue _mls_retval; +//│ auto _mls_x_3 = _mlsValue::create<_mls_Lambda_0>(_mls_a, _mls_b); +//│ _mls_retval = _mls_x_3; +//│ return _mls_retval; +//│ } +//│ _mlsValue _mlsMain() { +//│ _mlsValue _mls_retval; +//│ auto _mls_x_4 = _mls_add4(_mlsValue::fromIntLit(1), _mlsValue::fromIntLit(2)); +//│ auto _mls_x_5 = _mlsMethodCall<_mls_Callable>(_mls_x_4)->_mls_apply2(_mlsValue::fromIntLit(3), _mlsValue::fromIntLit(4)); +//│ _mls_retval = _mls_x_5; +//│ return _mls_retval; +//│ } +//│ int main() { return _mlsLargeStack(_mlsMainWrapper); } +//│ //│ Interpreted: //│ 10 +:sllir +:intl +:scpp +fun add(a, b) = a + b +fun dummy() = add +dummy()(1, 2) +//│ = 3 +//│ LLIR: +//│ class Lambda$0() extends Callable { +//│ def apply2(arg$0,arg$1) = +//│ let* (x$1) = add(arg$0,arg$1) in +//│ x$1 +//│ } +//│ def add(a,b) = +//│ let x$0 = +(a,b) in +//│ x$0 +//│ def dummy() = +//│ let x$2 = Lambda$0() in +//│ x$2 +//│ let* (x$3) = dummy() in +//│ let x$4 = Callable.apply2(x$3,1,2) in +//│ x$4 +//│ +//│ Cpp: +//│ #include "mlsprelude.h" +//│ struct _mls_Lambda_0; +//│ _mlsValue _mls_add(_mlsValue, _mlsValue); +//│ _mlsValue _mls_dummy(); +//│ _mlsValue _mlsMain(); +//│ struct _mls_Lambda_0: public _mls_Callable { +//│ +//│ constexpr static inline const char *typeName = "Lambda$0"; +//│ constexpr static inline uint32_t typeTag = nextTypeTag(); +//│ virtual void print() const override { std::printf("%s", typeName); } +//│ virtual void destroy() override { operator delete (this, std::align_val_t(_mlsAlignment)); } +//│ static _mlsValue create() { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) _mls_Lambda_0; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; return _mlsValue(_mlsVal); } +//│ virtual _mlsValue _mls_apply2(_mlsValue _mls_arg_0, _mlsValue _mls_arg_1) { +//│ _mlsValue _mls_retval; +//│ auto _mls_x_1 = _mls_add(_mls_arg_0, _mls_arg_1); +//│ _mls_retval = _mls_x_1; +//│ return _mls_retval; +//│ } +//│ }; +//│ _mlsValue _mls_add(_mlsValue _mls_a, _mlsValue _mls_b) { +//│ _mlsValue _mls_retval; +//│ auto _mls_x_0 = (_mls_a + _mls_b); +//│ _mls_retval = _mls_x_0; +//│ return _mls_retval; +//│ } +//│ _mlsValue _mls_dummy() { +//│ _mlsValue _mls_retval; +//│ auto _mls_x_2 = _mlsValue::create<_mls_Lambda_0>(); +//│ _mls_retval = _mls_x_2; +//│ return _mls_retval; +//│ } +//│ _mlsValue _mlsMain() { +//│ _mlsValue _mls_retval; +//│ auto _mls_x_3 = _mls_dummy(); +//│ auto _mls_x_4 = _mlsMethodCall<_mls_Callable>(_mls_x_3)->_mls_apply2(_mlsValue::fromIntLit(1), _mlsValue::fromIntLit(2)); +//│ _mls_retval = _mls_x_4; +//│ return _mls_retval; +//│ } +//│ int main() { return _mlsLargeStack(_mlsMainWrapper); } +//│ +//│ Interpreted: +//│ 3 :sllir :intl @@ -59,23 +198,23 @@ fun map(f, l) = Nil then Nil fun inc(x) = x + 1 fun main() = - map(x => inc(x), 1 :: 2 :: 3 :: Nil) - map(inc, 1 :: 2 :: 3 :: Nil) + map(x => inc(x), 1 :: 2 :: Nil) + map(inc, 3 :: 4 :: Nil) main() -//│ = Cons(2, Cons(3, Cons(4, Nil))) +//│ = Cons(4, Cons(5, Nil)) //│ LLIR: //│ class List() //│ class Cons(head,tail) extends List //│ class Nil() extends List //│ class Lambda$0() extends Callable { //│ def apply1(x1) = -//│ let* (x$11) = inc(x1) in -//│ x$11 +//│ let* (x$10) = inc(x1) in +//│ x$10 //│ } //│ class Lambda$1() extends Callable { -//│ def apply1(lam_arg) = -//│ let* (x$18) = inc(lam_arg) in -//│ x$18 +//│ def apply1(arg$0) = +//│ let* (x$16) = inc(arg$0) in +//│ x$16 //│ } //│ def map(f,l) = //│ case l of @@ -102,21 +241,19 @@ main() //│ x$6 //│ def main() = //│ let x$7 = Nil() in -//│ let x$8 = Cons(3,x$7) in -//│ let x$9 = Cons(2,x$8) in -//│ let x$10 = Cons(1,x$9) in -//│ let x$12 = Lambda$0() in -//│ let* (x$13) = map(x$12,x$10) in -//│ let x$14 = Nil() in +//│ let x$8 = Cons(2,x$7) in +//│ let x$9 = Cons(1,x$8) in +//│ let x$11 = Lambda$0() in +//│ let* (x$12) = map(x$11,x$9) in +//│ let x$13 = Nil() in +//│ let x$14 = Cons(4,x$13) in //│ let x$15 = Cons(3,x$14) in -//│ let x$16 = Cons(2,x$15) in -//│ let x$17 = Cons(1,x$16) in -//│ let x$19 = Lambda$1() in -//│ let* (x$20) = map(x$19,x$17) in -//│ x$20 -//│ let* (x$21) = main() in -//│ x$21 +//│ let x$17 = Lambda$1() in +//│ let* (x$18) = map(x$17,x$15) in +//│ x$18 +//│ let* (x$19) = main() in +//│ x$19 //│ //│ Interpreted: -//│ Cons(2,Cons(3,Cons(4,Nil()))) +//│ Cons(4,Cons(5,Nil())) diff --git a/hkmc2/shared/src/test/mlscript/llir/Playground.mls b/hkmc2/shared/src/test/mlscript/llir/Playground.mls index a0bce1b917..93dfda7028 100644 --- a/hkmc2/shared/src/test/mlscript/llir/Playground.mls +++ b/hkmc2/shared/src/test/mlscript/llir/Playground.mls @@ -12,8 +12,8 @@ class Lazy[out A](init: () -> A) with fun lazy(x) = Lazy(x) //│ LLIR: //│ class Option() -//│ class Some(x) -//│ class None() +//│ class Some(x) extends Option +//│ class None() extends Option //│ class Lazy(init,cache) //│ def fromSome(s) = //│ case s of @@ -74,11 +74,11 @@ main() //│ = 404 //│ LLIR: //│ class Option() -//│ class Some(x) -//│ class None() +//│ class Some(x) extends Option +//│ class None() extends Option //│ class Nat() -//│ class S(s) -//│ class O() +//│ class S(s) extends Nat +//│ class O() extends Nat //│ def fromSome(s) = //│ case s of //│ Some => From e30a11b01d70a272ad8c816f25c92e88ce6de493 Mon Sep 17 00:00:00 2001 From: waterlens Date: Wed, 5 Feb 2025 20:49:26 +0800 Subject: [PATCH 28/88] Reorganize tests --- .../llir/{Playground.mls => ControlFlow.mls} | 147 +----------------- hkmc2/shared/src/test/mlscript/llir/Ctor.mls | 32 ++++ .../shared/src/test/mlscript/llir/Legacy.mls | 106 +++++++++++++ 3 files changed, 141 insertions(+), 144 deletions(-) rename hkmc2/shared/src/test/mlscript/llir/{Playground.mls => ControlFlow.mls} (65%) create mode 100644 hkmc2/shared/src/test/mlscript/llir/Ctor.mls create mode 100644 hkmc2/shared/src/test/mlscript/llir/Legacy.mls diff --git a/hkmc2/shared/src/test/mlscript/llir/Playground.mls b/hkmc2/shared/src/test/mlscript/llir/ControlFlow.mls similarity index 65% rename from hkmc2/shared/src/test/mlscript/llir/Playground.mls rename to hkmc2/shared/src/test/mlscript/llir/ControlFlow.mls index 93dfda7028..6879f6a5cf 100644 --- a/hkmc2/shared/src/test/mlscript/llir/Playground.mls +++ b/hkmc2/shared/src/test/mlscript/llir/ControlFlow.mls @@ -1,150 +1,7 @@ :js :llir - -:sllir -abstract class Option[out T]: Some[T] | None -class Some[out T](x: T) extends Option[T] -object None extends Option -fun fromSome(s) = if s is Some(x) then x -class Lazy[out A](init: () -> A) with - mut val cache: Option[A] = None -fun lazy(x) = Lazy(x) -//│ LLIR: -//│ class Option() -//│ class Some(x) extends Option -//│ class None() extends Option -//│ class Lazy(init,cache) -//│ def fromSome(s) = -//│ case s of -//│ Some => -//│ let x$0 = s. in -//│ x$0 -//│ _ => -//│ panic "match error" -//│ def j$0() = -//│ null -//│ def lazy(x1) = -//│ let x$1 = Lazy(x1) in -//│ x$1 -//│ undefined - -:sllir -fun testCtor1() = None -fun testCtor2() = new None -//│ LLIR: -//│ -//│ def testCtor1() = -//│ let x$0 = None() in -//│ x$0 -//│ def testCtor2() = -//│ let x$1 = None() in -//│ x$1 -//│ undefined - -:sllir -:intl -abstract class Option[out T]: Some[T] | None -class Some[out T](x: T) extends Option[T] -object None extends Option -fun fromSome(s) = if s is Some(x) then x -abstract class Nat: S[Nat] | O -class S(s: Nat) extends Nat -object O extends Nat -fun aaa() = - let m = 1 - let n = 2 - let p = 3 - let q = 4 - m + n - p + q -fun bbb() = - let x = aaa() - x * 100 + 4 -fun not(x) = - if x then false else true -fun foo(x) = - if x then None - else Some(foo(not(x))) -fun main() = - let x = foo(false) - if x is - None then aaa() - Some(b1) then bbb() -main() -//│ = 404 -//│ LLIR: -//│ class Option() -//│ class Some(x) extends Option -//│ class None() extends Option -//│ class Nat() -//│ class S(s) extends Nat -//│ class O() extends Nat -//│ def fromSome(s) = -//│ case s of -//│ Some => -//│ let x$0 = s. in -//│ x$0 -//│ _ => -//│ panic "match error" -//│ def j$0() = -//│ null -//│ def aaa() = -//│ let x$1 = 1 in -//│ let x$2 = 2 in -//│ let x$3 = 3 in -//│ let x$4 = 4 in -//│ let x$5 = +(x$1,x$2) in -//│ let x$6 = -(x$5,x$3) in -//│ let x$7 = +(x$6,x$4) in -//│ x$7 -//│ def bbb() = -//│ let* (x$8) = aaa() in -//│ let x$9 = *(x$8,100) in -//│ let x$10 = +(x$9,4) in -//│ x$10 -//│ def not(x2) = -//│ case x2 of -//│ BoolLit(true) => -//│ false -//│ _ => -//│ true -//│ def j$1() = -//│ null -//│ def foo(x3) = -//│ case x3 of -//│ BoolLit(true) => -//│ let x$11 = None() in -//│ x$11 -//│ _ => -//│ let* (x$12) = not(x3) in -//│ let* (x$13) = foo(x$12) in -//│ let x$14 = Some(x$13) in -//│ x$14 -//│ def j$2() = -//│ null -//│ def main() = -//│ let* (x$15) = foo(false) in -//│ case x$15 of -//│ None => -//│ let* (x$16) = aaa() in -//│ x$16 -//│ _ => -//│ case x$15 of -//│ Some => -//│ let x$17 = x$15. in -//│ let* (x$18) = bbb() in -//│ x$18 -//│ _ => -//│ panic "match error" -//│ def j$4() = -//│ jump j$3() -//│ def j$3() = -//│ null -//│ let* (x$19) = main() in -//│ x$19 -//│ -//│ Interpreted: -//│ 404 +:global :sllir :intl @@ -440,3 +297,5 @@ f() //│ Interpreted: //│ 11 + + diff --git a/hkmc2/shared/src/test/mlscript/llir/Ctor.mls b/hkmc2/shared/src/test/mlscript/llir/Ctor.mls new file mode 100644 index 0000000000..120bc1d1d4 --- /dev/null +++ b/hkmc2/shared/src/test/mlscript/llir/Ctor.mls @@ -0,0 +1,32 @@ +:js +:llir + +:global + +:sllir +object None +fun testCtor1() = None +fun testCtor2() = new None +//│ LLIR: +//│ class None() +//│ def testCtor1() = +//│ let x$0 = None() in +//│ x$0 +//│ def testCtor2() = +//│ let x$1 = None() in +//│ x$1 +//│ undefined + +:sllir +class A(x) +fun testCtor1() = A(1) +fun testCtor2() = new A(1) +//│ LLIR: +//│ class A(x) +//│ def testCtor1() = +//│ let x$0 = A(1) in +//│ x$0 +//│ def testCtor2() = +//│ let x$1 = A(1) in +//│ x$1 +//│ undefined diff --git a/hkmc2/shared/src/test/mlscript/llir/Legacy.mls b/hkmc2/shared/src/test/mlscript/llir/Legacy.mls new file mode 100644 index 0000000000..937a8d14b0 --- /dev/null +++ b/hkmc2/shared/src/test/mlscript/llir/Legacy.mls @@ -0,0 +1,106 @@ +:js +:llir + +:sllir +:intl +abstract class Option[out T]: Some[T] | None +class Some[out T](x: T) extends Option[T] +object None extends Option +fun fromSome(s) = if s is Some(x) then x +abstract class Nat: S[Nat] | O +class S(s: Nat) extends Nat +object O extends Nat +fun aaa() = + let m = 1 + let n = 2 + let p = 3 + let q = 4 + m + n - p + q +fun bbb() = + let x = aaa() + x * 100 + 4 +fun not(x) = + if x then false else true +fun foo(x) = + if x then None + else Some(foo(not(x))) +fun main() = + let x = foo(false) + if x is + None then aaa() + Some(b1) then bbb() +main() +//│ = 404 +//│ LLIR: +//│ class Option() +//│ class Some(x) extends Option +//│ class None() extends Option +//│ class Nat() +//│ class S(s) extends Nat +//│ class O() extends Nat +//│ def fromSome(s) = +//│ case s of +//│ Some => +//│ let x$0 = s. in +//│ x$0 +//│ _ => +//│ panic "match error" +//│ def j$0() = +//│ null +//│ def aaa() = +//│ let x$1 = 1 in +//│ let x$2 = 2 in +//│ let x$3 = 3 in +//│ let x$4 = 4 in +//│ let x$5 = +(x$1,x$2) in +//│ let x$6 = -(x$5,x$3) in +//│ let x$7 = +(x$6,x$4) in +//│ x$7 +//│ def bbb() = +//│ let* (x$8) = aaa() in +//│ let x$9 = *(x$8,100) in +//│ let x$10 = +(x$9,4) in +//│ x$10 +//│ def not(x2) = +//│ case x2 of +//│ BoolLit(true) => +//│ false +//│ _ => +//│ true +//│ def j$1() = +//│ null +//│ def foo(x3) = +//│ case x3 of +//│ BoolLit(true) => +//│ let x$11 = None() in +//│ x$11 +//│ _ => +//│ let* (x$12) = not(x3) in +//│ let* (x$13) = foo(x$12) in +//│ let x$14 = Some(x$13) in +//│ x$14 +//│ def j$2() = +//│ null +//│ def main() = +//│ let* (x$15) = foo(false) in +//│ case x$15 of +//│ None => +//│ let* (x$16) = aaa() in +//│ x$16 +//│ _ => +//│ case x$15 of +//│ Some => +//│ let x$17 = x$15. in +//│ let* (x$18) = bbb() in +//│ x$18 +//│ _ => +//│ panic "match error" +//│ def j$4() = +//│ jump j$3() +//│ def j$3() = +//│ null +//│ let* (x$19) = main() in +//│ x$19 +//│ +//│ Interpreted: +//│ 404 From 8a7c3b794510949ce6e00ffe80bd2e818c8ec3b0 Mon Sep 17 00:00:00 2001 From: waterlens Date: Wed, 5 Feb 2025 23:32:41 +0800 Subject: [PATCH 29/88] fix a bug about continuation; port legacy benchmarks --- .../main/scala/hkmc2/codegen/Printer.scala | 3 +- .../scala/hkmc2/codegen/llir/Builder.scala | 62 ++++--- .../test/mlscript/codegen/BlockPrinter.mls | 4 +- .../src/test/mlscript/llir/ControlFlow.mls | 39 ++++- .../shared/src/test/mlscript/llir/Legacy.mls | 163 ++++++++++++++++++ .../src/test/scala/hkmc2/LlirDiffMaker.scala | 8 +- 6 files changed, 250 insertions(+), 29 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Printer.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Printer.scala index 3015675670..cba032b362 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Printer.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Printer.scala @@ -31,7 +31,8 @@ object Printer: .map{ case (c, b) => doc"${case_doc(c)} => #{ # ${mkDocument(b)} #} " } .mkDocument(sep = doc" # ") val docDefault = dflt.map(mkDocument).getOrElse(doc"") - doc"match ${mkDocument(scrut)} #{ # ${docCases} # else #{ # ${docDefault} #} #} " + val docRest = mkDocument(rest) + doc"match ${mkDocument(scrut)} #{ # ${docCases} # else #{ # ${docDefault} #} #} # in # ${docRest}" case Return(res, implct) => doc"return ${mkDocument(res)}" case Throw(exc) => doc"throw ${mkDocument(exc)}" case Label(label, body, rest) => diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala index 032207c20b..7ead102972 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala @@ -97,6 +97,7 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger)(fresh: Fresh, f private def freeVarsFilter(fvs: Set[Local]) = fvs.filter: case s: BuiltinSymbol => false + case t: TopLevelSymbol => false case _ => true private def bBind(name: Opt[Str], e: Result, body: Block)(k: TrivialExpr => Ctx ?=> Node)(using ctx: Ctx)(using Raise, Scope): Node = @@ -105,12 +106,12 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger)(fresh: Fresh, f case r: Expr.Ref => given Ctx = ctx.addName(name.getOrElse(fresh.make.str), r.name) log(s"bBind ref: $name -> $r") - bBlock(body)(k) + bBlock(body)(k)(End("")) case l: Expr.Literal => val v = fresh.make given Ctx = ctx.addName(name.getOrElse(fresh.make.str), v) log(s"bBind lit: $name -> $v") - Node.LetExpr(v, l, bBlock(body)(k)) + Node.LetExpr(v, l, bBlock(body)(k)(End(""))) private def bArgs(e: Ls[Arg])(k: Ls[TrivialExpr] => Ctx ?=> Node)(using ctx: Ctx)(using Raise, Scope): Node = trace[Node](s"bArgs begin", x => s"bArgs end: ${x.show}"): @@ -145,7 +146,7 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger)(fresh: Fresh, f sym.nme, params = pl, resultNum = 1, - body = bBlock(body)(x => Node.Result(Ls(x)))(using ctx3) + body = bBlock(body)(x => Node.Result(Ls(x)))(End(""))(using ctx3) ) private def bMethodDef(e: FunDefn)(using ctx: Ctx)(using Raise, Scope): Func = @@ -165,7 +166,7 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger)(fresh: Fresh, f sym.nme, params = pl, resultNum = 1, - body = bBlock(body)(x => Node.Result(Ls(x)))(using ctx3) + body = bBlock(body)(x => Node.Result(Ls(x)))(End(""))(using ctx3) ) private def bClsLikeDef(e: ClsLikeDefn)(using ctx: Ctx)(using Raise, Scope): ClassInfo = @@ -208,7 +209,7 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger)(fresh: Fresh, f s"apply${params.params.length}", params = pl, resultNum = 1, - body = bBlock(body)(x => Node.Result(Ls(x)))(using ctx3) + body = bBlock(body)(x => Node.Result(Ls(x)))(End(""))(using ctx3) ) ctx.class_acc += ClassInfo( clsUid.make, @@ -237,6 +238,7 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger)(fresh: Fresh, f val app = Call(v, tempSymbols.map(x => Arg(false, Value.Ref(x))).toList)(true, false) bLam(Value.Lam(paramsList, Return(app, false)))(k) case None => + log(s"bValue Ref: $x") k(ctx.findName(x) |> sr) case Value.This(sym) => errStop(msg"Unsupported value: This") case Value.Lit(lit) => k(Expr.Literal(lit)) @@ -306,18 +308,20 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger)(fresh: Fresh, f Node.LetExpr(v, Expr.CtorApp(ClassRef.fromName(sym.nme), args), k(v |> sr)) case Instantiate(cls, args) => errStop(msg"Unsupported kind of Instantiate") - Node.Result(Ls()) case x: Path => bPath(x)(k) - private def bBlock(blk: Block)(k: TrivialExpr => Ctx ?=> Node)(using ctx: Ctx)(using Raise, Scope) : Node = + private def bBlock(blk: Block)(k: TrivialExpr => Ctx ?=> Node)(ct: Block)(using ctx: Ctx)(using Raise, Scope) : Node = trace[Node](s"bBlock begin", x => s"bBlock end: ${x.show}"): blk match case Match(scrut, arms, dflt, rest) => bPath(scrut): case e: TrivialExpr => + val nextCont = Begin(rest, ct) val jp = fresh.make("j") - val fvset = freeVarsFilter(rest.freeVars -- rest.definedVars).map(allocIfNew) + val fvset = freeVarsFilter(nextCont.freeVars -- nextCont.definedVars).map(allocIfNew) val fvs1 = fvset.toList + log(s"Next cont is $nextCont") + log(s"Match free vars: $fvset ${nextCont.freeVars} ${nextCont.definedVars} $fvs1") val new_ctx = fvs1.foldLeft(ctx)((acc, x) => acc.addName(x, fresh.make)) val fvs = fvs1.map(new_ctx.findName(_)) def cont(x: TrivialExpr)(using ctx: Ctx) = Node.Jump( @@ -326,18 +330,18 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger)(fresh: Fresh, f ) val casesList: Ls[(Pat, Node)] = arms.map: case (Case.Lit(lit), body) => - (Pat.Lit(lit), bBlock(body)(cont)(using ctx)) + (Pat.Lit(lit), bBlock(body)(cont)(nextCont)(using ctx)) case (Case.Cls(cls, _), body) => - (Pat.Class(ClassRef.fromName(cls.nme)), bBlock(body)(cont)(using ctx)) + (Pat.Class(ClassRef.fromName(cls.nme)), bBlock(body)(cont)(nextCont)(using ctx)) case (Case.Tup(len, inf), body) => - (Pat.Class(ClassRef.fromName("Tuple" + len.toString())), bBlock(body)(cont)(using ctx)) - val defaultCase = dflt.map(bBlock(_)(cont)) + (Pat.Class(ClassRef.fromName("Tuple" + len.toString())), bBlock(body)(cont)(nextCont)(using ctx)) + val defaultCase = dflt.map(bBlock(_)(cont)(nextCont)(using ctx)) val jpdef = Func( fnUid.make, jp.str, params = fvs, resultNum = 1, - bBlock(rest)(k)(using new_ctx), + bBlock(rest)(k)(ct)(using new_ctx), ) summon[Ctx].def_acc += jpdef Node.Case(e, casesList, defaultCase) @@ -353,16 +357,15 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger)(fresh: Fresh, f case _: BlockTail => val definedVars = sub.definedVars definedVars.foreach(allocIfNew) - bBlock(sub): - x => bBlock(rest)(k) + bBlock(sub)(x => bBlock(rest)(k)(ct))(Begin(rest, ct)) case Assign(lhs, rhs, rest2) => - bBlock(Assign(lhs, rhs, Begin(rest2, rest)))(k) + bBlock(Assign(lhs, rhs, Begin(rest2, rest)))(k)(ct) case Begin(sub, rest2) => - bBlock(Begin(sub, Begin(rest2, rest)))(k) + bBlock(Begin(sub, Begin(rest2, rest)))(k)(ct) case Define(defn, rest2) => - bBlock(Define(defn, Begin(rest2, rest)))(k) + bBlock(Define(defn, Begin(rest2, rest)))(k)(ct) case Match(scrut, arms, dflt, rest2) => - bBlock(Match(scrut, arms, dflt, Begin(rest2, rest)))(k) + bBlock(Match(scrut, arms, dflt, Begin(rest2, rest)))(k)(ct) case _ => TODO(s"Other non-tail sub components of Begin not supported $sub") case TryBlock(sub, finallyDo, rest) => TODO("TryBlock not supported") case Assign(lhs, rhs, rest) => @@ -375,24 +378,34 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger)(fresh: Fresh, f val ctx2 = ctx.addFuncName(sym, Name(sym.nme), params.head.params.length) val f = bFunDef(fd)(using ctx2) ctx.def_acc += f - bBlock(rest)(k)(using ctx2) - case Define(_: ClsLikeDefn, rest) => bBlock(rest)(k) + bBlock(rest)(k)(End(""))(using ctx2) + case Define(_: ClsLikeDefn, rest) => bBlock(rest)(k)(End("")) case End(msg) => k(Expr.Literal(Tree.UnitLit(false))) case _: Block => val docBlock = blk.showAsTree errStop(msg"Unsupported block: $docBlock") - Node.Result(Ls()) def registerClasses(b: Block)(using ctx: Ctx)(using Raise, Scope): Ctx = b match case Define(cd @ ClsLikeDefn(_own, isym, sym, kind, _paramsOpt, parentSym, methods, privateFields, publicFields, preCtor, ctor), rest) => val c = bClsLikeDef(cd) - ctx.class_acc += c val new_ctx = ctx.addClassName(sym, Name(c.name)).addClassName(isym, Name(c.name)) + ctx.class_acc += c log(s"Define class: ${sym.nme} -> ${new_ctx}") registerClasses(rest)(using new_ctx) case _ => b.subBlocks.foldLeft(ctx)((ctx, rest) => registerClasses(rest)(using ctx)) + + def registerFunctions(b: Block)(using ctx: Ctx)(using Raise, Scope): Ctx = + b match + case Define(fd @ FunDefn(_own, sym, params, body), rest) => + if params.length != 1 then + errStop(msg"Curried function or zero arguments function not supported: ${params.length.toString}") + val ctx2 = ctx.addFuncName(sym, Name(sym.nme), params.head.params.length) + log(s"Define function: ${sym.nme} -> ${ctx2}") + registerFunctions(rest)(using ctx2) + case _ => + b.subBlocks.foldLeft(ctx)((ctx, rest) => registerFunctions(rest)(using ctx)) def bProg(e: Program)(using Raise, Scope): LlirProgram = var ctx = Ctx.empty @@ -400,7 +413,8 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger)(fresh: Fresh, f // * Classes may be defined after other things such as functions, // * especially now that the elaborator moves all functions to the top of the block. ctx = registerClasses(e.main)(using ctx) + ctx = registerFunctions(e.main)(using ctx) - val entry = bBlock(e.main)(x => Node.Result(Ls(x)))(using ctx) + val entry = bBlock(e.main)(x => Node.Result(Ls(x)))(End(""))(using ctx) LlirProgram(ctx.class_acc.toSet, ctx.def_acc.toSet, entry) diff --git a/hkmc2/shared/src/test/mlscript/codegen/BlockPrinter.mls b/hkmc2/shared/src/test/mlscript/codegen/BlockPrinter.mls index 18eecb3883..570000db8d 100644 --- a/hkmc2/shared/src/test/mlscript/codegen/BlockPrinter.mls +++ b/hkmc2/shared/src/test/mlscript/codegen/BlockPrinter.mls @@ -37,7 +37,9 @@ let x = x + 1 //│ end //│ else //│ set tmp = 0 in -//│ end; +//│ end +//│ in +//│ end; //│ set x3 = tmp in //│ set tmp1 = +(x3, 1) in //│ set x4 = tmp1 in diff --git a/hkmc2/shared/src/test/mlscript/llir/ControlFlow.mls b/hkmc2/shared/src/test/mlscript/llir/ControlFlow.mls index 6879f6a5cf..7dee5c06c4 100644 --- a/hkmc2/shared/src/test/mlscript/llir/ControlFlow.mls +++ b/hkmc2/shared/src/test/mlscript/llir/ControlFlow.mls @@ -298,4 +298,41 @@ f() //│ 11 - +:sllir +:intl +class A(x) +class B(y) +fun f(a) = + let t = if a is + A(_) then 1 + B(_) then 2 + t +f(A(1)) +//│ = 1 +//│ LLIR: +//│ class A(x) +//│ class B(y) +//│ def f(a) = +//│ case a of +//│ A => +//│ let x$1 = a. in +//│ let x$2 = 1 in +//│ jump j$0(x$2) +//│ _ => +//│ case a of +//│ B => +//│ let x$4 = a. in +//│ let x$5 = 2 in +//│ jump j$1(x$5) +//│ _ => +//│ panic "match error" +//│ def j$1(x$3) = +//│ jump j$0(x$3) +//│ def j$0(x$0) = +//│ x$0 +//│ let x$6 = A(1) in +//│ let* (x$7) = f(x$6) in +//│ x$7 +//│ +//│ Interpreted: +//│ 1 diff --git a/hkmc2/shared/src/test/mlscript/llir/Legacy.mls b/hkmc2/shared/src/test/mlscript/llir/Legacy.mls index 937a8d14b0..f782b3f7d2 100644 --- a/hkmc2/shared/src/test/mlscript/llir/Legacy.mls +++ b/hkmc2/shared/src/test/mlscript/llir/Legacy.mls @@ -1,6 +1,169 @@ :js :llir +:global + +:intl +class Pair[A, B](x: A, y: B) +fun mktup2(x, y) = mktup(x, y) +fun mktup(x, y) = Pair(x, y) +fun foo() = + mktup2(1, 2) +foo() +//│ = Pair(1, 2) +//│ +//│ Interpreted: +//│ Pair(1,2) + +:intl +class Pair[A, B](x: A, y: B) +fun foo(pair) = + if pair is + Pair(x, y) then Pair(x, y) +fun bar() = + foo(Pair(1, 2)) +bar() +//│ = Pair(1, 2) +//│ +//│ Interpreted: +//│ Pair(1,2) + +:intl +class Pair[A, B](x: A, y: B) +fun foo(pair) = + if pair is + Pair(x, y) then Pair(x, y) +fun bar() = + foo(Pair(1, 2)) +bar() +//│ = Pair(1, 2) +//│ +//│ Interpreted: +//│ Pair(1,2) + +:intl +class Pair[A, B](x: A, y: B) +fun silly(pair) = + let x = 0 + let n = if pair is + Pair(x1, x2) then + if pair is + Pair (x3, x4) then x3 + 1 + n + 1 +fun foo() = + let a = Pair(0, 1) + let b = silly(a) + b +foo() +//│ = 2 +//│ +//│ Interpreted: +//│ 2 + + +:intl +class Pair[A, B](x: A, y: B) +fun inc_fst(pair) = + let c = 2 + if pair is + Pair(x1, x2) then x1 + c +fun foo() = + let a = Pair(0, 1) + let b = inc_fst(a) + b +foo() +//│ = 2 +//│ +//│ Interpreted: +//│ 2 + +:intl +class Pair[A, B](x: A, y: B) +fun inc_fst(pair) = + let x = 0 + if pair is + Pair(x1, x2) then x2 + 1 +fun foo() = + let b = inc_fst(Pair(0, 1)) + b +foo() +//│ = 2 +//│ +//│ Interpreted: +//│ 2 + +:intl +:slot +abstract class Either[out A, out B]: Left[A, B] | Right[A, B] +class Left[out A, out B](x: A) extends Either[A, B] +class Right[out A, out B](y: B) extends Either[A, B] +fun foo(a, b) = + let t = if a is + Left(x) then Left(x + 1) + Right(y) then Right(b) + if t is + Left(x) then x + Right(y) then y +fun bar() = + foo(Right(2), 2) +bar() +//│ Pretty Lowered: +//│ +//│ define fun foo(a, b) { +//│ begin +//│ match a +//│ Left => +//│ set param0 = a.x in +//│ set x = param0 in +//│ set tmp = +(x, 1) in +//│ set tmp1 = Left(tmp) in +//│ end +//│ else +//│ match a +//│ Right => +//│ set param01 = a.y in +//│ set y = param01 in +//│ set tmp1 = Right(b) in +//│ end +//│ else +//│ throw new globalThis.Error("match error") +//│ in +//│ end +//│ in +//│ end; +//│ set t = tmp1 in +//│ match t +//│ Left => +//│ set param02 = t.x in +//│ set x1 = param02 in +//│ return x1 +//│ else +//│ match t +//│ Right => +//│ set param03 = t.y in +//│ set y1 = param03 in +//│ return y1 +//│ else +//│ throw new globalThis.Error("match error") +//│ in +//│ end +//│ in +//│ end +//│ } in +//│ define fun bar() { +//│ set tmp2 = Right(2) in +//│ return foo(tmp2, 2) +//│ } in +//│ define class Either in +//│ define class Left(x2) in +//│ define class Right(y2) in +//│ set block$res7 = bar() in +//│ return undefined +//│ = 2 +//│ +//│ Interpreted: +//│ 2 + :sllir :intl abstract class Option[out T]: Some[T] | None diff --git a/hkmc2DiffTests/src/test/scala/hkmc2/LlirDiffMaker.scala b/hkmc2DiffTests/src/test/scala/hkmc2/LlirDiffMaker.scala index 802382911d..86e0debd09 100644 --- a/hkmc2DiffTests/src/test/scala/hkmc2/LlirDiffMaker.scala +++ b/hkmc2DiffTests/src/test/scala/hkmc2/LlirDiffMaker.scala @@ -25,6 +25,7 @@ abstract class LlirDiffMaker extends BbmlDiffMaker: val scpp = NullaryCommand("scpp") val rcpp = NullaryCommand("rcpp") val intl = NullaryCommand("intl") + val lprelude = NullaryCommand("lpre") val wcpp = Command[Str]("wcpp", false)(x => x.stripLeading()) def printToFile(f: java.io.File)(op: java.io.PrintWriter => Unit) = @@ -33,18 +34,21 @@ abstract class LlirDiffMaker extends BbmlDiffMaker: given Elaborator.Ctx = curCtx + var preludeBlock: Opt[Block] = None + override def processTerm(trm: Blk, inImport: Bool)(using Raise): Unit = super.processTerm(trm, inImport) if llir.isSet then val low = ltl.givenIn: codegen.Lowering(lowerHandlers = false, stackLimit = None) - val le = low.program(trm) + var le = low.program(trm) + if lprelude.isSet then + preludeBlock = Some(le.main) given Scope = Scope.empty val fresh = Fresh() val fuid = FreshInt() val cuid = FreshInt() val llb = LlirBuilder(tl)(fresh, fuid, cuid) - given Ctx = Ctx.empty try val llirProg = llb.bProg(le) if sllir.isSet then From 471adf62849d24a98d66a2f8bf15670c5ce3f140 Mon Sep 17 00:00:00 2001 From: waterlens Date: Thu, 6 Feb 2025 19:38:45 +0800 Subject: [PATCH 30/88] add more legacy tests --- .../scala/hkmc2/codegen/llir/Builder.scala | 36 +- .../src/test/mlscript/llir/ControlFlow.mls | 62 +++ .../shared/src/test/mlscript/llir/Legacy.mls | 392 +++++++++++++++--- 3 files changed, 421 insertions(+), 69 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala index 7ead102972..eca7181d0c 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala @@ -95,23 +95,23 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger)(fresh: Fresh, f case _ => summon[Scope].lookup_!(l) private def freeVarsFilter(fvs: Set[Local]) = - fvs.filter: - case s: BuiltinSymbol => false - case t: TopLevelSymbol => false - case _ => true + trace[Set[Local]](s"freeVarsFilter begin", x => s"freeVarsFilter end: $x"): + fvs.filter: + case _: (BuiltinSymbol | TopLevelSymbol | ClassSymbol | MemberSymbol[?]) => false + case _ => true - private def bBind(name: Opt[Str], e: Result, body: Block)(k: TrivialExpr => Ctx ?=> Node)(using ctx: Ctx)(using Raise, Scope): Node = + private def bBind(name: Opt[Str], e: Result, body: Block)(k: TrivialExpr => Ctx ?=> Node)(ct: Block)(using ctx: Ctx)(using Raise, Scope): Node = trace[Node](s"bBind begin: $name", x => s"bBind end: ${x.show}"): bResult(e): case r: Expr.Ref => given Ctx = ctx.addName(name.getOrElse(fresh.make.str), r.name) log(s"bBind ref: $name -> $r") - bBlock(body)(k)(End("")) + bBlock(body)(k)(ct) case l: Expr.Literal => val v = fresh.make given Ctx = ctx.addName(name.getOrElse(fresh.make.str), v) log(s"bBind lit: $name -> $v") - Node.LetExpr(v, l, bBlock(body)(k)(End(""))) + Node.LetExpr(v, l, bBlock(body)(k)(ct)) private def bArgs(e: Ls[Arg])(k: Ls[TrivialExpr] => Ctx ?=> Node)(using ctx: Ctx)(using Raise, Scope): Node = trace[Node](s"bArgs begin", x => s"bArgs end: ${x.show}"): @@ -146,7 +146,7 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger)(fresh: Fresh, f sym.nme, params = pl, resultNum = 1, - body = bBlock(body)(x => Node.Result(Ls(x)))(End(""))(using ctx3) + body = bBlockWithEndCont(body)(x => Node.Result(Ls(x)))(using ctx3) ) private def bMethodDef(e: FunDefn)(using ctx: Ctx)(using Raise, Scope): Func = @@ -166,7 +166,7 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger)(fresh: Fresh, f sym.nme, params = pl, resultNum = 1, - body = bBlock(body)(x => Node.Result(Ls(x)))(End(""))(using ctx3) + body = bBlockWithEndCont(body)(x => Node.Result(Ls(x)))(using ctx3) ) private def bClsLikeDef(e: ClsLikeDefn)(using ctx: Ctx)(using Raise, Scope): ClassInfo = @@ -209,7 +209,7 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger)(fresh: Fresh, f s"apply${params.params.length}", params = pl, resultNum = 1, - body = bBlock(body)(x => Node.Result(Ls(x)))(End(""))(using ctx3) + body = bBlockWithEndCont(body)(x => Node.Result(Ls(x)))(using ctx3) ) ctx.class_acc += ClassInfo( clsUid.make, @@ -310,6 +310,9 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger)(fresh: Fresh, f errStop(msg"Unsupported kind of Instantiate") case x: Path => bPath(x)(k) + private def bBlockWithEndCont(blk: Block)(k: TrivialExpr => Ctx ?=> Node)(using Ctx)(using Raise, Scope) : Node = + bBlock(blk)(k)(End("")) + private def bBlock(blk: Block)(k: TrivialExpr => Ctx ?=> Node)(ct: Block)(using ctx: Ctx)(using Raise, Scope) : Node = trace[Node](s"bBlock begin", x => s"bBlock end: ${x.show}"): blk match @@ -320,7 +323,6 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger)(fresh: Fresh, f val jp = fresh.make("j") val fvset = freeVarsFilter(nextCont.freeVars -- nextCont.definedVars).map(allocIfNew) val fvs1 = fvset.toList - log(s"Next cont is $nextCont") log(s"Match free vars: $fvset ${nextCont.freeVars} ${nextCont.definedVars} $fvs1") val new_ctx = fvs1.foldLeft(ctx)((acc, x) => acc.addName(x, fresh.make)) val fvs = fvs1.map(new_ctx.findName(_)) @@ -348,7 +350,7 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger)(fresh: Fresh, f case Return(res, implct) => bResult(res)(x => Node.Result(Ls(x))) case Throw(Instantiate(Select(Value.Ref(_), ident), Ls(Value.Lit(Tree.StrLit(e))))) if ident.name == "Error" => Node.Panic(e) - case Label(label, body, rest) => ??? + case Label(label, body, rest) => TODO("Label not supported") case Break(label) => TODO("Break not supported") case Continue(label) => TODO("Continue not supported") case Begin(sub, rest) => @@ -370,7 +372,7 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger)(fresh: Fresh, f case TryBlock(sub, finallyDo, rest) => TODO("TryBlock not supported") case Assign(lhs, rhs, rest) => val name = allocIfNew(lhs) - bBind(S(name), rhs, rest)(k) + bBind(S(name), rhs, rest)(k)(ct) case AssignField(lhs, nme, rhs, rest) => TODO("AssignField not supported") case Define(fd @ FunDefn(_own, sym, params, body), rest) => if params.length != 1 then @@ -378,8 +380,8 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger)(fresh: Fresh, f val ctx2 = ctx.addFuncName(sym, Name(sym.nme), params.head.params.length) val f = bFunDef(fd)(using ctx2) ctx.def_acc += f - bBlock(rest)(k)(End(""))(using ctx2) - case Define(_: ClsLikeDefn, rest) => bBlock(rest)(k)(End("")) + bBlock(rest)(k)(ct)(using ctx2) + case Define(_: ClsLikeDefn, rest) => bBlock(rest)(k)(ct) case End(msg) => k(Expr.Literal(Tree.UnitLit(false))) case _: Block => val docBlock = blk.showAsTree @@ -415,6 +417,8 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger)(fresh: Fresh, f ctx = registerClasses(e.main)(using ctx) ctx = registerFunctions(e.main)(using ctx) - val entry = bBlock(e.main)(x => Node.Result(Ls(x)))(End(""))(using ctx) + log(s"Classes: ${ctx.class_ctx}") + + val entry = bBlockWithEndCont(e.main)(x => Node.Result(Ls(x)))(using ctx) LlirProgram(ctx.class_acc.toSet, ctx.def_acc.toSet, entry) diff --git a/hkmc2/shared/src/test/mlscript/llir/ControlFlow.mls b/hkmc2/shared/src/test/mlscript/llir/ControlFlow.mls index 7dee5c06c4..4da906f22e 100644 --- a/hkmc2/shared/src/test/mlscript/llir/ControlFlow.mls +++ b/hkmc2/shared/src/test/mlscript/llir/ControlFlow.mls @@ -336,3 +336,65 @@ f(A(1)) //│ //│ Interpreted: //│ 1 + +:sllir +:intl +class A(x) +class B(y) +fun f(a) = + let t = if a is + A(_) then if a is + A(1) then 1 + B(_) then 2 + B(_) then 3 + t +f(A(1)) +//│ = 1 +//│ LLIR: +//│ class A(x) +//│ class B(y) +//│ def f(a) = +//│ case a of +//│ A => +//│ let x$1 = a. in +//│ case a of +//│ A => +//│ let x$3 = a. in +//│ case x$3 of +//│ IntLit(1) => +//│ let x$5 = 1 in +//│ jump j$2(x$5) +//│ _ => +//│ panic "match error" +//│ _ => +//│ case a of +//│ B => +//│ let x$7 = a. in +//│ let x$8 = 2 in +//│ jump j$3(x$8) +//│ _ => +//│ panic "match error" +//│ _ => +//│ case a of +//│ B => +//│ let x$10 = a. in +//│ let x$11 = 3 in +//│ jump j$4(x$11) +//│ _ => +//│ panic "match error" +//│ def j$2(x$4) = +//│ jump j$1(x$4) +//│ def j$3(x$6) = +//│ jump j$1(x$6) +//│ def j$1(x$2) = +//│ jump j$0(x$2) +//│ def j$4(x$9) = +//│ jump j$0(x$9) +//│ def j$0(x$0) = +//│ x$0 +//│ let x$12 = A(1) in +//│ let* (x$13) = f(x$12) in +//│ x$13 +//│ +//│ Interpreted: +//│ 1 diff --git a/hkmc2/shared/src/test/mlscript/llir/Legacy.mls b/hkmc2/shared/src/test/mlscript/llir/Legacy.mls index f782b3f7d2..a2e8455aa0 100644 --- a/hkmc2/shared/src/test/mlscript/llir/Legacy.mls +++ b/hkmc2/shared/src/test/mlscript/llir/Legacy.mls @@ -93,7 +93,6 @@ foo() //│ 2 :intl -:slot abstract class Either[out A, out B]: Left[A, B] | Right[A, B] class Left[out A, out B](x: A) extends Either[A, B] class Right[out A, out B](y: B) extends Either[A, B] @@ -107,63 +106,122 @@ fun foo(a, b) = fun bar() = foo(Right(2), 2) bar() -//│ Pretty Lowered: -//│ -//│ define fun foo(a, b) { -//│ begin -//│ match a -//│ Left => -//│ set param0 = a.x in -//│ set x = param0 in -//│ set tmp = +(x, 1) in -//│ set tmp1 = Left(tmp) in -//│ end -//│ else -//│ match a -//│ Right => -//│ set param01 = a.y in -//│ set y = param01 in -//│ set tmp1 = Right(b) in -//│ end -//│ else -//│ throw new globalThis.Error("match error") -//│ in -//│ end -//│ in -//│ end; -//│ set t = tmp1 in -//│ match t -//│ Left => -//│ set param02 = t.x in -//│ set x1 = param02 in -//│ return x1 -//│ else -//│ match t -//│ Right => -//│ set param03 = t.y in -//│ set y1 = param03 in -//│ return y1 -//│ else -//│ throw new globalThis.Error("match error") -//│ in -//│ end -//│ in -//│ end -//│ } in -//│ define fun bar() { -//│ set tmp2 = Right(2) in -//│ return foo(tmp2, 2) -//│ } in -//│ define class Either in -//│ define class Left(x2) in -//│ define class Right(y2) in -//│ set block$res7 = bar() in -//│ return undefined //│ = 2 //│ //│ Interpreted: //│ 2 +:intl +abstract class Nat: S[Nat] | O +class S(s: Nat) extends Nat +object O extends Nat +fun foo() = + bar(S(O)) +fun bar(x) = + baz(x) +fun baz(x) = + if x is + S(s) then s + O then x +foo() +//│ = O +//│ +//│ Interpreted: +//│ O() + +:intl +class A(x, y, z) +class B(m, n) +fun complex_foo(t) = + let r = if t is + A(x, y, z) then x + y * z + B(m, n) then m - n + let s = B(1, 2) + let u = if s is + A(x, y, z) then 3 + B(m, n) then 4 + r + u +fun bar() = + complex_foo(A(6, 7, 8)) + complex_foo(B(9, 10)) +bar() +//│ = 3 +//│ +//│ Interpreted: +//│ 3 + +:intl +class A(w, x) +class B(y) +class C(z) +fun complex_foo(t) = + let a = 1 + 2 + let b = 1 * 2 + let x = if t is + A(x, y) then y + B(x) then B(x + b) + C(x) then C(0) + let z = A(5, x) + let v = B(6) + let y = if x is + A(x, y) then + let m = x + a + b + if y is + A(x, y) then x + B(x) then m + C(x) then 0 + B(x) then 2 + C(x) then 3 + if z is + A(x, y) then x + B(x) then 4 + C(x) then + if v is + A(x, y) then x + B(x) then 7 + C(x) then 8 +fun bar() = + complex_foo(A(10, A(9, B(10)))) +bar() +//│ = 5 +//│ +//│ Interpreted: +//│ 5 + +:intl +fun fib(n) = if n < 2 then n else fib(n-1) + fib(n-2) +fib(20) +//│ = 6765 +//│ +//│ Interpreted: +//│ 6765 + +:intl +fun odd(x) = if x == 0 then false else even(x-1) +fun even(x) = if x == 0 then true else odd(x-1) +fun foo() = odd(10) +foo() +//│ = false +//│ +//│ Interpreted: +//│ false + +:intl +abstract class Option[out T]: Some[T] | None +class Some[out T](x: T) extends Option[T] +object None extends Option +fun not(x) = + if x then false else true +fun foo(x) = + if x then None + else Some(foo(not(x))) +fun main() = foo(false) +main() +//│ = Some(None) +//│ +//│ Interpreted: +//│ Some(None()) + :sllir :intl abstract class Option[out T]: Some[T] | None @@ -267,3 +325,231 @@ main() //│ //│ Interpreted: //│ 404 + +:intl +abstract class Nat: S[Nat] | O +class S(s: Nat) extends Nat +object O extends Nat +fun odd(x) = + if x is + O then false + S(s) then even(s) +fun even(x) = + if x is + O then true + S(s) then odd(s) +fun foo() = odd(S(S(S(O)))) +foo() +//│ = true +//│ +//│ Interpreted: +//│ true + +:intl +abstract class Nat: S[Nat] | O +class S(s: Nat) extends Nat +object O extends Nat +fun odd(x) = + if x is + O then false + S(s) then even(s) +fun even(x) = + if x is + O then true + S(s) then odd(s) +fun mk(n) = if n > 0 then S(mk(n - 1)) else O +fun foo() = odd(mk(10)) +foo() +//│ = false +//│ +//│ Interpreted: +//│ false + +:intl +abstract class Nat: S[Nat] | O +class S(s: Nat) extends Nat +object O extends Nat +fun odd(x) = + if x is + O then false + S(s) then even(s) +fun even(x) = + if x is + O then true + S(s) then odd(s) +fun mk(n) = if n > 0 then S(mk(n - 1)) else O +fun foo() = odd(S(S(mk(10)))) +foo() +//│ = false +//│ +//│ Interpreted: +//│ false + +:intl +abstract class Nat: S[Nat] | O +class S(s: Nat) extends Nat +object O extends Nat +fun odd(x) = + if x is + O then false + S(s) then even(s) +fun even(x) = + if x is + O then true + S(s) then odd(s) +fun foo() = odd(if 10 > 0 then S(O) else O) +fun bar() = if 10 > 0 then odd(S(O)) else odd(O) +fun main() = + foo() + bar() +main() +//│ = true +//│ +//│ Interpreted: +//│ true + +:intl +abstract class Option[out T]: Some[T] | None +class Some[out T](x: T) extends Option[T] +object None extends Option +abstract class List[out T]: Cons[T] | Nil +class (::) Cons[out T](head: T, tail: List[T]) extends List[T] +object Nil extends List +fun head_opt(l) = + if l is + Nil then None + Cons(h, t) then Some(h) +fun is_none(o) = + if o is + None then true + Some(x) then false +fun is_empty(l) = + is_none(head_opt(l)) +fun main() = + is_empty(Cons(1, Cons(2, Nil))) +main() +//│ = false +//│ +//│ Interpreted: +//│ false + +:intl +abstract class Option[out T]: Some[T] | None +class Some[out T](x: T) extends Option[T] +object None extends Option +abstract class List[out T]: Cons[T] | Nil +class (::) Cons[out T](head: T, tail: List[T]) extends List[T] +object Nil extends List +fun mk_list(n) = + if n == 0 then Nil else Cons(n, mk_list(n - 1)) +fun head_opt(l) = + if l is + Nil then None + Cons(h, t) then Some(h) +fun is_none(o) = + if o is + None then true + Some(x) then false +fun is_empty(l) = + is_none(head_opt(l)) +fun main() = + is_empty(mk_list(10)) +main() +//│ = false +//│ +//│ Interpreted: +//│ false + + +:intl +abstract class Option[out T]: Some[T] | None +class Some[out T](x: T) extends Option[T] +object None extends Option +abstract class List[out T]: Cons[T] | Nil +class (::) Cons[out T](head: T, tail: List[T]) extends List[T] +object Nil extends List +fun mk_list(n) = + if n == 0 then Nil else Cons(n, mk_list(n - 1)) +fun last_opt(l) = + if l is + Nil then None + Cons(h, t) then + if t is + Nil then Some(h) + Cons(h2, t2) then last_opt(t) +fun main() = + last_opt(mk_list(10)) +main() +//│ = Some(1) +//│ +//│ Interpreted: +//│ Some(1) + +:intl +abstract class Option[out T]: Some[T] | None +class Some[out T](x: T) extends Option[T] +object None extends Option +fun is_some(o) = + if o is + Some(x) then true + None then false +fun e0(w) = + w + 8 + 9 + 10 +fun e1(a, c) = + a + 1 + 2 + 3 + 4 +fun e3(c) = + let m = 4 + let n = 5 + let p = 6 + let q = 7 + if c then m + n + p + q else m + n - p + q +fun e2(x) = + x + 12 + 13 + 14 +fun f(x) = + let c1 = is_some(x) + let z = e3(c1) + let w = if x is + Some(a) then e1(a, z) + None then e2(z) + e0(w) +fun main() = + f(Some(2)) + f(None) +main() +//│ = 115 +//│ +//│ Interpreted: +//│ 115 + +:intl +abstract class Nat: S[Nat] | O +class S(s: Nat) extends Nat +object O extends Nat +fun pred(n) = + if n is + S(p) then p + O then O +fun plus(n1, n2) = + if n1 is + O then n2 + S(p) then S(plus(p, n2)) +fun fib(n) = + if n is + O then S(O) + S(p) then + if p is + O then S(O) + S(q) then plus(fib(p), fib(q)) +fun to_int(n) = + if n is + O then 0 + S(p) then 1 + to_int(p) +fun to_nat(n) = + if n == 0 then O + else S(to_nat(n - 1)) +fun main() = + to_int(fib(to_nat(14))) +main() +//│ = 610 +//│ +//│ Interpreted: +//│ 610 From 37b35332e2068bd0b5f70d5b3a339ac76ccc5548 Mon Sep 17 00:00:00 2001 From: waterlens Date: Thu, 6 Feb 2025 19:52:26 +0800 Subject: [PATCH 31/88] add a test --- hkmc2/shared/src/test/mlscript/llir/Classes.mls | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 hkmc2/shared/src/test/mlscript/llir/Classes.mls diff --git a/hkmc2/shared/src/test/mlscript/llir/Classes.mls b/hkmc2/shared/src/test/mlscript/llir/Classes.mls new file mode 100644 index 0000000000..adac4690da --- /dev/null +++ b/hkmc2/shared/src/test/mlscript/llir/Classes.mls @@ -0,0 +1,15 @@ +:llir + +:intl +abstract class Callable +object FnLike1 extends Callable with + fun apply1(x) = x * 2 +fun apply(f, x) = f(x) +fun main() = + let mul2 = FnLike1 + apply(mul2, 3) +main() +//│ +//│ Interpreted: +//│ 6 + From 1589d997c6d09b356fce39864ad9c1034ede96cb Mon Sep 17 00:00:00 2001 From: waterlens Date: Thu, 6 Feb 2025 21:01:58 +0800 Subject: [PATCH 32/88] add more tests --- .../main/scala/hkmc2/codegen/llir/Builder.scala | 13 +++++++++++-- hkmc2/shared/src/test/mlscript/llir/Classes.mls | 14 ++++++++++++++ .../shared/src/test/mlscript/llir/ControlFlow.mls | 1 + hkmc2/shared/src/test/mlscript/llir/Ctor.mls | 1 + .../shared/src/test/mlscript/llir/HigherOrder.mls | 1 + hkmc2/shared/src/test/mlscript/llir/Legacy.mls | 1 + hkmc2/shared/src/test/mlscript/llir/Method.mls | 15 +++++++++++---- .../src/test/mlscript/llir/NofibPrelude.mls | 7 +++++++ 8 files changed, 47 insertions(+), 6 deletions(-) create mode 100644 hkmc2/shared/src/test/mlscript/llir/NofibPrelude.mls diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala index eca7181d0c..bd8133cac9 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala @@ -183,7 +183,8 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger)(fresh: Fresh, f val funcs = methods.map(bMethodDef) def parentFromPath(p: Path): Set[Str] = p match case Value.Ref(l) => Set(l.nme) - case _ => errStop(msg"Unsupported parent path") + case Select(Value.Ref(l), Tree.Ident("class")) => Set(l.nme) + case _ => errStop(msg"Unsupported parent path ${p.toString()}") ClassInfo( clsUid.make, sym.nme, @@ -299,7 +300,15 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger)(fresh: Fresh, f bPath(s): case f: TrivialExpr => Node.LetMethodCall(Ls(v), ClassRef(R("Callable")), Name("apply" + args.length), f :: args, k(v |> sr)) - case Call(_, _) => errStop(msg"Unsupported kind of Call") + case Call(s @ Select(r @ Value.Ref(sym), Tree.Ident(fld)), args) if s.symbol.isDefined => + bPath(r): + case r => + bArgs(args): + case args: Ls[TrivialExpr] => + val v = fresh.make + log(s"Method Call Select: $r.$fld with ${s.symbol}") + errStop(msg"Unsupported method call") + case Call(_, _) => errStop(msg"Unsupported kind of Call ${r.toString()}") case Instantiate( Select(Value.Ref(sym), Tree.Ident("class")), args) => bPaths(args): diff --git a/hkmc2/shared/src/test/mlscript/llir/Classes.mls b/hkmc2/shared/src/test/mlscript/llir/Classes.mls index adac4690da..a9383aabcc 100644 --- a/hkmc2/shared/src/test/mlscript/llir/Classes.mls +++ b/hkmc2/shared/src/test/mlscript/llir/Classes.mls @@ -1,4 +1,5 @@ :llir +:cpp :intl abstract class Callable @@ -13,3 +14,16 @@ main() //│ Interpreted: //│ 6 +:todo SelProj +:intl +:sllir +class Base() with + fun get() = 1 +class Derived() extends Base with + fun get() = 2 +fun main() = + let d = Derived() + d.Base#get() * d.Derived#get() +main() +//│ ═══[COMPILATION ERROR] Unsupported method call +//│ Stopped due to an error during the Llir generation diff --git a/hkmc2/shared/src/test/mlscript/llir/ControlFlow.mls b/hkmc2/shared/src/test/mlscript/llir/ControlFlow.mls index 4da906f22e..fe075de7da 100644 --- a/hkmc2/shared/src/test/mlscript/llir/ControlFlow.mls +++ b/hkmc2/shared/src/test/mlscript/llir/ControlFlow.mls @@ -1,5 +1,6 @@ :js :llir +:cpp :global diff --git a/hkmc2/shared/src/test/mlscript/llir/Ctor.mls b/hkmc2/shared/src/test/mlscript/llir/Ctor.mls index 120bc1d1d4..fcf81a3eb7 100644 --- a/hkmc2/shared/src/test/mlscript/llir/Ctor.mls +++ b/hkmc2/shared/src/test/mlscript/llir/Ctor.mls @@ -1,5 +1,6 @@ :js :llir +:cpp :global diff --git a/hkmc2/shared/src/test/mlscript/llir/HigherOrder.mls b/hkmc2/shared/src/test/mlscript/llir/HigherOrder.mls index 6a7307cff2..3278410672 100644 --- a/hkmc2/shared/src/test/mlscript/llir/HigherOrder.mls +++ b/hkmc2/shared/src/test/mlscript/llir/HigherOrder.mls @@ -1,5 +1,6 @@ :js :llir +:cpp :global diff --git a/hkmc2/shared/src/test/mlscript/llir/Legacy.mls b/hkmc2/shared/src/test/mlscript/llir/Legacy.mls index a2e8455aa0..57e37c4e39 100644 --- a/hkmc2/shared/src/test/mlscript/llir/Legacy.mls +++ b/hkmc2/shared/src/test/mlscript/llir/Legacy.mls @@ -1,5 +1,6 @@ :js :llir +:cpp :global diff --git a/hkmc2/shared/src/test/mlscript/llir/Method.mls b/hkmc2/shared/src/test/mlscript/llir/Method.mls index 89cce0a7ef..9449d727fb 100644 --- a/hkmc2/shared/src/test/mlscript/llir/Method.mls +++ b/hkmc2/shared/src/test/mlscript/llir/Method.mls @@ -3,16 +3,23 @@ :llir :cpp - :sllir -:lot +:slot class A(m) with fun f() = m +fun main() = + let a = A(1) + a.A#f() +main() //│ LLIR: //│ class A(m) { //│ def f() = //│ m //│ } -//│ -//│ undefined +//│ def main() = +//│ let x$0 = A(1) in +//│ let x$1 = f.f(x$0) in +//│ x$1 +//│ let* (x$2) = main() in +//│ x$2 diff --git a/hkmc2/shared/src/test/mlscript/llir/NofibPrelude.mls b/hkmc2/shared/src/test/mlscript/llir/NofibPrelude.mls new file mode 100644 index 0000000000..14c35a2115 --- /dev/null +++ b/hkmc2/shared/src/test/mlscript/llir/NofibPrelude.mls @@ -0,0 +1,7 @@ +type Char = String + +abstract class Option[out T]: Some[T] | None +class Some[out T](x: T) extends Option[T] +object None extends Option + +fun fromSome(s) = if s is Some(x) then x From 0d6b593bee049f46cdafb8cd0817448ae5858310 Mon Sep 17 00:00:00 2001 From: waterlens Date: Fri, 7 Feb 2025 13:36:44 +0800 Subject: [PATCH 33/88] WIP save --- .../scala/hkmc2/codegen/llir/Builder.scala | 39 ++- .../shared/src/test/mlscript/llir/Classes.mls | 23 +- .../src/test/mlscript/llir/HigherOrder.mls | 18 +- .../shared/src/test/mlscript/llir/Method.mls | 2 +- .../src/test/mlscript/llir/NofibPrelude.mls | 271 ++++++++++++++++++ 5 files changed, 332 insertions(+), 21 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala index bd8133cac9..a91f519ca4 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala @@ -35,6 +35,7 @@ final case class Ctx( symbol_ctx: Map[Str, Name] = Map.empty, fn_ctx: Map[Local, FuncInfo] = Map.empty, // is a known function class_ctx: Map[Local, Name] = Map.empty, + flow_ctx: Map[Path, Name] = Map.empty, block_ctx: Map[Local, Name] = Map.empty, is_top_level: Bool = true, method_class: Opt[Symbol] = None, @@ -50,6 +51,7 @@ final case class Ctx( case None => errStop(msg"Class not found: ${n.toString}") case Some(value) => value + def addKnownClass(n: Path, m: Name) = copy(flow_ctx = flow_ctx + (n -> m)) def addName(n: Str, m: Name) = copy(symbol_ctx = symbol_ctx + (n -> m)) def findName(n: Str)(using Raise): Name = symbol_ctx.get(n) match case None => @@ -193,12 +195,12 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger)(fresh: Fresh, f funcs.map(f => f.name -> f).toMap, ) - private def bLam(lam: Value.Lam)(k: TrivialExpr => Ctx ?=> Node)(using ctx: Ctx)(using Raise, Scope) : Node = + private def bLam(lam: Value.Lam, nameHint: Opt[Str])(k: TrivialExpr => Ctx ?=> Node)(using ctx: Ctx)(using Raise, Scope) : Node = trace[Node](s"bLam begin", x => s"bLam end: ${x.show}"): val Value.Lam(params, body) = lam // Generate an auxiliary class inheriting from Callable val freeVars = freeVarsFilter(lam.freeVars -- lam.body.definedVars -- ctx.fn_ctx.keySet) - val name = fresh.make("Lambda") + val name = fresh.make(s"Lambda${nameHint.fold("")(x => "_" + x)}") val clsParams = freeVars.toList.map(_.nme) val args = freeVars.toList.map(allocIfNew) val ctx2 = ctx.setFreeVars(freeVars) @@ -237,20 +239,27 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger)(fresh: Fresh, f val tempSymbols = (0 until f.paramsSize).map(x => VarSymbol(Tree.Ident(fresh.make("arg").str))) val paramsList = PlainParamList((0 until f.paramsSize).zip(tempSymbols).map((_n, sym) => Param(FldFlags.empty, sym, N)).toList) val app = Call(v, tempSymbols.map(x => Arg(false, Value.Ref(x))).toList)(true, false) - bLam(Value.Lam(paramsList, Return(app, false)))(k) + log(s"bValue Ref: ${l.toString()} -> $x") + bLam(Value.Lam(paramsList, Return(app, false)), S(x))(k) case None => log(s"bValue Ref: $x") k(ctx.findName(x) |> sr) case Value.This(sym) => errStop(msg"Unsupported value: This") case Value.Lit(lit) => k(Expr.Literal(lit)) - case lam @ Value.Lam(params, body) => bLam(lam)(k) + case lam @ Value.Lam(params, body) => bLam(lam, N)(k) case Value.Arr(elems) => errStop(msg"Unsupported value: Arr") private def getClassOfMem(p: FieldSymbol)(using ctx: Ctx)(using Raise, Scope): Local = trace[Local](s"bMemSym { $p } begin", x => s"bMemSym end: $x"): p match case ts: TermSymbol => ts.owner.get - case ms: MemberSymbol[?] => ms.defn.get.sym + case ms: MemberSymbol[?] => + ms.defn match + case Some(d: ClassLikeDef) => d.owner.get + case Some(d: TermDefinition) => d.owner.get + case Some(value) => errStop(msg"Member symbol without class definition ${value.toString}") + case None => errStop(msg"Member symbol without definition") + private def bPath(p: Path)(k: TrivialExpr => Ctx ?=> Node)(using ctx: Ctx)(using Raise, Scope) : Node = trace[Node](s"bPath { $p } begin", x => s"bPath end: ${x.show}"): @@ -263,7 +272,19 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger)(fresh: Fresh, f log(s"bPath Select: $qual.$name with ${s.symbol}") s.symbol match case None => - errStop(msg"Unsupported selection by users") + ctx.flow_ctx.get(qual) match + case Some(cls) => + bPath(qual): + case q: Expr.Ref => + val v = fresh.make + val clsN = ClassRef.fromName(cls) + val field = name.name + Node.LetExpr(v, Expr.Select(q.name, clsN, field), k(v |> sr)) + case q: Expr.Literal => + errStop(msg"Unsupported select on literal") + case None => + log(s"${ctx.flow_ctx}") + errStop(msg"Unsupported selection by users") case Some(value) => bPath(qual): case q: Expr.Ref => @@ -273,7 +294,6 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger)(fresh: Fresh, f Node.LetExpr(v, Expr.Select(q.name, cls, field), k(v |> sr)) case q: Expr.Literal => errStop(msg"Unsupported select on literal") - Node.Result(Ls()) case x: Value => bValue(x)(k) private def bResult(r: Result)(k: TrivialExpr => Ctx ?=> Node)(using ctx: Ctx)(using Raise, Scope) : Node = @@ -307,7 +327,7 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger)(fresh: Fresh, f case args: Ls[TrivialExpr] => val v = fresh.make log(s"Method Call Select: $r.$fld with ${s.symbol}") - errStop(msg"Unsupported method call") + Node.LetMethodCall(Ls(v), ClassRef.fromName(getClassOfMem(s.symbol.get).nme), Name(fld), r :: args, k(v |> sr)) case Call(_, _) => errStop(msg"Unsupported kind of Call ${r.toString()}") case Instantiate( Select(Value.Ref(sym), Tree.Ident("class")), args) => @@ -345,7 +365,8 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger)(fresh: Fresh, f case (Case.Cls(cls, _), body) => (Pat.Class(ClassRef.fromName(cls.nme)), bBlock(body)(cont)(nextCont)(using ctx)) case (Case.Tup(len, inf), body) => - (Pat.Class(ClassRef.fromName("Tuple" + len.toString())), bBlock(body)(cont)(nextCont)(using ctx)) + val ctx2 = ctx.addKnownClass(scrut, Name("Tuple" + len.toString())) + (Pat.Class(ClassRef.fromName("Tuple" + len.toString())), bBlock(body)(cont)(nextCont)(using ctx2)) val defaultCase = dflt.map(bBlock(_)(cont)(nextCont)(using ctx)) val jpdef = Func( fnUid.make, diff --git a/hkmc2/shared/src/test/mlscript/llir/Classes.mls b/hkmc2/shared/src/test/mlscript/llir/Classes.mls index a9383aabcc..de14b09778 100644 --- a/hkmc2/shared/src/test/mlscript/llir/Classes.mls +++ b/hkmc2/shared/src/test/mlscript/llir/Classes.mls @@ -25,5 +25,24 @@ fun main() = let d = Derived() d.Base#get() * d.Derived#get() main() -//│ ═══[COMPILATION ERROR] Unsupported method call -//│ Stopped due to an error during the Llir generation +//│ LLIR: +//│ class Base() { +//│ def get() = +//│ 1 +//│ } +//│ class Derived() extends Base { +//│ def get() = +//│ 2 +//│ } +//│ def main() = +//│ let x$0 = Derived() in +//│ let x$1 = Base.get(x$0) in +//│ let x$2 = Derived.get(x$0) in +//│ let x$3 = *(x$1,x$2) in +//│ x$3 +//│ let* (x$4) = main() in +//│ x$4 +//│ +//│ Interpreted: +//│ 4 + diff --git a/hkmc2/shared/src/test/mlscript/llir/HigherOrder.mls b/hkmc2/shared/src/test/mlscript/llir/HigherOrder.mls index 3278410672..432a33f1ad 100644 --- a/hkmc2/shared/src/test/mlscript/llir/HigherOrder.mls +++ b/hkmc2/shared/src/test/mlscript/llir/HigherOrder.mls @@ -129,7 +129,7 @@ fun dummy() = add dummy()(1, 2) //│ = 3 //│ LLIR: -//│ class Lambda$0() extends Callable { +//│ class Lambda_add$0() extends Callable { //│ def apply2(arg$0,arg$1) = //│ let* (x$1) = add(arg$0,arg$1) in //│ x$1 @@ -138,7 +138,7 @@ dummy()(1, 2) //│ let x$0 = +(a,b) in //│ x$0 //│ def dummy() = -//│ let x$2 = Lambda$0() in +//│ let x$2 = Lambda_add$0() in //│ x$2 //│ let* (x$3) = dummy() in //│ let x$4 = Callable.apply2(x$3,1,2) in @@ -146,17 +146,17 @@ dummy()(1, 2) //│ //│ Cpp: //│ #include "mlsprelude.h" -//│ struct _mls_Lambda_0; +//│ struct _mls_Lambda_add_0; //│ _mlsValue _mls_add(_mlsValue, _mlsValue); //│ _mlsValue _mls_dummy(); //│ _mlsValue _mlsMain(); -//│ struct _mls_Lambda_0: public _mls_Callable { +//│ struct _mls_Lambda_add_0: public _mls_Callable { //│ -//│ constexpr static inline const char *typeName = "Lambda$0"; +//│ constexpr static inline const char *typeName = "Lambda_add$0"; //│ constexpr static inline uint32_t typeTag = nextTypeTag(); //│ virtual void print() const override { std::printf("%s", typeName); } //│ virtual void destroy() override { operator delete (this, std::align_val_t(_mlsAlignment)); } -//│ static _mlsValue create() { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) _mls_Lambda_0; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; return _mlsValue(_mlsVal); } +//│ static _mlsValue create() { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) _mls_Lambda_add_0; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; return _mlsValue(_mlsVal); } //│ virtual _mlsValue _mls_apply2(_mlsValue _mls_arg_0, _mlsValue _mls_arg_1) { //│ _mlsValue _mls_retval; //│ auto _mls_x_1 = _mls_add(_mls_arg_0, _mls_arg_1); @@ -172,7 +172,7 @@ dummy()(1, 2) //│ } //│ _mlsValue _mls_dummy() { //│ _mlsValue _mls_retval; -//│ auto _mls_x_2 = _mlsValue::create<_mls_Lambda_0>(); +//│ auto _mls_x_2 = _mlsValue::create<_mls_Lambda_add_0>(); //│ _mls_retval = _mls_x_2; //│ return _mls_retval; //│ } @@ -212,7 +212,7 @@ main() //│ let* (x$10) = inc(x1) in //│ x$10 //│ } -//│ class Lambda$1() extends Callable { +//│ class Lambda_inc$0() extends Callable { //│ def apply1(arg$0) = //│ let* (x$16) = inc(arg$0) in //│ x$16 @@ -249,7 +249,7 @@ main() //│ let x$13 = Nil() in //│ let x$14 = Cons(4,x$13) in //│ let x$15 = Cons(3,x$14) in -//│ let x$17 = Lambda$1() in +//│ let x$17 = Lambda_inc$0() in //│ let* (x$18) = map(x$17,x$15) in //│ x$18 //│ let* (x$19) = main() in diff --git a/hkmc2/shared/src/test/mlscript/llir/Method.mls b/hkmc2/shared/src/test/mlscript/llir/Method.mls index 9449d727fb..915d63f799 100644 --- a/hkmc2/shared/src/test/mlscript/llir/Method.mls +++ b/hkmc2/shared/src/test/mlscript/llir/Method.mls @@ -18,7 +18,7 @@ main() //│ } //│ def main() = //│ let x$0 = A(1) in -//│ let x$1 = f.f(x$0) in +//│ let x$1 = A.f(x$0) in //│ x$1 //│ let* (x$2) = main() in //│ x$2 diff --git a/hkmc2/shared/src/test/mlscript/llir/NofibPrelude.mls b/hkmc2/shared/src/test/mlscript/llir/NofibPrelude.mls index 14c35a2115..540684aee6 100644 --- a/hkmc2/shared/src/test/mlscript/llir/NofibPrelude.mls +++ b/hkmc2/shared/src/test/mlscript/llir/NofibPrelude.mls @@ -1,3 +1,6 @@ +:llir +:js + type Char = String abstract class Option[out T]: Some[T] | None @@ -5,3 +8,271 @@ class Some[out T](x: T) extends Option[T] object None extends Option fun fromSome(s) = if s is Some(x) then x + +abstract class List[out T]: Cons[T] | Nil +class (::) Cons[out T](head: T, tail: List[T]) extends List[T] +object Nil extends List +fun ltList(xs, ys, lt, gt) = if xs is + Nil and + ys is Nil then false + else true + x :: xs and ys is + Nil then false + y :: ys and + lt(x, y) then true + gt(x, y) then false + else ltList(xs, ys, lt, gt) + +fun ltTup2(t1, t2, lt1, gt1, lt2) = if t1 is [a, b] and t2 is [c, d] and + lt1(a, c) then true + gt1(a, c) then false + else lt2(b, d) +fun eqTup2(t1, t2) = if t1 is [a, b] and t2 is [c, d] then a == c and b == d + +fun compose(f, g) = x => f(g(x)) + +fun snd(x) = if x is [f, s] then s +fun fst(x) = if x is [f, s] then f + +fun until(p, f, i) = if p(i) then i else until(p, f, f(i)) + +fun flip(f, x, y) = f(y)(x) + +fun head(l) = if l is h :: t then h +fun tail(l) = if l is h :: t then t + +fun while_(p, f, x) = if p(x) then while_(p, f, f(x)) else x + +:todo +fun reverse(l) = + fun r(l', l) = if l is x :: xs then r(x :: l', xs) else l' + r(Nil, l) +//│ ═══[COMPILATION ERROR] Non top-level definition r not supported +//│ Stopped due to an error during the Llir generation + +fun map(f, xs) = if xs is + x :: xs then f(x) :: map(f, xs) + Nil then Nil + +fun listLen(ls) = + fun l(ls, a) = if ls is + Nil then a + h :: t then l(t, a + 1) + l(ls, 0) +//│ FAILURE: Unexpected compilation error +//│ ═══[COMPILATION ERROR] Non top-level definition l not supported +//│ Stopped due to an error during the Llir generation + +fun listEq(xs, ys) = if + xs is Nil and ys is Nil then true + xs is hx :: tx and ys is hy :: ty and (hx == hy) then listEq(tx, ty) + else false + +fun listEqBy(f, a, b) = if a is + Nil and b is Nil then true + x :: xs and b is y :: ys then f(x, y) && listEqBy(f, xs, ys) + else false + +fun listNeq(xs, ys) = if + xs is Nil and ys is Nil then false + xs is hx :: tx and ys is hy :: ty and (hx == hy) then listNeq(tx, ty) + else true + +fun enumFromTo(a, b) = if a <= b then a :: enumFromTo(a + 1, b) else Nil + +fun enumFromThenTo(a, t, b) = if a <= b then a :: enumFromThenTo(t, 2 * t - a, b) else Nil + +fun drop(n, ls) = if ls is + Nil then Nil + h :: t and + n <= 0 then ls + else drop(n - 1, t) + +fun take(n, ls) = if ls is + Nil then Nil + h :: t and + n <= 0 then Nil + else h :: take(n - 1, t) + +fun splitAt(n, ls) = [take(n, ls), drop(n, ls)] +//│ FAILURE: Unexpected compilation error +//│ ═══[COMPILATION ERROR] Name not found: take +//│ Stopped due to an error during the Llir generation + +fun zip(xs, ys) = if xs is + x :: xs and ys is y :: ys then [x, y] :: zip(xs, ys) + else Nil +//│ FAILURE: Unexpected compilation error +//│ ═══[COMPILATION ERROR] Unsupported value: Arr +//│ Stopped due to an error during the Llir generation + +fun inList(x, ls) = if ls is + h :: t and + x === h then true + else inList(x, t) + Nil then false + +fun notElem(x, ls) = not(inList(x, ls)) +//│ FAILURE: Unexpected compilation error +//│ ═══[COMPILATION ERROR] Name not found: inList +//│ Stopped due to an error during the Llir generation + +fun (+:) append(xs, ys) = if xs is + Nil then ys + x :: xs then x :: append(xs, ys) + +fun concat(ls) = if ls is + Nil then Nil + x :: xs then append(x, concat(xs)) +//│ FAILURE: Unexpected compilation error +//│ ═══[COMPILATION ERROR] Name not found: append +//│ Stopped due to an error during the Llir generation + +fun filter(f, ls) = if ls is + Nil then Nil + h :: t and + f(h) then h :: filter(f, t) + else filter(f, t) + +fun all(p, ls) = if ls is + Nil then true + h :: t and + p(h) then all(p, t) + else false + +fun orList(ls) = if ls is + Nil then false + h :: t and + h then true + else orList(t) + +fun dropWhile(f, ls) = if ls is + Nil then Nil + h :: t and + f(h) then dropWhile(f, t) + else h :: t + +fun foldl(f, a, xs) = if xs is + Nil then a + h :: t then foldl(f, f(a, h), t) + +fun scanl(f, q, ls) = if ls is + Nil then q :: Nil + x :: xs then q :: scanl(f, f(q, x), xs) + +fun scanr(f, q, ls) = if ls is + Nil then q :: Nil + x :: xs and scanr(f, q, xs) is q :: t then f(x, q) :: q :: t + +fun foldr(f, z, xs) = if xs is + Nil then z + h :: t then f(h, foldr(f, z, t)) + +fun foldl1(f, ls) = if + ls is x :: xs then foldl(f, x, xs) +//│ FAILURE: Unexpected compilation error +//│ ═══[COMPILATION ERROR] Name not found: foldl +//│ Stopped due to an error during the Llir generation + +fun foldr1(f, ls) = if ls is + x :: Nil then x + x :: xs then f(x, foldr1(f, xs)) + +fun maximum(xs) = foldl1((x, y) => if x > y then x else y, xs) +//│ FAILURE: Unexpected compilation error +//│ ═══[COMPILATION ERROR] Name not found: foldl1 +//│ Stopped due to an error during the Llir generation + +fun nubBy(eq, ls) = if ls is + Nil then Nil + h :: t then h :: nubBy(eq, filter(y => not(eq(h, y)), t)) +//│ FAILURE: Unexpected compilation error +//│ ═══[COMPILATION ERROR] Member symbol without definition +//│ Stopped due to an error during the Llir generation + +fun zipWith(f, xss, yss) = if + xss is x :: xs and yss is y :: ys then f(x, y) :: zipWith(f, xs, ys) + else Nil + +fun deleteBy(eq, x, ys) = if ys is + Nil then Nil + y :: ys and + eq(x, y) then ys + else y :: deleteBy(eq, x, ys) + +fun unionBy(eq, xs, ys) = append(xs, foldl((acc, y) => deleteBy(eq, y, acc), nubBy(eq, ys), xs)) +//│ FAILURE: Unexpected compilation error +//│ ═══[COMPILATION ERROR] Name not found: nubBy +//│ Stopped due to an error during the Llir generation + +fun union(xs, ys) = unionBy((x, y) => x == y, xs, ys) +//│ FAILURE: Unexpected compilation error +//│ ═══[COMPILATION ERROR] Name not found: unionBy +//│ Stopped due to an error during the Llir generation + +fun atIndex(i, ls) = if ls is + h :: t and + i == 0 then h + else atIndex(i - 1, t) + +fun sum(xs) = + fun go(xs, a) = if xs is + Nil then a + h :: t then go(t, a + h) + go(xs, 0) +//│ FAILURE: Unexpected compilation error +//│ ═══[COMPILATION ERROR] Non top-level definition go not supported +//│ Stopped due to an error during the Llir generation + +fun null_(ls) = if ls is + Nil then true + else false + +fun replicate(n, x) = if n == 0 then Nil else x :: replicate(n - 1, x) + +fun unzip(l) = + fun f(l, a, b) = if l is + Nil then [reverse(a), reverse(b)] + [x, y] :: t then f(t, x :: a, y :: b) + f(l, Nil, Nil) +//│ FAILURE: Unexpected compilation error +//│ ═══[COMPILATION ERROR] Non top-level definition f not supported +//│ Stopped due to an error during the Llir generation + +fun zip3(xs, ys, zs) = if + xs is x :: xs and ys is y :: ys and zs is z :: zs then [x, y, z] :: zip3(xs, ys, zs) + else Nil +//│ FAILURE: Unexpected compilation error +//│ ═══[COMPILATION ERROR] Unsupported value: Arr +//│ Stopped due to an error during the Llir generation + +fun transpose(xss) = + fun lscomp(ls) = if ls is + Nil then Nil + h :: t and h is + hd :: tl then [hd, tl] :: lscomp(t) + else lscomp(t) + fun combine(y, h, ys, t) = (y :: h) :: transpose(ys :: t) + if xss is + Nil then Nil + Nil :: xss then transpose(xss) + (x :: xs) :: xss and unzip(lscomp(xss)) is [hds, tls] then combine(x, hds, xs, tls) +//│ FAILURE: Unexpected compilation error +//│ ═══[COMPILATION ERROR] Non top-level definition lscomp not supported +//│ Stopped due to an error during the Llir generation + +fun break_(p, ls) = if ls is + Nil then [Nil, Nil] + x :: xs and + p(x) then [Nil, x :: xs] + break_(p, xs) is [ys, zs] then [x :: ys, zs] +//│ FAILURE: Unexpected compilation error +//│ ═══[COMPILATION ERROR] Unsupported value: Arr +//│ Stopped due to an error during the Llir generation + +fun flatMap(f, ls) = if ls is + Nil then Nil + h :: t then append(f(h), flatMap(f, t)) +//│ FAILURE: Unexpected compilation error +//│ ═══[COMPILATION ERROR] Name not found: append +//│ Stopped due to an error during the Llir generation From 17001b18d09afbbd8d7dd18c529b071da03647d1 Mon Sep 17 00:00:00 2001 From: waterlens Date: Tue, 11 Feb 2025 20:15:09 +0800 Subject: [PATCH 34/88] fix a name bug --- hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala index a91f519ca4..baa29f0a3a 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala @@ -201,7 +201,7 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger)(fresh: Fresh, f // Generate an auxiliary class inheriting from Callable val freeVars = freeVarsFilter(lam.freeVars -- lam.body.definedVars -- ctx.fn_ctx.keySet) val name = fresh.make(s"Lambda${nameHint.fold("")(x => "_" + x)}") - val clsParams = freeVars.toList.map(_.nme) + val clsParams = freeVars.toList.map(allocIfNew) val args = freeVars.toList.map(allocIfNew) val ctx2 = ctx.setFreeVars(freeVars) val applyParams = params.params.map(x => x -> summon[Scope].allocateName(x.sym)) From 013112d17c8f162e086e429a524fbf6005638c7f Mon Sep 17 00:00:00 2001 From: waterlens Date: Tue, 18 Feb 2025 19:25:04 +0800 Subject: [PATCH 35/88] Update --- .../scala/hkmc2/codegen/cpp/CodeGen.scala | 242 ------------ .../scala/hkmc2/codegen/llir/Analysis.scala | 65 ++-- .../scala/hkmc2/codegen/llir/Builder.scala | 309 +++++++++------ .../main/scala/hkmc2/codegen/llir/Fresh.scala | 18 - .../scala/hkmc2/codegen/llir/Interp.scala | 64 ++-- .../main/scala/hkmc2/codegen/llir/Llir.scala | 107 +++--- .../hkmc2/codegen/llir/RefResolver.scala | 56 --- .../scala/hkmc2/codegen/llir/Validator.scala | 45 --- .../src/test/mlscript/llir/BasicCpp.mls | 30 -- .../shared/src/test/mlscript/llir/Classes.mls | 20 +- .../src/test/mlscript/llir/ControlFlow.mls | 356 +++++++----------- hkmc2/shared/src/test/mlscript/llir/Ctor.mls | 26 +- .../src/test/mlscript/llir/HigherOrder.mls | 260 ++++--------- .../shared/src/test/mlscript/llir/Legacy.mls | 100 ++--- .../shared/src/test/mlscript/llir/Method.mls | 18 +- .../src/test/mlscript/llir/NofibPrelude.mls | 30 +- hkmc2/shared/src/test/mlscript/llir/Tuple.mls | 21 ++ .../src/test/scala/hkmc2/LlirDiffMaker.scala | 23 +- 18 files changed, 640 insertions(+), 1150 deletions(-) delete mode 100644 hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/CodeGen.scala delete mode 100644 hkmc2/shared/src/main/scala/hkmc2/codegen/llir/RefResolver.scala delete mode 100644 hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Validator.scala create mode 100644 hkmc2/shared/src/test/mlscript/llir/Tuple.mls diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/CodeGen.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/CodeGen.scala deleted file mode 100644 index d9916711b9..0000000000 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/CodeGen.scala +++ /dev/null @@ -1,242 +0,0 @@ -package hkmc2.codegen.cpp - -import mlscript.utils._ -import mlscript.utils.shorthands._ -import scala.collection.mutable.ListBuffer - -import hkmc2.codegen.llir.{Expr => IExpr, _} -import hkmc2.codegen.cpp._ - -object CppCodeGen: - def mapName(name: Name): Str = "_mls_" + name.str.replace('$', '_').replace('\'', '_') - def mapName(name: Str): Str = "_mls_" + name.replace('$', '_').replace('\'', '_') - val freshName = Fresh(div = '_'); - val mlsValType = Type.Prim("_mlsValue") - val mlsUnitValue = Expr.Call(Expr.Var("_mlsValue::create<_mls_Unit>"), Ls()); - val mlsRetValue = "_mls_retval" - val mlsRetValueDecl = Decl.VarDecl(mlsRetValue, mlsValType) - val mlsMainName = "_mlsMain" - val mlsPrelude = "#include \"mlsprelude.h\"" - val mlsPreludeImpl = "#include \"mlsprelude.cpp\"" - val mlsInternalClass = Set("True", "False", "Boolean", "Callable") - val mlsObject = "_mlsObject" - val mlsBuiltin = "builtin" - val mlsEntryPoint = s"int main() { return _mlsLargeStack(_mlsMainWrapper); }"; - def mlsIntLit(x: BigInt) = Expr.Call(Expr.Var("_mlsValue::fromIntLit"), Ls(Expr.IntLit(x))) - def mlsStrLit(x: Str) = Expr.Call(Expr.Var("_mlsValue::fromStrLit"), Ls(Expr.StrLit(x))) - def mlsCharLit(x: Char) = Expr.Call(Expr.Var("_mlsValue::fromIntLit"), Ls(Expr.CharLit(x))) - def mlsNewValue(cls: Str, args: Ls[Expr]) = Expr.Call(Expr.Var(s"_mlsValue::create<$cls>"), args) - def mlsIsValueOf(cls: Str, scrut: Expr) = Expr.Call(Expr.Var(s"_mlsValue::isValueOf<$cls>"), Ls(scrut)) - def mlsIsBoolLit(scrut: Expr, lit: hkmc2.syntax.Tree.BoolLit) = Expr.Call(Expr.Var("_mlsValue::isIntLit"), Ls(scrut, Expr.IntLit(if lit.value then 1 else 0))) - def mlsIsIntLit(scrut: Expr, lit: hkmc2.syntax.Tree.IntLit) = Expr.Call(Expr.Var("_mlsValue::isIntLit"), Ls(scrut, Expr.IntLit(lit.value))) - def mlsDebugPrint(x: Expr) = Expr.Call(Expr.Var("_mlsValue::print"), Ls(x)) - def mlsTupleValue(init: Expr) = Expr.Constructor("_mlsValue::tuple", init) - def mlsAs(name: Str, cls: Str) = Expr.Var(s"_mlsValue::as<$cls>($name)") - def mlsAsUnchecked(name: Str, cls: Str) = Expr.Var(s"_mlsValue::cast<$cls>($name)") - def mlsObjectNameMethod(name: Str) = s"constexpr static inline const char *typeName = \"${name}\";" - def mlsTypeTag() = s"constexpr static inline uint32_t typeTag = nextTypeTag();" - def mlsTypeTag(n: Int) = s"constexpr static inline uint32_t typeTag = $n;" - def mlsCommonCreateMethod(cls: Str, fields: Ls[Str], id: Int) = - val parameters = fields.map{x => s"_mlsValue $x"}.mkString(", ") - val fieldsAssignment = fields.map{x => s"_mlsVal->$x = $x; "}.mkString - s"static _mlsValue create($parameters) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) $cls; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; $fieldsAssignment return _mlsValue(_mlsVal); }" - def mlsCommonPrintMethod(fields: Ls[Str]) = - if fields.isEmpty then s"virtual void print() const override { std::printf(\"%s\", typeName); }" - else - val fieldsPrint = fields.map{x => s"this->$x.print(); "}.mkString("std::printf(\", \"); ") - s"virtual void print() const override { std::printf(\"%s\", typeName); std::printf(\"(\"); $fieldsPrint std::printf(\")\"); }" - def mlsCommonDestructorMethod(cls: Str, fields: Ls[Str]) = - val fieldsDeletion = fields.map{x => s"_mlsValue::destroy(this->$x); "}.mkString - s"virtual void destroy() override { $fieldsDeletion operator delete (this, std::align_val_t(_mlsAlignment)); }" - def mlsThrowNonExhaustiveMatch = Stmt.Raw("_mlsNonExhaustiveMatch();"); - def mlsCall(fn: Str, args: Ls[Expr]) = Expr.Call(Expr.Var("_mlsCall"), Expr.Var(fn) :: args) - def mlsMethodCall(cls: ClassRef, method: Str, args: Ls[Expr]) = - Expr.Call(Expr.Member(Expr.Call(Expr.Var(s"_mlsMethodCall<${cls.name |> mapName}>"), Ls(args.head)), method), args.tail) - def mlsFnWrapperName(fn: Str) = s"_mlsFn_$fn" - def mlsFnCreateMethod(fn: Str) = s"static _mlsValue create() { static _mlsFn_$fn mlsFn alignas(_mlsAlignment); mlsFn.refCount = stickyRefCount; mlsFn.tag = typeTag; return _mlsValue(&mlsFn); }" - def mlsNeverValue(n: Int) = if (n <= 1) then Expr.Call(Expr.Var(s"_mlsValue::never"), Ls()) else Expr.Call(Expr.Var(s"_mlsValue::never<$n>"), Ls()) - - case class Ctx( - defnCtx: Set[Str], - ) - - def codegenClassInfo(using ctx: Ctx)(cls: ClassInfo): (Opt[Def], Decl) = - val fields = cls.fields.map{x => (x |> mapName, mlsValType)} - val parents = if cls.parents.nonEmpty then cls.parents.toList.map(mapName) else mlsObject :: Nil - val decl = Decl.StructDecl(cls.name |> mapName) - if mlsInternalClass.contains(cls.name) then return (None, decl) - val theDef = Def.StructDef( - cls.name |> mapName, fields, - if parents.nonEmpty then Some(parents) else None, - Ls(Def.RawDef(mlsObjectNameMethod(cls.name)), - Def.RawDef(mlsTypeTag()), - Def.RawDef(mlsCommonPrintMethod(cls.fields.map(mapName))), - Def.RawDef(mlsCommonDestructorMethod(cls.name |> mapName, cls.fields.map(mapName))), - Def.RawDef(mlsCommonCreateMethod(cls.name |> mapName, cls.fields.map(mapName), cls.id))) - ++ cls.methods.map{case (name, defn) => { - val (theDef, decl) = codegenDefn(using Ctx(ctx.defnCtx + cls.name))(defn) - theDef match - case x @ Def.FuncDef(_, name, _, _, _, _) => x.copy(virt = true) - case _ => theDef - }} - ) - (S(theDef), decl) - - def toExpr(texpr: TrivialExpr, reifyUnit: Bool = false)(using ctx: Ctx): Opt[Expr] = texpr match - case IExpr.Ref(name) => S(Expr.Var(name |> mapName)) - case IExpr.Literal(hkmc2.syntax.Tree.BoolLit(x)) => S(mlsIntLit(if x then 1 else 0)) - case IExpr.Literal(hkmc2.syntax.Tree.IntLit(x)) => S(mlsIntLit(x)) - case IExpr.Literal(hkmc2.syntax.Tree.DecLit(x)) => S(mlsIntLit(x.toBigInt)) - case IExpr.Literal(hkmc2.syntax.Tree.StrLit(x)) => S(mlsStrLit(x)) - case IExpr.Literal(hkmc2.syntax.Tree.UnitLit(_)) => if reifyUnit then S(mlsUnitValue) else None - - def toExpr(texpr: TrivialExpr)(using ctx: Ctx): Expr = texpr match - case IExpr.Ref(name) => Expr.Var(name |> mapName) - case IExpr.Literal(hkmc2.syntax.Tree.BoolLit(x)) => mlsIntLit(if x then 1 else 0) - case IExpr.Literal(hkmc2.syntax.Tree.IntLit(x)) => mlsIntLit(x) - case IExpr.Literal(hkmc2.syntax.Tree.DecLit(x)) => mlsIntLit(x.toBigInt) - case IExpr.Literal(hkmc2.syntax.Tree.StrLit(x)) => mlsStrLit(x) - case IExpr.Literal(hkmc2.syntax.Tree.UnitLit(_)) => mlsUnitValue - - - def wrapMultiValues(exprs: Ls[TrivialExpr])(using ctx: Ctx): Expr = exprs match - case x :: Nil => toExpr(x, reifyUnit = true).get - case _ => - val init = Expr.Initializer(exprs.map{x => toExpr(x)}) - mlsTupleValue(init) - - def codegenCaseWithIfs(scrut: TrivialExpr, cases: Ls[(Pat, Node)], default: Opt[Node], storeInto: Str)(using decls: Ls[Decl], stmts: Ls[Stmt])(using ctx: Ctx): (Ls[Decl], Ls[Stmt]) = - val scrut2 = toExpr(scrut) - val init: Stmt = - default.fold(mlsThrowNonExhaustiveMatch)(x => { - val (decls2, stmts2) = codegen(x, storeInto)(using Ls.empty, Ls.empty[Stmt]) - Stmt.Block(decls2, stmts2) - }) - val stmt = cases.foldRight(S(init)) { - case ((Pat.Class(cls), arm), nextarm) => - val (decls2, stmts2) = codegen(arm, storeInto)(using Ls.empty, Ls.empty[Stmt]) - val stmt = Stmt.If(mlsIsValueOf(cls.name |> mapName, scrut2), Stmt.Block(decls2, stmts2), nextarm) - S(stmt) - case ((Pat.Lit(i @ hkmc2.syntax.Tree.IntLit(_)), arm), nextarm) => - val (decls2, stmts2) = codegen(arm, storeInto)(using Ls.empty, Ls.empty[Stmt]) - val stmt = Stmt.If(mlsIsIntLit(scrut2, i), Stmt.Block(decls2, stmts2), nextarm) - S(stmt) - case ((Pat.Lit(i @ hkmc2.syntax.Tree.BoolLit(_)), arm), nextarm) => - val (decls2, stmts2) = codegen(arm, storeInto)(using Ls.empty, Ls.empty[Stmt]) - val stmt = Stmt.If(mlsIsBoolLit(scrut2, i), Stmt.Block(decls2, stmts2), nextarm) - S(stmt) - case _ => ??? - } - (decls, stmt.fold(stmts)(x => stmts :+ x)) - - def codegenJumpWithCall(func: FuncRef, args: Ls[TrivialExpr], storeInto: Opt[Str])(using decls: Ls[Decl], stmts: Ls[Stmt])(using ctx: Ctx): (Ls[Decl], Ls[Stmt]) = - val call = Expr.Call(Expr.Var(func.name |> mapName), args.map(toExpr)) - val stmts2 = stmts ++ Ls(storeInto.fold(Stmt.Return(call))(x => Stmt.Assign(x, call))) - (decls, stmts2) - - def codegenOps(op: Str, args: Ls[TrivialExpr])(using ctx: Ctx) = op match - case "+" => Expr.Binary("+", toExpr(args(0)), toExpr(args(1))) - case "-" => Expr.Binary("-", toExpr(args(0)), toExpr(args(1))) - case "*" => Expr.Binary("*", toExpr(args(0)), toExpr(args(1))) - case "/" => Expr.Binary("/", toExpr(args(0)), toExpr(args(1))) - case "%" => Expr.Binary("%", toExpr(args(0)), toExpr(args(1))) - case "==" => Expr.Binary("==", toExpr(args(0)), toExpr(args(1))) - case "!=" => Expr.Binary("!=", toExpr(args(0)), toExpr(args(1))) - case "<" => Expr.Binary("<", toExpr(args(0)), toExpr(args(1))) - case "<=" => Expr.Binary("<=", toExpr(args(0)), toExpr(args(1))) - case ">" => Expr.Binary(">", toExpr(args(0)), toExpr(args(1))) - case ">=" => Expr.Binary(">=", toExpr(args(0)), toExpr(args(1))) - case "&&" => Expr.Binary("&&", toExpr(args(0)), toExpr(args(1))) - case "||" => Expr.Binary("||", toExpr(args(0)), toExpr(args(1))) - case "!" => Expr.Unary("!", toExpr(args(0))) - case _ => TODO("codegenOps") - - - def codegen(expr: IExpr)(using ctx: Ctx): Expr = expr match - case x @ (IExpr.Ref(_) | IExpr.Literal(_)) => toExpr(x, reifyUnit = true).get - case IExpr.CtorApp(cls, args) => mlsNewValue(cls.name |> mapName, args.map(toExpr)) - case IExpr.Select(name, cls, field) => Expr.Member(mlsAsUnchecked(name |> mapName, cls.name |> mapName), field |> mapName) - case IExpr.BasicOp(name, args) => codegenOps(name, args) - case IExpr.AssignField(assignee, cls, field, value) => TODO("codegen assign field") - - def codegenBuiltin(names: Ls[Name], builtin: Str, args: Ls[TrivialExpr])(using ctx: Ctx): Ls[Stmt] = builtin match - case "error" => Ls(Stmt.Raw("throw std::runtime_error(\"Error\");"), Stmt.AutoBind(names.map(mapName), mlsNeverValue(names.size))) - case _ => Ls(Stmt.AutoBind(names.map(mapName), Expr.Call(Expr.Var("_mls_builtin_" + builtin), args.map(toExpr)))) - - def codegen(body: Node, storeInto: Str)(using decls: Ls[Decl], stmts: Ls[Stmt])(using ctx: Ctx): (Ls[Decl], Ls[Stmt]) = body match - case Node.Result(res) => - val expr = wrapMultiValues(res) - val stmts2 = stmts ++ Ls(Stmt.Assign(storeInto, expr)) - (decls, stmts2) - case Node.Jump(defn, args) => - codegenJumpWithCall(defn, args, S(storeInto)) - case Node.Panic(msg) => (decls, stmts :+ Stmt.Raw(s"throw std::runtime_error(\"$msg\");")) - case Node.LetExpr(name, expr, body) => - val stmts2 = stmts ++ Ls(Stmt.AutoBind(Ls(name |> mapName), codegen(expr))) - codegen(body, storeInto)(using decls, stmts2) - case Node.LetMethodCall(names, cls, method, IExpr.Ref(Name("builtin")) :: args, body) => - val stmts2 = stmts ++ codegenBuiltin(names, args.head.toString.replace("\"", ""), args.tail) - codegen(body, storeInto)(using decls, stmts2) - case Node.LetMethodCall(names, cls, method, args, body) => - val call = mlsMethodCall(cls, method.str |> mapName, args.map(toExpr)) - val stmts2 = stmts ++ Ls(Stmt.AutoBind(names.map(mapName), call)) - codegen(body, storeInto)(using decls, stmts2) - case Node.LetCall(names, defn, args, body) => - val call = Expr.Call(Expr.Var(defn.name |> mapName), args.map(toExpr)) - val stmts2 = stmts ++ Ls(Stmt.AutoBind(names.map(mapName), call)) - codegen(body, storeInto)(using decls, stmts2) - case Node.Case(scrut, cases, default) => - codegenCaseWithIfs(scrut, cases, default, storeInto) - - def codegenDefn(using ctx: Ctx)(defn: Func): (Def, Decl) = defn match - case Func(id, name, params, resultNum, body) => - val decls = Ls(mlsRetValueDecl) - val stmts = Ls.empty[Stmt] - val (decls2, stmts2) = codegen(body, mlsRetValue)(using decls, stmts) - val stmtsWithReturn = stmts2 :+ Stmt.Return(Expr.Var(mlsRetValue)) - val theDef = Def.FuncDef(mlsValType, name |> mapName, params.map(x => (x |> mapName, mlsValType)), Stmt.Block(decls2, stmtsWithReturn)) - val decl = Decl.FuncDecl(mlsValType, name |> mapName, params.map(x => mlsValType)) - (theDef, decl) - - def codegenTopNode(node: Node)(using ctx: Ctx): (Def, Decl) = - val decls = Ls(mlsRetValueDecl) - val stmts = Ls.empty[Stmt] - val (decls2, stmts2) = codegen(node, mlsRetValue)(using decls, stmts) - val stmtsWithReturn = stmts2 :+ Stmt.Return(Expr.Var(mlsRetValue)) - val theDef = Def.FuncDef(mlsValType, mlsMainName, Ls(), Stmt.Block(decls2, stmtsWithReturn)) - val decl = Decl.FuncDecl(mlsValType, mlsMainName, Ls()) - (theDef, decl) - - // Topological sort of classes based on inheritance relationships - def sortClasses(prog: Program): Ls[ClassInfo] = - val builtinClasses = Set("Callable") - var depgraph = prog.classes.map(x => (x.name, x.parents)).toMap - ++ builtinClasses.map(x => (x, Set.empty[Str])) - var degree = depgraph.view.mapValues(_.size).toMap - def removeNode(node: Str) = - degree -= node - depgraph -= node - depgraph = depgraph.view.mapValues(_.filter(_ != node)).toMap - degree = depgraph.view.mapValues(_.size).toMap - val sorted = ListBuffer.empty[ClassInfo] - var work = degree.filter(_._2 == 0).keys.toSet - while work.nonEmpty do - val node = work.head - work -= node - prog.classes.find(_.name == node).fold(())(sorted.addOne) - removeNode(node) - val next = degree.filter(_._2 == 0).keys - work ++= next - if depgraph.nonEmpty then - val cycle = depgraph.keys.mkString(", ") - throw new Exception(s"Cycle detected in class hierarchy: $cycle") - sorted.toList - - def codegen(prog: Program): CompilationUnit = - val sortedClasses = sortClasses(prog) - val defnCtx = prog.defs.map(_.name) - val (defs, decls) = sortedClasses.map(codegenClassInfo(using Ctx(defnCtx))).unzip - val (defs2, decls2) = prog.defs.map(codegenDefn(using Ctx(defnCtx))).unzip - val (defMain, declMain) = codegenTopNode(prog.main)(using Ctx(defnCtx)) - CompilationUnit(Ls(mlsPrelude), decls ++ decls2 :+ declMain, defs.flatten ++ defs2 :+ defMain :+ Def.RawDef(mlsEntryPoint)) - diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Analysis.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Analysis.scala index 042295874a..51e4414fd9 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Analysis.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Analysis.scala @@ -7,10 +7,10 @@ import mlscript.utils._ import mlscript.utils.shorthands._ import hkmc2.semantics.BuiltinSymbol import hkmc2.syntax.Tree.UnitLit +import hkmc2.codegen.Local import hkmc2.{Raise, raise, Diagnostic, ErrorReport, Message} import hkmc2.Message.MessageContext import hkmc2.semantics.InnerSymbol -import hkmc2.codegen.llir.FuncRef.fromName import scala.collection.mutable.ListBuffer import scala.annotation.tailrec @@ -24,13 +24,13 @@ class UsefulnessAnalysis(verbose: Bool = false): def log(x: Any) = if verbose then println(x) - val uses = MutHMap[(Name, Int), Int]() - val defs = MutHMap[Name, Int]() + val uses = MutHMap[(Local, Int), Int]() + val defs = MutHMap[Local, Int]() - private def addDef(x: Name) = + private def addDef(x: Local) = defs.update(x, defs.getOrElse(x, 0) + 1) - private def addUse(x: Name) = + private def addUse(x: Local) = val def_count = defs.get(x) match case None => throw Exception(s"Use of undefined variable $x") case Some(value) => value @@ -68,58 +68,57 @@ class UsefulnessAnalysis(verbose: Bool = false): f(x.body) uses.toMap -class FreeVarAnalysis(extended_scope: Bool = true, verbose: Bool = false): +class FreeVarAnalysis(ctx: Map[Local, Func], extended_scope: Bool = true, verbose: Bool = false): import Expr._ import Node._ - private val visited = MutHSet[Str]() - private def f(using defined: Set[Str])(defn: Func, fv: Set[Str]): Set[Str] = - val defined2 = defn.params.foldLeft(defined)((acc, param) => acc + param.str) + private val visited = MutHSet[Local]() + private def f(using defined: Set[Local])(defn: Func, fv: Set[Local]): Set[Local] = + val defined2 = defn.params.foldLeft(defined)((acc, param) => acc + param) f(using defined2)(defn.body, fv) - private def f(using defined: Set[Str])(expr: Expr, fv: Set[Str]): Set[Str] = expr match - case Ref(name) => if defined.contains(name.str) then fv else fv + name.str + private def f(using defined: Set[Local])(expr: Expr, fv: Set[Local]): Set[Local] = expr match + case Ref(name) => if defined.contains(name) then fv else fv + name case Literal(lit) => fv case CtorApp(name, args) => args.foldLeft(fv)((acc, arg) => f(using defined)(arg.toExpr, acc)) - case Select(name, cls, field) => if defined.contains(name.str) then fv else fv + name.str + case Select(name, cls, field) => if defined.contains(name) then fv else fv + name case BasicOp(name, args) => args.foldLeft(fv)((acc, arg) => f(using defined)(arg.toExpr, acc)) case AssignField(assignee, _, _, value) => f(using defined)( value.toExpr, - if defined.contains(assignee.str) then fv + assignee.str else fv + if defined.contains(assignee) then fv + assignee else fv ) - private def f(using defined: Set[Str])(node: Node, fv: Set[Str]): Set[Str] = node match + private def f(using defined: Set[Local])(node: Node, fv: Set[Local]): Set[Local] = node match case Result(res) => res.foldLeft(fv)((acc, arg) => f(using defined)(arg.toExpr, acc)) - case Jump(defnref, args) => + case Jump(defn, args) => var fv2 = args.foldLeft(fv)((acc, arg) => f(using defined)(arg.toExpr, acc)) - if extended_scope && !visited.contains(defnref.name) then - val defn = defnref.expectFn - visited.add(defn.name) - val defined2 = defn.params.foldLeft(defined)((acc, param) => acc + param.str) - fv2 = f(using defined2)(defn, fv2) + if extended_scope && !visited.contains(defn) then + visited.add(defn) + val func = ctx.getOrElse(defn, throw Exception(s"Function $defn not found")) + val defined2 = func.params.foldLeft(defined)((acc, param) => acc + param) + fv2 = f(using defined2)(func, fv2) fv2 case Case(scrut, cases, default) => val fv2 = scrut match - case Ref(name) => if defined.contains(name.str) then fv else fv + name.str + case Ref(name) => if defined.contains(name) then fv else fv + name case _ => fv - val fv3 = cases.foldLeft(fv2) { + val fv3 = cases.foldLeft(fv2): case (acc, (cls, body)) => f(using defined)(body, acc) - } fv3 case LetMethodCall(resultNames, cls, method, args, body) => var fv2 = args.foldLeft(fv)((acc, arg) => f(using defined)(arg.toExpr, acc)) - val defined2 = resultNames.foldLeft(defined)((acc, name) => acc + name.str) + val defined2 = resultNames.foldLeft(defined)((acc, name) => acc + name) f(using defined2)(body, fv2) case LetExpr(name, expr, body) => val fv2 = f(using defined)(expr, fv) - val defined2 = defined + name.str + val defined2 = defined + name f(using defined2)(body, fv2) - case LetCall(resultNames, defnref, args, body) => + case LetCall(resultNames, defn, args, body) => var fv2 = args.foldLeft(fv)((acc, arg) => f(using defined)(arg.toExpr, acc)) - val defined2 = resultNames.foldLeft(defined)((acc, name) => acc + name.str) - if extended_scope && !visited.contains(defnref.name) then - val defn = defnref.expectFn - visited.add(defn.name) - val defined2 = defn.params.foldLeft(defined)((acc, param) => acc + param.str) - fv2 = f(using defined2)(defn, fv2) + val defined2 = resultNames.foldLeft(defined)((acc, name) => acc + name) + if extended_scope && !visited.contains(defn) then + visited.add(defn) + val func = ctx.getOrElse(defn, throw Exception(s"Function $defn not found")) + val defined2 = func.params.foldLeft(defined)((acc, param) => acc + param) + fv2 = f(using defined2)(func, fv2) f(using defined2)(body, fv2) def run(node: Node) = f(using Set.empty)(node, Set.empty) - def run_with(node: Node, defined: Set[Str]) = f(using defined)(node, Set.empty) + def run_with(node: Node, defined: Set[Local]) = f(using defined)(node, Set.empty) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala index baa29f0a3a..b8d765ba91 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala @@ -24,39 +24,32 @@ def errStop(msg: Message)(using Raise) = err(msg) throw LowLevelIRError("stopped") -final case class FuncInfo ( - name: Name, - paramsSize: Int, -) +final case class FuncInfo(paramsSize: Int) final case class Ctx( def_acc: ListBuffer[Func], class_acc: ListBuffer[ClassInfo], - symbol_ctx: Map[Str, Name] = Map.empty, + symbol_ctx: Map[Local, Local] = Map.empty, fn_ctx: Map[Local, FuncInfo] = Map.empty, // is a known function - class_ctx: Map[Local, Name] = Map.empty, - flow_ctx: Map[Path, Name] = Map.empty, - block_ctx: Map[Local, Name] = Map.empty, + class_ctx: Map[Local, ClassInfo] = Map.empty, + flow_ctx: Map[Path, Local] = Map.empty, is_top_level: Bool = true, method_class: Opt[Symbol] = None, free_vars: Set[Local] = Set.empty, ): - def addFuncName(n: Local, m: Name, paramsSize: Int) = copy(fn_ctx = fn_ctx + (n -> FuncInfo(m, paramsSize))) + def addFuncName(n: Local, paramsSize: Int) = copy(fn_ctx = fn_ctx + (n -> FuncInfo(paramsSize))) def findFuncName(n: Local)(using Raise) = fn_ctx.get(n) match - case None => - errStop(msg"Function name not found: ${n.toString()}") + case None => errStop(msg"Function name not found: ${n.toString()}") case Some(value) => value - def addClassName(n: Local, m: Name) = copy(class_ctx = class_ctx + (n -> m)) - def findClassName(n: Local)(using Raise) = class_ctx.get(n) match - case None => - errStop(msg"Class not found: ${n.toString}") + def addClassInfo(n: Local, m: ClassInfo) = copy(class_ctx = class_ctx + (n -> m)) + def addName(n: Local, m: Local) = copy(symbol_ctx = symbol_ctx + (n -> m)) + def findName(n: Local)(using Raise) = symbol_ctx.get(n) match + case None => errStop(msg"Name not found: ${n.toString}") case Some(value) => value - def addKnownClass(n: Path, m: Name) = copy(flow_ctx = flow_ctx + (n -> m)) - def addName(n: Str, m: Name) = copy(symbol_ctx = symbol_ctx + (n -> m)) - def findName(n: Str)(using Raise): Name = symbol_ctx.get(n) match - case None => - errStop(msg"Name not found: $n") + def findClassInfo(n: Local)(using Raise) = class_ctx.get(n) match + case None => errStop(msg"Class not found: ${n.toString}") case Some(value) => value + def addKnownClass(n: Path, m: Local) = copy(flow_ctx = flow_ctx + (n -> m)) def setClass(c: Symbol) = copy(method_class = Some(c)) def setFreeVars(n: Set[Local]) = copy(free_vars = free_vars) def nonTopLevel = copy(is_top_level = false) @@ -65,15 +58,13 @@ object Ctx: def empty = Ctx(ListBuffer.empty, ListBuffer.empty) -final class LlirBuilder(using Elaborator.State)(tl: TraceLogger)(fresh: Fresh, fnUid: FreshInt, clsUid: FreshInt): +final class LlirBuilder(using Elaborator.State)(tl: TraceLogger, uid: FreshInt): import tl.{trace, log, logs} def er = Expr.Ref def nr = Node.Result - def nme(x: Str) = Name(x) - def sr(x: Str) = er(Name(x)) - def sr(x: Name) = er(x) - def nsr(xs: Ls[Name]) = xs.map(er(_)) + def sr(x: Local) = er(x) + def nsr(xs: Ls[Local]) = xs.map(er(_)) private def allocIfNew(l: Local)(using Raise, Scope): String = trace[Str](s"allocIfNew begin: $l", x => s"allocIfNew end: $x"): @@ -101,17 +92,66 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger)(fresh: Fresh, f fvs.filter: case _: (BuiltinSymbol | TopLevelSymbol | ClassSymbol | MemberSymbol[?]) => false case _ => true - - private def bBind(name: Opt[Str], e: Result, body: Block)(k: TrivialExpr => Ctx ?=> Node)(ct: Block)(using ctx: Ctx)(using Raise, Scope): Node = + + private def newTemp = TempSymbol(N, "x") + private def newNamedTemp(name: Str) = TempSymbol(N, name) + private def newNamed(name: Str) = VarSymbol(Tree.Ident(name)) + private def newLambdaSym(name: Str) = + ClassSymbol(Tree.TypeDef(hkmc2.syntax.Cls, Tree.Empty(), N, N), Tree.Ident(name)) + private def newClassSym(len: Int) = + ClassSymbol(Tree.TypeDef(hkmc2.syntax.Cls, Tree.Empty(), N, N), Tree.Ident(s"Tuple$len")) + private def newMemSym(name: Str) = TermSymbol(hkmc2.syntax.ImmutVal, None, Tree.Ident(name)) + private val builtinField: Map[Int, Local] = + Map( + 0 -> newMemSym("field0"), + 1 -> newMemSym("field1"), + 2 -> newMemSym("field2"), + 3 -> newMemSym("field3"), + 4 -> newMemSym("field4"), + 5 -> newMemSym("field5"), + 6 -> newMemSym("field6"), + 7 -> newMemSym("field7"), + 8 -> newMemSym("field8"), + 9 -> newMemSym("field9"), + ) + private val builtinCallable: Local = newLambdaSym("Callable") + private val builtinApply: Map[Int, Local] = + Map( + 0 -> newLambdaSym("apply0"), + 1 -> newLambdaSym("apply1"), + 2 -> newLambdaSym("apply2"), + 3 -> newLambdaSym("apply3"), + 4 -> newLambdaSym("apply4"), + 5 -> newLambdaSym("apply5"), + 6 -> newLambdaSym("apply6"), + 7 -> newLambdaSym("apply7"), + 8 -> newLambdaSym("apply8"), + 9 -> newLambdaSym("apply9"), + ) + private val builtinTuple: Map[Int, Local] = + Map( + 0 -> newClassSym(0), + 1 -> newClassSym(1), + 2 -> newClassSym(2), + 3 -> newClassSym(3), + 4 -> newClassSym(4), + 5 -> newClassSym(5), + 6 -> newClassSym(6), + 7 -> newClassSym(7), + 8 -> newClassSym(8), + 9 -> newClassSym(9), + ) + + private def bBind(name: Opt[Local], e: Result, body: Block)(k: TrivialExpr => Ctx ?=> Node)(ct: Block)(using ctx: Ctx)(using Raise, Scope): Node = trace[Node](s"bBind begin: $name", x => s"bBind end: ${x.show}"): bResult(e): case r: Expr.Ref => - given Ctx = ctx.addName(name.getOrElse(fresh.make.str), r.name) + given Ctx = ctx.addName(name.getOrElse(newTemp), r.sym) log(s"bBind ref: $name -> $r") bBlock(body)(k)(ct) case l: Expr.Literal => - val v = fresh.make - given Ctx = ctx.addName(name.getOrElse(fresh.make.str), v) + val v = newTemp + given Ctx = ctx.addName(name.getOrElse(newTemp), v) log(s"bBind lit: $name -> $v") Node.LetExpr(v, l, bBlock(body)(k)(ct)) @@ -139,16 +179,12 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger)(fresh: Fresh, f else if params.length != 1 then errStop(msg"Curried function or zero arguments function not supported: ${params.length.toString}") else - val paramsList = params.head.params.map(x => x -> summon[Scope].allocateName(x.sym)) - val ctx2 = paramsList.foldLeft(ctx)((acc, x) => acc.addName(getVar_!(x._1.sym), x._2 |> nme)) - val ctx3 = ctx2.nonTopLevel - val pl = paramsList.map(_._2).map(nme) + val paramsList = params.head.params + val ctx2 = paramsList.foldLeft(ctx)((acc, x) => acc.addName(x.sym, x.sym)).nonTopLevel + val pl = paramsList.map(_.sym) Func( - fnUid.make, - sym.nme, - params = pl, - resultNum = 1, - body = bBlockWithEndCont(body)(x => Node.Result(Ls(x)))(using ctx3) + uid.make, sym, params = pl, resultNum = 1, + body = bBlockWithEndCont(body)(x => Node.Result(Ls(x)))(using ctx2) ) private def bMethodDef(e: FunDefn)(using ctx: Ctx)(using Raise, Scope): Func = @@ -159,38 +195,34 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger)(fresh: Fresh, f else if params.length != 1 then errStop(msg"Curried function or zero arguments function not supported: ${params.length.toString}") else - val paramsList = params.head.params.map(x => x -> summon[Scope].allocateName(x.sym)) - val ctx2 = paramsList.foldLeft(ctx)((acc, x) => acc.addName(getVar_!(x._1.sym), x._2 |> nme)) - val ctx3 = ctx2.nonTopLevel - val pl = paramsList.map(_._2).map(nme) + val paramsList = params.head.params + val ctx2 = paramsList.foldLeft(ctx)((acc, x) => acc.addName(x.sym, x.sym)).nonTopLevel + val pl = paramsList.map(_.sym) Func( - fnUid.make, - sym.nme, - params = pl, - resultNum = 1, - body = bBlockWithEndCont(body)(x => Node.Result(Ls(x)))(using ctx3) + uid.make, sym, params = pl, resultNum = 1, + body = bBlockWithEndCont(body)(x => Node.Result(Ls(x)))(using ctx2) ) private def bClsLikeDef(e: ClsLikeDefn)(using ctx: Ctx)(using Raise, Scope): ClassInfo = trace[ClassInfo](s"bClsLikeDef begin", x => s"bClsLikeDef end: ${x.show}"): val ClsLikeDefn( - _own, _isym, sym, kind, paramsOpt, parentSym, methods, privateFields, publicFields, preCtor, ctor) = e + _own, isym, _sym, kind, paramsOpt, parentSym, methods, privateFields, publicFields, preCtor, ctor) = e if !ctx.is_top_level then - errStop(msg"Non top-level definition ${sym.nme} not supported") + errStop(msg"Non top-level definition ${isym.toString()} not supported") else - val clsDefn = sym.defn.getOrElse(die) + val clsDefn = isym.defn.getOrElse(die) val clsParams = paramsOpt.fold(Nil)(_.paramSyms) val clsFields = publicFields.map(_.sym) - given Ctx = ctx.setClass(sym) + given Ctx = ctx.setClass(isym) val funcs = methods.map(bMethodDef) - def parentFromPath(p: Path): Set[Str] = p match - case Value.Ref(l) => Set(l.nme) - case Select(Value.Ref(l), Tree.Ident("class")) => Set(l.nme) + def parentFromPath(p: Path): Set[Local] = p match + case Value.Ref(l) => Set(l) + case Select(Value.Ref(l), Tree.Ident("class")) => Set(l) case _ => errStop(msg"Unsupported parent path ${p.toString()}") ClassInfo( - clsUid.make, - sym.nme, - clsParams.map(_.nme) ++ clsFields.map(_.nme), + uid.make, + isym, + clsParams ++ clsFields, parentSym.fold(Set.empty)(parentFromPath), funcs.map(f => f.name -> f).toMap, ) @@ -200,57 +232,61 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger)(fresh: Fresh, f val Value.Lam(params, body) = lam // Generate an auxiliary class inheriting from Callable val freeVars = freeVarsFilter(lam.freeVars -- lam.body.definedVars -- ctx.fn_ctx.keySet) - val name = fresh.make(s"Lambda${nameHint.fold("")(x => "_" + x)}") - val clsParams = freeVars.toList.map(allocIfNew) - val args = freeVars.toList.map(allocIfNew) + val name = newLambdaSym(s"Lambda${nameHint.fold("")(x => "_" + x)}") + val clsParams = freeVars.toList + val args = freeVars.toList val ctx2 = ctx.setFreeVars(freeVars) - val applyParams = params.params.map(x => x -> summon[Scope].allocateName(x.sym)) - val ctx3 = applyParams.foldLeft(ctx2)((acc, x) => acc.addName(getVar_!(x._1.sym), x._2 |> nme)).nonTopLevel - val pl = applyParams.map(_._2).map(nme) + val applyParams = params.params.map(x => x -> x.sym) + val ctx3 = applyParams.foldLeft(ctx2)((acc, x) => acc.addName(x._1.sym, x._1.sym)).nonTopLevel + val pl = applyParams.map(_._1.sym) val method = Func( - fnUid.make, - s"apply${params.params.length}", + uid.make, + builtinApply(params.params.length), params = pl, resultNum = 1, body = bBlockWithEndCont(body)(x => Node.Result(Ls(x)))(using ctx3) ) ctx.class_acc += ClassInfo( - clsUid.make, - name.str, + uid.make, + name, clsParams, - Set("Callable"), + Set(builtinCallable), Map(method.name -> method), ) - val v = fresh.make - Node.LetExpr(v, Expr.CtorApp(ClassRef.fromName(name), args.map(sr)), k(v |> sr)(using ctx)) + val v: Local = newTemp + Node.LetExpr(v, Expr.CtorApp(name, args.map(sr)), k(v |> sr)(using ctx)) private def bValue(v: Value)(k: TrivialExpr => Ctx ?=> Node)(using ctx: Ctx)(using Raise, Scope) : Node = trace[Node](s"bValue { $v } begin", x => s"bValue end: ${x.show}"): v match case Value.Ref(l: TermSymbol) if l.owner.nonEmpty => - k(Name(l.name) |> sr) + k(l |> sr) case Value.Ref(sym) if sym.nme.isCapitalized => - val v = fresh.make - Node.LetExpr(v, Expr.CtorApp(ClassRef.fromName(sym.nme), Ls()), k(v |> sr)) + val v: Local = newTemp + Node.LetExpr(v, Expr.CtorApp(fromMemToClass(sym), Ls()), k(v |> sr)) case Value.Ref(l) => - val x = getVar_!(l) ctx.fn_ctx.get(l) match case Some(f) => - val tempSymbols = (0 until f.paramsSize).map(x => VarSymbol(Tree.Ident(fresh.make("arg").str))) - val paramsList = PlainParamList((0 until f.paramsSize).zip(tempSymbols).map((_n, sym) => Param(FldFlags.empty, sym, N)).toList) + val tempSymbols = (0 until f.paramsSize).map(x => newNamed("arg")) + val paramsList = PlainParamList( + (0 until f.paramsSize).zip(tempSymbols).map((_n, sym) => + Param(FldFlags.empty, sym, N)).toList) val app = Call(v, tempSymbols.map(x => Arg(false, Value.Ref(x))).toList)(true, false) - log(s"bValue Ref: ${l.toString()} -> $x") - bLam(Value.Lam(paramsList, Return(app, false)), S(x))(k) + bLam(Value.Lam(paramsList, Return(app, false)), S(l.nme))(k) case None => - log(s"bValue Ref: $x") - k(ctx.findName(x) |> sr) + k(ctx.findName(l) |> sr) case Value.This(sym) => errStop(msg"Unsupported value: This") case Value.Lit(lit) => k(Expr.Literal(lit)) case lam @ Value.Lam(params, body) => bLam(lam, N)(k) - case Value.Arr(elems) => errStop(msg"Unsupported value: Arr") + case Value.Arr(elems) => + bArgs(elems): + case args: Ls[TrivialExpr] => + val v: Local = newTemp + Node.LetExpr(v, Expr.CtorApp(builtinTuple(elems.length), args), k(v |> sr)) + - private def getClassOfMem(p: FieldSymbol)(using ctx: Ctx)(using Raise, Scope): Local = - trace[Local](s"bMemSym { $p } begin", x => s"bMemSym end: $x"): + private def getClassOfField(p: FieldSymbol)(using ctx: Ctx)(using Raise, Scope): Local = + trace[Local](s"bClassOfField { $p } begin", x => s"bClassOfField end: $x"): p match case ts: TermSymbol => ts.owner.get case ms: MemberSymbol[?] => @@ -258,14 +294,33 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger)(fresh: Fresh, f case Some(d: ClassLikeDef) => d.owner.get case Some(d: TermDefinition) => d.owner.get case Some(value) => errStop(msg"Member symbol without class definition ${value.toString}") - case None => errStop(msg"Member symbol without definition") - + case None => errStop(msg"Member symbol without definition") + + private def fromMemToClass(m: Symbol)(using ctx: Ctx)(using Raise, Scope): Local = + trace[Local](s"bFromMemToClass", x => s"bFromMemToClass end: $x"): + m match + case ms: MemberSymbol[?] => + ms.defn match + case Some(d: ClassLikeDef) => d.sym + case Some(d: TermDefinition) => d.sym + case Some(value) => errStop(msg"Member symbol without class definition ${value.toString}") + case None => errStop(msg"Member symbol without definition") + case _ => errStop(msg"Unsupported symbol kind ${m.toString}") + private def bPath(p: Path)(k: TrivialExpr => Ctx ?=> Node)(using ctx: Ctx)(using Raise, Scope) : Node = trace[Node](s"bPath { $p } begin", x => s"bPath end: ${x.show}"): p match - case Select(Value.Ref(cls: ClassSymbol), name) if ctx.method_class.contains(cls) => - k(Name(name.name) |> sr) + case s @ Select(Value.Ref(cls: ClassSymbol), name) if ctx.method_class.contains(cls) => + s.symbol match + case None => + ctx.flow_ctx.get(p) match + case Some(cls) => + k(cls |> sr) + case None => + errStop(msg"Unsupported selection by users") + case Some(s) => + k(s |> sr) case s @ DynSelect(qual, fld, arrayIdx) => errStop(msg"Unsupported dynamic selection") case s @ Select(qual, name) => @@ -276,10 +331,9 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger)(fresh: Fresh, f case Some(cls) => bPath(qual): case q: Expr.Ref => - val v = fresh.make - val clsN = ClassRef.fromName(cls) + val v: Local = newTemp val field = name.name - Node.LetExpr(v, Expr.Select(q.name, clsN, field), k(v |> sr)) + Node.LetExpr(v, Expr.Select(q.sym, cls, field), k(v |> sr)) case q: Expr.Literal => errStop(msg"Unsupported select on literal") case None => @@ -288,10 +342,10 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger)(fresh: Fresh, f case Some(value) => bPath(qual): case q: Expr.Ref => - val v = fresh.make - val cls = ClassRef.fromName(getClassOfMem(s.symbol.get).nme) + val v: Local = newTemp + val cls = getClassOfField(s.symbol.get) val field = name.name - Node.LetExpr(v, Expr.Select(q.name, cls, field), k(v |> sr)) + Node.LetExpr(v, Expr.Select(q.sym, cls, field), k(v |> sr)) case q: Expr.Literal => errStop(msg"Unsupported select on literal") case x: Value => bValue(x)(k) @@ -302,39 +356,39 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger)(fresh: Fresh, f case Call(Value.Ref(sym: BuiltinSymbol), args) => bArgs(args): case args: Ls[TrivialExpr] => - val v = fresh.make - Node.LetExpr(v, Expr.BasicOp(sym.nme, args), k(v |> sr)) - case Call(Value.Ref(sym), args) if sym.nme.head.isUpper => + val v: Local = newTemp + Node.LetExpr(v, Expr.BasicOp(sym, args), k(v |> sr)) + case Call(Value.Ref(sym), args) if sym.nme.isCapitalized => bArgs(args): case args: Ls[TrivialExpr] => - val v = fresh.make - Node.LetExpr(v, Expr.CtorApp(ClassRef.fromName(sym.nme), args), k(v |> sr)) + val v: Local = newTemp + Node.LetExpr(v, Expr.CtorApp(fromMemToClass(sym), args), k(v |> sr)) case Call(s @ Value.Ref(sym), args) => bArgs(args): case args: Ls[TrivialExpr] => - val v = fresh.make + val v: Local = newTemp ctx.fn_ctx.get(sym) match case Some(f) => - Node.LetCall(Ls(v), FuncRef.fromName(f.name), args, k(v |> sr)) + Node.LetCall(Ls(v), sym, args, k(v |> sr)) case None => bPath(s): case f: TrivialExpr => - Node.LetMethodCall(Ls(v), ClassRef(R("Callable")), Name("apply" + args.length), f :: args, k(v |> sr)) + Node.LetMethodCall(Ls(v), builtinCallable, builtinApply(args.length), f :: args, k(v |> sr)) case Call(s @ Select(r @ Value.Ref(sym), Tree.Ident(fld)), args) if s.symbol.isDefined => bPath(r): case r => bArgs(args): case args: Ls[TrivialExpr] => - val v = fresh.make + val v: Local = newTemp log(s"Method Call Select: $r.$fld with ${s.symbol}") - Node.LetMethodCall(Ls(v), ClassRef.fromName(getClassOfMem(s.symbol.get).nme), Name(fld), r :: args, k(v |> sr)) + Node.LetMethodCall(Ls(v), getClassOfField(s.symbol.get), fromMemToClass(s.symbol.get), r :: args, k(v |> sr)) case Call(_, _) => errStop(msg"Unsupported kind of Call ${r.toString()}") case Instantiate( Select(Value.Ref(sym), Tree.Ident("class")), args) => bPaths(args): case args: Ls[TrivialExpr] => - val v = fresh.make - Node.LetExpr(v, Expr.CtorApp(ClassRef.fromName(sym.nme), args), k(v |> sr)) + val v: Local = newTemp + Node.LetExpr(v, Expr.CtorApp(fromMemToClass(sym), args), k(v |> sr)) case Instantiate(cls, args) => errStop(msg"Unsupported kind of Instantiate") case x: Path => bPath(x)(k) @@ -349,28 +403,27 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger)(fresh: Fresh, f bPath(scrut): case e: TrivialExpr => val nextCont = Begin(rest, ct) - val jp = fresh.make("j") - val fvset = freeVarsFilter(nextCont.freeVars -- nextCont.definedVars).map(allocIfNew) + val jp: Local = newNamedTemp("j") + val fvset = freeVarsFilter(nextCont.freeVars -- nextCont.definedVars) val fvs1 = fvset.toList log(s"Match free vars: $fvset ${nextCont.freeVars} ${nextCont.definedVars} $fvs1") - val new_ctx = fvs1.foldLeft(ctx)((acc, x) => acc.addName(x, fresh.make)) + val new_ctx = fvs1.foldLeft(ctx)((acc, x) => acc.addName(x, x)) val fvs = fvs1.map(new_ctx.findName(_)) def cont(x: TrivialExpr)(using ctx: Ctx) = Node.Jump( - FuncRef.fromName(jp), + jp, fvs1.map(x => ctx.findName(x)).map(sr) ) val casesList: Ls[(Pat, Node)] = arms.map: case (Case.Lit(lit), body) => (Pat.Lit(lit), bBlock(body)(cont)(nextCont)(using ctx)) case (Case.Cls(cls, _), body) => - (Pat.Class(ClassRef.fromName(cls.nme)), bBlock(body)(cont)(nextCont)(using ctx)) + (Pat.Class(cls), bBlock(body)(cont)(nextCont)(using ctx)) case (Case.Tup(len, inf), body) => - val ctx2 = ctx.addKnownClass(scrut, Name("Tuple" + len.toString())) - (Pat.Class(ClassRef.fromName("Tuple" + len.toString())), bBlock(body)(cont)(nextCont)(using ctx2)) + (Pat.Class(builtinTuple(len)), bBlock(body)(cont)(nextCont)(using ctx)) val defaultCase = dflt.map(bBlock(_)(cont)(nextCont)(using ctx)) val jpdef = Func( - fnUid.make, - jp.str, + uid.make, + jp, params = fvs, resultNum = 1, bBlock(rest)(k)(ct)(using new_ctx), @@ -401,13 +454,12 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger)(fresh: Fresh, f case _ => TODO(s"Other non-tail sub components of Begin not supported $sub") case TryBlock(sub, finallyDo, rest) => TODO("TryBlock not supported") case Assign(lhs, rhs, rest) => - val name = allocIfNew(lhs) - bBind(S(name), rhs, rest)(k)(ct) + bBind(S(lhs), rhs, rest)(k)(ct) case AssignField(lhs, nme, rhs, rest) => TODO("AssignField not supported") case Define(fd @ FunDefn(_own, sym, params, body), rest) => if params.length != 1 then errStop(msg"Curried function or zero arguments function not supported: ${params.length.toString}") - val ctx2 = ctx.addFuncName(sym, Name(sym.nme), params.head.params.length) + val ctx2 = ctx.addFuncName(sym, params.head.params.length) val f = bFunDef(fd)(using ctx2) ctx.def_acc += f bBlock(rest)(k)(ct)(using ctx2) @@ -421,19 +473,32 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger)(fresh: Fresh, f b match case Define(cd @ ClsLikeDefn(_own, isym, sym, kind, _paramsOpt, parentSym, methods, privateFields, publicFields, preCtor, ctor), rest) => val c = bClsLikeDef(cd) - val new_ctx = ctx.addClassName(sym, Name(c.name)).addClassName(isym, Name(c.name)) ctx.class_acc += c - log(s"Define class: ${sym.nme} -> ${new_ctx}") + val new_ctx = ctx.addClassInfo(sym, c).addClassInfo(isym, c) + log(s"Define class: ${isym.toString()} -> ${ctx}") registerClasses(rest)(using new_ctx) case _ => b.subBlocks.foldLeft(ctx)((ctx, rest) => registerClasses(rest)(using ctx)) + def registerInternalClasses(using ctx: Ctx)(using Raise, Scope): Ctx = + builtinTuple.foldLeft(ctx): + case (ctx, (len, sym)) => + val c = ClassInfo( + uid.make, + sym, + (0 until len).map(x => builtinField(x)).toList, + Set.empty, + Map.empty, + ) + ctx.class_acc += c + ctx.addClassInfo(sym, c) + def registerFunctions(b: Block)(using ctx: Ctx)(using Raise, Scope): Ctx = b match case Define(fd @ FunDefn(_own, sym, params, body), rest) => if params.length != 1 then errStop(msg"Curried function or zero arguments function not supported: ${params.length.toString}") - val ctx2 = ctx.addFuncName(sym, Name(sym.nme), params.head.params.length) + val ctx2 = ctx.addFuncName(sym, params.head.params.length) log(s"Define function: ${sym.nme} -> ${ctx2}") registerFunctions(rest)(using ctx2) case _ => @@ -442,6 +507,8 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger)(fresh: Fresh, f def bProg(e: Program)(using Raise, Scope): LlirProgram = var ctx = Ctx.empty + ctx = registerInternalClasses(using ctx) + // * Classes may be defined after other things such as functions, // * especially now that the elaborator moves all functions to the top of the block. ctx = registerClasses(e.main)(using ctx) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Fresh.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Fresh.scala index 0c5688eab6..ea12ef9a8b 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Fresh.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Fresh.scala @@ -1,23 +1,5 @@ package hkmc2.codegen.llir -import collection.mutable.{HashMap => MutHMap} -import mlscript.utils.shorthands._ - -final class Fresh(div : Char = '$'): - private val counter = MutHMap[Str, Int]() - private def gensym(s: Str) = { - val n = s.lastIndexOf(div) - val (ts, suffix) = s.splitAt(if n == -1 then s.length() else n) - var x = if suffix.stripPrefix(div.toString).forall(_.isDigit) then ts else s - val count = counter.getOrElse(x, 0) - val tmp = s"$x$div$count" - counter.update(x, count + 1) - Name(tmp) - } - - def make(s: Str) = gensym(s) - def make = gensym("x") - final class FreshInt: private var counter = 0 def make: Int = { diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Interp.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Interp.scala index 4f5416d1f3..bfd804b93a 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Interp.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Interp.scala @@ -9,6 +9,8 @@ import scala.util.boundary, boundary.break import hkmc2.codegen.llir.* import hkmc2.syntax.Tree +import hkmc2.codegen.Local +import hkmc2.utils.TraceLogger enum Stuck: case StuckExpr(expr: Expr, msg: Str) @@ -21,8 +23,8 @@ enum Stuck: final case class InterpreterError(message: String) extends Exception(message) -class Interpreter(verbose: Bool): - private def log(x: Any) = if verbose then println(x) +class Interpreter(tl: TraceLogger): + import tl.{trace, log, logs} import Stuck._ private case class Configuration( @@ -38,7 +40,7 @@ class Interpreter(verbose: Bool): override def toString: String = import hkmc2.syntax.Tree.* this match - case Class(cls, fields) => s"${cls.name}(${fields.mkString(",")})" + case Class(cls, fields) => s"${cls.name.nme}(${fields.mkString(",")})" case Literal(IntLit(lit)) => lit.toString case Literal(BoolLit(lit)) => lit.toString case Literal(DecLit(lit)) => lit.toString @@ -46,9 +48,9 @@ class Interpreter(verbose: Bool): case Literal(UnitLit(undefinedOrNull)) => if undefinedOrNull then "undefined" else "null" private final case class Ctx( - bindingCtx: Map[Str, Value], - classCtx: Map[Str, ClassInfo], - funcCtx: Map[Str, Func], + bindingCtx: Map[Local, Value], + classCtx: Map[Local, ClassInfo], + funcCtx: Map[Local, Func], ) import Node._ @@ -86,21 +88,21 @@ class Interpreter(verbose: Bool): stuck.toLeft(values.toList) private def eval(expr: TrivialExpr)(using ctx: Ctx): Result[Value] = expr match - case e @ Ref(name) => ctx.bindingCtx.get(name.str).toRight(StuckExpr(e, s"undefined variable $name")) + case e @ Ref(name) => ctx.bindingCtx.get(name).toRight(StuckExpr(e, s"undefined variable $name")) case Literal(lit) => R(Value.Literal(lit)) private def eval(expr: Expr)(using ctx: Ctx): Result[Value] = expr match - case Ref(Name(x)) => ctx.bindingCtx.get(x).toRight(StuckExpr(expr, s"undefined variable $x")) + case Ref(x) => ctx.bindingCtx.get(x).toRight(StuckExpr(expr, s"undefined variable $x")) case Literal(x) => R(Value.Literal(x)) case CtorApp(cls, args) => for xs <- evalArgs(args) - cls <- ctx.classCtx.get(cls.name).toRight(StuckExpr(expr, s"undefined class ${cls.name}")) + cls <- ctx.classCtx.get(cls).toRight(StuckExpr(expr, s"undefined class ${cls.nme}")) yield Value.Class(cls, xs) case Select(name, cls, field) => - ctx.bindingCtx.get(name.str).toRight(StuckExpr(expr, s"undefined variable $name")).flatMap { - case Value.Class(cls2, xs) if cls.name == cls2.name => - xs.zip(cls2.fields).find{_._2 == field} match + ctx.bindingCtx.get(name).toRight(StuckExpr(expr, s"undefined variable $name")).flatMap { + case Value.Class(cls2, xs) if cls == cls2.name => + xs.zip(cls2.fields).find{_._2.nme == field} match case Some((x, _)) => R(x) case None => L(StuckExpr(expr, s"unable to find selected field $field")) case Value.Class(cls2, xs) => L(StuckExpr(expr, s"unexpected class $cls2")) @@ -109,19 +111,19 @@ class Interpreter(verbose: Bool): case BasicOp(name, args) => boundary: evalArgs(args).flatMap( xs => - name match + name.nme match case "+" | "-" | "*" | "/" | "==" | "!=" | "<=" | ">=" | "<" | ">" => if xs.length < 2 then break: L(StuckExpr(expr, s"not enough arguments for basic operation $name")) - else eval(name, xs.head, xs.tail.head).toRight(StuckExpr(expr, s"unable to evaluate basic operation")) + else eval(name.nme, xs.head, xs.tail.head).toRight(StuckExpr(expr, s"unable to evaluate basic operation")) case _ => L(StuckExpr(expr, s"unexpected basic operation $name"))) case AssignField(assignee, cls, field, value) => for x <- eval(Ref(assignee): TrivialExpr) y <- eval(value) res <- x match - case obj @ Value.Class(cls2, xs) if cls.name == cls2.name => - xs.zip(cls2.fields).find{_._2 == field} match + case obj @ Value.Class(cls2, xs) if cls == cls2 => + xs.zip(cls2.fields).find{_._2.nme == field} match case Some((_, _)) => obj.fields = xs.map(x => if x == obj then y else x) // Ideally, we should return a unit value here, but here we return the assignee value for simplicity. @@ -136,15 +138,15 @@ class Interpreter(verbose: Bool): case Jump(func, args) => for xs <- evalArgs(args) - func <- ctx.funcCtx.get(func.name).toRight(StuckNode(node, s"undefined function ${func.name}")) - ctx1 = ctx.copy(bindingCtx = ctx.bindingCtx ++ func.params.map{_.str}.zip(xs)) + func <- ctx.funcCtx.get(func).toRight(StuckNode(node, s"undefined function ${func.nme}")) + ctx1 = ctx.copy(bindingCtx = ctx.bindingCtx ++ func.params.zip(xs)) res <- eval(func.body)(using ctx1) yield res case Case(scrut, cases, default) => eval(scrut) flatMap { case Value.Class(cls, fields) => cases.find { - case (Pat.Class(cls2), _) => cls.name == cls2.name + case (Pat.Class(cls2), _) => cls.name == cls2 case _ => false } match { case Some((_, x)) => eval(x) @@ -168,29 +170,35 @@ class Interpreter(verbose: Bool): case LetExpr(name, expr, body) => for x <- eval(expr) - ctx1 = ctx.copy(bindingCtx = ctx.bindingCtx + (name.str -> x)) + ctx1 = ctx.copy(bindingCtx = ctx.bindingCtx + (name -> x)) res <- eval(body)(using ctx1) yield res case LetMethodCall(names, cls, method, args, body) => + def lookup_method(cls: ClassInfo, method: Local): Option[Func] = + // The methods with the same name in a subclass will override the method in the superclass. + // But they have different symbols for the method definition. + // So, we don't directly use the method symbol to find the method. + // Instead, we fallback to use the method name. + cls.methods.find(_._1.nme == method.nme).map(_._2) for ys <- evalArgs(args).flatMap { case Value.Class(cls2, xs) :: args => - cls2.methods.get(method.str).toRight(StuckNode(node, s"undefined method ${method.str}")).flatMap { method => - val ctx1 = ctx.copy(bindingCtx = ctx.bindingCtx ++ cls2.fields.zip(xs) ++ method.params.map{_.str}.zip(args)) + lookup_method(cls2, method).toRight(StuckNode(node, s"undefined method ${method.nme}")).flatMap { method => + val ctx1 = ctx.copy(bindingCtx = ctx.bindingCtx ++ cls2.fields.zip(xs) ++ method.params.zip(args)) eval(method.body)(using ctx1) } case _ => L(StuckNode(node, s"not enough arguments for method call, or the first argument is not a class")) } - ctx2 = ctx.copy(bindingCtx = ctx.bindingCtx ++ names.map{_.str}.zip(ys)) + ctx2 = ctx.copy(bindingCtx = ctx.bindingCtx ++ names.zip(ys)) res <- eval(body)(using ctx2) yield res case LetCall(names, func, args, body) => for xs <- evalArgs(args) - func <- ctx.funcCtx.get(func.name).toRight(StuckNode(node, s"undefined function ${func.name}")) - ctx1 = ctx.copy(bindingCtx = ctx.bindingCtx ++ func.params.map{_.str}.zip(xs)) + func <- ctx.funcCtx.get(func).toRight(StuckNode(node, s"undefined function ${func.nme}")) + ctx1 = ctx.copy(bindingCtx = ctx.bindingCtx ++ func.params.zip(xs)) ys <- eval(func.body)(using ctx1) - ctx2 = ctx.copy(bindingCtx = ctx.bindingCtx ++ names.map{_.str}.zip(ys)) + ctx2 = ctx.copy(bindingCtx = ctx.bindingCtx ++ names.zip(ys)) res <- eval(body)(using ctx2) yield res case Panic(msg) => L(StuckNode(node, msg)) @@ -199,8 +207,8 @@ class Interpreter(verbose: Bool): val Program(classes, defs, main) = prog given Ctx = Ctx( bindingCtx = Map.empty, - classCtx = classes.map{cls => cls.name -> cls}.toMap, - funcCtx = defs.map{func => func.name -> func}.toMap, + classCtx = classes.map(cls => (cls.name, cls)).toMap, + funcCtx = defs.map(func => (func.name, func)).toMap, ) eval(main) match case R(x) => x diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Llir.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Llir.scala index 36971ad982..2a8a9b0a84 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Llir.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Llir.scala @@ -7,6 +7,7 @@ import mlscript.utils.shorthands._ import hkmc2.syntax._ import hkmc2.Message.MessageContext import hkmc2.document._ +import hkmc2.codegen.Local import util.Sorting import collection.immutable.SortedSet @@ -17,6 +18,13 @@ private def raw(x: String): Document = doc"$x" final case class LowLevelIRError(message: String) extends Exception(message) +private def docSymWithUid(sym: Local): Document = doc"${sym.nme}$$${sym.uid.toString()}" + +val hiddenPrefixes = Set("Tuple") + +def defaultHidden(x: Str): Bool = + hiddenPrefixes.exists(x.startsWith) + case class Program( classes: Set[ClassInfo], defs: Set[Func], @@ -29,14 +37,14 @@ case class Program( Sorting.quickSort(t2) s"Program({${t1.mkString(",\n")}}, {\n${t2.mkString("\n")}\n},\n$main)" - def show(hiddenNames: Set[Str] = Set.empty) = toDocument(hiddenNames).toString - def toDocument(hiddenNames: Set[Str] = Set.empty) : Document = - val t1 = classes.toArray + def show(hide: Str => Bool = defaultHidden) = toDocument(hide).toString + def toDocument(hide: Str => Bool = defaultHidden) : Document = + val t1 = classes.iterator.filterNot(c => hide(c.name.nme)).toArray val t2 = defs.toArray Sorting.quickSort(t1) Sorting.quickSort(t2) given Conversion[String, Document] = raw - val docClasses = t1.filter(x => !hiddenNames.contains(x.name)).map(_.toDocument).toList.mkDocument(doc" # ") + val docClasses = t1.map(_.toDocument).toList.mkDocument(doc" # ") val docDefs = t2.map(_.toDocument).toList.mkDocument(doc" # ") val docMain = main.toDocument doc" #{ $docClasses\n$docDefs\n$docMain #} " @@ -47,10 +55,10 @@ implicit object ClassInfoOrdering extends Ordering[ClassInfo] { case class ClassInfo( id: Int, - name: Str, - fields: Ls[Str], - parents: Set[Str], - methods: Map[Str, Func], + name: Local, + fields: Ls[Local], + parents: Set[Local], + methods: Map[Local, Func], ): override def hashCode: Int = id override def toString: String = @@ -59,55 +67,30 @@ case class ClassInfo( def show = toDocument.toString def toDocument: Document = given Conversion[String, Document] = raw - val ext = if parents.isEmpty then "" else " extends " + parents.mkString(", ") + val ext = if parents.isEmpty then "" else " extends " + parents.map(_.nme).mkString(", ") if methods.isEmpty then - doc"class $name(${fields.mkString(",")})$ext" + doc"class ${name.nme}(${fields.map(docSymWithUid).mkString(",")})$ext" else - val docFirst = doc"class $name(${fields.mkString(",")})$ext {" + val docFirst = doc"class ${name.nme}(${fields.map(docSymWithUid).mkString(",")})$ext {" val docMethods = methods.map { (_, func) => func.toDocument }.toList.mkDocument(doc" # ") val docLast = doc"}" doc"$docFirst #{ # $docMethods #} # $docLast" -case class Name(str: Str): - def trySubst(map: Map[Str, Name]) = map.getOrElse(str, this) - override def toString: String = str - -object FuncRef: - def fromName(name: Str) = FuncRef(Right(name)) - def fromName(name: Name) = FuncRef(Right(name.str)) - def fromFunc(func: Func) = FuncRef(Left(func)) - -class FuncRef(var func: Either[Func, Str]): - def name: String = func.fold(_.name, x => x) - def expectFn: Func = func.fold(identity, x => throw Exception(s"Expected a def, but got $x")) - def getFunc: Opt[Func] = func.left.toOption +class FuncRef(var func: Local): + def name: String = func.nme override def equals(o: Any): Bool = o match { case o: FuncRef => o.name == this.name case _ => false } -object ClassRef: - def fromName(name: Str) = ClassRef(Right(name)) - def fromName(name: Name) = ClassRef(Right(name.str)) - def fromClass(cls: ClassInfo) = ClassRef(Left(cls)) - -class ClassRef(var cls: Either[ClassInfo, Str]): - def name: String = cls.fold(_.name, x => x) - def expectCls: ClassInfo = cls.fold(identity, x => throw Exception(s"Expected a class, but got $x")) - def getClass: Opt[ClassInfo] = cls.left.toOption - override def equals(o: Any): Bool = o match { - case o: ClassRef => o.name == this.name - case _ => false - } - implicit object FuncOrdering extends Ordering[Func] { def compare(a: Func, b: Func) = a.id.compare(b.id) } case class Func( id: Int, - name: Str, - params: Ls[Name], + name: Local, + params: Ls[Local], resultNum: Int, body: Node ): @@ -121,7 +104,7 @@ case class Func( def show = toDocument def toDocument: Document = given Conversion[String, Document] = raw - val docFirst = doc"def $name(${params.map(_.toString).mkString(",")}) =" + val docFirst = doc"def ${docSymWithUid(name)}(${params.map(docSymWithUid).mkString(",")}) =" val docBody = body.toDocument doc"$docFirst #{ # $docBody #} " @@ -135,12 +118,12 @@ sealed trait TrivialExpr: private def showArguments(args: Ls[TrivialExpr]) = args map (_.show) mkString "," enum Expr: - case Ref(name: Name) extends Expr, TrivialExpr + case Ref(sym: Local) extends Expr, TrivialExpr case Literal(lit: hkmc2.syntax.Literal) extends Expr, TrivialExpr - case CtorApp(cls: ClassRef, args: Ls[TrivialExpr]) - case Select(name: Name, cls: ClassRef, field: Str) - case BasicOp(name: Str, args: Ls[TrivialExpr]) - case AssignField(assignee: Name, cls: ClassRef, field: Str, value: TrivialExpr) + case CtorApp(cls: Local, args: Ls[TrivialExpr]) + case Select(name: Local, cls: Local, field: Str) + case BasicOp(name: Local, args: Ls[TrivialExpr]) + case AssignField(assignee: Local, cls: Local, field: Str, value: TrivialExpr) override def toString: String = show @@ -149,39 +132,39 @@ enum Expr: def toDocument: Document = given Conversion[String, Document] = raw this match - case Ref(s) => s.toString + case Ref(s) => docSymWithUid(s) case Literal(Tree.BoolLit(lit)) => s"$lit" case Literal(Tree.IntLit(lit)) => s"$lit" case Literal(Tree.DecLit(lit)) => s"$lit" case Literal(Tree.StrLit(lit)) => s"$lit" case Literal(Tree.UnitLit(undefinedOrNull)) => if undefinedOrNull then "undefined" else "null" case CtorApp(cls, args) => - doc"${cls.name}(${args.map(_.toString).mkString(",")})" + doc"${docSymWithUid(cls)}(${args.map(_.toString).mkString(",")})" case Select(s, cls, fld) => - doc"${s.toString}.<${cls.name}:$fld>" - case BasicOp(name: Str, args) => - doc"$name(${args.map(_.toString).mkString(",")})" + doc"${docSymWithUid(s)}.<${docSymWithUid(cls)}:$fld>" + case BasicOp(sym, args) => + doc"${sym.nme}(${args.map(_.toString).mkString(",")})" case AssignField(assignee, clsInfo, fieldName, value) => - doc"${assignee.toString}.${fieldName} := ${value.toString}" + doc"${docSymWithUid(assignee)}.${fieldName} := ${value.toString}" enum Pat: case Lit(lit: hkmc2.syntax.Literal) - case Class(cls: ClassRef) + case Class(cls: Local) override def toString: String = this match case Lit(lit) => s"$lit" - case Class(cls) => s"${cls.name}" + case Class(cls) => s"${{docSymWithUid(cls)}}" enum Node: // Terminal forms: case Result(res: Ls[TrivialExpr]) - case Jump(func: FuncRef, args: Ls[TrivialExpr]) + case Jump(func: Local, args: Ls[TrivialExpr]) case Case(scrutinee: TrivialExpr, cases: Ls[(Pat, Node)], default: Opt[Node]) case Panic(msg: Str) // Intermediate forms: - case LetExpr(name: Name, expr: Expr, body: Node) - case LetMethodCall(names: Ls[Name], cls: ClassRef, method: Name, args: Ls[TrivialExpr], body: Node) - case LetCall(names: Ls[Name], func: FuncRef, args: Ls[TrivialExpr], body: Node) + case LetExpr(name: Local, expr: Expr, body: Node) + case LetMethodCall(names: Ls[Local], cls: Local, method: Local, args: Ls[TrivialExpr], body: Node) + case LetCall(names: Ls[Local], func: Local, args: Ls[TrivialExpr], body: Node) override def toString: String = show @@ -192,7 +175,7 @@ enum Node: this match case Result(res) => (res |> showArguments) case Jump(jp, args) => - doc"jump ${jp.name}(${args |> showArguments})" + doc"jump ${docSymWithUid(jp)}(${args |> showArguments})" case Case(x, cases, default) => val docFirst = doc"case ${x.toString} of" val docCases = cases.map { @@ -206,9 +189,9 @@ enum Node: case Panic(msg) => doc"panic ${s"\"$msg\""}" case LetExpr(x, expr, body) => - doc"let ${x.toString} = ${expr.toString} in # ${body.toDocument}" + doc"let ${docSymWithUid(x)} = ${expr.toString} in # ${body.toDocument}" case LetMethodCall(xs, cls, method, args, body) => - doc"let ${xs.map(_.toString).mkString(",")} = ${cls.name}.${method.toString}(${args.map(_.toString).mkString(",")}) in # ${body.toDocument}" + doc"let ${xs.map(docSymWithUid).mkString(",")} = ${cls.nme}.${docSymWithUid(method)}(${args.map(_.toString).mkString(",")}) in # ${body.toDocument}" case LetCall(xs, func, args, body) => - doc"let* (${xs.map(_.toString).mkString(",")}) = ${func.name}(${args.map(_.toString).mkString(",")}) in # ${body.toDocument}" + doc"let* (${xs.map(docSymWithUid).mkString(",")}) = ${func.nme}(${args.map(_.toString).mkString(",")}) in # ${body.toDocument}" diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/RefResolver.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/RefResolver.scala deleted file mode 100644 index 5b6da3eab9..0000000000 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/RefResolver.scala +++ /dev/null @@ -1,56 +0,0 @@ -package hkmc2.codegen.llir - -import mlscript.utils.shorthands._ - -import Node._ - -// Resolves the definition references by turning them from Right(name) to Left(Func). -private final class RefResolver(defs: Map[Str, Func], classes: Map[Str, ClassInfo], allowInlineJp: Bool): - private def f(x: Expr): Unit = x match - case Expr.Ref(name) => - case Expr.Literal(lit) => - case Expr.CtorApp(cls, args) => classes.get(cls.name) match - case None => throw LowLevelIRError(f"unknown class ${cls.name} in ${classes.keySet.mkString(",")}") - case Some(value) => cls.cls = Left(value) - case Expr.Select(name, cls, field) => classes.get(cls.name) match - case None => throw LowLevelIRError(f"unknown class ${cls.name} in ${classes.keySet.mkString(",")}") - case Some(value) => cls.cls = Left(value) - case Expr.BasicOp(name, args) => - case Expr.AssignField(name, cls, field, value) => classes.get(cls.name) match - case None => throw LowLevelIRError(f"unknown class ${cls.name} in ${classes.keySet.mkString(",")}") - case Some(value) => cls.cls = Left(value) - - private def f(x: Pat): Unit = x match - case Pat.Lit(lit) => - case Pat.Class(cls) => classes.get(cls.name) match - case None => throw LowLevelIRError(f"unknown class ${cls.name} in ${classes.keySet.mkString(",")}") - case Some(value) => cls.cls = Left(value) - - private def f(x: Node): Unit = x match - case Result(res) => - case Case(scrut, cases, default) => cases foreach { (_, body) => f(body) }; default foreach f - case LetExpr(name, expr, body) => f(expr); f(body) - case LetMethodCall(names, cls, method, args, body) => f(body) - case LetCall(resultNames, defnref, args, body) => - defs.get(defnref.name) match - case Some(defn) => defnref.func = Left(defn) - case None => throw LowLevelIRError(f"unknown function ${defnref.name} in ${defs.keySet.mkString(",")}") - f(body) - case Jump(defnref, _) => - // maybe not promoted yet - defs.get(defnref.name) match - case Some(defn) => defnref.func = Left(defn) - case None => - if !allowInlineJp then - throw LowLevelIRError(f"unknown function ${defnref.name} in ${defs.keySet.mkString(",")}") - case Panic(_) => - def run(node: Node) = f(node) - def run(node: Func) = f(node.body) - -def resolveRef(entry: Node, defs: Set[Func], classes: Set[ClassInfo], allowInlineJp: Bool = false): Unit = - val defsMap = defs.map(x => x.name -> x).toMap - val classesMap = classes.map(x => x.name -> x).toMap - val rl = RefResolver(defsMap, classesMap, allowInlineJp) - rl.run(entry) - defs.foreach(rl.run(_)) - diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Validator.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Validator.scala deleted file mode 100644 index a660f9f078..0000000000 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Validator.scala +++ /dev/null @@ -1,45 +0,0 @@ -package hkmc2.codegen.llir - -import hkmc2.utils._ - -private final class FuncRefInSet(defs: Set[Func], classes: Set[ClassInfo]): - import Node._ - import Expr._ - - private def f(x: Expr): Unit = x match - case Ref(name) => - case Literal(lit) => - case CtorApp(name, args) => - case Select(name, ref, field) => ref.getClass match { - case Some(real_class) => if !classes.exists(_ eq real_class) then throw LowLevelIRError("ref is not in the set") - case _ => - } - case BasicOp(name, args) => - case AssignField(assignee, ref, _, value) => ref.getClass match { - case Some(real_class) => if !classes.exists(_ eq real_class) then throw LowLevelIRError("ref is not in the set") - case _ => - } - - private def f(x: Node): Unit = x match - case Result(res) => - case Jump(func, args) => - case Case(x, cases, default) => cases foreach { (_, body) => f(body) }; default foreach f - case Panic(_) => - case LetExpr(name, expr, body) => f(body) - case LetMethodCall(names, cls, method, args, body) => f(body) - case LetCall(res, ref, args, body) => - ref.getFunc match { - case Some(real_func) => if !defs.exists(_ eq real_func) then throw LowLevelIRError("ref is not in the set") - case _ => - } - f(body) - def run(node: Node) = f(node) - def run(func: Func) = f(func.body) - -def validateRefInSet(entry: Node, defs: Set[Func], classes: Set[ClassInfo]): Unit = - val funcRefInSet = FuncRefInSet(defs, classes) - defs.foreach(funcRefInSet.run(_)) - -def validate(entry: Node, defs: Set[Func], classes: Set[ClassInfo]): Unit = - validateRefInSet(entry, defs, classes) - diff --git a/hkmc2/shared/src/test/mlscript/llir/BasicCpp.mls b/hkmc2/shared/src/test/mlscript/llir/BasicCpp.mls index be1d2e5400..823d319b3c 100644 --- a/hkmc2/shared/src/test/mlscript/llir/BasicCpp.mls +++ b/hkmc2/shared/src/test/mlscript/llir/BasicCpp.mls @@ -12,35 +12,5 @@ fun foo(a) = x + 1 //│ //│ Cpp: -//│ #include "mlsprelude.h" -//│ _mlsValue _mls_j_0(_mlsValue); -//│ _mlsValue _mls_foo(_mlsValue); -//│ _mlsValue _mlsMain(); -//│ _mlsValue _mls_j_0(_mlsValue _mls_x_2) { -//│ _mlsValue _mls_retval; -//│ auto _mls_x_6 = (_mls_x_2 + _mlsValue::fromIntLit(1)); -//│ _mls_retval = _mls_x_6; -//│ return _mls_retval; -//│ } -//│ _mlsValue _mls_foo(_mlsValue _mls_a) { -//│ _mlsValue _mls_retval; -//│ auto _mls_x_0 = _mlsValue::create<_mls_Unit>(); -//│ auto _mls_x_1 = (_mls_a > _mlsValue::fromIntLit(0)); -//│ if (_mlsValue::isIntLit(_mls_x_1, 1)) { -//│ auto _mls_x_3 = _mlsValue::fromIntLit(1); -//│ auto _mls_x_4 = _mlsValue::create<_mls_Unit>(); -//│ _mls_retval = _mls_j_0(_mls_x_3); -//│ } else { -//│ auto _mls_x_5 = _mlsValue::create<_mls_Unit>(); -//│ _mls_retval = _mls_j_0(_mls_x_0); -//│ } -//│ return _mls_retval; -//│ } -//│ _mlsValue _mlsMain() { -//│ _mlsValue _mls_retval; -//│ _mls_retval = _mlsValue::create<_mls_Unit>(); -//│ return _mls_retval; -//│ } -//│ int main() { return _mlsLargeStack(_mlsMainWrapper); } diff --git a/hkmc2/shared/src/test/mlscript/llir/Classes.mls b/hkmc2/shared/src/test/mlscript/llir/Classes.mls index de14b09778..eb61586740 100644 --- a/hkmc2/shared/src/test/mlscript/llir/Classes.mls +++ b/hkmc2/shared/src/test/mlscript/llir/Classes.mls @@ -27,21 +27,21 @@ fun main() = main() //│ LLIR: //│ class Base() { -//│ def get() = +//│ def get$327() = //│ 1 //│ } //│ class Derived() extends Base { -//│ def get() = +//│ def get$328() = //│ 2 //│ } -//│ def main() = -//│ let x$0 = Derived() in -//│ let x$1 = Base.get(x$0) in -//│ let x$2 = Derived.get(x$0) in -//│ let x$3 = *(x$1,x$2) in -//│ x$3 -//│ let* (x$4) = main() in -//│ x$4 +//│ def main$330() = +//│ let x$404 = Derived$335() in +//│ let x$405 = Base.get$327(x$404) in +//│ let x$406 = Derived.get$328(x$404) in +//│ let x$407 = *(x$405,x$406) in +//│ x$407 +//│ let* (x$408) = main() in +//│ x$408 //│ //│ Interpreted: //│ 4 diff --git a/hkmc2/shared/src/test/mlscript/llir/ControlFlow.mls b/hkmc2/shared/src/test/mlscript/llir/ControlFlow.mls index fe075de7da..1c657593e9 100644 --- a/hkmc2/shared/src/test/mlscript/llir/ControlFlow.mls +++ b/hkmc2/shared/src/test/mlscript/llir/ControlFlow.mls @@ -14,12 +14,12 @@ f1() //│ = 2 //│ LLIR: //│ -//│ def f1() = -//│ let x$0 = 1 in -//│ let x$1 = 2 in -//│ x$1 -//│ let* (x$2) = f1() in -//│ x$2 +//│ def f1$249() = +//│ let x$310 = 1 in +//│ let x$311 = 2 in +//│ x$311 +//│ let* (x$312) = f1() in +//│ x$312 //│ //│ Interpreted: //│ 2 @@ -33,18 +33,18 @@ f2() //│ = 3 //│ LLIR: //│ -//│ def f2() = -//│ let x$0 = 0 in -//│ let x$1 = ==(x$0,1) in -//│ case x$1 of +//│ def f2$313() = +//│ let x$375 = 0 in +//│ let x$376 = ==(x$375,1) in +//│ case x$376 of //│ BoolLit(true) => //│ 2 //│ _ => //│ 3 -//│ def j$0() = +//│ def j$377() = //│ null -//│ let* (x$2) = f2() in -//│ x$2 +//│ let* (x$378) = f2() in +//│ x$378 //│ //│ Interpreted: //│ 3 @@ -59,19 +59,19 @@ f3() //│ = 0 //│ LLIR: //│ -//│ def f3() = -//│ let x$0 = 0 in -//│ let x$1 = 1 in -//│ let x$2 = true in -//│ case x$2 of +//│ def f3$379() = +//│ let x$441 = 0 in +//│ let x$442 = 1 in +//│ let x$443 = true in +//│ case x$443 of //│ BoolLit(true) => -//│ x$0 +//│ x$441 //│ _ => -//│ x$1 -//│ def j$0() = +//│ x$442 +//│ def j$444() = //│ null -//│ let* (x$3) = f3() in -//│ x$3 +//│ let* (x$445) = f3() in +//│ x$445 :sllir @@ -84,20 +84,20 @@ f4() //│ = 3 //│ LLIR: //│ -//│ def f4() = -//│ let x$0 = 0 in -//│ let x$1 = ==(x$0,1) in -//│ case x$1 of +//│ def f4$446() = +//│ let x$511 = 0 in +//│ let x$512 = ==(x$511,1) in +//│ case x$512 of //│ BoolLit(true) => -//│ let x$3 = 2 in -//│ jump j$0(x$3) +//│ let x$514 = 2 in +//│ jump j$513(x$514) //│ _ => -//│ let x$4 = 3 in -//│ jump j$0(x$4) -//│ def j$0(x$2) = -//│ x$2 -//│ let* (x$5) = f4() in -//│ x$5 +//│ let x$515 = 3 in +//│ jump j$513(x$515) +//│ def j$513(tmp$457) = +//│ tmp$457 +//│ let* (x$516) = f4() in +//│ x$516 //│ //│ Interpreted: //│ 3 @@ -113,29 +113,29 @@ f5() //│ = 5 //│ LLIR: //│ -//│ def f5() = -//│ let x$0 = 0 in -//│ let x$1 = ==(x$0,1) in -//│ case x$1 of +//│ def f5$517() = +//│ let x$587 = 0 in +//│ let x$588 = ==(x$587,1) in +//│ case x$588 of //│ BoolLit(true) => -//│ let x$3 = 2 in -//│ jump j$0(x$3) +//│ let x$590 = 2 in +//│ jump j$589(x$590) //│ _ => -//│ let x$4 = 3 in -//│ jump j$0(x$4) -//│ def j$0(x$2) = -//│ let x$5 = ==(x$2,2) in -//│ case x$5 of +//│ let x$591 = 3 in +//│ jump j$589(x$591) +//│ def j$589(tmp$532) = +//│ let x$592 = ==(tmp$532,2) in +//│ case x$592 of //│ BoolLit(true) => -//│ let x$7 = 4 in -//│ jump j$1(x$7) +//│ let x$594 = 4 in +//│ jump j$593(x$594) //│ _ => -//│ let x$8 = 5 in -//│ jump j$1(x$8) -//│ def j$1(x$6) = -//│ x$6 -//│ let* (x$9) = f5() in -//│ x$9 +//│ let x$595 = 5 in +//│ jump j$593(x$595) +//│ def j$593(tmp$533) = +//│ tmp$533 +//│ let* (x$596) = f5() in +//│ x$596 //│ //│ Interpreted: //│ 5 @@ -146,45 +146,19 @@ fun test() = if true do test() //│ LLIR: //│ -//│ def test() = -//│ let x$0 = true in -//│ case x$0 of +//│ def test$597() = +//│ let x$657 = true in +//│ case x$657 of //│ BoolLit(true) => -//│ let* (x$1) = test() in -//│ x$1 +//│ let* (x$659) = test() in +//│ x$659 //│ _ => //│ undefined -//│ def j$0() = +//│ def j$658() = //│ null //│ undefined //│ //│ Cpp: -//│ #include "mlsprelude.h" -//│ _mlsValue _mls_j_0(); -//│ _mlsValue _mls_test(); -//│ _mlsValue _mlsMain(); -//│ _mlsValue _mls_j_0() { -//│ _mlsValue _mls_retval; -//│ _mls_retval = _mlsValue::create<_mls_Unit>(); -//│ return _mls_retval; -//│ } -//│ _mlsValue _mls_test() { -//│ _mlsValue _mls_retval; -//│ auto _mls_x_0 = _mlsValue::fromIntLit(1); -//│ if (_mlsValue::isIntLit(_mls_x_0, 1)) { -//│ auto _mls_x_1 = _mls_test(); -//│ _mls_retval = _mls_x_1; -//│ } else { -//│ _mls_retval = _mlsValue::create<_mls_Unit>(); -//│ } -//│ return _mls_retval; -//│ } -//│ _mlsValue _mlsMain() { -//│ _mlsValue _mls_retval; -//│ _mls_retval = _mlsValue::create<_mls_Unit>(); -//│ return _mls_retval; -//│ } -//│ int main() { return _mlsLargeStack(_mlsMainWrapper); } :sllir :scpp @@ -192,47 +166,20 @@ fun test() = (if true then test()) + 1 //│ LLIR: //│ -//│ def test() = -//│ let x$0 = true in -//│ case x$0 of +//│ def test$660() = +//│ let x$723 = true in +//│ case x$723 of //│ BoolLit(true) => -//│ let* (x$2) = test() in -//│ jump j$0(x$2) +//│ let* (x$725) = test() in +//│ jump j$724(x$725) //│ _ => //│ panic "match error" -//│ def j$0(x$1) = -//│ let x$3 = +(x$1,1) in -//│ x$3 +//│ def j$724(tmp$670) = +//│ let x$726 = +(tmp$670,1) in +//│ x$726 //│ undefined //│ //│ Cpp: -//│ #include "mlsprelude.h" -//│ _mlsValue _mls_j_0(_mlsValue); -//│ _mlsValue _mls_test(); -//│ _mlsValue _mlsMain(); -//│ _mlsValue _mls_j_0(_mlsValue _mls_x_1) { -//│ _mlsValue _mls_retval; -//│ auto _mls_x_3 = (_mls_x_1 + _mlsValue::fromIntLit(1)); -//│ _mls_retval = _mls_x_3; -//│ return _mls_retval; -//│ } -//│ _mlsValue _mls_test() { -//│ _mlsValue _mls_retval; -//│ auto _mls_x_0 = _mlsValue::fromIntLit(1); -//│ if (_mlsValue::isIntLit(_mls_x_0, 1)) { -//│ auto _mls_x_2 = _mls_test(); -//│ _mls_retval = _mls_j_0(_mls_x_2); -//│ } else { -//│ throw std::runtime_error("match error"); -//│ } -//│ return _mls_retval; -//│ } -//│ _mlsValue _mlsMain() { -//│ _mlsValue _mls_retval; -//│ _mls_retval = _mlsValue::create<_mls_Unit>(); -//│ return _mls_retval; -//│ } -//│ int main() { return _mlsLargeStack(_mlsMainWrapper); } :sllir @@ -247,58 +194,27 @@ f() //│ = 11 //│ LLIR: //│ -//│ def f() = -//│ let x$0 = 10 in -//│ let x$1 = true in -//│ case x$1 of +//│ def f$727() = +//│ let x$793 = 10 in +//│ let x$794 = true in +//│ case x$794 of //│ BoolLit(true) => -//│ let x$3 = +(x$0,1) in -//│ let x$4 = undefined in -//│ jump j$0(x$3) +//│ let x$796 = +(x$793,1) in +//│ let x$797 = undefined in +//│ jump j$795(x$796) //│ _ => -//│ let x$5 = undefined in -//│ jump j$0(x$0) -//│ def j$0(x$2) = -//│ x$2 -//│ let* (x$6) = f() in -//│ x$6 +//│ let x$798 = undefined in +//│ jump j$795(x$793) +//│ def j$795(x$728) = +//│ x$728 +//│ let* (x$799) = f() in +//│ x$799 //│ //│ Cpp: -//│ #include "mlsprelude.h" -//│ _mlsValue _mls_j_0(_mlsValue); -//│ _mlsValue _mls_f(); -//│ _mlsValue _mlsMain(); -//│ _mlsValue _mls_j_0(_mlsValue _mls_x_2) { -//│ _mlsValue _mls_retval; -//│ _mls_retval = _mls_x_2; -//│ return _mls_retval; -//│ } -//│ _mlsValue _mls_f() { -//│ _mlsValue _mls_retval; -//│ auto _mls_x_0 = _mlsValue::fromIntLit(10); -//│ auto _mls_x_1 = _mlsValue::fromIntLit(1); -//│ if (_mlsValue::isIntLit(_mls_x_1, 1)) { -//│ auto _mls_x_3 = (_mls_x_0 + _mlsValue::fromIntLit(1)); -//│ auto _mls_x_4 = _mlsValue::create<_mls_Unit>(); -//│ _mls_retval = _mls_j_0(_mls_x_3); -//│ } else { -//│ auto _mls_x_5 = _mlsValue::create<_mls_Unit>(); -//│ _mls_retval = _mls_j_0(_mls_x_0); -//│ } -//│ return _mls_retval; -//│ } -//│ _mlsValue _mlsMain() { -//│ _mlsValue _mls_retval; -//│ auto _mls_x_6 = _mls_f(); -//│ _mls_retval = _mls_x_6; -//│ return _mls_retval; -//│ } -//│ int main() { return _mlsLargeStack(_mlsMainWrapper); } //│ //│ Interpreted: //│ 11 - :sllir :intl class A(x) @@ -311,29 +227,29 @@ fun f(a) = f(A(1)) //│ = 1 //│ LLIR: -//│ class A(x) -//│ class B(y) -//│ def f(a) = -//│ case a of -//│ A => -//│ let x$1 = a. in -//│ let x$2 = 1 in -//│ jump j$0(x$2) +//│ class A(x$805) +//│ class B(y$808) +//│ def f$802(a$809) = +//│ case a$809 of +//│ A$803 => +//│ let x$881 = a$809. in +//│ let x$882 = 1 in +//│ jump j$880(x$882) //│ _ => -//│ case a of -//│ B => -//│ let x$4 = a. in -//│ let x$5 = 2 in -//│ jump j$1(x$5) +//│ case a$809 of +//│ B$806 => +//│ let x$884 = a$809. in +//│ let x$885 = 2 in +//│ jump j$883(x$885) //│ _ => //│ panic "match error" -//│ def j$1(x$3) = -//│ jump j$0(x$3) -//│ def j$0(x$0) = -//│ x$0 -//│ let x$6 = A(1) in -//│ let* (x$7) = f(x$6) in -//│ x$7 +//│ def j$883(tmp$824) = +//│ jump j$880(tmp$824) +//│ def j$880(tmp$824) = +//│ tmp$824 +//│ let x$886 = A$803(1) in +//│ let* (x$887) = f(x$886) in +//│ x$887 //│ //│ Interpreted: //│ 1 @@ -352,50 +268,50 @@ fun f(a) = f(A(1)) //│ = 1 //│ LLIR: -//│ class A(x) -//│ class B(y) -//│ def f(a) = -//│ case a of -//│ A => -//│ let x$1 = a. in -//│ case a of -//│ A => -//│ let x$3 = a. in -//│ case x$3 of +//│ class A(x$893) +//│ class B(y$896) +//│ def f$890(a$897) = +//│ case a$897 of +//│ A$891 => +//│ let x$973 = a$897. in +//│ case a$897 of +//│ A$891 => +//│ let x$975 = a$897. in +//│ case x$975 of //│ IntLit(1) => -//│ let x$5 = 1 in -//│ jump j$2(x$5) +//│ let x$977 = 1 in +//│ jump j$976(x$977) //│ _ => //│ panic "match error" //│ _ => -//│ case a of -//│ B => -//│ let x$7 = a. in -//│ let x$8 = 2 in -//│ jump j$3(x$8) +//│ case a$897 of +//│ B$894 => +//│ let x$979 = a$897. in +//│ let x$980 = 2 in +//│ jump j$978(x$980) //│ _ => //│ panic "match error" //│ _ => -//│ case a of -//│ B => -//│ let x$10 = a. in -//│ let x$11 = 3 in -//│ jump j$4(x$11) +//│ case a$897 of +//│ B$894 => +//│ let x$982 = a$897. in +//│ let x$983 = 3 in +//│ jump j$981(x$983) //│ _ => //│ panic "match error" -//│ def j$2(x$4) = -//│ jump j$1(x$4) -//│ def j$3(x$6) = -//│ jump j$1(x$6) -//│ def j$1(x$2) = -//│ jump j$0(x$2) -//│ def j$4(x$9) = -//│ jump j$0(x$9) -//│ def j$0(x$0) = -//│ x$0 -//│ let x$12 = A(1) in -//│ let* (x$13) = f(x$12) in -//│ x$13 +//│ def j$976(tmp$915) = +//│ jump j$974(tmp$915) +//│ def j$978(tmp$915) = +//│ jump j$974(tmp$915) +//│ def j$974(tmp$915) = +//│ jump j$972(tmp$915) +//│ def j$981(tmp$916) = +//│ jump j$972(tmp$916) +//│ def j$972(tmp$916) = +//│ tmp$916 +//│ let x$984 = A$891(1) in +//│ let* (x$985) = f(x$984) in +//│ x$985 //│ //│ Interpreted: //│ 1 diff --git a/hkmc2/shared/src/test/mlscript/llir/Ctor.mls b/hkmc2/shared/src/test/mlscript/llir/Ctor.mls index fcf81a3eb7..5dbcad49b0 100644 --- a/hkmc2/shared/src/test/mlscript/llir/Ctor.mls +++ b/hkmc2/shared/src/test/mlscript/llir/Ctor.mls @@ -10,12 +10,12 @@ fun testCtor1() = None fun testCtor2() = new None //│ LLIR: //│ class None() -//│ def testCtor1() = -//│ let x$0 = None() in -//│ x$0 -//│ def testCtor2() = -//│ let x$1 = None() in -//│ x$1 +//│ def testCtor1$250() = +//│ let x$311 = None$252() in +//│ x$311 +//│ def testCtor2$249() = +//│ let x$312 = None$252() in +//│ x$312 //│ undefined :sllir @@ -23,11 +23,11 @@ class A(x) fun testCtor1() = A(1) fun testCtor2() = new A(1) //│ LLIR: -//│ class A(x) -//│ def testCtor1() = -//│ let x$0 = A(1) in -//│ x$0 -//│ def testCtor2() = -//│ let x$1 = A(1) in -//│ x$1 +//│ class A(x$318) +//│ def testCtor1$315() = +//│ let x$378 = A$316(1) in +//│ x$378 +//│ def testCtor2$314() = +//│ let x$379 = A$316(1) in +//│ x$379 //│ undefined diff --git a/hkmc2/shared/src/test/mlscript/llir/HigherOrder.mls b/hkmc2/shared/src/test/mlscript/llir/HigherOrder.mls index 432a33f1ad..73a501c844 100644 --- a/hkmc2/shared/src/test/mlscript/llir/HigherOrder.mls +++ b/hkmc2/shared/src/test/mlscript/llir/HigherOrder.mls @@ -11,51 +11,19 @@ fun add(x) = y => x + y add(1)(2) //│ = 3 //│ LLIR: -//│ class Lambda$0(x) extends Callable { -//│ def apply1(y) = -//│ let x$0 = +(x,y) in -//│ x$0 +//│ class Lambda(x$250) extends Callable { +//│ def apply1$278(y$251) = +//│ let x$318 = +(x$250,y$251) in +//│ x$318 //│ } -//│ def add(x) = -//│ let x$1 = Lambda$0(x) in -//│ x$1 -//│ let* (x$2) = add(1) in -//│ let x$3 = Callable.apply1(x$2,2) in -//│ x$3 +//│ def add$249(x$250) = +//│ let x$319 = Lambda$316(x$250) in +//│ x$319 +//│ let* (x$320) = add(1) in +//│ let x$321 = Callable.apply1$278(x$320,2) in +//│ x$321 //│ //│ Cpp: -//│ #include "mlsprelude.h" -//│ struct _mls_Lambda_0; -//│ _mlsValue _mls_add(_mlsValue); -//│ _mlsValue _mlsMain(); -//│ struct _mls_Lambda_0: public _mls_Callable { -//│ _mlsValue _mls_x; -//│ constexpr static inline const char *typeName = "Lambda$0"; -//│ constexpr static inline uint32_t typeTag = nextTypeTag(); -//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->_mls_x.print(); std::printf(")"); } -//│ virtual void destroy() override { _mlsValue::destroy(this->_mls_x); operator delete (this, std::align_val_t(_mlsAlignment)); } -//│ static _mlsValue create(_mlsValue _mls_x) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) _mls_Lambda_0; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->_mls_x = _mls_x; return _mlsValue(_mlsVal); } -//│ virtual _mlsValue _mls_apply1(_mlsValue _mls_y) { -//│ _mlsValue _mls_retval; -//│ auto _mls_x_0 = (_mls_x + _mls_y); -//│ _mls_retval = _mls_x_0; -//│ return _mls_retval; -//│ } -//│ }; -//│ _mlsValue _mls_add(_mlsValue _mls_x) { -//│ _mlsValue _mls_retval; -//│ auto _mls_x_1 = _mlsValue::create<_mls_Lambda_0>(_mls_x); -//│ _mls_retval = _mls_x_1; -//│ return _mls_retval; -//│ } -//│ _mlsValue _mlsMain() { -//│ _mlsValue _mls_retval; -//│ auto _mls_x_2 = _mls_add(_mlsValue::fromIntLit(1)); -//│ auto _mls_x_3 = _mlsMethodCall<_mls_Callable>(_mls_x_2)->_mls_apply1(_mlsValue::fromIntLit(2)); -//│ _mls_retval = _mls_x_3; -//│ return _mls_retval; -//│ } -//│ int main() { return _mlsLargeStack(_mlsMainWrapper); } //│ //│ Interpreted: //│ 3 @@ -67,56 +35,21 @@ fun add4(a, b) = (c, d) => a + b + c + d add4(1, 2)(3, 4) //│ = 10 //│ LLIR: -//│ class Lambda$0(a,b) extends Callable { -//│ def apply2(c,d) = -//│ let x$0 = +(a,b) in -//│ let x$1 = +(x$0,c) in -//│ let x$2 = +(x$1,d) in -//│ x$2 +//│ class Lambda(b$324,a$323) extends Callable { +//│ def apply2$361(c$325,d$326) = +//│ let x$399 = +(a$323,b$324) in +//│ let x$400 = +(x$399,c$325) in +//│ let x$401 = +(x$400,d$326) in +//│ x$401 //│ } -//│ def add4(a,b) = -//│ let x$3 = Lambda$0(a,b) in -//│ x$3 -//│ let* (x$4) = add4(1,2) in -//│ let x$5 = Callable.apply2(x$4,3,4) in -//│ x$5 +//│ def add4$322(a$323,b$324) = +//│ let x$402 = Lambda$397(b$324,a$323) in +//│ x$402 +//│ let* (x$403) = add4(1,2) in +//│ let x$404 = Callable.apply2$361(x$403,3,4) in +//│ x$404 //│ //│ Cpp: -//│ #include "mlsprelude.h" -//│ struct _mls_Lambda_0; -//│ _mlsValue _mls_add4(_mlsValue, _mlsValue); -//│ _mlsValue _mlsMain(); -//│ struct _mls_Lambda_0: public _mls_Callable { -//│ _mlsValue _mls_a; -//│ _mlsValue _mls_b; -//│ constexpr static inline const char *typeName = "Lambda$0"; -//│ constexpr static inline uint32_t typeTag = nextTypeTag(); -//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->_mls_a.print(); std::printf(", "); this->_mls_b.print(); std::printf(")"); } -//│ virtual void destroy() override { _mlsValue::destroy(this->_mls_a); _mlsValue::destroy(this->_mls_b); operator delete (this, std::align_val_t(_mlsAlignment)); } -//│ static _mlsValue create(_mlsValue _mls_a, _mlsValue _mls_b) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) _mls_Lambda_0; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->_mls_a = _mls_a; _mlsVal->_mls_b = _mls_b; return _mlsValue(_mlsVal); } -//│ virtual _mlsValue _mls_apply2(_mlsValue _mls_c, _mlsValue _mls_d) { -//│ _mlsValue _mls_retval; -//│ auto _mls_x_0 = (_mls_a + _mls_b); -//│ auto _mls_x_1 = (_mls_x_0 + _mls_c); -//│ auto _mls_x_2 = (_mls_x_1 + _mls_d); -//│ _mls_retval = _mls_x_2; -//│ return _mls_retval; -//│ } -//│ }; -//│ _mlsValue _mls_add4(_mlsValue _mls_a, _mlsValue _mls_b) { -//│ _mlsValue _mls_retval; -//│ auto _mls_x_3 = _mlsValue::create<_mls_Lambda_0>(_mls_a, _mls_b); -//│ _mls_retval = _mls_x_3; -//│ return _mls_retval; -//│ } -//│ _mlsValue _mlsMain() { -//│ _mlsValue _mls_retval; -//│ auto _mls_x_4 = _mls_add4(_mlsValue::fromIntLit(1), _mlsValue::fromIntLit(2)); -//│ auto _mls_x_5 = _mlsMethodCall<_mls_Callable>(_mls_x_4)->_mls_apply2(_mlsValue::fromIntLit(3), _mlsValue::fromIntLit(4)); -//│ _mls_retval = _mls_x_5; -//│ return _mls_retval; -//│ } -//│ int main() { return _mlsLargeStack(_mlsMainWrapper); } //│ //│ Interpreted: //│ 10 @@ -129,61 +62,22 @@ fun dummy() = add dummy()(1, 2) //│ = 3 //│ LLIR: -//│ class Lambda_add$0() extends Callable { -//│ def apply2(arg$0,arg$1) = -//│ let* (x$1) = add(arg$0,arg$1) in -//│ x$1 +//│ class Lambda_add() extends Callable { +//│ def apply2$438(arg$475,arg$476) = +//│ let* (x$479) = add(arg$475,arg$476) in +//│ x$479 //│ } -//│ def add(a,b) = -//│ let x$0 = +(a,b) in -//│ x$0 -//│ def dummy() = -//│ let x$2 = Lambda_add$0() in -//│ x$2 -//│ let* (x$3) = dummy() in -//│ let x$4 = Callable.apply2(x$3,1,2) in -//│ x$4 +//│ def add$405(a$407,b$408) = +//│ let x$474 = +(a$407,b$408) in +//│ x$474 +//│ def dummy$406() = +//│ let x$480 = Lambda_add$477() in +//│ x$480 +//│ let* (x$481) = dummy() in +//│ let x$482 = Callable.apply2$438(x$481,1,2) in +//│ x$482 //│ //│ Cpp: -//│ #include "mlsprelude.h" -//│ struct _mls_Lambda_add_0; -//│ _mlsValue _mls_add(_mlsValue, _mlsValue); -//│ _mlsValue _mls_dummy(); -//│ _mlsValue _mlsMain(); -//│ struct _mls_Lambda_add_0: public _mls_Callable { -//│ -//│ constexpr static inline const char *typeName = "Lambda_add$0"; -//│ constexpr static inline uint32_t typeTag = nextTypeTag(); -//│ virtual void print() const override { std::printf("%s", typeName); } -//│ virtual void destroy() override { operator delete (this, std::align_val_t(_mlsAlignment)); } -//│ static _mlsValue create() { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) _mls_Lambda_add_0; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; return _mlsValue(_mlsVal); } -//│ virtual _mlsValue _mls_apply2(_mlsValue _mls_arg_0, _mlsValue _mls_arg_1) { -//│ _mlsValue _mls_retval; -//│ auto _mls_x_1 = _mls_add(_mls_arg_0, _mls_arg_1); -//│ _mls_retval = _mls_x_1; -//│ return _mls_retval; -//│ } -//│ }; -//│ _mlsValue _mls_add(_mlsValue _mls_a, _mlsValue _mls_b) { -//│ _mlsValue _mls_retval; -//│ auto _mls_x_0 = (_mls_a + _mls_b); -//│ _mls_retval = _mls_x_0; -//│ return _mls_retval; -//│ } -//│ _mlsValue _mls_dummy() { -//│ _mlsValue _mls_retval; -//│ auto _mls_x_2 = _mlsValue::create<_mls_Lambda_add_0>(); -//│ _mls_retval = _mls_x_2; -//│ return _mls_retval; -//│ } -//│ _mlsValue _mlsMain() { -//│ _mlsValue _mls_retval; -//│ auto _mls_x_3 = _mls_dummy(); -//│ auto _mls_x_4 = _mlsMethodCall<_mls_Callable>(_mls_x_3)->_mls_apply2(_mlsValue::fromIntLit(1), _mlsValue::fromIntLit(2)); -//│ _mls_retval = _mls_x_4; -//│ return _mls_retval; -//│ } -//│ int main() { return _mlsLargeStack(_mlsMainWrapper); } //│ //│ Interpreted: //│ 3 @@ -205,55 +99,55 @@ main() //│ = Cons(4, Cons(5, Nil)) //│ LLIR: //│ class List() -//│ class Cons(head,tail) extends List +//│ class Cons(head$495,tail$496) extends List //│ class Nil() extends List -//│ class Lambda$0() extends Callable { -//│ def apply1(x1) = -//│ let* (x$10) = inc(x1) in -//│ x$10 +//│ class Lambda() extends Callable { +//│ def apply1$577(x$513) = +//│ let* (x$629) = inc(x$513) in +//│ x$629 //│ } -//│ class Lambda_inc$0() extends Callable { -//│ def apply1(arg$0) = -//│ let* (x$16) = inc(arg$0) in -//│ x$16 +//│ class Lambda_inc() extends Callable { +//│ def apply1$577(arg$635) = +//│ let* (x$638) = inc(arg$635) in +//│ x$638 //│ } -//│ def map(f,l) = -//│ case l of -//│ Cons => -//│ let x$0 = l. in -//│ let x$1 = l. in -//│ let x$2 = Callable.apply1(f,x$0) in -//│ let* (x$3) = map(f,x$1) in -//│ let x$4 = Cons(x$2,x$3) in -//│ x$4 +//│ def map$484(f$499,l$500) = +//│ case l$500 of +//│ Cons$492 => +//│ let x$616 = l$500. in +//│ let x$617 = l$500. in +//│ let x$618 = Callable.apply1$577(f$499,x$616) in +//│ let* (x$619) = map(f$499,x$617) in +//│ let x$620 = Cons$492(x$618,x$619) in +//│ x$620 //│ _ => -//│ case l of -//│ Nil => -//│ let x$5 = Nil() in -//│ x$5 +//│ case l$500 of +//│ Nil$497 => +//│ let x$622 = Nil$497() in +//│ x$622 //│ _ => //│ panic "match error" -//│ def j$1() = -//│ jump j$0() -//│ def j$0() = +//│ def j$621() = +//│ jump j$615() +//│ def j$615() = //│ null -//│ def inc(x) = -//│ let x$6 = +(x,1) in -//│ x$6 -//│ def main() = -//│ let x$7 = Nil() in -//│ let x$8 = Cons(2,x$7) in -//│ let x$9 = Cons(1,x$8) in -//│ let x$11 = Lambda$0() in -//│ let* (x$12) = map(x$11,x$9) in -//│ let x$13 = Nil() in -//│ let x$14 = Cons(4,x$13) in -//│ let x$15 = Cons(3,x$14) in -//│ let x$17 = Lambda_inc$0() in -//│ let* (x$18) = map(x$17,x$15) in -//│ x$18 -//│ let* (x$19) = main() in -//│ x$19 +//│ def inc$487(x$509) = +//│ let x$623 = +(x$509,1) in +//│ x$623 +//│ def main$485() = +//│ let x$624 = Nil$497() in +//│ let x$625 = Cons$492(2,x$624) in +//│ let x$626 = Cons$492(1,x$625) in +//│ let x$630 = Lambda$627() in +//│ let* (x$631) = map(x$630,x$626) in +//│ let x$632 = Nil$497() in +//│ let x$633 = Cons$492(4,x$632) in +//│ let x$634 = Cons$492(3,x$633) in +//│ let x$639 = Lambda_inc$636() in +//│ let* (x$640) = map(x$639,x$634) in +//│ x$640 +//│ let* (x$641) = main() in +//│ x$641 //│ //│ Interpreted: //│ Cons(4,Cons(5,Nil())) diff --git a/hkmc2/shared/src/test/mlscript/llir/Legacy.mls b/hkmc2/shared/src/test/mlscript/llir/Legacy.mls index 57e37c4e39..1008b74ef2 100644 --- a/hkmc2/shared/src/test/mlscript/llir/Legacy.mls +++ b/hkmc2/shared/src/test/mlscript/llir/Legacy.mls @@ -255,74 +255,74 @@ main() //│ = 404 //│ LLIR: //│ class Option() -//│ class Some(x) extends Option +//│ class Some(x$1742) extends Option //│ class None() extends Option //│ class Nat() -//│ class S(s) extends Nat +//│ class S(s$1753) extends Nat //│ class O() extends Nat -//│ def fromSome(s) = -//│ case s of -//│ Some => -//│ let x$0 = s. in -//│ x$0 +//│ def fromSome$1725(s$1745) = +//│ case s$1745 of +//│ Some$1739 => +//│ let x$1872 = s$1745. in +//│ x$1872 //│ _ => //│ panic "match error" -//│ def j$0() = +//│ def j$1871() = //│ null -//│ def aaa() = -//│ let x$1 = 1 in -//│ let x$2 = 2 in -//│ let x$3 = 3 in -//│ let x$4 = 4 in -//│ let x$5 = +(x$1,x$2) in -//│ let x$6 = -(x$5,x$3) in -//│ let x$7 = +(x$6,x$4) in -//│ x$7 -//│ def bbb() = -//│ let* (x$8) = aaa() in -//│ let x$9 = *(x$8,100) in -//│ let x$10 = +(x$9,4) in -//│ x$10 -//│ def not(x2) = -//│ case x2 of +//│ def aaa$1730() = +//│ let x$1873 = 1 in +//│ let x$1874 = 2 in +//│ let x$1875 = 3 in +//│ let x$1876 = 4 in +//│ let x$1877 = +(x$1873,x$1874) in +//│ let x$1878 = -(x$1877,x$1875) in +//│ let x$1879 = +(x$1878,x$1876) in +//│ x$1879 +//│ def bbb$1732() = +//│ let* (x$1880) = aaa() in +//│ let x$1881 = *(x$1880,100) in +//│ let x$1882 = +(x$1881,4) in +//│ x$1882 +//│ def not$1728(x$1769) = +//│ case x$1769 of //│ BoolLit(true) => //│ false //│ _ => //│ true -//│ def j$1() = +//│ def j$1883() = //│ null -//│ def foo(x3) = -//│ case x3 of +//│ def foo$1735(x$1771) = +//│ case x$1771 of //│ BoolLit(true) => -//│ let x$11 = None() in -//│ x$11 +//│ let x$1885 = None$1743() in +//│ x$1885 //│ _ => -//│ let* (x$12) = not(x3) in -//│ let* (x$13) = foo(x$12) in -//│ let x$14 = Some(x$13) in -//│ x$14 -//│ def j$2() = +//│ let* (x$1886) = not(x$1771) in +//│ let* (x$1887) = foo(x$1886) in +//│ let x$1888 = Some$1739(x$1887) in +//│ x$1888 +//│ def j$1884() = //│ null -//│ def main() = -//│ let* (x$15) = foo(false) in -//│ case x$15 of -//│ None => -//│ let* (x$16) = aaa() in -//│ x$16 +//│ def main$1726() = +//│ let* (x$1889) = foo(false) in +//│ case x$1889 of +//│ None$1743 => +//│ let* (x$1891) = aaa() in +//│ x$1891 //│ _ => -//│ case x$15 of -//│ Some => -//│ let x$17 = x$15. in -//│ let* (x$18) = bbb() in -//│ x$18 +//│ case x$1889 of +//│ Some$1739 => +//│ let x$1893 = x$1889. in +//│ let* (x$1894) = bbb() in +//│ x$1894 //│ _ => //│ panic "match error" -//│ def j$4() = -//│ jump j$3() -//│ def j$3() = +//│ def j$1892() = +//│ jump j$1890() +//│ def j$1890() = //│ null -//│ let* (x$19) = main() in -//│ x$19 +//│ let* (x$1895) = main() in +//│ x$1895 //│ //│ Interpreted: //│ 404 diff --git a/hkmc2/shared/src/test/mlscript/llir/Method.mls b/hkmc2/shared/src/test/mlscript/llir/Method.mls index 915d63f799..e6415fbbd9 100644 --- a/hkmc2/shared/src/test/mlscript/llir/Method.mls +++ b/hkmc2/shared/src/test/mlscript/llir/Method.mls @@ -12,14 +12,14 @@ fun main() = a.A#f() main() //│ LLIR: -//│ class A(m) { -//│ def f() = -//│ m +//│ class A(m$200) { +//│ def f$195() = +//│ m$200 //│ } -//│ def main() = -//│ let x$0 = A(1) in -//│ let x$1 = A.f(x$0) in -//│ x$1 -//│ let* (x$2) = main() in -//│ x$2 +//│ def main$197() = +//│ let x$264 = A$198(1) in +//│ let x$265 = A.f$195(x$264) in +//│ x$265 +//│ let* (x$266) = main() in +//│ x$266 diff --git a/hkmc2/shared/src/test/mlscript/llir/NofibPrelude.mls b/hkmc2/shared/src/test/mlscript/llir/NofibPrelude.mls index 540684aee6..0bd4b4c5eb 100644 --- a/hkmc2/shared/src/test/mlscript/llir/NofibPrelude.mls +++ b/hkmc2/shared/src/test/mlscript/llir/NofibPrelude.mls @@ -28,11 +28,17 @@ fun ltTup2(t1, t2, lt1, gt1, lt2) = if t1 is [a, b] and t2 is [c, d] and gt1(a, c) then false else lt2(b, d) fun eqTup2(t1, t2) = if t1 is [a, b] and t2 is [c, d] then a == c and b == d +//│ FAILURE: Unexpected compilation error +//│ ═══[COMPILATION ERROR] Unsupported selection by users +//│ Stopped due to an error during the Llir generation fun compose(f, g) = x => f(g(x)) fun snd(x) = if x is [f, s] then s fun fst(x) = if x is [f, s] then f +//│ FAILURE: Unexpected compilation error +//│ ═══[COMPILATION ERROR] Unsupported selection by users +//│ Stopped due to an error during the Llir generation fun until(p, f, i) = if p(i) then i else until(p, f, f(i)) @@ -96,15 +102,12 @@ fun take(n, ls) = if ls is fun splitAt(n, ls) = [take(n, ls), drop(n, ls)] //│ FAILURE: Unexpected compilation error -//│ ═══[COMPILATION ERROR] Name not found: take +//│ ═══[COMPILATION ERROR] Name not found: member:take //│ Stopped due to an error during the Llir generation fun zip(xs, ys) = if xs is x :: xs and ys is y :: ys then [x, y] :: zip(xs, ys) else Nil -//│ FAILURE: Unexpected compilation error -//│ ═══[COMPILATION ERROR] Unsupported value: Arr -//│ Stopped due to an error during the Llir generation fun inList(x, ls) = if ls is h :: t and @@ -114,7 +117,7 @@ fun inList(x, ls) = if ls is fun notElem(x, ls) = not(inList(x, ls)) //│ FAILURE: Unexpected compilation error -//│ ═══[COMPILATION ERROR] Name not found: inList +//│ ═══[COMPILATION ERROR] Name not found: member:inList //│ Stopped due to an error during the Llir generation fun (+:) append(xs, ys) = if xs is @@ -125,7 +128,7 @@ fun concat(ls) = if ls is Nil then Nil x :: xs then append(x, concat(xs)) //│ FAILURE: Unexpected compilation error -//│ ═══[COMPILATION ERROR] Name not found: append +//│ ═══[COMPILATION ERROR] Name not found: member:append //│ Stopped due to an error during the Llir generation fun filter(f, ls) = if ls is @@ -171,7 +174,7 @@ fun foldr(f, z, xs) = if xs is fun foldl1(f, ls) = if ls is x :: xs then foldl(f, x, xs) //│ FAILURE: Unexpected compilation error -//│ ═══[COMPILATION ERROR] Name not found: foldl +//│ ═══[COMPILATION ERROR] Name not found: member:foldl //│ Stopped due to an error during the Llir generation fun foldr1(f, ls) = if ls is @@ -180,7 +183,7 @@ fun foldr1(f, ls) = if ls is fun maximum(xs) = foldl1((x, y) => if x > y then x else y, xs) //│ FAILURE: Unexpected compilation error -//│ ═══[COMPILATION ERROR] Name not found: foldl1 +//│ ═══[COMPILATION ERROR] Name not found: member:foldl1 //│ Stopped due to an error during the Llir generation fun nubBy(eq, ls) = if ls is @@ -202,12 +205,12 @@ fun deleteBy(eq, x, ys) = if ys is fun unionBy(eq, xs, ys) = append(xs, foldl((acc, y) => deleteBy(eq, y, acc), nubBy(eq, ys), xs)) //│ FAILURE: Unexpected compilation error -//│ ═══[COMPILATION ERROR] Name not found: nubBy +//│ ═══[COMPILATION ERROR] Name not found: member:nubBy //│ Stopped due to an error during the Llir generation fun union(xs, ys) = unionBy((x, y) => x == y, xs, ys) //│ FAILURE: Unexpected compilation error -//│ ═══[COMPILATION ERROR] Name not found: unionBy +//│ ═══[COMPILATION ERROR] Name not found: member:unionBy //│ Stopped due to an error during the Llir generation fun atIndex(i, ls) = if ls is @@ -242,9 +245,6 @@ fun unzip(l) = fun zip3(xs, ys, zs) = if xs is x :: xs and ys is y :: ys and zs is z :: zs then [x, y, z] :: zip3(xs, ys, zs) else Nil -//│ FAILURE: Unexpected compilation error -//│ ═══[COMPILATION ERROR] Unsupported value: Arr -//│ Stopped due to an error during the Llir generation fun transpose(xss) = fun lscomp(ls) = if ls is @@ -267,12 +267,12 @@ fun break_(p, ls) = if ls is p(x) then [Nil, x :: xs] break_(p, xs) is [ys, zs] then [x :: ys, zs] //│ FAILURE: Unexpected compilation error -//│ ═══[COMPILATION ERROR] Unsupported value: Arr +//│ ═══[COMPILATION ERROR] Unsupported selection by users //│ Stopped due to an error during the Llir generation fun flatMap(f, ls) = if ls is Nil then Nil h :: t then append(f(h), flatMap(f, t)) //│ FAILURE: Unexpected compilation error -//│ ═══[COMPILATION ERROR] Name not found: append +//│ ═══[COMPILATION ERROR] Name not found: member:append //│ Stopped due to an error during the Llir generation diff --git a/hkmc2/shared/src/test/mlscript/llir/Tuple.mls b/hkmc2/shared/src/test/mlscript/llir/Tuple.mls new file mode 100644 index 0000000000..0463e91561 --- /dev/null +++ b/hkmc2/shared/src/test/mlscript/llir/Tuple.mls @@ -0,0 +1,21 @@ +:js +:llir +:cpp + +:global + +:intl +:sllir +fun mkTup(x, y) = [x, y] +mkTup(1, 2) +//│ = [1, 2] +//│ LLIR: +//│ +//│ def mkTup$249(x$250,y$251) = +//│ let x$310 = Tuple2$294(x$250,y$251) in +//│ x$310 +//│ let* (x$311) = mkTup(1,2) in +//│ x$311 +//│ +//│ Interpreted: +//│ Tuple2(1,2) diff --git a/hkmc2DiffTests/src/test/scala/hkmc2/LlirDiffMaker.scala b/hkmc2DiffTests/src/test/scala/hkmc2/LlirDiffMaker.scala index 86e0debd09..bc6fa5180d 100644 --- a/hkmc2DiffTests/src/test/scala/hkmc2/LlirDiffMaker.scala +++ b/hkmc2DiffTests/src/test/scala/hkmc2/LlirDiffMaker.scala @@ -12,9 +12,7 @@ import codegen.cpp.* import hkmc2.syntax.Tree.Ident import hkmc2.codegen.Path import hkmc2.semantics.Term.Blk -import hkmc2.codegen.llir.Fresh import hkmc2.utils.Scope -import hkmc2.codegen.llir.Ctx import hkmc2.codegen.llir._ import hkmc2.semantics.Elaborator @@ -34,7 +32,7 @@ abstract class LlirDiffMaker extends BbmlDiffMaker: given Elaborator.Ctx = curCtx - var preludeBlock: Opt[Block] = None + var freshId = FreshInt() override def processTerm(trm: Blk, inImport: Bool)(using Raise): Unit = super.processTerm(trm, inImport) @@ -42,36 +40,31 @@ abstract class LlirDiffMaker extends BbmlDiffMaker: val low = ltl.givenIn: codegen.Lowering(lowerHandlers = false, stackLimit = None) var le = low.program(trm) - if lprelude.isSet then - preludeBlock = Some(le.main) given Scope = Scope.empty - val fresh = Fresh() - val fuid = FreshInt() - val cuid = FreshInt() - val llb = LlirBuilder(tl)(fresh, fuid, cuid) + val llb = LlirBuilder(tl, freshId) try val llirProg = llb.bProg(le) if sllir.isSet then output("LLIR:") output(llirProg.show()) if cpp.isSet || scpp.isSet || rcpp.isSet || wcpp.isSet then - val cpp = codegen.cpp.CppCodeGen.codegen(llirProg) + // val cpp = codegen.cpp.CppCodeGen.codegen(llirProg) if scpp.isSet then output("\nCpp:") - output(cpp.toDocument.toString) + // output(cpp.toDocument.toString) val auxPath = os.Path(rootPath) / "hkmc2"/"shared"/"src"/"test"/"mlscript-compile"/"cpp" if wcpp.isSet then - printToFile(java.io.File((auxPath / s"${wcpp.get.get}.cpp").toString)): - p => p.println(cpp.toDocument.toString) + // printToFile(java.io.File((auxPath / s"${wcpp.get.get}.cpp").toString)): + // p => p.println(cpp.toDocument.toString) if rcpp.isSet then val cppHost = CppCompilerHost(auxPath.toString, output.apply) if !cppHost.ready then output("\nCpp Compilation Failed: Cpp compiler or GNU Make not found") else output("\n") - cppHost.compileAndRun(cpp.toDocument.toString) + // cppHost.compileAndRun(cpp.toDocument.toString) if intl.isSet then - val intr = codegen.llir.Interpreter(verbose = true) + val intr = codegen.llir.Interpreter(tl) output("\nInterpreted:") output(intr.interpret(llirProg)) catch From e65a51db81fb67401745926f586316df1f6a32f8 Mon Sep 17 00:00:00 2001 From: waterlens Date: Tue, 18 Feb 2025 21:48:53 +0800 Subject: [PATCH 36/88] get cpp codegen back --- .../scala/hkmc2/codegen/cpp/CodeGen.scala | 283 +++++++ .../scala/hkmc2/codegen/llir/Builder.scala | 24 +- .../src/test/mlscript/llir/BasicCpp.mls | 174 +++++ .../shared/src/test/mlscript/llir/Classes.mls | 20 +- .../src/test/mlscript/llir/ControlFlow.mls | 733 ++++++++++++++---- hkmc2/shared/src/test/mlscript/llir/Ctor.mls | 26 +- .../src/test/mlscript/llir/HigherOrder.mls | 632 +++++++++++++-- .../shared/src/test/mlscript/llir/Legacy.mls | 100 +-- .../shared/src/test/mlscript/llir/Method.mls | 10 +- hkmc2/shared/src/test/mlscript/llir/Tuple.mls | 10 +- .../src/test/scala/hkmc2/LlirDiffMaker.scala | 13 +- 11 files changed, 1715 insertions(+), 310 deletions(-) create mode 100644 hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/CodeGen.scala diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/CodeGen.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/CodeGen.scala new file mode 100644 index 0000000000..1605e31da2 --- /dev/null +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/CodeGen.scala @@ -0,0 +1,283 @@ +package hkmc2.codegen.cpp + +import mlscript.utils._ +import mlscript.utils.shorthands._ +import scala.collection.mutable.ListBuffer + +import hkmc2.codegen.llir.{Expr => IExpr, _} +import hkmc2.codegen.cpp._ +import hkmc2.codegen.Local +import hkmc2.utils.{Scope, TraceLogger} +import hkmc2.Raise +import hkmc2.semantics.BuiltinSymbol + +class CppCodeGen(tl: TraceLogger): + import tl.{trace, log, logs} + def mapName(name: Str): Str = "_mls_" + name.replace('$', '_').replace('\'', '_') + val mlsValType = Type.Prim("_mlsValue") + val mlsUnitValue = Expr.Call(Expr.Var("_mlsValue::create<_mls_Unit>"), Ls()); + val mlsRetValue = "_mls_retval" + val mlsRetValueDecl = Decl.VarDecl(mlsRetValue, mlsValType) + val mlsMainName = "_mlsMain" + val mlsPrelude = "#include \"mlsprelude.h\"" + val mlsPreludeImpl = "#include \"mlsprelude.cpp\"" + def mlsIsInternalClass(sym: Local) = + sym.nme.startsWith("Callable") + val mlsObject = "_mlsObject" + val mlsBuiltin = "builtin" + val mlsEntryPoint = s"int main() { return _mlsLargeStack(_mlsMainWrapper); }"; + def mlsIntLit(x: BigInt) = Expr.Call(Expr.Var("_mlsValue::fromIntLit"), Ls(Expr.IntLit(x))) + def mlsStrLit(x: Str) = Expr.Call(Expr.Var("_mlsValue::fromStrLit"), Ls(Expr.StrLit(x))) + def mlsCharLit(x: Char) = Expr.Call(Expr.Var("_mlsValue::fromIntLit"), Ls(Expr.CharLit(x))) + def mlsNewValue(cls: Str, args: Ls[Expr]) = Expr.Call(Expr.Var(s"_mlsValue::create<$cls>"), args) + def mlsIsValueOf(cls: Str, scrut: Expr) = Expr.Call(Expr.Var(s"_mlsValue::isValueOf<$cls>"), Ls(scrut)) + def mlsIsBoolLit(scrut: Expr, lit: hkmc2.syntax.Tree.BoolLit) = Expr.Call(Expr.Var("_mlsValue::isIntLit"), Ls(scrut, Expr.IntLit(if lit.value then 1 else 0))) + def mlsIsIntLit(scrut: Expr, lit: hkmc2.syntax.Tree.IntLit) = Expr.Call(Expr.Var("_mlsValue::isIntLit"), Ls(scrut, Expr.IntLit(lit.value))) + def mlsDebugPrint(x: Expr) = Expr.Call(Expr.Var("_mlsValue::print"), Ls(x)) + def mlsTupleValue(init: Expr) = Expr.Constructor("_mlsValue::tuple", init) + def mlsAs(name: Str, cls: Str) = Expr.Var(s"_mlsValue::as<$cls>($name)") + def mlsAsUnchecked(name: Str, cls: Str) = Expr.Var(s"_mlsValue::cast<$cls>($name)") + def mlsObjectNameMethod(name: Str) = s"constexpr static inline const char *typeName = \"${name}\";" + def mlsTypeTag() = s"constexpr static inline uint32_t typeTag = nextTypeTag();" + def mlsTypeTag(n: Int) = s"constexpr static inline uint32_t typeTag = $n;" + def mlsCommonCreateMethod(cls: Str, fields: Ls[Str], id: Int) = + val parameters = fields.map{x => s"_mlsValue $x"}.mkString(", ") + val fieldsAssignment = fields.map{x => s"_mlsVal->$x = $x; "}.mkString + s"static _mlsValue create($parameters) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) $cls; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; $fieldsAssignment return _mlsValue(_mlsVal); }" + def mlsCommonPrintMethod(fields: Ls[Str]) = + if fields.isEmpty then s"virtual void print() const override { std::printf(\"%s\", typeName); }" + else + val fieldsPrint = fields.map{x => s"this->$x.print(); "}.mkString("std::printf(\", \"); ") + s"virtual void print() const override { std::printf(\"%s\", typeName); std::printf(\"(\"); $fieldsPrint std::printf(\")\"); }" + def mlsCommonDestructorMethod(cls: Str, fields: Ls[Str]) = + val fieldsDeletion = fields.map{x => s"_mlsValue::destroy(this->$x); "}.mkString + s"virtual void destroy() override { $fieldsDeletion operator delete (this, std::align_val_t(_mlsAlignment)); }" + def mlsThrowNonExhaustiveMatch = Stmt.Raw("_mlsNonExhaustiveMatch();"); + def mlsCall(fn: Str, args: Ls[Expr]) = Expr.Call(Expr.Var("_mlsCall"), Expr.Var(fn) :: args) + def mlsMethodCall(cls: Local, method: Str, args: Ls[Expr])(using Raise, Scope) = + Expr.Call(Expr.Member(Expr.Call(Expr.Var(s"_mlsMethodCall<${cls.nme}>"), Ls(args.head)), method), args.tail) + def mlsFnWrapperName(fn: Str) = s"_mlsFn_$fn" + def mlsFnCreateMethod(fn: Str) = s"static _mlsValue create() { static _mlsFn_$fn mlsFn alignas(_mlsAlignment); mlsFn.refCount = stickyRefCount; mlsFn.tag = typeTag; return _mlsValue(&mlsFn); }" + def mlsNeverValue(n: Int) = if (n <= 1) then Expr.Call(Expr.Var(s"_mlsValue::never"), Ls()) else Expr.Call(Expr.Var(s"_mlsValue::never<$n>"), Ls()) + + case class Ctx( + defnCtx: Set[Local], + ) + + def getVar(l: Local)(using Raise, Scope): String = l match + case ts: hkmc2.semantics.TermSymbol => + ts.owner match + case S(owner) => summon[Scope].lookup_!(ts) + case N => summon[Scope].lookup_!(ts) + case ts: hkmc2.semantics.InnerSymbol => + if ts.asMod.isDefined + then + summon[Scope].lookup_!(ts) + else summon[Scope].findThis_!(ts) + case _ => summon[Scope].lookup_!(l) + + def allocIfNew(l: Local)(using Raise, Scope): String = + if summon[Scope].lookup(l).isDefined then + getVar(l) + else + summon[Scope].allocateName(l) + + def codegenClassInfo(using Ctx, Raise, Scope)(cls: ClassInfo): (Opt[Def], Decl) = + val fields = cls.fields.map{x => (x |> allocIfNew, mlsValType)} + val parents = if cls.parents.nonEmpty then cls.parents.toList.map(_.nme) else mlsObject :: Nil + val decl = Decl.StructDecl(cls.name.nme) + if mlsIsInternalClass(cls.name) then return (None, decl) + val theDef = Def.StructDef( + cls.name |> allocIfNew, fields, + if parents.nonEmpty then Some(parents) else None, + Ls(Def.RawDef(mlsObjectNameMethod(cls.name.nme)), + Def.RawDef(mlsTypeTag()), + Def.RawDef(mlsCommonPrintMethod(cls.fields.map(_.nme))), + Def.RawDef(mlsCommonDestructorMethod(cls.name.nme, cls.fields.map(_.nme))), + Def.RawDef(mlsCommonCreateMethod(cls.name.nme, cls.fields.map(_.nme), cls.id))) + ++ cls.methods.map{case (name, defn) => { + val (theDef, decl) = codegenDefn(using Ctx(summon[Ctx].defnCtx + cls.name))(defn) + theDef match + case x @ Def.FuncDef(_, name, _, _, _, _) => x.copy(virt = true) + case _ => theDef + }} + ) + (S(theDef), decl) + + def toExpr(texpr: TrivialExpr, reifyUnit: Bool = false)(using Ctx, Raise, Scope): Opt[Expr] = texpr match + case IExpr.Ref(name) => S(Expr.Var(name |> allocIfNew)) + case IExpr.Literal(hkmc2.syntax.Tree.BoolLit(x)) => S(mlsIntLit(if x then 1 else 0)) + case IExpr.Literal(hkmc2.syntax.Tree.IntLit(x)) => S(mlsIntLit(x)) + case IExpr.Literal(hkmc2.syntax.Tree.DecLit(x)) => S(mlsIntLit(x.toBigInt)) + case IExpr.Literal(hkmc2.syntax.Tree.StrLit(x)) => S(mlsStrLit(x)) + case IExpr.Literal(hkmc2.syntax.Tree.UnitLit(_)) => if reifyUnit then S(mlsUnitValue) else None + + def toExpr(texpr: TrivialExpr)(using Ctx, Raise, Scope): Expr = texpr match + case IExpr.Ref(name) => Expr.Var(name |> allocIfNew) + case IExpr.Literal(hkmc2.syntax.Tree.BoolLit(x)) => mlsIntLit(if x then 1 else 0) + case IExpr.Literal(hkmc2.syntax.Tree.IntLit(x)) => mlsIntLit(x) + case IExpr.Literal(hkmc2.syntax.Tree.DecLit(x)) => mlsIntLit(x.toBigInt) + case IExpr.Literal(hkmc2.syntax.Tree.StrLit(x)) => mlsStrLit(x) + case IExpr.Literal(hkmc2.syntax.Tree.UnitLit(_)) => mlsUnitValue + + + def wrapMultiValues(exprs: Ls[TrivialExpr])(using Ctx, Raise, Scope): Expr = exprs match + case x :: Nil => toExpr(x, reifyUnit = true).get + case _ => + val init = Expr.Initializer(exprs.map{x => toExpr(x)}) + mlsTupleValue(init) + + def codegenCaseWithIfs(scrut: TrivialExpr, cases: Ls[(Pat, Node)], default: Opt[Node], storeInto: Str)(using decls: Ls[Decl], stmts: Ls[Stmt])(using Ctx, Raise, Scope): (Ls[Decl], Ls[Stmt]) = + val scrut2 = toExpr(scrut) + val init: Stmt = + default.fold(mlsThrowNonExhaustiveMatch)(x => { + val (decls2, stmts2) = codegen(x, storeInto)(using Ls.empty, Ls.empty[Stmt]) + Stmt.Block(decls2, stmts2) + }) + val stmt = cases.foldRight(S(init)) { + case ((Pat.Class(cls), arm), nextarm) => + val (decls2, stmts2) = codegen(arm, storeInto)(using Ls.empty, Ls.empty[Stmt]) + val stmt = Stmt.If(mlsIsValueOf(cls.nme, scrut2), Stmt.Block(decls2, stmts2), nextarm) + S(stmt) + case ((Pat.Lit(i @ hkmc2.syntax.Tree.IntLit(_)), arm), nextarm) => + val (decls2, stmts2) = codegen(arm, storeInto)(using Ls.empty, Ls.empty[Stmt]) + val stmt = Stmt.If(mlsIsIntLit(scrut2, i), Stmt.Block(decls2, stmts2), nextarm) + S(stmt) + case ((Pat.Lit(i @ hkmc2.syntax.Tree.BoolLit(_)), arm), nextarm) => + val (decls2, stmts2) = codegen(arm, storeInto)(using Ls.empty, Ls.empty[Stmt]) + val stmt = Stmt.If(mlsIsBoolLit(scrut2, i), Stmt.Block(decls2, stmts2), nextarm) + S(stmt) + case _ => TODO("codegenCaseWithIfs don't support these patterns currently") + } + (decls, stmt.fold(stmts)(x => stmts :+ x)) + + def codegenJumpWithCall(func: Local, args: Ls[TrivialExpr], storeInto: Opt[Str])(using decls: Ls[Decl], stmts: Ls[Stmt])(using Ctx, Raise, Scope): (Ls[Decl], Ls[Stmt]) = + val call = Expr.Call(Expr.Var(func |> allocIfNew), args.map(toExpr)) + val stmts2 = stmts ++ Ls(storeInto.fold(Stmt.Return(call))(x => Stmt.Assign(x, call))) + (decls, stmts2) + + def codegenOps(op: Local, args: Ls[TrivialExpr])(using Ctx, Raise, Scope) = + val op2 = op.nme + op2 match + case "+" => Expr.Binary("+", toExpr(args(0)), toExpr(args(1))) + case "-" => Expr.Binary("-", toExpr(args(0)), toExpr(args(1))) + case "*" => Expr.Binary("*", toExpr(args(0)), toExpr(args(1))) + case "/" => Expr.Binary("/", toExpr(args(0)), toExpr(args(1))) + case "%" => Expr.Binary("%", toExpr(args(0)), toExpr(args(1))) + case "==" => Expr.Binary("==", toExpr(args(0)), toExpr(args(1))) + case "!=" => Expr.Binary("!=", toExpr(args(0)), toExpr(args(1))) + case "<" => Expr.Binary("<", toExpr(args(0)), toExpr(args(1))) + case "<=" => Expr.Binary("<=", toExpr(args(0)), toExpr(args(1))) + case ">" => Expr.Binary(">", toExpr(args(0)), toExpr(args(1))) + case ">=" => Expr.Binary(">=", toExpr(args(0)), toExpr(args(1))) + case "&&" => Expr.Binary("&&", toExpr(args(0)), toExpr(args(1))) + case "||" => Expr.Binary("||", toExpr(args(0)), toExpr(args(1))) + case "!" => Expr.Unary("!", toExpr(args(0))) + case _ => TODO("codegenOps") + + + def codegen(expr: IExpr)(using Ctx, Raise, Scope): Expr = expr match + case x @ (IExpr.Ref(_) | IExpr.Literal(_)) => toExpr(x, reifyUnit = true).get + case IExpr.CtorApp(cls, args) => mlsNewValue(cls.nme, args.map(toExpr)) + case IExpr.Select(name, cls, field) => Expr.Member(mlsAsUnchecked(name |> allocIfNew, cls.nme), field) + case IExpr.BasicOp(name, args) => codegenOps(name, args) + case IExpr.AssignField(assignee, cls, field, value) => TODO("codegen assign field") + + def codegenBuiltin(names: Ls[Local], builtin: Str, args: Ls[TrivialExpr])(using Ctx, Raise, Scope): Ls[Stmt] = builtin match + case "error" => Ls(Stmt.Raw("throw std::runtime_error(\"Error\");"), Stmt.AutoBind(names.map(allocIfNew), mlsNeverValue(names.size))) + case _ => Ls(Stmt.AutoBind(names.map(allocIfNew), Expr.Call(Expr.Var("_mls_builtin_" + builtin), args.map(toExpr)))) + + lazy val builtinApply = Set( + "apply0", + "apply1", + "apply2", + "apply3", + "apply4", + "apply5", + "apply6", + "apply7", + "apply8", + "apply9", + ) + + def codegen(body: Node, storeInto: Str)(using decls: Ls[Decl], stmts: Ls[Stmt])(using Ctx, Raise, Scope): (Ls[Decl], Ls[Stmt]) = body match + case Node.Result(res) => + val expr = wrapMultiValues(res) + val stmts2 = stmts ++ Ls(Stmt.Assign(storeInto, expr)) + (decls, stmts2) + case Node.Jump(defn, args) => + codegenJumpWithCall(defn, args, S(storeInto)) + case Node.Panic(msg) => (decls, stmts :+ Stmt.Raw(s"throw std::runtime_error(\"$msg\");")) + case Node.LetExpr(name, expr, body) => + val stmts2 = stmts ++ Ls(Stmt.AutoBind(Ls(name |> allocIfNew), codegen(expr))) + codegen(body, storeInto)(using decls, stmts2) + case Node.LetMethodCall(names, cls, method, IExpr.Ref(bin: BuiltinSymbol) :: args, body) if bin.nme == "builtin" => + val stmts2 = stmts ++ codegenBuiltin(names, args.head.toString.replace("\"", ""), args.tail) + codegen(body, storeInto)(using decls, stmts2) + case Node.LetMethodCall(names, cls, method, args, body) if builtinApply.contains(method.nme) => + val call = mlsMethodCall(cls, method.nme, args.map(toExpr)) + val stmts2 = stmts ++ Ls(Stmt.AutoBind(names.map(allocIfNew), call)) + codegen(body, storeInto)(using decls, stmts2) + case Node.LetMethodCall(names, cls, method, args, body) => + val call = mlsMethodCall(cls, method |> allocIfNew, args.map(toExpr)) + val stmts2 = stmts ++ Ls(Stmt.AutoBind(names.map(allocIfNew), call)) + codegen(body, storeInto)(using decls, stmts2) + case Node.LetCall(names, defn, args, body) => + val call = Expr.Call(Expr.Var(defn |> allocIfNew), args.map(toExpr)) + val stmts2 = stmts ++ Ls(Stmt.AutoBind(names.map(allocIfNew), call)) + codegen(body, storeInto)(using decls, stmts2) + case Node.Case(scrut, cases, default) => + codegenCaseWithIfs(scrut, cases, default, storeInto) + + def codegenDefn(using Ctx, Raise, Scope)(defn: Func): (Def, Decl) = defn match + case Func(id, name, params, resultNum, body) => + val decls = Ls(mlsRetValueDecl) + val stmts = Ls.empty[Stmt] + val (decls2, stmts2) = codegen(body, mlsRetValue)(using decls, stmts) + val stmtsWithReturn = stmts2 :+ Stmt.Return(Expr.Var(mlsRetValue)) + val theDef = Def.FuncDef(mlsValType, name |> allocIfNew, params.map(x => (x |> allocIfNew, mlsValType)), Stmt.Block(decls2, stmtsWithReturn)) + val decl = Decl.FuncDecl(mlsValType, name |> allocIfNew, params.map(x => mlsValType)) + (theDef, decl) + + def codegenTopNode(node: Node)(using Ctx, Raise, Scope): (Def, Decl) = + val decls = Ls(mlsRetValueDecl) + val stmts = Ls.empty[Stmt] + val (decls2, stmts2) = codegen(node, mlsRetValue)(using decls, stmts) + val stmtsWithReturn = stmts2 :+ Stmt.Return(Expr.Var(mlsRetValue)) + val theDef = Def.FuncDef(mlsValType, mlsMainName, Ls(), Stmt.Block(decls2, stmtsWithReturn)) + val decl = Decl.FuncDecl(mlsValType, mlsMainName, Ls()) + (theDef, decl) + + // Topological sort of classes based on inheritance relationships + def sortClasses(builtinSymbols: Set[Local], prog: Program): Ls[ClassInfo] = + val builtinClasses = Set("Callable") + var depgraph = prog.classes.map(x => (x.name.nme, x.parents.map(_.nme))).toMap + ++ builtinClasses.map(x => (x, Set.empty[String])) + var degree = depgraph.view.mapValues(_.size).toMap + def removeNode(node: String) = + degree -= node + depgraph -= node + depgraph = depgraph.view.mapValues(_.filter(_ != node)).toMap + degree = depgraph.view.mapValues(_.size).toMap + val sorted = ListBuffer.empty[ClassInfo] + var work = degree.filter(_._2 == 0).keys.toSet + while work.nonEmpty do + val node = work.head + work -= node + prog.classes.find(_.name.nme == node).fold(())(sorted.addOne) + removeNode(node) + val next = degree.filter(_._2 == 0).keys + work ++= next + if depgraph.nonEmpty then + val cycle = depgraph.keys.mkString(", ") + throw new Exception(s"Cycle detected in class hierarchy: $cycle") + sorted.toList + + def codegen(builtinSymbols: Set[Local], prog: Program)(using Raise, Scope): CompilationUnit = + val sortedClasses = sortClasses(builtinSymbols, prog) + val defnCtx = prog.defs.map(_.name) + val (defs, decls) = sortedClasses.map(codegenClassInfo(using Ctx(defnCtx))).unzip + val (defs2, decls2) = prog.defs.map(codegenDefn(using Ctx(defnCtx))).unzip + val (defMain, declMain) = codegenTopNode(prog.main)(using Ctx(defnCtx)) + CompilationUnit(Ls(mlsPrelude), decls ++ decls2 :+ declMain, defs.flatten ++ defs2 :+ defMain :+ Def.RawDef(mlsEntryPoint)) + diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala index b8d765ba91..842687e352 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala @@ -101,6 +101,7 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger, uid: FreshInt): private def newClassSym(len: Int) = ClassSymbol(Tree.TypeDef(hkmc2.syntax.Cls, Tree.Empty(), N, N), Tree.Ident(s"Tuple$len")) private def newMemSym(name: Str) = TermSymbol(hkmc2.syntax.ImmutVal, None, Tree.Ident(name)) + private def newMethodSym(name: Str) = TermSymbol(hkmc2.syntax.Fun, None, Tree.Ident(name)) private val builtinField: Map[Int, Local] = Map( 0 -> newMemSym("field0"), @@ -117,18 +118,18 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger, uid: FreshInt): private val builtinCallable: Local = newLambdaSym("Callable") private val builtinApply: Map[Int, Local] = Map( - 0 -> newLambdaSym("apply0"), - 1 -> newLambdaSym("apply1"), - 2 -> newLambdaSym("apply2"), - 3 -> newLambdaSym("apply3"), - 4 -> newLambdaSym("apply4"), - 5 -> newLambdaSym("apply5"), - 6 -> newLambdaSym("apply6"), - 7 -> newLambdaSym("apply7"), - 8 -> newLambdaSym("apply8"), - 9 -> newLambdaSym("apply9"), + 0 -> newMethodSym("apply0"), + 1 -> newMethodSym("apply1"), + 2 -> newMethodSym("apply2"), + 3 -> newMethodSym("apply3"), + 4 -> newMethodSym("apply4"), + 5 -> newMethodSym("apply5"), + 6 -> newMethodSym("apply6"), + 7 -> newMethodSym("apply7"), + 8 -> newMethodSym("apply8"), + 9 -> newMethodSym("apply9"), ) - private val builtinTuple: Map[Int, Local] = + private val builtinTuple: Map[Int, Local] = Map( 0 -> newClassSym(0), 1 -> newClassSym(1), @@ -141,6 +142,7 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger, uid: FreshInt): 8 -> newClassSym(8), 9 -> newClassSym(9), ) + val builtinSymbols = Set(builtinCallable) private def bBind(name: Opt[Local], e: Result, body: Block)(k: TrivialExpr => Ctx ?=> Node)(ct: Block)(using ctx: Ctx)(using Raise, Scope): Node = trace[Node](s"bBind begin: $name", x => s"bBind end: ${x.show}"): diff --git a/hkmc2/shared/src/test/mlscript/llir/BasicCpp.mls b/hkmc2/shared/src/test/mlscript/llir/BasicCpp.mls index 823d319b3c..ce9cdbfec5 100644 --- a/hkmc2/shared/src/test/mlscript/llir/BasicCpp.mls +++ b/hkmc2/shared/src/test/mlscript/llir/BasicCpp.mls @@ -5,12 +5,186 @@ :scpp +:sllir fun foo(a) = let x if a > 0 do x = 1 x + 1 +//│ LLIR: +//│ +//│ def foo$195(a$196) = +//│ let x$245 = null in +//│ let x$246 = >(a$196,0) in +//│ case x$246 of +//│ BoolLit(true) => +//│ let x$248 = 1 in +//│ let x$249 = undefined in +//│ jump j$247(x$248) +//│ _ => +//│ let x$250 = undefined in +//│ jump j$247(x$245) +//│ def j$247(x$197) = +//│ let x$251 = +(x$197,1) in +//│ x$251 +//│ undefined //│ //│ Cpp: +//│ #include "mlsprelude.h" +//│ struct Tuple4; +//│ struct Tuple3; +//│ struct Tuple2; +//│ struct Tuple8; +//│ struct Tuple0; +//│ struct Tuple1; +//│ struct Tuple7; +//│ struct Tuple6; +//│ struct Tuple9; +//│ struct Tuple5; +//│ _mlsValue j(_mlsValue); +//│ _mlsValue foo(_mlsValue); +//│ _mlsValue _mlsMain(); +//│ struct Tuple4: public _mlsObject { +//│ _mlsValue field0; +//│ _mlsValue field1; +//│ _mlsValue field2; +//│ _mlsValue field3; +//│ constexpr static inline const char *typeName = "Tuple4"; +//│ constexpr static inline uint32_t typeTag = nextTypeTag(); +//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(", "); this->field1.print(); std::printf(", "); this->field2.print(); std::printf(", "); this->field3.print(); std::printf(")"); } +//│ virtual void destroy() override { _mlsValue::destroy(this->field0); _mlsValue::destroy(this->field1); _mlsValue::destroy(this->field2); _mlsValue::destroy(this->field3); operator delete (this, std::align_val_t(_mlsAlignment)); } +//│ static _mlsValue create(_mlsValue field0, _mlsValue field1, _mlsValue field2, _mlsValue field3) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple4; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; _mlsVal->field1 = field1; _mlsVal->field2 = field2; _mlsVal->field3 = field3; return _mlsValue(_mlsVal); } +//│ }; +//│ struct Tuple3: public _mlsObject { +//│ _mlsValue field0; +//│ _mlsValue field1; +//│ _mlsValue field2; +//│ constexpr static inline const char *typeName = "Tuple3"; +//│ constexpr static inline uint32_t typeTag = nextTypeTag(); +//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(", "); this->field1.print(); std::printf(", "); this->field2.print(); std::printf(")"); } +//│ virtual void destroy() override { _mlsValue::destroy(this->field0); _mlsValue::destroy(this->field1); _mlsValue::destroy(this->field2); operator delete (this, std::align_val_t(_mlsAlignment)); } +//│ static _mlsValue create(_mlsValue field0, _mlsValue field1, _mlsValue field2) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple3; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; _mlsVal->field1 = field1; _mlsVal->field2 = field2; return _mlsValue(_mlsVal); } +//│ }; +//│ struct Tuple2: public _mlsObject { +//│ _mlsValue field0; +//│ _mlsValue field1; +//│ constexpr static inline const char *typeName = "Tuple2"; +//│ constexpr static inline uint32_t typeTag = nextTypeTag(); +//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(", "); this->field1.print(); std::printf(")"); } +//│ virtual void destroy() override { _mlsValue::destroy(this->field0); _mlsValue::destroy(this->field1); operator delete (this, std::align_val_t(_mlsAlignment)); } +//│ static _mlsValue create(_mlsValue field0, _mlsValue field1) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple2; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; _mlsVal->field1 = field1; return _mlsValue(_mlsVal); } +//│ }; +//│ struct Tuple8: public _mlsObject { +//│ _mlsValue field0; +//│ _mlsValue field1; +//│ _mlsValue field2; +//│ _mlsValue field3; +//│ _mlsValue field4; +//│ _mlsValue field5; +//│ _mlsValue field6; +//│ _mlsValue field7; +//│ constexpr static inline const char *typeName = "Tuple8"; +//│ constexpr static inline uint32_t typeTag = nextTypeTag(); +//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(", "); this->field1.print(); std::printf(", "); this->field2.print(); std::printf(", "); this->field3.print(); std::printf(", "); this->field4.print(); std::printf(", "); this->field5.print(); std::printf(", "); this->field6.print(); std::printf(", "); this->field7.print(); std::printf(")"); } +//│ virtual void destroy() override { _mlsValue::destroy(this->field0); _mlsValue::destroy(this->field1); _mlsValue::destroy(this->field2); _mlsValue::destroy(this->field3); _mlsValue::destroy(this->field4); _mlsValue::destroy(this->field5); _mlsValue::destroy(this->field6); _mlsValue::destroy(this->field7); operator delete (this, std::align_val_t(_mlsAlignment)); } +//│ static _mlsValue create(_mlsValue field0, _mlsValue field1, _mlsValue field2, _mlsValue field3, _mlsValue field4, _mlsValue field5, _mlsValue field6, _mlsValue field7) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple8; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; _mlsVal->field1 = field1; _mlsVal->field2 = field2; _mlsVal->field3 = field3; _mlsVal->field4 = field4; _mlsVal->field5 = field5; _mlsVal->field6 = field6; _mlsVal->field7 = field7; return _mlsValue(_mlsVal); } +//│ }; +//│ struct Tuple0: public _mlsObject { +//│ +//│ constexpr static inline const char *typeName = "Tuple0"; +//│ constexpr static inline uint32_t typeTag = nextTypeTag(); +//│ virtual void print() const override { std::printf("%s", typeName); } +//│ virtual void destroy() override { operator delete (this, std::align_val_t(_mlsAlignment)); } +//│ static _mlsValue create() { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple0; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; return _mlsValue(_mlsVal); } +//│ }; +//│ struct Tuple1: public _mlsObject { +//│ _mlsValue field0; +//│ constexpr static inline const char *typeName = "Tuple1"; +//│ constexpr static inline uint32_t typeTag = nextTypeTag(); +//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(")"); } +//│ virtual void destroy() override { _mlsValue::destroy(this->field0); operator delete (this, std::align_val_t(_mlsAlignment)); } +//│ static _mlsValue create(_mlsValue field0) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple1; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; return _mlsValue(_mlsVal); } +//│ }; +//│ struct Tuple7: public _mlsObject { +//│ _mlsValue field0; +//│ _mlsValue field1; +//│ _mlsValue field2; +//│ _mlsValue field3; +//│ _mlsValue field4; +//│ _mlsValue field5; +//│ _mlsValue field6; +//│ constexpr static inline const char *typeName = "Tuple7"; +//│ constexpr static inline uint32_t typeTag = nextTypeTag(); +//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(", "); this->field1.print(); std::printf(", "); this->field2.print(); std::printf(", "); this->field3.print(); std::printf(", "); this->field4.print(); std::printf(", "); this->field5.print(); std::printf(", "); this->field6.print(); std::printf(")"); } +//│ virtual void destroy() override { _mlsValue::destroy(this->field0); _mlsValue::destroy(this->field1); _mlsValue::destroy(this->field2); _mlsValue::destroy(this->field3); _mlsValue::destroy(this->field4); _mlsValue::destroy(this->field5); _mlsValue::destroy(this->field6); operator delete (this, std::align_val_t(_mlsAlignment)); } +//│ static _mlsValue create(_mlsValue field0, _mlsValue field1, _mlsValue field2, _mlsValue field3, _mlsValue field4, _mlsValue field5, _mlsValue field6) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple7; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; _mlsVal->field1 = field1; _mlsVal->field2 = field2; _mlsVal->field3 = field3; _mlsVal->field4 = field4; _mlsVal->field5 = field5; _mlsVal->field6 = field6; return _mlsValue(_mlsVal); } +//│ }; +//│ struct Tuple6: public _mlsObject { +//│ _mlsValue field0; +//│ _mlsValue field1; +//│ _mlsValue field2; +//│ _mlsValue field3; +//│ _mlsValue field4; +//│ _mlsValue field5; +//│ constexpr static inline const char *typeName = "Tuple6"; +//│ constexpr static inline uint32_t typeTag = nextTypeTag(); +//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(", "); this->field1.print(); std::printf(", "); this->field2.print(); std::printf(", "); this->field3.print(); std::printf(", "); this->field4.print(); std::printf(", "); this->field5.print(); std::printf(")"); } +//│ virtual void destroy() override { _mlsValue::destroy(this->field0); _mlsValue::destroy(this->field1); _mlsValue::destroy(this->field2); _mlsValue::destroy(this->field3); _mlsValue::destroy(this->field4); _mlsValue::destroy(this->field5); operator delete (this, std::align_val_t(_mlsAlignment)); } +//│ static _mlsValue create(_mlsValue field0, _mlsValue field1, _mlsValue field2, _mlsValue field3, _mlsValue field4, _mlsValue field5) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple6; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; _mlsVal->field1 = field1; _mlsVal->field2 = field2; _mlsVal->field3 = field3; _mlsVal->field4 = field4; _mlsVal->field5 = field5; return _mlsValue(_mlsVal); } +//│ }; +//│ struct Tuple9: public _mlsObject { +//│ _mlsValue field0; +//│ _mlsValue field1; +//│ _mlsValue field2; +//│ _mlsValue field3; +//│ _mlsValue field4; +//│ _mlsValue field5; +//│ _mlsValue field6; +//│ _mlsValue field7; +//│ _mlsValue field8; +//│ constexpr static inline const char *typeName = "Tuple9"; +//│ constexpr static inline uint32_t typeTag = nextTypeTag(); +//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(", "); this->field1.print(); std::printf(", "); this->field2.print(); std::printf(", "); this->field3.print(); std::printf(", "); this->field4.print(); std::printf(", "); this->field5.print(); std::printf(", "); this->field6.print(); std::printf(", "); this->field7.print(); std::printf(", "); this->field8.print(); std::printf(")"); } +//│ virtual void destroy() override { _mlsValue::destroy(this->field0); _mlsValue::destroy(this->field1); _mlsValue::destroy(this->field2); _mlsValue::destroy(this->field3); _mlsValue::destroy(this->field4); _mlsValue::destroy(this->field5); _mlsValue::destroy(this->field6); _mlsValue::destroy(this->field7); _mlsValue::destroy(this->field8); operator delete (this, std::align_val_t(_mlsAlignment)); } +//│ static _mlsValue create(_mlsValue field0, _mlsValue field1, _mlsValue field2, _mlsValue field3, _mlsValue field4, _mlsValue field5, _mlsValue field6, _mlsValue field7, _mlsValue field8) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple9; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; _mlsVal->field1 = field1; _mlsVal->field2 = field2; _mlsVal->field3 = field3; _mlsVal->field4 = field4; _mlsVal->field5 = field5; _mlsVal->field6 = field6; _mlsVal->field7 = field7; _mlsVal->field8 = field8; return _mlsValue(_mlsVal); } +//│ }; +//│ struct Tuple5: public _mlsObject { +//│ _mlsValue field0; +//│ _mlsValue field1; +//│ _mlsValue field2; +//│ _mlsValue field3; +//│ _mlsValue field4; +//│ constexpr static inline const char *typeName = "Tuple5"; +//│ constexpr static inline uint32_t typeTag = nextTypeTag(); +//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(", "); this->field1.print(); std::printf(", "); this->field2.print(); std::printf(", "); this->field3.print(); std::printf(", "); this->field4.print(); std::printf(")"); } +//│ virtual void destroy() override { _mlsValue::destroy(this->field0); _mlsValue::destroy(this->field1); _mlsValue::destroy(this->field2); _mlsValue::destroy(this->field3); _mlsValue::destroy(this->field4); operator delete (this, std::align_val_t(_mlsAlignment)); } +//│ static _mlsValue create(_mlsValue field0, _mlsValue field1, _mlsValue field2, _mlsValue field3, _mlsValue field4) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple5; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; _mlsVal->field1 = field1; _mlsVal->field2 = field2; _mlsVal->field3 = field3; _mlsVal->field4 = field4; return _mlsValue(_mlsVal); } +//│ }; +//│ _mlsValue j(_mlsValue x1) { +//│ _mlsValue _mls_retval; +//│ auto x = (x1 + _mlsValue::fromIntLit(1)); +//│ _mls_retval = x; +//│ return _mls_retval; +//│ } +//│ _mlsValue foo(_mlsValue a) { +//│ _mlsValue _mls_retval; +//│ auto x2 = _mlsValue::create<_mls_Unit>(); +//│ auto x3 = (a > _mlsValue::fromIntLit(0)); +//│ if (_mlsValue::isIntLit(x3, 1)) { +//│ auto x5 = _mlsValue::fromIntLit(1); +//│ auto x6 = _mlsValue::create<_mls_Unit>(); +//│ _mls_retval = j(x5); +//│ } else { +//│ auto x4 = _mlsValue::create<_mls_Unit>(); +//│ _mls_retval = j(x2); +//│ } +//│ return _mls_retval; +//│ } +//│ _mlsValue _mlsMain() { +//│ _mlsValue _mls_retval; +//│ _mls_retval = _mlsValue::create<_mls_Unit>(); +//│ return _mls_retval; +//│ } +//│ int main() { return _mlsLargeStack(_mlsMainWrapper); } diff --git a/hkmc2/shared/src/test/mlscript/llir/Classes.mls b/hkmc2/shared/src/test/mlscript/llir/Classes.mls index eb61586740..7ad28722bc 100644 --- a/hkmc2/shared/src/test/mlscript/llir/Classes.mls +++ b/hkmc2/shared/src/test/mlscript/llir/Classes.mls @@ -27,21 +27,21 @@ fun main() = main() //│ LLIR: //│ class Base() { -//│ def get$327() = +//│ def get$307() = //│ 1 //│ } //│ class Derived() extends Base { -//│ def get$328() = +//│ def get$308() = //│ 2 //│ } -//│ def main$330() = -//│ let x$404 = Derived$335() in -//│ let x$405 = Base.get$327(x$404) in -//│ let x$406 = Derived.get$328(x$404) in -//│ let x$407 = *(x$405,x$406) in -//│ x$407 -//│ let* (x$408) = main() in -//│ x$408 +//│ def main$310() = +//│ let x$374 = Derived$315() in +//│ let x$375 = Base.get$307(x$374) in +//│ let x$376 = Derived.get$308(x$374) in +//│ let x$377 = *(x$375,x$376) in +//│ x$377 +//│ let* (x$378) = main() in +//│ x$378 //│ //│ Interpreted: //│ 4 diff --git a/hkmc2/shared/src/test/mlscript/llir/ControlFlow.mls b/hkmc2/shared/src/test/mlscript/llir/ControlFlow.mls index 1c657593e9..aa9e8a97e2 100644 --- a/hkmc2/shared/src/test/mlscript/llir/ControlFlow.mls +++ b/hkmc2/shared/src/test/mlscript/llir/ControlFlow.mls @@ -14,12 +14,12 @@ f1() //│ = 2 //│ LLIR: //│ -//│ def f1$249() = -//│ let x$310 = 1 in -//│ let x$311 = 2 in -//│ x$311 -//│ let* (x$312) = f1() in -//│ x$312 +//│ def f1$239() = +//│ let x$290 = 1 in +//│ let x$291 = 2 in +//│ x$291 +//│ let* (x$292) = f1() in +//│ x$292 //│ //│ Interpreted: //│ 2 @@ -33,18 +33,18 @@ f2() //│ = 3 //│ LLIR: //│ -//│ def f2$313() = -//│ let x$375 = 0 in -//│ let x$376 = ==(x$375,1) in -//│ case x$376 of +//│ def f2$293() = +//│ let x$345 = 0 in +//│ let x$346 = ==(x$345,1) in +//│ case x$346 of //│ BoolLit(true) => //│ 2 //│ _ => //│ 3 -//│ def j$377() = +//│ def j$347() = //│ null -//│ let* (x$378) = f2() in -//│ x$378 +//│ let* (x$348) = f2() in +//│ x$348 //│ //│ Interpreted: //│ 3 @@ -59,19 +59,19 @@ f3() //│ = 0 //│ LLIR: //│ -//│ def f3$379() = -//│ let x$441 = 0 in -//│ let x$442 = 1 in -//│ let x$443 = true in -//│ case x$443 of +//│ def f3$349() = +//│ let x$401 = 0 in +//│ let x$402 = 1 in +//│ let x$403 = true in +//│ case x$403 of //│ BoolLit(true) => -//│ x$441 +//│ x$401 //│ _ => -//│ x$442 -//│ def j$444() = +//│ x$402 +//│ def j$404() = //│ null -//│ let* (x$445) = f3() in -//│ x$445 +//│ let* (x$405) = f3() in +//│ x$405 :sllir @@ -84,20 +84,20 @@ f4() //│ = 3 //│ LLIR: //│ -//│ def f4$446() = -//│ let x$511 = 0 in -//│ let x$512 = ==(x$511,1) in -//│ case x$512 of +//│ def f4$406() = +//│ let x$461 = 0 in +//│ let x$462 = ==(x$461,1) in +//│ case x$462 of //│ BoolLit(true) => -//│ let x$514 = 2 in -//│ jump j$513(x$514) +//│ let x$464 = 2 in +//│ jump j$463(x$464) //│ _ => -//│ let x$515 = 3 in -//│ jump j$513(x$515) -//│ def j$513(tmp$457) = -//│ tmp$457 -//│ let* (x$516) = f4() in -//│ x$516 +//│ let x$465 = 3 in +//│ jump j$463(x$465) +//│ def j$463(tmp$417) = +//│ tmp$417 +//│ let* (x$466) = f4() in +//│ x$466 //│ //│ Interpreted: //│ 3 @@ -113,29 +113,29 @@ f5() //│ = 5 //│ LLIR: //│ -//│ def f5$517() = -//│ let x$587 = 0 in -//│ let x$588 = ==(x$587,1) in -//│ case x$588 of +//│ def f5$467() = +//│ let x$527 = 0 in +//│ let x$528 = ==(x$527,1) in +//│ case x$528 of //│ BoolLit(true) => -//│ let x$590 = 2 in -//│ jump j$589(x$590) +//│ let x$530 = 2 in +//│ jump j$529(x$530) //│ _ => -//│ let x$591 = 3 in -//│ jump j$589(x$591) -//│ def j$589(tmp$532) = -//│ let x$592 = ==(tmp$532,2) in -//│ case x$592 of +//│ let x$531 = 3 in +//│ jump j$529(x$531) +//│ def j$529(tmp$482) = +//│ let x$532 = ==(tmp$482,2) in +//│ case x$532 of //│ BoolLit(true) => -//│ let x$594 = 4 in -//│ jump j$593(x$594) +//│ let x$534 = 4 in +//│ jump j$533(x$534) //│ _ => -//│ let x$595 = 5 in -//│ jump j$593(x$595) -//│ def j$593(tmp$533) = -//│ tmp$533 -//│ let* (x$596) = f5() in -//│ x$596 +//│ let x$535 = 5 in +//│ jump j$533(x$535) +//│ def j$533(tmp$483) = +//│ tmp$483 +//│ let* (x$536) = f5() in +//│ x$536 //│ //│ Interpreted: //│ 5 @@ -146,19 +146,171 @@ fun test() = if true do test() //│ LLIR: //│ -//│ def test$597() = -//│ let x$657 = true in -//│ case x$657 of +//│ def test$537() = +//│ let x$587 = true in +//│ case x$587 of //│ BoolLit(true) => -//│ let* (x$659) = test() in -//│ x$659 +//│ let* (x$589) = test() in +//│ x$589 //│ _ => //│ undefined -//│ def j$658() = +//│ def j$588() = //│ null //│ undefined //│ //│ Cpp: +//│ #include "mlsprelude.h" +//│ struct Tuple4; +//│ struct Tuple3; +//│ struct Tuple2; +//│ struct Tuple8; +//│ struct Tuple0; +//│ struct Tuple1; +//│ struct Tuple7; +//│ struct Tuple6; +//│ struct Tuple9; +//│ struct Tuple5; +//│ _mlsValue j(); +//│ _mlsValue test(); +//│ _mlsValue _mlsMain(); +//│ struct Tuple4: public _mlsObject { +//│ _mlsValue field0; +//│ _mlsValue field1; +//│ _mlsValue field2; +//│ _mlsValue field3; +//│ constexpr static inline const char *typeName = "Tuple4"; +//│ constexpr static inline uint32_t typeTag = nextTypeTag(); +//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(", "); this->field1.print(); std::printf(", "); this->field2.print(); std::printf(", "); this->field3.print(); std::printf(")"); } +//│ virtual void destroy() override { _mlsValue::destroy(this->field0); _mlsValue::destroy(this->field1); _mlsValue::destroy(this->field2); _mlsValue::destroy(this->field3); operator delete (this, std::align_val_t(_mlsAlignment)); } +//│ static _mlsValue create(_mlsValue field0, _mlsValue field1, _mlsValue field2, _mlsValue field3) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple4; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; _mlsVal->field1 = field1; _mlsVal->field2 = field2; _mlsVal->field3 = field3; return _mlsValue(_mlsVal); } +//│ }; +//│ struct Tuple3: public _mlsObject { +//│ _mlsValue field0; +//│ _mlsValue field1; +//│ _mlsValue field2; +//│ constexpr static inline const char *typeName = "Tuple3"; +//│ constexpr static inline uint32_t typeTag = nextTypeTag(); +//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(", "); this->field1.print(); std::printf(", "); this->field2.print(); std::printf(")"); } +//│ virtual void destroy() override { _mlsValue::destroy(this->field0); _mlsValue::destroy(this->field1); _mlsValue::destroy(this->field2); operator delete (this, std::align_val_t(_mlsAlignment)); } +//│ static _mlsValue create(_mlsValue field0, _mlsValue field1, _mlsValue field2) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple3; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; _mlsVal->field1 = field1; _mlsVal->field2 = field2; return _mlsValue(_mlsVal); } +//│ }; +//│ struct Tuple2: public _mlsObject { +//│ _mlsValue field0; +//│ _mlsValue field1; +//│ constexpr static inline const char *typeName = "Tuple2"; +//│ constexpr static inline uint32_t typeTag = nextTypeTag(); +//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(", "); this->field1.print(); std::printf(")"); } +//│ virtual void destroy() override { _mlsValue::destroy(this->field0); _mlsValue::destroy(this->field1); operator delete (this, std::align_val_t(_mlsAlignment)); } +//│ static _mlsValue create(_mlsValue field0, _mlsValue field1) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple2; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; _mlsVal->field1 = field1; return _mlsValue(_mlsVal); } +//│ }; +//│ struct Tuple8: public _mlsObject { +//│ _mlsValue field0; +//│ _mlsValue field1; +//│ _mlsValue field2; +//│ _mlsValue field3; +//│ _mlsValue field4; +//│ _mlsValue field5; +//│ _mlsValue field6; +//│ _mlsValue field7; +//│ constexpr static inline const char *typeName = "Tuple8"; +//│ constexpr static inline uint32_t typeTag = nextTypeTag(); +//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(", "); this->field1.print(); std::printf(", "); this->field2.print(); std::printf(", "); this->field3.print(); std::printf(", "); this->field4.print(); std::printf(", "); this->field5.print(); std::printf(", "); this->field6.print(); std::printf(", "); this->field7.print(); std::printf(")"); } +//│ virtual void destroy() override { _mlsValue::destroy(this->field0); _mlsValue::destroy(this->field1); _mlsValue::destroy(this->field2); _mlsValue::destroy(this->field3); _mlsValue::destroy(this->field4); _mlsValue::destroy(this->field5); _mlsValue::destroy(this->field6); _mlsValue::destroy(this->field7); operator delete (this, std::align_val_t(_mlsAlignment)); } +//│ static _mlsValue create(_mlsValue field0, _mlsValue field1, _mlsValue field2, _mlsValue field3, _mlsValue field4, _mlsValue field5, _mlsValue field6, _mlsValue field7) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple8; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; _mlsVal->field1 = field1; _mlsVal->field2 = field2; _mlsVal->field3 = field3; _mlsVal->field4 = field4; _mlsVal->field5 = field5; _mlsVal->field6 = field6; _mlsVal->field7 = field7; return _mlsValue(_mlsVal); } +//│ }; +//│ struct Tuple0: public _mlsObject { +//│ +//│ constexpr static inline const char *typeName = "Tuple0"; +//│ constexpr static inline uint32_t typeTag = nextTypeTag(); +//│ virtual void print() const override { std::printf("%s", typeName); } +//│ virtual void destroy() override { operator delete (this, std::align_val_t(_mlsAlignment)); } +//│ static _mlsValue create() { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple0; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; return _mlsValue(_mlsVal); } +//│ }; +//│ struct Tuple1: public _mlsObject { +//│ _mlsValue field0; +//│ constexpr static inline const char *typeName = "Tuple1"; +//│ constexpr static inline uint32_t typeTag = nextTypeTag(); +//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(")"); } +//│ virtual void destroy() override { _mlsValue::destroy(this->field0); operator delete (this, std::align_val_t(_mlsAlignment)); } +//│ static _mlsValue create(_mlsValue field0) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple1; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; return _mlsValue(_mlsVal); } +//│ }; +//│ struct Tuple7: public _mlsObject { +//│ _mlsValue field0; +//│ _mlsValue field1; +//│ _mlsValue field2; +//│ _mlsValue field3; +//│ _mlsValue field4; +//│ _mlsValue field5; +//│ _mlsValue field6; +//│ constexpr static inline const char *typeName = "Tuple7"; +//│ constexpr static inline uint32_t typeTag = nextTypeTag(); +//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(", "); this->field1.print(); std::printf(", "); this->field2.print(); std::printf(", "); this->field3.print(); std::printf(", "); this->field4.print(); std::printf(", "); this->field5.print(); std::printf(", "); this->field6.print(); std::printf(")"); } +//│ virtual void destroy() override { _mlsValue::destroy(this->field0); _mlsValue::destroy(this->field1); _mlsValue::destroy(this->field2); _mlsValue::destroy(this->field3); _mlsValue::destroy(this->field4); _mlsValue::destroy(this->field5); _mlsValue::destroy(this->field6); operator delete (this, std::align_val_t(_mlsAlignment)); } +//│ static _mlsValue create(_mlsValue field0, _mlsValue field1, _mlsValue field2, _mlsValue field3, _mlsValue field4, _mlsValue field5, _mlsValue field6) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple7; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; _mlsVal->field1 = field1; _mlsVal->field2 = field2; _mlsVal->field3 = field3; _mlsVal->field4 = field4; _mlsVal->field5 = field5; _mlsVal->field6 = field6; return _mlsValue(_mlsVal); } +//│ }; +//│ struct Tuple6: public _mlsObject { +//│ _mlsValue field0; +//│ _mlsValue field1; +//│ _mlsValue field2; +//│ _mlsValue field3; +//│ _mlsValue field4; +//│ _mlsValue field5; +//│ constexpr static inline const char *typeName = "Tuple6"; +//│ constexpr static inline uint32_t typeTag = nextTypeTag(); +//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(", "); this->field1.print(); std::printf(", "); this->field2.print(); std::printf(", "); this->field3.print(); std::printf(", "); this->field4.print(); std::printf(", "); this->field5.print(); std::printf(")"); } +//│ virtual void destroy() override { _mlsValue::destroy(this->field0); _mlsValue::destroy(this->field1); _mlsValue::destroy(this->field2); _mlsValue::destroy(this->field3); _mlsValue::destroy(this->field4); _mlsValue::destroy(this->field5); operator delete (this, std::align_val_t(_mlsAlignment)); } +//│ static _mlsValue create(_mlsValue field0, _mlsValue field1, _mlsValue field2, _mlsValue field3, _mlsValue field4, _mlsValue field5) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple6; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; _mlsVal->field1 = field1; _mlsVal->field2 = field2; _mlsVal->field3 = field3; _mlsVal->field4 = field4; _mlsVal->field5 = field5; return _mlsValue(_mlsVal); } +//│ }; +//│ struct Tuple9: public _mlsObject { +//│ _mlsValue field0; +//│ _mlsValue field1; +//│ _mlsValue field2; +//│ _mlsValue field3; +//│ _mlsValue field4; +//│ _mlsValue field5; +//│ _mlsValue field6; +//│ _mlsValue field7; +//│ _mlsValue field8; +//│ constexpr static inline const char *typeName = "Tuple9"; +//│ constexpr static inline uint32_t typeTag = nextTypeTag(); +//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(", "); this->field1.print(); std::printf(", "); this->field2.print(); std::printf(", "); this->field3.print(); std::printf(", "); this->field4.print(); std::printf(", "); this->field5.print(); std::printf(", "); this->field6.print(); std::printf(", "); this->field7.print(); std::printf(", "); this->field8.print(); std::printf(")"); } +//│ virtual void destroy() override { _mlsValue::destroy(this->field0); _mlsValue::destroy(this->field1); _mlsValue::destroy(this->field2); _mlsValue::destroy(this->field3); _mlsValue::destroy(this->field4); _mlsValue::destroy(this->field5); _mlsValue::destroy(this->field6); _mlsValue::destroy(this->field7); _mlsValue::destroy(this->field8); operator delete (this, std::align_val_t(_mlsAlignment)); } +//│ static _mlsValue create(_mlsValue field0, _mlsValue field1, _mlsValue field2, _mlsValue field3, _mlsValue field4, _mlsValue field5, _mlsValue field6, _mlsValue field7, _mlsValue field8) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple9; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; _mlsVal->field1 = field1; _mlsVal->field2 = field2; _mlsVal->field3 = field3; _mlsVal->field4 = field4; _mlsVal->field5 = field5; _mlsVal->field6 = field6; _mlsVal->field7 = field7; _mlsVal->field8 = field8; return _mlsValue(_mlsVal); } +//│ }; +//│ struct Tuple5: public _mlsObject { +//│ _mlsValue field0; +//│ _mlsValue field1; +//│ _mlsValue field2; +//│ _mlsValue field3; +//│ _mlsValue field4; +//│ constexpr static inline const char *typeName = "Tuple5"; +//│ constexpr static inline uint32_t typeTag = nextTypeTag(); +//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(", "); this->field1.print(); std::printf(", "); this->field2.print(); std::printf(", "); this->field3.print(); std::printf(", "); this->field4.print(); std::printf(")"); } +//│ virtual void destroy() override { _mlsValue::destroy(this->field0); _mlsValue::destroy(this->field1); _mlsValue::destroy(this->field2); _mlsValue::destroy(this->field3); _mlsValue::destroy(this->field4); operator delete (this, std::align_val_t(_mlsAlignment)); } +//│ static _mlsValue create(_mlsValue field0, _mlsValue field1, _mlsValue field2, _mlsValue field3, _mlsValue field4) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple5; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; _mlsVal->field1 = field1; _mlsVal->field2 = field2; _mlsVal->field3 = field3; _mlsVal->field4 = field4; return _mlsValue(_mlsVal); } +//│ }; +//│ _mlsValue j() { +//│ _mlsValue _mls_retval; +//│ _mls_retval = _mlsValue::create<_mls_Unit>(); +//│ return _mls_retval; +//│ } +//│ _mlsValue test() { +//│ _mlsValue _mls_retval; +//│ auto x = _mlsValue::fromIntLit(1); +//│ if (_mlsValue::isIntLit(x, 1)) { +//│ auto x1 = test(); +//│ _mls_retval = x1; +//│ } else { +//│ _mls_retval = _mlsValue::create<_mls_Unit>(); +//│ } +//│ return _mls_retval; +//│ } +//│ _mlsValue _mlsMain() { +//│ _mlsValue _mls_retval; +//│ _mls_retval = _mlsValue::create<_mls_Unit>(); +//│ return _mls_retval; +//│ } +//│ int main() { return _mlsLargeStack(_mlsMainWrapper); } :sllir :scpp @@ -166,20 +318,173 @@ fun test() = (if true then test()) + 1 //│ LLIR: //│ -//│ def test$660() = -//│ let x$723 = true in -//│ case x$723 of +//│ def test$590() = +//│ let x$643 = true in +//│ case x$643 of //│ BoolLit(true) => -//│ let* (x$725) = test() in -//│ jump j$724(x$725) +//│ let* (x$645) = test() in +//│ jump j$644(x$645) //│ _ => //│ panic "match error" -//│ def j$724(tmp$670) = -//│ let x$726 = +(tmp$670,1) in -//│ x$726 +//│ def j$644(tmp$600) = +//│ let x$646 = +(tmp$600,1) in +//│ x$646 //│ undefined //│ //│ Cpp: +//│ #include "mlsprelude.h" +//│ struct Tuple4; +//│ struct Tuple3; +//│ struct Tuple2; +//│ struct Tuple8; +//│ struct Tuple0; +//│ struct Tuple1; +//│ struct Tuple7; +//│ struct Tuple6; +//│ struct Tuple9; +//│ struct Tuple5; +//│ _mlsValue j(_mlsValue); +//│ _mlsValue test(); +//│ _mlsValue _mlsMain(); +//│ struct Tuple4: public _mlsObject { +//│ _mlsValue field0; +//│ _mlsValue field1; +//│ _mlsValue field2; +//│ _mlsValue field3; +//│ constexpr static inline const char *typeName = "Tuple4"; +//│ constexpr static inline uint32_t typeTag = nextTypeTag(); +//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(", "); this->field1.print(); std::printf(", "); this->field2.print(); std::printf(", "); this->field3.print(); std::printf(")"); } +//│ virtual void destroy() override { _mlsValue::destroy(this->field0); _mlsValue::destroy(this->field1); _mlsValue::destroy(this->field2); _mlsValue::destroy(this->field3); operator delete (this, std::align_val_t(_mlsAlignment)); } +//│ static _mlsValue create(_mlsValue field0, _mlsValue field1, _mlsValue field2, _mlsValue field3) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple4; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; _mlsVal->field1 = field1; _mlsVal->field2 = field2; _mlsVal->field3 = field3; return _mlsValue(_mlsVal); } +//│ }; +//│ struct Tuple3: public _mlsObject { +//│ _mlsValue field0; +//│ _mlsValue field1; +//│ _mlsValue field2; +//│ constexpr static inline const char *typeName = "Tuple3"; +//│ constexpr static inline uint32_t typeTag = nextTypeTag(); +//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(", "); this->field1.print(); std::printf(", "); this->field2.print(); std::printf(")"); } +//│ virtual void destroy() override { _mlsValue::destroy(this->field0); _mlsValue::destroy(this->field1); _mlsValue::destroy(this->field2); operator delete (this, std::align_val_t(_mlsAlignment)); } +//│ static _mlsValue create(_mlsValue field0, _mlsValue field1, _mlsValue field2) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple3; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; _mlsVal->field1 = field1; _mlsVal->field2 = field2; return _mlsValue(_mlsVal); } +//│ }; +//│ struct Tuple2: public _mlsObject { +//│ _mlsValue field0; +//│ _mlsValue field1; +//│ constexpr static inline const char *typeName = "Tuple2"; +//│ constexpr static inline uint32_t typeTag = nextTypeTag(); +//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(", "); this->field1.print(); std::printf(")"); } +//│ virtual void destroy() override { _mlsValue::destroy(this->field0); _mlsValue::destroy(this->field1); operator delete (this, std::align_val_t(_mlsAlignment)); } +//│ static _mlsValue create(_mlsValue field0, _mlsValue field1) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple2; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; _mlsVal->field1 = field1; return _mlsValue(_mlsVal); } +//│ }; +//│ struct Tuple8: public _mlsObject { +//│ _mlsValue field0; +//│ _mlsValue field1; +//│ _mlsValue field2; +//│ _mlsValue field3; +//│ _mlsValue field4; +//│ _mlsValue field5; +//│ _mlsValue field6; +//│ _mlsValue field7; +//│ constexpr static inline const char *typeName = "Tuple8"; +//│ constexpr static inline uint32_t typeTag = nextTypeTag(); +//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(", "); this->field1.print(); std::printf(", "); this->field2.print(); std::printf(", "); this->field3.print(); std::printf(", "); this->field4.print(); std::printf(", "); this->field5.print(); std::printf(", "); this->field6.print(); std::printf(", "); this->field7.print(); std::printf(")"); } +//│ virtual void destroy() override { _mlsValue::destroy(this->field0); _mlsValue::destroy(this->field1); _mlsValue::destroy(this->field2); _mlsValue::destroy(this->field3); _mlsValue::destroy(this->field4); _mlsValue::destroy(this->field5); _mlsValue::destroy(this->field6); _mlsValue::destroy(this->field7); operator delete (this, std::align_val_t(_mlsAlignment)); } +//│ static _mlsValue create(_mlsValue field0, _mlsValue field1, _mlsValue field2, _mlsValue field3, _mlsValue field4, _mlsValue field5, _mlsValue field6, _mlsValue field7) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple8; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; _mlsVal->field1 = field1; _mlsVal->field2 = field2; _mlsVal->field3 = field3; _mlsVal->field4 = field4; _mlsVal->field5 = field5; _mlsVal->field6 = field6; _mlsVal->field7 = field7; return _mlsValue(_mlsVal); } +//│ }; +//│ struct Tuple0: public _mlsObject { +//│ +//│ constexpr static inline const char *typeName = "Tuple0"; +//│ constexpr static inline uint32_t typeTag = nextTypeTag(); +//│ virtual void print() const override { std::printf("%s", typeName); } +//│ virtual void destroy() override { operator delete (this, std::align_val_t(_mlsAlignment)); } +//│ static _mlsValue create() { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple0; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; return _mlsValue(_mlsVal); } +//│ }; +//│ struct Tuple1: public _mlsObject { +//│ _mlsValue field0; +//│ constexpr static inline const char *typeName = "Tuple1"; +//│ constexpr static inline uint32_t typeTag = nextTypeTag(); +//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(")"); } +//│ virtual void destroy() override { _mlsValue::destroy(this->field0); operator delete (this, std::align_val_t(_mlsAlignment)); } +//│ static _mlsValue create(_mlsValue field0) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple1; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; return _mlsValue(_mlsVal); } +//│ }; +//│ struct Tuple7: public _mlsObject { +//│ _mlsValue field0; +//│ _mlsValue field1; +//│ _mlsValue field2; +//│ _mlsValue field3; +//│ _mlsValue field4; +//│ _mlsValue field5; +//│ _mlsValue field6; +//│ constexpr static inline const char *typeName = "Tuple7"; +//│ constexpr static inline uint32_t typeTag = nextTypeTag(); +//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(", "); this->field1.print(); std::printf(", "); this->field2.print(); std::printf(", "); this->field3.print(); std::printf(", "); this->field4.print(); std::printf(", "); this->field5.print(); std::printf(", "); this->field6.print(); std::printf(")"); } +//│ virtual void destroy() override { _mlsValue::destroy(this->field0); _mlsValue::destroy(this->field1); _mlsValue::destroy(this->field2); _mlsValue::destroy(this->field3); _mlsValue::destroy(this->field4); _mlsValue::destroy(this->field5); _mlsValue::destroy(this->field6); operator delete (this, std::align_val_t(_mlsAlignment)); } +//│ static _mlsValue create(_mlsValue field0, _mlsValue field1, _mlsValue field2, _mlsValue field3, _mlsValue field4, _mlsValue field5, _mlsValue field6) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple7; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; _mlsVal->field1 = field1; _mlsVal->field2 = field2; _mlsVal->field3 = field3; _mlsVal->field4 = field4; _mlsVal->field5 = field5; _mlsVal->field6 = field6; return _mlsValue(_mlsVal); } +//│ }; +//│ struct Tuple6: public _mlsObject { +//│ _mlsValue field0; +//│ _mlsValue field1; +//│ _mlsValue field2; +//│ _mlsValue field3; +//│ _mlsValue field4; +//│ _mlsValue field5; +//│ constexpr static inline const char *typeName = "Tuple6"; +//│ constexpr static inline uint32_t typeTag = nextTypeTag(); +//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(", "); this->field1.print(); std::printf(", "); this->field2.print(); std::printf(", "); this->field3.print(); std::printf(", "); this->field4.print(); std::printf(", "); this->field5.print(); std::printf(")"); } +//│ virtual void destroy() override { _mlsValue::destroy(this->field0); _mlsValue::destroy(this->field1); _mlsValue::destroy(this->field2); _mlsValue::destroy(this->field3); _mlsValue::destroy(this->field4); _mlsValue::destroy(this->field5); operator delete (this, std::align_val_t(_mlsAlignment)); } +//│ static _mlsValue create(_mlsValue field0, _mlsValue field1, _mlsValue field2, _mlsValue field3, _mlsValue field4, _mlsValue field5) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple6; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; _mlsVal->field1 = field1; _mlsVal->field2 = field2; _mlsVal->field3 = field3; _mlsVal->field4 = field4; _mlsVal->field5 = field5; return _mlsValue(_mlsVal); } +//│ }; +//│ struct Tuple9: public _mlsObject { +//│ _mlsValue field0; +//│ _mlsValue field1; +//│ _mlsValue field2; +//│ _mlsValue field3; +//│ _mlsValue field4; +//│ _mlsValue field5; +//│ _mlsValue field6; +//│ _mlsValue field7; +//│ _mlsValue field8; +//│ constexpr static inline const char *typeName = "Tuple9"; +//│ constexpr static inline uint32_t typeTag = nextTypeTag(); +//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(", "); this->field1.print(); std::printf(", "); this->field2.print(); std::printf(", "); this->field3.print(); std::printf(", "); this->field4.print(); std::printf(", "); this->field5.print(); std::printf(", "); this->field6.print(); std::printf(", "); this->field7.print(); std::printf(", "); this->field8.print(); std::printf(")"); } +//│ virtual void destroy() override { _mlsValue::destroy(this->field0); _mlsValue::destroy(this->field1); _mlsValue::destroy(this->field2); _mlsValue::destroy(this->field3); _mlsValue::destroy(this->field4); _mlsValue::destroy(this->field5); _mlsValue::destroy(this->field6); _mlsValue::destroy(this->field7); _mlsValue::destroy(this->field8); operator delete (this, std::align_val_t(_mlsAlignment)); } +//│ static _mlsValue create(_mlsValue field0, _mlsValue field1, _mlsValue field2, _mlsValue field3, _mlsValue field4, _mlsValue field5, _mlsValue field6, _mlsValue field7, _mlsValue field8) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple9; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; _mlsVal->field1 = field1; _mlsVal->field2 = field2; _mlsVal->field3 = field3; _mlsVal->field4 = field4; _mlsVal->field5 = field5; _mlsVal->field6 = field6; _mlsVal->field7 = field7; _mlsVal->field8 = field8; return _mlsValue(_mlsVal); } +//│ }; +//│ struct Tuple5: public _mlsObject { +//│ _mlsValue field0; +//│ _mlsValue field1; +//│ _mlsValue field2; +//│ _mlsValue field3; +//│ _mlsValue field4; +//│ constexpr static inline const char *typeName = "Tuple5"; +//│ constexpr static inline uint32_t typeTag = nextTypeTag(); +//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(", "); this->field1.print(); std::printf(", "); this->field2.print(); std::printf(", "); this->field3.print(); std::printf(", "); this->field4.print(); std::printf(")"); } +//│ virtual void destroy() override { _mlsValue::destroy(this->field0); _mlsValue::destroy(this->field1); _mlsValue::destroy(this->field2); _mlsValue::destroy(this->field3); _mlsValue::destroy(this->field4); operator delete (this, std::align_val_t(_mlsAlignment)); } +//│ static _mlsValue create(_mlsValue field0, _mlsValue field1, _mlsValue field2, _mlsValue field3, _mlsValue field4) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple5; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; _mlsVal->field1 = field1; _mlsVal->field2 = field2; _mlsVal->field3 = field3; _mlsVal->field4 = field4; return _mlsValue(_mlsVal); } +//│ }; +//│ _mlsValue j(_mlsValue tmp) { +//│ _mlsValue _mls_retval; +//│ auto x = (tmp + _mlsValue::fromIntLit(1)); +//│ _mls_retval = x; +//│ return _mls_retval; +//│ } +//│ _mlsValue test() { +//│ _mlsValue _mls_retval; +//│ auto x1 = _mlsValue::fromIntLit(1); +//│ if (_mlsValue::isIntLit(x1, 1)) { +//│ auto x2 = test(); +//│ _mls_retval = j(x2); +//│ } else { +//│ throw std::runtime_error("match error"); +//│ } +//│ return _mls_retval; +//│ } +//│ _mlsValue _mlsMain() { +//│ _mlsValue _mls_retval; +//│ _mls_retval = _mlsValue::create<_mls_Unit>(); +//│ return _mls_retval; +//│ } +//│ int main() { return _mlsLargeStack(_mlsMainWrapper); } :sllir @@ -194,23 +499,179 @@ f() //│ = 11 //│ LLIR: //│ -//│ def f$727() = -//│ let x$793 = 10 in -//│ let x$794 = true in -//│ case x$794 of +//│ def f$647() = +//│ let x$703 = 10 in +//│ let x$704 = true in +//│ case x$704 of //│ BoolLit(true) => -//│ let x$796 = +(x$793,1) in -//│ let x$797 = undefined in -//│ jump j$795(x$796) +//│ let x$706 = +(x$703,1) in +//│ let x$707 = undefined in +//│ jump j$705(x$706) //│ _ => -//│ let x$798 = undefined in -//│ jump j$795(x$793) -//│ def j$795(x$728) = -//│ x$728 -//│ let* (x$799) = f() in -//│ x$799 +//│ let x$708 = undefined in +//│ jump j$705(x$703) +//│ def j$705(x$648) = +//│ x$648 +//│ let* (x$709) = f() in +//│ x$709 //│ //│ Cpp: +//│ #include "mlsprelude.h" +//│ struct Tuple4; +//│ struct Tuple3; +//│ struct Tuple2; +//│ struct Tuple8; +//│ struct Tuple0; +//│ struct Tuple1; +//│ struct Tuple7; +//│ struct Tuple6; +//│ struct Tuple9; +//│ struct Tuple5; +//│ _mlsValue j(_mlsValue); +//│ _mlsValue f(); +//│ _mlsValue _mlsMain(); +//│ struct Tuple4: public _mlsObject { +//│ _mlsValue field0; +//│ _mlsValue field1; +//│ _mlsValue field2; +//│ _mlsValue field3; +//│ constexpr static inline const char *typeName = "Tuple4"; +//│ constexpr static inline uint32_t typeTag = nextTypeTag(); +//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(", "); this->field1.print(); std::printf(", "); this->field2.print(); std::printf(", "); this->field3.print(); std::printf(")"); } +//│ virtual void destroy() override { _mlsValue::destroy(this->field0); _mlsValue::destroy(this->field1); _mlsValue::destroy(this->field2); _mlsValue::destroy(this->field3); operator delete (this, std::align_val_t(_mlsAlignment)); } +//│ static _mlsValue create(_mlsValue field0, _mlsValue field1, _mlsValue field2, _mlsValue field3) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple4; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; _mlsVal->field1 = field1; _mlsVal->field2 = field2; _mlsVal->field3 = field3; return _mlsValue(_mlsVal); } +//│ }; +//│ struct Tuple3: public _mlsObject { +//│ _mlsValue field0; +//│ _mlsValue field1; +//│ _mlsValue field2; +//│ constexpr static inline const char *typeName = "Tuple3"; +//│ constexpr static inline uint32_t typeTag = nextTypeTag(); +//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(", "); this->field1.print(); std::printf(", "); this->field2.print(); std::printf(")"); } +//│ virtual void destroy() override { _mlsValue::destroy(this->field0); _mlsValue::destroy(this->field1); _mlsValue::destroy(this->field2); operator delete (this, std::align_val_t(_mlsAlignment)); } +//│ static _mlsValue create(_mlsValue field0, _mlsValue field1, _mlsValue field2) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple3; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; _mlsVal->field1 = field1; _mlsVal->field2 = field2; return _mlsValue(_mlsVal); } +//│ }; +//│ struct Tuple2: public _mlsObject { +//│ _mlsValue field0; +//│ _mlsValue field1; +//│ constexpr static inline const char *typeName = "Tuple2"; +//│ constexpr static inline uint32_t typeTag = nextTypeTag(); +//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(", "); this->field1.print(); std::printf(")"); } +//│ virtual void destroy() override { _mlsValue::destroy(this->field0); _mlsValue::destroy(this->field1); operator delete (this, std::align_val_t(_mlsAlignment)); } +//│ static _mlsValue create(_mlsValue field0, _mlsValue field1) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple2; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; _mlsVal->field1 = field1; return _mlsValue(_mlsVal); } +//│ }; +//│ struct Tuple8: public _mlsObject { +//│ _mlsValue field0; +//│ _mlsValue field1; +//│ _mlsValue field2; +//│ _mlsValue field3; +//│ _mlsValue field4; +//│ _mlsValue field5; +//│ _mlsValue field6; +//│ _mlsValue field7; +//│ constexpr static inline const char *typeName = "Tuple8"; +//│ constexpr static inline uint32_t typeTag = nextTypeTag(); +//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(", "); this->field1.print(); std::printf(", "); this->field2.print(); std::printf(", "); this->field3.print(); std::printf(", "); this->field4.print(); std::printf(", "); this->field5.print(); std::printf(", "); this->field6.print(); std::printf(", "); this->field7.print(); std::printf(")"); } +//│ virtual void destroy() override { _mlsValue::destroy(this->field0); _mlsValue::destroy(this->field1); _mlsValue::destroy(this->field2); _mlsValue::destroy(this->field3); _mlsValue::destroy(this->field4); _mlsValue::destroy(this->field5); _mlsValue::destroy(this->field6); _mlsValue::destroy(this->field7); operator delete (this, std::align_val_t(_mlsAlignment)); } +//│ static _mlsValue create(_mlsValue field0, _mlsValue field1, _mlsValue field2, _mlsValue field3, _mlsValue field4, _mlsValue field5, _mlsValue field6, _mlsValue field7) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple8; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; _mlsVal->field1 = field1; _mlsVal->field2 = field2; _mlsVal->field3 = field3; _mlsVal->field4 = field4; _mlsVal->field5 = field5; _mlsVal->field6 = field6; _mlsVal->field7 = field7; return _mlsValue(_mlsVal); } +//│ }; +//│ struct Tuple0: public _mlsObject { +//│ +//│ constexpr static inline const char *typeName = "Tuple0"; +//│ constexpr static inline uint32_t typeTag = nextTypeTag(); +//│ virtual void print() const override { std::printf("%s", typeName); } +//│ virtual void destroy() override { operator delete (this, std::align_val_t(_mlsAlignment)); } +//│ static _mlsValue create() { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple0; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; return _mlsValue(_mlsVal); } +//│ }; +//│ struct Tuple1: public _mlsObject { +//│ _mlsValue field0; +//│ constexpr static inline const char *typeName = "Tuple1"; +//│ constexpr static inline uint32_t typeTag = nextTypeTag(); +//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(")"); } +//│ virtual void destroy() override { _mlsValue::destroy(this->field0); operator delete (this, std::align_val_t(_mlsAlignment)); } +//│ static _mlsValue create(_mlsValue field0) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple1; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; return _mlsValue(_mlsVal); } +//│ }; +//│ struct Tuple7: public _mlsObject { +//│ _mlsValue field0; +//│ _mlsValue field1; +//│ _mlsValue field2; +//│ _mlsValue field3; +//│ _mlsValue field4; +//│ _mlsValue field5; +//│ _mlsValue field6; +//│ constexpr static inline const char *typeName = "Tuple7"; +//│ constexpr static inline uint32_t typeTag = nextTypeTag(); +//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(", "); this->field1.print(); std::printf(", "); this->field2.print(); std::printf(", "); this->field3.print(); std::printf(", "); this->field4.print(); std::printf(", "); this->field5.print(); std::printf(", "); this->field6.print(); std::printf(")"); } +//│ virtual void destroy() override { _mlsValue::destroy(this->field0); _mlsValue::destroy(this->field1); _mlsValue::destroy(this->field2); _mlsValue::destroy(this->field3); _mlsValue::destroy(this->field4); _mlsValue::destroy(this->field5); _mlsValue::destroy(this->field6); operator delete (this, std::align_val_t(_mlsAlignment)); } +//│ static _mlsValue create(_mlsValue field0, _mlsValue field1, _mlsValue field2, _mlsValue field3, _mlsValue field4, _mlsValue field5, _mlsValue field6) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple7; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; _mlsVal->field1 = field1; _mlsVal->field2 = field2; _mlsVal->field3 = field3; _mlsVal->field4 = field4; _mlsVal->field5 = field5; _mlsVal->field6 = field6; return _mlsValue(_mlsVal); } +//│ }; +//│ struct Tuple6: public _mlsObject { +//│ _mlsValue field0; +//│ _mlsValue field1; +//│ _mlsValue field2; +//│ _mlsValue field3; +//│ _mlsValue field4; +//│ _mlsValue field5; +//│ constexpr static inline const char *typeName = "Tuple6"; +//│ constexpr static inline uint32_t typeTag = nextTypeTag(); +//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(", "); this->field1.print(); std::printf(", "); this->field2.print(); std::printf(", "); this->field3.print(); std::printf(", "); this->field4.print(); std::printf(", "); this->field5.print(); std::printf(")"); } +//│ virtual void destroy() override { _mlsValue::destroy(this->field0); _mlsValue::destroy(this->field1); _mlsValue::destroy(this->field2); _mlsValue::destroy(this->field3); _mlsValue::destroy(this->field4); _mlsValue::destroy(this->field5); operator delete (this, std::align_val_t(_mlsAlignment)); } +//│ static _mlsValue create(_mlsValue field0, _mlsValue field1, _mlsValue field2, _mlsValue field3, _mlsValue field4, _mlsValue field5) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple6; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; _mlsVal->field1 = field1; _mlsVal->field2 = field2; _mlsVal->field3 = field3; _mlsVal->field4 = field4; _mlsVal->field5 = field5; return _mlsValue(_mlsVal); } +//│ }; +//│ struct Tuple9: public _mlsObject { +//│ _mlsValue field0; +//│ _mlsValue field1; +//│ _mlsValue field2; +//│ _mlsValue field3; +//│ _mlsValue field4; +//│ _mlsValue field5; +//│ _mlsValue field6; +//│ _mlsValue field7; +//│ _mlsValue field8; +//│ constexpr static inline const char *typeName = "Tuple9"; +//│ constexpr static inline uint32_t typeTag = nextTypeTag(); +//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(", "); this->field1.print(); std::printf(", "); this->field2.print(); std::printf(", "); this->field3.print(); std::printf(", "); this->field4.print(); std::printf(", "); this->field5.print(); std::printf(", "); this->field6.print(); std::printf(", "); this->field7.print(); std::printf(", "); this->field8.print(); std::printf(")"); } +//│ virtual void destroy() override { _mlsValue::destroy(this->field0); _mlsValue::destroy(this->field1); _mlsValue::destroy(this->field2); _mlsValue::destroy(this->field3); _mlsValue::destroy(this->field4); _mlsValue::destroy(this->field5); _mlsValue::destroy(this->field6); _mlsValue::destroy(this->field7); _mlsValue::destroy(this->field8); operator delete (this, std::align_val_t(_mlsAlignment)); } +//│ static _mlsValue create(_mlsValue field0, _mlsValue field1, _mlsValue field2, _mlsValue field3, _mlsValue field4, _mlsValue field5, _mlsValue field6, _mlsValue field7, _mlsValue field8) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple9; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; _mlsVal->field1 = field1; _mlsVal->field2 = field2; _mlsVal->field3 = field3; _mlsVal->field4 = field4; _mlsVal->field5 = field5; _mlsVal->field6 = field6; _mlsVal->field7 = field7; _mlsVal->field8 = field8; return _mlsValue(_mlsVal); } +//│ }; +//│ struct Tuple5: public _mlsObject { +//│ _mlsValue field0; +//│ _mlsValue field1; +//│ _mlsValue field2; +//│ _mlsValue field3; +//│ _mlsValue field4; +//│ constexpr static inline const char *typeName = "Tuple5"; +//│ constexpr static inline uint32_t typeTag = nextTypeTag(); +//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(", "); this->field1.print(); std::printf(", "); this->field2.print(); std::printf(", "); this->field3.print(); std::printf(", "); this->field4.print(); std::printf(")"); } +//│ virtual void destroy() override { _mlsValue::destroy(this->field0); _mlsValue::destroy(this->field1); _mlsValue::destroy(this->field2); _mlsValue::destroy(this->field3); _mlsValue::destroy(this->field4); operator delete (this, std::align_val_t(_mlsAlignment)); } +//│ static _mlsValue create(_mlsValue field0, _mlsValue field1, _mlsValue field2, _mlsValue field3, _mlsValue field4) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple5; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; _mlsVal->field1 = field1; _mlsVal->field2 = field2; _mlsVal->field3 = field3; _mlsVal->field4 = field4; return _mlsValue(_mlsVal); } +//│ }; +//│ _mlsValue j(_mlsValue x) { +//│ _mlsValue _mls_retval; +//│ _mls_retval = x; +//│ return _mls_retval; +//│ } +//│ _mlsValue f() { +//│ _mlsValue _mls_retval; +//│ auto x1 = _mlsValue::fromIntLit(10); +//│ auto x2 = _mlsValue::fromIntLit(1); +//│ if (_mlsValue::isIntLit(x2, 1)) { +//│ auto x4 = (x1 + _mlsValue::fromIntLit(1)); +//│ auto x5 = _mlsValue::create<_mls_Unit>(); +//│ _mls_retval = j(x4); +//│ } else { +//│ auto x3 = _mlsValue::create<_mls_Unit>(); +//│ _mls_retval = j(x1); +//│ } +//│ return _mls_retval; +//│ } +//│ _mlsValue _mlsMain() { +//│ _mlsValue _mls_retval; +//│ auto x6 = f(); +//│ _mls_retval = x6; +//│ return _mls_retval; +//│ } +//│ int main() { return _mlsLargeStack(_mlsMainWrapper); } //│ //│ Interpreted: //│ 11 @@ -227,29 +688,29 @@ fun f(a) = f(A(1)) //│ = 1 //│ LLIR: -//│ class A(x$805) -//│ class B(y$808) -//│ def f$802(a$809) = -//│ case a$809 of -//│ A$803 => -//│ let x$881 = a$809. in -//│ let x$882 = 1 in -//│ jump j$880(x$882) +//│ class A(x$715) +//│ class B(y$718) +//│ def f$712(a$719) = +//│ case a$719 of +//│ A$713 => +//│ let x$781 = a$719. in +//│ let x$782 = 1 in +//│ jump j$780(x$782) //│ _ => -//│ case a$809 of -//│ B$806 => -//│ let x$884 = a$809. in -//│ let x$885 = 2 in -//│ jump j$883(x$885) +//│ case a$719 of +//│ B$716 => +//│ let x$784 = a$719. in +//│ let x$785 = 2 in +//│ jump j$783(x$785) //│ _ => //│ panic "match error" -//│ def j$883(tmp$824) = -//│ jump j$880(tmp$824) -//│ def j$880(tmp$824) = -//│ tmp$824 -//│ let x$886 = A$803(1) in -//│ let* (x$887) = f(x$886) in -//│ x$887 +//│ def j$783(tmp$734) = +//│ jump j$780(tmp$734) +//│ def j$780(tmp$734) = +//│ tmp$734 +//│ let x$786 = A$713(1) in +//│ let* (x$787) = f(x$786) in +//│ x$787 //│ //│ Interpreted: //│ 1 @@ -268,50 +729,50 @@ fun f(a) = f(A(1)) //│ = 1 //│ LLIR: -//│ class A(x$893) -//│ class B(y$896) -//│ def f$890(a$897) = -//│ case a$897 of -//│ A$891 => -//│ let x$973 = a$897. in -//│ case a$897 of -//│ A$891 => -//│ let x$975 = a$897. in -//│ case x$975 of +//│ class A(x$793) +//│ class B(y$796) +//│ def f$790(a$797) = +//│ case a$797 of +//│ A$791 => +//│ let x$863 = a$797. in +//│ case a$797 of +//│ A$791 => +//│ let x$865 = a$797. in +//│ case x$865 of //│ IntLit(1) => -//│ let x$977 = 1 in -//│ jump j$976(x$977) +//│ let x$867 = 1 in +//│ jump j$866(x$867) //│ _ => //│ panic "match error" //│ _ => -//│ case a$897 of -//│ B$894 => -//│ let x$979 = a$897. in -//│ let x$980 = 2 in -//│ jump j$978(x$980) +//│ case a$797 of +//│ B$794 => +//│ let x$869 = a$797. in +//│ let x$870 = 2 in +//│ jump j$868(x$870) //│ _ => //│ panic "match error" //│ _ => -//│ case a$897 of -//│ B$894 => -//│ let x$982 = a$897. in -//│ let x$983 = 3 in -//│ jump j$981(x$983) +//│ case a$797 of +//│ B$794 => +//│ let x$872 = a$797. in +//│ let x$873 = 3 in +//│ jump j$871(x$873) //│ _ => //│ panic "match error" -//│ def j$976(tmp$915) = -//│ jump j$974(tmp$915) -//│ def j$978(tmp$915) = -//│ jump j$974(tmp$915) -//│ def j$974(tmp$915) = -//│ jump j$972(tmp$915) -//│ def j$981(tmp$916) = -//│ jump j$972(tmp$916) -//│ def j$972(tmp$916) = -//│ tmp$916 -//│ let x$984 = A$891(1) in -//│ let* (x$985) = f(x$984) in -//│ x$985 +//│ def j$866(tmp$815) = +//│ jump j$864(tmp$815) +//│ def j$868(tmp$815) = +//│ jump j$864(tmp$815) +//│ def j$864(tmp$815) = +//│ jump j$862(tmp$815) +//│ def j$871(tmp$816) = +//│ jump j$862(tmp$816) +//│ def j$862(tmp$816) = +//│ tmp$816 +//│ let x$874 = A$791(1) in +//│ let* (x$875) = f(x$874) in +//│ x$875 //│ //│ Interpreted: //│ 1 diff --git a/hkmc2/shared/src/test/mlscript/llir/Ctor.mls b/hkmc2/shared/src/test/mlscript/llir/Ctor.mls index 5dbcad49b0..2095671808 100644 --- a/hkmc2/shared/src/test/mlscript/llir/Ctor.mls +++ b/hkmc2/shared/src/test/mlscript/llir/Ctor.mls @@ -10,12 +10,12 @@ fun testCtor1() = None fun testCtor2() = new None //│ LLIR: //│ class None() -//│ def testCtor1$250() = -//│ let x$311 = None$252() in -//│ x$311 -//│ def testCtor2$249() = -//│ let x$312 = None$252() in -//│ x$312 +//│ def testCtor1$240() = +//│ let x$291 = None$242() in +//│ x$291 +//│ def testCtor2$239() = +//│ let x$292 = None$242() in +//│ x$292 //│ undefined :sllir @@ -23,11 +23,11 @@ class A(x) fun testCtor1() = A(1) fun testCtor2() = new A(1) //│ LLIR: -//│ class A(x$318) -//│ def testCtor1$315() = -//│ let x$378 = A$316(1) in -//│ x$378 -//│ def testCtor2$314() = -//│ let x$379 = A$316(1) in -//│ x$379 +//│ class A(x$298) +//│ def testCtor1$295() = +//│ let x$348 = A$296(1) in +//│ x$348 +//│ def testCtor2$294() = +//│ let x$349 = A$296(1) in +//│ x$349 //│ undefined diff --git a/hkmc2/shared/src/test/mlscript/llir/HigherOrder.mls b/hkmc2/shared/src/test/mlscript/llir/HigherOrder.mls index 73a501c844..40569a7872 100644 --- a/hkmc2/shared/src/test/mlscript/llir/HigherOrder.mls +++ b/hkmc2/shared/src/test/mlscript/llir/HigherOrder.mls @@ -11,19 +11,177 @@ fun add(x) = y => x + y add(1)(2) //│ = 3 //│ LLIR: -//│ class Lambda(x$250) extends Callable { -//│ def apply1$278(y$251) = -//│ let x$318 = +(x$250,y$251) in -//│ x$318 +//│ class Lambda(x$240) extends Callable { +//│ def apply1$267(y$241) = +//│ let x$298 = +(x$240,y$241) in +//│ x$298 //│ } -//│ def add$249(x$250) = -//│ let x$319 = Lambda$316(x$250) in -//│ x$319 -//│ let* (x$320) = add(1) in -//│ let x$321 = Callable.apply1$278(x$320,2) in -//│ x$321 +//│ def add$239(x$240) = +//│ let x$299 = Lambda$296(x$240) in +//│ x$299 +//│ let* (x$300) = add(1) in +//│ let x$301 = Callable.apply1$267(x$300,2) in +//│ x$301 //│ //│ Cpp: +//│ #include "mlsprelude.h" +//│ struct Tuple4; +//│ struct Tuple3; +//│ struct Tuple2; +//│ struct Tuple8; +//│ struct Tuple0; +//│ struct Tuple1; +//│ struct Tuple7; +//│ struct Tuple6; +//│ struct Tuple9; +//│ struct Tuple5; +//│ struct Lambda; +//│ _mlsValue add(_mlsValue); +//│ _mlsValue _mlsMain(); +//│ struct Tuple4: public _mlsObject { +//│ _mlsValue field0; +//│ _mlsValue field1; +//│ _mlsValue field2; +//│ _mlsValue field3; +//│ constexpr static inline const char *typeName = "Tuple4"; +//│ constexpr static inline uint32_t typeTag = nextTypeTag(); +//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(", "); this->field1.print(); std::printf(", "); this->field2.print(); std::printf(", "); this->field3.print(); std::printf(")"); } +//│ virtual void destroy() override { _mlsValue::destroy(this->field0); _mlsValue::destroy(this->field1); _mlsValue::destroy(this->field2); _mlsValue::destroy(this->field3); operator delete (this, std::align_val_t(_mlsAlignment)); } +//│ static _mlsValue create(_mlsValue field0, _mlsValue field1, _mlsValue field2, _mlsValue field3) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple4; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; _mlsVal->field1 = field1; _mlsVal->field2 = field2; _mlsVal->field3 = field3; return _mlsValue(_mlsVal); } +//│ }; +//│ struct Tuple3: public _mlsObject { +//│ _mlsValue field0; +//│ _mlsValue field1; +//│ _mlsValue field2; +//│ constexpr static inline const char *typeName = "Tuple3"; +//│ constexpr static inline uint32_t typeTag = nextTypeTag(); +//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(", "); this->field1.print(); std::printf(", "); this->field2.print(); std::printf(")"); } +//│ virtual void destroy() override { _mlsValue::destroy(this->field0); _mlsValue::destroy(this->field1); _mlsValue::destroy(this->field2); operator delete (this, std::align_val_t(_mlsAlignment)); } +//│ static _mlsValue create(_mlsValue field0, _mlsValue field1, _mlsValue field2) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple3; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; _mlsVal->field1 = field1; _mlsVal->field2 = field2; return _mlsValue(_mlsVal); } +//│ }; +//│ struct Tuple2: public _mlsObject { +//│ _mlsValue field0; +//│ _mlsValue field1; +//│ constexpr static inline const char *typeName = "Tuple2"; +//│ constexpr static inline uint32_t typeTag = nextTypeTag(); +//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(", "); this->field1.print(); std::printf(")"); } +//│ virtual void destroy() override { _mlsValue::destroy(this->field0); _mlsValue::destroy(this->field1); operator delete (this, std::align_val_t(_mlsAlignment)); } +//│ static _mlsValue create(_mlsValue field0, _mlsValue field1) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple2; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; _mlsVal->field1 = field1; return _mlsValue(_mlsVal); } +//│ }; +//│ struct Tuple8: public _mlsObject { +//│ _mlsValue field0; +//│ _mlsValue field1; +//│ _mlsValue field2; +//│ _mlsValue field3; +//│ _mlsValue field4; +//│ _mlsValue field5; +//│ _mlsValue field6; +//│ _mlsValue field7; +//│ constexpr static inline const char *typeName = "Tuple8"; +//│ constexpr static inline uint32_t typeTag = nextTypeTag(); +//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(", "); this->field1.print(); std::printf(", "); this->field2.print(); std::printf(", "); this->field3.print(); std::printf(", "); this->field4.print(); std::printf(", "); this->field5.print(); std::printf(", "); this->field6.print(); std::printf(", "); this->field7.print(); std::printf(")"); } +//│ virtual void destroy() override { _mlsValue::destroy(this->field0); _mlsValue::destroy(this->field1); _mlsValue::destroy(this->field2); _mlsValue::destroy(this->field3); _mlsValue::destroy(this->field4); _mlsValue::destroy(this->field5); _mlsValue::destroy(this->field6); _mlsValue::destroy(this->field7); operator delete (this, std::align_val_t(_mlsAlignment)); } +//│ static _mlsValue create(_mlsValue field0, _mlsValue field1, _mlsValue field2, _mlsValue field3, _mlsValue field4, _mlsValue field5, _mlsValue field6, _mlsValue field7) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple8; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; _mlsVal->field1 = field1; _mlsVal->field2 = field2; _mlsVal->field3 = field3; _mlsVal->field4 = field4; _mlsVal->field5 = field5; _mlsVal->field6 = field6; _mlsVal->field7 = field7; return _mlsValue(_mlsVal); } +//│ }; +//│ struct Tuple0: public _mlsObject { +//│ +//│ constexpr static inline const char *typeName = "Tuple0"; +//│ constexpr static inline uint32_t typeTag = nextTypeTag(); +//│ virtual void print() const override { std::printf("%s", typeName); } +//│ virtual void destroy() override { operator delete (this, std::align_val_t(_mlsAlignment)); } +//│ static _mlsValue create() { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple0; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; return _mlsValue(_mlsVal); } +//│ }; +//│ struct Tuple1: public _mlsObject { +//│ _mlsValue field0; +//│ constexpr static inline const char *typeName = "Tuple1"; +//│ constexpr static inline uint32_t typeTag = nextTypeTag(); +//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(")"); } +//│ virtual void destroy() override { _mlsValue::destroy(this->field0); operator delete (this, std::align_val_t(_mlsAlignment)); } +//│ static _mlsValue create(_mlsValue field0) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple1; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; return _mlsValue(_mlsVal); } +//│ }; +//│ struct Tuple7: public _mlsObject { +//│ _mlsValue field0; +//│ _mlsValue field1; +//│ _mlsValue field2; +//│ _mlsValue field3; +//│ _mlsValue field4; +//│ _mlsValue field5; +//│ _mlsValue field6; +//│ constexpr static inline const char *typeName = "Tuple7"; +//│ constexpr static inline uint32_t typeTag = nextTypeTag(); +//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(", "); this->field1.print(); std::printf(", "); this->field2.print(); std::printf(", "); this->field3.print(); std::printf(", "); this->field4.print(); std::printf(", "); this->field5.print(); std::printf(", "); this->field6.print(); std::printf(")"); } +//│ virtual void destroy() override { _mlsValue::destroy(this->field0); _mlsValue::destroy(this->field1); _mlsValue::destroy(this->field2); _mlsValue::destroy(this->field3); _mlsValue::destroy(this->field4); _mlsValue::destroy(this->field5); _mlsValue::destroy(this->field6); operator delete (this, std::align_val_t(_mlsAlignment)); } +//│ static _mlsValue create(_mlsValue field0, _mlsValue field1, _mlsValue field2, _mlsValue field3, _mlsValue field4, _mlsValue field5, _mlsValue field6) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple7; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; _mlsVal->field1 = field1; _mlsVal->field2 = field2; _mlsVal->field3 = field3; _mlsVal->field4 = field4; _mlsVal->field5 = field5; _mlsVal->field6 = field6; return _mlsValue(_mlsVal); } +//│ }; +//│ struct Tuple6: public _mlsObject { +//│ _mlsValue field0; +//│ _mlsValue field1; +//│ _mlsValue field2; +//│ _mlsValue field3; +//│ _mlsValue field4; +//│ _mlsValue field5; +//│ constexpr static inline const char *typeName = "Tuple6"; +//│ constexpr static inline uint32_t typeTag = nextTypeTag(); +//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(", "); this->field1.print(); std::printf(", "); this->field2.print(); std::printf(", "); this->field3.print(); std::printf(", "); this->field4.print(); std::printf(", "); this->field5.print(); std::printf(")"); } +//│ virtual void destroy() override { _mlsValue::destroy(this->field0); _mlsValue::destroy(this->field1); _mlsValue::destroy(this->field2); _mlsValue::destroy(this->field3); _mlsValue::destroy(this->field4); _mlsValue::destroy(this->field5); operator delete (this, std::align_val_t(_mlsAlignment)); } +//│ static _mlsValue create(_mlsValue field0, _mlsValue field1, _mlsValue field2, _mlsValue field3, _mlsValue field4, _mlsValue field5) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple6; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; _mlsVal->field1 = field1; _mlsVal->field2 = field2; _mlsVal->field3 = field3; _mlsVal->field4 = field4; _mlsVal->field5 = field5; return _mlsValue(_mlsVal); } +//│ }; +//│ struct Tuple9: public _mlsObject { +//│ _mlsValue field0; +//│ _mlsValue field1; +//│ _mlsValue field2; +//│ _mlsValue field3; +//│ _mlsValue field4; +//│ _mlsValue field5; +//│ _mlsValue field6; +//│ _mlsValue field7; +//│ _mlsValue field8; +//│ constexpr static inline const char *typeName = "Tuple9"; +//│ constexpr static inline uint32_t typeTag = nextTypeTag(); +//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(", "); this->field1.print(); std::printf(", "); this->field2.print(); std::printf(", "); this->field3.print(); std::printf(", "); this->field4.print(); std::printf(", "); this->field5.print(); std::printf(", "); this->field6.print(); std::printf(", "); this->field7.print(); std::printf(", "); this->field8.print(); std::printf(")"); } +//│ virtual void destroy() override { _mlsValue::destroy(this->field0); _mlsValue::destroy(this->field1); _mlsValue::destroy(this->field2); _mlsValue::destroy(this->field3); _mlsValue::destroy(this->field4); _mlsValue::destroy(this->field5); _mlsValue::destroy(this->field6); _mlsValue::destroy(this->field7); _mlsValue::destroy(this->field8); operator delete (this, std::align_val_t(_mlsAlignment)); } +//│ static _mlsValue create(_mlsValue field0, _mlsValue field1, _mlsValue field2, _mlsValue field3, _mlsValue field4, _mlsValue field5, _mlsValue field6, _mlsValue field7, _mlsValue field8) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple9; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; _mlsVal->field1 = field1; _mlsVal->field2 = field2; _mlsVal->field3 = field3; _mlsVal->field4 = field4; _mlsVal->field5 = field5; _mlsVal->field6 = field6; _mlsVal->field7 = field7; _mlsVal->field8 = field8; return _mlsValue(_mlsVal); } +//│ }; +//│ struct Tuple5: public _mlsObject { +//│ _mlsValue field0; +//│ _mlsValue field1; +//│ _mlsValue field2; +//│ _mlsValue field3; +//│ _mlsValue field4; +//│ constexpr static inline const char *typeName = "Tuple5"; +//│ constexpr static inline uint32_t typeTag = nextTypeTag(); +//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(", "); this->field1.print(); std::printf(", "); this->field2.print(); std::printf(", "); this->field3.print(); std::printf(", "); this->field4.print(); std::printf(")"); } +//│ virtual void destroy() override { _mlsValue::destroy(this->field0); _mlsValue::destroy(this->field1); _mlsValue::destroy(this->field2); _mlsValue::destroy(this->field3); _mlsValue::destroy(this->field4); operator delete (this, std::align_val_t(_mlsAlignment)); } +//│ static _mlsValue create(_mlsValue field0, _mlsValue field1, _mlsValue field2, _mlsValue field3, _mlsValue field4) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple5; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; _mlsVal->field1 = field1; _mlsVal->field2 = field2; _mlsVal->field3 = field3; _mlsVal->field4 = field4; return _mlsValue(_mlsVal); } +//│ }; +//│ struct Lambda: public Callable { +//│ _mlsValue x; +//│ constexpr static inline const char *typeName = "Lambda"; +//│ constexpr static inline uint32_t typeTag = nextTypeTag(); +//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->x.print(); std::printf(")"); } +//│ virtual void destroy() override { _mlsValue::destroy(this->x); operator delete (this, std::align_val_t(_mlsAlignment)); } +//│ static _mlsValue create(_mlsValue x) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Lambda; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->x = x; return _mlsValue(_mlsVal); } +//│ virtual _mlsValue apply1(_mlsValue y) { +//│ _mlsValue _mls_retval; +//│ auto x1 = (x + y); +//│ _mls_retval = x1; +//│ return _mls_retval; +//│ } +//│ }; +//│ _mlsValue add(_mlsValue x) { +//│ _mlsValue _mls_retval; +//│ auto x2 = _mlsValue::create(x); +//│ _mls_retval = x2; +//│ return _mls_retval; +//│ } +//│ _mlsValue _mlsMain() { +//│ _mlsValue _mls_retval; +//│ auto x3 = add(_mlsValue::fromIntLit(1)); +//│ auto x4 = _mlsMethodCall(x3)->apply1(_mlsValue::fromIntLit(2)); +//│ _mls_retval = x4; +//│ return _mls_retval; +//│ } +//│ int main() { return _mlsLargeStack(_mlsMainWrapper); } //│ //│ Interpreted: //│ 3 @@ -35,21 +193,182 @@ fun add4(a, b) = (c, d) => a + b + c + d add4(1, 2)(3, 4) //│ = 10 //│ LLIR: -//│ class Lambda(b$324,a$323) extends Callable { -//│ def apply2$361(c$325,d$326) = -//│ let x$399 = +(a$323,b$324) in -//│ let x$400 = +(x$399,c$325) in -//│ let x$401 = +(x$400,d$326) in -//│ x$401 +//│ class Lambda(a$303,b$304) extends Callable { +//│ def apply2$339(c$305,d$306) = +//│ let x$369 = +(a$303,b$304) in +//│ let x$370 = +(x$369,c$305) in +//│ let x$371 = +(x$370,d$306) in +//│ x$371 //│ } -//│ def add4$322(a$323,b$324) = -//│ let x$402 = Lambda$397(b$324,a$323) in -//│ x$402 -//│ let* (x$403) = add4(1,2) in -//│ let x$404 = Callable.apply2$361(x$403,3,4) in -//│ x$404 +//│ def add4$302(a$303,b$304) = +//│ let x$372 = Lambda$367(a$303,b$304) in +//│ x$372 +//│ let* (x$373) = add4(1,2) in +//│ let x$374 = Callable.apply2$339(x$373,3,4) in +//│ x$374 //│ //│ Cpp: +//│ #include "mlsprelude.h" +//│ struct Tuple4; +//│ struct Tuple3; +//│ struct Tuple2; +//│ struct Tuple8; +//│ struct Tuple0; +//│ struct Tuple1; +//│ struct Tuple7; +//│ struct Tuple6; +//│ struct Tuple9; +//│ struct Tuple5; +//│ struct Lambda; +//│ _mlsValue add4(_mlsValue, _mlsValue); +//│ _mlsValue _mlsMain(); +//│ struct Tuple4: public _mlsObject { +//│ _mlsValue field0; +//│ _mlsValue field1; +//│ _mlsValue field2; +//│ _mlsValue field3; +//│ constexpr static inline const char *typeName = "Tuple4"; +//│ constexpr static inline uint32_t typeTag = nextTypeTag(); +//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(", "); this->field1.print(); std::printf(", "); this->field2.print(); std::printf(", "); this->field3.print(); std::printf(")"); } +//│ virtual void destroy() override { _mlsValue::destroy(this->field0); _mlsValue::destroy(this->field1); _mlsValue::destroy(this->field2); _mlsValue::destroy(this->field3); operator delete (this, std::align_val_t(_mlsAlignment)); } +//│ static _mlsValue create(_mlsValue field0, _mlsValue field1, _mlsValue field2, _mlsValue field3) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple4; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; _mlsVal->field1 = field1; _mlsVal->field2 = field2; _mlsVal->field3 = field3; return _mlsValue(_mlsVal); } +//│ }; +//│ struct Tuple3: public _mlsObject { +//│ _mlsValue field0; +//│ _mlsValue field1; +//│ _mlsValue field2; +//│ constexpr static inline const char *typeName = "Tuple3"; +//│ constexpr static inline uint32_t typeTag = nextTypeTag(); +//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(", "); this->field1.print(); std::printf(", "); this->field2.print(); std::printf(")"); } +//│ virtual void destroy() override { _mlsValue::destroy(this->field0); _mlsValue::destroy(this->field1); _mlsValue::destroy(this->field2); operator delete (this, std::align_val_t(_mlsAlignment)); } +//│ static _mlsValue create(_mlsValue field0, _mlsValue field1, _mlsValue field2) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple3; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; _mlsVal->field1 = field1; _mlsVal->field2 = field2; return _mlsValue(_mlsVal); } +//│ }; +//│ struct Tuple2: public _mlsObject { +//│ _mlsValue field0; +//│ _mlsValue field1; +//│ constexpr static inline const char *typeName = "Tuple2"; +//│ constexpr static inline uint32_t typeTag = nextTypeTag(); +//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(", "); this->field1.print(); std::printf(")"); } +//│ virtual void destroy() override { _mlsValue::destroy(this->field0); _mlsValue::destroy(this->field1); operator delete (this, std::align_val_t(_mlsAlignment)); } +//│ static _mlsValue create(_mlsValue field0, _mlsValue field1) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple2; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; _mlsVal->field1 = field1; return _mlsValue(_mlsVal); } +//│ }; +//│ struct Tuple8: public _mlsObject { +//│ _mlsValue field0; +//│ _mlsValue field1; +//│ _mlsValue field2; +//│ _mlsValue field3; +//│ _mlsValue field4; +//│ _mlsValue field5; +//│ _mlsValue field6; +//│ _mlsValue field7; +//│ constexpr static inline const char *typeName = "Tuple8"; +//│ constexpr static inline uint32_t typeTag = nextTypeTag(); +//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(", "); this->field1.print(); std::printf(", "); this->field2.print(); std::printf(", "); this->field3.print(); std::printf(", "); this->field4.print(); std::printf(", "); this->field5.print(); std::printf(", "); this->field6.print(); std::printf(", "); this->field7.print(); std::printf(")"); } +//│ virtual void destroy() override { _mlsValue::destroy(this->field0); _mlsValue::destroy(this->field1); _mlsValue::destroy(this->field2); _mlsValue::destroy(this->field3); _mlsValue::destroy(this->field4); _mlsValue::destroy(this->field5); _mlsValue::destroy(this->field6); _mlsValue::destroy(this->field7); operator delete (this, std::align_val_t(_mlsAlignment)); } +//│ static _mlsValue create(_mlsValue field0, _mlsValue field1, _mlsValue field2, _mlsValue field3, _mlsValue field4, _mlsValue field5, _mlsValue field6, _mlsValue field7) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple8; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; _mlsVal->field1 = field1; _mlsVal->field2 = field2; _mlsVal->field3 = field3; _mlsVal->field4 = field4; _mlsVal->field5 = field5; _mlsVal->field6 = field6; _mlsVal->field7 = field7; return _mlsValue(_mlsVal); } +//│ }; +//│ struct Tuple0: public _mlsObject { +//│ +//│ constexpr static inline const char *typeName = "Tuple0"; +//│ constexpr static inline uint32_t typeTag = nextTypeTag(); +//│ virtual void print() const override { std::printf("%s", typeName); } +//│ virtual void destroy() override { operator delete (this, std::align_val_t(_mlsAlignment)); } +//│ static _mlsValue create() { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple0; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; return _mlsValue(_mlsVal); } +//│ }; +//│ struct Tuple1: public _mlsObject { +//│ _mlsValue field0; +//│ constexpr static inline const char *typeName = "Tuple1"; +//│ constexpr static inline uint32_t typeTag = nextTypeTag(); +//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(")"); } +//│ virtual void destroy() override { _mlsValue::destroy(this->field0); operator delete (this, std::align_val_t(_mlsAlignment)); } +//│ static _mlsValue create(_mlsValue field0) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple1; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; return _mlsValue(_mlsVal); } +//│ }; +//│ struct Tuple7: public _mlsObject { +//│ _mlsValue field0; +//│ _mlsValue field1; +//│ _mlsValue field2; +//│ _mlsValue field3; +//│ _mlsValue field4; +//│ _mlsValue field5; +//│ _mlsValue field6; +//│ constexpr static inline const char *typeName = "Tuple7"; +//│ constexpr static inline uint32_t typeTag = nextTypeTag(); +//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(", "); this->field1.print(); std::printf(", "); this->field2.print(); std::printf(", "); this->field3.print(); std::printf(", "); this->field4.print(); std::printf(", "); this->field5.print(); std::printf(", "); this->field6.print(); std::printf(")"); } +//│ virtual void destroy() override { _mlsValue::destroy(this->field0); _mlsValue::destroy(this->field1); _mlsValue::destroy(this->field2); _mlsValue::destroy(this->field3); _mlsValue::destroy(this->field4); _mlsValue::destroy(this->field5); _mlsValue::destroy(this->field6); operator delete (this, std::align_val_t(_mlsAlignment)); } +//│ static _mlsValue create(_mlsValue field0, _mlsValue field1, _mlsValue field2, _mlsValue field3, _mlsValue field4, _mlsValue field5, _mlsValue field6) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple7; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; _mlsVal->field1 = field1; _mlsVal->field2 = field2; _mlsVal->field3 = field3; _mlsVal->field4 = field4; _mlsVal->field5 = field5; _mlsVal->field6 = field6; return _mlsValue(_mlsVal); } +//│ }; +//│ struct Tuple6: public _mlsObject { +//│ _mlsValue field0; +//│ _mlsValue field1; +//│ _mlsValue field2; +//│ _mlsValue field3; +//│ _mlsValue field4; +//│ _mlsValue field5; +//│ constexpr static inline const char *typeName = "Tuple6"; +//│ constexpr static inline uint32_t typeTag = nextTypeTag(); +//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(", "); this->field1.print(); std::printf(", "); this->field2.print(); std::printf(", "); this->field3.print(); std::printf(", "); this->field4.print(); std::printf(", "); this->field5.print(); std::printf(")"); } +//│ virtual void destroy() override { _mlsValue::destroy(this->field0); _mlsValue::destroy(this->field1); _mlsValue::destroy(this->field2); _mlsValue::destroy(this->field3); _mlsValue::destroy(this->field4); _mlsValue::destroy(this->field5); operator delete (this, std::align_val_t(_mlsAlignment)); } +//│ static _mlsValue create(_mlsValue field0, _mlsValue field1, _mlsValue field2, _mlsValue field3, _mlsValue field4, _mlsValue field5) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple6; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; _mlsVal->field1 = field1; _mlsVal->field2 = field2; _mlsVal->field3 = field3; _mlsVal->field4 = field4; _mlsVal->field5 = field5; return _mlsValue(_mlsVal); } +//│ }; +//│ struct Tuple9: public _mlsObject { +//│ _mlsValue field0; +//│ _mlsValue field1; +//│ _mlsValue field2; +//│ _mlsValue field3; +//│ _mlsValue field4; +//│ _mlsValue field5; +//│ _mlsValue field6; +//│ _mlsValue field7; +//│ _mlsValue field8; +//│ constexpr static inline const char *typeName = "Tuple9"; +//│ constexpr static inline uint32_t typeTag = nextTypeTag(); +//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(", "); this->field1.print(); std::printf(", "); this->field2.print(); std::printf(", "); this->field3.print(); std::printf(", "); this->field4.print(); std::printf(", "); this->field5.print(); std::printf(", "); this->field6.print(); std::printf(", "); this->field7.print(); std::printf(", "); this->field8.print(); std::printf(")"); } +//│ virtual void destroy() override { _mlsValue::destroy(this->field0); _mlsValue::destroy(this->field1); _mlsValue::destroy(this->field2); _mlsValue::destroy(this->field3); _mlsValue::destroy(this->field4); _mlsValue::destroy(this->field5); _mlsValue::destroy(this->field6); _mlsValue::destroy(this->field7); _mlsValue::destroy(this->field8); operator delete (this, std::align_val_t(_mlsAlignment)); } +//│ static _mlsValue create(_mlsValue field0, _mlsValue field1, _mlsValue field2, _mlsValue field3, _mlsValue field4, _mlsValue field5, _mlsValue field6, _mlsValue field7, _mlsValue field8) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple9; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; _mlsVal->field1 = field1; _mlsVal->field2 = field2; _mlsVal->field3 = field3; _mlsVal->field4 = field4; _mlsVal->field5 = field5; _mlsVal->field6 = field6; _mlsVal->field7 = field7; _mlsVal->field8 = field8; return _mlsValue(_mlsVal); } +//│ }; +//│ struct Tuple5: public _mlsObject { +//│ _mlsValue field0; +//│ _mlsValue field1; +//│ _mlsValue field2; +//│ _mlsValue field3; +//│ _mlsValue field4; +//│ constexpr static inline const char *typeName = "Tuple5"; +//│ constexpr static inline uint32_t typeTag = nextTypeTag(); +//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(", "); this->field1.print(); std::printf(", "); this->field2.print(); std::printf(", "); this->field3.print(); std::printf(", "); this->field4.print(); std::printf(")"); } +//│ virtual void destroy() override { _mlsValue::destroy(this->field0); _mlsValue::destroy(this->field1); _mlsValue::destroy(this->field2); _mlsValue::destroy(this->field3); _mlsValue::destroy(this->field4); operator delete (this, std::align_val_t(_mlsAlignment)); } +//│ static _mlsValue create(_mlsValue field0, _mlsValue field1, _mlsValue field2, _mlsValue field3, _mlsValue field4) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple5; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; _mlsVal->field1 = field1; _mlsVal->field2 = field2; _mlsVal->field3 = field3; _mlsVal->field4 = field4; return _mlsValue(_mlsVal); } +//│ }; +//│ struct Lambda: public Callable { +//│ _mlsValue a; +//│ _mlsValue b; +//│ constexpr static inline const char *typeName = "Lambda"; +//│ constexpr static inline uint32_t typeTag = nextTypeTag(); +//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->a.print(); std::printf(", "); this->b.print(); std::printf(")"); } +//│ virtual void destroy() override { _mlsValue::destroy(this->a); _mlsValue::destroy(this->b); operator delete (this, std::align_val_t(_mlsAlignment)); } +//│ static _mlsValue create(_mlsValue a, _mlsValue b) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Lambda; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->a = a; _mlsVal->b = b; return _mlsValue(_mlsVal); } +//│ virtual _mlsValue apply2(_mlsValue c, _mlsValue d) { +//│ _mlsValue _mls_retval; +//│ auto x = (a + b); +//│ auto x1 = (x + c); +//│ auto x2 = (x1 + d); +//│ _mls_retval = x2; +//│ return _mls_retval; +//│ } +//│ }; +//│ _mlsValue add4(_mlsValue a, _mlsValue b) { +//│ _mlsValue _mls_retval; +//│ auto x3 = _mlsValue::create(a, b); +//│ _mls_retval = x3; +//│ return _mls_retval; +//│ } +//│ _mlsValue _mlsMain() { +//│ _mlsValue _mls_retval; +//│ auto x4 = add4(_mlsValue::fromIntLit(1), _mlsValue::fromIntLit(2)); +//│ auto x5 = _mlsMethodCall(x4)->apply2(_mlsValue::fromIntLit(3), _mlsValue::fromIntLit(4)); +//│ _mls_retval = x5; +//│ return _mls_retval; +//│ } +//│ int main() { return _mlsLargeStack(_mlsMainWrapper); } //│ //│ Interpreted: //│ 10 @@ -63,21 +382,186 @@ dummy()(1, 2) //│ = 3 //│ LLIR: //│ class Lambda_add() extends Callable { -//│ def apply2$438(arg$475,arg$476) = -//│ let* (x$479) = add(arg$475,arg$476) in -//│ x$479 +//│ def apply2$406(arg$435,arg$436) = +//│ let* (x$439) = add(arg$435,arg$436) in +//│ x$439 //│ } -//│ def add$405(a$407,b$408) = -//│ let x$474 = +(a$407,b$408) in -//│ x$474 -//│ def dummy$406() = -//│ let x$480 = Lambda_add$477() in -//│ x$480 -//│ let* (x$481) = dummy() in -//│ let x$482 = Callable.apply2$438(x$481,1,2) in -//│ x$482 +//│ def add$375(a$377,b$378) = +//│ let x$434 = +(a$377,b$378) in +//│ x$434 +//│ def dummy$376() = +//│ let x$440 = Lambda_add$437() in +//│ x$440 +//│ let* (x$441) = dummy() in +//│ let x$442 = Callable.apply2$406(x$441,1,2) in +//│ x$442 //│ //│ Cpp: +//│ #include "mlsprelude.h" +//│ struct Tuple4; +//│ struct Tuple3; +//│ struct Tuple2; +//│ struct Tuple8; +//│ struct Tuple0; +//│ struct Tuple1; +//│ struct Tuple7; +//│ struct Tuple6; +//│ struct Tuple9; +//│ struct Tuple5; +//│ struct Lambda_add; +//│ _mlsValue add(_mlsValue, _mlsValue); +//│ _mlsValue dummy(); +//│ _mlsValue _mlsMain(); +//│ struct Tuple4: public _mlsObject { +//│ _mlsValue field0; +//│ _mlsValue field1; +//│ _mlsValue field2; +//│ _mlsValue field3; +//│ constexpr static inline const char *typeName = "Tuple4"; +//│ constexpr static inline uint32_t typeTag = nextTypeTag(); +//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(", "); this->field1.print(); std::printf(", "); this->field2.print(); std::printf(", "); this->field3.print(); std::printf(")"); } +//│ virtual void destroy() override { _mlsValue::destroy(this->field0); _mlsValue::destroy(this->field1); _mlsValue::destroy(this->field2); _mlsValue::destroy(this->field3); operator delete (this, std::align_val_t(_mlsAlignment)); } +//│ static _mlsValue create(_mlsValue field0, _mlsValue field1, _mlsValue field2, _mlsValue field3) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple4; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; _mlsVal->field1 = field1; _mlsVal->field2 = field2; _mlsVal->field3 = field3; return _mlsValue(_mlsVal); } +//│ }; +//│ struct Tuple3: public _mlsObject { +//│ _mlsValue field0; +//│ _mlsValue field1; +//│ _mlsValue field2; +//│ constexpr static inline const char *typeName = "Tuple3"; +//│ constexpr static inline uint32_t typeTag = nextTypeTag(); +//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(", "); this->field1.print(); std::printf(", "); this->field2.print(); std::printf(")"); } +//│ virtual void destroy() override { _mlsValue::destroy(this->field0); _mlsValue::destroy(this->field1); _mlsValue::destroy(this->field2); operator delete (this, std::align_val_t(_mlsAlignment)); } +//│ static _mlsValue create(_mlsValue field0, _mlsValue field1, _mlsValue field2) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple3; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; _mlsVal->field1 = field1; _mlsVal->field2 = field2; return _mlsValue(_mlsVal); } +//│ }; +//│ struct Tuple2: public _mlsObject { +//│ _mlsValue field0; +//│ _mlsValue field1; +//│ constexpr static inline const char *typeName = "Tuple2"; +//│ constexpr static inline uint32_t typeTag = nextTypeTag(); +//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(", "); this->field1.print(); std::printf(")"); } +//│ virtual void destroy() override { _mlsValue::destroy(this->field0); _mlsValue::destroy(this->field1); operator delete (this, std::align_val_t(_mlsAlignment)); } +//│ static _mlsValue create(_mlsValue field0, _mlsValue field1) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple2; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; _mlsVal->field1 = field1; return _mlsValue(_mlsVal); } +//│ }; +//│ struct Tuple8: public _mlsObject { +//│ _mlsValue field0; +//│ _mlsValue field1; +//│ _mlsValue field2; +//│ _mlsValue field3; +//│ _mlsValue field4; +//│ _mlsValue field5; +//│ _mlsValue field6; +//│ _mlsValue field7; +//│ constexpr static inline const char *typeName = "Tuple8"; +//│ constexpr static inline uint32_t typeTag = nextTypeTag(); +//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(", "); this->field1.print(); std::printf(", "); this->field2.print(); std::printf(", "); this->field3.print(); std::printf(", "); this->field4.print(); std::printf(", "); this->field5.print(); std::printf(", "); this->field6.print(); std::printf(", "); this->field7.print(); std::printf(")"); } +//│ virtual void destroy() override { _mlsValue::destroy(this->field0); _mlsValue::destroy(this->field1); _mlsValue::destroy(this->field2); _mlsValue::destroy(this->field3); _mlsValue::destroy(this->field4); _mlsValue::destroy(this->field5); _mlsValue::destroy(this->field6); _mlsValue::destroy(this->field7); operator delete (this, std::align_val_t(_mlsAlignment)); } +//│ static _mlsValue create(_mlsValue field0, _mlsValue field1, _mlsValue field2, _mlsValue field3, _mlsValue field4, _mlsValue field5, _mlsValue field6, _mlsValue field7) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple8; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; _mlsVal->field1 = field1; _mlsVal->field2 = field2; _mlsVal->field3 = field3; _mlsVal->field4 = field4; _mlsVal->field5 = field5; _mlsVal->field6 = field6; _mlsVal->field7 = field7; return _mlsValue(_mlsVal); } +//│ }; +//│ struct Tuple0: public _mlsObject { +//│ +//│ constexpr static inline const char *typeName = "Tuple0"; +//│ constexpr static inline uint32_t typeTag = nextTypeTag(); +//│ virtual void print() const override { std::printf("%s", typeName); } +//│ virtual void destroy() override { operator delete (this, std::align_val_t(_mlsAlignment)); } +//│ static _mlsValue create() { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple0; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; return _mlsValue(_mlsVal); } +//│ }; +//│ struct Tuple1: public _mlsObject { +//│ _mlsValue field0; +//│ constexpr static inline const char *typeName = "Tuple1"; +//│ constexpr static inline uint32_t typeTag = nextTypeTag(); +//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(")"); } +//│ virtual void destroy() override { _mlsValue::destroy(this->field0); operator delete (this, std::align_val_t(_mlsAlignment)); } +//│ static _mlsValue create(_mlsValue field0) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple1; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; return _mlsValue(_mlsVal); } +//│ }; +//│ struct Tuple7: public _mlsObject { +//│ _mlsValue field0; +//│ _mlsValue field1; +//│ _mlsValue field2; +//│ _mlsValue field3; +//│ _mlsValue field4; +//│ _mlsValue field5; +//│ _mlsValue field6; +//│ constexpr static inline const char *typeName = "Tuple7"; +//│ constexpr static inline uint32_t typeTag = nextTypeTag(); +//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(", "); this->field1.print(); std::printf(", "); this->field2.print(); std::printf(", "); this->field3.print(); std::printf(", "); this->field4.print(); std::printf(", "); this->field5.print(); std::printf(", "); this->field6.print(); std::printf(")"); } +//│ virtual void destroy() override { _mlsValue::destroy(this->field0); _mlsValue::destroy(this->field1); _mlsValue::destroy(this->field2); _mlsValue::destroy(this->field3); _mlsValue::destroy(this->field4); _mlsValue::destroy(this->field5); _mlsValue::destroy(this->field6); operator delete (this, std::align_val_t(_mlsAlignment)); } +//│ static _mlsValue create(_mlsValue field0, _mlsValue field1, _mlsValue field2, _mlsValue field3, _mlsValue field4, _mlsValue field5, _mlsValue field6) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple7; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; _mlsVal->field1 = field1; _mlsVal->field2 = field2; _mlsVal->field3 = field3; _mlsVal->field4 = field4; _mlsVal->field5 = field5; _mlsVal->field6 = field6; return _mlsValue(_mlsVal); } +//│ }; +//│ struct Tuple6: public _mlsObject { +//│ _mlsValue field0; +//│ _mlsValue field1; +//│ _mlsValue field2; +//│ _mlsValue field3; +//│ _mlsValue field4; +//│ _mlsValue field5; +//│ constexpr static inline const char *typeName = "Tuple6"; +//│ constexpr static inline uint32_t typeTag = nextTypeTag(); +//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(", "); this->field1.print(); std::printf(", "); this->field2.print(); std::printf(", "); this->field3.print(); std::printf(", "); this->field4.print(); std::printf(", "); this->field5.print(); std::printf(")"); } +//│ virtual void destroy() override { _mlsValue::destroy(this->field0); _mlsValue::destroy(this->field1); _mlsValue::destroy(this->field2); _mlsValue::destroy(this->field3); _mlsValue::destroy(this->field4); _mlsValue::destroy(this->field5); operator delete (this, std::align_val_t(_mlsAlignment)); } +//│ static _mlsValue create(_mlsValue field0, _mlsValue field1, _mlsValue field2, _mlsValue field3, _mlsValue field4, _mlsValue field5) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple6; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; _mlsVal->field1 = field1; _mlsVal->field2 = field2; _mlsVal->field3 = field3; _mlsVal->field4 = field4; _mlsVal->field5 = field5; return _mlsValue(_mlsVal); } +//│ }; +//│ struct Tuple9: public _mlsObject { +//│ _mlsValue field0; +//│ _mlsValue field1; +//│ _mlsValue field2; +//│ _mlsValue field3; +//│ _mlsValue field4; +//│ _mlsValue field5; +//│ _mlsValue field6; +//│ _mlsValue field7; +//│ _mlsValue field8; +//│ constexpr static inline const char *typeName = "Tuple9"; +//│ constexpr static inline uint32_t typeTag = nextTypeTag(); +//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(", "); this->field1.print(); std::printf(", "); this->field2.print(); std::printf(", "); this->field3.print(); std::printf(", "); this->field4.print(); std::printf(", "); this->field5.print(); std::printf(", "); this->field6.print(); std::printf(", "); this->field7.print(); std::printf(", "); this->field8.print(); std::printf(")"); } +//│ virtual void destroy() override { _mlsValue::destroy(this->field0); _mlsValue::destroy(this->field1); _mlsValue::destroy(this->field2); _mlsValue::destroy(this->field3); _mlsValue::destroy(this->field4); _mlsValue::destroy(this->field5); _mlsValue::destroy(this->field6); _mlsValue::destroy(this->field7); _mlsValue::destroy(this->field8); operator delete (this, std::align_val_t(_mlsAlignment)); } +//│ static _mlsValue create(_mlsValue field0, _mlsValue field1, _mlsValue field2, _mlsValue field3, _mlsValue field4, _mlsValue field5, _mlsValue field6, _mlsValue field7, _mlsValue field8) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple9; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; _mlsVal->field1 = field1; _mlsVal->field2 = field2; _mlsVal->field3 = field3; _mlsVal->field4 = field4; _mlsVal->field5 = field5; _mlsVal->field6 = field6; _mlsVal->field7 = field7; _mlsVal->field8 = field8; return _mlsValue(_mlsVal); } +//│ }; +//│ struct Tuple5: public _mlsObject { +//│ _mlsValue field0; +//│ _mlsValue field1; +//│ _mlsValue field2; +//│ _mlsValue field3; +//│ _mlsValue field4; +//│ constexpr static inline const char *typeName = "Tuple5"; +//│ constexpr static inline uint32_t typeTag = nextTypeTag(); +//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(", "); this->field1.print(); std::printf(", "); this->field2.print(); std::printf(", "); this->field3.print(); std::printf(", "); this->field4.print(); std::printf(")"); } +//│ virtual void destroy() override { _mlsValue::destroy(this->field0); _mlsValue::destroy(this->field1); _mlsValue::destroy(this->field2); _mlsValue::destroy(this->field3); _mlsValue::destroy(this->field4); operator delete (this, std::align_val_t(_mlsAlignment)); } +//│ static _mlsValue create(_mlsValue field0, _mlsValue field1, _mlsValue field2, _mlsValue field3, _mlsValue field4) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple5; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; _mlsVal->field1 = field1; _mlsVal->field2 = field2; _mlsVal->field3 = field3; _mlsVal->field4 = field4; return _mlsValue(_mlsVal); } +//│ }; +//│ struct Lambda_add: public Callable { +//│ +//│ constexpr static inline const char *typeName = "Lambda_add"; +//│ constexpr static inline uint32_t typeTag = nextTypeTag(); +//│ virtual void print() const override { std::printf("%s", typeName); } +//│ virtual void destroy() override { operator delete (this, std::align_val_t(_mlsAlignment)); } +//│ static _mlsValue create() { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Lambda_add; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; return _mlsValue(_mlsVal); } +//│ virtual _mlsValue apply2(_mlsValue arg, _mlsValue arg1) { +//│ _mlsValue _mls_retval; +//│ auto x = add(arg, arg1); +//│ _mls_retval = x; +//│ return _mls_retval; +//│ } +//│ }; +//│ _mlsValue add(_mlsValue a, _mlsValue b) { +//│ _mlsValue _mls_retval; +//│ auto x1 = (a + b); +//│ _mls_retval = x1; +//│ return _mls_retval; +//│ } +//│ _mlsValue dummy() { +//│ _mlsValue _mls_retval; +//│ auto x2 = _mlsValue::create(); +//│ _mls_retval = x2; +//│ return _mls_retval; +//│ } +//│ _mlsValue _mlsMain() { +//│ _mlsValue _mls_retval; +//│ auto x3 = dummy(); +//│ auto x4 = _mlsMethodCall(x3)->apply2(_mlsValue::fromIntLit(1), _mlsValue::fromIntLit(2)); +//│ _mls_retval = x4; +//│ return _mls_retval; +//│ } +//│ int main() { return _mlsLargeStack(_mlsMainWrapper); } //│ //│ Interpreted: //│ 3 @@ -99,55 +583,55 @@ main() //│ = Cons(4, Cons(5, Nil)) //│ LLIR: //│ class List() -//│ class Cons(head$495,tail$496) extends List +//│ class Cons(head$455,tail$456) extends List //│ class Nil() extends List //│ class Lambda() extends Callable { -//│ def apply1$577(x$513) = -//│ let* (x$629) = inc(x$513) in -//│ x$629 +//│ def apply1$536(x$473) = +//│ let* (x$579) = inc(x$473) in +//│ x$579 //│ } //│ class Lambda_inc() extends Callable { -//│ def apply1$577(arg$635) = -//│ let* (x$638) = inc(arg$635) in -//│ x$638 +//│ def apply1$536(arg$585) = +//│ let* (x$588) = inc(arg$585) in +//│ x$588 //│ } -//│ def map$484(f$499,l$500) = -//│ case l$500 of -//│ Cons$492 => -//│ let x$616 = l$500. in -//│ let x$617 = l$500. in -//│ let x$618 = Callable.apply1$577(f$499,x$616) in -//│ let* (x$619) = map(f$499,x$617) in -//│ let x$620 = Cons$492(x$618,x$619) in -//│ x$620 +//│ def map$444(f$459,l$460) = +//│ case l$460 of +//│ Cons$452 => +//│ let x$566 = l$460. in +//│ let x$567 = l$460. in +//│ let x$568 = Callable.apply1$536(f$459,x$566) in +//│ let* (x$569) = map(f$459,x$567) in +//│ let x$570 = Cons$452(x$568,x$569) in +//│ x$570 //│ _ => -//│ case l$500 of -//│ Nil$497 => -//│ let x$622 = Nil$497() in -//│ x$622 +//│ case l$460 of +//│ Nil$457 => +//│ let x$572 = Nil$457() in +//│ x$572 //│ _ => //│ panic "match error" -//│ def j$621() = -//│ jump j$615() -//│ def j$615() = +//│ def j$571() = +//│ jump j$565() +//│ def j$565() = //│ null -//│ def inc$487(x$509) = -//│ let x$623 = +(x$509,1) in -//│ x$623 -//│ def main$485() = -//│ let x$624 = Nil$497() in -//│ let x$625 = Cons$492(2,x$624) in -//│ let x$626 = Cons$492(1,x$625) in -//│ let x$630 = Lambda$627() in -//│ let* (x$631) = map(x$630,x$626) in -//│ let x$632 = Nil$497() in -//│ let x$633 = Cons$492(4,x$632) in -//│ let x$634 = Cons$492(3,x$633) in -//│ let x$639 = Lambda_inc$636() in -//│ let* (x$640) = map(x$639,x$634) in -//│ x$640 -//│ let* (x$641) = main() in -//│ x$641 +//│ def inc$447(x$469) = +//│ let x$573 = +(x$469,1) in +//│ x$573 +//│ def main$445() = +//│ let x$574 = Nil$457() in +//│ let x$575 = Cons$452(2,x$574) in +//│ let x$576 = Cons$452(1,x$575) in +//│ let x$580 = Lambda$577() in +//│ let* (x$581) = map(x$580,x$576) in +//│ let x$582 = Nil$457() in +//│ let x$583 = Cons$452(4,x$582) in +//│ let x$584 = Cons$452(3,x$583) in +//│ let x$589 = Lambda_inc$586() in +//│ let* (x$590) = map(x$589,x$584) in +//│ x$590 +//│ let* (x$591) = main() in +//│ x$591 //│ //│ Interpreted: //│ Cons(4,Cons(5,Nil())) diff --git a/hkmc2/shared/src/test/mlscript/llir/Legacy.mls b/hkmc2/shared/src/test/mlscript/llir/Legacy.mls index 1008b74ef2..adad5b6064 100644 --- a/hkmc2/shared/src/test/mlscript/llir/Legacy.mls +++ b/hkmc2/shared/src/test/mlscript/llir/Legacy.mls @@ -255,74 +255,74 @@ main() //│ = 404 //│ LLIR: //│ class Option() -//│ class Some(x$1742) extends Option +//│ class Some(x$1602) extends Option //│ class None() extends Option //│ class Nat() -//│ class S(s$1753) extends Nat +//│ class S(s$1613) extends Nat //│ class O() extends Nat -//│ def fromSome$1725(s$1745) = -//│ case s$1745 of -//│ Some$1739 => -//│ let x$1872 = s$1745. in -//│ x$1872 +//│ def fromSome$1585(s$1605) = +//│ case s$1605 of +//│ Some$1599 => +//│ let x$1722 = s$1605. in +//│ x$1722 //│ _ => //│ panic "match error" -//│ def j$1871() = +//│ def j$1721() = //│ null -//│ def aaa$1730() = -//│ let x$1873 = 1 in -//│ let x$1874 = 2 in -//│ let x$1875 = 3 in -//│ let x$1876 = 4 in -//│ let x$1877 = +(x$1873,x$1874) in -//│ let x$1878 = -(x$1877,x$1875) in -//│ let x$1879 = +(x$1878,x$1876) in -//│ x$1879 -//│ def bbb$1732() = -//│ let* (x$1880) = aaa() in -//│ let x$1881 = *(x$1880,100) in -//│ let x$1882 = +(x$1881,4) in -//│ x$1882 -//│ def not$1728(x$1769) = -//│ case x$1769 of +//│ def aaa$1590() = +//│ let x$1723 = 1 in +//│ let x$1724 = 2 in +//│ let x$1725 = 3 in +//│ let x$1726 = 4 in +//│ let x$1727 = +(x$1723,x$1724) in +//│ let x$1728 = -(x$1727,x$1725) in +//│ let x$1729 = +(x$1728,x$1726) in +//│ x$1729 +//│ def bbb$1592() = +//│ let* (x$1730) = aaa() in +//│ let x$1731 = *(x$1730,100) in +//│ let x$1732 = +(x$1731,4) in +//│ x$1732 +//│ def not$1588(x$1629) = +//│ case x$1629 of //│ BoolLit(true) => //│ false //│ _ => //│ true -//│ def j$1883() = +//│ def j$1733() = //│ null -//│ def foo$1735(x$1771) = -//│ case x$1771 of +//│ def foo$1595(x$1631) = +//│ case x$1631 of //│ BoolLit(true) => -//│ let x$1885 = None$1743() in -//│ x$1885 +//│ let x$1735 = None$1603() in +//│ x$1735 //│ _ => -//│ let* (x$1886) = not(x$1771) in -//│ let* (x$1887) = foo(x$1886) in -//│ let x$1888 = Some$1739(x$1887) in -//│ x$1888 -//│ def j$1884() = +//│ let* (x$1736) = not(x$1631) in +//│ let* (x$1737) = foo(x$1736) in +//│ let x$1738 = Some$1599(x$1737) in +//│ x$1738 +//│ def j$1734() = //│ null -//│ def main$1726() = -//│ let* (x$1889) = foo(false) in -//│ case x$1889 of -//│ None$1743 => -//│ let* (x$1891) = aaa() in -//│ x$1891 +//│ def main$1586() = +//│ let* (x$1739) = foo(false) in +//│ case x$1739 of +//│ None$1603 => +//│ let* (x$1741) = aaa() in +//│ x$1741 //│ _ => -//│ case x$1889 of -//│ Some$1739 => -//│ let x$1893 = x$1889. in -//│ let* (x$1894) = bbb() in -//│ x$1894 +//│ case x$1739 of +//│ Some$1599 => +//│ let x$1743 = x$1739. in +//│ let* (x$1744) = bbb() in +//│ x$1744 //│ _ => //│ panic "match error" -//│ def j$1892() = -//│ jump j$1890() -//│ def j$1890() = +//│ def j$1742() = +//│ jump j$1740() +//│ def j$1740() = //│ null -//│ let* (x$1895) = main() in -//│ x$1895 +//│ let* (x$1745) = main() in +//│ x$1745 //│ //│ Interpreted: //│ 404 diff --git a/hkmc2/shared/src/test/mlscript/llir/Method.mls b/hkmc2/shared/src/test/mlscript/llir/Method.mls index e6415fbbd9..0c742e17ab 100644 --- a/hkmc2/shared/src/test/mlscript/llir/Method.mls +++ b/hkmc2/shared/src/test/mlscript/llir/Method.mls @@ -17,9 +17,9 @@ main() //│ m$200 //│ } //│ def main$197() = -//│ let x$264 = A$198(1) in -//│ let x$265 = A.f$195(x$264) in -//│ x$265 -//│ let* (x$266) = main() in -//│ x$266 +//│ let x$254 = A$198(1) in +//│ let x$255 = A.f$195(x$254) in +//│ x$255 +//│ let* (x$256) = main() in +//│ x$256 diff --git a/hkmc2/shared/src/test/mlscript/llir/Tuple.mls b/hkmc2/shared/src/test/mlscript/llir/Tuple.mls index 0463e91561..911c54b0bd 100644 --- a/hkmc2/shared/src/test/mlscript/llir/Tuple.mls +++ b/hkmc2/shared/src/test/mlscript/llir/Tuple.mls @@ -11,11 +11,11 @@ mkTup(1, 2) //│ = [1, 2] //│ LLIR: //│ -//│ def mkTup$249(x$250,y$251) = -//│ let x$310 = Tuple2$294(x$250,y$251) in -//│ x$310 -//│ let* (x$311) = mkTup(1,2) in -//│ x$311 +//│ def mkTup$239(x$240,y$241) = +//│ let x$290 = Tuple2$274(x$240,y$241) in +//│ x$290 +//│ let* (x$291) = mkTup(1,2) in +//│ x$291 //│ //│ Interpreted: //│ Tuple2(1,2) diff --git a/hkmc2DiffTests/src/test/scala/hkmc2/LlirDiffMaker.scala b/hkmc2DiffTests/src/test/scala/hkmc2/LlirDiffMaker.scala index bc6fa5180d..fa23ef5a4d 100644 --- a/hkmc2DiffTests/src/test/scala/hkmc2/LlirDiffMaker.scala +++ b/hkmc2DiffTests/src/test/scala/hkmc2/LlirDiffMaker.scala @@ -14,6 +14,7 @@ import hkmc2.codegen.Path import hkmc2.semantics.Term.Blk import hkmc2.utils.Scope import hkmc2.codegen.llir._ +import hkmc2.codegen.cpp._ import hkmc2.semantics.Elaborator abstract class LlirDiffMaker extends BbmlDiffMaker: @@ -48,21 +49,21 @@ abstract class LlirDiffMaker extends BbmlDiffMaker: output("LLIR:") output(llirProg.show()) if cpp.isSet || scpp.isSet || rcpp.isSet || wcpp.isSet then - // val cpp = codegen.cpp.CppCodeGen.codegen(llirProg) + val cpp = CppCodeGen(tl).codegen(llb.builtinSymbols, llirProg) if scpp.isSet then output("\nCpp:") - // output(cpp.toDocument.toString) - val auxPath = os.Path(rootPath) / "hkmc2"/"shared"/"src"/"test"/"mlscript-compile"/"cpp" + output(cpp.toDocument.toString) + val auxPath = os.Path(rootPath)/"hkmc2"/"shared"/"src"/"test"/"mlscript-compile"/"cpp" if wcpp.isSet then - // printToFile(java.io.File((auxPath / s"${wcpp.get.get}.cpp").toString)): - // p => p.println(cpp.toDocument.toString) + printToFile(java.io.File((auxPath / s"${wcpp.get.get}.cpp").toString)): + p => p.println(cpp.toDocument.toString) if rcpp.isSet then val cppHost = CppCompilerHost(auxPath.toString, output.apply) if !cppHost.ready then output("\nCpp Compilation Failed: Cpp compiler or GNU Make not found") else output("\n") - // cppHost.compileAndRun(cpp.toDocument.toString) + cppHost.compileAndRun(cpp.toDocument.toString) if intl.isSet then val intr = codegen.llir.Interpreter(tl) output("\nInterpreted:") From 2f92c413d056012902818e019a25c03bd0c36bf8 Mon Sep 17 00:00:00 2001 From: waterlens Date: Wed, 19 Feb 2025 16:30:23 +0800 Subject: [PATCH 37/88] Define symbols only when necessary --- .../scala/hkmc2/codegen/llir/Builder.scala | 60 +- .../src/test/mlscript/llir/BasicCpp.mls | 148 +--- .../shared/src/test/mlscript/llir/Classes.mls | 20 +- .../src/test/mlscript/llir/ControlFlow.mls | 650 ++++-------------- hkmc2/shared/src/test/mlscript/llir/Ctor.mls | 26 +- .../src/test/mlscript/llir/HigherOrder.mls | 536 +++------------ .../shared/src/test/mlscript/llir/Legacy.mls | 100 +-- .../shared/src/test/mlscript/llir/Method.mls | 10 +- hkmc2/shared/src/test/mlscript/llir/Tuple.mls | 10 +- 9 files changed, 324 insertions(+), 1236 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala index 842687e352..f4c00c0210 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala @@ -3,6 +3,7 @@ package codegen package llir import scala.collection.mutable.ListBuffer +import scala.collection.mutable.{HashMap => MutMap} import mlscript.utils.* import mlscript.utils.shorthands.* @@ -98,51 +99,19 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger, uid: FreshInt): private def newNamed(name: Str) = VarSymbol(Tree.Ident(name)) private def newLambdaSym(name: Str) = ClassSymbol(Tree.TypeDef(hkmc2.syntax.Cls, Tree.Empty(), N, N), Tree.Ident(name)) - private def newClassSym(len: Int) = + private def newTupleSym(len: Int) = ClassSymbol(Tree.TypeDef(hkmc2.syntax.Cls, Tree.Empty(), N, N), Tree.Ident(s"Tuple$len")) private def newMemSym(name: Str) = TermSymbol(hkmc2.syntax.ImmutVal, None, Tree.Ident(name)) private def newMethodSym(name: Str) = TermSymbol(hkmc2.syntax.Fun, None, Tree.Ident(name)) - private val builtinField: Map[Int, Local] = - Map( - 0 -> newMemSym("field0"), - 1 -> newMemSym("field1"), - 2 -> newMemSym("field2"), - 3 -> newMemSym("field3"), - 4 -> newMemSym("field4"), - 5 -> newMemSym("field5"), - 6 -> newMemSym("field6"), - 7 -> newMemSym("field7"), - 8 -> newMemSym("field8"), - 9 -> newMemSym("field9"), - ) - private val builtinCallable: Local = newLambdaSym("Callable") - private val builtinApply: Map[Int, Local] = - Map( - 0 -> newMethodSym("apply0"), - 1 -> newMethodSym("apply1"), - 2 -> newMethodSym("apply2"), - 3 -> newMethodSym("apply3"), - 4 -> newMethodSym("apply4"), - 5 -> newMethodSym("apply5"), - 6 -> newMethodSym("apply6"), - 7 -> newMethodSym("apply7"), - 8 -> newMethodSym("apply8"), - 9 -> newMethodSym("apply9"), - ) - private val builtinTuple: Map[Int, Local] = - Map( - 0 -> newClassSym(0), - 1 -> newClassSym(1), - 2 -> newClassSym(2), - 3 -> newClassSym(3), - 4 -> newClassSym(4), - 5 -> newClassSym(5), - 6 -> newClassSym(6), - 7 -> newClassSym(7), - 8 -> newClassSym(8), - 9 -> newClassSym(9), - ) - val builtinSymbols = Set(builtinCallable) + private val fieldSym: MutMap[Int, Local] = MutMap.empty + private val applySym: MutMap[Int, Local] = MutMap.empty + private val tupleSym: MutMap[Int, Local] = MutMap.empty + private val callableSym = newMemSym("Callable") + private def builtinField(n: Int) = fieldSym.getOrElseUpdate(n, newMemSym(s"field$n")) + private def builtinApply(n: Int) = applySym.getOrElseUpdate(n, newMethodSym(s"apply$n")) + private def builtinTuple(n: Int) = tupleSym.getOrElseUpdate(n, newTupleSym(n)) + private def builtinCallable: Local = callableSym + val builtinSymbols = Set(builtinCallable) // Callable is implicitly defined in the runtime private def bBind(name: Opt[Local], e: Result, body: Block)(k: TrivialExpr => Ctx ?=> Node)(ct: Block)(using ctx: Ctx)(using Raise, Scope): Node = trace[Node](s"bBind begin: $name", x => s"bBind end: ${x.show}"): @@ -483,7 +452,7 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger, uid: FreshInt): b.subBlocks.foldLeft(ctx)((ctx, rest) => registerClasses(rest)(using ctx)) def registerInternalClasses(using ctx: Ctx)(using Raise, Scope): Ctx = - builtinTuple.foldLeft(ctx): + tupleSym.foldLeft(ctx): case (ctx, (len, sym)) => val c = ClassInfo( uid.make, @@ -509,8 +478,6 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger, uid: FreshInt): def bProg(e: Program)(using Raise, Scope): LlirProgram = var ctx = Ctx.empty - ctx = registerInternalClasses(using ctx) - // * Classes may be defined after other things such as functions, // * especially now that the elaborator moves all functions to the top of the block. ctx = registerClasses(e.main)(using ctx) @@ -519,5 +486,8 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger, uid: FreshInt): log(s"Classes: ${ctx.class_ctx}") val entry = bBlockWithEndCont(e.main)(x => Node.Result(Ls(x)))(using ctx) + + ctx = registerInternalClasses(using ctx) + LlirProgram(ctx.class_acc.toSet, ctx.def_acc.toSet, entry) diff --git a/hkmc2/shared/src/test/mlscript/llir/BasicCpp.mls b/hkmc2/shared/src/test/mlscript/llir/BasicCpp.mls index ce9cdbfec5..060aaab7b3 100644 --- a/hkmc2/shared/src/test/mlscript/llir/BasicCpp.mls +++ b/hkmc2/shared/src/test/mlscript/llir/BasicCpp.mls @@ -14,152 +14,26 @@ fun foo(a) = //│ LLIR: //│ //│ def foo$195(a$196) = -//│ let x$245 = null in -//│ let x$246 = >(a$196,0) in -//│ case x$246 of +//│ let x$204 = null in +//│ let x$205 = >(a$196,0) in +//│ case x$205 of //│ BoolLit(true) => -//│ let x$248 = 1 in -//│ let x$249 = undefined in -//│ jump j$247(x$248) +//│ let x$207 = 1 in +//│ let x$208 = undefined in +//│ jump j$206(x$207) //│ _ => -//│ let x$250 = undefined in -//│ jump j$247(x$245) -//│ def j$247(x$197) = -//│ let x$251 = +(x$197,1) in -//│ x$251 +//│ let x$209 = undefined in +//│ jump j$206(x$204) +//│ def j$206(x$197) = +//│ let x$210 = +(x$197,1) in +//│ x$210 //│ undefined //│ //│ Cpp: //│ #include "mlsprelude.h" -//│ struct Tuple4; -//│ struct Tuple3; -//│ struct Tuple2; -//│ struct Tuple8; -//│ struct Tuple0; -//│ struct Tuple1; -//│ struct Tuple7; -//│ struct Tuple6; -//│ struct Tuple9; -//│ struct Tuple5; //│ _mlsValue j(_mlsValue); //│ _mlsValue foo(_mlsValue); //│ _mlsValue _mlsMain(); -//│ struct Tuple4: public _mlsObject { -//│ _mlsValue field0; -//│ _mlsValue field1; -//│ _mlsValue field2; -//│ _mlsValue field3; -//│ constexpr static inline const char *typeName = "Tuple4"; -//│ constexpr static inline uint32_t typeTag = nextTypeTag(); -//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(", "); this->field1.print(); std::printf(", "); this->field2.print(); std::printf(", "); this->field3.print(); std::printf(")"); } -//│ virtual void destroy() override { _mlsValue::destroy(this->field0); _mlsValue::destroy(this->field1); _mlsValue::destroy(this->field2); _mlsValue::destroy(this->field3); operator delete (this, std::align_val_t(_mlsAlignment)); } -//│ static _mlsValue create(_mlsValue field0, _mlsValue field1, _mlsValue field2, _mlsValue field3) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple4; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; _mlsVal->field1 = field1; _mlsVal->field2 = field2; _mlsVal->field3 = field3; return _mlsValue(_mlsVal); } -//│ }; -//│ struct Tuple3: public _mlsObject { -//│ _mlsValue field0; -//│ _mlsValue field1; -//│ _mlsValue field2; -//│ constexpr static inline const char *typeName = "Tuple3"; -//│ constexpr static inline uint32_t typeTag = nextTypeTag(); -//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(", "); this->field1.print(); std::printf(", "); this->field2.print(); std::printf(")"); } -//│ virtual void destroy() override { _mlsValue::destroy(this->field0); _mlsValue::destroy(this->field1); _mlsValue::destroy(this->field2); operator delete (this, std::align_val_t(_mlsAlignment)); } -//│ static _mlsValue create(_mlsValue field0, _mlsValue field1, _mlsValue field2) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple3; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; _mlsVal->field1 = field1; _mlsVal->field2 = field2; return _mlsValue(_mlsVal); } -//│ }; -//│ struct Tuple2: public _mlsObject { -//│ _mlsValue field0; -//│ _mlsValue field1; -//│ constexpr static inline const char *typeName = "Tuple2"; -//│ constexpr static inline uint32_t typeTag = nextTypeTag(); -//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(", "); this->field1.print(); std::printf(")"); } -//│ virtual void destroy() override { _mlsValue::destroy(this->field0); _mlsValue::destroy(this->field1); operator delete (this, std::align_val_t(_mlsAlignment)); } -//│ static _mlsValue create(_mlsValue field0, _mlsValue field1) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple2; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; _mlsVal->field1 = field1; return _mlsValue(_mlsVal); } -//│ }; -//│ struct Tuple8: public _mlsObject { -//│ _mlsValue field0; -//│ _mlsValue field1; -//│ _mlsValue field2; -//│ _mlsValue field3; -//│ _mlsValue field4; -//│ _mlsValue field5; -//│ _mlsValue field6; -//│ _mlsValue field7; -//│ constexpr static inline const char *typeName = "Tuple8"; -//│ constexpr static inline uint32_t typeTag = nextTypeTag(); -//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(", "); this->field1.print(); std::printf(", "); this->field2.print(); std::printf(", "); this->field3.print(); std::printf(", "); this->field4.print(); std::printf(", "); this->field5.print(); std::printf(", "); this->field6.print(); std::printf(", "); this->field7.print(); std::printf(")"); } -//│ virtual void destroy() override { _mlsValue::destroy(this->field0); _mlsValue::destroy(this->field1); _mlsValue::destroy(this->field2); _mlsValue::destroy(this->field3); _mlsValue::destroy(this->field4); _mlsValue::destroy(this->field5); _mlsValue::destroy(this->field6); _mlsValue::destroy(this->field7); operator delete (this, std::align_val_t(_mlsAlignment)); } -//│ static _mlsValue create(_mlsValue field0, _mlsValue field1, _mlsValue field2, _mlsValue field3, _mlsValue field4, _mlsValue field5, _mlsValue field6, _mlsValue field7) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple8; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; _mlsVal->field1 = field1; _mlsVal->field2 = field2; _mlsVal->field3 = field3; _mlsVal->field4 = field4; _mlsVal->field5 = field5; _mlsVal->field6 = field6; _mlsVal->field7 = field7; return _mlsValue(_mlsVal); } -//│ }; -//│ struct Tuple0: public _mlsObject { -//│ -//│ constexpr static inline const char *typeName = "Tuple0"; -//│ constexpr static inline uint32_t typeTag = nextTypeTag(); -//│ virtual void print() const override { std::printf("%s", typeName); } -//│ virtual void destroy() override { operator delete (this, std::align_val_t(_mlsAlignment)); } -//│ static _mlsValue create() { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple0; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; return _mlsValue(_mlsVal); } -//│ }; -//│ struct Tuple1: public _mlsObject { -//│ _mlsValue field0; -//│ constexpr static inline const char *typeName = "Tuple1"; -//│ constexpr static inline uint32_t typeTag = nextTypeTag(); -//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(")"); } -//│ virtual void destroy() override { _mlsValue::destroy(this->field0); operator delete (this, std::align_val_t(_mlsAlignment)); } -//│ static _mlsValue create(_mlsValue field0) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple1; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; return _mlsValue(_mlsVal); } -//│ }; -//│ struct Tuple7: public _mlsObject { -//│ _mlsValue field0; -//│ _mlsValue field1; -//│ _mlsValue field2; -//│ _mlsValue field3; -//│ _mlsValue field4; -//│ _mlsValue field5; -//│ _mlsValue field6; -//│ constexpr static inline const char *typeName = "Tuple7"; -//│ constexpr static inline uint32_t typeTag = nextTypeTag(); -//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(", "); this->field1.print(); std::printf(", "); this->field2.print(); std::printf(", "); this->field3.print(); std::printf(", "); this->field4.print(); std::printf(", "); this->field5.print(); std::printf(", "); this->field6.print(); std::printf(")"); } -//│ virtual void destroy() override { _mlsValue::destroy(this->field0); _mlsValue::destroy(this->field1); _mlsValue::destroy(this->field2); _mlsValue::destroy(this->field3); _mlsValue::destroy(this->field4); _mlsValue::destroy(this->field5); _mlsValue::destroy(this->field6); operator delete (this, std::align_val_t(_mlsAlignment)); } -//│ static _mlsValue create(_mlsValue field0, _mlsValue field1, _mlsValue field2, _mlsValue field3, _mlsValue field4, _mlsValue field5, _mlsValue field6) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple7; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; _mlsVal->field1 = field1; _mlsVal->field2 = field2; _mlsVal->field3 = field3; _mlsVal->field4 = field4; _mlsVal->field5 = field5; _mlsVal->field6 = field6; return _mlsValue(_mlsVal); } -//│ }; -//│ struct Tuple6: public _mlsObject { -//│ _mlsValue field0; -//│ _mlsValue field1; -//│ _mlsValue field2; -//│ _mlsValue field3; -//│ _mlsValue field4; -//│ _mlsValue field5; -//│ constexpr static inline const char *typeName = "Tuple6"; -//│ constexpr static inline uint32_t typeTag = nextTypeTag(); -//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(", "); this->field1.print(); std::printf(", "); this->field2.print(); std::printf(", "); this->field3.print(); std::printf(", "); this->field4.print(); std::printf(", "); this->field5.print(); std::printf(")"); } -//│ virtual void destroy() override { _mlsValue::destroy(this->field0); _mlsValue::destroy(this->field1); _mlsValue::destroy(this->field2); _mlsValue::destroy(this->field3); _mlsValue::destroy(this->field4); _mlsValue::destroy(this->field5); operator delete (this, std::align_val_t(_mlsAlignment)); } -//│ static _mlsValue create(_mlsValue field0, _mlsValue field1, _mlsValue field2, _mlsValue field3, _mlsValue field4, _mlsValue field5) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple6; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; _mlsVal->field1 = field1; _mlsVal->field2 = field2; _mlsVal->field3 = field3; _mlsVal->field4 = field4; _mlsVal->field5 = field5; return _mlsValue(_mlsVal); } -//│ }; -//│ struct Tuple9: public _mlsObject { -//│ _mlsValue field0; -//│ _mlsValue field1; -//│ _mlsValue field2; -//│ _mlsValue field3; -//│ _mlsValue field4; -//│ _mlsValue field5; -//│ _mlsValue field6; -//│ _mlsValue field7; -//│ _mlsValue field8; -//│ constexpr static inline const char *typeName = "Tuple9"; -//│ constexpr static inline uint32_t typeTag = nextTypeTag(); -//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(", "); this->field1.print(); std::printf(", "); this->field2.print(); std::printf(", "); this->field3.print(); std::printf(", "); this->field4.print(); std::printf(", "); this->field5.print(); std::printf(", "); this->field6.print(); std::printf(", "); this->field7.print(); std::printf(", "); this->field8.print(); std::printf(")"); } -//│ virtual void destroy() override { _mlsValue::destroy(this->field0); _mlsValue::destroy(this->field1); _mlsValue::destroy(this->field2); _mlsValue::destroy(this->field3); _mlsValue::destroy(this->field4); _mlsValue::destroy(this->field5); _mlsValue::destroy(this->field6); _mlsValue::destroy(this->field7); _mlsValue::destroy(this->field8); operator delete (this, std::align_val_t(_mlsAlignment)); } -//│ static _mlsValue create(_mlsValue field0, _mlsValue field1, _mlsValue field2, _mlsValue field3, _mlsValue field4, _mlsValue field5, _mlsValue field6, _mlsValue field7, _mlsValue field8) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple9; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; _mlsVal->field1 = field1; _mlsVal->field2 = field2; _mlsVal->field3 = field3; _mlsVal->field4 = field4; _mlsVal->field5 = field5; _mlsVal->field6 = field6; _mlsVal->field7 = field7; _mlsVal->field8 = field8; return _mlsValue(_mlsVal); } -//│ }; -//│ struct Tuple5: public _mlsObject { -//│ _mlsValue field0; -//│ _mlsValue field1; -//│ _mlsValue field2; -//│ _mlsValue field3; -//│ _mlsValue field4; -//│ constexpr static inline const char *typeName = "Tuple5"; -//│ constexpr static inline uint32_t typeTag = nextTypeTag(); -//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(", "); this->field1.print(); std::printf(", "); this->field2.print(); std::printf(", "); this->field3.print(); std::printf(", "); this->field4.print(); std::printf(")"); } -//│ virtual void destroy() override { _mlsValue::destroy(this->field0); _mlsValue::destroy(this->field1); _mlsValue::destroy(this->field2); _mlsValue::destroy(this->field3); _mlsValue::destroy(this->field4); operator delete (this, std::align_val_t(_mlsAlignment)); } -//│ static _mlsValue create(_mlsValue field0, _mlsValue field1, _mlsValue field2, _mlsValue field3, _mlsValue field4) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple5; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; _mlsVal->field1 = field1; _mlsVal->field2 = field2; _mlsVal->field3 = field3; _mlsVal->field4 = field4; return _mlsValue(_mlsVal); } -//│ }; //│ _mlsValue j(_mlsValue x1) { //│ _mlsValue _mls_retval; //│ auto x = (x1 + _mlsValue::fromIntLit(1)); diff --git a/hkmc2/shared/src/test/mlscript/llir/Classes.mls b/hkmc2/shared/src/test/mlscript/llir/Classes.mls index 7ad28722bc..7e5353fb06 100644 --- a/hkmc2/shared/src/test/mlscript/llir/Classes.mls +++ b/hkmc2/shared/src/test/mlscript/llir/Classes.mls @@ -27,21 +27,21 @@ fun main() = main() //│ LLIR: //│ class Base() { -//│ def get$307() = +//│ def get$226() = //│ 1 //│ } //│ class Derived() extends Base { -//│ def get$308() = +//│ def get$227() = //│ 2 //│ } -//│ def main$310() = -//│ let x$374 = Derived$315() in -//│ let x$375 = Base.get$307(x$374) in -//│ let x$376 = Derived.get$308(x$374) in -//│ let x$377 = *(x$375,x$376) in -//│ x$377 -//│ let* (x$378) = main() in -//│ x$378 +//│ def main$229() = +//│ let x$252 = Derived$234() in +//│ let x$253 = Base.get$226(x$252) in +//│ let x$254 = Derived.get$227(x$252) in +//│ let x$255 = *(x$253,x$254) in +//│ x$255 +//│ let* (x$256) = main() in +//│ x$256 //│ //│ Interpreted: //│ 4 diff --git a/hkmc2/shared/src/test/mlscript/llir/ControlFlow.mls b/hkmc2/shared/src/test/mlscript/llir/ControlFlow.mls index aa9e8a97e2..c28822bba7 100644 --- a/hkmc2/shared/src/test/mlscript/llir/ControlFlow.mls +++ b/hkmc2/shared/src/test/mlscript/llir/ControlFlow.mls @@ -14,12 +14,12 @@ f1() //│ = 2 //│ LLIR: //│ -//│ def f1$239() = -//│ let x$290 = 1 in -//│ let x$291 = 2 in -//│ x$291 -//│ let* (x$292) = f1() in -//│ x$292 +//│ def f1$198() = +//│ let x$208 = 1 in +//│ let x$209 = 2 in +//│ x$209 +//│ let* (x$210) = f1() in +//│ x$210 //│ //│ Interpreted: //│ 2 @@ -33,18 +33,18 @@ f2() //│ = 3 //│ LLIR: //│ -//│ def f2$293() = -//│ let x$345 = 0 in -//│ let x$346 = ==(x$345,1) in -//│ case x$346 of +//│ def f2$211() = +//│ let x$222 = 0 in +//│ let x$223 = ==(x$222,1) in +//│ case x$223 of //│ BoolLit(true) => //│ 2 //│ _ => //│ 3 -//│ def j$347() = +//│ def j$224() = //│ null -//│ let* (x$348) = f2() in -//│ x$348 +//│ let* (x$225) = f2() in +//│ x$225 //│ //│ Interpreted: //│ 3 @@ -59,19 +59,19 @@ f3() //│ = 0 //│ LLIR: //│ -//│ def f3$349() = -//│ let x$401 = 0 in -//│ let x$402 = 1 in -//│ let x$403 = true in -//│ case x$403 of +//│ def f3$226() = +//│ let x$237 = 0 in +//│ let x$238 = 1 in +//│ let x$239 = true in +//│ case x$239 of //│ BoolLit(true) => -//│ x$401 +//│ x$237 //│ _ => -//│ x$402 -//│ def j$404() = +//│ x$238 +//│ def j$240() = //│ null -//│ let* (x$405) = f3() in -//│ x$405 +//│ let* (x$241) = f3() in +//│ x$241 :sllir @@ -84,20 +84,20 @@ f4() //│ = 3 //│ LLIR: //│ -//│ def f4$406() = -//│ let x$461 = 0 in -//│ let x$462 = ==(x$461,1) in -//│ case x$462 of +//│ def f4$242() = +//│ let x$256 = 0 in +//│ let x$257 = ==(x$256,1) in +//│ case x$257 of //│ BoolLit(true) => -//│ let x$464 = 2 in -//│ jump j$463(x$464) +//│ let x$259 = 2 in +//│ jump j$258(x$259) //│ _ => -//│ let x$465 = 3 in -//│ jump j$463(x$465) -//│ def j$463(tmp$417) = -//│ tmp$417 -//│ let* (x$466) = f4() in -//│ x$466 +//│ let x$260 = 3 in +//│ jump j$258(x$260) +//│ def j$258(tmp$253) = +//│ tmp$253 +//│ let* (x$261) = f4() in +//│ x$261 //│ //│ Interpreted: //│ 3 @@ -113,29 +113,29 @@ f5() //│ = 5 //│ LLIR: //│ -//│ def f5$467() = -//│ let x$527 = 0 in -//│ let x$528 = ==(x$527,1) in -//│ case x$528 of +//│ def f5$262() = +//│ let x$281 = 0 in +//│ let x$282 = ==(x$281,1) in +//│ case x$282 of //│ BoolLit(true) => -//│ let x$530 = 2 in -//│ jump j$529(x$530) +//│ let x$284 = 2 in +//│ jump j$283(x$284) //│ _ => -//│ let x$531 = 3 in -//│ jump j$529(x$531) -//│ def j$529(tmp$482) = -//│ let x$532 = ==(tmp$482,2) in -//│ case x$532 of +//│ let x$285 = 3 in +//│ jump j$283(x$285) +//│ def j$283(tmp$277) = +//│ let x$286 = ==(tmp$277,2) in +//│ case x$286 of //│ BoolLit(true) => -//│ let x$534 = 4 in -//│ jump j$533(x$534) +//│ let x$288 = 4 in +//│ jump j$287(x$288) //│ _ => -//│ let x$535 = 5 in -//│ jump j$533(x$535) -//│ def j$533(tmp$483) = -//│ tmp$483 -//│ let* (x$536) = f5() in -//│ x$536 +//│ let x$289 = 5 in +//│ jump j$287(x$289) +//│ def j$287(tmp$278) = +//│ tmp$278 +//│ let* (x$290) = f5() in +//│ x$290 //│ //│ Interpreted: //│ 5 @@ -146,149 +146,23 @@ fun test() = if true do test() //│ LLIR: //│ -//│ def test$537() = -//│ let x$587 = true in -//│ case x$587 of +//│ def test$291() = +//│ let x$300 = true in +//│ case x$300 of //│ BoolLit(true) => -//│ let* (x$589) = test() in -//│ x$589 +//│ let* (x$302) = test() in +//│ x$302 //│ _ => //│ undefined -//│ def j$588() = +//│ def j$301() = //│ null //│ undefined //│ //│ Cpp: //│ #include "mlsprelude.h" -//│ struct Tuple4; -//│ struct Tuple3; -//│ struct Tuple2; -//│ struct Tuple8; -//│ struct Tuple0; -//│ struct Tuple1; -//│ struct Tuple7; -//│ struct Tuple6; -//│ struct Tuple9; -//│ struct Tuple5; //│ _mlsValue j(); //│ _mlsValue test(); //│ _mlsValue _mlsMain(); -//│ struct Tuple4: public _mlsObject { -//│ _mlsValue field0; -//│ _mlsValue field1; -//│ _mlsValue field2; -//│ _mlsValue field3; -//│ constexpr static inline const char *typeName = "Tuple4"; -//│ constexpr static inline uint32_t typeTag = nextTypeTag(); -//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(", "); this->field1.print(); std::printf(", "); this->field2.print(); std::printf(", "); this->field3.print(); std::printf(")"); } -//│ virtual void destroy() override { _mlsValue::destroy(this->field0); _mlsValue::destroy(this->field1); _mlsValue::destroy(this->field2); _mlsValue::destroy(this->field3); operator delete (this, std::align_val_t(_mlsAlignment)); } -//│ static _mlsValue create(_mlsValue field0, _mlsValue field1, _mlsValue field2, _mlsValue field3) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple4; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; _mlsVal->field1 = field1; _mlsVal->field2 = field2; _mlsVal->field3 = field3; return _mlsValue(_mlsVal); } -//│ }; -//│ struct Tuple3: public _mlsObject { -//│ _mlsValue field0; -//│ _mlsValue field1; -//│ _mlsValue field2; -//│ constexpr static inline const char *typeName = "Tuple3"; -//│ constexpr static inline uint32_t typeTag = nextTypeTag(); -//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(", "); this->field1.print(); std::printf(", "); this->field2.print(); std::printf(")"); } -//│ virtual void destroy() override { _mlsValue::destroy(this->field0); _mlsValue::destroy(this->field1); _mlsValue::destroy(this->field2); operator delete (this, std::align_val_t(_mlsAlignment)); } -//│ static _mlsValue create(_mlsValue field0, _mlsValue field1, _mlsValue field2) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple3; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; _mlsVal->field1 = field1; _mlsVal->field2 = field2; return _mlsValue(_mlsVal); } -//│ }; -//│ struct Tuple2: public _mlsObject { -//│ _mlsValue field0; -//│ _mlsValue field1; -//│ constexpr static inline const char *typeName = "Tuple2"; -//│ constexpr static inline uint32_t typeTag = nextTypeTag(); -//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(", "); this->field1.print(); std::printf(")"); } -//│ virtual void destroy() override { _mlsValue::destroy(this->field0); _mlsValue::destroy(this->field1); operator delete (this, std::align_val_t(_mlsAlignment)); } -//│ static _mlsValue create(_mlsValue field0, _mlsValue field1) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple2; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; _mlsVal->field1 = field1; return _mlsValue(_mlsVal); } -//│ }; -//│ struct Tuple8: public _mlsObject { -//│ _mlsValue field0; -//│ _mlsValue field1; -//│ _mlsValue field2; -//│ _mlsValue field3; -//│ _mlsValue field4; -//│ _mlsValue field5; -//│ _mlsValue field6; -//│ _mlsValue field7; -//│ constexpr static inline const char *typeName = "Tuple8"; -//│ constexpr static inline uint32_t typeTag = nextTypeTag(); -//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(", "); this->field1.print(); std::printf(", "); this->field2.print(); std::printf(", "); this->field3.print(); std::printf(", "); this->field4.print(); std::printf(", "); this->field5.print(); std::printf(", "); this->field6.print(); std::printf(", "); this->field7.print(); std::printf(")"); } -//│ virtual void destroy() override { _mlsValue::destroy(this->field0); _mlsValue::destroy(this->field1); _mlsValue::destroy(this->field2); _mlsValue::destroy(this->field3); _mlsValue::destroy(this->field4); _mlsValue::destroy(this->field5); _mlsValue::destroy(this->field6); _mlsValue::destroy(this->field7); operator delete (this, std::align_val_t(_mlsAlignment)); } -//│ static _mlsValue create(_mlsValue field0, _mlsValue field1, _mlsValue field2, _mlsValue field3, _mlsValue field4, _mlsValue field5, _mlsValue field6, _mlsValue field7) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple8; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; _mlsVal->field1 = field1; _mlsVal->field2 = field2; _mlsVal->field3 = field3; _mlsVal->field4 = field4; _mlsVal->field5 = field5; _mlsVal->field6 = field6; _mlsVal->field7 = field7; return _mlsValue(_mlsVal); } -//│ }; -//│ struct Tuple0: public _mlsObject { -//│ -//│ constexpr static inline const char *typeName = "Tuple0"; -//│ constexpr static inline uint32_t typeTag = nextTypeTag(); -//│ virtual void print() const override { std::printf("%s", typeName); } -//│ virtual void destroy() override { operator delete (this, std::align_val_t(_mlsAlignment)); } -//│ static _mlsValue create() { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple0; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; return _mlsValue(_mlsVal); } -//│ }; -//│ struct Tuple1: public _mlsObject { -//│ _mlsValue field0; -//│ constexpr static inline const char *typeName = "Tuple1"; -//│ constexpr static inline uint32_t typeTag = nextTypeTag(); -//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(")"); } -//│ virtual void destroy() override { _mlsValue::destroy(this->field0); operator delete (this, std::align_val_t(_mlsAlignment)); } -//│ static _mlsValue create(_mlsValue field0) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple1; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; return _mlsValue(_mlsVal); } -//│ }; -//│ struct Tuple7: public _mlsObject { -//│ _mlsValue field0; -//│ _mlsValue field1; -//│ _mlsValue field2; -//│ _mlsValue field3; -//│ _mlsValue field4; -//│ _mlsValue field5; -//│ _mlsValue field6; -//│ constexpr static inline const char *typeName = "Tuple7"; -//│ constexpr static inline uint32_t typeTag = nextTypeTag(); -//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(", "); this->field1.print(); std::printf(", "); this->field2.print(); std::printf(", "); this->field3.print(); std::printf(", "); this->field4.print(); std::printf(", "); this->field5.print(); std::printf(", "); this->field6.print(); std::printf(")"); } -//│ virtual void destroy() override { _mlsValue::destroy(this->field0); _mlsValue::destroy(this->field1); _mlsValue::destroy(this->field2); _mlsValue::destroy(this->field3); _mlsValue::destroy(this->field4); _mlsValue::destroy(this->field5); _mlsValue::destroy(this->field6); operator delete (this, std::align_val_t(_mlsAlignment)); } -//│ static _mlsValue create(_mlsValue field0, _mlsValue field1, _mlsValue field2, _mlsValue field3, _mlsValue field4, _mlsValue field5, _mlsValue field6) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple7; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; _mlsVal->field1 = field1; _mlsVal->field2 = field2; _mlsVal->field3 = field3; _mlsVal->field4 = field4; _mlsVal->field5 = field5; _mlsVal->field6 = field6; return _mlsValue(_mlsVal); } -//│ }; -//│ struct Tuple6: public _mlsObject { -//│ _mlsValue field0; -//│ _mlsValue field1; -//│ _mlsValue field2; -//│ _mlsValue field3; -//│ _mlsValue field4; -//│ _mlsValue field5; -//│ constexpr static inline const char *typeName = "Tuple6"; -//│ constexpr static inline uint32_t typeTag = nextTypeTag(); -//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(", "); this->field1.print(); std::printf(", "); this->field2.print(); std::printf(", "); this->field3.print(); std::printf(", "); this->field4.print(); std::printf(", "); this->field5.print(); std::printf(")"); } -//│ virtual void destroy() override { _mlsValue::destroy(this->field0); _mlsValue::destroy(this->field1); _mlsValue::destroy(this->field2); _mlsValue::destroy(this->field3); _mlsValue::destroy(this->field4); _mlsValue::destroy(this->field5); operator delete (this, std::align_val_t(_mlsAlignment)); } -//│ static _mlsValue create(_mlsValue field0, _mlsValue field1, _mlsValue field2, _mlsValue field3, _mlsValue field4, _mlsValue field5) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple6; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; _mlsVal->field1 = field1; _mlsVal->field2 = field2; _mlsVal->field3 = field3; _mlsVal->field4 = field4; _mlsVal->field5 = field5; return _mlsValue(_mlsVal); } -//│ }; -//│ struct Tuple9: public _mlsObject { -//│ _mlsValue field0; -//│ _mlsValue field1; -//│ _mlsValue field2; -//│ _mlsValue field3; -//│ _mlsValue field4; -//│ _mlsValue field5; -//│ _mlsValue field6; -//│ _mlsValue field7; -//│ _mlsValue field8; -//│ constexpr static inline const char *typeName = "Tuple9"; -//│ constexpr static inline uint32_t typeTag = nextTypeTag(); -//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(", "); this->field1.print(); std::printf(", "); this->field2.print(); std::printf(", "); this->field3.print(); std::printf(", "); this->field4.print(); std::printf(", "); this->field5.print(); std::printf(", "); this->field6.print(); std::printf(", "); this->field7.print(); std::printf(", "); this->field8.print(); std::printf(")"); } -//│ virtual void destroy() override { _mlsValue::destroy(this->field0); _mlsValue::destroy(this->field1); _mlsValue::destroy(this->field2); _mlsValue::destroy(this->field3); _mlsValue::destroy(this->field4); _mlsValue::destroy(this->field5); _mlsValue::destroy(this->field6); _mlsValue::destroy(this->field7); _mlsValue::destroy(this->field8); operator delete (this, std::align_val_t(_mlsAlignment)); } -//│ static _mlsValue create(_mlsValue field0, _mlsValue field1, _mlsValue field2, _mlsValue field3, _mlsValue field4, _mlsValue field5, _mlsValue field6, _mlsValue field7, _mlsValue field8) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple9; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; _mlsVal->field1 = field1; _mlsVal->field2 = field2; _mlsVal->field3 = field3; _mlsVal->field4 = field4; _mlsVal->field5 = field5; _mlsVal->field6 = field6; _mlsVal->field7 = field7; _mlsVal->field8 = field8; return _mlsValue(_mlsVal); } -//│ }; -//│ struct Tuple5: public _mlsObject { -//│ _mlsValue field0; -//│ _mlsValue field1; -//│ _mlsValue field2; -//│ _mlsValue field3; -//│ _mlsValue field4; -//│ constexpr static inline const char *typeName = "Tuple5"; -//│ constexpr static inline uint32_t typeTag = nextTypeTag(); -//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(", "); this->field1.print(); std::printf(", "); this->field2.print(); std::printf(", "); this->field3.print(); std::printf(", "); this->field4.print(); std::printf(")"); } -//│ virtual void destroy() override { _mlsValue::destroy(this->field0); _mlsValue::destroy(this->field1); _mlsValue::destroy(this->field2); _mlsValue::destroy(this->field3); _mlsValue::destroy(this->field4); operator delete (this, std::align_val_t(_mlsAlignment)); } -//│ static _mlsValue create(_mlsValue field0, _mlsValue field1, _mlsValue field2, _mlsValue field3, _mlsValue field4) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple5; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; _mlsVal->field1 = field1; _mlsVal->field2 = field2; _mlsVal->field3 = field3; _mlsVal->field4 = field4; return _mlsValue(_mlsVal); } -//│ }; //│ _mlsValue j() { //│ _mlsValue _mls_retval; //│ _mls_retval = _mlsValue::create<_mls_Unit>(); @@ -318,150 +192,24 @@ fun test() = (if true then test()) + 1 //│ LLIR: //│ -//│ def test$590() = -//│ let x$643 = true in -//│ case x$643 of +//│ def test$303() = +//│ let x$315 = true in +//│ case x$315 of //│ BoolLit(true) => -//│ let* (x$645) = test() in -//│ jump j$644(x$645) +//│ let* (x$317) = test() in +//│ jump j$316(x$317) //│ _ => //│ panic "match error" -//│ def j$644(tmp$600) = -//│ let x$646 = +(tmp$600,1) in -//│ x$646 +//│ def j$316(tmp$313) = +//│ let x$318 = +(tmp$313,1) in +//│ x$318 //│ undefined //│ //│ Cpp: //│ #include "mlsprelude.h" -//│ struct Tuple4; -//│ struct Tuple3; -//│ struct Tuple2; -//│ struct Tuple8; -//│ struct Tuple0; -//│ struct Tuple1; -//│ struct Tuple7; -//│ struct Tuple6; -//│ struct Tuple9; -//│ struct Tuple5; //│ _mlsValue j(_mlsValue); //│ _mlsValue test(); //│ _mlsValue _mlsMain(); -//│ struct Tuple4: public _mlsObject { -//│ _mlsValue field0; -//│ _mlsValue field1; -//│ _mlsValue field2; -//│ _mlsValue field3; -//│ constexpr static inline const char *typeName = "Tuple4"; -//│ constexpr static inline uint32_t typeTag = nextTypeTag(); -//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(", "); this->field1.print(); std::printf(", "); this->field2.print(); std::printf(", "); this->field3.print(); std::printf(")"); } -//│ virtual void destroy() override { _mlsValue::destroy(this->field0); _mlsValue::destroy(this->field1); _mlsValue::destroy(this->field2); _mlsValue::destroy(this->field3); operator delete (this, std::align_val_t(_mlsAlignment)); } -//│ static _mlsValue create(_mlsValue field0, _mlsValue field1, _mlsValue field2, _mlsValue field3) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple4; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; _mlsVal->field1 = field1; _mlsVal->field2 = field2; _mlsVal->field3 = field3; return _mlsValue(_mlsVal); } -//│ }; -//│ struct Tuple3: public _mlsObject { -//│ _mlsValue field0; -//│ _mlsValue field1; -//│ _mlsValue field2; -//│ constexpr static inline const char *typeName = "Tuple3"; -//│ constexpr static inline uint32_t typeTag = nextTypeTag(); -//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(", "); this->field1.print(); std::printf(", "); this->field2.print(); std::printf(")"); } -//│ virtual void destroy() override { _mlsValue::destroy(this->field0); _mlsValue::destroy(this->field1); _mlsValue::destroy(this->field2); operator delete (this, std::align_val_t(_mlsAlignment)); } -//│ static _mlsValue create(_mlsValue field0, _mlsValue field1, _mlsValue field2) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple3; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; _mlsVal->field1 = field1; _mlsVal->field2 = field2; return _mlsValue(_mlsVal); } -//│ }; -//│ struct Tuple2: public _mlsObject { -//│ _mlsValue field0; -//│ _mlsValue field1; -//│ constexpr static inline const char *typeName = "Tuple2"; -//│ constexpr static inline uint32_t typeTag = nextTypeTag(); -//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(", "); this->field1.print(); std::printf(")"); } -//│ virtual void destroy() override { _mlsValue::destroy(this->field0); _mlsValue::destroy(this->field1); operator delete (this, std::align_val_t(_mlsAlignment)); } -//│ static _mlsValue create(_mlsValue field0, _mlsValue field1) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple2; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; _mlsVal->field1 = field1; return _mlsValue(_mlsVal); } -//│ }; -//│ struct Tuple8: public _mlsObject { -//│ _mlsValue field0; -//│ _mlsValue field1; -//│ _mlsValue field2; -//│ _mlsValue field3; -//│ _mlsValue field4; -//│ _mlsValue field5; -//│ _mlsValue field6; -//│ _mlsValue field7; -//│ constexpr static inline const char *typeName = "Tuple8"; -//│ constexpr static inline uint32_t typeTag = nextTypeTag(); -//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(", "); this->field1.print(); std::printf(", "); this->field2.print(); std::printf(", "); this->field3.print(); std::printf(", "); this->field4.print(); std::printf(", "); this->field5.print(); std::printf(", "); this->field6.print(); std::printf(", "); this->field7.print(); std::printf(")"); } -//│ virtual void destroy() override { _mlsValue::destroy(this->field0); _mlsValue::destroy(this->field1); _mlsValue::destroy(this->field2); _mlsValue::destroy(this->field3); _mlsValue::destroy(this->field4); _mlsValue::destroy(this->field5); _mlsValue::destroy(this->field6); _mlsValue::destroy(this->field7); operator delete (this, std::align_val_t(_mlsAlignment)); } -//│ static _mlsValue create(_mlsValue field0, _mlsValue field1, _mlsValue field2, _mlsValue field3, _mlsValue field4, _mlsValue field5, _mlsValue field6, _mlsValue field7) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple8; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; _mlsVal->field1 = field1; _mlsVal->field2 = field2; _mlsVal->field3 = field3; _mlsVal->field4 = field4; _mlsVal->field5 = field5; _mlsVal->field6 = field6; _mlsVal->field7 = field7; return _mlsValue(_mlsVal); } -//│ }; -//│ struct Tuple0: public _mlsObject { -//│ -//│ constexpr static inline const char *typeName = "Tuple0"; -//│ constexpr static inline uint32_t typeTag = nextTypeTag(); -//│ virtual void print() const override { std::printf("%s", typeName); } -//│ virtual void destroy() override { operator delete (this, std::align_val_t(_mlsAlignment)); } -//│ static _mlsValue create() { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple0; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; return _mlsValue(_mlsVal); } -//│ }; -//│ struct Tuple1: public _mlsObject { -//│ _mlsValue field0; -//│ constexpr static inline const char *typeName = "Tuple1"; -//│ constexpr static inline uint32_t typeTag = nextTypeTag(); -//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(")"); } -//│ virtual void destroy() override { _mlsValue::destroy(this->field0); operator delete (this, std::align_val_t(_mlsAlignment)); } -//│ static _mlsValue create(_mlsValue field0) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple1; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; return _mlsValue(_mlsVal); } -//│ }; -//│ struct Tuple7: public _mlsObject { -//│ _mlsValue field0; -//│ _mlsValue field1; -//│ _mlsValue field2; -//│ _mlsValue field3; -//│ _mlsValue field4; -//│ _mlsValue field5; -//│ _mlsValue field6; -//│ constexpr static inline const char *typeName = "Tuple7"; -//│ constexpr static inline uint32_t typeTag = nextTypeTag(); -//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(", "); this->field1.print(); std::printf(", "); this->field2.print(); std::printf(", "); this->field3.print(); std::printf(", "); this->field4.print(); std::printf(", "); this->field5.print(); std::printf(", "); this->field6.print(); std::printf(")"); } -//│ virtual void destroy() override { _mlsValue::destroy(this->field0); _mlsValue::destroy(this->field1); _mlsValue::destroy(this->field2); _mlsValue::destroy(this->field3); _mlsValue::destroy(this->field4); _mlsValue::destroy(this->field5); _mlsValue::destroy(this->field6); operator delete (this, std::align_val_t(_mlsAlignment)); } -//│ static _mlsValue create(_mlsValue field0, _mlsValue field1, _mlsValue field2, _mlsValue field3, _mlsValue field4, _mlsValue field5, _mlsValue field6) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple7; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; _mlsVal->field1 = field1; _mlsVal->field2 = field2; _mlsVal->field3 = field3; _mlsVal->field4 = field4; _mlsVal->field5 = field5; _mlsVal->field6 = field6; return _mlsValue(_mlsVal); } -//│ }; -//│ struct Tuple6: public _mlsObject { -//│ _mlsValue field0; -//│ _mlsValue field1; -//│ _mlsValue field2; -//│ _mlsValue field3; -//│ _mlsValue field4; -//│ _mlsValue field5; -//│ constexpr static inline const char *typeName = "Tuple6"; -//│ constexpr static inline uint32_t typeTag = nextTypeTag(); -//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(", "); this->field1.print(); std::printf(", "); this->field2.print(); std::printf(", "); this->field3.print(); std::printf(", "); this->field4.print(); std::printf(", "); this->field5.print(); std::printf(")"); } -//│ virtual void destroy() override { _mlsValue::destroy(this->field0); _mlsValue::destroy(this->field1); _mlsValue::destroy(this->field2); _mlsValue::destroy(this->field3); _mlsValue::destroy(this->field4); _mlsValue::destroy(this->field5); operator delete (this, std::align_val_t(_mlsAlignment)); } -//│ static _mlsValue create(_mlsValue field0, _mlsValue field1, _mlsValue field2, _mlsValue field3, _mlsValue field4, _mlsValue field5) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple6; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; _mlsVal->field1 = field1; _mlsVal->field2 = field2; _mlsVal->field3 = field3; _mlsVal->field4 = field4; _mlsVal->field5 = field5; return _mlsValue(_mlsVal); } -//│ }; -//│ struct Tuple9: public _mlsObject { -//│ _mlsValue field0; -//│ _mlsValue field1; -//│ _mlsValue field2; -//│ _mlsValue field3; -//│ _mlsValue field4; -//│ _mlsValue field5; -//│ _mlsValue field6; -//│ _mlsValue field7; -//│ _mlsValue field8; -//│ constexpr static inline const char *typeName = "Tuple9"; -//│ constexpr static inline uint32_t typeTag = nextTypeTag(); -//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(", "); this->field1.print(); std::printf(", "); this->field2.print(); std::printf(", "); this->field3.print(); std::printf(", "); this->field4.print(); std::printf(", "); this->field5.print(); std::printf(", "); this->field6.print(); std::printf(", "); this->field7.print(); std::printf(", "); this->field8.print(); std::printf(")"); } -//│ virtual void destroy() override { _mlsValue::destroy(this->field0); _mlsValue::destroy(this->field1); _mlsValue::destroy(this->field2); _mlsValue::destroy(this->field3); _mlsValue::destroy(this->field4); _mlsValue::destroy(this->field5); _mlsValue::destroy(this->field6); _mlsValue::destroy(this->field7); _mlsValue::destroy(this->field8); operator delete (this, std::align_val_t(_mlsAlignment)); } -//│ static _mlsValue create(_mlsValue field0, _mlsValue field1, _mlsValue field2, _mlsValue field3, _mlsValue field4, _mlsValue field5, _mlsValue field6, _mlsValue field7, _mlsValue field8) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple9; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; _mlsVal->field1 = field1; _mlsVal->field2 = field2; _mlsVal->field3 = field3; _mlsVal->field4 = field4; _mlsVal->field5 = field5; _mlsVal->field6 = field6; _mlsVal->field7 = field7; _mlsVal->field8 = field8; return _mlsValue(_mlsVal); } -//│ }; -//│ struct Tuple5: public _mlsObject { -//│ _mlsValue field0; -//│ _mlsValue field1; -//│ _mlsValue field2; -//│ _mlsValue field3; -//│ _mlsValue field4; -//│ constexpr static inline const char *typeName = "Tuple5"; -//│ constexpr static inline uint32_t typeTag = nextTypeTag(); -//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(", "); this->field1.print(); std::printf(", "); this->field2.print(); std::printf(", "); this->field3.print(); std::printf(", "); this->field4.print(); std::printf(")"); } -//│ virtual void destroy() override { _mlsValue::destroy(this->field0); _mlsValue::destroy(this->field1); _mlsValue::destroy(this->field2); _mlsValue::destroy(this->field3); _mlsValue::destroy(this->field4); operator delete (this, std::align_val_t(_mlsAlignment)); } -//│ static _mlsValue create(_mlsValue field0, _mlsValue field1, _mlsValue field2, _mlsValue field3, _mlsValue field4) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple5; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; _mlsVal->field1 = field1; _mlsVal->field2 = field2; _mlsVal->field3 = field3; _mlsVal->field4 = field4; return _mlsValue(_mlsVal); } -//│ }; //│ _mlsValue j(_mlsValue tmp) { //│ _mlsValue _mls_retval; //│ auto x = (tmp + _mlsValue::fromIntLit(1)); @@ -499,153 +247,27 @@ f() //│ = 11 //│ LLIR: //│ -//│ def f$647() = -//│ let x$703 = 10 in -//│ let x$704 = true in -//│ case x$704 of +//│ def f$319() = +//│ let x$334 = 10 in +//│ let x$335 = true in +//│ case x$335 of //│ BoolLit(true) => -//│ let x$706 = +(x$703,1) in -//│ let x$707 = undefined in -//│ jump j$705(x$706) +//│ let x$337 = +(x$334,1) in +//│ let x$338 = undefined in +//│ jump j$336(x$337) //│ _ => -//│ let x$708 = undefined in -//│ jump j$705(x$703) -//│ def j$705(x$648) = -//│ x$648 -//│ let* (x$709) = f() in -//│ x$709 +//│ let x$339 = undefined in +//│ jump j$336(x$334) +//│ def j$336(x$320) = +//│ x$320 +//│ let* (x$340) = f() in +//│ x$340 //│ //│ Cpp: //│ #include "mlsprelude.h" -//│ struct Tuple4; -//│ struct Tuple3; -//│ struct Tuple2; -//│ struct Tuple8; -//│ struct Tuple0; -//│ struct Tuple1; -//│ struct Tuple7; -//│ struct Tuple6; -//│ struct Tuple9; -//│ struct Tuple5; //│ _mlsValue j(_mlsValue); //│ _mlsValue f(); //│ _mlsValue _mlsMain(); -//│ struct Tuple4: public _mlsObject { -//│ _mlsValue field0; -//│ _mlsValue field1; -//│ _mlsValue field2; -//│ _mlsValue field3; -//│ constexpr static inline const char *typeName = "Tuple4"; -//│ constexpr static inline uint32_t typeTag = nextTypeTag(); -//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(", "); this->field1.print(); std::printf(", "); this->field2.print(); std::printf(", "); this->field3.print(); std::printf(")"); } -//│ virtual void destroy() override { _mlsValue::destroy(this->field0); _mlsValue::destroy(this->field1); _mlsValue::destroy(this->field2); _mlsValue::destroy(this->field3); operator delete (this, std::align_val_t(_mlsAlignment)); } -//│ static _mlsValue create(_mlsValue field0, _mlsValue field1, _mlsValue field2, _mlsValue field3) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple4; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; _mlsVal->field1 = field1; _mlsVal->field2 = field2; _mlsVal->field3 = field3; return _mlsValue(_mlsVal); } -//│ }; -//│ struct Tuple3: public _mlsObject { -//│ _mlsValue field0; -//│ _mlsValue field1; -//│ _mlsValue field2; -//│ constexpr static inline const char *typeName = "Tuple3"; -//│ constexpr static inline uint32_t typeTag = nextTypeTag(); -//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(", "); this->field1.print(); std::printf(", "); this->field2.print(); std::printf(")"); } -//│ virtual void destroy() override { _mlsValue::destroy(this->field0); _mlsValue::destroy(this->field1); _mlsValue::destroy(this->field2); operator delete (this, std::align_val_t(_mlsAlignment)); } -//│ static _mlsValue create(_mlsValue field0, _mlsValue field1, _mlsValue field2) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple3; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; _mlsVal->field1 = field1; _mlsVal->field2 = field2; return _mlsValue(_mlsVal); } -//│ }; -//│ struct Tuple2: public _mlsObject { -//│ _mlsValue field0; -//│ _mlsValue field1; -//│ constexpr static inline const char *typeName = "Tuple2"; -//│ constexpr static inline uint32_t typeTag = nextTypeTag(); -//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(", "); this->field1.print(); std::printf(")"); } -//│ virtual void destroy() override { _mlsValue::destroy(this->field0); _mlsValue::destroy(this->field1); operator delete (this, std::align_val_t(_mlsAlignment)); } -//│ static _mlsValue create(_mlsValue field0, _mlsValue field1) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple2; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; _mlsVal->field1 = field1; return _mlsValue(_mlsVal); } -//│ }; -//│ struct Tuple8: public _mlsObject { -//│ _mlsValue field0; -//│ _mlsValue field1; -//│ _mlsValue field2; -//│ _mlsValue field3; -//│ _mlsValue field4; -//│ _mlsValue field5; -//│ _mlsValue field6; -//│ _mlsValue field7; -//│ constexpr static inline const char *typeName = "Tuple8"; -//│ constexpr static inline uint32_t typeTag = nextTypeTag(); -//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(", "); this->field1.print(); std::printf(", "); this->field2.print(); std::printf(", "); this->field3.print(); std::printf(", "); this->field4.print(); std::printf(", "); this->field5.print(); std::printf(", "); this->field6.print(); std::printf(", "); this->field7.print(); std::printf(")"); } -//│ virtual void destroy() override { _mlsValue::destroy(this->field0); _mlsValue::destroy(this->field1); _mlsValue::destroy(this->field2); _mlsValue::destroy(this->field3); _mlsValue::destroy(this->field4); _mlsValue::destroy(this->field5); _mlsValue::destroy(this->field6); _mlsValue::destroy(this->field7); operator delete (this, std::align_val_t(_mlsAlignment)); } -//│ static _mlsValue create(_mlsValue field0, _mlsValue field1, _mlsValue field2, _mlsValue field3, _mlsValue field4, _mlsValue field5, _mlsValue field6, _mlsValue field7) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple8; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; _mlsVal->field1 = field1; _mlsVal->field2 = field2; _mlsVal->field3 = field3; _mlsVal->field4 = field4; _mlsVal->field5 = field5; _mlsVal->field6 = field6; _mlsVal->field7 = field7; return _mlsValue(_mlsVal); } -//│ }; -//│ struct Tuple0: public _mlsObject { -//│ -//│ constexpr static inline const char *typeName = "Tuple0"; -//│ constexpr static inline uint32_t typeTag = nextTypeTag(); -//│ virtual void print() const override { std::printf("%s", typeName); } -//│ virtual void destroy() override { operator delete (this, std::align_val_t(_mlsAlignment)); } -//│ static _mlsValue create() { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple0; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; return _mlsValue(_mlsVal); } -//│ }; -//│ struct Tuple1: public _mlsObject { -//│ _mlsValue field0; -//│ constexpr static inline const char *typeName = "Tuple1"; -//│ constexpr static inline uint32_t typeTag = nextTypeTag(); -//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(")"); } -//│ virtual void destroy() override { _mlsValue::destroy(this->field0); operator delete (this, std::align_val_t(_mlsAlignment)); } -//│ static _mlsValue create(_mlsValue field0) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple1; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; return _mlsValue(_mlsVal); } -//│ }; -//│ struct Tuple7: public _mlsObject { -//│ _mlsValue field0; -//│ _mlsValue field1; -//│ _mlsValue field2; -//│ _mlsValue field3; -//│ _mlsValue field4; -//│ _mlsValue field5; -//│ _mlsValue field6; -//│ constexpr static inline const char *typeName = "Tuple7"; -//│ constexpr static inline uint32_t typeTag = nextTypeTag(); -//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(", "); this->field1.print(); std::printf(", "); this->field2.print(); std::printf(", "); this->field3.print(); std::printf(", "); this->field4.print(); std::printf(", "); this->field5.print(); std::printf(", "); this->field6.print(); std::printf(")"); } -//│ virtual void destroy() override { _mlsValue::destroy(this->field0); _mlsValue::destroy(this->field1); _mlsValue::destroy(this->field2); _mlsValue::destroy(this->field3); _mlsValue::destroy(this->field4); _mlsValue::destroy(this->field5); _mlsValue::destroy(this->field6); operator delete (this, std::align_val_t(_mlsAlignment)); } -//│ static _mlsValue create(_mlsValue field0, _mlsValue field1, _mlsValue field2, _mlsValue field3, _mlsValue field4, _mlsValue field5, _mlsValue field6) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple7; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; _mlsVal->field1 = field1; _mlsVal->field2 = field2; _mlsVal->field3 = field3; _mlsVal->field4 = field4; _mlsVal->field5 = field5; _mlsVal->field6 = field6; return _mlsValue(_mlsVal); } -//│ }; -//│ struct Tuple6: public _mlsObject { -//│ _mlsValue field0; -//│ _mlsValue field1; -//│ _mlsValue field2; -//│ _mlsValue field3; -//│ _mlsValue field4; -//│ _mlsValue field5; -//│ constexpr static inline const char *typeName = "Tuple6"; -//│ constexpr static inline uint32_t typeTag = nextTypeTag(); -//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(", "); this->field1.print(); std::printf(", "); this->field2.print(); std::printf(", "); this->field3.print(); std::printf(", "); this->field4.print(); std::printf(", "); this->field5.print(); std::printf(")"); } -//│ virtual void destroy() override { _mlsValue::destroy(this->field0); _mlsValue::destroy(this->field1); _mlsValue::destroy(this->field2); _mlsValue::destroy(this->field3); _mlsValue::destroy(this->field4); _mlsValue::destroy(this->field5); operator delete (this, std::align_val_t(_mlsAlignment)); } -//│ static _mlsValue create(_mlsValue field0, _mlsValue field1, _mlsValue field2, _mlsValue field3, _mlsValue field4, _mlsValue field5) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple6; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; _mlsVal->field1 = field1; _mlsVal->field2 = field2; _mlsVal->field3 = field3; _mlsVal->field4 = field4; _mlsVal->field5 = field5; return _mlsValue(_mlsVal); } -//│ }; -//│ struct Tuple9: public _mlsObject { -//│ _mlsValue field0; -//│ _mlsValue field1; -//│ _mlsValue field2; -//│ _mlsValue field3; -//│ _mlsValue field4; -//│ _mlsValue field5; -//│ _mlsValue field6; -//│ _mlsValue field7; -//│ _mlsValue field8; -//│ constexpr static inline const char *typeName = "Tuple9"; -//│ constexpr static inline uint32_t typeTag = nextTypeTag(); -//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(", "); this->field1.print(); std::printf(", "); this->field2.print(); std::printf(", "); this->field3.print(); std::printf(", "); this->field4.print(); std::printf(", "); this->field5.print(); std::printf(", "); this->field6.print(); std::printf(", "); this->field7.print(); std::printf(", "); this->field8.print(); std::printf(")"); } -//│ virtual void destroy() override { _mlsValue::destroy(this->field0); _mlsValue::destroy(this->field1); _mlsValue::destroy(this->field2); _mlsValue::destroy(this->field3); _mlsValue::destroy(this->field4); _mlsValue::destroy(this->field5); _mlsValue::destroy(this->field6); _mlsValue::destroy(this->field7); _mlsValue::destroy(this->field8); operator delete (this, std::align_val_t(_mlsAlignment)); } -//│ static _mlsValue create(_mlsValue field0, _mlsValue field1, _mlsValue field2, _mlsValue field3, _mlsValue field4, _mlsValue field5, _mlsValue field6, _mlsValue field7, _mlsValue field8) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple9; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; _mlsVal->field1 = field1; _mlsVal->field2 = field2; _mlsVal->field3 = field3; _mlsVal->field4 = field4; _mlsVal->field5 = field5; _mlsVal->field6 = field6; _mlsVal->field7 = field7; _mlsVal->field8 = field8; return _mlsValue(_mlsVal); } -//│ }; -//│ struct Tuple5: public _mlsObject { -//│ _mlsValue field0; -//│ _mlsValue field1; -//│ _mlsValue field2; -//│ _mlsValue field3; -//│ _mlsValue field4; -//│ constexpr static inline const char *typeName = "Tuple5"; -//│ constexpr static inline uint32_t typeTag = nextTypeTag(); -//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(", "); this->field1.print(); std::printf(", "); this->field2.print(); std::printf(", "); this->field3.print(); std::printf(", "); this->field4.print(); std::printf(")"); } -//│ virtual void destroy() override { _mlsValue::destroy(this->field0); _mlsValue::destroy(this->field1); _mlsValue::destroy(this->field2); _mlsValue::destroy(this->field3); _mlsValue::destroy(this->field4); operator delete (this, std::align_val_t(_mlsAlignment)); } -//│ static _mlsValue create(_mlsValue field0, _mlsValue field1, _mlsValue field2, _mlsValue field3, _mlsValue field4) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple5; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; _mlsVal->field1 = field1; _mlsVal->field2 = field2; _mlsVal->field3 = field3; _mlsVal->field4 = field4; return _mlsValue(_mlsVal); } -//│ }; //│ _mlsValue j(_mlsValue x) { //│ _mlsValue _mls_retval; //│ _mls_retval = x; @@ -688,29 +310,29 @@ fun f(a) = f(A(1)) //│ = 1 //│ LLIR: -//│ class A(x$715) -//│ class B(y$718) -//│ def f$712(a$719) = -//│ case a$719 of -//│ A$713 => -//│ let x$781 = a$719. in -//│ let x$782 = 1 in -//│ jump j$780(x$782) +//│ class A(x$346) +//│ class B(y$349) +//│ def f$343(a$350) = +//│ case a$350 of +//│ A$344 => +//│ let x$371 = a$350. in +//│ let x$372 = 1 in +//│ jump j$370(x$372) //│ _ => -//│ case a$719 of -//│ B$716 => -//│ let x$784 = a$719. in -//│ let x$785 = 2 in -//│ jump j$783(x$785) +//│ case a$350 of +//│ B$347 => +//│ let x$374 = a$350. in +//│ let x$375 = 2 in +//│ jump j$373(x$375) //│ _ => //│ panic "match error" -//│ def j$783(tmp$734) = -//│ jump j$780(tmp$734) -//│ def j$780(tmp$734) = -//│ tmp$734 -//│ let x$786 = A$713(1) in -//│ let* (x$787) = f(x$786) in -//│ x$787 +//│ def j$373(tmp$365) = +//│ jump j$370(tmp$365) +//│ def j$370(tmp$365) = +//│ tmp$365 +//│ let x$376 = A$344(1) in +//│ let* (x$377) = f(x$376) in +//│ x$377 //│ //│ Interpreted: //│ 1 @@ -729,50 +351,50 @@ fun f(a) = f(A(1)) //│ = 1 //│ LLIR: -//│ class A(x$793) -//│ class B(y$796) -//│ def f$790(a$797) = -//│ case a$797 of -//│ A$791 => -//│ let x$863 = a$797. in -//│ case a$797 of -//│ A$791 => -//│ let x$865 = a$797. in -//│ case x$865 of +//│ class A(x$383) +//│ class B(y$386) +//│ def f$380(a$387) = +//│ case a$387 of +//│ A$381 => +//│ let x$412 = a$387. in +//│ case a$387 of +//│ A$381 => +//│ let x$414 = a$387. in +//│ case x$414 of //│ IntLit(1) => -//│ let x$867 = 1 in -//│ jump j$866(x$867) +//│ let x$416 = 1 in +//│ jump j$415(x$416) //│ _ => //│ panic "match error" //│ _ => -//│ case a$797 of -//│ B$794 => -//│ let x$869 = a$797. in -//│ let x$870 = 2 in -//│ jump j$868(x$870) +//│ case a$387 of +//│ B$384 => +//│ let x$418 = a$387. in +//│ let x$419 = 2 in +//│ jump j$417(x$419) //│ _ => //│ panic "match error" //│ _ => -//│ case a$797 of -//│ B$794 => -//│ let x$872 = a$797. in -//│ let x$873 = 3 in -//│ jump j$871(x$873) +//│ case a$387 of +//│ B$384 => +//│ let x$421 = a$387. in +//│ let x$422 = 3 in +//│ jump j$420(x$422) //│ _ => //│ panic "match error" -//│ def j$866(tmp$815) = -//│ jump j$864(tmp$815) -//│ def j$868(tmp$815) = -//│ jump j$864(tmp$815) -//│ def j$864(tmp$815) = -//│ jump j$862(tmp$815) -//│ def j$871(tmp$816) = -//│ jump j$862(tmp$816) -//│ def j$862(tmp$816) = -//│ tmp$816 -//│ let x$874 = A$791(1) in -//│ let* (x$875) = f(x$874) in -//│ x$875 +//│ def j$415(tmp$405) = +//│ jump j$413(tmp$405) +//│ def j$417(tmp$405) = +//│ jump j$413(tmp$405) +//│ def j$413(tmp$405) = +//│ jump j$411(tmp$405) +//│ def j$420(tmp$406) = +//│ jump j$411(tmp$406) +//│ def j$411(tmp$406) = +//│ tmp$406 +//│ let x$423 = A$381(1) in +//│ let* (x$424) = f(x$423) in +//│ x$424 //│ //│ Interpreted: //│ 1 diff --git a/hkmc2/shared/src/test/mlscript/llir/Ctor.mls b/hkmc2/shared/src/test/mlscript/llir/Ctor.mls index 2095671808..7237a0eb64 100644 --- a/hkmc2/shared/src/test/mlscript/llir/Ctor.mls +++ b/hkmc2/shared/src/test/mlscript/llir/Ctor.mls @@ -10,12 +10,12 @@ fun testCtor1() = None fun testCtor2() = new None //│ LLIR: //│ class None() -//│ def testCtor1$240() = -//│ let x$291 = None$242() in -//│ x$291 -//│ def testCtor2$239() = -//│ let x$292 = None$242() in -//│ x$292 +//│ def testCtor1$199() = +//│ let x$209 = None$201() in +//│ x$209 +//│ def testCtor2$198() = +//│ let x$210 = None$201() in +//│ x$210 //│ undefined :sllir @@ -23,11 +23,11 @@ class A(x) fun testCtor1() = A(1) fun testCtor2() = new A(1) //│ LLIR: -//│ class A(x$298) -//│ def testCtor1$295() = -//│ let x$348 = A$296(1) in -//│ x$348 -//│ def testCtor2$294() = -//│ let x$349 = A$296(1) in -//│ x$349 +//│ class A(x$216) +//│ def testCtor1$213() = +//│ let x$225 = A$214(1) in +//│ x$225 +//│ def testCtor2$212() = +//│ let x$226 = A$214(1) in +//│ x$226 //│ undefined diff --git a/hkmc2/shared/src/test/mlscript/llir/HigherOrder.mls b/hkmc2/shared/src/test/mlscript/llir/HigherOrder.mls index 40569a7872..01e4c91a84 100644 --- a/hkmc2/shared/src/test/mlscript/llir/HigherOrder.mls +++ b/hkmc2/shared/src/test/mlscript/llir/HigherOrder.mls @@ -11,149 +11,23 @@ fun add(x) = y => x + y add(1)(2) //│ = 3 //│ LLIR: -//│ class Lambda(x$240) extends Callable { -//│ def apply1$267(y$241) = -//│ let x$298 = +(x$240,y$241) in -//│ x$298 +//│ class Lambda(x$199) extends Callable { +//│ def apply1$216(y$200) = +//│ let x$217 = +(x$199,y$200) in +//│ x$217 //│ } -//│ def add$239(x$240) = -//│ let x$299 = Lambda$296(x$240) in -//│ x$299 -//│ let* (x$300) = add(1) in -//│ let x$301 = Callable.apply1$267(x$300,2) in -//│ x$301 +//│ def add$198(x$199) = +//│ let x$218 = Lambda$214(x$199) in +//│ x$218 +//│ let* (x$219) = add(1) in +//│ let x$220 = Callable.apply1$216(x$219,2) in +//│ x$220 //│ //│ Cpp: //│ #include "mlsprelude.h" -//│ struct Tuple4; -//│ struct Tuple3; -//│ struct Tuple2; -//│ struct Tuple8; -//│ struct Tuple0; -//│ struct Tuple1; -//│ struct Tuple7; -//│ struct Tuple6; -//│ struct Tuple9; -//│ struct Tuple5; //│ struct Lambda; //│ _mlsValue add(_mlsValue); //│ _mlsValue _mlsMain(); -//│ struct Tuple4: public _mlsObject { -//│ _mlsValue field0; -//│ _mlsValue field1; -//│ _mlsValue field2; -//│ _mlsValue field3; -//│ constexpr static inline const char *typeName = "Tuple4"; -//│ constexpr static inline uint32_t typeTag = nextTypeTag(); -//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(", "); this->field1.print(); std::printf(", "); this->field2.print(); std::printf(", "); this->field3.print(); std::printf(")"); } -//│ virtual void destroy() override { _mlsValue::destroy(this->field0); _mlsValue::destroy(this->field1); _mlsValue::destroy(this->field2); _mlsValue::destroy(this->field3); operator delete (this, std::align_val_t(_mlsAlignment)); } -//│ static _mlsValue create(_mlsValue field0, _mlsValue field1, _mlsValue field2, _mlsValue field3) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple4; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; _mlsVal->field1 = field1; _mlsVal->field2 = field2; _mlsVal->field3 = field3; return _mlsValue(_mlsVal); } -//│ }; -//│ struct Tuple3: public _mlsObject { -//│ _mlsValue field0; -//│ _mlsValue field1; -//│ _mlsValue field2; -//│ constexpr static inline const char *typeName = "Tuple3"; -//│ constexpr static inline uint32_t typeTag = nextTypeTag(); -//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(", "); this->field1.print(); std::printf(", "); this->field2.print(); std::printf(")"); } -//│ virtual void destroy() override { _mlsValue::destroy(this->field0); _mlsValue::destroy(this->field1); _mlsValue::destroy(this->field2); operator delete (this, std::align_val_t(_mlsAlignment)); } -//│ static _mlsValue create(_mlsValue field0, _mlsValue field1, _mlsValue field2) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple3; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; _mlsVal->field1 = field1; _mlsVal->field2 = field2; return _mlsValue(_mlsVal); } -//│ }; -//│ struct Tuple2: public _mlsObject { -//│ _mlsValue field0; -//│ _mlsValue field1; -//│ constexpr static inline const char *typeName = "Tuple2"; -//│ constexpr static inline uint32_t typeTag = nextTypeTag(); -//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(", "); this->field1.print(); std::printf(")"); } -//│ virtual void destroy() override { _mlsValue::destroy(this->field0); _mlsValue::destroy(this->field1); operator delete (this, std::align_val_t(_mlsAlignment)); } -//│ static _mlsValue create(_mlsValue field0, _mlsValue field1) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple2; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; _mlsVal->field1 = field1; return _mlsValue(_mlsVal); } -//│ }; -//│ struct Tuple8: public _mlsObject { -//│ _mlsValue field0; -//│ _mlsValue field1; -//│ _mlsValue field2; -//│ _mlsValue field3; -//│ _mlsValue field4; -//│ _mlsValue field5; -//│ _mlsValue field6; -//│ _mlsValue field7; -//│ constexpr static inline const char *typeName = "Tuple8"; -//│ constexpr static inline uint32_t typeTag = nextTypeTag(); -//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(", "); this->field1.print(); std::printf(", "); this->field2.print(); std::printf(", "); this->field3.print(); std::printf(", "); this->field4.print(); std::printf(", "); this->field5.print(); std::printf(", "); this->field6.print(); std::printf(", "); this->field7.print(); std::printf(")"); } -//│ virtual void destroy() override { _mlsValue::destroy(this->field0); _mlsValue::destroy(this->field1); _mlsValue::destroy(this->field2); _mlsValue::destroy(this->field3); _mlsValue::destroy(this->field4); _mlsValue::destroy(this->field5); _mlsValue::destroy(this->field6); _mlsValue::destroy(this->field7); operator delete (this, std::align_val_t(_mlsAlignment)); } -//│ static _mlsValue create(_mlsValue field0, _mlsValue field1, _mlsValue field2, _mlsValue field3, _mlsValue field4, _mlsValue field5, _mlsValue field6, _mlsValue field7) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple8; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; _mlsVal->field1 = field1; _mlsVal->field2 = field2; _mlsVal->field3 = field3; _mlsVal->field4 = field4; _mlsVal->field5 = field5; _mlsVal->field6 = field6; _mlsVal->field7 = field7; return _mlsValue(_mlsVal); } -//│ }; -//│ struct Tuple0: public _mlsObject { -//│ -//│ constexpr static inline const char *typeName = "Tuple0"; -//│ constexpr static inline uint32_t typeTag = nextTypeTag(); -//│ virtual void print() const override { std::printf("%s", typeName); } -//│ virtual void destroy() override { operator delete (this, std::align_val_t(_mlsAlignment)); } -//│ static _mlsValue create() { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple0; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; return _mlsValue(_mlsVal); } -//│ }; -//│ struct Tuple1: public _mlsObject { -//│ _mlsValue field0; -//│ constexpr static inline const char *typeName = "Tuple1"; -//│ constexpr static inline uint32_t typeTag = nextTypeTag(); -//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(")"); } -//│ virtual void destroy() override { _mlsValue::destroy(this->field0); operator delete (this, std::align_val_t(_mlsAlignment)); } -//│ static _mlsValue create(_mlsValue field0) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple1; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; return _mlsValue(_mlsVal); } -//│ }; -//│ struct Tuple7: public _mlsObject { -//│ _mlsValue field0; -//│ _mlsValue field1; -//│ _mlsValue field2; -//│ _mlsValue field3; -//│ _mlsValue field4; -//│ _mlsValue field5; -//│ _mlsValue field6; -//│ constexpr static inline const char *typeName = "Tuple7"; -//│ constexpr static inline uint32_t typeTag = nextTypeTag(); -//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(", "); this->field1.print(); std::printf(", "); this->field2.print(); std::printf(", "); this->field3.print(); std::printf(", "); this->field4.print(); std::printf(", "); this->field5.print(); std::printf(", "); this->field6.print(); std::printf(")"); } -//│ virtual void destroy() override { _mlsValue::destroy(this->field0); _mlsValue::destroy(this->field1); _mlsValue::destroy(this->field2); _mlsValue::destroy(this->field3); _mlsValue::destroy(this->field4); _mlsValue::destroy(this->field5); _mlsValue::destroy(this->field6); operator delete (this, std::align_val_t(_mlsAlignment)); } -//│ static _mlsValue create(_mlsValue field0, _mlsValue field1, _mlsValue field2, _mlsValue field3, _mlsValue field4, _mlsValue field5, _mlsValue field6) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple7; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; _mlsVal->field1 = field1; _mlsVal->field2 = field2; _mlsVal->field3 = field3; _mlsVal->field4 = field4; _mlsVal->field5 = field5; _mlsVal->field6 = field6; return _mlsValue(_mlsVal); } -//│ }; -//│ struct Tuple6: public _mlsObject { -//│ _mlsValue field0; -//│ _mlsValue field1; -//│ _mlsValue field2; -//│ _mlsValue field3; -//│ _mlsValue field4; -//│ _mlsValue field5; -//│ constexpr static inline const char *typeName = "Tuple6"; -//│ constexpr static inline uint32_t typeTag = nextTypeTag(); -//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(", "); this->field1.print(); std::printf(", "); this->field2.print(); std::printf(", "); this->field3.print(); std::printf(", "); this->field4.print(); std::printf(", "); this->field5.print(); std::printf(")"); } -//│ virtual void destroy() override { _mlsValue::destroy(this->field0); _mlsValue::destroy(this->field1); _mlsValue::destroy(this->field2); _mlsValue::destroy(this->field3); _mlsValue::destroy(this->field4); _mlsValue::destroy(this->field5); operator delete (this, std::align_val_t(_mlsAlignment)); } -//│ static _mlsValue create(_mlsValue field0, _mlsValue field1, _mlsValue field2, _mlsValue field3, _mlsValue field4, _mlsValue field5) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple6; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; _mlsVal->field1 = field1; _mlsVal->field2 = field2; _mlsVal->field3 = field3; _mlsVal->field4 = field4; _mlsVal->field5 = field5; return _mlsValue(_mlsVal); } -//│ }; -//│ struct Tuple9: public _mlsObject { -//│ _mlsValue field0; -//│ _mlsValue field1; -//│ _mlsValue field2; -//│ _mlsValue field3; -//│ _mlsValue field4; -//│ _mlsValue field5; -//│ _mlsValue field6; -//│ _mlsValue field7; -//│ _mlsValue field8; -//│ constexpr static inline const char *typeName = "Tuple9"; -//│ constexpr static inline uint32_t typeTag = nextTypeTag(); -//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(", "); this->field1.print(); std::printf(", "); this->field2.print(); std::printf(", "); this->field3.print(); std::printf(", "); this->field4.print(); std::printf(", "); this->field5.print(); std::printf(", "); this->field6.print(); std::printf(", "); this->field7.print(); std::printf(", "); this->field8.print(); std::printf(")"); } -//│ virtual void destroy() override { _mlsValue::destroy(this->field0); _mlsValue::destroy(this->field1); _mlsValue::destroy(this->field2); _mlsValue::destroy(this->field3); _mlsValue::destroy(this->field4); _mlsValue::destroy(this->field5); _mlsValue::destroy(this->field6); _mlsValue::destroy(this->field7); _mlsValue::destroy(this->field8); operator delete (this, std::align_val_t(_mlsAlignment)); } -//│ static _mlsValue create(_mlsValue field0, _mlsValue field1, _mlsValue field2, _mlsValue field3, _mlsValue field4, _mlsValue field5, _mlsValue field6, _mlsValue field7, _mlsValue field8) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple9; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; _mlsVal->field1 = field1; _mlsVal->field2 = field2; _mlsVal->field3 = field3; _mlsVal->field4 = field4; _mlsVal->field5 = field5; _mlsVal->field6 = field6; _mlsVal->field7 = field7; _mlsVal->field8 = field8; return _mlsValue(_mlsVal); } -//│ }; -//│ struct Tuple5: public _mlsObject { -//│ _mlsValue field0; -//│ _mlsValue field1; -//│ _mlsValue field2; -//│ _mlsValue field3; -//│ _mlsValue field4; -//│ constexpr static inline const char *typeName = "Tuple5"; -//│ constexpr static inline uint32_t typeTag = nextTypeTag(); -//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(", "); this->field1.print(); std::printf(", "); this->field2.print(); std::printf(", "); this->field3.print(); std::printf(", "); this->field4.print(); std::printf(")"); } -//│ virtual void destroy() override { _mlsValue::destroy(this->field0); _mlsValue::destroy(this->field1); _mlsValue::destroy(this->field2); _mlsValue::destroy(this->field3); _mlsValue::destroy(this->field4); operator delete (this, std::align_val_t(_mlsAlignment)); } -//│ static _mlsValue create(_mlsValue field0, _mlsValue field1, _mlsValue field2, _mlsValue field3, _mlsValue field4) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple5; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; _mlsVal->field1 = field1; _mlsVal->field2 = field2; _mlsVal->field3 = field3; _mlsVal->field4 = field4; return _mlsValue(_mlsVal); } -//│ }; //│ struct Lambda: public Callable { //│ _mlsValue x; //│ constexpr static inline const char *typeName = "Lambda"; @@ -193,159 +67,33 @@ fun add4(a, b) = (c, d) => a + b + c + d add4(1, 2)(3, 4) //│ = 10 //│ LLIR: -//│ class Lambda(a$303,b$304) extends Callable { -//│ def apply2$339(c$305,d$306) = -//│ let x$369 = +(a$303,b$304) in -//│ let x$370 = +(x$369,c$305) in -//│ let x$371 = +(x$370,d$306) in -//│ x$371 +//│ class Lambda(b$223,a$222) extends Callable { +//│ def apply2$247(c$224,d$225) = +//│ let x$248 = +(a$222,b$223) in +//│ let x$249 = +(x$248,c$224) in +//│ let x$250 = +(x$249,d$225) in +//│ x$250 //│ } -//│ def add4$302(a$303,b$304) = -//│ let x$372 = Lambda$367(a$303,b$304) in -//│ x$372 -//│ let* (x$373) = add4(1,2) in -//│ let x$374 = Callable.apply2$339(x$373,3,4) in -//│ x$374 +//│ def add4$221(a$222,b$223) = +//│ let x$251 = Lambda$245(b$223,a$222) in +//│ x$251 +//│ let* (x$252) = add4(1,2) in +//│ let x$253 = Callable.apply2$247(x$252,3,4) in +//│ x$253 //│ //│ Cpp: //│ #include "mlsprelude.h" -//│ struct Tuple4; -//│ struct Tuple3; -//│ struct Tuple2; -//│ struct Tuple8; -//│ struct Tuple0; -//│ struct Tuple1; -//│ struct Tuple7; -//│ struct Tuple6; -//│ struct Tuple9; -//│ struct Tuple5; //│ struct Lambda; //│ _mlsValue add4(_mlsValue, _mlsValue); //│ _mlsValue _mlsMain(); -//│ struct Tuple4: public _mlsObject { -//│ _mlsValue field0; -//│ _mlsValue field1; -//│ _mlsValue field2; -//│ _mlsValue field3; -//│ constexpr static inline const char *typeName = "Tuple4"; -//│ constexpr static inline uint32_t typeTag = nextTypeTag(); -//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(", "); this->field1.print(); std::printf(", "); this->field2.print(); std::printf(", "); this->field3.print(); std::printf(")"); } -//│ virtual void destroy() override { _mlsValue::destroy(this->field0); _mlsValue::destroy(this->field1); _mlsValue::destroy(this->field2); _mlsValue::destroy(this->field3); operator delete (this, std::align_val_t(_mlsAlignment)); } -//│ static _mlsValue create(_mlsValue field0, _mlsValue field1, _mlsValue field2, _mlsValue field3) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple4; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; _mlsVal->field1 = field1; _mlsVal->field2 = field2; _mlsVal->field3 = field3; return _mlsValue(_mlsVal); } -//│ }; -//│ struct Tuple3: public _mlsObject { -//│ _mlsValue field0; -//│ _mlsValue field1; -//│ _mlsValue field2; -//│ constexpr static inline const char *typeName = "Tuple3"; -//│ constexpr static inline uint32_t typeTag = nextTypeTag(); -//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(", "); this->field1.print(); std::printf(", "); this->field2.print(); std::printf(")"); } -//│ virtual void destroy() override { _mlsValue::destroy(this->field0); _mlsValue::destroy(this->field1); _mlsValue::destroy(this->field2); operator delete (this, std::align_val_t(_mlsAlignment)); } -//│ static _mlsValue create(_mlsValue field0, _mlsValue field1, _mlsValue field2) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple3; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; _mlsVal->field1 = field1; _mlsVal->field2 = field2; return _mlsValue(_mlsVal); } -//│ }; -//│ struct Tuple2: public _mlsObject { -//│ _mlsValue field0; -//│ _mlsValue field1; -//│ constexpr static inline const char *typeName = "Tuple2"; -//│ constexpr static inline uint32_t typeTag = nextTypeTag(); -//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(", "); this->field1.print(); std::printf(")"); } -//│ virtual void destroy() override { _mlsValue::destroy(this->field0); _mlsValue::destroy(this->field1); operator delete (this, std::align_val_t(_mlsAlignment)); } -//│ static _mlsValue create(_mlsValue field0, _mlsValue field1) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple2; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; _mlsVal->field1 = field1; return _mlsValue(_mlsVal); } -//│ }; -//│ struct Tuple8: public _mlsObject { -//│ _mlsValue field0; -//│ _mlsValue field1; -//│ _mlsValue field2; -//│ _mlsValue field3; -//│ _mlsValue field4; -//│ _mlsValue field5; -//│ _mlsValue field6; -//│ _mlsValue field7; -//│ constexpr static inline const char *typeName = "Tuple8"; -//│ constexpr static inline uint32_t typeTag = nextTypeTag(); -//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(", "); this->field1.print(); std::printf(", "); this->field2.print(); std::printf(", "); this->field3.print(); std::printf(", "); this->field4.print(); std::printf(", "); this->field5.print(); std::printf(", "); this->field6.print(); std::printf(", "); this->field7.print(); std::printf(")"); } -//│ virtual void destroy() override { _mlsValue::destroy(this->field0); _mlsValue::destroy(this->field1); _mlsValue::destroy(this->field2); _mlsValue::destroy(this->field3); _mlsValue::destroy(this->field4); _mlsValue::destroy(this->field5); _mlsValue::destroy(this->field6); _mlsValue::destroy(this->field7); operator delete (this, std::align_val_t(_mlsAlignment)); } -//│ static _mlsValue create(_mlsValue field0, _mlsValue field1, _mlsValue field2, _mlsValue field3, _mlsValue field4, _mlsValue field5, _mlsValue field6, _mlsValue field7) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple8; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; _mlsVal->field1 = field1; _mlsVal->field2 = field2; _mlsVal->field3 = field3; _mlsVal->field4 = field4; _mlsVal->field5 = field5; _mlsVal->field6 = field6; _mlsVal->field7 = field7; return _mlsValue(_mlsVal); } -//│ }; -//│ struct Tuple0: public _mlsObject { -//│ -//│ constexpr static inline const char *typeName = "Tuple0"; -//│ constexpr static inline uint32_t typeTag = nextTypeTag(); -//│ virtual void print() const override { std::printf("%s", typeName); } -//│ virtual void destroy() override { operator delete (this, std::align_val_t(_mlsAlignment)); } -//│ static _mlsValue create() { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple0; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; return _mlsValue(_mlsVal); } -//│ }; -//│ struct Tuple1: public _mlsObject { -//│ _mlsValue field0; -//│ constexpr static inline const char *typeName = "Tuple1"; -//│ constexpr static inline uint32_t typeTag = nextTypeTag(); -//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(")"); } -//│ virtual void destroy() override { _mlsValue::destroy(this->field0); operator delete (this, std::align_val_t(_mlsAlignment)); } -//│ static _mlsValue create(_mlsValue field0) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple1; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; return _mlsValue(_mlsVal); } -//│ }; -//│ struct Tuple7: public _mlsObject { -//│ _mlsValue field0; -//│ _mlsValue field1; -//│ _mlsValue field2; -//│ _mlsValue field3; -//│ _mlsValue field4; -//│ _mlsValue field5; -//│ _mlsValue field6; -//│ constexpr static inline const char *typeName = "Tuple7"; -//│ constexpr static inline uint32_t typeTag = nextTypeTag(); -//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(", "); this->field1.print(); std::printf(", "); this->field2.print(); std::printf(", "); this->field3.print(); std::printf(", "); this->field4.print(); std::printf(", "); this->field5.print(); std::printf(", "); this->field6.print(); std::printf(")"); } -//│ virtual void destroy() override { _mlsValue::destroy(this->field0); _mlsValue::destroy(this->field1); _mlsValue::destroy(this->field2); _mlsValue::destroy(this->field3); _mlsValue::destroy(this->field4); _mlsValue::destroy(this->field5); _mlsValue::destroy(this->field6); operator delete (this, std::align_val_t(_mlsAlignment)); } -//│ static _mlsValue create(_mlsValue field0, _mlsValue field1, _mlsValue field2, _mlsValue field3, _mlsValue field4, _mlsValue field5, _mlsValue field6) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple7; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; _mlsVal->field1 = field1; _mlsVal->field2 = field2; _mlsVal->field3 = field3; _mlsVal->field4 = field4; _mlsVal->field5 = field5; _mlsVal->field6 = field6; return _mlsValue(_mlsVal); } -//│ }; -//│ struct Tuple6: public _mlsObject { -//│ _mlsValue field0; -//│ _mlsValue field1; -//│ _mlsValue field2; -//│ _mlsValue field3; -//│ _mlsValue field4; -//│ _mlsValue field5; -//│ constexpr static inline const char *typeName = "Tuple6"; -//│ constexpr static inline uint32_t typeTag = nextTypeTag(); -//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(", "); this->field1.print(); std::printf(", "); this->field2.print(); std::printf(", "); this->field3.print(); std::printf(", "); this->field4.print(); std::printf(", "); this->field5.print(); std::printf(")"); } -//│ virtual void destroy() override { _mlsValue::destroy(this->field0); _mlsValue::destroy(this->field1); _mlsValue::destroy(this->field2); _mlsValue::destroy(this->field3); _mlsValue::destroy(this->field4); _mlsValue::destroy(this->field5); operator delete (this, std::align_val_t(_mlsAlignment)); } -//│ static _mlsValue create(_mlsValue field0, _mlsValue field1, _mlsValue field2, _mlsValue field3, _mlsValue field4, _mlsValue field5) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple6; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; _mlsVal->field1 = field1; _mlsVal->field2 = field2; _mlsVal->field3 = field3; _mlsVal->field4 = field4; _mlsVal->field5 = field5; return _mlsValue(_mlsVal); } -//│ }; -//│ struct Tuple9: public _mlsObject { -//│ _mlsValue field0; -//│ _mlsValue field1; -//│ _mlsValue field2; -//│ _mlsValue field3; -//│ _mlsValue field4; -//│ _mlsValue field5; -//│ _mlsValue field6; -//│ _mlsValue field7; -//│ _mlsValue field8; -//│ constexpr static inline const char *typeName = "Tuple9"; -//│ constexpr static inline uint32_t typeTag = nextTypeTag(); -//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(", "); this->field1.print(); std::printf(", "); this->field2.print(); std::printf(", "); this->field3.print(); std::printf(", "); this->field4.print(); std::printf(", "); this->field5.print(); std::printf(", "); this->field6.print(); std::printf(", "); this->field7.print(); std::printf(", "); this->field8.print(); std::printf(")"); } -//│ virtual void destroy() override { _mlsValue::destroy(this->field0); _mlsValue::destroy(this->field1); _mlsValue::destroy(this->field2); _mlsValue::destroy(this->field3); _mlsValue::destroy(this->field4); _mlsValue::destroy(this->field5); _mlsValue::destroy(this->field6); _mlsValue::destroy(this->field7); _mlsValue::destroy(this->field8); operator delete (this, std::align_val_t(_mlsAlignment)); } -//│ static _mlsValue create(_mlsValue field0, _mlsValue field1, _mlsValue field2, _mlsValue field3, _mlsValue field4, _mlsValue field5, _mlsValue field6, _mlsValue field7, _mlsValue field8) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple9; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; _mlsVal->field1 = field1; _mlsVal->field2 = field2; _mlsVal->field3 = field3; _mlsVal->field4 = field4; _mlsVal->field5 = field5; _mlsVal->field6 = field6; _mlsVal->field7 = field7; _mlsVal->field8 = field8; return _mlsValue(_mlsVal); } -//│ }; -//│ struct Tuple5: public _mlsObject { -//│ _mlsValue field0; -//│ _mlsValue field1; -//│ _mlsValue field2; -//│ _mlsValue field3; -//│ _mlsValue field4; -//│ constexpr static inline const char *typeName = "Tuple5"; -//│ constexpr static inline uint32_t typeTag = nextTypeTag(); -//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(", "); this->field1.print(); std::printf(", "); this->field2.print(); std::printf(", "); this->field3.print(); std::printf(", "); this->field4.print(); std::printf(")"); } -//│ virtual void destroy() override { _mlsValue::destroy(this->field0); _mlsValue::destroy(this->field1); _mlsValue::destroy(this->field2); _mlsValue::destroy(this->field3); _mlsValue::destroy(this->field4); operator delete (this, std::align_val_t(_mlsAlignment)); } -//│ static _mlsValue create(_mlsValue field0, _mlsValue field1, _mlsValue field2, _mlsValue field3, _mlsValue field4) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple5; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; _mlsVal->field1 = field1; _mlsVal->field2 = field2; _mlsVal->field3 = field3; _mlsVal->field4 = field4; return _mlsValue(_mlsVal); } -//│ }; //│ struct Lambda: public Callable { -//│ _mlsValue a; //│ _mlsValue b; +//│ _mlsValue a; //│ constexpr static inline const char *typeName = "Lambda"; //│ constexpr static inline uint32_t typeTag = nextTypeTag(); -//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->a.print(); std::printf(", "); this->b.print(); std::printf(")"); } -//│ virtual void destroy() override { _mlsValue::destroy(this->a); _mlsValue::destroy(this->b); operator delete (this, std::align_val_t(_mlsAlignment)); } -//│ static _mlsValue create(_mlsValue a, _mlsValue b) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Lambda; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->a = a; _mlsVal->b = b; return _mlsValue(_mlsVal); } +//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->b.print(); std::printf(", "); this->a.print(); std::printf(")"); } +//│ virtual void destroy() override { _mlsValue::destroy(this->b); _mlsValue::destroy(this->a); operator delete (this, std::align_val_t(_mlsAlignment)); } +//│ static _mlsValue create(_mlsValue b, _mlsValue a) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Lambda; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->b = b; _mlsVal->a = a; return _mlsValue(_mlsVal); } //│ virtual _mlsValue apply2(_mlsValue c, _mlsValue d) { //│ _mlsValue _mls_retval; //│ auto x = (a + b); @@ -357,7 +105,7 @@ add4(1, 2)(3, 4) //│ }; //│ _mlsValue add4(_mlsValue a, _mlsValue b) { //│ _mlsValue _mls_retval; -//│ auto x3 = _mlsValue::create(a, b); +//│ auto x3 = _mlsValue::create(b, a); //│ _mls_retval = x3; //│ return _mls_retval; //│ } @@ -382,152 +130,26 @@ dummy()(1, 2) //│ = 3 //│ LLIR: //│ class Lambda_add() extends Callable { -//│ def apply2$406(arg$435,arg$436) = -//│ let* (x$439) = add(arg$435,arg$436) in -//│ x$439 +//│ def apply2$277(arg$273,arg$274) = +//│ let* (x$278) = add(arg$273,arg$274) in +//│ x$278 //│ } -//│ def add$375(a$377,b$378) = -//│ let x$434 = +(a$377,b$378) in -//│ x$434 -//│ def dummy$376() = -//│ let x$440 = Lambda_add$437() in -//│ x$440 -//│ let* (x$441) = dummy() in -//│ let x$442 = Callable.apply2$406(x$441,1,2) in -//│ x$442 +//│ def add$254(a$256,b$257) = +//│ let x$272 = +(a$256,b$257) in +//│ x$272 +//│ def dummy$255() = +//│ let x$279 = Lambda_add$275() in +//│ x$279 +//│ let* (x$280) = dummy() in +//│ let x$281 = Callable.apply2$277(x$280,1,2) in +//│ x$281 //│ //│ Cpp: //│ #include "mlsprelude.h" -//│ struct Tuple4; -//│ struct Tuple3; -//│ struct Tuple2; -//│ struct Tuple8; -//│ struct Tuple0; -//│ struct Tuple1; -//│ struct Tuple7; -//│ struct Tuple6; -//│ struct Tuple9; -//│ struct Tuple5; //│ struct Lambda_add; //│ _mlsValue add(_mlsValue, _mlsValue); //│ _mlsValue dummy(); //│ _mlsValue _mlsMain(); -//│ struct Tuple4: public _mlsObject { -//│ _mlsValue field0; -//│ _mlsValue field1; -//│ _mlsValue field2; -//│ _mlsValue field3; -//│ constexpr static inline const char *typeName = "Tuple4"; -//│ constexpr static inline uint32_t typeTag = nextTypeTag(); -//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(", "); this->field1.print(); std::printf(", "); this->field2.print(); std::printf(", "); this->field3.print(); std::printf(")"); } -//│ virtual void destroy() override { _mlsValue::destroy(this->field0); _mlsValue::destroy(this->field1); _mlsValue::destroy(this->field2); _mlsValue::destroy(this->field3); operator delete (this, std::align_val_t(_mlsAlignment)); } -//│ static _mlsValue create(_mlsValue field0, _mlsValue field1, _mlsValue field2, _mlsValue field3) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple4; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; _mlsVal->field1 = field1; _mlsVal->field2 = field2; _mlsVal->field3 = field3; return _mlsValue(_mlsVal); } -//│ }; -//│ struct Tuple3: public _mlsObject { -//│ _mlsValue field0; -//│ _mlsValue field1; -//│ _mlsValue field2; -//│ constexpr static inline const char *typeName = "Tuple3"; -//│ constexpr static inline uint32_t typeTag = nextTypeTag(); -//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(", "); this->field1.print(); std::printf(", "); this->field2.print(); std::printf(")"); } -//│ virtual void destroy() override { _mlsValue::destroy(this->field0); _mlsValue::destroy(this->field1); _mlsValue::destroy(this->field2); operator delete (this, std::align_val_t(_mlsAlignment)); } -//│ static _mlsValue create(_mlsValue field0, _mlsValue field1, _mlsValue field2) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple3; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; _mlsVal->field1 = field1; _mlsVal->field2 = field2; return _mlsValue(_mlsVal); } -//│ }; -//│ struct Tuple2: public _mlsObject { -//│ _mlsValue field0; -//│ _mlsValue field1; -//│ constexpr static inline const char *typeName = "Tuple2"; -//│ constexpr static inline uint32_t typeTag = nextTypeTag(); -//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(", "); this->field1.print(); std::printf(")"); } -//│ virtual void destroy() override { _mlsValue::destroy(this->field0); _mlsValue::destroy(this->field1); operator delete (this, std::align_val_t(_mlsAlignment)); } -//│ static _mlsValue create(_mlsValue field0, _mlsValue field1) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple2; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; _mlsVal->field1 = field1; return _mlsValue(_mlsVal); } -//│ }; -//│ struct Tuple8: public _mlsObject { -//│ _mlsValue field0; -//│ _mlsValue field1; -//│ _mlsValue field2; -//│ _mlsValue field3; -//│ _mlsValue field4; -//│ _mlsValue field5; -//│ _mlsValue field6; -//│ _mlsValue field7; -//│ constexpr static inline const char *typeName = "Tuple8"; -//│ constexpr static inline uint32_t typeTag = nextTypeTag(); -//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(", "); this->field1.print(); std::printf(", "); this->field2.print(); std::printf(", "); this->field3.print(); std::printf(", "); this->field4.print(); std::printf(", "); this->field5.print(); std::printf(", "); this->field6.print(); std::printf(", "); this->field7.print(); std::printf(")"); } -//│ virtual void destroy() override { _mlsValue::destroy(this->field0); _mlsValue::destroy(this->field1); _mlsValue::destroy(this->field2); _mlsValue::destroy(this->field3); _mlsValue::destroy(this->field4); _mlsValue::destroy(this->field5); _mlsValue::destroy(this->field6); _mlsValue::destroy(this->field7); operator delete (this, std::align_val_t(_mlsAlignment)); } -//│ static _mlsValue create(_mlsValue field0, _mlsValue field1, _mlsValue field2, _mlsValue field3, _mlsValue field4, _mlsValue field5, _mlsValue field6, _mlsValue field7) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple8; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; _mlsVal->field1 = field1; _mlsVal->field2 = field2; _mlsVal->field3 = field3; _mlsVal->field4 = field4; _mlsVal->field5 = field5; _mlsVal->field6 = field6; _mlsVal->field7 = field7; return _mlsValue(_mlsVal); } -//│ }; -//│ struct Tuple0: public _mlsObject { -//│ -//│ constexpr static inline const char *typeName = "Tuple0"; -//│ constexpr static inline uint32_t typeTag = nextTypeTag(); -//│ virtual void print() const override { std::printf("%s", typeName); } -//│ virtual void destroy() override { operator delete (this, std::align_val_t(_mlsAlignment)); } -//│ static _mlsValue create() { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple0; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; return _mlsValue(_mlsVal); } -//│ }; -//│ struct Tuple1: public _mlsObject { -//│ _mlsValue field0; -//│ constexpr static inline const char *typeName = "Tuple1"; -//│ constexpr static inline uint32_t typeTag = nextTypeTag(); -//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(")"); } -//│ virtual void destroy() override { _mlsValue::destroy(this->field0); operator delete (this, std::align_val_t(_mlsAlignment)); } -//│ static _mlsValue create(_mlsValue field0) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple1; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; return _mlsValue(_mlsVal); } -//│ }; -//│ struct Tuple7: public _mlsObject { -//│ _mlsValue field0; -//│ _mlsValue field1; -//│ _mlsValue field2; -//│ _mlsValue field3; -//│ _mlsValue field4; -//│ _mlsValue field5; -//│ _mlsValue field6; -//│ constexpr static inline const char *typeName = "Tuple7"; -//│ constexpr static inline uint32_t typeTag = nextTypeTag(); -//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(", "); this->field1.print(); std::printf(", "); this->field2.print(); std::printf(", "); this->field3.print(); std::printf(", "); this->field4.print(); std::printf(", "); this->field5.print(); std::printf(", "); this->field6.print(); std::printf(")"); } -//│ virtual void destroy() override { _mlsValue::destroy(this->field0); _mlsValue::destroy(this->field1); _mlsValue::destroy(this->field2); _mlsValue::destroy(this->field3); _mlsValue::destroy(this->field4); _mlsValue::destroy(this->field5); _mlsValue::destroy(this->field6); operator delete (this, std::align_val_t(_mlsAlignment)); } -//│ static _mlsValue create(_mlsValue field0, _mlsValue field1, _mlsValue field2, _mlsValue field3, _mlsValue field4, _mlsValue field5, _mlsValue field6) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple7; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; _mlsVal->field1 = field1; _mlsVal->field2 = field2; _mlsVal->field3 = field3; _mlsVal->field4 = field4; _mlsVal->field5 = field5; _mlsVal->field6 = field6; return _mlsValue(_mlsVal); } -//│ }; -//│ struct Tuple6: public _mlsObject { -//│ _mlsValue field0; -//│ _mlsValue field1; -//│ _mlsValue field2; -//│ _mlsValue field3; -//│ _mlsValue field4; -//│ _mlsValue field5; -//│ constexpr static inline const char *typeName = "Tuple6"; -//│ constexpr static inline uint32_t typeTag = nextTypeTag(); -//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(", "); this->field1.print(); std::printf(", "); this->field2.print(); std::printf(", "); this->field3.print(); std::printf(", "); this->field4.print(); std::printf(", "); this->field5.print(); std::printf(")"); } -//│ virtual void destroy() override { _mlsValue::destroy(this->field0); _mlsValue::destroy(this->field1); _mlsValue::destroy(this->field2); _mlsValue::destroy(this->field3); _mlsValue::destroy(this->field4); _mlsValue::destroy(this->field5); operator delete (this, std::align_val_t(_mlsAlignment)); } -//│ static _mlsValue create(_mlsValue field0, _mlsValue field1, _mlsValue field2, _mlsValue field3, _mlsValue field4, _mlsValue field5) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple6; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; _mlsVal->field1 = field1; _mlsVal->field2 = field2; _mlsVal->field3 = field3; _mlsVal->field4 = field4; _mlsVal->field5 = field5; return _mlsValue(_mlsVal); } -//│ }; -//│ struct Tuple9: public _mlsObject { -//│ _mlsValue field0; -//│ _mlsValue field1; -//│ _mlsValue field2; -//│ _mlsValue field3; -//│ _mlsValue field4; -//│ _mlsValue field5; -//│ _mlsValue field6; -//│ _mlsValue field7; -//│ _mlsValue field8; -//│ constexpr static inline const char *typeName = "Tuple9"; -//│ constexpr static inline uint32_t typeTag = nextTypeTag(); -//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(", "); this->field1.print(); std::printf(", "); this->field2.print(); std::printf(", "); this->field3.print(); std::printf(", "); this->field4.print(); std::printf(", "); this->field5.print(); std::printf(", "); this->field6.print(); std::printf(", "); this->field7.print(); std::printf(", "); this->field8.print(); std::printf(")"); } -//│ virtual void destroy() override { _mlsValue::destroy(this->field0); _mlsValue::destroy(this->field1); _mlsValue::destroy(this->field2); _mlsValue::destroy(this->field3); _mlsValue::destroy(this->field4); _mlsValue::destroy(this->field5); _mlsValue::destroy(this->field6); _mlsValue::destroy(this->field7); _mlsValue::destroy(this->field8); operator delete (this, std::align_val_t(_mlsAlignment)); } -//│ static _mlsValue create(_mlsValue field0, _mlsValue field1, _mlsValue field2, _mlsValue field3, _mlsValue field4, _mlsValue field5, _mlsValue field6, _mlsValue field7, _mlsValue field8) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple9; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; _mlsVal->field1 = field1; _mlsVal->field2 = field2; _mlsVal->field3 = field3; _mlsVal->field4 = field4; _mlsVal->field5 = field5; _mlsVal->field6 = field6; _mlsVal->field7 = field7; _mlsVal->field8 = field8; return _mlsValue(_mlsVal); } -//│ }; -//│ struct Tuple5: public _mlsObject { -//│ _mlsValue field0; -//│ _mlsValue field1; -//│ _mlsValue field2; -//│ _mlsValue field3; -//│ _mlsValue field4; -//│ constexpr static inline const char *typeName = "Tuple5"; -//│ constexpr static inline uint32_t typeTag = nextTypeTag(); -//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->field0.print(); std::printf(", "); this->field1.print(); std::printf(", "); this->field2.print(); std::printf(", "); this->field3.print(); std::printf(", "); this->field4.print(); std::printf(")"); } -//│ virtual void destroy() override { _mlsValue::destroy(this->field0); _mlsValue::destroy(this->field1); _mlsValue::destroy(this->field2); _mlsValue::destroy(this->field3); _mlsValue::destroy(this->field4); operator delete (this, std::align_val_t(_mlsAlignment)); } -//│ static _mlsValue create(_mlsValue field0, _mlsValue field1, _mlsValue field2, _mlsValue field3, _mlsValue field4) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Tuple5; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->field0 = field0; _mlsVal->field1 = field1; _mlsVal->field2 = field2; _mlsVal->field3 = field3; _mlsVal->field4 = field4; return _mlsValue(_mlsVal); } -//│ }; //│ struct Lambda_add: public Callable { //│ //│ constexpr static inline const char *typeName = "Lambda_add"; @@ -583,55 +205,55 @@ main() //│ = Cons(4, Cons(5, Nil)) //│ LLIR: //│ class List() -//│ class Cons(head$455,tail$456) extends List +//│ class Cons(head$294,tail$295) extends List //│ class Nil() extends List //│ class Lambda() extends Callable { -//│ def apply1$536(x$473) = -//│ let* (x$579) = inc(x$473) in -//│ x$579 +//│ def apply1$367(x$312) = +//│ let* (x$378) = inc(x$312) in +//│ x$378 //│ } //│ class Lambda_inc() extends Callable { -//│ def apply1$536(arg$585) = -//│ let* (x$588) = inc(arg$585) in -//│ x$588 +//│ def apply1$367(arg$384) = +//│ let* (x$387) = inc(arg$384) in +//│ x$387 //│ } -//│ def map$444(f$459,l$460) = -//│ case l$460 of -//│ Cons$452 => -//│ let x$566 = l$460. in -//│ let x$567 = l$460. in -//│ let x$568 = Callable.apply1$536(f$459,x$566) in -//│ let* (x$569) = map(f$459,x$567) in -//│ let x$570 = Cons$452(x$568,x$569) in -//│ x$570 +//│ def map$283(f$298,l$299) = +//│ case l$299 of +//│ Cons$291 => +//│ let x$364 = l$299. in +//│ let x$365 = l$299. in +//│ let x$366 = Callable.apply1$367(f$298,x$364) in +//│ let* (x$368) = map(f$298,x$365) in +//│ let x$369 = Cons$291(x$366,x$368) in +//│ x$369 //│ _ => -//│ case l$460 of -//│ Nil$457 => -//│ let x$572 = Nil$457() in -//│ x$572 +//│ case l$299 of +//│ Nil$296 => +//│ let x$371 = Nil$296() in +//│ x$371 //│ _ => //│ panic "match error" -//│ def j$571() = -//│ jump j$565() -//│ def j$565() = +//│ def j$370() = +//│ jump j$363() +//│ def j$363() = //│ null -//│ def inc$447(x$469) = -//│ let x$573 = +(x$469,1) in -//│ x$573 -//│ def main$445() = -//│ let x$574 = Nil$457() in -//│ let x$575 = Cons$452(2,x$574) in -//│ let x$576 = Cons$452(1,x$575) in -//│ let x$580 = Lambda$577() in -//│ let* (x$581) = map(x$580,x$576) in -//│ let x$582 = Nil$457() in -//│ let x$583 = Cons$452(4,x$582) in -//│ let x$584 = Cons$452(3,x$583) in -//│ let x$589 = Lambda_inc$586() in -//│ let* (x$590) = map(x$589,x$584) in -//│ x$590 -//│ let* (x$591) = main() in -//│ x$591 +//│ def inc$286(x$308) = +//│ let x$372 = +(x$308,1) in +//│ x$372 +//│ def main$284() = +//│ let x$373 = Nil$296() in +//│ let x$374 = Cons$291(2,x$373) in +//│ let x$375 = Cons$291(1,x$374) in +//│ let x$379 = Lambda$376() in +//│ let* (x$380) = map(x$379,x$375) in +//│ let x$381 = Nil$296() in +//│ let x$382 = Cons$291(4,x$381) in +//│ let x$383 = Cons$291(3,x$382) in +//│ let x$388 = Lambda_inc$385() in +//│ let* (x$389) = map(x$388,x$383) in +//│ x$389 +//│ let* (x$390) = main() in +//│ x$390 //│ //│ Interpreted: //│ Cons(4,Cons(5,Nil())) diff --git a/hkmc2/shared/src/test/mlscript/llir/Legacy.mls b/hkmc2/shared/src/test/mlscript/llir/Legacy.mls index adad5b6064..ba0cc42a44 100644 --- a/hkmc2/shared/src/test/mlscript/llir/Legacy.mls +++ b/hkmc2/shared/src/test/mlscript/llir/Legacy.mls @@ -255,74 +255,74 @@ main() //│ = 404 //│ LLIR: //│ class Option() -//│ class Some(x$1602) extends Option +//│ class Some(x$1028) extends Option //│ class None() extends Option //│ class Nat() -//│ class S(s$1613) extends Nat +//│ class S(s$1039) extends Nat //│ class O() extends Nat -//│ def fromSome$1585(s$1605) = -//│ case s$1605 of -//│ Some$1599 => -//│ let x$1722 = s$1605. in -//│ x$1722 +//│ def fromSome$1011(s$1031) = +//│ case s$1031 of +//│ Some$1025 => +//│ let x$1107 = s$1031. in +//│ x$1107 //│ _ => //│ panic "match error" -//│ def j$1721() = +//│ def j$1106() = //│ null -//│ def aaa$1590() = -//│ let x$1723 = 1 in -//│ let x$1724 = 2 in -//│ let x$1725 = 3 in -//│ let x$1726 = 4 in -//│ let x$1727 = +(x$1723,x$1724) in -//│ let x$1728 = -(x$1727,x$1725) in -//│ let x$1729 = +(x$1728,x$1726) in -//│ x$1729 -//│ def bbb$1592() = -//│ let* (x$1730) = aaa() in -//│ let x$1731 = *(x$1730,100) in -//│ let x$1732 = +(x$1731,4) in -//│ x$1732 -//│ def not$1588(x$1629) = -//│ case x$1629 of +//│ def aaa$1016() = +//│ let x$1108 = 1 in +//│ let x$1109 = 2 in +//│ let x$1110 = 3 in +//│ let x$1111 = 4 in +//│ let x$1112 = +(x$1108,x$1109) in +//│ let x$1113 = -(x$1112,x$1110) in +//│ let x$1114 = +(x$1113,x$1111) in +//│ x$1114 +//│ def bbb$1018() = +//│ let* (x$1115) = aaa() in +//│ let x$1116 = *(x$1115,100) in +//│ let x$1117 = +(x$1116,4) in +//│ x$1117 +//│ def not$1014(x$1055) = +//│ case x$1055 of //│ BoolLit(true) => //│ false //│ _ => //│ true -//│ def j$1733() = +//│ def j$1118() = //│ null -//│ def foo$1595(x$1631) = -//│ case x$1631 of +//│ def foo$1021(x$1057) = +//│ case x$1057 of //│ BoolLit(true) => -//│ let x$1735 = None$1603() in -//│ x$1735 +//│ let x$1120 = None$1029() in +//│ x$1120 //│ _ => -//│ let* (x$1736) = not(x$1631) in -//│ let* (x$1737) = foo(x$1736) in -//│ let x$1738 = Some$1599(x$1737) in -//│ x$1738 -//│ def j$1734() = +//│ let* (x$1121) = not(x$1057) in +//│ let* (x$1122) = foo(x$1121) in +//│ let x$1123 = Some$1025(x$1122) in +//│ x$1123 +//│ def j$1119() = //│ null -//│ def main$1586() = -//│ let* (x$1739) = foo(false) in -//│ case x$1739 of -//│ None$1603 => -//│ let* (x$1741) = aaa() in -//│ x$1741 +//│ def main$1012() = +//│ let* (x$1124) = foo(false) in +//│ case x$1124 of +//│ None$1029 => +//│ let* (x$1126) = aaa() in +//│ x$1126 //│ _ => -//│ case x$1739 of -//│ Some$1599 => -//│ let x$1743 = x$1739. in -//│ let* (x$1744) = bbb() in -//│ x$1744 +//│ case x$1124 of +//│ Some$1025 => +//│ let x$1128 = x$1124. in +//│ let* (x$1129) = bbb() in +//│ x$1129 //│ _ => //│ panic "match error" -//│ def j$1742() = -//│ jump j$1740() -//│ def j$1740() = +//│ def j$1127() = +//│ jump j$1125() +//│ def j$1125() = //│ null -//│ let* (x$1745) = main() in -//│ x$1745 +//│ let* (x$1130) = main() in +//│ x$1130 //│ //│ Interpreted: //│ 404 diff --git a/hkmc2/shared/src/test/mlscript/llir/Method.mls b/hkmc2/shared/src/test/mlscript/llir/Method.mls index 0c742e17ab..bf994c4abb 100644 --- a/hkmc2/shared/src/test/mlscript/llir/Method.mls +++ b/hkmc2/shared/src/test/mlscript/llir/Method.mls @@ -17,9 +17,9 @@ main() //│ m$200 //│ } //│ def main$197() = -//│ let x$254 = A$198(1) in -//│ let x$255 = A.f$195(x$254) in -//│ x$255 -//│ let* (x$256) = main() in -//│ x$256 +//│ let x$213 = A$198(1) in +//│ let x$214 = A.f$195(x$213) in +//│ x$214 +//│ let* (x$215) = main() in +//│ x$215 diff --git a/hkmc2/shared/src/test/mlscript/llir/Tuple.mls b/hkmc2/shared/src/test/mlscript/llir/Tuple.mls index 911c54b0bd..d94a4baf45 100644 --- a/hkmc2/shared/src/test/mlscript/llir/Tuple.mls +++ b/hkmc2/shared/src/test/mlscript/llir/Tuple.mls @@ -11,11 +11,11 @@ mkTup(1, 2) //│ = [1, 2] //│ LLIR: //│ -//│ def mkTup$239(x$240,y$241) = -//│ let x$290 = Tuple2$274(x$240,y$241) in -//│ x$290 -//│ let* (x$291) = mkTup(1,2) in -//│ x$291 +//│ def mkTup$198(x$199,y$200) = +//│ let x$208 = Tuple2$209(x$199,y$200) in +//│ x$208 +//│ let* (x$211) = mkTup(1,2) in +//│ x$211 //│ //│ Interpreted: //│ Tuple2(1,2) From 29ad4fa22762862c272e596af4fcaa747da50a9f Mon Sep 17 00:00:00 2001 From: waterlens Date: Wed, 19 Feb 2025 17:07:59 +0800 Subject: [PATCH 38/88] Support curried function --- .../scala/hkmc2/codegen/llir/Builder.scala | 25 ++- .../src/test/mlscript/llir/HigherOrder.mls | 194 ++++++++++-------- 2 files changed, 126 insertions(+), 93 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala index f4c00c0210..f5b77fdddd 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala @@ -147,15 +147,16 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger, uid: FreshInt): val FunDefn(_own, sym, params, body) = e if !ctx.is_top_level then errStop(msg"Non top-level definition ${sym.nme} not supported") - else if params.length != 1 then - errStop(msg"Curried function or zero arguments function not supported: ${params.length.toString}") + else if params.length == 0 then + errStop(msg"Function without arguments not supported: ${params.length.toString}") else val paramsList = params.head.params val ctx2 = paramsList.foldLeft(ctx)((acc, x) => acc.addName(x.sym, x.sym)).nonTopLevel val pl = paramsList.map(_.sym) + val wrappedLambda = params.tail.foldRight(body)((params, acc) => Return(Value.Lam(params, acc), false)) Func( uid.make, sym, params = pl, resultNum = 1, - body = bBlockWithEndCont(body)(x => Node.Result(Ls(x)))(using ctx2) + body = bBlockWithEndCont(wrappedLambda)(x => Node.Result(Ls(x)))(using ctx2) ) private def bMethodDef(e: FunDefn)(using ctx: Ctx)(using Raise, Scope): Func = @@ -163,15 +164,16 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger, uid: FreshInt): val FunDefn(_own, sym, params, body) = e if !ctx.is_top_level then errStop(msg"Non top-level definition ${sym.nme} not supported") - else if params.length != 1 then - errStop(msg"Curried function or zero arguments function not supported: ${params.length.toString}") + else if params.length == 0 then + errStop(msg"Function without arguments not supported: ${params.length.toString}") else val paramsList = params.head.params val ctx2 = paramsList.foldLeft(ctx)((acc, x) => acc.addName(x.sym, x.sym)).nonTopLevel val pl = paramsList.map(_.sym) + val wrappedLambda = params.tail.foldRight(body)((params, acc) => Return(Value.Lam(params, acc), false)) Func( uid.make, sym, params = pl, resultNum = 1, - body = bBlockWithEndCont(body)(x => Node.Result(Ls(x)))(using ctx2) + body = bBlockWithEndCont(wrappedLambda)(x => Node.Result(Ls(x)))(using ctx2) ) private def bClsLikeDef(e: ClsLikeDefn)(using ctx: Ctx)(using Raise, Scope): ClassInfo = @@ -428,12 +430,9 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger, uid: FreshInt): bBind(S(lhs), rhs, rest)(k)(ct) case AssignField(lhs, nme, rhs, rest) => TODO("AssignField not supported") case Define(fd @ FunDefn(_own, sym, params, body), rest) => - if params.length != 1 then - errStop(msg"Curried function or zero arguments function not supported: ${params.length.toString}") - val ctx2 = ctx.addFuncName(sym, params.head.params.length) - val f = bFunDef(fd)(using ctx2) + val f = bFunDef(fd)(using ctx) ctx.def_acc += f - bBlock(rest)(k)(ct)(using ctx2) + bBlock(rest)(k)(ct)(using ctx) case Define(_: ClsLikeDefn, rest) => bBlock(rest)(k)(ct) case End(msg) => k(Expr.Literal(Tree.UnitLit(false))) case _: Block => @@ -467,8 +466,8 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger, uid: FreshInt): def registerFunctions(b: Block)(using ctx: Ctx)(using Raise, Scope): Ctx = b match case Define(fd @ FunDefn(_own, sym, params, body), rest) => - if params.length != 1 then - errStop(msg"Curried function or zero arguments function not supported: ${params.length.toString}") + if params.length == 0 then + errStop(msg"Function without arguments not supported: ${params.length.toString}") val ctx2 = ctx.addFuncName(sym, params.head.params.length) log(s"Define function: ${sym.nme} -> ${ctx2}") registerFunctions(rest)(using ctx2) diff --git a/hkmc2/shared/src/test/mlscript/llir/HigherOrder.mls b/hkmc2/shared/src/test/mlscript/llir/HigherOrder.mls index 01e4c91a84..545672eb1b 100644 --- a/hkmc2/shared/src/test/mlscript/llir/HigherOrder.mls +++ b/hkmc2/shared/src/test/mlscript/llir/HigherOrder.mls @@ -8,25 +8,35 @@ :intl :scpp fun add(x) = y => x + y +fun add_curried(x)(y) = x + y add(1)(2) //│ = 3 //│ LLIR: -//│ class Lambda(x$199) extends Callable { -//│ def apply1$216(y$200) = -//│ let x$217 = +(x$199,y$200) in -//│ x$217 +//│ class Lambda(x$200) extends Callable { +//│ def apply1$221(y$201) = +//│ let x$222 = +(x$200,y$201) in +//│ x$222 //│ } -//│ def add$198(x$199) = -//│ let x$218 = Lambda$214(x$199) in -//│ x$218 -//│ let* (x$219) = add(1) in -//│ let x$220 = Callable.apply1$216(x$219,2) in -//│ x$220 +//│ class Lambda(x$204) extends Callable { +//│ def apply1$221(y$205) = +//│ let x$226 = +(x$204,y$205) in +//│ x$226 +//│ } +//│ def add$198(x$200) = +//│ let x$223 = Lambda$219(x$200) in +//│ x$223 +//│ def add_curried$199(x$204) = +//│ let x$227 = Lambda$224(x$204) in +//│ x$227 +//│ let* (x$228) = add(1) in +//│ let x$229 = Callable.apply1$221(x$228,2) in +//│ x$229 //│ //│ Cpp: //│ #include "mlsprelude.h" //│ struct Lambda; //│ _mlsValue add(_mlsValue); +//│ _mlsValue add_curried(_mlsValue); //│ _mlsValue _mlsMain(); //│ struct Lambda: public Callable { //│ _mlsValue x; @@ -48,11 +58,17 @@ add(1)(2) //│ _mls_retval = x2; //│ return _mls_retval; //│ } +//│ _mlsValue add_curried(_mlsValue x4) { +//│ _mlsValue _mls_retval; +//│ auto x3 = _mlsValue::create(x4); +//│ _mls_retval = x3; +//│ return _mls_retval; +//│ } //│ _mlsValue _mlsMain() { //│ _mlsValue _mls_retval; -//│ auto x3 = add(_mlsValue::fromIntLit(1)); -//│ auto x4 = _mlsMethodCall(x3)->apply1(_mlsValue::fromIntLit(2)); -//│ _mls_retval = x4; +//│ auto x5 = add(_mlsValue::fromIntLit(1)); +//│ auto x6 = _mlsMethodCall(x5)->apply1(_mlsValue::fromIntLit(2)); +//│ _mls_retval = x6; //│ return _mls_retval; //│ } //│ int main() { return _mlsLargeStack(_mlsMainWrapper); } @@ -64,27 +80,39 @@ add(1)(2) :intl :scpp fun add4(a, b) = (c, d) => a + b + c + d +fun add4_curried(a, b)(c, d) = a + b + c + d add4(1, 2)(3, 4) //│ = 10 //│ LLIR: -//│ class Lambda(b$223,a$222) extends Callable { -//│ def apply2$247(c$224,d$225) = -//│ let x$248 = +(a$222,b$223) in -//│ let x$249 = +(x$248,c$224) in -//│ let x$250 = +(x$249,d$225) in -//│ x$250 +//│ class Lambda(b$233,a$232) extends Callable { +//│ def apply2$269(c$234,d$235) = +//│ let x$270 = +(a$232,b$233) in +//│ let x$271 = +(x$270,c$234) in +//│ let x$272 = +(x$271,d$235) in +//│ x$272 +//│ } +//│ class Lambda(a$240,b$241) extends Callable { +//│ def apply2$269(c$242,d$243) = +//│ let x$276 = +(a$240,b$241) in +//│ let x$277 = +(x$276,c$242) in +//│ let x$278 = +(x$277,d$243) in +//│ x$278 //│ } -//│ def add4$221(a$222,b$223) = -//│ let x$251 = Lambda$245(b$223,a$222) in -//│ x$251 -//│ let* (x$252) = add4(1,2) in -//│ let x$253 = Callable.apply2$247(x$252,3,4) in -//│ x$253 +//│ def add4$231(a$232,b$233) = +//│ let x$273 = Lambda$267(b$233,a$232) in +//│ x$273 +//│ def add4_curried$230(a$240,b$241) = +//│ let x$279 = Lambda$274(a$240,b$241) in +//│ x$279 +//│ let* (x$280) = add4(1,2) in +//│ let x$281 = Callable.apply2$269(x$280,3,4) in +//│ x$281 //│ //│ Cpp: //│ #include "mlsprelude.h" //│ struct Lambda; //│ _mlsValue add4(_mlsValue, _mlsValue); +//│ _mlsValue add4_curried(_mlsValue, _mlsValue); //│ _mlsValue _mlsMain(); //│ struct Lambda: public Callable { //│ _mlsValue b; @@ -109,11 +137,17 @@ add4(1, 2)(3, 4) //│ _mls_retval = x3; //│ return _mls_retval; //│ } +//│ _mlsValue add4_curried(_mlsValue a1, _mlsValue b1) { +//│ _mlsValue _mls_retval; +//│ auto x4 = _mlsValue::create(a1, b1); +//│ _mls_retval = x4; +//│ return _mls_retval; +//│ } //│ _mlsValue _mlsMain() { //│ _mlsValue _mls_retval; -//│ auto x4 = add4(_mlsValue::fromIntLit(1), _mlsValue::fromIntLit(2)); -//│ auto x5 = _mlsMethodCall(x4)->apply2(_mlsValue::fromIntLit(3), _mlsValue::fromIntLit(4)); -//│ _mls_retval = x5; +//│ auto x5 = add4(_mlsValue::fromIntLit(1), _mlsValue::fromIntLit(2)); +//│ auto x6 = _mlsMethodCall(x5)->apply2(_mlsValue::fromIntLit(3), _mlsValue::fromIntLit(4)); +//│ _mls_retval = x6; //│ return _mls_retval; //│ } //│ int main() { return _mlsLargeStack(_mlsMainWrapper); } @@ -130,19 +164,19 @@ dummy()(1, 2) //│ = 3 //│ LLIR: //│ class Lambda_add() extends Callable { -//│ def apply2$277(arg$273,arg$274) = -//│ let* (x$278) = add(arg$273,arg$274) in -//│ x$278 +//│ def apply2$305(arg$301,arg$302) = +//│ let* (x$306) = add(arg$301,arg$302) in +//│ x$306 //│ } -//│ def add$254(a$256,b$257) = -//│ let x$272 = +(a$256,b$257) in -//│ x$272 -//│ def dummy$255() = -//│ let x$279 = Lambda_add$275() in -//│ x$279 -//│ let* (x$280) = dummy() in -//│ let x$281 = Callable.apply2$277(x$280,1,2) in -//│ x$281 +//│ def add$282(a$284,b$285) = +//│ let x$300 = +(a$284,b$285) in +//│ x$300 +//│ def dummy$283() = +//│ let x$307 = Lambda_add$303() in +//│ x$307 +//│ let* (x$308) = dummy() in +//│ let x$309 = Callable.apply2$305(x$308,1,2) in +//│ x$309 //│ //│ Cpp: //│ #include "mlsprelude.h" @@ -205,55 +239,55 @@ main() //│ = Cons(4, Cons(5, Nil)) //│ LLIR: //│ class List() -//│ class Cons(head$294,tail$295) extends List +//│ class Cons(head$322,tail$323) extends List //│ class Nil() extends List //│ class Lambda() extends Callable { -//│ def apply1$367(x$312) = -//│ let* (x$378) = inc(x$312) in -//│ x$378 +//│ def apply1$395(x$340) = +//│ let* (x$406) = inc(x$340) in +//│ x$406 //│ } //│ class Lambda_inc() extends Callable { -//│ def apply1$367(arg$384) = -//│ let* (x$387) = inc(arg$384) in -//│ x$387 +//│ def apply1$395(arg$412) = +//│ let* (x$415) = inc(arg$412) in +//│ x$415 //│ } -//│ def map$283(f$298,l$299) = -//│ case l$299 of -//│ Cons$291 => -//│ let x$364 = l$299. in -//│ let x$365 = l$299. in -//│ let x$366 = Callable.apply1$367(f$298,x$364) in -//│ let* (x$368) = map(f$298,x$365) in -//│ let x$369 = Cons$291(x$366,x$368) in -//│ x$369 +//│ def map$311(f$326,l$327) = +//│ case l$327 of +//│ Cons$319 => +//│ let x$392 = l$327. in +//│ let x$393 = l$327. in +//│ let x$394 = Callable.apply1$395(f$326,x$392) in +//│ let* (x$396) = map(f$326,x$393) in +//│ let x$397 = Cons$319(x$394,x$396) in +//│ x$397 //│ _ => -//│ case l$299 of -//│ Nil$296 => -//│ let x$371 = Nil$296() in -//│ x$371 +//│ case l$327 of +//│ Nil$324 => +//│ let x$399 = Nil$324() in +//│ x$399 //│ _ => //│ panic "match error" -//│ def j$370() = -//│ jump j$363() -//│ def j$363() = +//│ def j$398() = +//│ jump j$391() +//│ def j$391() = //│ null -//│ def inc$286(x$308) = -//│ let x$372 = +(x$308,1) in -//│ x$372 -//│ def main$284() = -//│ let x$373 = Nil$296() in -//│ let x$374 = Cons$291(2,x$373) in -//│ let x$375 = Cons$291(1,x$374) in -//│ let x$379 = Lambda$376() in -//│ let* (x$380) = map(x$379,x$375) in -//│ let x$381 = Nil$296() in -//│ let x$382 = Cons$291(4,x$381) in -//│ let x$383 = Cons$291(3,x$382) in -//│ let x$388 = Lambda_inc$385() in -//│ let* (x$389) = map(x$388,x$383) in -//│ x$389 -//│ let* (x$390) = main() in -//│ x$390 +//│ def inc$314(x$336) = +//│ let x$400 = +(x$336,1) in +//│ x$400 +//│ def main$312() = +//│ let x$401 = Nil$324() in +//│ let x$402 = Cons$319(2,x$401) in +//│ let x$403 = Cons$319(1,x$402) in +//│ let x$407 = Lambda$404() in +//│ let* (x$408) = map(x$407,x$403) in +//│ let x$409 = Nil$324() in +//│ let x$410 = Cons$319(4,x$409) in +//│ let x$411 = Cons$319(3,x$410) in +//│ let x$416 = Lambda_inc$413() in +//│ let* (x$417) = map(x$416,x$411) in +//│ x$417 +//│ let* (x$418) = main() in +//│ x$418 //│ //│ Interpreted: //│ Cons(4,Cons(5,Nil())) From ea7628e54542692fe9ab5fbd17b611c0601795f2 Mon Sep 17 00:00:00 2001 From: waterlens Date: Wed, 19 Feb 2025 17:12:54 +0800 Subject: [PATCH 39/88] Support tuple selection --- .../scala/hkmc2/codegen/llir/Builder.scala | 3 ++- .../src/test/mlscript/llir/NofibPrelude.mls | 10 +-------- hkmc2/shared/src/test/mlscript/llir/Tuple.mls | 21 ++++++++++++++----- 3 files changed, 19 insertions(+), 15 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala index f5b77fdddd..2defb910c0 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala @@ -392,7 +392,8 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger, uid: FreshInt): case (Case.Cls(cls, _), body) => (Pat.Class(cls), bBlock(body)(cont)(nextCont)(using ctx)) case (Case.Tup(len, inf), body) => - (Pat.Class(builtinTuple(len)), bBlock(body)(cont)(nextCont)(using ctx)) + val ctx2 = ctx.addKnownClass(scrut, builtinTuple(len)) + (Pat.Class(builtinTuple(len)), bBlock(body)(cont)(nextCont)(using ctx2)) val defaultCase = dflt.map(bBlock(_)(cont)(nextCont)(using ctx)) val jpdef = Func( uid.make, diff --git a/hkmc2/shared/src/test/mlscript/llir/NofibPrelude.mls b/hkmc2/shared/src/test/mlscript/llir/NofibPrelude.mls index 0bd4b4c5eb..0e01d58c9e 100644 --- a/hkmc2/shared/src/test/mlscript/llir/NofibPrelude.mls +++ b/hkmc2/shared/src/test/mlscript/llir/NofibPrelude.mls @@ -28,17 +28,11 @@ fun ltTup2(t1, t2, lt1, gt1, lt2) = if t1 is [a, b] and t2 is [c, d] and gt1(a, c) then false else lt2(b, d) fun eqTup2(t1, t2) = if t1 is [a, b] and t2 is [c, d] then a == c and b == d -//│ FAILURE: Unexpected compilation error -//│ ═══[COMPILATION ERROR] Unsupported selection by users -//│ Stopped due to an error during the Llir generation fun compose(f, g) = x => f(g(x)) fun snd(x) = if x is [f, s] then s fun fst(x) = if x is [f, s] then f -//│ FAILURE: Unexpected compilation error -//│ ═══[COMPILATION ERROR] Unsupported selection by users -//│ Stopped due to an error during the Llir generation fun until(p, f, i) = if p(i) then i else until(p, f, f(i)) @@ -266,9 +260,6 @@ fun break_(p, ls) = if ls is x :: xs and p(x) then [Nil, x :: xs] break_(p, xs) is [ys, zs] then [x :: ys, zs] -//│ FAILURE: Unexpected compilation error -//│ ═══[COMPILATION ERROR] Unsupported selection by users -//│ Stopped due to an error during the Llir generation fun flatMap(f, ls) = if ls is Nil then Nil @@ -276,3 +267,4 @@ fun flatMap(f, ls) = if ls is //│ FAILURE: Unexpected compilation error //│ ═══[COMPILATION ERROR] Name not found: member:append //│ Stopped due to an error during the Llir generation + diff --git a/hkmc2/shared/src/test/mlscript/llir/Tuple.mls b/hkmc2/shared/src/test/mlscript/llir/Tuple.mls index d94a4baf45..0a4a94df8f 100644 --- a/hkmc2/shared/src/test/mlscript/llir/Tuple.mls +++ b/hkmc2/shared/src/test/mlscript/llir/Tuple.mls @@ -7,15 +7,26 @@ :intl :sllir fun mkTup(x, y) = [x, y] +fun fst(t) = if t is [x, y] then x mkTup(1, 2) //│ = [1, 2] //│ LLIR: //│ -//│ def mkTup$198(x$199,y$200) = -//│ let x$208 = Tuple2$209(x$199,y$200) in -//│ x$208 -//│ let* (x$211) = mkTup(1,2) in -//│ x$211 +//│ def mkTup$198(x$200,y$201) = +//│ let x$215 = Tuple2$216(x$200,y$201) in +//│ x$215 +//│ def fst$199(t$203) = +//│ case t$203 of +//│ Tuple2$216 => +//│ let x$219 = t$203. in +//│ let x$220 = t$203. in +//│ x$219 +//│ _ => +//│ panic "match error" +//│ def j$218() = +//│ null +//│ let* (x$221) = mkTup(1,2) in +//│ x$221 //│ //│ Interpreted: //│ Tuple2(1,2) From 5c0888ed0a985b70b68705bf73610ffd92ef6e93 Mon Sep 17 00:00:00 2001 From: waterlens Date: Wed, 19 Feb 2025 20:47:31 +0800 Subject: [PATCH 40/88] Fix some problems --- .../scala/hkmc2/codegen/cpp/CodeGen.scala | 143 ++++++++-------- .../scala/hkmc2/codegen/llir/Builder.scala | 33 ++-- .../src/test/mlscript/llir/BadPrograms.mls | 2 +- .../src/test/mlscript/llir/BasicCpp.mls | 40 ++--- .../shared/src/test/mlscript/llir/Classes.mls | 1 - .../src/test/mlscript/llir/ControlFlow.mls | 66 ++++---- .../src/test/mlscript/llir/HigherOrder.mls | 159 +++++++++++------- .../src/test/mlscript/llir/NofibPrelude.mls | 30 +--- .../src/test/scala/hkmc2/LlirDiffMaker.scala | 72 +++++--- 9 files changed, 294 insertions(+), 252 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/CodeGen.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/CodeGen.scala index 1605e31da2..dbfb159458 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/CodeGen.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/CodeGen.scala @@ -11,9 +11,12 @@ import hkmc2.utils.{Scope, TraceLogger} import hkmc2.Raise import hkmc2.semantics.BuiltinSymbol -class CppCodeGen(tl: TraceLogger): +class CppCodeGen(builtinClassSymbols: Set[Local], tl: TraceLogger): import tl.{trace, log, logs} def mapName(name: Str): Str = "_mls_" + name.replace('$', '_').replace('\'', '_') + def directName(sym: Local)(using Raise, Scope): Str = + if builtinClassSymbols.contains(sym) then sym.nme + else allocIfNew(sym) val mlsValType = Type.Prim("_mlsValue") val mlsUnitValue = Expr.Call(Expr.Var("_mlsValue::create<_mls_Unit>"), Ls()); val mlsRetValue = "_mls_retval" @@ -55,7 +58,7 @@ class CppCodeGen(tl: TraceLogger): def mlsThrowNonExhaustiveMatch = Stmt.Raw("_mlsNonExhaustiveMatch();"); def mlsCall(fn: Str, args: Ls[Expr]) = Expr.Call(Expr.Var("_mlsCall"), Expr.Var(fn) :: args) def mlsMethodCall(cls: Local, method: Str, args: Ls[Expr])(using Raise, Scope) = - Expr.Call(Expr.Member(Expr.Call(Expr.Var(s"_mlsMethodCall<${cls.nme}>"), Ls(args.head)), method), args.tail) + Expr.Call(Expr.Member(Expr.Call(Expr.Var(s"_mlsMethodCall<${cls |> directName}>"), Ls(args.head)), method), args.tail) def mlsFnWrapperName(fn: Str) = s"_mlsFn_$fn" def mlsFnCreateMethod(fn: Str) = s"static _mlsValue create() { static _mlsFn_$fn mlsFn alignas(_mlsAlignment); mlsFn.refCount = stickyRefCount; mlsFn.tag = typeTag; return _mlsValue(&mlsFn); }" def mlsNeverValue(n: Int) = if (n <= 1) then Expr.Call(Expr.Var(s"_mlsValue::never"), Ls()) else Expr.Call(Expr.Var(s"_mlsValue::never<$n>"), Ls()) @@ -70,39 +73,39 @@ class CppCodeGen(tl: TraceLogger): case S(owner) => summon[Scope].lookup_!(ts) case N => summon[Scope].lookup_!(ts) case ts: hkmc2.semantics.InnerSymbol => - if ts.asMod.isDefined - then - summon[Scope].lookup_!(ts) - else summon[Scope].findThis_!(ts) + summon[Scope].lookup_!(ts) case _ => summon[Scope].lookup_!(l) - def allocIfNew(l: Local)(using Raise, Scope): String = - if summon[Scope].lookup(l).isDefined then - getVar(l) - else - summon[Scope].allocateName(l) + def allocIfNew(l: Local)(using Raise, Scope): Str = + trace[Str](s"allocIfNew $l begin", r => s"allocIfNew $l end -> $r"): + if summon[Scope].lookup(l).isDefined then + getVar(l) |> mapName + else + summon[Scope].allocateName(l) |> mapName def codegenClassInfo(using Ctx, Raise, Scope)(cls: ClassInfo): (Opt[Def], Decl) = - val fields = cls.fields.map{x => (x |> allocIfNew, mlsValType)} - val parents = if cls.parents.nonEmpty then cls.parents.toList.map(_.nme) else mlsObject :: Nil - val decl = Decl.StructDecl(cls.name.nme) - if mlsIsInternalClass(cls.name) then return (None, decl) - val theDef = Def.StructDef( - cls.name |> allocIfNew, fields, - if parents.nonEmpty then Some(parents) else None, - Ls(Def.RawDef(mlsObjectNameMethod(cls.name.nme)), - Def.RawDef(mlsTypeTag()), - Def.RawDef(mlsCommonPrintMethod(cls.fields.map(_.nme))), - Def.RawDef(mlsCommonDestructorMethod(cls.name.nme, cls.fields.map(_.nme))), - Def.RawDef(mlsCommonCreateMethod(cls.name.nme, cls.fields.map(_.nme), cls.id))) - ++ cls.methods.map{case (name, defn) => { - val (theDef, decl) = codegenDefn(using Ctx(summon[Ctx].defnCtx + cls.name))(defn) - theDef match - case x @ Def.FuncDef(_, name, _, _, _, _) => x.copy(virt = true) - case _ => theDef - }} - ) - (S(theDef), decl) + trace[(Opt[Def], Decl)](s"codegenClassInfo ${cls.name} begin"): + val fields = cls.fields.map{x => (x |> directName, mlsValType)} + val parents = if cls.parents.nonEmpty then cls.parents.toList.map(directName) else mlsObject :: Nil + val decl = Decl.StructDecl(cls.name |> directName) + if mlsIsInternalClass(cls.name) then (None, decl) + else + val theDef = Def.StructDef( + cls.name |> directName, fields, + if parents.nonEmpty then Some(parents) else None, + Ls(Def.RawDef(mlsObjectNameMethod(cls.name |> directName)), + Def.RawDef(mlsTypeTag()), + Def.RawDef(mlsCommonPrintMethod(cls.fields.map(directName))), + Def.RawDef(mlsCommonDestructorMethod(cls.name |> directName, cls.fields.map(directName))), + Def.RawDef(mlsCommonCreateMethod(cls.name |> directName, cls.fields.map(directName), cls.id))) + ++ cls.methods.map{case (name, defn) => { + val (theDef, decl) = codegenDefn(using Ctx(summon[Ctx].defnCtx + cls.name))(defn) + theDef match + case x @ Def.FuncDef(_, name, _, _, _, _) => x.copy(virt = true) + case _ => theDef + }} + ) + (S(theDef), decl) def toExpr(texpr: TrivialExpr, reifyUnit: Bool = false)(using Ctx, Raise, Scope): Opt[Expr] = texpr match case IExpr.Ref(name) => S(Expr.Var(name |> allocIfNew)) @@ -137,7 +140,7 @@ class CppCodeGen(tl: TraceLogger): val stmt = cases.foldRight(S(init)) { case ((Pat.Class(cls), arm), nextarm) => val (decls2, stmts2) = codegen(arm, storeInto)(using Ls.empty, Ls.empty[Stmt]) - val stmt = Stmt.If(mlsIsValueOf(cls.nme, scrut2), Stmt.Block(decls2, stmts2), nextarm) + val stmt = Stmt.If(mlsIsValueOf(cls |> directName, scrut2), Stmt.Block(decls2, stmts2), nextarm) S(stmt) case ((Pat.Lit(i @ hkmc2.syntax.Tree.IntLit(_)), arm), nextarm) => val (decls2, stmts2) = codegen(arm, storeInto)(using Ls.empty, Ls.empty[Stmt]) @@ -178,8 +181,8 @@ class CppCodeGen(tl: TraceLogger): def codegen(expr: IExpr)(using Ctx, Raise, Scope): Expr = expr match case x @ (IExpr.Ref(_) | IExpr.Literal(_)) => toExpr(x, reifyUnit = true).get - case IExpr.CtorApp(cls, args) => mlsNewValue(cls.nme, args.map(toExpr)) - case IExpr.Select(name, cls, field) => Expr.Member(mlsAsUnchecked(name |> allocIfNew, cls.nme), field) + case IExpr.CtorApp(cls, args) => mlsNewValue(cls |> directName, args.map(toExpr)) + case IExpr.Select(name, cls, field) => Expr.Member(mlsAsUnchecked(name |> allocIfNew, cls |> directName), field) case IExpr.BasicOp(name, args) => codegenOps(name, args) case IExpr.AssignField(assignee, cls, field, value) => TODO("codegen assign field") @@ -200,34 +203,36 @@ class CppCodeGen(tl: TraceLogger): "apply9", ) - def codegen(body: Node, storeInto: Str)(using decls: Ls[Decl], stmts: Ls[Stmt])(using Ctx, Raise, Scope): (Ls[Decl], Ls[Stmt]) = body match - case Node.Result(res) => - val expr = wrapMultiValues(res) - val stmts2 = stmts ++ Ls(Stmt.Assign(storeInto, expr)) - (decls, stmts2) - case Node.Jump(defn, args) => - codegenJumpWithCall(defn, args, S(storeInto)) - case Node.Panic(msg) => (decls, stmts :+ Stmt.Raw(s"throw std::runtime_error(\"$msg\");")) - case Node.LetExpr(name, expr, body) => - val stmts2 = stmts ++ Ls(Stmt.AutoBind(Ls(name |> allocIfNew), codegen(expr))) - codegen(body, storeInto)(using decls, stmts2) - case Node.LetMethodCall(names, cls, method, IExpr.Ref(bin: BuiltinSymbol) :: args, body) if bin.nme == "builtin" => - val stmts2 = stmts ++ codegenBuiltin(names, args.head.toString.replace("\"", ""), args.tail) - codegen(body, storeInto)(using decls, stmts2) - case Node.LetMethodCall(names, cls, method, args, body) if builtinApply.contains(method.nme) => - val call = mlsMethodCall(cls, method.nme, args.map(toExpr)) - val stmts2 = stmts ++ Ls(Stmt.AutoBind(names.map(allocIfNew), call)) - codegen(body, storeInto)(using decls, stmts2) - case Node.LetMethodCall(names, cls, method, args, body) => - val call = mlsMethodCall(cls, method |> allocIfNew, args.map(toExpr)) - val stmts2 = stmts ++ Ls(Stmt.AutoBind(names.map(allocIfNew), call)) - codegen(body, storeInto)(using decls, stmts2) - case Node.LetCall(names, defn, args, body) => - val call = Expr.Call(Expr.Var(defn |> allocIfNew), args.map(toExpr)) - val stmts2 = stmts ++ Ls(Stmt.AutoBind(names.map(allocIfNew), call)) - codegen(body, storeInto)(using decls, stmts2) - case Node.Case(scrut, cases, default) => - codegenCaseWithIfs(scrut, cases, default, storeInto) + def codegen(body: Node, storeInto: Str)(using decls: Ls[Decl], stmts: Ls[Stmt])(using Ctx, Raise, Scope): (Ls[Decl], Ls[Stmt]) = + trace[(Ls[Decl], Ls[Stmt])](s"codegen $body begin"): + body match + case Node.Result(res) => + val expr = wrapMultiValues(res) + val stmts2 = stmts ++ Ls(Stmt.Assign(storeInto, expr)) + (decls, stmts2) + case Node.Jump(defn, args) => + codegenJumpWithCall(defn, args, S(storeInto)) + case Node.Panic(msg) => (decls, stmts :+ Stmt.Raw(s"throw std::runtime_error(\"$msg\");")) + case Node.LetExpr(name, expr, body) => + val stmts2 = stmts ++ Ls(Stmt.AutoBind(Ls(name |> allocIfNew), codegen(expr))) + codegen(body, storeInto)(using decls, stmts2) + case Node.LetMethodCall(names, cls, method, IExpr.Ref(bin: BuiltinSymbol) :: args, body) if bin.nme == "builtin" => + val stmts2 = stmts ++ codegenBuiltin(names, args.head.toString.replace("\"", ""), args.tail) + codegen(body, storeInto)(using decls, stmts2) + case Node.LetMethodCall(names, cls, method, args, body) if builtinApply.contains(method.nme) => + val call = mlsMethodCall(cls, method |> directName, args.map(toExpr)) + val stmts2 = stmts ++ Ls(Stmt.AutoBind(names.map(allocIfNew), call)) + codegen(body, storeInto)(using decls, stmts2) + case Node.LetMethodCall(names, cls, method, args, body) => + val call = mlsMethodCall(cls, method |> allocIfNew, args.map(toExpr)) + val stmts2 = stmts ++ Ls(Stmt.AutoBind(names.map(allocIfNew), call)) + codegen(body, storeInto)(using decls, stmts2) + case Node.LetCall(names, defn, args, body) => + val call = Expr.Call(Expr.Var(defn |> allocIfNew), args.map(toExpr)) + val stmts2 = stmts ++ Ls(Stmt.AutoBind(names.map(allocIfNew), call)) + codegen(body, storeInto)(using decls, stmts2) + case Node.Case(scrut, cases, default) => + codegenCaseWithIfs(scrut, cases, default, storeInto) def codegenDefn(using Ctx, Raise, Scope)(defn: Func): (Def, Decl) = defn match case Func(id, name, params, resultNum, body) => @@ -249,10 +254,10 @@ class CppCodeGen(tl: TraceLogger): (theDef, decl) // Topological sort of classes based on inheritance relationships - def sortClasses(builtinSymbols: Set[Local], prog: Program): Ls[ClassInfo] = - val builtinClasses = Set("Callable") - var depgraph = prog.classes.map(x => (x.name.nme, x.parents.map(_.nme))).toMap - ++ builtinClasses.map(x => (x, Set.empty[String])) + def sortClasses(prog: Program)(using Raise, Scope): Ls[ClassInfo] = + var depgraph = prog.classes.map(x => (x.name |> directName, x.parents.map(directName))).toMap + ++ builtinClassSymbols.map(x => (x |> directName, Set.empty[String])) + log(s"depgraph: $depgraph") var degree = depgraph.view.mapValues(_.size).toMap def removeNode(node: String) = degree -= node @@ -264,7 +269,7 @@ class CppCodeGen(tl: TraceLogger): while work.nonEmpty do val node = work.head work -= node - prog.classes.find(_.name.nme == node).fold(())(sorted.addOne) + prog.classes.find(x => (x.name |> directName) == node).fold(())(sorted.addOne) removeNode(node) val next = degree.filter(_._2 == 0).keys work ++= next @@ -273,8 +278,8 @@ class CppCodeGen(tl: TraceLogger): throw new Exception(s"Cycle detected in class hierarchy: $cycle") sorted.toList - def codegen(builtinSymbols: Set[Local], prog: Program)(using Raise, Scope): CompilationUnit = - val sortedClasses = sortClasses(builtinSymbols, prog) + def codegen(prog: Program)(using Raise, Scope): CompilationUnit = + val sortedClasses = sortClasses(prog) val defnCtx = prog.defs.map(_.name) val (defs, decls) = sortedClasses.map(codegenClassInfo(using Ctx(defnCtx))).unzip val (defs2, decls2) = prog.defs.map(codegenDefn(using Ctx(defnCtx))).unzip diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala index 2defb910c0..ba93b9fdb1 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala @@ -189,8 +189,8 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger, uid: FreshInt): given Ctx = ctx.setClass(isym) val funcs = methods.map(bMethodDef) def parentFromPath(p: Path): Set[Local] = p match - case Value.Ref(l) => Set(l) - case Select(Value.Ref(l), Tree.Ident("class")) => Set(l) + case Value.Ref(l) => Set(fromMemToClass(l)) + case Select(Value.Ref(l), Tree.Ident("class")) => Set(fromMemToClass(l)) case _ => errStop(msg"Unsupported parent path ${p.toString()}") ClassInfo( uid.make, @@ -267,17 +267,17 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger, uid: FreshInt): case Some(d: ClassLikeDef) => d.owner.get case Some(d: TermDefinition) => d.owner.get case Some(value) => errStop(msg"Member symbol without class definition ${value.toString}") - case None => errStop(msg"Member symbol without definition") + case None => errStop(msg"Member symbol without definition ${ms.toString}") private def fromMemToClass(m: Symbol)(using ctx: Ctx)(using Raise, Scope): Local = - trace[Local](s"bFromMemToClass", x => s"bFromMemToClass end: $x"): + trace[Local](s"bFromMemToClass $m", x => s"bFromMemToClass end: $x"): m match case ms: MemberSymbol[?] => ms.defn match - case Some(d: ClassLikeDef) => d.sym + case Some(d: ClassLikeDef) => d.sym.asClsLike.getOrElse(errStop(msg"Class definition without symbol")) case Some(d: TermDefinition) => d.sym case Some(value) => errStop(msg"Member symbol without class definition ${value.toString}") - case None => errStop(msg"Member symbol without definition") + case None => errStop(msg"Member symbol without definition ${ms.toString}") case _ => errStop(msg"Unsupported symbol kind ${m.toString}") @@ -445,7 +445,7 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger, uid: FreshInt): case Define(cd @ ClsLikeDefn(_own, isym, sym, kind, _paramsOpt, parentSym, methods, privateFields, publicFields, preCtor, ctor), rest) => val c = bClsLikeDef(cd) ctx.class_acc += c - val new_ctx = ctx.addClassInfo(sym, c).addClassInfo(isym, c) + val new_ctx = ctx.addClassInfo(isym, c) log(s"Define class: ${isym.toString()} -> ${ctx}") registerClasses(rest)(using new_ctx) case _ => @@ -454,13 +454,7 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger, uid: FreshInt): def registerInternalClasses(using ctx: Ctx)(using Raise, Scope): Ctx = tupleSym.foldLeft(ctx): case (ctx, (len, sym)) => - val c = ClassInfo( - uid.make, - sym, - (0 until len).map(x => builtinField(x)).toList, - Set.empty, - Map.empty, - ) + val c = ClassInfo(uid.make, sym, (0 until len).map(x => builtinField(x)).toList, Set.empty, Map.empty) ctx.class_acc += c ctx.addClassInfo(sym, c) @@ -475,8 +469,8 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger, uid: FreshInt): case _ => b.subBlocks.foldLeft(ctx)((ctx, rest) => registerFunctions(rest)(using ctx)) - def bProg(e: Program)(using Raise, Scope): LlirProgram = - var ctx = Ctx.empty + def bProg(e: Program)(using Raise, Scope, Ctx): (LlirProgram, Ctx) = + var ctx = summon[Ctx] // * Classes may be defined after other things such as functions, // * especially now that the elaborator moves all functions to the top of the block. @@ -489,5 +483,10 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger, uid: FreshInt): ctx = registerInternalClasses(using ctx) - LlirProgram(ctx.class_acc.toSet, ctx.def_acc.toSet, entry) + val prog = LlirProgram(ctx.class_acc.toSet, ctx.def_acc.toSet, entry) + + ctx.class_acc.clear() + ctx.def_acc.clear() + + (prog, ctx) diff --git a/hkmc2/shared/src/test/mlscript/llir/BadPrograms.mls b/hkmc2/shared/src/test/mlscript/llir/BadPrograms.mls index 931f95a27d..0a4417b4ee 100644 --- a/hkmc2/shared/src/test/mlscript/llir/BadPrograms.mls +++ b/hkmc2/shared/src/test/mlscript/llir/BadPrograms.mls @@ -10,7 +10,7 @@ fun oops(a) = class A with fun m = a let x = 1 -//│ ═══[COMPILATION ERROR] Curried function or zero arguments function not supported: 0 +//│ ═══[COMPILATION ERROR] Function without arguments not supported: 0 //│ Stopped due to an error during the Llir generation :ge diff --git a/hkmc2/shared/src/test/mlscript/llir/BasicCpp.mls b/hkmc2/shared/src/test/mlscript/llir/BasicCpp.mls index 060aaab7b3..0cb1ff92e2 100644 --- a/hkmc2/shared/src/test/mlscript/llir/BasicCpp.mls +++ b/hkmc2/shared/src/test/mlscript/llir/BasicCpp.mls @@ -3,8 +3,6 @@ :llir :cpp - -:scpp :sllir fun foo(a) = let x @@ -28,37 +26,39 @@ fun foo(a) = //│ let x$210 = +(x$197,1) in //│ x$210 //│ undefined + +:showWholeCpp +foo(1) //│ -//│ Cpp: +//│ WholeProgramCpp: //│ #include "mlsprelude.h" -//│ _mlsValue j(_mlsValue); -//│ _mlsValue foo(_mlsValue); +//│ _mlsValue _mls_j(_mlsValue); +//│ _mlsValue _mls_foo(_mlsValue); //│ _mlsValue _mlsMain(); -//│ _mlsValue j(_mlsValue x1) { +//│ _mlsValue _mls_j(_mlsValue _mls_x1) { //│ _mlsValue _mls_retval; -//│ auto x = (x1 + _mlsValue::fromIntLit(1)); -//│ _mls_retval = x; +//│ auto _mls_x = (_mls_x1 + _mlsValue::fromIntLit(1)); +//│ _mls_retval = _mls_x; //│ return _mls_retval; //│ } -//│ _mlsValue foo(_mlsValue a) { +//│ _mlsValue _mls_foo(_mlsValue _mls_a) { //│ _mlsValue _mls_retval; -//│ auto x2 = _mlsValue::create<_mls_Unit>(); -//│ auto x3 = (a > _mlsValue::fromIntLit(0)); -//│ if (_mlsValue::isIntLit(x3, 1)) { -//│ auto x5 = _mlsValue::fromIntLit(1); -//│ auto x6 = _mlsValue::create<_mls_Unit>(); -//│ _mls_retval = j(x5); +//│ auto _mls_x2 = _mlsValue::create<_mls_Unit>(); +//│ auto _mls_x3 = (_mls_a > _mlsValue::fromIntLit(0)); +//│ if (_mlsValue::isIntLit(_mls_x3, 1)) { +//│ auto _mls_x5 = _mlsValue::fromIntLit(1); +//│ auto _mls_x6 = _mlsValue::create<_mls_Unit>(); +//│ _mls_retval = _mls_j(_mls_x5); //│ } else { -//│ auto x4 = _mlsValue::create<_mls_Unit>(); -//│ _mls_retval = j(x2); +//│ auto _mls_x4 = _mlsValue::create<_mls_Unit>(); +//│ _mls_retval = _mls_j(_mls_x2); //│ } //│ return _mls_retval; //│ } //│ _mlsValue _mlsMain() { //│ _mlsValue _mls_retval; -//│ _mls_retval = _mlsValue::create<_mls_Unit>(); +//│ auto _mls_x7 = _mls_foo(_mlsValue::fromIntLit(1)); +//│ _mls_retval = _mls_x7; //│ return _mls_retval; //│ } //│ int main() { return _mlsLargeStack(_mlsMainWrapper); } - - diff --git a/hkmc2/shared/src/test/mlscript/llir/Classes.mls b/hkmc2/shared/src/test/mlscript/llir/Classes.mls index 7e5353fb06..834f231e73 100644 --- a/hkmc2/shared/src/test/mlscript/llir/Classes.mls +++ b/hkmc2/shared/src/test/mlscript/llir/Classes.mls @@ -14,7 +14,6 @@ main() //│ Interpreted: //│ 6 -:todo SelProj :intl :sllir class Base() with diff --git a/hkmc2/shared/src/test/mlscript/llir/ControlFlow.mls b/hkmc2/shared/src/test/mlscript/llir/ControlFlow.mls index c28822bba7..f74b97988d 100644 --- a/hkmc2/shared/src/test/mlscript/llir/ControlFlow.mls +++ b/hkmc2/shared/src/test/mlscript/llir/ControlFlow.mls @@ -160,20 +160,20 @@ fun test() = //│ //│ Cpp: //│ #include "mlsprelude.h" -//│ _mlsValue j(); -//│ _mlsValue test(); +//│ _mlsValue _mls_j5(); +//│ _mlsValue _mls_test(); //│ _mlsValue _mlsMain(); -//│ _mlsValue j() { +//│ _mlsValue _mls_j5() { //│ _mlsValue _mls_retval; //│ _mls_retval = _mlsValue::create<_mls_Unit>(); //│ return _mls_retval; //│ } -//│ _mlsValue test() { +//│ _mlsValue _mls_test() { //│ _mlsValue _mls_retval; -//│ auto x = _mlsValue::fromIntLit(1); -//│ if (_mlsValue::isIntLit(x, 1)) { -//│ auto x1 = test(); -//│ _mls_retval = x1; +//│ auto _mls_x23 = _mlsValue::fromIntLit(1); +//│ if (_mlsValue::isIntLit(_mls_x23, 1)) { +//│ auto _mls_x24 = _mls_test(); +//│ _mls_retval = _mls_x24; //│ } else { //│ _mls_retval = _mlsValue::create<_mls_Unit>(); //│ } @@ -207,21 +207,21 @@ fun test() = //│ //│ Cpp: //│ #include "mlsprelude.h" -//│ _mlsValue j(_mlsValue); -//│ _mlsValue test(); +//│ _mlsValue _mls_j6(_mlsValue); +//│ _mlsValue _mls_test1(); //│ _mlsValue _mlsMain(); -//│ _mlsValue j(_mlsValue tmp) { +//│ _mlsValue _mls_j6(_mlsValue _mls_tmp3) { //│ _mlsValue _mls_retval; -//│ auto x = (tmp + _mlsValue::fromIntLit(1)); -//│ _mls_retval = x; +//│ auto _mls_x25 = (_mls_tmp3 + _mlsValue::fromIntLit(1)); +//│ _mls_retval = _mls_x25; //│ return _mls_retval; //│ } -//│ _mlsValue test() { +//│ _mlsValue _mls_test1() { //│ _mlsValue _mls_retval; -//│ auto x1 = _mlsValue::fromIntLit(1); -//│ if (_mlsValue::isIntLit(x1, 1)) { -//│ auto x2 = test(); -//│ _mls_retval = j(x2); +//│ auto _mls_x26 = _mlsValue::fromIntLit(1); +//│ if (_mlsValue::isIntLit(_mls_x26, 1)) { +//│ auto _mls_x27 = _mls_test1(); +//│ _mls_retval = _mls_j6(_mls_x27); //│ } else { //│ throw std::runtime_error("match error"); //│ } @@ -265,32 +265,32 @@ f() //│ //│ Cpp: //│ #include "mlsprelude.h" -//│ _mlsValue j(_mlsValue); -//│ _mlsValue f(); +//│ _mlsValue _mls_j7(_mlsValue); +//│ _mlsValue _mls_f(); //│ _mlsValue _mlsMain(); -//│ _mlsValue j(_mlsValue x) { +//│ _mlsValue _mls_j7(_mlsValue _mls_x28) { //│ _mlsValue _mls_retval; -//│ _mls_retval = x; +//│ _mls_retval = _mls_x28; //│ return _mls_retval; //│ } -//│ _mlsValue f() { +//│ _mlsValue _mls_f() { //│ _mlsValue _mls_retval; -//│ auto x1 = _mlsValue::fromIntLit(10); -//│ auto x2 = _mlsValue::fromIntLit(1); -//│ if (_mlsValue::isIntLit(x2, 1)) { -//│ auto x4 = (x1 + _mlsValue::fromIntLit(1)); -//│ auto x5 = _mlsValue::create<_mls_Unit>(); -//│ _mls_retval = j(x4); +//│ auto _mls_x29 = _mlsValue::fromIntLit(10); +//│ auto _mls_x30 = _mlsValue::fromIntLit(1); +//│ if (_mlsValue::isIntLit(_mls_x30, 1)) { +//│ auto _mls_x32 = (_mls_x29 + _mlsValue::fromIntLit(1)); +//│ auto _mls_x33 = _mlsValue::create<_mls_Unit>(); +//│ _mls_retval = _mls_j7(_mls_x32); //│ } else { -//│ auto x3 = _mlsValue::create<_mls_Unit>(); -//│ _mls_retval = j(x1); +//│ auto _mls_x31 = _mlsValue::create<_mls_Unit>(); +//│ _mls_retval = _mls_j7(_mls_x29); //│ } //│ return _mls_retval; //│ } //│ _mlsValue _mlsMain() { //│ _mlsValue _mls_retval; -//│ auto x6 = f(); -//│ _mls_retval = x6; +//│ auto _mls_x34 = _mls_f(); +//│ _mls_retval = _mls_x34; //│ return _mls_retval; //│ } //│ int main() { return _mlsLargeStack(_mlsMainWrapper); } diff --git a/hkmc2/shared/src/test/mlscript/llir/HigherOrder.mls b/hkmc2/shared/src/test/mlscript/llir/HigherOrder.mls index 545672eb1b..48259d8857 100644 --- a/hkmc2/shared/src/test/mlscript/llir/HigherOrder.mls +++ b/hkmc2/shared/src/test/mlscript/llir/HigherOrder.mls @@ -34,41 +34,56 @@ add(1)(2) //│ //│ Cpp: //│ #include "mlsprelude.h" -//│ struct Lambda; -//│ _mlsValue add(_mlsValue); -//│ _mlsValue add_curried(_mlsValue); +//│ struct _mls_Lambda; +//│ struct _mls_Lambda1; +//│ _mlsValue _mls_add(_mlsValue); +//│ _mlsValue _mls_add_curried(_mlsValue); //│ _mlsValue _mlsMain(); -//│ struct Lambda: public Callable { -//│ _mlsValue x; -//│ constexpr static inline const char *typeName = "Lambda"; +//│ struct _mls_Lambda: public Callable { +//│ _mlsValue _mls_x; +//│ constexpr static inline const char *typeName = "_mls_Lambda"; //│ constexpr static inline uint32_t typeTag = nextTypeTag(); -//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->x.print(); std::printf(")"); } -//│ virtual void destroy() override { _mlsValue::destroy(this->x); operator delete (this, std::align_val_t(_mlsAlignment)); } -//│ static _mlsValue create(_mlsValue x) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Lambda; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->x = x; return _mlsValue(_mlsVal); } -//│ virtual _mlsValue apply1(_mlsValue y) { +//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->_mls_x.print(); std::printf(")"); } +//│ virtual void destroy() override { _mlsValue::destroy(this->_mls_x); operator delete (this, std::align_val_t(_mlsAlignment)); } +//│ static _mlsValue create(_mlsValue _mls_x) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) _mls_Lambda; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->_mls_x = _mls_x; return _mlsValue(_mlsVal); } +//│ virtual _mlsValue _mls_apply1(_mlsValue _mls_y) { //│ _mlsValue _mls_retval; -//│ auto x1 = (x + y); -//│ _mls_retval = x1; +//│ auto _mls_x1 = (_mls_x + _mls_y); +//│ _mls_retval = _mls_x1; //│ return _mls_retval; //│ } //│ }; -//│ _mlsValue add(_mlsValue x) { +//│ struct _mls_Lambda1: public Callable { +//│ _mlsValue _mls_x2; +//│ constexpr static inline const char *typeName = "_mls_Lambda1"; +//│ constexpr static inline uint32_t typeTag = nextTypeTag(); +//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->_mls_x2.print(); std::printf(")"); } +//│ virtual void destroy() override { _mlsValue::destroy(this->_mls_x2); operator delete (this, std::align_val_t(_mlsAlignment)); } +//│ static _mlsValue create(_mlsValue _mls_x2) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) _mls_Lambda1; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->_mls_x2 = _mls_x2; return _mlsValue(_mlsVal); } +//│ virtual _mlsValue _mls_apply1(_mlsValue _mls_y1) { +//│ _mlsValue _mls_retval; +//│ auto _mls_x3 = (_mls_x2 + _mls_y1); +//│ _mls_retval = _mls_x3; +//│ return _mls_retval; +//│ } +//│ }; +//│ _mlsValue _mls_add(_mlsValue _mls_x) { //│ _mlsValue _mls_retval; -//│ auto x2 = _mlsValue::create(x); -//│ _mls_retval = x2; +//│ auto _mls_x4 = _mlsValue::create<_mls_Lambda>(_mls_x); +//│ _mls_retval = _mls_x4; //│ return _mls_retval; //│ } -//│ _mlsValue add_curried(_mlsValue x4) { +//│ _mlsValue _mls_add_curried(_mlsValue _mls_x2) { //│ _mlsValue _mls_retval; -//│ auto x3 = _mlsValue::create(x4); -//│ _mls_retval = x3; +//│ auto _mls_x5 = _mlsValue::create<_mls_Lambda1>(_mls_x2); +//│ _mls_retval = _mls_x5; //│ return _mls_retval; //│ } //│ _mlsValue _mlsMain() { //│ _mlsValue _mls_retval; -//│ auto x5 = add(_mlsValue::fromIntLit(1)); -//│ auto x6 = _mlsMethodCall(x5)->apply1(_mlsValue::fromIntLit(2)); -//│ _mls_retval = x6; +//│ auto _mls_x6 = _mls_add(_mlsValue::fromIntLit(1)); +//│ auto _mls_x7 = _mlsMethodCall(_mls_x6)->_mls_apply1(_mlsValue::fromIntLit(2)); +//│ _mls_retval = _mls_x7; //│ return _mls_retval; //│ } //│ int main() { return _mlsLargeStack(_mlsMainWrapper); } @@ -110,44 +125,62 @@ add4(1, 2)(3, 4) //│ //│ Cpp: //│ #include "mlsprelude.h" -//│ struct Lambda; -//│ _mlsValue add4(_mlsValue, _mlsValue); -//│ _mlsValue add4_curried(_mlsValue, _mlsValue); +//│ struct _mls_Lambda2; +//│ struct _mls_Lambda3; +//│ _mlsValue _mls_add4(_mlsValue, _mlsValue); +//│ _mlsValue _mls_add4_curried(_mlsValue, _mlsValue); //│ _mlsValue _mlsMain(); -//│ struct Lambda: public Callable { -//│ _mlsValue b; -//│ _mlsValue a; -//│ constexpr static inline const char *typeName = "Lambda"; +//│ struct _mls_Lambda2: public Callable { +//│ _mlsValue _mls_b; +//│ _mlsValue _mls_a; +//│ constexpr static inline const char *typeName = "_mls_Lambda2"; +//│ constexpr static inline uint32_t typeTag = nextTypeTag(); +//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->_mls_b.print(); std::printf(", "); this->_mls_a.print(); std::printf(")"); } +//│ virtual void destroy() override { _mlsValue::destroy(this->_mls_b); _mlsValue::destroy(this->_mls_a); operator delete (this, std::align_val_t(_mlsAlignment)); } +//│ static _mlsValue create(_mlsValue _mls_b, _mlsValue _mls_a) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) _mls_Lambda2; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->_mls_b = _mls_b; _mlsVal->_mls_a = _mls_a; return _mlsValue(_mlsVal); } +//│ virtual _mlsValue _mls_apply2(_mlsValue _mls_c, _mlsValue _mls_d) { +//│ _mlsValue _mls_retval; +//│ auto _mls_x8 = (_mls_a + _mls_b); +//│ auto _mls_x9 = (_mls_x8 + _mls_c); +//│ auto _mls_x10 = (_mls_x9 + _mls_d); +//│ _mls_retval = _mls_x10; +//│ return _mls_retval; +//│ } +//│ }; +//│ struct _mls_Lambda3: public Callable { +//│ _mlsValue _mls_a1; +//│ _mlsValue _mls_b1; +//│ constexpr static inline const char *typeName = "_mls_Lambda3"; //│ constexpr static inline uint32_t typeTag = nextTypeTag(); -//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->b.print(); std::printf(", "); this->a.print(); std::printf(")"); } -//│ virtual void destroy() override { _mlsValue::destroy(this->b); _mlsValue::destroy(this->a); operator delete (this, std::align_val_t(_mlsAlignment)); } -//│ static _mlsValue create(_mlsValue b, _mlsValue a) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Lambda; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->b = b; _mlsVal->a = a; return _mlsValue(_mlsVal); } -//│ virtual _mlsValue apply2(_mlsValue c, _mlsValue d) { +//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->_mls_a1.print(); std::printf(", "); this->_mls_b1.print(); std::printf(")"); } +//│ virtual void destroy() override { _mlsValue::destroy(this->_mls_a1); _mlsValue::destroy(this->_mls_b1); operator delete (this, std::align_val_t(_mlsAlignment)); } +//│ static _mlsValue create(_mlsValue _mls_a1, _mlsValue _mls_b1) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) _mls_Lambda3; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->_mls_a1 = _mls_a1; _mlsVal->_mls_b1 = _mls_b1; return _mlsValue(_mlsVal); } +//│ virtual _mlsValue _mls_apply2(_mlsValue _mls_c1, _mlsValue _mls_d1) { //│ _mlsValue _mls_retval; -//│ auto x = (a + b); -//│ auto x1 = (x + c); -//│ auto x2 = (x1 + d); -//│ _mls_retval = x2; +//│ auto _mls_x11 = (_mls_a1 + _mls_b1); +//│ auto _mls_x12 = (_mls_x11 + _mls_c1); +//│ auto _mls_x13 = (_mls_x12 + _mls_d1); +//│ _mls_retval = _mls_x13; //│ return _mls_retval; //│ } //│ }; -//│ _mlsValue add4(_mlsValue a, _mlsValue b) { +//│ _mlsValue _mls_add4(_mlsValue _mls_a, _mlsValue _mls_b) { //│ _mlsValue _mls_retval; -//│ auto x3 = _mlsValue::create(b, a); -//│ _mls_retval = x3; +//│ auto _mls_x14 = _mlsValue::create<_mls_Lambda2>(_mls_b, _mls_a); +//│ _mls_retval = _mls_x14; //│ return _mls_retval; //│ } -//│ _mlsValue add4_curried(_mlsValue a1, _mlsValue b1) { +//│ _mlsValue _mls_add4_curried(_mlsValue _mls_a1, _mlsValue _mls_b1) { //│ _mlsValue _mls_retval; -//│ auto x4 = _mlsValue::create(a1, b1); -//│ _mls_retval = x4; +//│ auto _mls_x15 = _mlsValue::create<_mls_Lambda3>(_mls_a1, _mls_b1); +//│ _mls_retval = _mls_x15; //│ return _mls_retval; //│ } //│ _mlsValue _mlsMain() { //│ _mlsValue _mls_retval; -//│ auto x5 = add4(_mlsValue::fromIntLit(1), _mlsValue::fromIntLit(2)); -//│ auto x6 = _mlsMethodCall(x5)->apply2(_mlsValue::fromIntLit(3), _mlsValue::fromIntLit(4)); -//│ _mls_retval = x6; +//│ auto _mls_x16 = _mls_add4(_mlsValue::fromIntLit(1), _mlsValue::fromIntLit(2)); +//│ auto _mls_x17 = _mlsMethodCall(_mls_x16)->_mls_apply2(_mlsValue::fromIntLit(3), _mlsValue::fromIntLit(4)); +//│ _mls_retval = _mls_x17; //│ return _mls_retval; //│ } //│ int main() { return _mlsLargeStack(_mlsMainWrapper); } @@ -180,41 +213,41 @@ dummy()(1, 2) //│ //│ Cpp: //│ #include "mlsprelude.h" -//│ struct Lambda_add; -//│ _mlsValue add(_mlsValue, _mlsValue); -//│ _mlsValue dummy(); +//│ struct _mls_Lambda_add; +//│ _mlsValue _mls_add1(_mlsValue, _mlsValue); +//│ _mlsValue _mls_dummy(); //│ _mlsValue _mlsMain(); -//│ struct Lambda_add: public Callable { +//│ struct _mls_Lambda_add: public Callable { //│ -//│ constexpr static inline const char *typeName = "Lambda_add"; +//│ constexpr static inline const char *typeName = "_mls_Lambda_add"; //│ constexpr static inline uint32_t typeTag = nextTypeTag(); //│ virtual void print() const override { std::printf("%s", typeName); } //│ virtual void destroy() override { operator delete (this, std::align_val_t(_mlsAlignment)); } -//│ static _mlsValue create() { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) Lambda_add; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; return _mlsValue(_mlsVal); } -//│ virtual _mlsValue apply2(_mlsValue arg, _mlsValue arg1) { +//│ static _mlsValue create() { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) _mls_Lambda_add; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; return _mlsValue(_mlsVal); } +//│ virtual _mlsValue _mls_apply21(_mlsValue _mls_arg, _mlsValue _mls_arg1) { //│ _mlsValue _mls_retval; -//│ auto x = add(arg, arg1); -//│ _mls_retval = x; +//│ auto _mls_x18 = _mls_add1(_mls_arg, _mls_arg1); +//│ _mls_retval = _mls_x18; //│ return _mls_retval; //│ } //│ }; -//│ _mlsValue add(_mlsValue a, _mlsValue b) { +//│ _mlsValue _mls_add1(_mlsValue _mls_a2, _mlsValue _mls_b2) { //│ _mlsValue _mls_retval; -//│ auto x1 = (a + b); -//│ _mls_retval = x1; +//│ auto _mls_x19 = (_mls_a2 + _mls_b2); +//│ _mls_retval = _mls_x19; //│ return _mls_retval; //│ } -//│ _mlsValue dummy() { +//│ _mlsValue _mls_dummy() { //│ _mlsValue _mls_retval; -//│ auto x2 = _mlsValue::create(); -//│ _mls_retval = x2; +//│ auto _mls_x20 = _mlsValue::create<_mls_Lambda_add>(); +//│ _mls_retval = _mls_x20; //│ return _mls_retval; //│ } //│ _mlsValue _mlsMain() { //│ _mlsValue _mls_retval; -//│ auto x3 = dummy(); -//│ auto x4 = _mlsMethodCall(x3)->apply2(_mlsValue::fromIntLit(1), _mlsValue::fromIntLit(2)); -//│ _mls_retval = x4; +//│ auto _mls_x21 = _mls_dummy(); +//│ auto _mls_x22 = _mlsMethodCall(_mls_x21)->_mls_apply21(_mlsValue::fromIntLit(1), _mlsValue::fromIntLit(2)); +//│ _mls_retval = _mls_x22; //│ return _mls_retval; //│ } //│ int main() { return _mlsLargeStack(_mlsMainWrapper); } diff --git a/hkmc2/shared/src/test/mlscript/llir/NofibPrelude.mls b/hkmc2/shared/src/test/mlscript/llir/NofibPrelude.mls index 0e01d58c9e..49801d6335 100644 --- a/hkmc2/shared/src/test/mlscript/llir/NofibPrelude.mls +++ b/hkmc2/shared/src/test/mlscript/llir/NofibPrelude.mls @@ -1,6 +1,9 @@ :llir :js +// shadow the one in Predef +fun not(c) = if c then false else true + type Char = String abstract class Option[out T]: Some[T] | None @@ -95,9 +98,6 @@ fun take(n, ls) = if ls is else h :: take(n - 1, t) fun splitAt(n, ls) = [take(n, ls), drop(n, ls)] -//│ FAILURE: Unexpected compilation error -//│ ═══[COMPILATION ERROR] Name not found: member:take -//│ Stopped due to an error during the Llir generation fun zip(xs, ys) = if xs is x :: xs and ys is y :: ys then [x, y] :: zip(xs, ys) @@ -110,9 +110,6 @@ fun inList(x, ls) = if ls is Nil then false fun notElem(x, ls) = not(inList(x, ls)) -//│ FAILURE: Unexpected compilation error -//│ ═══[COMPILATION ERROR] Name not found: member:inList -//│ Stopped due to an error during the Llir generation fun (+:) append(xs, ys) = if xs is Nil then ys @@ -121,9 +118,6 @@ fun (+:) append(xs, ys) = if xs is fun concat(ls) = if ls is Nil then Nil x :: xs then append(x, concat(xs)) -//│ FAILURE: Unexpected compilation error -//│ ═══[COMPILATION ERROR] Name not found: member:append -//│ Stopped due to an error during the Llir generation fun filter(f, ls) = if ls is Nil then Nil @@ -167,25 +161,16 @@ fun foldr(f, z, xs) = if xs is fun foldl1(f, ls) = if ls is x :: xs then foldl(f, x, xs) -//│ FAILURE: Unexpected compilation error -//│ ═══[COMPILATION ERROR] Name not found: member:foldl -//│ Stopped due to an error during the Llir generation fun foldr1(f, ls) = if ls is x :: Nil then x x :: xs then f(x, foldr1(f, xs)) fun maximum(xs) = foldl1((x, y) => if x > y then x else y, xs) -//│ FAILURE: Unexpected compilation error -//│ ═══[COMPILATION ERROR] Name not found: member:foldl1 -//│ Stopped due to an error during the Llir generation fun nubBy(eq, ls) = if ls is Nil then Nil h :: t then h :: nubBy(eq, filter(y => not(eq(h, y)), t)) -//│ FAILURE: Unexpected compilation error -//│ ═══[COMPILATION ERROR] Member symbol without definition -//│ Stopped due to an error during the Llir generation fun zipWith(f, xss, yss) = if xss is x :: xs and yss is y :: ys then f(x, y) :: zipWith(f, xs, ys) @@ -198,14 +183,8 @@ fun deleteBy(eq, x, ys) = if ys is else y :: deleteBy(eq, x, ys) fun unionBy(eq, xs, ys) = append(xs, foldl((acc, y) => deleteBy(eq, y, acc), nubBy(eq, ys), xs)) -//│ FAILURE: Unexpected compilation error -//│ ═══[COMPILATION ERROR] Name not found: member:nubBy -//│ Stopped due to an error during the Llir generation fun union(xs, ys) = unionBy((x, y) => x == y, xs, ys) -//│ FAILURE: Unexpected compilation error -//│ ═══[COMPILATION ERROR] Name not found: member:unionBy -//│ Stopped due to an error during the Llir generation fun atIndex(i, ls) = if ls is h :: t and @@ -264,7 +243,4 @@ fun break_(p, ls) = if ls is fun flatMap(f, ls) = if ls is Nil then Nil h :: t then append(f(h), flatMap(f, t)) -//│ FAILURE: Unexpected compilation error -//│ ═══[COMPILATION ERROR] Name not found: member:append -//│ Stopped due to an error during the Llir generation diff --git a/hkmc2DiffTests/src/test/scala/hkmc2/LlirDiffMaker.scala b/hkmc2DiffTests/src/test/scala/hkmc2/LlirDiffMaker.scala index fa23ef5a4d..063c367e30 100644 --- a/hkmc2DiffTests/src/test/scala/hkmc2/LlirDiffMaker.scala +++ b/hkmc2DiffTests/src/test/scala/hkmc2/LlirDiffMaker.scala @@ -16,17 +16,27 @@ import hkmc2.utils.Scope import hkmc2.codegen.llir._ import hkmc2.codegen.cpp._ import hkmc2.semantics.Elaborator +import scala.collection.mutable.ListBuffer abstract class LlirDiffMaker extends BbmlDiffMaker: val llir = NullaryCommand("llir") - val cpp = NullaryCommand("cpp") val sllir = NullaryCommand("sllir") - val scpp = NullaryCommand("scpp") - val rcpp = NullaryCommand("rcpp") val intl = NullaryCommand("intl") val lprelude = NullaryCommand("lpre") + + // C++ codegen generation commands for individual blocks + val cpp = NullaryCommand("cpp") + val scpp = NullaryCommand("scpp") + val rcpp = NullaryCommand("rcpp") val wcpp = Command[Str]("wcpp", false)(x => x.stripLeading()) + // C++ codegen generation commands for the whole program + val wholeCpp = NullaryCommand("wholeCpp") + val sWholeCpp = NullaryCommand("showWholeCpp") + val rWholeCpp = NullaryCommand("runWholeCpp") + val wWholeCpp = Command[Str]("writeWholeCpp", false)(x => x.stripLeading()) + + def printToFile(f: java.io.File)(op: java.io.PrintWriter => Unit) = val p = new java.io.PrintWriter(f) try { op(p) } finally { p.close() } @@ -34,6 +44,19 @@ abstract class LlirDiffMaker extends BbmlDiffMaker: given Elaborator.Ctx = curCtx var freshId = FreshInt() + var ctx = codegen.llir.Ctx.empty + val scope = Scope.empty + val wholeProg = ListBuffer.empty[Program] + + def mkWholeProgram: Program = + if wholeProg.length == 0 then + Program(Set.empty, Set.empty, Node.Panic("No program to compile")) + else + Program( + classes = wholeProg.iterator.flatMap(_.classes).toSet, + defs = wholeProg.iterator.flatMap(_.defs).toSet, + main = wholeProg.last.main + ) override def processTerm(trm: Blk, inImport: Bool)(using Raise): Unit = super.processTerm(trm, inImport) @@ -41,29 +64,36 @@ abstract class LlirDiffMaker extends BbmlDiffMaker: val low = ltl.givenIn: codegen.Lowering(lowerHandlers = false, stackLimit = None) var le = low.program(trm) - given Scope = Scope.empty + given Scope = scope + given Ctx = ctx val llb = LlirBuilder(tl, freshId) try - val llirProg = llb.bProg(le) + val (llirProg, ctx2) = llb.bProg(le) + ctx = ctx2 + wholeProg += llirProg if sllir.isSet then output("LLIR:") output(llirProg.show()) - if cpp.isSet || scpp.isSet || rcpp.isSet || wcpp.isSet then - val cpp = CppCodeGen(tl).codegen(llb.builtinSymbols, llirProg) - if scpp.isSet then - output("\nCpp:") - output(cpp.toDocument.toString) - val auxPath = os.Path(rootPath)/"hkmc2"/"shared"/"src"/"test"/"mlscript-compile"/"cpp" - if wcpp.isSet then - printToFile(java.io.File((auxPath / s"${wcpp.get.get}.cpp").toString)): - p => p.println(cpp.toDocument.toString) - if rcpp.isSet then - val cppHost = CppCompilerHost(auxPath.toString, output.apply) - if !cppHost.ready then - output("\nCpp Compilation Failed: Cpp compiler or GNU Make not found") - else - output("\n") - cppHost.compileAndRun(cpp.toDocument.toString) + def cppGen(name: String, prog: Program, gen: Bool, show: Bool, run: Bool, write: Opt[Str]): Unit = + tl.log(s"Generating $name") + if gen || show || run || write.isDefined then + val cpp = CppCodeGen(llb.builtinSymbols, tl).codegen(prog) + if show then + output(s"\n$name:") + output(cpp.toDocument.toString) + val auxPath = os.Path(rootPath)/"hkmc2"/"shared"/"src"/"test"/"mlscript-compile"/"cpp" + if write.isDefined then + printToFile(java.io.File((auxPath / s"${write.get}.cpp").toString)): + p => p.println(cpp.toDocument.toString) + if run then + val cppHost = CppCompilerHost(auxPath.toString, output.apply) + if !cppHost.ready then + output("\nCpp Compilation Failed: Cpp compiler or GNU Make not found") + else + output("\n") + cppHost.compileAndRun(cpp.toDocument.toString) + cppGen("Cpp", llirProg, cpp.isSet, scpp.isSet, rcpp.isSet, wcpp.get) + cppGen("WholeProgramCpp", mkWholeProgram, wholeCpp.isSet, sWholeCpp.isSet, rWholeCpp.isSet, wWholeCpp.get) if intl.isSet then val intr = codegen.llir.Interpreter(tl) output("\nInterpreted:") From 441cfe1420fc674a66269e1777a70860b0246b5a Mon Sep 17 00:00:00 2001 From: waterlens Date: Wed, 19 Feb 2025 21:43:25 +0800 Subject: [PATCH 41/88] fix a problem on cpp generation --- .../scala/hkmc2/codegen/cpp/CodeGen.scala | 49 ++++++++++-------- .../mlscript-compile/cpp/compile_flags.txt | 8 +++ .../src/test/mlscript/llir/BasicCpp.mls | 13 ++++- .../src/test/mlscript/llir/HigherOrder.mls | 50 +++++++++---------- 4 files changed, 73 insertions(+), 47 deletions(-) create mode 100644 hkmc2/shared/src/test/mlscript-compile/cpp/compile_flags.txt diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/CodeGen.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/CodeGen.scala index dbfb159458..23db22f3ed 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/CodeGen.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/CodeGen.scala @@ -14,9 +14,11 @@ import hkmc2.semantics.BuiltinSymbol class CppCodeGen(builtinClassSymbols: Set[Local], tl: TraceLogger): import tl.{trace, log, logs} def mapName(name: Str): Str = "_mls_" + name.replace('$', '_').replace('\'', '_') - def directName(sym: Local)(using Raise, Scope): Str = - if builtinClassSymbols.contains(sym) then sym.nme + def mapClsLikeName(sym: Local)(using Raise, Scope): Str = + if builtinClassSymbols.contains(sym) then sym.nme |> mapName else allocIfNew(sym) + def directName(sym: Local): Str = + sym.nme |> mapName val mlsValType = Type.Prim("_mlsValue") val mlsUnitValue = Expr.Call(Expr.Var("_mlsValue::create<_mls_Unit>"), Ls()); val mlsRetValue = "_mls_retval" @@ -58,13 +60,14 @@ class CppCodeGen(builtinClassSymbols: Set[Local], tl: TraceLogger): def mlsThrowNonExhaustiveMatch = Stmt.Raw("_mlsNonExhaustiveMatch();"); def mlsCall(fn: Str, args: Ls[Expr]) = Expr.Call(Expr.Var("_mlsCall"), Expr.Var(fn) :: args) def mlsMethodCall(cls: Local, method: Str, args: Ls[Expr])(using Raise, Scope) = - Expr.Call(Expr.Member(Expr.Call(Expr.Var(s"_mlsMethodCall<${cls |> directName}>"), Ls(args.head)), method), args.tail) + Expr.Call(Expr.Member(Expr.Call(Expr.Var(s"_mlsMethodCall<${cls |> mapClsLikeName}>"), Ls(args.head)), method), args.tail) def mlsFnWrapperName(fn: Str) = s"_mlsFn_$fn" def mlsFnCreateMethod(fn: Str) = s"static _mlsValue create() { static _mlsFn_$fn mlsFn alignas(_mlsAlignment); mlsFn.refCount = stickyRefCount; mlsFn.tag = typeTag; return _mlsValue(&mlsFn); }" def mlsNeverValue(n: Int) = if (n <= 1) then Expr.Call(Expr.Var(s"_mlsValue::never"), Ls()) else Expr.Call(Expr.Var(s"_mlsValue::never<$n>"), Ls()) case class Ctx( defnCtx: Set[Local], + fieldCtx: Set[Local], ) def getVar(l: Local)(using Raise, Scope): String = l match @@ -86,28 +89,31 @@ class CppCodeGen(builtinClassSymbols: Set[Local], tl: TraceLogger): def codegenClassInfo(using Ctx, Raise, Scope)(cls: ClassInfo): (Opt[Def], Decl) = trace[(Opt[Def], Decl)](s"codegenClassInfo ${cls.name} begin"): val fields = cls.fields.map{x => (x |> directName, mlsValType)} - val parents = if cls.parents.nonEmpty then cls.parents.toList.map(directName) else mlsObject :: Nil - val decl = Decl.StructDecl(cls.name |> directName) + cls.fields.foreach(x => summon[Scope].allocateName(x)) + val parents = if cls.parents.nonEmpty then cls.parents.toList.map(mapClsLikeName) else mlsObject :: Nil + val decl = Decl.StructDecl(cls.name |> mapClsLikeName) if mlsIsInternalClass(cls.name) then (None, decl) else val theDef = Def.StructDef( - cls.name |> directName, fields, + cls.name |> mapClsLikeName, fields, if parents.nonEmpty then Some(parents) else None, - Ls(Def.RawDef(mlsObjectNameMethod(cls.name |> directName)), + Ls(Def.RawDef(mlsObjectNameMethod(cls.name.nme)), Def.RawDef(mlsTypeTag()), Def.RawDef(mlsCommonPrintMethod(cls.fields.map(directName))), - Def.RawDef(mlsCommonDestructorMethod(cls.name |> directName, cls.fields.map(directName))), - Def.RawDef(mlsCommonCreateMethod(cls.name |> directName, cls.fields.map(directName), cls.id))) + Def.RawDef(mlsCommonDestructorMethod(cls.name |> mapClsLikeName, cls.fields.map(directName))), + Def.RawDef(mlsCommonCreateMethod(cls.name |> mapClsLikeName, cls.fields.map(directName), cls.id))) ++ cls.methods.map{case (name, defn) => { - val (theDef, decl) = codegenDefn(using Ctx(summon[Ctx].defnCtx + cls.name))(defn) + val (theDef, decl) = codegenDefn(using Ctx(summon[Ctx].defnCtx + cls.name, summon[Ctx].fieldCtx ++ cls.fields))(defn) theDef match - case x @ Def.FuncDef(_, name, _, _, _, _) => x.copy(virt = true) + case x @ Def.FuncDef(_, _, _, _, _, _) if builtinApply.contains(defn.name.nme) => x.copy(virt = true, name = defn.name |> directName) + case x @ Def.FuncDef(_, _, _, _, _, _) => x.copy(virt = true) case _ => theDef }} ) (S(theDef), decl) def toExpr(texpr: TrivialExpr, reifyUnit: Bool = false)(using Ctx, Raise, Scope): Opt[Expr] = texpr match + case IExpr.Ref(name) if summon[Ctx].fieldCtx.contains(name) => S(Expr.Var(name |> directName)) case IExpr.Ref(name) => S(Expr.Var(name |> allocIfNew)) case IExpr.Literal(hkmc2.syntax.Tree.BoolLit(x)) => S(mlsIntLit(if x then 1 else 0)) case IExpr.Literal(hkmc2.syntax.Tree.IntLit(x)) => S(mlsIntLit(x)) @@ -116,6 +122,7 @@ class CppCodeGen(builtinClassSymbols: Set[Local], tl: TraceLogger): case IExpr.Literal(hkmc2.syntax.Tree.UnitLit(_)) => if reifyUnit then S(mlsUnitValue) else None def toExpr(texpr: TrivialExpr)(using Ctx, Raise, Scope): Expr = texpr match + case IExpr.Ref(name) if summon[Ctx].fieldCtx.contains(name) => Expr.Var(name |> directName) case IExpr.Ref(name) => Expr.Var(name |> allocIfNew) case IExpr.Literal(hkmc2.syntax.Tree.BoolLit(x)) => mlsIntLit(if x then 1 else 0) case IExpr.Literal(hkmc2.syntax.Tree.IntLit(x)) => mlsIntLit(x) @@ -140,7 +147,7 @@ class CppCodeGen(builtinClassSymbols: Set[Local], tl: TraceLogger): val stmt = cases.foldRight(S(init)) { case ((Pat.Class(cls), arm), nextarm) => val (decls2, stmts2) = codegen(arm, storeInto)(using Ls.empty, Ls.empty[Stmt]) - val stmt = Stmt.If(mlsIsValueOf(cls |> directName, scrut2), Stmt.Block(decls2, stmts2), nextarm) + val stmt = Stmt.If(mlsIsValueOf(cls |> mapClsLikeName, scrut2), Stmt.Block(decls2, stmts2), nextarm) S(stmt) case ((Pat.Lit(i @ hkmc2.syntax.Tree.IntLit(_)), arm), nextarm) => val (decls2, stmts2) = codegen(arm, storeInto)(using Ls.empty, Ls.empty[Stmt]) @@ -181,8 +188,8 @@ class CppCodeGen(builtinClassSymbols: Set[Local], tl: TraceLogger): def codegen(expr: IExpr)(using Ctx, Raise, Scope): Expr = expr match case x @ (IExpr.Ref(_) | IExpr.Literal(_)) => toExpr(x, reifyUnit = true).get - case IExpr.CtorApp(cls, args) => mlsNewValue(cls |> directName, args.map(toExpr)) - case IExpr.Select(name, cls, field) => Expr.Member(mlsAsUnchecked(name |> allocIfNew, cls |> directName), field) + case IExpr.CtorApp(cls, args) => mlsNewValue(cls |> mapClsLikeName, args.map(toExpr)) + case IExpr.Select(name, cls, field) => Expr.Member(mlsAsUnchecked(name |> allocIfNew, cls |> mapClsLikeName), field |> mapName) case IExpr.BasicOp(name, args) => codegenOps(name, args) case IExpr.AssignField(assignee, cls, field, value) => TODO("codegen assign field") @@ -255,8 +262,8 @@ class CppCodeGen(builtinClassSymbols: Set[Local], tl: TraceLogger): // Topological sort of classes based on inheritance relationships def sortClasses(prog: Program)(using Raise, Scope): Ls[ClassInfo] = - var depgraph = prog.classes.map(x => (x.name |> directName, x.parents.map(directName))).toMap - ++ builtinClassSymbols.map(x => (x |> directName, Set.empty[String])) + var depgraph = prog.classes.map(x => (x.name |> mapClsLikeName, x.parents.map(mapClsLikeName))).toMap + ++ builtinClassSymbols.map(x => (x |> mapClsLikeName, Set.empty[String])) log(s"depgraph: $depgraph") var degree = depgraph.view.mapValues(_.size).toMap def removeNode(node: String) = @@ -269,7 +276,7 @@ class CppCodeGen(builtinClassSymbols: Set[Local], tl: TraceLogger): while work.nonEmpty do val node = work.head work -= node - prog.classes.find(x => (x.name |> directName) == node).fold(())(sorted.addOne) + prog.classes.find(x => (x.name |> mapClsLikeName) == node).fold(())(sorted.addOne) removeNode(node) val next = degree.filter(_._2 == 0).keys work ++= next @@ -281,8 +288,10 @@ class CppCodeGen(builtinClassSymbols: Set[Local], tl: TraceLogger): def codegen(prog: Program)(using Raise, Scope): CompilationUnit = val sortedClasses = sortClasses(prog) val defnCtx = prog.defs.map(_.name) - val (defs, decls) = sortedClasses.map(codegenClassInfo(using Ctx(defnCtx))).unzip - val (defs2, decls2) = prog.defs.map(codegenDefn(using Ctx(defnCtx))).unzip - val (defMain, declMain) = codegenTopNode(prog.main)(using Ctx(defnCtx)) + val fieldCtx = Set.empty[Local] + given Ctx = Ctx(defnCtx, fieldCtx) + val (defs, decls) = sortedClasses.map(codegenClassInfo).unzip + val (defs2, decls2) = prog.defs.map(codegenDefn).unzip + val (defMain, declMain) = codegenTopNode(prog.main) CompilationUnit(Ls(mlsPrelude), decls ++ decls2 :+ declMain, defs.flatten ++ defs2 :+ defMain :+ Def.RawDef(mlsEntryPoint)) diff --git a/hkmc2/shared/src/test/mlscript-compile/cpp/compile_flags.txt b/hkmc2/shared/src/test/mlscript-compile/cpp/compile_flags.txt new file mode 100644 index 0000000000..a5a7cabbdf --- /dev/null +++ b/hkmc2/shared/src/test/mlscript-compile/cpp/compile_flags.txt @@ -0,0 +1,8 @@ +-O +-Wall +-Wextra +-std=c++20 +-I. +-Wno-inconsistent-missing-override +-I/opt/homebrew/include +-L/opt/homebrew/lib diff --git a/hkmc2/shared/src/test/mlscript/llir/BasicCpp.mls b/hkmc2/shared/src/test/mlscript/llir/BasicCpp.mls index 0cb1ff92e2..aa154237e4 100644 --- a/hkmc2/shared/src/test/mlscript/llir/BasicCpp.mls +++ b/hkmc2/shared/src/test/mlscript/llir/BasicCpp.mls @@ -28,12 +28,15 @@ fun foo(a) = //│ undefined :showWholeCpp +fun bar(x) = + x + 1 foo(1) //│ //│ WholeProgramCpp: //│ #include "mlsprelude.h" //│ _mlsValue _mls_j(_mlsValue); //│ _mlsValue _mls_foo(_mlsValue); +//│ _mlsValue _mls_bar(_mlsValue); //│ _mlsValue _mlsMain(); //│ _mlsValue _mls_j(_mlsValue _mls_x1) { //│ _mlsValue _mls_retval; @@ -55,10 +58,16 @@ foo(1) //│ } //│ return _mls_retval; //│ } -//│ _mlsValue _mlsMain() { +//│ _mlsValue _mls_bar(_mlsValue _mls_x8) { //│ _mlsValue _mls_retval; -//│ auto _mls_x7 = _mls_foo(_mlsValue::fromIntLit(1)); +//│ auto _mls_x7 = (_mls_x8 + _mlsValue::fromIntLit(1)); //│ _mls_retval = _mls_x7; //│ return _mls_retval; //│ } +//│ _mlsValue _mlsMain() { +//│ _mlsValue _mls_retval; +//│ auto _mls_x9 = _mls_foo(_mlsValue::fromIntLit(1)); +//│ _mls_retval = _mls_x9; +//│ return _mls_retval; +//│ } //│ int main() { return _mlsLargeStack(_mlsMainWrapper); } diff --git a/hkmc2/shared/src/test/mlscript/llir/HigherOrder.mls b/hkmc2/shared/src/test/mlscript/llir/HigherOrder.mls index 48259d8857..27c37659ff 100644 --- a/hkmc2/shared/src/test/mlscript/llir/HigherOrder.mls +++ b/hkmc2/shared/src/test/mlscript/llir/HigherOrder.mls @@ -39,9 +39,9 @@ add(1)(2) //│ _mlsValue _mls_add(_mlsValue); //│ _mlsValue _mls_add_curried(_mlsValue); //│ _mlsValue _mlsMain(); -//│ struct _mls_Lambda: public Callable { +//│ struct _mls_Lambda: public _mls_Callable { //│ _mlsValue _mls_x; -//│ constexpr static inline const char *typeName = "_mls_Lambda"; +//│ constexpr static inline const char *typeName = "Lambda"; //│ constexpr static inline uint32_t typeTag = nextTypeTag(); //│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->_mls_x.print(); std::printf(")"); } //│ virtual void destroy() override { _mlsValue::destroy(this->_mls_x); operator delete (this, std::align_val_t(_mlsAlignment)); } @@ -53,16 +53,16 @@ add(1)(2) //│ return _mls_retval; //│ } //│ }; -//│ struct _mls_Lambda1: public Callable { -//│ _mlsValue _mls_x2; -//│ constexpr static inline const char *typeName = "_mls_Lambda1"; +//│ struct _mls_Lambda1: public _mls_Callable { +//│ _mlsValue _mls_x; +//│ constexpr static inline const char *typeName = "Lambda"; //│ constexpr static inline uint32_t typeTag = nextTypeTag(); -//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->_mls_x2.print(); std::printf(")"); } -//│ virtual void destroy() override { _mlsValue::destroy(this->_mls_x2); operator delete (this, std::align_val_t(_mlsAlignment)); } -//│ static _mlsValue create(_mlsValue _mls_x2) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) _mls_Lambda1; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->_mls_x2 = _mls_x2; return _mlsValue(_mlsVal); } +//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->_mls_x.print(); std::printf(")"); } +//│ virtual void destroy() override { _mlsValue::destroy(this->_mls_x); operator delete (this, std::align_val_t(_mlsAlignment)); } +//│ static _mlsValue create(_mlsValue _mls_x) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) _mls_Lambda1; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->_mls_x = _mls_x; return _mlsValue(_mlsVal); } //│ virtual _mlsValue _mls_apply1(_mlsValue _mls_y1) { //│ _mlsValue _mls_retval; -//│ auto _mls_x3 = (_mls_x2 + _mls_y1); +//│ auto _mls_x3 = (_mls_x + _mls_y1); //│ _mls_retval = _mls_x3; //│ return _mls_retval; //│ } @@ -82,7 +82,7 @@ add(1)(2) //│ _mlsValue _mlsMain() { //│ _mlsValue _mls_retval; //│ auto _mls_x6 = _mls_add(_mlsValue::fromIntLit(1)); -//│ auto _mls_x7 = _mlsMethodCall(_mls_x6)->_mls_apply1(_mlsValue::fromIntLit(2)); +//│ auto _mls_x7 = _mlsMethodCall<_mls_Callable>(_mls_x6)->_mls_apply1(_mlsValue::fromIntLit(2)); //│ _mls_retval = _mls_x7; //│ return _mls_retval; //│ } @@ -130,10 +130,10 @@ add4(1, 2)(3, 4) //│ _mlsValue _mls_add4(_mlsValue, _mlsValue); //│ _mlsValue _mls_add4_curried(_mlsValue, _mlsValue); //│ _mlsValue _mlsMain(); -//│ struct _mls_Lambda2: public Callable { +//│ struct _mls_Lambda2: public _mls_Callable { //│ _mlsValue _mls_b; //│ _mlsValue _mls_a; -//│ constexpr static inline const char *typeName = "_mls_Lambda2"; +//│ constexpr static inline const char *typeName = "Lambda"; //│ constexpr static inline uint32_t typeTag = nextTypeTag(); //│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->_mls_b.print(); std::printf(", "); this->_mls_a.print(); std::printf(")"); } //│ virtual void destroy() override { _mlsValue::destroy(this->_mls_b); _mlsValue::destroy(this->_mls_a); operator delete (this, std::align_val_t(_mlsAlignment)); } @@ -147,17 +147,17 @@ add4(1, 2)(3, 4) //│ return _mls_retval; //│ } //│ }; -//│ struct _mls_Lambda3: public Callable { -//│ _mlsValue _mls_a1; -//│ _mlsValue _mls_b1; -//│ constexpr static inline const char *typeName = "_mls_Lambda3"; +//│ struct _mls_Lambda3: public _mls_Callable { +//│ _mlsValue _mls_a; +//│ _mlsValue _mls_b; +//│ constexpr static inline const char *typeName = "Lambda"; //│ constexpr static inline uint32_t typeTag = nextTypeTag(); -//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->_mls_a1.print(); std::printf(", "); this->_mls_b1.print(); std::printf(")"); } -//│ virtual void destroy() override { _mlsValue::destroy(this->_mls_a1); _mlsValue::destroy(this->_mls_b1); operator delete (this, std::align_val_t(_mlsAlignment)); } -//│ static _mlsValue create(_mlsValue _mls_a1, _mlsValue _mls_b1) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) _mls_Lambda3; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->_mls_a1 = _mls_a1; _mlsVal->_mls_b1 = _mls_b1; return _mlsValue(_mlsVal); } +//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->_mls_a.print(); std::printf(", "); this->_mls_b.print(); std::printf(")"); } +//│ virtual void destroy() override { _mlsValue::destroy(this->_mls_a); _mlsValue::destroy(this->_mls_b); operator delete (this, std::align_val_t(_mlsAlignment)); } +//│ static _mlsValue create(_mlsValue _mls_a, _mlsValue _mls_b) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) _mls_Lambda3; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->_mls_a = _mls_a; _mlsVal->_mls_b = _mls_b; return _mlsValue(_mlsVal); } //│ virtual _mlsValue _mls_apply2(_mlsValue _mls_c1, _mlsValue _mls_d1) { //│ _mlsValue _mls_retval; -//│ auto _mls_x11 = (_mls_a1 + _mls_b1); +//│ auto _mls_x11 = (_mls_a + _mls_b); //│ auto _mls_x12 = (_mls_x11 + _mls_c1); //│ auto _mls_x13 = (_mls_x12 + _mls_d1); //│ _mls_retval = _mls_x13; @@ -179,7 +179,7 @@ add4(1, 2)(3, 4) //│ _mlsValue _mlsMain() { //│ _mlsValue _mls_retval; //│ auto _mls_x16 = _mls_add4(_mlsValue::fromIntLit(1), _mlsValue::fromIntLit(2)); -//│ auto _mls_x17 = _mlsMethodCall(_mls_x16)->_mls_apply2(_mlsValue::fromIntLit(3), _mlsValue::fromIntLit(4)); +//│ auto _mls_x17 = _mlsMethodCall<_mls_Callable>(_mls_x16)->_mls_apply2(_mlsValue::fromIntLit(3), _mlsValue::fromIntLit(4)); //│ _mls_retval = _mls_x17; //│ return _mls_retval; //│ } @@ -217,14 +217,14 @@ dummy()(1, 2) //│ _mlsValue _mls_add1(_mlsValue, _mlsValue); //│ _mlsValue _mls_dummy(); //│ _mlsValue _mlsMain(); -//│ struct _mls_Lambda_add: public Callable { +//│ struct _mls_Lambda_add: public _mls_Callable { //│ -//│ constexpr static inline const char *typeName = "_mls_Lambda_add"; +//│ constexpr static inline const char *typeName = "Lambda_add"; //│ constexpr static inline uint32_t typeTag = nextTypeTag(); //│ virtual void print() const override { std::printf("%s", typeName); } //│ virtual void destroy() override { operator delete (this, std::align_val_t(_mlsAlignment)); } //│ static _mlsValue create() { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) _mls_Lambda_add; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; return _mlsValue(_mlsVal); } -//│ virtual _mlsValue _mls_apply21(_mlsValue _mls_arg, _mlsValue _mls_arg1) { +//│ virtual _mlsValue _mls_apply2(_mlsValue _mls_arg, _mlsValue _mls_arg1) { //│ _mlsValue _mls_retval; //│ auto _mls_x18 = _mls_add1(_mls_arg, _mls_arg1); //│ _mls_retval = _mls_x18; @@ -246,7 +246,7 @@ dummy()(1, 2) //│ _mlsValue _mlsMain() { //│ _mlsValue _mls_retval; //│ auto _mls_x21 = _mls_dummy(); -//│ auto _mls_x22 = _mlsMethodCall(_mls_x21)->_mls_apply21(_mlsValue::fromIntLit(1), _mlsValue::fromIntLit(2)); +//│ auto _mls_x22 = _mlsMethodCall<_mls_Callable>(_mls_x21)->_mls_apply2(_mlsValue::fromIntLit(1), _mlsValue::fromIntLit(2)); //│ _mls_retval = _mls_x22; //│ return _mls_retval; //│ } From 57a314c5c1936af09242ef1bfbaa15caafc4c18e Mon Sep 17 00:00:00 2001 From: waterlens Date: Thu, 20 Feb 2025 16:33:32 +0800 Subject: [PATCH 42/88] avoid duplicate symbols over blocks --- .../scala/hkmc2/codegen/llir/Builder.scala | 34 ++- .../src/test/mlscript/llir/BasicCpp.mls | 22 +- .../shared/src/test/mlscript/llir/Classes.mls | 14 +- .../src/test/mlscript/llir/ControlFlow.mls | 272 +++++++++--------- hkmc2/shared/src/test/mlscript/llir/Ctor.mls | 26 +- .../src/test/mlscript/llir/HigherOrder.mls | 162 +++++------ .../shared/src/test/mlscript/llir/Legacy.mls | 100 +++---- .../shared/src/test/mlscript/llir/Method.mls | 10 +- hkmc2/shared/src/test/mlscript/llir/Tuple.mls | 24 +- .../src/test/scala/hkmc2/LlirDiffMaker.scala | 2 +- 10 files changed, 338 insertions(+), 328 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala index ba93b9fdb1..0122446104 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala @@ -27,6 +27,13 @@ def errStop(msg: Message)(using Raise) = final case class FuncInfo(paramsSize: Int) +final case class BuiltinSymbols( + var callableSym: Opt[Local] = None, + fieldSym: MutMap[Int, Local] = MutMap.empty, + applySym: MutMap[Int, Local] = MutMap.empty, + tupleSym: MutMap[Int, Local] = MutMap.empty, +) + final case class Ctx( def_acc: ListBuffer[Func], class_acc: ListBuffer[ClassInfo], @@ -37,6 +44,7 @@ final case class Ctx( is_top_level: Bool = true, method_class: Opt[Symbol] = None, free_vars: Set[Local] = Set.empty, + builtin_sym: BuiltinSymbols = BuiltinSymbols(), ): def addFuncName(n: Local, paramsSize: Int) = copy(fn_ctx = fn_ctx + (n -> FuncInfo(paramsSize))) def findFuncName(n: Local)(using Raise) = fn_ctx.get(n) match @@ -97,21 +105,23 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger, uid: FreshInt): private def newTemp = TempSymbol(N, "x") private def newNamedTemp(name: Str) = TempSymbol(N, name) private def newNamed(name: Str) = VarSymbol(Tree.Ident(name)) - private def newLambdaSym(name: Str) = + private def newClassSym(name: Str) = ClassSymbol(Tree.TypeDef(hkmc2.syntax.Cls, Tree.Empty(), N, N), Tree.Ident(name)) private def newTupleSym(len: Int) = ClassSymbol(Tree.TypeDef(hkmc2.syntax.Cls, Tree.Empty(), N, N), Tree.Ident(s"Tuple$len")) private def newMemSym(name: Str) = TermSymbol(hkmc2.syntax.ImmutVal, None, Tree.Ident(name)) private def newMethodSym(name: Str) = TermSymbol(hkmc2.syntax.Fun, None, Tree.Ident(name)) - private val fieldSym: MutMap[Int, Local] = MutMap.empty - private val applySym: MutMap[Int, Local] = MutMap.empty - private val tupleSym: MutMap[Int, Local] = MutMap.empty - private val callableSym = newMemSym("Callable") - private def builtinField(n: Int) = fieldSym.getOrElseUpdate(n, newMemSym(s"field$n")) - private def builtinApply(n: Int) = applySym.getOrElseUpdate(n, newMethodSym(s"apply$n")) - private def builtinTuple(n: Int) = tupleSym.getOrElseUpdate(n, newTupleSym(n)) - private def builtinCallable: Local = callableSym - val builtinSymbols = Set(builtinCallable) // Callable is implicitly defined in the runtime + private def builtinField(n: Int)(using Ctx) = summon[Ctx].builtin_sym.fieldSym.getOrElseUpdate(n, newMemSym(s"field$n")) + private def builtinApply(n: Int)(using Ctx) = summon[Ctx].builtin_sym.applySym.getOrElseUpdate(n, newMethodSym(s"apply$n")) + private def builtinTuple(n: Int)(using Ctx) = summon[Ctx].builtin_sym.tupleSym.getOrElseUpdate(n, newTupleSym(n)) + private def builtinCallable(using ctx: Ctx) : Local = + ctx.builtin_sym.callableSym match + case None => + val sym = newClassSym("Callable") + ctx.builtin_sym.callableSym = Some(sym); + sym + case Some(value) => value + private def bBind(name: Opt[Local], e: Result, body: Block)(k: TrivialExpr => Ctx ?=> Node)(ct: Block)(using ctx: Ctx)(using Raise, Scope): Node = trace[Node](s"bBind begin: $name", x => s"bBind end: ${x.show}"): @@ -205,7 +215,7 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger, uid: FreshInt): val Value.Lam(params, body) = lam // Generate an auxiliary class inheriting from Callable val freeVars = freeVarsFilter(lam.freeVars -- lam.body.definedVars -- ctx.fn_ctx.keySet) - val name = newLambdaSym(s"Lambda${nameHint.fold("")(x => "_" + x)}") + val name = newClassSym(s"Lambda${nameHint.fold("")(x => "_" + x)}") val clsParams = freeVars.toList val args = freeVars.toList val ctx2 = ctx.setFreeVars(freeVars) @@ -452,7 +462,7 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger, uid: FreshInt): b.subBlocks.foldLeft(ctx)((ctx, rest) => registerClasses(rest)(using ctx)) def registerInternalClasses(using ctx: Ctx)(using Raise, Scope): Ctx = - tupleSym.foldLeft(ctx): + ctx.builtin_sym.tupleSym.foldLeft(ctx): case (ctx, (len, sym)) => val c = ClassInfo(uid.make, sym, (0 until len).map(x => builtinField(x)).toList, Set.empty, Map.empty) ctx.class_acc += c diff --git a/hkmc2/shared/src/test/mlscript/llir/BasicCpp.mls b/hkmc2/shared/src/test/mlscript/llir/BasicCpp.mls index aa154237e4..ea79b1f6d0 100644 --- a/hkmc2/shared/src/test/mlscript/llir/BasicCpp.mls +++ b/hkmc2/shared/src/test/mlscript/llir/BasicCpp.mls @@ -12,19 +12,19 @@ fun foo(a) = //│ LLIR: //│ //│ def foo$195(a$196) = -//│ let x$204 = null in -//│ let x$205 = >(a$196,0) in -//│ case x$205 of +//│ let x$203 = null in +//│ let x$204 = >(a$196,0) in +//│ case x$204 of //│ BoolLit(true) => -//│ let x$207 = 1 in -//│ let x$208 = undefined in -//│ jump j$206(x$207) +//│ let x$206 = 1 in +//│ let x$207 = undefined in +//│ jump j$205(x$206) //│ _ => -//│ let x$209 = undefined in -//│ jump j$206(x$204) -//│ def j$206(x$197) = -//│ let x$210 = +(x$197,1) in -//│ x$210 +//│ let x$208 = undefined in +//│ jump j$205(x$203) +//│ def j$205(x$197) = +//│ let x$209 = +(x$197,1) in +//│ x$209 //│ undefined :showWholeCpp diff --git a/hkmc2/shared/src/test/mlscript/llir/Classes.mls b/hkmc2/shared/src/test/mlscript/llir/Classes.mls index 834f231e73..33c0a4f221 100644 --- a/hkmc2/shared/src/test/mlscript/llir/Classes.mls +++ b/hkmc2/shared/src/test/mlscript/llir/Classes.mls @@ -34,13 +34,13 @@ main() //│ 2 //│ } //│ def main$229() = -//│ let x$252 = Derived$234() in -//│ let x$253 = Base.get$226(x$252) in -//│ let x$254 = Derived.get$227(x$252) in -//│ let x$255 = *(x$253,x$254) in -//│ x$255 -//│ let* (x$256) = main() in -//│ x$256 +//│ let x$251 = Derived$234() in +//│ let x$252 = Base.get$226(x$251) in +//│ let x$253 = Derived.get$227(x$251) in +//│ let x$254 = *(x$252,x$253) in +//│ x$254 +//│ let* (x$255) = main() in +//│ x$255 //│ //│ Interpreted: //│ 4 diff --git a/hkmc2/shared/src/test/mlscript/llir/ControlFlow.mls b/hkmc2/shared/src/test/mlscript/llir/ControlFlow.mls index f74b97988d..a4737e982d 100644 --- a/hkmc2/shared/src/test/mlscript/llir/ControlFlow.mls +++ b/hkmc2/shared/src/test/mlscript/llir/ControlFlow.mls @@ -14,12 +14,12 @@ f1() //│ = 2 //│ LLIR: //│ -//│ def f1$198() = -//│ let x$208 = 1 in -//│ let x$209 = 2 in -//│ x$209 -//│ let* (x$210) = f1() in -//│ x$210 +//│ def f1$197() = +//│ let x$206 = 1 in +//│ let x$207 = 2 in +//│ x$207 +//│ let* (x$208) = f1() in +//│ x$208 //│ //│ Interpreted: //│ 2 @@ -33,18 +33,18 @@ f2() //│ = 3 //│ LLIR: //│ -//│ def f2$211() = -//│ let x$222 = 0 in -//│ let x$223 = ==(x$222,1) in -//│ case x$223 of +//│ def f2$209() = +//│ let x$219 = 0 in +//│ let x$220 = ==(x$219,1) in +//│ case x$220 of //│ BoolLit(true) => //│ 2 //│ _ => //│ 3 -//│ def j$224() = +//│ def j$221() = //│ null -//│ let* (x$225) = f2() in -//│ x$225 +//│ let* (x$222) = f2() in +//│ x$222 //│ //│ Interpreted: //│ 3 @@ -59,19 +59,19 @@ f3() //│ = 0 //│ LLIR: //│ -//│ def f3$226() = -//│ let x$237 = 0 in -//│ let x$238 = 1 in -//│ let x$239 = true in -//│ case x$239 of +//│ def f3$223() = +//│ let x$233 = 0 in +//│ let x$234 = 1 in +//│ let x$235 = true in +//│ case x$235 of //│ BoolLit(true) => -//│ x$237 +//│ x$233 //│ _ => -//│ x$238 -//│ def j$240() = +//│ x$234 +//│ def j$236() = //│ null -//│ let* (x$241) = f3() in -//│ x$241 +//│ let* (x$237) = f3() in +//│ x$237 :sllir @@ -84,20 +84,20 @@ f4() //│ = 3 //│ LLIR: //│ -//│ def f4$242() = -//│ let x$256 = 0 in -//│ let x$257 = ==(x$256,1) in -//│ case x$257 of +//│ def f4$238() = +//│ let x$251 = 0 in +//│ let x$252 = ==(x$251,1) in +//│ case x$252 of //│ BoolLit(true) => -//│ let x$259 = 2 in -//│ jump j$258(x$259) +//│ let x$254 = 2 in +//│ jump j$253(x$254) //│ _ => -//│ let x$260 = 3 in -//│ jump j$258(x$260) -//│ def j$258(tmp$253) = -//│ tmp$253 -//│ let* (x$261) = f4() in -//│ x$261 +//│ let x$255 = 3 in +//│ jump j$253(x$255) +//│ def j$253(tmp$249) = +//│ tmp$249 +//│ let* (x$256) = f4() in +//│ x$256 //│ //│ Interpreted: //│ 3 @@ -113,29 +113,29 @@ f5() //│ = 5 //│ LLIR: //│ -//│ def f5$262() = -//│ let x$281 = 0 in -//│ let x$282 = ==(x$281,1) in -//│ case x$282 of +//│ def f5$257() = +//│ let x$275 = 0 in +//│ let x$276 = ==(x$275,1) in +//│ case x$276 of //│ BoolLit(true) => -//│ let x$284 = 2 in -//│ jump j$283(x$284) +//│ let x$278 = 2 in +//│ jump j$277(x$278) //│ _ => -//│ let x$285 = 3 in -//│ jump j$283(x$285) -//│ def j$283(tmp$277) = -//│ let x$286 = ==(tmp$277,2) in -//│ case x$286 of +//│ let x$279 = 3 in +//│ jump j$277(x$279) +//│ def j$277(tmp$272) = +//│ let x$280 = ==(tmp$272,2) in +//│ case x$280 of //│ BoolLit(true) => -//│ let x$288 = 4 in -//│ jump j$287(x$288) +//│ let x$282 = 4 in +//│ jump j$281(x$282) //│ _ => -//│ let x$289 = 5 in -//│ jump j$287(x$289) -//│ def j$287(tmp$278) = -//│ tmp$278 -//│ let* (x$290) = f5() in -//│ x$290 +//│ let x$283 = 5 in +//│ jump j$281(x$283) +//│ def j$281(tmp$273) = +//│ tmp$273 +//│ let* (x$284) = f5() in +//│ x$284 //│ //│ Interpreted: //│ 5 @@ -146,15 +146,15 @@ fun test() = if true do test() //│ LLIR: //│ -//│ def test$291() = -//│ let x$300 = true in -//│ case x$300 of +//│ def test$285() = +//│ let x$293 = true in +//│ case x$293 of //│ BoolLit(true) => -//│ let* (x$302) = test() in -//│ x$302 +//│ let* (x$295) = test() in +//│ x$295 //│ _ => //│ undefined -//│ def j$301() = +//│ def j$294() = //│ null //│ undefined //│ @@ -192,17 +192,17 @@ fun test() = (if true then test()) + 1 //│ LLIR: //│ -//│ def test$303() = -//│ let x$315 = true in -//│ case x$315 of +//│ def test$296() = +//│ let x$307 = true in +//│ case x$307 of //│ BoolLit(true) => -//│ let* (x$317) = test() in -//│ jump j$316(x$317) +//│ let* (x$309) = test() in +//│ jump j$308(x$309) //│ _ => //│ panic "match error" -//│ def j$316(tmp$313) = -//│ let x$318 = +(tmp$313,1) in -//│ x$318 +//│ def j$308(tmp$306) = +//│ let x$310 = +(tmp$306,1) in +//│ x$310 //│ undefined //│ //│ Cpp: @@ -247,21 +247,21 @@ f() //│ = 11 //│ LLIR: //│ -//│ def f$319() = -//│ let x$334 = 10 in -//│ let x$335 = true in -//│ case x$335 of +//│ def f$311() = +//│ let x$325 = 10 in +//│ let x$326 = true in +//│ case x$326 of //│ BoolLit(true) => -//│ let x$337 = +(x$334,1) in -//│ let x$338 = undefined in -//│ jump j$336(x$337) +//│ let x$328 = +(x$325,1) in +//│ let x$329 = undefined in +//│ jump j$327(x$328) //│ _ => -//│ let x$339 = undefined in -//│ jump j$336(x$334) -//│ def j$336(x$320) = -//│ x$320 -//│ let* (x$340) = f() in -//│ x$340 +//│ let x$330 = undefined in +//│ jump j$327(x$325) +//│ def j$327(x$312) = +//│ x$312 +//│ let* (x$331) = f() in +//│ x$331 //│ //│ Cpp: //│ #include "mlsprelude.h" @@ -310,29 +310,29 @@ fun f(a) = f(A(1)) //│ = 1 //│ LLIR: -//│ class A(x$346) -//│ class B(y$349) -//│ def f$343(a$350) = -//│ case a$350 of -//│ A$344 => -//│ let x$371 = a$350. in -//│ let x$372 = 1 in -//│ jump j$370(x$372) +//│ class A(x$337) +//│ class B(y$340) +//│ def f$334(a$341) = +//│ case a$341 of +//│ A$335 => +//│ let x$361 = a$341. in +//│ let x$362 = 1 in +//│ jump j$360(x$362) //│ _ => -//│ case a$350 of -//│ B$347 => -//│ let x$374 = a$350. in -//│ let x$375 = 2 in -//│ jump j$373(x$375) +//│ case a$341 of +//│ B$338 => +//│ let x$364 = a$341. in +//│ let x$365 = 2 in +//│ jump j$363(x$365) //│ _ => //│ panic "match error" -//│ def j$373(tmp$365) = -//│ jump j$370(tmp$365) -//│ def j$370(tmp$365) = -//│ tmp$365 -//│ let x$376 = A$344(1) in -//│ let* (x$377) = f(x$376) in -//│ x$377 +//│ def j$363(tmp$356) = +//│ jump j$360(tmp$356) +//│ def j$360(tmp$356) = +//│ tmp$356 +//│ let x$366 = A$335(1) in +//│ let* (x$367) = f(x$366) in +//│ x$367 //│ //│ Interpreted: //│ 1 @@ -351,50 +351,50 @@ fun f(a) = f(A(1)) //│ = 1 //│ LLIR: -//│ class A(x$383) -//│ class B(y$386) -//│ def f$380(a$387) = -//│ case a$387 of -//│ A$381 => -//│ let x$412 = a$387. in -//│ case a$387 of -//│ A$381 => -//│ let x$414 = a$387. in -//│ case x$414 of +//│ class A(x$373) +//│ class B(y$376) +//│ def f$370(a$377) = +//│ case a$377 of +//│ A$371 => +//│ let x$401 = a$377. in +//│ case a$377 of +//│ A$371 => +//│ let x$403 = a$377. in +//│ case x$403 of //│ IntLit(1) => -//│ let x$416 = 1 in -//│ jump j$415(x$416) +//│ let x$405 = 1 in +//│ jump j$404(x$405) //│ _ => //│ panic "match error" //│ _ => -//│ case a$387 of -//│ B$384 => -//│ let x$418 = a$387. in -//│ let x$419 = 2 in -//│ jump j$417(x$419) +//│ case a$377 of +//│ B$374 => +//│ let x$407 = a$377. in +//│ let x$408 = 2 in +//│ jump j$406(x$408) //│ _ => //│ panic "match error" //│ _ => -//│ case a$387 of -//│ B$384 => -//│ let x$421 = a$387. in -//│ let x$422 = 3 in -//│ jump j$420(x$422) +//│ case a$377 of +//│ B$374 => +//│ let x$410 = a$377. in +//│ let x$411 = 3 in +//│ jump j$409(x$411) //│ _ => //│ panic "match error" -//│ def j$415(tmp$405) = -//│ jump j$413(tmp$405) -//│ def j$417(tmp$405) = -//│ jump j$413(tmp$405) -//│ def j$413(tmp$405) = -//│ jump j$411(tmp$405) -//│ def j$420(tmp$406) = -//│ jump j$411(tmp$406) -//│ def j$411(tmp$406) = -//│ tmp$406 -//│ let x$423 = A$381(1) in -//│ let* (x$424) = f(x$423) in -//│ x$424 +//│ def j$404(tmp$395) = +//│ jump j$402(tmp$395) +//│ def j$406(tmp$395) = +//│ jump j$402(tmp$395) +//│ def j$402(tmp$395) = +//│ jump j$400(tmp$395) +//│ def j$409(tmp$396) = +//│ jump j$400(tmp$396) +//│ def j$400(tmp$396) = +//│ tmp$396 +//│ let x$412 = A$371(1) in +//│ let* (x$413) = f(x$412) in +//│ x$413 //│ //│ Interpreted: //│ 1 diff --git a/hkmc2/shared/src/test/mlscript/llir/Ctor.mls b/hkmc2/shared/src/test/mlscript/llir/Ctor.mls index 7237a0eb64..d76b5fff0f 100644 --- a/hkmc2/shared/src/test/mlscript/llir/Ctor.mls +++ b/hkmc2/shared/src/test/mlscript/llir/Ctor.mls @@ -10,12 +10,12 @@ fun testCtor1() = None fun testCtor2() = new None //│ LLIR: //│ class None() -//│ def testCtor1$199() = -//│ let x$209 = None$201() in -//│ x$209 -//│ def testCtor2$198() = -//│ let x$210 = None$201() in -//│ x$210 +//│ def testCtor1$198() = +//│ let x$207 = None$200() in +//│ x$207 +//│ def testCtor2$197() = +//│ let x$208 = None$200() in +//│ x$208 //│ undefined :sllir @@ -23,11 +23,11 @@ class A(x) fun testCtor1() = A(1) fun testCtor2() = new A(1) //│ LLIR: -//│ class A(x$216) -//│ def testCtor1$213() = -//│ let x$225 = A$214(1) in -//│ x$225 -//│ def testCtor2$212() = -//│ let x$226 = A$214(1) in -//│ x$226 +//│ class A(x$214) +//│ def testCtor1$211() = +//│ let x$222 = A$212(1) in +//│ x$222 +//│ def testCtor2$210() = +//│ let x$223 = A$212(1) in +//│ x$223 //│ undefined diff --git a/hkmc2/shared/src/test/mlscript/llir/HigherOrder.mls b/hkmc2/shared/src/test/mlscript/llir/HigherOrder.mls index 27c37659ff..05ea80c8f7 100644 --- a/hkmc2/shared/src/test/mlscript/llir/HigherOrder.mls +++ b/hkmc2/shared/src/test/mlscript/llir/HigherOrder.mls @@ -12,24 +12,24 @@ fun add_curried(x)(y) = x + y add(1)(2) //│ = 3 //│ LLIR: -//│ class Lambda(x$200) extends Callable { -//│ def apply1$221(y$201) = -//│ let x$222 = +(x$200,y$201) in -//│ x$222 +//│ class Lambda(x$199) extends Callable { +//│ def apply1$219(y$200) = +//│ let x$220 = +(x$199,y$200) in +//│ x$220 //│ } -//│ class Lambda(x$204) extends Callable { -//│ def apply1$221(y$205) = -//│ let x$226 = +(x$204,y$205) in +//│ class Lambda(x$203) extends Callable { +//│ def apply1$219(y$204) = +//│ let x$226 = +(x$203,y$204) in //│ x$226 //│ } -//│ def add$198(x$200) = -//│ let x$223 = Lambda$219(x$200) in +//│ def add$197(x$199) = +//│ let x$223 = Lambda$217(x$199) in //│ x$223 -//│ def add_curried$199(x$204) = -//│ let x$227 = Lambda$224(x$204) in +//│ def add_curried$198(x$203) = +//│ let x$227 = Lambda$224(x$203) in //│ x$227 //│ let* (x$228) = add(1) in -//│ let x$229 = Callable.apply1$221(x$228,2) in +//│ let x$229 = Callable.apply1$219(x$228,2) in //│ x$229 //│ //│ Cpp: @@ -100,28 +100,28 @@ add4(1, 2)(3, 4) //│ = 10 //│ LLIR: //│ class Lambda(b$233,a$232) extends Callable { -//│ def apply2$269(c$234,d$235) = -//│ let x$270 = +(a$232,b$233) in -//│ let x$271 = +(x$270,c$234) in -//│ let x$272 = +(x$271,d$235) in -//│ x$272 +//│ def apply2$268(c$234,d$235) = +//│ let x$269 = +(a$232,b$233) in +//│ let x$270 = +(x$269,c$234) in +//│ let x$271 = +(x$270,d$235) in +//│ x$271 //│ } //│ class Lambda(a$240,b$241) extends Callable { -//│ def apply2$269(c$242,d$243) = -//│ let x$276 = +(a$240,b$241) in -//│ let x$277 = +(x$276,c$242) in -//│ let x$278 = +(x$277,d$243) in -//│ x$278 +//│ def apply2$268(c$242,d$243) = +//│ let x$275 = +(a$240,b$241) in +//│ let x$276 = +(x$275,c$242) in +//│ let x$277 = +(x$276,d$243) in +//│ x$277 //│ } //│ def add4$231(a$232,b$233) = -//│ let x$273 = Lambda$267(b$233,a$232) in -//│ x$273 +//│ let x$272 = Lambda$266(b$233,a$232) in +//│ x$272 //│ def add4_curried$230(a$240,b$241) = -//│ let x$279 = Lambda$274(a$240,b$241) in -//│ x$279 -//│ let* (x$280) = add4(1,2) in -//│ let x$281 = Callable.apply2$269(x$280,3,4) in -//│ x$281 +//│ let x$278 = Lambda$273(a$240,b$241) in +//│ x$278 +//│ let* (x$279) = add4(1,2) in +//│ let x$280 = Callable.apply2$268(x$279,3,4) in +//│ x$280 //│ //│ Cpp: //│ #include "mlsprelude.h" @@ -197,19 +197,19 @@ dummy()(1, 2) //│ = 3 //│ LLIR: //│ class Lambda_add() extends Callable { -//│ def apply2$305(arg$301,arg$302) = -//│ let* (x$306) = add(arg$301,arg$302) in -//│ x$306 +//│ def apply2$268(arg$299,arg$300) = +//│ let* (x$303) = add(arg$299,arg$300) in +//│ x$303 //│ } -//│ def add$282(a$284,b$285) = -//│ let x$300 = +(a$284,b$285) in -//│ x$300 -//│ def dummy$283() = -//│ let x$307 = Lambda_add$303() in -//│ x$307 -//│ let* (x$308) = dummy() in -//│ let x$309 = Callable.apply2$305(x$308,1,2) in -//│ x$309 +//│ def add$281(a$283,b$284) = +//│ let x$298 = +(a$283,b$284) in +//│ x$298 +//│ def dummy$282() = +//│ let x$304 = Lambda_add$301() in +//│ x$304 +//│ let* (x$305) = dummy() in +//│ let x$306 = Callable.apply2$268(x$305,1,2) in +//│ x$306 //│ //│ Cpp: //│ #include "mlsprelude.h" @@ -272,55 +272,55 @@ main() //│ = Cons(4, Cons(5, Nil)) //│ LLIR: //│ class List() -//│ class Cons(head$322,tail$323) extends List +//│ class Cons(head$319,tail$320) extends List //│ class Nil() extends List //│ class Lambda() extends Callable { -//│ def apply1$395(x$340) = -//│ let* (x$406) = inc(x$340) in -//│ x$406 +//│ def apply1$219(x$337) = +//│ let* (x$401) = inc(x$337) in +//│ x$401 //│ } //│ class Lambda_inc() extends Callable { -//│ def apply1$395(arg$412) = -//│ let* (x$415) = inc(arg$412) in -//│ x$415 +//│ def apply1$219(arg$407) = +//│ let* (x$410) = inc(arg$407) in +//│ x$410 //│ } -//│ def map$311(f$326,l$327) = -//│ case l$327 of -//│ Cons$319 => -//│ let x$392 = l$327. in -//│ let x$393 = l$327. in -//│ let x$394 = Callable.apply1$395(f$326,x$392) in -//│ let* (x$396) = map(f$326,x$393) in -//│ let x$397 = Cons$319(x$394,x$396) in -//│ x$397 +//│ def map$308(f$323,l$324) = +//│ case l$324 of +//│ Cons$316 => +//│ let x$388 = l$324. in +//│ let x$389 = l$324. in +//│ let x$390 = Callable.apply1$219(f$323,x$388) in +//│ let* (x$391) = map(f$323,x$389) in +//│ let x$392 = Cons$316(x$390,x$391) in +//│ x$392 //│ _ => -//│ case l$327 of -//│ Nil$324 => -//│ let x$399 = Nil$324() in -//│ x$399 +//│ case l$324 of +//│ Nil$321 => +//│ let x$394 = Nil$321() in +//│ x$394 //│ _ => //│ panic "match error" -//│ def j$398() = -//│ jump j$391() -//│ def j$391() = +//│ def j$393() = +//│ jump j$387() +//│ def j$387() = //│ null -//│ def inc$314(x$336) = -//│ let x$400 = +(x$336,1) in -//│ x$400 -//│ def main$312() = -//│ let x$401 = Nil$324() in -//│ let x$402 = Cons$319(2,x$401) in -//│ let x$403 = Cons$319(1,x$402) in -//│ let x$407 = Lambda$404() in -//│ let* (x$408) = map(x$407,x$403) in -//│ let x$409 = Nil$324() in -//│ let x$410 = Cons$319(4,x$409) in -//│ let x$411 = Cons$319(3,x$410) in -//│ let x$416 = Lambda_inc$413() in -//│ let* (x$417) = map(x$416,x$411) in -//│ x$417 -//│ let* (x$418) = main() in -//│ x$418 +//│ def inc$311(x$333) = +//│ let x$395 = +(x$333,1) in +//│ x$395 +//│ def main$309() = +//│ let x$396 = Nil$321() in +//│ let x$397 = Cons$316(2,x$396) in +//│ let x$398 = Cons$316(1,x$397) in +//│ let x$402 = Lambda$399() in +//│ let* (x$403) = map(x$402,x$398) in +//│ let x$404 = Nil$321() in +//│ let x$405 = Cons$316(4,x$404) in +//│ let x$406 = Cons$316(3,x$405) in +//│ let x$411 = Lambda_inc$408() in +//│ let* (x$412) = map(x$411,x$406) in +//│ x$412 +//│ let* (x$413) = main() in +//│ x$413 //│ //│ Interpreted: //│ Cons(4,Cons(5,Nil())) diff --git a/hkmc2/shared/src/test/mlscript/llir/Legacy.mls b/hkmc2/shared/src/test/mlscript/llir/Legacy.mls index ba0cc42a44..aad2239602 100644 --- a/hkmc2/shared/src/test/mlscript/llir/Legacy.mls +++ b/hkmc2/shared/src/test/mlscript/llir/Legacy.mls @@ -255,74 +255,74 @@ main() //│ = 404 //│ LLIR: //│ class Option() -//│ class Some(x$1028) extends Option +//│ class Some(x$1014) extends Option //│ class None() extends Option //│ class Nat() -//│ class S(s$1039) extends Nat +//│ class S(s$1025) extends Nat //│ class O() extends Nat -//│ def fromSome$1011(s$1031) = -//│ case s$1031 of -//│ Some$1025 => -//│ let x$1107 = s$1031. in -//│ x$1107 +//│ def fromSome$997(s$1017) = +//│ case s$1017 of +//│ Some$1011 => +//│ let x$1092 = s$1017. in +//│ x$1092 //│ _ => //│ panic "match error" -//│ def j$1106() = +//│ def j$1091() = //│ null -//│ def aaa$1016() = -//│ let x$1108 = 1 in -//│ let x$1109 = 2 in -//│ let x$1110 = 3 in -//│ let x$1111 = 4 in -//│ let x$1112 = +(x$1108,x$1109) in -//│ let x$1113 = -(x$1112,x$1110) in -//│ let x$1114 = +(x$1113,x$1111) in -//│ x$1114 -//│ def bbb$1018() = -//│ let* (x$1115) = aaa() in -//│ let x$1116 = *(x$1115,100) in -//│ let x$1117 = +(x$1116,4) in -//│ x$1117 -//│ def not$1014(x$1055) = -//│ case x$1055 of +//│ def aaa$1002() = +//│ let x$1093 = 1 in +//│ let x$1094 = 2 in +//│ let x$1095 = 3 in +//│ let x$1096 = 4 in +//│ let x$1097 = +(x$1093,x$1094) in +//│ let x$1098 = -(x$1097,x$1095) in +//│ let x$1099 = +(x$1098,x$1096) in +//│ x$1099 +//│ def bbb$1004() = +//│ let* (x$1100) = aaa() in +//│ let x$1101 = *(x$1100,100) in +//│ let x$1102 = +(x$1101,4) in +//│ x$1102 +//│ def not$1000(x$1041) = +//│ case x$1041 of //│ BoolLit(true) => //│ false //│ _ => //│ true -//│ def j$1118() = +//│ def j$1103() = //│ null -//│ def foo$1021(x$1057) = -//│ case x$1057 of +//│ def foo$1007(x$1043) = +//│ case x$1043 of //│ BoolLit(true) => -//│ let x$1120 = None$1029() in -//│ x$1120 +//│ let x$1105 = None$1015() in +//│ x$1105 //│ _ => -//│ let* (x$1121) = not(x$1057) in -//│ let* (x$1122) = foo(x$1121) in -//│ let x$1123 = Some$1025(x$1122) in -//│ x$1123 -//│ def j$1119() = +//│ let* (x$1106) = not(x$1043) in +//│ let* (x$1107) = foo(x$1106) in +//│ let x$1108 = Some$1011(x$1107) in +//│ x$1108 +//│ def j$1104() = //│ null -//│ def main$1012() = -//│ let* (x$1124) = foo(false) in -//│ case x$1124 of -//│ None$1029 => -//│ let* (x$1126) = aaa() in -//│ x$1126 +//│ def main$998() = +//│ let* (x$1109) = foo(false) in +//│ case x$1109 of +//│ None$1015 => +//│ let* (x$1111) = aaa() in +//│ x$1111 //│ _ => -//│ case x$1124 of -//│ Some$1025 => -//│ let x$1128 = x$1124. in -//│ let* (x$1129) = bbb() in -//│ x$1129 +//│ case x$1109 of +//│ Some$1011 => +//│ let x$1113 = x$1109. in +//│ let* (x$1114) = bbb() in +//│ x$1114 //│ _ => //│ panic "match error" -//│ def j$1127() = -//│ jump j$1125() -//│ def j$1125() = +//│ def j$1112() = +//│ jump j$1110() +//│ def j$1110() = //│ null -//│ let* (x$1130) = main() in -//│ x$1130 +//│ let* (x$1115) = main() in +//│ x$1115 //│ //│ Interpreted: //│ 404 diff --git a/hkmc2/shared/src/test/mlscript/llir/Method.mls b/hkmc2/shared/src/test/mlscript/llir/Method.mls index bf994c4abb..2f980e49ae 100644 --- a/hkmc2/shared/src/test/mlscript/llir/Method.mls +++ b/hkmc2/shared/src/test/mlscript/llir/Method.mls @@ -17,9 +17,9 @@ main() //│ m$200 //│ } //│ def main$197() = -//│ let x$213 = A$198(1) in -//│ let x$214 = A.f$195(x$213) in -//│ x$214 -//│ let* (x$215) = main() in -//│ x$215 +//│ let x$212 = A$198(1) in +//│ let x$213 = A.f$195(x$212) in +//│ x$213 +//│ let* (x$214) = main() in +//│ x$214 diff --git a/hkmc2/shared/src/test/mlscript/llir/Tuple.mls b/hkmc2/shared/src/test/mlscript/llir/Tuple.mls index 0a4a94df8f..215a393903 100644 --- a/hkmc2/shared/src/test/mlscript/llir/Tuple.mls +++ b/hkmc2/shared/src/test/mlscript/llir/Tuple.mls @@ -12,21 +12,21 @@ mkTup(1, 2) //│ = [1, 2] //│ LLIR: //│ -//│ def mkTup$198(x$200,y$201) = -//│ let x$215 = Tuple2$216(x$200,y$201) in -//│ x$215 -//│ def fst$199(t$203) = -//│ case t$203 of -//│ Tuple2$216 => -//│ let x$219 = t$203. in -//│ let x$220 = t$203. in -//│ x$219 +//│ def mkTup$197(x$199,y$200) = +//│ let x$213 = Tuple2$214(x$199,y$200) in +//│ x$213 +//│ def fst$198(t$202) = +//│ case t$202 of +//│ Tuple2$214 => +//│ let x$217 = t$202. in +//│ let x$218 = t$202. in +//│ x$217 //│ _ => //│ panic "match error" -//│ def j$218() = +//│ def j$216() = //│ null -//│ let* (x$221) = mkTup(1,2) in -//│ x$221 +//│ let* (x$219) = mkTup(1,2) in +//│ x$219 //│ //│ Interpreted: //│ Tuple2(1,2) diff --git a/hkmc2DiffTests/src/test/scala/hkmc2/LlirDiffMaker.scala b/hkmc2DiffTests/src/test/scala/hkmc2/LlirDiffMaker.scala index 063c367e30..c8a1664a90 100644 --- a/hkmc2DiffTests/src/test/scala/hkmc2/LlirDiffMaker.scala +++ b/hkmc2DiffTests/src/test/scala/hkmc2/LlirDiffMaker.scala @@ -77,7 +77,7 @@ abstract class LlirDiffMaker extends BbmlDiffMaker: def cppGen(name: String, prog: Program, gen: Bool, show: Bool, run: Bool, write: Opt[Str]): Unit = tl.log(s"Generating $name") if gen || show || run || write.isDefined then - val cpp = CppCodeGen(llb.builtinSymbols, tl).codegen(prog) + val cpp = CppCodeGen(ctx.builtin_sym.callableSym.toSet, tl).codegen(prog) if show then output(s"\n$name:") output(cpp.toDocument.toString) From 17bd141407fa39120042b29c2593b89b8067e319 Mon Sep 17 00:00:00 2001 From: waterlens Date: Thu, 20 Feb 2025 19:54:36 +0800 Subject: [PATCH 43/88] compile NofibPrelude.mls --- .../main/scala/hkmc2/codegen/cpp/Ast.scala | 26 +- .../scala/hkmc2/codegen/cpp/CodeGen.scala | 51 +- .../scala/hkmc2/codegen/llir/Builder.scala | 72 ++- .../scala/hkmc2/codegen/llir/Interp.scala | 35 +- .../test/mlscript-compile/cpp/mlsprelude.h | 18 + .../shared/src/test/mlscript/llir/Classes.mls | 20 +- .../src/test/mlscript/llir/HigherOrder.mls | 518 ++++++++++++++---- .../src/test/mlscript/llir/NofibPrelude.mls | 16 +- hkmc2/shared/src/test/mlscript/llir/Tuple.mls | 48 ++ 9 files changed, 597 insertions(+), 207 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/Ast.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/Ast.scala index c05e4f1d3e..5c584be257 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/Ast.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/Ast.scala @@ -161,43 +161,48 @@ case class CompilationUnit(includes: Ls[Str], decls: Ls[Decl], defs: Ls[Def]): def toDocumentWithoutHidden: Document = val hiddenNames: Set[Str] = Set() defs.filterNot { - case Def.StructDef(name, _, _, _) => hiddenNames.contains(name.stripPrefix("_mls_")) + case Def.StructDef(name, _, _, _, _) => hiddenNames.contains(name.stripPrefix("_mls_")) case _ => false }.map(_.toDocument).mkDocument(doc" # ") enum Decl: case StructDecl(name: Str) case EnumDecl(name: Str) - case FuncDecl(ret: Type, name: Str, args: Ls[Type]) + case FuncDecl(ret: Type, name: Str, args: Ls[Type], or: Bool = false, virt: Bool = false) case VarDecl(name: Str, typ: Type) def toDocument: Document = def aux(x: Decl): Document = x match case StructDecl(name) => doc"struct $name;" case EnumDecl(name) => doc"enum $name;" - case FuncDecl(ret, name, args) => - doc"${ret.toDocument()} $name(${Type.toDocuments(args, sep = ", ")});" + case FuncDecl(ret, name, args, or, virt) => + val docVirt = (if virt then doc"virtual " else doc"") + val docSpecRet = ret.toDocument() + val docArgs = Type.toDocuments(args, sep = ", ") + val docOverride = if or then doc" override" else doc"" + doc"$docVirt$docSpecRet $name($docArgs)$docOverride;" case VarDecl(name, typ) => doc"${typ.toDocument()} $name;" aux(this) enum Def: - case StructDef(name: Str, fields: Ls[(Str, Type)], inherit: Opt[Ls[Str]], methods: Ls[Def] = Ls.empty) + case StructDef(name: Str, fields: Ls[(Str, Type)], inherit: Opt[Ls[Str]], methods: Ls[Def] = Ls.empty, methods_decl: Ls[Decl] = Ls.empty) case EnumDef(name: Str, fields: Ls[(Str, Opt[Int])]) - case FuncDef(specret: Type, name: Str, args: Ls[(Str, Type)], body: Stmt.Block, or: Bool = false, virt: Bool = false) + case FuncDef(specret: Type, name: Str, args: Ls[(Str, Type)], body: Stmt.Block, or: Bool = false, virt: Bool = false, scope: Opt[Str] = None) case VarDef(typ: Type, name: Str, init: Opt[Expr]) case RawDef(raw: Str) def toDocument: Document = def aux(x: Def): Document = x match - case StructDef(name, fields, inherit, defs) => + case StructDef(name, fields, inherit, defs, decls) => val docFirst = doc"struct $name${inherit.fold(doc"")(x => doc": public ${x.mkDocument(doc", ")}")} {" val docFields = fields.map { case (name, typ) => doc"${typ.toDocument()} $name;" }.mkDocument(doc" # ") val docDefs = defs.map(_.toDocument).mkDocument(doc" # ") + val docDecls = decls.map(_.toDocument).mkDocument(doc" # ") val docLast = "};" - doc"$docFirst #{ # $docFields # $docDefs #} # $docLast" + doc"$docFirst #{ # $docFields # $docDefs # $docDecls #} # $docLast" case EnumDef(name, fields) => val docFirst = doc"enum $name {" val docFields = fields.map { @@ -205,13 +210,14 @@ enum Def: }.mkDocument(doc" # ") val docLast = "};" doc"$docFirst #{ # $docFields #} # $docLast" - case FuncDef(specret, name, args, body, or, virt) => + case FuncDef(specret, name, args, body, or, virt, scope) => val docVirt = (if virt then doc"virtual " else doc"") val docSpecRet = specret.toDocument() val docArgs = Type.toDocuments(args, sep = ", ") val docOverride = if or then doc" override" else doc"" val docBody = body.toDocument - doc"$docVirt$docSpecRet $name($docArgs)$docOverride ${body.toDocument}" + val docScope = scope.fold(doc"")(x => doc"$x::") + doc"$docVirt$docSpecRet $docScope$name($docArgs)$docOverride ${body.toDocument}" case VarDef(typ, name, init) => val docTyp = typ.toDocument() val docInit = init.fold(raw(""))(x => doc" = ${x.toDocument}") diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/CodeGen.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/CodeGen.scala index 23db22f3ed..11530926d0 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/CodeGen.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/CodeGen.scala @@ -61,6 +61,8 @@ class CppCodeGen(builtinClassSymbols: Set[Local], tl: TraceLogger): def mlsCall(fn: Str, args: Ls[Expr]) = Expr.Call(Expr.Var("_mlsCall"), Expr.Var(fn) :: args) def mlsMethodCall(cls: Local, method: Str, args: Ls[Expr])(using Raise, Scope) = Expr.Call(Expr.Member(Expr.Call(Expr.Var(s"_mlsMethodCall<${cls |> mapClsLikeName}>"), Ls(args.head)), method), args.tail) + def mlsThisCall(cls: Local, method: Str, args: Ls[Expr])(using Raise, Scope) = + Expr.Call(Expr.Member(Expr.Var("this"), method), args) def mlsFnWrapperName(fn: Str) = s"_mlsFn_$fn" def mlsFnCreateMethod(fn: Str) = s"static _mlsValue create() { static _mlsFn_$fn mlsFn alignas(_mlsAlignment); mlsFn.refCount = stickyRefCount; mlsFn.tag = typeTag; return _mlsValue(&mlsFn); }" def mlsNeverValue(n: Int) = if (n <= 1) then Expr.Call(Expr.Var(s"_mlsValue::never"), Ls()) else Expr.Call(Expr.Var(s"_mlsValue::never<$n>"), Ls()) @@ -85,15 +87,28 @@ class CppCodeGen(builtinClassSymbols: Set[Local], tl: TraceLogger): getVar(l) |> mapName else summon[Scope].allocateName(l) |> mapName - - def codegenClassInfo(using Ctx, Raise, Scope)(cls: ClassInfo): (Opt[Def], Decl) = - trace[(Opt[Def], Decl)](s"codegenClassInfo ${cls.name} begin"): + + def codegenClassInfo(using Ctx, Raise, Scope)(cls: ClassInfo) = + trace[(Opt[Def], Decl, Ls[Def])](s"codegenClassInfo ${cls.name} begin"): val fields = cls.fields.map{x => (x |> directName, mlsValType)} cls.fields.foreach(x => summon[Scope].allocateName(x)) val parents = if cls.parents.nonEmpty then cls.parents.toList.map(mapClsLikeName) else mlsObject :: Nil val decl = Decl.StructDecl(cls.name |> mapClsLikeName) - if mlsIsInternalClass(cls.name) then (None, decl) + if mlsIsInternalClass(cls.name) then (None, decl, Ls.empty) else + val methods = cls.methods.map: + case (name, defn) => + val (cdef, decl) = codegenDefn(using Ctx(summon[Ctx].defnCtx + cls.name, summon[Ctx].fieldCtx ++ cls.fields))(defn) + val cdef2 = cdef match + case x: Def.FuncDef if builtinApply.contains(defn.name.nme) => x.copy(name = defn.name |> directName, scope = Some(cls.name |> mapClsLikeName)) + case x: Def.FuncDef => x.copy(scope = Some(cls.name |> mapClsLikeName)) + case _ => throw new Exception(s"codegenClassInfo: unexpected def $cdef") + val decl2 = decl match + case x: Decl.FuncDecl if builtinApply.contains(defn.name.nme) => x.copy(virt = true, name = defn.name |> directName) + case x: Decl.FuncDecl => x.copy(virt = true) + case _ => throw new Exception(s"codegenClassInfo: unexpected decl $decl") + log(s"codegenClassInfo: ${cls.name} method ${defn.name} $decl2") + (cdef2, decl2) val theDef = Def.StructDef( cls.name |> mapClsLikeName, fields, if parents.nonEmpty then Some(parents) else None, @@ -101,16 +116,10 @@ class CppCodeGen(builtinClassSymbols: Set[Local], tl: TraceLogger): Def.RawDef(mlsTypeTag()), Def.RawDef(mlsCommonPrintMethod(cls.fields.map(directName))), Def.RawDef(mlsCommonDestructorMethod(cls.name |> mapClsLikeName, cls.fields.map(directName))), - Def.RawDef(mlsCommonCreateMethod(cls.name |> mapClsLikeName, cls.fields.map(directName), cls.id))) - ++ cls.methods.map{case (name, defn) => { - val (theDef, decl) = codegenDefn(using Ctx(summon[Ctx].defnCtx + cls.name, summon[Ctx].fieldCtx ++ cls.fields))(defn) - theDef match - case x @ Def.FuncDef(_, _, _, _, _, _) if builtinApply.contains(defn.name.nme) => x.copy(virt = true, name = defn.name |> directName) - case x @ Def.FuncDef(_, _, _, _, _, _) => x.copy(virt = true) - case _ => theDef - }} + Def.RawDef(mlsCommonCreateMethod(cls.name |> mapClsLikeName, cls.fields.map(directName), cls.id))), + methods.iterator.map(_._2).toList ) - (S(theDef), decl) + (S(theDef), decl, methods.iterator.map(_._1).toList) def toExpr(texpr: TrivialExpr, reifyUnit: Bool = false)(using Ctx, Raise, Scope): Opt[Expr] = texpr match case IExpr.Ref(name) if summon[Ctx].fieldCtx.contains(name) => S(Expr.Var(name |> directName)) @@ -174,7 +183,7 @@ class CppCodeGen(builtinClassSymbols: Set[Local], tl: TraceLogger): case "*" => Expr.Binary("*", toExpr(args(0)), toExpr(args(1))) case "/" => Expr.Binary("/", toExpr(args(0)), toExpr(args(1))) case "%" => Expr.Binary("%", toExpr(args(0)), toExpr(args(1))) - case "==" => Expr.Binary("==", toExpr(args(0)), toExpr(args(1))) + case "==" | "===" => Expr.Binary("==", toExpr(args(0)), toExpr(args(1))) case "!=" => Expr.Binary("!=", toExpr(args(0)), toExpr(args(1))) case "<" => Expr.Binary("<", toExpr(args(0)), toExpr(args(1))) case "<=" => Expr.Binary("<=", toExpr(args(0)), toExpr(args(1))) @@ -183,12 +192,14 @@ class CppCodeGen(builtinClassSymbols: Set[Local], tl: TraceLogger): case "&&" => Expr.Binary("&&", toExpr(args(0)), toExpr(args(1))) case "||" => Expr.Binary("||", toExpr(args(0)), toExpr(args(1))) case "!" => Expr.Unary("!", toExpr(args(0))) - case _ => TODO("codegenOps") + case _ => TODO(s"codegenOps $op2") def codegen(expr: IExpr)(using Ctx, Raise, Scope): Expr = expr match case x @ (IExpr.Ref(_) | IExpr.Literal(_)) => toExpr(x, reifyUnit = true).get case IExpr.CtorApp(cls, args) => mlsNewValue(cls |> mapClsLikeName, args.map(toExpr)) + case IExpr.Select(name, cls, field) if field.forall(_.isDigit) => + Expr.Member(mlsAsUnchecked(name |> allocIfNew, cls |> mapClsLikeName), s"field${field}" |> mapName) case IExpr.Select(name, cls, field) => Expr.Member(mlsAsUnchecked(name |> allocIfNew, cls |> mapClsLikeName), field |> mapName) case IExpr.BasicOp(name, args) => codegenOps(name, args) case IExpr.AssignField(assignee, cls, field, value) => TODO("codegen assign field") @@ -223,9 +234,13 @@ class CppCodeGen(builtinClassSymbols: Set[Local], tl: TraceLogger): case Node.LetExpr(name, expr, body) => val stmts2 = stmts ++ Ls(Stmt.AutoBind(Ls(name |> allocIfNew), codegen(expr))) codegen(body, storeInto)(using decls, stmts2) - case Node.LetMethodCall(names, cls, method, IExpr.Ref(bin: BuiltinSymbol) :: args, body) if bin.nme == "builtin" => + case Node.LetMethodCall(names, cls, method, IExpr.Ref(bin: BuiltinSymbol) :: args, body) if bin.nme == "" => val stmts2 = stmts ++ codegenBuiltin(names, args.head.toString.replace("\"", ""), args.tail) codegen(body, storeInto)(using decls, stmts2) + case Node.LetMethodCall(names, cls, method, IExpr.Ref(bin: BuiltinSymbol) :: args, body) if bin.nme == "" => + val call = mlsThisCall(cls, method |> directName, args.map(toExpr)) + val stmts2 = stmts ++ Ls(Stmt.AutoBind(names.map(allocIfNew), call)) + codegen(body, storeInto)(using decls, stmts2) case Node.LetMethodCall(names, cls, method, args, body) if builtinApply.contains(method.nme) => val call = mlsMethodCall(cls, method |> directName, args.map(toExpr)) val stmts2 = stmts ++ Ls(Stmt.AutoBind(names.map(allocIfNew), call)) @@ -290,8 +305,8 @@ class CppCodeGen(builtinClassSymbols: Set[Local], tl: TraceLogger): val defnCtx = prog.defs.map(_.name) val fieldCtx = Set.empty[Local] given Ctx = Ctx(defnCtx, fieldCtx) - val (defs, decls) = sortedClasses.map(codegenClassInfo).unzip + val (defs, decls, methodsDef) = sortedClasses.map(codegenClassInfo).unzip3 val (defs2, decls2) = prog.defs.map(codegenDefn).unzip val (defMain, declMain) = codegenTopNode(prog.main) - CompilationUnit(Ls(mlsPrelude), decls ++ decls2 :+ declMain, defs.flatten ++ defs2 :+ defMain :+ Def.RawDef(mlsEntryPoint)) + CompilationUnit(Ls(mlsPrelude), decls ++ decls2 :+ declMain, defs.flatten ++ defs2 ++ methodsDef.flatten :+ defMain :+ Def.RawDef(mlsEntryPoint)) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala index 0122446104..e84a68f6fa 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala @@ -29,6 +29,7 @@ final case class FuncInfo(paramsSize: Int) final case class BuiltinSymbols( var callableSym: Opt[Local] = None, + var thisSym: Opt[Local] = None, fieldSym: MutMap[Int, Local] = MutMap.empty, applySym: MutMap[Int, Local] = MutMap.empty, tupleSym: MutMap[Int, Local] = MutMap.empty, @@ -44,7 +45,7 @@ final case class Ctx( is_top_level: Bool = true, method_class: Opt[Symbol] = None, free_vars: Set[Local] = Set.empty, - builtin_sym: BuiltinSymbols = BuiltinSymbols(), + builtin_sym: BuiltinSymbols = BuiltinSymbols() ): def addFuncName(n: Local, paramsSize: Int) = copy(fn_ctx = fn_ctx + (n -> FuncInfo(paramsSize))) def findFuncName(n: Local)(using Raise) = fn_ctx.get(n) match @@ -66,7 +67,6 @@ final case class Ctx( object Ctx: def empty = Ctx(ListBuffer.empty, ListBuffer.empty) - final class LlirBuilder(using Elaborator.State)(tl: TraceLogger, uid: FreshInt): import tl.{trace, log, logs} @@ -100,7 +100,10 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger, uid: FreshInt): trace[Set[Local]](s"freeVarsFilter begin", x => s"freeVarsFilter end: $x"): fvs.filter: case _: (BuiltinSymbol | TopLevelSymbol | ClassSymbol | MemberSymbol[?]) => false - case _ => true + case x => true + + private def symMap(s: Local)(using ctx: Ctx)(using Raise, Scope) = + ctx.findName(s) private def newTemp = TempSymbol(N, "x") private def newNamedTemp(name: Str) = TempSymbol(N, name) @@ -111,17 +114,24 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger, uid: FreshInt): ClassSymbol(Tree.TypeDef(hkmc2.syntax.Cls, Tree.Empty(), N, N), Tree.Ident(s"Tuple$len")) private def newMemSym(name: Str) = TermSymbol(hkmc2.syntax.ImmutVal, None, Tree.Ident(name)) private def newMethodSym(name: Str) = TermSymbol(hkmc2.syntax.Fun, None, Tree.Ident(name)) + private def newBuiltinSym(name: Str) = BuiltinSymbol(name, false, false, false, false) private def builtinField(n: Int)(using Ctx) = summon[Ctx].builtin_sym.fieldSym.getOrElseUpdate(n, newMemSym(s"field$n")) private def builtinApply(n: Int)(using Ctx) = summon[Ctx].builtin_sym.applySym.getOrElseUpdate(n, newMethodSym(s"apply$n")) private def builtinTuple(n: Int)(using Ctx) = summon[Ctx].builtin_sym.tupleSym.getOrElseUpdate(n, newTupleSym(n)) private def builtinCallable(using ctx: Ctx) : Local = ctx.builtin_sym.callableSym match case None => - val sym = newClassSym("Callable") + val sym = newBuiltinSym("Callable") ctx.builtin_sym.callableSym = Some(sym); sym case Some(value) => value - + private def builtinThis(using ctx: Ctx) : Local = + ctx.builtin_sym.thisSym match + case None => + val sym = newBuiltinSym("") + ctx.builtin_sym.thisSym = Some(sym); + sym + case Some(value) => value private def bBind(name: Opt[Local], e: Result, body: Block)(k: TrivialExpr => Ctx ?=> Node)(ct: Block)(using ctx: Ctx)(using Raise, Scope): Node = trace[Node](s"bBind begin: $name", x => s"bBind end: ${x.show}"): @@ -152,12 +162,21 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger, uid: FreshInt): case r: TrivialExpr => bPaths(xs): case rs: Ls[TrivialExpr] => k(r :: rs) + private def bNestedFunDef(e: FunDefn)(k: TrivialExpr => Ctx ?=> Node)(using ctx: Ctx)(using Raise, Scope): Node = + val FunDefn(_own, sym, params, body) = e + // generate it as a single named lambda expression that may be self-recursing + if params.length == 0 then + errStop(msg"Function without arguments not supported: ${params.length.toString}") + else + val fstParams = params.head + val wrappedLambda = params.tail.foldRight(body)((params, acc) => Return(Value.Lam(params, acc), false)) + bLam(Value.Lam(fstParams, wrappedLambda), S(sym.nme), S(sym))(k)(using ctx) + private def bFunDef(e: FunDefn)(using ctx: Ctx)(using Raise, Scope): Func = trace[Func](s"bFunDef begin: ${e.sym}", x => s"bFunDef end: ${x.show}"): val FunDefn(_own, sym, params, body) = e - if !ctx.is_top_level then - errStop(msg"Non top-level definition ${sym.nme} not supported") - else if params.length == 0 then + assert(ctx.is_top_level) + if params.length == 0 then errStop(msg"Function without arguments not supported: ${params.length.toString}") else val paramsList = params.head.params @@ -210,24 +229,25 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger, uid: FreshInt): funcs.map(f => f.name -> f).toMap, ) - private def bLam(lam: Value.Lam, nameHint: Opt[Str])(k: TrivialExpr => Ctx ?=> Node)(using ctx: Ctx)(using Raise, Scope) : Node = + private def bLam(lam: Value.Lam, nameHint: Opt[Str], recName: Opt[Local])(k: TrivialExpr => Ctx ?=> Node)(using ctx: Ctx)(using Raise, Scope) : Node = trace[Node](s"bLam begin", x => s"bLam end: ${x.show}"): val Value.Lam(params, body) = lam // Generate an auxiliary class inheriting from Callable val freeVars = freeVarsFilter(lam.freeVars -- lam.body.definedVars -- ctx.fn_ctx.keySet) val name = newClassSym(s"Lambda${nameHint.fold("")(x => "_" + x)}") - val clsParams = freeVars.toList - val args = freeVars.toList + val args = freeVars.toList.map(symMap) + val clsParams = args val ctx2 = ctx.setFreeVars(freeVars) val applyParams = params.params.map(x => x -> x.sym) val ctx3 = applyParams.foldLeft(ctx2)((acc, x) => acc.addName(x._1.sym, x._1.sym)).nonTopLevel + val ctx4 = recName.fold(ctx3)(x => ctx3.addName(x, builtinThis)) val pl = applyParams.map(_._1.sym) val method = Func( uid.make, builtinApply(params.params.length), params = pl, resultNum = 1, - body = bBlockWithEndCont(body)(x => Node.Result(Ls(x)))(using ctx3) + body = bBlockWithEndCont(body)(x => Node.Result(Ls(x)))(using ctx4) ) ctx.class_acc += ClassInfo( uid.make, @@ -237,7 +257,8 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger, uid: FreshInt): Map(method.name -> method), ) val v: Local = newTemp - Node.LetExpr(v, Expr.CtorApp(name, args.map(sr)), k(v |> sr)(using ctx)) + val new_ctx = recName.fold(ctx)(x => ctx.addName(x, v)) + Node.LetExpr(v, Expr.CtorApp(name, args.map(sr)), k(v |> sr)(using new_ctx)) private def bValue(v: Value)(k: TrivialExpr => Ctx ?=> Node)(using ctx: Ctx)(using Raise, Scope) : Node = trace[Node](s"bValue { $v } begin", x => s"bValue end: ${x.show}"): @@ -255,12 +276,12 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger, uid: FreshInt): (0 until f.paramsSize).zip(tempSymbols).map((_n, sym) => Param(FldFlags.empty, sym, N)).toList) val app = Call(v, tempSymbols.map(x => Arg(false, Value.Ref(x))).toList)(true, false) - bLam(Value.Lam(paramsList, Return(app, false)), S(l.nme))(k) + bLam(Value.Lam(paramsList, Return(app, false)), S(l.nme), N)(k) case None => k(ctx.findName(l) |> sr) case Value.This(sym) => errStop(msg"Unsupported value: This") case Value.Lit(lit) => k(Expr.Literal(lit)) - case lam @ Value.Lam(params, body) => bLam(lam, N)(k) + case lam @ Value.Lam(params, body) => bLam(lam, N, N)(k) case Value.Arr(elems) => bArgs(elems): case args: Ls[TrivialExpr] => @@ -347,16 +368,18 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger, uid: FreshInt): val v: Local = newTemp Node.LetExpr(v, Expr.CtorApp(fromMemToClass(sym), args), k(v |> sr)) case Call(s @ Value.Ref(sym), args) => - bArgs(args): - case args: Ls[TrivialExpr] => val v: Local = newTemp ctx.fn_ctx.get(sym) match case Some(f) => - Node.LetCall(Ls(v), sym, args, k(v |> sr)) + bArgs(args): + case args: Ls[TrivialExpr] => + Node.LetCall(Ls(v), sym, args, k(v |> sr)) case None => bPath(s): case f: TrivialExpr => - Node.LetMethodCall(Ls(v), builtinCallable, builtinApply(args.length), f :: args, k(v |> sr)) + bArgs(args): + case args: Ls[TrivialExpr] => + Node.LetMethodCall(Ls(v), builtinCallable, builtinApply(args.length), f :: args, k(v |> sr)) case Call(s @ Select(r @ Value.Ref(sym), Tree.Ident(fld)), args) if s.symbol.isDefined => bPath(r): case r => @@ -441,9 +464,14 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger, uid: FreshInt): bBind(S(lhs), rhs, rest)(k)(ct) case AssignField(lhs, nme, rhs, rest) => TODO("AssignField not supported") case Define(fd @ FunDefn(_own, sym, params, body), rest) => - val f = bFunDef(fd)(using ctx) - ctx.def_acc += f - bBlock(rest)(k)(ct)(using ctx) + if ctx.is_top_level then + val f = bFunDef(fd) + ctx.def_acc += f + bBlock(rest)(k)(ct) + else + bNestedFunDef(fd): + case r: TrivialExpr => + bBlock(rest)(k)(ct) case Define(_: ClsLikeDefn, rest) => bBlock(rest)(k)(ct) case End(msg) => k(Expr.Literal(Tree.UnitLit(false))) case _: Block => diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Interp.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Interp.scala index bfd804b93a..a22e9ec44a 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Interp.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Interp.scala @@ -11,6 +11,7 @@ import hkmc2.codegen.llir.* import hkmc2.syntax.Tree import hkmc2.codegen.Local import hkmc2.utils.TraceLogger +import hkmc2.semantics.BuiltinSymbol enum Stuck: case StuckExpr(expr: Expr, msg: Str) @@ -51,6 +52,7 @@ class Interpreter(tl: TraceLogger): bindingCtx: Map[Local, Value], classCtx: Map[Local, ClassInfo], funcCtx: Map[Local, Func], + thisVal: Opt[Value], ) import Node._ @@ -67,7 +69,10 @@ class Interpreter(tl: TraceLogger): case ("-", Li(IntLit(x)), Li(IntLit(y))) => S(Li(IntLit(x - y))) case ("*", Li(IntLit(x)), Li(IntLit(y))) => S(Li(IntLit(x * y))) case ("/", Li(IntLit(x)), Li(IntLit(y))) => S(Li(IntLit(x / y))) + case ("&&", Li(BoolLit(x)), Li(BoolLit(y))) => S(if x && y then getTrue else getFalse) + case ("||", Li(BoolLit(x)), Li(BoolLit(y))) => S(if x || y then getTrue else getFalse) case ("==", Li(IntLit(x)), Li(IntLit(y))) => S(if x == y then getTrue else getFalse) + case ("===", Li(IntLit(x)), Li(IntLit(y))) => S(if x == y then getTrue else getFalse) case ("!=", Li(IntLit(x)), Li(IntLit(y))) => S(if x != y then getTrue else getFalse) case ("<=", Li(IntLit(x)), Li(IntLit(y))) => S(if x <= y then getTrue else getFalse) case (">=", Li(IntLit(x)), Li(IntLit(y))) => S(if x >= y then getTrue else getFalse) @@ -80,20 +85,22 @@ class Interpreter(tl: TraceLogger): var stuck: Opt[Stuck] = None exprs foreach { expr => stuck match - case None => eval(expr) match + case None => eval_t(expr) match case L(x) => stuck = Some(x) case R(x) => values += x case _ => () } stuck.toLeft(values.toList) - private def eval(expr: TrivialExpr)(using ctx: Ctx): Result[Value] = expr match - case e @ Ref(name) => ctx.bindingCtx.get(name).toRight(StuckExpr(e, s"undefined variable $name")) - case Literal(lit) => R(Value.Literal(lit)) + private def eval_t(expr: TrivialExpr)(using ctx: Ctx): Result[Value] = expr match + case Ref(x: BuiltinSymbol) => x.nme match + case "" => ctx.thisVal.toRight(StuckExpr(expr.toExpr, s"undefined this value")) + case _ => L(StuckExpr(expr.toExpr, s"undefined builtin ${x.nme}")) + case Ref(x) => ctx.bindingCtx.get(x).toRight(StuckExpr(expr.toExpr, s"undefined variable $x")) + case Literal(x) => R(Value.Literal(x)) private def eval(expr: Expr)(using ctx: Ctx): Result[Value] = expr match - case Ref(x) => ctx.bindingCtx.get(x).toRight(StuckExpr(expr, s"undefined variable $x")) - case Literal(x) => R(Value.Literal(x)) + case x: TrivialExpr => eval_t(x) case CtorApp(cls, args) => for xs <- evalArgs(args) @@ -112,15 +119,15 @@ class Interpreter(tl: TraceLogger): evalArgs(args).flatMap( xs => name.nme match - case "+" | "-" | "*" | "/" | "==" | "!=" | "<=" | ">=" | "<" | ">" => + case "+" | "-" | "*" | "/" | "==" | "===" | "!=" | "<=" | ">=" | "<" | ">" => if xs.length < 2 then break: L(StuckExpr(expr, s"not enough arguments for basic operation $name")) else eval(name.nme, xs.head, xs.tail.head).toRight(StuckExpr(expr, s"unable to evaluate basic operation")) case _ => L(StuckExpr(expr, s"unexpected basic operation $name"))) case AssignField(assignee, cls, field, value) => for - x <- eval(Ref(assignee): TrivialExpr) - y <- eval(value) + x <- eval_t(Ref(assignee): TrivialExpr) + y <- eval_t(value) res <- x match case obj @ Value.Class(cls2, xs) if cls == cls2 => xs.zip(cls2.fields).find{_._2.nme == field} match @@ -143,7 +150,7 @@ class Interpreter(tl: TraceLogger): res <- eval(func.body)(using ctx1) yield res case Case(scrut, cases, default) => - eval(scrut) flatMap { + eval_t(scrut) flatMap { case Value.Class(cls, fields) => cases.find { case (Pat.Class(cls2), _) => cls.name == cls2 @@ -182,9 +189,12 @@ class Interpreter(tl: TraceLogger): cls.methods.find(_._1.nme == method.nme).map(_._2) for ys <- evalArgs(args).flatMap { - case Value.Class(cls2, xs) :: args => + case (ths @ Value.Class(cls2, xs)) :: args => lookup_method(cls2, method).toRight(StuckNode(node, s"undefined method ${method.nme}")).flatMap { method => - val ctx1 = ctx.copy(bindingCtx = ctx.bindingCtx ++ cls2.fields.zip(xs) ++ method.params.zip(args)) + val ctx1 = ctx.copy( + bindingCtx = ctx.bindingCtx ++ cls2.fields.zip(xs) ++ method.params.zip(args), + thisVal = S(ths) + ) eval(method.body)(using ctx1) } case _ => L(StuckNode(node, s"not enough arguments for method call, or the first argument is not a class")) @@ -209,6 +219,7 @@ class Interpreter(tl: TraceLogger): bindingCtx = Map.empty, classCtx = classes.map(cls => (cls.name, cls)).toMap, funcCtx = defs.map(func => (func.name, func)).toMap, + thisVal = None, ) eval(main) match case R(x) => x diff --git a/hkmc2/shared/src/test/mlscript-compile/cpp/mlsprelude.h b/hkmc2/shared/src/test/mlscript-compile/cpp/mlsprelude.h index fed52549bb..d84ac89b9e 100644 --- a/hkmc2/shared/src/test/mlscript-compile/cpp/mlsprelude.h +++ b/hkmc2/shared/src/test/mlscript-compile/cpp/mlsprelude.h @@ -206,6 +206,24 @@ class _mlsValue { assert(false); } + _mlsValue operator!=(const _mlsValue &other) const { + if (isInt63() && other.isInt63()) + return _mlsValue::fromBoolLit(!eqInt63(other)); + assert(false); + } + + _mlsValue operator&&(const _mlsValue &other) const { + if (isInt63() && other.isInt63()) + return _mlsValue::fromBoolLit(asInt63() && other.asInt63()); + assert(false); + } + + _mlsValue operator||(const _mlsValue &other) const { + if (isInt63() && other.isInt63()) + return _mlsValue::fromBoolLit(asInt63() || other.asInt63()); + assert(false); + } + _mlsValue operator+(const _mlsValue &other) const { if (isInt63() && other.isInt63()) return addInt63(other); diff --git a/hkmc2/shared/src/test/mlscript/llir/Classes.mls b/hkmc2/shared/src/test/mlscript/llir/Classes.mls index 33c0a4f221..8a56cbb9be 100644 --- a/hkmc2/shared/src/test/mlscript/llir/Classes.mls +++ b/hkmc2/shared/src/test/mlscript/llir/Classes.mls @@ -26,21 +26,21 @@ fun main() = main() //│ LLIR: //│ class Base() { -//│ def get$226() = +//│ def get$225() = //│ 1 //│ } //│ class Derived() extends Base { -//│ def get$227() = +//│ def get$226() = //│ 2 //│ } -//│ def main$229() = -//│ let x$251 = Derived$234() in -//│ let x$252 = Base.get$226(x$251) in -//│ let x$253 = Derived.get$227(x$251) in -//│ let x$254 = *(x$252,x$253) in -//│ x$254 -//│ let* (x$255) = main() in -//│ x$255 +//│ def main$228() = +//│ let x$250 = Derived$233() in +//│ let x$251 = Base.get$225(x$250) in +//│ let x$252 = Derived.get$226(x$250) in +//│ let x$253 = *(x$251,x$252) in +//│ x$253 +//│ let* (x$254) = main() in +//│ x$254 //│ //│ Interpreted: //│ 4 diff --git a/hkmc2/shared/src/test/mlscript/llir/HigherOrder.mls b/hkmc2/shared/src/test/mlscript/llir/HigherOrder.mls index 05ea80c8f7..58e5c602b1 100644 --- a/hkmc2/shared/src/test/mlscript/llir/HigherOrder.mls +++ b/hkmc2/shared/src/test/mlscript/llir/HigherOrder.mls @@ -19,18 +19,18 @@ add(1)(2) //│ } //│ class Lambda(x$203) extends Callable { //│ def apply1$219(y$204) = -//│ let x$226 = +(x$203,y$204) in -//│ x$226 +//│ let x$225 = +(x$203,y$204) in +//│ x$225 //│ } //│ def add$197(x$199) = -//│ let x$223 = Lambda$217(x$199) in -//│ x$223 +//│ let x$222 = Lambda$217(x$199) in +//│ x$222 //│ def add_curried$198(x$203) = -//│ let x$227 = Lambda$224(x$203) in -//│ x$227 -//│ let* (x$228) = add(1) in -//│ let x$229 = Callable.apply1$219(x$228,2) in -//│ x$229 +//│ let x$226 = Lambda$223(x$203) in +//│ x$226 +//│ let* (x$227) = add(1) in +//│ let x$228 = Callable.apply1$219(x$227,2) in +//│ x$228 //│ //│ Cpp: //│ #include "mlsprelude.h" @@ -46,12 +46,7 @@ add(1)(2) //│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->_mls_x.print(); std::printf(")"); } //│ virtual void destroy() override { _mlsValue::destroy(this->_mls_x); operator delete (this, std::align_val_t(_mlsAlignment)); } //│ static _mlsValue create(_mlsValue _mls_x) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) _mls_Lambda; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->_mls_x = _mls_x; return _mlsValue(_mlsVal); } -//│ virtual _mlsValue _mls_apply1(_mlsValue _mls_y) { -//│ _mlsValue _mls_retval; -//│ auto _mls_x1 = (_mls_x + _mls_y); -//│ _mls_retval = _mls_x1; -//│ return _mls_retval; -//│ } +//│ virtual _mlsValue _mls_apply1(_mlsValue); //│ }; //│ struct _mls_Lambda1: public _mls_Callable { //│ _mlsValue _mls_x; @@ -60,12 +55,7 @@ add(1)(2) //│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->_mls_x.print(); std::printf(")"); } //│ virtual void destroy() override { _mlsValue::destroy(this->_mls_x); operator delete (this, std::align_val_t(_mlsAlignment)); } //│ static _mlsValue create(_mlsValue _mls_x) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) _mls_Lambda1; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->_mls_x = _mls_x; return _mlsValue(_mlsVal); } -//│ virtual _mlsValue _mls_apply1(_mlsValue _mls_y1) { -//│ _mlsValue _mls_retval; -//│ auto _mls_x3 = (_mls_x + _mls_y1); -//│ _mls_retval = _mls_x3; -//│ return _mls_retval; -//│ } +//│ virtual _mlsValue _mls_apply1(_mlsValue); //│ }; //│ _mlsValue _mls_add(_mlsValue _mls_x) { //│ _mlsValue _mls_retval; @@ -79,6 +69,18 @@ add(1)(2) //│ _mls_retval = _mls_x5; //│ return _mls_retval; //│ } +//│ _mlsValue _mls_Lambda::_mls_apply1(_mlsValue _mls_y) { +//│ _mlsValue _mls_retval; +//│ auto _mls_x1 = (_mls_x + _mls_y); +//│ _mls_retval = _mls_x1; +//│ return _mls_retval; +//│ } +//│ _mlsValue _mls_Lambda1::_mls_apply1(_mlsValue _mls_y1) { +//│ _mlsValue _mls_retval; +//│ auto _mls_x3 = (_mls_x + _mls_y1); +//│ _mls_retval = _mls_x3; +//│ return _mls_retval; +//│ } //│ _mlsValue _mlsMain() { //│ _mlsValue _mls_retval; //│ auto _mls_x6 = _mls_add(_mlsValue::fromIntLit(1)); @@ -99,29 +101,29 @@ fun add4_curried(a, b)(c, d) = a + b + c + d add4(1, 2)(3, 4) //│ = 10 //│ LLIR: -//│ class Lambda(b$233,a$232) extends Callable { -//│ def apply2$268(c$234,d$235) = -//│ let x$269 = +(a$232,b$233) in -//│ let x$270 = +(x$269,c$234) in -//│ let x$271 = +(x$270,d$235) in -//│ x$271 +//│ class Lambda(a$231,b$232) extends Callable { +//│ def apply2$267(c$233,d$234) = +//│ let x$268 = +(a$231,b$232) in +//│ let x$269 = +(x$268,c$233) in +//│ let x$270 = +(x$269,d$234) in +//│ x$270 //│ } -//│ class Lambda(a$240,b$241) extends Callable { -//│ def apply2$268(c$242,d$243) = -//│ let x$275 = +(a$240,b$241) in -//│ let x$276 = +(x$275,c$242) in -//│ let x$277 = +(x$276,d$243) in -//│ x$277 +//│ class Lambda(b$240,a$239) extends Callable { +//│ def apply2$267(c$241,d$242) = +//│ let x$274 = +(a$239,b$240) in +//│ let x$275 = +(x$274,c$241) in +//│ let x$276 = +(x$275,d$242) in +//│ x$276 //│ } -//│ def add4$231(a$232,b$233) = -//│ let x$272 = Lambda$266(b$233,a$232) in -//│ x$272 -//│ def add4_curried$230(a$240,b$241) = -//│ let x$278 = Lambda$273(a$240,b$241) in -//│ x$278 -//│ let* (x$279) = add4(1,2) in -//│ let x$280 = Callable.apply2$268(x$279,3,4) in -//│ x$280 +//│ def add4$230(a$231,b$232) = +//│ let x$271 = Lambda$265(a$231,b$232) in +//│ x$271 +//│ def add4_curried$229(a$239,b$240) = +//│ let x$277 = Lambda$272(b$240,a$239) in +//│ x$277 +//│ let* (x$278) = add4(1,2) in +//│ let x$279 = Callable.apply2$267(x$278,3,4) in +//│ x$279 //│ //│ Cpp: //│ #include "mlsprelude.h" @@ -131,51 +133,53 @@ add4(1, 2)(3, 4) //│ _mlsValue _mls_add4_curried(_mlsValue, _mlsValue); //│ _mlsValue _mlsMain(); //│ struct _mls_Lambda2: public _mls_Callable { -//│ _mlsValue _mls_b; //│ _mlsValue _mls_a; +//│ _mlsValue _mls_b; //│ constexpr static inline const char *typeName = "Lambda"; //│ constexpr static inline uint32_t typeTag = nextTypeTag(); -//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->_mls_b.print(); std::printf(", "); this->_mls_a.print(); std::printf(")"); } -//│ virtual void destroy() override { _mlsValue::destroy(this->_mls_b); _mlsValue::destroy(this->_mls_a); operator delete (this, std::align_val_t(_mlsAlignment)); } -//│ static _mlsValue create(_mlsValue _mls_b, _mlsValue _mls_a) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) _mls_Lambda2; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->_mls_b = _mls_b; _mlsVal->_mls_a = _mls_a; return _mlsValue(_mlsVal); } -//│ virtual _mlsValue _mls_apply2(_mlsValue _mls_c, _mlsValue _mls_d) { -//│ _mlsValue _mls_retval; -//│ auto _mls_x8 = (_mls_a + _mls_b); -//│ auto _mls_x9 = (_mls_x8 + _mls_c); -//│ auto _mls_x10 = (_mls_x9 + _mls_d); -//│ _mls_retval = _mls_x10; -//│ return _mls_retval; -//│ } +//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->_mls_a.print(); std::printf(", "); this->_mls_b.print(); std::printf(")"); } +//│ virtual void destroy() override { _mlsValue::destroy(this->_mls_a); _mlsValue::destroy(this->_mls_b); operator delete (this, std::align_val_t(_mlsAlignment)); } +//│ static _mlsValue create(_mlsValue _mls_a, _mlsValue _mls_b) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) _mls_Lambda2; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->_mls_a = _mls_a; _mlsVal->_mls_b = _mls_b; return _mlsValue(_mlsVal); } +//│ virtual _mlsValue _mls_apply2(_mlsValue, _mlsValue); //│ }; //│ struct _mls_Lambda3: public _mls_Callable { -//│ _mlsValue _mls_a; //│ _mlsValue _mls_b; +//│ _mlsValue _mls_a; //│ constexpr static inline const char *typeName = "Lambda"; //│ constexpr static inline uint32_t typeTag = nextTypeTag(); -//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->_mls_a.print(); std::printf(", "); this->_mls_b.print(); std::printf(")"); } -//│ virtual void destroy() override { _mlsValue::destroy(this->_mls_a); _mlsValue::destroy(this->_mls_b); operator delete (this, std::align_val_t(_mlsAlignment)); } -//│ static _mlsValue create(_mlsValue _mls_a, _mlsValue _mls_b) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) _mls_Lambda3; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->_mls_a = _mls_a; _mlsVal->_mls_b = _mls_b; return _mlsValue(_mlsVal); } -//│ virtual _mlsValue _mls_apply2(_mlsValue _mls_c1, _mlsValue _mls_d1) { -//│ _mlsValue _mls_retval; -//│ auto _mls_x11 = (_mls_a + _mls_b); -//│ auto _mls_x12 = (_mls_x11 + _mls_c1); -//│ auto _mls_x13 = (_mls_x12 + _mls_d1); -//│ _mls_retval = _mls_x13; -//│ return _mls_retval; -//│ } +//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->_mls_b.print(); std::printf(", "); this->_mls_a.print(); std::printf(")"); } +//│ virtual void destroy() override { _mlsValue::destroy(this->_mls_b); _mlsValue::destroy(this->_mls_a); operator delete (this, std::align_val_t(_mlsAlignment)); } +//│ static _mlsValue create(_mlsValue _mls_b, _mlsValue _mls_a) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) _mls_Lambda3; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->_mls_b = _mls_b; _mlsVal->_mls_a = _mls_a; return _mlsValue(_mlsVal); } +//│ virtual _mlsValue _mls_apply2(_mlsValue, _mlsValue); //│ }; //│ _mlsValue _mls_add4(_mlsValue _mls_a, _mlsValue _mls_b) { //│ _mlsValue _mls_retval; -//│ auto _mls_x14 = _mlsValue::create<_mls_Lambda2>(_mls_b, _mls_a); +//│ auto _mls_x14 = _mlsValue::create<_mls_Lambda2>(_mls_a, _mls_b); //│ _mls_retval = _mls_x14; //│ return _mls_retval; //│ } //│ _mlsValue _mls_add4_curried(_mlsValue _mls_a1, _mlsValue _mls_b1) { //│ _mlsValue _mls_retval; -//│ auto _mls_x15 = _mlsValue::create<_mls_Lambda3>(_mls_a1, _mls_b1); +//│ auto _mls_x15 = _mlsValue::create<_mls_Lambda3>(_mls_b1, _mls_a1); //│ _mls_retval = _mls_x15; //│ return _mls_retval; //│ } +//│ _mlsValue _mls_Lambda2::_mls_apply2(_mlsValue _mls_c, _mlsValue _mls_d) { +//│ _mlsValue _mls_retval; +//│ auto _mls_x8 = (_mls_a + _mls_b); +//│ auto _mls_x9 = (_mls_x8 + _mls_c); +//│ auto _mls_x10 = (_mls_x9 + _mls_d); +//│ _mls_retval = _mls_x10; +//│ return _mls_retval; +//│ } +//│ _mlsValue _mls_Lambda3::_mls_apply2(_mlsValue _mls_c1, _mlsValue _mls_d1) { +//│ _mlsValue _mls_retval; +//│ auto _mls_x11 = (_mls_a + _mls_b); +//│ auto _mls_x12 = (_mls_x11 + _mls_c1); +//│ auto _mls_x13 = (_mls_x12 + _mls_d1); +//│ _mls_retval = _mls_x13; +//│ return _mls_retval; +//│ } //│ _mlsValue _mlsMain() { //│ _mlsValue _mls_retval; //│ auto _mls_x16 = _mls_add4(_mlsValue::fromIntLit(1), _mlsValue::fromIntLit(2)); @@ -197,19 +201,19 @@ dummy()(1, 2) //│ = 3 //│ LLIR: //│ class Lambda_add() extends Callable { -//│ def apply2$268(arg$299,arg$300) = -//│ let* (x$303) = add(arg$299,arg$300) in -//│ x$303 +//│ def apply2$267(arg$298,arg$299) = +//│ let* (x$302) = add(arg$298,arg$299) in +//│ x$302 //│ } -//│ def add$281(a$283,b$284) = -//│ let x$298 = +(a$283,b$284) in -//│ x$298 -//│ def dummy$282() = -//│ let x$304 = Lambda_add$301() in -//│ x$304 -//│ let* (x$305) = dummy() in -//│ let x$306 = Callable.apply2$268(x$305,1,2) in -//│ x$306 +//│ def add$280(a$282,b$283) = +//│ let x$297 = +(a$282,b$283) in +//│ x$297 +//│ def dummy$281() = +//│ let x$303 = Lambda_add$300() in +//│ x$303 +//│ let* (x$304) = dummy() in +//│ let x$305 = Callable.apply2$267(x$304,1,2) in +//│ x$305 //│ //│ Cpp: //│ #include "mlsprelude.h" @@ -224,12 +228,7 @@ dummy()(1, 2) //│ virtual void print() const override { std::printf("%s", typeName); } //│ virtual void destroy() override { operator delete (this, std::align_val_t(_mlsAlignment)); } //│ static _mlsValue create() { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) _mls_Lambda_add; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; return _mlsValue(_mlsVal); } -//│ virtual _mlsValue _mls_apply2(_mlsValue _mls_arg, _mlsValue _mls_arg1) { -//│ _mlsValue _mls_retval; -//│ auto _mls_x18 = _mls_add1(_mls_arg, _mls_arg1); -//│ _mls_retval = _mls_x18; -//│ return _mls_retval; -//│ } +//│ virtual _mlsValue _mls_apply2(_mlsValue, _mlsValue); //│ }; //│ _mlsValue _mls_add1(_mlsValue _mls_a2, _mlsValue _mls_b2) { //│ _mlsValue _mls_retval; @@ -243,6 +242,12 @@ dummy()(1, 2) //│ _mls_retval = _mls_x20; //│ return _mls_retval; //│ } +//│ _mlsValue _mls_Lambda_add::_mls_apply2(_mlsValue _mls_arg, _mlsValue _mls_arg1) { +//│ _mlsValue _mls_retval; +//│ auto _mls_x18 = _mls_add1(_mls_arg, _mls_arg1); +//│ _mls_retval = _mls_x18; +//│ return _mls_retval; +//│ } //│ _mlsValue _mlsMain() { //│ _mlsValue _mls_retval; //│ auto _mls_x21 = _mls_dummy(); @@ -272,11 +277,11 @@ main() //│ = Cons(4, Cons(5, Nil)) //│ LLIR: //│ class List() -//│ class Cons(head$319,tail$320) extends List +//│ class Cons(head$318,tail$319) extends List //│ class Nil() extends List //│ class Lambda() extends Callable { -//│ def apply1$219(x$337) = -//│ let* (x$401) = inc(x$337) in +//│ def apply1$219(x$336) = +//│ let* (x$401) = inc(x$336) in //│ x$401 //│ } //│ class Lambda_inc() extends Callable { @@ -284,44 +289,317 @@ main() //│ let* (x$410) = inc(arg$407) in //│ x$410 //│ } -//│ def map$308(f$323,l$324) = -//│ case l$324 of -//│ Cons$316 => -//│ let x$388 = l$324. in -//│ let x$389 = l$324. in -//│ let x$390 = Callable.apply1$219(f$323,x$388) in -//│ let* (x$391) = map(f$323,x$389) in -//│ let x$392 = Cons$316(x$390,x$391) in -//│ x$392 +//│ def map$307(f$322,l$323) = +//│ case l$323 of +//│ Cons$315 => +//│ let x$387 = l$323. in +//│ let x$388 = l$323. in +//│ let x$389 = Callable.apply1$219(f$322,x$387) in +//│ let* (x$390) = map(f$322,x$388) in +//│ let x$391 = Cons$315(x$389,x$390) in +//│ x$391 //│ _ => -//│ case l$324 of -//│ Nil$321 => -//│ let x$394 = Nil$321() in -//│ x$394 +//│ case l$323 of +//│ Nil$320 => +//│ let x$393 = Nil$320() in +//│ x$393 //│ _ => //│ panic "match error" -//│ def j$393() = -//│ jump j$387() -//│ def j$387() = +//│ def j$392() = +//│ jump j$386() +//│ def j$386() = //│ null -//│ def inc$311(x$333) = -//│ let x$395 = +(x$333,1) in -//│ x$395 -//│ def main$309() = -//│ let x$396 = Nil$321() in -//│ let x$397 = Cons$316(2,x$396) in -//│ let x$398 = Cons$316(1,x$397) in +//│ def inc$310(x$332) = +//│ let x$394 = +(x$332,1) in +//│ x$394 +//│ def main$308() = +//│ let x$395 = Nil$320() in +//│ let x$396 = Cons$315(2,x$395) in +//│ let x$397 = Cons$315(1,x$396) in //│ let x$402 = Lambda$399() in -//│ let* (x$403) = map(x$402,x$398) in -//│ let x$404 = Nil$321() in -//│ let x$405 = Cons$316(4,x$404) in -//│ let x$406 = Cons$316(3,x$405) in +//│ let* (x$398) = map(x$402,x$397) in +//│ let x$403 = Nil$320() in +//│ let x$404 = Cons$315(4,x$403) in +//│ let x$405 = Cons$315(3,x$404) in //│ let x$411 = Lambda_inc$408() in -//│ let* (x$412) = map(x$411,x$406) in -//│ x$412 -//│ let* (x$413) = main() in -//│ x$413 +//│ let* (x$406) = map(x$411,x$405) in +//│ x$406 +//│ let* (x$412) = main() in +//│ x$412 //│ //│ Interpreted: //│ Cons(4,Cons(5,Nil())) +:scpp +:sllir +:intl +abstract class List[out T]: Cons[T] | Nil +class (::) Cons[out T](head: T, tail: List[T]) extends List[T] +object Nil extends List +fun not(c) = if c then false else true +fun filter(f, ls) = if ls is + Nil then Nil + h :: t and + f(h) then h :: filter(f, t) + else filter(f, t) +fun nubBy(eq, ls) = if ls is + Nil then Nil + h :: t then h :: nubBy(eq, filter(y => not(eq(h, y)), t)) +nubBy((x, y) => x == y, 1 :: 2 :: 3 :: 3 :: Nil) +//│ = Cons(1, Cons(2, Cons(3, Nil))) +//│ LLIR: +//│ class List() +//│ class Cons(head$425,tail$426) extends List +//│ class Nil() extends List +//│ class Lambda(eq$443,x$527) extends Callable { +//│ def apply1$219(y$452) = +//│ let x$532 = Callable.apply2$267(eq$443,x$527,y$452) in +//│ let* (x$533) = not(x$532) in +//│ x$533 +//│ } +//│ class Lambda() extends Callable { +//│ def apply2$267(x$457,y$458) = +//│ let x$545 = ==(x$457,y$458) in +//│ x$545 +//│ } +//│ def not$416(c$429) = +//│ case c$429 of +//│ BoolLit(true) => +//│ false +//│ _ => +//│ true +//│ def j$513() = +//│ null +//│ def filter$415(f$431,ls$432) = +//│ case ls$432 of +//│ Nil$427 => +//│ let x$515 = Nil$427() in +//│ x$515 +//│ _ => +//│ case ls$432 of +//│ Cons$422 => +//│ let x$517 = ls$432. in +//│ let x$518 = ls$432. in +//│ let x$519 = Callable.apply1$219(f$431,x$517) in +//│ case x$519 of +//│ BoolLit(true) => +//│ let* (x$521) = filter(f$431,x$518) in +//│ let x$522 = Cons$422(x$517,x$521) in +//│ x$522 +//│ _ => +//│ let* (x$523) = filter(f$431,x$518) in +//│ x$523 +//│ _ => +//│ panic "match error" +//│ def j$520() = +//│ jump j$516() +//│ def j$516() = +//│ jump j$514() +//│ def j$514() = +//│ null +//│ def nubBy$418(eq$443,ls$444) = +//│ case ls$444 of +//│ Nil$427 => +//│ let x$525 = Nil$427() in +//│ x$525 +//│ _ => +//│ case ls$444 of +//│ Cons$422 => +//│ let x$527 = ls$444. in +//│ let x$528 = ls$444. in +//│ let x$534 = Lambda$530(eq$443,x$527) in +//│ let* (x$529) = filter(x$534,x$528) in +//│ let* (x$535) = nubBy(eq$443,x$529) in +//│ let x$536 = Cons$422(x$527,x$535) in +//│ x$536 +//│ _ => +//│ panic "match error" +//│ def j$526() = +//│ jump j$524() +//│ def j$524() = +//│ null +//│ let x$537 = Nil$427() in +//│ let x$538 = Cons$422(3,x$537) in +//│ let x$539 = Cons$422(3,x$538) in +//│ let x$540 = Cons$422(2,x$539) in +//│ let x$541 = Cons$422(1,x$540) in +//│ let x$546 = Lambda$543() in +//│ let* (x$542) = nubBy(x$546,x$541) in +//│ x$542 +//│ +//│ Cpp: +//│ #include "mlsprelude.h" +//│ struct _mls_List1; +//│ struct _mls_Cons1; +//│ struct _mls_Nil1; +//│ struct _mls_Lambda6; +//│ struct _mls_Lambda5; +//│ _mlsValue _mls_j4(); +//│ _mlsValue _mls_j6(); +//│ _mlsValue _mls_filter(_mlsValue, _mlsValue); +//│ _mlsValue _mls_j7(); +//│ _mlsValue _mls_j5(); +//│ _mlsValue _mls_not(_mlsValue); +//│ _mlsValue _mls_nubBy(_mlsValue, _mlsValue); +//│ _mlsValue _mls_j2(); +//│ _mlsValue _mls_j3(); +//│ _mlsValue _mlsMain(); +//│ struct _mls_List1: public _mlsObject { +//│ +//│ constexpr static inline const char *typeName = "List"; +//│ constexpr static inline uint32_t typeTag = nextTypeTag(); +//│ virtual void print() const override { std::printf("%s", typeName); } +//│ virtual void destroy() override { operator delete (this, std::align_val_t(_mlsAlignment)); } +//│ static _mlsValue create() { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) _mls_List1; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; return _mlsValue(_mlsVal); } +//│ +//│ }; +//│ struct _mls_Cons1: public _mls_List1 { +//│ _mlsValue _mls_head; +//│ _mlsValue _mls_tail; +//│ constexpr static inline const char *typeName = "Cons"; +//│ constexpr static inline uint32_t typeTag = nextTypeTag(); +//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->_mls_head.print(); std::printf(", "); this->_mls_tail.print(); std::printf(")"); } +//│ virtual void destroy() override { _mlsValue::destroy(this->_mls_head); _mlsValue::destroy(this->_mls_tail); operator delete (this, std::align_val_t(_mlsAlignment)); } +//│ static _mlsValue create(_mlsValue _mls_head, _mlsValue _mls_tail) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) _mls_Cons1; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->_mls_head = _mls_head; _mlsVal->_mls_tail = _mls_tail; return _mlsValue(_mlsVal); } +//│ +//│ }; +//│ struct _mls_Nil1: public _mls_List1 { +//│ +//│ constexpr static inline const char *typeName = "Nil"; +//│ constexpr static inline uint32_t typeTag = nextTypeTag(); +//│ virtual void print() const override { std::printf("%s", typeName); } +//│ virtual void destroy() override { operator delete (this, std::align_val_t(_mlsAlignment)); } +//│ static _mlsValue create() { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) _mls_Nil1; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; return _mlsValue(_mlsVal); } +//│ +//│ }; +//│ struct _mls_Lambda6: public _mls_Callable { +//│ +//│ constexpr static inline const char *typeName = "Lambda"; +//│ constexpr static inline uint32_t typeTag = nextTypeTag(); +//│ virtual void print() const override { std::printf("%s", typeName); } +//│ virtual void destroy() override { operator delete (this, std::align_val_t(_mlsAlignment)); } +//│ static _mlsValue create() { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) _mls_Lambda6; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; return _mlsValue(_mlsVal); } +//│ virtual _mlsValue _mls_apply2(_mlsValue, _mlsValue); +//│ }; +//│ struct _mls_Lambda5: public _mls_Callable { +//│ _mlsValue _mls_eq; +//│ _mlsValue _mls_x; +//│ constexpr static inline const char *typeName = "Lambda"; +//│ constexpr static inline uint32_t typeTag = nextTypeTag(); +//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->_mls_eq.print(); std::printf(", "); this->_mls_x.print(); std::printf(")"); } +//│ virtual void destroy() override { _mlsValue::destroy(this->_mls_eq); _mlsValue::destroy(this->_mls_x); operator delete (this, std::align_val_t(_mlsAlignment)); } +//│ static _mlsValue create(_mlsValue _mls_eq, _mlsValue _mls_x) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) _mls_Lambda5; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->_mls_eq = _mls_eq; _mlsVal->_mls_x = _mls_x; return _mlsValue(_mlsVal); } +//│ virtual _mlsValue _mls_apply1(_mlsValue); +//│ }; +//│ _mlsValue _mls_not(_mlsValue _mls_c2) { +//│ _mlsValue _mls_retval; +//│ if (_mlsValue::isIntLit(_mls_c2, 1)) { +//│ _mls_retval = _mlsValue::fromIntLit(0); +//│ } else { +//│ _mls_retval = _mlsValue::fromIntLit(1); +//│ } +//│ return _mls_retval; +//│ } +//│ _mlsValue _mls_j3() { +//│ _mlsValue _mls_retval; +//│ _mls_retval = _mlsValue::create<_mls_Unit>(); +//│ return _mls_retval; +//│ } +//│ _mlsValue _mls_j5() { +//│ _mlsValue _mls_retval; +//│ _mls_retval = _mls_j2(); +//│ return _mls_retval; +//│ } +//│ _mlsValue _mls_j4() { +//│ _mlsValue _mls_retval; +//│ _mls_retval = _mls_j3(); +//│ return _mls_retval; +//│ } +//│ _mlsValue _mls_filter(_mlsValue _mls_f1, _mlsValue _mls_ls1) { +//│ _mlsValue _mls_retval; +//│ if (_mlsValue::isValueOf<_mls_Nil1>(_mls_ls1)) { +//│ auto _mls_x62 = _mlsValue::create<_mls_Nil1>(); +//│ _mls_retval = _mls_x62; +//│ } else { +//│ if (_mlsValue::isValueOf<_mls_Cons1>(_mls_ls1)) { +//│ auto _mls_x56 = _mlsValue::cast<_mls_Cons1>(_mls_ls1)->_mls_head; +//│ auto _mls_x57 = _mlsValue::cast<_mls_Cons1>(_mls_ls1)->_mls_tail; +//│ auto _mls_x58 = _mlsMethodCall<_mls_Callable>(_mls_f1)->_mls_apply1(_mls_x56); +//│ if (_mlsValue::isIntLit(_mls_x58, 1)) { +//│ auto _mls_x60 = _mls_filter(_mls_f1, _mls_x57); +//│ auto _mls_x61 = _mlsValue::create<_mls_Cons1>(_mls_x56, _mls_x60); +//│ _mls_retval = _mls_x61; +//│ } else { +//│ auto _mls_x59 = _mls_filter(_mls_f1, _mls_x57); +//│ _mls_retval = _mls_x59; +//│ } +//│ } else { +//│ throw std::runtime_error("match error"); +//│ } +//│ } +//│ return _mls_retval; +//│ } +//│ _mlsValue _mls_j6() { +//│ _mlsValue _mls_retval; +//│ _mls_retval = _mlsValue::create<_mls_Unit>(); +//│ return _mls_retval; +//│ } +//│ _mlsValue _mls_j7() { +//│ _mlsValue _mls_retval; +//│ _mls_retval = _mls_j4(); +//│ return _mls_retval; +//│ } +//│ _mlsValue _mls_j2() { +//│ _mlsValue _mls_retval; +//│ _mls_retval = _mlsValue::create<_mls_Unit>(); +//│ return _mls_retval; +//│ } +//│ _mlsValue _mls_nubBy(_mlsValue _mls_eq, _mlsValue _mls_ls) { +//│ _mlsValue _mls_retval; +//│ if (_mlsValue::isValueOf<_mls_Nil1>(_mls_ls)) { +//│ auto _mls_x55 = _mlsValue::create<_mls_Nil1>(); +//│ _mls_retval = _mls_x55; +//│ } else { +//│ if (_mlsValue::isValueOf<_mls_Cons1>(_mls_ls)) { +//│ auto _mls_x47 = _mlsValue::cast<_mls_Cons1>(_mls_ls)->_mls_head; +//│ auto _mls_x50 = _mlsValue::cast<_mls_Cons1>(_mls_ls)->_mls_tail; +//│ auto _mls_x51 = _mlsValue::create<_mls_Lambda5>(_mls_eq, _mls_x47); +//│ auto _mls_x52 = _mls_filter(_mls_x51, _mls_x50); +//│ auto _mls_x53 = _mls_nubBy(_mls_eq, _mls_x52); +//│ auto _mls_x54 = _mlsValue::create<_mls_Cons1>(_mls_x47, _mls_x53); +//│ _mls_retval = _mls_x54; +//│ } else { +//│ throw std::runtime_error("match error"); +//│ } +//│ } +//│ return _mls_retval; +//│ } +//│ _mlsValue _mls_Lambda6::_mls_apply2(_mlsValue _mls_x46, _mlsValue _mls_y2) { +//│ _mlsValue _mls_retval; +//│ auto _mls_x45 = (_mls_x46 == _mls_y2); +//│ _mls_retval = _mls_x45; +//│ return _mls_retval; +//│ } +//│ _mlsValue _mls_Lambda5::_mls_apply1(_mlsValue _mls_y3) { +//│ _mlsValue _mls_retval; +//│ auto _mls_x48 = _mlsMethodCall<_mls_Callable>(_mls_eq)->_mls_apply2(_mls_x, _mls_y3); +//│ auto _mls_x49 = _mls_not(_mls_x48); +//│ _mls_retval = _mls_x49; +//│ return _mls_retval; +//│ } +//│ _mlsValue _mlsMain() { +//│ _mlsValue _mls_retval; +//│ auto _mls_x63 = _mlsValue::create<_mls_Nil1>(); +//│ auto _mls_x64 = _mlsValue::create<_mls_Cons1>(_mlsValue::fromIntLit(3), _mls_x63); +//│ auto _mls_x65 = _mlsValue::create<_mls_Cons1>(_mlsValue::fromIntLit(3), _mls_x64); +//│ auto _mls_x66 = _mlsValue::create<_mls_Cons1>(_mlsValue::fromIntLit(2), _mls_x65); +//│ auto _mls_x67 = _mlsValue::create<_mls_Cons1>(_mlsValue::fromIntLit(1), _mls_x66); +//│ auto _mls_x68 = _mlsValue::create<_mls_Lambda6>(); +//│ auto _mls_x69 = _mls_nubBy(_mls_x68, _mls_x67); +//│ _mls_retval = _mls_x69; +//│ return _mls_retval; +//│ } +//│ int main() { return _mlsLargeStack(_mlsMainWrapper); } +//│ +//│ Interpreted: +//│ Cons(1,Cons(2,Cons(3,Nil()))) diff --git a/hkmc2/shared/src/test/mlscript/llir/NofibPrelude.mls b/hkmc2/shared/src/test/mlscript/llir/NofibPrelude.mls index 49801d6335..a06cde4f1c 100644 --- a/hkmc2/shared/src/test/mlscript/llir/NofibPrelude.mls +++ b/hkmc2/shared/src/test/mlscript/llir/NofibPrelude.mls @@ -50,21 +50,17 @@ fun while_(p, f, x) = if p(x) then while_(p, f, f(x)) else x fun reverse(l) = fun r(l', l) = if l is x :: xs then r(x :: l', xs) else l' r(Nil, l) -//│ ═══[COMPILATION ERROR] Non top-level definition r not supported -//│ Stopped due to an error during the Llir generation fun map(f, xs) = if xs is x :: xs then f(x) :: map(f, xs) Nil then Nil + fun listLen(ls) = fun l(ls, a) = if ls is Nil then a h :: t then l(t, a + 1) l(ls, 0) -//│ FAILURE: Unexpected compilation error -//│ ═══[COMPILATION ERROR] Non top-level definition l not supported -//│ Stopped due to an error during the Llir generation fun listEq(xs, ys) = if xs is Nil and ys is Nil then true @@ -196,9 +192,6 @@ fun sum(xs) = Nil then a h :: t then go(t, a + h) go(xs, 0) -//│ FAILURE: Unexpected compilation error -//│ ═══[COMPILATION ERROR] Non top-level definition go not supported -//│ Stopped due to an error during the Llir generation fun null_(ls) = if ls is Nil then true @@ -211,9 +204,6 @@ fun unzip(l) = Nil then [reverse(a), reverse(b)] [x, y] :: t then f(t, x :: a, y :: b) f(l, Nil, Nil) -//│ FAILURE: Unexpected compilation error -//│ ═══[COMPILATION ERROR] Non top-level definition f not supported -//│ Stopped due to an error during the Llir generation fun zip3(xs, ys, zs) = if xs is x :: xs and ys is y :: ys and zs is z :: zs then [x, y, z] :: zip3(xs, ys, zs) @@ -230,9 +220,6 @@ fun transpose(xss) = Nil then Nil Nil :: xss then transpose(xss) (x :: xs) :: xss and unzip(lscomp(xss)) is [hds, tls] then combine(x, hds, xs, tls) -//│ FAILURE: Unexpected compilation error -//│ ═══[COMPILATION ERROR] Non top-level definition lscomp not supported -//│ Stopped due to an error during the Llir generation fun break_(p, ls) = if ls is Nil then [Nil, Nil] @@ -243,4 +230,3 @@ fun break_(p, ls) = if ls is fun flatMap(f, ls) = if ls is Nil then Nil h :: t then append(f(h), flatMap(f, t)) - diff --git a/hkmc2/shared/src/test/mlscript/llir/Tuple.mls b/hkmc2/shared/src/test/mlscript/llir/Tuple.mls index 215a393903..be40d7b535 100644 --- a/hkmc2/shared/src/test/mlscript/llir/Tuple.mls +++ b/hkmc2/shared/src/test/mlscript/llir/Tuple.mls @@ -6,6 +6,7 @@ :intl :sllir +:scpp fun mkTup(x, y) = [x, y] fun fst(t) = if t is [x, y] then x mkTup(1, 2) @@ -28,5 +29,52 @@ mkTup(1, 2) //│ let* (x$219) = mkTup(1,2) in //│ x$219 //│ +//│ Cpp: +//│ #include "mlsprelude.h" +//│ struct _mls_Tuple2; +//│ _mlsValue _mls_mkTup(_mlsValue, _mlsValue); +//│ _mlsValue _mls_j(); +//│ _mlsValue _mls_fst(_mlsValue); +//│ _mlsValue _mlsMain(); +//│ struct _mls_Tuple2: public _mlsObject { +//│ _mlsValue _mls_field0; +//│ _mlsValue _mls_field1; +//│ constexpr static inline const char *typeName = "Tuple2"; +//│ constexpr static inline uint32_t typeTag = nextTypeTag(); +//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->_mls_field0.print(); std::printf(", "); this->_mls_field1.print(); std::printf(")"); } +//│ virtual void destroy() override { _mlsValue::destroy(this->_mls_field0); _mlsValue::destroy(this->_mls_field1); operator delete (this, std::align_val_t(_mlsAlignment)); } +//│ static _mlsValue create(_mlsValue _mls_field0, _mlsValue _mls_field1) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) _mls_Tuple2; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->_mls_field0 = _mls_field0; _mlsVal->_mls_field1 = _mls_field1; return _mlsValue(_mlsVal); } +//│ +//│ }; +//│ _mlsValue _mls_mkTup(_mlsValue _mls_x1, _mlsValue _mls_y) { +//│ _mlsValue _mls_retval; +//│ auto _mls_x = _mlsValue::create<_mls_Tuple2>(_mls_x1, _mls_y); +//│ _mls_retval = _mls_x; +//│ return _mls_retval; +//│ } +//│ _mlsValue _mls_j() { +//│ _mlsValue _mls_retval; +//│ _mls_retval = _mlsValue::create<_mls_Unit>(); +//│ return _mls_retval; +//│ } +//│ _mlsValue _mls_fst(_mlsValue _mls_t) { +//│ _mlsValue _mls_retval; +//│ if (_mlsValue::isValueOf<_mls_Tuple2>(_mls_t)) { +//│ auto _mls_x2 = _mlsValue::cast<_mls_Tuple2>(_mls_t)->_mls_field0; +//│ auto _mls_x3 = _mlsValue::cast<_mls_Tuple2>(_mls_t)->_mls_field1; +//│ _mls_retval = _mls_x2; +//│ } else { +//│ throw std::runtime_error("match error"); +//│ } +//│ return _mls_retval; +//│ } +//│ _mlsValue _mlsMain() { +//│ _mlsValue _mls_retval; +//│ auto _mls_x4 = _mls_mkTup(_mlsValue::fromIntLit(1), _mlsValue::fromIntLit(2)); +//│ _mls_retval = _mls_x4; +//│ return _mls_retval; +//│ } +//│ int main() { return _mlsLargeStack(_mlsMainWrapper); } +//│ //│ Interpreted: //│ Tuple2(1,2) From 66ad4c5db9a4b0bb2db2ca150530c8cf4d929b62 Mon Sep 17 00:00:00 2001 From: waterlens Date: Thu, 20 Feb 2025 21:15:03 +0800 Subject: [PATCH 44/88] Add builtin stuff --- .../scala/hkmc2/codegen/cpp/CodeGen.scala | 2 +- .../scala/hkmc2/codegen/llir/Builder.scala | 13 ++++++++ .../src/test/mlscript/llir/NofibPrelude.mls | 30 +++++++++++++++++-- 3 files changed, 42 insertions(+), 3 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/CodeGen.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/CodeGen.scala index 11530926d0..47b34f9a1a 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/CodeGen.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/CodeGen.scala @@ -234,7 +234,7 @@ class CppCodeGen(builtinClassSymbols: Set[Local], tl: TraceLogger): case Node.LetExpr(name, expr, body) => val stmts2 = stmts ++ Ls(Stmt.AutoBind(Ls(name |> allocIfNew), codegen(expr))) codegen(body, storeInto)(using decls, stmts2) - case Node.LetMethodCall(names, cls, method, IExpr.Ref(bin: BuiltinSymbol) :: args, body) if bin.nme == "" => + case Node.LetCall(names, bin: BuiltinSymbol, args, body) if bin.nme == "" => val stmts2 = stmts ++ codegenBuiltin(names, args.head.toString.replace("\"", ""), args.tail) codegen(body, storeInto)(using decls, stmts2) case Node.LetMethodCall(names, cls, method, IExpr.Ref(bin: BuiltinSymbol) :: args, body) if bin.nme == "" => diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala index e84a68f6fa..3efe2cd345 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala @@ -30,6 +30,7 @@ final case class FuncInfo(paramsSize: Int) final case class BuiltinSymbols( var callableSym: Opt[Local] = None, var thisSym: Opt[Local] = None, + var builtinSym: Opt[Local] = None, fieldSym: MutMap[Int, Local] = MutMap.empty, applySym: MutMap[Int, Local] = MutMap.empty, tupleSym: MutMap[Int, Local] = MutMap.empty, @@ -132,6 +133,13 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger, uid: FreshInt): ctx.builtin_sym.thisSym = Some(sym); sym case Some(value) => value + private def builtin(using ctx: Ctx) : Local = + ctx.builtin_sym.thisSym match + case None => + val sym = newBuiltinSym("") + ctx.builtin_sym.builtinSym = Some(sym); + sym + case Some(value) => value private def bBind(name: Opt[Local], e: Result, body: Block)(k: TrivialExpr => Ctx ?=> Node)(ct: Block)(using ctx: Ctx)(using Raise, Scope): Node = trace[Node](s"bBind begin: $name", x => s"bBind end: ${x.show}"): @@ -380,6 +388,11 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger, uid: FreshInt): bArgs(args): case args: Ls[TrivialExpr] => Node.LetMethodCall(Ls(v), builtinCallable, builtinApply(args.length), f :: args, k(v |> sr)) + case Call(Select(Value.Ref(sym: TopLevelSymbol), Tree.Ident("builtin")), args) => + bArgs(args): + case args: Ls[TrivialExpr] => + val v: Local = newTemp + Node.LetCall(Ls(v), builtin, args, k(v |> sr)) case Call(s @ Select(r @ Value.Ref(sym), Tree.Ident(fld)), args) if s.symbol.isDefined => bPath(r): case r => diff --git a/hkmc2/shared/src/test/mlscript/llir/NofibPrelude.mls b/hkmc2/shared/src/test/mlscript/llir/NofibPrelude.mls index a06cde4f1c..bdb0c72feb 100644 --- a/hkmc2/shared/src/test/mlscript/llir/NofibPrelude.mls +++ b/hkmc2/shared/src/test/mlscript/llir/NofibPrelude.mls @@ -41,12 +41,27 @@ fun until(p, f, i) = if p(i) then i else until(p, f, f(i)) fun flip(f, x, y) = f(y)(x) +fun power(a, n) = globalThis.builtin("pow", a, n) + +fun intDiv(a, b) = globalThis.builtin("floor_div", a, b) +fun intQuot(a, b) = a / b + +fun intMod(a, b) = a - (b * intDiv(a, b)) +fun intRem(a, b) = a - (b * intQuot(a, b)) + +fun quotRem(a, b) = [intQuot(a, b), intRem(a, b)] +fun divMod(a, b) = [intDiv(a, b), intMod(a, b)] + +fun max(a, b) = if a > b then a else b +fun min(a, b) = if a < b then a else b + +fun abs(x) = if x < 0 then -x else x + fun head(l) = if l is h :: t then h fun tail(l) = if l is h :: t then t fun while_(p, f, x) = if p(x) then while_(p, f, f(x)) else x -:todo fun reverse(l) = fun r(l', l) = if l is x :: xs then r(x :: l', xs) else l' r(Nil, l) @@ -55,7 +70,6 @@ fun map(f, xs) = if xs is x :: xs then f(x) :: map(f, xs) Nil then Nil - fun listLen(ls) = fun l(ls, a) = if ls is Nil then a @@ -230,3 +244,15 @@ fun break_(p, ls) = if ls is fun flatMap(f, ls) = if ls is Nil then Nil h :: t then append(f(h), flatMap(f, t)) + +fun stringOfInt(x) = globalThis.builtin("string_of_int", x) +fun stringConcat(x, y) = globalThis.builtin("str_concat", x, y) +fun stringListConcat(ls) = if ls is + Nil then "" + h :: t then stringConcat(h, stringListConcat(t)) +fun sqrt(x) = globalThis.builtin("sqrt", x) +fun tan(x) = globalThis.builtin("tan", x) +fun sin(x) = globalThis.builtin("sin", x) +fun cos(x) = globalThis.builtin("cos", x) +fun round(x) = globalThis.builtin("round", x) +fun int_of_char(x) = globalThis.builtin("int_of_char", x) From cb238d5032a294ea0381aac4bf823eef5d55baa5 Mon Sep 17 00:00:00 2001 From: waterlens Date: Mon, 24 Feb 2025 20:40:09 +0800 Subject: [PATCH 45/88] Math builtins; String and Lazy support in Cpp backend --- .../scala/hkmc2/codegen/cpp/CodeGen.scala | 7 +- .../scala/hkmc2/codegen/llir/Builder.scala | 18 +- .../main/scala/hkmc2/codegen/llir/Llir.scala | 3 +- .../mlscript-compile/cpp/compile_flags.txt | 4 +- .../test/mlscript-compile/cpp/mlsprelude.h | 223 ++++++++++-- .../src/test/mlscript/decls/Prelude.mls | 14 +- .../src/test/mlscript/llir/BasicCpp.mls | 24 +- .../shared/src/test/mlscript/llir/Classes.mls | 20 +- .../src/test/mlscript/llir/ControlFlow.mls | 272 +++++++-------- hkmc2/shared/src/test/mlscript/llir/Ctor.mls | 26 +- .../src/test/mlscript/llir/HigherOrder.mls | 326 +++++++++--------- hkmc2/shared/src/test/mlscript/llir/Lazy.mls | 116 +++++++ .../shared/src/test/mlscript/llir/Legacy.mls | 100 +++--- .../shared/src/test/mlscript/llir/Method.mls | 18 +- .../src/test/mlscript/llir/NofibPrelude.mls | 51 +-- hkmc2/shared/src/test/mlscript/llir/Tuple.mls | 24 +- .../src/test/scala/hkmc2/LlirDiffMaker.scala | 2 +- 17 files changed, 778 insertions(+), 470 deletions(-) create mode 100644 hkmc2/shared/src/test/mlscript/llir/Lazy.mls diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/CodeGen.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/CodeGen.scala index 47b34f9a1a..a0fe2f1ba1 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/CodeGen.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/CodeGen.scala @@ -10,6 +10,7 @@ import hkmc2.codegen.Local import hkmc2.utils.{Scope, TraceLogger} import hkmc2.Raise import hkmc2.semantics.BuiltinSymbol +import hkmc2.escaped class CppCodeGen(builtinClassSymbols: Set[Local], tl: TraceLogger): import tl.{trace, log, logs} @@ -26,13 +27,13 @@ class CppCodeGen(builtinClassSymbols: Set[Local], tl: TraceLogger): val mlsMainName = "_mlsMain" val mlsPrelude = "#include \"mlsprelude.h\"" val mlsPreludeImpl = "#include \"mlsprelude.cpp\"" - def mlsIsInternalClass(sym: Local) = - sym.nme.startsWith("Callable") + val builtinClassSymbolNames = Set("Callable", "Lazy") + def mlsIsInternalClass(sym: Local) = builtinClassSymbolNames.contains(sym.nme) val mlsObject = "_mlsObject" val mlsBuiltin = "builtin" val mlsEntryPoint = s"int main() { return _mlsLargeStack(_mlsMainWrapper); }"; def mlsIntLit(x: BigInt) = Expr.Call(Expr.Var("_mlsValue::fromIntLit"), Ls(Expr.IntLit(x))) - def mlsStrLit(x: Str) = Expr.Call(Expr.Var("_mlsValue::fromStrLit"), Ls(Expr.StrLit(x))) + def mlsStrLit(x: Str) = Expr.Call(Expr.Var("_mlsValue::create<_mls_Str>"), Ls(Expr.StrLit(x))) def mlsCharLit(x: Char) = Expr.Call(Expr.Var("_mlsValue::fromIntLit"), Ls(Expr.CharLit(x))) def mlsNewValue(cls: Str, args: Ls[Expr]) = Expr.Call(Expr.Var(s"_mlsValue::create<$cls>"), args) def mlsIsValueOf(cls: Str, scrut: Expr) = Expr.Call(Expr.Var(s"_mlsValue::isValueOf<$cls>"), Ls(scrut)) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala index 3efe2cd345..162cb72a1a 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala @@ -15,6 +15,7 @@ import hkmc2.syntax.Tree import hkmc2.semantics.* import hkmc2.codegen.llir.{ Program => LlirProgram, Node, Func } import hkmc2.codegen.Program +import hkmc2.codegen.cpp.Expr.StrLit def err(msg: Message)(using Raise): Unit = @@ -34,7 +35,8 @@ final case class BuiltinSymbols( fieldSym: MutMap[Int, Local] = MutMap.empty, applySym: MutMap[Int, Local] = MutMap.empty, tupleSym: MutMap[Int, Local] = MutMap.empty, -) +): + def hiddenClasses = callableSym.toSet final case class Ctx( def_acc: ListBuffer[Func], @@ -134,7 +136,7 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger, uid: FreshInt): sym case Some(value) => value private def builtin(using ctx: Ctx) : Local = - ctx.builtin_sym.thisSym match + ctx.builtin_sym.builtinSym match case None => val sym = newBuiltinSym("") ctx.builtin_sym.builtinSym = Some(sym); @@ -388,11 +390,21 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger, uid: FreshInt): bArgs(args): case args: Ls[TrivialExpr] => Node.LetMethodCall(Ls(v), builtinCallable, builtinApply(args.length), f :: args, k(v |> sr)) - case Call(Select(Value.Ref(sym: TopLevelSymbol), Tree.Ident("builtin")), args) => + case Call(Select(Value.Ref(_: TopLevelSymbol), Tree.Ident("builtin")), args) => bArgs(args): case args: Ls[TrivialExpr] => val v: Local = newTemp Node.LetCall(Ls(v), builtin, args, k(v |> sr)) + case Call(Select(Select(Value.Ref(_: TopLevelSymbol), Tree.Ident("console")), Tree.Ident("log")), args) => + bArgs(args): + case args: Ls[TrivialExpr] => + val v: Local = newTemp + Node.LetCall(Ls(v), builtin, Expr.Literal(Tree.StrLit("println")) :: args, k(v |> sr)) + case Call(Select(Select(Value.Ref(_: TopLevelSymbol), Tree.Ident("Math")), Tree.Ident(mathPrimitive)), args) => + bArgs(args): + case args: Ls[TrivialExpr] => + val v: Local = newTemp + Node.LetCall(Ls(v), builtin, Expr.Literal(Tree.StrLit(mathPrimitive)) :: args, k(v |> sr)) case Call(s @ Select(r @ Value.Ref(sym), Tree.Ident(fld)), args) if s.symbol.isDefined => bPath(r): case r => diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Llir.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Llir.scala index 2a8a9b0a84..9780f28ced 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Llir.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Llir.scala @@ -13,6 +13,7 @@ import util.Sorting import collection.immutable.SortedSet import language.implicitConversions import collection.mutable.{Map as MutMap, Set as MutSet, HashMap, ListBuffer} +import hkmc2.escaped private def raw(x: String): Document = doc"$x" @@ -136,7 +137,7 @@ enum Expr: case Literal(Tree.BoolLit(lit)) => s"$lit" case Literal(Tree.IntLit(lit)) => s"$lit" case Literal(Tree.DecLit(lit)) => s"$lit" - case Literal(Tree.StrLit(lit)) => s"$lit" + case Literal(Tree.StrLit(lit)) => s"${lit.escaped}" case Literal(Tree.UnitLit(undefinedOrNull)) => if undefinedOrNull then "undefined" else "null" case CtorApp(cls, args) => doc"${docSymWithUid(cls)}(${args.map(_.toString).mkString(",")})" diff --git a/hkmc2/shared/src/test/mlscript-compile/cpp/compile_flags.txt b/hkmc2/shared/src/test/mlscript-compile/cpp/compile_flags.txt index a5a7cabbdf..3b6e59f935 100644 --- a/hkmc2/shared/src/test/mlscript-compile/cpp/compile_flags.txt +++ b/hkmc2/shared/src/test/mlscript-compile/cpp/compile_flags.txt @@ -1,8 +1,8 @@ -O --Wall --Wextra +-Wall -std=c++20 -I. -Wno-inconsistent-missing-override -I/opt/homebrew/include -L/opt/homebrew/lib +-xc++ diff --git a/hkmc2/shared/src/test/mlscript-compile/cpp/mlsprelude.h b/hkmc2/shared/src/test/mlscript-compile/cpp/mlsprelude.h index d84ac89b9e..7e1e4a4a38 100644 --- a/hkmc2/shared/src/test/mlscript-compile/cpp/mlsprelude.h +++ b/hkmc2/shared/src/test/mlscript-compile/cpp/mlsprelude.h @@ -8,7 +8,7 @@ #include #include #include -#include +#include #include constexpr std::size_t _mlsAlignment = 8; @@ -67,9 +67,18 @@ struct _mlsObject { virtual void destroy() = 0; }; +class _mlsUtil { +public: + [[noreturn]] static void panic(const char *msg) { + std::fprintf(stderr, "Panic: %s\n", msg); + std::abort(); + } +}; + class _mlsValue { using uintptr_t = std::uintptr_t; - using uint64_t = std::uint64_t; + using intptr_t = std::intptr_t; + using int64_t = std::int64_t; void *value alignas(_mlsAlignment); @@ -77,7 +86,7 @@ class _mlsValue { bool isPtr() const { return (reinterpret_cast(value) & 1) == 0; } - uint64_t asInt63() const { return reinterpret_cast(value) >> 1; } + int64_t asInt63() const { return reinterpret_cast(value) >> 1; } uintptr_t asRawInt() const { return reinterpret_cast(value); } @@ -85,7 +94,7 @@ class _mlsValue { return _mlsValue(reinterpret_cast(i)); } - static _mlsValue fromInt63(uint64_t i) { + static _mlsValue fromInt63(int64_t i) { return _mlsValue(reinterpret_cast((i << 1) | 1)); } @@ -119,20 +128,60 @@ class _mlsValue { return fromInt63(asInt63() / other.asInt63()); } + _mlsValue modInt63(const _mlsValue &other) const { + return fromInt63(asInt63() % other.asInt63()); + } + _mlsValue gtInt63(const _mlsValue &other) const { - return _mlsValue::fromBoolLit(asInt63() > other.asInt63()); + return fromBoolLit(asInt63() > other.asInt63()); } _mlsValue ltInt63(const _mlsValue &other) const { - return _mlsValue::fromBoolLit(asInt63() < other.asInt63()); + return fromBoolLit(asInt63() < other.asInt63()); } _mlsValue geInt63(const _mlsValue &other) const { - return _mlsValue::fromBoolLit(asInt63() >= other.asInt63()); + return fromBoolLit(asInt63() >= other.asInt63()); } _mlsValue leInt63(const _mlsValue &other) const { - return _mlsValue::fromBoolLit(asInt63() <= other.asInt63()); + return fromBoolLit(asInt63() <= other.asInt63()); + } + + _mlsValue minInt63(const _mlsValue &other) const { + int64_t a = asInt63(); + int64_t b = other.asInt63(); + return fromInt63(a < b ? a : b); + } + + _mlsValue maxInt63(const _mlsValue &other) const { + int64_t a = asInt63(); + int64_t b = other.asInt63(); + return fromInt63(a > b ? a : b); + } + + _mlsValue absInt63() const { + int64_t a = asInt63(); + return fromInt63(a < 0 ? -a : a); + } + + _mlsValue floorDivInt63(const _mlsValue &other) const { + int64_t a = asInt63(); + int64_t b = other.asInt63(); + int64_t q = a / b; + int64_t r = a % b; + if ((r > 0 && b < 0) || (r < 0 && b > 0)) + q = q - 1; + return fromInt63(q); + } + + _mlsValue floorModInt63(const _mlsValue &other) const { + int64_t a = asInt63(); + int64_t b = other.asInt63(); + long r = a % b; + if ((r > 0 && b < 0) || (r < 0 && b > 0)) + r = r + b; + return fromInt63(r); } public: @@ -160,12 +209,12 @@ class _mlsValue { } } - uint64_t asInt() const { + int64_t asInt() const { assert(isInt63()); return asInt63(); } - static _mlsValue fromIntLit(uint64_t i) { return fromInt63(i); } + static _mlsValue fromIntLit(int64_t i) { return fromInt63(i); } static _mlsValue fromBoolLit(bool b) { return fromInt63(b); } @@ -184,11 +233,11 @@ class _mlsValue { return v.asObject()->tag == T::typeTag; } - static bool isIntLit(const _mlsValue &v, uint64_t n) { + static bool isIntLit(const _mlsValue &v, int64_t n) { return v.asInt63() == n; } - static bool isIntLit(const _mlsValue &v) { return v.isInt63(); } + static bool isInt(const _mlsValue &v) { return v.isInt63(); } template static T *as(const _mlsValue &v) { return dynamic_cast(v.asObject()); @@ -198,78 +247,102 @@ class _mlsValue { return static_cast(v.asObject()); } + _mlsValue floorDiv(const _mlsValue &other) const { + if (isInt63() && other.isInt63()) + return floorDivInt63(other); + _mlsUtil::panic("incorrect type"); + } + + _mlsValue floorMod(const _mlsValue &other) const { + if (isInt63() && other.isInt63()) + return floorModInt63(other); + _mlsUtil::panic("incorrect type"); + } + + _mlsValue pow(const _mlsValue &other) const { + if (isInt63() && other.isInt63()) + return fromInt63(std::pow(asInt63(), other.asInt63())); + _mlsUtil::panic("incorrect type"); + } + // Operators _mlsValue operator==(const _mlsValue &other) const { if (isInt63() && other.isInt63()) return _mlsValue::fromBoolLit(eqInt63(other)); - assert(false); + _mlsUtil::panic("incorrect type"); } _mlsValue operator!=(const _mlsValue &other) const { if (isInt63() && other.isInt63()) return _mlsValue::fromBoolLit(!eqInt63(other)); - assert(false); + _mlsUtil::panic("incorrect type"); } _mlsValue operator&&(const _mlsValue &other) const { if (isInt63() && other.isInt63()) return _mlsValue::fromBoolLit(asInt63() && other.asInt63()); - assert(false); + _mlsUtil::panic("incorrect type"); } _mlsValue operator||(const _mlsValue &other) const { if (isInt63() && other.isInt63()) return _mlsValue::fromBoolLit(asInt63() || other.asInt63()); - assert(false); + _mlsUtil::panic("incorrect type"); } _mlsValue operator+(const _mlsValue &other) const { if (isInt63() && other.isInt63()) return addInt63(other); - assert(false); + _mlsUtil::panic("incorrect type"); } _mlsValue operator-(const _mlsValue &other) const { if (isInt63() && other.isInt63()) return subInt63(other); - assert(false); + _mlsUtil::panic("incorrect type"); } _mlsValue operator*(const _mlsValue &other) const { if (isInt63() && other.isInt63()) return mulInt63(other); - assert(false); + _mlsUtil::panic("incorrect type"); } _mlsValue operator/(const _mlsValue &other) const { if (isInt63() && other.isInt63()) return divInt63(other); - assert(false); + _mlsUtil::panic("incorrect type"); + } + + _mlsValue operator%(const _mlsValue &other) const { + if (isInt63() && other.isInt63()) + return modInt63(other); + _mlsUtil::panic("incorrect type"); } _mlsValue operator>(const _mlsValue &other) const { if (isInt63() && other.isInt63()) return gtInt63(other); - assert(false); + _mlsUtil::panic("incorrect type"); } _mlsValue operator<(const _mlsValue &other) const { if (isInt63() && other.isInt63()) return ltInt63(other); - assert(false); + _mlsUtil::panic("incorrect type"); } _mlsValue operator>=(const _mlsValue &other) const { if (isInt63() && other.isInt63()) return geInt63(other); - assert(false); + _mlsUtil::panic("incorrect type"); } _mlsValue operator<=(const _mlsValue &other) const { if (isInt63() && other.isInt63()) return leInt63(other); - assert(false); + _mlsUtil::panic("incorrect type"); } // Auxiliary functions @@ -283,7 +356,9 @@ class _mlsValue { }; struct _mls_Callable : public _mlsObject { - virtual _mlsValue _mls_apply0() { throw std::runtime_error("Not implemented"); } + virtual _mlsValue _mls_apply0() { + throw std::runtime_error("Not implemented"); + } virtual _mlsValue _mls_apply1(_mlsValue) { throw std::runtime_error("Not implemented"); } @@ -321,8 +396,7 @@ inline static _mlsValue _mlsCall(_mlsValue f, U... args) { return _mlsToCallable(f)->_mls_apply4(args...); } -template -inline static T *_mlsMethodCall(_mlsValue self) { +template inline static T *_mlsMethodCall(_mlsValue self) { auto *ptr = _mlsValue::as(self); if (!ptr) throw std::runtime_error("unable to convert object for method calls"); @@ -367,6 +441,59 @@ struct _mls_Unit final : public _mlsObject { virtual void destroy() override {} }; +struct _mls_Str final : public _mlsObject { + std::string str; + constexpr static inline const char *typeName = "Str"; + constexpr static inline uint32_t typeTag = nextTypeTag(); + virtual void print() const override { + std::printf(typeName); + std::printf("("); + std::printf("%s", str.c_str()); + std::printf(")"); + } + static _mlsValue create(const char *str) { + auto _mlsVal = new (std::align_val_t(_mlsAlignment)) _mls_Str; + _mlsVal->str = str; + _mlsVal->refCount = 1; + _mlsVal->tag = typeTag; + return _mlsValue(_mlsVal); + } + virtual void destroy() override { + str.~basic_string(); + operator delete(this, std::align_val_t(_mlsAlignment)); + } +}; + +struct _mls_Lazy final : public _mlsObject { + _mlsValue init; + _mlsValue value; + bool evaluated; + constexpr static inline const char *typeName = "Lazy"; + constexpr static inline uint32_t typeTag = nextTypeTag(); + virtual void print() const override { std::printf(typeName); } + static _mlsValue create(_mlsValue init) { + auto _mlsVal = new (std::align_val_t(_mlsAlignment)) _mls_Lazy; + _mlsVal->refCount = 1; + _mlsVal->tag = typeTag; + _mlsVal->init = init; + _mlsVal->value = _mlsValue::create<_mls_Unit>(); + _mlsVal->evaluated = false; + return _mlsValue(_mlsVal); + } + virtual void destroy() override { + _mlsValue::destroy(init); + _mlsValue::destroy(value); + operator delete(this, std::align_val_t(_mlsAlignment)); + } + _mlsValue _mls_get() { + if (!evaluated) { + value = _mlsCall(init); + evaluated = true; + } + return value; + } +}; + #include struct _mls_ZInt final : public _mlsObject { @@ -386,7 +513,7 @@ struct _mls_ZInt final : public _mlsObject { static _mlsValue create() { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) _mls_ZInt; _mlsVal->refCount = 1; - _mlsVal->tag = typeTag; + _mlsVal->tag = typeTag; return _mlsValue(_mlsVal); } static _mlsValue create(_mlsValue z) { @@ -447,16 +574,46 @@ struct _mls_ZInt final : public _mlsObject { } _mlsValue toInt() const { - return _mlsValue::fromIntLit(z.convert_to()); + return _mlsValue::fromIntLit(z.convert_to()); } - static _mlsValue fromInt(uint64_t i) { + static _mlsValue fromInt(int64_t i) { return _mlsValue::create<_mls_ZInt>(_mlsValue::fromIntLit(i)); } }; -__attribute__((noinline)) inline void _mlsNonExhaustiveMatch() { - throw std::runtime_error("Non-exhaustive match"); +[[noreturn, gnu::noinline]] inline void _mlsNonExhaustiveMatch() { + _mlsUtil::panic("Non-exhaustive match"); +} + +inline _mlsValue _mls_builtin_pow(_mlsValue a, _mlsValue b) { + assert(_mlsValue::isInt(a)); + assert(_mlsValue::isInt(b)); + return a.pow(b); +} + +inline _mlsValue _mls_builtin_floor_div(_mlsValue a, _mlsValue b) { + assert(_mlsValue::isInt(a)); + assert(_mlsValue::isInt(b)); + return a.floorDiv(b); +} + +inline _mlsValue _mls_builtin_floor_mod(_mlsValue a, _mlsValue b) { + assert(_mlsValue::isInt(a)); + assert(_mlsValue::isInt(b)); + return a.floorMod(b); +} + +inline _mlsValue _mls_builtin_trunc_div(_mlsValue a, _mlsValue b) { + assert(_mlsValue::isInt(a)); + assert(_mlsValue::isInt(b)); + return a / b; +} + +inline _mlsValue _mls_builtin_trunc_mod(_mlsValue a, _mlsValue b) { + assert(_mlsValue::isInt(a)); + assert(_mlsValue::isInt(b)); + return a % b; } inline _mlsValue _mls_builtin_z_add(_mlsValue a, _mlsValue b) { @@ -525,7 +682,7 @@ inline _mlsValue _mls_builtin_z_to_int(_mlsValue a) { } inline _mlsValue _mls_builtin_z_of_int(_mlsValue a) { - assert(_mlsValue::isIntLit(a)); + assert(_mlsValue::isInt(a)); return _mlsValue::create<_mls_ZInt>(a); } diff --git a/hkmc2/shared/src/test/mlscript/decls/Prelude.mls b/hkmc2/shared/src/test/mlscript/decls/Prelude.mls index 9d49be4914..e0ea52bc5f 100644 --- a/hkmc2/shared/src/test/mlscript/decls/Prelude.mls +++ b/hkmc2/shared/src/test/mlscript/decls/Prelude.mls @@ -26,8 +26,18 @@ declare class Str with declare class String declare class RegExp -// declare module Math // TODO: list members -declare val Math // so we can, eg, `open { pow }` in the meantime +declare module Math with + // TODO: add more functions + fun abs: Num -> Num + fun sqrt: Num -> Num + fun sin: Num -> Num + fun cos: Num -> Num + fun tan: Num -> Num + fun pow: Num -> Num + fun round: Num -> Num + fun trunc: Num -> Num + fun min: (Num, Num) -> Num + fun max: (Num, Num) -> Num declare val console declare val process diff --git a/hkmc2/shared/src/test/mlscript/llir/BasicCpp.mls b/hkmc2/shared/src/test/mlscript/llir/BasicCpp.mls index ea79b1f6d0..857ac1d5e6 100644 --- a/hkmc2/shared/src/test/mlscript/llir/BasicCpp.mls +++ b/hkmc2/shared/src/test/mlscript/llir/BasicCpp.mls @@ -11,20 +11,20 @@ fun foo(a) = x + 1 //│ LLIR: //│ -//│ def foo$195(a$196) = -//│ let x$203 = null in -//│ let x$204 = >(a$196,0) in -//│ case x$204 of +//│ def foo$216(a$217) = +//│ let x$224 = null in +//│ let x$225 = >(a$217,0) in +//│ case x$225 of //│ BoolLit(true) => -//│ let x$206 = 1 in -//│ let x$207 = undefined in -//│ jump j$205(x$206) +//│ let x$227 = 1 in +//│ let x$228 = undefined in +//│ jump j$226(x$227) //│ _ => -//│ let x$208 = undefined in -//│ jump j$205(x$203) -//│ def j$205(x$197) = -//│ let x$209 = +(x$197,1) in -//│ x$209 +//│ let x$229 = undefined in +//│ jump j$226(x$224) +//│ def j$226(x$218) = +//│ let x$230 = +(x$218,1) in +//│ x$230 //│ undefined :showWholeCpp diff --git a/hkmc2/shared/src/test/mlscript/llir/Classes.mls b/hkmc2/shared/src/test/mlscript/llir/Classes.mls index 8a56cbb9be..4bbbd2e105 100644 --- a/hkmc2/shared/src/test/mlscript/llir/Classes.mls +++ b/hkmc2/shared/src/test/mlscript/llir/Classes.mls @@ -26,21 +26,21 @@ fun main() = main() //│ LLIR: //│ class Base() { -//│ def get$225() = +//│ def get$246() = //│ 1 //│ } //│ class Derived() extends Base { -//│ def get$226() = +//│ def get$247() = //│ 2 //│ } -//│ def main$228() = -//│ let x$250 = Derived$233() in -//│ let x$251 = Base.get$225(x$250) in -//│ let x$252 = Derived.get$226(x$250) in -//│ let x$253 = *(x$251,x$252) in -//│ x$253 -//│ let* (x$254) = main() in -//│ x$254 +//│ def main$249() = +//│ let x$271 = Derived$254() in +//│ let x$272 = Base.get$246(x$271) in +//│ let x$273 = Derived.get$247(x$271) in +//│ let x$274 = *(x$272,x$273) in +//│ x$274 +//│ let* (x$275) = main() in +//│ x$275 //│ //│ Interpreted: //│ 4 diff --git a/hkmc2/shared/src/test/mlscript/llir/ControlFlow.mls b/hkmc2/shared/src/test/mlscript/llir/ControlFlow.mls index a4737e982d..2b3bff9e11 100644 --- a/hkmc2/shared/src/test/mlscript/llir/ControlFlow.mls +++ b/hkmc2/shared/src/test/mlscript/llir/ControlFlow.mls @@ -14,12 +14,12 @@ f1() //│ = 2 //│ LLIR: //│ -//│ def f1$197() = -//│ let x$206 = 1 in -//│ let x$207 = 2 in -//│ x$207 -//│ let* (x$208) = f1() in -//│ x$208 +//│ def f1$218() = +//│ let x$227 = 1 in +//│ let x$228 = 2 in +//│ x$228 +//│ let* (x$229) = f1() in +//│ x$229 //│ //│ Interpreted: //│ 2 @@ -33,18 +33,18 @@ f2() //│ = 3 //│ LLIR: //│ -//│ def f2$209() = -//│ let x$219 = 0 in -//│ let x$220 = ==(x$219,1) in -//│ case x$220 of +//│ def f2$230() = +//│ let x$240 = 0 in +//│ let x$241 = ==(x$240,1) in +//│ case x$241 of //│ BoolLit(true) => //│ 2 //│ _ => //│ 3 -//│ def j$221() = +//│ def j$242() = //│ null -//│ let* (x$222) = f2() in -//│ x$222 +//│ let* (x$243) = f2() in +//│ x$243 //│ //│ Interpreted: //│ 3 @@ -59,19 +59,19 @@ f3() //│ = 0 //│ LLIR: //│ -//│ def f3$223() = -//│ let x$233 = 0 in -//│ let x$234 = 1 in -//│ let x$235 = true in -//│ case x$235 of +//│ def f3$244() = +//│ let x$254 = 0 in +//│ let x$255 = 1 in +//│ let x$256 = true in +//│ case x$256 of //│ BoolLit(true) => -//│ x$233 +//│ x$254 //│ _ => -//│ x$234 -//│ def j$236() = +//│ x$255 +//│ def j$257() = //│ null -//│ let* (x$237) = f3() in -//│ x$237 +//│ let* (x$258) = f3() in +//│ x$258 :sllir @@ -84,20 +84,20 @@ f4() //│ = 3 //│ LLIR: //│ -//│ def f4$238() = -//│ let x$251 = 0 in -//│ let x$252 = ==(x$251,1) in -//│ case x$252 of +//│ def f4$259() = +//│ let x$272 = 0 in +//│ let x$273 = ==(x$272,1) in +//│ case x$273 of //│ BoolLit(true) => -//│ let x$254 = 2 in -//│ jump j$253(x$254) +//│ let x$275 = 2 in +//│ jump j$274(x$275) //│ _ => -//│ let x$255 = 3 in -//│ jump j$253(x$255) -//│ def j$253(tmp$249) = -//│ tmp$249 -//│ let* (x$256) = f4() in -//│ x$256 +//│ let x$276 = 3 in +//│ jump j$274(x$276) +//│ def j$274(tmp$270) = +//│ tmp$270 +//│ let* (x$277) = f4() in +//│ x$277 //│ //│ Interpreted: //│ 3 @@ -113,29 +113,29 @@ f5() //│ = 5 //│ LLIR: //│ -//│ def f5$257() = -//│ let x$275 = 0 in -//│ let x$276 = ==(x$275,1) in -//│ case x$276 of +//│ def f5$278() = +//│ let x$296 = 0 in +//│ let x$297 = ==(x$296,1) in +//│ case x$297 of //│ BoolLit(true) => -//│ let x$278 = 2 in -//│ jump j$277(x$278) +//│ let x$299 = 2 in +//│ jump j$298(x$299) //│ _ => -//│ let x$279 = 3 in -//│ jump j$277(x$279) -//│ def j$277(tmp$272) = -//│ let x$280 = ==(tmp$272,2) in -//│ case x$280 of +//│ let x$300 = 3 in +//│ jump j$298(x$300) +//│ def j$298(tmp$293) = +//│ let x$301 = ==(tmp$293,2) in +//│ case x$301 of //│ BoolLit(true) => -//│ let x$282 = 4 in -//│ jump j$281(x$282) +//│ let x$303 = 4 in +//│ jump j$302(x$303) //│ _ => -//│ let x$283 = 5 in -//│ jump j$281(x$283) -//│ def j$281(tmp$273) = -//│ tmp$273 -//│ let* (x$284) = f5() in -//│ x$284 +//│ let x$304 = 5 in +//│ jump j$302(x$304) +//│ def j$302(tmp$294) = +//│ tmp$294 +//│ let* (x$305) = f5() in +//│ x$305 //│ //│ Interpreted: //│ 5 @@ -146,15 +146,15 @@ fun test() = if true do test() //│ LLIR: //│ -//│ def test$285() = -//│ let x$293 = true in -//│ case x$293 of +//│ def test$306() = +//│ let x$314 = true in +//│ case x$314 of //│ BoolLit(true) => -//│ let* (x$295) = test() in -//│ x$295 +//│ let* (x$316) = test() in +//│ x$316 //│ _ => //│ undefined -//│ def j$294() = +//│ def j$315() = //│ null //│ undefined //│ @@ -192,17 +192,17 @@ fun test() = (if true then test()) + 1 //│ LLIR: //│ -//│ def test$296() = -//│ let x$307 = true in -//│ case x$307 of +//│ def test$317() = +//│ let x$328 = true in +//│ case x$328 of //│ BoolLit(true) => -//│ let* (x$309) = test() in -//│ jump j$308(x$309) +//│ let* (x$330) = test() in +//│ jump j$329(x$330) //│ _ => //│ panic "match error" -//│ def j$308(tmp$306) = -//│ let x$310 = +(tmp$306,1) in -//│ x$310 +//│ def j$329(tmp$327) = +//│ let x$331 = +(tmp$327,1) in +//│ x$331 //│ undefined //│ //│ Cpp: @@ -247,21 +247,21 @@ f() //│ = 11 //│ LLIR: //│ -//│ def f$311() = -//│ let x$325 = 10 in -//│ let x$326 = true in -//│ case x$326 of +//│ def f$332() = +//│ let x$346 = 10 in +//│ let x$347 = true in +//│ case x$347 of //│ BoolLit(true) => -//│ let x$328 = +(x$325,1) in -//│ let x$329 = undefined in -//│ jump j$327(x$328) +//│ let x$349 = +(x$346,1) in +//│ let x$350 = undefined in +//│ jump j$348(x$349) //│ _ => -//│ let x$330 = undefined in -//│ jump j$327(x$325) -//│ def j$327(x$312) = -//│ x$312 -//│ let* (x$331) = f() in -//│ x$331 +//│ let x$351 = undefined in +//│ jump j$348(x$346) +//│ def j$348(x$333) = +//│ x$333 +//│ let* (x$352) = f() in +//│ x$352 //│ //│ Cpp: //│ #include "mlsprelude.h" @@ -310,29 +310,29 @@ fun f(a) = f(A(1)) //│ = 1 //│ LLIR: -//│ class A(x$337) -//│ class B(y$340) -//│ def f$334(a$341) = -//│ case a$341 of -//│ A$335 => -//│ let x$361 = a$341. in -//│ let x$362 = 1 in -//│ jump j$360(x$362) +//│ class A(x$358) +//│ class B(y$361) +//│ def f$355(a$362) = +//│ case a$362 of +//│ A$356 => +//│ let x$382 = a$362. in +//│ let x$383 = 1 in +//│ jump j$381(x$383) //│ _ => -//│ case a$341 of -//│ B$338 => -//│ let x$364 = a$341. in -//│ let x$365 = 2 in -//│ jump j$363(x$365) +//│ case a$362 of +//│ B$359 => +//│ let x$385 = a$362. in +//│ let x$386 = 2 in +//│ jump j$384(x$386) //│ _ => //│ panic "match error" -//│ def j$363(tmp$356) = -//│ jump j$360(tmp$356) -//│ def j$360(tmp$356) = -//│ tmp$356 -//│ let x$366 = A$335(1) in -//│ let* (x$367) = f(x$366) in -//│ x$367 +//│ def j$384(tmp$377) = +//│ jump j$381(tmp$377) +//│ def j$381(tmp$377) = +//│ tmp$377 +//│ let x$387 = A$356(1) in +//│ let* (x$388) = f(x$387) in +//│ x$388 //│ //│ Interpreted: //│ 1 @@ -351,50 +351,50 @@ fun f(a) = f(A(1)) //│ = 1 //│ LLIR: -//│ class A(x$373) -//│ class B(y$376) -//│ def f$370(a$377) = -//│ case a$377 of -//│ A$371 => -//│ let x$401 = a$377. in -//│ case a$377 of -//│ A$371 => -//│ let x$403 = a$377. in -//│ case x$403 of +//│ class A(x$394) +//│ class B(y$397) +//│ def f$391(a$398) = +//│ case a$398 of +//│ A$392 => +//│ let x$422 = a$398. in +//│ case a$398 of +//│ A$392 => +//│ let x$424 = a$398. in +//│ case x$424 of //│ IntLit(1) => -//│ let x$405 = 1 in -//│ jump j$404(x$405) +//│ let x$426 = 1 in +//│ jump j$425(x$426) //│ _ => //│ panic "match error" //│ _ => -//│ case a$377 of -//│ B$374 => -//│ let x$407 = a$377. in -//│ let x$408 = 2 in -//│ jump j$406(x$408) +//│ case a$398 of +//│ B$395 => +//│ let x$428 = a$398. in +//│ let x$429 = 2 in +//│ jump j$427(x$429) //│ _ => //│ panic "match error" //│ _ => -//│ case a$377 of -//│ B$374 => -//│ let x$410 = a$377. in -//│ let x$411 = 3 in -//│ jump j$409(x$411) +//│ case a$398 of +//│ B$395 => +//│ let x$431 = a$398. in +//│ let x$432 = 3 in +//│ jump j$430(x$432) //│ _ => //│ panic "match error" -//│ def j$404(tmp$395) = -//│ jump j$402(tmp$395) -//│ def j$406(tmp$395) = -//│ jump j$402(tmp$395) -//│ def j$402(tmp$395) = -//│ jump j$400(tmp$395) -//│ def j$409(tmp$396) = -//│ jump j$400(tmp$396) -//│ def j$400(tmp$396) = -//│ tmp$396 -//│ let x$412 = A$371(1) in -//│ let* (x$413) = f(x$412) in -//│ x$413 +//│ def j$425(tmp$416) = +//│ jump j$423(tmp$416) +//│ def j$427(tmp$416) = +//│ jump j$423(tmp$416) +//│ def j$423(tmp$416) = +//│ jump j$421(tmp$416) +//│ def j$430(tmp$417) = +//│ jump j$421(tmp$417) +//│ def j$421(tmp$417) = +//│ tmp$417 +//│ let x$433 = A$392(1) in +//│ let* (x$434) = f(x$433) in +//│ x$434 //│ //│ Interpreted: //│ 1 diff --git a/hkmc2/shared/src/test/mlscript/llir/Ctor.mls b/hkmc2/shared/src/test/mlscript/llir/Ctor.mls index d76b5fff0f..fd01b7828a 100644 --- a/hkmc2/shared/src/test/mlscript/llir/Ctor.mls +++ b/hkmc2/shared/src/test/mlscript/llir/Ctor.mls @@ -10,12 +10,12 @@ fun testCtor1() = None fun testCtor2() = new None //│ LLIR: //│ class None() -//│ def testCtor1$198() = -//│ let x$207 = None$200() in -//│ x$207 -//│ def testCtor2$197() = -//│ let x$208 = None$200() in -//│ x$208 +//│ def testCtor1$219() = +//│ let x$228 = None$221() in +//│ x$228 +//│ def testCtor2$218() = +//│ let x$229 = None$221() in +//│ x$229 //│ undefined :sllir @@ -23,11 +23,11 @@ class A(x) fun testCtor1() = A(1) fun testCtor2() = new A(1) //│ LLIR: -//│ class A(x$214) -//│ def testCtor1$211() = -//│ let x$222 = A$212(1) in -//│ x$222 -//│ def testCtor2$210() = -//│ let x$223 = A$212(1) in -//│ x$223 +//│ class A(x$235) +//│ def testCtor1$232() = +//│ let x$243 = A$233(1) in +//│ x$243 +//│ def testCtor2$231() = +//│ let x$244 = A$233(1) in +//│ x$244 //│ undefined diff --git a/hkmc2/shared/src/test/mlscript/llir/HigherOrder.mls b/hkmc2/shared/src/test/mlscript/llir/HigherOrder.mls index 58e5c602b1..6b21b9a84b 100644 --- a/hkmc2/shared/src/test/mlscript/llir/HigherOrder.mls +++ b/hkmc2/shared/src/test/mlscript/llir/HigherOrder.mls @@ -12,25 +12,25 @@ fun add_curried(x)(y) = x + y add(1)(2) //│ = 3 //│ LLIR: -//│ class Lambda(x$199) extends Callable { -//│ def apply1$219(y$200) = -//│ let x$220 = +(x$199,y$200) in -//│ x$220 +//│ class Lambda(x$220) extends Callable { +//│ def apply1$240(y$221) = +//│ let x$241 = +(x$220,y$221) in +//│ x$241 //│ } -//│ class Lambda(x$203) extends Callable { -//│ def apply1$219(y$204) = -//│ let x$225 = +(x$203,y$204) in -//│ x$225 +//│ class Lambda(x$224) extends Callable { +//│ def apply1$240(y$225) = +//│ let x$246 = +(x$224,y$225) in +//│ x$246 //│ } -//│ def add$197(x$199) = -//│ let x$222 = Lambda$217(x$199) in -//│ x$222 -//│ def add_curried$198(x$203) = -//│ let x$226 = Lambda$223(x$203) in -//│ x$226 -//│ let* (x$227) = add(1) in -//│ let x$228 = Callable.apply1$219(x$227,2) in -//│ x$228 +//│ def add$218(x$220) = +//│ let x$243 = Lambda$238(x$220) in +//│ x$243 +//│ def add_curried$219(x$224) = +//│ let x$247 = Lambda$244(x$224) in +//│ x$247 +//│ let* (x$248) = add(1) in +//│ let x$249 = Callable.apply1$240(x$248,2) in +//│ x$249 //│ //│ Cpp: //│ #include "mlsprelude.h" @@ -101,29 +101,29 @@ fun add4_curried(a, b)(c, d) = a + b + c + d add4(1, 2)(3, 4) //│ = 10 //│ LLIR: -//│ class Lambda(a$231,b$232) extends Callable { -//│ def apply2$267(c$233,d$234) = -//│ let x$268 = +(a$231,b$232) in -//│ let x$269 = +(x$268,c$233) in -//│ let x$270 = +(x$269,d$234) in -//│ x$270 +//│ class Lambda(b$253,a$252) extends Callable { +//│ def apply2$288(c$254,d$255) = +//│ let x$289 = +(a$252,b$253) in +//│ let x$290 = +(x$289,c$254) in +//│ let x$291 = +(x$290,d$255) in +//│ x$291 //│ } -//│ class Lambda(b$240,a$239) extends Callable { -//│ def apply2$267(c$241,d$242) = -//│ let x$274 = +(a$239,b$240) in -//│ let x$275 = +(x$274,c$241) in -//│ let x$276 = +(x$275,d$242) in -//│ x$276 +//│ class Lambda(b$261,a$260) extends Callable { +//│ def apply2$288(c$262,d$263) = +//│ let x$295 = +(a$260,b$261) in +//│ let x$296 = +(x$295,c$262) in +//│ let x$297 = +(x$296,d$263) in +//│ x$297 //│ } -//│ def add4$230(a$231,b$232) = -//│ let x$271 = Lambda$265(a$231,b$232) in -//│ x$271 -//│ def add4_curried$229(a$239,b$240) = -//│ let x$277 = Lambda$272(b$240,a$239) in -//│ x$277 -//│ let* (x$278) = add4(1,2) in -//│ let x$279 = Callable.apply2$267(x$278,3,4) in -//│ x$279 +//│ def add4$251(a$252,b$253) = +//│ let x$292 = Lambda$286(b$253,a$252) in +//│ x$292 +//│ def add4_curried$250(a$260,b$261) = +//│ let x$298 = Lambda$293(b$261,a$260) in +//│ x$298 +//│ let* (x$299) = add4(1,2) in +//│ let x$300 = Callable.apply2$288(x$299,3,4) in +//│ x$300 //│ //│ Cpp: //│ #include "mlsprelude.h" @@ -133,13 +133,13 @@ add4(1, 2)(3, 4) //│ _mlsValue _mls_add4_curried(_mlsValue, _mlsValue); //│ _mlsValue _mlsMain(); //│ struct _mls_Lambda2: public _mls_Callable { -//│ _mlsValue _mls_a; //│ _mlsValue _mls_b; +//│ _mlsValue _mls_a; //│ constexpr static inline const char *typeName = "Lambda"; //│ constexpr static inline uint32_t typeTag = nextTypeTag(); -//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->_mls_a.print(); std::printf(", "); this->_mls_b.print(); std::printf(")"); } -//│ virtual void destroy() override { _mlsValue::destroy(this->_mls_a); _mlsValue::destroy(this->_mls_b); operator delete (this, std::align_val_t(_mlsAlignment)); } -//│ static _mlsValue create(_mlsValue _mls_a, _mlsValue _mls_b) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) _mls_Lambda2; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->_mls_a = _mls_a; _mlsVal->_mls_b = _mls_b; return _mlsValue(_mlsVal); } +//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->_mls_b.print(); std::printf(", "); this->_mls_a.print(); std::printf(")"); } +//│ virtual void destroy() override { _mlsValue::destroy(this->_mls_b); _mlsValue::destroy(this->_mls_a); operator delete (this, std::align_val_t(_mlsAlignment)); } +//│ static _mlsValue create(_mlsValue _mls_b, _mlsValue _mls_a) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) _mls_Lambda2; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->_mls_b = _mls_b; _mlsVal->_mls_a = _mls_a; return _mlsValue(_mlsVal); } //│ virtual _mlsValue _mls_apply2(_mlsValue, _mlsValue); //│ }; //│ struct _mls_Lambda3: public _mls_Callable { @@ -154,7 +154,7 @@ add4(1, 2)(3, 4) //│ }; //│ _mlsValue _mls_add4(_mlsValue _mls_a, _mlsValue _mls_b) { //│ _mlsValue _mls_retval; -//│ auto _mls_x14 = _mlsValue::create<_mls_Lambda2>(_mls_a, _mls_b); +//│ auto _mls_x14 = _mlsValue::create<_mls_Lambda2>(_mls_b, _mls_a); //│ _mls_retval = _mls_x14; //│ return _mls_retval; //│ } @@ -201,19 +201,19 @@ dummy()(1, 2) //│ = 3 //│ LLIR: //│ class Lambda_add() extends Callable { -//│ def apply2$267(arg$298,arg$299) = -//│ let* (x$302) = add(arg$298,arg$299) in -//│ x$302 +//│ def apply2$288(arg$319,arg$320) = +//│ let* (x$323) = add(arg$319,arg$320) in +//│ x$323 //│ } -//│ def add$280(a$282,b$283) = -//│ let x$297 = +(a$282,b$283) in -//│ x$297 -//│ def dummy$281() = -//│ let x$303 = Lambda_add$300() in -//│ x$303 -//│ let* (x$304) = dummy() in -//│ let x$305 = Callable.apply2$267(x$304,1,2) in -//│ x$305 +//│ def add$301(a$303,b$304) = +//│ let x$318 = +(a$303,b$304) in +//│ x$318 +//│ def dummy$302() = +//│ let x$324 = Lambda_add$321() in +//│ x$324 +//│ let* (x$325) = dummy() in +//│ let x$326 = Callable.apply2$288(x$325,1,2) in +//│ x$326 //│ //│ Cpp: //│ #include "mlsprelude.h" @@ -277,55 +277,55 @@ main() //│ = Cons(4, Cons(5, Nil)) //│ LLIR: //│ class List() -//│ class Cons(head$318,tail$319) extends List +//│ class Cons(head$339,tail$340) extends List //│ class Nil() extends List //│ class Lambda() extends Callable { -//│ def apply1$219(x$336) = -//│ let* (x$401) = inc(x$336) in -//│ x$401 +//│ def apply1$240(x$357) = +//│ let* (x$422) = inc(x$357) in +//│ x$422 //│ } //│ class Lambda_inc() extends Callable { -//│ def apply1$219(arg$407) = -//│ let* (x$410) = inc(arg$407) in -//│ x$410 +//│ def apply1$240(arg$428) = +//│ let* (x$431) = inc(arg$428) in +//│ x$431 //│ } -//│ def map$307(f$322,l$323) = -//│ case l$323 of -//│ Cons$315 => -//│ let x$387 = l$323. in -//│ let x$388 = l$323. in -//│ let x$389 = Callable.apply1$219(f$322,x$387) in -//│ let* (x$390) = map(f$322,x$388) in -//│ let x$391 = Cons$315(x$389,x$390) in -//│ x$391 +//│ def map$328(f$343,l$344) = +//│ case l$344 of +//│ Cons$336 => +//│ let x$408 = l$344. in +//│ let x$409 = l$344. in +//│ let x$410 = Callable.apply1$240(f$343,x$408) in +//│ let* (x$411) = map(f$343,x$409) in +//│ let x$412 = Cons$336(x$410,x$411) in +//│ x$412 //│ _ => -//│ case l$323 of -//│ Nil$320 => -//│ let x$393 = Nil$320() in -//│ x$393 +//│ case l$344 of +//│ Nil$341 => +//│ let x$414 = Nil$341() in +//│ x$414 //│ _ => //│ panic "match error" -//│ def j$392() = -//│ jump j$386() -//│ def j$386() = +//│ def j$413() = +//│ jump j$407() +//│ def j$407() = //│ null -//│ def inc$310(x$332) = -//│ let x$394 = +(x$332,1) in -//│ x$394 -//│ def main$308() = -//│ let x$395 = Nil$320() in -//│ let x$396 = Cons$315(2,x$395) in -//│ let x$397 = Cons$315(1,x$396) in -//│ let x$402 = Lambda$399() in -//│ let* (x$398) = map(x$402,x$397) in -//│ let x$403 = Nil$320() in -//│ let x$404 = Cons$315(4,x$403) in -//│ let x$405 = Cons$315(3,x$404) in -//│ let x$411 = Lambda_inc$408() in -//│ let* (x$406) = map(x$411,x$405) in -//│ x$406 -//│ let* (x$412) = main() in -//│ x$412 +//│ def inc$331(x$353) = +//│ let x$415 = +(x$353,1) in +//│ x$415 +//│ def main$329() = +//│ let x$416 = Nil$341() in +//│ let x$417 = Cons$336(2,x$416) in +//│ let x$418 = Cons$336(1,x$417) in +//│ let x$423 = Lambda$420() in +//│ let* (x$419) = map(x$423,x$418) in +//│ let x$424 = Nil$341() in +//│ let x$425 = Cons$336(4,x$424) in +//│ let x$426 = Cons$336(3,x$425) in +//│ let x$432 = Lambda_inc$429() in +//│ let* (x$427) = map(x$432,x$426) in +//│ x$427 +//│ let* (x$433) = main() in +//│ x$433 //│ //│ Interpreted: //│ Cons(4,Cons(5,Nil())) @@ -349,83 +349,83 @@ nubBy((x, y) => x == y, 1 :: 2 :: 3 :: 3 :: Nil) //│ = Cons(1, Cons(2, Cons(3, Nil))) //│ LLIR: //│ class List() -//│ class Cons(head$425,tail$426) extends List +//│ class Cons(head$446,tail$447) extends List //│ class Nil() extends List -//│ class Lambda(eq$443,x$527) extends Callable { -//│ def apply1$219(y$452) = -//│ let x$532 = Callable.apply2$267(eq$443,x$527,y$452) in -//│ let* (x$533) = not(x$532) in -//│ x$533 +//│ class Lambda(x$548,eq$464) extends Callable { +//│ def apply1$240(y$473) = +//│ let x$553 = Callable.apply2$288(eq$464,x$548,y$473) in +//│ let* (x$554) = not(x$553) in +//│ x$554 //│ } //│ class Lambda() extends Callable { -//│ def apply2$267(x$457,y$458) = -//│ let x$545 = ==(x$457,y$458) in -//│ x$545 +//│ def apply2$288(x$478,y$479) = +//│ let x$566 = ==(x$478,y$479) in +//│ x$566 //│ } -//│ def not$416(c$429) = -//│ case c$429 of +//│ def not$437(c$450) = +//│ case c$450 of //│ BoolLit(true) => //│ false //│ _ => //│ true -//│ def j$513() = +//│ def j$534() = //│ null -//│ def filter$415(f$431,ls$432) = -//│ case ls$432 of -//│ Nil$427 => -//│ let x$515 = Nil$427() in -//│ x$515 +//│ def filter$436(f$452,ls$453) = +//│ case ls$453 of +//│ Nil$448 => +//│ let x$536 = Nil$448() in +//│ x$536 //│ _ => -//│ case ls$432 of -//│ Cons$422 => -//│ let x$517 = ls$432. in -//│ let x$518 = ls$432. in -//│ let x$519 = Callable.apply1$219(f$431,x$517) in -//│ case x$519 of +//│ case ls$453 of +//│ Cons$443 => +//│ let x$538 = ls$453. in +//│ let x$539 = ls$453. in +//│ let x$540 = Callable.apply1$240(f$452,x$538) in +//│ case x$540 of //│ BoolLit(true) => -//│ let* (x$521) = filter(f$431,x$518) in -//│ let x$522 = Cons$422(x$517,x$521) in -//│ x$522 +//│ let* (x$542) = filter(f$452,x$539) in +//│ let x$543 = Cons$443(x$538,x$542) in +//│ x$543 //│ _ => -//│ let* (x$523) = filter(f$431,x$518) in -//│ x$523 +//│ let* (x$544) = filter(f$452,x$539) in +//│ x$544 //│ _ => //│ panic "match error" -//│ def j$520() = -//│ jump j$516() -//│ def j$516() = -//│ jump j$514() -//│ def j$514() = +//│ def j$541() = +//│ jump j$537() +//│ def j$537() = +//│ jump j$535() +//│ def j$535() = //│ null -//│ def nubBy$418(eq$443,ls$444) = -//│ case ls$444 of -//│ Nil$427 => -//│ let x$525 = Nil$427() in -//│ x$525 +//│ def nubBy$439(eq$464,ls$465) = +//│ case ls$465 of +//│ Nil$448 => +//│ let x$546 = Nil$448() in +//│ x$546 //│ _ => -//│ case ls$444 of -//│ Cons$422 => -//│ let x$527 = ls$444. in -//│ let x$528 = ls$444. in -//│ let x$534 = Lambda$530(eq$443,x$527) in -//│ let* (x$529) = filter(x$534,x$528) in -//│ let* (x$535) = nubBy(eq$443,x$529) in -//│ let x$536 = Cons$422(x$527,x$535) in -//│ x$536 +//│ case ls$465 of +//│ Cons$443 => +//│ let x$548 = ls$465. in +//│ let x$549 = ls$465. in +//│ let x$555 = Lambda$551(x$548,eq$464) in +//│ let* (x$550) = filter(x$555,x$549) in +//│ let* (x$556) = nubBy(eq$464,x$550) in +//│ let x$557 = Cons$443(x$548,x$556) in +//│ x$557 //│ _ => //│ panic "match error" -//│ def j$526() = -//│ jump j$524() -//│ def j$524() = +//│ def j$547() = +//│ jump j$545() +//│ def j$545() = //│ null -//│ let x$537 = Nil$427() in -//│ let x$538 = Cons$422(3,x$537) in -//│ let x$539 = Cons$422(3,x$538) in -//│ let x$540 = Cons$422(2,x$539) in -//│ let x$541 = Cons$422(1,x$540) in -//│ let x$546 = Lambda$543() in -//│ let* (x$542) = nubBy(x$546,x$541) in -//│ x$542 +//│ let x$558 = Nil$448() in +//│ let x$559 = Cons$443(3,x$558) in +//│ let x$560 = Cons$443(3,x$559) in +//│ let x$561 = Cons$443(2,x$560) in +//│ let x$562 = Cons$443(1,x$561) in +//│ let x$567 = Lambda$564() in +//│ let* (x$563) = nubBy(x$567,x$562) in +//│ x$563 //│ //│ Cpp: //│ #include "mlsprelude.h" @@ -482,13 +482,13 @@ nubBy((x, y) => x == y, 1 :: 2 :: 3 :: 3 :: Nil) //│ virtual _mlsValue _mls_apply2(_mlsValue, _mlsValue); //│ }; //│ struct _mls_Lambda5: public _mls_Callable { -//│ _mlsValue _mls_eq; //│ _mlsValue _mls_x; +//│ _mlsValue _mls_eq; //│ constexpr static inline const char *typeName = "Lambda"; //│ constexpr static inline uint32_t typeTag = nextTypeTag(); -//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->_mls_eq.print(); std::printf(", "); this->_mls_x.print(); std::printf(")"); } -//│ virtual void destroy() override { _mlsValue::destroy(this->_mls_eq); _mlsValue::destroy(this->_mls_x); operator delete (this, std::align_val_t(_mlsAlignment)); } -//│ static _mlsValue create(_mlsValue _mls_eq, _mlsValue _mls_x) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) _mls_Lambda5; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->_mls_eq = _mls_eq; _mlsVal->_mls_x = _mls_x; return _mlsValue(_mlsVal); } +//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->_mls_x.print(); std::printf(", "); this->_mls_eq.print(); std::printf(")"); } +//│ virtual void destroy() override { _mlsValue::destroy(this->_mls_x); _mlsValue::destroy(this->_mls_eq); operator delete (this, std::align_val_t(_mlsAlignment)); } +//│ static _mlsValue create(_mlsValue _mls_x, _mlsValue _mls_eq) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) _mls_Lambda5; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->_mls_x = _mls_x; _mlsVal->_mls_eq = _mls_eq; return _mlsValue(_mlsVal); } //│ virtual _mlsValue _mls_apply1(_mlsValue); //│ }; //│ _mlsValue _mls_not(_mlsValue _mls_c2) { @@ -544,11 +544,6 @@ nubBy((x, y) => x == y, 1 :: 2 :: 3 :: 3 :: Nil) //│ _mls_retval = _mlsValue::create<_mls_Unit>(); //│ return _mls_retval; //│ } -//│ _mlsValue _mls_j7() { -//│ _mlsValue _mls_retval; -//│ _mls_retval = _mls_j4(); -//│ return _mls_retval; -//│ } //│ _mlsValue _mls_j2() { //│ _mlsValue _mls_retval; //│ _mls_retval = _mlsValue::create<_mls_Unit>(); @@ -563,7 +558,7 @@ nubBy((x, y) => x == y, 1 :: 2 :: 3 :: 3 :: Nil) //│ if (_mlsValue::isValueOf<_mls_Cons1>(_mls_ls)) { //│ auto _mls_x47 = _mlsValue::cast<_mls_Cons1>(_mls_ls)->_mls_head; //│ auto _mls_x50 = _mlsValue::cast<_mls_Cons1>(_mls_ls)->_mls_tail; -//│ auto _mls_x51 = _mlsValue::create<_mls_Lambda5>(_mls_eq, _mls_x47); +//│ auto _mls_x51 = _mlsValue::create<_mls_Lambda5>(_mls_x47, _mls_eq); //│ auto _mls_x52 = _mls_filter(_mls_x51, _mls_x50); //│ auto _mls_x53 = _mls_nubBy(_mls_eq, _mls_x52); //│ auto _mls_x54 = _mlsValue::create<_mls_Cons1>(_mls_x47, _mls_x53); @@ -574,6 +569,11 @@ nubBy((x, y) => x == y, 1 :: 2 :: 3 :: 3 :: Nil) //│ } //│ return _mls_retval; //│ } +//│ _mlsValue _mls_j7() { +//│ _mlsValue _mls_retval; +//│ _mls_retval = _mls_j4(); +//│ return _mls_retval; +//│ } //│ _mlsValue _mls_Lambda6::_mls_apply2(_mlsValue _mls_x46, _mlsValue _mls_y2) { //│ _mlsValue _mls_retval; //│ auto _mls_x45 = (_mls_x46 == _mls_y2); diff --git a/hkmc2/shared/src/test/mlscript/llir/Lazy.mls b/hkmc2/shared/src/test/mlscript/llir/Lazy.mls new file mode 100644 index 0000000000..87edefa35f --- /dev/null +++ b/hkmc2/shared/src/test/mlscript/llir/Lazy.mls @@ -0,0 +1,116 @@ +:llir + +:sllir +:scpp +abstract class Lazy[out A](init: () -> A) with + fun get: A +fun lazy(x) = Lazy(x) +fun force(x) = if x is Lazy then x.Lazy#get() +fun side_effect() = + console.log("executed") + 1 +fun main() = + let x = lazy(() => side_effect()) + let y = force(x) + let y1 = force(x) // force again, but should not execute side_effect again + () +main() +//│ LLIR: +//│ class Lazy(init$225) +//│ class Lambda() extends Callable { +//│ def apply0$265() = +//│ let* (x$266) = side_effect() in +//│ x$266 +//│ } +//│ def lazy$217(x$227) = +//│ let x$257 = Lazy$222(x$227) in +//│ x$257 +//│ def force$218(x$230) = +//│ case x$230 of +//│ Lazy$222 => +//│ let x$259 = Lazy.get$216(x$230) in +//│ x$259 +//│ _ => +//│ panic "match error" +//│ def j$258() = +//│ null +//│ def side_effect$221() = +//│ let* (x$260) = ("println","executed") in +//│ 1 +//│ def main$219() = +//│ let x$268 = Lambda$263() in +//│ let* (x$262) = lazy(x$268) in +//│ let* (x$269) = force(x$262) in +//│ let* (x$270) = force(x$262) in +//│ undefined +//│ let* (x$271) = main() in +//│ x$271 +//│ +//│ Cpp: +//│ #include "mlsprelude.h" +//│ struct _mls_Lazy; +//│ struct _mls_Lambda; +//│ _mlsValue _mls_main(); +//│ _mlsValue _mls_force(_mlsValue); +//│ _mlsValue _mls_lazy(_mlsValue); +//│ _mlsValue _mls_j(); +//│ _mlsValue _mls_side_effect(); +//│ _mlsValue _mlsMain(); +//│ struct _mls_Lambda: public _mls_Callable { +//│ +//│ constexpr static inline const char *typeName = "Lambda"; +//│ constexpr static inline uint32_t typeTag = nextTypeTag(); +//│ virtual void print() const override { std::printf("%s", typeName); } +//│ virtual void destroy() override { operator delete (this, std::align_val_t(_mlsAlignment)); } +//│ static _mlsValue create() { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) _mls_Lambda; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; return _mlsValue(_mlsVal); } +//│ virtual _mlsValue _mls_apply0(); +//│ }; +//│ _mlsValue _mls_lazy(_mlsValue _mls_x6) { +//│ _mlsValue _mls_retval; +//│ auto _mls_x5 = _mlsValue::create<_mls_Lazy>(_mls_x6); +//│ _mls_retval = _mls_x5; +//│ return _mls_retval; +//│ } +//│ _mlsValue _mls_j() { +//│ _mlsValue _mls_retval; +//│ _mls_retval = _mlsValue::create<_mls_Unit>(); +//│ return _mls_retval; +//│ } +//│ _mlsValue _mls_force(_mlsValue _mls_x7) { +//│ _mlsValue _mls_retval; +//│ if (_mlsValue::isValueOf<_mls_Lazy>(_mls_x7)) { +//│ auto _mls_x8 = _mlsMethodCall<_mls_Lazy>(_mls_x7)->_mls_get(); +//│ _mls_retval = _mls_x8; +//│ } else { +//│ throw std::runtime_error("match error"); +//│ } +//│ return _mls_retval; +//│ } +//│ _mlsValue _mls_side_effect() { +//│ _mlsValue _mls_retval; +//│ auto _mls_x9 = _mls_builtin_println(_mlsValue::create<_mls_Str>("executed")); +//│ _mls_retval = _mlsValue::fromIntLit(1); +//│ return _mls_retval; +//│ } +//│ _mlsValue _mls_main() { +//│ _mlsValue _mls_retval; +//│ auto _mls_x1 = _mlsValue::create<_mls_Lambda>(); +//│ auto _mls_x2 = _mls_lazy(_mls_x1); +//│ auto _mls_x3 = _mls_force(_mls_x2); +//│ auto _mls_x4 = _mls_force(_mls_x2); +//│ _mls_retval = _mlsValue::create<_mls_Unit>(); +//│ return _mls_retval; +//│ } +//│ _mlsValue _mls_Lambda::_mls_apply0() { +//│ _mlsValue _mls_retval; +//│ auto _mls_x = _mls_side_effect(); +//│ _mls_retval = _mls_x; +//│ return _mls_retval; +//│ } +//│ _mlsValue _mlsMain() { +//│ _mlsValue _mls_retval; +//│ auto _mls_x10 = _mls_main(); +//│ _mls_retval = _mls_x10; +//│ return _mls_retval; +//│ } +//│ int main() { return _mlsLargeStack(_mlsMainWrapper); } diff --git a/hkmc2/shared/src/test/mlscript/llir/Legacy.mls b/hkmc2/shared/src/test/mlscript/llir/Legacy.mls index aad2239602..e0046814fc 100644 --- a/hkmc2/shared/src/test/mlscript/llir/Legacy.mls +++ b/hkmc2/shared/src/test/mlscript/llir/Legacy.mls @@ -255,74 +255,74 @@ main() //│ = 404 //│ LLIR: //│ class Option() -//│ class Some(x$1014) extends Option +//│ class Some(x$1035) extends Option //│ class None() extends Option //│ class Nat() -//│ class S(s$1025) extends Nat +//│ class S(s$1046) extends Nat //│ class O() extends Nat -//│ def fromSome$997(s$1017) = -//│ case s$1017 of -//│ Some$1011 => -//│ let x$1092 = s$1017. in -//│ x$1092 +//│ def fromSome$1018(s$1038) = +//│ case s$1038 of +//│ Some$1032 => +//│ let x$1113 = s$1038. in +//│ x$1113 //│ _ => //│ panic "match error" -//│ def j$1091() = +//│ def j$1112() = //│ null -//│ def aaa$1002() = -//│ let x$1093 = 1 in -//│ let x$1094 = 2 in -//│ let x$1095 = 3 in -//│ let x$1096 = 4 in -//│ let x$1097 = +(x$1093,x$1094) in -//│ let x$1098 = -(x$1097,x$1095) in -//│ let x$1099 = +(x$1098,x$1096) in -//│ x$1099 -//│ def bbb$1004() = -//│ let* (x$1100) = aaa() in -//│ let x$1101 = *(x$1100,100) in -//│ let x$1102 = +(x$1101,4) in -//│ x$1102 -//│ def not$1000(x$1041) = -//│ case x$1041 of +//│ def aaa$1023() = +//│ let x$1114 = 1 in +//│ let x$1115 = 2 in +//│ let x$1116 = 3 in +//│ let x$1117 = 4 in +//│ let x$1118 = +(x$1114,x$1115) in +//│ let x$1119 = -(x$1118,x$1116) in +//│ let x$1120 = +(x$1119,x$1117) in +//│ x$1120 +//│ def bbb$1025() = +//│ let* (x$1121) = aaa() in +//│ let x$1122 = *(x$1121,100) in +//│ let x$1123 = +(x$1122,4) in +//│ x$1123 +//│ def not$1021(x$1062) = +//│ case x$1062 of //│ BoolLit(true) => //│ false //│ _ => //│ true -//│ def j$1103() = +//│ def j$1124() = //│ null -//│ def foo$1007(x$1043) = -//│ case x$1043 of +//│ def foo$1028(x$1064) = +//│ case x$1064 of //│ BoolLit(true) => -//│ let x$1105 = None$1015() in -//│ x$1105 +//│ let x$1126 = None$1036() in +//│ x$1126 //│ _ => -//│ let* (x$1106) = not(x$1043) in -//│ let* (x$1107) = foo(x$1106) in -//│ let x$1108 = Some$1011(x$1107) in -//│ x$1108 -//│ def j$1104() = +//│ let* (x$1127) = not(x$1064) in +//│ let* (x$1128) = foo(x$1127) in +//│ let x$1129 = Some$1032(x$1128) in +//│ x$1129 +//│ def j$1125() = //│ null -//│ def main$998() = -//│ let* (x$1109) = foo(false) in -//│ case x$1109 of -//│ None$1015 => -//│ let* (x$1111) = aaa() in -//│ x$1111 +//│ def main$1019() = +//│ let* (x$1130) = foo(false) in +//│ case x$1130 of +//│ None$1036 => +//│ let* (x$1132) = aaa() in +//│ x$1132 //│ _ => -//│ case x$1109 of -//│ Some$1011 => -//│ let x$1113 = x$1109. in -//│ let* (x$1114) = bbb() in -//│ x$1114 +//│ case x$1130 of +//│ Some$1032 => +//│ let x$1134 = x$1130. in +//│ let* (x$1135) = bbb() in +//│ x$1135 //│ _ => //│ panic "match error" -//│ def j$1112() = -//│ jump j$1110() -//│ def j$1110() = +//│ def j$1133() = +//│ jump j$1131() +//│ def j$1131() = //│ null -//│ let* (x$1115) = main() in -//│ x$1115 +//│ let* (x$1136) = main() in +//│ x$1136 //│ //│ Interpreted: //│ 404 diff --git a/hkmc2/shared/src/test/mlscript/llir/Method.mls b/hkmc2/shared/src/test/mlscript/llir/Method.mls index 2f980e49ae..e73b4ef9e6 100644 --- a/hkmc2/shared/src/test/mlscript/llir/Method.mls +++ b/hkmc2/shared/src/test/mlscript/llir/Method.mls @@ -12,14 +12,14 @@ fun main() = a.A#f() main() //│ LLIR: -//│ class A(m$200) { -//│ def f$195() = -//│ m$200 +//│ class A(m$221) { +//│ def f$216() = +//│ m$221 //│ } -//│ def main$197() = -//│ let x$212 = A$198(1) in -//│ let x$213 = A.f$195(x$212) in -//│ x$213 -//│ let* (x$214) = main() in -//│ x$214 +//│ def main$218() = +//│ let x$233 = A$219(1) in +//│ let x$234 = A.f$216(x$233) in +//│ x$234 +//│ let* (x$235) = main() in +//│ x$235 diff --git a/hkmc2/shared/src/test/mlscript/llir/NofibPrelude.mls b/hkmc2/shared/src/test/mlscript/llir/NofibPrelude.mls index bdb0c72feb..17d01fe806 100644 --- a/hkmc2/shared/src/test/mlscript/llir/NofibPrelude.mls +++ b/hkmc2/shared/src/test/mlscript/llir/NofibPrelude.mls @@ -10,6 +10,11 @@ abstract class Option[out T]: Some[T] | None class Some[out T](x: T) extends Option[T] object None extends Option +abstract class Lazy[out A](init: () -> A) with + fun get() +fun lazy(x) = Lazy(x) +fun force(x) = if x is Lazy then x.Lazy#get() + fun fromSome(s) = if s is Some(x) then x abstract class List[out T]: Cons[T] | Nil @@ -41,22 +46,17 @@ fun until(p, f, i) = if p(i) then i else until(p, f, f(i)) fun flip(f, x, y) = f(y)(x) -fun power(a, n) = globalThis.builtin("pow", a, n) +fun power(a, n) = Math.pow(a, n) fun intDiv(a, b) = globalThis.builtin("floor_div", a, b) -fun intQuot(a, b) = a / b +fun intQuot(a, b) = globalThis.builtin("trunc_div", a, b) -fun intMod(a, b) = a - (b * intDiv(a, b)) -fun intRem(a, b) = a - (b * intQuot(a, b)) +fun intMod(a, b) = globalThis.builtin("floor_mod", a, b) +fun intRem(a, b) = globalThis.builtin("trunc_mod", a, b) fun quotRem(a, b) = [intQuot(a, b), intRem(a, b)] fun divMod(a, b) = [intDiv(a, b), intMod(a, b)] -fun max(a, b) = if a > b then a else b -fun min(a, b) = if a < b then a else b - -fun abs(x) = if x < 0 then -x else x - fun head(l) = if l is h :: t then h fun tail(l) = if l is h :: t then t @@ -245,14 +245,25 @@ fun flatMap(f, ls) = if ls is Nil then Nil h :: t then append(f(h), flatMap(f, t)) -fun stringOfInt(x) = globalThis.builtin("string_of_int", x) -fun stringConcat(x, y) = globalThis.builtin("str_concat", x, y) -fun stringListConcat(ls) = if ls is - Nil then "" - h :: t then stringConcat(h, stringListConcat(t)) -fun sqrt(x) = globalThis.builtin("sqrt", x) -fun tan(x) = globalThis.builtin("tan", x) -fun sin(x) = globalThis.builtin("sin", x) -fun cos(x) = globalThis.builtin("cos", x) -fun round(x) = globalThis.builtin("round", x) -fun int_of_char(x) = globalThis.builtin("int_of_char", x) +// fun stringOfInt(x) = globalThis.builtin("int2str", x) +// fun stringConcat(x, y) = globalThis.builtin("str_concat", x, y) +// fun stringListConcat(ls) = if ls is +// Nil then "" +// h :: t then stringConcat(h, stringListConcat(t)) + +// fun max(a, b) = Math.min(a, b) +// fun min(a, b) = Math.max(a, b) +// fun abs(x) = Math.abs(x) +// fun sqrt(x) = Math.sqrt(x) +// fun tan(x) = Math.tan(x) +// fun sin(x) = Math.sin(x) +// fun cos(x) = Math.cos(x) +// fun round(x) = Math.round(x) + +:runWholeCpp +1 +//│ = 1 +//│ +//│ +//│ Execution succeeded: +//│ 1 diff --git a/hkmc2/shared/src/test/mlscript/llir/Tuple.mls b/hkmc2/shared/src/test/mlscript/llir/Tuple.mls index be40d7b535..2a152afb66 100644 --- a/hkmc2/shared/src/test/mlscript/llir/Tuple.mls +++ b/hkmc2/shared/src/test/mlscript/llir/Tuple.mls @@ -13,21 +13,21 @@ mkTup(1, 2) //│ = [1, 2] //│ LLIR: //│ -//│ def mkTup$197(x$199,y$200) = -//│ let x$213 = Tuple2$214(x$199,y$200) in -//│ x$213 -//│ def fst$198(t$202) = -//│ case t$202 of -//│ Tuple2$214 => -//│ let x$217 = t$202. in -//│ let x$218 = t$202. in -//│ x$217 +//│ def mkTup$218(x$220,y$221) = +//│ let x$234 = Tuple2$235(x$220,y$221) in +//│ x$234 +//│ def fst$219(t$223) = +//│ case t$223 of +//│ Tuple2$235 => +//│ let x$238 = t$223. in +//│ let x$239 = t$223. in +//│ x$238 //│ _ => //│ panic "match error" -//│ def j$216() = +//│ def j$237() = //│ null -//│ let* (x$219) = mkTup(1,2) in -//│ x$219 +//│ let* (x$240) = mkTup(1,2) in +//│ x$240 //│ //│ Cpp: //│ #include "mlsprelude.h" diff --git a/hkmc2DiffTests/src/test/scala/hkmc2/LlirDiffMaker.scala b/hkmc2DiffTests/src/test/scala/hkmc2/LlirDiffMaker.scala index c8a1664a90..90dff27e14 100644 --- a/hkmc2DiffTests/src/test/scala/hkmc2/LlirDiffMaker.scala +++ b/hkmc2DiffTests/src/test/scala/hkmc2/LlirDiffMaker.scala @@ -77,7 +77,7 @@ abstract class LlirDiffMaker extends BbmlDiffMaker: def cppGen(name: String, prog: Program, gen: Bool, show: Bool, run: Bool, write: Opt[Str]): Unit = tl.log(s"Generating $name") if gen || show || run || write.isDefined then - val cpp = CppCodeGen(ctx.builtin_sym.callableSym.toSet, tl).codegen(prog) + val cpp = CppCodeGen(ctx.builtin_sym.hiddenClasses, tl).codegen(prog) if show then output(s"\n$name:") output(cpp.toDocument.toString) From 304ebbc56a3d3ace234234996dfb8ed11f963330 Mon Sep 17 00:00:00 2001 From: waterlens Date: Thu, 27 Feb 2025 20:41:28 +0800 Subject: [PATCH 46/88] Fix some subtle bugs; add lazy utils to the prelude --- .../src/main/scala/hkmc2/codegen/Block.scala | 7 +- .../main/scala/hkmc2/codegen/cpp/Ast.scala | 3 +- .../scala/hkmc2/codegen/llir/Builder.scala | 31 ++++--- .../src/test/mlscript/llir/NofibPrelude.mls | 82 +++++++++++++++++++ .../src/test/scala/hkmc2/LlirDiffMaker.scala | 9 +- 5 files changed, 115 insertions(+), 17 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Block.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Block.scala index 94cf60f869..3a387a2b46 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Block.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Block.scala @@ -88,8 +88,10 @@ sealed abstract class Block extends Product with AutoLocated: case Continue(label) => Set(label) case Begin(sub, rest) => sub.freeVars ++ rest.freeVars case TryBlock(sub, finallyDo, rest) => sub.freeVars ++ finallyDo.freeVars ++ rest.freeVars - case Assign(lhs, rhs, rest) => Set(lhs) ++ rhs.freeVars ++ rest.freeVars + case Assign(lhs: TermSymbol, rhs, rest) => rhs.freeVars ++ rest.freeVars + case Assign(lhs, rhs, rest) => rhs.freeVars ++ (rest.freeVars - lhs) case AssignField(lhs, nme, rhs, rest) => lhs.freeVars ++ rhs.freeVars ++ rest.freeVars + case AssignDynField(lhs, fld, arrayIdx, rhs, rest) => lhs.freeVars ++ fld.freeVars ++ rhs.freeVars ++ rest.freeVars case Define(defn, rest) => defn.freeVars ++ rest.freeVars case HandleBlock(lhs, res, par, args, cls, hdr, bod, rst) => (bod.freeVars - lhs) ++ rst.freeVars ++ hdr.flatMap(_.freeVars) @@ -271,7 +273,8 @@ sealed abstract class Result: lazy val freeVars: Set[Local] = this match case Call(fun, args) => fun.freeVars ++ args.flatMap(_.value.freeVars).toSet case Instantiate(cls, args) => cls.freeVars ++ args.flatMap(_.freeVars).toSet - case Select(qual, name) => qual.freeVars + case Select(qual, name) => qual.freeVars + case DynSelect(qual, fld, arrayIdx) => qual.freeVars ++ fld.freeVars case Value.Ref(l) => Set(l) case Value.This(sym) => Set.empty case Value.Lit(lit) => Set.empty diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/Ast.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/Ast.scala index 5c584be257..c36a46de73 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/Ast.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/Ast.scala @@ -8,6 +8,7 @@ import hkmc2.Message.MessageContext import hkmc2.document._ import scala.language.implicitConversions +import hkmc2.escaped private def raw(x: String): Document = doc"$x" given Conversion[String, Document] = x => doc"$x" @@ -137,7 +138,7 @@ enum Expr: case Var(name) => name case IntLit(value) => value.toString case DoubleLit(value) => value.toString - case StrLit(value) => s"\"$value\"" // need more reliable escape utils + case StrLit(value) => value.escaped case CharLit(value) => value.toInt.toString case Call(func, args) => doc"${func.toDocument}(${Expr.toDocuments(args, sep = ", ")})" diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala index 162cb72a1a..649c6c3f22 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala @@ -47,7 +47,6 @@ final case class Ctx( flow_ctx: Map[Path, Local] = Map.empty, is_top_level: Bool = true, method_class: Opt[Symbol] = None, - free_vars: Set[Local] = Set.empty, builtin_sym: BuiltinSymbols = BuiltinSymbols() ): def addFuncName(n: Local, paramsSize: Int) = copy(fn_ctx = fn_ctx + (n -> FuncInfo(paramsSize))) @@ -64,7 +63,6 @@ final case class Ctx( case Some(value) => value def addKnownClass(n: Path, m: Local) = copy(flow_ctx = flow_ctx + (n -> m)) def setClass(c: Symbol) = copy(method_class = Some(c)) - def setFreeVars(n: Set[Local]) = copy(free_vars = free_vars) def nonTopLevel = copy(is_top_level = false) object Ctx: @@ -243,15 +241,23 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger, uid: FreshInt): trace[Node](s"bLam begin", x => s"bLam end: ${x.show}"): val Value.Lam(params, body) = lam // Generate an auxiliary class inheriting from Callable - val freeVars = freeVarsFilter(lam.freeVars -- lam.body.definedVars -- ctx.fn_ctx.keySet) + val freeVars = freeVarsFilter(lam.freeVars -- ctx.fn_ctx.keySet) + log(s"Match free vars: ${lam.freeVars} ${body.definedVars} ${params.params.map(p => p.sym)}") val name = newClassSym(s"Lambda${nameHint.fold("")(x => "_" + x)}") - val args = freeVars.toList.map(symMap) - val clsParams = args - val ctx2 = ctx.setFreeVars(freeVars) - val applyParams = params.params.map(x => x -> x.sym) - val ctx3 = applyParams.foldLeft(ctx2)((acc, x) => acc.addName(x._1.sym, x._1.sym)).nonTopLevel - val ctx4 = recName.fold(ctx3)(x => ctx3.addName(x, builtinThis)) - val pl = applyParams.map(_._1.sym) + val freeVarsList = freeVars.toList + val args = freeVarsList.map(symMap) + // args may have the same name (with different uid) + // it's not allowed when generating the names of fields in the backend + val clsParams = args.zipWithIndex.map: + case (arg, i) => newNamedTemp(s"lam_arg$i") + val applyParams = params.params + // add the parameters of lambda expression to the context + val ctx2 = applyParams.foldLeft(ctx)((acc, x) => acc.addName(x.sym, x.sym)) + // add the free variables (class parameters) to the context + val ctx3 = clsParams.iterator.zip(freeVarsList).foldLeft(ctx2): + case (acc, (param, arg)) => acc.addName(arg, param) + val ctx4 = recName.fold(ctx3)(x => ctx3.addName(x, builtinThis)).nonTopLevel + val pl = applyParams.map(_.sym) val method = Func( uid.make, builtinApply(params.params.length), @@ -273,6 +279,7 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger, uid: FreshInt): private def bValue(v: Value)(k: TrivialExpr => Ctx ?=> Node)(using ctx: Ctx)(using Raise, Scope) : Node = trace[Node](s"bValue { $v } begin", x => s"bValue end: ${x.show}"): v match + // TODO: why? case Value.Ref(l: TermSymbol) if l.owner.nonEmpty => k(l |> sr) case Value.Ref(sym) if sym.nme.isCapitalized => @@ -435,9 +442,9 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger, uid: FreshInt): case e: TrivialExpr => val nextCont = Begin(rest, ct) val jp: Local = newNamedTemp("j") - val fvset = freeVarsFilter(nextCont.freeVars -- nextCont.definedVars) + val fvset = freeVarsFilter(nextCont.freeVars) val fvs1 = fvset.toList - log(s"Match free vars: $fvset ${nextCont.freeVars} ${nextCont.definedVars} $fvs1") + log(s"Match free vars: $fvset ${nextCont.freeVars} $fvs1") val new_ctx = fvs1.foldLeft(ctx)((acc, x) => acc.addName(x, x)) val fvs = fvs1.map(new_ctx.findName(_)) def cont(x: TrivialExpr)(using ctx: Ctx) = Node.Jump( diff --git a/hkmc2/shared/src/test/mlscript/llir/NofibPrelude.mls b/hkmc2/shared/src/test/mlscript/llir/NofibPrelude.mls index 17d01fe806..57be414045 100644 --- a/hkmc2/shared/src/test/mlscript/llir/NofibPrelude.mls +++ b/hkmc2/shared/src/test/mlscript/llir/NofibPrelude.mls @@ -31,6 +31,11 @@ fun ltList(xs, ys, lt, gt) = if xs is gt(x, y) then false else ltList(xs, ys, lt, gt) +type LazyList[out T] = Lazy[LzList[T]] +abstract class LzList[out T]: LzCons[T] | LzNil +class LzCons[out T](head: T, tail: LazyList[T]) extends LzList[T] +object LzNil extends LzList + fun ltTup2(t1, t2, lt1, gt1, lt2) = if t1 is [a, b] and t2 is [c, d] and lt1(a, c) then true gt1(a, c) then false @@ -245,6 +250,83 @@ fun flatMap(f, ls) = if ls is Nil then Nil h :: t then append(f(h), flatMap(f, t)) + +// ===================== + +fun map_lz(f, ls) = lazy of () => + if force(ls) is + LzNil then LzNil + LzCons(h, t) then LzCons(f(h), map_lz(f, t)) + +fun filter_lz(p, ls) = Lazy of () => + if force(ls) is + LzNil then LzNil + LzCons(h, t) and + p(h) then LzCons(h, filter_lz(p, t)) + else force(filter_lz(p, t)) + +fun nubBy_lz(eq, ls) = Lazy of () => + if force(ls) is + LzNil then LzNil + LzCons(h, t) then LzCons(h, nubBy_lz(eq, filter_lz(y => not(eq(h, y)), t))) + +fun nub_lz(ls) = nubBy_lz((x, y) => x == y, ls) + +fun take_lz(n, ls) = if + n > 0 and force(ls) is + LzNil then Nil + LzCons(h, t) then h :: take_lz(n - 1, t) + else Nil + +fun take_lz_lz(n, ls) = lazy of () => + if n > 0 and force(ls) is + LzNil then LzNil + LzCons(h, t) then LzCons(h, take_lz_lz(n - 1, t)) + else LzNil + +fun drop_lz(n, ls) = if + n <= 0 then ls + force(ls) is + LzNil then lazy of () => LzNil + LzCons(h, t) then drop_lz(n - 1, t) + +fun splitAt_lz(n, ls) = [take_lz(n, ls), drop_lz(n, ls)] + +fun zip_lz_nl(xs, ys) = if + force(xs) is LzCons(x, xs) and ys is y :: ys then [x, y] :: zip_lz_nl(xs, ys) + else Nil + +fun zip_lz_lz(xs, ys) = if + force(xs) is LzCons(x, xs) and force(ys) is LzCons(y, ys) then lazy of () => LzCons([x, y], zip_lz_lz(xs, ys)) + else lazy of () => LzNil + +fun zipWith_lz_lz(f, xss, yss) = lazy of () => if + force(xss) is LzCons(x, xs) and (force(yss)) is LzCons(y, ys) then LzCons(f(x, y), zipWith_lz_lz(f, xs, ys)) + else LzNil + +fun zipWith_lz_nl(f, xss, yss) = if + force(xss) is LzCons(x, xs) and yss is y :: ys then f(x, y) :: zipWith_lz_nl(f, xs, ys) + else Nil + +fun iterate(f, x) = lazy of () => LzCons(x, iterate(f, f(x))) + +fun append_nl_lz(xs, ys) = if xs is + Nil then ys + h :: t then lazy of () => LzCons(h, append_nl_lz(t, ys)) + +fun append_lz_lz(xs, ys) = lazy of () => if force(xs) is + LzNil then force(ys) + LzCons(h, t) then LzCons(h, append_lz_lz(t, ys)) + +fun replicate_lz(n, x) = if n == 0 then lazy of () => LzNil else lazy of () => LzCons(x, replicate_lz(n - 1, x)) + +fun enumFrom(a) = lazy of () => LzCons(a, enumFrom(a + 1)) + +fun head_lz(ls) = if force(ls) is LzCons(h, t) then h + +fun repeat(x) = lazy of () => LzCons(x, repeat(x)) +// ===================== + // fun stringOfInt(x) = globalThis.builtin("int2str", x) // fun stringConcat(x, y) = globalThis.builtin("str_concat", x, y) // fun stringListConcat(ls) = if ls is diff --git a/hkmc2DiffTests/src/test/scala/hkmc2/LlirDiffMaker.scala b/hkmc2DiffTests/src/test/scala/hkmc2/LlirDiffMaker.scala index 90dff27e14..696c0b9a66 100644 --- a/hkmc2DiffTests/src/test/scala/hkmc2/LlirDiffMaker.scala +++ b/hkmc2DiffTests/src/test/scala/hkmc2/LlirDiffMaker.scala @@ -81,11 +81,16 @@ abstract class LlirDiffMaker extends BbmlDiffMaker: if show then output(s"\n$name:") output(cpp.toDocument.toString) - val auxPath = os.Path(rootPath)/"hkmc2"/"shared"/"src"/"test"/"mlscript-compile"/"cpp" + val rPath = os.Path(rootPath) + val auxPath = + if rPath.last == "mlscript" then + rPath/"hkmc2"/"shared"/"src"/"test"/"mlscript-compile"/"cpp" + else + rPath/"src"/"test"/"mlscript-compile"/"cpp" if write.isDefined then printToFile(java.io.File((auxPath / s"${write.get}.cpp").toString)): p => p.println(cpp.toDocument.toString) - if run then + if run then val cppHost = CppCompilerHost(auxPath.toString, output.apply) if !cppHost.ready then output("\nCpp Compilation Failed: Cpp compiler or GNU Make not found") From 951f310930b2c876455383dedebefb93a3760c49 Mon Sep 17 00:00:00 2001 From: waterlens Date: Thu, 27 Feb 2025 21:50:32 +0800 Subject: [PATCH 47/88] be able to run atom.mls --- .../scala/hkmc2/codegen/cpp/CodeGen.scala | 44 ++- .../test/mlscript-compile/cpp/mlsprelude.h | 333 +++++++++++++----- .../src/test/mlscript/llir/NofibPrelude.mls | 19 +- 3 files changed, 278 insertions(+), 118 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/CodeGen.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/CodeGen.scala index a0fe2f1ba1..f84bac22bc 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/CodeGen.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/CodeGen.scala @@ -34,6 +34,7 @@ class CppCodeGen(builtinClassSymbols: Set[Local], tl: TraceLogger): val mlsEntryPoint = s"int main() { return _mlsLargeStack(_mlsMainWrapper); }"; def mlsIntLit(x: BigInt) = Expr.Call(Expr.Var("_mlsValue::fromIntLit"), Ls(Expr.IntLit(x))) def mlsStrLit(x: Str) = Expr.Call(Expr.Var("_mlsValue::create<_mls_Str>"), Ls(Expr.StrLit(x))) + def mlsDecLit(x: BigDecimal) = Expr.Call(Expr.Var("_mlsValue::create<_mls_Float>"), Ls(Expr.DoubleLit(x.toDouble))) def mlsCharLit(x: Char) = Expr.Call(Expr.Var("_mlsValue::fromIntLit"), Ls(Expr.CharLit(x))) def mlsNewValue(cls: Str, args: Ls[Expr]) = Expr.Call(Expr.Var(s"_mlsValue::create<$cls>"), args) def mlsIsValueOf(cls: Str, scrut: Expr) = Expr.Call(Expr.Var(s"_mlsValue::isValueOf<$cls>"), Ls(scrut)) @@ -127,7 +128,7 @@ class CppCodeGen(builtinClassSymbols: Set[Local], tl: TraceLogger): case IExpr.Ref(name) => S(Expr.Var(name |> allocIfNew)) case IExpr.Literal(hkmc2.syntax.Tree.BoolLit(x)) => S(mlsIntLit(if x then 1 else 0)) case IExpr.Literal(hkmc2.syntax.Tree.IntLit(x)) => S(mlsIntLit(x)) - case IExpr.Literal(hkmc2.syntax.Tree.DecLit(x)) => S(mlsIntLit(x.toBigInt)) + case IExpr.Literal(hkmc2.syntax.Tree.DecLit(x)) => S(mlsDecLit(x)) case IExpr.Literal(hkmc2.syntax.Tree.StrLit(x)) => S(mlsStrLit(x)) case IExpr.Literal(hkmc2.syntax.Tree.UnitLit(_)) => if reifyUnit then S(mlsUnitValue) else None @@ -136,7 +137,7 @@ class CppCodeGen(builtinClassSymbols: Set[Local], tl: TraceLogger): case IExpr.Ref(name) => Expr.Var(name |> allocIfNew) case IExpr.Literal(hkmc2.syntax.Tree.BoolLit(x)) => mlsIntLit(if x then 1 else 0) case IExpr.Literal(hkmc2.syntax.Tree.IntLit(x)) => mlsIntLit(x) - case IExpr.Literal(hkmc2.syntax.Tree.DecLit(x)) => mlsIntLit(x.toBigInt) + case IExpr.Literal(hkmc2.syntax.Tree.DecLit(x)) => mlsDecLit(x) case IExpr.Literal(hkmc2.syntax.Tree.StrLit(x)) => mlsStrLit(x) case IExpr.Literal(hkmc2.syntax.Tree.UnitLit(_)) => mlsUnitValue @@ -177,23 +178,28 @@ class CppCodeGen(builtinClassSymbols: Set[Local], tl: TraceLogger): (decls, stmts2) def codegenOps(op: Local, args: Ls[TrivialExpr])(using Ctx, Raise, Scope) = - val op2 = op.nme - op2 match - case "+" => Expr.Binary("+", toExpr(args(0)), toExpr(args(1))) - case "-" => Expr.Binary("-", toExpr(args(0)), toExpr(args(1))) - case "*" => Expr.Binary("*", toExpr(args(0)), toExpr(args(1))) - case "/" => Expr.Binary("/", toExpr(args(0)), toExpr(args(1))) - case "%" => Expr.Binary("%", toExpr(args(0)), toExpr(args(1))) - case "==" | "===" => Expr.Binary("==", toExpr(args(0)), toExpr(args(1))) - case "!=" => Expr.Binary("!=", toExpr(args(0)), toExpr(args(1))) - case "<" => Expr.Binary("<", toExpr(args(0)), toExpr(args(1))) - case "<=" => Expr.Binary("<=", toExpr(args(0)), toExpr(args(1))) - case ">" => Expr.Binary(">", toExpr(args(0)), toExpr(args(1))) - case ">=" => Expr.Binary(">=", toExpr(args(0)), toExpr(args(1))) - case "&&" => Expr.Binary("&&", toExpr(args(0)), toExpr(args(1))) - case "||" => Expr.Binary("||", toExpr(args(0)), toExpr(args(1))) - case "!" => Expr.Unary("!", toExpr(args(0))) - case _ => TODO(s"codegenOps $op2") + trace[Expr](s"codegenOps $op begin"): + val op2 = op.nme + op2 match + case "+" => + if args.size == 1 then Expr.Unary("+", toExpr(args(0))) + else Expr.Binary("+", toExpr(args(0)), toExpr(args(1))) + case "-" => + if args.size == 1 then Expr.Unary("-", toExpr(args(0))) + else Expr.Binary("-", toExpr(args(0)), toExpr(args(1))) + case "*" => Expr.Binary("*", toExpr(args(0)), toExpr(args(1))) + case "/" => Expr.Binary("/", toExpr(args(0)), toExpr(args(1))) + case "%" => Expr.Binary("%", toExpr(args(0)), toExpr(args(1))) + case "==" | "===" => Expr.Binary("==", toExpr(args(0)), toExpr(args(1))) + case "!=" => Expr.Binary("!=", toExpr(args(0)), toExpr(args(1))) + case "<" => Expr.Binary("<", toExpr(args(0)), toExpr(args(1))) + case "<=" => Expr.Binary("<=", toExpr(args(0)), toExpr(args(1))) + case ">" => Expr.Binary(">", toExpr(args(0)), toExpr(args(1))) + case ">=" => Expr.Binary(">=", toExpr(args(0)), toExpr(args(1))) + case "&&" => Expr.Binary("&&", toExpr(args(0)), toExpr(args(1))) + case "||" => Expr.Binary("||", toExpr(args(0)), toExpr(args(1))) + case "!" => Expr.Unary("!", toExpr(args(0))) + case _ => TODO(s"codegenOps $op2") def codegen(expr: IExpr)(using Ctx, Raise, Scope): Expr = expr match diff --git a/hkmc2/shared/src/test/mlscript-compile/cpp/mlsprelude.h b/hkmc2/shared/src/test/mlscript-compile/cpp/mlsprelude.h index 7e1e4a4a38..e2e3f2eeae 100644 --- a/hkmc2/shared/src/test/mlscript-compile/cpp/mlsprelude.h +++ b/hkmc2/shared/src/test/mlscript-compile/cpp/mlsprelude.h @@ -6,9 +6,10 @@ #include #include #include +#include +#include #include #include -#include #include constexpr std::size_t _mlsAlignment = 8; @@ -47,6 +48,11 @@ consteval auto nextTypeTag() { return nextTypeTag(); } +constexpr static inline uint32_t unitTag = nextTypeTag(); +constexpr static inline uint32_t floatTag = nextTypeTag(); +constexpr static inline uint32_t strTag = nextTypeTag(); +constexpr static inline uint32_t lazyTag = nextTypeTag(); + struct _mlsObject { uint32_t refCount; uint32_t tag; @@ -75,15 +81,21 @@ class _mlsUtil { } }; +struct _mlsFloatShape : public _mlsObject { + double f; +}; + class _mlsValue { using uintptr_t = std::uintptr_t; using intptr_t = std::intptr_t; using int64_t = std::int64_t; - void *value alignas(_mlsAlignment); + void *value; bool isInt63() const { return (reinterpret_cast(value) & 1) == 1; } + bool isFloat() const { return isPtr() && asObject()->tag == floatTag; } + bool isPtr() const { return (reinterpret_cast(value) & 1) == 0; } int64_t asInt63() const { return reinterpret_cast(value) >> 1; } @@ -247,103 +259,41 @@ class _mlsValue { return static_cast(v.asObject()); } - _mlsValue floorDiv(const _mlsValue &other) const { - if (isInt63() && other.isInt63()) - return floorDivInt63(other); - _mlsUtil::panic("incorrect type"); - } + _mlsValue floorDiv(const _mlsValue &other) const; - _mlsValue floorMod(const _mlsValue &other) const { - if (isInt63() && other.isInt63()) - return floorModInt63(other); - _mlsUtil::panic("incorrect type"); - } + _mlsValue floorMod(const _mlsValue &other) const; - _mlsValue pow(const _mlsValue &other) const { - if (isInt63() && other.isInt63()) - return fromInt63(std::pow(asInt63(), other.asInt63())); - _mlsUtil::panic("incorrect type"); - } + _mlsValue pow(const _mlsValue &other) const; // Operators - _mlsValue operator==(const _mlsValue &other) const { - if (isInt63() && other.isInt63()) - return _mlsValue::fromBoolLit(eqInt63(other)); - _mlsUtil::panic("incorrect type"); - } + _mlsValue operator==(const _mlsValue &other) const; - _mlsValue operator!=(const _mlsValue &other) const { - if (isInt63() && other.isInt63()) - return _mlsValue::fromBoolLit(!eqInt63(other)); - _mlsUtil::panic("incorrect type"); - } + _mlsValue operator!=(const _mlsValue &other) const; - _mlsValue operator&&(const _mlsValue &other) const { - if (isInt63() && other.isInt63()) - return _mlsValue::fromBoolLit(asInt63() && other.asInt63()); - _mlsUtil::panic("incorrect type"); - } + _mlsValue operator&&(const _mlsValue &other) const; - _mlsValue operator||(const _mlsValue &other) const { - if (isInt63() && other.isInt63()) - return _mlsValue::fromBoolLit(asInt63() || other.asInt63()); - _mlsUtil::panic("incorrect type"); - } + _mlsValue operator||(const _mlsValue &other) const; - _mlsValue operator+(const _mlsValue &other) const { - if (isInt63() && other.isInt63()) - return addInt63(other); - _mlsUtil::panic("incorrect type"); - } + _mlsValue operator+(const _mlsValue &other) const; - _mlsValue operator-(const _mlsValue &other) const { - if (isInt63() && other.isInt63()) - return subInt63(other); - _mlsUtil::panic("incorrect type"); - } + _mlsValue operator-(const _mlsValue &other) const; - _mlsValue operator*(const _mlsValue &other) const { - if (isInt63() && other.isInt63()) - return mulInt63(other); - _mlsUtil::panic("incorrect type"); - } + _mlsValue operator-() const; - _mlsValue operator/(const _mlsValue &other) const { - if (isInt63() && other.isInt63()) - return divInt63(other); - _mlsUtil::panic("incorrect type"); - } + _mlsValue operator*(const _mlsValue &other) const; - _mlsValue operator%(const _mlsValue &other) const { - if (isInt63() && other.isInt63()) - return modInt63(other); - _mlsUtil::panic("incorrect type"); - } + _mlsValue operator/(const _mlsValue &other) const; - _mlsValue operator>(const _mlsValue &other) const { - if (isInt63() && other.isInt63()) - return gtInt63(other); - _mlsUtil::panic("incorrect type"); - } + _mlsValue operator%(const _mlsValue &other) const; - _mlsValue operator<(const _mlsValue &other) const { - if (isInt63() && other.isInt63()) - return ltInt63(other); - _mlsUtil::panic("incorrect type"); - } + _mlsValue operator>(const _mlsValue &other) const; - _mlsValue operator>=(const _mlsValue &other) const { - if (isInt63() && other.isInt63()) - return geInt63(other); - _mlsUtil::panic("incorrect type"); - } + _mlsValue operator<(const _mlsValue &other) const; - _mlsValue operator<=(const _mlsValue &other) const { - if (isInt63() && other.isInt63()) - return leInt63(other); - _mlsUtil::panic("incorrect type"); - } + _mlsValue operator>=(const _mlsValue &other) const; + + _mlsValue operator<=(const _mlsValue &other) const; // Auxiliary functions @@ -430,7 +380,7 @@ inline void *_mlsMainWrapper(void *) { struct _mls_Unit final : public _mlsObject { constexpr static inline const char *typeName = "Unit"; - constexpr static inline uint32_t typeTag = nextTypeTag(); + constexpr static inline uint32_t typeTag = unitTag; virtual void print() const override { std::printf(typeName); } static _mlsValue create() { static _mls_Unit mlsUnit alignas(_mlsAlignment); @@ -441,23 +391,83 @@ struct _mls_Unit final : public _mlsObject { virtual void destroy() override {} }; +struct _mls_Float final : public _mlsFloatShape { + constexpr static inline const char *typeName = "Float"; + constexpr static inline uint32_t typeTag = floatTag; + virtual void print() const override { + std::printf(typeName); + std::printf("("); + std::printf("%f", f); + std::printf(")"); + } + static _mlsValue create(double f) { + auto _mlsVal = new (std::align_val_t(_mlsAlignment)) _mls_Float; + _mlsVal->f = f; + _mlsVal->refCount = 1; + _mlsVal->tag = typeTag; + return _mlsValue(_mlsVal); + } + _mlsValue operator+(const _mls_Float &other) const { + return _mlsValue::create<_mls_Float>(f + other.f); + } + _mlsValue operator-(const _mls_Float &other) const { + return _mlsValue::create<_mls_Float>(f - other.f); + } + _mlsValue operator*(const _mls_Float &other) const { + return _mlsValue::create<_mls_Float>(f * other.f); + } + _mlsValue operator/(const _mls_Float &other) const { + return _mlsValue::create<_mls_Float>(f / other.f); + } + _mlsValue operator==(const _mls_Float &other) const { + return _mlsValue::fromBoolLit(f == other.f); + } + _mlsValue operator!=(const _mls_Float &other) const { + return _mlsValue::fromBoolLit(f == other.f); + } + _mlsValue operator>(const _mls_Float &other) const { + return _mlsValue::fromBoolLit(f > other.f); + } + _mlsValue operator<(const _mls_Float &other) const { + return _mlsValue::fromBoolLit(f < other.f); + } + _mlsValue operator>=(const _mls_Float &other) const { + return _mlsValue::fromBoolLit(f >= other.f); + } + _mlsValue operator<=(const _mls_Float &other) const { + return _mlsValue::fromBoolLit(f <= other.f); + } + virtual void destroy() override { + operator delete(this, std::align_val_t(_mlsAlignment)); + } +}; + struct _mls_Str final : public _mlsObject { std::string str; constexpr static inline const char *typeName = "Str"; - constexpr static inline uint32_t typeTag = nextTypeTag(); + constexpr static inline uint32_t typeTag = strTag; virtual void print() const override { std::printf(typeName); std::printf("("); std::printf("%s", str.c_str()); std::printf(")"); } - static _mlsValue create(const char *str) { + static _mlsValue create(const std::string_view str) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) _mls_Str; _mlsVal->str = str; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; return _mlsValue(_mlsVal); } + static _mlsValue create(const std::string_view str1, + const std::string_view str2) { + auto _mlsVal = new (std::align_val_t(_mlsAlignment)) _mls_Str; + _mlsVal->str = str1; + _mlsVal->str += str2; + _mlsVal->refCount = 1; + _mlsVal->tag = typeTag; + return _mlsValue(_mlsVal); + } virtual void destroy() override { str.~basic_string(); operator delete(this, std::align_val_t(_mlsAlignment)); @@ -469,7 +479,7 @@ struct _mls_Lazy final : public _mlsObject { _mlsValue value; bool evaluated; constexpr static inline const char *typeName = "Lazy"; - constexpr static inline uint32_t typeTag = nextTypeTag(); + constexpr static inline uint32_t typeTag = lazyTag; virtual void print() const override { std::printf(typeName); } static _mlsValue create(_mlsValue init) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) _mls_Lazy; @@ -616,6 +626,28 @@ inline _mlsValue _mls_builtin_trunc_mod(_mlsValue a, _mlsValue b) { return a % b; } +inline _mlsValue _mls_builtin_int2str(_mlsValue a) { + assert(_mlsValue::isInt(a)); + char buf[32]; + std::snprintf(buf, sizeof(buf), "%" PRIu64, a.asInt()); + return _mlsValue::create<_mls_Str>(buf); +} + +inline _mlsValue _mls_builtin_float2str(_mlsValue a) { + assert(_mlsValue::isValueOf<_mls_Float>(a)); + char buf[128]; + std::snprintf(buf, sizeof(buf), "%f", _mlsValue::cast<_mls_Float>(a)->f); + return _mlsValue::create<_mls_Str>(buf); +} + +inline _mlsValue _mls_builtin_str_concat(_mlsValue a, _mlsValue b) { + assert(_mlsValue::isValueOf<_mls_Str>(a)); + assert(_mlsValue::isValueOf<_mls_Str>(b)); + auto *strA = _mlsValue::cast<_mls_Str>(a); + auto *strB = _mlsValue::cast<_mls_Str>(b); + return _mlsValue::create<_mls_Str>(strA->str.c_str(), strB->str.c_str()); +} + inline _mlsValue _mls_builtin_z_add(_mlsValue a, _mlsValue b) { assert(_mlsValue::isValueOf<_mls_ZInt>(a)); assert(_mlsValue::isValueOf<_mls_ZInt>(b)); @@ -702,3 +734,132 @@ inline _mlsValue _mls_builtin_debug(_mlsValue a) { std::puts(""); return a; } + +inline _mlsValue _mlsValue::floorDiv(const _mlsValue &other) const { + if (isInt63() && other.isInt63()) + return floorDivInt63(other); + _mlsUtil::panic("incorrect type"); +} + +inline _mlsValue _mlsValue::floorMod(const _mlsValue &other) const { + if (isInt63() && other.isInt63()) + return floorModInt63(other); + _mlsUtil::panic("incorrect type"); +} + +inline _mlsValue _mlsValue::pow(const _mlsValue &other) const { + if (isInt63() && other.isInt63()) + return fromInt63(std::pow(asInt63(), other.asInt63())); + if (isFloat() && other.isFloat()) + return _mlsValue::create<_mls_Float>( + std::pow(as<_mls_Float>(*this)->f, as<_mls_Float>(other)->f)); + _mlsUtil::panic("incorrect type"); +} + +// Operators + +inline _mlsValue _mlsValue::operator==(const _mlsValue &other) const { + if (isInt63() && other.isInt63()) + return _mlsValue::fromBoolLit(eqInt63(other)); + if (isFloat() && other.isFloat()) + return *as<_mls_Float>(*this) == *as<_mls_Float>(other); + _mlsUtil::panic("incorrect type"); +} + +inline _mlsValue _mlsValue::operator!=(const _mlsValue &other) const { + if (isInt63() && other.isInt63()) + return _mlsValue::fromBoolLit(!eqInt63(other)); + if (isFloat() && other.isFloat()) + return *as<_mls_Float>(*this) != *as<_mls_Float>(other); + _mlsUtil::panic("incorrect type"); +} + +inline _mlsValue _mlsValue::operator&&(const _mlsValue &other) const { + if (isInt63() && other.isInt63()) + return _mlsValue::fromBoolLit(asInt63() && other.asInt63()); + _mlsUtil::panic("incorrect type"); +} + +inline _mlsValue _mlsValue::operator||(const _mlsValue &other) const { + if (isInt63() && other.isInt63()) + return _mlsValue::fromBoolLit(asInt63() || other.asInt63()); + _mlsUtil::panic("incorrect type"); +} + +inline _mlsValue _mlsValue::operator+(const _mlsValue &other) const { + if (isInt63() && other.isInt63()) + return addInt63(other); + if (isFloat() && other.isFloat()) + return *as<_mls_Float>(*this) + *as<_mls_Float>(other); + _mlsUtil::panic("incorrect type"); +} + +inline _mlsValue _mlsValue::operator-(const _mlsValue &other) const { + if (isInt63() && other.isInt63()) + return subInt63(other); + if (isFloat() && other.isFloat()) + return *as<_mls_Float>(*this) - *as<_mls_Float>(other); + _mlsUtil::panic("incorrect type"); +} + +inline _mlsValue _mlsValue::operator-() const { + if (isInt63()) + return fromInt63(-asInt63()); + if (isFloat()) + return _mlsValue::create<_mls_Float>(-as<_mls_Float>(*this)->f); + _mlsUtil::panic("incorrect type"); +} + +inline _mlsValue _mlsValue::operator*(const _mlsValue &other) const { + if (isInt63() && other.isInt63()) + return mulInt63(other); + if (isFloat() && other.isFloat()) + return *as<_mls_Float>(*this) * *as<_mls_Float>(other); + _mlsUtil::panic("incorrect type"); +} + +inline _mlsValue _mlsValue::operator/(const _mlsValue &other) const { + if (isInt63() && other.isInt63()) + return divInt63(other); + if (isFloat() && other.isFloat()) + return *as<_mls_Float>(*this) / *as<_mls_Float>(other); + _mlsUtil::panic("incorrect type"); +} + +inline _mlsValue _mlsValue::operator%(const _mlsValue &other) const { + if (isInt63() && other.isInt63()) + return modInt63(other); + _mlsUtil::panic("incorrect type"); +} + +inline _mlsValue _mlsValue::operator>(const _mlsValue &other) const { + if (isInt63() && other.isInt63()) + return gtInt63(other); + if (isFloat() && other.isFloat()) + return *as<_mls_Float>(*this) > *as<_mls_Float>(other); + _mlsUtil::panic("incorrect type"); +} + +inline _mlsValue _mlsValue::operator<(const _mlsValue &other) const { + if (isInt63() && other.isInt63()) + return ltInt63(other); + if (isFloat() && other.isFloat()) + return *as<_mls_Float>(*this) < *as<_mls_Float>(other); + _mlsUtil::panic("incorrect type"); +} + +inline _mlsValue _mlsValue::operator>=(const _mlsValue &other) const { + if (isInt63() && other.isInt63()) + return geInt63(other); + if (isFloat() && other.isFloat()) + return *as<_mls_Float>(*this) >= *as<_mls_Float>(other); + _mlsUtil::panic("incorrect type"); +} + +inline _mlsValue _mlsValue::operator<=(const _mlsValue &other) const { + if (isInt63() && other.isInt63()) + return leInt63(other); + if (isFloat() && other.isFloat()) + return *as<_mls_Float>(*this) <= *as<_mls_Float>(other); + _mlsUtil::panic("incorrect type"); +} diff --git a/hkmc2/shared/src/test/mlscript/llir/NofibPrelude.mls b/hkmc2/shared/src/test/mlscript/llir/NofibPrelude.mls index 57be414045..5da4a6ca91 100644 --- a/hkmc2/shared/src/test/mlscript/llir/NofibPrelude.mls +++ b/hkmc2/shared/src/test/mlscript/llir/NofibPrelude.mls @@ -1,5 +1,4 @@ :llir -:js // shadow the one in Predef fun not(c) = if c then false else true @@ -327,11 +326,12 @@ fun head_lz(ls) = if force(ls) is LzCons(h, t) then h fun repeat(x) = lazy of () => LzCons(x, repeat(x)) // ===================== -// fun stringOfInt(x) = globalThis.builtin("int2str", x) -// fun stringConcat(x, y) = globalThis.builtin("str_concat", x, y) -// fun stringListConcat(ls) = if ls is -// Nil then "" -// h :: t then stringConcat(h, stringListConcat(t)) +fun stringOfInt(x) = globalThis.builtin("int2str", x) +fun stringOfFloat(x) = globalThis.builtin("float2str", x) +fun stringConcat(x, y) = globalThis.builtin("str_concat", x, y) +fun stringListConcat(ls) = if ls is + Nil then "" + h :: t then stringConcat(h, stringListConcat(t)) // fun max(a, b) = Math.min(a, b) // fun min(a, b) = Math.max(a, b) @@ -342,10 +342,3 @@ fun repeat(x) = lazy of () => LzCons(x, repeat(x)) // fun cos(x) = Math.cos(x) // fun round(x) = Math.round(x) -:runWholeCpp -1 -//│ = 1 -//│ -//│ -//│ Execution succeeded: -//│ 1 From 1cb19e9a0ff6e651ca6651805f1f182532017f16 Mon Sep 17 00:00:00 2001 From: waterlens Date: Fri, 28 Feb 2025 22:52:22 +0800 Subject: [PATCH 48/88] fix some nofib tests; fix Builder; fix mutual recursion --- .../src/main/scala/hkmc2/codegen/Block.scala | 3 +- .../scala/hkmc2/codegen/cpp/CodeGen.scala | 3 + .../scala/hkmc2/codegen/llir/Builder.scala | 39 +- .../src/test/mlscript-compile/cpp/Makefile | 6 +- .../test/mlscript-compile/cpp/mlsprelude.h | 200 ++++-- .../src/test/mlscript/llir/HigherOrder.mls | 640 ++++++++++++------ .../llir/{ => nofib}/NofibPrelude.mls | 12 +- .../src/test/mlscript/llir/nofib/atom.mls | 51 ++ .../src/test/mlscript/llir/nofib/awards.mls | 176 +++++ .../test/mlscript/llir/nofib/constraints.mls | 281 ++++++++ .../src/test/scala/hkmc2/LlirDiffMaker.scala | 2 +- 11 files changed, 1137 insertions(+), 276 deletions(-) rename hkmc2/shared/src/test/mlscript/llir/{ => nofib}/NofibPrelude.mls (97%) create mode 100644 hkmc2/shared/src/test/mlscript/llir/nofib/atom.mls create mode 100644 hkmc2/shared/src/test/mlscript/llir/nofib/awards.mls create mode 100644 hkmc2/shared/src/test/mlscript/llir/nofib/constraints.mls diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Block.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Block.scala index 3a387a2b46..50b6aa526a 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Block.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Block.scala @@ -92,7 +92,8 @@ sealed abstract class Block extends Product with AutoLocated: case Assign(lhs, rhs, rest) => rhs.freeVars ++ (rest.freeVars - lhs) case AssignField(lhs, nme, rhs, rest) => lhs.freeVars ++ rhs.freeVars ++ rest.freeVars case AssignDynField(lhs, fld, arrayIdx, rhs, rest) => lhs.freeVars ++ fld.freeVars ++ rhs.freeVars ++ rest.freeVars - case Define(defn, rest) => defn.freeVars ++ rest.freeVars + case Define(defn, rest) => + defn.freeVars ++ (rest.freeVars - defn.sym) case HandleBlock(lhs, res, par, args, cls, hdr, bod, rst) => (bod.freeVars - lhs) ++ rst.freeVars ++ hdr.flatMap(_.freeVars) case HandleBlockReturn(res) => res.freeVars diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/CodeGen.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/CodeGen.scala index f84bac22bc..3eb7f896b1 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/CodeGen.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/CodeGen.scala @@ -68,6 +68,7 @@ class CppCodeGen(builtinClassSymbols: Set[Local], tl: TraceLogger): def mlsFnWrapperName(fn: Str) = s"_mlsFn_$fn" def mlsFnCreateMethod(fn: Str) = s"static _mlsValue create() { static _mlsFn_$fn mlsFn alignas(_mlsAlignment); mlsFn.refCount = stickyRefCount; mlsFn.tag = typeTag; return _mlsValue(&mlsFn); }" def mlsNeverValue(n: Int) = if (n <= 1) then Expr.Call(Expr.Var(s"_mlsValue::never"), Ls()) else Expr.Call(Expr.Var(s"_mlsValue::never<$n>"), Ls()) + val mlsThis = Expr.Var("_mlsValue(this)") case class Ctx( defnCtx: Set[Local], @@ -125,6 +126,7 @@ class CppCodeGen(builtinClassSymbols: Set[Local], tl: TraceLogger): def toExpr(texpr: TrivialExpr, reifyUnit: Bool = false)(using Ctx, Raise, Scope): Opt[Expr] = texpr match case IExpr.Ref(name) if summon[Ctx].fieldCtx.contains(name) => S(Expr.Var(name |> directName)) + case IExpr.Ref(name: BuiltinSymbol) if name.nme == "" => S(mlsThis) case IExpr.Ref(name) => S(Expr.Var(name |> allocIfNew)) case IExpr.Literal(hkmc2.syntax.Tree.BoolLit(x)) => S(mlsIntLit(if x then 1 else 0)) case IExpr.Literal(hkmc2.syntax.Tree.IntLit(x)) => S(mlsIntLit(x)) @@ -134,6 +136,7 @@ class CppCodeGen(builtinClassSymbols: Set[Local], tl: TraceLogger): def toExpr(texpr: TrivialExpr)(using Ctx, Raise, Scope): Expr = texpr match case IExpr.Ref(name) if summon[Ctx].fieldCtx.contains(name) => Expr.Var(name |> directName) + case IExpr.Ref(name: BuiltinSymbol) if name.nme == "" => mlsThis case IExpr.Ref(name) => Expr.Var(name |> allocIfNew) case IExpr.Literal(hkmc2.syntax.Tree.BoolLit(x)) => mlsIntLit(if x then 1 else 0) case IExpr.Literal(hkmc2.syntax.Tree.IntLit(x)) => mlsIntLit(x) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala index 649c6c3f22..a84aea77f5 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala @@ -100,7 +100,10 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger, uid: FreshInt): private def freeVarsFilter(fvs: Set[Local]) = trace[Set[Local]](s"freeVarsFilter begin", x => s"freeVarsFilter end: $x"): fvs.filter: - case _: (BuiltinSymbol | TopLevelSymbol | ClassSymbol | MemberSymbol[?]) => false + case _: (BuiltinSymbol | TopLevelSymbol | ClassSymbol) => false + case ms: MemberSymbol[?] => ms.defn match + case Some(d: ClassLikeDef) => false + case _ => true case x => true private def symMap(s: Local)(using ctx: Ctx)(using Raise, Scope) = @@ -241,8 +244,8 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger, uid: FreshInt): trace[Node](s"bLam begin", x => s"bLam end: ${x.show}"): val Value.Lam(params, body) = lam // Generate an auxiliary class inheriting from Callable - val freeVars = freeVarsFilter(lam.freeVars -- ctx.fn_ctx.keySet) - log(s"Match free vars: ${lam.freeVars} ${body.definedVars} ${params.params.map(p => p.sym)}") + val freeVars = freeVarsFilter(lam.freeVars -- body.definedVars -- recName.iterator -- ctx.fn_ctx.keySet) + log(s"Match free vars: ${lam.freeVars -- body.definedVars} ${ctx.fn_ctx.keySet} ${params.params.map(p => p.sym)}") val name = newClassSym(s"Lambda${nameHint.fold("")(x => "_" + x)}") val freeVarsList = freeVars.toList val args = freeVarsList.map(symMap) @@ -442,9 +445,9 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger, uid: FreshInt): case e: TrivialExpr => val nextCont = Begin(rest, ct) val jp: Local = newNamedTemp("j") - val fvset = freeVarsFilter(nextCont.freeVars) + val fvset = freeVarsFilter(nextCont.freeVars -- nextCont.definedVars -- ctx.fn_ctx.keySet) val fvs1 = fvset.toList - log(s"Match free vars: $fvset ${nextCont.freeVars} $fvs1") + log(s"Match free vars: $fvset ${nextCont.freeVars -- nextCont.definedVars} $fvs1") val new_ctx = fvs1.foldLeft(ctx)((acc, x) => acc.addName(x, x)) val fvs = fvs1.map(new_ctx.findName(_)) def cont(x: TrivialExpr)(using ctx: Ctx) = Node.Jump( @@ -530,14 +533,36 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger, uid: FreshInt): def registerFunctions(b: Block)(using ctx: Ctx)(using Raise, Scope): Ctx = b match + case Match(scrut, arms, dflt, rest) => registerFunctions(rest) + case Return(res, implct) => ctx + case Throw(exc) => ctx + case Label(label, body, rest) => registerFunctions(rest) + case Break(label) => ctx + case Continue(label) => ctx + case Begin(sub, rest) => + val ctx1 = registerFunctions(sub) + registerFunctions(rest)(using ctx1) + case TryBlock(sub, finallyDo, rest) => + val ctx1 = registerFunctions(sub) + val ctx2 = registerFunctions(finallyDo) + registerFunctions(rest)(using ctx2) + case Assign(lhs, rhs, rest) => + registerFunctions(rest) + case AssignField(lhs, nme, rhs, rest) => + registerFunctions(rest) + case AssignDynField(lhs, fld, arrayIdx, rhs, rest) => + registerFunctions(rest) case Define(fd @ FunDefn(_own, sym, params, body), rest) => if params.length == 0 then errStop(msg"Function without arguments not supported: ${params.length.toString}") val ctx2 = ctx.addFuncName(sym, params.head.params.length) log(s"Define function: ${sym.nme} -> ${ctx2}") registerFunctions(rest)(using ctx2) - case _ => - b.subBlocks.foldLeft(ctx)((ctx, rest) => registerFunctions(rest)(using ctx)) + case Define(defn, rest) => registerFunctions(rest) + case HandleBlock(lhs, res, par, args, cls, hdr, bod, rst) => + TODO("HandleBlock not supported") + case HandleBlockReturn(res) => ctx + case End(msg) => ctx def bProg(e: Program)(using Raise, Scope, Ctx): (LlirProgram, Ctx) = var ctx = summon[Ctx] diff --git a/hkmc2/shared/src/test/mlscript-compile/cpp/Makefile b/hkmc2/shared/src/test/mlscript-compile/cpp/Makefile index 45aae4802c..a1e6af7889 100644 --- a/hkmc2/shared/src/test/mlscript-compile/cpp/Makefile +++ b/hkmc2/shared/src/test/mlscript-compile/cpp/Makefile @@ -1,7 +1,7 @@ CXX := g++ -CFLAGS += -O3 -Wall -Wextra -std=c++20 -I. -Wno-inconsistent-missing-override -I/opt/homebrew/include +CFLAGS += -O3 -g -Wall -Wextra -std=c++20 -I. -Wno-inconsistent-missing-override -I/opt/homebrew/include LDFLAGS += -L/opt/homebrew/lib -LDLIBS := -lmimalloc -lgmp +LDLIBS := -lgmp -lboost_stacktrace_basic SRC := INCLUDES := mlsprelude.h DST := @@ -24,4 +24,4 @@ clean: auto: $(TARGET) $(TARGET): $(SRC) $(INCLUDES) - $(CXX) $(CFLAGS) $(LDFLAGS) $(SRC) $(LDLIBS) -o $(TARGET) + $(CXX) $(CFLAGS) $(LDFLAGS) mlsaux.cxx $(SRC) $(LDLIBS) -o $(TARGET) diff --git a/hkmc2/shared/src/test/mlscript-compile/cpp/mlsprelude.h b/hkmc2/shared/src/test/mlscript-compile/cpp/mlsprelude.h index e2e3f2eeae..85591423d1 100644 --- a/hkmc2/shared/src/test/mlscript-compile/cpp/mlsprelude.h +++ b/hkmc2/shared/src/test/mlscript-compile/cpp/mlsprelude.h @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include @@ -73,14 +74,34 @@ struct _mlsObject { virtual void destroy() = 0; }; +#define BOOST_STACKTRACE_GNU_SOURCE_NOT_REQUIRED +#include + class _mlsUtil { public: [[noreturn]] static void panic(const char *msg) { std::fprintf(stderr, "Panic: %s\n", msg); + std::string st = + boost::stacktrace::to_string(boost::stacktrace::stacktrace()); + std::fprintf(stderr, "%s\n", st.c_str()); + std::abort(); + } + [[noreturn]] static void panic_with(const char *msg, const char *func, + const char *file, int line) { + std::fprintf(stderr, "Panic: %s at %s %s:%d\n", msg, func, file, line); + std::string st = + boost::stacktrace::to_string(boost::stacktrace::stacktrace()); + std::fprintf(stderr, "%s\n", st.c_str()); std::abort(); } }; +#define _mls_assert(e) \ + (__builtin_expect(!(e), 0) \ + ? _mlsUtil::panic_with("assertion failed", __func__, \ + __ASSERT_FILE_NAME, __LINE__) \ + : (void)0) + struct _mlsFloatShape : public _mlsObject { double f; }; @@ -111,12 +132,12 @@ class _mlsValue { } void *asPtr() const { - assert(!isInt63()); + _mls_assert(!isInt63()); return value; } _mlsObject *asObject() const { - assert(isPtr()); + _mls_assert(isPtr()); return static_cast<_mlsObject *>(value); } @@ -222,7 +243,7 @@ class _mlsValue { } int64_t asInt() const { - assert(isInt63()); + _mls_assert(isInt63()); return asInt63(); } @@ -265,6 +286,8 @@ class _mlsValue { _mlsValue pow(const _mlsValue &other) const; + _mlsValue abs() const; + // Operators _mlsValue operator==(const _mlsValue &other) const; @@ -447,10 +470,51 @@ struct _mls_Str final : public _mlsObject { constexpr static inline const char *typeName = "Str"; constexpr static inline uint32_t typeTag = strTag; virtual void print() const override { - std::printf(typeName); - std::printf("("); - std::printf("%s", str.c_str()); - std::printf(")"); + std::printf("\""); + for (const auto c : str) { + switch (c) { + case '\'': + std::printf("\\\'"); + break; + case '\"': + std::printf("\\\""); + break; + case '\?': + std::printf("\\\?"); + break; + case '\\': + std::printf("\\\\"); + break; + case '\a': + std::printf("\\a"); + break; + case '\b': + std::printf("\\b"); + break; + case '\f': + std::printf("\\f"); + break; + case '\n': + std::printf("\\n"); + break; + case '\r': + std::printf("\\r"); + break; + case '\t': + std::printf("\\t"); + break; + case '\v': + std::printf("\\v"); + break; + default: + if (c < 32 || c > 126) + std::printf("\\x%02x", c); + else + std::putchar(c); + } + } + std::printf("\""); + std::fflush(stdout); } static _mlsValue create(const std::string_view str) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) _mls_Str; @@ -596,125 +660,119 @@ struct _mls_ZInt final : public _mlsObject { _mlsUtil::panic("Non-exhaustive match"); } -inline _mlsValue _mls_builtin_pow(_mlsValue a, _mlsValue b) { - assert(_mlsValue::isInt(a)); - assert(_mlsValue::isInt(b)); - return a.pow(b); -} +inline _mlsValue _mls_builtin_pow(_mlsValue a, _mlsValue b) { return a.pow(b); } + +inline _mlsValue _mls_builtin_abs(_mlsValue a) { return a.abs(); } inline _mlsValue _mls_builtin_floor_div(_mlsValue a, _mlsValue b) { - assert(_mlsValue::isInt(a)); - assert(_mlsValue::isInt(b)); return a.floorDiv(b); } inline _mlsValue _mls_builtin_floor_mod(_mlsValue a, _mlsValue b) { - assert(_mlsValue::isInt(a)); - assert(_mlsValue::isInt(b)); return a.floorMod(b); } inline _mlsValue _mls_builtin_trunc_div(_mlsValue a, _mlsValue b) { - assert(_mlsValue::isInt(a)); - assert(_mlsValue::isInt(b)); + _mls_assert(_mlsValue::isInt(a)); + _mls_assert(_mlsValue::isInt(b)); return a / b; } inline _mlsValue _mls_builtin_trunc_mod(_mlsValue a, _mlsValue b) { - assert(_mlsValue::isInt(a)); - assert(_mlsValue::isInt(b)); + _mls_assert(_mlsValue::isInt(a)); + _mls_assert(_mlsValue::isInt(b)); return a % b; } inline _mlsValue _mls_builtin_int2str(_mlsValue a) { - assert(_mlsValue::isInt(a)); + _mls_assert(_mlsValue::isInt(a)); char buf[32]; std::snprintf(buf, sizeof(buf), "%" PRIu64, a.asInt()); return _mlsValue::create<_mls_Str>(buf); } inline _mlsValue _mls_builtin_float2str(_mlsValue a) { - assert(_mlsValue::isValueOf<_mls_Float>(a)); + _mls_assert(_mlsValue::isValueOf<_mls_Float>(a)); char buf[128]; std::snprintf(buf, sizeof(buf), "%f", _mlsValue::cast<_mls_Float>(a)->f); return _mlsValue::create<_mls_Str>(buf); } inline _mlsValue _mls_builtin_str_concat(_mlsValue a, _mlsValue b) { - assert(_mlsValue::isValueOf<_mls_Str>(a)); - assert(_mlsValue::isValueOf<_mls_Str>(b)); + _mls_assert(_mlsValue::isValueOf<_mls_Str>(a)); + _mls_assert(_mlsValue::isValueOf<_mls_Str>(b)); auto *strA = _mlsValue::cast<_mls_Str>(a); auto *strB = _mlsValue::cast<_mls_Str>(b); return _mlsValue::create<_mls_Str>(strA->str.c_str(), strB->str.c_str()); } inline _mlsValue _mls_builtin_z_add(_mlsValue a, _mlsValue b) { - assert(_mlsValue::isValueOf<_mls_ZInt>(a)); - assert(_mlsValue::isValueOf<_mls_ZInt>(b)); + _mls_assert(_mlsValue::isValueOf<_mls_ZInt>(a)); + _mls_assert(_mlsValue::isValueOf<_mls_ZInt>(b)); return *_mlsValue::cast<_mls_ZInt>(a) + *_mlsValue::cast<_mls_ZInt>(b); } inline _mlsValue _mls_builtin_z_sub(_mlsValue a, _mlsValue b) { - assert(_mlsValue::isValueOf<_mls_ZInt>(a)); - assert(_mlsValue::isValueOf<_mls_ZInt>(b)); + _mls_assert(_mlsValue::isValueOf<_mls_ZInt>(a)); + _mls_assert(_mlsValue::isValueOf<_mls_ZInt>(b)); return *_mlsValue::cast<_mls_ZInt>(a) - *_mlsValue::cast<_mls_ZInt>(b); } inline _mlsValue _mls_builtin_z_mul(_mlsValue a, _mlsValue b) { - assert(_mlsValue::isValueOf<_mls_ZInt>(a)); - assert(_mlsValue::isValueOf<_mls_ZInt>(b)); + _mls_assert(_mlsValue::isValueOf<_mls_ZInt>(a)); + _mls_assert(_mlsValue::isValueOf<_mls_ZInt>(b)); return *_mlsValue::cast<_mls_ZInt>(a) * *_mlsValue::cast<_mls_ZInt>(b); } inline _mlsValue _mls_builtin_z_div(_mlsValue a, _mlsValue b) { - assert(_mlsValue::isValueOf<_mls_ZInt>(a)); - assert(_mlsValue::isValueOf<_mls_ZInt>(b)); + _mls_assert(_mlsValue::isValueOf<_mls_ZInt>(a)); + _mls_assert(_mlsValue::isValueOf<_mls_ZInt>(b)); return *_mlsValue::cast<_mls_ZInt>(a) / *_mlsValue::cast<_mls_ZInt>(b); } inline _mlsValue _mls_builtin_z_mod(_mlsValue a, _mlsValue b) { - assert(_mlsValue::isValueOf<_mls_ZInt>(a)); - assert(_mlsValue::isValueOf<_mls_ZInt>(b)); + _mls_assert(_mlsValue::isValueOf<_mls_ZInt>(a)); + _mls_assert(_mlsValue::isValueOf<_mls_ZInt>(b)); return *_mlsValue::cast<_mls_ZInt>(a) % *_mlsValue::cast<_mls_ZInt>(b); } inline _mlsValue _mls_builtin_z_equal(_mlsValue a, _mlsValue b) { - assert(_mlsValue::isValueOf<_mls_ZInt>(a)); - assert(_mlsValue::isValueOf<_mls_ZInt>(b)); + _mls_assert(_mlsValue::isValueOf<_mls_ZInt>(a)); + _mls_assert(_mlsValue::isValueOf<_mls_ZInt>(b)); return *_mlsValue::cast<_mls_ZInt>(a) == *_mlsValue::cast<_mls_ZInt>(b); } inline _mlsValue _mls_builtin_z_gt(_mlsValue a, _mlsValue b) { - assert(_mlsValue::isValueOf<_mls_ZInt>(a)); - assert(_mlsValue::isValueOf<_mls_ZInt>(b)); + _mls_assert(_mlsValue::isValueOf<_mls_ZInt>(a)); + _mls_assert(_mlsValue::isValueOf<_mls_ZInt>(b)); return *_mlsValue::cast<_mls_ZInt>(a) > *_mlsValue::cast<_mls_ZInt>(b); } inline _mlsValue _mls_builtin_z_lt(_mlsValue a, _mlsValue b) { - assert(_mlsValue::isValueOf<_mls_ZInt>(a)); - assert(_mlsValue::isValueOf<_mls_ZInt>(b)); + _mls_assert(_mlsValue::isValueOf<_mls_ZInt>(a)); + _mls_assert(_mlsValue::isValueOf<_mls_ZInt>(b)); return *_mlsValue::cast<_mls_ZInt>(a) < *_mlsValue::cast<_mls_ZInt>(b); } inline _mlsValue _mls_builtin_z_geq(_mlsValue a, _mlsValue b) { - assert(_mlsValue::isValueOf<_mls_ZInt>(a)); - assert(_mlsValue::isValueOf<_mls_ZInt>(b)); + _mls_assert(_mlsValue::isValueOf<_mls_ZInt>(a)); + _mls_assert(_mlsValue::isValueOf<_mls_ZInt>(b)); return *_mlsValue::cast<_mls_ZInt>(a) >= *_mlsValue::cast<_mls_ZInt>(b); } inline _mlsValue _mls_builtin_z_leq(_mlsValue a, _mlsValue b) { - assert(_mlsValue::isValueOf<_mls_ZInt>(a)); - assert(_mlsValue::isValueOf<_mls_ZInt>(b)); + _mls_assert(_mlsValue::isValueOf<_mls_ZInt>(a)); + _mls_assert(_mlsValue::isValueOf<_mls_ZInt>(b)); return *_mlsValue::cast<_mls_ZInt>(a) <= *_mlsValue::cast<_mls_ZInt>(b); } inline _mlsValue _mls_builtin_z_to_int(_mlsValue a) { - assert(_mlsValue::isValueOf<_mls_ZInt>(a)); + _mls_assert(_mlsValue::isValueOf<_mls_ZInt>(a)); return _mlsValue::cast<_mls_ZInt>(a)->toInt(); } inline _mlsValue _mls_builtin_z_of_int(_mlsValue a) { - assert(_mlsValue::isInt(a)); + _mls_assert(_mlsValue::isInt(a)); return _mlsValue::create<_mls_ZInt>(a); } @@ -738,13 +796,13 @@ inline _mlsValue _mls_builtin_debug(_mlsValue a) { inline _mlsValue _mlsValue::floorDiv(const _mlsValue &other) const { if (isInt63() && other.isInt63()) return floorDivInt63(other); - _mlsUtil::panic("incorrect type"); + _mls_assert(false); } inline _mlsValue _mlsValue::floorMod(const _mlsValue &other) const { if (isInt63() && other.isInt63()) return floorModInt63(other); - _mlsUtil::panic("incorrect type"); + _mls_assert(false); } inline _mlsValue _mlsValue::pow(const _mlsValue &other) const { @@ -753,7 +811,15 @@ inline _mlsValue _mlsValue::pow(const _mlsValue &other) const { if (isFloat() && other.isFloat()) return _mlsValue::create<_mls_Float>( std::pow(as<_mls_Float>(*this)->f, as<_mls_Float>(other)->f)); - _mlsUtil::panic("incorrect type"); + _mls_assert(false); +} + +inline _mlsValue _mlsValue::abs() const { + if (isInt63()) + return absInt63(); + if (isFloat()) + return _mlsValue::create<_mls_Float>(std::abs(as<_mls_Float>(*this)->f)); + _mls_assert(false); } // Operators @@ -763,7 +829,11 @@ inline _mlsValue _mlsValue::operator==(const _mlsValue &other) const { return _mlsValue::fromBoolLit(eqInt63(other)); if (isFloat() && other.isFloat()) return *as<_mls_Float>(*this) == *as<_mls_Float>(other); - _mlsUtil::panic("incorrect type"); + bool sameTag = + isPtr() && other.isPtr() && asObject()->tag == other.asObject()->tag; + if (!sameTag) + return _mlsValue::fromBoolLit(false); + _mls_assert(false); } inline _mlsValue _mlsValue::operator!=(const _mlsValue &other) const { @@ -771,19 +841,23 @@ inline _mlsValue _mlsValue::operator!=(const _mlsValue &other) const { return _mlsValue::fromBoolLit(!eqInt63(other)); if (isFloat() && other.isFloat()) return *as<_mls_Float>(*this) != *as<_mls_Float>(other); - _mlsUtil::panic("incorrect type"); + bool sameTag = + isPtr() && other.isPtr() && asObject()->tag == other.asObject()->tag; + if (!sameTag) + return _mlsValue::fromBoolLit(true); + _mls_assert(false); } inline _mlsValue _mlsValue::operator&&(const _mlsValue &other) const { if (isInt63() && other.isInt63()) return _mlsValue::fromBoolLit(asInt63() && other.asInt63()); - _mlsUtil::panic("incorrect type"); + _mls_assert(false); } inline _mlsValue _mlsValue::operator||(const _mlsValue &other) const { if (isInt63() && other.isInt63()) return _mlsValue::fromBoolLit(asInt63() || other.asInt63()); - _mlsUtil::panic("incorrect type"); + _mls_assert(false); } inline _mlsValue _mlsValue::operator+(const _mlsValue &other) const { @@ -791,7 +865,7 @@ inline _mlsValue _mlsValue::operator+(const _mlsValue &other) const { return addInt63(other); if (isFloat() && other.isFloat()) return *as<_mls_Float>(*this) + *as<_mls_Float>(other); - _mlsUtil::panic("incorrect type"); + _mls_assert(false); } inline _mlsValue _mlsValue::operator-(const _mlsValue &other) const { @@ -799,7 +873,7 @@ inline _mlsValue _mlsValue::operator-(const _mlsValue &other) const { return subInt63(other); if (isFloat() && other.isFloat()) return *as<_mls_Float>(*this) - *as<_mls_Float>(other); - _mlsUtil::panic("incorrect type"); + _mls_assert(false); } inline _mlsValue _mlsValue::operator-() const { @@ -807,7 +881,7 @@ inline _mlsValue _mlsValue::operator-() const { return fromInt63(-asInt63()); if (isFloat()) return _mlsValue::create<_mls_Float>(-as<_mls_Float>(*this)->f); - _mlsUtil::panic("incorrect type"); + _mls_assert(false); } inline _mlsValue _mlsValue::operator*(const _mlsValue &other) const { @@ -815,7 +889,7 @@ inline _mlsValue _mlsValue::operator*(const _mlsValue &other) const { return mulInt63(other); if (isFloat() && other.isFloat()) return *as<_mls_Float>(*this) * *as<_mls_Float>(other); - _mlsUtil::panic("incorrect type"); + _mls_assert(false); } inline _mlsValue _mlsValue::operator/(const _mlsValue &other) const { @@ -823,13 +897,13 @@ inline _mlsValue _mlsValue::operator/(const _mlsValue &other) const { return divInt63(other); if (isFloat() && other.isFloat()) return *as<_mls_Float>(*this) / *as<_mls_Float>(other); - _mlsUtil::panic("incorrect type"); + _mls_assert(false); } inline _mlsValue _mlsValue::operator%(const _mlsValue &other) const { if (isInt63() && other.isInt63()) return modInt63(other); - _mlsUtil::panic("incorrect type"); + _mls_assert(false); } inline _mlsValue _mlsValue::operator>(const _mlsValue &other) const { @@ -837,7 +911,7 @@ inline _mlsValue _mlsValue::operator>(const _mlsValue &other) const { return gtInt63(other); if (isFloat() && other.isFloat()) return *as<_mls_Float>(*this) > *as<_mls_Float>(other); - _mlsUtil::panic("incorrect type"); + _mls_assert(false); } inline _mlsValue _mlsValue::operator<(const _mlsValue &other) const { @@ -845,7 +919,7 @@ inline _mlsValue _mlsValue::operator<(const _mlsValue &other) const { return ltInt63(other); if (isFloat() && other.isFloat()) return *as<_mls_Float>(*this) < *as<_mls_Float>(other); - _mlsUtil::panic("incorrect type"); + _mls_assert(false); } inline _mlsValue _mlsValue::operator>=(const _mlsValue &other) const { @@ -853,7 +927,7 @@ inline _mlsValue _mlsValue::operator>=(const _mlsValue &other) const { return geInt63(other); if (isFloat() && other.isFloat()) return *as<_mls_Float>(*this) >= *as<_mls_Float>(other); - _mlsUtil::panic("incorrect type"); + _mls_assert(false); } inline _mlsValue _mlsValue::operator<=(const _mlsValue &other) const { @@ -861,5 +935,5 @@ inline _mlsValue _mlsValue::operator<=(const _mlsValue &other) const { return leInt63(other); if (isFloat() && other.isFloat()) return *as<_mls_Float>(*this) <= *as<_mls_Float>(other); - _mlsUtil::panic("incorrect type"); + _mls_assert(false); } diff --git a/hkmc2/shared/src/test/mlscript/llir/HigherOrder.mls b/hkmc2/shared/src/test/mlscript/llir/HigherOrder.mls index 6b21b9a84b..958ee31c9f 100644 --- a/hkmc2/shared/src/test/mlscript/llir/HigherOrder.mls +++ b/hkmc2/shared/src/test/mlscript/llir/HigherOrder.mls @@ -12,25 +12,25 @@ fun add_curried(x)(y) = x + y add(1)(2) //│ = 3 //│ LLIR: -//│ class Lambda(x$220) extends Callable { -//│ def apply1$240(y$221) = -//│ let x$241 = +(x$220,y$221) in -//│ x$241 +//│ class Lambda(lam_arg0$240) extends Callable { +//│ def apply1$241(y$221) = +//│ let x$242 = +(lam_arg0$240,y$221) in +//│ x$242 //│ } -//│ class Lambda(x$224) extends Callable { -//│ def apply1$240(y$225) = -//│ let x$246 = +(x$224,y$225) in -//│ x$246 +//│ class Lambda(lam_arg0$247) extends Callable { +//│ def apply1$241(y$225) = +//│ let x$248 = +(lam_arg0$247,y$225) in +//│ x$248 //│ } //│ def add$218(x$220) = -//│ let x$243 = Lambda$238(x$220) in -//│ x$243 +//│ let x$244 = Lambda$238(x$220) in +//│ x$244 //│ def add_curried$219(x$224) = -//│ let x$247 = Lambda$244(x$224) in -//│ x$247 -//│ let* (x$248) = add(1) in -//│ let x$249 = Callable.apply1$240(x$248,2) in -//│ x$249 +//│ let x$249 = Lambda$245(x$224) in +//│ x$249 +//│ let* (x$250) = add(1) in +//│ let x$251 = Callable.apply1$241(x$250,2) in +//│ x$251 //│ //│ Cpp: //│ #include "mlsprelude.h" @@ -40,45 +40,45 @@ add(1)(2) //│ _mlsValue _mls_add_curried(_mlsValue); //│ _mlsValue _mlsMain(); //│ struct _mls_Lambda: public _mls_Callable { -//│ _mlsValue _mls_x; +//│ _mlsValue _mls_lam_arg0; //│ constexpr static inline const char *typeName = "Lambda"; //│ constexpr static inline uint32_t typeTag = nextTypeTag(); -//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->_mls_x.print(); std::printf(")"); } -//│ virtual void destroy() override { _mlsValue::destroy(this->_mls_x); operator delete (this, std::align_val_t(_mlsAlignment)); } -//│ static _mlsValue create(_mlsValue _mls_x) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) _mls_Lambda; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->_mls_x = _mls_x; return _mlsValue(_mlsVal); } +//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->_mls_lam_arg0.print(); std::printf(")"); } +//│ virtual void destroy() override { _mlsValue::destroy(this->_mls_lam_arg0); operator delete (this, std::align_val_t(_mlsAlignment)); } +//│ static _mlsValue create(_mlsValue _mls_lam_arg0) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) _mls_Lambda; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->_mls_lam_arg0 = _mls_lam_arg0; return _mlsValue(_mlsVal); } //│ virtual _mlsValue _mls_apply1(_mlsValue); //│ }; //│ struct _mls_Lambda1: public _mls_Callable { -//│ _mlsValue _mls_x; +//│ _mlsValue _mls_lam_arg0; //│ constexpr static inline const char *typeName = "Lambda"; //│ constexpr static inline uint32_t typeTag = nextTypeTag(); -//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->_mls_x.print(); std::printf(")"); } -//│ virtual void destroy() override { _mlsValue::destroy(this->_mls_x); operator delete (this, std::align_val_t(_mlsAlignment)); } -//│ static _mlsValue create(_mlsValue _mls_x) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) _mls_Lambda1; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->_mls_x = _mls_x; return _mlsValue(_mlsVal); } +//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->_mls_lam_arg0.print(); std::printf(")"); } +//│ virtual void destroy() override { _mlsValue::destroy(this->_mls_lam_arg0); operator delete (this, std::align_val_t(_mlsAlignment)); } +//│ static _mlsValue create(_mlsValue _mls_lam_arg0) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) _mls_Lambda1; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->_mls_lam_arg0 = _mls_lam_arg0; return _mlsValue(_mlsVal); } //│ virtual _mlsValue _mls_apply1(_mlsValue); //│ }; -//│ _mlsValue _mls_add(_mlsValue _mls_x) { +//│ _mlsValue _mls_add(_mlsValue _mls_x3) { //│ _mlsValue _mls_retval; -//│ auto _mls_x4 = _mlsValue::create<_mls_Lambda>(_mls_x); -//│ _mls_retval = _mls_x4; +//│ auto _mls_x2 = _mlsValue::create<_mls_Lambda>(_mls_x3); +//│ _mls_retval = _mls_x2; //│ return _mls_retval; //│ } -//│ _mlsValue _mls_add_curried(_mlsValue _mls_x2) { +//│ _mlsValue _mls_add_curried(_mlsValue _mls_x5) { //│ _mlsValue _mls_retval; -//│ auto _mls_x5 = _mlsValue::create<_mls_Lambda1>(_mls_x2); -//│ _mls_retval = _mls_x5; +//│ auto _mls_x4 = _mlsValue::create<_mls_Lambda1>(_mls_x5); +//│ _mls_retval = _mls_x4; //│ return _mls_retval; //│ } //│ _mlsValue _mls_Lambda::_mls_apply1(_mlsValue _mls_y) { //│ _mlsValue _mls_retval; -//│ auto _mls_x1 = (_mls_x + _mls_y); -//│ _mls_retval = _mls_x1; +//│ auto _mls_x = (_mls_lam_arg0 + _mls_y); +//│ _mls_retval = _mls_x; //│ return _mls_retval; //│ } //│ _mlsValue _mls_Lambda1::_mls_apply1(_mlsValue _mls_y1) { //│ _mlsValue _mls_retval; -//│ auto _mls_x3 = (_mls_x + _mls_y1); -//│ _mls_retval = _mls_x3; +//│ auto _mls_x1 = (_mls_lam_arg0 + _mls_y1); +//│ _mls_retval = _mls_x1; //│ return _mls_retval; //│ } //│ _mlsValue _mlsMain() { @@ -101,29 +101,29 @@ fun add4_curried(a, b)(c, d) = a + b + c + d add4(1, 2)(3, 4) //│ = 10 //│ LLIR: -//│ class Lambda(b$253,a$252) extends Callable { -//│ def apply2$288(c$254,d$255) = -//│ let x$289 = +(a$252,b$253) in -//│ let x$290 = +(x$289,c$254) in -//│ let x$291 = +(x$290,d$255) in -//│ x$291 +//│ class Lambda(lam_arg0$290,lam_arg1$291) extends Callable { +//│ def apply2$292(c$256,d$257) = +//│ let x$293 = +(lam_arg1$291,lam_arg0$290) in +//│ let x$294 = +(x$293,c$256) in +//│ let x$295 = +(x$294,d$257) in +//│ x$295 //│ } -//│ class Lambda(b$261,a$260) extends Callable { -//│ def apply2$288(c$262,d$263) = -//│ let x$295 = +(a$260,b$261) in -//│ let x$296 = +(x$295,c$262) in -//│ let x$297 = +(x$296,d$263) in -//│ x$297 +//│ class Lambda(lam_arg0$299,lam_arg1$300) extends Callable { +//│ def apply2$292(c$264,d$265) = +//│ let x$301 = +(lam_arg1$300,lam_arg0$299) in +//│ let x$302 = +(x$301,c$264) in +//│ let x$303 = +(x$302,d$265) in +//│ x$303 //│ } -//│ def add4$251(a$252,b$253) = -//│ let x$292 = Lambda$286(b$253,a$252) in -//│ x$292 -//│ def add4_curried$250(a$260,b$261) = -//│ let x$298 = Lambda$293(b$261,a$260) in -//│ x$298 -//│ let* (x$299) = add4(1,2) in -//│ let x$300 = Callable.apply2$288(x$299,3,4) in -//│ x$300 +//│ def add4$253(a$254,b$255) = +//│ let x$296 = Lambda$288(b$255,a$254) in +//│ x$296 +//│ def add4_curried$252(a$262,b$263) = +//│ let x$304 = Lambda$297(b$263,a$262) in +//│ x$304 +//│ let* (x$305) = add4(1,2) in +//│ let x$306 = Callable.apply2$292(x$305,3,4) in +//│ x$306 //│ //│ Cpp: //│ #include "mlsprelude.h" @@ -133,23 +133,23 @@ add4(1, 2)(3, 4) //│ _mlsValue _mls_add4_curried(_mlsValue, _mlsValue); //│ _mlsValue _mlsMain(); //│ struct _mls_Lambda2: public _mls_Callable { -//│ _mlsValue _mls_b; -//│ _mlsValue _mls_a; +//│ _mlsValue _mls_lam_arg0; +//│ _mlsValue _mls_lam_arg1; //│ constexpr static inline const char *typeName = "Lambda"; //│ constexpr static inline uint32_t typeTag = nextTypeTag(); -//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->_mls_b.print(); std::printf(", "); this->_mls_a.print(); std::printf(")"); } -//│ virtual void destroy() override { _mlsValue::destroy(this->_mls_b); _mlsValue::destroy(this->_mls_a); operator delete (this, std::align_val_t(_mlsAlignment)); } -//│ static _mlsValue create(_mlsValue _mls_b, _mlsValue _mls_a) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) _mls_Lambda2; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->_mls_b = _mls_b; _mlsVal->_mls_a = _mls_a; return _mlsValue(_mlsVal); } +//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->_mls_lam_arg0.print(); std::printf(", "); this->_mls_lam_arg1.print(); std::printf(")"); } +//│ virtual void destroy() override { _mlsValue::destroy(this->_mls_lam_arg0); _mlsValue::destroy(this->_mls_lam_arg1); operator delete (this, std::align_val_t(_mlsAlignment)); } +//│ static _mlsValue create(_mlsValue _mls_lam_arg0, _mlsValue _mls_lam_arg1) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) _mls_Lambda2; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->_mls_lam_arg0 = _mls_lam_arg0; _mlsVal->_mls_lam_arg1 = _mls_lam_arg1; return _mlsValue(_mlsVal); } //│ virtual _mlsValue _mls_apply2(_mlsValue, _mlsValue); //│ }; //│ struct _mls_Lambda3: public _mls_Callable { -//│ _mlsValue _mls_b; -//│ _mlsValue _mls_a; +//│ _mlsValue _mls_lam_arg0; +//│ _mlsValue _mls_lam_arg1; //│ constexpr static inline const char *typeName = "Lambda"; //│ constexpr static inline uint32_t typeTag = nextTypeTag(); -//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->_mls_b.print(); std::printf(", "); this->_mls_a.print(); std::printf(")"); } -//│ virtual void destroy() override { _mlsValue::destroy(this->_mls_b); _mlsValue::destroy(this->_mls_a); operator delete (this, std::align_val_t(_mlsAlignment)); } -//│ static _mlsValue create(_mlsValue _mls_b, _mlsValue _mls_a) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) _mls_Lambda3; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->_mls_b = _mls_b; _mlsVal->_mls_a = _mls_a; return _mlsValue(_mlsVal); } +//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->_mls_lam_arg0.print(); std::printf(", "); this->_mls_lam_arg1.print(); std::printf(")"); } +//│ virtual void destroy() override { _mlsValue::destroy(this->_mls_lam_arg0); _mlsValue::destroy(this->_mls_lam_arg1); operator delete (this, std::align_val_t(_mlsAlignment)); } +//│ static _mlsValue create(_mlsValue _mls_lam_arg0, _mlsValue _mls_lam_arg1) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) _mls_Lambda3; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->_mls_lam_arg0 = _mls_lam_arg0; _mlsVal->_mls_lam_arg1 = _mls_lam_arg1; return _mlsValue(_mlsVal); } //│ virtual _mlsValue _mls_apply2(_mlsValue, _mlsValue); //│ }; //│ _mlsValue _mls_add4(_mlsValue _mls_a, _mlsValue _mls_b) { @@ -166,7 +166,7 @@ add4(1, 2)(3, 4) //│ } //│ _mlsValue _mls_Lambda2::_mls_apply2(_mlsValue _mls_c, _mlsValue _mls_d) { //│ _mlsValue _mls_retval; -//│ auto _mls_x8 = (_mls_a + _mls_b); +//│ auto _mls_x8 = (_mls_lam_arg1 + _mls_lam_arg0); //│ auto _mls_x9 = (_mls_x8 + _mls_c); //│ auto _mls_x10 = (_mls_x9 + _mls_d); //│ _mls_retval = _mls_x10; @@ -174,7 +174,7 @@ add4(1, 2)(3, 4) //│ } //│ _mlsValue _mls_Lambda3::_mls_apply2(_mlsValue _mls_c1, _mlsValue _mls_d1) { //│ _mlsValue _mls_retval; -//│ auto _mls_x11 = (_mls_a + _mls_b); +//│ auto _mls_x11 = (_mls_lam_arg1 + _mls_lam_arg0); //│ auto _mls_x12 = (_mls_x11 + _mls_c1); //│ auto _mls_x13 = (_mls_x12 + _mls_d1); //│ _mls_retval = _mls_x13; @@ -201,19 +201,19 @@ dummy()(1, 2) //│ = 3 //│ LLIR: //│ class Lambda_add() extends Callable { -//│ def apply2$288(arg$319,arg$320) = -//│ let* (x$323) = add(arg$319,arg$320) in -//│ x$323 +//│ def apply2$292(arg$325,arg$326) = +//│ let* (x$329) = add(arg$325,arg$326) in +//│ x$329 //│ } -//│ def add$301(a$303,b$304) = -//│ let x$318 = +(a$303,b$304) in -//│ x$318 -//│ def dummy$302() = -//│ let x$324 = Lambda_add$321() in +//│ def add$307(a$309,b$310) = +//│ let x$324 = +(a$309,b$310) in //│ x$324 -//│ let* (x$325) = dummy() in -//│ let x$326 = Callable.apply2$288(x$325,1,2) in -//│ x$326 +//│ def dummy$308() = +//│ let x$330 = Lambda_add$327() in +//│ x$330 +//│ let* (x$331) = dummy() in +//│ let x$332 = Callable.apply2$292(x$331,1,2) in +//│ x$332 //│ //│ Cpp: //│ #include "mlsprelude.h" @@ -277,55 +277,55 @@ main() //│ = Cons(4, Cons(5, Nil)) //│ LLIR: //│ class List() -//│ class Cons(head$339,tail$340) extends List +//│ class Cons(head$345,tail$346) extends List //│ class Nil() extends List //│ class Lambda() extends Callable { -//│ def apply1$240(x$357) = -//│ let* (x$422) = inc(x$357) in -//│ x$422 +//│ def apply1$241(x$363) = +//│ let* (x$428) = inc(x$363) in +//│ x$428 //│ } //│ class Lambda_inc() extends Callable { -//│ def apply1$240(arg$428) = -//│ let* (x$431) = inc(arg$428) in -//│ x$431 +//│ def apply1$241(arg$434) = +//│ let* (x$437) = inc(arg$434) in +//│ x$437 //│ } -//│ def map$328(f$343,l$344) = -//│ case l$344 of -//│ Cons$336 => -//│ let x$408 = l$344. in -//│ let x$409 = l$344. in -//│ let x$410 = Callable.apply1$240(f$343,x$408) in -//│ let* (x$411) = map(f$343,x$409) in -//│ let x$412 = Cons$336(x$410,x$411) in -//│ x$412 +//│ def map$334(f$349,l$350) = +//│ case l$350 of +//│ Cons$342 => +//│ let x$414 = l$350. in +//│ let x$415 = l$350. in +//│ let x$416 = Callable.apply1$241(f$349,x$414) in +//│ let* (x$417) = map(f$349,x$415) in +//│ let x$418 = Cons$342(x$416,x$417) in +//│ x$418 //│ _ => -//│ case l$344 of -//│ Nil$341 => -//│ let x$414 = Nil$341() in -//│ x$414 +//│ case l$350 of +//│ Nil$347 => +//│ let x$420 = Nil$347() in +//│ x$420 //│ _ => //│ panic "match error" +//│ def j$419() = +//│ jump j$413() //│ def j$413() = -//│ jump j$407() -//│ def j$407() = //│ null -//│ def inc$331(x$353) = -//│ let x$415 = +(x$353,1) in -//│ x$415 -//│ def main$329() = -//│ let x$416 = Nil$341() in -//│ let x$417 = Cons$336(2,x$416) in -//│ let x$418 = Cons$336(1,x$417) in -//│ let x$423 = Lambda$420() in -//│ let* (x$419) = map(x$423,x$418) in -//│ let x$424 = Nil$341() in -//│ let x$425 = Cons$336(4,x$424) in -//│ let x$426 = Cons$336(3,x$425) in -//│ let x$432 = Lambda_inc$429() in -//│ let* (x$427) = map(x$432,x$426) in -//│ x$427 -//│ let* (x$433) = main() in -//│ x$433 +//│ def inc$337(x$359) = +//│ let x$421 = +(x$359,1) in +//│ x$421 +//│ def main$335() = +//│ let x$422 = Nil$347() in +//│ let x$423 = Cons$342(2,x$422) in +//│ let x$424 = Cons$342(1,x$423) in +//│ let x$429 = Lambda$426() in +//│ let* (x$425) = map(x$429,x$424) in +//│ let x$430 = Nil$347() in +//│ let x$431 = Cons$342(4,x$430) in +//│ let x$432 = Cons$342(3,x$431) in +//│ let x$438 = Lambda_inc$435() in +//│ let* (x$433) = map(x$438,x$432) in +//│ x$433 +//│ let* (x$439) = main() in +//│ x$439 //│ //│ Interpreted: //│ Cons(4,Cons(5,Nil())) @@ -349,83 +349,83 @@ nubBy((x, y) => x == y, 1 :: 2 :: 3 :: 3 :: Nil) //│ = Cons(1, Cons(2, Cons(3, Nil))) //│ LLIR: //│ class List() -//│ class Cons(head$446,tail$447) extends List +//│ class Cons(head$452,tail$453) extends List //│ class Nil() extends List -//│ class Lambda(x$548,eq$464) extends Callable { -//│ def apply1$240(y$473) = -//│ let x$553 = Callable.apply2$288(eq$464,x$548,y$473) in -//│ let* (x$554) = not(x$553) in -//│ x$554 +//│ class Lambda(lam_arg0$559,lam_arg1$560) extends Callable { +//│ def apply1$241(y$479) = +//│ let x$561 = Callable.apply2$292(lam_arg0$559,lam_arg1$560,y$479) in +//│ let* (x$562) = not(x$561) in +//│ x$562 //│ } //│ class Lambda() extends Callable { -//│ def apply2$288(x$478,y$479) = -//│ let x$566 = ==(x$478,y$479) in -//│ x$566 +//│ def apply2$292(x$484,y$485) = +//│ let x$574 = ==(x$484,y$485) in +//│ x$574 //│ } -//│ def not$437(c$450) = -//│ case c$450 of +//│ def not$443(c$456) = +//│ case c$456 of //│ BoolLit(true) => //│ false //│ _ => //│ true -//│ def j$534() = +//│ def j$540() = //│ null -//│ def filter$436(f$452,ls$453) = -//│ case ls$453 of -//│ Nil$448 => -//│ let x$536 = Nil$448() in -//│ x$536 +//│ def filter$442(f$458,ls$459) = +//│ case ls$459 of +//│ Nil$454 => +//│ let x$542 = Nil$454() in +//│ x$542 //│ _ => -//│ case ls$453 of -//│ Cons$443 => -//│ let x$538 = ls$453. in -//│ let x$539 = ls$453. in -//│ let x$540 = Callable.apply1$240(f$452,x$538) in -//│ case x$540 of +//│ case ls$459 of +//│ Cons$449 => +//│ let x$544 = ls$459. in +//│ let x$545 = ls$459. in +//│ let x$546 = Callable.apply1$241(f$458,x$544) in +//│ case x$546 of //│ BoolLit(true) => -//│ let* (x$542) = filter(f$452,x$539) in -//│ let x$543 = Cons$443(x$538,x$542) in -//│ x$543 +//│ let* (x$548) = filter(f$458,x$545) in +//│ let x$549 = Cons$449(x$544,x$548) in +//│ x$549 //│ _ => -//│ let* (x$544) = filter(f$452,x$539) in -//│ x$544 +//│ let* (x$550) = filter(f$458,x$545) in +//│ x$550 //│ _ => //│ panic "match error" +//│ def j$547() = +//│ jump j$543() +//│ def j$543() = +//│ jump j$541() //│ def j$541() = -//│ jump j$537() -//│ def j$537() = -//│ jump j$535() -//│ def j$535() = //│ null -//│ def nubBy$439(eq$464,ls$465) = -//│ case ls$465 of -//│ Nil$448 => -//│ let x$546 = Nil$448() in -//│ x$546 +//│ def nubBy$445(eq$470,ls$471) = +//│ case ls$471 of +//│ Nil$454 => +//│ let x$552 = Nil$454() in +//│ x$552 //│ _ => -//│ case ls$465 of -//│ Cons$443 => -//│ let x$548 = ls$465. in -//│ let x$549 = ls$465. in -//│ let x$555 = Lambda$551(x$548,eq$464) in -//│ let* (x$550) = filter(x$555,x$549) in -//│ let* (x$556) = nubBy(eq$464,x$550) in -//│ let x$557 = Cons$443(x$548,x$556) in -//│ x$557 +//│ case ls$471 of +//│ Cons$449 => +//│ let x$554 = ls$471. in +//│ let x$555 = ls$471. in +//│ let x$563 = Lambda$557(eq$470,x$554) in +//│ let* (x$556) = filter(x$563,x$555) in +//│ let* (x$564) = nubBy(eq$470,x$556) in +//│ let x$565 = Cons$449(x$554,x$564) in +//│ x$565 //│ _ => //│ panic "match error" -//│ def j$547() = -//│ jump j$545() -//│ def j$545() = +//│ def j$553() = +//│ jump j$551() +//│ def j$551() = //│ null -//│ let x$558 = Nil$448() in -//│ let x$559 = Cons$443(3,x$558) in -//│ let x$560 = Cons$443(3,x$559) in -//│ let x$561 = Cons$443(2,x$560) in -//│ let x$562 = Cons$443(1,x$561) in -//│ let x$567 = Lambda$564() in -//│ let* (x$563) = nubBy(x$567,x$562) in -//│ x$563 +//│ let x$566 = Nil$454() in +//│ let x$567 = Cons$449(3,x$566) in +//│ let x$568 = Cons$449(3,x$567) in +//│ let x$569 = Cons$449(2,x$568) in +//│ let x$570 = Cons$449(1,x$569) in +//│ let x$575 = Lambda$572() in +//│ let* (x$571) = nubBy(x$575,x$570) in +//│ x$571 //│ //│ Cpp: //│ #include "mlsprelude.h" @@ -482,24 +482,15 @@ nubBy((x, y) => x == y, 1 :: 2 :: 3 :: 3 :: Nil) //│ virtual _mlsValue _mls_apply2(_mlsValue, _mlsValue); //│ }; //│ struct _mls_Lambda5: public _mls_Callable { -//│ _mlsValue _mls_x; -//│ _mlsValue _mls_eq; +//│ _mlsValue _mls_lam_arg0; +//│ _mlsValue _mls_lam_arg1; //│ constexpr static inline const char *typeName = "Lambda"; //│ constexpr static inline uint32_t typeTag = nextTypeTag(); -//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->_mls_x.print(); std::printf(", "); this->_mls_eq.print(); std::printf(")"); } -//│ virtual void destroy() override { _mlsValue::destroy(this->_mls_x); _mlsValue::destroy(this->_mls_eq); operator delete (this, std::align_val_t(_mlsAlignment)); } -//│ static _mlsValue create(_mlsValue _mls_x, _mlsValue _mls_eq) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) _mls_Lambda5; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->_mls_x = _mls_x; _mlsVal->_mls_eq = _mls_eq; return _mlsValue(_mlsVal); } +//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->_mls_lam_arg0.print(); std::printf(", "); this->_mls_lam_arg1.print(); std::printf(")"); } +//│ virtual void destroy() override { _mlsValue::destroy(this->_mls_lam_arg0); _mlsValue::destroy(this->_mls_lam_arg1); operator delete (this, std::align_val_t(_mlsAlignment)); } +//│ static _mlsValue create(_mlsValue _mls_lam_arg0, _mlsValue _mls_lam_arg1) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) _mls_Lambda5; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->_mls_lam_arg0 = _mls_lam_arg0; _mlsVal->_mls_lam_arg1 = _mls_lam_arg1; return _mlsValue(_mlsVal); } //│ virtual _mlsValue _mls_apply1(_mlsValue); //│ }; -//│ _mlsValue _mls_not(_mlsValue _mls_c2) { -//│ _mlsValue _mls_retval; -//│ if (_mlsValue::isIntLit(_mls_c2, 1)) { -//│ _mls_retval = _mlsValue::fromIntLit(0); -//│ } else { -//│ _mls_retval = _mlsValue::fromIntLit(1); -//│ } -//│ return _mls_retval; -//│ } //│ _mlsValue _mls_j3() { //│ _mlsValue _mls_retval; //│ _mls_retval = _mlsValue::create<_mls_Unit>(); @@ -544,11 +535,25 @@ nubBy((x, y) => x == y, 1 :: 2 :: 3 :: 3 :: Nil) //│ _mls_retval = _mlsValue::create<_mls_Unit>(); //│ return _mls_retval; //│ } +//│ _mlsValue _mls_j7() { +//│ _mlsValue _mls_retval; +//│ _mls_retval = _mls_j4(); +//│ return _mls_retval; +//│ } //│ _mlsValue _mls_j2() { //│ _mlsValue _mls_retval; //│ _mls_retval = _mlsValue::create<_mls_Unit>(); //│ return _mls_retval; //│ } +//│ _mlsValue _mls_not(_mlsValue _mls_c2) { +//│ _mlsValue _mls_retval; +//│ if (_mlsValue::isIntLit(_mls_c2, 1)) { +//│ _mls_retval = _mlsValue::fromIntLit(0); +//│ } else { +//│ _mls_retval = _mlsValue::fromIntLit(1); +//│ } +//│ return _mls_retval; +//│ } //│ _mlsValue _mls_nubBy(_mlsValue _mls_eq, _mlsValue _mls_ls) { //│ _mlsValue _mls_retval; //│ if (_mlsValue::isValueOf<_mls_Nil1>(_mls_ls)) { @@ -556,12 +561,12 @@ nubBy((x, y) => x == y, 1 :: 2 :: 3 :: 3 :: Nil) //│ _mls_retval = _mls_x55; //│ } else { //│ if (_mlsValue::isValueOf<_mls_Cons1>(_mls_ls)) { -//│ auto _mls_x47 = _mlsValue::cast<_mls_Cons1>(_mls_ls)->_mls_head; +//│ auto _mls_x49 = _mlsValue::cast<_mls_Cons1>(_mls_ls)->_mls_head; //│ auto _mls_x50 = _mlsValue::cast<_mls_Cons1>(_mls_ls)->_mls_tail; -//│ auto _mls_x51 = _mlsValue::create<_mls_Lambda5>(_mls_x47, _mls_eq); +//│ auto _mls_x51 = _mlsValue::create<_mls_Lambda5>(_mls_eq, _mls_x49); //│ auto _mls_x52 = _mls_filter(_mls_x51, _mls_x50); //│ auto _mls_x53 = _mls_nubBy(_mls_eq, _mls_x52); -//│ auto _mls_x54 = _mlsValue::create<_mls_Cons1>(_mls_x47, _mls_x53); +//│ auto _mls_x54 = _mlsValue::create<_mls_Cons1>(_mls_x49, _mls_x53); //│ _mls_retval = _mls_x54; //│ } else { //│ throw std::runtime_error("match error"); @@ -569,11 +574,6 @@ nubBy((x, y) => x == y, 1 :: 2 :: 3 :: 3 :: Nil) //│ } //│ return _mls_retval; //│ } -//│ _mlsValue _mls_j7() { -//│ _mlsValue _mls_retval; -//│ _mls_retval = _mls_j4(); -//│ return _mls_retval; -//│ } //│ _mlsValue _mls_Lambda6::_mls_apply2(_mlsValue _mls_x46, _mlsValue _mls_y2) { //│ _mlsValue _mls_retval; //│ auto _mls_x45 = (_mls_x46 == _mls_y2); @@ -582,9 +582,9 @@ nubBy((x, y) => x == y, 1 :: 2 :: 3 :: 3 :: Nil) //│ } //│ _mlsValue _mls_Lambda5::_mls_apply1(_mlsValue _mls_y3) { //│ _mlsValue _mls_retval; -//│ auto _mls_x48 = _mlsMethodCall<_mls_Callable>(_mls_eq)->_mls_apply2(_mls_x, _mls_y3); -//│ auto _mls_x49 = _mls_not(_mls_x48); -//│ _mls_retval = _mls_x49; +//│ auto _mls_x47 = _mlsMethodCall<_mls_Callable>(_mls_lam_arg0)->_mls_apply2(_mls_lam_arg1, _mls_y3); +//│ auto _mls_x48 = _mls_not(_mls_x47); +//│ _mls_retval = _mls_x48; //│ return _mls_retval; //│ } //│ _mlsValue _mlsMain() { @@ -603,3 +603,247 @@ nubBy((x, y) => x == y, 1 :: 2 :: 3 :: 3 :: Nil) //│ //│ Interpreted: //│ Cons(1,Cons(2,Cons(3,Nil()))) + +:sllir +:intl +:scpp +fun f(x) = + fun self_rec(x) = + if x == 0 then 0 + else x + self_rec(x - 1) + self_rec(x) +f(3) +//│ = 6 +//│ LLIR: +//│ class Lambda_self_rec() extends Callable { +//│ def apply1$241(x$579) = +//│ let x$604 = ==(x$579,0) in +//│ case x$604 of +//│ BoolLit(true) => +//│ 0 +//│ _ => +//│ let x$606 = -(x$579,1) in +//│ let x$607 = Callable.apply1$241($603,x$606) in +//│ let x$608 = +(x$579,x$607) in +//│ x$608 +//│ } +//│ def f$577(x$578) = +//│ let x$609 = Lambda_self_rec$601() in +//│ let x$610 = Callable.apply1$241(x$609,x$578) in +//│ x$610 +//│ def j$605() = +//│ null +//│ let* (x$611) = f(3) in +//│ x$611 +//│ +//│ Cpp: +//│ #include "mlsprelude.h" +//│ struct _mls_Lambda_self_rec; +//│ _mlsValue _mls_j8(); +//│ _mlsValue _mls_f2(_mlsValue); +//│ _mlsValue _mlsMain(); +//│ struct _mls_Lambda_self_rec: public _mls_Callable { +//│ +//│ constexpr static inline const char *typeName = "Lambda_self_rec"; +//│ constexpr static inline uint32_t typeTag = nextTypeTag(); +//│ virtual void print() const override { std::printf("%s", typeName); } +//│ virtual void destroy() override { operator delete (this, std::align_val_t(_mlsAlignment)); } +//│ static _mlsValue create() { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) _mls_Lambda_self_rec; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; return _mlsValue(_mlsVal); } +//│ virtual _mlsValue _mls_apply1(_mlsValue); +//│ }; +//│ _mlsValue _mls_j8() { +//│ _mlsValue _mls_retval; +//│ _mls_retval = _mlsValue::create<_mls_Unit>(); +//│ return _mls_retval; +//│ } +//│ _mlsValue _mls_f2(_mlsValue _mls_x76) { +//│ _mlsValue _mls_retval; +//│ auto _mls_x75 = _mlsValue::create<_mls_Lambda_self_rec>(); +//│ auto _mls_x77 = _mlsMethodCall<_mls_Callable>(_mls_x75)->_mls_apply1(_mls_x76); +//│ _mls_retval = _mls_x77; +//│ return _mls_retval; +//│ } +//│ _mlsValue _mls_Lambda_self_rec::_mls_apply1(_mlsValue _mls_x71) { +//│ _mlsValue _mls_retval; +//│ auto _mls_x70 = (_mls_x71 == _mlsValue::fromIntLit(0)); +//│ if (_mlsValue::isIntLit(_mls_x70, 1)) { +//│ _mls_retval = _mlsValue::fromIntLit(0); +//│ } else { +//│ auto _mls_x72 = (_mls_x71 - _mlsValue::fromIntLit(1)); +//│ auto _mls_x73 = this->_mls_apply1(_mls_x72); +//│ auto _mls_x74 = (_mls_x71 + _mls_x73); +//│ _mls_retval = _mls_x74; +//│ } +//│ return _mls_retval; +//│ } +//│ _mlsValue _mlsMain() { +//│ _mlsValue _mls_retval; +//│ auto _mls_x78 = _mls_f2(_mlsValue::fromIntLit(3)); +//│ _mls_retval = _mls_x78; +//│ return _mls_retval; +//│ } +//│ int main() { return _mlsLargeStack(_mlsMainWrapper); } +//│ +//│ Interpreted: +//│ 6 + +:sllir +:scpp +fun f(x) = + fun even(x) = + fun odd(x) = + if x == 0 then true + else if x == 1 then false + else even(x - 1) + if x == 0 then true + else if x == 1 then false + else odd(x - 1) + even(x) +f(3) +//│ = false +//│ LLIR: +//│ class Lambda_odd(lam_arg0$653) extends Callable { +//│ def apply1$241(x$617) = +//│ let x$654 = ==(x$617,0) in +//│ case x$654 of +//│ BoolLit(true) => +//│ true +//│ _ => +//│ let x$656 = ==(x$617,1) in +//│ case x$656 of +//│ BoolLit(true) => +//│ false +//│ _ => +//│ let x$658 = -(x$617,1) in +//│ let x$659 = Callable.apply1$241(lam_arg0$653,x$658) in +//│ x$659 +//│ } +//│ class Lambda_even() extends Callable { +//│ def apply1$241(x$616) = +//│ let x$660 = Lambda_odd$651($603) in +//│ let x$661 = ==(x$616,0) in +//│ case x$661 of +//│ BoolLit(true) => +//│ true +//│ _ => +//│ let x$663 = ==(x$616,1) in +//│ case x$663 of +//│ BoolLit(true) => +//│ false +//│ _ => +//│ let x$665 = -(x$616,1) in +//│ let x$666 = Callable.apply1$241(x$660,x$665) in +//│ x$666 +//│ } +//│ def f$614(x$615) = +//│ let x$667 = Lambda_even$649() in +//│ let x$668 = Callable.apply1$241(x$667,x$615) in +//│ x$668 +//│ def j$657() = +//│ jump j$655() +//│ def j$655() = +//│ null +//│ def j$664() = +//│ jump j$662() +//│ def j$662() = +//│ null +//│ let* (x$669) = f(3) in +//│ x$669 +//│ +//│ Cpp: +//│ #include "mlsprelude.h" +//│ struct _mls_Lambda_odd; +//│ struct _mls_Lambda_even; +//│ _mlsValue _mls_j11(); +//│ _mlsValue _mls_f3(_mlsValue); +//│ _mlsValue _mls_j10(); +//│ _mlsValue _mls_j9(); +//│ _mlsValue _mls_j12(); +//│ _mlsValue _mlsMain(); +//│ struct _mls_Lambda_odd: public _mls_Callable { +//│ _mlsValue _mls_lam_arg0; +//│ constexpr static inline const char *typeName = "Lambda_odd"; +//│ constexpr static inline uint32_t typeTag = nextTypeTag(); +//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->_mls_lam_arg0.print(); std::printf(")"); } +//│ virtual void destroy() override { _mlsValue::destroy(this->_mls_lam_arg0); operator delete (this, std::align_val_t(_mlsAlignment)); } +//│ static _mlsValue create(_mlsValue _mls_lam_arg0) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) _mls_Lambda_odd; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->_mls_lam_arg0 = _mls_lam_arg0; return _mlsValue(_mlsVal); } +//│ virtual _mlsValue _mls_apply1(_mlsValue); +//│ }; +//│ struct _mls_Lambda_even: public _mls_Callable { +//│ +//│ constexpr static inline const char *typeName = "Lambda_even"; +//│ constexpr static inline uint32_t typeTag = nextTypeTag(); +//│ virtual void print() const override { std::printf("%s", typeName); } +//│ virtual void destroy() override { operator delete (this, std::align_val_t(_mlsAlignment)); } +//│ static _mlsValue create() { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) _mls_Lambda_even; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; return _mlsValue(_mlsVal); } +//│ virtual _mlsValue _mls_apply1(_mlsValue); +//│ }; +//│ _mlsValue _mls_j10() { +//│ _mlsValue _mls_retval; +//│ _mls_retval = _mlsValue::create<_mls_Unit>(); +//│ return _mls_retval; +//│ } +//│ _mlsValue _mls_j12() { +//│ _mlsValue _mls_retval; +//│ _mls_retval = _mls_j9(); +//│ return _mls_retval; +//│ } +//│ _mlsValue _mls_j9() { +//│ _mlsValue _mls_retval; +//│ _mls_retval = _mlsValue::create<_mls_Unit>(); +//│ return _mls_retval; +//│ } +//│ _mlsValue _mls_f3(_mlsValue _mls_x91) { +//│ _mlsValue _mls_retval; +//│ auto _mls_x90 = _mlsValue::create<_mls_Lambda_even>(); +//│ auto _mls_x92 = _mlsMethodCall<_mls_Callable>(_mls_x90)->_mls_apply1(_mls_x91); +//│ _mls_retval = _mls_x92; +//│ return _mls_retval; +//│ } +//│ _mlsValue _mls_j11() { +//│ _mlsValue _mls_retval; +//│ _mls_retval = _mls_j10(); +//│ return _mls_retval; +//│ } +//│ _mlsValue _mls_Lambda_odd::_mls_apply1(_mlsValue _mls_x80) { +//│ _mlsValue _mls_retval; +//│ auto _mls_x79 = (_mls_x80 == _mlsValue::fromIntLit(0)); +//│ if (_mlsValue::isIntLit(_mls_x79, 1)) { +//│ _mls_retval = _mlsValue::fromIntLit(1); +//│ } else { +//│ auto _mls_x81 = (_mls_x80 == _mlsValue::fromIntLit(1)); +//│ if (_mlsValue::isIntLit(_mls_x81, 1)) { +//│ _mls_retval = _mlsValue::fromIntLit(0); +//│ } else { +//│ auto _mls_x82 = (_mls_x80 - _mlsValue::fromIntLit(1)); +//│ auto _mls_x83 = _mlsMethodCall<_mls_Callable>(_mls_lam_arg0)->_mls_apply1(_mls_x82); +//│ _mls_retval = _mls_x83; +//│ } +//│ } +//│ return _mls_retval; +//│ } +//│ _mlsValue _mls_Lambda_even::_mls_apply1(_mlsValue _mls_x86) { +//│ _mlsValue _mls_retval; +//│ auto _mls_x84 = _mlsValue::create<_mls_Lambda_odd>(_mlsValue(this)); +//│ auto _mls_x85 = (_mls_x86 == _mlsValue::fromIntLit(0)); +//│ if (_mlsValue::isIntLit(_mls_x85, 1)) { +//│ _mls_retval = _mlsValue::fromIntLit(1); +//│ } else { +//│ auto _mls_x87 = (_mls_x86 == _mlsValue::fromIntLit(1)); +//│ if (_mlsValue::isIntLit(_mls_x87, 1)) { +//│ _mls_retval = _mlsValue::fromIntLit(0); +//│ } else { +//│ auto _mls_x88 = (_mls_x86 - _mlsValue::fromIntLit(1)); +//│ auto _mls_x89 = _mlsMethodCall<_mls_Callable>(_mls_x84)->_mls_apply1(_mls_x88); +//│ _mls_retval = _mls_x89; +//│ } +//│ } +//│ return _mls_retval; +//│ } +//│ _mlsValue _mlsMain() { +//│ _mlsValue _mls_retval; +//│ auto _mls_x93 = _mls_f3(_mlsValue::fromIntLit(3)); +//│ _mls_retval = _mls_x93; +//│ return _mls_retval; +//│ } +//│ int main() { return _mlsLargeStack(_mlsMainWrapper); } diff --git a/hkmc2/shared/src/test/mlscript/llir/NofibPrelude.mls b/hkmc2/shared/src/test/mlscript/llir/nofib/NofibPrelude.mls similarity index 97% rename from hkmc2/shared/src/test/mlscript/llir/NofibPrelude.mls rename to hkmc2/shared/src/test/mlscript/llir/nofib/NofibPrelude.mls index 5da4a6ca91..59ed496033 100644 --- a/hkmc2/shared/src/test/mlscript/llir/NofibPrelude.mls +++ b/hkmc2/shared/src/test/mlscript/llir/nofib/NofibPrelude.mls @@ -1,5 +1,3 @@ -:llir - // shadow the one in Predef fun not(c) = if c then false else true @@ -11,7 +9,7 @@ object None extends Option abstract class Lazy[out A](init: () -> A) with fun get() -fun lazy(x) = Lazy(x) +fun lazy(x) = Lazy(x) fun force(x) = if x is Lazy then x.Lazy#get() fun fromSome(s) = if s is Some(x) then x @@ -139,6 +137,12 @@ fun filter(f, ls) = if ls is f(h) then h :: filter(f, t) else filter(f, t) +fun filterCurried(f)(ls) = if ls is + Nil then Nil + h :: t and + f(h) then h :: filter(f, t) + else filter(f, t) + fun all(p, ls) = if ls is Nil then true h :: t and @@ -332,6 +336,8 @@ fun stringConcat(x, y) = globalThis.builtin("str_concat", x, y) fun stringListConcat(ls) = if ls is Nil then "" h :: t then stringConcat(h, stringListConcat(t)) +fun print(x) = globalThis.builtin("println", x) +fun abs(x) = globalThis.Math.abs(x) // fun max(a, b) = Math.min(a, b) // fun min(a, b) = Math.max(a, b) diff --git a/hkmc2/shared/src/test/mlscript/llir/nofib/atom.mls b/hkmc2/shared/src/test/mlscript/llir/nofib/atom.mls new file mode 100644 index 0000000000..c7eb73ace6 --- /dev/null +++ b/hkmc2/shared/src/test/mlscript/llir/nofib/atom.mls @@ -0,0 +1,51 @@ +:llir + +:import NofibPrelude.mls +//│ Imported 100 member(s) + +class State(position: List[Num], velocity: List[Num]) + +fun dotPlus(fs, gs) = if + fs is Nil then gs + gs is Nil then fs + fs is f :: fs and gs is g :: gs then (f + g) :: dotPlus(fs, gs) + +fun dotMult(fs, gs) = if + fs is f :: fs and gs is g :: gs then (f * g) :: dotMult(fs, gs) + else Nil + +fun scalarMut(c, fs) = if fs is + Nil then Nil + f :: fs then (c * f) :: scalarMut(c, fs) + +fun testforce(k, ss) = lazy of () => + if force(ss) is + LzCons(State(pos, vel), atoms) then LzCons(dotMult(scalarMut(-1.0, k), pos), testforce(k, atoms)) + +fun show(s) = + fun lscomp(ls) = if ls is + Nil then Nil + component :: t then Cons(stringConcat(stringOfFloat(component), "\t"), lscomp(t)) + if s is State(pos, vel) then + stringListConcat of lscomp(pos) + +fun propagate(dt, aforce, state) = if state is State(pos, vel) then + State(dotPlus(pos, scalarMut(dt, vel)), dotPlus(vel, scalarMut(dt, aforce))) + +fun runExperiment(law, dt, param, init) = lazy of () => + let stream = runExperiment(law, dt, param, init) + LzCons(init, zipWith_lz_lz((x, y) => propagate(dt, x, y), law(param, stream), stream)) + +fun testAtom_nofib(n) = + fun lscomp(ls) = if ls is + Nil then Nil + state :: t then stringConcat(show(state), "\n") :: lscomp(t) + stringListConcat of lscomp(take_lz(n, runExperiment(testforce, 0.02, 1.0 :: Nil, State(1.0 :: Nil, 0.0 :: Nil)))) + + +:runWholeCpp +testAtom_nofib(20) +//│ +//│ +//│ Execution succeeded: +//│ "1.000000\t\n1.000000\t\n0.999600\t\n0.998800\t\n0.997600\t\n0.996001\t\n0.994002\t\n0.991606\t\n0.988811\t\n0.985620\t\n0.982034\t\n0.978053\t\n0.973679\t\n0.968914\t\n0.963760\t\n0.958218\t\n0.952291\t\n0.945980\t\n0.939288\t\n0.932218\t\n" diff --git a/hkmc2/shared/src/test/mlscript/llir/nofib/awards.mls b/hkmc2/shared/src/test/mlscript/llir/nofib/awards.mls new file mode 100644 index 0000000000..0de078f809 --- /dev/null +++ b/hkmc2/shared/src/test/mlscript/llir/nofib/awards.mls @@ -0,0 +1,176 @@ +:llir + +:import NofibPrelude.mls +//│ Imported 101 member(s) + +fun delete_(xs, e) = deleteBy((x, y) => x == y, e, xs) + +fun listDiff(a, ls) = foldl(delete_, a, ls) + +:... +//│ ———————————————————————————————————————————————————————————————————————————————— +fun qsort(le, ls, r) = if ls is + Nil then r + x :: Nil then x :: r + x :: xs then qpart(le, x, xs, Nil, Nil, r) + +fun qpart(le, x, ys, rlt, rge, r) = if ys is + Nil then rqsort(le, rlt, x :: rqsort(le, rge, r)) + y :: ys and + le(x, y) then qpart(le, x, ys, rlt, y :: rge, r) + else qpart(le, x, ys, y :: rlt, rge, r) + +fun rqsort(le, ls, r) = if ls is + Nil then r + x :: Nil then x :: r + x :: xs then rqpart(le, x, xs, Nil, Nil, r) + +fun rqpart(le, x, yss, rle, rgt, r) = if yss is + Nil then qsort(le, rle, x :: qsort(le, rgt, r)) + y :: ys and + le(y, x) then rqpart(le, x, ys, y :: rle, rgt, r) + else rqpart(le, x, ys, rle, y :: rgt, r) +//│ ———————————————————————————————————————————————————————————————————————————————— + +fun sort(l) = qsort((a, b) => ltTup2(a, b, (a, b) => a < b, (a, b) => a > b, (a, b) => ltList(a, b, (a, b) => a < b, (a, b) => a > b)), l, Nil) + +fun perms(m, nns) = if + nns is Nil then Nil + m == 1 then map(x => x :: Nil, nns) + nns is n :: ns then map(x => n :: x, perms(m-1, ns)) +: perms(m, ns) + +fun atleast(threshold, sumscores) = + filter(case { [sum_, p] then sum_ >= threshold }, sumscores) + +fun award(name_threshold, sumscores) = if name_threshold is [name, threshold] then + map(ps => [name, ps], sort(atleast(threshold, sumscores))) + +fun awards(scores) = + let sumscores = map(p => [sum(p), p], perms(3, scores)) + + award(["Gold", 70], sumscores) +: award(["Silver", 60], sumscores) +: award(["Bronze", 50], sumscores) + +fun findawards(scores) = if awards(scores) is + Nil then Nil + head_ :: tail_ and head_ is [award, [sum_, perm]] then + [award, [sum_, perm]] :: findawards(listDiff(scores, perm)) + +fun findallawards(competitors) = + map(case { [name, scores] then [name, findawards(scores)] }, competitors) + +fun competitors(i) = + ["Simon", (35 :: 27 :: 40 :: i :: 34 :: 21 :: Nil)] :: + ["Hans", (23 :: 19 :: 45 :: i :: 17 :: 10 :: 5 :: 8 :: 14 :: Nil)] :: + ["Phil", (1 :: 18 :: i :: 20 :: 21 :: 19 :: 34 :: 8 :: 16 :: 21 :: Nil)] :: + ["Kevin", (9 :: 23 :: 17 :: 54 :: i :: 41 :: 9 :: 18 :: 14 :: Nil)] :: + Nil + +fun testAwards_nofib(n) = + map(x => print(findallawards(competitors(intMod(x, 100)))), enumFromTo(1, n)) + +:runWholeCpp +testAwards_nofib(100) +//│ +//│ +//│ Execution succeeded: +//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(70, Cons(35, Cons(1, Cons(34, Nil))))), Cons(Tuple2("Gold", Tuple2(88, Cons(27, Cons(40, Cons(21, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Bronze", Tuple2(52, Cons(23, Cons(19, Cons(10, Nil))))), Nil))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Nil))), Nil)))) +//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(71, Cons(35, Cons(2, Cons(34, Nil))))), Cons(Tuple2("Gold", Tuple2(88, Cons(27, Cons(40, Cons(21, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(23, Cons(45, Cons(2, Nil))))), Cons(Tuple2("Bronze", Tuple2(50, Cons(19, Cons(17, Cons(14, Nil))))), Nil))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(70, Cons(54, Cons(2, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(73, Cons(9, Cons(23, Cons(41, Nil))))), Nil))), Nil)))) +//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(70, Cons(27, Cons(40, Cons(3, Nil))))), Cons(Tuple2("Gold", Tuple2(90, Cons(35, Cons(34, Cons(21, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Bronze", Tuple2(52, Cons(23, Cons(19, Cons(10, Nil))))), Nil))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(71, Cons(54, Cons(3, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(73, Cons(9, Cons(23, Cons(41, Nil))))), Nil))), Nil)))) +//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(71, Cons(27, Cons(40, Cons(4, Nil))))), Cons(Tuple2("Gold", Tuple2(90, Cons(35, Cons(34, Cons(21, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Bronze", Tuple2(52, Cons(23, Cons(19, Cons(10, Nil))))), Nil))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Nil))), Nil)))) +//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(72, Cons(27, Cons(40, Cons(5, Nil))))), Cons(Tuple2("Gold", Tuple2(90, Cons(35, Cons(34, Cons(21, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Bronze", Tuple2(52, Cons(23, Cons(19, Cons(10, Nil))))), Nil))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Nil))), Nil)))) +//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(73, Cons(27, Cons(40, Cons(6, Nil))))), Cons(Tuple2("Gold", Tuple2(90, Cons(35, Cons(34, Cons(21, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(19, Cons(45, Cons(6, Nil))))), Cons(Tuple2("Bronze", Tuple2(50, Cons(23, Cons(17, Cons(10, Nil))))), Nil))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(70, Cons(23, Cons(6, Cons(41, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Nil))), Nil)))) +//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(74, Cons(27, Cons(40, Cons(7, Nil))))), Cons(Tuple2("Gold", Tuple2(90, Cons(35, Cons(34, Cons(21, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Bronze", Tuple2(52, Cons(23, Cons(19, Cons(10, Nil))))), Nil))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(70, Cons(9, Cons(54, Cons(7, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Bronze", Tuple2(50, Cons(23, Cons(9, Cons(18, Nil))))), Nil)))), Nil)))) +//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(70, Cons(35, Cons(27, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(95, Cons(40, Cons(34, Cons(21, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(8, Cons(17, Nil))))), Cons(Tuple2("Bronze", Tuple2(50, Cons(23, Cons(19, Cons(8, Nil))))), Nil))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(71, Cons(9, Cons(54, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Bronze", Tuple2(50, Cons(23, Cons(9, Cons(18, Nil))))), Nil)))), Nil)))) +//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(70, Cons(27, Cons(9, Cons(34, Nil))))), Cons(Tuple2("Gold", Tuple2(96, Cons(35, Cons(40, Cons(21, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Bronze", Tuple2(51, Cons(23, Cons(19, Cons(9, Nil))))), Nil))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Bronze", Tuple2(50, Cons(23, Cons(9, Cons(18, Nil))))), Nil)))), Nil)))) +//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(71, Cons(27, Cons(10, Cons(34, Nil))))), Cons(Tuple2("Gold", Tuple2(96, Cons(35, Cons(40, Cons(21, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Bronze", Tuple2(52, Cons(23, Cons(19, Cons(10, Nil))))), Nil))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Bronze", Tuple2(51, Cons(23, Cons(10, Cons(18, Nil))))), Nil)))), Nil)))) +//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(72, Cons(27, Cons(11, Cons(34, Nil))))), Cons(Tuple2("Gold", Tuple2(96, Cons(35, Cons(40, Cons(21, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(11, Cons(14, Nil))))), Cons(Tuple2("Bronze", Tuple2(50, Cons(23, Cons(17, Cons(10, Nil))))), Nil))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(70, Cons(11, Cons(41, Cons(18, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Bronze", Tuple2(54, Cons(23, Cons(17, Cons(14, Nil))))), Nil)))), Nil)))) +//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(73, Cons(27, Cons(12, Cons(34, Nil))))), Cons(Tuple2("Gold", Tuple2(96, Cons(35, Cons(40, Cons(21, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Bronze", Tuple2(52, Cons(23, Cons(19, Cons(10, Nil))))), Nil))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(70, Cons(17, Cons(12, Cons(41, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Bronze", Tuple2(55, Cons(23, Cons(18, Cons(14, Nil))))), Nil)))), Nil)))) +//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(74, Cons(27, Cons(13, Cons(34, Nil))))), Cons(Tuple2("Gold", Tuple2(96, Cons(35, Cons(40, Cons(21, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Bronze", Tuple2(50, Cons(23, Cons(13, Cons(14, Nil))))), Nil))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(71, Cons(17, Cons(13, Cons(41, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Bronze", Tuple2(55, Cons(23, Cons(18, Cons(14, Nil))))), Nil)))), Nil)))) +//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(70, Cons(35, Cons(14, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(101, Cons(27, Cons(40, Cons(34, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Bronze", Tuple2(51, Cons(23, Cons(14, Cons(14, Nil))))), Nil))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(14, Cons(41, Nil))))), Cons(Tuple2("Bronze", Tuple2(55, Cons(23, Cons(18, Cons(14, Nil))))), Nil)))), Nil)))) +//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(70, Cons(15, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(102, Cons(35, Cons(27, Cons(40, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(15, Cons(10, Nil))))), Cons(Tuple2("Bronze", Tuple2(50, Cons(19, Cons(17, Cons(14, Nil))))), Nil))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(15, Cons(21, Cons(34, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(20, Cons(19, Cons(21, Nil))))), Nil))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(70, Cons(15, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Bronze", Tuple2(58, Cons(23, Cons(17, Cons(18, Nil))))), Nil)))), Nil)))) +//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(71, Cons(16, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(102, Cons(35, Cons(27, Cons(40, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Bronze", Tuple2(52, Cons(23, Cons(19, Cons(10, Nil))))), Nil))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(16, Cons(20, Cons(34, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(71, Cons(16, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Bronze", Tuple2(58, Cons(23, Cons(17, Cons(18, Nil))))), Nil)))), Nil)))) +//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(102, Cons(35, Cons(27, Cons(40, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Bronze", Tuple2(50, Cons(19, Cons(17, Cons(14, Nil))))), Nil))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(17, Cons(19, Cons(34, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Bronze", Tuple2(58, Cons(23, Cons(17, Cons(18, Nil))))), Nil)))), Nil)))) +//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(73, Cons(18, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(102, Cons(35, Cons(27, Cons(40, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(23, Cons(19, Cons(18, Nil))))), Nil))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(18, Cons(18, Cons(34, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(20, Cons(19, Cons(21, Nil))))), Nil))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Bronze", Tuple2(59, Cons(23, Cons(18, Cons(18, Nil))))), Nil)))), Nil)))) +//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(74, Cons(19, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(102, Cons(35, Cons(27, Cons(40, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Silver", Tuple2(61, Cons(23, Cons(19, Cons(19, Nil))))), Nil))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(23, Cons(19, Cons(18, Nil))))), Nil)))), Nil)))) +//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(75, Cons(20, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(102, Cons(35, Cons(27, Cons(40, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Silver", Tuple2(62, Cons(23, Cons(19, Cons(20, Nil))))), Nil))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(70, Cons(9, Cons(20, Cons(41, Nil))))), Cons(Tuple2("Gold", Tuple2(77, Cons(54, Cons(9, Cons(14, Nil))))), Cons(Tuple2("Bronze", Tuple2(58, Cons(23, Cons(17, Cons(18, Nil))))), Nil)))), Nil)))) +//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(76, Cons(21, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(102, Cons(35, Cons(27, Cons(40, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Silver", Tuple2(63, Cons(23, Cons(19, Cons(21, Nil))))), Nil))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(71, Cons(9, Cons(21, Cons(41, Nil))))), Cons(Tuple2("Gold", Tuple2(77, Cons(54, Cons(9, Cons(14, Nil))))), Cons(Tuple2("Bronze", Tuple2(58, Cons(23, Cons(17, Cons(18, Nil))))), Nil)))), Nil)))) +//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(70, Cons(27, Cons(22, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(109, Cons(35, Cons(40, Cons(34, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Silver", Tuple2(64, Cons(23, Cons(19, Cons(22, Nil))))), Nil))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(22, Cons(41, Nil))))), Cons(Tuple2("Gold", Tuple2(77, Cons(54, Cons(9, Cons(14, Nil))))), Cons(Tuple2("Bronze", Tuple2(58, Cons(23, Cons(17, Cons(18, Nil))))), Nil)))), Nil)))) +//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(71, Cons(27, Cons(23, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(109, Cons(35, Cons(40, Cons(34, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(23, Cons(23, Cons(14, Nil))))), Nil))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Cons(Tuple2("Bronze", Tuple2(50, Cons(23, Cons(19, Cons(8, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Silver", Tuple2(64, Cons(23, Cons(23, Cons(18, Nil))))), Nil)))), Nil)))) +//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(72, Cons(27, Cons(24, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(109, Cons(35, Cons(40, Cons(34, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Silver", Tuple2(61, Cons(23, Cons(24, Cons(14, Nil))))), Nil))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Cons(Tuple2("Bronze", Tuple2(51, Cons(24, Cons(19, Cons(8, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Silver", Tuple2(65, Cons(23, Cons(24, Cons(18, Nil))))), Nil)))), Nil)))) +//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(73, Cons(27, Cons(25, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(109, Cons(35, Cons(40, Cons(34, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Silver", Tuple2(62, Cons(23, Cons(25, Cons(14, Nil))))), Nil))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Cons(Tuple2("Bronze", Tuple2(52, Cons(25, Cons(19, Cons(8, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Silver", Tuple2(66, Cons(23, Cons(25, Cons(18, Nil))))), Nil)))), Nil)))) +//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(74, Cons(27, Cons(26, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(109, Cons(35, Cons(40, Cons(34, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Silver", Tuple2(63, Cons(23, Cons(26, Cons(14, Nil))))), Nil))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Cons(Tuple2("Bronze", Tuple2(53, Cons(26, Cons(19, Cons(8, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Silver", Tuple2(67, Cons(23, Cons(26, Cons(18, Nil))))), Nil)))), Nil)))) +//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(75, Cons(27, Cons(27, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(109, Cons(35, Cons(40, Cons(34, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(19, Cons(27, Cons(14, Nil))))), Nil))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Cons(Tuple2("Bronze", Tuple2(54, Cons(27, Cons(19, Cons(8, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Silver", Tuple2(68, Cons(23, Cons(27, Cons(18, Nil))))), Nil)))), Nil)))) +//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(76, Cons(27, Cons(28, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(109, Cons(35, Cons(40, Cons(34, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(23, Cons(19, Cons(28, Nil))))), Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Nil))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(70, Cons(28, Cons(21, Cons(21, Nil))))), Nil))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Silver", Tuple2(69, Cons(23, Cons(28, Cons(18, Nil))))), Nil)))), Nil)))) +//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(77, Cons(27, Cons(29, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(109, Cons(35, Cons(40, Cons(34, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(71, Cons(23, Cons(19, Cons(29, Nil))))), Nil))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(71, Cons(29, Cons(21, Cons(21, Nil))))), Nil))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(70, Cons(23, Cons(29, Cons(18, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Nil)))), Nil)))) +//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(78, Cons(27, Cons(30, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(109, Cons(35, Cons(40, Cons(34, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(23, Cons(30, Cons(17, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(19, Cons(45, Cons(8, Nil))))), Nil))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(70, Cons(30, Cons(19, Cons(21, Nil))))), Nil))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(70, Cons(23, Cons(17, Cons(30, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(73, Cons(41, Cons(18, Cons(14, Nil))))), Nil)))), Nil)))) +//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(79, Cons(27, Cons(31, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(109, Cons(35, Cons(40, Cons(34, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(73, Cons(23, Cons(19, Cons(31, Nil))))), Nil))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(18, Cons(31, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Nil))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(71, Cons(23, Cons(17, Cons(31, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(73, Cons(41, Cons(18, Cons(14, Nil))))), Nil)))), Nil)))) +//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(80, Cons(27, Cons(32, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(109, Cons(35, Cons(40, Cons(34, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(74, Cons(23, Cons(19, Cons(32, Nil))))), Nil))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(18, Cons(32, Cons(20, Nil))))), Cons(Tuple2("Gold", Tuple2(71, Cons(21, Cons(34, Cons(16, Nil))))), Nil))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(73, Cons(23, Cons(32, Cons(18, Nil))))), Nil)))), Nil)))) +//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(81, Cons(27, Cons(33, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(109, Cons(35, Cons(40, Cons(34, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(23, Cons(33, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Nil))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(18, Cons(33, Cons(19, Nil))))), Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Bronze", Tuple2(50, Cons(21, Cons(8, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(70, Cons(23, Cons(33, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(76, Cons(17, Cons(41, Cons(18, Nil))))), Nil)))), Nil)))) +//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(109, Cons(35, Cons(40, Cons(34, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(19, Cons(34, Cons(17, Nil))))), Cons(Tuple2("Gold", Tuple2(73, Cons(23, Cons(45, Cons(5, Nil))))), Nil))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(71, Cons(18, Cons(19, Cons(34, Nil))))), Cons(Tuple2("Bronze", Tuple2(50, Cons(21, Cons(8, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(71, Cons(23, Cons(34, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(76, Cons(17, Cons(41, Cons(18, Nil))))), Nil)))), Nil)))) +//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(110, Cons(35, Cons(40, Cons(35, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(23, Cons(35, Cons(14, Nil))))), Nil))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(1, Cons(35, Cons(34, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Cons(Tuple2("Bronze", Tuple2(55, Cons(20, Cons(19, Cons(16, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(70, Cons(17, Cons(35, Cons(18, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(78, Cons(23, Cons(41, Cons(14, Nil))))), Nil)))), Nil)))) +//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(111, Cons(35, Cons(40, Cons(36, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(73, Cons(23, Cons(36, Cons(14, Nil))))), Nil))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(18, Cons(36, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(73, Cons(20, Cons(19, Cons(34, Nil))))), Cons(Tuple2("Bronze", Tuple2(50, Cons(21, Cons(8, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(71, Cons(17, Cons(36, Cons(18, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(78, Cons(23, Cons(41, Cons(14, Nil))))), Nil)))), Nil)))) +//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(112, Cons(35, Cons(40, Cons(37, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(19, Cons(37, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Nil))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(74, Cons(18, Cons(37, Cons(19, Nil))))), Cons(Tuple2("Bronze", Tuple2(50, Cons(21, Cons(8, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(37, Cons(18, Nil))))), Cons(Tuple2("Gold", Tuple2(78, Cons(23, Cons(41, Cons(14, Nil))))), Nil)))), Nil)))) +//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(113, Cons(35, Cons(40, Cons(38, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(71, Cons(19, Cons(38, Cons(14, Nil))))), Nil))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(75, Cons(18, Cons(38, Cons(19, Nil))))), Cons(Tuple2("Bronze", Tuple2(50, Cons(21, Cons(8, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(70, Cons(9, Cons(23, Cons(38, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(81, Cons(54, Cons(9, Cons(18, Nil))))), Nil)))), Nil)))) +//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(114, Cons(35, Cons(40, Cons(39, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(23, Cons(39, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(45, Cons(17, Cons(10, Nil))))), Nil))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(76, Cons(18, Cons(39, Cons(19, Nil))))), Cons(Tuple2("Bronze", Tuple2(50, Cons(21, Cons(8, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(70, Cons(17, Cons(39, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(82, Cons(23, Cons(41, Cons(18, Nil))))), Nil)))), Nil)))) +//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(115, Cons(35, Cons(40, Cons(40, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(73, Cons(19, Cons(40, Cons(14, Nil))))), Nil))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(77, Cons(18, Cons(40, Cons(19, Nil))))), Cons(Tuple2("Bronze", Tuple2(50, Cons(21, Cons(8, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(71, Cons(17, Cons(40, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(82, Cons(23, Cons(41, Cons(18, Nil))))), Nil)))), Nil)))) +//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(116, Cons(35, Cons(40, Cons(41, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(19, Cons(41, Cons(10, Nil))))), Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Nil))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(70, Cons(41, Cons(8, Cons(21, Nil))))), Cons(Tuple2("Bronze", Tuple2(58, Cons(18, Cons(19, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(82, Cons(23, Cons(41, Cons(18, Nil))))), Nil)))), Nil)))) +//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(117, Cons(35, Cons(40, Cons(42, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(23, Cons(42, Cons(5, Nil))))), Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Nil))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(71, Cons(42, Cons(8, Cons(21, Nil))))), Cons(Tuple2("Bronze", Tuple2(58, Cons(18, Cons(19, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(83, Cons(23, Cons(42, Cons(18, Nil))))), Nil)))), Nil)))) +//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(118, Cons(35, Cons(40, Cons(43, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(19, Cons(43, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(45, Cons(17, Cons(10, Nil))))), Nil))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(70, Cons(43, Cons(19, Cons(8, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(70, Cons(9, Cons(43, Cons(18, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(86, Cons(23, Cons(54, Cons(9, Nil))))), Nil)))), Nil)))) +//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(119, Cons(35, Cons(40, Cons(44, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(23, Cons(44, Cons(5, Nil))))), Nil))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(18, Cons(44, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Silver", Tuple2(61, Cons(21, Cons(19, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(70, Cons(9, Cons(17, Cons(44, Nil))))), Cons(Tuple2("Gold", Tuple2(73, Cons(23, Cons(41, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(86, Cons(54, Cons(18, Cons(14, Nil))))), Nil)))), Nil)))) +//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(120, Cons(35, Cons(40, Cons(45, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(73, Cons(23, Cons(45, Cons(5, Nil))))), Nil))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(71, Cons(18, Cons(45, Cons(8, Nil))))), Cons(Tuple2("Silver", Tuple2(61, Cons(21, Cons(19, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(71, Cons(9, Cons(17, Cons(45, Nil))))), Cons(Tuple2("Gold", Tuple2(73, Cons(23, Cons(41, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(86, Cons(54, Cons(18, Cons(14, Nil))))), Nil)))), Nil)))) +//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(121, Cons(35, Cons(40, Cons(46, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(19, Cons(46, Cons(5, Nil))))), Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Nil))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(18, Cons(46, Cons(8, Nil))))), Cons(Tuple2("Silver", Tuple2(61, Cons(21, Cons(19, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(17, Cons(46, Nil))))), Cons(Tuple2("Gold", Tuple2(73, Cons(23, Cons(41, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(86, Cons(54, Cons(18, Cons(14, Nil))))), Nil)))), Nil)))) +//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(122, Cons(35, Cons(40, Cons(47, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(71, Cons(19, Cons(47, Cons(5, Nil))))), Nil))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(73, Cons(18, Cons(47, Cons(8, Nil))))), Cons(Tuple2("Silver", Tuple2(61, Cons(21, Cons(19, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(70, Cons(9, Cons(47, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(73, Cons(23, Cons(41, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(89, Cons(17, Cons(54, Cons(18, Nil))))), Nil)))), Nil)))) +//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(123, Cons(35, Cons(40, Cons(48, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(19, Cons(48, Cons(5, Nil))))), Nil))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(1, Cons(48, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Bronze", Tuple2(58, Cons(18, Cons(19, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(71, Cons(9, Cons(48, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(73, Cons(23, Cons(41, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(89, Cons(17, Cons(54, Cons(18, Nil))))), Nil)))), Nil)))) +//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(124, Cons(35, Cons(40, Cons(49, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(73, Cons(19, Cons(49, Cons(5, Nil))))), Nil))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(1, Cons(49, Cons(20, Nil))))), Cons(Tuple2("Gold", Tuple2(71, Cons(18, Cons(19, Cons(34, Nil))))), Cons(Tuple2("Bronze", Tuple2(50, Cons(21, Cons(8, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(49, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(73, Cons(23, Cons(41, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(89, Cons(17, Cons(54, Cons(18, Nil))))), Nil)))), Nil)))) +//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(125, Cons(35, Cons(40, Cons(50, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(74, Cons(19, Cons(50, Cons(5, Nil))))), Nil))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(1, Cons(50, Cons(19, Nil))))), Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(91, Cons(23, Cons(50, Cons(18, Nil))))), Nil)))), Nil)))) +//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(126, Cons(35, Cons(40, Cons(51, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(70, Cons(51, Cons(5, Cons(14, Nil))))), Cons(Tuple2("Bronze", Tuple2(52, Cons(23, Cons(19, Cons(10, Nil))))), Nil)))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(1, Cons(18, Cons(51, Nil))))), Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Silver", Tuple2(61, Cons(21, Cons(19, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(92, Cons(23, Cons(51, Cons(18, Nil))))), Nil)))), Nil)))) +//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(127, Cons(35, Cons(40, Cons(52, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(71, Cons(52, Cons(5, Cons(14, Nil))))), Cons(Tuple2("Bronze", Tuple2(52, Cons(23, Cons(19, Cons(10, Nil))))), Nil)))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(71, Cons(1, Cons(18, Cons(52, Nil))))), Cons(Tuple2("Silver", Tuple2(61, Cons(21, Cons(19, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(70, Cons(9, Cons(52, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(95, Cons(23, Cons(54, Cons(18, Nil))))), Nil)))), Nil)))) +//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(128, Cons(35, Cons(40, Cons(53, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(53, Cons(5, Cons(14, Nil))))), Cons(Tuple2("Bronze", Tuple2(52, Cons(23, Cons(19, Cons(10, Nil))))), Nil)))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(1, Cons(53, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(71, Cons(18, Cons(19, Cons(34, Nil))))), Cons(Tuple2("Silver", Tuple2(62, Cons(20, Cons(21, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(71, Cons(9, Cons(53, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(95, Cons(23, Cons(54, Cons(18, Nil))))), Nil)))), Nil)))) +//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(129, Cons(35, Cons(40, Cons(54, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(73, Cons(54, Cons(5, Cons(14, Nil))))), Cons(Tuple2("Bronze", Tuple2(52, Cons(23, Cons(19, Cons(10, Nil))))), Nil)))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(73, Cons(1, Cons(18, Cons(54, Nil))))), Cons(Tuple2("Silver", Tuple2(61, Cons(21, Cons(19, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(95, Cons(23, Cons(54, Cons(18, Nil))))), Nil)))), Nil)))) +//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(130, Cons(35, Cons(40, Cons(55, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(70, Cons(55, Cons(10, Cons(5, Nil))))), Cons(Tuple2("Bronze", Tuple2(56, Cons(23, Cons(19, Cons(14, Nil))))), Nil)))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(74, Cons(1, Cons(18, Cons(55, Nil))))), Cons(Tuple2("Silver", Tuple2(61, Cons(21, Cons(19, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(96, Cons(23, Cons(55, Cons(18, Nil))))), Nil)))), Nil)))) +//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(131, Cons(35, Cons(40, Cons(56, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(71, Cons(56, Cons(10, Cons(5, Nil))))), Cons(Tuple2("Bronze", Tuple2(56, Cons(23, Cons(19, Cons(14, Nil))))), Nil)))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(75, Cons(1, Cons(18, Cons(56, Nil))))), Cons(Tuple2("Silver", Tuple2(61, Cons(21, Cons(19, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(97, Cons(23, Cons(56, Cons(18, Nil))))), Nil)))), Nil)))) +//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(132, Cons(35, Cons(40, Cons(57, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(57, Cons(10, Cons(5, Nil))))), Cons(Tuple2("Bronze", Tuple2(56, Cons(23, Cons(19, Cons(14, Nil))))), Nil)))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(76, Cons(1, Cons(18, Cons(57, Nil))))), Cons(Tuple2("Silver", Tuple2(61, Cons(21, Cons(19, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(98, Cons(23, Cons(57, Cons(18, Nil))))), Nil)))), Nil)))) +//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(133, Cons(35, Cons(40, Cons(58, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(73, Cons(58, Cons(10, Cons(5, Nil))))), Cons(Tuple2("Bronze", Tuple2(56, Cons(23, Cons(19, Cons(14, Nil))))), Nil)))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(77, Cons(1, Cons(18, Cons(58, Nil))))), Cons(Tuple2("Silver", Tuple2(61, Cons(21, Cons(19, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(99, Cons(23, Cons(58, Cons(18, Nil))))), Nil)))), Nil)))) +//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(134, Cons(35, Cons(40, Cons(59, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(74, Cons(59, Cons(10, Cons(5, Nil))))), Cons(Tuple2("Bronze", Tuple2(56, Cons(23, Cons(19, Cons(14, Nil))))), Nil)))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(78, Cons(1, Cons(18, Cons(59, Nil))))), Cons(Tuple2("Silver", Tuple2(61, Cons(21, Cons(19, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(100, Cons(23, Cons(59, Cons(18, Nil))))), Nil)))), Nil)))) +//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(135, Cons(35, Cons(40, Cons(60, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(75, Cons(60, Cons(10, Cons(5, Nil))))), Cons(Tuple2("Bronze", Tuple2(56, Cons(23, Cons(19, Cons(14, Nil))))), Nil)))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(79, Cons(1, Cons(18, Cons(60, Nil))))), Cons(Tuple2("Silver", Tuple2(61, Cons(21, Cons(19, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(101, Cons(23, Cons(60, Cons(18, Nil))))), Nil)))), Nil)))) +//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(136, Cons(35, Cons(40, Cons(61, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(76, Cons(61, Cons(10, Cons(5, Nil))))), Cons(Tuple2("Bronze", Tuple2(56, Cons(23, Cons(19, Cons(14, Nil))))), Nil)))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(1, Cons(61, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(102, Cons(23, Cons(61, Cons(18, Nil))))), Nil)))), Nil)))) +//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(137, Cons(35, Cons(40, Cons(62, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(77, Cons(62, Cons(10, Cons(5, Nil))))), Cons(Tuple2("Bronze", Tuple2(56, Cons(23, Cons(19, Cons(14, Nil))))), Nil)))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(71, Cons(1, Cons(62, Cons(8, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(103, Cons(23, Cons(62, Cons(18, Nil))))), Nil)))), Nil)))) +//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(138, Cons(35, Cons(40, Cons(63, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(78, Cons(63, Cons(10, Cons(5, Nil))))), Cons(Tuple2("Bronze", Tuple2(56, Cons(23, Cons(19, Cons(14, Nil))))), Nil)))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(1, Cons(63, Cons(8, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(104, Cons(23, Cons(63, Cons(18, Nil))))), Nil)))), Nil)))) +//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(139, Cons(35, Cons(40, Cons(64, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(79, Cons(64, Cons(10, Cons(5, Nil))))), Cons(Tuple2("Bronze", Tuple2(56, Cons(23, Cons(19, Cons(14, Nil))))), Nil)))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(73, Cons(1, Cons(64, Cons(8, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(105, Cons(23, Cons(64, Cons(18, Nil))))), Nil)))), Nil)))) +//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(140, Cons(35, Cons(40, Cons(65, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(80, Cons(65, Cons(10, Cons(5, Nil))))), Cons(Tuple2("Bronze", Tuple2(56, Cons(23, Cons(19, Cons(14, Nil))))), Nil)))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(74, Cons(1, Cons(65, Cons(8, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(106, Cons(23, Cons(65, Cons(18, Nil))))), Nil)))), Nil)))) +//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(141, Cons(35, Cons(40, Cons(66, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(81, Cons(66, Cons(10, Cons(5, Nil))))), Cons(Tuple2("Bronze", Tuple2(56, Cons(23, Cons(19, Cons(14, Nil))))), Nil)))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(75, Cons(1, Cons(66, Cons(8, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(107, Cons(23, Cons(66, Cons(18, Nil))))), Nil)))), Nil)))) +//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(142, Cons(35, Cons(40, Cons(67, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(82, Cons(67, Cons(10, Cons(5, Nil))))), Cons(Tuple2("Bronze", Tuple2(56, Cons(23, Cons(19, Cons(14, Nil))))), Nil)))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(76, Cons(1, Cons(67, Cons(8, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(108, Cons(23, Cons(67, Cons(18, Nil))))), Nil)))), Nil)))) +//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(143, Cons(35, Cons(40, Cons(68, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(83, Cons(68, Cons(10, Cons(5, Nil))))), Cons(Tuple2("Bronze", Tuple2(56, Cons(23, Cons(19, Cons(14, Nil))))), Nil)))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(77, Cons(1, Cons(68, Cons(8, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(109, Cons(23, Cons(68, Cons(18, Nil))))), Nil)))), Nil)))) +//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(144, Cons(35, Cons(40, Cons(69, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(84, Cons(69, Cons(10, Cons(5, Nil))))), Cons(Tuple2("Bronze", Tuple2(56, Cons(23, Cons(19, Cons(14, Nil))))), Nil)))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(78, Cons(1, Cons(69, Cons(8, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(110, Cons(23, Cons(69, Cons(18, Nil))))), Nil)))), Nil)))) +//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(145, Cons(35, Cons(40, Cons(70, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(85, Cons(70, Cons(10, Cons(5, Nil))))), Cons(Tuple2("Bronze", Tuple2(56, Cons(23, Cons(19, Cons(14, Nil))))), Nil)))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(79, Cons(1, Cons(70, Cons(8, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(111, Cons(23, Cons(70, Cons(18, Nil))))), Nil)))), Nil)))) +//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(146, Cons(35, Cons(40, Cons(71, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(86, Cons(71, Cons(10, Cons(5, Nil))))), Cons(Tuple2("Bronze", Tuple2(56, Cons(23, Cons(19, Cons(14, Nil))))), Nil)))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(80, Cons(1, Cons(71, Cons(8, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(112, Cons(23, Cons(71, Cons(18, Nil))))), Nil)))), Nil)))) +//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(147, Cons(35, Cons(40, Cons(72, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(87, Cons(72, Cons(10, Cons(5, Nil))))), Cons(Tuple2("Bronze", Tuple2(56, Cons(23, Cons(19, Cons(14, Nil))))), Nil)))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(81, Cons(1, Cons(72, Cons(8, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(113, Cons(23, Cons(72, Cons(18, Nil))))), Nil)))), Nil)))) +//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(148, Cons(35, Cons(40, Cons(73, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(88, Cons(73, Cons(10, Cons(5, Nil))))), Cons(Tuple2("Bronze", Tuple2(56, Cons(23, Cons(19, Cons(14, Nil))))), Nil)))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(82, Cons(1, Cons(73, Cons(8, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(114, Cons(23, Cons(73, Cons(18, Nil))))), Nil)))), Nil)))) +//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(149, Cons(35, Cons(40, Cons(74, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(89, Cons(74, Cons(10, Cons(5, Nil))))), Cons(Tuple2("Bronze", Tuple2(56, Cons(23, Cons(19, Cons(14, Nil))))), Nil)))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(83, Cons(1, Cons(74, Cons(8, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(115, Cons(23, Cons(74, Cons(18, Nil))))), Nil)))), Nil)))) +//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(150, Cons(35, Cons(40, Cons(75, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(90, Cons(75, Cons(10, Cons(5, Nil))))), Cons(Tuple2("Bronze", Tuple2(56, Cons(23, Cons(19, Cons(14, Nil))))), Nil)))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(84, Cons(1, Cons(75, Cons(8, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(116, Cons(23, Cons(75, Cons(18, Nil))))), Nil)))), Nil)))) +//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(151, Cons(35, Cons(40, Cons(76, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(91, Cons(76, Cons(10, Cons(5, Nil))))), Cons(Tuple2("Bronze", Tuple2(56, Cons(23, Cons(19, Cons(14, Nil))))), Nil)))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(85, Cons(1, Cons(76, Cons(8, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(117, Cons(23, Cons(76, Cons(18, Nil))))), Nil)))), Nil)))) +//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(152, Cons(35, Cons(40, Cons(77, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(92, Cons(77, Cons(10, Cons(5, Nil))))), Cons(Tuple2("Bronze", Tuple2(56, Cons(23, Cons(19, Cons(14, Nil))))), Nil)))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(86, Cons(1, Cons(77, Cons(8, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(118, Cons(23, Cons(77, Cons(18, Nil))))), Nil)))), Nil)))) +//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(153, Cons(35, Cons(40, Cons(78, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(93, Cons(78, Cons(10, Cons(5, Nil))))), Cons(Tuple2("Bronze", Tuple2(56, Cons(23, Cons(19, Cons(14, Nil))))), Nil)))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(87, Cons(1, Cons(78, Cons(8, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(119, Cons(23, Cons(78, Cons(18, Nil))))), Nil)))), Nil)))) +//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(154, Cons(35, Cons(40, Cons(79, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(94, Cons(79, Cons(10, Cons(5, Nil))))), Cons(Tuple2("Bronze", Tuple2(56, Cons(23, Cons(19, Cons(14, Nil))))), Nil)))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(88, Cons(1, Cons(79, Cons(8, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(120, Cons(23, Cons(79, Cons(18, Nil))))), Nil)))), Nil)))) +//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(155, Cons(35, Cons(40, Cons(80, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(95, Cons(80, Cons(10, Cons(5, Nil))))), Cons(Tuple2("Bronze", Tuple2(56, Cons(23, Cons(19, Cons(14, Nil))))), Nil)))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(89, Cons(1, Cons(80, Cons(8, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(121, Cons(23, Cons(80, Cons(18, Nil))))), Nil)))), Nil)))) +//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(156, Cons(35, Cons(40, Cons(81, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(96, Cons(81, Cons(10, Cons(5, Nil))))), Cons(Tuple2("Bronze", Tuple2(56, Cons(23, Cons(19, Cons(14, Nil))))), Nil)))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(90, Cons(1, Cons(81, Cons(8, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(122, Cons(23, Cons(81, Cons(18, Nil))))), Nil)))), Nil)))) +//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(157, Cons(35, Cons(40, Cons(82, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(97, Cons(82, Cons(10, Cons(5, Nil))))), Cons(Tuple2("Bronze", Tuple2(56, Cons(23, Cons(19, Cons(14, Nil))))), Nil)))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(91, Cons(1, Cons(82, Cons(8, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(123, Cons(23, Cons(82, Cons(18, Nil))))), Nil)))), Nil)))) +//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(158, Cons(35, Cons(40, Cons(83, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(98, Cons(83, Cons(10, Cons(5, Nil))))), Cons(Tuple2("Bronze", Tuple2(56, Cons(23, Cons(19, Cons(14, Nil))))), Nil)))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(92, Cons(1, Cons(83, Cons(8, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(124, Cons(23, Cons(83, Cons(18, Nil))))), Nil)))), Nil)))) +//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(159, Cons(35, Cons(40, Cons(84, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(99, Cons(84, Cons(10, Cons(5, Nil))))), Cons(Tuple2("Bronze", Tuple2(56, Cons(23, Cons(19, Cons(14, Nil))))), Nil)))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(93, Cons(1, Cons(84, Cons(8, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(125, Cons(23, Cons(84, Cons(18, Nil))))), Nil)))), Nil)))) +//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(160, Cons(35, Cons(40, Cons(85, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(100, Cons(85, Cons(10, Cons(5, Nil))))), Cons(Tuple2("Bronze", Tuple2(56, Cons(23, Cons(19, Cons(14, Nil))))), Nil)))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(94, Cons(1, Cons(85, Cons(8, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(126, Cons(23, Cons(85, Cons(18, Nil))))), Nil)))), Nil)))) +//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(161, Cons(35, Cons(40, Cons(86, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(101, Cons(86, Cons(10, Cons(5, Nil))))), Cons(Tuple2("Bronze", Tuple2(56, Cons(23, Cons(19, Cons(14, Nil))))), Nil)))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(95, Cons(1, Cons(86, Cons(8, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(127, Cons(23, Cons(86, Cons(18, Nil))))), Nil)))), Nil)))) +//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(162, Cons(35, Cons(40, Cons(87, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(102, Cons(87, Cons(10, Cons(5, Nil))))), Cons(Tuple2("Bronze", Tuple2(56, Cons(23, Cons(19, Cons(14, Nil))))), Nil)))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(96, Cons(1, Cons(87, Cons(8, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(128, Cons(23, Cons(87, Cons(18, Nil))))), Nil)))), Nil)))) +//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(163, Cons(35, Cons(40, Cons(88, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(103, Cons(88, Cons(10, Cons(5, Nil))))), Cons(Tuple2("Bronze", Tuple2(56, Cons(23, Cons(19, Cons(14, Nil))))), Nil)))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(97, Cons(1, Cons(88, Cons(8, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(129, Cons(23, Cons(88, Cons(18, Nil))))), Nil)))), Nil)))) +//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(164, Cons(35, Cons(40, Cons(89, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(104, Cons(89, Cons(10, Cons(5, Nil))))), Cons(Tuple2("Bronze", Tuple2(56, Cons(23, Cons(19, Cons(14, Nil))))), Nil)))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(98, Cons(1, Cons(89, Cons(8, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(130, Cons(23, Cons(89, Cons(18, Nil))))), Nil)))), Nil)))) +//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(165, Cons(35, Cons(40, Cons(90, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(105, Cons(90, Cons(10, Cons(5, Nil))))), Cons(Tuple2("Bronze", Tuple2(56, Cons(23, Cons(19, Cons(14, Nil))))), Nil)))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(99, Cons(1, Cons(90, Cons(8, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(131, Cons(23, Cons(90, Cons(18, Nil))))), Nil)))), Nil)))) +//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(166, Cons(35, Cons(40, Cons(91, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(106, Cons(91, Cons(10, Cons(5, Nil))))), Cons(Tuple2("Bronze", Tuple2(56, Cons(23, Cons(19, Cons(14, Nil))))), Nil)))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(100, Cons(1, Cons(91, Cons(8, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(132, Cons(23, Cons(91, Cons(18, Nil))))), Nil)))), Nil)))) +//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(167, Cons(35, Cons(40, Cons(92, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(107, Cons(92, Cons(10, Cons(5, Nil))))), Cons(Tuple2("Bronze", Tuple2(56, Cons(23, Cons(19, Cons(14, Nil))))), Nil)))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(101, Cons(1, Cons(92, Cons(8, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(133, Cons(23, Cons(92, Cons(18, Nil))))), Nil)))), Nil)))) +//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(168, Cons(35, Cons(40, Cons(93, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(108, Cons(93, Cons(10, Cons(5, Nil))))), Cons(Tuple2("Bronze", Tuple2(56, Cons(23, Cons(19, Cons(14, Nil))))), Nil)))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(102, Cons(1, Cons(93, Cons(8, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(134, Cons(23, Cons(93, Cons(18, Nil))))), Nil)))), Nil)))) +//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(169, Cons(35, Cons(40, Cons(94, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(109, Cons(94, Cons(10, Cons(5, Nil))))), Cons(Tuple2("Bronze", Tuple2(56, Cons(23, Cons(19, Cons(14, Nil))))), Nil)))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(103, Cons(1, Cons(94, Cons(8, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(135, Cons(23, Cons(94, Cons(18, Nil))))), Nil)))), Nil)))) +//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(170, Cons(35, Cons(40, Cons(95, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(110, Cons(95, Cons(10, Cons(5, Nil))))), Cons(Tuple2("Bronze", Tuple2(56, Cons(23, Cons(19, Cons(14, Nil))))), Nil)))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(104, Cons(1, Cons(95, Cons(8, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(136, Cons(23, Cons(95, Cons(18, Nil))))), Nil)))), Nil)))) +//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(171, Cons(35, Cons(40, Cons(96, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(111, Cons(96, Cons(10, Cons(5, Nil))))), Cons(Tuple2("Bronze", Tuple2(56, Cons(23, Cons(19, Cons(14, Nil))))), Nil)))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(105, Cons(1, Cons(96, Cons(8, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(137, Cons(23, Cons(96, Cons(18, Nil))))), Nil)))), Nil)))) +//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(172, Cons(35, Cons(40, Cons(97, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(112, Cons(97, Cons(10, Cons(5, Nil))))), Cons(Tuple2("Bronze", Tuple2(56, Cons(23, Cons(19, Cons(14, Nil))))), Nil)))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(106, Cons(1, Cons(97, Cons(8, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(138, Cons(23, Cons(97, Cons(18, Nil))))), Nil)))), Nil)))) +//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(173, Cons(35, Cons(40, Cons(98, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(113, Cons(98, Cons(10, Cons(5, Nil))))), Cons(Tuple2("Bronze", Tuple2(56, Cons(23, Cons(19, Cons(14, Nil))))), Nil)))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(107, Cons(1, Cons(98, Cons(8, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(139, Cons(23, Cons(98, Cons(18, Nil))))), Nil)))), Nil)))) +//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(174, Cons(35, Cons(40, Cons(99, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(114, Cons(99, Cons(10, Cons(5, Nil))))), Cons(Tuple2("Bronze", Tuple2(56, Cons(23, Cons(19, Cons(14, Nil))))), Nil)))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(108, Cons(1, Cons(99, Cons(8, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(140, Cons(23, Cons(99, Cons(18, Nil))))), Nil)))), Nil)))) +//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(74, Cons(40, Cons(0, Cons(34, Nil))))), Cons(Tuple2("Gold", Tuple2(83, Cons(35, Cons(27, Cons(21, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Bronze", Tuple2(52, Cons(23, Cons(19, Cons(10, Nil))))), Nil))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(71, Cons(17, Cons(54, Cons(0, Nil))))), Cons(Tuple2("Gold", Tuple2(73, Cons(9, Cons(23, Cons(41, Nil))))), Nil))), Nil)))) +//│ Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Nil)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))) diff --git a/hkmc2/shared/src/test/mlscript/llir/nofib/constraints.mls b/hkmc2/shared/src/test/mlscript/llir/nofib/constraints.mls new file mode 100644 index 0000000000..179c42be6a --- /dev/null +++ b/hkmc2/shared/src/test/mlscript/llir/nofib/constraints.mls @@ -0,0 +1,281 @@ +:llir + +:import NofibPrelude.mls +//│ Imported 103 member(s) + + +// -- Figure 1. CSPs in Haskell. +class Assign(varr: Int, value: Int) + +class CSP(vars: Int, vals: Int, rel: Int) + +:... +//│ ———————————————————————————————————————————————————————————————————————————————— +fun qsort(le, ls, r) = if ls is + Nil then r + x :: Nil then x :: r + x :: xs then qpart(le, x, xs, Nil, Nil, r) + +fun qpart(le, x, ls, rlt, rge, r) = if ls is + Nil then rqsort(le, rlt, x :: rqsort(le, rge, r)) + y :: ys and + le(x, y) then qpart(le, x, ys, rlt, y :: rge, r) + else qpart(le, x, ys, y :: rlt, rge, r) + +fun rqsort(le, ls, r) = if ls is + Nil then r + x :: Nil then x :: r + x :: xs then rqpart(le, x, xs, Nil, Nil, r) + +fun rqpart(le, x, ls, rle, rgt, r) = if ls is + Nil then rqsort(le, rle, x :: qsort(le, rgt, r)) + y :: ys and + le(y, x) then rqpart(le, x, ys, y :: rle, rgt, r) + else rqpart(le, x, ys, rle, y :: rgt, r) +//│ ———————————————————————————————————————————————————————————————————————————————— + +fun level(a) = if a is Assign(v, _) then v + +fun value(a) = if a is Assign(_, v) then v + +fun maxLevel(ls) = if ls is + Nil then 0 + Assign(v, _) :: t then v + +fun complete(csp, s) = if csp is CSP(v, _, _) then maxLevel(s) == v + +fun generate(csp) = + fun g(vals, var_) = + fun lscomp1(ls) = if ls is + Nil then Nil + val_ :: t1 then + fun lscomp2(ls) = if ls is + Nil then lscomp1(t1) + st :: t2 then (Assign(var_, val_) :: st) :: lscomp2(t2) + lscomp2(g(vals, var_ - 1)) + if var_ == 0 then + Nil :: Nil + else + lscomp1(enumFromTo(1, vals)) + + if csp is CSP(vars, vals, rel) then g(vals, vars) + + +fun inconsistencies(csp, as_) = if csp is CSP(vars, vals, rel) then + fun lscomp1(ls) = if ls is + Nil then Nil + a :: t1 then + fun lscomp2(ls) = if ls is + Nil then lscomp1(t1) + b :: t2 and + a > b and not(rel(a, b)) then [level(a), (b)] :: lscomp2(t2) + else lscomp2(t2) + lscomp2(reverse(as_)) + + lscomp1(as_) + +fun consistent(csp)(x) = null_(inconsistencies(csp, x)) + +fun test(csp, ls) = filter(consistent(csp), ls) + +fun solver(csp) = test(csp, generate(csp)) + +fun safe(as1, as2) = if as1 is Assign(i, m) and as2 is Assign(j, n) then not(m == n) and not(abs(i - j) == abs(m - n)) + +fun queens(n) = CSP(n, n, safe) + +// -- Figure 2. Trees in Haskell. +class Node[out T](lab: T, children: List[Node[T]]) + +fun label(n) = if n is Node(l, _) then l + +fun mapTree(f, n) = if n is Node(l, c) then Node(f(l), map((x => mapTree(f, x)), c)) + +fun foldTree(f, n) = if n is Node(l, c) then f(l, map((x => foldTree(f, x)), c)) + +fun filterTree(p, t) = + fun f1(a, cs) = Node(a, filter(x => p(label(x)), cs)) + foldTree(f1, t) + +fun prune(p, t) = filterTree(x => not(p(x)), t) + +fun leaves(t) = if t is + Node(leaf, Nil) then leaf :: Nil + Node(_, cs) then concat(map(leaves, cs)) + +fun initTree(f, x) = Node(x, map(y => initTree(f, y), f(x))) + +// -- Figure 3. Simple backtracking solver for CSPs. +fun mkTree(csp) = if csp is CSP(vars, vals, rel) then + fun next(ss) = + if maxLevel(ss) < vars then + fun lscomp1(ls) = if ls is + Nil then Nil + j :: t1 then + (Assign(maxLevel(ss) + 1, j) :: ss) :: lscomp1(t1) + lscomp1(enumFromTo(1, vals)) + else + Nil + + initTree(next, Nil) + + +fun earliestInconsistency(csp, aas) = if csp is CSP(vars, vals, rel) and aas is + Nil then None + a :: as_ and filter(x => not(rel(a, x)), reverse(as_)) is + Nil then None + b :: _ then Some([level(a), level(b)]) + +fun labelInconsistencies(csp, t) = + fun f2(s) = [s, earliestInconsistency(csp, s)] + + mapTree(f2, t) + + +fun btsolver0(csp) = + filter of + x => complete(csp, x) + leaves of + mapTree of + fst + prune of + x => not(snd(x) is None) + labelInconsistencies(csp, mkTree(csp)) + +// -- Figure 6. Conflict-directed solving of CSPs. +abstract class ConflictSet: Known | Unknown +class Known(vs: List[Int]) extends ConflictSet +object Unknown extends ConflictSet + +fun knownConflict(c) = if c is + Known(a :: as_) then true + else false + +fun knownSolution(c) = if c is + Known(Nil) then true + else false + +fun checkComplete(csp, s) = if complete(csp, s) then Known(Nil) else Unknown + +fun search(labeler, csp) = + map of + fst + filter of + x => knownSolution(snd(x)) + leaves of prune of + x => knownConflict(snd(x)) + labeler(csp, mkTree(csp)) + +fun bt(csp, t) = + fun f3(s) = [s, (if earliestInconsistency(csp, s) is Some([a, b]) then Known(a :: b :: Nil) else checkComplete(csp, s))] + + mapTree(f3, t) + +// -- Figure 8. Backmarking. + +fun emptyTable(csp) = if csp is CSP(vars, vals, rel) then + fun lscomp1(ls) = if ls is + Nil then Nil + n :: t1 then + fun lscomp2(ls) = if ls is + Nil then Nil + m :: t2 then + Unknown :: lscomp2(t2) + lscomp2(enumFromTo(1, vals)) :: lscomp1(t1) + + Nil :: lscomp1(enumFromTo(1, vars)) + + +fun fillTable(s, csp, tbl) = if s is + Nil then tbl + Assign(var_, val_) :: as_ and csp is CSP(vars, vals, rel) then + fun f4(cs, varval) = if varval is [varr, vall] and + cs is Unknown and not(rel(Assign(var_, val_), Assign(varr, vall))) then Known(var_ :: varr :: Nil) + else cs + + fun lscomp1(ls) = if ls is + Nil then Nil + varrr :: t1 then + fun lscomp2(ls) = if ls is + Nil then Nil + valll :: t2 then [varrr, valll] :: lscomp2(t2) + lscomp2(enumFromTo(1, vals)) :: lscomp1(t1) + + zipWith((x, y) => zipWith(f4, x, y), tbl, lscomp1(enumFromTo(var_ + 1, vars))) + + +fun lookupCache(csp, t) = + fun f5(csp, tp) = if tp is + [Nil, tbl] then [[Nil, Unknown], tbl] + [a :: as_, tbl] then + let tableEntry = atIndex(value(a) - 1, head(tbl)) + let cs = if tableEntry is Unknown then checkComplete(csp, a :: as_) else tableEntry + [[a :: as_, cs], tbl] + + mapTree(x => f5(csp, x), t) + + +fun cacheChecks(csp, tbl, n) = if n is Node(s, cs) then + Node([s, tbl], map(x => cacheChecks(csp, fillTable(s, csp, tail(tbl)), x), cs)) + +fun bm(csp, t) = mapTree(fst, lookupCache(csp, cacheChecks(csp, emptyTable(csp), t))) + +// -- Figure 10. Conflict-directed backjumping. +fun combine(ls, acc) = if ls is + Nil then acc + [s, Known(cs)] :: css and + notElem(maxLevel(s), cs) then cs + else combine(css, union(cs, acc)) + +fun bj_(csp, t) = + fun f7(tp2, chs) = if tp2 is + [a, Known(cs)] then Node([a, Known(cs)], chs) + [a, Unknown] and + let cs_ = Known(combine(map(label, chs), Nil)) + knownConflict(cs_) then Node([a, cs_], Nil) + else Node([a, cs_], chs) + + foldTree(f7, t) + + +fun bj(csp, t) = + fun f6(tp2, chs) = if tp2 is + [a, Known(cs)] then Node([a, Known(cs)], chs) + [a, Unknown] then Node([a, Known(combine(map(label, chs), Nil))], chs) + + foldTree(f6, t) + + +fun bjbt(csp, t) = bj(csp, bt(csp, t)) + +fun bjbt_(csp, t) = bj_(csp, bt(csp, t)) + +// -- Figure 11. Forward checking. +fun collect(ls) = if ls is + Nil then Nil + Known(cs) :: css then union(cs, collect(css)) + +fun domainWipeout(csp, t) = if csp is CSP(vars, vals, rel) then + fun f8(tp2) = if tp2 is [[as_, cs], tbl] then + let wipedDomains = + fun lscomp1(ls) = if ls is + Nil then Nil + vs :: t1 and + all(knownConflict, vs) then vs :: lscomp1(t1) + else lscomp1(t1) + lscomp1(tbl) + let cs_ = if null_(wipedDomains) then cs else Known(collect(head(wipedDomains))) + [as_, cs_] + + mapTree(f8, t) + + +fun fc(csp, t) = domainWipeout(csp, lookupCache(csp, cacheChecks(csp, emptyTable(csp), t))) + +fun try_(n, algorithm) = listLen(search(algorithm, queens(n))) + +fun testConstraints_nofib(n) = map(x => try_(n, x), bt :: bm :: bjbt :: bjbt_ :: fc :: Nil) + + +:writeWholeCpp constraints.cxx +print(testConstraints_nofib(6)) diff --git a/hkmc2DiffTests/src/test/scala/hkmc2/LlirDiffMaker.scala b/hkmc2DiffTests/src/test/scala/hkmc2/LlirDiffMaker.scala index 696c0b9a66..b062176a86 100644 --- a/hkmc2DiffTests/src/test/scala/hkmc2/LlirDiffMaker.scala +++ b/hkmc2DiffTests/src/test/scala/hkmc2/LlirDiffMaker.scala @@ -88,7 +88,7 @@ abstract class LlirDiffMaker extends BbmlDiffMaker: else rPath/"src"/"test"/"mlscript-compile"/"cpp" if write.isDefined then - printToFile(java.io.File((auxPath / s"${write.get}.cpp").toString)): + printToFile(java.io.File((auxPath / s"${write.get}").toString)): p => p.println(cpp.toDocument.toString) if run then val cppHost = CppCompilerHost(auxPath.toString, output.apply) From e44e7a0faecb96a9b5404bcaf731b43107e2f88c Mon Sep 17 00:00:00 2001 From: waterlens Date: Fri, 28 Feb 2025 22:53:57 +0800 Subject: [PATCH 49/88] update --- hkmc2/shared/src/test/mlscript/llir/nofib/constraints.mls | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/hkmc2/shared/src/test/mlscript/llir/nofib/constraints.mls b/hkmc2/shared/src/test/mlscript/llir/nofib/constraints.mls index 179c42be6a..72e86e091e 100644 --- a/hkmc2/shared/src/test/mlscript/llir/nofib/constraints.mls +++ b/hkmc2/shared/src/test/mlscript/llir/nofib/constraints.mls @@ -277,5 +277,10 @@ fun try_(n, algorithm) = listLen(search(algorithm, queens(n))) fun testConstraints_nofib(n) = map(x => try_(n, x), bt :: bm :: bjbt :: bjbt_ :: fc :: Nil) -:writeWholeCpp constraints.cxx +:runWholeCpp print(testConstraints_nofib(6)) +//│ +//│ +//│ Execution succeeded: +//│ Cons(4, Cons(4, Cons(4, Cons(4, Cons(4, Nil))))) +//│ Unit From e9fde9646255afe3975eb8a8e1c466f0f6f7bf91 Mon Sep 17 00:00:00 2001 From: waterlens Date: Sat, 1 Mar 2025 19:07:57 +0800 Subject: [PATCH 50/88] fix mimalloc --- hkmc2/shared/src/test/mlscript-compile/cpp/Makefile | 2 +- hkmc2/shared/src/test/mlscript-compile/cpp/mlsaux.cxx | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) create mode 100644 hkmc2/shared/src/test/mlscript-compile/cpp/mlsaux.cxx diff --git a/hkmc2/shared/src/test/mlscript-compile/cpp/Makefile b/hkmc2/shared/src/test/mlscript-compile/cpp/Makefile index a1e6af7889..88d7f6046b 100644 --- a/hkmc2/shared/src/test/mlscript-compile/cpp/Makefile +++ b/hkmc2/shared/src/test/mlscript-compile/cpp/Makefile @@ -1,7 +1,7 @@ CXX := g++ CFLAGS += -O3 -g -Wall -Wextra -std=c++20 -I. -Wno-inconsistent-missing-override -I/opt/homebrew/include LDFLAGS += -L/opt/homebrew/lib -LDLIBS := -lgmp -lboost_stacktrace_basic +LDLIBS := -lmimalloc -lgmp -lboost_stacktrace_basic SRC := INCLUDES := mlsprelude.h DST := diff --git a/hkmc2/shared/src/test/mlscript-compile/cpp/mlsaux.cxx b/hkmc2/shared/src/test/mlscript-compile/cpp/mlsaux.cxx new file mode 100644 index 0000000000..edc8d63c3f --- /dev/null +++ b/hkmc2/shared/src/test/mlscript-compile/cpp/mlsaux.cxx @@ -0,0 +1,4 @@ +#include "mlsprelude.h" + +#include +#include From d5d3da93a9c56b8aa0c12da23ba511ad632c8706 Mon Sep 17 00:00:00 2001 From: waterlens Date: Sun, 2 Mar 2025 19:15:12 +0800 Subject: [PATCH 51/88] add secretary --- .../scala/hkmc2/codegen/cpp/CodeGen.scala | 2 +- .../test/mlscript-compile/cpp/mlsprelude.h | 9 ++ hkmc2/shared/src/test/mlscript/llir/Lazy.mls | 87 ++++------ .../src/test/mlscript/llir/LazyCycle.mls | 148 ++++++++++++++++++ .../test/mlscript/llir/nofib/NofibPrelude.mls | 1 + .../test/mlscript/llir/nofib/constraints.mls | 2 +- .../src/test/mlscript/llir/nofib/scc.mls | 58 +++++++ .../test/mlscript/llir/nofib/secretary.mls | 47 ++++++ 8 files changed, 292 insertions(+), 62 deletions(-) create mode 100644 hkmc2/shared/src/test/mlscript/llir/LazyCycle.mls create mode 100644 hkmc2/shared/src/test/mlscript/llir/nofib/scc.mls create mode 100644 hkmc2/shared/src/test/mlscript/llir/nofib/secretary.mls diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/CodeGen.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/CodeGen.scala index 3eb7f896b1..c7e6550522 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/CodeGen.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/CodeGen.scala @@ -68,7 +68,7 @@ class CppCodeGen(builtinClassSymbols: Set[Local], tl: TraceLogger): def mlsFnWrapperName(fn: Str) = s"_mlsFn_$fn" def mlsFnCreateMethod(fn: Str) = s"static _mlsValue create() { static _mlsFn_$fn mlsFn alignas(_mlsAlignment); mlsFn.refCount = stickyRefCount; mlsFn.tag = typeTag; return _mlsValue(&mlsFn); }" def mlsNeverValue(n: Int) = if (n <= 1) then Expr.Call(Expr.Var(s"_mlsValue::never"), Ls()) else Expr.Call(Expr.Var(s"_mlsValue::never<$n>"), Ls()) - val mlsThis = Expr.Var("_mlsValue(this)") + val mlsThis = Expr.Var("_mlsValue(this, _mlsValue::inc_ref_tag{})") // first construct a value, then incRef() case class Ctx( defnCtx: Set[Local], diff --git a/hkmc2/shared/src/test/mlscript-compile/cpp/mlsprelude.h b/hkmc2/shared/src/test/mlscript-compile/cpp/mlsprelude.h index 85591423d1..ee03b0d2e4 100644 --- a/hkmc2/shared/src/test/mlscript-compile/cpp/mlsprelude.h +++ b/hkmc2/shared/src/test/mlscript-compile/cpp/mlsprelude.h @@ -218,8 +218,13 @@ class _mlsValue { } public: + struct inc_ref_tag {}; explicit _mlsValue() : value(nullptr) {} explicit _mlsValue(void *value) : value(value) {} + explicit _mlsValue(void *value, inc_ref_tag) : value(value) { + if (isPtr()) + asObject()->incRef(); + } _mlsValue(const _mlsValue &other) : value(other.value) { if (isPtr()) asObject()->incRef(); @@ -698,6 +703,10 @@ inline _mlsValue _mls_builtin_float2str(_mlsValue a) { return _mlsValue::create<_mls_Str>(buf); } +inline _mlsValue _mls_builtin_int2float(_mlsValue a) { + return _mlsValue::create<_mls_Float>(a.asInt()); +} + inline _mlsValue _mls_builtin_str_concat(_mlsValue a, _mlsValue b) { _mls_assert(_mlsValue::isValueOf<_mls_Str>(a)); _mls_assert(_mlsValue::isValueOf<_mls_Str>(b)); diff --git a/hkmc2/shared/src/test/mlscript/llir/Lazy.mls b/hkmc2/shared/src/test/mlscript/llir/Lazy.mls index 87edefa35f..40894667ee 100644 --- a/hkmc2/shared/src/test/mlscript/llir/Lazy.mls +++ b/hkmc2/shared/src/test/mlscript/llir/Lazy.mls @@ -1,11 +1,16 @@ :llir -:sllir -:scpp abstract class Lazy[out A](init: () -> A) with fun get: A fun lazy(x) = Lazy(x) fun force(x) = if x is Lazy then x.Lazy#get() +type LazyList[out T] = Lazy[LzList[T]] +abstract class LzList[out T]: LzCons[T] | LzNil +class LzCons[out T](head: T, tail: LazyList[T]) extends LzList[T] +object LzNil extends LzList + +:sllir +:scpp fun side_effect() = console.log("executed") 1 @@ -16,45 +21,28 @@ fun main() = () main() //│ LLIR: -//│ class Lazy(init$225) //│ class Lambda() extends Callable { -//│ def apply0$265() = -//│ let* (x$266) = side_effect() in -//│ x$266 +//│ def apply0$281() = +//│ let* (x$282) = side_effect() in +//│ x$282 //│ } -//│ def lazy$217(x$227) = -//│ let x$257 = Lazy$222(x$227) in -//│ x$257 -//│ def force$218(x$230) = -//│ case x$230 of -//│ Lazy$222 => -//│ let x$259 = Lazy.get$216(x$230) in -//│ x$259 -//│ _ => -//│ panic "match error" -//│ def j$258() = -//│ null -//│ def side_effect$221() = -//│ let* (x$260) = ("println","executed") in +//│ def side_effect$254() = +//│ let* (x$276) = ("println","executed") in //│ 1 -//│ def main$219() = -//│ let x$268 = Lambda$263() in -//│ let* (x$262) = lazy(x$268) in -//│ let* (x$269) = force(x$262) in -//│ let* (x$270) = force(x$262) in +//│ def main$253() = +//│ let x$284 = Lambda$279() in +//│ let* (x$278) = lazy(x$284) in +//│ let* (x$285) = force(x$278) in +//│ let* (x$286) = force(x$278) in //│ undefined -//│ let* (x$271) = main() in -//│ x$271 +//│ let* (x$287) = main() in +//│ x$287 //│ //│ Cpp: //│ #include "mlsprelude.h" -//│ struct _mls_Lazy; //│ struct _mls_Lambda; -//│ _mlsValue _mls_main(); -//│ _mlsValue _mls_force(_mlsValue); -//│ _mlsValue _mls_lazy(_mlsValue); -//│ _mlsValue _mls_j(); //│ _mlsValue _mls_side_effect(); +//│ _mlsValue _mls_main(); //│ _mlsValue _mlsMain(); //│ struct _mls_Lambda: public _mls_Callable { //│ @@ -65,39 +53,18 @@ main() //│ static _mlsValue create() { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) _mls_Lambda; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; return _mlsValue(_mlsVal); } //│ virtual _mlsValue _mls_apply0(); //│ }; -//│ _mlsValue _mls_lazy(_mlsValue _mls_x6) { -//│ _mlsValue _mls_retval; -//│ auto _mls_x5 = _mlsValue::create<_mls_Lazy>(_mls_x6); -//│ _mls_retval = _mls_x5; -//│ return _mls_retval; -//│ } -//│ _mlsValue _mls_j() { -//│ _mlsValue _mls_retval; -//│ _mls_retval = _mlsValue::create<_mls_Unit>(); -//│ return _mls_retval; -//│ } -//│ _mlsValue _mls_force(_mlsValue _mls_x7) { -//│ _mlsValue _mls_retval; -//│ if (_mlsValue::isValueOf<_mls_Lazy>(_mls_x7)) { -//│ auto _mls_x8 = _mlsMethodCall<_mls_Lazy>(_mls_x7)->_mls_get(); -//│ _mls_retval = _mls_x8; -//│ } else { -//│ throw std::runtime_error("match error"); -//│ } -//│ return _mls_retval; -//│ } //│ _mlsValue _mls_side_effect() { //│ _mlsValue _mls_retval; -//│ auto _mls_x9 = _mls_builtin_println(_mlsValue::create<_mls_Str>("executed")); +//│ auto _mls_x1 = _mls_builtin_println(_mlsValue::create<_mls_Str>("executed")); //│ _mls_retval = _mlsValue::fromIntLit(1); //│ return _mls_retval; //│ } //│ _mlsValue _mls_main() { //│ _mlsValue _mls_retval; -//│ auto _mls_x1 = _mlsValue::create<_mls_Lambda>(); -//│ auto _mls_x2 = _mls_lazy(_mls_x1); -//│ auto _mls_x3 = _mls_force(_mls_x2); -//│ auto _mls_x4 = _mls_force(_mls_x2); +//│ auto _mls_x2 = _mlsValue::create<_mls_Lambda>(); +//│ auto _mls_x3 = _mls_lazy(_mls_x2); +//│ auto _mls_x4 = _mls_force(_mls_x3); +//│ auto _mls_x5 = _mls_force(_mls_x3); //│ _mls_retval = _mlsValue::create<_mls_Unit>(); //│ return _mls_retval; //│ } @@ -109,8 +76,8 @@ main() //│ } //│ _mlsValue _mlsMain() { //│ _mlsValue _mls_retval; -//│ auto _mls_x10 = _mls_main(); -//│ _mls_retval = _mls_x10; +//│ auto _mls_x6 = _mls_main(); +//│ _mls_retval = _mls_x6; //│ return _mls_retval; //│ } //│ int main() { return _mlsLargeStack(_mlsMainWrapper); } diff --git a/hkmc2/shared/src/test/mlscript/llir/LazyCycle.mls b/hkmc2/shared/src/test/mlscript/llir/LazyCycle.mls new file mode 100644 index 0000000000..16bed6171d --- /dev/null +++ b/hkmc2/shared/src/test/mlscript/llir/LazyCycle.mls @@ -0,0 +1,148 @@ +:llir + +abstract class Lazy[out A](init: () -> A) with + fun get: A +fun lazy(x) = Lazy(x) +fun force(x) = if x is Lazy then x.Lazy#get() +type LazyList[out T] = Lazy[LzList[T]] +abstract class LzList[out T]: LzCons[T] | LzNil +class LzCons[out T](head: T, tail: LazyList[T]) extends LzList[T] +object LzNil extends LzList + +:sllir +:showWholeCpp +fun llist(x) = + fun f(x) = lazy(() => LzCons(x, f(x + 1))) + f(x) +llist(1) +//│ LLIR: +//│ class Lambda(lam_arg0$279,lam_arg1$280) extends Callable { +//│ def apply0$281() = +//│ let x$282 = +(lam_arg0$279,1) in +//│ let x$283 = Callable.apply1$275(lam_arg1$280,x$282) in +//│ let x$285 = LzCons$241(lam_arg0$279,x$283) in +//│ x$285 +//│ } +//│ class Lambda_f() extends Callable { +//│ def apply1$275(x$256) = +//│ let x$286 = Lambda$277(x$256,$274) in +//│ let* (x$276) = lazy(x$286) in +//│ x$276 +//│ } +//│ def llist$254(x$255) = +//│ let x$287 = Lambda_f$272() in +//│ let x$288 = Callable.apply1$275(x$287,x$255) in +//│ x$288 +//│ let* (x$289) = llist(1) in +//│ x$289 +//│ +//│ WholeProgramCpp: +//│ #include "mlsprelude.h" +//│ struct _mls_Lazy; +//│ struct _mls_LzList; +//│ struct _mls_Lambda; +//│ struct _mls_Lambda_f; +//│ struct _mls_LzNil; +//│ struct _mls_LzCons; +//│ _mlsValue _mls_lazy(_mlsValue); +//│ _mlsValue _mls_j(); +//│ _mlsValue _mls_force(_mlsValue); +//│ _mlsValue _mls_llist(_mlsValue); +//│ _mlsValue _mlsMain(); +//│ struct _mls_LzList: public _mlsObject { +//│ +//│ constexpr static inline const char *typeName = "LzList"; +//│ constexpr static inline uint32_t typeTag = nextTypeTag(); +//│ virtual void print() const override { std::printf("%s", typeName); } +//│ virtual void destroy() override { operator delete (this, std::align_val_t(_mlsAlignment)); } +//│ static _mlsValue create() { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) _mls_LzList; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; return _mlsValue(_mlsVal); } +//│ +//│ }; +//│ struct _mls_Lambda: public _mls_Callable { +//│ _mlsValue _mls_lam_arg0; +//│ _mlsValue _mls_lam_arg1; +//│ constexpr static inline const char *typeName = "Lambda"; +//│ constexpr static inline uint32_t typeTag = nextTypeTag(); +//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->_mls_lam_arg0.print(); std::printf(", "); this->_mls_lam_arg1.print(); std::printf(")"); } +//│ virtual void destroy() override { _mlsValue::destroy(this->_mls_lam_arg0); _mlsValue::destroy(this->_mls_lam_arg1); operator delete (this, std::align_val_t(_mlsAlignment)); } +//│ static _mlsValue create(_mlsValue _mls_lam_arg0, _mlsValue _mls_lam_arg1) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) _mls_Lambda; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->_mls_lam_arg0 = _mls_lam_arg0; _mlsVal->_mls_lam_arg1 = _mls_lam_arg1; return _mlsValue(_mlsVal); } +//│ virtual _mlsValue _mls_apply0(); +//│ }; +//│ struct _mls_Lambda_f: public _mls_Callable { +//│ +//│ constexpr static inline const char *typeName = "Lambda_f"; +//│ constexpr static inline uint32_t typeTag = nextTypeTag(); +//│ virtual void print() const override { std::printf("%s", typeName); } +//│ virtual void destroy() override { operator delete (this, std::align_val_t(_mlsAlignment)); } +//│ static _mlsValue create() { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) _mls_Lambda_f; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; return _mlsValue(_mlsVal); } +//│ virtual _mlsValue _mls_apply1(_mlsValue); +//│ }; +//│ struct _mls_LzNil: public _mls_LzList { +//│ +//│ constexpr static inline const char *typeName = "LzNil"; +//│ constexpr static inline uint32_t typeTag = nextTypeTag(); +//│ virtual void print() const override { std::printf("%s", typeName); } +//│ virtual void destroy() override { operator delete (this, std::align_val_t(_mlsAlignment)); } +//│ static _mlsValue create() { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) _mls_LzNil; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; return _mlsValue(_mlsVal); } +//│ +//│ }; +//│ struct _mls_LzCons: public _mls_LzList { +//│ _mlsValue _mls_head; +//│ _mlsValue _mls_tail; +//│ constexpr static inline const char *typeName = "LzCons"; +//│ constexpr static inline uint32_t typeTag = nextTypeTag(); +//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->_mls_head.print(); std::printf(", "); this->_mls_tail.print(); std::printf(")"); } +//│ virtual void destroy() override { _mlsValue::destroy(this->_mls_head); _mlsValue::destroy(this->_mls_tail); operator delete (this, std::align_val_t(_mlsAlignment)); } +//│ static _mlsValue create(_mlsValue _mls_head, _mlsValue _mls_tail) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) _mls_LzCons; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->_mls_head = _mls_head; _mlsVal->_mls_tail = _mls_tail; return _mlsValue(_mlsVal); } +//│ +//│ }; +//│ _mlsValue _mls_lazy(_mlsValue _mls_x7) { +//│ _mlsValue _mls_retval; +//│ auto _mls_x6 = _mlsValue::create<_mls_Lazy>(_mls_x7); +//│ _mls_retval = _mls_x6; +//│ return _mls_retval; +//│ } +//│ _mlsValue _mls_j() { +//│ _mlsValue _mls_retval; +//│ _mls_retval = _mlsValue::create<_mls_Unit>(); +//│ return _mls_retval; +//│ } +//│ _mlsValue _mls_force(_mlsValue _mls_x8) { +//│ _mlsValue _mls_retval; +//│ if (_mlsValue::isValueOf<_mls_Lazy>(_mls_x8)) { +//│ auto _mls_x9 = _mlsMethodCall<_mls_Lazy>(_mls_x8)->_mls_get(); +//│ _mls_retval = _mls_x9; +//│ } else { +//│ throw std::runtime_error("match error"); +//│ } +//│ return _mls_retval; +//│ } +//│ _mlsValue _mls_llist(_mlsValue _mls_x11) { +//│ _mlsValue _mls_retval; +//│ auto _mls_x10 = _mlsValue::create<_mls_Lambda_f>(); +//│ auto _mls_x12 = _mlsMethodCall<_mls_Callable>(_mls_x10)->_mls_apply1(_mls_x11); +//│ _mls_retval = _mls_x12; +//│ return _mls_retval; +//│ } +//│ _mlsValue _mls_Lambda::_mls_apply0() { +//│ _mlsValue _mls_retval; +//│ auto _mls_x = (_mls_lam_arg0 + _mlsValue::fromIntLit(1)); +//│ auto _mls_x1 = _mlsMethodCall<_mls_Callable>(_mls_lam_arg1)->_mls_apply1(_mls_x); +//│ auto _mls_x2 = _mlsValue::create<_mls_LzCons>(_mls_lam_arg0, _mls_x1); +//│ _mls_retval = _mls_x2; +//│ return _mls_retval; +//│ } +//│ _mlsValue _mls_Lambda_f::_mls_apply1(_mlsValue _mls_x4) { +//│ _mlsValue _mls_retval; +//│ auto _mls_x3 = _mlsValue::create<_mls_Lambda>(_mls_x4, _mlsValue(this, _mlsValue::inc_ref_tag{})); +//│ auto _mls_x5 = _mls_lazy(_mls_x3); +//│ _mls_retval = _mls_x5; +//│ return _mls_retval; +//│ } +//│ _mlsValue _mlsMain() { +//│ _mlsValue _mls_retval; +//│ auto _mls_x13 = _mls_llist(_mlsValue::fromIntLit(1)); +//│ _mls_retval = _mls_x13; +//│ return _mls_retval; +//│ } +//│ int main() { return _mlsLargeStack(_mlsMainWrapper); } diff --git a/hkmc2/shared/src/test/mlscript/llir/nofib/NofibPrelude.mls b/hkmc2/shared/src/test/mlscript/llir/nofib/NofibPrelude.mls index 59ed496033..8b09b484aa 100644 --- a/hkmc2/shared/src/test/mlscript/llir/nofib/NofibPrelude.mls +++ b/hkmc2/shared/src/test/mlscript/llir/nofib/NofibPrelude.mls @@ -338,6 +338,7 @@ fun stringListConcat(ls) = if ls is h :: t then stringConcat(h, stringListConcat(t)) fun print(x) = globalThis.builtin("println", x) fun abs(x) = globalThis.Math.abs(x) +fun floatOfInt(x) = globalThis.builtin("int2float", x) // fun max(a, b) = Math.min(a, b) // fun min(a, b) = Math.max(a, b) diff --git a/hkmc2/shared/src/test/mlscript/llir/nofib/constraints.mls b/hkmc2/shared/src/test/mlscript/llir/nofib/constraints.mls index 72e86e091e..4501796aee 100644 --- a/hkmc2/shared/src/test/mlscript/llir/nofib/constraints.mls +++ b/hkmc2/shared/src/test/mlscript/llir/nofib/constraints.mls @@ -1,7 +1,7 @@ :llir :import NofibPrelude.mls -//│ Imported 103 member(s) +//│ Imported 104 member(s) // -- Figure 1. CSPs in Haskell. diff --git a/hkmc2/shared/src/test/mlscript/llir/nofib/scc.mls b/hkmc2/shared/src/test/mlscript/llir/nofib/scc.mls new file mode 100644 index 0000000000..30c8d04c61 --- /dev/null +++ b/hkmc2/shared/src/test/mlscript/llir/nofib/scc.mls @@ -0,0 +1,58 @@ +:llir + +:import NofibPrelude.mls +//│ Imported 103 member(s) + + +fun dfs(r, vsns, xs) = if vsns is [vs, ns] and + xs is + Nil then [vs, ns] + x :: xs and + inList(x, vs) then dfs(r, [vs, ns], xs) + dfs(r, [x :: vs, Nil], r(x)) is [vs', ns'] then dfs(r, [vs', (x :: ns') +: ns], xs) + +fun stronglyConnComp(es, vs) = + fun swap(a) = if a is [f, s] then [s, f] + + fun new_range(xys, w) = if xys is + Nil then Nil + [x, y] :: xys and + x == w then y :: new_range(xys, w) + else new_range(xys, w) + + fun span_tree(r, vsns, xs) = if vsns is [vs, ns] and + xs is + Nil then [vs, ns] + x :: xs and + inList(x, vs) then span_tree(r, [vs, ns], xs) + dfs(r, [x :: vs, Nil], r(x)) is [vs', ns'] then span_tree(r, [vs', (x :: ns') :: ns], xs) + + snd of span_tree of + x => new_range(map(swap, es), x) + [Nil, Nil] + snd of dfs of + x => new_range(es, x) + [Nil, Nil] + vs + + +fun testScc_nofib(d) = + let a = 1 + let b = 2 + let c = 3 + let d = 4 + let f = 5 + let g = 6 + let h = 7 + let vertices = a :: b :: c :: d :: f :: g :: h :: Nil + let edges = [b, a] :: [c, b] :: [c, d] :: [c, h] :: [d, c] :: [f, a] :: [f, g] :: [f, h] :: [g, f] :: [h, g] :: Nil + + stronglyConnComp(edges, vertices) + +:runWholeCpp +print(testScc_nofib(0)) +//│ +//│ +//│ Execution succeeded: +//│ Cons(Cons(1, Nil), Cons(Cons(2, Nil), Cons(Cons(7, Cons(5, Cons(6, Nil))), Cons(Cons(3, Cons(4, Nil)), Nil)))) +//│ Unit diff --git a/hkmc2/shared/src/test/mlscript/llir/nofib/secretary.mls b/hkmc2/shared/src/test/mlscript/llir/nofib/secretary.mls new file mode 100644 index 0000000000..33aed8e42b --- /dev/null +++ b/hkmc2/shared/src/test/mlscript/llir/nofib/secretary.mls @@ -0,0 +1,47 @@ +:llir + +:import NofibPrelude.mls +//│ Imported 104 member(s) + + +fun infRand(m, s) = + fun f(x) = lazy(() => LzCons((intMod(x, m) + 1), f(intMod((97 * x + 11), power(2, 7))))) + + f(s) + + +fun simulate(n, m, proc) = + fun lscomp(ls) = if ls is + Nil then Nil + seed :: t then proc(infRand(m, seed)) :: lscomp(t) + + floatOfInt(listLen(filter(x => x, lscomp(enumFromTo(1, n))))) / floatOfInt(n) + + +fun sim(n, k) = + fun proc(rs) = + let xs = take_lz(100, nub_lz(rs)) + let best = 100 + let bestk = maximum(take(k, xs)) + let afterk = dropWhile(x => x < bestk, drop(k, xs)) + listEq(best :: Nil, take(1, afterk)) + + simulate(n, 100, proc) + + +fun testSecretary_nofib(n) = + fun listcomp(ls) = if ls is + Nil then Nil + h :: t then sim(n, h) :: listcomp(t) + + listcomp(enumFromTo(35, 39)) + + +:writeWholeCpp secretary.cxx +:runWholeCpp +print(testSecretary_nofib(50)) +//│ +//│ +//│ Execution succeeded: +//│ Cons(Float(0.300000), Cons(Float(0.300000), Cons(Float(0.300000), Cons(Float(0.340000), Cons(Float(0.360000), Nil))))) +//│ Unit From 98d332bf20e690b4735809c6542ec193fddf18af Mon Sep 17 00:00:00 2001 From: waterlens Date: Mon, 3 Mar 2025 16:57:13 +0800 Subject: [PATCH 52/88] Programs now contain an entry function rather an entry node --- .../scala/hkmc2/codegen/cpp/CodeGen.scala | 13 +- .../scala/hkmc2/codegen/llir/Builder.scala | 69 +- .../scala/hkmc2/codegen/llir/Interp.scala | 6 +- .../main/scala/hkmc2/codegen/llir/Llir.scala | 6 +- .../src/test/mlscript/llir/BasicCpp.mls | 39 +- .../shared/src/test/mlscript/llir/Classes.mls | 22 +- .../src/test/mlscript/llir/ControlFlow.mls | 311 ++++----- hkmc2/shared/src/test/mlscript/llir/Ctor.mls | 32 +- .../src/test/mlscript/llir/HigherOrder.mls | 598 +++++++++--------- hkmc2/shared/src/test/mlscript/llir/Lazy.mls | 41 +- .../src/test/mlscript/llir/LazyCycle.mls | 89 +-- .../shared/src/test/mlscript/llir/Legacy.mls | 102 +-- .../shared/src/test/mlscript/llir/Method.mls | 6 +- hkmc2/shared/src/test/mlscript/llir/Tuple.mls | 31 +- .../src/test/mlscript/llir/nofib/atom.mls | 2 +- .../src/test/mlscript/llir/nofib/awards.mls | 2 +- .../src/test/mlscript/llir/nofib/scc.mls | 2 +- .../test/mlscript/llir/nofib/secretary.mls | 1 - .../src/test/scala/hkmc2/LlirDiffMaker.scala | 6 +- 19 files changed, 728 insertions(+), 650 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/CodeGen.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/CodeGen.scala index c7e6550522..2887f296e9 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/CodeGen.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/CodeGen.scala @@ -32,6 +32,7 @@ class CppCodeGen(builtinClassSymbols: Set[Local], tl: TraceLogger): val mlsObject = "_mlsObject" val mlsBuiltin = "builtin" val mlsEntryPoint = s"int main() { return _mlsLargeStack(_mlsMainWrapper); }"; + def mlsCallEntry(s: Str) = s"_mlsValue _mlsMain() { return $s(); }" def mlsIntLit(x: BigInt) = Expr.Call(Expr.Var("_mlsValue::fromIntLit"), Ls(Expr.IntLit(x))) def mlsStrLit(x: Str) = Expr.Call(Expr.Var("_mlsValue::create<_mls_Str>"), Ls(Expr.StrLit(x))) def mlsDecLit(x: BigDecimal) = Expr.Call(Expr.Var("_mlsValue::create<_mls_Float>"), Ls(Expr.DoubleLit(x.toDouble))) @@ -276,15 +277,6 @@ class CppCodeGen(builtinClassSymbols: Set[Local], tl: TraceLogger): val decl = Decl.FuncDecl(mlsValType, name |> allocIfNew, params.map(x => mlsValType)) (theDef, decl) - def codegenTopNode(node: Node)(using Ctx, Raise, Scope): (Def, Decl) = - val decls = Ls(mlsRetValueDecl) - val stmts = Ls.empty[Stmt] - val (decls2, stmts2) = codegen(node, mlsRetValue)(using decls, stmts) - val stmtsWithReturn = stmts2 :+ Stmt.Return(Expr.Var(mlsRetValue)) - val theDef = Def.FuncDef(mlsValType, mlsMainName, Ls(), Stmt.Block(decls2, stmtsWithReturn)) - val decl = Decl.FuncDecl(mlsValType, mlsMainName, Ls()) - (theDef, decl) - // Topological sort of classes based on inheritance relationships def sortClasses(prog: Program)(using Raise, Scope): Ls[ClassInfo] = var depgraph = prog.classes.map(x => (x.name |> mapClsLikeName, x.parents.map(mapClsLikeName))).toMap @@ -317,6 +309,5 @@ class CppCodeGen(builtinClassSymbols: Set[Local], tl: TraceLogger): given Ctx = Ctx(defnCtx, fieldCtx) val (defs, decls, methodsDef) = sortedClasses.map(codegenClassInfo).unzip3 val (defs2, decls2) = prog.defs.map(codegenDefn).unzip - val (defMain, declMain) = codegenTopNode(prog.main) - CompilationUnit(Ls(mlsPrelude), decls ++ decls2 :+ declMain, defs.flatten ++ defs2 ++ methodsDef.flatten :+ defMain :+ Def.RawDef(mlsEntryPoint)) + CompilationUnit(Ls(mlsPrelude), decls ++ decls2, defs.flatten ++ defs2 ++ methodsDef.flatten :+ Def.RawDef(mlsCallEntry(prog.entry |> allocIfNew)) :+ Def.RawDef(mlsEntryPoint)) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala index a84aea77f5..ab0bd9e1dc 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala @@ -17,13 +17,9 @@ import hkmc2.codegen.llir.{ Program => LlirProgram, Node, Func } import hkmc2.codegen.Program import hkmc2.codegen.cpp.Expr.StrLit - -def err(msg: Message)(using Raise): Unit = +private def bErrStop(msg: Message)(using Raise) = raise(ErrorReport(msg -> N :: Nil, source = Diagnostic.Source.Compilation)) - -def errStop(msg: Message)(using Raise) = - err(msg) throw LowLevelIRError("stopped") final case class FuncInfo(paramsSize: Int) @@ -51,15 +47,15 @@ final case class Ctx( ): def addFuncName(n: Local, paramsSize: Int) = copy(fn_ctx = fn_ctx + (n -> FuncInfo(paramsSize))) def findFuncName(n: Local)(using Raise) = fn_ctx.get(n) match - case None => errStop(msg"Function name not found: ${n.toString()}") + case None => bErrStop(msg"Function name not found: ${n.toString()}") case Some(value) => value def addClassInfo(n: Local, m: ClassInfo) = copy(class_ctx = class_ctx + (n -> m)) def addName(n: Local, m: Local) = copy(symbol_ctx = symbol_ctx + (n -> m)) def findName(n: Local)(using Raise) = symbol_ctx.get(n) match - case None => errStop(msg"Name not found: ${n.toString}") + case None => bErrStop(msg"Name not found: ${n.toString}") case Some(value) => value def findClassInfo(n: Local)(using Raise) = class_ctx.get(n) match - case None => errStop(msg"Class not found: ${n.toString}") + case None => bErrStop(msg"Class not found: ${n.toString}") case Some(value) => value def addKnownClass(n: Path, m: Local) = copy(flow_ctx = flow_ctx + (n -> m)) def setClass(c: Symbol) = copy(method_class = Some(c)) @@ -117,10 +113,10 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger, uid: FreshInt): private def newTupleSym(len: Int) = ClassSymbol(Tree.TypeDef(hkmc2.syntax.Cls, Tree.Empty(), N, N), Tree.Ident(s"Tuple$len")) private def newMemSym(name: Str) = TermSymbol(hkmc2.syntax.ImmutVal, None, Tree.Ident(name)) - private def newMethodSym(name: Str) = TermSymbol(hkmc2.syntax.Fun, None, Tree.Ident(name)) + private def newFunSym(name: Str) = TermSymbol(hkmc2.syntax.Fun, None, Tree.Ident(name)) private def newBuiltinSym(name: Str) = BuiltinSymbol(name, false, false, false, false) private def builtinField(n: Int)(using Ctx) = summon[Ctx].builtin_sym.fieldSym.getOrElseUpdate(n, newMemSym(s"field$n")) - private def builtinApply(n: Int)(using Ctx) = summon[Ctx].builtin_sym.applySym.getOrElseUpdate(n, newMethodSym(s"apply$n")) + private def builtinApply(n: Int)(using Ctx) = summon[Ctx].builtin_sym.applySym.getOrElseUpdate(n, newFunSym(s"apply$n")) private def builtinTuple(n: Int)(using Ctx) = summon[Ctx].builtin_sym.tupleSym.getOrElseUpdate(n, newTupleSym(n)) private def builtinCallable(using ctx: Ctx) : Local = ctx.builtin_sym.callableSym match @@ -177,7 +173,7 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger, uid: FreshInt): val FunDefn(_own, sym, params, body) = e // generate it as a single named lambda expression that may be self-recursing if params.length == 0 then - errStop(msg"Function without arguments not supported: ${params.length.toString}") + bErrStop(msg"Function without arguments not supported: ${params.length.toString}") else val fstParams = params.head val wrappedLambda = params.tail.foldRight(body)((params, acc) => Return(Value.Lam(params, acc), false)) @@ -188,7 +184,7 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger, uid: FreshInt): val FunDefn(_own, sym, params, body) = e assert(ctx.is_top_level) if params.length == 0 then - errStop(msg"Function without arguments not supported: ${params.length.toString}") + bErrStop(msg"Function without arguments not supported: ${params.length.toString}") else val paramsList = params.head.params val ctx2 = paramsList.foldLeft(ctx)((acc, x) => acc.addName(x.sym, x.sym)).nonTopLevel @@ -203,9 +199,9 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger, uid: FreshInt): trace[Func](s"bFunDef begin: ${e.sym}", x => s"bFunDef end: ${x.show}"): val FunDefn(_own, sym, params, body) = e if !ctx.is_top_level then - errStop(msg"Non top-level definition ${sym.nme} not supported") + bErrStop(msg"Non top-level definition ${sym.nme} not supported") else if params.length == 0 then - errStop(msg"Function without arguments not supported: ${params.length.toString}") + bErrStop(msg"Function without arguments not supported: ${params.length.toString}") else val paramsList = params.head.params val ctx2 = paramsList.foldLeft(ctx)((acc, x) => acc.addName(x.sym, x.sym)).nonTopLevel @@ -221,7 +217,7 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger, uid: FreshInt): val ClsLikeDefn( _own, isym, _sym, kind, paramsOpt, parentSym, methods, privateFields, publicFields, preCtor, ctor) = e if !ctx.is_top_level then - errStop(msg"Non top-level definition ${isym.toString()} not supported") + bErrStop(msg"Non top-level definition ${isym.toString()} not supported") else val clsDefn = isym.defn.getOrElse(die) val clsParams = paramsOpt.fold(Nil)(_.paramSyms) @@ -231,7 +227,7 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger, uid: FreshInt): def parentFromPath(p: Path): Set[Local] = p match case Value.Ref(l) => Set(fromMemToClass(l)) case Select(Value.Ref(l), Tree.Ident("class")) => Set(fromMemToClass(l)) - case _ => errStop(msg"Unsupported parent path ${p.toString()}") + case _ => bErrStop(msg"Unsupported parent path ${p.toString()}") ClassInfo( uid.make, isym, @@ -299,7 +295,7 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger, uid: FreshInt): bLam(Value.Lam(paramsList, Return(app, false)), S(l.nme), N)(k) case None => k(ctx.findName(l) |> sr) - case Value.This(sym) => errStop(msg"Unsupported value: This") + case Value.This(sym) => bErrStop(msg"Unsupported value: This") case Value.Lit(lit) => k(Expr.Literal(lit)) case lam @ Value.Lam(params, body) => bLam(lam, N, N)(k) case Value.Arr(elems) => @@ -317,19 +313,19 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger, uid: FreshInt): ms.defn match case Some(d: ClassLikeDef) => d.owner.get case Some(d: TermDefinition) => d.owner.get - case Some(value) => errStop(msg"Member symbol without class definition ${value.toString}") - case None => errStop(msg"Member symbol without definition ${ms.toString}") + case Some(value) => bErrStop(msg"Member symbol without class definition ${value.toString}") + case None => bErrStop(msg"Member symbol without definition ${ms.toString}") private def fromMemToClass(m: Symbol)(using ctx: Ctx)(using Raise, Scope): Local = trace[Local](s"bFromMemToClass $m", x => s"bFromMemToClass end: $x"): m match case ms: MemberSymbol[?] => ms.defn match - case Some(d: ClassLikeDef) => d.sym.asClsLike.getOrElse(errStop(msg"Class definition without symbol")) + case Some(d: ClassLikeDef) => d.sym.asClsLike.getOrElse(bErrStop(msg"Class definition without symbol")) case Some(d: TermDefinition) => d.sym - case Some(value) => errStop(msg"Member symbol without class definition ${value.toString}") - case None => errStop(msg"Member symbol without definition ${ms.toString}") - case _ => errStop(msg"Unsupported symbol kind ${m.toString}") + case Some(value) => bErrStop(msg"Member symbol without class definition ${value.toString}") + case None => bErrStop(msg"Member symbol without definition ${ms.toString}") + case _ => bErrStop(msg"Unsupported symbol kind ${m.toString}") private def bPath(p: Path)(k: TrivialExpr => Ctx ?=> Node)(using ctx: Ctx)(using Raise, Scope) : Node = @@ -342,11 +338,11 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger, uid: FreshInt): case Some(cls) => k(cls |> sr) case None => - errStop(msg"Unsupported selection by users") + bErrStop(msg"Unsupported selection by users") case Some(s) => k(s |> sr) case s @ DynSelect(qual, fld, arrayIdx) => - errStop(msg"Unsupported dynamic selection") + bErrStop(msg"Unsupported dynamic selection") case s @ Select(qual, name) => log(s"bPath Select: $qual.$name with ${s.symbol}") s.symbol match @@ -359,10 +355,10 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger, uid: FreshInt): val field = name.name Node.LetExpr(v, Expr.Select(q.sym, cls, field), k(v |> sr)) case q: Expr.Literal => - errStop(msg"Unsupported select on literal") + bErrStop(msg"Unsupported select on literal") case None => log(s"${ctx.flow_ctx}") - errStop(msg"Unsupported selection by users") + bErrStop(msg"Unsupported selection by users") case Some(value) => bPath(qual): case q: Expr.Ref => @@ -371,7 +367,7 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger, uid: FreshInt): val field = name.name Node.LetExpr(v, Expr.Select(q.sym, cls, field), k(v |> sr)) case q: Expr.Literal => - errStop(msg"Unsupported select on literal") + bErrStop(msg"Unsupported select on literal") case x: Value => bValue(x)(k) private def bResult(r: Result)(k: TrivialExpr => Ctx ?=> Node)(using ctx: Ctx)(using Raise, Scope) : Node = @@ -423,7 +419,7 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger, uid: FreshInt): val v: Local = newTemp log(s"Method Call Select: $r.$fld with ${s.symbol}") Node.LetMethodCall(Ls(v), getClassOfField(s.symbol.get), fromMemToClass(s.symbol.get), r :: args, k(v |> sr)) - case Call(_, _) => errStop(msg"Unsupported kind of Call ${r.toString()}") + case Call(_, _) => bErrStop(msg"Unsupported kind of Call ${r.toString()}") case Instantiate( Select(Value.Ref(sym), Tree.Ident("class")), args) => bPaths(args): @@ -431,7 +427,7 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger, uid: FreshInt): val v: Local = newTemp Node.LetExpr(v, Expr.CtorApp(fromMemToClass(sym), args), k(v |> sr)) case Instantiate(cls, args) => - errStop(msg"Unsupported kind of Instantiate") + bErrStop(msg"Unsupported kind of Instantiate") case x: Path => bPath(x)(k) private def bBlockWithEndCont(blk: Block)(k: TrivialExpr => Ctx ?=> Node)(using Ctx)(using Raise, Scope) : Node = @@ -511,7 +507,7 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger, uid: FreshInt): case End(msg) => k(Expr.Literal(Tree.UnitLit(false))) case _: Block => val docBlock = blk.showAsTree - errStop(msg"Unsupported block: $docBlock") + bErrStop(msg"Unsupported block: $docBlock") def registerClasses(b: Block)(using ctx: Ctx)(using Raise, Scope): Ctx = b match @@ -554,7 +550,7 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger, uid: FreshInt): registerFunctions(rest) case Define(fd @ FunDefn(_own, sym, params, body), rest) => if params.length == 0 then - errStop(msg"Function without arguments not supported: ${params.length.toString}") + bErrStop(msg"Function without arguments not supported: ${params.length.toString}") val ctx2 = ctx.addFuncName(sym, params.head.params.length) log(s"Define function: ${sym.nme} -> ${ctx2}") registerFunctions(rest)(using ctx2) @@ -574,11 +570,16 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger, uid: FreshInt): log(s"Classes: ${ctx.class_ctx}") - val entry = bBlockWithEndCont(e.main)(x => Node.Result(Ls(x)))(using ctx) + val entryBody = bBlockWithEndCont(e.main)(x => Node.Result(Ls(x)))(using ctx) + val entryFunc = Func( + uid.make, newFunSym("entry"), params = Ls.empty, resultNum = 1, + body = entryBody + ) + ctx.def_acc += entryFunc ctx = registerInternalClasses(using ctx) - val prog = LlirProgram(ctx.class_acc.toSet, ctx.def_acc.toSet, entry) + val prog = LlirProgram(ctx.class_acc.toSet, ctx.def_acc.toSet, entryFunc.name) ctx.class_acc.clear() ctx.def_acc.clear() diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Interp.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Interp.scala index a22e9ec44a..b5e11caffa 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Interp.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Interp.scala @@ -214,14 +214,16 @@ class Interpreter(tl: TraceLogger): case Panic(msg) => L(StuckNode(node, msg)) private def f(prog: Program): Ls[Value] = - val Program(classes, defs, main) = prog + val Program(classes, defs, entry) = prog given Ctx = Ctx( bindingCtx = Map.empty, classCtx = classes.map(cls => (cls.name, cls)).toMap, funcCtx = defs.map(func => (func.name, func)).toMap, thisVal = None, ) - eval(main) match + val entryFunc = summon[Ctx].funcCtx.getOrElse(entry, throw InterpreterError("Entry doesn't exist")) + assert(entryFunc.params.isEmpty, "Entry function should not have parameters") + eval(entryFunc.body) match case R(x) => x case L(x) => throw InterpreterError("Stuck evaluation: " + x.toString) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Llir.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Llir.scala index 9780f28ced..fd772bb8b4 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Llir.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Llir.scala @@ -29,14 +29,14 @@ def defaultHidden(x: Str): Bool = case class Program( classes: Set[ClassInfo], defs: Set[Func], - main: Node, + entry: Local, ): override def toString: String = val t1 = classes.toArray val t2 = defs.toArray Sorting.quickSort(t1) Sorting.quickSort(t2) - s"Program({${t1.mkString(",\n")}}, {\n${t2.mkString("\n")}\n},\n$main)" + s"Program({${t1.mkString(",\n")}}, {\n${t2.mkString("\n")}\n},\n$entry)" def show(hide: Str => Bool = defaultHidden) = toDocument(hide).toString def toDocument(hide: Str => Bool = defaultHidden) : Document = @@ -47,7 +47,7 @@ case class Program( given Conversion[String, Document] = raw val docClasses = t1.map(_.toDocument).toList.mkDocument(doc" # ") val docDefs = t2.map(_.toDocument).toList.mkDocument(doc" # ") - val docMain = main.toDocument + val docMain = doc"entry = ${entry.nme}$$${entry.uid.toString()}" doc" #{ $docClasses\n$docDefs\n$docMain #} " implicit object ClassInfoOrdering extends Ordering[ClassInfo] { diff --git a/hkmc2/shared/src/test/mlscript/llir/BasicCpp.mls b/hkmc2/shared/src/test/mlscript/llir/BasicCpp.mls index 857ac1d5e6..9a6f3b003e 100644 --- a/hkmc2/shared/src/test/mlscript/llir/BasicCpp.mls +++ b/hkmc2/shared/src/test/mlscript/llir/BasicCpp.mls @@ -25,7 +25,9 @@ fun foo(a) = //│ def j$226(x$218) = //│ let x$230 = +(x$218,1) in //│ x$230 -//│ undefined +//│ def entry$231() = +//│ undefined +//│ entry = entry$231 :showWholeCpp fun bar(x) = @@ -34,16 +36,34 @@ foo(1) //│ //│ WholeProgramCpp: //│ #include "mlsprelude.h" -//│ _mlsValue _mls_j(_mlsValue); //│ _mlsValue _mls_foo(_mlsValue); +//│ _mlsValue _mls_entry(); +//│ _mlsValue _mls_j(_mlsValue); +//│ _mlsValue _mls_entry1(); //│ _mlsValue _mls_bar(_mlsValue); -//│ _mlsValue _mlsMain(); +//│ _mlsValue _mls_bar(_mlsValue _mls_x8) { +//│ _mlsValue _mls_retval; +//│ auto _mls_x7 = (_mls_x8 + _mlsValue::fromIntLit(1)); +//│ _mls_retval = _mls_x7; +//│ return _mls_retval; +//│ } //│ _mlsValue _mls_j(_mlsValue _mls_x1) { //│ _mlsValue _mls_retval; //│ auto _mls_x = (_mls_x1 + _mlsValue::fromIntLit(1)); //│ _mls_retval = _mls_x; //│ return _mls_retval; //│ } +//│ _mlsValue _mls_entry1() { +//│ _mlsValue _mls_retval; +//│ auto _mls_x9 = _mls_foo(_mlsValue::fromIntLit(1)); +//│ _mls_retval = _mls_x9; +//│ return _mls_retval; +//│ } +//│ _mlsValue _mls_entry() { +//│ _mlsValue _mls_retval; +//│ _mls_retval = _mlsValue::create<_mls_Unit>(); +//│ return _mls_retval; +//│ } //│ _mlsValue _mls_foo(_mlsValue _mls_a) { //│ _mlsValue _mls_retval; //│ auto _mls_x2 = _mlsValue::create<_mls_Unit>(); @@ -58,16 +78,5 @@ foo(1) //│ } //│ return _mls_retval; //│ } -//│ _mlsValue _mls_bar(_mlsValue _mls_x8) { -//│ _mlsValue _mls_retval; -//│ auto _mls_x7 = (_mls_x8 + _mlsValue::fromIntLit(1)); -//│ _mls_retval = _mls_x7; -//│ return _mls_retval; -//│ } -//│ _mlsValue _mlsMain() { -//│ _mlsValue _mls_retval; -//│ auto _mls_x9 = _mls_foo(_mlsValue::fromIntLit(1)); -//│ _mls_retval = _mls_x9; -//│ return _mls_retval; -//│ } +//│ _mlsValue _mlsMain() { return _mls_entry1(); } //│ int main() { return _mlsLargeStack(_mlsMainWrapper); } diff --git a/hkmc2/shared/src/test/mlscript/llir/Classes.mls b/hkmc2/shared/src/test/mlscript/llir/Classes.mls index 4bbbd2e105..4ee28bc028 100644 --- a/hkmc2/shared/src/test/mlscript/llir/Classes.mls +++ b/hkmc2/shared/src/test/mlscript/llir/Classes.mls @@ -26,21 +26,23 @@ fun main() = main() //│ LLIR: //│ class Base() { -//│ def get$246() = +//│ def get$248() = //│ 1 //│ } //│ class Derived() extends Base { -//│ def get$247() = +//│ def get$249() = //│ 2 //│ } -//│ def main$249() = -//│ let x$271 = Derived$254() in -//│ let x$272 = Base.get$246(x$271) in -//│ let x$273 = Derived.get$247(x$271) in -//│ let x$274 = *(x$272,x$273) in -//│ x$274 -//│ let* (x$275) = main() in -//│ x$275 +//│ def main$251() = +//│ let x$273 = Derived$256() in +//│ let x$274 = Base.get$248(x$273) in +//│ let x$275 = Derived.get$249(x$273) in +//│ let x$276 = *(x$274,x$275) in +//│ x$276 +//│ def entry$278() = +//│ let* (x$277) = main() in +//│ x$277 +//│ entry = entry$278 //│ //│ Interpreted: //│ 4 diff --git a/hkmc2/shared/src/test/mlscript/llir/ControlFlow.mls b/hkmc2/shared/src/test/mlscript/llir/ControlFlow.mls index 2b3bff9e11..d905e1d4cd 100644 --- a/hkmc2/shared/src/test/mlscript/llir/ControlFlow.mls +++ b/hkmc2/shared/src/test/mlscript/llir/ControlFlow.mls @@ -14,12 +14,14 @@ f1() //│ = 2 //│ LLIR: //│ -//│ def f1$218() = -//│ let x$227 = 1 in -//│ let x$228 = 2 in -//│ x$228 -//│ let* (x$229) = f1() in -//│ x$229 +//│ def f1$219() = +//│ let x$228 = 1 in +//│ let x$229 = 2 in +//│ x$229 +//│ def entry$231() = +//│ let* (x$230) = f1() in +//│ x$230 +//│ entry = entry$231 //│ //│ Interpreted: //│ 2 @@ -33,18 +35,20 @@ f2() //│ = 3 //│ LLIR: //│ -//│ def f2$230() = -//│ let x$240 = 0 in -//│ let x$241 = ==(x$240,1) in -//│ case x$241 of +//│ def f2$232() = +//│ let x$242 = 0 in +//│ let x$243 = ==(x$242,1) in +//│ case x$243 of //│ BoolLit(true) => //│ 2 //│ _ => //│ 3 -//│ def j$242() = +//│ def j$244() = //│ null -//│ let* (x$243) = f2() in -//│ x$243 +//│ def entry$246() = +//│ let* (x$245) = f2() in +//│ x$245 +//│ entry = entry$246 //│ //│ Interpreted: //│ 3 @@ -59,19 +63,21 @@ f3() //│ = 0 //│ LLIR: //│ -//│ def f3$244() = -//│ let x$254 = 0 in -//│ let x$255 = 1 in -//│ let x$256 = true in -//│ case x$256 of +//│ def f3$247() = +//│ let x$257 = 0 in +//│ let x$258 = 1 in +//│ let x$259 = true in +//│ case x$259 of //│ BoolLit(true) => -//│ x$254 +//│ x$257 //│ _ => -//│ x$255 -//│ def j$257() = +//│ x$258 +//│ def j$260() = //│ null -//│ let* (x$258) = f3() in -//│ x$258 +//│ def entry$262() = +//│ let* (x$261) = f3() in +//│ x$261 +//│ entry = entry$262 :sllir @@ -84,20 +90,22 @@ f4() //│ = 3 //│ LLIR: //│ -//│ def f4$259() = -//│ let x$272 = 0 in -//│ let x$273 = ==(x$272,1) in -//│ case x$273 of +//│ def f4$263() = +//│ let x$276 = 0 in +//│ let x$277 = ==(x$276,1) in +//│ case x$277 of //│ BoolLit(true) => -//│ let x$275 = 2 in -//│ jump j$274(x$275) +//│ let x$279 = 2 in +//│ jump j$278(x$279) //│ _ => -//│ let x$276 = 3 in -//│ jump j$274(x$276) -//│ def j$274(tmp$270) = -//│ tmp$270 -//│ let* (x$277) = f4() in -//│ x$277 +//│ let x$280 = 3 in +//│ jump j$278(x$280) +//│ def j$278(tmp$274) = +//│ tmp$274 +//│ def entry$282() = +//│ let* (x$281) = f4() in +//│ x$281 +//│ entry = entry$282 //│ //│ Interpreted: //│ 3 @@ -113,29 +121,31 @@ f5() //│ = 5 //│ LLIR: //│ -//│ def f5$278() = -//│ let x$296 = 0 in -//│ let x$297 = ==(x$296,1) in -//│ case x$297 of +//│ def f5$283() = +//│ let x$301 = 0 in +//│ let x$302 = ==(x$301,1) in +//│ case x$302 of //│ BoolLit(true) => -//│ let x$299 = 2 in -//│ jump j$298(x$299) +//│ let x$304 = 2 in +//│ jump j$303(x$304) //│ _ => -//│ let x$300 = 3 in -//│ jump j$298(x$300) -//│ def j$298(tmp$293) = -//│ let x$301 = ==(tmp$293,2) in -//│ case x$301 of +//│ let x$305 = 3 in +//│ jump j$303(x$305) +//│ def j$303(tmp$298) = +//│ let x$306 = ==(tmp$298,2) in +//│ case x$306 of //│ BoolLit(true) => -//│ let x$303 = 4 in -//│ jump j$302(x$303) +//│ let x$308 = 4 in +//│ jump j$307(x$308) //│ _ => -//│ let x$304 = 5 in -//│ jump j$302(x$304) -//│ def j$302(tmp$294) = -//│ tmp$294 -//│ let* (x$305) = f5() in -//│ x$305 +//│ let x$309 = 5 in +//│ jump j$307(x$309) +//│ def j$307(tmp$299) = +//│ tmp$299 +//│ def entry$311() = +//│ let* (x$310) = f5() in +//│ x$310 +//│ entry = entry$311 //│ //│ Interpreted: //│ 5 @@ -146,23 +156,25 @@ fun test() = if true do test() //│ LLIR: //│ -//│ def test$306() = -//│ let x$314 = true in -//│ case x$314 of +//│ def test$312() = +//│ let x$320 = true in +//│ case x$320 of //│ BoolLit(true) => -//│ let* (x$316) = test() in -//│ x$316 +//│ let* (x$322) = test() in +//│ x$322 //│ _ => //│ undefined -//│ def j$315() = +//│ def j$321() = //│ null -//│ undefined +//│ def entry$323() = +//│ undefined +//│ entry = entry$323 //│ //│ Cpp: //│ #include "mlsprelude.h" //│ _mlsValue _mls_j5(); //│ _mlsValue _mls_test(); -//│ _mlsValue _mlsMain(); +//│ _mlsValue _mls_entry6(); //│ _mlsValue _mls_j5() { //│ _mlsValue _mls_retval; //│ _mls_retval = _mlsValue::create<_mls_Unit>(); @@ -179,11 +191,12 @@ fun test() = //│ } //│ return _mls_retval; //│ } -//│ _mlsValue _mlsMain() { +//│ _mlsValue _mls_entry6() { //│ _mlsValue _mls_retval; //│ _mls_retval = _mlsValue::create<_mls_Unit>(); //│ return _mls_retval; //│ } +//│ _mlsValue _mlsMain() { return _mls_entry6(); } //│ int main() { return _mlsLargeStack(_mlsMainWrapper); } :sllir @@ -192,24 +205,26 @@ fun test() = (if true then test()) + 1 //│ LLIR: //│ -//│ def test$317() = -//│ let x$328 = true in -//│ case x$328 of +//│ def test$324() = +//│ let x$335 = true in +//│ case x$335 of //│ BoolLit(true) => -//│ let* (x$330) = test() in -//│ jump j$329(x$330) +//│ let* (x$337) = test() in +//│ jump j$336(x$337) //│ _ => //│ panic "match error" -//│ def j$329(tmp$327) = -//│ let x$331 = +(tmp$327,1) in -//│ x$331 -//│ undefined +//│ def j$336(tmp$334) = +//│ let x$338 = +(tmp$334,1) in +//│ x$338 +//│ def entry$339() = +//│ undefined +//│ entry = entry$339 //│ //│ Cpp: //│ #include "mlsprelude.h" //│ _mlsValue _mls_j6(_mlsValue); //│ _mlsValue _mls_test1(); -//│ _mlsValue _mlsMain(); +//│ _mlsValue _mls_entry7(); //│ _mlsValue _mls_j6(_mlsValue _mls_tmp3) { //│ _mlsValue _mls_retval; //│ auto _mls_x25 = (_mls_tmp3 + _mlsValue::fromIntLit(1)); @@ -227,11 +242,12 @@ fun test() = //│ } //│ return _mls_retval; //│ } -//│ _mlsValue _mlsMain() { +//│ _mlsValue _mls_entry7() { //│ _mlsValue _mls_retval; //│ _mls_retval = _mlsValue::create<_mls_Unit>(); //│ return _mls_retval; //│ } +//│ _mlsValue _mlsMain() { return _mls_entry7(); } //│ int main() { return _mlsLargeStack(_mlsMainWrapper); } @@ -247,27 +263,29 @@ f() //│ = 11 //│ LLIR: //│ -//│ def f$332() = -//│ let x$346 = 10 in -//│ let x$347 = true in -//│ case x$347 of +//│ def f$340() = +//│ let x$354 = 10 in +//│ let x$355 = true in +//│ case x$355 of //│ BoolLit(true) => -//│ let x$349 = +(x$346,1) in -//│ let x$350 = undefined in -//│ jump j$348(x$349) +//│ let x$357 = +(x$354,1) in +//│ let x$358 = undefined in +//│ jump j$356(x$357) //│ _ => -//│ let x$351 = undefined in -//│ jump j$348(x$346) -//│ def j$348(x$333) = -//│ x$333 -//│ let* (x$352) = f() in -//│ x$352 +//│ let x$359 = undefined in +//│ jump j$356(x$354) +//│ def j$356(x$341) = +//│ x$341 +//│ def entry$361() = +//│ let* (x$360) = f() in +//│ x$360 +//│ entry = entry$361 //│ //│ Cpp: //│ #include "mlsprelude.h" //│ _mlsValue _mls_j7(_mlsValue); //│ _mlsValue _mls_f(); -//│ _mlsValue _mlsMain(); +//│ _mlsValue _mls_entry8(); //│ _mlsValue _mls_j7(_mlsValue _mls_x28) { //│ _mlsValue _mls_retval; //│ _mls_retval = _mls_x28; @@ -287,12 +305,13 @@ f() //│ } //│ return _mls_retval; //│ } -//│ _mlsValue _mlsMain() { +//│ _mlsValue _mls_entry8() { //│ _mlsValue _mls_retval; //│ auto _mls_x34 = _mls_f(); //│ _mls_retval = _mls_x34; //│ return _mls_retval; //│ } +//│ _mlsValue _mlsMain() { return _mls_entry8(); } //│ int main() { return _mlsLargeStack(_mlsMainWrapper); } //│ //│ Interpreted: @@ -310,29 +329,31 @@ fun f(a) = f(A(1)) //│ = 1 //│ LLIR: -//│ class A(x$358) -//│ class B(y$361) -//│ def f$355(a$362) = -//│ case a$362 of -//│ A$356 => -//│ let x$382 = a$362. in -//│ let x$383 = 1 in -//│ jump j$381(x$383) +//│ class A(x$367) +//│ class B(y$370) +//│ def f$364(a$371) = +//│ case a$371 of +//│ A$365 => +//│ let x$391 = a$371. in +//│ let x$392 = 1 in +//│ jump j$390(x$392) //│ _ => -//│ case a$362 of -//│ B$359 => -//│ let x$385 = a$362. in -//│ let x$386 = 2 in -//│ jump j$384(x$386) +//│ case a$371 of +//│ B$368 => +//│ let x$394 = a$371. in +//│ let x$395 = 2 in +//│ jump j$393(x$395) //│ _ => //│ panic "match error" -//│ def j$384(tmp$377) = -//│ jump j$381(tmp$377) -//│ def j$381(tmp$377) = -//│ tmp$377 -//│ let x$387 = A$356(1) in -//│ let* (x$388) = f(x$387) in -//│ x$388 +//│ def j$393(tmp$386) = +//│ jump j$390(tmp$386) +//│ def j$390(tmp$386) = +//│ tmp$386 +//│ def entry$398() = +//│ let x$396 = A$365(1) in +//│ let* (x$397) = f(x$396) in +//│ x$397 +//│ entry = entry$398 //│ //│ Interpreted: //│ 1 @@ -351,50 +372,52 @@ fun f(a) = f(A(1)) //│ = 1 //│ LLIR: -//│ class A(x$394) -//│ class B(y$397) -//│ def f$391(a$398) = -//│ case a$398 of -//│ A$392 => -//│ let x$422 = a$398. in -//│ case a$398 of -//│ A$392 => -//│ let x$424 = a$398. in -//│ case x$424 of +//│ class A(x$404) +//│ class B(y$407) +//│ def f$401(a$408) = +//│ case a$408 of +//│ A$402 => +//│ let x$432 = a$408. in +//│ case a$408 of +//│ A$402 => +//│ let x$434 = a$408. in +//│ case x$434 of //│ IntLit(1) => -//│ let x$426 = 1 in -//│ jump j$425(x$426) +//│ let x$436 = 1 in +//│ jump j$435(x$436) //│ _ => //│ panic "match error" //│ _ => -//│ case a$398 of -//│ B$395 => -//│ let x$428 = a$398. in -//│ let x$429 = 2 in -//│ jump j$427(x$429) +//│ case a$408 of +//│ B$405 => +//│ let x$438 = a$408. in +//│ let x$439 = 2 in +//│ jump j$437(x$439) //│ _ => //│ panic "match error" //│ _ => -//│ case a$398 of -//│ B$395 => -//│ let x$431 = a$398. in -//│ let x$432 = 3 in -//│ jump j$430(x$432) +//│ case a$408 of +//│ B$405 => +//│ let x$441 = a$408. in +//│ let x$442 = 3 in +//│ jump j$440(x$442) //│ _ => //│ panic "match error" -//│ def j$425(tmp$416) = -//│ jump j$423(tmp$416) -//│ def j$427(tmp$416) = -//│ jump j$423(tmp$416) -//│ def j$423(tmp$416) = -//│ jump j$421(tmp$416) -//│ def j$430(tmp$417) = -//│ jump j$421(tmp$417) -//│ def j$421(tmp$417) = -//│ tmp$417 -//│ let x$433 = A$392(1) in -//│ let* (x$434) = f(x$433) in -//│ x$434 +//│ def j$435(tmp$426) = +//│ jump j$433(tmp$426) +//│ def j$437(tmp$426) = +//│ jump j$433(tmp$426) +//│ def j$433(tmp$426) = +//│ jump j$431(tmp$426) +//│ def j$440(tmp$427) = +//│ jump j$431(tmp$427) +//│ def j$431(tmp$427) = +//│ tmp$427 +//│ def entry$445() = +//│ let x$443 = A$402(1) in +//│ let* (x$444) = f(x$443) in +//│ x$444 +//│ entry = entry$445 //│ //│ Interpreted: //│ 1 diff --git a/hkmc2/shared/src/test/mlscript/llir/Ctor.mls b/hkmc2/shared/src/test/mlscript/llir/Ctor.mls index fd01b7828a..9a946e410d 100644 --- a/hkmc2/shared/src/test/mlscript/llir/Ctor.mls +++ b/hkmc2/shared/src/test/mlscript/llir/Ctor.mls @@ -10,24 +10,28 @@ fun testCtor1() = None fun testCtor2() = new None //│ LLIR: //│ class None() -//│ def testCtor1$219() = -//│ let x$228 = None$221() in -//│ x$228 -//│ def testCtor2$218() = -//│ let x$229 = None$221() in +//│ def testCtor1$220() = +//│ let x$229 = None$222() in //│ x$229 -//│ undefined +//│ def testCtor2$219() = +//│ let x$230 = None$222() in +//│ x$230 +//│ def entry$231() = +//│ undefined +//│ entry = entry$231 :sllir class A(x) fun testCtor1() = A(1) fun testCtor2() = new A(1) //│ LLIR: -//│ class A(x$235) -//│ def testCtor1$232() = -//│ let x$243 = A$233(1) in -//│ x$243 -//│ def testCtor2$231() = -//│ let x$244 = A$233(1) in -//│ x$244 -//│ undefined +//│ class A(x$237) +//│ def testCtor1$234() = +//│ let x$245 = A$235(1) in +//│ x$245 +//│ def testCtor2$233() = +//│ let x$246 = A$235(1) in +//│ x$246 +//│ def entry$247() = +//│ undefined +//│ entry = entry$247 diff --git a/hkmc2/shared/src/test/mlscript/llir/HigherOrder.mls b/hkmc2/shared/src/test/mlscript/llir/HigherOrder.mls index 958ee31c9f..9081241d30 100644 --- a/hkmc2/shared/src/test/mlscript/llir/HigherOrder.mls +++ b/hkmc2/shared/src/test/mlscript/llir/HigherOrder.mls @@ -12,25 +12,27 @@ fun add_curried(x)(y) = x + y add(1)(2) //│ = 3 //│ LLIR: -//│ class Lambda(lam_arg0$240) extends Callable { -//│ def apply1$241(y$221) = -//│ let x$242 = +(lam_arg0$240,y$221) in -//│ x$242 +//│ class Lambda(lam_arg0$241) extends Callable { +//│ def apply1$242(y$222) = +//│ let x$243 = +(lam_arg0$241,y$222) in +//│ x$243 //│ } -//│ class Lambda(lam_arg0$247) extends Callable { -//│ def apply1$241(y$225) = -//│ let x$248 = +(lam_arg0$247,y$225) in -//│ x$248 +//│ class Lambda(lam_arg0$248) extends Callable { +//│ def apply1$242(y$226) = +//│ let x$249 = +(lam_arg0$248,y$226) in +//│ x$249 //│ } -//│ def add$218(x$220) = -//│ let x$244 = Lambda$238(x$220) in -//│ x$244 -//│ def add_curried$219(x$224) = -//│ let x$249 = Lambda$245(x$224) in -//│ x$249 -//│ let* (x$250) = add(1) in -//│ let x$251 = Callable.apply1$241(x$250,2) in -//│ x$251 +//│ def add$219(x$221) = +//│ let x$245 = Lambda$239(x$221) in +//│ x$245 +//│ def add_curried$220(x$225) = +//│ let x$250 = Lambda$246(x$225) in +//│ x$250 +//│ def entry$253() = +//│ let* (x$251) = add(1) in +//│ let x$252 = Callable.apply1$242(x$251,2) in +//│ x$252 +//│ entry = entry$253 //│ //│ Cpp: //│ #include "mlsprelude.h" @@ -38,7 +40,7 @@ add(1)(2) //│ struct _mls_Lambda1; //│ _mlsValue _mls_add(_mlsValue); //│ _mlsValue _mls_add_curried(_mlsValue); -//│ _mlsValue _mlsMain(); +//│ _mlsValue _mls_entry1(); //│ struct _mls_Lambda: public _mls_Callable { //│ _mlsValue _mls_lam_arg0; //│ constexpr static inline const char *typeName = "Lambda"; @@ -69,6 +71,13 @@ add(1)(2) //│ _mls_retval = _mls_x4; //│ return _mls_retval; //│ } +//│ _mlsValue _mls_entry1() { +//│ _mlsValue _mls_retval; +//│ auto _mls_x6 = _mls_add(_mlsValue::fromIntLit(1)); +//│ auto _mls_x7 = _mlsMethodCall<_mls_Callable>(_mls_x6)->_mls_apply1(_mlsValue::fromIntLit(2)); +//│ _mls_retval = _mls_x7; +//│ return _mls_retval; +//│ } //│ _mlsValue _mls_Lambda::_mls_apply1(_mlsValue _mls_y) { //│ _mlsValue _mls_retval; //│ auto _mls_x = (_mls_lam_arg0 + _mls_y); @@ -81,13 +90,7 @@ add(1)(2) //│ _mls_retval = _mls_x1; //│ return _mls_retval; //│ } -//│ _mlsValue _mlsMain() { -//│ _mlsValue _mls_retval; -//│ auto _mls_x6 = _mls_add(_mlsValue::fromIntLit(1)); -//│ auto _mls_x7 = _mlsMethodCall<_mls_Callable>(_mls_x6)->_mls_apply1(_mlsValue::fromIntLit(2)); -//│ _mls_retval = _mls_x7; -//│ return _mls_retval; -//│ } +//│ _mlsValue _mlsMain() { return _mls_entry1(); } //│ int main() { return _mlsLargeStack(_mlsMainWrapper); } //│ //│ Interpreted: @@ -101,29 +104,31 @@ fun add4_curried(a, b)(c, d) = a + b + c + d add4(1, 2)(3, 4) //│ = 10 //│ LLIR: -//│ class Lambda(lam_arg0$290,lam_arg1$291) extends Callable { -//│ def apply2$292(c$256,d$257) = -//│ let x$293 = +(lam_arg1$291,lam_arg0$290) in -//│ let x$294 = +(x$293,c$256) in -//│ let x$295 = +(x$294,d$257) in -//│ x$295 +//│ class Lambda(lam_arg0$292,lam_arg1$293) extends Callable { +//│ def apply2$294(c$258,d$259) = +//│ let x$295 = +(lam_arg1$293,lam_arg0$292) in +//│ let x$296 = +(x$295,c$258) in +//│ let x$297 = +(x$296,d$259) in +//│ x$297 //│ } -//│ class Lambda(lam_arg0$299,lam_arg1$300) extends Callable { -//│ def apply2$292(c$264,d$265) = -//│ let x$301 = +(lam_arg1$300,lam_arg0$299) in -//│ let x$302 = +(x$301,c$264) in -//│ let x$303 = +(x$302,d$265) in -//│ x$303 +//│ class Lambda(lam_arg0$301,lam_arg1$302) extends Callable { +//│ def apply2$294(c$266,d$267) = +//│ let x$303 = +(lam_arg1$302,lam_arg0$301) in +//│ let x$304 = +(x$303,c$266) in +//│ let x$305 = +(x$304,d$267) in +//│ x$305 //│ } -//│ def add4$253(a$254,b$255) = -//│ let x$296 = Lambda$288(b$255,a$254) in -//│ x$296 -//│ def add4_curried$252(a$262,b$263) = -//│ let x$304 = Lambda$297(b$263,a$262) in -//│ x$304 -//│ let* (x$305) = add4(1,2) in -//│ let x$306 = Callable.apply2$292(x$305,3,4) in -//│ x$306 +//│ def add4$255(a$256,b$257) = +//│ let x$298 = Lambda$290(b$257,a$256) in +//│ x$298 +//│ def add4_curried$254(a$264,b$265) = +//│ let x$306 = Lambda$299(b$265,a$264) in +//│ x$306 +//│ def entry$309() = +//│ let* (x$307) = add4(1,2) in +//│ let x$308 = Callable.apply2$294(x$307,3,4) in +//│ x$308 +//│ entry = entry$309 //│ //│ Cpp: //│ #include "mlsprelude.h" @@ -131,7 +136,7 @@ add4(1, 2)(3, 4) //│ struct _mls_Lambda3; //│ _mlsValue _mls_add4(_mlsValue, _mlsValue); //│ _mlsValue _mls_add4_curried(_mlsValue, _mlsValue); -//│ _mlsValue _mlsMain(); +//│ _mlsValue _mls_entry2(); //│ struct _mls_Lambda2: public _mls_Callable { //│ _mlsValue _mls_lam_arg0; //│ _mlsValue _mls_lam_arg1; @@ -164,6 +169,13 @@ add4(1, 2)(3, 4) //│ _mls_retval = _mls_x15; //│ return _mls_retval; //│ } +//│ _mlsValue _mls_entry2() { +//│ _mlsValue _mls_retval; +//│ auto _mls_x16 = _mls_add4(_mlsValue::fromIntLit(1), _mlsValue::fromIntLit(2)); +//│ auto _mls_x17 = _mlsMethodCall<_mls_Callable>(_mls_x16)->_mls_apply2(_mlsValue::fromIntLit(3), _mlsValue::fromIntLit(4)); +//│ _mls_retval = _mls_x17; +//│ return _mls_retval; +//│ } //│ _mlsValue _mls_Lambda2::_mls_apply2(_mlsValue _mls_c, _mlsValue _mls_d) { //│ _mlsValue _mls_retval; //│ auto _mls_x8 = (_mls_lam_arg1 + _mls_lam_arg0); @@ -180,13 +192,7 @@ add4(1, 2)(3, 4) //│ _mls_retval = _mls_x13; //│ return _mls_retval; //│ } -//│ _mlsValue _mlsMain() { -//│ _mlsValue _mls_retval; -//│ auto _mls_x16 = _mls_add4(_mlsValue::fromIntLit(1), _mlsValue::fromIntLit(2)); -//│ auto _mls_x17 = _mlsMethodCall<_mls_Callable>(_mls_x16)->_mls_apply2(_mlsValue::fromIntLit(3), _mlsValue::fromIntLit(4)); -//│ _mls_retval = _mls_x17; -//│ return _mls_retval; -//│ } +//│ _mlsValue _mlsMain() { return _mls_entry2(); } //│ int main() { return _mlsLargeStack(_mlsMainWrapper); } //│ //│ Interpreted: @@ -201,26 +207,28 @@ dummy()(1, 2) //│ = 3 //│ LLIR: //│ class Lambda_add() extends Callable { -//│ def apply2$292(arg$325,arg$326) = -//│ let* (x$329) = add(arg$325,arg$326) in -//│ x$329 +//│ def apply2$294(arg$328,arg$329) = +//│ let* (x$332) = add(arg$328,arg$329) in +//│ x$332 //│ } -//│ def add$307(a$309,b$310) = -//│ let x$324 = +(a$309,b$310) in -//│ x$324 -//│ def dummy$308() = -//│ let x$330 = Lambda_add$327() in -//│ x$330 -//│ let* (x$331) = dummy() in -//│ let x$332 = Callable.apply2$292(x$331,1,2) in -//│ x$332 +//│ def add$310(a$312,b$313) = +//│ let x$327 = +(a$312,b$313) in +//│ x$327 +//│ def dummy$311() = +//│ let x$333 = Lambda_add$330() in +//│ x$333 +//│ def entry$336() = +//│ let* (x$334) = dummy() in +//│ let x$335 = Callable.apply2$294(x$334,1,2) in +//│ x$335 +//│ entry = entry$336 //│ //│ Cpp: //│ #include "mlsprelude.h" //│ struct _mls_Lambda_add; //│ _mlsValue _mls_add1(_mlsValue, _mlsValue); //│ _mlsValue _mls_dummy(); -//│ _mlsValue _mlsMain(); +//│ _mlsValue _mls_entry3(); //│ struct _mls_Lambda_add: public _mls_Callable { //│ //│ constexpr static inline const char *typeName = "Lambda_add"; @@ -242,19 +250,20 @@ dummy()(1, 2) //│ _mls_retval = _mls_x20; //│ return _mls_retval; //│ } -//│ _mlsValue _mls_Lambda_add::_mls_apply2(_mlsValue _mls_arg, _mlsValue _mls_arg1) { -//│ _mlsValue _mls_retval; -//│ auto _mls_x18 = _mls_add1(_mls_arg, _mls_arg1); -//│ _mls_retval = _mls_x18; -//│ return _mls_retval; -//│ } -//│ _mlsValue _mlsMain() { +//│ _mlsValue _mls_entry3() { //│ _mlsValue _mls_retval; //│ auto _mls_x21 = _mls_dummy(); //│ auto _mls_x22 = _mlsMethodCall<_mls_Callable>(_mls_x21)->_mls_apply2(_mlsValue::fromIntLit(1), _mlsValue::fromIntLit(2)); //│ _mls_retval = _mls_x22; //│ return _mls_retval; //│ } +//│ _mlsValue _mls_Lambda_add::_mls_apply2(_mlsValue _mls_arg, _mlsValue _mls_arg1) { +//│ _mlsValue _mls_retval; +//│ auto _mls_x18 = _mls_add1(_mls_arg, _mls_arg1); +//│ _mls_retval = _mls_x18; +//│ return _mls_retval; +//│ } +//│ _mlsValue _mlsMain() { return _mls_entry3(); } //│ int main() { return _mlsLargeStack(_mlsMainWrapper); } //│ //│ Interpreted: @@ -277,55 +286,57 @@ main() //│ = Cons(4, Cons(5, Nil)) //│ LLIR: //│ class List() -//│ class Cons(head$345,tail$346) extends List +//│ class Cons(head$349,tail$350) extends List //│ class Nil() extends List //│ class Lambda() extends Callable { -//│ def apply1$241(x$363) = -//│ let* (x$428) = inc(x$363) in -//│ x$428 +//│ def apply1$242(x$367) = +//│ let* (x$432) = inc(x$367) in +//│ x$432 //│ } //│ class Lambda_inc() extends Callable { -//│ def apply1$241(arg$434) = -//│ let* (x$437) = inc(arg$434) in -//│ x$437 +//│ def apply1$242(arg$438) = +//│ let* (x$441) = inc(arg$438) in +//│ x$441 //│ } -//│ def map$334(f$349,l$350) = -//│ case l$350 of -//│ Cons$342 => -//│ let x$414 = l$350. in -//│ let x$415 = l$350. in -//│ let x$416 = Callable.apply1$241(f$349,x$414) in -//│ let* (x$417) = map(f$349,x$415) in -//│ let x$418 = Cons$342(x$416,x$417) in -//│ x$418 +//│ def map$338(f$353,l$354) = +//│ case l$354 of +//│ Cons$346 => +//│ let x$418 = l$354. in +//│ let x$419 = l$354. in +//│ let x$420 = Callable.apply1$242(f$353,x$418) in +//│ let* (x$421) = map(f$353,x$419) in +//│ let x$422 = Cons$346(x$420,x$421) in +//│ x$422 //│ _ => -//│ case l$350 of -//│ Nil$347 => -//│ let x$420 = Nil$347() in -//│ x$420 +//│ case l$354 of +//│ Nil$351 => +//│ let x$424 = Nil$351() in +//│ x$424 //│ _ => //│ panic "match error" -//│ def j$419() = -//│ jump j$413() -//│ def j$413() = +//│ def j$423() = +//│ jump j$417() +//│ def j$417() = //│ null -//│ def inc$337(x$359) = -//│ let x$421 = +(x$359,1) in -//│ x$421 -//│ def main$335() = -//│ let x$422 = Nil$347() in -//│ let x$423 = Cons$342(2,x$422) in -//│ let x$424 = Cons$342(1,x$423) in -//│ let x$429 = Lambda$426() in -//│ let* (x$425) = map(x$429,x$424) in -//│ let x$430 = Nil$347() in -//│ let x$431 = Cons$342(4,x$430) in -//│ let x$432 = Cons$342(3,x$431) in -//│ let x$438 = Lambda_inc$435() in -//│ let* (x$433) = map(x$438,x$432) in -//│ x$433 -//│ let* (x$439) = main() in -//│ x$439 +//│ def inc$341(x$363) = +//│ let x$425 = +(x$363,1) in +//│ x$425 +//│ def main$339() = +//│ let x$426 = Nil$351() in +//│ let x$427 = Cons$346(2,x$426) in +//│ let x$428 = Cons$346(1,x$427) in +//│ let x$433 = Lambda$430() in +//│ let* (x$429) = map(x$433,x$428) in +//│ let x$434 = Nil$351() in +//│ let x$435 = Cons$346(4,x$434) in +//│ let x$436 = Cons$346(3,x$435) in +//│ let x$442 = Lambda_inc$439() in +//│ let* (x$437) = map(x$442,x$436) in +//│ x$437 +//│ def entry$444() = +//│ let* (x$443) = main() in +//│ x$443 +//│ entry = entry$444 //│ //│ Interpreted: //│ Cons(4,Cons(5,Nil())) @@ -349,83 +360,85 @@ nubBy((x, y) => x == y, 1 :: 2 :: 3 :: 3 :: Nil) //│ = Cons(1, Cons(2, Cons(3, Nil))) //│ LLIR: //│ class List() -//│ class Cons(head$452,tail$453) extends List +//│ class Cons(head$457,tail$458) extends List //│ class Nil() extends List -//│ class Lambda(lam_arg0$559,lam_arg1$560) extends Callable { -//│ def apply1$241(y$479) = -//│ let x$561 = Callable.apply2$292(lam_arg0$559,lam_arg1$560,y$479) in -//│ let* (x$562) = not(x$561) in -//│ x$562 +//│ class Lambda(lam_arg0$564,lam_arg1$565) extends Callable { +//│ def apply1$242(y$484) = +//│ let x$566 = Callable.apply2$294(lam_arg0$564,lam_arg1$565,y$484) in +//│ let* (x$567) = not(x$566) in +//│ x$567 //│ } //│ class Lambda() extends Callable { -//│ def apply2$292(x$484,y$485) = -//│ let x$574 = ==(x$484,y$485) in -//│ x$574 +//│ def apply2$294(x$489,y$490) = +//│ let x$579 = ==(x$489,y$490) in +//│ x$579 //│ } -//│ def not$443(c$456) = -//│ case c$456 of +//│ def not$448(c$461) = +//│ case c$461 of //│ BoolLit(true) => //│ false //│ _ => //│ true -//│ def j$540() = +//│ def j$545() = //│ null -//│ def filter$442(f$458,ls$459) = -//│ case ls$459 of -//│ Nil$454 => -//│ let x$542 = Nil$454() in -//│ x$542 +//│ def filter$447(f$463,ls$464) = +//│ case ls$464 of +//│ Nil$459 => +//│ let x$547 = Nil$459() in +//│ x$547 //│ _ => -//│ case ls$459 of -//│ Cons$449 => -//│ let x$544 = ls$459. in -//│ let x$545 = ls$459. in -//│ let x$546 = Callable.apply1$241(f$458,x$544) in -//│ case x$546 of +//│ case ls$464 of +//│ Cons$454 => +//│ let x$549 = ls$464. in +//│ let x$550 = ls$464. in +//│ let x$551 = Callable.apply1$242(f$463,x$549) in +//│ case x$551 of //│ BoolLit(true) => -//│ let* (x$548) = filter(f$458,x$545) in -//│ let x$549 = Cons$449(x$544,x$548) in -//│ x$549 +//│ let* (x$553) = filter(f$463,x$550) in +//│ let x$554 = Cons$454(x$549,x$553) in +//│ x$554 //│ _ => -//│ let* (x$550) = filter(f$458,x$545) in -//│ x$550 +//│ let* (x$555) = filter(f$463,x$550) in +//│ x$555 //│ _ => //│ panic "match error" -//│ def j$547() = -//│ jump j$543() -//│ def j$543() = -//│ jump j$541() -//│ def j$541() = +//│ def j$552() = +//│ jump j$548() +//│ def j$548() = +//│ jump j$546() +//│ def j$546() = //│ null -//│ def nubBy$445(eq$470,ls$471) = -//│ case ls$471 of -//│ Nil$454 => -//│ let x$552 = Nil$454() in -//│ x$552 +//│ def nubBy$450(eq$475,ls$476) = +//│ case ls$476 of +//│ Nil$459 => +//│ let x$557 = Nil$459() in +//│ x$557 //│ _ => -//│ case ls$471 of -//│ Cons$449 => -//│ let x$554 = ls$471. in -//│ let x$555 = ls$471. in -//│ let x$563 = Lambda$557(eq$470,x$554) in -//│ let* (x$556) = filter(x$563,x$555) in -//│ let* (x$564) = nubBy(eq$470,x$556) in -//│ let x$565 = Cons$449(x$554,x$564) in -//│ x$565 +//│ case ls$476 of +//│ Cons$454 => +//│ let x$559 = ls$476. in +//│ let x$560 = ls$476. in +//│ let x$568 = Lambda$562(eq$475,x$559) in +//│ let* (x$561) = filter(x$568,x$560) in +//│ let* (x$569) = nubBy(eq$475,x$561) in +//│ let x$570 = Cons$454(x$559,x$569) in +//│ x$570 //│ _ => //│ panic "match error" -//│ def j$553() = -//│ jump j$551() -//│ def j$551() = +//│ def j$558() = +//│ jump j$556() +//│ def j$556() = //│ null -//│ let x$566 = Nil$454() in -//│ let x$567 = Cons$449(3,x$566) in -//│ let x$568 = Cons$449(3,x$567) in -//│ let x$569 = Cons$449(2,x$568) in -//│ let x$570 = Cons$449(1,x$569) in -//│ let x$575 = Lambda$572() in -//│ let* (x$571) = nubBy(x$575,x$570) in -//│ x$571 +//│ def entry$581() = +//│ let x$571 = Nil$459() in +//│ let x$572 = Cons$454(3,x$571) in +//│ let x$573 = Cons$454(3,x$572) in +//│ let x$574 = Cons$454(2,x$573) in +//│ let x$575 = Cons$454(1,x$574) in +//│ let x$580 = Lambda$577() in +//│ let* (x$576) = nubBy(x$580,x$575) in +//│ x$576 +//│ entry = entry$581 //│ //│ Cpp: //│ #include "mlsprelude.h" @@ -434,6 +447,7 @@ nubBy((x, y) => x == y, 1 :: 2 :: 3 :: 3 :: Nil) //│ struct _mls_Nil1; //│ struct _mls_Lambda6; //│ struct _mls_Lambda5; +//│ _mlsValue _mls_entry5(); //│ _mlsValue _mls_j4(); //│ _mlsValue _mls_j6(); //│ _mlsValue _mls_filter(_mlsValue, _mlsValue); @@ -443,7 +457,6 @@ nubBy((x, y) => x == y, 1 :: 2 :: 3 :: 3 :: Nil) //│ _mlsValue _mls_nubBy(_mlsValue, _mlsValue); //│ _mlsValue _mls_j2(); //│ _mlsValue _mls_j3(); -//│ _mlsValue _mlsMain(); //│ struct _mls_List1: public _mlsObject { //│ //│ constexpr static inline const char *typeName = "List"; @@ -491,70 +504,78 @@ nubBy((x, y) => x == y, 1 :: 2 :: 3 :: 3 :: Nil) //│ static _mlsValue create(_mlsValue _mls_lam_arg0, _mlsValue _mls_lam_arg1) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) _mls_Lambda5; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->_mls_lam_arg0 = _mls_lam_arg0; _mlsVal->_mls_lam_arg1 = _mls_lam_arg1; return _mlsValue(_mlsVal); } //│ virtual _mlsValue _mls_apply1(_mlsValue); //│ }; -//│ _mlsValue _mls_j3() { +//│ _mlsValue _mls_not(_mlsValue _mls_c2) { //│ _mlsValue _mls_retval; -//│ _mls_retval = _mlsValue::create<_mls_Unit>(); +//│ if (_mlsValue::isIntLit(_mls_c2, 1)) { +//│ _mls_retval = _mlsValue::fromIntLit(0); +//│ } else { +//│ _mls_retval = _mlsValue::fromIntLit(1); +//│ } //│ return _mls_retval; //│ } -//│ _mlsValue _mls_j5() { +//│ _mlsValue _mls_entry5() { //│ _mlsValue _mls_retval; -//│ _mls_retval = _mls_j2(); +//│ auto _mls_x56 = _mlsValue::create<_mls_Nil1>(); +//│ auto _mls_x57 = _mlsValue::create<_mls_Cons1>(_mlsValue::fromIntLit(3), _mls_x56); +//│ auto _mls_x58 = _mlsValue::create<_mls_Cons1>(_mlsValue::fromIntLit(3), _mls_x57); +//│ auto _mls_x59 = _mlsValue::create<_mls_Cons1>(_mlsValue::fromIntLit(2), _mls_x58); +//│ auto _mls_x60 = _mlsValue::create<_mls_Cons1>(_mlsValue::fromIntLit(1), _mls_x59); +//│ auto _mls_x61 = _mlsValue::create<_mls_Lambda6>(); +//│ auto _mls_x62 = _mls_nubBy(_mls_x61, _mls_x60); +//│ _mls_retval = _mls_x62; //│ return _mls_retval; //│ } -//│ _mlsValue _mls_j4() { +//│ _mlsValue _mls_j6() { //│ _mlsValue _mls_retval; -//│ _mls_retval = _mls_j3(); +//│ _mls_retval = _mls_j5(); +//│ return _mls_retval; +//│ } +//│ _mlsValue _mls_j3() { +//│ _mlsValue _mls_retval; +//│ _mls_retval = _mlsValue::create<_mls_Unit>(); //│ return _mls_retval; //│ } -//│ _mlsValue _mls_filter(_mlsValue _mls_f1, _mlsValue _mls_ls1) { +//│ _mlsValue _mls_nubBy(_mlsValue _mls_eq, _mlsValue _mls_ls1) { //│ _mlsValue _mls_retval; //│ if (_mlsValue::isValueOf<_mls_Nil1>(_mls_ls1)) { -//│ auto _mls_x62 = _mlsValue::create<_mls_Nil1>(); -//│ _mls_retval = _mls_x62; +//│ auto _mls_x69 = _mlsValue::create<_mls_Nil1>(); +//│ _mls_retval = _mls_x69; //│ } else { //│ if (_mlsValue::isValueOf<_mls_Cons1>(_mls_ls1)) { -//│ auto _mls_x56 = _mlsValue::cast<_mls_Cons1>(_mls_ls1)->_mls_head; -//│ auto _mls_x57 = _mlsValue::cast<_mls_Cons1>(_mls_ls1)->_mls_tail; -//│ auto _mls_x58 = _mlsMethodCall<_mls_Callable>(_mls_f1)->_mls_apply1(_mls_x56); -//│ if (_mlsValue::isIntLit(_mls_x58, 1)) { -//│ auto _mls_x60 = _mls_filter(_mls_f1, _mls_x57); -//│ auto _mls_x61 = _mlsValue::create<_mls_Cons1>(_mls_x56, _mls_x60); -//│ _mls_retval = _mls_x61; -//│ } else { -//│ auto _mls_x59 = _mls_filter(_mls_f1, _mls_x57); -//│ _mls_retval = _mls_x59; -//│ } +//│ auto _mls_x63 = _mlsValue::cast<_mls_Cons1>(_mls_ls1)->_mls_head; +//│ auto _mls_x64 = _mlsValue::cast<_mls_Cons1>(_mls_ls1)->_mls_tail; +//│ auto _mls_x65 = _mlsValue::create<_mls_Lambda5>(_mls_eq, _mls_x63); +//│ auto _mls_x66 = _mls_filter(_mls_x65, _mls_x64); +//│ auto _mls_x67 = _mls_nubBy(_mls_eq, _mls_x66); +//│ auto _mls_x68 = _mlsValue::create<_mls_Cons1>(_mls_x63, _mls_x67); +//│ _mls_retval = _mls_x68; //│ } else { //│ throw std::runtime_error("match error"); //│ } //│ } //│ return _mls_retval; //│ } -//│ _mlsValue _mls_j6() { +//│ _mlsValue _mls_j4() { //│ _mlsValue _mls_retval; -//│ _mls_retval = _mlsValue::create<_mls_Unit>(); +//│ _mls_retval = _mls_j2(); //│ return _mls_retval; //│ } -//│ _mlsValue _mls_j7() { +//│ _mlsValue _mls_j2() { //│ _mlsValue _mls_retval; -//│ _mls_retval = _mls_j4(); +//│ _mls_retval = _mlsValue::create<_mls_Unit>(); //│ return _mls_retval; //│ } -//│ _mlsValue _mls_j2() { +//│ _mlsValue _mls_j5() { //│ _mlsValue _mls_retval; -//│ _mls_retval = _mlsValue::create<_mls_Unit>(); +//│ _mls_retval = _mls_j3(); //│ return _mls_retval; //│ } -//│ _mlsValue _mls_not(_mlsValue _mls_c2) { +//│ _mlsValue _mls_j7() { //│ _mlsValue _mls_retval; -//│ if (_mlsValue::isIntLit(_mls_c2, 1)) { -//│ _mls_retval = _mlsValue::fromIntLit(0); -//│ } else { -//│ _mls_retval = _mlsValue::fromIntLit(1); -//│ } +//│ _mls_retval = _mlsValue::create<_mls_Unit>(); //│ return _mls_retval; //│ } -//│ _mlsValue _mls_nubBy(_mlsValue _mls_eq, _mlsValue _mls_ls) { +//│ _mlsValue _mls_filter(_mlsValue _mls_f1, _mlsValue _mls_ls) { //│ _mlsValue _mls_retval; //│ if (_mlsValue::isValueOf<_mls_Nil1>(_mls_ls)) { //│ auto _mls_x55 = _mlsValue::create<_mls_Nil1>(); @@ -563,11 +584,15 @@ nubBy((x, y) => x == y, 1 :: 2 :: 3 :: 3 :: Nil) //│ if (_mlsValue::isValueOf<_mls_Cons1>(_mls_ls)) { //│ auto _mls_x49 = _mlsValue::cast<_mls_Cons1>(_mls_ls)->_mls_head; //│ auto _mls_x50 = _mlsValue::cast<_mls_Cons1>(_mls_ls)->_mls_tail; -//│ auto _mls_x51 = _mlsValue::create<_mls_Lambda5>(_mls_eq, _mls_x49); -//│ auto _mls_x52 = _mls_filter(_mls_x51, _mls_x50); -//│ auto _mls_x53 = _mls_nubBy(_mls_eq, _mls_x52); -//│ auto _mls_x54 = _mlsValue::create<_mls_Cons1>(_mls_x49, _mls_x53); -//│ _mls_retval = _mls_x54; +//│ auto _mls_x51 = _mlsMethodCall<_mls_Callable>(_mls_f1)->_mls_apply1(_mls_x49); +//│ if (_mlsValue::isIntLit(_mls_x51, 1)) { +//│ auto _mls_x53 = _mls_filter(_mls_f1, _mls_x50); +//│ auto _mls_x54 = _mlsValue::create<_mls_Cons1>(_mls_x49, _mls_x53); +//│ _mls_retval = _mls_x54; +//│ } else { +//│ auto _mls_x52 = _mls_filter(_mls_f1, _mls_x50); +//│ _mls_retval = _mls_x52; +//│ } //│ } else { //│ throw std::runtime_error("match error"); //│ } @@ -587,18 +612,7 @@ nubBy((x, y) => x == y, 1 :: 2 :: 3 :: 3 :: Nil) //│ _mls_retval = _mls_x48; //│ return _mls_retval; //│ } -//│ _mlsValue _mlsMain() { -//│ _mlsValue _mls_retval; -//│ auto _mls_x63 = _mlsValue::create<_mls_Nil1>(); -//│ auto _mls_x64 = _mlsValue::create<_mls_Cons1>(_mlsValue::fromIntLit(3), _mls_x63); -//│ auto _mls_x65 = _mlsValue::create<_mls_Cons1>(_mlsValue::fromIntLit(3), _mls_x64); -//│ auto _mls_x66 = _mlsValue::create<_mls_Cons1>(_mlsValue::fromIntLit(2), _mls_x65); -//│ auto _mls_x67 = _mlsValue::create<_mls_Cons1>(_mlsValue::fromIntLit(1), _mls_x66); -//│ auto _mls_x68 = _mlsValue::create<_mls_Lambda6>(); -//│ auto _mls_x69 = _mls_nubBy(_mls_x68, _mls_x67); -//│ _mls_retval = _mls_x69; -//│ return _mls_retval; -//│ } +//│ _mlsValue _mlsMain() { return _mls_entry5(); } //│ int main() { return _mlsLargeStack(_mlsMainWrapper); } //│ //│ Interpreted: @@ -616,32 +630,34 @@ f(3) //│ = 6 //│ LLIR: //│ class Lambda_self_rec() extends Callable { -//│ def apply1$241(x$579) = -//│ let x$604 = ==(x$579,0) in -//│ case x$604 of +//│ def apply1$242(x$585) = +//│ let x$610 = ==(x$585,0) in +//│ case x$610 of //│ BoolLit(true) => //│ 0 //│ _ => -//│ let x$606 = -(x$579,1) in -//│ let x$607 = Callable.apply1$241($603,x$606) in -//│ let x$608 = +(x$579,x$607) in -//│ x$608 +//│ let x$612 = -(x$585,1) in +//│ let x$613 = Callable.apply1$242($609,x$612) in +//│ let x$614 = +(x$585,x$613) in +//│ x$614 //│ } -//│ def f$577(x$578) = -//│ let x$609 = Lambda_self_rec$601() in -//│ let x$610 = Callable.apply1$241(x$609,x$578) in -//│ x$610 -//│ def j$605() = +//│ def f$583(x$584) = +//│ let x$615 = Lambda_self_rec$607() in +//│ let x$616 = Callable.apply1$242(x$615,x$584) in +//│ x$616 +//│ def j$611() = //│ null -//│ let* (x$611) = f(3) in -//│ x$611 +//│ def entry$618() = +//│ let* (x$617) = f(3) in +//│ x$617 +//│ entry = entry$618 //│ //│ Cpp: //│ #include "mlsprelude.h" //│ struct _mls_Lambda_self_rec; //│ _mlsValue _mls_j8(); //│ _mlsValue _mls_f2(_mlsValue); -//│ _mlsValue _mlsMain(); +//│ _mlsValue _mls_entry6(); //│ struct _mls_Lambda_self_rec: public _mls_Callable { //│ //│ constexpr static inline const char *typeName = "Lambda_self_rec"; @@ -663,6 +679,12 @@ f(3) //│ _mls_retval = _mls_x77; //│ return _mls_retval; //│ } +//│ _mlsValue _mls_entry6() { +//│ _mlsValue _mls_retval; +//│ auto _mls_x78 = _mls_f2(_mlsValue::fromIntLit(3)); +//│ _mls_retval = _mls_x78; +//│ return _mls_retval; +//│ } //│ _mlsValue _mls_Lambda_self_rec::_mls_apply1(_mlsValue _mls_x71) { //│ _mlsValue _mls_retval; //│ auto _mls_x70 = (_mls_x71 == _mlsValue::fromIntLit(0)); @@ -676,12 +698,7 @@ f(3) //│ } //│ return _mls_retval; //│ } -//│ _mlsValue _mlsMain() { -//│ _mlsValue _mls_retval; -//│ auto _mls_x78 = _mls_f2(_mlsValue::fromIntLit(3)); -//│ _mls_retval = _mls_x78; -//│ return _mls_retval; -//│ } +//│ _mlsValue _mlsMain() { return _mls_entry6(); } //│ int main() { return _mlsLargeStack(_mlsMainWrapper); } //│ //│ Interpreted: @@ -702,64 +719,66 @@ fun f(x) = f(3) //│ = false //│ LLIR: -//│ class Lambda_odd(lam_arg0$653) extends Callable { -//│ def apply1$241(x$617) = -//│ let x$654 = ==(x$617,0) in -//│ case x$654 of +//│ class Lambda_odd(lam_arg0$660) extends Callable { +//│ def apply1$242(x$624) = +//│ let x$661 = ==(x$624,0) in +//│ case x$661 of //│ BoolLit(true) => //│ true //│ _ => -//│ let x$656 = ==(x$617,1) in -//│ case x$656 of +//│ let x$663 = ==(x$624,1) in +//│ case x$663 of //│ BoolLit(true) => //│ false //│ _ => -//│ let x$658 = -(x$617,1) in -//│ let x$659 = Callable.apply1$241(lam_arg0$653,x$658) in -//│ x$659 +//│ let x$665 = -(x$624,1) in +//│ let x$666 = Callable.apply1$242(lam_arg0$660,x$665) in +//│ x$666 //│ } //│ class Lambda_even() extends Callable { -//│ def apply1$241(x$616) = -//│ let x$660 = Lambda_odd$651($603) in -//│ let x$661 = ==(x$616,0) in -//│ case x$661 of +//│ def apply1$242(x$623) = +//│ let x$667 = Lambda_odd$658($609) in +//│ let x$668 = ==(x$623,0) in +//│ case x$668 of //│ BoolLit(true) => //│ true //│ _ => -//│ let x$663 = ==(x$616,1) in -//│ case x$663 of +//│ let x$670 = ==(x$623,1) in +//│ case x$670 of //│ BoolLit(true) => //│ false //│ _ => -//│ let x$665 = -(x$616,1) in -//│ let x$666 = Callable.apply1$241(x$660,x$665) in -//│ x$666 +//│ let x$672 = -(x$623,1) in +//│ let x$673 = Callable.apply1$242(x$667,x$672) in +//│ x$673 //│ } -//│ def f$614(x$615) = -//│ let x$667 = Lambda_even$649() in -//│ let x$668 = Callable.apply1$241(x$667,x$615) in -//│ x$668 -//│ def j$657() = -//│ jump j$655() -//│ def j$655() = -//│ null +//│ def f$621(x$622) = +//│ let x$674 = Lambda_even$656() in +//│ let x$675 = Callable.apply1$242(x$674,x$622) in +//│ x$675 //│ def j$664() = //│ jump j$662() //│ def j$662() = //│ null -//│ let* (x$669) = f(3) in -//│ x$669 +//│ def j$671() = +//│ jump j$669() +//│ def j$669() = +//│ null +//│ def entry$677() = +//│ let* (x$676) = f(3) in +//│ x$676 +//│ entry = entry$677 //│ //│ Cpp: //│ #include "mlsprelude.h" //│ struct _mls_Lambda_odd; //│ struct _mls_Lambda_even; //│ _mlsValue _mls_j11(); +//│ _mlsValue _mls_entry7(); //│ _mlsValue _mls_f3(_mlsValue); //│ _mlsValue _mls_j10(); //│ _mlsValue _mls_j9(); //│ _mlsValue _mls_j12(); -//│ _mlsValue _mlsMain(); //│ struct _mls_Lambda_odd: public _mls_Callable { //│ _mlsValue _mls_lam_arg0; //│ constexpr static inline const char *typeName = "Lambda_odd"; @@ -778,14 +797,20 @@ f(3) //│ static _mlsValue create() { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) _mls_Lambda_even; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; return _mlsValue(_mlsVal); } //│ virtual _mlsValue _mls_apply1(_mlsValue); //│ }; -//│ _mlsValue _mls_j10() { +//│ _mlsValue _mls_entry7() { //│ _mlsValue _mls_retval; -//│ _mls_retval = _mlsValue::create<_mls_Unit>(); +//│ auto _mls_x90 = _mls_f3(_mlsValue::fromIntLit(3)); +//│ _mls_retval = _mls_x90; //│ return _mls_retval; //│ } //│ _mlsValue _mls_j12() { //│ _mlsValue _mls_retval; -//│ _mls_retval = _mls_j9(); +//│ _mls_retval = _mls_j11(); +//│ return _mls_retval; +//│ } +//│ _mlsValue _mls_j11() { +//│ _mlsValue _mls_retval; +//│ _mls_retval = _mlsValue::create<_mls_Unit>(); //│ return _mls_retval; //│ } //│ _mlsValue _mls_j9() { @@ -793,16 +818,16 @@ f(3) //│ _mls_retval = _mlsValue::create<_mls_Unit>(); //│ return _mls_retval; //│ } -//│ _mlsValue _mls_f3(_mlsValue _mls_x91) { +//│ _mlsValue _mls_f3(_mlsValue _mls_x92) { //│ _mlsValue _mls_retval; -//│ auto _mls_x90 = _mlsValue::create<_mls_Lambda_even>(); -//│ auto _mls_x92 = _mlsMethodCall<_mls_Callable>(_mls_x90)->_mls_apply1(_mls_x91); -//│ _mls_retval = _mls_x92; +//│ auto _mls_x91 = _mlsValue::create<_mls_Lambda_even>(); +//│ auto _mls_x93 = _mlsMethodCall<_mls_Callable>(_mls_x91)->_mls_apply1(_mls_x92); +//│ _mls_retval = _mls_x93; //│ return _mls_retval; //│ } -//│ _mlsValue _mls_j11() { +//│ _mlsValue _mls_j10() { //│ _mlsValue _mls_retval; -//│ _mls_retval = _mls_j10(); +//│ _mls_retval = _mls_j9(); //│ return _mls_retval; //│ } //│ _mlsValue _mls_Lambda_odd::_mls_apply1(_mlsValue _mls_x80) { @@ -824,7 +849,7 @@ f(3) //│ } //│ _mlsValue _mls_Lambda_even::_mls_apply1(_mlsValue _mls_x86) { //│ _mlsValue _mls_retval; -//│ auto _mls_x84 = _mlsValue::create<_mls_Lambda_odd>(_mlsValue(this)); +//│ auto _mls_x84 = _mlsValue::create<_mls_Lambda_odd>(_mlsValue(this, _mlsValue::inc_ref_tag{})); //│ auto _mls_x85 = (_mls_x86 == _mlsValue::fromIntLit(0)); //│ if (_mlsValue::isIntLit(_mls_x85, 1)) { //│ _mls_retval = _mlsValue::fromIntLit(1); @@ -840,10 +865,5 @@ f(3) //│ } //│ return _mls_retval; //│ } -//│ _mlsValue _mlsMain() { -//│ _mlsValue _mls_retval; -//│ auto _mls_x93 = _mls_f3(_mlsValue::fromIntLit(3)); -//│ _mls_retval = _mls_x93; -//│ return _mls_retval; -//│ } +//│ _mlsValue _mlsMain() { return _mls_entry7(); } //│ int main() { return _mlsLargeStack(_mlsMainWrapper); } diff --git a/hkmc2/shared/src/test/mlscript/llir/Lazy.mls b/hkmc2/shared/src/test/mlscript/llir/Lazy.mls index 40894667ee..483dda0ee6 100644 --- a/hkmc2/shared/src/test/mlscript/llir/Lazy.mls +++ b/hkmc2/shared/src/test/mlscript/llir/Lazy.mls @@ -22,28 +22,30 @@ fun main() = main() //│ LLIR: //│ class Lambda() extends Callable { -//│ def apply0$281() = -//│ let* (x$282) = side_effect() in -//│ x$282 +//│ def apply0$283() = +//│ let* (x$284) = side_effect() in +//│ x$284 //│ } -//│ def side_effect$254() = -//│ let* (x$276) = ("println","executed") in +//│ def side_effect$256() = +//│ let* (x$278) = ("println","executed") in //│ 1 -//│ def main$253() = -//│ let x$284 = Lambda$279() in -//│ let* (x$278) = lazy(x$284) in -//│ let* (x$285) = force(x$278) in -//│ let* (x$286) = force(x$278) in +//│ def main$255() = +//│ let x$286 = Lambda$281() in +//│ let* (x$280) = lazy(x$286) in +//│ let* (x$287) = force(x$280) in +//│ let* (x$288) = force(x$280) in //│ undefined -//│ let* (x$287) = main() in -//│ x$287 +//│ def entry$290() = +//│ let* (x$289) = main() in +//│ x$289 +//│ entry = entry$290 //│ //│ Cpp: //│ #include "mlsprelude.h" //│ struct _mls_Lambda; //│ _mlsValue _mls_side_effect(); //│ _mlsValue _mls_main(); -//│ _mlsValue _mlsMain(); +//│ _mlsValue _mls_entry(); //│ struct _mls_Lambda: public _mls_Callable { //│ //│ constexpr static inline const char *typeName = "Lambda"; @@ -68,16 +70,17 @@ main() //│ _mls_retval = _mlsValue::create<_mls_Unit>(); //│ return _mls_retval; //│ } -//│ _mlsValue _mls_Lambda::_mls_apply0() { +//│ _mlsValue _mls_entry() { //│ _mlsValue _mls_retval; -//│ auto _mls_x = _mls_side_effect(); -//│ _mls_retval = _mls_x; +//│ auto _mls_x6 = _mls_main(); +//│ _mls_retval = _mls_x6; //│ return _mls_retval; //│ } -//│ _mlsValue _mlsMain() { +//│ _mlsValue _mls_Lambda::_mls_apply0() { //│ _mlsValue _mls_retval; -//│ auto _mls_x6 = _mls_main(); -//│ _mls_retval = _mls_x6; +//│ auto _mls_x = _mls_side_effect(); +//│ _mls_retval = _mls_x; //│ return _mls_retval; //│ } +//│ _mlsValue _mlsMain() { return _mls_entry(); } //│ int main() { return _mlsLargeStack(_mlsMainWrapper); } diff --git a/hkmc2/shared/src/test/mlscript/llir/LazyCycle.mls b/hkmc2/shared/src/test/mlscript/llir/LazyCycle.mls index 16bed6171d..74715c337d 100644 --- a/hkmc2/shared/src/test/mlscript/llir/LazyCycle.mls +++ b/hkmc2/shared/src/test/mlscript/llir/LazyCycle.mls @@ -16,25 +16,27 @@ fun llist(x) = f(x) llist(1) //│ LLIR: -//│ class Lambda(lam_arg0$279,lam_arg1$280) extends Callable { -//│ def apply0$281() = -//│ let x$282 = +(lam_arg0$279,1) in -//│ let x$283 = Callable.apply1$275(lam_arg1$280,x$282) in -//│ let x$285 = LzCons$241(lam_arg0$279,x$283) in -//│ x$285 +//│ class Lambda(lam_arg0$281,lam_arg1$282) extends Callable { +//│ def apply0$283() = +//│ let x$284 = +(lam_arg0$281,1) in +//│ let x$285 = Callable.apply1$277(lam_arg1$282,x$284) in +//│ let x$287 = LzCons$242(lam_arg0$281,x$285) in +//│ x$287 //│ } //│ class Lambda_f() extends Callable { -//│ def apply1$275(x$256) = -//│ let x$286 = Lambda$277(x$256,$274) in -//│ let* (x$276) = lazy(x$286) in -//│ x$276 +//│ def apply1$277(x$258) = +//│ let x$288 = Lambda$279(x$258,$276) in +//│ let* (x$278) = lazy(x$288) in +//│ x$278 //│ } -//│ def llist$254(x$255) = -//│ let x$287 = Lambda_f$272() in -//│ let x$288 = Callable.apply1$275(x$287,x$255) in -//│ x$288 -//│ let* (x$289) = llist(1) in -//│ x$289 +//│ def llist$256(x$257) = +//│ let x$289 = Lambda_f$274() in +//│ let x$290 = Callable.apply1$277(x$289,x$257) in +//│ x$290 +//│ def entry$292() = +//│ let* (x$291) = llist(1) in +//│ x$291 +//│ entry = entry$292 //│ //│ WholeProgramCpp: //│ #include "mlsprelude.h" @@ -44,11 +46,13 @@ llist(1) //│ struct _mls_Lambda_f; //│ struct _mls_LzNil; //│ struct _mls_LzCons; +//│ _mlsValue _mls_entry2(); +//│ _mlsValue _mls_entry(); +//│ _mlsValue _mls_llist(_mlsValue); +//│ _mlsValue _mls_force(_mlsValue); //│ _mlsValue _mls_lazy(_mlsValue); //│ _mlsValue _mls_j(); -//│ _mlsValue _mls_force(_mlsValue); -//│ _mlsValue _mls_llist(_mlsValue); -//│ _mlsValue _mlsMain(); +//│ _mlsValue _mls_entry1(); //│ struct _mls_LzList: public _mlsObject { //│ //│ constexpr static inline const char *typeName = "LzList"; @@ -96,34 +100,50 @@ llist(1) //│ static _mlsValue create(_mlsValue _mls_head, _mlsValue _mls_tail) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) _mls_LzCons; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->_mls_head = _mls_head; _mlsVal->_mls_tail = _mls_tail; return _mlsValue(_mlsVal); } //│ //│ }; +//│ _mlsValue _mls_j() { +//│ _mlsValue _mls_retval; +//│ _mls_retval = _mlsValue::create<_mls_Unit>(); +//│ return _mls_retval; +//│ } +//│ _mlsValue _mls_entry() { +//│ _mlsValue _mls_retval; +//│ _mls_retval = _mlsValue::create<_mls_Unit>(); +//│ return _mls_retval; +//│ } //│ _mlsValue _mls_lazy(_mlsValue _mls_x7) { //│ _mlsValue _mls_retval; //│ auto _mls_x6 = _mlsValue::create<_mls_Lazy>(_mls_x7); //│ _mls_retval = _mls_x6; //│ return _mls_retval; //│ } -//│ _mlsValue _mls_j() { +//│ _mlsValue _mls_llist(_mlsValue _mls_x12) { +//│ _mlsValue _mls_retval; +//│ auto _mls_x11 = _mlsValue::create<_mls_Lambda_f>(); +//│ auto _mls_x13 = _mlsMethodCall<_mls_Callable>(_mls_x11)->_mls_apply1(_mls_x12); +//│ _mls_retval = _mls_x13; +//│ return _mls_retval; +//│ } +//│ _mlsValue _mls_entry1() { +//│ _mlsValue _mls_retval; +//│ auto _mls_x8 = _mls_llist(_mlsValue::fromIntLit(1)); +//│ _mls_retval = _mls_x8; +//│ return _mls_retval; +//│ } +//│ _mlsValue _mls_entry2() { //│ _mlsValue _mls_retval; //│ _mls_retval = _mlsValue::create<_mls_Unit>(); //│ return _mls_retval; //│ } -//│ _mlsValue _mls_force(_mlsValue _mls_x8) { +//│ _mlsValue _mls_force(_mlsValue _mls_x9) { //│ _mlsValue _mls_retval; -//│ if (_mlsValue::isValueOf<_mls_Lazy>(_mls_x8)) { -//│ auto _mls_x9 = _mlsMethodCall<_mls_Lazy>(_mls_x8)->_mls_get(); -//│ _mls_retval = _mls_x9; +//│ if (_mlsValue::isValueOf<_mls_Lazy>(_mls_x9)) { +//│ auto _mls_x10 = _mlsMethodCall<_mls_Lazy>(_mls_x9)->_mls_get(); +//│ _mls_retval = _mls_x10; //│ } else { //│ throw std::runtime_error("match error"); //│ } //│ return _mls_retval; //│ } -//│ _mlsValue _mls_llist(_mlsValue _mls_x11) { -//│ _mlsValue _mls_retval; -//│ auto _mls_x10 = _mlsValue::create<_mls_Lambda_f>(); -//│ auto _mls_x12 = _mlsMethodCall<_mls_Callable>(_mls_x10)->_mls_apply1(_mls_x11); -//│ _mls_retval = _mls_x12; -//│ return _mls_retval; -//│ } //│ _mlsValue _mls_Lambda::_mls_apply0() { //│ _mlsValue _mls_retval; //│ auto _mls_x = (_mls_lam_arg0 + _mlsValue::fromIntLit(1)); @@ -139,10 +159,5 @@ llist(1) //│ _mls_retval = _mls_x5; //│ return _mls_retval; //│ } -//│ _mlsValue _mlsMain() { -//│ _mlsValue _mls_retval; -//│ auto _mls_x13 = _mls_llist(_mlsValue::fromIntLit(1)); -//│ _mls_retval = _mls_x13; -//│ return _mls_retval; -//│ } +//│ _mlsValue _mlsMain() { return _mls_entry1(); } //│ int main() { return _mlsLargeStack(_mlsMainWrapper); } diff --git a/hkmc2/shared/src/test/mlscript/llir/Legacy.mls b/hkmc2/shared/src/test/mlscript/llir/Legacy.mls index e0046814fc..5ec40b43be 100644 --- a/hkmc2/shared/src/test/mlscript/llir/Legacy.mls +++ b/hkmc2/shared/src/test/mlscript/llir/Legacy.mls @@ -255,74 +255,76 @@ main() //│ = 404 //│ LLIR: //│ class Option() -//│ class Some(x$1035) extends Option +//│ class Some(x$1049) extends Option //│ class None() extends Option //│ class Nat() -//│ class S(s$1046) extends Nat +//│ class S(s$1060) extends Nat //│ class O() extends Nat -//│ def fromSome$1018(s$1038) = -//│ case s$1038 of -//│ Some$1032 => -//│ let x$1113 = s$1038. in -//│ x$1113 +//│ def fromSome$1032(s$1052) = +//│ case s$1052 of +//│ Some$1046 => +//│ let x$1127 = s$1052. in +//│ x$1127 //│ _ => //│ panic "match error" -//│ def j$1112() = +//│ def j$1126() = //│ null -//│ def aaa$1023() = -//│ let x$1114 = 1 in -//│ let x$1115 = 2 in -//│ let x$1116 = 3 in -//│ let x$1117 = 4 in -//│ let x$1118 = +(x$1114,x$1115) in -//│ let x$1119 = -(x$1118,x$1116) in -//│ let x$1120 = +(x$1119,x$1117) in -//│ x$1120 -//│ def bbb$1025() = -//│ let* (x$1121) = aaa() in -//│ let x$1122 = *(x$1121,100) in -//│ let x$1123 = +(x$1122,4) in -//│ x$1123 -//│ def not$1021(x$1062) = -//│ case x$1062 of +//│ def aaa$1037() = +//│ let x$1128 = 1 in +//│ let x$1129 = 2 in +//│ let x$1130 = 3 in +//│ let x$1131 = 4 in +//│ let x$1132 = +(x$1128,x$1129) in +//│ let x$1133 = -(x$1132,x$1130) in +//│ let x$1134 = +(x$1133,x$1131) in +//│ x$1134 +//│ def bbb$1039() = +//│ let* (x$1135) = aaa() in +//│ let x$1136 = *(x$1135,100) in +//│ let x$1137 = +(x$1136,4) in +//│ x$1137 +//│ def not$1035(x$1076) = +//│ case x$1076 of //│ BoolLit(true) => //│ false //│ _ => //│ true -//│ def j$1124() = +//│ def j$1138() = //│ null -//│ def foo$1028(x$1064) = -//│ case x$1064 of +//│ def foo$1042(x$1078) = +//│ case x$1078 of //│ BoolLit(true) => -//│ let x$1126 = None$1036() in -//│ x$1126 +//│ let x$1140 = None$1050() in +//│ x$1140 //│ _ => -//│ let* (x$1127) = not(x$1064) in -//│ let* (x$1128) = foo(x$1127) in -//│ let x$1129 = Some$1032(x$1128) in -//│ x$1129 -//│ def j$1125() = +//│ let* (x$1141) = not(x$1078) in +//│ let* (x$1142) = foo(x$1141) in +//│ let x$1143 = Some$1046(x$1142) in +//│ x$1143 +//│ def j$1139() = //│ null -//│ def main$1019() = -//│ let* (x$1130) = foo(false) in -//│ case x$1130 of -//│ None$1036 => -//│ let* (x$1132) = aaa() in -//│ x$1132 +//│ def main$1033() = +//│ let* (x$1144) = foo(false) in +//│ case x$1144 of +//│ None$1050 => +//│ let* (x$1146) = aaa() in +//│ x$1146 //│ _ => -//│ case x$1130 of -//│ Some$1032 => -//│ let x$1134 = x$1130. in -//│ let* (x$1135) = bbb() in -//│ x$1135 +//│ case x$1144 of +//│ Some$1046 => +//│ let x$1148 = x$1144. in +//│ let* (x$1149) = bbb() in +//│ x$1149 //│ _ => //│ panic "match error" -//│ def j$1133() = -//│ jump j$1131() -//│ def j$1131() = +//│ def j$1147() = +//│ jump j$1145() +//│ def j$1145() = //│ null -//│ let* (x$1136) = main() in -//│ x$1136 +//│ def entry$1151() = +//│ let* (x$1150) = main() in +//│ x$1150 +//│ entry = entry$1151 //│ //│ Interpreted: //│ 404 diff --git a/hkmc2/shared/src/test/mlscript/llir/Method.mls b/hkmc2/shared/src/test/mlscript/llir/Method.mls index e73b4ef9e6..4ce8590f90 100644 --- a/hkmc2/shared/src/test/mlscript/llir/Method.mls +++ b/hkmc2/shared/src/test/mlscript/llir/Method.mls @@ -20,6 +20,8 @@ main() //│ let x$233 = A$219(1) in //│ let x$234 = A.f$216(x$233) in //│ x$234 -//│ let* (x$235) = main() in -//│ x$235 +//│ def entry$236() = +//│ let* (x$235) = main() in +//│ x$235 +//│ entry = entry$236 diff --git a/hkmc2/shared/src/test/mlscript/llir/Tuple.mls b/hkmc2/shared/src/test/mlscript/llir/Tuple.mls index 2a152afb66..9ba7103ba4 100644 --- a/hkmc2/shared/src/test/mlscript/llir/Tuple.mls +++ b/hkmc2/shared/src/test/mlscript/llir/Tuple.mls @@ -13,21 +13,23 @@ mkTup(1, 2) //│ = [1, 2] //│ LLIR: //│ -//│ def mkTup$218(x$220,y$221) = -//│ let x$234 = Tuple2$235(x$220,y$221) in -//│ x$234 -//│ def fst$219(t$223) = -//│ case t$223 of -//│ Tuple2$235 => -//│ let x$238 = t$223. in -//│ let x$239 = t$223. in -//│ x$238 +//│ def mkTup$219(x$221,y$222) = +//│ let x$235 = Tuple2$236(x$221,y$222) in +//│ x$235 +//│ def fst$220(t$224) = +//│ case t$224 of +//│ Tuple2$236 => +//│ let x$239 = t$224. in +//│ let x$240 = t$224. in +//│ x$239 //│ _ => //│ panic "match error" -//│ def j$237() = +//│ def j$238() = //│ null -//│ let* (x$240) = mkTup(1,2) in -//│ x$240 +//│ def entry$242() = +//│ let* (x$241) = mkTup(1,2) in +//│ x$241 +//│ entry = entry$242 //│ //│ Cpp: //│ #include "mlsprelude.h" @@ -35,7 +37,7 @@ mkTup(1, 2) //│ _mlsValue _mls_mkTup(_mlsValue, _mlsValue); //│ _mlsValue _mls_j(); //│ _mlsValue _mls_fst(_mlsValue); -//│ _mlsValue _mlsMain(); +//│ _mlsValue _mls_entry1(); //│ struct _mls_Tuple2: public _mlsObject { //│ _mlsValue _mls_field0; //│ _mlsValue _mls_field1; @@ -68,12 +70,13 @@ mkTup(1, 2) //│ } //│ return _mls_retval; //│ } -//│ _mlsValue _mlsMain() { +//│ _mlsValue _mls_entry1() { //│ _mlsValue _mls_retval; //│ auto _mls_x4 = _mls_mkTup(_mlsValue::fromIntLit(1), _mlsValue::fromIntLit(2)); //│ _mls_retval = _mls_x4; //│ return _mls_retval; //│ } +//│ _mlsValue _mlsMain() { return _mls_entry1(); } //│ int main() { return _mlsLargeStack(_mlsMainWrapper); } //│ //│ Interpreted: diff --git a/hkmc2/shared/src/test/mlscript/llir/nofib/atom.mls b/hkmc2/shared/src/test/mlscript/llir/nofib/atom.mls index c7eb73ace6..3d63c632af 100644 --- a/hkmc2/shared/src/test/mlscript/llir/nofib/atom.mls +++ b/hkmc2/shared/src/test/mlscript/llir/nofib/atom.mls @@ -1,7 +1,7 @@ :llir :import NofibPrelude.mls -//│ Imported 100 member(s) +//│ Imported 104 member(s) class State(position: List[Num], velocity: List[Num]) diff --git a/hkmc2/shared/src/test/mlscript/llir/nofib/awards.mls b/hkmc2/shared/src/test/mlscript/llir/nofib/awards.mls index 0de078f809..9bcfe86bf9 100644 --- a/hkmc2/shared/src/test/mlscript/llir/nofib/awards.mls +++ b/hkmc2/shared/src/test/mlscript/llir/nofib/awards.mls @@ -1,7 +1,7 @@ :llir :import NofibPrelude.mls -//│ Imported 101 member(s) +//│ Imported 104 member(s) fun delete_(xs, e) = deleteBy((x, y) => x == y, e, xs) diff --git a/hkmc2/shared/src/test/mlscript/llir/nofib/scc.mls b/hkmc2/shared/src/test/mlscript/llir/nofib/scc.mls index 30c8d04c61..1aa585e648 100644 --- a/hkmc2/shared/src/test/mlscript/llir/nofib/scc.mls +++ b/hkmc2/shared/src/test/mlscript/llir/nofib/scc.mls @@ -1,7 +1,7 @@ :llir :import NofibPrelude.mls -//│ Imported 103 member(s) +//│ Imported 104 member(s) fun dfs(r, vsns, xs) = if vsns is [vs, ns] and diff --git a/hkmc2/shared/src/test/mlscript/llir/nofib/secretary.mls b/hkmc2/shared/src/test/mlscript/llir/nofib/secretary.mls index 33aed8e42b..c7a2b328f7 100644 --- a/hkmc2/shared/src/test/mlscript/llir/nofib/secretary.mls +++ b/hkmc2/shared/src/test/mlscript/llir/nofib/secretary.mls @@ -37,7 +37,6 @@ fun testSecretary_nofib(n) = listcomp(enumFromTo(35, 39)) -:writeWholeCpp secretary.cxx :runWholeCpp print(testSecretary_nofib(50)) //│ diff --git a/hkmc2DiffTests/src/test/scala/hkmc2/LlirDiffMaker.scala b/hkmc2DiffTests/src/test/scala/hkmc2/LlirDiffMaker.scala index b062176a86..76ec60d6d5 100644 --- a/hkmc2DiffTests/src/test/scala/hkmc2/LlirDiffMaker.scala +++ b/hkmc2DiffTests/src/test/scala/hkmc2/LlirDiffMaker.scala @@ -50,12 +50,12 @@ abstract class LlirDiffMaker extends BbmlDiffMaker: def mkWholeProgram: Program = if wholeProg.length == 0 then - Program(Set.empty, Set.empty, Node.Panic("No program to compile")) + throw new Exception("No program to make") else Program( classes = wholeProg.iterator.flatMap(_.classes).toSet, defs = wholeProg.iterator.flatMap(_.defs).toSet, - main = wholeProg.last.main + entry = wholeProg.last.entry ) override def processTerm(trm: Blk, inImport: Bool)(using Raise): Unit = @@ -106,4 +106,6 @@ abstract class LlirDiffMaker extends BbmlDiffMaker: catch case e: LowLevelIRError => output("Stopped due to an error during the Llir generation") + case e: OptErr => + output("Stopped due to an error during the optimization") From 52a3ead6901422b0d396307edf6de840b59ab45a Mon Sep 17 00:00:00 2001 From: waterlens Date: Mon, 3 Mar 2025 21:05:22 +0800 Subject: [PATCH 53/88] Save --- .../main/scala/hkmc2/codegen/llir/Opt.scala | 275 ++++++++++++++++++ 1 file changed, 275 insertions(+) create mode 100644 hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Opt.scala diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Opt.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Opt.scala new file mode 100644 index 0000000000..743a2089d5 --- /dev/null +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Opt.scala @@ -0,0 +1,275 @@ +package hkmc2 +package codegen +package llir + +import mlscript.utils.* +import mlscript.utils.shorthands.* +import hkmc2.utils.* +import hkmc2.document.* +import hkmc2.Message.MessageContext + +import hkmc2.syntax.Tree +import hkmc2.semantics.* +import hkmc2.codegen.llir.{ Program => LlirProgram, Node, Func } +import hkmc2.codegen.Program +import hkmc2.codegen.cpp.Expr.StrLit + +import language.implicitConversions +import annotation.tailrec +import collection.immutable._ +import collection.mutable.{HashMap => MutHMap} +import collection.mutable.{HashSet => MutHSet, Set => MutSet} +import collection.mutable.{MultiMap, Queue} +import javax.imageio.event.IIOWriteProgressListener +import hkmc2.syntax.Keyword.`do` + +final case class OptErr(message: String) extends Exception(message) + +private def oErrStop(msg: Message)(using Raise) = + raise(ErrorReport(msg -> N :: Nil, + source = Diagnostic.Source.Compilation)) + throw OptErr("stopped") + +final class LlirOpt(using Elaborator.State, Raise)(tl: TraceLogger): + import tl.{log, trace} + + object DestructUtils: + @tailrec + def getFirstDestructed(node: Node): Opt[Local] = node match + case Node.Result(res) => N + case Node.Jump(func, args) => N + case Node.Case(Expr.Ref(scrut), cases, default) => S(scrut) + case Node.Case(_, _, _) => N + case Node.Panic(msg) => N + case Node.LetExpr(name, expr, body) => getFirstDestructed(body) + case Node.LetMethodCall(names, cls, method, args, body) => N + case Node.LetCall(names, func, args, body) => N + + def isDestructed(node: Node) = getFirstDestructed(node).isDefined + + case class Loc(node: Node) + given Conversion[Node, Loc] = Loc(_) + + enum IInfo: + case Ctor(c: Local) + case Mixed(i: Set[I]) + case Tuple(n: Int) + + enum EInfo: + case Pass + case Des + case IndDes + case Sel(cls: Local, fld: Str) + + case class E(loc: Loc, info: EInfo) + case class I(loc: Loc, info: IInfo) + + implicit object EOrdering extends Ordering[E]: + override def compare(a: E, b: E) = a.info.toString.compare(b.info.toString) + implicit object IOrdering extends Ordering[I]: + override def compare(a: I, b: I) = a.info.toString.compare(b.info.toString) + + case class FnInfo( + activeParams: MutHMap[Local, Ls[SortedSet[E]]] = MutHMap.empty, + activeResults: MutHMap[Local, Ls[Opt[I]]] = MutHMap.empty, + func: MutHMap[Local, Func] = MutHMap.empty, + ): + def getActiveParams(func: Local) = + activeParams.getOrElse(func, oErrStop(s"Function $func with empty activeParams")) + + def getActiveResults(func: Local) = + activeResults.getOrElse(func, oErrStop(s"Function $func with empty activeResults")) + + def getFunc(sym: Local): Func = + func.getOrElse(sym, oErrStop(s"Function $func not found")) + + def setActiveParams(func: Local, aps: Ls[SortedSet[E]]) = + activeParams.update(func, aps) + + def setActiveResults(func: Local, ars: Ls[Opt[I]]) = + activeResults.update(func, ars) + + private object EliminationAnalysis: + case class Env( + val def_count: MutHMap[Local, Int] = MutHMap.empty, + val elims: MutHMap[Local, MutHSet[E]] = MutHMap.empty, + val defn: Local, + val visited: MutHSet[Local] = MutHSet.empty, + ) + private class EliminationAnalysis(info: FnInfo): + import EliminationAnalysis.Env + def addE(sym: Local, e: E)(using env: Env) = + assert(env.def_count.getOrElse(sym, 0) <= 1, s"Multiple definitions of $sym") + env.elims.getOrElseUpdate(sym, MutHSet.empty) += e + + def addBackwardE(sym: Local, e: E, newLoc: Loc)(using env: Env) = + assert(env.def_count.getOrElse(sym, 0) <= 1, s"Multiple definitions of $sym") + import EInfo.* + for + e2 <- e match + case E(_, Des) | E(_, IndDes) => Some(E(newLoc, IndDes)) + case E(_, Pass) => Some(E(newLoc, Pass)) + case _ => None + _ = env.elims.getOrElseUpdate(sym, MutHSet.empty).add(e2) + yield () + + def addDef(sym: Local)(using env: Env) = + env.def_count.update(sym, env.def_count.getOrElse(sym, 0) + 1) + + def fTExprWithLoc(x: TrivialExpr, loc: Loc)(using env: Env): Unit = x match + case Expr.Ref(name) => addE(name, E(loc, EInfo.Pass)) + case _ => () + + def fExprWithLoc(x: Expr, loc: Loc)(using env: Env): Unit = x match + case Expr.Ref(name) => addE(name, E(loc, EInfo.Pass)) + case Expr.Literal(lit) => + case Expr.CtorApp(name, args) => args.foreach(fTExprWithLoc(_, loc)) + case Expr.Select(name, cls, field) => addE(name, E(loc, EInfo.Sel(cls, field))) + case Expr.BasicOp(name, args) => args.foreach(fTExprWithLoc(_, loc)) + case Expr.AssignField(assignee, _, _, value) => TODO("fExprWithLoc: AssignField") + + def getFunc(func: Local)(using env: Env): Func = + info.func.getOrElse(func, oErrStop(s"Function $func not found")) + + + def fNode(node: Node)(using env: Env): Unit = + def fDef(func: Local, args: Ls[TrivialExpr], funcDefn: Func)(using env: Env) = + val aps = info.getActiveParams(func) + args.iterator.zip(aps).foreach: + case (Expr.Ref(x), ys) => ys.foreach(y => addBackwardE(x, y, node)) + case _ => oErrStop("fNode: Jump") + if !env.visited.contains(func) then + env.visited.add(func) + val funcDefn = getFunc(func) + funcDefn.params.foreach(addDef) + val newEnv = env.copy(defn = func) + fNode(funcDefn.body)(using newEnv) + node match + case Node.Result(res) => res.foreach(fTExprWithLoc(_, node)) + case Node.Jump(func, args) => + args.foreach(fTExprWithLoc(_, node)) + fDef(func, args, getFunc(func)) + case Node.Case(Expr.Ref(scrutinee), cases, default) => + addE(scrutinee, E(node, EInfo.Pass)) + addE(scrutinee, E(node, EInfo.Des)) + cases.foreach { case (cls, body) => fNode(body) } + default.foreach(fNode) + case Node.Case(_, cases, default) => + cases.foreach { case (cls, body) => fNode(body) } + default.foreach(fNode) + case Node.Panic(msg) => + case Node.LetExpr(name, expr, body) => + fExprWithLoc(expr, node) + addDef(name) + fNode(body) + case Node.LetMethodCall(names, cls, method, args, body) => + // TODO: LetMethodCall + fNode(body) + case Node.LetCall(names, func, args, body) => + names.foreach(addDef) + args.foreach(fTExprWithLoc(_, node)) + fDef(func, args, getFunc(func)) + fNode(body) + + def run(prog: LlirProgram) = + var changed = true + while changed do + changed = false + prog.defs.foreach: func => + val old = info.getActiveParams(func.name) + val env = Env(defn = func.name) + func.params.foreach(addDef(_)(using env)) + fNode(func.body)(using env) + val nu = func.params.iterator.map(p => env.elims.getOrElse(p, MutHSet.empty).toSortedSet).toList + changed |= old != nu + info.setActiveParams(func.name, nu) + + private object IntroductionAnalysis: + case class Env( + intros: MutHMap[Local, I] = MutHMap.empty, + default_intro: Ls[Opt[I]], // the intro of panic + ) + private class IntroductionAnalysis(info: FnInfo): + import IntroductionAnalysis.Env + def mergeIntros(xs: Ls[Ls[Opt[I]]], loc: Loc): Ls[Opt[I]] = + val xst = xs.transpose + xst.map: ys => + val z = ys.flatMap: + case N => Set.empty[I] + case S(I(loc, IInfo.Mixed(i))) => i + case S(i) => Set(i) + .toSet + if z.nonEmpty then S(I(loc, IInfo.Mixed(z))) else N + + def addI(sym: Local, i: I)(using env: Env) = + if env.intros.contains(sym) then + throw OptErr(s"Multiple introductions of $sym") + env.intros.addOne(sym -> i) + + def fTExprWithLoc(x: TrivialExpr, loc: Loc)(using env: Env): Opt[I] = x match + case Expr.Ref(name) => env.intros.get(name) + case _ => N + + def fExprWithLoc(e: Expr, loc: Loc)(using env: Env): Opt[I] = e match + case Expr.Ref(sym) => env.intros.get(sym) + case Expr.CtorApp(cls, args) => S(I(loc, IInfo.Ctor(cls))) + case _ => N + + def fNode(node: Node)(using env: Env): Ls[Opt[I]] = node match + case Node.Result(res) => res.map(f => fTExprWithLoc(f, node)) + case Node.Jump(func, args) => info.getActiveResults(func) + case Node.Case(scrutinee, cases, default) => + val casesIntros = cases.map: + case (Pat.Class(cls), body) => + addI(cls, I(node, IInfo.Ctor(cls))) + fNode(body) + case (Pat.Lit(lit), body) => fNode(body) + default match + case N => mergeIntros(casesIntros, node) + case S(x) => mergeIntros(casesIntros :+ fNode(x), node) + case Node.Panic(msg) => env.default_intro + case Node.LetExpr(name, expr, body) => + for + i <- fExprWithLoc(expr, node) + _ = addI(name, i) + yield () + fNode(body) + case Node.LetMethodCall(names, cls, method, args, body) => + fNode(body) + case Node.LetCall(names, func, args, body) => + val funcDefn = info.getFunc(func) + val ars = info.getActiveResults(func) + funcDefn.params.iterator.zip(ars).foreach: + case (p, S(i)) => addI(p, i) + case _ => () + fNode(body) + + def run(prog: LlirProgram) = + var changed = true + while changed do + changed = false + prog.defs.foreach: func => + val old = info.getActiveResults(func.name) + val nu = fNode(func.body)(using Env(default_intro = List.fill(func.params.length)(N))) + assert(old.length == nu.length, s"old: $old, nu: $nu") + changed |= old != nu + info.setActiveResults(func.name, nu) + + case class PreFunc(sym: Local, results: Ls[Local]) + case class PostFunc(sym: Local, params: Ls[Local]) + + // given the arguments of a function call, we find their intro-info and propagate them to the function's parameters + private def bindIInfo(args: Ls[TrivialExpr], params: Ls[Symbol])(using env: IntroductionAnalysis.Env) = + args.iterator.zip(params).foreach: + case (Expr.Ref(x), p) if env.intros.contains(x) => env.intros.addOne(p -> env.intros(x)) + case _ => () + + // given the intro-info of a function's parameters, update the intros env + private def updateIInfo(func: Func, intros: Ls[Opt[I]])(using env: IntroductionAnalysis.Env) = + func.params.iterator.zip(intros).foreach: + case (p, S(i)) => env.intros.addOne(p -> i) + case _ => () + + + private class Splitting(info: FnInfo): + def f() = ??? \ No newline at end of file From 7e93c302537356385325d5ab60fa9272daad6750 Mon Sep 17 00:00:00 2001 From: waterlens Date: Tue, 4 Mar 2025 20:41:13 +0800 Subject: [PATCH 54/88] Save --- .../main/scala/hkmc2/codegen/llir/Opt.scala | 149 +++++++++++++++--- 1 file changed, 125 insertions(+), 24 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Opt.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Opt.scala index 743a2089d5..670b866633 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Opt.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Opt.scala @@ -20,8 +20,7 @@ import collection.immutable._ import collection.mutable.{HashMap => MutHMap} import collection.mutable.{HashSet => MutHSet, Set => MutSet} import collection.mutable.{MultiMap, Queue} -import javax.imageio.event.IIOWriteProgressListener -import hkmc2.syntax.Keyword.`do` +import scala.collection.mutable.ListBuffer final case class OptErr(message: String) extends Exception(message) @@ -206,6 +205,12 @@ final class LlirOpt(using Elaborator.State, Raise)(tl: TraceLogger): throw OptErr(s"Multiple introductions of $sym") env.intros.addOne(sym -> i) + // given the arguments of a function call, we find their intro-info and propagate them to the function's parameters + def bindIInfo(args: Ls[TrivialExpr], params: Ls[Symbol])(using env: Env) = + args.iterator.zip(params).foreach: + case (Expr.Ref(x), p) if env.intros.contains(x) => env.intros.addOne(p -> env.intros(x)) + case _ => () + def fTExprWithLoc(x: TrivialExpr, loc: Loc)(using env: Env): Opt[I] = x match case Expr.Ref(name) => env.intros.get(name) case _ => N @@ -217,7 +222,10 @@ final class LlirOpt(using Elaborator.State, Raise)(tl: TraceLogger): def fNode(node: Node)(using env: Env): Ls[Opt[I]] = node match case Node.Result(res) => res.map(f => fTExprWithLoc(f, node)) - case Node.Jump(func, args) => info.getActiveResults(func) + case Node.Jump(func, args) => + info.getActiveResults(func).map: + case N => N + case S(I(loc, i)) => S(I(node, i)) case Node.Case(scrutinee, cases, default) => val casesIntros = cases.map: case (Pat.Class(cls), body) => @@ -229,18 +237,14 @@ final class LlirOpt(using Elaborator.State, Raise)(tl: TraceLogger): case S(x) => mergeIntros(casesIntros :+ fNode(x), node) case Node.Panic(msg) => env.default_intro case Node.LetExpr(name, expr, body) => - for - i <- fExprWithLoc(expr, node) - _ = addI(name, i) - yield () - fNode(body) - case Node.LetMethodCall(names, cls, method, args, body) => + for i <- fExprWithLoc(expr, node); _ = addI(name, i) yield () fNode(body) + case Node.LetMethodCall(names, cls, method, args, body) => fNode(body) case Node.LetCall(names, func, args, body) => val funcDefn = info.getFunc(func) val ars = info.getActiveResults(func) - funcDefn.params.iterator.zip(ars).foreach: - case (p, S(i)) => addI(p, i) + names.iterator.zip(ars).foreach: + case (rv, S(I(oldLoc, i))) => addI(rv, I(node, i)) case _ => () fNode(body) @@ -257,19 +261,116 @@ final class LlirOpt(using Elaborator.State, Raise)(tl: TraceLogger): case class PreFunc(sym: Local, results: Ls[Local]) case class PostFunc(sym: Local, params: Ls[Local]) + + private class Splitting(info: FnInfo): + case class Env( + i: IntroductionAnalysis.Env, + e: EliminationAnalysis.Env, + ) - // given the arguments of a function call, we find their intro-info and propagate them to the function's parameters - private def bindIInfo(args: Ls[TrivialExpr], params: Ls[Symbol])(using env: IntroductionAnalysis.Env) = - args.iterator.zip(params).foreach: - case (Expr.Ref(x), p) if env.intros.contains(x) => env.intros.addOne(p -> env.intros(x)) - case _ => () + case class SymDDesc( + knownClass: Local, + isIndirect: Bool, + e: E + ) - // given the intro-info of a function's parameters, update the intros env - private def updateIInfo(func: Func, intros: Ls[Opt[I]])(using env: IntroductionAnalysis.Env) = - func.params.iterator.zip(intros).foreach: - case (p, S(i)) => env.intros.addOne(p -> i) - case _ => () + case class SDesc( + func: Func, + argumentsDesc: MutHMap[Local, SymDDesc] = MutHMap.empty, + firstDestructedSym: Opt[Local] = N, + mixingProducer: MutHMap[Local, Func] = MutHMap.empty, + ) - - private class Splitting(info: FnInfo): - def f() = ??? \ No newline at end of file + def symAndIntroOfTExpr(te: TrivialExpr)(using env: Env): Opt[(Local, I)] = te match + case Expr.Ref(x) => for i <- env.i.intros.get(x) yield (x, i) + case _ => none + + def checkSTarget(func: Func, args: Ls[TrivialExpr])(using env: Env) = + val activeParams = info.getActiveParams(func.name) + val params = func.params + val argsIntros = args.iterator.map(symAndIntroOfTExpr) + val firstD = DestructUtils.getFirstDestructed(func.body) + var argumentsDesc = MutHMap.empty[Local, SymDDesc] + val mixingProducer = MutHMap.empty[Local, Func] + argsIntros.zip(params.iterator.zip(activeParams.iterator)).foreach: + case ((S((arg, I(loc, IInfo.Ctor(cls))))), (param, elims)) => + for e <- elims do e match + case E(loc, EInfo.Des) => argumentsDesc.update(param, SymDDesc(cls, false, e)) + case E(loc, EInfo.IndDes) => argumentsDesc.update(param, SymDDesc(cls, true, e)) + case _ => + case (S((arg, I(loc, IInfo.Mixed(is)))), (p, elims)) => + for e <- elims do e match + case E(_, EInfo.Des | EInfo.IndDes) => + loc match + case Loc(Node.LetCall(_, producer, _, _)) => + // what to do with a mixing producer? + // it's different with other kinds of splitting + // + // for example, in f0, we have following program: + // ... #1 + // let x1 = f1() in + // ... #2 + // let x2 = f2(x1) in + // ... #3 + // where x1 is `IInfo.Mixed` + // + // what we need to to is splitting f1 + // let ... = f1_pre() in + // case ... of + // C1(...) => let x1 = f1_post1(...) in + // jump f0_post(x1) + // C2(...) => let x1' = f1_post2(...) in + // jump f0_post(x1') + // + // f0_post will looks like + // ... #2 + // let x2 = f2(x1) in + // ... #2 + // the problem is how to correctly collect all structures necessary for `f0_post``. + // as we are traversing over the node chain, we shall accumulate the continuation that with a node hole. + // + // in the example above, when we see f2(x1) and find the producer of x1 should be splitted, + // we already have the continuation until `... in #1` + // (we need record the pre-cont before every possible splitting position). + // though, it's still necessary to obtain `... #2` to `... #3` directly. + // how to do that? we also need record the post-cont after every possible splitting position. + // it indicates that yet another kind of context should be carefully maintained. + // another point is worth noticing that we need to do alpha-renaming after using the pre-cont and post-cont!!! + mixingProducer.update(p, info.getFunc(producer)) + case _ => () + case _ => + case _ => () + SDesc(func, argumentsDesc, firstD, mixingProducer) + + def fNode(node: Node)(k: Node => Env ?=> Node)(using env: Env): Node = node match + case Node.Result(res) => k(node) + case Node.Jump(func, args) => + checkSTarget(info.getFunc(func), args) + k(node) + case Node.Case(scrutinee, cases, default) => + symAndIntroOfTExpr(scrutinee) match + case Some((scrutinee, I(loc, IInfo.Mixed(i)))) => + ??? + case _ => + val nuCases = cases.map: + case (p @ Pat.Class(cls), body) => + val old = env.i.intros.put(cls, I(node, IInfo.Ctor(cls))) + val nuBody = fNode(body)(x => x) + for i <- old; _ = env.i.intros.update(cls, i) yield () + (p, nuBody) + case (p @ Pat.Lit(lit), body) => + (p, fNode(body)(x => x)) + val dfltCase = default.map(fNode(_)(x => x)) + k(Node.Case(scrutinee, nuCases, dfltCase)) + case Node.Panic(msg) => node + case Node.LetExpr(name, expr, body) => + fNode(body): inner => + k(Node.LetExpr(name, expr, inner)) + case Node.LetMethodCall(names, cls, method, args, body) => + fNode(body): inner => + k(Node.LetMethodCall(names, cls, method, args, inner)) + case Node.LetCall(names, func, args, body) => + checkSTarget(info.getFunc(func), args) + fNode(body): inner => + k(Node.LetCall(names, func, args, inner)) + \ No newline at end of file From 19e7c90fe9bf09ec396cce4be716ff9aa752713f Mon Sep 17 00:00:00 2001 From: waterlens Date: Tue, 4 Mar 2025 20:59:56 +0800 Subject: [PATCH 55/88] save --- .../main/scala/hkmc2/codegen/llir/Opt.scala | 109 ++++++++++-------- 1 file changed, 62 insertions(+), 47 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Opt.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Opt.scala index 670b866633..c4e530f034 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Opt.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Opt.scala @@ -104,13 +104,11 @@ final class LlirOpt(using Elaborator.State, Raise)(tl: TraceLogger): def addBackwardE(sym: Local, e: E, newLoc: Loc)(using env: Env) = assert(env.def_count.getOrElse(sym, 0) <= 1, s"Multiple definitions of $sym") import EInfo.* - for - e2 <- e match - case E(_, Des) | E(_, IndDes) => Some(E(newLoc, IndDes)) - case E(_, Pass) => Some(E(newLoc, Pass)) - case _ => None - _ = env.elims.getOrElseUpdate(sym, MutHSet.empty).add(e2) - yield () + val e2 = e match + case E(_, Des) | E(_, IndDes) => Some(E(newLoc, IndDes)) + case E(_, Pass) => Some(E(newLoc, Pass)) + case _ => None + for e2 <- e2 do env.elims.getOrElseUpdate(sym, MutHSet.empty).add(e2) def addDef(sym: Local)(using env: Env) = env.def_count.update(sym, env.def_count.getOrElse(sym, 0) + 1) @@ -237,7 +235,7 @@ final class LlirOpt(using Elaborator.State, Raise)(tl: TraceLogger): case S(x) => mergeIntros(casesIntros :+ fNode(x), node) case Node.Panic(msg) => env.default_intro case Node.LetExpr(name, expr, body) => - for i <- fExprWithLoc(expr, node); _ = addI(name, i) yield () + for i <- fExprWithLoc(expr, node) do addI(name, i) fNode(body) case Node.LetMethodCall(names, cls, method, args, body) => fNode(body) case Node.LetCall(names, func, args, body) => @@ -261,11 +259,20 @@ final class LlirOpt(using Elaborator.State, Raise)(tl: TraceLogger): case class PreFunc(sym: Local, results: Ls[Local]) case class PostFunc(sym: Local, params: Ls[Local]) + case class PreFuncBody(body: Node => Node) + case class PostFuncBody(body: Node) private class Splitting(info: FnInfo): + case class RefEqNode(node: Node): + override def equals(that: Any) = that match + case RefEqNode(thatNode) => node eq thatNode + case _ => false + override def hashCode = node.hashCode + case class Env( i: IntroductionAnalysis.Env, e: EliminationAnalysis.Env, + possibleSplitting: MutHMap[RefEqNode, (PreFuncBody, PostFuncBody)] = MutHMap.empty, ) case class SymDDesc( @@ -285,6 +292,10 @@ final class LlirOpt(using Elaborator.State, Raise)(tl: TraceLogger): case Expr.Ref(x) => for i <- env.i.intros.get(x) yield (x, i) case _ => none + def findProducer(loc: Loc) = loc match + case Loc(Node.LetCall(_, producer, _, _)) => some(producer) + case _ => none + def checkSTarget(func: Func, args: Ls[TrivialExpr])(using env: Env) = val activeParams = info.getActiveParams(func.name) val params = func.params @@ -301,47 +312,50 @@ final class LlirOpt(using Elaborator.State, Raise)(tl: TraceLogger): case (S((arg, I(loc, IInfo.Mixed(is)))), (p, elims)) => for e <- elims do e match case E(_, EInfo.Des | EInfo.IndDes) => - loc match - case Loc(Node.LetCall(_, producer, _, _)) => - // what to do with a mixing producer? - // it's different with other kinds of splitting - // - // for example, in f0, we have following program: - // ... #1 - // let x1 = f1() in - // ... #2 - // let x2 = f2(x1) in - // ... #3 - // where x1 is `IInfo.Mixed` - // - // what we need to to is splitting f1 - // let ... = f1_pre() in - // case ... of - // C1(...) => let x1 = f1_post1(...) in - // jump f0_post(x1) - // C2(...) => let x1' = f1_post2(...) in - // jump f0_post(x1') - // - // f0_post will looks like - // ... #2 - // let x2 = f2(x1) in - // ... #2 - // the problem is how to correctly collect all structures necessary for `f0_post``. - // as we are traversing over the node chain, we shall accumulate the continuation that with a node hole. - // - // in the example above, when we see f2(x1) and find the producer of x1 should be splitted, - // we already have the continuation until `... in #1` - // (we need record the pre-cont before every possible splitting position). - // though, it's still necessary to obtain `... #2` to `... #3` directly. - // how to do that? we also need record the post-cont after every possible splitting position. - // it indicates that yet another kind of context should be carefully maintained. - // another point is worth noticing that we need to do alpha-renaming after using the pre-cont and post-cont!!! - mixingProducer.update(p, info.getFunc(producer)) - case _ => () + // what to do with a mixing producer? + // it's different with other kinds of splitting + // + // for example, in f0, we have following program: + // ... #1 + // let x1 = f1() in + // ... #2 + // let x2 = f2(x1) in + // ... #3 + // where x1 is `IInfo.Mixed` + // + // what we need to to is splitting f1 + // let ... = f1_pre() in + // case ... of + // C1(...) => let x1 = f1_post1(...) in + // jump f0_post(x1) + // C2(...) => let x1' = f1_post2(...) in + // jump f0_post(x1') + // + // f0_post will looks like + // ... #2 + // let x2 = f2(x1) in + // ... #2 + // the problem is how to correctly collect all structures necessary for `f0_post``. + // as we are traversing over the node chain, we shall accumulate the continuation that with a node hole. + // + // in the example above, when we see f2(x1) and find the producer of x1 should be splitted, + // we already have the continuation until `... in #1` + // (we need record the pre-cont before every possible splitting position). + // though, it's still necessary to obtain `... #2` to `... #3` directly. + // how to do that? it's just a node following the f1() call, so it's naturally included by the LetCall node + // it also indicates that yet another kind of context should be carefully maintained. + // another point is worth noticing that we need to do alpha-renaming after using the pre-cont and post-cont!!! + val producer = findProducer(loc) + for p <- producer do + mixingProducer.update(p, info.getFunc(p)) case _ => case _ => () SDesc(func, argumentsDesc, firstD, mixingProducer) + def memoCall(callNode: Node.LetCall)(k: Node => Env ?=> Node)(using env: Env): Unit = + val Node.LetCall(names, func, args, body) = callNode + env.possibleSplitting.update(RefEqNode(callNode), (PreFuncBody(node => k(node)(using env)), PostFuncBody(body))) + def fNode(node: Node)(k: Node => Env ?=> Node)(using env: Env): Node = node match case Node.Result(res) => k(node) case Node.Jump(func, args) => @@ -356,7 +370,7 @@ final class LlirOpt(using Elaborator.State, Raise)(tl: TraceLogger): case (p @ Pat.Class(cls), body) => val old = env.i.intros.put(cls, I(node, IInfo.Ctor(cls))) val nuBody = fNode(body)(x => x) - for i <- old; _ = env.i.intros.update(cls, i) yield () + for i <- old do env.i.intros.update(cls, i) (p, nuBody) case (p @ Pat.Lit(lit), body) => (p, fNode(body)(x => x)) @@ -369,8 +383,9 @@ final class LlirOpt(using Elaborator.State, Raise)(tl: TraceLogger): case Node.LetMethodCall(names, cls, method, args, body) => fNode(body): inner => k(Node.LetMethodCall(names, cls, method, args, inner)) - case Node.LetCall(names, func, args, body) => + case node @ Node.LetCall(names, func, args, body) => checkSTarget(info.getFunc(func), args) + memoCall(node)(k) fNode(body): inner => k(Node.LetCall(names, func, args, inner)) \ No newline at end of file From 4372f0d32bf70abc1706981e102abfd9c0ba7bf0 Mon Sep 17 00:00:00 2001 From: waterlens Date: Wed, 5 Mar 2025 21:31:24 +0800 Subject: [PATCH 56/88] Save --- .../scala/hkmc2/codegen/llir/Analysis.scala | 16 +- .../main/scala/hkmc2/codegen/llir/Opt.scala | 319 ++++++++++++++++-- 2 files changed, 287 insertions(+), 48 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Analysis.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Analysis.scala index 51e4414fd9..b34944fc75 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Analysis.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Analysis.scala @@ -68,7 +68,7 @@ class UsefulnessAnalysis(verbose: Bool = false): f(x.body) uses.toMap -class FreeVarAnalysis(ctx: Map[Local, Func], extended_scope: Bool = true, verbose: Bool = false): +class FreeVarAnalysis(ctx: Local => Func): import Expr._ import Node._ @@ -89,13 +89,7 @@ class FreeVarAnalysis(ctx: Map[Local, Func], extended_scope: Bool = true, verbos private def f(using defined: Set[Local])(node: Node, fv: Set[Local]): Set[Local] = node match case Result(res) => res.foldLeft(fv)((acc, arg) => f(using defined)(arg.toExpr, acc)) case Jump(defn, args) => - var fv2 = args.foldLeft(fv)((acc, arg) => f(using defined)(arg.toExpr, acc)) - if extended_scope && !visited.contains(defn) then - visited.add(defn) - val func = ctx.getOrElse(defn, throw Exception(s"Function $defn not found")) - val defined2 = func.params.foldLeft(defined)((acc, param) => acc + param) - fv2 = f(using defined2)(func, fv2) - fv2 + args.foldLeft(fv)((acc, arg) => f(using defined)(arg.toExpr, acc)) case Case(scrut, cases, default) => val fv2 = scrut match case Ref(name) => if defined.contains(name) then fv else fv + name @@ -103,6 +97,7 @@ class FreeVarAnalysis(ctx: Map[Local, Func], extended_scope: Bool = true, verbos val fv3 = cases.foldLeft(fv2): case (acc, (cls, body)) => f(using defined)(body, acc) fv3 + case Panic(msg) => fv case LetMethodCall(resultNames, cls, method, args, body) => var fv2 = args.foldLeft(fv)((acc, arg) => f(using defined)(arg.toExpr, acc)) val defined2 = resultNames.foldLeft(defined)((acc, name) => acc + name) @@ -114,11 +109,6 @@ class FreeVarAnalysis(ctx: Map[Local, Func], extended_scope: Bool = true, verbos case LetCall(resultNames, defn, args, body) => var fv2 = args.foldLeft(fv)((acc, arg) => f(using defined)(arg.toExpr, acc)) val defined2 = resultNames.foldLeft(defined)((acc, name) => acc + name) - if extended_scope && !visited.contains(defn) then - visited.add(defn) - val func = ctx.getOrElse(defn, throw Exception(s"Function $defn not found")) - val defined2 = func.params.foldLeft(defined)((acc, param) => acc + param) - fv2 = f(using defined2)(func, fv2) f(using defined2)(body, fv2) def run(node: Node) = f(using Set.empty)(node, Set.empty) def run_with(node: Node, defined: Set[Local]) = f(using defined)(node, Set.empty) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Opt.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Opt.scala index c4e530f034..f2c9d363d4 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Opt.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Opt.scala @@ -17,9 +17,7 @@ import hkmc2.codegen.cpp.Expr.StrLit import language.implicitConversions import annotation.tailrec import collection.immutable._ -import collection.mutable.{HashMap => MutHMap} -import collection.mutable.{HashSet => MutHSet, Set => MutSet} -import collection.mutable.{MultiMap, Queue} +import collection.mutable.{HashMap => MutHMap, HashSet => MutHSet, LinkedHashMap => MutLMap, LinkedHashSet => MutLSet} import scala.collection.mutable.ListBuffer final case class OptErr(message: String) extends Exception(message) @@ -29,7 +27,7 @@ private def oErrStop(msg: Message)(using Raise) = source = Diagnostic.Source.Compilation)) throw OptErr("stopped") -final class LlirOpt(using Elaborator.State, Raise)(tl: TraceLogger): +final class LlirOpt(using Elaborator.State, Raise)(tl: TraceLogger, freshInt: FreshInt): import tl.{log, trace} object DestructUtils: @@ -46,8 +44,25 @@ final class LlirOpt(using Elaborator.State, Raise)(tl: TraceLogger): def isDestructed(node: Node) = getFirstDestructed(node).isDefined - case class Loc(node: Node) - given Conversion[Node, Loc] = Loc(_) + def newFunSym(name: Str) = TermSymbol(hkmc2.syntax.Fun, None, Tree.Ident(name)) + def newTemp = TempSymbol(N, "x") + + class SubstUtil: + val symMap = MutHMap.empty[Local, Local] + def susbt(sym: Local) = symMap.getOrElseUpdate(sym, newTemp) + def subst(sym: IterableOnce[Local]) = sym.iterator.map(susbt) + def substT(sym: TrivialExpr) = sym match + case Expr.Ref(x) => Expr.Ref(susbt(x)) + case _ => sym + def substT(sym: IterableOnce[TrivialExpr]): Iterator[TrivialExpr] = sym.iterator.map(substT) + + case class RefEqNode(node: Node): + override def equals(that: Any) = that match + case RefEqNode(thatNode) => node eq thatNode + case _ => false + override def hashCode = node.hashCode + type Loc = RefEqNode + given Conversion[Node, Loc] = RefEqNode(_) enum IInfo: case Ctor(c: Local) @@ -257,22 +272,17 @@ final class LlirOpt(using Elaborator.State, Raise)(tl: TraceLogger): changed |= old != nu info.setActiveResults(func.name, nu) - case class PreFunc(sym: Local, results: Ls[Local]) - case class PostFunc(sym: Local, params: Ls[Local]) - case class PreFuncBody(body: Node => Node) - case class PostFuncBody(body: Node) - private class Splitting(info: FnInfo): - case class RefEqNode(node: Node): - override def equals(that: Any) = that match - case RefEqNode(thatNode) => node eq thatNode - case _ => false - override def hashCode = node.hashCode - + case class PreFunc(sym: Local, results: Ls[Local], body: PreFuncBody, orig: Func) + case class PostFunc(sym: Local, params: Ls[Local], body: PostFuncBody, orig: Func) + case class PreFuncBody(body: Node => Node) + case class PostFuncBody(body: Node) + case class Env( i: IntroductionAnalysis.Env, e: EliminationAnalysis.Env, possibleSplitting: MutHMap[RefEqNode, (PreFuncBody, PostFuncBody)] = MutHMap.empty, + workingList: MutLSet[Func] = MutLSet.empty, ) case class SymDDesc( @@ -282,10 +292,9 @@ final class LlirOpt(using Elaborator.State, Raise)(tl: TraceLogger): ) case class SDesc( - func: Func, - argumentsDesc: MutHMap[Local, SymDDesc] = MutHMap.empty, + argumentsDesc: MutLMap[Local, SymDDesc] = MutLMap.empty, firstDestructedSym: Opt[Local] = N, - mixingProducer: MutHMap[Local, Func] = MutHMap.empty, + mixingProducer: MutLMap[Local, Loc] = MutLMap.empty, ) def symAndIntroOfTExpr(te: TrivialExpr)(using env: Env): Opt[(Local, I)] = te match @@ -293,16 +302,20 @@ final class LlirOpt(using Elaborator.State, Raise)(tl: TraceLogger): case _ => none def findProducer(loc: Loc) = loc match - case Loc(Node.LetCall(_, producer, _, _)) => some(producer) + case RefEqNode(Node.LetCall(_, producer, _, _)) => some(producer) case _ => none + // how this function reflects the splitting decision? + // if argumentsDesc is non-empty, it means the callee is a target of been splitted + // if mixingProducer is non-empty, it means a call happens before is a mixing producer, + // as well as the splitting target def checkSTarget(func: Func, args: Ls[TrivialExpr])(using env: Env) = val activeParams = info.getActiveParams(func.name) val params = func.params val argsIntros = args.iterator.map(symAndIntroOfTExpr) val firstD = DestructUtils.getFirstDestructed(func.body) - var argumentsDesc = MutHMap.empty[Local, SymDDesc] - val mixingProducer = MutHMap.empty[Local, Func] + var argumentsDesc = MutLMap.empty[Local, SymDDesc] + val mixingProducer = MutLMap.empty[Local, Loc] argsIntros.zip(params.iterator.zip(activeParams.iterator)).foreach: case ((S((arg, I(loc, IInfo.Ctor(cls))))), (param, elims)) => for e <- elims do e match @@ -347,20 +360,243 @@ final class LlirOpt(using Elaborator.State, Raise)(tl: TraceLogger): // another point is worth noticing that we need to do alpha-renaming after using the pre-cont and post-cont!!! val producer = findProducer(loc) for p <- producer do - mixingProducer.update(p, info.getFunc(p)) + mixingProducer.update(p, loc) case _ => case _ => () - SDesc(func, argumentsDesc, firstD, mixingProducer) + SDesc(argumentsDesc, firstD, mixingProducer) def memoCall(callNode: Node.LetCall)(k: Node => Env ?=> Node)(using env: Env): Unit = val Node.LetCall(names, func, args, body) = callNode env.possibleSplitting.update(RefEqNode(callNode), (PreFuncBody(node => k(node)(using env)), PostFuncBody(body))) + // there's another strategy to split a callee of functions calls + // they can be categorized into several kinds: + // 1. the elimination happens in a nested call + // a). the elimination happens in a most-out level, which means it isn't contained by any other case. + // so what need to do is simply split the callee into 3 parts, namely pre, call, and post. + // this mode is called A mode + // b). it's inside a case + // it's a little difficult to handle, but if this happens, how about to delegate it to the 3rd case + // as we already have a mechanism to handle it. + // 2. the elimination happens in a nested jump + // similar to case 1, but only 2 parts for 2.a, which is called B mode + // 3. the elimination happens in a case + // a). still the case is the outmost one, which is called C mode + // in this case, the function is split into 1 + #(case arms) parts + // b). it's inside another case + // still, split the outmost case first + // + // In any case and sub-case above, it should be guaranteed that the node contains at least one let-call, + // jump, or case node. Otherwise, the splitting is problematic, which implies a bug in the algorithm. + + case class CallShape( + func: Local, + returns: Opt[Ls[Local]], + args: Ls[TrivialExpr], + ) + + case class CaseShape( + scrutinee: TrivialExpr, + cases: Ls[(Pat, PostFunc)], + default: Opt[PostFunc], + ) + + enum SplittingMode: + case A(pre: PreFunc, post: PostFunc, callS: CallShape) + case B(pre: PreFunc, callS: CallShape) + case C(pre: PreFunc, caseS: CaseShape) + + case class ComposeResult( + k: Node => Node, + newFunc: Ls[Func], + invalidFunc: Func + ) + + def reComposeWithArgs(sm: SplittingMode, args: Ls[TrivialExpr], returns: Opt[Ls[Local]], knownClass: Opt[Local]): ComposeResult = + sm match + case SplittingMode.A( + PreFunc(preSym, results, PreFuncBody(preBody), orig), + PostFunc(postSym, params, PostFuncBody(postBody), _), + CallShape(func, nestedReturns, nestedArgs)) => + val preNode = preBody(Node.Result(results.map(Expr.Ref(_)))) + val postNode = postBody + val preFunc = Func(freshInt.make, preSym, orig.params, results.length, preNode) + val postFunc = Func(freshInt.make, postSym, params, orig.resultNum, postNode) + val k = (node: Node) => + val subst = SubstUtil() + // alpha rename the nestedReturns, results, nestedArgs, and params + // since they may be reused in different contexts + val nuNestedReturns = subst.subst(nestedReturns.get) + val nuResults = subst.subst(results) + val nuNestedArgs = subst.substT(nestedArgs) + val nuParams = subst.subst(params) + val tailJump = returns.isEmpty + Node.LetCall(nuResults.toList, preSym, args, + Node.LetCall(nuNestedReturns.toList, func, nuNestedArgs.toList, + if tailJump then + Node.Jump(postSym, nuParams.map(Expr.Ref(_)).toList) + else + Node.LetCall(returns.get, postSym, nuParams.map(Expr.Ref(_)).toList, node))) + ComposeResult(k, List(preFunc, postFunc), orig) + case SplittingMode.B( + PreFunc(preSym, results, PreFuncBody(preBody), orig), + CallShape(func, nestedReturns, nestedArgs)) => + val preNode = preBody(Node.Result(results.map(Expr.Ref(_)))) + val preFunc = Func(freshInt.make, preSym, orig.params, results.length, preNode) + val k = (node: Node) => + val subst = SubstUtil() + // there are no nested returns since in original function it's a jump + val nuResults = subst.subst(results) + val nuNestedArgs = subst.substT(nestedArgs) + val tailJump = returns.isEmpty + Node.LetCall(nuResults.toList, preSym, args, + if tailJump then + Node.Jump(func, nuNestedArgs.toList) + else + Node.LetCall(returns.get, func, nuNestedArgs.toList, node)) + ComposeResult(k, List(preFunc), orig) + case SplittingMode.C( + PreFunc(preSym, results, PreFuncBody(preBody), orig), + CaseShape(scrutinee, cases, default)) => + val preNode = preBody(Node.Result(results.map(Expr.Ref(_)))) + val preFunc = Func(freshInt.make, preSym, orig.params, results.length, preNode) + var matchedPat = none[Pat] + val allPostFunc = cases.map: + case (pat, PostFunc(postSym, params, PostFuncBody(postBody), _)) => + val postNode = postBody + val postFunc = Func(freshInt.make, postSym, params, orig.resultNum, postNode) + (pat, knownClass) match + case (Pat.Class(cls), S(cls2)) if cls == cls2 => matchedPat = some(pat) + case _ => + pat -> postFunc + val defaultPostFunc = default.map: + case PostFunc(postSym, params, PostFuncBody(postBody), _) => + val postNode = postBody + val postFunc = Func(freshInt.make, postSym, params, orig.resultNum, postNode) + postFunc + def tailNodeLetCall(postFunc: Func, node: Node) = + Node.LetCall(returns.get, postFunc.name, postFunc.params.map(Expr.Ref(_)).toList, node) + def tailNodeJump(postFunc: Func) = + Node.Jump(postFunc.name, postFunc.params.map(Expr.Ref(_)).toList) + def tailNodeChoose(postFunc: Func, node: Node) = + if returns.isEmpty then tailNodeJump(postFunc) else tailNodeLetCall(postFunc, node) + // the supplied node should be trivial, otherwise we actually duplicate stuff here + val k = (node: Node) => + val subst = SubstUtil() + val nuResults = subst.subst(results) + val nuScrutinee = subst.substT(scrutinee) + val tailJump = returns.isEmpty + (knownClass, matchedPat) match + case (None, _) => + Node.LetCall(nuResults.toList, preSym, args, + Node.Case(nuScrutinee, allPostFunc.map: + case (pat, postFunc) => + pat -> tailNodeChoose(postFunc, node), + defaultPostFunc.map(postFunc => + tailNodeChoose(postFunc, node)))) + case (Some(_), None) => + // only keep the default case if there's one + defaultPostFunc match + case None => + Node.LetCall(nuResults.toList, preSym, args, + Node.Case(nuScrutinee, allPostFunc.map: + case (pat, postFunc) => + pat -> tailNodeChoose(postFunc, node), + defaultPostFunc.map(postFunc => + tailNodeChoose(postFunc, node)))) + case Some(postFunc) => + Node.LetCall(nuResults.toList, preSym, args, + tailNodeChoose(postFunc, node)) + case (Some(_), Some(matched)) => + Node.LetCall(nuResults.toList, preSym, args, + allPostFunc.flatMap: + case (pat, postFunc) => if pat == matched then + S(tailNodeChoose(postFunc, node)) else N + .head) + ComposeResult(k, preFunc :: allPostFunc.map(_._2) ++ defaultPostFunc.toList, orig) + + + def sFunc(func: Func, splitPos: Loc): SplittingMode = + sNode(func.body, splitPos, func)(identity) + + def sNode(node: Node, splitPos: Loc, thisFunc: Func)(acc: Node => Node): SplittingMode = node match + case Node.Result(res) => oErrStop("sNode: unexpected Result") + case Node.Jump(func, args) => + // B mode + val sym = newFunSym(s"${thisFunc.name.nme}_pre") + val pfBody = PreFuncBody(acc) + val fvs = FreeVarAnalysis(info.func).run(node) + val results = fvs.toList + val pf = PreFunc(sym, results, pfBody, thisFunc) + val cs = CallShape(func, none, args) + SplittingMode.B(pf, cs) + case Node.Case(scrutinee, cases, default) => + // C mode + val sym = newFunSym(s"${thisFunc.name.nme}_pre") + val pfBody = PreFuncBody(acc) + val fvs = FreeVarAnalysis(info.func).run(node) + val results = fvs.toList + val pf = PreFunc(sym, results, pfBody, thisFunc) + val cases2 = cases.zipWithIndex.map: + case ((pat, body), i) => + val sym = newFunSym(s"${thisFunc.name.nme}_case$i") + val fvs = FreeVarAnalysis(info.func).run(node) + val pfBody = PostFuncBody(body) + val pf = PostFunc(sym, fvs.toList, pfBody, thisFunc) + (pat, pf) + val default2 = default.map: node => + val sym = newFunSym(s"${thisFunc.name.nme}_default") + val fvs = FreeVarAnalysis(info.func).run(node) + val pfBody = PostFuncBody(node) + val pf = PostFunc(sym, fvs.toList, pfBody, thisFunc) + pf + val caseS = CaseShape(scrutinee, cases2, default2) + SplittingMode.C(pf, caseS) + case Node.Panic(msg) => oErrStop("sNode: unexpected Panic") + case Node.LetExpr(name, expr, body) => + sNode(body, splitPos, thisFunc)(x => Node.LetExpr(name, expr, x)) + case Node.LetMethodCall(names, cls, method, args, body) => + sNode(body, splitPos, thisFunc)(x => Node.LetMethodCall(names, cls, method, args, x)) + case Node.LetCall(names, func, args, body) => + if splitPos == RefEqNode(node) then + // A mode + val sym = newFunSym(s"${thisFunc.name.nme}_pre") + val pfBody = PreFuncBody(acc) + val fvs = FreeVarAnalysis(info.func).run(node) + val results = fvs.toList + val pf = PreFunc(sym, results, pfBody, thisFunc) + val cs = CallShape(func, some(names), args) + SplittingMode.A(pf, PostFunc(func, names, PostFuncBody(body), thisFunc), cs) + else + sNode(body, splitPos, thisFunc)(x => Node.LetCall(names, func, args, x)) + + // yet another thing is to avoid duplication. once we split a function + // the sub-components of the function will be wrapped into a new function + // so the original function should be correspondingly updated. + def rFunc(orig: Func, sm: SplittingMode)(using env: Env): Unit = + val s = SubstUtil() + val nuParams = s.subst(orig.params).toList + val nuArgs = nuParams.map(Expr.Ref(_)).toList + val ComposeResult(k, newFuncs, invalidFunc) = reComposeWithArgs(sm, nuArgs, N, N) + assert(orig.name == invalidFunc.name, s"rFunc: invalidFunc: $invalidFunc, orig: $orig") + env.workingList.remove(invalidFunc) + val nuFunc = Func( + orig.id, + orig.name, + nuParams, + orig.resultNum, + k(Node.Panic("placeholder here")) + ) + info.func.update(invalidFunc.name, nuFunc) + + def fNode(node: Node)(k: Node => Env ?=> Node)(using env: Env): Node = node match case Node.Result(res) => k(node) case Node.Jump(func, args) => - checkSTarget(info.getFunc(func), args) - k(node) + val sDesc = checkSTarget(info.getFunc(func), args) + (sDesc.argumentsDesc.isEmpty, sDesc.mixingProducer.isEmpty) match + case (true, true) => k(node) + case _ => ??? case Node.Case(scrutinee, cases, default) => symAndIntroOfTExpr(scrutinee) match case Some((scrutinee, I(loc, IInfo.Mixed(i)))) => @@ -369,12 +605,12 @@ final class LlirOpt(using Elaborator.State, Raise)(tl: TraceLogger): val nuCases = cases.map: case (p @ Pat.Class(cls), body) => val old = env.i.intros.put(cls, I(node, IInfo.Ctor(cls))) - val nuBody = fNode(body)(x => x) + val nuBody = fNode(body)(identity) for i <- old do env.i.intros.update(cls, i) (p, nuBody) case (p @ Pat.Lit(lit), body) => - (p, fNode(body)(x => x)) - val dfltCase = default.map(fNode(_)(x => x)) + (p, fNode(body)(identity)) + val dfltCase = default.map(fNode(_)(identity)) k(Node.Case(scrutinee, nuCases, dfltCase)) case Node.Panic(msg) => node case Node.LetExpr(name, expr, body) => @@ -384,8 +620,21 @@ final class LlirOpt(using Elaborator.State, Raise)(tl: TraceLogger): fNode(body): inner => k(Node.LetMethodCall(names, cls, method, args, inner)) case node @ Node.LetCall(names, func, args, body) => - checkSTarget(info.getFunc(func), args) - memoCall(node)(k) - fNode(body): inner => - k(Node.LetCall(names, func, args, inner)) - \ No newline at end of file + val sDesc = checkSTarget(info.getFunc(func), args) + (sDesc.argumentsDesc.isEmpty, sDesc.mixingProducer.isEmpty) match + case (true, _) => + memoCall(node)(k) + fNode(body): inner => + k(Node.LetCall(names, func, args, inner)) + case (false, _) => + val desc = sDesc.argumentsDesc.head + val (sym, SymDDesc(knownC, isInd, e)) = desc + val old = info.getFunc(func) + val sm = sFunc(info.getFunc(func), e.loc) + rFunc(old, sm) + val cr = reComposeWithArgs(sm, args, S(names), N) + // make a post function for current `body` + // deal with alpha renaming + ??? + // case (_, false) => ??? + From 19925895899976787f8e0f9c6871d25e134e4831 Mon Sep 17 00:00:00 2001 From: waterlens Date: Thu, 6 Mar 2025 19:45:12 +0800 Subject: [PATCH 57/88] Add simplification opt --- .../main/scala/hkmc2/codegen/llir/Llir.scala | 6 + .../main/scala/hkmc2/codegen/llir/Opt.scala | 487 ++++++++++++++---- .../shared/src/test/mlscript/llir/Legacy.mls | 81 +-- .../src/test/mlscript/llir/nofib/atom.mls | 4 +- .../src/test/mlscript/llir/nofib/awards.mls | 2 + .../test/mlscript/llir/nofib/constraints.mls | 2 + .../src/test/mlscript/llir/nofib/scc.mls | 2 + .../test/mlscript/llir/nofib/secretary.mls | 2 + .../src/test/scala/hkmc2/LlirDiffMaker.scala | 33 +- 9 files changed, 438 insertions(+), 181 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Llir.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Llir.scala index fd772bb8b4..67b2acec26 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Llir.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Llir.scala @@ -115,6 +115,12 @@ sealed trait TrivialExpr: def show: String def toDocument: Document def toExpr: Expr = this match { case x: Expr => x } + def foldRef(f: Local => TrivialExpr): TrivialExpr = this match + case Ref(sym) => f(sym) + case _ => this + def iterRef(f: Local => Unit): Unit = this match + case Ref(sym) => f(sym) + case _ => () private def showArguments(args: Ls[TrivialExpr]) = args map (_.show) mkString "," diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Opt.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Opt.scala index f2c9d363d4..a1c19861b1 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Opt.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Opt.scala @@ -27,7 +27,18 @@ private def oErrStop(msg: Message)(using Raise) = source = Diagnostic.Source.Compilation)) throw OptErr("stopped") -final class LlirOpt(using Elaborator.State, Raise)(tl: TraceLogger, freshInt: FreshInt): +def notBuiltinLetCall(node: Node.LetCall) = + node.func.nme != "" + +def notBuiltin(sym: Local) = + sym.nme != "" + +def notCallable(sym: Local) = + sym.nme != "Callable" + +def showSym(sym: Local) = s"${sym.nme}$$${sym.uid.toString()}" + +final class LlirOpt(using Elaborator.State, Raise)(tl: TraceLogger, freshInt: FreshInt, flags: Set[Str]): import tl.{log, trace} object DestructUtils: @@ -46,14 +57,23 @@ final class LlirOpt(using Elaborator.State, Raise)(tl: TraceLogger, freshInt: Fr def newFunSym(name: Str) = TermSymbol(hkmc2.syntax.Fun, None, Tree.Ident(name)) def newTemp = TempSymbol(N, "x") + val placeHolderSym = TempSymbol(N, "") - class SubstUtil: - val symMap = MutHMap.empty[Local, Local] - def susbt(sym: Local) = symMap.getOrElseUpdate(sym, newTemp) - def subst(sym: IterableOnce[Local]) = sym.iterator.map(susbt) - def substT(sym: TrivialExpr) = sym match - case Expr.Ref(x) => Expr.Ref(susbt(x)) - case _ => sym + class RenameUtil(): + val map: MutHMap[Local, Local] = MutHMap.empty + def subst(sym: Local): Local = map.getOrElseUpdate(sym, newTemp) + def subst(sym: IterableOnce[Local]): Iterator[Local] = sym.iterator.map(subst) + def substT(sym: TrivialExpr): TrivialExpr = sym.foldRef(x => Expr.Ref(subst(x))) + def substT(sym: IterableOnce[TrivialExpr]): Iterator[TrivialExpr] = sym.iterator.map(substT) + + class SubstUtil[K, +V](val map: Map[K, V]): + def subst(k: K) = map.getOrElse(k, oErrStop(s"Key $k not found")) + def subst(k: IterableOnce[K]): Iterator[V] = k.iterator.map(subst) + + class MapUtil(val map: Map[Local, Local]): + def subst(k: Local) = map.getOrElse(k, k) + def subst(k: IterableOnce[Local]): Iterator[Local] = k.iterator.map(subst) + def substT(sym: TrivialExpr): TrivialExpr = sym.foldRef(x => Expr.Ref(subst(x))) def substT(sym: IterableOnce[TrivialExpr]): Iterator[TrivialExpr] = sym.iterator.map(substT) case class RefEqNode(node: Node): @@ -83,11 +103,26 @@ final class LlirOpt(using Elaborator.State, Raise)(tl: TraceLogger, freshInt: Fr implicit object IOrdering extends Ordering[I]: override def compare(a: I, b: I) = a.info.toString.compare(b.info.toString) - case class FnInfo( - activeParams: MutHMap[Local, Ls[SortedSet[E]]] = MutHMap.empty, - activeResults: MutHMap[Local, Ls[Opt[I]]] = MutHMap.empty, - func: MutHMap[Local, Func] = MutHMap.empty, + object ProgInfo: + def fromProgram(prog: LlirProgram) = + ProgInfo( + activeParams = MutHMap.from(prog.defs.iterator.map(f => f.name -> f.params.map(_ => SortedSet.empty[E]))), + activeResults = MutHMap.from(prog.defs.iterator.map(f => f.name -> List.fill(f.resultNum)(N))), + func = MutHMap.from(prog.defs.map(f => f.name -> f)), + classes = MutHMap.from(prog.classes.map(c => c.name -> c)), + entry = prog.entry + ) + + case class ProgInfo( + activeParams: MutHMap[Local, Ls[SortedSet[E]]], + activeResults: MutHMap[Local, Ls[Opt[I]]], + func: MutHMap[Local, Func], + classes: MutHMap[Local, ClassInfo], + entry: Local, ): + def toProgram = + LlirProgram(classes.values.toSet, func.values.toSet, entry = entry) + def getActiveParams(func: Local) = activeParams.getOrElse(func, oErrStop(s"Function $func with empty activeParams")) @@ -95,7 +130,10 @@ final class LlirOpt(using Elaborator.State, Raise)(tl: TraceLogger, freshInt: Fr activeResults.getOrElse(func, oErrStop(s"Function $func with empty activeResults")) def getFunc(sym: Local): Func = - func.getOrElse(sym, oErrStop(s"Function $func not found")) + func.getOrElse(sym, oErrStop(s"Function $sym not found")) + + def getClass(sym: Local): ClassInfo = + classes.getOrElse(sym, oErrStop(s"Class $sym not found")) def setActiveParams(func: Local, aps: Ls[SortedSet[E]]) = activeParams.update(func, aps) @@ -110,14 +148,13 @@ final class LlirOpt(using Elaborator.State, Raise)(tl: TraceLogger, freshInt: Fr val defn: Local, val visited: MutHSet[Local] = MutHSet.empty, ) - private class EliminationAnalysis(info: FnInfo): + + private class EliminationAnalysis(info: ProgInfo): import EliminationAnalysis.Env def addE(sym: Local, e: E)(using env: Env) = - assert(env.def_count.getOrElse(sym, 0) <= 1, s"Multiple definitions of $sym") env.elims.getOrElseUpdate(sym, MutHSet.empty) += e def addBackwardE(sym: Local, e: E, newLoc: Loc)(using env: Env) = - assert(env.def_count.getOrElse(sym, 0) <= 1, s"Multiple definitions of $sym") import EInfo.* val e2 = e match case E(_, Des) | E(_, IndDes) => Some(E(newLoc, IndDes)) @@ -128,9 +165,8 @@ final class LlirOpt(using Elaborator.State, Raise)(tl: TraceLogger, freshInt: Fr def addDef(sym: Local)(using env: Env) = env.def_count.update(sym, env.def_count.getOrElse(sym, 0) + 1) - def fTExprWithLoc(x: TrivialExpr, loc: Loc)(using env: Env): Unit = x match - case Expr.Ref(name) => addE(name, E(loc, EInfo.Pass)) - case _ => () + def fTExprWithLoc(x: TrivialExpr, loc: Loc)(using env: Env): Unit = + x.iterRef(addE(_, E(loc, EInfo.Pass))) def fExprWithLoc(x: Expr, loc: Loc)(using env: Env): Unit = x match case Expr.Ref(name) => addE(name, E(loc, EInfo.Pass)) @@ -140,19 +176,15 @@ final class LlirOpt(using Elaborator.State, Raise)(tl: TraceLogger, freshInt: Fr case Expr.BasicOp(name, args) => args.foreach(fTExprWithLoc(_, loc)) case Expr.AssignField(assignee, _, _, value) => TODO("fExprWithLoc: AssignField") - def getFunc(func: Local)(using env: Env): Func = - info.func.getOrElse(func, oErrStop(s"Function $func not found")) - - def fNode(node: Node)(using env: Env): Unit = def fDef(func: Local, args: Ls[TrivialExpr], funcDefn: Func)(using env: Env) = val aps = info.getActiveParams(func) args.iterator.zip(aps).foreach: case (Expr.Ref(x), ys) => ys.foreach(y => addBackwardE(x, y, node)) - case _ => oErrStop("fNode: Jump") - if !env.visited.contains(func) then + case _ => + if !env.visited.contains(func) && notBuiltin(func) then env.visited.add(func) - val funcDefn = getFunc(func) + val funcDefn = info.getFunc(func) funcDefn.params.foreach(addDef) val newEnv = env.copy(defn = func) fNode(funcDefn.body)(using newEnv) @@ -160,7 +192,8 @@ final class LlirOpt(using Elaborator.State, Raise)(tl: TraceLogger, freshInt: Fr case Node.Result(res) => res.foreach(fTExprWithLoc(_, node)) case Node.Jump(func, args) => args.foreach(fTExprWithLoc(_, node)) - fDef(func, args, getFunc(func)) + if notBuiltin(func) then + fDef(func, args, info.getFunc(func)) case Node.Case(Expr.Ref(scrutinee), cases, default) => addE(scrutinee, E(node, EInfo.Pass)) addE(scrutinee, E(node, EInfo.Des)) @@ -180,43 +213,54 @@ final class LlirOpt(using Elaborator.State, Raise)(tl: TraceLogger, freshInt: Fr case Node.LetCall(names, func, args, body) => names.foreach(addDef) args.foreach(fTExprWithLoc(_, node)) - fDef(func, args, getFunc(func)) + if notBuiltin(func) then + fDef(func, args, info.getFunc(func)) fNode(body) - def run(prog: LlirProgram) = + def run() = var changed = true + var env = Env(defn = placeHolderSym) while changed do changed = false - prog.defs.foreach: func => + env = Env(defn = placeHolderSym) + info.func.values.foreach: func => val old = info.getActiveParams(func.name) - val env = Env(defn = func.name) func.params.foreach(addDef(_)(using env)) fNode(func.body)(using env) val nu = func.params.iterator.map(p => env.elims.getOrElse(p, MutHSet.empty).toSortedSet).toList changed |= old != nu info.setActiveParams(func.name, nu) + env private object IntroductionAnalysis: case class Env( intros: MutHMap[Local, I] = MutHMap.empty, default_intro: Ls[Opt[I]], // the intro of panic ) - private class IntroductionAnalysis(info: FnInfo): + + private class IntroductionAnalysis(info: ProgInfo): import IntroductionAnalysis.Env def mergeIntros(xs: Ls[Ls[Opt[I]]], loc: Loc): Ls[Opt[I]] = - val xst = xs.transpose - xst.map: ys => - val z = ys.flatMap: - case N => Set.empty[I] - case S(I(loc, IInfo.Mixed(i))) => i - case S(i) => Set(i) - .toSet - if z.nonEmpty then S(I(loc, IInfo.Mixed(z))) else N + trace[Ls[Opt[I]]](s"mergeIntros: $xs"): + val xst = xs.transpose + xst.map: ys => + val z = ys.flatMap: + case N => Set.empty[I] + case S(I(loc, IInfo.Mixed(i))) => i + case S(i) => Set(i) + .toSet + if z.nonEmpty then S(I(loc, IInfo.Mixed(z))) else N def addI(sym: Local, i: I)(using env: Env) = - if env.intros.contains(sym) then - throw OptErr(s"Multiple introductions of $sym") - env.intros.addOne(sym -> i) + trace[Unit](s"addI: ${sym.nme}$$${sym.uid.toString()} -> $i"): + if env.intros.contains(sym) then + oErrStop(s"Multiple introductions of ${sym.nme}$$${sym.uid.toString()}") + env.intros.update(sym, i) + + + def addITExpr(te: TrivialExpr, i: I)(using env: Env) = te match + case Expr.Ref(x) => addI(x, i) + case _ => () // given the arguments of a function call, we find their intro-info and propagate them to the function's parameters def bindIInfo(args: Ls[TrivialExpr], params: Ls[Symbol])(using env: Env) = @@ -233,46 +277,52 @@ final class LlirOpt(using Elaborator.State, Raise)(tl: TraceLogger, freshInt: Fr case Expr.CtorApp(cls, args) => S(I(loc, IInfo.Ctor(cls))) case _ => N - def fNode(node: Node)(using env: Env): Ls[Opt[I]] = node match - case Node.Result(res) => res.map(f => fTExprWithLoc(f, node)) - case Node.Jump(func, args) => - info.getActiveResults(func).map: - case N => N - case S(I(loc, i)) => S(I(node, i)) - case Node.Case(scrutinee, cases, default) => - val casesIntros = cases.map: - case (Pat.Class(cls), body) => - addI(cls, I(node, IInfo.Ctor(cls))) - fNode(body) - case (Pat.Lit(lit), body) => fNode(body) - default match - case N => mergeIntros(casesIntros, node) - case S(x) => mergeIntros(casesIntros :+ fNode(x), node) - case Node.Panic(msg) => env.default_intro - case Node.LetExpr(name, expr, body) => - for i <- fExprWithLoc(expr, node) do addI(name, i) - fNode(body) - case Node.LetMethodCall(names, cls, method, args, body) => fNode(body) - case Node.LetCall(names, func, args, body) => - val funcDefn = info.getFunc(func) - val ars = info.getActiveResults(func) - names.iterator.zip(ars).foreach: - case (rv, S(I(oldLoc, i))) => addI(rv, I(node, i)) - case _ => () - fNode(body) - - def run(prog: LlirProgram) = + def fNode(node: Node)(using env: Env): Ls[Opt[I]] = + trace[Ls[Opt[I]]](s"fNode: $node"): + node match + case Node.Result(res) => res.map(f => fTExprWithLoc(f, node)) + case Node.Jump(func, args) => + info.getActiveResults(func).map: + case N => N + case S(I(loc, i)) => S(I(node, i)) + case Node.Case(scrutinee, cases, default) => + val casesIntros = cases.map: + case (Pat.Class(cls), body) => + // addITExpr(scrutinee, I(node, IInfo.Ctor(cls))) + fNode(body) + case (Pat.Lit(lit), body) => fNode(body) + default match + case N => mergeIntros(casesIntros, node) + case S(x) => mergeIntros(casesIntros :+ fNode(x), node) + case Node.Panic(msg) => env.default_intro + case Node.LetExpr(name, expr, body) => + for i <- fExprWithLoc(expr, node) do addI(name, i) + fNode(body) + case Node.LetMethodCall(names, cls, method, args, body) => fNode(body) + case Node.LetCall(names, func, args, body) => + if notBuiltin(func) then + val funcDefn = info.getFunc(func) + val ars = info.getActiveResults(func) + names.iterator.zip(ars).foreach: + case (rv, S(I(oldLoc, i))) => addI(rv, I(node, i)) + case _ => () + fNode(body) + + def run() = var changed = true + var env = Env(default_intro = Nil) while changed do changed = false - prog.defs.foreach: func => + env = Env(default_intro = Nil) + info.func.values.foreach: func => val old = info.getActiveResults(func.name) - val nu = fNode(func.body)(using Env(default_intro = List.fill(func.params.length)(N))) + val nu = fNode(func.body)(using env.copy(default_intro = List.fill(func.resultNum)(N))) assert(old.length == nu.length, s"old: $old, nu: $nu") changed |= old != nu info.setActiveResults(func.name, nu) + env - private class Splitting(info: FnInfo): + private class Splitting(info: ProgInfo): case class PreFunc(sym: Local, results: Ls[Local], body: PreFuncBody, orig: Func) case class PostFunc(sym: Local, params: Ls[Local], body: PostFuncBody, orig: Func) case class PreFuncBody(body: Node => Node) @@ -412,6 +462,34 @@ final class LlirOpt(using Elaborator.State, Raise)(tl: TraceLogger, freshInt: Fr invalidFunc: Func ) + def renameExpr(expr: Expr)(using s: RenameUtil): Expr = expr match + case Expr.Ref(sym) => Expr.Ref(s.subst(sym)) + case Expr.Literal(lit) => expr + case Expr.CtorApp(cls, args) => Expr.CtorApp(cls, s.substT(args).toList) + case Expr.Select(name, cls, field) => Expr.Select(s.subst(name), s.subst(cls), field) + case Expr.BasicOp(name, args) => Expr.BasicOp(s.subst(name), s.substT(args).toList) + case Expr.AssignField(assignee, cls, field, value) => Expr.AssignField(s.subst(assignee), cls, field, s.substT(value)) + + + def renameNode(node: Node)(using s: RenameUtil): Node = node match + case Node.Result(res) => Node.Result(s.substT(res).toList) + case Node.Jump(func, args) => Node.Jump(func, s.substT(args).toList) + case Node.Case(scrutinee, cases, default) => + Node.Case(s.substT(scrutinee), cases.map: + case (pat, body) => pat -> renameNode(body), + default.map(renameNode(_))) + case Node.Panic(msg) => Node.Panic(msg) + case Node.LetExpr(name, expr, body) => + val nuName = s.subst(name) + val nuExpr = renameExpr(expr) + Node.LetExpr(nuName, expr, renameNode(body)) + case Node.LetMethodCall(names, cls, method, args, body) => + val nuNames = names.map(s.subst) + Node.LetMethodCall(nuNames, cls, method, s.substT(args).toList, renameNode(body)) + case Node.LetCall(names, func, args, body) => + val nuNames = names.map(s.subst) + Node.LetCall(nuNames, func, s.substT(args).toList, renameNode(body)) + def reComposeWithArgs(sm: SplittingMode, args: Ls[TrivialExpr], returns: Opt[Ls[Local]], knownClass: Opt[Local]): ComposeResult = sm match case SplittingMode.A( @@ -423,7 +501,7 @@ final class LlirOpt(using Elaborator.State, Raise)(tl: TraceLogger, freshInt: Fr val preFunc = Func(freshInt.make, preSym, orig.params, results.length, preNode) val postFunc = Func(freshInt.make, postSym, params, orig.resultNum, postNode) val k = (node: Node) => - val subst = SubstUtil() + val subst = RenameUtil() // alpha rename the nestedReturns, results, nestedArgs, and params // since they may be reused in different contexts val nuNestedReturns = subst.subst(nestedReturns.get) @@ -444,7 +522,7 @@ final class LlirOpt(using Elaborator.State, Raise)(tl: TraceLogger, freshInt: Fr val preNode = preBody(Node.Result(results.map(Expr.Ref(_)))) val preFunc = Func(freshInt.make, preSym, orig.params, results.length, preNode) val k = (node: Node) => - val subst = SubstUtil() + val subst = RenameUtil() // there are no nested returns since in original function it's a jump val nuResults = subst.subst(results) val nuNestedArgs = subst.substT(nestedArgs) @@ -482,7 +560,7 @@ final class LlirOpt(using Elaborator.State, Raise)(tl: TraceLogger, freshInt: Fr if returns.isEmpty then tailNodeJump(postFunc) else tailNodeLetCall(postFunc, node) // the supplied node should be trivial, otherwise we actually duplicate stuff here val k = (node: Node) => - val subst = SubstUtil() + val subst = RenameUtil() val nuResults = subst.subst(results) val nuScrutinee = subst.substT(scrutinee) val tailJump = returns.isEmpty @@ -574,7 +652,7 @@ final class LlirOpt(using Elaborator.State, Raise)(tl: TraceLogger, freshInt: Fr // the sub-components of the function will be wrapped into a new function // so the original function should be correspondingly updated. def rFunc(orig: Func, sm: SplittingMode)(using env: Env): Unit = - val s = SubstUtil() + val s = RenameUtil() val nuParams = s.subst(orig.params).toList val nuArgs = nuParams.map(Expr.Ref(_)).toList val ComposeResult(k, newFuncs, invalidFunc) = reComposeWithArgs(sm, nuArgs, N, N) @@ -587,20 +665,38 @@ final class LlirOpt(using Elaborator.State, Raise)(tl: TraceLogger, freshInt: Fr orig.resultNum, k(Node.Panic("placeholder here")) ) + newFuncs.foreach(f => info.func.update(f.name, f)) info.func.update(invalidFunc.name, nuFunc) - - def fNode(node: Node)(k: Node => Env ?=> Node)(using env: Env): Node = node match + def wrapPost(node: Node)(using env: Env, thisFunc: Func): Node = + val fvs = FreeVarAnalysis(info.func).run(node).toList + val sym = newFunSym(s"${thisFunc.name.nme}_post") + val s = RenameUtil() + val nuBody = renameNode(node)(using s) + val nuParams = s.subst(fvs).toList + val nuFunc = Func(freshInt.make, sym, nuParams, thisFunc.resultNum, nuBody) + info.func.update(sym, nuFunc) + Node.Jump(sym, fvs.map(Expr.Ref(_))) + + def fNode(node: Node)(k: Node => Env ?=> Node)(using env: Env, thisFunc: Func): Node = node match case Node.Result(res) => k(node) case Node.Jump(func, args) => val sDesc = checkSTarget(info.getFunc(func), args) (sDesc.argumentsDesc.isEmpty, sDesc.mixingProducer.isEmpty) match - case (true, true) => k(node) - case _ => ??? + case (true, _) => k(node) + case (false, _) => + val desc = sDesc.argumentsDesc.head + val (sym, SymDDesc(knownC, isInd, e)) = desc + val old = info.getFunc(func) + val sm = sFunc(info.getFunc(func), e.loc) + rFunc(old, sm) + val cr = reComposeWithArgs(sm, args, N, N) + val nuBody = cr.k(Node.Panic("placeholder here")) + k(nuBody) case Node.Case(scrutinee, cases, default) => symAndIntroOfTExpr(scrutinee) match - case Some((scrutinee, I(loc, IInfo.Mixed(i)))) => - ??? + // case Some((scrutinee, I(loc, IInfo.Mixed(i)))) => + // ??? case _ => val nuCases = cases.map: case (p @ Pat.Class(cls), body) => @@ -620,21 +716,208 @@ final class LlirOpt(using Elaborator.State, Raise)(tl: TraceLogger, freshInt: Fr fNode(body): inner => k(Node.LetMethodCall(names, cls, method, args, inner)) case node @ Node.LetCall(names, func, args, body) => - val sDesc = checkSTarget(info.getFunc(func), args) - (sDesc.argumentsDesc.isEmpty, sDesc.mixingProducer.isEmpty) match - case (true, _) => - memoCall(node)(k) - fNode(body): inner => - k(Node.LetCall(names, func, args, inner)) - case (false, _) => - val desc = sDesc.argumentsDesc.head - val (sym, SymDDesc(knownC, isInd, e)) = desc - val old = info.getFunc(func) - val sm = sFunc(info.getFunc(func), e.loc) - rFunc(old, sm) - val cr = reComposeWithArgs(sm, args, S(names), N) - // make a post function for current `body` - // deal with alpha renaming - ??? - // case (_, false) => ??? + if notBuiltin(func) then + val sDesc = checkSTarget(info.getFunc(func), args) + (sDesc.argumentsDesc.isEmpty, sDesc.mixingProducer.isEmpty) match + case (true, _) => + memoCall(node)(k) + fNode(body): inner => + k(Node.LetCall(names, func, args, inner)) + case (false, _) => + val desc = sDesc.argumentsDesc.head + val (sym, SymDDesc(knownC, isInd, e)) = desc + val old = info.getFunc(func) + val sm = sFunc(info.getFunc(func), e.loc) + rFunc(old, sm) + val cr = reComposeWithArgs(sm, args, S(names), N) + val tail = wrapPost(body) + val nuBody = cr.k(tail) + k(nuBody) + // case (_, false) => ??? + else + fNode(body): inner => + k(Node.LetCall(names, func, args, inner)) + + def fFunc(func: Func)(using env: Env): Unit = + val nuFunc = Func(func.id, func.name, func.params, func.resultNum, fNode(func.body)(identity)(using env, func)) + info.func.update(func.name, nuFunc) + def run() = + val i = IntroductionAnalysis(info) + val iEnv = i.run() + val e = EliminationAnalysis(info) + val eEnv = e.run() + val env = Env(iEnv, eEnv) + env.workingList.addAll(info.func.values) + log(s"workingList: ${env.workingList.iterator.map(_.name).toList}") + while env.workingList.nonEmpty do + val func = env.workingList.head + env.workingList.remove(func) + fFunc(func)(using env) + + private class Simplify(info: ProgInfo): + def simplify = + val newFuncs = info.func.map: + case (name, func) => + val newBody = removeTrivialCallAndJump(func.body)(using MapUtil(Map.empty)) + func.name -> func.copy(body = newBody) + info.func.clear() + info.func.addAll(newFuncs) + val reachable = ProgDfs(info).dfs(true) + log(s"reachableFuncs: ${reachable.funcs.map(showSym).toList}") + log(s"unreachableFuncs: ${info.func.keys.filterNot(reachable.funcs.contains(_)).map(showSym).toList}") + log(s"reachableClasses: ${reachable.classes.map(showSym).toList}") + log(s"unreachableClasses: ${info.classes.keys.filterNot(reachable.classes.contains(_)).map(showSym).toList}") + info.func.filterInPlace((k, _) => reachable.funcs.contains(k)) + info.classes.filterInPlace((k, _) => reachable.classes.contains(k)) + + private def removeTrivialCallAndJump(expr: Expr)(using m: MapUtil): Expr = expr match + case Expr.Ref(name) => Expr.Ref(m.subst(name)) + case Expr.Literal(lit) => expr + case Expr.CtorApp(cls, args) => Expr.CtorApp(cls, m.substT(args).toList) + case Expr.Select(name, cls, field) => Expr.Select(m.subst(name), m.subst(cls), field) + case Expr.BasicOp(name, args) => Expr.BasicOp(m.subst(name), m.substT(args).toList) + case Expr.AssignField(assignee, cls, field, value) => + Expr.AssignField(m.subst(assignee), cls, field, m.substT(value)) + + private def removeTrivialCallAndJump(node: Node)(using MapUtil): Node = node match + case Node.Result(res) => Node.Result(summon[MapUtil].substT(res).toList) + case Node.Jump(func, args) => + if notBuiltin(func) then + val funcDefn = info.getFunc(func) + val nuArgs = summon[MapUtil].substT(args).toList + val m = SubstUtil(funcDefn.params.zip(nuArgs).toMap) + funcDefn.body match + case Node.Result(res) => + Node.Result(res.map(_.foldRef(m.subst))) + case Node.Jump(func, args) => + Node.Jump(func, args.map(_.foldRef(m.subst))) + case _ => node + else + node + case Node.Case(scrutinee, cases, default) => + Node.Case(summon[MapUtil].substT(scrutinee), cases.map: + case (pat, body) => pat -> removeTrivialCallAndJump(body), + default.map(removeTrivialCallAndJump(_))) + case Node.Panic(msg) => node + case Node.LetExpr(name, expr, body) => + val nuExpr = removeTrivialCallAndJump(expr) + Node.LetExpr(name, nuExpr, removeTrivialCallAndJump(body)) + case Node.LetMethodCall(names, cls, method, args, body) => + val nuArgs = summon[MapUtil].substT(args).toList + Node.LetMethodCall(names, cls, method, nuArgs, removeTrivialCallAndJump(body)) + case Node.LetCall(names, func, args, body) => + if notBuiltin(func) then + val funcDefn = info.getFunc(func) + val nuArgs = summon[MapUtil].substT(args).toList + val m = SubstUtil(funcDefn.params.zip(nuArgs).toMap) + funcDefn.body match + case Node.Jump(func, args) => + Node.LetCall(names, func, args.map(_.foldRef(m.subst)), removeTrivialCallAndJump(body)) + case _ => node + else + node + + def run(prog: LlirProgram) = + val info = ProgInfo.fromProgram(prog) + if flags.contains("simp") then + val simp = Simplify(info) + simp.simplify + if flags.contains("!split") then + () + else + val splitting = Splitting(info) + splitting.run() + info.toProgram + + + class ProgDfs(info: ProgInfo): + import Node._ + import Expr._ + + case class FuncAndClass(funcs: Ls[Local] = Nil, classes: Ls[Local] = Nil): + def addF(func: Local): FuncAndClass = copy(funcs = func :: funcs) + def addC(cls: Local): FuncAndClass = copy(classes = cls :: classes) + + case class Buf(funcs: ListBuffer[Local] = ListBuffer.empty, classes: ListBuffer[Local] = ListBuffer.empty) + + private object Successors: + def find(expr: Expr)(using acc: FuncAndClass): FuncAndClass = + expr match + case Ref(sym) => acc + case Literal(lit) => acc + case CtorApp(cls, args) => acc.addC(cls) + case Select(name, cls, field) => acc.addC(cls) + case BasicOp(name, args) => acc + case AssignField(assignee, cls, field, value) => acc.addC(cls) + + def find(node: Node)(using acc: FuncAndClass): FuncAndClass = + node match + case Result(res) => acc + case Jump(func, args) => if notBuiltin(func) then acc.addF(func) else acc + case Case(scrutinee, cases, default) => + val acc2 = cases.map(_._2) ++ default.toList + acc2.foldLeft(acc)((acc, x) => find(x)(using acc)) + case Panic(msg) => acc + case LetExpr(name, expr, body) => + val acc2 = find(expr) + find(body)(using acc2) + case LetMethodCall(names, cls, method, args, body) => find(body)(using acc.addC(cls)) + case LetCall(names, func, args, body) => find(body)(using if notBuiltin(func) then acc.addF(func) else acc) + + def find(func: Func): FuncAndClass = find(func.body)(using FuncAndClass()) + + + + private def dfs(using visited: MutHMap[Local, Bool], out: Buf, postfix: Bool)(x: Func): Unit = + trace[Unit](s"dfs: ${{showSym(x.name)}}"): + visited.update(x.name, true) + if !postfix then + out.funcs += x.name + val successors = Successors.find(x) + successors.funcs.foreach: + y => if !visited(y) then + dfs(info.getFunc(y)) + successors.classes.foreach: y => + if notCallable(y) && !visited(y) then + dfs(info.getClass(y)) + if postfix then + out.funcs += x.name + + private def dfs(using visited: MutHMap[Local, Bool], out: Buf, postfix: Bool)(x: ClassInfo): Unit = + trace[Unit](s"dfs: ${{showSym(x.name)}}"): + visited.update(x.name, true) + if !postfix then + out.classes += x.name + x.parents.foreach: y => + if notCallable(y) && !visited(y) then + dfs(info.getClass(y)) + x.methods.values.foreach: m => + val successors = Successors.find(m.body)(using FuncAndClass()) + successors.funcs.foreach: y => + if !visited(y) then + dfs(info.getFunc(y)) + successors.classes.foreach: y => + if notCallable(y) && !visited(y) then + dfs(info.getClass(y)) + if postfix then + out.classes += x.name + + private def dfs(using visited: MutHMap[Local, Bool], out: Buf, postfix: Bool)(x: Node): Unit = + trace[Unit](s"dfs: $x"): + val successors = Successors.find(x)(using FuncAndClass()) + successors.funcs.foreach: y => + if !visited(y) then + dfs(info.getFunc(y)) + successors.classes.foreach: y => + if notCallable(y) && !visited(y) then + dfs(info.getClass(y)) + + def dfs(postfix: Bool): FuncAndClass = + val visited = MutHMap[Local, Bool]() + val allFuncsClassesMethods = info.func.keys ++ info.classes.iterator.keys + visited.addAll(allFuncsClassesMethods.map(k => k -> false)) + val out = Buf(ListBuffer.empty, ListBuffer.empty) + dfs(using visited, out, postfix)(info.func.get(info.entry).get) + FuncAndClass(out.funcs.toList, out.classes.toList) + diff --git a/hkmc2/shared/src/test/mlscript/llir/Legacy.mls b/hkmc2/shared/src/test/mlscript/llir/Legacy.mls index 5ec40b43be..912f3dbc50 100644 --- a/hkmc2/shared/src/test/mlscript/llir/Legacy.mls +++ b/hkmc2/shared/src/test/mlscript/llir/Legacy.mls @@ -1,6 +1,8 @@ :js :llir :cpp +:opt +:optf simp,!split :global @@ -223,7 +225,6 @@ main() //│ Interpreted: //│ Some(None()) -:sllir :intl abstract class Option[out T]: Some[T] | None class Some[out T](x: T) extends Option[T] @@ -253,78 +254,6 @@ fun main() = Some(b1) then bbb() main() //│ = 404 -//│ LLIR: -//│ class Option() -//│ class Some(x$1049) extends Option -//│ class None() extends Option -//│ class Nat() -//│ class S(s$1060) extends Nat -//│ class O() extends Nat -//│ def fromSome$1032(s$1052) = -//│ case s$1052 of -//│ Some$1046 => -//│ let x$1127 = s$1052. in -//│ x$1127 -//│ _ => -//│ panic "match error" -//│ def j$1126() = -//│ null -//│ def aaa$1037() = -//│ let x$1128 = 1 in -//│ let x$1129 = 2 in -//│ let x$1130 = 3 in -//│ let x$1131 = 4 in -//│ let x$1132 = +(x$1128,x$1129) in -//│ let x$1133 = -(x$1132,x$1130) in -//│ let x$1134 = +(x$1133,x$1131) in -//│ x$1134 -//│ def bbb$1039() = -//│ let* (x$1135) = aaa() in -//│ let x$1136 = *(x$1135,100) in -//│ let x$1137 = +(x$1136,4) in -//│ x$1137 -//│ def not$1035(x$1076) = -//│ case x$1076 of -//│ BoolLit(true) => -//│ false -//│ _ => -//│ true -//│ def j$1138() = -//│ null -//│ def foo$1042(x$1078) = -//│ case x$1078 of -//│ BoolLit(true) => -//│ let x$1140 = None$1050() in -//│ x$1140 -//│ _ => -//│ let* (x$1141) = not(x$1078) in -//│ let* (x$1142) = foo(x$1141) in -//│ let x$1143 = Some$1046(x$1142) in -//│ x$1143 -//│ def j$1139() = -//│ null -//│ def main$1033() = -//│ let* (x$1144) = foo(false) in -//│ case x$1144 of -//│ None$1050 => -//│ let* (x$1146) = aaa() in -//│ x$1146 -//│ _ => -//│ case x$1144 of -//│ Some$1046 => -//│ let x$1148 = x$1144. in -//│ let* (x$1149) = bbb() in -//│ x$1149 -//│ _ => -//│ panic "match error" -//│ def j$1147() = -//│ jump j$1145() -//│ def j$1145() = -//│ null -//│ def entry$1151() = -//│ let* (x$1150) = main() in -//│ x$1150 -//│ entry = entry$1151 //│ //│ Interpreted: //│ 404 @@ -550,9 +479,9 @@ fun to_nat(n) = if n == 0 then O else S(to_nat(n - 1)) fun main() = - to_int(fib(to_nat(14))) + to_int(fib(to_nat(10))) main() -//│ = 610 +//│ = 89 //│ //│ Interpreted: -//│ 610 +//│ 89 diff --git a/hkmc2/shared/src/test/mlscript/llir/nofib/atom.mls b/hkmc2/shared/src/test/mlscript/llir/nofib/atom.mls index 3d63c632af..ce7bfe3323 100644 --- a/hkmc2/shared/src/test/mlscript/llir/nofib/atom.mls +++ b/hkmc2/shared/src/test/mlscript/llir/nofib/atom.mls @@ -42,7 +42,9 @@ fun testAtom_nofib(n) = state :: t then stringConcat(show(state), "\n") :: lscomp(t) stringListConcat of lscomp(take_lz(n, runExperiment(testforce, 0.02, 1.0 :: Nil, State(1.0 :: Nil, 0.0 :: Nil)))) - +:wholeOpt +:wholeOptFlags simp,!split +:runWholeCpp :runWholeCpp testAtom_nofib(20) //│ diff --git a/hkmc2/shared/src/test/mlscript/llir/nofib/awards.mls b/hkmc2/shared/src/test/mlscript/llir/nofib/awards.mls index 9bcfe86bf9..86f3a8d494 100644 --- a/hkmc2/shared/src/test/mlscript/llir/nofib/awards.mls +++ b/hkmc2/shared/src/test/mlscript/llir/nofib/awards.mls @@ -68,6 +68,8 @@ fun competitors(i) = fun testAwards_nofib(n) = map(x => print(findallawards(competitors(intMod(x, 100)))), enumFromTo(1, n)) +:wholeOpt +:wholeOptFlags simp,!split :runWholeCpp testAwards_nofib(100) //│ diff --git a/hkmc2/shared/src/test/mlscript/llir/nofib/constraints.mls b/hkmc2/shared/src/test/mlscript/llir/nofib/constraints.mls index 4501796aee..8c188cd0dc 100644 --- a/hkmc2/shared/src/test/mlscript/llir/nofib/constraints.mls +++ b/hkmc2/shared/src/test/mlscript/llir/nofib/constraints.mls @@ -277,6 +277,8 @@ fun try_(n, algorithm) = listLen(search(algorithm, queens(n))) fun testConstraints_nofib(n) = map(x => try_(n, x), bt :: bm :: bjbt :: bjbt_ :: fc :: Nil) +:wholeOpt +:wholeOptFlags simp,!split :runWholeCpp print(testConstraints_nofib(6)) //│ diff --git a/hkmc2/shared/src/test/mlscript/llir/nofib/scc.mls b/hkmc2/shared/src/test/mlscript/llir/nofib/scc.mls index 1aa585e648..daeb5a1f43 100644 --- a/hkmc2/shared/src/test/mlscript/llir/nofib/scc.mls +++ b/hkmc2/shared/src/test/mlscript/llir/nofib/scc.mls @@ -49,6 +49,8 @@ fun testScc_nofib(d) = stronglyConnComp(edges, vertices) +:wholeOpt +:wholeOptFlags simp,!split :runWholeCpp print(testScc_nofib(0)) //│ diff --git a/hkmc2/shared/src/test/mlscript/llir/nofib/secretary.mls b/hkmc2/shared/src/test/mlscript/llir/nofib/secretary.mls index c7a2b328f7..8a36069477 100644 --- a/hkmc2/shared/src/test/mlscript/llir/nofib/secretary.mls +++ b/hkmc2/shared/src/test/mlscript/llir/nofib/secretary.mls @@ -37,6 +37,8 @@ fun testSecretary_nofib(n) = listcomp(enumFromTo(35, 39)) +:wholeOpt +:wholeOptFlags simp,!split :runWholeCpp print(testSecretary_nofib(50)) //│ diff --git a/hkmc2DiffTests/src/test/scala/hkmc2/LlirDiffMaker.scala b/hkmc2DiffTests/src/test/scala/hkmc2/LlirDiffMaker.scala index 76ec60d6d5..4fb4a1600c 100644 --- a/hkmc2DiffTests/src/test/scala/hkmc2/LlirDiffMaker.scala +++ b/hkmc2DiffTests/src/test/scala/hkmc2/LlirDiffMaker.scala @@ -36,6 +36,17 @@ abstract class LlirDiffMaker extends BbmlDiffMaker: val rWholeCpp = NullaryCommand("runWholeCpp") val wWholeCpp = Command[Str]("writeWholeCpp", false)(x => x.stripLeading()) + val dopt = NullaryCommand("dopt") + + // Optimizer commands for individual blocks + val opt = NullaryCommand("opt") + val sopt = NullaryCommand("sopt") + val optFlags = Command[Set[Str]]("optf", false)(x => x.stripLeading().split(",").toSet) + + // Optimizer commands for the whole program + val wholeOpt = NullaryCommand("wholeOpt") + val sWholeOpt = NullaryCommand("showWholeOpt") + val wholeOptFlags = Command[Set[Str]]("wholeOptFlags", false)(x => x.stripLeading().split(",").toSet) def printToFile(f: java.io.File)(op: java.io.PrintWriter => Unit) = val p = new java.io.PrintWriter(f) @@ -74,6 +85,20 @@ abstract class LlirDiffMaker extends BbmlDiffMaker: if sllir.isSet then output("LLIR:") output(llirProg.show()) + def optimize(name: String, prog: Program, opt: Bool, show: Bool, optFlags: Set[Str]): Program = + given tl: TraceLogger with + override def doTrace = dopt.isSet + override def emitDbg(str: String): Unit = output(str) + if opt || show then + tl.log(s"Optimizing $name") + val opt = codegen.llir.LlirOpt(tl, freshId, optFlags) + val optProg = opt.run(prog) + if show then + output(s"\n$name:") + output(optProg.show()) + optProg + else + prog def cppGen(name: String, prog: Program, gen: Bool, show: Bool, run: Bool, write: Opt[Str]): Unit = tl.log(s"Generating $name") if gen || show || run || write.isDefined then @@ -97,8 +122,12 @@ abstract class LlirDiffMaker extends BbmlDiffMaker: else output("\n") cppHost.compileAndRun(cpp.toDocument.toString) - cppGen("Cpp", llirProg, cpp.isSet, scpp.isSet, rcpp.isSet, wcpp.get) - cppGen("WholeProgramCpp", mkWholeProgram, wholeCpp.isSet, sWholeCpp.isSet, rWholeCpp.isSet, wWholeCpp.get) + cppGen("Cpp", + optimize("Opt", llirProg, opt.isSet, sopt.isSet, optFlags.get.getOrElse(Set.empty)), + cpp.isSet, scpp.isSet, rcpp.isSet, wcpp.get) + cppGen("WholeProgramCpp", + optimize("WholeProgramOpt", mkWholeProgram, wholeOpt.isSet, sWholeOpt.isSet, wholeOptFlags.get.getOrElse(Set.empty)), + wholeCpp.isSet, sWholeCpp.isSet, rWholeCpp.isSet, wWholeCpp.get) if intl.isSet then val intr = codegen.llir.Interpreter(tl) output("\nInterpreted:") From cfab5f0b513ffe4e8ea30ef8afb5ba72fd1ab6ee Mon Sep 17 00:00:00 2001 From: waterlens Date: Thu, 6 Mar 2025 21:30:38 +0800 Subject: [PATCH 58/88] Splitting on the fly (with bugs) --- .../main/scala/hkmc2/codegen/llir/Opt.scala | 317 ++--- .../shared/src/test/mlscript/llir/Legacy.mls | 1027 ++++++++++++++++- 2 files changed, 1190 insertions(+), 154 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Opt.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Opt.scala index a1c19861b1..77c4e4653e 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Opt.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Opt.scala @@ -55,7 +55,7 @@ final class LlirOpt(using Elaborator.State, Raise)(tl: TraceLogger, freshInt: Fr def isDestructed(node: Node) = getFirstDestructed(node).isDefined - def newFunSym(name: Str) = TermSymbol(hkmc2.syntax.Fun, None, Tree.Ident(name)) + def newFunSym(name: Str) = BlockMemberSymbol(name, Nil) def newTemp = TempSymbol(N, "x") val placeHolderSym = TempSymbol(N, "") @@ -77,8 +77,10 @@ final class LlirOpt(using Elaborator.State, Raise)(tl: TraceLogger, freshInt: Fr def substT(sym: IterableOnce[TrivialExpr]): Iterator[TrivialExpr] = sym.iterator.map(substT) case class RefEqNode(node: Node): - override def equals(that: Any) = that match - case RefEqNode(thatNode) => node eq thatNode + override def equals(that: Any) = + that match + case RefEqNode(thatNode) => + node is thatNode case _ => false override def hashCode = node.hashCode type Loc = RefEqNode @@ -466,11 +468,10 @@ final class LlirOpt(using Elaborator.State, Raise)(tl: TraceLogger, freshInt: Fr case Expr.Ref(sym) => Expr.Ref(s.subst(sym)) case Expr.Literal(lit) => expr case Expr.CtorApp(cls, args) => Expr.CtorApp(cls, s.substT(args).toList) - case Expr.Select(name, cls, field) => Expr.Select(s.subst(name), s.subst(cls), field) - case Expr.BasicOp(name, args) => Expr.BasicOp(s.subst(name), s.substT(args).toList) + case Expr.Select(name, cls, field) => Expr.Select(s.subst(name), cls, field) + case Expr.BasicOp(name, args) => Expr.BasicOp(name, s.substT(args).toList) case Expr.AssignField(assignee, cls, field, value) => Expr.AssignField(s.subst(assignee), cls, field, s.substT(value)) - def renameNode(node: Node)(using s: RenameUtil): Node = node match case Node.Result(res) => Node.Result(s.substT(res).toList) case Node.Jump(func, args) => Node.Jump(func, s.substT(args).toList) @@ -482,7 +483,7 @@ final class LlirOpt(using Elaborator.State, Raise)(tl: TraceLogger, freshInt: Fr case Node.LetExpr(name, expr, body) => val nuName = s.subst(name) val nuExpr = renameExpr(expr) - Node.LetExpr(nuName, expr, renameNode(body)) + Node.LetExpr(nuName, nuExpr, renameNode(body)) case Node.LetMethodCall(names, cls, method, args, body) => val nuNames = names.map(s.subst) Node.LetMethodCall(nuNames, cls, method, s.substT(args).toList, renameNode(body)) @@ -490,20 +491,32 @@ final class LlirOpt(using Elaborator.State, Raise)(tl: TraceLogger, freshInt: Fr val nuNames = names.map(s.subst) Node.LetCall(nuNames, func, s.substT(args).toList, renameNode(body)) + def reComposePreFunc(subst: RenameUtil, preBody: Node => Node, origParams: Ls[Local], preSym: Local, results: Ls[Local]): Func = + trace[Func](s"reComposePreFunc begin", f => s"reComposePreFunc end: $f"): + val preParams = subst.subst(origParams) + val preNode = renameNode(preBody(Node.Result(results.map(Expr.Ref(_)))))(using subst) + val preFunc = Func(freshInt.make, preSym, preParams.toList, results.length, preNode) + preFunc + + def reComposePostFunc(subst: RenameUtil, params: Ls[Local], postBody: Node, postSym: Local, resultNum: Int): Func = + trace[Func](s"reComposePostFunc begin: $params $postBody", f => s"reComposePostFunc end: $f"): + val postParams = subst.subst(params) + val postNode = renameNode(postBody)(using subst) + val postFunc = Func(freshInt.make, postSym, postParams.toList, resultNum, postNode) + postFunc + def reComposeWithArgs(sm: SplittingMode, args: Ls[TrivialExpr], returns: Opt[Ls[Local]], knownClass: Opt[Local]): ComposeResult = sm match case SplittingMode.A( PreFunc(preSym, results, PreFuncBody(preBody), orig), PostFunc(postSym, params, PostFuncBody(postBody), _), CallShape(func, nestedReturns, nestedArgs)) => - val preNode = preBody(Node.Result(results.map(Expr.Ref(_)))) - val postNode = postBody - val preFunc = Func(freshInt.make, preSym, orig.params, results.length, preNode) - val postFunc = Func(freshInt.make, postSym, params, orig.resultNum, postNode) + val preFunc = reComposePreFunc(RenameUtil(), preBody, orig.params, preSym, results) + val postFunc = reComposePostFunc(RenameUtil(), params, postBody, postSym, orig.resultNum) val k = (node: Node) => - val subst = RenameUtil() // alpha rename the nestedReturns, results, nestedArgs, and params // since they may be reused in different contexts + val subst = RenameUtil() val nuNestedReturns = subst.subst(nestedReturns.get) val nuResults = subst.subst(results) val nuNestedArgs = subst.substT(nestedArgs) @@ -514,13 +527,13 @@ final class LlirOpt(using Elaborator.State, Raise)(tl: TraceLogger, freshInt: Fr if tailJump then Node.Jump(postSym, nuParams.map(Expr.Ref(_)).toList) else - Node.LetCall(returns.get, postSym, nuParams.map(Expr.Ref(_)).toList, node))) + val nuReturns = subst.subst(returns.get) + Node.LetCall(nuReturns.toList, postSym, nuParams.map(Expr.Ref(_)).toList, renameNode(node)(using subst)))) ComposeResult(k, List(preFunc, postFunc), orig) case SplittingMode.B( PreFunc(preSym, results, PreFuncBody(preBody), orig), CallShape(func, nestedReturns, nestedArgs)) => - val preNode = preBody(Node.Result(results.map(Expr.Ref(_)))) - val preFunc = Func(freshInt.make, preSym, orig.params, results.length, preNode) + val preFunc = reComposePreFunc(RenameUtil(), preBody, orig.params, preSym, results) val k = (node: Node) => val subst = RenameUtil() // there are no nested returns since in original function it's a jump @@ -531,36 +544,41 @@ final class LlirOpt(using Elaborator.State, Raise)(tl: TraceLogger, freshInt: Fr if tailJump then Node.Jump(func, nuNestedArgs.toList) else - Node.LetCall(returns.get, func, nuNestedArgs.toList, node)) + val nuReturns = subst.subst(returns.get) + Node.LetCall(nuReturns.toList, func, nuNestedArgs.toList, renameNode(node)(using subst))) ComposeResult(k, List(preFunc), orig) case SplittingMode.C( PreFunc(preSym, results, PreFuncBody(preBody), orig), CaseShape(scrutinee, cases, default)) => - val preNode = preBody(Node.Result(results.map(Expr.Ref(_)))) - val preFunc = Func(freshInt.make, preSym, orig.params, results.length, preNode) + val preFunc = reComposePreFunc(RenameUtil(), preBody, orig.params, preSym, results) var matchedPat = none[Pat] + val allPostFunc = cases.map: case (pat, PostFunc(postSym, params, PostFuncBody(postBody), _)) => - val postNode = postBody - val postFunc = Func(freshInt.make, postSym, params, orig.resultNum, postNode) + val postFunc = reComposePostFunc(RenameUtil(), params, postBody, postSym, orig.resultNum) (pat, knownClass) match case (Pat.Class(cls), S(cls2)) if cls == cls2 => matchedPat = some(pat) case _ => - pat -> postFunc + (params, pat, postFunc) val defaultPostFunc = default.map: case PostFunc(postSym, params, PostFuncBody(postBody), _) => - val postNode = postBody - val postFunc = Func(freshInt.make, postSym, params, orig.resultNum, postNode) - postFunc - def tailNodeLetCall(postFunc: Func, node: Node) = - Node.LetCall(returns.get, postFunc.name, postFunc.params.map(Expr.Ref(_)).toList, node) - def tailNodeJump(postFunc: Func) = - Node.Jump(postFunc.name, postFunc.params.map(Expr.Ref(_)).toList) - def tailNodeChoose(postFunc: Func, node: Node) = - if returns.isEmpty then tailNodeJump(postFunc) else tailNodeLetCall(postFunc, node) + (params, reComposePostFunc(RenameUtil(), params, postBody, postSym, orig.resultNum)) + + def tailNodeLetCall(postFunc: Func, postFvs: Ls[Local], node: Node)(using subst: RenameUtil) = + // the reason for postFvs instead of postFunc.params is that the later has been renamed + // so they cannot be correctly renamed with another RenameUtil + val postArgs = subst.subst(postFvs).map(Expr.Ref(_)).toList + val subst2 = RenameUtil() + val nuReturns = subst2.subst(returns.get) + Node.LetCall(nuReturns.toList, postFunc.name, postArgs, renameNode(node)(using subst2)) + def tailNodeJump(postFunc: Func, postFvs: Ls[Local])(using subst: RenameUtil) = + val postArgs = subst.subst(postFvs).map(Expr.Ref(_)).toList + Node.Jump(postFunc.name, postArgs) + def tailNodeChoose(postFvs: Ls[Local], postFunc: Func, node: Node)(using subst: RenameUtil) = + if returns.isEmpty then tailNodeJump(postFunc, postFvs) else tailNodeLetCall(postFunc, postFvs, node) // the supplied node should be trivial, otherwise we actually duplicate stuff here val k = (node: Node) => - val subst = RenameUtil() + given subst: RenameUtil = RenameUtil() val nuResults = subst.subst(results) val nuScrutinee = subst.substT(scrutinee) val tailJump = returns.isEmpty @@ -568,85 +586,88 @@ final class LlirOpt(using Elaborator.State, Raise)(tl: TraceLogger, freshInt: Fr case (None, _) => Node.LetCall(nuResults.toList, preSym, args, Node.Case(nuScrutinee, allPostFunc.map: - case (pat, postFunc) => - pat -> tailNodeChoose(postFunc, node), - defaultPostFunc.map(postFunc => - tailNodeChoose(postFunc, node)))) + case (args, pat, postFunc) => + pat -> tailNodeChoose(args, postFunc, node), + defaultPostFunc.map((args, postFunc) => + tailNodeChoose(args, postFunc, node)))) case (Some(_), None) => // only keep the default case if there's one defaultPostFunc match case None => Node.LetCall(nuResults.toList, preSym, args, Node.Case(nuScrutinee, allPostFunc.map: - case (pat, postFunc) => - pat -> tailNodeChoose(postFunc, node), - defaultPostFunc.map(postFunc => - tailNodeChoose(postFunc, node)))) - case Some(postFunc) => + case (args, pat, postFunc) => + pat -> tailNodeChoose(args, postFunc, node), + defaultPostFunc.map((args, postFunc) => + tailNodeChoose(args, postFunc, node)))) + case Some((args2, postFunc)) => Node.LetCall(nuResults.toList, preSym, args, - tailNodeChoose(postFunc, node)) + tailNodeChoose(args2, postFunc, node)) case (Some(_), Some(matched)) => Node.LetCall(nuResults.toList, preSym, args, allPostFunc.flatMap: - case (pat, postFunc) => if pat == matched then - S(tailNodeChoose(postFunc, node)) else N + case (args, pat, postFunc) => if pat == matched then + S(tailNodeChoose(args, postFunc, node)) else N .head) - ComposeResult(k, preFunc :: allPostFunc.map(_._2) ++ defaultPostFunc.toList, orig) + ComposeResult(k, preFunc :: allPostFunc.map(_._3) ++ defaultPostFunc.map(_._2).toList, orig) def sFunc(func: Func, splitPos: Loc): SplittingMode = - sNode(func.body, splitPos, func)(identity) + trace[SplittingMode](s"sFunc: ${func.name |> showSym}, $splitPos"): + sNode(func.body, splitPos, func)(identity) - def sNode(node: Node, splitPos: Loc, thisFunc: Func)(acc: Node => Node): SplittingMode = node match - case Node.Result(res) => oErrStop("sNode: unexpected Result") - case Node.Jump(func, args) => - // B mode - val sym = newFunSym(s"${thisFunc.name.nme}_pre") - val pfBody = PreFuncBody(acc) - val fvs = FreeVarAnalysis(info.func).run(node) - val results = fvs.toList - val pf = PreFunc(sym, results, pfBody, thisFunc) - val cs = CallShape(func, none, args) - SplittingMode.B(pf, cs) - case Node.Case(scrutinee, cases, default) => - // C mode - val sym = newFunSym(s"${thisFunc.name.nme}_pre") - val pfBody = PreFuncBody(acc) - val fvs = FreeVarAnalysis(info.func).run(node) - val results = fvs.toList - val pf = PreFunc(sym, results, pfBody, thisFunc) - val cases2 = cases.zipWithIndex.map: - case ((pat, body), i) => - val sym = newFunSym(s"${thisFunc.name.nme}_case$i") - val fvs = FreeVarAnalysis(info.func).run(node) - val pfBody = PostFuncBody(body) - val pf = PostFunc(sym, fvs.toList, pfBody, thisFunc) - (pat, pf) - val default2 = default.map: node => - val sym = newFunSym(s"${thisFunc.name.nme}_default") - val fvs = FreeVarAnalysis(info.func).run(node) - val pfBody = PostFuncBody(node) - val pf = PostFunc(sym, fvs.toList, pfBody, thisFunc) - pf - val caseS = CaseShape(scrutinee, cases2, default2) - SplittingMode.C(pf, caseS) - case Node.Panic(msg) => oErrStop("sNode: unexpected Panic") - case Node.LetExpr(name, expr, body) => - sNode(body, splitPos, thisFunc)(x => Node.LetExpr(name, expr, x)) - case Node.LetMethodCall(names, cls, method, args, body) => - sNode(body, splitPos, thisFunc)(x => Node.LetMethodCall(names, cls, method, args, x)) - case Node.LetCall(names, func, args, body) => - if splitPos == RefEqNode(node) then - // A mode + def sNode(node: Node, splitPos: Loc, thisFunc: Func)(acc: Node => Node): SplittingMode = + trace[SplittingMode](s"sNode: $node"): + node match + case Node.Result(res) => oErrStop("sNode: unexpected Result") + case Node.Jump(func, args) => + // B mode val sym = newFunSym(s"${thisFunc.name.nme}_pre") val pfBody = PreFuncBody(acc) val fvs = FreeVarAnalysis(info.func).run(node) val results = fvs.toList val pf = PreFunc(sym, results, pfBody, thisFunc) - val cs = CallShape(func, some(names), args) - SplittingMode.A(pf, PostFunc(func, names, PostFuncBody(body), thisFunc), cs) - else - sNode(body, splitPos, thisFunc)(x => Node.LetCall(names, func, args, x)) + val cs = CallShape(func, none, args) + SplittingMode.B(pf, cs) + case Node.Case(scrutinee, cases, default) => + // C mode + val sym = newFunSym(s"${thisFunc.name.nme}_pre") + val pfBody = PreFuncBody(acc) + val fvs = FreeVarAnalysis(info.func).run(node) + val results = fvs.toList + val pf = PreFunc(sym, results, pfBody, thisFunc) + val cases2 = cases.zipWithIndex.map: + case ((pat, body), i) => + val sym = newFunSym(s"${thisFunc.name.nme}_case$i") + val fvs = FreeVarAnalysis(info.func).run(node) + val pfBody = PostFuncBody(body) + val pf = PostFunc(sym, fvs.toList, pfBody, thisFunc) + (pat, pf) + val default2 = default.map: node => + val sym = newFunSym(s"${thisFunc.name.nme}_default") + val fvs = FreeVarAnalysis(info.func).run(node) + val pfBody = PostFuncBody(node) + val pf = PostFunc(sym, fvs.toList, pfBody, thisFunc) + pf + val caseS = CaseShape(scrutinee, cases2, default2) + SplittingMode.C(pf, caseS) + case Node.Panic(msg) => oErrStop("sNode: unexpected Panic") + case Node.LetExpr(name, expr, body) => + sNode(body, splitPos, thisFunc)(x => Node.LetExpr(name, expr, x)) + case Node.LetMethodCall(names, cls, method, args, body) => + sNode(body, splitPos, thisFunc)(x => Node.LetMethodCall(names, cls, method, args, x)) + case Node.LetCall(names, func, args, body) => + if splitPos == RefEqNode(node) then + // A mode + val sym = newFunSym(s"${thisFunc.name.nme}_pre") + val pfBody = PreFuncBody(acc) + val fvs = FreeVarAnalysis(info.func).run(node) + val results = fvs.toList + val pf = PreFunc(sym, results, pfBody, thisFunc) + val cs = CallShape(func, some(names), args) + SplittingMode.A(pf, PostFunc(func, names, PostFuncBody(body), thisFunc), cs) + else + sNode(body, splitPos, thisFunc)(x => Node.LetCall(names, func, args, x)) // yet another thing is to avoid duplication. once we split a function // the sub-components of the function will be wrapped into a new function @@ -678,69 +699,74 @@ final class LlirOpt(using Elaborator.State, Raise)(tl: TraceLogger, freshInt: Fr info.func.update(sym, nuFunc) Node.Jump(sym, fvs.map(Expr.Ref(_))) - def fNode(node: Node)(k: Node => Env ?=> Node)(using env: Env, thisFunc: Func): Node = node match - case Node.Result(res) => k(node) - case Node.Jump(func, args) => - val sDesc = checkSTarget(info.getFunc(func), args) - (sDesc.argumentsDesc.isEmpty, sDesc.mixingProducer.isEmpty) match - case (true, _) => k(node) - case (false, _) => - val desc = sDesc.argumentsDesc.head - val (sym, SymDDesc(knownC, isInd, e)) = desc - val old = info.getFunc(func) - val sm = sFunc(info.getFunc(func), e.loc) - rFunc(old, sm) - val cr = reComposeWithArgs(sm, args, N, N) - val nuBody = cr.k(Node.Panic("placeholder here")) - k(nuBody) - case Node.Case(scrutinee, cases, default) => - symAndIntroOfTExpr(scrutinee) match - // case Some((scrutinee, I(loc, IInfo.Mixed(i)))) => - // ??? - case _ => - val nuCases = cases.map: - case (p @ Pat.Class(cls), body) => - val old = env.i.intros.put(cls, I(node, IInfo.Ctor(cls))) - val nuBody = fNode(body)(identity) - for i <- old do env.i.intros.update(cls, i) - (p, nuBody) - case (p @ Pat.Lit(lit), body) => - (p, fNode(body)(identity)) - val dfltCase = default.map(fNode(_)(identity)) - k(Node.Case(scrutinee, nuCases, dfltCase)) - case Node.Panic(msg) => node - case Node.LetExpr(name, expr, body) => - fNode(body): inner => - k(Node.LetExpr(name, expr, inner)) - case Node.LetMethodCall(names, cls, method, args, body) => - fNode(body): inner => - k(Node.LetMethodCall(names, cls, method, args, inner)) - case node @ Node.LetCall(names, func, args, body) => - if notBuiltin(func) then + def fNode(node: Node)(k: Node => Env ?=> Node)(using env: Env, thisFunc: Func): Node = + trace[Node](s"split fNode: $node"): + node match + case Node.Result(res) => k(node) + case Node.Jump(func, args) => val sDesc = checkSTarget(info.getFunc(func), args) (sDesc.argumentsDesc.isEmpty, sDesc.mixingProducer.isEmpty) match - case (true, _) => - memoCall(node)(k) - fNode(body): inner => - k(Node.LetCall(names, func, args, inner)) + case (true, _) => k(node) case (false, _) => val desc = sDesc.argumentsDesc.head val (sym, SymDDesc(knownC, isInd, e)) = desc val old = info.getFunc(func) + log(s"splitting: ${old.name |> showSym}") val sm = sFunc(info.getFunc(func), e.loc) rFunc(old, sm) - val cr = reComposeWithArgs(sm, args, S(names), N) - val tail = wrapPost(body) - val nuBody = cr.k(tail) + val cr = reComposeWithArgs(sm, args, N, N) + val nuBody = cr.k(Node.Panic("placeholder here")) k(nuBody) - // case (_, false) => ??? - else + case Node.Case(scrutinee, cases, default) => + symAndIntroOfTExpr(scrutinee) match + // case Some((scrutinee, I(loc, IInfo.Mixed(i)))) => + // ??? + case _ => + val nuCases = cases.map: + case (p @ Pat.Class(cls), body) => + val old = env.i.intros.put(cls, I(node, IInfo.Ctor(cls))) + val nuBody = fNode(body)(identity) + for i <- old do env.i.intros.update(cls, i) + (p, nuBody) + case (p @ Pat.Lit(lit), body) => + (p, fNode(body)(identity)) + val dfltCase = default.map(fNode(_)(identity)) + k(Node.Case(scrutinee, nuCases, dfltCase)) + case Node.Panic(msg) => node + case Node.LetExpr(name, expr, body) => + fNode(body): inner => + k(Node.LetExpr(name, expr, inner)) + case Node.LetMethodCall(names, cls, method, args, body) => fNode(body): inner => - k(Node.LetCall(names, func, args, inner)) + k(Node.LetMethodCall(names, cls, method, args, inner)) + case node @ Node.LetCall(names, func, args, body) => + if notBuiltin(func) then + val sDesc = checkSTarget(info.getFunc(func), args) + (sDesc.argumentsDesc.isEmpty, sDesc.mixingProducer.isEmpty) match + case (true, _) => + memoCall(node)(k) + fNode(body): inner => + k(Node.LetCall(names, func, args, inner)) + case (false, _) => + val desc = sDesc.argumentsDesc.head + val (sym, SymDDesc(knownC, isInd, e)) = desc + val old = info.getFunc(func) + log(s"splitting: ${old.name |> showSym}") + val sm = sFunc(info.getFunc(func), e.loc) + rFunc(old, sm) + val cr = reComposeWithArgs(sm, args, S(names), N) + val tail = wrapPost(body) + val nuBody = cr.k(tail) + k(nuBody) + // case (_, false) => ??? + else + fNode(body): inner => + k(Node.LetCall(names, func, args, inner)) def fFunc(func: Func)(using env: Env): Unit = - val nuFunc = Func(func.id, func.name, func.params, func.resultNum, fNode(func.body)(identity)(using env, func)) - info.func.update(func.name, nuFunc) + trace[Unit](s"split fFunc: ${func.name |> showSym}"): + val nuFunc = Func(func.id, func.name, func.params, func.resultNum, fNode(func.body)(identity)(using env, func)) + info.func.update(func.name, nuFunc) def run() = val i = IntroductionAnalysis(info) @@ -775,8 +801,8 @@ final class LlirOpt(using Elaborator.State, Raise)(tl: TraceLogger, freshInt: Fr case Expr.Ref(name) => Expr.Ref(m.subst(name)) case Expr.Literal(lit) => expr case Expr.CtorApp(cls, args) => Expr.CtorApp(cls, m.substT(args).toList) - case Expr.Select(name, cls, field) => Expr.Select(m.subst(name), m.subst(cls), field) - case Expr.BasicOp(name, args) => Expr.BasicOp(m.subst(name), m.substT(args).toList) + case Expr.Select(name, cls, field) => Expr.Select(m.subst(name), cls, field) + case Expr.BasicOp(name, args) => Expr.BasicOp(name, m.substT(args).toList) case Expr.AssignField(assignee, cls, field, value) => Expr.AssignField(m.subst(assignee), cls, field, m.substT(value)) @@ -828,6 +854,9 @@ final class LlirOpt(using Elaborator.State, Raise)(tl: TraceLogger, freshInt: Fr else val splitting = Splitting(info) splitting.run() + if flags.contains("simp2") then + val simp = Simplify(info) + simp.simplify info.toProgram @@ -867,8 +896,6 @@ final class LlirOpt(using Elaborator.State, Raise)(tl: TraceLogger, freshInt: Fr def find(func: Func): FuncAndClass = find(func.body)(using FuncAndClass()) - - private def dfs(using visited: MutHMap[Local, Bool], out: Buf, postfix: Bool)(x: Func): Unit = trace[Unit](s"dfs: ${{showSym(x.name)}}"): visited.update(x.name, true) diff --git a/hkmc2/shared/src/test/mlscript/llir/Legacy.mls b/hkmc2/shared/src/test/mlscript/llir/Legacy.mls index 912f3dbc50..13148b33b7 100644 --- a/hkmc2/shared/src/test/mlscript/llir/Legacy.mls +++ b/hkmc2/shared/src/test/mlscript/llir/Legacy.mls @@ -1,9 +1,15 @@ :js :llir :cpp -:opt -:optf simp,!split +:sopt +:optf simp,simp2 +//│ +//│ Opt: +//│ +//│ def entry$218() = +//│ undefined +//│ entry = entry$218 :global :intl @@ -15,6 +21,22 @@ fun foo() = foo() //│ = Pair(1, 2) //│ +//│ Opt: +//│ class Pair(x$228,y$229) +//│ def mktup2$222(x$230,y$231) = +//│ let* (x$251) = mktup(x$230,y$231) in +//│ x$251 +//│ def mktup$220(x$234,y$235) = +//│ let x$252 = Pair$224(x$234,y$235) in +//│ x$252 +//│ def foo$221() = +//│ let* (x$253) = mktup2(1,2) in +//│ x$253 +//│ def entry$255() = +//│ let* (x$254) = foo() in +//│ x$254 +//│ entry = entry$255 +//│ //│ Interpreted: //│ Pair(1,2) @@ -28,6 +50,34 @@ fun bar() = bar() //│ = Pair(1, 2) //│ +//│ Opt: +//│ class Pair(x$264,y$265) +//│ def bar$257() = +//│ let x$295 = Pair$260(1,2) in +//│ let* (x$317) = foo_pre(x$295) in +//│ case x$317 of +//│ Pair$260 => +//│ let* (x$318) = foo_case0(x$317) in +//│ jump bar_post$315(x$318) +//│ _ => +//│ let* (x$319) = foo_default() in +//│ jump bar_post$315(x$319) +//│ def entry$298() = +//│ let* (x$297) = bar() in +//│ x$297 +//│ def foo_pre$300(x$304) = +//│ x$304 +//│ def foo_case0$301(x$306) = +//│ let x$305 = x$306. in +//│ let x$307 = x$306. in +//│ let x$308 = Pair$260(x$305,x$307) in +//│ x$308 +//│ def foo_default$302() = +//│ panic "match error" +//│ def bar_post$315(x$316) = +//│ x$316 +//│ entry = entry$298 +//│ //│ Interpreted: //│ Pair(1,2) @@ -41,6 +91,34 @@ fun bar() = bar() //│ = Pair(1, 2) //│ +//│ Opt: +//│ class Pair(x$327,y$328) +//│ def bar$320() = +//│ let x$358 = Pair$323(1,2) in +//│ let* (x$380) = foo_pre(x$358) in +//│ case x$380 of +//│ Pair$323 => +//│ let* (x$381) = foo_case0(x$380) in +//│ jump bar_post$378(x$381) +//│ _ => +//│ let* (x$382) = foo_default() in +//│ jump bar_post$378(x$382) +//│ def entry$361() = +//│ let* (x$360) = bar() in +//│ x$360 +//│ def foo_pre$363(x$367) = +//│ x$367 +//│ def foo_case0$364(x$369) = +//│ let x$368 = x$369. in +//│ let x$370 = x$369. in +//│ let x$371 = Pair$323(x$368,x$370) in +//│ x$371 +//│ def foo_default$365() = +//│ panic "match error" +//│ def bar_post$378(x$379) = +//│ x$379 +//│ entry = entry$361 +//│ //│ Interpreted: //│ Pair(1,2) @@ -60,10 +138,47 @@ fun foo() = foo() //│ = 2 //│ +//│ Opt: +//│ class Pair(x$390,y$391) +//│ def j$431(tmp$424) = +//│ let x$438 = +(tmp$424,1) in +//│ x$438 +//│ def foo$384() = +//│ let x$439 = Pair$386(0,1) in +//│ let* (x$467) = silly_pre(x$439) in +//│ case x$467 of +//│ Pair$386 => +//│ let* (x$468) = silly_case0(x$467) in +//│ jump foo_post$465(x$468) +//│ _ => +//│ let* (x$469) = silly_default() in +//│ jump foo_post$465(x$469) +//│ def entry$442() = +//│ let* (x$441) = foo() in +//│ x$441 +//│ def silly_pre$444(x$449) = +//│ let x$448 = 0 in +//│ x$449 +//│ def silly_case0$445(x$451) = +//│ let x$450 = x$451. in +//│ let x$452 = x$451. in +//│ case x$451 of +//│ Pair$386 => +//│ let x$453 = x$451. in +//│ let x$454 = x$451. in +//│ let x$455 = +(x$453,1) in +//│ jump j$431(x$455) +//│ _ => +//│ panic "match error" +//│ def silly_default$446() = +//│ panic "match error" +//│ def foo_post$465(x$466) = +//│ x$466 +//│ entry = entry$442 +//│ //│ Interpreted: //│ 2 - :intl class Pair[A, B](x: A, y: B) fun inc_fst(pair) = @@ -77,6 +192,35 @@ fun foo() = foo() //│ = 2 //│ +//│ Opt: +//│ class Pair(x$477,y$478) +//│ def foo$471() = +//│ let x$512 = Pair$473(0,1) in +//│ let* (x$539,x$540) = inc_fst_pre(x$512) in +//│ case x$539 of +//│ Pair$473 => +//│ let* (x$541) = inc_fst_case0(x$539,x$540) in +//│ jump foo_post$537(x$541) +//│ _ => +//│ let* (x$542) = inc_fst_default() in +//│ jump foo_post$537(x$542) +//│ def entry$515() = +//│ let* (x$514) = foo() in +//│ x$514 +//│ def inc_fst_pre$517(x$522) = +//│ let x$521 = 2 in +//│ x$522,x$521 +//│ def inc_fst_case0$518(x$524,x$527) = +//│ let x$523 = x$524. in +//│ let x$525 = x$524. in +//│ let x$526 = +(x$523,x$527) in +//│ x$526 +//│ def inc_fst_default$519() = +//│ panic "match error" +//│ def foo_post$537(x$538) = +//│ x$538 +//│ entry = entry$515 +//│ //│ Interpreted: //│ 2 @@ -92,6 +236,35 @@ fun foo() = foo() //│ = 2 //│ +//│ Opt: +//│ class Pair(x$550,y$551) +//│ def foo$544() = +//│ let x$584 = Pair$546(0,1) in +//│ let* (x$608) = inc_fst_pre(x$584) in +//│ case x$608 of +//│ Pair$546 => +//│ let* (x$609) = inc_fst_case0(x$608) in +//│ jump foo_post$606(x$609) +//│ _ => +//│ let* (x$610) = inc_fst_default() in +//│ jump foo_post$606(x$610) +//│ def entry$587() = +//│ let* (x$586) = foo() in +//│ x$586 +//│ def inc_fst_pre$589(x$594) = +//│ let x$593 = 0 in +//│ x$594 +//│ def inc_fst_case0$590(x$596) = +//│ let x$595 = x$596. in +//│ let x$597 = x$596. in +//│ let x$598 = +(x$597,1) in +//│ x$598 +//│ def inc_fst_default$591() = +//│ panic "match error" +//│ def foo_post$606(x$607) = +//│ x$607 +//│ entry = entry$587 +//│ //│ Interpreted: //│ 2 @@ -111,6 +284,54 @@ fun bar() = bar() //│ = 2 //│ +//│ Opt: +//│ class Either() +//│ class Left(x$624) extends Either +//│ class Right(y$629) extends Either +//│ def j$669(tmp$663) = +//│ case tmp$663 of +//│ Left$620 => +//│ let x$677 = tmp$663. in +//│ x$677 +//│ _ => +//│ case tmp$663 of +//│ Right$625 => +//│ let x$679 = tmp$663. in +//│ x$679 +//│ _ => +//│ panic "match error" +//│ def bar$613() = +//│ let x$680 = Right$625(2) in +//│ let* (x$714) = foo_pre(x$680,2) in +//│ case x$714 of +//│ Left$620 => +//│ let* (x$715) = foo_case0(x$714) in +//│ jump bar_post$712(x$715) +//│ _ => +//│ let* (x$717) = foo_default(x$714,x$716) in +//│ jump bar_post$712(x$717) +//│ def entry$683() = +//│ let* (x$682) = bar() in +//│ x$682 +//│ def foo_pre$685(x$690,x$691) = +//│ x$690 +//│ def foo_case0$686(x$693) = +//│ let x$692 = x$693. in +//│ let x$694 = +(x$692,1) in +//│ let x$695 = Left$620(x$694) in +//│ jump j$669(x$695) +//│ def foo_default$687(x$696,x$699) = +//│ case x$696 of +//│ Right$625 => +//│ let x$697 = x$696. in +//│ let x$698 = Right$625(x$699) in +//│ jump j$669(x$698) +//│ _ => +//│ panic "match error" +//│ def bar_post$712(x$713) = +//│ x$713 +//│ entry = entry$683 +//│ //│ Interpreted: //│ 2 @@ -129,6 +350,28 @@ fun baz(x) = foo() //│ = O //│ +//│ Opt: +//│ class Nat() +//│ class S(s$728) extends Nat +//│ class O() extends Nat +//│ def foo$723() = +//│ let x$756 = O$729() in +//│ let x$757 = S$726(x$756) in +//│ let* (x$776) = bar_pre(x$757) in +//│ let* (x$777) = baz(x$776) in +//│ let* (x$778) = baz(x$777) in +//│ jump foo_post$774(x$778) +//│ def entry$764() = +//│ let* (x$763) = foo() in +//│ x$763 +//│ def bar_pre$766(x$768) = +//│ x$768 +//│ def baz$720(x$769) = +//│ x$769 +//│ def foo_post$774(x$775) = +//│ x$775 +//│ entry = entry$764 +//│ //│ Interpreted: //│ O() @@ -150,6 +393,74 @@ fun bar() = bar() //│ = 3 //│ +//│ Opt: +//│ class A(x$785,y$786,z$787) +//│ class B(m$790,n$791) +//│ def complex_foo$782(x$892) = +//│ let* (x$904) = complex_foo_pre(x$892) in +//│ case x$904 of +//│ A$783 => +//│ jump complex_foo_case0$890(x$904) +//│ _ => +//│ jump complex_foo_default$891(x$904) +//│ def j$861(tmp$849) = +//│ let x$871 = B$788(1,2) in +//│ case x$871 of +//│ A$783 => +//│ let x$873 = x$871. in +//│ let x$874 = x$871. in +//│ let x$875 = x$871. in +//│ let x$876 = 3 in +//│ jump j$872(x$876,tmp$849) +//│ _ => +//│ case x$871 of +//│ B$788 => +//│ let x$878 = x$871. in +//│ let x$879 = x$871. in +//│ let x$880 = 4 in +//│ jump j$872(x$880,tmp$849) +//│ _ => +//│ panic "match error" +//│ def j$872(tmp$852,r$793) = +//│ let x$881 = +(r$793,tmp$852) in +//│ x$881 +//│ def bar$781() = +//│ let x$882 = A$783(6,7,8) in +//│ let* (x$919) = complex_foo_pre(x$882) in +//│ case x$919 of +//│ A$783 => +//│ let* (x$920) = complex_foo_case0(x$919) in +//│ jump bar_post$916() +//│ _ => +//│ let* (x$921) = complex_foo_default(x$919) in +//│ jump bar_post$916() +//│ def entry$887() = +//│ let* (x$886) = bar() in +//│ x$886 +//│ def complex_foo_pre$889(x$893) = +//│ x$893 +//│ def complex_foo_case0$890(x$895) = +//│ let x$894 = x$895. in +//│ let x$896 = x$895. in +//│ let x$897 = x$895. in +//│ let x$898 = *(x$896,x$897) in +//│ let x$899 = +(x$894,x$898) in +//│ jump j$861(x$899) +//│ def complex_foo_default$891(x$900) = +//│ case x$900 of +//│ B$788 => +//│ let x$901 = x$900. in +//│ let x$902 = x$900. in +//│ let x$903 = -(x$901,x$902) in +//│ jump j$861(x$903) +//│ _ => +//│ panic "match error" +//│ def bar_post$916() = +//│ let x$917 = B$788(9,10) in +//│ let* (x$918) = complex_foo(x$917) in +//│ x$918 +//│ entry = entry$887 +//│ //│ Interpreted: //│ 3 @@ -188,6 +499,140 @@ fun bar() = bar() //│ = 5 //│ +//│ Opt: +//│ class A(w$929,x$930) +//│ class B(y$933) +//│ class C(z$936) +//│ def j$1053(x$1108,x$1109,x$1110) = +//│ let* (x$1137,x$1138,x$1139,x$1140,x$1141) = j_pre(x$1108,x$1109,x$1110) in +//│ case x$1137 of +//│ A$927 => +//│ jump j_case0$1106(x$1137,x$1138,x$1139,x$1140,x$1141) +//│ _ => +//│ jump j_default$1107(x$1137,x$1138,x$1139) +//│ def j$1065(tmp$1042,z$954,v$956) = +//│ case z$954 of +//│ A$927 => +//│ let x$1085 = z$954. in +//│ let x$1086 = z$954. in +//│ x$1085 +//│ _ => +//│ case z$954 of +//│ B$931 => +//│ let x$1088 = z$954. in +//│ 4 +//│ _ => +//│ case z$954 of +//│ C$934 => +//│ let x$1090 = z$954. in +//│ case v$956 of +//│ A$927 => +//│ let x$1092 = v$956. in +//│ let x$1093 = v$956. in +//│ x$1092 +//│ _ => +//│ case v$956 of +//│ B$931 => +//│ let x$1095 = v$956. in +//│ 7 +//│ _ => +//│ case v$956 of +//│ C$934 => +//│ let x$1097 = v$956. in +//│ 8 +//│ _ => +//│ panic "match error" +//│ _ => +//│ panic "match error" +//│ def bar$925() = +//│ let x$1098 = B$931(10) in +//│ let x$1099 = A$927(9,x$1098) in +//│ let x$1100 = A$927(10,x$1099) in +//│ let* (x$1246,x$1247,x$1248) = complex_foo_pre(x$1100) in +//│ case x$1246 of +//│ A$927 => +//│ let* (x$1249) = complex_foo_case0(x$1246,x$1247,x$1248) in +//│ jump bar_post$1244(x$1249) +//│ _ => +//│ let* (x$1250) = complex_foo_default(x$1246,x$1248,x$1247) in +//│ jump bar_post$1244(x$1250) +//│ def entry$1103() = +//│ let* (x$1102) = bar() in +//│ x$1102 +//│ def j_pre$1105(x$1112,x$1114,x$1115) = +//│ let x$1111 = B$931(6) in +//│ x$1112,x$1113,x$1111,x$1114,x$1115 +//│ def j_case0$1106(x$1117,x$1125,x$1126,x$1120,x$1122) = +//│ let x$1116 = x$1117. in +//│ let x$1118 = x$1117. in +//│ let x$1119 = +(x$1116,x$1120) in +//│ let x$1121 = +(x$1119,x$1122) in +//│ case x$1118 of +//│ A$927 => +//│ let x$1123 = x$1118. in +//│ let x$1124 = x$1118. in +//│ jump j$1065(x$1123,x$1125,x$1126) +//│ _ => +//│ case x$1118 of +//│ B$931 => +//│ let x$1127 = x$1118. in +//│ jump j$1065(x$1121,x$1125,x$1126) +//│ _ => +//│ case x$1118 of +//│ C$934 => +//│ let x$1128 = x$1118. in +//│ let x$1129 = 0 in +//│ jump j$1065(x$1129,x$1125,x$1126) +//│ _ => +//│ panic "match error" +//│ def j_default$1107(x$1130,x$1133,x$1134) = +//│ case x$1130 of +//│ B$931 => +//│ let x$1131 = x$1130. in +//│ let x$1132 = 2 in +//│ jump j$1065(x$1132,x$1133,x$1134) +//│ _ => +//│ case x$1130 of +//│ C$934 => +//│ let x$1135 = x$1130. in +//│ let x$1136 = 3 in +//│ jump j$1065(x$1136,x$1133,x$1134) +//│ _ => +//│ panic "match error" +//│ def j_pre$1173(x$1177,x$1178,x$1179) = +//│ x$1177,x$1178,x$1179 +//│ def complex_foo_pre$1189(x$1194) = +//│ let x$1193 = *(1,2) in +//│ x$1194,x$1195,x$1193 +//│ def complex_foo_case0$1190(x$1197,x$1199,x$1200) = +//│ let x$1196 = x$1197. in +//│ let x$1198 = x$1197. in +//│ jump j$1053(x$1198,x$1199,x$1200) +//│ def complex_foo_default$1191(x$1201,x$1204,x$1211) = +//│ case x$1201 of +//│ B$931 => +//│ let x$1202 = x$1201. in +//│ let x$1203 = +(x$1202,x$1204) in +//│ let x$1205 = B$931(x$1203) in +//│ let* (x$1206,x$1207,x$1208,x$1209,x$1210) = j_pre(x$1205,x$1211,x$1204) in +//│ case x$1206 of +//│ A$927 => +//│ jump j_case0$1106(x$1206,x$1207,x$1208,x$1209,x$1210) +//│ _ => +//│ jump j_default$1107(x$1206,x$1207,x$1208) +//│ _ => +//│ case x$1201 of +//│ C$934 => +//│ let x$1212 = x$1201. in +//│ let x$1213 = C$934(0) in +//│ let* (x$1214,x$1215,x$1216) = j_pre(x$1213,x$1211,x$1204) in +//│ jump j$1053(x$1214,x$1215,x$1216) +//│ _ => +//│ panic "match error" +//│ def bar_post$1244(x$1245) = +//│ x$1245 +//│ entry = entry$1103 +//│ //│ Interpreted: //│ 5 @@ -196,6 +641,25 @@ fun fib(n) = if n < 2 then n else fib(n-1) + fib(n-2) fib(20) //│ = 6765 //│ +//│ Opt: +//│ +//│ def fib$1251(n$1252) = +//│ let x$1278 = <(n$1252,2) in +//│ case x$1278 of +//│ BoolLit(true) => +//│ n$1252 +//│ _ => +//│ let x$1280 = -(n$1252,1) in +//│ let* (x$1281) = fib(x$1280) in +//│ let x$1282 = -(n$1252,2) in +//│ let* (x$1283) = fib(x$1282) in +//│ let x$1284 = +(x$1281,x$1283) in +//│ x$1284 +//│ def entry$1286() = +//│ let* (x$1285) = fib(20) in +//│ x$1285 +//│ entry = entry$1286 +//│ //│ Interpreted: //│ 6765 @@ -206,6 +670,34 @@ fun foo() = odd(10) foo() //│ = false //│ +//│ Opt: +//│ +//│ def odd$1290(x$1291) = +//│ let x$1320 = ==(x$1291,0) in +//│ case x$1320 of +//│ BoolLit(true) => +//│ false +//│ _ => +//│ let x$1322 = -(x$1291,1) in +//│ let* (x$1323) = even(x$1322) in +//│ x$1323 +//│ def even$1288(x$1297) = +//│ let x$1324 = ==(x$1297,0) in +//│ case x$1324 of +//│ BoolLit(true) => +//│ true +//│ _ => +//│ let x$1326 = -(x$1297,1) in +//│ let* (x$1327) = odd(x$1326) in +//│ x$1327 +//│ def foo$1289() = +//│ let* (x$1328) = odd(10) in +//│ x$1328 +//│ def entry$1330() = +//│ let* (x$1329) = foo() in +//│ x$1329 +//│ entry = entry$1330 +//│ //│ Interpreted: //│ false @@ -222,6 +714,34 @@ fun main() = foo(false) main() //│ = Some(None) //│ +//│ Opt: +//│ class Option() +//│ class Some(x$1344) extends Option +//│ class None() extends Option +//│ def not$1334(x$1347) = +//│ case x$1347 of +//│ BoolLit(true) => +//│ false +//│ _ => +//│ true +//│ def foo$1337(x$1349) = +//│ case x$1349 of +//│ BoolLit(true) => +//│ let x$1376 = None$1345() in +//│ x$1376 +//│ _ => +//│ let* (x$1377) = not(x$1349) in +//│ let* (x$1378) = foo(x$1377) in +//│ let x$1379 = Some$1341(x$1378) in +//│ x$1379 +//│ def main$1332() = +//│ let* (x$1380) = foo(false) in +//│ x$1380 +//│ def entry$1382() = +//│ let* (x$1381) = main() in +//│ x$1381 +//│ entry = entry$1382 +//│ //│ Interpreted: //│ Some(None()) @@ -255,6 +775,59 @@ fun main() = main() //│ = 404 //│ +//│ Opt: +//│ class Option() +//│ class Some(x$1402) extends Option +//│ class None() extends Option +//│ def aaa$1390() = +//│ let x$1481 = 1 in +//│ let x$1482 = 2 in +//│ let x$1483 = 3 in +//│ let x$1484 = 4 in +//│ let x$1485 = +(x$1481,x$1482) in +//│ let x$1486 = -(x$1485,x$1483) in +//│ let x$1487 = +(x$1486,x$1484) in +//│ x$1487 +//│ def bbb$1392() = +//│ let* (x$1488) = aaa() in +//│ let x$1489 = *(x$1488,100) in +//│ let x$1490 = +(x$1489,4) in +//│ x$1490 +//│ def not$1388(x$1429) = +//│ case x$1429 of +//│ BoolLit(true) => +//│ false +//│ _ => +//│ true +//│ def foo$1395(x$1431) = +//│ case x$1431 of +//│ BoolLit(true) => +//│ let x$1493 = None$1403() in +//│ x$1493 +//│ _ => +//│ let* (x$1494) = not(x$1431) in +//│ let* (x$1495) = foo(x$1494) in +//│ let x$1496 = Some$1399(x$1495) in +//│ x$1496 +//│ def main$1386() = +//│ let* (x$1497) = foo(false) in +//│ case x$1497 of +//│ None$1403 => +//│ let* (x$1499) = aaa() in +//│ x$1499 +//│ _ => +//│ case x$1497 of +//│ Some$1399 => +//│ let x$1501 = x$1497. in +//│ let* (x$1502) = bbb() in +//│ x$1502 +//│ _ => +//│ panic "match error" +//│ def entry$1504() = +//│ let* (x$1503) = main() in +//│ x$1503 +//│ entry = entry$1504 +//│ //│ Interpreted: //│ 404 @@ -274,6 +847,61 @@ fun foo() = odd(S(S(S(O)))) foo() //│ = true //│ +//│ Opt: +//│ class Nat() +//│ class S(s$1516) extends Nat +//│ class O() extends Nat +//│ def odd$1507(x$1578) = +//│ let* (x$1584) = odd_pre(x$1578) in +//│ case x$1584 of +//│ O$1517 => +//│ jump odd_case0$1576(x$1584) +//│ _ => +//│ jump odd_default$1577(x$1584) +//│ def even$1508(x$1524) = +//│ case x$1524 of +//│ O$1517 => +//│ true +//│ _ => +//│ case x$1524 of +//│ S$1514 => +//│ let x$1565 = x$1524. in +//│ let* (x$1566) = odd(x$1565) in +//│ x$1566 +//│ _ => +//│ panic "match error" +//│ def foo$1511() = +//│ let x$1567 = O$1517() in +//│ let x$1568 = S$1514(x$1567) in +//│ let x$1569 = S$1514(x$1568) in +//│ let x$1570 = S$1514(x$1569) in +//│ let* (x$1592) = odd_pre(x$1570) in +//│ case x$1592 of +//│ O$1517 => +//│ let* (x$1593) = odd_case0(x$1592) in +//│ jump foo_post$1590(x$1593) +//│ _ => +//│ let* (x$1594) = odd_default(x$1592) in +//│ jump foo_post$1590(x$1594) +//│ def entry$1573() = +//│ let* (x$1572) = foo() in +//│ x$1572 +//│ def odd_pre$1575(x$1579) = +//│ x$1579 +//│ def odd_case0$1576(x$1580) = +//│ false +//│ def odd_default$1577(x$1581) = +//│ case x$1581 of +//│ S$1514 => +//│ let x$1582 = x$1581. in +//│ let* (x$1583) = even(x$1582) in +//│ x$1583 +//│ _ => +//│ panic "match error" +//│ def foo_post$1590(x$1591) = +//│ x$1591 +//│ entry = entry$1573 +//│ //│ Interpreted: //│ true @@ -294,6 +922,54 @@ fun foo() = odd(mk(10)) foo() //│ = false //│ +//│ Opt: +//│ class Nat() +//│ class S(s$1606) extends Nat +//│ class O() extends Nat +//│ def odd$1596(x$1609) = +//│ case x$1609 of +//│ O$1607 => +//│ false +//│ _ => +//│ case x$1609 of +//│ S$1604 => +//│ let x$1656 = x$1609. in +//│ let* (x$1657) = even(x$1656) in +//│ x$1657 +//│ _ => +//│ panic "match error" +//│ def even$1598(x$1614) = +//│ case x$1614 of +//│ O$1607 => +//│ true +//│ _ => +//│ case x$1614 of +//│ S$1604 => +//│ let x$1660 = x$1614. in +//│ let* (x$1661) = odd(x$1660) in +//│ x$1661 +//│ _ => +//│ panic "match error" +//│ def mk$1597(n$1619) = +//│ let x$1662 = >(n$1619,0) in +//│ case x$1662 of +//│ BoolLit(true) => +//│ let x$1664 = -(n$1619,1) in +//│ let* (x$1665) = mk(x$1664) in +//│ let x$1666 = S$1604(x$1665) in +//│ x$1666 +//│ _ => +//│ let x$1667 = O$1607() in +//│ x$1667 +//│ def foo$1601() = +//│ let* (x$1668) = mk(10) in +//│ let* (x$1669) = odd(x$1668) in +//│ x$1669 +//│ def entry$1671() = +//│ let* (x$1670) = foo() in +//│ x$1670 +//│ entry = entry$1671 +//│ //│ Interpreted: //│ false @@ -314,9 +990,75 @@ fun foo() = odd(S(S(mk(10)))) foo() //│ = false //│ +//│ Opt: +//│ class Nat() +//│ class S(s$1684) extends Nat +//│ class O() extends Nat +//│ def odd$1674(x$1766) = +//│ let* (x$1772) = odd_pre(x$1766) in +//│ case x$1772 of +//│ O$1685 => +//│ jump odd_case0$1764(x$1772) +//│ _ => +//│ jump odd_default$1765(x$1772) +//│ def even$1676(x$1692) = +//│ case x$1692 of +//│ O$1685 => +//│ true +//│ _ => +//│ case x$1692 of +//│ S$1682 => +//│ let x$1748 = x$1692. in +//│ let* (x$1749) = odd(x$1748) in +//│ x$1749 +//│ _ => +//│ panic "match error" +//│ def mk$1675(n$1697) = +//│ let x$1750 = >(n$1697,0) in +//│ case x$1750 of +//│ BoolLit(true) => +//│ let x$1752 = -(n$1697,1) in +//│ let* (x$1753) = mk(x$1752) in +//│ let x$1754 = S$1682(x$1753) in +//│ x$1754 +//│ _ => +//│ let x$1755 = O$1685() in +//│ x$1755 +//│ def foo$1679() = +//│ let* (x$1756) = mk(10) in +//│ let x$1757 = S$1682(x$1756) in +//│ let x$1758 = S$1682(x$1757) in +//│ let* (x$1780) = odd_pre(x$1758) in +//│ case x$1780 of +//│ O$1685 => +//│ let* (x$1781) = odd_case0(x$1780) in +//│ jump foo_post$1778(x$1781) +//│ _ => +//│ let* (x$1782) = odd_default(x$1780) in +//│ jump foo_post$1778(x$1782) +//│ def entry$1761() = +//│ let* (x$1760) = foo() in +//│ x$1760 +//│ def odd_pre$1763(x$1767) = +//│ x$1767 +//│ def odd_case0$1764(x$1768) = +//│ false +//│ def odd_default$1765(x$1769) = +//│ case x$1769 of +//│ S$1682 => +//│ let x$1770 = x$1769. in +//│ let* (x$1771) = even(x$1770) in +//│ x$1771 +//│ _ => +//│ panic "match error" +//│ def foo_post$1778(x$1779) = +//│ x$1779 +//│ entry = entry$1761 +//│ //│ Interpreted: //│ false +:todo "this is a bug because we use reference equality to locate the split point, but the reference changed after previous iteration" :intl abstract class Nat: S[Nat] | O class S(s: Nat) extends Nat @@ -336,10 +1078,10 @@ fun main() = bar() main() //│ = true -//│ -//│ Interpreted: -//│ true +//│ ═══[COMPILATION ERROR] sNode: unexpected Result +//│ Stopped due to an error during the optimization +:todo "this is a bug because we use reference equality to locate the split point, but the reference changed after previous iteration" :intl abstract class Option[out T]: Some[T] | None class Some[out T](x: T) extends Option[T] @@ -361,9 +1103,8 @@ fun main() = is_empty(Cons(1, Cons(2, Nil))) main() //│ = false -//│ -//│ Interpreted: -//│ false +//│ ═══[COMPILATION ERROR] sNode: unexpected Result +//│ Stopped due to an error during the optimization :intl abstract class Option[out T]: Some[T] | None @@ -389,6 +1130,62 @@ fun main() = main() //│ = false //│ +//│ Opt: +//│ class Option() +//│ class Some(x$2028) extends Option +//│ class None() extends Option +//│ class List() +//│ class Cons(head$2037,tail$2038) extends List +//│ class Nil() extends List +//│ def mk_list$2012(n$2041) = +//│ let x$2098 = ==(n$2041,0) in +//│ case x$2098 of +//│ BoolLit(true) => +//│ let x$2100 = Nil$2039() in +//│ x$2100 +//│ _ => +//│ let x$2101 = -(n$2041,1) in +//│ let* (x$2102) = mk_list(x$2101) in +//│ let x$2103 = Cons$2034(n$2041,x$2102) in +//│ x$2103 +//│ def head_opt$2015(l$2048) = +//│ case l$2048 of +//│ Nil$2039 => +//│ let x$2105 = None$2029() in +//│ x$2105 +//│ _ => +//│ case l$2048 of +//│ Cons$2034 => +//│ let x$2107 = l$2048. in +//│ let x$2108 = l$2048. in +//│ let x$2109 = Some$2025(x$2107) in +//│ x$2109 +//│ _ => +//│ panic "match error" +//│ def is_none$2020(o$2055) = +//│ case o$2055 of +//│ None$2029 => +//│ true +//│ _ => +//│ case o$2055 of +//│ Some$2025 => +//│ let x$2112 = o$2055. in +//│ false +//│ _ => +//│ panic "match error" +//│ def is_empty$2021(l$2059) = +//│ let* (x$2113) = head_opt(l$2059) in +//│ let* (x$2114) = is_none(x$2113) in +//│ x$2114 +//│ def main$2013() = +//│ let* (x$2115) = mk_list(10) in +//│ let* (x$2116) = is_empty(x$2115) in +//│ x$2116 +//│ def entry$2118() = +//│ let* (x$2117) = main() in +//│ x$2117 +//│ entry = entry$2118 +//│ //│ Interpreted: //│ false @@ -414,6 +1211,58 @@ fun main() = main() //│ = Some(1) //│ +//│ Opt: +//│ class Option() +//│ class Some(x$2135) extends Option +//│ class None() extends Option +//│ class List() +//│ class Cons(head$2144,tail$2145) extends List +//│ class Nil() extends List +//│ def mk_list$2121(n$2148) = +//│ let x$2197 = ==(n$2148,0) in +//│ case x$2197 of +//│ BoolLit(true) => +//│ let x$2199 = Nil$2146() in +//│ x$2199 +//│ _ => +//│ let x$2200 = -(n$2148,1) in +//│ let* (x$2201) = mk_list(x$2200) in +//│ let x$2202 = Cons$2141(n$2148,x$2201) in +//│ x$2202 +//│ def last_opt$2128(l$2155) = +//│ case l$2155 of +//│ Nil$2146 => +//│ let x$2204 = None$2136() in +//│ x$2204 +//│ _ => +//│ case l$2155 of +//│ Cons$2141 => +//│ let x$2206 = l$2155. in +//│ let x$2207 = l$2155. in +//│ case x$2207 of +//│ Nil$2146 => +//│ let x$2209 = Some$2132(x$2206) in +//│ x$2209 +//│ _ => +//│ case x$2207 of +//│ Cons$2141 => +//│ let x$2211 = x$2207. in +//│ let x$2212 = x$2207. in +//│ let* (x$2213) = last_opt(x$2207) in +//│ x$2213 +//│ _ => +//│ panic "match error" +//│ _ => +//│ panic "match error" +//│ def main$2127() = +//│ let* (x$2214) = mk_list(10) in +//│ let* (x$2215) = last_opt(x$2214) in +//│ x$2215 +//│ def entry$2217() = +//│ let* (x$2216) = main() in +//│ x$2216 +//│ entry = entry$2217 +//│ //│ Interpreted: //│ Some(1) @@ -449,6 +1298,88 @@ fun main() = main() //│ = 115 //│ +//│ Opt: +//│ class Option() +//│ class Some(x$2235) extends Option +//│ class None() extends Option +//│ def e0$2221(w$2242) = +//│ let x$2348 = +(w$2242,8) in +//│ let x$2349 = +(x$2348,9) in +//│ let x$2350 = +(x$2349,10) in +//│ x$2350 +//│ def e1$2219(a$2247,c$2248) = +//│ let x$2351 = +(a$2247,1) in +//│ let x$2352 = +(x$2351,2) in +//│ let x$2353 = +(x$2352,3) in +//│ let x$2354 = +(x$2353,4) in +//│ x$2354 +//│ def e3$2223(c$2254) = +//│ let x$2355 = 4 in +//│ let x$2356 = 5 in +//│ let x$2357 = 6 in +//│ let x$2358 = 7 in +//│ case c$2254 of +//│ BoolLit(true) => +//│ let x$2360 = +(x$2355,x$2356) in +//│ let x$2361 = +(x$2360,x$2357) in +//│ let x$2362 = +(x$2361,x$2358) in +//│ x$2362 +//│ _ => +//│ let x$2363 = +(x$2355,x$2356) in +//│ let x$2364 = -(x$2363,x$2357) in +//│ let x$2365 = +(x$2364,x$2358) in +//│ x$2365 +//│ def e2$2228(x$2266) = +//│ let x$2366 = +(x$2266,12) in +//│ let x$2367 = +(x$2366,13) in +//│ let x$2368 = +(x$2367,14) in +//│ x$2368 +//│ def f$2220(x$2388) = +//│ let* (x$2399,x$2400) = f_pre(x$2388) in +//│ case x$2399 of +//│ Some$2232 => +//│ jump f_case0$2386(x$2399,x$2400) +//│ _ => +//│ jump f_default$2387(x$2399,x$2400) +//│ def j$2374(tmp$2335) = +//│ jump j$2371(tmp$2335) +//│ def j$2371(tmp$2335) = +//│ let* (x$2376) = e0(tmp$2335) in +//│ x$2376 +//│ def main$2222() = +//│ let x$2377 = Some$2232(2) in +//│ let* (x$2416,x$2417) = f_pre(x$2377) in +//│ case x$2416 of +//│ Some$2232 => +//│ let* (x$2418) = f_case0(x$2416,x$2417) in +//│ jump main_post$2411(x$2418) +//│ _ => +//│ let* (x$2419) = f_default(x$2416,x$2417) in +//│ jump main_post$2411(x$2419) +//│ def entry$2383() = +//│ let* (x$2382) = main() in +//│ x$2382 +//│ def f_pre$2385(x$2391) = +//│ let* (x$2389) = e3(x$2390) in +//│ x$2391,x$2389 +//│ def f_case0$2386(x$2393,x$2395) = +//│ let x$2392 = x$2393. in +//│ let* (x$2394) = e1(x$2392,x$2395) in +//│ jump j$2371(x$2394) +//│ def f_default$2387(x$2396,x$2398) = +//│ case x$2396 of +//│ None$2236 => +//│ let* (x$2397) = e2(x$2398) in +//│ jump j$2374(x$2397) +//│ _ => +//│ panic "match error" +//│ def main_post$2411(x$2415) = +//│ let x$2412 = None$2236() in +//│ let* (x$2413) = f(x$2412) in +//│ let x$2414 = +(x$2415,x$2413) in +//│ x$2414 +//│ entry = entry$2383 +//│ //│ Interpreted: //│ 115 @@ -483,5 +1414,83 @@ fun main() = main() //│ = 89 //│ +//│ Opt: +//│ class Nat() +//│ class S(s$2433) extends Nat +//│ class O() extends Nat +//│ def plus$2421(n1$2440,n2$2441) = +//│ case n1$2440 of +//│ O$2434 => +//│ n2$2441 +//│ _ => +//│ case n1$2440 of +//│ S$2431 => +//│ let x$2530 = n1$2440. in +//│ let* (x$2531) = plus(x$2530,n2$2441) in +//│ let x$2532 = S$2431(x$2531) in +//│ x$2532 +//│ _ => +//│ panic "match error" +//│ def fib$2425(n$2447) = +//│ case n$2447 of +//│ O$2434 => +//│ let x$2534 = O$2434() in +//│ let x$2535 = S$2431(x$2534) in +//│ x$2535 +//│ _ => +//│ case n$2447 of +//│ S$2431 => +//│ let x$2537 = n$2447. in +//│ case x$2537 of +//│ O$2434 => +//│ let x$2539 = O$2434() in +//│ let x$2540 = S$2431(x$2539) in +//│ x$2540 +//│ _ => +//│ case x$2537 of +//│ S$2431 => +//│ let x$2542 = x$2537. in +//│ let* (x$2543) = fib(x$2537) in +//│ let* (x$2544) = fib(x$2542) in +//│ let* (x$2545) = plus(x$2543,x$2544) in +//│ x$2545 +//│ _ => +//│ panic "match error" +//│ _ => +//│ panic "match error" +//│ def to_int$2427(n$2458) = +//│ case n$2458 of +//│ O$2434 => +//│ 0 +//│ _ => +//│ case n$2458 of +//│ S$2431 => +//│ let x$2548 = n$2458. in +//│ let* (x$2549) = to_int(x$2548) in +//│ let x$2550 = +(1,x$2549) in +//│ x$2550 +//│ _ => +//│ panic "match error" +//│ def to_nat$2420(n$2464) = +//│ let x$2551 = ==(n$2464,0) in +//│ case x$2551 of +//│ BoolLit(true) => +//│ let x$2553 = O$2434() in +//│ x$2553 +//│ _ => +//│ let x$2554 = -(n$2464,1) in +//│ let* (x$2555) = to_nat(x$2554) in +//│ let x$2556 = S$2431(x$2555) in +//│ x$2556 +//│ def main$2422() = +//│ let* (x$2557) = to_nat(10) in +//│ let* (x$2558) = fib(x$2557) in +//│ let* (x$2559) = to_int(x$2558) in +//│ x$2559 +//│ def entry$2561() = +//│ let* (x$2560) = main() in +//│ x$2560 +//│ entry = entry$2561 +//│ //│ Interpreted: //│ 89 From 6d57e5b965790bb51e96b0387b6be7ef980fe8dc Mon Sep 17 00:00:00 2001 From: waterlens Date: Sat, 15 Mar 2025 12:17:49 +0800 Subject: [PATCH 59/88] checkout the benchmark for reproduction --- flake.nix | 1 + .../src/test/mlscript-compile/cpp/Makefile | 2 +- .../test/mlscript-compile/cpp/mlsprelude.h | 4 +- hkmc2/shared/src/test/mlscript/llir/SRC.mls | 253 ++++++++++++++++++ 4 files changed, 257 insertions(+), 3 deletions(-) create mode 100644 hkmc2/shared/src/test/mlscript/llir/SRC.mls diff --git a/flake.nix b/flake.nix index 8e657face9..42559a9dbe 100644 --- a/flake.nix +++ b/flake.nix @@ -28,6 +28,7 @@ mimalloc sbt nodejs_22 + hyperfine ]; }; }); diff --git a/hkmc2/shared/src/test/mlscript-compile/cpp/Makefile b/hkmc2/shared/src/test/mlscript-compile/cpp/Makefile index 88d7f6046b..4e93f9cb22 100644 --- a/hkmc2/shared/src/test/mlscript-compile/cpp/Makefile +++ b/hkmc2/shared/src/test/mlscript-compile/cpp/Makefile @@ -5,7 +5,7 @@ LDLIBS := -lmimalloc -lgmp -lboost_stacktrace_basic SRC := INCLUDES := mlsprelude.h DST := -DEFAULT_TARGET := mls +DEFAULT_TARGET := $(SRC:=.out) TARGET := $(or $(DST),$(DEFAULT_TARGET)) .PHONY: pre all run clean auto diff --git a/hkmc2/shared/src/test/mlscript-compile/cpp/mlsprelude.h b/hkmc2/shared/src/test/mlscript-compile/cpp/mlsprelude.h index ee03b0d2e4..5002497f9b 100644 --- a/hkmc2/shared/src/test/mlscript-compile/cpp/mlsprelude.h +++ b/hkmc2/shared/src/test/mlscript-compile/cpp/mlsprelude.h @@ -99,7 +99,7 @@ class _mlsUtil { #define _mls_assert(e) \ (__builtin_expect(!(e), 0) \ ? _mlsUtil::panic_with("assertion failed", __func__, \ - __ASSERT_FILE_NAME, __LINE__) \ + __FILE__, __LINE__) \ : (void)0) struct _mlsFloatShape : public _mlsObject { @@ -385,7 +385,7 @@ inline int _mlsLargeStack(void *(*fn)(void *)) { pthread_t thread; pthread_attr_t attr; - size_t stacksize = 512 * 1024 * 1024; + size_t stacksize = 1024 * 1024 * 1024; pthread_attr_init(&attr); pthread_attr_setstacksize(&attr, stacksize); diff --git a/hkmc2/shared/src/test/mlscript/llir/SRC.mls b/hkmc2/shared/src/test/mlscript/llir/SRC.mls new file mode 100644 index 0000000000..031fd49d09 --- /dev/null +++ b/hkmc2/shared/src/test/mlscript/llir/SRC.mls @@ -0,0 +1,253 @@ +:llir + +:global + +:sopt +:optf simp,!split +:wcpp orig.cpp +abstract class Iter[T] +object Done +class Yield(n) +class Map(f, it) +fun done(it) = if it is Done then true else false +fun map(f, it) = Map(f, it) +fun dec(n) = Yield(n) +fun next(it) = if it is + Yield(n) then + if n == 0 then [0, Done] + else [n, Yield(n - 1)] + Map(f, it) then + if next(it) is [n, it] then + if done(it) then [f(n), Done] + else [f(n), Map(f, it)] +fun fold(acc, it) = + if next(it) is [n, it] then + if done(it) then acc else fold(n + acc, it) +fun map_sum(f, n) = let it = map(f, dec(n)) in fold(0, it) +map_sum(x => x, 2000000) +//│ +//│ Opt: +//│ class Done() +//│ class Yield(n$234) +//│ class Map(f$237,it$238) +//│ class Lambda() extends Callable { +//│ def apply1$344(x$292) = +//│ x$292 +//│ } +//│ def done$223(it$239) = +//│ case it$239 of +//│ Done$230 => +//│ true +//│ _ => +//│ false +//│ def map$217(f$241,it$242) = +//│ let x$320 = Map$235(f$241,it$242) in +//│ x$320 +//│ def dec$226(n$245) = +//│ let x$321 = Yield$232(n$245) in +//│ x$321 +//│ def next$222(it$248) = +//│ case it$248 of +//│ Yield$232 => +//│ let x$323 = it$248. in +//│ let x$324 = ==(x$323,0) in +//│ case x$324 of +//│ BoolLit(true) => +//│ let x$326 = Done$230() in +//│ let x$327 = Tuple2$328(0,x$326) in +//│ x$327 +//│ _ => +//│ let x$330 = -(x$323,1) in +//│ let x$331 = Yield$232(x$330) in +//│ let x$332 = Tuple2$328(x$323,x$331) in +//│ x$332 +//│ _ => +//│ case it$248 of +//│ Map$235 => +//│ let x$334 = it$248. in +//│ let x$335 = it$248. in +//│ let* (x$336) = next(x$335) in +//│ case x$336 of +//│ Tuple2$328 => +//│ let x$338 = x$336. in +//│ let x$339 = x$336. in +//│ let* (x$340) = done(x$339) in +//│ case x$340 of +//│ BoolLit(true) => +//│ let x$342 = Callable.apply1$344(x$334,x$338) in +//│ let x$345 = Done$230() in +//│ let x$346 = Tuple2$328(x$342,x$345) in +//│ x$346 +//│ _ => +//│ let x$347 = Callable.apply1$344(x$334,x$338) in +//│ let x$348 = Map$235(x$334,x$339) in +//│ let x$349 = Tuple2$328(x$347,x$348) in +//│ x$349 +//│ _ => +//│ panic "match error" +//│ _ => +//│ panic "match error" +//│ def fold$219(acc$271,it$272) = +//│ let* (x$350) = next(it$272) in +//│ case x$350 of +//│ Tuple2$328 => +//│ let x$352 = x$350. in +//│ let x$353 = x$350. in +//│ let* (x$354) = done(x$353) in +//│ case x$354 of +//│ BoolLit(true) => +//│ acc$271 +//│ _ => +//│ let x$356 = +(x$352,acc$271) in +//│ let* (x$357) = fold(x$356,x$353) in +//│ x$357 +//│ _ => +//│ panic "match error" +//│ def map_sum$225(f$284,n$285) = +//│ let* (x$358) = dec(n$285) in +//│ let* (x$359) = map(f$284,x$358) in +//│ let* (x$360) = fold(0,x$359) in +//│ x$360 +//│ def entry$365() = +//│ let x$364 = Lambda$362() in +//│ let* (x$361) = map_sum(x$364,2000000) in +//│ x$361 +//│ entry = entry$365 + + +:sopt +:optf simp,!split +:wcpp inlined.cpp +abstract class Iter[T] +object Done +class Yield(n) +class Map(f, it) +fun done(it) = if it is Done then true else false +fun map(f, it) = Map(f, it) +fun dec(n) = Yield(n) +fun next(it) = if it is + Yield(n) then + if n == 0 then [0, Done] + else [n, Yield(n - 1)] + Map(f, it) then + if next(it) is [n, it] then + if done(it) then [f(n), Done] + else [f(n), Map(f, it)] +fun fold(acc, iter) = if iter is + Yield(n) then + if n == 0 then acc + else fold(n + acc, Yield(n - 1)) + Map(f, it) then + if next(it) is [n, it] then + if it is Done then acc else fold(f(n) + acc, Map(f, it)) +fun map_sum(f, n) = let it = map(f, dec(n)) in fold(0, it) +map_sum(x => x, 2000000) +//│ +//│ Opt: +//│ class Done() +//│ class Yield(n$386) +//│ class Map(f$389,it$390) +//│ class Lambda() extends Callable { +//│ def apply1$344(x$456) = +//│ x$456 +//│ } +//│ def done$375(it$391) = +//│ case it$391 of +//│ Done$382 => +//│ true +//│ _ => +//│ false +//│ def map$369(f$393,it$394) = +//│ let x$492 = Map$387(f$393,it$394) in +//│ x$492 +//│ def dec$378(n$397) = +//│ let x$493 = Yield$384(n$397) in +//│ x$493 +//│ def next$374(it$400) = +//│ case it$400 of +//│ Yield$384 => +//│ let x$495 = it$400. in +//│ let x$496 = ==(x$495,0) in +//│ case x$496 of +//│ BoolLit(true) => +//│ let x$498 = Done$382() in +//│ let x$499 = Tuple2$328(0,x$498) in +//│ x$499 +//│ _ => +//│ let x$500 = -(x$495,1) in +//│ let x$501 = Yield$384(x$500) in +//│ let x$502 = Tuple2$328(x$495,x$501) in +//│ x$502 +//│ _ => +//│ case it$400 of +//│ Map$387 => +//│ let x$504 = it$400. in +//│ let x$505 = it$400. in +//│ let* (x$506) = next(x$505) in +//│ case x$506 of +//│ Tuple2$328 => +//│ let x$508 = x$506. in +//│ let x$509 = x$506. in +//│ let* (x$510) = done(x$509) in +//│ case x$510 of +//│ BoolLit(true) => +//│ let x$512 = Callable.apply1$344(x$504,x$508) in +//│ let x$513 = Done$382() in +//│ let x$514 = Tuple2$328(x$512,x$513) in +//│ x$514 +//│ _ => +//│ let x$515 = Callable.apply1$344(x$504,x$508) in +//│ let x$516 = Map$387(x$504,x$509) in +//│ let x$517 = Tuple2$328(x$515,x$516) in +//│ x$517 +//│ _ => +//│ panic "match error" +//│ _ => +//│ panic "match error" +//│ def fold$371(acc$423,iter$424) = +//│ case iter$424 of +//│ Yield$384 => +//│ let x$519 = iter$424. in +//│ let x$520 = ==(x$519,0) in +//│ case x$520 of +//│ BoolLit(true) => +//│ acc$423 +//│ _ => +//│ let x$522 = +(x$519,acc$423) in +//│ let x$523 = -(x$519,1) in +//│ let x$524 = Yield$384(x$523) in +//│ let* (x$525) = fold(x$522,x$524) in +//│ x$525 +//│ _ => +//│ case iter$424 of +//│ Map$387 => +//│ let x$527 = iter$424. in +//│ let x$528 = iter$424. in +//│ let* (x$529) = next(x$528) in +//│ case x$529 of +//│ Tuple2$328 => +//│ let x$531 = x$529. in +//│ let x$532 = x$529. in +//│ case x$532 of +//│ Done$382 => +//│ acc$423 +//│ _ => +//│ let x$534 = Callable.apply1$344(x$527,x$531) in +//│ let x$535 = +(x$534,acc$423) in +//│ let x$536 = Map$387(x$527,x$532) in +//│ let* (x$537) = fold(x$535,x$536) in +//│ x$537 +//│ _ => +//│ panic "match error" +//│ _ => +//│ panic "match error" +//│ def map_sum$377(f$448,n$449) = +//│ let* (x$538) = dec(n$449) in +//│ let* (x$539) = map(f$448,x$538) in +//│ let* (x$540) = fold(0,x$539) in +//│ x$540 +//│ def entry$545() = +//│ let x$544 = Lambda$542() in +//│ let* (x$541) = map_sum(x$544,2000000) in +//│ x$541 +//│ entry = entry$545 From d11259f499bbf9615b384d1de57eb29e423e828d Mon Sep 17 00:00:00 2001 From: waterlens Date: Tue, 18 Mar 2025 23:21:45 +0800 Subject: [PATCH 60/88] Reconcile Lifter and LLIR Builder again --- .../src/main/scala/hkmc2/codegen/Block.scala | 50 ++++++++++++++++++- .../scala/hkmc2/codegen/llir/Builder.scala | 12 +++-- 2 files changed, 55 insertions(+), 7 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Block.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Block.scala index 3eb6131e5f..233f45ca3e 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Block.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Block.scala @@ -90,8 +90,7 @@ sealed abstract class Block extends Product with AutoLocated: case Continue(label) => Set(label) case Begin(sub, rest) => sub.freeVars ++ rest.freeVars case TryBlock(sub, finallyDo, rest) => sub.freeVars ++ finallyDo.freeVars ++ rest.freeVars - case Assign(lhs: TermSymbol, rhs, rest) => rhs.freeVars ++ rest.freeVars - case Assign(lhs, rhs, rest) => rhs.freeVars ++ (rest.freeVars - lhs) + case Assign(l, rhs, rest) => Set(l) ++ rhs.freeVars ++ rest.freeVars case AssignField(lhs, nme, rhs, rest) => lhs.freeVars ++ rhs.freeVars ++ rest.freeVars case AssignDynField(lhs, fld, arrayIdx, rhs, rest) => lhs.freeVars ++ fld.freeVars ++ rhs.freeVars ++ rest.freeVars case Define(defn, rest) => defn.freeVars ++ (rest.freeVars - defn.sym) @@ -99,6 +98,26 @@ sealed abstract class Block extends Product with AutoLocated: (bod.freeVars - lhs) ++ rst.freeVars ++ hdr.flatMap(_.freeVars) case End(msg) => Set.empty + lazy val freeVarsLLIR: Set[Local] = this match + case Match(scrut, arms, dflt, rest) => + scrut.freeVarsLLIR ++ dflt.toList.flatMap(_.freeVarsLLIR) ++ rest.freeVarsLLIR + ++ arms.flatMap: + (pat, arm) => arm.freeVarsLLIR -- pat.freeVarsLLIR + case Return(res, implct) => res.freeVarsLLIR + case Throw(exc) => exc.freeVarsLLIR + case Label(label, body, rest) => (body.freeVarsLLIR - label) ++ rest.freeVarsLLIR + case Break(label) => Set(label) + case Continue(label) => Set(label) + case Begin(sub, rest) => sub.freeVarsLLIR ++ rest.freeVarsLLIR + case TryBlock(sub, finallyDo, rest) => sub.freeVarsLLIR ++ finallyDo.freeVarsLLIR ++ rest.freeVarsLLIR + case Assign(l, rhs, rest) => rhs.freeVarsLLIR ++ (rest.freeVarsLLIR - l) + case AssignField(lhs, nme, rhs, rest) => lhs.freeVarsLLIR ++ rhs.freeVarsLLIR ++ rest.freeVarsLLIR + case AssignDynField(lhs, fld, arrayIdx, rhs, rest) => lhs.freeVarsLLIR ++ fld.freeVarsLLIR ++ rhs.freeVarsLLIR ++ rest.freeVarsLLIR + case Define(defn, rest) => defn.freeVarsLLIR ++ (rest.freeVarsLLIR - defn.sym) + case HandleBlock(lhs, res, par, args, cls, hdr, bod, rst) => + (bod.freeVarsLLIR - lhs) ++ rst.freeVarsLLIR ++ hdr.flatMap(_.freeVarsLLIR) + case End(msg) => Set.empty + lazy val subBlocks: Ls[Block] = this match case Match(p, arms, dflt, rest) => p.subBlocks ++ arms.map(_._2) ++ dflt.toList :+ rest case Begin(sub, rest) => sub :: rest :: Nil @@ -293,6 +312,15 @@ sealed abstract class Defn: preCtor.freeVars ++ ctor.freeVars ++ methods.flatMap(_.freeVars) -- auxParams.flatMap(_.paramSyms) + + lazy val freeVarsLLIR: Set[Local] = this match + case FunDefn(own, sym, params, body) => body.freeVarsLLIR -- params.flatMap(_.paramSyms) - sym + case ValDefn(owner, k, sym, rhs) => rhs.freeVarsLLIR + case ClsLikeDefn(own, isym, sym, k, paramsOpt, auxParams, parentSym, + methods, privateFields, publicFields, preCtor, ctor) => + preCtor.freeVarsLLIR + ++ ctor.freeVarsLLIR ++ methods.flatMap(_.freeVarsLLIR) + -- auxParams.flatMap(_.paramSyms) final case class FunDefn( owner: Opt[InnerSymbol], @@ -333,6 +361,7 @@ final case class Handler( body: Block, ): lazy val freeVars: Set[Local] = body.freeVars -- params.flatMap(_.paramSyms) - sym - resumeSym + lazy val freeVarsLLIR: Set[Local] = body.freeVarsLLIR -- params.flatMap(_.paramSyms) - sym - resumeSym /* Represents either unreachable code (for functions that must return a result) * or the end of a non-returning function or a REPL block */ @@ -348,6 +377,11 @@ enum Case: case Cls(_, path) => path.freeVars case Tup(_, _) => Set.empty + lazy val freeVarsLLIR: Set[Local] = this match + case Lit(_) => Set.empty + case Cls(_, path) => path.freeVarsLLIR + case Tup(_, _) => Set.empty + sealed trait TrivialResult extends Result sealed abstract class Result: @@ -372,6 +406,18 @@ sealed abstract class Result: case Value.Arr(elems) => elems.flatMap(_.value.freeVars).toSet case Value.Rcd(elems) => elems.flatMap(_.value.freeVars).toSet case DynSelect(qual, fld, arrayIdx) => qual.freeVars ++ fld.freeVars + + lazy val freeVarsLLIR: Set[Local] = this match + case Call(fun, args) => fun.freeVarsLLIR ++ args.flatMap(_.value.freeVarsLLIR).toSet + case Instantiate(cls, args) => cls.freeVarsLLIR ++ args.flatMap(_.freeVarsLLIR).toSet + case Select(qual, name) => qual.freeVarsLLIR + case Value.Ref(l) => Set(l) + case Value.This(sym) => Set.empty + case Value.Lit(lit) => Set.empty + case Value.Lam(params, body) => body.freeVarsLLIR -- params.paramSyms + case Value.Arr(elems) => elems.flatMap(_.value.freeVarsLLIR).toSet + case Value.Rcd(elems) => elems.flatMap(_.value.freeVarsLLIR).toSet + case DynSelect(qual, fld, arrayIdx) => qual.freeVarsLLIR ++ fld.freeVarsLLIR // type Local = LocalSymbol type Local = Symbol diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala index 63b3dde955..2687e2c0b7 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala @@ -98,7 +98,7 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger, uid: FreshInt): private def freeVarsFilter(fvs: Set[Local]) = trace[Set[Local]](s"freeVarsFilter begin", x => s"freeVarsFilter end: $x"): fvs.filter: - case _: (BuiltinSymbol | TopLevelSymbol | ClassSymbol) => false + case _: (BuiltinSymbol | TopLevelSymbol | ClassSymbol | TermSymbol) => false case ms: MemberSymbol[?] => ms.defn match case Some(d: ClassLikeDef) => false case _ => true @@ -241,8 +241,10 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger, uid: FreshInt): trace[Node](s"bLam begin", x => s"bLam end: ${x.show}"): val Value.Lam(params, body) = lam // Generate an auxiliary class inheriting from Callable - val freeVars = freeVarsFilter(lam.freeVars -- body.definedVars -- recName.iterator -- ctx.fn_ctx.keySet) - log(s"Match free vars: ${lam.freeVars -- body.definedVars} ${ctx.fn_ctx.keySet} ${params.params.map(p => p.sym)}") + val freeVars = freeVarsFilter(lam.freeVarsLLIR -- body.definedVars -- recName.iterator -- ctx.fn_ctx.keySet) + log(s"Defined vars: ${body.definedVars}") + log(s"Match free vars: ${lam.freeVarsLLIR -- body.definedVars} ${ctx.fn_ctx.keySet} ${params.params.map(p => p.sym)}") + log(s"Lot: $lam") val name = newClassSym(s"Lambda${nameHint.fold("")(x => "_" + x)}") val freeVarsList = freeVars.toList val args = freeVarsList.map(symMap) @@ -444,9 +446,9 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger, uid: FreshInt): case e: TrivialExpr => val nextCont = Begin(rest, ct) val jp: Local = newNamedTemp("j") - val fvset = freeVarsFilter(nextCont.freeVars -- nextCont.definedVars -- ctx.fn_ctx.keySet) + val fvset = freeVarsFilter(nextCont.freeVarsLLIR -- nextCont.definedVars -- ctx.fn_ctx.keySet) val fvs1 = fvset.toList - log(s"Match free vars: $fvset ${nextCont.freeVars -- nextCont.definedVars} $fvs1") + log(s"Match free vars: $fvset ${nextCont.freeVarsLLIR -- nextCont.definedVars} $fvs1") val new_ctx = fvs1.foldLeft(ctx)((acc, x) => acc.addName(x, x)) val fvs = fvs1.map(new_ctx.findName(_)) def cont(x: TrivialExpr)(using ctx: Ctx) = Node.Jump( From 81b9be0a71fbc5879738f716be6574f6adfc4705 Mon Sep 17 00:00:00 2001 From: waterlens Date: Thu, 20 Mar 2025 23:40:26 +0800 Subject: [PATCH 61/88] Remove the optimizer part --- .../main/scala/hkmc2/codegen/llir/Opt.scala | 950 ------------------ .../shared/src/test/mlscript/llir/Legacy.mls | 936 ----------------- .../src/test/mlscript/llir/nofib/atom.mls | 2 - .../src/test/mlscript/llir/nofib/awards.mls | 2 - .../test/mlscript/llir/nofib/constraints.mls | 3 - .../src/test/mlscript/llir/nofib/scc.mls | 2 - .../test/mlscript/llir/nofib/secretary.mls | 3 - .../src/test/scala/hkmc2/LlirDiffMaker.scala | 35 +- 8 files changed, 2 insertions(+), 1931 deletions(-) delete mode 100644 hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Opt.scala diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Opt.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Opt.scala deleted file mode 100644 index c771c9e549..0000000000 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Opt.scala +++ /dev/null @@ -1,950 +0,0 @@ -package hkmc2 -package codegen -package llir - -import mlscript.utils.* -import mlscript.utils.shorthands.* -import hkmc2.utils.* -import hkmc2.document.* -import hkmc2.Message.MessageContext - -import hkmc2.syntax.Tree -import hkmc2.semantics.* -import hkmc2.codegen.llir.{ Program => LlirProgram, Node, Func } -import hkmc2.codegen.Program -import hkmc2.codegen.cpp.Expr.StrLit - -import language.implicitConversions -import annotation.tailrec -import collection.immutable._ -import collection.mutable.{HashMap => MutHMap, HashSet => MutHSet, LinkedHashMap => MutLMap, LinkedHashSet => MutLSet} -import scala.collection.mutable.ListBuffer - -final case class OptErr(message: String) extends Exception(message) - -private def oErrStop(msg: Message)(using Raise) = - raise(ErrorReport(msg -> N :: Nil, - source = Diagnostic.Source.Compilation)) - throw OptErr("stopped") - -def notBuiltinLetCall(node: Node.LetCall) = - node.func.nme != "" - -def notBuiltin(sym: Local) = - sym.nme != "" - -def notCallable(sym: Local) = - sym.nme != "Callable" - -def showSym(sym: Local) = s"${sym.nme}$$${sym.uid.toString()}" - -final class LlirOpt(using Elaborator.State, Raise)(tl: TraceLogger, freshInt: FreshInt, flags: Set[Str]): - import tl.{log, trace} - - object DestructUtils: - @tailrec - def getFirstDestructed(node: Node): Opt[Local] = node match - case Node.Result(res) => N - case Node.Jump(func, args) => N - case Node.Case(Expr.Ref(scrut), cases, default) => S(scrut) - case Node.Case(_, _, _) => N - case Node.Panic(msg) => N - case Node.LetExpr(name, expr, body) => getFirstDestructed(body) - case Node.LetMethodCall(names, cls, method, args, body) => N - case Node.LetCall(names, func, args, body) => N - - def isDestructed(node: Node) = getFirstDestructed(node).isDefined - - def newFunSym(name: Str) = BlockMemberSymbol(name, Nil) - def newTemp = TempSymbol(N, "x") - val placeHolderSym = TempSymbol(N, "") - - class RenameUtil(): - val map: MutHMap[Local, Local] = MutHMap.empty - def subst(sym: Local): Local = map.getOrElseUpdate(sym, newTemp) - def subst(sym: IterableOnce[Local]): Iterator[Local] = sym.iterator.map(subst) - def substT(sym: TrivialExpr): TrivialExpr = sym.foldRef(x => Expr.Ref(subst(x))) - def substT(sym: IterableOnce[TrivialExpr]): Iterator[TrivialExpr] = sym.iterator.map(substT) - - class SubstUtil[K, +V](val map: Map[K, V]): - def subst(k: K) = map.getOrElse(k, oErrStop(s"Key $k not found")) - def subst(k: IterableOnce[K]): Iterator[V] = k.iterator.map(subst) - - class MapUtil(val map: Map[Local, Local]): - def subst(k: Local) = map.getOrElse(k, k) - def subst(k: IterableOnce[Local]): Iterator[Local] = k.iterator.map(subst) - def substT(sym: TrivialExpr): TrivialExpr = sym.foldRef(x => Expr.Ref(subst(x))) - def substT(sym: IterableOnce[TrivialExpr]): Iterator[TrivialExpr] = sym.iterator.map(substT) - - case class RefEqNode(node: Node): - override def equals(that: Any) = - that match - case RefEqNode(thatNode) => - node is thatNode - case _ => false - override def hashCode = node.hashCode - type Loc = RefEqNode - given Conversion[Node, Loc] = RefEqNode(_) - - enum IInfo: - case Ctor(c: Local) - case Mixed(i: Set[I]) - case Tuple(n: Int) - - enum EInfo: - case Pass - case Des - case IndDes - case Sel(cls: Local, fld: Str) - - case class E(loc: Loc, info: EInfo) - case class I(loc: Loc, info: IInfo) - - implicit object EOrdering extends Ordering[E]: - override def compare(a: E, b: E) = a.info.toString.compare(b.info.toString) - implicit object IOrdering extends Ordering[I]: - override def compare(a: I, b: I) = a.info.toString.compare(b.info.toString) - - object ProgInfo: - def fromProgram(prog: LlirProgram) = - ProgInfo( - activeParams = MutHMap.from(prog.defs.iterator.map(f => f.name -> f.params.map(_ => SortedSet.empty[E]))), - activeResults = MutHMap.from(prog.defs.iterator.map(f => f.name -> List.fill(f.resultNum)(N))), - func = MutHMap.from(prog.defs.map(f => f.name -> f)), - classes = MutHMap.from(prog.classes.map(c => c.name -> c)), - entry = prog.entry - ) - - case class ProgInfo( - activeParams: MutHMap[Local, Ls[SortedSet[E]]], - activeResults: MutHMap[Local, Ls[Opt[I]]], - func: MutHMap[Local, Func], - classes: MutHMap[Local, ClassInfo], - entry: Local, - ): - def toProgram = - LlirProgram(classes.values.toSet, func.values.toSet, entry = entry) - - def getActiveParams(func: Local) = - activeParams.getOrElse(func, oErrStop(s"Function $func with empty activeParams")) - - def getActiveResults(func: Local) = - activeResults.getOrElse(func, oErrStop(s"Function $func with empty activeResults")) - - def getFunc(sym: Local): Func = - func.getOrElse(sym, oErrStop(s"Function $sym not found")) - - def getClass(sym: Local): ClassInfo = - classes.getOrElse(sym, oErrStop(s"Class $sym not found")) - - def setActiveParams(func: Local, aps: Ls[SortedSet[E]]) = - activeParams.update(func, aps) - - def setActiveResults(func: Local, ars: Ls[Opt[I]]) = - activeResults.update(func, ars) - - private object EliminationAnalysis: - case class Env( - val def_count: MutHMap[Local, Int] = MutHMap.empty, - val elims: MutHMap[Local, MutHSet[E]] = MutHMap.empty, - val defn: Local, - val visited: MutHSet[Local] = MutHSet.empty, - ) - - private class EliminationAnalysis(info: ProgInfo): - import EliminationAnalysis.Env - def addE(sym: Local, e: E)(using env: Env) = - env.elims.getOrElseUpdate(sym, MutHSet.empty) += e - - def addBackwardE(sym: Local, e: E, newLoc: Loc)(using env: Env) = - import EInfo.* - val e2 = e match - case E(_, Des) | E(_, IndDes) => Some(E(newLoc, IndDes)) - case E(_, Pass) => Some(E(newLoc, Pass)) - case _ => None - for e2 <- e2 do env.elims.getOrElseUpdate(sym, MutHSet.empty).add(e2) - - def addDef(sym: Local)(using env: Env) = - env.def_count.update(sym, env.def_count.getOrElse(sym, 0) + 1) - - def fTExprWithLoc(x: TrivialExpr, loc: Loc)(using env: Env): Unit = - x.iterRef(addE(_, E(loc, EInfo.Pass))) - - def fExprWithLoc(x: Expr, loc: Loc)(using env: Env): Unit = x match - case Expr.Ref(name) => addE(name, E(loc, EInfo.Pass)) - case Expr.Literal(lit) => - case Expr.CtorApp(name, args) => args.foreach(fTExprWithLoc(_, loc)) - case Expr.Select(name, cls, field) => addE(name, E(loc, EInfo.Sel(cls, field))) - case Expr.BasicOp(name, args) => args.foreach(fTExprWithLoc(_, loc)) - case Expr.AssignField(assignee, _, _, value) => TODO("fExprWithLoc: AssignField") - - def fNode(node: Node)(using env: Env): Unit = - def fDef(func: Local, args: Ls[TrivialExpr], funcDefn: Func)(using env: Env) = - val aps = info.getActiveParams(func) - args.iterator.zip(aps).foreach: - case (Expr.Ref(x), ys) => ys.foreach(y => addBackwardE(x, y, node)) - case _ => - if !env.visited.contains(func) && notBuiltin(func) then - env.visited.add(func) - val funcDefn = info.getFunc(func) - funcDefn.params.foreach(addDef) - val newEnv = env.copy(defn = func) - fNode(funcDefn.body)(using newEnv) - node match - case Node.Result(res) => res.foreach(fTExprWithLoc(_, node)) - case Node.Jump(func, args) => - args.foreach(fTExprWithLoc(_, node)) - if notBuiltin(func) then - fDef(func, args, info.getFunc(func)) - case Node.Case(Expr.Ref(scrutinee), cases, default) => - addE(scrutinee, E(node, EInfo.Pass)) - addE(scrutinee, E(node, EInfo.Des)) - cases.foreach { case (cls, body) => fNode(body) } - default.foreach(fNode) - case Node.Case(_, cases, default) => - cases.foreach { case (cls, body) => fNode(body) } - default.foreach(fNode) - case Node.Panic(msg) => - case Node.LetExpr(name, expr, body) => - fExprWithLoc(expr, node) - addDef(name) - fNode(body) - case Node.LetMethodCall(names, cls, method, args, body) => - // TODO: LetMethodCall - fNode(body) - case Node.LetCall(names, func, args, body) => - names.foreach(addDef) - args.foreach(fTExprWithLoc(_, node)) - if notBuiltin(func) then - fDef(func, args, info.getFunc(func)) - fNode(body) - - def run() = - var changed = true - var env = Env(defn = placeHolderSym) - while changed do - changed = false - env = Env(defn = placeHolderSym) - info.func.values.foreach: func => - val old = info.getActiveParams(func.name) - func.params.foreach(addDef(_)(using env)) - fNode(func.body)(using env) - val nu = func.params.iterator.map(p => env.elims.getOrElse(p, MutHSet.empty).toSortedSet).toList - changed |= old != nu - info.setActiveParams(func.name, nu) - env - - private object IntroductionAnalysis: - case class Env( - intros: MutHMap[Local, I] = MutHMap.empty, - default_intro: Ls[Opt[I]], // the intro of panic - ) - - private class IntroductionAnalysis(info: ProgInfo): - import IntroductionAnalysis.Env - def mergeIntros(xs: Ls[Ls[Opt[I]]], loc: Loc): Ls[Opt[I]] = - trace[Ls[Opt[I]]](s"mergeIntros: $xs"): - val xst = xs.transpose - xst.map: ys => - val z = ys.flatMap: - case N => Set.empty[I] - case S(I(loc, IInfo.Mixed(i))) => i - case S(i) => Set(i) - .toSet - if z.nonEmpty then S(I(loc, IInfo.Mixed(z))) else N - - def addI(sym: Local, i: I)(using env: Env) = - trace[Unit](s"addI: ${sym.nme}$$${sym.uid.toString()} -> $i"): - if env.intros.contains(sym) then - oErrStop(s"Multiple introductions of ${sym.nme}$$${sym.uid.toString()}") - env.intros.update(sym, i) - - - def addITExpr(te: TrivialExpr, i: I)(using env: Env) = te match - case Expr.Ref(x) => addI(x, i) - case _ => () - - // given the arguments of a function call, we find their intro-info and propagate them to the function's parameters - def bindIInfo(args: Ls[TrivialExpr], params: Ls[Symbol])(using env: Env) = - args.iterator.zip(params).foreach: - case (Expr.Ref(x), p) if env.intros.contains(x) => env.intros.addOne(p -> env.intros(x)) - case _ => () - - def fTExprWithLoc(x: TrivialExpr, loc: Loc)(using env: Env): Opt[I] = x match - case Expr.Ref(name) => env.intros.get(name) - case _ => N - - def fExprWithLoc(e: Expr, loc: Loc)(using env: Env): Opt[I] = e match - case Expr.Ref(sym) => env.intros.get(sym) - case Expr.CtorApp(cls, args) => S(I(loc, IInfo.Ctor(cls))) - case _ => N - - def fNode(node: Node)(using env: Env): Ls[Opt[I]] = - trace[Ls[Opt[I]]](s"fNode: $node"): - node match - case Node.Result(res) => res.map(f => fTExprWithLoc(f, node)) - case Node.Jump(func, args) => - info.getActiveResults(func).map: - case N => N - case S(I(loc, i)) => S(I(node, i)) - case Node.Case(scrutinee, cases, default) => - val casesIntros = cases.map: - case (Pat.Class(cls), body) => - // addITExpr(scrutinee, I(node, IInfo.Ctor(cls))) - fNode(body) - case (Pat.Lit(lit), body) => fNode(body) - default match - case N => mergeIntros(casesIntros, node) - case S(x) => mergeIntros(casesIntros :+ fNode(x), node) - case Node.Panic(msg) => env.default_intro - case Node.LetExpr(name, expr, body) => - for i <- fExprWithLoc(expr, node) do addI(name, i) - fNode(body) - case Node.LetMethodCall(names, cls, method, args, body) => fNode(body) - case Node.LetCall(names, func, args, body) => - if notBuiltin(func) then - val funcDefn = info.getFunc(func) - val ars = info.getActiveResults(func) - names.iterator.zip(ars).foreach: - case (rv, S(I(oldLoc, i))) => addI(rv, I(node, i)) - case _ => () - fNode(body) - - def run() = - var changed = true - var env = Env(default_intro = Nil) - while changed do - changed = false - env = Env(default_intro = Nil) - info.func.values.foreach: func => - val old = info.getActiveResults(func.name) - val nu = fNode(func.body)(using env.copy(default_intro = List.fill(func.resultNum)(N))) - assert(old.length == nu.length, s"old: $old, nu: $nu") - changed |= old != nu - info.setActiveResults(func.name, nu) - env - - private class Splitting(info: ProgInfo): - case class PreFunc(sym: Local, results: Ls[Local], body: PreFuncBody, orig: Func) - case class PostFunc(sym: Local, params: Ls[Local], body: PostFuncBody, orig: Func) - case class PreFuncBody(body: Node => Node) - case class PostFuncBody(body: Node) - - case class Env( - i: IntroductionAnalysis.Env, - e: EliminationAnalysis.Env, - possibleSplitting: MutHMap[RefEqNode, (PreFuncBody, PostFuncBody)] = MutHMap.empty, - workingList: MutLSet[Func] = MutLSet.empty, - ) - - case class SymDDesc( - knownClass: Local, - isIndirect: Bool, - e: E - ) - - case class SDesc( - argumentsDesc: MutLMap[Local, SymDDesc] = MutLMap.empty, - firstDestructedSym: Opt[Local] = N, - mixingProducer: MutLMap[Local, Loc] = MutLMap.empty, - ) - - def symAndIntroOfTExpr(te: TrivialExpr)(using env: Env): Opt[(Local, I)] = te match - case Expr.Ref(x) => for i <- env.i.intros.get(x) yield (x, i) - case _ => none - - def findProducer(loc: Loc) = loc match - case RefEqNode(Node.LetCall(_, producer, _, _)) => some(producer) - case _ => none - - // how this function reflects the splitting decision? - // if argumentsDesc is non-empty, it means the callee is a target of been splitted - // if mixingProducer is non-empty, it means a call happens before is a mixing producer, - // as well as the splitting target - def checkSTarget(func: Func, args: Ls[TrivialExpr])(using env: Env) = - val activeParams = info.getActiveParams(func.name) - val params = func.params - val argsIntros = args.iterator.map(symAndIntroOfTExpr) - val firstD = DestructUtils.getFirstDestructed(func.body) - var argumentsDesc = MutLMap.empty[Local, SymDDesc] - val mixingProducer = MutLMap.empty[Local, Loc] - argsIntros.zip(params.iterator.zip(activeParams.iterator)).foreach: - case ((S((arg, I(loc, IInfo.Ctor(cls))))), (param, elims)) => - for e <- elims do e match - case E(loc, EInfo.Des) => argumentsDesc.update(param, SymDDesc(cls, false, e)) - case E(loc, EInfo.IndDes) => argumentsDesc.update(param, SymDDesc(cls, true, e)) - case _ => - case (S((arg, I(loc, IInfo.Mixed(is)))), (p, elims)) => - for e <- elims do e match - case E(_, EInfo.Des | EInfo.IndDes) => - // what to do with a mixing producer? - // it's different with other kinds of splitting - // - // for example, in f0, we have following program: - // ... #1 - // let x1 = f1() in - // ... #2 - // let x2 = f2(x1) in - // ... #3 - // where x1 is `IInfo.Mixed` - // - // what we need to to is splitting f1 - // let ... = f1_pre() in - // case ... of - // C1(...) => let x1 = f1_post1(...) in - // jump f0_post(x1) - // C2(...) => let x1' = f1_post2(...) in - // jump f0_post(x1') - // - // f0_post will looks like - // ... #2 - // let x2 = f2(x1) in - // ... #2 - // the problem is how to correctly collect all structures necessary for `f0_post``. - // as we are traversing over the node chain, we shall accumulate the continuation that with a node hole. - // - // in the example above, when we see f2(x1) and find the producer of x1 should be splitted, - // we already have the continuation until `... in #1` - // (we need record the pre-cont before every possible splitting position). - // though, it's still necessary to obtain `... #2` to `... #3` directly. - // how to do that? it's just a node following the f1() call, so it's naturally included by the LetCall node - // it also indicates that yet another kind of context should be carefully maintained. - // another point is worth noticing that we need to do alpha-renaming after using the pre-cont and post-cont!!! - val producer = findProducer(loc) - for p <- producer do - mixingProducer.update(p, loc) - case _ => - case _ => () - SDesc(argumentsDesc, firstD, mixingProducer) - - def memoCall(callNode: Node.LetCall)(k: Node => Env ?=> Node)(using env: Env): Unit = - val Node.LetCall(names, func, args, body) = callNode - env.possibleSplitting.update(RefEqNode(callNode), (PreFuncBody(node => k(node)(using env)), PostFuncBody(body))) - - // there's another strategy to split a callee of functions calls - // they can be categorized into several kinds: - // 1. the elimination happens in a nested call - // a). the elimination happens in a most-out level, which means it isn't contained by any other case. - // so what need to do is simply split the callee into 3 parts, namely pre, call, and post. - // this mode is called A mode - // b). it's inside a case - // it's a little difficult to handle, but if this happens, how about to delegate it to the 3rd case - // as we already have a mechanism to handle it. - // 2. the elimination happens in a nested jump - // similar to case 1, but only 2 parts for 2.a, which is called B mode - // 3. the elimination happens in a case - // a). still the case is the outmost one, which is called C mode - // in this case, the function is split into 1 + #(case arms) parts - // b). it's inside another case - // still, split the outmost case first - // - // In any case and sub-case above, it should be guaranteed that the node contains at least one let-call, - // jump, or case node. Otherwise, the splitting is problematic, which implies a bug in the algorithm. - - case class CallShape( - func: Local, - returns: Opt[Ls[Local]], - args: Ls[TrivialExpr], - ) - - case class CaseShape( - scrutinee: TrivialExpr, - cases: Ls[(Pat, PostFunc)], - default: Opt[PostFunc], - ) - - enum SplittingMode: - case A(pre: PreFunc, post: PostFunc, callS: CallShape) - case B(pre: PreFunc, callS: CallShape) - case C(pre: PreFunc, caseS: CaseShape) - - case class ComposeResult( - k: Node => Node, - newFunc: Ls[Func], - invalidFunc: Func - ) - - def renameExpr(expr: Expr)(using s: RenameUtil): Expr = expr match - case Expr.Ref(sym) => Expr.Ref(s.subst(sym)) - case Expr.Literal(lit) => expr - case Expr.CtorApp(cls, args) => Expr.CtorApp(cls, s.substT(args).toList) - case Expr.Select(name, cls, field) => Expr.Select(s.subst(name), cls, field) - case Expr.BasicOp(name, args) => Expr.BasicOp(name, s.substT(args).toList) - case Expr.AssignField(assignee, cls, field, value) => Expr.AssignField(s.subst(assignee), cls, field, s.substT(value)) - - def renameNode(node: Node)(using s: RenameUtil): Node = node match - case Node.Result(res) => Node.Result(s.substT(res).toList) - case Node.Jump(func, args) => Node.Jump(func, s.substT(args).toList) - case Node.Case(scrutinee, cases, default) => - Node.Case(s.substT(scrutinee), cases.map: - case (pat, body) => pat -> renameNode(body), - default.map(renameNode(_))) - case Node.Panic(msg) => Node.Panic(msg) - case Node.LetExpr(name, expr, body) => - val nuName = s.subst(name) - val nuExpr = renameExpr(expr) - Node.LetExpr(nuName, nuExpr, renameNode(body)) - case Node.LetMethodCall(names, cls, method, args, body) => - val nuNames = names.map(s.subst) - Node.LetMethodCall(nuNames, cls, method, s.substT(args).toList, renameNode(body)) - case Node.LetCall(names, func, args, body) => - val nuNames = names.map(s.subst) - Node.LetCall(nuNames, func, s.substT(args).toList, renameNode(body)) - - def reComposePreFunc(subst: RenameUtil, preBody: Node => Node, origParams: Ls[Local], preSym: Local, results: Ls[Local]): Func = - trace[Func](s"reComposePreFunc begin", f => s"reComposePreFunc end: $f"): - val preParams = subst.subst(origParams) - val preNode = renameNode(preBody(Node.Result(results.map(Expr.Ref(_)))))(using subst) - val preFunc = Func(freshInt.make, preSym, preParams.toList, results.length, preNode) - preFunc - - def reComposePostFunc(subst: RenameUtil, params: Ls[Local], postBody: Node, postSym: Local, resultNum: Int): Func = - trace[Func](s"reComposePostFunc begin: $params $postBody", f => s"reComposePostFunc end: $f"): - val postParams = subst.subst(params) - val postNode = renameNode(postBody)(using subst) - val postFunc = Func(freshInt.make, postSym, postParams.toList, resultNum, postNode) - postFunc - - def reComposeWithArgs(sm: SplittingMode, args: Ls[TrivialExpr], returns: Opt[Ls[Local]], knownClass: Opt[Local]): ComposeResult = - sm match - case SplittingMode.A( - PreFunc(preSym, results, PreFuncBody(preBody), orig), - PostFunc(postSym, params, PostFuncBody(postBody), _), - CallShape(func, nestedReturns, nestedArgs)) => - val preFunc = reComposePreFunc(RenameUtil(), preBody, orig.params, preSym, results) - val postFunc = reComposePostFunc(RenameUtil(), params, postBody, postSym, orig.resultNum) - val k = (node: Node) => - // alpha rename the nestedReturns, results, nestedArgs, and params - // since they may be reused in different contexts - val subst = RenameUtil() - val nuNestedReturns = subst.subst(nestedReturns.get) - val nuResults = subst.subst(results) - val nuNestedArgs = subst.substT(nestedArgs) - val nuParams = subst.subst(params) - val tailJump = returns.isEmpty - Node.LetCall(nuResults.toList, preSym, args, - Node.LetCall(nuNestedReturns.toList, func, nuNestedArgs.toList, - if tailJump then - Node.Jump(postSym, nuParams.map(Expr.Ref(_)).toList) - else - val nuReturns = subst.subst(returns.get) - Node.LetCall(nuReturns.toList, postSym, nuParams.map(Expr.Ref(_)).toList, renameNode(node)(using subst)))) - ComposeResult(k, List(preFunc, postFunc), orig) - case SplittingMode.B( - PreFunc(preSym, results, PreFuncBody(preBody), orig), - CallShape(func, nestedReturns, nestedArgs)) => - val preFunc = reComposePreFunc(RenameUtil(), preBody, orig.params, preSym, results) - val k = (node: Node) => - val subst = RenameUtil() - // there are no nested returns since in original function it's a jump - val nuResults = subst.subst(results) - val nuNestedArgs = subst.substT(nestedArgs) - val tailJump = returns.isEmpty - Node.LetCall(nuResults.toList, preSym, args, - if tailJump then - Node.Jump(func, nuNestedArgs.toList) - else - val nuReturns = subst.subst(returns.get) - Node.LetCall(nuReturns.toList, func, nuNestedArgs.toList, renameNode(node)(using subst))) - ComposeResult(k, List(preFunc), orig) - case SplittingMode.C( - PreFunc(preSym, results, PreFuncBody(preBody), orig), - CaseShape(scrutinee, cases, default)) => - val preFunc = reComposePreFunc(RenameUtil(), preBody, orig.params, preSym, results) - var matchedPat = none[Pat] - - val allPostFunc = cases.map: - case (pat, PostFunc(postSym, params, PostFuncBody(postBody), _)) => - val postFunc = reComposePostFunc(RenameUtil(), params, postBody, postSym, orig.resultNum) - (pat, knownClass) match - case (Pat.Class(cls), S(cls2)) if cls == cls2 => matchedPat = some(pat) - case _ => - (params, pat, postFunc) - val defaultPostFunc = default.map: - case PostFunc(postSym, params, PostFuncBody(postBody), _) => - (params, reComposePostFunc(RenameUtil(), params, postBody, postSym, orig.resultNum)) - - def tailNodeLetCall(postFunc: Func, postFvs: Ls[Local], node: Node)(using subst: RenameUtil) = - // the reason for postFvs instead of postFunc.params is that the later has been renamed - // so they cannot be correctly renamed with another RenameUtil - val postArgs = subst.subst(postFvs).map(Expr.Ref(_)).toList - val subst2 = RenameUtil() - val nuReturns = subst2.subst(returns.get) - Node.LetCall(nuReturns.toList, postFunc.name, postArgs, renameNode(node)(using subst2)) - def tailNodeJump(postFunc: Func, postFvs: Ls[Local])(using subst: RenameUtil) = - val postArgs = subst.subst(postFvs).map(Expr.Ref(_)).toList - Node.Jump(postFunc.name, postArgs) - def tailNodeChoose(postFvs: Ls[Local], postFunc: Func, node: Node)(using subst: RenameUtil) = - if returns.isEmpty then tailNodeJump(postFunc, postFvs) else tailNodeLetCall(postFunc, postFvs, node) - // the supplied node should be trivial, otherwise we actually duplicate stuff here - val k = (node: Node) => - given subst: RenameUtil = RenameUtil() - val nuResults = subst.subst(results) - val nuScrutinee = subst.substT(scrutinee) - val tailJump = returns.isEmpty - (knownClass, matchedPat) match - case (None, _) => - Node.LetCall(nuResults.toList, preSym, args, - Node.Case(nuScrutinee, allPostFunc.map: - case (args, pat, postFunc) => - pat -> tailNodeChoose(args, postFunc, node), - defaultPostFunc.map((args, postFunc) => - tailNodeChoose(args, postFunc, node)))) - case (Some(_), None) => - // only keep the default case if there's one - defaultPostFunc match - case None => - Node.LetCall(nuResults.toList, preSym, args, - Node.Case(nuScrutinee, allPostFunc.map: - case (args, pat, postFunc) => - pat -> tailNodeChoose(args, postFunc, node), - defaultPostFunc.map((args, postFunc) => - tailNodeChoose(args, postFunc, node)))) - case Some((args2, postFunc)) => - Node.LetCall(nuResults.toList, preSym, args, - tailNodeChoose(args2, postFunc, node)) - case (Some(_), Some(matched)) => - Node.LetCall(nuResults.toList, preSym, args, - allPostFunc.flatMap: - case (args, pat, postFunc) => if pat == matched then - S(tailNodeChoose(args, postFunc, node)) else N - .head) - ComposeResult(k, preFunc :: allPostFunc.map(_._3) ++ defaultPostFunc.map(_._2).toList, orig) - - - def sFunc(func: Func, splitPos: Loc): SplittingMode = - trace[SplittingMode](s"sFunc: ${func.name |> showSym}, $splitPos"): - sNode(func.body, splitPos, func)(identity) - - def sNode(node: Node, splitPos: Loc, thisFunc: Func)(acc: Node => Node): SplittingMode = - trace[SplittingMode](s"sNode: $node"): - node match - case Node.Result(res) => oErrStop(s"sNode: unexpected Result $res") - case Node.Jump(func, args) => - // B mode - val sym = newFunSym(s"${thisFunc.name.nme}_pre") - val pfBody = PreFuncBody(acc) - val fvs = FreeVarAnalysis(info.func).run(node) - val results = fvs.toList - val pf = PreFunc(sym, results, pfBody, thisFunc) - val cs = CallShape(func, none, args) - SplittingMode.B(pf, cs) - case Node.Case(scrutinee, cases, default) => - // C mode - val sym = newFunSym(s"${thisFunc.name.nme}_pre") - val pfBody = PreFuncBody(acc) - val fvs = FreeVarAnalysis(info.func).run(node) - val results = fvs.toList - val pf = PreFunc(sym, results, pfBody, thisFunc) - val cases2 = cases.zipWithIndex.map: - case ((pat, body), i) => - val sym = newFunSym(s"${thisFunc.name.nme}_case$i") - val fvs = FreeVarAnalysis(info.func).run(node) - val pfBody = PostFuncBody(body) - val pf = PostFunc(sym, fvs.toList, pfBody, thisFunc) - (pat, pf) - val default2 = default.map: node => - val sym = newFunSym(s"${thisFunc.name.nme}_default") - val fvs = FreeVarAnalysis(info.func).run(node) - val pfBody = PostFuncBody(node) - val pf = PostFunc(sym, fvs.toList, pfBody, thisFunc) - pf - val caseS = CaseShape(scrutinee, cases2, default2) - SplittingMode.C(pf, caseS) - case Node.Panic(msg) => oErrStop("sNode: unexpected Panic") - case Node.LetExpr(name, expr, body) => - sNode(body, splitPos, thisFunc)(x => Node.LetExpr(name, expr, x)) - case Node.LetMethodCall(names, cls, method, args, body) => - sNode(body, splitPos, thisFunc)(x => Node.LetMethodCall(names, cls, method, args, x)) - case Node.LetCall(names, func, args, body) => - if splitPos == RefEqNode(node) then - // A mode - val sym = newFunSym(s"${thisFunc.name.nme}_pre") - val pfBody = PreFuncBody(acc) - val fvs = FreeVarAnalysis(info.func).run(node) - val results = fvs.toList - val pf = PreFunc(sym, results, pfBody, thisFunc) - val cs = CallShape(func, some(names), args) - SplittingMode.A(pf, PostFunc(func, names, PostFuncBody(body), thisFunc), cs) - else - sNode(body, splitPos, thisFunc)(x => Node.LetCall(names, func, args, x)) - - // yet another thing is to avoid duplication. once we split a function - // the sub-components of the function will be wrapped into a new function - // so the original function should be correspondingly updated. - def rFunc(orig: Func, sm: SplittingMode)(using env: Env): Unit = - val s = RenameUtil() - val nuParams = s.subst(orig.params).toList - val nuArgs = nuParams.map(Expr.Ref(_)).toList - val ComposeResult(k, newFuncs, invalidFunc) = reComposeWithArgs(sm, nuArgs, N, N) - assert(orig.name == invalidFunc.name, s"rFunc: invalidFunc: $invalidFunc, orig: $orig") - env.workingList.remove(invalidFunc) - val nuFunc = Func( - orig.id, - orig.name, - nuParams, - orig.resultNum, - k(Node.Panic("placeholder here")) - ) - newFuncs.foreach(f => info.func.update(f.name, f)) - info.func.update(invalidFunc.name, nuFunc) - - def wrapPost(node: Node)(using env: Env, thisFunc: Func): Node = - val fvs = FreeVarAnalysis(info.func).run(node).toList - val sym = newFunSym(s"${thisFunc.name.nme}_post") - val s = RenameUtil() - val nuBody = renameNode(node)(using s) - val nuParams = s.subst(fvs).toList - val nuFunc = Func(freshInt.make, sym, nuParams, thisFunc.resultNum, nuBody) - info.func.update(sym, nuFunc) - Node.Jump(sym, fvs.map(Expr.Ref(_))) - - def fNode(node: Node)(k: Node => Env ?=> Node)(using env: Env, thisFunc: Func): Node = - trace[Node](s"split fNode: $node"): - node match - case Node.Result(res) => k(node) - case Node.Jump(func, args) => - val sDesc = checkSTarget(info.getFunc(func), args) - (sDesc.argumentsDesc.isEmpty, sDesc.mixingProducer.isEmpty) match - case (true, _) => k(node) - case (false, _) => - val desc = sDesc.argumentsDesc.head - val (sym, SymDDesc(knownC, isInd, e)) = desc - val old = info.getFunc(func) - log(s"splitting: ${old.name |> showSym}") - val sm = sFunc(info.getFunc(func), e.loc) - rFunc(old, sm) - val cr = reComposeWithArgs(sm, args, N, N) - val nuBody = cr.k(Node.Panic("placeholder here")) - k(nuBody) - case Node.Case(scrutinee, cases, default) => - symAndIntroOfTExpr(scrutinee) match - // case Some((scrutinee, I(loc, IInfo.Mixed(i)))) => - // ??? - case _ => - val nuCases = cases.map: - case (p @ Pat.Class(cls), body) => - val old = env.i.intros.put(cls, I(node, IInfo.Ctor(cls))) - val nuBody = fNode(body)(identity) - for i <- old do env.i.intros.update(cls, i) - (p, nuBody) - case (p @ Pat.Lit(lit), body) => - (p, fNode(body)(identity)) - val dfltCase = default.map(fNode(_)(identity)) - k(Node.Case(scrutinee, nuCases, dfltCase)) - case Node.Panic(msg) => node - case Node.LetExpr(name, expr, body) => - fNode(body): inner => - k(Node.LetExpr(name, expr, inner)) - case Node.LetMethodCall(names, cls, method, args, body) => - fNode(body): inner => - k(Node.LetMethodCall(names, cls, method, args, inner)) - case node @ Node.LetCall(names, func, args, body) => - if notBuiltin(func) then - val sDesc = checkSTarget(info.getFunc(func), args) - (sDesc.argumentsDesc.isEmpty, sDesc.mixingProducer.isEmpty) match - case (true, _) => - memoCall(node)(k) - fNode(body): inner => - k(Node.LetCall(names, func, args, inner)) - case (false, _) => - val desc = sDesc.argumentsDesc.head - val (sym, SymDDesc(knownC, isInd, e)) = desc - val old = info.getFunc(func) - log(s"splitting: ${old.name |> showSym}") - val sm = sFunc(info.getFunc(func), e.loc) - rFunc(old, sm) - val cr = reComposeWithArgs(sm, args, S(names), N) - val tail = wrapPost(body) - val nuBody = cr.k(tail) - k(nuBody) - // case (_, false) => ??? - else - fNode(body): inner => - k(Node.LetCall(names, func, args, inner)) - - def fFunc(func: Func)(using env: Env): Unit = - trace[Unit](s"split fFunc: ${func.name |> showSym}"): - val nuFunc = Func(func.id, func.name, func.params, func.resultNum, fNode(func.body)(identity)(using env, func)) - info.func.update(func.name, nuFunc) - - def run() = - val i = IntroductionAnalysis(info) - val iEnv = i.run() - val e = EliminationAnalysis(info) - val eEnv = e.run() - val env = Env(iEnv, eEnv) - env.workingList.addAll(info.func.values) - log(s"workingList: ${env.workingList.iterator.map(_.name).toList}") - while env.workingList.nonEmpty do - val func = env.workingList.head - env.workingList.remove(func) - fFunc(func)(using env) - - private class Simplify(info: ProgInfo): - def simplify = - val newFuncs = info.func.map: - case (name, func) => - val newBody = removeTrivialCallAndJump(func.body)(using MapUtil(Map.empty)) - func.name -> func.copy(body = newBody) - info.func.clear() - info.func.addAll(newFuncs) - val reachable = ProgDfs(info).dfs(true) - log(s"reachableFuncs: ${reachable.funcs.map(showSym).toList}") - log(s"unreachableFuncs: ${info.func.keys.filterNot(reachable.funcs.contains(_)).map(showSym).toList}") - log(s"reachableClasses: ${reachable.classes.map(showSym).toList}") - log(s"unreachableClasses: ${info.classes.keys.filterNot(reachable.classes.contains(_)).map(showSym).toList}") - info.func.filterInPlace((k, _) => reachable.funcs.contains(k)) - info.classes.filterInPlace((k, _) => reachable.classes.contains(k)) - - private def removeTrivialCallAndJump(expr: Expr)(using m: MapUtil): Expr = expr match - case Expr.Ref(name) => Expr.Ref(m.subst(name)) - case Expr.Literal(lit) => expr - case Expr.CtorApp(cls, args) => Expr.CtorApp(cls, m.substT(args).toList) - case Expr.Select(name, cls, field) => Expr.Select(m.subst(name), cls, field) - case Expr.BasicOp(name, args) => Expr.BasicOp(name, m.substT(args).toList) - case Expr.AssignField(assignee, cls, field, value) => - Expr.AssignField(m.subst(assignee), cls, field, m.substT(value)) - - private def removeTrivialCallAndJump(node: Node)(using MapUtil): Node = node match - case Node.Result(res) => Node.Result(summon[MapUtil].substT(res).toList) - case Node.Jump(func, args) => - if notBuiltin(func) then - val funcDefn = info.getFunc(func) - val nuArgs = summon[MapUtil].substT(args).toList - val m = SubstUtil(funcDefn.params.zip(nuArgs).toMap) - funcDefn.body match - case Node.Result(res) => - Node.Result(res.map(_.foldRef(m.subst))) - case Node.Jump(func, args) => - Node.Jump(func, args.map(_.foldRef(m.subst))) - case _ => node - else - node - case Node.Case(scrutinee, cases, default) => - Node.Case(summon[MapUtil].substT(scrutinee), cases.map: - case (pat, body) => pat -> removeTrivialCallAndJump(body), - default.map(removeTrivialCallAndJump(_))) - case Node.Panic(msg) => node - case Node.LetExpr(name, expr, body) => - val nuExpr = removeTrivialCallAndJump(expr) - Node.LetExpr(name, nuExpr, removeTrivialCallAndJump(body)) - case Node.LetMethodCall(names, cls, method, args, body) => - val nuArgs = summon[MapUtil].substT(args).toList - Node.LetMethodCall(names, cls, method, nuArgs, removeTrivialCallAndJump(body)) - case Node.LetCall(names, func, args, body) => - if notBuiltin(func) then - val funcDefn = info.getFunc(func) - val nuArgs = summon[MapUtil].substT(args).toList - val m = SubstUtil(funcDefn.params.zip(nuArgs).toMap) - funcDefn.body match - case Node.Jump(func, args) => - Node.LetCall(names, func, args.map(_.foldRef(m.subst)), removeTrivialCallAndJump(body)) - case _ => node - else - node - - def run(prog: LlirProgram) = - val info = ProgInfo.fromProgram(prog) - if flags.contains("simp") then - val simp = Simplify(info) - simp.simplify - if flags.contains("!split") then - () - else - val splitting = Splitting(info) - splitting.run() - if flags.contains("simp2") then - val simp = Simplify(info) - simp.simplify - info.toProgram - - - class ProgDfs(info: ProgInfo): - import Node._ - import Expr._ - - case class FuncAndClass(funcs: Ls[Local] = Nil, classes: Ls[Local] = Nil): - def addF(func: Local): FuncAndClass = copy(funcs = func :: funcs) - def addC(cls: Local): FuncAndClass = copy(classes = cls :: classes) - - case class Buf(funcs: ListBuffer[Local] = ListBuffer.empty, classes: ListBuffer[Local] = ListBuffer.empty) - - private object Successors: - def find(expr: Expr)(using acc: FuncAndClass): FuncAndClass = - expr match - case Ref(sym) => acc - case Literal(lit) => acc - case CtorApp(cls, args) => acc.addC(cls) - case Select(name, cls, field) => acc.addC(cls) - case BasicOp(name, args) => acc - case AssignField(assignee, cls, field, value) => acc.addC(cls) - - def find(node: Node)(using acc: FuncAndClass): FuncAndClass = - node match - case Result(res) => acc - case Jump(func, args) => if notBuiltin(func) then acc.addF(func) else acc - case Case(scrutinee, cases, default) => - val acc2 = cases.map(_._2) ++ default.toList - acc2.foldLeft(acc)((acc, x) => find(x)(using acc)) - case Panic(msg) => acc - case LetExpr(name, expr, body) => - val acc2 = find(expr) - find(body)(using acc2) - case LetMethodCall(names, cls, method, args, body) => find(body)(using acc.addC(cls)) - case LetCall(names, func, args, body) => find(body)(using if notBuiltin(func) then acc.addF(func) else acc) - - def find(func: Func): FuncAndClass = find(func.body)(using FuncAndClass()) - - private def dfs(using visited: MutHMap[Local, Bool], out: Buf, postfix: Bool)(x: Func): Unit = - trace[Unit](s"dfs: ${{showSym(x.name)}}"): - visited.update(x.name, true) - if !postfix then - out.funcs += x.name - val successors = Successors.find(x) - successors.funcs.foreach: - y => if !visited(y) then - dfs(info.getFunc(y)) - successors.classes.foreach: y => - if notCallable(y) && !visited(y) then - dfs(info.getClass(y)) - if postfix then - out.funcs += x.name - - private def dfs(using visited: MutHMap[Local, Bool], out: Buf, postfix: Bool)(x: ClassInfo): Unit = - trace[Unit](s"dfs: ${{showSym(x.name)}}"): - visited.update(x.name, true) - if !postfix then - out.classes += x.name - x.parents.foreach: y => - if notCallable(y) && !visited(y) then - dfs(info.getClass(y)) - x.methods.values.foreach: m => - val successors = Successors.find(m.body)(using FuncAndClass()) - successors.funcs.foreach: y => - if !visited(y) then - dfs(info.getFunc(y)) - successors.classes.foreach: y => - if notCallable(y) && !visited(y) then - dfs(info.getClass(y)) - if postfix then - out.classes += x.name - - private def dfs(using visited: MutHMap[Local, Bool], out: Buf, postfix: Bool)(x: Node): Unit = - trace[Unit](s"dfs: $x"): - val successors = Successors.find(x)(using FuncAndClass()) - successors.funcs.foreach: y => - if !visited(y) then - dfs(info.getFunc(y)) - successors.classes.foreach: y => - if notCallable(y) && !visited(y) then - dfs(info.getClass(y)) - - def dfs(postfix: Bool): FuncAndClass = - val visited = MutHMap[Local, Bool]() - val allFuncsClassesMethods = info.func.keys ++ info.classes.iterator.keys - visited.addAll(allFuncsClassesMethods.map(k => k -> false)) - val out = Buf(ListBuffer.empty, ListBuffer.empty) - dfs(using visited, out, postfix)(info.func.get(info.entry).get) - FuncAndClass(out.funcs.toList, out.classes.toList) - diff --git a/hkmc2/shared/src/test/mlscript/llir/Legacy.mls b/hkmc2/shared/src/test/mlscript/llir/Legacy.mls index 38bb272ca4..a4fa93b8b8 100644 --- a/hkmc2/shared/src/test/mlscript/llir/Legacy.mls +++ b/hkmc2/shared/src/test/mlscript/llir/Legacy.mls @@ -1,15 +1,7 @@ :js :llir :cpp -:sopt -:optf simp,simp2,!split -//│ -//│ Opt: -//│ -//│ def entry$566() = -//│ undefined -//│ entry = entry$566 :global :intl @@ -21,22 +13,6 @@ fun foo() = foo() //│ = Pair() //│ -//│ Opt: -//│ class Pair(x$576,y$577) -//│ def mktup2$570(x$581,y$582) = -//│ let* (x$596) = mktup(x$581,y$582) in -//│ x$596 -//│ def mktup$568(x$586,y$587) = -//│ let x$597 = Pair$572(x$586,y$587) in -//│ x$597 -//│ def foo$569() = -//│ let* (x$598) = mktup2(1,2) in -//│ x$598 -//│ def entry$600() = -//│ let* (x$599) = foo() in -//│ x$599 -//│ entry = entry$600 -//│ //│ Interpreted: //│ Pair(1,2) @@ -50,26 +26,6 @@ fun bar() = bar() //│ = Pair() //│ -//│ Opt: -//│ class Pair(x$609,y$610) -//│ def foo$603(pair$614) = -//│ case pair$614 of -//│ Pair$605 => -//│ let x$633 = pair$614. in -//│ let x$634 = pair$614. in -//│ let x$635 = Pair$605(x$633,x$634) in -//│ x$635 -//│ _ => -//│ panic "match error" -//│ def bar$602() = -//│ let x$636 = Pair$605(1,2) in -//│ let* (x$637) = foo(x$636) in -//│ x$637 -//│ def entry$639() = -//│ let* (x$638) = bar() in -//│ x$638 -//│ entry = entry$639 -//│ //│ Interpreted: //│ Pair(1,2) @@ -83,26 +39,6 @@ fun bar() = bar() //│ = Pair() //│ -//│ Opt: -//│ class Pair(x$648,y$649) -//│ def foo$642(pair$653) = -//│ case pair$653 of -//│ Pair$644 => -//│ let x$672 = pair$653. in -//│ let x$673 = pair$653. in -//│ let x$674 = Pair$644(x$672,x$673) in -//│ x$674 -//│ _ => -//│ panic "match error" -//│ def bar$641() = -//│ let x$675 = Pair$644(1,2) in -//│ let* (x$676) = foo(x$675) in -//│ x$676 -//│ def entry$678() = -//│ let* (x$677) = bar() in -//│ x$677 -//│ entry = entry$678 -//│ //│ Interpreted: //│ Pair(1,2) @@ -122,36 +58,6 @@ fun foo() = foo() //│ = NaN //│ -//│ Opt: -//│ class Pair(x$687,y$688) -//│ def silly$680(pair$692) = -//│ let x$725 = 0 in -//│ case pair$692 of -//│ Pair$683 => -//│ let x$727 = pair$692. in -//│ let x$728 = pair$692. in -//│ case pair$692 of -//│ Pair$683 => -//│ let x$730 = pair$692. in -//│ let x$731 = pair$692. in -//│ let x$732 = +(x$730,1) in -//│ jump j$726(x$732) -//│ _ => -//│ panic "match error" -//│ _ => -//│ panic "match error" -//│ def j$726(tmp$722) = -//│ let x$733 = +(tmp$722,1) in -//│ x$733 -//│ def foo$681() = -//│ let x$734 = Pair$683(0,1) in -//│ let* (x$735) = silly(x$734) in -//│ x$735 -//│ def entry$737() = -//│ let* (x$736) = foo() in -//│ x$736 -//│ entry = entry$737 -//│ //│ Interpreted: //│ 2 @@ -168,27 +74,6 @@ fun foo() = foo() //│ = NaN //│ -//│ Opt: -//│ class Pair(x$746,y$747) -//│ def inc_fst$739(pair$751) = -//│ let x$774 = 2 in -//│ case pair$751 of -//│ Pair$742 => -//│ let x$776 = pair$751. in -//│ let x$777 = pair$751. in -//│ let x$778 = +(x$776,x$774) in -//│ x$778 -//│ _ => -//│ panic "match error" -//│ def foo$740() = -//│ let x$779 = Pair$742(0,1) in -//│ let* (x$780) = inc_fst(x$779) in -//│ x$780 -//│ def entry$782() = -//│ let* (x$781) = foo() in -//│ x$781 -//│ entry = entry$782 -//│ //│ Interpreted: //│ 2 @@ -204,27 +89,6 @@ fun foo() = foo() //│ = NaN //│ -//│ Opt: -//│ class Pair(x$791,y$792) -//│ def inc_fst$784(pair$796) = -//│ let x$818 = 0 in -//│ case pair$796 of -//│ Pair$787 => -//│ let x$820 = pair$796. in -//│ let x$821 = pair$796. in -//│ let x$822 = +(x$821,1) in -//│ x$822 -//│ _ => -//│ panic "match error" -//│ def foo$785() = -//│ let x$823 = Pair$787(0,1) in -//│ let* (x$824) = inc_fst(x$823) in -//│ x$824 -//│ def entry$826() = -//│ let* (x$825) = foo() in -//│ x$825 -//│ entry = entry$826 -//│ //│ Interpreted: //│ 2 @@ -244,42 +108,6 @@ fun bar() = bar() //│ = 2 //│ -//│ Opt: -//│ class Either() -//│ class Left(x$841) extends Either -//│ class Right(y$848) extends Either -//│ def foo$832(a$852,b$853) = -//│ case a$852 of -//│ Left$837 => -//│ let x$883 = a$852. in -//│ let x$884 = +(x$883,1) in -//│ let x$885 = Left$837(x$884) in -//│ jump j$882(x$885) -//│ Right$844 => -//│ let x$886 = a$852. in -//│ let x$887 = Right$844(b$853) in -//│ jump j$882(x$887) -//│ _ => -//│ panic "match error" -//│ def j$882(tmp$880) = -//│ case tmp$880 of -//│ Left$837 => -//│ let x$889 = tmp$880. in -//│ x$889 -//│ Right$844 => -//│ let x$890 = tmp$880. in -//│ x$890 -//│ _ => -//│ panic "match error" -//│ def bar$830() = -//│ let x$891 = Right$844(2) in -//│ let* (x$892) = foo(x$891,2) in -//│ x$892 -//│ def entry$894() = -//│ let* (x$893) = bar() in -//│ x$893 -//│ entry = entry$894 -//│ //│ Interpreted: //│ 2 @@ -298,32 +126,6 @@ fun baz(x) = foo() //│ = O //│ -//│ Opt: -//│ class Nat() -//│ class S(s$906) extends Nat -//│ class O() extends Nat -//│ def foo$901() = -//│ let x$931 = O$909() in -//│ let x$932 = S$904(x$931) in -//│ let* (x$933) = bar(x$932) in -//│ x$933 -//│ def bar$897(x$916) = -//│ let* (x$934) = baz(x$916) in -//│ x$934 -//│ def baz$898(x$920) = -//│ case x$920 of -//│ S$904 => -//│ let x$936 = x$920. in -//│ x$936 -//│ O$909 => -//│ x$920 -//│ _ => -//│ panic "match error" -//│ def entry$938() = -//│ let* (x$937) = foo() in -//│ x$937 -//│ entry = entry$938 -//│ //│ Interpreted: //│ O() @@ -345,55 +147,6 @@ fun bar() = bar() //│ = NaN //│ -//│ Opt: -//│ class A(x$946,y$947,z$948) -//│ class B(m$954,n$955) -//│ def complex_foo$943(t$959) = -//│ case t$959 of -//│ A$944 => -//│ let x$1018 = t$959. in -//│ let x$1019 = t$959. in -//│ let x$1020 = t$959. in -//│ let x$1021 = *(x$1019,x$1020) in -//│ let x$1022 = +(x$1018,x$1021) in -//│ jump j$1017(x$1022) -//│ B$952 => -//│ let x$1023 = t$959. in -//│ let x$1024 = t$959. in -//│ let x$1025 = -(x$1023,x$1024) in -//│ jump j$1017(x$1025) -//│ _ => -//│ panic "match error" -//│ def j$1017(tmp$1011) = -//│ let x$1026 = B$952(1,2) in -//│ case x$1026 of -//│ A$944 => -//│ let x$1028 = x$1026. in -//│ let x$1029 = x$1026. in -//│ let x$1030 = x$1026. in -//│ let x$1031 = 3 in -//│ jump j$1027(x$1031,tmp$1011) -//│ B$952 => -//│ let x$1032 = x$1026. in -//│ let x$1033 = x$1026. in -//│ let x$1034 = 4 in -//│ jump j$1027(x$1034,tmp$1011) -//│ _ => -//│ panic "match error" -//│ def j$1027(tmp$1013,r$960) = -//│ let x$1035 = +(r$960,tmp$1013) in -//│ x$1035 -//│ def bar$942() = -//│ let x$1036 = A$944(6,7,8) in -//│ let* (x$1037) = complex_foo(x$1036) in -//│ let x$1038 = B$952(9,10) in -//│ let* (x$1039) = complex_foo(x$1038) in -//│ x$1039 -//│ def entry$1041() = -//│ let* (x$1040) = bar() in -//│ x$1040 -//│ entry = entry$1041 -//│ //│ Interpreted: //│ 3 @@ -432,99 +185,6 @@ fun bar() = bar() //│ = 5 //│ -//│ Opt: -//│ class A(w$1050,x$1051) -//│ class B(y$1058) -//│ class C(z$1063) -//│ def complex_foo$1044(t$1067) = -//│ let x$1164 = +(1,2) in -//│ let x$1165 = *(1,2) in -//│ case t$1067 of -//│ A$1048 => -//│ let x$1167 = t$1067. in -//│ let x$1168 = t$1067. in -//│ jump j$1166(x$1164,x$1168,x$1165) -//│ B$1056 => -//│ let x$1169 = t$1067. in -//│ let x$1170 = +(x$1169,x$1165) in -//│ let x$1171 = B$1056(x$1170) in -//│ jump j$1166(x$1164,x$1171,x$1165) -//│ C$1061 => -//│ let x$1172 = t$1067. in -//│ let x$1173 = C$1061(0) in -//│ jump j$1166(x$1164,x$1173,x$1165) -//│ _ => -//│ panic "match error" -//│ def j$1166(a$1068,tmp$1153,b$1070) = -//│ let x$1174 = A$1048(5,tmp$1153) in -//│ let x$1175 = B$1056(6) in -//│ case tmp$1153 of -//│ A$1048 => -//│ let x$1177 = tmp$1153. in -//│ let x$1178 = tmp$1153. in -//│ let x$1179 = +(x$1177,a$1068) in -//│ let x$1180 = +(x$1179,b$1070) in -//│ case x$1178 of -//│ A$1048 => -//│ let x$1182 = x$1178. in -//│ let x$1183 = x$1178. in -//│ jump j$1176(x$1182,x$1174,x$1175) -//│ B$1056 => -//│ let x$1184 = x$1178. in -//│ jump j$1176(x$1180,x$1174,x$1175) -//│ C$1061 => -//│ let x$1185 = x$1178. in -//│ let x$1186 = 0 in -//│ jump j$1176(x$1186,x$1174,x$1175) -//│ _ => -//│ panic "match error" -//│ B$1056 => -//│ let x$1187 = tmp$1153. in -//│ let x$1188 = 2 in -//│ jump j$1176(x$1188,x$1174,x$1175) -//│ C$1061 => -//│ let x$1189 = tmp$1153. in -//│ let x$1190 = 3 in -//│ jump j$1176(x$1190,x$1174,x$1175) -//│ _ => -//│ panic "match error" -//│ def j$1176(tmp$1160,z$1084,v$1086) = -//│ case z$1084 of -//│ A$1048 => -//│ let x$1192 = z$1084. in -//│ let x$1193 = z$1084. in -//│ x$1192 -//│ B$1056 => -//│ let x$1194 = z$1084. in -//│ 4 -//│ C$1061 => -//│ let x$1195 = z$1084. in -//│ case v$1086 of -//│ A$1048 => -//│ let x$1197 = v$1086. in -//│ let x$1198 = v$1086. in -//│ x$1197 -//│ B$1056 => -//│ let x$1199 = v$1086. in -//│ 7 -//│ C$1061 => -//│ let x$1200 = v$1086. in -//│ 8 -//│ _ => -//│ panic "match error" -//│ _ => -//│ panic "match error" -//│ def bar$1046() = -//│ let x$1201 = B$1056(10) in -//│ let x$1202 = A$1048(9,x$1201) in -//│ let x$1203 = A$1048(10,x$1202) in -//│ let* (x$1204) = complex_foo(x$1203) in -//│ x$1204 -//│ def entry$1206() = -//│ let* (x$1205) = bar() in -//│ x$1205 -//│ entry = entry$1206 -//│ //│ Interpreted: //│ 5 @@ -533,25 +193,6 @@ fun fib(n) = if n < 2 then n else fib(n-1) + fib(n-2) fib(20) //│ = 6765 //│ -//│ Opt: -//│ -//│ def fib$1208(n$1210) = -//│ let x$1230 = <(n$1210,2) in -//│ case x$1230 of -//│ BoolLit(true) => -//│ n$1210 -//│ _ => -//│ let x$1232 = -(n$1210,1) in -//│ let* (x$1233) = fib(x$1232) in -//│ let x$1234 = -(n$1210,2) in -//│ let* (x$1235) = fib(x$1234) in -//│ let x$1236 = +(x$1233,x$1235) in -//│ x$1236 -//│ def entry$1238() = -//│ let* (x$1237) = fib(20) in -//│ x$1237 -//│ entry = entry$1238 -//│ //│ Interpreted: //│ 6765 @@ -562,34 +203,6 @@ fun foo() = odd(10) foo() //│ = false //│ -//│ Opt: -//│ -//│ def odd$1242(x$1244) = -//│ let x$1267 = ==(x$1244,0) in -//│ case x$1267 of -//│ BoolLit(true) => -//│ false -//│ _ => -//│ let x$1269 = -(x$1244,1) in -//│ let* (x$1270) = even(x$1269) in -//│ x$1270 -//│ def even$1240(x$1251) = -//│ let x$1271 = ==(x$1251,0) in -//│ case x$1271 of -//│ BoolLit(true) => -//│ true -//│ _ => -//│ let x$1273 = -(x$1251,1) in -//│ let* (x$1274) = odd(x$1273) in -//│ x$1274 -//│ def foo$1241() = -//│ let* (x$1275) = odd(10) in -//│ x$1275 -//│ def entry$1277() = -//│ let* (x$1276) = foo() in -//│ x$1276 -//│ entry = entry$1277 -//│ //│ Interpreted: //│ false @@ -606,34 +219,6 @@ fun main() = foo(false) main() //│ = Some() //│ -//│ Opt: -//│ class Option() -//│ class Some(x$1291) extends Option -//│ class None() extends Option -//│ def not$1281(x$1296) = -//│ case x$1296 of -//│ BoolLit(true) => -//│ false -//│ _ => -//│ true -//│ def foo$1284(x$1299) = -//│ case x$1299 of -//│ BoolLit(true) => -//│ let x$1317 = None$1293() in -//│ x$1317 -//│ _ => -//│ let* (x$1318) = not(x$1299) in -//│ let* (x$1319) = foo(x$1318) in -//│ let x$1320 = Some$1288(x$1319) in -//│ x$1320 -//│ def main$1279() = -//│ let* (x$1321) = foo(false) in -//│ x$1321 -//│ def entry$1323() = -//│ let* (x$1322) = main() in -//│ x$1322 -//│ entry = entry$1323 -//│ //│ Interpreted: //│ Some(None()) @@ -667,57 +252,6 @@ fun main() = main() //│ = 404 //│ -//│ Opt: -//│ class Option() -//│ class Some(x$1343) extends Option -//│ class None() extends Option -//│ def aaa$1331() = -//│ let x$1414 = 1 in -//│ let x$1415 = 2 in -//│ let x$1416 = 3 in -//│ let x$1417 = 4 in -//│ let x$1418 = +(x$1414,x$1415) in -//│ let x$1419 = -(x$1418,x$1416) in -//│ let x$1420 = +(x$1419,x$1417) in -//│ x$1420 -//│ def bbb$1333() = -//│ let* (x$1421) = aaa() in -//│ let x$1422 = *(x$1421,100) in -//│ let x$1423 = +(x$1422,4) in -//│ x$1423 -//│ def not$1329(x$1376) = -//│ case x$1376 of -//│ BoolLit(true) => -//│ false -//│ _ => -//│ true -//│ def foo$1336(x$1379) = -//│ case x$1379 of -//│ BoolLit(true) => -//│ let x$1426 = None$1345() in -//│ x$1426 -//│ _ => -//│ let* (x$1427) = not(x$1379) in -//│ let* (x$1428) = foo(x$1427) in -//│ let x$1429 = Some$1340(x$1428) in -//│ x$1429 -//│ def main$1327() = -//│ let* (x$1430) = foo(false) in -//│ case x$1430 of -//│ None$1345 => -//│ let* (x$1432) = aaa() in -//│ x$1432 -//│ Some$1340 => -//│ let x$1433 = x$1430. in -//│ let* (x$1434) = bbb() in -//│ x$1434 -//│ _ => -//│ panic "match error" -//│ def entry$1436() = -//│ let* (x$1435) = main() in -//│ x$1435 -//│ entry = entry$1436 -//│ //│ Interpreted: //│ 404 @@ -737,42 +271,6 @@ fun foo() = odd(S(S(S(O)))) foo() //│ = true //│ -//│ Opt: -//│ class Nat() -//│ class S(s$1448) extends Nat -//│ class O() extends Nat -//│ def odd$1439(x$1454) = -//│ case x$1454 of -//│ O$1451 => -//│ false -//│ S$1446 => -//│ let x$1483 = x$1454. in -//│ let* (x$1484) = even(x$1483) in -//│ x$1484 -//│ _ => -//│ panic "match error" -//│ def even$1440(x$1460) = -//│ case x$1460 of -//│ O$1451 => -//│ true -//│ S$1446 => -//│ let x$1486 = x$1460. in -//│ let* (x$1487) = odd(x$1486) in -//│ x$1487 -//│ _ => -//│ panic "match error" -//│ def foo$1443() = -//│ let x$1488 = O$1451() in -//│ let x$1489 = S$1446(x$1488) in -//│ let x$1490 = S$1446(x$1489) in -//│ let x$1491 = S$1446(x$1490) in -//│ let* (x$1492) = odd(x$1491) in -//│ x$1492 -//│ def entry$1494() = -//│ let* (x$1493) = foo() in -//│ x$1493 -//│ entry = entry$1494 -//│ //│ Interpreted: //│ true @@ -793,50 +291,6 @@ fun foo() = odd(mk(10)) foo() //│ = false //│ -//│ Opt: -//│ class Nat() -//│ class S(s$1507) extends Nat -//│ class O() extends Nat -//│ def odd$1497(x$1513) = -//│ case x$1513 of -//│ O$1510 => -//│ false -//│ S$1505 => -//│ let x$1548 = x$1513. in -//│ let* (x$1549) = even(x$1548) in -//│ x$1549 -//│ _ => -//│ panic "match error" -//│ def even$1499(x$1519) = -//│ case x$1519 of -//│ O$1510 => -//│ true -//│ S$1505 => -//│ let x$1551 = x$1519. in -//│ let* (x$1552) = odd(x$1551) in -//│ x$1552 -//│ _ => -//│ panic "match error" -//│ def mk$1498(n$1525) = -//│ let x$1553 = >(n$1525,0) in -//│ case x$1553 of -//│ BoolLit(true) => -//│ let x$1555 = -(n$1525,1) in -//│ let* (x$1556) = mk(x$1555) in -//│ let x$1557 = S$1505(x$1556) in -//│ x$1557 -//│ _ => -//│ let x$1558 = O$1510() in -//│ x$1558 -//│ def foo$1502() = -//│ let* (x$1559) = mk(10) in -//│ let* (x$1560) = odd(x$1559) in -//│ x$1560 -//│ def entry$1562() = -//│ let* (x$1561) = foo() in -//│ x$1561 -//│ entry = entry$1562 -//│ //│ Interpreted: //│ false @@ -857,52 +311,6 @@ fun foo() = odd(S(S(mk(10)))) foo() //│ = false //│ -//│ Opt: -//│ class Nat() -//│ class S(s$1575) extends Nat -//│ class O() extends Nat -//│ def odd$1565(x$1581) = -//│ case x$1581 of -//│ O$1578 => -//│ false -//│ S$1573 => -//│ let x$1622 = x$1581. in -//│ let* (x$1623) = even(x$1622) in -//│ x$1623 -//│ _ => -//│ panic "match error" -//│ def even$1567(x$1587) = -//│ case x$1587 of -//│ O$1578 => -//│ true -//│ S$1573 => -//│ let x$1625 = x$1587. in -//│ let* (x$1626) = odd(x$1625) in -//│ x$1626 -//│ _ => -//│ panic "match error" -//│ def mk$1566(n$1593) = -//│ let x$1627 = >(n$1593,0) in -//│ case x$1627 of -//│ BoolLit(true) => -//│ let x$1629 = -(n$1593,1) in -//│ let* (x$1630) = mk(x$1629) in -//│ let x$1631 = S$1573(x$1630) in -//│ x$1631 -//│ _ => -//│ let x$1632 = O$1578() in -//│ x$1632 -//│ def foo$1570() = -//│ let* (x$1633) = mk(10) in -//│ let x$1634 = S$1573(x$1633) in -//│ let x$1635 = S$1573(x$1634) in -//│ let* (x$1636) = odd(x$1635) in -//│ x$1636 -//│ def entry$1638() = -//│ let* (x$1637) = foo() in -//│ x$1637 -//│ entry = entry$1638 -//│ //│ Interpreted: //│ false @@ -927,64 +335,6 @@ fun main() = main() //│ = true //│ -//│ Opt: -//│ class Nat() -//│ class S(s$1652) extends Nat -//│ class O() extends Nat -//│ def odd$1641(x$1658) = -//│ case x$1658 of -//│ O$1655 => -//│ false -//│ S$1650 => -//│ let x$1698 = x$1658. in -//│ let* (x$1699) = even(x$1698) in -//│ x$1699 -//│ _ => -//│ panic "match error" -//│ def even$1643(x$1664) = -//│ case x$1664 of -//│ O$1655 => -//│ true -//│ S$1650 => -//│ let x$1701 = x$1664. in -//│ let* (x$1702) = odd(x$1701) in -//│ x$1702 -//│ _ => -//│ panic "match error" -//│ def foo$1647() = -//│ let x$1703 = >(10,0) in -//│ case x$1703 of -//│ BoolLit(true) => -//│ let x$1705 = O$1655() in -//│ let x$1706 = S$1650(x$1705) in -//│ jump j$1704(x$1706) -//│ _ => -//│ let x$1707 = O$1655() in -//│ jump j$1704(x$1707) -//│ def j$1704(tmp$1694) = -//│ let* (x$1708) = odd(tmp$1694) in -//│ x$1708 -//│ def bar$1644() = -//│ let x$1709 = >(10,0) in -//│ case x$1709 of -//│ BoolLit(true) => -//│ let x$1711 = O$1655() in -//│ let x$1712 = S$1650(x$1711) in -//│ let* (x$1713) = odd(x$1712) in -//│ x$1713 -//│ _ => -//│ let x$1715 = O$1655() in -//│ let* (x$1714) = odd(x$1715) in -//│ x$1714 -//│ def main$1642() = -//│ let* (x$1716) = foo() in -//│ let* (x$1717) = bar() in -//│ x$1717 -//│ def entry$1719() = -//│ let* (x$1718) = main() in -//│ x$1718 -//│ entry = entry$1719 -//│ //│ Interpreted: //│ true @@ -1011,49 +361,6 @@ fun main() = main() //│ = false //│ -//│ Opt: -//│ class Option() -//│ class Some(x$1737) extends Option -//│ class None() extends Option -//│ class List() -//│ class Cons(head$1747,tail$1748) extends List -//│ class Nil() extends List -//│ def head_opt$1724(l$1754) = -//│ case l$1754 of -//│ Nil$1751 => -//│ let x$1791 = None$1739() in -//│ x$1791 -//│ Cons$1744 => -//│ let x$1792 = l$1754. in -//│ let x$1793 = l$1754. in -//│ let x$1794 = Some$1734(x$1792) in -//│ x$1794 -//│ _ => -//│ panic "match error" -//│ def is_none$1729(o$1762) = -//│ case o$1762 of -//│ None$1739 => -//│ true -//│ Some$1734 => -//│ let x$1796 = o$1762. in -//│ false -//│ _ => -//│ panic "match error" -//│ def is_empty$1730(l$1767) = -//│ let* (x$1797) = head_opt(l$1767) in -//│ let* (x$1798) = is_none(x$1797) in -//│ x$1798 -//│ def main$1722() = -//│ let x$1799 = Nil$1751() in -//│ let x$1800 = Cons$1744(2,x$1799) in -//│ let x$1801 = Cons$1744(1,x$1800) in -//│ let* (x$1802) = is_empty(x$1801) in -//│ x$1802 -//│ def entry$1804() = -//│ let* (x$1803) = main() in -//│ x$1803 -//│ entry = entry$1804 -//│ //│ Interpreted: //│ false @@ -1081,58 +388,6 @@ fun main() = main() //│ = false //│ -//│ Opt: -//│ class Option() -//│ class Some(x$1823) extends Option -//│ class None() extends Option -//│ class List() -//│ class Cons(head$1833,tail$1834) extends List -//│ class Nil() extends List -//│ def mk_list$1807(n$1840) = -//│ let x$1885 = ==(n$1840,0) in -//│ case x$1885 of -//│ BoolLit(true) => -//│ let x$1887 = Nil$1837() in -//│ x$1887 -//│ _ => -//│ let x$1888 = -(n$1840,1) in -//│ let* (x$1889) = mk_list(x$1888) in -//│ let x$1890 = Cons$1830(n$1840,x$1889) in -//│ x$1890 -//│ def head_opt$1810(l$1848) = -//│ case l$1848 of -//│ Nil$1837 => -//│ let x$1892 = None$1825() in -//│ x$1892 -//│ Cons$1830 => -//│ let x$1893 = l$1848. in -//│ let x$1894 = l$1848. in -//│ let x$1895 = Some$1820(x$1893) in -//│ x$1895 -//│ _ => -//│ panic "match error" -//│ def is_none$1815(o$1856) = -//│ case o$1856 of -//│ None$1825 => -//│ true -//│ Some$1820 => -//│ let x$1897 = o$1856. in -//│ false -//│ _ => -//│ panic "match error" -//│ def is_empty$1816(l$1861) = -//│ let* (x$1898) = head_opt(l$1861) in -//│ let* (x$1899) = is_none(x$1898) in -//│ x$1899 -//│ def main$1808() = -//│ let* (x$1900) = mk_list(10) in -//│ let* (x$1901) = is_empty(x$1900) in -//│ x$1901 -//│ def entry$1903() = -//│ let* (x$1902) = main() in -//│ x$1902 -//│ entry = entry$1903 -//│ //│ Interpreted: //│ false @@ -1158,54 +413,6 @@ fun main() = main() //│ = Some(1) //│ -//│ Opt: -//│ class Option() -//│ class Some(x$1920) extends Option -//│ class None() extends Option -//│ class List() -//│ class Cons(head$1931,tail$1932) extends List -//│ class Nil() extends List -//│ def mk_list$1906(n$1940) = -//│ let x$1977 = ==(n$1940,0) in -//│ case x$1977 of -//│ BoolLit(true) => -//│ let x$1979 = Nil$1937() in -//│ x$1979 -//│ _ => -//│ let x$1980 = -(n$1940,1) in -//│ let* (x$1981) = mk_list(x$1980) in -//│ let x$1982 = Cons$1928(n$1940,x$1981) in -//│ x$1982 -//│ def last_opt$1913(l$1948) = -//│ case l$1948 of -//│ Nil$1937 => -//│ let x$1984 = None$1923() in -//│ x$1984 -//│ Cons$1928 => -//│ let x$1985 = l$1948. in -//│ let x$1986 = l$1948. in -//│ case x$1986 of -//│ Nil$1937 => -//│ let x$1988 = Some$1917(x$1985) in -//│ x$1988 -//│ Cons$1928 => -//│ let x$1989 = x$1986. in -//│ let x$1990 = x$1986. in -//│ let* (x$1991) = last_opt(x$1986) in -//│ x$1991 -//│ _ => -//│ panic "match error" -//│ _ => -//│ panic "match error" -//│ def main$1912() = -//│ let* (x$1992) = mk_list(10) in -//│ let* (x$1993) = last_opt(x$1992) in -//│ x$1993 -//│ def entry$1995() = -//│ let* (x$1994) = main() in -//│ x$1994 -//│ entry = entry$1995 -//│ //│ Interpreted: //│ Some(1) @@ -1241,79 +448,6 @@ fun main() = main() //│ = NaN //│ -//│ Opt: -//│ class Option() -//│ class Some(x$2013) extends Option -//│ class None() extends Option -//│ def is_some$2005(o$2018) = -//│ case o$2018 of -//│ Some$2010 => -//│ let x$2114 = o$2018. in -//│ true -//│ None$2015 => -//│ false -//│ _ => -//│ panic "match error" -//│ def e0$1999(w$2023) = -//│ let x$2115 = +(w$2023,8) in -//│ let x$2116 = +(x$2115,9) in -//│ let x$2117 = +(x$2116,10) in -//│ x$2117 -//│ def e1$1997(a$2029,c$2030) = -//│ let x$2118 = +(a$2029,1) in -//│ let x$2119 = +(x$2118,2) in -//│ let x$2120 = +(x$2119,3) in -//│ let x$2121 = +(x$2120,4) in -//│ x$2121 -//│ def e3$2001(c$2037) = -//│ let x$2122 = 4 in -//│ let x$2123 = 5 in -//│ let x$2124 = 6 in -//│ let x$2125 = 7 in -//│ case c$2037 of -//│ BoolLit(true) => -//│ let x$2127 = +(x$2122,x$2123) in -//│ let x$2128 = +(x$2127,x$2124) in -//│ let x$2129 = +(x$2128,x$2125) in -//│ x$2129 -//│ _ => -//│ let x$2130 = +(x$2122,x$2123) in -//│ let x$2131 = -(x$2130,x$2124) in -//│ let x$2132 = +(x$2131,x$2125) in -//│ x$2132 -//│ def e2$2006(x$2050) = -//│ let x$2133 = +(x$2050,12) in -//│ let x$2134 = +(x$2133,13) in -//│ let x$2135 = +(x$2134,14) in -//│ x$2135 -//│ def f$1998(x$2056) = -//│ let* (x$2136) = is_some(x$2056) in -//│ let* (x$2137) = e3(x$2136) in -//│ case x$2056 of -//│ Some$2010 => -//│ let x$2139 = x$2056. in -//│ let* (x$2140) = e1(x$2139,x$2137) in -//│ jump j$2138(x$2140) -//│ None$2015 => -//│ let* (x$2141) = e2(x$2137) in -//│ jump j$2138(x$2141) -//│ _ => -//│ panic "match error" -//│ def j$2138(tmp$2109) = -//│ let* (x$2142) = e0(tmp$2109) in -//│ x$2142 -//│ def main$2000() = -//│ let x$2143 = Some$2010(2) in -//│ let* (x$2144) = f(x$2143) in -//│ let x$2146 = None$2015() in -//│ let* (x$2145) = f(x$2146) in -//│ let x$2147 = +(x$2144,x$2145) in -//│ x$2147 -//│ def entry$2149() = -//│ let* (x$2148) = main() in -//│ x$2148 -//│ entry = entry$2149 -//│ //│ Interpreted: //│ 115 @@ -1348,75 +482,5 @@ fun main() = main() //│ = 89 //│ -//│ Opt: -//│ class Nat() -//│ class S(s$2164) extends Nat -//│ class O() extends Nat -//│ def plus$2152(n1$2175,n2$2176) = -//│ case n1$2175 of -//│ O$2167 => -//│ n2$2176 -//│ S$2162 => -//│ let x$2239 = n1$2175. in -//│ let* (x$2240) = plus(x$2239,n2$2176) in -//│ let x$2241 = S$2162(x$2240) in -//│ x$2241 -//│ _ => -//│ panic "match error" -//│ def fib$2156(n$2183) = -//│ case n$2183 of -//│ O$2167 => -//│ let x$2243 = O$2167() in -//│ let x$2244 = S$2162(x$2243) in -//│ x$2244 -//│ S$2162 => -//│ let x$2245 = n$2183. in -//│ case x$2245 of -//│ O$2167 => -//│ let x$2247 = O$2167() in -//│ let x$2248 = S$2162(x$2247) in -//│ x$2248 -//│ S$2162 => -//│ let x$2249 = x$2245. in -//│ let* (x$2250) = fib(x$2245) in -//│ let* (x$2251) = fib(x$2249) in -//│ let* (x$2252) = plus(x$2250,x$2251) in -//│ x$2252 -//│ _ => -//│ panic "match error" -//│ _ => -//│ panic "match error" -//│ def to_int$2158(n$2195) = -//│ case n$2195 of -//│ O$2167 => -//│ 0 -//│ S$2162 => -//│ let x$2254 = n$2195. in -//│ let* (x$2255) = to_int(x$2254) in -//│ let x$2256 = +(1,x$2255) in -//│ x$2256 -//│ _ => -//│ panic "match error" -//│ def to_nat$2151(n$2202) = -//│ let x$2257 = ==(n$2202,0) in -//│ case x$2257 of -//│ BoolLit(true) => -//│ let x$2259 = O$2167() in -//│ x$2259 -//│ _ => -//│ let x$2260 = -(n$2202,1) in -//│ let* (x$2261) = to_nat(x$2260) in -//│ let x$2262 = S$2162(x$2261) in -//│ x$2262 -//│ def main$2153() = -//│ let* (x$2263) = to_nat(10) in -//│ let* (x$2264) = fib(x$2263) in -//│ let* (x$2265) = to_int(x$2264) in -//│ x$2265 -//│ def entry$2267() = -//│ let* (x$2266) = main() in -//│ x$2266 -//│ entry = entry$2267 -//│ //│ Interpreted: //│ 89 diff --git a/hkmc2/shared/src/test/mlscript/llir/nofib/atom.mls b/hkmc2/shared/src/test/mlscript/llir/nofib/atom.mls index ce7bfe3323..3bd8f38625 100644 --- a/hkmc2/shared/src/test/mlscript/llir/nofib/atom.mls +++ b/hkmc2/shared/src/test/mlscript/llir/nofib/atom.mls @@ -42,8 +42,6 @@ fun testAtom_nofib(n) = state :: t then stringConcat(show(state), "\n") :: lscomp(t) stringListConcat of lscomp(take_lz(n, runExperiment(testforce, 0.02, 1.0 :: Nil, State(1.0 :: Nil, 0.0 :: Nil)))) -:wholeOpt -:wholeOptFlags simp,!split :runWholeCpp :runWholeCpp testAtom_nofib(20) diff --git a/hkmc2/shared/src/test/mlscript/llir/nofib/awards.mls b/hkmc2/shared/src/test/mlscript/llir/nofib/awards.mls index 86f3a8d494..9bcfe86bf9 100644 --- a/hkmc2/shared/src/test/mlscript/llir/nofib/awards.mls +++ b/hkmc2/shared/src/test/mlscript/llir/nofib/awards.mls @@ -68,8 +68,6 @@ fun competitors(i) = fun testAwards_nofib(n) = map(x => print(findallawards(competitors(intMod(x, 100)))), enumFromTo(1, n)) -:wholeOpt -:wholeOptFlags simp,!split :runWholeCpp testAwards_nofib(100) //│ diff --git a/hkmc2/shared/src/test/mlscript/llir/nofib/constraints.mls b/hkmc2/shared/src/test/mlscript/llir/nofib/constraints.mls index 16528c1cf8..8d8a7e9ecb 100644 --- a/hkmc2/shared/src/test/mlscript/llir/nofib/constraints.mls +++ b/hkmc2/shared/src/test/mlscript/llir/nofib/constraints.mls @@ -276,9 +276,6 @@ fun try_(n, algorithm) = listLen(search(algorithm, queens(n))) fun testConstraints_nofib(n) = map(x => try_(n, x), bt :: bm :: bjbt :: bjbt_ :: fc :: Nil) - -:wholeOpt -:wholeOptFlags simp,!split :runWholeCpp print(testConstraints_nofib(6)) //│ diff --git a/hkmc2/shared/src/test/mlscript/llir/nofib/scc.mls b/hkmc2/shared/src/test/mlscript/llir/nofib/scc.mls index daeb5a1f43..1aa585e648 100644 --- a/hkmc2/shared/src/test/mlscript/llir/nofib/scc.mls +++ b/hkmc2/shared/src/test/mlscript/llir/nofib/scc.mls @@ -49,8 +49,6 @@ fun testScc_nofib(d) = stronglyConnComp(edges, vertices) -:wholeOpt -:wholeOptFlags simp,!split :runWholeCpp print(testScc_nofib(0)) //│ diff --git a/hkmc2/shared/src/test/mlscript/llir/nofib/secretary.mls b/hkmc2/shared/src/test/mlscript/llir/nofib/secretary.mls index 8a36069477..a995685efe 100644 --- a/hkmc2/shared/src/test/mlscript/llir/nofib/secretary.mls +++ b/hkmc2/shared/src/test/mlscript/llir/nofib/secretary.mls @@ -36,9 +36,6 @@ fun testSecretary_nofib(n) = listcomp(enumFromTo(35, 39)) - -:wholeOpt -:wholeOptFlags simp,!split :runWholeCpp print(testSecretary_nofib(50)) //│ diff --git a/hkmc2DiffTests/src/test/scala/hkmc2/LlirDiffMaker.scala b/hkmc2DiffTests/src/test/scala/hkmc2/LlirDiffMaker.scala index cac9ea5364..913eb40b75 100644 --- a/hkmc2DiffTests/src/test/scala/hkmc2/LlirDiffMaker.scala +++ b/hkmc2DiffTests/src/test/scala/hkmc2/LlirDiffMaker.scala @@ -36,18 +36,6 @@ abstract class LlirDiffMaker extends BbmlDiffMaker: val rWholeCpp = NullaryCommand("runWholeCpp") val wWholeCpp = Command[Str]("writeWholeCpp", false)(x => x.stripLeading()) - val dopt = NullaryCommand("dopt") - - // Optimizer commands for individual blocks - val opt = NullaryCommand("opt") - val sopt = NullaryCommand("sopt") - val optFlags = Command[Set[Str]]("optf", false)(x => x.stripLeading().split(",").toSet) - - // Optimizer commands for the whole program - val wholeOpt = NullaryCommand("wholeOpt") - val sWholeOpt = NullaryCommand("showWholeOpt") - val wholeOptFlags = Command[Set[Str]]("wholeOptFlags", false)(x => x.stripLeading().split(",").toSet) - def printToFile(f: java.io.File)(op: java.io.PrintWriter => Unit) = val p = new java.io.PrintWriter(f) try { op(p) } finally { p.close() } @@ -85,20 +73,6 @@ abstract class LlirDiffMaker extends BbmlDiffMaker: if sllir.isSet then output("LLIR:") output(llirProg.show()) - def optimize(name: String, prog: Program, opt: Bool, show: Bool, optFlags: Set[Str]): Program = - given tl: TraceLogger with - override def doTrace = dopt.isSet - override def emitDbg(str: String): Unit = output(str) - if opt || show then - tl.log(s"Optimizing $name") - val opt = codegen.llir.LlirOpt(tl, freshId, optFlags) - val optProg = opt.run(prog) - if show then - output(s"\n$name:") - output(optProg.show()) - optProg - else - prog def cppGen(name: String, prog: Program, gen: Bool, show: Bool, run: Bool, write: Opt[Str]): Unit = tl.log(s"Generating $name") if gen || show || run || write.isDefined then @@ -122,11 +96,9 @@ abstract class LlirDiffMaker extends BbmlDiffMaker: else output("\n") cppHost.compileAndRun(cpp.toDocument.toString) - cppGen("Cpp", - optimize("Opt", llirProg, opt.isSet, sopt.isSet, optFlags.get.getOrElse(Set.empty)), + cppGen("Cpp", llirProg, cpp.isSet, scpp.isSet, rcpp.isSet, wcpp.get) - cppGen("WholeProgramCpp", - optimize("WholeProgramOpt", mkWholeProgram, wholeOpt.isSet, sWholeOpt.isSet, wholeOptFlags.get.getOrElse(Set.empty)), + cppGen("WholeProgramCpp", mkWholeProgram, wholeCpp.isSet, sWholeCpp.isSet, rWholeCpp.isSet, wWholeCpp.get) if intl.isSet then val intr = codegen.llir.Interpreter(tl) @@ -135,6 +107,3 @@ abstract class LlirDiffMaker extends BbmlDiffMaker: catch case e: LowLevelIRError => output("Stopped due to an error during the Llir generation") - case e: OptErr => - output("Stopped due to an error during the optimization") - From 3eaa589b1021afa95995f4f95876c1a3cb8c1472 Mon Sep 17 00:00:00 2001 From: waterlens Date: Thu, 20 Mar 2025 23:54:01 +0800 Subject: [PATCH 62/88] Improve code style --- flake.nix | 1 - hkmc2/shared/src/main/scala/hkmc2/codegen/Block.scala | 10 +++++----- .../shared/src/main/scala/hkmc2/codegen/Printer.scala | 3 +-- .../src/main/scala/hkmc2/codegen/llir/Builder.scala | 10 ++++++---- hkmc2/shared/src/test/mlscript-compile/cpp/Makefile | 6 +++--- .../src/test/mlscript-compile/cpp/compile_flags.txt | 8 -------- 6 files changed, 15 insertions(+), 23 deletions(-) delete mode 100644 hkmc2/shared/src/test/mlscript-compile/cpp/compile_flags.txt diff --git a/flake.nix b/flake.nix index 42559a9dbe..8e657face9 100644 --- a/flake.nix +++ b/flake.nix @@ -28,7 +28,6 @@ mimalloc sbt nodejs_22 - hyperfine ]; }; }); diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Block.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Block.scala index 233f45ca3e..161a96d5ee 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Block.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Block.scala @@ -90,10 +90,10 @@ sealed abstract class Block extends Product with AutoLocated: case Continue(label) => Set(label) case Begin(sub, rest) => sub.freeVars ++ rest.freeVars case TryBlock(sub, finallyDo, rest) => sub.freeVars ++ finallyDo.freeVars ++ rest.freeVars - case Assign(l, rhs, rest) => Set(l) ++ rhs.freeVars ++ rest.freeVars + case Assign(lhs, rhs, rest) => Set(lhs) ++ rhs.freeVars ++ rest.freeVars case AssignField(lhs, nme, rhs, rest) => lhs.freeVars ++ rhs.freeVars ++ rest.freeVars case AssignDynField(lhs, fld, arrayIdx, rhs, rest) => lhs.freeVars ++ fld.freeVars ++ rhs.freeVars ++ rest.freeVars - case Define(defn, rest) => defn.freeVars ++ (rest.freeVars - defn.sym) + case Define(defn, rest) => defn.freeVars ++ rest.freeVars case HandleBlock(lhs, res, par, args, cls, hdr, bod, rst) => (bod.freeVars - lhs) ++ rst.freeVars ++ hdr.flatMap(_.freeVars) case End(msg) => Set.empty @@ -110,7 +110,7 @@ sealed abstract class Block extends Product with AutoLocated: case Continue(label) => Set(label) case Begin(sub, rest) => sub.freeVarsLLIR ++ rest.freeVarsLLIR case TryBlock(sub, finallyDo, rest) => sub.freeVarsLLIR ++ finallyDo.freeVarsLLIR ++ rest.freeVarsLLIR - case Assign(l, rhs, rest) => rhs.freeVarsLLIR ++ (rest.freeVarsLLIR - l) + case Assign(lhs, rhs, rest) => rhs.freeVarsLLIR ++ (rest.freeVarsLLIR - lhs) case AssignField(lhs, nme, rhs, rest) => lhs.freeVarsLLIR ++ rhs.freeVarsLLIR ++ rest.freeVarsLLIR case AssignDynField(lhs, fld, arrayIdx, rhs, rest) => lhs.freeVarsLLIR ++ fld.freeVarsLLIR ++ rhs.freeVarsLLIR ++ rest.freeVarsLLIR case Define(defn, rest) => defn.freeVarsLLIR ++ (rest.freeVarsLLIR - defn.sym) @@ -321,7 +321,7 @@ sealed abstract class Defn: preCtor.freeVarsLLIR ++ ctor.freeVarsLLIR ++ methods.flatMap(_.freeVarsLLIR) -- auxParams.flatMap(_.paramSyms) - + final case class FunDefn( owner: Opt[InnerSymbol], sym: BlockMemberSymbol, @@ -376,7 +376,7 @@ enum Case: case Lit(_) => Set.empty case Cls(_, path) => path.freeVars case Tup(_, _) => Set.empty - + lazy val freeVarsLLIR: Set[Local] = this match case Lit(_) => Set.empty case Cls(_, path) => path.freeVarsLLIR diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Printer.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Printer.scala index e7860c250e..dfd194f4d2 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Printer.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Printer.scala @@ -31,8 +31,7 @@ object Printer: .map{ case (c, b) => doc"${case_doc(c)} => #{ # ${mkDocument(b)} #} " } .mkDocument(sep = doc" # ") val docDefault = dflt.map(mkDocument).getOrElse(doc"") - val docRest = mkDocument(rest) - doc"match ${mkDocument(scrut)} #{ # ${docCases} # else #{ # ${docDefault} #} #} # in # ${docRest}" + doc"match ${mkDocument(scrut)} #{ # ${docCases} # else #{ # ${docDefault} #} #} # in # ${mkDocument(rest)}" case Return(res, implct) => doc"return ${mkDocument(res)}" case Throw(exc) => doc"throw ${mkDocument(exc)}" case Label(label, body, rest) => diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala index 2687e2c0b7..43f47f8e32 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala @@ -31,11 +31,11 @@ final case class BuiltinSymbols( fieldSym: MutMap[Int, Local] = MutMap.empty, applySym: MutMap[Int, Local] = MutMap.empty, tupleSym: MutMap[Int, Local] = MutMap.empty, + runtimeSym: Opt[TempSymbol] = None, ): def hiddenClasses = callableSym.toSet final case class Ctx( - runtimeSymbol: TempSymbol, def_acc: ListBuffer[Func], class_acc: ListBuffer[ClassInfo], symbol_ctx: Map[Local, Local] = Map.empty, @@ -64,7 +64,9 @@ final case class Ctx( object Ctx: def empty(using Elaborator.State) = - Ctx(Elaborator.State.runtimeSymbol, ListBuffer.empty, ListBuffer.empty) + Ctx(ListBuffer.empty, ListBuffer.empty).copy(builtin_sym = BuiltinSymbols( + runtimeSym = Some(Elaborator.State.runtimeSymbol) + )) final class LlirBuilder(using Elaborator.State)(tl: TraceLogger, uid: FreshInt): import tl.{trace, log, logs} @@ -281,7 +283,6 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger, uid: FreshInt): private def bValue(v: Value)(k: TrivialExpr => Ctx ?=> Node)(using ctx: Ctx)(using Raise, Scope) : Node = trace[Node](s"bValue { $v } begin", x => s"bValue end: ${x.show}"): v match - // TODO: why? case Value.Ref(l: TermSymbol) if l.owner.nonEmpty => k(l |> sr) case Value.Ref(sym) if sym.nme.isCapitalized => @@ -306,6 +307,7 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger, uid: FreshInt): case args: Ls[TrivialExpr] => val v: Local = newTemp Node.LetExpr(v, Expr.CtorApp(builtinTuple(elems.length), args), k(v |> sr)) + case Value.Rcd(fields) => bErrStop(msg"Unsupported value: Rcd") private def getClassOfField(p: FieldSymbol)(using ctx: Ctx)(using Raise, Scope): Local = @@ -334,7 +336,7 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger, uid: FreshInt): private def bPath(p: Path)(k: TrivialExpr => Ctx ?=> Node)(using ctx: Ctx)(using Raise, Scope) : Node = trace[Node](s"bPath { $p } begin", x => s"bPath end: ${x.show}"): p match - case s @ Select(Value.Ref(sym), Tree.Ident("Unit")) if sym is ctx.runtimeSymbol => + case s @ Select(Value.Ref(sym), Tree.Ident("Unit")) if sym is ctx.builtin_sym.runtimeSym => bPath(Value.Lit(Tree.UnitLit(false)))(k) case s @ Select(Value.Ref(cls: ClassSymbol), name) if ctx.method_class.contains(cls) => s.symbol match diff --git a/hkmc2/shared/src/test/mlscript-compile/cpp/Makefile b/hkmc2/shared/src/test/mlscript-compile/cpp/Makefile index 4e93f9cb22..bba9ca31e9 100644 --- a/hkmc2/shared/src/test/mlscript-compile/cpp/Makefile +++ b/hkmc2/shared/src/test/mlscript-compile/cpp/Makefile @@ -1,11 +1,11 @@ CXX := g++ -CFLAGS += -O3 -g -Wall -Wextra -std=c++20 -I. -Wno-inconsistent-missing-override -I/opt/homebrew/include +CFLAGS += -O3 -Wall -Wextra -std=c++20 -I. -Wno-inconsistent-missing-override -I/opt/homebrew/include LDFLAGS += -L/opt/homebrew/lib -LDLIBS := -lmimalloc -lgmp -lboost_stacktrace_basic +LDLIBS := -lmimalloc -lgmp SRC := INCLUDES := mlsprelude.h DST := -DEFAULT_TARGET := $(SRC:=.out) +DEFAULT_TARGET := mls TARGET := $(or $(DST),$(DEFAULT_TARGET)) .PHONY: pre all run clean auto diff --git a/hkmc2/shared/src/test/mlscript-compile/cpp/compile_flags.txt b/hkmc2/shared/src/test/mlscript-compile/cpp/compile_flags.txt deleted file mode 100644 index 3b6e59f935..0000000000 --- a/hkmc2/shared/src/test/mlscript-compile/cpp/compile_flags.txt +++ /dev/null @@ -1,8 +0,0 @@ --O --Wall --std=c++20 --I. --Wno-inconsistent-missing-override --I/opt/homebrew/include --L/opt/homebrew/lib --xc++ From ae263daecc5fa19963d63b00e5e3c4e53f7e956b Mon Sep 17 00:00:00 2001 From: waterlens Date: Thu, 20 Mar 2025 23:57:35 +0800 Subject: [PATCH 63/88] Add missing spaces --- hkmc2/shared/src/main/scala/hkmc2/codegen/Block.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Block.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Block.scala index 161a96d5ee..cd420d1b2b 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Block.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Block.scala @@ -312,7 +312,7 @@ sealed abstract class Defn: preCtor.freeVars ++ ctor.freeVars ++ methods.flatMap(_.freeVars) -- auxParams.flatMap(_.paramSyms) - + lazy val freeVarsLLIR: Set[Local] = this match case FunDefn(own, sym, params, body) => body.freeVarsLLIR -- params.flatMap(_.paramSyms) - sym case ValDefn(owner, k, sym, rhs) => rhs.freeVarsLLIR From b16e2152ab92d15d200f477254a92db8c86cf3b9 Mon Sep 17 00:00:00 2001 From: waterlens Date: Fri, 21 Mar 2025 00:08:28 +0800 Subject: [PATCH 64/88] Fix a small mistake --- .../scala/hkmc2/codegen/llir/Builder.scala | 2 +- hkmc2/shared/src/test/mlscript/llir/SRC.mls | 253 ------------------ 2 files changed, 1 insertion(+), 254 deletions(-) delete mode 100644 hkmc2/shared/src/test/mlscript/llir/SRC.mls diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala index 43f47f8e32..e6ad9696a9 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala @@ -336,7 +336,7 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger, uid: FreshInt): private def bPath(p: Path)(k: TrivialExpr => Ctx ?=> Node)(using ctx: Ctx)(using Raise, Scope) : Node = trace[Node](s"bPath { $p } begin", x => s"bPath end: ${x.show}"): p match - case s @ Select(Value.Ref(sym), Tree.Ident("Unit")) if sym is ctx.builtin_sym.runtimeSym => + case s @ Select(Value.Ref(sym), Tree.Ident("Unit")) if sym is ctx.builtin_sym.runtimeSym.get => bPath(Value.Lit(Tree.UnitLit(false)))(k) case s @ Select(Value.Ref(cls: ClassSymbol), name) if ctx.method_class.contains(cls) => s.symbol match diff --git a/hkmc2/shared/src/test/mlscript/llir/SRC.mls b/hkmc2/shared/src/test/mlscript/llir/SRC.mls deleted file mode 100644 index 32b49de76a..0000000000 --- a/hkmc2/shared/src/test/mlscript/llir/SRC.mls +++ /dev/null @@ -1,253 +0,0 @@ -:llir - -:global - -:sopt -:optf simp,!split -:wcpp orig.cpp -abstract class Iter[T] -object Done -class Yield(n) -class Map(f, it) -fun done(it) = if it is Done then true else false -fun map(f, it) = Map(f, it) -fun dec(n) = Yield(n) -fun next(it) = if it is - Yield(n) then - if n == 0 then [0, Done] - else [n, Yield(n - 1)] - Map(f, it) then - if next(it) is [n, it] then - if done(it) then [f(n), Done] - else [f(n), Map(f, it)] -fun fold(acc, it) = - if next(it) is [n, it] then - if done(it) then acc else fold(n + acc, it) -fun map_sum(f, n) = let it = map(f, dec(n)) in fold(0, it) -map_sum(x => x, 2000000) -//│ -//│ Opt: -//│ class Done() -//│ class Yield(n$582) -//│ class Map(f$586,it$587) -//│ class Lambda_lambda() extends Callable { -//│ def apply1$686(arg$704) = -//│ let* (x$707) = lambda(arg$704) in -//│ x$707 -//│ } -//│ def done$571(it$591) = -//│ case it$591 of -//│ Done$578 => -//│ true -//│ _ => -//│ false -//│ def map$565(f$594,it$595) = -//│ let x$663 = Map$584(f$594,it$595) in -//│ x$663 -//│ def dec$574(n$599) = -//│ let x$664 = Yield$580(n$599) in -//│ x$664 -//│ def next$570(it$603) = -//│ case it$603 of -//│ Yield$580 => -//│ let x$666 = it$603. in -//│ let x$667 = ==(x$666,0) in -//│ case x$667 of -//│ BoolLit(true) => -//│ let x$669 = Done$578() in -//│ let x$670 = Tuple2$671(0,x$669) in -//│ x$670 -//│ _ => -//│ let x$673 = -(x$666,1) in -//│ let x$674 = Yield$580(x$673) in -//│ let x$675 = Tuple2$671(x$666,x$674) in -//│ x$675 -//│ Map$584 => -//│ let x$676 = it$603. in -//│ let x$677 = it$603. in -//│ let* (x$678) = next(x$677) in -//│ case x$678 of -//│ Tuple2$671 => -//│ let x$680 = x$678. in -//│ let x$681 = x$678. in -//│ let* (x$682) = done(x$681) in -//│ case x$682 of -//│ BoolLit(true) => -//│ let x$684 = Callable.apply1$686(x$676,x$680) in -//│ let x$687 = Done$578() in -//│ let x$688 = Tuple2$671(x$684,x$687) in -//│ x$688 -//│ _ => -//│ let x$689 = Callable.apply1$686(x$676,x$680) in -//│ let x$690 = Map$584(x$676,x$681) in -//│ let x$691 = Tuple2$671(x$689,x$690) in -//│ x$691 -//│ _ => -//│ panic "match error" -//│ _ => -//│ panic "match error" -//│ def fold$567(acc$627,it$628) = -//│ let* (x$692) = next(it$628) in -//│ case x$692 of -//│ Tuple2$671 => -//│ let x$694 = x$692. in -//│ let x$695 = x$692. in -//│ let* (x$696) = done(x$695) in -//│ case x$696 of -//│ BoolLit(true) => -//│ acc$627 -//│ _ => -//│ let x$698 = +(x$694,acc$627) in -//│ let* (x$699) = fold(x$698,x$695) in -//│ x$699 -//│ _ => -//│ panic "match error" -//│ def map_sum$573(f$641,n$642) = -//│ let* (x$700) = dec(n$642) in -//│ let* (x$701) = map(f$641,x$700) in -//│ let* (x$702) = fold(0,x$701) in -//│ x$702 -//│ def lambda$661(x$649) = -//│ x$649 -//│ def entry$709() = -//│ let x$708 = Lambda_lambda$705() in -//│ let* (x$703) = map_sum(x$708,2000000) in -//│ x$703 -//│ entry = entry$709 - - -:sopt -:optf simp,!split -:wcpp inlined.cpp -abstract class Iter[T] -object Done -class Yield(n) -class Map(f, it) -fun done(it) = if it is Done then true else false -fun map(f, it) = Map(f, it) -fun dec(n) = Yield(n) -fun next(it) = if it is - Yield(n) then - if n == 0 then [0, Done] - else [n, Yield(n - 1)] - Map(f, it) then - if next(it) is [n, it] then - if done(it) then [f(n), Done] - else [f(n), Map(f, it)] -fun fold(acc, iter) = if iter is - Yield(n) then - if n == 0 then acc - else fold(n + acc, Yield(n - 1)) - Map(f, it) then - if next(it) is [n, it] then - if it is Done then acc else fold(f(n) + acc, Map(f, it)) -fun map_sum(f, n) = let it = map(f, dec(n)) in fold(0, it) -map_sum(x => x, 2000000) -//│ -//│ Opt: -//│ class Done() -//│ class Yield(n$730) -//│ class Map(f$734,it$735) -//│ class Lambda_lambda() extends Callable { -//│ def apply1$686(arg$876) = -//│ let* (x$879) = lambda(arg$876) in -//│ x$879 -//│ } -//│ def done$719(it$739) = -//│ case it$739 of -//│ Done$726 => -//│ true -//│ _ => -//│ false -//│ def map$713(f$742,it$743) = -//│ let x$828 = Map$732(f$742,it$743) in -//│ x$828 -//│ def dec$722(n$747) = -//│ let x$829 = Yield$728(n$747) in -//│ x$829 -//│ def next$718(it$751) = -//│ case it$751 of -//│ Yield$728 => -//│ let x$831 = it$751. in -//│ let x$832 = ==(x$831,0) in -//│ case x$832 of -//│ BoolLit(true) => -//│ let x$834 = Done$726() in -//│ let x$835 = Tuple2$671(0,x$834) in -//│ x$835 -//│ _ => -//│ let x$836 = -(x$831,1) in -//│ let x$837 = Yield$728(x$836) in -//│ let x$838 = Tuple2$671(x$831,x$837) in -//│ x$838 -//│ Map$732 => -//│ let x$839 = it$751. in -//│ let x$840 = it$751. in -//│ let* (x$841) = next(x$840) in -//│ case x$841 of -//│ Tuple2$671 => -//│ let x$843 = x$841. in -//│ let x$844 = x$841. in -//│ let* (x$845) = done(x$844) in -//│ case x$845 of -//│ BoolLit(true) => -//│ let x$847 = Callable.apply1$686(x$839,x$843) in -//│ let x$848 = Done$726() in -//│ let x$849 = Tuple2$671(x$847,x$848) in -//│ x$849 -//│ _ => -//│ let x$850 = Callable.apply1$686(x$839,x$843) in -//│ let x$851 = Map$732(x$839,x$844) in -//│ let x$852 = Tuple2$671(x$850,x$851) in -//│ x$852 -//│ _ => -//│ panic "match error" -//│ _ => -//│ panic "match error" -//│ def fold$715(acc$775,iter$776) = -//│ case iter$776 of -//│ Yield$728 => -//│ let x$854 = iter$776. in -//│ let x$855 = ==(x$854,0) in -//│ case x$855 of -//│ BoolLit(true) => -//│ acc$775 -//│ _ => -//│ let x$857 = +(x$854,acc$775) in -//│ let x$858 = -(x$854,1) in -//│ let x$859 = Yield$728(x$858) in -//│ let* (x$860) = fold(x$857,x$859) in -//│ x$860 -//│ Map$732 => -//│ let x$861 = iter$776. in -//│ let x$862 = iter$776. in -//│ let* (x$863) = next(x$862) in -//│ case x$863 of -//│ Tuple2$671 => -//│ let x$865 = x$863. in -//│ let x$866 = x$863. in -//│ case x$866 of -//│ Done$726 => -//│ acc$775 -//│ _ => -//│ let x$868 = Callable.apply1$686(x$861,x$865) in -//│ let x$869 = +(x$868,acc$775) in -//│ let x$870 = Map$732(x$861,x$866) in -//│ let* (x$871) = fold(x$869,x$870) in -//│ x$871 -//│ _ => -//│ panic "match error" -//│ _ => -//│ panic "match error" -//│ def map_sum$721(f$801,n$802) = -//│ let* (x$872) = dec(n$802) in -//│ let* (x$873) = map(f$801,x$872) in -//│ let* (x$874) = fold(0,x$873) in -//│ x$874 -//│ def lambda$826(x$809) = -//│ x$809 -//│ def entry$881() = -//│ let x$880 = Lambda_lambda$877() in -//│ let* (x$875) = map_sum(x$880,2000000) in -//│ x$875 -//│ entry = entry$881 From b58fd9fb0ce027f984c785b2e0a7482685264c7b Mon Sep 17 00:00:00 2001 From: waterlens Date: Sat, 22 Mar 2025 15:04:06 +0800 Subject: [PATCH 65/88] Rename test --- hkmc2/shared/src/test/mlscript/llir/Split.mls | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 hkmc2/shared/src/test/mlscript/llir/Split.mls diff --git a/hkmc2/shared/src/test/mlscript/llir/Split.mls b/hkmc2/shared/src/test/mlscript/llir/Split.mls new file mode 100644 index 0000000000..cc5d298121 --- /dev/null +++ b/hkmc2/shared/src/test/mlscript/llir/Split.mls @@ -0,0 +1,49 @@ +:llir + +:global + +abstract class Iter[T] +object Done +class Yield(n) +class Map(f, it) +fun done(it) = if it is Done then true else false +fun map(f, it) = Map(f, it) +fun dec(n) = Yield(n) +fun next(it) = if it is + Yield(n) then + if n == 0 then [0, Done] + else [n, Yield(n - 1)] + Map(f, it) then + if next(it) is [n, it] then + if done(it) then [f(n), Done] + else [f(n), Map(f, it)] +fun fold(acc, it) = + if next(it) is [n, it] then + if done(it) then acc else fold(n + acc, it) +fun map_sum(f, n) = let it = map(f, dec(n)) in fold(0, it) +map_sum(x => x, 2000000) + +abstract class Iter[T] +object Done +class Yield(n) +class Map(f, it) +fun done(it) = if it is Done then true else false +fun map(f, it) = Map(f, it) +fun dec(n) = Yield(n) +fun next(it) = if it is + Yield(n) then + if n == 0 then [0, Done] + else [n, Yield(n - 1)] + Map(f, it) then + if next(it) is [n, it] then + if done(it) then [f(n), Done] + else [f(n), Map(f, it)] +fun fold(acc, iter) = if iter is + Yield(n) then + if n == 0 then acc + else fold(n + acc, Yield(n - 1)) + Map(f, it) then + if next(it) is [n, it] then + if it is Done then acc else fold(f(n) + acc, Map(f, it)) +fun map_sum(f, n) = let it = map(f, dec(n)) in fold(0, it) +map_sum(x => x, 2000000) From 348168fe7302475ff1ddc7479810915a40c93ae0 Mon Sep 17 00:00:00 2001 From: waterlens Date: Sat, 22 Mar 2025 20:26:25 +0800 Subject: [PATCH 66/88] Remove unused :global --- hkmc2/shared/src/test/mlscript/llir/BadPrograms.mls | 3 --- hkmc2/shared/src/test/mlscript/llir/BasicCpp.mls | 10 ---------- hkmc2/shared/src/test/mlscript/llir/ControlFlow.mls | 2 -- hkmc2/shared/src/test/mlscript/llir/Ctor.mls | 2 -- hkmc2/shared/src/test/mlscript/llir/HigherOrder.mls | 2 -- hkmc2/shared/src/test/mlscript/llir/Legacy.mls | 2 -- hkmc2/shared/src/test/mlscript/llir/Method.mls | 1 - hkmc2/shared/src/test/mlscript/llir/Split.mls | 2 -- hkmc2/shared/src/test/mlscript/llir/Tuple.mls | 2 -- 9 files changed, 26 deletions(-) diff --git a/hkmc2/shared/src/test/mlscript/llir/BadPrograms.mls b/hkmc2/shared/src/test/mlscript/llir/BadPrograms.mls index 0a4417b4ee..8342a860e5 100644 --- a/hkmc2/shared/src/test/mlscript/llir/BadPrograms.mls +++ b/hkmc2/shared/src/test/mlscript/llir/BadPrograms.mls @@ -1,9 +1,6 @@ - -:global :llir :cpp - :todo :ge fun oops(a) = diff --git a/hkmc2/shared/src/test/mlscript/llir/BasicCpp.mls b/hkmc2/shared/src/test/mlscript/llir/BasicCpp.mls index f10d220cf7..6d2f24ad7b 100644 --- a/hkmc2/shared/src/test/mlscript/llir/BasicCpp.mls +++ b/hkmc2/shared/src/test/mlscript/llir/BasicCpp.mls @@ -1,5 +1,4 @@ :js -:global :llir :cpp @@ -34,15 +33,6 @@ fun bar(x) = x + 1 foo(1) //│ = 2 -//│ LLIR: -//│ -//│ def bar$587(x$589) = -//│ let x$595 = +(x$589,1) in -//│ x$595 -//│ def entry$597() = -//│ let* (x$596) = foo(1) in -//│ x$596 -//│ entry = entry$597 //│ //│ WholeProgramCpp: //│ #include "mlsprelude.h" diff --git a/hkmc2/shared/src/test/mlscript/llir/ControlFlow.mls b/hkmc2/shared/src/test/mlscript/llir/ControlFlow.mls index ea9e8dacd2..fc175438f9 100644 --- a/hkmc2/shared/src/test/mlscript/llir/ControlFlow.mls +++ b/hkmc2/shared/src/test/mlscript/llir/ControlFlow.mls @@ -2,8 +2,6 @@ :llir :cpp -:global - :sllir :intl fun f1() = diff --git a/hkmc2/shared/src/test/mlscript/llir/Ctor.mls b/hkmc2/shared/src/test/mlscript/llir/Ctor.mls index 1a5a8c9c01..b6929ff54b 100644 --- a/hkmc2/shared/src/test/mlscript/llir/Ctor.mls +++ b/hkmc2/shared/src/test/mlscript/llir/Ctor.mls @@ -2,8 +2,6 @@ :llir :cpp -:global - :sllir object None fun testCtor1() = None diff --git a/hkmc2/shared/src/test/mlscript/llir/HigherOrder.mls b/hkmc2/shared/src/test/mlscript/llir/HigherOrder.mls index fe774c19c5..4b0347f7ef 100644 --- a/hkmc2/shared/src/test/mlscript/llir/HigherOrder.mls +++ b/hkmc2/shared/src/test/mlscript/llir/HigherOrder.mls @@ -2,8 +2,6 @@ :llir :cpp -:global - :sllir :intl :scpp diff --git a/hkmc2/shared/src/test/mlscript/llir/Legacy.mls b/hkmc2/shared/src/test/mlscript/llir/Legacy.mls index a4fa93b8b8..c9a81e31b5 100644 --- a/hkmc2/shared/src/test/mlscript/llir/Legacy.mls +++ b/hkmc2/shared/src/test/mlscript/llir/Legacy.mls @@ -2,8 +2,6 @@ :llir :cpp -:global - :intl class Pair[A, B](x: A, y: B) fun mktup2(x, y) = mktup(x, y) diff --git a/hkmc2/shared/src/test/mlscript/llir/Method.mls b/hkmc2/shared/src/test/mlscript/llir/Method.mls index 2a1e864ca8..cd309e7f72 100644 --- a/hkmc2/shared/src/test/mlscript/llir/Method.mls +++ b/hkmc2/shared/src/test/mlscript/llir/Method.mls @@ -1,5 +1,4 @@ :js -:global :llir :cpp diff --git a/hkmc2/shared/src/test/mlscript/llir/Split.mls b/hkmc2/shared/src/test/mlscript/llir/Split.mls index cc5d298121..8c00f7bfd2 100644 --- a/hkmc2/shared/src/test/mlscript/llir/Split.mls +++ b/hkmc2/shared/src/test/mlscript/llir/Split.mls @@ -1,7 +1,5 @@ :llir -:global - abstract class Iter[T] object Done class Yield(n) diff --git a/hkmc2/shared/src/test/mlscript/llir/Tuple.mls b/hkmc2/shared/src/test/mlscript/llir/Tuple.mls index a731681cd0..a99ef3592f 100644 --- a/hkmc2/shared/src/test/mlscript/llir/Tuple.mls +++ b/hkmc2/shared/src/test/mlscript/llir/Tuple.mls @@ -2,8 +2,6 @@ :llir :cpp -:global - :intl :sllir :scpp From 68edbfcf429a7e61510fd7625b0df8195e4b1afa Mon Sep 17 00:00:00 2001 From: waterlens Date: Sun, 23 Mar 2025 20:54:10 +0800 Subject: [PATCH 67/88] Add missing `data`; Fix interpreter on tuple field selection --- .../scala/hkmc2/codegen/llir/Interp.scala | 10 +++++ hkmc2/shared/src/test/mlscript/llir/Lazy.mls | 30 ++++++------- .../src/test/mlscript/llir/LazyCycle.mls | 38 ++++++++-------- .../shared/src/test/mlscript/llir/Legacy.mls | 44 +++++++++---------- hkmc2/shared/src/test/mlscript/llir/Split.mls | 20 ++++++--- 5 files changed, 80 insertions(+), 62 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Interp.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Interp.scala index 22e4798f75..5b06af3c76 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Interp.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Interp.scala @@ -107,6 +107,16 @@ class Interpreter(tl: TraceLogger): xs <- evalArgs(args) cls <- ctx.classCtx.get(cls).toRight(StuckExpr(expr, s"undefined class ${cls.nme}")) yield Value.Class(cls, xs) + case Select(name, cls, field) if field.forall(_.isDigit) => + val nth = field.toInt + ctx.bindingCtx.get(name).toRight(StuckExpr(expr, s"undefined variable $name")).flatMap { + case Value.Class(cls2, xs) if cls == cls2.name => + xs.lift(nth) match + case Some(x) => R(x) + case None => L(StuckExpr(expr, s"unable to find selected field $field")) + case Value.Class(cls2, xs) => L(StuckExpr(expr, s"unexpected class $cls2")) + case x => L(StuckExpr(expr, s"unexpected value $x")) + } case Select(name, cls, field) => ctx.bindingCtx.get(name).toRight(StuckExpr(expr, s"undefined variable $name")).flatMap { case Value.Class(cls2, xs) if cls == cls2.name => diff --git a/hkmc2/shared/src/test/mlscript/llir/Lazy.mls b/hkmc2/shared/src/test/mlscript/llir/Lazy.mls index f9bafe7017..eba9ab7c2c 100644 --- a/hkmc2/shared/src/test/mlscript/llir/Lazy.mls +++ b/hkmc2/shared/src/test/mlscript/llir/Lazy.mls @@ -6,7 +6,7 @@ fun lazy(x) = Lazy(x) fun force(x) = if x is Lazy then x.Lazy#get() type LazyList[out T] = Lazy[LzList[T]] abstract class LzList[out T]: LzCons[T] | LzNil -class LzCons[out T](head: T, tail: LazyList[T]) extends LzList[T] +data class LzCons[out T](head: T, tail: LazyList[T]) extends LzList[T] object LzNil extends LzList :sllir @@ -22,23 +22,23 @@ fun main() = main() //│ LLIR: //│ class Lambda_lambda() extends Callable { -//│ def apply0$633() = -//│ let* (x$634) = side_effect() in -//│ x$634 +//│ def apply0$635() = +//│ let* (x$636) = side_effect() in +//│ x$636 //│ } -//│ def side_effect$608() = -//│ let* (x$628) = ("println","executed") in +//│ def side_effect$610() = +//│ let* (x$630) = ("println","executed") in //│ 1 -//│ def main$607() = -//│ let x$636 = Lambda_lambda$630() in -//│ let* (x$637) = lazy(x$636) in -//│ let* (x$638) = force(x$637) in -//│ let* (x$639) = force(x$637) in +//│ def main$609() = +//│ let x$638 = Lambda_lambda$632() in +//│ let* (x$639) = lazy(x$638) in +//│ let* (x$640) = force(x$639) in +//│ let* (x$641) = force(x$639) in //│ undefined -//│ def entry$641() = -//│ let* (x$640) = main() in -//│ x$640 -//│ entry = entry$641 +//│ def entry$643() = +//│ let* (x$642) = main() in +//│ x$642 +//│ entry = entry$643 //│ //│ Cpp: //│ #include "mlsprelude.h" diff --git a/hkmc2/shared/src/test/mlscript/llir/LazyCycle.mls b/hkmc2/shared/src/test/mlscript/llir/LazyCycle.mls index 38abe447d6..d820bd5881 100644 --- a/hkmc2/shared/src/test/mlscript/llir/LazyCycle.mls +++ b/hkmc2/shared/src/test/mlscript/llir/LazyCycle.mls @@ -6,7 +6,7 @@ fun lazy(x) = Lazy(x) fun force(x) = if x is Lazy then x.Lazy#get() type LazyList[out T] = Lazy[LzList[T]] abstract class LzList[out T]: LzCons[T] | LzNil -class LzCons[out T](head: T, tail: LazyList[T]) extends LzList[T] +data class LzCons[out T](head: T, tail: LazyList[T]) extends LzList[T] object LzNil extends LzList :sllir @@ -16,27 +16,27 @@ fun llist(x) = f(x) llist(1) //│ LLIR: -//│ class Lambda_lambda(lam_arg0$630,lam_arg1$631) extends Callable { -//│ def apply0$632() = -//│ let x$633 = +(lam_arg0$630,1) in -//│ let x$634 = Callable.apply1$627(lam_arg1$631,x$633) in -//│ let x$636 = LzCons$594(lam_arg0$630,x$634) in -//│ x$636 +//│ class Lambda_lambda(lam_arg0$632,lam_arg1$633) extends Callable { +//│ def apply0$634() = +//│ let x$635 = +(lam_arg0$632,1) in +//│ let x$636 = Callable.apply1$629(lam_arg1$633,x$635) in +//│ let x$638 = LzCons$594(lam_arg0$632,x$636) in +//│ x$638 //│ } //│ class Lambda_f() extends Callable { -//│ def apply1$627(x$612) = -//│ let x$637 = Lambda_lambda$628(x$612,$626) in -//│ let* (x$638) = lazy(x$637) in -//│ x$638 +//│ def apply1$629(x$614) = +//│ let x$639 = Lambda_lambda$630(x$614,$628) in +//│ let* (x$640) = lazy(x$639) in +//│ x$640 //│ } -//│ def llist$608(x$610) = -//│ let x$639 = Lambda_f$624() in -//│ let x$640 = Callable.apply1$627(x$639,x$610) in -//│ x$640 -//│ def entry$642() = -//│ let* (x$641) = llist(1) in -//│ x$641 -//│ entry = entry$642 +//│ def llist$610(x$612) = +//│ let x$641 = Lambda_f$626() in +//│ let x$642 = Callable.apply1$629(x$641,x$612) in +//│ x$642 +//│ def entry$644() = +//│ let* (x$643) = llist(1) in +//│ x$643 +//│ entry = entry$644 //│ //│ WholeProgramCpp: //│ #include "mlsprelude.h" diff --git a/hkmc2/shared/src/test/mlscript/llir/Legacy.mls b/hkmc2/shared/src/test/mlscript/llir/Legacy.mls index c9a81e31b5..304f174762 100644 --- a/hkmc2/shared/src/test/mlscript/llir/Legacy.mls +++ b/hkmc2/shared/src/test/mlscript/llir/Legacy.mls @@ -3,45 +3,45 @@ :cpp :intl -class Pair[A, B](x: A, y: B) +data class Pair[A, B](x: A, y: B) fun mktup2(x, y) = mktup(x, y) fun mktup(x, y) = Pair(x, y) fun foo() = mktup2(1, 2) foo() -//│ = Pair() +//│ = Pair(1, 2) //│ //│ Interpreted: //│ Pair(1,2) :intl -class Pair[A, B](x: A, y: B) +data class Pair[A, B](x: A, y: B) fun foo(pair) = if pair is Pair(x, y) then Pair(x, y) fun bar() = foo(Pair(1, 2)) bar() -//│ = Pair() +//│ = Pair(1, 2) //│ //│ Interpreted: //│ Pair(1,2) :intl -class Pair[A, B](x: A, y: B) +data class Pair[A, B](x: A, y: B) fun foo(pair) = if pair is Pair(x, y) then Pair(x, y) fun bar() = foo(Pair(1, 2)) bar() -//│ = Pair() +//│ = Pair(1, 2) //│ //│ Interpreted: //│ Pair(1,2) :intl -class Pair[A, B](x: A, y: B) +data class Pair[A, B](x: A, y: B) fun silly(pair) = let x = 0 let n = if pair is @@ -54,13 +54,13 @@ fun foo() = let b = silly(a) b foo() -//│ = NaN +//│ = 2 //│ //│ Interpreted: //│ 2 :intl -class Pair[A, B](x: A, y: B) +data class Pair[A, B](x: A, y: B) fun inc_fst(pair) = let c = 2 if pair is @@ -70,13 +70,13 @@ fun foo() = let b = inc_fst(a) b foo() -//│ = NaN +//│ = 2 //│ //│ Interpreted: //│ 2 :intl -class Pair[A, B](x: A, y: B) +data class Pair[A, B](x: A, y: B) fun inc_fst(pair) = let x = 0 if pair is @@ -85,7 +85,7 @@ fun foo() = let b = inc_fst(Pair(0, 1)) b foo() -//│ = NaN +//│ = 2 //│ //│ Interpreted: //│ 2 @@ -206,7 +206,7 @@ foo() :intl abstract class Option[out T]: Some[T] | None -class Some[out T](x: T) extends Option[T] +data class Some[out T](x: T) extends Option[T] object None extends Option fun not(x) = if x then false else true @@ -215,18 +215,18 @@ fun foo(x) = else Some(foo(not(x))) fun main() = foo(false) main() -//│ = Some() +//│ = Some(None) //│ //│ Interpreted: //│ Some(None()) :intl abstract class Option[out T]: Some[T] | None -class Some[out T](x: T) extends Option[T] +data class Some[out T](x: T) extends Option[T] object None extends Option fun fromSome(s) = if s is Some(x) then x abstract class Nat: S[Nat] | O -class S(s: Nat) extends Nat +data class S(s: Nat) extends Nat object O extends Nat fun aaa() = let m = 1 @@ -339,10 +339,10 @@ main() :todo "this is a bug because we use reference equality to locate the split point, but the reference changed after previous iteration" :intl abstract class Option[out T]: Some[T] | None -class Some[out T](x: T) extends Option[T] +data class Some[out T](x: T) extends Option[T] object None extends Option abstract class List[out T]: Cons[T] | Nil -class (::) Cons[out T](head: T, tail: List[T]) extends List[T] +data class (::) Cons[out T](head: T, tail: List[T]) extends List[T] object Nil extends List fun head_opt(l) = if l is @@ -364,10 +364,10 @@ main() :intl abstract class Option[out T]: Some[T] | None -class Some[out T](x: T) extends Option[T] +data class Some[out T](x: T) extends Option[T] object None extends Option abstract class List[out T]: Cons[T] | Nil -class (::) Cons[out T](head: T, tail: List[T]) extends List[T] +data class (::) Cons[out T](head: T, tail: List[T]) extends List[T] object Nil extends List fun mk_list(n) = if n == 0 then Nil else Cons(n, mk_list(n - 1)) @@ -416,7 +416,7 @@ main() :intl abstract class Option[out T]: Some[T] | None -class Some[out T](x: T) extends Option[T] +data class Some[out T](x: T) extends Option[T] object None extends Option fun is_some(o) = if o is @@ -444,7 +444,7 @@ fun f(x) = fun main() = f(Some(2)) + f(None) main() -//│ = NaN +//│ = 115 //│ //│ Interpreted: //│ 115 diff --git a/hkmc2/shared/src/test/mlscript/llir/Split.mls b/hkmc2/shared/src/test/mlscript/llir/Split.mls index 8c00f7bfd2..af0f4ad158 100644 --- a/hkmc2/shared/src/test/mlscript/llir/Split.mls +++ b/hkmc2/shared/src/test/mlscript/llir/Split.mls @@ -1,9 +1,10 @@ :llir +:intl abstract class Iter[T] object Done -class Yield(n) -class Map(f, it) +data class Yield(n) +data class Map(f, it) fun done(it) = if it is Done then true else false fun map(f, it) = Map(f, it) fun dec(n) = Yield(n) @@ -19,12 +20,16 @@ fun fold(acc, it) = if next(it) is [n, it] then if done(it) then acc else fold(n + acc, it) fun map_sum(f, n) = let it = map(f, dec(n)) in fold(0, it) -map_sum(x => x, 2000000) +map_sum(x => x, 200) +//│ +//│ Interpreted: +//│ 20100 +:intl abstract class Iter[T] object Done -class Yield(n) -class Map(f, it) +data class Yield(n) +data class Map(f, it) fun done(it) = if it is Done then true else false fun map(f, it) = Map(f, it) fun dec(n) = Yield(n) @@ -44,4 +49,7 @@ fun fold(acc, iter) = if iter is if next(it) is [n, it] then if it is Done then acc else fold(f(n) + acc, Map(f, it)) fun map_sum(f, n) = let it = map(f, dec(n)) in fold(0, it) -map_sum(x => x, 2000000) +map_sum(x => x, 200) +//│ +//│ Interpreted: +//│ 20100 From 8788e4f8d87097ecd632516cc52bd95b0db779ef Mon Sep 17 00:00:00 2001 From: waterlens Date: Sat, 29 Mar 2025 19:26:54 +0800 Subject: [PATCH 68/88] Improve test style --- .../src/test/mlscript/llir/BasicCpp.mls | 20 - .../src/test/mlscript/llir/ControlFlow.mls | 95 --- .../src/test/mlscript/llir/HigherOrder.mls | 745 +----------------- .../shared/src/test/mlscript/llir/Legacy.mls | 8 +- .../src/test/mlscript/llir/nofib/awards.mls | 105 +-- .../src/test/scala/hkmc2/LlirDiffMaker.scala | 4 +- 6 files changed, 14 insertions(+), 963 deletions(-) diff --git a/hkmc2/shared/src/test/mlscript/llir/BasicCpp.mls b/hkmc2/shared/src/test/mlscript/llir/BasicCpp.mls index 6d2f24ad7b..50b35ad37e 100644 --- a/hkmc2/shared/src/test/mlscript/llir/BasicCpp.mls +++ b/hkmc2/shared/src/test/mlscript/llir/BasicCpp.mls @@ -2,31 +2,11 @@ :llir :cpp -:sllir fun foo(a) = let x if a > 0 do x = 1 x + 1 -//│ LLIR: -//│ -//│ def foo$567(a$569) = -//│ let x$579 = undefined in -//│ let x$580 = >(a$569,0) in -//│ case x$580 of -//│ BoolLit(true) => -//│ let x$582 = 1 in -//│ let x$583 = undefined in -//│ jump j$581(x$582) -//│ _ => -//│ let x$584 = undefined in -//│ jump j$581(x$579) -//│ def j$581(x$570) = -//│ let x$585 = +(x$570,1) in -//│ x$585 -//│ def entry$586() = -//│ undefined -//│ entry = entry$586 :showWholeCpp fun bar(x) = diff --git a/hkmc2/shared/src/test/mlscript/llir/ControlFlow.mls b/hkmc2/shared/src/test/mlscript/llir/ControlFlow.mls index fc175438f9..744fe2ca42 100644 --- a/hkmc2/shared/src/test/mlscript/llir/ControlFlow.mls +++ b/hkmc2/shared/src/test/mlscript/llir/ControlFlow.mls @@ -149,7 +149,6 @@ f5() //│ 5 :sllir -:scpp fun test() = if true do test() //│ LLIR: @@ -167,38 +166,8 @@ fun test() = //│ def entry$665() = //│ undefined //│ entry = entry$665 -//│ -//│ Cpp: -//│ #include "mlsprelude.h" -//│ _mlsValue _mls_j5(); -//│ _mlsValue _mls_test(); -//│ _mlsValue _mls_entry6(); -//│ _mlsValue _mls_j5() { -//│ _mlsValue _mls_retval; -//│ _mls_retval = _mlsValue::create<_mls_Unit>(); -//│ return _mls_retval; -//│ } -//│ _mlsValue _mls_test() { -//│ _mlsValue _mls_retval; -//│ auto _mls_x23 = _mlsValue::fromIntLit(1); -//│ if (_mlsValue::isIntLit(_mls_x23, 1)) { -//│ auto _mls_x24 = _mls_test(); -//│ _mls_retval = _mls_x24; -//│ } else { -//│ _mls_retval = _mlsValue::create<_mls_Unit>(); -//│ } -//│ return _mls_retval; -//│ } -//│ _mlsValue _mls_entry6() { -//│ _mlsValue _mls_retval; -//│ _mls_retval = _mlsValue::create<_mls_Unit>(); -//│ return _mls_retval; -//│ } -//│ _mlsValue _mlsMain() { return _mls_entry6(); } -//│ int main() { return _mlsLargeStack(_mlsMainWrapper); } :sllir -:scpp fun test() = (if true then test()) + 1 //│ LLIR: @@ -217,41 +186,10 @@ fun test() = //│ def entry$680() = //│ undefined //│ entry = entry$680 -//│ -//│ Cpp: -//│ #include "mlsprelude.h" -//│ _mlsValue _mls_j6(_mlsValue); -//│ _mlsValue _mls_test1(); -//│ _mlsValue _mls_entry7(); -//│ _mlsValue _mls_j6(_mlsValue _mls_tmp3) { -//│ _mlsValue _mls_retval; -//│ auto _mls_x25 = (_mls_tmp3 + _mlsValue::fromIntLit(1)); -//│ _mls_retval = _mls_x25; -//│ return _mls_retval; -//│ } -//│ _mlsValue _mls_test1() { -//│ _mlsValue _mls_retval; -//│ auto _mls_x26 = _mlsValue::fromIntLit(1); -//│ if (_mlsValue::isIntLit(_mls_x26, 1)) { -//│ auto _mls_x27 = _mls_test1(); -//│ _mls_retval = _mls_j6(_mls_x27); -//│ } else { -//│ throw std::runtime_error("match error"); -//│ } -//│ return _mls_retval; -//│ } -//│ _mlsValue _mls_entry7() { -//│ _mlsValue _mls_retval; -//│ _mls_retval = _mlsValue::create<_mls_Unit>(); -//│ return _mls_retval; -//│ } -//│ _mlsValue _mlsMain() { return _mls_entry7(); } -//│ int main() { return _mlsLargeStack(_mlsMainWrapper); } :sllir :intl -:scpp fun f() = let x = 10 if true do @@ -279,39 +217,6 @@ f() //│ x$700 //│ entry = entry$701 //│ -//│ Cpp: -//│ #include "mlsprelude.h" -//│ _mlsValue _mls_j7(_mlsValue); -//│ _mlsValue _mls_f(); -//│ _mlsValue _mls_entry8(); -//│ _mlsValue _mls_j7(_mlsValue _mls_x28) { -//│ _mlsValue _mls_retval; -//│ _mls_retval = _mls_x28; -//│ return _mls_retval; -//│ } -//│ _mlsValue _mls_f() { -//│ _mlsValue _mls_retval; -//│ auto _mls_x29 = _mlsValue::fromIntLit(10); -//│ auto _mls_x30 = _mlsValue::fromIntLit(1); -//│ if (_mlsValue::isIntLit(_mls_x30, 1)) { -//│ auto _mls_x32 = (_mls_x29 + _mlsValue::fromIntLit(1)); -//│ auto _mls_x33 = _mlsValue::create<_mls_Unit>(); -//│ _mls_retval = _mls_j7(_mls_x32); -//│ } else { -//│ auto _mls_x31 = _mlsValue::create<_mls_Unit>(); -//│ _mls_retval = _mls_j7(_mls_x29); -//│ } -//│ return _mls_retval; -//│ } -//│ _mlsValue _mls_entry8() { -//│ _mlsValue _mls_retval; -//│ auto _mls_x34 = _mls_f(); -//│ _mls_retval = _mls_x34; -//│ return _mls_retval; -//│ } -//│ _mlsValue _mlsMain() { return _mls_entry8(); } -//│ int main() { return _mlsLargeStack(_mlsMainWrapper); } -//│ //│ Interpreted: //│ 11 diff --git a/hkmc2/shared/src/test/mlscript/llir/HigherOrder.mls b/hkmc2/shared/src/test/mlscript/llir/HigherOrder.mls index 4b0347f7ef..d1a76b556c 100644 --- a/hkmc2/shared/src/test/mlscript/llir/HigherOrder.mls +++ b/hkmc2/shared/src/test/mlscript/llir/HigherOrder.mls @@ -1,10 +1,12 @@ :js :llir :cpp +:intl +//│ +//│ Interpreted: +//│ undefined :sllir -:intl -:scpp fun add(x) = y => x + y fun add_curried(x)(y) = x + y add(1)(2) @@ -32,244 +34,25 @@ add(1)(2) //│ x$601 //│ entry = entry$602 //│ -//│ Cpp: -//│ #include "mlsprelude.h" -//│ struct _mls_Lambda_lambda; -//│ struct _mls_Lambda; -//│ _mlsValue _mls_add(_mlsValue); -//│ _mlsValue _mls_add_curried(_mlsValue); -//│ _mlsValue _mls_entry1(); -//│ struct _mls_Lambda_lambda: public _mls_Callable { -//│ _mlsValue _mls_lam_arg0; -//│ constexpr static inline const char *typeName = "Lambda_lambda"; -//│ constexpr static inline uint32_t typeTag = nextTypeTag(); -//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->_mls_lam_arg0.print(); std::printf(")"); } -//│ virtual void destroy() override { _mlsValue::destroy(this->_mls_lam_arg0); operator delete (this, std::align_val_t(_mlsAlignment)); } -//│ static _mlsValue create(_mlsValue _mls_lam_arg0) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) _mls_Lambda_lambda; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->_mls_lam_arg0 = _mls_lam_arg0; return _mlsValue(_mlsVal); } -//│ virtual _mlsValue _mls_apply1(_mlsValue); -//│ }; -//│ struct _mls_Lambda: public _mls_Callable { -//│ _mlsValue _mls_lam_arg0; -//│ constexpr static inline const char *typeName = "Lambda"; -//│ constexpr static inline uint32_t typeTag = nextTypeTag(); -//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->_mls_lam_arg0.print(); std::printf(")"); } -//│ virtual void destroy() override { _mlsValue::destroy(this->_mls_lam_arg0); operator delete (this, std::align_val_t(_mlsAlignment)); } -//│ static _mlsValue create(_mlsValue _mls_lam_arg0) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) _mls_Lambda; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->_mls_lam_arg0 = _mls_lam_arg0; return _mlsValue(_mlsVal); } -//│ virtual _mlsValue _mls_apply1(_mlsValue); -//│ }; -//│ _mlsValue _mls_add(_mlsValue _mls_x3) { -//│ _mlsValue _mls_retval; -//│ auto _mls_x2 = _mlsValue::create<_mls_Lambda_lambda>(_mls_x3); -//│ _mls_retval = _mls_x2; -//│ return _mls_retval; -//│ } -//│ _mlsValue _mls_add_curried(_mlsValue _mls_x5) { -//│ _mlsValue _mls_retval; -//│ auto _mls_x4 = _mlsValue::create<_mls_Lambda>(_mls_x5); -//│ _mls_retval = _mls_x4; -//│ return _mls_retval; -//│ } -//│ _mlsValue _mls_entry1() { -//│ _mlsValue _mls_retval; -//│ auto _mls_x6 = _mls_add(_mlsValue::fromIntLit(1)); -//│ auto _mls_x7 = _mlsMethodCall<_mls_Callable>(_mls_x6)->_mls_apply1(_mlsValue::fromIntLit(2)); -//│ _mls_retval = _mls_x7; -//│ return _mls_retval; -//│ } -//│ _mlsValue _mls_Lambda_lambda::_mls_apply1(_mlsValue _mls_y) { -//│ _mlsValue _mls_retval; -//│ auto _mls_x = (_mls_lam_arg0 + _mls_y); -//│ _mls_retval = _mls_x; -//│ return _mls_retval; -//│ } -//│ _mlsValue _mls_Lambda::_mls_apply1(_mlsValue _mls_y1) { -//│ _mlsValue _mls_retval; -//│ auto _mls_x1 = (_mls_lam_arg0 + _mls_y1); -//│ _mls_retval = _mls_x1; -//│ return _mls_retval; -//│ } -//│ _mlsValue _mlsMain() { return _mls_entry1(); } -//│ int main() { return _mlsLargeStack(_mlsMainWrapper); } -//│ //│ Interpreted: //│ 3 -:sllir -:intl -:scpp fun add4(a, b) = (c, d) => a + b + c + d fun add4_curried(a, b)(c, d) = a + b + c + d add4(1, 2)(3, 4) //│ = 10 -//│ LLIR: -//│ class Lambda_lambda(lam_arg0$641,lam_arg1$642) extends Callable { -//│ def apply2$643(c$608,d$609) = -//│ let x$644 = +(lam_arg0$641,lam_arg1$642) in -//│ let x$645 = +(x$644,c$608) in -//│ let x$646 = +(x$645,d$609) in -//│ x$646 -//│ } -//│ class Lambda(lam_arg0$650,lam_arg1$651) extends Callable { -//│ def apply2$643(c$617,d$618) = -//│ let x$652 = +(lam_arg0$650,lam_arg1$651) in -//│ let x$653 = +(x$652,c$617) in -//│ let x$654 = +(x$653,d$618) in -//│ x$654 -//│ } -//│ def add4$604(a$606,b$607) = -//│ let x$647 = Lambda_lambda$639(a$606,b$607) in -//│ x$647 -//│ def add4_curried$603(a$615,b$616) = -//│ let x$655 = Lambda$648(a$615,b$616) in -//│ x$655 -//│ def entry$658() = -//│ let* (x$656) = add4(1,2) in -//│ let x$657 = Callable.apply2$643(x$656,3,4) in -//│ x$657 -//│ entry = entry$658 -//│ -//│ Cpp: -//│ #include "mlsprelude.h" -//│ struct _mls_Lambda_lambda1; -//│ struct _mls_Lambda1; -//│ _mlsValue _mls_add4(_mlsValue, _mlsValue); -//│ _mlsValue _mls_add4_curried(_mlsValue, _mlsValue); -//│ _mlsValue _mls_entry2(); -//│ struct _mls_Lambda_lambda1: public _mls_Callable { -//│ _mlsValue _mls_lam_arg0; -//│ _mlsValue _mls_lam_arg1; -//│ constexpr static inline const char *typeName = "Lambda_lambda"; -//│ constexpr static inline uint32_t typeTag = nextTypeTag(); -//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->_mls_lam_arg0.print(); std::printf(", "); this->_mls_lam_arg1.print(); std::printf(")"); } -//│ virtual void destroy() override { _mlsValue::destroy(this->_mls_lam_arg0); _mlsValue::destroy(this->_mls_lam_arg1); operator delete (this, std::align_val_t(_mlsAlignment)); } -//│ static _mlsValue create(_mlsValue _mls_lam_arg0, _mlsValue _mls_lam_arg1) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) _mls_Lambda_lambda1; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->_mls_lam_arg0 = _mls_lam_arg0; _mlsVal->_mls_lam_arg1 = _mls_lam_arg1; return _mlsValue(_mlsVal); } -//│ virtual _mlsValue _mls_apply2(_mlsValue, _mlsValue); -//│ }; -//│ struct _mls_Lambda1: public _mls_Callable { -//│ _mlsValue _mls_lam_arg0; -//│ _mlsValue _mls_lam_arg1; -//│ constexpr static inline const char *typeName = "Lambda"; -//│ constexpr static inline uint32_t typeTag = nextTypeTag(); -//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->_mls_lam_arg0.print(); std::printf(", "); this->_mls_lam_arg1.print(); std::printf(")"); } -//│ virtual void destroy() override { _mlsValue::destroy(this->_mls_lam_arg0); _mlsValue::destroy(this->_mls_lam_arg1); operator delete (this, std::align_val_t(_mlsAlignment)); } -//│ static _mlsValue create(_mlsValue _mls_lam_arg0, _mlsValue _mls_lam_arg1) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) _mls_Lambda1; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->_mls_lam_arg0 = _mls_lam_arg0; _mlsVal->_mls_lam_arg1 = _mls_lam_arg1; return _mlsValue(_mlsVal); } -//│ virtual _mlsValue _mls_apply2(_mlsValue, _mlsValue); -//│ }; -//│ _mlsValue _mls_add4(_mlsValue _mls_a, _mlsValue _mls_b) { -//│ _mlsValue _mls_retval; -//│ auto _mls_x14 = _mlsValue::create<_mls_Lambda_lambda1>(_mls_a, _mls_b); -//│ _mls_retval = _mls_x14; -//│ return _mls_retval; -//│ } -//│ _mlsValue _mls_add4_curried(_mlsValue _mls_a1, _mlsValue _mls_b1) { -//│ _mlsValue _mls_retval; -//│ auto _mls_x15 = _mlsValue::create<_mls_Lambda1>(_mls_a1, _mls_b1); -//│ _mls_retval = _mls_x15; -//│ return _mls_retval; -//│ } -//│ _mlsValue _mls_entry2() { -//│ _mlsValue _mls_retval; -//│ auto _mls_x16 = _mls_add4(_mlsValue::fromIntLit(1), _mlsValue::fromIntLit(2)); -//│ auto _mls_x17 = _mlsMethodCall<_mls_Callable>(_mls_x16)->_mls_apply2(_mlsValue::fromIntLit(3), _mlsValue::fromIntLit(4)); -//│ _mls_retval = _mls_x17; -//│ return _mls_retval; -//│ } -//│ _mlsValue _mls_Lambda_lambda1::_mls_apply2(_mlsValue _mls_c, _mlsValue _mls_d) { -//│ _mlsValue _mls_retval; -//│ auto _mls_x8 = (_mls_lam_arg0 + _mls_lam_arg1); -//│ auto _mls_x9 = (_mls_x8 + _mls_c); -//│ auto _mls_x10 = (_mls_x9 + _mls_d); -//│ _mls_retval = _mls_x10; -//│ return _mls_retval; -//│ } -//│ _mlsValue _mls_Lambda1::_mls_apply2(_mlsValue _mls_c1, _mlsValue _mls_d1) { -//│ _mlsValue _mls_retval; -//│ auto _mls_x11 = (_mls_lam_arg0 + _mls_lam_arg1); -//│ auto _mls_x12 = (_mls_x11 + _mls_c1); -//│ auto _mls_x13 = (_mls_x12 + _mls_d1); -//│ _mls_retval = _mls_x13; -//│ return _mls_retval; -//│ } -//│ _mlsValue _mlsMain() { return _mls_entry2(); } -//│ int main() { return _mlsLargeStack(_mlsMainWrapper); } //│ //│ Interpreted: //│ 10 -:sllir -:intl -:scpp fun add(a, b) = a + b fun dummy() = add dummy()(1, 2) //│ = 3 -//│ LLIR: -//│ class Lambda_add() extends Callable { -//│ def apply2$643(arg$675,arg$676) = -//│ let* (x$679) = add(arg$675,arg$676) in -//│ x$679 -//│ } -//│ def add$659(a$662,b$663) = -//│ let x$674 = +(a$662,b$663) in -//│ x$674 -//│ def dummy$660() = -//│ let x$680 = Lambda_add$677() in -//│ x$680 -//│ def entry$683() = -//│ let* (x$681) = dummy() in -//│ let x$682 = Callable.apply2$643(x$681,1,2) in -//│ x$682 -//│ entry = entry$683 -//│ -//│ Cpp: -//│ #include "mlsprelude.h" -//│ struct _mls_Lambda_add; -//│ _mlsValue _mls_add1(_mlsValue, _mlsValue); -//│ _mlsValue _mls_dummy(); -//│ _mlsValue _mls_entry3(); -//│ struct _mls_Lambda_add: public _mls_Callable { -//│ -//│ constexpr static inline const char *typeName = "Lambda_add"; -//│ constexpr static inline uint32_t typeTag = nextTypeTag(); -//│ virtual void print() const override { std::printf("%s", typeName); } -//│ virtual void destroy() override { operator delete (this, std::align_val_t(_mlsAlignment)); } -//│ static _mlsValue create() { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) _mls_Lambda_add; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; return _mlsValue(_mlsVal); } -//│ virtual _mlsValue _mls_apply2(_mlsValue, _mlsValue); -//│ }; -//│ _mlsValue _mls_add1(_mlsValue _mls_a2, _mlsValue _mls_b2) { -//│ _mlsValue _mls_retval; -//│ auto _mls_x19 = (_mls_a2 + _mls_b2); -//│ _mls_retval = _mls_x19; -//│ return _mls_retval; -//│ } -//│ _mlsValue _mls_dummy() { -//│ _mlsValue _mls_retval; -//│ auto _mls_x20 = _mlsValue::create<_mls_Lambda_add>(); -//│ _mls_retval = _mls_x20; -//│ return _mls_retval; -//│ } -//│ _mlsValue _mls_entry3() { -//│ _mlsValue _mls_retval; -//│ auto _mls_x21 = _mls_dummy(); -//│ auto _mls_x22 = _mlsMethodCall<_mls_Callable>(_mls_x21)->_mls_apply2(_mlsValue::fromIntLit(1), _mlsValue::fromIntLit(2)); -//│ _mls_retval = _mls_x22; -//│ return _mls_retval; -//│ } -//│ _mlsValue _mls_Lambda_add::_mls_apply2(_mlsValue _mls_arg, _mlsValue _mls_arg1) { -//│ _mlsValue _mls_retval; -//│ auto _mls_x18 = _mls_add1(_mls_arg, _mls_arg1); -//│ _mls_retval = _mls_x18; -//│ return _mls_retval; -//│ } -//│ _mlsValue _mlsMain() { return _mls_entry3(); } -//│ int main() { return _mlsLargeStack(_mlsMainWrapper); } //│ //│ Interpreted: //│ 3 -:todo "js backend has problem with private field / pattern matching" -:sllir -:intl abstract class List[out T]: Cons[T] | Nil data class (::) Cons[out T](head: T, tail: List[T]) extends List[T] object Nil extends List @@ -283,62 +66,10 @@ fun main() = map(inc, 3 :: 4 :: Nil) main() //│ = Cons(4, Cons(5, Nil)) -//│ LLIR: -//│ class List() -//│ class Cons(head$696,tail$697) extends List -//│ class Nil() extends List -//│ class Lambda_lambda() extends Callable { -//│ def apply1$591(x$721) = -//│ let* (x$764) = inc(x$721) in -//│ x$764 -//│ } -//│ class Lambda_inc() extends Callable { -//│ def apply1$591(arg$771) = -//│ let* (x$774) = inc(arg$771) in -//│ x$774 -//│ } -//│ def map$685(f$705,l$706) = -//│ case l$706 of -//│ Cons$693 => -//│ let x$752 = l$706. in -//│ let x$753 = l$706. in -//│ let x$754 = Callable.apply1$591(f$705,x$752) in -//│ let* (x$755) = map(f$705,x$753) in -//│ let x$756 = Cons$693(x$754,x$755) in -//│ x$756 -//│ Nil$702 => -//│ let x$757 = Nil$702() in -//│ x$757 -//│ _ => -//│ panic "match error" -//│ def j$751() = -//│ undefined -//│ def inc$688(x$716) = -//│ let x$758 = +(x$716,1) in -//│ x$758 -//│ def main$686() = -//│ let x$759 = Nil$702() in -//│ let x$760 = Cons$693(2,x$759) in -//│ let x$761 = Cons$693(1,x$760) in -//│ let x$765 = Lambda_lambda$762() in -//│ let* (x$766) = map(x$765,x$761) in -//│ let x$767 = Nil$702() in -//│ let x$768 = Cons$693(4,x$767) in -//│ let x$769 = Cons$693(3,x$768) in -//│ let x$775 = Lambda_inc$772() in -//│ let* (x$770) = map(x$775,x$769) in -//│ x$770 -//│ def entry$777() = -//│ let* (x$776) = main() in -//│ x$776 -//│ entry = entry$777 //│ //│ Interpreted: //│ Cons(4,Cons(5,Nil())) -:scpp -:sllir -:intl abstract class List[out T]: Cons[T] | Nil data class (::) Cons[out T](head: T, tail: List[T]) extends List[T] object Nil extends List @@ -353,255 +84,11 @@ fun nubBy(eq, ls) = if ls is h :: t then h :: nubBy(eq, filter(y => not(eq(h, y)), t)) nubBy((x, y) => x == y, 1 :: 2 :: 3 :: 3 :: Nil) //│ = Cons(1, Cons(2, Cons(3, Nil))) -//│ LLIR: -//│ class List() -//│ class Cons(head$790,tail$791) extends List -//│ class Nil() extends List -//│ class Lambda_lambda(lam_arg0$877,lam_arg1$878) extends Callable { -//│ def apply1$591(y$824) = -//│ let x$879 = Callable.apply2$643(lam_arg0$877,lam_arg1$878,y$824) in -//│ let* (x$880) = not(x$879) in -//│ x$880 -//│ } -//│ class Lambda_lambda() extends Callable { -//│ def apply2$643(arg$892,arg$893) = -//│ let* (x$896) = lambda(arg$892,arg$893) in -//│ x$896 -//│ } -//│ def not$781(c$799) = -//│ case c$799 of -//│ BoolLit(true) => -//│ false -//│ _ => -//│ true -//│ def j$861() = -//│ undefined -//│ def filter$780(f$802,ls$803) = -//│ case ls$803 of -//│ Nil$796 => -//│ let x$863 = Nil$796() in -//│ x$863 -//│ Cons$787 => -//│ let x$864 = ls$803. in -//│ let x$865 = ls$803. in -//│ let x$866 = Callable.apply1$591(f$802,x$864) in -//│ case x$866 of -//│ BoolLit(true) => -//│ let* (x$868) = filter(f$802,x$865) in -//│ let x$869 = Cons$787(x$864,x$868) in -//│ x$869 -//│ _ => -//│ let* (x$870) = filter(f$802,x$865) in -//│ x$870 -//│ _ => -//│ panic "match error" -//│ def j$867() = -//│ jump j$862() -//│ def j$862() = -//│ undefined -//│ def nubBy$783(eq$815,ls$816) = -//│ case ls$816 of -//│ Nil$796 => -//│ let x$872 = Nil$796() in -//│ x$872 -//│ Cons$787 => -//│ let x$873 = ls$816. in -//│ let x$874 = ls$816. in -//│ let x$881 = Lambda_lambda$875(eq$815,x$873) in -//│ let* (x$882) = filter(x$881,x$874) in -//│ let* (x$883) = nubBy(eq$815,x$882) in -//│ let x$884 = Cons$787(x$873,x$883) in -//│ x$884 -//│ _ => -//│ panic "match error" -//│ def j$871() = -//│ undefined -//│ def lambda$860(x$829,y$830) = -//│ let x$890 = ==(x$829,y$830) in -//│ x$890 -//│ def entry$898() = -//│ let x$885 = Nil$796() in -//│ let x$886 = Cons$787(3,x$885) in -//│ let x$887 = Cons$787(3,x$886) in -//│ let x$888 = Cons$787(2,x$887) in -//│ let x$889 = Cons$787(1,x$888) in -//│ let x$897 = Lambda_lambda$894() in -//│ let* (x$891) = nubBy(x$897,x$889) in -//│ x$891 -//│ entry = entry$898 -//│ -//│ Cpp: -//│ #include "mlsprelude.h" -//│ struct _mls_List1; -//│ struct _mls_Cons1; -//│ struct _mls_Nil1; -//│ struct _mls_Lambda_lambda4; -//│ struct _mls_Lambda_lambda3; -//│ _mlsValue _mls_entry5(); -//│ _mlsValue _mls_j4(); -//│ _mlsValue _mls_lambda(_mlsValue, _mlsValue); -//│ _mlsValue _mls_filter(_mlsValue, _mlsValue); -//│ _mlsValue _mls_nubBy(_mlsValue, _mlsValue); -//│ _mlsValue _mls_j2(); -//│ _mlsValue _mls_j3(); -//│ _mlsValue _mls_not(_mlsValue); -//│ _mlsValue _mls_j1(); -//│ struct _mls_List1: public _mlsObject { -//│ -//│ constexpr static inline const char *typeName = "List"; -//│ constexpr static inline uint32_t typeTag = nextTypeTag(); -//│ virtual void print() const override { std::printf("%s", typeName); } -//│ virtual void destroy() override { operator delete (this, std::align_val_t(_mlsAlignment)); } -//│ static _mlsValue create() { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) _mls_List1; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; return _mlsValue(_mlsVal); } -//│ -//│ }; -//│ struct _mls_Cons1: public _mls_List1 { -//│ _mlsValue _mls_head; -//│ _mlsValue _mls_tail; -//│ constexpr static inline const char *typeName = "Cons"; -//│ constexpr static inline uint32_t typeTag = nextTypeTag(); -//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->_mls_head.print(); std::printf(", "); this->_mls_tail.print(); std::printf(")"); } -//│ virtual void destroy() override { _mlsValue::destroy(this->_mls_head); _mlsValue::destroy(this->_mls_tail); operator delete (this, std::align_val_t(_mlsAlignment)); } -//│ static _mlsValue create(_mlsValue _mls_head, _mlsValue _mls_tail) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) _mls_Cons1; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->_mls_head = _mls_head; _mlsVal->_mls_tail = _mls_tail; return _mlsValue(_mlsVal); } -//│ -//│ }; -//│ struct _mls_Nil1: public _mls_List1 { -//│ -//│ constexpr static inline const char *typeName = "Nil"; -//│ constexpr static inline uint32_t typeTag = nextTypeTag(); -//│ virtual void print() const override { std::printf("%s", typeName); } -//│ virtual void destroy() override { operator delete (this, std::align_val_t(_mlsAlignment)); } -//│ static _mlsValue create() { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) _mls_Nil1; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; return _mlsValue(_mlsVal); } -//│ -//│ }; -//│ struct _mls_Lambda_lambda4: public _mls_Callable { -//│ -//│ constexpr static inline const char *typeName = "Lambda_lambda"; -//│ constexpr static inline uint32_t typeTag = nextTypeTag(); -//│ virtual void print() const override { std::printf("%s", typeName); } -//│ virtual void destroy() override { operator delete (this, std::align_val_t(_mlsAlignment)); } -//│ static _mlsValue create() { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) _mls_Lambda_lambda4; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; return _mlsValue(_mlsVal); } -//│ virtual _mlsValue _mls_apply2(_mlsValue, _mlsValue); -//│ }; -//│ struct _mls_Lambda_lambda3: public _mls_Callable { -//│ _mlsValue _mls_lam_arg0; -//│ _mlsValue _mls_lam_arg1; -//│ constexpr static inline const char *typeName = "Lambda_lambda"; -//│ constexpr static inline uint32_t typeTag = nextTypeTag(); -//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->_mls_lam_arg0.print(); std::printf(", "); this->_mls_lam_arg1.print(); std::printf(")"); } -//│ virtual void destroy() override { _mlsValue::destroy(this->_mls_lam_arg0); _mlsValue::destroy(this->_mls_lam_arg1); operator delete (this, std::align_val_t(_mlsAlignment)); } -//│ static _mlsValue create(_mlsValue _mls_lam_arg0, _mlsValue _mls_lam_arg1) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) _mls_Lambda_lambda3; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->_mls_lam_arg0 = _mls_lam_arg0; _mlsVal->_mls_lam_arg1 = _mls_lam_arg1; return _mlsValue(_mlsVal); } -//│ virtual _mlsValue _mls_apply1(_mlsValue); -//│ }; -//│ _mlsValue _mls_not(_mlsValue _mls_c2) { -//│ _mlsValue _mls_retval; -//│ if (_mlsValue::isIntLit(_mls_c2, 1)) { -//│ _mls_retval = _mlsValue::fromIntLit(0); -//│ } else { -//│ _mls_retval = _mlsValue::fromIntLit(1); -//│ } -//│ return _mls_retval; -//│ } -//│ _mlsValue _mls_j3() { -//│ _mlsValue _mls_retval; -//│ _mls_retval = _mlsValue::create<_mls_Unit>(); -//│ return _mls_retval; -//│ } -//│ _mlsValue _mls_nubBy(_mlsValue _mls_eq, _mlsValue _mls_ls1) { -//│ _mlsValue _mls_retval; -//│ if (_mlsValue::isValueOf<_mls_Nil1>(_mls_ls1)) { -//│ auto _mls_x63 = _mlsValue::create<_mls_Nil1>(); -//│ _mls_retval = _mls_x63; -//│ } else if (_mlsValue::isValueOf<_mls_Cons1>(_mls_ls1)) { -//│ auto _mls_x57 = _mlsValue::cast<_mls_Cons1>(_mls_ls1)->_mls_head; -//│ auto _mls_x58 = _mlsValue::cast<_mls_Cons1>(_mls_ls1)->_mls_tail; -//│ auto _mls_x59 = _mlsValue::create<_mls_Lambda_lambda3>(_mls_eq, _mls_x57); -//│ auto _mls_x60 = _mls_filter(_mls_x59, _mls_x58); -//│ auto _mls_x61 = _mls_nubBy(_mls_eq, _mls_x60); -//│ auto _mls_x62 = _mlsValue::create<_mls_Cons1>(_mls_x57, _mls_x61); -//│ _mls_retval = _mls_x62; -//│ } else { -//│ throw std::runtime_error("match error"); -//│ } -//│ return _mls_retval; -//│ } -//│ _mlsValue _mls_entry5() { -//│ _mlsValue _mls_retval; -//│ auto _mls_x64 = _mlsValue::create<_mls_Nil1>(); -//│ auto _mls_x65 = _mlsValue::create<_mls_Cons1>(_mlsValue::fromIntLit(3), _mls_x64); -//│ auto _mls_x66 = _mlsValue::create<_mls_Cons1>(_mlsValue::fromIntLit(3), _mls_x65); -//│ auto _mls_x67 = _mlsValue::create<_mls_Cons1>(_mlsValue::fromIntLit(2), _mls_x66); -//│ auto _mls_x68 = _mlsValue::create<_mls_Cons1>(_mlsValue::fromIntLit(1), _mls_x67); -//│ auto _mls_x69 = _mlsValue::create<_mls_Lambda_lambda4>(); -//│ auto _mls_x70 = _mls_nubBy(_mls_x69, _mls_x68); -//│ _mls_retval = _mls_x70; -//│ return _mls_retval; -//│ } -//│ _mlsValue _mls_j1() { -//│ _mlsValue _mls_retval; -//│ _mls_retval = _mlsValue::create<_mls_Unit>(); -//│ return _mls_retval; -//│ } -//│ _mlsValue _mls_filter(_mlsValue _mls_f1, _mlsValue _mls_ls) { -//│ _mlsValue _mls_retval; -//│ if (_mlsValue::isValueOf<_mls_Nil1>(_mls_ls)) { -//│ auto _mls_x54 = _mlsValue::create<_mls_Nil1>(); -//│ _mls_retval = _mls_x54; -//│ } else if (_mlsValue::isValueOf<_mls_Cons1>(_mls_ls)) { -//│ auto _mls_x48 = _mlsValue::cast<_mls_Cons1>(_mls_ls)->_mls_head; -//│ auto _mls_x49 = _mlsValue::cast<_mls_Cons1>(_mls_ls)->_mls_tail; -//│ auto _mls_x50 = _mlsMethodCall<_mls_Callable>(_mls_f1)->_mls_apply1(_mls_x48); -//│ if (_mlsValue::isIntLit(_mls_x50, 1)) { -//│ auto _mls_x52 = _mls_filter(_mls_f1, _mls_x49); -//│ auto _mls_x53 = _mlsValue::create<_mls_Cons1>(_mls_x48, _mls_x52); -//│ _mls_retval = _mls_x53; -//│ } else { -//│ auto _mls_x51 = _mls_filter(_mls_f1, _mls_x49); -//│ _mls_retval = _mls_x51; -//│ } -//│ } else { -//│ throw std::runtime_error("match error"); -//│ } -//│ return _mls_retval; -//│ } -//│ _mlsValue _mls_j2() { -//│ _mlsValue _mls_retval; -//│ _mls_retval = _mls_j1(); -//│ return _mls_retval; -//│ } -//│ _mlsValue _mls_lambda(_mlsValue _mls_x56, _mlsValue _mls_y3) { -//│ _mlsValue _mls_retval; -//│ auto _mls_x55 = (_mls_x56 == _mls_y3); -//│ _mls_retval = _mls_x55; -//│ return _mls_retval; -//│ } -//│ _mlsValue _mls_j4() { -//│ _mlsValue _mls_retval; -//│ _mls_retval = _mlsValue::create<_mls_Unit>(); -//│ return _mls_retval; -//│ } -//│ _mlsValue _mls_Lambda_lambda4::_mls_apply2(_mlsValue _mls_arg3, _mlsValue _mls_arg4) { -//│ _mlsValue _mls_retval; -//│ auto _mls_x45 = _mls_lambda(_mls_arg3, _mls_arg4); -//│ _mls_retval = _mls_x45; -//│ return _mls_retval; -//│ } -//│ _mlsValue _mls_Lambda_lambda3::_mls_apply1(_mlsValue _mls_y2) { -//│ _mlsValue _mls_retval; -//│ auto _mls_x46 = _mlsMethodCall<_mls_Callable>(_mls_lam_arg0)->_mls_apply2(_mls_lam_arg1, _mls_y2); -//│ auto _mls_x47 = _mls_not(_mls_x46); -//│ _mls_retval = _mls_x47; -//│ return _mls_retval; -//│ } -//│ _mlsValue _mlsMain() { return _mls_entry5(); } -//│ int main() { return _mlsLargeStack(_mlsMainWrapper); } //│ //│ Interpreted: //│ Cons(1,Cons(2,Cons(3,Nil()))) -:sllir :intl -:scpp fun f(x) = fun self_rec(x) = if x == 0 then 0 @@ -609,84 +96,10 @@ fun f(x) = self_rec(x) f(3) //│ = 6 -//│ LLIR: -//│ class Lambda_self_rec() extends Callable { -//│ def apply1$591(x$904) = -//│ let x$922 = ==(x$904,0) in -//│ case x$922 of -//│ BoolLit(true) => -//│ 0 -//│ _ => -//│ let x$924 = -(x$904,1) in -//│ let x$925 = Callable.apply1$591($590,x$924) in -//│ let x$926 = +(x$904,x$925) in -//│ x$926 -//│ } -//│ def f$900(x$902) = -//│ let x$927 = Lambda_self_rec$920() in -//│ let x$928 = Callable.apply1$591(x$927,x$902) in -//│ x$928 -//│ def j$923() = -//│ undefined -//│ def entry$930() = -//│ let* (x$929) = f(3) in -//│ x$929 -//│ entry = entry$930 -//│ -//│ Cpp: -//│ #include "mlsprelude.h" -//│ struct _mls_Lambda_self_rec; -//│ _mlsValue _mls_j5(); -//│ _mlsValue _mls_f2(_mlsValue); -//│ _mlsValue _mls_entry6(); -//│ struct _mls_Lambda_self_rec: public _mls_Callable { -//│ -//│ constexpr static inline const char *typeName = "Lambda_self_rec"; -//│ constexpr static inline uint32_t typeTag = nextTypeTag(); -//│ virtual void print() const override { std::printf("%s", typeName); } -//│ virtual void destroy() override { operator delete (this, std::align_val_t(_mlsAlignment)); } -//│ static _mlsValue create() { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) _mls_Lambda_self_rec; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; return _mlsValue(_mlsVal); } -//│ virtual _mlsValue _mls_apply1(_mlsValue); -//│ }; -//│ _mlsValue _mls_j5() { -//│ _mlsValue _mls_retval; -//│ _mls_retval = _mlsValue::create<_mls_Unit>(); -//│ return _mls_retval; -//│ } -//│ _mlsValue _mls_f2(_mlsValue _mls_x77) { -//│ _mlsValue _mls_retval; -//│ auto _mls_x76 = _mlsValue::create<_mls_Lambda_self_rec>(); -//│ auto _mls_x78 = _mlsMethodCall<_mls_Callable>(_mls_x76)->_mls_apply1(_mls_x77); -//│ _mls_retval = _mls_x78; -//│ return _mls_retval; -//│ } -//│ _mlsValue _mls_entry6() { -//│ _mlsValue _mls_retval; -//│ auto _mls_x79 = _mls_f2(_mlsValue::fromIntLit(3)); -//│ _mls_retval = _mls_x79; -//│ return _mls_retval; -//│ } -//│ _mlsValue _mls_Lambda_self_rec::_mls_apply1(_mlsValue _mls_x72) { -//│ _mlsValue _mls_retval; -//│ auto _mls_x71 = (_mls_x72 == _mlsValue::fromIntLit(0)); -//│ if (_mlsValue::isIntLit(_mls_x71, 1)) { -//│ _mls_retval = _mlsValue::fromIntLit(0); -//│ } else { -//│ auto _mls_x73 = (_mls_x72 - _mlsValue::fromIntLit(1)); -//│ auto _mls_x74 = this->_mls_apply1(_mls_x73); -//│ auto _mls_x75 = (_mls_x72 + _mls_x74); -//│ _mls_retval = _mls_x75; -//│ } -//│ return _mls_retval; -//│ } -//│ _mlsValue _mlsMain() { return _mls_entry6(); } -//│ int main() { return _mlsLargeStack(_mlsMainWrapper); } //│ //│ Interpreted: //│ 6 -:sllir -:scpp fun f(x) = fun even(x) = fun odd(x) = @@ -699,152 +112,6 @@ fun f(x) = even(x) f(3) //│ = false -//│ LLIR: -//│ class Lambda_odd(lam_arg0$967) extends Callable { -//│ def apply1$591(x$939) = -//│ let x$968 = ==(x$939,0) in -//│ case x$968 of -//│ BoolLit(true) => -//│ true -//│ _ => -//│ let x$970 = ==(x$939,1) in -//│ case x$970 of -//│ BoolLit(true) => -//│ false -//│ _ => -//│ let x$972 = -(x$939,1) in -//│ let x$973 = Callable.apply1$591(lam_arg0$967,x$972) in -//│ x$973 -//│ } -//│ class Lambda_even() extends Callable { -//│ def apply1$591(x$937) = -//│ let x$974 = Lambda_odd$965($590) in -//│ let x$975 = ==(x$937,0) in -//│ case x$975 of -//│ BoolLit(true) => -//│ true -//│ _ => -//│ let x$977 = ==(x$937,1) in -//│ case x$977 of -//│ BoolLit(true) => -//│ false -//│ _ => -//│ let x$979 = -(x$937,1) in -//│ let x$980 = Callable.apply1$591(x$974,x$979) in -//│ x$980 -//│ } -//│ def f$933(x$935) = -//│ let x$981 = Lambda_even$963() in -//│ let x$982 = Callable.apply1$591(x$981,x$935) in -//│ x$982 -//│ def j$971() = -//│ jump j$969() -//│ def j$969() = -//│ undefined -//│ def j$978() = -//│ jump j$976() -//│ def j$976() = -//│ undefined -//│ def entry$984() = -//│ let* (x$983) = f(3) in -//│ x$983 -//│ entry = entry$984 //│ -//│ Cpp: -//│ #include "mlsprelude.h" -//│ struct _mls_Lambda_odd; -//│ struct _mls_Lambda_even; -//│ _mlsValue _mls_entry7(); -//│ _mlsValue _mls_j6(); -//│ _mlsValue _mls_f3(_mlsValue); -//│ _mlsValue _mls_j7(); -//│ _mlsValue _mls_j9(); -//│ _mlsValue _mls_j8(); -//│ struct _mls_Lambda_odd: public _mls_Callable { -//│ _mlsValue _mls_lam_arg0; -//│ constexpr static inline const char *typeName = "Lambda_odd"; -//│ constexpr static inline uint32_t typeTag = nextTypeTag(); -//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->_mls_lam_arg0.print(); std::printf(")"); } -//│ virtual void destroy() override { _mlsValue::destroy(this->_mls_lam_arg0); operator delete (this, std::align_val_t(_mlsAlignment)); } -//│ static _mlsValue create(_mlsValue _mls_lam_arg0) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) _mls_Lambda_odd; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->_mls_lam_arg0 = _mls_lam_arg0; return _mlsValue(_mlsVal); } -//│ virtual _mlsValue _mls_apply1(_mlsValue); -//│ }; -//│ struct _mls_Lambda_even: public _mls_Callable { -//│ -//│ constexpr static inline const char *typeName = "Lambda_even"; -//│ constexpr static inline uint32_t typeTag = nextTypeTag(); -//│ virtual void print() const override { std::printf("%s", typeName); } -//│ virtual void destroy() override { operator delete (this, std::align_val_t(_mlsAlignment)); } -//│ static _mlsValue create() { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) _mls_Lambda_even; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; return _mlsValue(_mlsVal); } -//│ virtual _mlsValue _mls_apply1(_mlsValue); -//│ }; -//│ _mlsValue _mls_entry7() { -//│ _mlsValue _mls_retval; -//│ auto _mls_x94 = _mls_f3(_mlsValue::fromIntLit(3)); -//│ _mls_retval = _mls_x94; -//│ return _mls_retval; -//│ } -//│ _mlsValue _mls_j6() { -//│ _mlsValue _mls_retval; -//│ _mls_retval = _mlsValue::create<_mls_Unit>(); -//│ return _mls_retval; -//│ } -//│ _mlsValue _mls_f3(_mlsValue _mls_x92) { -//│ _mlsValue _mls_retval; -//│ auto _mls_x91 = _mlsValue::create<_mls_Lambda_even>(); -//│ auto _mls_x93 = _mlsMethodCall<_mls_Callable>(_mls_x91)->_mls_apply1(_mls_x92); -//│ _mls_retval = _mls_x93; -//│ return _mls_retval; -//│ } -//│ _mlsValue _mls_j9() { -//│ _mlsValue _mls_retval; -//│ _mls_retval = _mls_j8(); -//│ return _mls_retval; -//│ } -//│ _mlsValue _mls_j7() { -//│ _mlsValue _mls_retval; -//│ _mls_retval = _mls_j6(); -//│ return _mls_retval; -//│ } -//│ _mlsValue _mls_j8() { -//│ _mlsValue _mls_retval; -//│ _mls_retval = _mlsValue::create<_mls_Unit>(); -//│ return _mls_retval; -//│ } -//│ _mlsValue _mls_Lambda_odd::_mls_apply1(_mlsValue _mls_x81) { -//│ _mlsValue _mls_retval; -//│ auto _mls_x80 = (_mls_x81 == _mlsValue::fromIntLit(0)); -//│ if (_mlsValue::isIntLit(_mls_x80, 1)) { -//│ _mls_retval = _mlsValue::fromIntLit(1); -//│ } else { -//│ auto _mls_x82 = (_mls_x81 == _mlsValue::fromIntLit(1)); -//│ if (_mlsValue::isIntLit(_mls_x82, 1)) { -//│ _mls_retval = _mlsValue::fromIntLit(0); -//│ } else { -//│ auto _mls_x83 = (_mls_x81 - _mlsValue::fromIntLit(1)); -//│ auto _mls_x84 = _mlsMethodCall<_mls_Callable>(_mls_lam_arg0)->_mls_apply1(_mls_x83); -//│ _mls_retval = _mls_x84; -//│ } -//│ } -//│ return _mls_retval; -//│ } -//│ _mlsValue _mls_Lambda_even::_mls_apply1(_mlsValue _mls_x87) { -//│ _mlsValue _mls_retval; -//│ auto _mls_x85 = _mlsValue::create<_mls_Lambda_odd>(_mlsValue(this, _mlsValue::inc_ref_tag{})); -//│ auto _mls_x86 = (_mls_x87 == _mlsValue::fromIntLit(0)); -//│ if (_mlsValue::isIntLit(_mls_x86, 1)) { -//│ _mls_retval = _mlsValue::fromIntLit(1); -//│ } else { -//│ auto _mls_x88 = (_mls_x87 == _mlsValue::fromIntLit(1)); -//│ if (_mlsValue::isIntLit(_mls_x88, 1)) { -//│ _mls_retval = _mlsValue::fromIntLit(0); -//│ } else { -//│ auto _mls_x89 = (_mls_x87 - _mlsValue::fromIntLit(1)); -//│ auto _mls_x90 = _mlsMethodCall<_mls_Callable>(_mls_x85)->_mls_apply1(_mls_x89); -//│ _mls_retval = _mls_x90; -//│ } -//│ } -//│ return _mls_retval; -//│ } -//│ _mlsValue _mlsMain() { return _mls_entry7(); } -//│ int main() { return _mlsLargeStack(_mlsMainWrapper); } +//│ Interpreted: +//│ false diff --git a/hkmc2/shared/src/test/mlscript/llir/Legacy.mls b/hkmc2/shared/src/test/mlscript/llir/Legacy.mls index 304f174762..15b19f7106 100644 --- a/hkmc2/shared/src/test/mlscript/llir/Legacy.mls +++ b/hkmc2/shared/src/test/mlscript/llir/Legacy.mls @@ -2,6 +2,8 @@ :llir :cpp +// This file contains all legacy tests for LLIR in the old MLScript compiler. + :intl data class Pair[A, B](x: A, y: B) fun mktup2(x, y) = mktup(x, y) @@ -128,8 +130,8 @@ foo() //│ O() :intl -class A(x, y, z) -class B(m, n) +data class A(x, y, z) +data class B(m, n) fun complex_foo(t) = let r = if t is A(x, y, z) then x + y * z @@ -143,7 +145,7 @@ fun bar() = complex_foo(A(6, 7, 8)) complex_foo(B(9, 10)) bar() -//│ = NaN +//│ = 3 //│ //│ Interpreted: //│ 3 diff --git a/hkmc2/shared/src/test/mlscript/llir/nofib/awards.mls b/hkmc2/shared/src/test/mlscript/llir/nofib/awards.mls index 9bcfe86bf9..9a10765bba 100644 --- a/hkmc2/shared/src/test/mlscript/llir/nofib/awards.mls +++ b/hkmc2/shared/src/test/mlscript/llir/nofib/awards.mls @@ -69,108 +69,5 @@ fun testAwards_nofib(n) = map(x => print(findallawards(competitors(intMod(x, 100)))), enumFromTo(1, n)) :runWholeCpp +:silent testAwards_nofib(100) -//│ -//│ -//│ Execution succeeded: -//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(70, Cons(35, Cons(1, Cons(34, Nil))))), Cons(Tuple2("Gold", Tuple2(88, Cons(27, Cons(40, Cons(21, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Bronze", Tuple2(52, Cons(23, Cons(19, Cons(10, Nil))))), Nil))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Nil))), Nil)))) -//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(71, Cons(35, Cons(2, Cons(34, Nil))))), Cons(Tuple2("Gold", Tuple2(88, Cons(27, Cons(40, Cons(21, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(23, Cons(45, Cons(2, Nil))))), Cons(Tuple2("Bronze", Tuple2(50, Cons(19, Cons(17, Cons(14, Nil))))), Nil))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(70, Cons(54, Cons(2, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(73, Cons(9, Cons(23, Cons(41, Nil))))), Nil))), Nil)))) -//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(70, Cons(27, Cons(40, Cons(3, Nil))))), Cons(Tuple2("Gold", Tuple2(90, Cons(35, Cons(34, Cons(21, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Bronze", Tuple2(52, Cons(23, Cons(19, Cons(10, Nil))))), Nil))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(71, Cons(54, Cons(3, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(73, Cons(9, Cons(23, Cons(41, Nil))))), Nil))), Nil)))) -//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(71, Cons(27, Cons(40, Cons(4, Nil))))), Cons(Tuple2("Gold", Tuple2(90, Cons(35, Cons(34, Cons(21, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Bronze", Tuple2(52, Cons(23, Cons(19, Cons(10, Nil))))), Nil))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Nil))), Nil)))) -//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(72, Cons(27, Cons(40, Cons(5, Nil))))), Cons(Tuple2("Gold", Tuple2(90, Cons(35, Cons(34, Cons(21, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Bronze", Tuple2(52, Cons(23, Cons(19, Cons(10, Nil))))), Nil))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Nil))), Nil)))) -//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(73, Cons(27, Cons(40, Cons(6, Nil))))), Cons(Tuple2("Gold", Tuple2(90, Cons(35, Cons(34, Cons(21, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(19, Cons(45, Cons(6, Nil))))), Cons(Tuple2("Bronze", Tuple2(50, Cons(23, Cons(17, Cons(10, Nil))))), Nil))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(70, Cons(23, Cons(6, Cons(41, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Nil))), Nil)))) -//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(74, Cons(27, Cons(40, Cons(7, Nil))))), Cons(Tuple2("Gold", Tuple2(90, Cons(35, Cons(34, Cons(21, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Bronze", Tuple2(52, Cons(23, Cons(19, Cons(10, Nil))))), Nil))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(70, Cons(9, Cons(54, Cons(7, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Bronze", Tuple2(50, Cons(23, Cons(9, Cons(18, Nil))))), Nil)))), Nil)))) -//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(70, Cons(35, Cons(27, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(95, Cons(40, Cons(34, Cons(21, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(8, Cons(17, Nil))))), Cons(Tuple2("Bronze", Tuple2(50, Cons(23, Cons(19, Cons(8, Nil))))), Nil))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(71, Cons(9, Cons(54, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Bronze", Tuple2(50, Cons(23, Cons(9, Cons(18, Nil))))), Nil)))), Nil)))) -//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(70, Cons(27, Cons(9, Cons(34, Nil))))), Cons(Tuple2("Gold", Tuple2(96, Cons(35, Cons(40, Cons(21, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Bronze", Tuple2(51, Cons(23, Cons(19, Cons(9, Nil))))), Nil))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Bronze", Tuple2(50, Cons(23, Cons(9, Cons(18, Nil))))), Nil)))), Nil)))) -//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(71, Cons(27, Cons(10, Cons(34, Nil))))), Cons(Tuple2("Gold", Tuple2(96, Cons(35, Cons(40, Cons(21, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Bronze", Tuple2(52, Cons(23, Cons(19, Cons(10, Nil))))), Nil))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Bronze", Tuple2(51, Cons(23, Cons(10, Cons(18, Nil))))), Nil)))), Nil)))) -//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(72, Cons(27, Cons(11, Cons(34, Nil))))), Cons(Tuple2("Gold", Tuple2(96, Cons(35, Cons(40, Cons(21, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(11, Cons(14, Nil))))), Cons(Tuple2("Bronze", Tuple2(50, Cons(23, Cons(17, Cons(10, Nil))))), Nil))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(70, Cons(11, Cons(41, Cons(18, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Bronze", Tuple2(54, Cons(23, Cons(17, Cons(14, Nil))))), Nil)))), Nil)))) -//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(73, Cons(27, Cons(12, Cons(34, Nil))))), Cons(Tuple2("Gold", Tuple2(96, Cons(35, Cons(40, Cons(21, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Bronze", Tuple2(52, Cons(23, Cons(19, Cons(10, Nil))))), Nil))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(70, Cons(17, Cons(12, Cons(41, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Bronze", Tuple2(55, Cons(23, Cons(18, Cons(14, Nil))))), Nil)))), Nil)))) -//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(74, Cons(27, Cons(13, Cons(34, Nil))))), Cons(Tuple2("Gold", Tuple2(96, Cons(35, Cons(40, Cons(21, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Bronze", Tuple2(50, Cons(23, Cons(13, Cons(14, Nil))))), Nil))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(71, Cons(17, Cons(13, Cons(41, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Bronze", Tuple2(55, Cons(23, Cons(18, Cons(14, Nil))))), Nil)))), Nil)))) -//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(70, Cons(35, Cons(14, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(101, Cons(27, Cons(40, Cons(34, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Bronze", Tuple2(51, Cons(23, Cons(14, Cons(14, Nil))))), Nil))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(14, Cons(41, Nil))))), Cons(Tuple2("Bronze", Tuple2(55, Cons(23, Cons(18, Cons(14, Nil))))), Nil)))), Nil)))) -//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(70, Cons(15, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(102, Cons(35, Cons(27, Cons(40, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(15, Cons(10, Nil))))), Cons(Tuple2("Bronze", Tuple2(50, Cons(19, Cons(17, Cons(14, Nil))))), Nil))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(15, Cons(21, Cons(34, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(20, Cons(19, Cons(21, Nil))))), Nil))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(70, Cons(15, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Bronze", Tuple2(58, Cons(23, Cons(17, Cons(18, Nil))))), Nil)))), Nil)))) -//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(71, Cons(16, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(102, Cons(35, Cons(27, Cons(40, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Bronze", Tuple2(52, Cons(23, Cons(19, Cons(10, Nil))))), Nil))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(16, Cons(20, Cons(34, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(71, Cons(16, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Bronze", Tuple2(58, Cons(23, Cons(17, Cons(18, Nil))))), Nil)))), Nil)))) -//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(102, Cons(35, Cons(27, Cons(40, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Bronze", Tuple2(50, Cons(19, Cons(17, Cons(14, Nil))))), Nil))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(17, Cons(19, Cons(34, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Bronze", Tuple2(58, Cons(23, Cons(17, Cons(18, Nil))))), Nil)))), Nil)))) -//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(73, Cons(18, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(102, Cons(35, Cons(27, Cons(40, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(23, Cons(19, Cons(18, Nil))))), Nil))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(18, Cons(18, Cons(34, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(20, Cons(19, Cons(21, Nil))))), Nil))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Bronze", Tuple2(59, Cons(23, Cons(18, Cons(18, Nil))))), Nil)))), Nil)))) -//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(74, Cons(19, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(102, Cons(35, Cons(27, Cons(40, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Silver", Tuple2(61, Cons(23, Cons(19, Cons(19, Nil))))), Nil))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(23, Cons(19, Cons(18, Nil))))), Nil)))), Nil)))) -//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(75, Cons(20, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(102, Cons(35, Cons(27, Cons(40, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Silver", Tuple2(62, Cons(23, Cons(19, Cons(20, Nil))))), Nil))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(70, Cons(9, Cons(20, Cons(41, Nil))))), Cons(Tuple2("Gold", Tuple2(77, Cons(54, Cons(9, Cons(14, Nil))))), Cons(Tuple2("Bronze", Tuple2(58, Cons(23, Cons(17, Cons(18, Nil))))), Nil)))), Nil)))) -//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(76, Cons(21, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(102, Cons(35, Cons(27, Cons(40, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Silver", Tuple2(63, Cons(23, Cons(19, Cons(21, Nil))))), Nil))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(71, Cons(9, Cons(21, Cons(41, Nil))))), Cons(Tuple2("Gold", Tuple2(77, Cons(54, Cons(9, Cons(14, Nil))))), Cons(Tuple2("Bronze", Tuple2(58, Cons(23, Cons(17, Cons(18, Nil))))), Nil)))), Nil)))) -//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(70, Cons(27, Cons(22, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(109, Cons(35, Cons(40, Cons(34, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Silver", Tuple2(64, Cons(23, Cons(19, Cons(22, Nil))))), Nil))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(22, Cons(41, Nil))))), Cons(Tuple2("Gold", Tuple2(77, Cons(54, Cons(9, Cons(14, Nil))))), Cons(Tuple2("Bronze", Tuple2(58, Cons(23, Cons(17, Cons(18, Nil))))), Nil)))), Nil)))) -//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(71, Cons(27, Cons(23, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(109, Cons(35, Cons(40, Cons(34, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(23, Cons(23, Cons(14, Nil))))), Nil))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Cons(Tuple2("Bronze", Tuple2(50, Cons(23, Cons(19, Cons(8, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Silver", Tuple2(64, Cons(23, Cons(23, Cons(18, Nil))))), Nil)))), Nil)))) -//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(72, Cons(27, Cons(24, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(109, Cons(35, Cons(40, Cons(34, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Silver", Tuple2(61, Cons(23, Cons(24, Cons(14, Nil))))), Nil))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Cons(Tuple2("Bronze", Tuple2(51, Cons(24, Cons(19, Cons(8, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Silver", Tuple2(65, Cons(23, Cons(24, Cons(18, Nil))))), Nil)))), Nil)))) -//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(73, Cons(27, Cons(25, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(109, Cons(35, Cons(40, Cons(34, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Silver", Tuple2(62, Cons(23, Cons(25, Cons(14, Nil))))), Nil))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Cons(Tuple2("Bronze", Tuple2(52, Cons(25, Cons(19, Cons(8, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Silver", Tuple2(66, Cons(23, Cons(25, Cons(18, Nil))))), Nil)))), Nil)))) -//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(74, Cons(27, Cons(26, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(109, Cons(35, Cons(40, Cons(34, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Silver", Tuple2(63, Cons(23, Cons(26, Cons(14, Nil))))), Nil))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Cons(Tuple2("Bronze", Tuple2(53, Cons(26, Cons(19, Cons(8, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Silver", Tuple2(67, Cons(23, Cons(26, Cons(18, Nil))))), Nil)))), Nil)))) -//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(75, Cons(27, Cons(27, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(109, Cons(35, Cons(40, Cons(34, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(19, Cons(27, Cons(14, Nil))))), Nil))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Cons(Tuple2("Bronze", Tuple2(54, Cons(27, Cons(19, Cons(8, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Silver", Tuple2(68, Cons(23, Cons(27, Cons(18, Nil))))), Nil)))), Nil)))) -//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(76, Cons(27, Cons(28, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(109, Cons(35, Cons(40, Cons(34, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(23, Cons(19, Cons(28, Nil))))), Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Nil))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(70, Cons(28, Cons(21, Cons(21, Nil))))), Nil))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Silver", Tuple2(69, Cons(23, Cons(28, Cons(18, Nil))))), Nil)))), Nil)))) -//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(77, Cons(27, Cons(29, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(109, Cons(35, Cons(40, Cons(34, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(71, Cons(23, Cons(19, Cons(29, Nil))))), Nil))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(71, Cons(29, Cons(21, Cons(21, Nil))))), Nil))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(70, Cons(23, Cons(29, Cons(18, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Nil)))), Nil)))) -//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(78, Cons(27, Cons(30, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(109, Cons(35, Cons(40, Cons(34, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(23, Cons(30, Cons(17, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(19, Cons(45, Cons(8, Nil))))), Nil))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(70, Cons(30, Cons(19, Cons(21, Nil))))), Nil))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(70, Cons(23, Cons(17, Cons(30, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(73, Cons(41, Cons(18, Cons(14, Nil))))), Nil)))), Nil)))) -//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(79, Cons(27, Cons(31, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(109, Cons(35, Cons(40, Cons(34, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(73, Cons(23, Cons(19, Cons(31, Nil))))), Nil))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(18, Cons(31, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Nil))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(71, Cons(23, Cons(17, Cons(31, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(73, Cons(41, Cons(18, Cons(14, Nil))))), Nil)))), Nil)))) -//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(80, Cons(27, Cons(32, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(109, Cons(35, Cons(40, Cons(34, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(74, Cons(23, Cons(19, Cons(32, Nil))))), Nil))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(18, Cons(32, Cons(20, Nil))))), Cons(Tuple2("Gold", Tuple2(71, Cons(21, Cons(34, Cons(16, Nil))))), Nil))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(73, Cons(23, Cons(32, Cons(18, Nil))))), Nil)))), Nil)))) -//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(81, Cons(27, Cons(33, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(109, Cons(35, Cons(40, Cons(34, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(23, Cons(33, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Nil))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(18, Cons(33, Cons(19, Nil))))), Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Bronze", Tuple2(50, Cons(21, Cons(8, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(70, Cons(23, Cons(33, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(76, Cons(17, Cons(41, Cons(18, Nil))))), Nil)))), Nil)))) -//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(109, Cons(35, Cons(40, Cons(34, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(19, Cons(34, Cons(17, Nil))))), Cons(Tuple2("Gold", Tuple2(73, Cons(23, Cons(45, Cons(5, Nil))))), Nil))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(71, Cons(18, Cons(19, Cons(34, Nil))))), Cons(Tuple2("Bronze", Tuple2(50, Cons(21, Cons(8, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(71, Cons(23, Cons(34, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(76, Cons(17, Cons(41, Cons(18, Nil))))), Nil)))), Nil)))) -//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(110, Cons(35, Cons(40, Cons(35, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(23, Cons(35, Cons(14, Nil))))), Nil))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(1, Cons(35, Cons(34, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Cons(Tuple2("Bronze", Tuple2(55, Cons(20, Cons(19, Cons(16, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(70, Cons(17, Cons(35, Cons(18, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(78, Cons(23, Cons(41, Cons(14, Nil))))), Nil)))), Nil)))) -//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(111, Cons(35, Cons(40, Cons(36, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(73, Cons(23, Cons(36, Cons(14, Nil))))), Nil))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(18, Cons(36, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(73, Cons(20, Cons(19, Cons(34, Nil))))), Cons(Tuple2("Bronze", Tuple2(50, Cons(21, Cons(8, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(71, Cons(17, Cons(36, Cons(18, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(78, Cons(23, Cons(41, Cons(14, Nil))))), Nil)))), Nil)))) -//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(112, Cons(35, Cons(40, Cons(37, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(19, Cons(37, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Nil))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(74, Cons(18, Cons(37, Cons(19, Nil))))), Cons(Tuple2("Bronze", Tuple2(50, Cons(21, Cons(8, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(37, Cons(18, Nil))))), Cons(Tuple2("Gold", Tuple2(78, Cons(23, Cons(41, Cons(14, Nil))))), Nil)))), Nil)))) -//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(113, Cons(35, Cons(40, Cons(38, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(71, Cons(19, Cons(38, Cons(14, Nil))))), Nil))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(75, Cons(18, Cons(38, Cons(19, Nil))))), Cons(Tuple2("Bronze", Tuple2(50, Cons(21, Cons(8, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(70, Cons(9, Cons(23, Cons(38, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(81, Cons(54, Cons(9, Cons(18, Nil))))), Nil)))), Nil)))) -//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(114, Cons(35, Cons(40, Cons(39, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(23, Cons(39, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(45, Cons(17, Cons(10, Nil))))), Nil))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(76, Cons(18, Cons(39, Cons(19, Nil))))), Cons(Tuple2("Bronze", Tuple2(50, Cons(21, Cons(8, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(70, Cons(17, Cons(39, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(82, Cons(23, Cons(41, Cons(18, Nil))))), Nil)))), Nil)))) -//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(115, Cons(35, Cons(40, Cons(40, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(73, Cons(19, Cons(40, Cons(14, Nil))))), Nil))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(77, Cons(18, Cons(40, Cons(19, Nil))))), Cons(Tuple2("Bronze", Tuple2(50, Cons(21, Cons(8, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(71, Cons(17, Cons(40, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(82, Cons(23, Cons(41, Cons(18, Nil))))), Nil)))), Nil)))) -//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(116, Cons(35, Cons(40, Cons(41, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(19, Cons(41, Cons(10, Nil))))), Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Nil))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(70, Cons(41, Cons(8, Cons(21, Nil))))), Cons(Tuple2("Bronze", Tuple2(58, Cons(18, Cons(19, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(82, Cons(23, Cons(41, Cons(18, Nil))))), Nil)))), Nil)))) -//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(117, Cons(35, Cons(40, Cons(42, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(23, Cons(42, Cons(5, Nil))))), Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Nil))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(71, Cons(42, Cons(8, Cons(21, Nil))))), Cons(Tuple2("Bronze", Tuple2(58, Cons(18, Cons(19, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(83, Cons(23, Cons(42, Cons(18, Nil))))), Nil)))), Nil)))) -//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(118, Cons(35, Cons(40, Cons(43, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(19, Cons(43, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(45, Cons(17, Cons(10, Nil))))), Nil))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(70, Cons(43, Cons(19, Cons(8, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(70, Cons(9, Cons(43, Cons(18, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(86, Cons(23, Cons(54, Cons(9, Nil))))), Nil)))), Nil)))) -//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(119, Cons(35, Cons(40, Cons(44, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(23, Cons(44, Cons(5, Nil))))), Nil))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(18, Cons(44, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Silver", Tuple2(61, Cons(21, Cons(19, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(70, Cons(9, Cons(17, Cons(44, Nil))))), Cons(Tuple2("Gold", Tuple2(73, Cons(23, Cons(41, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(86, Cons(54, Cons(18, Cons(14, Nil))))), Nil)))), Nil)))) -//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(120, Cons(35, Cons(40, Cons(45, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(73, Cons(23, Cons(45, Cons(5, Nil))))), Nil))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(71, Cons(18, Cons(45, Cons(8, Nil))))), Cons(Tuple2("Silver", Tuple2(61, Cons(21, Cons(19, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(71, Cons(9, Cons(17, Cons(45, Nil))))), Cons(Tuple2("Gold", Tuple2(73, Cons(23, Cons(41, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(86, Cons(54, Cons(18, Cons(14, Nil))))), Nil)))), Nil)))) -//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(121, Cons(35, Cons(40, Cons(46, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(19, Cons(46, Cons(5, Nil))))), Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Nil))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(18, Cons(46, Cons(8, Nil))))), Cons(Tuple2("Silver", Tuple2(61, Cons(21, Cons(19, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(17, Cons(46, Nil))))), Cons(Tuple2("Gold", Tuple2(73, Cons(23, Cons(41, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(86, Cons(54, Cons(18, Cons(14, Nil))))), Nil)))), Nil)))) -//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(122, Cons(35, Cons(40, Cons(47, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(71, Cons(19, Cons(47, Cons(5, Nil))))), Nil))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(73, Cons(18, Cons(47, Cons(8, Nil))))), Cons(Tuple2("Silver", Tuple2(61, Cons(21, Cons(19, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(70, Cons(9, Cons(47, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(73, Cons(23, Cons(41, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(89, Cons(17, Cons(54, Cons(18, Nil))))), Nil)))), Nil)))) -//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(123, Cons(35, Cons(40, Cons(48, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(19, Cons(48, Cons(5, Nil))))), Nil))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(1, Cons(48, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Bronze", Tuple2(58, Cons(18, Cons(19, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(71, Cons(9, Cons(48, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(73, Cons(23, Cons(41, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(89, Cons(17, Cons(54, Cons(18, Nil))))), Nil)))), Nil)))) -//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(124, Cons(35, Cons(40, Cons(49, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(73, Cons(19, Cons(49, Cons(5, Nil))))), Nil))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(1, Cons(49, Cons(20, Nil))))), Cons(Tuple2("Gold", Tuple2(71, Cons(18, Cons(19, Cons(34, Nil))))), Cons(Tuple2("Bronze", Tuple2(50, Cons(21, Cons(8, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(49, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(73, Cons(23, Cons(41, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(89, Cons(17, Cons(54, Cons(18, Nil))))), Nil)))), Nil)))) -//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(125, Cons(35, Cons(40, Cons(50, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(74, Cons(19, Cons(50, Cons(5, Nil))))), Nil))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(1, Cons(50, Cons(19, Nil))))), Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(91, Cons(23, Cons(50, Cons(18, Nil))))), Nil)))), Nil)))) -//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(126, Cons(35, Cons(40, Cons(51, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(70, Cons(51, Cons(5, Cons(14, Nil))))), Cons(Tuple2("Bronze", Tuple2(52, Cons(23, Cons(19, Cons(10, Nil))))), Nil)))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(1, Cons(18, Cons(51, Nil))))), Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Silver", Tuple2(61, Cons(21, Cons(19, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(92, Cons(23, Cons(51, Cons(18, Nil))))), Nil)))), Nil)))) -//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(127, Cons(35, Cons(40, Cons(52, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(71, Cons(52, Cons(5, Cons(14, Nil))))), Cons(Tuple2("Bronze", Tuple2(52, Cons(23, Cons(19, Cons(10, Nil))))), Nil)))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(71, Cons(1, Cons(18, Cons(52, Nil))))), Cons(Tuple2("Silver", Tuple2(61, Cons(21, Cons(19, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(70, Cons(9, Cons(52, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(95, Cons(23, Cons(54, Cons(18, Nil))))), Nil)))), Nil)))) -//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(128, Cons(35, Cons(40, Cons(53, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(53, Cons(5, Cons(14, Nil))))), Cons(Tuple2("Bronze", Tuple2(52, Cons(23, Cons(19, Cons(10, Nil))))), Nil)))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(1, Cons(53, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(71, Cons(18, Cons(19, Cons(34, Nil))))), Cons(Tuple2("Silver", Tuple2(62, Cons(20, Cons(21, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(71, Cons(9, Cons(53, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(95, Cons(23, Cons(54, Cons(18, Nil))))), Nil)))), Nil)))) -//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(129, Cons(35, Cons(40, Cons(54, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(73, Cons(54, Cons(5, Cons(14, Nil))))), Cons(Tuple2("Bronze", Tuple2(52, Cons(23, Cons(19, Cons(10, Nil))))), Nil)))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(73, Cons(1, Cons(18, Cons(54, Nil))))), Cons(Tuple2("Silver", Tuple2(61, Cons(21, Cons(19, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(95, Cons(23, Cons(54, Cons(18, Nil))))), Nil)))), Nil)))) -//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(130, Cons(35, Cons(40, Cons(55, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(70, Cons(55, Cons(10, Cons(5, Nil))))), Cons(Tuple2("Bronze", Tuple2(56, Cons(23, Cons(19, Cons(14, Nil))))), Nil)))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(74, Cons(1, Cons(18, Cons(55, Nil))))), Cons(Tuple2("Silver", Tuple2(61, Cons(21, Cons(19, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(96, Cons(23, Cons(55, Cons(18, Nil))))), Nil)))), Nil)))) -//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(131, Cons(35, Cons(40, Cons(56, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(71, Cons(56, Cons(10, Cons(5, Nil))))), Cons(Tuple2("Bronze", Tuple2(56, Cons(23, Cons(19, Cons(14, Nil))))), Nil)))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(75, Cons(1, Cons(18, Cons(56, Nil))))), Cons(Tuple2("Silver", Tuple2(61, Cons(21, Cons(19, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(97, Cons(23, Cons(56, Cons(18, Nil))))), Nil)))), Nil)))) -//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(132, Cons(35, Cons(40, Cons(57, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(57, Cons(10, Cons(5, Nil))))), Cons(Tuple2("Bronze", Tuple2(56, Cons(23, Cons(19, Cons(14, Nil))))), Nil)))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(76, Cons(1, Cons(18, Cons(57, Nil))))), Cons(Tuple2("Silver", Tuple2(61, Cons(21, Cons(19, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(98, Cons(23, Cons(57, Cons(18, Nil))))), Nil)))), Nil)))) -//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(133, Cons(35, Cons(40, Cons(58, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(73, Cons(58, Cons(10, Cons(5, Nil))))), Cons(Tuple2("Bronze", Tuple2(56, Cons(23, Cons(19, Cons(14, Nil))))), Nil)))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(77, Cons(1, Cons(18, Cons(58, Nil))))), Cons(Tuple2("Silver", Tuple2(61, Cons(21, Cons(19, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(99, Cons(23, Cons(58, Cons(18, Nil))))), Nil)))), Nil)))) -//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(134, Cons(35, Cons(40, Cons(59, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(74, Cons(59, Cons(10, Cons(5, Nil))))), Cons(Tuple2("Bronze", Tuple2(56, Cons(23, Cons(19, Cons(14, Nil))))), Nil)))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(78, Cons(1, Cons(18, Cons(59, Nil))))), Cons(Tuple2("Silver", Tuple2(61, Cons(21, Cons(19, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(100, Cons(23, Cons(59, Cons(18, Nil))))), Nil)))), Nil)))) -//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(135, Cons(35, Cons(40, Cons(60, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(75, Cons(60, Cons(10, Cons(5, Nil))))), Cons(Tuple2("Bronze", Tuple2(56, Cons(23, Cons(19, Cons(14, Nil))))), Nil)))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(79, Cons(1, Cons(18, Cons(60, Nil))))), Cons(Tuple2("Silver", Tuple2(61, Cons(21, Cons(19, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(101, Cons(23, Cons(60, Cons(18, Nil))))), Nil)))), Nil)))) -//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(136, Cons(35, Cons(40, Cons(61, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(76, Cons(61, Cons(10, Cons(5, Nil))))), Cons(Tuple2("Bronze", Tuple2(56, Cons(23, Cons(19, Cons(14, Nil))))), Nil)))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(1, Cons(61, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(102, Cons(23, Cons(61, Cons(18, Nil))))), Nil)))), Nil)))) -//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(137, Cons(35, Cons(40, Cons(62, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(77, Cons(62, Cons(10, Cons(5, Nil))))), Cons(Tuple2("Bronze", Tuple2(56, Cons(23, Cons(19, Cons(14, Nil))))), Nil)))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(71, Cons(1, Cons(62, Cons(8, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(103, Cons(23, Cons(62, Cons(18, Nil))))), Nil)))), Nil)))) -//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(138, Cons(35, Cons(40, Cons(63, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(78, Cons(63, Cons(10, Cons(5, Nil))))), Cons(Tuple2("Bronze", Tuple2(56, Cons(23, Cons(19, Cons(14, Nil))))), Nil)))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(1, Cons(63, Cons(8, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(104, Cons(23, Cons(63, Cons(18, Nil))))), Nil)))), Nil)))) -//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(139, Cons(35, Cons(40, Cons(64, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(79, Cons(64, Cons(10, Cons(5, Nil))))), Cons(Tuple2("Bronze", Tuple2(56, Cons(23, Cons(19, Cons(14, Nil))))), Nil)))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(73, Cons(1, Cons(64, Cons(8, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(105, Cons(23, Cons(64, Cons(18, Nil))))), Nil)))), Nil)))) -//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(140, Cons(35, Cons(40, Cons(65, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(80, Cons(65, Cons(10, Cons(5, Nil))))), Cons(Tuple2("Bronze", Tuple2(56, Cons(23, Cons(19, Cons(14, Nil))))), Nil)))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(74, Cons(1, Cons(65, Cons(8, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(106, Cons(23, Cons(65, Cons(18, Nil))))), Nil)))), Nil)))) -//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(141, Cons(35, Cons(40, Cons(66, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(81, Cons(66, Cons(10, Cons(5, Nil))))), Cons(Tuple2("Bronze", Tuple2(56, Cons(23, Cons(19, Cons(14, Nil))))), Nil)))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(75, Cons(1, Cons(66, Cons(8, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(107, Cons(23, Cons(66, Cons(18, Nil))))), Nil)))), Nil)))) -//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(142, Cons(35, Cons(40, Cons(67, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(82, Cons(67, Cons(10, Cons(5, Nil))))), Cons(Tuple2("Bronze", Tuple2(56, Cons(23, Cons(19, Cons(14, Nil))))), Nil)))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(76, Cons(1, Cons(67, Cons(8, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(108, Cons(23, Cons(67, Cons(18, Nil))))), Nil)))), Nil)))) -//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(143, Cons(35, Cons(40, Cons(68, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(83, Cons(68, Cons(10, Cons(5, Nil))))), Cons(Tuple2("Bronze", Tuple2(56, Cons(23, Cons(19, Cons(14, Nil))))), Nil)))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(77, Cons(1, Cons(68, Cons(8, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(109, Cons(23, Cons(68, Cons(18, Nil))))), Nil)))), Nil)))) -//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(144, Cons(35, Cons(40, Cons(69, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(84, Cons(69, Cons(10, Cons(5, Nil))))), Cons(Tuple2("Bronze", Tuple2(56, Cons(23, Cons(19, Cons(14, Nil))))), Nil)))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(78, Cons(1, Cons(69, Cons(8, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(110, Cons(23, Cons(69, Cons(18, Nil))))), Nil)))), Nil)))) -//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(145, Cons(35, Cons(40, Cons(70, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(85, Cons(70, Cons(10, Cons(5, Nil))))), Cons(Tuple2("Bronze", Tuple2(56, Cons(23, Cons(19, Cons(14, Nil))))), Nil)))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(79, Cons(1, Cons(70, Cons(8, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(111, Cons(23, Cons(70, Cons(18, Nil))))), Nil)))), Nil)))) -//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(146, Cons(35, Cons(40, Cons(71, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(86, Cons(71, Cons(10, Cons(5, Nil))))), Cons(Tuple2("Bronze", Tuple2(56, Cons(23, Cons(19, Cons(14, Nil))))), Nil)))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(80, Cons(1, Cons(71, Cons(8, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(112, Cons(23, Cons(71, Cons(18, Nil))))), Nil)))), Nil)))) -//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(147, Cons(35, Cons(40, Cons(72, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(87, Cons(72, Cons(10, Cons(5, Nil))))), Cons(Tuple2("Bronze", Tuple2(56, Cons(23, Cons(19, Cons(14, Nil))))), Nil)))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(81, Cons(1, Cons(72, Cons(8, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(113, Cons(23, Cons(72, Cons(18, Nil))))), Nil)))), Nil)))) -//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(148, Cons(35, Cons(40, Cons(73, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(88, Cons(73, Cons(10, Cons(5, Nil))))), Cons(Tuple2("Bronze", Tuple2(56, Cons(23, Cons(19, Cons(14, Nil))))), Nil)))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(82, Cons(1, Cons(73, Cons(8, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(114, Cons(23, Cons(73, Cons(18, Nil))))), Nil)))), Nil)))) -//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(149, Cons(35, Cons(40, Cons(74, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(89, Cons(74, Cons(10, Cons(5, Nil))))), Cons(Tuple2("Bronze", Tuple2(56, Cons(23, Cons(19, Cons(14, Nil))))), Nil)))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(83, Cons(1, Cons(74, Cons(8, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(115, Cons(23, Cons(74, Cons(18, Nil))))), Nil)))), Nil)))) -//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(150, Cons(35, Cons(40, Cons(75, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(90, Cons(75, Cons(10, Cons(5, Nil))))), Cons(Tuple2("Bronze", Tuple2(56, Cons(23, Cons(19, Cons(14, Nil))))), Nil)))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(84, Cons(1, Cons(75, Cons(8, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(116, Cons(23, Cons(75, Cons(18, Nil))))), Nil)))), Nil)))) -//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(151, Cons(35, Cons(40, Cons(76, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(91, Cons(76, Cons(10, Cons(5, Nil))))), Cons(Tuple2("Bronze", Tuple2(56, Cons(23, Cons(19, Cons(14, Nil))))), Nil)))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(85, Cons(1, Cons(76, Cons(8, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(117, Cons(23, Cons(76, Cons(18, Nil))))), Nil)))), Nil)))) -//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(152, Cons(35, Cons(40, Cons(77, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(92, Cons(77, Cons(10, Cons(5, Nil))))), Cons(Tuple2("Bronze", Tuple2(56, Cons(23, Cons(19, Cons(14, Nil))))), Nil)))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(86, Cons(1, Cons(77, Cons(8, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(118, Cons(23, Cons(77, Cons(18, Nil))))), Nil)))), Nil)))) -//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(153, Cons(35, Cons(40, Cons(78, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(93, Cons(78, Cons(10, Cons(5, Nil))))), Cons(Tuple2("Bronze", Tuple2(56, Cons(23, Cons(19, Cons(14, Nil))))), Nil)))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(87, Cons(1, Cons(78, Cons(8, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(119, Cons(23, Cons(78, Cons(18, Nil))))), Nil)))), Nil)))) -//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(154, Cons(35, Cons(40, Cons(79, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(94, Cons(79, Cons(10, Cons(5, Nil))))), Cons(Tuple2("Bronze", Tuple2(56, Cons(23, Cons(19, Cons(14, Nil))))), Nil)))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(88, Cons(1, Cons(79, Cons(8, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(120, Cons(23, Cons(79, Cons(18, Nil))))), Nil)))), Nil)))) -//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(155, Cons(35, Cons(40, Cons(80, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(95, Cons(80, Cons(10, Cons(5, Nil))))), Cons(Tuple2("Bronze", Tuple2(56, Cons(23, Cons(19, Cons(14, Nil))))), Nil)))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(89, Cons(1, Cons(80, Cons(8, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(121, Cons(23, Cons(80, Cons(18, Nil))))), Nil)))), Nil)))) -//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(156, Cons(35, Cons(40, Cons(81, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(96, Cons(81, Cons(10, Cons(5, Nil))))), Cons(Tuple2("Bronze", Tuple2(56, Cons(23, Cons(19, Cons(14, Nil))))), Nil)))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(90, Cons(1, Cons(81, Cons(8, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(122, Cons(23, Cons(81, Cons(18, Nil))))), Nil)))), Nil)))) -//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(157, Cons(35, Cons(40, Cons(82, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(97, Cons(82, Cons(10, Cons(5, Nil))))), Cons(Tuple2("Bronze", Tuple2(56, Cons(23, Cons(19, Cons(14, Nil))))), Nil)))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(91, Cons(1, Cons(82, Cons(8, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(123, Cons(23, Cons(82, Cons(18, Nil))))), Nil)))), Nil)))) -//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(158, Cons(35, Cons(40, Cons(83, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(98, Cons(83, Cons(10, Cons(5, Nil))))), Cons(Tuple2("Bronze", Tuple2(56, Cons(23, Cons(19, Cons(14, Nil))))), Nil)))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(92, Cons(1, Cons(83, Cons(8, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(124, Cons(23, Cons(83, Cons(18, Nil))))), Nil)))), Nil)))) -//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(159, Cons(35, Cons(40, Cons(84, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(99, Cons(84, Cons(10, Cons(5, Nil))))), Cons(Tuple2("Bronze", Tuple2(56, Cons(23, Cons(19, Cons(14, Nil))))), Nil)))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(93, Cons(1, Cons(84, Cons(8, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(125, Cons(23, Cons(84, Cons(18, Nil))))), Nil)))), Nil)))) -//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(160, Cons(35, Cons(40, Cons(85, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(100, Cons(85, Cons(10, Cons(5, Nil))))), Cons(Tuple2("Bronze", Tuple2(56, Cons(23, Cons(19, Cons(14, Nil))))), Nil)))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(94, Cons(1, Cons(85, Cons(8, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(126, Cons(23, Cons(85, Cons(18, Nil))))), Nil)))), Nil)))) -//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(161, Cons(35, Cons(40, Cons(86, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(101, Cons(86, Cons(10, Cons(5, Nil))))), Cons(Tuple2("Bronze", Tuple2(56, Cons(23, Cons(19, Cons(14, Nil))))), Nil)))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(95, Cons(1, Cons(86, Cons(8, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(127, Cons(23, Cons(86, Cons(18, Nil))))), Nil)))), Nil)))) -//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(162, Cons(35, Cons(40, Cons(87, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(102, Cons(87, Cons(10, Cons(5, Nil))))), Cons(Tuple2("Bronze", Tuple2(56, Cons(23, Cons(19, Cons(14, Nil))))), Nil)))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(96, Cons(1, Cons(87, Cons(8, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(128, Cons(23, Cons(87, Cons(18, Nil))))), Nil)))), Nil)))) -//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(163, Cons(35, Cons(40, Cons(88, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(103, Cons(88, Cons(10, Cons(5, Nil))))), Cons(Tuple2("Bronze", Tuple2(56, Cons(23, Cons(19, Cons(14, Nil))))), Nil)))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(97, Cons(1, Cons(88, Cons(8, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(129, Cons(23, Cons(88, Cons(18, Nil))))), Nil)))), Nil)))) -//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(164, Cons(35, Cons(40, Cons(89, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(104, Cons(89, Cons(10, Cons(5, Nil))))), Cons(Tuple2("Bronze", Tuple2(56, Cons(23, Cons(19, Cons(14, Nil))))), Nil)))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(98, Cons(1, Cons(89, Cons(8, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(130, Cons(23, Cons(89, Cons(18, Nil))))), Nil)))), Nil)))) -//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(165, Cons(35, Cons(40, Cons(90, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(105, Cons(90, Cons(10, Cons(5, Nil))))), Cons(Tuple2("Bronze", Tuple2(56, Cons(23, Cons(19, Cons(14, Nil))))), Nil)))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(99, Cons(1, Cons(90, Cons(8, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(131, Cons(23, Cons(90, Cons(18, Nil))))), Nil)))), Nil)))) -//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(166, Cons(35, Cons(40, Cons(91, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(106, Cons(91, Cons(10, Cons(5, Nil))))), Cons(Tuple2("Bronze", Tuple2(56, Cons(23, Cons(19, Cons(14, Nil))))), Nil)))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(100, Cons(1, Cons(91, Cons(8, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(132, Cons(23, Cons(91, Cons(18, Nil))))), Nil)))), Nil)))) -//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(167, Cons(35, Cons(40, Cons(92, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(107, Cons(92, Cons(10, Cons(5, Nil))))), Cons(Tuple2("Bronze", Tuple2(56, Cons(23, Cons(19, Cons(14, Nil))))), Nil)))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(101, Cons(1, Cons(92, Cons(8, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(133, Cons(23, Cons(92, Cons(18, Nil))))), Nil)))), Nil)))) -//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(168, Cons(35, Cons(40, Cons(93, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(108, Cons(93, Cons(10, Cons(5, Nil))))), Cons(Tuple2("Bronze", Tuple2(56, Cons(23, Cons(19, Cons(14, Nil))))), Nil)))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(102, Cons(1, Cons(93, Cons(8, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(134, Cons(23, Cons(93, Cons(18, Nil))))), Nil)))), Nil)))) -//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(169, Cons(35, Cons(40, Cons(94, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(109, Cons(94, Cons(10, Cons(5, Nil))))), Cons(Tuple2("Bronze", Tuple2(56, Cons(23, Cons(19, Cons(14, Nil))))), Nil)))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(103, Cons(1, Cons(94, Cons(8, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(135, Cons(23, Cons(94, Cons(18, Nil))))), Nil)))), Nil)))) -//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(170, Cons(35, Cons(40, Cons(95, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(110, Cons(95, Cons(10, Cons(5, Nil))))), Cons(Tuple2("Bronze", Tuple2(56, Cons(23, Cons(19, Cons(14, Nil))))), Nil)))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(104, Cons(1, Cons(95, Cons(8, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(136, Cons(23, Cons(95, Cons(18, Nil))))), Nil)))), Nil)))) -//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(171, Cons(35, Cons(40, Cons(96, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(111, Cons(96, Cons(10, Cons(5, Nil))))), Cons(Tuple2("Bronze", Tuple2(56, Cons(23, Cons(19, Cons(14, Nil))))), Nil)))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(105, Cons(1, Cons(96, Cons(8, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(137, Cons(23, Cons(96, Cons(18, Nil))))), Nil)))), Nil)))) -//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(172, Cons(35, Cons(40, Cons(97, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(112, Cons(97, Cons(10, Cons(5, Nil))))), Cons(Tuple2("Bronze", Tuple2(56, Cons(23, Cons(19, Cons(14, Nil))))), Nil)))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(106, Cons(1, Cons(97, Cons(8, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(138, Cons(23, Cons(97, Cons(18, Nil))))), Nil)))), Nil)))) -//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(173, Cons(35, Cons(40, Cons(98, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(113, Cons(98, Cons(10, Cons(5, Nil))))), Cons(Tuple2("Bronze", Tuple2(56, Cons(23, Cons(19, Cons(14, Nil))))), Nil)))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(107, Cons(1, Cons(98, Cons(8, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(139, Cons(23, Cons(98, Cons(18, Nil))))), Nil)))), Nil)))) -//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(82, Cons(27, Cons(34, Cons(21, Nil))))), Cons(Tuple2("Gold", Tuple2(174, Cons(35, Cons(40, Cons(99, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Gold", Tuple2(114, Cons(99, Cons(10, Cons(5, Nil))))), Cons(Tuple2("Bronze", Tuple2(56, Cons(23, Cons(19, Cons(14, Nil))))), Nil)))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Gold", Tuple2(108, Cons(1, Cons(99, Cons(8, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil)))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(72, Cons(9, Cons(54, Cons(9, Nil))))), Cons(Tuple2("Gold", Tuple2(72, Cons(17, Cons(41, Cons(14, Nil))))), Cons(Tuple2("Gold", Tuple2(140, Cons(23, Cons(99, Cons(18, Nil))))), Nil)))), Nil)))) -//│ Cons(Tuple2("Simon", Cons(Tuple2("Gold", Tuple2(74, Cons(40, Cons(0, Cons(34, Nil))))), Cons(Tuple2("Gold", Tuple2(83, Cons(35, Cons(27, Cons(21, Nil))))), Nil))), Cons(Tuple2("Hans", Cons(Tuple2("Gold", Tuple2(70, Cons(45, Cons(17, Cons(8, Nil))))), Cons(Tuple2("Bronze", Tuple2(52, Cons(23, Cons(19, Cons(10, Nil))))), Nil))), Cons(Tuple2("Phil", Cons(Tuple2("Gold", Tuple2(70, Cons(20, Cons(34, Cons(16, Nil))))), Cons(Tuple2("Silver", Tuple2(60, Cons(18, Cons(21, Cons(21, Nil))))), Nil))), Cons(Tuple2("Kevin", Cons(Tuple2("Gold", Tuple2(71, Cons(17, Cons(54, Cons(0, Nil))))), Cons(Tuple2("Gold", Tuple2(73, Cons(9, Cons(23, Cons(41, Nil))))), Nil))), Nil)))) -//│ Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Cons(Unit, Nil)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))) diff --git a/hkmc2DiffTests/src/test/scala/hkmc2/LlirDiffMaker.scala b/hkmc2DiffTests/src/test/scala/hkmc2/LlirDiffMaker.scala index 913eb40b75..4c8354b1ea 100644 --- a/hkmc2DiffTests/src/test/scala/hkmc2/LlirDiffMaker.scala +++ b/hkmc2DiffTests/src/test/scala/hkmc2/LlirDiffMaker.scala @@ -70,7 +70,7 @@ abstract class LlirDiffMaker extends BbmlDiffMaker: val (llirProg, ctx2) = llb.bProg(le) ctx = ctx2 wholeProg += llirProg - if sllir.isSet then + if sllir.isSet && !silent.isSet then output("LLIR:") output(llirProg.show()) def cppGen(name: String, prog: Program, gen: Bool, show: Bool, run: Bool, write: Opt[Str]): Unit = @@ -93,7 +93,7 @@ abstract class LlirDiffMaker extends BbmlDiffMaker: val cppHost = CppCompilerHost(auxPath.toString, output.apply) if !cppHost.ready then output("\nCpp Compilation Failed: Cpp compiler or GNU Make not found") - else + else if !silent.isSet then output("\n") cppHost.compileAndRun(cpp.toDocument.toString) cppGen("Cpp", llirProg, From 8aa2777e1f93b7e13f6b25def87dff6cd2313343 Mon Sep 17 00:00:00 2001 From: waterlens Date: Sat, 29 Mar 2025 19:32:53 +0800 Subject: [PATCH 69/88] Remove more unnecessary outputs --- hkmc2/shared/src/test/mlscript/llir/Ctor.mls | 24 -------------------- 1 file changed, 24 deletions(-) diff --git a/hkmc2/shared/src/test/mlscript/llir/Ctor.mls b/hkmc2/shared/src/test/mlscript/llir/Ctor.mls index b6929ff54b..fbbcc0b22e 100644 --- a/hkmc2/shared/src/test/mlscript/llir/Ctor.mls +++ b/hkmc2/shared/src/test/mlscript/llir/Ctor.mls @@ -2,34 +2,10 @@ :llir :cpp -:sllir object None fun testCtor1() = None fun testCtor2() = new None -//│ LLIR: -//│ class None() -//│ def testCtor1$568() = -//│ let x$579 = None$570() in -//│ x$579 -//│ def testCtor2$567() = -//│ let x$580 = None$570() in -//│ x$580 -//│ def entry$581() = -//│ undefined -//│ entry = entry$581 -:sllir class A(x) fun testCtor1() = A(1) fun testCtor2() = new A(1) -//│ LLIR: -//│ class A(x$587) -//│ def testCtor1$584() = -//│ let x$596 = A$585(1) in -//│ x$596 -//│ def testCtor2$583() = -//│ let x$597 = A$585(1) in -//│ x$597 -//│ def entry$598() = -//│ undefined -//│ entry = entry$598 From 4f15cc74958d623acd8ea33f36fdc2578116575b Mon Sep 17 00:00:00 2001 From: waterlens Date: Sat, 29 Mar 2025 20:03:00 +0800 Subject: [PATCH 70/88] Find some additional missing `data` --- .../src/test/mlscript/llir/ControlFlow.mls | 100 +++++++++--------- .../src/test/mlscript/llir/nofib/atom.mls | 2 +- .../test/mlscript/llir/nofib/constraints.mls | 4 +- 3 files changed, 53 insertions(+), 53 deletions(-) diff --git a/hkmc2/shared/src/test/mlscript/llir/ControlFlow.mls b/hkmc2/shared/src/test/mlscript/llir/ControlFlow.mls index 744fe2ca42..a6a1f7a3a9 100644 --- a/hkmc2/shared/src/test/mlscript/llir/ControlFlow.mls +++ b/hkmc2/shared/src/test/mlscript/llir/ControlFlow.mls @@ -222,8 +222,8 @@ f() :sllir :intl -class A(x) -class B(y) +data class A(x) +data class B(y) fun f(a) = let t = if a is A(_) then 1 @@ -233,26 +233,26 @@ f(A(1)) //│ = 1 //│ LLIR: //│ class A(x$707) -//│ class B(y$711) -//│ def f$704(a$714) = -//│ case a$714 of +//│ class B(y$712) +//│ def f$704(a$716) = +//│ case a$716 of //│ A$705 => -//│ let x$730 = a$714. in -//│ let x$731 = 1 in -//│ jump j$729(x$731) -//│ B$709 => -//│ let x$732 = a$714. in -//│ let x$733 = 2 in -//│ jump j$729(x$733) +//│ let x$732 = a$716. in +//│ let x$733 = 1 in +//│ jump j$731(x$733) +//│ B$710 => +//│ let x$734 = a$716. in +//│ let x$735 = 2 in +//│ jump j$731(x$735) //│ _ => //│ panic "match error" -//│ def j$729(tmp$727) = -//│ tmp$727 -//│ def entry$736() = -//│ let x$734 = A$705(1) in -//│ let* (x$735) = f(x$734) in -//│ x$735 -//│ entry = entry$736 +//│ def j$731(tmp$729) = +//│ tmp$729 +//│ def entry$738() = +//│ let x$736 = A$705(1) in +//│ let* (x$737) = f(x$736) in +//│ x$737 +//│ entry = entry$738 //│ //│ Interpreted: //│ 1 @@ -271,44 +271,44 @@ fun f(a) = f(A(1)) //│ = 1 //│ LLIR: -//│ class A(x$742) -//│ class B(y$747) -//│ def f$739(a$751) = -//│ case a$751 of -//│ A$740 => -//│ let x$771 = a$751. in -//│ case a$751 of -//│ A$740 => -//│ let x$773 = a$751. in -//│ case x$773 of +//│ class A(x$744) +//│ class B(y$749) +//│ def f$741(a$753) = +//│ case a$753 of +//│ A$742 => +//│ let x$773 = a$753. in +//│ case a$753 of +//│ A$742 => +//│ let x$775 = a$753. in +//│ case x$775 of //│ IntLit(1) => -//│ let x$775 = 1 in -//│ jump j$774(x$775) +//│ let x$777 = 1 in +//│ jump j$776(x$777) //│ _ => //│ panic "match error" -//│ B$745 => -//│ let x$776 = a$751. in -//│ let x$777 = 2 in -//│ jump j$772(x$777) +//│ B$747 => +//│ let x$778 = a$753. in +//│ let x$779 = 2 in +//│ jump j$774(x$779) //│ _ => //│ panic "match error" -//│ B$745 => -//│ let x$778 = a$751. in -//│ let x$779 = 3 in -//│ jump j$770(x$779) +//│ B$747 => +//│ let x$780 = a$753. in +//│ let x$781 = 3 in +//│ jump j$772(x$781) //│ _ => //│ panic "match error" -//│ def j$774(tmp$767) = -//│ jump j$772(tmp$767) -//│ def j$772(tmp$767) = -//│ jump j$770(tmp$767) -//│ def j$770(tmp$768) = -//│ tmp$768 -//│ def entry$782() = -//│ let x$780 = A$740(1) in -//│ let* (x$781) = f(x$780) in -//│ x$781 -//│ entry = entry$782 +//│ def j$776(tmp$769) = +//│ jump j$774(tmp$769) +//│ def j$774(tmp$769) = +//│ jump j$772(tmp$769) +//│ def j$772(tmp$770) = +//│ tmp$770 +//│ def entry$784() = +//│ let x$782 = A$742(1) in +//│ let* (x$783) = f(x$782) in +//│ x$783 +//│ entry = entry$784 //│ //│ Interpreted: //│ 1 diff --git a/hkmc2/shared/src/test/mlscript/llir/nofib/atom.mls b/hkmc2/shared/src/test/mlscript/llir/nofib/atom.mls index 3bd8f38625..56a63cafca 100644 --- a/hkmc2/shared/src/test/mlscript/llir/nofib/atom.mls +++ b/hkmc2/shared/src/test/mlscript/llir/nofib/atom.mls @@ -3,7 +3,7 @@ :import NofibPrelude.mls //│ Imported 104 member(s) -class State(position: List[Num], velocity: List[Num]) +data class State(position: List[Num], velocity: List[Num]) fun dotPlus(fs, gs) = if fs is Nil then gs diff --git a/hkmc2/shared/src/test/mlscript/llir/nofib/constraints.mls b/hkmc2/shared/src/test/mlscript/llir/nofib/constraints.mls index 8d8a7e9ecb..894114a2f3 100644 --- a/hkmc2/shared/src/test/mlscript/llir/nofib/constraints.mls +++ b/hkmc2/shared/src/test/mlscript/llir/nofib/constraints.mls @@ -85,7 +85,7 @@ fun safe(as1, as2) = if as1 is Assign(i, m) and as2 is Assign(j, n) then not(m = fun queens(n) = CSP(n, n, safe) // -- Figure 2. Trees in Haskell. -class Node[out T](lab: T, children: List[Node[T]]) +data class Node[out T](lab: T, children: List[Node[T]]) fun label(n) = if n is Node(l, _) then l @@ -144,7 +144,7 @@ fun btsolver0(csp) = // -- Figure 6. Conflict-directed solving of CSPs. abstract class ConflictSet: Known | Unknown -class Known(vs: List[Int]) extends ConflictSet +data class Known(vs: List[Int]) extends ConflictSet object Unknown extends ConflictSet fun knownConflict(c) = if c is From 771909a02c3f8cf7bc3162a1a46fb48d2d29872b Mon Sep 17 00:00:00 2001 From: waterlens Date: Tue, 1 Apr 2025 23:42:38 +0800 Subject: [PATCH 71/88] Backport the fix to multi-value return value --- .../scala/hkmc2/codegen/cpp/CodeGen.scala | 21 +++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/CodeGen.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/CodeGen.scala index 2887f296e9..f41257c04c 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/CodeGen.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/CodeGen.scala @@ -23,7 +23,16 @@ class CppCodeGen(builtinClassSymbols: Set[Local], tl: TraceLogger): val mlsValType = Type.Prim("_mlsValue") val mlsUnitValue = Expr.Call(Expr.Var("_mlsValue::create<_mls_Unit>"), Ls()); val mlsRetValue = "_mls_retval" - val mlsRetValueDecl = Decl.VarDecl(mlsRetValue, mlsValType) + def mlsRetValType(n: Int) = + if n == 1 then + mlsValType + else + Type.Template("std::tuple", Ls.fill(n)(mlsValType)) + def mlsRetValueDecl(n: Int) = + if n == 1 then + Decl.VarDecl(mlsRetValue, mlsValType) + else + Decl.VarDecl(mlsRetValue, mlsRetValType(n)) val mlsMainName = "_mlsMain" val mlsPrelude = "#include \"mlsprelude.h\"" val mlsPreludeImpl = "#include \"mlsprelude.cpp\"" @@ -42,7 +51,7 @@ class CppCodeGen(builtinClassSymbols: Set[Local], tl: TraceLogger): def mlsIsBoolLit(scrut: Expr, lit: hkmc2.syntax.Tree.BoolLit) = Expr.Call(Expr.Var("_mlsValue::isIntLit"), Ls(scrut, Expr.IntLit(if lit.value then 1 else 0))) def mlsIsIntLit(scrut: Expr, lit: hkmc2.syntax.Tree.IntLit) = Expr.Call(Expr.Var("_mlsValue::isIntLit"), Ls(scrut, Expr.IntLit(lit.value))) def mlsDebugPrint(x: Expr) = Expr.Call(Expr.Var("_mlsValue::print"), Ls(x)) - def mlsTupleValue(init: Expr) = Expr.Constructor("_mlsValue::tuple", init) + def mlsTupleValue(init: Ls[Expr]) = Expr.Call(Expr.Var("std::make_tuple"), init) def mlsAs(name: Str, cls: Str) = Expr.Var(s"_mlsValue::as<$cls>($name)") def mlsAsUnchecked(name: Str, cls: Str) = Expr.Var(s"_mlsValue::cast<$cls>($name)") def mlsObjectNameMethod(name: Str) = s"constexpr static inline const char *typeName = \"${name}\";" @@ -149,7 +158,7 @@ class CppCodeGen(builtinClassSymbols: Set[Local], tl: TraceLogger): def wrapMultiValues(exprs: Ls[TrivialExpr])(using Ctx, Raise, Scope): Expr = exprs match case x :: Nil => toExpr(x, reifyUnit = true).get case _ => - val init = Expr.Initializer(exprs.map{x => toExpr(x)}) + val init = exprs.map{x => toExpr(x)} mlsTupleValue(init) def codegenCaseWithIfs(scrut: TrivialExpr, cases: Ls[(Pat, Node)], default: Opt[Node], storeInto: Str)(using decls: Ls[Decl], stmts: Ls[Stmt])(using Ctx, Raise, Scope): (Ls[Decl], Ls[Stmt]) = @@ -269,12 +278,12 @@ class CppCodeGen(builtinClassSymbols: Set[Local], tl: TraceLogger): def codegenDefn(using Ctx, Raise, Scope)(defn: Func): (Def, Decl) = defn match case Func(id, name, params, resultNum, body) => - val decls = Ls(mlsRetValueDecl) + val decls = Ls(mlsRetValueDecl(resultNum)) val stmts = Ls.empty[Stmt] val (decls2, stmts2) = codegen(body, mlsRetValue)(using decls, stmts) val stmtsWithReturn = stmts2 :+ Stmt.Return(Expr.Var(mlsRetValue)) - val theDef = Def.FuncDef(mlsValType, name |> allocIfNew, params.map(x => (x |> allocIfNew, mlsValType)), Stmt.Block(decls2, stmtsWithReturn)) - val decl = Decl.FuncDecl(mlsValType, name |> allocIfNew, params.map(x => mlsValType)) + val theDef = Def.FuncDef(mlsRetValType(resultNum), name |> allocIfNew, params.map(x => (x |> allocIfNew, mlsValType)), Stmt.Block(decls2, stmtsWithReturn)) + val decl = Decl.FuncDecl(mlsRetValType(resultNum), name |> allocIfNew, params.map(x => mlsValType)) (theDef, decl) // Topological sort of classes based on inheritance relationships From cab9e132fa1b0aed8b29be51daf3784f2dee1c39 Mon Sep 17 00:00:00 2001 From: waterlens Date: Fri, 4 Apr 2025 15:20:50 +0800 Subject: [PATCH 72/88] Save --- .../src/main/scala/hkmc2/codegen/Block.scala | 2 +- .../main/scala/hkmc2/codegen/cpp/Ast.scala | 16 +- .../scala/hkmc2/codegen/cpp/CodeGen.scala | 62 +- .../scala/hkmc2/codegen/llir/Analysis.scala | 17 +- .../scala/hkmc2/codegen/llir/Builder.scala | 16 +- .../scala/hkmc2/codegen/llir/Interp.scala | 10 +- .../main/scala/hkmc2/codegen/llir/Llir.scala | 15 +- .../scala/hkmc2/codegen/llir/OldOpt.scala | 1586 +++++++++++++++++ .../llir/{Legacy.mls => Original.mls} | 2 +- 9 files changed, 1648 insertions(+), 78 deletions(-) create mode 100644 hkmc2/shared/src/main/scala/hkmc2/codegen/llir/OldOpt.scala rename hkmc2/shared/src/test/mlscript/llir/{Legacy.mls => Original.mls} (99%) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Block.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Block.scala index cd420d1b2b..ab9e64aa7a 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Block.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Block.scala @@ -321,7 +321,7 @@ sealed abstract class Defn: preCtor.freeVarsLLIR ++ ctor.freeVarsLLIR ++ methods.flatMap(_.freeVarsLLIR) -- auxParams.flatMap(_.paramSyms) - + final case class FunDefn( owner: Opt[InnerSymbol], sym: BlockMemberSymbol, diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/Ast.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/Ast.scala index c36a46de73..71fd13203d 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/Ast.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/Ast.scala @@ -1,14 +1,12 @@ -package hkmc2.codegen.cpp +package hkmc2 +package codegen.cpp import mlscript._ import mlscript.utils._ import mlscript.utils.shorthands._ - -import hkmc2.Message.MessageContext -import hkmc2.document._ - import scala.language.implicitConversions -import hkmc2.escaped + +import document._ private def raw(x: String): Document = doc"$x" given Conversion[String, Document] = x => doc"$x" @@ -169,7 +167,7 @@ case class CompilationUnit(includes: Ls[Str], decls: Ls[Decl], defs: Ls[Def]): enum Decl: case StructDecl(name: Str) case EnumDecl(name: Str) - case FuncDecl(ret: Type, name: Str, args: Ls[Type], or: Bool = false, virt: Bool = false) + case FuncDecl(ret: Type, name: Str, args: Ls[Type], is_override: Bool, is_virtual: Bool) case VarDecl(name: Str, typ: Type) def toDocument: Document = @@ -187,9 +185,9 @@ enum Decl: aux(this) enum Def: - case StructDef(name: Str, fields: Ls[(Str, Type)], inherit: Opt[Ls[Str]], methods: Ls[Def] = Ls.empty, methods_decl: Ls[Decl] = Ls.empty) + case StructDef(name: Str, fields: Ls[(Str, Type)], inherit: Opt[Ls[Str]], methods: Ls[Def], methods_decl: Ls[Decl]) case EnumDef(name: Str, fields: Ls[(Str, Opt[Int])]) - case FuncDef(specret: Type, name: Str, args: Ls[(Str, Type)], body: Stmt.Block, or: Bool = false, virt: Bool = false, scope: Opt[Str] = None) + case FuncDef(specret: Type, name: Str, args: Ls[(Str, Type)], body: Stmt.Block, is_override: Bool, is_virtual: Bool = false, in_scope: Opt[Str]) case VarDef(typ: Type, name: Str, init: Opt[Expr]) case RawDef(raw: Str) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/CodeGen.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/CodeGen.scala index f41257c04c..7bd6ac3d15 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/CodeGen.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/CodeGen.scala @@ -1,16 +1,14 @@ -package hkmc2.codegen.cpp +package hkmc2 +package codegen +package cpp import mlscript.utils._ import mlscript.utils.shorthands._ import scala.collection.mutable.ListBuffer -import hkmc2.codegen.llir.{Expr => IExpr, _} -import hkmc2.codegen.cpp._ -import hkmc2.codegen.Local -import hkmc2.utils.{Scope, TraceLogger} -import hkmc2.Raise -import hkmc2.semantics.BuiltinSymbol -import hkmc2.escaped +import llir.{Expr => IExpr, _} +import utils.{Scope, TraceLogger} +import semantics.BuiltinSymbol class CppCodeGen(builtinClassSymbols: Set[Local], tl: TraceLogger): import tl.{trace, log, logs} @@ -113,12 +111,12 @@ class CppCodeGen(builtinClassSymbols: Set[Local], tl: TraceLogger): case (name, defn) => val (cdef, decl) = codegenDefn(using Ctx(summon[Ctx].defnCtx + cls.name, summon[Ctx].fieldCtx ++ cls.fields))(defn) val cdef2 = cdef match - case x: Def.FuncDef if builtinApply.contains(defn.name.nme) => x.copy(name = defn.name |> directName, scope = Some(cls.name |> mapClsLikeName)) - case x: Def.FuncDef => x.copy(scope = Some(cls.name |> mapClsLikeName)) + case x: Def.FuncDef if builtinApply.contains(defn.name.nme) => x.copy(name = defn.name |> directName, in_scope = Some(cls.name |> mapClsLikeName)) + case x: Def.FuncDef => x.copy(in_scope = Some(cls.name |> mapClsLikeName)) case _ => throw new Exception(s"codegenClassInfo: unexpected def $cdef") val decl2 = decl match - case x: Decl.FuncDecl if builtinApply.contains(defn.name.nme) => x.copy(virt = true, name = defn.name |> directName) - case x: Decl.FuncDecl => x.copy(virt = true) + case x: Decl.FuncDecl if builtinApply.contains(defn.name.nme) => x.copy(is_virtual = true, name = defn.name |> directName) + case x: Decl.FuncDecl => x.copy(is_virtual = true) case _ => throw new Exception(s"codegenClassInfo: unexpected decl $decl") log(s"codegenClassInfo: ${cls.name} method ${defn.name} $decl2") (cdef2, decl2) @@ -181,7 +179,7 @@ class CppCodeGen(builtinClassSymbols: Set[Local], tl: TraceLogger): val (decls2, stmts2) = codegen(arm, storeInto)(using Ls.empty, Ls.empty[Stmt]) val stmt = Stmt.If(mlsIsBoolLit(scrut2, i), Stmt.Block(decls2, stmts2), nextarm) S(stmt) - case _ => TODO("codegenCaseWithIfs don't support these patterns currently") + case _ => TODO("codegenCaseWithIfs doesn't support these patterns currently") } (decls, stmt.fold(stmts)(x => stmts :+ x)) @@ -190,29 +188,19 @@ class CppCodeGen(builtinClassSymbols: Set[Local], tl: TraceLogger): val stmts2 = stmts ++ Ls(storeInto.fold(Stmt.Return(call))(x => Stmt.Assign(x, call))) (decls, stmts2) - def codegenOps(op: Local, args: Ls[TrivialExpr])(using Ctx, Raise, Scope) = + def codegenOps(op: BuiltinSymbol, args: Ls[TrivialExpr])(using Ctx, Raise, Scope) = trace[Expr](s"codegenOps $op begin"): - val op2 = op.nme - op2 match - case "+" => - if args.size == 1 then Expr.Unary("+", toExpr(args(0))) - else Expr.Binary("+", toExpr(args(0)), toExpr(args(1))) - case "-" => - if args.size == 1 then Expr.Unary("-", toExpr(args(0))) - else Expr.Binary("-", toExpr(args(0)), toExpr(args(1))) - case "*" => Expr.Binary("*", toExpr(args(0)), toExpr(args(1))) - case "/" => Expr.Binary("/", toExpr(args(0)), toExpr(args(1))) - case "%" => Expr.Binary("%", toExpr(args(0)), toExpr(args(1))) - case "==" | "===" => Expr.Binary("==", toExpr(args(0)), toExpr(args(1))) - case "!=" => Expr.Binary("!=", toExpr(args(0)), toExpr(args(1))) - case "<" => Expr.Binary("<", toExpr(args(0)), toExpr(args(1))) - case "<=" => Expr.Binary("<=", toExpr(args(0)), toExpr(args(1))) - case ">" => Expr.Binary(">", toExpr(args(0)), toExpr(args(1))) - case ">=" => Expr.Binary(">=", toExpr(args(0)), toExpr(args(1))) - case "&&" => Expr.Binary("&&", toExpr(args(0)), toExpr(args(1))) - case "||" => Expr.Binary("||", toExpr(args(0)), toExpr(args(1))) - case "!" => Expr.Unary("!", toExpr(args(0))) - case _ => TODO(s"codegenOps $op2") + var op2 = op.nme + if op2 == "===" then + op2 = "==" + else if op2 == "!===" then + op2 = "!=" + if op.binary && args.length == 2 then + Expr.Binary(op2, toExpr(args(0)), toExpr(args(1))) + else if op.unary && args.length == 1 then + Expr.Unary(op2, toExpr(args(0))) + else + TODO(s"codegenOps ${op.nme} ${args.size} ${op.binary} ${op.unary} ${args.map(_.show)}") def codegen(expr: IExpr)(using Ctx, Raise, Scope): Expr = expr match @@ -282,8 +270,8 @@ class CppCodeGen(builtinClassSymbols: Set[Local], tl: TraceLogger): val stmts = Ls.empty[Stmt] val (decls2, stmts2) = codegen(body, mlsRetValue)(using decls, stmts) val stmtsWithReturn = stmts2 :+ Stmt.Return(Expr.Var(mlsRetValue)) - val theDef = Def.FuncDef(mlsRetValType(resultNum), name |> allocIfNew, params.map(x => (x |> allocIfNew, mlsValType)), Stmt.Block(decls2, stmtsWithReturn)) - val decl = Decl.FuncDecl(mlsRetValType(resultNum), name |> allocIfNew, params.map(x => mlsValType)) + val theDef = Def.FuncDef(mlsRetValType(resultNum), name |> allocIfNew, params.map(x => (x |> allocIfNew, mlsValType)), Stmt.Block(decls2, stmtsWithReturn), false, false, None) + val decl = Decl.FuncDecl(mlsRetValType(resultNum), name |> allocIfNew, params.map(x => mlsValType), false, false) (theDef, decl) // Topological sort of classes based on inheritance relationships diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Analysis.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Analysis.scala index b34944fc75..f4a9fe1bcc 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Analysis.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Analysis.scala @@ -1,18 +1,15 @@ -package hkmc2.codegen.llir +package hkmc2 +package codegen +package llir import mlscript._ -import hkmc2.codegen._ -import hkmc2.codegen.llir.{ Program => LlirProgram, Node, Func } import mlscript.utils._ import mlscript.utils.shorthands._ -import hkmc2.semantics.BuiltinSymbol -import hkmc2.syntax.Tree.UnitLit -import hkmc2.codegen.Local -import hkmc2.{Raise, raise, Diagnostic, ErrorReport, Message} -import hkmc2.Message.MessageContext -import hkmc2.semantics.InnerSymbol -import scala.collection.mutable.ListBuffer +import semantics.BuiltinSymbol +import syntax.Tree.UnitLit +import semantics.InnerSymbol +import scala.collection.mutable.ListBuffer import scala.annotation.tailrec import scala.collection.immutable.* import scala.collection.mutable.{HashMap => MutHMap} diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala index e6ad9696a9..78464db155 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala @@ -7,15 +7,15 @@ import scala.collection.mutable.{HashMap => MutMap} import mlscript.utils.* import mlscript.utils.shorthands.* -import hkmc2.utils.* -import hkmc2.document.* -import hkmc2.Message.MessageContext +import utils.* +import document.* +import Message.MessageContext -import hkmc2.syntax.Tree -import hkmc2.semantics.* -import hkmc2.codegen.llir.{ Program => LlirProgram, Node, Func } -import hkmc2.codegen.Program -import hkmc2.codegen.cpp.Expr.StrLit +import syntax.Tree +import semantics.* +import codegen.llir.{ Program => LlirProgram, Node, Func } +import codegen.Program +import cpp.Expr.StrLit private def bErrStop(msg: Message)(using Raise) = raise(ErrorReport(msg -> N :: Nil, diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Interp.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Interp.scala index 5b06af3c76..7394962cf8 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Interp.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Interp.scala @@ -1,4 +1,6 @@ -package hkmc2.codegen.llir +package hkmc2 +package codegen +package llir import mlscript.* import mlscript.utils.* @@ -7,11 +9,9 @@ import scala.collection.mutable.ListBuffer import shorthands.* import scala.util.boundary, boundary.break -import hkmc2.codegen.llir.* -import hkmc2.syntax.Tree -import hkmc2.codegen.Local +import syntax.Tree import hkmc2.utils.TraceLogger -import hkmc2.semantics.BuiltinSymbol +import semantics.BuiltinSymbol enum Stuck: case StuckExpr(expr: Expr, msg: Str) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Llir.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Llir.scala index 72db698634..ece2f1f1b0 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Llir.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Llir.scala @@ -1,19 +1,20 @@ -package hkmc2.codegen.llir +package hkmc2 +package codegen.llir import mlscript._ import mlscript.utils._ import mlscript.utils.shorthands._ -import hkmc2.syntax._ -import hkmc2.Message.MessageContext -import hkmc2.document._ -import hkmc2.codegen.Local +import syntax._ +import Message.MessageContext +import document._ +import codegen.Local import util.Sorting import collection.immutable.SortedSet import language.implicitConversions import collection.mutable.{Map as MutMap, Set as MutSet, HashMap, ListBuffer} -import hkmc2.escaped +import hkmc2.semantics.BuiltinSymbol private def raw(x: String): Document = doc"$x" @@ -129,7 +130,7 @@ enum Expr: case Literal(lit: hkmc2.syntax.Literal) extends Expr, TrivialExpr case CtorApp(cls: Local, args: Ls[TrivialExpr]) case Select(name: Local, cls: Local, field: Str) - case BasicOp(name: Local, args: Ls[TrivialExpr]) + case BasicOp(name: BuiltinSymbol, args: Ls[TrivialExpr]) case AssignField(assignee: Local, cls: Local, field: Str, value: TrivialExpr) override def toString: String = show diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/OldOpt.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/OldOpt.scala new file mode 100644 index 0000000000..949b9f5da3 --- /dev/null +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/OldOpt.scala @@ -0,0 +1,1586 @@ + +// class Optimizer(fresh: Fresh, fn_uid: FreshInt, class_uid: FreshInt, tag: FreshInt, verbose: Bool = false): +// import Expr._ +// import Node._ +// import Elim._ +// import Intro._ + +// private var split_cache: Opt[SplittingResult] = None + +// private def log(x: Any) = if verbose then println(x) + +// private type ClassCtx = Map[Str, ClassInfo] + +// private def makeClassCtx(classes: Set[ClassInfo]) = classes.map { case c @ ClassInfo(_, name, _) => (name, c) }.toMap + +// private type FieldCtx = Map[Str, (Str, ClassInfo)] + +// private class DestructAnalysis: +// private def f(node: Node): Opt[Name] = node match +// case Result(res) => None +// case Jump(defn, args) => None +// case Case(scrut, cases, default) => Some(scrut) +// case LetExpr(name, expr, body) => f(body) +// case LetCall(names, defn, args, body) => f(body) + +// def isDestructed(node: Node, name: Name) = +// f(node).contains(name) + +// def firstDestructed(node: Node) = +// f(node) + +// private class EliminationAnalysis: +// private case class ElimEnv( +// val defcount: MutHMap[Str, Int], +// val elims: MutHMap[Str, MutHSet[ElimInfo]], +// val defn: Str, +// val visited: MutHSet[Str], +// ) + +// private def addElim(env: ElimEnv, x: Name, elim: Elim, loc: LocMarker) = +// if (env.defcount.getOrElse(x.str, 0) <= 1) +// env.elims.getOrElseUpdate(x.str, MutHSet.empty) += ElimInfo(elim, DefnLocMarker(env.defn, loc)) + +// private def addBackwardElim(env: ElimEnv, x: Name, elim: ElimInfo, loc: LocMarker) = +// if (env.defcount.getOrElse(x.str, 0) <= 1) +// for { +// elim2 <- elim match { +// // If a variable is destructed in the callee, +// // then it is also indirectly destructed by the call to the callee +// case ElimInfo(EDestruct, _) | ElimInfo(EIndirectDestruct, _) => Some(ElimInfo(EIndirectDestruct, DefnLocMarker(env.defn, loc))) +// case ElimInfo(EDirect, _) => None +// case _ => Some(elim) +// } +// _ = env.elims.getOrElseUpdate(x.str, MutHSet.empty).add(elim2) +// } yield () + +// private def addDef(env: ElimEnv, name: Name) = +// env.defcount.update(name.str, env.defcount.getOrElse(name.str, 0) + 1) + +// private def f(env: ElimEnv, x: Name, loc: LocMarker): Unit = +// addElim(env, x, EDirect, loc) + +// private def f(env: ElimEnv, x: TrivialExpr, loc: LocMarker): Unit = x match +// case Ref(name) => f(env, name, loc) +// case _ => + +// private def f(env: ElimEnv, x: Expr, loc: LocMarker): Unit = x match +// case Ref(name) => f(env, name, loc) +// case Literal(lit) => +// case CtorApp(name, args) => args.foreach(f(env, _, loc)) +// case Select(name, cls, field) => addElim(env, name, ESelect(field), loc) +// case BasicOp(name, args) => args.foreach(f(env, _, loc)) + +// private def f(env: ElimEnv, x: Node): Unit = x match +// case Result(res) => res.foreach(f(env, _, x.locMarker)) +// case Jump(defnref, args) => +// args.foreach(f(env, _, x.locMarker)) +// val defn = defnref.expectDefn +// val loc = x.locMarker +// args.zip(defn.newActiveParams).foreach { +// case (Ref(x), ys) => ys.foreach { y => addBackwardElim(env, x, y, loc) } +// case _ => +// } +// if (!env.visited.contains(defn.name)) +// env.visited.add(defn.name) +// defn.params.foreach(addDef(env, _)) +// f(env.copy(defn = defn.name), defn.body) +// case Case(scrut, cases, default) => +// f(env, scrut, x.locMarker) +// addElim(env, scrut, EDestruct, x.locMarker) +// cases.foreach((cls, arm) => f(env, arm)) +// default.foreach(f(env, _)) +// case LetExpr(name, expr, body) => +// f(env, expr, x.locMarker) +// addDef(env, name) +// f(env, body) +// case LetCall(names, defnref, args, body) => +// val loc = x.locMarker +// args.foreach(f(env, _, loc)) +// val defn = defnref.expectDefn +// args.zip(defn.newActiveParams).foreach { +// case (Ref(x), ys) => ys.foreach { y => addBackwardElim(env, x, y, loc) } +// case _ => +// } +// if (!env.visited.contains(defn.name)) +// env.visited.add(defn.name) +// defn.params.foreach(addDef(env, _)) +// f(env.copy(defn = defn.name), defn.body) +// names.foreach(addDef(env, _)) +// f(env, body) + +// def run(x: Program) = +// var changed = true +// while (changed) +// changed = false +// x.defs.foreach { defn => +// val old = defn.newActiveParams +// val env = ElimEnv(MutHMap.empty, MutHMap.empty, defn.name, MutHSet.empty) +// defn.params.foreach(addDef(env, _)) +// f(env, defn.body) +// defn.newActiveParams = defn.params.map { +// param => +// env.elims.get(param.str).getOrElse(MutHSet.empty).toSortedSet +// } +// changed |= (old != defn.newActiveParams) +// } + +// private object IntroductionAnalysis: +// private def combine_intros(xs: Ls[Ls[Opt[Intro]]]): Ls[Opt[Intro]] = +// val xst = xs.transpose +// xst.map { +// ys => +// val z = ys.flatMap { +// case None => Set() +// case Some(IMix(i)) => i +// case Some(i) => Set(i) +// }.toSet +// if z.nonEmpty then Some(IMix(z)) else None +// } +// def getIntro(n: Int, node: Node, intros: Map[Str, Intro]): Ls[Opt[Intro]] = node match +// case Case(scrut, cases, default) => +// val cases_intros = cases.map { +// case (Pat.Class(cls), node) => +// getIntro(n, node, intros + (scrut.str -> ICtor(cls.ident))) +// case (Pat.Lit(_), node) => +// getIntro(n, node, intros) +// } +// default match +// case None => combine_intros(cases_intros) +// case Some(dc) => combine_intros(cases_intros :+ getIntro(n, dc, intros)) +// case Jump(defnref, args) => +// val jpdef = defnref.expectDefn +// jpdef.activeInputs = updateInputInfo(jpdef, intros, args) +// jpdef.activeResults +// case LetCall(resultNames, defnref, args, body) => +// val defn = defnref.expectDefn +// val intros2 = updateIntroInfo(defn, intros, resultNames) +// defn.activeInputs = updateInputInfo(defn, intros, args) +// getIntro(n, body, intros2) +// case LetExpr(name, expr, body) => +// val intros2 = getIntro(expr, intros) match +// case None => intros +// case Some(x) => +// intros + (name.str -> x) +// getIntro(n, body, intros2) +// case Result(res) => +// res.map { x => getIntro(x, intros) } + +// def getIntro(expr: TrivialExpr, intros: Map[Str, Intro]) = expr match +// case Literal(lit) => None +// case Ref(name) => intros.get(name.str) + +// def getIntro(expr: Expr, intros: Map[Str, Intro]): Opt[Intro] = expr match +// case CtorApp(cls, args) => Some(ICtor(cls.ident)) +// case _ => None + +// def getIntro(expr: TrivialExpr): Opt[Intro] = getIntro(expr, Map.empty) +// def getIntro(expr: Expr): Opt[Intro] = getIntro(expr, Map.empty) +// def getIntro(n: Int, node: Node): Ls[Opt[Intro]] = getIntro(n, node, Map.empty) + +// def run(x: Program) = +// var changed = true +// while (changed) +// changed = false +// x.defs.foreach { +// defn => +// val old = defn.activeResults +// defn.activeResults = +// getIntro(defn.resultNum, defn.body, +// defn.specialized.map(bindIntroInfoUsingInput(Map.empty, _, defn.params)) +// .getOrElse(Map.empty)) +// if defn.resultNum != defn.activeResults.length then throw OptimizingError(s"Inconsistent result number for ${defn.name}") +// changed |= old != defn.activeResults +// } + +// private case class PreFunction(val name: Str, val retvals: Ls[Str]): +// override def toString = s"Pre($name, [$retvals])" +// private case class PostFunction(val name: Str, val params: Ls[Str]): +// override def toString = s"Post($name, [$params])" + +// private def bindIntroInfo(intros: Map[Str, Intro], args: Ls[TrivialExpr], params: Ls[Name]) = +// args.zip(params).foldLeft(intros) { +// case (accu, (Ref(Name(arg)), Name(param))) if intros.contains(arg) => accu + (param -> intros(arg)) +// case (accu, _) => accu +// } + +// private def updateIntroInfo(defn: Defn, intros: Map[Str, Intro], xs: Ls[Name]) = +// defn.activeResults.zip(xs).foldLeft(intros) { +// case (intros, (Some(i), name)) => +// intros + (name.str -> i) +// case (intros, _) => intros +// } + +// private def updateIntroInfoAndMaintainMixingIntros(out: MutHMap[Str, Str], defn: Defn, intros: Map[Str, Intro], xs: Ls[Name]) = +// defn.activeResults.zip(xs).foldLeft(intros) { +// case (intros, (Some(i @ IMix(_)), name)) => +// out += (name.str -> defn.name) +// intros + (name.str -> i) +// case (intros, (Some(i), name)) => +// intros + (name.str -> i) +// case (intros, _) => intros +// } + +// private def updateIntroInfoAndMaintainMixingIntros(out: MutHMap[Str, LocMarker], defn: Defn, loc: LocMarker, intros: Map[Str, Intro], xs: Ls[Name]) = +// defn.activeResults.zip(xs).foldLeft(intros) { +// case (intros, (Some(i @ IMix(_)), name)) => +// out += (name.str -> loc) +// intros + (name.str -> i) +// case (intros, (Some(i), name)) => +// intros + (name.str -> i) +// case (intros, _) => intros +// } + +// private def bindIntroInfoUsingInput(intros: Map[Str, Intro], input: Ls[Opt[Intro]], params: Ls[Name]) = +// input.zip(params).foldLeft(intros) { +// case (accu, (Some(i), param)) => +// accu + (param.str -> i) +// case (accu, _) => accu +// } + +// private def updateInputInfo(defn: Defn, intros: Map[Str, Intro], args: Ls[TrivialExpr]) = +// var all_none = true +// val ls = args.map { +// case Ref(Name(arg)) if intros.contains(arg) => all_none = false; Some(intros(arg)) +// case _ => None +// } +// if all_none then defn.activeInputs else defn.activeInputs + ls + + +// private class SplittingTarget( +// val mixing_producer: Map[LocMarker, Str], +// val mixing_consumer: Map[LocMarker, Str], +// val indirect_consumer: Map[LocMarker, IndirectConsumer], +// val known_case: Map[LocMarker, Str], +// val specialize: Map[LocMarker, WrapAndSpecialize], +// ) + +// private case class SplittingResult( +// val targets: SplittingTarget, +// val first_case: Map[Str, DefnLocMarker], +// val specialized_map: Map[Str, Str], +// val pre_map: Map[DefnLocMarker, PreFunction], +// val single_post_map: Map[DefnLocMarker, PostFunction], +// val mutli_post_map: Map[DefnLocMarker, Map[ClassInfo, PostFunction]], +// val pre_defs: Map[Str, Defn], +// val post_defs: Map[Str, Defn], +// val specialized_defs: Map[Str, Defn], +// val overwrite_defs: Map[Str, Defn], +// ): +// def all_defs = pre_defs.values ++ post_defs.values ++ specialized_defs.values +// def overwrite(defs: Set[Defn]) = +// defs.map(x => if overwrite_defs.contains(x.name) then overwrite_defs(x.name) else x) +// def into_cache(g: Program) = +// val new_pre_defs = pre_defs.flatMap((k, v) => g.defs.find(_.name == k).map(x => (k, x))) +// val new_post_defs = post_defs.flatMap((k, v) => g.defs.find(_.name == k).map(x => (k, x))) +// val new_specialized_defs = specialized_defs.flatMap((k, v) => g.defs.find(_.name == k).map(x => (k, x))) +// val new_pre_defs_names = new_pre_defs.keys.toSet +// val new_post_defs_names = new_post_defs.keys.toSet +// val new_specialized_defs_names = new_specialized_defs.keys.toSet +// val new_specialized_map = specialized_map.filter((k, v) => new_specialized_defs_names.contains(v)) +// val new_pre_map = pre_map.filter((k, v) => new_pre_defs_names.contains(v.name)) +// val new_single_post_map = single_post_map.filter((k, v) => new_post_defs_names.contains(v.name)) +// val new_mutli_post_map = mutli_post_map.map { (k, v) => (k, v.filter((k, v) => new_post_defs_names.contains(v.name))) } +// val new_first_case = first_case.filter((k, v) => pre_map.contains(v)) + +// this.copy( +// first_case = new_first_case, +// pre_map = new_pre_map, +// single_post_map = new_single_post_map, +// mutli_post_map = new_mutli_post_map, +// pre_defs = new_pre_defs, +// post_defs = new_post_defs, +// overwrite_defs = Map.empty, +// ) + +// private enum IndirectSplitKind: +// case FirstCase // a pre and multiple posts +// case JumpBeforeCase // a pre +// case CallBeforeCase // a pre and a post +// case AfterCase // a pre and multiple posts + +// private def get_indirect_split_kind(node: Node, loc: LocMarker): Opt[IndirectSplitKind] = +// import IndirectSplitKind._ +// node match +// case Result(res) => None +// case Jump(defn, args) => +// if loc matches node then Some(CallBeforeCase) +// else None +// case Case(scrut, cases, default) => +// if loc matches node then Some(FirstCase) +// else cases.find { (cls, arm) => get_indirect_split_kind(arm, loc).isDefined } match +// case Some(_) => Some(AfterCase) +// case None => None +// case LetExpr(name, expr, body) => get_indirect_split_kind(body, loc) +// case LetCall(xs, defnref, args, body) => +// if loc matches node then Some(CallBeforeCase) +// else get_indirect_split_kind(body, loc) + +// private class FunctionSplitting(prev_sr: Opt[SplittingResult] = None): +// private val first_case = MutHMap[Str, DefnLocMarker]() +// private val specialized_map = MutHMap[Str, Str]() +// private val pre_map = MutHMap[DefnLocMarker, PreFunction]() +// private val single_post_map = MutHMap[DefnLocMarker, PostFunction]() +// private val mutli_post_map = MutHMap[DefnLocMarker, MutHMap[ClassInfo, PostFunction]]() +// private val pre_defs = MutHMap[Str, Defn]() +// private val post_defs = MutHMap[Str, Defn]() +// private val overwrite_defs = MutHMap[Str, Defn]() +// private val specialized_defs = MutHMap[Str, Defn]() +// private val split_memo = MutHSet[DefnLocMarker]() + +// def run(defs: Set[Defn], targets: SplittingTarget): SplittingResult = +// prev_sr match +// case None => +// case Some(value) => +// first_case ++= value.first_case +// pre_map ++= value.pre_map +// single_post_map ++= value.single_post_map +// value.mutli_post_map.foreach((k, v) => mutli_post_map.getOrElseUpdate(k, MutHMap.empty) ++= v) +// pre_defs ++= value.pre_defs +// post_defs ++= value.post_defs +// split_memo ++= value.pre_map.keySet + +// val defs_map = defs.map(x => (x.name, x)).toMap +// targets.mixing_producer.values.foreach { defn_name => +// val defn = defs_map(defn_name) +// split_at_first_case(SplitEnv(defn, n => n, None), defn.body) +// } +// targets.mixing_consumer.values.foreach { defn_name => +// val defn = defs_map(defn_name) +// split_at_first_case(SplitEnv(defn, n => n, None), defn.body) +// } +// targets.indirect_consumer.values.foreach { case IndirectConsumer(defn_name, where, kind) => +// import IndirectSplitKind._ +// val defn = defs_map(defn_name) +// kind match +// case FirstCase => split_at_first_case(SplitEnv(defn, n => n, None), defn.body) +// case JumpBeforeCase | CallBeforeCase => split_at_jump_or_letcall(SplitEnv(defn, n => n, None), defn.body, where.marker) +// case AfterCase => split_at_first_case(SplitEnv(defn, n => n, None), defn.body) +// } +// targets.specialize.values.foreach { case WrapAndSpecialize(defn_name, spec) => +// val defn = defs_map(defn_name) +// val new_defn = Defn( +// name = fresh.make(defn_name + "$O").str, +// resultNum = defn.resultNum, +// params = defn.params, +// id = fn_uid.make, +// body = Jump(DefnRef(Right(defn_name)),defn.params.map(Ref(_))).attachTag(tag), +// specialized = Some(spec), +// ) +// specialized_map.update(defn_name, new_defn.name) +// specialized_defs.update(new_defn.name, new_defn) +// } +// val result = SplittingResult( +// targets = targets, +// first_case = first_case.toMap, specialized_map = specialized_map.toMap, +// pre_map = pre_map.toMap, single_post_map = single_post_map.toMap, +// mutli_post_map = mutli_post_map.map { (k, v) => (k, v.toMap) }.toMap, +// pre_defs = pre_defs.toMap, post_defs = post_defs.toMap, overwrite_defs = overwrite_defs.toMap, +// specialized_defs = specialized_defs.toMap +// ) + +// first_case.clear() +// pre_map.clear() +// single_post_map.clear() +// mutli_post_map.clear() +// split_memo.clear() +// pre_defs.clear() +// post_defs.clear() +// result + +// private case class SplitEnv( +// val defn: Defn, +// val accu: Node => Node, +// val specialize_on: Opt[Ls[Opt[Intro]]], +// ) + +// private def duplicate_and_keep_tags(node: Node): Node = node match +// case Result(res) => Result(res).copyTag(node) +// case Jump(defn, args) => Jump(defn, args).copyTag(node) +// case Case(scrut, cases, default) => Case(scrut, cases map { (cls, arm) => (cls, duplicate_and_keep_tags(arm)) }, default.map(duplicate_and_keep_tags)).copyTag(node) +// case LetExpr(name, expr, body) => LetExpr(name, expr, duplicate_and_keep_tags(body)).copyTag(node) +// case LetCall(names, defn, args, body) => LetCall(names, defn, args, duplicate_and_keep_tags(body)).copyTag(node) + +// private def split_at_jump_or_letcall(env: SplitEnv, node: Node, marker: LocMarker): Opt[DefnLocMarker] = node match +// case Result(res) => None +// case Jump(defnref, args) => +// val defn = env.defn +// val dloc = DefnLocMarker(defn.name, marker) + +// if split_memo.contains(dloc) then return None +// else split_memo.add(dloc) + +// val all_fv = FreeVarAnalysis().run(node) +// val all_fv_list = all_fv.toList +// val fv_retvals = all_fv_list.map { x => Ref(Name(x)) } + +// val pre_body = env.accu(Result(fv_retvals).attachTag(tag)) +// val pre_name = fresh.make(defn.name + "$A") +// val pre_defn = Defn( +// fn_uid.make, +// pre_name.str, +// defn.params, +// all_fv.size, +// None, +// pre_body) +// pre_map.update(dloc, PreFunction(pre_name.str, all_fv_list)) +// pre_defs.update(pre_name.str, pre_defn) + +// val new_names = make_new_names_for_free_variables(all_fv_list) +// val names_map = all_fv_list.zip(new_names).toMap +// val override_defn = +// env.defn.copy(body = +// LetCall(new_names, DefnRef(Right(pre_name.str)), env.defn.params.map(Ref(_)), +// Jump(defnref, args.map { case Ref(Name(x)) => Ref(names_map(x)); case x => x }).attachTag(tag)).attachTag(tag)) +// overwrite_defs.put(defn.name, override_defn).map(x => throw OptimizingError("Unexpected overwrite")) +// Some(dloc) +// case Case(scrut, cases, default) => None +// case LetExpr(name, expr, body) => split_at_jump_or_letcall(env.copy(accu = n => env.accu(LetExpr(name, expr, n).copyTag(node))), body, marker) +// case LetCall(xs, defnref, args, body) if marker matches node => +// val defn = env.defn +// val dloc = DefnLocMarker(defn.name, marker) + +// if split_memo.contains(dloc) then return None +// else split_memo.add(dloc) + +// val bindings_fv = xs.map(_.str) +// val all_fv = FreeVarAnalysis().run(node) +// val all_fv_list = all_fv.toList +// val fv_retvals = all_fv_list.map { x => Ref(Name(x)) } + +// val pre_body = env.accu(Result(fv_retvals).attachTag(tag)) +// val pre_name = fresh.make(defn.name + "$X") +// val pre_defn = Defn( +// fn_uid.make, +// pre_name.str, +// defn.params, +// all_fv.size, +// None, +// pre_body) +// pre_map.update(dloc, PreFunction(pre_name.str, all_fv_list)) +// pre_defs.update(pre_name.str, pre_defn) + +// val post_name = fresh.make(defn.name + "$Y") +// val post_params_list = bindings_fv ++ all_fv.toList +// val post_params = post_params_list.map(Name(_)) +// val new_defn = Defn( +// fn_uid.make, +// post_name.str, +// post_params, +// defn.resultNum, +// None, +// body) +// single_post_map.update(dloc, PostFunction(post_name.str, post_params_list)) +// post_defs.update(post_name.str, new_defn) + +// val new_names = make_new_names_for_free_variables(all_fv_list) +// val names_map = all_fv_list.zip(new_names).toMap +// val new_names_2 = make_new_names_for_free_variables(xs.map(_.str)) +// val names_map_2 = names_map ++ xs.map(_.str).zip(new_names_2).toMap +// val override_defn = +// env.defn.copy(body = +// LetCall(new_names, DefnRef(Right(pre_name.str)), env.defn.params.map(Ref(_)), +// LetCall(new_names_2, defnref, args.map { case Ref(Name(x)) => Ref(names_map(x)); case x => x }, +// Jump(DefnRef(Right(post_name.str)), post_params.map{x => Ref(names_map_2(x.str))}).attachTag(tag)).attachTag(tag)).attachTag(tag)) +// overwrite_defs.put(defn.name, override_defn).map(x => throw OptimizingError("Unexpected overwrite")) +// Some(dloc) +// case LetCall(xs, defnref, args, body) => +// split_at_jump_or_letcall(env.copy(accu = n => env.accu(LetCall(xs, defnref, args, n).copyTag(node))), body, marker) + +// private def split_at_first_case(env: SplitEnv, node: Node): Opt[DefnLocMarker] = node match +// case Result(res) => None +// case Jump(defn, args) => None +// case Case(scrut, cases, default) => +// val defn = env.defn +// val loc = node.locMarker +// val dloc = DefnLocMarker(defn.name, loc) + +// if split_memo.contains(dloc) then return None +// else split_memo.add(dloc) + +// first_case.update(env.defn.name, dloc) + +// val arm_fv = cases.map(x => FreeVarAnalysis().run(x._2)) +// val all_fv = arm_fv.reduce(_ ++ _) + scrut.str +// val all_fv_list = all_fv.toList +// val fv_retvals = all_fv_list.map { x => Ref(Name(x)) } + +// val pre_body = env.accu(Result(fv_retvals).attachTag(tag)) +// val pre_name = fresh.make(defn.name + "$P") +// val pre_defn = Defn( +// fn_uid.make, +// pre_name.str, +// env.defn.params, +// all_fv.size, +// None, +// pre_body) +// pre_map.update(dloc, PreFunction(pre_name.str, all_fv_list)) +// pre_defs.update(pre_name.str, pre_defn) + +// val new_cases = cases.zip(arm_fv).map { +// case ((Pat.Class(cls), body), fv) => +// val post_name = fresh.make(defn.name + "$D") +// val post_params_list = fv.toList +// val post_params = post_params_list.map(Name(_)) +// val new_defn = Defn( +// fn_uid.make, +// post_name.str, +// post_params, +// defn.resultNum, +// None, +// body) +// mutli_post_map +// .getOrElseUpdate(dloc, MutHMap.empty) +// .update(cls, PostFunction(post_name.str, post_params_list)) +// post_defs.update(post_name.str, new_defn) +// (cls, (post_name.str, post_params_list)) +// case _ => ??? +// } + +// val (new_names, scrut_new_name) = make_new_names_for_free_variables(all_fv_list, scrut.str) +// val names_map = all_fv_list.zip(new_names).toMap +// val overwrite_defn = env.defn.copy( +// body = +// LetCall(new_names, DefnRef(Right(pre_name.str)), env.defn.params.map(Ref(_)), +// Case(scrut_new_name.get, new_cases.map { +// case (cls, (post_f, post_params)) => +// (Pat.Class(cls), Jump(DefnRef(Right(post_f)), post_params.map{x => Ref(names_map(x))}).attachTag(tag)) +// }, None).attachTag(tag)).attachTag(tag)) +// overwrite_defs.put(defn.name, overwrite_defn).map(x => throw OptimizingError("Unexpected overwrite")) + +// Some(dloc) +// case LetExpr(name, expr, body) => +// split_at_first_case(env.copy(accu = n => env.accu(LetExpr(name, expr, n).copyTag(node))), body) +// case LetCall(xs, defnref, args, body) => +// split_at_first_case(env.copy(accu = n => env.accu(LetCall(xs, defnref, args, n).copyTag(node))), body) + +// private case class IndirectConsumer(val defn: Str, val where: DefnLocMarker, val kind: IndirectSplitKind) +// private case class WrapAndSpecialize(val defn: Str, val spec: Ls[Opt[Intro]]) + +// private class SplittingTargetAnalysis: +// private val known_case = MutHMap[LocMarker, Str]() +// private val indirect_consumer = MutHMap[LocMarker, IndirectConsumer]() +// private val specialize = MutHMap[LocMarker, WrapAndSpecialize]() +// private val mixing_consumer = MutHMap[LocMarker, Str]() +// private val mixing_producer = MutHMap[LocMarker, Str]() +// private val name_defn_map = MutHMap[Str, LocMarker]() + +// private case class SplitTargetEnv( +// val intros: Map[Str, Intro], +// val defn: Defn, +// val visited: MutHSet[Str], +// ) + +// private def checkTargets(env: SplitTargetEnv, defn: Defn, csloc: DefnLocMarker, args: Ls[TrivialExpr]) = +// val intros = env.intros +// val name = defn.name +// val params = defn.params +// val active = defn.newActiveParams +// val asa: Ls[(Opt[Name], Opt[Intro])] = args.map { +// case Ref(x) => (Some(x), intros.get(x.str)) +// case _ => (None, None) +// } +// asa.zip(params).zip(active).foreach { +// case (((_, Some(ICtor(cls))), param), elims) => +// def aux: Unit = +// for (elim <- elims) +// elim match +// case ElimInfo(EDestruct, _) => +// mixing_consumer += csloc.marker -> name +// if DestructAnalysis().firstDestructed(defn.body) == Some(param) then +// known_case += csloc.marker -> cls +// return +// case ElimInfo(EIndirectDestruct, loc) => +// val split_kind = get_indirect_split_kind(defn.body, loc.marker) +// if split_kind.isDefined then +// indirect_consumer += csloc.marker -> IndirectConsumer(name, loc, split_kind.get) +// if DestructAnalysis().firstDestructed(defn.body) == Some(param) then +// // known_case += csloc.marker -> cls +// return +// case _ => +// aux +// case (((Some(arg), Some(IMix(_))), param), elims) => +// def aux: Unit = +// for (elim <- elims) +// elim match +// case ElimInfo(EDestruct, _) | ElimInfo(EIndirectDestruct, _) => +// name_defn_map.get(arg.str) match +// case Some(loc) => +// val target = ( +// loc match +// case LocMarker.MLetCall(_, defn, _) => defn +// case _ => throw OptimizingError("Unexpected loc marker")) +// mixing_producer += loc -> target +// return +// case None => +// case _ => +// aux +// case _ => +// } +// /* +// val ai = asa.map(_._2) +// if defn.specialized.isEmpty && +// ai.exists{ case Some(ICtor(_)) => true; case _ => false } && +// ai.forall{ case Some(IMix(_)) => false; case _ => true } then +// specialize += csloc.marker -> WrapAndSpecialize(name, ai) +// */ + +// private def f(env: SplitTargetEnv, node: Node): Unit = node match +// case Result(res) => +// case Jump(defnref, args) => +// val dloc = DefnLocMarker(env.defn.name, node.locMarker) +// val defn = defnref.expectDefn +// checkTargets(env, defn, dloc, args) +// case Case(x, cases, default) => +// val dloc = DefnLocMarker(env.defn.name, node.locMarker) +// env.intros.get(x.str) match +// case Some(IMix(_)) => name_defn_map.get(x.str) match +// case Some(loc) => +// mixing_producer += loc -> (loc match +// case LocMarker.MLetCall(_, defn, _) => defn +// case _ => throw OptimizingError("Unexpected loc marker")) +// case None => +// case _ => +// cases foreach { +// case (Pat.Class(cls), arm) => +// val intros2 = env.intros + (x.str -> ICtor(cls.ident)) +// f(env.copy(intros = intros2), arm) +// case (Pat.Lit(_), arm) => +// f(env, arm) +// } +// default foreach { x => f(env, x) } +// case LetExpr(x, e1, e2) => +// val intros = IntroductionAnalysis.getIntro(e1, env.intros).map { y => env.intros + (x.str -> y) }.getOrElse(env.intros) +// f(env.copy(intros = intros), e2) +// case LetCall(xs, defnref, args, e) => +// val defn = defnref.expectDefn +// val dloc = DefnLocMarker(env.defn.name, node.locMarker) +// checkTargets(env, defn, dloc, args) +// val intros2 = updateIntroInfoAndMaintainMixingIntros(name_defn_map, defn, node.locMarker, env.intros, xs) +// f(env.copy(intros = intros2), e) + +// def run(x: Program) = +// x.defs.foreach { defn => +// val env = SplitTargetEnv( +// defn.specialized.map(bindIntroInfoUsingInput(Map.empty, _, defn.params)).getOrElse(Map.empty), +// defn, +// MutHSet.empty) +// f(env, defn.body) +// } +// SplittingTarget(mixing_producer.toMap, mixing_consumer.toMap, indirect_consumer.toMap, known_case.toMap, specialize.toMap) + +// private def recBoundaryMatched(producer: Opt[Int], consumer: Opt[Int]) = +// (producer, consumer) match +// case (Some(_), Some(_)) => false +// case _ => true + +// private def make_new_names_for_free_variables(fvs: Ls[Str]) = +// val new_names = fvs.map { fv => fresh.make } +// new_names + +// private def make_new_names_for_free_variables(fvs: Ls[Str], scrut: Str) = +// var scrut_new_name: Opt[Name] = None +// val new_names = fvs.map { fv => +// val name = fresh.make +// if (scrut == fv) +// scrut_new_name = Some(name) +// name +// } +// (new_names, scrut_new_name) + +// private class SplittingCallSiteReplacement( +// clsctx: ClassCtx, +// split_result: SplittingResult, +// ): +// var changed = false +// private val name_defn_map = MutHMap[Str, LocMarker]() +// private val new_defs = MutHSet[Defn]() +// private var defs = Set.empty[Defn] + +// private val pre_map = split_result.pre_map +// private val single_post_map = split_result.single_post_map +// private val mutli_post_map = split_result.mutli_post_map +// private val first_case = split_result.first_case +// private val specialized_map = split_result.specialized_map + +// private val targets = split_result.targets + +// private case class SubstEnv( +// val intros: Map[Str, Intro], +// val defn: Defn, +// ) + +// private def rebuild_args_from_marker(args: Ls[LocMarker], map: Map[Str, Name]) = +// args.map { +// case LocMarker.MRef(x) => Ref(map(x)) +// case LocMarker.MLit(x) => Literal(x) +// case _ => ??? +// } + +// private def subst_letcall_known_case(env: SubstEnv, sdloc: DefnLocMarker, xs: Ls[Name], as: Ls[TrivialExpr], body: Node, known_case: Str): Node = +// val scrut = sdloc.marker match +// case LocMarker.MCase(scrut, cases, default) => scrut +// case _ => throw OptimizingError("unexpected marker") +// val PreFunction(pre_f, pre_retvals) = pre_map(sdloc) +// val cases = mutli_post_map(sdloc) +// val (new_names, scrut_new_name) = make_new_names_for_free_variables(pre_retvals, scrut) +// val names_map = pre_retvals.zip(new_names).toMap + +// val cls = clsctx(known_case) +// val PostFunction(post_f, post_params) = cases(cls) + +// LetCall(new_names, DefnRef(Right(pre_f)), as, +// LetCall(xs, DefnRef(Right(post_f)), post_params.map{x => Ref(names_map(x))}, +// body).attachTag(tag)).attachTag(tag) + +// private def subst_letcall_mixing_cases(env: SubstEnv, sdloc: DefnLocMarker, xs: Ls[Name], as: Ls[TrivialExpr], body: Node): Node = +// val scrut = sdloc.marker match +// case LocMarker.MCase(scrut, cases, default) => scrut +// case _ => throw OptimizingError("unexpected marker") +// val PreFunction(pre_f, pre_retvals) = pre_map(sdloc) +// val cases = mutli_post_map(sdloc) +// val (new_names, scrut_new_name) = make_new_names_for_free_variables(pre_retvals, scrut) +// val names_map = pre_retvals.zip(new_names).toMap + +// val fv = FreeVarAnalysis().run(body) +// val fv_list = fv.toList + +// val new_jp_name = fresh.make(env.defn.name + "$M") +// val new_jp = Defn( +// fn_uid.make, +// new_jp_name.str, +// fv_list.map(Name(_)), +// env.defn.resultNum, +// None, +// body, +// ) + +// defs += new_jp + +// val new_cases = cases.map { +// case (cls, PostFunction(post_f, post_params)) => +// val new_names_2 = xs.map { _ => fresh.make } +// val names_map_2 = xs.map(_.str).zip(new_names_2).toMap + +// (Pat.Class(cls), +// LetCall(new_names_2, DefnRef(Right(post_f)), post_params.map{x => Ref(names_map(x))}, +// Jump(DefnRef(Right(new_jp.name)), fv_list.map{x => Ref(names_map_2.getOrElse(x, Name(x)))}).attachTag(tag)).attachTag(tag)) +// } + +// val node = LetCall(new_names, DefnRef(Right(pre_f)), as, +// Case(scrut_new_name.get, new_cases.toList, None).attachTag(tag)).attachTag(tag) +// node + +// private def subst_letcall_indirect(env: SubstEnv, ic: IndirectConsumer, xs: Ls[Name], as: Ls[TrivialExpr], body: Node): Node = +// val defn_name = ic.defn +// val kind = ic.kind +// import IndirectSplitKind._ +// kind match +// case FirstCase | AfterCase => +// // it's impossible to have first case here because we have an EIndirectDestruct elim +// subst_letcall_mixing_cases(env, first_case(defn_name), xs, as, body) +// case JumpBeforeCase => +// val (name, args) = ic.where.marker match +// case LocMarker.MJump(name, args) => (name, args) +// case _ => throw OptimizingError("unexpected marker") +// val PreFunction(pre_f, pre_retvals) = pre_map(ic.where) +// val new_names = make_new_names_for_free_variables(pre_retvals) +// val names_map = pre_retvals.zip(new_names).toMap +// LetCall(new_names, DefnRef(Right(pre_f)), as, +// LetCall(xs, DefnRef(Right(name)), rebuild_args_from_marker(args, names_map), +// body).attachTag(tag)).attachTag(tag) +// case CallBeforeCase => +// val (names, defn2, args) = ic.where.marker match +// case LocMarker.MLetCall(names, defn, args) => (names, defn, args) +// case _ => throw OptimizingError("unexpected marker") +// val PreFunction(pre_f, pre_retvals) = pre_map(ic.where) +// val new_names = make_new_names_for_free_variables(pre_retvals) +// val names_map = pre_retvals.zip(new_names).toMap +// val new_names_2 = make_new_names_for_free_variables(names) +// val names_map_2 = names_map ++ names.zip(new_names_2).toMap +// val PostFunction(post_f, post_params) = single_post_map(ic.where) +// val node = LetCall(new_names, DefnRef(Right(pre_f)), as, +// LetCall(new_names_2, DefnRef(Right(defn2)), rebuild_args_from_marker(args, names_map), +// LetCall(xs, DefnRef(Right(post_f)), post_params.map{x => Ref(names_map_2(x))}, body).attachTag(tag)).attachTag(tag)).attachTag(tag) +// node + +// private def subst_jump_known_case(sdloc: DefnLocMarker, as: Ls[TrivialExpr], known_case: Str): Node = +// val scrut = sdloc.marker match +// case LocMarker.MCase(scrut, cases, default) => scrut +// case _ => throw OptimizingError("unexpected marker") +// val PreFunction(pre_f, pre_retvals) = pre_map(sdloc) +// val cases = mutli_post_map(sdloc) +// val (new_names, scrut_new_name) = make_new_names_for_free_variables(pre_retvals, scrut) +// val names_map = pre_retvals.zip(new_names).toMap + +// val cls = clsctx(known_case) +// val PostFunction(post_f, post_params) = cases(cls) + +// LetCall(new_names, DefnRef(Right(pre_f)), as, +// Jump(DefnRef(Right(post_f)), post_params.map{x => Ref(names_map(x))}).attachTag(tag)).attachTag(tag) + +// private def subst_jump_mixing_cases(sdloc: DefnLocMarker, as: Ls[TrivialExpr]): Node = +// val scrut = sdloc.marker match +// case LocMarker.MCase(scrut, cases, default) => scrut +// case _ => throw OptimizingError("unexpected marker") +// val PreFunction(pre_f, pre_retvals) = pre_map(sdloc) +// val cases = mutli_post_map(sdloc) +// val (new_names, scrut_new_name) = make_new_names_for_free_variables(pre_retvals, scrut) +// val names_map = pre_retvals.zip(new_names).toMap +// val new_cases = cases.map { +// case (cls, PostFunction(post_f, post_params)) => ( +// Pat.Class(cls), +// Jump(DefnRef(Right(post_f)), post_params.map{x => Ref(names_map(x))}).attachTag(tag) +// ) +// } +// LetCall(new_names, DefnRef(Right(pre_f)), as, +// Case(scrut_new_name.get, new_cases.toList, None).attachTag(tag)).attachTag(tag) + +// private def subst_jump_indirect(ic: IndirectConsumer, as: Ls[TrivialExpr]) = +// val defn_name = ic.defn +// val kind = ic.kind +// import IndirectSplitKind._ +// kind match +// case FirstCase | AfterCase => +// // it's impossible to have first case here because we have an EIndirectDestruct elim +// subst_jump_mixing_cases(first_case(defn_name), as) +// case JumpBeforeCase => +// val (name, args) = ic.where.marker match +// case LocMarker.MJump(name, args) => (name, args) +// case _ => throw OptimizingError("unexpected marker") +// val PreFunction(pre_f, pre_retvals) = pre_map(ic.where) +// val new_names = make_new_names_for_free_variables(pre_retvals) +// val names_map = pre_retvals.zip(new_names).toMap +// LetCall(new_names, DefnRef(Right(pre_f)), as, +// Jump(DefnRef(Right(name)), rebuild_args_from_marker(args, names_map)).attachTag(tag)).attachTag(tag) +// case CallBeforeCase => +// val (names, defn2, args) = ic.where.marker match +// case LocMarker.MLetCall(names, defn, args) => (names, defn, args) +// case _ => throw OptimizingError("unexpected marker") +// val PreFunction(pre_f, pre_retvals) = pre_map(ic.where) +// val new_names = make_new_names_for_free_variables(pre_retvals) +// val names_map = pre_retvals.zip(new_names).toMap +// val new_names_2 = make_new_names_for_free_variables(names) +// val names_map_2 = names_map ++ names.zip(new_names_2).toMap +// val PostFunction(post_f, post_params) = single_post_map(ic.where) +// LetCall(new_names, DefnRef(Right(pre_f)), as, +// LetCall(new_names_2, DefnRef(Right(defn2)), rebuild_args_from_marker(args, names_map), +// Jump(DefnRef(Right(post_f)), post_params.map{x => Ref(names_map_2(x))}).attachTag(tag)).attachTag(tag)).attachTag(tag) + +// private def f(env: SubstEnv, node: Node): Node = node match +// case Result(res) => node +// case Case(scrut, cases, default) => +// Case(scrut, cases map { +// case (x @ Pat.Class(cls), arm) => +// (x, f(env.copy(intros = env.intros + (scrut.str -> ICtor(cls.ident))), arm)) +// case (x @ Pat.Lit(_), arm) => +// (x, f(env, arm)) +// }, default map { x => f(env, x) }).copyTag(node) +// case LetExpr(x, e1, e2) => +// val intros2 = IntroductionAnalysis.getIntro(e1, env.intros).map { y => env.intros + (x.str -> y) }.getOrElse(env.intros) +// LetExpr(x, e1, f(env.copy(intros = intros2), e2)).copyTag(node) +// case Jump(defnref, args) => +// val dloc = DefnLocMarker(env.defn.name, node.locMarker) +// val defn = defnref.expectDefn +// if targets.indirect_consumer.contains(node.locMarker) then +// changed = true +// val spec = targets.indirect_consumer(node.locMarker) +// subst_jump_indirect(spec, args) +// else if targets.mixing_consumer.contains(node.locMarker) && first_case.contains(targets.mixing_consumer(node.locMarker)) then +// changed = true +// val target = targets.mixing_consumer(node.locMarker) +// if targets.known_case.contains(node.locMarker) then +// subst_jump_known_case(first_case(target), args, targets.known_case(node.locMarker)) +// else +// subst_jump_mixing_cases(first_case(target), args) +// else /* if targets.specialize.contains(node.locMarker) then +// changed = true +// val spec = targets.specialize(node.locMarker) +// val new_defn = specialized_map(spec.defn) +// val new_node = Jump(DefnRef(Right(new_defn)), args).attachTag(tag) +// new_node +// else */ +// node +// case LetCall(names, defnref, args, body) => +// val dloc = DefnLocMarker(env.defn.name, node.locMarker) +// val defn = defnref.expectDefn +// val intros2 = updateIntroInfoAndMaintainMixingIntros(name_defn_map, defn, node.locMarker, env.intros, names) +// if targets.indirect_consumer.contains(node.locMarker) then +// changed = true +// val spec = targets.indirect_consumer(node.locMarker) +// subst_letcall_indirect(env, spec, names, args, body) +// else if targets.mixing_consumer.contains(node.locMarker) && first_case.contains(targets.mixing_consumer(node.locMarker)) then +// changed = true +// val target = targets.mixing_consumer(node.locMarker) +// val new_node = if targets.known_case.contains(node.locMarker) then +// subst_letcall_known_case(env, first_case(target), names, args, body, targets.known_case(node.locMarker)) +// else +// subst_letcall_mixing_cases(env, first_case(target), names, args, body) +// new_node +// else if names.tail.isEmpty && intros2.get(names.head.str).exists(_.isInstanceOf[IMix]) && targets.mixing_producer.contains(node.locMarker) && first_case.contains(targets.mixing_producer(node.locMarker)) then +// changed = true +// val target = targets.mixing_producer(node.locMarker) +// val new_node = subst_letcall_mixing_cases(env, first_case(target), names, args, body) +// new_node +// else if targets.specialize.contains(node.locMarker) then +// changed = true +// val spec = targets.specialize(node.locMarker) +// val new_defn = specialized_map(spec.defn) +// val new_node = LetCall(names, DefnRef(Right(new_defn)), args, body).attachTag(tag) +// new_node +// else +// LetCall(names, defnref, args, f(env.copy(intros = intros2), body)).copyTag(node) +// def run(x: Program) = +// this.defs = Set.empty +// var defs = x.defs.map{ defn => +// val intros = defn.specialized.map(bindIntroInfoUsingInput(Map.empty, _, defn.params)).getOrElse(Map.empty) +// val new_defn = defn.copy(body = f(SubstEnv(intros, defn), defn.body)) +// new_defn +// } +// val main = x.main +// defs = defs ++ this.defs +// resolveDefnRef(main, defs) +// validate(main, defs) +// Program(x.classes, defs, main) + + +// private object Splitting: +// def run(x: Program) = +// val sta = SplittingTargetAnalysis() +// val targets = sta.run(x) +// val fs = FunctionSplitting(split_cache) +// val sr = fs.run(x.defs, targets) +// var y = x.copy(defs = sr.overwrite(x.defs) ++ sr.all_defs) +// resolveDefnRef(y.main, y.defs) +// validate(y.main, y.defs) +// activeAnalyze(y) +// recBoundaryAnalyze(y) +// val clsctx = makeClassCtx(y.classes) +// var changed = true +// while (changed) +// val scsr = SplittingCallSiteReplacement(clsctx, sr) +// y = scsr.run(y) +// resolveDefnRef(y.main, y.defs) +// validate(y.main, y.defs) +// activeAnalyze(y) +// recBoundaryAnalyze(y) +// changed = scsr.changed +// (y, sr) + +// private def splitFunction(prog: Program) = Splitting.run(prog) + +// private class ScalarReplacementTargetAnalysis extends Iterator: +// val ctx = MutHMap[Str, MutHMap[Str, Set[Str]]]() +// var name_map = Map[Str, Str]() +// private var intros = Map.empty[Str, Intro] + +// private def addTarget(name: Str, field: Str, target: Str) = +// ctx.getOrElseUpdate(name, MutHMap()).updateWith(target) { +// case Some(xs) => Some(xs + field) +// case None => Some(Set(field)) +// } + +// private def checkTargets(defn: Defn, intros: Map[Str, Intro], args: Ls[TrivialExpr]) = +// val name = defn.name +// val params = defn.params +// val active = defn.newActiveParams +// args.map { +// case Ref(x) => intros.get(x.str) +// case _ => None +// }.zip(params).zip(active).foreach { +// case ((Some(ICtor(cls)), param), elim) if elim.exists(_.elim.isInstanceOf[ESelect]) && !elim.exists(_.elim == EDirect) => +// elim.foreach { +// case ElimInfo(ESelect(field), _) => addTarget(name, field, param.str) +// case _ => +// } +// case x @ ((_, param), elim) => +// } + +// override def iterate(x: Jump): Unit = x match +// case Jump(defnref, args) => +// val defn = defnref.expectDefn +// checkTargets(defn, intros, args) + +// override def iterate(x: LetExpr): Unit = x match +// case LetExpr(x, e1, e2) => +// intros = IntroductionAnalysis.getIntro(e1, intros).map { y => intros + (x.str -> y) }.getOrElse(intros) +// e2.acceptIterator(this) + +// override def iterate(x: LetCall): Unit = x match +// case LetCall(xs, defnref, as, e) => +// val defn = defnref.expectDefn +// checkTargets(defn, intros, as) +// intros = updateIntroInfo(defn, intros, xs) +// e.acceptIterator(this) + +// override def iterate(x: Case) = x match +// case Case(x, cases, default) => +// cases foreach { +// case (Pat.Class(cls), arm) => +// intros = intros + (x.str -> ICtor(cls.ident)) +// arm.acceptIterator(this) +// case (Pat.Lit(_), arm) => +// arm.acceptIterator(this) +// } +// default foreach { x => x.acceptIterator(this) } + +// override def iterate(defn: Defn): Unit = +// intros = defn.specialized.map(bindIntroInfoUsingInput(Map.empty, _, defn.params)).getOrElse(Map.empty) +// defn.body.acceptIterator(this) + +// override def iterate(x: Program): Unit = +// x.defs.foreach { x => x.acceptIterator(this) } + +// private def sort_targets(fldctx: Map[Str, (Str, ClassInfo)], targets: Set[Str]) = +// val cls = fldctx(targets.head)._2 +// cls.fields.filter(targets.contains(_)) + +// def run(x: Program) = +// x.acceptIterator(this) +// val clsctx = makeClassCtx(x.classes) +// val fldctx = x.classes.flatMap { case ClassInfo(_, name, fields) => fields.map { fld => (fld, (name, clsctx(name))) } }.toMap +// name_map = ctx.map { (k, _) => k -> fresh.make(k + "$S").str }.toMap +// ctx.map { (k, v) => k -> v.map{ (k, v) => (k, sort_targets(fldctx, v)) }.toMap }.toMap + +// private enum ParamSubst: +// case ParamKeep +// case ParamFieldOf(orig: Str, field: Str) + +// import ParamSubst._ + +// private def fieldParamName(name: Str, field: Str) = Name(name + "_" + field) + +// private def fieldParamNames(targets: Map[Str, Ls[Str]]) = +// targets.flatMap { (k, fields) => fields.map { x => fieldParamName(k, x) } } + +// private def paramSubstMap(params: Ls[Name], targets: Map[Str, Ls[Str]]) = +// params.flatMap { +// case x if targets.contains(x.str) => None +// case x => Some(x.str -> ParamKeep) +// }.toMap ++ targets.flatMap { +// (k, fields) => fields.map { x => fieldParamName(k, x).str -> ParamFieldOf(k, x) } +// }.toMap + + +// private def newParams(params: Ls[Name], targets: Map[Str, Ls[Str]]) = +// params.filter(x => !targets.contains(x.str)) ++ fieldParamNames(targets) + +// private class SelectionReplacement(target_params: Set[Str]): +// def run(node: Node): Node = f(node) + +// private def f(node: Node): Node = node match +// case Result(res) => node +// case Jump(defn, args) => node +// case Case(scrut, cases, default) => +// Case(scrut, cases.map { (cls, arm) => (cls, f(arm)) }, default.map(f)).copyTag(node) +// case LetExpr(x, Select(y, cls, field), e2) if target_params.contains(y.str) => +// LetExpr(x, Ref(fieldParamName(y.str, field)), f(e2)).copyTag(node) +// case LetExpr(x, e1, e2) => +// LetExpr(x, e1, f(e2)).copyTag(node) +// case LetCall(names, defn, args, body) => +// LetCall(names, defn, args, f(body)).copyTag(node) + + +// private class ScalarReplacementDefinitionBuilder(name_map: Map[Str, Str], defn_param_map: Map[Str, Map[Str, Ls[Str]]]) extends Iterator: +// var sr_defs = MutHSet[Defn]() +// override def iterate(x: Defn) = +// if (name_map.contains(x.name)) +// val targets = defn_param_map(x.name) +// val new_params = newParams(x.params, targets) +// val new_name = name_map(x.name) +// val new_def = Defn( +// fn_uid.make, +// new_name, +// new_params, +// x.resultNum, +// None, +// SelectionReplacement(targets.keySet).run(x.body), +// ) +// sr_defs.add(new_def) + +// private class ScalarReplacementCallSiteReplacement(defn_map: Map[Str, Str], defn_param_map: Map[Str, Map[Str, Ls[Str]]]): +// var fldctx = Map.empty[Str, (Str, ClassInfo)] + +// private def susbtCallsite(defn: Defn, as: Ls[TrivialExpr], f: (Str, Ls[TrivialExpr]) => Node) = +// val new_name = defn_map(defn.name) +// val targets = defn_param_map(defn.name) +// val param_subst = paramSubstMap(defn.params, targets) +// val new_params = newParams(defn.params, targets) +// val argMap = defn.params.map(_.str).zip(as).toMap + +// val sel_ctx = MutHMap[(Name, Str), Name]() + +// val letlist = new_params.flatMap { +// param => param_subst(param.str) match { +// case ParamKeep => None +// case ParamFieldOf(orig, field) => +// val orig_arg = expectTexprIsRef(argMap(orig)) +// val new_var = fresh.make +// sel_ctx.addOne((orig_arg, field) -> new_var) +// Some((new_var, orig_arg, field)) +// } +// } + +// val new_args: Ls[TrivialExpr] = new_params.map { +// param => param_subst(param.str) match { +// case ParamKeep => argMap(param.str) +// case ParamFieldOf(orig, str) => +// val orig_arg = expectTexprIsRef(argMap(orig)) +// val x = sel_ctx.get((orig_arg, str)).get +// Ref(x) +// } +// } + +// val new_node = f(new_name, new_args) +// letlist.foldRight(new_node) { case ((x, y, field), node) => +// LetExpr(x, Select(y, fldctx(field)._2, field), node).attachTagAs[LetExpr](tag) +// } + +// private def f(node: Node): Node = node match +// case Result(res) => node +// case Jump(defnref, as) => +// val defn = defnref.expectDefn +// if (defn_param_map.contains(defn.name)) +// susbtCallsite(defn, as, (x, y) => Jump(DefnRef(Right(x)), y).copyTag(node)) +// else +// node +// case Case(scrut, cases, default) => +// Case(scrut, cases.map { (cls, arm) => (cls, f(arm)) }, default map f).copyTag(node) +// case LetExpr(name, expr, body) => +// LetExpr(name, expr, f(body)).copyTag(node) +// case LetCall(xs, defnref, as, e) => +// val defn = defnref.expectDefn +// if (defn_param_map.contains(defn.name)) +// susbtCallsite(defn, as, (x, y) => LetCall(xs, DefnRef(Right(x)), y, f(e)).copyTag(node)) +// else +// LetCall(xs, defnref, as, f(e)).copyTag(node) + +// def run(x: Program) = +// val clsctx = makeClassCtx(x.classes) +// fldctx = x.classes.flatMap { case ClassInfo(_, name, fields) => fields.map { fld => (fld, (name, clsctx(name))) } }.toMap +// val y = Program(x.classes, x.defs.map(x => x.copy(body = f(x. body))), f(x.main)) +// resolveDefnRef(y.main, y.defs) +// validate(y.main, y.defs) +// y + +// private def expectTexprIsRef(expr: TrivialExpr): Name = expr match { +// case Ref(name) => name +// case _ => ??? // how is a literal scalar replaced? +// } + +// private class ScalarReplacement: +// def run(x: Program) = +// val srta = ScalarReplacementTargetAnalysis() +// val worklist = srta.run(x) +// val name_map = srta.name_map +// val srdb = ScalarReplacementDefinitionBuilder(name_map, worklist) + +// x.acceptIterator(srdb) + +// val new_defs = x.defs ++ srdb.sr_defs + +// val srcsp = ScalarReplacementCallSiteReplacement(name_map, worklist) +// val y = Program(x.classes, new_defs, x.main) +// srcsp.run(y) + +// def replaceScalar(prog: Program): Program = +// ScalarReplacement().run(prog) + +// private class TrivialBindingSimplification: +// def run(x: Program) = +// val new_defs = x.defs.map(x => { x.copy(body = f(Map.empty, x.body))}) +// resolveDefnRef(x.main, new_defs) +// Program(x.classes, new_defs, x.main) + +// private def f(rctx: Map[Str, TrivialExpr], node: Node): Node = node match +// case Result(res) => Result(res.map(x => f(rctx, x))).copyTag(node) +// case Jump(defn, args) => Jump(defn, args.map(x => f(rctx, x))).copyTag(node) +// case Case(scrut, cases, default) => Case(f(rctx, scrut), cases.map { (cls, arm) => (cls, f(rctx, arm)) }, default.map(f(rctx, _))).copyTag(node) +// case LetExpr(x, Ref(Name(z)), e2) if rctx.contains(z) => +// val rctx2 = rctx + (x.str -> rctx(z)) +// f(rctx2, e2) +// case LetExpr(x, y @ Ref(Name(_)), e2) => +// val rctx2 = rctx + (x.str -> y) +// f(rctx2, e2) +// case LetExpr(x, y @ Literal(_), e2) => +// val rctx2 = rctx + (x.str -> y) +// f(rctx2, e2) +// case LetExpr(x, e1, e2) => +// LetExpr(x, f(rctx, e1), f(rctx, e2)).copyTag(node) +// case LetCall(names, defn, args, body) => +// LetCall(names, defn, args.map(x => f(rctx, x)), f(rctx, body)).copyTag(node) + +// private def f(rctx: Map[Str, TrivialExpr], x: Expr): Expr = x match +// case Ref(name) => f(rctx, x) +// case Literal(lit) => x +// case CtorApp(name, args) => CtorApp(name, args.map(x => f(rctx, x))) +// case Select(name, cls, field) => Select(f(rctx, name), cls, field) +// case BasicOp(name, args) => BasicOp(name, args.map(x => f(rctx, x))) + + +// private def f(rctx: Map[Str, TrivialExpr], y: TrivialExpr): TrivialExpr = y match +// case Ref(Name(x)) if rctx.contains(x) => +// rctx(x) +// case _ => y + +// private def f(rctx: Map[Str, TrivialExpr], z: Name): Name = +// val Name(x) = z +// rctx.get(x) match +// case Some(Ref(yy @ Name(y))) => yy +// case _ => z + +// private class SelectionSimplification: +// var cctx: Map[Str, Map[Str, TrivialExpr]] = Map.empty + +// def run(x: Program) = +// val new_defs = x.defs.map(x => { cctx = Map.empty; x.copy(body = f(x.body)) }) +// resolveDefnRef(x.main, new_defs) +// validate(x.main, new_defs) +// Program(x.classes, new_defs, x.main) + +// private def f(x: Node): Node = x match +// case Result(res) => x +// case Jump(defn, args) => x +// case Case(scrut, cases, default) => Case(scrut, cases map { (cls, arm) => (cls, f(arm)) }, default map f).copyTag(x) +// case LetExpr(name, sel @ Select(y, cls, field), e2) if cctx.contains(y.str) => +// cctx.get(y.str) match +// case Some(m) => +// m.get(field) match +// case Some(v) => +// LetExpr(name, v.toExpr, f(e2)) .copyTag(x) +// case None => +// LetExpr(name, sel, f(e2)).copyTag(x) +// case None => LetExpr(name, sel, f(e2)).copyTag(x) +// case LetExpr(name, y @ CtorApp(cls, args), e2) => +// val m = cls.fields.zip(args).toMap +// cctx = cctx + (name.str -> m) +// LetExpr(name, y, f(e2)).copyTag(x) +// case LetExpr(name, e1, e2) => +// LetExpr(name, e1, f(e2)).copyTag(x) +// case LetCall(names, defn, args, body) => +// LetCall(names, defn, args, f(body)).copyTag(x) + +// private class DestructSimplification: +// var cctx: Map[Str, Str] = Map.empty + +// private def f(x: Node): Node = x match +// case Result(res) => x +// case Jump(defn, args) => x +// case Case(scrut, cases, default) if cctx.contains(scrut.str) => +// cctx.get(scrut.str) match +// case Some(cls) => +// val arm = cases.find{ +// case (Pat.Class(cls2), _) => cls2.ident == cls +// case _ => false +// }.get._2 +// f(arm) +// case None => +// default match +// case Some(arm) => f(arm) +// case None => Case(scrut, cases map { (cls, arm) => (cls, f(arm)) }, None).copyTag(x) +// case Case(scrut, cases, default) => +// Case(scrut, cases map { (cls, arm) => (cls, f(arm)) }, default map f).copyTag(x) +// case LetExpr(name, y @ CtorApp(cls, args), e2) => +// cctx = cctx + (name.str -> cls.ident) +// LetExpr(name, y, f(e2)).copyTag(x) +// case LetExpr(name, e1, e2) => +// LetExpr(name, e1, f(e2)).copyTag(x) +// case LetCall(names, defn, args, body) => +// LetCall(names, defn, args, f(body)).copyTag(x) + +// def run(x: Program) = +// val new_defs = x.defs.map(x => { cctx = Map.empty; x.copy(body = f(x.body)) }) +// resolveDefnRef(x.main, new_defs) +// validate(x.main, new_defs) +// Program(x.classes, new_defs, x.main) + + +// private def argsToStrs(args: Ls[TrivialExpr]) = { +// args.flatMap { +// case Ref(x) => Some(x.str) +// case _ => None +// } +// } + +// private class DeadCodeElimination: +// val defs = MutHMap[Name, Int]() +// var uses = Map[(Name, Int), Int]() + +// private def addDef(x: Name) = +// defs.update(x, defs.getOrElse(x, 0) + 1) + +// private def f(x: Node): Node = x match +// case Result(res) => x +// case Jump(defn, args) => x +// case Case(scrut, cases, default) => Case(scrut, cases map { (cls, arm) => (cls, f(arm)) }, default map f).copyTag(x) +// case LetExpr(name, expr, body) => +// addDef(name) +// val ui = uses.get((name, defs(name))) +// ui match +// case Some(n) => +// LetExpr(name, expr, f(body)).copyTag(x) +// case None => +// f(body) +// case LetCall(names, defn, args, body) => +// names.foreach(addDef) +// val uis = names.map(name => uses.get(name, defs(name))) +// if uis.forall(_.isEmpty) then +// f(body) +// else +// LetCall(names, defn, args, f(body)).copyTag(x) + +// def run(x: Program) = +// val fns = DefRevPostOrdering.ordered(x.main, x.defs) +// val new_fns = fns.map { x => +// defs.clear() +// uses = UsefulnessAnalysis(verbose).run(x) +// x.params.foreach(addDef) +// x.copy(body = f(x.body)) +// }.toSet +// resolveDefnRef(x.main, new_fns) +// validate(x.main, new_fns) +// Program(x.classes, new_fns, x.main) + +// private class RemoveTrivialCallAndJump: +// private def subst_let_expr(le: LetExpr, map: Map[Name, TrivialExpr]): (Ls[(Name, TrivialExpr)], LetExpr) = +// var let_list = Ls[(Name, TrivialExpr)]() +// val new_expr = le.expr.mapName { +// x => map.get(x) match +// case None => x +// case Some(Ref(y)) => y +// case Some(other) => +// val y = fresh.make +// let_list ::= y -> other +// y + +// } +// val kernel = LetExpr(le.name, new_expr, le.body).attachTagAs[LetExpr](tag) +// (let_list, kernel) + +// private def subst_let_expr_to_node(le: LetExpr, map: Map[Name, TrivialExpr]): Node = +// val (rev_let_list, kernel) = subst_let_expr(le, map) +// rev_let_list.foldLeft(kernel) { +// case (accu, (name, value)) => LetExpr(name, value.toExpr, accu).attachTagAs[LetExpr](tag) +// } + +// private def let_list_to_node(let_list: Ls[(Name, TrivialExpr)], node: Node): Node = +// let_list.foldRight(node) { +// case ((name, value), accu) => LetExpr(name, value.toExpr, accu).attachTagAs[LetExpr](tag) +// } + +// private def param_to_arg(param: TrivialExpr, map: Map[Name, TrivialExpr]): TrivialExpr = param match +// case Ref(x) if map.contains(x) => map(x) +// case x: Ref => x +// case x: Literal => x + +// private def params_to_args(params: Ls[TrivialExpr], map: Map[Name, TrivialExpr]): Ls[TrivialExpr] = +// params.map(param_to_arg(_, map)) + +// private def f(x: Node): Node = x match +// case Result(res) => x +// case Jump(defnref, as) => +// val defn = defnref.expectDefn +// val parammap = defn.params.zip(as).toMap +// (defn.specialized.isEmpty, defn.body) match +// case (true, Result(ys)) => +// Result(params_to_args(ys, parammap)).attachTag(tag) +// case (true, Jump(defnref, as2)) => +// val node = let_list_to_node(defn.params.zip(as), Jump(defnref, as2).attachTag(tag)) +// node +// case (true, le @ LetExpr(y, e1, Result(Ref(z) :: Nil))) if y == z => +// val node = subst_let_expr_to_node(le, parammap) +// node +// case (true, LetCall(xs2, defnref2, as2, Result(xs3))) if +// xs2.zip(xs3).forall{ case (x, Ref(y)) => x == y; case _ => false } => +// val node = let_list_to_node( +// defn.params.zip(as), +// LetCall(xs2, defnref2, as2, Result(xs3).attachTag(tag)).attachTag(tag)) +// node +// case _ => x +// case Case(scrut, cases, default) => Case(scrut, cases.map { (cls, arm) => (cls, f(arm)) }, default map f).copyTag(x) +// case LetExpr(name, expr, body) => LetExpr(name, expr, f(body)).copyTag(x) +// case LetCall(xs, defnref, as, e) => +// val defn = defnref.expectDefn +// val parammap = defn.params.zip(as).toMap +// (defn.specialized.isEmpty, defn.body) match +// case (true, Result(ys)) => +// val init = e |> f +// xs.zip(ys).foldRight(init) { +// case ((name, retval), node) => +// LetExpr(name, param_to_arg(retval, parammap).toExpr, node).attachTag(tag) +// } +// case (true, Jump(defnref, as2)) => +// val node = let_list_to_node(defn.params.zip(as), LetCall(xs, defnref, as2, f(e)).attachTag(tag)) +// node +// case (true, le @ LetExpr(y, e1, Result(Ref(z) :: Nil))) if y == z => +// val (let_list, kernel) = subst_let_expr(le, parammap) +// let_list.foldLeft( +// LetExpr(kernel.name, kernel.expr, +// LetExpr(xs.head, Ref(kernel.name), e |> f).attachTag(tag)).attachTag(tag)) { +// case (accu, (name, value)) => LetExpr(name, value.toExpr, accu).attachTag(tag) +// } +// case (true, LetCall(xs2, defnref2, as2, Result(xs3))) if +// xs2.zip(xs3).forall{ case (x, Ref(y)) => x == y; case _ => false } => +// val node = let_list_to_node(defn.params.zip(as), LetCall(xs, defnref2, as2, f(e)).attachTag(tag)) +// node +// case _ => LetCall(xs, defnref, as, e |> f).copyTag(x) + +// def run(x: Program) = +// val new_defs = x.defs.map{ x => { x.copy(body = f(x.body)) }} +// resolveDefnRef(x.main, new_defs) +// validate(x.main, new_defs) +// Program(x.classes, new_defs, x.main) + +// def simplifyProgram(prog: Program): Program = { +// var changed = true +// var s = prog +// while (changed) { +// val ds = DestructSimplification() +// val ss = SelectionSimplification() +// val tbs = TrivialBindingSimplification() +// val rtcj = RemoveTrivialCallAndJump() +// val dce = DeadCodeElimination() +// var sf = s +// sf = ds.run(sf) +// activeAnalyze(sf) +// sf = ss.run(sf) +// activeAnalyze(sf) +// sf = tbs.run(sf) +// activeAnalyze(sf) +// sf = rtcj.run(sf) +// activeAnalyze(sf) +// sf = dce.run(sf) +// activeAnalyze(sf) +// validate(sf.main, sf.defs) +// changed = s.defs != sf.defs +// s = sf +// } +// s +// } + +// def activeAnalyze(prog: Program): Program = +// IntroductionAnalysis.run(prog) +// EliminationAnalysis().run(prog) +// prog + +// def optimize(prog: Program): Program = { +// var g = simplifyProgram(prog) +// g = activeAnalyze(g) +// g = recBoundaryAnalyze(g) + +// val (g2, sr) = splitFunction(g) +// g = g2 +// g = activeAnalyze(g) +// g = recBoundaryAnalyze(g) + +// g = simplifyProgram(g) +// g = activeAnalyze(g) +// g = recBoundaryAnalyze(g) + +// g = replaceScalar(g) +// g = activeAnalyze(g) +// g = recBoundaryAnalyze(g) + +// g = simplifyProgram(g) +// g = activeAnalyze(g) +// g = recBoundaryAnalyze(g) + +// split_cache = Some(sr.into_cache(g)) +// g +// } + +// def recBoundaryAnalyze(prog: Program): Program = +// RecursiveBoundaryAnalysis.run(prog) +// prog + +// private object RecursiveBoundaryAnalysis: +// import Expr._ +// import Node._ +// import Elim._ +// import Intro._ +// var count = 0 +// def run(x: Program, conservative: Bool = false) = +// val ca = CallAnalysis() +// val cg = ca.call_graph(x) +// val sccs = ca.scc() +// var scc_group = Map.empty[Str, Int] +// var scc_group_size = Map.empty[Int, Int] +// sccs.zipWithIndex.foreach { +// (scc, i) => scc.foreach { +// x => +// scc_group += x -> i +// scc_group_size += i -> (scc_group_size.getOrElse(i, 0) + 1) +// }} +// x.defs.foreach { defn => +// val group = scc_group(defn.name) +// val size = scc_group_size(group) +// defn.recBoundary = Some(group) +// if size == 1 && !cg.getOrElse(defn.name, Set.empty).contains(defn.name) then +// defn.recBoundary = None +// } + +// private class CallAnalysis: +// val cg = MutHMap[Str, MutHSet[Str]]() +// private var cur_defn: Opt[Defn] = None + +// private def f(x: Node): Unit = x match +// case Result(res) => +// case Jump(defn, args) => +// if cur_defn.nonEmpty then +// cg.getOrElseUpdate(cur_defn.get.getName, MutHSet.empty) += defn.getName +// case Case(scrut, cases, default) => cases foreach { (cls, arm) => f(arm) }; default foreach f +// case LetExpr(name, expr, body) => f(body) +// case LetCall(names, defn, args, body) => +// if cur_defn.nonEmpty then +// cg.getOrElseUpdate(cur_defn.get.getName, MutHSet.empty) += defn.getName +// f(body) + +// def call_graph(x: Program): Map[Str, Set[Str]] = +// cg.clear() +// cg.addAll(x.defs.map(x => x.getName -> MutHSet.empty)) +// x.defs.foreach{ defn => +// cur_defn = Some(defn) +// f(defn.body) +// cur_defn = None +// } +// cg.map { (k, v) => k -> v.toSet }.toMap + +// def scc(): List[Set[Str]] = +// var cur_index = 0 +// var index = Map.empty[Str, Int] +// var low = Map.empty[Str, Int] +// var stack = Ls[Str]() +// var on_stack = Set.empty[Str] +// var sccs = Ls[Set[Str]]() + +// def f(v: Str): Unit = { +// index += (v -> cur_index) +// low += (v -> cur_index) +// cur_index += 1 +// stack ::= v +// on_stack += v + +// cg.getOrElse(v, MutHSet.empty).foreach { +// w => +// if (!index.contains(w)) { +// f(w) +// low += v -> low(v).min(low(w)) +// } else if (on_stack.contains(w)) { +// low += v -> low(v).min(index(w)) +// } +// } + +// if (low(v) == index(v)) +// val (scc, new_stack) = stack.splitAt(stack.indexOf(v) + 1) +// stack = new_stack +// scc.foreach { x => on_stack -= x } +// sccs ::= scc.toSet +// } + +// cg.keys.foreach { +// x => if (!index.contains(x)) f(x) +// } + +// sccs + + diff --git a/hkmc2/shared/src/test/mlscript/llir/Legacy.mls b/hkmc2/shared/src/test/mlscript/llir/Original.mls similarity index 99% rename from hkmc2/shared/src/test/mlscript/llir/Legacy.mls rename to hkmc2/shared/src/test/mlscript/llir/Original.mls index 15b19f7106..2275c606bc 100644 --- a/hkmc2/shared/src/test/mlscript/llir/Legacy.mls +++ b/hkmc2/shared/src/test/mlscript/llir/Original.mls @@ -2,7 +2,7 @@ :llir :cpp -// This file contains all legacy tests for LLIR in the old MLScript compiler. +// This file contains all tests for LLIR in the original MLscript compiler. :intl data class Pair[A, B](x: A, y: B) From c753cb589ccd40ec4268beba7d54a21783fd48c2 Mon Sep 17 00:00:00 2001 From: waterlens Date: Fri, 4 Apr 2025 15:54:39 +0800 Subject: [PATCH 73/88] Save --- .../scala/hkmc2/codegen/cpp/CodeGen.scala | 4 +- .../scala/hkmc2/codegen/llir/Builder.scala | 68 +++++++++---------- 2 files changed, 36 insertions(+), 36 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/CodeGen.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/CodeGen.scala index 7bd6ac3d15..bbedfb68f3 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/CodeGen.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/CodeGen.scala @@ -280,7 +280,7 @@ class CppCodeGen(builtinClassSymbols: Set[Local], tl: TraceLogger): ++ builtinClassSymbols.map(x => (x |> mapClsLikeName, Set.empty[String])) log(s"depgraph: $depgraph") var degree = depgraph.view.mapValues(_.size).toMap - def removeNode(node: String) = + def removeNode(node: Str) = degree -= node depgraph -= node depgraph = depgraph.view.mapValues(_.filter(_ != node)).toMap @@ -290,7 +290,7 @@ class CppCodeGen(builtinClassSymbols: Set[Local], tl: TraceLogger): while work.nonEmpty do val node = work.head work -= node - prog.classes.find(x => (x.name |> mapClsLikeName) == node).fold(())(sorted.addOne) + prog.classes.find(x => (x.name |> mapClsLikeName) == node).foreach(sorted.addOne) removeNode(node) val next = degree.filter(_._2 == 0).keys work ++= next diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala index 78464db155..85a37d4589 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala @@ -64,7 +64,7 @@ final case class Ctx( object Ctx: def empty(using Elaborator.State) = - Ctx(ListBuffer.empty, ListBuffer.empty).copy(builtin_sym = BuiltinSymbols( + Ctx(ListBuffer.empty, ListBuffer.empty, builtin_sym = BuiltinSymbols( runtimeSym = Some(Elaborator.State.runtimeSymbol) )) @@ -223,7 +223,6 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger, uid: FreshInt): if !ctx.is_top_level then bErrStop(msg"Non top-level definition ${isym.toString()} not supported") else - val clsDefn = isym.defn.getOrElse(die) val clsParams = paramsOpt.fold(Nil)(_.paramSyms) given Ctx = ctx.setClass(isym) val funcs = methods.map(bMethodDef) @@ -530,7 +529,7 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger, uid: FreshInt): case _ => b.subBlocks.foldLeft(ctx)((ctx, rest) => registerClasses(rest)(using ctx)) - def registerInternalClasses(using ctx: Ctx)(using Raise, Scope): Ctx = + def registerBuiltinClasses(using ctx: Ctx)(using Raise, Scope): Ctx = ctx.builtin_sym.tupleSym.foldLeft(ctx): case (ctx, (len, sym)) => val c = ClassInfo(uid.make, sym, (0 until len).map(x => builtinField(x)).toList, Set.empty, Map.empty) @@ -538,36 +537,37 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger, uid: FreshInt): ctx.addClassInfo(sym, c) def registerFunctions(b: Block)(using ctx: Ctx)(using Raise, Scope): Ctx = - b match - case Match(scrut, arms, dflt, rest) => registerFunctions(rest) - case Return(res, implct) => ctx - case Throw(exc) => ctx - case Label(label, body, rest) => registerFunctions(rest) - case Break(label) => ctx - case Continue(label) => ctx - case Begin(sub, rest) => - val ctx1 = registerFunctions(sub) - registerFunctions(rest)(using ctx1) - case TryBlock(sub, finallyDo, rest) => - val ctx1 = registerFunctions(sub) - val ctx2 = registerFunctions(finallyDo) - registerFunctions(rest)(using ctx2) - case Assign(lhs, rhs, rest) => - registerFunctions(rest) - case AssignField(lhs, nme, rhs, rest) => - registerFunctions(rest) - case AssignDynField(lhs, fld, arrayIdx, rhs, rest) => - registerFunctions(rest) - case Define(fd @ FunDefn(_own, sym, params, body), rest) => - if params.length == 0 then - bErrStop(msg"Function without arguments not supported: ${params.length.toString}") - val ctx2 = ctx.addFuncName(sym, params.head.params.length) - log(s"Define function: ${sym.nme} -> ${ctx2}") - registerFunctions(rest)(using ctx2) - case Define(defn, rest) => registerFunctions(rest) - case HandleBlock(lhs, res, par, args, cls, hdr, bod, rst) => - TODO("HandleBlock not supported") - case End(msg) => ctx + var ctx2 = ctx + new BlockTraverser: + applyBlock(b) + + override def applyBlock(b: Block): Unit = b match + case Match(scrut, arms, dflt, rest) => applyBlock(rest) + case Return(res, implct) => + case Throw(exc) => + case Label(label, body, rest) => applyBlock(rest) + case Break(label) => + case Continue(label) => + case Begin(sub, rest) => applyBlock(rest) + case TryBlock(sub, finallyDo, rest) => applyBlock(rest) + case Assign(lhs, rhs, rest) => applyBlock(rest) + case AssignField(_, _, _, rest) => applyBlock(rest) + case AssignDynField(lhs, fld, arrayIdx, rhs, rest) => applyBlock(rest) + case Define(defn, rest) => applyDefn(defn); applyBlock(rest) + case HandleBlock(lhs, res, par, args, cls, handlers, body, rest) => applyBlock(rest) + case End(msg) => + + override def applyDefn(defn: Defn): Unit = defn match + case f: FunDefn => applyFunDefn(f) + case _ => () + + override def applyFunDefn(fun: FunDefn): Unit = + val FunDefn(_own, sym, params, body) = fun + if params.length == 0 then + bErrStop(msg"Function without arguments not supported: ${params.length.toString}") + ctx2 = ctx2.addFuncName(sym, params.head.params.length) + log(s"Define function: ${sym.nme} -> ${ctx2}") + ctx2 def bProg(e: Program)(using Raise, Scope, Ctx): (LlirProgram, Ctx) = var ctx = summon[Ctx] @@ -586,7 +586,7 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger, uid: FreshInt): ) ctx.def_acc += entryFunc - ctx = registerInternalClasses(using ctx) + ctx = registerBuiltinClasses(using ctx) val prog = LlirProgram(ctx.class_acc.toSet, ctx.def_acc.toSet, entryFunc.name) From 1d5765975b818c84fe968389d8391508af976fa7 Mon Sep 17 00:00:00 2001 From: waterlens Date: Fri, 4 Apr 2025 16:14:29 +0800 Subject: [PATCH 74/88] Save --- hkmc2/shared/src/test/mlscript/llir/BadPrograms.mls | 1 - hkmc2/shared/src/test/mlscript/llir/Original.mls | 2 -- 2 files changed, 3 deletions(-) diff --git a/hkmc2/shared/src/test/mlscript/llir/BadPrograms.mls b/hkmc2/shared/src/test/mlscript/llir/BadPrograms.mls index 8342a860e5..4c231a2836 100644 --- a/hkmc2/shared/src/test/mlscript/llir/BadPrograms.mls +++ b/hkmc2/shared/src/test/mlscript/llir/BadPrograms.mls @@ -1,7 +1,6 @@ :llir :cpp -:todo :ge fun oops(a) = class A with diff --git a/hkmc2/shared/src/test/mlscript/llir/Original.mls b/hkmc2/shared/src/test/mlscript/llir/Original.mls index 2275c606bc..12f12bb424 100644 --- a/hkmc2/shared/src/test/mlscript/llir/Original.mls +++ b/hkmc2/shared/src/test/mlscript/llir/Original.mls @@ -314,7 +314,6 @@ foo() //│ Interpreted: //│ false -:todo "this is a bug because we use reference equality to locate the split point, but the reference changed after previous iteration" :intl abstract class Nat: S[Nat] | O data class S(s: Nat) extends Nat @@ -338,7 +337,6 @@ main() //│ Interpreted: //│ true -:todo "this is a bug because we use reference equality to locate the split point, but the reference changed after previous iteration" :intl abstract class Option[out T]: Some[T] | None data class Some[out T](x: T) extends Option[T] From a8e152529ad53be13f4aea38b91a1a8b9206d8eb Mon Sep 17 00:00:00 2001 From: waterlens Date: Fri, 4 Apr 2025 16:23:28 +0800 Subject: [PATCH 75/88] Rename --- .../shared/src/test/mlscript/llir/{Original.mls => BasisLLIR.mls} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename hkmc2/shared/src/test/mlscript/llir/{Original.mls => BasisLLIR.mls} (100%) diff --git a/hkmc2/shared/src/test/mlscript/llir/Original.mls b/hkmc2/shared/src/test/mlscript/llir/BasisLLIR.mls similarity index 100% rename from hkmc2/shared/src/test/mlscript/llir/Original.mls rename to hkmc2/shared/src/test/mlscript/llir/BasisLLIR.mls From b65632090f354762492520ce3371b279b235c3b5 Mon Sep 17 00:00:00 2001 From: waterlens Date: Fri, 4 Apr 2025 17:25:36 +0800 Subject: [PATCH 76/88] Save --- .../shared/src/main/scala/hkmc2/codegen/llir/Builder.scala | 6 +++--- hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Llir.scala | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala index 85a37d4589..19beeeab75 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala @@ -30,7 +30,7 @@ final case class BuiltinSymbols( var builtinSym: Opt[Local] = None, fieldSym: MutMap[Int, Local] = MutMap.empty, applySym: MutMap[Int, Local] = MutMap.empty, - tupleSym: MutMap[Int, Local] = MutMap.empty, + tupleSym: MutMap[Int, MemberSymbol[? <: ClassLikeDef]] = MutMap.empty, runtimeSym: Opt[TempSymbol] = None, ): def hiddenClasses = callableSym.toSet @@ -43,7 +43,7 @@ final case class Ctx( class_ctx: Map[Local, ClassInfo] = Map.empty, flow_ctx: Map[Path, Local] = Map.empty, is_top_level: Bool = true, - method_class: Opt[Symbol] = None, + method_class: Opt[MemberSymbol[? <: ClassLikeDef]] = None, builtin_sym: BuiltinSymbols = BuiltinSymbols() ): def addFuncName(n: Local, paramsSize: Int) = copy(fn_ctx = fn_ctx + (n -> FuncInfo(paramsSize))) @@ -59,7 +59,7 @@ final case class Ctx( case None => bErrStop(msg"Class not found: ${n.toString}") case Some(value) => value def addKnownClass(n: Path, m: Local) = copy(flow_ctx = flow_ctx + (n -> m)) - def setClass(c: Symbol) = copy(method_class = Some(c)) + def setClass(c: MemberSymbol[? <: ClassLikeDef]) = copy(method_class = Some(c)) def nonTopLevel = copy(is_top_level = false) object Ctx: diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Llir.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Llir.scala index ece2f1f1b0..b275ba1587 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Llir.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Llir.scala @@ -8,13 +8,13 @@ import mlscript.utils.shorthands._ import syntax._ import Message.MessageContext import document._ -import codegen.Local +import codegen._ import util.Sorting import collection.immutable.SortedSet import language.implicitConversions import collection.mutable.{Map as MutMap, Set as MutSet, HashMap, ListBuffer} -import hkmc2.semantics.BuiltinSymbol +import hkmc2.semantics._ private def raw(x: String): Document = doc"$x" @@ -57,7 +57,7 @@ implicit object ClassInfoOrdering extends Ordering[ClassInfo] { case class ClassInfo( id: Int, - name: Local, + name: MemberSymbol[? <: ClassLikeDef], fields: Ls[Local], parents: Set[Local], methods: Map[Local, Func], From 77bd997d2e3a2decc2c0512da6eadb127a8d45a1 Mon Sep 17 00:00:00 2001 From: waterlens Date: Fri, 4 Apr 2025 17:30:09 +0800 Subject: [PATCH 77/88] Save --- .../scala/hkmc2/codegen/llir/Builder.scala | 19 ++++++++++--------- .../main/scala/hkmc2/codegen/llir/Llir.scala | 2 +- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala index 19beeeab75..af88ef44f5 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala @@ -40,7 +40,8 @@ final case class Ctx( class_acc: ListBuffer[ClassInfo], symbol_ctx: Map[Local, Local] = Map.empty, fn_ctx: Map[Local, FuncInfo] = Map.empty, // is a known function - class_ctx: Map[Local, ClassInfo] = Map.empty, + class_ctx: Map[MemberSymbol[? <: ClassLikeDef], ClassInfo] = Map.empty, + class_sym_ctx: Map[BlockMemberSymbol, MemberSymbol[? <: ClassLikeDef]] = Map.empty, flow_ctx: Map[Path, Local] = Map.empty, is_top_level: Bool = true, method_class: Opt[MemberSymbol[? <: ClassLikeDef]] = None, @@ -50,12 +51,13 @@ final case class Ctx( def findFuncName(n: Local)(using Raise) = fn_ctx.get(n) match case None => bErrStop(msg"Function name not found: ${n.toString()}") case Some(value) => value - def addClassInfo(n: Local, m: ClassInfo) = copy(class_ctx = class_ctx + (n -> m)) + def addClassInfo(n: MemberSymbol[? <: ClassLikeDef], bsym: BlockMemberSymbol, m: ClassInfo) = + copy(class_ctx = class_ctx + (n -> m), class_sym_ctx = class_sym_ctx + (bsym -> n)) def addName(n: Local, m: Local) = copy(symbol_ctx = symbol_ctx + (n -> m)) def findName(n: Local)(using Raise) = symbol_ctx.get(n) match case None => bErrStop(msg"Name not found: ${n.toString}") case Some(value) => value - def findClassInfo(n: Local)(using Raise) = class_ctx.get(n) match + def findClassInfo(n: MemberSymbol[? <: ClassLikeDef])(using Raise) = class_ctx.get(n) match case None => bErrStop(msg"Class not found: ${n.toString}") case Some(value) => value def addKnownClass(n: Path, m: Local) = copy(flow_ctx = flow_ctx + (n -> m)) @@ -320,13 +322,12 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger, uid: FreshInt): case Some(value) => bErrStop(msg"Member symbol without class definition ${value.toString}") case None => bErrStop(msg"Member symbol without definition ${ms.toString}") - private def fromMemToClass(m: Symbol)(using ctx: Ctx)(using Raise, Scope): Local = - trace[Local](s"bFromMemToClass $m", x => s"bFromMemToClass end: $x"): + private def fromMemToClass(m: Symbol)(using ctx: Ctx)(using Raise, Scope): MemberSymbol[? <: ClassLikeDef] = + trace[MemberSymbol[? <: ClassLikeDef]](s"bFromMemToClass $m", x => s"bFromMemToClass end: $x"): m match case ms: MemberSymbol[?] => ms.defn match case Some(d: ClassLikeDef) => d.sym.asClsLike.getOrElse(bErrStop(msg"Class definition without symbol")) - case Some(d: TermDefinition) => d.sym case Some(value) => bErrStop(msg"Member symbol without class definition ${value.toString}") case None => bErrStop(msg"Member symbol without definition ${ms.toString}") case _ => bErrStop(msg"Unsupported symbol kind ${m.toString}") @@ -424,7 +425,7 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger, uid: FreshInt): case args: Ls[TrivialExpr] => val v: Local = newTemp log(s"Method Call Select: $r.$fld with ${s.symbol}") - Node.LetMethodCall(Ls(v), getClassOfField(s.symbol.get), fromMemToClass(s.symbol.get), r :: args, k(v |> sr)) + Node.LetMethodCall(Ls(v), getClassOfField(s.symbol.get), s.symbol.get, r :: args, k(v |> sr)) case Call(_, _) => bErrStop(msg"Unsupported kind of Call ${r.toString()}") case Instantiate( Select(Value.Ref(sym), Tree.Ident("class")), args) => @@ -523,7 +524,7 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger, uid: FreshInt): bErrStop(msg"The class ${sym.nme} has auxiliary parameters, which are not yet supported") val c = bClsLikeDef(cd) ctx.class_acc += c - val new_ctx = ctx.addClassInfo(isym, c) + val new_ctx = ctx.addClassInfo(isym, sym, c) log(s"Define class: ${isym.toString()} -> ${ctx}") registerClasses(rest)(using new_ctx) case _ => @@ -534,7 +535,7 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger, uid: FreshInt): case (ctx, (len, sym)) => val c = ClassInfo(uid.make, sym, (0 until len).map(x => builtinField(x)).toList, Set.empty, Map.empty) ctx.class_acc += c - ctx.addClassInfo(sym, c) + ctx.addClassInfo(sym, BlockMemberSymbol(sym.nme, Nil), c) def registerFunctions(b: Block)(using ctx: Ctx)(using Raise, Scope): Ctx = var ctx2 = ctx diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Llir.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Llir.scala index b275ba1587..7af479556f 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Llir.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Llir.scala @@ -128,7 +128,7 @@ private def showArguments(args: Ls[TrivialExpr]) = args map (_.show) mkString ", enum Expr: case Ref(sym: Local) extends Expr, TrivialExpr case Literal(lit: hkmc2.syntax.Literal) extends Expr, TrivialExpr - case CtorApp(cls: Local, args: Ls[TrivialExpr]) + case CtorApp(cls: MemberSymbol[? <: ClassLikeDef], args: Ls[TrivialExpr]) case Select(name: Local, cls: Local, field: Str) case BasicOp(name: BuiltinSymbol, args: Ls[TrivialExpr]) case AssignField(assignee: Local, cls: Local, field: Str, value: TrivialExpr) From a2a88ca89fe1bb5c9609eb7ee3b02caf2c4bde46 Mon Sep 17 00:00:00 2001 From: waterlens Date: Fri, 4 Apr 2025 17:47:51 +0800 Subject: [PATCH 78/88] Don't hack --- .../shared/src/main/scala/hkmc2/codegen/llir/Builder.scala | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala index af88ef44f5..75f6121448 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala @@ -385,7 +385,11 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger, uid: FreshInt): case args: Ls[TrivialExpr] => val v: Local = newTemp Node.LetExpr(v, Expr.BasicOp(sym, args), k(v |> sr)) - case Call(Value.Ref(sym), args) if sym.nme.isCapitalized => + case Call(Value.Ref(sym: MemberSymbol[?]), args) if sym.defn.exists(defn => defn match + case cls: ClassLikeDef => true + case _ => false + ) => + log(s"xxx $sym is ${sym.getClass()}") bArgs(args): case args: Ls[TrivialExpr] => val v: Local = newTemp From 23d69f208a3fb50407ac9c1bf30ecc6352198ab9 Mon Sep 17 00:00:00 2001 From: waterlens Date: Fri, 4 Apr 2025 19:22:30 +0800 Subject: [PATCH 79/88] Update --- .../main/scala/hkmc2/codegen/cpp/CodeGen.scala | 8 +++----- .../main/scala/hkmc2/codegen/llir/Builder.scala | 15 ++++++++------- .../src/main/scala/hkmc2/codegen/llir/Llir.scala | 4 ++-- 3 files changed, 13 insertions(+), 14 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/CodeGen.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/CodeGen.scala index bbedfb68f3..1fc3def999 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/CodeGen.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/CodeGen.scala @@ -8,7 +8,7 @@ import scala.collection.mutable.ListBuffer import llir.{Expr => IExpr, _} import utils.{Scope, TraceLogger} -import semantics.BuiltinSymbol +import semantics._ class CppCodeGen(builtinClassSymbols: Set[Local], tl: TraceLogger): import tl.{trace, log, logs} @@ -79,7 +79,6 @@ class CppCodeGen(builtinClassSymbols: Set[Local], tl: TraceLogger): val mlsThis = Expr.Var("_mlsValue(this, _mlsValue::inc_ref_tag{})") // first construct a value, then incRef() case class Ctx( - defnCtx: Set[Local], fieldCtx: Set[Local], ) @@ -109,7 +108,7 @@ class CppCodeGen(builtinClassSymbols: Set[Local], tl: TraceLogger): else val methods = cls.methods.map: case (name, defn) => - val (cdef, decl) = codegenDefn(using Ctx(summon[Ctx].defnCtx + cls.name, summon[Ctx].fieldCtx ++ cls.fields))(defn) + val (cdef, decl) = codegenDefn(using Ctx(summon[Ctx].fieldCtx ++ cls.fields))(defn) val cdef2 = cdef match case x: Def.FuncDef if builtinApply.contains(defn.name.nme) => x.copy(name = defn.name |> directName, in_scope = Some(cls.name |> mapClsLikeName)) case x: Def.FuncDef => x.copy(in_scope = Some(cls.name |> mapClsLikeName)) @@ -301,9 +300,8 @@ class CppCodeGen(builtinClassSymbols: Set[Local], tl: TraceLogger): def codegen(prog: Program)(using Raise, Scope): CompilationUnit = val sortedClasses = sortClasses(prog) - val defnCtx = prog.defs.map(_.name) val fieldCtx = Set.empty[Local] - given Ctx = Ctx(defnCtx, fieldCtx) + given Ctx = Ctx(fieldCtx) val (defs, decls, methodsDef) = sortedClasses.map(codegenClassInfo).unzip3 val (defs2, decls2) = prog.defs.map(codegenDefn).unzip CompilationUnit(Ls(mlsPrelude), decls ++ decls2, defs.flatten ++ defs2 ++ methodsDef.flatten :+ Def.RawDef(mlsCallEntry(prog.entry |> allocIfNew)) :+ Def.RawDef(mlsEntryPoint)) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala index 75f6121448..790e129fd3 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala @@ -28,8 +28,8 @@ final case class BuiltinSymbols( var callableSym: Opt[Local] = None, var thisSym: Opt[Local] = None, var builtinSym: Opt[Local] = None, - fieldSym: MutMap[Int, Local] = MutMap.empty, - applySym: MutMap[Int, Local] = MutMap.empty, + fieldSym: MutMap[Int, VarSymbol] = MutMap.empty, + applySym: MutMap[Int, BlockMemberSymbol] = MutMap.empty, tupleSym: MutMap[Int, MemberSymbol[? <: ClassLikeDef]] = MutMap.empty, runtimeSym: Opt[TempSymbol] = None, ): @@ -113,15 +113,16 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger, uid: FreshInt): private def newTemp = TempSymbol(N, "x") private def newNamedTemp(name: Str) = TempSymbol(N, name) + private def newNamedBlockMem(name: Str) = BlockMemberSymbol(name, Nil) private def newNamed(name: Str) = VarSymbol(Tree.Ident(name)) private def newClassSym(name: Str) = ClassSymbol(Tree.TypeDef(hkmc2.syntax.Cls, Tree.Empty(), N, N), Tree.Ident(name)) private def newTupleSym(len: Int) = ClassSymbol(Tree.TypeDef(hkmc2.syntax.Cls, Tree.Empty(), N, N), Tree.Ident(s"Tuple$len")) - private def newMemSym(name: Str) = TermSymbol(hkmc2.syntax.ImmutVal, None, Tree.Ident(name)) - private def newFunSym(name: Str) = TermSymbol(hkmc2.syntax.Fun, None, Tree.Ident(name)) + private def newVarSym(name: Str) = VarSymbol(Tree.Ident(name)) + private def newFunSym(name: Str) = BlockMemberSymbol(name, Nil) private def newBuiltinSym(name: Str) = BuiltinSymbol(name, false, false, false, false) - private def builtinField(n: Int)(using Ctx) = summon[Ctx].builtin_sym.fieldSym.getOrElseUpdate(n, newMemSym(s"field$n")) + private def builtinField(n: Int)(using Ctx) = summon[Ctx].builtin_sym.fieldSym.getOrElseUpdate(n, newVarSym(s"field$n")) private def builtinApply(n: Int)(using Ctx) = summon[Ctx].builtin_sym.applySym.getOrElseUpdate(n, newFunSym(s"apply$n")) private def builtinTuple(n: Int)(using Ctx) = summon[Ctx].builtin_sym.tupleSym.getOrElseUpdate(n, newTupleSym(n)) private def builtinCallable(using ctx: Ctx) : Local = @@ -254,7 +255,7 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger, uid: FreshInt): // args may have the same name (with different uid) // it's not allowed when generating the names of fields in the backend val clsParams = args.zipWithIndex.map: - case (arg, i) => newNamedTemp(s"lam_arg$i") + case (arg, i) => newVarSym(s"lam_arg$i") val applyParams = params.params // add the parameters of lambda expression to the context val ctx2 = applyParams.foldLeft(ctx)((acc, x) => acc.addName(x.sym, x.sym)) @@ -451,7 +452,7 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger, uid: FreshInt): bPath(scrut): case e: TrivialExpr => val nextCont = Begin(rest, ct) - val jp: Local = newNamedTemp("j") + val jp: BlockMemberSymbol = newNamedBlockMem("j") val fvset = freeVarsFilter(nextCont.freeVarsLLIR -- nextCont.definedVars -- ctx.fn_ctx.keySet) val fvs1 = fvset.toList log(s"Match free vars: $fvset ${nextCont.freeVarsLLIR -- nextCont.definedVars} $fvs1") diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Llir.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Llir.scala index 7af479556f..976177db42 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Llir.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Llir.scala @@ -58,7 +58,7 @@ implicit object ClassInfoOrdering extends Ordering[ClassInfo] { case class ClassInfo( id: Int, name: MemberSymbol[? <: ClassLikeDef], - fields: Ls[Local], + fields: Ls[VarSymbol], parents: Set[Local], methods: Map[Local, Func], ): @@ -91,7 +91,7 @@ implicit object FuncOrdering extends Ordering[Func] { case class Func( id: Int, - name: Local, + name: BlockMemberSymbol, params: Ls[Local], resultNum: Int, body: Node From c97e5a4a8d51e9a015515bfc35f79899fb5b1693 Mon Sep 17 00:00:00 2001 From: waterlens Date: Fri, 4 Apr 2025 19:37:13 +0800 Subject: [PATCH 80/88] Fix --- .../shared/src/main/scala/hkmc2/codegen/Block.scala | 8 ++++++-- .../src/main/scala/hkmc2/codegen/llir/Builder.scala | 13 ++----------- 2 files changed, 8 insertions(+), 13 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/Block.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/Block.scala index ab9e64aa7a..c88ca7d2a6 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/Block.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/Block.scala @@ -106,8 +106,8 @@ sealed abstract class Block extends Product with AutoLocated: case Return(res, implct) => res.freeVarsLLIR case Throw(exc) => exc.freeVarsLLIR case Label(label, body, rest) => (body.freeVarsLLIR - label) ++ rest.freeVarsLLIR - case Break(label) => Set(label) - case Continue(label) => Set(label) + case Break(label) => Set.empty + case Continue(label) => Set.empty case Begin(sub, rest) => sub.freeVarsLLIR ++ rest.freeVarsLLIR case TryBlock(sub, finallyDo, rest) => sub.freeVarsLLIR ++ finallyDo.freeVarsLLIR ++ rest.freeVarsLLIR case Assign(lhs, rhs, rest) => rhs.freeVarsLLIR ++ (rest.freeVarsLLIR - lhs) @@ -411,6 +411,10 @@ sealed abstract class Result: case Call(fun, args) => fun.freeVarsLLIR ++ args.flatMap(_.value.freeVarsLLIR).toSet case Instantiate(cls, args) => cls.freeVarsLLIR ++ args.flatMap(_.freeVarsLLIR).toSet case Select(qual, name) => qual.freeVarsLLIR + case Value.Ref(l: (BuiltinSymbol | TopLevelSymbol | ClassSymbol | TermSymbol)) => Set.empty + case Value.Ref(l: MemberSymbol[?]) => l.defn match + case Some(d: ClassLikeDef) => Set.empty + case _ => Set(l) case Value.Ref(l) => Set(l) case Value.This(sym) => Set.empty case Value.Lit(lit) => Set.empty diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala index 790e129fd3..5c1e9e9a1a 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala @@ -98,15 +98,6 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger, uid: FreshInt): case ts: semantics.InnerSymbol => summon[Scope].findThis_!(ts) case _ => summon[Scope].lookup_!(l) - - private def freeVarsFilter(fvs: Set[Local]) = - trace[Set[Local]](s"freeVarsFilter begin", x => s"freeVarsFilter end: $x"): - fvs.filter: - case _: (BuiltinSymbol | TopLevelSymbol | ClassSymbol | TermSymbol) => false - case ms: MemberSymbol[?] => ms.defn match - case Some(d: ClassLikeDef) => false - case _ => true - case x => true private def symMap(s: Local)(using ctx: Ctx)(using Raise, Scope) = ctx.findName(s) @@ -245,7 +236,7 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger, uid: FreshInt): trace[Node](s"bLam begin", x => s"bLam end: ${x.show}"): val Value.Lam(params, body) = lam // Generate an auxiliary class inheriting from Callable - val freeVars = freeVarsFilter(lam.freeVarsLLIR -- body.definedVars -- recName.iterator -- ctx.fn_ctx.keySet) + val freeVars = lam.freeVarsLLIR -- body.definedVars -- recName.iterator -- ctx.fn_ctx.keySet log(s"Defined vars: ${body.definedVars}") log(s"Match free vars: ${lam.freeVarsLLIR -- body.definedVars} ${ctx.fn_ctx.keySet} ${params.params.map(p => p.sym)}") log(s"Lot: $lam") @@ -453,7 +444,7 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger, uid: FreshInt): case e: TrivialExpr => val nextCont = Begin(rest, ct) val jp: BlockMemberSymbol = newNamedBlockMem("j") - val fvset = freeVarsFilter(nextCont.freeVarsLLIR -- nextCont.definedVars -- ctx.fn_ctx.keySet) + val fvset = nextCont.freeVarsLLIR -- nextCont.definedVars -- ctx.fn_ctx.keySet val fvs1 = fvset.toList log(s"Match free vars: $fvset ${nextCont.freeVarsLLIR -- nextCont.definedVars} $fvs1") val new_ctx = fvs1.foldLeft(ctx)((acc, x) => acc.addName(x, x)) From f22ec12c02bbd8a8ec4c9e577e2b8dd1c2b866c2 Mon Sep 17 00:00:00 2001 From: waterlens Date: Fri, 11 Apr 2025 14:34:04 +0800 Subject: [PATCH 81/88] fix: free vars on llir --- hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Analysis.scala | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Analysis.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Analysis.scala index f4a9fe1bcc..f69ddd6f0c 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Analysis.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Analysis.scala @@ -93,7 +93,9 @@ class FreeVarAnalysis(ctx: Local => Func): case _ => fv val fv3 = cases.foldLeft(fv2): case (acc, (cls, body)) => f(using defined)(body, acc) - fv3 + default match + case Some(body) => f(using defined)(body, fv3) + case None => fv3 case Panic(msg) => fv case LetMethodCall(resultNames, cls, method, args, body) => var fv2 = args.foldLeft(fv)((acc, arg) => f(using defined)(arg.toExpr, acc)) From 58bd65df0be75347979b6e6b0a555738f4f013af Mon Sep 17 00:00:00 2001 From: waterlens Date: Fri, 11 Apr 2025 14:38:41 +0800 Subject: [PATCH 82/88] misc: sync with upstream --- .../test/mlscript/basics/BadModuleUses.mls | 18 +- .../test/mlscript/basics/MiscArrayTests.mls | 6 +- .../test/mlscript/basics/ModuleMethods.mls | 34 +- .../src/test/mlscript/bbml/bbGetters.mls | 12 +- .../src/test/mlscript/codegen/BadSpreads.mls | 2 +- .../shared/src/test/mlscript/llir/Classes.mls | 24 +- .../src/test/mlscript/llir/ControlFlow.mls | 294 +++++++++--------- .../src/test/mlscript/llir/HigherOrder.mls | 38 +-- hkmc2/shared/src/test/mlscript/llir/Lazy.mls | 28 +- .../src/test/mlscript/llir/LazyCycle.mls | 36 +-- .../shared/src/test/mlscript/llir/Method.mls | 22 +- hkmc2/shared/src/test/mlscript/llir/Tuple.mls | 28 +- 12 files changed, 271 insertions(+), 271 deletions(-) diff --git a/hkmc2/shared/src/test/mlscript/basics/BadModuleUses.mls b/hkmc2/shared/src/test/mlscript/basics/BadModuleUses.mls index cd0d56b450..ca0cfd75b8 100644 --- a/hkmc2/shared/src/test/mlscript/basics/BadModuleUses.mls +++ b/hkmc2/shared/src/test/mlscript/basics/BadModuleUses.mls @@ -16,7 +16,7 @@ module Example with :e let m = Example.foo() //│ ╔══[ERROR] Unexpected moduleful application. -//│ ║ l.17: let m = Example.foo() +//│ ║ l.16: let m = Example.foo() //│ ╙── ^^^^^^^^^^^^^ //│ m = M @@ -32,7 +32,7 @@ Example.foo() :e id(Example.foo()) //│ ╔══[ERROR] Unexpected moduleful application. -//│ ║ l.33: id(Example.foo()) +//│ ║ l.30: id(Example.foo()) //│ ║ ^^^^^^^^^^^^^ //│ ╙── Module argument passed to a non-module parameter. //│ = M @@ -43,21 +43,21 @@ Example.foo().mtd() :e Example.foo() + 1 //│ ╔══[ERROR] Unexpected moduleful application. -//│ ║ l.44: Example.foo() + 1 +//│ ║ l.40: Example.foo() + 1 //│ ╙── ^^^^^^^^^^^^^ //│ = "M1" :e M + 1 //│ ╔══[ERROR] Unexpected moduleful reference. -//│ ║ l.51: M + 1 +//│ ║ l.45: M + 1 //│ ╙── ^ //│ = "M1" :e M |> id //│ ╔══[ERROR] Unexpected moduleful reference. -//│ ║ l.58: M |> id +//│ ║ l.50: M |> id //│ ║ ^ //│ ╙── Module argument passed to a non-module parameter. //│ = M @@ -65,7 +65,7 @@ M |> id :e id <| M //│ ╔══[ERROR] Unexpected moduleful reference. -//│ ║ l.66: id <| M +//│ ║ l.57: id <| M //│ ║ ^ //│ ╙── Module argument passed to a non-module parameter. //│ = M @@ -75,7 +75,7 @@ fun (+) lol(a, b) = [a, b] :e M + 1 //│ ╔══[ERROR] Unexpected moduleful reference. -//│ ║ l.76: M + 1 +//│ ║ l.66: M + 1 //│ ║ ^ //│ ╙── Module argument passed to a non-module parameter. //│ = [M, 1] @@ -83,7 +83,7 @@ M + 1 :e let m = M //│ ╔══[ERROR] Unexpected moduleful reference. -//│ ║ l.84: let m = M +//│ ║ l.73: let m = M //│ ╙── ^ //│ m = M @@ -95,7 +95,7 @@ module B with val a: module A = A print(B.a) //│ ╔══[ERROR] Unexpected moduleful selection. -//│ ║ l.96: print(B.a) +//│ ║ l.83: print(B.a) //│ ╙── ^^^ //│ > A diff --git a/hkmc2/shared/src/test/mlscript/basics/MiscArrayTests.mls b/hkmc2/shared/src/test/mlscript/basics/MiscArrayTests.mls index 61c37a4ee5..237ef3cb78 100644 --- a/hkmc2/shared/src/test/mlscript/basics/MiscArrayTests.mls +++ b/hkmc2/shared/src/test/mlscript/basics/MiscArrayTests.mls @@ -65,7 +65,7 @@ xs //│ rhs = Tup of Ls of //│ Ident of "f" //│ ╔══[ERROR] Expected 2 arguments, got 1 -//│ ║ l.56: . map(f) +//│ ║ l.53: . map(f) //│ ╙── ^^^ //│ ═══[RUNTIME ERROR] Error: Function 'map' expected 2 arguments but got 1 @@ -73,7 +73,7 @@ xs xs . map(x => x * 2) //│ ╔══[ERROR] Expected 2 arguments, got 1 -//│ ║ l.74: . map(x => x * 2) +//│ ║ l.68: . map(x => x * 2) //│ ╙── ^^^ //│ ═══[RUNTIME ERROR] Error: Function 'map' expected 2 arguments but got 1 @@ -82,7 +82,7 @@ xs . map(x => x * 2) . print() //│ ╔══[ERROR] Expected 2 arguments, got 1 -//│ ║ l.82: . map(x => x * 2) +//│ ║ l.73: . map(x => x * 2) //│ ╙── ^^^ //│ ═══[RUNTIME ERROR] Error: Function 'map' expected 2 arguments but got 1 diff --git a/hkmc2/shared/src/test/mlscript/basics/ModuleMethods.mls b/hkmc2/shared/src/test/mlscript/basics/ModuleMethods.mls index c4a844e876..be01c6a474 100644 --- a/hkmc2/shared/src/test/mlscript/basics/ModuleMethods.mls +++ b/hkmc2/shared/src/test/mlscript/basics/ModuleMethods.mls @@ -17,7 +17,7 @@ fun f(m) :e f(M) //│ ╔══[ERROR] Unexpected moduleful reference. -//│ ║ l.18: f(M) +//│ ║ l.15: f(M) //│ ║ ^ //│ ╙── Module argument passed to a non-module parameter. @@ -26,7 +26,7 @@ f(42) :e fun f(module m) //│ ╔══[ERROR] Module parameter must have explicit type. -//│ ║ l.27: fun f(module m) +//│ ║ l.23: fun f(module m) //│ ╙── ^ fun f(module m: M) @@ -38,7 +38,7 @@ f(M) :e fun f[T](module m: T) //│ ╔══[ERROR] Expected a module, found non-moduleful reference. -//│ ║ l.39: fun f[T](module m: T) +//│ ║ l.35: fun f[T](module m: T) //│ ║ ^ //│ ╙── Module parameter must have a module type. @@ -61,18 +61,18 @@ fun assertNonMM[T](m) :e fun f() = M //│ ╔══[ERROR] Unexpected moduleful reference. -//│ ║ l.62: fun f() = M +//│ ║ l.57: fun f() = M //│ ║ ^ //│ ╙── Function must be marked as returning a 'module' in order to return a module. :e fun f(): M = M //│ ╔══[ERROR] Unexpected moduleful reference. -//│ ║ l.69: fun f(): M = M +//│ ║ l.63: fun f(): M = M //│ ║ ^ //│ ╙── Function must be marked as returning a 'module' in order to have a module return type. //│ ╔══[ERROR] Unexpected moduleful reference. -//│ ║ l.69: fun f(): M = M +//│ ║ l.63: fun f(): M = M //│ ║ ^ //│ ╙── Function must be marked as returning a 'module' in order to return a module. @@ -81,7 +81,7 @@ fun f(): module M = M :e assertNonM(f()) //│ ╔══[ERROR] Unexpected moduleful application. -//│ ║ l.82: assertNonM(f()) +//│ ║ l.76: assertNonM(f()) //│ ║ ^^^ //│ ╙── Module argument passed to a non-module parameter. @@ -90,7 +90,7 @@ assertM(f()) :e fun f4[T](): module T = M //│ ╔══[ERROR] Expected a module, found non-moduleful reference. -//│ ║ l.91: fun f4[T](): module T = M +//│ ║ l.84: fun f4[T](): module T = M //│ ║ ^ //│ ╙── Function marked as returning a 'module' must have a module return type. @@ -99,8 +99,8 @@ fun f[T](): module MM[T] = MM[T] :e assertNonM(f[Int]()) //│ ╔══[ERROR] Unexpected moduleful application. -//│ ║ l.100: assertNonM(f[Int]()) -//│ ║ ^^^^^^^^ +//│ ║ l.97: assertNonM(f[Int]()) +//│ ║ ^^^^^^^^ //│ ╙── Module argument passed to a non-module parameter. assertM(f[Int]()) @@ -110,14 +110,14 @@ assertM(f[Int]()) :e fun f3() = return M //│ ╔══[ERROR] Unexpected moduleful reference. -//│ ║ l.111: fun f3() = return M +//│ ║ l.105: fun f3() = return M //│ ╙── ^ :todo :e fun f3() = (() => M)() //│ ╔══[ERROR] Unexpected moduleful reference. -//│ ║ l.118: fun f3() = (() => M)() +//│ ║ l.109: fun f3() = (() => M)() //│ ╙── ^ // * [test:T4] @@ -126,7 +126,7 @@ fun f3() = (() => M)() :effectHandlers fun f3() = (() => return M)() //│ ╔══[ERROR] Unexpected moduleful reference. -//│ ║ l.127: fun f3() = (() => return M)() +//│ ║ l.115: fun f3() = (() => return M)() //│ ╙── ^ @@ -136,7 +136,7 @@ fun f3() = (() => return M)() :e fun f(module m: M) = m //│ ╔══[ERROR] Unexpected moduleful reference. -//│ ║ l.137: fun f(module m: M) = m +//│ ║ l.122: fun f(module m: M) = m //│ ║ ^ //│ ╙── Function must be marked as returning a 'module' in order to return a module. @@ -149,7 +149,7 @@ fun f(module m: M): module M = m :e val v = M //│ ╔══[ERROR] Unexpected moduleful reference. -//│ ║ l.150: val v = M +//│ ║ l.139: val v = M //│ ║ ^ //│ ╙── Value must be marked as returning a 'module' in order to return a module. @@ -172,8 +172,8 @@ class C with fun foo: module M = M val bar: module M = M //│ ╔══[ERROR] Function returning modules should not be a class member. -//│ ║ l.172: fun foo: module M = M +//│ ║ l.165: fun foo: module M = M //│ ╙── ^^^^^ //│ ╔══[ERROR] Value returning modules should not be a class member. -//│ ║ l.173: val bar: module M = M +//│ ║ l.166: val bar: module M = M //│ ╙── ^^^^^ diff --git a/hkmc2/shared/src/test/mlscript/bbml/bbGetters.mls b/hkmc2/shared/src/test/mlscript/bbml/bbGetters.mls index feb6229bcb..7dbf13f120 100644 --- a/hkmc2/shared/src/test/mlscript/bbml/bbGetters.mls +++ b/hkmc2/shared/src/test/mlscript/bbml/bbGetters.mls @@ -82,7 +82,7 @@ fun test2() = case n then funny(n - 1) + 1 funny //│ ╔══[WARNING] Pure expression in statement position -//│ ║ l.81: case 0 then 0 +//│ ║ l.79: case 0 then 0 //│ ╙── ^ //│ JS (unsanitized): //│ let test22; @@ -104,15 +104,15 @@ fun test2() = //│ return tmp1 //│ }; //│ ╔══[WARNING] Pure expression in statement position -//│ ║ l.81: case 0 then 0 +//│ ║ l.79: case 0 then 0 //│ ╙── ^ //│ ╔══[ERROR] Function definition shape not yet supported for funny -//│ ║ l.81: case 0 then 0 +//│ ║ l.79: case 0 then 0 //│ ║ ^ -//│ ║ l.82: case n then funny(n - 1) + 1 +//│ ║ l.80: case n then funny(n - 1) + 1 //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╔══[ERROR] Variable not found: funny -//│ ║ l.83: funny +//│ ║ l.81: funny //│ ╙── ^^^^^ //│ Type: ⊤ @@ -121,7 +121,7 @@ fun test2() = fun test3 = print("Hi") //│ ╔══[ERROR] Function definition shape not yet supported for test3 -//│ ║ l.122: print("Hi") +//│ ║ l.114: print("Hi") //│ ╙── ^^^^^^^^^^^ //│ Type: ⊤ diff --git a/hkmc2/shared/src/test/mlscript/codegen/BadSpreads.mls b/hkmc2/shared/src/test/mlscript/codegen/BadSpreads.mls index 678fb1773d..947fcc98c8 100644 --- a/hkmc2/shared/src/test/mlscript/codegen/BadSpreads.mls +++ b/hkmc2/shared/src/test/mlscript/codegen/BadSpreads.mls @@ -42,6 +42,6 @@ fun foo(1) = 2 :todo // proper error fun foo(...1) = 2 -//│ /!!!\ Uncaught error: scala.MatchError: Spread(keyword '...',Some(Loc(8,11,BadSpreads.mls:+44)),Some(IntLit(1))) (of class hkmc2.syntax.Tree$Spread) +//│ /!!!\ Uncaught error: scala.MatchError: Spread(keyword '...',Some(Loc(8,11,BadSpreads.mls:+42)),Some(IntLit(1))) (of class hkmc2.syntax.Tree$Spread) diff --git a/hkmc2/shared/src/test/mlscript/llir/Classes.mls b/hkmc2/shared/src/test/mlscript/llir/Classes.mls index 4acf1523c7..8fa45dd085 100644 --- a/hkmc2/shared/src/test/mlscript/llir/Classes.mls +++ b/hkmc2/shared/src/test/mlscript/llir/Classes.mls @@ -26,23 +26,23 @@ fun main() = main() //│ LLIR: //│ class Base() { -//│ def get$596() = +//│ def get$749() = //│ 1 //│ } //│ class Derived() extends Base { -//│ def get$597() = +//│ def get$750() = //│ 2 //│ } -//│ def main$599() = -//│ let x$620 = Derived$605() in -//│ let x$621 = Base.get$596(x$620) in -//│ let x$622 = Derived.get$597(x$620) in -//│ let x$623 = *(x$621,x$622) in -//│ x$623 -//│ def entry$625() = -//│ let* (x$624) = main() in -//│ x$624 -//│ entry = entry$625 +//│ def main$752() = +//│ let x$773 = Derived$758() in +//│ let x$774 = Base.get$749(x$773) in +//│ let x$775 = Derived.get$750(x$773) in +//│ let x$776 = *(x$774,x$775) in +//│ x$776 +//│ def entry$778() = +//│ let* (x$777) = main() in +//│ x$777 +//│ entry = entry$778 //│ //│ Interpreted: //│ 4 diff --git a/hkmc2/shared/src/test/mlscript/llir/ControlFlow.mls b/hkmc2/shared/src/test/mlscript/llir/ControlFlow.mls index a6a1f7a3a9..e08f40da59 100644 --- a/hkmc2/shared/src/test/mlscript/llir/ControlFlow.mls +++ b/hkmc2/shared/src/test/mlscript/llir/ControlFlow.mls @@ -12,14 +12,14 @@ f1() //│ = 2 //│ LLIR: //│ -//│ def f1$567() = -//│ let x$575 = 1 in -//│ let x$576 = 2 in -//│ x$576 -//│ def entry$578() = -//│ let* (x$577) = f1() in -//│ x$577 -//│ entry = entry$578 +//│ def f1$720() = +//│ let x$728 = 1 in +//│ let x$729 = 2 in +//│ x$729 +//│ def entry$731() = +//│ let* (x$730) = f1() in +//│ x$730 +//│ entry = entry$731 //│ //│ Interpreted: //│ 2 @@ -33,20 +33,20 @@ f2() //│ = 3 //│ LLIR: //│ -//│ def f2$579() = -//│ let x$588 = 0 in -//│ let x$589 = ==(x$588,1) in -//│ case x$589 of +//│ def f2$732() = +//│ let x$741 = 0 in +//│ let x$742 = ==(x$741,1) in +//│ case x$742 of //│ BoolLit(true) => //│ 2 //│ _ => //│ 3 -//│ def j$590() = +//│ def j$743() = //│ undefined -//│ def entry$592() = -//│ let* (x$591) = f2() in -//│ x$591 -//│ entry = entry$592 +//│ def entry$745() = +//│ let* (x$744) = f2() in +//│ x$744 +//│ entry = entry$745 //│ //│ Interpreted: //│ 3 @@ -61,21 +61,21 @@ f3() //│ = 0 //│ LLIR: //│ -//│ def f3$593() = -//│ let x$602 = 0 in -//│ let x$603 = 1 in -//│ let x$604 = true in -//│ case x$604 of +//│ def f3$746() = +//│ let x$755 = 0 in +//│ let x$756 = 1 in +//│ let x$757 = true in +//│ case x$757 of //│ BoolLit(true) => -//│ x$602 +//│ x$755 //│ _ => -//│ x$603 -//│ def j$605() = +//│ x$756 +//│ def j$758() = //│ undefined -//│ def entry$607() = -//│ let* (x$606) = f3() in -//│ x$606 -//│ entry = entry$607 +//│ def entry$760() = +//│ let* (x$759) = f3() in +//│ x$759 +//│ entry = entry$760 :sllir @@ -88,22 +88,22 @@ f4() //│ = 3 //│ LLIR: //│ -//│ def f4$608() = -//│ let x$620 = 0 in -//│ let x$621 = ==(x$620,1) in -//│ case x$621 of +//│ def f4$761() = +//│ let x$773 = 0 in +//│ let x$774 = ==(x$773,1) in +//│ case x$774 of //│ BoolLit(true) => -//│ let x$623 = 2 in -//│ jump j$622(x$623) +//│ let x$776 = 2 in +//│ jump j$775(x$776) //│ _ => -//│ let x$624 = 3 in -//│ jump j$622(x$624) -//│ def j$622(tmp$619) = -//│ tmp$619 -//│ def entry$626() = -//│ let* (x$625) = f4() in -//│ x$625 -//│ entry = entry$626 +//│ let x$777 = 3 in +//│ jump j$775(x$777) +//│ def j$775(tmp$772) = +//│ tmp$772 +//│ def entry$779() = +//│ let* (x$778) = f4() in +//│ x$778 +//│ entry = entry$779 //│ //│ Interpreted: //│ 3 @@ -119,31 +119,31 @@ f5() //│ = 5 //│ LLIR: //│ -//│ def f5$627() = -//│ let x$644 = 0 in -//│ let x$645 = ==(x$644,1) in -//│ case x$645 of +//│ def f5$780() = +//│ let x$797 = 0 in +//│ let x$798 = ==(x$797,1) in +//│ case x$798 of //│ BoolLit(true) => -//│ let x$647 = 2 in -//│ jump j$646(x$647) +//│ let x$800 = 2 in +//│ jump j$799(x$800) //│ _ => -//│ let x$648 = 3 in -//│ jump j$646(x$648) -//│ def j$646(tmp$642) = -//│ let x$649 = ==(tmp$642,2) in -//│ case x$649 of +//│ let x$801 = 3 in +//│ jump j$799(x$801) +//│ def j$799(tmp$795) = +//│ let x$802 = ==(tmp$795,2) in +//│ case x$802 of //│ BoolLit(true) => -//│ let x$651 = 4 in -//│ jump j$650(x$651) +//│ let x$804 = 4 in +//│ jump j$803(x$804) //│ _ => -//│ let x$652 = 5 in -//│ jump j$650(x$652) -//│ def j$650(tmp$643) = -//│ tmp$643 -//│ def entry$654() = -//│ let* (x$653) = f5() in -//│ x$653 -//│ entry = entry$654 +//│ let x$805 = 5 in +//│ jump j$803(x$805) +//│ def j$803(tmp$796) = +//│ tmp$796 +//│ def entry$807() = +//│ let* (x$806) = f5() in +//│ x$806 +//│ entry = entry$807 //│ //│ Interpreted: //│ 5 @@ -153,39 +153,39 @@ fun test() = if true do test() //│ LLIR: //│ -//│ def test$655() = -//│ let x$662 = true in -//│ case x$662 of +//│ def test$808() = +//│ let x$815 = true in +//│ case x$815 of //│ BoolLit(true) => -//│ let* (x$664) = test() in -//│ x$664 +//│ let* (x$817) = test() in +//│ x$817 //│ _ => //│ undefined -//│ def j$663() = +//│ def j$816() = //│ undefined -//│ def entry$665() = +//│ def entry$818() = //│ undefined -//│ entry = entry$665 +//│ entry = entry$818 :sllir fun test() = (if true then test()) + 1 //│ LLIR: //│ -//│ def test$666() = -//│ let x$676 = true in -//│ case x$676 of +//│ def test$819() = +//│ let x$829 = true in +//│ case x$829 of //│ BoolLit(true) => -//│ let* (x$678) = test() in -//│ jump j$677(x$678) +//│ let* (x$831) = test() in +//│ jump j$830(x$831) //│ _ => //│ panic "match error" -//│ def j$677(tmp$675) = -//│ let x$679 = +(tmp$675,1) in -//│ x$679 -//│ def entry$680() = +//│ def j$830(tmp$828) = +//│ let x$832 = +(tmp$828,1) in +//│ x$832 +//│ def entry$833() = //│ undefined -//│ entry = entry$680 +//│ entry = entry$833 :sllir @@ -199,23 +199,23 @@ f() //│ = 11 //│ LLIR: //│ -//│ def f$681() = -//│ let x$694 = 10 in -//│ let x$695 = true in -//│ case x$695 of +//│ def f$834() = +//│ let x$847 = 10 in +//│ let x$848 = true in +//│ case x$848 of //│ BoolLit(true) => -//│ let x$697 = +(x$694,1) in -//│ let x$698 = undefined in -//│ jump j$696(x$697) +//│ let x$850 = +(x$847,1) in +//│ let x$851 = undefined in +//│ jump j$849(x$850) //│ _ => -//│ let x$699 = undefined in -//│ jump j$696(x$694) -//│ def j$696(x$683) = -//│ x$683 -//│ def entry$701() = -//│ let* (x$700) = f() in -//│ x$700 -//│ entry = entry$701 +//│ let x$852 = undefined in +//│ jump j$849(x$847) +//│ def j$849(x$836) = +//│ x$836 +//│ def entry$854() = +//│ let* (x$853) = f() in +//│ x$853 +//│ entry = entry$854 //│ //│ Interpreted: //│ 11 @@ -232,27 +232,27 @@ fun f(a) = f(A(1)) //│ = 1 //│ LLIR: -//│ class A(x$707) -//│ class B(y$712) -//│ def f$704(a$716) = -//│ case a$716 of -//│ A$705 => -//│ let x$732 = a$716. in -//│ let x$733 = 1 in -//│ jump j$731(x$733) -//│ B$710 => -//│ let x$734 = a$716. in -//│ let x$735 = 2 in -//│ jump j$731(x$735) +//│ class A(x$860) +//│ class B(y$865) +//│ def f$857(a$869) = +//│ case a$869 of +//│ A$858 => +//│ let x$885 = a$869. in +//│ let x$886 = 1 in +//│ jump j$884(x$886) +//│ B$863 => +//│ let x$887 = a$869. in +//│ let x$888 = 2 in +//│ jump j$884(x$888) //│ _ => //│ panic "match error" -//│ def j$731(tmp$729) = -//│ tmp$729 -//│ def entry$738() = -//│ let x$736 = A$705(1) in -//│ let* (x$737) = f(x$736) in -//│ x$737 -//│ entry = entry$738 +//│ def j$884(tmp$882) = +//│ tmp$882 +//│ def entry$891() = +//│ let x$889 = A$858(1) in +//│ let* (x$890) = f(x$889) in +//│ x$890 +//│ entry = entry$891 //│ //│ Interpreted: //│ 1 @@ -271,44 +271,44 @@ fun f(a) = f(A(1)) //│ = 1 //│ LLIR: -//│ class A(x$744) -//│ class B(y$749) -//│ def f$741(a$753) = -//│ case a$753 of -//│ A$742 => -//│ let x$773 = a$753. in -//│ case a$753 of -//│ A$742 => -//│ let x$775 = a$753. in -//│ case x$775 of +//│ class A(x$897) +//│ class B(y$902) +//│ def f$894(a$906) = +//│ case a$906 of +//│ A$895 => +//│ let x$926 = a$906. in +//│ case a$906 of +//│ A$895 => +//│ let x$928 = a$906. in +//│ case x$928 of //│ IntLit(1) => -//│ let x$777 = 1 in -//│ jump j$776(x$777) +//│ let x$930 = 1 in +//│ jump j$929(x$930) //│ _ => //│ panic "match error" -//│ B$747 => -//│ let x$778 = a$753. in -//│ let x$779 = 2 in -//│ jump j$774(x$779) +//│ B$900 => +//│ let x$931 = a$906. in +//│ let x$932 = 2 in +//│ jump j$927(x$932) //│ _ => //│ panic "match error" -//│ B$747 => -//│ let x$780 = a$753. in -//│ let x$781 = 3 in -//│ jump j$772(x$781) +//│ B$900 => +//│ let x$933 = a$906. in +//│ let x$934 = 3 in +//│ jump j$925(x$934) //│ _ => //│ panic "match error" -//│ def j$776(tmp$769) = -//│ jump j$774(tmp$769) -//│ def j$774(tmp$769) = -//│ jump j$772(tmp$769) -//│ def j$772(tmp$770) = -//│ tmp$770 -//│ def entry$784() = -//│ let x$782 = A$742(1) in -//│ let* (x$783) = f(x$782) in -//│ x$783 -//│ entry = entry$784 +//│ def j$929(tmp$922) = +//│ jump j$927(tmp$922) +//│ def j$927(tmp$922) = +//│ jump j$925(tmp$922) +//│ def j$925(tmp$923) = +//│ tmp$923 +//│ def entry$937() = +//│ let x$935 = A$895(1) in +//│ let* (x$936) = f(x$935) in +//│ x$936 +//│ entry = entry$937 //│ //│ Interpreted: //│ 1 diff --git a/hkmc2/shared/src/test/mlscript/llir/HigherOrder.mls b/hkmc2/shared/src/test/mlscript/llir/HigherOrder.mls index d1a76b556c..0ee0de12f9 100644 --- a/hkmc2/shared/src/test/mlscript/llir/HigherOrder.mls +++ b/hkmc2/shared/src/test/mlscript/llir/HigherOrder.mls @@ -12,27 +12,27 @@ fun add_curried(x)(y) = x + y add(1)(2) //│ = 3 //│ LLIR: -//│ class Lambda_lambda(lam_arg0$589) extends Callable { -//│ def apply1$591(y$571) = -//│ let x$592 = +(lam_arg0$589,y$571) in -//│ x$592 +//│ class Lambda_lambda(lam_arg0$742) extends Callable { +//│ def apply1$744(y$724) = +//│ let x$745 = +(lam_arg0$742,y$724) in +//│ x$745 //│ } -//│ class Lambda(lam_arg0$597) extends Callable { -//│ def apply1$591(y$576) = -//│ let x$598 = +(lam_arg0$597,y$576) in -//│ x$598 +//│ class Lambda(lam_arg0$750) extends Callable { +//│ def apply1$744(y$729) = +//│ let x$751 = +(lam_arg0$750,y$729) in +//│ x$751 //│ } -//│ def add$567(x$570) = -//│ let x$594 = Lambda_lambda$587(x$570) in -//│ x$594 -//│ def add_curried$568(x$575) = -//│ let x$599 = Lambda$595(x$575) in -//│ x$599 -//│ def entry$602() = -//│ let* (x$600) = add(1) in -//│ let x$601 = Callable.apply1$591(x$600,2) in -//│ x$601 -//│ entry = entry$602 +//│ def add$720(x$723) = +//│ let x$747 = Lambda_lambda$740(x$723) in +//│ x$747 +//│ def add_curried$721(x$728) = +//│ let x$752 = Lambda$748(x$728) in +//│ x$752 +//│ def entry$755() = +//│ let* (x$753) = add(1) in +//│ let x$754 = Callable.apply1$744(x$753,2) in +//│ x$754 +//│ entry = entry$755 //│ //│ Interpreted: //│ 3 diff --git a/hkmc2/shared/src/test/mlscript/llir/Lazy.mls b/hkmc2/shared/src/test/mlscript/llir/Lazy.mls index eba9ab7c2c..da733739cf 100644 --- a/hkmc2/shared/src/test/mlscript/llir/Lazy.mls +++ b/hkmc2/shared/src/test/mlscript/llir/Lazy.mls @@ -22,23 +22,23 @@ fun main() = main() //│ LLIR: //│ class Lambda_lambda() extends Callable { -//│ def apply0$635() = -//│ let* (x$636) = side_effect() in -//│ x$636 +//│ def apply0$788() = +//│ let* (x$789) = side_effect() in +//│ x$789 //│ } -//│ def side_effect$610() = -//│ let* (x$630) = ("println","executed") in +//│ def side_effect$763() = +//│ let* (x$783) = ("println","executed") in //│ 1 -//│ def main$609() = -//│ let x$638 = Lambda_lambda$632() in -//│ let* (x$639) = lazy(x$638) in -//│ let* (x$640) = force(x$639) in -//│ let* (x$641) = force(x$639) in +//│ def main$762() = +//│ let x$791 = Lambda_lambda$785() in +//│ let* (x$792) = lazy(x$791) in +//│ let* (x$793) = force(x$792) in +//│ let* (x$794) = force(x$792) in //│ undefined -//│ def entry$643() = -//│ let* (x$642) = main() in -//│ x$642 -//│ entry = entry$643 +//│ def entry$796() = +//│ let* (x$795) = main() in +//│ x$795 +//│ entry = entry$796 //│ //│ Cpp: //│ #include "mlsprelude.h" diff --git a/hkmc2/shared/src/test/mlscript/llir/LazyCycle.mls b/hkmc2/shared/src/test/mlscript/llir/LazyCycle.mls index d820bd5881..5e0a3a7e1a 100644 --- a/hkmc2/shared/src/test/mlscript/llir/LazyCycle.mls +++ b/hkmc2/shared/src/test/mlscript/llir/LazyCycle.mls @@ -16,27 +16,27 @@ fun llist(x) = f(x) llist(1) //│ LLIR: -//│ class Lambda_lambda(lam_arg0$632,lam_arg1$633) extends Callable { -//│ def apply0$634() = -//│ let x$635 = +(lam_arg0$632,1) in -//│ let x$636 = Callable.apply1$629(lam_arg1$633,x$635) in -//│ let x$638 = LzCons$594(lam_arg0$632,x$636) in -//│ x$638 +//│ class Lambda_lambda(lam_arg0$785,lam_arg1$786) extends Callable { +//│ def apply0$787() = +//│ let x$788 = +(lam_arg0$785,1) in +//│ let x$789 = Callable.apply1$782(lam_arg1$786,x$788) in +//│ let x$791 = LzCons$747(lam_arg0$785,x$789) in +//│ x$791 //│ } //│ class Lambda_f() extends Callable { -//│ def apply1$629(x$614) = -//│ let x$639 = Lambda_lambda$630(x$614,$628) in -//│ let* (x$640) = lazy(x$639) in -//│ x$640 +//│ def apply1$782(x$767) = +//│ let x$792 = Lambda_lambda$783(x$767,$781) in +//│ let* (x$793) = lazy(x$792) in +//│ x$793 //│ } -//│ def llist$610(x$612) = -//│ let x$641 = Lambda_f$626() in -//│ let x$642 = Callable.apply1$629(x$641,x$612) in -//│ x$642 -//│ def entry$644() = -//│ let* (x$643) = llist(1) in -//│ x$643 -//│ entry = entry$644 +//│ def llist$763(x$765) = +//│ let x$794 = Lambda_f$779() in +//│ let x$795 = Callable.apply1$782(x$794,x$765) in +//│ x$795 +//│ def entry$797() = +//│ let* (x$796) = llist(1) in +//│ x$796 +//│ entry = entry$797 //│ //│ WholeProgramCpp: //│ #include "mlsprelude.h" diff --git a/hkmc2/shared/src/test/mlscript/llir/Method.mls b/hkmc2/shared/src/test/mlscript/llir/Method.mls index cd309e7f72..0808f8066d 100644 --- a/hkmc2/shared/src/test/mlscript/llir/Method.mls +++ b/hkmc2/shared/src/test/mlscript/llir/Method.mls @@ -11,16 +11,16 @@ fun main() = main() //│ = 1 //│ LLIR: -//│ class A(m$572) { -//│ def f$567() = -//│ m$573 +//│ class A(m$725) { +//│ def f$720() = +//│ m$726 //│ } -//│ def main$569() = -//│ let x$587 = A$570(1) in -//│ let x$588 = A.f$567(x$587) in -//│ x$588 -//│ def entry$590() = -//│ let* (x$589) = main() in -//│ x$589 -//│ entry = entry$590 +//│ def main$722() = +//│ let x$740 = A$723(1) in +//│ let x$741 = A.f$720(x$740) in +//│ x$741 +//│ def entry$743() = +//│ let* (x$742) = main() in +//│ x$742 +//│ entry = entry$743 diff --git a/hkmc2/shared/src/test/mlscript/llir/Tuple.mls b/hkmc2/shared/src/test/mlscript/llir/Tuple.mls index a99ef3592f..7c71f98197 100644 --- a/hkmc2/shared/src/test/mlscript/llir/Tuple.mls +++ b/hkmc2/shared/src/test/mlscript/llir/Tuple.mls @@ -11,23 +11,23 @@ mkTup(1, 2) //│ = [1, 2] //│ LLIR: //│ -//│ def mkTup$567(x$570,y$571) = -//│ let x$583 = Tuple2$584(x$570,y$571) in -//│ x$583 -//│ def fst$568(t$574) = -//│ case t$574 of -//│ Tuple2$584 => -//│ let x$587 = t$574. in -//│ let x$588 = t$574. in -//│ x$587 +//│ def mkTup$720(x$723,y$724) = +//│ let x$736 = Tuple2$737(x$723,y$724) in +//│ x$736 +//│ def fst$721(t$727) = +//│ case t$727 of +//│ Tuple2$737 => +//│ let x$740 = t$727. in +//│ let x$741 = t$727. in +//│ x$740 //│ _ => //│ panic "match error" -//│ def j$586() = +//│ def j$739() = //│ undefined -//│ def entry$590() = -//│ let* (x$589) = mkTup(1,2) in -//│ x$589 -//│ entry = entry$590 +//│ def entry$743() = +//│ let* (x$742) = mkTup(1,2) in +//│ x$742 +//│ entry = entry$743 //│ //│ Cpp: //│ #include "mlsprelude.h" From de1fd2f16d1226a70a14347b71dfe5463ddf4ed9 Mon Sep 17 00:00:00 2001 From: waterlens Date: Fri, 11 Apr 2025 16:26:12 +0800 Subject: [PATCH 83/88] revert part of "misc: sync with upstream" --- .../test/mlscript/basics/BadModuleUses.mls | 18 +++++----- .../test/mlscript/basics/MiscArrayTests.mls | 6 ++-- .../test/mlscript/basics/ModuleMethods.mls | 34 +++++++++---------- .../src/test/mlscript/bbml/bbGetters.mls | 12 +++---- .../src/test/mlscript/codegen/BadSpreads.mls | 2 +- 5 files changed, 36 insertions(+), 36 deletions(-) diff --git a/hkmc2/shared/src/test/mlscript/basics/BadModuleUses.mls b/hkmc2/shared/src/test/mlscript/basics/BadModuleUses.mls index ca0cfd75b8..cd0d56b450 100644 --- a/hkmc2/shared/src/test/mlscript/basics/BadModuleUses.mls +++ b/hkmc2/shared/src/test/mlscript/basics/BadModuleUses.mls @@ -16,7 +16,7 @@ module Example with :e let m = Example.foo() //│ ╔══[ERROR] Unexpected moduleful application. -//│ ║ l.16: let m = Example.foo() +//│ ║ l.17: let m = Example.foo() //│ ╙── ^^^^^^^^^^^^^ //│ m = M @@ -32,7 +32,7 @@ Example.foo() :e id(Example.foo()) //│ ╔══[ERROR] Unexpected moduleful application. -//│ ║ l.30: id(Example.foo()) +//│ ║ l.33: id(Example.foo()) //│ ║ ^^^^^^^^^^^^^ //│ ╙── Module argument passed to a non-module parameter. //│ = M @@ -43,21 +43,21 @@ Example.foo().mtd() :e Example.foo() + 1 //│ ╔══[ERROR] Unexpected moduleful application. -//│ ║ l.40: Example.foo() + 1 +//│ ║ l.44: Example.foo() + 1 //│ ╙── ^^^^^^^^^^^^^ //│ = "M1" :e M + 1 //│ ╔══[ERROR] Unexpected moduleful reference. -//│ ║ l.45: M + 1 +//│ ║ l.51: M + 1 //│ ╙── ^ //│ = "M1" :e M |> id //│ ╔══[ERROR] Unexpected moduleful reference. -//│ ║ l.50: M |> id +//│ ║ l.58: M |> id //│ ║ ^ //│ ╙── Module argument passed to a non-module parameter. //│ = M @@ -65,7 +65,7 @@ M |> id :e id <| M //│ ╔══[ERROR] Unexpected moduleful reference. -//│ ║ l.57: id <| M +//│ ║ l.66: id <| M //│ ║ ^ //│ ╙── Module argument passed to a non-module parameter. //│ = M @@ -75,7 +75,7 @@ fun (+) lol(a, b) = [a, b] :e M + 1 //│ ╔══[ERROR] Unexpected moduleful reference. -//│ ║ l.66: M + 1 +//│ ║ l.76: M + 1 //│ ║ ^ //│ ╙── Module argument passed to a non-module parameter. //│ = [M, 1] @@ -83,7 +83,7 @@ M + 1 :e let m = M //│ ╔══[ERROR] Unexpected moduleful reference. -//│ ║ l.73: let m = M +//│ ║ l.84: let m = M //│ ╙── ^ //│ m = M @@ -95,7 +95,7 @@ module B with val a: module A = A print(B.a) //│ ╔══[ERROR] Unexpected moduleful selection. -//│ ║ l.83: print(B.a) +//│ ║ l.96: print(B.a) //│ ╙── ^^^ //│ > A diff --git a/hkmc2/shared/src/test/mlscript/basics/MiscArrayTests.mls b/hkmc2/shared/src/test/mlscript/basics/MiscArrayTests.mls index 237ef3cb78..61c37a4ee5 100644 --- a/hkmc2/shared/src/test/mlscript/basics/MiscArrayTests.mls +++ b/hkmc2/shared/src/test/mlscript/basics/MiscArrayTests.mls @@ -65,7 +65,7 @@ xs //│ rhs = Tup of Ls of //│ Ident of "f" //│ ╔══[ERROR] Expected 2 arguments, got 1 -//│ ║ l.53: . map(f) +//│ ║ l.56: . map(f) //│ ╙── ^^^ //│ ═══[RUNTIME ERROR] Error: Function 'map' expected 2 arguments but got 1 @@ -73,7 +73,7 @@ xs xs . map(x => x * 2) //│ ╔══[ERROR] Expected 2 arguments, got 1 -//│ ║ l.68: . map(x => x * 2) +//│ ║ l.74: . map(x => x * 2) //│ ╙── ^^^ //│ ═══[RUNTIME ERROR] Error: Function 'map' expected 2 arguments but got 1 @@ -82,7 +82,7 @@ xs . map(x => x * 2) . print() //│ ╔══[ERROR] Expected 2 arguments, got 1 -//│ ║ l.73: . map(x => x * 2) +//│ ║ l.82: . map(x => x * 2) //│ ╙── ^^^ //│ ═══[RUNTIME ERROR] Error: Function 'map' expected 2 arguments but got 1 diff --git a/hkmc2/shared/src/test/mlscript/basics/ModuleMethods.mls b/hkmc2/shared/src/test/mlscript/basics/ModuleMethods.mls index be01c6a474..c4a844e876 100644 --- a/hkmc2/shared/src/test/mlscript/basics/ModuleMethods.mls +++ b/hkmc2/shared/src/test/mlscript/basics/ModuleMethods.mls @@ -17,7 +17,7 @@ fun f(m) :e f(M) //│ ╔══[ERROR] Unexpected moduleful reference. -//│ ║ l.15: f(M) +//│ ║ l.18: f(M) //│ ║ ^ //│ ╙── Module argument passed to a non-module parameter. @@ -26,7 +26,7 @@ f(42) :e fun f(module m) //│ ╔══[ERROR] Module parameter must have explicit type. -//│ ║ l.23: fun f(module m) +//│ ║ l.27: fun f(module m) //│ ╙── ^ fun f(module m: M) @@ -38,7 +38,7 @@ f(M) :e fun f[T](module m: T) //│ ╔══[ERROR] Expected a module, found non-moduleful reference. -//│ ║ l.35: fun f[T](module m: T) +//│ ║ l.39: fun f[T](module m: T) //│ ║ ^ //│ ╙── Module parameter must have a module type. @@ -61,18 +61,18 @@ fun assertNonMM[T](m) :e fun f() = M //│ ╔══[ERROR] Unexpected moduleful reference. -//│ ║ l.57: fun f() = M +//│ ║ l.62: fun f() = M //│ ║ ^ //│ ╙── Function must be marked as returning a 'module' in order to return a module. :e fun f(): M = M //│ ╔══[ERROR] Unexpected moduleful reference. -//│ ║ l.63: fun f(): M = M +//│ ║ l.69: fun f(): M = M //│ ║ ^ //│ ╙── Function must be marked as returning a 'module' in order to have a module return type. //│ ╔══[ERROR] Unexpected moduleful reference. -//│ ║ l.63: fun f(): M = M +//│ ║ l.69: fun f(): M = M //│ ║ ^ //│ ╙── Function must be marked as returning a 'module' in order to return a module. @@ -81,7 +81,7 @@ fun f(): module M = M :e assertNonM(f()) //│ ╔══[ERROR] Unexpected moduleful application. -//│ ║ l.76: assertNonM(f()) +//│ ║ l.82: assertNonM(f()) //│ ║ ^^^ //│ ╙── Module argument passed to a non-module parameter. @@ -90,7 +90,7 @@ assertM(f()) :e fun f4[T](): module T = M //│ ╔══[ERROR] Expected a module, found non-moduleful reference. -//│ ║ l.84: fun f4[T](): module T = M +//│ ║ l.91: fun f4[T](): module T = M //│ ║ ^ //│ ╙── Function marked as returning a 'module' must have a module return type. @@ -99,8 +99,8 @@ fun f[T](): module MM[T] = MM[T] :e assertNonM(f[Int]()) //│ ╔══[ERROR] Unexpected moduleful application. -//│ ║ l.97: assertNonM(f[Int]()) -//│ ║ ^^^^^^^^ +//│ ║ l.100: assertNonM(f[Int]()) +//│ ║ ^^^^^^^^ //│ ╙── Module argument passed to a non-module parameter. assertM(f[Int]()) @@ -110,14 +110,14 @@ assertM(f[Int]()) :e fun f3() = return M //│ ╔══[ERROR] Unexpected moduleful reference. -//│ ║ l.105: fun f3() = return M +//│ ║ l.111: fun f3() = return M //│ ╙── ^ :todo :e fun f3() = (() => M)() //│ ╔══[ERROR] Unexpected moduleful reference. -//│ ║ l.109: fun f3() = (() => M)() +//│ ║ l.118: fun f3() = (() => M)() //│ ╙── ^ // * [test:T4] @@ -126,7 +126,7 @@ fun f3() = (() => M)() :effectHandlers fun f3() = (() => return M)() //│ ╔══[ERROR] Unexpected moduleful reference. -//│ ║ l.115: fun f3() = (() => return M)() +//│ ║ l.127: fun f3() = (() => return M)() //│ ╙── ^ @@ -136,7 +136,7 @@ fun f3() = (() => return M)() :e fun f(module m: M) = m //│ ╔══[ERROR] Unexpected moduleful reference. -//│ ║ l.122: fun f(module m: M) = m +//│ ║ l.137: fun f(module m: M) = m //│ ║ ^ //│ ╙── Function must be marked as returning a 'module' in order to return a module. @@ -149,7 +149,7 @@ fun f(module m: M): module M = m :e val v = M //│ ╔══[ERROR] Unexpected moduleful reference. -//│ ║ l.139: val v = M +//│ ║ l.150: val v = M //│ ║ ^ //│ ╙── Value must be marked as returning a 'module' in order to return a module. @@ -172,8 +172,8 @@ class C with fun foo: module M = M val bar: module M = M //│ ╔══[ERROR] Function returning modules should not be a class member. -//│ ║ l.165: fun foo: module M = M +//│ ║ l.172: fun foo: module M = M //│ ╙── ^^^^^ //│ ╔══[ERROR] Value returning modules should not be a class member. -//│ ║ l.166: val bar: module M = M +//│ ║ l.173: val bar: module M = M //│ ╙── ^^^^^ diff --git a/hkmc2/shared/src/test/mlscript/bbml/bbGetters.mls b/hkmc2/shared/src/test/mlscript/bbml/bbGetters.mls index 7dbf13f120..feb6229bcb 100644 --- a/hkmc2/shared/src/test/mlscript/bbml/bbGetters.mls +++ b/hkmc2/shared/src/test/mlscript/bbml/bbGetters.mls @@ -82,7 +82,7 @@ fun test2() = case n then funny(n - 1) + 1 funny //│ ╔══[WARNING] Pure expression in statement position -//│ ║ l.79: case 0 then 0 +//│ ║ l.81: case 0 then 0 //│ ╙── ^ //│ JS (unsanitized): //│ let test22; @@ -104,15 +104,15 @@ fun test2() = //│ return tmp1 //│ }; //│ ╔══[WARNING] Pure expression in statement position -//│ ║ l.79: case 0 then 0 +//│ ║ l.81: case 0 then 0 //│ ╙── ^ //│ ╔══[ERROR] Function definition shape not yet supported for funny -//│ ║ l.79: case 0 then 0 +//│ ║ l.81: case 0 then 0 //│ ║ ^ -//│ ║ l.80: case n then funny(n - 1) + 1 +//│ ║ l.82: case n then funny(n - 1) + 1 //│ ╙── ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //│ ╔══[ERROR] Variable not found: funny -//│ ║ l.81: funny +//│ ║ l.83: funny //│ ╙── ^^^^^ //│ Type: ⊤ @@ -121,7 +121,7 @@ fun test2() = fun test3 = print("Hi") //│ ╔══[ERROR] Function definition shape not yet supported for test3 -//│ ║ l.114: print("Hi") +//│ ║ l.122: print("Hi") //│ ╙── ^^^^^^^^^^^ //│ Type: ⊤ diff --git a/hkmc2/shared/src/test/mlscript/codegen/BadSpreads.mls b/hkmc2/shared/src/test/mlscript/codegen/BadSpreads.mls index 947fcc98c8..678fb1773d 100644 --- a/hkmc2/shared/src/test/mlscript/codegen/BadSpreads.mls +++ b/hkmc2/shared/src/test/mlscript/codegen/BadSpreads.mls @@ -42,6 +42,6 @@ fun foo(1) = 2 :todo // proper error fun foo(...1) = 2 -//│ /!!!\ Uncaught error: scala.MatchError: Spread(keyword '...',Some(Loc(8,11,BadSpreads.mls:+42)),Some(IntLit(1))) (of class hkmc2.syntax.Tree$Spread) +//│ /!!!\ Uncaught error: scala.MatchError: Spread(keyword '...',Some(Loc(8,11,BadSpreads.mls:+44)),Some(IntLit(1))) (of class hkmc2.syntax.Tree$Spread) From 0cf2b0040042bb2b3d3a4536fc2eccd49b815dcc Mon Sep 17 00:00:00 2001 From: waterlens Date: Fri, 11 Apr 2025 17:56:26 +0800 Subject: [PATCH 84/88] doc: add comments about builtin class `Lazy` --- hkmc2/shared/src/test/mlscript/llir/Lazy.mls | 3 +++ hkmc2/shared/src/test/mlscript/llir/LazyCycle.mls | 3 +++ hkmc2/shared/src/test/mlscript/llir/nofib/NofibPrelude.mls | 3 +++ 3 files changed, 9 insertions(+) diff --git a/hkmc2/shared/src/test/mlscript/llir/Lazy.mls b/hkmc2/shared/src/test/mlscript/llir/Lazy.mls index da733739cf..d572431986 100644 --- a/hkmc2/shared/src/test/mlscript/llir/Lazy.mls +++ b/hkmc2/shared/src/test/mlscript/llir/Lazy.mls @@ -1,5 +1,8 @@ :llir +// This should ideally be a declaration. +// Now it is a built-in class specially handled in the C++ backend, +// with related logic defined in `mlsprelude.h`. abstract class Lazy[out A](init: () -> A) with fun get: A fun lazy(x) = Lazy(x) diff --git a/hkmc2/shared/src/test/mlscript/llir/LazyCycle.mls b/hkmc2/shared/src/test/mlscript/llir/LazyCycle.mls index 5e0a3a7e1a..cde22032b0 100644 --- a/hkmc2/shared/src/test/mlscript/llir/LazyCycle.mls +++ b/hkmc2/shared/src/test/mlscript/llir/LazyCycle.mls @@ -1,5 +1,8 @@ :llir +// This should ideally be a declaration. +// Now it is a built-in class specially handled in the C++ backend, +// with related logic defined in `mlsprelude.h`. abstract class Lazy[out A](init: () -> A) with fun get: A fun lazy(x) = Lazy(x) diff --git a/hkmc2/shared/src/test/mlscript/llir/nofib/NofibPrelude.mls b/hkmc2/shared/src/test/mlscript/llir/nofib/NofibPrelude.mls index 85af9fb78a..599c2ad7d8 100644 --- a/hkmc2/shared/src/test/mlscript/llir/nofib/NofibPrelude.mls +++ b/hkmc2/shared/src/test/mlscript/llir/nofib/NofibPrelude.mls @@ -7,6 +7,9 @@ abstract class Option[out T]: Some[T] | None data class Some[out T](x: T) extends Option[T] object None extends Option +// This should ideally be a declaration. +// Now it is a built-in class specially handled in the C++ backend, +// with related logic defined in `mlsprelude.h`. abstract class Lazy[out A](init: () -> A) with fun get() fun lazy(x) = Lazy(x) From 4197beae5164a0feec11bd346bac8ea4cf0bef9d Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Wed, 16 Apr 2025 14:33:35 +0800 Subject: [PATCH 85/88] Changes from meeting --- .../mlscript/compiler/codegen/CppAst.scala | 2 +- .../compiler/codegen/CppCompilerHost.scala | 2 +- .../main/scala/hkmc2/codegen/cpp/Ast.scala | 9 +- .../scala/hkmc2/codegen/cpp/CodeGen.scala | 60 +- .../scala/hkmc2/codegen/llir/Analysis.scala | 16 +- .../scala/hkmc2/codegen/llir/Builder.scala | 68 +- .../scala/hkmc2/codegen/llir/Interp.scala | 28 +- .../main/scala/hkmc2/codegen/llir/Llir.scala | 12 +- .../scala/hkmc2/codegen/llir/OldOpt.scala | 1586 ----------------- .../src/test/mlscript/llir/LazyCycle.mls | 42 +- .../src/test/scala/hkmc2/LlirDiffMaker.scala | 2 +- 11 files changed, 119 insertions(+), 1708 deletions(-) delete mode 100644 hkmc2/shared/src/main/scala/hkmc2/codegen/llir/OldOpt.scala diff --git a/compiler/shared/main/scala/mlscript/compiler/codegen/CppAst.scala b/compiler/shared/main/scala/mlscript/compiler/codegen/CppAst.scala index ef054b0268..954a91672e 100644 --- a/compiler/shared/main/scala/mlscript/compiler/codegen/CppAst.scala +++ b/compiler/shared/main/scala/mlscript/compiler/codegen/CppAst.scala @@ -161,7 +161,7 @@ case class CompilationUnit(includes: Ls[Str], decls: Ls[Decl], defs: Ls[Def]): "HiddenTheseEntities", "True", "False", "Callable", "List", "Cons", "Nil", "Option", "Some", "None", "Pair", "Tuple2", "Tuple3", "Nat", "S", "O" ) stack_list(defs.filterNot { - case Def.StructDef(name, _, _, _) => hiddenNames.contains(name.stripPrefix("_mls_")) + case d: Def.StructDef => hiddenNames.contains(d.name.stripPrefix("_mls_")) case _ => false }.map(_.toDocument)) diff --git a/compiler/shared/main/scala/mlscript/compiler/codegen/CppCompilerHost.scala b/compiler/shared/main/scala/mlscript/compiler/codegen/CppCompilerHost.scala index 3897648dbc..4bbfa19b7b 100644 --- a/compiler/shared/main/scala/mlscript/compiler/codegen/CppCompilerHost.scala +++ b/compiler/shared/main/scala/mlscript/compiler/codegen/CppCompilerHost.scala @@ -41,4 +41,4 @@ final class CppCompilerHost(val auxPath: Str): return output("Execution succeeded: ") - for line <- stdout do output(line) \ No newline at end of file + for line <- stdout do output(line) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/Ast.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/Ast.scala index 71fd13203d..d415c8933d 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/Ast.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/Ast.scala @@ -129,7 +129,6 @@ enum Expr: case Unary(op: Str, expr: Expr) case Binary(op: Str, lhs: Expr, rhs: Expr) case Initializer(exprs: Ls[Expr]) - case Constructor(name: Str, init: Expr) def toDocument: Document = def aux(x: Expr): Document = x match @@ -150,8 +149,6 @@ enum Expr: doc"(${lhs.toDocument} $op ${rhs.toDocument})" case Initializer(exprs) => doc"{${Expr.toDocuments(exprs, sep = ", ")}}" - case Constructor(name, init) => - doc"$name(${init.toDocument})" aux(this) case class CompilationUnit(includes: Ls[Str], decls: Ls[Decl], defs: Ls[Def]): @@ -167,7 +164,7 @@ case class CompilationUnit(includes: Ls[Str], decls: Ls[Decl], defs: Ls[Def]): enum Decl: case StructDecl(name: Str) case EnumDecl(name: Str) - case FuncDecl(ret: Type, name: Str, args: Ls[Type], is_override: Bool, is_virtual: Bool) + case FuncDecl(ret: Type, name: Str, args: Ls[Type], isOverride: Bool, isVirtual: Bool) case VarDecl(name: Str, typ: Type) def toDocument: Document = @@ -185,9 +182,9 @@ enum Decl: aux(this) enum Def: - case StructDef(name: Str, fields: Ls[(Str, Type)], inherit: Opt[Ls[Str]], methods: Ls[Def], methods_decl: Ls[Decl]) + case StructDef(name: Str, fields: Ls[(Str, Type)], inherit: Opt[Ls[Str]], methods: Ls[Def], methodsDecl: Ls[Decl]) case EnumDef(name: Str, fields: Ls[(Str, Opt[Int])]) - case FuncDef(specret: Type, name: Str, args: Ls[(Str, Type)], body: Stmt.Block, is_override: Bool, is_virtual: Bool = false, in_scope: Opt[Str]) + case FuncDef(specret: Type, name: Str, args: Ls[(Str, Type)], body: Stmt.Block, isOverride: Bool, isVirtual: Bool = false, in_scope: Opt[Str]) case VarDef(typ: Type, name: Str, init: Opt[Expr]) case RawDef(raw: Str) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/CodeGen.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/CodeGen.scala index 1fc3def999..b3d0e7462c 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/CodeGen.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/CodeGen.scala @@ -12,7 +12,7 @@ import semantics._ class CppCodeGen(builtinClassSymbols: Set[Local], tl: TraceLogger): import tl.{trace, log, logs} - def mapName(name: Str): Str = "_mls_" + name.replace('$', '_').replace('\'', '_') + def mapName(name: Str): Str = "_mls_" + Scope.replaceInvalidCharacters(name) def mapClsLikeName(sym: Local)(using Raise, Scope): Str = if builtinClassSymbols.contains(sym) then sym.nme |> mapName else allocIfNew(sym) @@ -22,12 +22,12 @@ class CppCodeGen(builtinClassSymbols: Set[Local], tl: TraceLogger): val mlsUnitValue = Expr.Call(Expr.Var("_mlsValue::create<_mls_Unit>"), Ls()); val mlsRetValue = "_mls_retval" def mlsRetValType(n: Int) = - if n == 1 then + if n === 1 then mlsValType else Type.Template("std::tuple", Ls.fill(n)(mlsValType)) def mlsRetValueDecl(n: Int) = - if n == 1 then + if n === 1 then Decl.VarDecl(mlsRetValue, mlsValType) else Decl.VarDecl(mlsRetValue, mlsRetValType(n)) @@ -99,41 +99,41 @@ class CppCodeGen(builtinClassSymbols: Set[Local], tl: TraceLogger): summon[Scope].allocateName(l) |> mapName def codegenClassInfo(using Ctx, Raise, Scope)(cls: ClassInfo) = - trace[(Opt[Def], Decl, Ls[Def])](s"codegenClassInfo ${cls.name} begin"): + trace[(Opt[Def], Decl, Ls[Def])](s"codegenClassInfo ${cls.symbol} begin"): val fields = cls.fields.map{x => (x |> directName, mlsValType)} cls.fields.foreach(x => summon[Scope].allocateName(x)) val parents = if cls.parents.nonEmpty then cls.parents.toList.map(mapClsLikeName) else mlsObject :: Nil - val decl = Decl.StructDecl(cls.name |> mapClsLikeName) - if mlsIsInternalClass(cls.name) then (None, decl, Ls.empty) + val decl = Decl.StructDecl(cls.symbol |> mapClsLikeName) + if mlsIsInternalClass(cls.symbol) then (None, decl, Ls.empty) else val methods = cls.methods.map: case (name, defn) => val (cdef, decl) = codegenDefn(using Ctx(summon[Ctx].fieldCtx ++ cls.fields))(defn) val cdef2 = cdef match - case x: Def.FuncDef if builtinApply.contains(defn.name.nme) => x.copy(name = defn.name |> directName, in_scope = Some(cls.name |> mapClsLikeName)) - case x: Def.FuncDef => x.copy(in_scope = Some(cls.name |> mapClsLikeName)) + case x: Def.FuncDef if builtinApply.contains(defn.name.nme) => x.copy(name = defn.name |> directName, in_scope = Some(cls.symbol |> mapClsLikeName)) + case x: Def.FuncDef => x.copy(in_scope = Some(cls.symbol |> mapClsLikeName)) case _ => throw new Exception(s"codegenClassInfo: unexpected def $cdef") val decl2 = decl match - case x: Decl.FuncDecl if builtinApply.contains(defn.name.nme) => x.copy(is_virtual = true, name = defn.name |> directName) - case x: Decl.FuncDecl => x.copy(is_virtual = true) + case x: Decl.FuncDecl if builtinApply.contains(defn.name.nme) => x.copy(isVirtual = true, name = defn.name |> directName) + case x: Decl.FuncDecl => x.copy(isVirtual = true) case _ => throw new Exception(s"codegenClassInfo: unexpected decl $decl") - log(s"codegenClassInfo: ${cls.name} method ${defn.name} $decl2") + log(s"codegenClassInfo: ${cls.symbol} method ${defn.name} $decl2") (cdef2, decl2) val theDef = Def.StructDef( - cls.name |> mapClsLikeName, fields, + cls.symbol |> mapClsLikeName, fields, if parents.nonEmpty then Some(parents) else None, - Ls(Def.RawDef(mlsObjectNameMethod(cls.name.nme)), + Ls(Def.RawDef(mlsObjectNameMethod(cls.symbol.nme)), Def.RawDef(mlsTypeTag()), Def.RawDef(mlsCommonPrintMethod(cls.fields.map(directName))), - Def.RawDef(mlsCommonDestructorMethod(cls.name |> mapClsLikeName, cls.fields.map(directName))), - Def.RawDef(mlsCommonCreateMethod(cls.name |> mapClsLikeName, cls.fields.map(directName), cls.id))), + Def.RawDef(mlsCommonDestructorMethod(cls.symbol |> mapClsLikeName, cls.fields.map(directName))), + Def.RawDef(mlsCommonCreateMethod(cls.symbol |> mapClsLikeName, cls.fields.map(directName), cls.id))), methods.iterator.map(_._2).toList ) (S(theDef), decl, methods.iterator.map(_._1).toList) def toExpr(texpr: TrivialExpr, reifyUnit: Bool = false)(using Ctx, Raise, Scope): Opt[Expr] = texpr match case IExpr.Ref(name) if summon[Ctx].fieldCtx.contains(name) => S(Expr.Var(name |> directName)) - case IExpr.Ref(name: BuiltinSymbol) if name.nme == "" => S(mlsThis) + case IExpr.Ref(name: BuiltinSymbol) if name.nme === "" => S(mlsThis) case IExpr.Ref(name) => S(Expr.Var(name |> allocIfNew)) case IExpr.Literal(hkmc2.syntax.Tree.BoolLit(x)) => S(mlsIntLit(if x then 1 else 0)) case IExpr.Literal(hkmc2.syntax.Tree.IntLit(x)) => S(mlsIntLit(x)) @@ -143,7 +143,7 @@ class CppCodeGen(builtinClassSymbols: Set[Local], tl: TraceLogger): def toExpr(texpr: TrivialExpr)(using Ctx, Raise, Scope): Expr = texpr match case IExpr.Ref(name) if summon[Ctx].fieldCtx.contains(name) => Expr.Var(name |> directName) - case IExpr.Ref(name: BuiltinSymbol) if name.nme == "" => mlsThis + case IExpr.Ref(name: BuiltinSymbol) if name.nme === "" => mlsThis case IExpr.Ref(name) => Expr.Var(name |> allocIfNew) case IExpr.Literal(hkmc2.syntax.Tree.BoolLit(x)) => mlsIntLit(if x then 1 else 0) case IExpr.Literal(hkmc2.syntax.Tree.IntLit(x)) => mlsIntLit(x) @@ -190,13 +190,13 @@ class CppCodeGen(builtinClassSymbols: Set[Local], tl: TraceLogger): def codegenOps(op: BuiltinSymbol, args: Ls[TrivialExpr])(using Ctx, Raise, Scope) = trace[Expr](s"codegenOps $op begin"): var op2 = op.nme - if op2 == "===" then + if op2 === "===" then op2 = "==" - else if op2 == "!===" then + else if op2 === "!===" then op2 = "!=" - if op.binary && args.length == 2 then + if op.binary && args.length === 2 then Expr.Binary(op2, toExpr(args(0)), toExpr(args(1))) - else if op.unary && args.length == 1 then + else if op.unary && args.length === 1 then Expr.Unary(op2, toExpr(args(0))) else TODO(s"codegenOps ${op.nme} ${args.size} ${op.binary} ${op.unary} ${args.map(_.show)}") @@ -241,10 +241,10 @@ class CppCodeGen(builtinClassSymbols: Set[Local], tl: TraceLogger): case Node.LetExpr(name, expr, body) => val stmts2 = stmts ++ Ls(Stmt.AutoBind(Ls(name |> allocIfNew), codegen(expr))) codegen(body, storeInto)(using decls, stmts2) - case Node.LetCall(names, bin: BuiltinSymbol, args, body) if bin.nme == "" => + case Node.LetCall(names, bin: BuiltinSymbol, args, body) if bin.nme === "" => val stmts2 = stmts ++ codegenBuiltin(names, args.head.toString.replace("\"", ""), args.tail) codegen(body, storeInto)(using decls, stmts2) - case Node.LetMethodCall(names, cls, method, IExpr.Ref(bin: BuiltinSymbol) :: args, body) if bin.nme == "" => + case Node.LetMethodCall(names, cls, method, IExpr.Ref(bin: BuiltinSymbol) :: args, body) if bin.nme === "" => val call = mlsThisCall(cls, method |> directName, args.map(toExpr)) val stmts2 = stmts ++ Ls(Stmt.AutoBind(names.map(allocIfNew), call)) codegen(body, storeInto)(using decls, stmts2) @@ -275,23 +275,23 @@ class CppCodeGen(builtinClassSymbols: Set[Local], tl: TraceLogger): // Topological sort of classes based on inheritance relationships def sortClasses(prog: Program)(using Raise, Scope): Ls[ClassInfo] = - var depgraph = prog.classes.map(x => (x.name |> mapClsLikeName, x.parents.map(mapClsLikeName))).toMap - ++ builtinClassSymbols.map(x => (x |> mapClsLikeName, Set.empty[String])) + var depgraph = prog.classes.map(x => (x.symbol, x.parents)).toMap + ++ builtinClassSymbols.map(x => (x, Set.empty[Symbol])) log(s"depgraph: $depgraph") var degree = depgraph.view.mapValues(_.size).toMap - def removeNode(node: Str) = + def removeNode(node: Symbol) = degree -= node depgraph -= node - depgraph = depgraph.view.mapValues(_.filter(_ != node)).toMap + depgraph = depgraph.view.mapValues(_.filter(_ =/= node)).toMap degree = depgraph.view.mapValues(_.size).toMap val sorted = ListBuffer.empty[ClassInfo] - var work = degree.filter(_._2 == 0).keys.toSet + var work = degree.filter(_._2 === 0).keys.toSet while work.nonEmpty do val node = work.head work -= node - prog.classes.find(x => (x.name |> mapClsLikeName) == node).foreach(sorted.addOne) + prog.classes.find(x => (x.symbol) === node).foreach(sorted.addOne) removeNode(node) - val next = degree.filter(_._2 == 0).keys + val next = degree.filter(_._2 === 0).keys work ++= next if depgraph.nonEmpty then val cycle = depgraph.keys.mkString(", ") diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Analysis.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Analysis.scala index f69ddd6f0c..befe5ac59a 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Analysis.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Analysis.scala @@ -2,19 +2,19 @@ package hkmc2 package codegen package llir -import mlscript._ -import mlscript.utils._ -import mlscript.utils.shorthands._ -import semantics.BuiltinSymbol -import syntax.Tree.UnitLit -import semantics.InnerSymbol - -import scala.collection.mutable.ListBuffer import scala.annotation.tailrec import scala.collection.immutable.* +import scala.collection.mutable.ListBuffer import scala.collection.mutable.{HashMap => MutHMap} import scala.collection.mutable.{HashSet => MutHSet, Set => MutSet} +import mlscript._ +import mlscript.utils._ +import mlscript.utils.shorthands._ + +import syntax.Tree.UnitLit +import semantics.{BuiltinSymbol, InnerSymbol} + class UsefulnessAnalysis(verbose: Bool = false): import Expr._ import Node._ diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala index 5c1e9e9a1a..8592dfd090 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Builder.scala @@ -43,9 +43,9 @@ final case class Ctx( class_ctx: Map[MemberSymbol[? <: ClassLikeDef], ClassInfo] = Map.empty, class_sym_ctx: Map[BlockMemberSymbol, MemberSymbol[? <: ClassLikeDef]] = Map.empty, flow_ctx: Map[Path, Local] = Map.empty, - is_top_level: Bool = true, + isTopLevel: Bool = true, method_class: Opt[MemberSymbol[? <: ClassLikeDef]] = None, - builtin_sym: BuiltinSymbols = BuiltinSymbols() + builtinSym: BuiltinSymbols = BuiltinSymbols() ): def addFuncName(n: Local, paramsSize: Int) = copy(fn_ctx = fn_ctx + (n -> FuncInfo(paramsSize))) def findFuncName(n: Local)(using Raise) = fn_ctx.get(n) match @@ -62,11 +62,11 @@ final case class Ctx( case Some(value) => value def addKnownClass(n: Path, m: Local) = copy(flow_ctx = flow_ctx + (n -> m)) def setClass(c: MemberSymbol[? <: ClassLikeDef]) = copy(method_class = Some(c)) - def nonTopLevel = copy(is_top_level = false) + def nonTopLevel = copy(isTopLevel = false) object Ctx: def empty(using Elaborator.State) = - Ctx(ListBuffer.empty, ListBuffer.empty, builtin_sym = BuiltinSymbols( + Ctx(ListBuffer.empty, ListBuffer.empty, builtinSym = BuiltinSymbols( runtimeSym = Some(Elaborator.State.runtimeSymbol) )) @@ -113,28 +113,28 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger, uid: FreshInt): private def newVarSym(name: Str) = VarSymbol(Tree.Ident(name)) private def newFunSym(name: Str) = BlockMemberSymbol(name, Nil) private def newBuiltinSym(name: Str) = BuiltinSymbol(name, false, false, false, false) - private def builtinField(n: Int)(using Ctx) = summon[Ctx].builtin_sym.fieldSym.getOrElseUpdate(n, newVarSym(s"field$n")) - private def builtinApply(n: Int)(using Ctx) = summon[Ctx].builtin_sym.applySym.getOrElseUpdate(n, newFunSym(s"apply$n")) - private def builtinTuple(n: Int)(using Ctx) = summon[Ctx].builtin_sym.tupleSym.getOrElseUpdate(n, newTupleSym(n)) + private def builtinField(n: Int)(using Ctx) = summon[Ctx].builtinSym.fieldSym.getOrElseUpdate(n, newVarSym(s"field$n")) + private def builtinApply(n: Int)(using Ctx) = summon[Ctx].builtinSym.applySym.getOrElseUpdate(n, newFunSym(s"apply$n")) + private def builtinTuple(n: Int)(using Ctx) = summon[Ctx].builtinSym.tupleSym.getOrElseUpdate(n, newTupleSym(n)) private def builtinCallable(using ctx: Ctx) : Local = - ctx.builtin_sym.callableSym match + ctx.builtinSym.callableSym match case None => val sym = newBuiltinSym("Callable") - ctx.builtin_sym.callableSym = Some(sym); + ctx.builtinSym.callableSym = Some(sym); sym case Some(value) => value private def builtinThis(using ctx: Ctx) : Local = - ctx.builtin_sym.thisSym match + ctx.builtinSym.thisSym match case None => val sym = newBuiltinSym("") - ctx.builtin_sym.thisSym = Some(sym); + ctx.builtinSym.thisSym = Some(sym); sym case Some(value) => value private def builtin(using ctx: Ctx) : Local = - ctx.builtin_sym.builtinSym match + ctx.builtinSym.builtinSym match case None => val sym = newBuiltinSym("") - ctx.builtin_sym.builtinSym = Some(sym); + ctx.builtinSym.builtinSym = Some(sym); sym case Some(value) => value @@ -170,7 +170,7 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger, uid: FreshInt): private def bNestedFunDef(e: FunDefn)(k: TrivialExpr => Ctx ?=> Node)(using ctx: Ctx)(using Raise, Scope): Node = val FunDefn(_own, sym, params, body) = e // generate it as a single named lambda expression that may be self-recursing - if params.length == 0 then + if params.length === 0 then bErrStop(msg"Function without arguments not supported: ${params.length.toString}") else val fstParams = params.head @@ -180,8 +180,8 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger, uid: FreshInt): private def bFunDef(e: FunDefn)(using ctx: Ctx)(using Raise, Scope): Func = trace[Func](s"bFunDef begin: ${e.sym}", x => s"bFunDef end: ${x.show}"): val FunDefn(_own, sym, params, body) = e - assert(ctx.is_top_level) - if params.length == 0 then + assert(ctx.isTopLevel) + if params.length === 0 then bErrStop(msg"Function without arguments not supported: ${params.length.toString}") else val paramsList = params.head.params @@ -196,9 +196,9 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger, uid: FreshInt): private def bMethodDef(e: FunDefn)(using ctx: Ctx)(using Raise, Scope): Func = trace[Func](s"bFunDef begin: ${e.sym}", x => s"bFunDef end: ${x.show}"): val FunDefn(_own, sym, params, body) = e - if !ctx.is_top_level then + if !ctx.isTopLevel then bErrStop(msg"Non top-level definition ${sym.nme} not supported") - else if params.length == 0 then + else if params.length === 0 then bErrStop(msg"Function without arguments not supported: ${params.length.toString}") else val paramsList = params.head.params @@ -214,7 +214,7 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger, uid: FreshInt): trace[ClassInfo](s"bClsLikeDef begin", x => s"bClsLikeDef end: ${x.show}"): val ClsLikeDefn( _own, isym, _sym, kind, paramsOpt, auxParams, parentSym, methods, privateFields, publicFields, preCtor, ctor) = e - if !ctx.is_top_level then + if !ctx.isTopLevel then bErrStop(msg"Non top-level definition ${isym.toString()} not supported") else val clsParams = paramsOpt.fold(Nil)(_.paramSyms) @@ -328,7 +328,7 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger, uid: FreshInt): private def bPath(p: Path)(k: TrivialExpr => Ctx ?=> Node)(using ctx: Ctx)(using Raise, Scope) : Node = trace[Node](s"bPath { $p } begin", x => s"bPath end: ${x.show}"): p match - case s @ Select(Value.Ref(sym), Tree.Ident("Unit")) if sym is ctx.builtin_sym.runtimeSym.get => + case s @ Select(Value.Ref(sym), Tree.Ident("Unit")) if sym is ctx.builtinSym.runtimeSym.get => bPath(Value.Lit(Tree.UnitLit(false)))(k) case s @ Select(Value.Ref(cls: ClassSymbol), name) if ctx.method_class.contains(cls) => s.symbol match @@ -387,18 +387,18 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger, uid: FreshInt): val v: Local = newTemp Node.LetExpr(v, Expr.CtorApp(fromMemToClass(sym), args), k(v |> sr)) case Call(s @ Value.Ref(sym), args) => - val v: Local = newTemp - ctx.fn_ctx.get(sym) match - case Some(f) => + val v: Local = newTemp + ctx.fn_ctx.get(sym) match + case Some(f) => + bArgs(args): + case args: Ls[TrivialExpr] => + Node.LetCall(Ls(v), sym, args, k(v |> sr)) + case None => + bPath(s): + case f: TrivialExpr => bArgs(args): case args: Ls[TrivialExpr] => - Node.LetCall(Ls(v), sym, args, k(v |> sr)) - case None => - bPath(s): - case f: TrivialExpr => - bArgs(args): - case args: Ls[TrivialExpr] => - Node.LetMethodCall(Ls(v), builtinCallable, builtinApply(args.length), f :: args, k(v |> sr)) + Node.LetMethodCall(Ls(v), builtinCallable, builtinApply(args.length), f :: args, k(v |> sr)) case Call(Select(Value.Ref(_: TopLevelSymbol), Tree.Ident("builtin")), args) => bArgs(args): case args: Ls[TrivialExpr] => @@ -472,7 +472,7 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger, uid: FreshInt): summon[Ctx].def_acc += jpdef Node.Case(e, casesList, defaultCase) case Return(res, implct) => bResult(res)(x => Node.Result(Ls(x))) - case Throw(Instantiate(Select(Value.Ref(_), ident), Ls(Value.Lit(Tree.StrLit(e))))) if ident.name == "Error" => + case Throw(Instantiate(Select(Value.Ref(_), ident), Ls(Value.Lit(Tree.StrLit(e))))) if ident.name === "Error" => Node.Panic(e) case Label(label, body, rest) => TODO("Label not supported") case Break(label) => TODO("Break not supported") @@ -498,7 +498,7 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger, uid: FreshInt): bBind(S(lhs), rhs, rest)(k)(ct) case AssignField(lhs, nme, rhs, rest) => TODO("AssignField not supported") case Define(fd @ FunDefn(_own, sym, params, body), rest) => - if ctx.is_top_level then + if ctx.isTopLevel then val f = bFunDef(fd) ctx.def_acc += f bBlock(rest)(k)(ct) @@ -527,7 +527,7 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger, uid: FreshInt): b.subBlocks.foldLeft(ctx)((ctx, rest) => registerClasses(rest)(using ctx)) def registerBuiltinClasses(using ctx: Ctx)(using Raise, Scope): Ctx = - ctx.builtin_sym.tupleSym.foldLeft(ctx): + ctx.builtinSym.tupleSym.foldLeft(ctx): case (ctx, (len, sym)) => val c = ClassInfo(uid.make, sym, (0 until len).map(x => builtinField(x)).toList, Set.empty, Map.empty) ctx.class_acc += c @@ -560,7 +560,7 @@ final class LlirBuilder(using Elaborator.State)(tl: TraceLogger, uid: FreshInt): override def applyFunDefn(fun: FunDefn): Unit = val FunDefn(_own, sym, params, body) = fun - if params.length == 0 then + if params.length === 0 then bErrStop(msg"Function without arguments not supported: ${params.length.toString}") ctx2 = ctx2.addFuncName(sym, params.head.params.length) log(s"Define function: ${sym.nme} -> ${ctx2}") diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Interp.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Interp.scala index 7394962cf8..33380a55dd 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Interp.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Interp.scala @@ -41,7 +41,7 @@ class Interpreter(tl: TraceLogger): override def toString: String = import hkmc2.syntax.Tree.* this match - case Class(cls, fields) => s"${cls.name.nme}(${fields.mkString(",")})" + case Class(cls, fields) => s"${cls.symbol.nme}(${fields.mkString(",")})" case Literal(IntLit(lit)) => lit.toString case Literal(BoolLit(lit)) => lit.toString case Literal(DecLit(lit)) => lit.toString @@ -72,8 +72,8 @@ class Interpreter(tl: TraceLogger): case ("/", Li(IntLit(x)), Li(IntLit(y))) => S(Li(IntLit(x / y))) case ("&&", Li(BoolLit(x)), Li(BoolLit(y))) => S(if x && y then getTrue else getFalse) case ("||", Li(BoolLit(x)), Li(BoolLit(y))) => S(if x || y then getTrue else getFalse) - case ("==", Li(IntLit(x)), Li(IntLit(y))) => S(if x == y then getTrue else getFalse) - case ("===", Li(IntLit(x)), Li(IntLit(y))) => S(if x == y then getTrue else getFalse) + case ("==", Li(IntLit(x)), Li(IntLit(y))) => S(if x === y then getTrue else getFalse) + case ("===", Li(IntLit(x)), Li(IntLit(y))) => S(if x === y then getTrue else getFalse) case ("!=", Li(IntLit(x)), Li(IntLit(y))) => S(if x != y then getTrue else getFalse) case ("<=", Li(IntLit(x)), Li(IntLit(y))) => S(if x <= y then getTrue else getFalse) case (">=", Li(IntLit(x)), Li(IntLit(y))) => S(if x >= y then getTrue else getFalse) @@ -110,7 +110,7 @@ class Interpreter(tl: TraceLogger): case Select(name, cls, field) if field.forall(_.isDigit) => val nth = field.toInt ctx.bindingCtx.get(name).toRight(StuckExpr(expr, s"undefined variable $name")).flatMap { - case Value.Class(cls2, xs) if cls == cls2.name => + case Value.Class(cls2, xs) if cls === cls2.symbol => xs.lift(nth) match case Some(x) => R(x) case None => L(StuckExpr(expr, s"unable to find selected field $field")) @@ -119,8 +119,8 @@ class Interpreter(tl: TraceLogger): } case Select(name, cls, field) => ctx.bindingCtx.get(name).toRight(StuckExpr(expr, s"undefined variable $name")).flatMap { - case Value.Class(cls2, xs) if cls == cls2.name => - xs.zip(cls2.fields).find{_._2.nme == field} match + case Value.Class(cls2, xs) if cls === cls2.symbol => + xs.zip(cls2.fields).find{_._2.nme === field} match case Some((x, _)) => R(x) case None => L(StuckExpr(expr, s"unable to find selected field $field")) case Value.Class(cls2, xs) => L(StuckExpr(expr, s"unexpected class $cls2")) @@ -140,10 +140,10 @@ class Interpreter(tl: TraceLogger): x <- eval_t(Ref(assignee): TrivialExpr) y <- eval_t(value) res <- x match - case obj @ Value.Class(cls2, xs) if cls == cls2 => - xs.zip(cls2.fields).find{_._2.nme == field} match + case obj @ Value.Class(cls2, xs) if cls === cls2 => + xs.zip(cls2.fields).find{_._2.nme === field} match case Some((_, _)) => - obj.fields = xs.map(x => if x == obj then y else x) + obj.fields = xs.map(x => if x === obj then y else x) // Ideally, we should return a unit value here, but here we return the assignee value for simplicity. R(obj) case None => L(StuckExpr(expr, s"unable to find selected field $field")) @@ -164,18 +164,18 @@ class Interpreter(tl: TraceLogger): eval_t(scrut) flatMap { case Value.Class(cls, fields) => cases.find { - case (Pat.Class(cls2), _) => cls.name == cls2 + case (Pat.Class(cls2), _) => cls.symbol === cls2 case _ => false } match { case Some((_, x)) => eval(x) case None => default match case S(x) => eval(x) - case N => L(StuckNode(node, s"can not find the matched case, ${cls.name} expected")) + case N => L(StuckNode(node, s"can not find the matched case, ${cls.symbol} expected")) } case Value.Literal(lit) => cases.find { - case (Pat.Lit(lit2), _) => lit == lit2 + case (Pat.Lit(lit2), _) => lit === lit2 case _ => false } match { case Some((_, x)) => eval(x) @@ -197,7 +197,7 @@ class Interpreter(tl: TraceLogger): // But they have different symbols for the method definition. // So, we don't directly use the method symbol to find the method. // Instead, we fallback to use the method name. - cls.methods.find(_._1.nme == method.nme).map(_._2) + cls.methods.find(_._1.nme === method.nme).map(_._2) for ys <- evalArgs(args).flatMap { case (ths @ Value.Class(cls2, xs)) :: args => @@ -228,7 +228,7 @@ class Interpreter(tl: TraceLogger): val Program(classes, defs, entry) = prog given Ctx = Ctx( bindingCtx = Map.empty, - classCtx = classes.map(cls => (cls.name, cls)).toMap, + classCtx = classes.map(cls => (cls.symbol, cls)).toMap, funcCtx = defs.map(func => (func.name, func)).toMap, thisVal = None, ) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Llir.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Llir.scala index 976177db42..bfe1aff914 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Llir.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/Llir.scala @@ -41,7 +41,7 @@ case class Program( def show(hide: Str => Bool = defaultHidden) = toDocument(hide).toString def toDocument(hide: Str => Bool = defaultHidden) : Document = - val t1 = classes.iterator.filterNot(c => hide(c.name.nme)).toArray + val t1 = classes.iterator.filterNot(c => hide(c.symbol.nme)).toArray val t2 = defs.toArray Sorting.quickSort(t1) Sorting.quickSort(t2) @@ -57,23 +57,23 @@ implicit object ClassInfoOrdering extends Ordering[ClassInfo] { case class ClassInfo( id: Int, - name: MemberSymbol[? <: ClassLikeDef], + symbol: MemberSymbol[? <: ClassLikeDef], fields: Ls[VarSymbol], parents: Set[Local], methods: Map[Local, Func], ): override def hashCode: Int = id override def toString: String = - s"ClassInfo($id, $name, [${fields mkString ","}], parents: ${parents mkString ","}, methods:\n${methods mkString ",\n"})" + s"ClassInfo($id, $symbol, [${fields mkString ","}], parents: ${parents mkString ","}, methods:\n${methods mkString ",\n"})" def show = toDocument.toString def toDocument: Document = given Conversion[String, Document] = raw val ext = if parents.isEmpty then "" else " extends " + parents.map(_.nme).mkString(", ") if methods.isEmpty then - doc"class ${name.nme}(${fields.map(docSymWithUid).mkString(",")})$ext" + doc"class ${symbol.nme}(${fields.map(docSymWithUid).mkString(",")})$ext" else - val docFirst = doc"class ${name.nme}(${fields.map(docSymWithUid).mkString(",")})$ext {" + val docFirst = doc"class ${symbol.nme}(${fields.map(docSymWithUid).mkString(",")})$ext {" val docMethods = methods.map { (_, func) => func.toDocument }.toList.mkDocument(doc" # ") val docLast = doc"}" doc"$docFirst #{ # $docMethods #} # $docLast" @@ -81,7 +81,7 @@ case class ClassInfo( class FuncRef(var func: Local): def name: String = func.nme override def equals(o: Any): Bool = o match { - case o: FuncRef => o.name == this.name + case o: FuncRef => o.name === this.name case _ => false } diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/OldOpt.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/OldOpt.scala deleted file mode 100644 index 949b9f5da3..0000000000 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/llir/OldOpt.scala +++ /dev/null @@ -1,1586 +0,0 @@ - -// class Optimizer(fresh: Fresh, fn_uid: FreshInt, class_uid: FreshInt, tag: FreshInt, verbose: Bool = false): -// import Expr._ -// import Node._ -// import Elim._ -// import Intro._ - -// private var split_cache: Opt[SplittingResult] = None - -// private def log(x: Any) = if verbose then println(x) - -// private type ClassCtx = Map[Str, ClassInfo] - -// private def makeClassCtx(classes: Set[ClassInfo]) = classes.map { case c @ ClassInfo(_, name, _) => (name, c) }.toMap - -// private type FieldCtx = Map[Str, (Str, ClassInfo)] - -// private class DestructAnalysis: -// private def f(node: Node): Opt[Name] = node match -// case Result(res) => None -// case Jump(defn, args) => None -// case Case(scrut, cases, default) => Some(scrut) -// case LetExpr(name, expr, body) => f(body) -// case LetCall(names, defn, args, body) => f(body) - -// def isDestructed(node: Node, name: Name) = -// f(node).contains(name) - -// def firstDestructed(node: Node) = -// f(node) - -// private class EliminationAnalysis: -// private case class ElimEnv( -// val defcount: MutHMap[Str, Int], -// val elims: MutHMap[Str, MutHSet[ElimInfo]], -// val defn: Str, -// val visited: MutHSet[Str], -// ) - -// private def addElim(env: ElimEnv, x: Name, elim: Elim, loc: LocMarker) = -// if (env.defcount.getOrElse(x.str, 0) <= 1) -// env.elims.getOrElseUpdate(x.str, MutHSet.empty) += ElimInfo(elim, DefnLocMarker(env.defn, loc)) - -// private def addBackwardElim(env: ElimEnv, x: Name, elim: ElimInfo, loc: LocMarker) = -// if (env.defcount.getOrElse(x.str, 0) <= 1) -// for { -// elim2 <- elim match { -// // If a variable is destructed in the callee, -// // then it is also indirectly destructed by the call to the callee -// case ElimInfo(EDestruct, _) | ElimInfo(EIndirectDestruct, _) => Some(ElimInfo(EIndirectDestruct, DefnLocMarker(env.defn, loc))) -// case ElimInfo(EDirect, _) => None -// case _ => Some(elim) -// } -// _ = env.elims.getOrElseUpdate(x.str, MutHSet.empty).add(elim2) -// } yield () - -// private def addDef(env: ElimEnv, name: Name) = -// env.defcount.update(name.str, env.defcount.getOrElse(name.str, 0) + 1) - -// private def f(env: ElimEnv, x: Name, loc: LocMarker): Unit = -// addElim(env, x, EDirect, loc) - -// private def f(env: ElimEnv, x: TrivialExpr, loc: LocMarker): Unit = x match -// case Ref(name) => f(env, name, loc) -// case _ => - -// private def f(env: ElimEnv, x: Expr, loc: LocMarker): Unit = x match -// case Ref(name) => f(env, name, loc) -// case Literal(lit) => -// case CtorApp(name, args) => args.foreach(f(env, _, loc)) -// case Select(name, cls, field) => addElim(env, name, ESelect(field), loc) -// case BasicOp(name, args) => args.foreach(f(env, _, loc)) - -// private def f(env: ElimEnv, x: Node): Unit = x match -// case Result(res) => res.foreach(f(env, _, x.locMarker)) -// case Jump(defnref, args) => -// args.foreach(f(env, _, x.locMarker)) -// val defn = defnref.expectDefn -// val loc = x.locMarker -// args.zip(defn.newActiveParams).foreach { -// case (Ref(x), ys) => ys.foreach { y => addBackwardElim(env, x, y, loc) } -// case _ => -// } -// if (!env.visited.contains(defn.name)) -// env.visited.add(defn.name) -// defn.params.foreach(addDef(env, _)) -// f(env.copy(defn = defn.name), defn.body) -// case Case(scrut, cases, default) => -// f(env, scrut, x.locMarker) -// addElim(env, scrut, EDestruct, x.locMarker) -// cases.foreach((cls, arm) => f(env, arm)) -// default.foreach(f(env, _)) -// case LetExpr(name, expr, body) => -// f(env, expr, x.locMarker) -// addDef(env, name) -// f(env, body) -// case LetCall(names, defnref, args, body) => -// val loc = x.locMarker -// args.foreach(f(env, _, loc)) -// val defn = defnref.expectDefn -// args.zip(defn.newActiveParams).foreach { -// case (Ref(x), ys) => ys.foreach { y => addBackwardElim(env, x, y, loc) } -// case _ => -// } -// if (!env.visited.contains(defn.name)) -// env.visited.add(defn.name) -// defn.params.foreach(addDef(env, _)) -// f(env.copy(defn = defn.name), defn.body) -// names.foreach(addDef(env, _)) -// f(env, body) - -// def run(x: Program) = -// var changed = true -// while (changed) -// changed = false -// x.defs.foreach { defn => -// val old = defn.newActiveParams -// val env = ElimEnv(MutHMap.empty, MutHMap.empty, defn.name, MutHSet.empty) -// defn.params.foreach(addDef(env, _)) -// f(env, defn.body) -// defn.newActiveParams = defn.params.map { -// param => -// env.elims.get(param.str).getOrElse(MutHSet.empty).toSortedSet -// } -// changed |= (old != defn.newActiveParams) -// } - -// private object IntroductionAnalysis: -// private def combine_intros(xs: Ls[Ls[Opt[Intro]]]): Ls[Opt[Intro]] = -// val xst = xs.transpose -// xst.map { -// ys => -// val z = ys.flatMap { -// case None => Set() -// case Some(IMix(i)) => i -// case Some(i) => Set(i) -// }.toSet -// if z.nonEmpty then Some(IMix(z)) else None -// } -// def getIntro(n: Int, node: Node, intros: Map[Str, Intro]): Ls[Opt[Intro]] = node match -// case Case(scrut, cases, default) => -// val cases_intros = cases.map { -// case (Pat.Class(cls), node) => -// getIntro(n, node, intros + (scrut.str -> ICtor(cls.ident))) -// case (Pat.Lit(_), node) => -// getIntro(n, node, intros) -// } -// default match -// case None => combine_intros(cases_intros) -// case Some(dc) => combine_intros(cases_intros :+ getIntro(n, dc, intros)) -// case Jump(defnref, args) => -// val jpdef = defnref.expectDefn -// jpdef.activeInputs = updateInputInfo(jpdef, intros, args) -// jpdef.activeResults -// case LetCall(resultNames, defnref, args, body) => -// val defn = defnref.expectDefn -// val intros2 = updateIntroInfo(defn, intros, resultNames) -// defn.activeInputs = updateInputInfo(defn, intros, args) -// getIntro(n, body, intros2) -// case LetExpr(name, expr, body) => -// val intros2 = getIntro(expr, intros) match -// case None => intros -// case Some(x) => -// intros + (name.str -> x) -// getIntro(n, body, intros2) -// case Result(res) => -// res.map { x => getIntro(x, intros) } - -// def getIntro(expr: TrivialExpr, intros: Map[Str, Intro]) = expr match -// case Literal(lit) => None -// case Ref(name) => intros.get(name.str) - -// def getIntro(expr: Expr, intros: Map[Str, Intro]): Opt[Intro] = expr match -// case CtorApp(cls, args) => Some(ICtor(cls.ident)) -// case _ => None - -// def getIntro(expr: TrivialExpr): Opt[Intro] = getIntro(expr, Map.empty) -// def getIntro(expr: Expr): Opt[Intro] = getIntro(expr, Map.empty) -// def getIntro(n: Int, node: Node): Ls[Opt[Intro]] = getIntro(n, node, Map.empty) - -// def run(x: Program) = -// var changed = true -// while (changed) -// changed = false -// x.defs.foreach { -// defn => -// val old = defn.activeResults -// defn.activeResults = -// getIntro(defn.resultNum, defn.body, -// defn.specialized.map(bindIntroInfoUsingInput(Map.empty, _, defn.params)) -// .getOrElse(Map.empty)) -// if defn.resultNum != defn.activeResults.length then throw OptimizingError(s"Inconsistent result number for ${defn.name}") -// changed |= old != defn.activeResults -// } - -// private case class PreFunction(val name: Str, val retvals: Ls[Str]): -// override def toString = s"Pre($name, [$retvals])" -// private case class PostFunction(val name: Str, val params: Ls[Str]): -// override def toString = s"Post($name, [$params])" - -// private def bindIntroInfo(intros: Map[Str, Intro], args: Ls[TrivialExpr], params: Ls[Name]) = -// args.zip(params).foldLeft(intros) { -// case (accu, (Ref(Name(arg)), Name(param))) if intros.contains(arg) => accu + (param -> intros(arg)) -// case (accu, _) => accu -// } - -// private def updateIntroInfo(defn: Defn, intros: Map[Str, Intro], xs: Ls[Name]) = -// defn.activeResults.zip(xs).foldLeft(intros) { -// case (intros, (Some(i), name)) => -// intros + (name.str -> i) -// case (intros, _) => intros -// } - -// private def updateIntroInfoAndMaintainMixingIntros(out: MutHMap[Str, Str], defn: Defn, intros: Map[Str, Intro], xs: Ls[Name]) = -// defn.activeResults.zip(xs).foldLeft(intros) { -// case (intros, (Some(i @ IMix(_)), name)) => -// out += (name.str -> defn.name) -// intros + (name.str -> i) -// case (intros, (Some(i), name)) => -// intros + (name.str -> i) -// case (intros, _) => intros -// } - -// private def updateIntroInfoAndMaintainMixingIntros(out: MutHMap[Str, LocMarker], defn: Defn, loc: LocMarker, intros: Map[Str, Intro], xs: Ls[Name]) = -// defn.activeResults.zip(xs).foldLeft(intros) { -// case (intros, (Some(i @ IMix(_)), name)) => -// out += (name.str -> loc) -// intros + (name.str -> i) -// case (intros, (Some(i), name)) => -// intros + (name.str -> i) -// case (intros, _) => intros -// } - -// private def bindIntroInfoUsingInput(intros: Map[Str, Intro], input: Ls[Opt[Intro]], params: Ls[Name]) = -// input.zip(params).foldLeft(intros) { -// case (accu, (Some(i), param)) => -// accu + (param.str -> i) -// case (accu, _) => accu -// } - -// private def updateInputInfo(defn: Defn, intros: Map[Str, Intro], args: Ls[TrivialExpr]) = -// var all_none = true -// val ls = args.map { -// case Ref(Name(arg)) if intros.contains(arg) => all_none = false; Some(intros(arg)) -// case _ => None -// } -// if all_none then defn.activeInputs else defn.activeInputs + ls - - -// private class SplittingTarget( -// val mixing_producer: Map[LocMarker, Str], -// val mixing_consumer: Map[LocMarker, Str], -// val indirect_consumer: Map[LocMarker, IndirectConsumer], -// val known_case: Map[LocMarker, Str], -// val specialize: Map[LocMarker, WrapAndSpecialize], -// ) - -// private case class SplittingResult( -// val targets: SplittingTarget, -// val first_case: Map[Str, DefnLocMarker], -// val specialized_map: Map[Str, Str], -// val pre_map: Map[DefnLocMarker, PreFunction], -// val single_post_map: Map[DefnLocMarker, PostFunction], -// val mutli_post_map: Map[DefnLocMarker, Map[ClassInfo, PostFunction]], -// val pre_defs: Map[Str, Defn], -// val post_defs: Map[Str, Defn], -// val specialized_defs: Map[Str, Defn], -// val overwrite_defs: Map[Str, Defn], -// ): -// def all_defs = pre_defs.values ++ post_defs.values ++ specialized_defs.values -// def overwrite(defs: Set[Defn]) = -// defs.map(x => if overwrite_defs.contains(x.name) then overwrite_defs(x.name) else x) -// def into_cache(g: Program) = -// val new_pre_defs = pre_defs.flatMap((k, v) => g.defs.find(_.name == k).map(x => (k, x))) -// val new_post_defs = post_defs.flatMap((k, v) => g.defs.find(_.name == k).map(x => (k, x))) -// val new_specialized_defs = specialized_defs.flatMap((k, v) => g.defs.find(_.name == k).map(x => (k, x))) -// val new_pre_defs_names = new_pre_defs.keys.toSet -// val new_post_defs_names = new_post_defs.keys.toSet -// val new_specialized_defs_names = new_specialized_defs.keys.toSet -// val new_specialized_map = specialized_map.filter((k, v) => new_specialized_defs_names.contains(v)) -// val new_pre_map = pre_map.filter((k, v) => new_pre_defs_names.contains(v.name)) -// val new_single_post_map = single_post_map.filter((k, v) => new_post_defs_names.contains(v.name)) -// val new_mutli_post_map = mutli_post_map.map { (k, v) => (k, v.filter((k, v) => new_post_defs_names.contains(v.name))) } -// val new_first_case = first_case.filter((k, v) => pre_map.contains(v)) - -// this.copy( -// first_case = new_first_case, -// pre_map = new_pre_map, -// single_post_map = new_single_post_map, -// mutli_post_map = new_mutli_post_map, -// pre_defs = new_pre_defs, -// post_defs = new_post_defs, -// overwrite_defs = Map.empty, -// ) - -// private enum IndirectSplitKind: -// case FirstCase // a pre and multiple posts -// case JumpBeforeCase // a pre -// case CallBeforeCase // a pre and a post -// case AfterCase // a pre and multiple posts - -// private def get_indirect_split_kind(node: Node, loc: LocMarker): Opt[IndirectSplitKind] = -// import IndirectSplitKind._ -// node match -// case Result(res) => None -// case Jump(defn, args) => -// if loc matches node then Some(CallBeforeCase) -// else None -// case Case(scrut, cases, default) => -// if loc matches node then Some(FirstCase) -// else cases.find { (cls, arm) => get_indirect_split_kind(arm, loc).isDefined } match -// case Some(_) => Some(AfterCase) -// case None => None -// case LetExpr(name, expr, body) => get_indirect_split_kind(body, loc) -// case LetCall(xs, defnref, args, body) => -// if loc matches node then Some(CallBeforeCase) -// else get_indirect_split_kind(body, loc) - -// private class FunctionSplitting(prev_sr: Opt[SplittingResult] = None): -// private val first_case = MutHMap[Str, DefnLocMarker]() -// private val specialized_map = MutHMap[Str, Str]() -// private val pre_map = MutHMap[DefnLocMarker, PreFunction]() -// private val single_post_map = MutHMap[DefnLocMarker, PostFunction]() -// private val mutli_post_map = MutHMap[DefnLocMarker, MutHMap[ClassInfo, PostFunction]]() -// private val pre_defs = MutHMap[Str, Defn]() -// private val post_defs = MutHMap[Str, Defn]() -// private val overwrite_defs = MutHMap[Str, Defn]() -// private val specialized_defs = MutHMap[Str, Defn]() -// private val split_memo = MutHSet[DefnLocMarker]() - -// def run(defs: Set[Defn], targets: SplittingTarget): SplittingResult = -// prev_sr match -// case None => -// case Some(value) => -// first_case ++= value.first_case -// pre_map ++= value.pre_map -// single_post_map ++= value.single_post_map -// value.mutli_post_map.foreach((k, v) => mutli_post_map.getOrElseUpdate(k, MutHMap.empty) ++= v) -// pre_defs ++= value.pre_defs -// post_defs ++= value.post_defs -// split_memo ++= value.pre_map.keySet - -// val defs_map = defs.map(x => (x.name, x)).toMap -// targets.mixing_producer.values.foreach { defn_name => -// val defn = defs_map(defn_name) -// split_at_first_case(SplitEnv(defn, n => n, None), defn.body) -// } -// targets.mixing_consumer.values.foreach { defn_name => -// val defn = defs_map(defn_name) -// split_at_first_case(SplitEnv(defn, n => n, None), defn.body) -// } -// targets.indirect_consumer.values.foreach { case IndirectConsumer(defn_name, where, kind) => -// import IndirectSplitKind._ -// val defn = defs_map(defn_name) -// kind match -// case FirstCase => split_at_first_case(SplitEnv(defn, n => n, None), defn.body) -// case JumpBeforeCase | CallBeforeCase => split_at_jump_or_letcall(SplitEnv(defn, n => n, None), defn.body, where.marker) -// case AfterCase => split_at_first_case(SplitEnv(defn, n => n, None), defn.body) -// } -// targets.specialize.values.foreach { case WrapAndSpecialize(defn_name, spec) => -// val defn = defs_map(defn_name) -// val new_defn = Defn( -// name = fresh.make(defn_name + "$O").str, -// resultNum = defn.resultNum, -// params = defn.params, -// id = fn_uid.make, -// body = Jump(DefnRef(Right(defn_name)),defn.params.map(Ref(_))).attachTag(tag), -// specialized = Some(spec), -// ) -// specialized_map.update(defn_name, new_defn.name) -// specialized_defs.update(new_defn.name, new_defn) -// } -// val result = SplittingResult( -// targets = targets, -// first_case = first_case.toMap, specialized_map = specialized_map.toMap, -// pre_map = pre_map.toMap, single_post_map = single_post_map.toMap, -// mutli_post_map = mutli_post_map.map { (k, v) => (k, v.toMap) }.toMap, -// pre_defs = pre_defs.toMap, post_defs = post_defs.toMap, overwrite_defs = overwrite_defs.toMap, -// specialized_defs = specialized_defs.toMap -// ) - -// first_case.clear() -// pre_map.clear() -// single_post_map.clear() -// mutli_post_map.clear() -// split_memo.clear() -// pre_defs.clear() -// post_defs.clear() -// result - -// private case class SplitEnv( -// val defn: Defn, -// val accu: Node => Node, -// val specialize_on: Opt[Ls[Opt[Intro]]], -// ) - -// private def duplicate_and_keep_tags(node: Node): Node = node match -// case Result(res) => Result(res).copyTag(node) -// case Jump(defn, args) => Jump(defn, args).copyTag(node) -// case Case(scrut, cases, default) => Case(scrut, cases map { (cls, arm) => (cls, duplicate_and_keep_tags(arm)) }, default.map(duplicate_and_keep_tags)).copyTag(node) -// case LetExpr(name, expr, body) => LetExpr(name, expr, duplicate_and_keep_tags(body)).copyTag(node) -// case LetCall(names, defn, args, body) => LetCall(names, defn, args, duplicate_and_keep_tags(body)).copyTag(node) - -// private def split_at_jump_or_letcall(env: SplitEnv, node: Node, marker: LocMarker): Opt[DefnLocMarker] = node match -// case Result(res) => None -// case Jump(defnref, args) => -// val defn = env.defn -// val dloc = DefnLocMarker(defn.name, marker) - -// if split_memo.contains(dloc) then return None -// else split_memo.add(dloc) - -// val all_fv = FreeVarAnalysis().run(node) -// val all_fv_list = all_fv.toList -// val fv_retvals = all_fv_list.map { x => Ref(Name(x)) } - -// val pre_body = env.accu(Result(fv_retvals).attachTag(tag)) -// val pre_name = fresh.make(defn.name + "$A") -// val pre_defn = Defn( -// fn_uid.make, -// pre_name.str, -// defn.params, -// all_fv.size, -// None, -// pre_body) -// pre_map.update(dloc, PreFunction(pre_name.str, all_fv_list)) -// pre_defs.update(pre_name.str, pre_defn) - -// val new_names = make_new_names_for_free_variables(all_fv_list) -// val names_map = all_fv_list.zip(new_names).toMap -// val override_defn = -// env.defn.copy(body = -// LetCall(new_names, DefnRef(Right(pre_name.str)), env.defn.params.map(Ref(_)), -// Jump(defnref, args.map { case Ref(Name(x)) => Ref(names_map(x)); case x => x }).attachTag(tag)).attachTag(tag)) -// overwrite_defs.put(defn.name, override_defn).map(x => throw OptimizingError("Unexpected overwrite")) -// Some(dloc) -// case Case(scrut, cases, default) => None -// case LetExpr(name, expr, body) => split_at_jump_or_letcall(env.copy(accu = n => env.accu(LetExpr(name, expr, n).copyTag(node))), body, marker) -// case LetCall(xs, defnref, args, body) if marker matches node => -// val defn = env.defn -// val dloc = DefnLocMarker(defn.name, marker) - -// if split_memo.contains(dloc) then return None -// else split_memo.add(dloc) - -// val bindings_fv = xs.map(_.str) -// val all_fv = FreeVarAnalysis().run(node) -// val all_fv_list = all_fv.toList -// val fv_retvals = all_fv_list.map { x => Ref(Name(x)) } - -// val pre_body = env.accu(Result(fv_retvals).attachTag(tag)) -// val pre_name = fresh.make(defn.name + "$X") -// val pre_defn = Defn( -// fn_uid.make, -// pre_name.str, -// defn.params, -// all_fv.size, -// None, -// pre_body) -// pre_map.update(dloc, PreFunction(pre_name.str, all_fv_list)) -// pre_defs.update(pre_name.str, pre_defn) - -// val post_name = fresh.make(defn.name + "$Y") -// val post_params_list = bindings_fv ++ all_fv.toList -// val post_params = post_params_list.map(Name(_)) -// val new_defn = Defn( -// fn_uid.make, -// post_name.str, -// post_params, -// defn.resultNum, -// None, -// body) -// single_post_map.update(dloc, PostFunction(post_name.str, post_params_list)) -// post_defs.update(post_name.str, new_defn) - -// val new_names = make_new_names_for_free_variables(all_fv_list) -// val names_map = all_fv_list.zip(new_names).toMap -// val new_names_2 = make_new_names_for_free_variables(xs.map(_.str)) -// val names_map_2 = names_map ++ xs.map(_.str).zip(new_names_2).toMap -// val override_defn = -// env.defn.copy(body = -// LetCall(new_names, DefnRef(Right(pre_name.str)), env.defn.params.map(Ref(_)), -// LetCall(new_names_2, defnref, args.map { case Ref(Name(x)) => Ref(names_map(x)); case x => x }, -// Jump(DefnRef(Right(post_name.str)), post_params.map{x => Ref(names_map_2(x.str))}).attachTag(tag)).attachTag(tag)).attachTag(tag)) -// overwrite_defs.put(defn.name, override_defn).map(x => throw OptimizingError("Unexpected overwrite")) -// Some(dloc) -// case LetCall(xs, defnref, args, body) => -// split_at_jump_or_letcall(env.copy(accu = n => env.accu(LetCall(xs, defnref, args, n).copyTag(node))), body, marker) - -// private def split_at_first_case(env: SplitEnv, node: Node): Opt[DefnLocMarker] = node match -// case Result(res) => None -// case Jump(defn, args) => None -// case Case(scrut, cases, default) => -// val defn = env.defn -// val loc = node.locMarker -// val dloc = DefnLocMarker(defn.name, loc) - -// if split_memo.contains(dloc) then return None -// else split_memo.add(dloc) - -// first_case.update(env.defn.name, dloc) - -// val arm_fv = cases.map(x => FreeVarAnalysis().run(x._2)) -// val all_fv = arm_fv.reduce(_ ++ _) + scrut.str -// val all_fv_list = all_fv.toList -// val fv_retvals = all_fv_list.map { x => Ref(Name(x)) } - -// val pre_body = env.accu(Result(fv_retvals).attachTag(tag)) -// val pre_name = fresh.make(defn.name + "$P") -// val pre_defn = Defn( -// fn_uid.make, -// pre_name.str, -// env.defn.params, -// all_fv.size, -// None, -// pre_body) -// pre_map.update(dloc, PreFunction(pre_name.str, all_fv_list)) -// pre_defs.update(pre_name.str, pre_defn) - -// val new_cases = cases.zip(arm_fv).map { -// case ((Pat.Class(cls), body), fv) => -// val post_name = fresh.make(defn.name + "$D") -// val post_params_list = fv.toList -// val post_params = post_params_list.map(Name(_)) -// val new_defn = Defn( -// fn_uid.make, -// post_name.str, -// post_params, -// defn.resultNum, -// None, -// body) -// mutli_post_map -// .getOrElseUpdate(dloc, MutHMap.empty) -// .update(cls, PostFunction(post_name.str, post_params_list)) -// post_defs.update(post_name.str, new_defn) -// (cls, (post_name.str, post_params_list)) -// case _ => ??? -// } - -// val (new_names, scrut_new_name) = make_new_names_for_free_variables(all_fv_list, scrut.str) -// val names_map = all_fv_list.zip(new_names).toMap -// val overwrite_defn = env.defn.copy( -// body = -// LetCall(new_names, DefnRef(Right(pre_name.str)), env.defn.params.map(Ref(_)), -// Case(scrut_new_name.get, new_cases.map { -// case (cls, (post_f, post_params)) => -// (Pat.Class(cls), Jump(DefnRef(Right(post_f)), post_params.map{x => Ref(names_map(x))}).attachTag(tag)) -// }, None).attachTag(tag)).attachTag(tag)) -// overwrite_defs.put(defn.name, overwrite_defn).map(x => throw OptimizingError("Unexpected overwrite")) - -// Some(dloc) -// case LetExpr(name, expr, body) => -// split_at_first_case(env.copy(accu = n => env.accu(LetExpr(name, expr, n).copyTag(node))), body) -// case LetCall(xs, defnref, args, body) => -// split_at_first_case(env.copy(accu = n => env.accu(LetCall(xs, defnref, args, n).copyTag(node))), body) - -// private case class IndirectConsumer(val defn: Str, val where: DefnLocMarker, val kind: IndirectSplitKind) -// private case class WrapAndSpecialize(val defn: Str, val spec: Ls[Opt[Intro]]) - -// private class SplittingTargetAnalysis: -// private val known_case = MutHMap[LocMarker, Str]() -// private val indirect_consumer = MutHMap[LocMarker, IndirectConsumer]() -// private val specialize = MutHMap[LocMarker, WrapAndSpecialize]() -// private val mixing_consumer = MutHMap[LocMarker, Str]() -// private val mixing_producer = MutHMap[LocMarker, Str]() -// private val name_defn_map = MutHMap[Str, LocMarker]() - -// private case class SplitTargetEnv( -// val intros: Map[Str, Intro], -// val defn: Defn, -// val visited: MutHSet[Str], -// ) - -// private def checkTargets(env: SplitTargetEnv, defn: Defn, csloc: DefnLocMarker, args: Ls[TrivialExpr]) = -// val intros = env.intros -// val name = defn.name -// val params = defn.params -// val active = defn.newActiveParams -// val asa: Ls[(Opt[Name], Opt[Intro])] = args.map { -// case Ref(x) => (Some(x), intros.get(x.str)) -// case _ => (None, None) -// } -// asa.zip(params).zip(active).foreach { -// case (((_, Some(ICtor(cls))), param), elims) => -// def aux: Unit = -// for (elim <- elims) -// elim match -// case ElimInfo(EDestruct, _) => -// mixing_consumer += csloc.marker -> name -// if DestructAnalysis().firstDestructed(defn.body) == Some(param) then -// known_case += csloc.marker -> cls -// return -// case ElimInfo(EIndirectDestruct, loc) => -// val split_kind = get_indirect_split_kind(defn.body, loc.marker) -// if split_kind.isDefined then -// indirect_consumer += csloc.marker -> IndirectConsumer(name, loc, split_kind.get) -// if DestructAnalysis().firstDestructed(defn.body) == Some(param) then -// // known_case += csloc.marker -> cls -// return -// case _ => -// aux -// case (((Some(arg), Some(IMix(_))), param), elims) => -// def aux: Unit = -// for (elim <- elims) -// elim match -// case ElimInfo(EDestruct, _) | ElimInfo(EIndirectDestruct, _) => -// name_defn_map.get(arg.str) match -// case Some(loc) => -// val target = ( -// loc match -// case LocMarker.MLetCall(_, defn, _) => defn -// case _ => throw OptimizingError("Unexpected loc marker")) -// mixing_producer += loc -> target -// return -// case None => -// case _ => -// aux -// case _ => -// } -// /* -// val ai = asa.map(_._2) -// if defn.specialized.isEmpty && -// ai.exists{ case Some(ICtor(_)) => true; case _ => false } && -// ai.forall{ case Some(IMix(_)) => false; case _ => true } then -// specialize += csloc.marker -> WrapAndSpecialize(name, ai) -// */ - -// private def f(env: SplitTargetEnv, node: Node): Unit = node match -// case Result(res) => -// case Jump(defnref, args) => -// val dloc = DefnLocMarker(env.defn.name, node.locMarker) -// val defn = defnref.expectDefn -// checkTargets(env, defn, dloc, args) -// case Case(x, cases, default) => -// val dloc = DefnLocMarker(env.defn.name, node.locMarker) -// env.intros.get(x.str) match -// case Some(IMix(_)) => name_defn_map.get(x.str) match -// case Some(loc) => -// mixing_producer += loc -> (loc match -// case LocMarker.MLetCall(_, defn, _) => defn -// case _ => throw OptimizingError("Unexpected loc marker")) -// case None => -// case _ => -// cases foreach { -// case (Pat.Class(cls), arm) => -// val intros2 = env.intros + (x.str -> ICtor(cls.ident)) -// f(env.copy(intros = intros2), arm) -// case (Pat.Lit(_), arm) => -// f(env, arm) -// } -// default foreach { x => f(env, x) } -// case LetExpr(x, e1, e2) => -// val intros = IntroductionAnalysis.getIntro(e1, env.intros).map { y => env.intros + (x.str -> y) }.getOrElse(env.intros) -// f(env.copy(intros = intros), e2) -// case LetCall(xs, defnref, args, e) => -// val defn = defnref.expectDefn -// val dloc = DefnLocMarker(env.defn.name, node.locMarker) -// checkTargets(env, defn, dloc, args) -// val intros2 = updateIntroInfoAndMaintainMixingIntros(name_defn_map, defn, node.locMarker, env.intros, xs) -// f(env.copy(intros = intros2), e) - -// def run(x: Program) = -// x.defs.foreach { defn => -// val env = SplitTargetEnv( -// defn.specialized.map(bindIntroInfoUsingInput(Map.empty, _, defn.params)).getOrElse(Map.empty), -// defn, -// MutHSet.empty) -// f(env, defn.body) -// } -// SplittingTarget(mixing_producer.toMap, mixing_consumer.toMap, indirect_consumer.toMap, known_case.toMap, specialize.toMap) - -// private def recBoundaryMatched(producer: Opt[Int], consumer: Opt[Int]) = -// (producer, consumer) match -// case (Some(_), Some(_)) => false -// case _ => true - -// private def make_new_names_for_free_variables(fvs: Ls[Str]) = -// val new_names = fvs.map { fv => fresh.make } -// new_names - -// private def make_new_names_for_free_variables(fvs: Ls[Str], scrut: Str) = -// var scrut_new_name: Opt[Name] = None -// val new_names = fvs.map { fv => -// val name = fresh.make -// if (scrut == fv) -// scrut_new_name = Some(name) -// name -// } -// (new_names, scrut_new_name) - -// private class SplittingCallSiteReplacement( -// clsctx: ClassCtx, -// split_result: SplittingResult, -// ): -// var changed = false -// private val name_defn_map = MutHMap[Str, LocMarker]() -// private val new_defs = MutHSet[Defn]() -// private var defs = Set.empty[Defn] - -// private val pre_map = split_result.pre_map -// private val single_post_map = split_result.single_post_map -// private val mutli_post_map = split_result.mutli_post_map -// private val first_case = split_result.first_case -// private val specialized_map = split_result.specialized_map - -// private val targets = split_result.targets - -// private case class SubstEnv( -// val intros: Map[Str, Intro], -// val defn: Defn, -// ) - -// private def rebuild_args_from_marker(args: Ls[LocMarker], map: Map[Str, Name]) = -// args.map { -// case LocMarker.MRef(x) => Ref(map(x)) -// case LocMarker.MLit(x) => Literal(x) -// case _ => ??? -// } - -// private def subst_letcall_known_case(env: SubstEnv, sdloc: DefnLocMarker, xs: Ls[Name], as: Ls[TrivialExpr], body: Node, known_case: Str): Node = -// val scrut = sdloc.marker match -// case LocMarker.MCase(scrut, cases, default) => scrut -// case _ => throw OptimizingError("unexpected marker") -// val PreFunction(pre_f, pre_retvals) = pre_map(sdloc) -// val cases = mutli_post_map(sdloc) -// val (new_names, scrut_new_name) = make_new_names_for_free_variables(pre_retvals, scrut) -// val names_map = pre_retvals.zip(new_names).toMap - -// val cls = clsctx(known_case) -// val PostFunction(post_f, post_params) = cases(cls) - -// LetCall(new_names, DefnRef(Right(pre_f)), as, -// LetCall(xs, DefnRef(Right(post_f)), post_params.map{x => Ref(names_map(x))}, -// body).attachTag(tag)).attachTag(tag) - -// private def subst_letcall_mixing_cases(env: SubstEnv, sdloc: DefnLocMarker, xs: Ls[Name], as: Ls[TrivialExpr], body: Node): Node = -// val scrut = sdloc.marker match -// case LocMarker.MCase(scrut, cases, default) => scrut -// case _ => throw OptimizingError("unexpected marker") -// val PreFunction(pre_f, pre_retvals) = pre_map(sdloc) -// val cases = mutli_post_map(sdloc) -// val (new_names, scrut_new_name) = make_new_names_for_free_variables(pre_retvals, scrut) -// val names_map = pre_retvals.zip(new_names).toMap - -// val fv = FreeVarAnalysis().run(body) -// val fv_list = fv.toList - -// val new_jp_name = fresh.make(env.defn.name + "$M") -// val new_jp = Defn( -// fn_uid.make, -// new_jp_name.str, -// fv_list.map(Name(_)), -// env.defn.resultNum, -// None, -// body, -// ) - -// defs += new_jp - -// val new_cases = cases.map { -// case (cls, PostFunction(post_f, post_params)) => -// val new_names_2 = xs.map { _ => fresh.make } -// val names_map_2 = xs.map(_.str).zip(new_names_2).toMap - -// (Pat.Class(cls), -// LetCall(new_names_2, DefnRef(Right(post_f)), post_params.map{x => Ref(names_map(x))}, -// Jump(DefnRef(Right(new_jp.name)), fv_list.map{x => Ref(names_map_2.getOrElse(x, Name(x)))}).attachTag(tag)).attachTag(tag)) -// } - -// val node = LetCall(new_names, DefnRef(Right(pre_f)), as, -// Case(scrut_new_name.get, new_cases.toList, None).attachTag(tag)).attachTag(tag) -// node - -// private def subst_letcall_indirect(env: SubstEnv, ic: IndirectConsumer, xs: Ls[Name], as: Ls[TrivialExpr], body: Node): Node = -// val defn_name = ic.defn -// val kind = ic.kind -// import IndirectSplitKind._ -// kind match -// case FirstCase | AfterCase => -// // it's impossible to have first case here because we have an EIndirectDestruct elim -// subst_letcall_mixing_cases(env, first_case(defn_name), xs, as, body) -// case JumpBeforeCase => -// val (name, args) = ic.where.marker match -// case LocMarker.MJump(name, args) => (name, args) -// case _ => throw OptimizingError("unexpected marker") -// val PreFunction(pre_f, pre_retvals) = pre_map(ic.where) -// val new_names = make_new_names_for_free_variables(pre_retvals) -// val names_map = pre_retvals.zip(new_names).toMap -// LetCall(new_names, DefnRef(Right(pre_f)), as, -// LetCall(xs, DefnRef(Right(name)), rebuild_args_from_marker(args, names_map), -// body).attachTag(tag)).attachTag(tag) -// case CallBeforeCase => -// val (names, defn2, args) = ic.where.marker match -// case LocMarker.MLetCall(names, defn, args) => (names, defn, args) -// case _ => throw OptimizingError("unexpected marker") -// val PreFunction(pre_f, pre_retvals) = pre_map(ic.where) -// val new_names = make_new_names_for_free_variables(pre_retvals) -// val names_map = pre_retvals.zip(new_names).toMap -// val new_names_2 = make_new_names_for_free_variables(names) -// val names_map_2 = names_map ++ names.zip(new_names_2).toMap -// val PostFunction(post_f, post_params) = single_post_map(ic.where) -// val node = LetCall(new_names, DefnRef(Right(pre_f)), as, -// LetCall(new_names_2, DefnRef(Right(defn2)), rebuild_args_from_marker(args, names_map), -// LetCall(xs, DefnRef(Right(post_f)), post_params.map{x => Ref(names_map_2(x))}, body).attachTag(tag)).attachTag(tag)).attachTag(tag) -// node - -// private def subst_jump_known_case(sdloc: DefnLocMarker, as: Ls[TrivialExpr], known_case: Str): Node = -// val scrut = sdloc.marker match -// case LocMarker.MCase(scrut, cases, default) => scrut -// case _ => throw OptimizingError("unexpected marker") -// val PreFunction(pre_f, pre_retvals) = pre_map(sdloc) -// val cases = mutli_post_map(sdloc) -// val (new_names, scrut_new_name) = make_new_names_for_free_variables(pre_retvals, scrut) -// val names_map = pre_retvals.zip(new_names).toMap - -// val cls = clsctx(known_case) -// val PostFunction(post_f, post_params) = cases(cls) - -// LetCall(new_names, DefnRef(Right(pre_f)), as, -// Jump(DefnRef(Right(post_f)), post_params.map{x => Ref(names_map(x))}).attachTag(tag)).attachTag(tag) - -// private def subst_jump_mixing_cases(sdloc: DefnLocMarker, as: Ls[TrivialExpr]): Node = -// val scrut = sdloc.marker match -// case LocMarker.MCase(scrut, cases, default) => scrut -// case _ => throw OptimizingError("unexpected marker") -// val PreFunction(pre_f, pre_retvals) = pre_map(sdloc) -// val cases = mutli_post_map(sdloc) -// val (new_names, scrut_new_name) = make_new_names_for_free_variables(pre_retvals, scrut) -// val names_map = pre_retvals.zip(new_names).toMap -// val new_cases = cases.map { -// case (cls, PostFunction(post_f, post_params)) => ( -// Pat.Class(cls), -// Jump(DefnRef(Right(post_f)), post_params.map{x => Ref(names_map(x))}).attachTag(tag) -// ) -// } -// LetCall(new_names, DefnRef(Right(pre_f)), as, -// Case(scrut_new_name.get, new_cases.toList, None).attachTag(tag)).attachTag(tag) - -// private def subst_jump_indirect(ic: IndirectConsumer, as: Ls[TrivialExpr]) = -// val defn_name = ic.defn -// val kind = ic.kind -// import IndirectSplitKind._ -// kind match -// case FirstCase | AfterCase => -// // it's impossible to have first case here because we have an EIndirectDestruct elim -// subst_jump_mixing_cases(first_case(defn_name), as) -// case JumpBeforeCase => -// val (name, args) = ic.where.marker match -// case LocMarker.MJump(name, args) => (name, args) -// case _ => throw OptimizingError("unexpected marker") -// val PreFunction(pre_f, pre_retvals) = pre_map(ic.where) -// val new_names = make_new_names_for_free_variables(pre_retvals) -// val names_map = pre_retvals.zip(new_names).toMap -// LetCall(new_names, DefnRef(Right(pre_f)), as, -// Jump(DefnRef(Right(name)), rebuild_args_from_marker(args, names_map)).attachTag(tag)).attachTag(tag) -// case CallBeforeCase => -// val (names, defn2, args) = ic.where.marker match -// case LocMarker.MLetCall(names, defn, args) => (names, defn, args) -// case _ => throw OptimizingError("unexpected marker") -// val PreFunction(pre_f, pre_retvals) = pre_map(ic.where) -// val new_names = make_new_names_for_free_variables(pre_retvals) -// val names_map = pre_retvals.zip(new_names).toMap -// val new_names_2 = make_new_names_for_free_variables(names) -// val names_map_2 = names_map ++ names.zip(new_names_2).toMap -// val PostFunction(post_f, post_params) = single_post_map(ic.where) -// LetCall(new_names, DefnRef(Right(pre_f)), as, -// LetCall(new_names_2, DefnRef(Right(defn2)), rebuild_args_from_marker(args, names_map), -// Jump(DefnRef(Right(post_f)), post_params.map{x => Ref(names_map_2(x))}).attachTag(tag)).attachTag(tag)).attachTag(tag) - -// private def f(env: SubstEnv, node: Node): Node = node match -// case Result(res) => node -// case Case(scrut, cases, default) => -// Case(scrut, cases map { -// case (x @ Pat.Class(cls), arm) => -// (x, f(env.copy(intros = env.intros + (scrut.str -> ICtor(cls.ident))), arm)) -// case (x @ Pat.Lit(_), arm) => -// (x, f(env, arm)) -// }, default map { x => f(env, x) }).copyTag(node) -// case LetExpr(x, e1, e2) => -// val intros2 = IntroductionAnalysis.getIntro(e1, env.intros).map { y => env.intros + (x.str -> y) }.getOrElse(env.intros) -// LetExpr(x, e1, f(env.copy(intros = intros2), e2)).copyTag(node) -// case Jump(defnref, args) => -// val dloc = DefnLocMarker(env.defn.name, node.locMarker) -// val defn = defnref.expectDefn -// if targets.indirect_consumer.contains(node.locMarker) then -// changed = true -// val spec = targets.indirect_consumer(node.locMarker) -// subst_jump_indirect(spec, args) -// else if targets.mixing_consumer.contains(node.locMarker) && first_case.contains(targets.mixing_consumer(node.locMarker)) then -// changed = true -// val target = targets.mixing_consumer(node.locMarker) -// if targets.known_case.contains(node.locMarker) then -// subst_jump_known_case(first_case(target), args, targets.known_case(node.locMarker)) -// else -// subst_jump_mixing_cases(first_case(target), args) -// else /* if targets.specialize.contains(node.locMarker) then -// changed = true -// val spec = targets.specialize(node.locMarker) -// val new_defn = specialized_map(spec.defn) -// val new_node = Jump(DefnRef(Right(new_defn)), args).attachTag(tag) -// new_node -// else */ -// node -// case LetCall(names, defnref, args, body) => -// val dloc = DefnLocMarker(env.defn.name, node.locMarker) -// val defn = defnref.expectDefn -// val intros2 = updateIntroInfoAndMaintainMixingIntros(name_defn_map, defn, node.locMarker, env.intros, names) -// if targets.indirect_consumer.contains(node.locMarker) then -// changed = true -// val spec = targets.indirect_consumer(node.locMarker) -// subst_letcall_indirect(env, spec, names, args, body) -// else if targets.mixing_consumer.contains(node.locMarker) && first_case.contains(targets.mixing_consumer(node.locMarker)) then -// changed = true -// val target = targets.mixing_consumer(node.locMarker) -// val new_node = if targets.known_case.contains(node.locMarker) then -// subst_letcall_known_case(env, first_case(target), names, args, body, targets.known_case(node.locMarker)) -// else -// subst_letcall_mixing_cases(env, first_case(target), names, args, body) -// new_node -// else if names.tail.isEmpty && intros2.get(names.head.str).exists(_.isInstanceOf[IMix]) && targets.mixing_producer.contains(node.locMarker) && first_case.contains(targets.mixing_producer(node.locMarker)) then -// changed = true -// val target = targets.mixing_producer(node.locMarker) -// val new_node = subst_letcall_mixing_cases(env, first_case(target), names, args, body) -// new_node -// else if targets.specialize.contains(node.locMarker) then -// changed = true -// val spec = targets.specialize(node.locMarker) -// val new_defn = specialized_map(spec.defn) -// val new_node = LetCall(names, DefnRef(Right(new_defn)), args, body).attachTag(tag) -// new_node -// else -// LetCall(names, defnref, args, f(env.copy(intros = intros2), body)).copyTag(node) -// def run(x: Program) = -// this.defs = Set.empty -// var defs = x.defs.map{ defn => -// val intros = defn.specialized.map(bindIntroInfoUsingInput(Map.empty, _, defn.params)).getOrElse(Map.empty) -// val new_defn = defn.copy(body = f(SubstEnv(intros, defn), defn.body)) -// new_defn -// } -// val main = x.main -// defs = defs ++ this.defs -// resolveDefnRef(main, defs) -// validate(main, defs) -// Program(x.classes, defs, main) - - -// private object Splitting: -// def run(x: Program) = -// val sta = SplittingTargetAnalysis() -// val targets = sta.run(x) -// val fs = FunctionSplitting(split_cache) -// val sr = fs.run(x.defs, targets) -// var y = x.copy(defs = sr.overwrite(x.defs) ++ sr.all_defs) -// resolveDefnRef(y.main, y.defs) -// validate(y.main, y.defs) -// activeAnalyze(y) -// recBoundaryAnalyze(y) -// val clsctx = makeClassCtx(y.classes) -// var changed = true -// while (changed) -// val scsr = SplittingCallSiteReplacement(clsctx, sr) -// y = scsr.run(y) -// resolveDefnRef(y.main, y.defs) -// validate(y.main, y.defs) -// activeAnalyze(y) -// recBoundaryAnalyze(y) -// changed = scsr.changed -// (y, sr) - -// private def splitFunction(prog: Program) = Splitting.run(prog) - -// private class ScalarReplacementTargetAnalysis extends Iterator: -// val ctx = MutHMap[Str, MutHMap[Str, Set[Str]]]() -// var name_map = Map[Str, Str]() -// private var intros = Map.empty[Str, Intro] - -// private def addTarget(name: Str, field: Str, target: Str) = -// ctx.getOrElseUpdate(name, MutHMap()).updateWith(target) { -// case Some(xs) => Some(xs + field) -// case None => Some(Set(field)) -// } - -// private def checkTargets(defn: Defn, intros: Map[Str, Intro], args: Ls[TrivialExpr]) = -// val name = defn.name -// val params = defn.params -// val active = defn.newActiveParams -// args.map { -// case Ref(x) => intros.get(x.str) -// case _ => None -// }.zip(params).zip(active).foreach { -// case ((Some(ICtor(cls)), param), elim) if elim.exists(_.elim.isInstanceOf[ESelect]) && !elim.exists(_.elim == EDirect) => -// elim.foreach { -// case ElimInfo(ESelect(field), _) => addTarget(name, field, param.str) -// case _ => -// } -// case x @ ((_, param), elim) => -// } - -// override def iterate(x: Jump): Unit = x match -// case Jump(defnref, args) => -// val defn = defnref.expectDefn -// checkTargets(defn, intros, args) - -// override def iterate(x: LetExpr): Unit = x match -// case LetExpr(x, e1, e2) => -// intros = IntroductionAnalysis.getIntro(e1, intros).map { y => intros + (x.str -> y) }.getOrElse(intros) -// e2.acceptIterator(this) - -// override def iterate(x: LetCall): Unit = x match -// case LetCall(xs, defnref, as, e) => -// val defn = defnref.expectDefn -// checkTargets(defn, intros, as) -// intros = updateIntroInfo(defn, intros, xs) -// e.acceptIterator(this) - -// override def iterate(x: Case) = x match -// case Case(x, cases, default) => -// cases foreach { -// case (Pat.Class(cls), arm) => -// intros = intros + (x.str -> ICtor(cls.ident)) -// arm.acceptIterator(this) -// case (Pat.Lit(_), arm) => -// arm.acceptIterator(this) -// } -// default foreach { x => x.acceptIterator(this) } - -// override def iterate(defn: Defn): Unit = -// intros = defn.specialized.map(bindIntroInfoUsingInput(Map.empty, _, defn.params)).getOrElse(Map.empty) -// defn.body.acceptIterator(this) - -// override def iterate(x: Program): Unit = -// x.defs.foreach { x => x.acceptIterator(this) } - -// private def sort_targets(fldctx: Map[Str, (Str, ClassInfo)], targets: Set[Str]) = -// val cls = fldctx(targets.head)._2 -// cls.fields.filter(targets.contains(_)) - -// def run(x: Program) = -// x.acceptIterator(this) -// val clsctx = makeClassCtx(x.classes) -// val fldctx = x.classes.flatMap { case ClassInfo(_, name, fields) => fields.map { fld => (fld, (name, clsctx(name))) } }.toMap -// name_map = ctx.map { (k, _) => k -> fresh.make(k + "$S").str }.toMap -// ctx.map { (k, v) => k -> v.map{ (k, v) => (k, sort_targets(fldctx, v)) }.toMap }.toMap - -// private enum ParamSubst: -// case ParamKeep -// case ParamFieldOf(orig: Str, field: Str) - -// import ParamSubst._ - -// private def fieldParamName(name: Str, field: Str) = Name(name + "_" + field) - -// private def fieldParamNames(targets: Map[Str, Ls[Str]]) = -// targets.flatMap { (k, fields) => fields.map { x => fieldParamName(k, x) } } - -// private def paramSubstMap(params: Ls[Name], targets: Map[Str, Ls[Str]]) = -// params.flatMap { -// case x if targets.contains(x.str) => None -// case x => Some(x.str -> ParamKeep) -// }.toMap ++ targets.flatMap { -// (k, fields) => fields.map { x => fieldParamName(k, x).str -> ParamFieldOf(k, x) } -// }.toMap - - -// private def newParams(params: Ls[Name], targets: Map[Str, Ls[Str]]) = -// params.filter(x => !targets.contains(x.str)) ++ fieldParamNames(targets) - -// private class SelectionReplacement(target_params: Set[Str]): -// def run(node: Node): Node = f(node) - -// private def f(node: Node): Node = node match -// case Result(res) => node -// case Jump(defn, args) => node -// case Case(scrut, cases, default) => -// Case(scrut, cases.map { (cls, arm) => (cls, f(arm)) }, default.map(f)).copyTag(node) -// case LetExpr(x, Select(y, cls, field), e2) if target_params.contains(y.str) => -// LetExpr(x, Ref(fieldParamName(y.str, field)), f(e2)).copyTag(node) -// case LetExpr(x, e1, e2) => -// LetExpr(x, e1, f(e2)).copyTag(node) -// case LetCall(names, defn, args, body) => -// LetCall(names, defn, args, f(body)).copyTag(node) - - -// private class ScalarReplacementDefinitionBuilder(name_map: Map[Str, Str], defn_param_map: Map[Str, Map[Str, Ls[Str]]]) extends Iterator: -// var sr_defs = MutHSet[Defn]() -// override def iterate(x: Defn) = -// if (name_map.contains(x.name)) -// val targets = defn_param_map(x.name) -// val new_params = newParams(x.params, targets) -// val new_name = name_map(x.name) -// val new_def = Defn( -// fn_uid.make, -// new_name, -// new_params, -// x.resultNum, -// None, -// SelectionReplacement(targets.keySet).run(x.body), -// ) -// sr_defs.add(new_def) - -// private class ScalarReplacementCallSiteReplacement(defn_map: Map[Str, Str], defn_param_map: Map[Str, Map[Str, Ls[Str]]]): -// var fldctx = Map.empty[Str, (Str, ClassInfo)] - -// private def susbtCallsite(defn: Defn, as: Ls[TrivialExpr], f: (Str, Ls[TrivialExpr]) => Node) = -// val new_name = defn_map(defn.name) -// val targets = defn_param_map(defn.name) -// val param_subst = paramSubstMap(defn.params, targets) -// val new_params = newParams(defn.params, targets) -// val argMap = defn.params.map(_.str).zip(as).toMap - -// val sel_ctx = MutHMap[(Name, Str), Name]() - -// val letlist = new_params.flatMap { -// param => param_subst(param.str) match { -// case ParamKeep => None -// case ParamFieldOf(orig, field) => -// val orig_arg = expectTexprIsRef(argMap(orig)) -// val new_var = fresh.make -// sel_ctx.addOne((orig_arg, field) -> new_var) -// Some((new_var, orig_arg, field)) -// } -// } - -// val new_args: Ls[TrivialExpr] = new_params.map { -// param => param_subst(param.str) match { -// case ParamKeep => argMap(param.str) -// case ParamFieldOf(orig, str) => -// val orig_arg = expectTexprIsRef(argMap(orig)) -// val x = sel_ctx.get((orig_arg, str)).get -// Ref(x) -// } -// } - -// val new_node = f(new_name, new_args) -// letlist.foldRight(new_node) { case ((x, y, field), node) => -// LetExpr(x, Select(y, fldctx(field)._2, field), node).attachTagAs[LetExpr](tag) -// } - -// private def f(node: Node): Node = node match -// case Result(res) => node -// case Jump(defnref, as) => -// val defn = defnref.expectDefn -// if (defn_param_map.contains(defn.name)) -// susbtCallsite(defn, as, (x, y) => Jump(DefnRef(Right(x)), y).copyTag(node)) -// else -// node -// case Case(scrut, cases, default) => -// Case(scrut, cases.map { (cls, arm) => (cls, f(arm)) }, default map f).copyTag(node) -// case LetExpr(name, expr, body) => -// LetExpr(name, expr, f(body)).copyTag(node) -// case LetCall(xs, defnref, as, e) => -// val defn = defnref.expectDefn -// if (defn_param_map.contains(defn.name)) -// susbtCallsite(defn, as, (x, y) => LetCall(xs, DefnRef(Right(x)), y, f(e)).copyTag(node)) -// else -// LetCall(xs, defnref, as, f(e)).copyTag(node) - -// def run(x: Program) = -// val clsctx = makeClassCtx(x.classes) -// fldctx = x.classes.flatMap { case ClassInfo(_, name, fields) => fields.map { fld => (fld, (name, clsctx(name))) } }.toMap -// val y = Program(x.classes, x.defs.map(x => x.copy(body = f(x. body))), f(x.main)) -// resolveDefnRef(y.main, y.defs) -// validate(y.main, y.defs) -// y - -// private def expectTexprIsRef(expr: TrivialExpr): Name = expr match { -// case Ref(name) => name -// case _ => ??? // how is a literal scalar replaced? -// } - -// private class ScalarReplacement: -// def run(x: Program) = -// val srta = ScalarReplacementTargetAnalysis() -// val worklist = srta.run(x) -// val name_map = srta.name_map -// val srdb = ScalarReplacementDefinitionBuilder(name_map, worklist) - -// x.acceptIterator(srdb) - -// val new_defs = x.defs ++ srdb.sr_defs - -// val srcsp = ScalarReplacementCallSiteReplacement(name_map, worklist) -// val y = Program(x.classes, new_defs, x.main) -// srcsp.run(y) - -// def replaceScalar(prog: Program): Program = -// ScalarReplacement().run(prog) - -// private class TrivialBindingSimplification: -// def run(x: Program) = -// val new_defs = x.defs.map(x => { x.copy(body = f(Map.empty, x.body))}) -// resolveDefnRef(x.main, new_defs) -// Program(x.classes, new_defs, x.main) - -// private def f(rctx: Map[Str, TrivialExpr], node: Node): Node = node match -// case Result(res) => Result(res.map(x => f(rctx, x))).copyTag(node) -// case Jump(defn, args) => Jump(defn, args.map(x => f(rctx, x))).copyTag(node) -// case Case(scrut, cases, default) => Case(f(rctx, scrut), cases.map { (cls, arm) => (cls, f(rctx, arm)) }, default.map(f(rctx, _))).copyTag(node) -// case LetExpr(x, Ref(Name(z)), e2) if rctx.contains(z) => -// val rctx2 = rctx + (x.str -> rctx(z)) -// f(rctx2, e2) -// case LetExpr(x, y @ Ref(Name(_)), e2) => -// val rctx2 = rctx + (x.str -> y) -// f(rctx2, e2) -// case LetExpr(x, y @ Literal(_), e2) => -// val rctx2 = rctx + (x.str -> y) -// f(rctx2, e2) -// case LetExpr(x, e1, e2) => -// LetExpr(x, f(rctx, e1), f(rctx, e2)).copyTag(node) -// case LetCall(names, defn, args, body) => -// LetCall(names, defn, args.map(x => f(rctx, x)), f(rctx, body)).copyTag(node) - -// private def f(rctx: Map[Str, TrivialExpr], x: Expr): Expr = x match -// case Ref(name) => f(rctx, x) -// case Literal(lit) => x -// case CtorApp(name, args) => CtorApp(name, args.map(x => f(rctx, x))) -// case Select(name, cls, field) => Select(f(rctx, name), cls, field) -// case BasicOp(name, args) => BasicOp(name, args.map(x => f(rctx, x))) - - -// private def f(rctx: Map[Str, TrivialExpr], y: TrivialExpr): TrivialExpr = y match -// case Ref(Name(x)) if rctx.contains(x) => -// rctx(x) -// case _ => y - -// private def f(rctx: Map[Str, TrivialExpr], z: Name): Name = -// val Name(x) = z -// rctx.get(x) match -// case Some(Ref(yy @ Name(y))) => yy -// case _ => z - -// private class SelectionSimplification: -// var cctx: Map[Str, Map[Str, TrivialExpr]] = Map.empty - -// def run(x: Program) = -// val new_defs = x.defs.map(x => { cctx = Map.empty; x.copy(body = f(x.body)) }) -// resolveDefnRef(x.main, new_defs) -// validate(x.main, new_defs) -// Program(x.classes, new_defs, x.main) - -// private def f(x: Node): Node = x match -// case Result(res) => x -// case Jump(defn, args) => x -// case Case(scrut, cases, default) => Case(scrut, cases map { (cls, arm) => (cls, f(arm)) }, default map f).copyTag(x) -// case LetExpr(name, sel @ Select(y, cls, field), e2) if cctx.contains(y.str) => -// cctx.get(y.str) match -// case Some(m) => -// m.get(field) match -// case Some(v) => -// LetExpr(name, v.toExpr, f(e2)) .copyTag(x) -// case None => -// LetExpr(name, sel, f(e2)).copyTag(x) -// case None => LetExpr(name, sel, f(e2)).copyTag(x) -// case LetExpr(name, y @ CtorApp(cls, args), e2) => -// val m = cls.fields.zip(args).toMap -// cctx = cctx + (name.str -> m) -// LetExpr(name, y, f(e2)).copyTag(x) -// case LetExpr(name, e1, e2) => -// LetExpr(name, e1, f(e2)).copyTag(x) -// case LetCall(names, defn, args, body) => -// LetCall(names, defn, args, f(body)).copyTag(x) - -// private class DestructSimplification: -// var cctx: Map[Str, Str] = Map.empty - -// private def f(x: Node): Node = x match -// case Result(res) => x -// case Jump(defn, args) => x -// case Case(scrut, cases, default) if cctx.contains(scrut.str) => -// cctx.get(scrut.str) match -// case Some(cls) => -// val arm = cases.find{ -// case (Pat.Class(cls2), _) => cls2.ident == cls -// case _ => false -// }.get._2 -// f(arm) -// case None => -// default match -// case Some(arm) => f(arm) -// case None => Case(scrut, cases map { (cls, arm) => (cls, f(arm)) }, None).copyTag(x) -// case Case(scrut, cases, default) => -// Case(scrut, cases map { (cls, arm) => (cls, f(arm)) }, default map f).copyTag(x) -// case LetExpr(name, y @ CtorApp(cls, args), e2) => -// cctx = cctx + (name.str -> cls.ident) -// LetExpr(name, y, f(e2)).copyTag(x) -// case LetExpr(name, e1, e2) => -// LetExpr(name, e1, f(e2)).copyTag(x) -// case LetCall(names, defn, args, body) => -// LetCall(names, defn, args, f(body)).copyTag(x) - -// def run(x: Program) = -// val new_defs = x.defs.map(x => { cctx = Map.empty; x.copy(body = f(x.body)) }) -// resolveDefnRef(x.main, new_defs) -// validate(x.main, new_defs) -// Program(x.classes, new_defs, x.main) - - -// private def argsToStrs(args: Ls[TrivialExpr]) = { -// args.flatMap { -// case Ref(x) => Some(x.str) -// case _ => None -// } -// } - -// private class DeadCodeElimination: -// val defs = MutHMap[Name, Int]() -// var uses = Map[(Name, Int), Int]() - -// private def addDef(x: Name) = -// defs.update(x, defs.getOrElse(x, 0) + 1) - -// private def f(x: Node): Node = x match -// case Result(res) => x -// case Jump(defn, args) => x -// case Case(scrut, cases, default) => Case(scrut, cases map { (cls, arm) => (cls, f(arm)) }, default map f).copyTag(x) -// case LetExpr(name, expr, body) => -// addDef(name) -// val ui = uses.get((name, defs(name))) -// ui match -// case Some(n) => -// LetExpr(name, expr, f(body)).copyTag(x) -// case None => -// f(body) -// case LetCall(names, defn, args, body) => -// names.foreach(addDef) -// val uis = names.map(name => uses.get(name, defs(name))) -// if uis.forall(_.isEmpty) then -// f(body) -// else -// LetCall(names, defn, args, f(body)).copyTag(x) - -// def run(x: Program) = -// val fns = DefRevPostOrdering.ordered(x.main, x.defs) -// val new_fns = fns.map { x => -// defs.clear() -// uses = UsefulnessAnalysis(verbose).run(x) -// x.params.foreach(addDef) -// x.copy(body = f(x.body)) -// }.toSet -// resolveDefnRef(x.main, new_fns) -// validate(x.main, new_fns) -// Program(x.classes, new_fns, x.main) - -// private class RemoveTrivialCallAndJump: -// private def subst_let_expr(le: LetExpr, map: Map[Name, TrivialExpr]): (Ls[(Name, TrivialExpr)], LetExpr) = -// var let_list = Ls[(Name, TrivialExpr)]() -// val new_expr = le.expr.mapName { -// x => map.get(x) match -// case None => x -// case Some(Ref(y)) => y -// case Some(other) => -// val y = fresh.make -// let_list ::= y -> other -// y - -// } -// val kernel = LetExpr(le.name, new_expr, le.body).attachTagAs[LetExpr](tag) -// (let_list, kernel) - -// private def subst_let_expr_to_node(le: LetExpr, map: Map[Name, TrivialExpr]): Node = -// val (rev_let_list, kernel) = subst_let_expr(le, map) -// rev_let_list.foldLeft(kernel) { -// case (accu, (name, value)) => LetExpr(name, value.toExpr, accu).attachTagAs[LetExpr](tag) -// } - -// private def let_list_to_node(let_list: Ls[(Name, TrivialExpr)], node: Node): Node = -// let_list.foldRight(node) { -// case ((name, value), accu) => LetExpr(name, value.toExpr, accu).attachTagAs[LetExpr](tag) -// } - -// private def param_to_arg(param: TrivialExpr, map: Map[Name, TrivialExpr]): TrivialExpr = param match -// case Ref(x) if map.contains(x) => map(x) -// case x: Ref => x -// case x: Literal => x - -// private def params_to_args(params: Ls[TrivialExpr], map: Map[Name, TrivialExpr]): Ls[TrivialExpr] = -// params.map(param_to_arg(_, map)) - -// private def f(x: Node): Node = x match -// case Result(res) => x -// case Jump(defnref, as) => -// val defn = defnref.expectDefn -// val parammap = defn.params.zip(as).toMap -// (defn.specialized.isEmpty, defn.body) match -// case (true, Result(ys)) => -// Result(params_to_args(ys, parammap)).attachTag(tag) -// case (true, Jump(defnref, as2)) => -// val node = let_list_to_node(defn.params.zip(as), Jump(defnref, as2).attachTag(tag)) -// node -// case (true, le @ LetExpr(y, e1, Result(Ref(z) :: Nil))) if y == z => -// val node = subst_let_expr_to_node(le, parammap) -// node -// case (true, LetCall(xs2, defnref2, as2, Result(xs3))) if -// xs2.zip(xs3).forall{ case (x, Ref(y)) => x == y; case _ => false } => -// val node = let_list_to_node( -// defn.params.zip(as), -// LetCall(xs2, defnref2, as2, Result(xs3).attachTag(tag)).attachTag(tag)) -// node -// case _ => x -// case Case(scrut, cases, default) => Case(scrut, cases.map { (cls, arm) => (cls, f(arm)) }, default map f).copyTag(x) -// case LetExpr(name, expr, body) => LetExpr(name, expr, f(body)).copyTag(x) -// case LetCall(xs, defnref, as, e) => -// val defn = defnref.expectDefn -// val parammap = defn.params.zip(as).toMap -// (defn.specialized.isEmpty, defn.body) match -// case (true, Result(ys)) => -// val init = e |> f -// xs.zip(ys).foldRight(init) { -// case ((name, retval), node) => -// LetExpr(name, param_to_arg(retval, parammap).toExpr, node).attachTag(tag) -// } -// case (true, Jump(defnref, as2)) => -// val node = let_list_to_node(defn.params.zip(as), LetCall(xs, defnref, as2, f(e)).attachTag(tag)) -// node -// case (true, le @ LetExpr(y, e1, Result(Ref(z) :: Nil))) if y == z => -// val (let_list, kernel) = subst_let_expr(le, parammap) -// let_list.foldLeft( -// LetExpr(kernel.name, kernel.expr, -// LetExpr(xs.head, Ref(kernel.name), e |> f).attachTag(tag)).attachTag(tag)) { -// case (accu, (name, value)) => LetExpr(name, value.toExpr, accu).attachTag(tag) -// } -// case (true, LetCall(xs2, defnref2, as2, Result(xs3))) if -// xs2.zip(xs3).forall{ case (x, Ref(y)) => x == y; case _ => false } => -// val node = let_list_to_node(defn.params.zip(as), LetCall(xs, defnref2, as2, f(e)).attachTag(tag)) -// node -// case _ => LetCall(xs, defnref, as, e |> f).copyTag(x) - -// def run(x: Program) = -// val new_defs = x.defs.map{ x => { x.copy(body = f(x.body)) }} -// resolveDefnRef(x.main, new_defs) -// validate(x.main, new_defs) -// Program(x.classes, new_defs, x.main) - -// def simplifyProgram(prog: Program): Program = { -// var changed = true -// var s = prog -// while (changed) { -// val ds = DestructSimplification() -// val ss = SelectionSimplification() -// val tbs = TrivialBindingSimplification() -// val rtcj = RemoveTrivialCallAndJump() -// val dce = DeadCodeElimination() -// var sf = s -// sf = ds.run(sf) -// activeAnalyze(sf) -// sf = ss.run(sf) -// activeAnalyze(sf) -// sf = tbs.run(sf) -// activeAnalyze(sf) -// sf = rtcj.run(sf) -// activeAnalyze(sf) -// sf = dce.run(sf) -// activeAnalyze(sf) -// validate(sf.main, sf.defs) -// changed = s.defs != sf.defs -// s = sf -// } -// s -// } - -// def activeAnalyze(prog: Program): Program = -// IntroductionAnalysis.run(prog) -// EliminationAnalysis().run(prog) -// prog - -// def optimize(prog: Program): Program = { -// var g = simplifyProgram(prog) -// g = activeAnalyze(g) -// g = recBoundaryAnalyze(g) - -// val (g2, sr) = splitFunction(g) -// g = g2 -// g = activeAnalyze(g) -// g = recBoundaryAnalyze(g) - -// g = simplifyProgram(g) -// g = activeAnalyze(g) -// g = recBoundaryAnalyze(g) - -// g = replaceScalar(g) -// g = activeAnalyze(g) -// g = recBoundaryAnalyze(g) - -// g = simplifyProgram(g) -// g = activeAnalyze(g) -// g = recBoundaryAnalyze(g) - -// split_cache = Some(sr.into_cache(g)) -// g -// } - -// def recBoundaryAnalyze(prog: Program): Program = -// RecursiveBoundaryAnalysis.run(prog) -// prog - -// private object RecursiveBoundaryAnalysis: -// import Expr._ -// import Node._ -// import Elim._ -// import Intro._ -// var count = 0 -// def run(x: Program, conservative: Bool = false) = -// val ca = CallAnalysis() -// val cg = ca.call_graph(x) -// val sccs = ca.scc() -// var scc_group = Map.empty[Str, Int] -// var scc_group_size = Map.empty[Int, Int] -// sccs.zipWithIndex.foreach { -// (scc, i) => scc.foreach { -// x => -// scc_group += x -> i -// scc_group_size += i -> (scc_group_size.getOrElse(i, 0) + 1) -// }} -// x.defs.foreach { defn => -// val group = scc_group(defn.name) -// val size = scc_group_size(group) -// defn.recBoundary = Some(group) -// if size == 1 && !cg.getOrElse(defn.name, Set.empty).contains(defn.name) then -// defn.recBoundary = None -// } - -// private class CallAnalysis: -// val cg = MutHMap[Str, MutHSet[Str]]() -// private var cur_defn: Opt[Defn] = None - -// private def f(x: Node): Unit = x match -// case Result(res) => -// case Jump(defn, args) => -// if cur_defn.nonEmpty then -// cg.getOrElseUpdate(cur_defn.get.getName, MutHSet.empty) += defn.getName -// case Case(scrut, cases, default) => cases foreach { (cls, arm) => f(arm) }; default foreach f -// case LetExpr(name, expr, body) => f(body) -// case LetCall(names, defn, args, body) => -// if cur_defn.nonEmpty then -// cg.getOrElseUpdate(cur_defn.get.getName, MutHSet.empty) += defn.getName -// f(body) - -// def call_graph(x: Program): Map[Str, Set[Str]] = -// cg.clear() -// cg.addAll(x.defs.map(x => x.getName -> MutHSet.empty)) -// x.defs.foreach{ defn => -// cur_defn = Some(defn) -// f(defn.body) -// cur_defn = None -// } -// cg.map { (k, v) => k -> v.toSet }.toMap - -// def scc(): List[Set[Str]] = -// var cur_index = 0 -// var index = Map.empty[Str, Int] -// var low = Map.empty[Str, Int] -// var stack = Ls[Str]() -// var on_stack = Set.empty[Str] -// var sccs = Ls[Set[Str]]() - -// def f(v: Str): Unit = { -// index += (v -> cur_index) -// low += (v -> cur_index) -// cur_index += 1 -// stack ::= v -// on_stack += v - -// cg.getOrElse(v, MutHSet.empty).foreach { -// w => -// if (!index.contains(w)) { -// f(w) -// low += v -> low(v).min(low(w)) -// } else if (on_stack.contains(w)) { -// low += v -> low(v).min(index(w)) -// } -// } - -// if (low(v) == index(v)) -// val (scc, new_stack) = stack.splitAt(stack.indexOf(v) + 1) -// stack = new_stack -// scc.foreach { x => on_stack -= x } -// sccs ::= scc.toSet -// } - -// cg.keys.foreach { -// x => if (!index.contains(x)) f(x) -// } - -// sccs - - diff --git a/hkmc2/shared/src/test/mlscript/llir/LazyCycle.mls b/hkmc2/shared/src/test/mlscript/llir/LazyCycle.mls index cde22032b0..e007670d9d 100644 --- a/hkmc2/shared/src/test/mlscript/llir/LazyCycle.mls +++ b/hkmc2/shared/src/test/mlscript/llir/LazyCycle.mls @@ -45,10 +45,10 @@ llist(1) //│ #include "mlsprelude.h" //│ struct _mls_Lazy; //│ struct _mls_LzList; +//│ struct _mls_LzCons; +//│ struct _mls_LzNil; //│ struct _mls_Lambda_lambda; //│ struct _mls_Lambda_f; -//│ struct _mls_LzNil; -//│ struct _mls_LzCons; //│ _mlsValue _mls_entry2(); //│ _mlsValue _mls_entry(); //│ _mlsValue _mls_llist(_mlsValue); @@ -65,6 +65,25 @@ llist(1) //│ static _mlsValue create() { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) _mls_LzList; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; return _mlsValue(_mlsVal); } //│ //│ }; +//│ struct _mls_LzCons: public _mls_LzList { +//│ _mlsValue _mls_head; +//│ _mlsValue _mls_tail; +//│ constexpr static inline const char *typeName = "LzCons"; +//│ constexpr static inline uint32_t typeTag = nextTypeTag(); +//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->_mls_head.print(); std::printf(", "); this->_mls_tail.print(); std::printf(")"); } +//│ virtual void destroy() override { _mlsValue::destroy(this->_mls_head); _mlsValue::destroy(this->_mls_tail); operator delete (this, std::align_val_t(_mlsAlignment)); } +//│ static _mlsValue create(_mlsValue _mls_head, _mlsValue _mls_tail) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) _mls_LzCons; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->_mls_head = _mls_head; _mlsVal->_mls_tail = _mls_tail; return _mlsValue(_mlsVal); } +//│ +//│ }; +//│ struct _mls_LzNil: public _mls_LzList { +//│ +//│ constexpr static inline const char *typeName = "LzNil"; +//│ constexpr static inline uint32_t typeTag = nextTypeTag(); +//│ virtual void print() const override { std::printf("%s", typeName); } +//│ virtual void destroy() override { operator delete (this, std::align_val_t(_mlsAlignment)); } +//│ static _mlsValue create() { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) _mls_LzNil; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; return _mlsValue(_mlsVal); } +//│ +//│ }; //│ struct _mls_Lambda_lambda: public _mls_Callable { //│ _mlsValue _mls_lam_arg0; //│ _mlsValue _mls_lam_arg1; @@ -84,25 +103,6 @@ llist(1) //│ static _mlsValue create() { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) _mls_Lambda_f; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; return _mlsValue(_mlsVal); } //│ virtual _mlsValue _mls_apply1(_mlsValue); //│ }; -//│ struct _mls_LzNil: public _mls_LzList { -//│ -//│ constexpr static inline const char *typeName = "LzNil"; -//│ constexpr static inline uint32_t typeTag = nextTypeTag(); -//│ virtual void print() const override { std::printf("%s", typeName); } -//│ virtual void destroy() override { operator delete (this, std::align_val_t(_mlsAlignment)); } -//│ static _mlsValue create() { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) _mls_LzNil; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; return _mlsValue(_mlsVal); } -//│ -//│ }; -//│ struct _mls_LzCons: public _mls_LzList { -//│ _mlsValue _mls_head; -//│ _mlsValue _mls_tail; -//│ constexpr static inline const char *typeName = "LzCons"; -//│ constexpr static inline uint32_t typeTag = nextTypeTag(); -//│ virtual void print() const override { std::printf("%s", typeName); std::printf("("); this->_mls_head.print(); std::printf(", "); this->_mls_tail.print(); std::printf(")"); } -//│ virtual void destroy() override { _mlsValue::destroy(this->_mls_head); _mlsValue::destroy(this->_mls_tail); operator delete (this, std::align_val_t(_mlsAlignment)); } -//│ static _mlsValue create(_mlsValue _mls_head, _mlsValue _mls_tail) { auto _mlsVal = new (std::align_val_t(_mlsAlignment)) _mls_LzCons; _mlsVal->refCount = 1; _mlsVal->tag = typeTag; _mlsVal->_mls_head = _mls_head; _mlsVal->_mls_tail = _mls_tail; return _mlsValue(_mlsVal); } -//│ -//│ }; //│ _mlsValue _mls_j() { //│ _mlsValue _mls_retval; //│ _mls_retval = _mlsValue::create<_mls_Unit>(); diff --git a/hkmc2DiffTests/src/test/scala/hkmc2/LlirDiffMaker.scala b/hkmc2DiffTests/src/test/scala/hkmc2/LlirDiffMaker.scala index 4c8354b1ea..83078051a4 100644 --- a/hkmc2DiffTests/src/test/scala/hkmc2/LlirDiffMaker.scala +++ b/hkmc2DiffTests/src/test/scala/hkmc2/LlirDiffMaker.scala @@ -76,7 +76,7 @@ abstract class LlirDiffMaker extends BbmlDiffMaker: def cppGen(name: String, prog: Program, gen: Bool, show: Bool, run: Bool, write: Opt[Str]): Unit = tl.log(s"Generating $name") if gen || show || run || write.isDefined then - val cpp = CppCodeGen(ctx.builtin_sym.hiddenClasses, tl).codegen(prog) + val cpp = CppCodeGen(ctx.builtinSym.hiddenClasses, tl).codegen(prog) if show then output(s"\n$name:") output(cpp.toDocument.toString) From 99d8b9ad1d0cdd22460c34427163db009513c722 Mon Sep 17 00:00:00 2001 From: waterlens Date: Fri, 18 Apr 2025 13:18:44 +0800 Subject: [PATCH 86/88] misc: avoid running cpp tests --- hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/Ast.scala | 2 +- hkmc2/shared/src/test/mlscript/llir/nofib/atom.mls | 6 ------ hkmc2/shared/src/test/mlscript/llir/nofib/awards.mls | 2 -- hkmc2/shared/src/test/mlscript/llir/nofib/constraints.mls | 6 ------ hkmc2/shared/src/test/mlscript/llir/nofib/scc.mls | 6 ------ hkmc2/shared/src/test/mlscript/llir/nofib/secretary.mls | 6 ------ 6 files changed, 1 insertion(+), 27 deletions(-) diff --git a/hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/Ast.scala b/hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/Ast.scala index d415c8933d..e2218e3295 100644 --- a/hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/Ast.scala +++ b/hkmc2/shared/src/main/scala/hkmc2/codegen/cpp/Ast.scala @@ -184,7 +184,7 @@ enum Decl: enum Def: case StructDef(name: Str, fields: Ls[(Str, Type)], inherit: Opt[Ls[Str]], methods: Ls[Def], methodsDecl: Ls[Decl]) case EnumDef(name: Str, fields: Ls[(Str, Opt[Int])]) - case FuncDef(specret: Type, name: Str, args: Ls[(Str, Type)], body: Stmt.Block, isOverride: Bool, isVirtual: Bool = false, in_scope: Opt[Str]) + case FuncDef(specret: Type, name: Str, args: Ls[(Str, Type)], body: Stmt.Block, isOverride: Bool, isVirtual: Bool, in_scope: Opt[Str]) case VarDef(typ: Type, name: Str, init: Opt[Expr]) case RawDef(raw: Str) diff --git a/hkmc2/shared/src/test/mlscript/llir/nofib/atom.mls b/hkmc2/shared/src/test/mlscript/llir/nofib/atom.mls index 56a63cafca..9ba81686cc 100644 --- a/hkmc2/shared/src/test/mlscript/llir/nofib/atom.mls +++ b/hkmc2/shared/src/test/mlscript/llir/nofib/atom.mls @@ -42,10 +42,4 @@ fun testAtom_nofib(n) = state :: t then stringConcat(show(state), "\n") :: lscomp(t) stringListConcat of lscomp(take_lz(n, runExperiment(testforce, 0.02, 1.0 :: Nil, State(1.0 :: Nil, 0.0 :: Nil)))) -:runWholeCpp -:runWholeCpp testAtom_nofib(20) -//│ -//│ -//│ Execution succeeded: -//│ "1.000000\t\n1.000000\t\n0.999600\t\n0.998800\t\n0.997600\t\n0.996001\t\n0.994002\t\n0.991606\t\n0.988811\t\n0.985620\t\n0.982034\t\n0.978053\t\n0.973679\t\n0.968914\t\n0.963760\t\n0.958218\t\n0.952291\t\n0.945980\t\n0.939288\t\n0.932218\t\n" diff --git a/hkmc2/shared/src/test/mlscript/llir/nofib/awards.mls b/hkmc2/shared/src/test/mlscript/llir/nofib/awards.mls index 9a10765bba..5696241d2e 100644 --- a/hkmc2/shared/src/test/mlscript/llir/nofib/awards.mls +++ b/hkmc2/shared/src/test/mlscript/llir/nofib/awards.mls @@ -68,6 +68,4 @@ fun competitors(i) = fun testAwards_nofib(n) = map(x => print(findallawards(competitors(intMod(x, 100)))), enumFromTo(1, n)) -:runWholeCpp -:silent testAwards_nofib(100) diff --git a/hkmc2/shared/src/test/mlscript/llir/nofib/constraints.mls b/hkmc2/shared/src/test/mlscript/llir/nofib/constraints.mls index 894114a2f3..00cb73aeeb 100644 --- a/hkmc2/shared/src/test/mlscript/llir/nofib/constraints.mls +++ b/hkmc2/shared/src/test/mlscript/llir/nofib/constraints.mls @@ -276,10 +276,4 @@ fun try_(n, algorithm) = listLen(search(algorithm, queens(n))) fun testConstraints_nofib(n) = map(x => try_(n, x), bt :: bm :: bjbt :: bjbt_ :: fc :: Nil) -:runWholeCpp print(testConstraints_nofib(6)) -//│ -//│ -//│ Execution succeeded: -//│ Cons(4, Cons(4, Cons(4, Cons(4, Cons(4, Nil))))) -//│ Unit diff --git a/hkmc2/shared/src/test/mlscript/llir/nofib/scc.mls b/hkmc2/shared/src/test/mlscript/llir/nofib/scc.mls index 1aa585e648..48c4d12f41 100644 --- a/hkmc2/shared/src/test/mlscript/llir/nofib/scc.mls +++ b/hkmc2/shared/src/test/mlscript/llir/nofib/scc.mls @@ -49,10 +49,4 @@ fun testScc_nofib(d) = stronglyConnComp(edges, vertices) -:runWholeCpp print(testScc_nofib(0)) -//│ -//│ -//│ Execution succeeded: -//│ Cons(Cons(1, Nil), Cons(Cons(2, Nil), Cons(Cons(7, Cons(5, Cons(6, Nil))), Cons(Cons(3, Cons(4, Nil)), Nil)))) -//│ Unit diff --git a/hkmc2/shared/src/test/mlscript/llir/nofib/secretary.mls b/hkmc2/shared/src/test/mlscript/llir/nofib/secretary.mls index a995685efe..b17fe12a31 100644 --- a/hkmc2/shared/src/test/mlscript/llir/nofib/secretary.mls +++ b/hkmc2/shared/src/test/mlscript/llir/nofib/secretary.mls @@ -36,10 +36,4 @@ fun testSecretary_nofib(n) = listcomp(enumFromTo(35, 39)) -:runWholeCpp print(testSecretary_nofib(50)) -//│ -//│ -//│ Execution succeeded: -//│ Cons(Float(0.300000), Cons(Float(0.300000), Cons(Float(0.300000), Cons(Float(0.340000), Cons(Float(0.360000), Nil))))) -//│ Unit From cf7e03687c13d4009957a10dd537270f05fc2c57 Mon Sep 17 00:00:00 2001 From: waterlens Date: Fri, 18 Apr 2025 16:09:36 +0800 Subject: [PATCH 87/88] Don't do hack on absolute path --- hkmc2DiffTests/src/test/scala/hkmc2/LlirDiffMaker.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hkmc2DiffTests/src/test/scala/hkmc2/LlirDiffMaker.scala b/hkmc2DiffTests/src/test/scala/hkmc2/LlirDiffMaker.scala index 83078051a4..14d155554b 100644 --- a/hkmc2DiffTests/src/test/scala/hkmc2/LlirDiffMaker.scala +++ b/hkmc2DiffTests/src/test/scala/hkmc2/LlirDiffMaker.scala @@ -82,7 +82,7 @@ abstract class LlirDiffMaker extends BbmlDiffMaker: output(cpp.toDocument.toString) val rPath = os.Path(rootPath) val auxPath = - if rPath.last == "mlscript" then + if rPath.last =/= "shared" then rPath/"hkmc2"/"shared"/"src"/"test"/"mlscript-compile"/"cpp" else rPath/"src"/"test"/"mlscript-compile"/"cpp" From d3f01edb36afbd16665941855d7b1322c920b5c1 Mon Sep 17 00:00:00 2001 From: Lionel Parreaux Date: Tue, 22 Apr 2025 16:58:15 +0800 Subject: [PATCH 88/88] Improve LLIR testing and fix a problem in paths --- .../src/test/scala/hkmc2/LlirDiffMaker.scala | 20 +++++++++---------- .../src/test/scala/hkmc2/Watcher.scala | 7 ++++--- 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/hkmc2DiffTests/src/test/scala/hkmc2/LlirDiffMaker.scala b/hkmc2DiffTests/src/test/scala/hkmc2/LlirDiffMaker.scala index 14d155554b..0c90e8945c 100644 --- a/hkmc2DiffTests/src/test/scala/hkmc2/LlirDiffMaker.scala +++ b/hkmc2DiffTests/src/test/scala/hkmc2/LlirDiffMaker.scala @@ -41,12 +41,14 @@ abstract class LlirDiffMaker extends BbmlDiffMaker: try { op(p) } finally { p.close() } given Elaborator.Ctx = curCtx - - var freshId = FreshInt() - var ctx = codegen.llir.Ctx.empty - val scope = Scope.empty - val wholeProg = ListBuffer.empty[Program] - + + object Llir: // Avoid polluting the namespace + val freshId = FreshInt() + var ctx = codegen.llir.Ctx.empty + val scope = Scope.empty + val wholeProg = ListBuffer.empty[Program] + import Llir.* + def mkWholeProgram: Program = if wholeProg.length == 0 then throw new Exception("No program to make") @@ -81,11 +83,7 @@ abstract class LlirDiffMaker extends BbmlDiffMaker: output(s"\n$name:") output(cpp.toDocument.toString) val rPath = os.Path(rootPath) - val auxPath = - if rPath.last =/= "shared" then - rPath/"hkmc2"/"shared"/"src"/"test"/"mlscript-compile"/"cpp" - else - rPath/"src"/"test"/"mlscript-compile"/"cpp" + val auxPath = rPath/"hkmc2"/"shared"/"src"/"test"/"mlscript-compile"/"cpp" if write.isDefined then printToFile(java.io.File((auxPath / s"${write.get}").toString)): p => p.println(cpp.toDocument.toString) diff --git a/hkmc2DiffTests/src/test/scala/hkmc2/Watcher.scala b/hkmc2DiffTests/src/test/scala/hkmc2/Watcher.scala index 9a9df47c9f..511b999a00 100644 --- a/hkmc2DiffTests/src/test/scala/hkmc2/Watcher.scala +++ b/hkmc2DiffTests/src/test/scala/hkmc2/Watcher.scala @@ -89,15 +89,16 @@ class Watcher(dirs: Ls[File]): val path = os.Path(file.pathAsString) val basePath = path.segments.drop(dirPaths.head.segmentCount).toList.init val relativeName = basePath.map(_ + "/").mkString + path.baseName - val preludePath = os.pwd/os.up/"hkmc2"/"shared"/"src"/"test"/"mlscript"/"decls"/"Prelude.mls" - val predefPath = os.pwd/os.up/"hkmc2"/"shared"/"src"/"test"/"mlscript-compile"/"Predef.mls" + val rootPath = os.pwd/os.up + val preludePath = rootPath/"hkmc2"/"shared"/"src"/"test"/"mlscript"/"decls"/"Prelude.mls" + val predefPath = rootPath/"hkmc2"/"shared"/"src"/"test"/"mlscript-compile"/"Predef.mls" val isModuleFile = path.segments.contains("mlscript-compile") if isModuleFile then given Config = Config.default MLsCompiler(preludePath, outputConsumer => outputConsumer(System.out.println)).compileModule(path) else - val dm = new MainDiffMaker((dirPaths.head/os.up).toString, path, preludePath, predefPath, relativeName): + val dm = new MainDiffMaker(rootPath.toString, path, preludePath, predefPath, relativeName): override def unhandled(blockLineNum: Int, exc: Throwable): Unit = exc.printStackTrace() super.unhandled(blockLineNum, exc)