blob: c5c41667a02f76c4ac2f4f9b415e10afe3971533 [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 Murdochb8a8cc12014-11-26 15:28:44 +00005#include "test/cctest/cctest.h"
6#include "test/cctest/compiler/codegen-tester.h"
7#include "test/cctest/compiler/value-helper.h"
8
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009namespace v8 {
10namespace internal {
11namespace compiler {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012
13static IrOpcode::Value int32cmp_opcodes[] = {
14 IrOpcode::kWord32Equal, IrOpcode::kInt32LessThan,
15 IrOpcode::kInt32LessThanOrEqual, IrOpcode::kUint32LessThan,
16 IrOpcode::kUint32LessThanOrEqual};
17
18
19TEST(BranchCombineWord32EqualZero_1) {
20 // Test combining a branch with x == 0
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000021 RawMachineAssemblerTester<int32_t> m(MachineType::Int32());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000022 int32_t eq_constant = -1033;
23 int32_t ne_constant = 825118;
24 Node* p0 = m.Parameter(0);
25
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000026 RawMachineLabel blocka, blockb;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000027 m.Branch(m.Word32Equal(p0, m.Int32Constant(0)), &blocka, &blockb);
28 m.Bind(&blocka);
29 m.Return(m.Int32Constant(eq_constant));
30 m.Bind(&blockb);
31 m.Return(m.Int32Constant(ne_constant));
32
33 FOR_INT32_INPUTS(i) {
34 int32_t a = *i;
35 int32_t expect = a == 0 ? eq_constant : ne_constant;
36 CHECK_EQ(expect, m.Call(a));
37 }
38}
39
40
41TEST(BranchCombineWord32EqualZero_chain) {
42 // Test combining a branch with a chain of x == 0 == 0 == 0 ...
43 int32_t eq_constant = -1133;
44 int32_t ne_constant = 815118;
45
46 for (int k = 0; k < 6; k++) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000047 RawMachineAssemblerTester<int32_t> m(MachineType::Int32());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000048 Node* p0 = m.Parameter(0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000049 RawMachineLabel blocka, blockb;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000050 Node* cond = p0;
51 for (int j = 0; j < k; j++) {
52 cond = m.Word32Equal(cond, m.Int32Constant(0));
53 }
54 m.Branch(cond, &blocka, &blockb);
55 m.Bind(&blocka);
56 m.Return(m.Int32Constant(eq_constant));
57 m.Bind(&blockb);
58 m.Return(m.Int32Constant(ne_constant));
59
60 FOR_INT32_INPUTS(i) {
61 int32_t a = *i;
62 int32_t expect = (k & 1) == 1 ? (a == 0 ? eq_constant : ne_constant)
63 : (a == 0 ? ne_constant : eq_constant);
64 CHECK_EQ(expect, m.Call(a));
65 }
66 }
67}
68
69
70TEST(BranchCombineInt32LessThanZero_1) {
71 // Test combining a branch with x < 0
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000072 RawMachineAssemblerTester<int32_t> m(MachineType::Int32());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000073 int32_t eq_constant = -1433;
74 int32_t ne_constant = 845118;
75 Node* p0 = m.Parameter(0);
76
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000077 RawMachineLabel blocka, blockb;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000078 m.Branch(m.Int32LessThan(p0, m.Int32Constant(0)), &blocka, &blockb);
79 m.Bind(&blocka);
80 m.Return(m.Int32Constant(eq_constant));
81 m.Bind(&blockb);
82 m.Return(m.Int32Constant(ne_constant));
83
84 FOR_INT32_INPUTS(i) {
85 int32_t a = *i;
86 int32_t expect = a < 0 ? eq_constant : ne_constant;
87 CHECK_EQ(expect, m.Call(a));
88 }
89}
90
91
92TEST(BranchCombineUint32LessThan100_1) {
93 // Test combining a branch with x < 100
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000094 RawMachineAssemblerTester<int32_t> m(MachineType::Uint32());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000095 int32_t eq_constant = 1471;
96 int32_t ne_constant = 88845718;
97 Node* p0 = m.Parameter(0);
98
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000099 RawMachineLabel blocka, blockb;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000100 m.Branch(m.Uint32LessThan(p0, m.Int32Constant(100)), &blocka, &blockb);
101 m.Bind(&blocka);
102 m.Return(m.Int32Constant(eq_constant));
103 m.Bind(&blockb);
104 m.Return(m.Int32Constant(ne_constant));
105
106 FOR_UINT32_INPUTS(i) {
107 uint32_t a = *i;
108 int32_t expect = a < 100 ? eq_constant : ne_constant;
109 CHECK_EQ(expect, m.Call(a));
110 }
111}
112
113
114TEST(BranchCombineUint32LessThanOrEqual100_1) {
115 // Test combining a branch with x <= 100
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000116 RawMachineAssemblerTester<int32_t> m(MachineType::Uint32());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000117 int32_t eq_constant = 1479;
118 int32_t ne_constant = 77845719;
119 Node* p0 = m.Parameter(0);
120
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000121 RawMachineLabel blocka, blockb;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000122 m.Branch(m.Uint32LessThanOrEqual(p0, m.Int32Constant(100)), &blocka, &blockb);
123 m.Bind(&blocka);
124 m.Return(m.Int32Constant(eq_constant));
125 m.Bind(&blockb);
126 m.Return(m.Int32Constant(ne_constant));
127
128 FOR_UINT32_INPUTS(i) {
129 uint32_t a = *i;
130 int32_t expect = a <= 100 ? eq_constant : ne_constant;
131 CHECK_EQ(expect, m.Call(a));
132 }
133}
134
135
136TEST(BranchCombineZeroLessThanInt32_1) {
137 // Test combining a branch with 0 < x
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000138 RawMachineAssemblerTester<int32_t> m(MachineType::Int32());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000139 int32_t eq_constant = -2033;
140 int32_t ne_constant = 225118;
141 Node* p0 = m.Parameter(0);
142
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000143 RawMachineLabel blocka, blockb;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000144 m.Branch(m.Int32LessThan(m.Int32Constant(0), p0), &blocka, &blockb);
145 m.Bind(&blocka);
146 m.Return(m.Int32Constant(eq_constant));
147 m.Bind(&blockb);
148 m.Return(m.Int32Constant(ne_constant));
149
150 FOR_INT32_INPUTS(i) {
151 int32_t a = *i;
152 int32_t expect = 0 < a ? eq_constant : ne_constant;
153 CHECK_EQ(expect, m.Call(a));
154 }
155}
156
157
158TEST(BranchCombineInt32GreaterThanZero_1) {
159 // Test combining a branch with x > 0
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000160 RawMachineAssemblerTester<int32_t> m(MachineType::Int32());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000161 int32_t eq_constant = -1073;
162 int32_t ne_constant = 825178;
163 Node* p0 = m.Parameter(0);
164
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000165 RawMachineLabel blocka, blockb;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000166 m.Branch(m.Int32GreaterThan(p0, m.Int32Constant(0)), &blocka, &blockb);
167 m.Bind(&blocka);
168 m.Return(m.Int32Constant(eq_constant));
169 m.Bind(&blockb);
170 m.Return(m.Int32Constant(ne_constant));
171
172 FOR_INT32_INPUTS(i) {
173 int32_t a = *i;
174 int32_t expect = a > 0 ? eq_constant : ne_constant;
175 CHECK_EQ(expect, m.Call(a));
176 }
177}
178
179
180TEST(BranchCombineWord32EqualP) {
181 // Test combining a branch with an Word32Equal.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000182 RawMachineAssemblerTester<int32_t> m(MachineType::Int32(),
183 MachineType::Int32());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000184 int32_t eq_constant = -1035;
185 int32_t ne_constant = 825018;
186 Node* p0 = m.Parameter(0);
187 Node* p1 = m.Parameter(1);
188
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000189 RawMachineLabel blocka, blockb;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000190 m.Branch(m.Word32Equal(p0, p1), &blocka, &blockb);
191 m.Bind(&blocka);
192 m.Return(m.Int32Constant(eq_constant));
193 m.Bind(&blockb);
194 m.Return(m.Int32Constant(ne_constant));
195
196 FOR_INT32_INPUTS(i) {
197 FOR_INT32_INPUTS(j) {
198 int32_t a = *i;
199 int32_t b = *j;
200 int32_t expect = a == b ? eq_constant : ne_constant;
201 CHECK_EQ(expect, m.Call(a, b));
202 }
203 }
204}
205
206
207TEST(BranchCombineWord32EqualI) {
208 int32_t eq_constant = -1135;
209 int32_t ne_constant = 925718;
210
211 for (int left = 0; left < 2; left++) {
212 FOR_INT32_INPUTS(i) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000213 RawMachineAssemblerTester<int32_t> m(MachineType::Int32());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000214 int32_t a = *i;
215
216 Node* p0 = m.Int32Constant(a);
217 Node* p1 = m.Parameter(0);
218
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000219 RawMachineLabel blocka, blockb;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000220 if (left == 1) m.Branch(m.Word32Equal(p0, p1), &blocka, &blockb);
221 if (left == 0) m.Branch(m.Word32Equal(p1, p0), &blocka, &blockb);
222 m.Bind(&blocka);
223 m.Return(m.Int32Constant(eq_constant));
224 m.Bind(&blockb);
225 m.Return(m.Int32Constant(ne_constant));
226
227 FOR_INT32_INPUTS(j) {
228 int32_t b = *j;
229 int32_t expect = a == b ? eq_constant : ne_constant;
230 CHECK_EQ(expect, m.Call(b));
231 }
232 }
233 }
234}
235
236
237TEST(BranchCombineInt32CmpP) {
238 int32_t eq_constant = -1235;
239 int32_t ne_constant = 725018;
240
241 for (int op = 0; op < 2; op++) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000242 RawMachineAssemblerTester<int32_t> m(MachineType::Int32(),
243 MachineType::Int32());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000244 Node* p0 = m.Parameter(0);
245 Node* p1 = m.Parameter(1);
246
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000247 RawMachineLabel blocka, blockb;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000248 if (op == 0) m.Branch(m.Int32LessThan(p0, p1), &blocka, &blockb);
249 if (op == 1) m.Branch(m.Int32LessThanOrEqual(p0, p1), &blocka, &blockb);
250 m.Bind(&blocka);
251 m.Return(m.Int32Constant(eq_constant));
252 m.Bind(&blockb);
253 m.Return(m.Int32Constant(ne_constant));
254
255 FOR_INT32_INPUTS(i) {
256 FOR_INT32_INPUTS(j) {
257 int32_t a = *i;
258 int32_t b = *j;
259 int32_t expect = 0;
260 if (op == 0) expect = a < b ? eq_constant : ne_constant;
261 if (op == 1) expect = a <= b ? eq_constant : ne_constant;
262 CHECK_EQ(expect, m.Call(a, b));
263 }
264 }
265 }
266}
267
268
269TEST(BranchCombineInt32CmpI) {
270 int32_t eq_constant = -1175;
271 int32_t ne_constant = 927711;
272
273 for (int op = 0; op < 2; op++) {
274 FOR_INT32_INPUTS(i) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000275 RawMachineAssemblerTester<int32_t> m(MachineType::Int32());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000276 int32_t a = *i;
277 Node* p0 = m.Int32Constant(a);
278 Node* p1 = m.Parameter(0);
279
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000280 RawMachineLabel blocka, blockb;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000281 if (op == 0) m.Branch(m.Int32LessThan(p0, p1), &blocka, &blockb);
282 if (op == 1) m.Branch(m.Int32LessThanOrEqual(p0, p1), &blocka, &blockb);
283 m.Bind(&blocka);
284 m.Return(m.Int32Constant(eq_constant));
285 m.Bind(&blockb);
286 m.Return(m.Int32Constant(ne_constant));
287
288 FOR_INT32_INPUTS(j) {
289 int32_t b = *j;
290 int32_t expect = 0;
291 if (op == 0) expect = a < b ? eq_constant : ne_constant;
292 if (op == 1) expect = a <= b ? eq_constant : ne_constant;
293 CHECK_EQ(expect, m.Call(b));
294 }
295 }
296 }
297}
298
299
300// Now come the sophisticated tests for many input shape combinations.
301
302// Materializes a boolean (1 or 0) from a comparison.
303class CmpMaterializeBoolGen : public BinopGen<int32_t> {
304 public:
305 CompareWrapper w;
306 bool invert;
307
308 CmpMaterializeBoolGen(IrOpcode::Value opcode, bool i)
309 : w(opcode), invert(i) {}
310
311 virtual void gen(RawMachineAssemblerTester<int32_t>* m, Node* a, Node* b) {
312 Node* cond = w.MakeNode(m, a, b);
313 if (invert) cond = m->Word32Equal(cond, m->Int32Constant(0));
314 m->Return(cond);
315 }
316 virtual int32_t expected(int32_t a, int32_t b) {
317 if (invert) return !w.Int32Compare(a, b) ? 1 : 0;
318 return w.Int32Compare(a, b) ? 1 : 0;
319 }
320};
321
322
323// Generates a branch and return one of two values from a comparison.
324class CmpBranchGen : public BinopGen<int32_t> {
325 public:
326 CompareWrapper w;
327 bool invert;
328 bool true_first;
329 int32_t eq_constant;
330 int32_t ne_constant;
331
332 CmpBranchGen(IrOpcode::Value opcode, bool i, bool t, int32_t eq, int32_t ne)
333 : w(opcode), invert(i), true_first(t), eq_constant(eq), ne_constant(ne) {}
334
335 virtual void gen(RawMachineAssemblerTester<int32_t>* m, Node* a, Node* b) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000336 RawMachineLabel blocka, blockb;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000337 Node* cond = w.MakeNode(m, a, b);
338 if (invert) cond = m->Word32Equal(cond, m->Int32Constant(0));
339 m->Branch(cond, &blocka, &blockb);
340 if (true_first) {
341 m->Bind(&blocka);
342 m->Return(m->Int32Constant(eq_constant));
343 m->Bind(&blockb);
344 m->Return(m->Int32Constant(ne_constant));
345 } else {
346 m->Bind(&blockb);
347 m->Return(m->Int32Constant(ne_constant));
348 m->Bind(&blocka);
349 m->Return(m->Int32Constant(eq_constant));
350 }
351 }
352 virtual int32_t expected(int32_t a, int32_t b) {
353 if (invert) return !w.Int32Compare(a, b) ? eq_constant : ne_constant;
354 return w.Int32Compare(a, b) ? eq_constant : ne_constant;
355 }
356};
357
358
359TEST(BranchCombineInt32CmpAllInputShapes_materialized) {
360 for (size_t i = 0; i < arraysize(int32cmp_opcodes); i++) {
361 CmpMaterializeBoolGen gen(int32cmp_opcodes[i], false);
362 Int32BinopInputShapeTester tester(&gen);
363 tester.TestAllInputShapes();
364 }
365}
366
367
368TEST(BranchCombineInt32CmpAllInputShapes_inverted_materialized) {
369 for (size_t i = 0; i < arraysize(int32cmp_opcodes); i++) {
370 CmpMaterializeBoolGen gen(int32cmp_opcodes[i], true);
371 Int32BinopInputShapeTester tester(&gen);
372 tester.TestAllInputShapes();
373 }
374}
375
376
377TEST(BranchCombineInt32CmpAllInputShapes_branch_true) {
378 for (int i = 0; i < static_cast<int>(arraysize(int32cmp_opcodes)); i++) {
379 CmpBranchGen gen(int32cmp_opcodes[i], false, false, 995 + i, -1011 - i);
380 Int32BinopInputShapeTester tester(&gen);
381 tester.TestAllInputShapes();
382 }
383}
384
385
386TEST(BranchCombineInt32CmpAllInputShapes_branch_false) {
387 for (int i = 0; i < static_cast<int>(arraysize(int32cmp_opcodes)); i++) {
388 CmpBranchGen gen(int32cmp_opcodes[i], false, true, 795 + i, -2011 - i);
389 Int32BinopInputShapeTester tester(&gen);
390 tester.TestAllInputShapes();
391 }
392}
393
394
395TEST(BranchCombineInt32CmpAllInputShapes_inverse_branch_true) {
396 for (int i = 0; i < static_cast<int>(arraysize(int32cmp_opcodes)); i++) {
397 CmpBranchGen gen(int32cmp_opcodes[i], true, false, 695 + i, -3011 - i);
398 Int32BinopInputShapeTester tester(&gen);
399 tester.TestAllInputShapes();
400 }
401}
402
403
404TEST(BranchCombineInt32CmpAllInputShapes_inverse_branch_false) {
405 for (int i = 0; i < static_cast<int>(arraysize(int32cmp_opcodes)); i++) {
406 CmpBranchGen gen(int32cmp_opcodes[i], true, true, 595 + i, -4011 - i);
407 Int32BinopInputShapeTester tester(&gen);
408 tester.TestAllInputShapes();
409 }
410}
411
412
413TEST(BranchCombineFloat64Compares) {
414 double inf = V8_INFINITY;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000415 double nan = std::numeric_limits<double>::quiet_NaN();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000416 double inputs[] = {0.0, 1.0, -1.0, -inf, inf, nan};
417
418 int32_t eq_constant = -1733;
419 int32_t ne_constant = 915118;
420
421 double input_a = 0.0;
422 double input_b = 0.0;
423
424 CompareWrapper cmps[] = {CompareWrapper(IrOpcode::kFloat64Equal),
425 CompareWrapper(IrOpcode::kFloat64LessThan),
426 CompareWrapper(IrOpcode::kFloat64LessThanOrEqual)};
427
428 for (size_t c = 0; c < arraysize(cmps); c++) {
429 CompareWrapper cmp = cmps[c];
430 for (int invert = 0; invert < 2; invert++) {
431 RawMachineAssemblerTester<int32_t> m;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000432 Node* a = m.LoadFromPointer(&input_a, MachineType::Float64());
433 Node* b = m.LoadFromPointer(&input_b, MachineType::Float64());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000434
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000435 RawMachineLabel blocka, blockb;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000436 Node* cond = cmp.MakeNode(&m, a, b);
437 if (invert) cond = m.Word32Equal(cond, m.Int32Constant(0));
438 m.Branch(cond, &blocka, &blockb);
439 m.Bind(&blocka);
440 m.Return(m.Int32Constant(eq_constant));
441 m.Bind(&blockb);
442 m.Return(m.Int32Constant(ne_constant));
443
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000444 for (size_t i = 0; i < arraysize(inputs); ++i) {
445 for (size_t j = 0; j < arraysize(inputs); ++j) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000446 input_a = inputs[i];
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000447 input_b = inputs[j];
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000448 int32_t expected =
449 invert ? (cmp.Float64Compare(input_a, input_b) ? ne_constant
450 : eq_constant)
451 : (cmp.Float64Compare(input_a, input_b) ? eq_constant
452 : ne_constant);
453 CHECK_EQ(expected, m.Call());
454 }
455 }
456 }
457 }
458}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000459
Ben Murdochc5610432016-08-08 18:44:38 +0100460TEST(BranchCombineEffectLevel) {
461 // Test that the load doesn't get folded into the branch, as there's a store
462 // between them. See http://crbug.com/611976.
463 int32_t input = 0;
464
465 RawMachineAssemblerTester<int32_t> m;
466 Node* a = m.LoadFromPointer(&input, MachineType::Int32());
467 Node* compare = m.Word32And(a, m.Int32Constant(1));
468 Node* equal = m.Word32Equal(compare, m.Int32Constant(0));
469 m.StoreToPointer(&input, MachineRepresentation::kWord32, m.Int32Constant(1));
470
471 RawMachineLabel blocka, blockb;
472 m.Branch(equal, &blocka, &blockb);
473 m.Bind(&blocka);
474 m.Return(m.Int32Constant(42));
475 m.Bind(&blockb);
476 m.Return(m.Int32Constant(0));
477
478 CHECK_EQ(42, m.Call());
479}
480
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000481} // namespace compiler
482} // namespace internal
483} // namespace v8