Commit fed64c22 authored by Eva Darulova's avatar Eva Darulova
Browse files

code generation for different float types

parent 8b7ef425
......@@ -6,3 +6,4 @@ rawdata/*
.ensime*
/daisy
last.log
output/*.scala
......@@ -25,6 +25,7 @@ object Main {
//ParamOptionDef("timeout", "Timeout in ms.", "1000"),
ListOptionDef("debug", "For which sections to print debug info.",
List("analysis","solver")),
FlagOptionDef("codegen", "Generate code (as opposed to just doing analysis."),
optionFunctions,
optionPrintToughSMTCalls
)
......@@ -162,16 +163,18 @@ object Main {
private def computePipeline(ctx: Context): Pipeline[Program, Program] = {
// this is not ideal, using 'magic' strings
val dynamicF = ctx.hasFlag("dynamic")
if (dynamicF) {
if (ctx.hasFlag("dynamic")) {
analysis.SpecsProcessingPhase andThen
analysis.DynamicPhase
} else {
} else if (ctx.hasFlag("codegen")) {
analysis.SpecsProcessingPhase andThen
analysis.RangeErrorPhase andThen
InfoPhase andThen
backend.CodeGenerationPhase
} else {
analysis.SpecsProcessingPhase andThen
analysis.RangeErrorPhase andThen
InfoPhase
}
}
......
......@@ -84,7 +84,7 @@ object RangeErrorPhase extends DaisyPhase with ErrorFunctions {
case "Fixed64" =>
uniformPrecision = Fixed(64)
case _ =>
reporter.warning(s"Unknown precision specified: $s, choosing default (Float64)!")
reporter.warning(s"Unknown precision specified: $s, choosing default ($uniformPrecision)!")
}
case _ =>
}
......
......@@ -3,47 +3,106 @@ package daisy
package backend
import daisy.lang.{ScalaPrinter, PrettyPrinter}
import lang.Trees.Program
import lang.Trees._
import utils.FinitePrecision._
import lang.Types._
import lang.Extractors.ArithOperator
object CodeGenerationPhase extends DaisyPhase {
override val name = "Codegen"
override val description = "Generates code."
override val name = "codegen"
override val description = "Generates (executable) code."
// TODO: have this generate C code
override val definedOptions: Set[CmdLineOptionDef[Any]] = Set(
FlagOptionDef("printToFile", "print generated code to file")
)
override val definedOptions: Set[CmdLineOptionDef[Any]] = Set()
implicit val debugSection = DebugSectionBackend
def run(ctx: Context, prg: Program): (Context, Program) = {
var printToFile = false
var uniformPrecision: Precision = Float64
/* Process relevant options */
for (opt <- ctx.options) opt match {
case FlagOption("printToFile") => printToFile = true
// this option is defined in RangeErrorPhase. This is not ideal,
// but since for now, Codegen will only be called after RangeErrorPhase
// it should be OK for now.
case ChoiceOption("precision", s) => s match {
case "Float32" => uniformPrecision = Float32
case "Float64" => uniformPrecision = Float64
case "DoubleDouble" => uniformPrecision = DoubleDouble
case "QuadDouble" => uniformPrecision = QuadDouble
case "Fixed16" => uniformPrecision = Fixed(16)
case "Fixed32" => uniformPrecision = Fixed(32)
case "Fixed64" => uniformPrecision = Fixed(64)
case _ =>
ctx.reporter.warning(s"Unknown precision specified: $s, choosing default ($uniformPrecision)!")
}
case _ => ;
}
// TODO: why is this here?
def writeScalaFile(filename: String) {
import java.io.FileWriter
import java.io.BufferedWriter
val fstream = new FileWriter(filename)
val out = new BufferedWriter(fstream)
out.write(ScalaPrinter.apply(prg))
out.close
}
//println(ScalaPrinter.apply(prg))
if (printToFile){
val fileLocation = "./output/" + prg.id + ".scala"
ctx.reporter.info("Generated code: " + fileLocation)
writeScalaFile(fileLocation)
uniformPrecision match {
// if we have fixed-point code, we need to generate it first
case Fixed(b) =>
throw new Exception("unsupported yet")
// if we have floating-point code, we need to just change the types
case _ =>
val fileLocation = "./output/" + prg.id + ".scala"
ctx.reporter.info("generating code in " + fileLocation)
val typedPrg = assignFloatType(prg, FinitePrecisionType(uniformPrecision))
writeScalaFile(fileLocation, typedPrg)
}
(ctx, prg)
}
private def writeScalaFile(filename: String, prg: Program) {
import java.io.FileWriter
import java.io.BufferedWriter
val fstream = new FileWriter(filename)
val out = new BufferedWriter(fstream)
out.write(ScalaPrinter.apply(prg))
out.close
}
private def assignFloatType(prg: Program, tpe: FinitePrecisionType): Program = {
def changeType(e: Expr): Expr = e match {
case Variable(id) => Variable(id.changeType(tpe))
case x @ RealLiteral(r) =>
val tmp = FinitePrecisionLiteral(r, tpe.prec)
tmp.stringValue = x.stringValue
tmp
case ArithOperator(args, recons) =>
recons(args.map(changeType))
case Let(id, value, body) =>
Let(id.changeType(tpe), changeType(value), changeType(body))
}
val newDefs = prg.defs.map({
case FunDef(id, returnType, params, pre, body, post, isField) =>
FunDef(id, tpe,
params.map(vd => ValDef(vd.id.changeType(tpe))),
// this should really be changed too
pre,
body.map(changeType(_)),
post,
isField
)
})
Program(prg.id, newDefs)
}
}
......@@ -65,6 +65,10 @@ object Identifiers {
// keeps identifier intact
def deepCopy: Identifier = this
def changeType(newTpe: TypeTree): Identifier = {
new Identifier(this.name, this.globalId, this.id, newTpe, this.alwaysShowUniqueID)
}
}
class UniqueCounter[K] {
......
......@@ -14,6 +14,7 @@ import scala.collection.immutable.Seq
import Trees._
import Types._
import Identifiers._
import utils.FinitePrecision._
object PrettyPrinter {
......@@ -140,6 +141,10 @@ class PrettyPrinter(val sb: StringBuffer = new StringBuffer, printUniqueIds: Boo
case BooleanLiteral(v) => sb.append(v)
case UnitLiteral() => sb.append("()")
case RealLiteral(r) => sb.append(r.toString)
case x @ FinitePrecisionLiteral(r, Float32) =>
sb.append(x.stringValue + "f")
case x @ FinitePrecisionLiteral(r, _) =>
sb.append(x.stringValue)
case FunctionInvocation(fdId, _, args, _) =>
pp(fdId, p)
......@@ -182,6 +187,10 @@ class PrettyPrinter(val sb: StringBuffer = new StringBuffer, printUniqueIds: Boo
case Int32Type => sb.append("Int")
case BooleanType => sb.append("Boolean")
case RealType => sb.append("Real")
case FinitePrecisionType(Float32) => sb.append("Float")
case FinitePrecisionType(Float64) => sb.append("Double")
case FinitePrecisionType(DoubleDouble) => sb.append("DoubleDouble")
case FinitePrecisionType(QuadDouble) => sb.append("QuadDouble")
case FunctionType(fts, tt) =>
if (fts.size > 1) {
ppNary(fts, "(", ", ", ")")
......
......@@ -36,8 +36,12 @@ class ScalaPrinter extends PrettyPrinter {
case Not(Equals(l, r)) => ppBinary(l, r, " != ") // \neq
case Not(expr) => ppUnary(expr, "!(", ")") // \neg
// TODO: support the other types too
case RealType => sb.append("Double")
// this should never be called by this printer, i.e. all RealTypes
// should have been transformed before
case RealType =>
throw new Exception("RealType found in ScalaPrinter")
case Program(id, defs) =>
assert(lvl == 0)
......
......@@ -16,6 +16,7 @@ import Types._
import utils.Positioned
import Identifiers._
import utils.Rational
import utils.FinitePrecision.Precision
object Trees {
......@@ -284,6 +285,25 @@ object Trees {
}
}
case class FinitePrecisionLiteral(value: Rational, prec: Precision) extends Literal[Rational] with NumAnnotation {
val getType = FinitePrecisionType(prec)
private var _stringValue: String = null
def stringValue_=(s: String): Unit = {
if (_stringValue == null) {
_stringValue = s
} else {
throw new Exception("'stringValue' is a write-only-once field, but you tried twice!")
}
}
def stringValue = _stringValue
def deepCopy = {
val tmp = FinitePrecisionLiteral(value, prec)
tmp.stringValue = this.stringValue
tmp
}
}
/* Propositional logic */
......@@ -370,12 +390,8 @@ object Trees {
case class Plus(lhs: Expr, rhs: Expr) extends Expr with NumAnnotation {
assert(lhs.getType == rhs.getType)
// this does not hold for function calls
//assert(lhs.isInstanceOf[NumAnnotation] && rhs.isInstanceOf[NumAnnotation])
val getType = {
if (lhs.getType == RealType) RealType
else if (lhs.getType == IntegerType) IntegerType
else Untyped
}
assert(lhs.isInstanceOf[NumAnnotation] && rhs.isInstanceOf[NumAnnotation])
val getType = lhs.getType
def deepCopy = Plus(lhs.deepCopy, rhs.deepCopy)
}
......@@ -383,22 +399,14 @@ object Trees {
case class Minus(lhs: Expr, rhs: Expr) extends Expr with NumAnnotation {
assert(lhs.getType == rhs.getType)
assert(lhs.isInstanceOf[NumAnnotation] && rhs.isInstanceOf[NumAnnotation])
val getType = {
if (lhs.getType == RealType) RealType
else if (lhs.getType == IntegerType) IntegerType
else Untyped
}
val getType = lhs.getType
def deepCopy = Minus(lhs.deepCopy, rhs.deepCopy)
}
/** $encodingof `- ... for BigInts`*/
case class UMinus(expr: Expr) extends Expr with NumAnnotation {
assert(expr.isInstanceOf[NumAnnotation])
val getType = {
if (expr.getType == RealType) RealType
else if (expr.getType == IntegerType) IntegerType
else Untyped
}
val getType = expr.getType
def deepCopy = UMinus(expr.deepCopy)
}
......@@ -406,23 +414,15 @@ object Trees {
case class Times(lhs: Expr, rhs: Expr) extends Expr with NumAnnotation {
assert(lhs.getType == rhs.getType)
assert(lhs.isInstanceOf[NumAnnotation] && rhs.isInstanceOf[NumAnnotation])
val getType = {
if (lhs.getType == RealType) RealType
else if (lhs.getType == IntegerType) IntegerType
else Untyped
}
val getType = lhs.getType
def deepCopy = Times(lhs.deepCopy, rhs.deepCopy)
}
/** $encodingof `... / ...` */
case class Division(lhs: Expr, rhs: Expr) extends Expr with NumAnnotation {
assert(lhs.getType == rhs.getType)
assert(lhs.getType == rhs.getType, "lhs: " + lhs.getType + ", " + rhs.getType)
assert(lhs.isInstanceOf[NumAnnotation] && rhs.isInstanceOf[NumAnnotation])
val getType = {
if (lhs.getType == RealType) RealType
else if (lhs.getType == IntegerType) IntegerType
else Untyped
}
val getType = lhs.getType
def deepCopy = Division(lhs.deepCopy, rhs.deepCopy)
}
......@@ -439,7 +439,8 @@ object Trees {
case class Sqrt(t: Expr) extends Expr with NumAnnotation {
require(t.getType == RealType)
assert(t.isInstanceOf[NumAnnotation])
val getType = RealType
// TODO: this operation may not be available for Float32
val getType = t.getType
def deepCopy = Sqrt(t.deepCopy)
}
......
......@@ -10,6 +10,7 @@ package daisy
package lang
import scala.collection.immutable.Seq
import utils.FinitePrecision.Precision
import Trees._
......@@ -52,6 +53,7 @@ object Types {
case object IntegerType extends TypeTree
case object Int32Type extends TypeTree
case object RealType extends TypeTree
case class FinitePrecisionType(prec: Precision) extends TypeTree
case class FunctionType(from: Seq[TypeTree], to: TypeTree) extends TypeTree
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment