@@ -353,36 +353,45 @@ private struct CallSiteSpecializer {
353353 var directResults = resultInstruction. results. makeIterator ( )
354354 var substitutedResultTupleElements = [ any Value ] ( )
355355 var mappedResultPacks = self . callee. resultMap. makeIterator ( )
356+ var indirectResultIterator = self . apply. indirectResultOperands. makeIterator ( )
356357
357358 for resultInfo in self . apply. functionConvention. results {
358359 // We only need to handle direct and pack results, since indirect results are handled above
359360 if !resultInfo. isSILIndirect {
360361 // Direct results of the original function are mapped to direct results of the specialized function.
361362 substitutedResultTupleElements. append ( directResults. next ( ) !)
362363
363- } else if resultInfo. type. shouldExplode {
364- // Some elements of pack results may get mapped to direct results of the specialized function.
365- // We handle those here.
366- let mapped = mappedResultPacks. next ( ) !
367-
368- let originalPackArgument = self . apply. arguments [ mapped. argumentIndex]
369- let packIndices = packArgumentIndices [ mapped. argumentIndex] !
370-
371- for (mappedDirectResult, ( packIndex, elementType) ) in zip (
372- mapped. expandedElements, zip ( packIndices, originalPackArgument. type. packElements)
373- )
374- where !mappedDirectResult. isSILIndirect
375- {
376-
377- let result = directResults. next ( ) !
378- let outputResultAddress = builder. createPackElementGet (
379- packIndex: packIndex, pack: originalPackArgument,
380- elementType: elementType)
381-
382- builder. createStore (
383- source: result, destination: outputResultAddress,
384- // The callee is responsible for initializing return pack elements
385- ownership: storeOwnership ( for: result, normal: . initialize) )
364+ } else {
365+ guard let indirectResult = indirectResultIterator. next ( ) ? . value,
366+ indirectResult. type. shouldExplode
367+ else {
368+ continue
369+ }
370+
371+ do {
372+ // Some elements of pack results may get mapped to direct results of the specialized function.
373+ // We handle those here.
374+ let mapped = mappedResultPacks. next ( ) !
375+
376+
377+ let packIndices = packArgumentIndices [ mapped. argumentIndex] !
378+
379+ for (mappedDirectResult, ( packIndex, elementType) ) in zip (
380+ mapped. expandedElements, zip ( packIndices, indirectResult. type. packElements)
381+ )
382+ where !mappedDirectResult. isSILIndirect
383+ {
384+
385+ let result = directResults. next ( ) !
386+ let outputResultAddress = builder. createPackElementGet (
387+ packIndex: packIndex, pack: indirectResult,
388+ elementType: elementType)
389+
390+ builder. createStore (
391+ source: result, destination: outputResultAddress,
392+ // The callee is responsible for initializing return pack elements
393+ ownership: storeOwnership ( for: result, normal: . initialize) )
394+ }
386395 }
387396 }
388397 }
@@ -499,6 +508,14 @@ private struct PackExplodedFunction {
499508 /// Index of this pack in the function's result type tuple.
500509 /// For a non-tuple result, this is 0.
501510 let resultIndex : Int
511+ /// ResultInfo for the results produced by exploding the original result.
512+ ///
513+ /// NOTE: The expandedElements members of MappedResult & MappedParameter
514+ /// correspond to slices of the [ResultInfo] and [ParameterInfo] arrays
515+ /// produced at the same time as the ResultMap & ParameterMap respectively.
516+ /// Replacing these members with integer ranges or spans referring to those
517+ /// full arrays could be an easy performance optimization if this pass
518+ /// becomes a bottleneck.
502519 let expandedElements : [ ResultInfo ]
503520 }
504521
@@ -510,6 +527,7 @@ private struct PackExplodedFunction {
510527 /// order.
511528 struct MappedParameter {
512529 let argumentIndex : Int
530+ /// ParameterInfo for the parameters produced by exploding the original parameter.
513531 let expandedElements : [ ParameterInfo ]
514532 }
515533
@@ -600,10 +618,9 @@ private struct PackExplodedFunction {
600618
601619 for (argument, parameterInfo) in zip ( function. parameters, function. convention. parameters) {
602620 if argument. type. shouldExplode {
603-
604621 let mappedParameterInfos = argument. type. packElements. map { element in
605622 ParameterInfo (
606- type: element. canonicalType,
623+ type: element. hasArchetype ? element . rawType . mapOutOfEnvironment ( ) . canonical : element . canonicalType,
607624 convention: explodedPackElementArgumentConvention (
608625 pack: parameterInfo, type: element, in: function) ,
609626 options: parameterInfo. options,
@@ -631,36 +648,42 @@ private struct PackExplodedFunction {
631648 var resultMap = ResultMap ( )
632649 var newResults = [ ResultInfo] ( )
633650
634- var indirectResultIdx = 0
635- for (resultIndex, resultInfo) in function. convention. results. enumerated ( ) {
636- let silType = resultInfo. type. loweredType ( in: function)
637- if silType. shouldExplode {
638- let mappedResultInfos = silType. packElements. map { elem in
639- // TODO: Determine correct values for options and hasLoweredAddress
640- ResultInfo (
641- type: elem. canonicalType,
642- convention: explodedPackElementResultConvention ( in: function, type: elem) ,
643- options: resultInfo. options,
644- hasLoweredAddresses: resultInfo. hasLoweredAddresses)
645- }
651+ var indirectResultIterator = function. arguments [ 0 ..< function. convention. indirectSILResultCount]
652+ . lazy. enumerated ( ) . makeIterator ( )
646653
647- resultMap. append (
648- MappedResult (
649- argumentIndex: indirectResultIdx, resultIndex: resultIndex,
650- expandedElements: mappedResultInfos) )
651- newResults += mappedResultInfos
652- } else {
653- // Leave the original result unchanged
654+ for (resultIndex, resultInfo) in function. convention. results. enumerated ( ) {
655+ assert (
656+ !resultInfo. isSILIndirect || !indirectResultIterator. isEmpty,
657+ " There must be exactly as many indirect results in the function convention and argument list. "
658+ )
659+
660+ guard resultInfo. isSILIndirect,
661+ // There should always be a value here (expressed by the assert above).
662+ let ( indirectResultIdx, indirectResult) = indirectResultIterator. next ( ) ,
663+ indirectResult. type. shouldExplode
664+ else {
654665 newResults. append ( resultInfo)
666+ continue
655667 }
656668
657- if resultInfo. isSILIndirect {
658- indirectResultIdx += 1
669+ let mappedResultInfos = indirectResult. type. packElements. map { element in
670+ ResultInfo (
671+ type: element. hasArchetype ? element. rawType. mapOutOfEnvironment ( ) . canonical : element. canonicalType,
672+ convention: explodedPackElementResultConvention ( in: function, type: element) ,
673+ options: resultInfo. options,
674+ hasLoweredAddresses: resultInfo. hasLoweredAddresses)
659675 }
676+
677+ resultMap. append (
678+ MappedResult (
679+ argumentIndex: indirectResultIdx, resultIndex: resultIndex,
680+ expandedElements: mappedResultInfos) )
681+ newResults += mappedResultInfos
682+
660683 }
661684
662685 assert (
663- indirectResultIdx == function . argumentConventions . firstParameterIndex ,
686+ indirectResultIterator . isEmpty ,
664687 " We should have walked through all the indirect results, and no further. " )
665688
666689 return ( newResults, resultMap)
@@ -726,31 +749,36 @@ private struct PackExplodedFunction {
726749 let originalValue = originalReturn. returnedValue
727750
728751 let originalReturnTupleElements : [ Value ]
729- if originalValue. type. isTuple {
752+ if originalValue. type. isVoid {
753+ originalReturnTupleElements = [ ]
754+ } else if originalValue. type. isTuple {
730755 originalReturnTupleElements = [ Value] (
731756 builder. createDestructureTuple ( tuple: originalValue) . results)
732757 } else {
733758 originalReturnTupleElements = [ originalValue]
734759 }
735760
736- var returnValues = [ any Value ] ( )
737-
738761 // Thread together the original and exploded direct return values.
739- var resultMapIndex = 0
740- var originalReturnIndex = 0
741- for (i, originalResult) in self . original. convention. results. enumerated ( )
742- where originalResult. type. shouldExplode
743- || !originalResult. isSILIndirect
744- {
745- if !resultMap. indices. contains ( resultMapIndex) || resultMap [ resultMapIndex] . resultIndex != i {
746- returnValues. append ( originalReturnTupleElements [ originalReturnIndex] )
747- originalReturnIndex += 1
748-
749- } else {
762+ let theReturnValues : [ any Value ]
763+ do {
764+ var returnValues = [ any Value ] ( )
765+ // The next original result to process.
766+ var resultIndex = 0
767+ var originalDirectResultIterator = originalReturnTupleElements. makeIterator ( )
768+
769+ for mappedResult in resultMap {
770+
771+ // Collect any direct results before the next mappedResult.
772+ while resultIndex < mappedResult. resultIndex {
773+ if !self . original. convention. results [ resultIndex] . isSILIndirect {
774+ returnValues. append ( originalDirectResultIterator. next ( ) !)
775+ }
776+ resultIndex += 1
777+ }
750778
751- let mapped = resultMap [ resultMapIndex ]
779+ assert ( resultIndex == mappedResult . resultIndex , " The next pack result is not skipped. " )
752780
753- let argumentMapping = argumentMap [ mapped . argumentIndex] !
781+ let argumentMapping = argumentMap [ mappedResult . argumentIndex] !
754782 for argument in argumentMapping. arguments {
755783
756784 switch argument. resources {
@@ -769,18 +797,26 @@ private struct PackExplodedFunction {
769797 }
770798 }
771799
772- resultMapIndex += 1
800+ // We have finished processing mappedResult, so step forward.
801+ resultIndex += 1
773802 }
803+
804+ // Collect any remaining original direct results.
805+ while let directResult = originalDirectResultIterator. next ( ) {
806+ returnValues. append ( directResult)
807+ }
808+
809+ theReturnValues = returnValues
774810 }
775811
776- // Return the single value directly, rather than constructing a single-element tuple for it.
777- if returnValues . count == 1 {
778- builder. createReturn ( of: returnValues [ 0 ] )
812+ // Return a single return value directly, rather than constructing a single-element tuple for it.
813+ if theReturnValues . count == 1 {
814+ builder. createReturn ( of: theReturnValues [ 0 ] )
779815 } else {
780- let tupleElementTypes = returnValues . map { $0. type }
816+ let tupleElementTypes = theReturnValues . map { $0. type }
781817 let tupleType = context. getTupleType ( elements: tupleElementTypes) . loweredType (
782818 in: specialized)
783- let tuple = builder. createTuple ( type: tupleType, elements: returnValues )
819+ let tuple = builder. createTuple ( type: tupleType, elements: theReturnValues )
784820 builder. createReturn ( of: tuple)
785821 }
786822
@@ -1026,7 +1062,7 @@ private func loadOwnership(for value: any Value, normal: LoadInst.LoadOwnership)
10261062 }
10271063}
10281064
1029- extension TypeProperties {
1065+ extension Type {
10301066 /// A pack argument can explode if it contains no pack expansion types
10311067 fileprivate var shouldExplode : Bool {
10321068 // For now, we only attempt to explode indirect packs, since these are the most common and inefficient.
0 commit comments