OSDN Git Service

Add constant folding for long unary operations in opt. compiler.
authorRoland Levillain <rpl@google.com>
Thu, 11 Dec 2014 12:14:33 +0000 (12:14 +0000)
committerRoland Levillain <rpl@google.com>
Wed, 5 Aug 2015 10:01:40 +0000 (11:01 +0100)
Add tests to exercise the constant folding of these
instructions.

Also, prevent Java methods from run-tests exercising the
code generation of these instruction from being inlined,
so that they continue to check the generated code (and
not the code produced by the constant folding pass).

Change-Id: I28efca7cdb5142ac2b6d158ba296fb9136d62481

compiler/optimizing/constant_folding_test.cc
compiler/optimizing/nodes.cc
test/415-optimizing-arith-neg/src/Main.java
test/442-checker-constant-folding/src/Main.java

index 11f6362..10e4bc9 100644 (file)
@@ -81,7 +81,7 @@ static void TestCode(const uint16_t* data,
  *                              offset
  *                              ------
  *     v0 <- 1                  0.      const/4 v0, #+1
- *     v1 <- -v0                1.      neg-int v0, v1
+ *     v1 <- -v0                1.      neg-int v1, v0
  *     return v1                2.      return v1
  */
 TEST(ConstantFolding, IntConstantFoldingNegation) {
@@ -132,6 +132,69 @@ TEST(ConstantFolding, IntConstantFoldingNegation) {
 }
 
 /**
+ * Tiny three-register program exercising long constant folding on negation.
+ *
+ *                              16-bit
+ *                              offset
+ *                              ------
+ *     (v0, v1) <- 4294967296   0.      const-wide v0 #+4294967296
+ *     (v2, v3) <- -(v0, v1)    1.      neg-long v2, v0
+ *     return (v2, v3)          2.      return-wide v2
+ */
+TEST(ConstantFolding, LongConstantFoldingNegation) {
+  const int64_t input = INT64_C(4294967296);             // 2^32
+  const uint16_t word0 = Low16Bits(Low32Bits(input));    // LSW.
+  const uint16_t word1 = High16Bits(Low32Bits(input));
+  const uint16_t word2 = Low16Bits(High32Bits(input));
+  const uint16_t word3 = High16Bits(High32Bits(input));  // MSW.
+  const uint16_t data[] = FOUR_REGISTERS_CODE_ITEM(
+    Instruction::CONST_WIDE | 0 << 8, word0, word1, word2, word3,
+    Instruction::NEG_LONG | 2 << 8 | 0 << 12,
+    Instruction::RETURN_WIDE | 2 << 8);
+
+  std::string expected_before =
+      "BasicBlock 0, succ: 1\n"
+      "  4: LongConstant [7]\n"
+      "  12: SuspendCheck\n"
+      "  13: Goto 1\n"
+      "BasicBlock 1, pred: 0, succ: 2\n"
+      "  7: Neg(4) [10]\n"
+      "  10: Return(7)\n"
+      "BasicBlock 2, pred: 1\n"
+      "  11: Exit\n";
+
+  // Expected difference after constant folding.
+  diff_t expected_cf_diff = {
+    { "  4: LongConstant [7]\n", "  4: LongConstant\n" },
+    { "  12: SuspendCheck\n",    "  12: SuspendCheck\n"
+                                 "  14: LongConstant [10]\n" },
+    { "  7: Neg(4) [10]\n",      removed },
+    { "  10: Return(7)\n",       "  10: Return(14)\n" }
+  };
+  std::string expected_after_cf = Patch(expected_before, expected_cf_diff);
+
+  // Check the value of the computed constant.
+  auto check_after_cf = [](HGraph* graph) {
+    HInstruction* inst = graph->GetBlock(1)->GetFirstInstruction()->InputAt(0);
+    ASSERT_TRUE(inst->IsLongConstant());
+    ASSERT_EQ(inst->AsLongConstant()->GetValue(), INT64_C(-4294967296));
+  };
+
+  // Expected difference after dead code elimination.
+  diff_t expected_dce_diff = {
+    { "  4: LongConstant\n", removed },
+  };
+  std::string expected_after_dce = Patch(expected_after_cf, expected_dce_diff);
+
+  TestCode(data,
+           expected_before,
+           expected_after_cf,
+           expected_after_dce,
+           check_after_cf,
+           Primitive::kPrimLong);
+}
+
+/**
  * Tiny three-register program exercising int constant folding on addition.
  *
  *                              16-bit
index 296c1b0..efaf48c 100644 (file)
@@ -1008,12 +1008,8 @@ HConstant* HUnaryOperation::TryStaticEvaluation() const {
     int32_t value = Evaluate(GetInput()->AsIntConstant()->GetValue());
     return GetBlock()->GetGraph()->GetIntConstant(value);
   } else if (GetInput()->IsLongConstant()) {
-    // TODO: Implement static evaluation of long unary operations.
-    //
-    // Do not exit with a fatal condition here.  Instead, simply
-    // return `null' to notify the caller that this instruction
-    // cannot (yet) be statically evaluated.
-    return nullptr;
+    int64_t value = Evaluate(GetInput()->AsLongConstant()->GetValue());
+    return GetBlock()->GetGraph()->GetLongConstant(value);
   }
   return nullptr;
 }
index cabf635..c53b639 100644 (file)
@@ -15,7 +15,8 @@
  */
 
 // Note that $opt$ is a marker for the optimizing compiler to test
-// it does compile the method.
+// it does compile the method, and that $noinline$ is a marker to
+// test that it does not inline it.
 public class Main {
 
   public static void assertEquals(int expected, int result) {
@@ -68,23 +69,23 @@ public class Main {
 
   public static void main(String[] args) {
     negInt();
-    $opt$InplaceNegOneInt(1);
+    $opt$noinline$InplaceNegOneInt(1);
 
     negLong();
-    $opt$InplaceNegOneLong(1L);
+    $opt$noinline$InplaceNegOneLong(1L);
 
     negFloat();
     negDouble();
   }
 
   private static void negInt() {
-    assertEquals(-1, $opt$NegInt(1));
-    assertEquals(1, $opt$NegInt(-1));
-    assertEquals(0, $opt$NegInt(0));
-    assertEquals(51, $opt$NegInt(-51));
-    assertEquals(-51, $opt$NegInt(51));
-    assertEquals(2147483647, $opt$NegInt(-2147483647));  // -(2^31 - 1)
-    assertEquals(-2147483647, $opt$NegInt(2147483647));  // 2^31 - 1
+    assertEquals(-1, $opt$noinline$NegInt(1));
+    assertEquals(1, $opt$noinline$NegInt(-1));
+    assertEquals(0, $opt$noinline$NegInt(0));
+    assertEquals(51, $opt$noinline$NegInt(-51));
+    assertEquals(-51, $opt$noinline$NegInt(51));
+    assertEquals(2147483647, $opt$noinline$NegInt(-2147483647));  // -(2^31 - 1)
+    assertEquals(-2147483647, $opt$noinline$NegInt(2147483647));  // 2^31 - 1
     // From the Java 7 SE Edition specification:
     // http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.15.4
     //
@@ -95,101 +96,128 @@ public class Main {
     //   int or long results in that same maximum negative number.
     //   Overflow occurs in this case, but no exception is thrown.
     //   For all integer values x, -x equals (~x)+1.''
-    assertEquals(-2147483648, $opt$NegInt(-2147483648)); // -(2^31)
-  }
-
-  private static void $opt$InplaceNegOneInt(int a) {
-    a = -a;
-    assertEquals(-1, a);
+    assertEquals(-2147483648, $opt$noinline$NegInt(-2147483648)); // -(2^31)
   }
 
   private static void negLong() {
-    assertEquals(-1L, $opt$NegLong(1L));
-    assertEquals(1L, $opt$NegLong(-1L));
-    assertEquals(0L, $opt$NegLong(0L));
-    assertEquals(51L, $opt$NegLong(-51L));
-    assertEquals(-51L, $opt$NegLong(51L));
-
-    assertEquals(2147483647L, $opt$NegLong(-2147483647L));  // -(2^31 - 1)
-    assertEquals(-2147483647L, $opt$NegLong(2147483647L));  // (2^31 - 1)
-    assertEquals(2147483648L, $opt$NegLong(-2147483648L));  // -(2^31)
-    assertEquals(-2147483648L, $opt$NegLong(2147483648L));  // 2^31
-
-    assertEquals(9223372036854775807L, $opt$NegLong(-9223372036854775807L));  // -(2^63 - 1)
-    assertEquals(-9223372036854775807L, $opt$NegLong(9223372036854775807L));  // 2^63 - 1
+    assertEquals(-1L, $opt$noinline$NegLong(1L));
+    assertEquals(1L, $opt$noinline$NegLong(-1L));
+    assertEquals(0L, $opt$noinline$NegLong(0L));
+    assertEquals(51L, $opt$noinline$NegLong(-51L));
+    assertEquals(-51L, $opt$noinline$NegLong(51L));
+
+    assertEquals(2147483647L, $opt$noinline$NegLong(-2147483647L));  // -(2^31 - 1)
+    assertEquals(-2147483647L, $opt$noinline$NegLong(2147483647L));  // (2^31 - 1)
+    assertEquals(2147483648L, $opt$noinline$NegLong(-2147483648L));  // -(2^31)
+    assertEquals(-2147483648L, $opt$noinline$NegLong(2147483648L));  // 2^31
+
+    assertEquals(9223372036854775807L, $opt$noinline$NegLong(-9223372036854775807L));  // -(2^63 - 1)
+    assertEquals(-9223372036854775807L, $opt$noinline$NegLong(9223372036854775807L));  // 2^63 - 1
     // See remark regarding the negation of the maximum negative
     // (long) value in negInt().
-    assertEquals(-9223372036854775808L, $opt$NegLong(-9223372036854775808L)); // -(2^63)
+    assertEquals(-9223372036854775808L, $opt$noinline$NegLong(-9223372036854775808L)); // -(2^63)
+  }
+
+  private static void negFloat() {
+     assertEquals("-0.0", $opt$noinline$NegFloat(0F));
+     assertEquals("0.0", $opt$noinline$NegFloat(-0F));
+     assertEquals(-1F, $opt$noinline$NegFloat(1F));
+     assertEquals(1F, $opt$noinline$NegFloat(-1F));
+     assertEquals(51F, $opt$noinline$NegFloat(-51F));
+     assertEquals(-51F, $opt$noinline$NegFloat(51F));
+
+     assertEquals(-0.1F, $opt$noinline$NegFloat(0.1F));
+     assertEquals(0.1F, $opt$noinline$NegFloat(-0.1F));
+     assertEquals(343597.38362F, $opt$noinline$NegFloat(-343597.38362F));
+     assertEquals(-343597.38362F, $opt$noinline$NegFloat(343597.38362F));
+
+     assertEquals(-Float.MIN_NORMAL, $opt$noinline$NegFloat(Float.MIN_NORMAL));
+     assertEquals(Float.MIN_NORMAL, $opt$noinline$NegFloat(-Float.MIN_NORMAL));
+     assertEquals(-Float.MIN_VALUE, $opt$noinline$NegFloat(Float.MIN_VALUE));
+     assertEquals(Float.MIN_VALUE, $opt$noinline$NegFloat(-Float.MIN_VALUE));
+     assertEquals(-Float.MAX_VALUE, $opt$noinline$NegFloat(Float.MAX_VALUE));
+     assertEquals(Float.MAX_VALUE, $opt$noinline$NegFloat(-Float.MAX_VALUE));
+
+     assertEquals(Float.NEGATIVE_INFINITY, $opt$noinline$NegFloat(Float.POSITIVE_INFINITY));
+     assertEquals(Float.POSITIVE_INFINITY, $opt$noinline$NegFloat(Float.NEGATIVE_INFINITY));
+     assertIsNaN($opt$noinline$NegFloat(Float.NaN));
   }
 
-  private static void $opt$InplaceNegOneLong(long a) {
+  private static void negDouble() {
+     assertEquals("-0.0", $opt$noinline$NegDouble(0D));
+     assertEquals("0.0", $opt$noinline$NegDouble(-0D));
+     assertEquals(-1D, $opt$noinline$NegDouble(1D));
+     assertEquals(1D, $opt$noinline$NegDouble(-1D));
+     assertEquals(51D, $opt$noinline$NegDouble(-51D));
+     assertEquals(-51D, $opt$noinline$NegDouble(51D));
+
+     assertEquals(-0.1D, $opt$noinline$NegDouble(0.1D));
+     assertEquals(0.1D, $opt$noinline$NegDouble(-0.1D));
+     assertEquals(343597.38362D, $opt$noinline$NegDouble(-343597.38362D));
+     assertEquals(-343597.38362D, $opt$noinline$NegDouble(343597.38362D));
+
+     assertEquals(-Double.MIN_NORMAL, $opt$noinline$NegDouble(Double.MIN_NORMAL));
+     assertEquals(Double.MIN_NORMAL, $opt$noinline$NegDouble(-Double.MIN_NORMAL));
+     assertEquals(-Double.MIN_VALUE, $opt$noinline$NegDouble(Double.MIN_VALUE));
+     assertEquals(Double.MIN_VALUE, $opt$noinline$NegDouble(-Double.MIN_VALUE));
+     assertEquals(-Double.MAX_VALUE, $opt$noinline$NegDouble(Double.MAX_VALUE));
+     assertEquals(Double.MAX_VALUE, $opt$noinline$NegDouble(-Double.MAX_VALUE));
+
+     assertEquals(Double.NEGATIVE_INFINITY, $opt$noinline$NegDouble(Double.POSITIVE_INFINITY));
+     assertEquals(Double.POSITIVE_INFINITY, $opt$noinline$NegDouble(Double.NEGATIVE_INFINITY));
+     assertIsNaN($opt$noinline$NegDouble(Double.NaN));
+  }
+
+
+  static boolean doThrow = false;
+
+  private static void $opt$noinline$InplaceNegOneInt(int a) {
+    if (doThrow) {
+      // Try defeating inlining.
+      throw new Error();
+    }
     a = -a;
-    assertEquals(-1L, a);
+    assertEquals(-1, a);
   }
 
-  private static void negFloat() {
-     assertEquals("-0.0", $opt$NegFloat(0F));
-     assertEquals("0.0", $opt$NegFloat(-0F));
-     assertEquals(-1F, $opt$NegFloat(1F));
-     assertEquals(1F, $opt$NegFloat(-1F));
-     assertEquals(51F, $opt$NegFloat(-51F));
-     assertEquals(-51F, $opt$NegFloat(51F));
-
-     assertEquals(-0.1F, $opt$NegFloat(0.1F));
-     assertEquals(0.1F, $opt$NegFloat(-0.1F));
-     assertEquals(343597.38362F, $opt$NegFloat(-343597.38362F));
-     assertEquals(-343597.38362F, $opt$NegFloat(343597.38362F));
-
-     assertEquals(-Float.MIN_NORMAL, $opt$NegFloat(Float.MIN_NORMAL));
-     assertEquals(Float.MIN_NORMAL, $opt$NegFloat(-Float.MIN_NORMAL));
-     assertEquals(-Float.MIN_VALUE, $opt$NegFloat(Float.MIN_VALUE));
-     assertEquals(Float.MIN_VALUE, $opt$NegFloat(-Float.MIN_VALUE));
-     assertEquals(-Float.MAX_VALUE, $opt$NegFloat(Float.MAX_VALUE));
-     assertEquals(Float.MAX_VALUE, $opt$NegFloat(-Float.MAX_VALUE));
-
-     assertEquals(Float.NEGATIVE_INFINITY, $opt$NegFloat(Float.POSITIVE_INFINITY));
-     assertEquals(Float.POSITIVE_INFINITY, $opt$NegFloat(Float.NEGATIVE_INFINITY));
-     assertIsNaN($opt$NegFloat(Float.NaN));
+  private static void $opt$noinline$InplaceNegOneLong(long a) {
+    if (doThrow) {
+      // Try defeating inlining.
+      throw new Error();
+    }
+    a = -a;
+    assertEquals(-1L, a);
   }
 
-  private static void negDouble() {
-     assertEquals("-0.0", $opt$NegDouble(0D));
-     assertEquals("0.0", $opt$NegDouble(-0D));
-     assertEquals(-1D, $opt$NegDouble(1D));
-     assertEquals(1D, $opt$NegDouble(-1D));
-     assertEquals(51D, $opt$NegDouble(-51D));
-     assertEquals(-51D, $opt$NegDouble(51D));
-
-     assertEquals(-0.1D, $opt$NegDouble(0.1D));
-     assertEquals(0.1D, $opt$NegDouble(-0.1D));
-     assertEquals(343597.38362D, $opt$NegDouble(-343597.38362D));
-     assertEquals(-343597.38362D, $opt$NegDouble(343597.38362D));
-
-     assertEquals(-Double.MIN_NORMAL, $opt$NegDouble(Double.MIN_NORMAL));
-     assertEquals(Double.MIN_NORMAL, $opt$NegDouble(-Double.MIN_NORMAL));
-     assertEquals(-Double.MIN_VALUE, $opt$NegDouble(Double.MIN_VALUE));
-     assertEquals(Double.MIN_VALUE, $opt$NegDouble(-Double.MIN_VALUE));
-     assertEquals(-Double.MAX_VALUE, $opt$NegDouble(Double.MAX_VALUE));
-     assertEquals(Double.MAX_VALUE, $opt$NegDouble(-Double.MAX_VALUE));
-
-     assertEquals(Double.NEGATIVE_INFINITY, $opt$NegDouble(Double.POSITIVE_INFINITY));
-     assertEquals(Double.POSITIVE_INFINITY, $opt$NegDouble(Double.NEGATIVE_INFINITY));
-     assertIsNaN($opt$NegDouble(Double.NaN));
-  }
-
-  static int $opt$NegInt(int a){
+  private static int $opt$noinline$NegInt(int a){
+    if (doThrow) {
+      // Try defeating inlining.
+      throw new Error();
+    }
     return -a;
   }
 
-  static long $opt$NegLong(long a){
+  private static long $opt$noinline$NegLong(long a){
+    if (doThrow) {
+      // Try defeating inlining.
+      throw new Error();
+    }
     return -a;
   }
 
-  static float $opt$NegFloat(float a){
+  private static float $opt$noinline$NegFloat(float a){
+    if (doThrow) {
+      // Try defeating inlining.
+      throw new Error();
+    }
     return -a;
   }
 
-  static double $opt$NegDouble(double a){
+  private static double $opt$noinline$NegDouble(double a){
+    if (doThrow) {
+      // Try defeating inlining.
+      throw new Error();
+    }
     return -a;
   }
 }
index 20dac42..4805d77 100644 (file)
@@ -70,6 +70,25 @@ public class Main {
     return y;
   }
 
+  /// CHECK-START: long Main.LongNegation() constant_folding (before)
+  /// CHECK-DAG:     <<Const42:j\d+>>  LongConstant 42
+  /// CHECK-DAG:     <<Neg:j\d+>>      Neg [<<Const42>>]
+  /// CHECK-DAG:                       Return [<<Neg>>]
+
+  /// CHECK-START: long Main.LongNegation() constant_folding (after)
+  /// CHECK-DAG:     <<ConstN42:j\d+>> LongConstant -42
+  /// CHECK-DAG:                       Return [<<ConstN42>>]
+
+  /// CHECK-START: long Main.LongNegation() constant_folding (after)
+  /// CHECK-NOT:                       Neg
+
+  public static long LongNegation() {
+    long x, y;
+    x = 42L;
+    y = -x;
+    return y;
+  }
+
 
   /**
    * Exercise constant folding on addition.
@@ -866,6 +885,7 @@ public class Main {
 
   public static void main(String[] args) {
     assertIntEquals(-42, IntNegation());
+    assertLongEquals(-42L, LongNegation());
 
     assertIntEquals(3, IntAddition1());
     assertIntEquals(14, IntAddition2());