@@ -706,3 +706,163 @@ bb0(%0 : $*T, %1 : $*T):
706706 %10 = tuple ()
707707 return %10 : $()
708708}
709+
710+ // Test reference root casts.
711+ class A {
712+ var prop0: Int64
713+ }
714+ class B : A {
715+ var alsoProp0: Int64
716+ }
717+
718+ // CHECK-LABEL: @testReferenceRootCast
719+ // CHECK: ###For MemOp: store %0 to [[ADR0:%.*]] : $*Int64
720+ // CHECK: Class %{{.*}} = alloc_ref $B
721+ // CHECK: Field: var prop0: Int64 Index: 0
722+ // CHECK: Base: [[ADR0]] = ref_element_addr %{{.*}} : $A, #A.prop0
723+ // CHECK: Storage: Class %1 = alloc_ref $B
724+ // CHECK: Field: var prop0: Int64 Index: 0
725+ // CHECK: Path: ()
726+ // CHECK: Exact Uses {
727+ // CHECK-NEXT: store %0 to [[ADR0]] : $*Int64
728+ // CHECK-NEXT: Path: ()
729+ // CHECK-NEXT: }
730+ // CHECK: Overlapping Uses {
731+ // CHECK-NEXT: store %0 to [[ADR0]] : $*Int64
732+ // CHECK-NEXT: Path: ()
733+ // CHECK-NEXT: }
734+ // CHECK: ###For MemOp: store %0 to [[ADR1:%.*]] : $*Int64
735+ // CHECK-NEXT: Class %{{.*}} = alloc_ref $B
736+ // CHECK-NEXT: Field: var alsoProp0: Int64 Index: 1
737+ // CHECK-NEXT: Base: [[ADR1]] = ref_element_addr %10 : $B, #B.alsoProp0
738+ // CHECK-NEXT: Storage: Class %{{.*}} = alloc_ref $B
739+ // CHECK-NEXT: Field: var alsoProp0: Int64 Index: 1
740+ // CHECK-NEXT: Path: ()
741+ // CHECK-NEXT: Exact Uses {
742+ // CHECK-NEXT: store %0 to [[ADR1]] : $*Int64
743+ // CHECK-NEXT: Path: ()
744+ // CHECK-NEXT: }
745+ // CHECK: Overlapping Uses {
746+ // CHECK-NEXT: store %0 to [[ADR1]] : $*Int64
747+ // CHECK-NEXT: Path: ()
748+ // CHECK-NEXT: }
749+ sil @testReferenceRootCast : $@convention(thin) (Int64) -> () {
750+ bb0(%0 : $Int64):
751+ %1 = alloc_ref $B
752+ cond_br undef, bb1, bb2
753+
754+ bb1:
755+ %3 = upcast %1 : $B to $A
756+ br bb3(%3 : $A)
757+
758+ bb2:
759+ %5 = upcast %1 : $B to $A
760+ br bb3(%5 : $A)
761+
762+ bb3(%7 : $A):
763+ %8 = ref_element_addr %7 : $A, #A.prop0
764+ store %0 to %8 : $*Int64
765+ %10 = unchecked_ref_cast %7 : $A to $B
766+ %11 = ref_element_addr %10 : $B, #B.alsoProp0
767+ store %0 to %11 : $*Int64
768+ %99 = tuple ()
769+ return %99 : $()
770+ }
771+
772+ // Test a phi cycle where the phi itself is the root (there is no common phi reference).
773+ // CHECK-LABEL: @testRootPhiCycle
774+ // CHECK: ###For MemOp: %{{.*}} = load %{{.*}} : $*Double
775+ // CHECK: Storage: Tail %{{.*}} = argument of bb3 : $Builtin.BridgeObject
776+ // CHECK: Path: ()
777+ // CHECK: Exact Uses {
778+ // CHECK-NEXT: %{{.*}} = load %{{.*}} : $*Double
779+ // CHECK-NEXT: Path: ()
780+ // CHECK-NEXT: %{{.*}} = load %{{.*}} : $*Double
781+ // CHECK-NEXT: Path: ()
782+ // CHECK-NEXT: }
783+ // CHECK: ###For MemOp: %{{.*}} = load %{{.*}} : $*Double
784+ // CHECK: Storage: Tail %{{.*}} = argument of bb3 : $Builtin.BridgeObject
785+ // CHECK: Path: ()
786+ // CHECK: Exact Uses {
787+ // CHECK-NEXT: %{{.*}} = load %{{.*}} : $*Double
788+ // CHECK-NEXT: Path: ()
789+ // CHECK-NEXT: %{{.*}} = load %{{.*}} : $*Double
790+ // CHECK-NEXT: Path: ()
791+ // CHECK-NEXT: }
792+ sil @testRootPhiCycle : $@convention(thin) (Builtin.BridgeObject, Builtin.BridgeObject) -> () {
793+ bb0(%0 : $Builtin.BridgeObject, %1 : $Builtin.BridgeObject):
794+ cond_br undef, bb1, bb2
795+
796+ bb1:
797+ br bb3(%0 : $Builtin.BridgeObject)
798+
799+ bb2:
800+ br bb3(%1 : $Builtin.BridgeObject)
801+
802+ bb3(%820 : $Builtin.BridgeObject):
803+ %834 = unchecked_ref_cast %820 : $Builtin.BridgeObject to $C
804+ %844 = ref_tail_addr [immutable] %834 : $C, $Double
805+ %853 = load %844 : $*Double
806+ %943 = load %844 : $*Double
807+ cond_br undef, bb4, bb5
808+
809+ bb4:
810+ br bb3(%820 : $Builtin.BridgeObject)
811+
812+ bb5:
813+ %999 = tuple ()
814+ return %999 : $()
815+ }
816+
817+ class C {}
818+
819+ // Test a CoW mutation followed by a phi cycle.
820+ //
821+ // Note: FindReferenceRoot currently does not see past CoW mutation,
822+ // but probably should.
823+ // CHECK: @testCowMutationPhi
824+ // CHECK: ###For MemOp: (%{{.*}}, %{{.*}}) = begin_cow_mutation [native] %0 : $Builtin.BridgeObject
825+ // CHECK-NEXT: ###For MemOp: %{{.*}} = load %{{.*}} : $*Double
826+ // CHECK: Storage: Tail %{{.*}} = argument of bb3 : $Builtin.BridgeObject
827+ // CHECK: Path: ()
828+ // CHECK: Exact Uses {
829+ // CHECK-NEXT: %{{.*}} = load %{{.*}} : $*Double
830+ // CHECK-NEXT: Path: ()
831+ // CHECK-NEXT: %{{.*}} = load %{{.*}} : $*Double
832+ // CHECK-NEXT: Path: ()
833+ // CHECK-NEXT: }
834+ // CHECK: ###For MemOp: %{{.*}} = load %{{.*}} : $*Double
835+ // CHECK: Storage: Tail %{{.*}} = argument of bb3 : $Builtin.BridgeObject
836+ // CHECK: Path: ()
837+ // CHECK: Exact Uses {
838+ // CHECK-NEXT: %{{.*}} = load %{{.*}} : $*Double
839+ // CHECK-NEXT: Path: ()
840+ // CHECK-NEXT: %{{.*}} = load %{{.*}} : $*Double
841+ // CHECK-NEXT: Path: ()
842+ // CHECK-NEXT: }
843+ sil @testCowMutationPhi : $@convention(thin) (Builtin.BridgeObject) -> () {
844+ bb0(%0 : $Builtin.BridgeObject):
845+ cond_br undef, bb1, bb2
846+
847+ bb1:
848+ br bb3(%0 : $Builtin.BridgeObject)
849+
850+ bb2:
851+ (%3, %4) = begin_cow_mutation [native] %0 : $Builtin.BridgeObject
852+ %5 = end_cow_mutation [keep_unique] %4 : $Builtin.BridgeObject
853+ br bb3(%5 : $Builtin.BridgeObject)
854+
855+ bb3(%820 : $Builtin.BridgeObject):
856+ %834 = unchecked_ref_cast %820 : $Builtin.BridgeObject to $C
857+ %844 = ref_tail_addr [immutable] %834 : $C, $Double
858+ %853 = load %844 : $*Double
859+ %943 = load %844 : $*Double
860+ cond_br undef, bb4, bb5
861+
862+ bb4:
863+ br bb3(%820 : $Builtin.BridgeObject)
864+
865+ bb5:
866+ %999 = tuple ()
867+ return %999 : $()
868+ }
0 commit comments