• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2014 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "test/cctest/cctest.h"
6 #include "test/cctest/compiler/codegen-tester.h"
7 #include "test/cctest/compiler/value-helper.h"
8 
9 namespace v8 {
10 namespace internal {
11 namespace compiler {
12 
13 static IrOpcode::Value int32cmp_opcodes[] = {
14     IrOpcode::kWord32Equal, IrOpcode::kInt32LessThan,
15     IrOpcode::kInt32LessThanOrEqual, IrOpcode::kUint32LessThan,
16     IrOpcode::kUint32LessThanOrEqual};
17 
18 
TEST(BranchCombineWord32EqualZero_1)19 TEST(BranchCombineWord32EqualZero_1) {
20   // Test combining a branch with x == 0
21   RawMachineAssemblerTester<int32_t> m(MachineType::Int32());
22   int32_t eq_constant = -1033;
23   int32_t ne_constant = 825118;
24   Node* p0 = m.Parameter(0);
25 
26   RawMachineLabel blocka, blockb;
27   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 
TEST(BranchCombineWord32EqualZero_chain)41 TEST(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++) {
47     RawMachineAssemblerTester<int32_t> m(MachineType::Int32());
48     Node* p0 = m.Parameter(0);
49     RawMachineLabel blocka, blockb;
50     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 
TEST(BranchCombineInt32LessThanZero_1)70 TEST(BranchCombineInt32LessThanZero_1) {
71   // Test combining a branch with x < 0
72   RawMachineAssemblerTester<int32_t> m(MachineType::Int32());
73   int32_t eq_constant = -1433;
74   int32_t ne_constant = 845118;
75   Node* p0 = m.Parameter(0);
76 
77   RawMachineLabel blocka, blockb;
78   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 
TEST(BranchCombineUint32LessThan100_1)92 TEST(BranchCombineUint32LessThan100_1) {
93   // Test combining a branch with x < 100
94   RawMachineAssemblerTester<int32_t> m(MachineType::Uint32());
95   int32_t eq_constant = 1471;
96   int32_t ne_constant = 88845718;
97   Node* p0 = m.Parameter(0);
98 
99   RawMachineLabel blocka, blockb;
100   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 
TEST(BranchCombineUint32LessThanOrEqual100_1)114 TEST(BranchCombineUint32LessThanOrEqual100_1) {
115   // Test combining a branch with x <= 100
116   RawMachineAssemblerTester<int32_t> m(MachineType::Uint32());
117   int32_t eq_constant = 1479;
118   int32_t ne_constant = 77845719;
119   Node* p0 = m.Parameter(0);
120 
121   RawMachineLabel blocka, blockb;
122   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 
TEST(BranchCombineZeroLessThanInt32_1)136 TEST(BranchCombineZeroLessThanInt32_1) {
137   // Test combining a branch with 0 < x
138   RawMachineAssemblerTester<int32_t> m(MachineType::Int32());
139   int32_t eq_constant = -2033;
140   int32_t ne_constant = 225118;
141   Node* p0 = m.Parameter(0);
142 
143   RawMachineLabel blocka, blockb;
144   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 
TEST(BranchCombineInt32GreaterThanZero_1)158 TEST(BranchCombineInt32GreaterThanZero_1) {
159   // Test combining a branch with x > 0
160   RawMachineAssemblerTester<int32_t> m(MachineType::Int32());
161   int32_t eq_constant = -1073;
162   int32_t ne_constant = 825178;
163   Node* p0 = m.Parameter(0);
164 
165   RawMachineLabel blocka, blockb;
166   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 
TEST(BranchCombineWord32EqualP)180 TEST(BranchCombineWord32EqualP) {
181   // Test combining a branch with an Word32Equal.
182   RawMachineAssemblerTester<int32_t> m(MachineType::Int32(),
183                                        MachineType::Int32());
184   int32_t eq_constant = -1035;
185   int32_t ne_constant = 825018;
186   Node* p0 = m.Parameter(0);
187   Node* p1 = m.Parameter(1);
188 
189   RawMachineLabel blocka, blockb;
190   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 
TEST(BranchCombineWord32EqualI)207 TEST(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) {
213       RawMachineAssemblerTester<int32_t> m(MachineType::Int32());
214       int32_t a = *i;
215 
216       Node* p0 = m.Int32Constant(a);
217       Node* p1 = m.Parameter(0);
218 
219       RawMachineLabel blocka, blockb;
220       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 
TEST(BranchCombineInt32CmpP)237 TEST(BranchCombineInt32CmpP) {
238   int32_t eq_constant = -1235;
239   int32_t ne_constant = 725018;
240 
241   for (int op = 0; op < 2; op++) {
242     RawMachineAssemblerTester<int32_t> m(MachineType::Int32(),
243                                          MachineType::Int32());
244     Node* p0 = m.Parameter(0);
245     Node* p1 = m.Parameter(1);
246 
247     RawMachineLabel blocka, blockb;
248     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 
TEST(BranchCombineInt32CmpI)269 TEST(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) {
275       RawMachineAssemblerTester<int32_t> m(MachineType::Int32());
276       int32_t a = *i;
277       Node* p0 = m.Int32Constant(a);
278       Node* p1 = m.Parameter(0);
279 
280       RawMachineLabel blocka, blockb;
281       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.
303 class CmpMaterializeBoolGen : public BinopGen<int32_t> {
304  public:
305   CompareWrapper w;
306   bool invert;
307 
CmpMaterializeBoolGen(IrOpcode::Value opcode,bool i)308   CmpMaterializeBoolGen(IrOpcode::Value opcode, bool i)
309       : w(opcode), invert(i) {}
310 
gen(RawMachineAssemblerTester<int32_t> * m,Node * a,Node * b)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   }
expected(int32_t a,int32_t b)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.
324 class 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 
CmpBranchGen(IrOpcode::Value opcode,bool i,bool t,int32_t eq,int32_t ne)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 
gen(RawMachineAssemblerTester<int32_t> * m,Node * a,Node * b)335   virtual void gen(RawMachineAssemblerTester<int32_t>* m, Node* a, Node* b) {
336     RawMachineLabel blocka, blockb;
337     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   }
expected(int32_t a,int32_t b)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 
TEST(BranchCombineInt32CmpAllInputShapes_materialized)359 TEST(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 
TEST(BranchCombineInt32CmpAllInputShapes_inverted_materialized)368 TEST(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 
TEST(BranchCombineInt32CmpAllInputShapes_branch_true)377 TEST(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 
TEST(BranchCombineInt32CmpAllInputShapes_branch_false)386 TEST(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 
TEST(BranchCombineInt32CmpAllInputShapes_inverse_branch_true)395 TEST(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 
TEST(BranchCombineInt32CmpAllInputShapes_inverse_branch_false)404 TEST(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 
TEST(BranchCombineFloat64Compares)413 TEST(BranchCombineFloat64Compares) {
414   double inf = V8_INFINITY;
415   double nan = std::numeric_limits<double>::quiet_NaN();
416   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;
432       Node* a = m.LoadFromPointer(&input_a, MachineType::Float64());
433       Node* b = m.LoadFromPointer(&input_b, MachineType::Float64());
434 
435       RawMachineLabel blocka, blockb;
436       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 
444       for (size_t i = 0; i < arraysize(inputs); ++i) {
445         for (size_t j = 0; j < arraysize(inputs); ++j) {
446           input_a = inputs[i];
447           input_b = inputs[j];
448           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 }
459 
460 }  // namespace compiler
461 }  // namespace internal
462 }  // namespace v8
463