From 4001e83ed8a12e56e2130cca7a59087b14096d03 Mon Sep 17 00:00:00 2001 From: Philippe Suter <philippe.suter@gmail.com> Date: Mon, 3 Dec 2012 19:46:06 +0100 Subject: [PATCH] First function compiles :) --- src/main/scala/leon/codegen/CodeGen.scala | 14 ---- .../scala/leon/codegen/CodeGenPhase.scala | 43 ++++++++++++ .../scala/leon/codegen/CodeGeneration.scala | 61 ++++++++++++++++++ .../leon/codegen/CompilationEnvironment.scala | 27 ++++++++ .../leon/codegen/CompilationException.scala | 6 ++ .../codegen/purescala/Prog001.scala | 4 +- unmanaged/32/cafebabe_2.9.2-1.2.jar | Bin 495982 -> 496094 bytes 7 files changed, 140 insertions(+), 15 deletions(-) delete mode 100644 src/main/scala/leon/codegen/CodeGen.scala create mode 100644 src/main/scala/leon/codegen/CodeGenPhase.scala create mode 100644 src/main/scala/leon/codegen/CodeGeneration.scala create mode 100644 src/main/scala/leon/codegen/CompilationEnvironment.scala create mode 100644 src/main/scala/leon/codegen/CompilationException.scala diff --git a/src/main/scala/leon/codegen/CodeGen.scala b/src/main/scala/leon/codegen/CodeGen.scala deleted file mode 100644 index 7f84a8976..000000000 --- a/src/main/scala/leon/codegen/CodeGen.scala +++ /dev/null @@ -1,14 +0,0 @@ -package leon -package codegen - -import purescala.Common._ -import purescala.Definitions._ - -object CodeGenPhase extends LeonPhase[Program,CompilationResult] { - val name = "CodeGen" - val description = "Compiles a Leon program into Java methods" - - def run(ctx : LeonContext)(p : Program) : CompilationResult = { - CompilationResult(successful = true) - } -} diff --git a/src/main/scala/leon/codegen/CodeGenPhase.scala b/src/main/scala/leon/codegen/CodeGenPhase.scala new file mode 100644 index 000000000..5c6c0ef16 --- /dev/null +++ b/src/main/scala/leon/codegen/CodeGenPhase.scala @@ -0,0 +1,43 @@ +package leon +package codegen + +import purescala.Common._ +import purescala.Definitions._ + +import cafebabe._ +import cafebabe.ClassFileTypes.U2 +import cafebabe.Flags._ + +object CodeGenPhase extends LeonPhase[Program,CompilationResult] { + val name = "CodeGen" + val description = "Compiles a Leon program into Java methods" + + def run(ctx : LeonContext)(p : Program) : CompilationResult = { + import CodeGeneration._ + + implicit val env = CompilationEnvironment.fromProgram(p) + + val cName = programToClassName(p) + + val cf = new ClassFile(cName, None) + cf.setFlags( + (cf.getFlags | CLASS_ACC_PUBLIC | CLASS_ACC_FINAL).asInstanceOf[U2] + ) + + // This assumes that all functions of a given program get compiled + // as methods of a single class file. + for(funDef <- p.definedFunctions; + (_,mn) <- env.funDefToMethod(funDef)) { + + val m = cf.addMethod( + typeToJVM(funDef.returnType), + mn, + funDef.args.map(a => typeToJVM(a.tpe)) : _* + ) + + CodeGeneration.compileFunDef(funDef, m.codeHandler) + } + + CompilationResult(successful = true) + } +} diff --git a/src/main/scala/leon/codegen/CodeGeneration.scala b/src/main/scala/leon/codegen/CodeGeneration.scala new file mode 100644 index 000000000..3fd57a438 --- /dev/null +++ b/src/main/scala/leon/codegen/CodeGeneration.scala @@ -0,0 +1,61 @@ +package leon +package codegen + +import purescala.Common._ +import purescala.Definitions._ +import purescala.Trees._ +import purescala.TypeTrees._ + +import cafebabe._ +import cafebabe.ByteCodes._ +import cafebabe.AbstractByteCodes._ + +object CodeGeneration { + def programToClassName(p : Program) : String = "Leon$CodeGen$" + p.mainObject.id.uniqueName + + def typeToJVM(tpe : TypeTree)(implicit env : CompilationEnvironment) : String = tpe match { + case Int32Type => "I" + case BooleanType => "Z" + case _ => throw CompilationException("Unsupported type : " + tpe) + } + + // Assumes the CodeHandler has never received any bytecode. + // Generates method body, and freezes the handler at the end. + def compileFunDef(funDef : FunDef, ch : CodeHandler)(implicit env : CompilationEnvironment) { + // TODO, change environment to include args. + mkExpr(funDef.getBody, ch) + + funDef.returnType match { + case Int32Type | BooleanType => + ch << IRETURN + + case other => + throw CompilationException("Unsupported return type : " + other) + } + + ch.freeze + } + + private def mkExpr(e : Expr, ch : CodeHandler)(implicit env : CompilationEnvironment) { + e match { + case IntLiteral(v) => ch << Ldc(v) + case BooleanLiteral(true) => ch << Ldc(1) + case BooleanLiteral(false) => ch << Ldc(0) + + case Plus(l, r) => + mkExpr(l, ch) + mkExpr(r, ch) + ch << IADD + + case Minus(l, r) => + mkExpr(l, ch) + mkExpr(r, ch) + ch << ISUB + + case UMinus(e) => + mkExpr(Minus(IntLiteral(0), e), ch) + + case _ => throw CompilationException("Unsupported expr : " + e) + } + } +} diff --git a/src/main/scala/leon/codegen/CompilationEnvironment.scala b/src/main/scala/leon/codegen/CompilationEnvironment.scala new file mode 100644 index 000000000..1eb9514e1 --- /dev/null +++ b/src/main/scala/leon/codegen/CompilationEnvironment.scala @@ -0,0 +1,27 @@ +package leon +package codegen + +import purescala.Common._ +import purescala.Definitions._ + +abstract class CompilationEnvironment() { + // Should contain: + // - a mapping of function defs to class + method name + // - a mapping of class defs to class names + // - a mapping of class fields to fields + + def funDefToMethod(funDef : FunDef) : Option[(String,String)] +} + +object CompilationEnvironment { + def fromProgram(p : Program) : CompilationEnvironment = { + val className = CodeGeneration.programToClassName(p) + + val fs = p.definedFunctions.filter(_.hasImplementation) + val fPairs : Map[FunDef,String] = fs.map(fd => (fd -> fd.id.uniqueName)).toMap + + new CompilationEnvironment { + def funDefToMethod(funDef : FunDef) = fPairs.get(funDef).map(n => (className, n)) + } + } +} diff --git a/src/main/scala/leon/codegen/CompilationException.scala b/src/main/scala/leon/codegen/CompilationException.scala new file mode 100644 index 000000000..236cc586e --- /dev/null +++ b/src/main/scala/leon/codegen/CompilationException.scala @@ -0,0 +1,6 @@ +package leon +package codegen + +case class CompilationException(msg : String) extends Exception { + override def getMessage = msg +} diff --git a/src/test/resources/regression/codegen/purescala/Prog001.scala b/src/test/resources/regression/codegen/purescala/Prog001.scala index c0eb52647..c0edc779f 100644 --- a/src/test/resources/regression/codegen/purescala/Prog001.scala +++ b/src/test/resources/regression/codegen/purescala/Prog001.scala @@ -1,3 +1,5 @@ object Prog001 { - def plus(x : Int, y : Int) : Int = x + y + def fortyTwo() = 42 + + // def plus(x : Int, y : Int) = x + y } diff --git a/unmanaged/32/cafebabe_2.9.2-1.2.jar b/unmanaged/32/cafebabe_2.9.2-1.2.jar index 57defc82adbd3db0baa2f7bfe33f08f1ee2f9e38..a7f91ed1b7e26933e0b0c657dbd2f240a423dc50 100644 GIT binary patch delta 9454 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 delta 9337 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 KEX2;hzyJWd&5;%W -- GitLab