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 2104165 : BytecodeWriter() {}
27 0 : virtual ~BytecodeWriter() {}
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 : virtual ~BytecodeRegisterOptimizer() {}
43 :
44 : // Perform explicit register transfer operations.
45 8909421 : 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 8909421 : RegisterTransfer(input_info, accumulator_info_);
50 8909425 : }
51 24505570 : void DoStar(Register output) {
52 : RegisterInfo* output_info = GetRegisterInfo(output);
53 24505570 : RegisterTransfer(accumulator_info_, output_info);
54 24505574 : }
55 831841 : void DoMov(Register input, Register output) {
56 : RegisterInfo* input_info = GetRegisterInfo(input);
57 : RegisterInfo* output_info = GetRegisterInfo(output);
58 831841 : RegisterTransfer(input_info, output_info);
59 831841 : }
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 : INLINE(void PrepareForBytecode()) {
67 47514620 : if (Bytecodes::IsJump(bytecode) || bytecode == Bytecode::kDebugger ||
68 : bytecode == Bytecode::kSuspendGenerator) {
69 : // All state must be flushed before emitting
70 : // - a jump bytecode (as the register equivalents at the jump target
71 : // aren't
72 : // known.
73 : // - a call to the debugger (as it can manipulate locals and parameters),
74 : // - a generator suspend (as this involves saving all registers).
75 3112898 : Flush();
76 : }
77 :
78 : // Materialize the accumulator if it is read by the bytecode. The
79 : // accumulator is special and no other register can be materialized
80 : // in it's place.
81 47544751 : if (BytecodeOperands::ReadsAccumulator(accumulator_use)) {
82 14678689 : Materialize(accumulator_info_);
83 : }
84 :
85 : // Materialize an equivalent to the accumulator if it will be
86 : // clobbered when the bytecode is dispatched.
87 47544756 : if (BytecodeOperands::WritesAccumulator(accumulator_use)) {
88 32705798 : PrepareOutputRegister(accumulator_);
89 : }
90 : }
91 :
92 : // Prepares |reg| for being used as an output operand.
93 : void PrepareOutputRegister(Register reg);
94 :
95 : // Prepares registers in |reg_list| for being used as an output operand.
96 : void PrepareOutputRegisterList(RegisterList reg_list);
97 :
98 : // Returns an equivalent register to |reg| to be used as an input operand.
99 : Register GetInputRegister(Register reg);
100 :
101 : // Returns an equivalent register list to |reg_list| to be used as an input
102 : // operand.
103 : RegisterList GetInputRegisterList(RegisterList reg_list);
104 :
105 : int maxiumum_register_index() const { return max_register_index_; }
106 :
107 : private:
108 : static const uint32_t kInvalidEquivalenceId;
109 :
110 : class RegisterInfo;
111 :
112 : // BytecodeRegisterAllocator::Observer interface.
113 : void RegisterAllocateEvent(Register reg) override;
114 : void RegisterListAllocateEvent(RegisterList reg_list) override;
115 : void RegisterListFreeEvent(RegisterList reg) override;
116 :
117 : // Update internal state for register transfer from |input| to |output|
118 : void RegisterTransfer(RegisterInfo* input, RegisterInfo* output);
119 :
120 : // Emit a register transfer bytecode from |input| to |output|.
121 : void OutputRegisterTransfer(RegisterInfo* input, RegisterInfo* output);
122 :
123 : void CreateMaterializedEquivalent(RegisterInfo* info);
124 : RegisterInfo* GetMaterializedEquivalent(RegisterInfo* info);
125 : RegisterInfo* GetMaterializedEquivalentNotAccumulator(RegisterInfo* info);
126 : void Materialize(RegisterInfo* info);
127 : void AddToEquivalenceSet(RegisterInfo* set_member,
128 : RegisterInfo* non_set_member);
129 :
130 : // Methods for finding and creating metadata for each register.
131 115809407 : RegisterInfo* GetRegisterInfo(Register reg) {
132 : size_t index = GetRegisterInfoTableIndex(reg);
133 : DCHECK_LT(index, register_info_table_.size());
134 230346481 : return register_info_table_[index];
135 : }
136 19437947 : RegisterInfo* GetOrCreateRegisterInfo(Register reg) {
137 : size_t index = GetRegisterInfoTableIndex(reg);
138 19437947 : return index < register_info_table_.size() ? register_info_table_[index]
139 52126383 : : NewRegisterInfo(reg);
140 : }
141 : RegisterInfo* NewRegisterInfo(Register reg) {
142 : size_t index = GetRegisterInfoTableIndex(reg);
143 : DCHECK_GE(index, register_info_table_.size());
144 6187467 : GrowRegisterMap(reg);
145 12374952 : return register_info_table_[index];
146 : }
147 :
148 : void GrowRegisterMap(Register reg);
149 :
150 : bool RegisterIsTemporary(Register reg) const {
151 : return reg >= temporary_base_;
152 : }
153 :
154 : bool RegisterIsObservable(Register reg) const {
155 103572366 : return reg != accumulator_ && !RegisterIsTemporary(reg);
156 : }
157 :
158 : static Register OperandToRegister(uint32_t operand) {
159 : return Register::FromOperand(static_cast<int32_t>(operand));
160 : }
161 :
162 : size_t GetRegisterInfoTableIndex(Register reg) const {
163 142679955 : return static_cast<size_t>(reg.index() + register_info_table_offset_);
164 : }
165 :
166 : Register RegisterFromRegisterInfoTableIndex(size_t index) const {
167 29585254 : return Register(static_cast<int>(index) - register_info_table_offset_);
168 : }
169 :
170 69139370 : uint32_t NextEquivalenceId() {
171 69139370 : equivalence_id_++;
172 : // TODO(rmcilroy): use the same type for these and remove static_cast.
173 69139370 : CHECK_NE(static_cast<size_t>(equivalence_id_), kInvalidEquivalenceId);
174 69139370 : return equivalence_id_;
175 : }
176 :
177 : Zone* zone() { return zone_; }
178 :
179 : const Register accumulator_;
180 : RegisterInfo* accumulator_info_;
181 : const Register temporary_base_;
182 : int max_register_index_;
183 :
184 : // Direct mapping to register info.
185 : ZoneVector<RegisterInfo*> register_info_table_;
186 : int register_info_table_offset_;
187 :
188 : // Counter for equivalence sets identifiers.
189 : int equivalence_id_;
190 :
191 : BytecodeWriter* bytecode_writer_;
192 : bool flush_required_;
193 : Zone* zone_;
194 :
195 : DISALLOW_COPY_AND_ASSIGN(BytecodeRegisterOptimizer);
196 : };
197 :
198 : } // namespace interpreter
199 : } // namespace internal
200 : } // namespace v8
201 :
202 : #endif // V8_INTERPRETER_BYTECODE_REGISTER_OPTIMIZER_H_
|