| OLD | NEW |
| 1 // Copyright 2016 the V8 project authors. All rights reserved. | 1 // Copyright 2016 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "src/compiler/simd-scalar-lowering.h" | 5 #include "src/compiler/simd-scalar-lowering.h" |
| 6 #include "src/compiler/diamond.h" | 6 #include "src/compiler/diamond.h" |
| 7 #include "src/compiler/linkage.h" | 7 #include "src/compiler/linkage.h" |
| 8 #include "src/compiler/node-matchers.h" | 8 #include "src/compiler/node-matchers.h" |
| 9 #include "src/compiler/node-properties.h" | 9 #include "src/compiler/node-properties.h" |
| 10 | 10 |
| 11 #include "src/compiler/node.h" | 11 #include "src/compiler/node.h" |
| 12 #include "src/objects-inl.h" | 12 #include "src/objects-inl.h" |
| 13 #include "src/wasm/wasm-module.h" | 13 #include "src/wasm/wasm-module.h" |
| 14 | 14 |
| 15 namespace v8 { | 15 namespace v8 { |
| 16 namespace internal { | 16 namespace internal { |
| 17 namespace compiler { | 17 namespace compiler { |
| 18 | 18 |
| 19 SimdScalarLowering::SimdScalarLowering( | 19 SimdScalarLowering::SimdScalarLowering( |
| 20 Graph* graph, MachineOperatorBuilder* machine, | 20 JSGraph* jsgraph, Signature<MachineRepresentation>* signature) |
| 21 CommonOperatorBuilder* common, Zone* zone, | 21 : jsgraph_(jsgraph), |
| 22 Signature<MachineRepresentation>* signature) | 22 state_(jsgraph->graph(), 3), |
| 23 : zone_(zone), | 23 stack_(jsgraph_->zone()), |
| 24 graph_(graph), | |
| 25 machine_(machine), | |
| 26 common_(common), | |
| 27 state_(graph, 3), | |
| 28 stack_(zone), | |
| 29 replacements_(nullptr), | 24 replacements_(nullptr), |
| 30 signature_(signature), | 25 signature_(signature), |
| 31 placeholder_( | 26 placeholder_(graph()->NewNode(common()->Parameter(-2, "placeholder"), |
| 32 graph->NewNode(common->Parameter(-2, "placeholder"), graph->start())), | 27 graph()->start())), |
| 33 parameter_count_after_lowering_(-1) { | 28 parameter_count_after_lowering_(-1) { |
| 34 DCHECK_NOT_NULL(graph); | 29 DCHECK_NOT_NULL(graph()); |
| 35 DCHECK_NOT_NULL(graph->end()); | 30 DCHECK_NOT_NULL(graph()->end()); |
| 36 replacements_ = zone->NewArray<Replacement>(graph->NodeCount()); | 31 replacements_ = zone()->NewArray<Replacement>(graph()->NodeCount()); |
| 37 memset(replacements_, 0, sizeof(Replacement) * graph->NodeCount()); | 32 memset(replacements_, 0, sizeof(Replacement) * graph()->NodeCount()); |
| 38 } | 33 } |
| 39 | 34 |
| 40 void SimdScalarLowering::LowerGraph() { | 35 void SimdScalarLowering::LowerGraph() { |
| 41 stack_.push_back({graph()->end(), 0}); | 36 stack_.push_back({graph()->end(), 0}); |
| 42 state_.Set(graph()->end(), State::kOnStack); | 37 state_.Set(graph()->end(), State::kOnStack); |
| 43 replacements_[graph()->end()->id()].type = SimdType::kInt32; | 38 replacements_[graph()->end()->id()].type = SimdType::kInt32; |
| 44 | 39 |
| 45 while (!stack_.empty()) { | 40 while (!stack_.empty()) { |
| 46 NodeState& top = stack_.back(); | 41 NodeState& top = stack_.back(); |
| 47 if (top.input_index == top.node->InputCount()) { | 42 if (top.input_index == top.node->InputCount()) { |
| (...skipping 25 matching lines...) Expand all Loading... |
| 73 | 68 |
| 74 #define FOREACH_INT32X4_OPCODE(V) \ | 69 #define FOREACH_INT32X4_OPCODE(V) \ |
| 75 V(Int32x4Splat) \ | 70 V(Int32x4Splat) \ |
| 76 V(Int32x4ExtractLane) \ | 71 V(Int32x4ExtractLane) \ |
| 77 V(Int32x4ReplaceLane) \ | 72 V(Int32x4ReplaceLane) \ |
| 78 V(Int32x4Neg) \ | 73 V(Int32x4Neg) \ |
| 79 V(Simd128Not) \ | 74 V(Simd128Not) \ |
| 80 V(Int32x4Add) \ | 75 V(Int32x4Add) \ |
| 81 V(Int32x4Sub) \ | 76 V(Int32x4Sub) \ |
| 82 V(Int32x4Mul) \ | 77 V(Int32x4Mul) \ |
| 78 V(Int32x4Min) \ |
| 79 V(Int32x4Max) \ |
| 80 V(Uint32x4Min) \ |
| 81 V(Uint32x4Max) \ |
| 83 V(Simd128And) \ | 82 V(Simd128And) \ |
| 84 V(Simd128Or) \ | 83 V(Simd128Or) \ |
| 85 V(Simd128Xor) | 84 V(Simd128Xor) \ |
| 85 V(Int32x4FromFloat32x4) \ |
| 86 V(Uint32x4FromFloat32x4) |
| 86 | 87 |
| 87 #define FOREACH_FLOAT32X4_OPCODE(V) \ | 88 #define FOREACH_FLOAT32X4_OPCODE(V) \ |
| 88 V(Float32x4Splat) \ | 89 V(Float32x4Splat) \ |
| 89 V(Float32x4ExtractLane) \ | 90 V(Float32x4ExtractLane) \ |
| 90 V(Float32x4ReplaceLane) \ | 91 V(Float32x4ReplaceLane) \ |
| 91 V(Float32x4Abs) \ | 92 V(Float32x4Abs) \ |
| 92 V(Float32x4Neg) \ | 93 V(Float32x4Neg) \ |
| 93 V(Float32x4Add) \ | 94 V(Float32x4Add) \ |
| 94 V(Float32x4Sub) \ | 95 V(Float32x4Sub) \ |
| 95 V(Float32x4Mul) \ | 96 V(Float32x4Mul) \ |
| (...skipping 12 matching lines...) Expand all Loading... |
| 108 case IrOpcode::kCall: { | 109 case IrOpcode::kCall: { |
| 109 replacements_[node->id()].type = SimdType::kInt32; | 110 replacements_[node->id()].type = SimdType::kInt32; |
| 110 break; | 111 break; |
| 111 } | 112 } |
| 112 FOREACH_FLOAT32X4_OPCODE(CASE_STMT) { | 113 FOREACH_FLOAT32X4_OPCODE(CASE_STMT) { |
| 113 replacements_[node->id()].type = SimdType::kFloat32; | 114 replacements_[node->id()].type = SimdType::kFloat32; |
| 114 break; | 115 break; |
| 115 } | 116 } |
| 116 #undef CASE_STMT | 117 #undef CASE_STMT |
| 117 default: { | 118 default: { |
| 118 if (output->opcode() == IrOpcode::kFloat32x4FromInt32x4 || | 119 switch (output->opcode()) { |
| 119 output->opcode() == IrOpcode::kFloat32x4FromUint32x4) { | 120 case IrOpcode::kFloat32x4FromInt32x4: |
| 120 replacements_[node->id()].type = SimdType::kInt32; | 121 case IrOpcode::kFloat32x4FromUint32x4: { |
| 121 } else { | 122 replacements_[node->id()].type = SimdType::kInt32; |
| 122 replacements_[node->id()].type = replacements_[output->id()].type; | 123 break; |
| 124 } |
| 125 case IrOpcode::kInt32x4FromFloat32x4: |
| 126 case IrOpcode::kUint32x4FromFloat32x4: { |
| 127 replacements_[node->id()].type = SimdType::kFloat32; |
| 128 break; |
| 129 } |
| 130 default: { |
| 131 replacements_[node->id()].type = replacements_[output->id()].type; |
| 132 } |
| 123 } | 133 } |
| 124 } | 134 } |
| 125 } | 135 } |
| 126 } | 136 } |
| 127 | 137 |
| 128 static int GetParameterIndexAfterLowering( | 138 static int GetParameterIndexAfterLowering( |
| 129 Signature<MachineRepresentation>* signature, int old_index) { | 139 Signature<MachineRepresentation>* signature, int old_index) { |
| 130 // In function calls, the simd128 types are passed as 4 Int32 types. The | 140 // In function calls, the simd128 types are passed as 4 Int32 types. The |
| 131 // parameters are typecast to the types as needed for various operations. | 141 // parameters are typecast to the types as needed for various operations. |
| 132 int result = old_index; | 142 int result = old_index; |
| (...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 257 const Operator* op) { | 267 const Operator* op) { |
| 258 DCHECK(node->InputCount() == 1); | 268 DCHECK(node->InputCount() == 1); |
| 259 Node** rep = GetReplacementsWithType(node->InputAt(0), input_rep_type); | 269 Node** rep = GetReplacementsWithType(node->InputAt(0), input_rep_type); |
| 260 Node* rep_node[kMaxLanes]; | 270 Node* rep_node[kMaxLanes]; |
| 261 for (int i = 0; i < kMaxLanes; ++i) { | 271 for (int i = 0; i < kMaxLanes; ++i) { |
| 262 rep_node[i] = graph()->NewNode(op, rep[i]); | 272 rep_node[i] = graph()->NewNode(op, rep[i]); |
| 263 } | 273 } |
| 264 ReplaceNode(node, rep_node); | 274 ReplaceNode(node, rep_node); |
| 265 } | 275 } |
| 266 | 276 |
| 277 void SimdScalarLowering::LowerIntMinMax(Node* node, const Operator* op, |
| 278 bool is_max) { |
| 279 DCHECK(node->InputCount() == 2); |
| 280 Node** rep_left = GetReplacementsWithType(node->InputAt(0), SimdType::kInt32); |
| 281 Node** rep_right = |
| 282 GetReplacementsWithType(node->InputAt(1), SimdType::kInt32); |
| 283 Node* rep_node[kMaxLanes]; |
| 284 for (int i = 0; i < kMaxLanes; ++i) { |
| 285 Diamond d(graph(), common(), |
| 286 graph()->NewNode(op, rep_left[i], rep_right[i])); |
| 287 if (is_max) { |
| 288 rep_node[i] = |
| 289 d.Phi(MachineRepresentation::kWord32, rep_right[i], rep_left[i]); |
| 290 } else { |
| 291 rep_node[i] = |
| 292 d.Phi(MachineRepresentation::kWord32, rep_left[i], rep_right[i]); |
| 293 } |
| 294 } |
| 295 ReplaceNode(node, rep_node); |
| 296 } |
| 297 |
| 298 Node* SimdScalarLowering::BuildF64Trunc(Node* input) { |
| 299 if (machine()->Float64RoundTruncate().IsSupported()) { |
| 300 return graph()->NewNode(machine()->Float64RoundTruncate().op(), input); |
| 301 } else { |
| 302 ExternalReference ref = |
| 303 ExternalReference::wasm_f64_trunc(jsgraph_->isolate()); |
| 304 Node* stack_slot = |
| 305 graph()->NewNode(machine()->StackSlot(MachineRepresentation::kFloat64)); |
| 306 const Operator* store_op = machine()->Store( |
| 307 StoreRepresentation(MachineRepresentation::kFloat64, kNoWriteBarrier)); |
| 308 Node* effect = |
| 309 graph()->NewNode(store_op, stack_slot, jsgraph_->Int32Constant(0), |
| 310 input, graph()->start(), graph()->start()); |
| 311 Node* function = graph()->NewNode(common()->ExternalConstant(ref)); |
| 312 Node** args = zone()->NewArray<Node*>(4); |
| 313 args[0] = function; |
| 314 args[1] = stack_slot; |
| 315 args[2] = effect; |
| 316 args[3] = graph()->start(); |
| 317 Signature<MachineType>::Builder sig_builder(zone(), 0, 1); |
| 318 sig_builder.AddParam(MachineType::Pointer()); |
| 319 CallDescriptor* desc = |
| 320 Linkage::GetSimplifiedCDescriptor(zone(), sig_builder.Build()); |
| 321 Node* call = graph()->NewNode(common()->Call(desc), 4, args); |
| 322 return graph()->NewNode(machine()->Load(LoadRepresentation::Float64()), |
| 323 stack_slot, jsgraph_->Int32Constant(0), call, |
| 324 graph()->start()); |
| 325 } |
| 326 } |
| 327 |
| 328 void SimdScalarLowering::LowerConvertFromFloat(Node* node, bool is_signed) { |
| 329 DCHECK(node->InputCount() == 1); |
| 330 Node** rep = GetReplacementsWithType(node->InputAt(0), SimdType::kFloat32); |
| 331 Node* rep_node[kMaxLanes]; |
| 332 Node* double_zero = graph()->NewNode(common()->Float64Constant(0.0)); |
| 333 Node* min = graph()->NewNode( |
| 334 common()->Float64Constant(static_cast<double>(is_signed ? kMinInt : 0))); |
| 335 Node* max = graph()->NewNode(common()->Float64Constant( |
| 336 static_cast<double>(is_signed ? kMaxInt : 0xffffffffu))); |
| 337 for (int i = 0; i < kMaxLanes; ++i) { |
| 338 Node* double_rep = |
| 339 graph()->NewNode(machine()->ChangeFloat32ToFloat64(), rep[i]); |
| 340 Diamond nan_d(graph(), common(), graph()->NewNode(machine()->Float64Equal(), |
| 341 double_rep, double_rep)); |
| 342 Node* temp = |
| 343 nan_d.Phi(MachineRepresentation::kFloat64, double_rep, double_zero); |
| 344 Diamond min_d(graph(), common(), |
| 345 graph()->NewNode(machine()->Float64LessThan(), temp, min)); |
| 346 temp = min_d.Phi(MachineRepresentation::kFloat64, min, temp); |
| 347 Diamond max_d(graph(), common(), |
| 348 graph()->NewNode(machine()->Float64LessThan(), max, temp)); |
| 349 temp = max_d.Phi(MachineRepresentation::kFloat64, max, temp); |
| 350 Node* trunc = BuildF64Trunc(temp); |
| 351 if (is_signed) { |
| 352 rep_node[i] = graph()->NewNode(machine()->ChangeFloat64ToInt32(), trunc); |
| 353 } else { |
| 354 rep_node[i] = |
| 355 graph()->NewNode(machine()->TruncateFloat64ToUint32(), trunc); |
| 356 } |
| 357 } |
| 358 ReplaceNode(node, rep_node); |
| 359 } |
| 360 |
| 361 void SimdScalarLowering::LowerShiftOp(Node* node, const Operator* op) { |
| 362 static int32_t shift_mask = 0x1f; |
| 363 DCHECK_EQ(1, node->InputCount()); |
| 364 int32_t shift_amount = OpParameter<int32_t>(node); |
| 365 Node* shift_node = |
| 366 graph()->NewNode(common()->Int32Constant(shift_amount & shift_mask)); |
| 367 Node** rep = GetReplacementsWithType(node->InputAt(0), SimdType::kInt32); |
| 368 Node* rep_node[kMaxLanes]; |
| 369 for (int i = 0; i < kMaxLanes; ++i) { |
| 370 rep_node[i] = graph()->NewNode(op, rep[i], shift_node); |
| 371 } |
| 372 ReplaceNode(node, rep_node); |
| 373 } |
| 374 |
| 267 void SimdScalarLowering::LowerNode(Node* node) { | 375 void SimdScalarLowering::LowerNode(Node* node) { |
| 268 SimdType rep_type = ReplacementType(node); | 376 SimdType rep_type = ReplacementType(node); |
| 269 switch (node->opcode()) { | 377 switch (node->opcode()) { |
| 270 case IrOpcode::kStart: { | 378 case IrOpcode::kStart: { |
| 271 int parameter_count = GetParameterCountAfterLowering(); | 379 int parameter_count = GetParameterCountAfterLowering(); |
| 272 // Only exchange the node if the parameter count actually changed. | 380 // Only exchange the node if the parameter count actually changed. |
| 273 if (parameter_count != static_cast<int>(signature()->parameter_count())) { | 381 if (parameter_count != static_cast<int>(signature()->parameter_count())) { |
| 274 int delta = | 382 int delta = |
| 275 parameter_count - static_cast<int>(signature()->parameter_count()); | 383 parameter_count - static_cast<int>(signature()->parameter_count()); |
| 276 int new_output_count = node->op()->ValueOutputCount() + delta; | 384 int new_output_count = node->op()->ValueOutputCount() + delta; |
| (...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 415 LowerBinaryOp(node, rep_type, machine()->instruction()); \ | 523 LowerBinaryOp(node, rep_type, machine()->instruction()); \ |
| 416 break; \ | 524 break; \ |
| 417 } | 525 } |
| 418 I32X4_BINOP_CASE(kInt32x4Add, Int32Add) | 526 I32X4_BINOP_CASE(kInt32x4Add, Int32Add) |
| 419 I32X4_BINOP_CASE(kInt32x4Sub, Int32Sub) | 527 I32X4_BINOP_CASE(kInt32x4Sub, Int32Sub) |
| 420 I32X4_BINOP_CASE(kInt32x4Mul, Int32Mul) | 528 I32X4_BINOP_CASE(kInt32x4Mul, Int32Mul) |
| 421 I32X4_BINOP_CASE(kSimd128And, Word32And) | 529 I32X4_BINOP_CASE(kSimd128And, Word32And) |
| 422 I32X4_BINOP_CASE(kSimd128Or, Word32Or) | 530 I32X4_BINOP_CASE(kSimd128Or, Word32Or) |
| 423 I32X4_BINOP_CASE(kSimd128Xor, Word32Xor) | 531 I32X4_BINOP_CASE(kSimd128Xor, Word32Xor) |
| 424 #undef I32X4_BINOP_CASE | 532 #undef I32X4_BINOP_CASE |
| 533 case IrOpcode::kInt32x4Max: { |
| 534 LowerIntMinMax(node, machine()->Int32LessThan(), true); |
| 535 break; |
| 536 } |
| 537 case IrOpcode::kInt32x4Min: { |
| 538 LowerIntMinMax(node, machine()->Int32LessThan(), false); |
| 539 break; |
| 540 } |
| 541 case IrOpcode::kUint32x4Max: { |
| 542 LowerIntMinMax(node, machine()->Uint32LessThan(), true); |
| 543 break; |
| 544 } |
| 545 case IrOpcode::kUint32x4Min: { |
| 546 LowerIntMinMax(node, machine()->Uint32LessThan(), false); |
| 547 break; |
| 548 } |
| 425 case IrOpcode::kInt32x4Neg: { | 549 case IrOpcode::kInt32x4Neg: { |
| 426 DCHECK(node->InputCount() == 1); | 550 DCHECK(node->InputCount() == 1); |
| 427 Node** rep = GetReplacementsWithType(node->InputAt(0), rep_type); | 551 Node** rep = GetReplacementsWithType(node->InputAt(0), rep_type); |
| 428 Node* rep_node[kMaxLanes]; | 552 Node* rep_node[kMaxLanes]; |
| 429 Node* zero = graph()->NewNode(common()->Int32Constant(0)); | 553 Node* zero = graph()->NewNode(common()->Int32Constant(0)); |
| 430 for (int i = 0; i < kMaxLanes; ++i) { | 554 for (int i = 0; i < kMaxLanes; ++i) { |
| 431 rep_node[i] = graph()->NewNode(machine()->Int32Sub(), zero, rep[i]); | 555 rep_node[i] = graph()->NewNode(machine()->Int32Sub(), zero, rep[i]); |
| 432 } | 556 } |
| 433 ReplaceNode(node, rep_node); | 557 ReplaceNode(node, rep_node); |
| 434 break; | 558 break; |
| 435 } | 559 } |
| 436 case IrOpcode::kSimd128Not: { | 560 case IrOpcode::kSimd128Not: { |
| 437 DCHECK(node->InputCount() == 1); | 561 DCHECK(node->InputCount() == 1); |
| 438 Node** rep = GetReplacementsWithType(node->InputAt(0), rep_type); | 562 Node** rep = GetReplacementsWithType(node->InputAt(0), rep_type); |
| 439 Node* rep_node[kMaxLanes]; | 563 Node* rep_node[kMaxLanes]; |
| 440 Node* mask = graph()->NewNode(common()->Int32Constant(0xffffffff)); | 564 Node* mask = graph()->NewNode(common()->Int32Constant(0xffffffff)); |
| 441 for (int i = 0; i < kMaxLanes; ++i) { | 565 for (int i = 0; i < kMaxLanes; ++i) { |
| 442 rep_node[i] = graph()->NewNode(machine()->Word32Xor(), rep[i], mask); | 566 rep_node[i] = graph()->NewNode(machine()->Word32Xor(), rep[i], mask); |
| 443 } | 567 } |
| 444 ReplaceNode(node, rep_node); | 568 ReplaceNode(node, rep_node); |
| 445 break; | 569 break; |
| 446 } | 570 } |
| 571 case IrOpcode::kInt32x4FromFloat32x4: { |
| 572 LowerConvertFromFloat(node, true); |
| 573 break; |
| 574 } |
| 575 case IrOpcode::kUint32x4FromFloat32x4: { |
| 576 LowerConvertFromFloat(node, false); |
| 577 break; |
| 578 } |
| 579 case IrOpcode::kInt32x4ShiftLeftByScalar: { |
| 580 LowerShiftOp(node, machine()->Word32Shl()); |
| 581 break; |
| 582 } |
| 583 case IrOpcode::kInt32x4ShiftRightByScalar: { |
| 584 LowerShiftOp(node, machine()->Word32Sar()); |
| 585 break; |
| 586 } |
| 587 case IrOpcode::kUint32x4ShiftRightByScalar: { |
| 588 LowerShiftOp(node, machine()->Word32Shr()); |
| 589 break; |
| 590 } |
| 447 #define F32X4_BINOP_CASE(name) \ | 591 #define F32X4_BINOP_CASE(name) \ |
| 448 case IrOpcode::kFloat32x4##name: { \ | 592 case IrOpcode::kFloat32x4##name: { \ |
| 449 LowerBinaryOp(node, rep_type, machine()->Float32##name()); \ | 593 LowerBinaryOp(node, rep_type, machine()->Float32##name()); \ |
| 450 break; \ | 594 break; \ |
| 451 } | 595 } |
| 452 F32X4_BINOP_CASE(Add) | 596 F32X4_BINOP_CASE(Add) |
| 453 F32X4_BINOP_CASE(Sub) | 597 F32X4_BINOP_CASE(Sub) |
| 454 F32X4_BINOP_CASE(Mul) | 598 F32X4_BINOP_CASE(Mul) |
| 455 F32X4_BINOP_CASE(Div) | 599 F32X4_BINOP_CASE(Div) |
| 456 F32X4_BINOP_CASE(Min) | 600 F32X4_BINOP_CASE(Min) |
| (...skipping 159 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 616 } else { | 760 } else { |
| 617 UNREACHABLE(); | 761 UNREACHABLE(); |
| 618 } | 762 } |
| 619 } | 763 } |
| 620 ReplaceNode(phi, rep_nodes); | 764 ReplaceNode(phi, rep_nodes); |
| 621 } | 765 } |
| 622 } | 766 } |
| 623 } // namespace compiler | 767 } // namespace compiler |
| 624 } // namespace internal | 768 } // namespace internal |
| 625 } // namespace v8 | 769 } // namespace v8 |
| OLD | NEW |