summaryrefslogtreecommitdiff
path: root/compiler/optimizing/optimizing_unit_test.h
diff options
context:
space:
mode:
author Vladimir Marko <vmarko@google.com> 2024-08-15 07:40:38 +0000
committer VladimĂ­r Marko <vmarko@google.com> 2024-08-16 15:44:10 +0000
commit2e593076d3db504d68298ff3b9ec04e26202b2fb (patch)
tree74023cbc5fc39ec9a817cb2bf207b89e2932e341 /compiler/optimizing/optimizing_unit_test.h
parent30970448e676c29c283d7b43a2f5115abc004ca0 (diff)
ART: Clean up loop construction in gtests.
Define and use helper functions for creating loops and linear loop variables. Also remove a dead `HAdd` from one BCE test and change a copy-pasted BCE test for `a[i %200]` to actually test that case (which also reverses the expectation). This change adds extra blocks to some tests, for example empty loop pre-headers, additional return blocks with `HReturnVoid` and a single-goto block to split a critical edge (in `BubbleSortArrayBoundsElimination`). It also adds some extra `HGoto` and `HReturnVoid` instructions and reorders some instructions (linear loop variable increments are added earlier). LSE test helper function `CreateTestControlFlowGraph()` was changed to reorder successors, effectively changing i = 0; do { ... } while (i++ >=128); to i = 0; do { ... } while (i++ < 128); with no impact on the tests using it. `SuperblockClonerTest.IndividualInstrCloner` now clones one additional `HGoto`. Test: m test-art-host-gtest Change-Id: Ie53b07429e62159dee7bfc719c59e06d2609a70e
Diffstat (limited to 'compiler/optimizing/optimizing_unit_test.h')
-rw-r--r--compiler/optimizing/optimizing_unit_test.h70
1 files changed, 68 insertions, 2 deletions
diff --git a/compiler/optimizing/optimizing_unit_test.h b/compiler/optimizing/optimizing_unit_test.h
index f0a279ca4d..f6267c5867 100644
--- a/compiler/optimizing/optimizing_unit_test.h
+++ b/compiler/optimizing/optimizing_unit_test.h
@@ -342,6 +342,53 @@ class OptimizingUnitTestHelper {
return {if_block, then_block, else_block};
}
+ // Insert "pre-header", "loop-header" and "loop-body" blocks before a given `loop_exit` block
+ // and connect them in a `while (...) { ... }` loop pattern. Return the new blocks.
+ // Adds `HGoto` to the "pre-header" and "loop-body" blocks but leaves the "loop-header" block
+ // empty, leaving the construction of an appropriate condition and `HIf` to the caller.
+ // Note: The `loop_exit` shall be the "then" successor of the "loop-header". If the `loop_exit`
+ // is needed as the "else" successor, use `HBlock::SwapSuccessors()` to adjust the order.
+ std::tuple<HBasicBlock*, HBasicBlock*, HBasicBlock*> CreateWhileLoop(HBasicBlock* loop_exit) {
+ HBasicBlock* pre_header = AddNewBlock();
+ HBasicBlock* loop_header = AddNewBlock();
+ HBasicBlock* loop_body = AddNewBlock();
+
+ HBasicBlock* predecessor = loop_exit->GetSinglePredecessor();
+ predecessor->ReplaceSuccessor(loop_exit, pre_header);
+
+ pre_header->AddSuccessor(loop_header);
+ loop_header->AddSuccessor(loop_exit); // true successor
+ loop_header->AddSuccessor(loop_body); // false successor
+ loop_body->AddSuccessor(loop_header);
+
+ MakeGoto(pre_header);
+ MakeGoto(loop_body);
+
+ return {pre_header, loop_header, loop_body};
+ }
+
+ // Insert "pre-header" and "loop" blocks before a given `loop_exit` block and connect them in a
+ // `do { ... } while (...);` loop pattern. Return the new blocks. Adds `HGoto` to the "pre-header"
+ // block but leaves the "loop" block empty, leaving the construction of an appropriate condition
+ // and `HIf` to the caller.
+ // Note: The `loop_exit` shall be the "then" successor of the "loop". If the `loop_exit`
+ // is needed as the "else" successor, use `HBlock::SwapSuccessors()` to adjust the order.
+ std::tuple<HBasicBlock*, HBasicBlock*> CreateDoWhileLoop(HBasicBlock* loop_exit) {
+ HBasicBlock* pre_header = AddNewBlock();
+ HBasicBlock* loop = AddNewBlock();
+
+ HBasicBlock* predecessor = loop_exit->GetSinglePredecessor();
+ predecessor->ReplaceSuccessor(loop_exit, pre_header);
+
+ pre_header->AddSuccessor(loop);
+ loop->AddSuccessor(loop_exit); // true successor
+ loop->AddSuccessor(loop); // fakse successor
+
+ MakeGoto(pre_header);
+
+ return {pre_header, loop};
+ }
+
HBasicBlock* AddNewBlock() {
HBasicBlock* block = new (GetAllocator()) HBasicBlock(graph_);
graph_->AddBlock(block);
@@ -671,8 +718,8 @@ class OptimizingUnitTestHelper {
HPhi* MakePhi(HBasicBlock* block, const std::vector<HInstruction*>& ins) {
EXPECT_GE(ins.size(), 2u) << "Phi requires at least 2 inputs";
- HPhi* phi =
- new (GetAllocator()) HPhi(GetAllocator(), kNoRegNumber, ins.size(), ins[0]->GetType());
+ DataType::Type type = DataType::Kind(ins[0]->GetType());
+ HPhi* phi = new (GetAllocator()) HPhi(GetAllocator(), kNoRegNumber, ins.size(), type);
for (auto [i, idx] : ZipCount(MakeIterationRange(ins))) {
phi->SetRawInputAt(idx, i);
}
@@ -680,6 +727,25 @@ class OptimizingUnitTestHelper {
return phi;
}
+ std::tuple<HPhi*, HAdd*> MakeLinearLoopVar(HBasicBlock* header,
+ HBasicBlock* body,
+ int32_t initial,
+ int32_t increment) {
+ HInstruction* initial_const = graph_->GetIntConstant(initial);
+ HInstruction* increment_const = graph_->GetIntConstant(increment);
+ return MakeLinearLoopVar(header, body, initial_const, increment_const);
+ }
+
+ std::tuple<HPhi*, HAdd*> MakeLinearLoopVar(HBasicBlock* header,
+ HBasicBlock* body,
+ HInstruction* initial,
+ HInstruction* increment) {
+ HPhi* phi = MakePhi(header, {initial, /* placeholder */ initial});
+ HAdd* add = MakeBinOp<HAdd>(body, phi->GetType(), phi, increment);
+ phi->ReplaceInput(add, 1u); // Update back-edge input.
+ return {phi, add};
+ }
+
dex::TypeIndex DefaultTypeIndexForType(DataType::Type type) {
switch (type) {
case DataType::Type::kBool: