summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Vladimir Marko <vmarko@google.com> 2024-08-13 10:59:26 +0000
committer Vladimir Marko <vmarko@google.com> 2024-08-14 13:46:06 +0000
commit3b6024d5db60c891c5ef6dc18cc17f8ece56c796 (patch)
treef3ec7d0d8543e28db82f9d9f1e3c58421b68458b
parent4910586af2f208262dd1f8225f42fa6f6e95d355 (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.cc109
-rw-r--r--compiler/optimizing/instruction_simplifier_test.cc65
-rw-r--r--compiler/optimizing/load_store_elimination_test.cc28
-rw-r--r--compiler/optimizing/nodes.cc56
-rw-r--r--compiler/optimizing/nodes.h9
-rw-r--r--compiler/optimizing/optimizing_unit_test.h53
-rw-r--r--compiler/optimizing/select_generator_test.cc34
-rw-r--r--compiler/optimizing/superblock_cloner_test.cc67
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, &current_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;