Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(208)

Side by Side Diff: src/compiler/wasm-compiler.cc

Issue 1839333002: [wasm] Fix asm.js semantics for divide by zero in WASM translation. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/compiler/wasm-compiler.h ('k') | src/wasm/wasm-opcodes.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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/elapsed-timer.h" 9 #include "src/base/platform/elapsed-timer.h"
10 #include "src/base/platform/platform.h" 10 #include "src/base/platform/platform.h"
(...skipping 375 matching lines...) Expand 10 before | Expand all | Expand 10 after
386 switch (opcode) { 386 switch (opcode) {
387 case wasm::kExprI32Add: 387 case wasm::kExprI32Add:
388 op = m->Int32Add(); 388 op = m->Int32Add();
389 break; 389 break;
390 case wasm::kExprI32Sub: 390 case wasm::kExprI32Sub:
391 op = m->Int32Sub(); 391 op = m->Int32Sub();
392 break; 392 break;
393 case wasm::kExprI32Mul: 393 case wasm::kExprI32Mul:
394 op = m->Int32Mul(); 394 op = m->Int32Mul();
395 break; 395 break;
396 case wasm::kExprI32DivS: { 396 case wasm::kExprI32DivS:
397 trap_->ZeroCheck32(kTrapDivByZero, right); 397 return BuildI32DivS(left, right);
398 Node* before = *control_;
399 Node* denom_is_m1;
400 Node* denom_is_not_m1;
401 Branch(graph()->NewNode(jsgraph()->machine()->Word32Equal(), right,
402 jsgraph()->Int32Constant(-1)),
403 &denom_is_m1, &denom_is_not_m1);
404 *control_ = denom_is_m1;
405 trap_->TrapIfEq32(kTrapDivUnrepresentable, left, kMinInt);
406 if (*control_ != denom_is_m1) {
407 *control_ = graph()->NewNode(jsgraph()->common()->Merge(2),
408 denom_is_not_m1, *control_);
409 } else {
410 *control_ = before;
411 }
412 return graph()->NewNode(m->Int32Div(), left, right, *control_);
413 }
414 case wasm::kExprI32DivU: 398 case wasm::kExprI32DivU:
415 op = m->Uint32Div(); 399 return BuildI32DivU(left, right);
416 return graph()->NewNode(op, left, right, 400 case wasm::kExprI32RemS:
417 trap_->ZeroCheck32(kTrapDivByZero, right)); 401 return BuildI32RemS(left, right);
418 case wasm::kExprI32RemS: {
419 trap_->ZeroCheck32(kTrapRemByZero, right);
420 Diamond d(graph(), jsgraph()->common(),
421 graph()->NewNode(jsgraph()->machine()->Word32Equal(), right,
422 jsgraph()->Int32Constant(-1)));
423
424 Node* rem = graph()->NewNode(m->Int32Mod(), left, right, d.if_false);
425
426 return d.Phi(MachineRepresentation::kWord32, jsgraph()->Int32Constant(0),
427 rem);
428 }
429 case wasm::kExprI32RemU: 402 case wasm::kExprI32RemU:
430 op = m->Uint32Mod(); 403 return BuildI32RemU(left, right);
431 return graph()->NewNode(op, left, right,
432 trap_->ZeroCheck32(kTrapRemByZero, right));
433 case wasm::kExprI32And: 404 case wasm::kExprI32And:
434 op = m->Word32And(); 405 op = m->Word32And();
435 break; 406 break;
436 case wasm::kExprI32Ior: 407 case wasm::kExprI32Ior:
437 op = m->Word32Or(); 408 op = m->Word32Or();
438 break; 409 break;
439 case wasm::kExprI32Xor: 410 case wasm::kExprI32Xor:
440 op = m->Word32Xor(); 411 op = m->Word32Xor();
441 break; 412 break;
442 case wasm::kExprI32Shl: 413 case wasm::kExprI32Shl:
(...skipping 1293 matching lines...) Expand 10 before | Expand all | Expand 10 after
1736 trap_->ZeroCheck32(kTrapFloatUnrepresentable, 1707 trap_->ZeroCheck32(kTrapFloatUnrepresentable,
1737 BuildCCall(sig_builder.Build(), args)); 1708 BuildCCall(sig_builder.Build(), args));
1738 const Operator* load_op = jsgraph()->machine()->Load(result_type); 1709 const Operator* load_op = jsgraph()->machine()->Load(result_type);
1739 Node* load = 1710 Node* load =
1740 graph()->NewNode(load_op, stack_slot_result, jsgraph()->Int32Constant(0), 1711 graph()->NewNode(load_op, stack_slot_result, jsgraph()->Int32Constant(0),
1741 *effect_, *control_); 1712 *effect_, *control_);
1742 *effect_ = load; 1713 *effect_ = load;
1743 return load; 1714 return load;
1744 } 1715 }
1745 1716
1717 Node* WasmGraphBuilder::BuildI32DivS(Node* left, Node* right) {
1718 MachineOperatorBuilder* m = jsgraph()->machine();
1719 if (module_ && module_->asm_js()) {
1720 // asm.js semantics return 0 on divide or mod by zero.
1721 if (m->Int32DivIsSafe()) {
1722 // The hardware instruction does the right thing (e.g. arm).
1723 return graph()->NewNode(m->Int32Div(), left, right, graph()->start());
1724 }
1725
1726 // Check denominator for zero.
1727 Diamond z(
1728 graph(), jsgraph()->common(),
1729 graph()->NewNode(m->Word32Equal(), right, jsgraph()->Int32Constant(0)),
1730 BranchHint::kFalse);
1731
1732 // Check numerator for -1. (avoid minint / -1 case).
1733 Diamond n(
1734 graph(), jsgraph()->common(),
1735 graph()->NewNode(m->Word32Equal(), right, jsgraph()->Int32Constant(-1)),
1736 BranchHint::kFalse);
1737
1738 Node* div = graph()->NewNode(m->Int32Div(), left, right, z.if_false);
1739 Node* neg =
1740 graph()->NewNode(m->Int32Sub(), jsgraph()->Int32Constant(0), left);
1741
1742 return n.Phi(MachineRepresentation::kWord32, neg,
1743 z.Phi(MachineRepresentation::kWord32,
1744 jsgraph()->Int32Constant(0), div));
1745 }
1746
1747 trap_->ZeroCheck32(kTrapDivByZero, right);
1748 Node* before = *control_;
1749 Node* denom_is_m1;
1750 Node* denom_is_not_m1;
1751 Branch(
1752 graph()->NewNode(m->Word32Equal(), right, jsgraph()->Int32Constant(-1)),
1753 &denom_is_m1, &denom_is_not_m1);
1754 *control_ = denom_is_m1;
1755 trap_->TrapIfEq32(kTrapDivUnrepresentable, left, kMinInt);
1756 if (*control_ != denom_is_m1) {
1757 *control_ = graph()->NewNode(jsgraph()->common()->Merge(2), denom_is_not_m1,
1758 *control_);
1759 } else {
1760 *control_ = before;
1761 }
1762 return graph()->NewNode(m->Int32Div(), left, right, *control_);
1763 }
1764
1765 Node* WasmGraphBuilder::BuildI32RemS(Node* left, Node* right) {
1766 MachineOperatorBuilder* m = jsgraph()->machine();
1767 if (module_ && module_->asm_js()) {
1768 // asm.js semantics return 0 on divide or mod by zero.
1769 if (m->Int32DivIsSafe()) {
1770 // The hardware instruction does the right thing (e.g. arm).
1771 return graph()->NewNode(m->Int32Mod(), left, right, graph()->start());
1772 }
1773
1774 // Explicit check for x % 0.
1775 Diamond z(
1776 graph(), jsgraph()->common(),
1777 graph()->NewNode(m->Word32Equal(), right, jsgraph()->Int32Constant(0)),
1778 BranchHint::kFalse);
1779
1780 // Explicit check for x % -1.
1781 Diamond d(
1782 graph(), jsgraph()->common(),
1783 graph()->NewNode(m->Word32Equal(), right, jsgraph()->Int32Constant(-1)),
1784 BranchHint::kFalse);
1785 d.Chain(z.if_false);
1786
1787 Node* rem =
1788 d.Phi(MachineRepresentation::kWord32, jsgraph()->Int32Constant(0),
1789 graph()->NewNode(m->Int32Mod(), left, right, d.if_false));
1790
1791 return z.Phi(MachineRepresentation::kWord32, jsgraph()->Int32Constant(0),
1792 rem);
1793 }
1794
1795 trap_->ZeroCheck32(kTrapRemByZero, right);
1796
1797 Diamond d(
1798 graph(), jsgraph()->common(),
1799 graph()->NewNode(m->Word32Equal(), right, jsgraph()->Int32Constant(-1)),
1800 BranchHint::kFalse);
1801 d.Chain(*control_);
1802
1803 Node* rem = d.Phi(MachineRepresentation::kWord32, jsgraph()->Int32Constant(0),
ahaas 2016/03/30 11:00:38 Is it necessary to introduce "rem" here?
titzer 2016/03/30 11:15:32 Done.
1804 graph()->NewNode(m->Int32Mod(), left, right, d.if_false));
1805 return rem;
1806 }
1807
1808 Node* WasmGraphBuilder::BuildI32DivU(Node* left, Node* right) {
1809 MachineOperatorBuilder* m = jsgraph()->machine();
1810 if (module_ && module_->asm_js()) {
1811 // asm.js semantics return 0 on divide or mod by zero.
1812 if (m->Uint32DivIsSafe()) {
1813 // The hardware instruction does the right thing (e.g. arm).
1814 return graph()->NewNode(m->Uint32Mod(), left, right, graph()->start());
ahaas 2016/03/30 11:00:37 m->Uint32Div()?
titzer 2016/03/30 11:15:32 Done.
1815 }
1816
1817 // Explicit check for x % 0.
1818 Diamond z(
1819 graph(), jsgraph()->common(),
1820 graph()->NewNode(m->Word32Equal(), right, jsgraph()->Int32Constant(0)),
1821 BranchHint::kFalse);
1822
ahaas 2016/03/30 11:00:37 z.Chain(*control_)?
titzer 2016/03/30 11:15:32 It's not necessary to chain the diamond here, beca
1823 Node* rem = graph()->NewNode(jsgraph()->machine()->Uint32Div(), left, right,
1824 z.if_false);
1825 return z.Phi(MachineRepresentation::kWord32, jsgraph()->Int32Constant(0),
1826 rem);
1827 }
1828 return graph()->NewNode(m->Uint32Div(), left, right,
1829 trap_->ZeroCheck32(kTrapDivByZero, right));
1830 }
1831
1832 Node* WasmGraphBuilder::BuildI32RemU(Node* left, Node* right) {
1833 MachineOperatorBuilder* m = jsgraph()->machine();
1834 if (module_ && module_->asm_js()) {
1835 // asm.js semantics return 0 on divide or mod by zero.
1836 if (m->Uint32DivIsSafe()) {
1837 // The hardware instruction does the right thing (e.g. arm).
1838 return graph()->NewNode(m->Uint32Mod(), left, right, graph()->start());
1839 }
1840
1841 // Explicit check for x % 0.
1842 Diamond z(
1843 graph(), jsgraph()->common(),
1844 graph()->NewNode(m->Word32Equal(), right, jsgraph()->Int32Constant(0)),
1845 BranchHint::kFalse);
1846
ahaas 2016/03/30 11:00:38 z.Chain(*control_)?
titzer 2016/03/30 11:15:32 Same as above.
1847 Node* rem = graph()->NewNode(jsgraph()->machine()->Uint32Mod(), left, right,
1848 z.if_false);
1849 return z.Phi(MachineRepresentation::kWord32, jsgraph()->Int32Constant(0),
1850 rem);
1851 }
1852
1853 return graph()->NewNode(m->Uint32Mod(), left, right,
1854 trap_->ZeroCheck32(kTrapRemByZero, right));
1855 }
1856
1746 Node* WasmGraphBuilder::BuildI64DivS(Node* left, Node* right) { 1857 Node* WasmGraphBuilder::BuildI64DivS(Node* left, Node* right) {
1747 if (jsgraph()->machine()->Is32()) { 1858 if (jsgraph()->machine()->Is32()) {
1748 return BuildDiv64Call( 1859 return BuildDiv64Call(
1749 left, right, ExternalReference::wasm_int64_div(jsgraph()->isolate()), 1860 left, right, ExternalReference::wasm_int64_div(jsgraph()->isolate()),
1750 MachineType::Int64(), kTrapDivByZero); 1861 MachineType::Int64(), kTrapDivByZero);
1751 } 1862 }
1752 trap_->ZeroCheck64(kTrapDivByZero, right); 1863 trap_->ZeroCheck64(kTrapDivByZero, right);
1753 Node* before = *control_; 1864 Node* before = *control_;
1754 Node* denom_is_m1; 1865 Node* denom_is_m1;
1755 Node* denom_is_not_m1; 1866 Node* denom_is_not_m1;
(...skipping 910 matching lines...) Expand 10 before | Expand all | Expand 10 after
2666 static_cast<int>(function.code_end_offset - function.code_start_offset), 2777 static_cast<int>(function.code_end_offset - function.code_start_offset),
2667 decode_ms, static_cast<int>(graph.NodeCount()), compile_ms); 2778 decode_ms, static_cast<int>(graph.NodeCount()), compile_ms);
2668 } 2779 }
2669 return code; 2780 return code;
2670 } 2781 }
2671 2782
2672 2783
2673 } // namespace compiler 2784 } // namespace compiler
2674 } // namespace internal 2785 } // namespace internal
2675 } // namespace v8 2786 } // namespace v8
OLDNEW
« no previous file with comments | « src/compiler/wasm-compiler.h ('k') | src/wasm/wasm-opcodes.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698