diff options
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, |