@@ -147,9 +147,6 @@ static EnumElementDecl *getInjectEnumCaseTo(SILValue Addr) {
147
147
}
148
148
149
149
SILInstruction *SILCombiner::visitSwitchEnumAddrInst (SwitchEnumAddrInst *SEAI) {
150
- if (SEAI->getFunction ()->hasOwnership ())
151
- return nullptr ;
152
-
153
150
// Convert switch_enum_addr -> br
154
151
// if the only thing which writes to the address is an inject_enum_addr.
155
152
SILValue Addr = SEAI->getOperand ();
@@ -172,41 +169,66 @@ SILInstruction *SILCombiner::visitSwitchEnumAddrInst(SwitchEnumAddrInst *SEAI) {
172
169
// ->
173
170
// %value = load %ptr
174
171
// switch_enum %value
175
- SmallVector<std::pair<EnumElementDecl*, SILBasicBlock*>, 8 > Cases;
176
- for (int i = 0 , e = SEAI->getNumCases (); i < e; ++i)
172
+ //
173
+ // If we are using ownership, we perform a load_borrow right before the new
174
+ // switch_enum and end the borrow scope right afterwards.
175
+ Builder.setCurrentDebugScope (SEAI->getDebugScope ());
176
+ SmallVector<std::pair<EnumElementDecl *, SILBasicBlock *>, 8 > Cases;
177
+ for (int i : range (SEAI->getNumCases ())) {
177
178
Cases.push_back (SEAI->getCase (i));
179
+ }
178
180
179
- Builder.setCurrentDebugScope (SEAI->getDebugScope ());
180
181
SILBasicBlock *Default = SEAI->hasDefault () ? SEAI->getDefaultBB () : nullptr ;
181
- LoadInst *EnumVal = Builder.createLoad (SEAI->getLoc (), Addr,
182
- LoadOwnershipQualifier::Unqualified);
183
- Builder.createSwitchEnum (SEAI->getLoc (), EnumVal, Default, Cases);
182
+ SILValue EnumVal = Builder.emitLoadBorrowOperation (SEAI->getLoc (), Addr);
183
+ auto *sei = Builder.createSwitchEnum (SEAI->getLoc (), EnumVal, Default, Cases);
184
+
185
+ if (Builder.hasOwnership ()) {
186
+ for (int i : range (sei->getNumCases ())) {
187
+ auto c = sei->getCase (i);
188
+ if (c.first ->hasAssociatedValues ()) {
189
+ auto eltType = Addr->getType ().getEnumElementType (
190
+ c.first , Builder.getModule (), Builder.getTypeExpansionContext ());
191
+ eltType = eltType.getObjectType ();
192
+ if (eltType.isTrivial (Builder.getFunction ())) {
193
+ c.second ->createPhiArgument (eltType, OwnershipKind::None);
194
+ } else {
195
+ c.second ->createPhiArgument (eltType, OwnershipKind::Guaranteed);
196
+ }
197
+ }
198
+ Builder.setInsertionPoint (c.second ->front ().getIterator ());
199
+ Builder.emitEndBorrowOperation (SEAI->getLoc (), EnumVal);
200
+ }
201
+
202
+ if (auto defaultBlock = sei->getDefaultBBOrNull ()) {
203
+ defaultBlock.get ()->createPhiArgument (EnumVal->getType (),
204
+ OwnershipKind::Guaranteed);
205
+ Builder.setInsertionPoint (defaultBlock.get ()->front ().getIterator ());
206
+ Builder.emitEndBorrowOperation (SEAI->getLoc (), EnumVal);
207
+ }
208
+ }
209
+
184
210
return eraseInstFromFunction (*SEAI);
185
211
}
186
212
187
- SILInstruction *SILCombiner::visitSelectEnumAddrInst (SelectEnumAddrInst *SEAI) {
188
- if (SEAI->getFunction ()->hasOwnership ())
189
- return nullptr ;
190
-
213
+ SILInstruction *SILCombiner::visitSelectEnumAddrInst (SelectEnumAddrInst *seai) {
191
214
// Canonicalize a select_enum_addr: if the default refers to exactly one case,
192
215
// then replace the default with that case.
193
- Builder.setCurrentDebugScope (SEAI ->getDebugScope ());
194
- if (SEAI ->hasDefault ()) {
195
- NullablePtr<EnumElementDecl> elementDecl = SEAI ->getUniqueCaseForDefault ();
216
+ Builder.setCurrentDebugScope (seai ->getDebugScope ());
217
+ if (seai ->hasDefault ()) {
218
+ NullablePtr<EnumElementDecl> elementDecl = seai ->getUniqueCaseForDefault ();
196
219
if (elementDecl.isNonNull ()) {
197
220
// Construct a new instruction by copying all the case entries.
198
- SmallVector<std::pair<EnumElementDecl *, SILValue>, 4 > CaseValues ;
199
- for (int idx = 0 , numIdcs = SEAI ->getNumCases (); idx < numIdcs; ++idx) {
200
- CaseValues .push_back (SEAI ->getCase (idx));
221
+ SmallVector<std::pair<EnumElementDecl *, SILValue>, 4 > caseValues ;
222
+ for (int idx = 0 , numIdcs = seai ->getNumCases (); idx < numIdcs; ++idx) {
223
+ caseValues .push_back (seai ->getCase (idx));
201
224
}
202
225
// Add the default-entry of the original instruction as case-entry.
203
- CaseValues .push_back (
204
- std::make_pair (elementDecl.get (), SEAI ->getDefaultResult ()));
226
+ caseValues .push_back (
227
+ std::make_pair (elementDecl.get (), seai ->getDefaultResult ()));
205
228
206
- return Builder.createSelectEnumAddr (SEAI->getLoc (),
207
- SEAI->getEnumOperand (),
208
- SEAI->getType (), SILValue (),
209
- CaseValues);
229
+ return Builder.createSelectEnumAddr (
230
+ seai->getLoc (), seai->getEnumOperand (), seai->getType (), SILValue (),
231
+ caseValues);
210
232
}
211
233
}
212
234
@@ -215,63 +237,65 @@ SILInstruction *SILCombiner::visitSelectEnumAddrInst(SelectEnumAddrInst *SEAI) {
215
237
// ->
216
238
// %value = load %ptr
217
239
// = select_enum %value
218
- SILType Ty = SEAI ->getEnumOperand ()->getType ();
219
- if (!Ty .isLoadable (*SEAI ->getFunction ()))
240
+ SILType ty = seai ->getEnumOperand ()->getType ();
241
+ if (!ty .isLoadable (*seai ->getFunction ()))
220
242
return nullptr ;
221
243
222
- SmallVector<std::pair<EnumElementDecl*, SILValue>, 8 > Cases;
223
- for (int i = 0 , e = SEAI->getNumCases (); i < e; ++i)
224
- Cases.push_back (SEAI->getCase (i));
225
-
226
- SILValue Default = SEAI->hasDefault () ? SEAI->getDefaultResult () : SILValue ();
227
- LoadInst *EnumVal = Builder.createLoad (SEAI->getLoc (), SEAI->getEnumOperand (),
228
- LoadOwnershipQualifier::Unqualified);
229
- auto *I = Builder.createSelectEnum (SEAI->getLoc (), EnumVal, SEAI->getType (),
230
- Default, Cases);
231
- return I;
244
+ SmallVector<std::pair<EnumElementDecl *, SILValue>, 8 > cases;
245
+ for (int i = 0 , e = seai->getNumCases (); i < e; ++i)
246
+ cases.push_back (seai->getCase (i));
247
+
248
+ SILValue defaultCase =
249
+ seai->hasDefault () ? seai->getDefaultResult () : SILValue ();
250
+ auto enumVal =
251
+ Builder.emitLoadBorrowOperation (seai->getLoc (), seai->getEnumOperand ());
252
+ auto *result = Builder.createSelectEnum (seai->getLoc (), enumVal,
253
+ seai->getType (), defaultCase, cases);
254
+ Builder.emitEndBorrowOperation (seai->getLoc (), enumVal);
255
+ replaceInstUsesWith (*seai, result);
256
+ return eraseInstFromFunction (*seai);
232
257
}
233
258
234
- SILInstruction *SILCombiner::visitSwitchValueInst (SwitchValueInst *SVI) {
235
- if (SVI->getFunction ()->hasOwnership ())
259
+ SILInstruction *SILCombiner::visitSwitchValueInst (SwitchValueInst *svi) {
260
+ SILValue cond = svi->getOperand ();
261
+ BuiltinIntegerType *condTy = cond->getType ().getAs <BuiltinIntegerType>();
262
+ if (!condTy || !condTy->isFixedWidth (1 ))
236
263
return nullptr ;
237
264
238
- SILValue Cond = SVI->getOperand ();
239
- BuiltinIntegerType *CondTy = Cond->getType ().getAs <BuiltinIntegerType>();
240
- if (!CondTy || !CondTy->isFixedWidth (1 ))
241
- return nullptr ;
242
-
243
- SILBasicBlock *FalseBB = nullptr ;
244
- SILBasicBlock *TrueBB = nullptr ;
245
- for (unsigned Idx = 0 , Num = SVI->getNumCases (); Idx < Num; ++Idx) {
246
- auto Case = SVI->getCase (Idx);
247
- auto *CaseVal = dyn_cast<IntegerLiteralInst>(Case.first );
248
- if (!CaseVal)
265
+ SILBasicBlock *falseBB = nullptr ;
266
+ SILBasicBlock *trueBB = nullptr ;
267
+ for (unsigned idx : range (svi->getNumCases ())) {
268
+ auto switchCase = svi->getCase (idx);
269
+ auto *caseVal = dyn_cast<IntegerLiteralInst>(switchCase.first );
270
+ if (!caseVal)
249
271
return nullptr ;
250
- SILBasicBlock *DestBB = Case .second ;
251
- assert (DestBB ->args_empty () &&
272
+ SILBasicBlock *destBB = switchCase .second ;
273
+ assert (destBB ->args_empty () &&
252
274
" switch_value case destination cannot take arguments" );
253
- if (CaseVal ->getValue () == 0 ) {
254
- assert (!FalseBB && " double case value 0 in switch_value" );
255
- FalseBB = DestBB ;
275
+ if (caseVal ->getValue () == 0 ) {
276
+ assert (!falseBB && " double case value 0 in switch_value" );
277
+ falseBB = destBB ;
256
278
} else {
257
- assert (!TrueBB && " double case value 1 in switch_value" );
258
- TrueBB = DestBB ;
279
+ assert (!trueBB && " double case value 1 in switch_value" );
280
+ trueBB = destBB ;
259
281
}
260
282
}
261
- if (SVI->hasDefault ()) {
262
- assert (SVI->getDefaultBB ()->args_empty () &&
283
+
284
+ if (svi->hasDefault ()) {
285
+ assert (svi->getDefaultBB ()->args_empty () &&
263
286
" switch_value default destination cannot take arguments" );
264
- if (!FalseBB ) {
265
- FalseBB = SVI ->getDefaultBB ();
266
- } else if (!TrueBB ) {
267
- TrueBB = SVI ->getDefaultBB ();
287
+ if (!falseBB ) {
288
+ falseBB = svi ->getDefaultBB ();
289
+ } else if (!trueBB ) {
290
+ trueBB = svi ->getDefaultBB ();
268
291
}
269
292
}
270
- if (!FalseBB || !TrueBB)
293
+
294
+ if (!falseBB || !trueBB)
271
295
return nullptr ;
272
296
273
- Builder.setCurrentDebugScope (SVI ->getDebugScope ());
274
- return Builder.createCondBranch (SVI ->getLoc (), Cond, TrueBB, FalseBB );
297
+ Builder.setCurrentDebugScope (svi ->getDebugScope ());
298
+ return Builder.createCondBranch (svi ->getLoc (), cond, trueBB, falseBB );
275
299
}
276
300
277
301
namespace {
@@ -759,12 +783,13 @@ SILInstruction *SILCombiner::optimizeLoadFromStringLiteral(LoadInst *LI) {
759
783
760
784
// / Returns true if \p LI loads a zero integer from the empty Array, Dictionary
761
785
// / or Set singleton.
762
- static bool isZeroLoadFromEmptyCollection (LoadInst *LI) {
786
+ static bool isZeroLoadFromEmptyCollection (SingleValueInstruction *LI) {
787
+ assert (isa<LoadInst>(LI) || isa<LoadBorrowInst>(LI));
763
788
auto intTy = LI->getType ().getAs <BuiltinIntegerType>();
764
789
if (!intTy)
765
790
return false ;
766
-
767
- SILValue addr = LI->getOperand ();
791
+
792
+ SILValue addr = LI->getOperand (0 );
768
793
769
794
// Find the root object of the load-address.
770
795
for (;;) {
@@ -805,6 +830,8 @@ static bool isZeroLoadFromEmptyCollection(LoadInst *LI) {
805
830
case ValueKind::UpcastInst:
806
831
case ValueKind::RawPointerToRefInst:
807
832
case ValueKind::AddressToPointerInst:
833
+ case ValueKind::BeginBorrowInst:
834
+ case ValueKind::CopyValueInst:
808
835
case ValueKind::EndCOWMutationInst:
809
836
addr = cast<SingleValueInstruction>(addr)->getOperand (0 );
810
837
break ;
@@ -839,15 +866,56 @@ static SingleValueInstruction *getValueFromStaticLet(SILValue v) {
839
866
return nullptr ;
840
867
}
841
868
842
- SILInstruction *SILCombiner::visitLoadInst (LoadInst *LI) {
843
- if (LI->getFunction ()->hasOwnership ())
869
+ SILInstruction *SILCombiner::visitLoadBorrowInst (LoadBorrowInst *lbi) {
870
+ // (load (upcast-ptr %x)) -> (upcast-ref (load %x))
871
+ Builder.setCurrentDebugScope (lbi->getDebugScope ());
872
+ if (auto *ui = dyn_cast<UpcastInst>(lbi->getOperand ())) {
873
+ // We want to RAUW the current load_borrow with the upcast. To do that
874
+ // safely, we need to insert new end_borrow on the new load_borrow, erase
875
+ // the end_borrow and then RAUW.
876
+ SmallVector<EndBorrowInst *, 32 > endBorrowInst;
877
+ for (auto *ebi : lbi->getEndBorrows ())
878
+ endBorrowInst.push_back (ebi);
879
+ auto newLBI = Builder.createLoadBorrow (lbi->getLoc (), ui->getOperand ());
880
+ for (auto *ebi : endBorrowInst) {
881
+ SILBuilderWithScope builder (ebi, Builder);
882
+ builder.emitEndBorrowOperation (ebi->getLoc (), newLBI);
883
+ eraseInstFromFunction (*ebi);
884
+ }
885
+ auto *uci = Builder.createUpcast (lbi->getLoc (), newLBI, lbi->getType ());
886
+ replaceInstUsesWith (*lbi, uci);
887
+ return eraseInstFromFunction (*lbi);
888
+ }
889
+
890
+ // Constant-propagate the 0 value when loading "count" or "capacity" from the
891
+ // empty Array, Set or Dictionary storage.
892
+ // On high-level SIL this optimization is also done by the
893
+ // ArrayCountPropagation pass, but only for Array. And even for Array it's
894
+ // sometimes needed to propagate the empty-array count when high-level
895
+ // semantics function are already inlined.
896
+ // Note that for non-empty arrays/sets/dictionaries, the count can be
897
+ // propagated by redundant load elimination.
898
+ if (isZeroLoadFromEmptyCollection (lbi))
899
+ return Builder.createIntegerLiteral (lbi->getLoc (), lbi->getType (), 0 );
900
+
901
+ // If we have a load_borrow that only has non_debug end_borrow uses, delete
902
+ // it.
903
+ if (llvm::all_of (getNonDebugUses (lbi), [](Operand *use) {
904
+ return isa<EndBorrowInst>(use->getUser ());
905
+ })) {
906
+ eraseInstIncludingUsers (lbi);
844
907
return nullptr ;
908
+ }
909
+
910
+ return nullptr ;
911
+ }
845
912
913
+ SILInstruction *SILCombiner::visitLoadInst (LoadInst *LI) {
846
914
// (load (upcast-ptr %x)) -> (upcast-ref (load %x))
847
915
Builder.setCurrentDebugScope (LI->getDebugScope ());
848
916
if (auto *UI = dyn_cast<UpcastInst>(LI->getOperand ())) {
849
- auto NewLI = Builder.createLoad (LI->getLoc (), UI->getOperand (),
850
- LoadOwnershipQualifier::Unqualified );
917
+ auto NewLI = Builder.emitLoadValueOperation (LI->getLoc (), UI->getOperand (),
918
+ LI-> getOwnershipQualifier () );
851
919
return Builder.createUpcast (LI->getLoc (), NewLI, LI->getType ());
852
920
}
853
921
@@ -874,6 +942,17 @@ SILInstruction *SILCombiner::visitLoadInst(LoadInst *LI) {
874
942
return cloner.clone (initVal);
875
943
}
876
944
945
+ // If we have a load [copy] whose only non-debug users are destroy_value, just
946
+ // eliminate it.
947
+ if (LI->getOwnershipQualifier () == LoadOwnershipQualifier::Copy) {
948
+ if (llvm::all_of (getNonDebugUses (LI), [](Operand *use) {
949
+ return isa<DestroyValueInst>(use->getUser ());
950
+ })) {
951
+ eraseInstIncludingUsers (LI);
952
+ return nullptr ;
953
+ }
954
+ }
955
+
877
956
return nullptr ;
878
957
}
879
958
0 commit comments