Merge "Be a bit smarter with JIT code triggering deoptimization."
diff --git a/compiler/Android.mk b/compiler/Android.mk
index b164942..159e9cf 100644
--- a/compiler/Android.mk
+++ b/compiler/Android.mk
@@ -90,7 +90,6 @@
optimizing/optimization.cc \
optimizing/optimizing_compiler.cc \
optimizing/parallel_move_resolver.cc \
- optimizing/pc_relative_fixups_x86.cc \
optimizing/prepare_for_register_allocation.cc \
optimizing/reference_type_propagation.cc \
optimizing/register_allocator.cc \
@@ -182,6 +181,7 @@
linker/x86/relative_patcher_x86_base.cc \
optimizing/code_generator_x86.cc \
optimizing/intrinsics_x86.cc \
+ optimizing/pc_relative_fixups_x86.cc \
utils/x86/assembler_x86.cc \
utils/x86/managed_register_x86.cc \
diff --git a/compiler/driver/compiled_method_storage.cc b/compiler/driver/compiled_method_storage.cc
index bc5c6ca..510613e 100644
--- a/compiler/driver/compiled_method_storage.cc
+++ b/compiler/driver/compiled_method_storage.cc
@@ -190,7 +190,8 @@
void CompiledMethodStorage::DumpMemoryUsage(std::ostream& os, bool extended) const {
if (swap_space_.get() != nullptr) {
- os << " swap=" << PrettySize(swap_space_->GetSize());
+ const size_t swap_size = swap_space_->GetSize();
+ os << " swap=" << PrettySize(swap_size) << " (" << swap_size << "B)";
}
if (extended) {
Thread* self = Thread::Current();
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index f078bf6..670fe94 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -2732,16 +2732,18 @@
std::string CompilerDriver::GetMemoryUsageString(bool extended) const {
std::ostringstream oss;
Runtime* const runtime = Runtime::Current();
- const ArenaPool* arena_pool = runtime->GetArenaPool();
- gc::Heap* const heap = runtime->GetHeap();
- oss << "arena alloc=" << PrettySize(arena_pool->GetBytesAllocated());
- oss << " java alloc=" << PrettySize(heap->GetBytesAllocated());
+ const ArenaPool* const arena_pool = runtime->GetArenaPool();
+ const gc::Heap* const heap = runtime->GetHeap();
+ const size_t arena_alloc = arena_pool->GetBytesAllocated();
+ const size_t java_alloc = heap->GetBytesAllocated();
+ oss << "arena alloc=" << PrettySize(arena_alloc) << " (" << arena_alloc << "B)";
+ oss << " java alloc=" << PrettySize(java_alloc) << " (" << java_alloc << "B)";
#if defined(__BIONIC__) || defined(__GLIBC__)
- struct mallinfo info = mallinfo();
+ const struct mallinfo info = mallinfo();
const size_t allocated_space = static_cast<size_t>(info.uordblks);
const size_t free_space = static_cast<size_t>(info.fordblks);
- oss << " native alloc=" << PrettySize(allocated_space) << " free="
- << PrettySize(free_space);
+ oss << " native alloc=" << PrettySize(allocated_space) << " (" << allocated_space << "B)"
+ << " free=" << PrettySize(free_space) << " (" << free_space << "B)";
#endif
compiled_method_storage_.DumpMemoryUsage(oss, extended);
return oss.str();
diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc
index 3c880c2..f032f51 100644
--- a/compiler/optimizing/code_generator_x86.cc
+++ b/compiler/optimizing/code_generator_x86.cc
@@ -26,7 +26,6 @@
#include "intrinsics_x86.h"
#include "mirror/array-inl.h"
#include "mirror/class-inl.h"
-#include "pc_relative_fixups_x86.h"
#include "thread.h"
#include "utils/assembler.h"
#include "utils/stack_checks.h"
@@ -1518,30 +1517,131 @@
/* false_target */ nullptr);
}
+static bool SelectCanUseCMOV(HSelect* select) {
+ // There are no conditional move instructions for XMMs.
+ if (Primitive::IsFloatingPointType(select->GetType())) {
+ return false;
+ }
+
+ // A FP condition doesn't generate the single CC that we need.
+ // In 32 bit mode, a long condition doesn't generate a single CC either.
+ HInstruction* condition = select->GetCondition();
+ if (condition->IsCondition()) {
+ Primitive::Type compare_type = condition->InputAt(0)->GetType();
+ if (compare_type == Primitive::kPrimLong ||
+ Primitive::IsFloatingPointType(compare_type)) {
+ return false;
+ }
+ }
+
+ // We can generate a CMOV for this Select.
+ return true;
+}
+
void LocationsBuilderX86::VisitSelect(HSelect* select) {
LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(select);
- Primitive::Type select_type = select->GetType();
- HInstruction* cond = select->GetCondition();
-
- if (Primitive::IsFloatingPointType(select_type)) {
+ if (Primitive::IsFloatingPointType(select->GetType())) {
locations->SetInAt(0, Location::RequiresFpuRegister());
+ locations->SetInAt(1, Location::Any());
} else {
locations->SetInAt(0, Location::RequiresRegister());
+ if (SelectCanUseCMOV(select)) {
+ if (select->InputAt(1)->IsConstant()) {
+ // Cmov can't handle a constant value.
+ locations->SetInAt(1, Location::RequiresRegister());
+ } else {
+ locations->SetInAt(1, Location::Any());
+ }
+ } else {
+ locations->SetInAt(1, Location::Any());
+ }
}
- locations->SetInAt(1, Location::Any());
- if (IsBooleanValueOrMaterializedCondition(cond)) {
- locations->SetInAt(2, Location::Any());
+ if (IsBooleanValueOrMaterializedCondition(select->GetCondition())) {
+ locations->SetInAt(2, Location::RequiresRegister());
}
locations->SetOut(Location::SameAsFirstInput());
}
+void InstructionCodeGeneratorX86::GenerateIntCompare(Location lhs, Location rhs) {
+ Register lhs_reg = lhs.AsRegister<Register>();
+ if (rhs.IsConstant()) {
+ int32_t value = CodeGenerator::GetInt32ValueOf(rhs.GetConstant());
+ codegen_->Compare32BitValue(lhs_reg, value);
+ } else if (rhs.IsStackSlot()) {
+ __ cmpl(lhs_reg, Address(ESP, rhs.GetStackIndex()));
+ } else {
+ __ cmpl(lhs_reg, rhs.AsRegister<Register>());
+ }
+}
+
void InstructionCodeGeneratorX86::VisitSelect(HSelect* select) {
LocationSummary* locations = select->GetLocations();
- NearLabel false_target;
- GenerateTestAndBranch<NearLabel>(
- select, /* condition_input_index */ 2, /* true_target */ nullptr, &false_target);
- codegen_->MoveLocation(locations->Out(), locations->InAt(1), select->GetType());
- __ Bind(&false_target);
+ DCHECK(locations->InAt(0).Equals(locations->Out()));
+ if (SelectCanUseCMOV(select)) {
+ // If both the condition and the source types are integer, we can generate
+ // a CMOV to implement Select.
+
+ HInstruction* select_condition = select->GetCondition();
+ Condition cond = kNotEqual;
+
+ // Figure out how to test the 'condition'.
+ if (select_condition->IsCondition()) {
+ HCondition* condition = select_condition->AsCondition();
+ if (!condition->IsEmittedAtUseSite()) {
+ // This was a previously materialized condition.
+ // Can we use the existing condition code?
+ if (AreEflagsSetFrom(condition, select)) {
+ // Materialization was the previous instruction. Condition codes are right.
+ cond = X86Condition(condition->GetCondition());
+ } else {
+ // No, we have to recreate the condition code.
+ Register cond_reg = locations->InAt(2).AsRegister<Register>();
+ __ testl(cond_reg, cond_reg);
+ }
+ } else {
+ // We can't handle FP or long here.
+ DCHECK_NE(condition->InputAt(0)->GetType(), Primitive::kPrimLong);
+ DCHECK(!Primitive::IsFloatingPointType(condition->InputAt(0)->GetType()));
+ LocationSummary* cond_locations = condition->GetLocations();
+ GenerateIntCompare(cond_locations->InAt(0), cond_locations->InAt(1));
+ cond = X86Condition(condition->GetCondition());
+ }
+ } else {
+ // Must be a boolean condition, which needs to be compared to 0.
+ Register cond_reg = locations->InAt(2).AsRegister<Register>();
+ __ testl(cond_reg, cond_reg);
+ }
+
+ // If the condition is true, overwrite the output, which already contains false.
+ Location false_loc = locations->InAt(0);
+ Location true_loc = locations->InAt(1);
+ if (select->GetType() == Primitive::kPrimLong) {
+ // 64 bit conditional move.
+ Register false_high = false_loc.AsRegisterPairHigh<Register>();
+ Register false_low = false_loc.AsRegisterPairLow<Register>();
+ if (true_loc.IsRegisterPair()) {
+ __ cmovl(cond, false_high, true_loc.AsRegisterPairHigh<Register>());
+ __ cmovl(cond, false_low, true_loc.AsRegisterPairLow<Register>());
+ } else {
+ __ cmovl(cond, false_high, Address(ESP, true_loc.GetHighStackIndex(kX86WordSize)));
+ __ cmovl(cond, false_low, Address(ESP, true_loc.GetStackIndex()));
+ }
+ } else {
+ // 32 bit conditional move.
+ Register false_reg = false_loc.AsRegister<Register>();
+ if (true_loc.IsRegister()) {
+ __ cmovl(cond, false_reg, true_loc.AsRegister<Register>());
+ } else {
+ __ cmovl(cond, false_reg, Address(ESP, true_loc.GetStackIndex()));
+ }
+ }
+ } else {
+ NearLabel false_target;
+ GenerateTestAndBranch<NearLabel>(
+ select, /* condition_input_index */ 2, /* true_target */ nullptr, &false_target);
+ codegen_->MoveLocation(locations->Out(), locations->InAt(1), select->GetType());
+ __ Bind(&false_target);
+ }
}
void LocationsBuilderX86::VisitNativeDebugInfo(HNativeDebugInfo* info) {
@@ -1655,15 +1755,7 @@
// Clear output register: setb only sets the low byte.
__ xorl(reg, reg);
-
- if (rhs.IsRegister()) {
- __ cmpl(lhs.AsRegister<Register>(), rhs.AsRegister<Register>());
- } else if (rhs.IsConstant()) {
- int32_t constant = CodeGenerator::GetInt32ValueOf(rhs.GetConstant());
- codegen_->Compare32BitValue(lhs.AsRegister<Register>(), constant);
- } else {
- __ cmpl(lhs.AsRegister<Register>(), Address(ESP, rhs.GetStackIndex()));
- }
+ GenerateIntCompare(lhs, rhs);
__ setb(X86Condition(cond->GetCondition()), reg);
return;
}
@@ -4141,15 +4233,7 @@
switch (compare->InputAt(0)->GetType()) {
case Primitive::kPrimInt: {
- Register left_reg = left.AsRegister<Register>();
- if (right.IsConstant()) {
- int32_t value = right.GetConstant()->AsIntConstant()->GetValue();
- codegen_->Compare32BitValue(left_reg, value);
- } else if (right.IsStackSlot()) {
- __ cmpl(left_reg, Address(ESP, right.GetStackIndex()));
- } else {
- __ cmpl(left_reg, right.AsRegister<Register>());
- }
+ GenerateIntCompare(left, right);
break;
}
case Primitive::kPrimLong: {
diff --git a/compiler/optimizing/code_generator_x86.h b/compiler/optimizing/code_generator_x86.h
index 2fb6d60..63e9b2f 100644
--- a/compiler/optimizing/code_generator_x86.h
+++ b/compiler/optimizing/code_generator_x86.h
@@ -297,6 +297,7 @@
HBasicBlock* default_block);
void GenerateFPCompare(Location lhs, Location rhs, HInstruction* insn, bool is_double);
+ void GenerateIntCompare(Location lhs, Location rhs);
X86Assembler* const assembler_;
CodeGeneratorX86* const codegen_;
diff --git a/compiler/optimizing/prepare_for_register_allocation.cc b/compiler/optimizing/prepare_for_register_allocation.cc
index 324d84f..0ad104e 100644
--- a/compiler/optimizing/prepare_for_register_allocation.cc
+++ b/compiler/optimizing/prepare_for_register_allocation.cc
@@ -138,15 +138,7 @@
}
if (user->IsSelect() && user->AsSelect()->GetCondition() == condition) {
- if (GetGraph()->GetInstructionSet() == kX86) {
- // Long values and long condition inputs result in 8 required core registers.
- // We don't have that many on x86. Materialize the condition in such case.
- return user->GetType() != Primitive::kPrimLong ||
- condition->InputAt(1)->GetType() != Primitive::kPrimLong ||
- condition->InputAt(1)->IsConstant();
- } else {
- return true;
- }
+ return true;
}
return false;
diff --git a/runtime/jit/jit_code_cache.cc b/runtime/jit/jit_code_cache.cc
index 9e4dddf..74ff741 100644
--- a/runtime/jit/jit_code_cache.cc
+++ b/runtime/jit/jit_code_cache.cc
@@ -269,6 +269,14 @@
}
}
}
+ for (auto it = osr_code_map_.begin(); it != osr_code_map_.end();) {
+ if (alloc.ContainsUnsafe(it->first)) {
+ // Note that the code has already been removed in the loop above.
+ it = osr_code_map_.erase(it);
+ } else {
+ ++it;
+ }
+ }
for (auto it = profiling_infos_.begin(); it != profiling_infos_.end();) {
ProfilingInfo* info = *it;
if (alloc.ContainsUnsafe(info->GetMethod())) {
diff --git a/test/566-checker-codegen-select/src/Main.java b/test/566-checker-codegen-select/src/Main.java
index 3a1b3fc..e215ab0 100644
--- a/test/566-checker-codegen-select/src/Main.java
+++ b/test/566-checker-codegen-select/src/Main.java
@@ -20,13 +20,6 @@
/// CHECK: <<Cond:z\d+>> LessThanOrEqual [{{j\d+}},{{j\d+}}]
/// CHECK-NEXT: Select [{{j\d+}},{{j\d+}},<<Cond>>]
- // Condition must be materialized on X86 because it would need too many
- // registers otherwise.
- /// CHECK-START-X86: long Main.$noinline$longSelect(long) disassembly (after)
- /// CHECK: LessThanOrEqual
- /// CHECK-NEXT: cmp
- /// CHECK: Select
-
public long $noinline$longSelect(long param) {
if (doThrow) { throw new Error(); }
long val_true = longB;
diff --git a/test/570-checker-select/src/Main.java b/test/570-checker-select/src/Main.java
index 8a4cf60..59741d6 100644
--- a/test/570-checker-select/src/Main.java
+++ b/test/570-checker-select/src/Main.java
@@ -29,6 +29,11 @@
/// CHECK: Select [{{i\d+}},{{i\d+}},<<Cond>>]
/// CHECK: cmovnz/ne
+ /// CHECK-START-X86: int Main.BoolCond_IntVarVar(boolean, int, int) disassembly (after)
+ /// CHECK: <<Cond:z\d+>> ParameterValue
+ /// CHECK: Select [{{i\d+}},{{i\d+}},<<Cond>>]
+ /// CHECK: cmovnz/ne
+
public static int BoolCond_IntVarVar(boolean cond, int x, int y) {
return cond ? x : y;
}
@@ -46,6 +51,11 @@
/// CHECK: Select [{{i\d+}},{{i\d+}},<<Cond>>]
/// CHECK: cmovnz/ne
+ /// CHECK-START-X86: int Main.BoolCond_IntVarCst(boolean, int) disassembly (after)
+ /// CHECK: <<Cond:z\d+>> ParameterValue
+ /// CHECK: Select [{{i\d+}},{{i\d+}},<<Cond>>]
+ /// CHECK: cmovnz/ne
+
public static int BoolCond_IntVarCst(boolean cond, int x) {
return cond ? x : 1;
}
@@ -63,6 +73,11 @@
/// CHECK: Select [{{i\d+}},{{i\d+}},<<Cond>>]
/// CHECK: cmovnz/ne
+ /// CHECK-START-X86: int Main.BoolCond_IntCstVar(boolean, int) disassembly (after)
+ /// CHECK: <<Cond:z\d+>> ParameterValue
+ /// CHECK: Select [{{i\d+}},{{i\d+}},<<Cond>>]
+ /// CHECK: cmovnz/ne
+
public static int BoolCond_IntCstVar(boolean cond, int y) {
return cond ? 1 : y;
}
@@ -80,6 +95,12 @@
/// CHECK: Select [{{j\d+}},{{j\d+}},<<Cond>>]
/// CHECK: cmovnz/neq
+ /// CHECK-START-X86: long Main.BoolCond_LongVarVar(boolean, long, long) disassembly (after)
+ /// CHECK: <<Cond:z\d+>> ParameterValue
+ /// CHECK: Select [{{j\d+}},{{j\d+}},<<Cond>>]
+ /// CHECK: cmovnz/ne
+ /// CHECK-NEXT: cmovnz/ne
+
public static long BoolCond_LongVarVar(boolean cond, long x, long y) {
return cond ? x : y;
}
@@ -97,6 +118,12 @@
/// CHECK: Select [{{j\d+}},{{j\d+}},<<Cond>>]
/// CHECK: cmovnz/neq
+ /// CHECK-START-X86: long Main.BoolCond_LongVarCst(boolean, long) disassembly (after)
+ /// CHECK: <<Cond:z\d+>> ParameterValue
+ /// CHECK: Select [{{j\d+}},{{j\d+}},<<Cond>>]
+ /// CHECK: cmovnz/ne
+ /// CHECK-NEXT: cmovnz/ne
+
public static long BoolCond_LongVarCst(boolean cond, long x) {
return cond ? x : 1L;
}
@@ -114,6 +141,12 @@
/// CHECK: Select [{{j\d+}},{{j\d+}},<<Cond>>]
/// CHECK: cmovnz/neq
+ /// CHECK-START-X86: long Main.BoolCond_LongCstVar(boolean, long) disassembly (after)
+ /// CHECK: <<Cond:z\d+>> ParameterValue
+ /// CHECK: Select [{{j\d+}},{{j\d+}},<<Cond>>]
+ /// CHECK: cmovnz/ne
+ /// CHECK-NEXT: cmovnz/ne
+
public static long BoolCond_LongCstVar(boolean cond, long y) {
return cond ? 1L : y;
}
@@ -168,6 +201,11 @@
/// CHECK-NEXT: Select [{{i\d+}},{{i\d+}},<<Cond>>]
/// CHECK: cmovle/ng
+ /// CHECK-START-X86: int Main.IntNonmatCond_IntVarVar(int, int, int, int) disassembly (after)
+ /// CHECK: <<Cond:z\d+>> LessThanOrEqual [{{i\d+}},{{i\d+}}]
+ /// CHECK-NEXT: Select [{{i\d+}},{{i\d+}},<<Cond>>]
+ /// CHECK: cmovle/ng
+
public static int IntNonmatCond_IntVarVar(int a, int b, int x, int y) {
return a > b ? x : y;
}
@@ -189,6 +227,11 @@
/// CHECK: Select [{{i\d+}},{{i\d+}},<<Cond>>]
/// CHECK: cmovle/ng
+ /// CHECK-START-X86: int Main.IntMatCond_IntVarVar(int, int, int, int) disassembly (after)
+ /// CHECK: <<Cond:z\d+>> LessThanOrEqual [{{i\d+}},{{i\d+}}]
+ /// CHECK: Select [{{i\d+}},{{i\d+}},<<Cond>>]
+ /// CHECK: cmovle/ng
+
public static int IntMatCond_IntVarVar(int a, int b, int x, int y) {
int result = (a > b ? x : y);
return result + (a > b ? 0 : 1);
@@ -208,6 +251,12 @@
/// CHECK-NEXT: Select [{{j\d+}},{{j\d+}},<<Cond>>]
/// CHECK: cmovle/ngq
+ /// CHECK-START-X86: long Main.IntNonmatCond_LongVarVar(int, int, long, long) disassembly (after)
+ /// CHECK: <<Cond:z\d+>> LessThanOrEqual [{{i\d+}},{{i\d+}}]
+ /// CHECK-NEXT: Select [{{j\d+}},{{j\d+}},<<Cond>>]
+ /// CHECK: cmovle/ng
+ /// CHECK-NEXT: cmovle/ng
+
public static long IntNonmatCond_LongVarVar(int a, int b, long x, long y) {
return a > b ? x : y;
}
@@ -232,6 +281,15 @@
/// CHECK: Select [{{j\d+}},{{j\d+}},<<Cond>>]
/// CHECK: cmovnz/neq
+ /// CHECK-START-X86: long Main.IntMatCond_LongVarVar(int, int, long, long) disassembly (after)
+ /// CHECK: <<Cond:z\d+>> LessThanOrEqual [{{i\d+}},{{i\d+}}]
+ /// CHECK: Select [{{j\d+}},{{j\d+}},<<Cond>>]
+ /// CHECK-NEXT: cmovle/ng
+ /// CHECK-NEXT: cmovle/ng
+ /// CHECK: Select [{{j\d+}},{{j\d+}},<<Cond>>]
+ /// CHECK: cmovnz/ne
+ /// CHECK-NEXT: cmovnz/ne
+
public static long IntMatCond_LongVarVar(int a, int b, long x, long y) {
long result = (a > b ? x : y);
return result + (a > b ? 0L : 1L);