Skip to content

Commit a2996b7

Browse files
authored
Merge pull request #35780 from eeckstein/static-function-arrays
SILOptimizer: allow function pointers in static globals and static global arrays.
2 parents ae695b2 + 0a483a6 commit a2996b7

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+402
-240
lines changed

include/swift/SIL/SILBuilder.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,8 @@ class SILBuilder {
201201
bool isInsertingIntoGlobal() const { return F == nullptr; }
202202

203203
TypeExpansionContext getTypeExpansionContext() const {
204+
if (!F)
205+
return TypeExpansionContext::minimal();
204206
return TypeExpansionContext(getFunction());
205207
}
206208

@@ -1027,7 +1029,7 @@ class SILBuilder {
10271029
SILType Ty,
10281030
bool WithoutActuallyEscaping) {
10291031
return insert(ConvertFunctionInst::create(getSILDebugLocation(Loc), Op, Ty,
1030-
getFunction(), C.OpenedArchetypes,
1032+
getModule(), F, C.OpenedArchetypes,
10311033
WithoutActuallyEscaping));
10321034
}
10331035

@@ -1157,7 +1159,7 @@ class SILBuilder {
11571159
ThinToThickFunctionInst *createThinToThickFunction(SILLocation Loc,
11581160
SILValue Op, SILType Ty) {
11591161
return insert(ThinToThickFunctionInst::create(
1160-
getSILDebugLocation(Loc), Op, Ty, getFunction(), C.OpenedArchetypes));
1162+
getSILDebugLocation(Loc), Op, Ty, getModule(), F, C.OpenedArchetypes));
11611163
}
11621164

11631165
ThickToObjCMetatypeInst *createThickToObjCMetatype(SILLocation Loc,

include/swift/SIL/SILCloner.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -967,7 +967,7 @@ template<typename ImplClass>
967967
void
968968
SILCloner<ImplClass>::visitFunctionRefInst(FunctionRefInst *Inst) {
969969
SILFunction *OpFunction =
970-
getOpFunction(Inst->getInitiallyReferencedFunction());
970+
getOpFunction(Inst->getReferencedFunction());
971971
getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope()));
972972
recordClonedInstruction(Inst, getBuilder().createFunctionRef(
973973
getOpLocation(Inst->getLoc()), OpFunction));

include/swift/SIL/SILGlobalVariable.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,10 @@ class SILGlobalVariable
128128
SILLinkage getLinkage() const { return SILLinkage(Linkage); }
129129
void setLinkage(SILLinkage linkage) { Linkage = unsigned(linkage); }
130130

131+
/// Returns true if the linkage of the SILFunction indicates that the global
132+
/// might be referenced from outside the current compilation unit.
133+
bool isPossiblyUsedExternally() const;
134+
131135
/// Get this global variable's serialized attribute.
132136
IsSerialized_t isSerialized() const;
133137
void setSerialized(IsSerialized_t isSerialized);

include/swift/SIL/SILInstruction.h

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2756,9 +2756,9 @@ class LiteralInst : public SingleValueInstruction {
27562756
};
27572757

27582758
class FunctionRefBaseInst : public LiteralInst {
2759+
protected:
27592760
SILFunction *f;
27602761

2761-
protected:
27622762
FunctionRefBaseInst(SILInstructionKind Kind, SILDebugLocation DebugLoc,
27632763
SILFunction *F, TypeExpansionContext context);
27642764

@@ -2819,6 +2819,9 @@ class FunctionRefInst : public FunctionRefBaseInst {
28192819
TypeExpansionContext context);
28202820

28212821
public:
2822+
/// Return the referenced function.
2823+
SILFunction *getReferencedFunction() const { return f; }
2824+
28222825
static bool classof(SILNodePointer node) {
28232826
return node->getKind() == SILNodeKind::FunctionRefInst;
28242827
}
@@ -4812,7 +4815,7 @@ class ConvertFunctionInst final
48124815

48134816
static ConvertFunctionInst *create(SILDebugLocation DebugLoc,
48144817
SILValue Operand, SILType Ty,
4815-
SILFunction &F,
4818+
SILModule &Mod, SILFunction *F,
48164819
SILOpenedArchetypesState &OpenedArchetypes,
48174820
bool WithoutActuallyEscaping);
48184821

@@ -5162,8 +5165,8 @@ class ThinToThickFunctionInst final
51625165
Operand.getOwnershipKind()) {}
51635166

51645167
static ThinToThickFunctionInst *
5165-
create(SILDebugLocation DebugLoc, SILValue Operand, SILType Ty,
5166-
SILFunction &F, SILOpenedArchetypesState &OpenedArchetypes);
5168+
create(SILDebugLocation DebugLoc, SILValue Operand, SILType Ty, SILModule &Mod,
5169+
SILFunction *F, SILOpenedArchetypesState &OpenedArchetypes);
51675170

51685171
public:
51695172
/// Return the callee of the thin_to_thick_function.

include/swift/SIL/TypeSubstCloner.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ class TypeSubstCloner : public SILClonerWithScopes<ImplClass> {
6969

7070
if (!Cloner.Inlining) {
7171
FunctionRefInst *FRI = dyn_cast<FunctionRefInst>(AI.getCallee());
72-
if (FRI && FRI->getInitiallyReferencedFunction() == AI.getFunction() &&
72+
if (FRI && FRI->getReferencedFunction() == AI.getFunction() &&
7373
Subs == Cloner.SubsMap) {
7474
// Handle recursions by replacing the apply to the callee with an
7575
// apply to the newly specialized function, but only if substitutions

include/swift/SILOptimizer/PassManager/Passes.def

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -140,8 +140,8 @@ PASS(DCE, "dce",
140140
"Dead Code Elimination")
141141
PASS(DeadArgSignatureOpt, "dead-arg-signature-opt",
142142
"Dead Argument Elimination via Function Specialization")
143-
PASS(DeadFunctionElimination, "sil-deadfuncelim",
144-
"Dead Function Elimination")
143+
PASS(DeadFunctionAndGlobalElimination, "sil-deadfuncelim",
144+
"Dead Function and Global Variable Elimination")
145145
PASS(DeadObjectElimination, "deadobject-elim",
146146
"Dead Object Elimination for Classes with Trivial Destruction")
147147
PASS(DefiniteInitialization, "definite-init",
@@ -220,8 +220,8 @@ PASS(LICM, "licm",
220220
"Loop Invariant Code Motion")
221221
PASS(LateCodeMotion, "late-codemotion",
222222
"Late Code Motion with Release Hoisting")
223-
PASS(LateDeadFunctionElimination, "late-deadfuncelim",
224-
"Late Dead Function Elimination")
223+
PASS(LateDeadFunctionAndGlobalElimination, "late-deadfuncelim",
224+
"Late Dead Function and Global Elimination")
225225
PASS(LateInliner, "late-inline",
226226
"Late Function Inlining")
227227
PASS(LoopCanonicalizer, "loop-canonicalizer",

include/swift/SILOptimizer/Utils/BasicBlockOptUtils.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -320,7 +320,9 @@ class StaticInitCloner : public SILCloner<StaticInitCloner> {
320320
/// Add \p InitVal and all its operands (transitively) for cloning.
321321
///
322322
/// Note: all init values must are added, before calling clone().
323-
void add(SILInstruction *initVal);
323+
/// Returns false if cloning is not possible, e.g. if we would end up cloning
324+
/// a reference to a private function into a function which is serialized.
325+
bool add(SILInstruction *initVal);
324326

325327
/// Clone \p InitVal and all its operands into the initializer of the
326328
/// SILGlobalVariable.
@@ -332,7 +334,9 @@ class StaticInitCloner : public SILCloner<StaticInitCloner> {
332334
static void appendToInitializer(SILGlobalVariable *gVar,
333335
SingleValueInstruction *initVal) {
334336
StaticInitCloner cloner(gVar);
335-
cloner.add(initVal);
337+
bool success = cloner.add(initVal);
338+
(void)success;
339+
assert(success && "adding initVal cannot fail for a global variable");
336340
cloner.clone(initVal);
337341
}
338342

lib/IRGen/GenConstant.cpp

Lines changed: 89 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include "GenTuple.h"
2323
#include "TypeInfo.h"
2424
#include "StructLayout.h"
25+
#include "Callee.h"
2526
#include "swift/Basic/Range.h"
2627
#include "swift/SIL/SILModule.h"
2728

@@ -109,11 +110,67 @@ llvm::Constant *irgen::emitAddrOfConstantString(IRGenModule &IGM,
109110
llvm_unreachable("bad string encoding");
110111
}
111112

112-
static llvm::Constant *emitConstantValue(IRGenModule &IGM, SILValue operand) {
113+
namespace {
114+
115+
/// Fill in the missing values for padding.
116+
void insertPadding(SmallVectorImpl<llvm::Constant *> &Elements,
117+
llvm::StructType *sTy) {
118+
// fill in any gaps, which are the explicit padding that swiftc inserts.
119+
for (unsigned i = 0, e = Elements.size(); i != e; ++i) {
120+
auto &elt = Elements[i];
121+
if (elt == nullptr) {
122+
auto *eltTy = sTy->getElementType(i);
123+
assert(eltTy->isArrayTy() &&
124+
eltTy->getArrayElementType()->isIntegerTy(8) &&
125+
"Unexpected non-byte-array type for constant struct padding");
126+
elt = llvm::UndefValue::get(eltTy);
127+
}
128+
}
129+
}
130+
131+
template <typename InstTy, typename NextIndexFunc>
132+
llvm::Constant *emitConstantStructOrTuple(IRGenModule &IGM, InstTy inst,
133+
NextIndexFunc nextIndex) {
134+
auto type = inst->getType();
135+
auto *sTy = cast<llvm::StructType>(IGM.getTypeInfo(type).getStorageType());
136+
137+
SmallVector<llvm::Constant *, 32> elts(sTy->getNumElements(), nullptr);
138+
139+
// run over the Swift initializers, putting them into the struct as
140+
// appropriate.
141+
for (unsigned i = 0, e = inst->getElements().size(); i != e; ++i) {
142+
auto operand = inst->getOperand(i);
143+
Optional<unsigned> index = nextIndex(IGM, type, i);
144+
if (index.hasValue()) {
145+
assert(elts[index.getValue()] == nullptr &&
146+
"Unexpected constant struct field overlap");
147+
148+
elts[index.getValue()] = emitConstantValue(IGM, operand);
149+
}
150+
}
151+
insertPadding(elts, sTy);
152+
return llvm::ConstantStruct::get(sTy, elts);
153+
}
154+
} // end anonymous namespace
155+
156+
llvm::Constant *irgen::emitConstantValue(IRGenModule &IGM, SILValue operand) {
113157
if (auto *SI = dyn_cast<StructInst>(operand)) {
114-
return emitConstantStruct(IGM, SI);
158+
// The only way to get a struct's stored properties (which we need to map to
159+
// their physical/LLVM index) is to iterate over the properties
160+
// progressively. Fortunately the iteration order matches the order of
161+
// operands in a StructInst.
162+
auto StoredProperties = SI->getStructDecl()->getStoredProperties();
163+
auto Iter = StoredProperties.begin();
164+
165+
return emitConstantStructOrTuple(
166+
IGM, SI, [&Iter](IRGenModule &IGM, SILType Type, unsigned _i) mutable {
167+
(void)_i;
168+
auto *FD = *Iter++;
169+
return irgen::getPhysicalStructFieldIndex(IGM, Type, FD);
170+
});
115171
} else if (auto *TI = dyn_cast<TupleInst>(operand)) {
116-
return emitConstantTuple(IGM, TI);
172+
return emitConstantStructOrTuple(IGM, TI,
173+
irgen::getPhysicalTupleElementStructIndex);
117174
} else if (auto *ILI = dyn_cast<IntegerLiteralInst>(operand)) {
118175
return emitConstantInt(IGM, ILI);
119176
} else if (auto *FLI = dyn_cast<FloatLiteralInst>(operand)) {
@@ -159,73 +216,43 @@ static llvm::Constant *emitConstantValue(IRGenModule &IGM, SILValue operand) {
159216
auto *val = emitConstantValue(IGM, VTBI->getOperand());
160217
auto *sTy = IGM.getTypeInfo(VTBI->getType()).getStorageType();
161218
return llvm::ConstantExpr::getIntToPtr(val, sTy);
162-
} else {
163-
llvm_unreachable("Unsupported SILInstruction in static initializer!");
164-
}
165-
}
166219

167-
namespace {
220+
} else if (auto *CFI = dyn_cast<ConvertFunctionInst>(operand)) {
221+
return emitConstantValue(IGM, CFI->getOperand());
168222

169-
/// Fill in the missing values for padding.
170-
void insertPadding(SmallVectorImpl<llvm::Constant *> &Elements,
171-
llvm::StructType *sTy) {
172-
// fill in any gaps, which are the explicit padding that swiftc inserts.
173-
for (unsigned i = 0, e = Elements.size(); i != e; ++i) {
174-
auto &elt = Elements[i];
175-
if (elt == nullptr) {
176-
auto *eltTy = sTy->getElementType(i);
177-
assert(eltTy->isArrayTy() &&
178-
eltTy->getArrayElementType()->isIntegerTy(8) &&
179-
"Unexpected non-byte-array type for constant struct padding");
180-
elt = llvm::UndefValue::get(eltTy);
181-
}
182-
}
183-
}
223+
} else if (auto *T2TFI = dyn_cast<ThinToThickFunctionInst>(operand)) {
224+
SILType type = operand->getType();
225+
auto *sTy = cast<llvm::StructType>(IGM.getTypeInfo(type).getStorageType());
184226

185-
template <typename InstTy, typename NextIndexFunc>
186-
llvm::Constant *emitConstantStructOrTuple(IRGenModule &IGM, InstTy inst,
187-
NextIndexFunc nextIndex) {
188-
auto type = inst->getType();
189-
auto *sTy = cast<llvm::StructType>(IGM.getTypeInfo(type).getStorageType());
227+
auto *function = llvm::ConstantExpr::getBitCast(
228+
emitConstantValue(IGM, T2TFI->getCallee()),
229+
sTy->getTypeAtIndex((unsigned)0));
190230

191-
SmallVector<llvm::Constant *, 32> elts(sTy->getNumElements(), nullptr);
231+
auto *context = llvm::ConstantExpr::getBitCast(
232+
llvm::ConstantPointerNull::get(IGM.OpaquePtrTy),
233+
sTy->getTypeAtIndex((unsigned)1));
234+
235+
return llvm::ConstantStruct::get(sTy, {function, context});
192236

193-
// run over the Swift initializers, putting them into the struct as
194-
// appropriate.
195-
for (unsigned i = 0, e = inst->getElements().size(); i != e; ++i) {
196-
auto operand = inst->getOperand(i);
197-
Optional<unsigned> index = nextIndex(IGM, type, i);
198-
if (index.hasValue()) {
199-
assert(elts[index.getValue()] == nullptr &&
200-
"Unexpected constant struct field overlap");
237+
} else if (auto *FRI = dyn_cast<FunctionRefInst>(operand)) {
238+
SILFunction *fn = FRI->getReferencedFunction();
201239

202-
elts[index.getValue()] = emitConstantValue(IGM, operand);
240+
llvm::Constant *fnPtr = IGM.getAddrOfSILFunction(fn, NotForDefinition);
241+
assert(!fn->isAsync() && "TODO: support async functions");
242+
243+
CanSILFunctionType fnType = FRI->getType().getAs<SILFunctionType>();
244+
auto authInfo = PointerAuthInfo::forFunctionPointer(IGM, fnType);
245+
if (authInfo.isSigned()) {
246+
auto constantDiscriminator =
247+
cast<llvm::Constant>(authInfo.getDiscriminator());
248+
assert(!constantDiscriminator->getType()->isPointerTy());
249+
fnPtr = IGM.getConstantSignedPointer(fnPtr, authInfo.getKey(), nullptr,
250+
constantDiscriminator);
203251
}
252+
return fnPtr;
253+
} else {
254+
llvm_unreachable("Unsupported SILInstruction in static initializer!");
204255
}
205-
insertPadding(elts, sTy);
206-
return llvm::ConstantStruct::get(sTy, elts);
207-
}
208-
} // end anonymous namespace
209-
210-
llvm::Constant *irgen::emitConstantStruct(IRGenModule &IGM, StructInst *SI) {
211-
// The only way to get a struct's stored properties (which we need to map to
212-
// their physical/LLVM index) is to iterate over the properties
213-
// progressively. Fortunately the iteration order matches the order of
214-
// operands in a StructInst.
215-
auto StoredProperties = SI->getStructDecl()->getStoredProperties();
216-
auto Iter = StoredProperties.begin();
217-
218-
return emitConstantStructOrTuple(
219-
IGM, SI, [&Iter](IRGenModule &IGM, SILType Type, unsigned _i) mutable {
220-
(void)_i;
221-
auto *FD = *Iter++;
222-
return irgen::getPhysicalStructFieldIndex(IGM, Type, FD);
223-
});
224-
}
225-
226-
llvm::Constant *irgen::emitConstantTuple(IRGenModule &IGM, TupleInst *TI) {
227-
return emitConstantStructOrTuple(IGM, TI,
228-
irgen::getPhysicalTupleElementStructIndex);
229256
}
230257

231258
llvm::Constant *irgen::emitConstantObject(IRGenModule &IGM, ObjectInst *OI,

lib/IRGen/GenConstant.h

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,8 @@ llvm::Constant *emitConstantFP(IRGenModule &IGM, FloatLiteralInst *FLI);
3737
llvm::Constant *emitAddrOfConstantString(IRGenModule &IGM,
3838
StringLiteralInst *SLI);
3939

40-
/// Construct a struct literal from a StructInst containing constant values.
41-
llvm::Constant *emitConstantStruct(IRGenModule &IGM, StructInst *SI);
42-
43-
/// Construct a struct literal from a TupleInst containing constant values.
44-
llvm::Constant *emitConstantTuple(IRGenModule &IGM, TupleInst *TI);
40+
/// Construct a constant from a SILValue containing constant values.
41+
llvm::Constant *emitConstantValue(IRGenModule &IGM, SILValue value);
4542

4643
/// Construct an object (with a HeapObject header) from an ObjectInst
4744
/// containing constant values.

lib/IRGen/IRGenSIL.cpp

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6414,17 +6414,8 @@ void IRGenModule::emitSILStaticInitializers() {
64146414
continue;
64156415
}
64166416

6417-
// Set the IR global's initializer to the constant for this SIL
6418-
// struct.
6419-
if (auto *SI = dyn_cast<StructInst>(InitValue)) {
6420-
IRGlobal->setInitializer(emitConstantStruct(*this, SI));
6421-
continue;
6422-
}
6423-
6424-
// Set the IR global's initializer to the constant for this SIL
6425-
// tuple.
6426-
auto *TI = cast<TupleInst>(InitValue);
6427-
IRGlobal->setInitializer(emitConstantTuple(*this, TI));
6417+
IRGlobal->setInitializer(
6418+
emitConstantValue(*this, cast<SingleValueInstruction>(InitValue)));
64286419
}
64296420
}
64306421

lib/SIL/IR/Linker.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ void SILLinkerVisitor::visitPartialApplyInst(PartialApplyInst *PAI) {
175175
}
176176

177177
void SILLinkerVisitor::visitFunctionRefInst(FunctionRefInst *FRI) {
178-
maybeAddFunctionToWorklist(FRI->getInitiallyReferencedFunction());
178+
maybeAddFunctionToWorklist(FRI->getReferencedFunction());
179179
}
180180

181181
void SILLinkerVisitor::visitDynamicFunctionRefInst(

0 commit comments

Comments
 (0)