blob: ed3d79e4baceb97719013588be3916d4bcdea8e5 [file] [log] [blame]
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001// 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
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005#include "src/compiler/instruction.h"
6#include "src/compiler/instruction-codes.h"
7#include "src/compiler/jump-threading.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00008#include "test/cctest/cctest.h"
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009
10namespace v8 {
11namespace internal {
12namespace compiler {
13
Emily Bernierd0a1eb72015-03-24 16:35:39 -040014class TestCode : public HandleAndZoneScope {
15 public:
16 TestCode()
17 : HandleAndZoneScope(),
18 blocks_(main_zone()),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000019 sequence_(main_isolate(), main_zone(), &blocks_),
Emily Bernierd0a1eb72015-03-24 16:35:39 -040020 rpo_number_(RpoNumber::FromInt(0)),
21 current_(NULL) {}
22
23 ZoneVector<InstructionBlock*> blocks_;
24 InstructionSequence sequence_;
25 RpoNumber rpo_number_;
26 InstructionBlock* current_;
27
28 int Jump(int target) {
29 Start();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000030 InstructionOperand ops[] = {UseRpo(target)};
31 sequence_.AddInstruction(
32 Instruction::New(main_zone(), kArchJmp, 0, NULL, 1, ops, 0, NULL));
Emily Bernierd0a1eb72015-03-24 16:35:39 -040033 int pos = static_cast<int>(sequence_.instructions().size() - 1);
34 End();
35 return pos;
36 }
37 void Fallthru() {
38 Start();
39 End();
40 }
41 int Branch(int ttarget, int ftarget) {
42 Start();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000043 InstructionOperand ops[] = {UseRpo(ttarget), UseRpo(ftarget)};
Emily Bernierd0a1eb72015-03-24 16:35:39 -040044 InstructionCode code = 119 | FlagsModeField::encode(kFlags_branch) |
45 FlagsConditionField::encode(kEqual);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000046 sequence_.AddInstruction(
47 Instruction::New(main_zone(), code, 0, NULL, 2, ops, 0, NULL));
Emily Bernierd0a1eb72015-03-24 16:35:39 -040048 int pos = static_cast<int>(sequence_.instructions().size() - 1);
49 End();
50 return pos;
51 }
52 void Nop() {
53 Start();
54 sequence_.AddInstruction(Instruction::New(main_zone(), kArchNop));
55 }
56 void RedundantMoves() {
57 Start();
58 sequence_.AddInstruction(Instruction::New(main_zone(), kArchNop));
59 int index = static_cast<int>(sequence_.instructions().size()) - 1;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000060 AddGapMove(index, AllocatedOperand(LocationOperand::REGISTER,
61 MachineRepresentation::kWord32, 13),
62 AllocatedOperand(LocationOperand::REGISTER,
63 MachineRepresentation::kWord32, 13));
Emily Bernierd0a1eb72015-03-24 16:35:39 -040064 }
65 void NonRedundantMoves() {
66 Start();
67 sequence_.AddInstruction(Instruction::New(main_zone(), kArchNop));
68 int index = static_cast<int>(sequence_.instructions().size()) - 1;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000069 AddGapMove(index, ConstantOperand(11),
70 AllocatedOperand(LocationOperand::REGISTER,
71 MachineRepresentation::kWord32, 11));
Emily Bernierd0a1eb72015-03-24 16:35:39 -040072 }
73 void Other() {
74 Start();
75 sequence_.AddInstruction(Instruction::New(main_zone(), 155));
76 }
77 void End() {
78 Start();
79 sequence_.EndBlock(current_->rpo_number());
80 current_ = NULL;
81 rpo_number_ = RpoNumber::FromInt(rpo_number_.ToInt() + 1);
82 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000083 InstructionOperand UseRpo(int num) {
84 return sequence_.AddImmediate(Constant(RpoNumber::FromInt(num)));
Emily Bernierd0a1eb72015-03-24 16:35:39 -040085 }
86 void Start(bool deferred = false) {
87 if (current_ == NULL) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000088 current_ = new (main_zone())
89 InstructionBlock(main_zone(), rpo_number_, RpoNumber::Invalid(),
90 RpoNumber::Invalid(), deferred, false);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040091 blocks_.push_back(current_);
92 sequence_.StartBlock(rpo_number_);
93 }
94 }
95 void Defer() {
96 CHECK(current_ == NULL);
97 Start(true);
98 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000099 void AddGapMove(int index, const InstructionOperand& from,
100 const InstructionOperand& to) {
101 sequence_.InstructionAt(index)
102 ->GetOrCreateParallelMove(Instruction::START, main_zone())
103 ->AddMove(from, to);
104 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400105};
106
107
108void VerifyForwarding(TestCode& code, int count, int* expected) {
Ben Murdochda12d292016-06-02 14:46:10 +0100109 base::AccountingAllocator allocator;
110 Zone local_zone(&allocator);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400111 ZoneVector<RpoNumber> result(&local_zone);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100112 JumpThreading::ComputeForwarding(&local_zone, result, &code.sequence_, true);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400113
114 CHECK(count == static_cast<int>(result.size()));
115 for (int i = 0; i < count; i++) {
116 CHECK(expected[i] == result[i].ToInt());
117 }
118}
119
120
121TEST(FwEmpty1) {
122 TestCode code;
123
124 // B0
125 code.Jump(1);
126 // B1
127 code.Jump(2);
128 // B2
129 code.End();
130
131 static int expected[] = {2, 2, 2};
132 VerifyForwarding(code, 3, expected);
133}
134
135
136TEST(FwEmptyN) {
137 for (int i = 0; i < 9; i++) {
138 TestCode code;
139
140 // B0
141 code.Jump(1);
142 // B1
143 for (int j = 0; j < i; j++) code.Nop();
144 code.Jump(2);
145 // B2
146 code.End();
147
148 static int expected[] = {2, 2, 2};
149 VerifyForwarding(code, 3, expected);
150 }
151}
152
153
154TEST(FwNone1) {
155 TestCode code;
156
157 // B0
158 code.End();
159
160 static int expected[] = {0};
161 VerifyForwarding(code, 1, expected);
162}
163
164
165TEST(FwMoves1) {
166 TestCode code;
167
168 // B0
169 code.RedundantMoves();
170 code.End();
171
172 static int expected[] = {0};
173 VerifyForwarding(code, 1, expected);
174}
175
176
177TEST(FwMoves2) {
178 TestCode code;
179
180 // B0
181 code.RedundantMoves();
182 code.Fallthru();
183 // B1
184 code.End();
185
186 static int expected[] = {1, 1};
187 VerifyForwarding(code, 2, expected);
188}
189
190
191TEST(FwMoves2b) {
192 TestCode code;
193
194 // B0
195 code.NonRedundantMoves();
196 code.Fallthru();
197 // B1
198 code.End();
199
200 static int expected[] = {0, 1};
201 VerifyForwarding(code, 2, expected);
202}
203
204
205TEST(FwOther2) {
206 TestCode code;
207
208 // B0
209 code.Other();
210 code.Fallthru();
211 // B1
212 code.End();
213
214 static int expected[] = {0, 1};
215 VerifyForwarding(code, 2, expected);
216}
217
218
219TEST(FwNone2a) {
220 TestCode code;
221
222 // B0
223 code.Fallthru();
224 // B1
225 code.End();
226
227 static int expected[] = {1, 1};
228 VerifyForwarding(code, 2, expected);
229}
230
231
232TEST(FwNone2b) {
233 TestCode code;
234
235 // B0
236 code.Jump(1);
237 // B1
238 code.End();
239
240 static int expected[] = {1, 1};
241 VerifyForwarding(code, 2, expected);
242}
243
244
245TEST(FwLoop1) {
246 TestCode code;
247
248 // B0
249 code.Jump(0);
250
251 static int expected[] = {0};
252 VerifyForwarding(code, 1, expected);
253}
254
255
256TEST(FwLoop2) {
257 TestCode code;
258
259 // B0
260 code.Fallthru();
261 // B1
262 code.Jump(0);
263
264 static int expected[] = {0, 0};
265 VerifyForwarding(code, 2, expected);
266}
267
268
269TEST(FwLoop3) {
270 TestCode code;
271
272 // B0
273 code.Fallthru();
274 // B1
275 code.Fallthru();
276 // B2
277 code.Jump(0);
278
279 static int expected[] = {0, 0, 0};
280 VerifyForwarding(code, 3, expected);
281}
282
283
284TEST(FwLoop1b) {
285 TestCode code;
286
287 // B0
288 code.Fallthru();
289 // B1
290 code.Jump(1);
291
292 static int expected[] = {1, 1};
293 VerifyForwarding(code, 2, expected);
294}
295
296
297TEST(FwLoop2b) {
298 TestCode code;
299
300 // B0
301 code.Fallthru();
302 // B1
303 code.Fallthru();
304 // B2
305 code.Jump(1);
306
307 static int expected[] = {1, 1, 1};
308 VerifyForwarding(code, 3, expected);
309}
310
311
312TEST(FwLoop3b) {
313 TestCode code;
314
315 // B0
316 code.Fallthru();
317 // B1
318 code.Fallthru();
319 // B2
320 code.Fallthru();
321 // B3
322 code.Jump(1);
323
324 static int expected[] = {1, 1, 1, 1};
325 VerifyForwarding(code, 4, expected);
326}
327
328
329TEST(FwLoop2_1a) {
330 TestCode code;
331
332 // B0
333 code.Fallthru();
334 // B1
335 code.Fallthru();
336 // B2
337 code.Fallthru();
338 // B3
339 code.Jump(1);
340 // B4
341 code.Jump(2);
342
343 static int expected[] = {1, 1, 1, 1, 1};
344 VerifyForwarding(code, 5, expected);
345}
346
347
348TEST(FwLoop2_1b) {
349 TestCode code;
350
351 // B0
352 code.Fallthru();
353 // B1
354 code.Fallthru();
355 // B2
356 code.Jump(4);
357 // B3
358 code.Jump(1);
359 // B4
360 code.Jump(2);
361
362 static int expected[] = {2, 2, 2, 2, 2};
363 VerifyForwarding(code, 5, expected);
364}
365
366
367TEST(FwLoop2_1c) {
368 TestCode code;
369
370 // B0
371 code.Fallthru();
372 // B1
373 code.Fallthru();
374 // B2
375 code.Jump(4);
376 // B3
377 code.Jump(2);
378 // B4
379 code.Jump(1);
380
381 static int expected[] = {1, 1, 1, 1, 1};
382 VerifyForwarding(code, 5, expected);
383}
384
385
386TEST(FwLoop2_1d) {
387 TestCode code;
388
389 // B0
390 code.Fallthru();
391 // B1
392 code.Fallthru();
393 // B2
394 code.Jump(1);
395 // B3
396 code.Jump(1);
397 // B4
398 code.Jump(1);
399
400 static int expected[] = {1, 1, 1, 1, 1};
401 VerifyForwarding(code, 5, expected);
402}
403
404
405TEST(FwLoop3_1a) {
406 TestCode code;
407
408 // B0
409 code.Fallthru();
410 // B1
411 code.Fallthru();
412 // B2
413 code.Fallthru();
414 // B3
415 code.Jump(2);
416 // B4
417 code.Jump(1);
418 // B5
419 code.Jump(0);
420
421 static int expected[] = {2, 2, 2, 2, 2, 2};
422 VerifyForwarding(code, 6, expected);
423}
424
425
426TEST(FwDiamonds) {
427 for (int i = 0; i < 2; i++) {
428 for (int j = 0; j < 2; j++) {
429 TestCode code;
430 // B0
431 code.Branch(1, 2);
432 // B1
433 if (i) code.Other();
434 code.Jump(3);
435 // B2
436 if (j) code.Other();
437 code.Jump(3);
438 // B3
439 code.End();
440
441 int expected[] = {0, i ? 1 : 3, j ? 2 : 3, 3};
442 VerifyForwarding(code, 4, expected);
443 }
444 }
445}
446
447
448TEST(FwDiamonds2) {
449 for (int i = 0; i < 2; i++) {
450 for (int j = 0; j < 2; j++) {
451 for (int k = 0; k < 2; k++) {
452 TestCode code;
453 // B0
454 code.Branch(1, 2);
455 // B1
456 if (i) code.Other();
457 code.Jump(3);
458 // B2
459 if (j) code.Other();
460 code.Jump(3);
461 // B3
462 if (k) code.NonRedundantMoves();
463 code.Jump(4);
464 // B4
465 code.End();
466
467 int merge = k ? 3 : 4;
468 int expected[] = {0, i ? 1 : merge, j ? 2 : merge, merge, 4};
469 VerifyForwarding(code, 5, expected);
470 }
471 }
472 }
473}
474
475
476TEST(FwDoubleDiamonds) {
477 for (int i = 0; i < 2; i++) {
478 for (int j = 0; j < 2; j++) {
479 for (int x = 0; x < 2; x++) {
480 for (int y = 0; y < 2; y++) {
481 TestCode code;
482 // B0
483 code.Branch(1, 2);
484 // B1
485 if (i) code.Other();
486 code.Jump(3);
487 // B2
488 if (j) code.Other();
489 code.Jump(3);
490 // B3
491 code.Branch(4, 5);
492 // B4
493 if (x) code.Other();
494 code.Jump(6);
495 // B5
496 if (y) code.Other();
497 code.Jump(6);
498 // B6
499 code.End();
500
501 int expected[] = {0, i ? 1 : 3, j ? 2 : 3, 3,
502 x ? 4 : 6, y ? 5 : 6, 6};
503 VerifyForwarding(code, 7, expected);
504 }
505 }
506 }
507 }
508}
509
510template <int kSize>
511void RunPermutationsRecursive(int outer[kSize], int start,
512 void (*run)(int*, int)) {
513 int permutation[kSize];
514
515 for (int i = 0; i < kSize; i++) permutation[i] = outer[i];
516
517 int count = kSize - start;
518 if (count == 0) return run(permutation, kSize);
519 for (int i = start; i < kSize; i++) {
520 permutation[start] = outer[i];
521 permutation[i] = outer[start];
522 RunPermutationsRecursive<kSize>(permutation, start + 1, run);
523 permutation[i] = outer[i];
524 permutation[start] = outer[start];
525 }
526}
527
528
529template <int kSize>
530void RunAllPermutations(void (*run)(int*, int)) {
531 int permutation[kSize];
532 for (int i = 0; i < kSize; i++) permutation[i] = i;
533 RunPermutationsRecursive<kSize>(permutation, 0, run);
534}
535
536
537void PrintPermutation(int* permutation, int size) {
538 printf("{ ");
539 for (int i = 0; i < size; i++) {
540 if (i > 0) printf(", ");
541 printf("%d", permutation[i]);
542 }
543 printf(" }\n");
544}
545
546
547int find(int x, int* permutation, int size) {
548 for (int i = 0; i < size; i++) {
549 if (permutation[i] == x) return i;
550 }
551 return size;
552}
553
554
555void RunPermutedChain(int* permutation, int size) {
556 TestCode code;
557 int cur = -1;
558 for (int i = 0; i < size; i++) {
559 code.Jump(find(cur + 1, permutation, size) + 1);
560 cur = permutation[i];
561 }
562 code.Jump(find(cur + 1, permutation, size) + 1);
563 code.End();
564
565 int expected[] = {size + 1, size + 1, size + 1, size + 1,
566 size + 1, size + 1, size + 1};
567 VerifyForwarding(code, size + 2, expected);
568}
569
570
571TEST(FwPermuted_chain) {
572 RunAllPermutations<3>(RunPermutedChain);
573 RunAllPermutations<4>(RunPermutedChain);
574 RunAllPermutations<5>(RunPermutedChain);
575}
576
577
578void RunPermutedDiamond(int* permutation, int size) {
579 TestCode code;
580 int br = 1 + find(0, permutation, size);
581 code.Jump(br);
582 for (int i = 0; i < size; i++) {
583 switch (permutation[i]) {
584 case 0:
585 code.Branch(1 + find(1, permutation, size),
586 1 + find(2, permutation, size));
587 break;
588 case 1:
589 code.Jump(1 + find(3, permutation, size));
590 break;
591 case 2:
592 code.Jump(1 + find(3, permutation, size));
593 break;
594 case 3:
595 code.Jump(5);
596 break;
597 }
598 }
599 code.End();
600
601 int expected[] = {br, 5, 5, 5, 5, 5};
602 expected[br] = br;
603 VerifyForwarding(code, 6, expected);
604}
605
606
607TEST(FwPermuted_diamond) { RunAllPermutations<4>(RunPermutedDiamond); }
608
609
610void ApplyForwarding(TestCode& code, int size, int* forward) {
611 ZoneVector<RpoNumber> vector(code.main_zone());
612 for (int i = 0; i < size; i++) {
613 vector.push_back(RpoNumber::FromInt(forward[i]));
614 }
615 JumpThreading::ApplyForwarding(vector, &code.sequence_);
616}
617
618
619void CheckJump(TestCode& code, int pos, int target) {
620 Instruction* instr = code.sequence_.InstructionAt(pos);
621 CHECK_EQ(kArchJmp, instr->arch_opcode());
622 CHECK_EQ(1, static_cast<int>(instr->InputCount()));
623 CHECK_EQ(0, static_cast<int>(instr->OutputCount()));
624 CHECK_EQ(0, static_cast<int>(instr->TempCount()));
625 CHECK_EQ(target, code.sequence_.InputRpo(instr, 0).ToInt());
626}
627
628
629void CheckNop(TestCode& code, int pos) {
630 Instruction* instr = code.sequence_.InstructionAt(pos);
631 CHECK_EQ(kArchNop, instr->arch_opcode());
632 CHECK_EQ(0, static_cast<int>(instr->InputCount()));
633 CHECK_EQ(0, static_cast<int>(instr->OutputCount()));
634 CHECK_EQ(0, static_cast<int>(instr->TempCount()));
635}
636
637
638void CheckBranch(TestCode& code, int pos, int t1, int t2) {
639 Instruction* instr = code.sequence_.InstructionAt(pos);
640 CHECK_EQ(2, static_cast<int>(instr->InputCount()));
641 CHECK_EQ(0, static_cast<int>(instr->OutputCount()));
642 CHECK_EQ(0, static_cast<int>(instr->TempCount()));
643 CHECK_EQ(t1, code.sequence_.InputRpo(instr, 0).ToInt());
644 CHECK_EQ(t2, code.sequence_.InputRpo(instr, 1).ToInt());
645}
646
647
648void CheckAssemblyOrder(TestCode& code, int size, int* expected) {
649 int i = 0;
650 for (auto const block : code.sequence_.instruction_blocks()) {
651 CHECK_EQ(expected[i++], block->ao_number().ToInt());
652 }
653}
654
655
656TEST(Rewire1) {
657 TestCode code;
658
659 // B0
660 int j1 = code.Jump(1);
661 // B1
662 int j2 = code.Jump(2);
663 // B2
664 code.End();
665
666 static int forward[] = {2, 2, 2};
667 ApplyForwarding(code, 3, forward);
668 CheckJump(code, j1, 2);
669 CheckNop(code, j2);
670
671 static int assembly[] = {0, 1, 1};
672 CheckAssemblyOrder(code, 3, assembly);
673}
674
675
676TEST(Rewire1_deferred) {
677 TestCode code;
678
679 // B0
680 int j1 = code.Jump(1);
681 // B1
682 int j2 = code.Jump(2);
683 // B2
684 code.Defer();
685 int j3 = code.Jump(3);
686 // B3
687 code.End();
688
689 static int forward[] = {3, 3, 3, 3};
690 ApplyForwarding(code, 4, forward);
691 CheckJump(code, j1, 3);
692 CheckNop(code, j2);
693 CheckNop(code, j3);
694
695 static int assembly[] = {0, 1, 2, 1};
696 CheckAssemblyOrder(code, 4, assembly);
697}
698
699
700TEST(Rewire2_deferred) {
701 TestCode code;
702
703 // B0
704 code.Other();
705 int j1 = code.Jump(1);
706 // B1
707 code.Defer();
708 code.Fallthru();
709 // B2
710 code.Defer();
711 int j2 = code.Jump(3);
712 // B3
713 code.End();
714
715 static int forward[] = {0, 1, 2, 3};
716 ApplyForwarding(code, 4, forward);
717 CheckJump(code, j1, 1);
718 CheckJump(code, j2, 3);
719
720 static int assembly[] = {0, 2, 3, 1};
721 CheckAssemblyOrder(code, 4, assembly);
722}
723
724
725TEST(Rewire_diamond) {
726 for (int i = 0; i < 2; i++) {
727 for (int j = 0; j < 2; j++) {
728 TestCode code;
729 // B0
730 int j1 = code.Jump(1);
731 // B1
732 int b1 = code.Branch(2, 3);
733 // B2
734 int j2 = code.Jump(4);
735 // B3
736 int j3 = code.Jump(4);
737 // B5
738 code.End();
739
740 int forward[] = {0, 1, i ? 4 : 2, j ? 4 : 3, 4};
741 ApplyForwarding(code, 5, forward);
742 CheckJump(code, j1, 1);
743 CheckBranch(code, b1, i ? 4 : 2, j ? 4 : 3);
744 if (i) {
745 CheckNop(code, j2);
746 } else {
747 CheckJump(code, j2, 4);
748 }
749 if (j) {
750 CheckNop(code, j3);
751 } else {
752 CheckJump(code, j3, 4);
753 }
754
755 int assembly[] = {0, 1, 2, 3, 4};
756 if (i) {
757 for (int k = 3; k < 5; k++) assembly[k]--;
758 }
759 if (j) {
760 for (int k = 4; k < 5; k++) assembly[k]--;
761 }
762 CheckAssemblyOrder(code, 5, assembly);
763 }
764 }
765}
766
767} // namespace compiler
768} // namespace internal
769} // namespace v8