summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.mk7
-rw-r--r--compiler/common_compiler_test.cc2
-rw-r--r--compiler/optimizing/nodes.cc4
-rw-r--r--compiler/optimizing/nodes.h1
-rw-r--r--compiler/optimizing/optimizing_compiler.cc4
-rw-r--r--compiler/optimizing/reference_type_propagation.cc23
-rw-r--r--compiler/optimizing/reference_type_propagation.h10
-rw-r--r--compiler/optimizing/reference_type_propagation_test.cc3
-rw-r--r--compiler/optimizing/select_generator.cc68
-rw-r--r--compiler/optimizing/select_generator.h27
-rw-r--r--compiler/utils/x86/assembler_x86.cc36
-rw-r--r--compiler/utils/x86/assembler_x86.h5
-rw-r--r--compiler/utils/x86/assembler_x86_test.cc16
-rw-r--r--compiler/utils/x86_64/assembler_x86_64.cc52
-rw-r--r--compiler/utils/x86_64/assembler_x86_64.h6
-rw-r--r--compiler/utils/x86_64/assembler_x86_64_test.cc23
-rw-r--r--dex2oat/dex2oat.cc12
-rw-r--r--dex2oat/dex2oat_test.cc1
-rw-r--r--disassembler/disassembler_x86.cc5
-rw-r--r--runtime/class_linker.cc9
-rw-r--r--runtime/class_linker.h4
-rw-r--r--runtime/common_runtime_test.h6
-rw-r--r--test/592-checker-regression-bool-input/smali/TestCase.smali12
-rw-r--r--test/663-checker-select-generator/expected.txt0
-rw-r--r--test/663-checker-select-generator/info.txt14
-rw-r--r--test/663-checker-select-generator/smali/TestCase.smali72
-rw-r--r--test/663-checker-select-generator/src/Main.java62
-rw-r--r--test/knownfailures.json6
-rw-r--r--tools/Android.mk6
-rw-r--r--tools/libcore_failures.txt7
30 files changed, 436 insertions, 67 deletions
diff --git a/Android.mk b/Android.mk
index 8735d7c24c..7081f7bec5 100644
--- a/Android.mk
+++ b/Android.mk
@@ -457,7 +457,7 @@ build-art-host: $(HOST_OUT_EXECUTABLES)/art $(ART_HOST_DEPENDENCIES) $(HOST_CO
build-art-target: $(TARGET_OUT_EXECUTABLES)/art $(ART_TARGET_DEPENDENCIES) $(TARGET_CORE_IMG_OUTS)
########################################################################
-# Phony target for only building what go/lem requires on target.
+# Phony target for only building what go/lem requires for pushing ART on /data.
.PHONY: build-art-target-golem
# Also include libartbenchmark, we always include it when running golem.
# libstdc++ is needed when building for ART_TARGET_LINUX.
@@ -482,6 +482,11 @@ build-art-host-golem: build-art-host \
$(ART_HOST_SHARED_LIBRARY_BENCHMARK)
########################################################################
+# Phony target for building what go/lem requires for syncing /system to target.
+.PHONY: build-art-unbundled-golem
+build-art-unbundled-golem: art-runtime linker oatdump $(TARGET_CORE_JARS)
+
+########################################################################
# Rules for building all dependencies for tests.
.PHONY: build-art-host-tests
diff --git a/compiler/common_compiler_test.cc b/compiler/common_compiler_test.cc
index a9a718f43c..0d38620b1a 100644
--- a/compiler/common_compiler_test.cc
+++ b/compiler/common_compiler_test.cc
@@ -95,7 +95,7 @@ void CommonCompilerTest::MakeExecutable(ArtMethod* method) {
const void* method_code = CompiledMethod::CodePointer(code_ptr,
compiled_method->GetInstructionSet());
LOG(INFO) << "MakeExecutable " << method->PrettyMethod() << " code=" << method_code;
- class_linker_->SetEntryPointsToCompiledCode(method, method_code);
+ method->SetEntryPointFromQuickCompiledCode(method_code);
} else {
// No code? You must mean to go into the interpreter.
// Or the generic JNI...
diff --git a/compiler/optimizing/nodes.cc b/compiler/optimizing/nodes.cc
index 508027e52a..1510eafa40 100644
--- a/compiler/optimizing/nodes.cc
+++ b/compiler/optimizing/nodes.cc
@@ -1751,6 +1751,10 @@ bool HBasicBlock::IsSingleGoto() const {
return HasOnlyOneInstruction(*this) && GetLastInstruction()->IsGoto();
}
+bool HBasicBlock::IsSingleReturn() const {
+ return HasOnlyOneInstruction(*this) && GetLastInstruction()->IsReturn();
+}
+
bool HBasicBlock::IsSingleTryBoundary() const {
return HasOnlyOneInstruction(*this) && GetLastInstruction()->IsTryBoundary();
}
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index 68d6c2ebbc..f60d532c37 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -959,6 +959,7 @@ class HBasicBlock : public ArenaObject<kArenaAllocBasicBlock> {
}
bool IsSingleGoto() const;
+ bool IsSingleReturn() const;
bool IsSingleTryBoundary() const;
// Returns true if this block emits nothing but a jump.
diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc
index 426a1691f5..e98c97cf9a 100644
--- a/compiler/optimizing/optimizing_compiler.cc
+++ b/compiler/optimizing/optimizing_compiler.cc
@@ -489,7 +489,7 @@ static HOptimization* BuildOptimization(
} else if (opt_name == HSharpening::kSharpeningPassName) {
return new (arena) HSharpening(graph, codegen, dex_compilation_unit, driver, handles);
} else if (opt_name == HSelectGenerator::kSelectGeneratorPassName) {
- return new (arena) HSelectGenerator(graph, stats);
+ return new (arena) HSelectGenerator(graph, handles, stats);
} else if (opt_name == HInductionVarAnalysis::kInductionPassName) {
return new (arena) HInductionVarAnalysis(graph);
} else if (opt_name == InstructionSimplifier::kInstructionSimplifierPassName) {
@@ -758,7 +758,7 @@ void OptimizingCompiler::RunOptimizations(HGraph* graph,
HConstantFolding* fold1 = new (arena) HConstantFolding(graph, "constant_folding");
InstructionSimplifier* simplify1 = new (arena) InstructionSimplifier(
graph, codegen, driver, stats);
- HSelectGenerator* select_generator = new (arena) HSelectGenerator(graph, stats);
+ HSelectGenerator* select_generator = new (arena) HSelectGenerator(graph, handles, stats);
HConstantFolding* fold2 = new (arena) HConstantFolding(
graph, "constant_folding$after_inlining");
HConstantFolding* fold3 = new (arena) HConstantFolding(graph, "constant_folding$after_bce");
diff --git a/compiler/optimizing/reference_type_propagation.cc b/compiler/optimizing/reference_type_propagation.cc
index 561c9eafa2..93613a5542 100644
--- a/compiler/optimizing/reference_type_propagation.cc
+++ b/compiler/optimizing/reference_type_propagation.cc
@@ -754,8 +754,23 @@ void ReferenceTypePropagation::VisitPhi(HPhi* phi) {
}
}
+void ReferenceTypePropagation::FixUpInstructionType(HInstruction* instruction,
+ VariableSizedHandleScope* handle_scope) {
+ if (instruction->IsSelect()) {
+ ScopedObjectAccess soa(Thread::Current());
+ HandleCache handle_cache(handle_scope);
+ HSelect* select = instruction->AsSelect();
+ ReferenceTypeInfo false_rti = select->GetFalseValue()->GetReferenceTypeInfo();
+ ReferenceTypeInfo true_rti = select->GetTrueValue()->GetReferenceTypeInfo();
+ select->SetReferenceTypeInfo(MergeTypes(false_rti, true_rti, &handle_cache));
+ } else {
+ LOG(FATAL) << "Invalid instruction in FixUpInstructionType";
+ }
+}
+
ReferenceTypeInfo ReferenceTypePropagation::MergeTypes(const ReferenceTypeInfo& a,
- const ReferenceTypeInfo& b) {
+ const ReferenceTypeInfo& b,
+ HandleCache* handle_cache) {
if (!b.IsValid()) {
return a;
}
@@ -780,7 +795,7 @@ ReferenceTypeInfo ReferenceTypePropagation::MergeTypes(const ReferenceTypeInfo&
is_exact = false;
} else if (!a_is_interface && !b_is_interface) {
result_type_handle =
- handle_cache_.NewHandle(a_type_handle->GetCommonSuperClass(b_type_handle));
+ handle_cache->NewHandle(a_type_handle->GetCommonSuperClass(b_type_handle));
is_exact = false;
} else {
// This can happen if:
@@ -790,7 +805,7 @@ ReferenceTypeInfo ReferenceTypePropagation::MergeTypes(const ReferenceTypeInfo&
// void foo(Interface i, boolean cond) {
// Object o = cond ? i : new Object();
// }
- result_type_handle = handle_cache_.GetObjectClassHandle();
+ result_type_handle = handle_cache->GetObjectClassHandle();
is_exact = false;
}
@@ -916,7 +931,7 @@ void ReferenceTypePropagation::UpdatePhi(HPhi* instr) {
if (inputs[i]->IsNullConstant()) {
continue;
}
- new_rti = MergeTypes(new_rti, inputs[i]->GetReferenceTypeInfo());
+ new_rti = MergeTypes(new_rti, inputs[i]->GetReferenceTypeInfo(), &handle_cache_);
if (new_rti.IsValid() && new_rti.IsObjectClass()) {
if (!new_rti.IsExact()) {
break;
diff --git a/compiler/optimizing/reference_type_propagation.h b/compiler/optimizing/reference_type_propagation.h
index b19f473e27..c221282b9b 100644
--- a/compiler/optimizing/reference_type_propagation.h
+++ b/compiler/optimizing/reference_type_propagation.h
@@ -54,6 +54,12 @@ class ReferenceTypePropagation : public HOptimization {
static constexpr const char* kReferenceTypePropagationPassName = "reference_type_propagation";
+ // Fix the reference type for an instruction whose inputs have changed.
+ // For a select instruction, the reference types of the inputs are merged
+ // and the resulting reference type is set on the select instruction.
+ static void FixUpInstructionType(HInstruction* instruction,
+ VariableSizedHandleScope* handle_scope);
+
private:
class HandleCache {
public:
@@ -101,7 +107,9 @@ class ReferenceTypePropagation : public HOptimization {
static void UpdateArrayGet(HArrayGet* instr, HandleCache* handle_cache)
REQUIRES_SHARED(Locks::mutator_lock_);
- ReferenceTypeInfo MergeTypes(const ReferenceTypeInfo& a, const ReferenceTypeInfo& b)
+ static ReferenceTypeInfo MergeTypes(const ReferenceTypeInfo& a,
+ const ReferenceTypeInfo& b,
+ HandleCache* handle_cache)
REQUIRES_SHARED(Locks::mutator_lock_);
void ValidateTypes();
diff --git a/compiler/optimizing/reference_type_propagation_test.cc b/compiler/optimizing/reference_type_propagation_test.cc
index d537459113..cb2af91d87 100644
--- a/compiler/optimizing/reference_type_propagation_test.cc
+++ b/compiler/optimizing/reference_type_propagation_test.cc
@@ -49,7 +49,7 @@ class ReferenceTypePropagationTest : public CommonCompilerTest {
// Relay method to merge type in reference type propagation.
ReferenceTypeInfo MergeTypes(const ReferenceTypeInfo& a,
const ReferenceTypeInfo& b) REQUIRES_SHARED(Locks::mutator_lock_) {
- return propagation_->MergeTypes(a, b);
+ return propagation_->MergeTypes(a, b, &propagation_->handle_cache_);
}
// Helper method to construct an invalid type.
@@ -163,4 +163,3 @@ TEST_F(ReferenceTypePropagationTest, MergeValidTypes) {
}
} // namespace art
-
diff --git a/compiler/optimizing/select_generator.cc b/compiler/optimizing/select_generator.cc
index cb7ade915f..e220d32344 100644
--- a/compiler/optimizing/select_generator.cc
+++ b/compiler/optimizing/select_generator.cc
@@ -20,9 +20,16 @@ namespace art {
static constexpr size_t kMaxInstructionsInBranch = 1u;
-// Returns true if `block` has only one predecessor, ends with a Goto and
-// contains at most `kMaxInstructionsInBranch` other movable instruction with
-// no side-effects.
+HSelectGenerator::HSelectGenerator(HGraph* graph,
+ VariableSizedHandleScope* handles,
+ OptimizingCompilerStats* stats)
+ : HOptimization(graph, kSelectGeneratorPassName, stats),
+ handle_scope_(handles) {
+}
+
+// Returns true if `block` has only one predecessor, ends with a Goto
+// or a Return and contains at most `kMaxInstructionsInBranch` other
+// movable instruction with no side-effects.
static bool IsSimpleBlock(HBasicBlock* block) {
if (block->GetPredecessors().size() != 1u) {
return false;
@@ -33,7 +40,10 @@ static bool IsSimpleBlock(HBasicBlock* block) {
for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
HInstruction* instruction = it.Current();
if (instruction->IsControlFlow()) {
- return instruction->IsGoto() && num_instructions <= kMaxInstructionsInBranch;
+ if (num_instructions > kMaxInstructionsInBranch) {
+ return false;
+ }
+ return instruction->IsGoto() || instruction->IsReturn();
} else if (instruction->CanBeMoved() && !instruction->HasSideEffects()) {
num_instructions++;
} else {
@@ -45,8 +55,8 @@ static bool IsSimpleBlock(HBasicBlock* block) {
UNREACHABLE();
}
-// Returns true if 'block1' and 'block2' are empty, merge into the same single
-// successor and the successor can only be reached from them.
+// Returns true if 'block1' and 'block2' are empty and merge into the
+// same single successor.
static bool BlocksMergeTogether(HBasicBlock* block1, HBasicBlock* block2) {
return block1->GetSingleSuccessor() == block2->GetSingleSuccessor();
}
@@ -94,48 +104,68 @@ void HSelectGenerator::Run() {
// If the branches are not empty, move instructions in front of the If.
// TODO(dbrazdil): This puts an instruction between If and its condition.
// Implement moving of conditions to first users if possible.
- if (!true_block->IsSingleGoto()) {
+ if (!true_block->IsSingleGoto() && !true_block->IsSingleReturn()) {
true_block->GetFirstInstruction()->MoveBefore(if_instruction);
}
- if (!false_block->IsSingleGoto()) {
+ if (!false_block->IsSingleGoto() && !false_block->IsSingleReturn()) {
false_block->GetFirstInstruction()->MoveBefore(if_instruction);
}
- DCHECK(true_block->IsSingleGoto());
- DCHECK(false_block->IsSingleGoto());
+ DCHECK(true_block->IsSingleGoto() || true_block->IsSingleReturn());
+ DCHECK(false_block->IsSingleGoto() || false_block->IsSingleReturn());
// Find the resulting true/false values.
size_t predecessor_index_true = merge_block->GetPredecessorIndexOf(true_block);
size_t predecessor_index_false = merge_block->GetPredecessorIndexOf(false_block);
DCHECK_NE(predecessor_index_true, predecessor_index_false);
+ bool both_successors_return = true_block->IsSingleReturn() && false_block->IsSingleReturn();
HPhi* phi = GetSingleChangedPhi(merge_block, predecessor_index_true, predecessor_index_false);
- if (phi == nullptr) {
+
+ HInstruction* true_value = nullptr;
+ HInstruction* false_value = nullptr;
+ if (both_successors_return) {
+ true_value = true_block->GetFirstInstruction()->InputAt(0);
+ false_value = false_block->GetFirstInstruction()->InputAt(0);
+ } else if (phi != nullptr) {
+ true_value = phi->InputAt(predecessor_index_true);
+ false_value = phi->InputAt(predecessor_index_false);
+ } else {
continue;
}
- HInstruction* true_value = phi->InputAt(predecessor_index_true);
- HInstruction* false_value = phi->InputAt(predecessor_index_false);
+ DCHECK(both_successors_return || phi != nullptr);
// Create the Select instruction and insert it in front of the If.
HSelect* select = new (graph_->GetArena()) HSelect(if_instruction->InputAt(0),
true_value,
false_value,
if_instruction->GetDexPc());
- if (phi->GetType() == Primitive::kPrimNot) {
+ if (both_successors_return) {
+ if (true_value->GetType() == Primitive::kPrimNot) {
+ DCHECK(false_value->GetType() == Primitive::kPrimNot);
+ ReferenceTypePropagation::FixUpInstructionType(select, handle_scope_);
+ }
+ } else if (phi->GetType() == Primitive::kPrimNot) {
select->SetReferenceTypeInfo(phi->GetReferenceTypeInfo());
}
block->InsertInstructionBefore(select, if_instruction);
- // Remove the true branch which removes the corresponding Phi input.
- // If left only with the false branch, the Phi is automatically removed.
- phi->ReplaceInput(select, predecessor_index_false);
+ // Remove the true branch which removes the corresponding Phi
+ // input if needed. If left only with the false branch, the Phi is
+ // automatically removed.
+ if (both_successors_return) {
+ false_block->GetFirstInstruction()->ReplaceInput(select, 0);
+ } else {
+ phi->ReplaceInput(select, predecessor_index_false);
+ }
+
bool only_two_predecessors = (merge_block->GetPredecessors().size() == 2u);
true_block->DisconnectAndDelete();
- DCHECK_EQ(only_two_predecessors, phi->GetBlock() == nullptr);
// Merge remaining blocks which are now connected with Goto.
DCHECK_EQ(block->GetSingleSuccessor(), false_block);
block->MergeWith(false_block);
- if (only_two_predecessors) {
+ if (!both_successors_return && only_two_predecessors) {
+ DCHECK_EQ(only_two_predecessors, phi->GetBlock() == nullptr);
DCHECK_EQ(block->GetSingleSuccessor(), merge_block);
block->MergeWith(merge_block);
}
diff --git a/compiler/optimizing/select_generator.h b/compiler/optimizing/select_generator.h
index c6dca581cc..c060146478 100644
--- a/compiler/optimizing/select_generator.h
+++ b/compiler/optimizing/select_generator.h
@@ -18,7 +18,7 @@
* This optimization recognizes the common diamond selection pattern and
* replaces it with an instance of the HSelect instruction.
*
- * Recognized pattern:
+ * Recognized patterns:
*
* If [ Condition ]
* / \
@@ -26,14 +26,30 @@
* \ /
* Phi [FalseValue, TrueValue]
*
+ * and
+ *
+ * If [ Condition ]
+ * / \
+ * false branch true branch
+ * return FalseValue return TrueValue
+ *
* The pattern will be simplified if `true_branch` and `false_branch` each
* contain at most one instruction without any side effects.
*
- * Blocks are merged into one and Select replaces the If and the Phi:
+ * Blocks are merged into one and Select replaces the If and the Phi.
+ *
+ * For the first pattern it simplifies to:
+ *
* true branch
* false branch
* Select [FalseValue, TrueValue, Condition]
*
+ * For the second pattern it simplifies to:
+ *
+ * true branch
+ * false branch
+ * return Select [FalseValue, TrueValue, Condition]
+ *
* Note: In order to recognize no side-effect blocks, this optimization must be
* run after the instruction simplifier has removed redundant suspend checks.
*/
@@ -42,19 +58,22 @@
#define ART_COMPILER_OPTIMIZING_SELECT_GENERATOR_H_
#include "optimization.h"
+#include "reference_type_propagation.h"
namespace art {
class HSelectGenerator : public HOptimization {
public:
- HSelectGenerator(HGraph* graph, OptimizingCompilerStats* stats)
- : HOptimization(graph, kSelectGeneratorPassName, stats) {}
+ HSelectGenerator(HGraph* graph,
+ VariableSizedHandleScope* handles,
+ OptimizingCompilerStats* stats);
void Run() OVERRIDE;
static constexpr const char* kSelectGeneratorPassName = "select_generator";
private:
+ VariableSizedHandleScope* handle_scope_;
DISALLOW_COPY_AND_ASSIGN(HSelectGenerator);
};
diff --git a/compiler/utils/x86/assembler_x86.cc b/compiler/utils/x86/assembler_x86.cc
index b50f1af8f9..b89af10749 100644
--- a/compiler/utils/x86/assembler_x86.cc
+++ b/compiler/utils/x86/assembler_x86.cc
@@ -1606,6 +1606,42 @@ void X86Assembler::punpcklqdq(XmmRegister dst, XmmRegister src) {
}
+void X86Assembler::punpckhbw(XmmRegister dst, XmmRegister src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x66);
+ EmitUint8(0x0F);
+ EmitUint8(0x68);
+ EmitXmmRegisterOperand(dst, src);
+}
+
+
+void X86Assembler::punpckhwd(XmmRegister dst, XmmRegister src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x66);
+ EmitUint8(0x0F);
+ EmitUint8(0x69);
+ EmitXmmRegisterOperand(dst, src);
+}
+
+
+void X86Assembler::punpckhdq(XmmRegister dst, XmmRegister src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x66);
+ EmitUint8(0x0F);
+ EmitUint8(0x6A);
+ EmitXmmRegisterOperand(dst, src);
+}
+
+
+void X86Assembler::punpckhqdq(XmmRegister dst, XmmRegister src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x66);
+ EmitUint8(0x0F);
+ EmitUint8(0x6D);
+ EmitXmmRegisterOperand(dst, src);
+}
+
+
void X86Assembler::psllw(XmmRegister reg, const Immediate& shift_count) {
DCHECK(shift_count.is_uint8());
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
diff --git a/compiler/utils/x86/assembler_x86.h b/compiler/utils/x86/assembler_x86.h
index 8578340ea7..511eeb9973 100644
--- a/compiler/utils/x86/assembler_x86.h
+++ b/compiler/utils/x86/assembler_x86.h
@@ -546,6 +546,11 @@ class X86Assembler FINAL : public Assembler {
void punpckldq(XmmRegister dst, XmmRegister src);
void punpcklqdq(XmmRegister dst, XmmRegister src);
+ void punpckhbw(XmmRegister dst, XmmRegister src);
+ void punpckhwd(XmmRegister dst, XmmRegister src);
+ void punpckhdq(XmmRegister dst, XmmRegister src);
+ void punpckhqdq(XmmRegister dst, XmmRegister src);
+
void psllw(XmmRegister reg, const Immediate& shift_count);
void pslld(XmmRegister reg, const Immediate& shift_count);
void psllq(XmmRegister reg, const Immediate& shift_count);
diff --git a/compiler/utils/x86/assembler_x86_test.cc b/compiler/utils/x86/assembler_x86_test.cc
index 3e1244ed5d..d2122db3fa 100644
--- a/compiler/utils/x86/assembler_x86_test.cc
+++ b/compiler/utils/x86/assembler_x86_test.cc
@@ -777,6 +777,22 @@ TEST_F(AssemblerX86Test, Punpcklqdq) {
DriverStr(RepeatFF(&x86::X86Assembler::punpcklqdq, "punpcklqdq %{reg2}, %{reg1}"), "punpcklqdq");
}
+TEST_F(AssemblerX86Test, Punpckhbw) {
+ DriverStr(RepeatFF(&x86::X86Assembler::punpckhbw, "punpckhbw %{reg2}, %{reg1}"), "punpckhbw");
+}
+
+TEST_F(AssemblerX86Test, Punpckhwd) {
+ DriverStr(RepeatFF(&x86::X86Assembler::punpckhwd, "punpckhwd %{reg2}, %{reg1}"), "punpckhwd");
+}
+
+TEST_F(AssemblerX86Test, Punpckhdq) {
+ DriverStr(RepeatFF(&x86::X86Assembler::punpckhdq, "punpckhdq %{reg2}, %{reg1}"), "punpckhdq");
+}
+
+TEST_F(AssemblerX86Test, Punpckhqdq) {
+ DriverStr(RepeatFF(&x86::X86Assembler::punpckhqdq, "punpckhqdq %{reg2}, %{reg1}"), "punpckhqdq");
+}
+
TEST_F(AssemblerX86Test, psllw) {
GetAssembler()->psllw(x86::XMM0, CreateImmediate(16));
DriverStr("psllw $0x10, %xmm0\n", "psllwi");
diff --git a/compiler/utils/x86_64/assembler_x86_64.cc b/compiler/utils/x86_64/assembler_x86_64.cc
index ea69a1c9be..3bff67d2f2 100644
--- a/compiler/utils/x86_64/assembler_x86_64.cc
+++ b/compiler/utils/x86_64/assembler_x86_64.cc
@@ -1835,6 +1835,46 @@ void X86_64Assembler::punpcklqdq(XmmRegister dst, XmmRegister src) {
}
+void X86_64Assembler::punpckhbw(XmmRegister dst, XmmRegister src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x66);
+ EmitOptionalRex32(dst, src);
+ EmitUint8(0x0F);
+ EmitUint8(0x68);
+ EmitXmmRegisterOperand(dst.LowBits(), src);
+}
+
+
+void X86_64Assembler::punpckhwd(XmmRegister dst, XmmRegister src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x66);
+ EmitOptionalRex32(dst, src);
+ EmitUint8(0x0F);
+ EmitUint8(0x69);
+ EmitXmmRegisterOperand(dst.LowBits(), src);
+}
+
+
+void X86_64Assembler::punpckhdq(XmmRegister dst, XmmRegister src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x66);
+ EmitOptionalRex32(dst, src);
+ EmitUint8(0x0F);
+ EmitUint8(0x6A);
+ EmitXmmRegisterOperand(dst.LowBits(), src);
+}
+
+
+void X86_64Assembler::punpckhqdq(XmmRegister dst, XmmRegister src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x66);
+ EmitOptionalRex32(dst, src);
+ EmitUint8(0x0F);
+ EmitUint8(0x6D);
+ EmitXmmRegisterOperand(dst.LowBits(), src);
+}
+
+
void X86_64Assembler::psllw(XmmRegister reg, const Immediate& shift_count) {
DCHECK(shift_count.is_uint8());
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
@@ -1931,6 +1971,18 @@ void X86_64Assembler::psrlq(XmmRegister reg, const Immediate& shift_count) {
}
+void X86_64Assembler::psrldq(XmmRegister reg, const Immediate& shift_count) {
+ DCHECK(shift_count.is_uint8());
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x66);
+ EmitOptionalRex(false, false, false, false, reg.NeedsRex());
+ EmitUint8(0x0F);
+ EmitUint8(0x73);
+ EmitXmmRegisterOperand(3, reg);
+ EmitUint8(shift_count.value());
+}
+
+
void X86_64Assembler::fldl(const Address& src) {
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
EmitUint8(0xDD);
diff --git a/compiler/utils/x86_64/assembler_x86_64.h b/compiler/utils/x86_64/assembler_x86_64.h
index 41450bff4f..3dab235d1c 100644
--- a/compiler/utils/x86_64/assembler_x86_64.h
+++ b/compiler/utils/x86_64/assembler_x86_64.h
@@ -574,6 +574,11 @@ class X86_64Assembler FINAL : public Assembler {
void punpckldq(XmmRegister dst, XmmRegister src);
void punpcklqdq(XmmRegister dst, XmmRegister src);
+ void punpckhbw(XmmRegister dst, XmmRegister src);
+ void punpckhwd(XmmRegister dst, XmmRegister src);
+ void punpckhdq(XmmRegister dst, XmmRegister src);
+ void punpckhqdq(XmmRegister dst, XmmRegister src);
+
void psllw(XmmRegister reg, const Immediate& shift_count);
void pslld(XmmRegister reg, const Immediate& shift_count);
void psllq(XmmRegister reg, const Immediate& shift_count);
@@ -585,6 +590,7 @@ class X86_64Assembler FINAL : public Assembler {
void psrlw(XmmRegister reg, const Immediate& shift_count);
void psrld(XmmRegister reg, const Immediate& shift_count);
void psrlq(XmmRegister reg, const Immediate& shift_count);
+ void psrldq(XmmRegister reg, const Immediate& shift_count);
void flds(const Address& src);
void fstps(const Address& dst);
diff --git a/compiler/utils/x86_64/assembler_x86_64_test.cc b/compiler/utils/x86_64/assembler_x86_64_test.cc
index 9f2c44d30d..85afee0746 100644
--- a/compiler/utils/x86_64/assembler_x86_64_test.cc
+++ b/compiler/utils/x86_64/assembler_x86_64_test.cc
@@ -1465,6 +1465,22 @@ TEST_F(AssemblerX86_64Test, Punpcklqdq) {
DriverStr(RepeatFF(&x86_64::X86_64Assembler::punpcklqdq, "punpcklqdq %{reg2}, %{reg1}"), "punpcklqdq");
}
+TEST_F(AssemblerX86_64Test, Punpckhbw) {
+ DriverStr(RepeatFF(&x86_64::X86_64Assembler::punpckhbw, "punpckhbw %{reg2}, %{reg1}"), "punpckhbw");
+}
+
+TEST_F(AssemblerX86_64Test, Punpckhwd) {
+ DriverStr(RepeatFF(&x86_64::X86_64Assembler::punpckhwd, "punpckhwd %{reg2}, %{reg1}"), "punpckhwd");
+}
+
+TEST_F(AssemblerX86_64Test, Punpckhdq) {
+ DriverStr(RepeatFF(&x86_64::X86_64Assembler::punpckhdq, "punpckhdq %{reg2}, %{reg1}"), "punpckhdq");
+}
+
+TEST_F(AssemblerX86_64Test, Punpckhqdq) {
+ DriverStr(RepeatFF(&x86_64::X86_64Assembler::punpckhqdq, "punpckhqdq %{reg2}, %{reg1}"), "punpckhqdq");
+}
+
TEST_F(AssemblerX86_64Test, Psllw) {
GetAssembler()->psllw(x86_64::XmmRegister(x86_64::XMM0), x86_64::Immediate(1));
GetAssembler()->psllw(x86_64::XmmRegister(x86_64::XMM15), x86_64::Immediate(2));
@@ -1521,6 +1537,13 @@ TEST_F(AssemblerX86_64Test, Psrlq) {
"psrlq $2, %xmm15\n", "pslrqi");
}
+TEST_F(AssemblerX86_64Test, Psrldq) {
+ GetAssembler()->psrldq(x86_64::XmmRegister(x86_64::XMM0), x86_64::Immediate(1));
+ GetAssembler()->psrldq(x86_64::XmmRegister(x86_64::XMM15), x86_64::Immediate(2));
+ DriverStr("psrldq $1, %xmm0\n"
+ "psrldq $2, %xmm15\n", "pslrdqi");
+}
+
TEST_F(AssemblerX86_64Test, UcomissAddress) {
GetAssembler()->ucomiss(x86_64::XmmRegister(x86_64::XMM0), x86_64::Address(
x86_64::CpuRegister(x86_64::RDI), x86_64::CpuRegister(x86_64::RBX), x86_64::TIMES_4, 12));
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index e9ec5faa7f..e3e01804db 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -1777,11 +1777,15 @@ class Dex2Oat FINAL {
}
bool ShouldCompileDexFilesIndividually() const {
- // Compile individually if we are not building an image, not using any compilation, and are
- // using multidex.
- // This means extract, verify, and quicken, will use the individual compilation mode (to reduce
- // RAM used by the compiler).
+ // Compile individually if we are:
+ // 1. not building an image,
+ // 2. not verifying a vdex file,
+ // 3. using multidex,
+ // 4. not doing any AOT compilation.
+ // This means extract, no-vdex verify, and quicken, will use the individual compilation
+ // mode (to reduce RAM used by the compiler).
return !IsImage() &&
+ !update_input_vdex_ &&
dex_files_.size() > 1 &&
!CompilerFilter::IsAotCompilationEnabled(compiler_options_->GetCompilerFilter());
}
diff --git a/dex2oat/dex2oat_test.cc b/dex2oat/dex2oat_test.cc
index 6a9d979d52..10efaf3d1b 100644
--- a/dex2oat/dex2oat_test.cc
+++ b/dex2oat/dex2oat_test.cc
@@ -950,6 +950,7 @@ TEST_F(Dex2oatWatchdogTest, TestWatchdogOK) {
}
TEST_F(Dex2oatWatchdogTest, TestWatchdogTrigger) {
+ TEST_DISABLED_FOR_MEMORY_TOOL_VALGRIND(); // b/63052624
// Check with ten milliseconds.
RunTest(false, { "--watchdog-timeout=10" });
}
diff --git a/disassembler/disassembler_x86.cc b/disassembler/disassembler_x86.cc
index 4824f70a28..bbc8e370ea 100644
--- a/disassembler/disassembler_x86.cc
+++ b/disassembler/disassembler_x86.cc
@@ -792,6 +792,7 @@ DISASSEMBLER_ENTRY(cmp,
src_reg_file = dst_reg_file = SSE;
break;
case 0x60: case 0x61: case 0x62: case 0x6C:
+ case 0x68: case 0x69: case 0x6A: case 0x6D:
if (prefix[2] == 0x66) {
src_reg_file = dst_reg_file = SSE;
prefix[2] = 0; // Clear prefix now. It has served its purpose as part of the opcode.
@@ -803,6 +804,10 @@ DISASSEMBLER_ENTRY(cmp,
case 0x61: opcode1 = "punpcklwd"; break;
case 0x62: opcode1 = "punpckldq"; break;
case 0x6c: opcode1 = "punpcklqdq"; break;
+ case 0x68: opcode1 = "punpckhbw"; break;
+ case 0x69: opcode1 = "punpckhwd"; break;
+ case 0x6A: opcode1 = "punpckhdq"; break;
+ case 0x6D: opcode1 = "punpckhqdq"; break;
}
load = true;
has_modrm = true;
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 9756f5787f..845bd6d5ff 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -8598,15 +8598,6 @@ const void* ClassLinker::GetRuntimeQuickGenericJniStub() const {
return GetQuickGenericJniStub();
}
-void ClassLinker::SetEntryPointsToCompiledCode(ArtMethod* method, const void* code) const {
- CHECK(code != nullptr);
- const uint8_t* base = reinterpret_cast<const uint8_t*>(code); // Base of data points at code.
- base -= sizeof(void*); // Move backward so that code_offset != 0.
- const uint32_t code_offset = sizeof(void*);
- OatFile::OatMethod oat_method(base, code_offset);
- oat_method.LinkMethod(method);
-}
-
void ClassLinker::SetEntryPointsToInterpreter(ArtMethod* method) const {
if (!method->IsNative()) {
method->SetEntryPointFromQuickCompiledCode(GetQuickToInterpreterBridge());
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index 2fbbe79e47..66bcbe091f 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -511,10 +511,6 @@ class ClassLinker {
return intern_table_;
}
- // Set the entrypoints up for method to the given code.
- void SetEntryPointsToCompiledCode(ArtMethod* method, const void* method_code) const
- REQUIRES_SHARED(Locks::mutator_lock_);
-
// Set the entrypoints up for method to the enter the interpreter.
void SetEntryPointsToInterpreter(ArtMethod* method) const
REQUIRES_SHARED(Locks::mutator_lock_);
diff --git a/runtime/common_runtime_test.h b/runtime/common_runtime_test.h
index 74bc0b2afb..e2131f1530 100644
--- a/runtime/common_runtime_test.h
+++ b/runtime/common_runtime_test.h
@@ -288,6 +288,12 @@ class CheckJniAbortCatcher {
return; \
}
+#define TEST_DISABLED_FOR_MEMORY_TOOL_VALGRIND() \
+ if (RUNNING_ON_MEMORY_TOOL > 0 && kMemoryToolIsValgrind) { \
+ printf("WARNING: TEST DISABLED FOR MEMORY TOOL VALGRIND\n"); \
+ return; \
+ }
+
#define TEST_DISABLED_FOR_MEMORY_TOOL_ASAN() \
if (RUNNING_ON_MEMORY_TOOL > 0 && !kMemoryToolIsValgrind) { \
printf("WARNING: TEST DISABLED FOR MEMORY TOOL ASAN\n"); \
diff --git a/test/592-checker-regression-bool-input/smali/TestCase.smali b/test/592-checker-regression-bool-input/smali/TestCase.smali
index 56c499d4b6..ad4e902724 100644
--- a/test/592-checker-regression-bool-input/smali/TestCase.smali
+++ b/test/592-checker-regression-bool-input/smali/TestCase.smali
@@ -16,8 +16,15 @@
.super Ljava/lang/Object;
+## CHECK-START: boolean TestCase.testCase() select_generator (after)
+## CHECK-DAG: <<Select:i\d+>> Select
+## CHECK-DAG: Return [<<Select>>]
+
## CHECK-START: boolean TestCase.testCase() load_store_elimination (after)
-## CHECK-DAG: If [{{b\d+}}]
+## CHECK-DAG: <<Or:i\d+>> Or
+## CHECK-DAG: <<TypeConversion:b\d+>> TypeConversion
+## CHECK-DAG: StaticFieldSet
+## CHECK-DAG: Return [<<TypeConversion>>]
.method public static testCase()Z
.registers 6
@@ -31,7 +38,8 @@
# LSE will replace this sget with the type conversion above...
sget-boolean v2, LMain;->field2:Z
- # ... and generate an If with a byte-typed condition.
+ # ... and select generation will replace this part with a select
+ # that simplifies into simply returning the stored boolean.
if-eqz v2, :else
const v0, 0x1
return v0
diff --git a/test/663-checker-select-generator/expected.txt b/test/663-checker-select-generator/expected.txt
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/test/663-checker-select-generator/expected.txt
diff --git a/test/663-checker-select-generator/info.txt b/test/663-checker-select-generator/info.txt
new file mode 100644
index 0000000000..792779f674
--- /dev/null
+++ b/test/663-checker-select-generator/info.txt
@@ -0,0 +1,14 @@
+Test for select generation for conditional returns.
+
+Tests the rewriting from:
+
+ If [ Condition ]
+ / \
+ false branch true branch
+ return FalseValue return TrueValue
+
+to:
+
+ true branch
+ false branch
+ return Select [FalseValue, TrueValue, Condition]
diff --git a/test/663-checker-select-generator/smali/TestCase.smali b/test/663-checker-select-generator/smali/TestCase.smali
new file mode 100644
index 0000000000..844a9cf883
--- /dev/null
+++ b/test/663-checker-select-generator/smali/TestCase.smali
@@ -0,0 +1,72 @@
+# Copyright (C) 2017 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.
+
+.class public LTestCase;
+
+.super Ljava/lang/Object;
+
+## CHECK-START: boolean TestCase.testCase(boolean) select_generator (before)
+## CHECK-DAG: <<Param:z\d+>> ParameterValue
+## CHECK-DAG: <<Int0:i\d+>> IntConstant 0
+## CHECK-DAG: <<Int1:i\d+>> IntConstant 1
+## CHECK-DAG: If [<<Param>>]
+## CHECK-DAG: Return [<<Int0>>]
+## CHECK-DAG: Return [<<Int1>>]
+
+## CHECK-START: boolean TestCase.testCase(boolean) select_generator (after)
+## CHECK-DAG: <<Param:z\d+>> ParameterValue
+## CHECK-DAG: <<Int0:i\d+>> IntConstant 0
+## CHECK-DAG: <<Int1:i\d+>> IntConstant 1
+## CHECK-DAG: <<Select:i\d+>> Select [<<Int0>>,<<Int1>>,<<Param>>]
+## CHECK-DAG: Return [<<Select>>]
+
+.method public static testCase(Z)Z
+ .registers 1
+
+ # The select generation will replace this with a select
+ # instruction and a return.
+ if-eqz v0, :else
+ const v0, 0x1
+ return v0
+
+ :else
+ const v0, 0x0
+ return v0
+.end method
+
+
+## CHECK-START: java.lang.Object TestCase.referenceTypeTestCase(Main$Sub1, Main$Sub2, boolean) select_generator (before)
+## CHECK-DAG: <<Param0:l\d+>> ParameterValue
+## CHECK-DAG: <<Param1:l\d+>> ParameterValue
+## CHECK-DAG: <<Param2:z\d+>> ParameterValue
+## CHECK-DAG: If [<<Param2>>]
+## CHECK-DAG: Return [<<Param1>>]
+## CHECK-DAG: Return [<<Param0>>]
+
+## CHECK-START: java.lang.Object TestCase.referenceTypeTestCase(Main$Sub1, Main$Sub2, boolean) select_generator (after)
+## CHECK-DAG: <<Param0:l\d+>> ParameterValue
+## CHECK-DAG: <<Param1:l\d+>> ParameterValue
+## CHECK-DAG: <<Param2:z\d+>> ParameterValue
+## CHECK-DAG: <<Select:l\d+>> Select [<<Param1>>,<<Param0>>,<<Param2>>]
+## CHECK-DAG: Return [<<Select>>]
+
+.method public static referenceTypeTestCase(LMain$Sub1;LMain$Sub2;Z)Ljava/lang/Object;
+ .registers 3
+
+ if-eqz v2, :else
+ return-object v0
+
+ :else
+ return-object v1
+.end method
diff --git a/test/663-checker-select-generator/src/Main.java b/test/663-checker-select-generator/src/Main.java
new file mode 100644
index 0000000000..c5c7a43955
--- /dev/null
+++ b/test/663-checker-select-generator/src/Main.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+import java.lang.reflect.Method;
+
+public class Main {
+ public static class Super {}
+ public static class Sub1 {}
+ public static class Sub2 {}
+
+ public static void assertTrue(boolean result) {
+ if (!result) {
+ throw new Error("Expected true");
+ }
+ }
+
+ public static void assertFalse(boolean result) {
+ if (result) {
+ throw new Error("Expected false");
+ }
+ }
+
+ public static void assertInstanceOfSub1(Object result) {
+ if (!(result instanceof Sub1)) {
+ throw new Error("Expected instance of Sub1");
+ }
+ }
+
+ public static void assertInstanceOfSub2(Object result) {
+ if (!(result instanceof Sub2)) {
+ throw new Error("Expected instance of Sub2");
+ }
+ }
+
+ public static void main(String[] args) throws Throwable {
+ Class<?> c = Class.forName("TestCase");
+ Method m = c.getMethod("testCase", boolean.class);
+ Method m2 = c.getMethod("referenceTypeTestCase", Sub1.class, Sub2.class, boolean.class);
+
+ try {
+ assertTrue((Boolean) m.invoke(null, true));
+ assertFalse((Boolean) m.invoke(null, false));
+ assertInstanceOfSub1(m2.invoke(null, new Sub1(), new Sub2(), true));
+ assertInstanceOfSub2(m2.invoke(null, new Sub1(), new Sub2(), false));
+ } catch (Exception e) {
+ throw new Error(e);
+ }
+ }
+}
diff --git a/test/knownfailures.json b/test/knownfailures.json
index a8191bbb23..1d4be6aefe 100644
--- a/test/knownfailures.json
+++ b/test/knownfailures.json
@@ -54,11 +54,6 @@
"doesn't (and isn't meant to) work with --prebuild."]
},
{
- "tests": ["529-checker-unresolved"],
- "variant": "no-prebuild",
- "bug": "http://b/27784033"
- },
- {
"tests": ["117-nopatchoat",
"147-stripped-dex-fallback",
"608-checker-unresolved-lse"],
@@ -505,6 +500,7 @@
"641-checker-arraycopy",
"643-checker-bogus-ic",
"645-checker-abs-simd",
+ "663-checker-select-generator",
"706-checker-scheduler"],
"description": ["Checker tests are not compatible with jvmti."],
"variant": "jvmti-stress | redefine-stress | trace-stress | field-stress | step-stress"
diff --git a/tools/Android.mk b/tools/Android.mk
index bc2fd8c53c..9ecf0cd7ed 100644
--- a/tools/Android.mk
+++ b/tools/Android.mk
@@ -20,13 +20,15 @@ LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_IS_HOST_MODULE := true
LOCAL_MODULE_CLASS := EXECUTABLES
-LOCAL_MODULE := art
+LOCAL_MODULE := art-script
LOCAL_SRC_FILES := art
+LOCAL_MODULE_STEM := art
include $(BUILD_PREBUILT)
# Copy the art shell script to the target's bin directory
include $(CLEAR_VARS)
LOCAL_MODULE_CLASS := EXECUTABLES
-LOCAL_MODULE := art
+LOCAL_MODULE := art-script
LOCAL_SRC_FILES := art
+LOCAL_MODULE_STEM := art
include $(BUILD_PREBUILT)
diff --git a/tools/libcore_failures.txt b/tools/libcore_failures.txt
index c6553f89fa..ea26b0e940 100644
--- a/tools/libcore_failures.txt
+++ b/tools/libcore_failures.txt
@@ -211,13 +211,6 @@
"libcore.java.lang.ProcessBuilderTest#testRedirect_nullStreams"]
},
{
- description: "Test is timing sensitive",
- result: EXEC_FAILED,
- bug: 62528691,
- modes: [device],
- names: ["libcore.java.util.TimeZoneTest#testSetDefaultRace"]
-},
-{
description: "Repeated annotations do not work in javac (OpenJDK8), fixed in OpenJDK9.
Blacklisted to support javac/dx build (b/36902714)",
result: EXEC_FAILED,