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

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: I see your build failures and raise you a rebase. Created 4 years, 7 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 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
178 // to keep the check here simple. 161 // to 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 {
rmcilroy 2016/05/24 14:00:11 nit - newline after {
oth 2016/05/24 15:07:14 Done.
172 void TransformLdaStarToLdrLdar(Bytecode new_bytecode, BytecodeNode* const last,
173 BytecodeNode* const current) {
174 DCHECK_EQ(current->bytecode(), Bytecodes::kStar);
175 //
176 // An example transformation here would be:
177 //
178 // LdaGlobal i0, i1 ____\ LdrGlobal i0, i1, R
179 // Star R ====/ Ldar R
180 //
181 // which loads a global value into both a register and the
182 // accumulator. However, in the second form the Ldar can often be
183 // peephole optimized away unlike the Star in the first form.
184 //
185 last->Transform(new_bytecode, current->operand(0), current->operand_scale());
186 current->set_bytecode(Bytecode::kLdar, current->operand(0),
187 current->operand_scale());
188
189 // If there was a source position on |current| transfer it to the
190 // updated |last| to maintain the debugger's causal view. ie. if an
191 // expression position LdrGlobal is the bytecode that could throw
192 // and if a statement position it needs to be placed before the
193 // store to R occurs.
194 last->source_info().Update(current->source_info());
195 current->source_info().set_invalid();
196 }
197 } // namespace
rmcilroy 2016/05/24 14:00:11 nit - newline above
oth 2016/05/24 15:07:15 Done.
198
199 bool BytecodePeepholeOptimizer::ChangeLdaToLdr(BytecodeNode* const current) {
200 if (current->bytecode() == Bytecode::kStar) {
201 switch (last_.bytecode()) {
202 case Bytecode::kLoadIC:
203 TransformLdaStarToLdrLdar(Bytecode::kLdrNamedProperty, &last_, current);
204 return true;
205 case Bytecode::kKeyedLoadIC:
206 TransformLdaStarToLdrLdar(Bytecode::kLdrKeyedProperty, &last_, current);
207 return true;
208 case Bytecode::kLdaGlobal:
209 TransformLdaStarToLdrLdar(Bytecode::kLdrGlobal, &last_, current);
210 return true;
211 case Bytecode::kLdaContextSlot:
212 TransformLdaStarToLdrLdar(Bytecode::kLdrContextSlot, &last_, current);
213 return true;
214 case Bytecode::kLdaUndefined:
215 TransformLdaStarToLdrLdar(Bytecode::kLdrUndefined, &last_, current);
216 return true;
217 default:
218 break;
219 }
220 }
221 return false;
222 }
223
224 bool BytecodePeepholeOptimizer::RemoveToBooleanFromJump(
225 BytecodeNode* const current) {
226 bool can_remove = Bytecodes::IsJumpIfToBoolean(current->bytecode()) &&
227 Bytecodes::WritesBooleanToAccumulator(last_.bytecode());
228 if (can_remove) {
229 // Conditional jumps with boolean conditions are emiitted in
230 // ToBoolean form by the bytecode array builder,
231 // i.e. JumpIfToBooleanTrue rather JumpIfTrue. The ToBoolean
232 // element can be removed if the previous bytecode put a boolean
233 // value in the accumulator.
234 Bytecode jump = Bytecodes::GetJumpWithoutToBoolean(current->bytecode());
235 current->set_bytecode(jump, current->operand(0), current->operand_scale());
236 }
237 return can_remove;
238 }
239
240 bool BytecodePeepholeOptimizer::RemoveToBooleanFromLogicalNot(
241 BytecodeNode* const current) {
242 bool can_remove = current->bytecode() == Bytecode::kToBooleanLogicalNot &&
243 Bytecodes::WritesBooleanToAccumulator(last_.bytecode());
244 if (can_remove) {
245 // Logical-nots are emitted in ToBoolean form by the bytecode array
246 // builder, The ToBoolean element can be removed if the previous bytecode
247 // put a boolean value in the accumulator.
248 current->set_bytecode(Bytecode::kLogicalNot);
249 }
250 return can_remove;
251 }
252
253 bool BytecodePeepholeOptimizer::UpdateLastAndCurrentBytecodes(
254 BytecodeNode* const current) {
255 return RemoveToBooleanFromJump(current) ||
256 RemoveToBooleanFromLogicalNot(current) || ChangeLdaToLdr(current);
257 }
258
188 bool BytecodePeepholeOptimizer::CanElideLast( 259 bool BytecodePeepholeOptimizer::CanElideLast(
189 const BytecodeNode* const current) const { 260 const BytecodeNode* const current) const {
190 if (!last_is_discardable_) { 261 if (!last_is_discardable_) {
191 return false; 262 return false;
192 } 263 }
193 264
194 if (last_.bytecode() == Bytecode::kNop) { 265 if (last_.bytecode() == Bytecode::kNop) {
195 // Nop are placeholders for holding source position information. 266 // Nop are placeholders for holding source position information.
196 return true; 267 return true;
197 } else if (Bytecodes::IsAccumulatorLoadWithoutEffects(current->bytecode()) && 268 } else if (Bytecodes::IsAccumulatorLoadWithoutEffects(current->bytecode()) &&
198 Bytecodes::IsAccumulatorLoadWithoutEffects(last_.bytecode())) { 269 Bytecodes::IsAccumulatorLoadWithoutEffects(last_.bytecode())) {
199 // The accumulator is invisible to the debugger. If there is a sequence of 270 // 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 271 // consecutive accumulator loads (that don't have side effects) then only
201 // the final load is potentially visible. 272 // the final load is potentially visible.
202 return true; 273 return true;
274 } else if (Bytecodes::GetAccumulatorUse(current->bytecode()) ==
275 AccumulatorUse::kWrite &&
276 Bytecodes::IsAccumulatorLoadWithoutEffects(last_.bytecode())) {
277 // The current instruction clobbers the accumulator without reading it. The
278 // load in the last instruction can be elided as it has no effect.
279 return true;
203 } else { 280 } else {
204 return false; 281 return false;
205 } 282 }
206 } 283 }
207 284
208 BytecodeNode* BytecodePeepholeOptimizer::Optimize(BytecodeNode* current) { 285 BytecodeNode* BytecodePeepholeOptimizer::Optimize(BytecodeNode* current) {
209 UpdateLastAndCurrentBytecodes(current); 286 TryToRemoveLastExpressionPosition(current);
287
288 if (UpdateLastAndCurrentBytecodes(current)) {
289 return current;
290 }
291
210 if (CanElideCurrent(current)) { 292 if (CanElideCurrent(current)) {
211 if (current->source_info().is_valid()) { 293 if (current->source_info().is_valid()) {
294 // Preserve the source information by replacing the current bytecode
295 // with a no op bytecode.
212 current->set_bytecode(Bytecode::kNop); 296 current->set_bytecode(Bytecode::kNop);
213 } else { 297 } else {
214 current = nullptr; 298 current = nullptr;
215 } 299 }
216 } else if (CanElideLast(current) && 300 return current;
217 CanElideLastBasedOnSourcePosition(current)) { 301 }
302
303 if (CanElideLast(current) && CanElideLastBasedOnSourcePosition(current)) {
218 current->source_info().Update(last_.source_info()); 304 current->source_info().Update(last_.source_info());
219 InvalidateLast(); 305 InvalidateLast();
rmcilroy 2016/05/24 14:00:11 Please add "return current" here too ensure we don
oth 2016/05/24 15:07:15 Done.
220 } 306 }
221 return current; 307 return current;
222 } 308 }
223 309
224 } // namespace interpreter 310 } // namespace interpreter
225 } // namespace internal 311 } // namespace internal
226 } // namespace v8 312 } // 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