Line data Source code
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
3 : // found in the LICENSE file.
4 :
5 : #include "src/compiler/simd-scalar-lowering.h"
6 :
7 : #include "src/compiler/diamond.h"
8 : #include "src/compiler/linkage.h"
9 : #include "src/compiler/node-matchers.h"
10 : #include "src/compiler/node-properties.h"
11 : #include "src/compiler/node.h"
12 : #include "src/compiler/wasm-compiler.h"
13 :
14 : namespace v8 {
15 : namespace internal {
16 : namespace compiler {
17 :
18 : namespace {
19 : static const int kNumLanes32 = 4;
20 : static const int kNumLanes16 = 8;
21 : static const int kNumLanes8 = 16;
22 : static const int32_t kMask16 = 0xffff;
23 : static const int32_t kMask8 = 0xff;
24 : static const int32_t kShift16 = 16;
25 : static const int32_t kShift8 = 24;
26 : } // anonymous
27 :
28 492 : SimdScalarLowering::SimdScalarLowering(
29 2460 : JSGraph* jsgraph, Signature<MachineRepresentation>* signature)
30 : : jsgraph_(jsgraph),
31 : state_(jsgraph->graph(), 3),
32 : stack_(jsgraph_->zone()),
33 : replacements_(nullptr),
34 : signature_(signature),
35 : placeholder_(graph()->NewNode(common()->Parameter(-2, "placeholder"),
36 984 : graph()->start())),
37 1968 : parameter_count_after_lowering_(-1) {
38 : DCHECK_NOT_NULL(graph());
39 : DCHECK_NOT_NULL(graph()->end());
40 984 : replacements_ = zone()->NewArray<Replacement>(graph()->NodeCount());
41 984 : memset(replacements_, 0, sizeof(Replacement) * graph()->NodeCount());
42 492 : }
43 :
44 1476 : void SimdScalarLowering::LowerGraph() {
45 984 : stack_.push_back({graph()->end(), 0});
46 492 : state_.Set(graph()->end(), State::kOnStack);
47 1476 : replacements_[graph()->end()->id()].type = SimdType::kInt32x4;
48 :
49 145398 : while (!stack_.empty()) {
50 : NodeState& top = stack_.back();
51 288828 : if (top.input_index == top.node->InputCount()) {
52 : // All inputs of top have already been lowered, now lower top.
53 : stack_.pop_back();
54 49560 : state_.Set(top.node, State::kVisited);
55 49560 : LowerNode(top.node);
56 : } else {
57 : // Push the next input onto the stack.
58 143922 : Node* input = top.node->InputAt(top.input_index++);
59 94854 : if (state_.Get(input) == State::kUnvisited) {
60 49068 : SetLoweredType(input, top.node);
61 49068 : if (input->opcode() == IrOpcode::kPhi) {
62 : // To break cycles with phi nodes we push phis on a separate stack so
63 : // that they are processed after all other nodes.
64 60 : PreparePhiReplacement(input);
65 120 : stack_.push_front({input, 0});
66 49008 : } else if (input->opcode() == IrOpcode::kEffectPhi ||
67 : input->opcode() == IrOpcode::kLoop) {
68 24 : stack_.push_front({input, 0});
69 : } else {
70 97992 : stack_.push_back({input, 0});
71 : }
72 : state_.Set(input, State::kOnStack);
73 : }
74 : }
75 : }
76 492 : }
77 :
78 : #define FOREACH_INT32X4_OPCODE(V) \
79 : V(I32x4Splat) \
80 : V(I32x4ExtractLane) \
81 : V(I32x4ReplaceLane) \
82 : V(I32x4SConvertF32x4) \
83 : V(I32x4UConvertF32x4) \
84 : V(I32x4Neg) \
85 : V(I32x4Shl) \
86 : V(I32x4ShrS) \
87 : V(I32x4Add) \
88 : V(I32x4Sub) \
89 : V(I32x4Mul) \
90 : V(I32x4MinS) \
91 : V(I32x4MaxS) \
92 : V(I32x4ShrU) \
93 : V(I32x4MinU) \
94 : V(I32x4MaxU) \
95 : V(I32x4Eq) \
96 : V(I32x4Ne) \
97 : V(I32x4LtS) \
98 : V(I32x4LeS) \
99 : V(I32x4GtS) \
100 : V(I32x4GeS) \
101 : V(I32x4LtU) \
102 : V(I32x4LeU) \
103 : V(I32x4GtU) \
104 : V(I32x4GeU) \
105 : V(S128And) \
106 : V(S128Or) \
107 : V(S128Xor) \
108 : V(S128Not)
109 :
110 : #define FOREACH_FLOAT32X4_OPCODE(V) \
111 : V(F32x4Splat) \
112 : V(F32x4ExtractLane) \
113 : V(F32x4ReplaceLane) \
114 : V(F32x4SConvertI32x4) \
115 : V(F32x4UConvertI32x4) \
116 : V(F32x4Abs) \
117 : V(F32x4Neg) \
118 : V(F32x4Add) \
119 : V(F32x4Sub) \
120 : V(F32x4Mul) \
121 : V(F32x4Min) \
122 : V(F32x4Max)
123 :
124 : #define FOREACH_FLOAT32X4_TO_INT32X4OPCODE(V) \
125 : V(F32x4Eq) \
126 : V(F32x4Ne) \
127 : V(F32x4Lt) \
128 : V(F32x4Le) \
129 : V(F32x4Gt) \
130 : V(F32x4Ge)
131 :
132 : #define FOREACH_INT16X8_OPCODE(V) \
133 : V(I16x8Splat) \
134 : V(I16x8ExtractLane) \
135 : V(I16x8ReplaceLane) \
136 : V(I16x8Neg) \
137 : V(I16x8Shl) \
138 : V(I16x8ShrS) \
139 : V(I16x8Add) \
140 : V(I16x8AddSaturateS) \
141 : V(I16x8Sub) \
142 : V(I16x8SubSaturateS) \
143 : V(I16x8Mul) \
144 : V(I16x8MinS) \
145 : V(I16x8MaxS) \
146 : V(I16x8ShrU) \
147 : V(I16x8AddSaturateU) \
148 : V(I16x8SubSaturateU) \
149 : V(I16x8MinU) \
150 : V(I16x8MaxU) \
151 : V(I16x8Eq) \
152 : V(I16x8Ne) \
153 : V(I16x8LtS) \
154 : V(I16x8LeS) \
155 : V(I16x8LtU) \
156 : V(I16x8LeU)
157 :
158 : #define FOREACH_INT8X16_OPCODE(V) \
159 : V(I8x16Splat) \
160 : V(I8x16ExtractLane) \
161 : V(I8x16ReplaceLane) \
162 : V(I8x16Neg) \
163 : V(I8x16Shl) \
164 : V(I8x16ShrS) \
165 : V(I8x16Add) \
166 : V(I8x16AddSaturateS) \
167 : V(I8x16Sub) \
168 : V(I8x16SubSaturateS) \
169 : V(I8x16Mul) \
170 : V(I8x16MinS) \
171 : V(I8x16MaxS) \
172 : V(I8x16ShrU) \
173 : V(I8x16AddSaturateU) \
174 : V(I8x16SubSaturateU) \
175 : V(I8x16MinU) \
176 : V(I8x16MaxU) \
177 : V(I8x16Eq) \
178 : V(I8x16Ne) \
179 : V(I8x16LtS) \
180 : V(I8x16LeS) \
181 : V(I8x16LtU) \
182 : V(I8x16LeU)
183 :
184 2766 : MachineType SimdScalarLowering::MachineTypeFrom(SimdType simdType) {
185 2766 : switch (simdType) {
186 : case SimdType::kFloat32x4:
187 : return MachineType::Float32();
188 : case SimdType::kInt32x4:
189 : return MachineType::Int32();
190 : case SimdType::kInt16x8:
191 : return MachineType::Int16();
192 : case SimdType::kInt8x16:
193 : return MachineType::Int8();
194 : }
195 : return MachineType::None();
196 : }
197 :
198 165024 : void SimdScalarLowering::SetLoweredType(Node* node, Node* output) {
199 49068 : switch (node->opcode()) {
200 : #define CASE_STMT(name) case IrOpcode::k##name:
201 : FOREACH_INT32X4_OPCODE(CASE_STMT)
202 : case IrOpcode::kReturn:
203 : case IrOpcode::kParameter:
204 : case IrOpcode::kCall: {
205 19044 : replacements_[node->id()].type = SimdType::kInt32x4;
206 9522 : break;
207 : }
208 : FOREACH_FLOAT32X4_OPCODE(CASE_STMT) {
209 0 : replacements_[node->id()].type = SimdType::kFloat32x4;
210 0 : break;
211 : }
212 : FOREACH_FLOAT32X4_TO_INT32X4OPCODE(CASE_STMT) {
213 0 : replacements_[node->id()].type = SimdType::kInt32x4;
214 0 : break;
215 : }
216 : FOREACH_INT16X8_OPCODE(CASE_STMT) {
217 4140 : replacements_[node->id()].type = SimdType::kInt16x8;
218 2070 : break;
219 : }
220 : FOREACH_INT8X16_OPCODE(CASE_STMT) {
221 8064 : replacements_[node->id()].type = SimdType::kInt8x16;
222 4032 : break;
223 : }
224 : default: {
225 33444 : switch (output->opcode()) {
226 : case IrOpcode::kF32x4SConvertI32x4:
227 : case IrOpcode::kF32x4UConvertI32x4: {
228 0 : replacements_[node->id()].type = SimdType::kInt32x4;
229 0 : break;
230 : }
231 : FOREACH_FLOAT32X4_TO_INT32X4OPCODE(CASE_STMT)
232 : case IrOpcode::kI32x4SConvertF32x4:
233 : case IrOpcode::kI32x4UConvertF32x4: {
234 0 : replacements_[node->id()].type = SimdType::kFloat32x4;
235 0 : break;
236 : }
237 : case IrOpcode::kS128Select: {
238 0 : replacements_[node->id()].type = SimdType::kInt32x4;
239 0 : break;
240 : }
241 : default: {
242 100332 : replacements_[node->id()].type = replacements_[output->id()].type;
243 : }
244 : }
245 : }
246 : #undef CASE_STMT
247 : }
248 49068 : }
249 :
250 : static int GetParameterIndexAfterLoweringSimd128(
251 1284 : Signature<MachineRepresentation>* signature, int old_index) {
252 : // In function calls, the simd128 types are passed as 4 Int32 types. The
253 : // parameters are typecast to the types as needed for various operations.
254 : int result = old_index;
255 1284 : for (int i = 0; i < old_index; ++i) {
256 2568 : if (signature->GetParam(i) == MachineRepresentation::kSimd128) {
257 0 : result += 3;
258 : }
259 : }
260 : return result;
261 : }
262 :
263 2748 : int SimdScalarLowering::GetParameterCountAfterLowering() {
264 2256 : if (parameter_count_after_lowering_ == -1) {
265 : // GetParameterIndexAfterLoweringSimd128(parameter_count) returns the
266 : // parameter count after lowering.
267 : parameter_count_after_lowering_ = GetParameterIndexAfterLoweringSimd128(
268 984 : signature(), static_cast<int>(signature()->parameter_count()));
269 : }
270 2256 : return parameter_count_after_lowering_;
271 : }
272 :
273 : static int GetReturnCountAfterLoweringSimd128(
274 12888 : Signature<MachineRepresentation>* signature) {
275 6444 : int result = static_cast<int>(signature->return_count());
276 6444 : for (int i = 0; i < static_cast<int>(signature->return_count()); ++i) {
277 12888 : if (signature->GetReturn(i) == MachineRepresentation::kSimd128) {
278 0 : result += 3;
279 : }
280 : }
281 : return result;
282 : }
283 :
284 50124 : int SimdScalarLowering::NumLanes(SimdType type) {
285 : int num_lanes = 0;
286 50124 : if (type == SimdType::kFloat32x4 || type == SimdType::kInt32x4) {
287 : num_lanes = kNumLanes32;
288 6474 : } else if (type == SimdType::kInt16x8) {
289 : num_lanes = kNumLanes16;
290 4206 : } else if (type == SimdType::kInt8x16) {
291 : num_lanes = kNumLanes8;
292 : } else {
293 0 : UNREACHABLE();
294 : }
295 50124 : return num_lanes;
296 : }
297 :
298 : constexpr int SimdScalarLowering::kLaneOffsets[];
299 :
300 66 : void SimdScalarLowering::GetIndexNodes(Node* index, Node** new_indices,
301 792 : SimdType type) {
302 66 : int num_lanes = NumLanes(type);
303 66 : int lane_width = kSimd128Size / num_lanes;
304 66 : int laneIndex = kLaneOffsets[0] / lane_width;
305 66 : new_indices[laneIndex] = index;
306 264 : for (int i = 1; i < num_lanes; ++i) {
307 198 : laneIndex = kLaneOffsets[i * lane_width] / lane_width;
308 198 : new_indices[laneIndex] = graph()->NewNode(
309 : machine()->Int32Add(), index,
310 : graph()->NewNode(
311 594 : common()->Int32Constant(static_cast<int>(i) * lane_width)));
312 : }
313 66 : }
314 :
315 1038 : void SimdScalarLowering::LowerLoadOp(MachineRepresentation rep, Node* node,
316 210 : const Operator* load_op, SimdType type) {
317 1038 : if (rep == MachineRepresentation::kSimd128) {
318 : Node* base = node->InputAt(0);
319 : Node* index = node->InputAt(1);
320 42 : int num_lanes = NumLanes(type);
321 42 : Node** indices = zone()->NewArray<Node*>(num_lanes);
322 42 : GetIndexNodes(index, indices, type);
323 : Node** rep_nodes = zone()->NewArray<Node*>(num_lanes);
324 42 : rep_nodes[0] = node;
325 42 : rep_nodes[0]->ReplaceInput(1, indices[0]);
326 42 : NodeProperties::ChangeOp(rep_nodes[0], load_op);
327 42 : if (node->InputCount() > 2) {
328 : DCHECK_LT(3, node->InputCount());
329 : Node* effect_input = node->InputAt(2);
330 : Node* control_input = node->InputAt(3);
331 168 : for (int i = num_lanes - 1; i > 0; --i) {
332 126 : rep_nodes[i] = graph()->NewNode(load_op, base, indices[i], effect_input,
333 252 : control_input);
334 : effect_input = rep_nodes[i];
335 : }
336 42 : rep_nodes[0]->ReplaceInput(2, rep_nodes[1]);
337 : } else {
338 0 : for (int i = 1; i < num_lanes; ++i) {
339 0 : rep_nodes[i] = graph()->NewNode(load_op, base, indices[i]);
340 : }
341 : }
342 42 : ReplaceNode(node, rep_nodes, num_lanes);
343 : } else {
344 996 : DefaultLowering(node);
345 : }
346 1038 : }
347 :
348 24 : void SimdScalarLowering::LowerStoreOp(MachineRepresentation rep, Node* node,
349 : const Operator* store_op,
350 120 : SimdType rep_type) {
351 24 : if (rep == MachineRepresentation::kSimd128) {
352 : Node* base = node->InputAt(0);
353 : Node* index = node->InputAt(1);
354 24 : int num_lanes = NumLanes(rep_type);
355 24 : Node** indices = zone()->NewArray<Node*>(num_lanes);
356 24 : GetIndexNodes(index, indices, rep_type);
357 : DCHECK_LT(2, node->InputCount());
358 : Node* value = node->InputAt(2);
359 : DCHECK(HasReplacement(1, value));
360 : Node** rep_nodes = zone()->NewArray<Node*>(num_lanes);
361 24 : rep_nodes[0] = node;
362 24 : Node** rep_inputs = GetReplacementsWithType(value, rep_type);
363 24 : rep_nodes[0]->ReplaceInput(2, rep_inputs[0]);
364 24 : rep_nodes[0]->ReplaceInput(1, indices[0]);
365 24 : NodeProperties::ChangeOp(node, store_op);
366 24 : if (node->InputCount() > 3) {
367 : DCHECK_LT(4, node->InputCount());
368 : Node* effect_input = node->InputAt(3);
369 : Node* control_input = node->InputAt(4);
370 96 : for (int i = num_lanes - 1; i > 0; --i) {
371 72 : rep_nodes[i] =
372 144 : graph()->NewNode(store_op, base, indices[i], rep_inputs[i],
373 216 : effect_input, control_input);
374 : effect_input = rep_nodes[i];
375 : }
376 24 : rep_nodes[0]->ReplaceInput(3, rep_nodes[1]);
377 : } else {
378 0 : for (int i = 1; i < num_lanes; ++i) {
379 0 : rep_nodes[i] =
380 0 : graph()->NewNode(store_op, base, indices[i], rep_inputs[i]);
381 : }
382 : }
383 24 : ReplaceNode(node, rep_nodes, num_lanes);
384 : } else {
385 0 : DefaultLowering(node);
386 : }
387 24 : }
388 :
389 42 : void SimdScalarLowering::LowerBinaryOp(Node* node, SimdType input_rep_type,
390 210 : const Operator* op) {
391 : DCHECK_EQ(2, node->InputCount());
392 42 : Node** rep_left = GetReplacementsWithType(node->InputAt(0), input_rep_type);
393 42 : Node** rep_right = GetReplacementsWithType(node->InputAt(1), input_rep_type);
394 42 : int num_lanes = NumLanes(input_rep_type);
395 42 : Node** rep_node = zone()->NewArray<Node*>(num_lanes);
396 210 : for (int i = 0; i < num_lanes; ++i) {
397 336 : rep_node[i] = graph()->NewNode(op, rep_left[i], rep_right[i]);
398 : }
399 42 : ReplaceNode(node, rep_node, num_lanes);
400 42 : }
401 :
402 162 : void SimdScalarLowering::LowerCompareOp(Node* node, SimdType input_rep_type,
403 : const Operator* op,
404 6210 : bool invert_inputs) {
405 : DCHECK_EQ(2, node->InputCount());
406 162 : Node** rep_left = GetReplacementsWithType(node->InputAt(0), input_rep_type);
407 162 : Node** rep_right = GetReplacementsWithType(node->InputAt(1), input_rep_type);
408 162 : int num_lanes = NumLanes(input_rep_type);
409 162 : Node** rep_node = zone()->NewArray<Node*>(num_lanes);
410 1674 : for (int i = 0; i < num_lanes; ++i) {
411 : Node* cmp_result = nullptr;
412 1512 : if (invert_inputs) {
413 1344 : cmp_result = graph()->NewNode(op, rep_right[i], rep_left[i]);
414 : } else {
415 168 : cmp_result = graph()->NewNode(op, rep_left[i], rep_right[i]);
416 : }
417 : Diamond d_cmp(graph(), common(),
418 : graph()->NewNode(machine()->Word32Equal(), cmp_result,
419 4536 : jsgraph_->Int32Constant(0)));
420 : MachineRepresentation rep =
421 : (input_rep_type == SimdType::kFloat32x4)
422 : ? MachineRepresentation::kWord32
423 1512 : : MachineTypeFrom(input_rep_type).representation();
424 1512 : rep_node[i] =
425 1512 : d_cmp.Phi(rep, jsgraph_->Int32Constant(0), jsgraph_->Int32Constant(-1));
426 : }
427 162 : ReplaceNode(node, rep_node, num_lanes);
428 162 : }
429 :
430 4080 : Node* SimdScalarLowering::FixUpperBits(Node* input, int32_t shift) {
431 : return graph()->NewNode(machine()->Word32Sar(),
432 : graph()->NewNode(machine()->Word32Shl(), input,
433 : jsgraph_->Int32Constant(shift)),
434 3264 : jsgraph_->Int32Constant(shift));
435 : }
436 :
437 30 : void SimdScalarLowering::LowerBinaryOpForSmallInt(Node* node,
438 : SimdType input_rep_type,
439 366 : const Operator* op) {
440 : DCHECK_EQ(2, node->InputCount());
441 : DCHECK(input_rep_type == SimdType::kInt16x8 ||
442 : input_rep_type == SimdType::kInt8x16);
443 30 : Node** rep_left = GetReplacementsWithType(node->InputAt(0), input_rep_type);
444 30 : Node** rep_right = GetReplacementsWithType(node->InputAt(1), input_rep_type);
445 30 : int num_lanes = NumLanes(input_rep_type);
446 30 : Node** rep_node = zone()->NewArray<Node*>(num_lanes);
447 : int32_t shift_val =
448 30 : (input_rep_type == SimdType::kInt16x8) ? kShift16 : kShift8;
449 366 : for (int i = 0; i < num_lanes; ++i) {
450 672 : rep_node[i] = FixUpperBits(graph()->NewNode(op, rep_left[i], rep_right[i]),
451 1008 : shift_val);
452 : }
453 30 : ReplaceNode(node, rep_node, num_lanes);
454 30 : }
455 :
456 1872 : Node* SimdScalarLowering::Mask(Node* input, int32_t mask) {
457 : return graph()->NewNode(machine()->Word32And(), input,
458 1872 : jsgraph_->Int32Constant(mask));
459 : }
460 :
461 48 : void SimdScalarLowering::LowerSaturateBinaryOp(Node* node,
462 : SimdType input_rep_type,
463 : const Operator* op,
464 4080 : bool is_signed) {
465 : DCHECK_EQ(2, node->InputCount());
466 : DCHECK(input_rep_type == SimdType::kInt16x8 ||
467 : input_rep_type == SimdType::kInt8x16);
468 48 : Node** rep_left = GetReplacementsWithType(node->InputAt(0), input_rep_type);
469 48 : Node** rep_right = GetReplacementsWithType(node->InputAt(1), input_rep_type);
470 : int32_t min = 0;
471 : int32_t max = 0;
472 : int32_t mask = 0;
473 : int32_t shift_val = 0;
474 : MachineRepresentation phi_rep;
475 48 : if (input_rep_type == SimdType::kInt16x8) {
476 24 : if (is_signed) {
477 : min = std::numeric_limits<int16_t>::min();
478 : max = std::numeric_limits<int16_t>::max();
479 : } else {
480 : min = std::numeric_limits<uint16_t>::min();
481 : max = std::numeric_limits<uint16_t>::max();
482 : }
483 : mask = kMask16;
484 : shift_val = kShift16;
485 : phi_rep = MachineRepresentation::kWord16;
486 : } else {
487 24 : if (is_signed) {
488 : min = std::numeric_limits<int8_t>::min();
489 : max = std::numeric_limits<int8_t>::max();
490 : } else {
491 : min = std::numeric_limits<uint8_t>::min();
492 : max = std::numeric_limits<uint8_t>::max();
493 : }
494 : mask = kMask8;
495 : shift_val = kShift8;
496 : phi_rep = MachineRepresentation::kWord8;
497 : }
498 48 : int num_lanes = NumLanes(input_rep_type);
499 48 : Node** rep_node = zone()->NewArray<Node*>(num_lanes);
500 624 : for (int i = 0; i < num_lanes; ++i) {
501 : Node* op_result = nullptr;
502 576 : Node* left = is_signed ? rep_left[i] : Mask(rep_left[i], mask);
503 576 : Node* right = is_signed ? rep_right[i] : Mask(rep_right[i], mask);
504 : op_result = graph()->NewNode(op, left, right);
505 : Diamond d_min(graph(), common(),
506 : graph()->NewNode(machine()->Int32LessThan(), op_result,
507 1728 : jsgraph_->Int32Constant(min)));
508 576 : rep_node[i] = d_min.Phi(phi_rep, jsgraph_->Int32Constant(min), op_result);
509 : Diamond d_max(graph(), common(),
510 : graph()->NewNode(machine()->Int32LessThan(),
511 1728 : jsgraph_->Int32Constant(max), rep_node[i]));
512 576 : rep_node[i] = d_max.Phi(phi_rep, jsgraph_->Int32Constant(max), rep_node[i]);
513 : rep_node[i] =
514 576 : is_signed ? rep_node[i] : FixUpperBits(rep_node[i], shift_val);
515 : }
516 48 : ReplaceNode(node, rep_node, num_lanes);
517 48 : }
518 :
519 0 : void SimdScalarLowering::LowerUnaryOp(Node* node, SimdType input_rep_type,
520 0 : const Operator* op) {
521 : DCHECK_EQ(1, node->InputCount());
522 0 : Node** rep = GetReplacementsWithType(node->InputAt(0), input_rep_type);
523 0 : int num_lanes = NumLanes(input_rep_type);
524 0 : Node** rep_node = zone()->NewArray<Node*>(num_lanes);
525 0 : for (int i = 0; i < num_lanes; ++i) {
526 0 : rep_node[i] = graph()->NewNode(op, rep[i]);
527 : }
528 0 : ReplaceNode(node, rep_node, num_lanes);
529 0 : }
530 :
531 72 : void SimdScalarLowering::LowerIntMinMax(Node* node, const Operator* op,
532 1416 : bool is_max, SimdType type) {
533 : DCHECK_EQ(2, node->InputCount());
534 72 : Node** rep_left = GetReplacementsWithType(node->InputAt(0), type);
535 72 : Node** rep_right = GetReplacementsWithType(node->InputAt(1), type);
536 72 : int num_lanes = NumLanes(type);
537 72 : Node** rep_node = zone()->NewArray<Node*>(num_lanes);
538 : MachineRepresentation rep = MachineRepresentation::kNone;
539 72 : if (type == SimdType::kInt32x4) {
540 : rep = MachineRepresentation::kWord32;
541 48 : } else if (type == SimdType::kInt16x8) {
542 : rep = MachineRepresentation::kWord16;
543 24 : } else if (type == SimdType::kInt8x16) {
544 : rep = MachineRepresentation::kWord8;
545 : } else {
546 0 : UNREACHABLE();
547 : }
548 744 : for (int i = 0; i < num_lanes; ++i) {
549 : Diamond d(graph(), common(),
550 1344 : graph()->NewNode(op, rep_left[i], rep_right[i]));
551 672 : if (is_max) {
552 336 : rep_node[i] = d.Phi(rep, rep_right[i], rep_left[i]);
553 : } else {
554 336 : rep_node[i] = d.Phi(rep, rep_left[i], rep_right[i]);
555 : }
556 : }
557 72 : ReplaceNode(node, rep_node, num_lanes);
558 72 : }
559 :
560 0 : Node* SimdScalarLowering::BuildF64Trunc(Node* input) {
561 0 : if (machine()->Float64RoundTruncate().IsSupported()) {
562 0 : return graph()->NewNode(machine()->Float64RoundTruncate().op(), input);
563 : } else {
564 : ExternalReference ref =
565 0 : ExternalReference::wasm_f64_trunc(jsgraph_->isolate());
566 : Node* stack_slot =
567 0 : graph()->NewNode(machine()->StackSlot(MachineRepresentation::kFloat64));
568 : const Operator* store_op = machine()->Store(
569 0 : StoreRepresentation(MachineRepresentation::kFloat64, kNoWriteBarrier));
570 : Node* effect =
571 : graph()->NewNode(store_op, stack_slot, jsgraph_->Int32Constant(0),
572 0 : input, graph()->start(), graph()->start());
573 0 : Node* function = graph()->NewNode(common()->ExternalConstant(ref));
574 : Node** args = zone()->NewArray<Node*>(4);
575 0 : args[0] = function;
576 0 : args[1] = stack_slot;
577 0 : args[2] = effect;
578 0 : args[3] = graph()->start();
579 : Signature<MachineType>::Builder sig_builder(zone(), 0, 1);
580 : sig_builder.AddParam(MachineType::Pointer());
581 : CallDescriptor* desc =
582 0 : Linkage::GetSimplifiedCDescriptor(zone(), sig_builder.Build());
583 0 : Node* call = graph()->NewNode(common()->Call(desc), 4, args);
584 : return graph()->NewNode(machine()->Load(LoadRepresentation::Float64()),
585 : stack_slot, jsgraph_->Int32Constant(0), call,
586 0 : graph()->start());
587 : }
588 : }
589 :
590 0 : void SimdScalarLowering::LowerConvertFromFloat(Node* node, bool is_signed) {
591 : DCHECK_EQ(1, node->InputCount());
592 0 : Node** rep = GetReplacementsWithType(node->InputAt(0), SimdType::kFloat32x4);
593 : Node* rep_node[kNumLanes32];
594 0 : Node* double_zero = graph()->NewNode(common()->Float64Constant(0.0));
595 : Node* min = graph()->NewNode(
596 0 : common()->Float64Constant(static_cast<double>(is_signed ? kMinInt : 0)));
597 : Node* max = graph()->NewNode(common()->Float64Constant(
598 0 : static_cast<double>(is_signed ? kMaxInt : 0xffffffffu)));
599 0 : for (int i = 0; i < kNumLanes32; ++i) {
600 : Node* double_rep =
601 0 : graph()->NewNode(machine()->ChangeFloat32ToFloat64(), rep[i]);
602 : Diamond nan_d(graph(), common(), graph()->NewNode(machine()->Float64Equal(),
603 0 : double_rep, double_rep));
604 : Node* temp =
605 0 : nan_d.Phi(MachineRepresentation::kFloat64, double_rep, double_zero);
606 : Diamond min_d(graph(), common(),
607 0 : graph()->NewNode(machine()->Float64LessThan(), temp, min));
608 0 : temp = min_d.Phi(MachineRepresentation::kFloat64, min, temp);
609 : Diamond max_d(graph(), common(),
610 0 : graph()->NewNode(machine()->Float64LessThan(), max, temp));
611 0 : temp = max_d.Phi(MachineRepresentation::kFloat64, max, temp);
612 0 : Node* trunc = BuildF64Trunc(temp);
613 0 : if (is_signed) {
614 0 : rep_node[i] = graph()->NewNode(machine()->ChangeFloat64ToInt32(), trunc);
615 : } else {
616 : rep_node[i] =
617 0 : graph()->NewNode(machine()->TruncateFloat64ToUint32(), trunc);
618 : }
619 : }
620 0 : ReplaceNode(node, rep_node, kNumLanes32);
621 0 : }
622 :
623 792 : void SimdScalarLowering::LowerShiftOp(Node* node, SimdType type) {
624 : DCHECK_EQ(1, node->InputCount());
625 36 : int32_t shift_amount = OpParameter<int32_t>(node);
626 36 : Node* shift_node = graph()->NewNode(common()->Int32Constant(shift_amount));
627 36 : Node** rep = GetReplacementsWithType(node->InputAt(0), type);
628 36 : int num_lanes = NumLanes(type);
629 36 : Node** rep_node = zone()->NewArray<Node*>(num_lanes);
630 252 : for (int i = 0; i < num_lanes; ++i) {
631 216 : rep_node[i] = rep[i];
632 216 : switch (node->opcode()) {
633 : case IrOpcode::kI8x16ShrU:
634 0 : rep_node[i] = Mask(rep_node[i], kMask8);
635 : rep_node[i] =
636 0 : graph()->NewNode(machine()->Word32Shr(), rep_node[i], shift_node);
637 0 : break;
638 : case IrOpcode::kI16x8ShrU:
639 48 : rep_node[i] = Mask(rep_node[i], kMask16); // Fall through.
640 : case IrOpcode::kI32x4ShrU:
641 : rep_node[i] =
642 216 : graph()->NewNode(machine()->Word32Shr(), rep_node[i], shift_node);
643 72 : break;
644 : case IrOpcode::kI32x4Shl:
645 : rep_node[i] =
646 48 : graph()->NewNode(machine()->Word32Shl(), rep_node[i], shift_node);
647 24 : break;
648 : case IrOpcode::kI16x8Shl:
649 : rep_node[i] =
650 96 : graph()->NewNode(machine()->Word32Shl(), rep_node[i], shift_node);
651 48 : rep_node[i] = FixUpperBits(rep_node[i], kShift16);
652 48 : break;
653 : case IrOpcode::kI8x16Shl:
654 : rep_node[i] =
655 0 : graph()->NewNode(machine()->Word32Shl(), rep_node[i], shift_node);
656 0 : rep_node[i] = FixUpperBits(rep_node[i], kShift8);
657 0 : break;
658 : case IrOpcode::kI32x4ShrS:
659 : case IrOpcode::kI16x8ShrS:
660 : case IrOpcode::kI8x16ShrS:
661 : rep_node[i] =
662 144 : graph()->NewNode(machine()->Word32Sar(), rep_node[i], shift_node);
663 72 : break;
664 : default:
665 0 : UNREACHABLE();
666 : }
667 : }
668 36 : ReplaceNode(node, rep_node, num_lanes);
669 36 : }
670 :
671 18 : void SimdScalarLowering::LowerNotEqual(Node* node, SimdType input_rep_type,
672 354 : const Operator* op) {
673 : DCHECK_EQ(2, node->InputCount());
674 18 : Node** rep_left = GetReplacementsWithType(node->InputAt(0), input_rep_type);
675 18 : Node** rep_right = GetReplacementsWithType(node->InputAt(1), input_rep_type);
676 18 : int num_lanes = NumLanes(input_rep_type);
677 18 : Node** rep_node = zone()->NewArray<Node*>(num_lanes);
678 186 : for (int i = 0; i < num_lanes; ++i) {
679 : Diamond d(graph(), common(),
680 336 : graph()->NewNode(op, rep_left[i], rep_right[i]));
681 : MachineRepresentation rep =
682 : (input_rep_type == SimdType::kFloat32x4)
683 : ? MachineRepresentation::kWord32
684 168 : : MachineTypeFrom(input_rep_type).representation();
685 168 : rep_node[i] =
686 168 : d.Phi(rep, jsgraph_->Int32Constant(0), jsgraph_->Int32Constant(-1));
687 : }
688 18 : ReplaceNode(node, rep_node, num_lanes);
689 18 : }
690 :
691 116796 : void SimdScalarLowering::LowerNode(Node* node) {
692 : SimdType rep_type = ReplacementType(node);
693 49560 : int num_lanes = NumLanes(rep_type);
694 49560 : switch (node->opcode()) {
695 : case IrOpcode::kStart: {
696 492 : int parameter_count = GetParameterCountAfterLowering();
697 : // Only exchange the node if the parameter count actually changed.
698 492 : if (parameter_count != static_cast<int>(signature()->parameter_count())) {
699 : int delta =
700 0 : parameter_count - static_cast<int>(signature()->parameter_count());
701 0 : int new_output_count = node->op()->ValueOutputCount() + delta;
702 0 : NodeProperties::ChangeOp(node, common()->Start(new_output_count));
703 : }
704 : break;
705 : }
706 : case IrOpcode::kParameter: {
707 : DCHECK_EQ(1, node->InputCount());
708 : // Only exchange the node if the parameter count actually changed. We do
709 : // not even have to do the default lowering because the the start node,
710 : // the only input of a parameter node, only changes if the parameter count
711 : // changes.
712 3528 : if (GetParameterCountAfterLowering() !=
713 1764 : static_cast<int>(signature()->parameter_count())) {
714 0 : int old_index = ParameterIndexOf(node->op());
715 : int new_index =
716 : GetParameterIndexAfterLoweringSimd128(signature(), old_index);
717 0 : if (old_index == new_index) {
718 0 : NodeProperties::ChangeOp(node, common()->Parameter(new_index));
719 :
720 : Node* new_node[kNumLanes32];
721 0 : for (int i = 0; i < kNumLanes32; ++i) {
722 0 : new_node[i] = nullptr;
723 : }
724 0 : new_node[0] = node;
725 0 : if (signature()->GetParam(old_index) ==
726 : MachineRepresentation::kSimd128) {
727 0 : for (int i = 1; i < kNumLanes32; ++i) {
728 : new_node[i] = graph()->NewNode(common()->Parameter(new_index + i),
729 0 : graph()->start());
730 : }
731 : }
732 0 : ReplaceNode(node, new_node, kNumLanes32);
733 : }
734 : }
735 : break;
736 : }
737 : case IrOpcode::kLoad: {
738 : MachineRepresentation rep =
739 1038 : LoadRepresentationOf(node->op()).representation();
740 : const Operator* load_op;
741 2076 : load_op = machine()->Load(MachineTypeFrom(rep_type));
742 1038 : LowerLoadOp(rep, node, load_op, rep_type);
743 1038 : break;
744 : }
745 : case IrOpcode::kUnalignedLoad: {
746 : MachineRepresentation rep =
747 0 : UnalignedLoadRepresentationOf(node->op()).representation();
748 : const Operator* load_op;
749 0 : load_op = machine()->UnalignedLoad(MachineTypeFrom(rep_type));
750 0 : LowerLoadOp(rep, node, load_op, rep_type);
751 0 : break;
752 : }
753 : case IrOpcode::kStore: {
754 : MachineRepresentation rep =
755 24 : StoreRepresentationOf(node->op()).representation();
756 : WriteBarrierKind write_barrier_kind =
757 24 : StoreRepresentationOf(node->op()).write_barrier_kind();
758 : const Operator* store_op;
759 : store_op = machine()->Store(StoreRepresentation(
760 48 : MachineTypeFrom(rep_type).representation(), write_barrier_kind));
761 24 : LowerStoreOp(rep, node, store_op, rep_type);
762 24 : break;
763 : }
764 : case IrOpcode::kUnalignedStore: {
765 0 : MachineRepresentation rep = UnalignedStoreRepresentationOf(node->op());
766 : const Operator* store_op;
767 : store_op =
768 0 : machine()->UnalignedStore(MachineTypeFrom(rep_type).representation());
769 0 : LowerStoreOp(rep, node, store_op, rep_type);
770 0 : break;
771 : }
772 : case IrOpcode::kReturn: {
773 6444 : DefaultLowering(node);
774 : int new_return_count = GetReturnCountAfterLoweringSimd128(signature());
775 6444 : if (static_cast<int>(signature()->return_count()) != new_return_count) {
776 0 : NodeProperties::ChangeOp(node, common()->Return(new_return_count));
777 : }
778 : break;
779 : }
780 : case IrOpcode::kCall: {
781 : // TODO(turbofan): Make wasm code const-correct wrt. CallDescriptor.
782 0 : CallDescriptor* descriptor =
783 0 : const_cast<CallDescriptor*>(CallDescriptorOf(node->op()));
784 0 : if (DefaultLowering(node) ||
785 0 : (descriptor->ReturnCount() == 1 &&
786 : descriptor->GetReturnType(0) == MachineType::Simd128())) {
787 : // We have to adjust the call descriptor.
788 : const Operator* op =
789 0 : common()->Call(GetI32WasmCallDescriptorForSimd(zone(), descriptor));
790 0 : NodeProperties::ChangeOp(node, op);
791 : }
792 0 : if (descriptor->ReturnCount() == 1 &&
793 : descriptor->GetReturnType(0) == MachineType::Simd128()) {
794 : // We access the additional return values through projections.
795 : Node* rep_node[kNumLanes32];
796 0 : for (int i = 0; i < kNumLanes32; ++i) {
797 : rep_node[i] =
798 0 : graph()->NewNode(common()->Projection(i), node, graph()->start());
799 : }
800 0 : ReplaceNode(node, rep_node, kNumLanes32);
801 : }
802 : break;
803 : }
804 : case IrOpcode::kPhi: {
805 60 : MachineRepresentation rep = PhiRepresentationOf(node->op());
806 60 : if (rep == MachineRepresentation::kSimd128) {
807 : // The replacement nodes have already been created, we only have to
808 : // replace placeholder nodes.
809 : Node** rep_node = GetReplacements(node);
810 54 : for (int i = 0; i < node->op()->ValueInputCount(); ++i) {
811 : Node** rep_input =
812 12 : GetReplacementsWithType(node->InputAt(i), rep_type);
813 60 : for (int j = 0; j < num_lanes; j++) {
814 48 : rep_node[j]->ReplaceInput(i, rep_input[j]);
815 : }
816 : }
817 : } else {
818 54 : DefaultLowering(node);
819 : }
820 : break;
821 : }
822 : #define I32X4_BINOP_CASE(opcode, instruction) \
823 : case IrOpcode::opcode: { \
824 : LowerBinaryOp(node, rep_type, machine()->instruction()); \
825 : break; \
826 : }
827 12 : I32X4_BINOP_CASE(kI32x4Add, Int32Add)
828 6 : I32X4_BINOP_CASE(kI32x4Sub, Int32Sub)
829 6 : I32X4_BINOP_CASE(kI32x4Mul, Int32Mul)
830 6 : I32X4_BINOP_CASE(kS128And, Word32And)
831 6 : I32X4_BINOP_CASE(kS128Or, Word32Or)
832 6 : I32X4_BINOP_CASE(kS128Xor, Word32Xor)
833 : #undef I32X4_BINOP_CASE
834 : case IrOpcode::kI16x8Add:
835 : case IrOpcode::kI8x16Add: {
836 12 : LowerBinaryOpForSmallInt(node, rep_type, machine()->Int32Add());
837 12 : break;
838 : }
839 : case IrOpcode::kI16x8Sub:
840 : case IrOpcode::kI8x16Sub: {
841 12 : LowerBinaryOpForSmallInt(node, rep_type, machine()->Int32Sub());
842 12 : break;
843 : }
844 : case IrOpcode::kI16x8Mul:
845 : case IrOpcode::kI8x16Mul: {
846 6 : LowerBinaryOpForSmallInt(node, rep_type, machine()->Int32Mul());
847 6 : break;
848 : }
849 : case IrOpcode::kI16x8AddSaturateS:
850 : case IrOpcode::kI8x16AddSaturateS: {
851 12 : LowerSaturateBinaryOp(node, rep_type, machine()->Int32Add(), true);
852 12 : break;
853 : }
854 : case IrOpcode::kI16x8SubSaturateS:
855 : case IrOpcode::kI8x16SubSaturateS: {
856 12 : LowerSaturateBinaryOp(node, rep_type, machine()->Int32Sub(), true);
857 12 : break;
858 : }
859 : case IrOpcode::kI16x8AddSaturateU:
860 : case IrOpcode::kI8x16AddSaturateU: {
861 12 : LowerSaturateBinaryOp(node, rep_type, machine()->Int32Add(), false);
862 12 : break;
863 : }
864 : case IrOpcode::kI16x8SubSaturateU:
865 : case IrOpcode::kI8x16SubSaturateU: {
866 12 : LowerSaturateBinaryOp(node, rep_type, machine()->Int32Sub(), false);
867 12 : break;
868 : }
869 : case IrOpcode::kI32x4MaxS:
870 : case IrOpcode::kI16x8MaxS:
871 : case IrOpcode::kI8x16MaxS: {
872 18 : LowerIntMinMax(node, machine()->Int32LessThan(), true, rep_type);
873 18 : break;
874 : }
875 : case IrOpcode::kI32x4MinS:
876 : case IrOpcode::kI16x8MinS:
877 : case IrOpcode::kI8x16MinS: {
878 18 : LowerIntMinMax(node, machine()->Int32LessThan(), false, rep_type);
879 18 : break;
880 : }
881 : case IrOpcode::kI32x4MaxU:
882 : case IrOpcode::kI16x8MaxU:
883 : case IrOpcode::kI8x16MaxU: {
884 18 : LowerIntMinMax(node, machine()->Uint32LessThan(), true, rep_type);
885 18 : break;
886 : }
887 : case IrOpcode::kI32x4MinU:
888 : case IrOpcode::kI16x8MinU:
889 : case IrOpcode::kI8x16MinU: {
890 18 : LowerIntMinMax(node, machine()->Uint32LessThan(), false, rep_type);
891 18 : break;
892 : }
893 : case IrOpcode::kI32x4Neg:
894 : case IrOpcode::kI16x8Neg:
895 : case IrOpcode::kI8x16Neg: {
896 : DCHECK_EQ(1, node->InputCount());
897 18 : Node** rep = GetReplacementsWithType(node->InputAt(0), rep_type);
898 18 : int num_lanes = NumLanes(rep_type);
899 18 : Node** rep_node = zone()->NewArray<Node*>(num_lanes);
900 18 : Node* zero = graph()->NewNode(common()->Int32Constant(0));
901 186 : for (int i = 0; i < num_lanes; ++i) {
902 504 : rep_node[i] = graph()->NewNode(machine()->Int32Sub(), zero, rep[i]);
903 168 : if (node->opcode() == IrOpcode::kI16x8Neg) {
904 48 : rep_node[i] = FixUpperBits(rep_node[i], kShift16);
905 120 : } else if (node->opcode() == IrOpcode::kI8x16Neg) {
906 96 : rep_node[i] = FixUpperBits(rep_node[i], kShift8);
907 : }
908 : }
909 18 : ReplaceNode(node, rep_node, num_lanes);
910 18 : break;
911 : }
912 : case IrOpcode::kS128Not: {
913 : DCHECK_EQ(1, node->InputCount());
914 6 : Node** rep = GetReplacementsWithType(node->InputAt(0), rep_type);
915 : Node* rep_node[kNumLanes32];
916 6 : Node* mask = graph()->NewNode(common()->Int32Constant(0xffffffff));
917 30 : for (int i = 0; i < kNumLanes32; ++i) {
918 72 : rep_node[i] = graph()->NewNode(machine()->Word32Xor(), rep[i], mask);
919 : }
920 6 : ReplaceNode(node, rep_node, kNumLanes32);
921 : break;
922 : }
923 : case IrOpcode::kI32x4SConvertF32x4: {
924 0 : LowerConvertFromFloat(node, true);
925 0 : break;
926 : }
927 : case IrOpcode::kI32x4UConvertF32x4: {
928 0 : LowerConvertFromFloat(node, false);
929 0 : break;
930 : }
931 : case IrOpcode::kI32x4Shl:
932 : case IrOpcode::kI16x8Shl:
933 : case IrOpcode::kI8x16Shl:
934 : case IrOpcode::kI32x4ShrS:
935 : case IrOpcode::kI16x8ShrS:
936 : case IrOpcode::kI8x16ShrS:
937 : case IrOpcode::kI32x4ShrU:
938 : case IrOpcode::kI16x8ShrU:
939 : case IrOpcode::kI8x16ShrU: {
940 36 : LowerShiftOp(node, rep_type);
941 36 : break;
942 : }
943 : #define F32X4_BINOP_CASE(name) \
944 : case IrOpcode::kF32x4##name: { \
945 : LowerBinaryOp(node, rep_type, machine()->Float32##name()); \
946 : break; \
947 : }
948 0 : F32X4_BINOP_CASE(Add)
949 0 : F32X4_BINOP_CASE(Sub)
950 0 : F32X4_BINOP_CASE(Mul)
951 0 : F32X4_BINOP_CASE(Min)
952 0 : F32X4_BINOP_CASE(Max)
953 : #undef F32X4_BINOP_CASE
954 : #define F32X4_UNOP_CASE(name) \
955 : case IrOpcode::kF32x4##name: { \
956 : LowerUnaryOp(node, rep_type, machine()->Float32##name()); \
957 : break; \
958 : }
959 0 : F32X4_UNOP_CASE(Abs)
960 0 : F32X4_UNOP_CASE(Neg)
961 : #undef F32x4_UNOP_CASE
962 : case IrOpcode::kF32x4SConvertI32x4: {
963 0 : LowerUnaryOp(node, SimdType::kInt32x4, machine()->RoundInt32ToFloat32());
964 0 : break;
965 : }
966 : case IrOpcode::kF32x4UConvertI32x4: {
967 0 : LowerUnaryOp(node, SimdType::kInt32x4, machine()->RoundUint32ToFloat32());
968 0 : break;
969 : }
970 : case IrOpcode::kI32x4Splat:
971 : case IrOpcode::kF32x4Splat:
972 : case IrOpcode::kI16x8Splat:
973 : case IrOpcode::kI8x16Splat: {
974 864 : Node** rep_node = zone()->NewArray<Node*>(num_lanes);
975 8568 : for (int i = 0; i < num_lanes; ++i) {
976 7704 : if (HasReplacement(0, node->InputAt(0))) {
977 48 : rep_node[i] = GetReplacements(node->InputAt(0))[0];
978 : } else {
979 15360 : rep_node[i] = node->InputAt(0);
980 : }
981 : }
982 864 : ReplaceNode(node, rep_node, num_lanes);
983 864 : break;
984 : }
985 : case IrOpcode::kI32x4ExtractLane:
986 : case IrOpcode::kF32x4ExtractLane:
987 : case IrOpcode::kI16x8ExtractLane:
988 : case IrOpcode::kI8x16ExtractLane: {
989 6018 : int32_t lane = OpParameter<int32_t>(node);
990 6018 : Node** rep_node = zone()->NewArray<Node*>(num_lanes);
991 6018 : rep_node[0] = GetReplacementsWithType(node->InputAt(0), rep_type)[lane];
992 73800 : for (int i = 1; i < num_lanes; ++i) {
993 67782 : rep_node[i] = nullptr;
994 : }
995 6018 : ReplaceNode(node, rep_node, num_lanes);
996 6018 : break;
997 : }
998 : case IrOpcode::kI32x4ReplaceLane:
999 : case IrOpcode::kF32x4ReplaceLane:
1000 : case IrOpcode::kI16x8ReplaceLane:
1001 : case IrOpcode::kI8x16ReplaceLane: {
1002 : DCHECK_EQ(2, node->InputCount());
1003 : Node* repNode = node->InputAt(1);
1004 198 : int32_t lane = OpParameter<int32_t>(node);
1005 198 : Node** rep_node = GetReplacementsWithType(node->InputAt(0), rep_type);
1006 198 : if (HasReplacement(0, repNode)) {
1007 0 : rep_node[lane] = GetReplacements(repNode)[0];
1008 : } else {
1009 198 : rep_node[lane] = repNode;
1010 : }
1011 198 : ReplaceNode(node, rep_node, num_lanes);
1012 198 : break;
1013 : }
1014 : #define COMPARISON_CASE(type, simd_op, lowering_op, invert) \
1015 : case IrOpcode::simd_op: { \
1016 : LowerCompareOp(node, SimdType::k##type, machine()->lowering_op(), invert); \
1017 : break; \
1018 : }
1019 0 : COMPARISON_CASE(Float32x4, kF32x4Eq, Float32Equal, false)
1020 0 : COMPARISON_CASE(Float32x4, kF32x4Lt, Float32LessThan, false)
1021 0 : COMPARISON_CASE(Float32x4, kF32x4Le, Float32LessThanOrEqual, false)
1022 0 : COMPARISON_CASE(Float32x4, kF32x4Gt, Float32LessThan, true)
1023 0 : COMPARISON_CASE(Float32x4, kF32x4Ge, Float32LessThanOrEqual, true)
1024 6 : COMPARISON_CASE(Int32x4, kI32x4Eq, Word32Equal, false)
1025 0 : COMPARISON_CASE(Int32x4, kI32x4LtS, Int32LessThan, false)
1026 0 : COMPARISON_CASE(Int32x4, kI32x4LeS, Int32LessThanOrEqual, false)
1027 12 : COMPARISON_CASE(Int32x4, kI32x4GtS, Int32LessThan, true)
1028 12 : COMPARISON_CASE(Int32x4, kI32x4GeS, Int32LessThanOrEqual, true)
1029 0 : COMPARISON_CASE(Int32x4, kI32x4LtU, Uint32LessThan, false)
1030 0 : COMPARISON_CASE(Int32x4, kI32x4LeU, Uint32LessThanOrEqual, false)
1031 12 : COMPARISON_CASE(Int32x4, kI32x4GtU, Uint32LessThan, true)
1032 12 : COMPARISON_CASE(Int32x4, kI32x4GeU, Uint32LessThanOrEqual, true)
1033 6 : COMPARISON_CASE(Int16x8, kI16x8Eq, Word32Equal, false)
1034 0 : COMPARISON_CASE(Int16x8, kI16x8LtS, Int32LessThan, false)
1035 0 : COMPARISON_CASE(Int16x8, kI16x8LeS, Int32LessThanOrEqual, false)
1036 12 : COMPARISON_CASE(Int16x8, kI16x8GtS, Int32LessThan, true)
1037 12 : COMPARISON_CASE(Int16x8, kI16x8GeS, Int32LessThanOrEqual, true)
1038 0 : COMPARISON_CASE(Int16x8, kI16x8LtU, Uint32LessThan, false)
1039 0 : COMPARISON_CASE(Int16x8, kI16x8LeU, Uint32LessThanOrEqual, false)
1040 12 : COMPARISON_CASE(Int16x8, kI16x8GtU, Uint32LessThan, true)
1041 12 : COMPARISON_CASE(Int16x8, kI16x8GeU, Uint32LessThanOrEqual, true)
1042 6 : COMPARISON_CASE(Int8x16, kI8x16Eq, Word32Equal, false)
1043 0 : COMPARISON_CASE(Int8x16, kI8x16LtS, Int32LessThan, false)
1044 0 : COMPARISON_CASE(Int8x16, kI8x16LeS, Int32LessThanOrEqual, false)
1045 12 : COMPARISON_CASE(Int8x16, kI8x16GtS, Int32LessThan, true)
1046 12 : COMPARISON_CASE(Int8x16, kI8x16GeS, Int32LessThanOrEqual, true)
1047 0 : COMPARISON_CASE(Int8x16, kI8x16LtU, Uint32LessThan, false)
1048 0 : COMPARISON_CASE(Int8x16, kI8x16LeU, Uint32LessThanOrEqual, false)
1049 12 : COMPARISON_CASE(Int8x16, kI8x16GtU, Uint32LessThan, true)
1050 12 : COMPARISON_CASE(Int8x16, kI8x16GeU, Uint32LessThanOrEqual, true)
1051 : #undef COMPARISON_CASE
1052 : case IrOpcode::kF32x4Ne: {
1053 0 : LowerNotEqual(node, SimdType::kFloat32x4, machine()->Float32Equal());
1054 0 : break;
1055 : }
1056 : case IrOpcode::kI32x4Ne: {
1057 6 : LowerNotEqual(node, SimdType::kInt32x4, machine()->Word32Equal());
1058 6 : break;
1059 : }
1060 : case IrOpcode::kI16x8Ne: {
1061 6 : LowerNotEqual(node, SimdType::kInt16x8, machine()->Word32Equal());
1062 6 : break;
1063 : }
1064 : case IrOpcode::kI8x16Ne: {
1065 6 : LowerNotEqual(node, SimdType::kInt8x16, machine()->Word32Equal());
1066 6 : break;
1067 : }
1068 : case IrOpcode::kS128Select: {
1069 : DCHECK_EQ(3, node->InputCount());
1070 : DCHECK(ReplacementType(node->InputAt(0)) == SimdType::kInt32x4 ||
1071 : ReplacementType(node->InputAt(0)) == SimdType::kInt16x8 ||
1072 : ReplacementType(node->InputAt(0)) == SimdType::kInt8x16);
1073 : Node** boolean_input = GetReplacements(node->InputAt(0));
1074 0 : Node** rep_left = GetReplacementsWithType(node->InputAt(1), rep_type);
1075 0 : Node** rep_right = GetReplacementsWithType(node->InputAt(2), rep_type);
1076 0 : Node** rep_node = zone()->NewArray<Node*>(num_lanes);
1077 0 : for (int i = 0; i < num_lanes; ++i) {
1078 : Diamond d(graph(), common(),
1079 0 : graph()->NewNode(machine()->Word32Equal(), boolean_input[i],
1080 0 : jsgraph_->Int32Constant(0)));
1081 0 : rep_node[i] = d.Phi(MachineTypeFrom(rep_type).representation(),
1082 0 : rep_right[1], rep_left[0]);
1083 : }
1084 0 : ReplaceNode(node, rep_node, num_lanes);
1085 0 : break;
1086 : }
1087 32226 : default: { DefaultLowering(node); }
1088 : }
1089 49560 : }
1090 :
1091 39720 : bool SimdScalarLowering::DefaultLowering(Node* node) {
1092 : bool something_changed = false;
1093 84882 : for (int i = NodeProperties::PastValueIndex(node) - 1; i >= 0; i--) {
1094 : Node* input = node->InputAt(i);
1095 45162 : if (HasReplacement(0, input)) {
1096 : something_changed = true;
1097 6012 : node->ReplaceInput(i, GetReplacements(input)[0]);
1098 : }
1099 45162 : if (HasReplacement(1, input)) {
1100 : something_changed = true;
1101 0 : for (int j = 1; j < ReplacementCount(input); ++j) {
1102 0 : node->InsertInput(zone(), i + j, GetReplacements(input)[j]);
1103 : }
1104 : }
1105 : }
1106 39720 : return something_changed;
1107 : }
1108 :
1109 118104 : void SimdScalarLowering::ReplaceNode(Node* old, Node** new_nodes, int count) {
1110 22752 : replacements_[old->id()].node = zone()->NewArray<Node*>(count);
1111 95352 : for (int i = 0; i < count; ++i) {
1112 175536 : replacements_[old->id()].node[i] = new_nodes[i];
1113 : }
1114 15168 : replacements_[old->id()].num_replacements = count;
1115 7584 : }
1116 :
1117 98226 : bool SimdScalarLowering::HasReplacement(size_t index, Node* node) {
1118 208500 : return replacements_[node->id()].node != nullptr &&
1119 12048 : replacements_[node->id()].node[index] != nullptr;
1120 : }
1121 :
1122 49566 : SimdScalarLowering::SimdType SimdScalarLowering::ReplacementType(Node* node) {
1123 106188 : return replacements_[node->id()].type;
1124 : }
1125 :
1126 7086 : Node** SimdScalarLowering::GetReplacements(Node* node) {
1127 14148 : Node** result = replacements_[node->id()].node;
1128 : DCHECK(result);
1129 0 : return result;
1130 : }
1131 :
1132 0 : int SimdScalarLowering::ReplacementCount(Node* node) {
1133 0 : return replacements_[node->id()].num_replacements;
1134 : }
1135 :
1136 0 : void SimdScalarLowering::Int32ToFloat32(Node** replacements, Node** result) {
1137 0 : for (int i = 0; i < kNumLanes32; ++i) {
1138 0 : if (replacements[i] != nullptr) {
1139 0 : result[i] =
1140 0 : graph()->NewNode(machine()->BitcastInt32ToFloat32(), replacements[i]);
1141 : } else {
1142 0 : result[i] = nullptr;
1143 : }
1144 : }
1145 0 : }
1146 :
1147 0 : void SimdScalarLowering::Float32ToInt32(Node** replacements, Node** result) {
1148 0 : for (int i = 0; i < kNumLanes32; ++i) {
1149 0 : if (replacements[i] != nullptr) {
1150 0 : result[i] =
1151 0 : graph()->NewNode(machine()->BitcastFloat32ToInt32(), replacements[i]);
1152 : } else {
1153 0 : result[i] = nullptr;
1154 : }
1155 : }
1156 0 : }
1157 :
1158 7056 : Node** SimdScalarLowering::GetReplacementsWithType(Node* node, SimdType type) {
1159 : Node** replacements = GetReplacements(node);
1160 7056 : if (ReplacementType(node) == type) {
1161 : return GetReplacements(node);
1162 : }
1163 0 : int num_lanes = NumLanes(type);
1164 0 : Node** result = zone()->NewArray<Node*>(num_lanes);
1165 0 : if (type == SimdType::kInt32x4) {
1166 0 : if (ReplacementType(node) == SimdType::kFloat32x4) {
1167 0 : Float32ToInt32(replacements, result);
1168 0 : } else if (ReplacementType(node) == SimdType::kInt16x8) {
1169 0 : UNIMPLEMENTED();
1170 : } else {
1171 0 : UNREACHABLE();
1172 : }
1173 0 : } else if (type == SimdType::kFloat32x4) {
1174 0 : if (ReplacementType(node) == SimdType::kInt32x4) {
1175 0 : Int32ToFloat32(replacements, result);
1176 0 : } else if (ReplacementType(node) == SimdType::kInt16x8) {
1177 0 : UNIMPLEMENTED();
1178 : } else {
1179 0 : UNREACHABLE();
1180 : }
1181 0 : } else if (type == SimdType::kInt16x8) {
1182 0 : if (ReplacementType(node) == SimdType::kInt32x4 ||
1183 : ReplacementType(node) == SimdType::kFloat32x4) {
1184 0 : UNIMPLEMENTED();
1185 : } else {
1186 0 : UNREACHABLE();
1187 : }
1188 : } else {
1189 0 : UNREACHABLE();
1190 : }
1191 0 : return result;
1192 : }
1193 :
1194 150 : void SimdScalarLowering::PreparePhiReplacement(Node* phi) {
1195 60 : MachineRepresentation rep = PhiRepresentationOf(phi->op());
1196 60 : if (rep == MachineRepresentation::kSimd128) {
1197 : // We have to create the replacements for a phi node before we actually
1198 : // lower the phi to break potential cycles in the graph. The replacements of
1199 : // input nodes do not exist yet, so we use a placeholder node to pass the
1200 : // graph verifier.
1201 6 : int value_count = phi->op()->ValueInputCount();
1202 : SimdType type = ReplacementType(phi);
1203 6 : int num_lanes = NumLanes(type);
1204 6 : Node*** inputs_rep = zone()->NewArray<Node**>(num_lanes);
1205 30 : for (int i = 0; i < num_lanes; ++i) {
1206 48 : inputs_rep[i] = zone()->NewArray<Node*>(value_count + 1);
1207 24 : inputs_rep[i][value_count] = NodeProperties::GetControlInput(phi, 0);
1208 : }
1209 12 : for (int i = 0; i < value_count; ++i) {
1210 48 : for (int j = 0; j < num_lanes; ++j) {
1211 48 : inputs_rep[j][i] = placeholder_;
1212 : }
1213 : }
1214 : Node** rep_nodes = zone()->NewArray<Node*>(num_lanes);
1215 30 : for (int i = 0; i < num_lanes; ++i) {
1216 24 : rep_nodes[i] = graph()->NewNode(
1217 : common()->Phi(MachineTypeFrom(type).representation(), value_count),
1218 72 : value_count + 1, inputs_rep[i], false);
1219 : }
1220 6 : ReplaceNode(phi, rep_nodes, num_lanes);
1221 : }
1222 60 : }
1223 : } // namespace compiler
1224 : } // namespace internal
1225 : } // namespace v8
|