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.
6 #include "test/cctest/cctest.h"
8 #include "src/compiler/instruction.h"
9 #include "src/compiler/instruction-codes.h"
10 #include "src/compiler/jump-threading.h"
16 typedef BasicBlock::RpoNumber RpoNumber;
18 class TestCode : public HandleAndZoneScope {
21 : HandleAndZoneScope(),
23 sequence_(main_isolate(), main_zone(), &blocks_),
24 rpo_number_(RpoNumber::FromInt(0)),
27 ZoneVector<InstructionBlock*> blocks_;
28 InstructionSequence sequence_;
29 RpoNumber rpo_number_;
30 InstructionBlock* current_;
32 int Jump(int target) {
34 InstructionOperand ops[] = {UseRpo(target)};
35 sequence_.AddInstruction(Instruction::New(main_zone(), kArchJmp, 0, NULL, 1,
36 ops, 0, NULL)->MarkAsControl());
37 int pos = static_cast<int>(sequence_.instructions().size() - 1);
45 int Branch(int ttarget, int ftarget) {
47 InstructionOperand ops[] = {UseRpo(ttarget), UseRpo(ftarget)};
48 InstructionCode code = 119 | FlagsModeField::encode(kFlags_branch) |
49 FlagsConditionField::encode(kEqual);
50 sequence_.AddInstruction(Instruction::New(main_zone(), code, 0, NULL, 2,
51 ops, 0, NULL)->MarkAsControl());
52 int pos = static_cast<int>(sequence_.instructions().size() - 1);
58 sequence_.AddInstruction(Instruction::New(main_zone(), kArchNop));
60 void RedundantMoves() {
62 sequence_.AddInstruction(Instruction::New(main_zone(), kArchNop));
63 int index = static_cast<int>(sequence_.instructions().size()) - 2;
64 sequence_.AddGapMove(index, RegisterOperand::New(13, main_zone()),
65 RegisterOperand::New(13, main_zone()));
67 void NonRedundantMoves() {
69 sequence_.AddInstruction(Instruction::New(main_zone(), kArchNop));
70 int index = static_cast<int>(sequence_.instructions().size()) - 2;
71 sequence_.AddGapMove(index, ImmediateOperand::New(11, main_zone()),
72 RegisterOperand::New(11, main_zone()));
76 sequence_.AddInstruction(Instruction::New(main_zone(), 155));
80 sequence_.EndBlock(current_->rpo_number());
82 rpo_number_ = RpoNumber::FromInt(rpo_number_.ToInt() + 1);
84 InstructionOperand UseRpo(int num) {
85 int index = sequence_.AddImmediate(Constant(RpoNumber::FromInt(num)));
86 return ImmediateOperand(index);
88 void Start(bool deferred = false) {
89 if (current_ == NULL) {
90 current_ = new (main_zone()) InstructionBlock(
91 main_zone(), BasicBlock::Id::FromInt(rpo_number_.ToInt()),
92 rpo_number_, RpoNumber::Invalid(), RpoNumber::Invalid(), deferred);
93 blocks_.push_back(current_);
94 sequence_.StartBlock(rpo_number_);
98 CHECK(current_ == NULL);
104 void VerifyForwarding(TestCode& code, int count, int* expected) {
106 ZoneVector<RpoNumber> result(&local_zone);
107 JumpThreading::ComputeForwarding(&local_zone, result, &code.sequence_);
109 CHECK(count == static_cast<int>(result.size()));
110 for (int i = 0; i < count; i++) {
111 CHECK(expected[i] == result[i].ToInt());
126 static int expected[] = {2, 2, 2};
127 VerifyForwarding(code, 3, expected);
132 for (int i = 0; i < 9; i++) {
138 for (int j = 0; j < i; j++) code.Nop();
143 static int expected[] = {2, 2, 2};
144 VerifyForwarding(code, 3, expected);
155 static int expected[] = {0};
156 VerifyForwarding(code, 1, expected);
164 code.RedundantMoves();
167 static int expected[] = {0};
168 VerifyForwarding(code, 1, expected);
176 code.RedundantMoves();
181 static int expected[] = {1, 1};
182 VerifyForwarding(code, 2, expected);
190 code.NonRedundantMoves();
195 static int expected[] = {0, 1};
196 VerifyForwarding(code, 2, expected);
209 static int expected[] = {0, 1};
210 VerifyForwarding(code, 2, expected);
222 static int expected[] = {1, 1};
223 VerifyForwarding(code, 2, expected);
235 static int expected[] = {1, 1};
236 VerifyForwarding(code, 2, expected);
246 static int expected[] = {0};
247 VerifyForwarding(code, 1, expected);
259 static int expected[] = {0, 0};
260 VerifyForwarding(code, 2, expected);
274 static int expected[] = {0, 0, 0};
275 VerifyForwarding(code, 3, expected);
287 static int expected[] = {1, 1};
288 VerifyForwarding(code, 2, expected);
302 static int expected[] = {1, 1, 1};
303 VerifyForwarding(code, 3, expected);
319 static int expected[] = {1, 1, 1, 1};
320 VerifyForwarding(code, 4, expected);
338 static int expected[] = {1, 1, 1, 1, 1};
339 VerifyForwarding(code, 5, expected);
357 static int expected[] = {2, 2, 2, 2, 2};
358 VerifyForwarding(code, 5, expected);
376 static int expected[] = {1, 1, 1, 1, 1};
377 VerifyForwarding(code, 5, expected);
395 static int expected[] = {1, 1, 1, 1, 1};
396 VerifyForwarding(code, 5, expected);
416 static int expected[] = {2, 2, 2, 2, 2, 2};
417 VerifyForwarding(code, 6, expected);
422 for (int i = 0; i < 2; i++) {
423 for (int j = 0; j < 2; j++) {
436 int expected[] = {0, i ? 1 : 3, j ? 2 : 3, 3};
437 VerifyForwarding(code, 4, expected);
444 for (int i = 0; i < 2; i++) {
445 for (int j = 0; j < 2; j++) {
446 for (int k = 0; k < 2; k++) {
457 if (k) code.NonRedundantMoves();
462 int merge = k ? 3 : 4;
463 int expected[] = {0, i ? 1 : merge, j ? 2 : merge, merge, 4};
464 VerifyForwarding(code, 5, expected);
471 TEST(FwDoubleDiamonds) {
472 for (int i = 0; i < 2; i++) {
473 for (int j = 0; j < 2; j++) {
474 for (int x = 0; x < 2; x++) {
475 for (int y = 0; y < 2; y++) {
496 int expected[] = {0, i ? 1 : 3, j ? 2 : 3, 3,
497 x ? 4 : 6, y ? 5 : 6, 6};
498 VerifyForwarding(code, 7, expected);
506 void RunPermutationsRecursive(int outer[kSize], int start,
507 void (*run)(int*, int)) {
508 int permutation[kSize];
510 for (int i = 0; i < kSize; i++) permutation[i] = outer[i];
512 int count = kSize - start;
513 if (count == 0) return run(permutation, kSize);
514 for (int i = start; i < kSize; i++) {
515 permutation[start] = outer[i];
516 permutation[i] = outer[start];
517 RunPermutationsRecursive<kSize>(permutation, start + 1, run);
518 permutation[i] = outer[i];
519 permutation[start] = outer[start];
525 void RunAllPermutations(void (*run)(int*, int)) {
526 int permutation[kSize];
527 for (int i = 0; i < kSize; i++) permutation[i] = i;
528 RunPermutationsRecursive<kSize>(permutation, 0, run);
532 void PrintPermutation(int* permutation, int size) {
534 for (int i = 0; i < size; i++) {
535 if (i > 0) printf(", ");
536 printf("%d", permutation[i]);
542 int find(int x, int* permutation, int size) {
543 for (int i = 0; i < size; i++) {
544 if (permutation[i] == x) return i;
550 void RunPermutedChain(int* permutation, int size) {
553 for (int i = 0; i < size; i++) {
554 code.Jump(find(cur + 1, permutation, size) + 1);
555 cur = permutation[i];
557 code.Jump(find(cur + 1, permutation, size) + 1);
560 int expected[] = {size + 1, size + 1, size + 1, size + 1,
561 size + 1, size + 1, size + 1};
562 VerifyForwarding(code, size + 2, expected);
566 TEST(FwPermuted_chain) {
567 RunAllPermutations<3>(RunPermutedChain);
568 RunAllPermutations<4>(RunPermutedChain);
569 RunAllPermutations<5>(RunPermutedChain);
573 void RunPermutedDiamond(int* permutation, int size) {
575 int br = 1 + find(0, permutation, size);
577 for (int i = 0; i < size; i++) {
578 switch (permutation[i]) {
580 code.Branch(1 + find(1, permutation, size),
581 1 + find(2, permutation, size));
584 code.Jump(1 + find(3, permutation, size));
587 code.Jump(1 + find(3, permutation, size));
596 int expected[] = {br, 5, 5, 5, 5, 5};
598 VerifyForwarding(code, 6, expected);
602 TEST(FwPermuted_diamond) { RunAllPermutations<4>(RunPermutedDiamond); }
605 void ApplyForwarding(TestCode& code, int size, int* forward) {
606 ZoneVector<RpoNumber> vector(code.main_zone());
607 for (int i = 0; i < size; i++) {
608 vector.push_back(RpoNumber::FromInt(forward[i]));
610 JumpThreading::ApplyForwarding(vector, &code.sequence_);
614 void CheckJump(TestCode& code, int pos, int target) {
615 Instruction* instr = code.sequence_.InstructionAt(pos);
616 CHECK_EQ(kArchJmp, instr->arch_opcode());
617 CHECK_EQ(1, static_cast<int>(instr->InputCount()));
618 CHECK_EQ(0, static_cast<int>(instr->OutputCount()));
619 CHECK_EQ(0, static_cast<int>(instr->TempCount()));
620 CHECK_EQ(target, code.sequence_.InputRpo(instr, 0).ToInt());
624 void CheckNop(TestCode& code, int pos) {
625 Instruction* instr = code.sequence_.InstructionAt(pos);
626 CHECK_EQ(kArchNop, instr->arch_opcode());
627 CHECK_EQ(0, static_cast<int>(instr->InputCount()));
628 CHECK_EQ(0, static_cast<int>(instr->OutputCount()));
629 CHECK_EQ(0, static_cast<int>(instr->TempCount()));
633 void CheckBranch(TestCode& code, int pos, int t1, int t2) {
634 Instruction* instr = code.sequence_.InstructionAt(pos);
635 CHECK_EQ(2, static_cast<int>(instr->InputCount()));
636 CHECK_EQ(0, static_cast<int>(instr->OutputCount()));
637 CHECK_EQ(0, static_cast<int>(instr->TempCount()));
638 CHECK_EQ(t1, code.sequence_.InputRpo(instr, 0).ToInt());
639 CHECK_EQ(t2, code.sequence_.InputRpo(instr, 1).ToInt());
643 void CheckAssemblyOrder(TestCode& code, int size, int* expected) {
645 for (auto const block : code.sequence_.instruction_blocks()) {
646 CHECK_EQ(expected[i++], block->ao_number().ToInt());
655 int j1 = code.Jump(1);
657 int j2 = code.Jump(2);
661 static int forward[] = {2, 2, 2};
662 ApplyForwarding(code, 3, forward);
663 CheckJump(code, j1, 2);
666 static int assembly[] = {0, 1, 1};
667 CheckAssemblyOrder(code, 3, assembly);
671 TEST(Rewire1_deferred) {
675 int j1 = code.Jump(1);
677 int j2 = code.Jump(2);
680 int j3 = code.Jump(3);
684 static int forward[] = {3, 3, 3, 3};
685 ApplyForwarding(code, 4, forward);
686 CheckJump(code, j1, 3);
690 static int assembly[] = {0, 1, 2, 1};
691 CheckAssemblyOrder(code, 4, assembly);
695 TEST(Rewire2_deferred) {
700 int j1 = code.Jump(1);
706 int j2 = code.Jump(3);
710 static int forward[] = {0, 1, 2, 3};
711 ApplyForwarding(code, 4, forward);
712 CheckJump(code, j1, 1);
713 CheckJump(code, j2, 3);
715 static int assembly[] = {0, 2, 3, 1};
716 CheckAssemblyOrder(code, 4, assembly);
720 TEST(Rewire_diamond) {
721 for (int i = 0; i < 2; i++) {
722 for (int j = 0; j < 2; j++) {
725 int j1 = code.Jump(1);
727 int b1 = code.Branch(2, 3);
729 int j2 = code.Jump(4);
731 int j3 = code.Jump(4);
735 int forward[] = {0, 1, i ? 4 : 2, j ? 4 : 3, 4};
736 ApplyForwarding(code, 5, forward);
737 CheckJump(code, j1, 1);
738 CheckBranch(code, b1, i ? 4 : 2, j ? 4 : 3);
742 CheckJump(code, j2, 4);
747 CheckJump(code, j3, 4);
750 int assembly[] = {0, 1, 2, 3, 4};
752 for (int k = 3; k < 5; k++) assembly[k]--;
755 for (int k = 4; k < 5; k++) assembly[k]--;
757 CheckAssemblyOrder(code, 5, assembly);
762 } // namespace compiler
763 } // namespace internal