Skip to content
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,14 @@ let mandatoryPerformanceOptimizations = ModulePass(name: "mandatory-performance-
(moduleContext: ModulePassContext) in

var worklist = FunctionWorklist()
worklist.addAllPerformanceAnnotatedFunctions(of: moduleContext)
worklist.addAllAnnotatedGlobalInitOnceFunctions(of: moduleContext)
// For embedded Swift, optimize all the functions (there cannot be any
// generics, type metadata, etc.)
if moduleContext.options.enableEmbeddedSwift {
worklist.addAllNonGenericFunctions(of: moduleContext)
} else {
worklist.addAllPerformanceAnnotatedFunctions(of: moduleContext)
worklist.addAllAnnotatedGlobalInitOnceFunctions(of: moduleContext)
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

addAllPerformanceAnnotatedFunctions and addAllAnnotatedGlobalInitOnceFunctions should be called in the else-branch of this if-statement


optimizeFunctionsTopDown(using: &worklist, moduleContext)
}
Expand Down Expand Up @@ -305,6 +311,13 @@ fileprivate struct FunctionWorklist {
}
}

mutating func addAllNonGenericFunctions(of moduleContext: ModulePassContext) {
for f in moduleContext.functions where f.isGenericFunction {
pushIfNotVisited(f)
}
return
}

mutating func addAllAnnotatedGlobalInitOnceFunctions(of moduleContext: ModulePassContext) {
for f in moduleContext.functions where f.isGlobalInitOnceFunction {
if let global = f.getInitializedGlobal(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ struct Options {
_bridged.enableSimplificationFor(inst.bridged)
}

var enableEmbeddedSwift: Bool {
_bridged.enableEmbeddedSwift()
}

enum AssertConfiguration {
case enabled
case disabled
Expand Down
2 changes: 2 additions & 0 deletions SwiftCompilerSources/Sources/SIL/Function.swift
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,8 @@ final public class Function : CustomStringConvertible, HasShortDescription, Hash
/// It's called from a `[global_init]` function via a `builtin "once"`.
public var isGlobalInitOnceFunction: Bool { bridged.isGlobalInitOnceFunction() }

public var isGenericFunction: Bool { bridged.isGenericFunction() }

/// Kinds of effect attributes which can be defined for a Swift function.
public enum EffectAttribute {
/// No effect attribute is specified.
Expand Down
3 changes: 3 additions & 0 deletions include/swift/AST/DiagnosticsFrontend.def
Original file line number Diff line number Diff line change
Expand Up @@ -554,5 +554,8 @@ ERROR(layout_string_instantiation_without_layout_strings,none,
"-enable-layout-string-value-witnesses-instantiation can not be enabled "
"without -enable-layout-string-value-witnesses.", ())

ERROR(evolution_with_embedded,none,
"Library evolution cannot be enabled with embedded Swift.", ())

#define UNDEFINE_DIAGNOSTIC_MACROS
#include "DefineDiagnosticMacros.h"
3 changes: 3 additions & 0 deletions include/swift/Basic/Features.def
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,9 @@ EXPERIMENTAL_FEATURE(ThenStatements, false)
/// Enable the `@_rawLayout` attribute.
EXPERIMENTAL_FEATURE(RawLayout, true)

/// Enables the "embedded" swift mode (no runtime).
EXPERIMENTAL_FEATURE(Embedded, true)

#undef EXPERIMENTAL_FEATURE_EXCLUDED_FROM_MODULE_INTERFACE
#undef EXPERIMENTAL_FEATURE
#undef UPCOMING_FEATURE
Expand Down
22 changes: 22 additions & 0 deletions include/swift/IRGen/Linking.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,18 @@ enum class TypeMetadataAddress {
FullMetadata,
};

inline bool isEmbedded(CanType t) {
return t->getASTContext().LangOpts.hasFeature(Feature::Embedded);
}

inline bool isEmbedded(Decl *d) {
return d->getASTContext().LangOpts.hasFeature(Feature::Embedded);
}

inline bool isEmbedded(const ProtocolConformance *c) {
return c->getType()->getASTContext().LangOpts.hasFeature(Feature::Embedded);
}

/// A link entity is some sort of named declaration, combined with all
/// the information necessary to distinguish specific implementations
/// of the declaration from each other.
Expand Down Expand Up @@ -828,13 +840,15 @@ class LinkEntity {
static LinkEntity forTypeMetadata(CanType concreteType,
TypeMetadataAddress addr) {
assert(!isObjCImplementation(concreteType));
assert(!isEmbedded(concreteType));
LinkEntity entity;
entity.setForType(Kind::TypeMetadata, concreteType);
entity.Data |= LINKENTITY_SET_FIELD(MetadataAddress, unsigned(addr));
return entity;
}

static LinkEntity forTypeMetadataPattern(NominalTypeDecl *decl) {
assert(!isEmbedded(decl));
LinkEntity entity;
entity.setForDecl(Kind::TypeMetadataPattern, decl);
return entity;
Expand Down Expand Up @@ -891,25 +905,29 @@ class LinkEntity {

static LinkEntity forNominalTypeDescriptor(NominalTypeDecl *decl) {
assert(!isObjCImplementation(decl));
assert(!isEmbedded(decl));
LinkEntity entity;
entity.setForDecl(Kind::NominalTypeDescriptor, decl);
return entity;
}

static LinkEntity forNominalTypeDescriptorRecord(NominalTypeDecl *decl) {
assert(!isObjCImplementation(decl));
assert(!isEmbedded(decl));
LinkEntity entity;
entity.setForDecl(Kind::NominalTypeDescriptorRecord, decl);
return entity;
}

static LinkEntity forOpaqueTypeDescriptor(OpaqueTypeDecl *decl) {
assert(!isEmbedded(decl));
LinkEntity entity;
entity.setForDecl(Kind::OpaqueTypeDescriptor, decl);
return entity;
}

static LinkEntity forOpaqueTypeDescriptorRecord(OpaqueTypeDecl *decl) {
assert(!isEmbedded(decl));
LinkEntity entity;
entity.setForDecl(Kind::OpaqueTypeDescriptorRecord, decl);
return entity;
Expand Down Expand Up @@ -990,6 +1008,7 @@ class LinkEntity {
}

static LinkEntity forValueWitness(CanType concreteType, ValueWitness witness) {
assert(!isEmbedded(concreteType));
LinkEntity entity;
entity.Pointer = concreteType.getPointer();
entity.Data = LINKENTITY_SET_FIELD(Kind, unsigned(Kind::ValueWitness))
Expand All @@ -998,6 +1017,7 @@ class LinkEntity {
}

static LinkEntity forValueWitnessTable(CanType type) {
assert(!isEmbedded(type));
LinkEntity entity;
entity.setForType(Kind::ValueWitnessTable, type);
return entity;
Expand Down Expand Up @@ -1027,13 +1047,15 @@ class LinkEntity {
}

static LinkEntity forProtocolWitnessTable(const RootProtocolConformance *C) {
assert(!isEmbedded(C));
LinkEntity entity;
entity.setForProtocolConformance(Kind::ProtocolWitnessTable, C);
return entity;
}

static LinkEntity
forProtocolWitnessTablePattern(const ProtocolConformance *C) {
assert(!isEmbedded(C));
LinkEntity entity;
entity.setForProtocolConformance(Kind::ProtocolWitnessTablePattern, C);
return entity;
Expand Down
3 changes: 3 additions & 0 deletions include/swift/SIL/RuntimeEffect.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@ enum class RuntimeEffect : unsigned {
/// The runtime function calls ObjectiveC methods.
ObjectiveC = 0x40,

/// Witness methods, boxing, unboxing, initializing, etc.
Existential = 0x80,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@eeckstein can you double check this?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm!


/// Not modelled currently.
Concurrency = 0x0,

Expand Down
4 changes: 4 additions & 0 deletions include/swift/SIL/SILBridging.h
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,10 @@ struct BridgedFunction {
return getFunction()->isGlobalInitOnceFunction();
}

bool isGenericFunction() const {
return getFunction()->getGenericSignature().isNull();
}

bool hasSemanticsAttr(llvm::StringRef attrName) const {
return getFunction()->hasSemanticsAttr(attrName);
}
Expand Down
5 changes: 5 additions & 0 deletions include/swift/SILOptimizer/OptimizerBridging.h
Original file line number Diff line number Diff line change
Expand Up @@ -494,6 +494,11 @@ struct BridgedPassContext {
return mod->getOptions().EnableStackProtection;
}

bool enableEmbeddedSwift() const {
swift::SILModule *mod = invocation->getPassManager()->getModule();
return mod->getASTContext().LangOpts.hasFeature(swift::Feature::Embedded);
}

bool enableMoveInoutStackProtection() const {
swift::SILModule *mod = invocation->getPassManager()->getModule();
return mod->getOptions().EnableMoveInoutStackProtection;
Expand Down
4 changes: 4 additions & 0 deletions lib/AST/ASTPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3148,6 +3148,10 @@ static bool usesFeatureBuiltinStackAlloc(Decl *decl) {
return false;
}

static bool usesFeatureEmbedded(Decl *decl) {
return false;
}

static bool usesFeatureBuiltinUnprotectedStackAlloc(Decl *decl) {
return false;
}
Expand Down
5 changes: 5 additions & 0 deletions lib/Frontend/CompilerInvocation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1316,6 +1316,11 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args,
}
Opts.BypassResilienceChecks |= Args.hasArg(OPT_bypass_resilience);

if (FrontendOpts.EnableLibraryEvolution && Opts.hasFeature(Feature::Embedded)) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kubamracek we want to require whole module optimization, right? That should probably be implicit though. I can add that in a follow-up patch.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

implicit

Not sure about that. I think I would prefer erroring out if WMO is not enabled. (Possibly we could allow building single-file modules without WMO.) Okay to do as a follow-up, yes.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, at least for now we need to require WMO

Diags.diagnose(SourceLoc(), diag::evolution_with_embedded);
HadError = true;
}

return HadError || UnsupportedOS || UnsupportedArch;
}

Expand Down
6 changes: 4 additions & 2 deletions lib/IRGen/GenClass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1075,8 +1075,10 @@ void IRGenModule::emitClassDecl(ClassDecl *D) {
assert(!IRGen.hasLazyMetadata(D));

// Emit the class metadata.
emitClassMetadata(*this, D, fragileLayout, resilientLayout);
emitFieldDescriptor(D);
if (!D->getASTContext().LangOpts.hasFeature(Feature::Embedded)) {
emitClassMetadata(*this, D, fragileLayout, resilientLayout);
emitFieldDescriptor(D);
}

IRGen.addClassForEagerInitialization(D);
IRGen.addBackDeployedObjCActorInitialization(D);
Expand Down
19 changes: 19 additions & 0 deletions lib/IRGen/GenDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1239,6 +1239,13 @@ void IRGenModule::emitGlobalLists() {
// Eagerly emit functions that are externally visible. Functions that are
// dynamic replacements must also be eagerly emitted.
static bool isLazilyEmittedFunction(SILFunction &f, SILModule &m) {
// Embedded Swift only emits specialized function, so don't emit genreic
// functions, even if they're externally visible.
if (f.getASTContext().LangOpts.hasFeature(Feature::Embedded) &&
f.getLoweredFunctionType()->getSubstGenericSignature()) {
return true;
}

if (f.isPossiblyUsedExternally())
return false;

Expand Down Expand Up @@ -1403,6 +1410,18 @@ deleteAndReenqueueForEmissionValuesDependentOnCanonicalPrespecializedMetadataRec
/// Emit any lazy definitions (of globals or functions or whatever
/// else) that we require.
void IRGenerator::emitLazyDefinitions() {
if (SIL.getASTContext().LangOpts.hasFeature(Feature::Embedded)) {
// In embedded Swift, the compiler cannot emit any metadata, etc.
LazyTypeMetadata.clear();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't we assert that those lazy lists are empty?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, but for now we need this for it to compile. Let's make these asserts as a follow up (they will require investigation).

LazySpecializedTypeMetadataRecords.clear();
LazyTypeContextDescriptors.clear();
LazyOpaqueTypeDescriptors.clear();
LazyFunctionDefinitions.clear();
LazyCanonicalSpecializedMetadataAccessors.clear();
LazyMetadataAccessors.clear();
LazyWitnessTables.clear();
}

while (!LazyTypeMetadata.empty() ||
!LazySpecializedTypeMetadataRecords.empty() ||
!LazyTypeContextDescriptors.empty() ||
Expand Down
3 changes: 2 additions & 1 deletion lib/IRGen/GenEnum.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7158,7 +7158,8 @@ const TypeInfo *TypeConverter::convertEnumType(TypeBase *key, CanType type,
}

void IRGenModule::emitEnumDecl(EnumDecl *theEnum) {
if (!IRGen.hasLazyMetadata(theEnum)) {
if (!IRGen.hasLazyMetadata(theEnum) &&
!theEnum->getASTContext().LangOpts.hasFeature(Feature::Embedded)) {
emitEnumMetadata(*this, theEnum);
emitFieldDescriptor(theEnum);
}
Expand Down
5 changes: 5 additions & 0 deletions lib/IRGen/GenExistential.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1780,6 +1780,11 @@ static void forEachProtocolWitnessTable(
assert(protocols.size() == witnessConformances.size() &&
"mismatched protocol conformances");

// Don't emit witness tables in embedded Swift.
if (srcType->getASTContext().LangOpts.hasFeature(Feature::Embedded)) {
return;
}

for (unsigned i = 0, e = protocols.size(); i < e; ++i) {
assert(protocols[i] == witnessConformances[i].getRequirement());
auto table = emitWitnessTableRef(IGF, srcType, srcMetadataCache,
Expand Down
8 changes: 8 additions & 0 deletions lib/IRGen/GenMeta.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2568,6 +2568,10 @@ static void eraseExistingTypeContextDescriptor(IRGenModule &IGM,
void irgen::emitLazyTypeContextDescriptor(IRGenModule &IGM,
NominalTypeDecl *type,
RequireMetadata_t requireMetadata) {
if (type->getASTContext().LangOpts.hasFeature(Feature::Embedded)) {
return;
}

eraseExistingTypeContextDescriptor(IGM, type);

bool hasLayoutString = false;
Expand Down Expand Up @@ -6466,6 +6470,10 @@ SpecialProtocol irgen::getSpecialProtocolID(ProtocolDecl *P) {
void IRGenModule::emitProtocolDecl(ProtocolDecl *protocol) {
PrettyStackTraceDecl stackTraceRAII("emitting metadata for", protocol);

if (protocol->getASTContext().LangOpts.hasFeature(Feature::Embedded)) {
return;
}

// Marker protocols are never emitted.
if (protocol->isMarkerProtocol())
return;
Expand Down
6 changes: 6 additions & 0 deletions lib/IRGen/GenProto.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2394,6 +2394,10 @@ static void addWTableTypeMetadata(IRGenModule &IGM,
}

void IRGenModule::emitSILWitnessTable(SILWitnessTable *wt) {
if (Context.LangOpts.hasFeature(Feature::Embedded)) {
return;
}

// Don't emit a witness table if it is a declaration.
if (wt->isDeclaration())
return;
Expand Down Expand Up @@ -3353,6 +3357,8 @@ llvm::Value *irgen::emitWitnessTableRef(IRGenFunction &IGF,
CanType srcType,
llvm::Value **srcMetadataCache,
ProtocolConformanceRef conformance) {
assert(!srcType->getASTContext().LangOpts.hasFeature(Feature::Embedded));

auto proto = conformance.getRequirement();
assert(Lowering::TypeConverter::protocolRequiresWitnessTable(proto)
&& "protocol does not have witness tables?!");
Expand Down
3 changes: 2 additions & 1 deletion lib/IRGen/GenStruct.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1597,7 +1597,8 @@ const TypeInfo *irgen::getPhysicalStructFieldTypeInfo(IRGenModule &IGM,
}

void IRGenModule::emitStructDecl(StructDecl *st) {
if (!IRGen.hasLazyMetadata(st)) {
if (!IRGen.hasLazyMetadata(st) &&
!st->getASTContext().LangOpts.hasFeature(Feature::Embedded)) {
emitStructMetadata(*this, st);
emitFieldDescriptor(st);
}
Expand Down
2 changes: 2 additions & 0 deletions lib/IRGen/MetadataRequest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3303,6 +3303,8 @@ llvm::Value *IRGenFunction::emitTypeMetadataRef(CanType type) {
MetadataResponse
IRGenFunction::emitTypeMetadataRef(CanType type,
DynamicMetadataRequest request) {
assert(!type->getASTContext().LangOpts.hasFeature(Feature::Embedded));

type = IGM.getRuntimeReifiedType(type);
// Look through any opaque types we're allowed to.
type = IGM.substOpaqueTypesWithUnderlyingTypes(type);
Expand Down
3 changes: 3 additions & 0 deletions lib/SIL/IR/SILSymbolVisitor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -601,6 +601,9 @@ class SILSymbolVisitorImpl : public ASTVisitor<SILSymbolVisitorImpl> {
if (canSkipNominal(NTD))
return;

if (NTD->getASTContext().LangOpts.hasFeature(Feature::Embedded))
return;

auto declaredType = NTD->getDeclaredType()->getCanonicalType();

if (!NTD->getObjCImplementationDecl()) {
Expand Down
Loading