Line data Source code
1 : // Copyright 2016 the V8 project authors. All rights reserved.
2 : // Use of this source code is governed by a BSD-style license that can be
3 : // found in the LICENSE file.
4 :
5 : #ifndef V8_INTERPRETER_BYTECODE_REGISTER_OPTIMIZER_H_
6 : #define V8_INTERPRETER_BYTECODE_REGISTER_OPTIMIZER_H_
7 :
8 : #include "src/base/compiler-specific.h"
9 : #include "src/globals.h"
10 : #include "src/interpreter/bytecode-register-allocator.h"
11 :
12 : namespace v8 {
13 : namespace internal {
14 : namespace interpreter {
15 :
16 : // An optimization stage for eliminating unnecessary transfers between
17 : // registers. The bytecode generator uses temporary registers
18 : // liberally for correctness and convenience and this stage removes
19 : // transfers that are not required and preserves correctness.
20 : class V8_EXPORT_PRIVATE BytecodeRegisterOptimizer final
21 : : public NON_EXPORTED_BASE(BytecodeRegisterAllocator::Observer),
22 : public NON_EXPORTED_BASE(ZoneObject) {
23 : public:
24 : class BytecodeWriter {
25 : public:
26 2106756 : BytecodeWriter() = default;
27 8 : virtual ~BytecodeWriter() = default;
28 :
29 : // Called to emit a register transfer bytecode.
30 : virtual void EmitLdar(Register input) = 0;
31 : virtual void EmitStar(Register output) = 0;
32 : virtual void EmitMov(Register input, Register output) = 0;
33 :
34 : private:
35 : DISALLOW_COPY_AND_ASSIGN(BytecodeWriter);
36 : };
37 :
38 : BytecodeRegisterOptimizer(Zone* zone,
39 : BytecodeRegisterAllocator* register_allocator,
40 : int fixed_registers_count, int parameter_count,
41 : BytecodeWriter* bytecode_writer);
42 0 : ~BytecodeRegisterOptimizer() override = default;
43 :
44 : // Perform explicit register transfer operations.
45 7629776 : void DoLdar(Register input) {
46 : // TODO(rmcilroy): Avoid treating accumulator loads as clobbering the
47 : // accumulator until the value is actually materialized in the accumulator.
48 : RegisterInfo* input_info = GetRegisterInfo(input);
49 7629776 : RegisterTransfer(input_info, accumulator_info_);
50 7629821 : }
51 24899342 : void DoStar(Register output) {
52 : RegisterInfo* output_info = GetRegisterInfo(output);
53 24899342 : RegisterTransfer(accumulator_info_, output_info);
54 24900225 : }
55 725061 : void DoMov(Register input, Register output) {
56 : RegisterInfo* input_info = GetRegisterInfo(input);
57 : RegisterInfo* output_info = GetRegisterInfo(output);
58 725061 : RegisterTransfer(input_info, output_info);
59 725073 : }
60 :
61 : // Materialize all live registers and flush equivalence sets.
62 : void Flush();
63 :
64 : // Prepares for |bytecode|.
65 : template <Bytecode bytecode, AccumulatorUse accumulator_use>
66 : V8_INLINE void PrepareForBytecode() {
67 53450135 : if (Bytecodes::IsJump(bytecode) || Bytecodes::IsSwitch(bytecode) ||
68 : bytecode == Bytecode::kDebugger ||
69 : bytecode == Bytecode::kSuspendGenerator ||
70 : bytecode == Bytecode::kResumeGenerator) {
71 : // All state must be flushed before emitting
72 : // - a jump bytecode (as the register equivalents at the jump target
73 : // aren't known)
74 : // - a switch bytecode (as the register equivalents at the switch targets
75 : // aren't known)
76 : // - a call to the debugger (as it can manipulate locals and parameters),
77 : // - a generator suspend (as this involves saving all registers).
78 : // - a generator register restore.
79 2144606 : Flush();
80 : }
81 :
82 : // Materialize the accumulator if it is read by the bytecode. The
83 : // accumulator is special and no other register can be materialized
84 : // in it's place.
85 53505525 : if (BytecodeOperands::ReadsAccumulator(accumulator_use)) {
86 16843333 : Materialize(accumulator_info_);
87 : }
88 :
89 : // Materialize an equivalent to the accumulator if it will be
90 : // clobbered when the bytecode is dispatched.
91 53505657 : if (BytecodeOperands::WritesAccumulator(accumulator_use)) {
92 39079145 : PrepareOutputRegister(accumulator_);
93 : }
94 : }
95 :
96 : // Prepares |reg| for being used as an output operand.
97 : void PrepareOutputRegister(Register reg);
98 :
99 : // Prepares registers in |reg_list| for being used as an output operand.
100 : void PrepareOutputRegisterList(RegisterList reg_list);
101 :
102 : // Returns an equivalent register to |reg| to be used as an input operand.
103 : Register GetInputRegister(Register reg);
104 :
105 : // Returns an equivalent register list to |reg_list| to be used as an input
106 : // operand.
107 : RegisterList GetInputRegisterList(RegisterList reg_list);
108 :
109 : int maxiumum_register_index() const { return max_register_index_; }
110 :
111 : private:
112 : static const uint32_t kInvalidEquivalenceId;
113 :
114 : class RegisterInfo;
115 :
116 : // BytecodeRegisterAllocator::Observer interface.
117 : void RegisterAllocateEvent(Register reg) override;
118 : void RegisterListAllocateEvent(RegisterList reg_list) override;
119 : void RegisterListFreeEvent(RegisterList reg) override;
120 :
121 : // Update internal state for register transfer from |input| to |output|
122 : void RegisterTransfer(RegisterInfo* input, RegisterInfo* output);
123 :
124 : // Emit a register transfer bytecode from |input| to |output|.
125 : void OutputRegisterTransfer(RegisterInfo* input, RegisterInfo* output);
126 :
127 : void CreateMaterializedEquivalent(RegisterInfo* info);
128 : RegisterInfo* GetMaterializedEquivalent(RegisterInfo* info);
129 : RegisterInfo* GetMaterializedEquivalentNotAccumulator(RegisterInfo* info);
130 : void Materialize(RegisterInfo* info);
131 : void AddToEquivalenceSet(RegisterInfo* set_member,
132 : RegisterInfo* non_set_member);
133 :
134 : void PushToRegistersNeedingFlush(RegisterInfo* reg);
135 : bool EnsureAllRegistersAreFlushed() const;
136 :
137 : // Methods for finding and creating metadata for each register.
138 124014014 : RegisterInfo* GetRegisterInfo(Register reg) {
139 : size_t index = GetRegisterInfoTableIndex(reg);
140 : DCHECK_LT(index, register_info_table_.size());
141 246646316 : return register_info_table_[index];
142 : }
143 21353888 : RegisterInfo* GetOrCreateRegisterInfo(Register reg) {
144 : size_t index = GetRegisterInfoTableIndex(reg);
145 21353888 : return index < register_info_table_.size() ? register_info_table_[index]
146 58113946 : : NewRegisterInfo(reg);
147 : }
148 : RegisterInfo* NewRegisterInfo(Register reg) {
149 : size_t index = GetRegisterInfoTableIndex(reg);
150 : DCHECK_GE(index, register_info_table_.size());
151 5947752 : GrowRegisterMap(reg);
152 11895572 : return register_info_table_[index];
153 : }
154 :
155 : void GrowRegisterMap(Register reg);
156 :
157 : bool RegisterIsTemporary(Register reg) const {
158 : return reg >= temporary_base_;
159 : }
160 :
161 : bool RegisterIsObservable(Register reg) const {
162 97238237 : return reg != accumulator_ && !RegisterIsTemporary(reg);
163 : }
164 :
165 : static Register OperandToRegister(uint32_t operand) {
166 : return Register::FromOperand(static_cast<int32_t>(operand));
167 : }
168 :
169 : size_t GetRegisterInfoTableIndex(Register reg) const {
170 152707781 : return static_cast<size_t>(reg.index() + register_info_table_offset_);
171 : }
172 :
173 : Register RegisterFromRegisterInfoTableIndex(size_t index) const {
174 26260318 : return Register(static_cast<int>(index) - register_info_table_offset_);
175 : }
176 :
177 72859077 : uint32_t NextEquivalenceId() {
178 72859077 : equivalence_id_++;
179 : // TODO(rmcilroy): use the same type for these and remove static_cast.
180 72859077 : CHECK_NE(static_cast<size_t>(equivalence_id_), kInvalidEquivalenceId);
181 72859077 : return equivalence_id_;
182 : }
183 :
184 : void AllocateRegister(RegisterInfo* info);
185 :
186 : Zone* zone() { return zone_; }
187 :
188 : const Register accumulator_;
189 : RegisterInfo* accumulator_info_;
190 : const Register temporary_base_;
191 : int max_register_index_;
192 :
193 : // Direct mapping to register info.
194 : ZoneVector<RegisterInfo*> register_info_table_;
195 : int register_info_table_offset_;
196 :
197 : ZoneDeque<RegisterInfo*> registers_needing_flushed_;
198 :
199 : // Counter for equivalence sets identifiers.
200 : int equivalence_id_;
201 :
202 : BytecodeWriter* bytecode_writer_;
203 : bool flush_required_;
204 : Zone* zone_;
205 :
206 : DISALLOW_COPY_AND_ASSIGN(BytecodeRegisterOptimizer);
207 : };
208 :
209 : } // namespace interpreter
210 : } // namespace internal
211 : } // namespace v8
212 :
213 : #endif // V8_INTERPRETER_BYTECODE_REGISTER_OPTIMIZER_H_
|