|
| 1 | +//===--- Existential.cpp - Functions analyzing existentials. -------------===// |
| 2 | +// |
| 3 | +// This source file is part of the Swift.org open source project |
| 4 | +// |
| 5 | +// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors |
| 6 | +// Licensed under Apache License v2.0 with Runtime Library Exception |
| 7 | +// |
| 8 | +// See https://swift.org/LICENSE.txt for license information |
| 9 | +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors |
| 10 | +// |
| 11 | +//===----------------------------------------------------------------------===// |
| 12 | + |
| 13 | +#include "swift/SILOptimizer/Utils/Existential.h" |
| 14 | +#include "swift/SILOptimizer/Utils/CFG.h" |
| 15 | +#include "swift/SIL/InstructionUtils.h" |
| 16 | +#include "swift/SIL/BasicBlockUtils.h" |
| 17 | +#include "llvm/ADT/SmallPtrSet.h" |
| 18 | + |
| 19 | +using namespace swift; |
| 20 | + |
| 21 | +/// Determine the pattern for global_addr. |
| 22 | +/// %3 = global_addr @$P : $*SomeP |
| 23 | +/// %4 = init_existential_addr %3 : $*SomeP, $SomeC |
| 24 | +/// %5 = alloc_ref $SomeC |
| 25 | +/// store %5 to %4 : $*SomeC |
| 26 | +/// %8 = alloc_stack $SomeP |
| 27 | +/// copy_addr %3 to [initialization] %8 : $*SomeP |
| 28 | +/// %9 = open_existential_addr immutable_access %8 : $*SomeP to $*@opened SomeP |
| 29 | +SILValue swift::findInitExistentialFromGlobalAddr(GlobalAddrInst *GAI, |
| 30 | + CopyAddrInst *CAI) { |
| 31 | + assert(CAI->getSrc() == SILValue(GAI) && |
| 32 | + "Broken Assumption! Global Addr is not the source of the passed in " |
| 33 | + "copy_addr?!"); |
| 34 | + |
| 35 | + /// Check for a single InitExistential usage for GAI and |
| 36 | + /// a simple dominance check: both InitExistential and CAI are in |
| 37 | + /// the same basic block and only one InitExistential |
| 38 | + /// occurs between GAI and CAI. |
| 39 | + llvm::SmallPtrSet<SILInstruction *, 8> IEUses; |
| 40 | + for (auto *Use : GAI->getUses()) { |
| 41 | + if (auto *InitExistential = |
| 42 | + dyn_cast<InitExistentialAddrInst>(Use->getUser())) { |
| 43 | + IEUses.insert(InitExistential); |
| 44 | + } |
| 45 | + } |
| 46 | + |
| 47 | + /// No InitExistential found in the basic block. |
| 48 | + if (IEUses.empty()) |
| 49 | + return SILValue(); |
| 50 | + |
| 51 | + /// Walk backwards from CAI instruction till the begining of the basic block |
| 52 | + /// looking for InitExistential. |
| 53 | + SILValue SingleIE; |
| 54 | + for (auto II = CAI->getIterator().getReverse(), IE = CAI->getParent()->rend(); |
| 55 | + II != IE; ++II) { |
| 56 | + if (!IEUses.count(&*II)) |
| 57 | + continue; |
| 58 | + if (SingleIE) |
| 59 | + return SILValue(); |
| 60 | + |
| 61 | + SingleIE = cast<InitExistentialAddrInst>(&*II); |
| 62 | + } |
| 63 | + return SingleIE; |
| 64 | +} |
| 65 | + |
| 66 | +/// Returns the address of an object with which the stack location \p ASI is |
| 67 | +/// initialized. This is either a init_existential_addr or the destination of a |
| 68 | +/// copy_addr. Returns a null value if the address does not dominate the |
| 69 | +/// alloc_stack user \p ASIUser. |
| 70 | +/// If the value is copied from another stack location, \p isCopied is set to |
| 71 | +/// true. |
| 72 | +SILValue swift::getAddressOfStackInit(AllocStackInst *ASI, |
| 73 | + SILInstruction *ASIUser, bool &isCopied) { |
| 74 | + SILInstruction *SingleWrite = nullptr; |
| 75 | + // Check that this alloc_stack is initialized only once. |
| 76 | + for (auto Use : ASI->getUses()) { |
| 77 | + auto *User = Use->getUser(); |
| 78 | + |
| 79 | + // Ignore instructions which don't write to the stack location. |
| 80 | + // Also ignore ASIUser (only kicks in if ASIUser is the original apply). |
| 81 | + if (isa<DeallocStackInst>(User) || isa<DebugValueAddrInst>(User) || |
| 82 | + isa<DestroyAddrInst>(User) || isa<WitnessMethodInst>(User) || |
| 83 | + isa<DeinitExistentialAddrInst>(User) || |
| 84 | + isa<OpenExistentialAddrInst>(User) || User == ASIUser) { |
| 85 | + continue; |
| 86 | + } |
| 87 | + if (auto *CAI = dyn_cast<CopyAddrInst>(User)) { |
| 88 | + if (CAI->getDest() == ASI) { |
| 89 | + if (SingleWrite) |
| 90 | + return SILValue(); |
| 91 | + SingleWrite = CAI; |
| 92 | + isCopied = true; |
| 93 | + } |
| 94 | + continue; |
| 95 | + } |
| 96 | + if (isa<InitExistentialAddrInst>(User)) { |
| 97 | + if (SingleWrite) |
| 98 | + return SILValue(); |
| 99 | + SingleWrite = User; |
| 100 | + continue; |
| 101 | + } |
| 102 | + if (isa<ApplyInst>(User) || isa<TryApplyInst>(User)) { |
| 103 | + // Ignore function calls which do not write to the stack location. |
| 104 | + auto Idx = |
| 105 | + Use->getOperandNumber() - ApplyInst::getArgumentOperandNumber(); |
| 106 | + auto Conv = FullApplySite(User).getArgumentConvention(Idx); |
| 107 | + if (Conv != SILArgumentConvention::Indirect_In && |
| 108 | + Conv != SILArgumentConvention::Indirect_In_Guaranteed) |
| 109 | + return SILValue(); |
| 110 | + continue; |
| 111 | + } |
| 112 | + // Bail if there is any unknown (and potentially writing) instruction. |
| 113 | + return SILValue(); |
| 114 | + } |
| 115 | + if (!SingleWrite) |
| 116 | + return SILValue(); |
| 117 | + |
| 118 | + // A very simple dominance check. As ASI is an operand of ASIUser, |
| 119 | + // SingleWrite dominates ASIUser if it is in the same block as ASI or ASIUser. |
| 120 | + SILBasicBlock *BB = SingleWrite->getParent(); |
| 121 | + if (BB != ASI->getParent() && BB != ASIUser->getParent()) |
| 122 | + return SILValue(); |
| 123 | + |
| 124 | + if (auto *CAI = dyn_cast<CopyAddrInst>(SingleWrite)) { |
| 125 | + // Try to derive the type from the copy_addr that was used to |
| 126 | + // initialize the alloc_stack. |
| 127 | + assert(isCopied && "isCopied not set for a copy_addr"); |
| 128 | + SILValue CAISrc = CAI->getSrc(); |
| 129 | + if (auto *ASI = dyn_cast<AllocStackInst>(CAISrc)) |
| 130 | + return getAddressOfStackInit(ASI, CAI, isCopied); |
| 131 | + // Check if the CAISrc is a global_addr. |
| 132 | + if (auto *GAI = dyn_cast<GlobalAddrInst>(CAISrc)) { |
| 133 | + return findInitExistentialFromGlobalAddr(GAI, CAI); |
| 134 | + } |
| 135 | + return CAISrc; |
| 136 | + } |
| 137 | + return cast<InitExistentialAddrInst>(SingleWrite); |
| 138 | +} |
| 139 | + |
| 140 | +/// Find the init_existential, which could be used to determine a concrete |
| 141 | +/// type of the \p Self. |
| 142 | +/// If the value is copied from another stack location, \p isCopied is set to |
| 143 | +/// true. |
| 144 | +SILInstruction *swift::findInitExistential(FullApplySite AI, SILValue Self, |
| 145 | + ArchetypeType *&OpenedArchetype, |
| 146 | + SILValue &OpenedArchetypeDef, |
| 147 | + bool &isCopied) { |
| 148 | + isCopied = false; |
| 149 | + if (auto *Instance = dyn_cast<AllocStackInst>(Self)) { |
| 150 | + // In case the Self operand is an alloc_stack where a copy_addr copies the |
| 151 | + // result of an open_existential_addr to this stack location. |
| 152 | + if (SILValue Src = |
| 153 | + getAddressOfStackInit(Instance, AI.getInstruction(), isCopied)) |
| 154 | + Self = Src; |
| 155 | + } |
| 156 | + |
| 157 | + if (auto *Open = dyn_cast<OpenExistentialAddrInst>(Self)) { |
| 158 | + auto Op = Open->getOperand(); |
| 159 | + auto *ASI = dyn_cast<AllocStackInst>(Op); |
| 160 | + if (!ASI) |
| 161 | + return nullptr; |
| 162 | + |
| 163 | + SILValue StackWrite = getAddressOfStackInit(ASI, Open, isCopied); |
| 164 | + if (!StackWrite) |
| 165 | + return nullptr; |
| 166 | + |
| 167 | + auto *IE = dyn_cast<InitExistentialAddrInst>(StackWrite); |
| 168 | + if (!IE) |
| 169 | + return nullptr; |
| 170 | + |
| 171 | + OpenedArchetype = Open->getType().castTo<ArchetypeType>(); |
| 172 | + OpenedArchetypeDef = Open; |
| 173 | + return IE; |
| 174 | + } |
| 175 | + |
| 176 | + if (auto *Open = dyn_cast<OpenExistentialRefInst>(Self)) { |
| 177 | + if (auto *IE = dyn_cast<InitExistentialRefInst>(Open->getOperand())) { |
| 178 | + OpenedArchetype = Open->getType().castTo<ArchetypeType>(); |
| 179 | + OpenedArchetypeDef = Open; |
| 180 | + return IE; |
| 181 | + } |
| 182 | + return nullptr; |
| 183 | + } |
| 184 | + |
| 185 | + if (auto *Open = dyn_cast<OpenExistentialMetatypeInst>(Self)) { |
| 186 | + if (auto *IE = dyn_cast<InitExistentialMetatypeInst>(Open->getOperand())) { |
| 187 | + auto Ty = Open->getType().getASTType(); |
| 188 | + while (auto Metatype = dyn_cast<MetatypeType>(Ty)) |
| 189 | + Ty = Metatype.getInstanceType(); |
| 190 | + OpenedArchetype = cast<ArchetypeType>(Ty); |
| 191 | + OpenedArchetypeDef = Open; |
| 192 | + return IE; |
| 193 | + } |
| 194 | + return nullptr; |
| 195 | + } |
| 196 | + return nullptr; |
| 197 | +} |
0 commit comments