From f956f924f43de7bb0434b805e9dea102bf693178 Mon Sep 17 00:00:00 2001 From: Regis Blanc <regwblanc@gmail.com> Date: Tue, 12 Jan 2016 19:14:48 +0100 Subject: [PATCH] working standalone but not in scalatest --- .../scala/leon/xlang/AntiAliasingPhase.scala | 195 ++++++++++-------- .../xlang/ImperativeCodeElimination.scala | 2 +- 2 files changed, 106 insertions(+), 91 deletions(-) diff --git a/src/main/scala/leon/xlang/AntiAliasingPhase.scala b/src/main/scala/leon/xlang/AntiAliasingPhase.scala index e6466d799..28f1ad9c6 100644 --- a/src/main/scala/leon/xlang/AntiAliasingPhase.scala +++ b/src/main/scala/leon/xlang/AntiAliasingPhase.scala @@ -21,111 +21,94 @@ object AntiAliasingPhase extends TransformationPhase { override def apply(ctx: LeonContext, pgm: Program): Program = { - var updatedFunctions: Map[FunDef, (FunDef, Seq[ValDef])] = Map() + var updatedFunctions: Map[FunDef, FunDef] = Map() - println("effects: " + effectsAnalysis(pgm).filter(p => p._2.size > 0).map(p => p._1.id + ": " + p._2)) + val effects = effectsAnalysis(pgm) + /* + * The first pass will introduce all new function definitions, + * so that in the next pass we can update function invocations + */ for { fd <- pgm.definedFunctions } { - updateFunDef(fd)(ctx).foreach{ case (nfd, mvs) => { - updatedFunctions += (fd -> ((nfd, mvs))) - }} + updatedFunctions += (fd -> updateFunDef(fd, effects)(ctx)) } - //println(updatedFunctions) - for { fd <- pgm.definedFunctions } { - fd.body = fd.body.map(bd => updateInvocations(bd, updatedFunctions)(ctx)) + updateBody(fd, effects, updatedFunctions)(ctx) } - val res = replaceFunDefs(pgm)(fd => updatedFunctions.get(fd).map(_._1), (fi, fd) => None) - //println(res._1) + val res = replaceFunDefs(pgm)(fd => updatedFunctions.get(fd), (fi, fd) => None) + println(res._1) res._1 } - private def updateInvocations(body: Expr, updatedFunctions: Map[FunDef, (FunDef, Seq[ValDef])])(ctx: LeonContext): Expr = { - val freshBody = postMap { - case fi@FunctionInvocation(fd, args) => updatedFunctions.get(fd.fd).map{ case (nfd, modifiedParams) => { - val modifiedArgs: Seq[Variable] = - args.zip(fd.params) - .filter(p => modifiedParams.contains(p._2)) - .map(_._1.asInstanceOf[Variable]) - - val freshRes = FreshIdentifier("res", nfd.returnType) - - val extractResults = Block( - modifiedArgs.zipWithIndex.map(p => Assignment(p._1.id, TupleSelect(freshRes.toVariable, p._2 + 2))), - TupleSelect(freshRes.toVariable, 1)) - - - Let(freshRes, FunctionInvocation(nfd.typed, args).setPos(fi), extractResults) - }} + /* + * Create a new FunDef for a given FunDef in the program. + * Adapt the signature to express its effects. In case the + * function has no effect, this will still introduce a fresh + * FunDef as the body might have to be updated anyway. + */ + private def updateFunDef(fd: FunDef, effects: Effects)(ctx: LeonContext): FunDef = { + + val ownEffects = effects(fd) + val aliasedParams: Seq[Identifier] = fd.params.zipWithIndex.flatMap{ + case (vd, i) if ownEffects.contains(i) => Some(vd) case _ => None - }(body) + }.map(_.id) - freshBody + val newReturnType: TypeTree = if(aliasedParams.isEmpty) fd.returnType else { + tupleTypeWrap(fd.returnType +: aliasedParams.map(_.getType)) + } + val newFunDef = new FunDef(fd.id.freshen, fd.tparams, fd.params, newReturnType) + newFunDef.addFlags(fd.flags) + newFunDef.setPos(fd) + newFunDef } - private def updateFunDef(fd: FunDef)(ctx: LeonContext): Option[(FunDef, Seq[ValDef])] = { - val aliasedParams: Seq[Identifier] = - fd.params.filter(vd => vd.getType match { - case ArrayType(_) => { - fd.body.exists(body => { - exists{ - case ArrayUpdate(Variable(a), _, _) => a == vd.id - case _ => false - }(body) - }) - } - case _ => false - }).map(_.id) + private def updateBody(fd: FunDef, effects: Effects, updatedFunDefs: Map[FunDef, FunDef]) + (ctx: LeonContext): Unit = { + val ownEffects = effects(fd) + val aliasedParams: Seq[Identifier] = fd.params.zipWithIndex.flatMap{ + case (vd, i) if ownEffects.contains(i) => Some(vd) + case _ => None + }.map(_.id) - val explicitBody = fd.body.map(bd => makeSideEffectsExplicit(bd, aliasedParams)(ctx)) + val newFunDef = updatedFunDefs(fd) if(aliasedParams.isEmpty) { - None + val newBody = fd.body.map(body => { + makeSideEffectsExplicit(body, Seq(), effects, updatedFunDefs)(ctx) + }) + newFunDef.body = newBody + newFunDef.precondition = fd.precondition + newFunDef.postcondition = fd.postcondition } else { val freshLocalVars: Seq[Identifier] = aliasedParams.map(v => v.freshen) val rewritingMap: Map[Identifier, Identifier] = aliasedParams.zip(freshLocalVars).toMap val newBody = fd.body.map(body => { - //val freshBody = postMap { - // case au@ArrayUpdate(a, i, v) => - // val Variable(id) = a - // rewritingMap.get(id).map(freshId => - // Assignment(freshId, ArrayUpdated(freshId.toVariable, i, v).setPos(au)).setPos(au) - // ) - // case _ => None - // //case as@ArraySelect(a, i) => - - // //case l@Let(i, IsTyped(v, ArrayType(_)), b) => - // // LetVar(i, v, b).setPos(l) - //}(body) - val freshBody = replaceFromIDs(rewritingMap.map(p => (p._1, p._2.toVariable)), body) + val explicitBody = makeSideEffectsExplicit(freshBody, freshLocalVars, effects, updatedFunDefs)(ctx) //WARNING: only works if side effects in Tuples are extracted from left to right, // in the ImperativeTransformation phase. - val finalBody: Expr = Tuple(freshBody +: freshLocalVars.map(_.toVariable)) + val finalBody: Expr = Tuple(explicitBody +: freshLocalVars.map(_.toVariable)) freshLocalVars.zip(aliasedParams).foldLeft(finalBody)((bd, vp) => { - Let(vp._1, Variable(vp._2), bd) + LetVar(vp._1, Variable(vp._2), bd) }) }) - val newReturnType: TypeTree = { - tupleTypeWrap(fd.returnType +: freshLocalVars.map(_.getType)) - } - val newPostcondition = fd.postcondition.map(post => { val Lambda(Seq(res), postBody) = post - val newRes = ValDef(FreshIdentifier(res.id.name, newReturnType)) + val newRes = ValDef(FreshIdentifier(res.id.name, newFunDef.returnType)) val newBody = replace( aliasedParams.zipWithIndex.map{ case (id, i) => @@ -135,20 +118,17 @@ object AntiAliasingPhase extends TransformationPhase { Lambda(Seq(newRes), newBody).setPos(post) }) - val newFunDef = new FunDef(fd.id.freshen, fd.tparams, fd.params, newReturnType) - newFunDef.addFlags(fd.flags) - newFunDef.setPos(fd) newFunDef.body = newBody newFunDef.precondition = fd.precondition newFunDef.postcondition = newPostcondition - - Some((newFunDef, aliasedParams.map(id => ValDef(id)))) } } //We turn all local val of mutable objects into vars and explicit side effects //using assignments. We also make sure that no aliasing is being done. - private def makeSideEffectsExplicit(body: Expr, aliasedParams: Seq[Identifier])(ctx: LeonContext): Expr = { + private def makeSideEffectsExplicit + (body: Expr, aliasedParams: Seq[Identifier], effects: Effects, updatedFunDefs: Map[FunDef, FunDef]) + (ctx: LeonContext): Expr = { preMapWithContext[Set[Identifier]]((expr, bindings) => expr match { case up@ArrayUpdate(a, i, v) => { @@ -179,9 +159,37 @@ object AntiAliasingPhase extends TransformationPhase { (None, bindings + id) } - + + case fi@FunctionInvocation(fd, args) => { + updatedFunDefs.get(fd.fd) match { + case None => (None, bindings) + case Some(nfd) => { + val nfi = FunctionInvocation(nfd.typed, args).setPos(fi) + val fiEffects = effects.getOrElse(fd.fd, Set()) + if(fiEffects.nonEmpty) { + val modifiedArgs: Seq[Variable] = + args.zipWithIndex.filter{ case (arg, i) => fiEffects.contains(i) } + .map(_._1.asInstanceOf[Variable]) + + val freshRes = FreshIdentifier("res", nfd.returnType) + + val extractResults = Block( + modifiedArgs.zipWithIndex.map(p => Assignment(p._1.id, TupleSelect(freshRes.toVariable, p._2 + 2))), + TupleSelect(freshRes.toVariable, 1)) + + + val newExpr = Let(freshRes, nfi, extractResults) + (Some(newExpr), bindings) + } else { + (Some(nfi), bindings) + } + } + } + } + case _ => (None, bindings) - })(body, Set()) + + })(body, aliasedParams.toSet) } //TODO: in the future, any object with vars could be aliased and so @@ -200,26 +208,30 @@ object AntiAliasingPhase extends TransformationPhase { for { fd <- pgm.definedFunctions - body <- fd.body } { + fd.body match { + case None => + effects += (fd -> Set()) + case Some(body) => { + val mutableParams = fd.params.filter(vd => vd.getType match { + case ArrayType(_) => true + case _ => false + }) + val mutatedParams = mutableParams.filter(vd => exists { + case ArrayUpdate(Variable(a), _, _) => a == vd.id + case _ => false + }(body)) + val mutatedParamsIndices = fd.params.zipWithIndex.flatMap{ + case (vd, i) if mutatedParams.contains(vd) => Some(i) + case _ => None + }.toSet + effects = effects + (fd -> mutatedParamsIndices) - val mutableParams = fd.params.filter(vd => vd.getType match { - case ArrayType(_) => true - case _ => false - }) - val mutatedParams = mutableParams.filter(vd => exists { - case ArrayUpdate(Variable(a), _, _) => a == vd.id - case _ => false - }(body)) - val mutatedParamsIndices = fd.params.zipWithIndex.flatMap{ - case (vd, i) if mutatedParams.contains(vd) => Some(i) - case _ => None - }.toSet - effects = effects + (fd -> mutatedParamsIndices) - - val missingCalls: Set[FunctionInvocation] = functionCallsOf(body).filterNot(fi => fi.tfd.fd == fd) - if(missingCalls.nonEmpty) - missingEffects += (fd -> missingCalls) + val missingCalls: Set[FunctionInvocation] = functionCallsOf(body).filterNot(fi => fi.tfd.fd == fd) + if(missingCalls.nonEmpty) + missingEffects += (fd -> missingCalls) + } + } } def rec(): Unit = { @@ -252,6 +264,9 @@ object AntiAliasingPhase extends TransformationPhase { def invocEffects(fi: FunctionInvocation): Set[Identifier] = { + if(!effects.isDefinedAt(fi.tfd.fd)) { + println("fi not defined: " + fi) + } val mutatedParams: Set[Int] = effects(fi.tfd.fd) fi.args.zipWithIndex.flatMap{ case (Variable(id), i) if mutatedParams.contains(i) => Some(id) diff --git a/src/main/scala/leon/xlang/ImperativeCodeElimination.scala b/src/main/scala/leon/xlang/ImperativeCodeElimination.scala index 45bb36770..8183074c3 100644 --- a/src/main/scala/leon/xlang/ImperativeCodeElimination.scala +++ b/src/main/scala/leon/xlang/ImperativeCodeElimination.scala @@ -67,7 +67,7 @@ object ImperativeCodeElimination extends UnitPhase[Program] { val (tRes, tScope, tFun) = toFunction(tExpr) val (eRes, eScope, eFun) = toFunction(eExpr) - val iteRType = leastUpperBound(tRes.getType, eRes.getType).get + val iteRType = leastUpperBound(tRes.getType, eRes.getType).getOrElse(Untyped) val modifiedVars: Seq[Identifier] = (tFun.keys ++ eFun.keys).toSet.intersect(varsInScope).toSeq val resId = FreshIdentifier("res", iteRType) -- GitLab