diff options
| -rw-r--r-- | build/Android.cpplint.mk | 9 | ||||
| -rw-r--r-- | compiler/Android.bp | 1 | ||||
| -rw-r--r-- | compiler/optimizing/nodes_vector.h | 142 | ||||
| -rw-r--r-- | compiler/optimizing/nodes_vector_test.cc | 335 | ||||
| -rw-r--r-- | runtime/gc/space/image_space.cc | 2 |
5 files changed, 482 insertions, 7 deletions
diff --git a/build/Android.cpplint.mk b/build/Android.cpplint.mk index f924a855b7..66ac897f76 100644 --- a/build/Android.cpplint.mk +++ b/build/Android.cpplint.mk @@ -18,7 +18,8 @@ include art/build/Android.common_build.mk ART_CPPLINT := $(LOCAL_PATH)/tools/cpplint.py ART_CPPLINT_FILTER := --filter=-whitespace/line_length,-build/include,-readability/function,-readability/streams,-readability/todo,-runtime/references,-runtime/sizeof,-runtime/threadsafe_fn,-runtime/printf -ART_CPPLINT_FLAGS := --quiet --root=$(ANDROID_BUILD_TOP) +ART_CPPLINT_FLAGS := --root=$(TOP) +ART_CPPLINT_QUIET := --quiet ART_CPPLINT_INGORED := \ runtime/elf.h \ runtime/openjdkjvmti/include/jvmti.h @@ -32,12 +33,12 @@ ART_CPPLINT_SRC := $(filter-out $(patsubst %,$(LOCAL_PATH)/%,$(ART_CPPLINT_INGOR # "mm cpplint-art" to verify we aren't regressing .PHONY: cpplint-art cpplint-art: - $(ART_CPPLINT) $(ART_CPPLINT_FILTER) $(ART_CPPLINT_SRC) + $(ART_CPPLINT) $(ART_CPPLINT_FLAGS) $(ART_CPPLINT_FILTER) $(ART_CPPLINT_SRC) # "mm cpplint-art-all" to see all warnings .PHONY: cpplint-art-all cpplint-art-all: - $(ART_CPPLINT) $(ART_CPPLINT_SRC) + $(ART_CPPLINT) $(ART_CPPLINT_FLAGS) $(ART_CPPLINT_SRC) OUT_CPPLINT := $(TARGET_COMMON_OUT_ROOT)/cpplint @@ -48,7 +49,7 @@ art_cpplint_file := $(1) art_cpplint_touch := $$(OUT_CPPLINT)/$$(subst /,__,$$(art_cpplint_file)) $$(art_cpplint_touch): $$(art_cpplint_file) $(ART_CPPLINT) art/build/Android.cpplint.mk - $(hide) $(ART_CPPLINT) $(ART_CPPLINT_FLAGS) $(ART_CPPLINT_FILTER) $$< + $(hide) $(ART_CPPLINT) $(ART_CPPLINT_QUIET) $(ART_CPPLINT_FLAGS) $(ART_CPPLINT_FILTER) $$< $(hide) mkdir -p $$(dir $$@) $(hide) touch $$@ diff --git a/compiler/Android.bp b/compiler/Android.bp index e590fb745c..761f53fa5a 100644 --- a/compiler/Android.bp +++ b/compiler/Android.bp @@ -356,6 +356,7 @@ art_cc_test { "optimizing/live_interval_test.cc", "optimizing/loop_optimization_test.cc", "optimizing/nodes_test.cc", + "optimizing/nodes_vector_test.cc", "optimizing/parallel_move_test.cc", "optimizing/pretty_printer_test.cc", "optimizing/reference_type_propagation_test.cc", diff --git a/compiler/optimizing/nodes_vector.h b/compiler/optimizing/nodes_vector.h index 5dbe29b4fa..6261171a00 100644 --- a/compiler/optimizing/nodes_vector.h +++ b/compiler/optimizing/nodes_vector.h @@ -46,6 +46,10 @@ class Alignment { return "ALIGN(" + std::to_string(base_) + "," + std::to_string(offset_) + ")"; } + bool operator==(const Alignment& other) const { + return base_ == other.base_ && offset_ == other.offset_; + } + private: size_t base_; size_t offset_; @@ -96,6 +100,19 @@ class HVecOperation : public HVariableInputSizeInstruction { return GetPackedField<TypeField>(); } + // Assumes vector nodes cannot be moved by default. Each concrete implementation + // that can be moved should override this method and return true. + bool CanBeMoved() const OVERRIDE { return false; } + + // Tests if all data of a vector node (vector length and packed type) is equal. + // Each concrete implementation that adds more fields should test equality of + // those fields in its own method *and* call all super methods. + bool InstructionDataEquals(const HInstruction* other) const OVERRIDE { + DCHECK(other->IsVecOperation()); + const HVecOperation* o = other->AsVecOperation(); + return GetVectorLength() == o->GetVectorLength() && GetPackedType() == o->GetPackedType(); + } + DECLARE_ABSTRACT_INSTRUCTION(VecOperation); protected: @@ -189,6 +206,12 @@ class HVecMemoryOperation : public HVecOperation { HInstruction* GetArray() const { return InputAt(0); } HInstruction* GetIndex() const { return InputAt(1); } + bool InstructionDataEquals(const HInstruction* other) const OVERRIDE { + DCHECK(other->IsVecMemoryOperation()); + const HVecMemoryOperation* o = other->AsVecMemoryOperation(); + return HVecOperation::InstructionDataEquals(o) && GetAlignment() == o->GetAlignment(); + } + DECLARE_ABSTRACT_INSTRUCTION(VecMemoryOperation); private: @@ -231,7 +254,13 @@ class HVecReplicateScalar FINAL : public HVecUnaryOperation { : HVecUnaryOperation(arena, scalar, packed_type, vector_length, dex_pc) { DCHECK(!scalar->IsVecOperation()); } + + // A replicate needs to stay in place, since SIMD registers are not + // kept alive across vector loop boundaries (yet). + bool CanBeMoved() const OVERRIDE { return false; } + DECLARE_INSTRUCTION(VecReplicateScalar); + private: DISALLOW_COPY_AND_ASSIGN(HVecReplicateScalar); }; @@ -251,7 +280,10 @@ class HVecSumReduce FINAL : public HVecUnaryOperation { // TODO: probably integral promotion Primitive::Type GetType() const OVERRIDE { return GetPackedType(); } + bool CanBeMoved() const OVERRIDE { return true; } + DECLARE_INSTRUCTION(VecSumReduce); + private: DISALLOW_COPY_AND_ASSIGN(HVecSumReduce); }; @@ -273,6 +305,8 @@ class HVecCnv FINAL : public HVecUnaryOperation { Primitive::Type GetInputType() const { return InputAt(0)->AsVecOperation()->GetPackedType(); } Primitive::Type GetResultType() const { return GetPackedType(); } + bool CanBeMoved() const OVERRIDE { return true; } + DECLARE_INSTRUCTION(VecCnv); private: @@ -291,7 +325,11 @@ class HVecNeg FINAL : public HVecUnaryOperation { : HVecUnaryOperation(arena, input, packed_type, vector_length, dex_pc) { DCHECK(HasConsistentPackedTypes(input, packed_type)); } + + bool CanBeMoved() const OVERRIDE { return true; } + DECLARE_INSTRUCTION(VecNeg); + private: DISALLOW_COPY_AND_ASSIGN(HVecNeg); }; @@ -308,7 +346,11 @@ class HVecAbs FINAL : public HVecUnaryOperation { : HVecUnaryOperation(arena, input, packed_type, vector_length, dex_pc) { DCHECK(HasConsistentPackedTypes(input, packed_type)); } + + bool CanBeMoved() const OVERRIDE { return true; } + DECLARE_INSTRUCTION(VecAbs); + private: DISALLOW_COPY_AND_ASSIGN(HVecAbs); }; @@ -326,7 +368,11 @@ class HVecNot FINAL : public HVecUnaryOperation { : HVecUnaryOperation(arena, input, packed_type, vector_length, dex_pc) { DCHECK(input->IsVecOperation()); } + + bool CanBeMoved() const OVERRIDE { return true; } + DECLARE_INSTRUCTION(VecNot); + private: DISALLOW_COPY_AND_ASSIGN(HVecNot); }; @@ -349,7 +395,11 @@ class HVecAdd FINAL : public HVecBinaryOperation { DCHECK(HasConsistentPackedTypes(left, packed_type)); DCHECK(HasConsistentPackedTypes(right, packed_type)); } + + bool CanBeMoved() const OVERRIDE { return true; } + DECLARE_INSTRUCTION(VecAdd); + private: DISALLOW_COPY_AND_ASSIGN(HVecAdd); }; @@ -378,6 +428,16 @@ class HVecHalvingAdd FINAL : public HVecBinaryOperation { bool IsUnsigned() const { return GetPackedFlag<kFieldHAddIsUnsigned>(); } bool IsRounded() const { return GetPackedFlag<kFieldHAddIsRounded>(); } + bool CanBeMoved() const OVERRIDE { return true; } + + bool InstructionDataEquals(const HInstruction* other) const OVERRIDE { + DCHECK(other->IsVecHalvingAdd()); + const HVecHalvingAdd* o = other->AsVecHalvingAdd(); + return HVecOperation::InstructionDataEquals(o) && + IsUnsigned() == o->IsUnsigned() && + IsRounded() == o->IsRounded(); + } + DECLARE_INSTRUCTION(VecHalvingAdd); private: @@ -404,7 +464,11 @@ class HVecSub FINAL : public HVecBinaryOperation { DCHECK(HasConsistentPackedTypes(left, packed_type)); DCHECK(HasConsistentPackedTypes(right, packed_type)); } + + bool CanBeMoved() const OVERRIDE { return true; } + DECLARE_INSTRUCTION(VecSub); + private: DISALLOW_COPY_AND_ASSIGN(HVecSub); }; @@ -423,7 +487,11 @@ class HVecMul FINAL : public HVecBinaryOperation { DCHECK(HasConsistentPackedTypes(left, packed_type)); DCHECK(HasConsistentPackedTypes(right, packed_type)); } + + bool CanBeMoved() const OVERRIDE { return true; } + DECLARE_INSTRUCTION(VecMul); + private: DISALLOW_COPY_AND_ASSIGN(HVecMul); }; @@ -442,7 +510,11 @@ class HVecDiv FINAL : public HVecBinaryOperation { DCHECK(HasConsistentPackedTypes(left, packed_type)); DCHECK(HasConsistentPackedTypes(right, packed_type)); } + + bool CanBeMoved() const OVERRIDE { return true; } + DECLARE_INSTRUCTION(VecDiv); + private: DISALLOW_COPY_AND_ASSIGN(HVecDiv); }; @@ -466,6 +538,14 @@ class HVecMin FINAL : public HVecBinaryOperation { bool IsUnsigned() const { return GetPackedFlag<kFieldMinOpIsUnsigned>(); } + bool CanBeMoved() const OVERRIDE { return true; } + + bool InstructionDataEquals(const HInstruction* other) const OVERRIDE { + DCHECK(other->IsVecMin()); + const HVecMin* o = other->AsVecMin(); + return HVecOperation::InstructionDataEquals(o) && IsUnsigned() == o->IsUnsigned(); + } + DECLARE_INSTRUCTION(VecMin); private: @@ -496,6 +576,14 @@ class HVecMax FINAL : public HVecBinaryOperation { bool IsUnsigned() const { return GetPackedFlag<kFieldMaxOpIsUnsigned>(); } + bool CanBeMoved() const OVERRIDE { return true; } + + bool InstructionDataEquals(const HInstruction* other) const OVERRIDE { + DCHECK(other->IsVecMax()); + const HVecMax* o = other->AsVecMax(); + return HVecOperation::InstructionDataEquals(o) && IsUnsigned() == o->IsUnsigned(); + } + DECLARE_INSTRUCTION(VecMax); private: @@ -520,7 +608,11 @@ class HVecAnd FINAL : public HVecBinaryOperation { : HVecBinaryOperation(arena, left, right, packed_type, vector_length, dex_pc) { DCHECK(left->IsVecOperation() && right->IsVecOperation()); } + + bool CanBeMoved() const OVERRIDE { return true; } + DECLARE_INSTRUCTION(VecAnd); + private: DISALLOW_COPY_AND_ASSIGN(HVecAnd); }; @@ -538,7 +630,11 @@ class HVecAndNot FINAL : public HVecBinaryOperation { : HVecBinaryOperation(arena, left, right, packed_type, vector_length, dex_pc) { DCHECK(left->IsVecOperation() && right->IsVecOperation()); } + + bool CanBeMoved() const OVERRIDE { return true; } + DECLARE_INSTRUCTION(VecAndNot); + private: DISALLOW_COPY_AND_ASSIGN(HVecAndNot); }; @@ -556,7 +652,11 @@ class HVecOr FINAL : public HVecBinaryOperation { : HVecBinaryOperation(arena, left, right, packed_type, vector_length, dex_pc) { DCHECK(left->IsVecOperation() && right->IsVecOperation()); } + + bool CanBeMoved() const OVERRIDE { return true; } + DECLARE_INSTRUCTION(VecOr); + private: DISALLOW_COPY_AND_ASSIGN(HVecOr); }; @@ -574,7 +674,11 @@ class HVecXor FINAL : public HVecBinaryOperation { : HVecBinaryOperation(arena, left, right, packed_type, vector_length, dex_pc) { DCHECK(left->IsVecOperation() && right->IsVecOperation()); } + + bool CanBeMoved() const OVERRIDE { return true; } + DECLARE_INSTRUCTION(VecXor); + private: DISALLOW_COPY_AND_ASSIGN(HVecXor); }; @@ -592,7 +696,11 @@ class HVecShl FINAL : public HVecBinaryOperation { : HVecBinaryOperation(arena, left, right, packed_type, vector_length, dex_pc) { DCHECK(HasConsistentPackedTypes(left, packed_type)); } + + bool CanBeMoved() const OVERRIDE { return true; } + DECLARE_INSTRUCTION(VecShl); + private: DISALLOW_COPY_AND_ASSIGN(HVecShl); }; @@ -610,7 +718,11 @@ class HVecShr FINAL : public HVecBinaryOperation { : HVecBinaryOperation(arena, left, right, packed_type, vector_length, dex_pc) { DCHECK(HasConsistentPackedTypes(left, packed_type)); } + + bool CanBeMoved() const OVERRIDE { return true; } + DECLARE_INSTRUCTION(VecShr); + private: DISALLOW_COPY_AND_ASSIGN(HVecShr); }; @@ -628,7 +740,11 @@ class HVecUShr FINAL : public HVecBinaryOperation { : HVecBinaryOperation(arena, left, right, packed_type, vector_length, dex_pc) { DCHECK(HasConsistentPackedTypes(left, packed_type)); } + + bool CanBeMoved() const OVERRIDE { return true; } + DECLARE_INSTRUCTION(VecUShr); + private: DISALLOW_COPY_AND_ASSIGN(HVecUShr); }; @@ -656,7 +772,13 @@ class HVecSetScalars FINAL : public HVecOperation { SetRawInputAt(0, scalars[i]); } } + + // Setting scalars needs to stay in place, since SIMD registers are not + // kept alive across vector loop boundaries (yet). + bool CanBeMoved() const OVERRIDE { return false; } + DECLARE_INSTRUCTION(VecSetScalars); + private: DISALLOW_COPY_AND_ASSIGN(HVecSetScalars); }; @@ -697,7 +819,9 @@ class HVecMultiplyAccumulate FINAL : public HVecOperation { bool CanBeMoved() const OVERRIDE { return true; } bool InstructionDataEquals(const HInstruction* other) const OVERRIDE { - return op_kind_ == other->AsVecMultiplyAccumulate()->op_kind_; + DCHECK(other->IsVecMultiplyAccumulate()); + const HVecMultiplyAccumulate* o = other->AsVecMultiplyAccumulate(); + return HVecOperation::InstructionDataEquals(o) && GetOpKind() == o->GetOpKind(); } InstructionKind GetOpKind() const { return op_kind_; } @@ -732,10 +856,19 @@ class HVecLoad FINAL : public HVecMemoryOperation { SetRawInputAt(1, index); SetPackedFlag<kFieldIsStringCharAt>(is_string_char_at); } - DECLARE_INSTRUCTION(VecLoad); bool IsStringCharAt() const { return GetPackedFlag<kFieldIsStringCharAt>(); } + bool CanBeMoved() const OVERRIDE { return true; } + + bool InstructionDataEquals(const HInstruction* other) const OVERRIDE { + DCHECK(other->IsVecLoad()); + const HVecLoad* o = other->AsVecLoad(); + return HVecMemoryOperation::InstructionDataEquals(o) && IsStringCharAt() == o->IsStringCharAt(); + } + + DECLARE_INSTRUCTION(VecLoad); + private: // Additional packed bits. static constexpr size_t kFieldIsStringCharAt = HVecOperation::kNumberOfVectorOpPackedBits; @@ -767,7 +900,12 @@ class HVecStore FINAL : public HVecMemoryOperation { SetRawInputAt(1, index); SetRawInputAt(2, value); } + + // A store needs to stay in place. + bool CanBeMoved() const OVERRIDE { return false; } + DECLARE_INSTRUCTION(VecStore); + private: DISALLOW_COPY_AND_ASSIGN(HVecStore); }; diff --git a/compiler/optimizing/nodes_vector_test.cc b/compiler/optimizing/nodes_vector_test.cc new file mode 100644 index 0000000000..0238ea4602 --- /dev/null +++ b/compiler/optimizing/nodes_vector_test.cc @@ -0,0 +1,335 @@ +/* + * 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. + */ + +#include "base/arena_allocator.h" +#include "nodes.h" +#include "optimizing_unit_test.h" + +namespace art { + +/** + * Fixture class for testing vector nodes. + */ +class NodesVectorTest : public CommonCompilerTest { + public: + NodesVectorTest() + : pool_(), + allocator_(&pool_), + graph_(CreateGraph(&allocator_)) { + BuildGraph(); + } + + ~NodesVectorTest() { } + + void BuildGraph() { + graph_->SetNumberOfVRegs(1); + entry_block_ = new (&allocator_) HBasicBlock(graph_); + exit_block_ = new (&allocator_) HBasicBlock(graph_); + graph_->AddBlock(entry_block_); + graph_->AddBlock(exit_block_); + graph_->SetEntryBlock(entry_block_); + graph_->SetExitBlock(exit_block_); + parameter_ = new (&allocator_) HParameterValue(graph_->GetDexFile(), + dex::TypeIndex(0), + 0, + Primitive::kPrimInt); + entry_block_->AddInstruction(parameter_); + } + + // General building fields. + ArenaPool pool_; + ArenaAllocator allocator_; + HGraph* graph_; + + HBasicBlock* entry_block_; + HBasicBlock* exit_block_; + + HInstruction* parameter_; +}; + +// +// The actual vector nodes tests. +// + +TEST(NodesVector, Alignment) { + EXPECT_TRUE(Alignment(1, 0).IsAlignedAt(1)); + EXPECT_FALSE(Alignment(1, 0).IsAlignedAt(2)); + + EXPECT_TRUE(Alignment(2, 0).IsAlignedAt(1)); + EXPECT_TRUE(Alignment(2, 1).IsAlignedAt(1)); + EXPECT_TRUE(Alignment(2, 0).IsAlignedAt(2)); + EXPECT_FALSE(Alignment(2, 1).IsAlignedAt(2)); + EXPECT_FALSE(Alignment(2, 0).IsAlignedAt(4)); + EXPECT_FALSE(Alignment(2, 1).IsAlignedAt(4)); + + EXPECT_TRUE(Alignment(4, 0).IsAlignedAt(1)); + EXPECT_TRUE(Alignment(4, 2).IsAlignedAt(1)); + EXPECT_TRUE(Alignment(4, 0).IsAlignedAt(2)); + EXPECT_TRUE(Alignment(4, 2).IsAlignedAt(2)); + EXPECT_TRUE(Alignment(4, 0).IsAlignedAt(4)); + EXPECT_FALSE(Alignment(4, 2).IsAlignedAt(4)); + EXPECT_FALSE(Alignment(4, 0).IsAlignedAt(8)); + EXPECT_FALSE(Alignment(4, 2).IsAlignedAt(8)); + + EXPECT_TRUE(Alignment(16, 0).IsAlignedAt(1)); + EXPECT_TRUE(Alignment(16, 0).IsAlignedAt(2)); + EXPECT_TRUE(Alignment(16, 0).IsAlignedAt(4)); + EXPECT_TRUE(Alignment(16, 8).IsAlignedAt(8)); + EXPECT_TRUE(Alignment(16, 0).IsAlignedAt(16)); + EXPECT_FALSE(Alignment(16, 1).IsAlignedAt(16)); + EXPECT_FALSE(Alignment(16, 7).IsAlignedAt(16)); + EXPECT_FALSE(Alignment(16, 0).IsAlignedAt(32)); +} + +TEST(NodesVector, AlignmentEQ) { + EXPECT_TRUE(Alignment(2, 0) == Alignment(2, 0)); + EXPECT_TRUE(Alignment(2, 1) == Alignment(2, 1)); + EXPECT_TRUE(Alignment(4, 0) == Alignment(4, 0)); + EXPECT_TRUE(Alignment(4, 2) == Alignment(4, 2)); + + EXPECT_FALSE(Alignment(4, 0) == Alignment(2, 0)); + EXPECT_FALSE(Alignment(4, 0) == Alignment(4, 1)); + EXPECT_FALSE(Alignment(4, 0) == Alignment(8, 0)); +} + +TEST(NodesVector, AlignmentString) { + EXPECT_STREQ("ALIGN(1,0)", Alignment(1, 0).ToString().c_str()); + + EXPECT_STREQ("ALIGN(2,0)", Alignment(2, 0).ToString().c_str()); + EXPECT_STREQ("ALIGN(2,1)", Alignment(2, 1).ToString().c_str()); + + EXPECT_STREQ("ALIGN(16,0)", Alignment(16, 0).ToString().c_str()); + EXPECT_STREQ("ALIGN(16,1)", Alignment(16, 1).ToString().c_str()); + EXPECT_STREQ("ALIGN(16,8)", Alignment(16, 8).ToString().c_str()); + EXPECT_STREQ("ALIGN(16,9)", Alignment(16, 9).ToString().c_str()); +} + +TEST_F(NodesVectorTest, VectorOperationProperties) { + HVecOperation* v0 = new (&allocator_) + HVecReplicateScalar(&allocator_, parameter_, Primitive::kPrimInt, 4); + HVecOperation* v1 = new (&allocator_) + HVecReplicateScalar(&allocator_, parameter_, Primitive::kPrimInt, 4); + HVecOperation* v2 = new (&allocator_) + HVecReplicateScalar(&allocator_, parameter_, Primitive::kPrimInt, 2); + HVecOperation* v3 = new (&allocator_) + HVecReplicateScalar(&allocator_, parameter_, Primitive::kPrimShort, 4); + HVecOperation* v4 = new (&allocator_) + HVecStore(&allocator_, parameter_, parameter_, v0, Primitive::kPrimInt, 4); + + EXPECT_TRUE(v0->Equals(v0)); + EXPECT_TRUE(v1->Equals(v1)); + EXPECT_TRUE(v2->Equals(v2)); + EXPECT_TRUE(v3->Equals(v3)); + EXPECT_TRUE(v4->Equals(v4)); + + EXPECT_TRUE(v0->Equals(v1)); + EXPECT_FALSE(v0->Equals(v2)); // different vector lengths + EXPECT_FALSE(v0->Equals(v3)); // different packed types + EXPECT_FALSE(v0->Equals(v4)); // different kinds + + EXPECT_TRUE(v1->Equals(v0)); // switch operands + EXPECT_FALSE(v4->Equals(v0)); + + EXPECT_EQ(4u, v0->GetVectorLength()); + EXPECT_EQ(4u, v1->GetVectorLength()); + EXPECT_EQ(2u, v2->GetVectorLength()); + EXPECT_EQ(4u, v3->GetVectorLength()); + EXPECT_EQ(4u, v4->GetVectorLength()); + + EXPECT_EQ(Primitive::kPrimDouble, v0->GetType()); + EXPECT_EQ(Primitive::kPrimDouble, v1->GetType()); + EXPECT_EQ(Primitive::kPrimDouble, v2->GetType()); + EXPECT_EQ(Primitive::kPrimDouble, v3->GetType()); + EXPECT_EQ(Primitive::kPrimDouble, v4->GetType()); + + EXPECT_EQ(Primitive::kPrimInt, v0->GetPackedType()); + EXPECT_EQ(Primitive::kPrimInt, v1->GetPackedType()); + EXPECT_EQ(Primitive::kPrimInt, v2->GetPackedType()); + EXPECT_EQ(Primitive::kPrimShort, v3->GetPackedType()); + EXPECT_EQ(Primitive::kPrimInt, v4->GetPackedType()); + + EXPECT_EQ(16u, v0->GetVectorNumberOfBytes()); + EXPECT_EQ(16u, v1->GetVectorNumberOfBytes()); + EXPECT_EQ(8u, v2->GetVectorNumberOfBytes()); + EXPECT_EQ(8u, v3->GetVectorNumberOfBytes()); + EXPECT_EQ(16u, v4->GetVectorNumberOfBytes()); + + EXPECT_FALSE(v0->CanBeMoved()); + EXPECT_FALSE(v1->CanBeMoved()); + EXPECT_FALSE(v2->CanBeMoved()); + EXPECT_FALSE(v3->CanBeMoved()); + EXPECT_FALSE(v4->CanBeMoved()); +} + +TEST_F(NodesVectorTest, VectorAlignmentAndStringCharAtMatterOnLoad) { + HVecLoad* v0 = new (&allocator_) + HVecLoad(&allocator_, parameter_, parameter_, Primitive::kPrimInt, 4, /*is_string_char_at*/ false); + HVecLoad* v1 = new (&allocator_) + HVecLoad(&allocator_, parameter_, parameter_, Primitive::kPrimInt, 4, /*is_string_char_at*/ false); + HVecLoad* v2 = new (&allocator_) + HVecLoad(&allocator_, parameter_, parameter_, Primitive::kPrimInt, 4, /*is_string_char_at*/ true); + + EXPECT_TRUE(v0->CanBeMoved()); + EXPECT_TRUE(v1->CanBeMoved()); + EXPECT_TRUE(v2->CanBeMoved()); + + EXPECT_FALSE(v0->IsStringCharAt()); + EXPECT_FALSE(v1->IsStringCharAt()); + EXPECT_TRUE(v2->IsStringCharAt()); + + EXPECT_TRUE(v0->Equals(v0)); + EXPECT_TRUE(v1->Equals(v1)); + EXPECT_TRUE(v2->Equals(v2)); + + EXPECT_TRUE(v0->Equals(v1)); + EXPECT_FALSE(v0->Equals(v2)); + + EXPECT_TRUE(v0->GetAlignment() == Alignment(4, 0)); + EXPECT_TRUE(v1->GetAlignment() == Alignment(4, 0)); + EXPECT_TRUE(v2->GetAlignment() == Alignment(4, 0)); + + v1->SetAlignment(Alignment(8, 0)); + + EXPECT_TRUE(v1->GetAlignment() == Alignment(8, 0)); + + EXPECT_FALSE(v0->Equals(v1)); // no longer equal +} + +TEST_F(NodesVectorTest, VectorSignMattersOnMin) { + HVecOperation* v0 = new (&allocator_) + HVecReplicateScalar(&allocator_, parameter_, Primitive::kPrimInt, 4); + + HVecMin* v1 = new (&allocator_) + HVecMin(&allocator_, v0, v0, Primitive::kPrimInt, 4, /*is_unsigned*/ true); + HVecMin* v2 = new (&allocator_) + HVecMin(&allocator_, v0, v0, Primitive::kPrimInt, 4, /*is_unsigned*/ false); + HVecMin* v3 = new (&allocator_) + HVecMin(&allocator_, v0, v0, Primitive::kPrimInt, 2, /*is_unsigned*/ true); + + EXPECT_FALSE(v0->CanBeMoved()); + EXPECT_TRUE(v1->CanBeMoved()); + EXPECT_TRUE(v2->CanBeMoved()); + EXPECT_TRUE(v3->CanBeMoved()); + + EXPECT_TRUE(v1->IsUnsigned()); + EXPECT_FALSE(v2->IsUnsigned()); + EXPECT_TRUE(v3->IsUnsigned()); + + EXPECT_TRUE(v1->Equals(v1)); + EXPECT_TRUE(v2->Equals(v2)); + EXPECT_TRUE(v3->Equals(v3)); + + EXPECT_FALSE(v1->Equals(v2)); // different signs + EXPECT_FALSE(v1->Equals(v3)); // different vector lengths +} + +TEST_F(NodesVectorTest, VectorSignMattersOnMax) { + HVecOperation* v0 = new (&allocator_) + HVecReplicateScalar(&allocator_, parameter_, Primitive::kPrimInt, 4); + + HVecMax* v1 = new (&allocator_) + HVecMax(&allocator_, v0, v0, Primitive::kPrimInt, 4, /*is_unsigned*/ true); + HVecMax* v2 = new (&allocator_) + HVecMax(&allocator_, v0, v0, Primitive::kPrimInt, 4, /*is_unsigned*/ false); + HVecMax* v3 = new (&allocator_) + HVecMax(&allocator_, v0, v0, Primitive::kPrimInt, 2, /*is_unsigned*/ true); + + EXPECT_FALSE(v0->CanBeMoved()); + EXPECT_TRUE(v1->CanBeMoved()); + EXPECT_TRUE(v2->CanBeMoved()); + EXPECT_TRUE(v3->CanBeMoved()); + + EXPECT_TRUE(v1->IsUnsigned()); + EXPECT_FALSE(v2->IsUnsigned()); + EXPECT_TRUE(v3->IsUnsigned()); + + EXPECT_TRUE(v1->Equals(v1)); + EXPECT_TRUE(v2->Equals(v2)); + EXPECT_TRUE(v3->Equals(v3)); + + EXPECT_FALSE(v1->Equals(v2)); // different signs + EXPECT_FALSE(v1->Equals(v3)); // different vector lengths +} + +TEST_F(NodesVectorTest, VectorAttributesMatterOnHalvingAdd) { + HVecOperation* v0 = new (&allocator_) + HVecReplicateScalar(&allocator_, parameter_, Primitive::kPrimInt, 4); + + HVecHalvingAdd* v1 = new (&allocator_) HVecHalvingAdd( + &allocator_, v0, v0, Primitive::kPrimInt, 4, /*is_unsigned*/ true, /*is_rounded*/ true); + HVecHalvingAdd* v2 = new (&allocator_) HVecHalvingAdd( + &allocator_, v0, v0, Primitive::kPrimInt, 4, /*is_unsigned*/ true, /*is_rounded*/ false); + HVecHalvingAdd* v3 = new (&allocator_) HVecHalvingAdd( + &allocator_, v0, v0, Primitive::kPrimInt, 4, /*is_unsigned*/ false, /*is_rounded*/ true); + HVecHalvingAdd* v4 = new (&allocator_) HVecHalvingAdd( + &allocator_, v0, v0, Primitive::kPrimInt, 4, /*is_unsigned*/ false, /*is_rounded*/ false); + HVecHalvingAdd* v5 = new (&allocator_) HVecHalvingAdd( + &allocator_, v0, v0, Primitive::kPrimInt, 2, /*is_unsigned*/ true, /*is_rounded*/ true); + + EXPECT_FALSE(v0->CanBeMoved()); + EXPECT_TRUE(v1->CanBeMoved()); + EXPECT_TRUE(v2->CanBeMoved()); + EXPECT_TRUE(v3->CanBeMoved()); + EXPECT_TRUE(v4->CanBeMoved()); + EXPECT_TRUE(v5->CanBeMoved()); + + EXPECT_TRUE(v1->Equals(v1)); + EXPECT_TRUE(v2->Equals(v2)); + EXPECT_TRUE(v3->Equals(v3)); + EXPECT_TRUE(v4->Equals(v4)); + EXPECT_TRUE(v5->Equals(v5)); + + EXPECT_TRUE(v1->IsUnsigned() && v1->IsRounded()); + EXPECT_TRUE(v2->IsUnsigned() && !v2->IsRounded()); + EXPECT_TRUE(!v3->IsUnsigned() && v3->IsRounded()); + EXPECT_TRUE(!v4->IsUnsigned() && !v4->IsRounded()); + EXPECT_TRUE(v5->IsUnsigned() && v5->IsRounded()); + + EXPECT_FALSE(v1->Equals(v2)); // different attributes + EXPECT_FALSE(v1->Equals(v3)); // different attributes + EXPECT_FALSE(v1->Equals(v4)); // different attributes + EXPECT_FALSE(v1->Equals(v5)); // different vector lengths +} + +TEST_F(NodesVectorTest, VectorOperationMattersOnMultiplyAccumulate) { + HVecOperation* v0 = new (&allocator_) + HVecReplicateScalar(&allocator_, parameter_, Primitive::kPrimInt, 4); + + HVecMultiplyAccumulate* v1 = new (&allocator_) + HVecMultiplyAccumulate(&allocator_, HInstruction::kAdd, v0, v0, v0, Primitive::kPrimInt, 4); + HVecMultiplyAccumulate* v2 = new (&allocator_) + HVecMultiplyAccumulate(&allocator_, HInstruction::kSub, v0, v0, v0, Primitive::kPrimInt, 4); + HVecMultiplyAccumulate* v3 = new (&allocator_) + HVecMultiplyAccumulate(&allocator_, HInstruction::kAdd, v0, v0, v0, Primitive::kPrimInt, 2); + + EXPECT_FALSE(v0->CanBeMoved()); + EXPECT_TRUE(v1->CanBeMoved()); + EXPECT_TRUE(v2->CanBeMoved()); + EXPECT_TRUE(v3->CanBeMoved()); + + EXPECT_EQ(HInstruction::kAdd, v1->GetOpKind()); + EXPECT_EQ(HInstruction::kSub, v2->GetOpKind()); + EXPECT_EQ(HInstruction::kAdd, v3->GetOpKind()); + + EXPECT_TRUE(v1->Equals(v1)); + EXPECT_TRUE(v2->Equals(v2)); + EXPECT_TRUE(v3->Equals(v3)); + + EXPECT_FALSE(v1->Equals(v2)); // different operators + EXPECT_FALSE(v1->Equals(v3)); // different vector lengths +} + +} // namespace art diff --git a/runtime/gc/space/image_space.cc b/runtime/gc/space/image_space.cc index b229b6cffd..3ae382e36f 100644 --- a/runtime/gc/space/image_space.cc +++ b/runtime/gc/space/image_space.cc @@ -1012,7 +1012,7 @@ class ImageSpaceLoader { mirror::Class* klass = obj->AsClass<kVerifyNone, kWithoutReadBarrier>(); // Fixup super class before visiting instance fields which require // information from their super class to calculate offsets. - mirror::Class* super_class = klass->GetSuperClass(); + mirror::Class* super_class = klass->GetSuperClass<kVerifyNone, kWithoutReadBarrier>(); if (super_class != nullptr) { mirror::Class* new_super_class = down_cast<mirror::Class*>(ForwardObject(super_class)); if (new_super_class != super_class && IsInAppImage(new_super_class)) { |