@@ -110,18 +110,10 @@ EscapeAnalysis::findCachedPointerKind(SILType Ty, const SILFunction &F) const {
110110 return pointerKind;
111111}
112112
113- static bool isExtractOfArrayUninitializedPointer (TupleExtractInst *TEI) {
114- if (auto apply = dyn_cast<ApplyInst>(TEI->getOperand ()))
115- if (ArraySemanticsCall (apply, " array.uninitialized" , false ))
116- return true ;
117-
118- return false ;
119- }
120-
121113// If EscapeAnalysis should consider the given value to be a derived address or
122114// pointer based on one of its address or pointer operands, then return that
123115// operand value. Otherwise, return an invalid value.
124- SILValue EscapeAnalysis::getPointerBase (SILValue value) const {
116+ SILValue EscapeAnalysis::getPointerBase (SILValue value) {
125117 switch (value->getKind ()) {
126118 case ValueKind::IndexAddrInst:
127119 case ValueKind::IndexRawPointerInst:
@@ -156,10 +148,8 @@ SILValue EscapeAnalysis::getPointerBase(SILValue value) const {
156148 case ValueKind::TupleExtractInst: {
157149 auto *TEI = cast<TupleExtractInst>(value);
158150 // Special handling for extracting the pointer-result from an
159- // array construction. We handle this like a ref_element_addr
160- // rather than a projection. See the handling of tuple_extract
161- // in analyzeInstruction().
162- if (isExtractOfArrayUninitializedPointer (TEI))
151+ // array construction. See createArrayUninitializedSubgraph.
152+ if (canOptimizeArrayUninitializedResult (TEI))
163153 return SILValue ();
164154 return TEI->getOperand ();
165155 }
@@ -188,7 +178,7 @@ SILValue EscapeAnalysis::getPointerBase(SILValue value) const {
188178// Recursively find the given value's pointer base. If the value cannot be
189179// represented in EscapeAnalysis as one of its operands, then return the same
190180// value.
191- SILValue EscapeAnalysis::getPointerRoot (SILValue value) const {
181+ SILValue EscapeAnalysis::getPointerRoot (SILValue value) {
192182 while (true ) {
193183 if (SILValue v2 = getPointerBase (value))
194184 value = v2;
@@ -1721,28 +1711,6 @@ void EscapeAnalysis::buildConnectionGraph(FunctionInfo *FInfo,
17211711 << FInfo->Graph .F ->getName () << ' \n ' );
17221712}
17231713
1724- // / Returns the tuple extract for the first two fields if all uses of \p I are
1725- // / tuple_extract instructions.
1726- static std::pair<TupleExtractInst *, TupleExtractInst *>
1727- onlyUsedInTupleExtract (SILValue V) {
1728- TupleExtractInst *field0 = nullptr ;
1729- TupleExtractInst *field1 = nullptr ;
1730- for (Operand *Use : getNonDebugUses (V)) {
1731- if (auto *TEI = dyn_cast<TupleExtractInst>(Use->getUser ())) {
1732- if (TEI->getFieldNo () == 0 ) {
1733- field0 = TEI;
1734- continue ;
1735- }
1736- if (TEI->getFieldNo () == 1 ) {
1737- field1 = TEI;
1738- continue ;
1739- }
1740- }
1741- return std::make_pair (nullptr , nullptr );
1742- }
1743- return std::make_pair (field0, field1);
1744- }
1745-
17461714bool EscapeAnalysis::buildConnectionGraphForCallees (
17471715 SILInstruction *Caller, CalleeList Callees, FunctionInfo *FInfo,
17481716 FunctionOrder &BottomUpOrder, int RecursionDepth) {
@@ -1799,38 +1767,79 @@ bool EscapeAnalysis::buildConnectionGraphForDestructor(
17991767 RecursionDepth);
18001768}
18011769
1802- // Handle array.uninitialized
1803- bool EscapeAnalysis::createArrayUninitializedSubgraph (
1804- FullApplySite apply, ConnectionGraph *conGraph) {
1770+ EscapeAnalysis::ArrayUninitCall
1771+ EscapeAnalysis::canOptimizeArrayUninitializedCall (ApplyInst *ai,
1772+ ConnectionGraph *conGraph) {
1773+ ArrayUninitCall call;
1774+ // This must be an exact match so we don't accidentally optimize
1775+ // "array.uninitialized_intrinsic".
1776+ if (!ArraySemanticsCall (ai, " array.uninitialized" , false ))
1777+ return call;
18051778
18061779 // Check if the result is used in the usual way: extracting the
18071780 // array and the element pointer with tuple_extract.
1808- TupleExtractInst *arrayStruct;
1809- TupleExtractInst *arrayElementPtr;
1810- std::tie (arrayStruct, arrayElementPtr) =
1811- onlyUsedInTupleExtract (cast<ApplyInst>(apply.getInstruction ()));
1812- if (!arrayStruct || !arrayElementPtr)
1781+ for (Operand *use : getNonDebugUses (ai)) {
1782+ if (auto *tei = dyn_cast<TupleExtractInst>(use->getUser ())) {
1783+ if (tei->getFieldNo () == 0 ) {
1784+ call.arrayStruct = tei;
1785+ continue ;
1786+ }
1787+ if (tei->getFieldNo () == 1 ) {
1788+ call.arrayElementPtr = tei;
1789+ continue ;
1790+ }
1791+ }
1792+ // If there are any other uses, such as a release_value, erase the previous
1793+ // call info and bail out.
1794+ call.arrayStruct = nullptr ;
1795+ call.arrayElementPtr = nullptr ;
1796+ break ;
1797+ }
1798+ // An "array.uninitialized" call may have a first argument which is the
1799+ // allocated array buffer. Make sure the call's argument is recognized by
1800+ // EscapeAnalysis as a pointer, otherwise createArrayUninitializedSubgraph
1801+ // won't be able to map the result nodes onto it. There is a variant of
1802+ // @_semantics("array.uninitialized") that does not take the storage as input,
1803+ // so it will effectively bail out here.
1804+ if (isPointer (ai->getArgument (0 )))
1805+ call.arrayStorageRef = ai->getArgument (0 );
1806+ return call;
1807+ }
1808+
1809+ bool EscapeAnalysis::canOptimizeArrayUninitializedResult (
1810+ TupleExtractInst *tei) {
1811+ ApplyInst *ai = dyn_cast<ApplyInst>(tei->getOperand ());
1812+ if (!ai)
18131813 return false ;
18141814
1815- // array.uninitialized may have a first argument which is the
1816- // allocated array buffer. The call is like a struct(buffer)
1817- // instruction.
1818- CGNode *arrayRefNode = conGraph->getNode (apply.getArgument (0 ));
1819- if (!arrayRefNode)
1820- return false ;
1815+ auto *conGraph = getConnectionGraph (ai->getFunction ());
1816+ return canOptimizeArrayUninitializedCall (ai, conGraph).isValid ();
1817+ }
18211818
1822- CGNode *arrayStructNode = conGraph->getNode (arrayStruct);
1819+ // Handle @_semantics("array.uninitialized")
1820+ //
1821+ // This call is analagous to a 'struct(storageRef)' instruction--we want a defer
1822+ // edge from the returned Array struct to the storage Reference that it
1823+ // contains.
1824+ //
1825+ // The returned unsafe pointer is handled simply by mapping the pointer value
1826+ // onto the object node that the storage argument points to.
1827+ void EscapeAnalysis::createArrayUninitializedSubgraph (
1828+ ArrayUninitCall call, ConnectionGraph *conGraph) {
1829+ CGNode *arrayStructNode = conGraph->getNode (call.arrayStruct );
18231830 assert (arrayStructNode && " Array struct must have a node" );
18241831
1825- CGNode *arrayObjNode = conGraph->getValueContent (apply.getArgument (0 ));
1832+ CGNode *arrayRefNode = conGraph->getNode (call.arrayStorageRef );
1833+ assert (arrayRefNode && " canOptimizeArrayUninitializedCall checks isPointer" );
1834+ // If the arrayRefNode != null then arrayObjNode must be valid.
1835+ CGNode *arrayObjNode = conGraph->getValueContent (call.arrayStorageRef );
18261836
18271837 // The reference argument is effectively stored inside the returned
1828- // array struct.
1838+ // array struct. This is like struct(arrayRefNode).
18291839 conGraph->defer (arrayStructNode, arrayRefNode);
18301840
18311841 // Map the returned element pointer to the array object's field pointer.
1832- conGraph->setNode (arrayElementPtr, arrayObjNode);
1833- return true ;
1842+ conGraph->setNode (call.arrayElementPtr , arrayObjNode);
18341843}
18351844
18361845void EscapeAnalysis::analyzeInstruction (SILInstruction *I,
@@ -1852,10 +1861,15 @@ void EscapeAnalysis::analyzeInstruction(SILInstruction *I,
18521861 case ArrayCallKind::kMakeMutable :
18531862 // These array semantics calls do not capture anything.
18541863 return ;
1855- case ArrayCallKind::kArrayUninitialized :
1856- if (createArrayUninitializedSubgraph (FAS, ConGraph))
1864+ case ArrayCallKind::kArrayUninitialized : {
1865+ ArrayUninitCall call = canOptimizeArrayUninitializedCall (
1866+ cast<ApplyInst>(FAS.getInstruction ()), ConGraph);
1867+ if (call.isValid ()) {
1868+ createArrayUninitializedSubgraph (call, ConGraph);
18571869 return ;
1870+ }
18581871 break ;
1872+ }
18591873 case ArrayCallKind::kGetElement :
18601874 if (CGNode *ArrayObjNode = ConGraph->getValueContent (ASC.getSelf ())) {
18611875 CGNode *LoadedElement = nullptr ;
@@ -2204,13 +2218,9 @@ void EscapeAnalysis::analyzeInstruction(SILInstruction *I,
22042218 case SILInstructionKind::TupleExtractInst: {
22052219 // This is a tuple_extract which extracts the second result of an
22062220 // array.uninitialized call (otherwise getPointerBase should have already
2207- // looked through it). The first result is the array itself. The second
2208- // result (which is a pointer to the array elements) must be the content
2209- // node of the first result. It's just like a ref_element_addr
2210- // instruction. It is mapped to a node when processing
2211- // array.uninitialized.
2221+ // looked through it).
22122222 auto *TEI = cast<TupleExtractInst>(I);
2213- assert (isExtractOfArrayUninitializedPointer (TEI)
2223+ assert (canOptimizeArrayUninitializedResult (TEI)
22142224 && " tuple_extract should be handled as projection" );
22152225 return ;
22162226 }
0 commit comments