"Fossies" - the Fresh Open Source Software Archive  

Source code changes of the file "lib/CodeGen/CGObjC.cpp" between
cfe-8.0.1.src.tar.xz and cfe-9.0.0.src.tar.xz

About: Clang is an LLVM front end for the C, C++, and Objective-C languages. Clang aims to provide a better user experience through expressive diagnostics, a high level of conformance to language standards, fast compilation, and low memory use.

CGObjC.cpp  (cfe-8.0.1.src.tar.xz):CGObjC.cpp  (cfe-9.0.0.src.tar.xz)
//===---- CGObjC.cpp - Emit LLVM Code for Objective-C ---------------------===// //===---- CGObjC.cpp - Emit LLVM Code for Objective-C ---------------------===//
// //
// The LLVM Compiler Infrastructure // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// // See https://llvm.org/LICENSE.txt for license information.
// This file is distributed under the University of Illinois Open Source // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// License. See LICENSE.TXT for details.
// //
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
// //
// This contains code to emit Objective-C code as LLVM code. // This contains code to emit Objective-C code as LLVM code.
// //
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
#include "CGDebugInfo.h" #include "CGDebugInfo.h"
#include "CGObjCRuntime.h" #include "CGObjCRuntime.h"
#include "CodeGenFunction.h" #include "CodeGenFunction.h"
#include "CodeGenModule.h" #include "CodeGenModule.h"
#include "ConstantEmitter.h"
#include "TargetInfo.h" #include "TargetInfo.h"
#include "clang/AST/ASTContext.h" #include "clang/AST/ASTContext.h"
#include "clang/AST/DeclObjC.h" #include "clang/AST/DeclObjC.h"
#include "clang/AST/StmtObjC.h" #include "clang/AST/StmtObjC.h"
#include "clang/Basic/Diagnostic.h" #include "clang/Basic/Diagnostic.h"
#include "clang/CodeGen/CGFunctionInfo.h" #include "clang/CodeGen/CGFunctionInfo.h"
#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/STLExtras.h"
#include "llvm/IR/CallSite.h"
#include "llvm/IR/DataLayout.h" #include "llvm/IR/DataLayout.h"
#include "llvm/IR/InlineAsm.h" #include "llvm/IR/InlineAsm.h"
using namespace clang; using namespace clang;
using namespace CodeGen; using namespace CodeGen;
typedef llvm::PointerIntPair<llvm::Value*,1,bool> TryEmitResult; typedef llvm::PointerIntPair<llvm::Value*,1,bool> TryEmitResult;
static TryEmitResult static TryEmitResult
tryEmitARCRetainScalarExpr(CodeGenFunction &CGF, const Expr *e); tryEmitARCRetainScalarExpr(CodeGenFunction &CGF, const Expr *e);
static RValue AdjustObjCObjectType(CodeGenFunction &CGF, static RValue AdjustObjCObjectType(CodeGenFunction &CGF,
QualType ET, QualType ET,
skipping to change at line 65 skipping to change at line 64
/// the appropriate expression boxing method. This will either be /// the appropriate expression boxing method. This will either be
/// one of +[NSNumber numberWith<Type>:], or +[NSString stringWithUTF8String:], /// one of +[NSNumber numberWith<Type>:], or +[NSString stringWithUTF8String:],
/// or [NSValue valueWithBytes:objCType:]. /// or [NSValue valueWithBytes:objCType:].
/// ///
llvm::Value * llvm::Value *
CodeGenFunction::EmitObjCBoxedExpr(const ObjCBoxedExpr *E) { CodeGenFunction::EmitObjCBoxedExpr(const ObjCBoxedExpr *E) {
// Generate the correct selector for this literal's concrete type. // Generate the correct selector for this literal's concrete type.
// Get the method. // Get the method.
const ObjCMethodDecl *BoxingMethod = E->getBoxingMethod(); const ObjCMethodDecl *BoxingMethod = E->getBoxingMethod();
const Expr *SubExpr = E->getSubExpr(); const Expr *SubExpr = E->getSubExpr();
assert(BoxingMethod && "BoxingMethod is null");
if (E->isExpressibleAsConstantInitializer()) {
ConstantEmitter ConstEmitter(CGM);
return ConstEmitter.tryEmitAbstract(E, E->getType());
}
assert(BoxingMethod->isClassMethod() && "BoxingMethod must be a class method") ; assert(BoxingMethod->isClassMethod() && "BoxingMethod must be a class method") ;
Selector Sel = BoxingMethod->getSelector(); Selector Sel = BoxingMethod->getSelector();
// Generate a reference to the class pointer, which will be the receiver. // Generate a reference to the class pointer, which will be the receiver.
// Assumes that the method was introduced in the class that should be // Assumes that the method was introduced in the class that should be
// messaged (avoids pulling it out of the result type). // messaged (avoids pulling it out of the result type).
CGObjCRuntime &Runtime = CGM.getObjCRuntime(); CGObjCRuntime &Runtime = CGM.getObjCRuntime();
const ObjCInterfaceDecl *ClassDecl = BoxingMethod->getClassInterface(); const ObjCInterfaceDecl *ClassDecl = BoxingMethod->getClassInterface();
llvm::Value *Receiver = Runtime.GetClass(*this, ClassDecl); llvm::Value *Receiver = Runtime.GetClass(*this, ClassDecl);
skipping to change at line 163 skipping to change at line 167
SmallVector<llvm::Value *, 16> NeededObjects; SmallVector<llvm::Value *, 16> NeededObjects;
bool TrackNeededObjects = bool TrackNeededObjects =
(getLangOpts().ObjCAutoRefCount && (getLangOpts().ObjCAutoRefCount &&
CGM.getCodeGenOpts().OptimizationLevel != 0); CGM.getCodeGenOpts().OptimizationLevel != 0);
// Perform the actual initialialization of the array(s). // Perform the actual initialialization of the array(s).
for (uint64_t i = 0; i < NumElements; i++) { for (uint64_t i = 0; i < NumElements; i++) {
if (ALE) { if (ALE) {
// Emit the element and store it to the appropriate array slot. // Emit the element and store it to the appropriate array slot.
const Expr *Rhs = ALE->getElement(i); const Expr *Rhs = ALE->getElement(i);
LValue LV = MakeAddrLValue( LValue LV = MakeAddrLValue(Builder.CreateConstArrayGEP(Objects, i),
Builder.CreateConstArrayGEP(Objects, i, getPointerSize()), ElementType, AlignmentSource::Decl);
ElementType, AlignmentSource::Decl);
llvm::Value *value = EmitScalarExpr(Rhs); llvm::Value *value = EmitScalarExpr(Rhs);
EmitStoreThroughLValue(RValue::get(value), LV, true); EmitStoreThroughLValue(RValue::get(value), LV, true);
if (TrackNeededObjects) { if (TrackNeededObjects) {
NeededObjects.push_back(value); NeededObjects.push_back(value);
} }
} else { } else {
// Emit the key and store it to the appropriate array slot. // Emit the key and store it to the appropriate array slot.
const Expr *Key = DLE->getKeyValueElement(i).Key; const Expr *Key = DLE->getKeyValueElement(i).Key;
LValue KeyLV = MakeAddrLValue( LValue KeyLV = MakeAddrLValue(Builder.CreateConstArrayGEP(Keys, i),
Builder.CreateConstArrayGEP(Keys, i, getPointerSize()), ElementType, AlignmentSource::Decl);
ElementType, AlignmentSource::Decl);
llvm::Value *keyValue = EmitScalarExpr(Key); llvm::Value *keyValue = EmitScalarExpr(Key);
EmitStoreThroughLValue(RValue::get(keyValue), KeyLV, /*isInit=*/true); EmitStoreThroughLValue(RValue::get(keyValue), KeyLV, /*isInit=*/true);
// Emit the value and store it to the appropriate array slot. // Emit the value and store it to the appropriate array slot.
const Expr *Value = DLE->getKeyValueElement(i).Value; const Expr *Value = DLE->getKeyValueElement(i).Value;
LValue ValueLV = MakeAddrLValue( LValue ValueLV = MakeAddrLValue(Builder.CreateConstArrayGEP(Objects, i),
Builder.CreateConstArrayGEP(Objects, i, getPointerSize()), ElementType, AlignmentSource::Decl);
ElementType, AlignmentSource::Decl);
llvm::Value *valueValue = EmitScalarExpr(Value); llvm::Value *valueValue = EmitScalarExpr(Value);
EmitStoreThroughLValue(RValue::get(valueValue), ValueLV, /*isInit=*/true); EmitStoreThroughLValue(RValue::get(valueValue), ValueLV, /*isInit=*/true);
if (TrackNeededObjects) { if (TrackNeededObjects) {
NeededObjects.push_back(keyValue); NeededObjects.push_back(keyValue);
NeededObjects.push_back(valueValue); NeededObjects.push_back(valueValue);
} }
} }
} }
// Generate the argument list. // Generate the argument list.
skipping to change at line 385 skipping to change at line 386
auto &CGM = CGF.CGM; auto &CGM = CGF.CGM;
if (!CGM.getCodeGenOpts().ObjCConvertMessagesToRuntimeCalls) if (!CGM.getCodeGenOpts().ObjCConvertMessagesToRuntimeCalls)
return None; return None;
auto &Runtime = CGM.getLangOpts().ObjCRuntime; auto &Runtime = CGM.getLangOpts().ObjCRuntime;
switch (Sel.getMethodFamily()) { switch (Sel.getMethodFamily()) {
case OMF_alloc: case OMF_alloc:
if (isClassMessage && if (isClassMessage &&
Runtime.shouldUseRuntimeFunctionsForAlloc() && Runtime.shouldUseRuntimeFunctionsForAlloc() &&
ResultType->isObjCObjectPointerType()) { ResultType->isObjCObjectPointerType()) {
// [Foo alloc] -> objc_alloc(Foo) // [Foo alloc] -> objc_alloc(Foo) or
// [self alloc] -> objc_alloc(self)
if (Sel.isUnarySelector() && Sel.getNameForSlot(0) == "alloc") if (Sel.isUnarySelector() && Sel.getNameForSlot(0) == "alloc")
return CGF.EmitObjCAlloc(Receiver, CGF.ConvertType(ResultType)); return CGF.EmitObjCAlloc(Receiver, CGF.ConvertType(ResultType));
// [Foo allocWithZone:nil] -> objc_allocWithZone(Foo) // [Foo allocWithZone:nil] -> objc_allocWithZone(Foo) or
// [self allocWithZone:nil] -> objc_allocWithZone(self)
if (Sel.isKeywordSelector() && Sel.getNumArgs() == 1 && if (Sel.isKeywordSelector() && Sel.getNumArgs() == 1 &&
Args.size() == 1 && Args.front().getType()->isPointerType() && Args.size() == 1 && Args.front().getType()->isPointerType() &&
Sel.getNameForSlot(0) == "allocWithZone") { Sel.getNameForSlot(0) == "allocWithZone") {
const llvm::Value* arg = Args.front().getKnownRValue().getScalarVal(); const llvm::Value* arg = Args.front().getKnownRValue().getScalarVal();
if (isa<llvm::ConstantPointerNull>(arg)) if (isa<llvm::ConstantPointerNull>(arg))
return CGF.EmitObjCAllocWithZone(Receiver, return CGF.EmitObjCAllocWithZone(Receiver,
CGF.ConvertType(ResultType)); CGF.ConvertType(ResultType));
return None; return None;
} }
} }
skipping to change at line 430 skipping to change at line 433
return nullptr; return nullptr;
} }
break; break;
default: default:
break; break;
} }
return None; return None;
} }
/// Instead of '[[MyClass alloc] init]', try to generate
/// 'objc_alloc_init(MyClass)'. This provides a code size improvement on the
/// caller side, as well as the optimized objc_alloc.
static Optional<llvm::Value *>
tryEmitSpecializedAllocInit(CodeGenFunction &CGF, const ObjCMessageExpr *OME) {
auto &Runtime = CGF.getLangOpts().ObjCRuntime;
if (!Runtime.shouldUseRuntimeFunctionForCombinedAllocInit())
return None;
// Match the exact pattern '[[MyClass alloc] init]'.
Selector Sel = OME->getSelector();
if (OME->getReceiverKind() != ObjCMessageExpr::Instance ||
!OME->getType()->isObjCObjectPointerType() || !Sel.isUnarySelector() ||
Sel.getNameForSlot(0) != "init")
return None;
// Okay, this is '[receiver init]', check if 'receiver' is '[cls alloc]' or
// we are in an ObjC class method and 'receiver' is '[self alloc]'.
auto *SubOME =
dyn_cast<ObjCMessageExpr>(OME->getInstanceReceiver()->IgnoreParenCasts());
if (!SubOME)
return None;
Selector SubSel = SubOME->getSelector();
// Check if we are in an ObjC class method and the receiver expression is
// 'self'.
const Expr *SelfInClassMethod = nullptr;
if (const auto *CurMD = dyn_cast_or_null<ObjCMethodDecl>(CGF.CurFuncDecl))
if (CurMD->isClassMethod())
if ((SelfInClassMethod = SubOME->getInstanceReceiver()))
if (!SelfInClassMethod->isObjCSelfExpr())
SelfInClassMethod = nullptr;
if ((SubOME->getReceiverKind() != ObjCMessageExpr::Class &&
!SelfInClassMethod) || !SubOME->getType()->isObjCObjectPointerType() ||
!SubSel.isUnarySelector() || SubSel.getNameForSlot(0) != "alloc")
return None;
llvm::Value *Receiver;
if (SelfInClassMethod) {
Receiver = CGF.EmitScalarExpr(SelfInClassMethod);
} else {
QualType ReceiverType = SubOME->getClassReceiver();
const ObjCObjectType *ObjTy = ReceiverType->getAs<ObjCObjectType>();
const ObjCInterfaceDecl *ID = ObjTy->getInterface();
assert(ID && "null interface should be impossible here");
Receiver = CGF.CGM.getObjCRuntime().GetClass(CGF, ID);
}
return CGF.EmitObjCAllocInit(Receiver, CGF.ConvertType(OME->getType()));
}
RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E, RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E,
ReturnValueSlot Return) { ReturnValueSlot Return) {
// Only the lookup mechanism and first two arguments of the method // Only the lookup mechanism and first two arguments of the method
// implementation vary between runtimes. We can get the receiver and // implementation vary between runtimes. We can get the receiver and
// arguments in generic code. // arguments in generic code.
bool isDelegateInit = E->isDelegateInitCall(); bool isDelegateInit = E->isDelegateInitCall();
const ObjCMethodDecl *method = E->getMethodDecl(); const ObjCMethodDecl *method = E->getMethodDecl();
skipping to change at line 451 skipping to change at line 505
// a __weak variable, peephole the entire operation to objc_loadWeakRetained. // a __weak variable, peephole the entire operation to objc_loadWeakRetained.
if (method && E->getReceiverKind() == ObjCMessageExpr::Instance && if (method && E->getReceiverKind() == ObjCMessageExpr::Instance &&
method->getMethodFamily() == OMF_retain) { method->getMethodFamily() == OMF_retain) {
if (auto lvalueExpr = findWeakLValue(E->getInstanceReceiver())) { if (auto lvalueExpr = findWeakLValue(E->getInstanceReceiver())) {
LValue lvalue = EmitLValue(lvalueExpr); LValue lvalue = EmitLValue(lvalueExpr);
llvm::Value *result = EmitARCLoadWeakRetained(lvalue.getAddress()); llvm::Value *result = EmitARCLoadWeakRetained(lvalue.getAddress());
return AdjustObjCObjectType(*this, E->getType(), RValue::get(result)); return AdjustObjCObjectType(*this, E->getType(), RValue::get(result));
} }
} }
if (Optional<llvm::Value *> Val = tryEmitSpecializedAllocInit(*this, E))
return AdjustObjCObjectType(*this, E->getType(), RValue::get(*Val));
// We don't retain the receiver in delegate init calls, and this is // We don't retain the receiver in delegate init calls, and this is
// safe because the receiver value is always loaded from 'self', // safe because the receiver value is always loaded from 'self',
// which we zero out. We don't want to Block_copy block receivers, // which we zero out. We don't want to Block_copy block receivers,
// though. // though.
bool retainSelf = bool retainSelf =
(!isDelegateInit && (!isDelegateInit &&
CGM.getLangOpts().ObjCAutoRefCount && CGM.getLangOpts().ObjCAutoRefCount &&
method && method &&
method->hasAttr<NSConsumesSelfAttr>()); method->hasAttr<NSConsumesSelfAttr>());
CGObjCRuntime &Runtime = CGM.getObjCRuntime(); CGObjCRuntime &Runtime = CGM.getObjCRuntime();
bool isSuperMessage = false; bool isSuperMessage = false;
bool isClassMessage = false; bool isClassMessage = false;
ObjCInterfaceDecl *OID = nullptr; ObjCInterfaceDecl *OID = nullptr;
// Find the receiver // Find the receiver
QualType ReceiverType; QualType ReceiverType;
llvm::Value *Receiver = nullptr; llvm::Value *Receiver = nullptr;
switch (E->getReceiverKind()) { switch (E->getReceiverKind()) {
case ObjCMessageExpr::Instance: case ObjCMessageExpr::Instance:
ReceiverType = E->getInstanceReceiver()->getType(); ReceiverType = E->getInstanceReceiver()->getType();
if (auto *OMD = dyn_cast_or_null<ObjCMethodDecl>(CurFuncDecl))
if (OMD->isClassMethod())
if (E->getInstanceReceiver()->isObjCSelfExpr())
isClassMessage = true;
if (retainSelf) { if (retainSelf) {
TryEmitResult ter = tryEmitARCRetainScalarExpr(*this, TryEmitResult ter = tryEmitARCRetainScalarExpr(*this,
E->getInstanceReceiver()); E->getInstanceReceiver());
Receiver = ter.getPointer(); Receiver = ter.getPointer();
if (ter.getInt()) retainSelf = false; if (ter.getInt()) retainSelf = false;
} else } else
Receiver = EmitScalarExpr(E->getInstanceReceiver()); Receiver = EmitScalarExpr(E->getInstanceReceiver());
break; break;
case ObjCMessageExpr::Class: { case ObjCMessageExpr::Class: {
skipping to change at line 688 skipping to change at line 749
args.add(RValue::get(dest.getPointer()), Context.VoidPtrTy); args.add(RValue::get(dest.getPointer()), Context.VoidPtrTy);
src = CGF.Builder.CreateBitCast(src, CGF.VoidPtrTy); src = CGF.Builder.CreateBitCast(src, CGF.VoidPtrTy);
args.add(RValue::get(src.getPointer()), Context.VoidPtrTy); args.add(RValue::get(src.getPointer()), Context.VoidPtrTy);
CharUnits size = CGF.getContext().getTypeSizeInChars(ivar->getType()); CharUnits size = CGF.getContext().getTypeSizeInChars(ivar->getType());
args.add(RValue::get(CGF.CGM.getSize(size)), Context.getSizeType()); args.add(RValue::get(CGF.CGM.getSize(size)), Context.getSizeType());
args.add(RValue::get(CGF.Builder.getInt1(isAtomic)), Context.BoolTy); args.add(RValue::get(CGF.Builder.getInt1(isAtomic)), Context.BoolTy);
args.add(RValue::get(CGF.Builder.getInt1(hasStrong)), Context.BoolTy); args.add(RValue::get(CGF.Builder.getInt1(hasStrong)), Context.BoolTy);
llvm::Constant *fn = CGF.CGM.getObjCRuntime().GetGetStructFunction(); llvm::FunctionCallee fn = CGF.CGM.getObjCRuntime().GetGetStructFunction();
CGCallee callee = CGCallee::forDirect(fn); CGCallee callee = CGCallee::forDirect(fn);
CGF.EmitCall(CGF.getTypes().arrangeBuiltinFunctionCall(Context.VoidTy, args), CGF.EmitCall(CGF.getTypes().arrangeBuiltinFunctionCall(Context.VoidTy, args),
callee, ReturnValueSlot(), args); callee, ReturnValueSlot(), args);
} }
/// Determine whether the given architecture supports unaligned atomic /// Determine whether the given architecture supports unaligned atomic
/// accesses. They don't have to be fast, just faster than a function /// accesses. They don't have to be fast, just faster than a function
/// call and a mutex. /// call and a mutex.
static bool hasUnalignedAtomics(llvm::Triple::ArchType arch) { static bool hasUnalignedAtomics(llvm::Triple::ArchType arch) {
// FIXME: Allow unaligned atomic load/store on x86. (It is not // FIXME: Allow unaligned atomic load/store on x86. (It is not
skipping to change at line 952 skipping to change at line 1013
// The 2nd argument is the address of the ivar. // The 2nd argument is the address of the ivar.
llvm::Value *ivarAddr = llvm::Value *ivarAddr =
CGF.EmitLValueForIvar(CGF.TypeOfSelfObject(), CGF.EmitLValueForIvar(CGF.TypeOfSelfObject(),
CGF.LoadObjCSelf(), ivar, 0).getPointer(); CGF.LoadObjCSelf(), ivar, 0).getPointer();
ivarAddr = CGF.Builder.CreateBitCast(ivarAddr, CGF.Int8PtrTy); ivarAddr = CGF.Builder.CreateBitCast(ivarAddr, CGF.Int8PtrTy);
args.add(RValue::get(ivarAddr), CGF.getContext().VoidPtrTy); args.add(RValue::get(ivarAddr), CGF.getContext().VoidPtrTy);
// Third argument is the helper function. // Third argument is the helper function.
args.add(RValue::get(AtomicHelperFn), CGF.getContext().VoidPtrTy); args.add(RValue::get(AtomicHelperFn), CGF.getContext().VoidPtrTy);
llvm::Constant *copyCppAtomicObjectFn = llvm::FunctionCallee copyCppAtomicObjectFn =
CGF.CGM.getObjCRuntime().GetCppAtomicObjectGetFunction(); CGF.CGM.getObjCRuntime().GetCppAtomicObjectGetFunction();
CGCallee callee = CGCallee::forDirect(copyCppAtomicObjectFn); CGCallee callee = CGCallee::forDirect(copyCppAtomicObjectFn);
CGF.EmitCall( CGF.EmitCall(
CGF.getTypes().arrangeBuiltinFunctionCall(CGF.getContext().VoidTy, args), CGF.getTypes().arrangeBuiltinFunctionCall(CGF.getContext().VoidTy, args),
callee, ReturnValueSlot(), args); callee, ReturnValueSlot(), args);
} }
void void
CodeGenFunction::generateObjCGetterBody(const ObjCImplementationDecl *classImpl, CodeGenFunction::generateObjCGetterBody(const ObjCImplementationDecl *classImpl,
const ObjCPropertyImplDecl *propImpl, const ObjCPropertyImplDecl *propImpl,
const ObjCMethodDecl *GetterMethodDecl, const ObjCMethodDecl *GetterMethodDecl,
skipping to change at line 1029 skipping to change at line 1090
} }
Builder.CreateStore(ivarVal, Builder.CreateStore(ivarVal,
Builder.CreateBitCast(ReturnValue, bitcastType)); Builder.CreateBitCast(ReturnValue, bitcastType));
// Make sure we don't do an autorelease. // Make sure we don't do an autorelease.
AutoreleaseResult = false; AutoreleaseResult = false;
return; return;
} }
case PropertyImplStrategy::GetSetProperty: { case PropertyImplStrategy::GetSetProperty: {
llvm::Constant *getPropertyFn = llvm::FunctionCallee getPropertyFn =
CGM.getObjCRuntime().GetPropertyGetFunction(); CGM.getObjCRuntime().GetPropertyGetFunction();
if (!getPropertyFn) { if (!getPropertyFn) {
CGM.ErrorUnsupported(propImpl, "Obj-C getter requiring atomic copy"); CGM.ErrorUnsupported(propImpl, "Obj-C getter requiring atomic copy");
return; return;
} }
CGCallee callee = CGCallee::forDirect(getPropertyFn); CGCallee callee = CGCallee::forDirect(getPropertyFn);
// Return (ivar-type) objc_getProperty((id) self, _cmd, offset, true). // Return (ivar-type) objc_getProperty((id) self, _cmd, offset, true).
// FIXME: Can't this be simpler? This might even be worse than the // FIXME: Can't this be simpler? This might even be worse than the
// corresponding gcc code. // corresponding gcc code.
llvm::Value *cmd = llvm::Value *cmd =
skipping to change at line 1055 skipping to change at line 1116
CallArgList args; CallArgList args;
args.add(RValue::get(self), getContext().getObjCIdType()); args.add(RValue::get(self), getContext().getObjCIdType());
args.add(RValue::get(cmd), getContext().getObjCSelType()); args.add(RValue::get(cmd), getContext().getObjCSelType());
args.add(RValue::get(ivarOffset), getContext().getPointerDiffType()); args.add(RValue::get(ivarOffset), getContext().getPointerDiffType());
args.add(RValue::get(Builder.getInt1(strategy.isAtomic())), args.add(RValue::get(Builder.getInt1(strategy.isAtomic())),
getContext().BoolTy); getContext().BoolTy);
// FIXME: We shouldn't need to get the function info here, the // FIXME: We shouldn't need to get the function info here, the
// runtime already should have computed it to build the function. // runtime already should have computed it to build the function.
llvm::Instruction *CallInstruction; llvm::CallBase *CallInstruction;
RValue RV = EmitCall( RValue RV = EmitCall(getTypes().arrangeBuiltinFunctionCall(
getTypes().arrangeBuiltinFunctionCall(propType, args), getContext().getObjCIdType(), args),
callee, ReturnValueSlot(), args, &CallInstruction); callee, ReturnValueSlot(), args, &CallInstruction);
if (llvm::CallInst *call = dyn_cast<llvm::CallInst>(CallInstruction)) if (llvm::CallInst *call = dyn_cast<llvm::CallInst>(CallInstruction))
call->setTailCall(); call->setTailCall();
// We need to fix the type here. Ivars with copy & retain are // We need to fix the type here. Ivars with copy & retain are
// always objects so we don't need to worry about complex or // always objects so we don't need to worry about complex or
// aggregates. // aggregates.
RV = RValue::get(Builder.CreateBitCast( RV = RValue::get(Builder.CreateBitCast(
RV.getScalarVal(), RV.getScalarVal(),
getTypes().ConvertType(getterMethod->getReturnType()))); getTypes().ConvertType(getterMethod->getReturnType())));
skipping to change at line 1099 skipping to change at line 1160
ComplexPairTy pair = EmitLoadOfComplex(LV, SourceLocation()); ComplexPairTy pair = EmitLoadOfComplex(LV, SourceLocation());
EmitStoreOfComplex(pair, MakeAddrLValue(ReturnValue, ivarType), EmitStoreOfComplex(pair, MakeAddrLValue(ReturnValue, ivarType),
/*init*/ true); /*init*/ true);
return; return;
} }
case TEK_Aggregate: { case TEK_Aggregate: {
// The return value slot is guaranteed to not be aliased, but // The return value slot is guaranteed to not be aliased, but
// that's not necessarily the same as "on the stack", so // that's not necessarily the same as "on the stack", so
// we still potentially need objc_memmove_collectable. // we still potentially need objc_memmove_collectable.
EmitAggregateCopy(/* Dest= */ MakeAddrLValue(ReturnValue, ivarType), EmitAggregateCopy(/* Dest= */ MakeAddrLValue(ReturnValue, ivarType),
/* Src= */ LV, ivarType, overlapForReturnValue()); /* Src= */ LV, ivarType, getOverlapForReturnValue());
return; return;
} }
case TEK_Scalar: { case TEK_Scalar: {
llvm::Value *value; llvm::Value *value;
if (propType->isReferenceType()) { if (propType->isReferenceType()) {
value = LV.getAddress().getPointer(); value = LV.getAddress().getPointer();
} else { } else {
// We want to load and autoreleaseReturnValue ARC __weak ivars. // We want to load and autoreleaseReturnValue ARC __weak ivars.
if (LV.getQuals().getObjCLifetime() == Qualifiers::OCL_Weak) { if (LV.getQuals().getObjCLifetime() == Qualifiers::OCL_Weak) {
if (getLangOpts().ObjCAutoRefCount) { if (getLangOpts().ObjCAutoRefCount) {
skipping to change at line 1173 skipping to change at line 1234
CGF.CGM.getSize(CGF.getContext().getTypeSizeInChars(ivar->getType())); CGF.CGM.getSize(CGF.getContext().getTypeSizeInChars(ivar->getType()));
args.add(RValue::get(size), CGF.getContext().getSizeType()); args.add(RValue::get(size), CGF.getContext().getSizeType());
// The fourth argument is the 'isAtomic' flag. // The fourth argument is the 'isAtomic' flag.
args.add(RValue::get(CGF.Builder.getTrue()), CGF.getContext().BoolTy); args.add(RValue::get(CGF.Builder.getTrue()), CGF.getContext().BoolTy);
// The fifth argument is the 'hasStrong' flag. // The fifth argument is the 'hasStrong' flag.
// FIXME: should this really always be false? // FIXME: should this really always be false?
args.add(RValue::get(CGF.Builder.getFalse()), CGF.getContext().BoolTy); args.add(RValue::get(CGF.Builder.getFalse()), CGF.getContext().BoolTy);
llvm::Constant *fn = CGF.CGM.getObjCRuntime().GetSetStructFunction(); llvm::FunctionCallee fn = CGF.CGM.getObjCRuntime().GetSetStructFunction();
CGCallee callee = CGCallee::forDirect(fn); CGCallee callee = CGCallee::forDirect(fn);
CGF.EmitCall( CGF.EmitCall(
CGF.getTypes().arrangeBuiltinFunctionCall(CGF.getContext().VoidTy, args), CGF.getTypes().arrangeBuiltinFunctionCall(CGF.getContext().VoidTy, args),
callee, ReturnValueSlot(), args); callee, ReturnValueSlot(), args);
} }
/// emitCPPObjectAtomicSetterCall - Call the runtime function to store /// emitCPPObjectAtomicSetterCall - Call the runtime function to store
/// the value from the first formal parameter into the given ivar, using /// the value from the first formal parameter into the given ivar, using
/// the Cpp API for atomic Cpp objects with non-trivial copy assignment. /// the Cpp API for atomic Cpp objects with non-trivial copy assignment.
static void emitCPPObjectAtomicSetterCall(CodeGenFunction &CGF, static void emitCPPObjectAtomicSetterCall(CodeGenFunction &CGF,
skipping to change at line 1210 skipping to change at line 1271
DeclRefExpr argRef(CGF.getContext(), argVar, false, DeclRefExpr argRef(CGF.getContext(), argVar, false,
argVar->getType().getNonReferenceType(), VK_LValue, argVar->getType().getNonReferenceType(), VK_LValue,
SourceLocation()); SourceLocation());
llvm::Value *argAddr = CGF.EmitLValue(&argRef).getPointer(); llvm::Value *argAddr = CGF.EmitLValue(&argRef).getPointer();
argAddr = CGF.Builder.CreateBitCast(argAddr, CGF.Int8PtrTy); argAddr = CGF.Builder.CreateBitCast(argAddr, CGF.Int8PtrTy);
args.add(RValue::get(argAddr), CGF.getContext().VoidPtrTy); args.add(RValue::get(argAddr), CGF.getContext().VoidPtrTy);
// Third argument is the helper function. // Third argument is the helper function.
args.add(RValue::get(AtomicHelperFn), CGF.getContext().VoidPtrTy); args.add(RValue::get(AtomicHelperFn), CGF.getContext().VoidPtrTy);
llvm::Constant *fn = llvm::FunctionCallee fn =
CGF.CGM.getObjCRuntime().GetCppAtomicObjectSetFunction(); CGF.CGM.getObjCRuntime().GetCppAtomicObjectSetFunction();
CGCallee callee = CGCallee::forDirect(fn); CGCallee callee = CGCallee::forDirect(fn);
CGF.EmitCall( CGF.EmitCall(
CGF.getTypes().arrangeBuiltinFunctionCall(CGF.getContext().VoidTy, args), CGF.getTypes().arrangeBuiltinFunctionCall(CGF.getContext().VoidTy, args),
callee, ReturnValueSlot(), args); callee, ReturnValueSlot(), args);
} }
static bool hasTrivialSetExpr(const ObjCPropertyImplDecl *PID) { static bool hasTrivialSetExpr(const ObjCPropertyImplDecl *PID) {
Expr *setter = PID->getSetterCXXAssignment(); Expr *setter = PID->getSetterCXXAssignment();
if (!setter) return true; if (!setter) return true;
skipping to change at line 1304 skipping to change at line 1365
// Perform an atomic store. There are no memory ordering requirements. // Perform an atomic store. There are no memory ordering requirements.
llvm::StoreInst *store = Builder.CreateStore(load, ivarAddr); llvm::StoreInst *store = Builder.CreateStore(load, ivarAddr);
store->setAtomic(llvm::AtomicOrdering::Unordered); store->setAtomic(llvm::AtomicOrdering::Unordered);
return; return;
} }
case PropertyImplStrategy::GetSetProperty: case PropertyImplStrategy::GetSetProperty:
case PropertyImplStrategy::SetPropertyAndExpressionGet: { case PropertyImplStrategy::SetPropertyAndExpressionGet: {
llvm::Constant *setOptimizedPropertyFn = nullptr; llvm::FunctionCallee setOptimizedPropertyFn = nullptr;
llvm::Constant *setPropertyFn = nullptr; llvm::FunctionCallee setPropertyFn = nullptr;
if (UseOptimizedSetter(CGM)) { if (UseOptimizedSetter(CGM)) {
// 10.8 and iOS 6.0 code and GC is off // 10.8 and iOS 6.0 code and GC is off
setOptimizedPropertyFn = setOptimizedPropertyFn =
CGM.getObjCRuntime() CGM.getObjCRuntime().GetOptimizedPropertySetFunction(
.GetOptimizedPropertySetFunction(strategy.isAtomic(), strategy.isAtomic(), strategy.isCopy());
strategy.isCopy());
if (!setOptimizedPropertyFn) { if (!setOptimizedPropertyFn) {
CGM.ErrorUnsupported(propImpl, "Obj-C optimized setter - NYI"); CGM.ErrorUnsupported(propImpl, "Obj-C optimized setter - NYI");
return; return;
} }
} }
else { else {
setPropertyFn = CGM.getObjCRuntime().GetPropertySetFunction(); setPropertyFn = CGM.getObjCRuntime().GetPropertySetFunction();
if (!setPropertyFn) { if (!setPropertyFn) {
CGM.ErrorUnsupported(propImpl, "Obj-C setter requiring atomic copy"); CGM.ErrorUnsupported(propImpl, "Obj-C setter requiring atomic copy");
return; return;
skipping to change at line 1561 skipping to change at line 1621
QualType CodeGenFunction::TypeOfSelfObject() { QualType CodeGenFunction::TypeOfSelfObject() {
const ObjCMethodDecl *OMD = cast<ObjCMethodDecl>(CurFuncDecl); const ObjCMethodDecl *OMD = cast<ObjCMethodDecl>(CurFuncDecl);
ImplicitParamDecl *selfDecl = OMD->getSelfDecl(); ImplicitParamDecl *selfDecl = OMD->getSelfDecl();
const ObjCObjectPointerType *PTy = cast<ObjCObjectPointerType>( const ObjCObjectPointerType *PTy = cast<ObjCObjectPointerType>(
getContext().getCanonicalType(selfDecl->getType())); getContext().getCanonicalType(selfDecl->getType()));
return PTy->getPointeeType(); return PTy->getPointeeType();
} }
void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){
llvm::Constant *EnumerationMutationFnPtr = llvm::FunctionCallee EnumerationMutationFnPtr =
CGM.getObjCRuntime().EnumerationMutationFunction(); CGM.getObjCRuntime().EnumerationMutationFunction();
if (!EnumerationMutationFnPtr) { if (!EnumerationMutationFnPtr) {
CGM.ErrorUnsupported(&S, "Obj-C fast enumeration for this runtime"); CGM.ErrorUnsupported(&S, "Obj-C fast enumeration for this runtime");
return; return;
} }
CGCallee EnumerationMutationFn = CGCallee EnumerationMutationFn =
CGCallee::forDirect(EnumerationMutationFnPtr); CGCallee::forDirect(EnumerationMutationFnPtr);
CGDebugInfo *DI = getDebugInfo(); CGDebugInfo *DI = getDebugInfo();
if (DI) if (DI)
DI->EmitLexicalBlockStart(Builder, S.getSourceRange().getBegin()); DI->EmitLexicalBlockStart(Builder, S.getSourceRange().getBegin());
skipping to change at line 1670 skipping to change at line 1730
Builder.CreateICmpEQ(initialBufferLimit, zero, "iszero"), EmptyBB, Builder.CreateICmpEQ(initialBufferLimit, zero, "iszero"), EmptyBB,
LoopInitBB, LoopInitBB,
createProfileWeights(EntryCount, getProfileCount(S.getBody()))); createProfileWeights(EntryCount, getProfileCount(S.getBody())));
// Otherwise, initialize the loop. // Otherwise, initialize the loop.
EmitBlock(LoopInitBB); EmitBlock(LoopInitBB);
// Save the initial mutations value. This is the value at an // Save the initial mutations value. This is the value at an
// address that was written into the state object by // address that was written into the state object by
// countByEnumeratingWithState:objects:count:. // countByEnumeratingWithState:objects:count:.
Address StateMutationsPtrPtr = Builder.CreateStructGEP( Address StateMutationsPtrPtr =
StatePtr, 2, 2 * getPointerSize(), "mutationsptr.ptr"); Builder.CreateStructGEP(StatePtr, 2, "mutationsptr.ptr");
llvm::Value *StateMutationsPtr llvm::Value *StateMutationsPtr
= Builder.CreateLoad(StateMutationsPtrPtr, "mutationsptr"); = Builder.CreateLoad(StateMutationsPtrPtr, "mutationsptr");
llvm::Value *initialMutations = llvm::Value *initialMutations =
Builder.CreateAlignedLoad(StateMutationsPtr, getPointerAlign(), Builder.CreateAlignedLoad(StateMutationsPtr, getPointerAlign(),
"forcoll.initial-mutations"); "forcoll.initial-mutations");
// Start looping. This is the point we return to whenever we have a // Start looping. This is the point we return to whenever we have a
// fresh, non-empty batch of objects. // fresh, non-empty batch of objects.
llvm::BasicBlock *LoopBodyBB = createBasicBlock("forcoll.loopbody"); llvm::BasicBlock *LoopBodyBB = createBasicBlock("forcoll.loopbody");
skipping to change at line 1752 skipping to change at line 1812
} else { } else {
elementLValue = LValue(); // suppress warning elementLValue = LValue(); // suppress warning
elementType = cast<Expr>(S.getElement())->getType(); elementType = cast<Expr>(S.getElement())->getType();
elementIsVariable = false; elementIsVariable = false;
} }
llvm::Type *convertedElementType = ConvertType(elementType); llvm::Type *convertedElementType = ConvertType(elementType);
// Fetch the buffer out of the enumeration state. // Fetch the buffer out of the enumeration state.
// TODO: this pointer should actually be invariant between // TODO: this pointer should actually be invariant between
// refreshes, which would help us do certain loop optimizations. // refreshes, which would help us do certain loop optimizations.
Address StateItemsPtr = Builder.CreateStructGEP( Address StateItemsPtr =
StatePtr, 1, getPointerSize(), "stateitems.ptr"); Builder.CreateStructGEP(StatePtr, 1, "stateitems.ptr");
llvm::Value *EnumStateItems = llvm::Value *EnumStateItems =
Builder.CreateLoad(StateItemsPtr, "stateitems"); Builder.CreateLoad(StateItemsPtr, "stateitems");
// Fetch the value at the current index from the buffer. // Fetch the value at the current index from the buffer.
llvm::Value *CurrentItemPtr = llvm::Value *CurrentItemPtr =
Builder.CreateGEP(EnumStateItems, index, "currentitem.ptr"); Builder.CreateGEP(EnumStateItems, index, "currentitem.ptr");
llvm::Value *CurrentItem = llvm::Value *CurrentItem =
Builder.CreateAlignedLoad(CurrentItemPtr, getPointerAlign()); Builder.CreateAlignedLoad(CurrentItemPtr, getPointerAlign());
// Cast that value to the right type. // Cast that value to the right type.
skipping to change at line 1892 skipping to change at line 1952
} }
llvm::Value *CodeGenFunction::EmitObjCExtendObjectLifetime(QualType type, llvm::Value *CodeGenFunction::EmitObjCExtendObjectLifetime(QualType type,
llvm::Value *value) { llvm::Value *value) {
return EmitARCRetainAutorelease(type, value); return EmitARCRetainAutorelease(type, value);
} }
/// Given a number of pointers, inform the optimizer that they're /// Given a number of pointers, inform the optimizer that they're
/// being intrinsically used up until this point in the program. /// being intrinsically used up until this point in the program.
void CodeGenFunction::EmitARCIntrinsicUse(ArrayRef<llvm::Value*> values) { void CodeGenFunction::EmitARCIntrinsicUse(ArrayRef<llvm::Value*> values) {
llvm::Constant *&fn = CGM.getObjCEntrypoints().clang_arc_use; llvm::Function *&fn = CGM.getObjCEntrypoints().clang_arc_use;
if (!fn) if (!fn)
fn = CGM.getIntrinsic(llvm::Intrinsic::objc_clang_arc_use); fn = CGM.getIntrinsic(llvm::Intrinsic::objc_clang_arc_use);
// This isn't really a "runtime" function, but as an intrinsic it // This isn't really a "runtime" function, but as an intrinsic it
// doesn't really matter as long as we align things up. // doesn't really matter as long as we align things up.
EmitNounwindRuntimeCall(fn, values); EmitNounwindRuntimeCall(fn, values);
} }
static void setARCRuntimeFunctionLinkage(CodeGenModule &CGM, static void setARCRuntimeFunctionLinkage(CodeGenModule &CGM, llvm::Value *RTF) {
llvm::Constant *RTF) {
if (auto *F = dyn_cast<llvm::Function>(RTF)) { if (auto *F = dyn_cast<llvm::Function>(RTF)) {
// If the target runtime doesn't naturally support ARC, emit weak // If the target runtime doesn't naturally support ARC, emit weak
// references to the runtime support library. We don't really // references to the runtime support library. We don't really
// permit this to fail, but we need a particular relocation style. // permit this to fail, but we need a particular relocation style.
if (!CGM.getLangOpts().ObjCRuntime.hasNativeARC() && if (!CGM.getLangOpts().ObjCRuntime.hasNativeARC() &&
!CGM.getTriple().isOSBinFormatCOFF()) { !CGM.getTriple().isOSBinFormatCOFF()) {
F->setLinkage(llvm::Function::ExternalWeakLinkage); F->setLinkage(llvm::Function::ExternalWeakLinkage);
} }
} }
} }
static void setARCRuntimeFunctionLinkage(CodeGenModule &CGM,
llvm::FunctionCallee RTF) {
setARCRuntimeFunctionLinkage(CGM, RTF.getCallee());
}
/// Perform an operation having the signature /// Perform an operation having the signature
/// i8* (i8*) /// i8* (i8*)
/// where a null input causes a no-op and returns null. /// where a null input causes a no-op and returns null.
static llvm::Value *emitARCValueOperation(CodeGenFunction &CGF, static llvm::Value *emitARCValueOperation(
llvm::Value *value, CodeGenFunction &CGF, llvm::Value *value, llvm::Type *returnType,
llvm::Type *returnType, llvm::Function *&fn, llvm::Intrinsic::ID IntID,
llvm::Constant *&fn, llvm::CallInst::TailCallKind tailKind = llvm::CallInst::TCK_None) {
llvm::Intrinsic::ID IntID,
bool isTailCall = false) {
if (isa<llvm::ConstantPointerNull>(value)) if (isa<llvm::ConstantPointerNull>(value))
return value; return value;
if (!fn) { if (!fn) {
fn = CGF.CGM.getIntrinsic(IntID); fn = CGF.CGM.getIntrinsic(IntID);
setARCRuntimeFunctionLinkage(CGF.CGM, fn); setARCRuntimeFunctionLinkage(CGF.CGM, fn);
} }
// Cast the argument to 'id'. // Cast the argument to 'id'.
llvm::Type *origType = returnType ? returnType : value->getType(); llvm::Type *origType = returnType ? returnType : value->getType();
value = CGF.Builder.CreateBitCast(value, CGF.Int8PtrTy); value = CGF.Builder.CreateBitCast(value, CGF.Int8PtrTy);
// Call the function. // Call the function.
llvm::CallInst *call = CGF.EmitNounwindRuntimeCall(fn, value); llvm::CallInst *call = CGF.EmitNounwindRuntimeCall(fn, value);
if (isTailCall) call->setTailCallKind(tailKind);
call->setTailCall();
// Cast the result back to the original type. // Cast the result back to the original type.
return CGF.Builder.CreateBitCast(call, origType); return CGF.Builder.CreateBitCast(call, origType);
} }
/// Perform an operation having the following signature: /// Perform an operation having the following signature:
/// i8* (i8**) /// i8* (i8**)
static llvm::Value *emitARCLoadOperation(CodeGenFunction &CGF, static llvm::Value *emitARCLoadOperation(CodeGenFunction &CGF, Address addr,
Address addr, llvm::Function *&fn,
llvm::Constant *&fn,
llvm::Intrinsic::ID IntID) { llvm::Intrinsic::ID IntID) {
if (!fn) { if (!fn) {
fn = CGF.CGM.getIntrinsic(IntID); fn = CGF.CGM.getIntrinsic(IntID);
setARCRuntimeFunctionLinkage(CGF.CGM, fn); setARCRuntimeFunctionLinkage(CGF.CGM, fn);
} }
// Cast the argument to 'id*'. // Cast the argument to 'id*'.
llvm::Type *origType = addr.getElementType(); llvm::Type *origType = addr.getElementType();
addr = CGF.Builder.CreateBitCast(addr, CGF.Int8PtrPtrTy); addr = CGF.Builder.CreateBitCast(addr, CGF.Int8PtrPtrTy);
skipping to change at line 1971 skipping to change at line 2031
// Cast the result back to a dereference of the original type. // Cast the result back to a dereference of the original type.
if (origType != CGF.Int8PtrTy) if (origType != CGF.Int8PtrTy)
result = CGF.Builder.CreateBitCast(result, origType); result = CGF.Builder.CreateBitCast(result, origType);
return result; return result;
} }
/// Perform an operation having the following signature: /// Perform an operation having the following signature:
/// i8* (i8**, i8*) /// i8* (i8**, i8*)
static llvm::Value *emitARCStoreOperation(CodeGenFunction &CGF, static llvm::Value *emitARCStoreOperation(CodeGenFunction &CGF, Address addr,
Address addr,
llvm::Value *value, llvm::Value *value,
llvm::Constant *&fn, llvm::Function *&fn,
llvm::Intrinsic::ID IntID, llvm::Intrinsic::ID IntID,
bool ignored) { bool ignored) {
assert(addr.getElementType() == value->getType()); assert(addr.getElementType() == value->getType());
if (!fn) { if (!fn) {
fn = CGF.CGM.getIntrinsic(IntID); fn = CGF.CGM.getIntrinsic(IntID);
setARCRuntimeFunctionLinkage(CGF.CGM, fn); setARCRuntimeFunctionLinkage(CGF.CGM, fn);
} }
llvm::Type *origType = value->getType(); llvm::Type *origType = value->getType();
skipping to change at line 1999 skipping to change at line 2058
}; };
llvm::CallInst *result = CGF.EmitNounwindRuntimeCall(fn, args); llvm::CallInst *result = CGF.EmitNounwindRuntimeCall(fn, args);
if (ignored) return nullptr; if (ignored) return nullptr;
return CGF.Builder.CreateBitCast(result, origType); return CGF.Builder.CreateBitCast(result, origType);
} }
/// Perform an operation having the following signature: /// Perform an operation having the following signature:
/// void (i8**, i8**) /// void (i8**, i8**)
static void emitARCCopyOperation(CodeGenFunction &CGF, static void emitARCCopyOperation(CodeGenFunction &CGF, Address dst, Address src,
Address dst, llvm::Function *&fn,
Address src,
llvm::Constant *&fn,
llvm::Intrinsic::ID IntID) { llvm::Intrinsic::ID IntID) {
assert(dst.getType() == src.getType()); assert(dst.getType() == src.getType());
if (!fn) { if (!fn) {
fn = CGF.CGM.getIntrinsic(IntID); fn = CGF.CGM.getIntrinsic(IntID);
setARCRuntimeFunctionLinkage(CGF.CGM, fn); setARCRuntimeFunctionLinkage(CGF.CGM, fn);
} }
llvm::Value *args[] = { llvm::Value *args[] = {
CGF.Builder.CreateBitCast(dst.getPointer(), CGF.Int8PtrPtrTy), CGF.Builder.CreateBitCast(dst.getPointer(), CGF.Int8PtrPtrTy),
skipping to change at line 2024 skipping to change at line 2081
}; };
CGF.EmitNounwindRuntimeCall(fn, args); CGF.EmitNounwindRuntimeCall(fn, args);
} }
/// Perform an operation having the signature /// Perform an operation having the signature
/// i8* (i8*) /// i8* (i8*)
/// where a null input causes a no-op and returns null. /// where a null input causes a no-op and returns null.
static llvm::Value *emitObjCValueOperation(CodeGenFunction &CGF, static llvm::Value *emitObjCValueOperation(CodeGenFunction &CGF,
llvm::Value *value, llvm::Value *value,
llvm::Type *returnType, llvm::Type *returnType,
llvm::Constant *&fn, llvm::FunctionCallee &fn,
StringRef fnName) { StringRef fnName) {
if (isa<llvm::ConstantPointerNull>(value)) if (isa<llvm::ConstantPointerNull>(value))
return value; return value;
if (!fn) { if (!fn) {
llvm::FunctionType *fnType = llvm::FunctionType *fnType =
llvm::FunctionType::get(CGF.Int8PtrTy, CGF.Int8PtrTy, false); llvm::FunctionType::get(CGF.Int8PtrTy, CGF.Int8PtrTy, false);
fn = CGF.CGM.CreateRuntimeFunction(fnType, fnName); fn = CGF.CGM.CreateRuntimeFunction(fnType, fnName);
// We have Native ARC, so set nonlazybind attribute for performance // We have Native ARC, so set nonlazybind attribute for performance
if (llvm::Function *f = dyn_cast<llvm::Function>(fn)) if (llvm::Function *f = dyn_cast<llvm::Function>(fn.getCallee()))
if (fnName == "objc_retain") if (fnName == "objc_retain")
f->addFnAttr(llvm::Attribute::NonLazyBind); f->addFnAttr(llvm::Attribute::NonLazyBind);
} }
// Cast the argument to 'id'. // Cast the argument to 'id'.
llvm::Type *origType = returnType ? returnType : value->getType(); llvm::Type *origType = returnType ? returnType : value->getType();
value = CGF.Builder.CreateBitCast(value, CGF.Int8PtrTy); value = CGF.Builder.CreateBitCast(value, CGF.Int8PtrTy);
// Call the function. // Call the function.
llvm::CallInst *call = CGF.EmitNounwindRuntimeCall(fn, value); llvm::CallBase *Inst = CGF.EmitCallOrInvoke(fn, value);
// Cast the result back to the original type. // Cast the result back to the original type.
return CGF.Builder.CreateBitCast(call, origType); return CGF.Builder.CreateBitCast(Inst, origType);
} }
/// Produce the code to do a retain. Based on the type, calls one of: /// Produce the code to do a retain. Based on the type, calls one of:
/// call i8* \@objc_retain(i8* %value) /// call i8* \@objc_retain(i8* %value)
/// call i8* \@objc_retainBlock(i8* %value) /// call i8* \@objc_retainBlock(i8* %value)
llvm::Value *CodeGenFunction::EmitARCRetain(QualType type, llvm::Value *value) { llvm::Value *CodeGenFunction::EmitARCRetain(QualType type, llvm::Value *value) {
if (type->isBlockPointerType()) if (type->isBlockPointerType())
return EmitARCRetainBlock(value, /*mandatory*/ false); return EmitARCRetainBlock(value, /*mandatory*/ false);
else else
return EmitARCRetainNonBlock(value); return EmitARCRetainNonBlock(value);
skipping to change at line 2123 skipping to change at line 2180
} else if (CGF.CGM.getCodeGenOpts().OptimizationLevel == 0) { } else if (CGF.CGM.getCodeGenOpts().OptimizationLevel == 0) {
llvm::FunctionType *type = llvm::FunctionType *type =
llvm::FunctionType::get(CGF.VoidTy, /*variadic*/false); llvm::FunctionType::get(CGF.VoidTy, /*variadic*/false);
marker = llvm::InlineAsm::get(type, assembly, "", /*sideeffects*/ true); marker = llvm::InlineAsm::get(type, assembly, "", /*sideeffects*/ true);
// If we're at -O1 and above, we don't want to litter the code // If we're at -O1 and above, we don't want to litter the code
// with this marker yet, so leave a breadcrumb for the ARC // with this marker yet, so leave a breadcrumb for the ARC
// optimizer to pick up. // optimizer to pick up.
} else { } else {
llvm::NamedMDNode *metadata = const char *markerKey = "clang.arc.retainAutoreleasedReturnValueMarker";
CGF.CGM.getModule().getOrInsertNamedMetadata( if (!CGF.CGM.getModule().getModuleFlag(markerKey)) {
"clang.arc.retainAutoreleasedReturnValueMarker"); auto *str = llvm::MDString::get(CGF.getLLVMContext(), assembly);
assert(metadata->getNumOperands() <= 1); CGF.CGM.getModule().addModuleFlag(llvm::Module::Error, markerKey, str);
if (metadata->getNumOperands() == 0) {
auto &ctx = CGF.getLLVMContext();
metadata->addOperand(llvm::MDNode::get(ctx,
llvm::MDString::get(ctx, assembly)));
} }
} }
} }
// Call the marker asm if we made one, which we do only at -O0. // Call the marker asm if we made one, which we do only at -O0.
if (marker) if (marker)
CGF.Builder.CreateCall(marker, None, CGF.getBundlesForFunclet(marker)); CGF.Builder.CreateCall(marker, None, CGF.getBundlesForFunclet(marker));
} }
/// Retain the given object which is the result of a function call. /// Retain the given object which is the result of a function call.
/// call i8* \@objc_retainAutoreleasedReturnValue(i8* %value) /// call i8* \@objc_retainAutoreleasedReturnValue(i8* %value)
/// ///
/// Yes, this function name is one character away from a different /// Yes, this function name is one character away from a different
/// call with completely different semantics. /// call with completely different semantics.
llvm::Value * llvm::Value *
CodeGenFunction::EmitARCRetainAutoreleasedReturnValue(llvm::Value *value) { CodeGenFunction::EmitARCRetainAutoreleasedReturnValue(llvm::Value *value) {
emitAutoreleasedReturnValueMarker(*this); emitAutoreleasedReturnValueMarker(*this);
return emitARCValueOperation(*this, value, nullptr, llvm::CallInst::TailCallKind tailKind =
CGM.getObjCEntrypoints().objc_retainAutoreleasedReturnValue, CGM.getTargetCodeGenInfo()
llvm::Intrinsic::objc_retainAutoreleasedReturnValue); .shouldSuppressTailCallsOfRetainAutoreleasedReturnValue()
? llvm::CallInst::TCK_NoTail
: llvm::CallInst::TCK_None;
return emitARCValueOperation(
*this, value, nullptr,
CGM.getObjCEntrypoints().objc_retainAutoreleasedReturnValue,
llvm::Intrinsic::objc_retainAutoreleasedReturnValue, tailKind);
} }
/// Claim a possibly-autoreleased return value at +0. This is only /// Claim a possibly-autoreleased return value at +0. This is only
/// valid to do in contexts which do not rely on the retain to keep /// valid to do in contexts which do not rely on the retain to keep
/// the object valid for all of its uses; for example, when /// the object valid for all of its uses; for example, when
/// the value is ignored, or when it is being assigned to an /// the value is ignored, or when it is being assigned to an
/// __unsafe_unretained variable. /// __unsafe_unretained variable.
/// ///
/// call i8* \@objc_unsafeClaimAutoreleasedReturnValue(i8* %value) /// call i8* \@objc_unsafeClaimAutoreleasedReturnValue(i8* %value)
llvm::Value * llvm::Value *
skipping to change at line 2174 skipping to change at line 2233
CGM.getObjCEntrypoints().objc_unsafeClaimAutoreleasedReturnValue, CGM.getObjCEntrypoints().objc_unsafeClaimAutoreleasedReturnValue,
llvm::Intrinsic::objc_unsafeClaimAutoreleasedReturnValue); llvm::Intrinsic::objc_unsafeClaimAutoreleasedReturnValue);
} }
/// Release the given object. /// Release the given object.
/// call void \@objc_release(i8* %value) /// call void \@objc_release(i8* %value)
void CodeGenFunction::EmitARCRelease(llvm::Value *value, void CodeGenFunction::EmitARCRelease(llvm::Value *value,
ARCPreciseLifetime_t precise) { ARCPreciseLifetime_t precise) {
if (isa<llvm::ConstantPointerNull>(value)) return; if (isa<llvm::ConstantPointerNull>(value)) return;
llvm::Constant *&fn = CGM.getObjCEntrypoints().objc_release; llvm::Function *&fn = CGM.getObjCEntrypoints().objc_release;
if (!fn) { if (!fn) {
fn = CGM.getIntrinsic(llvm::Intrinsic::objc_release); fn = CGM.getIntrinsic(llvm::Intrinsic::objc_release);
setARCRuntimeFunctionLinkage(CGM, fn); setARCRuntimeFunctionLinkage(CGM, fn);
} }
// Cast the argument to 'id'. // Cast the argument to 'id'.
value = Builder.CreateBitCast(value, Int8PtrTy); value = Builder.CreateBitCast(value, Int8PtrTy);
// Call objc_release. // Call objc_release.
llvm::CallInst *call = EmitNounwindRuntimeCall(fn, value); llvm::CallInst *call = EmitNounwindRuntimeCall(fn, value);
skipping to change at line 2220 skipping to change at line 2279
EmitARCRelease(value, precise); EmitARCRelease(value, precise);
} }
/// Store into a strong object. Always calls this: /// Store into a strong object. Always calls this:
/// call void \@objc_storeStrong(i8** %addr, i8* %value) /// call void \@objc_storeStrong(i8** %addr, i8* %value)
llvm::Value *CodeGenFunction::EmitARCStoreStrongCall(Address addr, llvm::Value *CodeGenFunction::EmitARCStoreStrongCall(Address addr,
llvm::Value *value, llvm::Value *value,
bool ignored) { bool ignored) {
assert(addr.getElementType() == value->getType()); assert(addr.getElementType() == value->getType());
llvm::Constant *&fn = CGM.getObjCEntrypoints().objc_storeStrong; llvm::Function *&fn = CGM.getObjCEntrypoints().objc_storeStrong;
if (!fn) { if (!fn) {
fn = CGM.getIntrinsic(llvm::Intrinsic::objc_storeStrong); fn = CGM.getIntrinsic(llvm::Intrinsic::objc_storeStrong);
setARCRuntimeFunctionLinkage(CGM, fn); setARCRuntimeFunctionLinkage(CGM, fn);
} }
llvm::Value *args[] = { llvm::Value *args[] = {
Builder.CreateBitCast(addr.getPointer(), Int8PtrPtrTy), Builder.CreateBitCast(addr.getPointer(), Int8PtrPtrTy),
Builder.CreateBitCast(value, Int8PtrTy) Builder.CreateBitCast(value, Int8PtrTy)
}; };
EmitNounwindRuntimeCall(fn, args); EmitNounwindRuntimeCall(fn, args);
skipping to change at line 2287 skipping to change at line 2346
llvm::Intrinsic::objc_autorelease); llvm::Intrinsic::objc_autorelease);
} }
/// Autorelease the given object. /// Autorelease the given object.
/// call i8* \@objc_autoreleaseReturnValue(i8* %value) /// call i8* \@objc_autoreleaseReturnValue(i8* %value)
llvm::Value * llvm::Value *
CodeGenFunction::EmitARCAutoreleaseReturnValue(llvm::Value *value) { CodeGenFunction::EmitARCAutoreleaseReturnValue(llvm::Value *value) {
return emitARCValueOperation(*this, value, nullptr, return emitARCValueOperation(*this, value, nullptr,
CGM.getObjCEntrypoints().objc_autoreleaseReturnValue , CGM.getObjCEntrypoints().objc_autoreleaseReturnValue ,
llvm::Intrinsic::objc_autoreleaseReturnValue, llvm::Intrinsic::objc_autoreleaseReturnValue,
/*isTailCall*/ true); llvm::CallInst::TCK_Tail);
} }
/// Do a fused retain/autorelease of the given object. /// Do a fused retain/autorelease of the given object.
/// call i8* \@objc_retainAutoreleaseReturnValue(i8* %value) /// call i8* \@objc_retainAutoreleaseReturnValue(i8* %value)
llvm::Value * llvm::Value *
CodeGenFunction::EmitARCRetainAutoreleaseReturnValue(llvm::Value *value) { CodeGenFunction::EmitARCRetainAutoreleaseReturnValue(llvm::Value *value) {
return emitARCValueOperation(*this, value, nullptr, return emitARCValueOperation(*this, value, nullptr,
CGM.getObjCEntrypoints().objc_retainAutoreleaseReturnValue, CGM.getObjCEntrypoints().objc_retainAutoreleaseReturnValue,
llvm::Intrinsic::objc_retainAutoreleaseReturnValue, llvm::Intrinsic::objc_retainAutoreleaseReturnValue,
/*isTailCall*/ true); llvm::CallInst::TCK_Tail);
} }
/// Do a fused retain/autorelease of the given object. /// Do a fused retain/autorelease of the given object.
/// call i8* \@objc_retainAutorelease(i8* %value) /// call i8* \@objc_retainAutorelease(i8* %value)
/// or /// or
/// %retain = call i8* \@objc_retainBlock(i8* %value) /// %retain = call i8* \@objc_retainBlock(i8* %value)
/// call i8* \@objc_autorelease(i8* %retain) /// call i8* \@objc_autorelease(i8* %retain)
llvm::Value *CodeGenFunction::EmitARCRetainAutorelease(QualType type, llvm::Value *CodeGenFunction::EmitARCRetainAutorelease(QualType type,
llvm::Value *value) { llvm::Value *value) {
if (!type->isBlockPointerType()) if (!type->isBlockPointerType())
skipping to change at line 2376 skipping to change at line 2435
} }
emitARCStoreOperation(*this, addr, value, emitARCStoreOperation(*this, addr, value,
CGM.getObjCEntrypoints().objc_initWeak, CGM.getObjCEntrypoints().objc_initWeak,
llvm::Intrinsic::objc_initWeak, /*ignored*/ true); llvm::Intrinsic::objc_initWeak, /*ignored*/ true);
} }
/// void \@objc_destroyWeak(i8** %addr) /// void \@objc_destroyWeak(i8** %addr)
/// Essentially objc_storeWeak(addr, nil). /// Essentially objc_storeWeak(addr, nil).
void CodeGenFunction::EmitARCDestroyWeak(Address addr) { void CodeGenFunction::EmitARCDestroyWeak(Address addr) {
llvm::Constant *&fn = CGM.getObjCEntrypoints().objc_destroyWeak; llvm::Function *&fn = CGM.getObjCEntrypoints().objc_destroyWeak;
if (!fn) { if (!fn) {
fn = CGM.getIntrinsic(llvm::Intrinsic::objc_destroyWeak); fn = CGM.getIntrinsic(llvm::Intrinsic::objc_destroyWeak);
setARCRuntimeFunctionLinkage(CGM, fn); setARCRuntimeFunctionLinkage(CGM, fn);
} }
// Cast the argument to 'id*'. // Cast the argument to 'id*'.
addr = Builder.CreateBitCast(addr, Int8PtrPtrTy); addr = Builder.CreateBitCast(addr, Int8PtrPtrTy);
EmitNounwindRuntimeCall(fn, addr.getPointer()); EmitNounwindRuntimeCall(fn, addr.getPointer());
} }
skipping to change at line 2424 skipping to change at line 2483
Address SrcAddr) { Address SrcAddr) {
llvm::Value *Object = EmitARCLoadWeakRetained(SrcAddr); llvm::Value *Object = EmitARCLoadWeakRetained(SrcAddr);
Object = EmitObjCConsumeObject(Ty, Object); Object = EmitObjCConsumeObject(Ty, Object);
EmitARCStoreWeak(DstAddr, Object, false); EmitARCStoreWeak(DstAddr, Object, false);
EmitARCDestroyWeak(SrcAddr); EmitARCDestroyWeak(SrcAddr);
} }
/// Produce the code to do a objc_autoreleasepool_push. /// Produce the code to do a objc_autoreleasepool_push.
/// call i8* \@objc_autoreleasePoolPush(void) /// call i8* \@objc_autoreleasePoolPush(void)
llvm::Value *CodeGenFunction::EmitObjCAutoreleasePoolPush() { llvm::Value *CodeGenFunction::EmitObjCAutoreleasePoolPush() {
llvm::Constant *&fn = CGM.getObjCEntrypoints().objc_autoreleasePoolPush; llvm::Function *&fn = CGM.getObjCEntrypoints().objc_autoreleasePoolPush;
if (!fn) { if (!fn) {
fn = CGM.getIntrinsic(llvm::Intrinsic::objc_autoreleasePoolPush); fn = CGM.getIntrinsic(llvm::Intrinsic::objc_autoreleasePoolPush);
setARCRuntimeFunctionLinkage(CGM, fn); setARCRuntimeFunctionLinkage(CGM, fn);
} }
return EmitNounwindRuntimeCall(fn); return EmitNounwindRuntimeCall(fn);
} }
/// Produce the code to do a primitive release. /// Produce the code to do a primitive release.
/// call void \@objc_autoreleasePoolPop(i8* %ptr) /// call void \@objc_autoreleasePoolPop(i8* %ptr)
void CodeGenFunction::EmitObjCAutoreleasePoolPop(llvm::Value *value) { void CodeGenFunction::EmitObjCAutoreleasePoolPop(llvm::Value *value) {
assert(value->getType() == Int8PtrTy); assert(value->getType() == Int8PtrTy);
if (getInvokeDest()) { if (getInvokeDest()) {
// Call the runtime method not the intrinsic if we are handling exceptions // Call the runtime method not the intrinsic if we are handling exceptions
llvm::Constant *&fn = llvm::FunctionCallee &fn =
CGM.getObjCEntrypoints().objc_autoreleasePoolPopInvoke; CGM.getObjCEntrypoints().objc_autoreleasePoolPopInvoke;
if (!fn) { if (!fn) {
llvm::FunctionType *fnType = llvm::FunctionType *fnType =
llvm::FunctionType::get(Builder.getVoidTy(), Int8PtrTy, false); llvm::FunctionType::get(Builder.getVoidTy(), Int8PtrTy, false);
fn = CGM.CreateRuntimeFunction(fnType, "objc_autoreleasePoolPop"); fn = CGM.CreateRuntimeFunction(fnType, "objc_autoreleasePoolPop");
setARCRuntimeFunctionLinkage(CGM, fn); setARCRuntimeFunctionLinkage(CGM, fn);
} }
// objc_autoreleasePoolPop can throw. // objc_autoreleasePoolPop can throw.
EmitRuntimeCallOrInvoke(fn, value); EmitRuntimeCallOrInvoke(fn, value);
} else { } else {
llvm::Constant *&fn = CGM.getObjCEntrypoints().objc_autoreleasePoolPop; llvm::FunctionCallee &fn = CGM.getObjCEntrypoints().objc_autoreleasePoolPop;
if (!fn) { if (!fn) {
fn = CGM.getIntrinsic(llvm::Intrinsic::objc_autoreleasePoolPop); fn = CGM.getIntrinsic(llvm::Intrinsic::objc_autoreleasePoolPop);
setARCRuntimeFunctionLinkage(CGM, fn); setARCRuntimeFunctionLinkage(CGM, fn);
} }
EmitRuntimeCall(fn, value); EmitRuntimeCall(fn, value);
} }
} }
/// Produce the code to do an MRR version objc_autoreleasepool_push. /// Produce the code to do an MRR version objc_autoreleasepool_push.
skipping to change at line 2508 skipping to change at line 2567
/// Allocate the given objc object. /// Allocate the given objc object.
/// call i8* \@objc_allocWithZone(i8* %value) /// call i8* \@objc_allocWithZone(i8* %value)
llvm::Value *CodeGenFunction::EmitObjCAllocWithZone(llvm::Value *value, llvm::Value *CodeGenFunction::EmitObjCAllocWithZone(llvm::Value *value,
llvm::Type *resultType) { llvm::Type *resultType) {
return emitObjCValueOperation(*this, value, resultType, return emitObjCValueOperation(*this, value, resultType,
CGM.getObjCEntrypoints().objc_allocWithZone, CGM.getObjCEntrypoints().objc_allocWithZone,
"objc_allocWithZone"); "objc_allocWithZone");
} }
llvm::Value *CodeGenFunction::EmitObjCAllocInit(llvm::Value *value,
llvm::Type *resultType) {
return emitObjCValueOperation(*this, value, resultType,
CGM.getObjCEntrypoints().objc_alloc_init,
"objc_alloc_init");
}
/// Produce the code to do a primitive release. /// Produce the code to do a primitive release.
/// [tmp drain]; /// [tmp drain];
void CodeGenFunction::EmitObjCMRRAutoreleasePoolPop(llvm::Value *Arg) { void CodeGenFunction::EmitObjCMRRAutoreleasePoolPop(llvm::Value *Arg) {
IdentifierInfo *II = &CGM.getContext().Idents.get("drain"); IdentifierInfo *II = &CGM.getContext().Idents.get("drain");
Selector DrainSel = getContext().Selectors.getSelector(0, &II); Selector DrainSel = getContext().Selectors.getSelector(0, &II);
CallArgList Args; CallArgList Args;
CGM.getObjCRuntime().GenerateMessageSend(*this, ReturnValueSlot(), CGM.getObjCRuntime().GenerateMessageSend(*this, ReturnValueSlot(),
getContext().VoidTy, DrainSel, Arg, Args); getContext().VoidTy, DrainSel, Arg, Args);
} }
skipping to change at line 2546 skipping to change at line 2612
void CodeGenFunction::emitARCIntrinsicUse(CodeGenFunction &CGF, Address addr, void CodeGenFunction::emitARCIntrinsicUse(CodeGenFunction &CGF, Address addr,
QualType type) { QualType type) {
llvm::Value *value = CGF.Builder.CreateLoad(addr); llvm::Value *value = CGF.Builder.CreateLoad(addr);
CGF.EmitARCIntrinsicUse(value); CGF.EmitARCIntrinsicUse(value);
} }
/// Autorelease the given object. /// Autorelease the given object.
/// call i8* \@objc_autorelease(i8* %value) /// call i8* \@objc_autorelease(i8* %value)
llvm::Value *CodeGenFunction::EmitObjCAutorelease(llvm::Value *value, llvm::Value *CodeGenFunction::EmitObjCAutorelease(llvm::Value *value,
llvm::Type *returnType) { llvm::Type *returnType) {
return emitObjCValueOperation(*this, value, returnType, return emitObjCValueOperation(
CGM.getObjCEntrypoints().objc_autoreleaseRuntimeFunction, *this, value, returnType,
"objc_autorelease"); CGM.getObjCEntrypoints().objc_autoreleaseRuntimeFunction,
"objc_autorelease");
} }
/// Retain the given object, with normal retain semantics. /// Retain the given object, with normal retain semantics.
/// call i8* \@objc_retain(i8* %value) /// call i8* \@objc_retain(i8* %value)
llvm::Value *CodeGenFunction::EmitObjCRetainNonBlock(llvm::Value *value, llvm::Value *CodeGenFunction::EmitObjCRetainNonBlock(llvm::Value *value,
llvm::Type *returnType) { llvm::Type *returnType) {
return emitObjCValueOperation(*this, value, returnType, return emitObjCValueOperation(
CGM.getObjCEntrypoints().objc_retainRuntimeFunction, *this, value, returnType,
"objc_retain"); CGM.getObjCEntrypoints().objc_retainRuntimeFunction, "objc_retain");
} }
/// Release the given object. /// Release the given object.
/// call void \@objc_release(i8* %value) /// call void \@objc_release(i8* %value)
void CodeGenFunction::EmitObjCRelease(llvm::Value *value, void CodeGenFunction::EmitObjCRelease(llvm::Value *value,
ARCPreciseLifetime_t precise) { ARCPreciseLifetime_t precise) {
if (isa<llvm::ConstantPointerNull>(value)) return; if (isa<llvm::ConstantPointerNull>(value)) return;
llvm::Constant *&fn = CGM.getObjCEntrypoints().objc_release; llvm::FunctionCallee &fn =
CGM.getObjCEntrypoints().objc_releaseRuntimeFunction;
if (!fn) { if (!fn) {
if (!fn) { llvm::FunctionType *fnType =
llvm::FunctionType *fnType =
llvm::FunctionType::get(Builder.getVoidTy(), Int8PtrTy, false); llvm::FunctionType::get(Builder.getVoidTy(), Int8PtrTy, false);
fn = CGM.CreateRuntimeFunction(fnType, "objc_release"); fn = CGM.CreateRuntimeFunction(fnType, "objc_release");
setARCRuntimeFunctionLinkage(CGM, fn); setARCRuntimeFunctionLinkage(CGM, fn);
// We have Native ARC, so set nonlazybind attribute for performance // We have Native ARC, so set nonlazybind attribute for performance
if (llvm::Function *f = dyn_cast<llvm::Function>(fn)) if (llvm::Function *f = dyn_cast<llvm::Function>(fn.getCallee()))
f->addFnAttr(llvm::Attribute::NonLazyBind); f->addFnAttr(llvm::Attribute::NonLazyBind);
}
} }
// Cast the argument to 'id'. // Cast the argument to 'id'.
value = Builder.CreateBitCast(value, Int8PtrTy); value = Builder.CreateBitCast(value, Int8PtrTy);
// Call objc_release. // Call objc_release.
llvm::CallInst *call = EmitNounwindRuntimeCall(fn, value); llvm::CallBase *call = EmitCallOrInvoke(fn, value);
if (precise == ARCImpreciseLifetime) { if (precise == ARCImpreciseLifetime) {
call->setMetadata("clang.imprecise_release", call->setMetadata("clang.imprecise_release",
llvm::MDNode::get(Builder.getContext(), None)); llvm::MDNode::get(Builder.getContext(), None));
} }
} }
namespace { namespace {
struct CallObjCAutoreleasePoolObject final : EHScopeStack::Cleanup { struct CallObjCAutoreleasePoolObject final : EHScopeStack::Cleanup {
llvm::Value *Token; llvm::Value *Token;
skipping to change at line 2830 skipping to change at line 2896
protected: protected:
CodeGenFunction &CGF; CodeGenFunction &CGF;
Impl &asImpl() { return *static_cast<Impl*>(this); } Impl &asImpl() { return *static_cast<Impl*>(this); }
ARCExprEmitter(CodeGenFunction &CGF) : CGF(CGF) {} ARCExprEmitter(CodeGenFunction &CGF) : CGF(CGF) {}
public: public:
Result visit(const Expr *e); Result visit(const Expr *e);
Result visitCastExpr(const CastExpr *e); Result visitCastExpr(const CastExpr *e);
Result visitPseudoObjectExpr(const PseudoObjectExpr *e); Result visitPseudoObjectExpr(const PseudoObjectExpr *e);
Result visitBlockExpr(const BlockExpr *e);
Result visitBinaryOperator(const BinaryOperator *e); Result visitBinaryOperator(const BinaryOperator *e);
Result visitBinAssign(const BinaryOperator *e); Result visitBinAssign(const BinaryOperator *e);
Result visitBinAssignUnsafeUnretained(const BinaryOperator *e); Result visitBinAssignUnsafeUnretained(const BinaryOperator *e);
Result visitBinAssignAutoreleasing(const BinaryOperator *e); Result visitBinAssignAutoreleasing(const BinaryOperator *e);
Result visitBinAssignWeak(const BinaryOperator *e); Result visitBinAssignWeak(const BinaryOperator *e);
Result visitBinAssignStrong(const BinaryOperator *e); Result visitBinAssignStrong(const BinaryOperator *e);
// Minimal implementation: // Minimal implementation:
// Result visitLValueToRValue(const Expr *e) // Result visitLValueToRValue(const Expr *e)
// Result visitConsumeObject(const Expr *e) // Result visitConsumeObject(const Expr *e)
skipping to change at line 2906 skipping to change at line 2973
} }
// Unbind all the opaques now. // Unbind all the opaques now.
for (unsigned i = 0, e = opaques.size(); i != e; ++i) for (unsigned i = 0, e = opaques.size(); i != e; ++i)
opaques[i].unbind(CGF); opaques[i].unbind(CGF);
return result; return result;
} }
template <typename Impl, typename Result> template <typename Impl, typename Result>
Result ARCExprEmitter<Impl, Result>::visitBlockExpr(const BlockExpr *e) {
// The default implementation just forwards the expression to visitExpr.
return asImpl().visitExpr(e);
}
template <typename Impl, typename Result>
Result ARCExprEmitter<Impl,Result>::visitCastExpr(const CastExpr *e) { Result ARCExprEmitter<Impl,Result>::visitCastExpr(const CastExpr *e) {
switch (e->getCastKind()) { switch (e->getCastKind()) {
// No-op casts don't change the type, so we just ignore them. // No-op casts don't change the type, so we just ignore them.
case CK_NoOp: case CK_NoOp:
return asImpl().visit(e->getSubExpr()); return asImpl().visit(e->getSubExpr());
// These casts can change the type. // These casts can change the type.
case CK_CPointerToObjCPointerCast: case CK_CPointerToObjCPointerCast:
case CK_BlockPointerToObjCPointerCast: case CK_BlockPointerToObjCPointerCast:
skipping to change at line 3048 skipping to change at line 3121
// returns-retained expression that *isn't* surrounded by // returns-retained expression that *isn't* surrounded by
// a consume. // a consume.
} else if (isa<CallExpr>(e) || } else if (isa<CallExpr>(e) ||
(isa<ObjCMessageExpr>(e) && (isa<ObjCMessageExpr>(e) &&
!cast<ObjCMessageExpr>(e)->isDelegateInitCall())) { !cast<ObjCMessageExpr>(e)->isDelegateInitCall())) {
return asImpl().visitCall(e); return asImpl().visitCall(e);
// Look through pseudo-object expressions. // Look through pseudo-object expressions.
} else if (const PseudoObjectExpr *pseudo = dyn_cast<PseudoObjectExpr>(e)) { } else if (const PseudoObjectExpr *pseudo = dyn_cast<PseudoObjectExpr>(e)) {
return asImpl().visitPseudoObjectExpr(pseudo); return asImpl().visitPseudoObjectExpr(pseudo);
} } else if (auto *be = dyn_cast<BlockExpr>(e))
return asImpl().visitBlockExpr(be);
return asImpl().visitExpr(e); return asImpl().visitExpr(e);
} }
namespace { namespace {
/// An emitter for +1 results. /// An emitter for +1 results.
struct ARCRetainExprEmitter : struct ARCRetainExprEmitter :
public ARCExprEmitter<ARCRetainExprEmitter, TryEmitResult> { public ARCExprEmitter<ARCRetainExprEmitter, TryEmitResult> {
skipping to change at line 3083 skipping to change at line 3157
return tryEmitARCRetainLoadOfScalar(CGF, e); return tryEmitARCRetainLoadOfScalar(CGF, e);
} }
/// For consumptions, just emit the subexpression and thus elide /// For consumptions, just emit the subexpression and thus elide
/// the retain/release pair. /// the retain/release pair.
TryEmitResult visitConsumeObject(const Expr *e) { TryEmitResult visitConsumeObject(const Expr *e) {
llvm::Value *result = CGF.EmitScalarExpr(e); llvm::Value *result = CGF.EmitScalarExpr(e);
return TryEmitResult(result, true); return TryEmitResult(result, true);
} }
TryEmitResult visitBlockExpr(const BlockExpr *e) {
TryEmitResult result = visitExpr(e);
// Avoid the block-retain if this is a block literal that doesn't need to be
// copied to the heap.
if (e->getBlockDecl()->canAvoidCopyToHeap())
result.setInt(true);
return result;
}
/// Block extends are net +0. Naively, we could just recurse on /// Block extends are net +0. Naively, we could just recurse on
/// the subexpression, but actually we need to ensure that the /// the subexpression, but actually we need to ensure that the
/// value is copied as a block, so there's a little filter here. /// value is copied as a block, so there's a little filter here.
TryEmitResult visitExtendBlockObject(const Expr *e) { TryEmitResult visitExtendBlockObject(const Expr *e) {
llvm::Value *result; // will be a +0 value llvm::Value *result; // will be a +0 value
// If we can't safely assume the sub-expression will produce a // If we can't safely assume the sub-expression will produce a
// block-copied value, emit the sub-expression at +0. // block-copied value, emit the sub-expression at +0.
if (shouldEmitSeparateBlockRetain(e)) { if (shouldEmitSeparateBlockRetain(e)) {
result = CGF.EmitScalarExpr(e); result = CGF.EmitScalarExpr(e);
skipping to change at line 3385 skipping to change at line 3468
if (DI) if (DI)
DI->EmitLexicalBlockEnd(Builder, S.getRBracLoc()); DI->EmitLexicalBlockEnd(Builder, S.getRBracLoc());
} }
/// EmitExtendGCLifetime - Given a pointer to an Objective-C object, /// EmitExtendGCLifetime - Given a pointer to an Objective-C object,
/// make sure it survives garbage collection until this point. /// make sure it survives garbage collection until this point.
void CodeGenFunction::EmitExtendGCLifetime(llvm::Value *object) { void CodeGenFunction::EmitExtendGCLifetime(llvm::Value *object) {
// We just use an inline assembly. // We just use an inline assembly.
llvm::FunctionType *extenderType llvm::FunctionType *extenderType
= llvm::FunctionType::get(VoidTy, VoidPtrTy, RequiredArgs::All); = llvm::FunctionType::get(VoidTy, VoidPtrTy, RequiredArgs::All);
llvm::Value *extender llvm::InlineAsm *extender = llvm::InlineAsm::get(extenderType,
= llvm::InlineAsm::get(extenderType, /* assembly */ "",
/* assembly */ "", /* constraints */ "r",
/* constraints */ "r", /* side effects */ true);
/* side effects */ true);
object = Builder.CreateBitCast(object, VoidPtrTy); object = Builder.CreateBitCast(object, VoidPtrTy);
EmitNounwindRuntimeCall(extender, object); EmitNounwindRuntimeCall(extender, object);
} }
/// GenerateObjCAtomicSetterCopyHelperFunction - Given a c++ object type with /// GenerateObjCAtomicSetterCopyHelperFunction - Given a c++ object type with
/// non-trivial copy assignment function, produce following helper function. /// non-trivial copy assignment function, produce following helper function.
/// static void copyHelper(Ty *dest, const Ty *source) { *dest = *source; } /// static void copyHelper(Ty *dest, const Ty *source) { *dest = *source; }
/// ///
llvm::Constant * llvm::Constant *
skipping to change at line 3648 skipping to change at line 3730
// CoreFoundation is not used in the code, the linker won't link the // CoreFoundation is not used in the code, the linker won't link the
// framework. // framework.
auto &Context = getLLVMContext(); auto &Context = getLLVMContext();
llvm::Metadata *Args[2] = {llvm::MDString::get(Context, "-framework"), llvm::Metadata *Args[2] = {llvm::MDString::get(Context, "-framework"),
llvm::MDString::get(Context, "CoreFoundation")}; llvm::MDString::get(Context, "CoreFoundation")};
LinkerOptionsMetadata.push_back(llvm::MDNode::get(Context, Args)); LinkerOptionsMetadata.push_back(llvm::MDNode::get(Context, Args));
// Emit a reference to a symbol from CoreFoundation to ensure that // Emit a reference to a symbol from CoreFoundation to ensure that
// CoreFoundation is linked into the final binary. // CoreFoundation is linked into the final binary.
llvm::FunctionType *FTy = llvm::FunctionType *FTy =
llvm::FunctionType::get(Int32Ty, {VoidPtrTy}, false); llvm::FunctionType::get(Int32Ty, {VoidPtrTy}, false);
llvm::Constant *CFFunc = llvm::FunctionCallee CFFunc =
CreateRuntimeFunction(FTy, "CFBundleGetVersionNumber"); CreateRuntimeFunction(FTy, "CFBundleGetVersionNumber");
llvm::FunctionType *CheckFTy = llvm::FunctionType::get(VoidTy, {}, false); llvm::FunctionType *CheckFTy = llvm::FunctionType::get(VoidTy, {}, false);
llvm::Function *CFLinkCheckFunc = cast<llvm::Function>(CreateBuiltinFunction( llvm::FunctionCallee CFLinkCheckFuncRef = CreateRuntimeFunction(
CheckFTy, "__clang_at_available_requires_core_foundation_framework")); CheckFTy, "__clang_at_available_requires_core_foundation_framework",
CFLinkCheckFunc->setLinkage(llvm::GlobalValue::LinkOnceAnyLinkage); llvm::AttributeList(), /*Local=*/true);
CFLinkCheckFunc->setVisibility(llvm::GlobalValue::HiddenVisibility); llvm::Function *CFLinkCheckFunc =
CodeGenFunction CGF(*this); cast<llvm::Function>(CFLinkCheckFuncRef.getCallee()->stripPointerCasts());
CGF.Builder.SetInsertPoint(CGF.createBasicBlock("", CFLinkCheckFunc)); if (CFLinkCheckFunc->empty()) {
CGF.EmitNounwindRuntimeCall(CFFunc, llvm::Constant::getNullValue(VoidPtrTy)); CFLinkCheckFunc->setLinkage(llvm::GlobalValue::LinkOnceAnyLinkage);
CGF.Builder.CreateUnreachable(); CFLinkCheckFunc->setVisibility(llvm::GlobalValue::HiddenVisibility);
addCompilerUsedGlobal(CFLinkCheckFunc); CodeGenFunction CGF(*this);
CGF.Builder.SetInsertPoint(CGF.createBasicBlock("", CFLinkCheckFunc));
CGF.EmitNounwindRuntimeCall(CFFunc,
llvm::Constant::getNullValue(VoidPtrTy));
CGF.Builder.CreateUnreachable();
addCompilerUsedGlobal(CFLinkCheckFunc);
}
} }
CGObjCRuntime::~CGObjCRuntime() {} CGObjCRuntime::~CGObjCRuntime() {}
 End of changes. 61 change blocks. 
118 lines changed or deleted 206 lines changed or added

Home  |  About  |  Features  |  All  |  Newest  |  Dox  |  Diffs  |  RSS Feeds  |  Screenshots  |  Comments  |  Imprint  |  Privacy  |  HTTP(S)