Skip to content

Commit 75e7583

Browse files
committed
AliasAnalysis: fix the memory behavior of end_borrow
Checking if an access base is derived from a begin-borrow was too optimistic. We have to bail for instructions which are not handled by the walker utilities. Fixes a verifier crash. rdar://139788357
1 parent 5ab0385 commit 75e7583

File tree

3 files changed

+140
-1
lines changed

3 files changed

+140
-1
lines changed

SwiftCompilerSources/Sources/Optimizer/Analysis/AliasAnalysis.swift

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -696,11 +696,23 @@ private struct FindBeginBorrowWalker : ValueUseDefWalker {
696696
if value == beginBorrow {
697697
return .abortWalk
698698
}
699+
if value.ownership != .guaranteed {
700+
// If value is owned then it cannot be the borrowed value.
701+
return .continueWalk
702+
}
699703
return walkUpDefault(value: value, path: path)
700704
}
701705

702706
mutating func rootDef(value: Value, path: SmallProjectionPath) -> WalkResult {
703-
return .continueWalk
707+
switch value {
708+
case is FunctionArgument,
709+
// Loading a value from memory cannot be the borrowed value.
710+
// Note that we exclude the "regular" `load` by checking for guaranteed ownership in `walkUp`.
711+
is LoadBorrowInst:
712+
return .continueWalk
713+
default:
714+
return .abortWalk
715+
}
704716
}
705717
}
706718

test/SILOptimizer/load-copy-to-borrow.sil

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,17 @@ final class Klass {
5252

5353
class C {}
5454

55+
class Base {
56+
@_hasStorage var c: C
57+
}
58+
59+
class Derived : Base {
60+
}
61+
62+
class Container {
63+
@_hasStorage var b: Base
64+
}
65+
5566
struct OptionalAndClass {
5667
var o: FakeOptional<C>
5768
var c: C
@@ -78,6 +89,9 @@ sil @use_inguaranteed : $@convention(thin) (@in_guaranteed Klass) -> ()
7889
sil @guaranteed_fakeoptional_klass_user : $@convention(thin) (@guaranteed FakeOptional<Klass>) -> ()
7990
sil @guaranteed_fakeoptional_classlet_user : $@convention(thin) (@guaranteed FakeOptional<ClassLet>) -> ()
8091
sil @closure : $@convention(thin) (@inout_aliasable Klass) -> ()
92+
sil @useC : $@convention(thin) (@guaranteed C) -> () {
93+
[global:]
94+
}
8195

8296
struct MyInt {
8397
var value: Builtin.Int32
@@ -2008,3 +2022,21 @@ bb5:
20082022
return %r : $()
20092023
}
20102024

2025+
// CHECK-LABEL: sil [ossa] @blocked_by_end_borrow :
2026+
// CHECK: %7 = load [copy] %6
2027+
// CHECK: } // end sil function 'blocked_by_end_borrow'
2028+
sil [ossa] @blocked_by_end_borrow : $@convention(thin) (@guaranteed Container) -> () {
2029+
bb0(%0 : @guaranteed $Container):
2030+
%1 = function_ref @useC : $@convention(thin) (@guaranteed C) -> ()
2031+
%2 = ref_element_addr [immutable] %0 : $Container, #Container.b
2032+
%3 = load_borrow %2 : $*Base
2033+
%4 = unconditional_checked_cast %3 : $Base to Derived
2034+
%5 = upcast %4 : $Derived to $Base
2035+
%6 = ref_element_addr [immutable] %5 : $Base, #Base.c
2036+
%7 = load [copy] %6 : $*C
2037+
end_borrow %3 : $Base
2038+
%9 = apply %1(%7) : $@convention(thin) (@guaranteed C) -> ()
2039+
destroy_value %7 : $C
2040+
return %9 : $()
2041+
}
2042+

test/SILOptimizer/mem-behavior.sil

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1462,6 +1462,101 @@ bb0(%0 : @guaranteed $X):
14621462
return %5 : $Int32
14631463
}
14641464

1465+
// CHECK-LABEL: @test_end_borrow3
1466+
// CHECK: PAIR #3.
1467+
// CHECK-NEXT: end_borrow %6 : $X
1468+
// CHECK-NEXT: %3 = ref_element_addr %2 : $X, #X.x
1469+
// CHECK-NEXT: r=0,w=0
1470+
// CHECK: PAIR #4.
1471+
// CHECK-NEXT: end_borrow %6 : $X
1472+
// CHECK-NEXT: %4 = ref_element_addr %0 : $X, #X.x
1473+
// CHECK-NEXT: r=0,w=0
1474+
// CHECK: PAIR #5.
1475+
// CHECK-NEXT: end_borrow %6 : $X
1476+
// CHECK-NEXT: %7 = ref_element_addr %6 : $X, #X.x
1477+
// CHECK-NEXT: r=1,w=1
1478+
// CHECK: PAIR #6.
1479+
// CHECK-NEXT: end_borrow %2 : $X
1480+
// CHECK-NEXT: %3 = ref_element_addr %2 : $X, #X.x
1481+
// CHECK-NEXT: r=1,w=1
1482+
// CHECK: PAIR #7.
1483+
// CHECK-NEXT: end_borrow %2 : $X
1484+
// CHECK-NEXT: %4 = ref_element_addr %0 : $X, #X.x
1485+
// CHECK-NEXT: r=0,w=0
1486+
// CHECK: PAIR #8.
1487+
// CHECK-NEXT: end_borrow %2 : $X
1488+
// CHECK-NEXT: %7 = ref_element_addr %6 : $X, #X.x
1489+
// CHECK-NEXT: r=0,w=0
1490+
sil [ossa] @test_end_borrow3 : $@convention(thin) (@guaranteed X, @owned X) -> @owned (X, X) {
1491+
bb0(%0 : @guaranteed $X, %1 : @owned $X):
1492+
%2 = begin_borrow %1 : $X
1493+
%3 = ref_element_addr %2 : $X, #X.x
1494+
%4 = ref_element_addr %0 : $X, #X.x
1495+
%5 = copy_value %2 : $X
1496+
%6 = begin_borrow %5 : $X
1497+
%7 = ref_element_addr %6 : $X, #X.x
1498+
end_borrow %6 : $X
1499+
end_borrow %2 : $X
1500+
%r = tuple (%5 : $X, %1 : $X)
1501+
return %r : $(X, X)
1502+
}
1503+
1504+
// CHECK-LABEL: @test_end_borrow4
1505+
// CHECK: PAIR #4.
1506+
// CHECK-NEXT: end_borrow %3 : $X
1507+
// CHECK-NEXT: %4 = ref_element_addr %3 : $X, #X.x
1508+
// CHECK-NEXT: r=1,w=1
1509+
// CHECK: PAIR #5.
1510+
// CHECK-NEXT: end_borrow %3 : $X
1511+
// CHECK-NEXT: %8 = ref_element_addr %7 : $X, #X.x
1512+
// CHECK-NEXT: r=0,w=0
1513+
// CHECK: PAIR #10.
1514+
// CHECK-NEXT: end_borrow %7 : $X
1515+
// CHECK-NEXT: %4 = ref_element_addr %3 : $X, #X.x
1516+
// CHECK-NEXT: r=0,w=0
1517+
// CHECK: PAIR #11.
1518+
// CHECK-NEXT: end_borrow %7 : $X
1519+
// CHECK-NEXT: %8 = ref_element_addr %7 : $X, #X.x
1520+
// CHECK-NEXT: r=1,w=1
1521+
// CHECK: PAIR #13.
1522+
// CHECK-NEXT: end_borrow %2 : $X
1523+
// CHECK-NEXT: %4 = ref_element_addr %3 : $X, #X.x
1524+
// CHECK-NEXT: r=0,w=0
1525+
// CHECK: PAIR #14.
1526+
// CHECK-NEXT: end_borrow %2 : $X
1527+
// CHECK-NEXT: %8 = ref_element_addr %7 : $X, #X.x
1528+
// CHECK-NEXT: r=0,w=0
1529+
sil [ossa] @test_end_borrow4 : $@convention(thin) (@guaranteed X, @in_guaranteed X) -> @owned X {
1530+
bb0(%0 : @guaranteed $X, %1 : $*X):
1531+
%2 = begin_borrow %0 : $X
1532+
%3 = load_borrow %1 : $*X
1533+
%4 = ref_element_addr %3 : $X, #X.x
1534+
end_borrow %3 : $X
1535+
%6 = load [copy] %1 : $*X
1536+
%7 = begin_borrow %6 : $X
1537+
%8 = ref_element_addr %7 : $X, #X.x
1538+
end_borrow %7 : $X
1539+
end_borrow %2 : $X
1540+
return %6 : $X
1541+
}
1542+
1543+
// CHECK-LABEL: @test_end_borrow5
1544+
// CHECK: PAIR #3.
1545+
// CHECK-NEXT: end_borrow %2 : $X
1546+
// CHECK-NEXT: %5 = ref_element_addr [immutable] %4 : $X, #X.x
1547+
// CHECK-NEXT: r=1,w=1
1548+
sil [ossa] @test_end_borrow5 : $@convention(thin) (@guaranteed X) -> () {
1549+
bb0(%0 : @guaranteed $X):
1550+
%1 = ref_element_addr [immutable] %0 : $X, #X.x
1551+
%2 = load_borrow %1 : $*X
1552+
%3 = unconditional_checked_cast %2 : $X to Derived
1553+
%4 = upcast %3 : $Derived to $X
1554+
%5 = ref_element_addr [immutable] %4 : $X, #X.x
1555+
end_borrow %2 : $X
1556+
%7 = tuple ()
1557+
return %7 : $()
1558+
}
1559+
14651560
// CHECK-LABEL: @test_load_borrow
14661561
// CHECK: PAIR #0.
14671562
// CHECK-NEXT: %1 = load_borrow %0 : $*X

0 commit comments

Comments
 (0)