| OLD | NEW |
| 1 // Copyright 2015 the V8 project authors. All rights reserved. | 1 // Copyright 2015 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "src/compiler/wasm-compiler.h" | 5 #include "src/compiler/wasm-compiler.h" |
| 6 | 6 |
| 7 #include "src/isolate-inl.h" | 7 #include "src/isolate-inl.h" |
| 8 | 8 |
| 9 #include "src/base/platform/platform.h" | 9 #include "src/base/platform/platform.h" |
| 10 | 10 |
| (...skipping 724 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 735 } | 735 } |
| 736 case wasm::kExprI32Popcnt: { | 736 case wasm::kExprI32Popcnt: { |
| 737 if (m->Word32Popcnt().IsSupported()) { | 737 if (m->Word32Popcnt().IsSupported()) { |
| 738 op = m->Word32Popcnt().op(); | 738 op = m->Word32Popcnt().op(); |
| 739 break; | 739 break; |
| 740 } else { | 740 } else { |
| 741 return BuildI32Popcnt(input); | 741 return BuildI32Popcnt(input); |
| 742 } | 742 } |
| 743 } | 743 } |
| 744 case wasm::kExprF32Floor: { | 744 case wasm::kExprF32Floor: { |
| 745 if (m->Float32RoundDown().IsSupported()) { | 745 if (!m->Float32RoundDown().IsSupported()) return BuildF32Floor(input); |
| 746 op = m->Float32RoundDown().op(); | 746 op = m->Float32RoundDown().op(); |
| 747 break; | 747 break; |
| 748 } else { | |
| 749 op = UnsupportedOpcode(opcode); | |
| 750 break; | |
| 751 } | |
| 752 } | 748 } |
| 753 case wasm::kExprF32Ceil: { | 749 case wasm::kExprF32Ceil: { |
| 754 if (m->Float32RoundUp().IsSupported()) { | 750 if (!m->Float32RoundUp().IsSupported()) return BuildF32Ceil(input); |
| 755 op = m->Float32RoundUp().op(); | 751 op = m->Float32RoundUp().op(); |
| 756 break; | 752 break; |
| 757 } else { | |
| 758 op = UnsupportedOpcode(opcode); | |
| 759 break; | |
| 760 } | |
| 761 } | 753 } |
| 762 case wasm::kExprF32Trunc: { | 754 case wasm::kExprF32Trunc: { |
| 763 if (m->Float32RoundTruncate().IsSupported()) { | 755 if (!m->Float32RoundTruncate().IsSupported()) return BuildF32Trunc(input); |
| 764 op = m->Float32RoundTruncate().op(); | 756 op = m->Float32RoundTruncate().op(); |
| 765 } else { | |
| 766 return BuildF32Trunc(input); | |
| 767 } | |
| 768 break; | 757 break; |
| 769 } | 758 } |
| 770 case wasm::kExprF32NearestInt: { | 759 case wasm::kExprF32NearestInt: { |
| 771 if (m->Float32RoundTiesEven().IsSupported()) { | 760 if (!m->Float32RoundTiesEven().IsSupported()) |
| 772 op = m->Float32RoundTiesEven().op(); | 761 return BuildF32NearestInt(input); |
| 773 break; | 762 op = m->Float32RoundTiesEven().op(); |
| 774 } else { | 763 break; |
| 775 op = UnsupportedOpcode(opcode); | |
| 776 break; | |
| 777 } | |
| 778 } | 764 } |
| 779 case wasm::kExprF64Floor: { | 765 case wasm::kExprF64Floor: { |
| 780 if (m->Float64RoundDown().IsSupported()) { | 766 if (!m->Float64RoundDown().IsSupported()) return BuildF64Floor(input); |
| 781 op = m->Float64RoundDown().op(); | 767 op = m->Float64RoundDown().op(); |
| 782 break; | 768 break; |
| 783 } else { | |
| 784 op = UnsupportedOpcode(opcode); | |
| 785 break; | |
| 786 } | |
| 787 } | 769 } |
| 788 case wasm::kExprF64Ceil: { | 770 case wasm::kExprF64Ceil: { |
| 789 if (m->Float64RoundUp().IsSupported()) { | 771 if (!m->Float64RoundUp().IsSupported()) return BuildF64Ceil(input); |
| 790 op = m->Float64RoundUp().op(); | 772 op = m->Float64RoundUp().op(); |
| 791 break; | 773 break; |
| 792 } else { | |
| 793 op = UnsupportedOpcode(opcode); | |
| 794 break; | |
| 795 } | |
| 796 } | 774 } |
| 797 case wasm::kExprF64Trunc: { | 775 case wasm::kExprF64Trunc: { |
| 798 if (!m->Float64RoundTruncate().IsSupported()) return BuildF64Trunc(input); | 776 if (!m->Float64RoundTruncate().IsSupported()) return BuildF64Trunc(input); |
| 799 op = m->Float64RoundTruncate().op(); | 777 op = m->Float64RoundTruncate().op(); |
| 800 break; | 778 break; |
| 801 } | 779 } |
| 802 case wasm::kExprF64NearestInt: { | 780 case wasm::kExprF64NearestInt: { |
| 803 if (m->Float64RoundTiesEven().IsSupported()) { | 781 if (!m->Float64RoundTiesEven().IsSupported()) |
| 804 op = m->Float64RoundTiesEven().op(); | 782 return BuildF64NearestInt(input); |
| 805 break; | 783 op = m->Float64RoundTiesEven().op(); |
| 806 } else { | 784 break; |
| 807 op = UnsupportedOpcode(opcode); | |
| 808 break; | |
| 809 } | |
| 810 } | 785 } |
| 811 | 786 |
| 812 #if WASM_64 | 787 #if WASM_64 |
| 813 // Opcodes only supported on 64-bit platforms. | 788 // Opcodes only supported on 64-bit platforms. |
| 814 // TODO(titzer): query the machine operator builder here instead of #ifdef. | 789 // TODO(titzer): query the machine operator builder here instead of #ifdef. |
| 815 case wasm::kExprI32ConvertI64: | 790 case wasm::kExprI32ConvertI64: |
| 816 op = m->TruncateInt64ToInt32(); | 791 op = m->TruncateInt64ToInt32(); |
| 817 break; | 792 break; |
| 818 case wasm::kExprI64SConvertI32: | 793 case wasm::kExprI64SConvertI32: |
| 819 op = m->ChangeInt32ToInt64(); | 794 op = m->ChangeInt32ToInt64(); |
| (...skipping 538 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1358 result = Binop(wasm::kExprI64Add, | 1333 result = Binop(wasm::kExprI64Add, |
| 1359 Binop(wasm::kExprI64And, Binop(wasm::kExprI64ShrU, result, | 1334 Binop(wasm::kExprI64And, Binop(wasm::kExprI64ShrU, result, |
| 1360 jsgraph()->Int64Constant(32)), | 1335 jsgraph()->Int64Constant(32)), |
| 1361 jsgraph()->Int64Constant(0x00000000ffffffff)), | 1336 jsgraph()->Int64Constant(0x00000000ffffffff)), |
| 1362 Binop(wasm::kExprI64And, result, | 1337 Binop(wasm::kExprI64And, result, |
| 1363 jsgraph()->Int64Constant(0x00000000ffffffff))); | 1338 jsgraph()->Int64Constant(0x00000000ffffffff))); |
| 1364 | 1339 |
| 1365 return result; | 1340 return result; |
| 1366 } | 1341 } |
| 1367 | 1342 |
| 1343 Node* WasmGraphBuilder::BuildF32Trunc(Node* input) { |
| 1344 MachineType type = MachineType::Float32(); |
| 1345 ExternalReference ref = |
| 1346 ExternalReference::f32_trunc_wrapper_function(jsgraph()->isolate()); |
| 1347 return BuildRoundingInstruction(input, ref, type); |
| 1348 } |
| 1368 | 1349 |
| 1369 Node* WasmGraphBuilder::BuildF32Trunc(Node* input) { | 1350 Node* WasmGraphBuilder::BuildF32Floor(Node* input) { |
| 1370 // int32_t int_input = bitftoi(input); | 1351 MachineType type = MachineType::Float32(); |
| 1371 // int32_t exponent = int_input & 0x7f800000; | 1352 ExternalReference ref = |
| 1372 // if (exponent >= ((23 + 127) << 23)) { | 1353 ExternalReference::f32_floor_wrapper_function(jsgraph()->isolate()); |
| 1373 // if (input != input) { | 1354 return BuildRoundingInstruction(input, ref, type); |
| 1374 // return bititof(int_input | (1 << 22)); | 1355 } |
| 1375 // } | |
| 1376 // return input; | |
| 1377 // } | |
| 1378 // int32_t sign = int_input & 0x80000000; | |
| 1379 // if (exponent < (127 << 23)) { | |
| 1380 // return bititof(sign); | |
| 1381 // } | |
| 1382 // int32_t mantissa = int_input & 0x007fffff; | |
| 1383 // int32_t shift = (127 + 23) - (exponent >> 23); | |
| 1384 // int32_t new_mantissa = (mantissa >> shift) << shift; | |
| 1385 // int32_t result = new_mantissa | exponent | sign; | |
| 1386 // return bititof(result); | |
| 1387 | 1356 |
| 1388 Node* int_input = Unop(wasm::kExprI32ReinterpretF32, input); | 1357 Node* WasmGraphBuilder::BuildF32Ceil(Node* input) { |
| 1389 Node* exponent = | 1358 MachineType type = MachineType::Float32(); |
| 1390 Binop(wasm::kExprI32And, int_input, jsgraph()->Int32Constant(0x7f800000)); | 1359 ExternalReference ref = |
| 1360 ExternalReference::f32_ceil_wrapper_function(jsgraph()->isolate()); |
| 1361 return BuildRoundingInstruction(input, ref, type); |
| 1362 } |
| 1391 | 1363 |
| 1392 Node* sign = | 1364 Node* WasmGraphBuilder::BuildF32NearestInt(Node* input) { |
| 1393 Binop(wasm::kExprI32And, int_input, jsgraph()->Int32Constant(0x80000000)); | 1365 MachineType type = MachineType::Float32(); |
| 1394 | 1366 ExternalReference ref = |
| 1395 Node* result_out_of_range = int_input; | 1367 ExternalReference::f32_nearest_int_wrapper_function(jsgraph()->isolate()); |
| 1396 | 1368 return BuildRoundingInstruction(input, ref, type); |
| 1397 Node* result_nan = | |
| 1398 Binop(wasm::kExprI32Ior, int_input, jsgraph()->Int32Constant(1 << 22)); | |
| 1399 | |
| 1400 Node* result_zero = sign; | |
| 1401 | |
| 1402 Node* mantissa = | |
| 1403 Binop(wasm::kExprI32And, int_input, jsgraph()->Int32Constant(0x007fffff)); | |
| 1404 Node* shift = | |
| 1405 Binop(wasm::kExprI32Sub, jsgraph()->Int32Constant(23 + 127), | |
| 1406 Binop(wasm::kExprI32ShrU, exponent, jsgraph()->Int32Constant(23))); | |
| 1407 Node* new_mantissa = Binop(wasm::kExprI32Shl, | |
| 1408 Binop(wasm::kExprI32ShrU, mantissa, shift), shift); | |
| 1409 Node* result_truncate = | |
| 1410 Binop(wasm::kExprI32Ior, Binop(wasm::kExprI32Ior, new_mantissa, exponent), | |
| 1411 sign); | |
| 1412 | |
| 1413 Diamond is_zero( | |
| 1414 graph(), jsgraph()->common(), | |
| 1415 Binop(wasm::kExprI32LtU, exponent, jsgraph()->Int32Constant(127 << 23))); | |
| 1416 | |
| 1417 Node* result_within_range = | |
| 1418 is_zero.Phi(wasm::kAstI32, result_zero, result_truncate); | |
| 1419 | |
| 1420 Diamond input_nan(graph(), jsgraph()->common(), | |
| 1421 Binop(wasm::kExprF32Ne, input, input)); | |
| 1422 Node* result_exponent_geq_23 = | |
| 1423 input_nan.Phi(wasm::kAstI32, result_nan, result_out_of_range); | |
| 1424 | |
| 1425 Diamond exponent_geq_23(graph(), jsgraph()->common(), | |
| 1426 Binop(wasm::kExprI32GeU, exponent, | |
| 1427 jsgraph()->Int32Constant((23 + 127) << 23))); | |
| 1428 | |
| 1429 Node* result = exponent_geq_23.Phi(wasm::kAstI32, result_exponent_geq_23, | |
| 1430 result_within_range); | |
| 1431 | |
| 1432 return Unop(wasm::kExprF32ReinterpretI32, result); | |
| 1433 } | 1369 } |
| 1434 | 1370 |
| 1435 Node* WasmGraphBuilder::BuildF64Trunc(Node* input) { | 1371 Node* WasmGraphBuilder::BuildF64Trunc(Node* input) { |
| 1372 MachineType type = MachineType::Float64(); |
| 1373 ExternalReference ref = |
| 1374 ExternalReference::f64_trunc_wrapper_function(jsgraph()->isolate()); |
| 1375 return BuildRoundingInstruction(input, ref, type); |
| 1376 } |
| 1377 |
| 1378 Node* WasmGraphBuilder::BuildF64Floor(Node* input) { |
| 1379 MachineType type = MachineType::Float64(); |
| 1380 ExternalReference ref = |
| 1381 ExternalReference::f64_floor_wrapper_function(jsgraph()->isolate()); |
| 1382 return BuildRoundingInstruction(input, ref, type); |
| 1383 } |
| 1384 |
| 1385 Node* WasmGraphBuilder::BuildF64Ceil(Node* input) { |
| 1386 MachineType type = MachineType::Float64(); |
| 1387 ExternalReference ref = |
| 1388 ExternalReference::f64_ceil_wrapper_function(jsgraph()->isolate()); |
| 1389 return BuildRoundingInstruction(input, ref, type); |
| 1390 } |
| 1391 |
| 1392 Node* WasmGraphBuilder::BuildF64NearestInt(Node* input) { |
| 1393 MachineType type = MachineType::Float64(); |
| 1394 ExternalReference ref = |
| 1395 ExternalReference::f64_nearest_int_wrapper_function(jsgraph()->isolate()); |
| 1396 return BuildRoundingInstruction(input, ref, type); |
| 1397 } |
| 1398 |
| 1399 Node* WasmGraphBuilder::BuildRoundingInstruction(Node* input, |
| 1400 ExternalReference ref, |
| 1401 MachineType type) { |
| 1436 // We do truncation by calling a C function which calculates the truncation | 1402 // We do truncation by calling a C function which calculates the truncation |
| 1437 // for us. The input is passed to the C function as a double* to avoid double | 1403 // for us. The input is passed to the C function as a double* to avoid double |
| 1438 // parameters. For this we reserve a slot on the stack, store the parameter in | 1404 // parameters. For this we reserve a slot on the stack, store the parameter in |
| 1439 // that slot, pass a pointer to the slot to the C function, and after calling | 1405 // that slot, pass a pointer to the slot to the C function, and after calling |
| 1440 // the C function we collect the return value from the stack slot. | 1406 // the C function we collect the return value from the stack slot. |
| 1441 | 1407 |
| 1442 Node* stack_slot_param = graph()->NewNode( | 1408 Node* stack_slot_param = |
| 1443 jsgraph()->machine()->StackSlot(MachineRepresentation::kFloat64)); | 1409 graph()->NewNode(jsgraph()->machine()->StackSlot(type.representation())); |
| 1444 | 1410 |
| 1445 const Operator* store_op = jsgraph()->machine()->Store( | 1411 const Operator* store_op = jsgraph()->machine()->Store( |
| 1446 StoreRepresentation(MachineRepresentation::kFloat64, kNoWriteBarrier)); | 1412 StoreRepresentation(type.representation(), kNoWriteBarrier)); |
| 1447 *effect_ = | 1413 *effect_ = |
| 1448 graph()->NewNode(store_op, stack_slot_param, jsgraph()->Int32Constant(0), | 1414 graph()->NewNode(store_op, stack_slot_param, jsgraph()->Int32Constant(0), |
| 1449 input, *effect_, *control_); | 1415 input, *effect_, *control_); |
| 1450 | 1416 |
| 1451 Signature<MachineType>::Builder sig_builder(jsgraph()->zone(), 0, 1); | 1417 Signature<MachineType>::Builder sig_builder(jsgraph()->zone(), 0, 1); |
| 1452 sig_builder.AddParam(MachineType::Pointer()); | 1418 sig_builder.AddParam(MachineType::Pointer()); |
| 1453 Node* function = graph()->NewNode(jsgraph()->common()->ExternalConstant( | 1419 Node* function = graph()->NewNode(jsgraph()->common()->ExternalConstant(ref)); |
| 1454 ExternalReference::trunc64_wrapper_function(jsgraph()->isolate()))); | |
| 1455 | 1420 |
| 1456 Node* args[] = {function, stack_slot_param}; | 1421 Node* args[] = {function, stack_slot_param}; |
| 1457 | 1422 |
| 1458 BuildCCall(sig_builder.Build(), args); | 1423 BuildCCall(sig_builder.Build(), args); |
| 1459 | 1424 |
| 1460 const Operator* load_op = jsgraph()->machine()->Load(MachineType::Float64()); | 1425 const Operator* load_op = jsgraph()->machine()->Load(type); |
| 1461 | 1426 |
| 1462 Node* load = | 1427 Node* load = |
| 1463 graph()->NewNode(load_op, stack_slot_param, jsgraph()->Int32Constant(0), | 1428 graph()->NewNode(load_op, stack_slot_param, jsgraph()->Int32Constant(0), |
| 1464 *effect_, *control_); | 1429 *effect_, *control_); |
| 1465 *effect_ = load; | 1430 *effect_ = load; |
| 1466 return load; | 1431 return load; |
| 1467 } | 1432 } |
| 1468 | 1433 |
| 1469 Node* WasmGraphBuilder::BuildCCall(MachineSignature* sig, Node** args) { | 1434 Node* WasmGraphBuilder::BuildCCall(MachineSignature* sig, Node** args) { |
| 1470 const size_t params = sig->parameter_count(); | 1435 const size_t params = sig->parameter_count(); |
| (...skipping 694 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2165 module_env->module->GetName(function.name_offset)); | 2130 module_env->module->GetName(function.name_offset)); |
| 2166 } | 2131 } |
| 2167 | 2132 |
| 2168 return code; | 2133 return code; |
| 2169 } | 2134 } |
| 2170 | 2135 |
| 2171 | 2136 |
| 2172 } // namespace compiler | 2137 } // namespace compiler |
| 2173 } // namespace internal | 2138 } // namespace internal |
| 2174 } // namespace v8 | 2139 } // namespace v8 |
| OLD | NEW |