Skip to content

Commit d5b98a0

Browse files
authored
Merge pull request #16116 from rajbarik/global_addr
Handle global_addr for concrete type propagation
2 parents e2f3e6d + 612d771 commit d5b98a0

File tree

2 files changed

+192
-0
lines changed

2 files changed

+192
-0
lines changed

lib/SILOptimizer/SILCombiner/SILCombinerApplyVisitors.cpp

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -600,6 +600,51 @@ SILCombiner::optimizeConcatenationOfStringLiterals(ApplyInst *AI) {
600600
return tryToConcatenateStrings(AI, Builder);
601601
}
602602

603+
/// Determine the pattern for global_addr.
604+
/// %3 = global_addr @$P : $*SomeP
605+
/// %4 = init_existential_addr %3 : $*SomeP, $SomeC
606+
/// %5 = alloc_ref $SomeC
607+
/// store %5 to %4 : $*SomeC
608+
/// %8 = alloc_stack $SomeP
609+
/// copy_addr %3 to [initialization] %8 : $*SomeP
610+
/// %9 = open_existential_addr immutable_access %8 : $*SomeP to $*@opened SomeP
611+
static SILValue findInitExistentialFromGlobalAddr(GlobalAddrInst *GAI,
612+
CopyAddrInst *CAI) {
613+
assert(CAI->getSrc() == SILValue(GAI) &&
614+
"Broken Assumption! Global Addr is not the source of the passed in "
615+
"copy_addr?!");
616+
617+
/// Check for a single InitExistential usage for GAI and
618+
/// a simple dominance check: both InitExistential and CAI are in
619+
/// the same basic block and only one InitExistential
620+
/// occurs between GAI and CAI.
621+
llvm::SmallPtrSet<SILInstruction *, 8> IEUses;
622+
for (auto *Use : GAI->getUses()) {
623+
if (auto *InitExistential =
624+
dyn_cast<InitExistentialAddrInst>(Use->getUser())) {
625+
IEUses.insert(InitExistential);
626+
}
627+
}
628+
629+
/// No InitExistential found in the basic block.
630+
if (IEUses.empty())
631+
return SILValue();
632+
633+
/// Walk backwards from CAI instruction till the begining of the basic block
634+
/// looking for InitExistential.
635+
SILValue SingleIE;
636+
for (auto II = CAI->getIterator().getReverse(), IE = CAI->getParent()->rend();
637+
II != IE; ++II) {
638+
if (!IEUses.count(&*II))
639+
continue;
640+
if (SingleIE)
641+
return SILValue();
642+
643+
SingleIE = cast<InitExistentialAddrInst>(&*II);
644+
}
645+
return SingleIE;
646+
}
647+
603648
/// Returns the address of an object with which the stack location \p ASI is
604649
/// initialized. This is either a init_existential_addr or the destination of a
605650
/// copy_addr. Returns a null value if the address does not dominate the
@@ -666,6 +711,10 @@ static SILValue getAddressOfStackInit(AllocStackInst *ASI,
666711
SILValue CAISrc = CAI->getSrc();
667712
if (auto *ASI = dyn_cast<AllocStackInst>(CAISrc))
668713
return getAddressOfStackInit(ASI, CAI, isCopied);
714+
// Check if the CAISrc is a global_addr.
715+
if (auto *GAI = dyn_cast<GlobalAddrInst>(CAISrc)) {
716+
return findInitExistentialFromGlobalAddr(GAI, CAI);
717+
}
669718
return CAISrc;
670719
}
671720
return cast<InitExistentialAddrInst>(SingleWrite);
Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
// RUN: %target-sil-opt -assume-parsing-unqualified-ownership-sil -enforce-exclusivity=none -enable-sil-verify-all %s -sil-combine -verify-skip-unreachable-must-be-last -devirtualizer | %FileCheck %s
2+
3+
// Test to see if concrete type can be propagated from
4+
// global_addr in sil_combiner.
5+
sil_stage canonical
6+
7+
import Builtin
8+
import Swift
9+
protocol SomeProtocol {
10+
func foo() -> Int
11+
}
12+
class SomeClass : SomeProtocol {
13+
init()
14+
func foo() -> Int
15+
}
16+
sil hidden [thunk] [always_inline] @foo_ : $@convention(witness_method:SomeProtocol) (@in_guaranteed SomeClass) -> Int {
17+
bb0(%0 : $*SomeClass):
18+
%1 = load %0 : $*SomeClass
19+
%2 = class_method %1 : $SomeClass, #SomeClass.foo!1 : (SomeClass) -> () -> Int, $@convention(method) (@guaranteed SomeClass) -> Int
20+
%3 = apply %2(%1) : $@convention(method) (@guaranteed SomeClass) -> Int
21+
return %3 : $Int
22+
}
23+
sil hidden [thunk] [always_inline] @foo : $@convention(method) (@guaranteed SomeClass) -> Int {
24+
bb0(%0: $SomeClass):
25+
%1 = integer_literal $Builtin.Int64, 10
26+
%2 = struct $Int (%1 : $Builtin.Int64)
27+
return %2 : $Int
28+
}
29+
sil_global hidden [let] @$global_var : $SomeProtocol
30+
31+
// CHECK-LABEL: sil @witness_global_addr
32+
// CHECK: bb0
33+
// CHECK: alloc_global
34+
// CHECK: global_addr
35+
// CHECK: init_existential_addr
36+
// CHECK: alloc_ref
37+
// CHECK: store
38+
// CHECK: function_ref
39+
// CHECK: apply
40+
// CHECK: return
41+
// CHECK: } // end sil function 'witness_global_addr'
42+
sil @witness_global_addr : $@convention(thin) () -> Int {
43+
bb0:
44+
alloc_global @$global_var
45+
%3 = global_addr @$global_var : $*SomeProtocol
46+
%4 = init_existential_addr %3 : $*SomeProtocol, $SomeClass
47+
%5 = alloc_ref $SomeClass
48+
store %5 to %4 : $*SomeClass
49+
%8 = alloc_stack $SomeProtocol
50+
copy_addr %3 to [initialization] %8 : $*SomeProtocol
51+
%9 = open_existential_addr immutable_access %8 : $*SomeProtocol to $*@opened("1B0A5B84-3441-11E8-AC03-DCA9048B1C6D") SomeProtocol
52+
%10 = witness_method $@opened("1B0A5B84-3441-11E8-AC03-DCA9048B1C6D") SomeProtocol, #SomeProtocol.foo!1 : <Self where Self : SomeProtocol> (Self) -> () -> Int, %9 : $*@opened("1B0A5B84-3441-11E8-AC03-DCA9048B1C6D") SomeProtocol : $@convention(witness_method: SomeProtocol) <τ_0_0 where τ_0_0 : SomeProtocol> (@in_guaranteed τ_0_0) -> Int
53+
%11 = apply %10<@opened("1B0A5B84-3441-11E8-AC03-DCA9048B1C6D") SomeProtocol>(%9) : $@convention(witness_method: SomeProtocol) <τ_0_0 where τ_0_0 : SomeProtocol> (@in_guaranteed τ_0_0) -> Int
54+
destroy_addr %8 : $*SomeProtocol
55+
dealloc_stack %8 : $*SomeProtocol
56+
return %11 : $Int
57+
}
58+
59+
// CHECK-LABEL: sil @witness_global_addr_fail_1
60+
// CHECK: bb0
61+
// CHECK: alloc_global
62+
// CHECK: global_addr
63+
// CHECK: bb1
64+
// CHECK: init_existential_addr
65+
// CHECK: bb2
66+
// CHECK: init_existential_addr
67+
// CHECK: bb3
68+
// CHECK: alloc_ref
69+
// CHECK: store
70+
// CHECK: alloc_stack
71+
// CHECK: copy_addr
72+
// CHECK: witness_method
73+
// CHECK: apply
74+
// CHECK: destroy_addr
75+
// CHECK: dealloc_stack
76+
// CHECK: return
77+
// CHECK: } // end sil function 'witness_global_addr_fail_1'
78+
sil @witness_global_addr_fail_1: $@convention(thin) (Builtin.Int1) -> Int {
79+
bb0(%0 : $Builtin.Int1):
80+
alloc_global @$global_var
81+
%3 = global_addr @$global_var : $*SomeProtocol
82+
cond_br %0, bb1, bb2
83+
bb1:
84+
%4 = init_existential_addr %3 : $*SomeProtocol, $SomeClass
85+
br bb3(%4 : $*SomeClass)
86+
bb2:
87+
%5 = init_existential_addr %3 : $*SomeProtocol, $SomeClass
88+
br bb3(%5 : $*SomeClass)
89+
bb3(%6 : $*SomeClass):
90+
%7 = alloc_ref $SomeClass
91+
store %7 to %6 : $*SomeClass
92+
%8 = alloc_stack $SomeProtocol
93+
copy_addr %3 to [initialization] %8 : $*SomeProtocol
94+
%9 = open_existential_addr immutable_access %8 : $*SomeProtocol to $*@opened("1B0A5B84-3441-11E8-AC03-DCA9048B1C6D") SomeProtocol
95+
%10 = witness_method $@opened("1B0A5B84-3441-11E8-AC03-DCA9048B1C6D") SomeProtocol, #SomeProtocol.foo!1 : <Self where Self : SomeProtocol> (Self) -> () -> Int, %9 : $*@opened("1B0A5B84-3441-11E8-AC03-DCA9048B1C6D") SomeProtocol : $@convention(witness_method: SomeProtocol) <τ_0_0 where τ_0_0 : SomeProtocol> (@in_guaranteed τ_0_0) -> Int
96+
%11 = apply %10<@opened("1B0A5B84-3441-11E8-AC03-DCA9048B1C6D") SomeProtocol>(%9) : $@convention(witness_method: SomeProtocol) <τ_0_0 where τ_0_0 : SomeProtocol> (@in_guaranteed τ_0_0) -> Int
97+
destroy_addr %8 : $*SomeProtocol
98+
dealloc_stack %8 : $*SomeProtocol
99+
return %11 : $Int
100+
}
101+
102+
// CHECK-LABEL: sil @witness_global_addr_fail_2
103+
// CHECK: bb0
104+
// CHECK: alloc_global
105+
// CHECK: global_addr
106+
// CHECK: init_existential_addr
107+
// CHECK: alloc_ref
108+
// CHECK: store
109+
// CHECK: init_existential_addr
110+
// CHECK: alloc_stack
111+
// CHECK: copy_addr
112+
// CHECK: open_existential_addr
113+
// CHECK: witness_method
114+
// CHECK: apply
115+
// CHECK: destroy_addr
116+
// CHECK: dealloc_stack
117+
// CHECK: return
118+
// CHECK: } // end sil function 'witness_global_addr_fail_2'
119+
sil @witness_global_addr_fail_2 : $@convention(thin) () -> Int {
120+
bb0:
121+
alloc_global @$global_var
122+
%3 = global_addr @$global_var : $*SomeProtocol
123+
%4 = init_existential_addr %3 : $*SomeProtocol, $SomeClass
124+
%5 = alloc_ref $SomeClass
125+
store %5 to %4 : $*SomeClass
126+
%6 = init_existential_addr %3 : $*SomeProtocol, $SomeClass
127+
%8 = alloc_stack $SomeProtocol
128+
copy_addr %3 to [initialization] %8 : $*SomeProtocol
129+
%9 = open_existential_addr immutable_access %8 : $*SomeProtocol to $*@opened("1B0A5B84-3441-11E8-AC03-DCA9048B1C6D") SomeProtocol
130+
%10 = witness_method $@opened("1B0A5B84-3441-11E8-AC03-DCA9048B1C6D") SomeProtocol, #SomeProtocol.foo!1 : <Self where Self : SomeProtocol> (Self) -> () -> Int, %9 : $*@opened("1B0A5B84-3441-11E8-AC03-DCA9048B1C6D") SomeProtocol : $@convention(witness_method: SomeProtocol) <τ_0_0 where τ_0_0 : SomeProtocol> (@in_guaranteed τ_0_0) -> Int
131+
%11 = apply %10<@opened("1B0A5B84-3441-11E8-AC03-DCA9048B1C6D") SomeProtocol>(%9) : $@convention(witness_method: SomeProtocol) <τ_0_0 where τ_0_0 : SomeProtocol> (@in_guaranteed τ_0_0) -> Int
132+
destroy_addr %8 : $*SomeProtocol
133+
dealloc_stack %8 : $*SomeProtocol
134+
return %11 : $Int
135+
}
136+
137+
sil_vtable SomeClass {
138+
#SomeClass.foo!1: (SomeClass) -> () -> Int : @foo
139+
}
140+
141+
sil_witness_table hidden SomeClass: SomeProtocol module test {
142+
method #SomeProtocol.foo!1: <Self where Self : SomeProtocol> (Self) -> () -> Int : @foo_
143+
}

0 commit comments

Comments
 (0)