Constant folding on unary operations in the optimizing compiler.
Change-Id: I4b77afa2a89f5ad2eedd4d6c0c6c382585419349
diff --git a/compiler/optimizing/constant_folding.cc b/compiler/optimizing/constant_folding.cc
index 0b3ad98..10a7e46 100644
--- a/compiler/optimizing/constant_folding.cc
+++ b/compiler/optimizing/constant_folding.cc
@@ -31,11 +31,19 @@
for (HInstructionIterator it(block->GetInstructions());
!it.Done(); it.Advance()) {
HInstruction* inst = it.Current();
- // Constant folding: replace `c <- a op b' with a compile-time
- // evaluation of `a op b' if `a' and `b' are constant.
if (inst->IsBinaryOperation()) {
+ // Constant folding: replace `op(a, b)' with a constant at
+ // compile time if `a' and `b' are both constants.
HConstant* constant =
- inst->AsBinaryOperation()->TryStaticEvaluation(graph_->GetArena());
+ inst->AsBinaryOperation()->TryStaticEvaluation();
+ if (constant != nullptr) {
+ inst->GetBlock()->ReplaceAndRemoveInstructionWith(inst, constant);
+ }
+ } else if (inst->IsUnaryOperation()) {
+ // Constant folding: replace `op(a)' with a constant at compile
+ // time if `a' is a constant.
+ HConstant* constant =
+ inst->AsUnaryOperation()->TryStaticEvaluation();
if (constant != nullptr) {
inst->GetBlock()->ReplaceAndRemoveInstructionWith(inst, constant);
}
diff --git a/compiler/optimizing/constant_folding_test.cc b/compiler/optimizing/constant_folding_test.cc
index ec2ff33..09bf2c8 100644
--- a/compiler/optimizing/constant_folding_test.cc
+++ b/compiler/optimizing/constant_folding_test.cc
@@ -72,6 +72,61 @@
/**
+ * Tiny three-register program exercising int constant folding on negation.
+ *
+ * 16-bit
+ * offset
+ * ------
+ * v0 <- 1 0. const/4 v0, #+1
+ * v1 <- -v0 1. neg-int v0, v1
+ * return v1 2. return v1
+ */
+TEST(ConstantFolding, IntConstantFoldingNegation) {
+ const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
+ Instruction::CONST_4 | 0 << 8 | 1 << 12,
+ Instruction::NEG_INT | 1 << 8 | 0 << 12,
+ Instruction::RETURN | 1 << 8);
+
+ std::string expected_before =
+ "BasicBlock 0, succ: 1\n"
+ " 2: IntConstant [5]\n"
+ " 10: SuspendCheck\n"
+ " 11: Goto 1\n"
+ "BasicBlock 1, pred: 0, succ: 2\n"
+ " 5: Neg(2) [8]\n"
+ " 8: Return(5)\n"
+ "BasicBlock 2, pred: 1\n"
+ " 9: Exit\n";
+
+ // Expected difference after constant folding.
+ diff_t expected_cf_diff = {
+ { " 2: IntConstant [5]\n", " 2: IntConstant\n" },
+ { " 5: Neg(2) [8]\n", " 12: IntConstant [8]\n" },
+ { " 8: Return(5)\n", " 8: Return(12)\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();
+ ASSERT_TRUE(inst->IsIntConstant());
+ ASSERT_EQ(inst->AsIntConstant()->GetValue(), -1);
+ };
+
+ // Expected difference after dead code elimination.
+ diff_t expected_dce_diff = {
+ { " 2: IntConstant\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);
+}
+
+/**
* Tiny three-register program exercising int constant folding on addition.
*
* 16-bit
diff --git a/compiler/optimizing/nodes.cc b/compiler/optimizing/nodes.cc
index 10c6014..a219b97 100644
--- a/compiler/optimizing/nodes.cc
+++ b/compiler/optimizing/nodes.cc
@@ -572,15 +572,26 @@
}
}
-HConstant* HBinaryOperation::TryStaticEvaluation(ArenaAllocator* allocator) const {
+HConstant* HUnaryOperation::TryStaticEvaluation() const {
+ if (GetInput()->IsIntConstant()) {
+ int32_t value = Evaluate(GetInput()->AsIntConstant()->GetValue());
+ return new(GetBlock()->GetGraph()->GetArena()) HIntConstant(value);
+ } else if (GetInput()->IsLongConstant()) {
+ LOG(FATAL) << "Static evaluation of long unary operations is not yet implemented.";
+ return nullptr;
+ }
+ return nullptr;
+}
+
+HConstant* HBinaryOperation::TryStaticEvaluation() const {
if (GetLeft()->IsIntConstant() && GetRight()->IsIntConstant()) {
int32_t value = Evaluate(GetLeft()->AsIntConstant()->GetValue(),
GetRight()->AsIntConstant()->GetValue());
- return new(allocator) HIntConstant(value);
+ return new(GetBlock()->GetGraph()->GetArena()) HIntConstant(value);
} else if (GetLeft()->IsLongConstant() && GetRight()->IsLongConstant()) {
int64_t value = Evaluate(GetLeft()->AsLongConstant()->GetValue(),
GetRight()->AsLongConstant()->GetValue());
- return new(allocator) HLongConstant(value);
+ return new(GetBlock()->GetGraph()->GetArena()) HLongConstant(value);
}
return nullptr;
}
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index 26d9bd1..3f29e53 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -1101,6 +1101,15 @@
virtual bool CanBeMoved() const { return true; }
virtual bool InstructionDataEquals(HInstruction* other) const { return true; }
+ // Try to statically evaluate `operation` and return a HConstant
+ // containing the result of this evaluation. If `operation` cannot
+ // be evaluated as a constant, return nullptr.
+ HConstant* TryStaticEvaluation() const;
+
+ // Apply this operation to `x`.
+ virtual int32_t Evaluate(int32_t x) const = 0;
+ virtual int64_t Evaluate(int64_t x) const = 0;
+
DECLARE_INSTRUCTION(UnaryOperation);
private:
@@ -1125,10 +1134,10 @@
virtual bool CanBeMoved() const { return true; }
virtual bool InstructionDataEquals(HInstruction* other) const { return true; }
- // Try to statically evaluate `operation` and return an HConstant
+ // Try to statically evaluate `operation` and return a HConstant
// containing the result of this evaluation. If `operation` cannot
// be evaluated as a constant, return nullptr.
- HConstant* TryStaticEvaluation(ArenaAllocator* allocator) const;
+ HConstant* TryStaticEvaluation() const;
// Apply this operation to `x` and `y`.
virtual int32_t Evaluate(int32_t x, int32_t y) const = 0;
@@ -1544,6 +1553,9 @@
explicit HNeg(Primitive::Type result_type, HInstruction* input)
: HUnaryOperation(result_type, input) {}
+ virtual int32_t Evaluate(int32_t x) const OVERRIDE { return -x; }
+ virtual int64_t Evaluate(int64_t x) const OVERRIDE { return -x; }
+
DECLARE_INSTRUCTION(Neg);
private: