1 // Copyright 2014 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/js-builtin-reducer.h"
6 #include "src/compiler/js-graph.h"
7 #include "src/compiler/node-properties.h"
8 #include "src/compiler/simplified-operator.h"
9 #include "src/compiler/typer.h"
10 #include "src/isolate-inl.h"
11 #include "test/unittests/compiler/graph-unittest.h"
12 #include "test/unittests/compiler/node-test-utils.h"
13 #include "testing/gmock-support.h"
14
15 using testing::BitEq;
16 using testing::Capture;
17
18 namespace v8 {
19 namespace internal {
20 namespace compiler {
21
22 class JSBuiltinReducerTest : public TypedGraphTest {
23 public:
JSBuiltinReducerTest()24 JSBuiltinReducerTest() : javascript_(zone()) {}
25
26 protected:
Reduce(Node * node,MachineOperatorBuilder::Flags flags=MachineOperatorBuilder::Flag::kNoFlags)27 Reduction Reduce(Node* node, MachineOperatorBuilder::Flags flags =
28 MachineOperatorBuilder::Flag::kNoFlags) {
29 MachineOperatorBuilder machine(zone(), MachineType::PointerRepresentation(),
30 flags);
31 SimplifiedOperatorBuilder simplified(zone());
32 JSGraph jsgraph(isolate(), graph(), common(), javascript(), &simplified,
33 &machine);
34 // TODO(titzer): mock the GraphReducer here for better unit testing.
35 GraphReducer graph_reducer(zone(), graph());
36 JSBuiltinReducer reducer(&graph_reducer, &jsgraph);
37 return reducer.Reduce(node);
38 }
39
MathFunction(const char * name)40 Node* MathFunction(const char* name) {
41 Handle<Object> m =
42 JSObject::GetProperty(isolate()->global_object(),
43 isolate()->factory()->NewStringFromAsciiChecked(
44 "Math")).ToHandleChecked();
45 Handle<JSFunction> f = Handle<JSFunction>::cast(
46 JSObject::GetProperty(
47 m, isolate()->factory()->NewStringFromAsciiChecked(name))
48 .ToHandleChecked());
49 return HeapConstant(f);
50 }
51
javascript()52 JSOperatorBuilder* javascript() { return &javascript_; }
53
54 private:
55 JSOperatorBuilder javascript_;
56 };
57
58
59 namespace {
60
61 Type* const kIntegral32Types[] = {Type::UnsignedSmall(), Type::Negative32(),
62 Type::Unsigned31(), Type::SignedSmall(),
63 Type::Signed32(), Type::Unsigned32(),
64 Type::Integral32()};
65
66
67 const LanguageMode kLanguageModes[] = {SLOPPY, STRICT, STRONG};
68
69
70 // TODO(mstarzinger): Find a common place and unify with test-js-typed-lowering.
71 Type* const kNumberTypes[] = {
72 Type::UnsignedSmall(), Type::Negative32(), Type::Unsigned31(),
73 Type::SignedSmall(), Type::Signed32(), Type::Unsigned32(),
74 Type::Integral32(), Type::MinusZero(), Type::NaN(),
75 Type::OrderedNumber(), Type::PlainNumber(), Type::Number()};
76
77 } // namespace
78
79
80 // -----------------------------------------------------------------------------
81 // Math.max
82
83
TEST_F(JSBuiltinReducerTest,MathMax0)84 TEST_F(JSBuiltinReducerTest, MathMax0) {
85 Node* function = MathFunction("max");
86
87 Node* effect = graph()->start();
88 Node* control = graph()->start();
89 Node* context = UndefinedConstant();
90 Node* frame_state = graph()->start();
91 TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) {
92 Node* call = graph()->NewNode(javascript()->CallFunction(2, language_mode),
93 function, UndefinedConstant(), context,
94 frame_state, frame_state, effect, control);
95 Reduction r = Reduce(call);
96
97 ASSERT_TRUE(r.Changed());
98 EXPECT_THAT(r.replacement(), IsNumberConstant(-V8_INFINITY));
99 }
100 }
101
102
TEST_F(JSBuiltinReducerTest,MathMax1)103 TEST_F(JSBuiltinReducerTest, MathMax1) {
104 Node* function = MathFunction("max");
105
106 Node* effect = graph()->start();
107 Node* control = graph()->start();
108 Node* context = UndefinedConstant();
109 Node* frame_state = graph()->start();
110 TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) {
111 TRACED_FOREACH(Type*, t0, kNumberTypes) {
112 Node* p0 = Parameter(t0, 0);
113 Node* call =
114 graph()->NewNode(javascript()->CallFunction(3, language_mode),
115 function, UndefinedConstant(), p0, context,
116 frame_state, frame_state, effect, control);
117 Reduction r = Reduce(call);
118
119 ASSERT_TRUE(r.Changed());
120 EXPECT_THAT(r.replacement(), p0);
121 }
122 }
123 }
124
125
TEST_F(JSBuiltinReducerTest,MathMax2)126 TEST_F(JSBuiltinReducerTest, MathMax2) {
127 Node* function = MathFunction("max");
128
129 Node* effect = graph()->start();
130 Node* control = graph()->start();
131 Node* context = UndefinedConstant();
132 Node* frame_state = graph()->start();
133 TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) {
134 TRACED_FOREACH(Type*, t0, kIntegral32Types) {
135 TRACED_FOREACH(Type*, t1, kIntegral32Types) {
136 Node* p0 = Parameter(t0, 0);
137 Node* p1 = Parameter(t1, 1);
138 Node* call =
139 graph()->NewNode(javascript()->CallFunction(4, language_mode),
140 function, UndefinedConstant(), p0, p1, context,
141 frame_state, frame_state, effect, control);
142 Reduction r = Reduce(call);
143
144 ASSERT_TRUE(r.Changed());
145 EXPECT_THAT(r.replacement(),
146 IsSelect(MachineRepresentation::kNone,
147 IsNumberLessThan(p1, p0), p0, p1));
148 }
149 }
150 }
151 }
152
153
154 // -----------------------------------------------------------------------------
155 // Math.imul
156
157
TEST_F(JSBuiltinReducerTest,MathImul)158 TEST_F(JSBuiltinReducerTest, MathImul) {
159 Node* function = MathFunction("imul");
160
161 Node* effect = graph()->start();
162 Node* control = graph()->start();
163 Node* context = UndefinedConstant();
164 Node* frame_state = graph()->start();
165 TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) {
166 TRACED_FOREACH(Type*, t0, kIntegral32Types) {
167 TRACED_FOREACH(Type*, t1, kIntegral32Types) {
168 Node* p0 = Parameter(t0, 0);
169 Node* p1 = Parameter(t1, 1);
170 Node* call =
171 graph()->NewNode(javascript()->CallFunction(4, language_mode),
172 function, UndefinedConstant(), p0, p1, context,
173 frame_state, frame_state, effect, control);
174 Reduction r = Reduce(call);
175
176 ASSERT_TRUE(r.Changed());
177 EXPECT_THAT(r.replacement(), IsInt32Mul(p0, p1));
178 }
179 }
180 }
181 }
182
183
184 // -----------------------------------------------------------------------------
185 // Math.fround
186
187
TEST_F(JSBuiltinReducerTest,MathFround)188 TEST_F(JSBuiltinReducerTest, MathFround) {
189 Node* function = MathFunction("fround");
190
191 Node* effect = graph()->start();
192 Node* control = graph()->start();
193 Node* context = UndefinedConstant();
194 Node* frame_state = graph()->start();
195 TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) {
196 TRACED_FOREACH(Type*, t0, kNumberTypes) {
197 Node* p0 = Parameter(t0, 0);
198 Node* call =
199 graph()->NewNode(javascript()->CallFunction(3, language_mode),
200 function, UndefinedConstant(), p0, context,
201 frame_state, frame_state, effect, control);
202 Reduction r = Reduce(call);
203
204 ASSERT_TRUE(r.Changed());
205 EXPECT_THAT(r.replacement(), IsTruncateFloat64ToFloat32(p0));
206 }
207 }
208 }
209
210 } // namespace compiler
211 } // namespace internal
212 } // namespace v8
213