Skip to content

Commit 7389b63

Browse files
authored
Merge pull request #13214 from harpocrates/alec/iinc
Teach backend to emit `iinc` instructions
2 parents e604e36 + 29de10a commit 7389b63

File tree

5 files changed

+93
-13
lines changed

5 files changed

+93
-13
lines changed

compiler/src/dotty/tools/backend/jvm/BCodeBodyBuilder.scala

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -88,9 +88,23 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder {
8888
case Assign(lhs, rhs) =>
8989
val s = lhs.symbol
9090
val Local(tk, _, idx, _) = locals.getOrMakeLocal(s)
91-
genLoad(rhs, tk)
92-
lineNumber(tree)
93-
bc.store(idx, tk)
91+
92+
rhs match {
93+
case Apply(Select(larg: Ident, nme.ADD), Literal(x) :: Nil)
94+
if larg.symbol == s && tk.isIntSizedType && x.isShortRange =>
95+
lineNumber(tree)
96+
bc.iinc(idx, x.intValue)
97+
98+
case Apply(Select(larg: Ident, nme.SUB), Literal(x) :: Nil)
99+
if larg.symbol == s && tk.isIntSizedType && Constant(-x.intValue).isShortRange =>
100+
lineNumber(tree)
101+
bc.iinc(idx, -x.intValue)
102+
103+
case _ =>
104+
genLoad(rhs, tk)
105+
lineNumber(tree)
106+
bc.store(idx, tk)
107+
}
94108

95109
case _ =>
96110
genLoad(tree, UNIT)

compiler/src/dotty/tools/backend/jvm/BCodeIdiomatic.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -433,6 +433,7 @@ trait BCodeIdiomatic {
433433

434434
final def load( idx: Int, tk: BType): Unit = { emitVarInsn(Opcodes.ILOAD, idx, tk) } // can-multi-thread
435435
final def store(idx: Int, tk: BType): Unit = { emitVarInsn(Opcodes.ISTORE, idx, tk) } // can-multi-thread
436+
final def iinc( idx: Int, increment: Int): Unit = jmethod.visitIincInsn(idx, increment) // can-multi-thread
436437

437438
final def aload( tk: BType): Unit = { emitTypeBased(JCodeMethodN.aloadOpcodes, tk) } // can-multi-thread
438439
final def astore(tk: BType): Unit = { emitTypeBased(JCodeMethodN.astoreOpcodes, tk) } // can-multi-thread

compiler/test/dotty/tools/backend/jvm/DottyBytecodeTests.scala

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -759,17 +759,14 @@ class TestBCode extends DottyBytecodeTest {
759759
FrameEntry(1, List(1), List()),
760760
VarOp(Opcodes.ILOAD, 1),
761761
Op(Opcodes.ICONST_5),
762-
Jump(Opcodes.IF_ICMPGT, Label(16)),
762+
Jump(Opcodes.IF_ICMPGT, Label(13)),
763763
Field(Opcodes.GETSTATIC, "scala/Predef$", "MODULE$", "Lscala/Predef$;"),
764764
VarOp(Opcodes.ILOAD, 1),
765765
Invoke(Opcodes.INVOKESTATIC, "scala/runtime/BoxesRunTime", "boxToInteger", "(I)Ljava/lang/Integer;", false),
766766
Invoke(Opcodes.INVOKEVIRTUAL, "scala/Predef$", "println", "(Ljava/lang/Object;)V", false),
767-
VarOp(Opcodes.ILOAD, 1),
768-
Op(Opcodes.ICONST_1),
769-
Op(Opcodes.IADD),
770-
VarOp(Opcodes.ISTORE, 1),
767+
Incr(Opcodes.IINC, 1, 1),
771768
Jump(Opcodes.GOTO, Label(2)),
772-
Label(16),
769+
Label(13),
773770
FrameEntry(3, List(), List()),
774771
Op(Opcodes.RETURN))
775772

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
package dotty.tools.backend.jvm
2+
3+
import org.junit.Test
4+
import org.junit.Assert._
5+
6+
import scala.tools.asm.Opcodes._
7+
8+
class IincTest extends DottyBytecodeTest {
9+
import ASMConverters._
10+
11+
@Test def increment = test(
12+
"""{
13+
| var i = x
14+
| i += 1
15+
| i += 54
16+
| i += 127
17+
| i -= 1
18+
| i -= 54
19+
| i -= 128
20+
| i
21+
|}""".stripMargin,
22+
List(1, 54, 127, -1, -54, -128)
23+
)
24+
25+
@Test def wideIncrement = test(
26+
"""{
27+
| var i = x
28+
| i += 128
29+
| i += 8765
30+
| i += 32767
31+
| i -= 129
32+
| i -= 8765
33+
| i -= 32768
34+
| i
35+
|}""".stripMargin,
36+
List(128, 8765, 32767, -129, -8765, -32768)
37+
)
38+
39+
@Test def tooBigForIinc = test(
40+
"""{
41+
| var i = x
42+
| i += 32768
43+
| i += 56789
44+
| i += 2147483647
45+
| i -= 32769
46+
| i -= 56789
47+
| i -= 2147483647
48+
| i
49+
|}""".stripMargin,
50+
Nil
51+
)
52+
53+
private def test(code: String, expectedIincs: List[Int])= {
54+
val source =
55+
s"""class Increment {
56+
| def test(x: Int): Int = $code
57+
|}
58+
""".stripMargin
59+
60+
checkBCode(source) { dir =>
61+
val clsIn = dir.lookupName("Increment.class", directory = false).input
62+
val clsNode = loadClassNode(clsIn)
63+
val meth = getMethod(clsNode, "test")
64+
65+
val foundIincs = instructionsFromMethod(meth).collect { case iinc: Incr => iinc.incr }
66+
67+
assertEquals(expectedIincs, foundIincs)
68+
}
69+
}
70+
71+
}

compiler/test/dotty/tools/backend/jvm/InlineBytecodeTests.scala

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -397,10 +397,7 @@ class InlineBytecodeTests extends DottyBytecodeTest {
397397
List(
398398
IntOp(BIPUSH, 10),
399399
VarOp(ISTORE, 1),
400-
VarOp(ILOAD, 1),
401-
Op(ICONST_1),
402-
Op(IADD),
403-
VarOp(ISTORE, 1),
400+
Incr(IINC, 1, 1),
404401
VarOp(ILOAD, 1),
405402
Op(IRETURN),
406403
)

0 commit comments

Comments
 (0)