diff options
-rw-r--r-- | compiler/common_compiler_test.cc | 10 | ||||
-rw-r--r-- | compiler/common_compiler_test.h | 8 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_arm64.cc | 10 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_arm64.h | 2 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_vector_arm64_sve.cc | 8 | ||||
-rw-r--r-- | compiler/optimizing/codegen_test.cc | 44 | ||||
-rw-r--r-- | compiler/optimizing/load_store_analysis_test.cc | 27 | ||||
-rw-r--r-- | compiler/optimizing/nodes_vector.h | 5 | ||||
-rw-r--r-- | compiler/optimizing/optimizing_unit_test.h | 47 | ||||
-rw-r--r-- | simulator/code_simulator_arm64.cc | 1 |
10 files changed, 144 insertions, 18 deletions
diff --git a/compiler/common_compiler_test.cc b/compiler/common_compiler_test.cc index 392a0d1001..d627af8158 100644 --- a/compiler/common_compiler_test.cc +++ b/compiler/common_compiler_test.cc @@ -186,7 +186,9 @@ class CommonCompilerTestImpl::OneCompiledMethodStorage final : public CompiledCo }; std::unique_ptr<CompilerOptions> CommonCompilerTestImpl::CreateCompilerOptions( - InstructionSet instruction_set, const std::string& variant) { + InstructionSet instruction_set, + const std::string& variant, + const std::optional<std::string>& extra_features) { std::unique_ptr<CompilerOptions> compiler_options = std::make_unique<CompilerOptions>(); compiler_options->emit_read_barrier_ = gUseReadBarrier; compiler_options->instruction_set_ = instruction_set; @@ -194,6 +196,12 @@ std::unique_ptr<CompilerOptions> CommonCompilerTestImpl::CreateCompilerOptions( compiler_options->instruction_set_features_ = InstructionSetFeatures::FromVariant(instruction_set, variant, &error_msg); CHECK(compiler_options->instruction_set_features_ != nullptr) << error_msg; + if (extra_features) { + compiler_options->instruction_set_features_ = + compiler_options->instruction_set_features_->AddFeaturesFromString(*extra_features, + &error_msg); + CHECK_NE(compiler_options->instruction_set_features_, nullptr) << error_msg; + } return compiler_options; } diff --git a/compiler/common_compiler_test.h b/compiler/common_compiler_test.h index 32a5234797..80b26eefe9 100644 --- a/compiler/common_compiler_test.h +++ b/compiler/common_compiler_test.h @@ -44,8 +44,12 @@ template<class T> class Handle; // Export all symbols in `CommonCompilerTestImpl` for dex2oat tests. class EXPORT CommonCompilerTestImpl { public: - static std::unique_ptr<CompilerOptions> CreateCompilerOptions(InstructionSet instruction_set, - const std::string& variant); + // Create compiler options from the given instruction set and variant. Optionally use a string of + // instruction set features in addition to the features from the variant. + static std::unique_ptr<CompilerOptions> CreateCompilerOptions( + InstructionSet instruction_set, + const std::string& variant, + const std::optional<std::string>& extra_features = std::nullopt); CommonCompilerTestImpl(); virtual ~CommonCompilerTestImpl(); diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc index d56146eb0e..13d126d3d4 100644 --- a/compiler/optimizing/code_generator_arm64.cc +++ b/compiler/optimizing/code_generator_arm64.cc @@ -138,6 +138,16 @@ inline Condition ARM64FPCondition(IfCondition cond, bool gt_bias) { } } +Condition ARM64PCondition(HVecPredToBoolean::PCondKind cond) { + switch (cond) { + case HVecPredToBoolean::PCondKind::kFirst: return mi; + case HVecPredToBoolean::PCondKind::kNFirst: return pl; + default: + LOG(FATAL) << "Unsupported condition type: " << enum_cast<uint32_t>(cond); + UNREACHABLE(); + } +} + Location ARM64ReturnLocation(DataType::Type return_type) { // Note that in practice, `LocationFrom(x0)` and `LocationFrom(w0)` create the // same Location object, and so do `LocationFrom(d0)` and `LocationFrom(s0)`, diff --git a/compiler/optimizing/code_generator_arm64.h b/compiler/optimizing/code_generator_arm64.h index c6427b2da3..11c130ce2d 100644 --- a/compiler/optimizing/code_generator_arm64.h +++ b/compiler/optimizing/code_generator_arm64.h @@ -130,6 +130,8 @@ const vixl::aarch64::CPURegList callee_saved_fp_registers(vixl::aarch64::CPURegi vixl::aarch64::d15.GetCode()); Location ARM64ReturnLocation(DataType::Type return_type); +vixl::aarch64::Condition ARM64PCondition(HVecPredToBoolean::PCondKind cond); + #define UNIMPLEMENTED_INTRINSIC_LIST_ARM64(V) \ V(MathSignumFloat) \ V(MathSignumDouble) \ diff --git a/compiler/optimizing/code_generator_vector_arm64_sve.cc b/compiler/optimizing/code_generator_vector_arm64_sve.cc index ef79932899..ccff02e6b6 100644 --- a/compiler/optimizing/code_generator_vector_arm64_sve.cc +++ b/compiler/optimizing/code_generator_vector_arm64_sve.cc @@ -1335,10 +1335,10 @@ void InstructionCodeGeneratorARM64Sve::VisitVecPredToBoolean(HVecPredToBoolean* // Instruction is not predicated, see nodes_vector.h DCHECK(!instruction->IsPredicated()); Register reg = OutputRegister(instruction); - // Currently VecPredToBoolean is only used as part of vectorized loop check condition - // evaluation. - DCHECK(instruction->GetPCondKind() == HVecPredToBoolean::PCondKind::kNFirst); - __ Cset(reg, pl); + HInstruction *input = instruction->InputAt(0); + const PRegister output_p_reg = GetVecPredSetFixedOutPReg(input->AsVecPredSetOperation()); + __ Ptest(output_p_reg, output_p_reg.VnB()); + __ Cset(reg, ARM64PCondition(instruction->GetPCondKind())); } Location InstructionCodeGeneratorARM64Sve::AllocateSIMDScratchLocation( diff --git a/compiler/optimizing/codegen_test.cc b/compiler/optimizing/codegen_test.cc index 75b0ea2a08..4f8551ab87 100644 --- a/compiler/optimizing/codegen_test.cc +++ b/compiler/optimizing/codegen_test.cc @@ -932,6 +932,50 @@ TEST_F(CodegenTest, ARM64FrameSizeNoSIMD) { EXPECT_EQ(codegen.GetFpuSpillSize(), kExpectedFPSpillSize); } +// This test checks that the result of the VecPredToBoolean instruction doesn't depend on +// conditional flags that can be updated by other instructions. For example: +// +// VecPredWhile p0, opa, opb +// Below opb, opa +// VecPredToBoolean p0 +// +// where Below updates conditions flags after VecPredWhile. +TEST_F(CodegenTest, ARM64SvePredicateToBoolean) { + std::unique_ptr<CompilerOptions> compiler_options = + CommonCompilerTest::CreateCompilerOptions(InstructionSet::kArm64, "default", "sve"); + for (int i = 0; i < 2; i++) { + for (int j = 0; j < 2; j++) { + HBasicBlock* block = InitEntryMainExitGraph(); + TestCodeGeneratorARM64 codegen(graph_, *compiler_options); + if (!codegen.SupportsPredicatedSIMD()) { + GTEST_SKIP() << "Predicated SIMD is not supported."; + } + + HInstruction *opa = graph_->GetIntConstant(i); + HInstruction *opb = graph_->GetIntConstant(j); + HVecPredWhile *pred_while = MakeVecPredWhile(block, + opa, + opb, + HVecPredWhile::CondKind::kLO, + DataType::Type::kInt32); + // Update condition flags by using Below instruction. + MakeCondition(block, IfCondition::kCondB, opb, opa); + HVecPredToBoolean *boolean = MakeVecPredToBoolean(block, + pred_while, + HVecPredToBoolean::PCondKind::kNFirst, + DataType::Type::kInt32); + MakeReturn(block, boolean); + + graph_->SetHasPredicatedSIMD(true); + graph_->BuildDominatorTree(); + + if (CanExecute(codegen)) { + RunCode(&codegen, graph_, [](HGraph*) {}, true, i >= j); + } + } + } +} + #endif } // namespace art diff --git a/compiler/optimizing/load_store_analysis_test.cc b/compiler/optimizing/load_store_analysis_test.cc index b6a7cd9c76..7c2e918d23 100644 --- a/compiler/optimizing/load_store_analysis_test.cc +++ b/compiler/optimizing/load_store_analysis_test.cc @@ -226,6 +226,9 @@ TEST_F(LoadStoreAnalysisTest, ArrayIndexAliasingTest) { } TEST_F(LoadStoreAnalysisTest, ArrayAliasingTest) { + constexpr size_t vlen1 = kDefaultTestVectorSize; + constexpr size_t vlen2 = vlen1 / 2; + HBasicBlock* main = InitEntryMainExitGraphWithReturnVoid(); HInstruction* array = MakeParam(DataType::Type::kReference); @@ -242,26 +245,32 @@ TEST_F(LoadStoreAnalysisTest, ArrayAliasingTest) { HVecOperation* v1 = new (GetAllocator()) HVecReplicateScalar(GetAllocator(), c1, DataType::Type::kInt32, - 4, + vlen1, kNoDexPc); AddOrInsertInstruction(main, v1); HVecOperation* v2 = new (GetAllocator()) HVecReplicateScalar(GetAllocator(), c1, DataType::Type::kInt32, - 2, + vlen2, kNoDexPc); AddOrInsertInstruction(main, v2); HInstruction* i_add6 = MakeBinOp<HAdd>(main, DataType::Type::kInt32, index, c6); HInstruction* i_add8 = MakeBinOp<HAdd>(main, DataType::Type::kInt32, index, c8); - HInstruction* vstore_0 = MakeVecStore(main, array, c0, v1, DataType::Type::kInt32); - HInstruction* vstore_1 = MakeVecStore(main, array, c1, v1, DataType::Type::kInt32); - HInstruction* vstore_8 = MakeVecStore(main, array, c8, v1, DataType::Type::kInt32); - HInstruction* vstore_i = MakeVecStore(main, array, index, v1, DataType::Type::kInt32); - HInstruction* vstore_i_add6 = MakeVecStore(main, array, i_add6, v1, DataType::Type::kInt32); - HInstruction* vstore_i_add8 = MakeVecStore(main, array, i_add8, v1, DataType::Type::kInt32); + HInstruction* vstore_0 = + MakeVecStore(main, array, c0, v1, DataType::Type::kInt32, vlen1); + HInstruction* vstore_1 = + MakeVecStore(main, array, c1, v1, DataType::Type::kInt32, vlen1); + HInstruction* vstore_8 = + MakeVecStore(main, array, c8, v1, DataType::Type::kInt32, vlen1); + HInstruction* vstore_i = + MakeVecStore(main, array, index, v1, DataType::Type::kInt32, vlen1); + HInstruction* vstore_i_add6 = + MakeVecStore(main, array, i_add6, v1, DataType::Type::kInt32, vlen1); + HInstruction* vstore_i_add8 = + MakeVecStore(main, array, i_add8, v1, DataType::Type::kInt32, vlen1); HInstruction* vstore_i_add6_vlen2 = - MakeVecStore(main, array, i_add6, v2, DataType::Type::kInt32, /*vector_lengt=*/ 2); + MakeVecStore(main, array, i_add6, v2, DataType::Type::kInt32, vlen2); graph_->BuildDominatorTree(); ScopedArenaAllocator allocator(graph_->GetArenaStack()); diff --git a/compiler/optimizing/nodes_vector.h b/compiler/optimizing/nodes_vector.h index 6a60d6be01..a5f5720f7e 100644 --- a/compiler/optimizing/nodes_vector.h +++ b/compiler/optimizing/nodes_vector.h @@ -1529,6 +1529,11 @@ class HVecPredNot final : public HVecPredSetOperation { DEFAULT_COPY_CONSTRUCTOR(VecPredNot); }; +// Return the number of elements of the given type that will fit into a vector of given size. +inline size_t GetNumberOfElementsInVector(size_t vector_size_in_bytes, DataType::Type type) { + return vector_size_in_bytes / DataType::Size(type); +} + } // namespace art #endif // ART_COMPILER_OPTIMIZING_NODES_VECTOR_H_ diff --git a/compiler/optimizing/optimizing_unit_test.h b/compiler/optimizing/optimizing_unit_test.h index a7c3558c5f..e2f3e0a510 100644 --- a/compiler/optimizing/optimizing_unit_test.h +++ b/compiler/optimizing/optimizing_unit_test.h @@ -632,15 +632,54 @@ class OptimizingUnitTestHelper { HInstruction* index, HInstruction* value, DataType::Type packed_type, - size_t vector_length = 4, + size_t vector_size_in_bytes = kDefaultTestVectorSize, uint32_t dex_pc = kNoDexPc) { + size_t num_of_elements = GetNumberOfElementsInVector(vector_size_in_bytes, packed_type); SideEffects side_effects = SideEffects::ArrayWriteOfType(packed_type); HVecStore* vec_store = new (GetAllocator()) HVecStore( - GetAllocator(), base, index, value, packed_type, side_effects, vector_length, dex_pc); + GetAllocator(), base, index, value, packed_type, side_effects, num_of_elements, dex_pc); AddOrInsertInstruction(block, vec_store); return vec_store; } + HVecPredToBoolean* MakeVecPredToBoolean(HBasicBlock* block, + HInstruction* input, + HVecPredToBoolean::PCondKind pred_cond, + DataType::Type packed_type, + size_t vector_size_in_bytes = kDefaultTestVectorSize, + uint32_t dex_pc = kNoDexPc) { + size_t num_of_elements = GetNumberOfElementsInVector(vector_size_in_bytes, packed_type); + HVecPredToBoolean* vec_pred_to_boolean = new (GetAllocator()) HVecPredToBoolean( + GetAllocator(), + input, + pred_cond, + packed_type, + num_of_elements, + dex_pc); + AddOrInsertInstruction(block, vec_pred_to_boolean); + return vec_pred_to_boolean; + } + + HVecPredWhile* MakeVecPredWhile(HBasicBlock* block, + HInstruction* left, + HInstruction* right, + HVecPredWhile::CondKind cond, + DataType::Type packed_type, + size_t vector_size_in_bytes = kDefaultTestVectorSize, + uint32_t dex_pc = kNoDexPc) { + size_t num_of_elements = GetNumberOfElementsInVector(vector_size_in_bytes, packed_type); + HVecPredWhile* vec_pred_while = new (GetAllocator()) HVecPredWhile( + GetAllocator(), + left, + right, + cond, + packed_type, + num_of_elements, + dex_pc); + AddOrInsertInstruction(block, vec_pred_while); + return vec_pred_while; + } + HInvokeStaticOrDirect* MakeInvokeStatic(HBasicBlock* block, DataType::Type return_type, const std::vector<HInstruction*>& args, @@ -836,6 +875,10 @@ class OptimizingUnitTestHelper { size_t class_idx_ = 42; uint32_t method_idx_ = 100; + // The default size of vectors to use for tests, in bytes. 16 bytes (128 bits) is used as it is + // commonly the smallest size of vector used in vector extensions. + static constexpr size_t kDefaultTestVectorSize = 16; + ScopedNullHandle<mirror::Class> null_klass_; }; diff --git a/simulator/code_simulator_arm64.cc b/simulator/code_simulator_arm64.cc index 32ca005a76..08a5deae1f 100644 --- a/simulator/code_simulator_arm64.cc +++ b/simulator/code_simulator_arm64.cc @@ -47,6 +47,7 @@ CodeSimulatorArm64::CodeSimulatorArm64() SimStack::Allocated stack = stack_builder.Allocate(); simulator_ = new Simulator(decoder_, stdout, std::move(stack)); + simulator_->SetVectorLengthInBits(kArm64DefaultSVEVectorLength); } CodeSimulatorArm64::~CodeSimulatorArm64() { |