@@ -100,13 +100,50 @@ void CopyPropagation::run() {
100100 }
101101 }
102102 }
103+ // Push copy_value instructions above their struct_extract operands by
104+ // inserting destructures.
105+ //
106+ // copiedDefs be be modified, but it never shrinks
107+ for (unsigned idx = 0 ; idx < copiedDefs.size (); ++idx) {
108+ SILValue def = copiedDefs[idx];
109+ auto *copy = dyn_cast<CopyValueInst>(def);
110+ if (!copy)
111+ continue ;
112+
113+ auto *extract = dyn_cast<StructExtractInst>(copy->getOperand ());
114+ if (!extract
115+ || SILValue (extract).getOwnershipKind () != OwnershipKind::Guaranteed)
116+ continue ;
117+
118+ if (SILValue destructuredResult = convertExtractToDestructure (extract)) {
119+ // Remove to-be-deleted instructions from copiedDeds. The extract cannot
120+ // be in the copiedDefs set since getCanonicalCopiedDef does not allow a
121+ // guaranteed projection to be a canonical def.
122+ copiedDefs.remove (copy);
123+ --idx; // point back to the current element, which was erased.
124+
125+ // TODO: unfortunately SetVector has no element replacement.
126+ copiedDefs.insert (destructuredResult);
127+
128+ auto *destructure = cast<DestructureStructInst>(
129+ destructuredResult.getDefiningInstruction ());
130+ auto *newCopy = cast<CopyValueInst>(destructure->getOperand ());
131+ copiedDefs.insert (
132+ CanonicalizeOSSALifetime::getCanonicalCopiedDef (newCopy));
133+
134+ LLVM_DEBUG (llvm::dbgs () << " Destructure Conversion:\n "
135+ << *extract << " to " << *destructure);
136+ // Delete both the copy and the extract.
137+ InstructionDeleter ().recursivelyDeleteUsersIfDead (extract);
138+ }
139+ }
103140 // Perform copy propgation for each copied value.
104141 CanonicalizeOSSALifetime canonicalizer (pruneDebug, poisonRefs,
105142 accessBlockAnalysis,
106143 dominanceAnalysis,
107144 deBlocksAnalysis->get (f));
108145 // Cleanup dead copies. If getCanonicalCopiedDef returns a copy (because the
109- // copy's source operand is unrecgonized), then the copy is itself treated
146+ // copy's source operand is unrecgonized), then thecan copy is itself treated
110147 // like a def and may be dead after canonicalization.
111148 llvm::SmallVector<CopyValueInst *, 4 > deadCopies;
112149 for (auto &def : copiedDefs) {
0 commit comments