mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
Changes to code generation to support non-objc targets
Swift SVN r23118
This commit is contained in:
@@ -93,12 +93,15 @@ public:
|
||||
/// Special codegen for playgrounds.
|
||||
unsigned Playground : 1;
|
||||
|
||||
/// Enable Objective-C interop code generation
|
||||
unsigned EnableObjCInterop : 1;
|
||||
|
||||
IRGenOptions() : OutputKind(IRGenOutputKind::LLVMAssembly), Verify(true),
|
||||
Optimize(false), DebugInfo(false), UseJIT(false),
|
||||
EnableDynamicValueTypeLayout(false),
|
||||
DisableLLVMOptzns(false), DisableLLVMARCOpts(false),
|
||||
DisableFPElim(true), HasUnderlyingModule(false),
|
||||
Playground(false) {}
|
||||
Playground(false), EnableObjCInterop(true) {}
|
||||
};
|
||||
|
||||
} // end namespace swift
|
||||
|
||||
@@ -86,6 +86,10 @@ namespace swift {
|
||||
/// Whether to split imported Objective-C selectors into Swift method names.
|
||||
bool SplitPrepositions = false;
|
||||
|
||||
/// Enable Objective-C Runtime interop code generation and build
|
||||
/// configuration options.
|
||||
bool EnableObjCInterop = true;
|
||||
|
||||
/// Enables checking that uses of @objc require importing
|
||||
/// the Foundation module.
|
||||
/// This is enabled by default because SILGen can crash in such a case, but
|
||||
|
||||
@@ -56,7 +56,15 @@ def verify : Flag<["-"], "verify">,
|
||||
|
||||
def show_diagnostics_after_fatal : Flag<["-"], "show-diagnostics-after-fatal">,
|
||||
HelpText<"Keep emitting subsequent diagnostics after a fatal error">;
|
||||
|
||||
|
||||
def enable_objc_interop :
|
||||
Flag<["-"], "enable-objc-interop">,
|
||||
HelpText<"Enable Objective-C interop code generation and config directives">;
|
||||
|
||||
def disable_objc_interop :
|
||||
Flag<["-"], "disable-objc-interop">,
|
||||
HelpText<"Disable Objective-C interop code generation and config directives">;
|
||||
|
||||
def enable_objc_attr_requires_foundation_module :
|
||||
Flag<["-"], "enable-objc-attr-requires-foundation-module">,
|
||||
HelpText<"Enable requiring uses of @objc to require importing the "
|
||||
|
||||
@@ -894,7 +894,7 @@ bool ASTContext::hasOptionalIntrinsics(LazyResolver *resolver) const {
|
||||
bool ASTContext::hasPointerArgumentIntrinsics(LazyResolver *resolver) const {
|
||||
return getUnsafeMutablePointerDecl()
|
||||
&& getUnsafePointerDecl()
|
||||
&& getAutoreleasingUnsafeMutablePointerDecl()
|
||||
&& (!LangOpts.EnableObjCInterop || getAutoreleasingUnsafeMutablePointerDecl())
|
||||
&& getConvertPointerToPointerArgument(resolver)
|
||||
&& getConvertMutableArrayToPointerArgument(resolver)
|
||||
&& getConvertConstArrayToPointerArgument(resolver)
|
||||
|
||||
@@ -91,6 +91,13 @@ static void addCommonFrontendArgs(const ToolChain &TC,
|
||||
arguments.push_back("-aarch64-use-tbi");
|
||||
}
|
||||
|
||||
// Enable or disable ObjC interop appropriately for the platform
|
||||
if (Triple.isOSDarwin()) {
|
||||
arguments.push_back("-enable-objc-interop");
|
||||
} else {
|
||||
arguments.push_back("-disable-objc-interop");
|
||||
}
|
||||
|
||||
// Handle the CPU and its preferences.
|
||||
if (auto arg = inputArgs.getLastArg(options::OPT_target_cpu))
|
||||
arg->render(inputArgs, arguments);
|
||||
|
||||
@@ -91,7 +91,7 @@ static void updateTargetConfigurationOptions(LangOptions &LangOpts,
|
||||
}
|
||||
|
||||
// Set the "runtime" target configuration.
|
||||
if (triple.isOSDarwin())
|
||||
if (LangOpts.EnableObjCInterop)
|
||||
LangOpts.addTargetConfigOption("_runtime", "_ObjC");
|
||||
else
|
||||
LangOpts.addTargetConfigOption("_runtime", "_Native");
|
||||
@@ -629,6 +629,12 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args,
|
||||
Opts.DebuggerSupport |= Args.hasArg(OPT_debugger_support);
|
||||
Opts.Playground |= Args.hasArg(OPT_playground);
|
||||
|
||||
if (auto A = Args.getLastArg(OPT_enable_objc_interop,
|
||||
OPT_disable_objc_interop)) {
|
||||
Opts.EnableObjCInterop
|
||||
= A->getOption().matches(OPT_enable_objc_interop);
|
||||
}
|
||||
|
||||
if (auto A = Args.getLastArg(OPT_enable_objc_attr_requires_foundation_module,
|
||||
OPT_disable_objc_attr_requires_foundation_module)) {
|
||||
Opts.EnableObjCAttrRequiresFoundation
|
||||
@@ -941,6 +947,12 @@ static bool ParseIRGenArgs(IRGenOptions &Opts, ArgList &Args,
|
||||
if (const Arg *A = Args.getLastArg(OPT_target))
|
||||
Opts.Triple = llvm::Triple::normalize(A->getValue());
|
||||
|
||||
if (auto A = Args.getLastArg(OPT_enable_objc_interop,
|
||||
OPT_disable_objc_interop)) {
|
||||
Opts.EnableObjCInterop
|
||||
= A->getOption().matches(OPT_enable_objc_interop);
|
||||
}
|
||||
|
||||
// TODO: investigate whether these should be removed, in favor of definitions
|
||||
// in other classes.
|
||||
if (FrontendOpts.PrimaryInput && FrontendOpts.PrimaryInput->isFilename()) {
|
||||
|
||||
@@ -70,11 +70,11 @@ public:
|
||||
// layout-compatible with an Objective-C class. The superclass
|
||||
// pointer is useful regardless of mode, but the rest of the data
|
||||
// isn't necessary.
|
||||
// FIXME: Figure out what can be removed altogether in non-objc-interop
|
||||
// mode and remove it. rdar://problem/18801263
|
||||
asImpl().addSuperClass();
|
||||
if (IGM.ObjCInterop) {
|
||||
asImpl().addClassCacheData();
|
||||
asImpl().addClassDataPointer();
|
||||
}
|
||||
asImpl().addClassCacheData();
|
||||
asImpl().addClassDataPointer();
|
||||
|
||||
asImpl().addClassFlags();
|
||||
asImpl().addInstanceAddressPoint();
|
||||
|
||||
@@ -241,6 +241,7 @@ llvm::Value *irgen::emitMetatypeDowncast(IRGenFunction &IGF,
|
||||
|
||||
switch (toMetatype->getRepresentation()) {
|
||||
case MetatypeRepresentation::Thick: {
|
||||
assert(IGF.IGM.ObjCInterop && "should have objc runtime");
|
||||
// Get the Swift metadata for the type we're checking.
|
||||
toMetadata = IGF.emitTypeMetadataRef(toMetatype.getInstanceType());
|
||||
switch (mode) {
|
||||
@@ -255,6 +256,8 @@ llvm::Value *irgen::emitMetatypeDowncast(IRGenFunction &IGF,
|
||||
}
|
||||
|
||||
case MetatypeRepresentation::ObjC: {
|
||||
assert(IGF.IGM.ObjCInterop && "should have objc runtime");
|
||||
|
||||
// Get the ObjC metadata for the type we're checking.
|
||||
toMetadata = emitClassHeapMetadataRef(IGF, toMetatype.getInstanceType(),
|
||||
MetadataValueType::ObjCClass);
|
||||
|
||||
@@ -295,8 +295,9 @@ static llvm::Value *emitNominalMetadataRef(IRGenFunction &IGF,
|
||||
if (!generics) {
|
||||
assert(metadata->getType() == IGF.IGM.TypeMetadataPtrTy);
|
||||
|
||||
// If this is a class, we need to force ObjC initialization.
|
||||
if (isa<ClassDecl>(theDecl)) {
|
||||
// If this is a class, we need to force ObjC initialization,
|
||||
// but only if we're doing Objective-C interop.
|
||||
if (IGF.IGM.ObjCInterop && isa<ClassDecl>(theDecl)) {
|
||||
metadata = IGF.Builder.CreateBitCast(metadata, IGF.IGM.ObjCClassPtrTy);
|
||||
metadata = IGF.Builder.CreateCall(IGF.IGM.getGetInitializedObjCClassFn(),
|
||||
metadata);
|
||||
@@ -2297,11 +2298,19 @@ namespace {
|
||||
static_assert(unsigned(MetadataKind::Class) == 0,
|
||||
"class metadata kind is non-zero?");
|
||||
|
||||
// Get the metaclass pointer as an intptr_t.
|
||||
auto metaclass = IGM.getAddrOfMetaclassObject(Target,
|
||||
NotForDefinition);
|
||||
auto flags = llvm::ConstantExpr::getPtrToInt(metaclass, IGM.IntPtrTy);
|
||||
addWord(flags);
|
||||
if (IGM.ObjCInterop) {
|
||||
// Get the metaclass pointer as an intptr_t.
|
||||
auto metaclass = IGM.getAddrOfMetaclassObject(Target,
|
||||
NotForDefinition);
|
||||
auto flags = llvm::ConstantExpr::getPtrToInt(metaclass, IGM.IntPtrTy);
|
||||
addWord(flags);
|
||||
} else {
|
||||
// On non-objc platforms just fill it with a null, there
|
||||
// is no objective-c metaclass.
|
||||
// FIXME: Remove this to save metadata space.
|
||||
// rdar://problem/18801263
|
||||
addWord(llvm::ConstantExpr::getNullValue(IGM.IntPtrTy));
|
||||
}
|
||||
}
|
||||
|
||||
/// The runtime provides a value witness table for Builtin.NativeObject.
|
||||
@@ -2435,11 +2444,18 @@ namespace {
|
||||
void addClassCacheData() {
|
||||
// We initially fill in these fields with addresses taken from
|
||||
// the ObjC runtime.
|
||||
// FIXME: Remove null data altogether rdar://problem/18801263
|
||||
addWord(IGM.getObjCEmptyCachePtr());
|
||||
addWord(IGM.getObjCEmptyVTablePtr());
|
||||
}
|
||||
|
||||
void addClassDataPointer() {
|
||||
if (!IGM.ObjCInterop) {
|
||||
// with no objective-c runtime, just give an empty pointer with the
|
||||
// swift bit set.
|
||||
addWord(llvm::ConstantInt::get(IGM.IntPtrTy, 1));
|
||||
return;
|
||||
}
|
||||
// Derive the RO-data.
|
||||
llvm::Constant *data = emitClassPrivateData(IGM, Target);
|
||||
|
||||
@@ -2621,6 +2637,12 @@ namespace {
|
||||
}
|
||||
|
||||
void addDependentData() {
|
||||
if (!IGM.ObjCInterop) {
|
||||
// Every piece of data in the dependent data appears to be related to
|
||||
// Objective-C information. If we're not doing Objective-C interop, we
|
||||
// can just skip adding it to the class.
|
||||
return;
|
||||
}
|
||||
// Emit space for the dependent metaclass.
|
||||
DependentMetaclassPoint = getNextOffset();
|
||||
// isa
|
||||
@@ -2729,31 +2751,42 @@ namespace {
|
||||
llvm::Value *metadata,
|
||||
llvm::Value *vwtable) {
|
||||
assert(!HasDependentVWT && "class should never have dependent VWT");
|
||||
|
||||
|
||||
// Fill in the metaclass pointer.
|
||||
Address metadataPtr(IGF.Builder.CreateBitCast(metadata, IGF.IGM.Int8PtrPtrTy),
|
||||
IGF.IGM.getPointerAlignment());
|
||||
|
||||
llvm::Value *metaclass;
|
||||
{
|
||||
if (IGF.IGM.ObjCInterop) {
|
||||
assert(!DependentMetaclassPoint.isInvalid());
|
||||
assert(!MetaclassPtrOffset.isInvalid());
|
||||
|
||||
Address metaclassPtrSlot = createPointerSizedGEP(IGF, metadataPtr,
|
||||
MetaclassPtrOffset - AddressPoint);
|
||||
MetaclassPtrOffset - AddressPoint);
|
||||
metaclassPtrSlot = IGF.Builder.CreateBitCast(metaclassPtrSlot,
|
||||
IGF.IGM.ObjCClassPtrTy->getPointerTo());
|
||||
IGF.IGM.ObjCClassPtrTy->getPointerTo());
|
||||
Address metaclassRawPtr = createPointerSizedGEP(IGF, metadataPtr,
|
||||
DependentMetaclassPoint - AddressPoint);
|
||||
DependentMetaclassPoint - AddressPoint);
|
||||
metaclass = IGF.Builder.CreateBitCast(metaclassRawPtr,
|
||||
IGF.IGM.ObjCClassPtrTy)
|
||||
.getAddress();
|
||||
IGF.Builder.CreateStore(metaclass, metaclassPtrSlot);
|
||||
} else {
|
||||
// FIXME: Remove altogether rather than injecting a NULL value.
|
||||
// rdar://problem/18801263
|
||||
assert(!MetaclassPtrOffset.isInvalid());
|
||||
Address metaclassPtrSlot = createPointerSizedGEP(IGF, metadataPtr,
|
||||
MetaclassPtrOffset - AddressPoint);
|
||||
metaclassPtrSlot = IGF.Builder.CreateBitCast(metaclassPtrSlot,
|
||||
IGF.IGM.ObjCClassPtrTy->getPointerTo());
|
||||
IGF.Builder.CreateStore(
|
||||
llvm::ConstantPointerNull::get(IGF.IGM.ObjCClassPtrTy),
|
||||
metaclassPtrSlot);
|
||||
}
|
||||
|
||||
// Fill in the rodata reference in the class.
|
||||
Address classRODataPtr;
|
||||
{
|
||||
if (IGF.IGM.ObjCInterop) {
|
||||
assert(!DependentClassRODataPoint.isInvalid());
|
||||
assert(!ClassRODataPtrOffset.isInvalid());
|
||||
Address rodataPtrSlot = createPointerSizedGEP(IGF, metadataPtr,
|
||||
@@ -2764,42 +2797,59 @@ namespace {
|
||||
classRODataPtr = createPointerSizedGEP(IGF, metadataPtr,
|
||||
DependentClassRODataPoint - AddressPoint);
|
||||
// Set the low bit of the value to indicate "compiled by Swift".
|
||||
llvm::Value *rodata = IGF.Builder.CreatePtrToInt(classRODataPtr.getAddress(),
|
||||
IGF.IGM.IntPtrTy);
|
||||
llvm::Value *rodata = IGF.Builder.CreatePtrToInt(
|
||||
classRODataPtr.getAddress(), IGF.IGM.IntPtrTy);
|
||||
rodata = IGF.Builder.CreateOr(rodata, 1);
|
||||
IGF.Builder.CreateStore(rodata, rodataPtrSlot);
|
||||
} else {
|
||||
// NOTE: Unlike other bits of the metadata that should later be removed,
|
||||
// this one is important because things check this value's flags to
|
||||
// determine what kind of object it is. That said, if those checks
|
||||
// are determined to be removeable, we can remove this as well per
|
||||
// rdar://problem/18801263
|
||||
assert(!ClassRODataPtrOffset.isInvalid());
|
||||
Address rodataPtrSlot = createPointerSizedGEP(IGF, metadataPtr,
|
||||
ClassRODataPtrOffset - AddressPoint);
|
||||
rodataPtrSlot = IGF.Builder.CreateBitCast(rodataPtrSlot,
|
||||
IGF.IGM.IntPtrTy->getPointerTo());
|
||||
|
||||
IGF.Builder.CreateStore(llvm::ConstantInt::get(IGF.IGM.IntPtrTy, 1),
|
||||
rodataPtrSlot);
|
||||
}
|
||||
|
||||
// Fill in the rodata reference in the metaclass.
|
||||
Address metaclassRODataPtr;
|
||||
{
|
||||
if (IGF.IGM.ObjCInterop) {
|
||||
assert(!DependentMetaclassRODataPoint.isInvalid());
|
||||
assert(!MetaclassRODataPtrOffset.isInvalid());
|
||||
Address rodataPtrSlot = createPointerSizedGEP(IGF, metadataPtr,
|
||||
MetaclassRODataPtrOffset - AddressPoint);
|
||||
rodataPtrSlot = IGF.Builder.CreateBitCast(rodataPtrSlot,
|
||||
IGF.IGM.IntPtrTy->getPointerTo());
|
||||
IGF.IGM.IntPtrTy->getPointerTo());
|
||||
|
||||
metaclassRODataPtr = createPointerSizedGEP(IGF, metadataPtr,
|
||||
DependentMetaclassRODataPoint - AddressPoint);
|
||||
llvm::Value *rodata = IGF.Builder.CreatePtrToInt(metaclassRODataPtr.getAddress(),
|
||||
IGF.IGM.IntPtrTy);
|
||||
llvm::Value *rodata = IGF.Builder.CreatePtrToInt(
|
||||
metaclassRODataPtr.getAddress(), IGF.IGM.IntPtrTy);
|
||||
IGF.Builder.CreateStore(rodata, rodataPtrSlot);
|
||||
}
|
||||
|
||||
// Generate the runtime name for the class and poke it into the rodata.
|
||||
llvm::SmallString<32> buf;
|
||||
auto basename = IGM.getAddrOfGlobalString(Target->getObjCRuntimeName(buf));
|
||||
auto name = IGF.Builder.CreateCall2(IGM.getGetGenericClassObjCNameFn(),
|
||||
metadata, basename);
|
||||
name->setDoesNotThrow();
|
||||
Size nameOffset(IGM.getPointerAlignment().getValue() > 4 ? 24 : 16);
|
||||
for (Address rodataPtr : {classRODataPtr, metaclassRODataPtr}) {
|
||||
auto namePtr = createPointerSizedGEP(IGF, rodataPtr, nameOffset);
|
||||
namePtr = IGF.Builder.CreateBitCast(namePtr, IGM.Int8PtrPtrTy);
|
||||
IGF.Builder.CreateStore(name, namePtr);
|
||||
if (IGF.IGM.ObjCInterop) {
|
||||
// Generate the runtime name for the class and poke it into the rodata.
|
||||
llvm::SmallString<32> buf;
|
||||
auto basename = IGM.getAddrOfGlobalString(
|
||||
Target->getObjCRuntimeName(buf));
|
||||
auto name = IGF.Builder.CreateCall2(IGM.getGetGenericClassObjCNameFn(),
|
||||
metadata, basename);
|
||||
name->setDoesNotThrow();
|
||||
Size nameOffset(IGM.getPointerAlignment().getValue() > 4 ? 24 : 16);
|
||||
for (Address rodataPtr : {classRODataPtr, metaclassRODataPtr}) {
|
||||
auto namePtr = createPointerSizedGEP(IGF, rodataPtr, nameOffset);
|
||||
namePtr = IGF.Builder.CreateBitCast(namePtr, IGM.Int8PtrPtrTy);
|
||||
IGF.Builder.CreateStore(name, namePtr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Get the superclass metadata.
|
||||
llvm::Value *superMetadata;
|
||||
if (Target->hasSuperclass()) {
|
||||
@@ -2815,7 +2865,7 @@ namespace {
|
||||
|
||||
// If the superclass is generic, we need to populate the
|
||||
// superclass field of the metaclass.
|
||||
if (HasDependentSuperclass) {
|
||||
if (IGF.IGM.ObjCInterop && HasDependentSuperclass) {
|
||||
// The superclass of the metaclass is the metaclass of the superclass.
|
||||
|
||||
// Read the superclass's metaclass.
|
||||
@@ -2830,7 +2880,7 @@ namespace {
|
||||
|
||||
IGF.Builder.CreateStore(superMetaClass, metaSuperField);
|
||||
}
|
||||
|
||||
|
||||
// If we have any ancestor generic parameters or field offset vectors,
|
||||
// copy them from the superclass metadata.
|
||||
if (!AncestorFieldOffsetVectors.empty() || !AncestorFillOps.empty()) {
|
||||
@@ -2919,9 +2969,11 @@ namespace {
|
||||
firstField.getAddress(), fieldVector);
|
||||
}
|
||||
|
||||
// Register the class with the ObjC runtime.
|
||||
llvm::Value *instantiateObjC = IGF.IGM.getInstantiateObjCClassFn();
|
||||
IGF.Builder.CreateCall(instantiateObjC, metadata);
|
||||
if (IGF.IGM.ObjCInterop) {
|
||||
// Register the class with the ObjC runtime.
|
||||
llvm::Value *instantiateObjC = IGF.IGM.getInstantiateObjCClassFn();
|
||||
IGF.Builder.CreateCall(instantiateObjC, metadata);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
@@ -97,7 +97,8 @@ IRGenModule::IRGenModule(ASTContext &Context,
|
||||
Module(*ClangCodeGen->GetModule()),
|
||||
LLVMContext(Module.getContext()), DataLayout(DataLayout),
|
||||
SILMod(SILMod), TargetInfo(SwiftTargetInfo::get(*this)),
|
||||
DebugInfo(0), Types(*new TypeConverter(*this))
|
||||
DebugInfo(0), ObjCInterop(Opts.EnableObjCInterop),
|
||||
Types(*new TypeConverter(*this))
|
||||
{
|
||||
VoidTy = llvm::Type::getVoidTy(getLLVMContext());
|
||||
Int1Ty = llvm::Type::getInt1Ty(getLLVMContext());
|
||||
@@ -363,9 +364,14 @@ llvm::Constant *IRGenModule::getEmptyTupleMetadata() {
|
||||
llvm::Constant *IRGenModule::getObjCEmptyCachePtr() {
|
||||
if (ObjCEmptyCachePtr) return ObjCEmptyCachePtr;
|
||||
|
||||
// struct objc_cache _objc_empty_cache;
|
||||
ObjCEmptyCachePtr = Module.getOrInsertGlobal("_objc_empty_cache",
|
||||
OpaquePtrTy->getElementType());
|
||||
if (ObjCInterop) {
|
||||
// struct objc_cache _objc_empty_cache;
|
||||
ObjCEmptyCachePtr = Module.getOrInsertGlobal("_objc_empty_cache",
|
||||
OpaquePtrTy->getElementType());
|
||||
} else {
|
||||
// FIXME: Remove even the null value per rdar://problem/18801263
|
||||
ObjCEmptyCachePtr = llvm::ConstantPointerNull::get(OpaquePtrTy);
|
||||
}
|
||||
return ObjCEmptyCachePtr;
|
||||
}
|
||||
|
||||
@@ -383,7 +389,7 @@ llvm::Constant *IRGenModule::getObjCEmptyVTablePtr() {
|
||||
// symbols correctly, such as the iOS simulator, and for these we
|
||||
// have to fill in null directly.
|
||||
|
||||
if (TargetInfo.ObjCUseNullForEmptyVTable) {
|
||||
if (!ObjCInterop || TargetInfo.ObjCUseNullForEmptyVTable) {
|
||||
ObjCEmptyVTablePtr = llvm::ConstantPointerNull::get(OpaquePtrTy);
|
||||
} else {
|
||||
ObjCEmptyVTablePtr = Module.getOrInsertGlobal("_objc_empty_vtable",
|
||||
|
||||
@@ -129,7 +129,7 @@ public:
|
||||
CodeGenABITypes *ABITypes;
|
||||
|
||||
/// Does the current target require Objective-C interoperation?
|
||||
static const bool ObjCInterop = true;
|
||||
bool ObjCInterop = true;
|
||||
|
||||
llvm::Type *VoidTy; /// void (usually {})
|
||||
llvm::IntegerType *Int1Ty; /// i1
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// RUN: %swift -parse %s -verify -D FOO -D BAR -target x86_64-unknown-linux-gnu -D FOO -parse-stdlib
|
||||
// RUN: %swift -parse %s -verify -D FOO -D BAR -target x86_64-unknown-linux-gnu -disable-objc-interop -D FOO -parse-stdlib
|
||||
// RUN: %swift-ide-test -test-input-complete -source-filename=%s -target x86_64-unknown-linux-gnu
|
||||
|
||||
#if arch(x86_64) && os(Linux) && _runtime(_Native)
|
||||
|
||||
Reference in New Issue
Block a user