Changes to code generation to support non-objc targets

Swift SVN r23118
This commit is contained in:
Graham Batty
2014-11-05 18:05:55 +00:00
parent ec4accfda8
commit 63a429f16e
12 changed files with 146 additions and 51 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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 "

View File

@@ -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)

View File

@@ -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);

View File

@@ -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()) {

View File

@@ -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();

View File

@@ -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);

View File

@@ -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);
}
}
};

View File

@@ -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",

View File

@@ -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

View File

@@ -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)