From 22aa54bf8469689c7c6c33f15ff4df2ffba8fa15 Mon Sep 17 00:00:00 2001 From: Alexandre Rames Date: Tue, 18 Oct 2016 09:32:29 +0100 Subject: AArch64: Add HInstruction scheduling support. This commit adds a new `HInstructionScheduling` pass that performs basic scheduling on the `HGraph`. Currently, scheduling is performed at the block level, so no `HInstruction` ever leaves its block in this pass. The scheduling process iterates through blocks in the graph. For blocks that we can and want to schedule: 1) Build a dependency graph for instructions. It includes data dependencies (inputs/uses), but also environment dependencies and side-effect dependencies. 2) Schedule the dependency graph. This is a topological sort of the dependency graph, using heuristics to decide what node to schedule first when there are multiple candidates. Currently the heuristics only consider instruction latencies and schedule first the instructions that are on the critical path. Test: m test-art-host Test: m test-art-target Change-Id: Iec103177d4f059666d7c9626e5770531fbc5ccdc --- compiler/optimizing/codegen_test.cc | 331 +----------------------------------- 1 file changed, 1 insertion(+), 330 deletions(-) (limited to 'compiler/optimizing/codegen_test.cc') diff --git a/compiler/optimizing/codegen_test.cc b/compiler/optimizing/codegen_test.cc index e3f3df0ff5..d1315091f3 100644 --- a/compiler/optimizing/codegen_test.cc +++ b/compiler/optimizing/codegen_test.cc @@ -17,30 +17,15 @@ #include #include -#include "arch/instruction_set.h" -#include "arch/arm/instruction_set_features_arm.h" -#include "arch/arm/registers_arm.h" -#include "arch/arm64/instruction_set_features_arm64.h" -#include "arch/mips/instruction_set_features_mips.h" -#include "arch/mips/registers_mips.h" -#include "arch/mips64/instruction_set_features_mips64.h" -#include "arch/mips64/registers_mips64.h" -#include "arch/x86/instruction_set_features_x86.h" -#include "arch/x86/registers_x86.h" -#include "arch/x86_64/instruction_set_features_x86_64.h" #include "base/macros.h" #include "builder.h" -#include "code_simulator_container.h" -#include "common_compiler_test.h" +#include "codegen_test_utils.h" #include "dex_file.h" #include "dex_instruction.h" #include "driver/compiler_options.h" -#include "graph_checker.h" #include "nodes.h" #include "optimizing_unit_test.h" -#include "prepare_for_register_allocation.h" #include "register_allocator_linear_scan.h" -#include "ssa_liveness_analysis.h" #include "utils.h" #include "utils/arm/assembler_arm_vixl.h" #include "utils/arm/managed_register_arm.h" @@ -48,324 +33,10 @@ #include "utils/mips64/managed_register_mips64.h" #include "utils/x86/managed_register_x86.h" -#ifdef ART_ENABLE_CODEGEN_arm -#include "code_generator_arm.h" -#include "code_generator_arm_vixl.h" -#endif - -#ifdef ART_ENABLE_CODEGEN_arm64 -#include "code_generator_arm64.h" -#endif - -#ifdef ART_ENABLE_CODEGEN_x86 -#include "code_generator_x86.h" -#endif - -#ifdef ART_ENABLE_CODEGEN_x86_64 -#include "code_generator_x86_64.h" -#endif - -#ifdef ART_ENABLE_CODEGEN_mips -#include "code_generator_mips.h" -#endif - -#ifdef ART_ENABLE_CODEGEN_mips64 -#include "code_generator_mips64.h" -#endif - #include "gtest/gtest.h" namespace art { -typedef CodeGenerator* (*CreateCodegenFn)(HGraph*, const CompilerOptions&); - -class CodegenTargetConfig { - public: - CodegenTargetConfig(InstructionSet isa, CreateCodegenFn create_codegen) - : isa_(isa), create_codegen_(create_codegen) { - } - InstructionSet GetInstructionSet() const { return isa_; } - CodeGenerator* CreateCodeGenerator(HGraph* graph, const CompilerOptions& compiler_options) { - return create_codegen_(graph, compiler_options); - } - - private: - CodegenTargetConfig() {} - InstructionSet isa_; - CreateCodegenFn create_codegen_; -}; - -#ifdef ART_ENABLE_CODEGEN_arm -// Provide our own codegen, that ensures the C calling conventions -// are preserved. Currently, ART and C do not match as R4 is caller-save -// in ART, and callee-save in C. Alternatively, we could use or write -// the stub that saves and restores all registers, but it is easier -// to just overwrite the code generator. -class TestCodeGeneratorARM : public arm::CodeGeneratorARM { - public: - TestCodeGeneratorARM(HGraph* graph, - const ArmInstructionSetFeatures& isa_features, - const CompilerOptions& compiler_options) - : arm::CodeGeneratorARM(graph, isa_features, compiler_options) { - AddAllocatedRegister(Location::RegisterLocation(arm::R6)); - AddAllocatedRegister(Location::RegisterLocation(arm::R7)); - } - - void SetupBlockedRegisters() const OVERRIDE { - arm::CodeGeneratorARM::SetupBlockedRegisters(); - blocked_core_registers_[arm::R4] = true; - blocked_core_registers_[arm::R6] = false; - blocked_core_registers_[arm::R7] = false; - } -}; - -// A way to test the VIXL32-based code generator on ARM. This will replace -// TestCodeGeneratorARM when the VIXL32-based backend replaces the existing one. -class TestCodeGeneratorARMVIXL : public arm::CodeGeneratorARMVIXL { - public: - TestCodeGeneratorARMVIXL(HGraph* graph, - const ArmInstructionSetFeatures& isa_features, - const CompilerOptions& compiler_options) - : arm::CodeGeneratorARMVIXL(graph, isa_features, compiler_options) { - AddAllocatedRegister(Location::RegisterLocation(arm::R6)); - AddAllocatedRegister(Location::RegisterLocation(arm::R7)); - } - - void SetupBlockedRegisters() const OVERRIDE { - arm::CodeGeneratorARMVIXL::SetupBlockedRegisters(); - blocked_core_registers_[arm::R4] = true; - blocked_core_registers_[arm::R6] = false; - blocked_core_registers_[arm::R7] = false; - } -}; -#endif - -#ifdef ART_ENABLE_CODEGEN_x86 -class TestCodeGeneratorX86 : public x86::CodeGeneratorX86 { - public: - TestCodeGeneratorX86(HGraph* graph, - const X86InstructionSetFeatures& isa_features, - const CompilerOptions& compiler_options) - : x86::CodeGeneratorX86(graph, isa_features, compiler_options) { - // Save edi, we need it for getting enough registers for long multiplication. - AddAllocatedRegister(Location::RegisterLocation(x86::EDI)); - } - - void SetupBlockedRegisters() const OVERRIDE { - x86::CodeGeneratorX86::SetupBlockedRegisters(); - // ebx is a callee-save register in C, but caller-save for ART. - blocked_core_registers_[x86::EBX] = true; - - // Make edi available. - blocked_core_registers_[x86::EDI] = false; - } -}; -#endif - -class InternalCodeAllocator : public CodeAllocator { - public: - InternalCodeAllocator() : size_(0) { } - - virtual uint8_t* Allocate(size_t size) { - size_ = size; - memory_.reset(new uint8_t[size]); - return memory_.get(); - } - - size_t GetSize() const { return size_; } - uint8_t* GetMemory() const { return memory_.get(); } - - private: - size_t size_; - std::unique_ptr memory_; - - DISALLOW_COPY_AND_ASSIGN(InternalCodeAllocator); -}; - -static bool CanExecuteOnHardware(InstructionSet target_isa) { - return (target_isa == kRuntimeISA) - // Handle the special case of ARM, with two instructions sets (ARM32 and Thumb-2). - || (kRuntimeISA == kArm && target_isa == kThumb2); -} - -static bool CanExecute(InstructionSet target_isa) { - CodeSimulatorContainer simulator(target_isa); - return CanExecuteOnHardware(target_isa) || simulator.CanSimulate(); -} - -template -static Expected SimulatorExecute(CodeSimulator* simulator, Expected (*f)()); - -template <> -bool SimulatorExecute(CodeSimulator* simulator, bool (*f)()) { - simulator->RunFrom(reinterpret_cast(f)); - return simulator->GetCReturnBool(); -} - -template <> -int32_t SimulatorExecute(CodeSimulator* simulator, int32_t (*f)()) { - simulator->RunFrom(reinterpret_cast(f)); - return simulator->GetCReturnInt32(); -} - -template <> -int64_t SimulatorExecute(CodeSimulator* simulator, int64_t (*f)()) { - simulator->RunFrom(reinterpret_cast(f)); - return simulator->GetCReturnInt64(); -} - -template -static void VerifyGeneratedCode(InstructionSet target_isa, - Expected (*f)(), - bool has_result, - Expected expected) { - ASSERT_TRUE(CanExecute(target_isa)) << "Target isa is not executable."; - - // Verify on simulator. - CodeSimulatorContainer simulator(target_isa); - if (simulator.CanSimulate()) { - Expected result = SimulatorExecute(simulator.Get(), f); - if (has_result) { - ASSERT_EQ(expected, result); - } - } - - // Verify on hardware. - if (CanExecuteOnHardware(target_isa)) { - Expected result = f(); - if (has_result) { - ASSERT_EQ(expected, result); - } - } -} - -template -static void Run(const InternalCodeAllocator& allocator, - const CodeGenerator& codegen, - bool has_result, - Expected expected) { - InstructionSet target_isa = codegen.GetInstructionSet(); - - typedef Expected (*fptr)(); - CommonCompilerTest::MakeExecutable(allocator.GetMemory(), allocator.GetSize()); - fptr f = reinterpret_cast(allocator.GetMemory()); - if (target_isa == kThumb2) { - // For thumb we need the bottom bit set. - f = reinterpret_cast(reinterpret_cast(f) + 1); - } - VerifyGeneratedCode(target_isa, f, has_result, expected); -} - -static void ValidateGraph(HGraph* graph) { - GraphChecker graph_checker(graph); - graph_checker.Run(); - if (!graph_checker.IsValid()) { - for (const auto& error : graph_checker.GetErrors()) { - std::cout << error << std::endl; - } - } - ASSERT_TRUE(graph_checker.IsValid()); -} - -template -static void RunCodeNoCheck(CodeGenerator* codegen, - HGraph* graph, - const std::function& hook_before_codegen, - bool has_result, - Expected expected) { - SsaLivenessAnalysis liveness(graph, codegen); - PrepareForRegisterAllocation(graph).Run(); - liveness.Analyze(); - RegisterAllocator::Create(graph->GetArena(), codegen, liveness)->AllocateRegisters(); - hook_before_codegen(graph); - InternalCodeAllocator allocator; - codegen->Compile(&allocator); - Run(allocator, *codegen, has_result, expected); -} - -template -static void RunCode(CodeGenerator* codegen, - HGraph* graph, - std::function hook_before_codegen, - bool has_result, - Expected expected) { - ValidateGraph(graph); - RunCodeNoCheck(codegen, graph, hook_before_codegen, has_result, expected); -} - -template -static void RunCode(CodegenTargetConfig target_config, - HGraph* graph, - std::function hook_before_codegen, - bool has_result, - Expected expected) { - CompilerOptions compiler_options; - std::unique_ptr codegen(target_config.CreateCodeGenerator(graph, compiler_options)); - RunCode(codegen.get(), graph, hook_before_codegen, has_result, expected); -} - -#ifdef ART_ENABLE_CODEGEN_arm -CodeGenerator* create_codegen_arm(HGraph* graph, const CompilerOptions& compiler_options) { - std::unique_ptr features_arm( - ArmInstructionSetFeatures::FromCppDefines()); - return new (graph->GetArena()) TestCodeGeneratorARM(graph, - *features_arm.get(), - compiler_options); -} - -CodeGenerator* create_codegen_arm_vixl32(HGraph* graph, const CompilerOptions& compiler_options) { - std::unique_ptr features_arm( - ArmInstructionSetFeatures::FromCppDefines()); - return new (graph->GetArena()) - TestCodeGeneratorARMVIXL(graph, *features_arm.get(), compiler_options); -} -#endif - -#ifdef ART_ENABLE_CODEGEN_arm64 -CodeGenerator* create_codegen_arm64(HGraph* graph, const CompilerOptions& compiler_options) { - std::unique_ptr features_arm64( - Arm64InstructionSetFeatures::FromCppDefines()); - return new (graph->GetArena()) arm64::CodeGeneratorARM64(graph, - *features_arm64.get(), - compiler_options); -} -#endif - -#ifdef ART_ENABLE_CODEGEN_x86 -CodeGenerator* create_codegen_x86(HGraph* graph, const CompilerOptions& compiler_options) { - std::unique_ptr features_x86( - X86InstructionSetFeatures::FromCppDefines()); - return new (graph->GetArena()) TestCodeGeneratorX86(graph, *features_x86.get(), compiler_options); -} -#endif - -#ifdef ART_ENABLE_CODEGEN_x86_64 -CodeGenerator* create_codegen_x86_64(HGraph* graph, const CompilerOptions& compiler_options) { - std::unique_ptr features_x86_64( - X86_64InstructionSetFeatures::FromCppDefines()); - return new (graph->GetArena()) - x86_64::CodeGeneratorX86_64(graph, *features_x86_64.get(), compiler_options); -} -#endif - -#ifdef ART_ENABLE_CODEGEN_mips -CodeGenerator* create_codegen_mips(HGraph* graph, const CompilerOptions& compiler_options) { - std::unique_ptr features_mips( - MipsInstructionSetFeatures::FromCppDefines()); - return new (graph->GetArena()) - mips::CodeGeneratorMIPS(graph, *features_mips.get(), compiler_options); -} -#endif - -#ifdef ART_ENABLE_CODEGEN_mips64 -CodeGenerator* create_codegen_mips64(HGraph* graph, const CompilerOptions& compiler_options) { - std::unique_ptr features_mips64( - Mips64InstructionSetFeatures::FromCppDefines()); - return new (graph->GetArena()) - mips64::CodeGeneratorMIPS64(graph, *features_mips64.get(), compiler_options); -} -#endif - // Return all combinations of ISA and code generator that are executable on // hardware, or on simulator, and that we'd like to test. static ::std::vector GetTargetConfigs() { -- cgit v1.2.3