OLD | NEW |
(Empty) | |
| 1 // Copyright 2014 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "src/v8.h" |
| 6 |
| 7 #include "test/cctest/cctest.h" |
| 8 #include "test/cctest/compiler/codegen-tester.h" |
| 9 #include "test/cctest/compiler/value-helper.h" |
| 10 |
| 11 #if V8_TURBOFAN_TARGET |
| 12 |
| 13 using namespace v8::internal; |
| 14 using namespace v8::internal::compiler; |
| 15 |
| 16 typedef RawMachineAssembler::Label MLabel; |
| 17 |
| 18 static IrOpcode::Value int32cmp_opcodes[] = { |
| 19 IrOpcode::kWord32Equal, |
| 20 IrOpcode::kInt32LessThan, |
| 21 IrOpcode::kInt32LessThanOrEqual, |
| 22 IrOpcode::kUint32LessThan, |
| 23 IrOpcode::kUint32LessThanOrEqual |
| 24 }; |
| 25 |
| 26 |
| 27 TEST(BranchCombineWord32EqualZero_1) { |
| 28 // Test combining a branch with x == 0 |
| 29 RawMachineAssemblerTester<int32_t> m(kMachineWord32); |
| 30 int32_t eq_constant = -1033; |
| 31 int32_t ne_constant = 825118; |
| 32 Node* p0 = m.Parameter(0); |
| 33 |
| 34 MLabel blocka, blockb; |
| 35 m.Branch(m.Word32Equal(p0, m.Int32Constant(0)), &blocka, &blockb); |
| 36 m.Bind(&blocka); |
| 37 m.Return(m.Int32Constant(eq_constant)); |
| 38 m.Bind(&blockb); |
| 39 m.Return(m.Int32Constant(ne_constant)); |
| 40 |
| 41 FOR_INT32_INPUTS(i) { |
| 42 int32_t a = *i; |
| 43 int32_t expect = a == 0 ? eq_constant : ne_constant; |
| 44 CHECK_EQ(expect, m.Call(a)); |
| 45 } |
| 46 } |
| 47 |
| 48 |
| 49 TEST(BranchCombineWord32EqualZero_chain) { |
| 50 // Test combining a branch with a chain of x == 0 == 0 == 0 ... |
| 51 int32_t eq_constant = -1133; |
| 52 int32_t ne_constant = 815118; |
| 53 |
| 54 for (int k = 0; k < 6; k++) { |
| 55 RawMachineAssemblerTester<int32_t> m(kMachineWord32); |
| 56 Node* p0 = m.Parameter(0); |
| 57 MLabel blocka, blockb; |
| 58 Node* cond = p0; |
| 59 for (int j = 0; j < k; j++) { |
| 60 cond = m.Word32Equal(cond, m.Int32Constant(0)); |
| 61 } |
| 62 m.Branch(cond, &blocka, &blockb); |
| 63 m.Bind(&blocka); |
| 64 m.Return(m.Int32Constant(eq_constant)); |
| 65 m.Bind(&blockb); |
| 66 m.Return(m.Int32Constant(ne_constant)); |
| 67 |
| 68 FOR_INT32_INPUTS(i) { |
| 69 int32_t a = *i; |
| 70 int32_t expect = (k & 1) == 1 ? |
| 71 (a == 0 ? eq_constant : ne_constant) : |
| 72 (a == 0 ? ne_constant : eq_constant); |
| 73 CHECK_EQ(expect, m.Call(a)); |
| 74 } |
| 75 } |
| 76 } |
| 77 |
| 78 |
| 79 TEST(BranchCombineInt32LessThanZero_1) { |
| 80 // Test combining a branch with x < 0 |
| 81 RawMachineAssemblerTester<int32_t> m(kMachineWord32); |
| 82 int32_t eq_constant = -1433; |
| 83 int32_t ne_constant = 845118; |
| 84 Node* p0 = m.Parameter(0); |
| 85 |
| 86 MLabel blocka, blockb; |
| 87 m.Branch(m.Int32LessThan(p0, m.Int32Constant(0)), &blocka, &blockb); |
| 88 m.Bind(&blocka); |
| 89 m.Return(m.Int32Constant(eq_constant)); |
| 90 m.Bind(&blockb); |
| 91 m.Return(m.Int32Constant(ne_constant)); |
| 92 |
| 93 FOR_INT32_INPUTS(i) { |
| 94 int32_t a = *i; |
| 95 int32_t expect = a < 0 ? eq_constant : ne_constant; |
| 96 CHECK_EQ(expect, m.Call(a)); |
| 97 } |
| 98 } |
| 99 |
| 100 |
| 101 TEST(BranchCombineUint32LessThan100_1) { |
| 102 // Test combining a branch with x < 100 |
| 103 RawMachineAssemblerTester<int32_t> m(kMachineWord32); |
| 104 int32_t eq_constant = 1471; |
| 105 int32_t ne_constant = 88845718; |
| 106 Node* p0 = m.Parameter(0); |
| 107 |
| 108 MLabel blocka, blockb; |
| 109 m.Branch(m.Uint32LessThan(p0, m.Int32Constant(100)), &blocka, &blockb); |
| 110 m.Bind(&blocka); |
| 111 m.Return(m.Int32Constant(eq_constant)); |
| 112 m.Bind(&blockb); |
| 113 m.Return(m.Int32Constant(ne_constant)); |
| 114 |
| 115 FOR_UINT32_INPUTS(i) { |
| 116 uint32_t a = *i; |
| 117 int32_t expect = a < 100 ? eq_constant : ne_constant; |
| 118 CHECK_EQ(expect, m.Call(a)); |
| 119 } |
| 120 } |
| 121 |
| 122 |
| 123 TEST(BranchCombineUint32LessThanOrEqual100_1) { |
| 124 // Test combining a branch with x <= 100 |
| 125 RawMachineAssemblerTester<int32_t> m(kMachineWord32); |
| 126 int32_t eq_constant = 1479; |
| 127 int32_t ne_constant = 77845719; |
| 128 Node* p0 = m.Parameter(0); |
| 129 |
| 130 MLabel blocka, blockb; |
| 131 m.Branch(m.Uint32LessThanOrEqual(p0, m.Int32Constant(100)), &blocka, &blockb); |
| 132 m.Bind(&blocka); |
| 133 m.Return(m.Int32Constant(eq_constant)); |
| 134 m.Bind(&blockb); |
| 135 m.Return(m.Int32Constant(ne_constant)); |
| 136 |
| 137 FOR_UINT32_INPUTS(i) { |
| 138 uint32_t a = *i; |
| 139 int32_t expect = a <= 100 ? eq_constant : ne_constant; |
| 140 CHECK_EQ(expect, m.Call(a)); |
| 141 } |
| 142 } |
| 143 |
| 144 |
| 145 TEST(BranchCombineZeroLessThanInt32_1) { |
| 146 // Test combining a branch with 0 < x |
| 147 RawMachineAssemblerTester<int32_t> m(kMachineWord32); |
| 148 int32_t eq_constant = -2033; |
| 149 int32_t ne_constant = 225118; |
| 150 Node* p0 = m.Parameter(0); |
| 151 |
| 152 MLabel blocka, blockb; |
| 153 m.Branch(m.Int32LessThan(m.Int32Constant(0), p0), &blocka, &blockb); |
| 154 m.Bind(&blocka); |
| 155 m.Return(m.Int32Constant(eq_constant)); |
| 156 m.Bind(&blockb); |
| 157 m.Return(m.Int32Constant(ne_constant)); |
| 158 |
| 159 FOR_INT32_INPUTS(i) { |
| 160 int32_t a = *i; |
| 161 int32_t expect = 0 < a ? eq_constant : ne_constant; |
| 162 CHECK_EQ(expect, m.Call(a)); |
| 163 } |
| 164 } |
| 165 |
| 166 |
| 167 TEST(BranchCombineInt32GreaterThanZero_1) { |
| 168 // Test combining a branch with x > 0 |
| 169 RawMachineAssemblerTester<int32_t> m(kMachineWord32); |
| 170 int32_t eq_constant = -1073; |
| 171 int32_t ne_constant = 825178; |
| 172 Node* p0 = m.Parameter(0); |
| 173 |
| 174 MLabel blocka, blockb; |
| 175 m.Branch(m.Int32GreaterThan(p0, m.Int32Constant(0)), &blocka, &blockb); |
| 176 m.Bind(&blocka); |
| 177 m.Return(m.Int32Constant(eq_constant)); |
| 178 m.Bind(&blockb); |
| 179 m.Return(m.Int32Constant(ne_constant)); |
| 180 |
| 181 FOR_INT32_INPUTS(i) { |
| 182 int32_t a = *i; |
| 183 int32_t expect = a > 0 ? eq_constant : ne_constant; |
| 184 CHECK_EQ(expect, m.Call(a)); |
| 185 } |
| 186 } |
| 187 |
| 188 |
| 189 TEST(BranchCombineWord32EqualP) { |
| 190 // Test combining a branch with an Word32Equal. |
| 191 RawMachineAssemblerTester<int32_t> m(kMachineWord32, kMachineWord32); |
| 192 int32_t eq_constant = -1035; |
| 193 int32_t ne_constant = 825018; |
| 194 Node* p0 = m.Parameter(0); |
| 195 Node* p1 = m.Parameter(1); |
| 196 |
| 197 MLabel blocka, blockb; |
| 198 m.Branch(m.Word32Equal(p0, p1), &blocka, &blockb); |
| 199 m.Bind(&blocka); |
| 200 m.Return(m.Int32Constant(eq_constant)); |
| 201 m.Bind(&blockb); |
| 202 m.Return(m.Int32Constant(ne_constant)); |
| 203 |
| 204 FOR_INT32_INPUTS(i) { |
| 205 FOR_INT32_INPUTS(j) { |
| 206 int32_t a = *i; |
| 207 int32_t b = *j; |
| 208 int32_t expect = a == b ? eq_constant : ne_constant; |
| 209 CHECK_EQ(expect, m.Call(a, b)); |
| 210 } |
| 211 } |
| 212 } |
| 213 |
| 214 |
| 215 TEST(BranchCombineWord32EqualI) { |
| 216 int32_t eq_constant = -1135; |
| 217 int32_t ne_constant = 925718; |
| 218 |
| 219 for (int left = 0; left < 2; left++) { |
| 220 FOR_INT32_INPUTS(i) { |
| 221 RawMachineAssemblerTester<int32_t> m(kMachineWord32); |
| 222 int32_t a = *i; |
| 223 |
| 224 Node* p0 = m.Int32Constant(a); |
| 225 Node* p1 = m.Parameter(0); |
| 226 |
| 227 MLabel blocka, blockb; |
| 228 if (left == 1) m.Branch(m.Word32Equal(p0, p1), &blocka, &blockb); |
| 229 if (left == 0) m.Branch(m.Word32Equal(p1, p0), &blocka, &blockb); |
| 230 m.Bind(&blocka); |
| 231 m.Return(m.Int32Constant(eq_constant)); |
| 232 m.Bind(&blockb); |
| 233 m.Return(m.Int32Constant(ne_constant)); |
| 234 |
| 235 FOR_INT32_INPUTS(j) { |
| 236 int32_t b = *j; |
| 237 int32_t expect = a == b ? eq_constant : ne_constant; |
| 238 CHECK_EQ(expect, m.Call(b)); |
| 239 } |
| 240 } |
| 241 } |
| 242 } |
| 243 |
| 244 |
| 245 TEST(BranchCombineInt32CmpP) { |
| 246 int32_t eq_constant = -1235; |
| 247 int32_t ne_constant = 725018; |
| 248 |
| 249 for (int op = 0; op < 2; op++) { |
| 250 RawMachineAssemblerTester<int32_t> m(kMachineWord32, kMachineWord32); |
| 251 Node* p0 = m.Parameter(0); |
| 252 Node* p1 = m.Parameter(1); |
| 253 |
| 254 MLabel blocka, blockb; |
| 255 if (op == 0) m.Branch(m.Int32LessThan(p0, p1), &blocka, &blockb); |
| 256 if (op == 1) m.Branch(m.Int32LessThanOrEqual(p0, p1), &blocka, &blockb); |
| 257 m.Bind(&blocka); |
| 258 m.Return(m.Int32Constant(eq_constant)); |
| 259 m.Bind(&blockb); |
| 260 m.Return(m.Int32Constant(ne_constant)); |
| 261 |
| 262 FOR_INT32_INPUTS(i) { |
| 263 FOR_INT32_INPUTS(j) { |
| 264 int32_t a = *i; |
| 265 int32_t b = *j; |
| 266 int32_t expect = 0; |
| 267 if (op == 0) expect = a < b ? eq_constant : ne_constant; |
| 268 if (op == 1) expect = a <= b ? eq_constant : ne_constant; |
| 269 CHECK_EQ(expect, m.Call(a, b)); |
| 270 } |
| 271 } |
| 272 } |
| 273 } |
| 274 |
| 275 |
| 276 TEST(BranchCombineInt32CmpI) { |
| 277 int32_t eq_constant = -1175; |
| 278 int32_t ne_constant = 927711; |
| 279 |
| 280 for (int op = 0; op < 2; op++) { |
| 281 FOR_INT32_INPUTS(i) { |
| 282 RawMachineAssemblerTester<int32_t> m(kMachineWord32); |
| 283 int32_t a = *i; |
| 284 Node* p0 = m.Int32Constant(a); |
| 285 Node* p1 = m.Parameter(0); |
| 286 |
| 287 MLabel blocka, blockb; |
| 288 if (op == 0) m.Branch(m.Int32LessThan(p0, p1), &blocka, &blockb); |
| 289 if (op == 1) m.Branch(m.Int32LessThanOrEqual(p0, p1), &blocka, &blockb); |
| 290 m.Bind(&blocka); |
| 291 m.Return(m.Int32Constant(eq_constant)); |
| 292 m.Bind(&blockb); |
| 293 m.Return(m.Int32Constant(ne_constant)); |
| 294 |
| 295 FOR_INT32_INPUTS(j) { |
| 296 int32_t b = *j; |
| 297 int32_t expect = 0; |
| 298 if (op == 0) expect = a < b ? eq_constant : ne_constant; |
| 299 if (op == 1) expect = a <= b ? eq_constant : ne_constant; |
| 300 CHECK_EQ(expect, m.Call(b)); |
| 301 } |
| 302 } |
| 303 } |
| 304 } |
| 305 |
| 306 |
| 307 // Now come the sophisticated tests for many input shape combinations. |
| 308 |
| 309 // Materializes a boolean (1 or 0) from a comparison. |
| 310 class CmpMaterializeBoolGen : public BinopGen<int32_t> { |
| 311 public: |
| 312 CompareWrapper w; |
| 313 bool invert; |
| 314 |
| 315 CmpMaterializeBoolGen(IrOpcode::Value opcode, bool i) |
| 316 : w(opcode), invert(i) { } |
| 317 |
| 318 virtual void gen(RawMachineAssemblerTester<int32_t>* m, Node* a, Node* b) { |
| 319 Node* cond = w.MakeNode(m, a, b); |
| 320 if (invert) cond = m->Word32Equal(cond, m->Int32Constant(0)); |
| 321 m->Return(cond); |
| 322 } |
| 323 virtual int32_t expected(int32_t a, int32_t b) { |
| 324 if (invert) return !w.Int32Compare(a, b) ? 1 : 0; |
| 325 return w.Int32Compare(a, b) ? 1 : 0; |
| 326 } |
| 327 }; |
| 328 |
| 329 |
| 330 // Generates a branch and return one of two values from a comparison. |
| 331 class CmpBranchGen : public BinopGen<int32_t> { |
| 332 public: |
| 333 CompareWrapper w; |
| 334 bool invert; |
| 335 bool true_first; |
| 336 int32_t eq_constant; |
| 337 int32_t ne_constant; |
| 338 |
| 339 CmpBranchGen(IrOpcode::Value opcode, bool i, bool t, int32_t eq, int32_t ne) |
| 340 : w(opcode), |
| 341 invert(i), |
| 342 true_first(t), |
| 343 eq_constant(eq), |
| 344 ne_constant(ne) { } |
| 345 |
| 346 virtual void gen(RawMachineAssemblerTester<int32_t>* m, Node* a, Node* b) { |
| 347 MLabel blocka, blockb; |
| 348 Node* cond = w.MakeNode(m, a, b); |
| 349 if (invert) cond = m->Word32Equal(cond, m->Int32Constant(0)); |
| 350 m->Branch(cond, &blocka, &blockb); |
| 351 if (true_first) { |
| 352 m->Bind(&blocka); |
| 353 m->Return(m->Int32Constant(eq_constant)); |
| 354 m->Bind(&blockb); |
| 355 m->Return(m->Int32Constant(ne_constant)); |
| 356 } else { |
| 357 m->Bind(&blockb); |
| 358 m->Return(m->Int32Constant(ne_constant)); |
| 359 m->Bind(&blocka); |
| 360 m->Return(m->Int32Constant(eq_constant)); |
| 361 } |
| 362 } |
| 363 virtual int32_t expected(int32_t a, int32_t b) { |
| 364 if (invert) return !w.Int32Compare(a, b) ? eq_constant : ne_constant; |
| 365 return w.Int32Compare(a, b) ? eq_constant : ne_constant; |
| 366 } |
| 367 }; |
| 368 |
| 369 |
| 370 TEST(BranchCombineInt32CmpAllInputShapes_materialized) { |
| 371 for (size_t i = 0; i < ARRAY_SIZE(int32cmp_opcodes); i++) { |
| 372 CmpMaterializeBoolGen gen(int32cmp_opcodes[i], false); |
| 373 Int32BinopInputShapeTester tester(&gen); |
| 374 tester.TestAllInputShapes(); |
| 375 } |
| 376 } |
| 377 |
| 378 |
| 379 TEST(BranchCombineInt32CmpAllInputShapes_inverted_materialized) { |
| 380 for (size_t i = 0; i < ARRAY_SIZE(int32cmp_opcodes); i++) { |
| 381 CmpMaterializeBoolGen gen(int32cmp_opcodes[i], true); |
| 382 Int32BinopInputShapeTester tester(&gen); |
| 383 tester.TestAllInputShapes(); |
| 384 } |
| 385 } |
| 386 |
| 387 |
| 388 TEST(BranchCombineInt32CmpAllInputShapes_branch_true) { |
| 389 for (size_t i = 0; i < ARRAY_SIZE(int32cmp_opcodes); i++) { |
| 390 CmpBranchGen gen(int32cmp_opcodes[i], false, false, 995+i, -1011-i); |
| 391 Int32BinopInputShapeTester tester(&gen); |
| 392 tester.TestAllInputShapes(); |
| 393 } |
| 394 } |
| 395 |
| 396 |
| 397 TEST(BranchCombineInt32CmpAllInputShapes_branch_false) { |
| 398 for (size_t i = 0; i < ARRAY_SIZE(int32cmp_opcodes); i++) { |
| 399 CmpBranchGen gen(int32cmp_opcodes[i], false, true, 795+i, -2011-i); |
| 400 Int32BinopInputShapeTester tester(&gen); |
| 401 tester.TestAllInputShapes(); |
| 402 } |
| 403 } |
| 404 |
| 405 |
| 406 TEST(BranchCombineInt32CmpAllInputShapes_inverse_branch_true) { |
| 407 for (size_t i = 0; i < ARRAY_SIZE(int32cmp_opcodes); i++) { |
| 408 CmpBranchGen gen(int32cmp_opcodes[i], true, false, 695+i, -3011-i); |
| 409 Int32BinopInputShapeTester tester(&gen); |
| 410 tester.TestAllInputShapes(); |
| 411 } |
| 412 } |
| 413 |
| 414 |
| 415 TEST(BranchCombineInt32CmpAllInputShapes_inverse_branch_false) { |
| 416 for (size_t i = 0; i < ARRAY_SIZE(int32cmp_opcodes); i++) { |
| 417 CmpBranchGen gen(int32cmp_opcodes[i], true, true, 595+i, -4011-i); |
| 418 Int32BinopInputShapeTester tester(&gen); |
| 419 tester.TestAllInputShapes(); |
| 420 } |
| 421 } |
| 422 |
| 423 |
| 424 TEST(BranchCombineFloat64Compares) { |
| 425 double inf = V8_INFINITY; |
| 426 double nan = v8::base::OS::nan_value(); |
| 427 double inputs[] = {0.0, 1.0, -1.0, -inf, inf, nan}; |
| 428 |
| 429 int32_t eq_constant = -1733; |
| 430 int32_t ne_constant = 915118; |
| 431 |
| 432 double input_a = 0.0; |
| 433 double input_b = 0.0; |
| 434 |
| 435 CompareWrapper cmps[] = { |
| 436 CompareWrapper(IrOpcode::kFloat64Equal), |
| 437 CompareWrapper(IrOpcode::kFloat64LessThan), |
| 438 CompareWrapper(IrOpcode::kFloat64LessThanOrEqual) |
| 439 }; |
| 440 |
| 441 for (size_t c = 0; c < ARRAY_SIZE(cmps); c++) { |
| 442 CompareWrapper cmp = cmps[c]; |
| 443 for (int invert = 0; invert < 2; invert++) { |
| 444 RawMachineAssemblerTester<int32_t> m; |
| 445 Node* a = m.LoadFromPointer(&input_a, kMachineFloat64); |
| 446 Node* b = m.LoadFromPointer(&input_b, kMachineFloat64); |
| 447 |
| 448 MLabel blocka, blockb; |
| 449 Node* cond = cmp.MakeNode(&m, a, b); |
| 450 if (invert) cond = m.Word32Equal(cond, m.Int32Constant(0)); |
| 451 m.Branch(cond, &blocka, &blockb); |
| 452 m.Bind(&blocka); |
| 453 m.Return(m.Int32Constant(eq_constant)); |
| 454 m.Bind(&blockb); |
| 455 m.Return(m.Int32Constant(ne_constant)); |
| 456 |
| 457 for (size_t i = 0; i < ARRAY_SIZE(inputs); i++) { |
| 458 for (size_t j = 0; j < ARRAY_SIZE(inputs); j += 2) { |
| 459 input_a = inputs[i]; |
| 460 input_b = inputs[i]; |
| 461 int32_t expected = invert ? |
| 462 (cmp.Float64Compare(input_a, input_b) ? ne_constant : eq_constant) : |
| 463 (cmp.Float64Compare(input_a, input_b) ? eq_constant : ne_constant); |
| 464 CHECK_EQ(expected, m.Call()); |
| 465 } |
| 466 } |
| 467 } |
| 468 } |
| 469 } |
| 470 #endif // V8_TURBOFAN_TARGET |
OLD | NEW |