summaryrefslogtreecommitdiff
path: root/compiler/optimizing
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/optimizing')
-rw-r--r--compiler/optimizing/builder.cc467
-rw-r--r--compiler/optimizing/builder.h22
-rw-r--r--compiler/optimizing/code_generator_arm.cc42
-rw-r--r--compiler/optimizing/code_generator_arm.h1
-rw-r--r--compiler/optimizing/code_generator_arm64.cc44
-rw-r--r--compiler/optimizing/code_generator_arm64.h1
-rw-r--r--compiler/optimizing/code_generator_x86.cc396
-rw-r--r--compiler/optimizing/code_generator_x86.h35
-rw-r--r--compiler/optimizing/code_generator_x86_64.cc36
-rw-r--r--compiler/optimizing/code_generator_x86_64.h1
-rw-r--r--compiler/optimizing/constant_area_fixups_x86.h37
-rw-r--r--compiler/optimizing/induction_var_analysis.cc278
-rw-r--r--compiler/optimizing/induction_var_analysis.h30
-rw-r--r--compiler/optimizing/induction_var_analysis_test.cc62
-rw-r--r--compiler/optimizing/induction_var_range.cc343
-rw-r--r--compiler/optimizing/induction_var_range.h103
-rw-r--r--compiler/optimizing/induction_var_range_test.cc341
-rw-r--r--compiler/optimizing/intrinsics.cc51
-rw-r--r--compiler/optimizing/intrinsics_arm.cc6
-rw-r--r--compiler/optimizing/intrinsics_arm64.cc5
-rw-r--r--compiler/optimizing/intrinsics_x86.cc5
-rw-r--r--compiler/optimizing/intrinsics_x86_64.cc5
-rw-r--r--compiler/optimizing/nodes.cc92
-rw-r--r--compiler/optimizing/nodes.h583
-rw-r--r--compiler/optimizing/nodes_x86.h66
-rw-r--r--compiler/optimizing/optimizing_compiler.cc15
26 files changed, 2315 insertions, 752 deletions
diff --git a/compiler/optimizing/builder.cc b/compiler/optimizing/builder.cc
index 1650fd1ced..7a3aa58149 100644
--- a/compiler/optimizing/builder.cc
+++ b/compiler/optimizing/builder.cc
@@ -46,7 +46,7 @@ class Temporaries : public ValueObject {
explicit Temporaries(HGraph* graph) : graph_(graph), index_(0) {}
void Add(HInstruction* instruction) {
- HInstruction* temp = new (graph_->GetArena()) HTemporary(index_);
+ HInstruction* temp = new (graph_->GetArena()) HTemporary(index_, instruction->GetDexPc());
instruction->GetBlock()->AddInstruction(temp);
DCHECK(temp->GetPrevious() == instruction);
@@ -161,23 +161,25 @@ void HGraphBuilder::InitializeParameters(uint16_t number_of_parameters) {
if (!dex_compilation_unit_->IsStatic()) {
// Add the implicit 'this' argument, not expressed in the signature.
- HParameterValue* parameter =
- new (arena_) HParameterValue(parameter_index++, Primitive::kPrimNot, true);
+ HParameterValue* parameter = new (arena_) HParameterValue(parameter_index++,
+ Primitive::kPrimNot,
+ true);
entry_block_->AddInstruction(parameter);
HLocal* local = GetLocalAt(locals_index++);
- entry_block_->AddInstruction(new (arena_) HStoreLocal(local, parameter));
+ entry_block_->AddInstruction(new (arena_) HStoreLocal(local, parameter, local->GetDexPc()));
number_of_parameters--;
}
uint32_t pos = 1;
for (int i = 0; i < number_of_parameters; i++) {
- HParameterValue* parameter =
- new (arena_) HParameterValue(parameter_index++, Primitive::GetType(shorty[pos++]));
+ HParameterValue* parameter = new (arena_) HParameterValue(parameter_index++,
+ Primitive::GetType(shorty[pos++]),
+ false);
entry_block_->AddInstruction(parameter);
HLocal* local = GetLocalAt(locals_index++);
// Store the parameter value in the local that the dex code will use
// to reference that parameter.
- entry_block_->AddInstruction(new (arena_) HStoreLocal(local, parameter));
+ entry_block_->AddInstruction(new (arena_) HStoreLocal(local, parameter, local->GetDexPc()));
bool is_wide = (parameter->GetType() == Primitive::kPrimLong)
|| (parameter->GetType() == Primitive::kPrimDouble);
if (is_wide) {
@@ -196,11 +198,11 @@ void HGraphBuilder::If_22t(const Instruction& instruction, uint32_t dex_pc) {
DCHECK(branch_target != nullptr);
DCHECK(fallthrough_target != nullptr);
PotentiallyAddSuspendCheck(branch_target, dex_pc);
- HInstruction* first = LoadLocal(instruction.VRegA(), Primitive::kPrimInt);
- HInstruction* second = LoadLocal(instruction.VRegB(), Primitive::kPrimInt);
- T* comparison = new (arena_) T(first, second);
+ HInstruction* first = LoadLocal(instruction.VRegA(), Primitive::kPrimInt, dex_pc);
+ HInstruction* second = LoadLocal(instruction.VRegB(), Primitive::kPrimInt, dex_pc);
+ T* comparison = new (arena_) T(first, second, dex_pc);
current_block_->AddInstruction(comparison);
- HInstruction* ifinst = new (arena_) HIf(comparison);
+ HInstruction* ifinst = new (arena_) HIf(comparison, dex_pc);
current_block_->AddInstruction(ifinst);
current_block_->AddSuccessor(branch_target);
current_block_->AddSuccessor(fallthrough_target);
@@ -215,10 +217,10 @@ void HGraphBuilder::If_21t(const Instruction& instruction, uint32_t dex_pc) {
DCHECK(branch_target != nullptr);
DCHECK(fallthrough_target != nullptr);
PotentiallyAddSuspendCheck(branch_target, dex_pc);
- HInstruction* value = LoadLocal(instruction.VRegA(), Primitive::kPrimInt);
- T* comparison = new (arena_) T(value, graph_->GetIntConstant(0));
+ HInstruction* value = LoadLocal(instruction.VRegA(), Primitive::kPrimInt, dex_pc);
+ T* comparison = new (arena_) T(value, graph_->GetIntConstant(0, dex_pc), dex_pc);
current_block_->AddInstruction(comparison);
- HInstruction* ifinst = new (arena_) HIf(comparison);
+ HInstruction* ifinst = new (arena_) HIf(comparison, dex_pc);
current_block_->AddInstruction(ifinst);
current_block_->AddSuccessor(branch_target);
current_block_->AddSuccessor(fallthrough_target);
@@ -320,7 +322,7 @@ void HGraphBuilder::SplitTryBoundaryEdge(HBasicBlock* predecessor,
const DexFile::CodeItem& code_item,
const DexFile::TryItem& try_item) {
// Split the edge with a single TryBoundary instruction.
- HTryBoundary* try_boundary = new (arena_) HTryBoundary(kind);
+ HTryBoundary* try_boundary = new (arena_) HTryBoundary(kind, successor->GetDexPc());
HBasicBlock* try_entry_block = graph_->SplitEdge(predecessor, successor);
try_entry_block->AddInstruction(try_boundary);
@@ -538,7 +540,7 @@ void HGraphBuilder::MaybeUpdateCurrentBlock(size_t dex_pc) {
// Branching instructions clear current_block, so we know
// the last instruction of the current block is not a branching
// instruction. We add an unconditional goto to the found block.
- current_block_->AddInstruction(new (arena_) HGoto());
+ current_block_->AddInstruction(new (arena_) HGoto(dex_pc));
current_block_->AddSuccessor(block);
}
graph_->AddBlock(block);
@@ -634,104 +636,92 @@ HBasicBlock* HGraphBuilder::FindOrCreateBlockStartingAt(int32_t dex_pc) {
}
template<typename T>
-void HGraphBuilder::Unop_12x(const Instruction& instruction, Primitive::Type type) {
- HInstruction* first = LoadLocal(instruction.VRegB(), type);
- current_block_->AddInstruction(new (arena_) T(type, first));
- UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction());
+void HGraphBuilder::Unop_12x(const Instruction& instruction,
+ Primitive::Type type,
+ uint32_t dex_pc) {
+ HInstruction* first = LoadLocal(instruction.VRegB(), type, dex_pc);
+ current_block_->AddInstruction(new (arena_) T(type, first, dex_pc));
+ UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction(), dex_pc);
}
void HGraphBuilder::Conversion_12x(const Instruction& instruction,
Primitive::Type input_type,
Primitive::Type result_type,
uint32_t dex_pc) {
- HInstruction* first = LoadLocal(instruction.VRegB(), input_type);
+ HInstruction* first = LoadLocal(instruction.VRegB(), input_type, dex_pc);
current_block_->AddInstruction(new (arena_) HTypeConversion(result_type, first, dex_pc));
- UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction());
-}
-
-template<typename T>
-void HGraphBuilder::Binop_23x(const Instruction& instruction, Primitive::Type type) {
- HInstruction* first = LoadLocal(instruction.VRegB(), type);
- HInstruction* second = LoadLocal(instruction.VRegC(), type);
- current_block_->AddInstruction(new (arena_) T(type, first, second));
- UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction());
+ UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction(), dex_pc);
}
template<typename T>
void HGraphBuilder::Binop_23x(const Instruction& instruction,
Primitive::Type type,
uint32_t dex_pc) {
- HInstruction* first = LoadLocal(instruction.VRegB(), type);
- HInstruction* second = LoadLocal(instruction.VRegC(), type);
+ HInstruction* first = LoadLocal(instruction.VRegB(), type, dex_pc);
+ HInstruction* second = LoadLocal(instruction.VRegC(), type, dex_pc);
current_block_->AddInstruction(new (arena_) T(type, first, second, dex_pc));
- UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction());
+ UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction(), dex_pc);
}
template<typename T>
void HGraphBuilder::Binop_23x_shift(const Instruction& instruction,
- Primitive::Type type) {
- HInstruction* first = LoadLocal(instruction.VRegB(), type);
- HInstruction* second = LoadLocal(instruction.VRegC(), Primitive::kPrimInt);
- current_block_->AddInstruction(new (arena_) T(type, first, second));
- UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction());
+ Primitive::Type type,
+ uint32_t dex_pc) {
+ HInstruction* first = LoadLocal(instruction.VRegB(), type, dex_pc);
+ HInstruction* second = LoadLocal(instruction.VRegC(), Primitive::kPrimInt, dex_pc);
+ current_block_->AddInstruction(new (arena_) T(type, first, second, dex_pc));
+ UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction(), dex_pc);
}
void HGraphBuilder::Binop_23x_cmp(const Instruction& instruction,
Primitive::Type type,
ComparisonBias bias,
uint32_t dex_pc) {
- HInstruction* first = LoadLocal(instruction.VRegB(), type);
- HInstruction* second = LoadLocal(instruction.VRegC(), type);
+ HInstruction* first = LoadLocal(instruction.VRegB(), type, dex_pc);
+ HInstruction* second = LoadLocal(instruction.VRegC(), type, dex_pc);
current_block_->AddInstruction(new (arena_) HCompare(type, first, second, bias, dex_pc));
- UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction());
+ UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction(), dex_pc);
}
template<typename T>
-void HGraphBuilder::Binop_12x(const Instruction& instruction, Primitive::Type type) {
- HInstruction* first = LoadLocal(instruction.VRegA(), type);
- HInstruction* second = LoadLocal(instruction.VRegB(), type);
- current_block_->AddInstruction(new (arena_) T(type, first, second));
- UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction());
-}
-
-template<typename T>
-void HGraphBuilder::Binop_12x_shift(const Instruction& instruction, Primitive::Type type) {
- HInstruction* first = LoadLocal(instruction.VRegA(), type);
- HInstruction* second = LoadLocal(instruction.VRegB(), Primitive::kPrimInt);
- current_block_->AddInstruction(new (arena_) T(type, first, second));
- UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction());
+void HGraphBuilder::Binop_12x_shift(const Instruction& instruction, Primitive::Type type,
+ uint32_t dex_pc) {
+ HInstruction* first = LoadLocal(instruction.VRegA(), type, dex_pc);
+ HInstruction* second = LoadLocal(instruction.VRegB(), Primitive::kPrimInt, dex_pc);
+ current_block_->AddInstruction(new (arena_) T(type, first, second, dex_pc));
+ UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction(), dex_pc);
}
template<typename T>
void HGraphBuilder::Binop_12x(const Instruction& instruction,
Primitive::Type type,
uint32_t dex_pc) {
- HInstruction* first = LoadLocal(instruction.VRegA(), type);
- HInstruction* second = LoadLocal(instruction.VRegB(), type);
+ HInstruction* first = LoadLocal(instruction.VRegA(), type, dex_pc);
+ HInstruction* second = LoadLocal(instruction.VRegB(), type, dex_pc);
current_block_->AddInstruction(new (arena_) T(type, first, second, dex_pc));
- UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction());
+ UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction(), dex_pc);
}
template<typename T>
-void HGraphBuilder::Binop_22s(const Instruction& instruction, bool reverse) {
- HInstruction* first = LoadLocal(instruction.VRegB(), Primitive::kPrimInt);
- HInstruction* second = graph_->GetIntConstant(instruction.VRegC_22s());
+void HGraphBuilder::Binop_22s(const Instruction& instruction, bool reverse, uint32_t dex_pc) {
+ HInstruction* first = LoadLocal(instruction.VRegB(), Primitive::kPrimInt, dex_pc);
+ HInstruction* second = graph_->GetIntConstant(instruction.VRegC_22s(), dex_pc);
if (reverse) {
std::swap(first, second);
}
- current_block_->AddInstruction(new (arena_) T(Primitive::kPrimInt, first, second));
- UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction());
+ current_block_->AddInstruction(new (arena_) T(Primitive::kPrimInt, first, second, dex_pc));
+ UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction(), dex_pc);
}
template<typename T>
-void HGraphBuilder::Binop_22b(const Instruction& instruction, bool reverse) {
- HInstruction* first = LoadLocal(instruction.VRegB(), Primitive::kPrimInt);
- HInstruction* second = graph_->GetIntConstant(instruction.VRegC_22b());
+void HGraphBuilder::Binop_22b(const Instruction& instruction, bool reverse, uint32_t dex_pc) {
+ HInstruction* first = LoadLocal(instruction.VRegB(), Primitive::kPrimInt, dex_pc);
+ HInstruction* second = graph_->GetIntConstant(instruction.VRegC_22b(), dex_pc);
if (reverse) {
std::swap(first, second);
}
- current_block_->AddInstruction(new (arena_) T(Primitive::kPrimInt, first, second));
- UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction());
+ current_block_->AddInstruction(new (arena_) T(Primitive::kPrimInt, first, second, dex_pc));
+ UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction(), dex_pc);
}
static bool RequiresConstructorBarrier(const DexCompilationUnit* cu, const CompilerDriver& driver) {
@@ -740,7 +730,9 @@ static bool RequiresConstructorBarrier(const DexCompilationUnit* cu, const Compi
&& driver.RequiresConstructorBarrier(self, cu->GetDexFile(), cu->GetClassDefIndex());
}
-void HGraphBuilder::BuildReturn(const Instruction& instruction, Primitive::Type type) {
+void HGraphBuilder::BuildReturn(const Instruction& instruction,
+ Primitive::Type type,
+ uint32_t dex_pc) {
if (type == Primitive::kPrimVoid) {
if (graph_->ShouldGenerateConstructorBarrier()) {
// The compilation unit is null during testing.
@@ -748,12 +740,12 @@ void HGraphBuilder::BuildReturn(const Instruction& instruction, Primitive::Type
DCHECK(RequiresConstructorBarrier(dex_compilation_unit_, *compiler_driver_))
<< "Inconsistent use of ShouldGenerateConstructorBarrier. Should not generate a barrier.";
}
- current_block_->AddInstruction(new (arena_) HMemoryBarrier(kStoreStore));
+ current_block_->AddInstruction(new (arena_) HMemoryBarrier(kStoreStore, dex_pc));
}
- current_block_->AddInstruction(new (arena_) HReturnVoid());
+ current_block_->AddInstruction(new (arena_) HReturnVoid(dex_pc));
} else {
- HInstruction* value = LoadLocal(instruction.VRegA(), type);
- current_block_->AddInstruction(new (arena_) HReturn(value));
+ HInstruction* value = LoadLocal(instruction.VRegA(), type, dex_pc);
+ current_block_->AddInstruction(new (arena_) HReturn(value, dex_pc));
}
current_block_->AddSuccessor(exit_block_);
current_block_ = nullptr;
@@ -1050,6 +1042,7 @@ bool HGraphBuilder::SetupArgumentsAndAddInvoke(HInvoke* invoke,
size_t start_index = 0;
size_t argument_index = 0;
uint32_t descriptor_index = 1; // Skip the return type.
+ uint32_t dex_pc = invoke->GetDexPc();
bool is_instance_call = invoke->GetOriginalInvokeType() != InvokeType::kStatic;
bool is_string_init = invoke->IsInvokeStaticOrDirect()
@@ -1060,7 +1053,7 @@ bool HGraphBuilder::SetupArgumentsAndAddInvoke(HInvoke* invoke,
argument_index = 0;
} else if (is_instance_call) {
Temporaries temps(graph_);
- HInstruction* arg = LoadLocal(is_range ? register_index : args[0], Primitive::kPrimNot);
+ HInstruction* arg = LoadLocal(is_range ? register_index : args[0], Primitive::kPrimNot, dex_pc);
HNullCheck* null_check = new (arena_) HNullCheck(arg, invoke->GetDexPc());
current_block_->AddInstruction(null_check);
temps.Add(null_check);
@@ -1089,7 +1082,7 @@ bool HGraphBuilder::SetupArgumentsAndAddInvoke(HInvoke* invoke,
MaybeRecordStat(MethodCompilationStat::kNotCompiledMalformedOpcode);
return false;
}
- HInstruction* arg = LoadLocal(is_range ? register_index + i : args[i], type);
+ HInstruction* arg = LoadLocal(is_range ? register_index + i : args[i], type, dex_pc);
invoke->SetArgumentAt(argument_index, arg);
if (is_wide) {
i++;
@@ -1122,7 +1115,7 @@ bool HGraphBuilder::SetupArgumentsAndAddInvoke(HInvoke* invoke,
// Add move-result for StringFactory method.
if (is_string_init) {
uint32_t orig_this_reg = is_range ? register_index : args[0];
- HInstruction* fake_string = LoadLocal(orig_this_reg, Primitive::kPrimNot);
+ HInstruction* fake_string = LoadLocal(orig_this_reg, Primitive::kPrimNot, dex_pc);
invoke->SetArgumentAt(argument_index, fake_string);
current_block_->AddInstruction(invoke);
PotentiallySimplifyFakeString(orig_this_reg, invoke->GetDexPc(), invoke);
@@ -1148,15 +1141,15 @@ void HGraphBuilder::PotentiallySimplifyFakeString(uint16_t original_dex_register
const VerifiedMethod* verified_method =
compiler_driver_->GetVerifiedMethod(dex_file_, dex_compilation_unit_->GetDexMethodIndex());
if (verified_method != nullptr) {
- UpdateLocal(original_dex_register, actual_string);
+ UpdateLocal(original_dex_register, actual_string, dex_pc);
const SafeMap<uint32_t, std::set<uint32_t>>& string_init_map =
verified_method->GetStringInitPcRegMap();
auto map_it = string_init_map.find(dex_pc);
if (map_it != string_init_map.end()) {
std::set<uint32_t> reg_set = map_it->second;
for (auto set_it = reg_set.begin(); set_it != reg_set.end(); ++set_it) {
- HInstruction* load_local = LoadLocal(original_dex_register, Primitive::kPrimNot);
- UpdateLocal(*set_it, load_local);
+ HInstruction* load_local = LoadLocal(original_dex_register, Primitive::kPrimNot, dex_pc);
+ UpdateLocal(*set_it, load_local, dex_pc);
}
}
} else {
@@ -1190,14 +1183,14 @@ bool HGraphBuilder::BuildInstanceFieldAccess(const Instruction& instruction,
Primitive::Type field_type = resolved_field->GetTypeAsPrimitiveType();
- HInstruction* object = LoadLocal(obj_reg, Primitive::kPrimNot);
+ HInstruction* object = LoadLocal(obj_reg, Primitive::kPrimNot, dex_pc);
current_block_->AddInstruction(new (arena_) HNullCheck(object, dex_pc));
if (is_put) {
Temporaries temps(graph_);
HInstruction* null_check = current_block_->GetLastInstruction();
// We need one temporary for the null check.
temps.Add(null_check);
- HInstruction* value = LoadLocal(source_or_dest_reg, field_type);
+ HInstruction* value = LoadLocal(source_or_dest_reg, field_type, dex_pc);
current_block_->AddInstruction(new (arena_) HInstanceFieldSet(
null_check,
value,
@@ -1206,7 +1199,8 @@ bool HGraphBuilder::BuildInstanceFieldAccess(const Instruction& instruction,
resolved_field->IsVolatile(),
field_index,
*dex_file_,
- dex_compilation_unit_->GetDexCache()));
+ dex_compilation_unit_->GetDexCache(),
+ dex_pc));
} else {
current_block_->AddInstruction(new (arena_) HInstanceFieldGet(
current_block_->GetLastInstruction(),
@@ -1215,9 +1209,10 @@ bool HGraphBuilder::BuildInstanceFieldAccess(const Instruction& instruction,
resolved_field->IsVolatile(),
field_index,
*dex_file_,
- dex_compilation_unit_->GetDexCache()));
+ dex_compilation_unit_->GetDexCache(),
+ dex_pc));
- UpdateLocal(source_or_dest_reg, current_block_->GetLastInstruction());
+ UpdateLocal(source_or_dest_reg, current_block_->GetLastInstruction(), dex_pc);
}
return true;
}
@@ -1328,7 +1323,7 @@ bool HGraphBuilder::BuildStaticFieldAccess(const Instruction& instruction,
// We need to keep the class alive before loading the value.
Temporaries temps(graph_);
temps.Add(cls);
- HInstruction* value = LoadLocal(source_or_dest_reg, field_type);
+ HInstruction* value = LoadLocal(source_or_dest_reg, field_type, dex_pc);
DCHECK_EQ(value->GetType(), field_type);
current_block_->AddInstruction(new (arena_) HStaticFieldSet(cls,
value,
@@ -1337,7 +1332,8 @@ bool HGraphBuilder::BuildStaticFieldAccess(const Instruction& instruction,
resolved_field->IsVolatile(),
field_index,
*dex_file_,
- dex_cache_));
+ dex_cache_,
+ dex_pc));
} else {
current_block_->AddInstruction(new (arena_) HStaticFieldGet(cls,
field_type,
@@ -1345,8 +1341,9 @@ bool HGraphBuilder::BuildStaticFieldAccess(const Instruction& instruction,
resolved_field->IsVolatile(),
field_index,
*dex_file_,
- dex_cache_));
- UpdateLocal(source_or_dest_reg, current_block_->GetLastInstruction());
+ dex_cache_,
+ dex_pc));
+ UpdateLocal(source_or_dest_reg, current_block_->GetLastInstruction(), dex_pc);
}
return true;
}
@@ -1360,16 +1357,16 @@ void HGraphBuilder::BuildCheckedDivRem(uint16_t out_vreg,
bool isDiv) {
DCHECK(type == Primitive::kPrimInt || type == Primitive::kPrimLong);
- HInstruction* first = LoadLocal(first_vreg, type);
+ HInstruction* first = LoadLocal(first_vreg, type, dex_pc);
HInstruction* second = nullptr;
if (second_is_constant) {
if (type == Primitive::kPrimInt) {
- second = graph_->GetIntConstant(second_vreg_or_constant);
+ second = graph_->GetIntConstant(second_vreg_or_constant, dex_pc);
} else {
- second = graph_->GetLongConstant(second_vreg_or_constant);
+ second = graph_->GetLongConstant(second_vreg_or_constant, dex_pc);
}
} else {
- second = LoadLocal(second_vreg_or_constant, type);
+ second = LoadLocal(second_vreg_or_constant, type, dex_pc);
}
if (!second_is_constant
@@ -1386,7 +1383,7 @@ void HGraphBuilder::BuildCheckedDivRem(uint16_t out_vreg,
} else {
current_block_->AddInstruction(new (arena_) HRem(type, first, second, dex_pc));
}
- UpdateLocal(out_vreg, current_block_->GetLastInstruction());
+ UpdateLocal(out_vreg, current_block_->GetLastInstruction(), dex_pc);
}
void HGraphBuilder::BuildArrayAccess(const Instruction& instruction,
@@ -1400,26 +1397,26 @@ void HGraphBuilder::BuildArrayAccess(const Instruction& instruction,
// We need one temporary for the null check, one for the index, and one for the length.
Temporaries temps(graph_);
- HInstruction* object = LoadLocal(array_reg, Primitive::kPrimNot);
+ HInstruction* object = LoadLocal(array_reg, Primitive::kPrimNot, dex_pc);
object = new (arena_) HNullCheck(object, dex_pc);
current_block_->AddInstruction(object);
temps.Add(object);
- HInstruction* length = new (arena_) HArrayLength(object);
+ HInstruction* length = new (arena_) HArrayLength(object, dex_pc);
current_block_->AddInstruction(length);
temps.Add(length);
- HInstruction* index = LoadLocal(index_reg, Primitive::kPrimInt);
+ HInstruction* index = LoadLocal(index_reg, Primitive::kPrimInt, dex_pc);
index = new (arena_) HBoundsCheck(index, length, dex_pc);
current_block_->AddInstruction(index);
temps.Add(index);
if (is_put) {
- HInstruction* value = LoadLocal(source_or_dest_reg, anticipated_type);
+ HInstruction* value = LoadLocal(source_or_dest_reg, anticipated_type, dex_pc);
// TODO: Insert a type check node if the type is Object.
current_block_->AddInstruction(new (arena_) HArraySet(
object, index, value, anticipated_type, dex_pc));
} else {
- current_block_->AddInstruction(new (arena_) HArrayGet(object, index, anticipated_type));
- UpdateLocal(source_or_dest_reg, current_block_->GetLastInstruction());
+ current_block_->AddInstruction(new (arena_) HArrayGet(object, index, anticipated_type, dex_pc));
+ UpdateLocal(source_or_dest_reg, current_block_->GetLastInstruction(), dex_pc);
}
graph_->SetHasBoundsChecks(true);
}
@@ -1430,7 +1427,7 @@ void HGraphBuilder::BuildFilledNewArray(uint32_t dex_pc,
bool is_range,
uint32_t* args,
uint32_t register_index) {
- HInstruction* length = graph_->GetIntConstant(number_of_vreg_arguments);
+ HInstruction* length = graph_->GetIntConstant(number_of_vreg_arguments, dex_pc);
QuickEntrypointEnum entrypoint = NeedsAccessCheck(type_index)
? kQuickAllocArrayWithAccessCheck
: kQuickAllocArray;
@@ -1454,8 +1451,8 @@ void HGraphBuilder::BuildFilledNewArray(uint32_t dex_pc,
Temporaries temps(graph_);
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 = graph_->GetIntConstant(i);
+ HInstruction* value = LoadLocal(is_range ? register_index + i : args[i], type, dex_pc);
+ HInstruction* index = graph_->GetIntConstant(i, dex_pc);
current_block_->AddInstruction(
new (arena_) HArraySet(object, index, value, type, dex_pc));
}
@@ -1469,8 +1466,8 @@ void HGraphBuilder::BuildFillArrayData(HInstruction* object,
Primitive::Type anticipated_type,
uint32_t dex_pc) {
for (uint32_t i = 0; i < element_count; ++i) {
- HInstruction* index = graph_->GetIntConstant(i);
- HInstruction* value = graph_->GetIntConstant(data[i]);
+ HInstruction* index = graph_->GetIntConstant(i, dex_pc);
+ HInstruction* value = graph_->GetIntConstant(data[i], dex_pc);
current_block_->AddInstruction(new (arena_) HArraySet(
object, index, value, anticipated_type, dex_pc));
}
@@ -1478,12 +1475,12 @@ void HGraphBuilder::BuildFillArrayData(HInstruction* object,
void HGraphBuilder::BuildFillArrayData(const Instruction& instruction, uint32_t dex_pc) {
Temporaries temps(graph_);
- HInstruction* array = LoadLocal(instruction.VRegA_31t(), Primitive::kPrimNot);
+ HInstruction* array = LoadLocal(instruction.VRegA_31t(), Primitive::kPrimNot, dex_pc);
HNullCheck* null_check = new (arena_) HNullCheck(array, dex_pc);
current_block_->AddInstruction(null_check);
temps.Add(null_check);
- HInstruction* length = new (arena_) HArrayLength(null_check);
+ HInstruction* length = new (arena_) HArrayLength(null_check, dex_pc);
current_block_->AddInstruction(length);
int32_t payload_offset = instruction.VRegB_31t() + dex_pc;
@@ -1494,7 +1491,7 @@ void HGraphBuilder::BuildFillArrayData(const Instruction& instruction, uint32_t
// Implementation of this DEX instruction seems to be that the bounds check is
// done before doing any stores.
- HInstruction* last_index = graph_->GetIntConstant(payload->element_count - 1);
+ HInstruction* last_index = graph_->GetIntConstant(payload->element_count - 1, dex_pc);
current_block_->AddInstruction(new (arena_) HBoundsCheck(last_index, length, dex_pc));
switch (payload->element_width) {
@@ -1536,8 +1533,8 @@ void HGraphBuilder::BuildFillWideArrayData(HInstruction* object,
uint32_t element_count,
uint32_t dex_pc) {
for (uint32_t i = 0; i < element_count; ++i) {
- HInstruction* index = graph_->GetIntConstant(i);
- HInstruction* value = graph_->GetLongConstant(data[i]);
+ HInstruction* index = graph_->GetIntConstant(i, dex_pc);
+ HInstruction* value = graph_->GetLongConstant(data[i], dex_pc);
current_block_->AddInstruction(new (arena_) HArraySet(
object, index, value, Primitive::kPrimLong, dex_pc));
}
@@ -1562,7 +1559,7 @@ bool HGraphBuilder::BuildTypeCheck(const Instruction& instruction,
MaybeRecordStat(MethodCompilationStat::kNotCompiledCantAccesType);
return false;
}
- HInstruction* object = LoadLocal(reference, Primitive::kPrimNot);
+ HInstruction* object = LoadLocal(reference, Primitive::kPrimNot, dex_pc);
HLoadClass* cls = new (arena_) HLoadClass(
graph_->GetCurrentMethod(),
type_index,
@@ -1576,7 +1573,7 @@ bool HGraphBuilder::BuildTypeCheck(const Instruction& instruction,
if (instruction.Opcode() == Instruction::INSTANCE_OF) {
current_block_->AddInstruction(
new (arena_) HInstanceOf(object, cls, type_known_final, dex_pc));
- UpdateLocal(destination, current_block_->GetLastInstruction());
+ UpdateLocal(destination, current_block_->GetLastInstruction(), dex_pc);
} else {
DCHECK_EQ(instruction.Opcode(), Instruction::CHECK_CAST);
current_block_->AddInstruction(
@@ -1598,7 +1595,7 @@ void HGraphBuilder::BuildPackedSwitch(const Instruction& instruction, uint32_t d
SwitchTable table(instruction, dex_pc, false);
// Value to test against.
- HInstruction* value = LoadLocal(instruction.VRegA(), Primitive::kPrimInt);
+ HInstruction* value = LoadLocal(instruction.VRegA(), Primitive::kPrimInt, dex_pc);
// Retrieve number of entries.
uint16_t num_entries = table.GetNumEntries();
@@ -1623,7 +1620,7 @@ void HGraphBuilder::BuildSparseSwitch(const Instruction& instruction, uint32_t d
SwitchTable table(instruction, dex_pc, true);
// Value to test against.
- HInstruction* value = LoadLocal(instruction.VRegA(), Primitive::kPrimInt);
+ HInstruction* value = LoadLocal(instruction.VRegA(), Primitive::kPrimInt, dex_pc);
uint16_t num_entries = table.GetNumEntries();
@@ -1642,12 +1639,12 @@ void HGraphBuilder::BuildSwitchCaseHelper(const Instruction& instruction, size_t
PotentiallyAddSuspendCheck(case_target, dex_pc);
// The current case's value.
- HInstruction* this_case_value = graph_->GetIntConstant(case_value_int);
+ HInstruction* this_case_value = graph_->GetIntConstant(case_value_int, dex_pc);
// Compare value and this_case_value.
- HEqual* comparison = new (arena_) HEqual(value, this_case_value);
+ HEqual* comparison = new (arena_) HEqual(value, this_case_value, dex_pc);
current_block_->AddInstruction(comparison);
- HInstruction* ifinst = new (arena_) HIf(comparison);
+ HInstruction* ifinst = new (arena_) HIf(comparison, dex_pc);
current_block_->AddInstruction(ifinst);
// Case hit: use the target offset to determine where to go.
@@ -1711,29 +1708,29 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, uint32
switch (instruction.Opcode()) {
case Instruction::CONST_4: {
int32_t register_index = instruction.VRegA();
- HIntConstant* constant = graph_->GetIntConstant(instruction.VRegB_11n());
- UpdateLocal(register_index, constant);
+ HIntConstant* constant = graph_->GetIntConstant(instruction.VRegB_11n(), dex_pc);
+ UpdateLocal(register_index, constant, dex_pc);
break;
}
case Instruction::CONST_16: {
int32_t register_index = instruction.VRegA();
- HIntConstant* constant = graph_->GetIntConstant(instruction.VRegB_21s());
- UpdateLocal(register_index, constant);
+ HIntConstant* constant = graph_->GetIntConstant(instruction.VRegB_21s(), dex_pc);
+ UpdateLocal(register_index, constant, dex_pc);
break;
}
case Instruction::CONST: {
int32_t register_index = instruction.VRegA();
- HIntConstant* constant = graph_->GetIntConstant(instruction.VRegB_31i());
- UpdateLocal(register_index, constant);
+ HIntConstant* constant = graph_->GetIntConstant(instruction.VRegB_31i(), dex_pc);
+ UpdateLocal(register_index, constant, dex_pc);
break;
}
case Instruction::CONST_HIGH16: {
int32_t register_index = instruction.VRegA();
- HIntConstant* constant = graph_->GetIntConstant(instruction.VRegB_21h() << 16);
- UpdateLocal(register_index, constant);
+ HIntConstant* constant = graph_->GetIntConstant(instruction.VRegB_21h() << 16, dex_pc);
+ UpdateLocal(register_index, constant, dex_pc);
break;
}
@@ -1743,8 +1740,8 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, uint32
int64_t value = instruction.VRegB_21s();
value <<= 48;
value >>= 48;
- HLongConstant* constant = graph_->GetLongConstant(value);
- UpdateLocal(register_index, constant);
+ HLongConstant* constant = graph_->GetLongConstant(value, dex_pc);
+ UpdateLocal(register_index, constant, dex_pc);
break;
}
@@ -1754,23 +1751,23 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, uint32
int64_t value = instruction.VRegB_31i();
value <<= 32;
value >>= 32;
- HLongConstant* constant = graph_->GetLongConstant(value);
- UpdateLocal(register_index, constant);
+ HLongConstant* constant = graph_->GetLongConstant(value, dex_pc);
+ UpdateLocal(register_index, constant, dex_pc);
break;
}
case Instruction::CONST_WIDE: {
int32_t register_index = instruction.VRegA();
- HLongConstant* constant = graph_->GetLongConstant(instruction.VRegB_51l());
- UpdateLocal(register_index, constant);
+ HLongConstant* constant = graph_->GetLongConstant(instruction.VRegB_51l(), dex_pc);
+ UpdateLocal(register_index, constant, dex_pc);
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 = graph_->GetLongConstant(value);
- UpdateLocal(register_index, constant);
+ HLongConstant* constant = graph_->GetLongConstant(value, dex_pc);
+ UpdateLocal(register_index, constant, dex_pc);
break;
}
@@ -1778,8 +1775,8 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, uint32
case Instruction::MOVE:
case Instruction::MOVE_FROM16:
case Instruction::MOVE_16: {
- HInstruction* value = LoadLocal(instruction.VRegB(), Primitive::kPrimInt);
- UpdateLocal(instruction.VRegA(), value);
+ HInstruction* value = LoadLocal(instruction.VRegB(), Primitive::kPrimInt, dex_pc);
+ UpdateLocal(instruction.VRegA(), value, dex_pc);
break;
}
@@ -1787,22 +1784,22 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, uint32
case Instruction::MOVE_WIDE:
case Instruction::MOVE_WIDE_FROM16:
case Instruction::MOVE_WIDE_16: {
- HInstruction* value = LoadLocal(instruction.VRegB(), Primitive::kPrimLong);
- UpdateLocal(instruction.VRegA(), value);
+ HInstruction* value = LoadLocal(instruction.VRegB(), Primitive::kPrimLong, dex_pc);
+ UpdateLocal(instruction.VRegA(), value, dex_pc);
break;
}
case Instruction::MOVE_OBJECT:
case Instruction::MOVE_OBJECT_16:
case Instruction::MOVE_OBJECT_FROM16: {
- HInstruction* value = LoadLocal(instruction.VRegB(), Primitive::kPrimNot);
- UpdateLocal(instruction.VRegA(), value);
+ HInstruction* value = LoadLocal(instruction.VRegB(), Primitive::kPrimNot, dex_pc);
+ UpdateLocal(instruction.VRegA(), value, dex_pc);
break;
}
case Instruction::RETURN_VOID_NO_BARRIER:
case Instruction::RETURN_VOID: {
- BuildReturn(instruction, Primitive::kPrimVoid);
+ BuildReturn(instruction, Primitive::kPrimVoid, dex_pc);
break;
}
@@ -1824,24 +1821,24 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, uint32
HBasicBlock* target = FindBlockStartingAt(offset + dex_pc);
DCHECK(target != nullptr);
PotentiallyAddSuspendCheck(target, dex_pc);
- current_block_->AddInstruction(new (arena_) HGoto());
+ current_block_->AddInstruction(new (arena_) HGoto(dex_pc));
current_block_->AddSuccessor(target);
current_block_ = nullptr;
break;
}
case Instruction::RETURN: {
- BuildReturn(instruction, return_type_);
+ BuildReturn(instruction, return_type_, dex_pc);
break;
}
case Instruction::RETURN_OBJECT: {
- BuildReturn(instruction, return_type_);
+ BuildReturn(instruction, return_type_, dex_pc);
break;
}
case Instruction::RETURN_WIDE: {
- BuildReturn(instruction, return_type_);
+ BuildReturn(instruction, return_type_, dex_pc);
break;
}
@@ -1895,32 +1892,32 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, uint32
}
case Instruction::NEG_INT: {
- Unop_12x<HNeg>(instruction, Primitive::kPrimInt);
+ Unop_12x<HNeg>(instruction, Primitive::kPrimInt, dex_pc);
break;
}
case Instruction::NEG_LONG: {
- Unop_12x<HNeg>(instruction, Primitive::kPrimLong);
+ Unop_12x<HNeg>(instruction, Primitive::kPrimLong, dex_pc);
break;
}
case Instruction::NEG_FLOAT: {
- Unop_12x<HNeg>(instruction, Primitive::kPrimFloat);
+ Unop_12x<HNeg>(instruction, Primitive::kPrimFloat, dex_pc);
break;
}
case Instruction::NEG_DOUBLE: {
- Unop_12x<HNeg>(instruction, Primitive::kPrimDouble);
+ Unop_12x<HNeg>(instruction, Primitive::kPrimDouble, dex_pc);
break;
}
case Instruction::NOT_INT: {
- Unop_12x<HNot>(instruction, Primitive::kPrimInt);
+ Unop_12x<HNot>(instruction, Primitive::kPrimInt, dex_pc);
break;
}
case Instruction::NOT_LONG: {
- Unop_12x<HNot>(instruction, Primitive::kPrimLong);
+ Unop_12x<HNot>(instruction, Primitive::kPrimLong, dex_pc);
break;
}
@@ -2000,67 +1997,67 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, uint32
}
case Instruction::ADD_INT: {
- Binop_23x<HAdd>(instruction, Primitive::kPrimInt);
+ Binop_23x<HAdd>(instruction, Primitive::kPrimInt, dex_pc);
break;
}
case Instruction::ADD_LONG: {
- Binop_23x<HAdd>(instruction, Primitive::kPrimLong);
+ Binop_23x<HAdd>(instruction, Primitive::kPrimLong, dex_pc);
break;
}
case Instruction::ADD_DOUBLE: {
- Binop_23x<HAdd>(instruction, Primitive::kPrimDouble);
+ Binop_23x<HAdd>(instruction, Primitive::kPrimDouble, dex_pc);
break;
}
case Instruction::ADD_FLOAT: {
- Binop_23x<HAdd>(instruction, Primitive::kPrimFloat);
+ Binop_23x<HAdd>(instruction, Primitive::kPrimFloat, dex_pc);
break;
}
case Instruction::SUB_INT: {
- Binop_23x<HSub>(instruction, Primitive::kPrimInt);
+ Binop_23x<HSub>(instruction, Primitive::kPrimInt, dex_pc);
break;
}
case Instruction::SUB_LONG: {
- Binop_23x<HSub>(instruction, Primitive::kPrimLong);
+ Binop_23x<HSub>(instruction, Primitive::kPrimLong, dex_pc);
break;
}
case Instruction::SUB_FLOAT: {
- Binop_23x<HSub>(instruction, Primitive::kPrimFloat);
+ Binop_23x<HSub>(instruction, Primitive::kPrimFloat, dex_pc);
break;
}
case Instruction::SUB_DOUBLE: {
- Binop_23x<HSub>(instruction, Primitive::kPrimDouble);
+ Binop_23x<HSub>(instruction, Primitive::kPrimDouble, dex_pc);
break;
}
case Instruction::ADD_INT_2ADDR: {
- Binop_12x<HAdd>(instruction, Primitive::kPrimInt);
+ Binop_12x<HAdd>(instruction, Primitive::kPrimInt, dex_pc);
break;
}
case Instruction::MUL_INT: {
- Binop_23x<HMul>(instruction, Primitive::kPrimInt);
+ Binop_23x<HMul>(instruction, Primitive::kPrimInt, dex_pc);
break;
}
case Instruction::MUL_LONG: {
- Binop_23x<HMul>(instruction, Primitive::kPrimLong);
+ Binop_23x<HMul>(instruction, Primitive::kPrimLong, dex_pc);
break;
}
case Instruction::MUL_FLOAT: {
- Binop_23x<HMul>(instruction, Primitive::kPrimFloat);
+ Binop_23x<HMul>(instruction, Primitive::kPrimFloat, dex_pc);
break;
}
case Instruction::MUL_DOUBLE: {
- Binop_23x<HMul>(instruction, Primitive::kPrimDouble);
+ Binop_23x<HMul>(instruction, Primitive::kPrimDouble, dex_pc);
break;
}
@@ -2109,117 +2106,117 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, uint32
}
case Instruction::AND_INT: {
- Binop_23x<HAnd>(instruction, Primitive::kPrimInt);
+ Binop_23x<HAnd>(instruction, Primitive::kPrimInt, dex_pc);
break;
}
case Instruction::AND_LONG: {
- Binop_23x<HAnd>(instruction, Primitive::kPrimLong);
+ Binop_23x<HAnd>(instruction, Primitive::kPrimLong, dex_pc);
break;
}
case Instruction::SHL_INT: {
- Binop_23x_shift<HShl>(instruction, Primitive::kPrimInt);
+ Binop_23x_shift<HShl>(instruction, Primitive::kPrimInt, dex_pc);
break;
}
case Instruction::SHL_LONG: {
- Binop_23x_shift<HShl>(instruction, Primitive::kPrimLong);
+ Binop_23x_shift<HShl>(instruction, Primitive::kPrimLong, dex_pc);
break;
}
case Instruction::SHR_INT: {
- Binop_23x_shift<HShr>(instruction, Primitive::kPrimInt);
+ Binop_23x_shift<HShr>(instruction, Primitive::kPrimInt, dex_pc);
break;
}
case Instruction::SHR_LONG: {
- Binop_23x_shift<HShr>(instruction, Primitive::kPrimLong);
+ Binop_23x_shift<HShr>(instruction, Primitive::kPrimLong, dex_pc);
break;
}
case Instruction::USHR_INT: {
- Binop_23x_shift<HUShr>(instruction, Primitive::kPrimInt);
+ Binop_23x_shift<HUShr>(instruction, Primitive::kPrimInt, dex_pc);
break;
}
case Instruction::USHR_LONG: {
- Binop_23x_shift<HUShr>(instruction, Primitive::kPrimLong);
+ Binop_23x_shift<HUShr>(instruction, Primitive::kPrimLong, dex_pc);
break;
}
case Instruction::OR_INT: {
- Binop_23x<HOr>(instruction, Primitive::kPrimInt);
+ Binop_23x<HOr>(instruction, Primitive::kPrimInt, dex_pc);
break;
}
case Instruction::OR_LONG: {
- Binop_23x<HOr>(instruction, Primitive::kPrimLong);
+ Binop_23x<HOr>(instruction, Primitive::kPrimLong, dex_pc);
break;
}
case Instruction::XOR_INT: {
- Binop_23x<HXor>(instruction, Primitive::kPrimInt);
+ Binop_23x<HXor>(instruction, Primitive::kPrimInt, dex_pc);
break;
}
case Instruction::XOR_LONG: {
- Binop_23x<HXor>(instruction, Primitive::kPrimLong);
+ Binop_23x<HXor>(instruction, Primitive::kPrimLong, dex_pc);
break;
}
case Instruction::ADD_LONG_2ADDR: {
- Binop_12x<HAdd>(instruction, Primitive::kPrimLong);
+ Binop_12x<HAdd>(instruction, Primitive::kPrimLong, dex_pc);
break;
}
case Instruction::ADD_DOUBLE_2ADDR: {
- Binop_12x<HAdd>(instruction, Primitive::kPrimDouble);
+ Binop_12x<HAdd>(instruction, Primitive::kPrimDouble, dex_pc);
break;
}
case Instruction::ADD_FLOAT_2ADDR: {
- Binop_12x<HAdd>(instruction, Primitive::kPrimFloat);
+ Binop_12x<HAdd>(instruction, Primitive::kPrimFloat, dex_pc);
break;
}
case Instruction::SUB_INT_2ADDR: {
- Binop_12x<HSub>(instruction, Primitive::kPrimInt);
+ Binop_12x<HSub>(instruction, Primitive::kPrimInt, dex_pc);
break;
}
case Instruction::SUB_LONG_2ADDR: {
- Binop_12x<HSub>(instruction, Primitive::kPrimLong);
+ Binop_12x<HSub>(instruction, Primitive::kPrimLong, dex_pc);
break;
}
case Instruction::SUB_FLOAT_2ADDR: {
- Binop_12x<HSub>(instruction, Primitive::kPrimFloat);
+ Binop_12x<HSub>(instruction, Primitive::kPrimFloat, dex_pc);
break;
}
case Instruction::SUB_DOUBLE_2ADDR: {
- Binop_12x<HSub>(instruction, Primitive::kPrimDouble);
+ Binop_12x<HSub>(instruction, Primitive::kPrimDouble, dex_pc);
break;
}
case Instruction::MUL_INT_2ADDR: {
- Binop_12x<HMul>(instruction, Primitive::kPrimInt);
+ Binop_12x<HMul>(instruction, Primitive::kPrimInt, dex_pc);
break;
}
case Instruction::MUL_LONG_2ADDR: {
- Binop_12x<HMul>(instruction, Primitive::kPrimLong);
+ Binop_12x<HMul>(instruction, Primitive::kPrimLong, dex_pc);
break;
}
case Instruction::MUL_FLOAT_2ADDR: {
- Binop_12x<HMul>(instruction, Primitive::kPrimFloat);
+ Binop_12x<HMul>(instruction, Primitive::kPrimFloat, dex_pc);
break;
}
case Instruction::MUL_DOUBLE_2ADDR: {
- Binop_12x<HMul>(instruction, Primitive::kPrimDouble);
+ Binop_12x<HMul>(instruction, Primitive::kPrimDouble, dex_pc);
break;
}
@@ -2258,32 +2255,32 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, uint32
}
case Instruction::SHL_INT_2ADDR: {
- Binop_12x_shift<HShl>(instruction, Primitive::kPrimInt);
+ Binop_12x_shift<HShl>(instruction, Primitive::kPrimInt, dex_pc);
break;
}
case Instruction::SHL_LONG_2ADDR: {
- Binop_12x_shift<HShl>(instruction, Primitive::kPrimLong);
+ Binop_12x_shift<HShl>(instruction, Primitive::kPrimLong, dex_pc);
break;
}
case Instruction::SHR_INT_2ADDR: {
- Binop_12x_shift<HShr>(instruction, Primitive::kPrimInt);
+ Binop_12x_shift<HShr>(instruction, Primitive::kPrimInt, dex_pc);
break;
}
case Instruction::SHR_LONG_2ADDR: {
- Binop_12x_shift<HShr>(instruction, Primitive::kPrimLong);
+ Binop_12x_shift<HShr>(instruction, Primitive::kPrimLong, dex_pc);
break;
}
case Instruction::USHR_INT_2ADDR: {
- Binop_12x_shift<HUShr>(instruction, Primitive::kPrimInt);
+ Binop_12x_shift<HUShr>(instruction, Primitive::kPrimInt, dex_pc);
break;
}
case Instruction::USHR_LONG_2ADDR: {
- Binop_12x_shift<HUShr>(instruction, Primitive::kPrimLong);
+ Binop_12x_shift<HUShr>(instruction, Primitive::kPrimLong, dex_pc);
break;
}
@@ -2298,92 +2295,92 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, uint32
}
case Instruction::AND_INT_2ADDR: {
- Binop_12x<HAnd>(instruction, Primitive::kPrimInt);
+ Binop_12x<HAnd>(instruction, Primitive::kPrimInt, dex_pc);
break;
}
case Instruction::AND_LONG_2ADDR: {
- Binop_12x<HAnd>(instruction, Primitive::kPrimLong);
+ Binop_12x<HAnd>(instruction, Primitive::kPrimLong, dex_pc);
break;
}
case Instruction::OR_INT_2ADDR: {
- Binop_12x<HOr>(instruction, Primitive::kPrimInt);
+ Binop_12x<HOr>(instruction, Primitive::kPrimInt, dex_pc);
break;
}
case Instruction::OR_LONG_2ADDR: {
- Binop_12x<HOr>(instruction, Primitive::kPrimLong);
+ Binop_12x<HOr>(instruction, Primitive::kPrimLong, dex_pc);
break;
}
case Instruction::XOR_INT_2ADDR: {
- Binop_12x<HXor>(instruction, Primitive::kPrimInt);
+ Binop_12x<HXor>(instruction, Primitive::kPrimInt, dex_pc);
break;
}
case Instruction::XOR_LONG_2ADDR: {
- Binop_12x<HXor>(instruction, Primitive::kPrimLong);
+ Binop_12x<HXor>(instruction, Primitive::kPrimLong, dex_pc);
break;
}
case Instruction::ADD_INT_LIT16: {
- Binop_22s<HAdd>(instruction, false);
+ Binop_22s<HAdd>(instruction, false, dex_pc);
break;
}
case Instruction::AND_INT_LIT16: {
- Binop_22s<HAnd>(instruction, false);
+ Binop_22s<HAnd>(instruction, false, dex_pc);
break;
}
case Instruction::OR_INT_LIT16: {
- Binop_22s<HOr>(instruction, false);
+ Binop_22s<HOr>(instruction, false, dex_pc);
break;
}
case Instruction::XOR_INT_LIT16: {
- Binop_22s<HXor>(instruction, false);
+ Binop_22s<HXor>(instruction, false, dex_pc);
break;
}
case Instruction::RSUB_INT: {
- Binop_22s<HSub>(instruction, true);
+ Binop_22s<HSub>(instruction, true, dex_pc);
break;
}
case Instruction::MUL_INT_LIT16: {
- Binop_22s<HMul>(instruction, false);
+ Binop_22s<HMul>(instruction, false, dex_pc);
break;
}
case Instruction::ADD_INT_LIT8: {
- Binop_22b<HAdd>(instruction, false);
+ Binop_22b<HAdd>(instruction, false, dex_pc);
break;
}
case Instruction::AND_INT_LIT8: {
- Binop_22b<HAnd>(instruction, false);
+ Binop_22b<HAnd>(instruction, false, dex_pc);
break;
}
case Instruction::OR_INT_LIT8: {
- Binop_22b<HOr>(instruction, false);
+ Binop_22b<HOr>(instruction, false, dex_pc);
break;
}
case Instruction::XOR_INT_LIT8: {
- Binop_22b<HXor>(instruction, false);
+ Binop_22b<HXor>(instruction, false, dex_pc);
break;
}
case Instruction::RSUB_INT_LIT8: {
- Binop_22b<HSub>(instruction, true);
+ Binop_22b<HSub>(instruction, true, dex_pc);
break;
}
case Instruction::MUL_INT_LIT8: {
- Binop_22b<HMul>(instruction, false);
+ Binop_22b<HMul>(instruction, false, dex_pc);
break;
}
@@ -2402,17 +2399,17 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, uint32
}
case Instruction::SHL_INT_LIT8: {
- Binop_22b<HShl>(instruction, false);
+ Binop_22b<HShl>(instruction, false, dex_pc);
break;
}
case Instruction::SHR_INT_LIT8: {
- Binop_22b<HShr>(instruction, false);
+ Binop_22b<HShr>(instruction, false, dex_pc);
break;
}
case Instruction::USHR_INT_LIT8: {
- Binop_22b<HUShr>(instruction, false);
+ Binop_22b<HUShr>(instruction, false, dex_pc);
break;
}
@@ -2420,9 +2417,9 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, uint32
uint16_t type_index = instruction.VRegB_21c();
if (compiler_driver_->IsStringTypeIndex(type_index, dex_file_)) {
int32_t register_index = instruction.VRegA();
- HFakeString* fake_string = new (arena_) HFakeString();
+ HFakeString* fake_string = new (arena_) HFakeString(dex_pc);
current_block_->AddInstruction(fake_string);
- UpdateLocal(register_index, fake_string);
+ UpdateLocal(register_index, fake_string, dex_pc);
} else {
QuickEntrypointEnum entrypoint = NeedsAccessCheck(type_index)
? kQuickAllocObjectWithAccessCheck
@@ -2434,14 +2431,14 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, uint32
type_index,
*dex_compilation_unit_->GetDexFile(),
entrypoint));
- UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction());
+ UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction(), dex_pc);
}
break;
}
case Instruction::NEW_ARRAY: {
uint16_t type_index = instruction.VRegC_22c();
- HInstruction* length = LoadLocal(instruction.VRegB_22c(), Primitive::kPrimInt);
+ HInstruction* length = LoadLocal(instruction.VRegB_22c(), Primitive::kPrimInt, dex_pc);
QuickEntrypointEnum entrypoint = NeedsAccessCheck(type_index)
? kQuickAllocArrayWithAccessCheck
: kQuickAllocArray;
@@ -2451,7 +2448,7 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, uint32
type_index,
*dex_compilation_unit_->GetDexFile(),
entrypoint));
- UpdateLocal(instruction.VRegA_22c(), current_block_->GetLastInstruction());
+ UpdateLocal(instruction.VRegA_22c(), current_block_->GetLastInstruction(), dex_pc);
break;
}
@@ -2491,7 +2488,7 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, uint32
// FilledNewArray, the local needs to be updated after the array was
// filled, otherwise we might overwrite an input vreg.
HStoreLocal* update_local =
- new (arena_) HStoreLocal(GetLocalAt(instruction.VRegA()), latest_result_);
+ new (arena_) HStoreLocal(GetLocalAt(instruction.VRegA()), latest_result_, dex_pc);
HBasicBlock* block = latest_result_->GetBlock();
if (block == current_block_) {
// MoveResult and the previous instruction are in the same block.
@@ -2621,27 +2618,27 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, uint32
ARRAY_XX(_SHORT, Primitive::kPrimShort);
case Instruction::ARRAY_LENGTH: {
- HInstruction* object = LoadLocal(instruction.VRegB_12x(), Primitive::kPrimNot);
+ HInstruction* object = LoadLocal(instruction.VRegB_12x(), Primitive::kPrimNot, dex_pc);
// No need for a temporary for the null check, it is the only input of the following
// instruction.
object = new (arena_) HNullCheck(object, dex_pc);
current_block_->AddInstruction(object);
- current_block_->AddInstruction(new (arena_) HArrayLength(object));
- UpdateLocal(instruction.VRegA_12x(), current_block_->GetLastInstruction());
+ current_block_->AddInstruction(new (arena_) HArrayLength(object, dex_pc));
+ UpdateLocal(instruction.VRegA_12x(), current_block_->GetLastInstruction(), dex_pc);
break;
}
case Instruction::CONST_STRING: {
current_block_->AddInstruction(
new (arena_) HLoadString(graph_->GetCurrentMethod(), instruction.VRegB_21c(), dex_pc));
- UpdateLocal(instruction.VRegA_21c(), current_block_->GetLastInstruction());
+ UpdateLocal(instruction.VRegA_21c(), current_block_->GetLastInstruction(), dex_pc);
break;
}
case Instruction::CONST_STRING_JUMBO: {
current_block_->AddInstruction(
new (arena_) HLoadString(graph_->GetCurrentMethod(), instruction.VRegB_31c(), dex_pc));
- UpdateLocal(instruction.VRegA_31c(), current_block_->GetLastInstruction());
+ UpdateLocal(instruction.VRegA_31c(), current_block_->GetLastInstruction(), dex_pc);
break;
}
@@ -2667,19 +2664,19 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, uint32
*dex_compilation_unit_->GetDexFile(),
IsOutermostCompilingClass(type_index),
dex_pc));
- UpdateLocal(instruction.VRegA_21c(), current_block_->GetLastInstruction());
+ UpdateLocal(instruction.VRegA_21c(), current_block_->GetLastInstruction(), dex_pc);
break;
}
case Instruction::MOVE_EXCEPTION: {
- current_block_->AddInstruction(new (arena_) HLoadException());
- UpdateLocal(instruction.VRegA_11x(), current_block_->GetLastInstruction());
- current_block_->AddInstruction(new (arena_) HClearException());
+ current_block_->AddInstruction(new (arena_) HLoadException(dex_pc));
+ UpdateLocal(instruction.VRegA_11x(), current_block_->GetLastInstruction(), dex_pc);
+ current_block_->AddInstruction(new (arena_) HClearException(dex_pc));
break;
}
case Instruction::THROW: {
- HInstruction* exception = LoadLocal(instruction.VRegA_11x(), Primitive::kPrimNot);
+ HInstruction* exception = LoadLocal(instruction.VRegA_11x(), Primitive::kPrimNot, dex_pc);
current_block_->AddInstruction(new (arena_) HThrow(exception, dex_pc));
// A throw instruction must branch to the exit block.
current_block_->AddSuccessor(exit_block_);
@@ -2710,7 +2707,7 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, uint32
case Instruction::MONITOR_ENTER: {
current_block_->AddInstruction(new (arena_) HMonitorOperation(
- LoadLocal(instruction.VRegA_11x(), Primitive::kPrimNot),
+ LoadLocal(instruction.VRegA_11x(), Primitive::kPrimNot, dex_pc),
HMonitorOperation::kEnter,
dex_pc));
break;
@@ -2718,7 +2715,7 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, uint32
case Instruction::MONITOR_EXIT: {
current_block_->AddInstruction(new (arena_) HMonitorOperation(
- LoadLocal(instruction.VRegA_11x(), Primitive::kPrimNot),
+ LoadLocal(instruction.VRegA_11x(), Primitive::kPrimNot, dex_pc),
HMonitorOperation::kExit,
dex_pc));
break;
@@ -2749,14 +2746,18 @@ HLocal* HGraphBuilder::GetLocalAt(int register_index) const {
return locals_.Get(register_index);
}
-void HGraphBuilder::UpdateLocal(int register_index, HInstruction* instruction) const {
+void HGraphBuilder::UpdateLocal(int register_index,
+ HInstruction* instruction,
+ uint32_t dex_pc) const {
HLocal* local = GetLocalAt(register_index);
- current_block_->AddInstruction(new (arena_) HStoreLocal(local, instruction));
+ current_block_->AddInstruction(new (arena_) HStoreLocal(local, instruction, dex_pc));
}
-HInstruction* HGraphBuilder::LoadLocal(int register_index, Primitive::Type type) const {
+HInstruction* HGraphBuilder::LoadLocal(int register_index,
+ Primitive::Type type,
+ uint32_t dex_pc) const {
HLocal* local = GetLocalAt(register_index);
- current_block_->AddInstruction(new (arena_) HLoadLocal(local, type));
+ current_block_->AddInstruction(new (arena_) HLoadLocal(local, type, dex_pc));
return current_block_->GetLastInstruction();
}
diff --git a/compiler/optimizing/builder.h b/compiler/optimizing/builder.h
index 560ed86e50..b0238dc5f8 100644
--- a/compiler/optimizing/builder.h
+++ b/compiler/optimizing/builder.h
@@ -131,23 +131,20 @@ class HGraphBuilder : public ValueObject {
void InitializeLocals(uint16_t count);
HLocal* GetLocalAt(int register_index) const;
- void UpdateLocal(int register_index, HInstruction* instruction) const;
- HInstruction* LoadLocal(int register_index, Primitive::Type type) const;
+ void UpdateLocal(int register_index, HInstruction* instruction, uint32_t dex_pc) const;
+ HInstruction* LoadLocal(int register_index, Primitive::Type type, uint32_t dex_pc) const;
void PotentiallyAddSuspendCheck(HBasicBlock* target, uint32_t dex_pc);
void InitializeParameters(uint16_t number_of_parameters);
bool NeedsAccessCheck(uint32_t type_index) const;
template<typename T>
- void Unop_12x(const Instruction& instruction, Primitive::Type type);
-
- template<typename T>
- void Binop_23x(const Instruction& instruction, Primitive::Type type);
+ void Unop_12x(const Instruction& instruction, Primitive::Type type, uint32_t dex_pc);
template<typename T>
void Binop_23x(const Instruction& instruction, Primitive::Type type, uint32_t dex_pc);
template<typename T>
- void Binop_23x_shift(const Instruction& instruction, Primitive::Type type);
+ void Binop_23x_shift(const Instruction& instruction, Primitive::Type type, uint32_t dex_pc);
void Binop_23x_cmp(const Instruction& instruction,
Primitive::Type type,
@@ -155,19 +152,16 @@ class HGraphBuilder : public ValueObject {
uint32_t dex_pc);
template<typename T>
- void Binop_12x(const Instruction& instruction, Primitive::Type type);
-
- template<typename T>
void Binop_12x(const Instruction& instruction, Primitive::Type type, uint32_t dex_pc);
template<typename T>
- void Binop_12x_shift(const Instruction& instruction, Primitive::Type type);
+ void Binop_12x_shift(const Instruction& instruction, Primitive::Type type, uint32_t dex_pc);
template<typename T>
- void Binop_22b(const Instruction& instruction, bool reverse);
+ void Binop_22b(const Instruction& instruction, bool reverse, uint32_t dex_pc);
template<typename T>
- void Binop_22s(const Instruction& instruction, bool reverse);
+ void Binop_22s(const Instruction& instruction, bool reverse, uint32_t dex_pc);
template<typename T> void If_21t(const Instruction& instruction, uint32_t dex_pc);
template<typename T> void If_22t(const Instruction& instruction, uint32_t dex_pc);
@@ -185,7 +179,7 @@ class HGraphBuilder : public ValueObject {
bool second_is_lit,
bool is_div);
- void BuildReturn(const Instruction& instruction, Primitive::Type type);
+ void BuildReturn(const Instruction& instruction, Primitive::Type type, uint32_t dex_pc);
// Builds an instance field access node and returns whether the instruction is supported.
bool BuildInstanceFieldAccess(const Instruction& instruction, uint32_t dex_pc, bool is_put);
diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc
index 679899a23c..438ef694bf 100644
--- a/compiler/optimizing/code_generator_arm.cc
+++ b/compiler/optimizing/code_generator_arm.cc
@@ -1560,25 +1560,7 @@ void InstructionCodeGeneratorARM::VisitInvokeVirtual(HInvokeVirtual* invoke) {
return;
}
- Register temp = invoke->GetLocations()->GetTemp(0).AsRegister<Register>();
- uint32_t method_offset = mirror::Class::EmbeddedVTableEntryOffset(
- invoke->GetVTableIndex(), kArmPointerSize).Uint32Value();
- LocationSummary* locations = invoke->GetLocations();
- Location receiver = locations->InAt(0);
- uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
- // temp = object->GetClass();
- DCHECK(receiver.IsRegister());
- __ LoadFromOffset(kLoadWord, temp, receiver.AsRegister<Register>(), class_offset);
- codegen_->MaybeRecordImplicitNullCheck(invoke);
- __ MaybeUnpoisonHeapReference(temp);
- // temp = temp->GetMethodAt(method_offset);
- uint32_t entry_point = ArtMethod::EntryPointFromQuickCompiledCodeOffset(
- kArmWordSize).Int32Value();
- __ LoadFromOffset(kLoadWord, temp, temp, method_offset);
- // LR = temp->GetEntryPoint();
- __ LoadFromOffset(kLoadWord, LR, temp, entry_point);
- // LR();
- __ blx(LR);
+ codegen_->GenerateVirtualCall(invoke, invoke->GetLocations()->GetTemp(0));
DCHECK(!codegen_->IsLeafMethod());
codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
}
@@ -4607,6 +4589,28 @@ void CodeGeneratorARM::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke,
DCHECK(!IsLeafMethod());
}
+void CodeGeneratorARM::GenerateVirtualCall(HInvokeVirtual* invoke, Location temp_location) {
+ Register temp = temp_location.AsRegister<Register>();
+ uint32_t method_offset = mirror::Class::EmbeddedVTableEntryOffset(
+ invoke->GetVTableIndex(), kArmPointerSize).Uint32Value();
+ LocationSummary* locations = invoke->GetLocations();
+ Location receiver = locations->InAt(0);
+ uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
+ // temp = object->GetClass();
+ DCHECK(receiver.IsRegister());
+ __ LoadFromOffset(kLoadWord, temp, receiver.AsRegister<Register>(), class_offset);
+ MaybeRecordImplicitNullCheck(invoke);
+ __ MaybeUnpoisonHeapReference(temp);
+ // temp = temp->GetMethodAt(method_offset);
+ uint32_t entry_point = ArtMethod::EntryPointFromQuickCompiledCodeOffset(
+ kArmWordSize).Int32Value();
+ __ LoadFromOffset(kLoadWord, temp, temp, method_offset);
+ // LR = temp->GetEntryPoint();
+ __ LoadFromOffset(kLoadWord, LR, temp, entry_point);
+ // LR();
+ __ blx(LR);
+}
+
void CodeGeneratorARM::EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patches) {
DCHECK(linker_patches->empty());
size_t size = method_patches_.size() + call_patches_.size() + relative_call_patches_.size();
diff --git a/compiler/optimizing/code_generator_arm.h b/compiler/optimizing/code_generator_arm.h
index 9528cca36f..4a0df4e936 100644
--- a/compiler/optimizing/code_generator_arm.h
+++ b/compiler/optimizing/code_generator_arm.h
@@ -327,6 +327,7 @@ class CodeGeneratorARM : public CodeGenerator {
Label* GetFrameEntryLabel() { return &frame_entry_label_; }
void GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp);
+ void GenerateVirtualCall(HInvokeVirtual* invoke, Location temp);
void EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patches) OVERRIDE;
diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc
index 390ea6b576..6b1457bc31 100644
--- a/compiler/optimizing/code_generator_arm64.cc
+++ b/compiler/optimizing/code_generator_arm64.cc
@@ -2474,6 +2474,29 @@ void CodeGeneratorARM64::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invok
DCHECK(!IsLeafMethod());
}
+void CodeGeneratorARM64::GenerateVirtualCall(HInvokeVirtual* invoke, Location temp_in) {
+ LocationSummary* locations = invoke->GetLocations();
+ Location receiver = locations->InAt(0);
+ Register temp = XRegisterFrom(temp_in);
+ size_t method_offset = mirror::Class::EmbeddedVTableEntryOffset(
+ invoke->GetVTableIndex(), kArm64PointerSize).SizeValue();
+ Offset class_offset = mirror::Object::ClassOffset();
+ Offset entry_point = ArtMethod::EntryPointFromQuickCompiledCodeOffset(kArm64WordSize);
+
+ BlockPoolsScope block_pools(GetVIXLAssembler());
+
+ DCHECK(receiver.IsRegister());
+ __ Ldr(temp.W(), HeapOperandFrom(receiver, class_offset));
+ MaybeRecordImplicitNullCheck(invoke);
+ GetAssembler()->MaybeUnpoisonHeapReference(temp.W());
+ // temp = temp->GetMethodAt(method_offset);
+ __ Ldr(temp, MemOperand(temp, method_offset));
+ // lr = temp->GetEntryPoint();
+ __ Ldr(lr, MemOperand(temp, entry_point.SizeValue()));
+ // lr();
+ __ Blr(lr);
+}
+
void CodeGeneratorARM64::EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patches) {
DCHECK(linker_patches->empty());
size_t size =
@@ -2567,26 +2590,7 @@ void InstructionCodeGeneratorARM64::VisitInvokeVirtual(HInvokeVirtual* invoke) {
return;
}
- LocationSummary* locations = invoke->GetLocations();
- Location receiver = locations->InAt(0);
- Register temp = XRegisterFrom(invoke->GetLocations()->GetTemp(0));
- size_t method_offset = mirror::Class::EmbeddedVTableEntryOffset(
- invoke->GetVTableIndex(), kArm64PointerSize).SizeValue();
- Offset class_offset = mirror::Object::ClassOffset();
- Offset entry_point = ArtMethod::EntryPointFromQuickCompiledCodeOffset(kArm64WordSize);
-
- BlockPoolsScope block_pools(GetVIXLAssembler());
-
- DCHECK(receiver.IsRegister());
- __ Ldr(temp.W(), HeapOperandFrom(receiver, class_offset));
- codegen_->MaybeRecordImplicitNullCheck(invoke);
- GetAssembler()->MaybeUnpoisonHeapReference(temp.W());
- // temp = temp->GetMethodAt(method_offset);
- __ Ldr(temp, MemOperand(temp, method_offset));
- // lr = temp->GetEntryPoint();
- __ Ldr(lr, MemOperand(temp, entry_point.SizeValue()));
- // lr();
- __ Blr(lr);
+ codegen_->GenerateVirtualCall(invoke, invoke->GetLocations()->GetTemp(0));
DCHECK(!codegen_->IsLeafMethod());
codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
}
diff --git a/compiler/optimizing/code_generator_arm64.h b/compiler/optimizing/code_generator_arm64.h
index 18070fc6b6..12ead7e11d 100644
--- a/compiler/optimizing/code_generator_arm64.h
+++ b/compiler/optimizing/code_generator_arm64.h
@@ -359,6 +359,7 @@ class CodeGeneratorARM64 : public CodeGenerator {
}
void GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp);
+ void GenerateVirtualCall(HInvokeVirtual* invoke, Location temp);
void EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patches) OVERRIDE;
diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc
index f48395b1e1..a5ad226e0b 100644
--- a/compiler/optimizing/code_generator_x86.cc
+++ b/compiler/optimizing/code_generator_x86.cc
@@ -19,6 +19,7 @@
#include "art_method.h"
#include "code_generator_utils.h"
#include "compiled_method.h"
+#include "constant_area_fixups_x86.h"
#include "entrypoints/quick/quick_entrypoints.h"
#include "entrypoints/quick/quick_entrypoints_enum.h"
#include "gc/accounting/card_table.h"
@@ -1548,23 +1549,11 @@ void LocationsBuilderX86::HandleInvoke(HInvoke* invoke) {
}
void InstructionCodeGeneratorX86::VisitInvokeVirtual(HInvokeVirtual* invoke) {
- Register temp = invoke->GetLocations()->GetTemp(0).AsRegister<Register>();
- uint32_t method_offset = mirror::Class::EmbeddedVTableEntryOffset(
- invoke->GetVTableIndex(), kX86PointerSize).Uint32Value();
- LocationSummary* locations = invoke->GetLocations();
- Location receiver = locations->InAt(0);
- uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
- // temp = object->GetClass();
- DCHECK(receiver.IsRegister());
- __ movl(temp, Address(receiver.AsRegister<Register>(), class_offset));
- codegen_->MaybeRecordImplicitNullCheck(invoke);
- __ MaybeUnpoisonHeapReference(temp);
- // temp = temp->GetMethodAt(method_offset);
- __ movl(temp, Address(temp, method_offset));
- // call temp->GetEntryPoint();
- __ call(Address(
- temp, ArtMethod::EntryPointFromQuickCompiledCodeOffset(kX86WordSize).Int32Value()));
+ if (TryGenerateIntrinsicCode(invoke, codegen_)) {
+ return;
+ }
+ codegen_->GenerateVirtualCall(invoke, invoke->GetLocations()->GetTemp(0));
DCHECK(!codegen_->IsLeafMethod());
codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
}
@@ -2213,7 +2202,7 @@ void LocationsBuilderX86::VisitAdd(HAdd* add) {
case Primitive::kPrimFloat:
case Primitive::kPrimDouble: {
locations->SetInAt(0, Location::RequiresFpuRegister());
- locations->SetInAt(1, Location::RequiresFpuRegister());
+ locations->SetInAt(1, Location::Any());
locations->SetOut(Location::SameAsFirstInput());
break;
}
@@ -2275,6 +2264,16 @@ void InstructionCodeGeneratorX86::VisitAdd(HAdd* add) {
case Primitive::kPrimFloat: {
if (second.IsFpuRegister()) {
__ addss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
+ } else if (add->InputAt(1)->IsX86LoadFromConstantTable()) {
+ HX86LoadFromConstantTable* const_area = add->InputAt(1)->AsX86LoadFromConstantTable();
+ DCHECK(!const_area->NeedsMaterialization());
+ __ addss(first.AsFpuRegister<XmmRegister>(),
+ codegen_->LiteralFloatAddress(
+ const_area->GetConstant()->AsFloatConstant()->GetValue(),
+ const_area->GetLocations()->InAt(0).AsRegister<Register>()));
+ } else {
+ DCHECK(second.IsStackSlot());
+ __ addss(first.AsFpuRegister<XmmRegister>(), Address(ESP, second.GetStackIndex()));
}
break;
}
@@ -2282,6 +2281,16 @@ void InstructionCodeGeneratorX86::VisitAdd(HAdd* add) {
case Primitive::kPrimDouble: {
if (second.IsFpuRegister()) {
__ addsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
+ } else if (add->InputAt(1)->IsX86LoadFromConstantTable()) {
+ HX86LoadFromConstantTable* const_area = add->InputAt(1)->AsX86LoadFromConstantTable();
+ DCHECK(!const_area->NeedsMaterialization());
+ __ addsd(first.AsFpuRegister<XmmRegister>(),
+ codegen_->LiteralDoubleAddress(
+ const_area->GetConstant()->AsDoubleConstant()->GetValue(),
+ const_area->GetLocations()->InAt(0).AsRegister<Register>()));
+ } else {
+ DCHECK(second.IsDoubleStackSlot());
+ __ addsd(first.AsFpuRegister<XmmRegister>(), Address(ESP, second.GetStackIndex()));
}
break;
}
@@ -2305,7 +2314,7 @@ void LocationsBuilderX86::VisitSub(HSub* sub) {
case Primitive::kPrimFloat:
case Primitive::kPrimDouble: {
locations->SetInAt(0, Location::RequiresFpuRegister());
- locations->SetInAt(1, Location::RequiresFpuRegister());
+ locations->SetInAt(1, Location::Any());
locations->SetOut(Location::SameAsFirstInput());
break;
}
@@ -2351,12 +2360,36 @@ void InstructionCodeGeneratorX86::VisitSub(HSub* sub) {
}
case Primitive::kPrimFloat: {
- __ subss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
+ if (second.IsFpuRegister()) {
+ __ subss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
+ } else if (sub->InputAt(1)->IsX86LoadFromConstantTable()) {
+ HX86LoadFromConstantTable* const_area = sub->InputAt(1)->AsX86LoadFromConstantTable();
+ DCHECK(!const_area->NeedsMaterialization());
+ __ subss(first.AsFpuRegister<XmmRegister>(),
+ codegen_->LiteralFloatAddress(
+ const_area->GetConstant()->AsFloatConstant()->GetValue(),
+ const_area->GetLocations()->InAt(0).AsRegister<Register>()));
+ } else {
+ DCHECK(second.IsStackSlot());
+ __ subss(first.AsFpuRegister<XmmRegister>(), Address(ESP, second.GetStackIndex()));
+ }
break;
}
case Primitive::kPrimDouble: {
- __ subsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
+ if (second.IsFpuRegister()) {
+ __ subsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
+ } else if (sub->InputAt(1)->IsX86LoadFromConstantTable()) {
+ HX86LoadFromConstantTable* const_area = sub->InputAt(1)->AsX86LoadFromConstantTable();
+ DCHECK(!const_area->NeedsMaterialization());
+ __ subsd(first.AsFpuRegister<XmmRegister>(),
+ codegen_->LiteralDoubleAddress(
+ const_area->GetConstant()->AsDoubleConstant()->GetValue(),
+ const_area->GetLocations()->InAt(0).AsRegister<Register>()));
+ } else {
+ DCHECK(second.IsDoubleStackSlot());
+ __ subsd(first.AsFpuRegister<XmmRegister>(), Address(ESP, second.GetStackIndex()));
+ }
break;
}
@@ -2391,7 +2424,7 @@ void LocationsBuilderX86::VisitMul(HMul* mul) {
case Primitive::kPrimFloat:
case Primitive::kPrimDouble: {
locations->SetInAt(0, Location::RequiresFpuRegister());
- locations->SetInAt(1, Location::RequiresFpuRegister());
+ locations->SetInAt(1, Location::Any());
locations->SetOut(Location::SameAsFirstInput());
break;
}
@@ -2507,12 +2540,38 @@ void InstructionCodeGeneratorX86::VisitMul(HMul* mul) {
}
case Primitive::kPrimFloat: {
- __ mulss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
+ DCHECK(first.Equals(locations->Out()));
+ if (second.IsFpuRegister()) {
+ __ mulss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
+ } else if (mul->InputAt(1)->IsX86LoadFromConstantTable()) {
+ HX86LoadFromConstantTable* const_area = mul->InputAt(1)->AsX86LoadFromConstantTable();
+ DCHECK(!const_area->NeedsMaterialization());
+ __ mulss(first.AsFpuRegister<XmmRegister>(),
+ codegen_->LiteralFloatAddress(
+ const_area->GetConstant()->AsFloatConstant()->GetValue(),
+ const_area->GetLocations()->InAt(0).AsRegister<Register>()));
+ } else {
+ DCHECK(second.IsStackSlot());
+ __ mulss(first.AsFpuRegister<XmmRegister>(), Address(ESP, second.GetStackIndex()));
+ }
break;
}
case Primitive::kPrimDouble: {
- __ mulsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
+ DCHECK(first.Equals(locations->Out()));
+ if (second.IsFpuRegister()) {
+ __ mulsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
+ } else if (mul->InputAt(1)->IsX86LoadFromConstantTable()) {
+ HX86LoadFromConstantTable* const_area = mul->InputAt(1)->AsX86LoadFromConstantTable();
+ DCHECK(!const_area->NeedsMaterialization());
+ __ mulsd(first.AsFpuRegister<XmmRegister>(),
+ codegen_->LiteralDoubleAddress(
+ const_area->GetConstant()->AsDoubleConstant()->GetValue(),
+ const_area->GetLocations()->InAt(0).AsRegister<Register>()));
+ } else {
+ DCHECK(second.IsDoubleStackSlot());
+ __ mulsd(first.AsFpuRegister<XmmRegister>(), Address(ESP, second.GetStackIndex()));
+ }
break;
}
@@ -2855,7 +2914,7 @@ void LocationsBuilderX86::VisitDiv(HDiv* div) {
case Primitive::kPrimFloat:
case Primitive::kPrimDouble: {
locations->SetInAt(0, Location::RequiresFpuRegister());
- locations->SetInAt(1, Location::RequiresFpuRegister());
+ locations->SetInAt(1, Location::Any());
locations->SetOut(Location::SameAsFirstInput());
break;
}
@@ -2867,7 +2926,6 @@ void LocationsBuilderX86::VisitDiv(HDiv* div) {
void InstructionCodeGeneratorX86::VisitDiv(HDiv* div) {
LocationSummary* locations = div->GetLocations();
- Location out = locations->Out();
Location first = locations->InAt(0);
Location second = locations->InAt(1);
@@ -2879,14 +2937,36 @@ void InstructionCodeGeneratorX86::VisitDiv(HDiv* div) {
}
case Primitive::kPrimFloat: {
- DCHECK(first.Equals(out));
- __ divss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
+ if (second.IsFpuRegister()) {
+ __ divss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
+ } else if (div->InputAt(1)->IsX86LoadFromConstantTable()) {
+ HX86LoadFromConstantTable* const_area = div->InputAt(1)->AsX86LoadFromConstantTable();
+ DCHECK(!const_area->NeedsMaterialization());
+ __ divss(first.AsFpuRegister<XmmRegister>(),
+ codegen_->LiteralFloatAddress(
+ const_area->GetConstant()->AsFloatConstant()->GetValue(),
+ const_area->GetLocations()->InAt(0).AsRegister<Register>()));
+ } else {
+ DCHECK(second.IsStackSlot());
+ __ divss(first.AsFpuRegister<XmmRegister>(), Address(ESP, second.GetStackIndex()));
+ }
break;
}
case Primitive::kPrimDouble: {
- DCHECK(first.Equals(out));
- __ divsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
+ if (second.IsFpuRegister()) {
+ __ divsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
+ } else if (div->InputAt(1)->IsX86LoadFromConstantTable()) {
+ HX86LoadFromConstantTable* const_area = div->InputAt(1)->AsX86LoadFromConstantTable();
+ DCHECK(!const_area->NeedsMaterialization());
+ __ divsd(first.AsFpuRegister<XmmRegister>(),
+ codegen_->LiteralDoubleAddress(
+ const_area->GetConstant()->AsDoubleConstant()->GetValue(),
+ const_area->GetLocations()->InAt(0).AsRegister<Register>()));
+ } else {
+ DCHECK(second.IsDoubleStackSlot());
+ __ divsd(first.AsFpuRegister<XmmRegister>(), Address(ESP, second.GetStackIndex()));
+ }
break;
}
@@ -3570,6 +3650,25 @@ void CodeGeneratorX86::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke,
DCHECK(!IsLeafMethod());
}
+void CodeGeneratorX86::GenerateVirtualCall(HInvokeVirtual* invoke, Location temp_in) {
+ Register temp = temp_in.AsRegister<Register>();
+ uint32_t method_offset = mirror::Class::EmbeddedVTableEntryOffset(
+ invoke->GetVTableIndex(), kX86PointerSize).Uint32Value();
+ LocationSummary* locations = invoke->GetLocations();
+ Location receiver = locations->InAt(0);
+ uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
+ // temp = object->GetClass();
+ DCHECK(receiver.IsRegister());
+ __ movl(temp, Address(receiver.AsRegister<Register>(), class_offset));
+ MaybeRecordImplicitNullCheck(invoke);
+ __ MaybeUnpoisonHeapReference(temp);
+ // temp = temp->GetMethodAt(method_offset);
+ __ movl(temp, Address(temp, method_offset));
+ // call temp->GetEntryPoint();
+ __ call(Address(
+ temp, ArtMethod::EntryPointFromQuickCompiledCodeOffset(kX86WordSize).Int32Value()));
+}
+
void CodeGeneratorX86::EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patches) {
DCHECK(linker_patches->empty());
linker_patches->reserve(method_patches_.size() + relative_call_patches_.size());
@@ -5085,6 +5184,245 @@ void InstructionCodeGeneratorX86::VisitFakeString(HFakeString* instruction ATTRI
// Will be generated at use site.
}
+void LocationsBuilderX86::VisitX86ComputeBaseMethodAddress(
+ HX86ComputeBaseMethodAddress* insn) {
+ LocationSummary* locations =
+ new (GetGraph()->GetArena()) LocationSummary(insn, LocationSummary::kNoCall);
+ locations->SetOut(Location::RequiresRegister());
+}
+
+void InstructionCodeGeneratorX86::VisitX86ComputeBaseMethodAddress(
+ HX86ComputeBaseMethodAddress* insn) {
+ LocationSummary* locations = insn->GetLocations();
+ Register reg = locations->Out().AsRegister<Register>();
+
+ // Generate call to next instruction.
+ Label next_instruction;
+ __ call(&next_instruction);
+ __ Bind(&next_instruction);
+
+ // Remember this offset for later use with constant area.
+ codegen_->SetMethodAddressOffset(GetAssembler()->CodeSize());
+
+ // Grab the return address off the stack.
+ __ popl(reg);
+}
+
+void LocationsBuilderX86::VisitX86LoadFromConstantTable(
+ HX86LoadFromConstantTable* insn) {
+ LocationSummary* locations =
+ new (GetGraph()->GetArena()) LocationSummary(insn, LocationSummary::kNoCall);
+
+ locations->SetInAt(0, Location::RequiresRegister());
+ locations->SetInAt(1, Location::ConstantLocation(insn->GetConstant()));
+
+ // If we don't need to be materialized, we only need the inputs to be set.
+ if (!insn->NeedsMaterialization()) {
+ return;
+ }
+
+ switch (insn->GetType()) {
+ case Primitive::kPrimFloat:
+ case Primitive::kPrimDouble:
+ locations->SetOut(Location::RequiresFpuRegister());
+ break;
+
+ case Primitive::kPrimInt:
+ locations->SetOut(Location::RequiresRegister());
+ break;
+
+ default:
+ LOG(FATAL) << "Unsupported x86 constant area type " << insn->GetType();
+ }
+}
+
+void InstructionCodeGeneratorX86::VisitX86LoadFromConstantTable(HX86LoadFromConstantTable* insn) {
+ if (!insn->NeedsMaterialization()) {
+ return;
+ }
+
+ LocationSummary* locations = insn->GetLocations();
+ Location out = locations->Out();
+ Register const_area = locations->InAt(0).AsRegister<Register>();
+ HConstant *value = insn->GetConstant();
+
+ switch (insn->GetType()) {
+ case Primitive::kPrimFloat:
+ __ movss(out.AsFpuRegister<XmmRegister>(),
+ codegen_->LiteralFloatAddress(value->AsFloatConstant()->GetValue(), const_area));
+ break;
+
+ case Primitive::kPrimDouble:
+ __ movsd(out.AsFpuRegister<XmmRegister>(),
+ codegen_->LiteralDoubleAddress(value->AsDoubleConstant()->GetValue(), const_area));
+ break;
+
+ case Primitive::kPrimInt:
+ __ movl(out.AsRegister<Register>(),
+ codegen_->LiteralInt32Address(value->AsIntConstant()->GetValue(), const_area));
+ break;
+
+ default:
+ LOG(FATAL) << "Unsupported x86 constant area type " << insn->GetType();
+ }
+}
+
+void CodeGeneratorX86::Finalize(CodeAllocator* allocator) {
+ // Generate the constant area if needed.
+ X86Assembler* assembler = GetAssembler();
+ if (!assembler->IsConstantAreaEmpty()) {
+ // Align to 4 byte boundary to reduce cache misses, as the data is 4 and 8
+ // byte values.
+ assembler->Align(4, 0);
+ constant_area_start_ = assembler->CodeSize();
+ assembler->AddConstantArea();
+ }
+
+ // And finish up.
+ CodeGenerator::Finalize(allocator);
+}
+
+/**
+ * Class to handle late fixup of offsets into constant area.
+ */
+class RIPFixup : public AssemblerFixup, public ArenaObject<kArenaAllocMisc> {
+ public:
+ RIPFixup(const CodeGeneratorX86& codegen, int offset)
+ : codegen_(codegen), offset_into_constant_area_(offset) {}
+
+ private:
+ void Process(const MemoryRegion& region, int pos) OVERRIDE {
+ // Patch the correct offset for the instruction. The place to patch is the
+ // last 4 bytes of the instruction.
+ // The value to patch is the distance from the offset in the constant area
+ // from the address computed by the HX86ComputeBaseMethodAddress instruction.
+ int32_t constant_offset = codegen_.ConstantAreaStart() + offset_into_constant_area_;
+ int32_t relative_position = constant_offset - codegen_.GetMethodAddressOffset();;
+
+ // Patch in the right value.
+ region.StoreUnaligned<int32_t>(pos - 4, relative_position);
+ }
+
+ const CodeGeneratorX86& codegen_;
+
+ // Location in constant area that the fixup refers to.
+ int offset_into_constant_area_;
+};
+
+Address CodeGeneratorX86::LiteralDoubleAddress(double v, Register reg) {
+ AssemblerFixup* fixup = new (GetGraph()->GetArena()) RIPFixup(*this, __ AddDouble(v));
+ return Address(reg, kDummy32BitOffset, fixup);
+}
+
+Address CodeGeneratorX86::LiteralFloatAddress(float v, Register reg) {
+ AssemblerFixup* fixup = new (GetGraph()->GetArena()) RIPFixup(*this, __ AddFloat(v));
+ return Address(reg, kDummy32BitOffset, fixup);
+}
+
+Address CodeGeneratorX86::LiteralInt32Address(int32_t v, Register reg) {
+ AssemblerFixup* fixup = new (GetGraph()->GetArena()) RIPFixup(*this, __ AddInt32(v));
+ return Address(reg, kDummy32BitOffset, fixup);
+}
+
+Address CodeGeneratorX86::LiteralInt64Address(int64_t v, Register reg) {
+ AssemblerFixup* fixup = new (GetGraph()->GetArena()) RIPFixup(*this, __ AddInt64(v));
+ return Address(reg, kDummy32BitOffset, fixup);
+}
+
+/**
+ * Finds instructions that need the constant area base as an input.
+ */
+class ConstantHandlerVisitor : public HGraphVisitor {
+ public:
+ explicit ConstantHandlerVisitor(HGraph* graph) : HGraphVisitor(graph), base_(nullptr) {}
+
+ private:
+ void VisitAdd(HAdd* add) OVERRIDE {
+ BinaryFP(add);
+ }
+
+ void VisitSub(HSub* sub) OVERRIDE {
+ BinaryFP(sub);
+ }
+
+ void VisitMul(HMul* mul) OVERRIDE {
+ BinaryFP(mul);
+ }
+
+ void VisitDiv(HDiv* div) OVERRIDE {
+ BinaryFP(div);
+ }
+
+ void VisitReturn(HReturn* ret) OVERRIDE {
+ HConstant* value = ret->InputAt(0)->AsConstant();
+ if ((value != nullptr && Primitive::IsFloatingPointType(value->GetType()))) {
+ ReplaceInput(ret, value, 0, true);
+ }
+ }
+
+ void VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) OVERRIDE {
+ HandleInvoke(invoke);
+ }
+
+ void VisitInvokeVirtual(HInvokeVirtual* invoke) OVERRIDE {
+ HandleInvoke(invoke);
+ }
+
+ void VisitInvokeInterface(HInvokeInterface* invoke) OVERRIDE {
+ HandleInvoke(invoke);
+ }
+
+ void BinaryFP(HBinaryOperation* bin) {
+ HConstant* rhs = bin->InputAt(1)->AsConstant();
+ if (rhs != nullptr && Primitive::IsFloatingPointType(bin->GetResultType())) {
+ ReplaceInput(bin, rhs, 1, false);
+ }
+ }
+
+ void InitializeConstantAreaPointer(HInstruction* user) {
+ // Ensure we only initialize the pointer once.
+ if (base_ != nullptr) {
+ return;
+ }
+
+ HGraph* graph = GetGraph();
+ HBasicBlock* entry = graph->GetEntryBlock();
+ base_ = new (graph->GetArena()) HX86ComputeBaseMethodAddress();
+ HInstruction* insert_pos = (user->GetBlock() == entry) ? user : entry->GetLastInstruction();
+ entry->InsertInstructionBefore(base_, insert_pos);
+ DCHECK(base_ != nullptr);
+ }
+
+ void ReplaceInput(HInstruction* insn, HConstant* value, int input_index, bool materialize) {
+ InitializeConstantAreaPointer(insn);
+ HGraph* graph = GetGraph();
+ HBasicBlock* block = insn->GetBlock();
+ HX86LoadFromConstantTable* load_constant =
+ new (graph->GetArena()) HX86LoadFromConstantTable(base_, value, materialize);
+ block->InsertInstructionBefore(load_constant, insn);
+ insn->ReplaceInput(load_constant, input_index);
+ }
+
+ void HandleInvoke(HInvoke* invoke) {
+ // Ensure that we can load FP arguments from the constant area.
+ for (size_t i = 0, e = invoke->InputCount(); i < e; i++) {
+ HConstant* input = invoke->InputAt(i)->AsConstant();
+ if (input != nullptr && Primitive::IsFloatingPointType(input->GetType())) {
+ ReplaceInput(invoke, input, i, true);
+ }
+ }
+ }
+
+ // The generated HX86ComputeBaseMethodAddress in the entry block needed as an
+ // input to the HX86LoadFromConstantTable instructions.
+ HX86ComputeBaseMethodAddress* base_;
+};
+
+void ConstantAreaFixups::Run() {
+ ConstantHandlerVisitor visitor(graph_);
+ visitor.VisitInsertionOrder();
+}
+
#undef __
} // namespace x86
diff --git a/compiler/optimizing/code_generator_x86.h b/compiler/optimizing/code_generator_x86.h
index 17787a82df..bd7cb12777 100644
--- a/compiler/optimizing/code_generator_x86.h
+++ b/compiler/optimizing/code_generator_x86.h
@@ -294,6 +294,8 @@ class CodeGeneratorX86 : public CodeGenerator {
// Generate a call to a static or direct method.
void GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp);
+ // Generate a call to a virtual method.
+ void GenerateVirtualCall(HInvokeVirtual* invoke, Location temp);
// Emit linker patches.
void EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patches) OVERRIDE;
@@ -325,6 +327,25 @@ class CodeGeneratorX86 : public CodeGenerator {
return isa_features_;
}
+ void SetMethodAddressOffset(int32_t offset) {
+ method_address_offset_ = offset;
+ }
+
+ int32_t GetMethodAddressOffset() const {
+ return method_address_offset_;
+ }
+
+ int32_t ConstantAreaStart() const {
+ return constant_area_start_;
+ }
+
+ Address LiteralDoubleAddress(double v, Register reg);
+ Address LiteralFloatAddress(float v, Register reg);
+ Address LiteralInt32Address(int32_t v, Register reg);
+ Address LiteralInt64Address(int64_t v, Register reg);
+
+ void Finalize(CodeAllocator* allocator) OVERRIDE;
+
private:
// Labels for each block that will be compiled.
GrowableArray<Label> block_labels_;
@@ -339,6 +360,20 @@ class CodeGeneratorX86 : public CodeGenerator {
ArenaDeque<MethodPatchInfo<Label>> method_patches_;
ArenaDeque<MethodPatchInfo<Label>> relative_call_patches_;
+ // Offset to the start of the constant area in the assembled code.
+ // Used for fixups to the constant area.
+ int32_t constant_area_start_;
+
+ // If there is a HX86ComputeBaseMethodAddress instruction in the graph
+ // (which shall be the sole instruction of this kind), subtracting this offset
+ // from the value contained in the out register of this HX86ComputeBaseMethodAddress
+ // instruction gives the address of the start of this method.
+ int32_t method_address_offset_;
+
+ // When we don't know the proper offset for the value, we use kDummy32BitOffset.
+ // The correct value will be inserted when processing Assembler fixups.
+ static constexpr int32_t kDummy32BitOffset = 256;
+
DISALLOW_COPY_AND_ASSIGN(CodeGeneratorX86);
};
diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc
index e1ec2ea64f..0f3eb74c64 100644
--- a/compiler/optimizing/code_generator_x86_64.cc
+++ b/compiler/optimizing/code_generator_x86_64.cc
@@ -475,6 +475,25 @@ void CodeGeneratorX86_64::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invo
DCHECK(!IsLeafMethod());
}
+void CodeGeneratorX86_64::GenerateVirtualCall(HInvokeVirtual* invoke, Location temp_in) {
+ CpuRegister temp = temp_in.AsRegister<CpuRegister>();
+ size_t method_offset = mirror::Class::EmbeddedVTableEntryOffset(
+ invoke->GetVTableIndex(), kX86_64PointerSize).SizeValue();
+ LocationSummary* locations = invoke->GetLocations();
+ Location receiver = locations->InAt(0);
+ size_t class_offset = mirror::Object::ClassOffset().SizeValue();
+ // temp = object->GetClass();
+ DCHECK(receiver.IsRegister());
+ __ movl(temp, Address(receiver.AsRegister<CpuRegister>(), class_offset));
+ MaybeRecordImplicitNullCheck(invoke);
+ __ MaybeUnpoisonHeapReference(temp);
+ // temp = temp->GetMethodAt(method_offset);
+ __ movq(temp, Address(temp, method_offset));
+ // call temp->GetEntryPoint();
+ __ call(Address(temp, ArtMethod::EntryPointFromQuickCompiledCodeOffset(
+ kX86_64WordSize).SizeValue()));
+}
+
void CodeGeneratorX86_64::EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patches) {
DCHECK(linker_patches->empty());
size_t size =
@@ -1709,22 +1728,7 @@ void InstructionCodeGeneratorX86_64::VisitInvokeVirtual(HInvokeVirtual* invoke)
return;
}
- CpuRegister temp = invoke->GetLocations()->GetTemp(0).AsRegister<CpuRegister>();
- size_t method_offset = mirror::Class::EmbeddedVTableEntryOffset(
- invoke->GetVTableIndex(), kX86_64PointerSize).SizeValue();
- LocationSummary* locations = invoke->GetLocations();
- Location receiver = locations->InAt(0);
- size_t class_offset = mirror::Object::ClassOffset().SizeValue();
- // temp = object->GetClass();
- DCHECK(receiver.IsRegister());
- __ movl(temp, Address(receiver.AsRegister<CpuRegister>(), class_offset));
- codegen_->MaybeRecordImplicitNullCheck(invoke);
- __ MaybeUnpoisonHeapReference(temp);
- // temp = temp->GetMethodAt(method_offset);
- __ movq(temp, Address(temp, method_offset));
- // call temp->GetEntryPoint();
- __ call(Address(temp, ArtMethod::EntryPointFromQuickCompiledCodeOffset(
- kX86_64WordSize).SizeValue()));
+ codegen_->GenerateVirtualCall(invoke, invoke->GetLocations()->GetTemp(0));
DCHECK(!codegen_->IsLeafMethod());
codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
diff --git a/compiler/optimizing/code_generator_x86_64.h b/compiler/optimizing/code_generator_x86_64.h
index 21357be0a5..f9d8e041d9 100644
--- a/compiler/optimizing/code_generator_x86_64.h
+++ b/compiler/optimizing/code_generator_x86_64.h
@@ -305,6 +305,7 @@ class CodeGeneratorX86_64 : public CodeGenerator {
}
void GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp);
+ void GenerateVirtualCall(HInvokeVirtual* invoke, Location temp);
void EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patches) OVERRIDE;
diff --git a/compiler/optimizing/constant_area_fixups_x86.h b/compiler/optimizing/constant_area_fixups_x86.h
new file mode 100644
index 0000000000..4138039cdd
--- /dev/null
+++ b/compiler/optimizing/constant_area_fixups_x86.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_COMPILER_OPTIMIZING_CONSTANT_AREA_FIXUPS_X86_H_
+#define ART_COMPILER_OPTIMIZING_CONSTANT_AREA_FIXUPS_X86_H_
+
+#include "nodes.h"
+#include "optimization.h"
+
+namespace art {
+namespace x86 {
+
+class ConstantAreaFixups : public HOptimization {
+ public:
+ ConstantAreaFixups(HGraph* graph, OptimizingCompilerStats* stats)
+ : HOptimization(graph, "constant_area_fixups_x86", stats) {}
+
+ void Run() OVERRIDE;
+};
+
+} // namespace x86
+} // namespace art
+
+#endif // ART_COMPILER_OPTIMIZING_CONSTANT_AREA_FIXUPS_X86_H_
diff --git a/compiler/optimizing/induction_var_analysis.cc b/compiler/optimizing/induction_var_analysis.cc
index 8b38414de0..3f5a6e7993 100644
--- a/compiler/optimizing/induction_var_analysis.cc
+++ b/compiler/optimizing/induction_var_analysis.cc
@@ -42,33 +42,6 @@ static bool IsEntryPhi(HLoopInformation* loop, HInstruction* instruction) {
instruction->GetBlock() == loop->GetHeader();
}
-/**
- * Returns true for 32/64-bit integral constant, passing its value as output parameter.
- */
-static bool IsIntAndGet(HInstruction* instruction, int64_t* value) {
- if (instruction->IsIntConstant()) {
- *value = instruction->AsIntConstant()->GetValue();
- return true;
- } else if (instruction->IsLongConstant()) {
- *value = instruction->AsLongConstant()->GetValue();
- return true;
- }
- return false;
-}
-
-/**
- * Returns a string representation of an instruction
- * (for testing and debugging only).
- */
-static std::string InstructionToString(HInstruction* instruction) {
- if (instruction->IsIntConstant()) {
- return std::to_string(instruction->AsIntConstant()->GetValue());
- } else if (instruction->IsLongConstant()) {
- return std::to_string(instruction->AsLongConstant()->GetValue()) + "L";
- }
- return std::to_string(instruction->GetId()) + ":" + instruction->DebugName();
-}
-
//
// Class methods.
//
@@ -125,6 +98,9 @@ void HInductionVarAnalysis::VisitLoop(HLoopInformation* loop) {
DCHECK(stack_.empty());
map_.clear();
+
+ // Determine the loop's trip count.
+ VisitControl(loop);
}
void HInductionVarAnalysis::VisitNode(HLoopInformation* loop, HInstruction* instruction) {
@@ -242,7 +218,7 @@ void HInductionVarAnalysis::ClassifyNonTrivial(HLoopInformation* loop) {
if (size == 1) {
InductionInfo* update = LookupInfo(loop, internal);
if (update != nullptr) {
- AssignInfo(loop, phi, NewInduction(kWrapAround, initial, update));
+ AssignInfo(loop, phi, CreateInduction(kWrapAround, initial, update));
}
return;
}
@@ -275,7 +251,7 @@ void HInductionVarAnalysis::ClassifyNonTrivial(HLoopInformation* loop) {
case kInvariant:
// Classify phi (last element in scc_) and then the rest of the cycle "on-demand".
// Statements are scanned in the Tarjan SCC order, with phi first.
- AssignInfo(loop, phi, NewInduction(kLinear, induction, initial));
+ AssignInfo(loop, phi, CreateInduction(kLinear, induction, initial));
for (size_t i = 0; i < size - 1; i++) {
ClassifyTrivial(loop, scc_[i]);
}
@@ -305,9 +281,9 @@ HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::RotatePeriodicInduc
// (b, c, d, e, a)
// in preparation of assigning this to the previous variable in the sequence.
if (induction->induction_class == kInvariant) {
- return NewInduction(kPeriodic, induction, last);
+ return CreateInduction(kPeriodic, induction, last);
}
- return NewInduction(kPeriodic, induction->op_a, RotatePeriodicInduction(induction->op_b, last));
+ return CreateInduction(kPeriodic, induction->op_a, RotatePeriodicInduction(induction->op_b, last));
}
HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::TransferPhi(InductionInfo* a,
@@ -327,9 +303,9 @@ HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::TransferAddSub(Indu
// be combined. All other combinations fail, however.
if (a != nullptr && b != nullptr) {
if (a->induction_class == kInvariant && b->induction_class == kInvariant) {
- return NewInvariantOp(op, a, b);
+ return CreateInvariantOp(op, a, b);
} else if (a->induction_class == kLinear && b->induction_class == kLinear) {
- return NewInduction(
+ return CreateInduction(
kLinear, TransferAddSub(a->op_a, b->op_a, op), TransferAddSub(a->op_b, b->op_b, op));
} else if (a->induction_class == kInvariant) {
InductionInfo* new_a = b->op_a;
@@ -340,7 +316,7 @@ HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::TransferAddSub(Indu
} else if (op == kSub) { // Negation required.
new_a = TransferNeg(new_a);
}
- return NewInduction(b->induction_class, new_a, new_b);
+ return CreateInduction(b->induction_class, new_a, new_b);
} else if (b->induction_class == kInvariant) {
InductionInfo* new_a = a->op_a;
InductionInfo* new_b = TransferAddSub(a->op_b, b, op);
@@ -348,7 +324,7 @@ HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::TransferAddSub(Indu
DCHECK(a->induction_class == kWrapAround || a->induction_class == kPeriodic);
new_a = TransferAddSub(new_a, b, op);
}
- return NewInduction(a->induction_class, new_a, new_b);
+ return CreateInduction(a->induction_class, new_a, new_b);
}
}
return nullptr;
@@ -361,11 +337,11 @@ HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::TransferMul(Inducti
// Two non-invariant inputs cannot be multiplied, however.
if (a != nullptr && b != nullptr) {
if (a->induction_class == kInvariant && b->induction_class == kInvariant) {
- return NewInvariantOp(kMul, a, b);
+ return CreateInvariantOp(kMul, a, b);
} else if (a->induction_class == kInvariant) {
- return NewInduction(b->induction_class, TransferMul(a, b->op_a), TransferMul(a, b->op_b));
+ return CreateInduction(b->induction_class, TransferMul(a, b->op_a), TransferMul(a, b->op_b));
} else if (b->induction_class == kInvariant) {
- return NewInduction(a->induction_class, TransferMul(a->op_a, b), TransferMul(a->op_b, b));
+ return CreateInduction(a->induction_class, TransferMul(a->op_a, b), TransferMul(a->op_b, b));
}
}
return nullptr;
@@ -373,21 +349,18 @@ HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::TransferMul(Inducti
HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::TransferShl(InductionInfo* a,
InductionInfo* b,
- Primitive::Type t) {
+ Primitive::Type type) {
// Transfer over a shift left: treat shift by restricted constant as equivalent multiplication.
- if (a != nullptr && b != nullptr && b->induction_class == kInvariant && b->operation == kFetch) {
- int64_t value = -1;
+ int64_t value = -1;
+ if (a != nullptr && IsIntAndGet(b, &value)) {
// Obtain the constant needed for the multiplication. This yields an existing instruction
// if the constants is already there. Otherwise, this has a side effect on the HIR.
// The restriction on the shift factor avoids generating a negative constant
// (viz. 1 << 31 and 1L << 63 set the sign bit). The code assumes that generalization
// for shift factors outside [0,32) and [0,64) ranges is done by earlier simplification.
- if (IsIntAndGet(b->fetch, &value)) {
- if (t == Primitive::kPrimInt && 0 <= value && value < 31) {
- return TransferMul(a, NewInvariantFetch(graph_->GetIntConstant(1 << value)));
- } else if (t == Primitive::kPrimLong && 0 <= value && value < 63) {
- return TransferMul(a, NewInvariantFetch(graph_->GetLongConstant(1L << value)));
- }
+ if ((type == Primitive::kPrimInt && 0 <= value && value < 31) ||
+ (type == Primitive::kPrimLong && 0 <= value && value < 63)) {
+ return TransferMul(a, CreateConstant(1 << value, type));
}
}
return nullptr;
@@ -398,9 +371,9 @@ HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::TransferNeg(Inducti
// yields a similar but negated induction as result.
if (a != nullptr) {
if (a->induction_class == kInvariant) {
- return NewInvariantOp(kNeg, nullptr, a);
+ return CreateInvariantOp(kNeg, nullptr, a);
}
- return NewInduction(a->induction_class, TransferNeg(a->op_a), TransferNeg(a->op_b));
+ return CreateInduction(a->induction_class, TransferNeg(a->op_a), TransferNeg(a->op_b));
}
return nullptr;
}
@@ -429,13 +402,13 @@ HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::SolvePhi(HLoopInfor
if (a != nullptr && a->induction_class == kInvariant) {
if (instruction->InputAt(1) == phi) {
InductionInfo* initial = LookupInfo(loop, phi->InputAt(0));
- return NewInduction(kPeriodic, a, initial);
+ return CreateInduction(kPeriodic, a, initial);
}
auto it = cycle_.find(instruction->InputAt(1));
if (it != cycle_.end()) {
InductionInfo* b = it->second;
if (b->induction_class == kPeriodic) {
- return NewInduction(kPeriodic, a, b);
+ return CreateInduction(kPeriodic, a, b);
}
}
}
@@ -456,13 +429,13 @@ HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::SolveAddSub(HLoopIn
InductionInfo* b = LookupInfo(loop, y);
if (b != nullptr && b->induction_class == kInvariant) {
if (x == phi) {
- return (op == kAdd) ? b : NewInvariantOp(kNeg, nullptr, b);
+ return (op == kAdd) ? b : CreateInvariantOp(kNeg, nullptr, b);
}
auto it = cycle_.find(x);
if (it != cycle_.end()) {
InductionInfo* a = it->second;
if (a->induction_class == kInvariant) {
- return NewInvariantOp(op, a, b);
+ return CreateInvariantOp(op, a, b);
}
}
}
@@ -479,7 +452,7 @@ HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::SolveAddSub(HLoopIn
InductionInfo* a = LookupInfo(loop, x);
if (a != nullptr && a->induction_class == kInvariant) {
InductionInfo* initial = LookupInfo(loop, phi->InputAt(0));
- return NewInduction(kPeriodic, NewInvariantOp(kSub, a, initial), initial);
+ return CreateInduction(kPeriodic, CreateInvariantOp(kSub, a, initial), initial);
}
}
}
@@ -487,6 +460,111 @@ HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::SolveAddSub(HLoopIn
return nullptr;
}
+void HInductionVarAnalysis::VisitControl(HLoopInformation* loop) {
+ HInstruction* control = loop->GetHeader()->GetLastInstruction();
+ if (control->IsIf()) {
+ HIf* ifs = control->AsIf();
+ HBasicBlock* if_true = ifs->IfTrueSuccessor();
+ HBasicBlock* if_false = ifs->IfFalseSuccessor();
+ HInstruction* if_expr = ifs->InputAt(0);
+ // Determine if loop has following structure in header.
+ // loop-header: ....
+ // if (condition) goto X
+ if (if_expr->IsCondition()) {
+ HCondition* condition = if_expr->AsCondition();
+ InductionInfo* a = LookupInfo(loop, condition->InputAt(0));
+ InductionInfo* b = LookupInfo(loop, condition->InputAt(1));
+ Primitive::Type type = condition->InputAt(0)->GetType();
+ // Determine if the loop control uses integral arithmetic and an if-exit (X outside) or an
+ // if-iterate (X inside), always expressed as if-iterate when passing into VisitCondition().
+ if (type != Primitive::kPrimInt && type != Primitive::kPrimLong) {
+ // Loop control is not 32/64-bit integral.
+ } else if (a == nullptr || b == nullptr) {
+ // Loop control is not a sequence.
+ } else if (if_true->GetLoopInformation() != loop && if_false->GetLoopInformation() == loop) {
+ VisitCondition(loop, a, b, type, condition->GetOppositeCondition());
+ } else if (if_true->GetLoopInformation() == loop && if_false->GetLoopInformation() != loop) {
+ VisitCondition(loop, a, b, type, condition->GetCondition());
+ }
+ }
+ }
+}
+
+void HInductionVarAnalysis::VisitCondition(HLoopInformation* loop,
+ InductionInfo* a,
+ InductionInfo* b,
+ Primitive::Type type,
+ IfCondition cmp) {
+ if (a->induction_class == kInvariant && b->induction_class == kLinear) {
+ // Swap conditions (e.g. U > i is same as i < U).
+ switch (cmp) {
+ case kCondLT: VisitCondition(loop, b, a, type, kCondGT); break;
+ case kCondLE: VisitCondition(loop, b, a, type, kCondGE); break;
+ case kCondGT: VisitCondition(loop, b, a, type, kCondLT); break;
+ case kCondGE: VisitCondition(loop, b, a, type, kCondLE); break;
+ default: break;
+ }
+ } else if (a->induction_class == kLinear && b->induction_class == kInvariant) {
+ // Normalize a linear loop control with a constant, nonzero stride:
+ // stride > 0, either i < U or i <= U
+ // stride < 0, either i > U or i >= U
+ InductionInfo* stride = a->op_a;
+ InductionInfo* lo_val = a->op_b;
+ InductionInfo* hi_val = b;
+ int64_t value = -1;
+ if (IsIntAndGet(stride, &value)) {
+ if ((value > 0 && (cmp == kCondLT || cmp == kCondLE)) ||
+ (value < 0 && (cmp == kCondGT || cmp == kCondGE))) {
+ bool is_strict = cmp == kCondLT || cmp == kCondGT;
+ VisitTripCount(loop, lo_val, hi_val, stride, value, type, is_strict);
+ }
+ }
+ }
+}
+
+void HInductionVarAnalysis::VisitTripCount(HLoopInformation* loop,
+ InductionInfo* lo_val,
+ InductionInfo* hi_val,
+ InductionInfo* stride,
+ int32_t stride_value,
+ Primitive::Type type,
+ bool is_strict) {
+ // Any loop of the general form:
+ //
+ // for (i = L; i <= U; i += S) // S > 0
+ // or for (i = L; i >= U; i += S) // S < 0
+ // .. i ..
+ //
+ // can be normalized into:
+ //
+ // for (n = 0; n < TC; n++) // where TC = (U + S - L) / S
+ // .. L + S * n ..
+ //
+ // NOTE: The TC (trip-count) expression is only valid if the top-test path is taken at
+ // least once. Otherwise TC is 0. Also, the expression assumes the loop does not
+ // have any early-exits. Otherwise, TC is an upper bound.
+ //
+ bool cancels = is_strict && abs(stride_value) == 1; // compensation cancels conversion?
+ if (!cancels) {
+ // Convert exclusive integral inequality into inclusive integral inequality,
+ // viz. condition i < U is i <= U - 1 and condition i > U is i >= U + 1.
+ if (is_strict) {
+ const InductionOp op = stride_value > 0 ? kSub : kAdd;
+ hi_val = CreateInvariantOp(op, hi_val, CreateConstant(1, type));
+ }
+ // Compensate for stride.
+ hi_val = CreateInvariantOp(kAdd, hi_val, stride);
+ }
+
+ // Assign the trip-count expression to the loop control. Clients that use the information
+ // should be aware that due to the L <= U assumption, the expression is only valid in the
+ // loop-body proper, and not yet in the loop-header. If the loop has any early exits, the
+ // trip-count forms a conservative upper bound on the number of loop iterations.
+ InductionInfo* trip_count =
+ CreateInvariantOp(kDiv, CreateInvariantOp(kSub, hi_val, lo_val), stride);
+ AssignInfo(loop, loop->GetHeader()->GetLastInstruction(), trip_count);
+}
+
void HInductionVarAnalysis::AssignInfo(HLoopInformation* loop,
HInstruction* instruction,
InductionInfo* info) {
@@ -509,13 +587,82 @@ HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::LookupInfo(HLoopInf
}
}
if (IsLoopInvariant(loop, instruction)) {
- InductionInfo* info = NewInvariantFetch(instruction);
+ InductionInfo* info = CreateInvariantFetch(instruction);
AssignInfo(loop, instruction, info);
return info;
}
return nullptr;
}
+HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::CreateConstant(int64_t value,
+ Primitive::Type type) {
+ if (type == Primitive::kPrimInt) {
+ return CreateInvariantFetch(graph_->GetIntConstant(value));
+ }
+ DCHECK_EQ(type, Primitive::kPrimLong);
+ return CreateInvariantFetch(graph_->GetLongConstant(value));
+}
+
+HInductionVarAnalysis::InductionInfo* HInductionVarAnalysis::CreateSimplifiedInvariant(
+ InductionOp op,
+ InductionInfo* a,
+ InductionInfo* b) {
+ // Perform some light-weight simplifications during construction of a new invariant.
+ // This often safes memory and yields a more concise representation of the induction.
+ // More exhaustive simplifications are done by later phases once induction nodes are
+ // translated back into HIR code (e.g. by loop optimizations or BCE).
+ int64_t value = -1;
+ if (IsIntAndGet(a, &value)) {
+ if (value == 0) {
+ // Simplify 0 + b = b, 0 * b = 0.
+ if (op == kAdd) {
+ return b;
+ } else if (op == kMul) {
+ return a;
+ }
+ } else if (op == kMul) {
+ // Simplify 1 * b = b, -1 * b = -b
+ if (value == 1) {
+ return b;
+ } else if (value == -1) {
+ op = kNeg;
+ a = nullptr;
+ }
+ }
+ }
+ if (IsIntAndGet(b, &value)) {
+ if (value == 0) {
+ // Simplify a + 0 = a, a - 0 = a, a * 0 = 0, -0 = 0.
+ if (op == kAdd || op == kSub) {
+ return a;
+ } else if (op == kMul || op == kNeg) {
+ return b;
+ }
+ } else if (op == kMul || op == kDiv) {
+ // Simplify a * 1 = a, a / 1 = a, a * -1 = -a, a / -1 = -a
+ if (value == 1) {
+ return a;
+ } else if (value == -1) {
+ op = kNeg;
+ b = a;
+ a = nullptr;
+ }
+ }
+ } else if (b->operation == kNeg) {
+ // Simplify a + (-b) = a - b, a - (-b) = a + b, -(-b) = b.
+ if (op == kAdd) {
+ op = kSub;
+ b = b->op_b;
+ } else if (op == kSub) {
+ op = kAdd;
+ b = b->op_b;
+ } else if (op == kNeg) {
+ return b->op_b;
+ }
+ }
+ return new (graph_->GetArena()) InductionInfo(kInvariant, op, a, b, nullptr);
+}
+
bool HInductionVarAnalysis::InductionEqual(InductionInfo* info1,
InductionInfo* info2) {
// Test structural equality only, without accounting for simplifications.
@@ -531,9 +678,24 @@ bool HInductionVarAnalysis::InductionEqual(InductionInfo* info1,
return info1 == info2;
}
+bool HInductionVarAnalysis::IsIntAndGet(InductionInfo* info, int64_t* value) {
+ if (info != nullptr && info->induction_class == kInvariant && info->operation == kFetch) {
+ DCHECK(info->fetch);
+ if (info->fetch->IsIntConstant()) {
+ *value = info->fetch->AsIntConstant()->GetValue();
+ return true;
+ } else if (info->fetch->IsLongConstant()) {
+ *value = info->fetch->AsLongConstant()->GetValue();
+ return true;
+ }
+ }
+ return false;
+}
+
std::string HInductionVarAnalysis::InductionToString(InductionInfo* info) {
if (info != nullptr) {
if (info->induction_class == kInvariant) {
+ int64_t value = -1;
std::string inv = "(";
inv += InductionToString(info->op_a);
switch (info->operation) {
@@ -545,7 +707,11 @@ std::string HInductionVarAnalysis::InductionToString(InductionInfo* info) {
case kDiv: inv += " / "; break;
case kFetch:
DCHECK(info->fetch);
- inv += InstructionToString(info->fetch);
+ if (IsIntAndGet(info, &value)) {
+ inv += std::to_string(value);
+ } else {
+ inv += std::to_string(info->fetch->GetId()) + ":" + info->fetch->DebugName();
+ }
break;
}
inv += InductionToString(info->op_b);
diff --git a/compiler/optimizing/induction_var_analysis.h b/compiler/optimizing/induction_var_analysis.h
index db00f58c7b..8eccf925c1 100644
--- a/compiler/optimizing/induction_var_analysis.h
+++ b/compiler/optimizing/induction_var_analysis.h
@@ -100,17 +100,17 @@ class HInductionVarAnalysis : public HOptimization {
return map_.find(instruction) != map_.end();
}
- InductionInfo* NewInvariantOp(InductionOp op, InductionInfo* a, InductionInfo* b) {
+ InductionInfo* CreateInvariantOp(InductionOp op, InductionInfo* a, InductionInfo* b) {
DCHECK(((op != kNeg && a != nullptr) || (op == kNeg && a == nullptr)) && b != nullptr);
- return new (graph_->GetArena()) InductionInfo(kInvariant, op, a, b, nullptr);
+ return CreateSimplifiedInvariant(op, a, b);
}
- InductionInfo* NewInvariantFetch(HInstruction* f) {
+ InductionInfo* CreateInvariantFetch(HInstruction* f) {
DCHECK(f != nullptr);
return new (graph_->GetArena()) InductionInfo(kInvariant, kFetch, nullptr, nullptr, f);
}
- InductionInfo* NewInduction(InductionClass ic, InductionInfo* a, InductionInfo* b) {
+ InductionInfo* CreateInduction(InductionClass ic, InductionInfo* a, InductionInfo* b) {
DCHECK(a != nullptr && b != nullptr);
return new (graph_->GetArena()) InductionInfo(ic, kNop, a, b, nullptr);
}
@@ -126,7 +126,7 @@ class HInductionVarAnalysis : public HOptimization {
InductionInfo* TransferPhi(InductionInfo* a, InductionInfo* b);
InductionInfo* TransferAddSub(InductionInfo* a, InductionInfo* b, InductionOp op);
InductionInfo* TransferMul(InductionInfo* a, InductionInfo* b);
- InductionInfo* TransferShl(InductionInfo* a, InductionInfo* b, Primitive::Type t);
+ InductionInfo* TransferShl(InductionInfo* a, InductionInfo* b, Primitive::Type type);
InductionInfo* TransferNeg(InductionInfo* a);
// Solvers.
@@ -142,12 +142,30 @@ class HInductionVarAnalysis : public HOptimization {
bool is_first_call);
InductionInfo* RotatePeriodicInduction(InductionInfo* induction, InductionInfo* last);
+ // Trip count information.
+ void VisitControl(HLoopInformation* loop);
+ void VisitCondition(HLoopInformation* loop,
+ InductionInfo* a,
+ InductionInfo* b,
+ Primitive::Type type,
+ IfCondition cmp);
+ void VisitTripCount(HLoopInformation* loop,
+ InductionInfo* lo_val,
+ InductionInfo* hi_val,
+ InductionInfo* stride,
+ int32_t stride_value,
+ Primitive::Type type,
+ bool is_strict);
+
// Assign and lookup.
void AssignInfo(HLoopInformation* loop, HInstruction* instruction, InductionInfo* info);
InductionInfo* LookupInfo(HLoopInformation* loop, HInstruction* instruction);
+ InductionInfo* CreateConstant(int64_t value, Primitive::Type type);
+ InductionInfo* CreateSimplifiedInvariant(InductionOp op, InductionInfo* a, InductionInfo* b);
// Helpers.
static bool InductionEqual(InductionInfo* info1, InductionInfo* info2);
+ static bool IsIntAndGet(InductionInfo* info, int64_t* value);
static std::string InductionToString(InductionInfo* info);
// TODO: fine tune the following data structures, only keep relevant data.
@@ -166,6 +184,8 @@ class HInductionVarAnalysis : public HOptimization {
ArenaSafeMap<HLoopInformation*, ArenaSafeMap<HInstruction*, InductionInfo*>> induction_;
friend class InductionVarAnalysisTest;
+ friend class InductionVarRange;
+ friend class InductionVarRangeTest;
DISALLOW_COPY_AND_ASSIGN(HInductionVarAnalysis);
};
diff --git a/compiler/optimizing/induction_var_analysis_test.cc b/compiler/optimizing/induction_var_analysis_test.cc
index b569fbe53a..fca1ca55e5 100644
--- a/compiler/optimizing/induction_var_analysis_test.cc
+++ b/compiler/optimizing/induction_var_analysis_test.cc
@@ -99,7 +99,7 @@ class InductionVarAnalysisTest : public testing::Test {
loop_preheader_[d]->AddInstruction(new (&allocator_) HStoreLocal(basic_[d], constant0_));
HInstruction* load = new (&allocator_) HLoadLocal(basic_[d], Primitive::kPrimInt);
loop_header_[d]->AddInstruction(load);
- HInstruction* compare = new (&allocator_) HGreaterThanOrEqual(load, constant100_);
+ HInstruction* compare = new (&allocator_) HLessThan(load, constant100_);
loop_header_[d]->AddInstruction(compare);
loop_header_[d]->AddInstruction(new (&allocator_) HIf(compare));
load = new (&allocator_) HLoadLocal(basic_[d], Primitive::kPrimInt);
@@ -230,7 +230,10 @@ TEST_F(InductionVarAnalysisTest, FindBasicInduction) {
PerformInductionVarAnalysis();
EXPECT_STREQ("((1) * i + (0))", GetInductionInfo(store->InputAt(1), 0).c_str());
- EXPECT_STREQ("((1) * i + ((0) + (1)))", GetInductionInfo(increment_[0], 0).c_str());
+ EXPECT_STREQ("((1) * i + (1))", GetInductionInfo(increment_[0], 0).c_str());
+
+ // Trip-count.
+ EXPECT_STREQ("(100)", GetInductionInfo(loop_header_[0]->GetLastInstruction(), 0).c_str());
}
TEST_F(InductionVarAnalysisTest, FindDerivedInduction) {
@@ -260,11 +263,11 @@ TEST_F(InductionVarAnalysisTest, FindDerivedInduction) {
InsertLocalStore(induc_, neg, 0);
PerformInductionVarAnalysis();
- EXPECT_STREQ("((1) * i + ((100) + (0)))", GetInductionInfo(add, 0).c_str());
- EXPECT_STREQ("(( - (1)) * i + ((100) - (0)))", GetInductionInfo(sub, 0).c_str());
- EXPECT_STREQ("(((100) * (1)) * i + ((100) * (0)))", GetInductionInfo(mul, 0).c_str());
- EXPECT_STREQ("(((1) * (2)) * i + ((0) * (2)))", GetInductionInfo(shl, 0).c_str());
- EXPECT_STREQ("(( - (1)) * i + ( - (0)))", GetInductionInfo(neg, 0).c_str());
+ EXPECT_STREQ("((1) * i + (100))", GetInductionInfo(add, 0).c_str());
+ EXPECT_STREQ("(( - (1)) * i + (100))", GetInductionInfo(sub, 0).c_str());
+ EXPECT_STREQ("((100) * i + (0))", GetInductionInfo(mul, 0).c_str());
+ EXPECT_STREQ("((2) * i + (0))", GetInductionInfo(shl, 0).c_str());
+ EXPECT_STREQ("(( - (1)) * i + (0))", GetInductionInfo(neg, 0).c_str());
}
TEST_F(InductionVarAnalysisTest, FindChainInduction) {
@@ -287,9 +290,9 @@ TEST_F(InductionVarAnalysisTest, FindChainInduction) {
HInstruction* store2 = InsertArrayStore(induc_, 0);
PerformInductionVarAnalysis();
- EXPECT_STREQ("(((100) - (1)) * i + ((0) + (100)))",
+ EXPECT_STREQ("(((100) - (1)) * i + (100))",
GetInductionInfo(store1->InputAt(1), 0).c_str());
- EXPECT_STREQ("(((100) - (1)) * i + (((0) + (100)) - (1)))",
+ EXPECT_STREQ("(((100) - (1)) * i + ((100) - (1)))",
GetInductionInfo(store2->InputAt(1), 0).c_str());
}
@@ -321,7 +324,7 @@ TEST_F(InductionVarAnalysisTest, FindTwoWayBasicInduction) {
HInstruction* store = InsertArrayStore(induc_, 0);
PerformInductionVarAnalysis();
- EXPECT_STREQ("((1) * i + ((0) + (1)))", GetInductionInfo(store->InputAt(1), 0).c_str());
+ EXPECT_STREQ("((1) * i + (1))", GetInductionInfo(store->InputAt(1), 0).c_str());
}
TEST_F(InductionVarAnalysisTest, FindTwoWayDerivedInduction) {
@@ -351,7 +354,7 @@ TEST_F(InductionVarAnalysisTest, FindTwoWayDerivedInduction) {
HInstruction* store = InsertArrayStore(induc_, 0);
PerformInductionVarAnalysis();
- EXPECT_STREQ("((1) * i + ((0) + (1)))", GetInductionInfo(store->InputAt(1), 0).c_str());
+ EXPECT_STREQ("((1) * i + (1))", GetInductionInfo(store->InputAt(1), 0).c_str());
}
TEST_F(InductionVarAnalysisTest, FindFirstOrderWrapAroundInduction) {
@@ -368,7 +371,7 @@ TEST_F(InductionVarAnalysisTest, FindFirstOrderWrapAroundInduction) {
InsertLocalStore(induc_, sub, 0);
PerformInductionVarAnalysis();
- EXPECT_STREQ("wrap((0), (( - (1)) * i + ((100) - (0))))",
+ EXPECT_STREQ("wrap((0), (( - (1)) * i + (100)))",
GetInductionInfo(store->InputAt(1), 0).c_str());
}
@@ -389,7 +392,7 @@ TEST_F(InductionVarAnalysisTest, FindSecondOrderWrapAroundInduction) {
InsertLocalStore(tmp_, sub, 0);
PerformInductionVarAnalysis();
- EXPECT_STREQ("wrap((0), wrap((100), (( - (1)) * i + ((100) - (0)))))",
+ EXPECT_STREQ("wrap((0), wrap((100), (( - (1)) * i + (100))))",
GetInductionInfo(store->InputAt(1), 0).c_str());
}
@@ -427,16 +430,11 @@ TEST_F(InductionVarAnalysisTest, FindWrapAroundDerivedInduction) {
HShl(Primitive::kPrimInt, InsertLocalLoad(basic_[0], 0), constant1_), 0), 0);
PerformInductionVarAnalysis();
- EXPECT_STREQ("wrap(((0) + (100)), (((1) * (2)) * i + (((0) * (2)) + (100))))",
- GetInductionInfo(add, 0).c_str());
- EXPECT_STREQ("wrap(((0) - (100)), (((1) * (2)) * i + (((0) * (2)) - (100))))",
- GetInductionInfo(sub, 0).c_str());
- EXPECT_STREQ("wrap(((0) * (100)), ((((1) * (2)) * (100)) * i + (((0) * (2)) * (100))))",
- GetInductionInfo(mul, 0).c_str());
- EXPECT_STREQ("wrap(((0) * (2)), ((((1) * (2)) * (2)) * i + (((0) * (2)) * (2))))",
- GetInductionInfo(shl, 0).c_str());
- EXPECT_STREQ("wrap(( - (0)), (( - ((1) * (2))) * i + ( - ((0) * (2)))))",
- GetInductionInfo(neg, 0).c_str());
+ EXPECT_STREQ("wrap((100), ((2) * i + (100)))", GetInductionInfo(add, 0).c_str());
+ EXPECT_STREQ("wrap(((0) - (100)), ((2) * i + ((0) - (100))))", GetInductionInfo(sub, 0).c_str());
+ EXPECT_STREQ("wrap((0), (((2) * (100)) * i + (0)))", GetInductionInfo(mul, 0).c_str());
+ EXPECT_STREQ("wrap((0), (((2) * (2)) * i + (0)))", GetInductionInfo(shl, 0).c_str());
+ EXPECT_STREQ("wrap((0), (( - (2)) * i + (0)))", GetInductionInfo(neg, 0).c_str());
}
TEST_F(InductionVarAnalysisTest, FindPeriodicInduction) {
@@ -477,8 +475,8 @@ TEST_F(InductionVarAnalysisTest, FindIdiomaticPeriodicInduction) {
InsertLocalStore(induc_, sub, 0);
PerformInductionVarAnalysis();
- EXPECT_STREQ("periodic((0), ((1) - (0)))", GetInductionInfo(store->InputAt(1), 0).c_str());
- EXPECT_STREQ("periodic(((1) - (0)), (0))", GetInductionInfo(sub, 0).c_str());
+ EXPECT_STREQ("periodic((0), (1))", GetInductionInfo(store->InputAt(1), 0).c_str());
+ EXPECT_STREQ("periodic((1), (0))", GetInductionInfo(sub, 0).c_str());
}
TEST_F(InductionVarAnalysisTest, FindDerivedPeriodicInduction) {
@@ -515,11 +513,11 @@ TEST_F(InductionVarAnalysisTest, FindDerivedPeriodicInduction) {
InsertLocalStore(tmp_, neg, 0);
PerformInductionVarAnalysis();
- EXPECT_STREQ("periodic((((1) - (0)) + (100)), ((0) + (100)))", GetInductionInfo(add, 0).c_str());
- EXPECT_STREQ("periodic((((1) - (0)) - (100)), ((0) - (100)))", GetInductionInfo(sub, 0).c_str());
- EXPECT_STREQ("periodic((((1) - (0)) * (100)), ((0) * (100)))", GetInductionInfo(mul, 0).c_str());
- EXPECT_STREQ("periodic((((1) - (0)) * (2)), ((0) * (2)))", GetInductionInfo(shl, 0).c_str());
- EXPECT_STREQ("periodic(( - ((1) - (0))), ( - (0)))", GetInductionInfo(neg, 0).c_str());
+ EXPECT_STREQ("periodic(((1) + (100)), (100))", GetInductionInfo(add, 0).c_str());
+ EXPECT_STREQ("periodic(((1) - (100)), ((0) - (100)))", GetInductionInfo(sub, 0).c_str());
+ EXPECT_STREQ("periodic((100), (0))", GetInductionInfo(mul, 0).c_str());
+ EXPECT_STREQ("periodic((2), (0))", GetInductionInfo(shl, 0).c_str());
+ EXPECT_STREQ("periodic(( - (1)), (0))", GetInductionInfo(neg, 0).c_str());
}
TEST_F(InductionVarAnalysisTest, FindDeepLoopInduction) {
@@ -550,7 +548,9 @@ TEST_F(InductionVarAnalysisTest, FindDeepLoopInduction) {
} else {
EXPECT_STREQ("", GetInductionInfo(store->InputAt(1), d).c_str());
}
- EXPECT_STREQ("((1) * i + ((0) + (1)))", GetInductionInfo(increment_[d], d).c_str());
+ EXPECT_STREQ("((1) * i + (1))", GetInductionInfo(increment_[d], d).c_str());
+ // Trip-count.
+ EXPECT_STREQ("(100)", GetInductionInfo(loop_header_[d]->GetLastInstruction(), d).c_str());
}
}
diff --git a/compiler/optimizing/induction_var_range.cc b/compiler/optimizing/induction_var_range.cc
new file mode 100644
index 0000000000..bd903340ad
--- /dev/null
+++ b/compiler/optimizing/induction_var_range.cc
@@ -0,0 +1,343 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <limits.h>
+
+#include "induction_var_range.h"
+
+namespace art {
+
+static bool IsValidConstant32(int32_t c) {
+ return INT_MIN < c && c < INT_MAX;
+}
+
+static bool IsValidConstant64(int64_t c) {
+ return INT_MIN < c && c < INT_MAX;
+}
+
+/** Returns true if 32-bit addition can be done safely (and is not an unknown range). */
+static bool IsSafeAdd(int32_t c1, int32_t c2) {
+ if (IsValidConstant32(c1) && IsValidConstant32(c2)) {
+ return IsValidConstant64(static_cast<int64_t>(c1) + static_cast<int64_t>(c2));
+ }
+ return false;
+}
+
+/** Returns true if 32-bit subtraction can be done safely (and is not an unknown range). */
+static bool IsSafeSub(int32_t c1, int32_t c2) {
+ if (IsValidConstant32(c1) && IsValidConstant32(c2)) {
+ return IsValidConstant64(static_cast<int64_t>(c1) - static_cast<int64_t>(c2));
+ }
+ return false;
+}
+
+/** Returns true if 32-bit multiplication can be done safely (and is not an unknown range). */
+static bool IsSafeMul(int32_t c1, int32_t c2) {
+ if (IsValidConstant32(c1) && IsValidConstant32(c2)) {
+ return IsValidConstant64(static_cast<int64_t>(c1) * static_cast<int64_t>(c2));
+ }
+ return false;
+}
+
+/** Returns true if 32-bit division can be done safely (and is not an unknown range). */
+static bool IsSafeDiv(int32_t c1, int32_t c2) {
+ if (IsValidConstant32(c1) && IsValidConstant32(c2) && c2 != 0) {
+ return IsValidConstant64(static_cast<int64_t>(c1) / static_cast<int64_t>(c2));
+ }
+ return false;
+}
+
+/** Returns true for 32/64-bit integral constant within known range. */
+static bool IsIntAndGet(HInstruction* instruction, int32_t* value) {
+ if (instruction->IsIntConstant()) {
+ const int32_t c = instruction->AsIntConstant()->GetValue();
+ if (IsValidConstant32(c)) {
+ *value = c;
+ return true;
+ }
+ } else if (instruction->IsLongConstant()) {
+ const int64_t c = instruction->AsLongConstant()->GetValue();
+ if (IsValidConstant64(c)) {
+ *value = c;
+ return true;
+ }
+ }
+ return false;
+}
+
+//
+// Public class methods.
+//
+
+InductionVarRange::InductionVarRange(HInductionVarAnalysis* induction_analysis)
+ : induction_analysis_(induction_analysis) {
+}
+
+InductionVarRange::Value InductionVarRange::GetMinInduction(HInstruction* context,
+ HInstruction* instruction) {
+ HLoopInformation* loop = context->GetBlock()->GetLoopInformation();
+ if (loop != nullptr && induction_analysis_ != nullptr) {
+ return GetMin(induction_analysis_->LookupInfo(loop, instruction), GetTripCount(loop, context));
+ }
+ return Value(INT_MIN);
+}
+
+InductionVarRange::Value InductionVarRange::GetMaxInduction(HInstruction* context,
+ HInstruction* instruction) {
+ HLoopInformation* loop = context->GetBlock()->GetLoopInformation();
+ if (loop != nullptr && induction_analysis_ != nullptr) {
+ return GetMax(induction_analysis_->LookupInfo(loop, instruction), GetTripCount(loop, context));
+ }
+ return Value(INT_MAX);
+}
+
+//
+// Private class methods.
+//
+
+HInductionVarAnalysis::InductionInfo* InductionVarRange::GetTripCount(HLoopInformation* loop,
+ HInstruction* context) {
+ // The trip-count expression is only valid when the top-test is taken at least once,
+ // that means, when the analyzed context appears outside the loop header itself.
+ // Early-exit loops are okay, since in those cases, the trip-count is conservative.
+ if (context->GetBlock() != loop->GetHeader()) {
+ HInductionVarAnalysis::InductionInfo* trip =
+ induction_analysis_->LookupInfo(loop, loop->GetHeader()->GetLastInstruction());
+ if (trip != nullptr) {
+ // Wrap the trip-count representation in its own unusual NOP node, so that range analysis
+ // is able to determine the [0, TC - 1] interval without having to construct constants.
+ return induction_analysis_->CreateInvariantOp(HInductionVarAnalysis::kNop, trip, trip);
+ }
+ }
+ return nullptr;
+}
+
+InductionVarRange::Value InductionVarRange::GetFetch(HInstruction* instruction,
+ int32_t fail_value) {
+ // Detect constants and chase the fetch a bit deeper into the HIR tree, so that it becomes
+ // more likely range analysis will compare the same instructions as terminal nodes.
+ int32_t value;
+ if (IsIntAndGet(instruction, &value)) {
+ return Value(value);
+ } else if (instruction->IsAdd()) {
+ if (IsIntAndGet(instruction->InputAt(0), &value)) {
+ return AddValue(Value(value), GetFetch(instruction->InputAt(1), fail_value), fail_value);
+ } else if (IsIntAndGet(instruction->InputAt(1), &value)) {
+ return AddValue(GetFetch(instruction->InputAt(0), fail_value), Value(value), fail_value);
+ }
+ }
+ return Value(instruction, 1, 0);
+}
+
+InductionVarRange::Value InductionVarRange::GetMin(HInductionVarAnalysis::InductionInfo* info,
+ HInductionVarAnalysis::InductionInfo* trip) {
+ if (info != nullptr) {
+ switch (info->induction_class) {
+ case HInductionVarAnalysis::kInvariant:
+ // Invariants.
+ switch (info->operation) {
+ case HInductionVarAnalysis::kNop: // normalized: 0
+ DCHECK_EQ(info->op_a, info->op_b);
+ return Value(0);
+ case HInductionVarAnalysis::kAdd:
+ return AddValue(GetMin(info->op_a, trip), GetMin(info->op_b, trip), INT_MIN);
+ case HInductionVarAnalysis::kSub: // second max!
+ return SubValue(GetMin(info->op_a, trip), GetMax(info->op_b, trip), INT_MIN);
+ case HInductionVarAnalysis::kNeg: // second max!
+ return SubValue(Value(0), GetMax(info->op_b, trip), INT_MIN);
+ case HInductionVarAnalysis::kMul:
+ return GetMul(info->op_a, info->op_b, trip, INT_MIN);
+ case HInductionVarAnalysis::kDiv:
+ return GetDiv(info->op_a, info->op_b, trip, INT_MIN);
+ case HInductionVarAnalysis::kFetch:
+ return GetFetch(info->fetch, INT_MIN);
+ }
+ break;
+ case HInductionVarAnalysis::kLinear:
+ // Minimum over linear induction a * i + b, for normalized 0 <= i < TC.
+ return AddValue(GetMul(info->op_a, trip, trip, INT_MIN),
+ GetMin(info->op_b, trip), INT_MIN);
+ case HInductionVarAnalysis::kWrapAround:
+ case HInductionVarAnalysis::kPeriodic:
+ // Minimum over all values in the wrap-around/periodic.
+ return MinValue(GetMin(info->op_a, trip), GetMin(info->op_b, trip));
+ }
+ }
+ return Value(INT_MIN);
+}
+
+InductionVarRange::Value InductionVarRange::GetMax(HInductionVarAnalysis::InductionInfo* info,
+ HInductionVarAnalysis::InductionInfo* trip) {
+ if (info != nullptr) {
+ switch (info->induction_class) {
+ case HInductionVarAnalysis::kInvariant:
+ // Invariants.
+ switch (info->operation) {
+ case HInductionVarAnalysis::kNop: // normalized: TC - 1
+ DCHECK_EQ(info->op_a, info->op_b);
+ return SubValue(GetMax(info->op_b, trip), Value(1), INT_MAX);
+ case HInductionVarAnalysis::kAdd:
+ return AddValue(GetMax(info->op_a, trip), GetMax(info->op_b, trip), INT_MAX);
+ case HInductionVarAnalysis::kSub: // second min!
+ return SubValue(GetMax(info->op_a, trip), GetMin(info->op_b, trip), INT_MAX);
+ case HInductionVarAnalysis::kNeg: // second min!
+ return SubValue(Value(0), GetMin(info->op_b, trip), INT_MAX);
+ case HInductionVarAnalysis::kMul:
+ return GetMul(info->op_a, info->op_b, trip, INT_MAX);
+ case HInductionVarAnalysis::kDiv:
+ return GetDiv(info->op_a, info->op_b, trip, INT_MAX);
+ case HInductionVarAnalysis::kFetch:
+ return GetFetch(info->fetch, INT_MAX);
+ }
+ break;
+ case HInductionVarAnalysis::kLinear:
+ // Maximum over linear induction a * i + b, for normalized 0 <= i < TC.
+ return AddValue(GetMul(info->op_a, trip, trip, INT_MAX),
+ GetMax(info->op_b, trip), INT_MAX);
+ case HInductionVarAnalysis::kWrapAround:
+ case HInductionVarAnalysis::kPeriodic:
+ // Maximum over all values in the wrap-around/periodic.
+ return MaxValue(GetMax(info->op_a, trip), GetMax(info->op_b, trip));
+ }
+ }
+ return Value(INT_MAX);
+}
+
+InductionVarRange::Value InductionVarRange::GetMul(HInductionVarAnalysis::InductionInfo* info1,
+ HInductionVarAnalysis::InductionInfo* info2,
+ HInductionVarAnalysis::InductionInfo* trip,
+ int32_t fail_value) {
+ Value v1_min = GetMin(info1, trip);
+ Value v1_max = GetMax(info1, trip);
+ Value v2_min = GetMin(info2, trip);
+ Value v2_max = GetMax(info2, trip);
+ if (v1_min.a_constant == 0 && v1_min.b_constant >= 0) {
+ // Positive range vs. positive or negative range.
+ if (v2_min.a_constant == 0 && v2_min.b_constant >= 0) {
+ return (fail_value < 0) ? MulValue(v1_min, v2_min, fail_value)
+ : MulValue(v1_max, v2_max, fail_value);
+ } else if (v2_max.a_constant == 0 && v2_max.b_constant <= 0) {
+ return (fail_value < 0) ? MulValue(v1_max, v2_min, fail_value)
+ : MulValue(v1_min, v2_max, fail_value);
+ }
+ } else if (v1_min.a_constant == 0 && v1_min.b_constant <= 0) {
+ // Negative range vs. positive or negative range.
+ if (v2_min.a_constant == 0 && v2_min.b_constant >= 0) {
+ return (fail_value < 0) ? MulValue(v1_min, v2_max, fail_value)
+ : MulValue(v1_max, v2_min, fail_value);
+ } else if (v2_max.a_constant == 0 && v2_max.b_constant <= 0) {
+ return (fail_value < 0) ? MulValue(v1_max, v2_max, fail_value)
+ : MulValue(v1_min, v2_min, fail_value);
+ }
+ }
+ return Value(fail_value);
+}
+
+InductionVarRange::Value InductionVarRange::GetDiv(HInductionVarAnalysis::InductionInfo* info1,
+ HInductionVarAnalysis::InductionInfo* info2,
+ HInductionVarAnalysis::InductionInfo* trip,
+ int32_t fail_value) {
+ Value v1_min = GetMin(info1, trip);
+ Value v1_max = GetMax(info1, trip);
+ Value v2_min = GetMin(info2, trip);
+ Value v2_max = GetMax(info2, trip);
+ if (v1_min.a_constant == 0 && v1_min.b_constant >= 0) {
+ // Positive range vs. positive or negative range.
+ if (v2_min.a_constant == 0 && v2_min.b_constant >= 0) {
+ return (fail_value < 0) ? DivValue(v1_min, v2_max, fail_value)
+ : DivValue(v1_max, v2_min, fail_value);
+ } else if (v2_max.a_constant == 0 && v2_max.b_constant <= 0) {
+ return (fail_value < 0) ? DivValue(v1_max, v2_max, fail_value)
+ : DivValue(v1_min, v2_min, fail_value);
+ }
+ } else if (v1_min.a_constant == 0 && v1_min.b_constant <= 0) {
+ // Negative range vs. positive or negative range.
+ if (v2_min.a_constant == 0 && v2_min.b_constant >= 0) {
+ return (fail_value < 0) ? DivValue(v1_min, v2_min, fail_value)
+ : DivValue(v1_max, v2_max, fail_value);
+ } else if (v2_max.a_constant == 0 && v2_max.b_constant <= 0) {
+ return (fail_value < 0) ? DivValue(v1_max, v2_min, fail_value)
+ : DivValue(v1_min, v2_max, fail_value);
+ }
+ }
+ return Value(fail_value);
+}
+
+InductionVarRange::Value InductionVarRange::AddValue(Value v1, Value v2, int32_t fail_value) {
+ if (IsSafeAdd(v1.b_constant, v2.b_constant)) {
+ const int32_t b = v1.b_constant + v2.b_constant;
+ if (v1.a_constant == 0) {
+ return Value(v2.instruction, v2.a_constant, b);
+ } else if (v2.a_constant == 0) {
+ return Value(v1.instruction, v1.a_constant, b);
+ } else if (v1.instruction == v2.instruction && IsSafeAdd(v1.a_constant, v2.a_constant)) {
+ return Value(v1.instruction, v1.a_constant + v2.a_constant, b);
+ }
+ }
+ return Value(fail_value);
+}
+
+InductionVarRange::Value InductionVarRange::SubValue(Value v1, Value v2, int32_t fail_value) {
+ if (IsSafeSub(v1.b_constant, v2.b_constant)) {
+ const int32_t b = v1.b_constant - v2.b_constant;
+ if (v1.a_constant == 0 && IsSafeSub(0, v2.a_constant)) {
+ return Value(v2.instruction, -v2.a_constant, b);
+ } else if (v2.a_constant == 0) {
+ return Value(v1.instruction, v1.a_constant, b);
+ } else if (v1.instruction == v2.instruction && IsSafeSub(v1.a_constant, v2.a_constant)) {
+ return Value(v1.instruction, v1.a_constant - v2.a_constant, b);
+ }
+ }
+ return Value(fail_value);
+}
+
+InductionVarRange::Value InductionVarRange::MulValue(Value v1, Value v2, int32_t fail_value) {
+ if (v1.a_constant == 0) {
+ if (IsSafeMul(v1.b_constant, v2.a_constant) && IsSafeMul(v1.b_constant, v2.b_constant)) {
+ return Value(v2.instruction, v1.b_constant * v2.a_constant, v1.b_constant * v2.b_constant);
+ }
+ } else if (v2.a_constant == 0) {
+ if (IsSafeMul(v1.a_constant, v2.b_constant) && IsSafeMul(v1.b_constant, v2.b_constant)) {
+ return Value(v1.instruction, v1.a_constant * v2.b_constant, v1.b_constant * v2.b_constant);
+ }
+ }
+ return Value(fail_value);
+}
+
+InductionVarRange::Value InductionVarRange::DivValue(Value v1, Value v2, int32_t fail_value) {
+ if (v1.a_constant == 0 && v2.a_constant == 0) {
+ if (IsSafeDiv(v1.b_constant, v2.b_constant)) {
+ return Value(v1.b_constant / v2.b_constant);
+ }
+ }
+ return Value(fail_value);
+}
+
+InductionVarRange::Value InductionVarRange::MinValue(Value v1, Value v2) {
+ if (v1.instruction == v2.instruction && v1.a_constant == v2.a_constant) {
+ return Value(v1.instruction, v1.a_constant, std::min(v1.b_constant, v2.b_constant));
+ }
+ return Value(INT_MIN);
+}
+
+InductionVarRange::Value InductionVarRange::MaxValue(Value v1, Value v2) {
+ if (v1.instruction == v2.instruction && v1.a_constant == v2.a_constant) {
+ return Value(v1.instruction, v1.a_constant, std::max(v1.b_constant, v2.b_constant));
+ }
+ return Value(INT_MAX);
+}
+
+} // namespace art
diff --git a/compiler/optimizing/induction_var_range.h b/compiler/optimizing/induction_var_range.h
new file mode 100644
index 0000000000..b079076852
--- /dev/null
+++ b/compiler/optimizing/induction_var_range.h
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_COMPILER_OPTIMIZING_INDUCTION_VAR_RANGE_H_
+#define ART_COMPILER_OPTIMIZING_INDUCTION_VAR_RANGE_H_
+
+#include "induction_var_analysis.h"
+
+namespace art {
+
+/**
+ * This class implements induction variable based range analysis on expressions within loops.
+ * It takes the results of induction variable analysis in the constructor and provides a public
+ * API to obtain a conservative lower and upper bound value on each instruction in the HIR.
+ *
+ * For example, given a linear induction 2 * i + x where 0 <= i <= 10, range analysis yields lower
+ * bound value x and upper bound value x + 20 for the expression, thus, the range [0, x + 20].
+ */
+class InductionVarRange {
+ public:
+ /*
+ * A value that can be represented as "a * instruction + b" for 32-bit constants, where
+ * Value(INT_MIN) and Value(INT_MAX) denote an unknown lower and upper bound, respectively.
+ * Although range analysis could yield more complex values, the format is sufficiently powerful
+ * to represent useful cases and feeds directly into optimizations like bounds check elimination.
+ */
+ struct Value {
+ Value(HInstruction* i, int32_t a, int32_t b)
+ : instruction(a ? i : nullptr),
+ a_constant(a),
+ b_constant(b) {}
+ explicit Value(int32_t b) : Value(nullptr, 0, b) {}
+ HInstruction* instruction;
+ int32_t a_constant;
+ int32_t b_constant;
+ };
+
+ explicit InductionVarRange(HInductionVarAnalysis* induction);
+
+ /**
+ * Given a context denoted by the first instruction, returns a,
+ * possibly conservative, lower bound on the instruction's value.
+ */
+ Value GetMinInduction(HInstruction* context, HInstruction* instruction);
+
+ /**
+ * Given a context denoted by the first instruction, returns a,
+ * possibly conservative, upper bound on the instruction's value.
+ */
+ Value GetMaxInduction(HInstruction* context, HInstruction* instruction);
+
+ private:
+ //
+ // Private helper methods.
+ //
+
+ HInductionVarAnalysis::InductionInfo* GetTripCount(HLoopInformation* loop,
+ HInstruction* context);
+
+ static Value GetFetch(HInstruction* instruction, int32_t fail_value);
+
+ static Value GetMin(HInductionVarAnalysis::InductionInfo* info,
+ HInductionVarAnalysis::InductionInfo* trip);
+ static Value GetMax(HInductionVarAnalysis::InductionInfo* info,
+ HInductionVarAnalysis::InductionInfo* trip);
+ static Value GetMul(HInductionVarAnalysis::InductionInfo* info1,
+ HInductionVarAnalysis::InductionInfo* info2,
+ HInductionVarAnalysis::InductionInfo* trip, int32_t fail_value);
+ static Value GetDiv(HInductionVarAnalysis::InductionInfo* info1,
+ HInductionVarAnalysis::InductionInfo* info2,
+ HInductionVarAnalysis::InductionInfo* trip, int32_t fail_value);
+
+ static Value AddValue(Value v1, Value v2, int32_t fail_value);
+ static Value SubValue(Value v1, Value v2, int32_t fail_value);
+ static Value MulValue(Value v1, Value v2, int32_t fail_value);
+ static Value DivValue(Value v1, Value v2, int32_t fail_value);
+ static Value MinValue(Value v1, Value v2);
+ static Value MaxValue(Value v1, Value v2);
+
+ /** Results of prior induction variable analysis. */
+ HInductionVarAnalysis *induction_analysis_;
+
+ friend class InductionVarRangeTest;
+
+ DISALLOW_COPY_AND_ASSIGN(InductionVarRange);
+};
+
+} // namespace art
+
+#endif // ART_COMPILER_OPTIMIZING_INDUCTION_VAR_RANGE_H_
diff --git a/compiler/optimizing/induction_var_range_test.cc b/compiler/optimizing/induction_var_range_test.cc
new file mode 100644
index 0000000000..d3c3518193
--- /dev/null
+++ b/compiler/optimizing/induction_var_range_test.cc
@@ -0,0 +1,341 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <limits.h>
+
+#include "base/arena_allocator.h"
+#include "builder.h"
+#include "gtest/gtest.h"
+#include "induction_var_analysis.h"
+#include "induction_var_range.h"
+#include "nodes.h"
+#include "optimizing_unit_test.h"
+
+namespace art {
+
+using Value = InductionVarRange::Value;
+
+/**
+ * Fixture class for the InductionVarRange tests.
+ */
+class InductionVarRangeTest : public testing::Test {
+ public:
+ InductionVarRangeTest() : pool_(), allocator_(&pool_) {
+ graph_ = CreateGraph(&allocator_);
+ iva_ = new (&allocator_) HInductionVarAnalysis(graph_);
+ BuildGraph();
+ }
+
+ ~InductionVarRangeTest() { }
+
+ void ExpectEqual(Value v1, Value v2) {
+ EXPECT_EQ(v1.instruction, v2.instruction);
+ EXPECT_EQ(v1.a_constant, v2.a_constant);
+ EXPECT_EQ(v1.b_constant, v2.b_constant);
+ }
+
+ /** Constructs bare minimum graph. */
+ void BuildGraph() {
+ graph_->SetNumberOfVRegs(1);
+ HBasicBlock* entry_block = new (&allocator_) HBasicBlock(graph_);
+ HBasicBlock* exit_block = new (&allocator_) HBasicBlock(graph_);
+ graph_->AddBlock(entry_block);
+ graph_->AddBlock(exit_block);
+ graph_->SetEntryBlock(entry_block);
+ graph_->SetExitBlock(exit_block);
+ }
+
+ /** Constructs an invariant. */
+ HInductionVarAnalysis::InductionInfo* CreateInvariant(char opc,
+ HInductionVarAnalysis::InductionInfo* a,
+ HInductionVarAnalysis::InductionInfo* b) {
+ HInductionVarAnalysis::InductionOp op;
+ switch (opc) {
+ case '+': op = HInductionVarAnalysis::kAdd; break;
+ case '-': op = HInductionVarAnalysis::kSub; break;
+ case 'n': op = HInductionVarAnalysis::kNeg; break;
+ case '*': op = HInductionVarAnalysis::kMul; break;
+ case '/': op = HInductionVarAnalysis::kDiv; break;
+ default: op = HInductionVarAnalysis::kNop; break;
+ }
+ return iva_->CreateInvariantOp(op, a, b);
+ }
+
+ /** Constructs a fetch. */
+ HInductionVarAnalysis::InductionInfo* CreateFetch(HInstruction* fetch) {
+ return iva_->CreateInvariantFetch(fetch);
+ }
+
+ /** Constructs a constant. */
+ HInductionVarAnalysis::InductionInfo* CreateConst(int32_t c) {
+ return CreateFetch(graph_->GetIntConstant(c));
+ }
+
+ /** Constructs a trip-count. */
+ HInductionVarAnalysis::InductionInfo* CreateTripCount(int32_t tc) {
+ HInductionVarAnalysis::InductionInfo* trip = CreateConst(tc);
+ return CreateInvariant('@', trip, trip);
+ }
+
+ /** Constructs a linear a * i + b induction. */
+ HInductionVarAnalysis::InductionInfo* CreateLinear(int32_t a, int32_t b) {
+ return iva_->CreateInduction(HInductionVarAnalysis::kLinear, CreateConst(a), CreateConst(b));
+ }
+
+ /** Constructs a range [lo, hi] using a periodic induction. */
+ HInductionVarAnalysis::InductionInfo* CreateRange(int32_t lo, int32_t hi) {
+ return iva_->CreateInduction(
+ HInductionVarAnalysis::kPeriodic, CreateConst(lo), CreateConst(hi));
+ }
+
+ /** Constructs a wrap-around induction consisting of a constant, followed by a range. */
+ HInductionVarAnalysis::InductionInfo* CreateWrapAround(int32_t initial, int32_t lo, int32_t hi) {
+ return iva_->CreateInduction(
+ HInductionVarAnalysis::kWrapAround, CreateConst(initial), CreateRange(lo, hi));
+ }
+
+ //
+ // Relay methods.
+ //
+
+ Value GetMin(HInductionVarAnalysis::InductionInfo* info,
+ HInductionVarAnalysis::InductionInfo* induc) {
+ return InductionVarRange::GetMin(info, induc);
+ }
+
+ Value GetMax(HInductionVarAnalysis::InductionInfo* info,
+ HInductionVarAnalysis::InductionInfo* induc) {
+ return InductionVarRange::GetMax(info, induc);
+ }
+
+ Value GetMul(HInductionVarAnalysis::InductionInfo* info1,
+ HInductionVarAnalysis::InductionInfo* info2, int32_t fail_value) {
+ return InductionVarRange::GetMul(info1, info2, nullptr, fail_value);
+ }
+
+ Value GetDiv(HInductionVarAnalysis::InductionInfo* info1,
+ HInductionVarAnalysis::InductionInfo* info2, int32_t fail_value) {
+ return InductionVarRange::GetDiv(info1, info2, nullptr, fail_value);
+ }
+
+ Value AddValue(Value v1, Value v2) { return InductionVarRange::AddValue(v1, v2, INT_MIN); }
+ Value SubValue(Value v1, Value v2) { return InductionVarRange::SubValue(v1, v2, INT_MIN); }
+ Value MulValue(Value v1, Value v2) { return InductionVarRange::MulValue(v1, v2, INT_MIN); }
+ Value DivValue(Value v1, Value v2) { return InductionVarRange::DivValue(v1, v2, INT_MIN); }
+ Value MinValue(Value v1, Value v2) { return InductionVarRange::MinValue(v1, v2); }
+ Value MaxValue(Value v1, Value v2) { return InductionVarRange::MaxValue(v1, v2); }
+
+ // General building fields.
+ ArenaPool pool_;
+ ArenaAllocator allocator_;
+ HGraph* graph_;
+ HInductionVarAnalysis* iva_;
+
+ // Two dummy instructions.
+ HReturnVoid x_;
+ HReturnVoid y_;
+};
+
+//
+// The actual InductionVarRange tests.
+//
+
+TEST_F(InductionVarRangeTest, GetMinMaxNull) {
+ ExpectEqual(Value(INT_MIN), GetMin(nullptr, nullptr));
+ ExpectEqual(Value(INT_MAX), GetMax(nullptr, nullptr));
+}
+
+TEST_F(InductionVarRangeTest, GetMinMaxAdd) {
+ ExpectEqual(Value(12),
+ GetMin(CreateInvariant('+', CreateConst(2), CreateRange(10, 20)), nullptr));
+ ExpectEqual(Value(22),
+ GetMax(CreateInvariant('+', CreateConst(2), CreateRange(10, 20)), nullptr));
+ ExpectEqual(Value(&x_, 1, -20),
+ GetMin(CreateInvariant('+', CreateFetch(&x_), CreateRange(-20, -10)), nullptr));
+ ExpectEqual(Value(&x_, 1, -10),
+ GetMax(CreateInvariant('+', CreateFetch(&x_), CreateRange(-20, -10)), nullptr));
+ ExpectEqual(Value(&x_, 1, 10),
+ GetMin(CreateInvariant('+', CreateRange(10, 20), CreateFetch(&x_)), nullptr));
+ ExpectEqual(Value(&x_, 1, 20),
+ GetMax(CreateInvariant('+', CreateRange(10, 20), CreateFetch(&x_)), nullptr));
+ ExpectEqual(Value(5),
+ GetMin(CreateInvariant('+', CreateRange(-5, -1), CreateRange(10, 20)), nullptr));
+ ExpectEqual(Value(19),
+ GetMax(CreateInvariant('+', CreateRange(-5, -1), CreateRange(10, 20)), nullptr));
+}
+
+TEST_F(InductionVarRangeTest, GetMinMaxSub) {
+ ExpectEqual(Value(-18),
+ GetMin(CreateInvariant('-', CreateConst(2), CreateRange(10, 20)), nullptr));
+ ExpectEqual(Value(-8),
+ GetMax(CreateInvariant('-', CreateConst(2), CreateRange(10, 20)), nullptr));
+ ExpectEqual(Value(&x_, 1, 10),
+ GetMin(CreateInvariant('-', CreateFetch(&x_), CreateRange(-20, -10)), nullptr));
+ ExpectEqual(Value(&x_, 1, 20),
+ GetMax(CreateInvariant('-', CreateFetch(&x_), CreateRange(-20, -10)), nullptr));
+ ExpectEqual(Value(&x_, -1, 10),
+ GetMin(CreateInvariant('-', CreateRange(10, 20), CreateFetch(&x_)), nullptr));
+ ExpectEqual(Value(&x_, -1, 20),
+ GetMax(CreateInvariant('-', CreateRange(10, 20), CreateFetch(&x_)), nullptr));
+ ExpectEqual(Value(-25),
+ GetMin(CreateInvariant('-', CreateRange(-5, -1), CreateRange(10, 20)), nullptr));
+ ExpectEqual(Value(-11),
+ GetMax(CreateInvariant('-', CreateRange(-5, -1), CreateRange(10, 20)), nullptr));
+}
+
+TEST_F(InductionVarRangeTest, GetMinMaxNeg) {
+ ExpectEqual(Value(-20), GetMin(CreateInvariant('n', nullptr, CreateRange(10, 20)), nullptr));
+ ExpectEqual(Value(-10), GetMax(CreateInvariant('n', nullptr, CreateRange(10, 20)), nullptr));
+ ExpectEqual(Value(10), GetMin(CreateInvariant('n', nullptr, CreateRange(-20, -10)), nullptr));
+ ExpectEqual(Value(20), GetMax(CreateInvariant('n', nullptr, CreateRange(-20, -10)), nullptr));
+ ExpectEqual(Value(&x_, -1, 0), GetMin(CreateInvariant('n', nullptr, CreateFetch(&x_)), nullptr));
+ ExpectEqual(Value(&x_, -1, 0), GetMax(CreateInvariant('n', nullptr, CreateFetch(&x_)), nullptr));
+}
+
+TEST_F(InductionVarRangeTest, GetMinMaxMul) {
+ ExpectEqual(Value(20),
+ GetMin(CreateInvariant('*', CreateConst(2), CreateRange(10, 20)), nullptr));
+ ExpectEqual(Value(40),
+ GetMax(CreateInvariant('*', CreateConst(2), CreateRange(10, 20)), nullptr));
+}
+
+TEST_F(InductionVarRangeTest, GetMinMaxDiv) {
+ ExpectEqual(Value(3),
+ GetMin(CreateInvariant('/', CreateRange(12, 20), CreateConst(4)), nullptr));
+ ExpectEqual(Value(5),
+ GetMax(CreateInvariant('/', CreateRange(12, 20), CreateConst(4)), nullptr));
+}
+
+TEST_F(InductionVarRangeTest, GetMinMaxConstant) {
+ ExpectEqual(Value(12345), GetMin(CreateConst(12345), nullptr));
+ ExpectEqual(Value(12345), GetMax(CreateConst(12345), nullptr));
+}
+
+TEST_F(InductionVarRangeTest, GetMinMaxFetch) {
+ ExpectEqual(Value(&x_, 1, 0), GetMin(CreateFetch(&x_), nullptr));
+ ExpectEqual(Value(&x_, 1, 0), GetMax(CreateFetch(&x_), nullptr));
+}
+
+TEST_F(InductionVarRangeTest, GetMinMaxLinear) {
+ ExpectEqual(Value(20), GetMin(CreateLinear(10, 20), CreateTripCount(100)));
+ ExpectEqual(Value(1010), GetMax(CreateLinear(10, 20), CreateTripCount(100)));
+ ExpectEqual(Value(-970), GetMin(CreateLinear(-10, 20), CreateTripCount(100)));
+ ExpectEqual(Value(20), GetMax(CreateLinear(-10, 20), CreateTripCount(100)));
+}
+
+TEST_F(InductionVarRangeTest, GetMinMaxWrapAround) {
+ ExpectEqual(Value(-5), GetMin(CreateWrapAround(-5, -1, 10), nullptr));
+ ExpectEqual(Value(10), GetMax(CreateWrapAround(-5, -1, 10), nullptr));
+ ExpectEqual(Value(-1), GetMin(CreateWrapAround(2, -1, 10), nullptr));
+ ExpectEqual(Value(10), GetMax(CreateWrapAround(2, -1, 10), nullptr));
+ ExpectEqual(Value(-1), GetMin(CreateWrapAround(20, -1, 10), nullptr));
+ ExpectEqual(Value(20), GetMax(CreateWrapAround(20, -1, 10), nullptr));
+}
+
+TEST_F(InductionVarRangeTest, GetMinMaxPeriodic) {
+ ExpectEqual(Value(-2), GetMin(CreateRange(-2, 99), nullptr));
+ ExpectEqual(Value(99), GetMax(CreateRange(-2, 99), nullptr));
+}
+
+TEST_F(InductionVarRangeTest, GetMulMin) {
+ ExpectEqual(Value(6), GetMul(CreateRange(2, 10), CreateRange(3, 5), INT_MIN));
+ ExpectEqual(Value(-50), GetMul(CreateRange(2, 10), CreateRange(-5, -3), INT_MIN));
+ ExpectEqual(Value(-50), GetMul(CreateRange(-10, -2), CreateRange(3, 5), INT_MIN));
+ ExpectEqual(Value(6), GetMul(CreateRange(-10, -2), CreateRange(-5, -3), INT_MIN));
+}
+
+TEST_F(InductionVarRangeTest, GetMulMax) {
+ ExpectEqual(Value(50), GetMul(CreateRange(2, 10), CreateRange(3, 5), INT_MAX));
+ ExpectEqual(Value(-6), GetMul(CreateRange(2, 10), CreateRange(-5, -3), INT_MAX));
+ ExpectEqual(Value(-6), GetMul(CreateRange(-10, -2), CreateRange(3, 5), INT_MAX));
+ ExpectEqual(Value(50), GetMul(CreateRange(-10, -2), CreateRange(-5, -3), INT_MAX));
+}
+
+TEST_F(InductionVarRangeTest, GetDivMin) {
+ ExpectEqual(Value(10), GetDiv(CreateRange(40, 1000), CreateRange(2, 4), INT_MIN));
+ ExpectEqual(Value(-500), GetDiv(CreateRange(40, 1000), CreateRange(-4, -2), INT_MIN));
+ ExpectEqual(Value(-500), GetDiv(CreateRange(-1000, -40), CreateRange(2, 4), INT_MIN));
+ ExpectEqual(Value(10), GetDiv(CreateRange(-1000, -40), CreateRange(-4, -2), INT_MIN));
+}
+
+TEST_F(InductionVarRangeTest, GetDivMax) {
+ ExpectEqual(Value(500), GetDiv(CreateRange(40, 1000), CreateRange(2, 4), INT_MAX));
+ ExpectEqual(Value(-10), GetDiv(CreateRange(40, 1000), CreateRange(-4, -2), INT_MAX));
+ ExpectEqual(Value(-10), GetDiv(CreateRange(-1000, -40), CreateRange(2, 4), INT_MAX));
+ ExpectEqual(Value(500), GetDiv(CreateRange(-1000, -40), CreateRange(-4, -2), INT_MAX));
+}
+
+TEST_F(InductionVarRangeTest, AddValue) {
+ ExpectEqual(Value(110), AddValue(Value(10), Value(100)));
+ ExpectEqual(Value(-5), AddValue(Value(&x_, 1, -4), Value(&x_, -1, -1)));
+ ExpectEqual(Value(&x_, 3, -5), AddValue(Value(&x_, 2, -4), Value(&x_, 1, -1)));
+ ExpectEqual(Value(INT_MIN), AddValue(Value(&x_, 1, 5), Value(&y_, 1, -7)));
+ ExpectEqual(Value(&x_, 1, 23), AddValue(Value(&x_, 1, 20), Value(3)));
+ ExpectEqual(Value(&y_, 1, 5), AddValue(Value(55), Value(&y_, 1, -50)));
+ // Unsafe.
+ ExpectEqual(Value(INT_MIN), AddValue(Value(INT_MAX - 5), Value(6)));
+}
+
+TEST_F(InductionVarRangeTest, SubValue) {
+ ExpectEqual(Value(-90), SubValue(Value(10), Value(100)));
+ ExpectEqual(Value(-3), SubValue(Value(&x_, 1, -4), Value(&x_, 1, -1)));
+ ExpectEqual(Value(&x_, 2, -3), SubValue(Value(&x_, 3, -4), Value(&x_, 1, -1)));
+ ExpectEqual(Value(INT_MIN), SubValue(Value(&x_, 1, 5), Value(&y_, 1, -7)));
+ ExpectEqual(Value(&x_, 1, 17), SubValue(Value(&x_, 1, 20), Value(3)));
+ ExpectEqual(Value(&y_, -4, 105), SubValue(Value(55), Value(&y_, 4, -50)));
+ // Unsafe.
+ ExpectEqual(Value(INT_MIN), SubValue(Value(INT_MIN + 5), Value(6)));
+}
+
+TEST_F(InductionVarRangeTest, MulValue) {
+ ExpectEqual(Value(1000), MulValue(Value(10), Value(100)));
+ ExpectEqual(Value(INT_MIN), MulValue(Value(&x_, 1, -4), Value(&x_, 1, -1)));
+ ExpectEqual(Value(INT_MIN), MulValue(Value(&x_, 1, 5), Value(&y_, 1, -7)));
+ ExpectEqual(Value(&x_, 9, 60), MulValue(Value(&x_, 3, 20), Value(3)));
+ ExpectEqual(Value(&y_, 55, -110), MulValue(Value(55), Value(&y_, 1, -2)));
+ // Unsafe.
+ ExpectEqual(Value(INT_MIN), MulValue(Value(90000), Value(-90000)));
+}
+
+TEST_F(InductionVarRangeTest, DivValue) {
+ ExpectEqual(Value(25), DivValue(Value(100), Value(4)));
+ ExpectEqual(Value(INT_MIN), DivValue(Value(&x_, 1, -4), Value(&x_, 1, -1)));
+ ExpectEqual(Value(INT_MIN), DivValue(Value(&x_, 1, 5), Value(&y_, 1, -7)));
+ ExpectEqual(Value(INT_MIN), DivValue(Value(&x_, 12, 24), Value(3)));
+ ExpectEqual(Value(INT_MIN), DivValue(Value(55), Value(&y_, 1, -50)));
+ // Unsafe.
+ ExpectEqual(Value(INT_MIN), DivValue(Value(1), Value(0)));
+}
+
+TEST_F(InductionVarRangeTest, MinValue) {
+ ExpectEqual(Value(10), MinValue(Value(10), Value(100)));
+ ExpectEqual(Value(&x_, 1, -4), MinValue(Value(&x_, 1, -4), Value(&x_, 1, -1)));
+ ExpectEqual(Value(&x_, 4, -4), MinValue(Value(&x_, 4, -4), Value(&x_, 4, -1)));
+ ExpectEqual(Value(INT_MIN), MinValue(Value(&x_, 1, 5), Value(&y_, 1, -7)));
+ ExpectEqual(Value(INT_MIN), MinValue(Value(&x_, 1, 20), Value(3)));
+ ExpectEqual(Value(INT_MIN), MinValue(Value(55), Value(&y_, 1, -50)));
+}
+
+TEST_F(InductionVarRangeTest, MaxValue) {
+ ExpectEqual(Value(100), MaxValue(Value(10), Value(100)));
+ ExpectEqual(Value(&x_, 1, -1), MaxValue(Value(&x_, 1, -4), Value(&x_, 1, -1)));
+ ExpectEqual(Value(&x_, 4, -1), MaxValue(Value(&x_, 4, -4), Value(&x_, 4, -1)));
+ ExpectEqual(Value(INT_MAX), MaxValue(Value(&x_, 1, 5), Value(&y_, 1, -7)));
+ ExpectEqual(Value(INT_MAX), MaxValue(Value(&x_, 1, 20), Value(3)));
+ ExpectEqual(Value(INT_MAX), MaxValue(Value(55), Value(&y_, 1, -50)));
+}
+
+} // namespace art
diff --git a/compiler/optimizing/intrinsics.cc b/compiler/optimizing/intrinsics.cc
index 2dd4bbabdb..b71fdb8f1d 100644
--- a/compiler/optimizing/intrinsics.cc
+++ b/compiler/optimizing/intrinsics.cc
@@ -16,12 +16,17 @@
#include "intrinsics.h"
+#include "art_method.h"
+#include "class_linker.h"
#include "dex/quick/dex_file_method_inliner.h"
#include "dex/quick/dex_file_to_method_inliner_map.h"
#include "driver/compiler_driver.h"
#include "invoke_type.h"
+#include "mirror/dex_cache-inl.h"
#include "nodes.h"
#include "quick/inline_method_analyser.h"
+#include "scoped_thread_state_change.h"
+#include "thread-inl.h"
#include "utils.h"
namespace art {
@@ -360,14 +365,23 @@ static Intrinsics GetIntrinsic(InlineMethod method, InstructionSet instruction_s
return Intrinsics::kNone;
}
-static bool CheckInvokeType(Intrinsics intrinsic, HInvoke* invoke) {
+static bool CheckInvokeType(Intrinsics intrinsic, HInvoke* invoke, const DexFile& dex_file) {
// The DexFileMethodInliner should have checked whether the methods are agreeing with
// what we expect, i.e., static methods are called as such. Add another check here for
// our expectations:
- // Whenever the intrinsic is marked as static-or-direct, report an error if we find an
- // InvokeVirtual. The other direction is not possible: we have intrinsics for virtual
- // functions that will perform a check inline. If the precise type is known, however,
- // the instruction will be sharpened to an InvokeStaticOrDirect.
+ //
+ // Whenever the intrinsic is marked as static, report an error if we find an InvokeVirtual.
+ //
+ // Whenever the intrinsic is marked as direct and we find an InvokeVirtual, a devirtualization
+ // failure occured. We might be in a situation where we have inlined a method that calls an
+ // intrinsic, but that method is in a different dex file on which we do not have a
+ // verified_method that would have helped the compiler driver sharpen the call. In that case,
+ // make sure that the intrinsic is actually for some final method (or in a final class), as
+ // otherwise the intrinsics setup is broken.
+ //
+ // For the last direction, we have intrinsics for virtual functions that will perform a check
+ // inline. If the precise type is known, however, the instruction will be sharpened to an
+ // InvokeStaticOrDirect.
InvokeType intrinsic_type = GetIntrinsicInvokeType(intrinsic);
InvokeType invoke_type = invoke->IsInvokeStaticOrDirect() ?
invoke->AsInvokeStaticOrDirect()->GetInvokeType() :
@@ -375,8 +389,22 @@ static bool CheckInvokeType(Intrinsics intrinsic, HInvoke* invoke) {
switch (intrinsic_type) {
case kStatic:
return (invoke_type == kStatic);
+
case kDirect:
- return (invoke_type == kDirect);
+ if (invoke_type == kDirect) {
+ return true;
+ }
+ if (invoke_type == kVirtual) {
+ ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+ ScopedObjectAccess soa(Thread::Current());
+ ArtMethod* art_method =
+ class_linker->FindDexCache(soa.Self(), dex_file)->GetResolvedMethod(
+ invoke->GetDexMethodIndex(), class_linker->GetImagePointerSize());
+ return art_method != nullptr &&
+ (art_method->IsFinal() || art_method->GetDeclaringClass()->IsFinal());
+ }
+ return false;
+
case kVirtual:
// Call might be devirtualized.
return (invoke_type == kVirtual || invoke_type == kDirect);
@@ -396,17 +424,18 @@ void IntrinsicsRecognizer::Run() {
if (inst->IsInvoke()) {
HInvoke* invoke = inst->AsInvoke();
InlineMethod method;
- DexFileMethodInliner* inliner =
- driver_->GetMethodInlinerMap()->GetMethodInliner(&invoke->GetDexFile());
+ const DexFile& dex_file = invoke->GetDexFile();
+ DexFileMethodInliner* inliner = driver_->GetMethodInlinerMap()->GetMethodInliner(&dex_file);
DCHECK(inliner != nullptr);
if (inliner->IsIntrinsic(invoke->GetDexMethodIndex(), &method)) {
Intrinsics intrinsic = GetIntrinsic(method, graph_->GetInstructionSet());
if (intrinsic != Intrinsics::kNone) {
- if (!CheckInvokeType(intrinsic, invoke)) {
+ if (!CheckInvokeType(intrinsic, invoke, dex_file)) {
LOG(WARNING) << "Found an intrinsic with unexpected invoke type: "
- << intrinsic << " for "
- << PrettyMethod(invoke->GetDexMethodIndex(), invoke->GetDexFile());
+ << intrinsic << " for "
+ << PrettyMethod(invoke->GetDexMethodIndex(), invoke->GetDexFile())
+ << invoke->DebugName();
} else {
invoke->SetIntrinsic(intrinsic, NeedsEnvironmentOrCache(intrinsic));
}
diff --git a/compiler/optimizing/intrinsics_arm.cc b/compiler/optimizing/intrinsics_arm.cc
index b7dc1df1db..cc8ddb6299 100644
--- a/compiler/optimizing/intrinsics_arm.cc
+++ b/compiler/optimizing/intrinsics_arm.cc
@@ -103,11 +103,11 @@ class IntrinsicSlowPathARM : public SlowPathCodeARM {
if (invoke_->IsInvokeStaticOrDirect()) {
codegen->GenerateStaticOrDirectCall(invoke_->AsInvokeStaticOrDirect(),
Location::RegisterLocation(kArtMethodRegister));
- codegen->RecordPcInfo(invoke_, invoke_->GetDexPc(), this);
} else {
- UNIMPLEMENTED(FATAL) << "Non-direct intrinsic slow-path not yet implemented";
- UNREACHABLE();
+ codegen->GenerateVirtualCall(invoke_->AsInvokeVirtual(),
+ Location::RegisterLocation(kArtMethodRegister));
}
+ codegen->RecordPcInfo(invoke_, invoke_->GetDexPc(), this);
// Copy the result back to the expected output.
Location out = invoke_->GetLocations()->Out();
diff --git a/compiler/optimizing/intrinsics_arm64.cc b/compiler/optimizing/intrinsics_arm64.cc
index 5efa01e1da..b0cfd0d1bc 100644
--- a/compiler/optimizing/intrinsics_arm64.cc
+++ b/compiler/optimizing/intrinsics_arm64.cc
@@ -112,11 +112,10 @@ class IntrinsicSlowPathARM64 : public SlowPathCodeARM64 {
if (invoke_->IsInvokeStaticOrDirect()) {
codegen->GenerateStaticOrDirectCall(invoke_->AsInvokeStaticOrDirect(),
LocationFrom(kArtMethodRegister));
- codegen->RecordPcInfo(invoke_, invoke_->GetDexPc(), this);
} else {
- UNIMPLEMENTED(FATAL) << "Non-direct intrinsic slow-path not yet implemented";
- UNREACHABLE();
+ codegen->GenerateVirtualCall(invoke_->AsInvokeVirtual(), LocationFrom(kArtMethodRegister));
}
+ codegen->RecordPcInfo(invoke_, invoke_->GetDexPc(), this);
// Copy the result back to the expected output.
Location out = invoke_->GetLocations()->Out();
diff --git a/compiler/optimizing/intrinsics_x86.cc b/compiler/optimizing/intrinsics_x86.cc
index bff29af542..c5d88d2b25 100644
--- a/compiler/optimizing/intrinsics_x86.cc
+++ b/compiler/optimizing/intrinsics_x86.cc
@@ -141,11 +141,10 @@ class IntrinsicSlowPathX86 : public SlowPathCodeX86 {
if (invoke_->IsInvokeStaticOrDirect()) {
codegen->GenerateStaticOrDirectCall(invoke_->AsInvokeStaticOrDirect(),
Location::RegisterLocation(EAX));
- codegen->RecordPcInfo(invoke_, invoke_->GetDexPc(), this);
} else {
- UNIMPLEMENTED(FATAL) << "Non-direct intrinsic slow-path not yet implemented";
- UNREACHABLE();
+ codegen->GenerateVirtualCall(invoke_->AsInvokeVirtual(), Location::RegisterLocation(EAX));
}
+ codegen->RecordPcInfo(invoke_, invoke_->GetDexPc(), this);
// Copy the result back to the expected output.
Location out = invoke_->GetLocations()->Out();
diff --git a/compiler/optimizing/intrinsics_x86_64.cc b/compiler/optimizing/intrinsics_x86_64.cc
index f91ad7fe94..258ae9a55f 100644
--- a/compiler/optimizing/intrinsics_x86_64.cc
+++ b/compiler/optimizing/intrinsics_x86_64.cc
@@ -132,11 +132,10 @@ class IntrinsicSlowPathX86_64 : public SlowPathCodeX86_64 {
if (invoke_->IsInvokeStaticOrDirect()) {
codegen->GenerateStaticOrDirectCall(
invoke_->AsInvokeStaticOrDirect(), Location::RegisterLocation(RDI));
- codegen->RecordPcInfo(invoke_, invoke_->GetDexPc(), this);
} else {
- UNIMPLEMENTED(FATAL) << "Non-direct intrinsic slow-path not yet implemented";
- UNREACHABLE();
+ codegen->GenerateVirtualCall(invoke_->AsInvokeVirtual(), Location::RegisterLocation(RDI));
}
+ codegen->RecordPcInfo(invoke_, invoke_->GetDexPc(), this);
// Copy the result back to the expected output.
Location out = invoke_->GetLocations()->Out();
diff --git a/compiler/optimizing/nodes.cc b/compiler/optimizing/nodes.cc
index 4332d7ed02..650c8e5fed 100644
--- a/compiler/optimizing/nodes.cc
+++ b/compiler/optimizing/nodes.cc
@@ -207,7 +207,7 @@ void HGraph::SplitCriticalEdge(HBasicBlock* block, HBasicBlock* successor) {
// Insert a new node between `block` and `successor` to split the
// critical edge.
HBasicBlock* new_block = SplitEdge(block, successor);
- new_block->AddInstruction(new (arena_) HGoto());
+ new_block->AddInstruction(new (arena_) HGoto(successor->GetDexPc()));
if (successor->IsLoopHeader()) {
// If we split at a back edge boundary, make the new block the back edge.
HLoopInformation* info = successor->GetLoopInformation();
@@ -228,7 +228,7 @@ void HGraph::SimplifyLoop(HBasicBlock* header) {
if (number_of_incomings != 1) {
HBasicBlock* pre_header = new (arena_) HBasicBlock(this, header->GetDexPc());
AddBlock(pre_header);
- pre_header->AddInstruction(new (arena_) HGoto());
+ pre_header->AddInstruction(new (arena_) HGoto(header->GetDexPc()));
for (size_t pred = 0; pred < header->GetPredecessors().Size(); ++pred) {
HBasicBlock* predecessor = header->GetPredecessors().Get(pred);
@@ -409,12 +409,12 @@ void HGraph::InsertConstant(HConstant* constant) {
}
}
-HNullConstant* HGraph::GetNullConstant() {
+HNullConstant* HGraph::GetNullConstant(uint32_t dex_pc) {
// For simplicity, don't bother reviving the cached null constant if it is
// not null and not in a block. Otherwise, we need to clear the instruction
// id and/or any invariants the graph is assuming when adding new instructions.
if ((cached_null_constant_ == nullptr) || (cached_null_constant_->GetBlock() == nullptr)) {
- cached_null_constant_ = new (arena_) HNullConstant();
+ cached_null_constant_ = new (arena_) HNullConstant(dex_pc);
InsertConstant(cached_null_constant_);
}
return cached_null_constant_;
@@ -426,7 +426,8 @@ HCurrentMethod* HGraph::GetCurrentMethod() {
// id and/or any invariants the graph is assuming when adding new instructions.
if ((cached_current_method_ == nullptr) || (cached_current_method_->GetBlock() == nullptr)) {
cached_current_method_ = new (arena_) HCurrentMethod(
- Is64BitInstructionSet(instruction_set_) ? Primitive::kPrimLong : Primitive::kPrimInt);
+ Is64BitInstructionSet(instruction_set_) ? Primitive::kPrimLong : Primitive::kPrimInt,
+ entry_block_->GetDexPc());
if (entry_block_->GetFirstInstruction() == nullptr) {
entry_block_->AddInstruction(cached_current_method_);
} else {
@@ -437,7 +438,7 @@ HCurrentMethod* HGraph::GetCurrentMethod() {
return cached_current_method_;
}
-HConstant* HGraph::GetConstant(Primitive::Type type, int64_t value) {
+HConstant* HGraph::GetConstant(Primitive::Type type, int64_t value, uint32_t dex_pc) {
switch (type) {
case Primitive::Type::kPrimBoolean:
DCHECK(IsUint<1>(value));
@@ -447,10 +448,10 @@ HConstant* HGraph::GetConstant(Primitive::Type type, int64_t value) {
case Primitive::Type::kPrimShort:
case Primitive::Type::kPrimInt:
DCHECK(IsInt(Primitive::ComponentSize(type) * kBitsPerByte, value));
- return GetIntConstant(static_cast<int32_t>(value));
+ return GetIntConstant(static_cast<int32_t>(value), dex_pc);
case Primitive::Type::kPrimLong:
- return GetLongConstant(value);
+ return GetLongConstant(value, dex_pc);
default:
LOG(FATAL) << "Unsupported constant type";
@@ -944,11 +945,11 @@ HConstant* HTypeConversion::TryStaticEvaluation() const {
int32_t value = GetInput()->AsIntConstant()->GetValue();
switch (GetResultType()) {
case Primitive::kPrimLong:
- return graph->GetLongConstant(static_cast<int64_t>(value));
+ return graph->GetLongConstant(static_cast<int64_t>(value), GetDexPc());
case Primitive::kPrimFloat:
- return graph->GetFloatConstant(static_cast<float>(value));
+ return graph->GetFloatConstant(static_cast<float>(value), GetDexPc());
case Primitive::kPrimDouble:
- return graph->GetDoubleConstant(static_cast<double>(value));
+ return graph->GetDoubleConstant(static_cast<double>(value), GetDexPc());
default:
return nullptr;
}
@@ -956,11 +957,11 @@ HConstant* HTypeConversion::TryStaticEvaluation() const {
int64_t value = GetInput()->AsLongConstant()->GetValue();
switch (GetResultType()) {
case Primitive::kPrimInt:
- return graph->GetIntConstant(static_cast<int32_t>(value));
+ return graph->GetIntConstant(static_cast<int32_t>(value), GetDexPc());
case Primitive::kPrimFloat:
- return graph->GetFloatConstant(static_cast<float>(value));
+ return graph->GetFloatConstant(static_cast<float>(value), GetDexPc());
case Primitive::kPrimDouble:
- return graph->GetDoubleConstant(static_cast<double>(value));
+ return graph->GetDoubleConstant(static_cast<double>(value), GetDexPc());
default:
return nullptr;
}
@@ -969,22 +970,22 @@ HConstant* HTypeConversion::TryStaticEvaluation() const {
switch (GetResultType()) {
case Primitive::kPrimInt:
if (std::isnan(value))
- return graph->GetIntConstant(0);
+ return graph->GetIntConstant(0, GetDexPc());
if (value >= kPrimIntMax)
- return graph->GetIntConstant(kPrimIntMax);
+ return graph->GetIntConstant(kPrimIntMax, GetDexPc());
if (value <= kPrimIntMin)
- return graph->GetIntConstant(kPrimIntMin);
- return graph->GetIntConstant(static_cast<int32_t>(value));
+ return graph->GetIntConstant(kPrimIntMin, GetDexPc());
+ return graph->GetIntConstant(static_cast<int32_t>(value), GetDexPc());
case Primitive::kPrimLong:
if (std::isnan(value))
- return graph->GetLongConstant(0);
+ return graph->GetLongConstant(0, GetDexPc());
if (value >= kPrimLongMax)
- return graph->GetLongConstant(kPrimLongMax);
+ return graph->GetLongConstant(kPrimLongMax, GetDexPc());
if (value <= kPrimLongMin)
- return graph->GetLongConstant(kPrimLongMin);
- return graph->GetLongConstant(static_cast<int64_t>(value));
+ return graph->GetLongConstant(kPrimLongMin, GetDexPc());
+ return graph->GetLongConstant(static_cast<int64_t>(value), GetDexPc());
case Primitive::kPrimDouble:
- return graph->GetDoubleConstant(static_cast<double>(value));
+ return graph->GetDoubleConstant(static_cast<double>(value), GetDexPc());
default:
return nullptr;
}
@@ -993,22 +994,22 @@ HConstant* HTypeConversion::TryStaticEvaluation() const {
switch (GetResultType()) {
case Primitive::kPrimInt:
if (std::isnan(value))
- return graph->GetIntConstant(0);
+ return graph->GetIntConstant(0, GetDexPc());
if (value >= kPrimIntMax)
- return graph->GetIntConstant(kPrimIntMax);
+ return graph->GetIntConstant(kPrimIntMax, GetDexPc());
if (value <= kPrimLongMin)
- return graph->GetIntConstant(kPrimIntMin);
- return graph->GetIntConstant(static_cast<int32_t>(value));
+ return graph->GetIntConstant(kPrimIntMin, GetDexPc());
+ return graph->GetIntConstant(static_cast<int32_t>(value), GetDexPc());
case Primitive::kPrimLong:
if (std::isnan(value))
- return graph->GetLongConstant(0);
+ return graph->GetLongConstant(0, GetDexPc());
if (value >= kPrimLongMax)
- return graph->GetLongConstant(kPrimLongMax);
+ return graph->GetLongConstant(kPrimLongMax, GetDexPc());
if (value <= kPrimLongMin)
- return graph->GetLongConstant(kPrimLongMin);
- return graph->GetLongConstant(static_cast<int64_t>(value));
+ return graph->GetLongConstant(kPrimLongMin, GetDexPc());
+ return graph->GetLongConstant(static_cast<int64_t>(value), GetDexPc());
case Primitive::kPrimFloat:
- return graph->GetFloatConstant(static_cast<float>(value));
+ return graph->GetFloatConstant(static_cast<float>(value), GetDexPc());
default:
return nullptr;
}
@@ -1122,7 +1123,8 @@ HBasicBlock* HBasicBlock::SplitBefore(HInstruction* cursor) {
DCHECK(!graph_->IsInSsaForm()) << "Support for SSA form not implemented";
DCHECK_EQ(cursor->GetBlock(), this);
- HBasicBlock* new_block = new (GetGraph()->GetArena()) HBasicBlock(GetGraph(), GetDexPc());
+ HBasicBlock* new_block = new (GetGraph()->GetArena()) HBasicBlock(GetGraph(),
+ cursor->GetDexPc());
new_block->instructions_.first_instruction_ = cursor;
new_block->instructions_.last_instruction_ = instructions_.last_instruction_;
instructions_.last_instruction_ = cursor->previous_;
@@ -1134,7 +1136,7 @@ HBasicBlock* HBasicBlock::SplitBefore(HInstruction* cursor) {
}
new_block->instructions_.SetBlockOfInstructions(new_block);
- AddInstruction(new (GetGraph()->GetArena()) HGoto());
+ AddInstruction(new (GetGraph()->GetArena()) HGoto(new_block->GetDexPc()));
for (size_t i = 0, e = GetSuccessors().Size(); i < e; ++i) {
HBasicBlock* successor = GetSuccessors().Get(i);
@@ -1309,7 +1311,7 @@ void HBasicBlock::DisconnectAndDelete() {
predecessor->RemoveSuccessor(this);
if (predecessor->GetSuccessors().Size() == 1u) {
DCHECK(last_instruction->IsIf());
- predecessor->AddInstruction(new (graph_->GetArena()) HGoto());
+ predecessor->AddInstruction(new (graph_->GetArena()) HGoto(last_instruction->GetDexPc()));
} else {
// The predecessor has no remaining successors and therefore must be dead.
// We deliberately leave it without a control-flow instruction so that the
@@ -1562,13 +1564,13 @@ HInstruction* HGraph::InlineInto(HGraph* outer_graph, HInvoke* invoke) {
if (!returns_void) {
return_value = last->InputAt(0);
}
- predecessor->AddInstruction(new (allocator) HGoto());
+ predecessor->AddInstruction(new (allocator) HGoto(last->GetDexPc()));
predecessor->RemoveInstruction(last);
} else {
if (!returns_void) {
// There will be multiple returns.
return_value = new (allocator) HPhi(
- allocator, kNoRegNumber, 0, HPhi::ToPhiType(invoke->GetType()));
+ allocator, kNoRegNumber, 0, HPhi::ToPhiType(invoke->GetType()), to->GetDexPc());
to->AddPhi(return_value->AsPhi());
}
for (size_t i = 0, e = to->GetPredecessors().Size(); i < e; ++i) {
@@ -1577,7 +1579,7 @@ HInstruction* HGraph::InlineInto(HGraph* outer_graph, HInvoke* invoke) {
if (!returns_void) {
return_value->AsPhi()->AddInput(last->InputAt(0));
}
- predecessor->AddInstruction(new (allocator) HGoto());
+ predecessor->AddInstruction(new (allocator) HGoto(last->GetDexPc()));
predecessor->RemoveInstruction(last);
}
}
@@ -1659,15 +1661,19 @@ HInstruction* HGraph::InlineInto(HGraph* outer_graph, HInvoke* invoke) {
for (HInstructionIterator it(entry_block_->GetInstructions()); !it.Done(); it.Advance()) {
HInstruction* current = it.Current();
if (current->IsNullConstant()) {
- current->ReplaceWith(outer_graph->GetNullConstant());
+ current->ReplaceWith(outer_graph->GetNullConstant(current->GetDexPc()));
} else if (current->IsIntConstant()) {
- current->ReplaceWith(outer_graph->GetIntConstant(current->AsIntConstant()->GetValue()));
+ current->ReplaceWith(outer_graph->GetIntConstant(
+ current->AsIntConstant()->GetValue(), current->GetDexPc()));
} else if (current->IsLongConstant()) {
- current->ReplaceWith(outer_graph->GetLongConstant(current->AsLongConstant()->GetValue()));
+ current->ReplaceWith(outer_graph->GetLongConstant(
+ current->AsLongConstant()->GetValue(), current->GetDexPc()));
} else if (current->IsFloatConstant()) {
- current->ReplaceWith(outer_graph->GetFloatConstant(current->AsFloatConstant()->GetValue()));
+ current->ReplaceWith(outer_graph->GetFloatConstant(
+ current->AsFloatConstant()->GetValue(), current->GetDexPc()));
} else if (current->IsDoubleConstant()) {
- current->ReplaceWith(outer_graph->GetDoubleConstant(current->AsDoubleConstant()->GetValue()));
+ current->ReplaceWith(outer_graph->GetDoubleConstant(
+ current->AsDoubleConstant()->GetValue(), current->GetDexPc()));
} else if (current->IsParameterValue()) {
if (kIsDebugBuild
&& invoke->IsInvokeStaticOrDirect()
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index fef6f21b46..23d605b7b5 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -77,6 +77,8 @@ static constexpr uint32_t kUnknownFieldIndex = static_cast<uint32_t>(-1);
static constexpr InvokeType kInvalidInvokeType = static_cast<InvokeType>(-1);
+static constexpr uint32_t kNoDexPc = -1;
+
enum IfCondition {
kCondEQ,
kCondNE,
@@ -316,24 +318,24 @@ class HGraph : public ArenaObject<kArenaAllocGraph> {
// Returns a constant of the given type and value. If it does not exist
// already, it is created and inserted into the graph. This method is only for
// integral types.
- HConstant* GetConstant(Primitive::Type type, int64_t value);
+ HConstant* GetConstant(Primitive::Type type, int64_t value, uint32_t dex_pc = kNoDexPc);
// TODO: This is problematic for the consistency of reference type propagation
// because it can be created anytime after the pass and thus it will be left
// with an invalid type.
- HNullConstant* GetNullConstant();
+ HNullConstant* GetNullConstant(uint32_t dex_pc = kNoDexPc);
- HIntConstant* GetIntConstant(int32_t value) {
- return CreateConstant(value, &cached_int_constants_);
+ HIntConstant* GetIntConstant(int32_t value, uint32_t dex_pc = kNoDexPc) {
+ return CreateConstant(value, &cached_int_constants_, dex_pc);
}
- HLongConstant* GetLongConstant(int64_t value) {
- return CreateConstant(value, &cached_long_constants_);
+ HLongConstant* GetLongConstant(int64_t value, uint32_t dex_pc = kNoDexPc) {
+ return CreateConstant(value, &cached_long_constants_, dex_pc);
}
- HFloatConstant* GetFloatConstant(float value) {
- return CreateConstant(bit_cast<int32_t, float>(value), &cached_float_constants_);
+ HFloatConstant* GetFloatConstant(float value, uint32_t dex_pc = kNoDexPc) {
+ return CreateConstant(bit_cast<int32_t, float>(value), &cached_float_constants_, dex_pc);
}
- HDoubleConstant* GetDoubleConstant(double value) {
- return CreateConstant(bit_cast<int64_t, double>(value), &cached_double_constants_);
+ HDoubleConstant* GetDoubleConstant(double value, uint32_t dex_pc = kNoDexPc) {
+ return CreateConstant(bit_cast<int64_t, double>(value), &cached_double_constants_, dex_pc);
}
HCurrentMethod* GetCurrentMethod();
@@ -372,7 +374,8 @@ class HGraph : public ArenaObject<kArenaAllocGraph> {
template <class InstructionType, typename ValueType>
InstructionType* CreateConstant(ValueType value,
- ArenaSafeMap<ValueType, InstructionType*>* cache) {
+ ArenaSafeMap<ValueType, InstructionType*>* cache,
+ uint32_t dex_pc = kNoDexPc) {
// Try to find an existing constant of the given value.
InstructionType* constant = nullptr;
auto cached_constant = cache->find(value);
@@ -383,7 +386,7 @@ class HGraph : public ArenaObject<kArenaAllocGraph> {
// If not found or previously deleted, create and cache a new instruction.
// Don't bother reviving a previously deleted instruction, for simplicity.
if (constant == nullptr || constant->GetBlock() == nullptr) {
- constant = new (arena_) InstructionType(value);
+ constant = new (arena_) InstructionType(value, dex_pc);
cache->Overwrite(value, constant);
InsertConstant(constant);
}
@@ -618,7 +621,6 @@ class TryCatchInformation : public ArenaObject<kArenaAllocTryCatchInfo> {
};
static constexpr size_t kNoLifetime = -1;
-static constexpr uint32_t kNoDexPc = -1;
// A block in a method. Contains the list of instructions represented
// as a double linked list. Each block knows its predecessors and
@@ -626,7 +628,7 @@ static constexpr uint32_t kNoDexPc = -1;
class HBasicBlock : public ArenaObject<kArenaAllocBasicBlock> {
public:
- explicit HBasicBlock(HGraph* graph, uint32_t dex_pc = kNoDexPc)
+ HBasicBlock(HGraph* graph, uint32_t dex_pc = kNoDexPc)
: graph_(graph),
predecessors_(graph->GetArena(), kDefaultNumberOfPredecessors),
successors_(graph->GetArena(), kDefaultNumberOfSuccessors),
@@ -683,6 +685,7 @@ class HBasicBlock : public ArenaObject<kArenaAllocBasicBlock> {
int GetBlockId() const { return block_id_; }
void SetBlockId(int id) { block_id_ = id; }
+ uint32_t GetDexPc() const { return dex_pc_; }
HBasicBlock* GetDominator() const { return dominator_; }
void SetDominator(HBasicBlock* dominator) { dominator_ = dominator; }
@@ -943,7 +946,6 @@ class HBasicBlock : public ArenaObject<kArenaAllocBasicBlock> {
void SetLifetimeStart(size_t start) { lifetime_start_ = start; }
void SetLifetimeEnd(size_t end) { lifetime_end_ = end; }
- uint32_t GetDexPc() const { return dex_pc_; }
bool EndsWithControlFlowInstruction() const;
bool EndsWithIf() const;
@@ -1076,7 +1078,9 @@ class HLoopInformationOutwardIterator : public ValueObject {
#define FOR_EACH_CONCRETE_INSTRUCTION_MIPS64(M)
-#define FOR_EACH_CONCRETE_INSTRUCTION_X86(M)
+#define FOR_EACH_CONCRETE_INSTRUCTION_X86(M) \
+ M(X86ComputeBaseMethodAddress, Instruction) \
+ M(X86LoadFromConstantTable, Instruction)
#define FOR_EACH_CONCRETE_INSTRUCTION_X86_64(M)
@@ -1689,10 +1693,11 @@ std::ostream& operator<<(std::ostream& os, const ReferenceTypeInfo& rhs);
class HInstruction : public ArenaObject<kArenaAllocInstruction> {
public:
- explicit HInstruction(SideEffects side_effects)
+ HInstruction(SideEffects side_effects, uint32_t dex_pc = kNoDexPc)
: previous_(nullptr),
next_(nullptr),
block_(nullptr),
+ dex_pc_(dex_pc),
id_(-1),
ssa_index_(-1),
environment_(nullptr),
@@ -1735,9 +1740,9 @@ class HInstruction : public ArenaObject<kArenaAllocInstruction> {
}
virtual bool NeedsEnvironment() const { return false; }
- virtual uint32_t GetDexPc() const {
- return kNoDexPc;
- }
+
+ uint32_t GetDexPc() const { return dex_pc_; }
+
virtual bool IsControlFlow() const { return false; }
virtual bool CanThrow() const { return false; }
@@ -1940,6 +1945,7 @@ class HInstruction : public ArenaObject<kArenaAllocInstruction> {
HInstruction* previous_;
HInstruction* next_;
HBasicBlock* block_;
+ const uint32_t dex_pc_;
// An instruction gets an id when it is added to the graph.
// It reflects creation order. A negative id means the instruction
@@ -2044,8 +2050,8 @@ class HBackwardInstructionIterator : public ValueObject {
template<size_t N>
class HTemplateInstruction: public HInstruction {
public:
- HTemplateInstruction<N>(SideEffects side_effects)
- : HInstruction(side_effects), inputs_() {}
+ HTemplateInstruction<N>(SideEffects side_effects, uint32_t dex_pc = kNoDexPc)
+ : HInstruction(side_effects, dex_pc), inputs_() {}
virtual ~HTemplateInstruction() {}
size_t InputCount() const OVERRIDE { return N; }
@@ -2071,7 +2077,9 @@ class HTemplateInstruction: public HInstruction {
template<>
class HTemplateInstruction<0>: public HInstruction {
public:
- explicit HTemplateInstruction(SideEffects side_effects) : HInstruction(side_effects) {}
+ explicit HTemplateInstruction<0>(SideEffects side_effects, uint32_t dex_pc = kNoDexPc)
+ : HInstruction(side_effects, dex_pc) {}
+
virtual ~HTemplateInstruction() {}
size_t InputCount() const OVERRIDE { return 0; }
@@ -2095,8 +2103,8 @@ class HTemplateInstruction<0>: public HInstruction {
template<intptr_t N>
class HExpression : public HTemplateInstruction<N> {
public:
- HExpression<N>(Primitive::Type type, SideEffects side_effects)
- : HTemplateInstruction<N>(side_effects), type_(type) {}
+ HExpression<N>(Primitive::Type type, SideEffects side_effects, uint32_t dex_pc = kNoDexPc)
+ : HTemplateInstruction<N>(side_effects, dex_pc), type_(type) {}
virtual ~HExpression() {}
Primitive::Type GetType() const OVERRIDE { return type_; }
@@ -2109,7 +2117,8 @@ class HExpression : public HTemplateInstruction<N> {
// instruction that branches to the exit block.
class HReturnVoid : public HTemplateInstruction<0> {
public:
- HReturnVoid() : HTemplateInstruction(SideEffects::None()) {}
+ explicit HReturnVoid(uint32_t dex_pc = kNoDexPc)
+ : HTemplateInstruction(SideEffects::None(), dex_pc) {}
bool IsControlFlow() const OVERRIDE { return true; }
@@ -2123,7 +2132,8 @@ class HReturnVoid : public HTemplateInstruction<0> {
// instruction that branches to the exit block.
class HReturn : public HTemplateInstruction<1> {
public:
- explicit HReturn(HInstruction* value) : HTemplateInstruction(SideEffects::None()) {
+ explicit HReturn(HInstruction* value, uint32_t dex_pc = kNoDexPc)
+ : HTemplateInstruction(SideEffects::None(), dex_pc) {
SetRawInputAt(0, value);
}
@@ -2140,7 +2150,7 @@ class HReturn : public HTemplateInstruction<1> {
// exit block.
class HExit : public HTemplateInstruction<0> {
public:
- HExit() : HTemplateInstruction(SideEffects::None()) {}
+ explicit HExit(uint32_t dex_pc = kNoDexPc) : HTemplateInstruction(SideEffects::None(), dex_pc) {}
bool IsControlFlow() const OVERRIDE { return true; }
@@ -2153,7 +2163,7 @@ class HExit : public HTemplateInstruction<0> {
// Jumps from one block to another.
class HGoto : public HTemplateInstruction<0> {
public:
- HGoto() : HTemplateInstruction(SideEffects::None()) {}
+ explicit HGoto(uint32_t dex_pc = kNoDexPc) : HTemplateInstruction(SideEffects::None(), dex_pc) {}
bool IsControlFlow() const OVERRIDE { return true; }
@@ -2169,7 +2179,8 @@ class HGoto : public HTemplateInstruction<0> {
class HConstant : public HExpression<0> {
public:
- explicit HConstant(Primitive::Type type) : HExpression(type, SideEffects::None()) {}
+ explicit HConstant(Primitive::Type type, uint32_t dex_pc = kNoDexPc)
+ : HExpression(type, SideEffects::None(), dex_pc) {}
bool CanBeMoved() const OVERRIDE { return true; }
@@ -2194,7 +2205,7 @@ class HNullConstant : public HConstant {
DECLARE_INSTRUCTION(NullConstant);
private:
- HNullConstant() : HConstant(Primitive::kPrimNot) {}
+ explicit HNullConstant(uint32_t dex_pc = kNoDexPc) : HConstant(Primitive::kPrimNot, dex_pc) {}
friend class HGraph;
DISALLOW_COPY_AND_ASSIGN(HNullConstant);
@@ -2220,8 +2231,10 @@ class HIntConstant : public HConstant {
DECLARE_INSTRUCTION(IntConstant);
private:
- explicit HIntConstant(int32_t value) : HConstant(Primitive::kPrimInt), value_(value) {}
- explicit HIntConstant(bool value) : HConstant(Primitive::kPrimInt), value_(value ? 1 : 0) {}
+ explicit HIntConstant(int32_t value, uint32_t dex_pc = kNoDexPc)
+ : HConstant(Primitive::kPrimInt, dex_pc), value_(value) {}
+ explicit HIntConstant(bool value, uint32_t dex_pc = kNoDexPc)
+ : HConstant(Primitive::kPrimInt, dex_pc), value_(value ? 1 : 0) {}
const int32_t value_;
@@ -2249,7 +2262,8 @@ class HLongConstant : public HConstant {
DECLARE_INSTRUCTION(LongConstant);
private:
- explicit HLongConstant(int64_t value) : HConstant(Primitive::kPrimLong), value_(value) {}
+ explicit HLongConstant(int64_t value, uint32_t dex_pc = kNoDexPc)
+ : HConstant(Primitive::kPrimLong, dex_pc), value_(value) {}
const int64_t value_;
@@ -2261,7 +2275,8 @@ class HLongConstant : public HConstant {
// two successors.
class HIf : public HTemplateInstruction<1> {
public:
- explicit HIf(HInstruction* input) : HTemplateInstruction(SideEffects::None()) {
+ explicit HIf(HInstruction* input, uint32_t dex_pc = kNoDexPc)
+ : HTemplateInstruction(SideEffects::None(), dex_pc) {
SetRawInputAt(0, input);
}
@@ -2294,8 +2309,8 @@ class HTryBoundary : public HTemplateInstruction<0> {
kExit,
};
- explicit HTryBoundary(BoundaryKind kind)
- : HTemplateInstruction(SideEffects::None()), kind_(kind) {}
+ explicit HTryBoundary(BoundaryKind kind, uint32_t dex_pc = kNoDexPc)
+ : HTemplateInstruction(SideEffects::None(), dex_pc), kind_(kind) {}
bool IsControlFlow() const OVERRIDE { return true; }
@@ -2352,21 +2367,17 @@ class HExceptionHandlerIterator : public ValueObject {
// Deoptimize to interpreter, upon checking a condition.
class HDeoptimize : public HTemplateInstruction<1> {
public:
- HDeoptimize(HInstruction* cond, uint32_t dex_pc)
- : HTemplateInstruction(SideEffects::None()),
- dex_pc_(dex_pc) {
+ explicit HDeoptimize(HInstruction* cond, uint32_t dex_pc)
+ : HTemplateInstruction(SideEffects::None(), dex_pc) {
SetRawInputAt(0, cond);
}
bool NeedsEnvironment() const OVERRIDE { return true; }
bool CanThrow() const OVERRIDE { return true; }
- uint32_t GetDexPc() const OVERRIDE { return dex_pc_; }
DECLARE_INSTRUCTION(Deoptimize);
private:
- uint32_t dex_pc_;
-
DISALLOW_COPY_AND_ASSIGN(HDeoptimize);
};
@@ -2375,7 +2386,8 @@ class HDeoptimize : public HTemplateInstruction<1> {
// instructions that work with the dex cache.
class HCurrentMethod : public HExpression<0> {
public:
- explicit HCurrentMethod(Primitive::Type type) : HExpression(type, SideEffects::None()) {}
+ explicit HCurrentMethod(Primitive::Type type, uint32_t dex_pc = kNoDexPc)
+ : HExpression(type, SideEffects::None(), dex_pc) {}
DECLARE_INSTRUCTION(CurrentMethod);
@@ -2385,8 +2397,8 @@ class HCurrentMethod : public HExpression<0> {
class HUnaryOperation : public HExpression<1> {
public:
- HUnaryOperation(Primitive::Type result_type, HInstruction* input)
- : HExpression(result_type, SideEffects::None()) {
+ HUnaryOperation(Primitive::Type result_type, HInstruction* input, uint32_t dex_pc = kNoDexPc)
+ : HExpression(result_type, SideEffects::None(), dex_pc) {
SetRawInputAt(0, input);
}
@@ -2419,8 +2431,9 @@ class HBinaryOperation : public HExpression<2> {
HBinaryOperation(Primitive::Type result_type,
HInstruction* left,
HInstruction* right,
- SideEffects side_effects = SideEffects::None())
- : HExpression(result_type, side_effects) {
+ SideEffects side_effects = SideEffects::None(),
+ uint32_t dex_pc = kNoDexPc)
+ : HExpression(result_type, side_effects, dex_pc) {
SetRawInputAt(0, left);
SetRawInputAt(1, right);
}
@@ -2512,8 +2525,8 @@ enum class ComparisonBias {
class HCondition : public HBinaryOperation {
public:
- HCondition(HInstruction* first, HInstruction* second)
- : HBinaryOperation(Primitive::kPrimBoolean, first, second),
+ HCondition(HInstruction* first, HInstruction* second, uint32_t dex_pc = kNoDexPc)
+ : HBinaryOperation(Primitive::kPrimBoolean, first, second, SideEffects::None(), dex_pc),
needs_materialization_(true),
bias_(ComparisonBias::kNoBias) {}
@@ -2564,18 +2577,20 @@ class HCondition : public HBinaryOperation {
// Instruction to check if two inputs are equal to each other.
class HEqual : public HCondition {
public:
- HEqual(HInstruction* first, HInstruction* second)
- : HCondition(first, second) {}
+ HEqual(HInstruction* first, HInstruction* second, uint32_t dex_pc = kNoDexPc)
+ : HCondition(first, second, dex_pc) {}
bool IsCommutative() const OVERRIDE { return true; }
template <typename T> bool Compute(T x, T y) const { return x == y; }
HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const OVERRIDE {
- return GetBlock()->GetGraph()->GetIntConstant(Compute(x->GetValue(), y->GetValue()));
+ return GetBlock()->GetGraph()->GetIntConstant(
+ Compute(x->GetValue(), y->GetValue()), GetDexPc());
}
HConstant* Evaluate(HLongConstant* x, HLongConstant* y) const OVERRIDE {
- return GetBlock()->GetGraph()->GetIntConstant(Compute(x->GetValue(), y->GetValue()));
+ return GetBlock()->GetGraph()->GetIntConstant(
+ Compute(x->GetValue(), y->GetValue()), GetDexPc());
}
DECLARE_INSTRUCTION(Equal);
@@ -2594,18 +2609,20 @@ class HEqual : public HCondition {
class HNotEqual : public HCondition {
public:
- HNotEqual(HInstruction* first, HInstruction* second)
- : HCondition(first, second) {}
+ HNotEqual(HInstruction* first, HInstruction* second, uint32_t dex_pc = kNoDexPc)
+ : HCondition(first, second, dex_pc) {}
bool IsCommutative() const OVERRIDE { return true; }
template <typename T> bool Compute(T x, T y) const { return x != y; }
HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const OVERRIDE {
- return GetBlock()->GetGraph()->GetIntConstant(Compute(x->GetValue(), y->GetValue()));
+ return GetBlock()->GetGraph()->GetIntConstant(
+ Compute(x->GetValue(), y->GetValue()), GetDexPc());
}
HConstant* Evaluate(HLongConstant* x, HLongConstant* y) const OVERRIDE {
- return GetBlock()->GetGraph()->GetIntConstant(Compute(x->GetValue(), y->GetValue()));
+ return GetBlock()->GetGraph()->GetIntConstant(
+ Compute(x->GetValue(), y->GetValue()), GetDexPc());
}
DECLARE_INSTRUCTION(NotEqual);
@@ -2624,16 +2641,18 @@ class HNotEqual : public HCondition {
class HLessThan : public HCondition {
public:
- HLessThan(HInstruction* first, HInstruction* second)
- : HCondition(first, second) {}
+ HLessThan(HInstruction* first, HInstruction* second, uint32_t dex_pc = kNoDexPc)
+ : HCondition(first, second, dex_pc) {}
template <typename T> bool Compute(T x, T y) const { return x < y; }
HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const OVERRIDE {
- return GetBlock()->GetGraph()->GetIntConstant(Compute(x->GetValue(), y->GetValue()));
+ return GetBlock()->GetGraph()->GetIntConstant(
+ Compute(x->GetValue(), y->GetValue()), GetDexPc());
}
HConstant* Evaluate(HLongConstant* x, HLongConstant* y) const OVERRIDE {
- return GetBlock()->GetGraph()->GetIntConstant(Compute(x->GetValue(), y->GetValue()));
+ return GetBlock()->GetGraph()->GetIntConstant(
+ Compute(x->GetValue(), y->GetValue()), GetDexPc());
}
DECLARE_INSTRUCTION(LessThan);
@@ -2652,16 +2671,18 @@ class HLessThan : public HCondition {
class HLessThanOrEqual : public HCondition {
public:
- HLessThanOrEqual(HInstruction* first, HInstruction* second)
- : HCondition(first, second) {}
+ HLessThanOrEqual(HInstruction* first, HInstruction* second, uint32_t dex_pc = kNoDexPc)
+ : HCondition(first, second, dex_pc) {}
template <typename T> bool Compute(T x, T y) const { return x <= y; }
HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const OVERRIDE {
- return GetBlock()->GetGraph()->GetIntConstant(Compute(x->GetValue(), y->GetValue()));
+ return GetBlock()->GetGraph()->GetIntConstant(
+ Compute(x->GetValue(), y->GetValue()), GetDexPc());
}
HConstant* Evaluate(HLongConstant* x, HLongConstant* y) const OVERRIDE {
- return GetBlock()->GetGraph()->GetIntConstant(Compute(x->GetValue(), y->GetValue()));
+ return GetBlock()->GetGraph()->GetIntConstant(
+ Compute(x->GetValue(), y->GetValue()), GetDexPc());
}
DECLARE_INSTRUCTION(LessThanOrEqual);
@@ -2680,16 +2701,18 @@ class HLessThanOrEqual : public HCondition {
class HGreaterThan : public HCondition {
public:
- HGreaterThan(HInstruction* first, HInstruction* second)
- : HCondition(first, second) {}
+ HGreaterThan(HInstruction* first, HInstruction* second, uint32_t dex_pc = kNoDexPc)
+ : HCondition(first, second, dex_pc) {}
template <typename T> bool Compute(T x, T y) const { return x > y; }
HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const OVERRIDE {
- return GetBlock()->GetGraph()->GetIntConstant(Compute(x->GetValue(), y->GetValue()));
+ return GetBlock()->GetGraph()->GetIntConstant(
+ Compute(x->GetValue(), y->GetValue()), GetDexPc());
}
HConstant* Evaluate(HLongConstant* x, HLongConstant* y) const OVERRIDE {
- return GetBlock()->GetGraph()->GetIntConstant(Compute(x->GetValue(), y->GetValue()));
+ return GetBlock()->GetGraph()->GetIntConstant(
+ Compute(x->GetValue(), y->GetValue()), GetDexPc());
}
DECLARE_INSTRUCTION(GreaterThan);
@@ -2708,16 +2731,18 @@ class HGreaterThan : public HCondition {
class HGreaterThanOrEqual : public HCondition {
public:
- HGreaterThanOrEqual(HInstruction* first, HInstruction* second)
- : HCondition(first, second) {}
+ HGreaterThanOrEqual(HInstruction* first, HInstruction* second, uint32_t dex_pc = kNoDexPc)
+ : HCondition(first, second, dex_pc) {}
template <typename T> bool Compute(T x, T y) const { return x >= y; }
HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const OVERRIDE {
- return GetBlock()->GetGraph()->GetIntConstant(Compute(x->GetValue(), y->GetValue()));
+ return GetBlock()->GetGraph()->GetIntConstant(
+ Compute(x->GetValue(), y->GetValue()), GetDexPc());
}
HConstant* Evaluate(HLongConstant* x, HLongConstant* y) const OVERRIDE {
- return GetBlock()->GetGraph()->GetIntConstant(Compute(x->GetValue(), y->GetValue()));
+ return GetBlock()->GetGraph()->GetIntConstant(
+ Compute(x->GetValue(), y->GetValue()), GetDexPc());
}
DECLARE_INSTRUCTION(GreaterThanOrEqual);
@@ -2744,9 +2769,12 @@ class HCompare : public HBinaryOperation {
HInstruction* second,
ComparisonBias bias,
uint32_t dex_pc)
- : HBinaryOperation(Primitive::kPrimInt, first, second, SideEffectsForArchRuntimeCalls(type)),
- bias_(bias),
- dex_pc_(dex_pc) {
+ : HBinaryOperation(Primitive::kPrimInt,
+ first,
+ second,
+ SideEffectsForArchRuntimeCalls(type),
+ dex_pc),
+ bias_(bias) {
DCHECK_EQ(type, first->GetType());
DCHECK_EQ(type, second->GetType());
}
@@ -2755,10 +2783,12 @@ class HCompare : public HBinaryOperation {
int32_t Compute(T x, T y) const { return x == y ? 0 : x > y ? 1 : -1; }
HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const OVERRIDE {
- return GetBlock()->GetGraph()->GetIntConstant(Compute(x->GetValue(), y->GetValue()));
+ return GetBlock()->GetGraph()->GetIntConstant(
+ Compute(x->GetValue(), y->GetValue()), GetDexPc());
}
HConstant* Evaluate(HLongConstant* x, HLongConstant* y) const OVERRIDE {
- return GetBlock()->GetGraph()->GetIntConstant(Compute(x->GetValue(), y->GetValue()));
+ return GetBlock()->GetGraph()->GetIntConstant(
+ Compute(x->GetValue(), y->GetValue()), GetDexPc());
}
bool InstructionDataEquals(HInstruction* other) const OVERRIDE {
@@ -2769,7 +2799,6 @@ class HCompare : public HBinaryOperation {
bool IsGtBias() { return bias_ == ComparisonBias::kGtBias; }
- uint32_t GetDexPc() const OVERRIDE { return dex_pc_; }
static SideEffects SideEffectsForArchRuntimeCalls(Primitive::Type type) {
// MIPS64 uses a runtime call for FP comparisons.
@@ -2780,7 +2809,6 @@ class HCompare : public HBinaryOperation {
private:
const ComparisonBias bias_;
- const uint32_t dex_pc_;
DISALLOW_COPY_AND_ASSIGN(HCompare);
};
@@ -2789,7 +2817,7 @@ class HCompare : public HBinaryOperation {
class HLocal : public HTemplateInstruction<0> {
public:
explicit HLocal(uint16_t reg_number)
- : HTemplateInstruction(SideEffects::None()), reg_number_(reg_number) {}
+ : HTemplateInstruction(SideEffects::None(), kNoDexPc), reg_number_(reg_number) {}
DECLARE_INSTRUCTION(Local);
@@ -2805,8 +2833,8 @@ class HLocal : public HTemplateInstruction<0> {
// Load a given local. The local is an input of this instruction.
class HLoadLocal : public HExpression<1> {
public:
- HLoadLocal(HLocal* local, Primitive::Type type)
- : HExpression(type, SideEffects::None()) {
+ HLoadLocal(HLocal* local, Primitive::Type type, uint32_t dex_pc = kNoDexPc)
+ : HExpression(type, SideEffects::None(), dex_pc) {
SetRawInputAt(0, local);
}
@@ -2822,7 +2850,8 @@ class HLoadLocal : public HExpression<1> {
// and the local.
class HStoreLocal : public HTemplateInstruction<2> {
public:
- HStoreLocal(HLocal* local, HInstruction* value) : HTemplateInstruction(SideEffects::None()) {
+ HStoreLocal(HLocal* local, HInstruction* value, uint32_t dex_pc = kNoDexPc)
+ : HTemplateInstruction(SideEffects::None(), dex_pc) {
SetRawInputAt(0, local);
SetRawInputAt(1, value);
}
@@ -2863,9 +2892,10 @@ class HFloatConstant : public HConstant {
DECLARE_INSTRUCTION(FloatConstant);
private:
- explicit HFloatConstant(float value) : HConstant(Primitive::kPrimFloat), value_(value) {}
- explicit HFloatConstant(int32_t value)
- : HConstant(Primitive::kPrimFloat), value_(bit_cast<float, int32_t>(value)) {}
+ explicit HFloatConstant(float value, uint32_t dex_pc = kNoDexPc)
+ : HConstant(Primitive::kPrimFloat, dex_pc), value_(value) {}
+ explicit HFloatConstant(int32_t value, uint32_t dex_pc = kNoDexPc)
+ : HConstant(Primitive::kPrimFloat, dex_pc), value_(bit_cast<float, int32_t>(value)) {}
const float value_;
@@ -2903,9 +2933,10 @@ class HDoubleConstant : public HConstant {
DECLARE_INSTRUCTION(DoubleConstant);
private:
- explicit HDoubleConstant(double value) : HConstant(Primitive::kPrimDouble), value_(value) {}
- explicit HDoubleConstant(int64_t value)
- : HConstant(Primitive::kPrimDouble), value_(bit_cast<double, int64_t>(value)) {}
+ explicit HDoubleConstant(double value, uint32_t dex_pc = kNoDexPc)
+ : HConstant(Primitive::kPrimDouble, dex_pc), value_(value) {}
+ explicit HDoubleConstant(int64_t value, uint32_t dex_pc = kNoDexPc)
+ : HConstant(Primitive::kPrimDouble, dex_pc), value_(bit_cast<double, int64_t>(value)) {}
const double value_;
@@ -2952,7 +2983,6 @@ class HInvoke : public HInstruction {
Primitive::Type GetType() const OVERRIDE { return return_type_; }
- uint32_t GetDexPc() const OVERRIDE { return dex_pc_; }
uint32_t GetDexMethodIndex() const { return dex_method_index_; }
const DexFile& GetDexFile() const { return GetEnvironment()->GetDexFile(); }
@@ -2985,11 +3015,10 @@ class HInvoke : public HInstruction {
uint32_t dex_method_index,
InvokeType original_invoke_type)
: HInstruction(
- SideEffects::AllExceptGCDependency()), // Assume write/read on all fields/arrays.
+ SideEffects::AllExceptGCDependency(), dex_pc), // Assume write/read on all fields/arrays.
number_of_arguments_(number_of_arguments),
inputs_(arena, number_of_arguments),
return_type_(return_type),
- dex_pc_(dex_pc),
dex_method_index_(dex_method_index),
original_invoke_type_(original_invoke_type),
intrinsic_(Intrinsics::kNone),
@@ -3006,7 +3035,6 @@ class HInvoke : public HInstruction {
uint32_t number_of_arguments_;
GrowableArray<HUserRecord<HInstruction*> > inputs_;
const Primitive::Type return_type_;
- const uint32_t dex_pc_;
const uint32_t dex_method_index_;
const InvokeType original_invoke_type_;
Intrinsics intrinsic_;
@@ -3307,15 +3335,13 @@ class HNewInstance : public HExpression<1> {
uint16_t type_index,
const DexFile& dex_file,
QuickEntrypointEnum entrypoint)
- : HExpression(Primitive::kPrimNot, SideEffects::CanTriggerGC()),
- dex_pc_(dex_pc),
+ : HExpression(Primitive::kPrimNot, SideEffects::CanTriggerGC(), dex_pc),
type_index_(type_index),
dex_file_(dex_file),
entrypoint_(entrypoint) {
SetRawInputAt(0, current_method);
}
- uint32_t GetDexPc() const OVERRIDE { return dex_pc_; }
uint16_t GetTypeIndex() const { return type_index_; }
const DexFile& GetDexFile() const { return dex_file_; }
@@ -3334,7 +3360,6 @@ class HNewInstance : public HExpression<1> {
DECLARE_INSTRUCTION(NewInstance);
private:
- const uint32_t dex_pc_;
const uint16_t type_index_;
const DexFile& dex_file_;
const QuickEntrypointEnum entrypoint_;
@@ -3344,16 +3369,16 @@ class HNewInstance : public HExpression<1> {
class HNeg : public HUnaryOperation {
public:
- HNeg(Primitive::Type result_type, HInstruction* input)
- : HUnaryOperation(result_type, input) {}
+ HNeg(Primitive::Type result_type, HInstruction* input, uint32_t dex_pc = kNoDexPc)
+ : HUnaryOperation(result_type, input, dex_pc) {}
template <typename T> T Compute(T x) const { return -x; }
HConstant* Evaluate(HIntConstant* x) const OVERRIDE {
- return GetBlock()->GetGraph()->GetIntConstant(Compute(x->GetValue()));
+ return GetBlock()->GetGraph()->GetIntConstant(Compute(x->GetValue()), GetDexPc());
}
HConstant* Evaluate(HLongConstant* x) const OVERRIDE {
- return GetBlock()->GetGraph()->GetLongConstant(Compute(x->GetValue()));
+ return GetBlock()->GetGraph()->GetLongConstant(Compute(x->GetValue()), GetDexPc());
}
DECLARE_INSTRUCTION(Neg);
@@ -3370,8 +3395,7 @@ class HNewArray : public HExpression<2> {
uint16_t type_index,
const DexFile& dex_file,
QuickEntrypointEnum entrypoint)
- : HExpression(Primitive::kPrimNot, SideEffects::CanTriggerGC()),
- dex_pc_(dex_pc),
+ : HExpression(Primitive::kPrimNot, SideEffects::CanTriggerGC(), dex_pc),
type_index_(type_index),
dex_file_(dex_file),
entrypoint_(entrypoint) {
@@ -3379,7 +3403,6 @@ class HNewArray : public HExpression<2> {
SetRawInputAt(1, current_method);
}
- uint32_t GetDexPc() const OVERRIDE { return dex_pc_; }
uint16_t GetTypeIndex() const { return type_index_; }
const DexFile& GetDexFile() const { return dex_file_; }
@@ -3396,7 +3419,6 @@ class HNewArray : public HExpression<2> {
DECLARE_INSTRUCTION(NewArray);
private:
- const uint32_t dex_pc_;
const uint16_t type_index_;
const DexFile& dex_file_;
const QuickEntrypointEnum entrypoint_;
@@ -3406,18 +3428,23 @@ class HNewArray : public HExpression<2> {
class HAdd : public HBinaryOperation {
public:
- HAdd(Primitive::Type result_type, HInstruction* left, HInstruction* right)
- : HBinaryOperation(result_type, left, right) {}
+ HAdd(Primitive::Type result_type,
+ HInstruction* left,
+ HInstruction* right,
+ uint32_t dex_pc = kNoDexPc)
+ : HBinaryOperation(result_type, left, right, SideEffects::None(), dex_pc) {}
bool IsCommutative() const OVERRIDE { return true; }
template <typename T> T Compute(T x, T y) const { return x + y; }
HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const OVERRIDE {
- return GetBlock()->GetGraph()->GetIntConstant(Compute(x->GetValue(), y->GetValue()));
+ return GetBlock()->GetGraph()->GetIntConstant(
+ Compute(x->GetValue(), y->GetValue()), GetDexPc());
}
HConstant* Evaluate(HLongConstant* x, HLongConstant* y) const OVERRIDE {
- return GetBlock()->GetGraph()->GetLongConstant(Compute(x->GetValue(), y->GetValue()));
+ return GetBlock()->GetGraph()->GetLongConstant(
+ Compute(x->GetValue(), y->GetValue()), GetDexPc());
}
DECLARE_INSTRUCTION(Add);
@@ -3428,16 +3455,21 @@ class HAdd : public HBinaryOperation {
class HSub : public HBinaryOperation {
public:
- HSub(Primitive::Type result_type, HInstruction* left, HInstruction* right)
- : HBinaryOperation(result_type, left, right) {}
+ HSub(Primitive::Type result_type,
+ HInstruction* left,
+ HInstruction* right,
+ uint32_t dex_pc = kNoDexPc)
+ : HBinaryOperation(result_type, left, right, SideEffects::None(), dex_pc) {}
template <typename T> T Compute(T x, T y) const { return x - y; }
HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const OVERRIDE {
- return GetBlock()->GetGraph()->GetIntConstant(Compute(x->GetValue(), y->GetValue()));
+ return GetBlock()->GetGraph()->GetIntConstant(
+ Compute(x->GetValue(), y->GetValue()), GetDexPc());
}
HConstant* Evaluate(HLongConstant* x, HLongConstant* y) const OVERRIDE {
- return GetBlock()->GetGraph()->GetLongConstant(Compute(x->GetValue(), y->GetValue()));
+ return GetBlock()->GetGraph()->GetLongConstant(
+ Compute(x->GetValue(), y->GetValue()), GetDexPc());
}
DECLARE_INSTRUCTION(Sub);
@@ -3448,18 +3480,23 @@ class HSub : public HBinaryOperation {
class HMul : public HBinaryOperation {
public:
- HMul(Primitive::Type result_type, HInstruction* left, HInstruction* right)
- : HBinaryOperation(result_type, left, right) {}
+ HMul(Primitive::Type result_type,
+ HInstruction* left,
+ HInstruction* right,
+ uint32_t dex_pc = kNoDexPc)
+ : HBinaryOperation(result_type, left, right, SideEffects::None(), dex_pc) {}
bool IsCommutative() const OVERRIDE { return true; }
template <typename T> T Compute(T x, T y) const { return x * y; }
HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const OVERRIDE {
- return GetBlock()->GetGraph()->GetIntConstant(Compute(x->GetValue(), y->GetValue()));
+ return GetBlock()->GetGraph()->GetIntConstant(
+ Compute(x->GetValue(), y->GetValue()), GetDexPc());
}
HConstant* Evaluate(HLongConstant* x, HLongConstant* y) const OVERRIDE {
- return GetBlock()->GetGraph()->GetLongConstant(Compute(x->GetValue(), y->GetValue()));
+ return GetBlock()->GetGraph()->GetLongConstant(
+ Compute(x->GetValue(), y->GetValue()), GetDexPc());
}
DECLARE_INSTRUCTION(Mul);
@@ -3470,9 +3507,11 @@ class HMul : public HBinaryOperation {
class HDiv : public HBinaryOperation {
public:
- HDiv(Primitive::Type result_type, HInstruction* left, HInstruction* right, uint32_t dex_pc)
- : HBinaryOperation(result_type, left, right, SideEffectsForArchRuntimeCalls()),
- dex_pc_(dex_pc) {}
+ HDiv(Primitive::Type result_type,
+ HInstruction* left,
+ HInstruction* right,
+ uint32_t dex_pc)
+ : HBinaryOperation(result_type, left, right, SideEffectsForArchRuntimeCalls(), dex_pc) {}
template <typename T>
T Compute(T x, T y) const {
@@ -3484,14 +3523,14 @@ class HDiv : public HBinaryOperation {
}
HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const OVERRIDE {
- return GetBlock()->GetGraph()->GetIntConstant(Compute(x->GetValue(), y->GetValue()));
+ return GetBlock()->GetGraph()->GetIntConstant(
+ Compute(x->GetValue(), y->GetValue()), GetDexPc());
}
HConstant* Evaluate(HLongConstant* x, HLongConstant* y) const OVERRIDE {
- return GetBlock()->GetGraph()->GetLongConstant(Compute(x->GetValue(), y->GetValue()));
+ return GetBlock()->GetGraph()->GetLongConstant(
+ Compute(x->GetValue(), y->GetValue()), GetDexPc());
}
- uint32_t GetDexPc() const OVERRIDE { return dex_pc_; }
-
static SideEffects SideEffectsForArchRuntimeCalls() {
// The generated code can use a runtime call.
return SideEffects::CanTriggerGC();
@@ -3500,16 +3539,16 @@ class HDiv : public HBinaryOperation {
DECLARE_INSTRUCTION(Div);
private:
- const uint32_t dex_pc_;
-
DISALLOW_COPY_AND_ASSIGN(HDiv);
};
class HRem : public HBinaryOperation {
public:
- HRem(Primitive::Type result_type, HInstruction* left, HInstruction* right, uint32_t dex_pc)
- : HBinaryOperation(result_type, left, right, SideEffectsForArchRuntimeCalls()),
- dex_pc_(dex_pc) {}
+ HRem(Primitive::Type result_type,
+ HInstruction* left,
+ HInstruction* right,
+ uint32_t dex_pc)
+ : HBinaryOperation(result_type, left, right, SideEffectsForArchRuntimeCalls(), dex_pc) {}
template <typename T>
T Compute(T x, T y) const {
@@ -3521,13 +3560,14 @@ class HRem : public HBinaryOperation {
}
HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const OVERRIDE {
- return GetBlock()->GetGraph()->GetIntConstant(Compute(x->GetValue(), y->GetValue()));
+ return GetBlock()->GetGraph()->GetIntConstant(
+ Compute(x->GetValue(), y->GetValue()), GetDexPc());
}
HConstant* Evaluate(HLongConstant* x, HLongConstant* y) const OVERRIDE {
- return GetBlock()->GetGraph()->GetLongConstant(Compute(x->GetValue(), y->GetValue()));
+ return GetBlock()->GetGraph()->GetLongConstant(
+ Compute(x->GetValue(), y->GetValue()), GetDexPc());
}
- uint32_t GetDexPc() const OVERRIDE { return dex_pc_; }
static SideEffects SideEffectsForArchRuntimeCalls() {
return SideEffects::CanTriggerGC();
@@ -3536,15 +3576,13 @@ class HRem : public HBinaryOperation {
DECLARE_INSTRUCTION(Rem);
private:
- const uint32_t dex_pc_;
-
DISALLOW_COPY_AND_ASSIGN(HRem);
};
class HDivZeroCheck : public HExpression<1> {
public:
HDivZeroCheck(HInstruction* value, uint32_t dex_pc)
- : HExpression(value->GetType(), SideEffects::None()), dex_pc_(dex_pc) {
+ : HExpression(value->GetType(), SideEffects::None(), dex_pc) {
SetRawInputAt(0, value);
}
@@ -3560,20 +3598,19 @@ class HDivZeroCheck : public HExpression<1> {
bool NeedsEnvironment() const OVERRIDE { return true; }
bool CanThrow() const OVERRIDE { return true; }
- uint32_t GetDexPc() const OVERRIDE { return dex_pc_; }
-
DECLARE_INSTRUCTION(DivZeroCheck);
private:
- const uint32_t dex_pc_;
-
DISALLOW_COPY_AND_ASSIGN(HDivZeroCheck);
};
class HShl : public HBinaryOperation {
public:
- HShl(Primitive::Type result_type, HInstruction* left, HInstruction* right)
- : HBinaryOperation(result_type, left, right) {}
+ HShl(Primitive::Type result_type,
+ HInstruction* left,
+ HInstruction* right,
+ uint32_t dex_pc = kNoDexPc)
+ : HBinaryOperation(result_type, left, right, SideEffects::None(), dex_pc) {}
template <typename T, typename U, typename V>
T Compute(T x, U y, V max_shift_value) const {
@@ -3584,17 +3621,17 @@ class HShl : public HBinaryOperation {
HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const OVERRIDE {
return GetBlock()->GetGraph()->GetIntConstant(
- Compute(x->GetValue(), y->GetValue(), kMaxIntShiftValue));
+ Compute(x->GetValue(), y->GetValue(), kMaxIntShiftValue), GetDexPc());
}
// There is no `Evaluate(HIntConstant* x, HLongConstant* y)`, as this
// case is handled as `x << static_cast<int>(y)`.
HConstant* Evaluate(HLongConstant* x, HIntConstant* y) const OVERRIDE {
return GetBlock()->GetGraph()->GetLongConstant(
- Compute(x->GetValue(), y->GetValue(), kMaxLongShiftValue));
+ Compute(x->GetValue(), y->GetValue(), kMaxLongShiftValue), GetDexPc());
}
HConstant* Evaluate(HLongConstant* x, HLongConstant* y) const OVERRIDE {
return GetBlock()->GetGraph()->GetLongConstant(
- Compute(x->GetValue(), y->GetValue(), kMaxLongShiftValue));
+ Compute(x->GetValue(), y->GetValue(), kMaxLongShiftValue), GetDexPc());
}
DECLARE_INSTRUCTION(Shl);
@@ -3605,8 +3642,11 @@ class HShl : public HBinaryOperation {
class HShr : public HBinaryOperation {
public:
- HShr(Primitive::Type result_type, HInstruction* left, HInstruction* right)
- : HBinaryOperation(result_type, left, right) {}
+ HShr(Primitive::Type result_type,
+ HInstruction* left,
+ HInstruction* right,
+ uint32_t dex_pc = kNoDexPc)
+ : HBinaryOperation(result_type, left, right, SideEffects::None(), dex_pc) {}
template <typename T, typename U, typename V>
T Compute(T x, U y, V max_shift_value) const {
@@ -3617,17 +3657,17 @@ class HShr : public HBinaryOperation {
HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const OVERRIDE {
return GetBlock()->GetGraph()->GetIntConstant(
- Compute(x->GetValue(), y->GetValue(), kMaxIntShiftValue));
+ Compute(x->GetValue(), y->GetValue(), kMaxIntShiftValue), GetDexPc());
}
// There is no `Evaluate(HIntConstant* x, HLongConstant* y)`, as this
// case is handled as `x >> static_cast<int>(y)`.
HConstant* Evaluate(HLongConstant* x, HIntConstant* y) const OVERRIDE {
return GetBlock()->GetGraph()->GetLongConstant(
- Compute(x->GetValue(), y->GetValue(), kMaxLongShiftValue));
+ Compute(x->GetValue(), y->GetValue(), kMaxLongShiftValue), GetDexPc());
}
HConstant* Evaluate(HLongConstant* x, HLongConstant* y) const OVERRIDE {
return GetBlock()->GetGraph()->GetLongConstant(
- Compute(x->GetValue(), y->GetValue(), kMaxLongShiftValue));
+ Compute(x->GetValue(), y->GetValue(), kMaxLongShiftValue), GetDexPc());
}
DECLARE_INSTRUCTION(Shr);
@@ -3638,8 +3678,11 @@ class HShr : public HBinaryOperation {
class HUShr : public HBinaryOperation {
public:
- HUShr(Primitive::Type result_type, HInstruction* left, HInstruction* right)
- : HBinaryOperation(result_type, left, right) {}
+ HUShr(Primitive::Type result_type,
+ HInstruction* left,
+ HInstruction* right,
+ uint32_t dex_pc = kNoDexPc)
+ : HBinaryOperation(result_type, left, right, SideEffects::None(), dex_pc) {}
template <typename T, typename U, typename V>
T Compute(T x, U y, V max_shift_value) const {
@@ -3651,17 +3694,17 @@ class HUShr : public HBinaryOperation {
HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const OVERRIDE {
return GetBlock()->GetGraph()->GetIntConstant(
- Compute(x->GetValue(), y->GetValue(), kMaxIntShiftValue));
+ Compute(x->GetValue(), y->GetValue(), kMaxIntShiftValue), GetDexPc());
}
// There is no `Evaluate(HIntConstant* x, HLongConstant* y)`, as this
// case is handled as `x >>> static_cast<int>(y)`.
HConstant* Evaluate(HLongConstant* x, HIntConstant* y) const OVERRIDE {
return GetBlock()->GetGraph()->GetLongConstant(
- Compute(x->GetValue(), y->GetValue(), kMaxLongShiftValue));
+ Compute(x->GetValue(), y->GetValue(), kMaxLongShiftValue), GetDexPc());
}
HConstant* Evaluate(HLongConstant* x, HLongConstant* y) const OVERRIDE {
return GetBlock()->GetGraph()->GetLongConstant(
- Compute(x->GetValue(), y->GetValue(), kMaxLongShiftValue));
+ Compute(x->GetValue(), y->GetValue(), kMaxLongShiftValue), GetDexPc());
}
DECLARE_INSTRUCTION(UShr);
@@ -3672,8 +3715,11 @@ class HUShr : public HBinaryOperation {
class HAnd : public HBinaryOperation {
public:
- HAnd(Primitive::Type result_type, HInstruction* left, HInstruction* right)
- : HBinaryOperation(result_type, left, right) {}
+ HAnd(Primitive::Type result_type,
+ HInstruction* left,
+ HInstruction* right,
+ uint32_t dex_pc = kNoDexPc)
+ : HBinaryOperation(result_type, left, right, SideEffects::None(), dex_pc) {}
bool IsCommutative() const OVERRIDE { return true; }
@@ -3681,16 +3727,20 @@ class HAnd : public HBinaryOperation {
auto Compute(T x, U y) const -> decltype(x & y) { return x & y; }
HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const OVERRIDE {
- return GetBlock()->GetGraph()->GetIntConstant(Compute(x->GetValue(), y->GetValue()));
+ return GetBlock()->GetGraph()->GetIntConstant(
+ Compute(x->GetValue(), y->GetValue()), GetDexPc());
}
HConstant* Evaluate(HIntConstant* x, HLongConstant* y) const OVERRIDE {
- return GetBlock()->GetGraph()->GetLongConstant(Compute(x->GetValue(), y->GetValue()));
+ return GetBlock()->GetGraph()->GetLongConstant(
+ Compute(x->GetValue(), y->GetValue()), GetDexPc());
}
HConstant* Evaluate(HLongConstant* x, HIntConstant* y) const OVERRIDE {
- return GetBlock()->GetGraph()->GetLongConstant(Compute(x->GetValue(), y->GetValue()));
+ return GetBlock()->GetGraph()->GetLongConstant(
+ Compute(x->GetValue(), y->GetValue()), GetDexPc());
}
HConstant* Evaluate(HLongConstant* x, HLongConstant* y) const OVERRIDE {
- return GetBlock()->GetGraph()->GetLongConstant(Compute(x->GetValue(), y->GetValue()));
+ return GetBlock()->GetGraph()->GetLongConstant(
+ Compute(x->GetValue(), y->GetValue()), GetDexPc());
}
DECLARE_INSTRUCTION(And);
@@ -3701,8 +3751,11 @@ class HAnd : public HBinaryOperation {
class HOr : public HBinaryOperation {
public:
- HOr(Primitive::Type result_type, HInstruction* left, HInstruction* right)
- : HBinaryOperation(result_type, left, right) {}
+ HOr(Primitive::Type result_type,
+ HInstruction* left,
+ HInstruction* right,
+ uint32_t dex_pc = kNoDexPc)
+ : HBinaryOperation(result_type, left, right, SideEffects::None(), dex_pc) {}
bool IsCommutative() const OVERRIDE { return true; }
@@ -3710,16 +3763,20 @@ class HOr : public HBinaryOperation {
auto Compute(T x, U y) const -> decltype(x | y) { return x | y; }
HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const OVERRIDE {
- return GetBlock()->GetGraph()->GetIntConstant(Compute(x->GetValue(), y->GetValue()));
+ return GetBlock()->GetGraph()->GetIntConstant(
+ Compute(x->GetValue(), y->GetValue()), GetDexPc());
}
HConstant* Evaluate(HIntConstant* x, HLongConstant* y) const OVERRIDE {
- return GetBlock()->GetGraph()->GetLongConstant(Compute(x->GetValue(), y->GetValue()));
+ return GetBlock()->GetGraph()->GetLongConstant(
+ Compute(x->GetValue(), y->GetValue()), GetDexPc());
}
HConstant* Evaluate(HLongConstant* x, HIntConstant* y) const OVERRIDE {
- return GetBlock()->GetGraph()->GetLongConstant(Compute(x->GetValue(), y->GetValue()));
+ return GetBlock()->GetGraph()->GetLongConstant(
+ Compute(x->GetValue(), y->GetValue()), GetDexPc());
}
HConstant* Evaluate(HLongConstant* x, HLongConstant* y) const OVERRIDE {
- return GetBlock()->GetGraph()->GetLongConstant(Compute(x->GetValue(), y->GetValue()));
+ return GetBlock()->GetGraph()->GetLongConstant(
+ Compute(x->GetValue(), y->GetValue()), GetDexPc());
}
DECLARE_INSTRUCTION(Or);
@@ -3730,8 +3787,11 @@ class HOr : public HBinaryOperation {
class HXor : public HBinaryOperation {
public:
- HXor(Primitive::Type result_type, HInstruction* left, HInstruction* right)
- : HBinaryOperation(result_type, left, right) {}
+ HXor(Primitive::Type result_type,
+ HInstruction* left,
+ HInstruction* right,
+ uint32_t dex_pc = kNoDexPc)
+ : HBinaryOperation(result_type, left, right, SideEffects::None(), dex_pc) {}
bool IsCommutative() const OVERRIDE { return true; }
@@ -3739,16 +3799,20 @@ class HXor : public HBinaryOperation {
auto Compute(T x, U y) const -> decltype(x ^ y) { return x ^ y; }
HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const OVERRIDE {
- return GetBlock()->GetGraph()->GetIntConstant(Compute(x->GetValue(), y->GetValue()));
+ return GetBlock()->GetGraph()->GetIntConstant(
+ Compute(x->GetValue(), y->GetValue()), GetDexPc());
}
HConstant* Evaluate(HIntConstant* x, HLongConstant* y) const OVERRIDE {
- return GetBlock()->GetGraph()->GetLongConstant(Compute(x->GetValue(), y->GetValue()));
+ return GetBlock()->GetGraph()->GetLongConstant(
+ Compute(x->GetValue(), y->GetValue()), GetDexPc());
}
HConstant* Evaluate(HLongConstant* x, HIntConstant* y) const OVERRIDE {
- return GetBlock()->GetGraph()->GetLongConstant(Compute(x->GetValue(), y->GetValue()));
+ return GetBlock()->GetGraph()->GetLongConstant(
+ Compute(x->GetValue(), y->GetValue()), GetDexPc());
}
HConstant* Evaluate(HLongConstant* x, HLongConstant* y) const OVERRIDE {
- return GetBlock()->GetGraph()->GetLongConstant(Compute(x->GetValue(), y->GetValue()));
+ return GetBlock()->GetGraph()->GetLongConstant(
+ Compute(x->GetValue(), y->GetValue()), GetDexPc());
}
DECLARE_INSTRUCTION(Xor);
@@ -3761,8 +3825,10 @@ class HXor : public HBinaryOperation {
// the calling convention.
class HParameterValue : public HExpression<0> {
public:
- HParameterValue(uint8_t index, Primitive::Type parameter_type, bool is_this = false)
- : HExpression(parameter_type, SideEffects::None()),
+ HParameterValue(uint8_t index,
+ Primitive::Type parameter_type,
+ bool is_this = false)
+ : HExpression(parameter_type, SideEffects::None(), kNoDexPc),
index_(index),
is_this_(is_this),
can_be_null_(!is_this) {}
@@ -3791,8 +3857,8 @@ class HParameterValue : public HExpression<0> {
class HNot : public HUnaryOperation {
public:
- HNot(Primitive::Type result_type, HInstruction* input)
- : HUnaryOperation(result_type, input) {}
+ HNot(Primitive::Type result_type, HInstruction* input, uint32_t dex_pc = kNoDexPc)
+ : HUnaryOperation(result_type, input, dex_pc) {}
bool CanBeMoved() const OVERRIDE { return true; }
bool InstructionDataEquals(HInstruction* other) const OVERRIDE {
@@ -3803,10 +3869,10 @@ class HNot : public HUnaryOperation {
template <typename T> T Compute(T x) const { return ~x; }
HConstant* Evaluate(HIntConstant* x) const OVERRIDE {
- return GetBlock()->GetGraph()->GetIntConstant(Compute(x->GetValue()));
+ return GetBlock()->GetGraph()->GetIntConstant(Compute(x->GetValue()), GetDexPc());
}
HConstant* Evaluate(HLongConstant* x) const OVERRIDE {
- return GetBlock()->GetGraph()->GetLongConstant(Compute(x->GetValue()));
+ return GetBlock()->GetGraph()->GetLongConstant(Compute(x->GetValue()), GetDexPc());
}
DECLARE_INSTRUCTION(Not);
@@ -3817,8 +3883,8 @@ class HNot : public HUnaryOperation {
class HBooleanNot : public HUnaryOperation {
public:
- explicit HBooleanNot(HInstruction* input)
- : HUnaryOperation(Primitive::Type::kPrimBoolean, input) {}
+ explicit HBooleanNot(HInstruction* input, uint32_t dex_pc = kNoDexPc)
+ : HUnaryOperation(Primitive::Type::kPrimBoolean, input, dex_pc) {}
bool CanBeMoved() const OVERRIDE { return true; }
bool InstructionDataEquals(HInstruction* other) const OVERRIDE {
@@ -3832,7 +3898,7 @@ class HBooleanNot : public HUnaryOperation {
}
HConstant* Evaluate(HIntConstant* x) const OVERRIDE {
- return GetBlock()->GetGraph()->GetIntConstant(Compute(x->GetValue()));
+ return GetBlock()->GetGraph()->GetIntConstant(Compute(x->GetValue()), GetDexPc());
}
HConstant* Evaluate(HLongConstant* x ATTRIBUTE_UNUSED) const OVERRIDE {
LOG(FATAL) << DebugName() << " is not defined for long values";
@@ -3849,8 +3915,9 @@ class HTypeConversion : public HExpression<1> {
public:
// Instantiate a type conversion of `input` to `result_type`.
HTypeConversion(Primitive::Type result_type, HInstruction* input, uint32_t dex_pc)
- : HExpression(result_type, SideEffectsForArchRuntimeCalls(input->GetType(), result_type)),
- dex_pc_(dex_pc) {
+ : HExpression(result_type,
+ SideEffectsForArchRuntimeCalls(input->GetType(), result_type),
+ dex_pc) {
SetRawInputAt(0, input);
DCHECK_NE(input->GetType(), result_type);
}
@@ -3861,7 +3928,6 @@ class HTypeConversion : public HExpression<1> {
// Required by the x86 and ARM code generators when producing calls
// to the runtime.
- uint32_t GetDexPc() const OVERRIDE { return dex_pc_; }
bool CanBeMoved() const OVERRIDE { return true; }
bool InstructionDataEquals(HInstruction* other ATTRIBUTE_UNUSED) const OVERRIDE { return true; }
@@ -3885,8 +3951,6 @@ class HTypeConversion : public HExpression<1> {
DECLARE_INSTRUCTION(TypeConversion);
private:
- const uint32_t dex_pc_;
-
DISALLOW_COPY_AND_ASSIGN(HTypeConversion);
};
@@ -3894,8 +3958,12 @@ static constexpr uint32_t kNoRegNumber = -1;
class HPhi : public HInstruction {
public:
- HPhi(ArenaAllocator* arena, uint32_t reg_number, size_t number_of_inputs, Primitive::Type type)
- : HInstruction(SideEffects::None()),
+ HPhi(ArenaAllocator* arena,
+ uint32_t reg_number,
+ size_t number_of_inputs,
+ Primitive::Type type,
+ uint32_t dex_pc = kNoDexPc)
+ : HInstruction(SideEffects::None(), dex_pc),
inputs_(arena, number_of_inputs),
reg_number_(reg_number),
type_(type),
@@ -3973,7 +4041,7 @@ class HPhi : public HInstruction {
class HNullCheck : public HExpression<1> {
public:
HNullCheck(HInstruction* value, uint32_t dex_pc)
- : HExpression(value->GetType(), SideEffects::None()), dex_pc_(dex_pc) {
+ : HExpression(value->GetType(), SideEffects::None(), dex_pc) {
SetRawInputAt(0, value);
}
@@ -3989,13 +4057,10 @@ class HNullCheck : public HExpression<1> {
bool CanBeNull() const OVERRIDE { return false; }
- uint32_t GetDexPc() const OVERRIDE { return dex_pc_; }
DECLARE_INSTRUCTION(NullCheck);
private:
- const uint32_t dex_pc_;
-
DISALLOW_COPY_AND_ASSIGN(HNullCheck);
};
@@ -4038,10 +4103,11 @@ class HInstanceFieldGet : public HExpression<1> {
bool is_volatile,
uint32_t field_idx,
const DexFile& dex_file,
- Handle<mirror::DexCache> dex_cache)
+ Handle<mirror::DexCache> dex_cache,
+ uint32_t dex_pc = kNoDexPc)
: HExpression(
field_type,
- SideEffects::FieldReadOfType(field_type, is_volatile)),
+ SideEffects::FieldReadOfType(field_type, is_volatile), dex_pc),
field_info_(field_offset, field_type, is_volatile, field_idx, dex_file, dex_cache) {
SetRawInputAt(0, value);
}
@@ -4083,9 +4149,10 @@ class HInstanceFieldSet : public HTemplateInstruction<2> {
bool is_volatile,
uint32_t field_idx,
const DexFile& dex_file,
- Handle<mirror::DexCache> dex_cache)
+ Handle<mirror::DexCache> dex_cache,
+ uint32_t dex_pc = kNoDexPc)
: HTemplateInstruction(
- SideEffects::FieldWriteOfType(field_type, is_volatile)),
+ SideEffects::FieldWriteOfType(field_type, is_volatile), dex_pc),
field_info_(field_offset, field_type, is_volatile, field_idx, dex_file, dex_cache),
value_can_be_null_(true) {
SetRawInputAt(0, object);
@@ -4115,8 +4182,11 @@ class HInstanceFieldSet : public HTemplateInstruction<2> {
class HArrayGet : public HExpression<2> {
public:
- HArrayGet(HInstruction* array, HInstruction* index, Primitive::Type type)
- : HExpression(type, SideEffects::ArrayReadOfType(type)) {
+ HArrayGet(HInstruction* array,
+ HInstruction* index,
+ Primitive::Type type,
+ uint32_t dex_pc = kNoDexPc)
+ : HExpression(type, SideEffects::ArrayReadOfType(type), dex_pc) {
SetRawInputAt(0, array);
SetRawInputAt(1, index);
}
@@ -4156,8 +4226,7 @@ class HArraySet : public HTemplateInstruction<3> {
uint32_t dex_pc)
: HTemplateInstruction(
SideEffects::ArrayWriteOfType(expected_component_type).Union(
- SideEffectsForArchRuntimeCalls(value->GetType()))),
- dex_pc_(dex_pc),
+ SideEffectsForArchRuntimeCalls(value->GetType())), dex_pc),
expected_component_type_(expected_component_type),
needs_type_check_(value->GetType() == Primitive::kPrimNot),
value_can_be_null_(true) {
@@ -4192,8 +4261,6 @@ class HArraySet : public HTemplateInstruction<3> {
bool GetValueCanBeNull() const { return value_can_be_null_; }
bool NeedsTypeCheck() const { return needs_type_check_; }
- uint32_t GetDexPc() const OVERRIDE { return dex_pc_; }
-
HInstruction* GetArray() const { return InputAt(0); }
HInstruction* GetIndex() const { return InputAt(1); }
HInstruction* GetValue() const { return InputAt(2); }
@@ -4216,7 +4283,6 @@ class HArraySet : public HTemplateInstruction<3> {
DECLARE_INSTRUCTION(ArraySet);
private:
- const uint32_t dex_pc_;
const Primitive::Type expected_component_type_;
bool needs_type_check_;
bool value_can_be_null_;
@@ -4226,8 +4292,8 @@ class HArraySet : public HTemplateInstruction<3> {
class HArrayLength : public HExpression<1> {
public:
- explicit HArrayLength(HInstruction* array)
- : HExpression(Primitive::kPrimInt, SideEffects::None()) {
+ explicit HArrayLength(HInstruction* array, uint32_t dex_pc = kNoDexPc)
+ : HExpression(Primitive::kPrimInt, SideEffects::None(), dex_pc) {
// Note that arrays do not change length, so the instruction does not
// depend on any write.
SetRawInputAt(0, array);
@@ -4251,7 +4317,7 @@ class HArrayLength : public HExpression<1> {
class HBoundsCheck : public HExpression<2> {
public:
HBoundsCheck(HInstruction* index, HInstruction* length, uint32_t dex_pc)
- : HExpression(index->GetType(), SideEffects::None()), dex_pc_(dex_pc) {
+ : HExpression(index->GetType(), SideEffects::None(), dex_pc) {
DCHECK(index->GetType() == Primitive::kPrimInt);
SetRawInputAt(0, index);
SetRawInputAt(1, length);
@@ -4267,13 +4333,10 @@ class HBoundsCheck : public HExpression<2> {
bool CanThrow() const OVERRIDE { return true; }
- uint32_t GetDexPc() const OVERRIDE { return dex_pc_; }
DECLARE_INSTRUCTION(BoundsCheck);
private:
- const uint32_t dex_pc_;
-
DISALLOW_COPY_AND_ASSIGN(HBoundsCheck);
};
@@ -4286,7 +4349,8 @@ class HBoundsCheck : public HExpression<2> {
*/
class HTemporary : public HTemplateInstruction<0> {
public:
- explicit HTemporary(size_t index) : HTemplateInstruction(SideEffects::None()), index_(index) {}
+ explicit HTemporary(size_t index, uint32_t dex_pc = kNoDexPc)
+ : HTemplateInstruction(SideEffects::None(), dex_pc), index_(index) {}
size_t GetIndex() const { return index_; }
@@ -4300,28 +4364,24 @@ class HTemporary : public HTemplateInstruction<0> {
private:
const size_t index_;
-
DISALLOW_COPY_AND_ASSIGN(HTemporary);
};
class HSuspendCheck : public HTemplateInstruction<0> {
public:
explicit HSuspendCheck(uint32_t dex_pc)
- : HTemplateInstruction(SideEffects::CanTriggerGC()), dex_pc_(dex_pc), slow_path_(nullptr) {}
+ : HTemplateInstruction(SideEffects::CanTriggerGC(), dex_pc), slow_path_(nullptr) {}
bool NeedsEnvironment() const OVERRIDE {
return true;
}
- uint32_t GetDexPc() const OVERRIDE { return dex_pc_; }
void SetSlowPath(SlowPathCode* slow_path) { slow_path_ = slow_path; }
SlowPathCode* GetSlowPath() const { return slow_path_; }
DECLARE_INSTRUCTION(SuspendCheck);
private:
- const uint32_t dex_pc_;
-
// Only used for code generation, in order to share the same slow path between back edges
// of a same loop.
SlowPathCode* slow_path_;
@@ -4339,11 +4399,10 @@ class HLoadClass : public HExpression<1> {
const DexFile& dex_file,
bool is_referrers_class,
uint32_t dex_pc)
- : HExpression(Primitive::kPrimNot, SideEffectsForArchRuntimeCalls()),
+ : HExpression(Primitive::kPrimNot, SideEffectsForArchRuntimeCalls(), dex_pc),
type_index_(type_index),
dex_file_(dex_file),
is_referrers_class_(is_referrers_class),
- dex_pc_(dex_pc),
generate_clinit_check_(false),
loaded_class_rti_(ReferenceTypeInfo::CreateInvalid()) {
SetRawInputAt(0, current_method);
@@ -4357,7 +4416,6 @@ class HLoadClass : public HExpression<1> {
size_t ComputeHashCode() const OVERRIDE { return type_index_; }
- uint32_t GetDexPc() const OVERRIDE { return dex_pc_; }
uint16_t GetTypeIndex() const { return type_index_; }
bool IsReferrersClass() const { return is_referrers_class_; }
bool CanBeNull() const OVERRIDE { return false; }
@@ -4410,7 +4468,6 @@ class HLoadClass : public HExpression<1> {
const uint16_t type_index_;
const DexFile& dex_file_;
const bool is_referrers_class_;
- const uint32_t dex_pc_;
// Whether this instruction must generate the initialization check.
// Used for code generation.
bool generate_clinit_check_;
@@ -4423,9 +4480,8 @@ class HLoadClass : public HExpression<1> {
class HLoadString : public HExpression<1> {
public:
HLoadString(HCurrentMethod* current_method, uint32_t string_index, uint32_t dex_pc)
- : HExpression(Primitive::kPrimNot, SideEffectsForArchRuntimeCalls()),
- string_index_(string_index),
- dex_pc_(dex_pc) {
+ : HExpression(Primitive::kPrimNot, SideEffectsForArchRuntimeCalls(), dex_pc),
+ string_index_(string_index) {
SetRawInputAt(0, current_method);
}
@@ -4437,7 +4493,6 @@ class HLoadString : public HExpression<1> {
size_t ComputeHashCode() const OVERRIDE { return string_index_; }
- uint32_t GetDexPc() const OVERRIDE { return dex_pc_; }
uint32_t GetStringIndex() const { return string_index_; }
// TODO: Can we deopt or debug when we resolve a string?
@@ -4453,7 +4508,6 @@ class HLoadString : public HExpression<1> {
private:
const uint32_t string_index_;
- const uint32_t dex_pc_;
DISALLOW_COPY_AND_ASSIGN(HLoadString);
};
@@ -4466,8 +4520,8 @@ class HClinitCheck : public HExpression<1> {
HClinitCheck(HLoadClass* constant, uint32_t dex_pc)
: HExpression(
Primitive::kPrimNot,
- SideEffects::AllChanges()), // Assume write/read on all fields/arrays.
- dex_pc_(dex_pc) {
+ SideEffects::AllChanges(), // Assume write/read on all fields/arrays.
+ dex_pc) {
SetRawInputAt(0, constant);
}
@@ -4482,15 +4536,12 @@ class HClinitCheck : public HExpression<1> {
return true;
}
- uint32_t GetDexPc() const OVERRIDE { return dex_pc_; }
HLoadClass* GetLoadClass() const { return InputAt(0)->AsLoadClass(); }
DECLARE_INSTRUCTION(ClinitCheck);
private:
- const uint32_t dex_pc_;
-
DISALLOW_COPY_AND_ASSIGN(HClinitCheck);
};
@@ -4502,10 +4553,11 @@ class HStaticFieldGet : public HExpression<1> {
bool is_volatile,
uint32_t field_idx,
const DexFile& dex_file,
- Handle<mirror::DexCache> dex_cache)
+ Handle<mirror::DexCache> dex_cache,
+ uint32_t dex_pc = kNoDexPc)
: HExpression(
field_type,
- SideEffects::FieldReadOfType(field_type, is_volatile)),
+ SideEffects::FieldReadOfType(field_type, is_volatile), dex_pc),
field_info_(field_offset, field_type, is_volatile, field_idx, dex_file, dex_cache) {
SetRawInputAt(0, cls);
}
@@ -4544,9 +4596,10 @@ class HStaticFieldSet : public HTemplateInstruction<2> {
bool is_volatile,
uint32_t field_idx,
const DexFile& dex_file,
- Handle<mirror::DexCache> dex_cache)
+ Handle<mirror::DexCache> dex_cache,
+ uint32_t dex_pc = kNoDexPc)
: HTemplateInstruction(
- SideEffects::FieldWriteOfType(field_type, is_volatile)),
+ SideEffects::FieldWriteOfType(field_type, is_volatile), dex_pc),
field_info_(field_offset, field_type, is_volatile, field_idx, dex_file, dex_cache),
value_can_be_null_(true) {
SetRawInputAt(0, cls);
@@ -4574,7 +4627,8 @@ class HStaticFieldSet : public HTemplateInstruction<2> {
// Implement the move-exception DEX instruction.
class HLoadException : public HExpression<0> {
public:
- HLoadException() : HExpression(Primitive::kPrimNot, SideEffects::None()) {}
+ explicit HLoadException(uint32_t dex_pc = kNoDexPc)
+ : HExpression(Primitive::kPrimNot, SideEffects::None(), dex_pc) {}
bool CanBeNull() const OVERRIDE { return false; }
@@ -4588,7 +4642,8 @@ class HLoadException : public HExpression<0> {
// Must not be removed because the runtime expects the TLS to get cleared.
class HClearException : public HTemplateInstruction<0> {
public:
- HClearException() : HTemplateInstruction(SideEffects::AllWrites()) {}
+ explicit HClearException(uint32_t dex_pc = kNoDexPc)
+ : HTemplateInstruction(SideEffects::AllWrites(), dex_pc) {}
DECLARE_INSTRUCTION(ClearException);
@@ -4599,7 +4654,7 @@ class HClearException : public HTemplateInstruction<0> {
class HThrow : public HTemplateInstruction<1> {
public:
HThrow(HInstruction* exception, uint32_t dex_pc)
- : HTemplateInstruction(SideEffects::CanTriggerGC()), dex_pc_(dex_pc) {
+ : HTemplateInstruction(SideEffects::CanTriggerGC(), dex_pc) {
SetRawInputAt(0, exception);
}
@@ -4609,13 +4664,10 @@ class HThrow : public HTemplateInstruction<1> {
bool CanThrow() const OVERRIDE { return true; }
- uint32_t GetDexPc() const OVERRIDE { return dex_pc_; }
DECLARE_INSTRUCTION(Throw);
private:
- const uint32_t dex_pc_;
-
DISALLOW_COPY_AND_ASSIGN(HThrow);
};
@@ -4625,10 +4677,11 @@ class HInstanceOf : public HExpression<2> {
HLoadClass* constant,
bool class_is_final,
uint32_t dex_pc)
- : HExpression(Primitive::kPrimBoolean, SideEffectsForArchRuntimeCalls(class_is_final)),
+ : HExpression(Primitive::kPrimBoolean,
+ SideEffectsForArchRuntimeCalls(class_is_final),
+ dex_pc),
class_is_final_(class_is_final),
- must_do_null_check_(true),
- dex_pc_(dex_pc) {
+ must_do_null_check_(true) {
SetRawInputAt(0, object);
SetRawInputAt(1, constant);
}
@@ -4643,8 +4696,6 @@ class HInstanceOf : public HExpression<2> {
return false;
}
- uint32_t GetDexPc() const OVERRIDE { return dex_pc_; }
-
bool IsClassFinal() const { return class_is_final_; }
// Used only in code generation.
@@ -4660,7 +4711,6 @@ class HInstanceOf : public HExpression<2> {
private:
const bool class_is_final_;
bool must_do_null_check_;
- const uint32_t dex_pc_;
DISALLOW_COPY_AND_ASSIGN(HInstanceOf);
};
@@ -4669,8 +4719,11 @@ class HBoundType : public HExpression<1> {
public:
// Constructs an HBoundType with the given upper_bound.
// Ensures that the upper_bound is valid.
- HBoundType(HInstruction* input, ReferenceTypeInfo upper_bound, bool upper_can_be_null)
- : HExpression(Primitive::kPrimNot, SideEffects::None()),
+ HBoundType(HInstruction* input,
+ ReferenceTypeInfo upper_bound,
+ bool upper_can_be_null,
+ uint32_t dex_pc = kNoDexPc)
+ : HExpression(Primitive::kPrimNot, SideEffects::None(), dex_pc),
upper_bound_(upper_bound),
upper_can_be_null_(upper_can_be_null),
can_be_null_(upper_can_be_null) {
@@ -4714,10 +4767,9 @@ class HCheckCast : public HTemplateInstruction<2> {
HLoadClass* constant,
bool class_is_final,
uint32_t dex_pc)
- : HTemplateInstruction(SideEffects::CanTriggerGC()),
+ : HTemplateInstruction(SideEffects::CanTriggerGC(), dex_pc),
class_is_final_(class_is_final),
- must_do_null_check_(true),
- dex_pc_(dex_pc) {
+ must_do_null_check_(true) {
SetRawInputAt(0, object);
SetRawInputAt(1, constant);
}
@@ -4738,7 +4790,6 @@ class HCheckCast : public HTemplateInstruction<2> {
bool MustDoNullCheck() const { return must_do_null_check_; }
void ClearMustDoNullCheck() { must_do_null_check_ = false; }
- uint32_t GetDexPc() const OVERRIDE { return dex_pc_; }
bool IsClassFinal() const { return class_is_final_; }
@@ -4747,16 +4798,15 @@ class HCheckCast : public HTemplateInstruction<2> {
private:
const bool class_is_final_;
bool must_do_null_check_;
- const uint32_t dex_pc_;
DISALLOW_COPY_AND_ASSIGN(HCheckCast);
};
class HMemoryBarrier : public HTemplateInstruction<0> {
public:
- explicit HMemoryBarrier(MemBarrierKind barrier_kind)
+ explicit HMemoryBarrier(MemBarrierKind barrier_kind, uint32_t dex_pc = kNoDexPc)
: HTemplateInstruction(
- SideEffects::AllWritesAndReads()), // Assume write/read on all fields/arrays.
+ SideEffects::AllWritesAndReads(), dex_pc), // Assume write/read on all fields/arrays.
barrier_kind_(barrier_kind) {}
MemBarrierKind GetBarrierKind() { return barrier_kind_; }
@@ -4778,8 +4828,8 @@ class HMonitorOperation : public HTemplateInstruction<1> {
HMonitorOperation(HInstruction* object, OperationKind kind, uint32_t dex_pc)
: HTemplateInstruction(
- SideEffects::AllExceptGCDependency()), // Assume write/read on all fields/arrays.
- kind_(kind), dex_pc_(dex_pc) {
+ SideEffects::AllExceptGCDependency(), dex_pc), // Assume write/read on all fields/arrays.
+ kind_(kind) {
SetRawInputAt(0, object);
}
@@ -4793,7 +4843,6 @@ class HMonitorOperation : public HTemplateInstruction<1> {
return IsEnter();
}
- uint32_t GetDexPc() const OVERRIDE { return dex_pc_; }
bool IsEnter() const { return kind_ == kEnter; }
@@ -4801,7 +4850,6 @@ class HMonitorOperation : public HTemplateInstruction<1> {
private:
const OperationKind kind_;
- const uint32_t dex_pc_;
private:
DISALLOW_COPY_AND_ASSIGN(HMonitorOperation);
@@ -4816,7 +4864,8 @@ class HMonitorOperation : public HTemplateInstruction<1> {
*/
class HFakeString : public HTemplateInstruction<0> {
public:
- HFakeString() : HTemplateInstruction(SideEffects::None()) {}
+ explicit HFakeString(uint32_t dex_pc = kNoDexPc)
+ : HTemplateInstruction(SideEffects::None(), dex_pc) {}
Primitive::Type GetType() const OVERRIDE { return Primitive::kPrimNot; }
@@ -4904,8 +4953,8 @@ static constexpr size_t kDefaultNumberOfMoves = 4;
class HParallelMove : public HTemplateInstruction<0> {
public:
- explicit HParallelMove(ArenaAllocator* arena)
- : HTemplateInstruction(SideEffects::None()), moves_(arena, kDefaultNumberOfMoves) {}
+ explicit HParallelMove(ArenaAllocator* arena, uint32_t dex_pc = kNoDexPc)
+ : HTemplateInstruction(SideEffects::None(), dex_pc), moves_(arena, kDefaultNumberOfMoves) {}
void AddMove(Location source,
Location destination,
@@ -4955,6 +5004,14 @@ class HParallelMove : public HTemplateInstruction<0> {
DISALLOW_COPY_AND_ASSIGN(HParallelMove);
};
+} // namespace art
+
+#ifdef ART_ENABLE_CODEGEN_x86
+#include "nodes_x86.h"
+#endif
+
+namespace art {
+
class HGraphVisitor : public ValueObject {
public:
explicit HGraphVisitor(HGraph* graph) : graph_(graph) {}
diff --git a/compiler/optimizing/nodes_x86.h b/compiler/optimizing/nodes_x86.h
new file mode 100644
index 0000000000..ddc5730215
--- /dev/null
+++ b/compiler/optimizing/nodes_x86.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_COMPILER_OPTIMIZING_NODES_X86_H_
+#define ART_COMPILER_OPTIMIZING_NODES_X86_H_
+
+namespace art {
+
+// Compute the address of the method for X86 Constant area support.
+class HX86ComputeBaseMethodAddress : public HExpression<0> {
+ public:
+ // Treat the value as an int32_t, but it is really a 32 bit native pointer.
+ HX86ComputeBaseMethodAddress() : HExpression(Primitive::kPrimInt, SideEffects::None()) {}
+
+ DECLARE_INSTRUCTION(X86ComputeBaseMethodAddress);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(HX86ComputeBaseMethodAddress);
+};
+
+// Load a constant value from the constant table.
+class HX86LoadFromConstantTable : public HExpression<2> {
+ public:
+ HX86LoadFromConstantTable(HX86ComputeBaseMethodAddress* method_base,
+ HConstant* constant,
+ bool needs_materialization = true)
+ : HExpression(constant->GetType(), SideEffects::None()),
+ needs_materialization_(needs_materialization) {
+ SetRawInputAt(0, method_base);
+ SetRawInputAt(1, constant);
+ }
+
+ bool NeedsMaterialization() const { return needs_materialization_; }
+
+ HX86ComputeBaseMethodAddress* GetBaseMethodAddress() const {
+ return InputAt(0)->AsX86ComputeBaseMethodAddress();
+ }
+
+ HConstant* GetConstant() const {
+ return InputAt(1)->AsConstant();
+ }
+
+ DECLARE_INSTRUCTION(X86LoadFromConstantTable);
+
+ private:
+ const bool needs_materialization_;
+
+ DISALLOW_COPY_AND_ASSIGN(HX86LoadFromConstantTable);
+};
+
+} // namespace art
+
+#endif // ART_COMPILER_OPTIMIZING_NODES_X86_H_
diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc
index 91b03d4bd1..f549ba8391 100644
--- a/compiler/optimizing/optimizing_compiler.cc
+++ b/compiler/optimizing/optimizing_compiler.cc
@@ -23,6 +23,10 @@
#include "instruction_simplifier_arm64.h"
#endif
+#ifdef ART_ENABLE_CODEGEN_x86
+#include "constant_area_fixups_x86.h"
+#endif
+
#include "art_method-inl.h"
#include "base/arena_allocator.h"
#include "base/arena_containers.h"
@@ -424,6 +428,17 @@ static void RunArchOptimizations(InstructionSet instruction_set,
break;
}
#endif
+#ifdef ART_ENABLE_CODEGEN_x86
+ case kX86: {
+ x86::ConstantAreaFixups* constant_area_fixups =
+ new (arena) x86::ConstantAreaFixups(graph, stats);
+ HOptimization* x86_optimizations[] = {
+ constant_area_fixups
+ };
+ RunOptimizations(x86_optimizations, arraysize(x86_optimizations), pass_observer);
+ break;
+ }
+#endif
default:
break;
}