From 4018a7d772fc09c7955eb4c88eea788be5cc2143 Mon Sep 17 00:00:00 2001 From: Vladimir Marko Date: Tue, 6 Aug 2024 07:54:26 +0000 Subject: ART: Clean up HIR construction in gtests. Make `OptimizingUnitTestHelper::Make*()` functions add the the new instruction to the block. If the block already ends with a control flow instruction, the new instruction is inserted before the control flow instruction (some tests create the control flow before adding instruction). Add new helper functions for additional instruction types, rename and clean up existing helpers. Test: m test-art-host-gtest Change-Id: I0bb88bc4d2ff6ce98ddbec25990a1ae68f582042 --- compiler/optimizing/optimizing_unit_test.h | 282 ++++++++++++++++++++++------- 1 file changed, 220 insertions(+), 62 deletions(-) (limited to 'compiler/optimizing/optimizing_unit_test.h') diff --git a/compiler/optimizing/optimizing_unit_test.h b/compiler/optimizing/optimizing_unit_test.h index e1d8969b2b..b256d439fb 100644 --- a/compiler/optimizing/optimizing_unit_test.h +++ b/compiler/optimizing/optimizing_unit_test.h @@ -306,11 +306,6 @@ class OptimizingUnitTestHelper { exit_block_->AddInstruction(new (GetAllocator()) HExit()); } - void AddParameter(HInstruction* parameter) { - entry_block_->AddInstruction(parameter); - parameters_.push_back(parameter); - } - HBasicBlock* AddNewBlock() { HBasicBlock* block = new (GetAllocator()) HBasicBlock(graph_); graph_->AddBlock(block); @@ -391,68 +386,167 @@ class OptimizingUnitTestHelper { OptimizingUnitTestHelper::ManuallyBuildEnvFor(ins, ¤t_locals); } - HLoadClass* MakeClassLoad(std::optional ti = std::nullopt, - std::optional> klass = std::nullopt) { - return new (GetAllocator()) HLoadClass(graph_->GetCurrentMethod(), - ti ? *ti : dex::TypeIndex(class_idx_++), - graph_->GetDexFile(), - /* klass= */ klass ? *klass : null_klass_, - /* is_referrers_class= */ false, - /* dex_pc= */ 0, - /* needs_access_check= */ false); + HLoadClass* MakeLoadClass(HBasicBlock* block, + std::optional ti = std::nullopt, + std::optional> klass = std::nullopt, + uint32_t dex_pc = kNoDexPc) { + HLoadClass* load_class = new (GetAllocator()) HLoadClass( + graph_->GetCurrentMethod(), + ti ? *ti : dex::TypeIndex(class_idx_++), + graph_->GetDexFile(), + /* klass= */ klass ? *klass : null_klass_, + /* is_referrers_class= */ false, + dex_pc, + /* needs_access_check= */ false); + AddOrInsertInstruction(block, load_class); + return load_class; } - HNewInstance* MakeNewInstance(HInstruction* cls, uint32_t dex_pc = 0u) { + HNewInstance* MakeNewInstance(HBasicBlock* block, HInstruction* cls, uint32_t dex_pc = kNoDexPc) { EXPECT_TRUE(cls->IsLoadClass() || cls->IsClinitCheck()) << *cls; HLoadClass* load = cls->IsLoadClass() ? cls->AsLoadClass() : cls->AsClinitCheck()->GetLoadClass(); - return new (GetAllocator()) HNewInstance(cls, - dex_pc, - load->GetTypeIndex(), - graph_->GetDexFile(), - /* finalizable= */ false, - QuickEntrypointEnum::kQuickAllocObjectInitialized); + HNewInstance* new_instance = new (GetAllocator()) HNewInstance( + cls, + dex_pc, + load->GetTypeIndex(), + graph_->GetDexFile(), + /* finalizable= */ false, + QuickEntrypointEnum::kQuickAllocObjectInitialized); + AddOrInsertInstruction(block, new_instance); + return new_instance; + } + + HInstanceFieldSet* MakeIFieldSet(HBasicBlock* block, + HInstruction* inst, + HInstruction* data, + MemberOffset off, + uint32_t dex_pc = kNoDexPc) { + CHECK(data != nullptr); + return MakeIFieldSet(block, inst, data, data->GetType(), off, dex_pc); } - HInstanceFieldSet* MakeIFieldSet(HInstruction* inst, + HInstanceFieldSet* MakeIFieldSet(HBasicBlock* block, + HInstruction* inst, HInstruction* data, + DataType::Type field_type, MemberOffset off, - uint32_t dex_pc = 0u) { - return new (GetAllocator()) HInstanceFieldSet(inst, - data, - /* field= */ nullptr, - /* field_type= */ data->GetType(), - /* field_offset= */ off, - /* is_volatile= */ false, - /* field_idx= */ 0, - /* declaring_class_def_index= */ 0, - graph_->GetDexFile(), - dex_pc); - } - - HInstanceFieldGet* MakeIFieldGet(HInstruction* inst, + uint32_t dex_pc = kNoDexPc) { + HInstanceFieldSet* ifield_set = new (GetAllocator()) HInstanceFieldSet( + inst, + data, + /* field= */ nullptr, + field_type, + /* field_offset= */ off, + /* is_volatile= */ false, + kUnknownFieldIndex, + kUnknownClassDefIndex, + graph_->GetDexFile(), + dex_pc); + AddOrInsertInstruction(block, ifield_set); + return ifield_set; + } + + HInstanceFieldGet* MakeIFieldGet(HBasicBlock* block, + HInstruction* inst, DataType::Type type, MemberOffset off, - uint32_t dex_pc = 0u) { - return new (GetAllocator()) HInstanceFieldGet(inst, - /* field= */ nullptr, - /* field_type= */ type, - /* field_offset= */ off, - /* is_volatile= */ false, - /* field_idx= */ 0, - /* declaring_class_def_index= */ 0, - graph_->GetDexFile(), - dex_pc); - } - - HInvokeStaticOrDirect* MakeInvoke(DataType::Type return_type, - const std::vector& args) { + uint32_t dex_pc = kNoDexPc) { + HInstanceFieldGet* ifield_get = new (GetAllocator()) HInstanceFieldGet( + inst, + /* field= */ nullptr, + /* field_type= */ type, + /* field_offset= */ off, + /* is_volatile= */ false, + kUnknownFieldIndex, + kUnknownClassDefIndex, + graph_->GetDexFile(), + dex_pc); + AddOrInsertInstruction(block, ifield_get); + return ifield_get; + } + + HNewArray* MakeNewArray(HBasicBlock* block, + HInstruction* cls, + HInstruction* length, + size_t component_size_shift = DataType::SizeShift(DataType::Type::kInt32), + uint32_t dex_pc = kNoDexPc) { + HNewArray* new_array = + new (GetAllocator()) HNewArray(cls, length, dex_pc, component_size_shift); + AddOrInsertInstruction(block, new_array); + return new_array; + } + + HArraySet* MakeArraySet(HBasicBlock* block, + HInstruction* array, + HInstruction* index, + HInstruction* value, + DataType::Type type, + uint32_t dex_pc = kNoDexPc) { + HArraySet* array_set = new (GetAllocator()) HArraySet(array, index, value, type, dex_pc); + AddOrInsertInstruction(block, array_set); + return array_set; + } + + HArrayGet* MakeArrayGet(HBasicBlock* block, + HInstruction* array, + HInstruction* index, + DataType::Type type, + uint32_t dex_pc = kNoDexPc) { + HArrayGet* array_get = new (GetAllocator()) HArrayGet(array, index, type, dex_pc); + AddOrInsertInstruction(block, array_get); + return array_get; + } + + HArrayLength* MakeArrayLength(HBasicBlock* block, + HInstruction* array, + uint32_t dex_pc = kNoDexPc) { + HArrayLength* array_length = new (GetAllocator()) HArrayLength(array, dex_pc); + AddOrInsertInstruction(block, array_length); + return array_length; + } + + HNullCheck* MakeNullCheck(HBasicBlock* block, + HInstruction* value, + uint32_t dex_pc = kNoDexPc) { + HNullCheck* null_check = new (GetAllocator()) HNullCheck(value, dex_pc); + AddOrInsertInstruction(block, null_check); + return null_check; + } + + HBoundsCheck* MakeBoundsCheck(HBasicBlock* block, + HInstruction* index, + HInstruction* length, + uint32_t dex_pc = kNoDexPc) { + HBoundsCheck* bounds_check = new (GetAllocator()) HBoundsCheck(index, length, dex_pc); + AddOrInsertInstruction(block, bounds_check); + return bounds_check; + } + + HVecStore* MakeVecStore(HBasicBlock* block, + HInstruction* base, + HInstruction* index, + HInstruction* value, + DataType::Type packed_type, + size_t vector_length = 4, + uint32_t dex_pc = kNoDexPc) { + 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); + AddOrInsertInstruction(block, vec_store); + return vec_store; + } + + HInvokeStaticOrDirect* MakeInvokeStatic(HBasicBlock* block, + DataType::Type return_type, + const std::vector& args, + uint32_t dex_pc = kNoDexPc) { MethodReference method_reference{/* file= */ &graph_->GetDexFile(), /* index= */ method_idx_++}; - HInvokeStaticOrDirect* res = new (GetAllocator()) + HInvokeStaticOrDirect* invoke = new (GetAllocator()) HInvokeStaticOrDirect(GetAllocator(), args.size(), return_type, - /* dex_pc= */ 0, + dex_pc, method_reference, /* resolved_method= */ nullptr, HInvokeStaticOrDirect::DispatchInfo{}, @@ -461,25 +555,91 @@ class OptimizingUnitTestHelper { HInvokeStaticOrDirect::ClinitCheckRequirement::kNone, !graph_->IsDebuggable()); for (auto [ins, idx] : ZipCount(MakeIterationRange(args))) { - res->SetRawInputAt(idx, ins); + invoke->SetRawInputAt(idx, ins); + } + AddOrInsertInstruction(block, invoke); + return invoke; + } + + template + Type* MakeBinOp(HBasicBlock* block, + DataType::Type result_type, + HInstruction* left, + HInstruction* right, + uint32_t dex_pc = kNoDexPc) { + static_assert(std::is_base_of_v); + Type* insn = new (GetAllocator()) Type(result_type, left, right, dex_pc); + AddOrInsertInstruction(block, insn); + return insn; + } + + template + Type* MakeCondition(HBasicBlock* block, + HInstruction* first, + HInstruction* second, + uint32_t dex_pc = kNoDexPc) { + static_assert(std::is_base_of_v); + Type* condition = new (GetAllocator()) Type(first, second, dex_pc); + AddOrInsertInstruction(block, condition); + return condition; + } + + HSuspendCheck* MakeSuspendCheck(HBasicBlock* block, uint32_t dex_pc = kNoDexPc) { + HSuspendCheck* suspend_check = new (GetAllocator()) HSuspendCheck(dex_pc); + AddOrInsertInstruction(block, suspend_check); + return suspend_check; + } + + void AddOrInsertInstruction(HBasicBlock* block, HInstruction* instruction) { + CHECK(!instruction->IsControlFlow()); + if (block->GetLastInstruction() != nullptr && block->GetLastInstruction()->IsControlFlow()) { + block->InsertInstructionBefore(instruction, block->GetLastInstruction()); + } else { + block->AddInstruction(instruction); } - return res; } - HPhi* MakePhi(const std::vector& ins) { + HIf* MakeIf(HBasicBlock* block, HInstruction* cond, uint32_t dex_pc = kNoDexPc) { + HIf* if_insn = new (GetAllocator()) HIf(cond, dex_pc); + block->AddInstruction(if_insn); + return if_insn; + } + + HGoto* MakeGoto(HBasicBlock* block, uint32_t dex_pc = kNoDexPc) { + HGoto* goto_insn = new (GetAllocator()) HGoto(dex_pc); + block->AddInstruction(goto_insn); + return goto_insn; + } + + HReturnVoid* MakeReturnVoid(HBasicBlock* block, uint32_t dex_pc = kNoDexPc) { + HReturnVoid* return_void = new (GetAllocator()) HReturnVoid(dex_pc); + block->AddInstruction(return_void); + return return_void; + } + + HReturn* MakeReturn(HBasicBlock* block, HInstruction* value, uint32_t dex_pc = kNoDexPc) { + HReturn* return_insn = new (GetAllocator()) HReturn(value, dex_pc); + block->AddInstruction(return_insn); + return return_insn; + } + + HExit* MakeExit(HBasicBlock* exit_block) { + HExit* exit = new (GetAllocator()) HExit(); + exit_block->AddInstruction(exit); + return exit; + } + + HPhi* MakePhi(HBasicBlock* block, const std::vector& ins) { EXPECT_GE(ins.size(), 2u) << "Phi requires at least 2 inputs"; HPhi* phi = new (GetAllocator()) HPhi(GetAllocator(), kNoRegNumber, ins.size(), ins[0]->GetType()); for (auto [i, idx] : ZipCount(MakeIterationRange(ins))) { phi->SetRawInputAt(idx, i); } + block->AddPhi(phi); return phi; } - void SetupExit(HBasicBlock* exit) { - exit->AddInstruction(new (GetAllocator()) HExit()); - } - dex::TypeIndex DefaultTypeIndexForType(DataType::Type type) { switch (type) { case DataType::Type::kBool: @@ -508,7 +668,7 @@ class OptimizingUnitTestHelper { } } - // Creates a parameter. The instruction is automatically added to the entry-block + // Creates a parameter. The instruction is automatically added to the entry-block. HParameterValue* MakeParam(DataType::Type type, std::optional ti = std::nullopt) { HParameterValue* val = new (GetAllocator()) HParameterValue( graph_->GetDexFile(), ti ? *ti : DefaultTypeIndexForType(type), param_count_++, type); @@ -532,8 +692,6 @@ class OptimizingUnitTestHelper { HBasicBlock* return_block_; HBasicBlock* exit_block_; - std::vector parameters_; - size_t param_count_ = 0; size_t class_idx_ = 42; uint32_t method_idx_ = 100; -- cgit v1.2.3-59-g8ed1b