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/codegen.h" 11 #include "src/compiler/diamond.h" 12 #include "src/compiler/graph.h" 13 #include "src/compiler/js-graph.h" 14 #include "src/compiler/node-matchers.h" 15 16 namespace v8 { 17 namespace internal { 18 namespace compiler { 19 20 MachineOperatorReducer::MachineOperatorReducer(JSGraph* jsgraph) 21 : jsgraph_(jsgraph) {} 22 23 24 MachineOperatorReducer::~MachineOperatorReducer() {} 25 26 27 Node* MachineOperatorReducer::Float32Constant(volatile float value) { 28 return graph()->NewNode(common()->Float32Constant(value)); 29 } 30 31 32 Node* MachineOperatorReducer::Float64Constant(volatile double value) { 33 return jsgraph()->Float64Constant(value); 34 } 35 36 37 Node* MachineOperatorReducer::Int32Constant(int32_t value) { 38 return jsgraph()->Int32Constant(value); 39 } 40 41 42 Node* MachineOperatorReducer::Int64Constant(int64_t value) { 43 return graph()->NewNode(common()->Int64Constant(value)); 44 } 45 46 47 Node* MachineOperatorReducer::Word32And(Node* lhs, Node* rhs) { 48 Node* const node = graph()->NewNode(machine()->Word32And(), lhs, rhs); 49 Reduction const reduction = ReduceWord32And(node); 50 return reduction.Changed() ? reduction.replacement() : node; 51 } 52 53 54 Node* MachineOperatorReducer::Word32Sar(Node* lhs, uint32_t rhs) { 55 if (rhs == 0) return lhs; 56 return graph()->NewNode(machine()->Word32Sar(), lhs, Uint32Constant(rhs)); 57 } 58 59 60 Node* MachineOperatorReducer::Word32Shr(Node* lhs, uint32_t rhs) { 61 if (rhs == 0) return lhs; 62 return graph()->NewNode(machine()->Word32Shr(), lhs, Uint32Constant(rhs)); 63 } 64 65 66 Node* MachineOperatorReducer::Word32Equal(Node* lhs, Node* rhs) { 67 return graph()->NewNode(machine()->Word32Equal(), lhs, rhs); 68 } 69 70 71 Node* MachineOperatorReducer::Int32Add(Node* lhs, Node* rhs) { 72 Node* const node = graph()->NewNode(machine()->Int32Add(), lhs, rhs); 73 Reduction const reduction = ReduceInt32Add(node); 74 return reduction.Changed() ? reduction.replacement() : node; 75 } 76 77 78 Node* MachineOperatorReducer::Int32Sub(Node* lhs, Node* rhs) { 79 Node* const node = graph()->NewNode(machine()->Int32Sub(), lhs, rhs); 80 Reduction const reduction = ReduceInt32Sub(node); 81 return reduction.Changed() ? reduction.replacement() : node; 82 } 83 84 85 Node* MachineOperatorReducer::Int32Mul(Node* lhs, Node* rhs) { 86 return graph()->NewNode(machine()->Int32Mul(), lhs, rhs); 87 } 88 89 90 Node* MachineOperatorReducer::Int32Div(Node* dividend, int32_t divisor) { 91 DCHECK_NE(0, divisor); 92 DCHECK_NE(std::numeric_limits<int32_t>::min(), divisor); 93 base::MagicNumbersForDivision<uint32_t> const mag = 94 base::SignedDivisionByConstant(bit_cast<uint32_t>(divisor)); 95 Node* quotient = graph()->NewNode(machine()->Int32MulHigh(), dividend, 96 Uint32Constant(mag.multiplier)); 97 if (divisor > 0 && bit_cast<int32_t>(mag.multiplier) < 0) { 98 quotient = Int32Add(quotient, dividend); 99 } else if (divisor < 0 && bit_cast<int32_t>(mag.multiplier) > 0) { 100 quotient = Int32Sub(quotient, dividend); 101 } 102 return Int32Add(Word32Sar(quotient, mag.shift), Word32Shr(dividend, 31)); 103 } 104 105 106 Node* MachineOperatorReducer::Uint32Div(Node* dividend, uint32_t divisor) { 107 DCHECK_LT(0u, divisor); 108 // If the divisor is even, we can avoid using the expensive fixup by shifting 109 // the dividend upfront. 110 unsigned const shift = base::bits::CountTrailingZeros32(divisor); 111 dividend = Word32Shr(dividend, shift); 112 divisor >>= shift; 113 // Compute the magic number for the (shifted) divisor. 114 base::MagicNumbersForDivision<uint32_t> const mag = 115 base::UnsignedDivisionByConstant(divisor, shift); 116 Node* quotient = graph()->NewNode(machine()->Uint32MulHigh(), dividend, 117 Uint32Constant(mag.multiplier)); 118 if (mag.add) { 119 DCHECK_LE(1u, mag.shift); 120 quotient = Word32Shr( 121 Int32Add(Word32Shr(Int32Sub(dividend, quotient), 1), quotient), 122 mag.shift - 1); 123 } else { 124 quotient = Word32Shr(quotient, mag.shift); 125 } 126 return quotient; 127 } 128 129 130 // Perform constant folding and strength reduction on machine operators. 131 Reduction MachineOperatorReducer::Reduce(Node* node) { 132 switch (node->opcode()) { 133 case IrOpcode::kProjection: 134 return ReduceProjection(ProjectionIndexOf(node->op()), node->InputAt(0)); 135 case IrOpcode::kWord32And: 136 return ReduceWord32And(node); 137 case IrOpcode::kWord32Or: 138 return ReduceWord32Or(node); 139 case IrOpcode::kWord32Xor: { 140 Int32BinopMatcher m(node); 141 if (m.right().Is(0)) return Replace(m.left().node()); // x ^ 0 => x 142 if (m.IsFoldable()) { // K ^ K => K 143 return ReplaceInt32(m.left().Value() ^ m.right().Value()); 144 } 145 if (m.LeftEqualsRight()) return ReplaceInt32(0); // x ^ x => 0 146 if (m.left().IsWord32Xor() && m.right().Is(-1)) { 147 Int32BinopMatcher mleft(m.left().node()); 148 if (mleft.right().Is(-1)) { // (x ^ -1) ^ -1 => x 149 return Replace(mleft.left().node()); 150 } 151 } 152 break; 153 } 154 case IrOpcode::kWord32Shl: 155 return ReduceWord32Shl(node); 156 case IrOpcode::kWord32Shr: 157 return ReduceWord32Shr(node); 158 case IrOpcode::kWord32Sar: 159 return ReduceWord32Sar(node); 160 case IrOpcode::kWord32Ror: { 161 Int32BinopMatcher m(node); 162 if (m.right().Is(0)) return Replace(m.left().node()); // x ror 0 => x 163 if (m.IsFoldable()) { // K ror K => K 164 return ReplaceInt32( 165 base::bits::RotateRight32(m.left().Value(), m.right().Value())); 166 } 167 break; 168 } 169 case IrOpcode::kWord32Equal: { 170 Int32BinopMatcher m(node); 171 if (m.IsFoldable()) { // K == K => K 172 return ReplaceBool(m.left().Value() == m.right().Value()); 173 } 174 if (m.left().IsInt32Sub() && m.right().Is(0)) { // x - y == 0 => x == y 175 Int32BinopMatcher msub(m.left().node()); 176 node->ReplaceInput(0, msub.left().node()); 177 node->ReplaceInput(1, msub.right().node()); 178 return Changed(node); 179 } 180 // TODO(turbofan): fold HeapConstant, ExternalReference, pointer compares 181 if (m.LeftEqualsRight()) return ReplaceBool(true); // x == x => true 182 break; 183 } 184 case IrOpcode::kWord64Equal: { 185 Int64BinopMatcher m(node); 186 if (m.IsFoldable()) { // K == K => K 187 return ReplaceBool(m.left().Value() == m.right().Value()); 188 } 189 if (m.left().IsInt64Sub() && m.right().Is(0)) { // x - y == 0 => x == y 190 Int64BinopMatcher msub(m.left().node()); 191 node->ReplaceInput(0, msub.left().node()); 192 node->ReplaceInput(1, msub.right().node()); 193 return Changed(node); 194 } 195 // TODO(turbofan): fold HeapConstant, ExternalReference, pointer compares 196 if (m.LeftEqualsRight()) return ReplaceBool(true); // x == x => true 197 break; 198 } 199 case IrOpcode::kInt32Add: 200 return ReduceInt32Add(node); 201 case IrOpcode::kInt32Sub: 202 return ReduceInt32Sub(node); 203 case IrOpcode::kInt32Mul: { 204 Int32BinopMatcher m(node); 205 if (m.right().Is(0)) return Replace(m.right().node()); // x * 0 => 0 206 if (m.right().Is(1)) return Replace(m.left().node()); // x * 1 => x 207 if (m.IsFoldable()) { // K * K => K 208 return ReplaceInt32(m.left().Value() * m.right().Value()); 209 } 210 if (m.right().Is(-1)) { // x * -1 => 0 - x 211 node->ReplaceInput(0, Int32Constant(0)); 212 node->ReplaceInput(1, m.left().node()); 213 NodeProperties::ChangeOp(node, machine()->Int32Sub()); 214 return Changed(node); 215 } 216 if (m.right().IsPowerOf2()) { // x * 2^n => x << n 217 node->ReplaceInput(1, Int32Constant(WhichPowerOf2(m.right().Value()))); 218 NodeProperties::ChangeOp(node, machine()->Word32Shl()); 219 Reduction reduction = ReduceWord32Shl(node); 220 return reduction.Changed() ? reduction : Changed(node); 221 } 222 break; 223 } 224 case IrOpcode::kInt32Div: 225 return ReduceInt32Div(node); 226 case IrOpcode::kUint32Div: 227 return ReduceUint32Div(node); 228 case IrOpcode::kInt32Mod: 229 return ReduceInt32Mod(node); 230 case IrOpcode::kUint32Mod: 231 return ReduceUint32Mod(node); 232 case IrOpcode::kInt32LessThan: { 233 Int32BinopMatcher m(node); 234 if (m.IsFoldable()) { // K < K => K 235 return ReplaceBool(m.left().Value() < m.right().Value()); 236 } 237 if (m.LeftEqualsRight()) return ReplaceBool(false); // x < x => false 238 break; 239 } 240 case IrOpcode::kInt32LessThanOrEqual: { 241 Int32BinopMatcher m(node); 242 if (m.IsFoldable()) { // K <= K => K 243 return ReplaceBool(m.left().Value() <= m.right().Value()); 244 } 245 if (m.LeftEqualsRight()) return ReplaceBool(true); // x <= x => true 246 break; 247 } 248 case IrOpcode::kUint32LessThan: { 249 Uint32BinopMatcher m(node); 250 if (m.left().Is(kMaxUInt32)) return ReplaceBool(false); // M < x => false 251 if (m.right().Is(0)) return ReplaceBool(false); // x < 0 => false 252 if (m.IsFoldable()) { // K < K => K 253 return ReplaceBool(m.left().Value() < m.right().Value()); 254 } 255 if (m.LeftEqualsRight()) return ReplaceBool(false); // x < x => false 256 if (m.left().IsWord32Sar() && m.right().HasValue()) { 257 Int32BinopMatcher mleft(m.left().node()); 258 if (mleft.right().HasValue()) { 259 // (x >> K) < C => x < (C << K) 260 // when C < (M >> K) 261 const uint32_t c = m.right().Value(); 262 const uint32_t k = mleft.right().Value() & 0x1f; 263 if (c < static_cast<uint32_t>(kMaxInt >> k)) { 264 node->ReplaceInput(0, mleft.left().node()); 265 node->ReplaceInput(1, Uint32Constant(c << k)); 266 return Changed(node); 267 } 268 // TODO(turbofan): else the comparison is always true. 269 } 270 } 271 break; 272 } 273 case IrOpcode::kUint32LessThanOrEqual: { 274 Uint32BinopMatcher m(node); 275 if (m.left().Is(0)) return ReplaceBool(true); // 0 <= x => true 276 if (m.right().Is(kMaxUInt32)) return ReplaceBool(true); // x <= M => true 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::kFloat64Add: { 284 Float64BinopMatcher m(node); 285 if (m.right().IsNaN()) { // x + NaN => NaN 286 return Replace(m.right().node()); 287 } 288 if (m.IsFoldable()) { // K + K => K 289 return ReplaceFloat64(m.left().Value() + m.right().Value()); 290 } 291 break; 292 } 293 case IrOpcode::kFloat64Sub: { 294 Float64BinopMatcher m(node); 295 if (m.right().Is(0) && (Double(m.right().Value()).Sign() > 0)) { 296 return Replace(m.left().node()); // x - 0 => x 297 } 298 if (m.right().IsNaN()) { // x - NaN => NaN 299 return Replace(m.right().node()); 300 } 301 if (m.left().IsNaN()) { // NaN - x => NaN 302 return Replace(m.left().node()); 303 } 304 if (m.IsFoldable()) { // K - K => K 305 return ReplaceFloat64(m.left().Value() - m.right().Value()); 306 } 307 break; 308 } 309 case IrOpcode::kFloat64Mul: { 310 Float64BinopMatcher m(node); 311 if (m.right().Is(-1)) { // x * -1.0 => -0.0 - x 312 node->ReplaceInput(0, Float64Constant(-0.0)); 313 node->ReplaceInput(1, m.left().node()); 314 NodeProperties::ChangeOp(node, machine()->Float64Sub()); 315 return Changed(node); 316 } 317 if (m.right().Is(1)) return Replace(m.left().node()); // x * 1.0 => x 318 if (m.right().IsNaN()) { // x * NaN => NaN 319 return Replace(m.right().node()); 320 } 321 if (m.IsFoldable()) { // K * K => K 322 return ReplaceFloat64(m.left().Value() * m.right().Value()); 323 } 324 break; 325 } 326 case IrOpcode::kFloat64Div: { 327 Float64BinopMatcher m(node); 328 if (m.right().Is(1)) return Replace(m.left().node()); // x / 1.0 => x 329 if (m.right().IsNaN()) { // x / NaN => NaN 330 return Replace(m.right().node()); 331 } 332 if (m.left().IsNaN()) { // NaN / x => NaN 333 return Replace(m.left().node()); 334 } 335 if (m.IsFoldable()) { // K / K => K 336 return ReplaceFloat64(m.left().Value() / m.right().Value()); 337 } 338 break; 339 } 340 case IrOpcode::kFloat64Mod: { 341 Float64BinopMatcher m(node); 342 if (m.right().Is(0)) { // x % 0 => NaN 343 return ReplaceFloat64(std::numeric_limits<double>::quiet_NaN()); 344 } 345 if (m.right().IsNaN()) { // x % NaN => NaN 346 return Replace(m.right().node()); 347 } 348 if (m.left().IsNaN()) { // NaN % x => NaN 349 return Replace(m.left().node()); 350 } 351 if (m.IsFoldable()) { // K % K => K 352 return ReplaceFloat64(modulo(m.left().Value(), m.right().Value())); 353 } 354 break; 355 } 356 case IrOpcode::kFloat64Atan: { 357 Float64Matcher m(node->InputAt(0)); 358 if (m.HasValue()) return ReplaceFloat64(base::ieee754::atan(m.Value())); 359 break; 360 } 361 case IrOpcode::kFloat64Atan2: { 362 Float64BinopMatcher m(node); 363 if (m.right().IsNaN()) { 364 return Replace(m.right().node()); 365 } 366 if (m.left().IsNaN()) { 367 return Replace(m.left().node()); 368 } 369 if (m.IsFoldable()) { 370 return ReplaceFloat64( 371 base::ieee754::atan2(m.left().Value(), m.right().Value())); 372 } 373 break; 374 } 375 case IrOpcode::kFloat64Atanh: { 376 Float64Matcher m(node->InputAt(0)); 377 if (m.HasValue()) return ReplaceFloat64(base::ieee754::atanh(m.Value())); 378 break; 379 } 380 case IrOpcode::kFloat64Cos: { 381 Float64Matcher m(node->InputAt(0)); 382 if (m.HasValue()) return ReplaceFloat64(base::ieee754::cos(m.Value())); 383 break; 384 } 385 case IrOpcode::kFloat64Exp: { 386 Float64Matcher m(node->InputAt(0)); 387 if (m.HasValue()) return ReplaceFloat64(base::ieee754::exp(m.Value())); 388 break; 389 } 390 case IrOpcode::kFloat64Expm1: { 391 Float64Matcher m(node->InputAt(0)); 392 if (m.HasValue()) return ReplaceFloat64(base::ieee754::expm1(m.Value())); 393 break; 394 } 395 case IrOpcode::kFloat64Log: { 396 Float64Matcher m(node->InputAt(0)); 397 if (m.HasValue()) return ReplaceFloat64(base::ieee754::log(m.Value())); 398 break; 399 } 400 case IrOpcode::kFloat64Log1p: { 401 Float64Matcher m(node->InputAt(0)); 402 if (m.HasValue()) return ReplaceFloat64(base::ieee754::log1p(m.Value())); 403 break; 404 } 405 case IrOpcode::kFloat64Log2: { 406 Float64Matcher m(node->InputAt(0)); 407 if (m.HasValue()) return ReplaceFloat64(base::ieee754::log2(m.Value())); 408 break; 409 } 410 case IrOpcode::kFloat64Log10: { 411 Float64Matcher m(node->InputAt(0)); 412 if (m.HasValue()) return ReplaceFloat64(base::ieee754::log10(m.Value())); 413 break; 414 } 415 case IrOpcode::kFloat64Cbrt: { 416 Float64Matcher m(node->InputAt(0)); 417 if (m.HasValue()) return ReplaceFloat64(base::ieee754::cbrt(m.Value())); 418 break; 419 } 420 case IrOpcode::kFloat64Sin: { 421 Float64Matcher m(node->InputAt(0)); 422 if (m.HasValue()) return ReplaceFloat64(base::ieee754::sin(m.Value())); 423 break; 424 } 425 case IrOpcode::kFloat64Tan: { 426 Float64Matcher m(node->InputAt(0)); 427 if (m.HasValue()) return ReplaceFloat64(base::ieee754::tan(m.Value())); 428 break; 429 } 430 case IrOpcode::kChangeFloat32ToFloat64: { 431 Float32Matcher m(node->InputAt(0)); 432 if (m.HasValue()) return ReplaceFloat64(m.Value()); 433 break; 434 } 435 case IrOpcode::kChangeFloat64ToInt32: { 436 Float64Matcher m(node->InputAt(0)); 437 if (m.HasValue()) return ReplaceInt32(FastD2I(m.Value())); 438 if (m.IsChangeInt32ToFloat64()) return Replace(m.node()->InputAt(0)); 439 break; 440 } 441 case IrOpcode::kChangeFloat64ToUint32: { 442 Float64Matcher m(node->InputAt(0)); 443 if (m.HasValue()) return ReplaceInt32(FastD2UI(m.Value())); 444 if (m.IsChangeUint32ToFloat64()) return Replace(m.node()->InputAt(0)); 445 break; 446 } 447 case IrOpcode::kChangeInt32ToFloat64: { 448 Int32Matcher m(node->InputAt(0)); 449 if (m.HasValue()) return ReplaceFloat64(FastI2D(m.Value())); 450 break; 451 } 452 case IrOpcode::kChangeInt32ToInt64: { 453 Int32Matcher m(node->InputAt(0)); 454 if (m.HasValue()) return ReplaceInt64(m.Value()); 455 break; 456 } 457 case IrOpcode::kChangeUint32ToFloat64: { 458 Uint32Matcher m(node->InputAt(0)); 459 if (m.HasValue()) return ReplaceFloat64(FastUI2D(m.Value())); 460 break; 461 } 462 case IrOpcode::kChangeUint32ToUint64: { 463 Uint32Matcher m(node->InputAt(0)); 464 if (m.HasValue()) return ReplaceInt64(static_cast<uint64_t>(m.Value())); 465 break; 466 } 467 case IrOpcode::kTruncateFloat64ToWord32: { 468 Float64Matcher m(node->InputAt(0)); 469 if (m.HasValue()) return ReplaceInt32(DoubleToInt32(m.Value())); 470 if (m.IsChangeInt32ToFloat64()) return Replace(m.node()->InputAt(0)); 471 return NoChange(); 472 } 473 case IrOpcode::kTruncateInt64ToInt32: { 474 Int64Matcher m(node->InputAt(0)); 475 if (m.HasValue()) return ReplaceInt32(static_cast<int32_t>(m.Value())); 476 if (m.IsChangeInt32ToInt64()) return Replace(m.node()->InputAt(0)); 477 break; 478 } 479 case IrOpcode::kTruncateFloat64ToFloat32: { 480 Float64Matcher m(node->InputAt(0)); 481 if (m.HasValue()) return ReplaceFloat32(DoubleToFloat32(m.Value())); 482 if (m.IsChangeFloat32ToFloat64()) return Replace(m.node()->InputAt(0)); 483 break; 484 } 485 case IrOpcode::kRoundFloat64ToInt32: { 486 Float64Matcher m(node->InputAt(0)); 487 if (m.HasValue()) return ReplaceInt32(static_cast<int32_t>(m.Value())); 488 if (m.IsChangeInt32ToFloat64()) return Replace(m.node()->InputAt(0)); 489 break; 490 } 491 case IrOpcode::kFloat64InsertLowWord32: 492 return ReduceFloat64InsertLowWord32(node); 493 case IrOpcode::kFloat64InsertHighWord32: 494 return ReduceFloat64InsertHighWord32(node); 495 case IrOpcode::kStore: 496 case IrOpcode::kCheckedStore: 497 return ReduceStore(node); 498 case IrOpcode::kFloat64Equal: 499 case IrOpcode::kFloat64LessThan: 500 case IrOpcode::kFloat64LessThanOrEqual: 501 return ReduceFloat64Compare(node); 502 default: 503 break; 504 } 505 return NoChange(); 506 } 507 508 509 Reduction MachineOperatorReducer::ReduceInt32Add(Node* node) { 510 DCHECK_EQ(IrOpcode::kInt32Add, node->opcode()); 511 Int32BinopMatcher m(node); 512 if (m.right().Is(0)) return Replace(m.left().node()); // x + 0 => x 513 if (m.IsFoldable()) { // K + K => K 514 return ReplaceUint32(bit_cast<uint32_t>(m.left().Value()) + 515 bit_cast<uint32_t>(m.right().Value())); 516 } 517 if (m.left().IsInt32Sub()) { 518 Int32BinopMatcher mleft(m.left().node()); 519 if (mleft.left().Is(0)) { // (0 - x) + y => y - x 520 node->ReplaceInput(0, m.right().node()); 521 node->ReplaceInput(1, mleft.right().node()); 522 NodeProperties::ChangeOp(node, machine()->Int32Sub()); 523 Reduction const reduction = ReduceInt32Sub(node); 524 return reduction.Changed() ? reduction : Changed(node); 525 } 526 } 527 if (m.right().IsInt32Sub()) { 528 Int32BinopMatcher mright(m.right().node()); 529 if (mright.left().Is(0)) { // y + (0 - x) => y - x 530 node->ReplaceInput(1, mright.right().node()); 531 NodeProperties::ChangeOp(node, machine()->Int32Sub()); 532 Reduction const reduction = ReduceInt32Sub(node); 533 return reduction.Changed() ? reduction : Changed(node); 534 } 535 } 536 return NoChange(); 537 } 538 539 540 Reduction MachineOperatorReducer::ReduceInt32Sub(Node* node) { 541 DCHECK_EQ(IrOpcode::kInt32Sub, node->opcode()); 542 Int32BinopMatcher m(node); 543 if (m.right().Is(0)) return Replace(m.left().node()); // x - 0 => x 544 if (m.IsFoldable()) { // K - K => K 545 return ReplaceInt32(static_cast<uint32_t>(m.left().Value()) - 546 static_cast<uint32_t>(m.right().Value())); 547 } 548 if (m.LeftEqualsRight()) return ReplaceInt32(0); // x - x => 0 549 if (m.right().HasValue()) { // x - K => x + -K 550 node->ReplaceInput(1, Int32Constant(-m.right().Value())); 551 NodeProperties::ChangeOp(node, machine()->Int32Add()); 552 Reduction const reduction = ReduceInt32Add(node); 553 return reduction.Changed() ? reduction : Changed(node); 554 } 555 return NoChange(); 556 } 557 558 559 Reduction MachineOperatorReducer::ReduceInt32Div(Node* node) { 560 Int32BinopMatcher m(node); 561 if (m.left().Is(0)) return Replace(m.left().node()); // 0 / x => 0 562 if (m.right().Is(0)) return Replace(m.right().node()); // x / 0 => 0 563 if (m.right().Is(1)) return Replace(m.left().node()); // x / 1 => x 564 if (m.IsFoldable()) { // K / K => K 565 return ReplaceInt32( 566 base::bits::SignedDiv32(m.left().Value(), m.right().Value())); 567 } 568 if (m.LeftEqualsRight()) { // x / x => x != 0 569 Node* const zero = Int32Constant(0); 570 return Replace(Word32Equal(Word32Equal(m.left().node(), zero), zero)); 571 } 572 if (m.right().Is(-1)) { // x / -1 => 0 - x 573 node->ReplaceInput(0, Int32Constant(0)); 574 node->ReplaceInput(1, m.left().node()); 575 node->TrimInputCount(2); 576 NodeProperties::ChangeOp(node, machine()->Int32Sub()); 577 return Changed(node); 578 } 579 if (m.right().HasValue()) { 580 int32_t const divisor = m.right().Value(); 581 Node* const dividend = m.left().node(); 582 Node* quotient = dividend; 583 if (base::bits::IsPowerOfTwo32(Abs(divisor))) { 584 uint32_t const shift = WhichPowerOf2Abs(divisor); 585 DCHECK_NE(0u, shift); 586 if (shift > 1) { 587 quotient = Word32Sar(quotient, 31); 588 } 589 quotient = Int32Add(Word32Shr(quotient, 32u - shift), dividend); 590 quotient = Word32Sar(quotient, shift); 591 } else { 592 quotient = Int32Div(quotient, Abs(divisor)); 593 } 594 if (divisor < 0) { 595 node->ReplaceInput(0, Int32Constant(0)); 596 node->ReplaceInput(1, quotient); 597 node->TrimInputCount(2); 598 NodeProperties::ChangeOp(node, machine()->Int32Sub()); 599 return Changed(node); 600 } 601 return Replace(quotient); 602 } 603 return NoChange(); 604 } 605 606 607 Reduction MachineOperatorReducer::ReduceUint32Div(Node* node) { 608 Uint32BinopMatcher m(node); 609 if (m.left().Is(0)) return Replace(m.left().node()); // 0 / x => 0 610 if (m.right().Is(0)) return Replace(m.right().node()); // x / 0 => 0 611 if (m.right().Is(1)) return Replace(m.left().node()); // x / 1 => x 612 if (m.IsFoldable()) { // K / K => K 613 return ReplaceUint32( 614 base::bits::UnsignedDiv32(m.left().Value(), m.right().Value())); 615 } 616 if (m.LeftEqualsRight()) { // x / x => x != 0 617 Node* const zero = Int32Constant(0); 618 return Replace(Word32Equal(Word32Equal(m.left().node(), zero), zero)); 619 } 620 if (m.right().HasValue()) { 621 Node* const dividend = m.left().node(); 622 uint32_t const divisor = m.right().Value(); 623 if (base::bits::IsPowerOfTwo32(divisor)) { // x / 2^n => x >> n 624 node->ReplaceInput(1, Uint32Constant(WhichPowerOf2(m.right().Value()))); 625 node->TrimInputCount(2); 626 NodeProperties::ChangeOp(node, machine()->Word32Shr()); 627 return Changed(node); 628 } else { 629 return Replace(Uint32Div(dividend, divisor)); 630 } 631 } 632 return NoChange(); 633 } 634 635 636 Reduction MachineOperatorReducer::ReduceInt32Mod(Node* node) { 637 Int32BinopMatcher m(node); 638 if (m.left().Is(0)) return Replace(m.left().node()); // 0 % x => 0 639 if (m.right().Is(0)) return Replace(m.right().node()); // x % 0 => 0 640 if (m.right().Is(1)) return ReplaceInt32(0); // x % 1 => 0 641 if (m.right().Is(-1)) return ReplaceInt32(0); // x % -1 => 0 642 if (m.LeftEqualsRight()) return ReplaceInt32(0); // x % x => 0 643 if (m.IsFoldable()) { // K % K => K 644 return ReplaceInt32( 645 base::bits::SignedMod32(m.left().Value(), m.right().Value())); 646 } 647 if (m.right().HasValue()) { 648 Node* const dividend = m.left().node(); 649 int32_t const divisor = Abs(m.right().Value()); 650 if (base::bits::IsPowerOfTwo32(divisor)) { 651 uint32_t const mask = divisor - 1; 652 Node* const zero = Int32Constant(0); 653 node->ReplaceInput( 654 0, graph()->NewNode(machine()->Int32LessThan(), dividend, zero)); 655 node->ReplaceInput( 656 1, Int32Sub(zero, Word32And(Int32Sub(zero, dividend), mask))); 657 node->ReplaceInput(2, Word32And(dividend, mask)); 658 NodeProperties::ChangeOp( 659 node, 660 common()->Select(MachineRepresentation::kWord32, BranchHint::kFalse)); 661 } else { 662 Node* quotient = Int32Div(dividend, divisor); 663 DCHECK_EQ(dividend, node->InputAt(0)); 664 node->ReplaceInput(1, Int32Mul(quotient, Int32Constant(divisor))); 665 node->TrimInputCount(2); 666 NodeProperties::ChangeOp(node, machine()->Int32Sub()); 667 } 668 return Changed(node); 669 } 670 return NoChange(); 671 } 672 673 674 Reduction MachineOperatorReducer::ReduceUint32Mod(Node* node) { 675 Uint32BinopMatcher m(node); 676 if (m.left().Is(0)) return Replace(m.left().node()); // 0 % x => 0 677 if (m.right().Is(0)) return Replace(m.right().node()); // x % 0 => 0 678 if (m.right().Is(1)) return ReplaceUint32(0); // x % 1 => 0 679 if (m.LeftEqualsRight()) return ReplaceInt32(0); // x % x => 0 680 if (m.IsFoldable()) { // K % K => K 681 return ReplaceUint32( 682 base::bits::UnsignedMod32(m.left().Value(), m.right().Value())); 683 } 684 if (m.right().HasValue()) { 685 Node* const dividend = m.left().node(); 686 uint32_t const divisor = m.right().Value(); 687 if (base::bits::IsPowerOfTwo32(divisor)) { // x % 2^n => x & 2^n-1 688 node->ReplaceInput(1, Uint32Constant(m.right().Value() - 1)); 689 node->TrimInputCount(2); 690 NodeProperties::ChangeOp(node, machine()->Word32And()); 691 } else { 692 Node* quotient = Uint32Div(dividend, divisor); 693 DCHECK_EQ(dividend, node->InputAt(0)); 694 node->ReplaceInput(1, Int32Mul(quotient, Uint32Constant(divisor))); 695 node->TrimInputCount(2); 696 NodeProperties::ChangeOp(node, machine()->Int32Sub()); 697 } 698 return Changed(node); 699 } 700 return NoChange(); 701 } 702 703 704 Reduction MachineOperatorReducer::ReduceStore(Node* node) { 705 NodeMatcher nm(node); 706 MachineRepresentation rep; 707 int value_input; 708 if (nm.IsCheckedStore()) { 709 rep = CheckedStoreRepresentationOf(node->op()); 710 value_input = 3; 711 } else { 712 rep = StoreRepresentationOf(node->op()).representation(); 713 value_input = 2; 714 } 715 716 Node* const value = node->InputAt(value_input); 717 718 switch (value->opcode()) { 719 case IrOpcode::kWord32And: { 720 Uint32BinopMatcher m(value); 721 if (m.right().HasValue() && ((rep == MachineRepresentation::kWord8 && 722 (m.right().Value() & 0xff) == 0xff) || 723 (rep == MachineRepresentation::kWord16 && 724 (m.right().Value() & 0xffff) == 0xffff))) { 725 node->ReplaceInput(value_input, m.left().node()); 726 return Changed(node); 727 } 728 break; 729 } 730 case IrOpcode::kWord32Sar: { 731 Int32BinopMatcher m(value); 732 if (m.left().IsWord32Shl() && ((rep == MachineRepresentation::kWord8 && 733 m.right().IsInRange(1, 24)) || 734 (rep == MachineRepresentation::kWord16 && 735 m.right().IsInRange(1, 16)))) { 736 Int32BinopMatcher mleft(m.left().node()); 737 if (mleft.right().Is(m.right().Value())) { 738 node->ReplaceInput(value_input, mleft.left().node()); 739 return Changed(node); 740 } 741 } 742 break; 743 } 744 default: 745 break; 746 } 747 return NoChange(); 748 } 749 750 751 Reduction MachineOperatorReducer::ReduceProjection(size_t index, Node* node) { 752 switch (node->opcode()) { 753 case IrOpcode::kInt32AddWithOverflow: { 754 DCHECK(index == 0 || index == 1); 755 Int32BinopMatcher m(node); 756 if (m.IsFoldable()) { 757 int32_t val; 758 bool ovf = base::bits::SignedAddOverflow32(m.left().Value(), 759 m.right().Value(), &val); 760 return ReplaceInt32((index == 0) ? val : ovf); 761 } 762 if (m.right().Is(0)) { 763 return (index == 0) ? Replace(m.left().node()) : ReplaceInt32(0); 764 } 765 break; 766 } 767 case IrOpcode::kInt32SubWithOverflow: { 768 DCHECK(index == 0 || index == 1); 769 Int32BinopMatcher m(node); 770 if (m.IsFoldable()) { 771 int32_t val; 772 bool ovf = base::bits::SignedSubOverflow32(m.left().Value(), 773 m.right().Value(), &val); 774 return ReplaceInt32((index == 0) ? val : ovf); 775 } 776 if (m.right().Is(0)) { 777 return (index == 0) ? Replace(m.left().node()) : ReplaceInt32(0); 778 } 779 break; 780 } 781 default: 782 break; 783 } 784 return NoChange(); 785 } 786 787 788 Reduction MachineOperatorReducer::ReduceWord32Shifts(Node* node) { 789 DCHECK((node->opcode() == IrOpcode::kWord32Shl) || 790 (node->opcode() == IrOpcode::kWord32Shr) || 791 (node->opcode() == IrOpcode::kWord32Sar)); 792 if (machine()->Word32ShiftIsSafe()) { 793 // Remove the explicit 'and' with 0x1f if the shift provided by the machine 794 // instruction matches that required by JavaScript. 795 Int32BinopMatcher m(node); 796 if (m.right().IsWord32And()) { 797 Int32BinopMatcher mright(m.right().node()); 798 if (mright.right().Is(0x1f)) { 799 node->ReplaceInput(1, mright.left().node()); 800 return Changed(node); 801 } 802 } 803 } 804 return NoChange(); 805 } 806 807 808 Reduction MachineOperatorReducer::ReduceWord32Shl(Node* node) { 809 DCHECK_EQ(IrOpcode::kWord32Shl, node->opcode()); 810 Int32BinopMatcher m(node); 811 if (m.right().Is(0)) return Replace(m.left().node()); // x << 0 => x 812 if (m.IsFoldable()) { // K << K => K 813 return ReplaceInt32(m.left().Value() << m.right().Value()); 814 } 815 if (m.right().IsInRange(1, 31)) { 816 // (x >>> K) << K => x & ~(2^K - 1) 817 // (x >> K) << K => x & ~(2^K - 1) 818 if (m.left().IsWord32Sar() || m.left().IsWord32Shr()) { 819 Int32BinopMatcher mleft(m.left().node()); 820 if (mleft.right().Is(m.right().Value())) { 821 node->ReplaceInput(0, mleft.left().node()); 822 node->ReplaceInput(1, 823 Uint32Constant(~((1U << m.right().Value()) - 1U))); 824 NodeProperties::ChangeOp(node, machine()->Word32And()); 825 Reduction reduction = ReduceWord32And(node); 826 return reduction.Changed() ? reduction : Changed(node); 827 } 828 } 829 } 830 return ReduceWord32Shifts(node); 831 } 832 833 Reduction MachineOperatorReducer::ReduceWord32Shr(Node* node) { 834 Uint32BinopMatcher m(node); 835 if (m.right().Is(0)) return Replace(m.left().node()); // x >>> 0 => x 836 if (m.IsFoldable()) { // K >>> K => K 837 return ReplaceInt32(m.left().Value() >> m.right().Value()); 838 } 839 if (m.left().IsWord32And() && m.right().HasValue()) { 840 Uint32BinopMatcher mleft(m.left().node()); 841 if (mleft.right().HasValue()) { 842 uint32_t shift = m.right().Value() & 0x1f; 843 uint32_t mask = mleft.right().Value(); 844 if ((mask >> shift) == 0) { 845 // (m >>> s) == 0 implies ((x & m) >>> s) == 0 846 return ReplaceInt32(0); 847 } 848 } 849 } 850 return ReduceWord32Shifts(node); 851 } 852 853 Reduction MachineOperatorReducer::ReduceWord32Sar(Node* node) { 854 Int32BinopMatcher m(node); 855 if (m.right().Is(0)) return Replace(m.left().node()); // x >> 0 => x 856 if (m.IsFoldable()) { // K >> K => K 857 return ReplaceInt32(m.left().Value() >> m.right().Value()); 858 } 859 if (m.left().IsWord32Shl()) { 860 Int32BinopMatcher mleft(m.left().node()); 861 if (mleft.left().IsComparison()) { 862 if (m.right().Is(31) && mleft.right().Is(31)) { 863 // Comparison << 31 >> 31 => 0 - Comparison 864 node->ReplaceInput(0, Int32Constant(0)); 865 node->ReplaceInput(1, mleft.left().node()); 866 NodeProperties::ChangeOp(node, machine()->Int32Sub()); 867 Reduction const reduction = ReduceInt32Sub(node); 868 return reduction.Changed() ? reduction : Changed(node); 869 } 870 } else if (mleft.left().IsLoad()) { 871 LoadRepresentation const rep = 872 LoadRepresentationOf(mleft.left().node()->op()); 873 if (m.right().Is(24) && mleft.right().Is(24) && 874 rep == MachineType::Int8()) { 875 // Load[kMachInt8] << 24 >> 24 => Load[kMachInt8] 876 return Replace(mleft.left().node()); 877 } 878 if (m.right().Is(16) && mleft.right().Is(16) && 879 rep == MachineType::Int16()) { 880 // Load[kMachInt16] << 16 >> 16 => Load[kMachInt8] 881 return Replace(mleft.left().node()); 882 } 883 } 884 } 885 return ReduceWord32Shifts(node); 886 } 887 888 889 Reduction MachineOperatorReducer::ReduceWord32And(Node* node) { 890 DCHECK_EQ(IrOpcode::kWord32And, node->opcode()); 891 Int32BinopMatcher m(node); 892 if (m.right().Is(0)) return Replace(m.right().node()); // x & 0 => 0 893 if (m.right().Is(-1)) return Replace(m.left().node()); // x & -1 => x 894 if (m.left().IsComparison() && m.right().Is(1)) { // CMP & 1 => CMP 895 return Replace(m.left().node()); 896 } 897 if (m.IsFoldable()) { // K & K => K 898 return ReplaceInt32(m.left().Value() & m.right().Value()); 899 } 900 if (m.LeftEqualsRight()) return Replace(m.left().node()); // x & x => x 901 if (m.left().IsWord32And() && m.right().HasValue()) { 902 Int32BinopMatcher mleft(m.left().node()); 903 if (mleft.right().HasValue()) { // (x & K) & K => x & K 904 node->ReplaceInput(0, mleft.left().node()); 905 node->ReplaceInput( 906 1, Int32Constant(m.right().Value() & mleft.right().Value())); 907 Reduction const reduction = ReduceWord32And(node); 908 return reduction.Changed() ? reduction : Changed(node); 909 } 910 } 911 if (m.right().IsNegativePowerOf2()) { 912 int32_t const mask = m.right().Value(); 913 if (m.left().IsWord32Shl()) { 914 Uint32BinopMatcher mleft(m.left().node()); 915 if (mleft.right().HasValue() && 916 mleft.right().Value() >= base::bits::CountTrailingZeros32(mask)) { 917 // (x << L) & (-1 << K) => x << L iff K >= L 918 return Replace(mleft.node()); 919 } 920 } else if (m.left().IsInt32Add()) { 921 Int32BinopMatcher mleft(m.left().node()); 922 if (mleft.right().HasValue() && 923 (mleft.right().Value() & mask) == mleft.right().Value()) { 924 // (x + (K << L)) & (-1 << L) => (x & (-1 << L)) + (K << L) 925 node->ReplaceInput(0, Word32And(mleft.left().node(), m.right().node())); 926 node->ReplaceInput(1, mleft.right().node()); 927 NodeProperties::ChangeOp(node, machine()->Int32Add()); 928 Reduction const reduction = ReduceInt32Add(node); 929 return reduction.Changed() ? reduction : Changed(node); 930 } 931 if (mleft.left().IsInt32Mul()) { 932 Int32BinopMatcher mleftleft(mleft.left().node()); 933 if (mleftleft.right().IsMultipleOf(-mask)) { 934 // (y * (K << L) + x) & (-1 << L) => (x & (-1 << L)) + y * (K << L) 935 node->ReplaceInput(0, 936 Word32And(mleft.right().node(), m.right().node())); 937 node->ReplaceInput(1, mleftleft.node()); 938 NodeProperties::ChangeOp(node, machine()->Int32Add()); 939 Reduction const reduction = ReduceInt32Add(node); 940 return reduction.Changed() ? reduction : Changed(node); 941 } 942 } 943 if (mleft.right().IsInt32Mul()) { 944 Int32BinopMatcher mleftright(mleft.right().node()); 945 if (mleftright.right().IsMultipleOf(-mask)) { 946 // (x + y * (K << L)) & (-1 << L) => (x & (-1 << L)) + y * (K << L) 947 node->ReplaceInput(0, 948 Word32And(mleft.left().node(), m.right().node())); 949 node->ReplaceInput(1, mleftright.node()); 950 NodeProperties::ChangeOp(node, machine()->Int32Add()); 951 Reduction const reduction = ReduceInt32Add(node); 952 return reduction.Changed() ? reduction : Changed(node); 953 } 954 } 955 if (mleft.left().IsWord32Shl()) { 956 Int32BinopMatcher mleftleft(mleft.left().node()); 957 if (mleftleft.right().Is(base::bits::CountTrailingZeros32(mask))) { 958 // (y << L + x) & (-1 << L) => (x & (-1 << L)) + y << L 959 node->ReplaceInput(0, 960 Word32And(mleft.right().node(), m.right().node())); 961 node->ReplaceInput(1, mleftleft.node()); 962 NodeProperties::ChangeOp(node, machine()->Int32Add()); 963 Reduction const reduction = ReduceInt32Add(node); 964 return reduction.Changed() ? reduction : Changed(node); 965 } 966 } 967 if (mleft.right().IsWord32Shl()) { 968 Int32BinopMatcher mleftright(mleft.right().node()); 969 if (mleftright.right().Is(base::bits::CountTrailingZeros32(mask))) { 970 // (x + y << L) & (-1 << L) => (x & (-1 << L)) + y << L 971 node->ReplaceInput(0, 972 Word32And(mleft.left().node(), m.right().node())); 973 node->ReplaceInput(1, mleftright.node()); 974 NodeProperties::ChangeOp(node, machine()->Int32Add()); 975 Reduction const reduction = ReduceInt32Add(node); 976 return reduction.Changed() ? reduction : Changed(node); 977 } 978 } 979 } else if (m.left().IsInt32Mul()) { 980 Int32BinopMatcher mleft(m.left().node()); 981 if (mleft.right().IsMultipleOf(-mask)) { 982 // (x * (K << L)) & (-1 << L) => x * (K << L) 983 return Replace(mleft.node()); 984 } 985 } 986 } 987 return NoChange(); 988 } 989 990 991 Reduction MachineOperatorReducer::ReduceWord32Or(Node* node) { 992 DCHECK_EQ(IrOpcode::kWord32Or, node->opcode()); 993 Int32BinopMatcher m(node); 994 if (m.right().Is(0)) return Replace(m.left().node()); // x | 0 => x 995 if (m.right().Is(-1)) return Replace(m.right().node()); // x | -1 => -1 996 if (m.IsFoldable()) { // K | K => K 997 return ReplaceInt32(m.left().Value() | m.right().Value()); 998 } 999 if (m.LeftEqualsRight()) return Replace(m.left().node()); // x | x => x 1000 1001 Node* shl = nullptr; 1002 Node* shr = nullptr; 1003 // Recognize rotation, we are matching either: 1004 // * x << y | x >>> (32 - y) => x ror (32 - y), i.e x rol y 1005 // * x << (32 - y) | x >>> y => x ror y 1006 // as well as their commuted form. 1007 if (m.left().IsWord32Shl() && m.right().IsWord32Shr()) { 1008 shl = m.left().node(); 1009 shr = m.right().node(); 1010 } else if (m.left().IsWord32Shr() && m.right().IsWord32Shl()) { 1011 shl = m.right().node(); 1012 shr = m.left().node(); 1013 } else { 1014 return NoChange(); 1015 } 1016 1017 Int32BinopMatcher mshl(shl); 1018 Int32BinopMatcher mshr(shr); 1019 if (mshl.left().node() != mshr.left().node()) return NoChange(); 1020 1021 if (mshl.right().HasValue() && mshr.right().HasValue()) { 1022 // Case where y is a constant. 1023 if (mshl.right().Value() + mshr.right().Value() != 32) return NoChange(); 1024 } else { 1025 Node* sub = nullptr; 1026 Node* y = nullptr; 1027 if (mshl.right().IsInt32Sub()) { 1028 sub = mshl.right().node(); 1029 y = mshr.right().node(); 1030 } else if (mshr.right().IsInt32Sub()) { 1031 sub = mshr.right().node(); 1032 y = mshl.right().node(); 1033 } else { 1034 return NoChange(); 1035 } 1036 1037 Int32BinopMatcher msub(sub); 1038 if (!msub.left().Is(32) || msub.right().node() != y) return NoChange(); 1039 } 1040 1041 node->ReplaceInput(0, mshl.left().node()); 1042 node->ReplaceInput(1, mshr.right().node()); 1043 NodeProperties::ChangeOp(node, machine()->Word32Ror()); 1044 return Changed(node); 1045 } 1046 1047 1048 Reduction MachineOperatorReducer::ReduceFloat64InsertLowWord32(Node* node) { 1049 DCHECK_EQ(IrOpcode::kFloat64InsertLowWord32, node->opcode()); 1050 Float64Matcher mlhs(node->InputAt(0)); 1051 Uint32Matcher mrhs(node->InputAt(1)); 1052 if (mlhs.HasValue() && mrhs.HasValue()) { 1053 return ReplaceFloat64(bit_cast<double>( 1054 (bit_cast<uint64_t>(mlhs.Value()) & V8_UINT64_C(0xFFFFFFFF00000000)) | 1055 mrhs.Value())); 1056 } 1057 return NoChange(); 1058 } 1059 1060 1061 Reduction MachineOperatorReducer::ReduceFloat64InsertHighWord32(Node* node) { 1062 DCHECK_EQ(IrOpcode::kFloat64InsertHighWord32, node->opcode()); 1063 Float64Matcher mlhs(node->InputAt(0)); 1064 Uint32Matcher mrhs(node->InputAt(1)); 1065 if (mlhs.HasValue() && mrhs.HasValue()) { 1066 return ReplaceFloat64(bit_cast<double>( 1067 (bit_cast<uint64_t>(mlhs.Value()) & V8_UINT64_C(0xFFFFFFFF)) | 1068 (static_cast<uint64_t>(mrhs.Value()) << 32))); 1069 } 1070 return NoChange(); 1071 } 1072 1073 1074 namespace { 1075 1076 bool IsFloat64RepresentableAsFloat32(const Float64Matcher& m) { 1077 if (m.HasValue()) { 1078 double v = m.Value(); 1079 float fv = static_cast<float>(v); 1080 return static_cast<double>(fv) == v; 1081 } 1082 return false; 1083 } 1084 1085 } // namespace 1086 1087 1088 Reduction MachineOperatorReducer::ReduceFloat64Compare(Node* node) { 1089 DCHECK((IrOpcode::kFloat64Equal == node->opcode()) || 1090 (IrOpcode::kFloat64LessThan == node->opcode()) || 1091 (IrOpcode::kFloat64LessThanOrEqual == node->opcode())); 1092 // As all Float32 values have an exact representation in Float64, comparing 1093 // two Float64 values both converted from Float32 is equivalent to comparing 1094 // the original Float32s, so we can ignore the conversions. We can also reduce 1095 // comparisons of converted Float64 values against constants that can be 1096 // represented exactly as Float32. 1097 Float64BinopMatcher m(node); 1098 if ((m.left().IsChangeFloat32ToFloat64() && 1099 m.right().IsChangeFloat32ToFloat64()) || 1100 (m.left().IsChangeFloat32ToFloat64() && 1101 IsFloat64RepresentableAsFloat32(m.right())) || 1102 (IsFloat64RepresentableAsFloat32(m.left()) && 1103 m.right().IsChangeFloat32ToFloat64())) { 1104 switch (node->opcode()) { 1105 case IrOpcode::kFloat64Equal: 1106 NodeProperties::ChangeOp(node, machine()->Float32Equal()); 1107 break; 1108 case IrOpcode::kFloat64LessThan: 1109 NodeProperties::ChangeOp(node, machine()->Float32LessThan()); 1110 break; 1111 case IrOpcode::kFloat64LessThanOrEqual: 1112 NodeProperties::ChangeOp(node, machine()->Float32LessThanOrEqual()); 1113 break; 1114 default: 1115 return NoChange(); 1116 } 1117 node->ReplaceInput( 1118 0, m.left().HasValue() 1119 ? Float32Constant(static_cast<float>(m.left().Value())) 1120 : m.left().InputAt(0)); 1121 node->ReplaceInput( 1122 1, m.right().HasValue() 1123 ? Float32Constant(static_cast<float>(m.right().Value())) 1124 : m.right().InputAt(0)); 1125 return Changed(node); 1126 } 1127 return NoChange(); 1128 } 1129 1130 1131 CommonOperatorBuilder* MachineOperatorReducer::common() const { 1132 return jsgraph()->common(); 1133 } 1134 1135 1136 MachineOperatorBuilder* MachineOperatorReducer::machine() const { 1137 return jsgraph()->machine(); 1138 } 1139 1140 1141 Graph* MachineOperatorReducer::graph() const { return jsgraph()->graph(); } 1142 1143 } // namespace compiler 1144 } // namespace internal 1145 } // namespace v8 1146