From b544a1017753bfef7b91a2ea3024ffbde6cd5bb9 Mon Sep 17 00:00:00 2001 From: Artem Serov Date: Mon, 7 Oct 2024 13:48:54 +0100 Subject: Arm64: Fix PackedSwitch codegen for large methods. This patch fixes a bug in arm64 PackedSwitch code generation for very large methods where we exceeded the range of Adr instruction - jump tables were emited in the very end of the method. Instead we now emit the jump table in-place as part of the PackedSwitch visitor - in the same way how it is done in arm32 backend. This patch also removes an incorrect assumption that the size of a method has a linear dependency on the number of its HIR instructions. This was used to choose whether to emit a jump table for a PackedSwitch. Test: art/test.py --target --host --optimizing Test: art/test.py --gtest art_compiler_tests Change-Id: I0795811a6408a25021879ab6be9e23ef5f1f50e4 --- compiler/optimizing/codegen_test.cc | 67 +++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) (limited to 'compiler/optimizing/codegen_test.cc') diff --git a/compiler/optimizing/codegen_test.cc b/compiler/optimizing/codegen_test.cc index 7365f0fb7f..14a419fcd8 100644 --- a/compiler/optimizing/codegen_test.cc +++ b/compiler/optimizing/codegen_test.cc @@ -73,6 +73,7 @@ class CodegenTest : public CommonCompilerTest, public OptimizingUnitTestHelper { int64_t j, DataType::Type type, const CodegenTargetConfig target_config); + void TestPackedSwitch(const CodegenTargetConfig target_config); }; void CodegenTest::TestCode(const std::vector& data, bool has_result, int32_t expected) { @@ -682,6 +683,72 @@ TEST_F(CodegenTest, ComparisonsLong) { } } +// Tests a PackedSwitch in a very large HGraph; validates that the switch jump table is in +// range for the PC-relative load in the codegen visitor. +void CodegenTest::TestPackedSwitch(const CodegenTargetConfig target_config) { + HBasicBlock* return_block = InitEntryMainExitGraph(); + constexpr DataType::Type data_type = DataType::Type::kInt32; + + // A number of entries - we are interested to test jump table implementation. + constexpr size_t kNumSwitchEntries = 10; + + // Number of jump targets (including a 'default' case). + constexpr size_t kNumBB = kNumSwitchEntries + 1; + // Some arbitrary value to be used as input. + constexpr int kInputValue = kNumBB - 4; + + HInstruction* input = graph_->GetIntConstant(kInputValue); + HIntConstant* constant_1 = graph_->GetIntConstant(1); + + HBasicBlock* switch_block = AddNewBlock(); + entry_block_->ReplaceSuccessor(return_block, switch_block); + + HPackedSwitch* hswitch = new (GetAllocator()) HPackedSwitch(0, kNumSwitchEntries, input); + switch_block->AddInstruction(hswitch); + + std::vector phi_inputs {}; + + // Add switch jump target blocks. + for (int i = 0; i < kNumBB; i++) { + HBasicBlock* case_block = AddNewBlock(); + case_block->AddPredecessor(switch_block); + case_block->AddSuccessor(return_block); + + HIntConstant* case_value = graph_->GetIntConstant(i); + HAdd* add = MakeBinOp(case_block, data_type, input, case_value); + phi_inputs.emplace_back(add); + + MakeGoto(case_block); + } + + HPhi* phi = MakePhi(return_block, phi_inputs); + HInstruction* return_val = phi; + + // Emit a huge number of HAdds - to simulate a very large HGraph. + constexpr int kNumOfAdds = 2 * 1024 * 1024; + for (int i = 0; i < kNumOfAdds; i++) { + return_val = MakeBinOp(return_block, data_type, return_val, constant_1); + } + + MakeReturn(return_block, return_val); + + graph_->BuildDominatorTree(); + EXPECT_TRUE(CheckGraph()); + + std::unique_ptr compiler_options = + CommonCompilerTest::CreateCompilerOptions(target_config.GetInstructionSet(), "default"); + RunCode(target_config, + *compiler_options, + graph_, + [](HGraph*) {}, true, kNumOfAdds + 2 * kInputValue); +} + +TEST_F(CodegenTest, PackedSwitchInHugeMethod) { + for (CodegenTargetConfig target_config : GetTargetConfigs()) { + TestPackedSwitch(target_config); + } +} + #ifdef ART_ENABLE_CODEGEN_arm TEST_F(CodegenTest, ARMVIXLParallelMoveResolver) { std::unique_ptr compiler_options = -- cgit v1.2.3-59-g8ed1b