V8 API Reference, 7.2.502.16 (for Deno 0.2.4)
machine-operator-reducer.cc
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
3 // found in the LICENSE file.
4 
5 #include "src/compiler/machine-operator-reducer.h"
6 
7 #include "src/base/bits.h"
8 #include "src/base/division-by-constant.h"
9 #include "src/base/ieee754.h"
10 #include "src/compiler/diamond.h"
11 #include "src/compiler/graph.h"
12 #include "src/compiler/machine-graph.h"
13 #include "src/compiler/node-matchers.h"
14 #include "src/compiler/node-properties.h"
15 #include "src/conversions-inl.h"
16 
17 namespace v8 {
18 namespace internal {
19 namespace compiler {
20 
21 MachineOperatorReducer::MachineOperatorReducer(MachineGraph* mcgraph,
22  bool allow_signalling_nan)
23  : mcgraph_(mcgraph), allow_signalling_nan_(allow_signalling_nan) {}
24 
25 MachineOperatorReducer::~MachineOperatorReducer() = default;
26 
27 
28 Node* MachineOperatorReducer::Float32Constant(volatile float value) {
29  return graph()->NewNode(common()->Float32Constant(value));
30 }
31 
32 
33 Node* MachineOperatorReducer::Float64Constant(volatile double value) {
34  return mcgraph()->Float64Constant(value);
35 }
36 
37 
38 Node* MachineOperatorReducer::Int32Constant(int32_t value) {
39  return mcgraph()->Int32Constant(value);
40 }
41 
42 
43 Node* MachineOperatorReducer::Int64Constant(int64_t value) {
44  return graph()->NewNode(common()->Int64Constant(value));
45 }
46 
47 Node* MachineOperatorReducer::Float64Mul(Node* lhs, Node* rhs) {
48  return graph()->NewNode(machine()->Float64Mul(), lhs, rhs);
49 }
50 
51 Node* MachineOperatorReducer::Float64PowHalf(Node* value) {
52  value =
53  graph()->NewNode(machine()->Float64Add(), Float64Constant(0.0), value);
54  Diamond d(graph(), common(),
55  graph()->NewNode(machine()->Float64LessThanOrEqual(), value,
56  Float64Constant(-V8_INFINITY)),
57  BranchHint::kFalse);
58  return d.Phi(MachineRepresentation::kFloat64, Float64Constant(V8_INFINITY),
59  graph()->NewNode(machine()->Float64Sqrt(), value));
60 }
61 
62 Node* MachineOperatorReducer::Word32And(Node* lhs, Node* rhs) {
63  Node* const node = graph()->NewNode(machine()->Word32And(), lhs, rhs);
64  Reduction const reduction = ReduceWord32And(node);
65  return reduction.Changed() ? reduction.replacement() : node;
66 }
67 
68 
69 Node* MachineOperatorReducer::Word32Sar(Node* lhs, uint32_t rhs) {
70  if (rhs == 0) return lhs;
71  return graph()->NewNode(machine()->Word32Sar(), lhs, Uint32Constant(rhs));
72 }
73 
74 
75 Node* MachineOperatorReducer::Word32Shr(Node* lhs, uint32_t rhs) {
76  if (rhs == 0) return lhs;
77  return graph()->NewNode(machine()->Word32Shr(), lhs, Uint32Constant(rhs));
78 }
79 
80 
81 Node* MachineOperatorReducer::Word32Equal(Node* lhs, Node* rhs) {
82  return graph()->NewNode(machine()->Word32Equal(), lhs, rhs);
83 }
84 
85 
86 Node* MachineOperatorReducer::Int32Add(Node* lhs, Node* rhs) {
87  Node* const node = graph()->NewNode(machine()->Int32Add(), lhs, rhs);
88  Reduction const reduction = ReduceInt32Add(node);
89  return reduction.Changed() ? reduction.replacement() : node;
90 }
91 
92 
93 Node* MachineOperatorReducer::Int32Sub(Node* lhs, Node* rhs) {
94  Node* const node = graph()->NewNode(machine()->Int32Sub(), lhs, rhs);
95  Reduction const reduction = ReduceInt32Sub(node);
96  return reduction.Changed() ? reduction.replacement() : node;
97 }
98 
99 
100 Node* MachineOperatorReducer::Int32Mul(Node* lhs, Node* rhs) {
101  return graph()->NewNode(machine()->Int32Mul(), lhs, rhs);
102 }
103 
104 
105 Node* MachineOperatorReducer::Int32Div(Node* dividend, int32_t divisor) {
106  DCHECK_NE(0, divisor);
107  DCHECK_NE(std::numeric_limits<int32_t>::min(), divisor);
108  base::MagicNumbersForDivision<uint32_t> const mag =
109  base::SignedDivisionByConstant(bit_cast<uint32_t>(divisor));
110  Node* quotient = graph()->NewNode(machine()->Int32MulHigh(), dividend,
111  Uint32Constant(mag.multiplier));
112  if (divisor > 0 && bit_cast<int32_t>(mag.multiplier) < 0) {
113  quotient = Int32Add(quotient, dividend);
114  } else if (divisor < 0 && bit_cast<int32_t>(mag.multiplier) > 0) {
115  quotient = Int32Sub(quotient, dividend);
116  }
117  return Int32Add(Word32Sar(quotient, mag.shift), Word32Shr(dividend, 31));
118 }
119 
120 
121 Node* MachineOperatorReducer::Uint32Div(Node* dividend, uint32_t divisor) {
122  DCHECK_LT(0u, divisor);
123  // If the divisor is even, we can avoid using the expensive fixup by shifting
124  // the dividend upfront.
125  unsigned const shift = base::bits::CountTrailingZeros(divisor);
126  dividend = Word32Shr(dividend, shift);
127  divisor >>= shift;
128  // Compute the magic number for the (shifted) divisor.
129  base::MagicNumbersForDivision<uint32_t> const mag =
130  base::UnsignedDivisionByConstant(divisor, shift);
131  Node* quotient = graph()->NewNode(machine()->Uint32MulHigh(), dividend,
132  Uint32Constant(mag.multiplier));
133  if (mag.add) {
134  DCHECK_LE(1u, mag.shift);
135  quotient = Word32Shr(
136  Int32Add(Word32Shr(Int32Sub(dividend, quotient), 1), quotient),
137  mag.shift - 1);
138  } else {
139  quotient = Word32Shr(quotient, mag.shift);
140  }
141  return quotient;
142 }
143 
144 
145 // Perform constant folding and strength reduction on machine operators.
146 Reduction MachineOperatorReducer::Reduce(Node* node) {
147  switch (node->opcode()) {
148  case IrOpcode::kProjection:
149  return ReduceProjection(ProjectionIndexOf(node->op()), node->InputAt(0));
150  case IrOpcode::kWord32And:
151  return ReduceWord32And(node);
152  case IrOpcode::kWord32Or:
153  return ReduceWord32Or(node);
154  case IrOpcode::kWord32Xor:
155  return ReduceWord32Xor(node);
156  case IrOpcode::kWord32Shl:
157  return ReduceWord32Shl(node);
158  case IrOpcode::kWord64Shl:
159  return ReduceWord64Shl(node);
160  case IrOpcode::kWord32Shr:
161  return ReduceWord32Shr(node);
162  case IrOpcode::kWord64Shr:
163  return ReduceWord64Shr(node);
164  case IrOpcode::kWord32Sar:
165  return ReduceWord32Sar(node);
166  case IrOpcode::kWord64Sar:
167  return ReduceWord64Sar(node);
168  case IrOpcode::kWord32Ror: {
169  Int32BinopMatcher m(node);
170  if (m.right().Is(0)) return Replace(m.left().node()); // x ror 0 => x
171  if (m.IsFoldable()) { // K ror K => K
172  return ReplaceInt32(
173  base::bits::RotateRight32(m.left().Value(), m.right().Value()));
174  }
175  break;
176  }
177  case IrOpcode::kWord32Equal: {
178  Int32BinopMatcher m(node);
179  if (m.IsFoldable()) { // K == K => K
180  return ReplaceBool(m.left().Value() == m.right().Value());
181  }
182  if (m.left().IsInt32Sub() && m.right().Is(0)) { // x - y == 0 => x == y
183  Int32BinopMatcher msub(m.left().node());
184  node->ReplaceInput(0, msub.left().node());
185  node->ReplaceInput(1, msub.right().node());
186  return Changed(node);
187  }
188  // TODO(turbofan): fold HeapConstant, ExternalReference, pointer compares
189  if (m.LeftEqualsRight()) return ReplaceBool(true); // x == x => true
190  break;
191  }
192  case IrOpcode::kWord64Equal: {
193  Int64BinopMatcher m(node);
194  if (m.IsFoldable()) { // K == K => K
195  return ReplaceBool(m.left().Value() == m.right().Value());
196  }
197  if (m.left().IsInt64Sub() && m.right().Is(0)) { // x - y == 0 => x == y
198  Int64BinopMatcher msub(m.left().node());
199  node->ReplaceInput(0, msub.left().node());
200  node->ReplaceInput(1, msub.right().node());
201  return Changed(node);
202  }
203  // TODO(turbofan): fold HeapConstant, ExternalReference, pointer compares
204  if (m.LeftEqualsRight()) return ReplaceBool(true); // x == x => true
205  break;
206  }
207  case IrOpcode::kInt32Add:
208  return ReduceInt32Add(node);
209  case IrOpcode::kInt64Add:
210  return ReduceInt64Add(node);
211  case IrOpcode::kInt32Sub:
212  return ReduceInt32Sub(node);
213  case IrOpcode::kInt64Sub:
214  return ReduceInt64Sub(node);
215  case IrOpcode::kInt32Mul: {
216  Int32BinopMatcher m(node);
217  if (m.right().Is(0)) return Replace(m.right().node()); // x * 0 => 0
218  if (m.right().Is(1)) return Replace(m.left().node()); // x * 1 => x
219  if (m.IsFoldable()) { // K * K => K
220  return ReplaceInt32(m.left().Value() * m.right().Value());
221  }
222  if (m.right().Is(-1)) { // x * -1 => 0 - x
223  node->ReplaceInput(0, Int32Constant(0));
224  node->ReplaceInput(1, m.left().node());
225  NodeProperties::ChangeOp(node, machine()->Int32Sub());
226  return Changed(node);
227  }
228  if (m.right().IsPowerOf2()) { // x * 2^n => x << n
229  node->ReplaceInput(1, Int32Constant(WhichPowerOf2(m.right().Value())));
230  NodeProperties::ChangeOp(node, machine()->Word32Shl());
231  Reduction reduction = ReduceWord32Shl(node);
232  return reduction.Changed() ? reduction : Changed(node);
233  }
234  break;
235  }
236  case IrOpcode::kInt32MulWithOverflow: {
237  Int32BinopMatcher m(node);
238  if (m.right().Is(2)) {
239  node->ReplaceInput(1, m.left().node());
240  NodeProperties::ChangeOp(node, machine()->Int32AddWithOverflow());
241  return Changed(node);
242  }
243  if (m.right().Is(-1)) {
244  node->ReplaceInput(0, Int32Constant(0));
245  node->ReplaceInput(1, m.left().node());
246  NodeProperties::ChangeOp(node, machine()->Int32SubWithOverflow());
247  return Changed(node);
248  }
249  break;
250  }
251  case IrOpcode::kInt32Div:
252  return ReduceInt32Div(node);
253  case IrOpcode::kUint32Div:
254  return ReduceUint32Div(node);
255  case IrOpcode::kInt32Mod:
256  return ReduceInt32Mod(node);
257  case IrOpcode::kUint32Mod:
258  return ReduceUint32Mod(node);
259  case IrOpcode::kInt32LessThan: {
260  Int32BinopMatcher m(node);
261  if (m.IsFoldable()) { // K < K => K
262  return ReplaceBool(m.left().Value() < m.right().Value());
263  }
264  if (m.LeftEqualsRight()) return ReplaceBool(false); // x < x => false
265  if (m.left().IsWord32Or() && m.right().Is(0)) {
266  // (x | K) < 0 => true or (K | x) < 0 => true iff K < 0
267  Int32BinopMatcher mleftmatcher(m.left().node());
268  if (mleftmatcher.left().IsNegative() ||
269  mleftmatcher.right().IsNegative()) {
270  return ReplaceBool(true);
271  }
272  }
273  break;
274  }
275  case IrOpcode::kInt32LessThanOrEqual: {
276  Int32BinopMatcher m(node);
277  if (m.IsFoldable()) { // K <= K => K
278  return ReplaceBool(m.left().Value() <= m.right().Value());
279  }
280  if (m.LeftEqualsRight()) return ReplaceBool(true); // x <= x => true
281  break;
282  }
283  case IrOpcode::kUint32LessThan: {
284  Uint32BinopMatcher m(node);
285  if (m.left().Is(kMaxUInt32)) return ReplaceBool(false); // M < x => false
286  if (m.right().Is(0)) return ReplaceBool(false); // x < 0 => false
287  if (m.IsFoldable()) { // K < K => K
288  return ReplaceBool(m.left().Value() < m.right().Value());
289  }
290  if (m.LeftEqualsRight()) return ReplaceBool(false); // x < x => false
291  if (m.left().IsWord32Sar() && m.right().HasValue()) {
292  Int32BinopMatcher mleft(m.left().node());
293  if (mleft.right().HasValue()) {
294  // (x >> K) < C => x < (C << K)
295  // when C < (M >> K)
296  const uint32_t c = m.right().Value();
297  const uint32_t k = mleft.right().Value() & 0x1F;
298  if (c < static_cast<uint32_t>(kMaxInt >> k)) {
299  node->ReplaceInput(0, mleft.left().node());
300  node->ReplaceInput(1, Uint32Constant(c << k));
301  return Changed(node);
302  }
303  // TODO(turbofan): else the comparison is always true.
304  }
305  }
306  break;
307  }
308  case IrOpcode::kUint32LessThanOrEqual: {
309  Uint32BinopMatcher m(node);
310  if (m.left().Is(0)) return ReplaceBool(true); // 0 <= x => true
311  if (m.right().Is(kMaxUInt32)) return ReplaceBool(true); // x <= M => true
312  if (m.IsFoldable()) { // K <= K => K
313  return ReplaceBool(m.left().Value() <= m.right().Value());
314  }
315  if (m.LeftEqualsRight()) return ReplaceBool(true); // x <= x => true
316  break;
317  }
318  case IrOpcode::kFloat32Sub: {
319  Float32BinopMatcher m(node);
320  if (allow_signalling_nan_ && m.right().Is(0) &&
321  (copysign(1.0, m.right().Value()) > 0)) {
322  return Replace(m.left().node()); // x - 0 => x
323  }
324  if (m.right().IsNaN()) { // x - NaN => NaN
325  // Do some calculation to make a signalling NaN quiet.
326  return ReplaceFloat32(m.right().Value() - m.right().Value());
327  }
328  if (m.left().IsNaN()) { // NaN - x => NaN
329  // Do some calculation to make a signalling NaN quiet.
330  return ReplaceFloat32(m.left().Value() - m.left().Value());
331  }
332  if (m.IsFoldable()) { // L - R => (L - R)
333  return ReplaceFloat32(m.left().Value() - m.right().Value());
334  }
335  if (allow_signalling_nan_ && m.left().IsMinusZero()) {
336  // -0.0 - round_down(-0.0 - R) => round_up(R)
337  if (machine()->Float32RoundUp().IsSupported() &&
338  m.right().IsFloat32RoundDown()) {
339  if (m.right().InputAt(0)->opcode() == IrOpcode::kFloat32Sub) {
340  Float32BinopMatcher mright0(m.right().InputAt(0));
341  if (mright0.left().IsMinusZero()) {
342  return Replace(graph()->NewNode(machine()->Float32RoundUp().op(),
343  mright0.right().node()));
344  }
345  }
346  }
347  // -0.0 - R => -R
348  node->RemoveInput(0);
349  NodeProperties::ChangeOp(node, machine()->Float32Neg());
350  return Changed(node);
351  }
352  break;
353  }
354  case IrOpcode::kFloat64Add: {
355  Float64BinopMatcher m(node);
356  if (m.IsFoldable()) { // K + K => K
357  return ReplaceFloat64(m.left().Value() + m.right().Value());
358  }
359  break;
360  }
361  case IrOpcode::kFloat64Sub: {
362  Float64BinopMatcher m(node);
363  if (allow_signalling_nan_ && m.right().Is(0) &&
364  (Double(m.right().Value()).Sign() > 0)) {
365  return Replace(m.left().node()); // x - 0 => x
366  }
367  if (m.right().IsNaN()) { // x - NaN => NaN
368  // Do some calculation to make a signalling NaN quiet.
369  return ReplaceFloat64(m.right().Value() - m.right().Value());
370  }
371  if (m.left().IsNaN()) { // NaN - x => NaN
372  // Do some calculation to make a signalling NaN quiet.
373  return ReplaceFloat64(m.left().Value() - m.left().Value());
374  }
375  if (m.IsFoldable()) { // L - R => (L - R)
376  return ReplaceFloat64(m.left().Value() - m.right().Value());
377  }
378  if (allow_signalling_nan_ && m.left().IsMinusZero()) {
379  // -0.0 - round_down(-0.0 - R) => round_up(R)
380  if (machine()->Float64RoundUp().IsSupported() &&
381  m.right().IsFloat64RoundDown()) {
382  if (m.right().InputAt(0)->opcode() == IrOpcode::kFloat64Sub) {
383  Float64BinopMatcher mright0(m.right().InputAt(0));
384  if (mright0.left().IsMinusZero()) {
385  return Replace(graph()->NewNode(machine()->Float64RoundUp().op(),
386  mright0.right().node()));
387  }
388  }
389  }
390  // -0.0 - R => -R
391  node->RemoveInput(0);
392  NodeProperties::ChangeOp(node, machine()->Float64Neg());
393  return Changed(node);
394  }
395  break;
396  }
397  case IrOpcode::kFloat64Mul: {
398  Float64BinopMatcher m(node);
399  if (allow_signalling_nan_ && m.right().Is(1))
400  return Replace(m.left().node()); // x * 1.0 => x
401  if (m.right().Is(-1)) { // x * -1.0 => -0.0 - x
402  node->ReplaceInput(0, Float64Constant(-0.0));
403  node->ReplaceInput(1, m.left().node());
404  NodeProperties::ChangeOp(node, machine()->Float64Sub());
405  return Changed(node);
406  }
407  if (m.right().IsNaN()) { // x * NaN => NaN
408  // Do some calculation to make a signalling NaN quiet.
409  return ReplaceFloat64(m.right().Value() - m.right().Value());
410  }
411  if (m.IsFoldable()) { // K * K => K
412  return ReplaceFloat64(m.left().Value() * m.right().Value());
413  }
414  if (m.right().Is(2)) { // x * 2.0 => x + x
415  node->ReplaceInput(1, m.left().node());
416  NodeProperties::ChangeOp(node, machine()->Float64Add());
417  return Changed(node);
418  }
419  break;
420  }
421  case IrOpcode::kFloat64Div: {
422  Float64BinopMatcher m(node);
423  if (allow_signalling_nan_ && m.right().Is(1))
424  return Replace(m.left().node()); // x / 1.0 => x
425  // TODO(ahaas): We could do x / 1.0 = x if we knew that x is not an sNaN.
426  if (m.right().IsNaN()) { // x / NaN => NaN
427  // Do some calculation to make a signalling NaN quiet.
428  return ReplaceFloat64(m.right().Value() - m.right().Value());
429  }
430  if (m.left().IsNaN()) { // NaN / x => NaN
431  // Do some calculation to make a signalling NaN quiet.
432  return ReplaceFloat64(m.left().Value() - m.left().Value());
433  }
434  if (m.IsFoldable()) { // K / K => K
435  return ReplaceFloat64(m.left().Value() / m.right().Value());
436  }
437  if (allow_signalling_nan_ && m.right().Is(-1)) { // x / -1.0 => -x
438  node->RemoveInput(1);
439  NodeProperties::ChangeOp(node, machine()->Float64Neg());
440  return Changed(node);
441  }
442  if (m.right().IsNormal() && m.right().IsPositiveOrNegativePowerOf2()) {
443  // All reciprocals of non-denormal powers of two can be represented
444  // exactly, so division by power of two can be reduced to
445  // multiplication by reciprocal, with the same result.
446  node->ReplaceInput(1, Float64Constant(1.0 / m.right().Value()));
447  NodeProperties::ChangeOp(node, machine()->Float64Mul());
448  return Changed(node);
449  }
450  break;
451  }
452  case IrOpcode::kFloat64Mod: {
453  Float64BinopMatcher m(node);
454  if (m.right().Is(0)) { // x % 0 => NaN
455  return ReplaceFloat64(std::numeric_limits<double>::quiet_NaN());
456  }
457  if (m.right().IsNaN()) { // x % NaN => NaN
458  return Replace(m.right().node());
459  }
460  if (m.left().IsNaN()) { // NaN % x => NaN
461  return Replace(m.left().node());
462  }
463  if (m.IsFoldable()) { // K % K => K
464  return ReplaceFloat64(Modulo(m.left().Value(), m.right().Value()));
465  }
466  break;
467  }
468  case IrOpcode::kFloat64Acos: {
469  Float64Matcher m(node->InputAt(0));
470  if (m.HasValue()) return ReplaceFloat64(base::ieee754::acos(m.Value()));
471  break;
472  }
473  case IrOpcode::kFloat64Acosh: {
474  Float64Matcher m(node->InputAt(0));
475  if (m.HasValue()) return ReplaceFloat64(base::ieee754::acosh(m.Value()));
476  break;
477  }
478  case IrOpcode::kFloat64Asin: {
479  Float64Matcher m(node->InputAt(0));
480  if (m.HasValue()) return ReplaceFloat64(base::ieee754::asin(m.Value()));
481  break;
482  }
483  case IrOpcode::kFloat64Asinh: {
484  Float64Matcher m(node->InputAt(0));
485  if (m.HasValue()) return ReplaceFloat64(base::ieee754::asinh(m.Value()));
486  break;
487  }
488  case IrOpcode::kFloat64Atan: {
489  Float64Matcher m(node->InputAt(0));
490  if (m.HasValue()) return ReplaceFloat64(base::ieee754::atan(m.Value()));
491  break;
492  }
493  case IrOpcode::kFloat64Atanh: {
494  Float64Matcher m(node->InputAt(0));
495  if (m.HasValue()) return ReplaceFloat64(base::ieee754::atanh(m.Value()));
496  break;
497  }
498  case IrOpcode::kFloat64Atan2: {
499  Float64BinopMatcher m(node);
500  if (m.right().IsNaN()) {
501  return Replace(m.right().node());
502  }
503  if (m.left().IsNaN()) {
504  return Replace(m.left().node());
505  }
506  if (m.IsFoldable()) {
507  return ReplaceFloat64(
508  base::ieee754::atan2(m.left().Value(), m.right().Value()));
509  }
510  break;
511  }
512  case IrOpcode::kFloat64Cbrt: {
513  Float64Matcher m(node->InputAt(0));
514  if (m.HasValue()) return ReplaceFloat64(base::ieee754::cbrt(m.Value()));
515  break;
516  }
517  case IrOpcode::kFloat64Cos: {
518  Float64Matcher m(node->InputAt(0));
519  if (m.HasValue()) return ReplaceFloat64(base::ieee754::cos(m.Value()));
520  break;
521  }
522  case IrOpcode::kFloat64Cosh: {
523  Float64Matcher m(node->InputAt(0));
524  if (m.HasValue()) return ReplaceFloat64(base::ieee754::cosh(m.Value()));
525  break;
526  }
527  case IrOpcode::kFloat64Exp: {
528  Float64Matcher m(node->InputAt(0));
529  if (m.HasValue()) return ReplaceFloat64(base::ieee754::exp(m.Value()));
530  break;
531  }
532  case IrOpcode::kFloat64Expm1: {
533  Float64Matcher m(node->InputAt(0));
534  if (m.HasValue()) return ReplaceFloat64(base::ieee754::expm1(m.Value()));
535  break;
536  }
537  case IrOpcode::kFloat64Log: {
538  Float64Matcher m(node->InputAt(0));
539  if (m.HasValue()) return ReplaceFloat64(base::ieee754::log(m.Value()));
540  break;
541  }
542  case IrOpcode::kFloat64Log1p: {
543  Float64Matcher m(node->InputAt(0));
544  if (m.HasValue()) return ReplaceFloat64(base::ieee754::log1p(m.Value()));
545  break;
546  }
547  case IrOpcode::kFloat64Log10: {
548  Float64Matcher m(node->InputAt(0));
549  if (m.HasValue()) return ReplaceFloat64(base::ieee754::log10(m.Value()));
550  break;
551  }
552  case IrOpcode::kFloat64Log2: {
553  Float64Matcher m(node->InputAt(0));
554  if (m.HasValue()) return ReplaceFloat64(base::ieee754::log2(m.Value()));
555  break;
556  }
557  case IrOpcode::kFloat64Pow: {
558  Float64BinopMatcher m(node);
559  if (m.IsFoldable()) {
560  return ReplaceFloat64(Pow(m.left().Value(), m.right().Value()));
561  } else if (m.right().Is(0.0)) { // x ** +-0.0 => 1.0
562  return ReplaceFloat64(1.0);
563  } else if (m.right().Is(-2.0)) { // x ** -2.0 => 1 / (x * x)
564  node->ReplaceInput(0, Float64Constant(1.0));
565  node->ReplaceInput(1, Float64Mul(m.left().node(), m.left().node()));
566  NodeProperties::ChangeOp(node, machine()->Float64Div());
567  return Changed(node);
568  } else if (m.right().Is(2.0)) { // x ** 2.0 => x * x
569  node->ReplaceInput(1, m.left().node());
570  NodeProperties::ChangeOp(node, machine()->Float64Mul());
571  return Changed(node);
572  } else if (m.right().Is(-0.5)) {
573  // x ** 0.5 => 1 / (if x <= -Infinity then Infinity else sqrt(0.0 + x))
574  node->ReplaceInput(0, Float64Constant(1.0));
575  node->ReplaceInput(1, Float64PowHalf(m.left().node()));
576  NodeProperties::ChangeOp(node, machine()->Float64Div());
577  return Changed(node);
578  } else if (m.right().Is(0.5)) {
579  // x ** 0.5 => if x <= -Infinity then Infinity else sqrt(0.0 + x)
580  return Replace(Float64PowHalf(m.left().node()));
581  }
582  break;
583  }
584  case IrOpcode::kFloat64Sin: {
585  Float64Matcher m(node->InputAt(0));
586  if (m.HasValue()) return ReplaceFloat64(base::ieee754::sin(m.Value()));
587  break;
588  }
589  case IrOpcode::kFloat64Sinh: {
590  Float64Matcher m(node->InputAt(0));
591  if (m.HasValue()) return ReplaceFloat64(base::ieee754::sinh(m.Value()));
592  break;
593  }
594  case IrOpcode::kFloat64Tan: {
595  Float64Matcher m(node->InputAt(0));
596  if (m.HasValue()) return ReplaceFloat64(base::ieee754::tan(m.Value()));
597  break;
598  }
599  case IrOpcode::kFloat64Tanh: {
600  Float64Matcher m(node->InputAt(0));
601  if (m.HasValue()) return ReplaceFloat64(base::ieee754::tanh(m.Value()));
602  break;
603  }
604  case IrOpcode::kChangeFloat32ToFloat64: {
605  Float32Matcher m(node->InputAt(0));
606  if (m.HasValue()) {
607  if (!allow_signalling_nan_ && std::isnan(m.Value())) {
608  // Do some calculation to make guarantee the value is a quiet NaN.
609  return ReplaceFloat64(m.Value() + m.Value());
610  }
611  return ReplaceFloat64(m.Value());
612  }
613  break;
614  }
615  case IrOpcode::kChangeFloat64ToInt32: {
616  Float64Matcher m(node->InputAt(0));
617  if (m.HasValue()) return ReplaceInt32(FastD2IChecked(m.Value()));
618  if (m.IsChangeInt32ToFloat64()) return Replace(m.node()->InputAt(0));
619  break;
620  }
621  case IrOpcode::kChangeFloat64ToInt64: {
622  Float64Matcher m(node->InputAt(0));
623  if (m.HasValue()) return ReplaceInt64(static_cast<int64_t>(m.Value()));
624  if (m.IsChangeInt64ToFloat64()) return Replace(m.node()->InputAt(0));
625  break;
626  }
627  case IrOpcode::kChangeFloat64ToUint32: {
628  Float64Matcher m(node->InputAt(0));
629  if (m.HasValue()) return ReplaceInt32(FastD2UI(m.Value()));
630  if (m.IsChangeUint32ToFloat64()) return Replace(m.node()->InputAt(0));
631  break;
632  }
633  case IrOpcode::kChangeInt32ToFloat64: {
634  Int32Matcher m(node->InputAt(0));
635  if (m.HasValue()) return ReplaceFloat64(FastI2D(m.Value()));
636  break;
637  }
638  case IrOpcode::kChangeInt32ToInt64: {
639  Int32Matcher m(node->InputAt(0));
640  if (m.HasValue()) return ReplaceInt64(m.Value());
641  break;
642  }
643  case IrOpcode::kChangeInt64ToFloat64: {
644  Int64Matcher m(node->InputAt(0));
645  if (m.HasValue()) return ReplaceFloat64(static_cast<double>(m.Value()));
646  if (m.IsChangeFloat64ToInt64()) return Replace(m.node()->InputAt(0));
647  break;
648  }
649  case IrOpcode::kChangeUint32ToFloat64: {
650  Uint32Matcher m(node->InputAt(0));
651  if (m.HasValue()) return ReplaceFloat64(FastUI2D(m.Value()));
652  break;
653  }
654  case IrOpcode::kChangeUint32ToUint64: {
655  Uint32Matcher m(node->InputAt(0));
656  if (m.HasValue()) return ReplaceInt64(static_cast<uint64_t>(m.Value()));
657  break;
658  }
659  case IrOpcode::kTruncateFloat64ToWord32: {
660  Float64Matcher m(node->InputAt(0));
661  if (m.HasValue()) return ReplaceInt32(DoubleToInt32(m.Value()));
662  if (m.IsChangeInt32ToFloat64()) return Replace(m.node()->InputAt(0));
663  return NoChange();
664  }
665  case IrOpcode::kTruncateInt64ToInt32: {
666  Int64Matcher m(node->InputAt(0));
667  if (m.HasValue()) return ReplaceInt32(static_cast<int32_t>(m.Value()));
668  if (m.IsChangeInt32ToInt64()) return Replace(m.node()->InputAt(0));
669  break;
670  }
671  case IrOpcode::kTruncateFloat64ToFloat32: {
672  Float64Matcher m(node->InputAt(0));
673  if (m.HasValue()) {
674  if (!allow_signalling_nan_ && std::isnan(m.Value())) {
675  // Do some calculation to make guarantee the value is a quiet NaN.
676  return ReplaceFloat32(DoubleToFloat32(m.Value() + m.Value()));
677  }
678  return ReplaceFloat32(DoubleToFloat32(m.Value()));
679  }
680  if (allow_signalling_nan_ && m.IsChangeFloat32ToFloat64())
681  return Replace(m.node()->InputAt(0));
682  break;
683  }
684  case IrOpcode::kRoundFloat64ToInt32: {
685  Float64Matcher m(node->InputAt(0));
686  if (m.HasValue()) {
687  return ReplaceInt32(DoubleToInt32(m.Value()));
688  }
689  if (m.IsChangeInt32ToFloat64()) return Replace(m.node()->InputAt(0));
690  break;
691  }
692  case IrOpcode::kFloat64InsertLowWord32:
693  return ReduceFloat64InsertLowWord32(node);
694  case IrOpcode::kFloat64InsertHighWord32:
695  return ReduceFloat64InsertHighWord32(node);
696  case IrOpcode::kStore:
697  case IrOpcode::kUnalignedStore:
698  return ReduceStore(node);
699  case IrOpcode::kFloat64Equal:
700  case IrOpcode::kFloat64LessThan:
701  case IrOpcode::kFloat64LessThanOrEqual:
702  return ReduceFloat64Compare(node);
703  case IrOpcode::kFloat64RoundDown:
704  return ReduceFloat64RoundDown(node);
705  default:
706  break;
707  }
708  return NoChange();
709 }
710 
711 Reduction MachineOperatorReducer::ReduceInt32Add(Node* node) {
712  DCHECK_EQ(IrOpcode::kInt32Add, node->opcode());
713  Int32BinopMatcher m(node);
714  if (m.right().Is(0)) return Replace(m.left().node()); // x + 0 => x
715  if (m.IsFoldable()) { // K + K => K
716  return ReplaceUint32(bit_cast<uint32_t>(m.left().Value()) +
717  bit_cast<uint32_t>(m.right().Value()));
718  }
719  if (m.left().IsInt32Sub()) {
720  Int32BinopMatcher mleft(m.left().node());
721  if (mleft.left().Is(0)) { // (0 - x) + y => y - x
722  node->ReplaceInput(0, m.right().node());
723  node->ReplaceInput(1, mleft.right().node());
724  NodeProperties::ChangeOp(node, machine()->Int32Sub());
725  Reduction const reduction = ReduceInt32Sub(node);
726  return reduction.Changed() ? reduction : Changed(node);
727  }
728  }
729  if (m.right().IsInt32Sub()) {
730  Int32BinopMatcher mright(m.right().node());
731  if (mright.left().Is(0)) { // y + (0 - x) => y - x
732  node->ReplaceInput(1, mright.right().node());
733  NodeProperties::ChangeOp(node, machine()->Int32Sub());
734  Reduction const reduction = ReduceInt32Sub(node);
735  return reduction.Changed() ? reduction : Changed(node);
736  }
737  }
738  return NoChange();
739 }
740 
741 Reduction MachineOperatorReducer::ReduceInt64Add(Node* node) {
742  DCHECK_EQ(IrOpcode::kInt64Add, node->opcode());
743  Int64BinopMatcher m(node);
744  if (m.right().Is(0)) return Replace(m.left().node()); // x + 0 => 0
745  if (m.IsFoldable()) {
746  return Replace(Uint64Constant(bit_cast<uint64_t>(m.left().Value()) +
747  bit_cast<uint64_t>(m.right().Value())));
748  }
749  return NoChange();
750 }
751 
752 Reduction MachineOperatorReducer::ReduceInt32Sub(Node* node) {
753  DCHECK_EQ(IrOpcode::kInt32Sub, node->opcode());
754  Int32BinopMatcher m(node);
755  if (m.right().Is(0)) return Replace(m.left().node()); // x - 0 => x
756  if (m.IsFoldable()) { // K - K => K
757  return ReplaceInt32(static_cast<uint32_t>(m.left().Value()) -
758  static_cast<uint32_t>(m.right().Value()));
759  }
760  if (m.LeftEqualsRight()) return ReplaceInt32(0); // x - x => 0
761  if (m.right().HasValue()) { // x - K => x + -K
762  node->ReplaceInput(1, Int32Constant(-m.right().Value()));
763  NodeProperties::ChangeOp(node, machine()->Int32Add());
764  Reduction const reduction = ReduceInt32Add(node);
765  return reduction.Changed() ? reduction : Changed(node);
766  }
767  return NoChange();
768 }
769 
770 Reduction MachineOperatorReducer::ReduceInt64Sub(Node* node) {
771  DCHECK_EQ(IrOpcode::kInt64Sub, node->opcode());
772  Int64BinopMatcher m(node);
773  if (m.right().Is(0)) return Replace(m.left().node()); // x - 0 => x
774  if (m.IsFoldable()) { // K - K => K
775  return Replace(Uint64Constant(bit_cast<uint64_t>(m.left().Value()) -
776  bit_cast<uint64_t>(m.right().Value())));
777  }
778  if (m.LeftEqualsRight()) return Replace(Int64Constant(0)); // x - x => 0
779  if (m.right().HasValue()) { // x - K => x + -K
780  node->ReplaceInput(1, Int64Constant(-m.right().Value()));
781  NodeProperties::ChangeOp(node, machine()->Int64Add());
782  Reduction const reduction = ReduceInt64Add(node);
783  return reduction.Changed() ? reduction : Changed(node);
784  }
785  return NoChange();
786 }
787 
788 Reduction MachineOperatorReducer::ReduceInt32Div(Node* node) {
789  Int32BinopMatcher m(node);
790  if (m.left().Is(0)) return Replace(m.left().node()); // 0 / x => 0
791  if (m.right().Is(0)) return Replace(m.right().node()); // x / 0 => 0
792  if (m.right().Is(1)) return Replace(m.left().node()); // x / 1 => x
793  if (m.IsFoldable()) { // K / K => K
794  return ReplaceInt32(
795  base::bits::SignedDiv32(m.left().Value(), m.right().Value()));
796  }
797  if (m.LeftEqualsRight()) { // x / x => x != 0
798  Node* const zero = Int32Constant(0);
799  return Replace(Word32Equal(Word32Equal(m.left().node(), zero), zero));
800  }
801  if (m.right().Is(-1)) { // x / -1 => 0 - x
802  node->ReplaceInput(0, Int32Constant(0));
803  node->ReplaceInput(1, m.left().node());
804  node->TrimInputCount(2);
805  NodeProperties::ChangeOp(node, machine()->Int32Sub());
806  return Changed(node);
807  }
808  if (m.right().HasValue()) {
809  int32_t const divisor = m.right().Value();
810  Node* const dividend = m.left().node();
811  Node* quotient = dividend;
812  if (base::bits::IsPowerOfTwo(Abs(divisor))) {
813  uint32_t const shift = WhichPowerOf2(Abs(divisor));
814  DCHECK_NE(0u, shift);
815  if (shift > 1) {
816  quotient = Word32Sar(quotient, 31);
817  }
818  quotient = Int32Add(Word32Shr(quotient, 32u - shift), dividend);
819  quotient = Word32Sar(quotient, shift);
820  } else {
821  quotient = Int32Div(quotient, Abs(divisor));
822  }
823  if (divisor < 0) {
824  node->ReplaceInput(0, Int32Constant(0));
825  node->ReplaceInput(1, quotient);
826  node->TrimInputCount(2);
827  NodeProperties::ChangeOp(node, machine()->Int32Sub());
828  return Changed(node);
829  }
830  return Replace(quotient);
831  }
832  return NoChange();
833 }
834 
835 
836 Reduction MachineOperatorReducer::ReduceUint32Div(Node* node) {
837  Uint32BinopMatcher m(node);
838  if (m.left().Is(0)) return Replace(m.left().node()); // 0 / x => 0
839  if (m.right().Is(0)) return Replace(m.right().node()); // x / 0 => 0
840  if (m.right().Is(1)) return Replace(m.left().node()); // x / 1 => x
841  if (m.IsFoldable()) { // K / K => K
842  return ReplaceUint32(
843  base::bits::UnsignedDiv32(m.left().Value(), m.right().Value()));
844  }
845  if (m.LeftEqualsRight()) { // x / x => x != 0
846  Node* const zero = Int32Constant(0);
847  return Replace(Word32Equal(Word32Equal(m.left().node(), zero), zero));
848  }
849  if (m.right().HasValue()) {
850  Node* const dividend = m.left().node();
851  uint32_t const divisor = m.right().Value();
852  if (base::bits::IsPowerOfTwo(divisor)) { // x / 2^n => x >> n
853  node->ReplaceInput(1, Uint32Constant(WhichPowerOf2(m.right().Value())));
854  node->TrimInputCount(2);
855  NodeProperties::ChangeOp(node, machine()->Word32Shr());
856  return Changed(node);
857  } else {
858  return Replace(Uint32Div(dividend, divisor));
859  }
860  }
861  return NoChange();
862 }
863 
864 
865 Reduction MachineOperatorReducer::ReduceInt32Mod(Node* node) {
866  Int32BinopMatcher m(node);
867  if (m.left().Is(0)) return Replace(m.left().node()); // 0 % x => 0
868  if (m.right().Is(0)) return Replace(m.right().node()); // x % 0 => 0
869  if (m.right().Is(1)) return ReplaceInt32(0); // x % 1 => 0
870  if (m.right().Is(-1)) return ReplaceInt32(0); // x % -1 => 0
871  if (m.LeftEqualsRight()) return ReplaceInt32(0); // x % x => 0
872  if (m.IsFoldable()) { // K % K => K
873  return ReplaceInt32(
874  base::bits::SignedMod32(m.left().Value(), m.right().Value()));
875  }
876  if (m.right().HasValue()) {
877  Node* const dividend = m.left().node();
878  uint32_t const divisor = Abs(m.right().Value());
879  if (base::bits::IsPowerOfTwo(divisor)) {
880  uint32_t const mask = divisor - 1;
881  Node* const zero = Int32Constant(0);
882  Diamond d(graph(), common(),
883  graph()->NewNode(machine()->Int32LessThan(), dividend, zero),
884  BranchHint::kFalse);
885  return Replace(
886  d.Phi(MachineRepresentation::kWord32,
887  Int32Sub(zero, Word32And(Int32Sub(zero, dividend), mask)),
888  Word32And(dividend, mask)));
889  } else {
890  Node* quotient = Int32Div(dividend, divisor);
891  DCHECK_EQ(dividend, node->InputAt(0));
892  node->ReplaceInput(1, Int32Mul(quotient, Int32Constant(divisor)));
893  node->TrimInputCount(2);
894  NodeProperties::ChangeOp(node, machine()->Int32Sub());
895  }
896  return Changed(node);
897  }
898  return NoChange();
899 }
900 
901 
902 Reduction MachineOperatorReducer::ReduceUint32Mod(Node* node) {
903  Uint32BinopMatcher m(node);
904  if (m.left().Is(0)) return Replace(m.left().node()); // 0 % x => 0
905  if (m.right().Is(0)) return Replace(m.right().node()); // x % 0 => 0
906  if (m.right().Is(1)) return ReplaceUint32(0); // x % 1 => 0
907  if (m.LeftEqualsRight()) return ReplaceInt32(0); // x % x => 0
908  if (m.IsFoldable()) { // K % K => K
909  return ReplaceUint32(
910  base::bits::UnsignedMod32(m.left().Value(), m.right().Value()));
911  }
912  if (m.right().HasValue()) {
913  Node* const dividend = m.left().node();
914  uint32_t const divisor = m.right().Value();
915  if (base::bits::IsPowerOfTwo(divisor)) { // x % 2^n => x & 2^n-1
916  node->ReplaceInput(1, Uint32Constant(m.right().Value() - 1));
917  node->TrimInputCount(2);
918  NodeProperties::ChangeOp(node, machine()->Word32And());
919  } else {
920  Node* quotient = Uint32Div(dividend, divisor);
921  DCHECK_EQ(dividend, node->InputAt(0));
922  node->ReplaceInput(1, Int32Mul(quotient, Uint32Constant(divisor)));
923  node->TrimInputCount(2);
924  NodeProperties::ChangeOp(node, machine()->Int32Sub());
925  }
926  return Changed(node);
927  }
928  return NoChange();
929 }
930 
931 
932 Reduction MachineOperatorReducer::ReduceStore(Node* node) {
933  NodeMatcher nm(node);
934  MachineRepresentation rep;
935  int value_input;
936  if (nm.IsStore()) {
937  rep = StoreRepresentationOf(node->op()).representation();
938  value_input = 2;
939  } else {
940  DCHECK(nm.IsUnalignedStore());
941  rep = UnalignedStoreRepresentationOf(node->op());
942  value_input = 2;
943  }
944 
945  Node* const value = node->InputAt(value_input);
946 
947  switch (value->opcode()) {
948  case IrOpcode::kWord32And: {
949  Uint32BinopMatcher m(value);
950  if (m.right().HasValue() && ((rep == MachineRepresentation::kWord8 &&
951  (m.right().Value() & 0xFF) == 0xFF) ||
952  (rep == MachineRepresentation::kWord16 &&
953  (m.right().Value() & 0xFFFF) == 0xFFFF))) {
954  node->ReplaceInput(value_input, m.left().node());
955  return Changed(node);
956  }
957  break;
958  }
959  case IrOpcode::kWord32Sar: {
960  Int32BinopMatcher m(value);
961  if (m.left().IsWord32Shl() && ((rep == MachineRepresentation::kWord8 &&
962  m.right().IsInRange(1, 24)) ||
963  (rep == MachineRepresentation::kWord16 &&
964  m.right().IsInRange(1, 16)))) {
965  Int32BinopMatcher mleft(m.left().node());
966  if (mleft.right().Is(m.right().Value())) {
967  node->ReplaceInput(value_input, mleft.left().node());
968  return Changed(node);
969  }
970  }
971  break;
972  }
973  default:
974  break;
975  }
976  return NoChange();
977 }
978 
979 
980 Reduction MachineOperatorReducer::ReduceProjection(size_t index, Node* node) {
981  switch (node->opcode()) {
982  case IrOpcode::kInt32AddWithOverflow: {
983  DCHECK(index == 0 || index == 1);
984  Int32BinopMatcher m(node);
985  if (m.IsFoldable()) {
986  int32_t val;
987  bool ovf = base::bits::SignedAddOverflow32(m.left().Value(),
988  m.right().Value(), &val);
989  return ReplaceInt32(index == 0 ? val : ovf);
990  }
991  if (m.right().Is(0)) {
992  return Replace(index == 0 ? m.left().node() : m.right().node());
993  }
994  break;
995  }
996  case IrOpcode::kInt32SubWithOverflow: {
997  DCHECK(index == 0 || index == 1);
998  Int32BinopMatcher m(node);
999  if (m.IsFoldable()) {
1000  int32_t val;
1001  bool ovf = base::bits::SignedSubOverflow32(m.left().Value(),
1002  m.right().Value(), &val);
1003  return ReplaceInt32(index == 0 ? val : ovf);
1004  }
1005  if (m.right().Is(0)) {
1006  return Replace(index == 0 ? m.left().node() : m.right().node());
1007  }
1008  break;
1009  }
1010  case IrOpcode::kInt32MulWithOverflow: {
1011  DCHECK(index == 0 || index == 1);
1012  Int32BinopMatcher m(node);
1013  if (m.IsFoldable()) {
1014  int32_t val;
1015  bool ovf = base::bits::SignedMulOverflow32(m.left().Value(),
1016  m.right().Value(), &val);
1017  return ReplaceInt32(index == 0 ? val : ovf);
1018  }
1019  if (m.right().Is(0)) {
1020  return Replace(m.right().node());
1021  }
1022  if (m.right().Is(1)) {
1023  return index == 0 ? Replace(m.left().node()) : ReplaceInt32(0);
1024  }
1025  break;
1026  }
1027  default:
1028  break;
1029  }
1030  return NoChange();
1031 }
1032 
1033 
1034 Reduction MachineOperatorReducer::ReduceWord32Shifts(Node* node) {
1035  DCHECK((node->opcode() == IrOpcode::kWord32Shl) ||
1036  (node->opcode() == IrOpcode::kWord32Shr) ||
1037  (node->opcode() == IrOpcode::kWord32Sar));
1038  if (machine()->Word32ShiftIsSafe()) {
1039  // Remove the explicit 'and' with 0x1F if the shift provided by the machine
1040  // instruction matches that required by JavaScript.
1041  Int32BinopMatcher m(node);
1042  if (m.right().IsWord32And()) {
1043  Int32BinopMatcher mright(m.right().node());
1044  if (mright.right().Is(0x1F)) {
1045  node->ReplaceInput(1, mright.left().node());
1046  return Changed(node);
1047  }
1048  }
1049  }
1050  return NoChange();
1051 }
1052 
1053 
1054 Reduction MachineOperatorReducer::ReduceWord32Shl(Node* node) {
1055  DCHECK_EQ(IrOpcode::kWord32Shl, node->opcode());
1056  Int32BinopMatcher m(node);
1057  if (m.right().Is(0)) return Replace(m.left().node()); // x << 0 => x
1058  if (m.IsFoldable()) { // K << K => K
1059  return ReplaceInt32(m.left().Value() << m.right().Value());
1060  }
1061  if (m.right().IsInRange(1, 31)) {
1062  // (x >>> K) << K => x & ~(2^K - 1)
1063  // (x >> K) << K => x & ~(2^K - 1)
1064  if (m.left().IsWord32Sar() || m.left().IsWord32Shr()) {
1065  Int32BinopMatcher mleft(m.left().node());
1066  if (mleft.right().Is(m.right().Value())) {
1067  node->ReplaceInput(0, mleft.left().node());
1068  node->ReplaceInput(1,
1069  Uint32Constant(~((1U << m.right().Value()) - 1U)));
1070  NodeProperties::ChangeOp(node, machine()->Word32And());
1071  Reduction reduction = ReduceWord32And(node);
1072  return reduction.Changed() ? reduction : Changed(node);
1073  }
1074  }
1075  }
1076  return ReduceWord32Shifts(node);
1077 }
1078 
1079 Reduction MachineOperatorReducer::ReduceWord64Shl(Node* node) {
1080  DCHECK_EQ(IrOpcode::kWord64Shl, node->opcode());
1081  Int64BinopMatcher m(node);
1082  if (m.right().Is(0)) return Replace(m.left().node()); // x << 0 => x
1083  if (m.IsFoldable()) { // K << K => K
1084  return ReplaceInt64(m.left().Value() << m.right().Value());
1085  }
1086  return NoChange();
1087 }
1088 
1089 Reduction MachineOperatorReducer::ReduceWord32Shr(Node* node) {
1090  Uint32BinopMatcher m(node);
1091  if (m.right().Is(0)) return Replace(m.left().node()); // x >>> 0 => x
1092  if (m.IsFoldable()) { // K >>> K => K
1093  return ReplaceInt32(m.left().Value() >> m.right().Value());
1094  }
1095  if (m.left().IsWord32And() && m.right().HasValue()) {
1096  Uint32BinopMatcher mleft(m.left().node());
1097  if (mleft.right().HasValue()) {
1098  uint32_t shift = m.right().Value() & 0x1F;
1099  uint32_t mask = mleft.right().Value();
1100  if ((mask >> shift) == 0) {
1101  // (m >>> s) == 0 implies ((x & m) >>> s) == 0
1102  return ReplaceInt32(0);
1103  }
1104  }
1105  }
1106  return ReduceWord32Shifts(node);
1107 }
1108 
1109 Reduction MachineOperatorReducer::ReduceWord64Shr(Node* node) {
1110  DCHECK_EQ(IrOpcode::kWord64Shr, node->opcode());
1111  Uint64BinopMatcher m(node);
1112  if (m.right().Is(0)) return Replace(m.left().node()); // x >>> 0 => x
1113  if (m.IsFoldable()) { // K >> K => K
1114  return ReplaceInt64(m.left().Value() >> m.right().Value());
1115  }
1116  return NoChange();
1117 }
1118 
1119 Reduction MachineOperatorReducer::ReduceWord32Sar(Node* node) {
1120  Int32BinopMatcher m(node);
1121  if (m.right().Is(0)) return Replace(m.left().node()); // x >> 0 => x
1122  if (m.IsFoldable()) { // K >> K => K
1123  return ReplaceInt32(m.left().Value() >> m.right().Value());
1124  }
1125  if (m.left().IsWord32Shl()) {
1126  Int32BinopMatcher mleft(m.left().node());
1127  if (mleft.left().IsComparison()) {
1128  if (m.right().Is(31) && mleft.right().Is(31)) {
1129  // Comparison << 31 >> 31 => 0 - Comparison
1130  node->ReplaceInput(0, Int32Constant(0));
1131  node->ReplaceInput(1, mleft.left().node());
1132  NodeProperties::ChangeOp(node, machine()->Int32Sub());
1133  Reduction const reduction = ReduceInt32Sub(node);
1134  return reduction.Changed() ? reduction : Changed(node);
1135  }
1136  } else if (mleft.left().IsLoad()) {
1137  LoadRepresentation const rep =
1138  LoadRepresentationOf(mleft.left().node()->op());
1139  if (m.right().Is(24) && mleft.right().Is(24) &&
1140  rep == MachineType::Int8()) {
1141  // Load[kMachInt8] << 24 >> 24 => Load[kMachInt8]
1142  return Replace(mleft.left().node());
1143  }
1144  if (m.right().Is(16) && mleft.right().Is(16) &&
1145  rep == MachineType::Int16()) {
1146  // Load[kMachInt16] << 16 >> 16 => Load[kMachInt8]
1147  return Replace(mleft.left().node());
1148  }
1149  }
1150  }
1151  return ReduceWord32Shifts(node);
1152 }
1153 
1154 Reduction MachineOperatorReducer::ReduceWord64Sar(Node* node) {
1155  Int64BinopMatcher m(node);
1156  if (m.right().Is(0)) return Replace(m.left().node()); // x >> 0 => x
1157  if (m.IsFoldable()) {
1158  return ReplaceInt64(m.left().Value() >> m.right().Value());
1159  }
1160  return NoChange();
1161 }
1162 
1163 Reduction MachineOperatorReducer::ReduceWord32And(Node* node) {
1164  DCHECK_EQ(IrOpcode::kWord32And, node->opcode());
1165  Int32BinopMatcher m(node);
1166  if (m.right().Is(0)) return Replace(m.right().node()); // x & 0 => 0
1167  if (m.right().Is(-1)) return Replace(m.left().node()); // x & -1 => x
1168  if (m.left().IsComparison() && m.right().Is(1)) { // CMP & 1 => CMP
1169  return Replace(m.left().node());
1170  }
1171  if (m.IsFoldable()) { // K & K => K
1172  return ReplaceInt32(m.left().Value() & m.right().Value());
1173  }
1174  if (m.LeftEqualsRight()) return Replace(m.left().node()); // x & x => x
1175  if (m.left().IsWord32And() && m.right().HasValue()) {
1176  Int32BinopMatcher mleft(m.left().node());
1177  if (mleft.right().HasValue()) { // (x & K) & K => x & K
1178  node->ReplaceInput(0, mleft.left().node());
1179  node->ReplaceInput(
1180  1, Int32Constant(m.right().Value() & mleft.right().Value()));
1181  Reduction const reduction = ReduceWord32And(node);
1182  return reduction.Changed() ? reduction : Changed(node);
1183  }
1184  }
1185  if (m.right().IsNegativePowerOf2()) {
1186  int32_t const mask = m.right().Value();
1187  if (m.left().IsWord32Shl()) {
1188  Uint32BinopMatcher mleft(m.left().node());
1189  if (mleft.right().HasValue() &&
1190  (mleft.right().Value() & 0x1F) >=
1191  base::bits::CountTrailingZeros(mask)) {
1192  // (x << L) & (-1 << K) => x << L iff L >= K
1193  return Replace(mleft.node());
1194  }
1195  } else if (m.left().IsInt32Add()) {
1196  Int32BinopMatcher mleft(m.left().node());
1197  if (mleft.right().HasValue() &&
1198  (mleft.right().Value() & mask) == mleft.right().Value()) {
1199  // (x + (K << L)) & (-1 << L) => (x & (-1 << L)) + (K << L)
1200  node->ReplaceInput(0, Word32And(mleft.left().node(), m.right().node()));
1201  node->ReplaceInput(1, mleft.right().node());
1202  NodeProperties::ChangeOp(node, machine()->Int32Add());
1203  Reduction const reduction = ReduceInt32Add(node);
1204  return reduction.Changed() ? reduction : Changed(node);
1205  }
1206  if (mleft.left().IsInt32Mul()) {
1207  Int32BinopMatcher mleftleft(mleft.left().node());
1208  if (mleftleft.right().IsMultipleOf(-mask)) {
1209  // (y * (K << L) + x) & (-1 << L) => (x & (-1 << L)) + y * (K << L)
1210  node->ReplaceInput(0,
1211  Word32And(mleft.right().node(), m.right().node()));
1212  node->ReplaceInput(1, mleftleft.node());
1213  NodeProperties::ChangeOp(node, machine()->Int32Add());
1214  Reduction const reduction = ReduceInt32Add(node);
1215  return reduction.Changed() ? reduction : Changed(node);
1216  }
1217  }
1218  if (mleft.right().IsInt32Mul()) {
1219  Int32BinopMatcher mleftright(mleft.right().node());
1220  if (mleftright.right().IsMultipleOf(-mask)) {
1221  // (x + y * (K << L)) & (-1 << L) => (x & (-1 << L)) + y * (K << L)
1222  node->ReplaceInput(0,
1223  Word32And(mleft.left().node(), m.right().node()));
1224  node->ReplaceInput(1, mleftright.node());
1225  NodeProperties::ChangeOp(node, machine()->Int32Add());
1226  Reduction const reduction = ReduceInt32Add(node);
1227  return reduction.Changed() ? reduction : Changed(node);
1228  }
1229  }
1230  if (mleft.left().IsWord32Shl()) {
1231  Int32BinopMatcher mleftleft(mleft.left().node());
1232  if (mleftleft.right().Is(base::bits::CountTrailingZeros(mask))) {
1233  // (y << L + x) & (-1 << L) => (x & (-1 << L)) + y << L
1234  node->ReplaceInput(0,
1235  Word32And(mleft.right().node(), m.right().node()));
1236  node->ReplaceInput(1, mleftleft.node());
1237  NodeProperties::ChangeOp(node, machine()->Int32Add());
1238  Reduction const reduction = ReduceInt32Add(node);
1239  return reduction.Changed() ? reduction : Changed(node);
1240  }
1241  }
1242  if (mleft.right().IsWord32Shl()) {
1243  Int32BinopMatcher mleftright(mleft.right().node());
1244  if (mleftright.right().Is(base::bits::CountTrailingZeros(mask))) {
1245  // (x + y << L) & (-1 << L) => (x & (-1 << L)) + y << L
1246  node->ReplaceInput(0,
1247  Word32And(mleft.left().node(), m.right().node()));
1248  node->ReplaceInput(1, mleftright.node());
1249  NodeProperties::ChangeOp(node, machine()->Int32Add());
1250  Reduction const reduction = ReduceInt32Add(node);
1251  return reduction.Changed() ? reduction : Changed(node);
1252  }
1253  }
1254  } else if (m.left().IsInt32Mul()) {
1255  Int32BinopMatcher mleft(m.left().node());
1256  if (mleft.right().IsMultipleOf(-mask)) {
1257  // (x * (K << L)) & (-1 << L) => x * (K << L)
1258  return Replace(mleft.node());
1259  }
1260  }
1261  }
1262  return NoChange();
1263 }
1264 
1265 Reduction MachineOperatorReducer::TryMatchWord32Ror(Node* node) {
1266  DCHECK(IrOpcode::kWord32Or == node->opcode() ||
1267  IrOpcode::kWord32Xor == node->opcode());
1268  Int32BinopMatcher m(node);
1269  Node* shl = nullptr;
1270  Node* shr = nullptr;
1271  // Recognize rotation, we are matching:
1272  // * x << y | x >>> (32 - y) => x ror (32 - y), i.e x rol y
1273  // * x << (32 - y) | x >>> y => x ror y
1274  // * x << y ^ x >>> (32 - y) => x ror (32 - y), i.e. x rol y
1275  // * x << (32 - y) ^ x >>> y => x ror y
1276  // as well as their commuted form.
1277  if (m.left().IsWord32Shl() && m.right().IsWord32Shr()) {
1278  shl = m.left().node();
1279  shr = m.right().node();
1280  } else if (m.left().IsWord32Shr() && m.right().IsWord32Shl()) {
1281  shl = m.right().node();
1282  shr = m.left().node();
1283  } else {
1284  return NoChange();
1285  }
1286 
1287  Int32BinopMatcher mshl(shl);
1288  Int32BinopMatcher mshr(shr);
1289  if (mshl.left().node() != mshr.left().node()) return NoChange();
1290 
1291  if (mshl.right().HasValue() && mshr.right().HasValue()) {
1292  // Case where y is a constant.
1293  if (mshl.right().Value() + mshr.right().Value() != 32) return NoChange();
1294  } else {
1295  Node* sub = nullptr;
1296  Node* y = nullptr;
1297  if (mshl.right().IsInt32Sub()) {
1298  sub = mshl.right().node();
1299  y = mshr.right().node();
1300  } else if (mshr.right().IsInt32Sub()) {
1301  sub = mshr.right().node();
1302  y = mshl.right().node();
1303  } else {
1304  return NoChange();
1305  }
1306 
1307  Int32BinopMatcher msub(sub);
1308  if (!msub.left().Is(32) || msub.right().node() != y) return NoChange();
1309  }
1310 
1311  node->ReplaceInput(0, mshl.left().node());
1312  node->ReplaceInput(1, mshr.right().node());
1313  NodeProperties::ChangeOp(node, machine()->Word32Ror());
1314  return Changed(node);
1315 }
1316 
1317 Reduction MachineOperatorReducer::ReduceWord32Or(Node* node) {
1318  DCHECK_EQ(IrOpcode::kWord32Or, node->opcode());
1319  Int32BinopMatcher m(node);
1320  if (m.right().Is(0)) return Replace(m.left().node()); // x | 0 => x
1321  if (m.right().Is(-1)) return Replace(m.right().node()); // x | -1 => -1
1322  if (m.IsFoldable()) { // K | K => K
1323  return ReplaceInt32(m.left().Value() | m.right().Value());
1324  }
1325  if (m.LeftEqualsRight()) return Replace(m.left().node()); // x | x => x
1326 
1327  return TryMatchWord32Ror(node);
1328 }
1329 
1330 Reduction MachineOperatorReducer::ReduceWord32Xor(Node* node) {
1331  DCHECK_EQ(IrOpcode::kWord32Xor, node->opcode());
1332  Int32BinopMatcher m(node);
1333  if (m.right().Is(0)) return Replace(m.left().node()); // x ^ 0 => x
1334  if (m.IsFoldable()) { // K ^ K => K
1335  return ReplaceInt32(m.left().Value() ^ m.right().Value());
1336  }
1337  if (m.LeftEqualsRight()) return ReplaceInt32(0); // x ^ x => 0
1338  if (m.left().IsWord32Xor() && m.right().Is(-1)) {
1339  Int32BinopMatcher mleft(m.left().node());
1340  if (mleft.right().Is(-1)) { // (x ^ -1) ^ -1 => x
1341  return Replace(mleft.left().node());
1342  }
1343  }
1344 
1345  return TryMatchWord32Ror(node);
1346 }
1347 
1348 Reduction MachineOperatorReducer::ReduceFloat64InsertLowWord32(Node* node) {
1349  DCHECK_EQ(IrOpcode::kFloat64InsertLowWord32, node->opcode());
1350  Float64Matcher mlhs(node->InputAt(0));
1351  Uint32Matcher mrhs(node->InputAt(1));
1352  if (mlhs.HasValue() && mrhs.HasValue()) {
1353  return ReplaceFloat64(bit_cast<double>(
1354  (bit_cast<uint64_t>(mlhs.Value()) & uint64_t{0xFFFFFFFF00000000}) |
1355  mrhs.Value()));
1356  }
1357  return NoChange();
1358 }
1359 
1360 
1361 Reduction MachineOperatorReducer::ReduceFloat64InsertHighWord32(Node* node) {
1362  DCHECK_EQ(IrOpcode::kFloat64InsertHighWord32, node->opcode());
1363  Float64Matcher mlhs(node->InputAt(0));
1364  Uint32Matcher mrhs(node->InputAt(1));
1365  if (mlhs.HasValue() && mrhs.HasValue()) {
1366  return ReplaceFloat64(bit_cast<double>(
1367  (bit_cast<uint64_t>(mlhs.Value()) & uint64_t{0xFFFFFFFF}) |
1368  (static_cast<uint64_t>(mrhs.Value()) << 32)));
1369  }
1370  return NoChange();
1371 }
1372 
1373 
1374 namespace {
1375 
1376 bool IsFloat64RepresentableAsFloat32(const Float64Matcher& m) {
1377  if (m.HasValue()) {
1378  double v = m.Value();
1379  float fv = static_cast<float>(v);
1380  return static_cast<double>(fv) == v;
1381  }
1382  return false;
1383 }
1384 
1385 } // namespace
1386 
1387 
1388 Reduction MachineOperatorReducer::ReduceFloat64Compare(Node* node) {
1389  DCHECK(IrOpcode::kFloat64Equal == node->opcode() ||
1390  IrOpcode::kFloat64LessThan == node->opcode() ||
1391  IrOpcode::kFloat64LessThanOrEqual == node->opcode());
1392  Float64BinopMatcher m(node);
1393  if (m.IsFoldable()) {
1394  switch (node->opcode()) {
1395  case IrOpcode::kFloat64Equal:
1396  return ReplaceBool(m.left().Value() == m.right().Value());
1397  case IrOpcode::kFloat64LessThan:
1398  return ReplaceBool(m.left().Value() < m.right().Value());
1399  case IrOpcode::kFloat64LessThanOrEqual:
1400  return ReplaceBool(m.left().Value() <= m.right().Value());
1401  default:
1402  UNREACHABLE();
1403  }
1404  } else if ((m.left().IsChangeFloat32ToFloat64() &&
1405  m.right().IsChangeFloat32ToFloat64()) ||
1406  (m.left().IsChangeFloat32ToFloat64() &&
1407  IsFloat64RepresentableAsFloat32(m.right())) ||
1408  (IsFloat64RepresentableAsFloat32(m.left()) &&
1409  m.right().IsChangeFloat32ToFloat64())) {
1410  // As all Float32 values have an exact representation in Float64, comparing
1411  // two Float64 values both converted from Float32 is equivalent to comparing
1412  // the original Float32s, so we can ignore the conversions. We can also
1413  // reduce comparisons of converted Float64 values against constants that
1414  // can be represented exactly as Float32.
1415  switch (node->opcode()) {
1416  case IrOpcode::kFloat64Equal:
1417  NodeProperties::ChangeOp(node, machine()->Float32Equal());
1418  break;
1419  case IrOpcode::kFloat64LessThan:
1420  NodeProperties::ChangeOp(node, machine()->Float32LessThan());
1421  break;
1422  case IrOpcode::kFloat64LessThanOrEqual:
1423  NodeProperties::ChangeOp(node, machine()->Float32LessThanOrEqual());
1424  break;
1425  default:
1426  UNREACHABLE();
1427  }
1428  node->ReplaceInput(
1429  0, m.left().HasValue()
1430  ? Float32Constant(static_cast<float>(m.left().Value()))
1431  : m.left().InputAt(0));
1432  node->ReplaceInput(
1433  1, m.right().HasValue()
1434  ? Float32Constant(static_cast<float>(m.right().Value()))
1435  : m.right().InputAt(0));
1436  return Changed(node);
1437  }
1438  return NoChange();
1439 }
1440 
1441 Reduction MachineOperatorReducer::ReduceFloat64RoundDown(Node* node) {
1442  DCHECK_EQ(IrOpcode::kFloat64RoundDown, node->opcode());
1443  Float64Matcher m(node->InputAt(0));
1444  if (m.HasValue()) {
1445  return ReplaceFloat64(Floor(m.Value()));
1446  }
1447  return NoChange();
1448 }
1449 
1450 CommonOperatorBuilder* MachineOperatorReducer::common() const {
1451  return mcgraph()->common();
1452 }
1453 
1454 
1455 MachineOperatorBuilder* MachineOperatorReducer::machine() const {
1456  return mcgraph()->machine();
1457 }
1458 
1459 Graph* MachineOperatorReducer::graph() const { return mcgraph()->graph(); }
1460 
1461 } // namespace compiler
1462 } // namespace internal
1463 } // namespace v8
Definition: libplatform.h:13