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