diff options
author | 2024-08-13 10:59:26 +0000 | |
---|---|---|
committer | 2024-08-14 13:46:06 +0000 | |
commit | 3b6024d5db60c891c5ef6dc18cc17f8ece56c796 (patch) | |
tree | f3ec7d0d8543e28db82f9d9f1e3c58421b68458b | |
parent | 4910586af2f208262dd1f8225f42fa6f6e95d355 (diff) |
Clean up condition simplification.
Leave condition construction in the `HGraph` but move the
rest of the condition simplification code to the simplifier
where it belongs.
Also clean up simplifier tests and a few other gtests. Note
that `SuperblockClonerTest.IndividualInstrCloner` now clones
an additional `HGoto` from the entry block.
Test: m test-art-host-gtest
Test: testrunner.py --host --optimizing
Change-Id: I73ee8c227c1c100ac7eb9d4a3813c61ad928b6dd
-rw-r--r-- | compiler/optimizing/instruction_simplifier.cc | 109 | ||||
-rw-r--r-- | compiler/optimizing/instruction_simplifier_test.cc | 65 | ||||
-rw-r--r-- | compiler/optimizing/load_store_elimination_test.cc | 28 | ||||
-rw-r--r-- | compiler/optimizing/nodes.cc | 56 | ||||
-rw-r--r-- | compiler/optimizing/nodes.h | 9 | ||||
-rw-r--r-- | compiler/optimizing/optimizing_unit_test.h | 53 | ||||
-rw-r--r-- | compiler/optimizing/select_generator_test.cc | 34 | ||||
-rw-r--r-- | compiler/optimizing/superblock_cloner_test.cc | 67 |
8 files changed, 198 insertions, 223 deletions
diff --git a/compiler/optimizing/instruction_simplifier.cc b/compiler/optimizing/instruction_simplifier.cc index 4bee9c0711..1d717f8477 100644 --- a/compiler/optimizing/instruction_simplifier.cc +++ b/compiler/optimizing/instruction_simplifier.cc @@ -131,6 +131,11 @@ class InstructionSimplifierVisitor final : public HGraphDelegateVisitor { bool CanUseKnownImageVarHandle(HInvoke* invoke); static bool CanEnsureNotNullAt(HInstruction* input, HInstruction* at); + // Returns an instruction with the opposite Boolean value from 'cond'. + // The instruction is inserted into the graph, either in the entry block + // (constant), or before the `cursor` (otherwise). + HInstruction* InsertOppositeCondition(HInstruction* cond, HInstruction* cursor); + CodeGenerator* codegen_; OptimizingCompilerStats* stats_; bool simplification_occurred_ = false; @@ -879,36 +884,50 @@ void InstructionSimplifierVisitor::VisitStaticFieldSet(HStaticFieldSet* instruct } } -static HCondition* CreateOppositeConditionSwapOps(ArenaAllocator* allocator, HInstruction* cond) { - HInstruction *lhs = cond->InputAt(0); - HInstruction *rhs = cond->InputAt(1); - switch (cond->GetKind()) { - case HInstruction::kEqual: - return new (allocator) HEqual(rhs, lhs); - case HInstruction::kNotEqual: - return new (allocator) HNotEqual(rhs, lhs); - case HInstruction::kLessThan: - return new (allocator) HGreaterThan(rhs, lhs); - case HInstruction::kLessThanOrEqual: - return new (allocator) HGreaterThanOrEqual(rhs, lhs); - case HInstruction::kGreaterThan: - return new (allocator) HLessThan(rhs, lhs); - case HInstruction::kGreaterThanOrEqual: - return new (allocator) HLessThanOrEqual(rhs, lhs); - case HInstruction::kBelow: - return new (allocator) HAbove(rhs, lhs); - case HInstruction::kBelowOrEqual: - return new (allocator) HAboveOrEqual(rhs, lhs); - case HInstruction::kAbove: - return new (allocator) HBelow(rhs, lhs); - case HInstruction::kAboveOrEqual: - return new (allocator) HBelowOrEqual(rhs, lhs); +static IfCondition GetOppositeConditionForOperandSwap(IfCondition cond) { + switch (cond) { + case kCondEQ: return kCondEQ; + case kCondNE: return kCondNE; + case kCondLT: return kCondGT; + case kCondLE: return kCondGE; + case kCondGT: return kCondLT; + case kCondGE: return kCondLE; + case kCondB: return kCondA; + case kCondBE: return kCondAE; + case kCondA: return kCondB; + case kCondAE: return kCondBE; default: - LOG(FATAL) << "Unknown ConditionType " << cond->GetKind(); + LOG(FATAL) << "Unknown ConditionType " << cond; UNREACHABLE(); } } +HInstruction* InstructionSimplifierVisitor::InsertOppositeCondition(HInstruction* cond, + HInstruction* cursor) { + if (cond->IsCondition() && + !DataType::IsFloatingPointType(cond->InputAt(0)->GetType())) { + // Can't reverse floating point conditions. We have to use `HBooleanNot` in that case. + HInstruction* lhs = cond->InputAt(0); + HInstruction* rhs = cond->InputAt(1); + HInstruction* replacement = + GetGraph()->CreateCondition(cond->AsCondition()->GetOppositeCondition(), lhs, rhs); + cursor->GetBlock()->InsertInstructionBefore(replacement, cursor); + return replacement; + } else if (cond->IsIntConstant()) { + HIntConstant* int_const = cond->AsIntConstant(); + if (int_const->IsFalse()) { + return GetGraph()->GetIntConstant(1); + } else { + DCHECK(int_const->IsTrue()) << int_const->GetValue(); + return GetGraph()->GetIntConstant(0); + } + } else { + HInstruction* replacement = new (GetGraph()->GetAllocator()) HBooleanNot(cond); + cursor->GetBlock()->InsertInstructionBefore(replacement, cursor); + return replacement; + } +} + void InstructionSimplifierVisitor::VisitEqual(HEqual* equal) { HInstruction* input_const = equal->GetConstantRight(); if (input_const != nullptr) { @@ -924,7 +943,7 @@ void InstructionSimplifierVisitor::VisitEqual(HEqual* equal) { RecordSimplification(); } else if (input_const->AsIntConstant()->IsFalse()) { // Replace (bool_value == false) with !bool_value - equal->ReplaceWith(GetGraph()->InsertOppositeCondition(input_value, equal)); + equal->ReplaceWith(InsertOppositeCondition(input_value, equal)); block->RemoveInstruction(equal); RecordSimplification(); } else { @@ -951,7 +970,7 @@ void InstructionSimplifierVisitor::VisitNotEqual(HNotEqual* not_equal) { // be any constant. if (input_const->AsIntConstant()->IsTrue()) { // Replace (bool_value != true) with !bool_value - not_equal->ReplaceWith(GetGraph()->InsertOppositeCondition(input_value, not_equal)); + not_equal->ReplaceWith(InsertOppositeCondition(input_value, not_equal)); block->RemoveInstruction(not_equal); RecordSimplification(); } else if (input_const->AsIntConstant()->IsFalse()) { @@ -993,7 +1012,7 @@ void InstructionSimplifierVisitor::VisitBooleanNot(HBooleanNot* bool_not) { // NaNs forces the compares to be done as written by the user. !DataType::IsFloatingPointType(input->InputAt(0)->GetType())) { // Replace condition with its opposite. - replace_with = GetGraph()->InsertOppositeCondition(input->AsCondition(), bool_not); + replace_with = InsertOppositeCondition(input->AsCondition(), bool_not); } if (replace_with != nullptr) { @@ -1109,7 +1128,7 @@ void InstructionSimplifierVisitor::VisitSelect(HSelect* select) { replace_with = condition; } else if (true_value->AsIntConstant()->IsFalse() && false_value->AsIntConstant()->IsTrue()) { // Replace (cond ? false : true) with (!cond). - replace_with = GetGraph()->InsertOppositeCondition(condition, select); + replace_with = InsertOppositeCondition(condition, select); } } else if (condition->IsCondition()) { IfCondition cmp = condition->AsCondition()->GetCondition(); @@ -1855,26 +1874,22 @@ void InstructionSimplifierVisitor::VisitCondition(HCondition* condition) { // Reverse condition if left is constant. Our code generators prefer constant // on the right hand side. HBasicBlock* block = condition->GetBlock(); - if (condition->GetLeft()->IsConstant() && !condition->GetRight()->IsConstant()) { - HCondition* replacement = - CreateOppositeConditionSwapOps(block->GetGraph()->GetAllocator(), condition); - // If it is a fp we must set the opposite bias. - if (replacement != nullptr) { - if (condition->IsLtBias()) { - replacement->SetBias(ComparisonBias::kGtBias); - } else if (condition->IsGtBias()) { - replacement->SetBias(ComparisonBias::kLtBias); - } - - block->ReplaceAndRemoveInstructionWith(condition, replacement); - RecordSimplification(); - - condition = replacement; - } - } - HInstruction* left = condition->GetLeft(); HInstruction* right = condition->GetRight(); + if (left->IsConstant() && !right->IsConstant()) { + IfCondition new_cond = GetOppositeConditionForOperandSwap(condition->GetCondition()); + HCondition* replacement = GetGraph()->CreateCondition(new_cond, right, left); + block->ReplaceAndRemoveInstructionWith(condition, replacement); + // If it is a FP condition, we must set the opposite bias. + if (condition->IsLtBias()) { + replacement->SetBias(ComparisonBias::kGtBias); + } else if (condition->IsGtBias()) { + replacement->SetBias(ComparisonBias::kLtBias); + } + RecordSimplification(); + condition = replacement; + std::swap(left, right); + } // Try to fold an HCompare into this HCondition. diff --git a/compiler/optimizing/instruction_simplifier_test.cc b/compiler/optimizing/instruction_simplifier_test.cc index 3f49492938..e140c4d058 100644 --- a/compiler/optimizing/instruction_simplifier_test.cc +++ b/compiler/optimizing/instruction_simplifier_test.cc @@ -52,16 +52,16 @@ class InstructionSimplifierTestBase : public SuperClass, public OptimizingUnitTe gLogVerbosity.compiler = false; } - void PerformSimplification(const AdjacencyListGraph& blks) { + void PerformSimplification() { if (kDebugSimplifierTests) { - LOG(INFO) << "Pre simplification " << blks; + graph_->Dump(LOG_STREAM(INFO) << "Pre simplification ", /* codegen_= */ nullptr); } graph_->ClearDominanceInformation(); graph_->BuildDominatorTree(); InstructionSimplifier simp(graph_, /*codegen=*/nullptr); simp.Run(); if (kDebugSimplifierTests) { - LOG(INFO) << "Post simplify " << blks; + graph_->Dump(LOG_STREAM(INFO) << "Post simplify ", /* codegen_= */ nullptr); } } }; @@ -104,9 +104,9 @@ class InstanceOfInstructionSimplifierTestGroup } std::pair<HLoadClass*, HLoadClass*> GetLoadClasses(HBasicBlock* block, - VariableSizedHandleScope* vshs) { + VariableSizedHandleScope* vshs) + REQUIRES_SHARED(Locks::mutator_lock_) { InstanceOfKind kind = GetParam(); - ScopedObjectAccess soa(Thread::Current()); // New inst always needs to have a valid rti since we dcheck that. HLoadClass* new_inst = MakeLoadClass( block, @@ -150,27 +150,14 @@ class InstanceOfInstructionSimplifierTestGroup TEST_P(InstanceOfInstructionSimplifierTestGroup, ExactClassInstanceOfOther) { ScopedObjectAccess soa(Thread::Current()); VariableSizedHandleScope vshs(soa.Self()); - InitGraph(/*handles=*/&vshs); - - AdjacencyListGraph blks(SetupFromAdjacencyList("entry", - "exit", - {{"entry", "left"}, - {"entry", "right"}, - {"left", "breturn"}, - {"right", "breturn"}, - {"breturn", "exit"}})); -#define GET_BLOCK(name) HBasicBlock* name = blks.Get(#name) - GET_BLOCK(entry); - GET_BLOCK(exit); - GET_BLOCK(breturn); - GET_BLOCK(left); - GET_BLOCK(right); -#undef GET_BLOCK + HBasicBlock* breturn = InitEntryMainExitGraph(/*handles=*/&vshs); + auto [if_block, left, right] = CreateDiamondPattern(breturn); EnsurePredecessorOrder(breturn, {left, right}); + HInstruction* test_res = graph_->GetIntConstant(GetConstantResult() ? 1 : 0); - auto [new_inst_klass, target_klass] = GetLoadClasses(entry, &vshs); - HInstruction* new_inst = MakeNewInstance(entry, new_inst_klass); + auto [new_inst_klass, target_klass] = GetLoadClasses(if_block, &vshs); + HInstruction* new_inst = MakeNewInstance(if_block, new_inst_klass); new_inst->SetReferenceTypeInfo( ReferenceTypeInfo::Create(new_inst_klass->GetClass(), /*is_exact=*/true)); HInstanceOf* instance_of = new (GetAllocator()) HInstanceOf(new_inst, @@ -184,25 +171,19 @@ TEST_P(InstanceOfInstructionSimplifierTestGroup, ExactClassInstanceOfOther) { if (target_klass->GetLoadedClassRTI().IsValid()) { instance_of->SetValidTargetClassRTI(); } - entry->AddInstruction(instance_of); - HIf* if_inst = MakeIf(entry, instance_of); + if_block->AddInstruction(instance_of); + HIf* if_inst = MakeIf(if_block, instance_of); ManuallyBuildEnvFor(new_inst_klass, {}); if (new_inst_klass != target_klass) { target_klass->CopyEnvironmentFrom(new_inst_klass->GetEnvironment()); } new_inst->CopyEnvironmentFrom(new_inst_klass->GetEnvironment()); - MakeGoto(left); - - MakeGoto(right); - HInstruction* read_bottom = MakeIFieldGet(breturn, new_inst, DataType::Type::kInt32, MemberOffset(32)); MakeReturn(breturn, read_bottom); - MakeExit(exit); - - PerformSimplification(blks); + PerformSimplification(); if (!GetConstantResult() || GetParam() == InstanceOfKind::kSelf) { EXPECT_INS_RETAINED(target_klass); @@ -222,16 +203,10 @@ TEST_P(InstanceOfInstructionSimplifierTestGroup, ExactClassInstanceOfOther) { TEST_P(InstanceOfInstructionSimplifierTestGroup, ExactClassCheckCastOther) { ScopedObjectAccess soa(Thread::Current()); VariableSizedHandleScope vshs(soa.Self()); - InitGraph(/*handles=*/&vshs); - - AdjacencyListGraph blks(SetupFromAdjacencyList("entry", "exit", {{"entry", "exit"}})); -#define GET_BLOCK(name) HBasicBlock* name = blks.Get(#name) - GET_BLOCK(entry); - GET_BLOCK(exit); -#undef GET_BLOCK + HBasicBlock* main = InitEntryMainExitGraph(/*handles=*/&vshs); - auto [new_inst_klass, target_klass] = GetLoadClasses(entry, &vshs); - HInstruction* new_inst = MakeNewInstance(entry, new_inst_klass); + auto [new_inst_klass, target_klass] = GetLoadClasses(main, &vshs); + HInstruction* new_inst = MakeNewInstance(main, new_inst_klass); new_inst->SetReferenceTypeInfo( ReferenceTypeInfo::Create(new_inst_klass->GetClass(), /*is_exact=*/true)); HCheckCast* check_cast = new (GetAllocator()) HCheckCast(new_inst, @@ -245,17 +220,15 @@ TEST_P(InstanceOfInstructionSimplifierTestGroup, ExactClassCheckCastOther) { if (target_klass->GetLoadedClassRTI().IsValid()) { check_cast->SetValidTargetClassRTI(); } - entry->AddInstruction(check_cast); - MakeReturn(entry, new_inst); + main->AddInstruction(check_cast); + MakeReturn(main, new_inst); ManuallyBuildEnvFor(new_inst_klass, {}); if (new_inst_klass != target_klass) { target_klass->CopyEnvironmentFrom(new_inst_klass->GetEnvironment()); } new_inst->CopyEnvironmentFrom(new_inst_klass->GetEnvironment()); - MakeExit(exit); - - PerformSimplification(blks); + PerformSimplification(); if (!GetConstantResult() || GetParam() == InstanceOfKind::kSelf) { EXPECT_INS_RETAINED(target_klass); diff --git a/compiler/optimizing/load_store_elimination_test.cc b/compiler/optimizing/load_store_elimination_test.cc index 1ac6f1f965..04f666ff49 100644 --- a/compiler/optimizing/load_store_elimination_test.cc +++ b/compiler/optimizing/load_store_elimination_test.cc @@ -158,22 +158,11 @@ class LoadStoreEliminationTestBase : public SuperTest, public OptimizingUnitTest InitGraphAndParameters(); CreateEntryBlockInstructions(); - HBasicBlock* upper = AddNewBlock(); - HBasicBlock* left = AddNewBlock(); - HBasicBlock* right = AddNewBlock(); - - entry_block_->ReplaceSuccessor(return_block_, upper); - upper->AddSuccessor(left); - upper->AddSuccessor(right); - left->AddSuccessor(return_block_); - right->AddSuccessor(return_block_); + auto [upper, left, right] = CreateDiamondPattern(return_block_); HInstruction* cmp = MakeCondition<HGreaterThanOrEqual>(upper, i_, j_); MakeIf(upper, cmp); - MakeGoto(left); - MakeGoto(right); - return std::make_tuple(upper, left, right, return_block_); } @@ -260,12 +249,13 @@ class LoadStoreEliminationTestBase : public SuperTest, public OptimizingUnitTest } void InitGraphAndParameters() { - InitGraph(); + return_block_ = InitEntryMainExitGraphWithReturnVoid(); array_ = MakeParam(DataType::Type::kInt32); i_ = MakeParam(DataType::Type::kInt32); j_ = MakeParam(DataType::Type::kInt32); } + HBasicBlock* return_block_; HBasicBlock* pre_header_; HBasicBlock* loop_; @@ -553,11 +543,7 @@ TEST_F(LoadStoreEliminationTest, LoadAfterSIMDLoopWithSideEffects) { // 'vstore3' is not removed. // 'vstore4' is not removed. Such cases are not supported at the moment. TEST_F(LoadStoreEliminationTest, MergePredecessorVecStores) { - HBasicBlock* upper; - HBasicBlock* left; - HBasicBlock* right; - HBasicBlock* down; - std::tie(upper, left, right, down) = CreateDiamondShapedCFG(); + auto [upper, left, right, down] = CreateDiamondShapedCFG(); // upper: a[i,... i + 3] = [1,...1] HInstruction* vstore1 = AddVecStore(upper, array_, i_); @@ -596,11 +582,7 @@ TEST_F(LoadStoreEliminationTest, MergePredecessorVecStores) { // 'store2' is not removed. // 'store3' is removed. TEST_F(LoadStoreEliminationTest, MergePredecessorStores) { - HBasicBlock* upper; - HBasicBlock* left; - HBasicBlock* right; - HBasicBlock* down; - std::tie(upper, left, right, down) = CreateDiamondShapedCFG(); + auto [upper, left, right, down] = CreateDiamondShapedCFG(); // upper: a[i,... i + 3] = [1,...1] AddArraySet(upper, array_, i_); diff --git a/compiler/optimizing/nodes.cc b/compiler/optimizing/nodes.cc index 38711c074b..4b401c8f75 100644 --- a/compiler/optimizing/nodes.cc +++ b/compiler/optimizing/nodes.cc @@ -3339,45 +3339,25 @@ HInstruction* ReplaceInstrOrPhiByClone(HInstruction* instr) { return clone; } -// Returns an instruction with the opposite Boolean value from 'cond'. -HInstruction* HGraph::InsertOppositeCondition(HInstruction* cond, HInstruction* cursor) { +HCondition* HGraph::CreateCondition(IfCondition cond, + HInstruction* lhs, + HInstruction* rhs, + uint32_t dex_pc) { ArenaAllocator* allocator = GetAllocator(); - - if (cond->IsCondition() && - !DataType::IsFloatingPointType(cond->InputAt(0)->GetType())) { - // Can't reverse floating point conditions. We have to use HBooleanNot in that case. - HInstruction* lhs = cond->InputAt(0); - HInstruction* rhs = cond->InputAt(1); - HInstruction* replacement = nullptr; - switch (cond->AsCondition()->GetOppositeCondition()) { // get *opposite* - case kCondEQ: replacement = new (allocator) HEqual(lhs, rhs); break; - case kCondNE: replacement = new (allocator) HNotEqual(lhs, rhs); break; - case kCondLT: replacement = new (allocator) HLessThan(lhs, rhs); break; - case kCondLE: replacement = new (allocator) HLessThanOrEqual(lhs, rhs); break; - case kCondGT: replacement = new (allocator) HGreaterThan(lhs, rhs); break; - case kCondGE: replacement = new (allocator) HGreaterThanOrEqual(lhs, rhs); break; - case kCondB: replacement = new (allocator) HBelow(lhs, rhs); break; - case kCondBE: replacement = new (allocator) HBelowOrEqual(lhs, rhs); break; - case kCondA: replacement = new (allocator) HAbove(lhs, rhs); break; - case kCondAE: replacement = new (allocator) HAboveOrEqual(lhs, rhs); break; - default: - LOG(FATAL) << "Unexpected condition"; - UNREACHABLE(); - } - cursor->GetBlock()->InsertInstructionBefore(replacement, cursor); - return replacement; - } else if (cond->IsIntConstant()) { - HIntConstant* int_const = cond->AsIntConstant(); - if (int_const->IsFalse()) { - return GetIntConstant(1); - } else { - DCHECK(int_const->IsTrue()) << int_const->GetValue(); - return GetIntConstant(0); - } - } else { - HInstruction* replacement = new (allocator) HBooleanNot(cond); - cursor->GetBlock()->InsertInstructionBefore(replacement, cursor); - return replacement; + switch (cond) { + case kCondEQ: return new (allocator) HEqual(lhs, rhs, dex_pc); + case kCondNE: return new (allocator) HNotEqual(lhs, rhs, dex_pc); + case kCondLT: return new (allocator) HLessThan(lhs, rhs, dex_pc); + case kCondLE: return new (allocator) HLessThanOrEqual(lhs, rhs, dex_pc); + case kCondGT: return new (allocator) HGreaterThan(lhs, rhs, dex_pc); + case kCondGE: return new (allocator) HGreaterThanOrEqual(lhs, rhs, dex_pc); + case kCondB: return new (allocator) HBelow(lhs, rhs, dex_pc); + case kCondBE: return new (allocator) HBelowOrEqual(lhs, rhs, dex_pc); + case kCondA: return new (allocator) HAbove(lhs, rhs, dex_pc); + case kCondAE: return new (allocator) HAboveOrEqual(lhs, rhs, dex_pc); + default: + LOG(FATAL) << "Unexpected condition " << cond; + UNREACHABLE(); } } diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h index 9d6da95f0f..3aaa7c60cd 100644 --- a/compiler/optimizing/nodes.h +++ b/compiler/optimizing/nodes.h @@ -58,6 +58,7 @@ class ArenaStack; class CodeGenerator; class GraphChecker; class HBasicBlock; +class HCondition; class HConstructorFence; class HCurrentMethod; class HDoubleConstant; @@ -719,10 +720,10 @@ class HGraph : public ArenaObject<kArenaAllocGraph> { void SetProfilingInfo(ProfilingInfo* info) { profiling_info_ = info; } ProfilingInfo* GetProfilingInfo() const { return profiling_info_; } - // Returns an instruction with the opposite Boolean value from 'cond'. - // The instruction has been inserted into the graph, either as a constant, or - // before cursor. - HInstruction* InsertOppositeCondition(HInstruction* cond, HInstruction* cursor); + HCondition* CreateCondition(IfCondition cond, + HInstruction* lhs, + HInstruction* rhs, + uint32_t dex_pc = kNoDexPc); ReferenceTypeInfo GetInexactObjectRti() { return ReferenceTypeInfo::Create(handle_cache_.GetObjectClassHandle(), /* is_exact= */ false); diff --git a/compiler/optimizing/optimizing_unit_test.h b/compiler/optimizing/optimizing_unit_test.h index c8412b876b..f0a279ca4d 100644 --- a/compiler/optimizing/optimizing_unit_test.h +++ b/compiler/optimizing/optimizing_unit_test.h @@ -219,7 +219,6 @@ class OptimizingUnitTestHelper { : pool_and_allocator_(new ArenaPoolAndAllocator()), graph_(nullptr), entry_block_(nullptr), - return_block_(nullptr), exit_block_(nullptr) { } ArenaAllocator* GetAllocator() { return pool_and_allocator_->GetAllocator(); } @@ -290,20 +289,57 @@ class OptimizingUnitTestHelper { } } - void InitGraph(VariableSizedHandleScope* handles = nullptr) { + // Create simple graph with "entry", "main" and "exit" blocks, return the "main" block. + // Adds `HGoto` to the "entry" block and `HExit` to the "exit block. Leaves "main" block empty. + HBasicBlock* InitEntryMainExitGraph(VariableSizedHandleScope* handles = nullptr) { CreateGraph(handles); entry_block_ = AddNewBlock(); - return_block_ = AddNewBlock(); + HBasicBlock* main_block = AddNewBlock(); exit_block_ = AddNewBlock(); graph_->SetEntryBlock(entry_block_); graph_->SetExitBlock(exit_block_); - entry_block_->AddSuccessor(return_block_); - return_block_->AddSuccessor(exit_block_); + entry_block_->AddSuccessor(main_block); + main_block->AddSuccessor(exit_block_); - return_block_->AddInstruction(new (GetAllocator()) HReturnVoid()); - exit_block_->AddInstruction(new (GetAllocator()) HExit()); + MakeGoto(entry_block_); + MakeExit(exit_block_); + + return main_block; + } + + // Creates a graph identical to `InitEntryMainExitGraph()` and adds `HReturnVoid`. + HBasicBlock* InitEntryMainExitGraphWithReturnVoid(VariableSizedHandleScope* handles = nullptr) { + HBasicBlock* return_block = InitEntryMainExitGraph(handles); + MakeReturnVoid(return_block); + return return_block; + } + + // Insert "if_block", "then_block" and "else_block" before a given `merge_block`. Return the + // new blocks. Adds `HGoto` to "then_block" and "else_block". Adds `HIf` to the "if_block" + // if the caller provides a `condition`. + std::tuple<HBasicBlock*, HBasicBlock*, HBasicBlock*> CreateDiamondPattern( + HBasicBlock* merge_block, HInstruction* condition = nullptr) { + HBasicBlock* if_block = AddNewBlock(); + HBasicBlock* then_block = AddNewBlock(); + HBasicBlock* else_block = AddNewBlock(); + + HBasicBlock* predecessor = merge_block->GetSinglePredecessor(); + predecessor->ReplaceSuccessor(merge_block, if_block); + + if_block->AddSuccessor(then_block); + if_block->AddSuccessor(else_block); + then_block->AddSuccessor(merge_block); + else_block->AddSuccessor(merge_block); + + if (condition != nullptr) { + MakeIf(if_block, condition); + } + MakeGoto(then_block); + MakeGoto(else_block); + + return {if_block, then_block, else_block}; } HBasicBlock* AddNewBlock() { @@ -676,7 +712,7 @@ class OptimizingUnitTestHelper { HParameterValue* MakeParam(DataType::Type type, std::optional<dex::TypeIndex> ti = std::nullopt) { HParameterValue* val = new (GetAllocator()) HParameterValue( graph_->GetDexFile(), ti ? *ti : DefaultTypeIndexForType(type), param_count_++, type); - graph_->GetEntryBlock()->AddInstruction(val); + AddOrInsertInstruction(graph_->GetEntryBlock(), val); return val; } @@ -693,7 +729,6 @@ class OptimizingUnitTestHelper { HGraph* graph_; HBasicBlock* entry_block_; - HBasicBlock* return_block_; HBasicBlock* exit_block_; size_t param_count_ = 0; diff --git a/compiler/optimizing/select_generator_test.cc b/compiler/optimizing/select_generator_test.cc index 501bebb9dd..2e91c884eb 100644 --- a/compiler/optimizing/select_generator_test.cc +++ b/compiler/optimizing/select_generator_test.cc @@ -27,29 +27,15 @@ namespace art HIDDEN { class SelectGeneratorTest : public OptimizingUnitTest { protected: - void ConstructBasicGraphForSelect(HInstruction* instr) { - HBasicBlock* if_block = AddNewBlock(); - HBasicBlock* then_block = AddNewBlock(); - HBasicBlock* else_block = AddNewBlock(); - - entry_block_->ReplaceSuccessor(return_block_, if_block); - - if_block->AddSuccessor(then_block); - if_block->AddSuccessor(else_block); - then_block->AddSuccessor(return_block_); - else_block->AddSuccessor(return_block_); - + HPhi* ConstructBasicGraphForSelect(HBasicBlock* return_block, HInstruction* instr) { HParameterValue* bool_param = MakeParam(DataType::Type::kBool); HIntConstant* const1 = graph_->GetIntConstant(1); - MakeIf(if_block, bool_param); - - then_block->AddInstruction(instr); - MakeGoto(then_block); - - MakeGoto(else_block); + auto [if_block, then_block, else_block] = CreateDiamondPattern(return_block, bool_param); - HPhi* phi = MakePhi(return_block_, {instr, const1}); + AddOrInsertInstruction(then_block, instr); + HPhi* phi = MakePhi(return_block, {instr, const1}); + return phi; } bool CheckGraphAndTrySelectGenerator() { @@ -64,25 +50,27 @@ class SelectGeneratorTest : public OptimizingUnitTest { // HDivZeroCheck might throw and should not be hoisted from the conditional to an unconditional. TEST_F(SelectGeneratorTest, testZeroCheck) { - InitGraph(); + HBasicBlock* return_block = InitEntryMainExitGraphWithReturnVoid(); HParameterValue* param = MakeParam(DataType::Type::kInt32); HDivZeroCheck* instr = new (GetAllocator()) HDivZeroCheck(param, 0); - ConstructBasicGraphForSelect(instr); + HPhi* phi = ConstructBasicGraphForSelect(return_block, instr); ArenaVector<HInstruction*> current_locals({param, graph_->GetIntConstant(1)}, GetAllocator()->Adapter(kArenaAllocInstruction)); ManuallyBuildEnvFor(instr, ¤t_locals); EXPECT_FALSE(CheckGraphAndTrySelectGenerator()); + EXPECT_FALSE(phi->GetBlock() == nullptr); } // Test that SelectGenerator succeeds with HAdd. TEST_F(SelectGeneratorTest, testAdd) { - InitGraph(); + HBasicBlock* return_block = InitEntryMainExitGraphWithReturnVoid(); HParameterValue* param = MakeParam(DataType::Type::kInt32); HAdd* instr = new (GetAllocator()) HAdd(DataType::Type::kInt32, param, param, /*dex_pc=*/ 0); - ConstructBasicGraphForSelect(instr); + HPhi* phi = ConstructBasicGraphForSelect(return_block, instr); EXPECT_TRUE(CheckGraphAndTrySelectGenerator()); + EXPECT_TRUE(phi->GetBlock() == nullptr); } } // namespace art diff --git a/compiler/optimizing/superblock_cloner_test.cc b/compiler/optimizing/superblock_cloner_test.cc index 9345fd175f..8cef156e70 100644 --- a/compiler/optimizing/superblock_cloner_test.cc +++ b/compiler/optimizing/superblock_cloner_test.cc @@ -33,9 +33,10 @@ using HEdgeSet = SuperblockCloner::HEdgeSet; // individual instruction cloning and cloning of the more coarse-grain structures. class SuperblockClonerTest : public OptimizingUnitTest { protected: - void InitGraphAndParameters() { - InitGraph(); + HBasicBlock* InitGraphAndParameters() { + HBasicBlock* return_block = InitEntryMainExitGraphWithReturnVoid(); param_ = MakeParam(DataType::Type::kInt32); + return return_block; } void CreateBasicLoopControlFlow(HBasicBlock* position, @@ -104,8 +105,8 @@ TEST_F(SuperblockClonerTest, IndividualInstrCloner) { HBasicBlock* header = nullptr; HBasicBlock* loop_body = nullptr; - InitGraphAndParameters(); - CreateBasicLoopControlFlow(entry_block_, return_block_, &header, &loop_body); + HBasicBlock* return_block = InitGraphAndParameters(); + CreateBasicLoopControlFlow(entry_block_, return_block, &header, &loop_body); CreateBasicLoopDataFlow(header, loop_body); graph_->BuildDominatorTree(); EXPECT_TRUE(CheckGraph()); @@ -116,12 +117,12 @@ TEST_F(SuperblockClonerTest, IndividualInstrCloner) { visitor.VisitInsertionOrder(); size_t instr_replaced_by_clones_count = visitor.GetInstrReplacedByClonesCount(); - EXPECT_EQ(instr_replaced_by_clones_count, 12u); + EXPECT_EQ(instr_replaced_by_clones_count, 13u); EXPECT_TRUE(CheckGraph()); visitor.VisitReversePostOrder(); instr_replaced_by_clones_count = visitor.GetInstrReplacedByClonesCount(); - EXPECT_EQ(instr_replaced_by_clones_count, 24u); + EXPECT_EQ(instr_replaced_by_clones_count, 26u); EXPECT_TRUE(CheckGraph()); HSuspendCheck* new_suspend_check = header->GetLoopInformation()->GetSuspendCheck(); @@ -136,8 +137,8 @@ TEST_F(SuperblockClonerTest, CloneBasicBlocks) { HBasicBlock* loop_body = nullptr; ArenaAllocator* arena = GetAllocator(); - InitGraphAndParameters(); - CreateBasicLoopControlFlow(entry_block_, return_block_, &header, &loop_body); + HBasicBlock* return_block = InitGraphAndParameters(); + CreateBasicLoopControlFlow(entry_block_, return_block, &header, &loop_body); CreateBasicLoopDataFlow(header, loop_body); graph_->BuildDominatorTree(); ASSERT_TRUE(CheckGraph()); @@ -217,8 +218,8 @@ TEST_F(SuperblockClonerTest, AdjustControlFlowInfo) { HBasicBlock* loop_body = nullptr; ArenaAllocator* arena = GetAllocator(); - InitGraphAndParameters(); - CreateBasicLoopControlFlow(entry_block_, return_block_, &header, &loop_body); + HBasicBlock* return_block = InitGraphAndParameters(); + CreateBasicLoopControlFlow(entry_block_, return_block, &header, &loop_body); CreateBasicLoopDataFlow(header, loop_body); graph_->BuildDominatorTree(); ASSERT_TRUE(CheckGraph()); @@ -256,8 +257,8 @@ TEST_F(SuperblockClonerTest, IsGraphConnected) { HBasicBlock* loop_body = nullptr; ArenaAllocator* arena = GetAllocator(); - InitGraphAndParameters(); - CreateBasicLoopControlFlow(entry_block_, return_block_, &header, &loop_body); + HBasicBlock* return_block = InitGraphAndParameters(); + CreateBasicLoopControlFlow(entry_block_, return_block, &header, &loop_body); CreateBasicLoopDataFlow(header, loop_body); HBasicBlock* unreachable_block = AddNewBlock(); @@ -279,8 +280,8 @@ TEST_F(SuperblockClonerTest, LoopPeeling) { HBasicBlock* header = nullptr; HBasicBlock* loop_body = nullptr; - InitGraphAndParameters(); - CreateBasicLoopControlFlow(entry_block_, return_block_, &header, &loop_body); + HBasicBlock* return_block = InitGraphAndParameters(); + CreateBasicLoopControlFlow(entry_block_, return_block, &header, &loop_body); CreateBasicLoopDataFlow(header, loop_body); graph_->BuildDominatorTree(); EXPECT_TRUE(CheckGraph()); @@ -316,8 +317,8 @@ TEST_F(SuperblockClonerTest, LoopUnrolling) { HBasicBlock* header = nullptr; HBasicBlock* loop_body = nullptr; - InitGraphAndParameters(); - CreateBasicLoopControlFlow(entry_block_, return_block_, &header, &loop_body); + HBasicBlock* return_block = InitGraphAndParameters(); + CreateBasicLoopControlFlow(entry_block_, return_block, &header, &loop_body); CreateBasicLoopDataFlow(header, loop_body); graph_->BuildDominatorTree(); EXPECT_TRUE(CheckGraph()); @@ -353,8 +354,8 @@ TEST_F(SuperblockClonerTest, LoopVersioning) { HBasicBlock* header = nullptr; HBasicBlock* loop_body = nullptr; - InitGraphAndParameters(); - CreateBasicLoopControlFlow(entry_block_, return_block_, &header, &loop_body); + HBasicBlock* return_block = InitGraphAndParameters(); + CreateBasicLoopControlFlow(entry_block_, return_block, &header, &loop_body); CreateBasicLoopDataFlow(header, loop_body); graph_->BuildDominatorTree(); EXPECT_TRUE(CheckGraph()); @@ -401,8 +402,8 @@ TEST_F(SuperblockClonerTest, LoopPeelingMultipleBackEdges) { HBasicBlock* header = nullptr; HBasicBlock* loop_body = nullptr; - InitGraphAndParameters(); - CreateBasicLoopControlFlow(entry_block_, return_block_, &header, &loop_body); + HBasicBlock* return_block = InitGraphAndParameters(); + CreateBasicLoopControlFlow(entry_block_, return_block, &header, &loop_body); CreateBasicLoopDataFlow(header, loop_body); // Transform a basic loop to have multiple back edges. @@ -452,16 +453,16 @@ TEST_F(SuperblockClonerTest, LoopPeelingNested) { HBasicBlock* header = nullptr; HBasicBlock* loop_body = nullptr; - InitGraphAndParameters(); + HBasicBlock* return_block = InitGraphAndParameters(); // Create the following nested structure of loops // Headers: 1 2 3 // [ ], [ [ ] ] - CreateBasicLoopControlFlow(entry_block_, return_block_, &header, &loop_body); + CreateBasicLoopControlFlow(entry_block_, return_block, &header, &loop_body); CreateBasicLoopDataFlow(header, loop_body); HBasicBlock* loop1_header = header; - CreateBasicLoopControlFlow(header, return_block_, &header, &loop_body); + CreateBasicLoopControlFlow(header, return_block, &header, &loop_body); CreateBasicLoopDataFlow(header, loop_body); HBasicBlock* loop2_header = header; @@ -499,12 +500,12 @@ TEST_F(SuperblockClonerTest, OuterLoopPopulationAfterInnerPeeled) { HBasicBlock* header = nullptr; HBasicBlock* loop_body = nullptr; - InitGraphAndParameters(); + HBasicBlock* return_block = InitGraphAndParameters(); // Create the following nested structure of loops // Headers: 1 2 3 4 // [ [ [ ] ] ], [ ] - CreateBasicLoopControlFlow(entry_block_, return_block_, &header, &loop_body); + CreateBasicLoopControlFlow(entry_block_, return_block, &header, &loop_body); CreateBasicLoopDataFlow(header, loop_body); HBasicBlock* loop1_header = header; @@ -516,7 +517,7 @@ TEST_F(SuperblockClonerTest, OuterLoopPopulationAfterInnerPeeled) { CreateBasicLoopDataFlow(header, loop_body); HBasicBlock* loop3_header = header; - CreateBasicLoopControlFlow(loop1_header, return_block_, &header, &loop_body); + CreateBasicLoopControlFlow(loop1_header, return_block, &header, &loop_body); CreateBasicLoopDataFlow(header, loop_body); HBasicBlock* loop4_header = header; @@ -556,12 +557,12 @@ TEST_F(SuperblockClonerTest, NestedCaseExitToOutermost) { HBasicBlock* header = nullptr; HBasicBlock* loop_body = nullptr; - InitGraphAndParameters(); + HBasicBlock* return_block = InitGraphAndParameters(); // Create the following nested structure of loops then peel loop3. // Headers: 1 2 3 // [ [ [ ] ] ] - CreateBasicLoopControlFlow(entry_block_, return_block_, &header, &loop_body); + CreateBasicLoopControlFlow(entry_block_, return_block, &header, &loop_body); CreateBasicLoopDataFlow(header, loop_body); HBasicBlock* loop1_header = header; HBasicBlock* loop_body1 = loop_body; @@ -610,8 +611,8 @@ TEST_F(SuperblockClonerTest, FastCaseCheck) { HBasicBlock* loop_body = nullptr; ArenaAllocator* arena = GetAllocator(); - InitGraphAndParameters(); - CreateBasicLoopControlFlow(entry_block_, return_block_, &header, &loop_body); + HBasicBlock* return_block = InitGraphAndParameters(); + CreateBasicLoopControlFlow(entry_block_, return_block, &header, &loop_body); CreateBasicLoopDataFlow(header, loop_body); graph_->BuildDominatorTree(); @@ -665,12 +666,12 @@ TEST_F(SuperblockClonerTest, FindCommonLoop) { HBasicBlock* header = nullptr; HBasicBlock* loop_body = nullptr; - InitGraphAndParameters(); + HBasicBlock* return_block = InitGraphAndParameters(); // Create the following nested structure of loops // Headers: 1 2 3 4 5 // [ [ [ ] ], [ ] ], [ ] - CreateBasicLoopControlFlow(entry_block_, return_block_, &header, &loop_body); + CreateBasicLoopControlFlow(entry_block_, return_block, &header, &loop_body); CreateBasicLoopDataFlow(header, loop_body); HBasicBlock* loop1_header = header; @@ -686,7 +687,7 @@ TEST_F(SuperblockClonerTest, FindCommonLoop) { CreateBasicLoopDataFlow(header, loop_body); HBasicBlock* loop4_header = header; - CreateBasicLoopControlFlow(loop1_header, return_block_, &header, &loop_body); + CreateBasicLoopControlFlow(loop1_header, return_block, &header, &loop_body); CreateBasicLoopDataFlow(header, loop_body); HBasicBlock* loop5_header = header; |