diff options
-rw-r--r-- | compiler/optimizing/constant_folding.cc | 14 | ||||
-rw-r--r-- | compiler/optimizing/constant_folding_test.cc | 55 | ||||
-rw-r--r-- | compiler/optimizing/nodes.cc | 17 | ||||
-rw-r--r-- | compiler/optimizing/nodes.h | 16 |
4 files changed, 94 insertions, 8 deletions
diff --git a/compiler/optimizing/constant_folding.cc b/compiler/optimizing/constant_folding.cc index 0b3ad9809f..10a7e46299 100644 --- a/compiler/optimizing/constant_folding.cc +++ b/compiler/optimizing/constant_folding.cc @@ -31,11 +31,19 @@ void HConstantFolding::Run() { 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 ec2ff33590..09bf2c8d7d 100644 --- a/compiler/optimizing/constant_folding_test.cc +++ b/compiler/optimizing/constant_folding_test.cc @@ -72,6 +72,61 @@ static void TestCode(const uint16_t* data, /** + * 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 10c60140ec..a219b97cc8 100644 --- a/compiler/optimizing/nodes.cc +++ b/compiler/optimizing/nodes.cc @@ -572,15 +572,26 @@ void HGraphVisitor::VisitBasicBlock(HBasicBlock* block) { } } -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 26d9bd1b32..3f29e53d65 100644 --- a/compiler/optimizing/nodes.h +++ b/compiler/optimizing/nodes.h @@ -1101,6 +1101,15 @@ class HUnaryOperation : public HExpression<1> { 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 @@ class HBinaryOperation : public HExpression<2> { 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 @@ class HNeg : public HUnaryOperation { 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: |