| OLD | NEW |
| 1 // Copyright 2014 the V8 project authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "src/v8.h" | 5 #include "src/v8.h" |
| 6 #include "test/cctest/cctest.h" | 6 #include "test/cctest/cctest.h" |
| 7 | 7 |
| 8 #include "src/compiler/graph-inl.h" | 8 #include "src/compiler/graph-inl.h" |
| 9 #include "src/compiler/js-typed-lowering.h" | 9 #include "src/compiler/js-typed-lowering.h" |
| 10 #include "src/compiler/node-properties-inl.h" | 10 #include "src/compiler/node-properties-inl.h" |
| (...skipping 15 matching lines...) Expand all Loading... |
| 26 common(main_zone()), | 26 common(main_zone()), |
| 27 graph(main_zone()), | 27 graph(main_zone()), |
| 28 typer(main_zone()), | 28 typer(main_zone()), |
| 29 context_node(NULL) { | 29 context_node(NULL) { |
| 30 typer.DecorateGraph(&graph); | 30 typer.DecorateGraph(&graph); |
| 31 Node* s = graph.NewNode(common.Start(num_parameters)); | 31 Node* s = graph.NewNode(common.Start(num_parameters)); |
| 32 graph.SetStart(s); | 32 graph.SetStart(s); |
| 33 } | 33 } |
| 34 | 34 |
| 35 Isolate* isolate; | 35 Isolate* isolate; |
| 36 Operator* binop; | 36 const Operator* binop; |
| 37 Operator* unop; | 37 const Operator* unop; |
| 38 JSOperatorBuilder javascript; | 38 JSOperatorBuilder javascript; |
| 39 MachineOperatorBuilder machine; | 39 MachineOperatorBuilder machine; |
| 40 SimplifiedOperatorBuilder simplified; | 40 SimplifiedOperatorBuilder simplified; |
| 41 CommonOperatorBuilder common; | 41 CommonOperatorBuilder common; |
| 42 Graph graph; | 42 Graph graph; |
| 43 Typer typer; | 43 Typer typer; |
| 44 Node* context_node; | 44 Node* context_node; |
| 45 | 45 |
| 46 Node* Parameter(Type* t, int32_t index = 0) { | 46 Node* Parameter(Type* t, int32_t index = 0) { |
| 47 Node* n = graph.NewNode(common.Parameter(index), graph.start()); | 47 Node* n = graph.NewNode(common.Parameter(index), graph.start()); |
| (...skipping 18 matching lines...) Expand all Loading... |
| 66 return context_node; | 66 return context_node; |
| 67 } | 67 } |
| 68 | 68 |
| 69 Node* control() { return start(); } | 69 Node* control() { return start(); } |
| 70 | 70 |
| 71 void CheckPureBinop(IrOpcode::Value expected, Node* node) { | 71 void CheckPureBinop(IrOpcode::Value expected, Node* node) { |
| 72 CHECK_EQ(expected, node->opcode()); | 72 CHECK_EQ(expected, node->opcode()); |
| 73 CHECK_EQ(2, node->InputCount()); // should not have context, effect, etc. | 73 CHECK_EQ(2, node->InputCount()); // should not have context, effect, etc. |
| 74 } | 74 } |
| 75 | 75 |
| 76 void CheckPureBinop(Operator* expected, Node* node) { | 76 void CheckPureBinop(const Operator* expected, Node* node) { |
| 77 CHECK_EQ(expected->opcode(), node->op()->opcode()); | 77 CHECK_EQ(expected->opcode(), node->op()->opcode()); |
| 78 CHECK_EQ(2, node->InputCount()); // should not have context, effect, etc. | 78 CHECK_EQ(2, node->InputCount()); // should not have context, effect, etc. |
| 79 } | 79 } |
| 80 | 80 |
| 81 Node* ReduceUnop(Operator* op, Type* input_type) { | 81 Node* ReduceUnop(const Operator* op, Type* input_type) { |
| 82 return reduce(Unop(op, Parameter(input_type))); | 82 return reduce(Unop(op, Parameter(input_type))); |
| 83 } | 83 } |
| 84 | 84 |
| 85 Node* ReduceBinop(Operator* op, Type* left_type, Type* right_type) { | 85 Node* ReduceBinop(const Operator* op, Type* left_type, Type* right_type) { |
| 86 return reduce(Binop(op, Parameter(left_type, 0), Parameter(right_type, 1))); | 86 return reduce(Binop(op, Parameter(left_type, 0), Parameter(right_type, 1))); |
| 87 } | 87 } |
| 88 | 88 |
| 89 Node* Binop(Operator* op, Node* left, Node* right) { | 89 Node* Binop(const Operator* op, Node* left, Node* right) { |
| 90 // JS binops also require context, effect, and control | 90 // JS binops also require context, effect, and control |
| 91 return graph.NewNode(op, left, right, context(), start(), control()); | 91 return graph.NewNode(op, left, right, context(), start(), control()); |
| 92 } | 92 } |
| 93 | 93 |
| 94 Node* Unop(Operator* op, Node* input) { | 94 Node* Unop(const Operator* op, Node* input) { |
| 95 // JS unops also require context, effect, and control | 95 // JS unops also require context, effect, and control |
| 96 return graph.NewNode(op, input, context(), start(), control()); | 96 return graph.NewNode(op, input, context(), start(), control()); |
| 97 } | 97 } |
| 98 | 98 |
| 99 Node* UseForEffect(Node* node) { | 99 Node* UseForEffect(Node* node) { |
| 100 // TODO(titzer): use EffectPhi after fixing EffectCount | 100 // TODO(titzer): use EffectPhi after fixing EffectCount |
| 101 return graph.NewNode(javascript.ToNumber(), node, context(), node, | 101 return graph.NewNode(javascript.ToNumber(), node, context(), node, |
| 102 control()); | 102 control()); |
| 103 } | 103 } |
| 104 | 104 |
| (...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 199 | 199 |
| 200 R.CheckPureBinop(IrOpcode::kNumberAdd, r); | 200 R.CheckPureBinop(IrOpcode::kNumberAdd, r); |
| 201 CHECK_EQ(p0, r->InputAt(0)); | 201 CHECK_EQ(p0, r->InputAt(0)); |
| 202 CHECK_EQ(p1, r->InputAt(1)); | 202 CHECK_EQ(p1, r->InputAt(1)); |
| 203 } | 203 } |
| 204 } | 204 } |
| 205 | 205 |
| 206 | 206 |
| 207 TEST(NumberBinops) { | 207 TEST(NumberBinops) { |
| 208 JSTypedLoweringTester R; | 208 JSTypedLoweringTester R; |
| 209 Operator* ops[] = { | 209 const Operator* ops[] = { |
| 210 R.javascript.Add(), R.simplified.NumberAdd(), | 210 R.javascript.Add(), R.simplified.NumberAdd(), |
| 211 R.javascript.Subtract(), R.simplified.NumberSubtract(), | 211 R.javascript.Subtract(), R.simplified.NumberSubtract(), |
| 212 R.javascript.Multiply(), R.simplified.NumberMultiply(), | 212 R.javascript.Multiply(), R.simplified.NumberMultiply(), |
| 213 R.javascript.Divide(), R.simplified.NumberDivide(), | 213 R.javascript.Divide(), R.simplified.NumberDivide(), |
| 214 R.javascript.Modulus(), R.simplified.NumberModulus(), | 214 R.javascript.Modulus(), R.simplified.NumberModulus(), |
| 215 }; | 215 }; |
| 216 | 216 |
| 217 for (size_t i = 0; i < arraysize(kNumberTypes); ++i) { | 217 for (size_t i = 0; i < arraysize(kNumberTypes); ++i) { |
| 218 Node* p0 = R.Parameter(kNumberTypes[i], 0); | 218 Node* p0 = R.Parameter(kNumberTypes[i], 0); |
| 219 | 219 |
| (...skipping 26 matching lines...) Expand all Loading... |
| 246 } else { | 246 } else { |
| 247 CHECK_EQ(NumberToI32(is_signed), new_input->opcode()); | 247 CHECK_EQ(NumberToI32(is_signed), new_input->opcode()); |
| 248 } | 248 } |
| 249 } | 249 } |
| 250 | 250 |
| 251 | 251 |
| 252 // A helper class for testing lowering of bitwise shift operators. | 252 // A helper class for testing lowering of bitwise shift operators. |
| 253 class JSBitwiseShiftTypedLoweringTester : public JSTypedLoweringTester { | 253 class JSBitwiseShiftTypedLoweringTester : public JSTypedLoweringTester { |
| 254 public: | 254 public: |
| 255 static const int kNumberOps = 6; | 255 static const int kNumberOps = 6; |
| 256 Operator* ops[kNumberOps]; | 256 const Operator* ops[kNumberOps]; |
| 257 bool signedness[kNumberOps]; | 257 bool signedness[kNumberOps]; |
| 258 | 258 |
| 259 JSBitwiseShiftTypedLoweringTester() { | 259 JSBitwiseShiftTypedLoweringTester() { |
| 260 int i = 0; | 260 int i = 0; |
| 261 set(i++, javascript.ShiftLeft(), true); | 261 set(i++, javascript.ShiftLeft(), true); |
| 262 set(i++, machine.Word32Shl(), false); | 262 set(i++, machine.Word32Shl(), false); |
| 263 set(i++, javascript.ShiftRight(), true); | 263 set(i++, javascript.ShiftRight(), true); |
| 264 set(i++, machine.Word32Sar(), false); | 264 set(i++, machine.Word32Sar(), false); |
| 265 set(i++, javascript.ShiftRightLogical(), false); | 265 set(i++, javascript.ShiftRightLogical(), false); |
| 266 set(i++, machine.Word32Shr(), false); | 266 set(i++, machine.Word32Shr(), false); |
| 267 } | 267 } |
| 268 | 268 |
| 269 private: | 269 private: |
| 270 void set(int idx, Operator* op, bool s) { | 270 void set(int idx, const Operator* op, bool s) { |
| 271 ops[idx] = op; | 271 ops[idx] = op; |
| 272 signedness[idx] = s; | 272 signedness[idx] = s; |
| 273 } | 273 } |
| 274 }; | 274 }; |
| 275 | 275 |
| 276 | 276 |
| 277 TEST(Int32BitwiseShifts) { | 277 TEST(Int32BitwiseShifts) { |
| 278 JSBitwiseShiftTypedLoweringTester R; | 278 JSBitwiseShiftTypedLoweringTester R; |
| 279 | 279 |
| 280 Type* types[] = { | 280 Type* types[] = { |
| (...skipping 25 matching lines...) Expand all Loading... |
| 306 } | 306 } |
| 307 } | 307 } |
| 308 } | 308 } |
| 309 } | 309 } |
| 310 | 310 |
| 311 | 311 |
| 312 // A helper class for testing lowering of bitwise operators. | 312 // A helper class for testing lowering of bitwise operators. |
| 313 class JSBitwiseTypedLoweringTester : public JSTypedLoweringTester { | 313 class JSBitwiseTypedLoweringTester : public JSTypedLoweringTester { |
| 314 public: | 314 public: |
| 315 static const int kNumberOps = 6; | 315 static const int kNumberOps = 6; |
| 316 Operator* ops[kNumberOps]; | 316 const Operator* ops[kNumberOps]; |
| 317 bool signedness[kNumberOps]; | 317 bool signedness[kNumberOps]; |
| 318 | 318 |
| 319 JSBitwiseTypedLoweringTester() { | 319 JSBitwiseTypedLoweringTester() { |
| 320 int i = 0; | 320 int i = 0; |
| 321 set(i++, javascript.BitwiseOr(), true); | 321 set(i++, javascript.BitwiseOr(), true); |
| 322 set(i++, machine.Word32Or(), true); | 322 set(i++, machine.Word32Or(), true); |
| 323 set(i++, javascript.BitwiseXor(), true); | 323 set(i++, javascript.BitwiseXor(), true); |
| 324 set(i++, machine.Word32Xor(), true); | 324 set(i++, machine.Word32Xor(), true); |
| 325 set(i++, javascript.BitwiseAnd(), true); | 325 set(i++, javascript.BitwiseAnd(), true); |
| 326 set(i++, machine.Word32And(), true); | 326 set(i++, machine.Word32And(), true); |
| 327 } | 327 } |
| 328 | 328 |
| 329 private: | 329 private: |
| 330 void set(int idx, Operator* op, bool s) { | 330 void set(int idx, const Operator* op, bool s) { |
| 331 ops[idx] = op; | 331 ops[idx] = op; |
| 332 signedness[idx] = s; | 332 signedness[idx] = s; |
| 333 } | 333 } |
| 334 }; | 334 }; |
| 335 | 335 |
| 336 | 336 |
| 337 TEST(Int32BitwiseBinops) { | 337 TEST(Int32BitwiseBinops) { |
| 338 JSBitwiseTypedLoweringTester R; | 338 JSBitwiseTypedLoweringTester R; |
| 339 | 339 |
| 340 Type* types[] = { | 340 Type* types[] = { |
| (...skipping 18 matching lines...) Expand all Loading... |
| 359 CheckToI32(p0, r->InputAt(0), R.signedness[k]); | 359 CheckToI32(p0, r->InputAt(0), R.signedness[k]); |
| 360 CheckToI32(p1, r->InputAt(1), R.signedness[k + 1]); | 360 CheckToI32(p1, r->InputAt(1), R.signedness[k + 1]); |
| 361 } | 361 } |
| 362 } | 362 } |
| 363 } | 363 } |
| 364 } | 364 } |
| 365 | 365 |
| 366 | 366 |
| 367 TEST(JSToNumber1) { | 367 TEST(JSToNumber1) { |
| 368 JSTypedLoweringTester R; | 368 JSTypedLoweringTester R; |
| 369 Operator* ton = R.javascript.ToNumber(); | 369 const Operator* ton = R.javascript.ToNumber(); |
| 370 | 370 |
| 371 for (size_t i = 0; i < arraysize(kNumberTypes); i++) { // ToNumber(number) | 371 for (size_t i = 0; i < arraysize(kNumberTypes); i++) { // ToNumber(number) |
| 372 Node* r = R.ReduceUnop(ton, kNumberTypes[i]); | 372 Node* r = R.ReduceUnop(ton, kNumberTypes[i]); |
| 373 CHECK_EQ(IrOpcode::kParameter, r->opcode()); | 373 CHECK_EQ(IrOpcode::kParameter, r->opcode()); |
| 374 } | 374 } |
| 375 | 375 |
| 376 { // ToNumber(undefined) | 376 { // ToNumber(undefined) |
| 377 Node* r = R.ReduceUnop(ton, Type::Undefined()); | 377 Node* r = R.ReduceUnop(ton, Type::Undefined()); |
| 378 R.CheckNaN(r); | 378 R.CheckNaN(r); |
| 379 } | 379 } |
| (...skipping 29 matching lines...) Expand all Loading... |
| 409 CHECK_EQ(n, add->InputAt(0)); | 409 CHECK_EQ(n, add->InputAt(0)); |
| 410 CHECK_EQ(r, add->InputAt(1)); | 410 CHECK_EQ(r, add->InputAt(1)); |
| 411 R.CheckEffectInput(R.start(), effect_use); | 411 R.CheckEffectInput(R.start(), effect_use); |
| 412 } | 412 } |
| 413 } | 413 } |
| 414 | 414 |
| 415 | 415 |
| 416 TEST(JSToNumberOfConstant) { | 416 TEST(JSToNumberOfConstant) { |
| 417 JSTypedLoweringTester R; | 417 JSTypedLoweringTester R; |
| 418 | 418 |
| 419 Operator* ops[] = {R.common.NumberConstant(0), R.common.NumberConstant(-1), | 419 const Operator* ops[] = { |
| 420 R.common.NumberConstant(0.1), R.common.Int32Constant(1177), | 420 R.common.NumberConstant(0), R.common.NumberConstant(-1), |
| 421 R.common.Float64Constant(0.99)}; | 421 R.common.NumberConstant(0.1), R.common.Int32Constant(1177), |
| 422 R.common.Float64Constant(0.99)}; |
| 422 | 423 |
| 423 for (size_t i = 0; i < arraysize(ops); i++) { | 424 for (size_t i = 0; i < arraysize(ops); i++) { |
| 424 Node* n = R.graph.NewNode(ops[i]); | 425 Node* n = R.graph.NewNode(ops[i]); |
| 425 Node* convert = R.Unop(R.javascript.ToNumber(), n); | 426 Node* convert = R.Unop(R.javascript.ToNumber(), n); |
| 426 Node* r = R.reduce(convert); | 427 Node* r = R.reduce(convert); |
| 427 // Note that either outcome below is correct. It only depends on whether | 428 // Note that either outcome below is correct. It only depends on whether |
| 428 // the types of constants are eagerly computed or only computed by the | 429 // the types of constants are eagerly computed or only computed by the |
| 429 // typing pass. | 430 // typing pass. |
| 430 if (NodeProperties::GetBounds(n).upper->Is(Type::Number())) { | 431 if (NodeProperties::GetBounds(n).upper->Is(Type::Number())) { |
| 431 // If number constants are eagerly typed, then reduction should | 432 // If number constants are eagerly typed, then reduction should |
| (...skipping 16 matching lines...) Expand all Loading... |
| 448 for (size_t i = 0; i < arraysize(others); i++) { | 449 for (size_t i = 0; i < arraysize(others); i++) { |
| 449 Type* t = Type::Union(Type::Number(), others[i], R.main_zone()); | 450 Type* t = Type::Union(Type::Number(), others[i], R.main_zone()); |
| 450 Node* r = R.ReduceUnop(R.javascript.ToNumber(), t); | 451 Node* r = R.ReduceUnop(R.javascript.ToNumber(), t); |
| 451 CHECK_EQ(IrOpcode::kJSToNumber, r->opcode()); | 452 CHECK_EQ(IrOpcode::kJSToNumber, r->opcode()); |
| 452 } | 453 } |
| 453 } | 454 } |
| 454 | 455 |
| 455 | 456 |
| 456 TEST(JSToBoolean) { | 457 TEST(JSToBoolean) { |
| 457 JSTypedLoweringTester R; | 458 JSTypedLoweringTester R; |
| 458 Operator* op = R.javascript.ToBoolean(); | 459 const Operator* op = R.javascript.ToBoolean(); |
| 459 | 460 |
| 460 { // ToBoolean(undefined) | 461 { // ToBoolean(undefined) |
| 461 Node* r = R.ReduceUnop(op, Type::Undefined()); | 462 Node* r = R.ReduceUnop(op, Type::Undefined()); |
| 462 R.CheckFalse(r); | 463 R.CheckFalse(r); |
| 463 } | 464 } |
| 464 | 465 |
| 465 { // ToBoolean(null) | 466 { // ToBoolean(null) |
| 466 Node* r = R.ReduceUnop(op, Type::Null()); | 467 Node* r = R.ReduceUnop(op, Type::Null()); |
| 467 R.CheckFalse(r); | 468 R.CheckFalse(r); |
| 468 } | 469 } |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 536 | 537 |
| 537 | 538 |
| 538 TEST(JSToString1) { | 539 TEST(JSToString1) { |
| 539 JSTypedLoweringTester R; | 540 JSTypedLoweringTester R; |
| 540 | 541 |
| 541 for (size_t i = 0; i < arraysize(kStringTypes); i++) { | 542 for (size_t i = 0; i < arraysize(kStringTypes); i++) { |
| 542 Node* r = R.ReduceUnop(R.javascript.ToString(), kStringTypes[i]); | 543 Node* r = R.ReduceUnop(R.javascript.ToString(), kStringTypes[i]); |
| 543 CHECK_EQ(IrOpcode::kParameter, r->opcode()); | 544 CHECK_EQ(IrOpcode::kParameter, r->opcode()); |
| 544 } | 545 } |
| 545 | 546 |
| 546 Operator* op = R.javascript.ToString(); | 547 const Operator* op = R.javascript.ToString(); |
| 547 | 548 |
| 548 { // ToString(undefined) => "undefined" | 549 { // ToString(undefined) => "undefined" |
| 549 Node* r = R.ReduceUnop(op, Type::Undefined()); | 550 Node* r = R.ReduceUnop(op, Type::Undefined()); |
| 550 R.CheckHandle(R.isolate->factory()->undefined_string(), r); | 551 R.CheckHandle(R.isolate->factory()->undefined_string(), r); |
| 551 } | 552 } |
| 552 | 553 |
| 553 { // ToString(null) => "null" | 554 { // ToString(null) => "null" |
| 554 Node* r = R.ReduceUnop(op, Type::Null()); | 555 Node* r = R.ReduceUnop(op, Type::Null()); |
| 555 R.CheckHandle(R.isolate->factory()->null_string(), r); | 556 R.CheckHandle(R.isolate->factory()->null_string(), r); |
| 556 } | 557 } |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 603 CHECK_EQ(n, add->InputAt(0)); | 604 CHECK_EQ(n, add->InputAt(0)); |
| 604 CHECK_EQ(r, add->InputAt(1)); | 605 CHECK_EQ(r, add->InputAt(1)); |
| 605 R.CheckEffectInput(R.start(), effect_use); | 606 R.CheckEffectInput(R.start(), effect_use); |
| 606 } | 607 } |
| 607 } | 608 } |
| 608 | 609 |
| 609 | 610 |
| 610 TEST(StringComparison) { | 611 TEST(StringComparison) { |
| 611 JSTypedLoweringTester R; | 612 JSTypedLoweringTester R; |
| 612 | 613 |
| 613 Operator* ops[] = { | 614 const Operator* ops[] = { |
| 614 R.javascript.LessThan(), R.simplified.StringLessThan(), | 615 R.javascript.LessThan(), R.simplified.StringLessThan(), |
| 615 R.javascript.LessThanOrEqual(), R.simplified.StringLessThanOrEqual(), | 616 R.javascript.LessThanOrEqual(), R.simplified.StringLessThanOrEqual(), |
| 616 R.javascript.GreaterThan(), R.simplified.StringLessThan(), | 617 R.javascript.GreaterThan(), R.simplified.StringLessThan(), |
| 617 R.javascript.GreaterThanOrEqual(), R.simplified.StringLessThanOrEqual()}; | 618 R.javascript.GreaterThanOrEqual(), R.simplified.StringLessThanOrEqual()}; |
| 618 | 619 |
| 619 for (size_t i = 0; i < arraysize(kStringTypes); i++) { | 620 for (size_t i = 0; i < arraysize(kStringTypes); i++) { |
| 620 Node* p0 = R.Parameter(kStringTypes[i], 0); | 621 Node* p0 = R.Parameter(kStringTypes[i], 0); |
| 621 for (size_t j = 0; j < arraysize(kStringTypes); j++) { | 622 for (size_t j = 0; j < arraysize(kStringTypes); j++) { |
| 622 Node* p1 = R.Parameter(kStringTypes[j], 1); | 623 Node* p1 = R.Parameter(kStringTypes[j], 1); |
| 623 | 624 |
| (...skipping 24 matching lines...) Expand all Loading... |
| 648 if (converted->opcode() == IrOpcode::kNumberConstant) return; | 649 if (converted->opcode() == IrOpcode::kNumberConstant) return; |
| 649 CHECK_EQ(IrOpcode::kJSToNumber, converted->opcode()); | 650 CHECK_EQ(IrOpcode::kJSToNumber, converted->opcode()); |
| 650 CHECK_EQ(val, converted->InputAt(0)); | 651 CHECK_EQ(val, converted->InputAt(0)); |
| 651 } | 652 } |
| 652 } | 653 } |
| 653 | 654 |
| 654 | 655 |
| 655 TEST(NumberComparison) { | 656 TEST(NumberComparison) { |
| 656 JSTypedLoweringTester R; | 657 JSTypedLoweringTester R; |
| 657 | 658 |
| 658 Operator* ops[] = { | 659 const Operator* ops[] = { |
| 659 R.javascript.LessThan(), R.simplified.NumberLessThan(), | 660 R.javascript.LessThan(), R.simplified.NumberLessThan(), |
| 660 R.javascript.LessThanOrEqual(), R.simplified.NumberLessThanOrEqual(), | 661 R.javascript.LessThanOrEqual(), R.simplified.NumberLessThanOrEqual(), |
| 661 R.javascript.GreaterThan(), R.simplified.NumberLessThan(), | 662 R.javascript.GreaterThan(), R.simplified.NumberLessThan(), |
| 662 R.javascript.GreaterThanOrEqual(), R.simplified.NumberLessThanOrEqual()}; | 663 R.javascript.GreaterThanOrEqual(), R.simplified.NumberLessThanOrEqual()}; |
| 663 | 664 |
| 664 for (size_t i = 0; i < arraysize(kJSTypes); i++) { | 665 for (size_t i = 0; i < arraysize(kJSTypes); i++) { |
| 665 Type* t0 = kJSTypes[i]; | 666 Type* t0 = kJSTypes[i]; |
| 666 if (t0->Is(Type::String())) continue; // skip Type::String | 667 if (t0->Is(Type::String())) continue; // skip Type::String |
| 667 Node* p0 = R.Parameter(t0, 0); | 668 Node* p0 = R.Parameter(t0, 0); |
| 668 | 669 |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 748 | 749 |
| 749 // Check effect chain is correct. | 750 // Check effect chain is correct. |
| 750 R.CheckEffectInput(R.start(), i0); | 751 R.CheckEffectInput(R.start(), i0); |
| 751 R.CheckEffectInput(i0, i1); | 752 R.CheckEffectInput(i0, i1); |
| 752 R.CheckEffectInput(i1, effect_use); | 753 R.CheckEffectInput(i1, effect_use); |
| 753 } | 754 } |
| 754 | 755 |
| 755 | 756 |
| 756 TEST(UnaryNot) { | 757 TEST(UnaryNot) { |
| 757 JSTypedLoweringTester R; | 758 JSTypedLoweringTester R; |
| 758 Operator* opnot = R.javascript.UnaryNot(); | 759 const Operator* opnot = R.javascript.UnaryNot(); |
| 759 | 760 |
| 760 for (size_t i = 0; i < arraysize(kJSTypes); i++) { | 761 for (size_t i = 0; i < arraysize(kJSTypes); i++) { |
| 761 Node* orig = R.Unop(opnot, R.Parameter(kJSTypes[i])); | 762 Node* orig = R.Unop(opnot, R.Parameter(kJSTypes[i])); |
| 762 Node* use = R.graph.NewNode(R.common.Return(), orig); | 763 Node* use = R.graph.NewNode(R.common.Return(), orig); |
| 763 Node* r = R.reduce(orig); | 764 Node* r = R.reduce(orig); |
| 764 // TODO(titzer): test will break if/when js-typed-lowering constant folds. | 765 // TODO(titzer): test will break if/when js-typed-lowering constant folds. |
| 765 CHECK_EQ(IrOpcode::kBooleanNot, use->InputAt(0)->opcode()); | 766 CHECK_EQ(IrOpcode::kBooleanNot, use->InputAt(0)->opcode()); |
| 766 | 767 |
| 767 if (r == orig && orig->opcode() == IrOpcode::kJSToBoolean) { | 768 if (r == orig && orig->opcode() == IrOpcode::kJSToBoolean) { |
| 768 // The original node was turned into a ToBoolean. | 769 // The original node was turned into a ToBoolean. |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 825 } | 826 } |
| 826 } | 827 } |
| 827 | 828 |
| 828 CHECK_EQ(NULL, effect_use); // should have done all cases above. | 829 CHECK_EQ(NULL, effect_use); // should have done all cases above. |
| 829 } | 830 } |
| 830 | 831 |
| 831 | 832 |
| 832 // Helper class for testing the reduction of a single binop. | 833 // Helper class for testing the reduction of a single binop. |
| 833 class BinopEffectsTester { | 834 class BinopEffectsTester { |
| 834 public: | 835 public: |
| 835 explicit BinopEffectsTester(Operator* op, Type* t0, Type* t1) | 836 explicit BinopEffectsTester(const Operator* op, Type* t0, Type* t1) |
| 836 : R(), | 837 : R(), |
| 837 p0(R.Parameter(t0, 0)), | 838 p0(R.Parameter(t0, 0)), |
| 838 p1(R.Parameter(t1, 1)), | 839 p1(R.Parameter(t1, 1)), |
| 839 binop(R.Binop(op, p0, p1)), | 840 binop(R.Binop(op, p0, p1)), |
| 840 effect_use(R.graph.NewNode(R.common.EffectPhi(1), binop, R.start())) { | 841 effect_use(R.graph.NewNode(R.common.EffectPhi(1), binop, R.start())) { |
| 841 // Effects should be ordered start -> binop -> effect_use | 842 // Effects should be ordered start -> binop -> effect_use |
| 842 R.CheckEffectInput(R.start(), binop); | 843 R.CheckEffectInput(R.start(), binop); |
| 843 R.CheckEffectInput(binop, effect_use); | 844 R.CheckEffectInput(binop, effect_use); |
| 844 result = R.reduce(binop); | 845 result = R.reduce(binop); |
| 845 } | 846 } |
| (...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 954 Node* p1 = R.Parameter(Type::String()); | 955 Node* p1 = R.Parameter(Type::String()); |
| 955 | 956 |
| 956 CheckEqualityReduction(&R, true, p0, p1, IrOpcode::kStringEqual); | 957 CheckEqualityReduction(&R, true, p0, p1, IrOpcode::kStringEqual); |
| 957 CheckEqualityReduction(&R, false, p0, p1, IrOpcode::kStringEqual); | 958 CheckEqualityReduction(&R, false, p0, p1, IrOpcode::kStringEqual); |
| 958 } | 959 } |
| 959 | 960 |
| 960 | 961 |
| 961 TEST(RemovePureNumberBinopEffects) { | 962 TEST(RemovePureNumberBinopEffects) { |
| 962 JSTypedLoweringTester R; | 963 JSTypedLoweringTester R; |
| 963 | 964 |
| 964 Operator* ops[] = { | 965 const Operator* ops[] = { |
| 965 R.javascript.Equal(), R.simplified.NumberEqual(), | 966 R.javascript.Equal(), R.simplified.NumberEqual(), |
| 966 R.javascript.Add(), R.simplified.NumberAdd(), | 967 R.javascript.Add(), R.simplified.NumberAdd(), |
| 967 R.javascript.Subtract(), R.simplified.NumberSubtract(), | 968 R.javascript.Subtract(), R.simplified.NumberSubtract(), |
| 968 R.javascript.Multiply(), R.simplified.NumberMultiply(), | 969 R.javascript.Multiply(), R.simplified.NumberMultiply(), |
| 969 R.javascript.Divide(), R.simplified.NumberDivide(), | 970 R.javascript.Divide(), R.simplified.NumberDivide(), |
| 970 R.javascript.Modulus(), R.simplified.NumberModulus(), | 971 R.javascript.Modulus(), R.simplified.NumberModulus(), |
| 971 R.javascript.LessThan(), R.simplified.NumberLessThan(), | 972 R.javascript.LessThan(), R.simplified.NumberLessThan(), |
| 972 R.javascript.LessThanOrEqual(), R.simplified.NumberLessThanOrEqual(), | 973 R.javascript.LessThanOrEqual(), R.simplified.NumberLessThanOrEqual(), |
| 973 }; | 974 }; |
| 974 | 975 |
| 975 for (size_t j = 0; j < arraysize(ops); j += 2) { | 976 for (size_t j = 0; j < arraysize(ops); j += 2) { |
| 976 BinopEffectsTester B(ops[j], Type::Number(), Type::Number()); | 977 BinopEffectsTester B(ops[j], Type::Number(), Type::Number()); |
| 977 CHECK_EQ(ops[j + 1]->opcode(), B.result->op()->opcode()); | 978 CHECK_EQ(ops[j + 1]->opcode(), B.result->op()->opcode()); |
| 978 | 979 |
| 979 B.R.CheckPureBinop(B.result->opcode(), B.result); | 980 B.R.CheckPureBinop(B.result->opcode(), B.result); |
| 980 | 981 |
| 981 B.CheckNoOp(0); | 982 B.CheckNoOp(0); |
| 982 B.CheckNoOp(1); | 983 B.CheckNoOp(1); |
| 983 | 984 |
| 984 B.CheckEffectsRemoved(); | 985 B.CheckEffectsRemoved(); |
| 985 } | 986 } |
| 986 } | 987 } |
| 987 | 988 |
| 988 | 989 |
| 989 TEST(OrderNumberBinopEffects1) { | 990 TEST(OrderNumberBinopEffects1) { |
| 990 JSTypedLoweringTester R; | 991 JSTypedLoweringTester R; |
| 991 | 992 |
| 992 Operator* ops[] = { | 993 const Operator* ops[] = { |
| 993 R.javascript.Subtract(), R.simplified.NumberSubtract(), | 994 R.javascript.Subtract(), R.simplified.NumberSubtract(), |
| 994 R.javascript.Multiply(), R.simplified.NumberMultiply(), | 995 R.javascript.Multiply(), R.simplified.NumberMultiply(), |
| 995 R.javascript.Divide(), R.simplified.NumberDivide(), | 996 R.javascript.Divide(), R.simplified.NumberDivide(), |
| 996 R.javascript.Modulus(), R.simplified.NumberModulus(), | 997 R.javascript.Modulus(), R.simplified.NumberModulus(), |
| 997 }; | 998 }; |
| 998 | 999 |
| 999 for (size_t j = 0; j < arraysize(ops); j += 2) { | 1000 for (size_t j = 0; j < arraysize(ops); j += 2) { |
| 1000 BinopEffectsTester B(ops[j], Type::Object(), Type::String()); | 1001 BinopEffectsTester B(ops[j], Type::Object(), Type::String()); |
| 1001 CHECK_EQ(ops[j + 1]->opcode(), B.result->op()->opcode()); | 1002 CHECK_EQ(ops[j + 1]->opcode(), B.result->op()->opcode()); |
| 1002 | 1003 |
| 1003 Node* i0 = B.CheckConvertedInput(IrOpcode::kJSToNumber, 0, true); | 1004 Node* i0 = B.CheckConvertedInput(IrOpcode::kJSToNumber, 0, true); |
| 1004 Node* i1 = B.CheckConvertedInput(IrOpcode::kJSToNumber, 1, true); | 1005 Node* i1 = B.CheckConvertedInput(IrOpcode::kJSToNumber, 1, true); |
| 1005 | 1006 |
| 1006 CHECK_EQ(B.p0, i0->InputAt(0)); | 1007 CHECK_EQ(B.p0, i0->InputAt(0)); |
| 1007 CHECK_EQ(B.p1, i1->InputAt(0)); | 1008 CHECK_EQ(B.p1, i1->InputAt(0)); |
| 1008 | 1009 |
| 1009 // Effects should be ordered start -> i0 -> i1 -> effect_use | 1010 // Effects should be ordered start -> i0 -> i1 -> effect_use |
| 1010 B.CheckEffectOrdering(i0, i1); | 1011 B.CheckEffectOrdering(i0, i1); |
| 1011 } | 1012 } |
| 1012 } | 1013 } |
| 1013 | 1014 |
| 1014 | 1015 |
| 1015 TEST(OrderNumberBinopEffects2) { | 1016 TEST(OrderNumberBinopEffects2) { |
| 1016 JSTypedLoweringTester R; | 1017 JSTypedLoweringTester R; |
| 1017 | 1018 |
| 1018 Operator* ops[] = { | 1019 const Operator* ops[] = { |
| 1019 R.javascript.Add(), R.simplified.NumberAdd(), | 1020 R.javascript.Add(), R.simplified.NumberAdd(), |
| 1020 R.javascript.Subtract(), R.simplified.NumberSubtract(), | 1021 R.javascript.Subtract(), R.simplified.NumberSubtract(), |
| 1021 R.javascript.Multiply(), R.simplified.NumberMultiply(), | 1022 R.javascript.Multiply(), R.simplified.NumberMultiply(), |
| 1022 R.javascript.Divide(), R.simplified.NumberDivide(), | 1023 R.javascript.Divide(), R.simplified.NumberDivide(), |
| 1023 R.javascript.Modulus(), R.simplified.NumberModulus(), | 1024 R.javascript.Modulus(), R.simplified.NumberModulus(), |
| 1024 }; | 1025 }; |
| 1025 | 1026 |
| 1026 for (size_t j = 0; j < arraysize(ops); j += 2) { | 1027 for (size_t j = 0; j < arraysize(ops); j += 2) { |
| 1027 BinopEffectsTester B(ops[j], Type::Number(), Type::Object()); | 1028 BinopEffectsTester B(ops[j], Type::Number(), Type::Object()); |
| 1028 | 1029 |
| (...skipping 18 matching lines...) Expand all Loading... |
| 1047 | 1048 |
| 1048 // Effects should be ordered start -> i0 -> effect_use | 1049 // Effects should be ordered start -> i0 -> effect_use |
| 1049 B.CheckEffectOrdering(i0); | 1050 B.CheckEffectOrdering(i0); |
| 1050 } | 1051 } |
| 1051 } | 1052 } |
| 1052 | 1053 |
| 1053 | 1054 |
| 1054 TEST(OrderCompareEffects) { | 1055 TEST(OrderCompareEffects) { |
| 1055 JSTypedLoweringTester R; | 1056 JSTypedLoweringTester R; |
| 1056 | 1057 |
| 1057 Operator* ops[] = { | 1058 const Operator* ops[] = { |
| 1058 R.javascript.GreaterThan(), R.simplified.NumberLessThan(), | 1059 R.javascript.GreaterThan(), R.simplified.NumberLessThan(), |
| 1059 R.javascript.GreaterThanOrEqual(), R.simplified.NumberLessThanOrEqual(), | 1060 R.javascript.GreaterThanOrEqual(), R.simplified.NumberLessThanOrEqual(), |
| 1060 }; | 1061 }; |
| 1061 | 1062 |
| 1062 for (size_t j = 0; j < arraysize(ops); j += 2) { | 1063 for (size_t j = 0; j < arraysize(ops); j += 2) { |
| 1063 BinopEffectsTester B(ops[j], Type::Object(), Type::String()); | 1064 BinopEffectsTester B(ops[j], Type::Object(), Type::String()); |
| 1064 CHECK_EQ(ops[j + 1]->opcode(), B.result->op()->opcode()); | 1065 CHECK_EQ(ops[j + 1]->opcode(), B.result->op()->opcode()); |
| 1065 | 1066 |
| 1066 Node* i0 = B.CheckConvertedInput(IrOpcode::kJSToNumber, 0, true); | 1067 Node* i0 = B.CheckConvertedInput(IrOpcode::kJSToNumber, 0, true); |
| 1067 Node* i1 = B.CheckConvertedInput(IrOpcode::kJSToNumber, 1, true); | 1068 Node* i1 = B.CheckConvertedInput(IrOpcode::kJSToNumber, 1, true); |
| (...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1180 CHECK_EQ(B.p0, ii0->InputAt(0)); | 1181 CHECK_EQ(B.p0, ii0->InputAt(0)); |
| 1181 CHECK_EQ(B.p1, ii1->InputAt(0)); | 1182 CHECK_EQ(B.p1, ii1->InputAt(0)); |
| 1182 | 1183 |
| 1183 B.CheckEffectOrdering(ii0, ii1); | 1184 B.CheckEffectOrdering(ii0, ii1); |
| 1184 } | 1185 } |
| 1185 } | 1186 } |
| 1186 | 1187 |
| 1187 | 1188 |
| 1188 TEST(UnaryNotEffects) { | 1189 TEST(UnaryNotEffects) { |
| 1189 JSTypedLoweringTester R; | 1190 JSTypedLoweringTester R; |
| 1190 Operator* opnot = R.javascript.UnaryNot(); | 1191 const Operator* opnot = R.javascript.UnaryNot(); |
| 1191 | 1192 |
| 1192 for (size_t i = 0; i < arraysize(kJSTypes); i++) { | 1193 for (size_t i = 0; i < arraysize(kJSTypes); i++) { |
| 1193 Node* p0 = R.Parameter(kJSTypes[i], 0); | 1194 Node* p0 = R.Parameter(kJSTypes[i], 0); |
| 1194 Node* orig = R.Unop(opnot, p0); | 1195 Node* orig = R.Unop(opnot, p0); |
| 1195 Node* effect_use = R.UseForEffect(orig); | 1196 Node* effect_use = R.UseForEffect(orig); |
| 1196 Node* value_use = R.graph.NewNode(R.common.Return(), orig); | 1197 Node* value_use = R.graph.NewNode(R.common.Return(), orig); |
| 1197 Node* r = R.reduce(orig); | 1198 Node* r = R.reduce(orig); |
| 1198 // TODO(titzer): test will break if/when js-typed-lowering constant folds. | 1199 // TODO(titzer): test will break if/when js-typed-lowering constant folds. |
| 1199 CHECK_EQ(IrOpcode::kBooleanNot, value_use->InputAt(0)->opcode()); | 1200 CHECK_EQ(IrOpcode::kBooleanNot, value_use->InputAt(0)->opcode()); |
| 1200 | 1201 |
| (...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1292 CHECK_EQ(add_node, other_use->InputAt(0)); | 1293 CHECK_EQ(add_node, other_use->InputAt(0)); |
| 1293 CHECK_EQ(one, other_use->InputAt(1)); | 1294 CHECK_EQ(one, other_use->InputAt(1)); |
| 1294 } | 1295 } |
| 1295 } | 1296 } |
| 1296 | 1297 |
| 1297 | 1298 |
| 1298 TEST(Int32Comparisons) { | 1299 TEST(Int32Comparisons) { |
| 1299 JSTypedLoweringTester R; | 1300 JSTypedLoweringTester R; |
| 1300 | 1301 |
| 1301 struct Entry { | 1302 struct Entry { |
| 1302 Operator* js_op; | 1303 const Operator* js_op; |
| 1303 Operator* uint_op; | 1304 const Operator* uint_op; |
| 1304 Operator* int_op; | 1305 const Operator* int_op; |
| 1305 Operator* num_op; | 1306 const Operator* num_op; |
| 1306 bool commute; | 1307 bool commute; |
| 1307 }; | 1308 }; |
| 1308 | 1309 |
| 1309 Entry ops[] = { | 1310 Entry ops[] = { |
| 1310 {R.javascript.LessThan(), R.machine.Uint32LessThan(), | 1311 {R.javascript.LessThan(), R.machine.Uint32LessThan(), |
| 1311 R.machine.Int32LessThan(), R.simplified.NumberLessThan(), false}, | 1312 R.machine.Int32LessThan(), R.simplified.NumberLessThan(), false}, |
| 1312 {R.javascript.LessThanOrEqual(), R.machine.Uint32LessThanOrEqual(), | 1313 {R.javascript.LessThanOrEqual(), R.machine.Uint32LessThanOrEqual(), |
| 1313 R.machine.Int32LessThanOrEqual(), R.simplified.NumberLessThanOrEqual(), | 1314 R.machine.Int32LessThanOrEqual(), R.simplified.NumberLessThanOrEqual(), |
| 1314 false}, | 1315 false}, |
| 1315 {R.javascript.GreaterThan(), R.machine.Uint32LessThan(), | 1316 {R.javascript.GreaterThan(), R.machine.Uint32LessThan(), |
| 1316 R.machine.Int32LessThan(), R.simplified.NumberLessThan(), true}, | 1317 R.machine.Int32LessThan(), R.simplified.NumberLessThan(), true}, |
| 1317 {R.javascript.GreaterThanOrEqual(), R.machine.Uint32LessThanOrEqual(), | 1318 {R.javascript.GreaterThanOrEqual(), R.machine.Uint32LessThanOrEqual(), |
| 1318 R.machine.Int32LessThanOrEqual(), R.simplified.NumberLessThanOrEqual(), | 1319 R.machine.Int32LessThanOrEqual(), R.simplified.NumberLessThanOrEqual(), |
| 1319 true}}; | 1320 true}}; |
| 1320 | 1321 |
| 1321 for (size_t o = 0; o < arraysize(ops); o++) { | 1322 for (size_t o = 0; o < arraysize(ops); o++) { |
| 1322 for (size_t i = 0; i < arraysize(kNumberTypes); i++) { | 1323 for (size_t i = 0; i < arraysize(kNumberTypes); i++) { |
| 1323 Type* t0 = kNumberTypes[i]; | 1324 Type* t0 = kNumberTypes[i]; |
| 1324 Node* p0 = R.Parameter(t0, 0); | 1325 Node* p0 = R.Parameter(t0, 0); |
| 1325 | 1326 |
| 1326 for (size_t j = 0; j < arraysize(kNumberTypes); j++) { | 1327 for (size_t j = 0; j < arraysize(kNumberTypes); j++) { |
| 1327 Type* t1 = kNumberTypes[j]; | 1328 Type* t1 = kNumberTypes[j]; |
| 1328 Node* p1 = R.Parameter(t1, 1); | 1329 Node* p1 = R.Parameter(t1, 1); |
| 1329 | 1330 |
| 1330 Node* cmp = R.Binop(ops[o].js_op, p0, p1); | 1331 Node* cmp = R.Binop(ops[o].js_op, p0, p1); |
| 1331 Node* r = R.reduce(cmp); | 1332 Node* r = R.reduce(cmp); |
| 1332 | 1333 |
| 1333 Operator* expected; | 1334 const Operator* expected; |
| 1334 if (t0->Is(Type::Unsigned32()) && t1->Is(Type::Unsigned32())) { | 1335 if (t0->Is(Type::Unsigned32()) && t1->Is(Type::Unsigned32())) { |
| 1335 expected = ops[o].uint_op; | 1336 expected = ops[o].uint_op; |
| 1336 } else if (t0->Is(Type::Signed32()) && t1->Is(Type::Signed32())) { | 1337 } else if (t0->Is(Type::Signed32()) && t1->Is(Type::Signed32())) { |
| 1337 expected = ops[o].int_op; | 1338 expected = ops[o].int_op; |
| 1338 } else { | 1339 } else { |
| 1339 expected = ops[o].num_op; | 1340 expected = ops[o].num_op; |
| 1340 } | 1341 } |
| 1341 R.CheckPureBinop(expected, r); | 1342 R.CheckPureBinop(expected, r); |
| 1342 if (ops[o].commute) { | 1343 if (ops[o].commute) { |
| 1343 CHECK_EQ(p1, r->InputAt(0)); | 1344 CHECK_EQ(p1, r->InputAt(0)); |
| 1344 CHECK_EQ(p0, r->InputAt(1)); | 1345 CHECK_EQ(p0, r->InputAt(1)); |
| 1345 } else { | 1346 } else { |
| 1346 CHECK_EQ(p0, r->InputAt(0)); | 1347 CHECK_EQ(p0, r->InputAt(0)); |
| 1347 CHECK_EQ(p1, r->InputAt(1)); | 1348 CHECK_EQ(p1, r->InputAt(1)); |
| 1348 } | 1349 } |
| 1349 } | 1350 } |
| 1350 } | 1351 } |
| 1351 } | 1352 } |
| 1352 } | 1353 } |
| OLD | NEW |