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/graph-unittest.h"
6 #include "src/compiler/js-builtin-reducer.h"
7 #include "src/compiler/js-graph.h"
8 #include "src/compiler/node-properties-inl.h"
9 #include "src/compiler/typer.h"
10 #include "testing/gmock-support.h"
11
12 using testing::Capture;
13
14 namespace v8 {
15 namespace internal {
16 namespace compiler {
17
18 class JSBuiltinReducerTest : public GraphTest {
19 public:
JSBuiltinReducerTest()20 JSBuiltinReducerTest() : javascript_(zone()) {}
21
22 protected:
Reduce(Node * node)23 Reduction Reduce(Node* node) {
24 Typer typer(zone());
25 MachineOperatorBuilder machine;
26 JSGraph jsgraph(graph(), common(), javascript(), &typer, &machine);
27 JSBuiltinReducer reducer(&jsgraph);
28 return reducer.Reduce(node);
29 }
30
Parameter(Type * t,int32_t index=0)31 Node* Parameter(Type* t, int32_t index = 0) {
32 Node* n = graph()->NewNode(common()->Parameter(index), graph()->start());
33 NodeProperties::SetBounds(n, Bounds(Type::None(), t));
34 return n;
35 }
36
UndefinedConstant()37 Node* UndefinedConstant() {
38 return HeapConstant(
39 Unique<HeapObject>::CreateImmovable(factory()->undefined_value()));
40 }
41
javascript()42 JSOperatorBuilder* javascript() { return &javascript_; }
43
44 private:
45 JSOperatorBuilder javascript_;
46 };
47
48
49 namespace {
50
51 // TODO(mstarzinger): Find a common place and unify with test-js-typed-lowering.
52 Type* const kNumberTypes[] = {
53 Type::UnsignedSmall(), Type::OtherSignedSmall(), Type::OtherUnsigned31(),
54 Type::OtherUnsigned32(), Type::OtherSigned32(), Type::SignedSmall(),
55 Type::Signed32(), Type::Unsigned32(), Type::Integral32(),
56 Type::MinusZero(), Type::NaN(), Type::OtherNumber(),
57 Type::OrderedNumber(), Type::Number()};
58
59 } // namespace
60
61
62 // -----------------------------------------------------------------------------
63 // Math.sqrt
64
65
TEST_F(JSBuiltinReducerTest,MathSqrt)66 TEST_F(JSBuiltinReducerTest, MathSqrt) {
67 Handle<JSFunction> f(isolate()->context()->math_sqrt_fun());
68
69 TRACED_FOREACH(Type*, t0, kNumberTypes) {
70 Node* p0 = Parameter(t0, 0);
71 Node* fun = HeapConstant(Unique<HeapObject>::CreateUninitialized(f));
72 Node* call = graph()->NewNode(javascript()->Call(3, NO_CALL_FUNCTION_FLAGS),
73 fun, UndefinedConstant(), p0);
74 Reduction r = Reduce(call);
75
76 ASSERT_TRUE(r.Changed());
77 EXPECT_THAT(r.replacement(), IsFloat64Sqrt(p0));
78 }
79 }
80
81
82 // -----------------------------------------------------------------------------
83 // Math.max
84
85
TEST_F(JSBuiltinReducerTest,MathMax0)86 TEST_F(JSBuiltinReducerTest, MathMax0) {
87 Handle<JSFunction> f(isolate()->context()->math_max_fun());
88
89 Node* fun = HeapConstant(Unique<HeapObject>::CreateUninitialized(f));
90 Node* call = graph()->NewNode(javascript()->Call(2, NO_CALL_FUNCTION_FLAGS),
91 fun, UndefinedConstant());
92 Reduction r = Reduce(call);
93
94 ASSERT_TRUE(r.Changed());
95 EXPECT_THAT(r.replacement(), IsNumberConstant(-V8_INFINITY));
96 }
97
98
TEST_F(JSBuiltinReducerTest,MathMax1)99 TEST_F(JSBuiltinReducerTest, MathMax1) {
100 Handle<JSFunction> f(isolate()->context()->math_max_fun());
101
102 TRACED_FOREACH(Type*, t0, kNumberTypes) {
103 Node* p0 = Parameter(t0, 0);
104 Node* fun = HeapConstant(Unique<HeapObject>::CreateUninitialized(f));
105 Node* call = graph()->NewNode(javascript()->Call(3, NO_CALL_FUNCTION_FLAGS),
106 fun, UndefinedConstant(), p0);
107 Reduction r = Reduce(call);
108
109 ASSERT_TRUE(r.Changed());
110 EXPECT_THAT(r.replacement(), p0);
111 }
112 }
113
114
TEST_F(JSBuiltinReducerTest,MathMax2)115 TEST_F(JSBuiltinReducerTest, MathMax2) {
116 Handle<JSFunction> f(isolate()->context()->math_max_fun());
117
118 TRACED_FOREACH(Type*, t0, kNumberTypes) {
119 TRACED_FOREACH(Type*, t1, kNumberTypes) {
120 Node* p0 = Parameter(t0, 0);
121 Node* p1 = Parameter(t1, 1);
122 Node* fun = HeapConstant(Unique<HeapObject>::CreateUninitialized(f));
123 Node* call =
124 graph()->NewNode(javascript()->Call(4, NO_CALL_FUNCTION_FLAGS), fun,
125 UndefinedConstant(), p0, p1);
126 Reduction r = Reduce(call);
127
128 if (t0->Is(Type::Integral32()) && t1->Is(Type::Integral32())) {
129 Capture<Node*> branch;
130 ASSERT_TRUE(r.Changed());
131 EXPECT_THAT(
132 r.replacement(),
133 IsPhi(kMachNone, p1, p0,
134 IsMerge(IsIfTrue(CaptureEq(&branch)),
135 IsIfFalse(AllOf(CaptureEq(&branch),
136 IsBranch(IsNumberLessThan(p0, p1),
137 graph()->start()))))));
138 } else {
139 ASSERT_FALSE(r.Changed());
140 EXPECT_EQ(IrOpcode::kJSCallFunction, call->opcode());
141 }
142 }
143 }
144 }
145
146
147 // -----------------------------------------------------------------------------
148 // Math.imul
149
150
TEST_F(JSBuiltinReducerTest,MathImul)151 TEST_F(JSBuiltinReducerTest, MathImul) {
152 Handle<JSFunction> f(isolate()->context()->math_imul_fun());
153
154 TRACED_FOREACH(Type*, t0, kNumberTypes) {
155 TRACED_FOREACH(Type*, t1, kNumberTypes) {
156 Node* p0 = Parameter(t0, 0);
157 Node* p1 = Parameter(t1, 1);
158 Node* fun = HeapConstant(Unique<HeapObject>::CreateUninitialized(f));
159 Node* call =
160 graph()->NewNode(javascript()->Call(4, NO_CALL_FUNCTION_FLAGS), fun,
161 UndefinedConstant(), p0, p1);
162 Reduction r = Reduce(call);
163
164 if (t0->Is(Type::Integral32()) && t1->Is(Type::Integral32())) {
165 ASSERT_TRUE(r.Changed());
166 EXPECT_THAT(r.replacement(), IsInt32Mul(p0, p1));
167 } else {
168 ASSERT_FALSE(r.Changed());
169 EXPECT_EQ(IrOpcode::kJSCallFunction, call->opcode());
170 }
171 }
172 }
173 }
174
175 } // namespace compiler
176 } // namespace internal
177 } // namespace v8
178