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 SimdScalarLowering::SimdScalarLowering( 29 MachineGraph* mcgraph, Signature<MachineRepresentation>* signature) 30 : mcgraph_(mcgraph), 31 state_(mcgraph->graph(), 3), 32 stack_(mcgraph_->zone()), 33 replacements_(nullptr), 34 signature_(signature), 35 placeholder_(graph()->NewNode(common()->Parameter(-2, "placeholder"), 36 graph()->start())), 37 parameter_count_after_lowering_(-1) { 38 DCHECK_NOT_NULL(graph()); 39 DCHECK_NOT_NULL(graph()->end()); 40 replacements_ = zone()->NewArray<Replacement>(graph()->NodeCount()); 41 memset(replacements_, 0, sizeof(Replacement) * graph()->NodeCount()); 42 } 43 44 void SimdScalarLowering::LowerGraph() { 45 stack_.push_back({graph()->end(), 0}); 46 state_.Set(graph()->end(), State::kOnStack); 47 replacements_[graph()->end()->id()].type = SimdType::kInt32x4; 48 49 while (!stack_.empty()) { 50 NodeState& top = stack_.back(); 51 if (top.input_index == top.node->InputCount()) { 52 // All inputs of top have already been lowered, now lower top. 53 stack_.pop_back(); 54 state_.Set(top.node, State::kVisited); 55 LowerNode(top.node); 56 } else { 57 // Push the next input onto the stack. 58 Node* input = top.node->InputAt(top.input_index++); 59 if (state_.Get(input) == State::kUnvisited) { 60 SetLoweredType(input, top.node); 61 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 PreparePhiReplacement(input); 65 stack_.push_front({input, 0}); 66 } else if (input->opcode() == IrOpcode::kEffectPhi || 67 input->opcode() == IrOpcode::kLoop) { 68 stack_.push_front({input, 0}); 69 } else { 70 stack_.push_back({input, 0}); 71 } 72 state_.Set(input, State::kOnStack); 73 } 74 } 75 } 76 } 77 78 #define FOREACH_INT32X4_OPCODE(V) \ 79 V(I32x4Splat) \ 80 V(I32x4ExtractLane) \ 81 V(I32x4ReplaceLane) \ 82 V(I32x4SConvertF32x4) \ 83 V(I32x4UConvertF32x4) \ 84 V(I32x4SConvertI16x8Low) \ 85 V(I32x4SConvertI16x8High) \ 86 V(I32x4Neg) \ 87 V(I32x4Shl) \ 88 V(I32x4ShrS) \ 89 V(I32x4Add) \ 90 V(I32x4AddHoriz) \ 91 V(I32x4Sub) \ 92 V(I32x4Mul) \ 93 V(I32x4MinS) \ 94 V(I32x4MaxS) \ 95 V(I32x4ShrU) \ 96 V(I32x4MinU) \ 97 V(I32x4MaxU) \ 98 V(I32x4Eq) \ 99 V(I32x4Ne) \ 100 V(I32x4LtS) \ 101 V(I32x4LeS) \ 102 V(I32x4GtS) \ 103 V(I32x4GeS) \ 104 V(I32x4UConvertI16x8Low) \ 105 V(I32x4UConvertI16x8High) \ 106 V(I32x4LtU) \ 107 V(I32x4LeU) \ 108 V(I32x4GtU) \ 109 V(I32x4GeU) \ 110 V(S128And) \ 111 V(S128Or) \ 112 V(S128Xor) \ 113 V(S128Not) \ 114 V(S1x4AnyTrue) \ 115 V(S1x4AllTrue) \ 116 V(S1x8AnyTrue) \ 117 V(S1x8AllTrue) \ 118 V(S1x16AnyTrue) \ 119 V(S1x16AllTrue) 120 121 #define FOREACH_FLOAT32X4_OPCODE(V) \ 122 V(F32x4Splat) \ 123 V(F32x4ExtractLane) \ 124 V(F32x4ReplaceLane) \ 125 V(F32x4SConvertI32x4) \ 126 V(F32x4UConvertI32x4) \ 127 V(F32x4Abs) \ 128 V(F32x4Neg) \ 129 V(F32x4RecipApprox) \ 130 V(F32x4RecipSqrtApprox) \ 131 V(F32x4Add) \ 132 V(F32x4AddHoriz) \ 133 V(F32x4Sub) \ 134 V(F32x4Mul) \ 135 V(F32x4Min) \ 136 V(F32x4Max) 137 138 #define FOREACH_FLOAT32X4_TO_INT32X4OPCODE(V) \ 139 V(F32x4Eq) \ 140 V(F32x4Ne) \ 141 V(F32x4Lt) \ 142 V(F32x4Le) \ 143 V(F32x4Gt) \ 144 V(F32x4Ge) 145 146 #define FOREACH_INT16X8_OPCODE(V) \ 147 V(I16x8Splat) \ 148 V(I16x8ExtractLane) \ 149 V(I16x8ReplaceLane) \ 150 V(I16x8SConvertI8x16Low) \ 151 V(I16x8SConvertI8x16High) \ 152 V(I16x8Neg) \ 153 V(I16x8Shl) \ 154 V(I16x8ShrS) \ 155 V(I16x8SConvertI32x4) \ 156 V(I16x8Add) \ 157 V(I16x8AddSaturateS) \ 158 V(I16x8AddHoriz) \ 159 V(I16x8Sub) \ 160 V(I16x8SubSaturateS) \ 161 V(I16x8Mul) \ 162 V(I16x8MinS) \ 163 V(I16x8MaxS) \ 164 V(I16x8UConvertI8x16Low) \ 165 V(I16x8UConvertI8x16High) \ 166 V(I16x8ShrU) \ 167 V(I16x8UConvertI32x4) \ 168 V(I16x8AddSaturateU) \ 169 V(I16x8SubSaturateU) \ 170 V(I16x8MinU) \ 171 V(I16x8MaxU) \ 172 V(I16x8Eq) \ 173 V(I16x8Ne) \ 174 V(I16x8LtS) \ 175 V(I16x8LeS) \ 176 V(I16x8LtU) \ 177 V(I16x8LeU) 178 179 #define FOREACH_INT8X16_OPCODE(V) \ 180 V(I8x16Splat) \ 181 V(I8x16ExtractLane) \ 182 V(I8x16ReplaceLane) \ 183 V(I8x16SConvertI16x8) \ 184 V(I8x16Neg) \ 185 V(I8x16Shl) \ 186 V(I8x16ShrS) \ 187 V(I8x16Add) \ 188 V(I8x16AddSaturateS) \ 189 V(I8x16Sub) \ 190 V(I8x16SubSaturateS) \ 191 V(I8x16Mul) \ 192 V(I8x16MinS) \ 193 V(I8x16MaxS) \ 194 V(I8x16ShrU) \ 195 V(I8x16UConvertI16x8) \ 196 V(I8x16AddSaturateU) \ 197 V(I8x16SubSaturateU) \ 198 V(I8x16MinU) \ 199 V(I8x16MaxU) \ 200 V(I8x16Eq) \ 201 V(I8x16Ne) \ 202 V(I8x16LtS) \ 203 V(I8x16LeS) \ 204 V(I8x16LtU) \ 205 V(I8x16LeU) \ 206 V(S8x16Shuffle) 207 208 MachineType SimdScalarLowering::MachineTypeFrom(SimdType simdType) { 209 switch (simdType) { 210 case SimdType::kFloat32x4: 211 return MachineType::Float32(); 212 case SimdType::kInt32x4: 213 return MachineType::Int32(); 214 case SimdType::kInt16x8: 215 return MachineType::Int16(); 216 case SimdType::kInt8x16: 217 return MachineType::Int8(); 218 } 219 return MachineType::None(); 220 } 221 222 void SimdScalarLowering::SetLoweredType(Node* node, Node* output) { 223 switch (node->opcode()) { 224 #define CASE_STMT(name) case IrOpcode::k##name: 225 FOREACH_INT32X4_OPCODE(CASE_STMT) 226 case IrOpcode::kReturn: 227 case IrOpcode::kParameter: 228 case IrOpcode::kCall: { 229 replacements_[node->id()].type = SimdType::kInt32x4; 230 break; 231 } 232 FOREACH_FLOAT32X4_OPCODE(CASE_STMT) { 233 replacements_[node->id()].type = SimdType::kFloat32x4; 234 break; 235 } 236 FOREACH_FLOAT32X4_TO_INT32X4OPCODE(CASE_STMT) { 237 replacements_[node->id()].type = SimdType::kInt32x4; 238 break; 239 } 240 FOREACH_INT16X8_OPCODE(CASE_STMT) { 241 replacements_[node->id()].type = SimdType::kInt16x8; 242 break; 243 } 244 FOREACH_INT8X16_OPCODE(CASE_STMT) { 245 replacements_[node->id()].type = SimdType::kInt8x16; 246 break; 247 } 248 default: { 249 switch (output->opcode()) { 250 case IrOpcode::kF32x4SConvertI32x4: 251 case IrOpcode::kF32x4UConvertI32x4: 252 case IrOpcode::kI16x8SConvertI32x4: 253 case IrOpcode::kI16x8UConvertI32x4: { 254 replacements_[node->id()].type = SimdType::kInt32x4; 255 break; 256 } 257 case IrOpcode::kI8x16SConvertI16x8: 258 case IrOpcode::kI8x16UConvertI16x8: 259 case IrOpcode::kI32x4SConvertI16x8Low: 260 case IrOpcode::kI32x4SConvertI16x8High: 261 case IrOpcode::kI32x4UConvertI16x8Low: 262 case IrOpcode::kI32x4UConvertI16x8High: { 263 replacements_[node->id()].type = SimdType::kInt16x8; 264 break; 265 } 266 case IrOpcode::kI16x8SConvertI8x16Low: 267 case IrOpcode::kI16x8SConvertI8x16High: 268 case IrOpcode::kI16x8UConvertI8x16Low: 269 case IrOpcode::kI16x8UConvertI8x16High: { 270 replacements_[node->id()].type = SimdType::kInt8x16; 271 break; 272 } 273 FOREACH_FLOAT32X4_TO_INT32X4OPCODE(CASE_STMT) 274 case IrOpcode::kI32x4SConvertF32x4: 275 case IrOpcode::kI32x4UConvertF32x4: { 276 replacements_[node->id()].type = SimdType::kFloat32x4; 277 break; 278 } 279 case IrOpcode::kS128Select: { 280 replacements_[node->id()].type = SimdType::kInt32x4; 281 break; 282 } 283 default: { 284 replacements_[node->id()].type = replacements_[output->id()].type; 285 } 286 } 287 } 288 #undef CASE_STMT 289 } 290 } 291 292 static int GetParameterIndexAfterLoweringSimd128( 293 Signature<MachineRepresentation>* signature, int old_index) { 294 // In function calls, the simd128 types are passed as 4 Int32 types. The 295 // parameters are typecast to the types as needed for various operations. 296 int result = old_index; 297 for (int i = 0; i < old_index; ++i) { 298 if (signature->GetParam(i) == MachineRepresentation::kSimd128) { 299 result += 3; 300 } 301 } 302 return result; 303 } 304 305 int SimdScalarLowering::GetParameterCountAfterLowering() { 306 if (parameter_count_after_lowering_ == -1) { 307 // GetParameterIndexAfterLoweringSimd128(parameter_count) returns the 308 // parameter count after lowering. 309 parameter_count_after_lowering_ = GetParameterIndexAfterLoweringSimd128( 310 signature(), static_cast<int>(signature()->parameter_count())); 311 } 312 return parameter_count_after_lowering_; 313 } 314 315 static int GetReturnCountAfterLoweringSimd128( 316 Signature<MachineRepresentation>* signature) { 317 int result = static_cast<int>(signature->return_count()); 318 for (int i = 0; i < static_cast<int>(signature->return_count()); ++i) { 319 if (signature->GetReturn(i) == MachineRepresentation::kSimd128) { 320 result += 3; 321 } 322 } 323 return result; 324 } 325 326 int SimdScalarLowering::NumLanes(SimdType type) { 327 int num_lanes = 0; 328 if (type == SimdType::kFloat32x4 || type == SimdType::kInt32x4) { 329 num_lanes = kNumLanes32; 330 } else if (type == SimdType::kInt16x8) { 331 num_lanes = kNumLanes16; 332 } else if (type == SimdType::kInt8x16) { 333 num_lanes = kNumLanes8; 334 } else { 335 UNREACHABLE(); 336 } 337 return num_lanes; 338 } 339 340 constexpr int SimdScalarLowering::kLaneOffsets[]; 341 342 void SimdScalarLowering::GetIndexNodes(Node* index, Node** new_indices, 343 SimdType type) { 344 int num_lanes = NumLanes(type); 345 int lane_width = kSimd128Size / num_lanes; 346 int laneIndex = kLaneOffsets[0] / lane_width; 347 new_indices[laneIndex] = index; 348 for (int i = 1; i < num_lanes; ++i) { 349 laneIndex = kLaneOffsets[i * lane_width] / lane_width; 350 new_indices[laneIndex] = graph()->NewNode( 351 machine()->Int32Add(), index, 352 graph()->NewNode( 353 common()->Int32Constant(static_cast<int>(i) * lane_width))); 354 } 355 } 356 357 void SimdScalarLowering::LowerLoadOp(Node* node, SimdType type) { 358 MachineRepresentation rep = LoadRepresentationOf(node->op()).representation(); 359 const Operator* load_op; 360 switch (node->opcode()) { 361 case IrOpcode::kLoad: 362 load_op = machine()->Load(MachineTypeFrom(type)); 363 break; 364 case IrOpcode::kUnalignedLoad: 365 load_op = machine()->UnalignedLoad(MachineTypeFrom(type)); 366 break; 367 case IrOpcode::kProtectedLoad: 368 load_op = machine()->ProtectedLoad(MachineTypeFrom(type)); 369 break; 370 default: 371 UNREACHABLE(); 372 } 373 if (rep == MachineRepresentation::kSimd128) { 374 Node* base = node->InputAt(0); 375 Node* index = node->InputAt(1); 376 int num_lanes = NumLanes(type); 377 Node** indices = zone()->NewArray<Node*>(num_lanes); 378 GetIndexNodes(index, indices, type); 379 Node** rep_nodes = zone()->NewArray<Node*>(num_lanes); 380 rep_nodes[0] = node; 381 rep_nodes[0]->ReplaceInput(1, indices[0]); 382 NodeProperties::ChangeOp(rep_nodes[0], load_op); 383 if (node->InputCount() > 2) { 384 DCHECK_LT(3, node->InputCount()); 385 Node* effect_input = node->InputAt(2); 386 Node* control_input = node->InputAt(3); 387 for (int i = num_lanes - 1; i > 0; --i) { 388 rep_nodes[i] = graph()->NewNode(load_op, base, indices[i], effect_input, 389 control_input); 390 effect_input = rep_nodes[i]; 391 } 392 rep_nodes[0]->ReplaceInput(2, rep_nodes[1]); 393 } else { 394 for (int i = 1; i < num_lanes; ++i) { 395 rep_nodes[i] = graph()->NewNode(load_op, base, indices[i]); 396 } 397 } 398 ReplaceNode(node, rep_nodes, num_lanes); 399 } else { 400 DefaultLowering(node); 401 } 402 } 403 404 void SimdScalarLowering::LowerStoreOp(Node* node) { 405 // For store operation, use replacement type of its input instead of the 406 // one of its effected node. 407 DCHECK_LT(2, node->InputCount()); 408 SimdType rep_type = ReplacementType(node->InputAt(2)); 409 replacements_[node->id()].type = rep_type; 410 const Operator* store_op; 411 MachineRepresentation rep; 412 switch (node->opcode()) { 413 case IrOpcode::kStore: { 414 rep = StoreRepresentationOf(node->op()).representation(); 415 WriteBarrierKind write_barrier_kind = 416 StoreRepresentationOf(node->op()).write_barrier_kind(); 417 store_op = machine()->Store(StoreRepresentation( 418 MachineTypeFrom(rep_type).representation(), write_barrier_kind)); 419 break; 420 } 421 case IrOpcode::kUnalignedStore: { 422 rep = UnalignedStoreRepresentationOf(node->op()); 423 store_op = 424 machine()->UnalignedStore(MachineTypeFrom(rep_type).representation()); 425 break; 426 } 427 case IrOpcode::kProtectedStore: { 428 rep = StoreRepresentationOf(node->op()).representation(); 429 store_op = 430 machine()->ProtectedStore(MachineTypeFrom(rep_type).representation()); 431 break; 432 } 433 default: 434 UNREACHABLE(); 435 } 436 if (rep == MachineRepresentation::kSimd128) { 437 Node* base = node->InputAt(0); 438 Node* index = node->InputAt(1); 439 int num_lanes = NumLanes(rep_type); 440 Node** indices = zone()->NewArray<Node*>(num_lanes); 441 GetIndexNodes(index, indices, rep_type); 442 Node* value = node->InputAt(2); 443 DCHECK(HasReplacement(1, value)); 444 Node** rep_nodes = zone()->NewArray<Node*>(num_lanes); 445 rep_nodes[0] = node; 446 Node** rep_inputs = GetReplacementsWithType(value, rep_type); 447 rep_nodes[0]->ReplaceInput(2, rep_inputs[0]); 448 rep_nodes[0]->ReplaceInput(1, indices[0]); 449 NodeProperties::ChangeOp(node, store_op); 450 if (node->InputCount() > 3) { 451 DCHECK_LT(4, node->InputCount()); 452 Node* effect_input = node->InputAt(3); 453 Node* control_input = node->InputAt(4); 454 for (int i = num_lanes - 1; i > 0; --i) { 455 rep_nodes[i] = 456 graph()->NewNode(store_op, base, indices[i], rep_inputs[i], 457 effect_input, control_input); 458 effect_input = rep_nodes[i]; 459 } 460 rep_nodes[0]->ReplaceInput(3, rep_nodes[1]); 461 } else { 462 for (int i = 1; i < num_lanes; ++i) { 463 rep_nodes[i] = 464 graph()->NewNode(store_op, base, indices[i], rep_inputs[i]); 465 } 466 } 467 ReplaceNode(node, rep_nodes, num_lanes); 468 } else { 469 DefaultLowering(node); 470 } 471 } 472 473 void SimdScalarLowering::LowerBinaryOp(Node* node, SimdType input_rep_type, 474 const Operator* op, 475 bool not_horizontal) { 476 DCHECK_EQ(2, node->InputCount()); 477 Node** rep_left = GetReplacementsWithType(node->InputAt(0), input_rep_type); 478 Node** rep_right = GetReplacementsWithType(node->InputAt(1), input_rep_type); 479 int num_lanes = NumLanes(input_rep_type); 480 Node** rep_node = zone()->NewArray<Node*>(num_lanes); 481 if (not_horizontal) { 482 for (int i = 0; i < num_lanes; ++i) { 483 rep_node[i] = graph()->NewNode(op, rep_left[i], rep_right[i]); 484 } 485 } else { 486 for (int i = 0; i < num_lanes / 2; ++i) { 487 rep_node[i] = graph()->NewNode(op, rep_left[i * 2], rep_left[i * 2 + 1]); 488 rep_node[i + num_lanes / 2] = 489 graph()->NewNode(op, rep_right[i * 2], rep_right[i * 2 + 1]); 490 } 491 } 492 ReplaceNode(node, rep_node, num_lanes); 493 } 494 495 void SimdScalarLowering::LowerCompareOp(Node* node, SimdType input_rep_type, 496 const Operator* op, 497 bool invert_inputs) { 498 DCHECK_EQ(2, node->InputCount()); 499 Node** rep_left = GetReplacementsWithType(node->InputAt(0), input_rep_type); 500 Node** rep_right = GetReplacementsWithType(node->InputAt(1), input_rep_type); 501 int num_lanes = NumLanes(input_rep_type); 502 Node** rep_node = zone()->NewArray<Node*>(num_lanes); 503 for (int i = 0; i < num_lanes; ++i) { 504 Node* cmp_result = nullptr; 505 if (invert_inputs) { 506 cmp_result = graph()->NewNode(op, rep_right[i], rep_left[i]); 507 } else { 508 cmp_result = graph()->NewNode(op, rep_left[i], rep_right[i]); 509 } 510 Diamond d_cmp(graph(), common(), 511 graph()->NewNode(machine()->Word32Equal(), cmp_result, 512 mcgraph_->Int32Constant(0))); 513 MachineRepresentation rep = 514 (input_rep_type == SimdType::kFloat32x4) 515 ? MachineRepresentation::kWord32 516 : MachineTypeFrom(input_rep_type).representation(); 517 rep_node[i] = 518 d_cmp.Phi(rep, mcgraph_->Int32Constant(0), mcgraph_->Int32Constant(-1)); 519 } 520 ReplaceNode(node, rep_node, num_lanes); 521 } 522 523 Node* SimdScalarLowering::FixUpperBits(Node* input, int32_t shift) { 524 return graph()->NewNode(machine()->Word32Sar(), 525 graph()->NewNode(machine()->Word32Shl(), input, 526 mcgraph_->Int32Constant(shift)), 527 mcgraph_->Int32Constant(shift)); 528 } 529 530 void SimdScalarLowering::LowerBinaryOpForSmallInt(Node* node, 531 SimdType input_rep_type, 532 const Operator* op, 533 bool not_horizontal) { 534 DCHECK_EQ(2, node->InputCount()); 535 DCHECK(input_rep_type == SimdType::kInt16x8 || 536 input_rep_type == SimdType::kInt8x16); 537 Node** rep_left = GetReplacementsWithType(node->InputAt(0), input_rep_type); 538 Node** rep_right = GetReplacementsWithType(node->InputAt(1), input_rep_type); 539 int num_lanes = NumLanes(input_rep_type); 540 Node** rep_node = zone()->NewArray<Node*>(num_lanes); 541 int32_t shift_val = 542 (input_rep_type == SimdType::kInt16x8) ? kShift16 : kShift8; 543 if (not_horizontal) { 544 for (int i = 0; i < num_lanes; ++i) { 545 rep_node[i] = FixUpperBits( 546 graph()->NewNode(op, rep_left[i], rep_right[i]), shift_val); 547 } 548 } else { 549 for (int i = 0; i < num_lanes / 2; ++i) { 550 rep_node[i] = FixUpperBits( 551 graph()->NewNode(op, rep_left[i * 2], rep_left[i * 2 + 1]), 552 shift_val); 553 rep_node[i + num_lanes / 2] = FixUpperBits( 554 graph()->NewNode(op, rep_right[i * 2], rep_right[i * 2 + 1]), 555 shift_val); 556 } 557 } 558 ReplaceNode(node, rep_node, num_lanes); 559 } 560 561 Node* SimdScalarLowering::Mask(Node* input, int32_t mask) { 562 return graph()->NewNode(machine()->Word32And(), input, 563 mcgraph_->Int32Constant(mask)); 564 } 565 566 void SimdScalarLowering::LowerSaturateBinaryOp(Node* node, 567 SimdType input_rep_type, 568 const Operator* op, 569 bool is_signed) { 570 DCHECK_EQ(2, node->InputCount()); 571 DCHECK(input_rep_type == SimdType::kInt16x8 || 572 input_rep_type == SimdType::kInt8x16); 573 Node** rep_left = GetReplacementsWithType(node->InputAt(0), input_rep_type); 574 Node** rep_right = GetReplacementsWithType(node->InputAt(1), input_rep_type); 575 int32_t min = 0; 576 int32_t max = 0; 577 int32_t mask = 0; 578 int32_t shift_val = 0; 579 MachineRepresentation phi_rep; 580 if (input_rep_type == SimdType::kInt16x8) { 581 if (is_signed) { 582 min = std::numeric_limits<int16_t>::min(); 583 max = std::numeric_limits<int16_t>::max(); 584 } else { 585 min = std::numeric_limits<uint16_t>::min(); 586 max = std::numeric_limits<uint16_t>::max(); 587 } 588 mask = kMask16; 589 shift_val = kShift16; 590 phi_rep = MachineRepresentation::kWord16; 591 } else { 592 if (is_signed) { 593 min = std::numeric_limits<int8_t>::min(); 594 max = std::numeric_limits<int8_t>::max(); 595 } else { 596 min = std::numeric_limits<uint8_t>::min(); 597 max = std::numeric_limits<uint8_t>::max(); 598 } 599 mask = kMask8; 600 shift_val = kShift8; 601 phi_rep = MachineRepresentation::kWord8; 602 } 603 int num_lanes = NumLanes(input_rep_type); 604 Node** rep_node = zone()->NewArray<Node*>(num_lanes); 605 for (int i = 0; i < num_lanes; ++i) { 606 Node* op_result = nullptr; 607 Node* left = is_signed ? rep_left[i] : Mask(rep_left[i], mask); 608 Node* right = is_signed ? rep_right[i] : Mask(rep_right[i], mask); 609 op_result = graph()->NewNode(op, left, right); 610 Diamond d_min(graph(), common(), 611 graph()->NewNode(machine()->Int32LessThan(), op_result, 612 mcgraph_->Int32Constant(min))); 613 rep_node[i] = d_min.Phi(phi_rep, mcgraph_->Int32Constant(min), op_result); 614 Diamond d_max(graph(), common(), 615 graph()->NewNode(machine()->Int32LessThan(), 616 mcgraph_->Int32Constant(max), rep_node[i])); 617 rep_node[i] = d_max.Phi(phi_rep, mcgraph_->Int32Constant(max), rep_node[i]); 618 rep_node[i] = 619 is_signed ? rep_node[i] : FixUpperBits(rep_node[i], shift_val); 620 } 621 ReplaceNode(node, rep_node, num_lanes); 622 } 623 624 void SimdScalarLowering::LowerUnaryOp(Node* node, SimdType input_rep_type, 625 const Operator* op) { 626 DCHECK_EQ(1, node->InputCount()); 627 Node** rep = GetReplacementsWithType(node->InputAt(0), input_rep_type); 628 int num_lanes = NumLanes(input_rep_type); 629 Node** rep_node = zone()->NewArray<Node*>(num_lanes); 630 for (int i = 0; i < num_lanes; ++i) { 631 rep_node[i] = graph()->NewNode(op, rep[i]); 632 } 633 ReplaceNode(node, rep_node, num_lanes); 634 } 635 636 void SimdScalarLowering::LowerIntMinMax(Node* node, const Operator* op, 637 bool is_max, SimdType type) { 638 DCHECK_EQ(2, node->InputCount()); 639 Node** rep_left = GetReplacementsWithType(node->InputAt(0), type); 640 Node** rep_right = GetReplacementsWithType(node->InputAt(1), type); 641 int num_lanes = NumLanes(type); 642 Node** rep_node = zone()->NewArray<Node*>(num_lanes); 643 MachineRepresentation rep = MachineRepresentation::kNone; 644 if (type == SimdType::kInt32x4) { 645 rep = MachineRepresentation::kWord32; 646 } else if (type == SimdType::kInt16x8) { 647 rep = MachineRepresentation::kWord16; 648 } else if (type == SimdType::kInt8x16) { 649 rep = MachineRepresentation::kWord8; 650 } else { 651 UNREACHABLE(); 652 } 653 for (int i = 0; i < num_lanes; ++i) { 654 Diamond d(graph(), common(), 655 graph()->NewNode(op, rep_left[i], rep_right[i])); 656 if (is_max) { 657 rep_node[i] = d.Phi(rep, rep_right[i], rep_left[i]); 658 } else { 659 rep_node[i] = d.Phi(rep, rep_left[i], rep_right[i]); 660 } 661 } 662 ReplaceNode(node, rep_node, num_lanes); 663 } 664 665 Node* SimdScalarLowering::BuildF64Trunc(Node* input) { 666 if (machine()->Float64RoundTruncate().IsSupported()) { 667 return graph()->NewNode(machine()->Float64RoundTruncate().op(), input); 668 } else { 669 ExternalReference ref = ExternalReference::wasm_f64_trunc(); 670 Node* stack_slot = 671 graph()->NewNode(machine()->StackSlot(MachineRepresentation::kFloat64)); 672 const Operator* store_op = machine()->Store( 673 StoreRepresentation(MachineRepresentation::kFloat64, kNoWriteBarrier)); 674 Node* effect = 675 graph()->NewNode(store_op, stack_slot, mcgraph_->Int32Constant(0), 676 input, graph()->start(), graph()->start()); 677 Node* function = graph()->NewNode(common()->ExternalConstant(ref)); 678 Node** args = zone()->NewArray<Node*>(4); 679 args[0] = function; 680 args[1] = stack_slot; 681 args[2] = effect; 682 args[3] = graph()->start(); 683 Signature<MachineType>::Builder sig_builder(zone(), 0, 1); 684 sig_builder.AddParam(MachineType::Pointer()); 685 auto call_descriptor = 686 Linkage::GetSimplifiedCDescriptor(zone(), sig_builder.Build()); 687 Node* call = graph()->NewNode(common()->Call(call_descriptor), 4, args); 688 return graph()->NewNode(machine()->Load(LoadRepresentation::Float64()), 689 stack_slot, mcgraph_->Int32Constant(0), call, 690 graph()->start()); 691 } 692 } 693 694 void SimdScalarLowering::LowerConvertFromFloat(Node* node, bool is_signed) { 695 DCHECK_EQ(1, node->InputCount()); 696 Node** rep = GetReplacementsWithType(node->InputAt(0), SimdType::kFloat32x4); 697 Node* rep_node[kNumLanes32]; 698 Node* double_zero = graph()->NewNode(common()->Float64Constant(0.0)); 699 Node* min = graph()->NewNode( 700 common()->Float64Constant(static_cast<double>(is_signed ? kMinInt : 0))); 701 Node* max = graph()->NewNode(common()->Float64Constant( 702 static_cast<double>(is_signed ? kMaxInt : 0xFFFFFFFFu))); 703 for (int i = 0; i < kNumLanes32; ++i) { 704 Node* double_rep = 705 graph()->NewNode(machine()->ChangeFloat32ToFloat64(), rep[i]); 706 Diamond nan_d(graph(), common(), graph()->NewNode(machine()->Float64Equal(), 707 double_rep, double_rep)); 708 Node* temp = 709 nan_d.Phi(MachineRepresentation::kFloat64, double_rep, double_zero); 710 Diamond min_d(graph(), common(), 711 graph()->NewNode(machine()->Float64LessThan(), temp, min)); 712 temp = min_d.Phi(MachineRepresentation::kFloat64, min, temp); 713 Diamond max_d(graph(), common(), 714 graph()->NewNode(machine()->Float64LessThan(), max, temp)); 715 temp = max_d.Phi(MachineRepresentation::kFloat64, max, temp); 716 Node* trunc = BuildF64Trunc(temp); 717 if (is_signed) { 718 rep_node[i] = graph()->NewNode(machine()->ChangeFloat64ToInt32(), trunc); 719 } else { 720 rep_node[i] = 721 graph()->NewNode(machine()->TruncateFloat64ToUint32(), trunc); 722 } 723 } 724 ReplaceNode(node, rep_node, kNumLanes32); 725 } 726 727 void SimdScalarLowering::LowerConvertFromInt(Node* node, 728 SimdType input_rep_type, 729 SimdType output_rep_type, 730 bool is_signed, int start_index) { 731 DCHECK_EQ(1, node->InputCount()); 732 Node** rep = GetReplacementsWithType(node->InputAt(0), input_rep_type); 733 734 int32_t mask = 0; 735 if (input_rep_type == SimdType::kInt16x8) { 736 DCHECK_EQ(output_rep_type, SimdType::kInt32x4); 737 mask = kMask16; 738 } else { 739 DCHECK_EQ(output_rep_type, SimdType::kInt16x8); 740 DCHECK_EQ(input_rep_type, SimdType::kInt8x16); 741 mask = kMask8; 742 } 743 744 int num_lanes = NumLanes(output_rep_type); 745 Node** rep_node = zone()->NewArray<Node*>(num_lanes); 746 for (int i = 0; i < num_lanes; ++i) { 747 rep_node[i] = 748 is_signed ? rep[i + start_index] : Mask(rep[i + start_index], mask); 749 } 750 751 ReplaceNode(node, rep_node, num_lanes); 752 } 753 754 void SimdScalarLowering::LowerPack(Node* node, SimdType input_rep_type, 755 SimdType output_rep_type, bool is_signed) { 756 DCHECK_EQ(2, node->InputCount()); 757 Node** rep_left = GetReplacementsWithType(node->InputAt(0), input_rep_type); 758 Node** rep_right = GetReplacementsWithType(node->InputAt(1), input_rep_type); 759 const Operator* less_op = 760 is_signed ? machine()->Int32LessThan() : machine()->Uint32LessThan(); 761 Node* min = nullptr; 762 Node* max = nullptr; 763 int32_t shift_val = 0; 764 MachineRepresentation phi_rep; 765 if (output_rep_type == SimdType::kInt16x8) { 766 DCHECK(input_rep_type == SimdType::kInt32x4); 767 if (is_signed) { 768 min = mcgraph_->Int32Constant(std::numeric_limits<int16_t>::min()); 769 max = mcgraph_->Int32Constant(std::numeric_limits<int16_t>::max()); 770 } else { 771 max = mcgraph_->Uint32Constant(std::numeric_limits<uint16_t>::max()); 772 shift_val = kShift16; 773 } 774 phi_rep = MachineRepresentation::kWord16; 775 } else { 776 DCHECK(output_rep_type == SimdType::kInt8x16 && 777 input_rep_type == SimdType::kInt16x8); 778 if (is_signed) { 779 min = mcgraph_->Int32Constant(std::numeric_limits<int8_t>::min()); 780 max = mcgraph_->Int32Constant(std::numeric_limits<int8_t>::max()); 781 } else { 782 max = mcgraph_->Uint32Constant(std::numeric_limits<uint8_t>::max()); 783 shift_val = kShift8; 784 } 785 phi_rep = MachineRepresentation::kWord8; 786 } 787 int num_lanes = NumLanes(output_rep_type); 788 Node** rep_node = zone()->NewArray<Node*>(num_lanes); 789 for (int i = 0; i < num_lanes; ++i) { 790 Node* input = nullptr; 791 if (i < num_lanes / 2) 792 input = rep_left[i]; 793 else 794 input = rep_right[i - num_lanes / 2]; 795 if (is_signed) { 796 Diamond d_min(graph(), common(), graph()->NewNode(less_op, input, min)); 797 input = d_min.Phi(phi_rep, min, input); 798 } 799 Diamond d_max(graph(), common(), graph()->NewNode(less_op, max, input)); 800 rep_node[i] = d_max.Phi(phi_rep, max, input); 801 rep_node[i] = 802 is_signed ? rep_node[i] : FixUpperBits(rep_node[i], shift_val); 803 } 804 ReplaceNode(node, rep_node, num_lanes); 805 } 806 807 void SimdScalarLowering::LowerShiftOp(Node* node, SimdType type) { 808 DCHECK_EQ(1, node->InputCount()); 809 int32_t shift_amount = OpParameter<int32_t>(node->op()); 810 Node* shift_node = graph()->NewNode(common()->Int32Constant(shift_amount)); 811 Node** rep = GetReplacementsWithType(node->InputAt(0), type); 812 int num_lanes = NumLanes(type); 813 Node** rep_node = zone()->NewArray<Node*>(num_lanes); 814 for (int i = 0; i < num_lanes; ++i) { 815 rep_node[i] = rep[i]; 816 switch (node->opcode()) { 817 case IrOpcode::kI8x16ShrU: 818 rep_node[i] = Mask(rep_node[i], kMask8); 819 rep_node[i] = 820 graph()->NewNode(machine()->Word32Shr(), rep_node[i], shift_node); 821 break; 822 case IrOpcode::kI16x8ShrU: 823 rep_node[i] = Mask(rep_node[i], kMask16); 824 V8_FALLTHROUGH; 825 case IrOpcode::kI32x4ShrU: 826 rep_node[i] = 827 graph()->NewNode(machine()->Word32Shr(), rep_node[i], shift_node); 828 break; 829 case IrOpcode::kI32x4Shl: 830 rep_node[i] = 831 graph()->NewNode(machine()->Word32Shl(), rep_node[i], shift_node); 832 break; 833 case IrOpcode::kI16x8Shl: 834 rep_node[i] = 835 graph()->NewNode(machine()->Word32Shl(), rep_node[i], shift_node); 836 rep_node[i] = FixUpperBits(rep_node[i], kShift16); 837 break; 838 case IrOpcode::kI8x16Shl: 839 rep_node[i] = 840 graph()->NewNode(machine()->Word32Shl(), rep_node[i], shift_node); 841 rep_node[i] = FixUpperBits(rep_node[i], kShift8); 842 break; 843 case IrOpcode::kI32x4ShrS: 844 case IrOpcode::kI16x8ShrS: 845 case IrOpcode::kI8x16ShrS: 846 rep_node[i] = 847 graph()->NewNode(machine()->Word32Sar(), rep_node[i], shift_node); 848 break; 849 default: 850 UNREACHABLE(); 851 } 852 } 853 ReplaceNode(node, rep_node, num_lanes); 854 } 855 856 void SimdScalarLowering::LowerNotEqual(Node* node, SimdType input_rep_type, 857 const Operator* op) { 858 DCHECK_EQ(2, node->InputCount()); 859 Node** rep_left = GetReplacementsWithType(node->InputAt(0), input_rep_type); 860 Node** rep_right = GetReplacementsWithType(node->InputAt(1), input_rep_type); 861 int num_lanes = NumLanes(input_rep_type); 862 Node** rep_node = zone()->NewArray<Node*>(num_lanes); 863 for (int i = 0; i < num_lanes; ++i) { 864 Diamond d(graph(), common(), 865 graph()->NewNode(op, rep_left[i], rep_right[i])); 866 MachineRepresentation rep = 867 (input_rep_type == SimdType::kFloat32x4) 868 ? MachineRepresentation::kWord32 869 : MachineTypeFrom(input_rep_type).representation(); 870 rep_node[i] = 871 d.Phi(rep, mcgraph_->Int32Constant(0), mcgraph_->Int32Constant(-1)); 872 } 873 ReplaceNode(node, rep_node, num_lanes); 874 } 875 876 void SimdScalarLowering::LowerNode(Node* node) { 877 SimdType rep_type = ReplacementType(node); 878 int num_lanes = NumLanes(rep_type); 879 switch (node->opcode()) { 880 case IrOpcode::kStart: { 881 int parameter_count = GetParameterCountAfterLowering(); 882 // Only exchange the node if the parameter count actually changed. 883 if (parameter_count != static_cast<int>(signature()->parameter_count())) { 884 int delta = 885 parameter_count - static_cast<int>(signature()->parameter_count()); 886 int new_output_count = node->op()->ValueOutputCount() + delta; 887 NodeProperties::ChangeOp(node, common()->Start(new_output_count)); 888 } 889 break; 890 } 891 case IrOpcode::kParameter: { 892 DCHECK_EQ(1, node->InputCount()); 893 // Only exchange the node if the parameter count actually changed. We do 894 // not even have to do the default lowering because the the start node, 895 // the only input of a parameter node, only changes if the parameter count 896 // changes. 897 if (GetParameterCountAfterLowering() != 898 static_cast<int>(signature()->parameter_count())) { 899 int old_index = ParameterIndexOf(node->op()); 900 int new_index = 901 GetParameterIndexAfterLoweringSimd128(signature(), old_index); 902 if (old_index == new_index) { 903 NodeProperties::ChangeOp(node, common()->Parameter(new_index)); 904 905 Node* new_node[kNumLanes32]; 906 for (int i = 0; i < kNumLanes32; ++i) { 907 new_node[i] = nullptr; 908 } 909 new_node[0] = node; 910 if (signature()->GetParam(old_index) == 911 MachineRepresentation::kSimd128) { 912 for (int i = 1; i < kNumLanes32; ++i) { 913 new_node[i] = graph()->NewNode(common()->Parameter(new_index + i), 914 graph()->start()); 915 } 916 } 917 ReplaceNode(node, new_node, kNumLanes32); 918 } 919 } 920 break; 921 } 922 case IrOpcode::kLoad: 923 case IrOpcode::kUnalignedLoad: 924 case IrOpcode::kProtectedLoad: { 925 LowerLoadOp(node, rep_type); 926 break; 927 } 928 case IrOpcode::kStore: 929 case IrOpcode::kUnalignedStore: 930 case IrOpcode::kProtectedStore: { 931 LowerStoreOp(node); 932 break; 933 } 934 case IrOpcode::kReturn: { 935 DefaultLowering(node); 936 int new_return_count = GetReturnCountAfterLoweringSimd128(signature()); 937 if (static_cast<int>(signature()->return_count()) != new_return_count) { 938 NodeProperties::ChangeOp(node, common()->Return(new_return_count)); 939 } 940 break; 941 } 942 case IrOpcode::kCall: { 943 // TODO(turbofan): Make wasm code const-correct wrt. CallDescriptor. 944 auto call_descriptor = 945 const_cast<CallDescriptor*>(CallDescriptorOf(node->op())); 946 if (DefaultLowering(node) || 947 (call_descriptor->ReturnCount() == 1 && 948 call_descriptor->GetReturnType(0) == MachineType::Simd128())) { 949 // We have to adjust the call descriptor. 950 const Operator* op = common()->Call( 951 GetI32WasmCallDescriptorForSimd(zone(), call_descriptor)); 952 NodeProperties::ChangeOp(node, op); 953 } 954 if (call_descriptor->ReturnCount() == 1 && 955 call_descriptor->GetReturnType(0) == MachineType::Simd128()) { 956 // We access the additional return values through projections. 957 Node* rep_node[kNumLanes32]; 958 for (int i = 0; i < kNumLanes32; ++i) { 959 rep_node[i] = 960 graph()->NewNode(common()->Projection(i), node, graph()->start()); 961 } 962 ReplaceNode(node, rep_node, kNumLanes32); 963 } 964 break; 965 } 966 case IrOpcode::kPhi: { 967 MachineRepresentation rep = PhiRepresentationOf(node->op()); 968 if (rep == MachineRepresentation::kSimd128) { 969 // The replacement nodes have already been created, we only have to 970 // replace placeholder nodes. 971 Node** rep_node = GetReplacements(node); 972 for (int i = 0; i < node->op()->ValueInputCount(); ++i) { 973 Node** rep_input = 974 GetReplacementsWithType(node->InputAt(i), rep_type); 975 for (int j = 0; j < num_lanes; j++) { 976 rep_node[j]->ReplaceInput(i, rep_input[j]); 977 } 978 } 979 } else { 980 DefaultLowering(node); 981 } 982 break; 983 } 984 #define I32X4_BINOP_CASE(opcode, instruction) \ 985 case IrOpcode::opcode: { \ 986 LowerBinaryOp(node, rep_type, machine()->instruction()); \ 987 break; \ 988 } 989 I32X4_BINOP_CASE(kI32x4Add, Int32Add) 990 I32X4_BINOP_CASE(kI32x4Sub, Int32Sub) 991 I32X4_BINOP_CASE(kI32x4Mul, Int32Mul) 992 I32X4_BINOP_CASE(kS128And, Word32And) 993 I32X4_BINOP_CASE(kS128Or, Word32Or) 994 I32X4_BINOP_CASE(kS128Xor, Word32Xor) 995 #undef I32X4_BINOP_CASE 996 case IrOpcode::kI32x4AddHoriz: { 997 LowerBinaryOp(node, rep_type, machine()->Int32Add(), false); 998 break; 999 } 1000 case IrOpcode::kI16x8AddHoriz: { 1001 LowerBinaryOpForSmallInt(node, rep_type, machine()->Int32Add(), false); 1002 break; 1003 } 1004 case IrOpcode::kI16x8Add: 1005 case IrOpcode::kI8x16Add: { 1006 LowerBinaryOpForSmallInt(node, rep_type, machine()->Int32Add()); 1007 break; 1008 } 1009 case IrOpcode::kI16x8Sub: 1010 case IrOpcode::kI8x16Sub: { 1011 LowerBinaryOpForSmallInt(node, rep_type, machine()->Int32Sub()); 1012 break; 1013 } 1014 case IrOpcode::kI16x8Mul: 1015 case IrOpcode::kI8x16Mul: { 1016 LowerBinaryOpForSmallInt(node, rep_type, machine()->Int32Mul()); 1017 break; 1018 } 1019 case IrOpcode::kI16x8AddSaturateS: 1020 case IrOpcode::kI8x16AddSaturateS: { 1021 LowerSaturateBinaryOp(node, rep_type, machine()->Int32Add(), true); 1022 break; 1023 } 1024 case IrOpcode::kI16x8SubSaturateS: 1025 case IrOpcode::kI8x16SubSaturateS: { 1026 LowerSaturateBinaryOp(node, rep_type, machine()->Int32Sub(), true); 1027 break; 1028 } 1029 case IrOpcode::kI16x8AddSaturateU: 1030 case IrOpcode::kI8x16AddSaturateU: { 1031 LowerSaturateBinaryOp(node, rep_type, machine()->Int32Add(), false); 1032 break; 1033 } 1034 case IrOpcode::kI16x8SubSaturateU: 1035 case IrOpcode::kI8x16SubSaturateU: { 1036 LowerSaturateBinaryOp(node, rep_type, machine()->Int32Sub(), false); 1037 break; 1038 } 1039 case IrOpcode::kI32x4MaxS: 1040 case IrOpcode::kI16x8MaxS: 1041 case IrOpcode::kI8x16MaxS: { 1042 LowerIntMinMax(node, machine()->Int32LessThan(), true, rep_type); 1043 break; 1044 } 1045 case IrOpcode::kI32x4MinS: 1046 case IrOpcode::kI16x8MinS: 1047 case IrOpcode::kI8x16MinS: { 1048 LowerIntMinMax(node, machine()->Int32LessThan(), false, rep_type); 1049 break; 1050 } 1051 case IrOpcode::kI32x4MaxU: 1052 case IrOpcode::kI16x8MaxU: 1053 case IrOpcode::kI8x16MaxU: { 1054 LowerIntMinMax(node, machine()->Uint32LessThan(), true, rep_type); 1055 break; 1056 } 1057 case IrOpcode::kI32x4MinU: 1058 case IrOpcode::kI16x8MinU: 1059 case IrOpcode::kI8x16MinU: { 1060 LowerIntMinMax(node, machine()->Uint32LessThan(), false, rep_type); 1061 break; 1062 } 1063 case IrOpcode::kI32x4Neg: 1064 case IrOpcode::kI16x8Neg: 1065 case IrOpcode::kI8x16Neg: { 1066 DCHECK_EQ(1, node->InputCount()); 1067 Node** rep = GetReplacementsWithType(node->InputAt(0), rep_type); 1068 int num_lanes = NumLanes(rep_type); 1069 Node** rep_node = zone()->NewArray<Node*>(num_lanes); 1070 Node* zero = graph()->NewNode(common()->Int32Constant(0)); 1071 for (int i = 0; i < num_lanes; ++i) { 1072 rep_node[i] = graph()->NewNode(machine()->Int32Sub(), zero, rep[i]); 1073 if (node->opcode() == IrOpcode::kI16x8Neg) { 1074 rep_node[i] = FixUpperBits(rep_node[i], kShift16); 1075 } else if (node->opcode() == IrOpcode::kI8x16Neg) { 1076 rep_node[i] = FixUpperBits(rep_node[i], kShift8); 1077 } 1078 } 1079 ReplaceNode(node, rep_node, num_lanes); 1080 break; 1081 } 1082 case IrOpcode::kS128Not: { 1083 DCHECK_EQ(1, node->InputCount()); 1084 Node** rep = GetReplacementsWithType(node->InputAt(0), rep_type); 1085 Node* rep_node[kNumLanes32]; 1086 Node* mask = graph()->NewNode(common()->Int32Constant(0xFFFFFFFF)); 1087 for (int i = 0; i < kNumLanes32; ++i) { 1088 rep_node[i] = graph()->NewNode(machine()->Word32Xor(), rep[i], mask); 1089 } 1090 ReplaceNode(node, rep_node, kNumLanes32); 1091 break; 1092 } 1093 case IrOpcode::kI32x4SConvertF32x4: { 1094 LowerConvertFromFloat(node, true); 1095 break; 1096 } 1097 case IrOpcode::kI32x4UConvertF32x4: { 1098 LowerConvertFromFloat(node, false); 1099 break; 1100 } 1101 case IrOpcode::kI32x4SConvertI16x8Low: { 1102 LowerConvertFromInt(node, SimdType::kInt16x8, SimdType::kInt32x4, true, 1103 0); 1104 break; 1105 } 1106 case IrOpcode::kI32x4SConvertI16x8High: { 1107 LowerConvertFromInt(node, SimdType::kInt16x8, SimdType::kInt32x4, true, 1108 4); 1109 break; 1110 } 1111 case IrOpcode::kI32x4UConvertI16x8Low: { 1112 LowerConvertFromInt(node, SimdType::kInt16x8, SimdType::kInt32x4, false, 1113 0); 1114 break; 1115 } 1116 case IrOpcode::kI32x4UConvertI16x8High: { 1117 LowerConvertFromInt(node, SimdType::kInt16x8, SimdType::kInt32x4, false, 1118 4); 1119 break; 1120 } 1121 case IrOpcode::kI16x8SConvertI8x16Low: { 1122 LowerConvertFromInt(node, SimdType::kInt8x16, SimdType::kInt16x8, true, 1123 0); 1124 break; 1125 } 1126 case IrOpcode::kI16x8SConvertI8x16High: { 1127 LowerConvertFromInt(node, SimdType::kInt8x16, SimdType::kInt16x8, true, 1128 8); 1129 break; 1130 } 1131 case IrOpcode::kI16x8UConvertI8x16Low: { 1132 LowerConvertFromInt(node, SimdType::kInt8x16, SimdType::kInt16x8, false, 1133 0); 1134 break; 1135 } 1136 case IrOpcode::kI16x8UConvertI8x16High: { 1137 LowerConvertFromInt(node, SimdType::kInt8x16, SimdType::kInt16x8, false, 1138 8); 1139 break; 1140 } 1141 case IrOpcode::kI16x8SConvertI32x4: { 1142 LowerPack(node, SimdType::kInt32x4, SimdType::kInt16x8, true); 1143 break; 1144 } 1145 case IrOpcode::kI16x8UConvertI32x4: { 1146 LowerPack(node, SimdType::kInt32x4, SimdType::kInt16x8, false); 1147 break; 1148 } 1149 case IrOpcode::kI8x16SConvertI16x8: { 1150 LowerPack(node, SimdType::kInt16x8, SimdType::kInt8x16, true); 1151 break; 1152 } 1153 case IrOpcode::kI8x16UConvertI16x8: { 1154 LowerPack(node, SimdType::kInt16x8, SimdType::kInt8x16, false); 1155 break; 1156 } 1157 case IrOpcode::kI32x4Shl: 1158 case IrOpcode::kI16x8Shl: 1159 case IrOpcode::kI8x16Shl: 1160 case IrOpcode::kI32x4ShrS: 1161 case IrOpcode::kI16x8ShrS: 1162 case IrOpcode::kI8x16ShrS: 1163 case IrOpcode::kI32x4ShrU: 1164 case IrOpcode::kI16x8ShrU: 1165 case IrOpcode::kI8x16ShrU: { 1166 LowerShiftOp(node, rep_type); 1167 break; 1168 } 1169 case IrOpcode::kF32x4AddHoriz: { 1170 LowerBinaryOp(node, rep_type, machine()->Float32Add(), false); 1171 break; 1172 } 1173 #define F32X4_BINOP_CASE(name) \ 1174 case IrOpcode::kF32x4##name: { \ 1175 LowerBinaryOp(node, rep_type, machine()->Float32##name()); \ 1176 break; \ 1177 } 1178 F32X4_BINOP_CASE(Add) 1179 F32X4_BINOP_CASE(Sub) 1180 F32X4_BINOP_CASE(Mul) 1181 F32X4_BINOP_CASE(Min) 1182 F32X4_BINOP_CASE(Max) 1183 #undef F32X4_BINOP_CASE 1184 #define F32X4_UNOP_CASE(name) \ 1185 case IrOpcode::kF32x4##name: { \ 1186 LowerUnaryOp(node, rep_type, machine()->Float32##name()); \ 1187 break; \ 1188 } 1189 F32X4_UNOP_CASE(Abs) 1190 F32X4_UNOP_CASE(Neg) 1191 #undef F32x4_UNOP_CASE 1192 case IrOpcode::kF32x4RecipApprox: 1193 case IrOpcode::kF32x4RecipSqrtApprox: { 1194 DCHECK_EQ(1, node->InputCount()); 1195 Node** rep = GetReplacementsWithType(node->InputAt(0), rep_type); 1196 Node** rep_node = zone()->NewArray<Node*>(num_lanes); 1197 Node* float_one = graph()->NewNode(common()->Float32Constant(1.0)); 1198 for (int i = 0; i < num_lanes; ++i) { 1199 Node* tmp = rep[i]; 1200 if (node->opcode() == IrOpcode::kF32x4RecipSqrtApprox) { 1201 tmp = graph()->NewNode(machine()->Float32Sqrt(), rep[i]); 1202 } 1203 rep_node[i] = graph()->NewNode(machine()->Float32Div(), float_one, tmp); 1204 } 1205 ReplaceNode(node, rep_node, num_lanes); 1206 break; 1207 } 1208 case IrOpcode::kF32x4SConvertI32x4: { 1209 LowerUnaryOp(node, SimdType::kInt32x4, machine()->RoundInt32ToFloat32()); 1210 break; 1211 } 1212 case IrOpcode::kF32x4UConvertI32x4: { 1213 LowerUnaryOp(node, SimdType::kInt32x4, machine()->RoundUint32ToFloat32()); 1214 break; 1215 } 1216 case IrOpcode::kI32x4Splat: 1217 case IrOpcode::kF32x4Splat: 1218 case IrOpcode::kI16x8Splat: 1219 case IrOpcode::kI8x16Splat: { 1220 Node** rep_node = zone()->NewArray<Node*>(num_lanes); 1221 for (int i = 0; i < num_lanes; ++i) { 1222 if (HasReplacement(0, node->InputAt(0))) { 1223 rep_node[i] = GetReplacements(node->InputAt(0))[0]; 1224 } else { 1225 rep_node[i] = node->InputAt(0); 1226 } 1227 } 1228 ReplaceNode(node, rep_node, num_lanes); 1229 break; 1230 } 1231 case IrOpcode::kI32x4ExtractLane: 1232 case IrOpcode::kF32x4ExtractLane: 1233 case IrOpcode::kI16x8ExtractLane: 1234 case IrOpcode::kI8x16ExtractLane: { 1235 int32_t lane = OpParameter<int32_t>(node->op()); 1236 Node** rep_node = zone()->NewArray<Node*>(num_lanes); 1237 rep_node[0] = GetReplacementsWithType(node->InputAt(0), rep_type)[lane]; 1238 for (int i = 1; i < num_lanes; ++i) { 1239 rep_node[i] = nullptr; 1240 } 1241 ReplaceNode(node, rep_node, num_lanes); 1242 break; 1243 } 1244 case IrOpcode::kI32x4ReplaceLane: 1245 case IrOpcode::kF32x4ReplaceLane: 1246 case IrOpcode::kI16x8ReplaceLane: 1247 case IrOpcode::kI8x16ReplaceLane: { 1248 DCHECK_EQ(2, node->InputCount()); 1249 Node* repNode = node->InputAt(1); 1250 int32_t lane = OpParameter<int32_t>(node->op()); 1251 Node** old_rep_node = GetReplacementsWithType(node->InputAt(0), rep_type); 1252 Node** rep_node = zone()->NewArray<Node*>(num_lanes); 1253 for (int i = 0; i < num_lanes; ++i) { 1254 rep_node[i] = old_rep_node[i]; 1255 } 1256 if (HasReplacement(0, repNode)) { 1257 rep_node[lane] = GetReplacements(repNode)[0]; 1258 } else { 1259 rep_node[lane] = repNode; 1260 } 1261 ReplaceNode(node, rep_node, num_lanes); 1262 break; 1263 } 1264 #define COMPARISON_CASE(type, simd_op, lowering_op, invert) \ 1265 case IrOpcode::simd_op: { \ 1266 LowerCompareOp(node, SimdType::k##type, machine()->lowering_op(), invert); \ 1267 break; \ 1268 } 1269 COMPARISON_CASE(Float32x4, kF32x4Eq, Float32Equal, false) 1270 COMPARISON_CASE(Float32x4, kF32x4Lt, Float32LessThan, false) 1271 COMPARISON_CASE(Float32x4, kF32x4Le, Float32LessThanOrEqual, false) 1272 COMPARISON_CASE(Float32x4, kF32x4Gt, Float32LessThan, true) 1273 COMPARISON_CASE(Float32x4, kF32x4Ge, Float32LessThanOrEqual, true) 1274 COMPARISON_CASE(Int32x4, kI32x4Eq, Word32Equal, false) 1275 COMPARISON_CASE(Int32x4, kI32x4LtS, Int32LessThan, false) 1276 COMPARISON_CASE(Int32x4, kI32x4LeS, Int32LessThanOrEqual, false) 1277 COMPARISON_CASE(Int32x4, kI32x4GtS, Int32LessThan, true) 1278 COMPARISON_CASE(Int32x4, kI32x4GeS, Int32LessThanOrEqual, true) 1279 COMPARISON_CASE(Int32x4, kI32x4LtU, Uint32LessThan, false) 1280 COMPARISON_CASE(Int32x4, kI32x4LeU, Uint32LessThanOrEqual, false) 1281 COMPARISON_CASE(Int32x4, kI32x4GtU, Uint32LessThan, true) 1282 COMPARISON_CASE(Int32x4, kI32x4GeU, Uint32LessThanOrEqual, true) 1283 COMPARISON_CASE(Int16x8, kI16x8Eq, Word32Equal, false) 1284 COMPARISON_CASE(Int16x8, kI16x8LtS, Int32LessThan, false) 1285 COMPARISON_CASE(Int16x8, kI16x8LeS, Int32LessThanOrEqual, false) 1286 COMPARISON_CASE(Int16x8, kI16x8GtS, Int32LessThan, true) 1287 COMPARISON_CASE(Int16x8, kI16x8GeS, Int32LessThanOrEqual, true) 1288 COMPARISON_CASE(Int16x8, kI16x8LtU, Uint32LessThan, false) 1289 COMPARISON_CASE(Int16x8, kI16x8LeU, Uint32LessThanOrEqual, false) 1290 COMPARISON_CASE(Int16x8, kI16x8GtU, Uint32LessThan, true) 1291 COMPARISON_CASE(Int16x8, kI16x8GeU, Uint32LessThanOrEqual, true) 1292 COMPARISON_CASE(Int8x16, kI8x16Eq, Word32Equal, false) 1293 COMPARISON_CASE(Int8x16, kI8x16LtS, Int32LessThan, false) 1294 COMPARISON_CASE(Int8x16, kI8x16LeS, Int32LessThanOrEqual, false) 1295 COMPARISON_CASE(Int8x16, kI8x16GtS, Int32LessThan, true) 1296 COMPARISON_CASE(Int8x16, kI8x16GeS, Int32LessThanOrEqual, true) 1297 COMPARISON_CASE(Int8x16, kI8x16LtU, Uint32LessThan, false) 1298 COMPARISON_CASE(Int8x16, kI8x16LeU, Uint32LessThanOrEqual, false) 1299 COMPARISON_CASE(Int8x16, kI8x16GtU, Uint32LessThan, true) 1300 COMPARISON_CASE(Int8x16, kI8x16GeU, Uint32LessThanOrEqual, true) 1301 #undef COMPARISON_CASE 1302 case IrOpcode::kF32x4Ne: { 1303 LowerNotEqual(node, SimdType::kFloat32x4, machine()->Float32Equal()); 1304 break; 1305 } 1306 case IrOpcode::kI32x4Ne: { 1307 LowerNotEqual(node, SimdType::kInt32x4, machine()->Word32Equal()); 1308 break; 1309 } 1310 case IrOpcode::kI16x8Ne: { 1311 LowerNotEqual(node, SimdType::kInt16x8, machine()->Word32Equal()); 1312 break; 1313 } 1314 case IrOpcode::kI8x16Ne: { 1315 LowerNotEqual(node, SimdType::kInt8x16, machine()->Word32Equal()); 1316 break; 1317 } 1318 case IrOpcode::kS128Select: { 1319 DCHECK_EQ(3, node->InputCount()); 1320 DCHECK(ReplacementType(node->InputAt(0)) == SimdType::kInt32x4 || 1321 ReplacementType(node->InputAt(0)) == SimdType::kInt16x8 || 1322 ReplacementType(node->InputAt(0)) == SimdType::kInt8x16); 1323 Node** boolean_input = GetReplacements(node->InputAt(0)); 1324 Node** rep_left = GetReplacementsWithType(node->InputAt(1), rep_type); 1325 Node** rep_right = GetReplacementsWithType(node->InputAt(2), rep_type); 1326 Node** rep_node = zone()->NewArray<Node*>(num_lanes); 1327 for (int i = 0; i < num_lanes; ++i) { 1328 Node* tmp1 = 1329 graph()->NewNode(machine()->Word32Xor(), rep_left[i], rep_right[i]); 1330 Node* tmp2 = 1331 graph()->NewNode(machine()->Word32And(), boolean_input[i], tmp1); 1332 rep_node[i] = 1333 graph()->NewNode(machine()->Word32Xor(), rep_right[i], tmp2); 1334 } 1335 ReplaceNode(node, rep_node, num_lanes); 1336 break; 1337 } 1338 case IrOpcode::kS8x16Shuffle: { 1339 DCHECK_EQ(2, node->InputCount()); 1340 const uint8_t* shuffle = OpParameter<uint8_t*>(node->op()); 1341 Node** rep_left = GetReplacementsWithType(node->InputAt(0), rep_type); 1342 Node** rep_right = GetReplacementsWithType(node->InputAt(1), rep_type); 1343 Node** rep_node = zone()->NewArray<Node*>(16); 1344 for (int i = 0; i < 16; i++) { 1345 int lane = shuffle[i]; 1346 rep_node[i] = lane < 16 ? rep_left[lane] : rep_right[lane - 16]; 1347 } 1348 ReplaceNode(node, rep_node, 16); 1349 break; 1350 } 1351 case IrOpcode::kS1x4AnyTrue: 1352 case IrOpcode::kS1x4AllTrue: 1353 case IrOpcode::kS1x8AnyTrue: 1354 case IrOpcode::kS1x8AllTrue: 1355 case IrOpcode::kS1x16AnyTrue: 1356 case IrOpcode::kS1x16AllTrue: { 1357 DCHECK_EQ(1, node->InputCount()); 1358 SimdType input_rep_type = ReplacementType(node->InputAt(0)); 1359 int input_num_lanes = NumLanes(input_rep_type); 1360 Node** rep = GetReplacements(node->InputAt(0)); 1361 Node** rep_node = zone()->NewArray<Node*>(num_lanes); 1362 Node* true_node = mcgraph_->Int32Constant(-1); 1363 Node* false_node = mcgraph_->Int32Constant(0); 1364 Node* tmp_result = false_node; 1365 if (node->opcode() == IrOpcode::kS1x4AllTrue || 1366 node->opcode() == IrOpcode::kS1x8AllTrue || 1367 node->opcode() == IrOpcode::kS1x16AllTrue) { 1368 tmp_result = true_node; 1369 } 1370 for (int i = 0; i < input_num_lanes; ++i) { 1371 Diamond is_false( 1372 graph(), common(), 1373 graph()->NewNode(machine()->Word32Equal(), rep[i], false_node)); 1374 if (node->opcode() == IrOpcode::kS1x4AllTrue || 1375 node->opcode() == IrOpcode::kS1x8AllTrue || 1376 node->opcode() == IrOpcode::kS1x16AllTrue) { 1377 tmp_result = is_false.Phi(MachineRepresentation::kWord32, false_node, 1378 tmp_result); 1379 } else { 1380 tmp_result = is_false.Phi(MachineRepresentation::kWord32, tmp_result, 1381 true_node); 1382 } 1383 } 1384 rep_node[0] = tmp_result; 1385 for (int i = 1; i < num_lanes; ++i) { 1386 rep_node[i] = nullptr; 1387 } 1388 ReplaceNode(node, rep_node, num_lanes); 1389 break; 1390 } 1391 default: { DefaultLowering(node); } 1392 } 1393 } 1394 1395 bool SimdScalarLowering::DefaultLowering(Node* node) { 1396 bool something_changed = false; 1397 for (int i = NodeProperties::PastValueIndex(node) - 1; i >= 0; i--) { 1398 Node* input = node->InputAt(i); 1399 if (HasReplacement(0, input)) { 1400 something_changed = true; 1401 node->ReplaceInput(i, GetReplacements(input)[0]); 1402 } 1403 if (HasReplacement(1, input)) { 1404 something_changed = true; 1405 for (int j = 1; j < ReplacementCount(input); ++j) { 1406 node->InsertInput(zone(), i + j, GetReplacements(input)[j]); 1407 } 1408 } 1409 } 1410 return something_changed; 1411 } 1412 1413 void SimdScalarLowering::ReplaceNode(Node* old, Node** new_nodes, int count) { 1414 replacements_[old->id()].node = zone()->NewArray<Node*>(count); 1415 for (int i = 0; i < count; ++i) { 1416 replacements_[old->id()].node[i] = new_nodes[i]; 1417 } 1418 replacements_[old->id()].num_replacements = count; 1419 } 1420 1421 bool SimdScalarLowering::HasReplacement(size_t index, Node* node) { 1422 return replacements_[node->id()].node != nullptr && 1423 replacements_[node->id()].node[index] != nullptr; 1424 } 1425 1426 SimdScalarLowering::SimdType SimdScalarLowering::ReplacementType(Node* node) { 1427 return replacements_[node->id()].type; 1428 } 1429 1430 Node** SimdScalarLowering::GetReplacements(Node* node) { 1431 Node** result = replacements_[node->id()].node; 1432 DCHECK(result); 1433 return result; 1434 } 1435 1436 int SimdScalarLowering::ReplacementCount(Node* node) { 1437 return replacements_[node->id()].num_replacements; 1438 } 1439 1440 void SimdScalarLowering::Int32ToFloat32(Node** replacements, Node** result) { 1441 for (int i = 0; i < kNumLanes32; ++i) { 1442 if (replacements[i] != nullptr) { 1443 result[i] = 1444 graph()->NewNode(machine()->BitcastInt32ToFloat32(), replacements[i]); 1445 } else { 1446 result[i] = nullptr; 1447 } 1448 } 1449 } 1450 1451 void SimdScalarLowering::Float32ToInt32(Node** replacements, Node** result) { 1452 for (int i = 0; i < kNumLanes32; ++i) { 1453 if (replacements[i] != nullptr) { 1454 result[i] = 1455 graph()->NewNode(machine()->BitcastFloat32ToInt32(), replacements[i]); 1456 } else { 1457 result[i] = nullptr; 1458 } 1459 } 1460 } 1461 1462 template <typename T> 1463 void SimdScalarLowering::Int32ToSmallerInt(Node** replacements, Node** result) { 1464 const int num_ints = sizeof(int32_t) / sizeof(T); 1465 const int bit_size = sizeof(T) * 8; 1466 const Operator* sign_extend; 1467 switch (sizeof(T)) { 1468 case 1: 1469 sign_extend = machine()->SignExtendWord8ToInt32(); 1470 break; 1471 case 2: 1472 sign_extend = machine()->SignExtendWord16ToInt32(); 1473 break; 1474 default: 1475 UNREACHABLE(); 1476 } 1477 1478 for (int i = 0; i < kNumLanes32; i++) { 1479 if (replacements[i] != nullptr) { 1480 for (int j = 0; j < num_ints; j++) { 1481 result[num_ints * i + j] = graph()->NewNode( 1482 sign_extend, 1483 graph()->NewNode(machine()->Word32Sar(), replacements[i], 1484 mcgraph_->Int32Constant(j * bit_size))); 1485 } 1486 } else { 1487 for (int j = 0; j < num_ints; j++) { 1488 result[num_ints * i + j] = nullptr; 1489 } 1490 } 1491 } 1492 } 1493 1494 template <typename T> 1495 void SimdScalarLowering::SmallerIntToInt32(Node** replacements, Node** result) { 1496 const int num_ints = sizeof(int32_t) / sizeof(T); 1497 const int bit_size = sizeof(T) * 8; 1498 const int bit_mask = (1 << bit_size) - 1; 1499 1500 for (int i = 0; i < kNumLanes32; ++i) { 1501 result[i] = mcgraph_->Int32Constant(0); 1502 for (int j = 0; j < num_ints; j++) { 1503 if (replacements[num_ints * i + j] != nullptr) { 1504 Node* clean_bits = graph()->NewNode(machine()->Word32And(), 1505 replacements[num_ints * i + j], 1506 mcgraph_->Int32Constant(bit_mask)); 1507 Node* shift = graph()->NewNode(machine()->Word32Shl(), clean_bits, 1508 mcgraph_->Int32Constant(j * bit_size)); 1509 result[i] = graph()->NewNode(machine()->Word32Or(), result[i], shift); 1510 } 1511 } 1512 } 1513 } 1514 1515 Node** SimdScalarLowering::GetReplacementsWithType(Node* node, SimdType type) { 1516 Node** replacements = GetReplacements(node); 1517 if (ReplacementType(node) == type) { 1518 return GetReplacements(node); 1519 } 1520 int num_lanes = NumLanes(type); 1521 Node** result = zone()->NewArray<Node*>(num_lanes); 1522 if (type == SimdType::kInt32x4) { 1523 if (ReplacementType(node) == SimdType::kFloat32x4) { 1524 Float32ToInt32(replacements, result); 1525 } else if (ReplacementType(node) == SimdType::kInt16x8) { 1526 SmallerIntToInt32<int16_t>(replacements, result); 1527 } else if (ReplacementType(node) == SimdType::kInt8x16) { 1528 SmallerIntToInt32<int8_t>(replacements, result); 1529 } else { 1530 UNREACHABLE(); 1531 } 1532 } else if (type == SimdType::kFloat32x4) { 1533 if (ReplacementType(node) == SimdType::kInt32x4) { 1534 Int32ToFloat32(replacements, result); 1535 } else if (ReplacementType(node) == SimdType::kInt16x8) { 1536 UNIMPLEMENTED(); 1537 } else { 1538 UNREACHABLE(); 1539 } 1540 } else if (type == SimdType::kInt16x8) { 1541 if (ReplacementType(node) == SimdType::kInt32x4) { 1542 Int32ToSmallerInt<int16_t>(replacements, result); 1543 } else if (ReplacementType(node) == SimdType::kFloat32x4) { 1544 UNIMPLEMENTED(); 1545 } else { 1546 UNREACHABLE(); 1547 } 1548 } else if (type == SimdType::kInt8x16) { 1549 if (ReplacementType(node) == SimdType::kInt32x4) { 1550 Int32ToSmallerInt<int8_t>(replacements, result); 1551 } else { 1552 UNIMPLEMENTED(); 1553 } 1554 } else { 1555 UNREACHABLE(); 1556 } 1557 return result; 1558 } 1559 1560 void SimdScalarLowering::PreparePhiReplacement(Node* phi) { 1561 MachineRepresentation rep = PhiRepresentationOf(phi->op()); 1562 if (rep == MachineRepresentation::kSimd128) { 1563 // We have to create the replacements for a phi node before we actually 1564 // lower the phi to break potential cycles in the graph. The replacements of 1565 // input nodes do not exist yet, so we use a placeholder node to pass the 1566 // graph verifier. 1567 int value_count = phi->op()->ValueInputCount(); 1568 SimdType type = ReplacementType(phi); 1569 int num_lanes = NumLanes(type); 1570 Node*** inputs_rep = zone()->NewArray<Node**>(num_lanes); 1571 for (int i = 0; i < num_lanes; ++i) { 1572 inputs_rep[i] = zone()->NewArray<Node*>(value_count + 1); 1573 inputs_rep[i][value_count] = NodeProperties::GetControlInput(phi, 0); 1574 } 1575 for (int i = 0; i < value_count; ++i) { 1576 for (int j = 0; j < num_lanes; ++j) { 1577 inputs_rep[j][i] = placeholder_; 1578 } 1579 } 1580 Node** rep_nodes = zone()->NewArray<Node*>(num_lanes); 1581 for (int i = 0; i < num_lanes; ++i) { 1582 rep_nodes[i] = graph()->NewNode( 1583 common()->Phi(MachineTypeFrom(type).representation(), value_count), 1584 value_count + 1, inputs_rep[i], false); 1585 } 1586 ReplaceNode(phi, rep_nodes, num_lanes); 1587 } 1588 } 1589 } // namespace compiler 1590 } // namespace internal 1591 } // namespace v8 1592