llvm_unreachable("bad kind");
}
- /// Does this runtime provide ARC entrypoints that are likely to be faster
- /// than an ordinary message send of the appropriate selector?
- ///
- /// The ARC entrypoints are guaranteed to be equivalent to just sending the
- /// corresponding message. If the entrypoint is implemented naively as just a
- /// message send, using it is a trade-off: it sacrifices a few cycles of
- /// overhead to save a small amount of code. However, it's possible for
- /// runtimes to detect and special-case classes that use "standard"
- /// retain/release behavior; if that's dynamically a large proportion of all
- /// retained objects, using the entrypoint will also be faster than using a
- /// message send.
- ///
- /// When this method returns true, Clang will turn non-super message sends of
- /// certain selectors into calls to the correspond entrypoint:
- /// retain => objc_retain
- /// release => objc_release
- bool shouldUseARCFunctionsForRetainRelease() const {
- switch (getKind()) {
- case FragileMacOSX:
- return false;
- case MacOSX:
- return getVersion() >= VersionTuple(10, 10);
- case iOS:
- return getVersion() >= VersionTuple(8);
- case WatchOS:
- return true;
-
- case GCC:
- return false;
- case GNUstep:
- return false;
- case ObjFW:
- return false;
- }
- llvm_unreachable("bad kind");
- }
-
- /// Does this runtime provide entrypoints that are likely to be faster
- /// than an ordinary message send of the "alloc" selector?
- ///
- /// The "alloc" entrypoint is guaranteed to be equivalent to just sending the
- /// corresponding message. If the entrypoint is implemented naively as just a
- /// message send, using it is a trade-off: it sacrifices a few cycles of
- /// overhead to save a small amount of code. However, it's possible for
- /// runtimes to detect and special-case classes that use "standard"
- /// alloc behavior; if that's dynamically a large proportion of all
- /// objects, using the entrypoint will also be faster than using a message
- /// send.
- ///
- /// When this method returns true, Clang will turn non-super message sends of
- /// certain selectors into calls to the correspond entrypoint:
- /// alloc => objc_alloc
- bool shouldUseRuntimeFunctionsForAlloc() const {
- switch (getKind()) {
- case FragileMacOSX:
- return false;
- case MacOSX:
- return getVersion() >= VersionTuple(10, 10);
- case iOS:
- return getVersion() >= VersionTuple(8);
- case WatchOS:
- return true;
-
- case GCC:
- return false;
- case GNUstep:
- return false;
- case ObjFW:
- return false;
- }
- llvm_unreachable("bad kind");
- }
-
/// \brief Does this runtime supports optimized setter entrypoints?
bool hasOptimizedSetter() const {
switch (getKind()) {
def fobjc_arc : Flag<["-"], "fobjc-arc">, Group<f_Group>, Flags<[CC1Option]>,
HelpText<"Synthesize retain and release calls for Objective-C pointers">;
def fno_objc_arc : Flag<["-"], "fno-objc-arc">, Group<f_Group>;
-def fobjc_convert_messages_to_runtime_calls :
- Flag<["-"], "fobjc-convert-messages-to-runtime-calls">, Group<f_Group>;
-def fno_objc_convert_messages_to_runtime_calls :
- Flag<["-"], "fno-objc-convert-messages-to-runtime-calls">, Group<f_Group>, Flags<[CC1Option]>;
def fobjc_arc_exceptions : Flag<["-"], "fobjc-arc-exceptions">, Group<f_Group>, Flags<[CC1Option]>,
HelpText<"Use EH-safe code when synthesizing retains and releases in -fobjc-arc">;
def fno_objc_arc_exceptions : Flag<["-"], "fno-objc-arc-exceptions">, Group<f_Group>;
CODEGENOPT(NoZeroInitializedInBSS , 1, 0) ///< -fno-zero-initialized-in-bss.
/// \brief Method of Objective-C dispatch to use.
ENUM_CODEGENOPT(ObjCDispatchMethod, ObjCDispatchMethodKind, 2, Legacy)
-/// Replace certain message sends with calls to ObjC runtime entrypoints
-CODEGENOPT(ObjCConvertMessagesToRuntimeCalls , 1, 1)
CODEGENOPT(OmitLeafFramePointer , 1, 0) ///< Set when -momit-leaf-frame-pointer is
///< enabled.
VALUE_CODEGENOPT(OptimizationLevel, 2, 0) ///< The -O[0-3] option specified.
return nullptr;
}
-/// The ObjC runtime may provide entrypoints that are likely to be faster
-/// than an ordinary message send of the appropriate selector.
-///
-/// The entrypoints are guaranteed to be equivalent to just sending the
-/// corresponding message. If the entrypoint is implemented naively as just a
-/// message send, using it is a trade-off: it sacrifices a few cycles of
-/// overhead to save a small amount of code. However, it's possible for
-/// runtimes to detect and special-case classes that use "standard"
-/// retain/release behavior; if that's dynamically a large proportion of all
-/// retained objects, using the entrypoint will also be faster than using a
-/// message send.
-///
-/// If the runtime does support a required entrypoint, then this method will
-/// generate a call and return the resulting value. Otherwise it will return
-/// None and the caller can generate a msgSend instead.
-static Optional<llvm::Value *>
-tryGenerateSpecializedMessageSend(CodeGenFunction &CGF, QualType ResultType,
- llvm::Value *Receiver, Selector Sel,
- const ObjCMethodDecl *method) {
- auto &CGM = CGF.CGM;
- if (!CGM.getCodeGenOpts().ObjCConvertMessagesToRuntimeCalls)
- return None;
-
- auto &Runtime = CGM.getLangOpts().ObjCRuntime;
- switch (Sel.getMethodFamily()) {
- case OMF_alloc:
- // Make sure the name is exactly 'alloc'. All methods with that
- // prefix are identified as OMF_alloc but we only want to call the
- // runtime for this version.
- if (Runtime.shouldUseRuntimeFunctionsForAlloc() && Sel.isUnarySelector() &&
- Sel.getNameForSlot(0) == "alloc" &&
- ResultType->isObjCObjectPointerType())
- return CGF.EmitObjCAlloc(Receiver, CGF.ConvertType(ResultType));
- break;
-
- case OMF_autorelease:
- if (ResultType->isObjCObjectPointerType() &&
- CGM.getLangOpts().getGC() == LangOptions::NonGC &&
- Runtime.shouldUseARCFunctionsForRetainRelease())
- return CGF.EmitARCAutorelease(Receiver, CGF.ConvertType(ResultType));
- break;
-
- case OMF_retain:
- if (ResultType->isObjCObjectPointerType() &&
- CGM.getLangOpts().getGC() == LangOptions::NonGC &&
- Runtime.shouldUseARCFunctionsForRetainRelease())
- return CGF.EmitARCRetainNonBlock(Receiver, CGF.ConvertType(ResultType));
- break;
-
- case OMF_release:
- if (ResultType->isVoidType() &&
- CGM.getLangOpts().getGC() == LangOptions::NonGC &&
- Runtime.shouldUseARCFunctionsForRetainRelease()) {
- CGF.EmitARCRelease(Receiver, ARCPreciseLifetime);
- return nullptr;
- }
- break;
- default:
- break;
- }
- return None;
-}
-
RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E,
ReturnValueSlot Return) {
// Only the lookup mechanism and first two arguments of the method
Args,
method);
} else {
- // Call runtime methods directly if we can.
- if (Optional<llvm::Value *> SpecializedResult =
- tryGenerateSpecializedMessageSend(*this, ResultType, Receiver,
- E->getSelector(), method)) {
- result = RValue::get(SpecializedResult.getValue());
- } else {
- result = Runtime.GenerateMessageSend(*this, Return, ResultType,
- E->getSelector(), Receiver, Args,
- OID, method);
- }
+ result = Runtime.GenerateMessageSend(*this, Return, ResultType,
+ E->getSelector(),
+ Receiver, Args, OID,
+ method);
}
// For delegate init calls in ARC, implicitly store the result of
/// where a null input causes a no-op and returns null.
static llvm::Value *emitARCValueOperation(CodeGenFunction &CGF,
llvm::Value *value,
- llvm::Type *returnType,
llvm::Constant *&fn,
StringRef fnName,
bool isTailCall = false) {
}
// Cast the argument to 'id'.
- llvm::Type *origType = returnType ? returnType : value->getType();
+ llvm::Type *origType = value->getType();
value = CGF.Builder.CreateBitCast(value, CGF.Int8PtrTy);
// Call the function.
/// Retain the given object, with normal retain semantics.
/// call i8* \@objc_retain(i8* %value)
-llvm::Value *CodeGenFunction::EmitARCRetainNonBlock(llvm::Value *value,
- llvm::Type *returnType) {
- return emitARCValueOperation(*this, value, returnType,
+llvm::Value *CodeGenFunction::EmitARCRetainNonBlock(llvm::Value *value) {
+ return emitARCValueOperation(*this, value,
CGM.getObjCEntrypoints().objc_retain,
"objc_retain");
}
llvm::Value *CodeGenFunction::EmitARCRetainBlock(llvm::Value *value,
bool mandatory) {
llvm::Value *result
- = emitARCValueOperation(*this, value, nullptr,
+ = emitARCValueOperation(*this, value,
CGM.getObjCEntrypoints().objc_retainBlock,
"objc_retainBlock");
llvm::Value *
CodeGenFunction::EmitARCRetainAutoreleasedReturnValue(llvm::Value *value) {
emitAutoreleasedReturnValueMarker(*this);
- return emitARCValueOperation(*this, value, nullptr,
+ return emitARCValueOperation(*this, value,
CGM.getObjCEntrypoints().objc_retainAutoreleasedReturnValue,
"objc_retainAutoreleasedReturnValue");
}
llvm::Value *
CodeGenFunction::EmitARCUnsafeClaimAutoreleasedReturnValue(llvm::Value *value) {
emitAutoreleasedReturnValueMarker(*this);
- return emitARCValueOperation(*this, value, nullptr,
+ return emitARCValueOperation(*this, value,
CGM.getObjCEntrypoints().objc_unsafeClaimAutoreleasedReturnValue,
"objc_unsafeClaimAutoreleasedReturnValue");
}
/// Autorelease the given object.
/// call i8* \@objc_autorelease(i8* %value)
-llvm::Value *CodeGenFunction::EmitARCAutorelease(llvm::Value *value,
- llvm::Type *resultType) {
- return emitARCValueOperation(*this, value, resultType,
+llvm::Value *CodeGenFunction::EmitARCAutorelease(llvm::Value *value) {
+ return emitARCValueOperation(*this, value,
CGM.getObjCEntrypoints().objc_autorelease,
"objc_autorelease");
}
/// call i8* \@objc_autoreleaseReturnValue(i8* %value)
llvm::Value *
CodeGenFunction::EmitARCAutoreleaseReturnValue(llvm::Value *value) {
- return emitARCValueOperation(*this, value, nullptr,
+ return emitARCValueOperation(*this, value,
CGM.getObjCEntrypoints().objc_autoreleaseReturnValue,
"objc_autoreleaseReturnValue",
/*isTailCall*/ true);
/// call i8* \@objc_retainAutoreleaseReturnValue(i8* %value)
llvm::Value *
CodeGenFunction::EmitARCRetainAutoreleaseReturnValue(llvm::Value *value) {
- return emitARCValueOperation(*this, value, nullptr,
+ return emitARCValueOperation(*this, value,
CGM.getObjCEntrypoints().objc_retainAutoreleaseReturnValue,
"objc_retainAutoreleaseReturnValue",
/*isTailCall*/ true);
/// call i8* \@objc_retainAutorelease(i8* %value)
llvm::Value *
CodeGenFunction::EmitARCRetainAutoreleaseNonBlock(llvm::Value *value) {
- return emitARCValueOperation(*this, value, nullptr,
+ return emitARCValueOperation(*this, value,
CGM.getObjCEntrypoints().objc_retainAutorelease,
"objc_retainAutorelease");
}
return InitRV.getScalarVal();
}
-/// Allocate the given objc object.
-/// call i8* \@objc_alloc(i8* %value)
-llvm::Value *CodeGenFunction::EmitObjCAlloc(llvm::Value *value,
- llvm::Type *resultType) {
- return emitARCValueOperation(*this, value, resultType,
- CGM.getObjCEntrypoints().objc_alloc,
- "objc_alloc");
-}
-
/// Produce the code to do a primitive release.
/// [tmp drain];
void CodeGenFunction::EmitObjCMRRAutoreleasePoolPop(llvm::Value *Arg) {
llvm::Value *EmitARCStoreStrongCall(Address addr, llvm::Value *value,
bool resultIgnored);
llvm::Value *EmitARCRetain(QualType type, llvm::Value *value);
- llvm::Value *EmitARCRetainNonBlock(llvm::Value *value,
- llvm::Type *returnType = nullptr);
+ llvm::Value *EmitARCRetainNonBlock(llvm::Value *value);
llvm::Value *EmitARCRetainBlock(llvm::Value *value, bool mandatory);
void EmitARCDestroyStrong(Address addr, ARCPreciseLifetime_t precise);
void EmitARCRelease(llvm::Value *value, ARCPreciseLifetime_t precise);
- llvm::Value *EmitARCAutorelease(llvm::Value *value,
- llvm::Type *returnType = nullptr);
+ llvm::Value *EmitARCAutorelease(llvm::Value *value);
llvm::Value *EmitARCAutoreleaseReturnValue(llvm::Value *value);
llvm::Value *EmitARCRetainAutoreleaseReturnValue(llvm::Value *value);
llvm::Value *EmitARCRetainAutoreleasedReturnValue(llvm::Value *value);
std::pair<LValue,llvm::Value*>
EmitARCStoreUnsafeUnretained(const BinaryOperator *e, bool ignored);
- llvm::Value *EmitObjCAlloc(llvm::Value *value,
- llvm::Type *returnType = nullptr);
llvm::Value *EmitObjCThrowOperand(const Expr *expr);
llvm::Value *EmitObjCConsumeObject(QualType T, llvm::Value *Ptr);
llvm::Value *EmitObjCExtendObjectLifetime(QualType T, llvm::Value *Ptr);
struct ObjCEntrypoints {
ObjCEntrypoints() { memset(this, 0, sizeof(*this)); }
- /// void objc_alloc(id);
- llvm::Constant *objc_alloc;
-
- /// void objc_autoreleasePoolPop(void*);
+ /// void objc_autoreleasePoolPop(void*);
llvm::Constant *objc_autoreleasePoolPop;
/// void *objc_autoreleasePoolPush(void);
}
- // Allow the user to control whether messages can be converted to runtime
- // functions.
- if (types::isObjC(InputType)) {
- auto *Arg = Args.getLastArg(
- options::OPT_fobjc_convert_messages_to_runtime_calls,
- options::OPT_fno_objc_convert_messages_to_runtime_calls);
- if (Arg &&
- Arg->getOption().matches(
- options::OPT_fno_objc_convert_messages_to_runtime_calls))
- CmdArgs.push_back("-fno-objc-convert-messages-to-runtime-calls");
- }
-
// -fobjc-infer-related-result-type is the default, except in the Objective-C
// rewriter.
if (rewriteKind != RK_None)
}
}
- if (Args.hasArg(OPT_fno_objc_convert_messages_to_runtime_calls))
- Opts.ObjCConvertMessagesToRuntimeCalls = 0;
-
Opts.EmulatedTLS =
Args.hasFlag(OPT_femulated_tls, OPT_fno_emulated_tls, false);
+++ /dev/null
-// RUN: %clang_cc1 -fobjc-runtime=macosx-10.10.0 -emit-llvm -o - %s -fno-objc-convert-messages-to-runtime-calls | FileCheck %s --check-prefix=MSGS
-// RUN: %clang_cc1 -fobjc-runtime=macosx-10.10.0 -emit-llvm -o - %s | FileCheck %s --check-prefix=CALLS
-// RUN: %clang_cc1 -fobjc-runtime=macosx-10.9.0 -emit-llvm -o - %s | FileCheck %s --check-prefix=MSGS
-// RUN: %clang_cc1 -fobjc-runtime=macosx-fragile-10.10.0 -emit-llvm -o - %s | FileCheck %s --check-prefix=MSGS
-// Make sure we don't do calls to retain/release when using GC.
-// RUN: %clang_cc1 -fobjc-runtime=macosx-10.10.0 -emit-llvm -o - %s -fobjc-gc | FileCheck %s --check-prefix=GC
-// RUN: %clang_cc1 -fobjc-runtime=ios-8.0 -emit-llvm -o - %s | FileCheck %s --check-prefix=CALLS
-// RUN: %clang_cc1 -fobjc-runtime=ios-7.0 -emit-llvm -o - %s | FileCheck %s --check-prefix=MSGS
-// Note: This line below is for tvos for which the driver passes through to use the ios9.0 runtime.
-// RUN: %clang_cc1 -fobjc-runtime=ios-9.0 -emit-llvm -o - %s | FileCheck %s --check-prefix=CALLS
-// RUN: %clang_cc1 -fobjc-runtime=watchos-2.0 -emit-llvm -o - %s | FileCheck %s --check-prefix=CALLS
-
-@interface NSObject
-+ (id)alloc;
-+ (id)alloc2;
-- (id)init;
-- (id)retain;
-- (void)release;
-- (id)autorelease;
-@end
-
-@interface NSString : NSObject
-+ (void)retain_self;
-- (void)retain_super;
-@end
-
-// CHECK-LABEL: define {{.*}}void @test1
-void test1(id x) {
- // MSGS: {{call.*@objc_msgSend}}
- // MSGS: {{call.*@objc_msgSend}}
- // MSGS: {{call.*@objc_msgSend}}
- // MSGS: {{call.*@objc_msgSend}}
- // CALLS: {{call.*@objc_alloc}}
- // CALLS: {{call.*@objc_retain}}
- // CALLS: {{call.*@objc_release}}
- // CALLS: {{call.*@objc_autorelease}}
- // GC: {{call.*@objc_alloc}}
- // GC: {{call.*@objc_msgSend}}
- // GC: {{call.*@objc_msgSend}}
- // GC: {{call.*@objc_msgSend}}
- [NSObject alloc];
- [x retain];
- [x release];
- [x autorelease];
-}
-
-// CHECK-LABEL: define {{.*}}void @test2
-void test2() {
- // MSGS: {{call.*@objc_msgSend}}
- // CALLS: {{call.*@objc_msgSend}}
- // GC: {{call.*@objc_msgSend}}
- // Make sure alloc has the correct name and number of types.
- [NSObject alloc2];
-}
-
-@class A;
-@interface B
-+ (A*) alloc;
-- (A*) retain;
-- (A*) autorelease;
-@end
-
-// Make sure we get a bitcast on the return type as the
-// call will return i8* which we have to cast to A*
-// CHECK-LABEL: define {{.*}}void @test_alloc_class_ptr
-A* test_alloc_class_ptr() {
- // CALLS: {{call.*@objc_alloc}}
- // CALLS-NEXT: bitcast i8*
- // CALLS-NEXT: ret
- return [B alloc];
-}
-
-// Make sure we get a bitcast on the return type as the
-// call will return i8* which we have to cast to A*
-// CHECK-LABEL: define {{.*}}void @test_retain_class_ptr
-A* test_retain_class_ptr(B *b) {
- // CALLS: {{call.*@objc_retain}}
- // CALLS-NEXT: bitcast i8*
- // CALLS-NEXT: ret
- return [b retain];
-}
-
-// Make sure we get a bitcast on the return type as the
-// call will return i8* which we have to cast to A*
-// CHECK-LABEL: define {{.*}}void @test_autorelease_class_ptr
-A* test_autorelease_class_ptr(B *b) {
- // CALLS: {{call.*@objc_autorelease}}
- // CALLS-NEXT: bitcast i8*
- // CALLS-NEXT: ret
- return [b autorelease];
-}
-
-@interface C
-- (float) retain;
-@end
-
-// Make sure we use a message and not a call as the return type is
-// not a pointer type.
-// CHECK-LABEL: define {{.*}}void @test_cannot_message_return_float
-float test_cannot_message_return_float(C *c) {
- // MSGS: {{call.*@objc_msgSend}}
- // CALLS: {{call.*@objc_msgSend}}
- // GC: {{call.*@objc_msgSend}}
- return [c retain];
-}
-
-@implementation NSString
-
-// Make sure we can convert a message to a dynamic receiver to a call
-// CHECK-LABEL: define {{.*}}void @retain_self
-+ (void)retain_self {
- // MSGS: {{call.*@objc_msgSend}}
- // CALLS: {{call.*@objc_retain}}
- // GC: {{call.*@objc_msgSend}}
- [self retain];
-}
-
-// Make sure we never convert a message to super to a call
-// CHECK-LABEL: define {{.*}}void @retain_super
-- (void)retain_super {
- // MSGS: {{call.*@objc_msgSend}}
- // CALLS: {{call.*@objc_msgSend}}
- // GC: {{call.*@objc_msgSend}}
- [super retain];
-}
-
-@end
-
-
+++ /dev/null
-// RUN: %clang %s -### -o %t.o 2>&1 -fsyntax-only -fobjc-convert-messages-to-runtime-calls -fno-objc-convert-messages-to-runtime-calls -target x86_64-apple-macosx10.10.0 | FileCheck %s --check-prefix=DISABLE
-// RUN: %clang %s -### -o %t.o 2>&1 -fsyntax-only -fno-objc-convert-messages-to-runtime-calls -fobjc-convert-messages-to-runtime-calls -target x86_64-apple-macosx10.10.0 | FileCheck %s --check-prefix=ENABLE
-
-// Check that we pass fobjc-convert-messages-to-runtime-calls only when supported, and not explicitly disabled.
-
-// DISABLE: "-fno-objc-convert-messages-to-runtime-calls"
-// ENABLE-NOT: "-fno-objc-convert-messages-to-runtime-calls"