| // Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file |
| // for details. All rights reserved. Use of this source code is governed by a |
| // BSD-style license that can be found in the LICENSE file. |
| |
| #ifndef RUNTIME_VM_COMPILER_BACKEND_PARALLEL_MOVE_RESOLVER_H_ |
| #define RUNTIME_VM_COMPILER_BACKEND_PARALLEL_MOVE_RESOLVER_H_ |
| |
| #if defined(DART_PRECOMPILED_RUNTIME) |
| #error "AOT runtime should not use compiler sources (including header files)" |
| #endif // defined(DART_PRECOMPILED_RUNTIME) |
| |
| #include "vm/allocation.h" |
| #include "vm/compiler/backend/flow_graph_compiler.h" |
| #include "vm/compiler/backend/locations.h" |
| #include "vm/constants.h" |
| |
| namespace dart { |
| |
| class MoveOperands; |
| |
| class ParallelMoveResolver : public ValueObject { |
| public: |
| ParallelMoveResolver(); |
| |
| // Schedule moves specified by the given parallel move and store the |
| // schedule on the parallel move itself. |
| void Resolve(ParallelMoveInstr* parallel_move); |
| |
| private: |
| // Build the initial list of moves. |
| void BuildInitialMoveList(ParallelMoveInstr* parallel_move); |
| |
| // Perform the move at the moves_ index in question (possibly requiring |
| // other moves to satisfy dependencies). |
| void PerformMove(const InstructionSource& source, int index); |
| |
| // Schedule a move and remove it from the move graph. |
| void AddMoveToSchedule(int index); |
| |
| // Schedule a swap of two operands. The move from |
| // source to destination is removed from the move graph. |
| void AddSwapToSchedule(int index); |
| |
| FlowGraphCompiler* compiler_; |
| |
| // List of moves not yet resolved. |
| GrowableArray<MoveOperands> moves_; |
| |
| enum class OpKind : uint8_t { |
| kNop, |
| kMove, |
| kSwap, |
| }; |
| |
| struct Op { |
| OpKind kind; |
| MoveOperands operands; |
| }; |
| |
| GrowableArray<Op> scheduled_ops_; |
| |
| friend class MoveSchedule; |
| friend class ParallelMoveEmitter; |
| friend class FlowGraphDeserializer; |
| }; |
| |
| class ParallelMoveEmitter : public ValueObject { |
| public: |
| ParallelMoveEmitter(FlowGraphCompiler* compiler, |
| ParallelMoveInstr* parallel_move) |
| : compiler_(compiler), parallel_move_(parallel_move) {} |
| |
| void EmitNativeCode(); |
| |
| private: |
| class ScratchFpuRegisterScope : public ValueObject { |
| public: |
| ScratchFpuRegisterScope(ParallelMoveEmitter* emitter, FpuRegister blocked); |
| ~ScratchFpuRegisterScope(); |
| |
| FpuRegister reg() const { return reg_; } |
| |
| private: |
| ParallelMoveEmitter* const emitter_; |
| FpuRegister reg_; |
| bool spilled_; |
| }; |
| |
| class TemporaryAllocator : public TemporaryRegisterAllocator { |
| public: |
| TemporaryAllocator(ParallelMoveEmitter* emitter, Register blocked); |
| |
| Register AllocateTemporary() override; |
| void ReleaseTemporary() override; |
| DEBUG_ONLY(bool DidAllocateTemporary() { return allocated_; }) |
| |
| virtual ~TemporaryAllocator() { ASSERT(reg_ == kNoRegister); } |
| |
| private: |
| ParallelMoveEmitter* const emitter_; |
| const Register blocked_; |
| Register reg_; |
| bool spilled_; |
| DEBUG_ONLY(bool allocated_ = false); |
| }; |
| |
| class ScratchRegisterScope : public ValueObject { |
| public: |
| ScratchRegisterScope(ParallelMoveEmitter* emitter, Register blocked); |
| ~ScratchRegisterScope(); |
| |
| Register reg() const { return reg_; } |
| |
| private: |
| TemporaryAllocator allocator_; |
| Register reg_; |
| }; |
| |
| bool IsScratchLocation(Location loc); |
| intptr_t AllocateScratchRegister(Location::Kind kind, |
| uword blocked_mask, |
| intptr_t first_free_register, |
| intptr_t last_free_register, |
| bool* spilled); |
| |
| void SpillScratch(Register reg); |
| void RestoreScratch(Register reg); |
| void SpillFpuScratch(FpuRegister reg); |
| void RestoreFpuScratch(FpuRegister reg); |
| |
| // Generate the code for a move from source to destination. |
| void EmitMove(const MoveOperands& move); |
| |
| void EmitSwap(const MoveOperands& swap); |
| |
| // Verify the move list before performing moves. |
| void Verify(); |
| |
| // Helpers for non-trivial source-destination combinations that cannot |
| // be handled by a single instruction. |
| void MoveMemoryToMemory(const compiler::Address& dst, |
| const compiler::Address& src); |
| void Exchange(Register reg, const compiler::Address& mem); |
| void Exchange(const compiler::Address& mem1, const compiler::Address& mem2); |
| void Exchange(Register reg, Register base_reg, intptr_t stack_offset); |
| void Exchange(Register base_reg1, |
| intptr_t stack_offset1, |
| Register base_reg2, |
| intptr_t stack_offset2); |
| |
| FlowGraphCompiler* const compiler_; |
| ParallelMoveInstr* parallel_move_; |
| intptr_t current_move_; |
| }; |
| |
| } // namespace dart |
| |
| #endif // RUNTIME_VM_COMPILER_BACKEND_PARALLEL_MOVE_RESOLVER_H_ |