Skip to content

Commit 6afb011

Browse files
Raj Barikatrick
authored andcommitted
Reorganizing the code to find init_existential; Move them to Existential.cpp/h in order for other passes such as ExistentialSpecializer to use it apart from SILCombiner
1 parent d0f0a05 commit 6afb011

File tree

4 files changed

+242
-131
lines changed

4 files changed

+242
-131
lines changed
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
//===--- Existential.h - Existential related Analyses. -------*- C++ //-*-===//
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+
#ifndef SWIFT_SILOPTIMIZER_UTILS_EXISTENTIAL_H
14+
#define SWIFT_SILOPTIMIZER_UTILS_EXISTENTIAL_H
15+
16+
#include "swift/SIL/SILInstruction.h"
17+
18+
namespace swift {
19+
20+
/// Find InitExistential from global_addr and copy_addr.
21+
SILValue findInitExistentialFromGlobalAddr(GlobalAddrInst *GAI,
22+
CopyAddrInst *CAI);
23+
24+
/// Returns the address of an object with which the stack location \p ASI is
25+
/// initialized. This is either a init_existential_addr or the destination of a
26+
/// copy_addr. Returns a null value if the address does not dominate the
27+
/// alloc_stack user \p ASIUser.
28+
/// If the value is copied from another stack location, \p isCopied is set to
29+
/// true.
30+
SILValue getAddressOfStackInit(AllocStackInst *ASI, SILInstruction *ASIUser,
31+
bool &isCopied);
32+
33+
/// Find the init_existential, which could be used to determine a concrete
34+
/// type of the \p Self.
35+
/// If the value is copied from another stack location, \p isCopied is set to
36+
/// true.
37+
SILInstruction *findInitExistential(FullApplySite AI, SILValue Self,
38+
ArchetypeType *&OpenedArchetype,
39+
SILValue &OpenedArchetypeDef,
40+
bool &isCopied);
41+
} // end namespace swift
42+
43+
#endif

lib/SILOptimizer/SILCombiner/SILCombinerApplyVisitors.cpp

Lines changed: 1 addition & 131 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include "swift/SILOptimizer/Analysis/AliasAnalysis.h"
2626
#include "swift/SILOptimizer/Analysis/CFG.h"
2727
#include "swift/SILOptimizer/Analysis/ValueTracking.h"
28+
#include "swift/SILOptimizer/Utils/Existential.h"
2829
#include "llvm/ADT/DenseMap.h"
2930
#include "llvm/ADT/SmallPtrSet.h"
3031
#include "llvm/ADT/SmallVector.h"
@@ -600,137 +601,6 @@ SILCombiner::optimizeConcatenationOfStringLiterals(ApplyInst *AI) {
600601
return tryToConcatenateStrings(AI, Builder);
601602
}
602603

603-
/// Returns the address of an object with which the stack location \p ASI is
604-
/// initialized. This is either a init_existential_addr or the destination of a
605-
/// copy_addr. Returns a null value if the address does not dominate the
606-
/// alloc_stack user \p ASIUser.
607-
/// If the value is copied from another stack location, \p isCopied is set to
608-
/// true.
609-
static SILValue getAddressOfStackInit(AllocStackInst *ASI,
610-
SILInstruction *ASIUser,
611-
bool &isCopied) {
612-
SILInstruction *SingleWrite = nullptr;
613-
// Check that this alloc_stack is initialized only once.
614-
for (auto Use : ASI->getUses()) {
615-
auto *User = Use->getUser();
616-
617-
// Ignore instructions which don't write to the stack location.
618-
// Also ignore ASIUser (only kicks in if ASIUser is the original apply).
619-
if (isa<DeallocStackInst>(User) || isa<DebugValueAddrInst>(User) ||
620-
isa<DestroyAddrInst>(User) || isa<WitnessMethodInst>(User) ||
621-
isa<DeinitExistentialAddrInst>(User) ||
622-
isa<OpenExistentialAddrInst>(User) ||
623-
User == ASIUser) {
624-
continue;
625-
}
626-
if (auto *CAI = dyn_cast<CopyAddrInst>(User)) {
627-
if (CAI->getDest() == ASI) {
628-
if (SingleWrite)
629-
return SILValue();
630-
SingleWrite = CAI;
631-
isCopied = true;
632-
}
633-
continue;
634-
}
635-
if (isa<InitExistentialAddrInst>(User)) {
636-
if (SingleWrite)
637-
return SILValue();
638-
SingleWrite = User;
639-
continue;
640-
}
641-
if (isa<ApplyInst>(User) || isa<TryApplyInst>(User)) {
642-
// Ignore function calls which do not write to the stack location.
643-
auto Idx = Use->getOperandNumber() - ApplyInst::getArgumentOperandNumber();
644-
auto Conv = FullApplySite(User).getArgumentConvention(Idx);
645-
if (Conv != SILArgumentConvention::Indirect_In &&
646-
Conv != SILArgumentConvention::Indirect_In_Guaranteed)
647-
return SILValue();
648-
continue;
649-
}
650-
// Bail if there is any unknown (and potentially writing) instruction.
651-
return SILValue();
652-
}
653-
if (!SingleWrite)
654-
return SILValue();
655-
656-
// A very simple dominance check. As ASI is an operand of ASIUser,
657-
// SingleWrite dominates ASIUser if it is in the same block as ASI or ASIUser.
658-
SILBasicBlock *BB = SingleWrite->getParent();
659-
if (BB != ASI->getParent() && BB != ASIUser->getParent())
660-
return SILValue();
661-
662-
if (auto *CAI = dyn_cast<CopyAddrInst>(SingleWrite)) {
663-
// Try to derive the type from the copy_addr that was used to
664-
// initialize the alloc_stack.
665-
assert(isCopied && "isCopied not set for a copy_addr");
666-
SILValue CAISrc = CAI->getSrc();
667-
if (auto *ASI = dyn_cast<AllocStackInst>(CAISrc))
668-
return getAddressOfStackInit(ASI, CAI, isCopied);
669-
return CAISrc;
670-
}
671-
return cast<InitExistentialAddrInst>(SingleWrite);
672-
}
673-
674-
/// Find the init_existential, which could be used to determine a concrete
675-
/// type of the \p Self.
676-
/// If the value is copied from another stack location, \p isCopied is set to
677-
/// true.
678-
static SILInstruction *findInitExistential(FullApplySite AI, SILValue Self,
679-
ArchetypeType *&OpenedArchetype,
680-
SILValue &OpenedArchetypeDef,
681-
bool &isCopied) {
682-
isCopied = false;
683-
if (auto *Instance = dyn_cast<AllocStackInst>(Self)) {
684-
// In case the Self operand is an alloc_stack where a copy_addr copies the
685-
// result of an open_existential_addr to this stack location.
686-
if (SILValue Src = getAddressOfStackInit(Instance, AI.getInstruction(),
687-
isCopied))
688-
Self = Src;
689-
}
690-
691-
if (auto *Open = dyn_cast<OpenExistentialAddrInst>(Self)) {
692-
auto Op = Open->getOperand();
693-
auto *ASI = dyn_cast<AllocStackInst>(Op);
694-
if (!ASI)
695-
return nullptr;
696-
697-
SILValue StackWrite = getAddressOfStackInit(ASI, Open, isCopied);
698-
if (!StackWrite)
699-
return nullptr;
700-
701-
auto *IE = dyn_cast<InitExistentialAddrInst>(StackWrite);
702-
if (!IE)
703-
return nullptr;
704-
705-
OpenedArchetype = Open->getType().castTo<ArchetypeType>();
706-
OpenedArchetypeDef = Open;
707-
return IE;
708-
}
709-
710-
if (auto *Open = dyn_cast<OpenExistentialRefInst>(Self)) {
711-
if (auto *IE = dyn_cast<InitExistentialRefInst>(Open->getOperand())) {
712-
OpenedArchetype = Open->getType().castTo<ArchetypeType>();
713-
OpenedArchetypeDef = Open;
714-
return IE;
715-
}
716-
return nullptr;
717-
}
718-
719-
if (auto *Open = dyn_cast<OpenExistentialMetatypeInst>(Self)) {
720-
if (auto *IE =
721-
dyn_cast<InitExistentialMetatypeInst>(Open->getOperand())) {
722-
auto Ty = Open->getType().getSwiftRValueType();
723-
while (auto Metatype = dyn_cast<MetatypeType>(Ty))
724-
Ty = Metatype.getInstanceType();
725-
OpenedArchetype = cast<ArchetypeType>(Ty);
726-
OpenedArchetypeDef = Open;
727-
return IE;
728-
}
729-
return nullptr;
730-
}
731-
return nullptr;
732-
}
733-
734604
/// Create a new apply instructions that uses the concrete type instead
735605
/// of the existential type.
736606
SILInstruction *

lib/SILOptimizer/Utils/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ set(UTILS_SOURCES
44
Utils/CheckedCastBrJumpThreading.cpp
55
Utils/ConstantFolding.cpp
66
Utils/Devirtualize.cpp
7+
Utils/Existential.cpp
78
Utils/FunctionSignatureOptUtils.cpp
89
Utils/GenericCloner.cpp
910
Utils/Generics.cpp
Lines changed: 197 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
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

Comments
 (0)