Skip to content

Commit 6ee4c17

Browse files
authored
Merge pull request #62573 from meg-gupta/sbiverify
Update store_borrow checking in MemoryLifetimeVerifier and fix ForEachLoopUnroll and GenericCloner
2 parents e833657 + 4dccf76 commit 6ee4c17

File tree

9 files changed

+53
-59
lines changed

9 files changed

+53
-59
lines changed

include/swift/SIL/SILInstruction.h

Lines changed: 0 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -4368,47 +4368,7 @@ class EndBorrowInst
43684368
EndBorrowInst(SILDebugLocation debugLoc, SILValue borrowedValue)
43694369
: UnaryInstructionBase(debugLoc, borrowedValue) {}
43704370

4371-
public:
4372-
/// Return the value that this end_borrow is ending the borrow of if we are
4373-
/// borrowing a single value.
4374-
SILValue getSingleOriginalValue() const {
4375-
SILValue v = getOperand();
4376-
if (auto *bbi = dyn_cast<BeginBorrowInst>(v))
4377-
return bbi->getOperand();
4378-
if (auto *lbi = dyn_cast<LoadBorrowInst>(v))
4379-
return lbi->getOperand();
4380-
return SILValue();
4381-
}
43824371

4383-
/// Return the set of guaranteed values that have scopes ended by this
4384-
/// end_borrow.
4385-
///
4386-
/// Discussion: We can only have multiple values associated with an end_borrow
4387-
/// in the case of having Phi arguments with guaranteed inputs. This is
4388-
/// necessary to represent certain conditional operations such as:
4389-
///
4390-
/// class Klass {
4391-
/// let k1: Klass
4392-
/// let k2: Klass
4393-
/// }
4394-
///
4395-
/// func useKlass(k: Klass) { ... }
4396-
/// var boolValue : Bool { ... }
4397-
///
4398-
/// func f(k: Klass) {
4399-
/// useKlass(boolValue ? k.k1 : k.k2)
4400-
/// }
4401-
///
4402-
/// Today, when we SILGen such code, we copy k.k1 and k.k2 before the Phi when
4403-
/// it could potentially be avoided. So today this just appends
4404-
/// getSingleOriginalValue() to originalValues.
4405-
///
4406-
/// TODO: Once this changes, this code must be update.
4407-
void getOriginalValues(SmallVectorImpl<SILValue> &originalValues) const {
4408-
SILValue value = getSingleOriginalValue();
4409-
assert(value && "Guaranteed phi arguments are not supported now");
4410-
originalValues.emplace_back(value);
4411-
}
44124372
};
44134373

44144374
/// Different kinds of access.

lib/IRGen/IRGenModule.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1871,6 +1871,7 @@ bool IRGenModule::canMakeStaticObjectsReadOnly() {
18711871
// rdar://101126543
18721872
return false;
18731873

1874+
#if 0
18741875
if (getOptions().DisableReadonlyStaticObjects)
18751876
return false;
18761877

@@ -1881,6 +1882,7 @@ bool IRGenModule::canMakeStaticObjectsReadOnly() {
18811882

18821883
return getAvailabilityContext().isContainedIn(
18831884
Context.getImmortalRefCountSymbolsAvailability());
1885+
#endif
18841886
}
18851887

18861888
void IRGenerator::addGenModule(SourceFile *SF, IRGenModule *IGM) {

lib/SIL/Verifier/MemoryLifetimeVerifier.cpp

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -377,6 +377,13 @@ void MemoryLifetimeVerifier::initDataflowInBlock(SILBasicBlock *block,
377377
}
378378
break;
379379
}
380+
case SILInstructionKind::EndBorrowInst: {
381+
auto *ebi = cast<EndBorrowInst>(&I);
382+
if (auto *sbi = dyn_cast<StoreBorrowInst>(ebi->getOperand())) {
383+
killBits(state, sbi->getDest());
384+
}
385+
break;
386+
}
380387
case SILInstructionKind::DestroyAddrInst:
381388
case SILInstructionKind::DeallocStackInst:
382389
killBits(state, I.getOperand(0));
@@ -696,8 +703,13 @@ void MemoryLifetimeVerifier::checkBlock(SILBasicBlock *block, Bits &bits) {
696703
break;
697704
}
698705
case SILInstructionKind::EndBorrowInst: {
699-
if (SILValue orig = cast<EndBorrowInst>(&I)->getSingleOriginalValue())
700-
requireBitsSet(bits, orig, &I);
706+
auto *ebi = cast<EndBorrowInst>(&I);
707+
if (auto *sbi = dyn_cast<StoreBorrowInst>(ebi->getOperand())) {
708+
requireBitsSet(bits, sbi->getDest(), &I);
709+
locations.clearBits(bits, sbi->getDest());
710+
} else if (auto *lbi = dyn_cast<LoadBorrowInst>(ebi->getOperand())) {
711+
requireBitsSet(bits, lbi->getOperand(), &I);
712+
}
701713
break;
702714
}
703715
case SILInstructionKind::UncheckedRefCastAddrInst:
@@ -779,11 +791,7 @@ void MemoryLifetimeVerifier::checkBlock(SILBasicBlock *block, Bits &bits) {
779791
}
780792
case SILInstructionKind::DeallocStackInst: {
781793
SILValue opVal = cast<DeallocStackInst>(&I)->getOperand();
782-
if (isStoreBorrowLocation(opVal)) {
783-
requireBitsSet(bits, opVal, &I);
784-
} else {
785-
requireBitsClear(bits & nonTrivialLocations, opVal, &I);
786-
}
794+
requireBitsClear(bits & nonTrivialLocations, opVal, &I);
787795
// Needed to clear any bits of trivial locations (which are not required
788796
// to be zero).
789797
locations.clearBits(bits, opVal);

lib/SILOptimizer/LoopTransforms/ForEachLoopUnroll.cpp

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -538,6 +538,7 @@ static void unrollForEach(ArrayInfo &arrayInfo, TryApplyInst *forEachCall,
538538
SILBasicBlock *currentBB = num > 1 ? normalTargetGenerator(nextNormalBB)
539539
: forEachCall->getParentBlock();
540540
SILBuilderWithScope unrollBuilder(currentBB, forEachCall);
541+
SILBuilderWithScope normalBuilder(&nextNormalBB->front(), forEachCall);
541542
SILValue borrowedElem;
542543
SILValue addr;
543544

@@ -552,9 +553,8 @@ static void unrollForEach(ArrayInfo &arrayInfo, TryApplyInst *forEachCall,
552553
borrowedElem = unrollBuilder.createBeginBorrow(forEachLoc, elementCopy);
553554
addr =
554555
unrollBuilder.createStoreBorrow(forEachLoc, borrowedElem, allocStack);
555-
SILBuilderWithScope builder(&nextNormalBB->front(), forEachCall);
556-
builder.createEndBorrow(forEachLoc, addr);
557-
builder.createEndBorrow(forEachLoc, borrowedElem);
556+
normalBuilder.createEndBorrow(forEachLoc, addr);
557+
normalBuilder.createEndBorrow(forEachLoc, borrowedElem);
558558
}
559559

560560
SILBasicBlock *errorTarget =
@@ -566,16 +566,18 @@ static void unrollForEach(ArrayInfo &arrayInfo, TryApplyInst *forEachCall,
566566
unrollBuilder.createTryApply(forEachLoc, forEachBodyClosure,
567567
SubstitutionMap(), addr, nextNormalBB,
568568
errorTarget);
569+
570+
if (nextNormalBB == normalBB) {
571+
// Dealloc the stack in the normalBB and also in errorBB. Note that every
572+
// try_apply created during the unrolling must pass through these blocks.
573+
normalBuilder.createDeallocStack(forEachLoc, allocStack);
574+
}
569575
nextNormalBB = currentBB;
570576
}
571-
572577
// Dealloc the stack in the normalBB and also in errorBB. Note that every
573578
// try_apply created during the unrolling must pass through these blocks.
574-
SILBuilderWithScope(&normalBB->front())
575-
.createDeallocStack(forEachLoc, allocStack);
576579
SILBuilderWithScope(&errorBB->front())
577580
.createDeallocStack(forEachLoc, allocStack);
578-
579581
// Remove the forEach call as it has now been unrolled.
580582
removeForEachCall(forEachCall, deleter);
581583
}

lib/SILOptimizer/Utils/GenericCloner.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -255,8 +255,9 @@ void GenericCloner::postFixUp(SILFunction *f) {
255255
scopedAddress.endScopeAtLivenessBoundary(&storeBorrowLiveness);
256256
continue;
257257
}
258-
for (auto *exit : FunctionExits) {
259-
scopedAddress.createScopeEnd(exit->getIterator(),
258+
auto *alloc = cast<AllocStackInst>(sbi->getDest());
259+
for (auto *dealloc : alloc->getUsersOfType<DeallocStackInst>()) {
260+
scopedAddress.createScopeEnd(dealloc->getIterator(),
260261
RegularLocation::getAutoGeneratedLocation());
261262
}
262263
}

test/SIL/memory_lifetime_failures.sil

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -373,6 +373,17 @@ bb0(%0 : @guaranteed $Optional<T>):
373373
return %res : $()
374374
}
375375

376+
// CHECK: SIL memory lifetime failure in @test_store_borrow_addr_after_dealloc: memory is initialized, but shouldn't be
377+
sil [ossa] @test_store_borrow_addr_after_dealloc : $@convention(thin) (@guaranteed Optional<T>) -> () {
378+
bb0(%0 : @guaranteed $Optional<T>):
379+
%s = alloc_stack $Optional<T>
380+
%sb = store_borrow %0 to %s : $*Optional<T>
381+
dealloc_stack %s : $*Optional<T>
382+
end_borrow %sb : $*Optional<T>
383+
%res = tuple ()
384+
return %res : $()
385+
}
386+
376387
// CHECK: SIL memory lifetime failure in @test_cast_br_take_always: memory is not initialized, but should be
377388
sil [ossa] @test_cast_br_take_always : $@convention(thin) <U, V> (@in U) -> () {
378389
bb0(%0 : $*U):

test/SIL/store_borrow_verify_errors.sil

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
// RUN: %target-sil-opt -verify-continue-on-failure -enable-sil-verify-all=0 %s -o /dev/null 2>&1 | %FileCheck %s
1+
// RUN: %target-sil-opt -dont-abort-on-memory-lifetime-errors -verify-continue-on-failure -enable-sil-verify-all=0 %s -o /dev/null 2>&1 | %FileCheck %s
2+
3+
// Memory lifetime verifier also raises errors in some of these cases, add dont-abort-on-memory-lifetime-errors so that we don't check it's output.
4+
// Memory lifetime verifier cannot subsume this because the verification is disabled on unreachable paths.
25

36
import Builtin
47

test/SILOptimizer/for_each_loop_unroll_test.sil

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,8 +134,8 @@ bb2(%39 : @owned $Error):
134134
// CHECK: br [[ERROR3:bb[0-9]+]]([[ERRPARAM2]] : $any Error)
135135

136136
// CHECK: [[NORMAL2]](%{{.*}} : $()):
137-
// CHECK: dealloc_stack [[STACK]]
138137
// CHECK: end_borrow [[ELEM2BORROW]]
138+
// CHECK: dealloc_stack [[STACK]]
139139
// Note that the temporary alloc_stack of the array created for the forEach call
140140
// will be cleaned up when the forEach call is removed.
141141
// CHECK: destroy_value

test/SILOptimizer/specialize_ossa.sil

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,14 @@ bb0(%0 : $Builtin.NativeObject):
3232
return %9999 : $()
3333
}
3434

35+
// CHECK-LABEL: sil shared [noinline] [ossa] @$s33XXX_foo_guaranteed_generic_returnBo_Tg5 :
36+
// CHECK: [[S1:%.*]] = alloc_stack $Builtin.NativeObject
37+
// CHECK: [[S2:%.*]] = alloc_stack $Builtin.NativeObject
38+
// CHECK: [[SBI:%.*]] = store_borrow %0 to [[S2]] : $*Builtin.NativeObject
39+
// CHECK: end_borrow [[SBI]] : $*Builtin.NativeObject
40+
// CHECK: dealloc_stack [[S2]] : $*Builtin.NativeObject
41+
// CHECK-LABEL: } // end sil function '$s33XXX_foo_guaranteed_generic_returnBo_Tg5'
42+
3543
// CHECK-LABEL: sil [ossa] @exp1 : $@convention(thin) () -> () {
3644
// CHECK-NOT: apply
3745
// Call of specialized initializer: <Int32>
@@ -115,7 +123,6 @@ bb0(%0 : $*T, %1 : $*XXX<T>):
115123
return %9 : $Int32 // id: %11
116124
}
117125

118-
119126
sil [ossa] [noinline] @XXX_foo_guaranteed_generic_return : $@convention(method) <T> (@in_guaranteed T, @in XXX<T>) -> @out T {
120127
bb0(%0 : $*T, %1 : $*T, %2 : $*XXX<T>):
121128
%3 = address_to_pointer %1 : $*T to $Builtin.RawPointer

0 commit comments

Comments
 (0)