Skip to content

SILOptimizer: allow function pointers in static globals and static global arrays. #35780

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Feb 10, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions include/swift/SIL/SILBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,8 @@ class SILBuilder {
bool isInsertingIntoGlobal() const { return F == nullptr; }

TypeExpansionContext getTypeExpansionContext() const {
if (!F)
return TypeExpansionContext::minimal();
return TypeExpansionContext(getFunction());
}

Expand Down Expand Up @@ -1027,7 +1029,7 @@ class SILBuilder {
SILType Ty,
bool WithoutActuallyEscaping) {
return insert(ConvertFunctionInst::create(getSILDebugLocation(Loc), Op, Ty,
getFunction(), C.OpenedArchetypes,
getModule(), F, C.OpenedArchetypes,
WithoutActuallyEscaping));
}

Expand Down Expand Up @@ -1157,7 +1159,7 @@ class SILBuilder {
ThinToThickFunctionInst *createThinToThickFunction(SILLocation Loc,
SILValue Op, SILType Ty) {
return insert(ThinToThickFunctionInst::create(
getSILDebugLocation(Loc), Op, Ty, getFunction(), C.OpenedArchetypes));
getSILDebugLocation(Loc), Op, Ty, getModule(), F, C.OpenedArchetypes));
}

ThickToObjCMetatypeInst *createThickToObjCMetatype(SILLocation Loc,
Expand Down
2 changes: 1 addition & 1 deletion include/swift/SIL/SILCloner.h
Original file line number Diff line number Diff line change
Expand Up @@ -967,7 +967,7 @@ template<typename ImplClass>
void
SILCloner<ImplClass>::visitFunctionRefInst(FunctionRefInst *Inst) {
SILFunction *OpFunction =
getOpFunction(Inst->getInitiallyReferencedFunction());
getOpFunction(Inst->getReferencedFunction());
getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope()));
recordClonedInstruction(Inst, getBuilder().createFunctionRef(
getOpLocation(Inst->getLoc()), OpFunction));
Expand Down
4 changes: 4 additions & 0 deletions include/swift/SIL/SILGlobalVariable.h
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,10 @@ class SILGlobalVariable
SILLinkage getLinkage() const { return SILLinkage(Linkage); }
void setLinkage(SILLinkage linkage) { Linkage = unsigned(linkage); }

/// Returns true if the linkage of the SILFunction indicates that the global
/// might be referenced from outside the current compilation unit.
bool isPossiblyUsedExternally() const;

/// Get this global variable's serialized attribute.
IsSerialized_t isSerialized() const;
void setSerialized(IsSerialized_t isSerialized);
Expand Down
11 changes: 7 additions & 4 deletions include/swift/SIL/SILInstruction.h
Original file line number Diff line number Diff line change
Expand Up @@ -2756,9 +2756,9 @@ class LiteralInst : public SingleValueInstruction {
};

class FunctionRefBaseInst : public LiteralInst {
protected:
SILFunction *f;

protected:
FunctionRefBaseInst(SILInstructionKind Kind, SILDebugLocation DebugLoc,
SILFunction *F, TypeExpansionContext context);

Expand Down Expand Up @@ -2819,6 +2819,9 @@ class FunctionRefInst : public FunctionRefBaseInst {
TypeExpansionContext context);

public:
/// Return the referenced function.
SILFunction *getReferencedFunction() const { return f; }

static bool classof(SILNodePointer node) {
return node->getKind() == SILNodeKind::FunctionRefInst;
}
Expand Down Expand Up @@ -4812,7 +4815,7 @@ class ConvertFunctionInst final

static ConvertFunctionInst *create(SILDebugLocation DebugLoc,
SILValue Operand, SILType Ty,
SILFunction &F,
SILModule &Mod, SILFunction *F,
SILOpenedArchetypesState &OpenedArchetypes,
bool WithoutActuallyEscaping);

Expand Down Expand Up @@ -5162,8 +5165,8 @@ class ThinToThickFunctionInst final
Operand.getOwnershipKind()) {}

static ThinToThickFunctionInst *
create(SILDebugLocation DebugLoc, SILValue Operand, SILType Ty,
SILFunction &F, SILOpenedArchetypesState &OpenedArchetypes);
create(SILDebugLocation DebugLoc, SILValue Operand, SILType Ty, SILModule &Mod,
SILFunction *F, SILOpenedArchetypesState &OpenedArchetypes);

public:
/// Return the callee of the thin_to_thick_function.
Expand Down
2 changes: 1 addition & 1 deletion include/swift/SIL/TypeSubstCloner.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ class TypeSubstCloner : public SILClonerWithScopes<ImplClass> {

if (!Cloner.Inlining) {
FunctionRefInst *FRI = dyn_cast<FunctionRefInst>(AI.getCallee());
if (FRI && FRI->getInitiallyReferencedFunction() == AI.getFunction() &&
if (FRI && FRI->getReferencedFunction() == AI.getFunction() &&
Subs == Cloner.SubsMap) {
// Handle recursions by replacing the apply to the callee with an
// apply to the newly specialized function, but only if substitutions
Expand Down
8 changes: 4 additions & 4 deletions include/swift/SILOptimizer/PassManager/Passes.def
Original file line number Diff line number Diff line change
Expand Up @@ -140,8 +140,8 @@ PASS(DCE, "dce",
"Dead Code Elimination")
PASS(DeadArgSignatureOpt, "dead-arg-signature-opt",
"Dead Argument Elimination via Function Specialization")
PASS(DeadFunctionElimination, "sil-deadfuncelim",
"Dead Function Elimination")
PASS(DeadFunctionAndGlobalElimination, "sil-deadfuncelim",
"Dead Function and Global Variable Elimination")
PASS(DeadObjectElimination, "deadobject-elim",
"Dead Object Elimination for Classes with Trivial Destruction")
PASS(DefiniteInitialization, "definite-init",
Expand Down Expand Up @@ -220,8 +220,8 @@ PASS(LICM, "licm",
"Loop Invariant Code Motion")
PASS(LateCodeMotion, "late-codemotion",
"Late Code Motion with Release Hoisting")
PASS(LateDeadFunctionElimination, "late-deadfuncelim",
"Late Dead Function Elimination")
PASS(LateDeadFunctionAndGlobalElimination, "late-deadfuncelim",
"Late Dead Function and Global Elimination")
PASS(LateInliner, "late-inline",
"Late Function Inlining")
PASS(LoopCanonicalizer, "loop-canonicalizer",
Expand Down
8 changes: 6 additions & 2 deletions include/swift/SILOptimizer/Utils/BasicBlockOptUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,9 @@ class StaticInitCloner : public SILCloner<StaticInitCloner> {
/// Add \p InitVal and all its operands (transitively) for cloning.
///
/// Note: all init values must are added, before calling clone().
void add(SILInstruction *initVal);
/// Returns false if cloning is not possible, e.g. if we would end up cloning
/// a reference to a private function into a function which is serialized.
bool add(SILInstruction *initVal);

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

Expand Down
151 changes: 89 additions & 62 deletions lib/IRGen/GenConstant.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include "GenTuple.h"
#include "TypeInfo.h"
#include "StructLayout.h"
#include "Callee.h"
#include "swift/Basic/Range.h"
#include "swift/SIL/SILModule.h"

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

static llvm::Constant *emitConstantValue(IRGenModule &IGM, SILValue operand) {
namespace {

/// Fill in the missing values for padding.
void insertPadding(SmallVectorImpl<llvm::Constant *> &Elements,
llvm::StructType *sTy) {
// fill in any gaps, which are the explicit padding that swiftc inserts.
for (unsigned i = 0, e = Elements.size(); i != e; ++i) {
auto &elt = Elements[i];
if (elt == nullptr) {
auto *eltTy = sTy->getElementType(i);
assert(eltTy->isArrayTy() &&
eltTy->getArrayElementType()->isIntegerTy(8) &&
"Unexpected non-byte-array type for constant struct padding");
elt = llvm::UndefValue::get(eltTy);
}
}
}

template <typename InstTy, typename NextIndexFunc>
llvm::Constant *emitConstantStructOrTuple(IRGenModule &IGM, InstTy inst,
NextIndexFunc nextIndex) {
auto type = inst->getType();
auto *sTy = cast<llvm::StructType>(IGM.getTypeInfo(type).getStorageType());

SmallVector<llvm::Constant *, 32> elts(sTy->getNumElements(), nullptr);

// run over the Swift initializers, putting them into the struct as
// appropriate.
for (unsigned i = 0, e = inst->getElements().size(); i != e; ++i) {
auto operand = inst->getOperand(i);
Optional<unsigned> index = nextIndex(IGM, type, i);
if (index.hasValue()) {
assert(elts[index.getValue()] == nullptr &&
"Unexpected constant struct field overlap");

elts[index.getValue()] = emitConstantValue(IGM, operand);
}
}
insertPadding(elts, sTy);
return llvm::ConstantStruct::get(sTy, elts);
}
} // end anonymous namespace

llvm::Constant *irgen::emitConstantValue(IRGenModule &IGM, SILValue operand) {
if (auto *SI = dyn_cast<StructInst>(operand)) {
return emitConstantStruct(IGM, SI);
// The only way to get a struct's stored properties (which we need to map to
// their physical/LLVM index) is to iterate over the properties
// progressively. Fortunately the iteration order matches the order of
// operands in a StructInst.
auto StoredProperties = SI->getStructDecl()->getStoredProperties();
auto Iter = StoredProperties.begin();

return emitConstantStructOrTuple(
IGM, SI, [&Iter](IRGenModule &IGM, SILType Type, unsigned _i) mutable {
(void)_i;
auto *FD = *Iter++;
return irgen::getPhysicalStructFieldIndex(IGM, Type, FD);
});
} else if (auto *TI = dyn_cast<TupleInst>(operand)) {
return emitConstantTuple(IGM, TI);
return emitConstantStructOrTuple(IGM, TI,
irgen::getPhysicalTupleElementStructIndex);
} else if (auto *ILI = dyn_cast<IntegerLiteralInst>(operand)) {
return emitConstantInt(IGM, ILI);
} else if (auto *FLI = dyn_cast<FloatLiteralInst>(operand)) {
Expand Down Expand Up @@ -159,73 +216,43 @@ static llvm::Constant *emitConstantValue(IRGenModule &IGM, SILValue operand) {
auto *val = emitConstantValue(IGM, VTBI->getOperand());
auto *sTy = IGM.getTypeInfo(VTBI->getType()).getStorageType();
return llvm::ConstantExpr::getIntToPtr(val, sTy);
} else {
llvm_unreachable("Unsupported SILInstruction in static initializer!");
}
}

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

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

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

SmallVector<llvm::Constant *, 32> elts(sTy->getNumElements(), nullptr);
auto *context = llvm::ConstantExpr::getBitCast(
llvm::ConstantPointerNull::get(IGM.OpaquePtrTy),
sTy->getTypeAtIndex((unsigned)1));

return llvm::ConstantStruct::get(sTy, {function, context});

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

elts[index.getValue()] = emitConstantValue(IGM, operand);
llvm::Constant *fnPtr = IGM.getAddrOfSILFunction(fn, NotForDefinition);
assert(!fn->isAsync() && "TODO: support async functions");

CanSILFunctionType fnType = FRI->getType().getAs<SILFunctionType>();
auto authInfo = PointerAuthInfo::forFunctionPointer(IGM, fnType);
if (authInfo.isSigned()) {
auto constantDiscriminator =
cast<llvm::Constant>(authInfo.getDiscriminator());
assert(!constantDiscriminator->getType()->isPointerTy());
fnPtr = IGM.getConstantSignedPointer(fnPtr, authInfo.getKey(), nullptr,
constantDiscriminator);
}
return fnPtr;
} else {
llvm_unreachable("Unsupported SILInstruction in static initializer!");
}
insertPadding(elts, sTy);
return llvm::ConstantStruct::get(sTy, elts);
}
} // end anonymous namespace

llvm::Constant *irgen::emitConstantStruct(IRGenModule &IGM, StructInst *SI) {
// The only way to get a struct's stored properties (which we need to map to
// their physical/LLVM index) is to iterate over the properties
// progressively. Fortunately the iteration order matches the order of
// operands in a StructInst.
auto StoredProperties = SI->getStructDecl()->getStoredProperties();
auto Iter = StoredProperties.begin();

return emitConstantStructOrTuple(
IGM, SI, [&Iter](IRGenModule &IGM, SILType Type, unsigned _i) mutable {
(void)_i;
auto *FD = *Iter++;
return irgen::getPhysicalStructFieldIndex(IGM, Type, FD);
});
}

llvm::Constant *irgen::emitConstantTuple(IRGenModule &IGM, TupleInst *TI) {
return emitConstantStructOrTuple(IGM, TI,
irgen::getPhysicalTupleElementStructIndex);
}

llvm::Constant *irgen::emitConstantObject(IRGenModule &IGM, ObjectInst *OI,
Expand Down
7 changes: 2 additions & 5 deletions lib/IRGen/GenConstant.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,8 @@ llvm::Constant *emitConstantFP(IRGenModule &IGM, FloatLiteralInst *FLI);
llvm::Constant *emitAddrOfConstantString(IRGenModule &IGM,
StringLiteralInst *SLI);

/// Construct a struct literal from a StructInst containing constant values.
llvm::Constant *emitConstantStruct(IRGenModule &IGM, StructInst *SI);

/// Construct a struct literal from a TupleInst containing constant values.
llvm::Constant *emitConstantTuple(IRGenModule &IGM, TupleInst *TI);
/// Construct a constant from a SILValue containing constant values.
llvm::Constant *emitConstantValue(IRGenModule &IGM, SILValue value);

/// Construct an object (with a HeapObject header) from an ObjectInst
/// containing constant values.
Expand Down
13 changes: 2 additions & 11 deletions lib/IRGen/IRGenSIL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6414,17 +6414,8 @@ void IRGenModule::emitSILStaticInitializers() {
continue;
}

// Set the IR global's initializer to the constant for this SIL
// struct.
if (auto *SI = dyn_cast<StructInst>(InitValue)) {
IRGlobal->setInitializer(emitConstantStruct(*this, SI));
continue;
}

// Set the IR global's initializer to the constant for this SIL
// tuple.
auto *TI = cast<TupleInst>(InitValue);
IRGlobal->setInitializer(emitConstantTuple(*this, TI));
IRGlobal->setInitializer(
emitConstantValue(*this, cast<SingleValueInstruction>(InitValue)));
}
}

Expand Down
2 changes: 1 addition & 1 deletion lib/SIL/IR/Linker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ void SILLinkerVisitor::visitPartialApplyInst(PartialApplyInst *PAI) {
}

void SILLinkerVisitor::visitFunctionRefInst(FunctionRefInst *FRI) {
maybeAddFunctionToWorklist(FRI->getInitiallyReferencedFunction());
maybeAddFunctionToWorklist(FRI->getReferencedFunction());
}

void SILLinkerVisitor::visitDynamicFunctionRefInst(
Expand Down
Loading