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 |