Skip to content

Commit fbe38ce

Browse files
committed
Fix EscapeAnalysis losing precision during merge.
Array storage was being stack promoted even though it escaped. This happened because multiple locally allocated arrays were merged into the same locally allocated array value box. For this to become a problem, other bizarre merge events need to take place, such as a value node being mapped with a content node. The series of events led to a missing edge in the connection graph. One of the arrays was mapped directly to a project_box instruction which had forgotten it's relationship with the alloc_box. It is a trivial one line fix to simply preserve all value mappings. <rdar://58371330> app crashes (miscompile)
1 parent 9c4d0c0 commit fbe38ce

File tree

2 files changed

+7
-47
lines changed

2 files changed

+7
-47
lines changed

lib/SILOptimizer/Analysis/EscapeAnalysis.cpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -732,9 +732,13 @@ void EscapeAnalysis::ConnectionGraph::mergeAllScheduledNodes() {
732732
From->isMerged = true;
733733

734734
if (From->mappedValue) {
735-
if (To->mappedValue)
736-
Values2Nodes.erase(From->mappedValue);
737-
else {
735+
// If possible, transfer 'From's mappedValue to 'To' for clarity. Any
736+
// values previously mapped to 'From' but not transferred to 'To's
737+
// mappedValue must remain mapped to 'From'. Lookups on those values will
738+
// find 'To' via the mergeTarget. Dropping a value's mapping is illegal
739+
// because it could cause a node to be recreated without the edges that
740+
// have already been discovered.
741+
if (!To->mappedValue) {
738742
To->mappedValue = From->mappedValue;
739743
Values2Nodes[To->mappedValue] = To;
740744
}

test/SILOptimizer/escape_analysis.sil

Lines changed: 0 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1817,47 +1817,3 @@ bb0(%0 : $IntWrapper):
18171817
%tuple = tuple (%bridge : $Builtin.BridgeObject, %ump : $UnsafeMutablePointer<Int64>)
18181818
return %tuple : $(Builtin.BridgeObject, UnsafeMutablePointer<Int64>)
18191819
}
1820-
1821-
// =============================================================================
1822-
// Test call to array.uninitialized that has extra release_value uses
1823-
1824-
class DummyArrayStorage<Element> {
1825-
@_hasStorage var count: Int { get }
1826-
@_hasStorage var capacity: Int { get }
1827-
init()
1828-
}
1829-
1830-
// init_any_array_with_buffer
1831-
sil [_semantics "array.uninitialized"] @init_any_array_with_buffer : $@convention(thin) (@owned DummyArrayStorage<AnyObject>, Int32, @thin Array<AnyObject>.Type) -> (@owned Array<AnyObject>, UnsafeMutablePointer<AnyObject>)
1832-
1833-
// CHECK-LABEL: CG of testBadArrayUninit
1834-
// CHECK-NEXT: Val [ref] %2 Esc: , Succ: (%2.1)
1835-
// CHECK-NEXT: Con [int] %2.1 Esc: G, Succ: (%2.2)
1836-
// CHECK-NEXT: Con [ref] %2.2 Esc: G, Succ:
1837-
// CHECK-NEXT: Val %5 Esc: , Succ: (%5.1)
1838-
// CHECK-NEXT: Con %5.1 Esc: G, Succ: %10
1839-
// CHECK-NEXT: Val [ref] %10 Esc: G, Succ: (%10.1)
1840-
// CHECK-NEXT: Con %10.1 Esc: G, Succ:
1841-
// CHECK-LABEL: End
1842-
sil hidden @testBadArrayUninit : $@convention(thin) (Builtin.Word, Int32) -> () {
1843-
bb0(%0 : $Builtin.Word, %1 : $Int32):
1844-
// create an array
1845-
%2 = alloc_ref [tail_elems $AnyObject * %0 : $Builtin.Word] $DummyArrayStorage<AnyObject>
1846-
%3 = metatype $@thin Array<AnyObject>.Type
1847-
%4 = function_ref @init_any_array_with_buffer : $@convention(thin) (@owned DummyArrayStorage<AnyObject>, Int32, @thin Array<AnyObject>.Type) -> (@owned Array<AnyObject>, UnsafeMutablePointer<AnyObject>)
1848-
%5 = apply %4(%2, %1, %3) : $@convention(thin) (@owned DummyArrayStorage<AnyObject>, Int32, @thin Array<AnyObject>.Type) -> (@owned Array<AnyObject>, UnsafeMutablePointer<AnyObject>)
1849-
%6 = tuple_extract %5 : $(Array<AnyObject>, UnsafeMutablePointer<AnyObject>), 0
1850-
%7 = tuple_extract %5 : $(Array<AnyObject>, UnsafeMutablePointer<AnyObject>), 1
1851-
%8 = struct_extract %7 : $UnsafeMutablePointer<AnyObject>, #UnsafeMutablePointer._rawValue
1852-
%9 = pointer_to_address %8 : $Builtin.RawPointer to [strict] $*AnyObject
1853-
1854-
// store an elt
1855-
%10 = alloc_ref $C
1856-
%11 = init_existential_ref %10 : $C : $C, $AnyObject
1857-
store %11 to %9 : $*AnyObject
1858-
1859-
// extra use of the call
1860-
release_value %5 : $(Array<AnyObject>, UnsafeMutablePointer<AnyObject>) // id: %228
1861-
%13 = tuple ()
1862-
return %13 : $()
1863-
}

0 commit comments

Comments
 (0)