summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSébastien Doeraene <sjrdoeraene@gmail.com>2016-04-23 09:10:30 +0200
committerLukas Rytz <lukas.rytz@typesafe.com>2016-04-23 09:10:30 +0200
commiteb954cafa2737a6f06f8a802ceec133a88959f71 (patch)
treec4dc3d3144ac05303e4093023fe4bf8db7d083f4
parentf55dd2084eca97c576a982473ab6701f98fb79a7 (diff)
downloadscala-eb954cafa2737a6f06f8a802ceec133a88959f71.tar.gz
scala-eb954cafa2737a6f06f8a802ceec133a88959f71.tar.bz2
scala-eb954cafa2737a6f06f8a802ceec133a88959f71.zip
SI-9516 Fix the behavior of Int shift Long operations. (#5117)
In any shift operation where the lhs is an Int (or smaller) and the rhs is a Long, the result kind must be Int, and not Long. This is important because the lhs must *not* be promoted to a Long, as that causes an opcode for long shift to be emitted. This uses an rhs modulo 64, instead of int shifts which use an rhs module 32. Instead, the rhs must be downgraded to an Int. The new behavior is consistent with the same operations in the Java programming language.
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala9
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/ConstantFolder.scala6
-rw-r--r--test/files/run/t9516.scala52
3 files changed, 60 insertions, 7 deletions
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala
index 22587c68f7..5d152ef0e8 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala
@@ -117,15 +117,16 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder {
// binary operation
case rarg :: Nil =>
- resKind = tpeTK(larg).maxType(tpeTK(rarg))
- if (scalaPrimitives.isShiftOp(code) || scalaPrimitives.isBitwiseOp(code)) {
+ val isShiftOp = scalaPrimitives.isShiftOp(code)
+ resKind = tpeTK(larg).maxType(if (isShiftOp) INT else tpeTK(rarg))
+
+ if (isShiftOp || scalaPrimitives.isBitwiseOp(code)) {
assert(resKind.isIntegralType || (resKind == BOOL),
s"$resKind incompatible with arithmetic modulo operation.")
}
genLoad(larg, resKind)
- genLoad(rarg, // check .NET size of shift arguments!
- if (scalaPrimitives.isShiftOp(code)) INT else resKind)
+ genLoad(rarg, if (isShiftOp) INT else resKind)
(code: @switch) match {
case ADD => bc add resKind
diff --git a/src/compiler/scala/tools/nsc/typechecker/ConstantFolder.scala b/src/compiler/scala/tools/nsc/typechecker/ConstantFolder.scala
index 2f4771e9d4..828a79ac4f 100644
--- a/src/compiler/scala/tools/nsc/typechecker/ConstantFolder.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/ConstantFolder.scala
@@ -102,13 +102,13 @@ abstract class ConstantFolder {
case nme.XOR => Constant(x.longValue ^ y.longValue)
case nme.AND => Constant(x.longValue & y.longValue)
case nme.LSL if x.tag <= IntTag
- => Constant(x.intValue << y.longValue)
+ => Constant(x.intValue << y.longValue.toInt) // TODO: remove .toInt once starr includes the fix for SI-9516 (2.12.0-M5)
case nme.LSL => Constant(x.longValue << y.longValue)
case nme.LSR if x.tag <= IntTag
- => Constant(x.intValue >>> y.longValue)
+ => Constant(x.intValue >>> y.longValue.toInt) // TODO: remove .toInt once starr includes the fix for SI-9516 (2.12.0-M5)
case nme.LSR => Constant(x.longValue >>> y.longValue)
case nme.ASR if x.tag <= IntTag
- => Constant(x.intValue >> y.longValue)
+ => Constant(x.intValue >> y.longValue.toInt) // TODO: remove .toInt once starr includes the fix for SI-9516 (2.12.0-M5)
case nme.ASR => Constant(x.longValue >> y.longValue)
case nme.EQ => Constant(x.longValue == y.longValue)
case nme.NE => Constant(x.longValue != y.longValue)
diff --git a/test/files/run/t9516.scala b/test/files/run/t9516.scala
new file mode 100644
index 0000000000..b3068dd1ff
--- /dev/null
+++ b/test/files/run/t9516.scala
@@ -0,0 +1,52 @@
+object Test {
+ def main(args: Array[String]): Unit = {
+ intShiftLeftLongConstantFolded()
+ intShiftLeftLongAtRuntime()
+ intShiftLogicalRightLongConstantFolded()
+ intShiftLogicalRightLongAtRuntime()
+ intShiftArithmeticRightLongConstantFolded()
+ intShiftArithmeticRightLongAtRuntime()
+ }
+
+ def intShiftLeftLongConstantFolded(): Unit = {
+ assert(0x01030507 << 36L == 271601776)
+ val r = 0x01030507 << 36L
+ assert(r == 271601776)
+ }
+
+ def intShiftLeftLongAtRuntime(): Unit = {
+ var x: Int = 0x01030507
+ var y: Long = 36L
+ assert(x << y == 271601776)
+ val r = x << y
+ assert(r == 271601776)
+ }
+
+ def intShiftLogicalRightLongConstantFolded(): Unit = {
+ assert(0x90503010 >>> 36L == 151323393)
+ val r = 0x90503010 >>> 36L
+ assert(r == 151323393)
+ }
+
+ def intShiftLogicalRightLongAtRuntime(): Unit = {
+ var x: Int = 0x90503010
+ var y: Long = 36L
+ assert(x >>> y == 151323393)
+ val r = x >>> y
+ assert(r == 151323393)
+ }
+
+ def intShiftArithmeticRightLongConstantFolded(): Unit = {
+ assert(0x90503010 >> 36L == -117112063)
+ val r = 0x90503010 >> 36L
+ assert(r == -117112063)
+ }
+
+ def intShiftArithmeticRightLongAtRuntime(): Unit = {
+ var x: Int = 0x90503010
+ var y: Long = 36L
+ assert(x >> y == -117112063)
+ val r = x >> y
+ assert(r == -117112063)
+ }
+}