From 2e593076d3db504d68298ff3b9ec04e26202b2fb Mon Sep 17 00:00:00 2001 From: Vladimir Marko Date: Thu, 15 Aug 2024 07:40:38 +0000 Subject: 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 --- compiler/optimizing/optimizing_unit_test.h | 70 +++++++++++++++++++++++++++++- 1 file changed, 68 insertions(+), 2 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 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 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 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& 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 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 MakeLinearLoopVar(HBasicBlock* header, + HBasicBlock* body, + HInstruction* initial, + HInstruction* increment) { + HPhi* phi = MakePhi(header, {initial, /* placeholder */ initial}); + HAdd* add = MakeBinOp(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: -- cgit v1.2.3-59-g8ed1b