aboutsummaryrefslogtreecommitdiff
path: root/lib/CodeGen/CGObjC.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/CodeGen/CGObjC.cpp')
-rw-r--r--lib/CodeGen/CGObjC.cpp511
1 files changed, 353 insertions, 158 deletions
diff --git a/lib/CodeGen/CGObjC.cpp b/lib/CodeGen/CGObjC.cpp
index b94bbf2a384f..9c66ff0e8fb2 100644
--- a/lib/CodeGen/CGObjC.cpp
+++ b/lib/CodeGen/CGObjC.cpp
@@ -127,7 +127,7 @@ llvm::Value *CodeGenFunction::EmitObjCCollectionLiteral(const Expr *E,
llvm::Constant *Constant =
CGM.CreateRuntimeVariable(ConvertType(IdTy), ConstantName);
LValue LV = MakeNaturalAlignAddrLValue(Constant, IdTy);
- llvm::Value *Ptr = EmitLoadOfScalar(LV, E->getLocStart());
+ llvm::Value *Ptr = EmitLoadOfScalar(LV, E->getBeginLoc());
cast<llvm::LoadInst>(Ptr)->setMetadata(
CGM.getModule().getMDKindID("invariant.load"),
llvm::MDNode::get(getLLVMContext(), None));
@@ -352,6 +352,81 @@ static const Expr *findWeakLValue(const Expr *E) {
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"
+/// behavior; if that's dynamically a large proportion of all 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,
+ const CallArgList& Args, Selector Sel,
+ const ObjCMethodDecl *method,
+ bool isClassMessage) {
+ auto &CGM = CGF.CGM;
+ if (!CGM.getCodeGenOpts().ObjCConvertMessagesToRuntimeCalls)
+ return None;
+
+ auto &Runtime = CGM.getLangOpts().ObjCRuntime;
+ switch (Sel.getMethodFamily()) {
+ case OMF_alloc:
+ if (isClassMessage &&
+ Runtime.shouldUseRuntimeFunctionsForAlloc() &&
+ ResultType->isObjCObjectPointerType()) {
+ // [Foo alloc] -> objc_alloc(Foo)
+ if (Sel.isUnarySelector() && Sel.getNameForSlot(0) == "alloc")
+ return CGF.EmitObjCAlloc(Receiver, CGF.ConvertType(ResultType));
+ // [Foo allocWithZone:nil] -> objc_allocWithZone(Foo)
+ if (Sel.isKeywordSelector() && Sel.getNumArgs() == 1 &&
+ Args.size() == 1 && Args.front().getType()->isPointerType() &&
+ Sel.getNameForSlot(0) == "allocWithZone") {
+ const llvm::Value* arg = Args.front().getKnownRValue().getScalarVal();
+ if (isa<llvm::ConstantPointerNull>(arg))
+ return CGF.EmitObjCAllocWithZone(Receiver,
+ CGF.ConvertType(ResultType));
+ return None;
+ }
+ }
+ break;
+
+ case OMF_autorelease:
+ if (ResultType->isObjCObjectPointerType() &&
+ CGM.getLangOpts().getGC() == LangOptions::NonGC &&
+ Runtime.shouldUseARCFunctionsForRetainRelease())
+ return CGF.EmitObjCAutorelease(Receiver, CGF.ConvertType(ResultType));
+ break;
+
+ case OMF_retain:
+ if (ResultType->isObjCObjectPointerType() &&
+ CGM.getLangOpts().getGC() == LangOptions::NonGC &&
+ Runtime.shouldUseARCFunctionsForRetainRelease())
+ return CGF.EmitObjCRetainNonBlock(Receiver, CGF.ConvertType(ResultType));
+ break;
+
+ case OMF_release:
+ if (ResultType->isVoidType() &&
+ CGM.getLangOpts().getGC() == LangOptions::NonGC &&
+ Runtime.shouldUseARCFunctionsForRetainRelease()) {
+ CGF.EmitObjCRelease(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
@@ -474,10 +549,17 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E,
Args,
method);
} else {
- result = Runtime.GenerateMessageSend(*this, Return, ResultType,
- E->getSelector(),
- Receiver, Args, OID,
- method);
+ // Call runtime methods directly if we can.
+ if (Optional<llvm::Value *> SpecializedResult =
+ tryGenerateSpecializedMessageSend(*this, ResultType, Receiver, Args,
+ E->getSelector(), method,
+ isClassMessage)) {
+ result = RValue::get(SpecializedResult.getValue());
+ } else {
+ result = Runtime.GenerateMessageSend(*this, Return, ResultType,
+ E->getSelector(), Receiver, Args,
+ OID, method);
+ }
}
// For delegate init calls in ARC, implicitly store the result of
@@ -531,7 +613,7 @@ struct FinishARCDealloc final : EHScopeStack::Cleanup {
/// CodeGenFunction.
void CodeGenFunction::StartObjCMethod(const ObjCMethodDecl *OMD,
const ObjCContainerDecl *CD) {
- SourceLocation StartLoc = OMD->getLocStart();
+ SourceLocation StartLoc = OMD->getBeginLoc();
FunctionArgList args;
// Check if we should generate debug info for this method.
if (OMD->hasAttr<NoDebugAttr>())
@@ -548,7 +630,7 @@ void CodeGenFunction::StartObjCMethod(const ObjCMethodDecl *OMD,
args.append(OMD->param_begin(), OMD->param_end());
CurGD = OMD;
- CurEHLocation = OMD->getLocEnd();
+ CurEHLocation = OMD->getEndLoc();
StartFunction(OMD, OMD->getReturnType(), Fn, FI, args,
OMD->getLocation(), StartLoc);
@@ -568,7 +650,7 @@ static llvm::Value *emitARCRetainLoadOfScalar(CodeGenFunction &CGF,
LValue lvalue, QualType type);
/// Generate an Objective-C method. An Objective-C method is a C function with
-/// its pointer, name, and types registered in the class struture.
+/// its pointer, name, and types registered in the class structure.
void CodeGenFunction::GenerateObjCMethod(const ObjCMethodDecl *OMD) {
StartObjCMethod(OMD, OMD->getClassInterface());
PGO.assignRegionCounters(GlobalDecl(OMD), CurFn);
@@ -883,9 +965,10 @@ CodeGenFunction::generateObjCGetterBody(const ObjCImplementationDecl *classImpl,
// If there's a non-trivial 'get' expression, we just have to emit that.
if (!hasTrivialGetExpr(propImpl)) {
if (!AtomicHelperFn) {
- ReturnStmt ret(SourceLocation(), propImpl->getGetterCXXConstructor(),
- /*nrvo*/ nullptr);
- EmitReturnStmt(ret);
+ auto *ret = ReturnStmt::Create(getContext(), SourceLocation(),
+ propImpl->getGetterCXXConstructor(),
+ /* NRVOCandidate=*/nullptr);
+ EmitReturnStmt(*ret);
}
else {
ObjCIvarDecl *ivar = propImpl->getPropertyIvarDecl();
@@ -1068,8 +1151,9 @@ static void emitStructSetterCall(CodeGenFunction &CGF, ObjCMethodDecl *OMD,
// The second argument is the address of the parameter variable.
ParmVarDecl *argVar = *OMD->param_begin();
- DeclRefExpr argRef(argVar, false, argVar->getType().getNonReferenceType(),
- VK_LValue, SourceLocation());
+ DeclRefExpr argRef(CGF.getContext(), argVar, false,
+ argVar->getType().getNonReferenceType(), VK_LValue,
+ SourceLocation());
llvm::Value *argAddr = CGF.EmitLValue(&argRef).getPointer();
argAddr = CGF.Builder.CreateBitCast(argAddr, CGF.Int8PtrTy);
args.add(RValue::get(argAddr), CGF.getContext().VoidPtrTy);
@@ -1113,8 +1197,9 @@ static void emitCPPObjectAtomicSetterCall(CodeGenFunction &CGF,
// The second argument is the address of the parameter variable.
ParmVarDecl *argVar = *OMD->param_begin();
- DeclRefExpr argRef(argVar, false, argVar->getType().getNonReferenceType(),
- VK_LValue, SourceLocation());
+ DeclRefExpr argRef(CGF.getContext(), argVar, false,
+ argVar->getType().getNonReferenceType(), VK_LValue,
+ SourceLocation());
llvm::Value *argAddr = CGF.EmitLValue(&argRef).getPointer();
argAddr = CGF.Builder.CreateBitCast(argAddr, CGF.Int8PtrTy);
args.add(RValue::get(argAddr), CGF.getContext().VoidPtrTy);
@@ -1286,7 +1371,7 @@ CodeGenFunction::generateObjCSetterBody(const ObjCImplementationDecl *classImpl,
// Otherwise, fake up some ASTs and emit a normal assignment.
ValueDecl *selfDecl = setterMethod->getSelfDecl();
- DeclRefExpr self(selfDecl, false, selfDecl->getType(),
+ DeclRefExpr self(getContext(), selfDecl, false, selfDecl->getType(),
VK_LValue, SourceLocation());
ImplicitCastExpr selfLoad(ImplicitCastExpr::OnStack,
selfDecl->getType(), CK_LValueToRValue, &self,
@@ -1297,7 +1382,8 @@ CodeGenFunction::generateObjCSetterBody(const ObjCImplementationDecl *classImpl,
ParmVarDecl *argDecl = *setterMethod->param_begin();
QualType argType = argDecl->getType().getNonReferenceType();
- DeclRefExpr arg(argDecl, false, argType, VK_LValue, SourceLocation());
+ DeclRefExpr arg(getContext(), argDecl, false, argType, VK_LValue,
+ SourceLocation());
ImplicitCastExpr argLoad(ImplicitCastExpr::OnStack,
argType.getUnqualifiedType(), CK_LValueToRValue,
&arg, VK_RValue);
@@ -1459,7 +1545,8 @@ void CodeGenFunction::GenerateObjCCtorDtorMethod(ObjCImplementationDecl *IMP,
llvm::Value *CodeGenFunction::LoadObjCSelf() {
VarDecl *Self = cast<ObjCMethodDecl>(CurFuncDecl)->getSelfDecl();
- DeclRefExpr DRE(Self, /*is enclosing local*/ (CurFuncDecl != CurCodeDecl),
+ DeclRefExpr DRE(getContext(), Self,
+ /*is enclosing local*/ (CurFuncDecl != CurCodeDecl),
Self->getType(), VK_LValue, SourceLocation());
return EmitLoadOfScalar(EmitDeclRefLValue(&DRE), SourceLocation());
}
@@ -1645,9 +1732,9 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){
// Initialize the variable, in case it's a __block variable or something.
EmitAutoVarInit(variable);
- const VarDecl* D = cast<VarDecl>(SD->getSingleDecl());
- DeclRefExpr tempDRE(const_cast<VarDecl*>(D), false, D->getType(),
- VK_LValue, SourceLocation());
+ const VarDecl *D = cast<VarDecl>(SD->getSingleDecl());
+ DeclRefExpr tempDRE(getContext(), const_cast<VarDecl *>(D), false,
+ D->getType(), VK_LValue, SourceLocation());
elementLValue = EmitLValue(&tempDRE);
elementType = D->getType();
elementIsVariable = true;
@@ -1805,23 +1892,16 @@ llvm::Value *CodeGenFunction::EmitObjCExtendObjectLifetime(QualType type,
/// being intrinsically used up until this point in the program.
void CodeGenFunction::EmitARCIntrinsicUse(ArrayRef<llvm::Value*> values) {
llvm::Constant *&fn = CGM.getObjCEntrypoints().clang_arc_use;
- if (!fn) {
- llvm::FunctionType *fnType =
- llvm::FunctionType::get(CGM.VoidTy, None, true);
- fn = CGM.CreateRuntimeFunction(fnType, "clang.arc.use");
- }
+ if (!fn)
+ fn = CGM.getIntrinsic(llvm::Intrinsic::objc_clang_arc_use);
// This isn't really a "runtime" function, but as an intrinsic it
// doesn't really matter as long as we align things up.
EmitNounwindRuntimeCall(fn, values);
}
-
-static llvm::Constant *createARCRuntimeFunction(CodeGenModule &CGM,
- llvm::FunctionType *FTy,
- StringRef Name) {
- llvm::Constant *RTF = CGM.CreateRuntimeFunction(FTy, Name);
-
+static void setARCRuntimeFunctionLinkage(CodeGenModule &CGM,
+ llvm::Constant *RTF) {
if (auto *F = dyn_cast<llvm::Function>(RTF)) {
// If the target runtime doesn't naturally support ARC, emit weak
// references to the runtime support library. We don't really
@@ -1829,14 +1909,8 @@ static llvm::Constant *createARCRuntimeFunction(CodeGenModule &CGM,
if (!CGM.getLangOpts().ObjCRuntime.hasNativeARC() &&
!CGM.getTriple().isOSBinFormatCOFF()) {
F->setLinkage(llvm::Function::ExternalWeakLinkage);
- } else if (Name == "objc_retain" || Name == "objc_release") {
- // If we have Native ARC, set nonlazybind attribute for these APIs for
- // performance.
- F->addFnAttr(llvm::Attribute::NonLazyBind);
}
}
-
- return RTF;
}
/// Perform an operation having the signature
@@ -1844,20 +1918,20 @@ static llvm::Constant *createARCRuntimeFunction(CodeGenModule &CGM,
/// 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,
+ llvm::Intrinsic::ID IntID,
bool isTailCall = false) {
if (isa<llvm::ConstantPointerNull>(value))
return value;
if (!fn) {
- llvm::FunctionType *fnType =
- llvm::FunctionType::get(CGF.Int8PtrTy, CGF.Int8PtrTy, false);
- fn = createARCRuntimeFunction(CGF.CGM, fnType, fnName);
+ fn = CGF.CGM.getIntrinsic(IntID);
+ setARCRuntimeFunctionLinkage(CGF.CGM, fn);
}
// Cast the argument to 'id'.
- llvm::Type *origType = value->getType();
+ llvm::Type *origType = returnType ? returnType : value->getType();
value = CGF.Builder.CreateBitCast(value, CGF.Int8PtrTy);
// Call the function.
@@ -1874,11 +1948,10 @@ static llvm::Value *emitARCValueOperation(CodeGenFunction &CGF,
static llvm::Value *emitARCLoadOperation(CodeGenFunction &CGF,
Address addr,
llvm::Constant *&fn,
- StringRef fnName) {
+ llvm::Intrinsic::ID IntID) {
if (!fn) {
- llvm::FunctionType *fnType =
- llvm::FunctionType::get(CGF.Int8PtrTy, CGF.Int8PtrPtrTy, false);
- fn = createARCRuntimeFunction(CGF.CGM, fnType, fnName);
+ fn = CGF.CGM.getIntrinsic(IntID);
+ setARCRuntimeFunctionLinkage(CGF.CGM, fn);
}
// Cast the argument to 'id*'.
@@ -1901,16 +1974,13 @@ static llvm::Value *emitARCStoreOperation(CodeGenFunction &CGF,
Address addr,
llvm::Value *value,
llvm::Constant *&fn,
- StringRef fnName,
+ llvm::Intrinsic::ID IntID,
bool ignored) {
assert(addr.getElementType() == value->getType());
if (!fn) {
- llvm::Type *argTypes[] = { CGF.Int8PtrPtrTy, CGF.Int8PtrTy };
-
- llvm::FunctionType *fnType
- = llvm::FunctionType::get(CGF.Int8PtrTy, argTypes, false);
- fn = createARCRuntimeFunction(CGF.CGM, fnType, fnName);
+ fn = CGF.CGM.getIntrinsic(IntID);
+ setARCRuntimeFunctionLinkage(CGF.CGM, fn);
}
llvm::Type *origType = value->getType();
@@ -1932,15 +2002,12 @@ static void emitARCCopyOperation(CodeGenFunction &CGF,
Address dst,
Address src,
llvm::Constant *&fn,
- StringRef fnName) {
+ llvm::Intrinsic::ID IntID) {
assert(dst.getType() == src.getType());
if (!fn) {
- llvm::Type *argTypes[] = { CGF.Int8PtrPtrTy, CGF.Int8PtrPtrTy };
-
- llvm::FunctionType *fnType
- = llvm::FunctionType::get(CGF.Builder.getVoidTy(), argTypes, false);
- fn = createARCRuntimeFunction(CGF.CGM, fnType, fnName);
+ fn = CGF.CGM.getIntrinsic(IntID);
+ setARCRuntimeFunctionLinkage(CGF.CGM, fn);
}
llvm::Value *args[] = {
@@ -1950,6 +2017,39 @@ static void emitARCCopyOperation(CodeGenFunction &CGF,
CGF.EmitNounwindRuntimeCall(fn, args);
}
+/// Perform an operation having the signature
+/// i8* (i8*)
+/// where a null input causes a no-op and returns null.
+static llvm::Value *emitObjCValueOperation(CodeGenFunction &CGF,
+ llvm::Value *value,
+ llvm::Type *returnType,
+ llvm::Constant *&fn,
+ StringRef fnName) {
+ if (isa<llvm::ConstantPointerNull>(value))
+ return value;
+
+ if (!fn) {
+ llvm::FunctionType *fnType =
+ llvm::FunctionType::get(CGF.Int8PtrTy, CGF.Int8PtrTy, false);
+ fn = CGF.CGM.CreateRuntimeFunction(fnType, fnName);
+
+ // We have Native ARC, so set nonlazybind attribute for performance
+ if (llvm::Function *f = dyn_cast<llvm::Function>(fn))
+ if (fnName == "objc_retain")
+ f->addFnAttr(llvm::Attribute::NonLazyBind);
+ }
+
+ // Cast the argument to 'id'.
+ llvm::Type *origType = returnType ? returnType : value->getType();
+ value = CGF.Builder.CreateBitCast(value, CGF.Int8PtrTy);
+
+ // Call the function.
+ llvm::CallInst *call = CGF.EmitNounwindRuntimeCall(fn, value);
+
+ // Cast the result back to the original type.
+ return CGF.Builder.CreateBitCast(call, origType);
+}
+
/// Produce the code to do a retain. Based on the type, calls one of:
/// call i8* \@objc_retain(i8* %value)
/// call i8* \@objc_retainBlock(i8* %value)
@@ -1963,9 +2063,9 @@ llvm::Value *CodeGenFunction::EmitARCRetain(QualType type, llvm::Value *value) {
/// Retain the given object, with normal retain semantics.
/// call i8* \@objc_retain(i8* %value)
llvm::Value *CodeGenFunction::EmitARCRetainNonBlock(llvm::Value *value) {
- return emitARCValueOperation(*this, value,
+ return emitARCValueOperation(*this, value, nullptr,
CGM.getObjCEntrypoints().objc_retain,
- "objc_retain");
+ llvm::Intrinsic::objc_retain);
}
/// Retain the given block, with _Block_copy semantics.
@@ -1977,9 +2077,9 @@ llvm::Value *CodeGenFunction::EmitARCRetainNonBlock(llvm::Value *value) {
llvm::Value *CodeGenFunction::EmitARCRetainBlock(llvm::Value *value,
bool mandatory) {
llvm::Value *result
- = emitARCValueOperation(*this, value,
+ = emitARCValueOperation(*this, value, nullptr,
CGM.getObjCEntrypoints().objc_retainBlock,
- "objc_retainBlock");
+ llvm::Intrinsic::objc_retainBlock);
// If the copy isn't mandatory, add !clang.arc.copy_on_escape to
// tell the optimizer that it doesn't need to do this copy if the
@@ -2047,9 +2147,9 @@ static void emitAutoreleasedReturnValueMarker(CodeGenFunction &CGF) {
llvm::Value *
CodeGenFunction::EmitARCRetainAutoreleasedReturnValue(llvm::Value *value) {
emitAutoreleasedReturnValueMarker(*this);
- return emitARCValueOperation(*this, value,
+ return emitARCValueOperation(*this, value, nullptr,
CGM.getObjCEntrypoints().objc_retainAutoreleasedReturnValue,
- "objc_retainAutoreleasedReturnValue");
+ llvm::Intrinsic::objc_retainAutoreleasedReturnValue);
}
/// Claim a possibly-autoreleased return value at +0. This is only
@@ -2062,9 +2162,9 @@ CodeGenFunction::EmitARCRetainAutoreleasedReturnValue(llvm::Value *value) {
llvm::Value *
CodeGenFunction::EmitARCUnsafeClaimAutoreleasedReturnValue(llvm::Value *value) {
emitAutoreleasedReturnValueMarker(*this);
- return emitARCValueOperation(*this, value,
+ return emitARCValueOperation(*this, value, nullptr,
CGM.getObjCEntrypoints().objc_unsafeClaimAutoreleasedReturnValue,
- "objc_unsafeClaimAutoreleasedReturnValue");
+ llvm::Intrinsic::objc_unsafeClaimAutoreleasedReturnValue);
}
/// Release the given object.
@@ -2075,9 +2175,8 @@ void CodeGenFunction::EmitARCRelease(llvm::Value *value,
llvm::Constant *&fn = CGM.getObjCEntrypoints().objc_release;
if (!fn) {
- llvm::FunctionType *fnType =
- llvm::FunctionType::get(Builder.getVoidTy(), Int8PtrTy, false);
- fn = createARCRuntimeFunction(CGM, fnType, "objc_release");
+ fn = CGM.getIntrinsic(llvm::Intrinsic::objc_release);
+ setARCRuntimeFunctionLinkage(CGM, fn);
}
// Cast the argument to 'id'.
@@ -2122,10 +2221,8 @@ llvm::Value *CodeGenFunction::EmitARCStoreStrongCall(Address addr,
llvm::Constant *&fn = CGM.getObjCEntrypoints().objc_storeStrong;
if (!fn) {
- llvm::Type *argTypes[] = { Int8PtrPtrTy, Int8PtrTy };
- llvm::FunctionType *fnType
- = llvm::FunctionType::get(Builder.getVoidTy(), argTypes, false);
- fn = createARCRuntimeFunction(CGM, fnType, "objc_storeStrong");
+ fn = CGM.getIntrinsic(llvm::Intrinsic::objc_storeStrong);
+ setARCRuntimeFunctionLinkage(CGM, fn);
}
llvm::Value *args[] = {
@@ -2177,18 +2274,18 @@ llvm::Value *CodeGenFunction::EmitARCStoreStrong(LValue dst,
/// Autorelease the given object.
/// call i8* \@objc_autorelease(i8* %value)
llvm::Value *CodeGenFunction::EmitARCAutorelease(llvm::Value *value) {
- return emitARCValueOperation(*this, value,
+ return emitARCValueOperation(*this, value, nullptr,
CGM.getObjCEntrypoints().objc_autorelease,
- "objc_autorelease");
+ llvm::Intrinsic::objc_autorelease);
}
/// Autorelease the given object.
/// call i8* \@objc_autoreleaseReturnValue(i8* %value)
llvm::Value *
CodeGenFunction::EmitARCAutoreleaseReturnValue(llvm::Value *value) {
- return emitARCValueOperation(*this, value,
+ return emitARCValueOperation(*this, value, nullptr,
CGM.getObjCEntrypoints().objc_autoreleaseReturnValue,
- "objc_autoreleaseReturnValue",
+ llvm::Intrinsic::objc_autoreleaseReturnValue,
/*isTailCall*/ true);
}
@@ -2196,9 +2293,9 @@ CodeGenFunction::EmitARCAutoreleaseReturnValue(llvm::Value *value) {
/// call i8* \@objc_retainAutoreleaseReturnValue(i8* %value)
llvm::Value *
CodeGenFunction::EmitARCRetainAutoreleaseReturnValue(llvm::Value *value) {
- return emitARCValueOperation(*this, value,
+ return emitARCValueOperation(*this, value, nullptr,
CGM.getObjCEntrypoints().objc_retainAutoreleaseReturnValue,
- "objc_retainAutoreleaseReturnValue",
+ llvm::Intrinsic::objc_retainAutoreleaseReturnValue,
/*isTailCall*/ true);
}
@@ -2225,9 +2322,9 @@ llvm::Value *CodeGenFunction::EmitARCRetainAutorelease(QualType type,
/// call i8* \@objc_retainAutorelease(i8* %value)
llvm::Value *
CodeGenFunction::EmitARCRetainAutoreleaseNonBlock(llvm::Value *value) {
- return emitARCValueOperation(*this, value,
+ return emitARCValueOperation(*this, value, nullptr,
CGM.getObjCEntrypoints().objc_retainAutorelease,
- "objc_retainAutorelease");
+ llvm::Intrinsic::objc_retainAutorelease);
}
/// i8* \@objc_loadWeak(i8** %addr)
@@ -2235,14 +2332,14 @@ CodeGenFunction::EmitARCRetainAutoreleaseNonBlock(llvm::Value *value) {
llvm::Value *CodeGenFunction::EmitARCLoadWeak(Address addr) {
return emitARCLoadOperation(*this, addr,
CGM.getObjCEntrypoints().objc_loadWeak,
- "objc_loadWeak");
+ llvm::Intrinsic::objc_loadWeak);
}
/// i8* \@objc_loadWeakRetained(i8** %addr)
llvm::Value *CodeGenFunction::EmitARCLoadWeakRetained(Address addr) {
return emitARCLoadOperation(*this, addr,
CGM.getObjCEntrypoints().objc_loadWeakRetained,
- "objc_loadWeakRetained");
+ llvm::Intrinsic::objc_loadWeakRetained);
}
/// i8* \@objc_storeWeak(i8** %addr, i8* %value)
@@ -2252,7 +2349,7 @@ llvm::Value *CodeGenFunction::EmitARCStoreWeak(Address addr,
bool ignored) {
return emitARCStoreOperation(*this, addr, value,
CGM.getObjCEntrypoints().objc_storeWeak,
- "objc_storeWeak", ignored);
+ llvm::Intrinsic::objc_storeWeak, ignored);
}
/// i8* \@objc_initWeak(i8** %addr, i8* %value)
@@ -2272,7 +2369,7 @@ void CodeGenFunction::EmitARCInitWeak(Address addr, llvm::Value *value) {
emitARCStoreOperation(*this, addr, value,
CGM.getObjCEntrypoints().objc_initWeak,
- "objc_initWeak", /*ignored*/ true);
+ llvm::Intrinsic::objc_initWeak, /*ignored*/ true);
}
/// void \@objc_destroyWeak(i8** %addr)
@@ -2280,9 +2377,8 @@ void CodeGenFunction::EmitARCInitWeak(Address addr, llvm::Value *value) {
void CodeGenFunction::EmitARCDestroyWeak(Address addr) {
llvm::Constant *&fn = CGM.getObjCEntrypoints().objc_destroyWeak;
if (!fn) {
- llvm::FunctionType *fnType =
- llvm::FunctionType::get(Builder.getVoidTy(), Int8PtrPtrTy, false);
- fn = createARCRuntimeFunction(CGM, fnType, "objc_destroyWeak");
+ fn = CGM.getIntrinsic(llvm::Intrinsic::objc_destroyWeak);
+ setARCRuntimeFunctionLinkage(CGM, fn);
}
// Cast the argument to 'id*'.
@@ -2297,7 +2393,7 @@ void CodeGenFunction::EmitARCDestroyWeak(Address addr) {
void CodeGenFunction::EmitARCMoveWeak(Address dst, Address src) {
emitARCCopyOperation(*this, dst, src,
CGM.getObjCEntrypoints().objc_moveWeak,
- "objc_moveWeak");
+ llvm::Intrinsic::objc_moveWeak);
}
/// void \@objc_copyWeak(i8** %dest, i8** %src)
@@ -2306,7 +2402,7 @@ void CodeGenFunction::EmitARCMoveWeak(Address dst, Address src) {
void CodeGenFunction::EmitARCCopyWeak(Address dst, Address src) {
emitARCCopyOperation(*this, dst, src,
CGM.getObjCEntrypoints().objc_copyWeak,
- "objc_copyWeak");
+ llvm::Intrinsic::objc_copyWeak);
}
void CodeGenFunction::emitARCCopyAssignWeak(QualType Ty, Address DstAddr,
@@ -2329,9 +2425,8 @@ void CodeGenFunction::emitARCMoveAssignWeak(QualType Ty, Address DstAddr,
llvm::Value *CodeGenFunction::EmitObjCAutoreleasePoolPush() {
llvm::Constant *&fn = CGM.getObjCEntrypoints().objc_autoreleasePoolPush;
if (!fn) {
- llvm::FunctionType *fnType =
- llvm::FunctionType::get(Int8PtrTy, false);
- fn = createARCRuntimeFunction(CGM, fnType, "objc_autoreleasePoolPush");
+ fn = CGM.getIntrinsic(llvm::Intrinsic::objc_autoreleasePoolPush);
+ setARCRuntimeFunctionLinkage(CGM, fn);
}
return EmitNounwindRuntimeCall(fn);
@@ -2342,18 +2437,28 @@ llvm::Value *CodeGenFunction::EmitObjCAutoreleasePoolPush() {
void CodeGenFunction::EmitObjCAutoreleasePoolPop(llvm::Value *value) {
assert(value->getType() == Int8PtrTy);
- llvm::Constant *&fn = CGM.getObjCEntrypoints().objc_autoreleasePoolPop;
- if (!fn) {
- llvm::FunctionType *fnType =
- llvm::FunctionType::get(Builder.getVoidTy(), Int8PtrTy, false);
+ if (getInvokeDest()) {
+ // Call the runtime method not the intrinsic if we are handling exceptions
+ llvm::Constant *&fn =
+ CGM.getObjCEntrypoints().objc_autoreleasePoolPopInvoke;
+ if (!fn) {
+ llvm::FunctionType *fnType =
+ llvm::FunctionType::get(Builder.getVoidTy(), Int8PtrTy, false);
+ fn = CGM.CreateRuntimeFunction(fnType, "objc_autoreleasePoolPop");
+ setARCRuntimeFunctionLinkage(CGM, fn);
+ }
- // We don't want to use a weak import here; instead we should not
- // fall into this path.
- fn = createARCRuntimeFunction(CGM, fnType, "objc_autoreleasePoolPop");
- }
+ // objc_autoreleasePoolPop can throw.
+ EmitRuntimeCallOrInvoke(fn, value);
+ } else {
+ llvm::Constant *&fn = CGM.getObjCEntrypoints().objc_autoreleasePoolPop;
+ if (!fn) {
+ fn = CGM.getIntrinsic(llvm::Intrinsic::objc_autoreleasePoolPop);
+ setARCRuntimeFunctionLinkage(CGM, fn);
+ }
- // objc_autoreleasePoolPop can throw.
- EmitRuntimeCallOrInvoke(fn, value);
+ EmitRuntimeCall(fn, value);
+ }
}
/// Produce the code to do an MRR version objc_autoreleasepool_push.
@@ -2384,6 +2489,24 @@ llvm::Value *CodeGenFunction::EmitObjCMRRAutoreleasePoolPush() {
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 emitObjCValueOperation(*this, value, resultType,
+ CGM.getObjCEntrypoints().objc_alloc,
+ "objc_alloc");
+}
+
+/// Allocate the given objc object.
+/// call i8* \@objc_allocWithZone(i8* %value)
+llvm::Value *CodeGenFunction::EmitObjCAllocWithZone(llvm::Value *value,
+ llvm::Type *resultType) {
+ return emitObjCValueOperation(*this, value, resultType,
+ CGM.getObjCEntrypoints().objc_allocWithZone,
+ "objc_allocWithZone");
+}
+
/// Produce the code to do a primitive release.
/// [tmp drain];
void CodeGenFunction::EmitObjCMRRAutoreleasePoolPop(llvm::Value *Arg) {
@@ -2418,6 +2541,55 @@ void CodeGenFunction::emitARCIntrinsicUse(CodeGenFunction &CGF, Address addr,
CGF.EmitARCIntrinsicUse(value);
}
+/// Autorelease the given object.
+/// call i8* \@objc_autorelease(i8* %value)
+llvm::Value *CodeGenFunction::EmitObjCAutorelease(llvm::Value *value,
+ llvm::Type *returnType) {
+ return emitObjCValueOperation(*this, value, returnType,
+ CGM.getObjCEntrypoints().objc_autoreleaseRuntimeFunction,
+ "objc_autorelease");
+}
+
+/// Retain the given object, with normal retain semantics.
+/// call i8* \@objc_retain(i8* %value)
+llvm::Value *CodeGenFunction::EmitObjCRetainNonBlock(llvm::Value *value,
+ llvm::Type *returnType) {
+ return emitObjCValueOperation(*this, value, returnType,
+ CGM.getObjCEntrypoints().objc_retainRuntimeFunction,
+ "objc_retain");
+}
+
+/// Release the given object.
+/// call void \@objc_release(i8* %value)
+void CodeGenFunction::EmitObjCRelease(llvm::Value *value,
+ ARCPreciseLifetime_t precise) {
+ if (isa<llvm::ConstantPointerNull>(value)) return;
+
+ llvm::Constant *&fn = CGM.getObjCEntrypoints().objc_release;
+ if (!fn) {
+ if (!fn) {
+ llvm::FunctionType *fnType =
+ llvm::FunctionType::get(Builder.getVoidTy(), Int8PtrTy, false);
+ fn = CGM.CreateRuntimeFunction(fnType, "objc_release");
+ setARCRuntimeFunctionLinkage(CGM, fn);
+ // We have Native ARC, so set nonlazybind attribute for performance
+ if (llvm::Function *f = dyn_cast<llvm::Function>(fn))
+ f->addFnAttr(llvm::Attribute::NonLazyBind);
+ }
+ }
+
+ // Cast the argument to 'id'.
+ value = Builder.CreateBitCast(value, Int8PtrTy);
+
+ // Call objc_release.
+ llvm::CallInst *call = EmitNounwindRuntimeCall(fn, value);
+
+ if (precise == ARCImpreciseLifetime) {
+ call->setMetadata("clang.imprecise_release",
+ llvm::MDNode::get(Builder.getContext(), None));
+ }
+}
+
namespace {
struct CallObjCAutoreleasePoolObject final : EHScopeStack::Cleanup {
llvm::Value *Token;
@@ -2446,27 +2618,36 @@ void CodeGenFunction::EmitObjCAutoreleasePoolCleanup(llvm::Value *Ptr) {
EHStack.pushCleanup<CallObjCMRRAutoreleasePoolObject>(NormalCleanup, Ptr);
}
-static TryEmitResult tryEmitARCRetainLoadOfScalar(CodeGenFunction &CGF,
- LValue lvalue,
- QualType type) {
- switch (type.getObjCLifetime()) {
+static bool shouldRetainObjCLifetime(Qualifiers::ObjCLifetime lifetime) {
+ switch (lifetime) {
case Qualifiers::OCL_None:
case Qualifiers::OCL_ExplicitNone:
case Qualifiers::OCL_Strong:
case Qualifiers::OCL_Autoreleasing:
- return TryEmitResult(CGF.EmitLoadOfLValue(lvalue,
- SourceLocation()).getScalarVal(),
- false);
+ return true;
case Qualifiers::OCL_Weak:
- return TryEmitResult(CGF.EmitARCLoadWeakRetained(lvalue.getAddress()),
- true);
+ return false;
}
llvm_unreachable("impossible lifetime!");
}
static TryEmitResult tryEmitARCRetainLoadOfScalar(CodeGenFunction &CGF,
+ LValue lvalue,
+ QualType type) {
+ llvm::Value *result;
+ bool shouldRetain = shouldRetainObjCLifetime(type.getObjCLifetime());
+ if (shouldRetain) {
+ result = CGF.EmitLoadOfLValue(lvalue, SourceLocation()).getScalarVal();
+ } else {
+ assert(type.getObjCLifetime() == Qualifiers::OCL_Weak);
+ result = CGF.EmitARCLoadWeakRetained(lvalue.getAddress());
+ }
+ return TryEmitResult(result, !shouldRetain);
+}
+
+static TryEmitResult tryEmitARCRetainLoadOfScalar(CodeGenFunction &CGF,
const Expr *e) {
e = e->IgnoreParens();
QualType type = e->getType();
@@ -2500,6 +2681,16 @@ static TryEmitResult tryEmitARCRetainLoadOfScalar(CodeGenFunction &CGF,
cast<BinaryOperator>(e)->getOpcode() == BO_Assign)
return TryEmitResult(CGF.EmitScalarExpr(e), false);
+ // Try to emit code for scalar constant instead of emitting LValue and
+ // loading it because we are not guaranteed to have an l-value. One of such
+ // cases is DeclRefExpr referencing non-odr-used constant-evaluated variable.
+ if (const auto *decl_expr = dyn_cast<DeclRefExpr>(e)) {
+ auto *DRE = const_cast<DeclRefExpr *>(decl_expr);
+ if (CodeGenFunction::ConstantEmission constant = CGF.tryEmitAsConstant(DRE))
+ return TryEmitResult(CGF.emitScalarConstant(constant, DRE),
+ !shouldRetainObjCLifetime(type.getObjCLifetime()));
+ }
+
return tryEmitARCRetainLoadOfScalar(CGF, CGF.EmitLValue(e), type);
}
@@ -3229,29 +3420,32 @@ CodeGenFunction::GenerateObjCAtomicSetterCopyHelperFunction(
ASTContext &C = getContext();
IdentifierInfo *II
= &CGM.getContext().Idents.get("__assign_helper_atomic_property_");
- FunctionDecl *FD = FunctionDecl::Create(C,
- C.getTranslationUnitDecl(),
- SourceLocation(),
- SourceLocation(), II, C.VoidTy,
- nullptr, SC_Static,
- false,
- false);
+ QualType ReturnTy = C.VoidTy;
QualType DestTy = C.getPointerType(Ty);
QualType SrcTy = Ty;
SrcTy.addConst();
SrcTy = C.getPointerType(SrcTy);
+ SmallVector<QualType, 2> ArgTys;
+ ArgTys.push_back(DestTy);
+ ArgTys.push_back(SrcTy);
+ QualType FunctionTy = C.getFunctionType(ReturnTy, ArgTys, {});
+
+ FunctionDecl *FD = FunctionDecl::Create(
+ C, C.getTranslationUnitDecl(), SourceLocation(), SourceLocation(), II,
+ FunctionTy, nullptr, SC_Static, false, false);
+
FunctionArgList args;
- ImplicitParamDecl DstDecl(getContext(), FD, SourceLocation(), /*Id=*/nullptr,
- DestTy, ImplicitParamDecl::Other);
+ ImplicitParamDecl DstDecl(C, FD, SourceLocation(), /*Id=*/nullptr, DestTy,
+ ImplicitParamDecl::Other);
args.push_back(&DstDecl);
- ImplicitParamDecl SrcDecl(getContext(), FD, SourceLocation(), /*Id=*/nullptr,
- SrcTy, ImplicitParamDecl::Other);
+ ImplicitParamDecl SrcDecl(C, FD, SourceLocation(), /*Id=*/nullptr, SrcTy,
+ ImplicitParamDecl::Other);
args.push_back(&SrcDecl);
const CGFunctionInfo &FI =
- CGM.getTypes().arrangeBuiltinFunctionDeclaration(C.VoidTy, args);
+ CGM.getTypes().arrangeBuiltinFunctionDeclaration(ReturnTy, args);
llvm::FunctionType *LTy = CGM.getTypes().GetFunctionType(FI);
@@ -3262,25 +3456,25 @@ CodeGenFunction::GenerateObjCAtomicSetterCopyHelperFunction(
CGM.SetInternalFunctionAttributes(GlobalDecl(), Fn, FI);
- StartFunction(FD, C.VoidTy, Fn, FI, args);
+ StartFunction(FD, ReturnTy, Fn, FI, args);
- DeclRefExpr DstExpr(&DstDecl, false, DestTy,
- VK_RValue, SourceLocation());
+ DeclRefExpr DstExpr(getContext(), &DstDecl, false, DestTy, VK_RValue,
+ SourceLocation());
UnaryOperator DST(&DstExpr, UO_Deref, DestTy->getPointeeType(),
VK_LValue, OK_Ordinary, SourceLocation(), false);
- DeclRefExpr SrcExpr(&SrcDecl, false, SrcTy,
- VK_RValue, SourceLocation());
+ DeclRefExpr SrcExpr(getContext(), &SrcDecl, false, SrcTy, VK_RValue,
+ SourceLocation());
UnaryOperator SRC(&SrcExpr, UO_Deref, SrcTy->getPointeeType(),
VK_LValue, OK_Ordinary, SourceLocation(), false);
Expr *Args[2] = { &DST, &SRC };
CallExpr *CalleeExp = cast<CallExpr>(PID->getSetterCXXAssignment());
- CXXOperatorCallExpr TheCall(C, OO_Equal, CalleeExp->getCallee(),
- Args, DestTy->getPointeeType(),
- VK_LValue, SourceLocation(), FPOptions());
+ CXXOperatorCallExpr *TheCall = CXXOperatorCallExpr::Create(
+ C, OO_Equal, CalleeExp->getCallee(), Args, DestTy->getPointeeType(),
+ VK_LValue, SourceLocation(), FPOptions());
- EmitStmt(&TheCall);
+ EmitStmt(TheCall);
FinishFunction();
HelperFn = llvm::ConstantExpr::getBitCast(Fn, VoidPtrTy);
@@ -3301,53 +3495,54 @@ CodeGenFunction::GenerateObjCAtomicGetterCopyHelperFunction(
if ((!(PD->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_atomic)))
return nullptr;
llvm::Constant *HelperFn = nullptr;
-
if (hasTrivialGetExpr(PID))
return nullptr;
assert(PID->getGetterCXXConstructor() && "getGetterCXXConstructor - null");
if ((HelperFn = CGM.getAtomicGetterHelperFnMap(Ty)))
return HelperFn;
-
ASTContext &C = getContext();
- IdentifierInfo *II
- = &CGM.getContext().Idents.get("__copy_helper_atomic_property_");
- FunctionDecl *FD = FunctionDecl::Create(C,
- C.getTranslationUnitDecl(),
- SourceLocation(),
- SourceLocation(), II, C.VoidTy,
- nullptr, SC_Static,
- false,
- false);
+ IdentifierInfo *II =
+ &CGM.getContext().Idents.get("__copy_helper_atomic_property_");
+ QualType ReturnTy = C.VoidTy;
QualType DestTy = C.getPointerType(Ty);
QualType SrcTy = Ty;
SrcTy.addConst();
SrcTy = C.getPointerType(SrcTy);
+ SmallVector<QualType, 2> ArgTys;
+ ArgTys.push_back(DestTy);
+ ArgTys.push_back(SrcTy);
+ QualType FunctionTy = C.getFunctionType(ReturnTy, ArgTys, {});
+
+ FunctionDecl *FD = FunctionDecl::Create(
+ C, C.getTranslationUnitDecl(), SourceLocation(), SourceLocation(), II,
+ FunctionTy, nullptr, SC_Static, false, false);
+
FunctionArgList args;
- ImplicitParamDecl DstDecl(getContext(), FD, SourceLocation(), /*Id=*/nullptr,
- DestTy, ImplicitParamDecl::Other);
+ ImplicitParamDecl DstDecl(C, FD, SourceLocation(), /*Id=*/nullptr, DestTy,
+ ImplicitParamDecl::Other);
args.push_back(&DstDecl);
- ImplicitParamDecl SrcDecl(getContext(), FD, SourceLocation(), /*Id=*/nullptr,
- SrcTy, ImplicitParamDecl::Other);
+ ImplicitParamDecl SrcDecl(C, FD, SourceLocation(), /*Id=*/nullptr, SrcTy,
+ ImplicitParamDecl::Other);
args.push_back(&SrcDecl);
const CGFunctionInfo &FI =
- CGM.getTypes().arrangeBuiltinFunctionDeclaration(C.VoidTy, args);
+ CGM.getTypes().arrangeBuiltinFunctionDeclaration(ReturnTy, args);
llvm::FunctionType *LTy = CGM.getTypes().GetFunctionType(FI);
- llvm::Function *Fn =
- llvm::Function::Create(LTy, llvm::GlobalValue::InternalLinkage,
- "__copy_helper_atomic_property_", &CGM.getModule());
+ llvm::Function *Fn = llvm::Function::Create(
+ LTy, llvm::GlobalValue::InternalLinkage, "__copy_helper_atomic_property_",
+ &CGM.getModule());
CGM.SetInternalFunctionAttributes(GlobalDecl(), Fn, FI);
- StartFunction(FD, C.VoidTy, Fn, FI, args);
+ StartFunction(FD, ReturnTy, Fn, FI, args);
- DeclRefExpr SrcExpr(&SrcDecl, false, SrcTy,
- VK_RValue, SourceLocation());
+ DeclRefExpr SrcExpr(getContext(), &SrcDecl, false, SrcTy, VK_RValue,
+ SourceLocation());
UnaryOperator SRC(&SrcExpr, UO_Deref, SrcTy->getPointeeType(),
VK_LValue, OK_Ordinary, SourceLocation(), false);
@@ -3372,8 +3567,8 @@ CodeGenFunction::GenerateObjCAtomicGetterCopyHelperFunction(
CXXConstExpr->getConstructionKind(),
SourceRange());
- DeclRefExpr DstExpr(&DstDecl, false, DestTy,
- VK_RValue, SourceLocation());
+ DeclRefExpr DstExpr(getContext(), &DstDecl, false, DestTy, VK_RValue,
+ SourceLocation());
RValue DV = EmitAnyExpr(&DstExpr);
CharUnits Alignment