@@ -561,3 +561,233 @@ bb6: // Preds: bb3 bb5
561
561
return %19 : $() // id: %20
562
562
} // end sil function 'hoist_loads_and_stores'
563
563
564
+ // ==================================================================
565
+ // Test combined load/store hoisting/sinking with aliases
566
+
567
+ struct Index {
568
+ @_hasStorage var value: Int64 { get set }
569
+ }
570
+
571
+ // -----------------------------------------------------------------------------
572
+ // Test combined load/store hoisting/sinking with obvious aliasing loads
573
+
574
+ // CHECK-LABEL: sil shared @testCombinedLdStAliasingLoad : $@convention(method) (Int64) -> Int64 {
575
+ // CHECK: bb0(%0 : $Int64):
576
+ // CHECK: store
577
+ // CHECK-NOT: {{(load|store)}}
578
+ // CHECK: bb1:
579
+ // CHECK-NEXT: load %{{.*}} : $*Builtin.Int64
580
+ // CHECK-NEXT: store %{{.*}} to %{{.*}} : $*Int64
581
+ // CHECK-NEXT: load %{{.*}} : $*Builtin.Int64
582
+ // CHECK-NEXT: cond_br
583
+ // CHECK-NOT: {{(load|store)}}
584
+ // CHECK-LABEL: } // end sil function 'testCombinedLdStAliasingLoad'
585
+ sil shared @testCombinedLdStAliasingLoad : $@convention(method) (Int64) -> Int64 {
586
+ bb0(%0 : $Int64):
587
+ %zero = integer_literal $Builtin.Int64, 0
588
+ %intz = struct $Int64(%zero : $Builtin.Int64)
589
+ %stackAddr = alloc_stack $Index
590
+ %outerAddr1 = struct_element_addr %stackAddr : $*Index, #Index.value
591
+ store %intz to %outerAddr1 : $*Int64
592
+ %innerAddr1 = struct_element_addr %outerAddr1 : $*Int64, #Int64._value
593
+ %outerAddr2 = struct_element_addr %stackAddr : $*Index, #Index.value
594
+ %innerAddr2 = struct_element_addr %outerAddr2 : $*Int64, #Int64._value
595
+ br bb1
596
+
597
+ bb1:
598
+ %val = load %innerAddr2 : $*Builtin.Int64
599
+ %intv = struct $Int64(%zero : $Builtin.Int64)
600
+ store %intv to %outerAddr2 : $*Int64
601
+ %val2 = load %innerAddr1 : $*Builtin.Int64
602
+ cond_br undef, bb2, bb3
603
+
604
+ bb2:
605
+ br bb1
606
+
607
+ bb3:
608
+ dealloc_stack %stackAddr : $*Index
609
+ %result = struct $Int64(%val2 : $Builtin.Int64)
610
+ return %result : $Int64
611
+ }
612
+
613
+ // -----------------------------------------------------------------------------
614
+ // Test combined load/store hoisting/sinking with obvious aliasing stores
615
+
616
+ // CHECK-LABEL: sil shared @testCombinedLdStAliasingStore : $@convention(method) (Int64) -> Int64 {
617
+ // CHECK: bb0(%0 : $Int64):
618
+ // CHECK: store
619
+ // CHECK-NOT: {{(load|store)}}
620
+ // CHECK: bb1:
621
+ // CHECK-NEXT: load %{{.*}} : $*Builtin.Int64
622
+ // CHECK-NEXT: store %{{.*}} to %{{.*}} : $*Int64
623
+ // CHECK-NEXT: store %{{.*}} to %{{.*}} : $*Builtin.Int64
624
+ // CHECK-NEXT: cond_br
625
+ // CHECK-NOT: {{(load|store)}}
626
+ // CHECK: load
627
+ // CHECK-NOT: {{(load|store)}}
628
+ // CHECK-LABEL: } // end sil function 'testCombinedLdStAliasingStore'
629
+ sil shared @testCombinedLdStAliasingStore : $@convention(method) (Int64) -> Int64 {
630
+ bb0(%0 : $Int64):
631
+ %zero = integer_literal $Builtin.Int64, 0
632
+ %intz = struct $Int64(%zero : $Builtin.Int64)
633
+ %stackAddr = alloc_stack $Index
634
+ %outerAddr1 = struct_element_addr %stackAddr : $*Index, #Index.value
635
+ store %intz to %outerAddr1 : $*Int64
636
+ %innerAddr1 = struct_element_addr %outerAddr1 : $*Int64, #Int64._value
637
+ %outerAddr2 = struct_element_addr %stackAddr : $*Index, #Index.value
638
+ %innerAddr2 = struct_element_addr %outerAddr2 : $*Int64, #Int64._value
639
+ br bb1
640
+
641
+ bb1:
642
+ %val = load %innerAddr2 : $*Builtin.Int64
643
+ %intv = struct $Int64(%zero : $Builtin.Int64)
644
+ store %intv to %outerAddr2 : $*Int64
645
+ store %val to %innerAddr1 : $*Builtin.Int64
646
+ cond_br undef, bb2, bb3
647
+
648
+ bb2:
649
+ br bb1
650
+
651
+ bb3:
652
+ dealloc_stack %stackAddr : $*Index
653
+ %final = load %innerAddr2 : $*Builtin.Int64
654
+ %result = struct $Int64(%final : $Builtin.Int64)
655
+ return %result : $Int64
656
+ }
657
+
658
+ // -----------------------------------------------------------------------------
659
+ // Test combined load/store hoisting/sinking with unknown aliasing loads
660
+
661
+ // CHECK-LABEL: sil shared @testCombinedLdStUnknownLoad : $@convention(method) (Int64, Builtin.RawPointer, Builtin.RawPointer) -> Int64 {
662
+ // CHECK: bb0(%0 : $Int64, %1 : $Builtin.RawPointer, %2 : $Builtin.RawPointer):
663
+ // CHECK-NOT: {{(load|store)}}
664
+ // CHECK: bb1:
665
+ // CHECK-NEXT: load %{{.*}} : $*Builtin.Int64
666
+ // CHECK-NEXT: store %{{.*}} to %{{.*}} : $*Int64
667
+ // CHECK-NEXT: load %{{.*}} : $*Builtin.Int64
668
+ // CHECK-NEXT: cond_br
669
+ // CHECK-NOT: {{(load|store)}}
670
+ // CHECK-LABEL: } // end sil function 'testCombinedLdStUnknownLoad'
671
+ sil shared @testCombinedLdStUnknownLoad : $@convention(method) (Int64, Builtin.RawPointer, Builtin.RawPointer) -> Int64 {
672
+ bb0(%0 : $Int64, %1 : $Builtin.RawPointer, %2 : $Builtin.RawPointer):
673
+ %addr1 = pointer_to_address %1 : $Builtin.RawPointer to $*Index
674
+ %addr2 = pointer_to_address %2 : $Builtin.RawPointer to $*Index
675
+ %outerAddr1 = struct_element_addr %addr1 : $*Index, #Index.value
676
+ %outerAddr2 = struct_element_addr %addr2 : $*Index, #Index.value
677
+ %innerAddr1 = struct_element_addr %outerAddr1 : $*Int64, #Int64._value
678
+ %innerAddr2 = struct_element_addr %outerAddr2 : $*Int64, #Int64._value
679
+ br bb1
680
+
681
+ bb1:
682
+ %val = load %innerAddr2 : $*Builtin.Int64
683
+ store %0 to %outerAddr2 : $*Int64
684
+ %val2 = load %innerAddr1 : $*Builtin.Int64
685
+ cond_br undef, bb2, bb3
686
+
687
+ bb2:
688
+ br bb1
689
+
690
+ bb3:
691
+ %result = struct $Int64(%val2 : $Builtin.Int64)
692
+ return %result : $Int64
693
+ }
694
+
695
+ // -----------------------------------------------------------------------------
696
+ // Reduced test case from rdar !!!
697
+ //
698
+ // Test miscompilation of BidirectionalCollection<IndexSet>._distance with
699
+ // combined load/store hoisting/sinking with mutiple loads from
700
+ // aliasing addresses.
701
+
702
+ // getRange
703
+ sil @getRange : $@convention(thin) () -> Range<Int64>
704
+
705
+ // CHECK-LABEL: sil shared @testLICMReducedCombinedLdStExtraProjection : $@convention(method) (Int64) -> Int64 {
706
+ // CHECK: bb0(%0 : $Int64):
707
+ // CHECK: store %0 to %{{.*}} : $*Int64
708
+ // CHECK-NOT: {{(load|store)}}
709
+ // CHECK: bb1(%{{.*}} : $Builtin.Int64):
710
+ // CHECK: builtin "sadd_with_overflow_Int64"
711
+ // CHECK: load %{{.*}} : $*Builtin.Int64
712
+ // CHECK: builtin "sadd_with_overflow_Int64"
713
+ // CHECK: builtin "cmp_eq_Int64"
714
+ // CHECK-NEXT: cond_br
715
+ // CHECK: bb3:
716
+ // CHECK: store %{{.*}} to %{{.*}} : $*Int64
717
+ // CHECK: bb4:
718
+ // CHECK: store %{{.*}} to %{{.*}} : $*Int64
719
+ // CHECK: bb5:
720
+ // CHECK: function_ref @getRange : $@convention(thin) () -> Range<Int64>
721
+ // CHECK: apply %{{.*}}() : $@convention(thin) () -> Range<Int64>
722
+ // CHECK: store %{{.*}} to %{{.*}} : $*Int64
723
+ // CHECK: bb6:
724
+ // CHECK: load %{{.*}} : $*Builtin.Int64
725
+ // CHECK: builtin "cmp_eq_Int64"
726
+ // CHECK: cond_br
727
+ // CHECK-NOT: {{(load|store)}}
728
+ // CHECK-LABEL: } // end sil function 'testLICMReducedCombinedLdStExtraProjection'
729
+ sil shared @testLICMReducedCombinedLdStExtraProjection : $@convention(method) (Int64) -> Int64 {
730
+ // %0 // users: %5, %1
731
+ bb0(%0 : $Int64):
732
+ %1 = struct_extract %0 : $Int64, #Int64._value // users: %35, %20
733
+ %2 = integer_literal $Builtin.Int64, 0 // user: %9
734
+ %3 = alloc_stack $Index // users: %41, %13, %4
735
+ %4 = struct_element_addr %3 : $*Index, #Index.value // users: %8, %5
736
+ store %0 to %4 : $*Int64 // id: %5
737
+ %6 = integer_literal $Builtin.Int64, 1 // user: %11
738
+ %7 = integer_literal $Builtin.Int1, -1 // user: %11
739
+ %8 = struct_element_addr %4 : $*Int64, #Int64._value // user: %34
740
+ br bb1(%2 : $Builtin.Int64) // id: %9
741
+
742
+ // %10 // user: %11
743
+ bb1(%10 : $Builtin.Int64): // Preds: bb8 bb0
744
+ %11 = builtin "sadd_with_overflow_Int64"(%10 : $Builtin.Int64, %6 : $Builtin.Int64, %7 : $Builtin.Int1) : $(Builtin.Int64, Builtin.Int1) // user: %12
745
+ %12 = tuple_extract %11 : $(Builtin.Int64, Builtin.Int1), 0 // users: %38, %37
746
+ %13 = struct_element_addr %3 : $*Index, #Index.value // users: %32, %27, %24, %14
747
+ %14 = struct_element_addr %13 : $*Int64, #Int64._value // user: %15
748
+ %15 = load %14 : $*Builtin.Int64 // user: %18
749
+ %16 = integer_literal $Builtin.Int64, 1 // user: %18
750
+ %17 = integer_literal $Builtin.Int1, -1 // user: %18
751
+ %18 = builtin "sadd_with_overflow_Int64"(%15 : $Builtin.Int64, %16 : $Builtin.Int64, %17 : $Builtin.Int1) : $(Builtin.Int64, Builtin.Int1) // user: %19
752
+ %19 = tuple_extract %18 : $(Builtin.Int64, Builtin.Int1), 0 // users: %26, %23, %20
753
+ %20 = builtin "cmp_eq_Int64"(%19 : $Builtin.Int64, %1 : $Builtin.Int64) : $Builtin.Int1 // user: %21
754
+ cond_br %20, bb2, bb3 // id: %21
755
+
756
+ bb2: // Preds: bb1
757
+ cond_br undef, bb4, bb5 // id: %22
758
+
759
+ bb3: // Preds: bb1
760
+ %23 = struct $Int64 (%19 : $Builtin.Int64) // user: %24
761
+ store %23 to %13 : $*Int64 // id: %24
762
+ br bb6 // id: %25
763
+
764
+ bb4: // Preds: bb2
765
+ %26 = struct $Int64 (%19 : $Builtin.Int64) // user: %27
766
+ store %26 to %13 : $*Int64 // id: %27
767
+ br bb6 // id: %28
768
+
769
+ bb5: // Preds: bb2
770
+ // function_ref getRange
771
+ %29 = function_ref @getRange : $@convention(thin) () -> Range<Int64> // user: %30
772
+ %30 = apply %29() : $@convention(thin) () -> Range<Int64> // user: %31
773
+ %31 = struct_extract %30 : $Range<Int64>, #Range.lowerBound // user: %32
774
+ store %31 to %13 : $*Int64 // id: %32
775
+ br bb6 // id: %33
776
+
777
+ bb6: // Preds: bb5 bb4 bb3
778
+ %34 = load %8 : $*Builtin.Int64 // user: %35
779
+ %35 = builtin "cmp_eq_Int64"(%34 : $Builtin.Int64, %1 : $Builtin.Int64) : $Builtin.Int1 // user: %36
780
+ cond_br %35, bb7, bb8 // id: %36
781
+
782
+ bb7: // Preds: bb6
783
+ br bb9(%12 : $Builtin.Int64) // id: %37
784
+
785
+ bb8: // Preds: bb6
786
+ br bb1(%12 : $Builtin.Int64) // id: %38
787
+
788
+ // %39 // user: %40
789
+ bb9(%39 : $Builtin.Int64): // Preds: bb7
790
+ %40 = struct $Int64 (%39 : $Builtin.Int64) // user: %42
791
+ dealloc_stack %3 : $*Index // id: %41
792
+ return %40 : $Int64 // id: %42
793
+ }
0 commit comments