Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(6)

Side by Side Diff: src/interpreter/bytecode-peephole-optimizer.cc

Issue 1985753002: [interpreter] Introduce fused bytecodes for common sequences. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Rebase. Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/interpreter/bytecode-peephole-optimizer.h ('k') | src/interpreter/bytecode-pipeline.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2015 the V8 project authors. All rights reserved. 1 // Copyright 2015 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "src/interpreter/bytecode-peephole-optimizer.h" 5 #include "src/interpreter/bytecode-peephole-optimizer.h"
6 6
7 #include "src/interpreter/constant-array-builder.h" 7 #include "src/interpreter/constant-array-builder.h"
8 #include "src/objects-inl.h" 8 #include "src/objects-inl.h"
9 #include "src/objects.h" 9 #include "src/objects.h"
10 10
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after
87 } 87 }
88 88
89 bool BytecodePeepholeOptimizer::LastBytecodePutsNameInAccumulator() const { 89 bool BytecodePeepholeOptimizer::LastBytecodePutsNameInAccumulator() const {
90 DCHECK(LastIsValid()); 90 DCHECK(LastIsValid());
91 return (last_.bytecode() == Bytecode::kTypeOf || 91 return (last_.bytecode() == Bytecode::kTypeOf ||
92 last_.bytecode() == Bytecode::kToName || 92 last_.bytecode() == Bytecode::kToName ||
93 (last_.bytecode() == Bytecode::kLdaConstant && 93 (last_.bytecode() == Bytecode::kLdaConstant &&
94 GetConstantForIndexOperand(&last_, 0)->IsName())); 94 GetConstantForIndexOperand(&last_, 0)->IsName()));
95 } 95 }
96 96
97 void BytecodePeepholeOptimizer::UpdateLastAndCurrentBytecodes( 97 void BytecodePeepholeOptimizer::TryToRemoveLastExpressionPosition(
98 BytecodeNode* current) { 98 const BytecodeNode* const current) {
99 if (Bytecodes::IsJumpIfToBoolean(current->bytecode()) &&
100 Bytecodes::WritesBooleanToAccumulator(last_.bytecode())) {
101 // Conditional jumps with boolean conditions are emitted in
102 // ToBoolean form by the bytecode array builder,
103 // i.e. JumpIfToBooleanTrue rather JumpIfTrue. The ToBoolean element
104 // can be removed if the previous bytecode put a boolean value in
105 // the accumulator.
106 Bytecode jump = Bytecodes::GetJumpWithoutToBoolean(current->bytecode());
107 current->set_bytecode(jump, current->operand(0), current->operand_scale());
108 } else if (current->bytecode() == Bytecode::kToBooleanLogicalNot &&
109 Bytecodes::WritesBooleanToAccumulator(last_.bytecode())) {
110 // Logical-nots are emitted in ToBoolean form by the bytecode array
111 // builder, The ToBoolean element can be removed if the previous bytecode
112 // put a boolean value in the accumulator.
113 current->set_bytecode(Bytecode::kLogicalNot);
114 }
115
116 if (current->source_info().is_statement() && 99 if (current->source_info().is_statement() &&
117 last_.source_info().is_expression() && 100 last_.source_info().is_expression() &&
118 Bytecodes::IsWithoutExternalSideEffects(last_.bytecode())) { 101 Bytecodes::IsWithoutExternalSideEffects(last_.bytecode())) {
119 // The last bytecode has been marked as expression. It has no 102 // The last bytecode has been marked as expression. It has no
120 // external effects so can't throw and the current bytecode is a 103 // external effects so can't throw and the current bytecode is a
121 // source position. Remove the expression position on the last 104 // source position. Remove the expression position on the last
122 // bytecode to open up potential peephole optimizations and to 105 // bytecode to open up potential peephole optimizations and to
123 // save the memory and perf cost of storing the unneeded 106 // save the memory and perf cost of storing the unneeded
124 // expression position. 107 // expression position.
125 last_.source_info().set_invalid(); 108 last_.source_info().set_invalid();
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
162 // | Expr | YES | MAYBE | MAYBE | 145 // | Expr | YES | MAYBE | MAYBE |
163 // S +--------+--------+--------+--------+ 146 // S +--------+--------+--------+--------+
164 // | Stmt | YES | NO | NO | 147 // | Stmt | YES | NO | NO |
165 // T +--------+--------+--------+--------+ 148 // T +--------+--------+--------+--------+
166 // 149 //
167 // The goal is not lose any statement positions and not lose useful 150 // The goal is not lose any statement positions and not lose useful
168 // expression positions. Whenever the last bytecode is elided it's 151 // expression positions. Whenever the last bytecode is elided it's
169 // source position information is applied to the current node 152 // source position information is applied to the current node
170 // updating it if necessary. 153 // updating it if necessary.
171 // 154 //
172 //
173 // The last bytecode can be elided for the MAYBE cases if the last 155 // The last bytecode can be elided for the MAYBE cases if the last
174 // bytecode is known not to throw. If it throws, the system would 156 // bytecode is known not to throw. If it throws, the system would
175 // not have correct stack trace information. The appropriate check 157 // not have correct stack trace information. The appropriate check
176 // for this would be Bytecodes::IsWithoutExternalSideEffects(), which 158 // for this would be Bytecodes::IsWithoutExternalSideEffects(),
177 // is checked in BytecodePeepholeOptimizer::UpdateLastAndCurrentBytecodes() 159 // which is checked in
178 // to keep the check here simple. 160 // BytecodePeepholeOptimizer::TransformLastAndCurrentBytecodes() to
161 // keep the check here simple.
179 // 162 //
180 // In rare cases, bytecode generation produces consecutive bytecodes 163 // In rare cases, bytecode generation produces consecutive bytecodes
181 // with the same expression positions. In principle, the latter of 164 // with the same expression positions. In principle, the latter of
182 // these can be elided, but would make this function more expensive. 165 // these can be elided, but would make this function more expensive.
183 // 166 //
184 return (!last_.source_info().is_valid() || 167 return (!last_.source_info().is_valid() ||
185 !current->source_info().is_valid()); 168 !current->source_info().is_valid());
186 } 169 }
187 170
171 namespace {
172
173 void TransformLdaStarToLdrLdar(Bytecode new_bytecode, BytecodeNode* const last,
174 BytecodeNode* const current) {
175 DCHECK_EQ(current->bytecode(), Bytecode::kStar);
176 //
177 // An example transformation here would be:
178 //
179 // LdaGlobal i0, i1 ____\ LdrGlobal i0, i1, R
180 // Star R ====/ Ldar R
181 //
182 // which loads a global value into both a register and the
183 // accumulator. However, in the second form the Ldar can often be
184 // peephole optimized away unlike the Star in the first form.
185 //
186 last->Transform(new_bytecode, current->operand(0), current->operand_scale());
187 current->set_bytecode(Bytecode::kLdar, current->operand(0),
188 current->operand_scale());
189
190 // If there was a source position on |current| transfer it to the
191 // updated |last| to maintain the debugger's causal view. ie. if an
192 // expression position LdrGlobal is the bytecode that could throw
193 // and if a statement position it needs to be placed before the
194 // store to R occurs.
195 last->source_info().Update(current->source_info());
196 current->source_info().set_invalid();
197 }
198
199 } // namespace
200
201 bool BytecodePeepholeOptimizer::ChangeLdaToLdr(BytecodeNode* const current) {
202 if (current->bytecode() == Bytecode::kStar) {
203 switch (last_.bytecode()) {
204 case Bytecode::kLoadIC:
205 TransformLdaStarToLdrLdar(Bytecode::kLdrNamedProperty, &last_, current);
206 return true;
207 case Bytecode::kKeyedLoadIC:
208 TransformLdaStarToLdrLdar(Bytecode::kLdrKeyedProperty, &last_, current);
209 return true;
210 case Bytecode::kLdaGlobal:
211 TransformLdaStarToLdrLdar(Bytecode::kLdrGlobal, &last_, current);
212 return true;
213 case Bytecode::kLdaContextSlot:
214 TransformLdaStarToLdrLdar(Bytecode::kLdrContextSlot, &last_, current);
215 return true;
216 case Bytecode::kLdaUndefined:
217 TransformLdaStarToLdrLdar(Bytecode::kLdrUndefined, &last_, current);
218 return true;
219 default:
220 break;
221 }
222 }
223 return false;
224 }
225
226 bool BytecodePeepholeOptimizer::RemoveToBooleanFromJump(
227 BytecodeNode* const current) {
228 bool can_remove = Bytecodes::IsJumpIfToBoolean(current->bytecode()) &&
229 Bytecodes::WritesBooleanToAccumulator(last_.bytecode());
230 if (can_remove) {
231 // Conditional jumps with boolean conditions are emiitted in
232 // ToBoolean form by the bytecode array builder,
233 // i.e. JumpIfToBooleanTrue rather JumpIfTrue. The ToBoolean
234 // element can be removed if the previous bytecode put a boolean
235 // value in the accumulator.
236 Bytecode jump = Bytecodes::GetJumpWithoutToBoolean(current->bytecode());
237 current->set_bytecode(jump, current->operand(0), current->operand_scale());
238 }
239 return can_remove;
240 }
241
242 bool BytecodePeepholeOptimizer::RemoveToBooleanFromLogicalNot(
243 BytecodeNode* const current) {
244 bool can_remove = current->bytecode() == Bytecode::kToBooleanLogicalNot &&
245 Bytecodes::WritesBooleanToAccumulator(last_.bytecode());
246 if (can_remove) {
247 // Logical-nots are emitted in ToBoolean form by the bytecode array
248 // builder, The ToBoolean element can be removed if the previous bytecode
249 // put a boolean value in the accumulator.
250 current->set_bytecode(Bytecode::kLogicalNot);
251 }
252 return can_remove;
253 }
254
255 bool BytecodePeepholeOptimizer::TransformLastAndCurrentBytecodes(
256 BytecodeNode* const current) {
257 return RemoveToBooleanFromJump(current) ||
258 RemoveToBooleanFromLogicalNot(current) || ChangeLdaToLdr(current);
259 }
260
188 bool BytecodePeepholeOptimizer::CanElideLast( 261 bool BytecodePeepholeOptimizer::CanElideLast(
189 const BytecodeNode* const current) const { 262 const BytecodeNode* const current) const {
190 if (!last_is_discardable_) { 263 if (!last_is_discardable_) {
191 return false; 264 return false;
192 } 265 }
193 266
194 if (last_.bytecode() == Bytecode::kNop) { 267 if (last_.bytecode() == Bytecode::kNop) {
195 // Nop are placeholders for holding source position information. 268 // Nop are placeholders for holding source position information.
196 return true; 269 return true;
197 } else if (Bytecodes::IsAccumulatorLoadWithoutEffects(current->bytecode()) && 270 } else if (Bytecodes::IsAccumulatorLoadWithoutEffects(current->bytecode()) &&
198 Bytecodes::IsAccumulatorLoadWithoutEffects(last_.bytecode())) { 271 Bytecodes::IsAccumulatorLoadWithoutEffects(last_.bytecode())) {
199 // The accumulator is invisible to the debugger. If there is a sequence of 272 // The accumulator is invisible to the debugger. If there is a sequence of
200 // consecutive accumulator loads (that don't have side effects) then only 273 // consecutive accumulator loads (that don't have side effects) then only
201 // the final load is potentially visible. 274 // the final load is potentially visible.
202 return true; 275 return true;
276 } else if (Bytecodes::GetAccumulatorUse(current->bytecode()) ==
277 AccumulatorUse::kWrite &&
278 Bytecodes::IsAccumulatorLoadWithoutEffects(last_.bytecode())) {
279 // The current instruction clobbers the accumulator without reading it. The
280 // load in the last instruction can be elided as it has no effect.
281 return true;
203 } else { 282 } else {
204 return false; 283 return false;
205 } 284 }
206 } 285 }
207 286
208 BytecodeNode* BytecodePeepholeOptimizer::Optimize(BytecodeNode* current) { 287 BytecodeNode* BytecodePeepholeOptimizer::Optimize(BytecodeNode* current) {
209 UpdateLastAndCurrentBytecodes(current); 288 TryToRemoveLastExpressionPosition(current);
289
290 if (TransformLastAndCurrentBytecodes(current)) {
291 return current;
292 }
293
210 if (CanElideCurrent(current)) { 294 if (CanElideCurrent(current)) {
211 if (current->source_info().is_valid()) { 295 if (current->source_info().is_valid()) {
296 // Preserve the source information by replacing the current bytecode
297 // with a no op bytecode.
212 current->set_bytecode(Bytecode::kNop); 298 current->set_bytecode(Bytecode::kNop);
213 } else { 299 } else {
214 current = nullptr; 300 current = nullptr;
215 } 301 }
216 } else if (CanElideLast(current) && 302 return current;
217 CanElideLastBasedOnSourcePosition(current)) { 303 }
304
305 if (CanElideLast(current) && CanElideLastBasedOnSourcePosition(current)) {
218 current->source_info().Update(last_.source_info()); 306 current->source_info().Update(last_.source_info());
219 InvalidateLast(); 307 InvalidateLast();
308 return current;
220 } 309 }
310
221 return current; 311 return current;
222 } 312 }
223 313
224 } // namespace interpreter 314 } // namespace interpreter
225 } // namespace internal 315 } // namespace internal
226 } // namespace v8 316 } // namespace v8
OLDNEW
« no previous file with comments | « src/interpreter/bytecode-peephole-optimizer.h ('k') | src/interpreter/bytecode-pipeline.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698