Skip to content

Commit 29f60be

Browse files
author
gan74
committed
ConstantFold improvements:
Expressions with constant type are now folded correctly. ConstantFold doesn't call typer's ConstFold.apply on every expression making it faster
1 parent 03d660a commit 29f60be

File tree

2 files changed

+66
-32
lines changed

2 files changed

+66
-32
lines changed

compiler/src/dotty/tools/dotc/transform/localopt/ConstantFold.scala

Lines changed: 15 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -21,18 +21,19 @@ import Simplify.desugarIdent
2121
* out (nested) if with equivalent branches wrt to isSimilar. For example:
2222
* - if (b) exp else exp → b; exp
2323
* - if (b1) e1 else if (b2) e1 else e2 → if (b1 || b2) e1 else e2
24+
* - if(!b) e1 else e2 → if(b) e2 else e1
2425
*
2526
* - Constant propagation over pattern matching.
2627
*
27-
* @author DarkDimius, OlivierBlanvillain
28+
* @author DarkDimius, OlivierBlanvillain, gan74
2829
*/
2930
class ConstantFold(val simplifyPhase: Simplify) extends Optimisation {
3031
import ast.tpd._
3132

3233
def visitor(implicit ctx: Context) = NoVisitor
3334
def clear(): Unit = ()
3435

35-
def transformer(implicit ctx: Context): Tree => Tree = { x => preEval(x) match {
36+
def transformer(implicit ctx: Context): Tree => Tree = {
3637
// TODO: include handling of isInstanceOf similar to one in IsInstanceOfEvaluator
3738
// TODO: include methods such as Int.int2double(see ./tests/pos/harmonize.scala)
3839
case If(cond1, thenp, elsep) if isSimilar(thenp, elsep) =>
@@ -75,7 +76,7 @@ import Simplify.desugarIdent
7576
// isBool(ift.tpe) && !elsep.const.booleanValue =>
7677
// cond.select(defn.Boolean_&&).appliedTo(elsep)
7778
// the other case ins't handled intentionally. See previous case for explanation
78-
79+
7980
case If(t @ Select(recv, _), thenp, elsep) if t.symbol eq defn.Boolean_! =>
8081
If(recv, elsep, thenp)
8182

@@ -141,6 +142,15 @@ import Simplify.desugarIdent
141142
// Block(List(lhs),
142143
// ref(defn.throwMethod).appliedTo(New(defn.ArithmeticExceptionClass.typeRef, defn.ArithmeticExceptionClass_stringConstructor, Literal(Constant("/ by zero")) :: Nil)))
143144

145+
case (l: Literal, r: Literal) =>
146+
(l.tpe.widenTermRefExpr, r.tpe.widenTermRefExpr) match {
147+
case (ConstantType(_), ConstantType(_)) =>
148+
val s = ConstFold.apply(t)
149+
if ((s ne null) && s.tpe.isInstanceOf[ConstantType]) Literal(s.tpe.asInstanceOf[ConstantType].value)
150+
else t
151+
case _ => t
152+
}
153+
144154
case _ => t
145155
}
146156

@@ -157,26 +167,10 @@ import Simplify.desugarIdent
157167

158168
case t: Literal => t
159169
case t: CaseDef => t
160-
case t if !isPureExpr(t) => t
161-
case t =>
162-
val s = ConstFold.apply(t)
163-
if ((s ne null) && s.tpe.isInstanceOf[ConstantType]) {
164-
val constant = s.tpe.asInstanceOf[ConstantType].value
165-
Literal(constant)
166-
} else t
167-
}
170+
case t => t
168171
}
169172

170-
def preEval(t: Tree)(implicit ctx: Context) = {
171-
if (t.isInstanceOf[Literal] || t.isInstanceOf[CaseDef] || !isPureExpr(t)) t
172-
else {
173-
val s = ConstFold.apply(t)
174-
if ((s ne null) && s.tpe.isInstanceOf[ConstantType]) {
175-
val constant = s.tpe.asInstanceOf[ConstantType].value
176-
Literal(constant)
177-
} else t
178-
}
179-
}
173+
180174

181175
def isSimilar(t1: Tree, t2: Tree)(implicit ctx: Context): Boolean = t1 match {
182176
case t1: Apply =>

compiler/test/dotty/tools/dotc/SimplifyTests.scala

Lines changed: 51 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -79,17 +79,6 @@ abstract class SimplifyTests(val optimise: Boolean) extends DottyBytecodeTest {
7979
|print(new Some(new Tuple2(1, "s")))
8080
""")
8181

82-
@Test def constantFold =
83-
check(
84-
"""
85-
|val t = true // val needed, or typer takes care of this
86-
|if (t) print(1)
87-
|else print(2)
88-
""",
89-
"""
90-
|print(1)
91-
""")
92-
9382
@Test def dropNoEffects =
9483
check(
9584
"""
@@ -124,6 +113,57 @@ abstract class SimplifyTests(val optimise: Boolean) extends DottyBytecodeTest {
124113
|println(true)
125114
""")
126115

116+
117+
/*
118+
* Constant folding tests
119+
*/
120+
121+
@Test def basicConstantFold =
122+
check(
123+
"""
124+
|val i = 3
125+
|val j = i + 4
126+
|print(j)
127+
""",
128+
"""
129+
|print(7)
130+
""")
131+
132+
@Test def branchConstantFold =
133+
check(
134+
"""
135+
|val t = true // val needed, or typer takes care of this
136+
|if (t) print(1)
137+
|else print(2)
138+
""",
139+
"""
140+
|print(1)
141+
""")
142+
143+
@Test def arithmeticConstantFold =
144+
check(
145+
"""
146+
|val i = 3
147+
|val j = i + 4
148+
|if(j - i >= (i + 1) / 2)
149+
| print(i + 1)
150+
""",
151+
"""
152+
|print(4)
153+
""")
154+
155+
@Test def twoValConstantFold =
156+
check(
157+
"""
158+
|val i = 3
159+
|val j = 4
160+
|val k = i * j
161+
|print(k - j)
162+
""",
163+
"""
164+
|print(8)
165+
""")
166+
127167
// @Test def listPatmapExample =
128168
// check(
129169
// """

0 commit comments

Comments
 (0)