OLD | NEW |
1 // Copyright 2014 the V8 project authors. All rights reserved. | 1 // Copyright 2014 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 #ifndef V8_COMPILER_NODE_MATCHERS_H_ | 5 #ifndef V8_COMPILER_NODE_MATCHERS_H_ |
6 #define V8_COMPILER_NODE_MATCHERS_H_ | 6 #define V8_COMPILER_NODE_MATCHERS_H_ |
7 | 7 |
8 #include <cmath> | 8 #include <cmath> |
9 | 9 |
10 #include "src/compiler/node.h" | 10 #include "src/compiler/node.h" |
(...skipping 153 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
164 typedef BinopMatcher<Int32Matcher, Int32Matcher> Int32BinopMatcher; | 164 typedef BinopMatcher<Int32Matcher, Int32Matcher> Int32BinopMatcher; |
165 typedef BinopMatcher<Uint32Matcher, Uint32Matcher> Uint32BinopMatcher; | 165 typedef BinopMatcher<Uint32Matcher, Uint32Matcher> Uint32BinopMatcher; |
166 typedef BinopMatcher<Int64Matcher, Int64Matcher> Int64BinopMatcher; | 166 typedef BinopMatcher<Int64Matcher, Int64Matcher> Int64BinopMatcher; |
167 typedef BinopMatcher<Uint64Matcher, Uint64Matcher> Uint64BinopMatcher; | 167 typedef BinopMatcher<Uint64Matcher, Uint64Matcher> Uint64BinopMatcher; |
168 typedef BinopMatcher<IntPtrMatcher, IntPtrMatcher> IntPtrBinopMatcher; | 168 typedef BinopMatcher<IntPtrMatcher, IntPtrMatcher> IntPtrBinopMatcher; |
169 typedef BinopMatcher<UintPtrMatcher, UintPtrMatcher> UintPtrBinopMatcher; | 169 typedef BinopMatcher<UintPtrMatcher, UintPtrMatcher> UintPtrBinopMatcher; |
170 typedef BinopMatcher<Float64Matcher, Float64Matcher> Float64BinopMatcher; | 170 typedef BinopMatcher<Float64Matcher, Float64Matcher> Float64BinopMatcher; |
171 typedef BinopMatcher<NumberMatcher, NumberMatcher> NumberBinopMatcher; | 171 typedef BinopMatcher<NumberMatcher, NumberMatcher> NumberBinopMatcher; |
172 | 172 |
173 | 173 |
| 174 template <class BinopMatcher, IrOpcode::Value kMulOpcode, |
| 175 IrOpcode::Value kShiftOpcode> |
| 176 struct ScaleMatcher { |
| 177 explicit ScaleMatcher(Node* node, bool allow_power_of_two_plus_one = false) |
| 178 : scale_(-1), power_of_two_plus_one_(false) { |
| 179 if (node->InputCount() < 2) return; |
| 180 BinopMatcher m(node); |
| 181 if (node->opcode() == kShiftOpcode) { |
| 182 if (m.right().HasValue()) { |
| 183 typename BinopMatcher::RightMatcher::ValueType value = |
| 184 m.right().Value(); |
| 185 if (value >= 0 && value <= 3) { |
| 186 scale_ = static_cast<int>(value); |
| 187 } |
| 188 } |
| 189 } else if (node->opcode() == kMulOpcode) { |
| 190 if (m.right().HasValue()) { |
| 191 typename BinopMatcher::RightMatcher::ValueType value = |
| 192 m.right().Value(); |
| 193 if (value == 1) { |
| 194 scale_ = 0; |
| 195 } else if (value == 2) { |
| 196 scale_ = 1; |
| 197 } else if (value == 4) { |
| 198 scale_ = 2; |
| 199 } else if (value == 8) { |
| 200 scale_ = 3; |
| 201 } else if (allow_power_of_two_plus_one) { |
| 202 if (value == 3) { |
| 203 scale_ = 1; |
| 204 power_of_two_plus_one_ = true; |
| 205 } else if (value == 5) { |
| 206 scale_ = 2; |
| 207 power_of_two_plus_one_ = true; |
| 208 } else if (value == 9) { |
| 209 scale_ = 3; |
| 210 power_of_two_plus_one_ = true; |
| 211 } |
| 212 } |
| 213 } |
| 214 } |
| 215 } |
| 216 |
| 217 bool matches() const { return scale_ != -1; } |
| 218 int scale() const { return scale_; } |
| 219 bool power_of_two_plus_one() const { return power_of_two_plus_one_; } |
| 220 |
| 221 private: |
| 222 int scale_; |
| 223 bool power_of_two_plus_one_; |
| 224 }; |
| 225 |
| 226 typedef ScaleMatcher<Int32BinopMatcher, IrOpcode::kInt32Mul, |
| 227 IrOpcode::kWord32Shl> Int32ScaleMatcher; |
| 228 typedef ScaleMatcher<Int64BinopMatcher, IrOpcode::kInt64Mul, |
| 229 IrOpcode::kWord64Shl> Int64ScaleMatcher; |
| 230 |
| 231 |
174 template <class BinopMatcher, IrOpcode::Value kAddOpcode, | 232 template <class BinopMatcher, IrOpcode::Value kAddOpcode, |
175 IrOpcode::Value kMulOpcode, IrOpcode::Value kShiftOpcode> | 233 IrOpcode::Value kMulOpcode, IrOpcode::Value kShiftOpcode> |
176 struct AddMatcher : public BinopMatcher { | 234 struct AddMatcher : public BinopMatcher { |
177 static const IrOpcode::Value kOpcode = kAddOpcode; | 235 static const IrOpcode::Value kOpcode = kAddOpcode; |
| 236 typedef ScaleMatcher<BinopMatcher, kMulOpcode, kShiftOpcode> Matcher; |
178 | 237 |
179 explicit AddMatcher(Node* node) : BinopMatcher(node), scale_exponent_(-1) { | 238 explicit AddMatcher(Node* node) |
180 if (this->HasProperty(Operator::kCommutative)) PutScaledInputOnLeft(); | 239 : BinopMatcher(node), scale_(-1), power_of_two_plus_one_(false) { |
181 } | 240 Matcher left_matcher(this->left().node(), true); |
| 241 if (left_matcher.matches()) { |
| 242 scale_ = left_matcher.scale(); |
| 243 power_of_two_plus_one_ = left_matcher.power_of_two_plus_one(); |
| 244 return; |
| 245 } |
182 | 246 |
183 bool HasScaledInput() const { return scale_exponent_ != -1; } | 247 if (!this->HasProperty(Operator::kCommutative)) { |
184 Node* ScaledInput() const { | 248 return; |
185 DCHECK(HasScaledInput()); | 249 } |
186 return this->left().node()->InputAt(0); | |
187 } | |
188 int ScaleExponent() const { | |
189 DCHECK(HasScaledInput()); | |
190 return scale_exponent_; | |
191 } | |
192 | 250 |
193 private: | 251 Matcher right_matcher(this->right().node(), true); |
194 int GetInputScaleExponent(Node* node) const { | 252 if (right_matcher.matches()) { |
195 if (node->opcode() == kShiftOpcode) { | 253 scale_ = right_matcher.scale(); |
196 BinopMatcher m(node); | 254 power_of_two_plus_one_ = right_matcher.power_of_two_plus_one(); |
197 if (m.right().HasValue()) { | 255 this->SwapInputs(); |
198 typename BinopMatcher::RightMatcher::ValueType value = | 256 return; |
199 m.right().Value(); | |
200 if (value >= 0 && value <= 3) { | |
201 return static_cast<int>(value); | |
202 } | |
203 } | |
204 } else if (node->opcode() == kMulOpcode) { | |
205 BinopMatcher m(node); | |
206 if (m.right().HasValue()) { | |
207 typename BinopMatcher::RightMatcher::ValueType value = | |
208 m.right().Value(); | |
209 if (value == 1) { | |
210 return 0; | |
211 } else if (value == 2) { | |
212 return 1; | |
213 } else if (value == 4) { | |
214 return 2; | |
215 } else if (value == 8) { | |
216 return 3; | |
217 } | |
218 } | |
219 } | 257 } |
220 return -1; | |
221 } | |
222 | 258 |
223 void PutScaledInputOnLeft() { | 259 if (this->right().opcode() == kAddOpcode && |
224 scale_exponent_ = GetInputScaleExponent(this->right().node()); | 260 this->left().opcode() != kAddOpcode) { |
225 if (scale_exponent_ >= 0) { | 261 this->SwapInputs(); |
226 int left_scale_exponent = GetInputScaleExponent(this->left().node()); | |
227 if (left_scale_exponent == -1) { | |
228 this->SwapInputs(); | |
229 } else { | |
230 scale_exponent_ = left_scale_exponent; | |
231 } | |
232 } else { | |
233 scale_exponent_ = GetInputScaleExponent(this->left().node()); | |
234 if (scale_exponent_ == -1) { | |
235 if (this->right().opcode() == kAddOpcode && | |
236 this->left().opcode() != kAddOpcode) { | |
237 this->SwapInputs(); | |
238 } | |
239 } | |
240 } | 262 } |
241 } | 263 } |
242 | 264 |
243 int scale_exponent_; | 265 bool HasIndexInput() const { return scale_ != -1; } |
| 266 Node* IndexInput() const { |
| 267 DCHECK(HasIndexInput()); |
| 268 return this->left().node()->InputAt(0); |
| 269 } |
| 270 int scale() const { |
| 271 DCHECK(HasIndexInput()); |
| 272 return scale_; |
| 273 } |
| 274 bool power_of_two_plus_one() const { return power_of_two_plus_one_; } |
| 275 |
| 276 private: |
| 277 int scale_; |
| 278 bool power_of_two_plus_one_; |
244 }; | 279 }; |
245 | 280 |
246 typedef AddMatcher<Int32BinopMatcher, IrOpcode::kInt32Add, IrOpcode::kInt32Mul, | 281 typedef AddMatcher<Int32BinopMatcher, IrOpcode::kInt32Add, IrOpcode::kInt32Mul, |
247 IrOpcode::kWord32Shl> Int32AddMatcher; | 282 IrOpcode::kWord32Shl> Int32AddMatcher; |
248 typedef AddMatcher<Int64BinopMatcher, IrOpcode::kInt64Add, IrOpcode::kInt64Mul, | 283 typedef AddMatcher<Int64BinopMatcher, IrOpcode::kInt64Add, IrOpcode::kInt64Mul, |
249 IrOpcode::kWord64Shl> Int64AddMatcher; | 284 IrOpcode::kWord64Shl> Int64AddMatcher; |
250 | 285 |
| 286 |
251 template <class AddMatcher> | 287 template <class AddMatcher> |
252 struct ScaledWithOffsetMatcher { | 288 struct BaseWithIndexAndDisplacementMatcher { |
253 explicit ScaledWithOffsetMatcher(Node* node) | 289 explicit BaseWithIndexAndDisplacementMatcher(Node* node) |
254 : matches_(false), | 290 : matches_(false), |
255 scaled_(NULL), | 291 index_(NULL), |
256 scale_exponent_(0), | 292 scale_(0), |
257 offset_(NULL), | 293 base_(NULL), |
258 constant_(NULL) { | 294 displacement_(NULL) { |
259 // The ScaledWithOffsetMatcher canonicalizes the order of constants and | 295 // The BaseWithIndexAndDisplacementMatcher canonicalizes the order of |
260 // scale factors that are used as inputs, so instead of enumerating all | 296 // displacements and scale factors that are used as inputs, so instead of |
261 // possible patterns by brute force, checking for node clusters using the | 297 // enumerating all possible patterns by brute force, checking for node |
262 // following templates in the following order suffices to find all of the | 298 // clusters using the following templates in the following order suffices to |
263 // interesting cases (S = scaled input, O = offset input, C = constant | 299 // find all of the interesting cases (S = index * scale, B = base input, D = |
264 // input): | 300 // displacement input): |
265 // (S + (O + C)) | 301 // (S + (B + D)) |
266 // (S + (O + O)) | 302 // (S + (B + B)) |
267 // (S + C) | 303 // (S + D) |
268 // (S + O) | 304 // (S + B) |
269 // ((S + C) + O) | 305 // ((S + D) + B) |
270 // ((S + O) + C) | 306 // ((S + B) + D) |
271 // ((O + C) + O) | 307 // ((B + D) + B) |
272 // ((O + O) + C) | 308 // ((B + B) + D) |
273 // (O + C) | 309 // (B + D) |
274 // (O + O) | 310 // (B + B) |
275 if (node->InputCount() < 2) return; | 311 if (node->InputCount() < 2) return; |
276 AddMatcher base_matcher(node); | 312 AddMatcher m(node); |
277 Node* left = base_matcher.left().node(); | 313 Node* left = m.left().node(); |
278 Node* right = base_matcher.right().node(); | 314 Node* right = m.right().node(); |
279 if (base_matcher.HasScaledInput() && left->OwnedBy(node)) { | 315 Node* displacement = NULL; |
280 scaled_ = base_matcher.ScaledInput(); | 316 Node* base = NULL; |
281 scale_exponent_ = base_matcher.ScaleExponent(); | 317 Node* index = NULL; |
| 318 Node* scale_expression = NULL; |
| 319 bool power_of_two_plus_one = false; |
| 320 int scale = 0; |
| 321 if (m.HasIndexInput() && left->OwnedBy(node)) { |
| 322 index = m.IndexInput(); |
| 323 scale = m.scale(); |
| 324 scale_expression = left; |
| 325 power_of_two_plus_one = m.power_of_two_plus_one(); |
282 if (right->opcode() == AddMatcher::kOpcode && right->OwnedBy(node)) { | 326 if (right->opcode() == AddMatcher::kOpcode && right->OwnedBy(node)) { |
283 AddMatcher right_matcher(right); | 327 AddMatcher right_matcher(right); |
284 if (right_matcher.right().HasValue()) { | 328 if (right_matcher.right().HasValue()) { |
285 // (S + (O + C)) | 329 // (S + (B + D)) |
286 offset_ = right_matcher.left().node(); | 330 base = right_matcher.left().node(); |
287 constant_ = right_matcher.right().node(); | 331 displacement = right_matcher.right().node(); |
288 } else { | 332 } else { |
289 // (S + (O + O)) | 333 // (S + (B + B)) |
290 offset_ = right; | 334 base = right; |
291 } | 335 } |
292 } else if (base_matcher.right().HasValue()) { | 336 } else if (m.right().HasValue()) { |
293 // (S + C) | 337 // (S + D) |
294 constant_ = right; | 338 displacement = right; |
295 } else { | 339 } else { |
296 // (S + O) | 340 // (S + B) |
297 offset_ = right; | 341 base = right; |
298 } | 342 } |
299 } else { | 343 } else { |
300 if (left->opcode() == AddMatcher::kOpcode && left->OwnedBy(node)) { | 344 if (left->opcode() == AddMatcher::kOpcode && left->OwnedBy(node)) { |
301 AddMatcher left_matcher(left); | 345 AddMatcher left_matcher(left); |
302 Node* left_left = left_matcher.left().node(); | 346 Node* left_left = left_matcher.left().node(); |
303 Node* left_right = left_matcher.right().node(); | 347 Node* left_right = left_matcher.right().node(); |
304 if (left_matcher.HasScaledInput() && left_left->OwnedBy(left)) { | 348 if (left_matcher.HasIndexInput() && left_left->OwnedBy(left)) { |
305 if (left_matcher.right().HasValue()) { | 349 if (left_matcher.right().HasValue()) { |
306 // ((S + C) + O) | 350 // ((S + D) + B) |
307 scaled_ = left_matcher.ScaledInput(); | 351 index = left_matcher.IndexInput(); |
308 scale_exponent_ = left_matcher.ScaleExponent(); | 352 scale = left_matcher.scale(); |
309 constant_ = left_right; | 353 scale_expression = left_left; |
310 offset_ = right; | 354 power_of_two_plus_one = left_matcher.power_of_two_plus_one(); |
311 } else if (base_matcher.right().HasValue()) { | 355 displacement = left_right; |
312 // ((S + O) + C) | 356 base = right; |
313 scaled_ = left_matcher.ScaledInput(); | 357 } else if (m.right().HasValue()) { |
314 scale_exponent_ = left_matcher.ScaleExponent(); | 358 // ((S + B) + D) |
315 offset_ = left_right; | 359 index = left_matcher.IndexInput(); |
316 constant_ = right; | 360 scale = left_matcher.scale(); |
| 361 scale_expression = left_left; |
| 362 power_of_two_plus_one = left_matcher.power_of_two_plus_one(); |
| 363 base = left_right; |
| 364 displacement = right; |
317 } else { | 365 } else { |
318 // (O + O) | 366 // (B + B) |
319 scaled_ = left; | 367 index = left; |
320 offset_ = right; | 368 base = right; |
321 } | 369 } |
322 } else { | 370 } else { |
323 if (left_matcher.right().HasValue()) { | 371 if (left_matcher.right().HasValue()) { |
324 // ((O + C) + O) | 372 // ((B + D) + B) |
325 scaled_ = left_left; | 373 index = left_left; |
326 constant_ = left_right; | 374 displacement = left_right; |
327 offset_ = right; | 375 base = right; |
328 } else if (base_matcher.right().HasValue()) { | 376 } else if (m.right().HasValue()) { |
329 // ((O + O) + C) | 377 // ((B + B) + D) |
330 scaled_ = left_left; | 378 index = left_left; |
331 offset_ = left_right; | 379 base = left_right; |
332 constant_ = right; | 380 displacement = right; |
333 } else { | 381 } else { |
334 // (O + O) | 382 // (B + B) |
335 scaled_ = left; | 383 index = left; |
336 offset_ = right; | 384 base = right; |
337 } | 385 } |
338 } | 386 } |
339 } else { | 387 } else { |
340 if (base_matcher.right().HasValue()) { | 388 if (m.right().HasValue()) { |
341 // (O + C) | 389 // (B + D) |
342 offset_ = left; | 390 base = left; |
343 constant_ = right; | 391 displacement = right; |
344 } else { | 392 } else { |
345 // (O + O) | 393 // (B + B) |
346 offset_ = left; | 394 base = left; |
347 scaled_ = right; | 395 index = right; |
348 } | 396 } |
349 } | 397 } |
350 } | 398 } |
351 int64_t value = 0; | 399 int64_t value = 0; |
352 if (constant_ != NULL) { | 400 if (displacement != NULL) { |
353 switch (constant_->opcode()) { | 401 switch (displacement->opcode()) { |
354 case IrOpcode::kInt32Constant: { | 402 case IrOpcode::kInt32Constant: { |
355 value = OpParameter<int32_t>(constant_); | 403 value = OpParameter<int32_t>(displacement); |
356 break; | 404 break; |
357 } | 405 } |
358 case IrOpcode::kInt64Constant: { | 406 case IrOpcode::kInt64Constant: { |
359 value = OpParameter<int64_t>(constant_); | 407 value = OpParameter<int64_t>(displacement); |
360 break; | 408 break; |
361 } | 409 } |
362 default: | 410 default: |
363 UNREACHABLE(); | 411 UNREACHABLE(); |
364 break; | 412 break; |
365 } | 413 } |
366 if (value == 0) { | 414 if (value == 0) { |
367 constant_ = NULL; | 415 displacement = NULL; |
368 } | 416 } |
369 } | 417 } |
| 418 if (power_of_two_plus_one) { |
| 419 if (base != NULL) { |
| 420 // If the scale requires explicitly using the index as the base, but a |
| 421 // base is already part of the match, then the (1 << N + 1) scale factor |
| 422 // can't be folded into the match and the entire index * scale |
| 423 // calculation must be computed separately. |
| 424 index = scale_expression; |
| 425 scale = 0; |
| 426 } else { |
| 427 base = index; |
| 428 } |
| 429 } |
| 430 base_ = base; |
| 431 displacement_ = displacement; |
| 432 index_ = index; |
| 433 scale_ = scale; |
370 matches_ = true; | 434 matches_ = true; |
371 } | 435 } |
372 | 436 |
373 bool matches() const { return matches_; } | 437 bool matches() const { return matches_; } |
374 Node* scaled() const { return scaled_; } | 438 Node* index() const { return index_; } |
375 int scale_exponent() const { return scale_exponent_; } | 439 int scale() const { return scale_; } |
376 Node* offset() const { return offset_; } | 440 Node* base() const { return base_; } |
377 Node* constant() const { return constant_; } | 441 Node* displacement() const { return displacement_; } |
378 | 442 |
379 private: | 443 private: |
380 bool matches_; | 444 bool matches_; |
381 | 445 |
382 protected: | 446 protected: |
383 Node* scaled_; | 447 Node* index_; |
384 int scale_exponent_; | 448 int scale_; |
385 Node* offset_; | 449 Node* base_; |
386 Node* constant_; | 450 Node* displacement_; |
387 }; | 451 }; |
388 | 452 |
389 typedef ScaledWithOffsetMatcher<Int32AddMatcher> ScaledWithOffset32Matcher; | 453 typedef BaseWithIndexAndDisplacementMatcher<Int32AddMatcher> |
390 typedef ScaledWithOffsetMatcher<Int64AddMatcher> ScaledWithOffset64Matcher; | 454 BaseWithIndexAndDisplacement32Matcher; |
| 455 typedef BaseWithIndexAndDisplacementMatcher<Int64AddMatcher> |
| 456 BaseWithIndexAndDisplacement64Matcher; |
391 | 457 |
392 } // namespace compiler | 458 } // namespace compiler |
393 } // namespace internal | 459 } // namespace internal |
394 } // namespace v8 | 460 } // namespace v8 |
395 | 461 |
396 #endif // V8_COMPILER_NODE_MATCHERS_H_ | 462 #endif // V8_COMPILER_NODE_MATCHERS_H_ |
OLD | NEW |