|
| 1 | +//===--- GuaranteedARCOpts.cpp --------------------------------------------===// |
| 2 | +// |
| 3 | +// This source file is part of the Swift.org open source project |
| 4 | +// |
| 5 | +// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors |
| 6 | +// Licensed under Apache License v2.0 with Runtime Library Exception |
| 7 | +// |
| 8 | +// See http://swift.org/LICENSE.txt for license information |
| 9 | +// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors |
| 10 | +// |
| 11 | +//===----------------------------------------------------------------------===// |
| 12 | + |
| 13 | +#define DEBUG_TYPE "sil-guaranteed-arc-opts" |
| 14 | +#include "swift/SILOptimizer/PassManager/Passes.h" |
| 15 | +#include "swift/SILOptimizer/PassManager/Transforms.h" |
| 16 | +#include "swift/SIL/SILVisitor.h" |
| 17 | + |
| 18 | +using namespace swift; |
| 19 | + |
| 20 | +namespace { |
| 21 | + |
| 22 | +struct GuaranteedARCOptsVisitor |
| 23 | + : SILInstructionVisitor<GuaranteedARCOptsVisitor, bool> { |
| 24 | + bool visitValueBase(ValueBase *V) { return false; } |
| 25 | + bool visitDestroyAddrInst(DestroyAddrInst *DAI); |
| 26 | + bool visitStrongReleaseInst(StrongReleaseInst *SRI); |
| 27 | + bool visitDestroyValueInst(DestroyValueInst *DVI); |
| 28 | + bool visitReleaseValueInst(ReleaseValueInst *RVI); |
| 29 | +}; |
| 30 | + |
| 31 | +} // end anonymous namespace |
| 32 | + |
| 33 | +static SILBasicBlock::reverse_iterator |
| 34 | +getPrevReverseIterator(SILInstruction *I) { |
| 35 | + auto Iter = std::next(I->getIterator()); |
| 36 | + return std::next(SILBasicBlock::reverse_iterator(Iter)); |
| 37 | +} |
| 38 | + |
| 39 | +bool GuaranteedARCOptsVisitor::visitDestroyAddrInst(DestroyAddrInst *DAI) { |
| 40 | + SILValue Operand = DAI->getOperand(); |
| 41 | + |
| 42 | + for (auto II = getPrevReverseIterator(DAI), IE = DAI->getParent()->rend(); |
| 43 | + II != IE;) { |
| 44 | + auto *Inst = &*II; |
| 45 | + ++II; |
| 46 | + |
| 47 | + if (auto *CA = dyn_cast<CopyAddrInst>(Inst)) { |
| 48 | + if (CA->getSrc() == Operand && !CA->isTakeOfSrc()) { |
| 49 | + CA->setIsTakeOfSrc(IsTake); |
| 50 | + DAI->eraseFromParent(); |
| 51 | + return true; |
| 52 | + } |
| 53 | + } |
| 54 | + |
| 55 | + // destroy_addrs commonly exist in a block of dealloc_stack's, which don't |
| 56 | + // affect take-ability. |
| 57 | + if (isa<DeallocStackInst>(Inst)) |
| 58 | + continue; |
| 59 | + |
| 60 | + // This code doesn't try to prove tricky validity constraints about whether |
| 61 | + // it is safe to push the destroy_addr past interesting instructions. |
| 62 | + if (Inst->mayHaveSideEffects()) |
| 63 | + break; |
| 64 | + } |
| 65 | + |
| 66 | + // If we didn't find a copy_addr to fold this into, emit the destroy_addr. |
| 67 | + return false; |
| 68 | +} |
| 69 | + |
| 70 | +static bool couldReduceStrongRefcount(SILInstruction *Inst) { |
| 71 | + // Simple memory accesses cannot reduce refcounts. |
| 72 | + if (isa<LoadInst>(Inst) || isa<StoreInst>(Inst) || |
| 73 | + isa<RetainValueInst>(Inst) || isa<UnownedRetainInst>(Inst) || |
| 74 | + isa<UnownedReleaseInst>(Inst) || isa<StrongRetainUnownedInst>(Inst) || |
| 75 | + isa<StoreWeakInst>(Inst) || isa<StrongRetainInst>(Inst) || |
| 76 | + isa<AllocStackInst>(Inst) || isa<DeallocStackInst>(Inst)) |
| 77 | + return false; |
| 78 | + |
| 79 | + // Assign and copyaddr of trivial types cannot drop refcounts, and 'inits' |
| 80 | + // never can either. Nontrivial ones can though, because the overwritten |
| 81 | + // value drops a retain. We would have to do more alias analysis to be able |
| 82 | + // to safely ignore one of those. |
| 83 | + if (auto *AI = dyn_cast<AssignInst>(Inst)) { |
| 84 | + SILType StoredType = AI->getOperand(0)->getType(); |
| 85 | + if (StoredType.isTrivial(Inst->getModule()) || |
| 86 | + StoredType.is<ReferenceStorageType>()) |
| 87 | + return false; |
| 88 | + } |
| 89 | + |
| 90 | + if (auto *CAI = dyn_cast<CopyAddrInst>(Inst)) { |
| 91 | + // Initializations can only increase refcounts. |
| 92 | + if (CAI->isInitializationOfDest()) |
| 93 | + return false; |
| 94 | + |
| 95 | + SILType StoredType = CAI->getOperand(0)->getType().getObjectType(); |
| 96 | + if (StoredType.isTrivial(Inst->getModule()) || |
| 97 | + StoredType.is<ReferenceStorageType>()) |
| 98 | + return false; |
| 99 | + } |
| 100 | + |
| 101 | + // This code doesn't try to prove tricky validity constraints about whether |
| 102 | + // it is safe to push the release past interesting instructions. |
| 103 | + return Inst->mayHaveSideEffects(); |
| 104 | +} |
| 105 | + |
| 106 | +bool GuaranteedARCOptsVisitor::visitStrongReleaseInst(StrongReleaseInst *SRI) { |
| 107 | + SILValue Operand = SRI->getOperand(); |
| 108 | + // Release on a functionref is a noop. |
| 109 | + if (isa<FunctionRefInst>(Operand)) { |
| 110 | + SRI->eraseFromParent(); |
| 111 | + return true; |
| 112 | + } |
| 113 | + |
| 114 | + // Check to see if the instruction immediately before the insertion point is a |
| 115 | + // strong_retain of the specified operand. If so, we can zap the pair. |
| 116 | + for (auto II = getPrevReverseIterator(SRI), IE = SRI->getParent()->rend(); |
| 117 | + II != IE;) { |
| 118 | + auto *Inst = &*II; |
| 119 | + ++II; |
| 120 | + |
| 121 | + if (auto *SRA = dyn_cast<StrongRetainInst>(Inst)) { |
| 122 | + if (SRA->getOperand() == Operand) { |
| 123 | + SRA->eraseFromParent(); |
| 124 | + SRI->eraseFromParent(); |
| 125 | + return true; |
| 126 | + } |
| 127 | + // Skip past unrelated retains. |
| 128 | + continue; |
| 129 | + } |
| 130 | + |
| 131 | + // Scan past simple instructions that cannot reduce strong refcounts. |
| 132 | + if (couldReduceStrongRefcount(Inst)) |
| 133 | + break; |
| 134 | + } |
| 135 | + |
| 136 | + // If we didn't find a retain to fold this into, return false. |
| 137 | + return false; |
| 138 | +} |
| 139 | + |
| 140 | +bool GuaranteedARCOptsVisitor::visitDestroyValueInst(DestroyValueInst *DVI) { |
| 141 | + SILValue Operand = DVI->getOperand(); |
| 142 | + for (auto II = getPrevReverseIterator(DVI), IE = DVI->getParent()->rend(); |
| 143 | + II != IE;) { |
| 144 | + auto *Inst = &*II; |
| 145 | + ++II; |
| 146 | + |
| 147 | + if (auto *CVI = dyn_cast<CopyValueInst>(Inst)) { |
| 148 | + if (SILValue(CVI) == Operand || CVI->getOperand() == Operand) { |
| 149 | + CVI->replaceAllUsesWith(CVI->getOperand()); |
| 150 | + CVI->eraseFromParent(); |
| 151 | + DVI->eraseFromParent(); |
| 152 | + return true; |
| 153 | + } |
| 154 | + // Skip past unrelated retains. |
| 155 | + continue; |
| 156 | + } |
| 157 | + |
| 158 | + // Scan past simple instructions that cannot reduce refcounts. |
| 159 | + if (couldReduceStrongRefcount(Inst)) |
| 160 | + break; |
| 161 | + } |
| 162 | + |
| 163 | + return false; |
| 164 | +} |
| 165 | + |
| 166 | +bool GuaranteedARCOptsVisitor::visitReleaseValueInst(ReleaseValueInst *RVI) { |
| 167 | + SILValue Operand = RVI->getOperand(); |
| 168 | + |
| 169 | + for (auto II = getPrevReverseIterator(RVI), IE = RVI->getParent()->rend(); |
| 170 | + II != IE;) { |
| 171 | + auto *Inst = &*II; |
| 172 | + ++II; |
| 173 | + |
| 174 | + if (auto *SRA = dyn_cast<RetainValueInst>(Inst)) { |
| 175 | + if (SRA->getOperand() == Operand) { |
| 176 | + SRA->eraseFromParent(); |
| 177 | + RVI->eraseFromParent(); |
| 178 | + return true; |
| 179 | + } |
| 180 | + // Skip past unrelated retains. |
| 181 | + continue; |
| 182 | + } |
| 183 | + |
| 184 | + // Scan past simple instructions that cannot reduce refcounts. |
| 185 | + if (couldReduceStrongRefcount(Inst)) |
| 186 | + break; |
| 187 | + } |
| 188 | + |
| 189 | + // If we didn't find a retain to fold this into, emit the release. |
| 190 | + return false; |
| 191 | +} |
| 192 | + |
| 193 | +//===----------------------------------------------------------------------===// |
| 194 | +// Top Level Entrypoint |
| 195 | +//===----------------------------------------------------------------------===// |
| 196 | + |
| 197 | +namespace { |
| 198 | + |
| 199 | +struct GuaranteedARCOpts : SILFunctionTransform { |
| 200 | + void run() override { |
| 201 | + GuaranteedARCOptsVisitor Visitor; |
| 202 | + |
| 203 | + bool MadeChange = false; |
| 204 | + SILFunction *F = getFunction(); |
| 205 | + for (auto &BB : *F) { |
| 206 | + for (auto II = BB.begin(), IE = BB.end(); II != IE;) { |
| 207 | + SILInstruction *I = &*II; |
| 208 | + ++II; |
| 209 | + MadeChange |= Visitor.visit(I); |
| 210 | + } |
| 211 | + } |
| 212 | + |
| 213 | + if (MadeChange) { |
| 214 | + invalidateAnalysis(SILAnalysis::InvalidationKind::Instructions); |
| 215 | + } |
| 216 | + } |
| 217 | + |
| 218 | + StringRef getName() override { return "Guaranteed ARC Opts"; } |
| 219 | +}; |
| 220 | + |
| 221 | +} // end swift namespace |
| 222 | + |
| 223 | +SILTransform *swift::createGuaranteedARCOpts() { |
| 224 | + return new GuaranteedARCOpts(); |
| 225 | +} |
0 commit comments