@@ -106,23 +106,91 @@ SILCombiner::visitAllocExistentialBoxInst(AllocExistentialBoxInst *AEBI) {
106
106
return nullptr ;
107
107
}
108
108
109
+ // / Return the enum case injected by an inject_enum_addr if it is the only
110
+ // / instruction which writes to \p Addr.
111
+ static EnumElementDecl *getInjectEnumCaseTo (SILValue Addr) {
112
+ while (true ) {
113
+ // For everything else than an alloc_stack we cannot easily prove that we
114
+ // see all writes.
115
+ if (!isa<AllocStackInst>(Addr))
116
+ return nullptr ;
117
+
118
+ SILInstruction *WritingInst = nullptr ;
119
+ int NumWrites = 0 ;
120
+ for (auto *Use : getNonDebugUses (Addr)) {
121
+ SILInstruction *User = Use->getUser ();
122
+ switch (User->getKind ()) {
123
+ // Handle a very narrow set of known not harmful instructions.
124
+ case swift::SILInstructionKind::DestroyAddrInst:
125
+ case swift::SILInstructionKind::DeallocStackInst:
126
+ case swift::SILInstructionKind::SwitchEnumAddrInst:
127
+ break ;
128
+ case swift::SILInstructionKind::ApplyInst:
129
+ case swift::SILInstructionKind::TryApplyInst: {
130
+ // Check if the addr is only passed to in_guaranteed arguments.
131
+ FullApplySite AI (User);
132
+ for (Operand &Op : AI.getArgumentOperands ()) {
133
+ if (Op.get () == Addr &&
134
+ AI.getArgumentConvention (Op) !=
135
+ SILArgumentConvention::Indirect_In_Guaranteed)
136
+ return nullptr ;
137
+ }
138
+ break ;
139
+ }
140
+ case swift::SILInstructionKind::InjectEnumAddrInst:
141
+ WritingInst = User;
142
+ ++NumWrites;
143
+ break ;
144
+ case swift::SILInstructionKind::CopyAddrInst:
145
+ if (Addr == cast<CopyAddrInst>(User)->getDest ()) {
146
+ WritingInst = User;
147
+ ++NumWrites;
148
+ }
149
+ break ;
150
+ default :
151
+ return nullptr ;
152
+ }
153
+ }
154
+ if (NumWrites != 1 )
155
+ return nullptr ;
156
+ if (auto *IEA = dyn_cast<InjectEnumAddrInst>(WritingInst))
157
+ return IEA->getElement ();
158
+
159
+ // In case of a copy_addr continue with the source of the copy.
160
+ Addr = dyn_cast<CopyAddrInst>(WritingInst)->getSrc ();
161
+ }
162
+ }
163
+
109
164
SILInstruction *SILCombiner::visitSwitchEnumAddrInst (SwitchEnumAddrInst *SEAI) {
165
+ // Convert switch_enum_addr -> br
166
+ // if the only thing which writes to the address is an inject_enum_addr.
167
+ SILValue Addr = SEAI->getOperand ();
168
+ if (EnumElementDecl *EnumCase = getInjectEnumCaseTo (Addr)) {
169
+ SILBasicBlock *Dest = SEAI->getCaseDestination (EnumCase);
170
+ // If the only instruction which writes to Addr is an inject_enum_addr we
171
+ // know that there cannot be an enum payload.
172
+ assert (Dest->getNumArguments () == 0 &&
173
+ " didn't expect a payload argument" );
174
+ Builder.createBranch (SEAI->getLoc (), Dest);
175
+ return eraseInstFromFunction (*SEAI);
176
+ }
177
+
178
+ SILType Ty = Addr->getType ();
179
+ if (!Ty.isLoadable (SEAI->getModule ()))
180
+ return nullptr ;
181
+
110
182
// Promote switch_enum_addr to switch_enum if the enum is loadable.
111
183
// switch_enum_addr %ptr : $*Optional<SomeClass>, case ...
112
184
// ->
113
185
// %value = load %ptr
114
186
// switch_enum %value
115
- SILType Ty = SEAI->getOperand ()->getType ();
116
- if (!Ty.isLoadable (SEAI->getModule ()))
117
- return nullptr ;
118
-
119
187
SmallVector<std::pair<EnumElementDecl*, SILBasicBlock*>, 8 > Cases;
120
188
for (int i = 0 , e = SEAI->getNumCases (); i < e; ++i)
121
189
Cases.push_back (SEAI->getCase (i));
122
190
123
191
Builder.setCurrentDebugScope (SEAI->getDebugScope ());
124
192
SILBasicBlock *Default = SEAI->hasDefault () ? SEAI->getDefaultBB () : nullptr ;
125
- LoadInst *EnumVal = Builder.createLoad (SEAI->getLoc (), SEAI-> getOperand () ,
193
+ LoadInst *EnumVal = Builder.createLoad (SEAI->getLoc (), Addr ,
126
194
LoadOwnershipQualifier::Unqualified);
127
195
Builder.createSwitchEnum (SEAI->getLoc (), EnumVal, Default, Cases);
128
196
return eraseInstFromFunction (*SEAI);
0 commit comments