Skip to content

Commit 48acd1b

Browse files
authored
Optimizing generated termination checks to omit unfolds and condition evaluations where they are not needed (#879)
1 parent 0715b81 commit 48acd1b

1 file changed

Lines changed: 32 additions & 7 deletions

File tree

src/main/scala/viper/silver/plugin/standard/termination/transformation/ExpTransformer.scala

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -45,24 +45,32 @@ trait ExpTransformer extends ProgramManager with ErrorReporter {
4545
val fstBlock = Seqn(Seq(fstIf), Seq(nonDetVarDecl))()
4646
val sndStmt = transformExp(snd, c, inhaleExp)
4747
Seqn(Seq(fstBlock, sndStmt), Nil)()
48+
4849
case CondExp(cond, thn, els) =>
4950
val condStmt = transformExp(cond, c, false)
5051
val thnStmt = transformExp(thn, c, inhaleExp)
5152
val elsStmt = transformExp(els, c, inhaleExp)
52-
53-
val ifStmt = If(cond, Seqn(Seq(thnStmt), Nil)(), Seqn(Seq(elsStmt), Nil)())()
54-
53+
val ifStmt = if (isEmptyStatement(thnStmt) && isEmptyStatement(elsStmt))
54+
EmptyStmt
55+
else
56+
If(cond, Seqn(Seq(thnStmt), Nil)(), Seqn(Seq(elsStmt), Nil)())()
5557
val stmts = Seq(condStmt, ifStmt)
5658
Seqn(stmts, Nil)()
59+
5760
case Unfolding(acc, unfBody) =>
5861
val permCheck = transformExp(acc.perm, c, false)
5962
val unfoldBody = transformExp(unfBody, c, inhaleExp)
6063
val unfold = Unfold(acc)()
6164
val nonDetVarDecl = LocalVarDecl(uniqueName("b"), Bool)(e.pos, e.info, e.errT)
6265
val assumeFalse = Inhale(FalseLit()())()
63-
val thenBranch = Seqn(Seq(permCheck, unfold, unfoldBody, assumeFalse), Nil)()
66+
val unfoldPart = if (!isEmptyStatement(unfoldBody)) Seqn(Seq(unfold, unfoldBody), Nil)() else EmptyStmt
67+
val thenBranch = Seqn(Seq(permCheck, unfoldPart, assumeFalse), Nil)()
6468
val elseBranch = if (inhaleExp) Seqn(Seq(Inhale(e)(e.pos, e.info)), Nil)() else EmptyStmt
65-
Seqn(Seq(If(nonDetVarDecl.localVar, thenBranch, elseBranch)()), Seq(nonDetVarDecl))()
69+
if (isEmptyStatement(permCheck) && isEmptyStatement(unfoldPart))
70+
elseBranch
71+
else
72+
Seqn(Seq(If(nonDetVarDecl.localVar, thenBranch, elseBranch)()), Seq(nonDetVarDecl))()
73+
6674
case Applying(wand, body) =>
6775
// note that this case is untested -- it's not possible to write a function with an `applying` expression
6876
val nonDetVarDecl = LocalVarDecl(uniqueName("b"), Bool)(e.pos, e.info, e.errT)
@@ -71,6 +79,7 @@ trait ExpTransformer extends ProgramManager with ErrorReporter {
7179
val thnStmt = Seqn(Seq(Apply(wand)(e.pos, e.info, e.errT), bodyStmt, killBranchStmt), Nil)()
7280
val ifStmt = If(nonDetVarDecl.localVar, thnStmt, EmptyStmt)(e.pos, e.info, e.errT)
7381
Seqn(Seq(ifStmt), Seq(nonDetVarDecl))(e.pos, e.info, e.errT)
82+
7483
case inex: InhaleExhaleExp =>
7584
val inhaleStmt = transformExp(inex.in, c, inhaleExp)
7685
val exhaleStmt = transformExp(inex.ex, c, inhaleExp)
@@ -79,6 +88,7 @@ trait ExpTransformer extends ProgramManager with ErrorReporter {
7988
case Some(conditionVar) => If(conditionVar.localVar, Seqn(Seq(inhaleStmt), Nil)(), Seqn(Seq(exhaleStmt), Nil)())()
8089
case None => Seqn(Seq(inhaleStmt, exhaleStmt), Nil)()
8190
}
91+
8292
case letExp: Let =>
8393
val expressionStmt = transformExp(letExp.exp, c, false)
8494
val localVarDecl = letExp.variable
@@ -87,15 +97,20 @@ trait ExpTransformer extends ProgramManager with ErrorReporter {
8797

8898
val bodyStmt = transformExp(letExp.body, c, inhaleExp)
8999

90-
Seqn(Seq(expressionStmt, inhaleEq, bodyStmt), Seq(localVarDecl))()
100+
val bodyCheck = if (isEmptyStatement(bodyStmt))
101+
EmptyStmt
102+
else
103+
Seqn(Seq(inhaleEq, bodyStmt), Seq(localVarDecl))()
104+
105+
Seqn(Seq(expressionStmt, bodyCheck), Nil)()
91106

92107
case b: BinExp =>
93108
val left = transformExp(b.left, c, inhaleExp)
94109
val right = transformExp(b.right, c, inhaleExp)
95110

96111
// Short circuit evaluation
97112
val pureLeft: Exp = toPureBooleanExp(c).execute(b.left)
98-
val rightSCE = b match {
113+
val rightSCE = if (isEmptyStatement(right)) EmptyStmt else b match {
99114
case _: Or =>
100115
If(Not(pureLeft)(), Seqn(Seq(right), Nil)(), EmptyStmt)()
101116
case _: And =>
@@ -119,12 +134,14 @@ trait ExpTransformer extends ProgramManager with ErrorReporter {
119134
val check = transformExp(ap.perm, c, false)
120135
val inhale = Inhale(ap)(ap.pos)
121136
Seqn(Seq(check, inhale), Nil)()
137+
122138
case fa: Forall =>
123139
// we turn the quantified variables into local variables with arbitrary value and show that the expression holds
124140
// for arbitrary values, which is similar to a forall introduction
125141
val (localDeclMapping, transformedExp) = substituteWithFreshVars(fa.variables, fa.exp)
126142
val expressionStmt = transformExp(transformedExp, c, inhaleExp)
127143
Seqn(Seq(expressionStmt), localDeclMapping.map(_._2))(fa.pos, fa.info, fa.errT)
144+
128145
case fp: ForPerm =>
129146
// let's pick arbitrary values for the quantified variables and check the body given that the current heap has
130147
// sufficient permissions
@@ -136,6 +153,7 @@ trait ExpTransformer extends ProgramManager with ErrorReporter {
136153
val ifCond = GtCmp(CurrentPerm(transformedRes)(e.pos, e.info, e.errT), NoPerm()(e.pos, e.info, e.errT))(e.pos, e.info, e.errT)
137154
val ifStmt = If(ifCond, thnStmt, EmptyStmt)(e.pos, e.info, e.errT)
138155
Seqn(Seq(ifStmt), localDeclMapping.map(_._2))(e.pos, e.info, e.errT)
156+
139157
case ex: Exists =>
140158
// we perform existential elimination by retrieving witnesses for the quantified variables
141159
val (localDeclMapping, transformedExp) = substituteWithFreshVars(ex.variables, ex.exp)
@@ -144,16 +162,23 @@ trait ExpTransformer extends ProgramManager with ErrorReporter {
144162
val inhaleWitnesses = Inhale(transformedExp)(ex.pos, ex.info, ex.errT)
145163
val expressionStmt = transformExp(transformedExp, c, inhaleExp)
146164
Seqn(Seq(inhaleWitnesses, expressionStmt), localDeclMapping.map(_._2))(ex.pos, ex.info, ex.errT)
165+
147166
case fa: FuncLikeApp =>
148167
val argStmts = fa.args.map(transformExp(_, c, false))
149168
Seqn(argStmts, Nil)()
169+
150170
case e: ExtensionExp => reportUnsupportedExp(e)
151171

152172
case _ =>
153173
val sub = e.subExps.map(transformExp(_, c, false))
154174
Seqn(sub, Nil)()
155175
}
156176

177+
def isEmptyStatement(stmt: Stmt): Boolean = stmt match {
178+
case Seqn(stmts, _) => stmts.forall(isEmptyStatement)
179+
case _ => false
180+
}
181+
157182
/**
158183
* Issues a consistency error for unsupported expressions.
159184
*

0 commit comments

Comments
 (0)