Skip to content
Open
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
17 changes: 17 additions & 0 deletions SwiftCompilerSources/Sources/AST/Conformance.swift
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,23 @@ public struct Conformance: CustomStringConvertible, Hashable, NoReflectionChildr
assert(isConcrete)
return bridged.getAssociatedConformance(assocType.bridged, proto.bridged).conformance
}

// This is a less precise definition of "resilient conformance" because it's
// only used for SIL optimizations -- where it's okay to think a conformance
// is resilient even if IRGen will decide it's not (see
// IRGenModule::isResilientConformance).
public func isResilientConformance(currentModule: ModuleDecl) -> Bool {
let conformanceModule = self.protocol.parentModule
let protocolModule = self.protocol.parentModule

// If the protocol and the conformance are both in the current module,
// they're not resilient.
if conformanceModule == currentModule && protocolModule == currentModule {
return false
}

return true
}
}

public struct ConformanceArray : RandomAccessCollection, CustomReflectable {
Expand Down
1 change: 1 addition & 0 deletions SwiftCompilerSources/Sources/AST/Declarations.swift
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ final public class ClassDecl: NominalTypeDecl {
final public class ProtocolDecl: NominalTypeDecl {
public var requiresClass: Bool { bridged.ProtocolDecl_requiresClass() }
public var isMarkerProtocol: Bool { bridged.ProtocolDecl_isMarkerProtocol() }
public var isInvertible: Bool { bridged.ProtocolDecl_isInvertible() }
}

final public class BuiltinTupleDecl: NominalTypeDecl {}
Expand Down
21 changes: 21 additions & 0 deletions SwiftCompilerSources/Sources/Optimizer/Utilities/OptUtils.swift
Original file line number Diff line number Diff line change
Expand Up @@ -503,6 +503,27 @@ extension Instruction {
}
case let gvi as GlobalValueInst:
return context.canMakeStaticObjectReadOnly(objectType: gvi.type)

// Metatypes (and upcasts of them to existentials) can be used as static initializers for SE-0492, as long as they
// do not require an accessor to reference the metadata (i.e. are not generic, not resilient and not a class).
// See also irgen::isCanonicalCompleteTypeMetadataStaticallyAddressable.
case let mti as MetatypeInst:
let silType = mti.type.loweredInstanceTypeOfMetatype(in: parentFunction)
let instanceType = mti.type.canonicalType.instanceTypeOfMetatype
if !mti.type.isGenericAtAnyLevel,
!instanceType.isClass,
let nominal = instanceType.nominal,
!nominal.isGenericAtAnyLevel,
silType.isFixedABI(in: mti.parentFunction) {
return true
}
return false
case let iemi as InitExistentialMetatypeInst:
let isAnyConformanceResilient = iemi.conformances.contains {
!$0.protocol.isInvertible && $0.isResilientConformance(currentModule: context.currentModuleContext)
}
return !iemi.type.isGenericAtAnyLevel && !isAnyConformanceResilient

case is StructInst,
is TupleInst,
is EnumInst,
Expand Down
4 changes: 4 additions & 0 deletions SwiftCompilerSources/Sources/SIL/Instruction.swift
Original file line number Diff line number Diff line change
Expand Up @@ -944,6 +944,10 @@ class OpenExistentialBoxValueInst : SingleValueInstruction, UnaryInstruction {}
final public
class InitExistentialMetatypeInst : SingleValueInstruction, UnaryInstruction {
public var metatype: Value { operand.value }

public var conformances: ConformanceArray {
ConformanceArray(bridged: bridged.InitExistentialMetatypeInst_getConformances())
}
}

final public
Expand Down
4 changes: 4 additions & 0 deletions SwiftCompilerSources/Sources/SIL/Type.swift
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,10 @@ public struct Type : TypeProperties, CustomStringConvertible, NoReflectionChildr
bridged.isAddressableForDeps(function.bridged)
}

public func isFixedABI(in function: Function) -> Bool {
bridged.isFixedABI(function.bridged)
}

/// If this is a raw layout type, returns the substituted like-type.
public var rawLayoutSubstitutedLikeType: AST.`Type`? {
.init(bridgedOrNil: bridged.getRawLayoutSubstitutedLikeType())
Expand Down
1 change: 1 addition & 0 deletions include/swift/AST/ASTBridging.h
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,7 @@ struct BridgedDeclObj {
BRIDGED_INLINE bool Class_isForeign() const;
BRIDGED_INLINE bool ProtocolDecl_requiresClass() const;
BRIDGED_INLINE bool ProtocolDecl_isMarkerProtocol() const;
BRIDGED_INLINE bool ProtocolDecl_isInvertible() const;
BRIDGED_INLINE bool AbstractFunction_isOverridden() const;
BRIDGED_INLINE bool Constructor_isInheritable() const;
BRIDGED_INLINE bool Destructor_isIsolated() const;
Expand Down
4 changes: 4 additions & 0 deletions include/swift/AST/ASTBridgingImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,10 @@ bool BridgedDeclObj::ProtocolDecl_isMarkerProtocol() const {
return getAs<swift::ProtocolDecl>()->isMarkerProtocol();
}

bool BridgedDeclObj::ProtocolDecl_isInvertible() const {
return getAs<swift::ProtocolDecl>()->getInvertibleProtocolKind() != std::nullopt;
}

bool BridgedDeclObj::AbstractFunction_isOverridden() const {
return getAs<swift::AbstractFunctionDecl>()->isOverridden();
}
Expand Down
2 changes: 2 additions & 0 deletions include/swift/SIL/SILBridging.h
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,7 @@ struct BridgedType {
BRIDGED_INLINE bool isExactSuperclassOf(BridgedType t) const;
BRIDGED_INLINE bool isMarkedAsImmortal() const;
BRIDGED_INLINE bool isAddressableForDeps(BridgedFunction f) const;
BRIDGED_INLINE bool isFixedABI(BridgedFunction f) const;
BRIDGED_INLINE SWIFT_IMPORT_UNSAFE BridgedASTType getRawLayoutSubstitutedLikeType() const;
BRIDGED_INLINE SWIFT_IMPORT_UNSAFE BridgedASTType getRawLayoutSubstitutedCountType() const;
BRIDGED_INLINE bool mayHaveCustomDeinit(BridgedFunction f) const;
Expand Down Expand Up @@ -810,6 +811,7 @@ struct BridgedInstruction {
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedCanType InitExistentialRefInst_getFormalConcreteType() const;
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedConformanceArray InitExistentialAddrInst_getConformances() const;
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedCanType InitExistentialAddrInst_getFormalConcreteType() const;
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedConformanceArray InitExistentialMetatypeInst_getConformances() const;
BRIDGED_INLINE bool OpenExistentialAddr_isImmutable() const;
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedGlobalVar GlobalAccessInst_getGlobal() const;
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedGlobalVar AllocGlobalInst_getGlobal() const;
Expand Down
8 changes: 8 additions & 0 deletions include/swift/SIL/SILBridgingImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -402,6 +402,10 @@ bool BridgedType::isAddressableForDeps(BridgedFunction f) const {
return unbridged().isAddressableForDeps(*f.getFunction());
}

bool BridgedType::isFixedABI(BridgedFunction f) const {
return unbridged().isFixedABI(*f.getFunction());
}

BridgedASTType BridgedType::getRawLayoutSubstitutedLikeType() const {
return {unbridged().getRawLayoutSubstitutedLikeType().getPointer()};
}
Expand Down Expand Up @@ -1296,6 +1300,10 @@ BridgedCanType BridgedInstruction::InitExistentialAddrInst_getFormalConcreteType
return getAs<swift::InitExistentialAddrInst>()->getFormalConcreteType();
}

BridgedConformanceArray BridgedInstruction::InitExistentialMetatypeInst_getConformances() const {
return {getAs<swift::InitExistentialMetatypeInst>()->getConformances()};
}

bool BridgedInstruction::OpenExistentialAddr_isImmutable() const {
switch (getAs<swift::OpenExistentialAddrInst>()->getAccessKind()) {
case swift::OpenedExistentialAccess::Immutable: return true;
Expand Down
9 changes: 9 additions & 0 deletions include/swift/SIL/SILBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -2155,6 +2155,11 @@ class SILBuilder {
createInitExistentialMetatype(SILLocation Loc, SILValue metatype,
SILType existentialType,
ArrayRef<ProtocolConformanceRef> conformances) {
if (isInsertingIntoGlobal()) {
return insert(InitExistentialMetatypeInst::create(
getSILDebugLocation(Loc), existentialType, metatype, conformances,
getModule()));
}
return insert(InitExistentialMetatypeInst::create(
getSILDebugLocation(Loc), existentialType, metatype, conformances,
&getFunction()));
Expand Down Expand Up @@ -2289,6 +2294,10 @@ class SILBuilder {
}

MetatypeInst *createMetatype(SILLocation Loc, SILType Metatype) {
if (isInsertingIntoGlobal()) {
return insert(MetatypeInst::create(getSILDebugLocation(Loc), Metatype,
getModule()));
}
return insert(MetatypeInst::create(getSILDebugLocation(Loc), Metatype,
&getFunction()));
}
Expand Down
8 changes: 8 additions & 0 deletions include/swift/SIL/SILInstruction.h
Original file line number Diff line number Diff line change
Expand Up @@ -7509,6 +7509,9 @@ class MetatypeInst final
ArrayRef<SILValue> TypeDependentOperands)
: NullaryInstructionWithTypeDependentOperandsBase(DebugLoc,
TypeDependentOperands, Metatype) {}

static MetatypeInst *create(SILDebugLocation DebugLoc, SILType Metatype,
SILModule &Mod);

static MetatypeInst *create(SILDebugLocation DebugLoc, SILType Metatype,
SILFunction *F);
Expand Down Expand Up @@ -8186,6 +8189,11 @@ class InitExistentialMetatypeInst final
ArrayRef<SILValue> TypeDependentOperands,
ArrayRef<ProtocolConformanceRef> conformances);

static InitExistentialMetatypeInst *
create(SILDebugLocation DebugLoc, SILType existentialMetatypeType,
SILValue metatype, ArrayRef<ProtocolConformanceRef> conformances,
SILModule &mod);

static InitExistentialMetatypeInst *
create(SILDebugLocation DebugLoc, SILType existentialMetatypeType,
SILValue metatype, ArrayRef<ProtocolConformanceRef> conformances,
Expand Down
24 changes: 24 additions & 0 deletions lib/IRGen/GenConstant.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,11 @@
#include "Explosion.h"
#include "GenConstant.h"
#include "GenEnum.h"
#include "GenExistential.h"
#include "GenIntegerLiteral.h"
#include "GenStruct.h"
#include "GenTuple.h"
#include "MetadataRequest.h"
#include "TypeInfo.h"
#include "StructLayout.h"
#include "Callee.h"
Expand All @@ -31,9 +33,11 @@
#include "swift/IRGen/Linking.h"
#include "swift/Basic/Assertions.h"
#include "swift/Basic/Range.h"
#include "swift/SIL/SILInstruction.h"
#include "swift/SIL/SILModule.h"
#include "llvm/Analysis/ConstantFolding.h"
#include "llvm/Support/BLAKE3.h"
#include "llvm/Support/ErrorHandling.h"

using namespace swift;
using namespace irgen;
Expand Down Expand Up @@ -414,6 +418,26 @@ Explosion irgen::emitConstantValue(IRGenModule &IGM, SILValue operand,
assert(ti.isFixedSize(expansion));
Address addr = IGM.getAddrOfSILGlobalVariable(var, ti, NotForDefinition);
return addr.getAddress();
} else if (auto *mti = dyn_cast<MetatypeInst>(operand)) {
auto metaTy = mti->getType().castTo<MetatypeType>();
auto type = metaTy.getInstanceType();
ASSERT(isCanonicalCompleteTypeMetadataStaticallyAddressable(IGM, type));
return IGM.getAddrOfTypeMetadata(type);
} else if (auto *iemi = dyn_cast<InitExistentialMetatypeInst>(operand)) {
auto *mti =
dyn_cast<MetatypeInst>(iemi->getOperand().getDefiningInstruction());
ASSERT(mti != nullptr && "couldn't constant fold initializer expression");

auto metaTy = mti->getType().castTo<MetatypeType>();
auto type = metaTy.getInstanceType();
ASSERT(isCanonicalCompleteTypeMetadataStaticallyAddressable(IGM, type));
llvm::Constant *metadata = IGM.getAddrOfTypeMetadata(type);

Explosion result;
emitExistentialMetatypeContainer(IGM, result, iemi->getType(), metadata,
iemi->getOperand()->getType(),
iemi->getConformances());
return result;
} else if (auto *atp = dyn_cast<AddressToPointerInst>(operand)) {
auto *val = emitConstantValue(IGM, atp->getOperand()).claimNextConstant();
return val;
Expand Down
12 changes: 11 additions & 1 deletion lib/IRGen/GenDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,13 @@
#include "swift/AST/ModuleDependencies.h"
#include "swift/AST/NameLookup.h"
#include "swift/AST/Pattern.h"
#include "swift/AST/PrettyStackTrace.h"
#include "swift/AST/ProtocolConformance.h"
#include "swift/AST/TypeMemberVisitor.h"
#include "swift/AST/Types.h"
#include "swift/Basic/Assertions.h"
#include "swift/Basic/Mangler.h"
#include "swift/Basic/PrettyStackTrace.h"
#include "swift/ClangImporter/ClangModule.h"
#include "swift/Demangling/ManglingMacros.h"
#include "swift/IRGen/Linking.h"
Expand Down Expand Up @@ -2931,6 +2933,9 @@ Address IRGenModule::getAddrOfSILGlobalVariable(SILGlobalVariable *var,
llvm::Constant *IRGenModule::getGlobalInitValue(SILGlobalVariable *var,
llvm::Type *storageType,
Alignment alignment) {
PrettyStackTraceStringAction trace(
"constant-folding init value for SIL global", var->getName());

if (var->isInitializedObject()) {
StructLayout *layout = StaticObjectLayouts[var].layout.get();
ObjectInst *oi = cast<ObjectInst>(var->getStaticInitializerValue());
Expand Down Expand Up @@ -2962,7 +2967,12 @@ llvm::Constant *IRGenModule::getGlobalInitValue(SILGlobalVariable *var,
if (SILInstruction *initInst = var->getStaticInitializerValue()) {
Explosion initExp = emitConstantValue(*this,
cast<SingleValueInstruction>(initInst));
return getConstantValue(std::move(initExp), /*paddingBytes=*/ 0);
llvm::Constant *initVal = getConstantValue(std::move(initExp), /*paddingBytes=*/ 0);
llvm::errs() << "getGlobalInitValue:\n";
var->dump();
initVal->dump();
llvm::errs() << "\n";
return initVal;
}
return nullptr;
}
Expand Down
34 changes: 34 additions & 0 deletions lib/IRGen/GenExistential.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2033,6 +2033,40 @@ void irgen::emitExistentialMetatypeContainer(IRGenFunction &IGF,
});
}

/// Emit an existential metatype container from a metatype value as an
/// explosion of llvm::Constant values (suitable for static initialization).
void irgen::emitExistentialMetatypeContainer(
IRGenModule &IGM, Explosion &out, SILType outType, llvm::Constant *metatype,
SILType metatypeType, ArrayRef<ProtocolConformanceRef> conformances) {
assert(outType.is<ExistentialMetatypeType>());
auto &destTI = IGM.getTypeInfo(outType).as<ExistentialMetatypeTypeInfo>();
out.add(metatype);

auto srcType = metatypeType.castTo<MetatypeType>().getInstanceType();
auto destType = outType.castTo<ExistentialMetatypeType>().getInstanceType();
while (auto destMetatypeType = dyn_cast<ExistentialMetatypeType>(destType)) {
destType = destMetatypeType.getInstanceType();
srcType = cast<AnyMetatypeType>(srcType).getInstanceType();
}

// Emit the witness table pointers as constants.
for (auto protocol : destTI.getStoredProtocols()) {
// Find the corresponding conformance
ProtocolConformanceRef conformance;
for (auto conf : conformances) {
if (conf.getProtocol() == protocol) {
conformance = conf;
break;
}
}
assert(conformance.isConcrete() && "missing conformance");

// Emit witness table constant
auto table = IGM.getAddrOfWitnessTable(conformance.getConcrete());
out.add(table);
}
}

void irgen::emitMetatypeOfOpaqueExistential(IRGenFunction &IGF, Address buffer,
SILType type, Explosion &out) {
assert(type.isExistentialType());
Expand Down
25 changes: 15 additions & 10 deletions lib/IRGen/GenExistential.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ namespace irgen {
class Address;
class Explosion;
class IRGenFunction;
class IRGenModule;

/// Emit the metadata and witness table initialization for an allocated
/// opaque existential container.
Expand All @@ -44,16 +45,20 @@ namespace irgen {
SILType loweredSrcType,
ArrayRef<ProtocolConformanceRef> conformances);

/// Emit an existential metatype container from a metatype value
/// as an explosion.
void emitExistentialMetatypeContainer(IRGenFunction &IGF,
Explosion &out,
SILType outType,
llvm::Value *metatype,
SILType metatypeType,
ArrayRef<ProtocolConformanceRef> conformances);


/// Emit an existential metatype container from a metatype value as an
/// explosion.
void emitExistentialMetatypeContainer(
IRGenFunction &IGF, Explosion &out, SILType outType,
llvm::Value *metatype, SILType metatypeType,
ArrayRef<ProtocolConformanceRef> conformances);

/// Emit an existential metatype container from a metatype value as an
/// explosion of llvm::Constant values (suitable for static initialization).
void emitExistentialMetatypeContainer(
IRGenModule &IGM, Explosion &out, SILType outType,
llvm::Constant *metatype, SILType metatypeType,
ArrayRef<ProtocolConformanceRef> conformances);

/// Emit a class existential container from a class instance value
/// as an explosion.
void emitClassExistentialContainer(IRGenFunction &IGF,
Expand Down
18 changes: 18 additions & 0 deletions lib/SIL/IR/SILInstructions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2328,6 +2328,17 @@ InitExistentialMetatypeInst::InitExistentialMetatypeInst(
getTrailingObjects<ProtocolConformanceRef>());
}

InitExistentialMetatypeInst *InitExistentialMetatypeInst::create(
SILDebugLocation Loc, SILType existentialMetatypeType, SILValue metatype,
ArrayRef<ProtocolConformanceRef> conformances, SILModule &M) {
unsigned size = totalSizeToAlloc<swift::Operand, ProtocolConformanceRef>(
1, conformances.size());
void *buffer = M.allocateInst(size, alignof(InitExistentialMetatypeInst));
return ::new (buffer) InitExistentialMetatypeInst(
Loc, existentialMetatypeType, metatype,
{}, conformances);
}

InitExistentialMetatypeInst *InitExistentialMetatypeInst::create(
SILDebugLocation Loc, SILType existentialMetatypeType, SILValue metatype,
ArrayRef<ProtocolConformanceRef> conformances, SILFunction *F) {
Expand Down Expand Up @@ -2738,6 +2749,13 @@ CheckedCastBranchInst *CheckedCastBranchInst::create(
Target2Count, forwardingOwnershipKind, preservesOwnership);
}

MetatypeInst *MetatypeInst::create(SILDebugLocation Loc, SILType Ty,
SILModule &Mod) {
auto Size = totalSizeToAlloc<swift::Operand>(1);
auto Buffer = Mod.allocateInst(Size, alignof(MetatypeInst));
return ::new (Buffer) MetatypeInst(Loc, Ty, {});
}

MetatypeInst *MetatypeInst::create(SILDebugLocation Loc, SILType Ty,
SILFunction *F) {
SILModule &Mod = F->getModule();
Expand Down
Loading