diff options
Diffstat (limited to 'lib/CodeGen/CGObjC.cpp')
-rw-r--r-- | lib/CodeGen/CGObjC.cpp | 511 |
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 |