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: nit. 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::UpdateCurrentBytecode(BytecodeNode* current) {
98 if (Bytecodes::IsJumpIfToBoolean(current->bytecode()) &&
99 Bytecodes::WritesBooleanToAccumulator(last_.bytecode())) {
100 // Conditional jumps with boolean conditions are emitted in
101 // ToBoolean form by the bytecode array builder,
102 // i.e. JumpIfToBooleanTrue rather JumpIfTrue. The ToBoolean element
103 // can be removed if the previous bytecode put a boolean value in
104 // the accumulator.
105 Bytecode jump = Bytecodes::GetJumpWithoutToBoolean(current->bytecode());
106 current->set_bytecode(jump, current->operand(0), current->operand_scale());
107 } else if (current->bytecode() == Bytecode::kToBooleanLogicalNot &&
108 Bytecodes::WritesBooleanToAccumulator(last_.bytecode())) {
109 // Logical-nots are emitted in ToBoolean form by the bytecode array
110 // builder, The ToBoolean element can be removed if the previous bytecode
111 // put a boolean value in the accumulator.
112 current->set_bytecode(Bytecode::kLogicalNot);
113 }
114 }
115
116 bool BytecodePeepholeOptimizer::CanElideCurrent( 97 bool BytecodePeepholeOptimizer::CanElideCurrent(
117 const BytecodeNode* const current) const { 98 const BytecodeNode* const current) const {
118 if (Bytecodes::IsLdarOrStar(last_.bytecode()) && 99 if (Bytecodes::IsLdarOrStar(last_.bytecode()) &&
119 Bytecodes::IsLdarOrStar(current->bytecode()) && 100 Bytecodes::IsLdarOrStar(current->bytecode()) &&
120 current->operand(0) == last_.operand(0)) { 101 current->operand(0) == last_.operand(0)) {
121 // Ldar and Star make the accumulator and register hold equivalent 102 // Ldar and Star make the accumulator and register hold equivalent
122 // values. Only the first bytecode is needed if there's a sequence 103 // values. Only the first bytecode is needed if there's a sequence
123 // of back-to-back Ldar and Star bytecodes with the same operand. 104 // of back-to-back Ldar and Star bytecodes with the same operand.
124 return true; 105 return true;
125 } else if (current->bytecode() == Bytecode::kToName && 106 } else if (current->bytecode() == Bytecode::kToName &&
126 LastBytecodePutsNameInAccumulator()) { 107 LastBytecodePutsNameInAccumulator()) {
127 // If the previous bytecode ensured a name was in the accumulator, 108 // If the previous bytecode ensured a name was in the accumulator,
128 // the type coercion ToName() can be elided. 109 // the type coercion ToName() can be elided.
129 return true; 110 return true;
130 } else { 111 } else {
131 // Additional candidates for eliding current: 112 // Additional candidates for eliding current:
132 // (i) ToNumber if the last puts a number in the accumulator. 113 // (i) ToNumber if the last puts a number in the accumulator.
133 return false; 114 return false;
134 } 115 }
135 } 116 }
136 117
118 void BytecodePeepholeOptimizer::ChangeLoadStarToLdrLdar(
119 Bytecode new_bytecode, BytecodeNode* const current) {
120 last_.Transform(new_bytecode, current->operand(0), current->operand_scale());
121 current->set_bytecode(Bytecode::kLdar, current->operand(0),
122 current->operand_scale());
123 if (current->source_info().is_valid()) {
124 last_.source_info().Update(current->source_info());
125 current->source_info().set_invalid();
126 }
127 }
128
129 bool BytecodePeepholeOptimizer::ChangeLoadToLdr(BytecodeNode* const current) {
130 if (current->bytecode() == Bytecode::kStar) {
131 switch (last_.bytecode()) {
132 case Bytecode::kLoadIC:
133 ChangeLoadStarToLdrLdar(Bytecode::kLdrNamedProperty, current);
134 return true;
135 case Bytecode::kKeyedLoadIC:
136 ChangeLoadStarToLdrLdar(Bytecode::kLdrKeyedProperty, current);
137 return true;
138 case Bytecode::kLdaGlobal:
139 ChangeLoadStarToLdrLdar(Bytecode::kLdrGlobal, current);
140 return true;
141 case Bytecode::kLdaContextSlot:
142 ChangeLoadStarToLdrLdar(Bytecode::kLdrContextSlot, current);
143 return true;
144 case Bytecode::kLdaUndefined:
145 ChangeLoadStarToLdrLdar(Bytecode::kLdrUndefined, current);
146 return true;
147 default:
148 break;
149 }
150 }
151 return false;
152 }
153
154 bool BytecodePeepholeOptimizer::RemoveToBooleanFromJump(
155 BytecodeNode* const current) {
156 bool can_remove = Bytecodes::IsJumpIfToBoolean(current->bytecode()) &&
157 Bytecodes::WritesBooleanToAccumulator(last_.bytecode());
158 if (can_remove) {
159 // Conditional jumps with boolean conditions are emiitted in
160 // ToBoolean form by the bytecode array builder,
161 // i.e. JumpIfToBooleanTrue rather JumpIfTrue. The ToBoolean
162 // element can be removed if the previous bytecode put a boolean
163 // value in the accumulator.
164 Bytecode jump = Bytecodes::GetJumpWithoutToBoolean(current->bytecode());
165 current->set_bytecode(jump, current->operand(0), current->operand_scale());
166 }
167 return can_remove;
168 }
169
170 bool BytecodePeepholeOptimizer::RemoveToBooleanFromLogicalNot(
171 BytecodeNode* const current) {
172 bool can_remove = current->bytecode() == Bytecode::kToBooleanLogicalNot &&
173 Bytecodes::WritesBooleanToAccumulator(last_.bytecode());
174 if (can_remove) {
175 // Logical-nots are emitted in ToBoolean form by the bytecode array
176 // builder, The ToBoolean element can be removed if the previous bytecode
177 // put a boolean value in the accumulator.
178 current->set_bytecode(Bytecode::kLogicalNot);
179 }
180 return can_remove;
181 }
182
183 bool BytecodePeepholeOptimizer::SimpleSubstitution(
184 BytecodeNode* const current) {
185 return RemoveToBooleanFromJump(current) || ChangeLoadToLdr(current) ||
186 RemoveToBooleanFromLogicalNot(current);
rmcilroy 2016/05/19 10:01:02 nit - RemoveTo calls together.
oth 2016/05/19 10:35:22 Done.
187 }
188
137 bool BytecodePeepholeOptimizer::CanElideLast( 189 bool BytecodePeepholeOptimizer::CanElideLast(
138 const BytecodeNode* const current) const { 190 const BytecodeNode* const current) const {
139 if (!last_is_discardable_) { 191 if (!last_is_discardable_) {
140 return false; 192 return false;
141 } 193 }
142 194
143 if (last_.bytecode() == Bytecode::kNop) { 195 if (last_.bytecode() == Bytecode::kNop) {
144 // Nop are placeholders for holding source position information 196 // Nop are placeholders for holding source position information
145 // and can be elided. 197 // and can be elided.
146 return true; 198 return true;
147 } else if (Bytecodes::IsAccumulatorLoadWithoutEffects(current->bytecode()) && 199 } else if (Bytecodes::IsAccumulatorLoadWithoutEffects(current->bytecode()) &&
148 Bytecodes::IsAccumulatorLoadWithoutEffects(last_.bytecode())) { 200 Bytecodes::IsAccumulatorLoadWithoutEffects(last_.bytecode())) {
149 // The accumulator is invisible to the debugger. If there is a sequence of 201 // The accumulator is invisible to the debugger. If there is a sequence of
150 // consecutive accumulator loads (that don't have side effects) then only 202 // consecutive accumulator loads (that don't have side effects) then only
151 // the final load is potentially visible. 203 // the final load is potentially visible.
152 return true; 204 return true;
205 } else if (Bytecodes::GetAccumulatorUse(current->bytecode()) ==
206 AccumulatorUse::kWrite &&
207 Bytecodes::IsAccumulatorLoadWithoutEffects(last_.bytecode())) {
208 // The current instruction clobbers the accumulator without reading it. The
209 // load in the last instruction can be elided as it has no effect.
210 return true;
153 } else { 211 } else {
154 return false; 212 return false;
155 } 213 }
156 } 214 }
157 215
158 BytecodeNode* BytecodePeepholeOptimizer::Optimize(BytecodeNode* current) { 216 BytecodeNode* BytecodePeepholeOptimizer::Optimize(BytecodeNode* current) {
159 UpdateCurrentBytecode(current); 217 if (!SimpleSubstitution(current)) {
218 if (CanElideCurrent(current)) {
219 if (current->source_info().is_valid()) {
rmcilroy 2016/05/19 10:01:02 As discussed offline, I think this should be if (c
oth 2016/05/19 10:35:22 The is_statement() was a daft mistake. Gone.
220 if (current->source_info().is_statement()) {
221 current->set_bytecode(Bytecode::kNop);
222 }
223 } else {
224 return nullptr;
225 }
226 }
160 227
161 if (CanElideCurrent(current)) { 228 if (CanElideLast(current)) {
162 if (current->source_info().is_valid()) { 229 if (last_.source_info().is_valid()) {
163 current->set_bytecode(Bytecode::kNop); 230 current->source_info().Update(last_.source_info());
164 } else { 231 }
165 current = nullptr; 232 InvalidateLast();
166 } 233 }
167 } else if (CanElideLast(current)) {
168 if (last_.source_info().is_valid()) {
169 current->source_info().Update(last_.source_info());
170 }
171 InvalidateLast();
172 } 234 }
173 return current; 235 return current;
174 } 236 }
175 237
176 } // namespace interpreter 238 } // namespace interpreter
177 } // namespace internal 239 } // namespace internal
178 } // namespace v8 240 } // 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