blob: 0dac0daa3fa4825a01801ff80cb8e29a86c3a791 [file] [log] [blame]
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001// 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
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005#include "src/compilation-dependencies.h"
Emily Bernierd0a1eb72015-03-24 16:35:39 -04006#include "src/compiler/js-graph.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007#include "src/compiler/js-typed-lowering.h"
Emily Bernierd0a1eb72015-03-24 16:35:39 -04008#include "src/compiler/machine-operator.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009#include "src/compiler/node-properties.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010#include "src/compiler/opcodes.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000011#include "src/compiler/operator-properties.h"
12#include "src/compiler/simplified-operator.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013#include "src/compiler/typer.h"
Emily Bernierd0a1eb72015-03-24 16:35:39 -040014#include "test/cctest/cctest.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000016namespace v8 {
17namespace internal {
18namespace compiler {
19
Ben Murdochb8a8cc12014-11-26 15:28:44 +000020class JSTypedLoweringTester : public HandleAndZoneScope {
21 public:
22 explicit JSTypedLoweringTester(int num_parameters = 0)
23 : isolate(main_isolate()),
24 binop(NULL),
25 unop(NULL),
26 javascript(main_zone()),
Emily Bernierd0a1eb72015-03-24 16:35:39 -040027 machine(main_zone()),
Ben Murdochb8a8cc12014-11-26 15:28:44 +000028 simplified(main_zone()),
29 common(main_zone()),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000030 deps(main_isolate(), main_zone()),
Ben Murdochb8a8cc12014-11-26 15:28:44 +000031 graph(main_zone()),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000032 typer(main_isolate(), &graph),
Ben Murdochb8a8cc12014-11-26 15:28:44 +000033 context_node(NULL) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040034 graph.SetStart(graph.NewNode(common.Start(num_parameters)));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000035 graph.SetEnd(graph.NewNode(common.End(1), graph.start()));
Emily Bernierd0a1eb72015-03-24 16:35:39 -040036 typer.Run();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000037 }
38
39 Isolate* isolate;
40 const Operator* binop;
41 const Operator* unop;
42 JSOperatorBuilder javascript;
43 MachineOperatorBuilder machine;
44 SimplifiedOperatorBuilder simplified;
45 CommonOperatorBuilder common;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000046 CompilationDependencies deps;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000047 Graph graph;
48 Typer typer;
49 Node* context_node;
Ben Murdoch61f157c2016-09-16 13:49:30 +010050 BinaryOperationHints const binop_hints = BinaryOperationHints::Any();
51 CompareOperationHints const compare_hints = CompareOperationHints::Any();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000052
53 Node* Parameter(Type* t, int32_t index = 0) {
54 Node* n = graph.NewNode(common.Parameter(index), graph.start());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000055 NodeProperties::SetType(n, t);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000056 return n;
57 }
58
59 Node* UndefinedConstant() {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000060 Handle<HeapObject> value = isolate->factory()->undefined_value();
61 return graph.NewNode(common.HeapConstant(value));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000062 }
63
Emily Bernierd0a1eb72015-03-24 16:35:39 -040064 Node* HeapConstant(Handle<HeapObject> constant) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000065 return graph.NewNode(common.HeapConstant(constant));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000066 }
67
68 Node* EmptyFrameState(Node* context) {
69 Node* parameters = graph.NewNode(common.StateValues(0));
70 Node* locals = graph.NewNode(common.StateValues(0));
71 Node* stack = graph.NewNode(common.StateValues(0));
72
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000073 Node* state_node = graph.NewNode(
74 common.FrameState(BailoutId::None(), OutputFrameStateCombine::Ignore(),
75 nullptr),
76 parameters, locals, stack, context, UndefinedConstant(), graph.start());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000077
78 return state_node;
79 }
80
81 Node* reduce(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000082 JSGraph jsgraph(main_isolate(), &graph, &common, &javascript, &simplified,
83 &machine);
84 // TODO(titzer): mock the GraphReducer here for better unit testing.
85 GraphReducer graph_reducer(main_zone(), &graph);
86 JSTypedLowering reducer(&graph_reducer, &deps,
87 JSTypedLowering::kDeoptimizationEnabled, &jsgraph,
88 main_zone());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000089 Reduction reduction = reducer.Reduce(node);
90 if (reduction.Changed()) return reduction.replacement();
91 return node;
92 }
93
94 Node* start() { return graph.start(); }
95
96 Node* context() {
97 if (context_node == NULL) {
98 context_node = graph.NewNode(common.Parameter(-1), graph.start());
99 }
100 return context_node;
101 }
102
103 Node* control() { return start(); }
104
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000105 void CheckBinop(IrOpcode::Value expected, Node* node) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000106 CHECK_EQ(expected, node->opcode());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000107 }
108
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000109 void CheckBinop(const Operator* expected, Node* node) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000110 CHECK_EQ(expected->opcode(), node->op()->opcode());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000111 }
112
113 Node* ReduceUnop(const Operator* op, Type* input_type) {
114 return reduce(Unop(op, Parameter(input_type)));
115 }
116
117 Node* ReduceBinop(const Operator* op, Type* left_type, Type* right_type) {
118 return reduce(Binop(op, Parameter(left_type, 0), Parameter(right_type, 1)));
119 }
120
121 Node* Binop(const Operator* op, Node* left, Node* right) {
122 // JS binops also require context, effect, and control
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000123 std::vector<Node*> inputs;
124 inputs.push_back(left);
125 inputs.push_back(right);
126 if (OperatorProperties::HasContextInput(op)) {
127 inputs.push_back(context());
128 }
129 for (int i = 0; i < OperatorProperties::GetFrameStateInputCount(op); i++) {
130 inputs.push_back(EmptyFrameState(context()));
131 }
132 if (op->EffectInputCount() > 0) {
133 inputs.push_back(start());
134 }
135 if (op->ControlInputCount() > 0) {
136 inputs.push_back(control());
137 }
138 return graph.NewNode(op, static_cast<int>(inputs.size()),
139 &(inputs.front()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000140 }
141
142 Node* Unop(const Operator* op, Node* input) {
143 // JS unops also require context, effect, and control
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000144 if (OperatorProperties::GetFrameStateInputCount(op) > 0) {
145 CHECK_EQ(1, OperatorProperties::GetFrameStateInputCount(op));
146 return graph.NewNode(op, input, context(), EmptyFrameState(context()),
147 start(), control());
148 } else {
149 return graph.NewNode(op, input, context(), start(), control());
150 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000151 }
152
153 Node* UseForEffect(Node* node) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100154 Node* merge = graph.NewNode(common.Merge(1), start());
155 return graph.NewNode(common.EffectPhi(1), node, merge);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000156 }
157
158 void CheckEffectInput(Node* effect, Node* use) {
159 CHECK_EQ(effect, NodeProperties::GetEffectInput(use));
160 }
161
162 void CheckInt32Constant(int32_t expected, Node* result) {
163 CHECK_EQ(IrOpcode::kInt32Constant, result->opcode());
164 CHECK_EQ(expected, OpParameter<int32_t>(result));
165 }
166
167 void CheckNumberConstant(double expected, Node* result) {
168 CHECK_EQ(IrOpcode::kNumberConstant, result->opcode());
169 CHECK_EQ(expected, OpParameter<double>(result));
170 }
171
172 void CheckNaN(Node* result) {
173 CHECK_EQ(IrOpcode::kNumberConstant, result->opcode());
174 double value = OpParameter<double>(result);
175 CHECK(std::isnan(value));
176 }
177
178 void CheckTrue(Node* result) {
179 CheckHandle(isolate->factory()->true_value(), result);
180 }
181
182 void CheckFalse(Node* result) {
183 CheckHandle(isolate->factory()->false_value(), result);
184 }
185
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000186 void CheckHandle(Handle<HeapObject> expected, Node* result) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000187 CHECK_EQ(IrOpcode::kHeapConstant, result->opcode());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000188 Handle<HeapObject> value = OpParameter<Handle<HeapObject>>(result);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000189 CHECK_EQ(*expected, *value);
190 }
191};
192
193static Type* kStringTypes[] = {Type::InternalizedString(), Type::OtherString(),
194 Type::String()};
195
196
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000197static Type* kInt32Types[] = {Type::UnsignedSmall(), Type::Negative32(),
198 Type::Unsigned31(), Type::SignedSmall(),
199 Type::Signed32(), Type::Unsigned32(),
200 Type::Integral32()};
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000201
202
203static Type* kNumberTypes[] = {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000204 Type::UnsignedSmall(), Type::Negative32(), Type::Unsigned31(),
205 Type::SignedSmall(), Type::Signed32(), Type::Unsigned32(),
206 Type::Integral32(), Type::MinusZero(), Type::NaN(),
207 Type::OrderedNumber(), Type::PlainNumber(), Type::Number()};
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000208
209
210static Type* I32Type(bool is_signed) {
211 return is_signed ? Type::Signed32() : Type::Unsigned32();
212}
213
214
215static IrOpcode::Value NumberToI32(bool is_signed) {
216 return is_signed ? IrOpcode::kNumberToInt32 : IrOpcode::kNumberToUint32;
217}
218
219
220// TODO(turbofan): Lowering of StringAdd is disabled for now.
221#if 0
Ben Murdoch097c5b22016-05-18 11:27:45 +0100222TEST(StringBinops) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000223 JSTypedLoweringTester R;
224
225 for (size_t i = 0; i < arraysize(kStringTypes); ++i) {
226 Node* p0 = R.Parameter(kStringTypes[i], 0);
227
228 for (size_t j = 0; j < arraysize(kStringTypes); ++j) {
229 Node* p1 = R.Parameter(kStringTypes[j], 1);
230
Ben Murdoch097c5b22016-05-18 11:27:45 +0100231 Node* add = R.Binop(R.javascript.Add(), p0, p1);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000232 Node* r = R.reduce(add);
233
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000234 R.CheckBinop(IrOpcode::kStringAdd, r);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000235 CHECK_EQ(p0, r->InputAt(0));
236 CHECK_EQ(p1, r->InputAt(1));
237 }
238 }
239}
240#endif
241
Ben Murdoch097c5b22016-05-18 11:27:45 +0100242TEST(AddNumber1) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000243 JSTypedLoweringTester R;
244 for (size_t i = 0; i < arraysize(kNumberTypes); ++i) {
245 Node* p0 = R.Parameter(kNumberTypes[i], 0);
246 Node* p1 = R.Parameter(kNumberTypes[i], 1);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100247 Node* add = R.Binop(R.javascript.Add(BinaryOperationHints::Any()), p0, p1);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000248 Node* r = R.reduce(add);
249
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000250 R.CheckBinop(IrOpcode::kNumberAdd, r);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000251 CHECK_EQ(p0, r->InputAt(0));
252 CHECK_EQ(p1, r->InputAt(1));
253 }
254}
255
Ben Murdoch097c5b22016-05-18 11:27:45 +0100256TEST(NumberBinops) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000257 JSTypedLoweringTester R;
258 const Operator* ops[] = {
Ben Murdoch61f157c2016-09-16 13:49:30 +0100259 R.javascript.Add(R.binop_hints), R.simplified.NumberAdd(),
260 R.javascript.Subtract(R.binop_hints), R.simplified.NumberSubtract(),
261 R.javascript.Multiply(R.binop_hints), R.simplified.NumberMultiply(),
262 R.javascript.Divide(R.binop_hints), R.simplified.NumberDivide(),
263 R.javascript.Modulus(R.binop_hints), R.simplified.NumberModulus(),
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000264 };
265
266 for (size_t i = 0; i < arraysize(kNumberTypes); ++i) {
267 Node* p0 = R.Parameter(kNumberTypes[i], 0);
268
269 for (size_t j = 0; j < arraysize(kNumberTypes); ++j) {
270 Node* p1 = R.Parameter(kNumberTypes[j], 1);
271
272 for (size_t k = 0; k < arraysize(ops); k += 2) {
273 Node* add = R.Binop(ops[k], p0, p1);
274 Node* r = R.reduce(add);
275
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000276 R.CheckBinop(ops[k + 1], r);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000277 CHECK_EQ(p0, r->InputAt(0));
278 CHECK_EQ(p1, r->InputAt(1));
279 }
280 }
281 }
282}
283
284
285static void CheckToI32(Node* old_input, Node* new_input, bool is_signed) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000286 Type* old_type = NodeProperties::GetType(old_input);
287 Type* new_type = NodeProperties::GetType(new_input);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000288 Type* expected_type = I32Type(is_signed);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400289 CHECK(new_type->Is(expected_type));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000290 if (old_type->Is(expected_type)) {
291 CHECK_EQ(old_input, new_input);
292 } else if (new_input->opcode() == IrOpcode::kNumberConstant) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000293 double v = OpParameter<double>(new_input);
294 double e = static_cast<double>(is_signed ? FastD2I(v) : FastD2UI(v));
295 CHECK_EQ(e, v);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000296 }
297}
298
299
300// A helper class for testing lowering of bitwise shift operators.
301class JSBitwiseShiftTypedLoweringTester : public JSTypedLoweringTester {
302 public:
Ben Murdoch097c5b22016-05-18 11:27:45 +0100303 JSBitwiseShiftTypedLoweringTester() : JSTypedLoweringTester() {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000304 int i = 0;
Ben Murdoch61f157c2016-09-16 13:49:30 +0100305 set(i++, javascript.ShiftLeft(binop_hints), true);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000306 set(i++, simplified.NumberShiftLeft(), false);
Ben Murdoch61f157c2016-09-16 13:49:30 +0100307 set(i++, javascript.ShiftRight(binop_hints), true);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000308 set(i++, simplified.NumberShiftRight(), false);
Ben Murdoch61f157c2016-09-16 13:49:30 +0100309 set(i++, javascript.ShiftRightLogical(binop_hints), false);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000310 set(i++, simplified.NumberShiftRightLogical(), false);
311 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000312 static const int kNumberOps = 6;
313 const Operator* ops[kNumberOps];
314 bool signedness[kNumberOps];
315
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000316 private:
317 void set(int idx, const Operator* op, bool s) {
318 ops[idx] = op;
319 signedness[idx] = s;
320 }
321};
322
323
324TEST(Int32BitwiseShifts) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100325 JSBitwiseShiftTypedLoweringTester R;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000326
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000327 Type* types[] = {
328 Type::SignedSmall(), Type::UnsignedSmall(), Type::Negative32(),
329 Type::Unsigned31(), Type::Unsigned32(), Type::Signed32(),
330 Type::MinusZero(), Type::NaN(), Type::Undefined(),
331 Type::Null(), Type::Boolean(), Type::Number(),
332 Type::PlainNumber(), Type::String()};
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000333
334 for (size_t i = 0; i < arraysize(types); ++i) {
335 Node* p0 = R.Parameter(types[i], 0);
336
337 for (size_t j = 0; j < arraysize(types); ++j) {
338 Node* p1 = R.Parameter(types[j], 1);
339
340 for (int k = 0; k < R.kNumberOps; k += 2) {
341 Node* add = R.Binop(R.ops[k], p0, p1);
342 Node* r = R.reduce(add);
343
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000344 R.CheckBinop(R.ops[k + 1], r);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000345 Node* r0 = r->InputAt(0);
346 Node* r1 = r->InputAt(1);
347
348 CheckToI32(p0, r0, R.signedness[k]);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000349 CheckToI32(p1, r1, false);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000350 }
351 }
352 }
353}
354
355
356// A helper class for testing lowering of bitwise operators.
357class JSBitwiseTypedLoweringTester : public JSTypedLoweringTester {
358 public:
Ben Murdoch097c5b22016-05-18 11:27:45 +0100359 JSBitwiseTypedLoweringTester() : JSTypedLoweringTester() {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000360 int i = 0;
Ben Murdoch61f157c2016-09-16 13:49:30 +0100361 set(i++, javascript.BitwiseOr(binop_hints), true);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000362 set(i++, simplified.NumberBitwiseOr(), true);
Ben Murdoch61f157c2016-09-16 13:49:30 +0100363 set(i++, javascript.BitwiseXor(binop_hints), true);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000364 set(i++, simplified.NumberBitwiseXor(), true);
Ben Murdoch61f157c2016-09-16 13:49:30 +0100365 set(i++, javascript.BitwiseAnd(binop_hints), true);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000366 set(i++, simplified.NumberBitwiseAnd(), true);
367 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000368 static const int kNumberOps = 6;
369 const Operator* ops[kNumberOps];
370 bool signedness[kNumberOps];
371
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000372 private:
373 void set(int idx, const Operator* op, bool s) {
374 ops[idx] = op;
375 signedness[idx] = s;
376 }
377};
378
379
380TEST(Int32BitwiseBinops) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100381 JSBitwiseTypedLoweringTester R;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000382
383 Type* types[] = {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400384 Type::SignedSmall(), Type::UnsignedSmall(), Type::Unsigned32(),
385 Type::Signed32(), Type::MinusZero(), Type::NaN(),
386 Type::OrderedNumber(), Type::PlainNumber(), Type::Undefined(),
387 Type::Null(), Type::Boolean(), Type::Number(),
388 Type::String()};
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000389
390 for (size_t i = 0; i < arraysize(types); ++i) {
391 Node* p0 = R.Parameter(types[i], 0);
392
393 for (size_t j = 0; j < arraysize(types); ++j) {
394 Node* p1 = R.Parameter(types[j], 1);
395
396 for (int k = 0; k < R.kNumberOps; k += 2) {
397 Node* add = R.Binop(R.ops[k], p0, p1);
398 Node* r = R.reduce(add);
399
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000400 R.CheckBinop(R.ops[k + 1], r);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000401
402 CheckToI32(p0, r->InputAt(0), R.signedness[k]);
403 CheckToI32(p1, r->InputAt(1), R.signedness[k + 1]);
404 }
405 }
406 }
407}
408
409
410TEST(JSToNumber1) {
411 JSTypedLoweringTester R;
412 const Operator* ton = R.javascript.ToNumber();
413
414 for (size_t i = 0; i < arraysize(kNumberTypes); i++) { // ToNumber(number)
415 Node* r = R.ReduceUnop(ton, kNumberTypes[i]);
416 CHECK_EQ(IrOpcode::kParameter, r->opcode());
417 }
418
419 { // ToNumber(undefined)
420 Node* r = R.ReduceUnop(ton, Type::Undefined());
421 R.CheckNaN(r);
422 }
423
424 { // ToNumber(null)
425 Node* r = R.ReduceUnop(ton, Type::Null());
426 R.CheckNumberConstant(0.0, r);
427 }
428}
429
430
431TEST(JSToNumber_replacement) {
432 JSTypedLoweringTester R;
433
434 Type* types[] = {Type::Null(), Type::Undefined(), Type::Number()};
435
436 for (size_t i = 0; i < arraysize(types); i++) {
437 Node* n = R.Parameter(types[i]);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000438 Node* c =
439 R.graph.NewNode(R.javascript.ToNumber(), n, R.context(),
440 R.EmptyFrameState(R.context()), R.start(), R.start());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000441 Node* effect_use = R.UseForEffect(c);
442 Node* add = R.graph.NewNode(R.simplified.ReferenceEqual(Type::Any()), n, c);
443
444 R.CheckEffectInput(c, effect_use);
445 Node* r = R.reduce(c);
446
447 if (types[i]->Is(Type::Number())) {
448 CHECK_EQ(n, r);
449 } else {
450 CHECK_EQ(IrOpcode::kNumberConstant, r->opcode());
451 }
452
453 CHECK_EQ(n, add->InputAt(0));
454 CHECK_EQ(r, add->InputAt(1));
455 R.CheckEffectInput(R.start(), effect_use);
456 }
457}
458
459
460TEST(JSToNumberOfConstant) {
461 JSTypedLoweringTester R;
462
463 const Operator* ops[] = {
464 R.common.NumberConstant(0), R.common.NumberConstant(-1),
465 R.common.NumberConstant(0.1), R.common.Int32Constant(1177),
466 R.common.Float64Constant(0.99)};
467
468 for (size_t i = 0; i < arraysize(ops); i++) {
469 Node* n = R.graph.NewNode(ops[i]);
470 Node* convert = R.Unop(R.javascript.ToNumber(), n);
471 Node* r = R.reduce(convert);
472 // Note that either outcome below is correct. It only depends on whether
473 // the types of constants are eagerly computed or only computed by the
474 // typing pass.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000475 if (NodeProperties::GetType(n)->Is(Type::Number())) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000476 // If number constants are eagerly typed, then reduction should
477 // remove the ToNumber.
478 CHECK_EQ(n, r);
479 } else {
480 // Otherwise, type-based lowering should only look at the type, and
481 // *not* try to constant fold.
482 CHECK_EQ(convert, r);
483 }
484 }
485}
486
487
488TEST(JSToNumberOfNumberOrOtherPrimitive) {
489 JSTypedLoweringTester R;
490 Type* others[] = {Type::Undefined(), Type::Null(), Type::Boolean(),
491 Type::String()};
492
493 for (size_t i = 0; i < arraysize(others); i++) {
494 Type* t = Type::Union(Type::Number(), others[i], R.main_zone());
495 Node* r = R.ReduceUnop(R.javascript.ToNumber(), t);
Ben Murdoch61f157c2016-09-16 13:49:30 +0100496 CHECK_EQ(IrOpcode::kPlainPrimitiveToNumber, r->opcode());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000497 }
498}
499
500
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000501TEST(JSToString1) {
502 JSTypedLoweringTester R;
503
504 for (size_t i = 0; i < arraysize(kStringTypes); i++) {
505 Node* r = R.ReduceUnop(R.javascript.ToString(), kStringTypes[i]);
506 CHECK_EQ(IrOpcode::kParameter, r->opcode());
507 }
508
509 const Operator* op = R.javascript.ToString();
510
511 { // ToString(undefined) => "undefined"
512 Node* r = R.ReduceUnop(op, Type::Undefined());
513 R.CheckHandle(R.isolate->factory()->undefined_string(), r);
514 }
515
516 { // ToString(null) => "null"
517 Node* r = R.ReduceUnop(op, Type::Null());
518 R.CheckHandle(R.isolate->factory()->null_string(), r);
519 }
520
521 { // ToString(boolean)
522 Node* r = R.ReduceUnop(op, Type::Boolean());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000523 CHECK_EQ(IrOpcode::kSelect, r->opcode());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000524 }
525
526 { // ToString(number)
527 Node* r = R.ReduceUnop(op, Type::Number());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000528 CHECK_EQ(IrOpcode::kJSToString, r->opcode());
529 }
530
531 { // ToString(string)
532 Node* r = R.ReduceUnop(op, Type::String());
533 CHECK_EQ(IrOpcode::kParameter, r->opcode()); // No-op
534 }
535
536 { // ToString(object)
537 Node* r = R.ReduceUnop(op, Type::Object());
538 CHECK_EQ(IrOpcode::kJSToString, r->opcode()); // No reduction.
539 }
540}
541
542
543TEST(JSToString_replacement) {
544 JSTypedLoweringTester R;
545
546 Type* types[] = {Type::Null(), Type::Undefined(), Type::String()};
547
548 for (size_t i = 0; i < arraysize(types); i++) {
549 Node* n = R.Parameter(types[i]);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000550 Node* c =
551 R.graph.NewNode(R.javascript.ToString(), n, R.context(),
552 R.EmptyFrameState(R.context()), R.start(), R.start());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000553 Node* effect_use = R.UseForEffect(c);
554 Node* add = R.graph.NewNode(R.simplified.ReferenceEqual(Type::Any()), n, c);
555
556 R.CheckEffectInput(c, effect_use);
557 Node* r = R.reduce(c);
558
559 if (types[i]->Is(Type::String())) {
560 CHECK_EQ(n, r);
561 } else {
562 CHECK_EQ(IrOpcode::kHeapConstant, r->opcode());
563 }
564
565 CHECK_EQ(n, add->InputAt(0));
566 CHECK_EQ(r, add->InputAt(1));
567 R.CheckEffectInput(R.start(), effect_use);
568 }
569}
570
Ben Murdoch097c5b22016-05-18 11:27:45 +0100571TEST(StringComparison) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000572 JSTypedLoweringTester R;
573
574 const Operator* ops[] = {
Ben Murdoch61f157c2016-09-16 13:49:30 +0100575 R.javascript.LessThan(CompareOperationHints::Any()),
576 R.simplified.StringLessThan(),
577 R.javascript.LessThanOrEqual(CompareOperationHints::Any()),
578 R.simplified.StringLessThanOrEqual(),
579 R.javascript.GreaterThan(CompareOperationHints::Any()),
580 R.simplified.StringLessThan(),
581 R.javascript.GreaterThanOrEqual(CompareOperationHints::Any()),
582 R.simplified.StringLessThanOrEqual()};
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000583
584 for (size_t i = 0; i < arraysize(kStringTypes); i++) {
585 Node* p0 = R.Parameter(kStringTypes[i], 0);
586 for (size_t j = 0; j < arraysize(kStringTypes); j++) {
587 Node* p1 = R.Parameter(kStringTypes[j], 1);
588
589 for (size_t k = 0; k < arraysize(ops); k += 2) {
590 Node* cmp = R.Binop(ops[k], p0, p1);
591 Node* r = R.reduce(cmp);
592
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000593 R.CheckBinop(ops[k + 1], r);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000594 if (k >= 4) {
595 // GreaterThan and GreaterThanOrEqual commute the inputs
596 // and use the LessThan and LessThanOrEqual operators.
597 CHECK_EQ(p1, r->InputAt(0));
598 CHECK_EQ(p0, r->InputAt(1));
599 } else {
600 CHECK_EQ(p0, r->InputAt(0));
601 CHECK_EQ(p1, r->InputAt(1));
602 }
603 }
604 }
605 }
606}
607
608
609static void CheckIsConvertedToNumber(Node* val, Node* converted) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000610 if (NodeProperties::GetType(val)->Is(Type::Number())) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000611 CHECK_EQ(val, converted);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000612 } else if (NodeProperties::GetType(val)->Is(Type::Boolean())) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000613 CHECK_EQ(IrOpcode::kBooleanToNumber, converted->opcode());
614 CHECK_EQ(val, converted->InputAt(0));
615 } else {
616 if (converted->opcode() == IrOpcode::kNumberConstant) return;
617 CHECK_EQ(IrOpcode::kJSToNumber, converted->opcode());
618 CHECK_EQ(val, converted->InputAt(0));
619 }
620}
621
Ben Murdoch097c5b22016-05-18 11:27:45 +0100622TEST(NumberComparison) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000623 JSTypedLoweringTester R;
624
625 const Operator* ops[] = {
Ben Murdoch61f157c2016-09-16 13:49:30 +0100626 R.javascript.LessThan(CompareOperationHints::Any()),
627 R.simplified.NumberLessThan(),
628 R.javascript.LessThanOrEqual(CompareOperationHints::Any()),
629 R.simplified.NumberLessThanOrEqual(),
630 R.javascript.GreaterThan(CompareOperationHints::Any()),
631 R.simplified.NumberLessThan(),
632 R.javascript.GreaterThanOrEqual(CompareOperationHints::Any()),
633 R.simplified.NumberLessThanOrEqual()};
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000634
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400635 Node* const p0 = R.Parameter(Type::Number(), 0);
636 Node* const p1 = R.Parameter(Type::Number(), 1);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000637
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400638 for (size_t k = 0; k < arraysize(ops); k += 2) {
639 Node* cmp = R.Binop(ops[k], p0, p1);
640 Node* r = R.reduce(cmp);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000641
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000642 R.CheckBinop(ops[k + 1], r);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400643 if (k >= 4) {
644 // GreaterThan and GreaterThanOrEqual commute the inputs
645 // and use the LessThan and LessThanOrEqual operators.
646 CheckIsConvertedToNumber(p1, r->InputAt(0));
647 CheckIsConvertedToNumber(p0, r->InputAt(1));
648 } else {
649 CheckIsConvertedToNumber(p0, r->InputAt(0));
650 CheckIsConvertedToNumber(p1, r->InputAt(1));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000651 }
652 }
653}
654
Ben Murdoch097c5b22016-05-18 11:27:45 +0100655TEST(MixedComparison1) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000656 JSTypedLoweringTester R;
657
658 Type* types[] = {Type::Number(), Type::String(),
659 Type::Union(Type::Number(), Type::String(), R.main_zone())};
660
661 for (size_t i = 0; i < arraysize(types); i++) {
662 Node* p0 = R.Parameter(types[i], 0);
663
664 for (size_t j = 0; j < arraysize(types); j++) {
665 Node* p1 = R.Parameter(types[j], 1);
666 {
Ben Murdoch61f157c2016-09-16 13:49:30 +0100667 const Operator* less_than =
668 R.javascript.LessThan(CompareOperationHints::Any());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000669 Node* cmp = R.Binop(less_than, p0, p1);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000670 Node* r = R.reduce(cmp);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000671 if (types[i]->Is(Type::String()) && types[j]->Is(Type::String())) {
672 R.CheckBinop(R.simplified.StringLessThan(), r);
673 } else if ((types[i]->Is(Type::Number()) &&
674 types[j]->Is(Type::Number())) ||
Ben Murdoch097c5b22016-05-18 11:27:45 +0100675 (!types[i]->Maybe(Type::String()) ||
676 !types[j]->Maybe(Type::String()))) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000677 R.CheckBinop(R.simplified.NumberLessThan(), r);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000678 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000679 // No reduction of mixed types.
680 CHECK_EQ(r->op(), less_than);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000681 }
682 }
683 }
684 }
685}
686
Ben Murdoch097c5b22016-05-18 11:27:45 +0100687TEST(RemoveToNumberEffects) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000688 JSTypedLoweringTester R;
689
690 Node* effect_use = NULL;
691 for (int i = 0; i < 10; i++) {
692 Node* p0 = R.Parameter(Type::Number());
693 Node* ton = R.Unop(R.javascript.ToNumber(), p0);
694 Node* frame_state = R.EmptyFrameState(R.context());
695 effect_use = NULL;
696
697 switch (i) {
698 case 0:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000699 CHECK_EQ(1, OperatorProperties::GetFrameStateInputCount(
700 R.javascript.ToNumber()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000701 effect_use = R.graph.NewNode(R.javascript.ToNumber(), p0, R.context(),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000702 frame_state, ton, R.start());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000703 break;
704 case 1:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000705 CHECK_EQ(1, OperatorProperties::GetFrameStateInputCount(
706 R.javascript.ToNumber()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000707 effect_use = R.graph.NewNode(R.javascript.ToNumber(), ton, R.context(),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000708 frame_state, ton, R.start());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000709 break;
710 case 2:
711 effect_use = R.graph.NewNode(R.common.EffectPhi(1), ton, R.start());
712 case 3:
Ben Murdoch61f157c2016-09-16 13:49:30 +0100713 effect_use = R.graph.NewNode(R.javascript.Add(R.binop_hints), ton, ton,
714 R.context(), frame_state, frame_state, ton,
715 R.start());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000716 break;
717 case 4:
Ben Murdoch61f157c2016-09-16 13:49:30 +0100718 effect_use = R.graph.NewNode(R.javascript.Add(R.binop_hints), p0, p0,
719 R.context(), frame_state, frame_state, ton,
720 R.start());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000721 break;
722 case 5:
723 effect_use = R.graph.NewNode(R.common.Return(), p0, ton, R.start());
724 break;
725 case 6:
726 effect_use = R.graph.NewNode(R.common.Return(), ton, ton, R.start());
727 }
728
729 R.CheckEffectInput(R.start(), ton);
730 if (effect_use != NULL) R.CheckEffectInput(ton, effect_use);
731
732 Node* r = R.reduce(ton);
733 CHECK_EQ(p0, r);
734 CHECK_NE(R.start(), r);
735
736 if (effect_use != NULL) {
737 R.CheckEffectInput(R.start(), effect_use);
738 // Check that value uses of ToNumber() do not go to start().
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400739 for (int i = 0; i < effect_use->op()->ValueInputCount(); i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000740 CHECK_NE(R.start(), effect_use->InputAt(i));
741 }
742 }
743 }
744
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000745 CHECK(!effect_use); // should have done all cases above.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000746}
747
748
749// Helper class for testing the reduction of a single binop.
750class BinopEffectsTester {
751 public:
752 explicit BinopEffectsTester(const Operator* op, Type* t0, Type* t1)
753 : R(),
754 p0(R.Parameter(t0, 0)),
755 p1(R.Parameter(t1, 1)),
756 binop(R.Binop(op, p0, p1)),
757 effect_use(R.graph.NewNode(R.common.EffectPhi(1), binop, R.start())) {
758 // Effects should be ordered start -> binop -> effect_use
759 R.CheckEffectInput(R.start(), binop);
760 R.CheckEffectInput(binop, effect_use);
761 result = R.reduce(binop);
762 }
763
764 JSTypedLoweringTester R;
765 Node* p0;
766 Node* p1;
767 Node* binop;
768 Node* effect_use;
769 Node* result;
770
771 void CheckEffectsRemoved() { R.CheckEffectInput(R.start(), effect_use); }
772
773 void CheckEffectOrdering(Node* n0) {
774 R.CheckEffectInput(R.start(), n0);
775 R.CheckEffectInput(n0, effect_use);
776 }
777
778 void CheckEffectOrdering(Node* n0, Node* n1) {
779 R.CheckEffectInput(R.start(), n0);
780 R.CheckEffectInput(n0, n1);
781 R.CheckEffectInput(n1, effect_use);
782 }
783
784 Node* CheckConvertedInput(IrOpcode::Value opcode, int which, bool effects) {
785 return CheckConverted(opcode, result->InputAt(which), effects);
786 }
787
788 Node* CheckConverted(IrOpcode::Value opcode, Node* node, bool effects) {
789 CHECK_EQ(opcode, node->opcode());
790 if (effects) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400791 CHECK_LT(0, node->op()->EffectInputCount());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000792 } else {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400793 CHECK_EQ(0, node->op()->EffectInputCount());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000794 }
795 return node;
796 }
797
798 Node* CheckNoOp(int which) {
799 CHECK_EQ(which == 0 ? p0 : p1, result->InputAt(which));
800 return result->InputAt(which);
801 }
802};
803
804
805// Helper function for strict and non-strict equality reductions.
806void CheckEqualityReduction(JSTypedLoweringTester* R, bool strict, Node* l,
807 Node* r, IrOpcode::Value expected) {
808 for (int j = 0; j < 2; j++) {
809 Node* p0 = j == 0 ? l : r;
810 Node* p1 = j == 1 ? l : r;
811
812 {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000813 const Operator* op =
Ben Murdoch61f157c2016-09-16 13:49:30 +0100814 strict ? R->javascript.StrictEqual(CompareOperationHints::Any())
815 : R->javascript.Equal(CompareOperationHints::Any());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000816 Node* eq = R->Binop(op, p0, p1);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000817 Node* r = R->reduce(eq);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000818 R->CheckBinop(expected, r);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000819 }
820
821 {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000822 const Operator* op =
Ben Murdoch61f157c2016-09-16 13:49:30 +0100823 strict ? R->javascript.StrictNotEqual(CompareOperationHints::Any())
824 : R->javascript.NotEqual(CompareOperationHints::Any());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000825 Node* ne = R->Binop(op, p0, p1);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000826 Node* n = R->reduce(ne);
827 CHECK_EQ(IrOpcode::kBooleanNot, n->opcode());
828 Node* r = n->InputAt(0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000829 R->CheckBinop(expected, r);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000830 }
831 }
832}
833
834
835TEST(EqualityForNumbers) {
836 JSTypedLoweringTester R;
837
838 Type* simple_number_types[] = {Type::UnsignedSmall(), Type::SignedSmall(),
839 Type::Signed32(), Type::Unsigned32(),
840 Type::Number()};
841
842
843 for (size_t i = 0; i < arraysize(simple_number_types); ++i) {
844 Node* p0 = R.Parameter(simple_number_types[i], 0);
845
846 for (size_t j = 0; j < arraysize(simple_number_types); ++j) {
847 Node* p1 = R.Parameter(simple_number_types[j], 1);
848
849 CheckEqualityReduction(&R, true, p0, p1, IrOpcode::kNumberEqual);
850 CheckEqualityReduction(&R, false, p0, p1, IrOpcode::kNumberEqual);
851 }
852 }
853}
854
855
856TEST(StrictEqualityForRefEqualTypes) {
857 JSTypedLoweringTester R;
858
859 Type* types[] = {Type::Undefined(), Type::Null(), Type::Boolean(),
860 Type::Object(), Type::Receiver()};
861
862 Node* p0 = R.Parameter(Type::Any());
863 for (size_t i = 0; i < arraysize(types); i++) {
864 Node* p1 = R.Parameter(types[i]);
865 CheckEqualityReduction(&R, true, p0, p1, IrOpcode::kReferenceEqual);
866 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000867}
868
Ben Murdoch097c5b22016-05-18 11:27:45 +0100869TEST(StrictEqualityForUnique) {
870 JSTypedLoweringTester R;
871
872 Node* p0 = R.Parameter(Type::Unique());
873 Node* p1 = R.Parameter(Type::Unique());
874 CheckEqualityReduction(&R, true, p0, p1, IrOpcode::kReferenceEqual);
875 CheckEqualityReduction(&R, true, p1, p0, IrOpcode::kReferenceEqual);
876}
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000877
878TEST(StringEquality) {
879 JSTypedLoweringTester R;
880 Node* p0 = R.Parameter(Type::String());
881 Node* p1 = R.Parameter(Type::String());
882
883 CheckEqualityReduction(&R, true, p0, p1, IrOpcode::kStringEqual);
884 CheckEqualityReduction(&R, false, p0, p1, IrOpcode::kStringEqual);
885}
886
Ben Murdoch097c5b22016-05-18 11:27:45 +0100887TEST(RemovePureNumberBinopEffects) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000888 JSTypedLoweringTester R;
889
890 const Operator* ops[] = {
Ben Murdoch61f157c2016-09-16 13:49:30 +0100891 R.javascript.Equal(R.compare_hints),
892 R.simplified.NumberEqual(),
893 R.javascript.Add(R.binop_hints),
894 R.simplified.NumberAdd(),
895 R.javascript.Subtract(R.binop_hints),
896 R.simplified.NumberSubtract(),
897 R.javascript.Multiply(R.binop_hints),
898 R.simplified.NumberMultiply(),
899 R.javascript.Divide(R.binop_hints),
900 R.simplified.NumberDivide(),
901 R.javascript.Modulus(R.binop_hints),
902 R.simplified.NumberModulus(),
903 R.javascript.LessThan(R.compare_hints),
904 R.simplified.NumberLessThan(),
905 R.javascript.LessThanOrEqual(R.compare_hints),
906 R.simplified.NumberLessThanOrEqual(),
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000907 };
908
909 for (size_t j = 0; j < arraysize(ops); j += 2) {
910 BinopEffectsTester B(ops[j], Type::Number(), Type::Number());
911 CHECK_EQ(ops[j + 1]->opcode(), B.result->op()->opcode());
912
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000913 B.R.CheckBinop(B.result->opcode(), B.result);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000914
915 B.CheckNoOp(0);
916 B.CheckNoOp(1);
917
918 B.CheckEffectsRemoved();
919 }
920}
921
922
923TEST(OrderNumberBinopEffects1) {
924 JSTypedLoweringTester R;
925
926 const Operator* ops[] = {
Ben Murdoch61f157c2016-09-16 13:49:30 +0100927 R.javascript.Subtract(R.binop_hints), R.simplified.NumberSubtract(),
928 R.javascript.Multiply(R.binop_hints), R.simplified.NumberMultiply(),
929 R.javascript.Divide(R.binop_hints), R.simplified.NumberDivide(),
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000930 };
931
932 for (size_t j = 0; j < arraysize(ops); j += 2) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400933 BinopEffectsTester B(ops[j], Type::Symbol(), Type::Symbol());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000934 CHECK_EQ(ops[j + 1]->opcode(), B.result->op()->opcode());
935
936 Node* i0 = B.CheckConvertedInput(IrOpcode::kJSToNumber, 0, true);
937 Node* i1 = B.CheckConvertedInput(IrOpcode::kJSToNumber, 1, true);
938
939 CHECK_EQ(B.p0, i0->InputAt(0));
940 CHECK_EQ(B.p1, i1->InputAt(0));
941
942 // Effects should be ordered start -> i0 -> i1 -> effect_use
943 B.CheckEffectOrdering(i0, i1);
944 }
945}
946
947
948TEST(OrderNumberBinopEffects2) {
949 JSTypedLoweringTester R;
950
951 const Operator* ops[] = {
Ben Murdoch61f157c2016-09-16 13:49:30 +0100952 R.javascript.Add(R.binop_hints), R.simplified.NumberAdd(),
953 R.javascript.Subtract(R.binop_hints), R.simplified.NumberSubtract(),
954 R.javascript.Multiply(R.binop_hints), R.simplified.NumberMultiply(),
955 R.javascript.Divide(R.binop_hints), R.simplified.NumberDivide(),
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000956 };
957
958 for (size_t j = 0; j < arraysize(ops); j += 2) {
959 BinopEffectsTester B(ops[j], Type::Number(), Type::Symbol());
960
961 Node* i0 = B.CheckNoOp(0);
962 Node* i1 = B.CheckConvertedInput(IrOpcode::kJSToNumber, 1, true);
963
964 CHECK_EQ(B.p0, i0);
965 CHECK_EQ(B.p1, i1->InputAt(0));
966
967 // Effects should be ordered start -> i1 -> effect_use
968 B.CheckEffectOrdering(i1);
969 }
970
971 for (size_t j = 0; j < arraysize(ops); j += 2) {
972 BinopEffectsTester B(ops[j], Type::Symbol(), Type::Number());
973
974 Node* i0 = B.CheckConvertedInput(IrOpcode::kJSToNumber, 0, true);
975 Node* i1 = B.CheckNoOp(1);
976
977 CHECK_EQ(B.p0, i0->InputAt(0));
978 CHECK_EQ(B.p1, i1);
979
980 // Effects should be ordered start -> i0 -> effect_use
981 B.CheckEffectOrdering(i0);
982 }
983}
984
985
986TEST(OrderCompareEffects) {
987 JSTypedLoweringTester R;
988
989 const Operator* ops[] = {
Ben Murdoch61f157c2016-09-16 13:49:30 +0100990 R.javascript.GreaterThan(R.compare_hints), R.simplified.NumberLessThan(),
991 R.javascript.GreaterThanOrEqual(R.compare_hints),
992 R.simplified.NumberLessThanOrEqual(),
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000993 };
994
995 for (size_t j = 0; j < arraysize(ops); j += 2) {
996 BinopEffectsTester B(ops[j], Type::Symbol(), Type::String());
997 CHECK_EQ(ops[j + 1]->opcode(), B.result->op()->opcode());
998
Ben Murdochda12d292016-06-02 14:46:10 +0100999 Node* i0 = B.CheckConvertedInput(IrOpcode::kStringToNumber, 0, false);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001000 Node* i1 = B.CheckConvertedInput(IrOpcode::kJSToNumber, 1, true);
1001
1002 // Inputs should be commuted.
1003 CHECK_EQ(B.p1, i0->InputAt(0));
1004 CHECK_EQ(B.p0, i1->InputAt(0));
1005
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001006 // But effects should be ordered start -> i1 -> effect_use
1007 B.CheckEffectOrdering(i1);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001008 }
1009
1010 for (size_t j = 0; j < arraysize(ops); j += 2) {
1011 BinopEffectsTester B(ops[j], Type::Number(), Type::Symbol());
1012
1013 Node* i0 = B.CheckConvertedInput(IrOpcode::kJSToNumber, 0, true);
1014 Node* i1 = B.result->InputAt(1);
1015
1016 CHECK_EQ(B.p1, i0->InputAt(0)); // Should be commuted.
1017 CHECK_EQ(B.p0, i1);
1018
1019 // Effects should be ordered start -> i1 -> effect_use
1020 B.CheckEffectOrdering(i0);
1021 }
1022
1023 for (size_t j = 0; j < arraysize(ops); j += 2) {
1024 BinopEffectsTester B(ops[j], Type::Symbol(), Type::Number());
1025
1026 Node* i0 = B.result->InputAt(0);
1027 Node* i1 = B.CheckConvertedInput(IrOpcode::kJSToNumber, 1, true);
1028
1029 CHECK_EQ(B.p1, i0); // Should be commuted.
1030 CHECK_EQ(B.p0, i1->InputAt(0));
1031
1032 // Effects should be ordered start -> i0 -> effect_use
1033 B.CheckEffectOrdering(i1);
1034 }
1035}
1036
1037
1038TEST(Int32BinopEffects) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001039 JSBitwiseTypedLoweringTester R;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001040 for (int j = 0; j < R.kNumberOps; j += 2) {
1041 bool signed_left = R.signedness[j], signed_right = R.signedness[j + 1];
1042 BinopEffectsTester B(R.ops[j], I32Type(signed_left), I32Type(signed_right));
1043 CHECK_EQ(R.ops[j + 1]->opcode(), B.result->op()->opcode());
1044
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001045 B.R.CheckBinop(B.result->opcode(), B.result);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001046
1047 B.CheckNoOp(0);
1048 B.CheckNoOp(1);
1049
1050 B.CheckEffectsRemoved();
1051 }
1052
1053 for (int j = 0; j < R.kNumberOps; j += 2) {
1054 bool signed_left = R.signedness[j], signed_right = R.signedness[j + 1];
1055 BinopEffectsTester B(R.ops[j], Type::Number(), Type::Number());
1056 CHECK_EQ(R.ops[j + 1]->opcode(), B.result->op()->opcode());
1057
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001058 B.R.CheckBinop(B.result->opcode(), B.result);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001059
1060 B.CheckConvertedInput(NumberToI32(signed_left), 0, false);
1061 B.CheckConvertedInput(NumberToI32(signed_right), 1, false);
1062
1063 B.CheckEffectsRemoved();
1064 }
1065
1066 for (int j = 0; j < R.kNumberOps; j += 2) {
1067 bool signed_left = R.signedness[j], signed_right = R.signedness[j + 1];
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001068 BinopEffectsTester B(R.ops[j], Type::Number(), Type::Primitive());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001069
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001070 B.R.CheckBinop(B.result->opcode(), B.result);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001071
1072 Node* i0 = B.CheckConvertedInput(NumberToI32(signed_left), 0, false);
1073 Node* i1 = B.CheckConvertedInput(NumberToI32(signed_right), 1, false);
1074
1075 CHECK_EQ(B.p0, i0->InputAt(0));
1076 Node* ii1 = B.CheckConverted(IrOpcode::kJSToNumber, i1->InputAt(0), true);
1077
1078 CHECK_EQ(B.p1, ii1->InputAt(0));
1079
1080 B.CheckEffectOrdering(ii1);
1081 }
1082
1083 for (int j = 0; j < R.kNumberOps; j += 2) {
1084 bool signed_left = R.signedness[j], signed_right = R.signedness[j + 1];
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001085 BinopEffectsTester B(R.ops[j], Type::Primitive(), Type::Number());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001086
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001087 B.R.CheckBinop(B.result->opcode(), B.result);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001088
1089 Node* i0 = B.CheckConvertedInput(NumberToI32(signed_left), 0, false);
1090 Node* i1 = B.CheckConvertedInput(NumberToI32(signed_right), 1, false);
1091
1092 Node* ii0 = B.CheckConverted(IrOpcode::kJSToNumber, i0->InputAt(0), true);
1093 CHECK_EQ(B.p1, i1->InputAt(0));
1094
1095 CHECK_EQ(B.p0, ii0->InputAt(0));
1096
1097 B.CheckEffectOrdering(ii0);
1098 }
1099
1100 for (int j = 0; j < R.kNumberOps; j += 2) {
1101 bool signed_left = R.signedness[j], signed_right = R.signedness[j + 1];
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001102 BinopEffectsTester B(R.ops[j], Type::Primitive(), Type::Primitive());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001103
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001104 B.R.CheckBinop(B.result->opcode(), B.result);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001105
1106 Node* i0 = B.CheckConvertedInput(NumberToI32(signed_left), 0, false);
1107 Node* i1 = B.CheckConvertedInput(NumberToI32(signed_right), 1, false);
1108
1109 Node* ii0 = B.CheckConverted(IrOpcode::kJSToNumber, i0->InputAt(0), true);
1110 Node* ii1 = B.CheckConverted(IrOpcode::kJSToNumber, i1->InputAt(0), true);
1111
1112 CHECK_EQ(B.p0, ii0->InputAt(0));
1113 CHECK_EQ(B.p1, ii1->InputAt(0));
1114
1115 B.CheckEffectOrdering(ii0, ii1);
1116 }
1117}
1118
Ben Murdoch097c5b22016-05-18 11:27:45 +01001119TEST(Int32AddNarrowing) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001120 {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001121 JSBitwiseTypedLoweringTester R;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001122
1123 for (int o = 0; o < R.kNumberOps; o += 2) {
1124 for (size_t i = 0; i < arraysize(kInt32Types); i++) {
1125 Node* n0 = R.Parameter(kInt32Types[i]);
1126 for (size_t j = 0; j < arraysize(kInt32Types); j++) {
1127 Node* n1 = R.Parameter(kInt32Types[j]);
1128 Node* one = R.graph.NewNode(R.common.NumberConstant(1));
1129
1130 for (int l = 0; l < 2; l++) {
1131 Node* add_node = R.Binop(R.simplified.NumberAdd(), n0, n1);
1132 Node* or_node =
1133 R.Binop(R.ops[o], l ? add_node : one, l ? one : add_node);
1134 Node* r = R.reduce(or_node);
1135
1136 CHECK_EQ(R.ops[o + 1]->opcode(), r->op()->opcode());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001137 CHECK_EQ(IrOpcode::kNumberAdd, add_node->opcode());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001138 }
1139 }
1140 }
1141 }
1142 }
1143 {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001144 JSBitwiseShiftTypedLoweringTester R;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001145
1146 for (int o = 0; o < R.kNumberOps; o += 2) {
1147 for (size_t i = 0; i < arraysize(kInt32Types); i++) {
1148 Node* n0 = R.Parameter(kInt32Types[i]);
1149 for (size_t j = 0; j < arraysize(kInt32Types); j++) {
1150 Node* n1 = R.Parameter(kInt32Types[j]);
1151 Node* one = R.graph.NewNode(R.common.NumberConstant(1));
1152
1153 for (int l = 0; l < 2; l++) {
1154 Node* add_node = R.Binop(R.simplified.NumberAdd(), n0, n1);
1155 Node* or_node =
1156 R.Binop(R.ops[o], l ? add_node : one, l ? one : add_node);
1157 Node* r = R.reduce(or_node);
1158
1159 CHECK_EQ(R.ops[o + 1]->opcode(), r->op()->opcode());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001160 CHECK_EQ(IrOpcode::kNumberAdd, add_node->opcode());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001161 }
1162 }
1163 }
1164 }
1165 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001166 {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001167 JSBitwiseTypedLoweringTester R;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001168
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001169 for (int o = 0; o < R.kNumberOps; o += 2) {
1170 Node* n0 = R.Parameter(I32Type(R.signedness[o]));
1171 Node* n1 = R.Parameter(I32Type(R.signedness[o + 1]));
1172 Node* one = R.graph.NewNode(R.common.NumberConstant(1));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001173
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001174 Node* add_node = R.Binop(R.simplified.NumberAdd(), n0, n1);
1175 Node* or_node = R.Binop(R.ops[o], add_node, one);
1176 Node* other_use = R.Binop(R.simplified.NumberAdd(), add_node, one);
1177 Node* r = R.reduce(or_node);
1178 CHECK_EQ(R.ops[o + 1]->opcode(), r->op()->opcode());
1179 CHECK_EQ(IrOpcode::kNumberAdd, add_node->opcode());
1180 // Conversion to int32 should be done.
1181 CheckToI32(add_node, r->InputAt(0), R.signedness[o]);
1182 CheckToI32(one, r->InputAt(1), R.signedness[o + 1]);
1183 // The other use should also not be touched.
1184 CHECK_EQ(add_node, other_use->InputAt(0));
1185 CHECK_EQ(one, other_use->InputAt(1));
1186 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001187 }
1188}
1189
Ben Murdoch097c5b22016-05-18 11:27:45 +01001190TEST(Int32Comparisons) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001191 JSTypedLoweringTester R;
1192
1193 struct Entry {
1194 const Operator* js_op;
1195 const Operator* uint_op;
1196 const Operator* int_op;
1197 const Operator* num_op;
1198 bool commute;
1199 };
1200
1201 Entry ops[] = {
Ben Murdoch61f157c2016-09-16 13:49:30 +01001202 {R.javascript.LessThan(R.compare_hints), R.machine.Uint32LessThan(),
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001203 R.machine.Int32LessThan(), R.simplified.NumberLessThan(), false},
Ben Murdoch61f157c2016-09-16 13:49:30 +01001204 {R.javascript.LessThanOrEqual(R.compare_hints),
1205 R.machine.Uint32LessThanOrEqual(), R.machine.Int32LessThanOrEqual(),
1206 R.simplified.NumberLessThanOrEqual(), false},
1207 {R.javascript.GreaterThan(R.compare_hints), R.machine.Uint32LessThan(),
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001208 R.machine.Int32LessThan(), R.simplified.NumberLessThan(), true},
Ben Murdoch61f157c2016-09-16 13:49:30 +01001209 {R.javascript.GreaterThanOrEqual(R.compare_hints),
1210 R.machine.Uint32LessThanOrEqual(), R.machine.Int32LessThanOrEqual(),
1211 R.simplified.NumberLessThanOrEqual(), true}};
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001212
1213 for (size_t o = 0; o < arraysize(ops); o++) {
1214 for (size_t i = 0; i < arraysize(kNumberTypes); i++) {
1215 Type* t0 = kNumberTypes[i];
1216 Node* p0 = R.Parameter(t0, 0);
1217
1218 for (size_t j = 0; j < arraysize(kNumberTypes); j++) {
1219 Type* t1 = kNumberTypes[j];
1220 Node* p1 = R.Parameter(t1, 1);
1221
1222 Node* cmp = R.Binop(ops[o].js_op, p0, p1);
1223 Node* r = R.reduce(cmp);
1224
1225 const Operator* expected;
1226 if (t0->Is(Type::Unsigned32()) && t1->Is(Type::Unsigned32())) {
1227 expected = ops[o].uint_op;
1228 } else if (t0->Is(Type::Signed32()) && t1->Is(Type::Signed32())) {
1229 expected = ops[o].int_op;
1230 } else {
1231 expected = ops[o].num_op;
1232 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001233 R.CheckBinop(expected, r);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001234 if (ops[o].commute) {
1235 CHECK_EQ(p1, r->InputAt(0));
1236 CHECK_EQ(p0, r->InputAt(1));
1237 } else {
1238 CHECK_EQ(p0, r->InputAt(0));
1239 CHECK_EQ(p1, r->InputAt(1));
1240 }
1241 }
1242 }
1243 }
1244}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001245
1246} // namespace compiler
1247} // namespace internal
1248} // namespace v8