} else if (cond->IsIntConstant()) {
HIntConstant* int_const = cond->AsIntConstant();
if (int_const->IsZero()) {
- return graph->GetIntConstant1();
+ return graph->GetIntConstant(1);
} else {
DCHECK(int_const->IsOne());
- return graph->GetIntConstant0();
+ return graph->GetIntConstant(0);
}
}
HParameterValue(0, Primitive::kPrimNot); // array
HInstruction* parameter2 = new (&allocator)
HParameterValue(0, Primitive::kPrimInt); // i
- HInstruction* constant_1 = new (&allocator) HIntConstant(1);
- HInstruction* constant_0 = new (&allocator) HIntConstant(0);
entry->AddInstruction(parameter1);
entry->AddInstruction(parameter2);
- entry->AddInstruction(constant_1);
- entry->AddInstruction(constant_0);
+
+ HInstruction* constant_1 = graph->GetIntConstant(1);
+ HInstruction* constant_0 = graph->GetIntConstant(0);
HBasicBlock* block1 = new (&allocator) HBasicBlock(graph);
graph->AddBlock(block1);
HParameterValue(0, Primitive::kPrimNot); // array
HInstruction* parameter2 = new (&allocator)
HParameterValue(0, Primitive::kPrimInt); // i
- HInstruction* constant_1 = new (&allocator) HIntConstant(1);
- HInstruction* constant_0 = new (&allocator) HIntConstant(0);
- HInstruction* constant_max_int = new (&allocator) HIntConstant(INT_MAX);
entry->AddInstruction(parameter1);
entry->AddInstruction(parameter2);
- entry->AddInstruction(constant_1);
- entry->AddInstruction(constant_0);
- entry->AddInstruction(constant_max_int);
+
+ HInstruction* constant_1 = graph->GetIntConstant(1);
+ HInstruction* constant_0 = graph->GetIntConstant(0);
+ HInstruction* constant_max_int = graph->GetIntConstant(INT_MAX);
HBasicBlock* block1 = new (&allocator) HBasicBlock(graph);
graph->AddBlock(block1);
HParameterValue(0, Primitive::kPrimNot); // array
HInstruction* parameter2 = new (&allocator)
HParameterValue(0, Primitive::kPrimInt); // i
- HInstruction* constant_1 = new (&allocator) HIntConstant(1);
- HInstruction* constant_0 = new (&allocator) HIntConstant(0);
- HInstruction* constant_max_int = new (&allocator) HIntConstant(INT_MAX);
entry->AddInstruction(parameter1);
entry->AddInstruction(parameter2);
- entry->AddInstruction(constant_1);
- entry->AddInstruction(constant_0);
- entry->AddInstruction(constant_max_int);
+
+ HInstruction* constant_1 = graph->GetIntConstant(1);
+ HInstruction* constant_0 = graph->GetIntConstant(0);
+ HInstruction* constant_max_int = graph->GetIntConstant(INT_MAX);
HBasicBlock* block1 = new (&allocator) HBasicBlock(graph);
graph->AddBlock(block1);
graph->AddBlock(entry);
graph->SetEntryBlock(entry);
HInstruction* parameter = new (&allocator) HParameterValue(0, Primitive::kPrimNot);
- HInstruction* constant_5 = new (&allocator) HIntConstant(5);
- HInstruction* constant_4 = new (&allocator) HIntConstant(4);
- HInstruction* constant_6 = new (&allocator) HIntConstant(6);
- HInstruction* constant_1 = new (&allocator) HIntConstant(1);
entry->AddInstruction(parameter);
- entry->AddInstruction(constant_5);
- entry->AddInstruction(constant_4);
- entry->AddInstruction(constant_6);
- entry->AddInstruction(constant_1);
+
+ HInstruction* constant_5 = graph->GetIntConstant(5);
+ HInstruction* constant_4 = graph->GetIntConstant(4);
+ HInstruction* constant_6 = graph->GetIntConstant(6);
+ HInstruction* constant_1 = graph->GetIntConstant(1);
HBasicBlock* block = new (&allocator) HBasicBlock(graph);
graph->AddBlock(block);
graph->AddBlock(entry);
graph->SetEntryBlock(entry);
HInstruction* parameter = new (allocator) HParameterValue(0, Primitive::kPrimNot);
- HInstruction* constant_initial = new (allocator) HIntConstant(initial);
- HInstruction* constant_increment = new (allocator) HIntConstant(increment);
- HInstruction* constant_10 = new (allocator) HIntConstant(10);
entry->AddInstruction(parameter);
- entry->AddInstruction(constant_initial);
- entry->AddInstruction(constant_increment);
- entry->AddInstruction(constant_10);
+
+ HInstruction* constant_initial = graph->GetIntConstant(initial);
+ HInstruction* constant_increment = graph->GetIntConstant(increment);
+ HInstruction* constant_10 = graph->GetIntConstant(10);
HBasicBlock* block = new (allocator) HBasicBlock(graph);
graph->AddBlock(block);
graph->AddBlock(entry);
graph->SetEntryBlock(entry);
HInstruction* parameter = new (allocator) HParameterValue(0, Primitive::kPrimNot);
- HInstruction* constant_initial = new (allocator) HIntConstant(initial);
- HInstruction* constant_increment = new (allocator) HIntConstant(increment);
- HInstruction* constant_minus_1 = new (allocator) HIntConstant(-1);
- HInstruction* constant_10 = new (allocator) HIntConstant(10);
entry->AddInstruction(parameter);
- entry->AddInstruction(constant_initial);
- entry->AddInstruction(constant_increment);
- entry->AddInstruction(constant_minus_1);
- entry->AddInstruction(constant_10);
+
+ HInstruction* constant_initial = graph->GetIntConstant(initial);
+ HInstruction* constant_increment = graph->GetIntConstant(increment);
+ HInstruction* constant_minus_1 = graph->GetIntConstant(-1);
+ HInstruction* constant_10 = graph->GetIntConstant(10);
HBasicBlock* block = new (allocator) HBasicBlock(graph);
graph->AddBlock(block);
HBasicBlock* entry = new (allocator) HBasicBlock(graph);
graph->AddBlock(entry);
graph->SetEntryBlock(entry);
- HInstruction* constant_10 = new (allocator) HIntConstant(10);
- HInstruction* constant_initial = new (allocator) HIntConstant(initial);
- HInstruction* constant_increment = new (allocator) HIntConstant(increment);
- entry->AddInstruction(constant_10);
- entry->AddInstruction(constant_initial);
- entry->AddInstruction(constant_increment);
+
+ HInstruction* constant_10 = graph->GetIntConstant(10);
+ HInstruction* constant_initial = graph->GetIntConstant(initial);
+ HInstruction* constant_increment = graph->GetIntConstant(increment);
HBasicBlock* block = new (allocator) HBasicBlock(graph);
graph->AddBlock(block);
graph->AddBlock(entry);
graph->SetEntryBlock(entry);
HInstruction* parameter = new (allocator) HParameterValue(0, Primitive::kPrimNot);
- HInstruction* constant_initial = new (allocator) HIntConstant(initial);
- HInstruction* constant_1 = new (allocator) HIntConstant(1);
- HInstruction* constant_10 = new (allocator) HIntConstant(10);
- HInstruction* constant_minus_1 = new (allocator) HIntConstant(-1);
entry->AddInstruction(parameter);
- entry->AddInstruction(constant_initial);
- entry->AddInstruction(constant_1);
- entry->AddInstruction(constant_10);
- entry->AddInstruction(constant_minus_1);
+
+ HInstruction* constant_initial = graph->GetIntConstant(initial);
+ HInstruction* constant_1 = graph->GetIntConstant(1);
+ HInstruction* constant_10 = graph->GetIntConstant(10);
+ HInstruction* constant_minus_1 = graph->GetIntConstant(-1);
HBasicBlock* block = new (allocator) HBasicBlock(graph);
graph->AddBlock(block);
graph->AddBlock(entry);
graph->SetEntryBlock(entry);
HInstruction* parameter = new (&allocator) HParameterValue(0, Primitive::kPrimNot);
- HInstruction* constant_0 = new (&allocator) HIntConstant(0);
- HInstruction* constant_minus_1 = new (&allocator) HIntConstant(-1);
- HInstruction* constant_1 = new (&allocator) HIntConstant(1);
entry->AddInstruction(parameter);
- entry->AddInstruction(constant_0);
- entry->AddInstruction(constant_minus_1);
- entry->AddInstruction(constant_1);
+
+ HInstruction* constant_0 = graph->GetIntConstant(0);
+ HInstruction* constant_minus_1 = graph->GetIntConstant(-1);
+ HInstruction* constant_1 = graph->GetIntConstant(1);
HBasicBlock* block = new (&allocator) HBasicBlock(graph);
graph->AddBlock(block);
DCHECK(fallthrough_target != nullptr);
PotentiallyAddSuspendCheck(branch_target, dex_pc);
HInstruction* value = LoadLocal(instruction.VRegA(), Primitive::kPrimInt);
- T* comparison = new (arena_) T(value, GetIntConstant(0));
+ T* comparison = new (arena_) T(value, graph_->GetIntConstant(0));
current_block_->AddInstruction(comparison);
HInstruction* ifinst = new (arena_) HIf(comparison);
current_block_->AddInstruction(ifinst);
template<typename T>
void HGraphBuilder::Binop_22s(const Instruction& instruction, bool reverse) {
HInstruction* first = LoadLocal(instruction.VRegB(), Primitive::kPrimInt);
- HInstruction* second = GetIntConstant(instruction.VRegC_22s());
+ HInstruction* second = graph_->GetIntConstant(instruction.VRegC_22s());
if (reverse) {
std::swap(first, second);
}
template<typename T>
void HGraphBuilder::Binop_22b(const Instruction& instruction, bool reverse) {
HInstruction* first = LoadLocal(instruction.VRegB(), Primitive::kPrimInt);
- HInstruction* second = GetIntConstant(instruction.VRegC_22b());
+ HInstruction* second = graph_->GetIntConstant(instruction.VRegC_22b());
if (reverse) {
std::swap(first, second);
}
HInstruction* second = nullptr;
if (second_is_constant) {
if (type == Primitive::kPrimInt) {
- second = GetIntConstant(second_vreg_or_constant);
+ second = graph_->GetIntConstant(second_vreg_or_constant);
} else {
- second = GetLongConstant(second_vreg_or_constant);
+ second = graph_->GetLongConstant(second_vreg_or_constant);
}
} else {
second = LoadLocal(second_vreg_or_constant, type);
bool is_range,
uint32_t* args,
uint32_t register_index) {
- HInstruction* length = GetIntConstant(number_of_vreg_arguments);
+ HInstruction* length = graph_->GetIntConstant(number_of_vreg_arguments);
QuickEntrypointEnum entrypoint = NeedsAccessCheck(type_index)
? kQuickAllocArrayWithAccessCheck
: kQuickAllocArray;
temps.Add(object);
for (size_t i = 0; i < number_of_vreg_arguments; ++i) {
HInstruction* value = LoadLocal(is_range ? register_index + i : args[i], type);
- HInstruction* index = GetIntConstant(i);
+ HInstruction* index = graph_->GetIntConstant(i);
current_block_->AddInstruction(
new (arena_) HArraySet(object, index, value, type, dex_pc));
}
Primitive::Type anticipated_type,
uint32_t dex_pc) {
for (uint32_t i = 0; i < element_count; ++i) {
- HInstruction* index = GetIntConstant(i);
- HInstruction* value = GetIntConstant(data[i]);
+ HInstruction* index = graph_->GetIntConstant(i);
+ HInstruction* value = graph_->GetIntConstant(data[i]);
current_block_->AddInstruction(new (arena_) HArraySet(
object, index, value, anticipated_type, dex_pc));
}
// Implementation of this DEX instruction seems to be that the bounds check is
// done before doing any stores.
- HInstruction* last_index = GetIntConstant(payload->element_count - 1);
+ HInstruction* last_index = graph_->GetIntConstant(payload->element_count - 1);
current_block_->AddInstruction(new (arena_) HBoundsCheck(last_index, length, dex_pc));
switch (payload->element_width) {
uint32_t element_count,
uint32_t dex_pc) {
for (uint32_t i = 0; i < element_count; ++i) {
- HInstruction* index = GetIntConstant(i);
- HInstruction* value = GetLongConstant(data[i]);
+ HInstruction* index = graph_->GetIntConstant(i);
+ HInstruction* value = graph_->GetLongConstant(data[i]);
current_block_->AddInstruction(new (arena_) HArraySet(
object, index, value, Primitive::kPrimLong, dex_pc));
}
PotentiallyAddSuspendCheck(case_target, dex_pc);
// The current case's value.
- HInstruction* this_case_value = GetIntConstant(case_value_int);
+ HInstruction* this_case_value = graph_->GetIntConstant(case_value_int);
// Compare value and this_case_value.
HEqual* comparison = new (arena_) HEqual(value, this_case_value);
switch (instruction.Opcode()) {
case Instruction::CONST_4: {
int32_t register_index = instruction.VRegA();
- HIntConstant* constant = GetIntConstant(instruction.VRegB_11n());
+ HIntConstant* constant = graph_->GetIntConstant(instruction.VRegB_11n());
UpdateLocal(register_index, constant);
break;
}
case Instruction::CONST_16: {
int32_t register_index = instruction.VRegA();
- HIntConstant* constant = GetIntConstant(instruction.VRegB_21s());
+ HIntConstant* constant = graph_->GetIntConstant(instruction.VRegB_21s());
UpdateLocal(register_index, constant);
break;
}
case Instruction::CONST: {
int32_t register_index = instruction.VRegA();
- HIntConstant* constant = GetIntConstant(instruction.VRegB_31i());
+ HIntConstant* constant = graph_->GetIntConstant(instruction.VRegB_31i());
UpdateLocal(register_index, constant);
break;
}
case Instruction::CONST_HIGH16: {
int32_t register_index = instruction.VRegA();
- HIntConstant* constant = GetIntConstant(instruction.VRegB_21h() << 16);
+ HIntConstant* constant = graph_->GetIntConstant(instruction.VRegB_21h() << 16);
UpdateLocal(register_index, constant);
break;
}
int64_t value = instruction.VRegB_21s();
value <<= 48;
value >>= 48;
- HLongConstant* constant = GetLongConstant(value);
+ HLongConstant* constant = graph_->GetLongConstant(value);
UpdateLocal(register_index, constant);
break;
}
int64_t value = instruction.VRegB_31i();
value <<= 32;
value >>= 32;
- HLongConstant* constant = GetLongConstant(value);
+ HLongConstant* constant = graph_->GetLongConstant(value);
UpdateLocal(register_index, constant);
break;
}
case Instruction::CONST_WIDE: {
int32_t register_index = instruction.VRegA();
- HLongConstant* constant = GetLongConstant(instruction.VRegB_51l());
+ HLongConstant* constant = graph_->GetLongConstant(instruction.VRegB_51l());
UpdateLocal(register_index, constant);
break;
}
case Instruction::CONST_WIDE_HIGH16: {
int32_t register_index = instruction.VRegA();
int64_t value = static_cast<int64_t>(instruction.VRegB_21h()) << 48;
- HLongConstant* constant = GetLongConstant(value);
+ HLongConstant* constant = graph_->GetLongConstant(value);
UpdateLocal(register_index, constant);
break;
}
return true;
} // NOLINT(readability/fn_size)
-HIntConstant* HGraphBuilder::GetIntConstant(int32_t constant) {
- switch (constant) {
- case 0: return graph_->GetIntConstant0();
- case 1: return graph_->GetIntConstant1();
- default: {
- HIntConstant* instruction = new (arena_) HIntConstant(constant);
- graph_->AddConstant(instruction);
- return instruction;
- }
- }
-}
-
-HLongConstant* HGraphBuilder::GetLongConstant(int64_t constant) {
- HLongConstant* instruction = new (arena_) HLongConstant(constant);
- graph_->AddConstant(instruction);
- return instruction;
-}
-
HLocal* HGraphBuilder::GetLocalAt(int register_index) const {
return locals_.Get(register_index);
}
void MaybeUpdateCurrentBlock(size_t index);
HBasicBlock* FindBlockStartingAt(int32_t index) const;
- HIntConstant* GetIntConstant(int32_t constant);
- HLongConstant* GetLongConstant(int64_t constant);
void InitializeLocals(uint16_t count);
HLocal* GetLocalAt(int register_index) const;
void UpdateLocal(int register_index, HInstruction* instruction) const;
HBasicBlock* first_block = new (&allocator) HBasicBlock(graph);
graph->AddBlock(first_block);
entry->AddSuccessor(first_block);
- HIntConstant* constant0 = new (&allocator) HIntConstant(0);
- entry->AddInstruction(constant0);
- HIntConstant* constant1 = new (&allocator) HIntConstant(1);
- entry->AddInstruction(constant1);
+ HIntConstant* constant0 = graph->GetIntConstant(0);
+ HIntConstant* constant1 = graph->GetIntConstant(1);
HEqual* equal = new (&allocator) HEqual(constant0, constant0);
first_block->AddInstruction(equal);
first_block->AddInstruction(new (&allocator) HIf(equal));
code_block->AddSuccessor(exit_block);
graph->SetExitBlock(exit_block);
- HIntConstant cst_lhs(lhs[i]);
- code_block->AddInstruction(&cst_lhs);
- HIntConstant cst_rhs(rhs[i]);
- code_block->AddInstruction(&cst_rhs);
- HLessThan cmp_lt(&cst_lhs, &cst_rhs);
+ HIntConstant* cst_lhs = graph->GetIntConstant(lhs[i]);
+ HIntConstant* cst_rhs = graph->GetIntConstant(rhs[i]);
+ HLessThan cmp_lt(cst_lhs, cst_rhs);
code_block->AddInstruction(&cmp_lt);
HReturn ret(&cmp_lt);
code_block->AddInstruction(&ret);
if_false_block->AddSuccessor(exit_block);
graph->SetExitBlock(exit_block);
- HIntConstant cst_lhs(lhs[i]);
- if_block->AddInstruction(&cst_lhs);
- HIntConstant cst_rhs(rhs[i]);
- if_block->AddInstruction(&cst_rhs);
- HLessThan cmp_lt(&cst_lhs, &cst_rhs);
+ HIntConstant* cst_lhs = graph->GetIntConstant(lhs[i]);
+ HIntConstant* cst_rhs = graph->GetIntConstant(rhs[i]);
+ HLessThan cmp_lt(cst_lhs, cst_rhs);
if_block->AddInstruction(&cmp_lt);
// We insert a temporary to separate the HIf from the HLessThan and force
// the materialization of the condition.
HIf if_lt(&cmp_lt);
if_block->AddInstruction(&if_lt);
- HIntConstant cst_lt(1);
- if_true_block->AddInstruction(&cst_lt);
- HReturn ret_lt(&cst_lt);
+ HIntConstant* cst_lt = graph->GetIntConstant(1);
+ HReturn ret_lt(cst_lt);
if_true_block->AddInstruction(&ret_lt);
- HIntConstant cst_ge(0);
- if_false_block->AddInstruction(&cst_ge);
- HReturn ret_ge(&cst_ge);
+ HIntConstant* cst_ge = graph->GetIntConstant(0);
+ HReturn ret_ge(cst_ge);
if_false_block->AddInstruction(&ret_ge);
auto hook_before_codegen = [](HGraph* graph_in) {
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();
+ HConstant* constant = inst->AsBinaryOperation()->TryStaticEvaluation();
if (constant != nullptr) {
- inst->GetBlock()->ReplaceAndRemoveInstructionWith(inst, constant);
+ inst->ReplaceWith(constant);
+ inst->GetBlock()->RemoveInstruction(inst);
} else {
inst->Accept(&simplifier);
}
} 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();
+ HConstant* constant = inst->AsUnaryOperation()->TryStaticEvaluation();
if (constant != nullptr) {
- inst->GetBlock()->ReplaceAndRemoveInstructionWith(inst, constant);
+ inst->ReplaceWith(constant);
+ inst->GetBlock()->RemoveInstruction(inst);
}
} else if (inst->IsDivZeroCheck()) {
// We can safely remove the check if the input is a non-null constant.
// REM dst, src, src
// with
// CONSTANT 0
- ArenaAllocator* allocator = GetGraph()->GetArena();
- block->ReplaceAndRemoveInstructionWith(instruction,
- HConstant::NewConstant(allocator, type, 0));
+ instruction->ReplaceWith(GetGraph()->GetConstant(type, 0));
+ block->RemoveInstruction(instruction);
}
}
}
HBasicBlock* block = instruction->GetBlock();
- ArenaAllocator* allocator = GetGraph()->GetArena();
// We assume that GVN has run before, so we only perform a pointer
// comparison. If for some reason the values are equal but the pointers are
// CONSTANT 0
// Note that we cannot optimise `x - x` to `0` for floating-point. It does
// not work when `x` is an infinity.
- block->ReplaceAndRemoveInstructionWith(instruction,
- HConstant::NewConstant(allocator, type, 0));
+ instruction->ReplaceWith(GetGraph()->GetConstant(type, 0));
+ block->RemoveInstruction(instruction);
}
}
// CONSTANT 0
Primitive::Type type = instruction->GetType();
HBasicBlock* block = instruction->GetBlock();
- ArenaAllocator* allocator = GetGraph()->GetArena();
-
- block->ReplaceAndRemoveInstructionWith(instruction,
- HConstant::NewConstant(allocator, type, 0));
+ instruction->ReplaceWith(GetGraph()->GetConstant(type, 0));
+ block->RemoveInstruction(instruction);
}
}
// 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" },
+ { " 10: SuspendCheck\n", " 10: SuspendCheck\n"
+ " 12: IntConstant [8]\n" },
+ { " 5: Neg(2) [8]\n", removed },
{ " 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();
+ HInstruction* inst = graph->GetBlock(1)->GetFirstInstruction()->InputAt(0);
ASSERT_TRUE(inst->IsIntConstant());
ASSERT_EQ(inst->AsIntConstant()->GetValue(), -1);
};
diff_t expected_cf_diff = {
{ " 3: IntConstant [9]\n", " 3: IntConstant\n" },
{ " 5: IntConstant [9]\n", " 5: IntConstant\n" },
- { " 9: Add(3, 5) [12]\n", " 16: IntConstant [12]\n" },
+ { " 14: SuspendCheck\n", " 14: SuspendCheck\n"
+ " 16: IntConstant [12]\n" },
+ { " 9: Add(3, 5) [12]\n", removed },
{ " 12: Return(9)\n", " 12: Return(16)\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();
+ HInstruction* inst = graph->GetBlock(1)->GetFirstInstruction()->InputAt(0);
ASSERT_TRUE(inst->IsIntConstant());
ASSERT_EQ(inst->AsIntConstant()->GetValue(), 3);
};
* v0 <- 1 0. const/4 v0, #+1
* v1 <- 2 1. const/4 v1, #+2
* v0 <- v0 + v1 2. add-int/2addr v0, v1
- * v1 <- 3 3. const/4 v1, #+3
- * v2 <- 4 4. const/4 v2, #+4
+ * v1 <- 4 3. const/4 v1, #+4
+ * v2 <- 5 4. const/4 v2, #+5
* v1 <- v1 + v2 5. add-int/2addr v1, v2
* v2 <- v0 + v1 6. add-int v2, v0, v1
* return v2 8. return v2
Instruction::CONST_4 | 0 << 8 | 1 << 12,
Instruction::CONST_4 | 1 << 8 | 2 << 12,
Instruction::ADD_INT_2ADDR | 0 << 8 | 1 << 12,
- Instruction::CONST_4 | 1 << 8 | 3 << 12,
- Instruction::CONST_4 | 2 << 8 | 4 << 12,
+ Instruction::CONST_4 | 1 << 8 | 4 << 12,
+ Instruction::CONST_4 | 2 << 8 | 5 << 12,
Instruction::ADD_INT_2ADDR | 1 << 8 | 2 << 12,
Instruction::ADD_INT | 2 << 8, 0 | 1 << 8,
Instruction::RETURN | 2 << 8);
{ " 5: IntConstant [9]\n", " 5: IntConstant\n" },
{ " 11: IntConstant [17]\n", " 11: IntConstant\n" },
{ " 13: IntConstant [17]\n", " 13: IntConstant\n" },
- { " 9: Add(3, 5) [21]\n", " 28: IntConstant\n" },
- { " 17: Add(11, 13) [21]\n", " 29: IntConstant\n" },
- { " 21: Add(9, 17) [24]\n", " 30: IntConstant [24]\n" },
+ { " 26: SuspendCheck\n", " 26: SuspendCheck\n"
+ " 28: IntConstant\n"
+ " 29: IntConstant\n"
+ " 30: IntConstant [24]\n" },
+ { " 9: Add(3, 5) [21]\n", removed },
+ { " 17: Add(11, 13) [21]\n", removed },
+ { " 21: Add(9, 17) [24]\n", removed },
{ " 24: Return(21)\n", " 24: Return(30)\n" }
};
std::string expected_after_cf = Patch(expected_before, expected_cf_diff);
// Check the values of the computed constants.
auto check_after_cf = [](HGraph* graph) {
- HInstruction* inst1 = graph->GetBlock(1)->GetFirstInstruction();
+ HInstruction* inst1 = graph->GetBlock(1)->GetFirstInstruction()->InputAt(0);
ASSERT_TRUE(inst1->IsIntConstant());
- ASSERT_EQ(inst1->AsIntConstant()->GetValue(), 3);
- HInstruction* inst2 = inst1->GetNext();
+ ASSERT_EQ(inst1->AsIntConstant()->GetValue(), 12);
+ HInstruction* inst2 = inst1->GetPrevious();
ASSERT_TRUE(inst2->IsIntConstant());
- ASSERT_EQ(inst2->AsIntConstant()->GetValue(), 7);
- HInstruction* inst3 = inst2->GetNext();
+ ASSERT_EQ(inst2->AsIntConstant()->GetValue(), 9);
+ HInstruction* inst3 = inst2->GetPrevious();
ASSERT_TRUE(inst3->IsIntConstant());
- ASSERT_EQ(inst3->AsIntConstant()->GetValue(), 10);
+ ASSERT_EQ(inst3->AsIntConstant()->GetValue(), 3);
};
// Expected difference after dead code elimination.
diff_t expected_cf_diff = {
{ " 3: IntConstant [9]\n", " 3: IntConstant\n" },
{ " 5: IntConstant [9]\n", " 5: IntConstant\n" },
- { " 9: Sub(3, 5) [12]\n", " 16: IntConstant [12]\n" },
+ { " 14: SuspendCheck\n", " 14: SuspendCheck\n"
+ " 16: IntConstant [12]\n" },
+ { " 9: Sub(3, 5) [12]\n", removed },
{ " 12: Return(9)\n", " 12: Return(16)\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();
+ HInstruction* inst = graph->GetBlock(1)->GetFirstInstruction()->InputAt(0);
ASSERT_TRUE(inst->IsIntConstant());
ASSERT_EQ(inst->AsIntConstant()->GetValue(), 1);
};
diff_t expected_cf_diff = {
{ " 6: LongConstant [12]\n", " 6: LongConstant\n" },
{ " 8: LongConstant [12]\n", " 8: LongConstant\n" },
- { " 12: Add(6, 8) [15]\n", " 19: LongConstant [15]\n" },
+ { " 17: SuspendCheck\n", " 17: SuspendCheck\n"
+ " 19: LongConstant [15]\n" },
+ { " 12: Add(6, 8) [15]\n", removed },
{ " 15: Return(12)\n", " 15: Return(19)\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();
+ HInstruction* inst = graph->GetBlock(1)->GetFirstInstruction()->InputAt(0);
ASSERT_TRUE(inst->IsLongConstant());
ASSERT_EQ(inst->AsLongConstant()->GetValue(), 3);
};
diff_t expected_cf_diff = {
{ " 6: LongConstant [12]\n", " 6: LongConstant\n" },
{ " 8: LongConstant [12]\n", " 8: LongConstant\n" },
- { " 12: Sub(6, 8) [15]\n", " 19: LongConstant [15]\n" },
+ { " 17: SuspendCheck\n", " 17: SuspendCheck\n"
+ " 19: LongConstant [15]\n" },
+ { " 12: Sub(6, 8) [15]\n", removed },
{ " 15: Return(12)\n", " 15: Return(19)\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();
+ HInstruction* inst = graph->GetBlock(1)->GetFirstInstruction()->InputAt(0);
ASSERT_TRUE(inst->IsLongConstant());
ASSERT_EQ(inst->AsLongConstant()->GetValue(), 1);
};
* 16-bit
* offset
* ------
- * v0 <- 0 0. const/4 v0, #+0
- * v1 <- 1 1. const/4 v1, #+1
+ * v0 <- 1 0. const/4 v0, #+1
+ * v1 <- 2 1. const/4 v1, #+2
* v2 <- v0 + v1 2. add-int v2, v0, v1
* goto L2 4. goto +4
- * L1: v1 <- v0 + 3 5. add-int/lit16 v1, v0, #+3
+ * L1: v1 <- v0 + 5 5. add-int/lit16 v1, v0, #+5
* goto L3 7. goto +4
- * L2: v0 <- v2 + 2 8. add-int/lit16 v0, v2, #+2
+ * L2: v0 <- v2 + 4 8. add-int/lit16 v0, v2, #+4
* goto L1 10. goto +(-5)
- * L3: v2 <- v1 + 4 11. add-int/lit16 v2, v1, #+4
+ * L3: v2 <- v1 + 8 11. add-int/lit16 v2, v1, #+8
* return v2 13. return v2
*/
TEST(ConstantFolding, IntConstantFoldingAndJumps) {
const uint16_t data[] = THREE_REGISTERS_CODE_ITEM(
- Instruction::CONST_4 | 0 << 8 | 0 << 12,
- Instruction::CONST_4 | 1 << 8 | 1 << 12,
+ Instruction::CONST_4 | 0 << 8 | 1 << 12,
+ Instruction::CONST_4 | 1 << 8 | 2 << 12,
Instruction::ADD_INT | 2 << 8, 0 | 1 << 8,
Instruction::GOTO | 4 << 8,
- Instruction::ADD_INT_LIT16 | 1 << 8 | 0 << 12, 3,
+ Instruction::ADD_INT_LIT16 | 1 << 8 | 0 << 12, 5,
Instruction::GOTO | 4 << 8,
- Instruction::ADD_INT_LIT16 | 0 << 8 | 2 << 12, 2,
+ Instruction::ADD_INT_LIT16 | 0 << 8 | 2 << 12, 4,
static_cast<uint16_t>(Instruction::GOTO | -5 << 8),
- Instruction::ADD_INT_LIT16 | 2 << 8 | 1 << 12, 4,
+ Instruction::ADD_INT_LIT16 | 2 << 8 | 1 << 12, 8,
Instruction::RETURN | 2 << 8);
std::string expected_before =
"BasicBlock 0, succ: 1\n"
- " 3: IntConstant [9]\n" // v0 <- 0
- " 5: IntConstant [9]\n" // v1 <- 1
- " 13: IntConstant [14]\n" // const 3
- " 18: IntConstant [19]\n" // const 2
- " 24: IntConstant [25]\n" // const 4
+ " 3: IntConstant [9]\n" // v0 <- 1
+ " 5: IntConstant [9]\n" // v1 <- 2
+ " 13: IntConstant [14]\n" // const 5
+ " 18: IntConstant [19]\n" // const 4
+ " 24: IntConstant [25]\n" // const 8
" 30: SuspendCheck\n"
" 31: Goto 1\n"
"BasicBlock 1, pred: 0, succ: 3\n"
- " 9: Add(3, 5) [19]\n" // v2 <- v0 + v1 = 0 + 1 = 1
+ " 9: Add(3, 5) [19]\n" // v2 <- v0 + v1 = 1 + 2 = 3
" 11: Goto 3\n" // goto L2
"BasicBlock 2, pred: 3, succ: 4\n" // L1:
- " 14: Add(19, 13) [25]\n" // v1 <- v0 + 3 = 3 + 3 = 6
+ " 14: Add(19, 13) [25]\n" // v1 <- v0 + 3 = 7 + 5 = 12
" 16: Goto 4\n" // goto L3
"BasicBlock 3, pred: 1, succ: 2\n" // L2:
- " 19: Add(9, 18) [14]\n" // v0 <- v2 + 2 = 1 + 2 = 3
+ " 19: Add(9, 18) [14]\n" // v0 <- v2 + 2 = 3 + 4 = 7
" 21: SuspendCheck\n"
" 22: Goto 2\n" // goto L1
"BasicBlock 4, pred: 2, succ: 5\n" // L3:
- " 25: Add(14, 24) [28]\n" // v2 <- v1 + 4 = 6 + 4 = 10
+ " 25: Add(14, 24) [28]\n" // v2 <- v1 + 4 = 12 + 8 = 20
" 28: Return(25)\n" // return v2
"BasicBlock 5, pred: 4\n"
" 29: Exit\n";
{ " 13: IntConstant [14]\n", " 13: IntConstant\n" },
{ " 18: IntConstant [19]\n", " 18: IntConstant\n" },
{ " 24: IntConstant [25]\n", " 24: IntConstant\n" },
- { " 9: Add(3, 5) [19]\n", " 32: IntConstant []\n" },
- { " 14: Add(19, 13) [25]\n", " 34: IntConstant\n" },
- { " 19: Add(9, 18) [14]\n", " 33: IntConstant []\n" },
- { " 25: Add(14, 24) [28]\n", " 35: IntConstant [28]\n" },
+ { " 30: SuspendCheck\n", " 30: SuspendCheck\n"
+ " 32: IntConstant []\n"
+ " 33: IntConstant []\n"
+ " 34: IntConstant\n"
+ " 35: IntConstant [28]\n" },
+ { " 9: Add(3, 5) [19]\n", removed },
+ { " 14: Add(19, 13) [25]\n", removed },
+ { " 19: Add(9, 18) [14]\n", removed },
+ { " 25: Add(14, 24) [28]\n", removed },
{ " 28: Return(25)\n", " 28: Return(35)\n"}
};
std::string expected_after_cf = Patch(expected_before, expected_cf_diff);
// Check the values of the computed constants.
auto check_after_cf = [](HGraph* graph) {
- HInstruction* inst1 = graph->GetBlock(1)->GetFirstInstruction();
+ HInstruction* inst1 = graph->GetBlock(4)->GetFirstInstruction()->InputAt(0);
ASSERT_TRUE(inst1->IsIntConstant());
- ASSERT_EQ(inst1->AsIntConstant()->GetValue(), 1);
- HInstruction* inst2 = graph->GetBlock(2)->GetFirstInstruction();
+ ASSERT_EQ(inst1->AsIntConstant()->GetValue(), 20);
+ HInstruction* inst2 = inst1->GetPrevious();
ASSERT_TRUE(inst2->IsIntConstant());
- ASSERT_EQ(inst2->AsIntConstant()->GetValue(), 6);
- HInstruction* inst3 = graph->GetBlock(3)->GetFirstInstruction();
+ ASSERT_EQ(inst2->AsIntConstant()->GetValue(), 12);
+ HInstruction* inst3 = inst2->GetPrevious();
ASSERT_TRUE(inst3->IsIntConstant());
- ASSERT_EQ(inst3->AsIntConstant()->GetValue(), 3);
- HInstruction* inst4 = graph->GetBlock(4)->GetFirstInstruction();
+ ASSERT_EQ(inst3->AsIntConstant()->GetValue(), 7);
+ HInstruction* inst4 = inst3->GetPrevious();
ASSERT_TRUE(inst4->IsIntConstant());
- ASSERT_EQ(inst4->AsIntConstant()->GetValue(), 10);
+ ASSERT_EQ(inst4->AsIntConstant()->GetValue(), 3);
};
// Expected difference after dead code elimination.
// Expected difference after constant folding.
diff_t expected_cf_diff = {
- { " 3: IntConstant [15, 22, 8]\n", " 3: IntConstant [15, 22]\n" },
+ { " 3: IntConstant [15, 22, 8]\n", " 3: IntConstant [9, 15, 22]\n" },
{ " 5: IntConstant [22, 8]\n", " 5: IntConstant [22]\n" },
- { " 8: GreaterThanOrEqual(3, 5) [9]\n", " 23: IntConstant [9]\n" },
- { " 9: If(8)\n", " 9: If(23)\n" }
+ { " 8: GreaterThanOrEqual(3, 5) [9]\n", removed },
+ { " 9: If(8)\n", " 9: If(3)\n" }
};
std::string expected_after_cf = Patch(expected_before, expected_cf_diff);
// Check the values of the computed constants.
auto check_after_cf = [](HGraph* graph) {
- HInstruction* inst = graph->GetBlock(1)->GetFirstInstruction();
+ HInstruction* inst = graph->GetBlock(1)->GetFirstInstruction()->InputAt(0);
ASSERT_TRUE(inst->IsIntConstant());
ASSERT_EQ(inst->AsIntConstant()->GetValue(), 1);
};
// Expected difference after dead code elimination.
diff_t expected_dce_diff = {
- { " 3: IntConstant [15, 22]\n", " 3: IntConstant [22]\n" },
- { " 22: Phi(3, 5) [15]\n", " 22: Phi(3, 5)\n" },
- { " 15: Add(22, 3)\n", removed }
+ { " 3: IntConstant [9, 15, 22]\n", " 3: IntConstant [9, 22]\n" },
+ { " 22: Phi(3, 5) [15]\n", " 22: Phi(3, 5)\n" },
+ { " 15: Add(22, 3)\n", removed }
};
std::string expected_after_dce = Patch(expected_after_cf, expected_dce_diff);
}
// Ensure `block` ends with a branch instruction.
- HInstruction* last_inst = block->GetLastInstruction();
- if (last_inst == nullptr || !last_inst->IsControlFlow()) {
+ if (!block->EndsWithControlFlowInstruction()) {
AddError(StringPrintf("Block %d does not end with a branch instruction.",
block->GetBlockId()));
}
}
}
+void SSAChecker::VisitConstant(HConstant* instruction) {
+ HBasicBlock* block = instruction->GetBlock();
+ if (!block->IsEntryBlock()) {
+ AddError(StringPrintf(
+ "%s %d should be in the entry block but is in block %d.",
+ instruction->DebugName(),
+ instruction->GetId(),
+ block->GetBlockId()));
+ }
+}
+
} // namespace art
void VisitBinaryOperation(HBinaryOperation* op) OVERRIDE;
void VisitCondition(HCondition* op) OVERRIDE;
void VisitIf(HIf* instruction) OVERRIDE;
+ void VisitConstant(HConstant* instruction) OVERRIDE;
private:
DISALLOW_COPY_AND_ASSIGN(SSAChecker);
static HBasicBlock* createIfBlock(HGraph* graph, ArenaAllocator* allocator) {
HBasicBlock* if_block = new (allocator) HBasicBlock(graph);
graph->AddBlock(if_block);
- HInstruction* instr = new (allocator) HIntConstant(4);
- if_block->AddInstruction(instr);
+ HInstruction* instr = graph->GetIntConstant(4);
HInstruction* equal = new (allocator) HEqual(instr, instr);
if_block->AddInstruction(equal);
instr = new (allocator) HIf(equal);
return block;
}
+static HBasicBlock* createEntryBlock(HGraph* graph, ArenaAllocator* allocator) {
+ HBasicBlock* block = createGotoBlock(graph, allocator);
+ graph->SetEntryBlock(block);
+ return block;
+}
+
static HBasicBlock* createReturnBlock(HGraph* graph, ArenaAllocator* allocator) {
HBasicBlock* block = new (allocator) HBasicBlock(graph);
graph->AddBlock(block);
ArenaAllocator allocator(&pool);
HGraph* graph = new (&allocator) HGraph(&allocator);
- HBasicBlock* entry_block = createGotoBlock(graph, &allocator);
+ HBasicBlock* entry_block = createEntryBlock(graph, &allocator);
HBasicBlock* if_block = createIfBlock(graph, &allocator);
HBasicBlock* if_true = createGotoBlock(graph, &allocator);
HBasicBlock* return_block = createReturnBlock(graph, &allocator);
ArenaAllocator allocator(&pool);
HGraph* graph = new (&allocator) HGraph(&allocator);
- HBasicBlock* entry_block = createGotoBlock(graph, &allocator);
+ HBasicBlock* entry_block = createEntryBlock(graph, &allocator);
HBasicBlock* if_block = createIfBlock(graph, &allocator);
HBasicBlock* if_false = createGotoBlock(graph, &allocator);
HBasicBlock* return_block = createReturnBlock(graph, &allocator);
ArenaAllocator allocator(&pool);
HGraph* graph = new (&allocator) HGraph(&allocator);
- HBasicBlock* entry_block = createGotoBlock(graph, &allocator);
+ HBasicBlock* entry_block = createEntryBlock(graph, &allocator);
HBasicBlock* if_block = createIfBlock(graph, &allocator);
HBasicBlock* return_block = createReturnBlock(graph, &allocator);
HBasicBlock* exit_block = createExitBlock(graph, &allocator);
- graph->SetEntryBlock(entry_block);
entry_block->AddSuccessor(if_block);
if_block->AddSuccessor(if_block);
if_block->AddSuccessor(return_block);
ArenaAllocator allocator(&pool);
HGraph* graph = new (&allocator) HGraph(&allocator);
- HBasicBlock* entry_block = createGotoBlock(graph, &allocator);
+ HBasicBlock* entry_block = createEntryBlock(graph, &allocator);
HBasicBlock* if_block = createIfBlock(graph, &allocator);
HBasicBlock* return_block = createReturnBlock(graph, &allocator);
HBasicBlock* exit_block = createExitBlock(graph, &allocator);
- graph->SetEntryBlock(entry_block);
entry_block->AddSuccessor(if_block);
if_block->AddSuccessor(return_block);
if_block->AddSuccessor(if_block);
ArenaAllocator allocator(&pool);
HGraph* graph = new (&allocator) HGraph(&allocator);
- HBasicBlock* entry_block = createGotoBlock(graph, &allocator);
+ HBasicBlock* entry_block = createEntryBlock(graph, &allocator);
HBasicBlock* first_if_block = createIfBlock(graph, &allocator);
HBasicBlock* if_block = createIfBlock(graph, &allocator);
HBasicBlock* loop_block = createGotoBlock(graph, &allocator);
HBasicBlock* return_block = createReturnBlock(graph, &allocator);
- graph->SetEntryBlock(entry_block);
entry_block->AddSuccessor(first_if_block);
first_if_block->AddSuccessor(if_block);
first_if_block->AddSuccessor(loop_block);
ArenaAllocator allocator(&pool);
HGraph* graph = new (&allocator) HGraph(&allocator);
- HBasicBlock* entry_block = createGotoBlock(graph, &allocator);
+ HBasicBlock* entry_block = createEntryBlock(graph, &allocator);
HBasicBlock* first_if_block = createIfBlock(graph, &allocator);
HBasicBlock* if_block = createIfBlock(graph, &allocator);
HBasicBlock* loop_block = createGotoBlock(graph, &allocator);
HBasicBlock* return_block = createReturnBlock(graph, &allocator);
- graph->SetEntryBlock(entry_block);
entry_block->AddSuccessor(first_if_block);
first_if_block->AddSuccessor(if_block);
first_if_block->AddSuccessor(loop_block);
// MUL dst, src, pow_of_2
// with
// SHL dst, src, log2(pow_of_2)
- HIntConstant* shift = new (allocator) HIntConstant(WhichPowerOf2(factor));
- block->InsertInstructionBefore(shift, instruction);
+ HIntConstant* shift = GetGraph()->GetIntConstant(WhichPowerOf2(factor));
HShl* shl = new(allocator) HShl(type, input_other, shift);
block->ReplaceAndRemoveInstructionWith(instruction, shl);
}
return true;
}
-void HGraph::AddConstant(HConstant* instruction) {
- HInstruction* last_instruction = entry_block_->GetLastInstruction();
- if (last_instruction == nullptr || !last_instruction->IsControlFlow()) {
- // Called from the builder. Insert at the end of the block.
- entry_block_->AddInstruction(instruction);
+void HGraph::InsertConstant(HConstant* constant) {
+ // New constants are inserted before the final control-flow instruction
+ // of the graph, or at its end if called from the graph builder.
+ if (entry_block_->EndsWithControlFlowInstruction()) {
+ entry_block_->InsertInstructionBefore(constant, entry_block_->GetLastInstruction());
} else {
- // Entry block ends with control-flow. Insert before the last instruction.
- entry_block_->InsertInstructionBefore(instruction, last_instruction);
+ entry_block_->AddInstruction(constant);
}
}
HNullConstant* HGraph::GetNullConstant() {
if (cached_null_constant_ == nullptr) {
cached_null_constant_ = new (arena_) HNullConstant();
- AddConstant(cached_null_constant_);
+ InsertConstant(cached_null_constant_);
}
return cached_null_constant_;
}
-HIntConstant* HGraph::GetIntConstant0() {
- if (cached_int_constant0_ == nullptr) {
- cached_int_constant0_ = new (arena_) HIntConstant(0);
- AddConstant(cached_int_constant0_);
+template <class InstructionType, typename ValueType>
+InstructionType* HGraph::CreateConstant(ValueType value,
+ ArenaSafeMap<ValueType, InstructionType*>* cache) {
+ // Try to find an existing constant of the given value.
+ InstructionType* constant = nullptr;
+ auto cached_constant = cache->find(value);
+ if (cached_constant != cache->end()) {
+ constant = cached_constant->second;
}
- return cached_int_constant0_;
+
+ // If not found or previously deleted, create and cache a new instruction.
+ if (constant == nullptr || constant->GetBlock() == nullptr) {
+ constant = new (arena_) InstructionType(value);
+ cache->Overwrite(value, constant);
+ InsertConstant(constant);
+ }
+ return constant;
}
-HIntConstant* HGraph::GetIntConstant1() {
- if (cached_int_constant1_ == nullptr) {
- cached_int_constant1_ = new (arena_) HIntConstant(1);
- AddConstant(cached_int_constant1_);
+HConstant* HGraph::GetConstant(Primitive::Type type, int64_t value) {
+ switch (type) {
+ case Primitive::Type::kPrimBoolean:
+ DCHECK(IsUint<1>(value));
+ FALLTHROUGH_INTENDED;
+ case Primitive::Type::kPrimByte:
+ case Primitive::Type::kPrimChar:
+ case Primitive::Type::kPrimShort:
+ case Primitive::Type::kPrimInt:
+ DCHECK(IsInt(Primitive::ComponentSize(type) * kBitsPerByte, value));
+ return GetIntConstant(static_cast<int32_t>(value));
+
+ case Primitive::Type::kPrimLong:
+ return GetLongConstant(value);
+
+ default:
+ LOG(FATAL) << "Unsupported constant type";
+ UNREACHABLE();
}
- return cached_int_constant1_;
}
void HLoopInformation::Add(HBasicBlock* block) {
HConstant* HUnaryOperation::TryStaticEvaluation() const {
if (GetInput()->IsIntConstant()) {
int32_t value = Evaluate(GetInput()->AsIntConstant()->GetValue());
- return new(GetBlock()->GetGraph()->GetArena()) HIntConstant(value);
+ return GetBlock()->GetGraph()->GetIntConstant(value);
} else if (GetInput()->IsLongConstant()) {
// TODO: Implement static evaluation of long unary operations.
//
if (GetLeft()->IsIntConstant() && GetRight()->IsIntConstant()) {
int32_t value = Evaluate(GetLeft()->AsIntConstant()->GetValue(),
GetRight()->AsIntConstant()->GetValue());
- return new(GetBlock()->GetGraph()->GetArena()) HIntConstant(value);
+ return GetBlock()->GetGraph()->GetIntConstant(value);
} else if (GetLeft()->IsLongConstant() && GetRight()->IsLongConstant()) {
int64_t value = Evaluate(GetLeft()->AsLongConstant()->GetValue(),
GetRight()->AsLongConstant()->GetValue());
if (GetResultType() == Primitive::kPrimLong) {
- return new(GetBlock()->GetGraph()->GetArena()) HLongConstant(value);
+ return GetBlock()->GetGraph()->GetLongConstant(value);
} else {
DCHECK_EQ(GetResultType(), Primitive::kPrimInt);
- return new(GetBlock()->GetGraph()->GetArena()) HIntConstant(value);
+ return GetBlock()->GetGraph()->GetIntConstant(static_cast<int32_t>(value));
}
}
return nullptr;
return this == if_->GetPreviousDisregardingMoves();
}
-HConstant* HConstant::NewConstant(ArenaAllocator* allocator, Primitive::Type type, int64_t val) {
- if (type == Primitive::kPrimInt) {
- DCHECK(IsInt<32>(val));
- return new (allocator) HIntConstant(val);
- } else {
- DCHECK_EQ(type, Primitive::kPrimLong);
- return new (allocator) HLongConstant(val);
- }
-}
-
bool HInstruction::Equals(HInstruction* other) const {
if (!InstructionTypeEquals(other)) return false;
DCHECK_EQ(GetKind(), other->GetKind());
&& (loop_info == nullptr || !loop_info->IsBackEdge(*this));
}
+bool HBasicBlock::EndsWithControlFlowInstruction() const {
+ return !GetInstructions().IsEmpty() && GetLastInstruction()->IsControlFlow();
+}
+
bool HBasicBlock::EndsWithIf() const {
return !GetInstructions().IsEmpty() && GetLastInstruction()->IsIf();
}
#ifndef ART_COMPILER_OPTIMIZING_NODES_H_
#define ART_COMPILER_OPTIMIZING_NODES_H_
+#include "base/arena_containers.h"
#include "base/arena_object.h"
#include "entrypoints/quick/quick_entrypoints_enum.h"
#include "handle.h"
class GraphChecker;
class HBasicBlock;
+class HDoubleConstant;
class HEnvironment;
+class HFloatConstant;
+class HGraphVisitor;
class HInstruction;
class HIntConstant;
class HInvoke;
-class HGraphVisitor;
+class HLongConstant;
class HNullConstant;
class HPhi;
class HSuspendCheck;
class LiveInterval;
class LocationSummary;
+class SsaBuilder;
static const int kDefaultNumberOfBlocks = 8;
static const int kDefaultNumberOfSuccessors = 2;
temporaries_vreg_slots_(0),
has_array_accesses_(false),
debuggable_(debuggable),
- current_instruction_id_(start_instruction_id) {}
+ current_instruction_id_(start_instruction_id),
+ cached_null_constant_(nullptr),
+ cached_int_constants_(std::less<int32_t>(), arena->Adapter()),
+ cached_long_constants_(std::less<int64_t>(), arena->Adapter()) {}
ArenaAllocator* GetArena() const { return arena_; }
const GrowableArray<HBasicBlock*>& GetBlocks() const { return blocks_; }
void SetExitBlock(HBasicBlock* block) { exit_block_ = block; }
void AddBlock(HBasicBlock* block);
- void AddConstant(HConstant* instruction);
// Try building the SSA form of this graph, with dominance computation and loop
// recognition. Returns whether it was successful in doing all these steps.
bool IsDebuggable() const { return debuggable_; }
+ // Returns a constant of the given type and value. If it does not exist
+ // already, it is created and inserted into the graph. Only integral types
+ // are currently supported.
+ HConstant* GetConstant(Primitive::Type type, int64_t value);
HNullConstant* GetNullConstant();
- HIntConstant* GetIntConstant0();
- HIntConstant* GetIntConstant1();
+ HIntConstant* GetIntConstant(int32_t value) {
+ return CreateConstant(value, &cached_int_constants_);
+ }
+ HLongConstant* GetLongConstant(int64_t value) {
+ return CreateConstant(value, &cached_long_constants_);
+ }
private:
HBasicBlock* FindCommonDominator(HBasicBlock* first, HBasicBlock* second) const;
void RemoveInstructionsAsUsersFromDeadBlocks(const ArenaBitVector& visited) const;
void RemoveDeadBlocks(const ArenaBitVector& visited) const;
+ template <class InstType, typename ValueType>
+ InstType* CreateConstant(ValueType value, ArenaSafeMap<ValueType, InstType*>* cache);
+ void InsertConstant(HConstant* instruction);
+
ArenaAllocator* const arena_;
// List of blocks in insertion order.
// The current id to assign to a newly added instruction. See HInstruction.id_.
int32_t current_instruction_id_;
- // Cached null constant that might be created when building SSA form.
- HNullConstant* cached_null_constant_;
-
// Cached common constants often needed by optimization passes.
- HIntConstant* cached_int_constant0_;
- HIntConstant* cached_int_constant1_;
+ HNullConstant* cached_null_constant_;
+ ArenaSafeMap<int32_t, HIntConstant*> cached_int_constants_;
+ ArenaSafeMap<int64_t, HLongConstant*> cached_long_constants_;
ART_FRIEND_TEST(GraphTest, IfSuccessorSimpleJoinBlock1);
DISALLOW_COPY_AND_ASSIGN(HGraph);
bool IsCatchBlock() const { return is_catch_block_; }
void SetIsCatchBlock() { is_catch_block_ = true; }
+ bool EndsWithControlFlowInstruction() const;
bool EndsWithIf() const;
bool HasSinglePhi() const;
virtual bool IsZero() const { return false; }
virtual bool IsOne() const { return false; }
- static HConstant* NewConstant(ArenaAllocator* allocator, Primitive::Type type, int64_t val);
-
DECLARE_INSTRUCTION(Constant);
private:
class HFloatConstant : public HConstant {
public:
- explicit HFloatConstant(float value) : HConstant(Primitive::kPrimFloat), value_(value) {}
-
float GetValue() const { return value_; }
bool InstructionDataEquals(HInstruction* other) const OVERRIDE {
DECLARE_INSTRUCTION(FloatConstant);
private:
+ explicit HFloatConstant(float value) : HConstant(Primitive::kPrimFloat), value_(value) {}
+
const float value_;
+ // Only the SsaBuilder can currently create floating-point constants. If we
+ // ever need to create them later in the pipeline, we will have to handle them
+ // the same way as integral constants.
+ friend class SsaBuilder;
DISALLOW_COPY_AND_ASSIGN(HFloatConstant);
};
class HDoubleConstant : public HConstant {
public:
- explicit HDoubleConstant(double value) : HConstant(Primitive::kPrimDouble), value_(value) {}
-
double GetValue() const { return value_; }
bool InstructionDataEquals(HInstruction* other) const OVERRIDE {
DECLARE_INSTRUCTION(DoubleConstant);
private:
+ explicit HDoubleConstant(double value) : HConstant(Primitive::kPrimDouble), value_(value) {}
+
const double value_;
+ // Only the SsaBuilder can currently create floating-point constants. If we
+ // ever need to create them later in the pipeline, we will have to handle them
+ // the same way as integral constants.
+ friend class SsaBuilder;
DISALLOW_COPY_AND_ASSIGN(HDoubleConstant);
};
class HNullConstant : public HConstant {
public:
- HNullConstant() : HConstant(Primitive::kPrimNot) {}
-
bool InstructionDataEquals(HInstruction* other ATTRIBUTE_UNUSED) const OVERRIDE {
return true;
}
DECLARE_INSTRUCTION(NullConstant);
private:
+ HNullConstant() : HConstant(Primitive::kPrimNot) {}
+
+ friend class HGraph;
DISALLOW_COPY_AND_ASSIGN(HNullConstant);
};
// synthesized (for example with the if-eqz instruction).
class HIntConstant : public HConstant {
public:
- explicit HIntConstant(int32_t value) : HConstant(Primitive::kPrimInt), value_(value) {}
-
int32_t GetValue() const { return value_; }
bool InstructionDataEquals(HInstruction* other) const OVERRIDE {
DECLARE_INSTRUCTION(IntConstant);
private:
+ explicit HIntConstant(int32_t value) : HConstant(Primitive::kPrimInt), value_(value) {}
+
const int32_t value_;
+ friend class HGraph;
+ ART_FRIEND_TEST(GraphTest, InsertInstructionBefore);
+ ART_FRIEND_TEST(ParallelMoveTest, ConstantLast);
DISALLOW_COPY_AND_ASSIGN(HIntConstant);
};
class HLongConstant : public HConstant {
public:
- explicit HLongConstant(int64_t value) : HConstant(Primitive::kPrimLong), value_(value) {}
-
int64_t GetValue() const { return value_; }
bool InstructionDataEquals(HInstruction* other) const OVERRIDE {
DECLARE_INSTRUCTION(LongConstant);
private:
+ explicit HLongConstant(int64_t value) : HConstant(Primitive::kPrimLong), value_(value) {}
+
const int64_t value_;
+ friend class HGraph;
DISALLOW_COPY_AND_ASSIGN(HLongConstant);
};
graph->AddBlock(entry);
graph->SetEntryBlock(entry);
HInstruction* parameter = new (allocator) HParameterValue(0, Primitive::kPrimInt);
- HInstruction* constant1 = new (allocator) HIntConstant(0);
- HInstruction* constant2 = new (allocator) HIntConstant(0);
entry->AddInstruction(parameter);
- entry->AddInstruction(constant1);
- entry->AddInstruction(constant2);
+
+ HInstruction* constant1 = graph->GetIntConstant(1);
+ HInstruction* constant2 = graph->GetIntConstant(2);
HBasicBlock* block = new (allocator) HBasicBlock(graph);
graph->AddBlock(block);
* is used for floating point operations. We create a floating-point equivalent
* constant to make the operations correctly typed.
*/
-static HFloatConstant* GetFloatEquivalent(HIntConstant* constant) {
+HFloatConstant* SsaBuilder::GetFloatEquivalent(HIntConstant* constant) {
// We place the floating point constant next to this constant.
HFloatConstant* result = constant->GetNext()->AsFloatConstant();
if (result == nullptr) {
* is used for floating point operations. We create a floating-point equivalent
* constant to make the operations correctly typed.
*/
-static HDoubleConstant* GetDoubleEquivalent(HLongConstant* constant) {
+HDoubleConstant* SsaBuilder::GetDoubleEquivalent(HLongConstant* constant) {
// We place the floating point constant next to this constant.
HDoubleConstant* result = constant->GetNext()->AsDoubleConstant();
if (result == nullptr) {
* floating point registers and core registers), we need to create a copy of the
* phi with a floating point / reference type.
*/
-static HPhi* GetFloatDoubleOrReferenceEquivalentOfPhi(HPhi* phi, Primitive::Type type) {
+HPhi* SsaBuilder::GetFloatDoubleOrReferenceEquivalentOfPhi(HPhi* phi, Primitive::Type type) {
// We place the floating point /reference phi next to this phi.
HInstruction* next = phi->GetNext();
if (next != nullptr
static constexpr const char* kSsaBuilderPassName = "ssa_builder";
private:
+ static HFloatConstant* GetFloatEquivalent(HIntConstant* constant);
+ static HDoubleConstant* GetDoubleEquivalent(HLongConstant* constant);
+ static HPhi* GetFloatDoubleOrReferenceEquivalentOfPhi(HPhi* phi, Primitive::Type type);
+
// Locals for the current block being visited.
HEnvironment* current_locals_;
typedef ArenaAllocatorAdapterKindImpl<kArenaAllocatorCountAllocations> ArenaAllocatorAdapterKind;
template <>
-class ArenaAllocatorAdapter<void>
- : private DebugStackReference, private ArenaAllocatorAdapterKind {
+class ArenaAllocatorAdapter<void> : private ArenaAllocatorAdapterKind {
public:
typedef void value_type;
typedef void* pointer;
explicit ArenaAllocatorAdapter(ArenaAllocator* arena_allocator,
ArenaAllocKind kind = kArenaAllocSTL)
- : DebugStackReference(arena_allocator),
- ArenaAllocatorAdapterKind(kind),
+ : ArenaAllocatorAdapterKind(kind),
arena_allocator_(arena_allocator) {
}
template <typename U>
ArenaAllocatorAdapter(const ArenaAllocatorAdapter<U>& other)
- : DebugStackReference(other),
- ArenaAllocatorAdapterKind(other),
+ : ArenaAllocatorAdapterKind(other),
arena_allocator_(other.arena_allocator_) {
}
ArenaAllocatorAdapter(const ArenaAllocatorAdapter&) = default;
};
template <typename T>
-class ArenaAllocatorAdapter : private DebugStackReference, private ArenaAllocatorAdapterKind {
+class ArenaAllocatorAdapter : private ArenaAllocatorAdapterKind {
public:
typedef T value_type;
typedef T* pointer;
};
explicit ArenaAllocatorAdapter(ArenaAllocator* arena_allocator, ArenaAllocKind kind)
- : DebugStackReference(arena_allocator),
- ArenaAllocatorAdapterKind(kind),
+ : ArenaAllocatorAdapterKind(kind),
arena_allocator_(arena_allocator) {
}
template <typename U>
ArenaAllocatorAdapter(const ArenaAllocatorAdapter<U>& other)
- : DebugStackReference(other),
- ArenaAllocatorAdapterKind(other),
+ : ArenaAllocatorAdapterKind(other),
arena_allocator_(other.arena_allocator_) {
}
ArenaAllocatorAdapter(const ArenaAllocatorAdapter&) = default;