blob: b5e992915f2970c5ab74edc632488cf97dc1ee35 [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
5#include <limits>
6
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00007#include "src/ast/scopes.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008#include "src/compiler/access-builder.h"
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009#include "src/compiler/change-lowering.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010#include "src/compiler/control-builders.h"
Emily Bernierd0a1eb72015-03-24 16:35:39 -040011#include "src/compiler/graph-reducer.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012#include "src/compiler/graph-visualizer.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013#include "src/compiler/node-properties.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014#include "src/compiler/pipeline.h"
15#include "src/compiler/representation-change.h"
16#include "src/compiler/simplified-lowering.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000017#include "src/compiler/source-position.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000018#include "src/compiler/typer.h"
19#include "src/compiler/verifier.h"
20#include "src/execution.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000021#include "src/parsing/parser.h"
22#include "src/parsing/rewriter.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000023#include "test/cctest/cctest.h"
24#include "test/cctest/compiler/codegen-tester.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000025#include "test/cctest/compiler/function-tester.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000026#include "test/cctest/compiler/graph-builder-tester.h"
27#include "test/cctest/compiler/value-helper.h"
28
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000029namespace v8 {
30namespace internal {
31namespace compiler {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000032
33template <typename ReturnType>
34class SimplifiedLoweringTester : public GraphBuilderTester<ReturnType> {
35 public:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000036 SimplifiedLoweringTester(MachineType p0 = MachineType::None(),
37 MachineType p1 = MachineType::None())
38 : GraphBuilderTester<ReturnType>(p0, p1),
39 typer(this->isolate(), this->graph()),
Ben Murdochb8a8cc12014-11-26 15:28:44 +000040 javascript(this->zone()),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000041 jsgraph(this->isolate(), this->graph(), this->common(), &javascript,
42 this->simplified(), this->machine()),
43 source_positions(jsgraph.graph()),
44 lowering(&jsgraph, this->zone(), &source_positions) {}
Ben Murdochb8a8cc12014-11-26 15:28:44 +000045
46 Typer typer;
47 JSOperatorBuilder javascript;
48 JSGraph jsgraph;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000049 SourcePositionTable source_positions;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000050 SimplifiedLowering lowering;
51
52 void LowerAllNodes() {
53 this->End();
Emily Bernierd0a1eb72015-03-24 16:35:39 -040054 typer.Run();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000055 lowering.LowerAllNodes();
56 }
57
Emily Bernierd0a1eb72015-03-24 16:35:39 -040058 void LowerAllNodesAndLowerChanges() {
59 this->End();
60 typer.Run();
61 lowering.LowerAllNodes();
62
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000063 ChangeLowering lowering(&jsgraph);
64 GraphReducer reducer(this->zone(), this->graph());
Emily Bernierd0a1eb72015-03-24 16:35:39 -040065 reducer.AddReducer(&lowering);
66 reducer.ReduceGraph();
67 Verifier::Run(this->graph());
68 }
69
70 void CheckNumberCall(double expected, double input) {
71 // TODO(titzer): make calls to NewNumber work in cctests.
72 if (expected <= Smi::kMinValue) return;
73 if (expected >= Smi::kMaxValue) return;
74 Handle<Object> num = factory()->NewNumber(input);
75 Object* result = this->Call(*num);
76 CHECK(factory()->NewNumber(expected)->SameValue(result));
77 }
78
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000079 template <typename T>
80 T* CallWithPotentialGC() {
81 // TODO(titzer): we wrap the code in a JSFunction here to reuse the
82 // JSEntryStub; that could be done with a special prologue or other stub.
83 Handle<JSFunction> fun = FunctionTester::ForMachineGraph(this->graph(), 0);
84 Handle<Object>* args = NULL;
85 MaybeHandle<Object> result = Execution::Call(
86 this->isolate(), fun, factory()->undefined_value(), 0, args);
87 return T::cast(*result.ToHandleChecked());
88 }
89
Ben Murdochb8a8cc12014-11-26 15:28:44 +000090 Factory* factory() { return this->isolate()->factory(); }
91 Heap* heap() { return this->isolate()->heap(); }
92};
93
94
Ben Murdochb8a8cc12014-11-26 15:28:44 +000095// TODO(titzer): factor these tests out to test-run-simplifiedops.cc.
96// TODO(titzer): test tagged representation for input to NumberToInt32.
97TEST(RunNumberToInt32_float64) {
98 // TODO(titzer): explicit load/stores here are only because of representations
99 double input;
100 int32_t result;
101 SimplifiedLoweringTester<Object*> t;
102 FieldAccess load = {kUntaggedBase, 0, Handle<Name>(), Type::Number(),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000103 MachineType::Float64()};
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000104 Node* loaded = t.LoadField(load, t.PointerConstant(&input));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000105 NodeProperties::SetType(loaded, Type::Number());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000106 Node* convert = t.NumberToInt32(loaded);
107 FieldAccess store = {kUntaggedBase, 0, Handle<Name>(), Type::Signed32(),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000108 MachineType::Int32()};
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000109 t.StoreField(store, t.PointerConstant(&result), convert);
110 t.Return(t.jsgraph.TrueConstant());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000111 t.LowerAllNodesAndLowerChanges();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000112 t.GenerateCode();
113
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000114 FOR_FLOAT64_INPUTS(i) {
115 input = *i;
116 int32_t expected = DoubleToInt32(*i);
117 t.Call();
118 CHECK_EQ(expected, result);
119 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000120}
121
122
123// TODO(titzer): test tagged representation for input to NumberToUint32.
124TEST(RunNumberToUint32_float64) {
125 // TODO(titzer): explicit load/stores here are only because of representations
126 double input;
127 uint32_t result;
128 SimplifiedLoweringTester<Object*> t;
129 FieldAccess load = {kUntaggedBase, 0, Handle<Name>(), Type::Number(),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000130 MachineType::Float64()};
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000131 Node* loaded = t.LoadField(load, t.PointerConstant(&input));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000132 NodeProperties::SetType(loaded, Type::Number());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000133 Node* convert = t.NumberToUint32(loaded);
134 FieldAccess store = {kUntaggedBase, 0, Handle<Name>(), Type::Unsigned32(),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000135 MachineType::Uint32()};
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000136 t.StoreField(store, t.PointerConstant(&result), convert);
137 t.Return(t.jsgraph.TrueConstant());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000138 t.LowerAllNodesAndLowerChanges();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000139 t.GenerateCode();
140
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000141 FOR_FLOAT64_INPUTS(i) {
142 input = *i;
143 uint32_t expected = DoubleToUint32(*i);
144 t.Call();
145 CHECK_EQ(static_cast<int32_t>(expected), static_cast<int32_t>(result));
146 }
147 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000148
149
150// Create a simple JSObject with a unique map.
151static Handle<JSObject> TestObject() {
152 static int index = 0;
153 char buffer[50];
154 v8::base::OS::SNPrintF(buffer, 50, "({'a_%d':1})", index++);
155 return Handle<JSObject>::cast(v8::Utils::OpenHandle(*CompileRun(buffer)));
156}
157
158
159TEST(RunLoadMap) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000160 SimplifiedLoweringTester<Object*> t(MachineType::AnyTagged());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000161 FieldAccess access = AccessBuilder::ForMap();
162 Node* load = t.LoadField(access, t.Parameter(0));
163 t.Return(load);
164
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000165 t.LowerAllNodesAndLowerChanges();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000166 t.GenerateCode();
167
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000168 Handle<JSObject> src = TestObject();
169 Handle<Map> src_map(src->map());
170 Object* result = t.Call(*src); // TODO(titzer): raw pointers in call
171 CHECK_EQ(*src_map, result);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000172}
173
174
175TEST(RunStoreMap) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000176 SimplifiedLoweringTester<int32_t> t(MachineType::AnyTagged(),
177 MachineType::AnyTagged());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000178 FieldAccess access = AccessBuilder::ForMap();
179 t.StoreField(access, t.Parameter(1), t.Parameter(0));
180 t.Return(t.jsgraph.TrueConstant());
181
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000182 t.LowerAllNodesAndLowerChanges();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000183 t.GenerateCode();
184
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000185 Handle<JSObject> src = TestObject();
186 Handle<Map> src_map(src->map());
187 Handle<JSObject> dst = TestObject();
188 CHECK(src->map() != dst->map());
189 t.Call(*src_map, *dst); // TODO(titzer): raw pointers in call
190 CHECK(*src_map == dst->map());
191 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000192
193
194TEST(RunLoadProperties) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000195 SimplifiedLoweringTester<Object*> t(MachineType::AnyTagged());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000196 FieldAccess access = AccessBuilder::ForJSObjectProperties();
197 Node* load = t.LoadField(access, t.Parameter(0));
198 t.Return(load);
199
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000200 t.LowerAllNodesAndLowerChanges();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000201 t.GenerateCode();
202
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000203 Handle<JSObject> src = TestObject();
204 Handle<FixedArray> src_props(src->properties());
205 Object* result = t.Call(*src); // TODO(titzer): raw pointers in call
206 CHECK_EQ(*src_props, result);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000207}
208
209
210TEST(RunLoadStoreMap) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000211 SimplifiedLoweringTester<Object*> t(MachineType::AnyTagged(),
212 MachineType::AnyTagged());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000213 FieldAccess access = AccessBuilder::ForMap();
214 Node* load = t.LoadField(access, t.Parameter(0));
215 t.StoreField(access, t.Parameter(1), load);
216 t.Return(load);
217
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000218 t.LowerAllNodesAndLowerChanges();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000219 t.GenerateCode();
220
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000221 Handle<JSObject> src = TestObject();
222 Handle<Map> src_map(src->map());
223 Handle<JSObject> dst = TestObject();
224 CHECK(src->map() != dst->map());
225 Object* result = t.Call(*src, *dst); // TODO(titzer): raw pointers in call
226 CHECK(result->IsMap());
227 CHECK_EQ(*src_map, result);
228 CHECK(*src_map == dst->map());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000229}
230
231
232TEST(RunLoadStoreFixedArrayIndex) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000233 SimplifiedLoweringTester<Object*> t(MachineType::AnyTagged());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000234 ElementAccess access = AccessBuilder::ForFixedArrayElement();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400235 Node* load = t.LoadElement(access, t.Parameter(0), t.Int32Constant(0));
236 t.StoreElement(access, t.Parameter(0), t.Int32Constant(1), load);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000237 t.Return(load);
238
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000239 t.LowerAllNodesAndLowerChanges();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000240 t.GenerateCode();
241
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000242 Handle<FixedArray> array = t.factory()->NewFixedArray(2);
243 Handle<JSObject> src = TestObject();
244 Handle<JSObject> dst = TestObject();
245 array->set(0, *src);
246 array->set(1, *dst);
247 Object* result = t.Call(*array);
248 CHECK_EQ(*src, result);
249 CHECK_EQ(*src, array->get(0));
250 CHECK_EQ(*src, array->get(1));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000251}
252
253
254TEST(RunLoadStoreArrayBuffer) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000255 SimplifiedLoweringTester<Object*> t(MachineType::AnyTagged());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000256 const int index = 12;
257 const int array_length = 2 * index;
258 ElementAccess buffer_access =
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000259 AccessBuilder::ForTypedArrayElement(kExternalInt8Array, true);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000260 Node* backing_store = t.LoadField(
261 AccessBuilder::ForJSArrayBufferBackingStore(), t.Parameter(0));
262 Node* load =
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400263 t.LoadElement(buffer_access, backing_store, t.Int32Constant(index));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000264 t.StoreElement(buffer_access, backing_store, t.Int32Constant(index + 1),
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400265 load);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000266 t.Return(t.jsgraph.TrueConstant());
267
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000268 t.LowerAllNodesAndLowerChanges();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000269 t.GenerateCode();
270
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000271 Handle<JSArrayBuffer> array = t.factory()->NewJSArrayBuffer();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000272 JSArrayBuffer::SetupAllocatingData(array, t.isolate(), array_length);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000273 uint8_t* data = reinterpret_cast<uint8_t*>(array->backing_store());
274 for (int i = 0; i < array_length; i++) {
275 data[i] = i;
276 }
277
278 // TODO(titzer): raw pointers in call
279 Object* result = t.Call(*array);
280 CHECK_EQ(t.isolate()->heap()->true_value(), result);
281 for (int i = 0; i < array_length; i++) {
282 uint8_t expected = i;
283 if (i == (index + 1)) expected = index;
284 CHECK_EQ(data[i], expected);
285 }
286 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000287
288
289TEST(RunLoadFieldFromUntaggedBase) {
290 Smi* smis[] = {Smi::FromInt(1), Smi::FromInt(2), Smi::FromInt(3)};
291
292 for (size_t i = 0; i < arraysize(smis); i++) {
293 int offset = static_cast<int>(i * sizeof(Smi*));
294 FieldAccess access = {kUntaggedBase, offset, Handle<Name>(),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000295 Type::Integral32(), MachineType::AnyTagged()};
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000296
297 SimplifiedLoweringTester<Object*> t;
298 Node* load = t.LoadField(access, t.PointerConstant(smis));
299 t.Return(load);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000300 t.LowerAllNodesAndLowerChanges();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000301
302 for (int j = -5; j <= 5; j++) {
303 Smi* expected = Smi::FromInt(j);
304 smis[i] = expected;
305 CHECK_EQ(expected, t.Call());
306 }
307 }
308}
309
310
311TEST(RunStoreFieldToUntaggedBase) {
312 Smi* smis[] = {Smi::FromInt(1), Smi::FromInt(2), Smi::FromInt(3)};
313
314 for (size_t i = 0; i < arraysize(smis); i++) {
315 int offset = static_cast<int>(i * sizeof(Smi*));
316 FieldAccess access = {kUntaggedBase, offset, Handle<Name>(),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000317 Type::Integral32(), MachineType::AnyTagged()};
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000318
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000319 SimplifiedLoweringTester<Object*> t(MachineType::AnyTagged());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000320 Node* p0 = t.Parameter(0);
321 t.StoreField(access, t.PointerConstant(smis), p0);
322 t.Return(p0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000323 t.LowerAllNodesAndLowerChanges();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000324
325 for (int j = -5; j <= 5; j++) {
326 Smi* expected = Smi::FromInt(j);
327 smis[i] = Smi::FromInt(-100);
328 CHECK_EQ(expected, t.Call(expected));
329 CHECK_EQ(expected, smis[i]);
330 }
331 }
332}
333
334
335TEST(RunLoadElementFromUntaggedBase) {
336 Smi* smis[] = {Smi::FromInt(1), Smi::FromInt(2), Smi::FromInt(3),
337 Smi::FromInt(4), Smi::FromInt(5)};
338
339 for (size_t i = 0; i < arraysize(smis); i++) { // for header sizes
340 for (size_t j = 0; (i + j) < arraysize(smis); j++) { // for element index
341 int offset = static_cast<int>(i * sizeof(Smi*));
342 ElementAccess access = {kUntaggedBase, offset, Type::Integral32(),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000343 MachineType::AnyTagged()};
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000344
345 SimplifiedLoweringTester<Object*> t;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400346 Node* load = t.LoadElement(access, t.PointerConstant(smis),
347 t.Int32Constant(static_cast<int>(j)));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000348 t.Return(load);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000349 t.LowerAllNodesAndLowerChanges();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000350
351 for (int k = -5; k <= 5; k++) {
352 Smi* expected = Smi::FromInt(k);
353 smis[i + j] = expected;
354 CHECK_EQ(expected, t.Call());
355 }
356 }
357 }
358}
359
360
361TEST(RunStoreElementFromUntaggedBase) {
362 Smi* smis[] = {Smi::FromInt(1), Smi::FromInt(2), Smi::FromInt(3),
363 Smi::FromInt(4), Smi::FromInt(5)};
364
365 for (size_t i = 0; i < arraysize(smis); i++) { // for header sizes
366 for (size_t j = 0; (i + j) < arraysize(smis); j++) { // for element index
367 int offset = static_cast<int>(i * sizeof(Smi*));
368 ElementAccess access = {kUntaggedBase, offset, Type::Integral32(),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000369 MachineType::AnyTagged()};
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000370
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000371 SimplifiedLoweringTester<Object*> t(MachineType::AnyTagged());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000372 Node* p0 = t.Parameter(0);
373 t.StoreElement(access, t.PointerConstant(smis),
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400374 t.Int32Constant(static_cast<int>(j)), p0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000375 t.Return(p0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000376 t.LowerAllNodesAndLowerChanges();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000377
378 for (int k = -5; k <= 5; k++) {
379 Smi* expected = Smi::FromInt(k);
380 smis[i + j] = Smi::FromInt(-100);
381 CHECK_EQ(expected, t.Call(expected));
382 CHECK_EQ(expected, smis[i + j]);
383 }
384
385 // TODO(titzer): assert the contents of the array.
386 }
387 }
388}
389
390
391// A helper class for accessing fields and elements of various types, on both
392// tagged and untagged base pointers. Contains both tagged and untagged buffers
393// for testing direct memory access from generated code.
394template <typename E>
395class AccessTester : public HandleAndZoneScope {
396 public:
397 bool tagged;
398 MachineType rep;
399 E* original_elements;
400 size_t num_elements;
401 E* untagged_array;
402 Handle<ByteArray> tagged_array; // TODO(titzer): use FixedArray for tagged.
403
404 AccessTester(bool t, MachineType r, E* orig, size_t num)
405 : tagged(t),
406 rep(r),
407 original_elements(orig),
408 num_elements(num),
409 untagged_array(static_cast<E*>(malloc(ByteSize()))),
410 tagged_array(main_isolate()->factory()->NewByteArray(
411 static_cast<int>(ByteSize()))) {
412 Reinitialize();
413 }
414
415 ~AccessTester() { free(untagged_array); }
416
417 size_t ByteSize() { return num_elements * sizeof(E); }
418
419 // Nuke both {untagged_array} and {tagged_array} with {original_elements}.
420 void Reinitialize() {
421 memcpy(untagged_array, original_elements, ByteSize());
422 CHECK_EQ(static_cast<int>(ByteSize()), tagged_array->length());
423 E* raw = reinterpret_cast<E*>(tagged_array->GetDataStartAddress());
424 memcpy(raw, original_elements, ByteSize());
425 }
426
427 // Create and run code that copies the element in either {untagged_array}
428 // or {tagged_array} at index {from_index} to index {to_index}.
429 void RunCopyElement(int from_index, int to_index) {
430 // TODO(titzer): test element and field accesses where the base is not
431 // a constant in the code.
432 BoundsCheck(from_index);
433 BoundsCheck(to_index);
434 ElementAccess access = GetElementAccess();
435
436 SimplifiedLoweringTester<Object*> t;
437 Node* ptr = GetBaseNode(&t);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400438 Node* load = t.LoadElement(access, ptr, t.Int32Constant(from_index));
439 t.StoreElement(access, ptr, t.Int32Constant(to_index), load);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000440 t.Return(t.jsgraph.TrueConstant());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000441 t.LowerAllNodesAndLowerChanges();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000442 t.GenerateCode();
443
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000444 Object* result = t.Call();
445 CHECK_EQ(t.isolate()->heap()->true_value(), result);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000446 }
447
448 // Create and run code that copies the field in either {untagged_array}
449 // or {tagged_array} at index {from_index} to index {to_index}.
450 void RunCopyField(int from_index, int to_index) {
451 BoundsCheck(from_index);
452 BoundsCheck(to_index);
453 FieldAccess from_access = GetFieldAccess(from_index);
454 FieldAccess to_access = GetFieldAccess(to_index);
455
456 SimplifiedLoweringTester<Object*> t;
457 Node* ptr = GetBaseNode(&t);
458 Node* load = t.LoadField(from_access, ptr);
459 t.StoreField(to_access, ptr, load);
460 t.Return(t.jsgraph.TrueConstant());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000461 t.LowerAllNodesAndLowerChanges();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000462 t.GenerateCode();
463
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000464 Object* result = t.Call();
465 CHECK_EQ(t.isolate()->heap()->true_value(), result);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000466 }
467
468 // Create and run code that copies the elements from {this} to {that}.
469 void RunCopyElements(AccessTester<E>* that) {
470// TODO(titzer): Rewrite this test without StructuredGraphBuilder support.
471#if 0
472 SimplifiedLoweringTester<Object*> t;
473
474 Node* one = t.Int32Constant(1);
475 Node* index = t.Int32Constant(0);
476 Node* limit = t.Int32Constant(static_cast<int>(num_elements));
477 t.environment()->Push(index);
478 Node* src = this->GetBaseNode(&t);
479 Node* dst = that->GetBaseNode(&t);
480 {
481 LoopBuilder loop(&t);
482 loop.BeginLoop();
483 // Loop exit condition
484 index = t.environment()->Top();
485 Node* condition = t.Int32LessThan(index, limit);
486 loop.BreakUnless(condition);
487 // dst[index] = src[index]
488 index = t.environment()->Pop();
489 Node* load = t.LoadElement(this->GetElementAccess(), src, index);
490 t.StoreElement(that->GetElementAccess(), dst, index, load);
491 // index++
492 index = t.Int32Add(index, one);
493 t.environment()->Push(index);
494 // continue
495 loop.EndBody();
496 loop.EndLoop();
497 }
498 index = t.environment()->Pop();
499 t.Return(t.jsgraph.TrueConstant());
500 t.LowerAllNodes();
501 t.GenerateCode();
502
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000503 Object* result = t.Call();
504 CHECK_EQ(t.isolate()->heap()->true_value(), result);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000505#endif
506 }
507
508 E GetElement(int index) {
509 BoundsCheck(index);
510 if (tagged) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000511 return GetTaggedElement(index);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000512 } else {
513 return untagged_array[index];
514 }
515 }
516
517 private:
518 ElementAccess GetElementAccess() {
519 ElementAccess access = {tagged ? kTaggedBase : kUntaggedBase,
520 tagged ? FixedArrayBase::kHeaderSize : 0,
521 Type::Any(), rep};
522 return access;
523 }
524
525 FieldAccess GetFieldAccess(int field) {
526 int offset = field * sizeof(E);
527 FieldAccess access = {tagged ? kTaggedBase : kUntaggedBase,
528 offset + (tagged ? FixedArrayBase::kHeaderSize : 0),
529 Handle<Name>(), Type::Any(), rep};
530 return access;
531 }
532
533 template <typename T>
534 Node* GetBaseNode(SimplifiedLoweringTester<T>* t) {
535 return tagged ? t->HeapConstant(tagged_array)
536 : t->PointerConstant(untagged_array);
537 }
538
539 void BoundsCheck(int index) {
540 CHECK_GE(index, 0);
541 CHECK_LT(index, static_cast<int>(num_elements));
542 CHECK_EQ(static_cast<int>(ByteSize()), tagged_array->length());
543 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000544
545 E GetTaggedElement(int index) {
546 E* raw = reinterpret_cast<E*>(tagged_array->GetDataStartAddress());
547 return raw[index];
548 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000549};
550
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000551template <>
552double AccessTester<double>::GetTaggedElement(int index) {
553 return ReadDoubleValue(tagged_array->GetDataStartAddress() +
554 index * sizeof(double));
555}
556
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000557
558template <typename E>
559static void RunAccessTest(MachineType rep, E* original_elements, size_t num) {
560 int num_elements = static_cast<int>(num);
561
562 for (int taggedness = 0; taggedness < 2; taggedness++) {
563 AccessTester<E> a(taggedness == 1, rep, original_elements, num);
564 for (int field = 0; field < 2; field++) {
565 for (int i = 0; i < num_elements - 1; i++) {
566 a.Reinitialize();
567 if (field == 0) {
568 a.RunCopyField(i, i + 1); // Test field read/write.
569 } else {
570 a.RunCopyElement(i, i + 1); // Test element read/write.
571 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000572 for (int j = 0; j < num_elements; j++) {
573 E expect =
574 j == (i + 1) ? original_elements[i] : original_elements[j];
575 CHECK_EQ(expect, a.GetElement(j));
576 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000577 }
578 }
579 }
580 // Test array copy.
581 for (int tf = 0; tf < 2; tf++) {
582 for (int tt = 0; tt < 2; tt++) {
583 AccessTester<E> a(tf == 1, rep, original_elements, num);
584 AccessTester<E> b(tt == 1, rep, original_elements, num);
585 a.RunCopyElements(&b);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000586 for (int i = 0; i < num_elements; i++) {
587 CHECK_EQ(a.GetElement(i), b.GetElement(i));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000588 }
589 }
590 }
591}
592
593
594TEST(RunAccessTests_uint8) {
595 uint8_t data[] = {0x07, 0x16, 0x25, 0x34, 0x43, 0x99,
596 0xab, 0x78, 0x89, 0x19, 0x2b, 0x38};
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000597 RunAccessTest<uint8_t>(MachineType::Int8(), data, arraysize(data));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000598}
599
600
601TEST(RunAccessTests_uint16) {
602 uint16_t data[] = {0x071a, 0x162b, 0x253c, 0x344d, 0x435e, 0x7777};
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000603 RunAccessTest<uint16_t>(MachineType::Int16(), data, arraysize(data));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000604}
605
606
607TEST(RunAccessTests_int32) {
608 int32_t data[] = {-211, 211, 628347, 2000000000, -2000000000, -1, -100000034};
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000609 RunAccessTest<int32_t>(MachineType::Int32(), data, arraysize(data));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000610}
611
612
613#define V8_2PART_INT64(a, b) (((static_cast<int64_t>(a) << 32) + 0x##b##u))
614
615
616TEST(RunAccessTests_int64) {
617 if (kPointerSize != 8) return;
618 int64_t data[] = {V8_2PART_INT64(0x10111213, 14151617),
619 V8_2PART_INT64(0x20212223, 24252627),
620 V8_2PART_INT64(0x30313233, 34353637),
621 V8_2PART_INT64(0xa0a1a2a3, a4a5a6a7),
622 V8_2PART_INT64(0xf0f1f2f3, f4f5f6f7)};
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000623 RunAccessTest<int64_t>(MachineType::Int64(), data, arraysize(data));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000624}
625
626
627TEST(RunAccessTests_float64) {
628 double data[] = {1.25, -1.25, 2.75, 11.0, 11100.8};
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000629 RunAccessTest<double>(MachineType::Float64(), data, arraysize(data));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000630}
631
632
633TEST(RunAccessTests_Smi) {
634 Smi* data[] = {Smi::FromInt(-1), Smi::FromInt(-9),
635 Smi::FromInt(0), Smi::FromInt(666),
636 Smi::FromInt(77777), Smi::FromInt(Smi::kMaxValue)};
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000637 RunAccessTest<Smi*>(MachineType::AnyTagged(), data, arraysize(data));
638}
639
640
641TEST(RunAllocate) {
642 PretenureFlag flag[] = {NOT_TENURED, TENURED};
643
644 for (size_t i = 0; i < arraysize(flag); i++) {
645 SimplifiedLoweringTester<HeapObject*> t;
646 FieldAccess access = AccessBuilder::ForMap();
647 Node* size = t.jsgraph.Constant(HeapNumber::kSize);
648 Node* alloc = t.NewNode(t.simplified()->Allocate(flag[i]), size);
649 Node* map = t.jsgraph.Constant(t.factory()->heap_number_map());
650 t.StoreField(access, alloc, map);
651 t.Return(alloc);
652
653 t.LowerAllNodesAndLowerChanges();
654 t.GenerateCode();
655
656 HeapObject* result = t.CallWithPotentialGC<HeapObject>();
657 CHECK(t.heap()->new_space()->Contains(result) || flag[i] == TENURED);
658 CHECK(t.heap()->old_space()->Contains(result) || flag[i] == NOT_TENURED);
659 CHECK(result->IsHeapNumber());
660 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000661}
662
663
664// Fills in most of the nodes of the graph in order to make tests shorter.
665class TestingGraph : public HandleAndZoneScope, public GraphAndBuilders {
666 public:
667 Typer typer;
668 JSOperatorBuilder javascript;
669 JSGraph jsgraph;
670 Node* p0;
671 Node* p1;
672 Node* p2;
673 Node* start;
674 Node* end;
675 Node* ret;
676
677 explicit TestingGraph(Type* p0_type, Type* p1_type = Type::None(),
678 Type* p2_type = Type::None())
679 : GraphAndBuilders(main_zone()),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000680 typer(main_isolate(), graph()),
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000681 javascript(main_zone()),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000682 jsgraph(main_isolate(), graph(), common(), &javascript, simplified(),
683 machine()) {
684 start = graph()->NewNode(common()->Start(4));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000685 graph()->SetStart(start);
686 ret =
687 graph()->NewNode(common()->Return(), jsgraph.Constant(0), start, start);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000688 end = graph()->NewNode(common()->End(1), ret);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000689 graph()->SetEnd(end);
690 p0 = graph()->NewNode(common()->Parameter(0), start);
691 p1 = graph()->NewNode(common()->Parameter(1), start);
692 p2 = graph()->NewNode(common()->Parameter(2), start);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400693 typer.Run();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000694 NodeProperties::SetType(p0, p0_type);
695 NodeProperties::SetType(p1, p1_type);
696 NodeProperties::SetType(p2, p2_type);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000697 }
698
699 void CheckLoweringBinop(IrOpcode::Value expected, const Operator* op) {
700 Node* node = Return(graph()->NewNode(op, p0, p1));
701 Lower();
702 CHECK_EQ(expected, node->opcode());
703 }
704
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000705 void CheckLoweringStringBinop(IrOpcode::Value expected, const Operator* op) {
706 Node* node = Return(
707 graph()->NewNode(op, p0, p1, graph()->start(), graph()->start()));
708 Lower();
709 CHECK_EQ(expected, node->opcode());
710 }
711
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000712 void CheckLoweringTruncatedBinop(IrOpcode::Value expected, const Operator* op,
713 const Operator* trunc) {
714 Node* node = graph()->NewNode(op, p0, p1);
715 Return(graph()->NewNode(trunc, node));
716 Lower();
717 CHECK_EQ(expected, node->opcode());
718 }
719
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000720 void Lower() {
721 SourcePositionTable table(jsgraph.graph());
722 SimplifiedLowering(&jsgraph, jsgraph.zone(), &table).LowerAllNodes();
723 }
724
725 void LowerAllNodesAndLowerChanges() {
726 SourcePositionTable table(jsgraph.graph());
727 SimplifiedLowering(&jsgraph, jsgraph.zone(), &table).LowerAllNodes();
728
729 ChangeLowering lowering(&jsgraph);
730 GraphReducer reducer(this->zone(), this->graph());
731 reducer.AddReducer(&lowering);
732 reducer.ReduceGraph();
733 Verifier::Run(this->graph());
734 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000735
736 // Inserts the node as the return value of the graph.
737 Node* Return(Node* node) {
738 ret->ReplaceInput(0, node);
739 return node;
740 }
741
742 // Inserts the node as the effect input to the return of the graph.
743 void Effect(Node* node) { ret->ReplaceInput(1, node); }
744
745 Node* ExampleWithOutput(MachineType type) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000746 if (type.semantic() == MachineSemantic::kInt32) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000747 return graph()->NewNode(machine()->Int32Add(), jsgraph.Int32Constant(1),
748 jsgraph.Int32Constant(1));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000749 } else if (type.semantic() == MachineSemantic::kUint32) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000750 return graph()->NewNode(machine()->Word32Shr(), jsgraph.Int32Constant(1),
751 jsgraph.Int32Constant(1));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000752 } else if (type.representation() == MachineRepresentation::kFloat64) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000753 return graph()->NewNode(machine()->Float64Add(),
754 jsgraph.Float64Constant(1),
755 jsgraph.Float64Constant(1));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000756 } else if (type.representation() == MachineRepresentation::kBit) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000757 return graph()->NewNode(machine()->Word32Equal(),
758 jsgraph.Int32Constant(1),
759 jsgraph.Int32Constant(1));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000760 } else if (type.representation() == MachineRepresentation::kWord64) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000761 return graph()->NewNode(machine()->Int64Add(), Int64Constant(1),
762 Int64Constant(1));
763 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000764 CHECK(type.representation() == MachineRepresentation::kTagged);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000765 return p0;
766 }
767 }
768
769 Node* Use(Node* node, MachineType type) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000770 if (type.semantic() == MachineSemantic::kInt32) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000771 return graph()->NewNode(machine()->Int32LessThan(), node,
772 jsgraph.Int32Constant(1));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000773 } else if (type.semantic() == MachineSemantic::kUint32) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000774 return graph()->NewNode(machine()->Uint32LessThan(), node,
775 jsgraph.Int32Constant(1));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000776 } else if (type.representation() == MachineRepresentation::kFloat64) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000777 return graph()->NewNode(machine()->Float64Add(), node,
778 jsgraph.Float64Constant(1));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000779 } else if (type.representation() == MachineRepresentation::kWord64) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000780 return graph()->NewNode(machine()->Int64LessThan(), node,
781 Int64Constant(1));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000782 } else if (type.representation() == MachineRepresentation::kWord32) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400783 return graph()->NewNode(machine()->Word32Equal(), node,
784 jsgraph.Int32Constant(1));
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000785 } else {
786 return graph()->NewNode(simplified()->ReferenceEqual(Type::Any()), node,
787 jsgraph.TrueConstant());
788 }
789 }
790
791 Node* Branch(Node* cond) {
792 Node* br = graph()->NewNode(common()->Branch(), cond, start);
793 Node* tb = graph()->NewNode(common()->IfTrue(), br);
794 Node* fb = graph()->NewNode(common()->IfFalse(), br);
795 Node* m = graph()->NewNode(common()->Merge(2), tb, fb);
796 NodeProperties::ReplaceControlInput(ret, m);
797 return br;
798 }
799
800 Node* Int64Constant(int64_t v) {
801 return graph()->NewNode(common()->Int64Constant(v));
802 }
803
804 SimplifiedOperatorBuilder* simplified() { return &main_simplified_; }
805 MachineOperatorBuilder* machine() { return &main_machine_; }
806 CommonOperatorBuilder* common() { return &main_common_; }
807 Graph* graph() { return main_graph_; }
808};
809
810
811TEST(LowerBooleanNot_bit_bit) {
812 // BooleanNot(x: kRepBit) used as kRepBit
813 TestingGraph t(Type::Boolean());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000814 Node* b = t.ExampleWithOutput(MachineType::Bool());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000815 Node* inv = t.graph()->NewNode(t.simplified()->BooleanNot(), b);
816 Node* use = t.Branch(inv);
817 t.Lower();
818 Node* cmp = use->InputAt(0);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400819 CHECK_EQ(t.machine()->Word32Equal()->opcode(), cmp->opcode());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000820 CHECK(b == cmp->InputAt(0) || b == cmp->InputAt(1));
821 Node* f = t.jsgraph.Int32Constant(0);
822 CHECK(f == cmp->InputAt(0) || f == cmp->InputAt(1));
823}
824
825
826TEST(LowerBooleanNot_bit_tagged) {
827 // BooleanNot(x: kRepBit) used as kRepTagged
828 TestingGraph t(Type::Boolean());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000829 Node* b = t.ExampleWithOutput(MachineType::Bool());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000830 Node* inv = t.graph()->NewNode(t.simplified()->BooleanNot(), b);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000831 Node* use = t.Use(inv, MachineType::AnyTagged());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000832 t.Return(use);
833 t.Lower();
834 CHECK_EQ(IrOpcode::kChangeBitToBool, use->InputAt(0)->opcode());
835 Node* cmp = use->InputAt(0)->InputAt(0);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400836 CHECK_EQ(t.machine()->Word32Equal()->opcode(), cmp->opcode());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000837 CHECK(b == cmp->InputAt(0) || b == cmp->InputAt(1));
838 Node* f = t.jsgraph.Int32Constant(0);
839 CHECK(f == cmp->InputAt(0) || f == cmp->InputAt(1));
840}
841
842
843TEST(LowerBooleanNot_tagged_bit) {
844 // BooleanNot(x: kRepTagged) used as kRepBit
845 TestingGraph t(Type::Boolean());
846 Node* b = t.p0;
847 Node* inv = t.graph()->NewNode(t.simplified()->BooleanNot(), b);
848 Node* use = t.Branch(inv);
849 t.Lower();
850 Node* cmp = use->InputAt(0);
851 CHECK_EQ(t.machine()->WordEqual()->opcode(), cmp->opcode());
852 CHECK(b == cmp->InputAt(0) || b == cmp->InputAt(1));
853 Node* f = t.jsgraph.FalseConstant();
854 CHECK(f == cmp->InputAt(0) || f == cmp->InputAt(1));
855}
856
857
858TEST(LowerBooleanNot_tagged_tagged) {
859 // BooleanNot(x: kRepTagged) used as kRepTagged
860 TestingGraph t(Type::Boolean());
861 Node* b = t.p0;
862 Node* inv = t.graph()->NewNode(t.simplified()->BooleanNot(), b);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000863 Node* use = t.Use(inv, MachineType::AnyTagged());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000864 t.Return(use);
865 t.Lower();
866 CHECK_EQ(IrOpcode::kChangeBitToBool, use->InputAt(0)->opcode());
867 Node* cmp = use->InputAt(0)->InputAt(0);
868 CHECK_EQ(t.machine()->WordEqual()->opcode(), cmp->opcode());
869 CHECK(b == cmp->InputAt(0) || b == cmp->InputAt(1));
870 Node* f = t.jsgraph.FalseConstant();
871 CHECK(f == cmp->InputAt(0) || f == cmp->InputAt(1));
872}
873
874
875TEST(LowerBooleanToNumber_bit_int32) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000876 // BooleanToNumber(x: kRepBit) used as MachineType::Int32()
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000877 TestingGraph t(Type::Boolean());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000878 Node* b = t.ExampleWithOutput(MachineType::Bool());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000879 Node* cnv = t.graph()->NewNode(t.simplified()->BooleanToNumber(), b);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000880 Node* use = t.Use(cnv, MachineType::Int32());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000881 t.Return(use);
882 t.Lower();
883 CHECK_EQ(b, use->InputAt(0));
884}
885
886
887TEST(LowerBooleanToNumber_tagged_int32) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000888 // BooleanToNumber(x: kRepTagged) used as MachineType::Int32()
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000889 TestingGraph t(Type::Boolean());
890 Node* b = t.p0;
891 Node* cnv = t.graph()->NewNode(t.simplified()->BooleanToNumber(), b);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000892 Node* use = t.Use(cnv, MachineType::Int32());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000893 t.Return(use);
894 t.Lower();
895 CHECK_EQ(t.machine()->WordEqual()->opcode(), cnv->opcode());
896 CHECK(b == cnv->InputAt(0) || b == cnv->InputAt(1));
897 Node* c = t.jsgraph.TrueConstant();
898 CHECK(c == cnv->InputAt(0) || c == cnv->InputAt(1));
899}
900
901
902TEST(LowerBooleanToNumber_bit_tagged) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000903 // BooleanToNumber(x: kRepBit) used as MachineType::AnyTagged()
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000904 TestingGraph t(Type::Boolean());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000905 Node* b = t.ExampleWithOutput(MachineType::Bool());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000906 Node* cnv = t.graph()->NewNode(t.simplified()->BooleanToNumber(), b);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000907 Node* use = t.Use(cnv, MachineType::AnyTagged());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000908 t.Return(use);
909 t.Lower();
910 CHECK_EQ(b, use->InputAt(0)->InputAt(0));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000911 CHECK_EQ(IrOpcode::kChangeUint32ToTagged, use->InputAt(0)->opcode());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000912}
913
914
915TEST(LowerBooleanToNumber_tagged_tagged) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000916 // BooleanToNumber(x: kRepTagged) used as MachineType::AnyTagged()
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000917 TestingGraph t(Type::Boolean());
918 Node* b = t.p0;
919 Node* cnv = t.graph()->NewNode(t.simplified()->BooleanToNumber(), b);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000920 Node* use = t.Use(cnv, MachineType::AnyTagged());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000921 t.Return(use);
922 t.Lower();
923 CHECK_EQ(cnv, use->InputAt(0)->InputAt(0));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000924 CHECK_EQ(IrOpcode::kChangeUint32ToTagged, use->InputAt(0)->opcode());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000925 CHECK_EQ(t.machine()->WordEqual()->opcode(), cnv->opcode());
926 CHECK(b == cnv->InputAt(0) || b == cnv->InputAt(1));
927 Node* c = t.jsgraph.TrueConstant();
928 CHECK(c == cnv->InputAt(0) || c == cnv->InputAt(1));
929}
930
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000931static Type* test_types[] = {Type::Signed32(), Type::Unsigned32(),
Ben Murdochda12d292016-06-02 14:46:10 +0100932 Type::Number()};
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000933
934TEST(LowerNumberCmp_to_int32) {
935 TestingGraph t(Type::Signed32(), Type::Signed32());
936
937 t.CheckLoweringBinop(IrOpcode::kWord32Equal, t.simplified()->NumberEqual());
938 t.CheckLoweringBinop(IrOpcode::kInt32LessThan,
939 t.simplified()->NumberLessThan());
940 t.CheckLoweringBinop(IrOpcode::kInt32LessThanOrEqual,
941 t.simplified()->NumberLessThanOrEqual());
942}
943
944
945TEST(LowerNumberCmp_to_uint32) {
946 TestingGraph t(Type::Unsigned32(), Type::Unsigned32());
947
948 t.CheckLoweringBinop(IrOpcode::kWord32Equal, t.simplified()->NumberEqual());
949 t.CheckLoweringBinop(IrOpcode::kUint32LessThan,
950 t.simplified()->NumberLessThan());
951 t.CheckLoweringBinop(IrOpcode::kUint32LessThanOrEqual,
952 t.simplified()->NumberLessThanOrEqual());
953}
954
955
956TEST(LowerNumberCmp_to_float64) {
Ben Murdochda12d292016-06-02 14:46:10 +0100957 TestingGraph t(Type::Number(), Type::Number());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000958
Ben Murdochda12d292016-06-02 14:46:10 +0100959 t.CheckLoweringBinop(IrOpcode::kFloat64Equal, t.simplified()->NumberEqual());
960 t.CheckLoweringBinop(IrOpcode::kFloat64LessThan,
961 t.simplified()->NumberLessThan());
962 t.CheckLoweringBinop(IrOpcode::kFloat64LessThanOrEqual,
963 t.simplified()->NumberLessThanOrEqual());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000964}
965
966
967TEST(LowerNumberAddSub_to_int32) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400968 HandleAndZoneScope scope;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000969 Type* small_range = Type::Range(1, 10, scope.main_zone());
970 Type* large_range = Type::Range(-1e+13, 1e+14, scope.main_zone());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400971 static Type* types[] = {Type::Signed32(), Type::Integral32(), small_range,
972 large_range};
973
974 for (size_t i = 0; i < arraysize(types); i++) {
975 for (size_t j = 0; j < arraysize(types); j++) {
976 TestingGraph t(types[i], types[j]);
977 t.CheckLoweringTruncatedBinop(IrOpcode::kInt32Add,
978 t.simplified()->NumberAdd(),
979 t.simplified()->NumberToInt32());
980 t.CheckLoweringTruncatedBinop(IrOpcode::kInt32Sub,
981 t.simplified()->NumberSubtract(),
982 t.simplified()->NumberToInt32());
983 }
984 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000985}
986
987
988TEST(LowerNumberAddSub_to_uint32) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400989 HandleAndZoneScope scope;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000990 Type* small_range = Type::Range(1, 10, scope.main_zone());
991 Type* large_range = Type::Range(-1e+13, 1e+14, scope.main_zone());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400992 static Type* types[] = {Type::Signed32(), Type::Integral32(), small_range,
993 large_range};
994
995 for (size_t i = 0; i < arraysize(types); i++) {
996 for (size_t j = 0; j < arraysize(types); j++) {
997 TestingGraph t(types[i], types[j]);
998 t.CheckLoweringTruncatedBinop(IrOpcode::kInt32Add,
999 t.simplified()->NumberAdd(),
1000 t.simplified()->NumberToUint32());
1001 t.CheckLoweringTruncatedBinop(IrOpcode::kInt32Sub,
1002 t.simplified()->NumberSubtract(),
1003 t.simplified()->NumberToUint32());
1004 }
1005 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001006}
1007
1008
1009TEST(LowerNumberAddSub_to_float64) {
1010 for (size_t i = 0; i < arraysize(test_types); i++) {
1011 TestingGraph t(test_types[i], test_types[i]);
1012
1013 t.CheckLoweringBinop(IrOpcode::kFloat64Add, t.simplified()->NumberAdd());
1014 t.CheckLoweringBinop(IrOpcode::kFloat64Sub,
1015 t.simplified()->NumberSubtract());
1016 }
1017}
1018
1019
1020TEST(LowerNumberDivMod_to_float64) {
1021 for (size_t i = 0; i < arraysize(test_types); i++) {
1022 TestingGraph t(test_types[i], test_types[i]);
1023
1024 t.CheckLoweringBinop(IrOpcode::kFloat64Div, t.simplified()->NumberDivide());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001025 if (!test_types[i]->Is(Type::Unsigned32())) {
1026 t.CheckLoweringBinop(IrOpcode::kFloat64Mod,
1027 t.simplified()->NumberModulus());
1028 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001029 }
1030}
1031
1032
1033static void CheckChangeOf(IrOpcode::Value change, Node* of, Node* node) {
1034 CHECK_EQ(change, node->opcode());
1035 CHECK_EQ(of, node->InputAt(0));
1036}
1037
1038
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001039TEST(LowerNumberToInt32_to_ChangeTaggedToInt32) {
1040 // NumberToInt32(x: kRepTagged | kTypeInt32) used as kRepWord32
1041 TestingGraph t(Type::Signed32());
1042 Node* trunc = t.graph()->NewNode(t.simplified()->NumberToInt32(), t.p0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001043 Node* use = t.Use(trunc, MachineType::Int32());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001044 t.Return(use);
1045 t.Lower();
1046 CheckChangeOf(IrOpcode::kChangeTaggedToInt32, t.p0, use->InputAt(0));
1047}
1048
1049
1050TEST(LowerNumberToInt32_to_TruncateFloat64ToInt32) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001051 // NumberToInt32(x: kRepFloat64) used as MachineType::Int32()
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001052 TestingGraph t(Type::Number());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001053 Node* p0 = t.ExampleWithOutput(MachineType::Float64());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001054 Node* trunc = t.graph()->NewNode(t.simplified()->NumberToInt32(), p0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001055 Node* use = t.Use(trunc, MachineType::Int32());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001056 t.Return(use);
1057 t.Lower();
1058 CheckChangeOf(IrOpcode::kTruncateFloat64ToInt32, p0, use->InputAt(0));
1059}
1060
1061
1062TEST(LowerNumberToInt32_to_TruncateFloat64ToInt32_with_change) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001063 // NumberToInt32(x: kTypeNumber | kRepTagged) used as MachineType::Int32()
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001064 TestingGraph t(Type::Number());
1065 Node* trunc = t.graph()->NewNode(t.simplified()->NumberToInt32(), t.p0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001066 Node* use = t.Use(trunc, MachineType::Int32());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001067 t.Return(use);
1068 t.Lower();
1069 Node* node = use->InputAt(0);
1070 CHECK_EQ(IrOpcode::kTruncateFloat64ToInt32, node->opcode());
1071 Node* of = node->InputAt(0);
1072 CHECK_EQ(IrOpcode::kChangeTaggedToFloat64, of->opcode());
1073 CHECK_EQ(t.p0, of->InputAt(0));
1074}
1075
1076
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001077TEST(LowerNumberToUint32_to_ChangeTaggedToUint32) {
1078 // NumberToUint32(x: kRepTagged | kTypeUint32) used as kRepWord32
1079 TestingGraph t(Type::Unsigned32());
1080 Node* trunc = t.graph()->NewNode(t.simplified()->NumberToUint32(), t.p0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001081 Node* use = t.Use(trunc, MachineType::Uint32());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001082 t.Return(use);
1083 t.Lower();
1084 CheckChangeOf(IrOpcode::kChangeTaggedToUint32, t.p0, use->InputAt(0));
1085}
1086
1087
1088TEST(LowerNumberToUint32_to_TruncateFloat64ToInt32) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001089 // NumberToUint32(x: kRepFloat64) used as MachineType::Uint32()
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001090 TestingGraph t(Type::Number());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001091 Node* p0 = t.ExampleWithOutput(MachineType::Float64());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001092 // TODO(titzer): run the typer here, or attach machine type to param.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001093 NodeProperties::SetType(p0, Type::Number());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001094 Node* trunc = t.graph()->NewNode(t.simplified()->NumberToUint32(), p0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001095 Node* use = t.Use(trunc, MachineType::Uint32());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001096 t.Return(use);
1097 t.Lower();
1098 CheckChangeOf(IrOpcode::kTruncateFloat64ToInt32, p0, use->InputAt(0));
1099}
1100
1101
1102TEST(LowerNumberToUint32_to_TruncateFloat64ToInt32_with_change) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001103 // NumberToInt32(x: kTypeNumber | kRepTagged) used as MachineType::Uint32()
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001104 TestingGraph t(Type::Number());
1105 Node* trunc = t.graph()->NewNode(t.simplified()->NumberToUint32(), t.p0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001106 Node* use = t.Use(trunc, MachineType::Uint32());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001107 t.Return(use);
1108 t.Lower();
1109 Node* node = use->InputAt(0);
1110 CHECK_EQ(IrOpcode::kTruncateFloat64ToInt32, node->opcode());
1111 Node* of = node->InputAt(0);
1112 CHECK_EQ(IrOpcode::kChangeTaggedToFloat64, of->opcode());
1113 CHECK_EQ(t.p0, of->InputAt(0));
1114}
1115
1116
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001117TEST(LowerNumberToUint32_to_TruncateFloat64ToInt32_uint32) {
1118 // NumberToUint32(x: kRepFloat64) used as kRepWord32
1119 TestingGraph t(Type::Unsigned32());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001120 Node* input = t.ExampleWithOutput(MachineType::Float64());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001121 Node* trunc = t.graph()->NewNode(t.simplified()->NumberToUint32(), input);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001122 Node* use = t.Use(trunc, MachineType::RepWord32());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001123 t.Return(use);
1124 t.Lower();
1125 CheckChangeOf(IrOpcode::kTruncateFloat64ToInt32, input, use->InputAt(0));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001126}
1127
1128
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001129TEST(LowerReferenceEqual_to_wordeq) {
1130 TestingGraph t(Type::Any(), Type::Any());
1131 IrOpcode::Value opcode =
1132 static_cast<IrOpcode::Value>(t.machine()->WordEqual()->opcode());
1133 t.CheckLoweringBinop(opcode, t.simplified()->ReferenceEqual(Type::Any()));
1134}
1135
Ben Murdochda12d292016-06-02 14:46:10 +01001136void CheckChangeInsertion(IrOpcode::Value expected, MachineType from,
1137 MachineType to, Type* type = Type::Any()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001138 TestingGraph t(Type::Any());
1139 Node* in = t.ExampleWithOutput(from);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001140 NodeProperties::SetType(in, type);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001141 Node* use = t.Use(in, to);
1142 t.Return(use);
1143 t.Lower();
1144 CHECK_EQ(expected, use->InputAt(0)->opcode());
1145 CHECK_EQ(in, use->InputAt(0)->InputAt(0));
1146}
1147
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001148TEST(InsertBasicChanges) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001149 CheckChangeInsertion(IrOpcode::kChangeFloat64ToInt32, MachineType::Float64(),
1150 MachineType::Int32(), Type::Signed32());
1151 CheckChangeInsertion(IrOpcode::kChangeFloat64ToUint32, MachineType::Float64(),
1152 MachineType::Uint32(), Type::Unsigned32());
1153 CheckChangeInsertion(IrOpcode::kTruncateFloat64ToInt32,
1154 MachineType::Float64(), MachineType::Uint32(),
1155 Type::Integral32());
1156 CheckChangeInsertion(IrOpcode::kChangeTaggedToInt32, MachineType::AnyTagged(),
1157 MachineType::Int32(), Type::Signed32());
1158 CheckChangeInsertion(IrOpcode::kChangeTaggedToUint32,
1159 MachineType::AnyTagged(), MachineType::Uint32(),
1160 Type::Unsigned32());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001161
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001162 CheckChangeInsertion(IrOpcode::kChangeFloat64ToTagged, MachineType::Float64(),
1163 MachineType::AnyTagged());
1164 CheckChangeInsertion(IrOpcode::kChangeTaggedToFloat64,
Ben Murdochda12d292016-06-02 14:46:10 +01001165 MachineType::AnyTagged(), MachineType::Float64(),
1166 Type::Number());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001167
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001168 CheckChangeInsertion(IrOpcode::kChangeInt32ToFloat64, MachineType::Int32(),
Ben Murdochda12d292016-06-02 14:46:10 +01001169 MachineType::Float64(), Type::Signed32());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001170 CheckChangeInsertion(IrOpcode::kChangeInt32ToTagged, MachineType::Int32(),
Ben Murdochda12d292016-06-02 14:46:10 +01001171 MachineType::AnyTagged(), Type::Signed32());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001172
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001173 CheckChangeInsertion(IrOpcode::kChangeUint32ToFloat64, MachineType::Uint32(),
Ben Murdochda12d292016-06-02 14:46:10 +01001174 MachineType::Float64(), Type::Unsigned32());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001175 CheckChangeInsertion(IrOpcode::kChangeUint32ToTagged, MachineType::Uint32(),
Ben Murdochda12d292016-06-02 14:46:10 +01001176 MachineType::AnyTagged(), Type::Unsigned32());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001177}
1178
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001179static void CheckChangesAroundBinop(TestingGraph* t, const Operator* op,
1180 IrOpcode::Value input_change,
Ben Murdochda12d292016-06-02 14:46:10 +01001181 IrOpcode::Value output_change,
1182 Type* type = Type::Any()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001183 Node* binop =
1184 op->ControlInputCount() == 0
1185 ? t->graph()->NewNode(op, t->p0, t->p1)
1186 : t->graph()->NewNode(op, t->p0, t->p1, t->graph()->start());
Ben Murdochda12d292016-06-02 14:46:10 +01001187 NodeProperties::SetType(binop, type);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001188 t->Return(binop);
1189 t->Lower();
1190 CHECK_EQ(input_change, binop->InputAt(0)->opcode());
1191 CHECK_EQ(input_change, binop->InputAt(1)->opcode());
1192 CHECK_EQ(t->p0, binop->InputAt(0)->InputAt(0));
1193 CHECK_EQ(t->p1, binop->InputAt(1)->InputAt(0));
1194 CHECK_EQ(output_change, t->ret->InputAt(0)->opcode());
1195 CHECK_EQ(binop, t->ret->InputAt(0)->InputAt(0));
1196}
1197
1198
1199TEST(InsertChangesAroundInt32Binops) {
1200 TestingGraph t(Type::Signed32(), Type::Signed32());
1201
1202 const Operator* ops[] = {t.machine()->Int32Add(), t.machine()->Int32Sub(),
1203 t.machine()->Int32Mul(), t.machine()->Int32Div(),
1204 t.machine()->Int32Mod(), t.machine()->Word32And(),
1205 t.machine()->Word32Or(), t.machine()->Word32Xor(),
1206 t.machine()->Word32Shl(), t.machine()->Word32Sar()};
1207
1208 for (size_t i = 0; i < arraysize(ops); i++) {
1209 CheckChangesAroundBinop(&t, ops[i], IrOpcode::kChangeTaggedToInt32,
Ben Murdochda12d292016-06-02 14:46:10 +01001210 IrOpcode::kChangeInt32ToTagged, Type::Signed32());
1211 CheckChangesAroundBinop(&t, ops[i], IrOpcode::kChangeTaggedToInt32,
1212 IrOpcode::kChangeInt32ToTagged, Type::Signed32());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001213 }
1214}
1215
1216
1217TEST(InsertChangesAroundInt32Cmp) {
1218 TestingGraph t(Type::Signed32(), Type::Signed32());
1219
1220 const Operator* ops[] = {t.machine()->Int32LessThan(),
1221 t.machine()->Int32LessThanOrEqual()};
1222
1223 for (size_t i = 0; i < arraysize(ops); i++) {
1224 CheckChangesAroundBinop(&t, ops[i], IrOpcode::kChangeTaggedToInt32,
1225 IrOpcode::kChangeBitToBool);
1226 }
1227}
1228
1229
1230TEST(InsertChangesAroundUint32Cmp) {
1231 TestingGraph t(Type::Unsigned32(), Type::Unsigned32());
1232
1233 const Operator* ops[] = {t.machine()->Uint32LessThan(),
1234 t.machine()->Uint32LessThanOrEqual()};
1235
1236 for (size_t i = 0; i < arraysize(ops); i++) {
1237 CheckChangesAroundBinop(&t, ops[i], IrOpcode::kChangeTaggedToUint32,
1238 IrOpcode::kChangeBitToBool);
1239 }
1240}
1241
1242
1243TEST(InsertChangesAroundFloat64Binops) {
1244 TestingGraph t(Type::Number(), Type::Number());
1245
1246 const Operator* ops[] = {
1247 t.machine()->Float64Add(), t.machine()->Float64Sub(),
1248 t.machine()->Float64Mul(), t.machine()->Float64Div(),
1249 t.machine()->Float64Mod(),
1250 };
1251
1252 for (size_t i = 0; i < arraysize(ops); i++) {
1253 CheckChangesAroundBinop(&t, ops[i], IrOpcode::kChangeTaggedToFloat64,
1254 IrOpcode::kChangeFloat64ToTagged);
1255 }
1256}
1257
1258
1259TEST(InsertChangesAroundFloat64Cmp) {
1260 TestingGraph t(Type::Number(), Type::Number());
1261
1262 const Operator* ops[] = {t.machine()->Float64Equal(),
1263 t.machine()->Float64LessThan(),
1264 t.machine()->Float64LessThanOrEqual()};
1265
1266 for (size_t i = 0; i < arraysize(ops); i++) {
1267 CheckChangesAroundBinop(&t, ops[i], IrOpcode::kChangeTaggedToFloat64,
1268 IrOpcode::kChangeBitToBool);
1269 }
1270}
1271
1272
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001273namespace {
1274
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001275void CheckFieldAccessArithmetic(FieldAccess access, Node* load_or_store) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001276 IntPtrMatcher mindex(load_or_store->InputAt(1));
1277 CHECK(mindex.Is(access.offset - access.tag()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001278}
1279
1280
1281Node* CheckElementAccessArithmetic(ElementAccess access, Node* load_or_store) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001282 Node* index = load_or_store->InputAt(1);
1283 if (kPointerSize == 8) {
1284 CHECK_EQ(IrOpcode::kChangeUint32ToUint64, index->opcode());
1285 index = index->InputAt(0);
1286 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001287
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001288 Int32BinopMatcher mindex(index);
1289 CHECK_EQ(IrOpcode::kInt32Add, mindex.node()->opcode());
1290 CHECK(mindex.right().Is(access.header_size - access.tag()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001291
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001292 const int element_size_shift =
1293 ElementSizeLog2Of(access.machine_type.representation());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001294 if (element_size_shift) {
1295 Int32BinopMatcher shl(mindex.left().node());
1296 CHECK_EQ(IrOpcode::kWord32Shl, shl.node()->opcode());
1297 CHECK(shl.right().Is(element_size_shift));
1298 return shl.left().node();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001299 } else {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001300 return mindex.left().node();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001301 }
1302}
1303
1304
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001305const MachineType kMachineReps[] = {
1306 MachineType::Int8(), MachineType::Int16(), MachineType::Int32(),
1307 MachineType::Uint32(), MachineType::Int64(), MachineType::Float64(),
1308 MachineType::AnyTagged()};
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001309
1310} // namespace
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001311
1312
1313TEST(LowerLoadField_to_load) {
1314 TestingGraph t(Type::Any(), Type::Signed32());
1315
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001316 for (size_t i = 0; i < arraysize(kMachineReps); i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001317 FieldAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize,
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001318 Handle<Name>::null(), Type::Any(), kMachineReps[i]};
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001319
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001320 Node* load = t.graph()->NewNode(t.simplified()->LoadField(access), t.p0,
1321 t.start, t.start);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001322 Node* use = t.Use(load, kMachineReps[i]);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001323 t.Return(use);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001324 t.LowerAllNodesAndLowerChanges();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001325 CHECK_EQ(IrOpcode::kLoad, load->opcode());
1326 CHECK_EQ(t.p0, load->InputAt(0));
1327 CheckFieldAccessArithmetic(access, load);
1328
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001329 MachineType rep = LoadRepresentationOf(load->op());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001330 CHECK_EQ(kMachineReps[i], rep);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001331 }
1332}
1333
1334
1335TEST(LowerStoreField_to_store) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001336 {
1337 TestingGraph t(Type::Any(), Type::Signed32());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001338
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001339 for (size_t i = 0; i < arraysize(kMachineReps); i++) {
1340 FieldAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize,
1341 Handle<Name>::null(), Type::Any(), kMachineReps[i]};
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001342
1343
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001344 Node* val = t.ExampleWithOutput(kMachineReps[i]);
1345 Node* store = t.graph()->NewNode(t.simplified()->StoreField(access), t.p0,
1346 val, t.start, t.start);
1347 t.Effect(store);
1348 t.LowerAllNodesAndLowerChanges();
1349 CHECK_EQ(IrOpcode::kStore, store->opcode());
1350 CHECK_EQ(val, store->InputAt(2));
1351 CheckFieldAccessArithmetic(access, store);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001352
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001353 StoreRepresentation rep = StoreRepresentationOf(store->op());
1354 if (kMachineReps[i].representation() == MachineRepresentation::kTagged) {
1355 CHECK_EQ(kFullWriteBarrier, rep.write_barrier_kind());
1356 }
1357 CHECK_EQ(kMachineReps[i].representation(), rep.representation());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001358 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001359 }
1360 {
1361 HandleAndZoneScope scope;
1362 Zone* z = scope.main_zone();
1363 TestingGraph t(Type::Any(), Type::Intersect(Type::SignedSmall(),
1364 Type::TaggedSigned(), z));
1365 FieldAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize,
1366 Handle<Name>::null(), Type::Any(),
1367 MachineType::AnyTagged()};
1368 Node* store = t.graph()->NewNode(t.simplified()->StoreField(access), t.p0,
1369 t.p1, t.start, t.start);
1370 t.Effect(store);
1371 t.LowerAllNodesAndLowerChanges();
1372 CHECK_EQ(IrOpcode::kStore, store->opcode());
1373 CHECK_EQ(t.p1, store->InputAt(2));
1374 StoreRepresentation rep = StoreRepresentationOf(store->op());
1375 CHECK_EQ(kNoWriteBarrier, rep.write_barrier_kind());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001376 }
1377}
1378
1379
1380TEST(LowerLoadElement_to_load) {
1381 TestingGraph t(Type::Any(), Type::Signed32());
1382
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001383 for (size_t i = 0; i < arraysize(kMachineReps); i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001384 ElementAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize,
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001385 Type::Any(), kMachineReps[i]};
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001386
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001387 Node* load = t.graph()->NewNode(t.simplified()->LoadElement(access), t.p0,
1388 t.p1, t.start, t.start);
1389 Node* use = t.Use(load, kMachineReps[i]);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001390 t.Return(use);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001391 t.LowerAllNodesAndLowerChanges();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001392 CHECK_EQ(IrOpcode::kLoad, load->opcode());
1393 CHECK_EQ(t.p0, load->InputAt(0));
1394 CheckElementAccessArithmetic(access, load);
1395
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001396 MachineType rep = LoadRepresentationOf(load->op());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001397 CHECK_EQ(kMachineReps[i], rep);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001398 }
1399}
1400
1401
1402TEST(LowerStoreElement_to_store) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001403 {
1404 TestingGraph t(Type::Any(), Type::Signed32());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001405
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001406 for (size_t i = 0; i < arraysize(kMachineReps); i++) {
1407 ElementAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize,
1408 Type::Any(), kMachineReps[i]};
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001409
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001410 Node* val = t.ExampleWithOutput(kMachineReps[i]);
1411 Node* store = t.graph()->NewNode(t.simplified()->StoreElement(access),
1412 t.p0, t.p1, val, t.start, t.start);
1413 t.Effect(store);
1414 t.LowerAllNodesAndLowerChanges();
1415 CHECK_EQ(IrOpcode::kStore, store->opcode());
1416 CHECK_EQ(val, store->InputAt(2));
1417 CheckElementAccessArithmetic(access, store);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001418
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001419 StoreRepresentation rep = StoreRepresentationOf(store->op());
1420 if (kMachineReps[i].representation() == MachineRepresentation::kTagged) {
1421 CHECK_EQ(kFullWriteBarrier, rep.write_barrier_kind());
1422 }
1423 CHECK_EQ(kMachineReps[i].representation(), rep.representation());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001424 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001425 }
1426 {
1427 HandleAndZoneScope scope;
1428 Zone* z = scope.main_zone();
1429 TestingGraph t(
1430 Type::Any(), Type::Signed32(),
1431 Type::Intersect(Type::SignedSmall(), Type::TaggedSigned(), z));
1432 ElementAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize,
1433 Type::Any(), MachineType::AnyTagged()};
1434 Node* store = t.graph()->NewNode(t.simplified()->StoreElement(access), t.p0,
1435 t.p1, t.p2, t.start, t.start);
1436 t.Effect(store);
1437 t.LowerAllNodesAndLowerChanges();
1438 CHECK_EQ(IrOpcode::kStore, store->opcode());
1439 CHECK_EQ(t.p2, store->InputAt(2));
1440 StoreRepresentation rep = StoreRepresentationOf(store->op());
1441 CHECK_EQ(kNoWriteBarrier, rep.write_barrier_kind());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001442 }
1443}
1444
1445
1446TEST(InsertChangeForLoadElementIndex) {
1447 // LoadElement(obj: Tagged, index: kTypeInt32 | kRepTagged, length) =>
1448 // Load(obj, Int32Add(Int32Mul(ChangeTaggedToInt32(index), #k), #k))
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001449 TestingGraph t(Type::Any(), Type::Signed32());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001450 ElementAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize, Type::Any(),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001451 MachineType::AnyTagged()};
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001452
1453 Node* load = t.graph()->NewNode(t.simplified()->LoadElement(access), t.p0,
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001454 t.p1, t.start, t.start);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001455 t.Return(load);
1456 t.Lower();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001457 CHECK_EQ(IrOpcode::kLoadElement, load->opcode());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001458 CHECK_EQ(t.p0, load->InputAt(0));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001459 CheckChangeOf(IrOpcode::kChangeTaggedToInt32, t.p1, load->InputAt(1));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001460}
1461
1462
1463TEST(InsertChangeForStoreElementIndex) {
1464 // StoreElement(obj: Tagged, index: kTypeInt32 | kRepTagged, length, val) =>
1465 // Store(obj, Int32Add(Int32Mul(ChangeTaggedToInt32(index), #k), #k), val)
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001466 TestingGraph t(Type::Any(), Type::Signed32());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001467 ElementAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize, Type::Any(),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001468 MachineType::AnyTagged()};
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001469
1470 Node* store =
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001471 t.graph()->NewNode(t.simplified()->StoreElement(access), t.p0, t.p1,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001472 t.jsgraph.TrueConstant(), t.start, t.start);
1473 t.Effect(store);
1474 t.Lower();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001475 CHECK_EQ(IrOpcode::kStoreElement, store->opcode());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001476 CHECK_EQ(t.p0, store->InputAt(0));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001477 CheckChangeOf(IrOpcode::kChangeTaggedToInt32, t.p1, store->InputAt(1));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001478}
1479
1480
1481TEST(InsertChangeForLoadElement) {
1482 // TODO(titzer): test all load/store representation change insertions.
1483 TestingGraph t(Type::Any(), Type::Signed32(), Type::Any());
1484 ElementAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize, Type::Any(),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001485 MachineType::Float64()};
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001486
1487 Node* load = t.graph()->NewNode(t.simplified()->LoadElement(access), t.p0,
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001488 t.p1, t.start, t.start);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001489 t.Return(load);
1490 t.Lower();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001491 CHECK_EQ(IrOpcode::kLoadElement, load->opcode());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001492 CHECK_EQ(t.p0, load->InputAt(0));
1493 CheckChangeOf(IrOpcode::kChangeFloat64ToTagged, load, t.ret->InputAt(0));
1494}
1495
1496
1497TEST(InsertChangeForLoadField) {
1498 // TODO(titzer): test all load/store representation change insertions.
1499 TestingGraph t(Type::Any(), Type::Signed32());
1500 FieldAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001501 Handle<Name>::null(), Type::Any(),
1502 MachineType::Float64()};
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001503
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001504 Node* load = t.graph()->NewNode(t.simplified()->LoadField(access), t.p0,
1505 t.start, t.start);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001506 t.Return(load);
1507 t.Lower();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001508 CHECK_EQ(IrOpcode::kLoadField, load->opcode());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001509 CHECK_EQ(t.p0, load->InputAt(0));
1510 CheckChangeOf(IrOpcode::kChangeFloat64ToTagged, load, t.ret->InputAt(0));
1511}
1512
1513
1514TEST(InsertChangeForStoreElement) {
1515 // TODO(titzer): test all load/store representation change insertions.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001516 TestingGraph t(Type::Any(), Type::Signed32());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001517 ElementAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize, Type::Any(),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001518 MachineType::Float64()};
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001519
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001520 Node* store =
1521 t.graph()->NewNode(t.simplified()->StoreElement(access), t.p0,
1522 t.jsgraph.Int32Constant(0), t.p1, t.start, t.start);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001523 t.Effect(store);
1524 t.Lower();
1525
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001526 CHECK_EQ(IrOpcode::kStoreElement, store->opcode());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001527 CHECK_EQ(t.p0, store->InputAt(0));
1528 CheckChangeOf(IrOpcode::kChangeTaggedToFloat64, t.p1, store->InputAt(2));
1529}
1530
1531
1532TEST(InsertChangeForStoreField) {
1533 // TODO(titzer): test all load/store representation change insertions.
1534 TestingGraph t(Type::Any(), Type::Signed32());
1535 FieldAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001536 Handle<Name>::null(), Type::Any(),
1537 MachineType::Float64()};
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001538
1539 Node* store = t.graph()->NewNode(t.simplified()->StoreField(access), t.p0,
1540 t.p1, t.start, t.start);
1541 t.Effect(store);
1542 t.Lower();
1543
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001544 CHECK_EQ(IrOpcode::kStoreField, store->opcode());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001545 CHECK_EQ(t.p0, store->InputAt(0));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001546 CheckChangeOf(IrOpcode::kChangeTaggedToFloat64, t.p1, store->InputAt(1));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001547}
1548
1549
1550TEST(UpdatePhi) {
1551 TestingGraph t(Type::Any(), Type::Signed32());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001552 static const MachineType kMachineTypes[] = {
1553 MachineType::Int32(), MachineType::Uint32(), MachineType::Float64()};
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001554 Type* kTypes[] = {Type::Signed32(), Type::Unsigned32(), Type::Number()};
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001555
1556 for (size_t i = 0; i < arraysize(kMachineTypes); i++) {
1557 FieldAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize,
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001558 Handle<Name>::null(), kTypes[i], kMachineTypes[i]};
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001559
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001560 Node* load0 = t.graph()->NewNode(t.simplified()->LoadField(access), t.p0,
1561 t.start, t.start);
1562 Node* load1 = t.graph()->NewNode(t.simplified()->LoadField(access), t.p1,
1563 t.start, t.start);
1564 Node* phi =
1565 t.graph()->NewNode(t.common()->Phi(MachineRepresentation::kTagged, 2),
1566 load0, load1, t.start);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001567 t.Return(t.Use(phi, kMachineTypes[i]));
1568 t.Lower();
1569
1570 CHECK_EQ(IrOpcode::kPhi, phi->opcode());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001571 CHECK_EQ(kMachineTypes[i].representation(), PhiRepresentationOf(phi->op()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001572 }
1573}
1574
1575
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001576TEST(RunNumberDivide_minus_1_TruncatingToInt32) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001577 SimplifiedLoweringTester<Object*> t(MachineType::AnyTagged());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001578 Node* num = t.NumberToInt32(t.Parameter(0));
1579 Node* div = t.NumberDivide(num, t.jsgraph.Constant(-1));
1580 Node* trunc = t.NumberToInt32(div);
1581 t.Return(trunc);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001582
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001583 t.LowerAllNodesAndLowerChanges();
1584 t.GenerateCode();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001585
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001586 FOR_INT32_INPUTS(i) {
1587 int32_t x = 0 - *i;
1588 t.CheckNumberCall(static_cast<double>(x), static_cast<double>(*i));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001589 }
1590}
1591
1592
1593TEST(RunNumberMultiply_TruncatingToInt32) {
1594 int32_t constants[] = {-100, -10, -1, 0, 1, 100, 1000, 3000999};
1595
1596 for (size_t i = 0; i < arraysize(constants); i++) {
1597 double k = static_cast<double>(constants[i]);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001598 SimplifiedLoweringTester<Object*> t(MachineType::AnyTagged());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001599 Node* num = t.NumberToInt32(t.Parameter(0));
1600 Node* mul = t.NumberMultiply(num, t.jsgraph.Constant(k));
1601 Node* trunc = t.NumberToInt32(mul);
1602 t.Return(trunc);
1603
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001604 t.LowerAllNodesAndLowerChanges();
1605 t.GenerateCode();
1606
1607 FOR_INT32_INPUTS(i) {
1608 int32_t x = DoubleToInt32(static_cast<double>(*i) * k);
1609 t.CheckNumberCall(static_cast<double>(x), static_cast<double>(*i));
1610 }
1611 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001612}
1613
1614
1615TEST(RunNumberMultiply_TruncatingToUint32) {
1616 uint32_t constants[] = {0, 1, 2, 3, 4, 100, 1000, 1024, 2048, 3000999};
1617
1618 for (size_t i = 0; i < arraysize(constants); i++) {
1619 double k = static_cast<double>(constants[i]);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001620 SimplifiedLoweringTester<Object*> t(MachineType::AnyTagged());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001621 Node* num = t.NumberToUint32(t.Parameter(0));
1622 Node* mul = t.NumberMultiply(num, t.jsgraph.Constant(k));
1623 Node* trunc = t.NumberToUint32(mul);
1624 t.Return(trunc);
1625
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001626 t.LowerAllNodesAndLowerChanges();
1627 t.GenerateCode();
1628
1629 FOR_UINT32_INPUTS(i) {
1630 uint32_t x = DoubleToUint32(static_cast<double>(*i) * k);
1631 t.CheckNumberCall(static_cast<double>(x), static_cast<double>(*i));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001632 }
1633 }
1634}
1635
1636
1637TEST(RunNumberDivide_2_TruncatingToUint32) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001638 SimplifiedLoweringTester<Object*> t(MachineType::AnyTagged());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001639 Node* num = t.NumberToUint32(t.Parameter(0));
1640 Node* div = t.NumberDivide(num, t.jsgraph.Constant(2));
1641 Node* trunc = t.NumberToUint32(div);
1642 t.Return(trunc);
1643
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001644 t.LowerAllNodesAndLowerChanges();
1645 t.GenerateCode();
1646
1647 FOR_UINT32_INPUTS(i) {
1648 uint32_t x = DoubleToUint32(static_cast<double>(*i / 2.0));
1649 t.CheckNumberCall(static_cast<double>(x), static_cast<double>(*i));
1650 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001651}
1652
1653
1654TEST(NumberMultiply_ConstantOutOfRange) {
1655 TestingGraph t(Type::Signed32());
1656 Node* k = t.jsgraph.Constant(1000000023);
1657 Node* mul = t.graph()->NewNode(t.simplified()->NumberMultiply(), t.p0, k);
1658 Node* trunc = t.graph()->NewNode(t.simplified()->NumberToInt32(), mul);
1659 t.Return(trunc);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001660 t.Lower();
1661
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001662 CHECK_EQ(IrOpcode::kFloat64Mul, mul->opcode());
1663}
1664
1665
1666TEST(NumberMultiply_NonTruncating) {
1667 TestingGraph t(Type::Signed32());
1668 Node* k = t.jsgraph.Constant(111);
1669 Node* mul = t.graph()->NewNode(t.simplified()->NumberMultiply(), t.p0, k);
1670 t.Return(mul);
1671 t.Lower();
1672
1673 CHECK_EQ(IrOpcode::kFloat64Mul, mul->opcode());
1674}
1675
1676
1677TEST(NumberDivide_TruncatingToInt32) {
1678 int32_t constants[] = {-100, -10, 1, 4, 100, 1000};
1679
1680 for (size_t i = 0; i < arraysize(constants); i++) {
1681 TestingGraph t(Type::Signed32());
1682 Node* k = t.jsgraph.Constant(constants[i]);
1683 Node* div = t.graph()->NewNode(t.simplified()->NumberDivide(), t.p0, k);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001684 Node* use = t.Use(div, MachineType::Int32());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001685 t.Return(use);
1686 t.Lower();
1687
1688 CHECK_EQ(IrOpcode::kInt32Div, use->InputAt(0)->opcode());
1689 }
1690}
1691
1692
1693TEST(RunNumberDivide_TruncatingToInt32) {
1694 int32_t constants[] = {-100, -10, -1, 1, 2, 100, 1000, 1024, 2048};
1695
1696 for (size_t i = 0; i < arraysize(constants); i++) {
1697 int32_t k = constants[i];
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001698 SimplifiedLoweringTester<Object*> t(MachineType::AnyTagged());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001699 Node* num = t.NumberToInt32(t.Parameter(0));
1700 Node* div = t.NumberDivide(num, t.jsgraph.Constant(k));
1701 Node* trunc = t.NumberToInt32(div);
1702 t.Return(trunc);
1703
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001704 t.LowerAllNodesAndLowerChanges();
1705 t.GenerateCode();
1706
1707 FOR_INT32_INPUTS(i) {
1708 if (*i == INT_MAX) continue; // exclude max int.
1709 int32_t x = DoubleToInt32(static_cast<double>(*i) / k);
1710 t.CheckNumberCall(static_cast<double>(x), static_cast<double>(*i));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001711 }
1712 }
1713}
1714
1715
1716TEST(NumberDivide_TruncatingToUint32) {
1717 double constants[] = {1, 3, 100, 1000, 100998348};
1718
1719 for (size_t i = 0; i < arraysize(constants); i++) {
1720 TestingGraph t(Type::Unsigned32());
1721 Node* k = t.jsgraph.Constant(constants[i]);
1722 Node* div = t.graph()->NewNode(t.simplified()->NumberDivide(), t.p0, k);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001723 Node* use = t.Use(div, MachineType::Uint32());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001724 t.Return(use);
1725 t.Lower();
1726
1727 CHECK_EQ(IrOpcode::kUint32Div, use->InputAt(0)->opcode());
1728 }
1729}
1730
1731
1732TEST(RunNumberDivide_TruncatingToUint32) {
1733 uint32_t constants[] = {100, 10, 1, 1, 2, 4, 1000, 1024, 2048};
1734
1735 for (size_t i = 0; i < arraysize(constants); i++) {
1736 uint32_t k = constants[i];
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001737 SimplifiedLoweringTester<Object*> t(MachineType::AnyTagged());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001738 Node* num = t.NumberToUint32(t.Parameter(0));
1739 Node* div = t.NumberDivide(num, t.jsgraph.Constant(static_cast<double>(k)));
1740 Node* trunc = t.NumberToUint32(div);
1741 t.Return(trunc);
1742
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001743 t.LowerAllNodesAndLowerChanges();
1744 t.GenerateCode();
1745
1746 FOR_UINT32_INPUTS(i) {
1747 uint32_t x = *i / k;
1748 t.CheckNumberCall(static_cast<double>(x), static_cast<double>(*i));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001749 }
1750 }
1751}
1752
1753
1754TEST(NumberDivide_BadConstants) {
1755 {
1756 TestingGraph t(Type::Signed32());
1757 Node* k = t.jsgraph.Constant(-1);
1758 Node* div = t.graph()->NewNode(t.simplified()->NumberDivide(), t.p0, k);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001759 Node* use = t.Use(div, MachineType::Int32());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001760 t.Return(use);
1761 t.Lower();
1762
1763 CHECK_EQ(IrOpcode::kInt32Sub, use->InputAt(0)->opcode());
1764 }
1765
1766 {
1767 TestingGraph t(Type::Signed32());
1768 Node* k = t.jsgraph.Constant(0);
1769 Node* div = t.graph()->NewNode(t.simplified()->NumberDivide(), t.p0, k);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001770 Node* use = t.Use(div, MachineType::Int32());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001771 t.Return(use);
1772 t.Lower();
1773
1774 CHECK_EQ(IrOpcode::kInt32Constant, use->InputAt(0)->opcode());
1775 CHECK_EQ(0, OpParameter<int32_t>(use->InputAt(0)));
1776 }
1777
1778 {
1779 TestingGraph t(Type::Unsigned32());
1780 Node* k = t.jsgraph.Constant(0);
1781 Node* div = t.graph()->NewNode(t.simplified()->NumberDivide(), t.p0, k);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001782 Node* use = t.Use(div, MachineType::Uint32());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001783 t.Return(use);
1784 t.Lower();
1785
1786 CHECK_EQ(IrOpcode::kInt32Constant, use->InputAt(0)->opcode());
1787 CHECK_EQ(0, OpParameter<int32_t>(use->InputAt(0)));
1788 }
1789}
1790
1791
1792TEST(NumberModulus_TruncatingToInt32) {
1793 int32_t constants[] = {-100, -10, 1, 4, 100, 1000};
1794
1795 for (size_t i = 0; i < arraysize(constants); i++) {
1796 TestingGraph t(Type::Signed32());
1797 Node* k = t.jsgraph.Constant(constants[i]);
1798 Node* mod = t.graph()->NewNode(t.simplified()->NumberModulus(), t.p0, k);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001799 Node* use = t.Use(mod, MachineType::Int32());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001800 t.Return(use);
1801 t.Lower();
1802
1803 CHECK_EQ(IrOpcode::kInt32Mod, use->InputAt(0)->opcode());
1804 }
1805}
1806
1807
1808TEST(RunNumberModulus_TruncatingToInt32) {
1809 int32_t constants[] = {-100, -10, -1, 1, 2, 100, 1000, 1024, 2048};
1810
1811 for (size_t i = 0; i < arraysize(constants); i++) {
1812 int32_t k = constants[i];
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001813 SimplifiedLoweringTester<Object*> t(MachineType::AnyTagged());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001814 Node* num = t.NumberToInt32(t.Parameter(0));
1815 Node* mod = t.NumberModulus(num, t.jsgraph.Constant(k));
1816 Node* trunc = t.NumberToInt32(mod);
1817 t.Return(trunc);
1818
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001819 t.LowerAllNodesAndLowerChanges();
1820 t.GenerateCode();
1821
1822 FOR_INT32_INPUTS(i) {
1823 if (*i == INT_MAX) continue; // exclude max int.
1824 int32_t x = DoubleToInt32(std::fmod(static_cast<double>(*i), k));
1825 t.CheckNumberCall(static_cast<double>(x), static_cast<double>(*i));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001826 }
1827 }
1828}
1829
1830
1831TEST(NumberModulus_TruncatingToUint32) {
1832 double constants[] = {1, 3, 100, 1000, 100998348};
1833
1834 for (size_t i = 0; i < arraysize(constants); i++) {
1835 TestingGraph t(Type::Unsigned32());
1836 Node* k = t.jsgraph.Constant(constants[i]);
1837 Node* mod = t.graph()->NewNode(t.simplified()->NumberModulus(), t.p0, k);
1838 Node* trunc = t.graph()->NewNode(t.simplified()->NumberToUint32(), mod);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001839 t.Return(trunc);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001840 t.Lower();
1841
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001842 CHECK_EQ(IrOpcode::kUint32Mod, t.ret->InputAt(0)->InputAt(0)->opcode());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001843 }
1844}
1845
1846
1847TEST(RunNumberModulus_TruncatingToUint32) {
1848 uint32_t constants[] = {1, 2, 100, 1000, 1024, 2048};
1849
1850 for (size_t i = 0; i < arraysize(constants); i++) {
1851 uint32_t k = constants[i];
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001852 SimplifiedLoweringTester<Object*> t(MachineType::AnyTagged());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001853 Node* num = t.NumberToUint32(t.Parameter(0));
1854 Node* mod =
1855 t.NumberModulus(num, t.jsgraph.Constant(static_cast<double>(k)));
1856 Node* trunc = t.NumberToUint32(mod);
1857 t.Return(trunc);
1858
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001859 t.LowerAllNodesAndLowerChanges();
1860 t.GenerateCode();
1861
1862 FOR_UINT32_INPUTS(i) {
1863 uint32_t x = *i % k;
1864 t.CheckNumberCall(static_cast<double>(x), static_cast<double>(*i));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001865 }
1866 }
1867}
1868
1869
1870TEST(NumberModulus_Int32) {
1871 int32_t constants[] = {-100, -10, 1, 4, 100, 1000};
1872
1873 for (size_t i = 0; i < arraysize(constants); i++) {
1874 TestingGraph t(Type::Signed32());
1875 Node* k = t.jsgraph.Constant(constants[i]);
1876 Node* mod = t.graph()->NewNode(t.simplified()->NumberModulus(), t.p0, k);
1877 t.Return(mod);
1878 t.Lower();
1879
1880 CHECK_EQ(IrOpcode::kFloat64Mod, mod->opcode()); // Pesky -0 behavior.
1881 }
1882}
1883
1884
1885TEST(NumberModulus_Uint32) {
1886 const double kConstants[] = {2, 100, 1000, 1024, 2048};
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001887 const MachineType kTypes[] = {MachineType::Int32(), MachineType::Uint32()};
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001888
1889 for (auto const type : kTypes) {
1890 for (auto const c : kConstants) {
1891 TestingGraph t(Type::Unsigned32());
1892 Node* k = t.jsgraph.Constant(c);
1893 Node* mod = t.graph()->NewNode(t.simplified()->NumberModulus(), t.p0, k);
1894 Node* use = t.Use(mod, type);
1895 t.Return(use);
1896 t.Lower();
1897
1898 CHECK_EQ(IrOpcode::kUint32Mod, use->InputAt(0)->opcode());
1899 }
1900 }
1901}
1902
1903
1904TEST(PhiRepresentation) {
1905 HandleAndZoneScope scope;
1906 Zone* z = scope.main_zone();
1907
1908 struct TestData {
1909 Type* arg1;
1910 Type* arg2;
1911 MachineType use;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001912 MachineRepresentation expected;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001913 };
1914
1915 TestData test_data[] = {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001916 {Type::Signed32(), Type::Unsigned32(), MachineType::Int32(),
1917 MachineRepresentation::kWord32},
1918 {Type::Signed32(), Type::Unsigned32(), MachineType::Uint32(),
1919 MachineRepresentation::kWord32},
1920 {Type::Signed32(), Type::Signed32(), MachineType::Int32(),
1921 MachineRepresentation::kWord32},
1922 {Type::Unsigned32(), Type::Unsigned32(), MachineType::Int32(),
1923 MachineRepresentation::kWord32},
1924 {Type::Number(), Type::Signed32(), MachineType::Int32(),
1925 MachineRepresentation::kWord32}};
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001926
1927 for (auto const d : test_data) {
1928 TestingGraph t(d.arg1, d.arg2, Type::Boolean());
1929
1930 Node* br = t.graph()->NewNode(t.common()->Branch(), t.p2, t.start);
1931 Node* tb = t.graph()->NewNode(t.common()->IfTrue(), br);
1932 Node* fb = t.graph()->NewNode(t.common()->IfFalse(), br);
1933 Node* m = t.graph()->NewNode(t.common()->Merge(2), tb, fb);
1934
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001935 Node* phi = t.graph()->NewNode(
1936 t.common()->Phi(MachineRepresentation::kTagged, 2), t.p0, t.p1, m);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001937
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001938 Type* phi_type = Type::Union(d.arg1, d.arg2, z);
1939 NodeProperties::SetType(phi, phi_type);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001940
1941 Node* use = t.Use(phi, d.use);
1942 t.Return(use);
1943 t.Lower();
1944
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001945 CHECK_EQ(d.expected, PhiRepresentationOf(phi->op()));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001946 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001947}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001948
1949} // namespace compiler
1950} // namespace internal
1951} // namespace v8