[embedded] Add support for some foreign metadata

This commit is contained in:
Arnold Schwaighofer
2025-12-08 09:43:21 -08:00
parent 93e494bc40
commit d06929ccd2
4 changed files with 166 additions and 15 deletions

View File

@@ -5308,7 +5308,8 @@ llvm::GlobalValue *IRGenModule::defineTypeMetadata(
return cast<llvm::GlobalValue>(addr);
}
bool hasEmbeddedExistentials =
Context.LangOpts.hasFeature(Feature::EmbeddedExistentials);
auto entity =
(isPrespecialized &&
!irgen::isCanonicalInitializableTypeMetadataStaticallyAddressable(
@@ -5324,7 +5325,7 @@ llvm::GlobalValue *IRGenModule::defineTypeMetadata(
if (Context.LangOpts.hasFeature(Feature::Embedded)) {
entity = LinkEntity::forTypeMetadata(concreteType,
TypeMetadataAddress::AddressPoint);
if (Context.LangOpts.hasFeature(Feature::EmbeddedExistentials))
if (hasEmbeddedExistentials)
entity = LinkEntity::forTypeMetadata(concreteType,
TypeMetadataAddress::FullMetadata);
}
@@ -5350,7 +5351,7 @@ llvm::GlobalValue *IRGenModule::defineTypeMetadata(
markGlobalAsUsedBasedOnLinkage(*this, link, var);
if (Context.LangOpts.hasFeature(Feature::Embedded) &&
!Context.LangOpts.hasFeature(Feature::EmbeddedExistentials)) {
!hasEmbeddedExistentials) {
return var;
}
@@ -5361,14 +5362,13 @@ llvm::GlobalValue *IRGenModule::defineTypeMetadata(
if (auto nominal = concreteType->getAnyNominal()) {
// Keep type metadata around for all types (except @_objcImplementation,
// since we're using ObjC metadata for that).
if (!isObjCImpl &&
!Context.LangOpts.hasFeature(Feature::EmbeddedExistentials))
if (!isObjCImpl && !hasEmbeddedExistentials)
addRuntimeResolvableType(nominal);
// Don't define the alias for foreign type metadata, prespecialized
// generic metadata, or @_objcImplementation classes, since they're not ABI.
if (requiresForeignTypeMetadata(nominal) ||
(isPrespecialized && !Context.LangOpts.hasFeature(Feature::EmbeddedExistentials)) ||
if ((requiresForeignTypeMetadata(nominal) && !hasEmbeddedExistentials) ||
(isPrespecialized && !hasEmbeddedExistentials) ||
isObjCImpl)
return var;
@@ -5382,7 +5382,7 @@ llvm::GlobalValue *IRGenModule::defineTypeMetadata(
}
}
if (Context.LangOpts.hasFeature(Feature::EmbeddedExistentials)) {
if (hasEmbeddedExistentials) {
adjustmentIndex = MetadataAdjustmentIndex::EmbeddedWithExistentials;
}

View File

@@ -7202,17 +7202,23 @@ void irgen::emitForeignTypeMetadata(IRGenModule &IGM, NominalTypeDecl *decl) {
auto init = builder.beginStruct();
init.setPacked(true);
auto isEmbedded =
IGM.Context.LangOpts.hasFeature(Feature::EmbeddedExistentials);
if (auto classDecl = dyn_cast<ClassDecl>(decl)) {
if (classDecl->isForeignReferenceType()) {
assert(!isEmbedded && "emitting foregin reference type not supported");
ForeignReferenceTypeMetadataBuilder builder(IGM, classDecl, init);
builder.layout();
IGM.defineTypeMetadata(type, /*isPattern=*/false,
builder.canBeConstant(),
init.finishAndCreateFuture());
builder.createMetadataAccessFunction();
if (!isEmbedded)
builder.createMetadataAccessFunction();
} else {
assert(classDecl->getForeignClassKind() == ClassDecl::ForeignKind::CFType);
assert(!isEmbedded && "emitting foregin cf class type not supported");
ForeignClassMetadataBuilder builder(IGM, classDecl, init);
builder.layout();
@@ -7220,28 +7226,37 @@ void irgen::emitForeignTypeMetadata(IRGenModule &IGM, NominalTypeDecl *decl) {
IGM.defineTypeMetadata(type, /*isPattern=*/false,
builder.canBeConstant(),
init.finishAndCreateFuture());
builder.createMetadataAccessFunction();
if (!isEmbedded)
builder.createMetadataAccessFunction();
}
} else if (auto structDecl = dyn_cast<StructDecl>(decl)) {
assert(isa<ClangModuleUnit>(structDecl->getModuleScopeContext()));
ForeignStructMetadataBuilder builder(IGM, structDecl, init);
builder.layout();
if (isEmbedded)
builder.embeddedLayout();
else
builder.layout();
IGM.defineTypeMetadata(type, /*isPattern=*/false,
builder.canBeConstant(),
init.finishAndCreateFuture());
builder.createMetadataAccessFunction();
if (!isEmbedded)
builder.createMetadataAccessFunction();
} else if (auto enumDecl = dyn_cast<EnumDecl>(decl)) {
assert(enumDecl->hasClangNode());
ForeignEnumMetadataBuilder builder(IGM, enumDecl, init);
builder.layout();
if (isEmbedded)
builder.embeddedLayout();
else
builder.layout();
IGM.defineTypeMetadata(type, /*isPattern=*/false,
builder.canBeConstant(),
init.finishAndCreateFuture());
builder.createMetadataAccessFunction();
if (!isEmbedded)
builder.createMetadataAccessFunction();
} else {
llvm_unreachable("foreign metadata for unexpected type?!");
}

View File

@@ -0,0 +1,34 @@
#pragma once
typedef struct {
unsigned long long f1;
unsigned long long f2;
} SomeCStruct;
static inline SomeCStruct createSomeCStruct() {
SomeCStruct s;
s.f1 = 1;
s.f2 = 2;
return s;
}
typedef enum {
caseA,
caseB,
caseC
} SomeCEnum;
static inline SomeCEnum createSomeCEnum() {
return caseA;
}
#define SWIFT_ENUM(_type, _name) enum _name : _type
typedef SWIFT_ENUM(unsigned short, SomeNSEnum) {
someCaseA,
someCaseB,
} SomeNSEnum;
static inline SomeNSEnum createSomeNSEnum() {
return someCaseB;
}

View File

@@ -0,0 +1,102 @@
// RUN: %target-run-simple-swift(-import-objc-header %S/Inputs/existential_foreign.h -enable-experimental-feature EmbeddedExistentials -enable-experimental-feature Embedded -parse-as-library -wmo) | %FileCheck %s --check-prefix=OUTPUT
// RUN: %target-run-simple-swift(-import-objc-header %S/Inputs/existential_foreign.h -enable-experimental-feature EmbeddedExistentials -enable-experimental-feature Embedded -parse-as-library -wmo -O) | %FileCheck %s --check-prefix=OUTPUT
// REQUIRES: swift_in_compiler
// REQUIRES: executable_test
// REQUIRES: optimized_stdlib
// REQUIRES: swift_feature_Embedded
// REQUIRES: swift_feature_EmbeddedExistentials
protocol P {
func printme()
}
protocol Q {
associatedtype Printable : P
func getPrintable() -> Printable
}
extension SomeCStruct : P {
func printme() {
print("SomeCStruct: \(self.f1), \(self.f2)")
}
}
extension SomeCEnum : P {
func printme() {
switch self {
case caseA:
print("SomeCEnum: .caseA")
case caseB:
print("SomeCEnum: .caseB")
case caseC:
print("SomeCEnum: .caseC")
default:
print("SomeCEnum: default")
}
}
}
struct SomeCStructContainer : Q {
let s: SomeCStruct
init() {
self.s = createSomeCStruct()
}
func getPrintable() -> SomeCStruct {
return s
}
}
struct SomeCEnumContainer : Q {
let s: SomeCEnum
init() {
self.s = createSomeCEnum()
}
func getPrintable() -> SomeCEnum {
return s
}
}
extension SomeNSEnum : P {
func printme() {
switch self {
case .someCaseA:
print("SomeNSEnum: .someCaseA")
case .someCaseB:
print("SomeNSEnum: .someCaseB")
}
}
}
struct SomeNSEnumContainer : Q {
let s: SomeNSEnum
init() {
self.s = createSomeNSEnum()
}
func getPrintable() -> SomeNSEnum {
return s
}
}
@main
struct Main {
static func main() {
let a: [any Q] = [ SomeCStructContainer(), SomeCEnumContainer(), SomeNSEnumContainer() ]
for x0 in a {
let x = x0.getPrintable()
x.printme()
// OUTPUT: SomeCStruct: 1, 2
// OUTPUT: SomeCEnum: .caseA
// OUTPUT: SomeNSEnum: .someCaseB
}
}
}