@@ -1555,8 +1555,9 @@ class CopyForwardingPass : public SILFunctionTransform
1555
1555
class TempRValueOptPass : public SILFunctionTransform {
1556
1556
AliasAnalysis *AA = nullptr ;
1557
1557
1558
- static bool collectLoads (Operand *UserOp, SILInstruction *UserInst,
1558
+ bool collectLoads (Operand *UserOp, SILInstruction *UserInst,
1559
1559
SingleValueInstruction *Addr,
1560
+ SILValue srcObject,
1560
1561
llvm::SmallPtrSetImpl<SILInstruction *> &LoadInsts);
1561
1562
1562
1563
bool checkNoSourceModification (CopyAddrInst *copyInst,
@@ -1615,6 +1616,7 @@ void TempRValueOptPass::run() {
1615
1616
// / reaching a load or returning false.
1616
1617
bool TempRValueOptPass::collectLoads (
1617
1618
Operand *userOp, SILInstruction *user, SingleValueInstruction *address,
1619
+ SILValue srcObject,
1618
1620
llvm::SmallPtrSetImpl<SILInstruction *> &loadInsts) {
1619
1621
// All normal uses (loads) must be in the initialization block.
1620
1622
// (The destroy and dealloc are commonly in a different block though.)
@@ -1639,22 +1641,42 @@ bool TempRValueOptPass::collectLoads(
1639
1641
1640
1642
case SILInstructionKind::ApplyInst: {
1641
1643
ApplySite apply (user);
1644
+
1645
+ // Check if the function can just read from userOp.
1642
1646
auto Convention = apply.getArgumentConvention (*userOp);
1643
- if (Convention.isGuaranteedConvention ()) {
1644
- loadInsts.insert (user);
1645
- return true ;
1647
+ if (!Convention.isGuaranteedConvention ()) {
1648
+ LLVM_DEBUG (llvm::dbgs () << " Temp consuming use may write/destroy "
1649
+ " its source" << *user);
1650
+ return false ;
1646
1651
}
1647
- LLVM_DEBUG (llvm::dbgs () << " Temp consuming use may write/destroy "
1648
- " its source"
1649
- << *user);
1650
- return false ;
1652
+
1653
+ // Check if there is another function argument, which is inout which might
1654
+ // modify the source of the copy_addr.
1655
+ // If we would remove the copy_addr in this case, it would result in an
1656
+ // exclusivity violation.
1657
+ auto calleeConv = apply.getSubstCalleeConv ();
1658
+ unsigned calleeArgIdx = apply.getCalleeArgIndexOfFirstAppliedArg ();
1659
+ for (Operand &operand : apply.getArgumentOperands ()) {
1660
+ auto argConv = calleeConv.getSILArgumentConvention (calleeArgIdx);
1661
+ if (argConv.isInoutConvention ()) {
1662
+ if (!AA->isNoAlias (operand.get (), srcObject)) {
1663
+ return false ;
1664
+ }
1665
+ }
1666
+ ++calleeArgIdx;
1667
+ }
1668
+
1669
+ // Everything is okay with the function call. Register it as a "load".
1670
+ loadInsts.insert (user);
1671
+ return true ;
1651
1672
}
1652
1673
case SILInstructionKind::StructElementAddrInst:
1653
1674
case SILInstructionKind::TupleElementAddrInst: {
1654
1675
// Transitively look through projections on stack addresses.
1655
1676
auto proj = cast<SingleValueInstruction>(user);
1656
1677
for (auto *projUseOper : proj->getUses ()) {
1657
- if (!collectLoads (projUseOper, projUseOper->getUser (), proj, loadInsts))
1678
+ if (!collectLoads (projUseOper, projUseOper->getUser (), proj, srcObject,
1679
+ loadInsts))
1658
1680
return false ;
1659
1681
}
1660
1682
return true ;
@@ -1744,7 +1766,7 @@ bool TempRValueOptPass::tryOptimizeCopyIntoTemp(CopyAddrInst *copyInst) {
1744
1766
if (isa<DestroyAddrInst>(user) || isa<DeallocStackInst>(user))
1745
1767
continue ;
1746
1768
1747
- if (!collectLoads (useOper, user, tempObj, loadInsts))
1769
+ if (!collectLoads (useOper, user, tempObj, copyInst-> getSrc (), loadInsts))
1748
1770
return false ;
1749
1771
}
1750
1772
0 commit comments