aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm/tools/clang/lib/CodeGen/CGObjC.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm/tools/clang/lib/CodeGen/CGObjC.cpp')
-rw-r--r--contrib/llvm/tools/clang/lib/CodeGen/CGObjC.cpp1362
1 files changed, 873 insertions, 489 deletions
diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGObjC.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGObjC.cpp
index 426cca00140c..51f20534d116 100644
--- a/contrib/llvm/tools/clang/lib/CodeGen/CGObjC.cpp
+++ b/contrib/llvm/tools/clang/lib/CodeGen/CGObjC.cpp
@@ -33,7 +33,7 @@ tryEmitARCRetainScalarExpr(CodeGenFunction &CGF, const Expr *e);
/// Given the address of a variable of pointer type, find the correct
/// null to store into it.
static llvm::Constant *getNullForVariable(llvm::Value *addr) {
- const llvm::Type *type =
+ llvm::Type *type =
cast<llvm::PointerType>(addr->getType())->getElementType();
return llvm::ConstantPointerNull::get(cast<llvm::PointerType>(type));
}
@@ -80,6 +80,53 @@ static RValue AdjustRelatedResultType(CodeGenFunction &CGF,
CGF.ConvertType(E->getType())));
}
+/// Decide whether to extend the lifetime of the receiver of a
+/// returns-inner-pointer message.
+static bool
+shouldExtendReceiverForInnerPointerMessage(const ObjCMessageExpr *message) {
+ switch (message->getReceiverKind()) {
+
+ // For a normal instance message, we should extend unless the
+ // receiver is loaded from a variable with precise lifetime.
+ case ObjCMessageExpr::Instance: {
+ const Expr *receiver = message->getInstanceReceiver();
+ const ImplicitCastExpr *ice = dyn_cast<ImplicitCastExpr>(receiver);
+ if (!ice || ice->getCastKind() != CK_LValueToRValue) return true;
+ receiver = ice->getSubExpr()->IgnoreParens();
+
+ // Only __strong variables.
+ if (receiver->getType().getObjCLifetime() != Qualifiers::OCL_Strong)
+ return true;
+
+ // All ivars and fields have precise lifetime.
+ if (isa<MemberExpr>(receiver) || isa<ObjCIvarRefExpr>(receiver))
+ return false;
+
+ // Otherwise, check for variables.
+ const DeclRefExpr *declRef = dyn_cast<DeclRefExpr>(ice->getSubExpr());
+ if (!declRef) return true;
+ const VarDecl *var = dyn_cast<VarDecl>(declRef->getDecl());
+ if (!var) return true;
+
+ // All variables have precise lifetime except local variables with
+ // automatic storage duration that aren't specially marked.
+ return (var->hasLocalStorage() &&
+ !var->hasAttr<ObjCPreciseLifetimeAttr>());
+ }
+
+ case ObjCMessageExpr::Class:
+ case ObjCMessageExpr::SuperClass:
+ // It's never necessary for class objects.
+ return false;
+
+ case ObjCMessageExpr::SuperInstance:
+ // We generally assume that 'self' lives throughout a method call.
+ return false;
+ }
+
+ llvm_unreachable("invalid receiver kind");
+}
+
RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E,
ReturnValueSlot Return) {
// Only the lookup mechanism and first two arguments of the method
@@ -88,6 +135,8 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E,
bool isDelegateInit = E->isDelegateInitCall();
+ const ObjCMethodDecl *method = E->getMethodDecl();
+
// We don't retain the receiver in delegate init calls, and this is
// safe because the receiver value is always loaded from 'self',
// which we zero out. We don't want to Block_copy block receivers,
@@ -95,8 +144,8 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E,
bool retainSelf =
(!isDelegateInit &&
CGM.getLangOptions().ObjCAutoRefCount &&
- E->getMethodDecl() &&
- E->getMethodDecl()->hasAttr<NSConsumesSelfAttr>());
+ method &&
+ method->hasAttr<NSConsumesSelfAttr>());
CGObjCRuntime &Runtime = CGM.getObjCRuntime();
bool isSuperMessage = false;
@@ -112,8 +161,7 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E,
TryEmitResult ter = tryEmitARCRetainScalarExpr(*this,
E->getInstanceReceiver());
Receiver = ter.getPointer();
- if (!ter.getInt())
- Receiver = EmitARCRetainNonBlock(Receiver);
+ if (ter.getInt()) retainSelf = false;
} else
Receiver = EmitScalarExpr(E->getInstanceReceiver());
break;
@@ -126,9 +174,6 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E,
assert(OID && "Invalid Objective-C class message send");
Receiver = Runtime.GetClass(Builder, OID);
isClassMessage = true;
-
- if (retainSelf)
- Receiver = EmitARCRetainNonBlock(Receiver);
break;
}
@@ -136,9 +181,6 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E,
ReceiverType = E->getSuperType();
Receiver = LoadObjCSelf();
isSuperMessage = true;
-
- if (retainSelf)
- Receiver = EmitARCRetainNonBlock(Receiver);
break;
case ObjCMessageExpr::SuperClass:
@@ -146,17 +188,25 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E,
Receiver = LoadObjCSelf();
isSuperMessage = true;
isClassMessage = true;
-
- if (retainSelf)
- Receiver = EmitARCRetainNonBlock(Receiver);
break;
}
+ if (retainSelf)
+ Receiver = EmitARCRetainNonBlock(Receiver);
+
+ // In ARC, we sometimes want to "extend the lifetime"
+ // (i.e. retain+autorelease) of receivers of returns-inner-pointer
+ // messages.
+ if (getLangOptions().ObjCAutoRefCount && method &&
+ method->hasAttr<ObjCReturnsInnerPointerAttr>() &&
+ shouldExtendReceiverForInnerPointerMessage(E))
+ Receiver = EmitARCRetainAutorelease(ReceiverType, Receiver);
+
QualType ResultType =
- E->getMethodDecl() ? E->getMethodDecl()->getResultType() : E->getType();
+ method ? method->getResultType() : E->getType();
CallArgList Args;
- EmitCallArgs(Args, E->getMethodDecl(), E->arg_begin(), E->arg_end());
+ EmitCallArgs(Args, method, E->arg_begin(), E->arg_end());
// For delegate init calls in ARC, do an unsafe store of null into
// self. This represents the call taking direct ownership of that
@@ -189,12 +239,12 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E,
Receiver,
isClassMessage,
Args,
- E->getMethodDecl());
+ method);
} else {
result = Runtime.GenerateMessageSend(*this, Return, ResultType,
E->getSelector(),
Receiver, Args, OID,
- E->getMethodDecl());
+ method);
}
// For delegate init calls in ARC, implicitly store the result of
@@ -206,14 +256,14 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E,
// The delegate return type isn't necessarily a matching type; in
// fact, it's quite likely to be 'id'.
- const llvm::Type *selfTy =
+ llvm::Type *selfTy =
cast<llvm::PointerType>(selfAddr->getType())->getElementType();
newSelf = Builder.CreateBitCast(newSelf, selfTy);
Builder.CreateStore(newSelf, selfAddr);
}
- return AdjustRelatedResultType(*this, E, E->getMethodDecl(), result);
+ return AdjustRelatedResultType(*this, E, method, result);
}
namespace {
@@ -263,7 +313,7 @@ void CodeGenFunction::StartObjCMethod(const ObjCMethodDecl *OMD,
args.push_back(OMD->getSelfDecl());
args.push_back(OMD->getCmdDecl());
- for (ObjCMethodDecl::param_iterator PI = OMD->param_begin(),
+ for (ObjCMethodDecl::param_const_iterator PI = OMD->param_begin(),
E = OMD->param_end(); PI != E; ++PI)
args.push_back(*PI);
@@ -285,39 +335,6 @@ void CodeGenFunction::StartObjCMethod(const ObjCMethodDecl *OMD,
static llvm::Value *emitARCRetainLoadOfScalar(CodeGenFunction &CGF,
LValue lvalue, QualType type);
-void CodeGenFunction::GenerateObjCGetterBody(ObjCIvarDecl *Ivar,
- bool IsAtomic, bool IsStrong) {
- LValue LV = EmitLValueForIvar(TypeOfSelfObject(), LoadObjCSelf(),
- Ivar, 0);
- llvm::Value *GetCopyStructFn =
- CGM.getObjCRuntime().GetGetStructFunction();
- CodeGenTypes &Types = CGM.getTypes();
- // objc_copyStruct (ReturnValue, &structIvar,
- // sizeof (Type of Ivar), isAtomic, false);
- CallArgList Args;
- RValue RV = RValue::get(Builder.CreateBitCast(ReturnValue, VoidPtrTy));
- Args.add(RV, getContext().VoidPtrTy);
- RV = RValue::get(Builder.CreateBitCast(LV.getAddress(), VoidPtrTy));
- Args.add(RV, getContext().VoidPtrTy);
- // sizeof (Type of Ivar)
- CharUnits Size = getContext().getTypeSizeInChars(Ivar->getType());
- llvm::Value *SizeVal =
- llvm::ConstantInt::get(Types.ConvertType(getContext().LongTy),
- Size.getQuantity());
- Args.add(RValue::get(SizeVal), getContext().LongTy);
- llvm::Value *isAtomic =
- llvm::ConstantInt::get(Types.ConvertType(getContext().BoolTy),
- IsAtomic ? 1 : 0);
- Args.add(RValue::get(isAtomic), getContext().BoolTy);
- llvm::Value *hasStrong =
- llvm::ConstantInt::get(Types.ConvertType(getContext().BoolTy),
- IsStrong ? 1 : 0);
- Args.add(RValue::get(hasStrong), getContext().BoolTy);
- EmitCall(Types.getFunctionInfo(getContext().VoidTy, Args,
- FunctionType::ExtInfo()),
- GetCopyStructFn, ReturnValueSlot(), Args);
-}
-
/// Generate an Objective-C method. An Objective-C method is a C function with
/// its pointer, name, and types registered in the class struture.
void CodeGenFunction::GenerateObjCMethod(const ObjCMethodDecl *OMD) {
@@ -326,218 +343,599 @@ void CodeGenFunction::GenerateObjCMethod(const ObjCMethodDecl *OMD) {
FinishFunction(OMD->getBodyRBrace());
}
-// FIXME: I wasn't sure about the synthesis approach. If we end up generating an
-// AST for the whole body we can just fall back to having a GenerateFunction
-// which takes the body Stmt.
+/// emitStructGetterCall - Call the runtime function to load a property
+/// into the return value slot.
+static void emitStructGetterCall(CodeGenFunction &CGF, ObjCIvarDecl *ivar,
+ bool isAtomic, bool hasStrong) {
+ ASTContext &Context = CGF.getContext();
+
+ llvm::Value *src =
+ CGF.EmitLValueForIvar(CGF.TypeOfSelfObject(), CGF.LoadObjCSelf(),
+ ivar, 0).getAddress();
+
+ // objc_copyStruct (ReturnValue, &structIvar,
+ // sizeof (Type of Ivar), isAtomic, false);
+ CallArgList args;
+
+ llvm::Value *dest = CGF.Builder.CreateBitCast(CGF.ReturnValue, CGF.VoidPtrTy);
+ args.add(RValue::get(dest), Context.VoidPtrTy);
+
+ src = CGF.Builder.CreateBitCast(src, CGF.VoidPtrTy);
+ args.add(RValue::get(src), Context.VoidPtrTy);
+
+ CharUnits size = CGF.getContext().getTypeSizeInChars(ivar->getType());
+ 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(hasStrong)), Context.BoolTy);
+
+ llvm::Value *fn = CGF.CGM.getObjCRuntime().GetGetStructFunction();
+ CGF.EmitCall(CGF.getTypes().getFunctionInfo(Context.VoidTy, args,
+ FunctionType::ExtInfo()),
+ fn, ReturnValueSlot(), args);
+}
+
+/// Determine whether the given architecture supports unaligned atomic
+/// accesses. They don't have to be fast, just faster than a function
+/// call and a mutex.
+static bool hasUnalignedAtomics(llvm::Triple::ArchType arch) {
+ // FIXME: Allow unaligned atomic load/store on x86. (It is not
+ // currently supported by the backend.)
+ return 0;
+}
+
+/// Return the maximum size that permits atomic accesses for the given
+/// architecture.
+static CharUnits getMaxAtomicAccessSize(CodeGenModule &CGM,
+ llvm::Triple::ArchType arch) {
+ // ARM has 8-byte atomic accesses, but it's not clear whether we
+ // want to rely on them here.
+
+ // In the default case, just assume that any size up to a pointer is
+ // fine given adequate alignment.
+ return CharUnits::fromQuantity(CGM.PointerSizeInBytes);
+}
+
+namespace {
+ class PropertyImplStrategy {
+ public:
+ enum StrategyKind {
+ /// The 'native' strategy is to use the architecture's provided
+ /// reads and writes.
+ Native,
+
+ /// Use objc_setProperty and objc_getProperty.
+ GetSetProperty,
+
+ /// Use objc_setProperty for the setter, but use expression
+ /// evaluation for the getter.
+ SetPropertyAndExpressionGet,
+
+ /// Use objc_copyStruct.
+ CopyStruct,
+
+ /// The 'expression' strategy is to emit normal assignment or
+ /// lvalue-to-rvalue expressions.
+ Expression
+ };
+
+ StrategyKind getKind() const { return StrategyKind(Kind); }
+
+ bool hasStrongMember() const { return HasStrong; }
+ bool isAtomic() const { return IsAtomic; }
+ bool isCopy() const { return IsCopy; }
+
+ CharUnits getIvarSize() const { return IvarSize; }
+ CharUnits getIvarAlignment() const { return IvarAlignment; }
+
+ PropertyImplStrategy(CodeGenModule &CGM,
+ const ObjCPropertyImplDecl *propImpl);
+
+ private:
+ unsigned Kind : 8;
+ unsigned IsAtomic : 1;
+ unsigned IsCopy : 1;
+ unsigned HasStrong : 1;
+
+ CharUnits IvarSize;
+ CharUnits IvarAlignment;
+ };
+}
+
+/// Pick an implementation strategy for the the given property synthesis.
+PropertyImplStrategy::PropertyImplStrategy(CodeGenModule &CGM,
+ const ObjCPropertyImplDecl *propImpl) {
+ const ObjCPropertyDecl *prop = propImpl->getPropertyDecl();
+ ObjCPropertyDecl::SetterKind setterKind = prop->getSetterKind();
+
+ IsCopy = (setterKind == ObjCPropertyDecl::Copy);
+ IsAtomic = prop->isAtomic();
+ HasStrong = false; // doesn't matter here.
+
+ // Evaluate the ivar's size and alignment.
+ ObjCIvarDecl *ivar = propImpl->getPropertyIvarDecl();
+ QualType ivarType = ivar->getType();
+ llvm::tie(IvarSize, IvarAlignment)
+ = CGM.getContext().getTypeInfoInChars(ivarType);
+
+ // If we have a copy property, we always have to use getProperty/setProperty.
+ // TODO: we could actually use setProperty and an expression for non-atomics.
+ if (IsCopy) {
+ Kind = GetSetProperty;
+ return;
+ }
+
+ // Handle retain.
+ if (setterKind == ObjCPropertyDecl::Retain) {
+ // In GC-only, there's nothing special that needs to be done.
+ if (CGM.getLangOptions().getGC() == LangOptions::GCOnly) {
+ // fallthrough
+
+ // In ARC, if the property is non-atomic, use expression emission,
+ // which translates to objc_storeStrong. This isn't required, but
+ // it's slightly nicer.
+ } else if (CGM.getLangOptions().ObjCAutoRefCount && !IsAtomic) {
+ Kind = Expression;
+ return;
+
+ // Otherwise, we need to at least use setProperty. However, if
+ // the property isn't atomic, we can use normal expression
+ // emission for the getter.
+ } else if (!IsAtomic) {
+ Kind = SetPropertyAndExpressionGet;
+ return;
+
+ // Otherwise, we have to use both setProperty and getProperty.
+ } else {
+ Kind = GetSetProperty;
+ return;
+ }
+ }
+
+ // If we're not atomic, just use expression accesses.
+ if (!IsAtomic) {
+ Kind = Expression;
+ return;
+ }
+
+ // Properties on bitfield ivars need to be emitted using expression
+ // accesses even if they're nominally atomic.
+ if (ivar->isBitField()) {
+ Kind = Expression;
+ return;
+ }
+
+ // GC-qualified or ARC-qualified ivars need to be emitted as
+ // expressions. This actually works out to being atomic anyway,
+ // except for ARC __strong, but that should trigger the above code.
+ if (ivarType.hasNonTrivialObjCLifetime() ||
+ (CGM.getLangOptions().getGC() &&
+ CGM.getContext().getObjCGCAttrKind(ivarType))) {
+ Kind = Expression;
+ return;
+ }
+
+ // Compute whether the ivar has strong members.
+ if (CGM.getLangOptions().getGC())
+ if (const RecordType *recordType = ivarType->getAs<RecordType>())
+ HasStrong = recordType->getDecl()->hasObjectMember();
+
+ // We can never access structs with object members with a native
+ // access, because we need to use write barriers. This is what
+ // objc_copyStruct is for.
+ if (HasStrong) {
+ Kind = CopyStruct;
+ return;
+ }
+
+ // Otherwise, this is target-dependent and based on the size and
+ // alignment of the ivar.
+
+ // If the size of the ivar is not a power of two, give up. We don't
+ // want to get into the business of doing compare-and-swaps.
+ if (!IvarSize.isPowerOfTwo()) {
+ Kind = CopyStruct;
+ return;
+ }
+
+ llvm::Triple::ArchType arch =
+ CGM.getContext().getTargetInfo().getTriple().getArch();
+
+ // Most architectures require memory to fit within a single cache
+ // line, so the alignment has to be at least the size of the access.
+ // Otherwise we have to grab a lock.
+ if (IvarAlignment < IvarSize && !hasUnalignedAtomics(arch)) {
+ Kind = CopyStruct;
+ return;
+ }
+
+ // If the ivar's size exceeds the architecture's maximum atomic
+ // access size, we have to use CopyStruct.
+ if (IvarSize > getMaxAtomicAccessSize(CGM, arch)) {
+ Kind = CopyStruct;
+ return;
+ }
+
+ // Otherwise, we can use native loads and stores.
+ Kind = Native;
+}
/// GenerateObjCGetter - Generate an Objective-C property getter
/// function. The given Decl must be an ObjCImplementationDecl. @synthesize
/// is illegal within a category.
void CodeGenFunction::GenerateObjCGetter(ObjCImplementationDecl *IMP,
const ObjCPropertyImplDecl *PID) {
- ObjCIvarDecl *Ivar = PID->getPropertyIvarDecl();
const ObjCPropertyDecl *PD = PID->getPropertyDecl();
- bool IsAtomic =
- !(PD->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_nonatomic);
ObjCMethodDecl *OMD = PD->getGetterMethodDecl();
assert(OMD && "Invalid call to generate getter (empty method)");
StartObjCMethod(OMD, IMP->getClassInterface(), PID->getLocStart());
-
- // Determine if we should use an objc_getProperty call for
- // this. Non-atomic properties are directly evaluated.
- // atomic 'copy' and 'retain' properties are also directly
- // evaluated in gc-only mode.
- if (CGM.getLangOptions().getGCMode() != LangOptions::GCOnly &&
- IsAtomic &&
- (PD->getSetterKind() == ObjCPropertyDecl::Copy ||
- PD->getSetterKind() == ObjCPropertyDecl::Retain)) {
- llvm::Value *GetPropertyFn =
- CGM.getObjCRuntime().GetPropertyGetFunction();
- if (!GetPropertyFn) {
- CGM.ErrorUnsupported(PID, "Obj-C getter requiring atomic copy");
- FinishFunction();
+ generateObjCGetterBody(IMP, PID);
+
+ FinishFunction();
+}
+
+static bool hasTrivialGetExpr(const ObjCPropertyImplDecl *propImpl) {
+ const Expr *getter = propImpl->getGetterCXXConstructor();
+ if (!getter) return true;
+
+ // Sema only makes only of these when the ivar has a C++ class type,
+ // so the form is pretty constrained.
+
+ // If the property has a reference type, we might just be binding a
+ // reference, in which case the result will be a gl-value. We should
+ // treat this as a non-trivial operation.
+ if (getter->isGLValue())
+ return false;
+
+ // If we selected a trivial copy-constructor, we're okay.
+ if (const CXXConstructExpr *construct = dyn_cast<CXXConstructExpr>(getter))
+ return (construct->getConstructor()->isTrivial());
+
+ // The constructor might require cleanups (in which case it's never
+ // trivial).
+ assert(isa<ExprWithCleanups>(getter));
+ return false;
+}
+
+void
+CodeGenFunction::generateObjCGetterBody(const ObjCImplementationDecl *classImpl,
+ const ObjCPropertyImplDecl *propImpl) {
+ // If there's a non-trivial 'get' expression, we just have to emit that.
+ if (!hasTrivialGetExpr(propImpl)) {
+ ReturnStmt ret(SourceLocation(), propImpl->getGetterCXXConstructor(),
+ /*nrvo*/ 0);
+ EmitReturnStmt(ret);
+ return;
+ }
+
+ const ObjCPropertyDecl *prop = propImpl->getPropertyDecl();
+ QualType propType = prop->getType();
+ ObjCMethodDecl *getterMethod = prop->getGetterMethodDecl();
+
+ ObjCIvarDecl *ivar = propImpl->getPropertyIvarDecl();
+
+ // Pick an implementation strategy.
+ PropertyImplStrategy strategy(CGM, propImpl);
+ switch (strategy.getKind()) {
+ case PropertyImplStrategy::Native: {
+ LValue LV = EmitLValueForIvar(TypeOfSelfObject(), LoadObjCSelf(), ivar, 0);
+
+ // Currently, all atomic accesses have to be through integer
+ // types, so there's no point in trying to pick a prettier type.
+ llvm::Type *bitcastType =
+ llvm::Type::getIntNTy(getLLVMContext(),
+ getContext().toBits(strategy.getIvarSize()));
+ bitcastType = bitcastType->getPointerTo(); // addrspace 0 okay
+
+ // Perform an atomic load. This does not impose ordering constraints.
+ llvm::Value *ivarAddr = LV.getAddress();
+ ivarAddr = Builder.CreateBitCast(ivarAddr, bitcastType);
+ llvm::LoadInst *load = Builder.CreateLoad(ivarAddr, "load");
+ load->setAlignment(strategy.getIvarAlignment().getQuantity());
+ load->setAtomic(llvm::Unordered);
+
+ // Store that value into the return address. Doing this with a
+ // bitcast is likely to produce some pretty ugly IR, but it's not
+ // the *most* terrible thing in the world.
+ Builder.CreateStore(load, Builder.CreateBitCast(ReturnValue, bitcastType));
+
+ // Make sure we don't do an autorelease.
+ AutoreleaseResult = false;
+ return;
+ }
+
+ case PropertyImplStrategy::GetSetProperty: {
+ llvm::Value *getPropertyFn =
+ CGM.getObjCRuntime().GetPropertyGetFunction();
+ if (!getPropertyFn) {
+ CGM.ErrorUnsupported(propImpl, "Obj-C getter requiring atomic copy");
return;
}
// Return (ivar-type) objc_getProperty((id) self, _cmd, offset, true).
// FIXME: Can't this be simpler? This might even be worse than the
// corresponding gcc code.
- CodeGenTypes &Types = CGM.getTypes();
- ValueDecl *Cmd = OMD->getCmdDecl();
- llvm::Value *CmdVal = Builder.CreateLoad(LocalDeclMap[Cmd], "cmd");
- QualType IdTy = getContext().getObjCIdType();
- llvm::Value *SelfAsId =
- Builder.CreateBitCast(LoadObjCSelf(), Types.ConvertType(IdTy));
- llvm::Value *Offset = EmitIvarOffset(IMP->getClassInterface(), Ivar);
- llvm::Value *True =
- llvm::ConstantInt::get(Types.ConvertType(getContext().BoolTy), 1);
- CallArgList Args;
- Args.add(RValue::get(SelfAsId), IdTy);
- Args.add(RValue::get(CmdVal), Cmd->getType());
- Args.add(RValue::get(Offset), getContext().getPointerDiffType());
- Args.add(RValue::get(True), getContext().BoolTy);
+ llvm::Value *cmd =
+ Builder.CreateLoad(LocalDeclMap[getterMethod->getCmdDecl()], "cmd");
+ llvm::Value *self = Builder.CreateBitCast(LoadObjCSelf(), VoidPtrTy);
+ llvm::Value *ivarOffset =
+ EmitIvarOffset(classImpl->getClassInterface(), ivar);
+
+ CallArgList args;
+ args.add(RValue::get(self), getContext().getObjCIdType());
+ args.add(RValue::get(cmd), getContext().getObjCSelType());
+ args.add(RValue::get(ivarOffset), getContext().getPointerDiffType());
+ args.add(RValue::get(Builder.getInt1(strategy.isAtomic())),
+ getContext().BoolTy);
+
// FIXME: We shouldn't need to get the function info here, the
// runtime already should have computed it to build the function.
- RValue RV = EmitCall(Types.getFunctionInfo(PD->getType(), Args,
- FunctionType::ExtInfo()),
- GetPropertyFn, ReturnValueSlot(), Args);
+ RValue RV = EmitCall(getTypes().getFunctionInfo(propType, args,
+ FunctionType::ExtInfo()),
+ getPropertyFn, ReturnValueSlot(), args);
+
// We need to fix the type here. Ivars with copy & retain are
// always objects so we don't need to worry about complex or
// aggregates.
RV = RValue::get(Builder.CreateBitCast(RV.getScalarVal(),
- Types.ConvertType(PD->getType())));
- EmitReturnOfRValue(RV, PD->getType());
+ getTypes().ConvertType(propType)));
+
+ EmitReturnOfRValue(RV, propType);
// objc_getProperty does an autorelease, so we should suppress ours.
AutoreleaseResult = false;
- } else {
- const llvm::Triple &Triple = getContext().Target.getTriple();
- QualType IVART = Ivar->getType();
- if (IsAtomic &&
- IVART->isScalarType() &&
- (Triple.getArch() == llvm::Triple::arm ||
- Triple.getArch() == llvm::Triple::thumb) &&
- (getContext().getTypeSizeInChars(IVART)
- > CharUnits::fromQuantity(4)) &&
- CGM.getObjCRuntime().GetGetStructFunction()) {
- GenerateObjCGetterBody(Ivar, true, false);
- }
- else if (IsAtomic &&
- (IVART->isScalarType() && !IVART->isRealFloatingType()) &&
- Triple.getArch() == llvm::Triple::x86 &&
- (getContext().getTypeSizeInChars(IVART)
- > CharUnits::fromQuantity(4)) &&
- CGM.getObjCRuntime().GetGetStructFunction()) {
- GenerateObjCGetterBody(Ivar, true, false);
- }
- else if (IsAtomic &&
- (IVART->isScalarType() && !IVART->isRealFloatingType()) &&
- Triple.getArch() == llvm::Triple::x86_64 &&
- (getContext().getTypeSizeInChars(IVART)
- > CharUnits::fromQuantity(8)) &&
- CGM.getObjCRuntime().GetGetStructFunction()) {
- GenerateObjCGetterBody(Ivar, true, false);
- }
- else if (IVART->isAnyComplexType()) {
- LValue LV = EmitLValueForIvar(TypeOfSelfObject(), LoadObjCSelf(),
- Ivar, 0);
- ComplexPairTy Pair = LoadComplexFromAddr(LV.getAddress(),
+
+ return;
+ }
+
+ case PropertyImplStrategy::CopyStruct:
+ emitStructGetterCall(*this, ivar, strategy.isAtomic(),
+ strategy.hasStrongMember());
+ return;
+
+ case PropertyImplStrategy::Expression:
+ case PropertyImplStrategy::SetPropertyAndExpressionGet: {
+ LValue LV = EmitLValueForIvar(TypeOfSelfObject(), LoadObjCSelf(), ivar, 0);
+
+ QualType ivarType = ivar->getType();
+ if (ivarType->isAnyComplexType()) {
+ ComplexPairTy pair = LoadComplexFromAddr(LV.getAddress(),
LV.isVolatileQualified());
- StoreComplexToAddr(Pair, ReturnValue, LV.isVolatileQualified());
- }
- else if (hasAggregateLLVMType(IVART)) {
- bool IsStrong = false;
- if ((IsStrong = IvarTypeWithAggrGCObjects(IVART))
- && CurFnInfo->getReturnInfo().getKind() == ABIArgInfo::Indirect
- && CGM.getObjCRuntime().GetGetStructFunction()) {
- GenerateObjCGetterBody(Ivar, IsAtomic, IsStrong);
- }
- else {
- const CXXRecordDecl *classDecl = IVART->getAsCXXRecordDecl();
-
- if (PID->getGetterCXXConstructor() &&
- classDecl && !classDecl->hasTrivialDefaultConstructor()) {
- ReturnStmt *Stmt =
- new (getContext()) ReturnStmt(SourceLocation(),
- PID->getGetterCXXConstructor(),
- 0);
- EmitReturnStmt(*Stmt);
- } else if (IsAtomic &&
- !IVART->isAnyComplexType() &&
- Triple.getArch() == llvm::Triple::x86 &&
- (getContext().getTypeSizeInChars(IVART)
- > CharUnits::fromQuantity(4)) &&
- CGM.getObjCRuntime().GetGetStructFunction()) {
- GenerateObjCGetterBody(Ivar, true, false);
- }
- else if (IsAtomic &&
- !IVART->isAnyComplexType() &&
- Triple.getArch() == llvm::Triple::x86_64 &&
- (getContext().getTypeSizeInChars(IVART)
- > CharUnits::fromQuantity(8)) &&
- CGM.getObjCRuntime().GetGetStructFunction()) {
- GenerateObjCGetterBody(Ivar, true, false);
- }
- else {
- LValue LV = EmitLValueForIvar(TypeOfSelfObject(), LoadObjCSelf(),
- Ivar, 0);
- EmitAggregateCopy(ReturnValue, LV.getAddress(), IVART);
- }
- }
- }
- else {
- LValue LV = EmitLValueForIvar(TypeOfSelfObject(), LoadObjCSelf(),
- Ivar, 0);
- QualType propType = PD->getType();
-
- llvm::Value *value;
- if (propType->isReferenceType()) {
- value = LV.getAddress();
+ StoreComplexToAddr(pair, ReturnValue, LV.isVolatileQualified());
+ } else if (hasAggregateLLVMType(ivarType)) {
+ // The return value slot is guaranteed to not be aliased, but
+ // that's not necessarily the same as "on the stack", so
+ // we still potentially need objc_memmove_collectable.
+ EmitAggregateCopy(ReturnValue, LV.getAddress(), ivarType);
+ } else {
+ llvm::Value *value;
+ if (propType->isReferenceType()) {
+ value = LV.getAddress();
+ } else {
+ // We want to load and autoreleaseReturnValue ARC __weak ivars.
+ if (LV.getQuals().getObjCLifetime() == Qualifiers::OCL_Weak) {
+ value = emitARCRetainLoadOfScalar(*this, LV, ivarType);
+
+ // Otherwise we want to do a simple load, suppressing the
+ // final autorelease.
} else {
- // In ARC, we want to emit this retained.
- if (getLangOptions().ObjCAutoRefCount &&
- PD->getType()->isObjCRetainableType())
- value = emitARCRetainLoadOfScalar(*this, LV, IVART);
- else
- value = EmitLoadOfLValue(LV).getScalarVal();
-
- value = Builder.CreateBitCast(value, ConvertType(propType));
+ value = EmitLoadOfLValue(LV).getScalarVal();
+ AutoreleaseResult = false;
}
- EmitReturnOfRValue(RValue::get(value), propType);
+ value = Builder.CreateBitCast(value, ConvertType(propType));
+ }
+
+ EmitReturnOfRValue(RValue::get(value), propType);
}
+ return;
}
- FinishFunction();
+ }
+ llvm_unreachable("bad @property implementation strategy!");
}
-void CodeGenFunction::GenerateObjCAtomicSetterBody(ObjCMethodDecl *OMD,
- ObjCIvarDecl *Ivar) {
+/// emitStructSetterCall - Call the runtime function to store the value
+/// from the first formal parameter into the given ivar.
+static void emitStructSetterCall(CodeGenFunction &CGF, ObjCMethodDecl *OMD,
+ ObjCIvarDecl *ivar) {
// objc_copyStruct (&structIvar, &Arg,
// sizeof (struct something), true, false);
- llvm::Value *GetCopyStructFn =
- CGM.getObjCRuntime().GetSetStructFunction();
- CodeGenTypes &Types = CGM.getTypes();
- CallArgList Args;
- LValue LV = EmitLValueForIvar(TypeOfSelfObject(), LoadObjCSelf(), Ivar, 0);
- RValue RV =
- RValue::get(Builder.CreateBitCast(LV.getAddress(),
- Types.ConvertType(getContext().VoidPtrTy)));
- Args.add(RV, getContext().VoidPtrTy);
- llvm::Value *Arg = LocalDeclMap[*OMD->param_begin()];
- llvm::Value *ArgAsPtrTy =
- Builder.CreateBitCast(Arg,
- Types.ConvertType(getContext().VoidPtrTy));
- RV = RValue::get(ArgAsPtrTy);
- Args.add(RV, getContext().VoidPtrTy);
- // sizeof (Type of Ivar)
- CharUnits Size = getContext().getTypeSizeInChars(Ivar->getType());
- llvm::Value *SizeVal =
- llvm::ConstantInt::get(Types.ConvertType(getContext().LongTy),
- Size.getQuantity());
- Args.add(RValue::get(SizeVal), getContext().LongTy);
- llvm::Value *True =
- llvm::ConstantInt::get(Types.ConvertType(getContext().BoolTy), 1);
- Args.add(RValue::get(True), getContext().BoolTy);
- llvm::Value *False =
- llvm::ConstantInt::get(Types.ConvertType(getContext().BoolTy), 0);
- Args.add(RValue::get(False), getContext().BoolTy);
- EmitCall(Types.getFunctionInfo(getContext().VoidTy, Args,
- FunctionType::ExtInfo()),
- GetCopyStructFn, ReturnValueSlot(), Args);
+ CallArgList args;
+
+ // The first argument is the address of the ivar.
+ llvm::Value *ivarAddr = CGF.EmitLValueForIvar(CGF.TypeOfSelfObject(),
+ CGF.LoadObjCSelf(), ivar, 0)
+ .getAddress();
+ ivarAddr = CGF.Builder.CreateBitCast(ivarAddr, CGF.Int8PtrTy);
+ args.add(RValue::get(ivarAddr), CGF.getContext().VoidPtrTy);
+
+ // The second argument is the address of the parameter variable.
+ ParmVarDecl *argVar = *OMD->param_begin();
+ DeclRefExpr argRef(argVar, argVar->getType(), VK_LValue, SourceLocation());
+ llvm::Value *argAddr = CGF.EmitLValue(&argRef).getAddress();
+ argAddr = CGF.Builder.CreateBitCast(argAddr, CGF.Int8PtrTy);
+ args.add(RValue::get(argAddr), CGF.getContext().VoidPtrTy);
+
+ // The third argument is the sizeof the type.
+ llvm::Value *size =
+ CGF.CGM.getSize(CGF.getContext().getTypeSizeInChars(ivar->getType()));
+ args.add(RValue::get(size), CGF.getContext().getSizeType());
+
+ // The fourth argument is the 'isAtomic' flag.
+ args.add(RValue::get(CGF.Builder.getTrue()), CGF.getContext().BoolTy);
+
+ // The fifth argument is the 'hasStrong' flag.
+ // FIXME: should this really always be false?
+ args.add(RValue::get(CGF.Builder.getFalse()), CGF.getContext().BoolTy);
+
+ llvm::Value *copyStructFn = CGF.CGM.getObjCRuntime().GetSetStructFunction();
+ CGF.EmitCall(CGF.getTypes().getFunctionInfo(CGF.getContext().VoidTy, args,
+ FunctionType::ExtInfo()),
+ copyStructFn, ReturnValueSlot(), args);
+}
+
+static bool hasTrivialSetExpr(const ObjCPropertyImplDecl *PID) {
+ Expr *setter = PID->getSetterCXXAssignment();
+ if (!setter) return true;
+
+ // Sema only makes only of these when the ivar has a C++ class type,
+ // so the form is pretty constrained.
+
+ // An operator call is trivial if the function it calls is trivial.
+ // This also implies that there's nothing non-trivial going on with
+ // the arguments, because operator= can only be trivial if it's a
+ // synthesized assignment operator and therefore both parameters are
+ // references.
+ if (CallExpr *call = dyn_cast<CallExpr>(setter)) {
+ if (const FunctionDecl *callee
+ = dyn_cast_or_null<FunctionDecl>(call->getCalleeDecl()))
+ if (callee->isTrivial())
+ return true;
+ return false;
+ }
+
+ assert(isa<ExprWithCleanups>(setter));
+ return false;
}
-static bool
-IvarAssignHasTrvialAssignment(const ObjCPropertyImplDecl *PID,
- QualType IvarT) {
- bool HasTrvialAssignment = true;
- if (PID->getSetterCXXAssignment()) {
- const CXXRecordDecl *classDecl = IvarT->getAsCXXRecordDecl();
- HasTrvialAssignment =
- (!classDecl || classDecl->hasTrivialCopyAssignment());
+void
+CodeGenFunction::generateObjCSetterBody(const ObjCImplementationDecl *classImpl,
+ const ObjCPropertyImplDecl *propImpl) {
+ // Just use the setter expression if Sema gave us one and it's
+ // non-trivial. There's no way to do this atomically.
+ if (!hasTrivialSetExpr(propImpl)) {
+ EmitStmt(propImpl->getSetterCXXAssignment());
+ return;
+ }
+
+ const ObjCPropertyDecl *prop = propImpl->getPropertyDecl();
+ ObjCIvarDecl *ivar = propImpl->getPropertyIvarDecl();
+ ObjCMethodDecl *setterMethod = prop->getSetterMethodDecl();
+
+ PropertyImplStrategy strategy(CGM, propImpl);
+ switch (strategy.getKind()) {
+ case PropertyImplStrategy::Native: {
+ llvm::Value *argAddr = LocalDeclMap[*setterMethod->param_begin()];
+
+ LValue ivarLValue =
+ EmitLValueForIvar(TypeOfSelfObject(), LoadObjCSelf(), ivar, /*quals*/ 0);
+ llvm::Value *ivarAddr = ivarLValue.getAddress();
+
+ // Currently, all atomic accesses have to be through integer
+ // types, so there's no point in trying to pick a prettier type.
+ llvm::Type *bitcastType =
+ llvm::Type::getIntNTy(getLLVMContext(),
+ getContext().toBits(strategy.getIvarSize()));
+ bitcastType = bitcastType->getPointerTo(); // addrspace 0 okay
+
+ // Cast both arguments to the chosen operation type.
+ argAddr = Builder.CreateBitCast(argAddr, bitcastType);
+ ivarAddr = Builder.CreateBitCast(ivarAddr, bitcastType);
+
+ // This bitcast load is likely to cause some nasty IR.
+ llvm::Value *load = Builder.CreateLoad(argAddr);
+
+ // Perform an atomic store. There are no memory ordering requirements.
+ llvm::StoreInst *store = Builder.CreateStore(load, ivarAddr);
+ store->setAlignment(strategy.getIvarAlignment().getQuantity());
+ store->setAtomic(llvm::Unordered);
+ return;
+ }
+
+ case PropertyImplStrategy::GetSetProperty:
+ case PropertyImplStrategy::SetPropertyAndExpressionGet: {
+ llvm::Value *setPropertyFn =
+ CGM.getObjCRuntime().GetPropertySetFunction();
+ if (!setPropertyFn) {
+ CGM.ErrorUnsupported(propImpl, "Obj-C setter requiring atomic copy");
+ return;
+ }
+
+ // Emit objc_setProperty((id) self, _cmd, offset, arg,
+ // <is-atomic>, <is-copy>).
+ llvm::Value *cmd =
+ Builder.CreateLoad(LocalDeclMap[setterMethod->getCmdDecl()]);
+ llvm::Value *self =
+ Builder.CreateBitCast(LoadObjCSelf(), VoidPtrTy);
+ llvm::Value *ivarOffset =
+ EmitIvarOffset(classImpl->getClassInterface(), ivar);
+ llvm::Value *arg = LocalDeclMap[*setterMethod->param_begin()];
+ arg = Builder.CreateBitCast(Builder.CreateLoad(arg, "arg"), VoidPtrTy);
+
+ CallArgList args;
+ args.add(RValue::get(self), getContext().getObjCIdType());
+ args.add(RValue::get(cmd), getContext().getObjCSelType());
+ args.add(RValue::get(ivarOffset), getContext().getPointerDiffType());
+ args.add(RValue::get(arg), getContext().getObjCIdType());
+ args.add(RValue::get(Builder.getInt1(strategy.isAtomic())),
+ getContext().BoolTy);
+ args.add(RValue::get(Builder.getInt1(strategy.isCopy())),
+ getContext().BoolTy);
+ // FIXME: We shouldn't need to get the function info here, the runtime
+ // already should have computed it to build the function.
+ EmitCall(getTypes().getFunctionInfo(getContext().VoidTy, args,
+ FunctionType::ExtInfo()),
+ setPropertyFn, ReturnValueSlot(), args);
+ return;
+ }
+
+ case PropertyImplStrategy::CopyStruct:
+ emitStructSetterCall(*this, setterMethod, ivar);
+ return;
+
+ case PropertyImplStrategy::Expression:
+ break;
+ }
+
+ // Otherwise, fake up some ASTs and emit a normal assignment.
+ ValueDecl *selfDecl = setterMethod->getSelfDecl();
+ DeclRefExpr self(selfDecl, selfDecl->getType(), VK_LValue, SourceLocation());
+ ImplicitCastExpr selfLoad(ImplicitCastExpr::OnStack,
+ selfDecl->getType(), CK_LValueToRValue, &self,
+ VK_RValue);
+ ObjCIvarRefExpr ivarRef(ivar, ivar->getType().getNonReferenceType(),
+ SourceLocation(), &selfLoad, true, true);
+
+ ParmVarDecl *argDecl = *setterMethod->param_begin();
+ QualType argType = argDecl->getType().getNonReferenceType();
+ DeclRefExpr arg(argDecl, argType, VK_LValue, SourceLocation());
+ ImplicitCastExpr argLoad(ImplicitCastExpr::OnStack,
+ argType.getUnqualifiedType(), CK_LValueToRValue,
+ &arg, VK_RValue);
+
+ // The property type can differ from the ivar type in some situations with
+ // Objective-C pointer types, we can always bit cast the RHS in these cases.
+ // The following absurdity is just to ensure well-formed IR.
+ CastKind argCK = CK_NoOp;
+ if (ivarRef.getType()->isObjCObjectPointerType()) {
+ if (argLoad.getType()->isObjCObjectPointerType())
+ argCK = CK_BitCast;
+ else if (argLoad.getType()->isBlockPointerType())
+ argCK = CK_BlockPointerToObjCPointerCast;
+ else
+ argCK = CK_CPointerToObjCPointerCast;
+ } else if (ivarRef.getType()->isBlockPointerType()) {
+ if (argLoad.getType()->isBlockPointerType())
+ argCK = CK_BitCast;
+ else
+ argCK = CK_AnyPointerToBlockPointerCast;
+ } else if (ivarRef.getType()->isPointerType()) {
+ argCK = CK_BitCast;
}
- return HasTrvialAssignment;
+ ImplicitCastExpr argCast(ImplicitCastExpr::OnStack,
+ ivarRef.getType(), argCK, &argLoad,
+ VK_RValue);
+ Expr *finalArg = &argLoad;
+ if (!getContext().hasSameUnqualifiedType(ivarRef.getType(),
+ argLoad.getType()))
+ finalArg = &argCast;
+
+
+ BinaryOperator assign(&ivarRef, finalArg, BO_Assign,
+ ivarRef.getType(), VK_RValue, OK_Ordinary,
+ SourceLocation());
+ EmitStmt(&assign);
}
/// GenerateObjCSetter - Generate an Objective-C property setter
@@ -545,136 +943,12 @@ IvarAssignHasTrvialAssignment(const ObjCPropertyImplDecl *PID,
/// is illegal within a category.
void CodeGenFunction::GenerateObjCSetter(ObjCImplementationDecl *IMP,
const ObjCPropertyImplDecl *PID) {
- ObjCIvarDecl *Ivar = PID->getPropertyIvarDecl();
const ObjCPropertyDecl *PD = PID->getPropertyDecl();
ObjCMethodDecl *OMD = PD->getSetterMethodDecl();
assert(OMD && "Invalid call to generate setter (empty method)");
StartObjCMethod(OMD, IMP->getClassInterface(), PID->getLocStart());
- const llvm::Triple &Triple = getContext().Target.getTriple();
- QualType IVART = Ivar->getType();
- bool IsCopy = PD->getSetterKind() == ObjCPropertyDecl::Copy;
- bool IsAtomic =
- !(PD->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_nonatomic);
-
- // Determine if we should use an objc_setProperty call for
- // this. Properties with 'copy' semantics always use it, as do
- // non-atomic properties with 'release' semantics as long as we are
- // not in gc-only mode.
- if (IsCopy ||
- (CGM.getLangOptions().getGCMode() != LangOptions::GCOnly &&
- PD->getSetterKind() == ObjCPropertyDecl::Retain)) {
- llvm::Value *SetPropertyFn =
- CGM.getObjCRuntime().GetPropertySetFunction();
-
- if (!SetPropertyFn) {
- CGM.ErrorUnsupported(PID, "Obj-C getter requiring atomic copy");
- FinishFunction();
- return;
- }
- // Emit objc_setProperty((id) self, _cmd, offset, arg,
- // <is-atomic>, <is-copy>).
- // FIXME: Can't this be simpler? This might even be worse than the
- // corresponding gcc code.
- CodeGenTypes &Types = CGM.getTypes();
- ValueDecl *Cmd = OMD->getCmdDecl();
- llvm::Value *CmdVal = Builder.CreateLoad(LocalDeclMap[Cmd], "cmd");
- QualType IdTy = getContext().getObjCIdType();
- llvm::Value *SelfAsId =
- Builder.CreateBitCast(LoadObjCSelf(), Types.ConvertType(IdTy));
- llvm::Value *Offset = EmitIvarOffset(IMP->getClassInterface(), Ivar);
- llvm::Value *Arg = LocalDeclMap[*OMD->param_begin()];
- llvm::Value *ArgAsId =
- Builder.CreateBitCast(Builder.CreateLoad(Arg, "arg"),
- Types.ConvertType(IdTy));
- llvm::Value *True =
- llvm::ConstantInt::get(Types.ConvertType(getContext().BoolTy), 1);
- llvm::Value *False =
- llvm::ConstantInt::get(Types.ConvertType(getContext().BoolTy), 0);
- CallArgList Args;
- Args.add(RValue::get(SelfAsId), IdTy);
- Args.add(RValue::get(CmdVal), Cmd->getType());
- Args.add(RValue::get(Offset), getContext().getPointerDiffType());
- Args.add(RValue::get(ArgAsId), IdTy);
- Args.add(RValue::get(IsAtomic ? True : False), getContext().BoolTy);
- Args.add(RValue::get(IsCopy ? True : False), getContext().BoolTy);
- // FIXME: We shouldn't need to get the function info here, the runtime
- // already should have computed it to build the function.
- EmitCall(Types.getFunctionInfo(getContext().VoidTy, Args,
- FunctionType::ExtInfo()),
- SetPropertyFn,
- ReturnValueSlot(), Args);
- } else if (IsAtomic && hasAggregateLLVMType(IVART) &&
- !IVART->isAnyComplexType() &&
- IvarAssignHasTrvialAssignment(PID, IVART) &&
- ((Triple.getArch() == llvm::Triple::x86 &&
- (getContext().getTypeSizeInChars(IVART)
- > CharUnits::fromQuantity(4))) ||
- (Triple.getArch() == llvm::Triple::x86_64 &&
- (getContext().getTypeSizeInChars(IVART)
- > CharUnits::fromQuantity(8))))
- && CGM.getObjCRuntime().GetSetStructFunction()) {
- // objc_copyStruct (&structIvar, &Arg,
- // sizeof (struct something), true, false);
- GenerateObjCAtomicSetterBody(OMD, Ivar);
- } else if (PID->getSetterCXXAssignment()) {
- EmitIgnoredExpr(PID->getSetterCXXAssignment());
- } else {
- if (IsAtomic &&
- IVART->isScalarType() &&
- (Triple.getArch() == llvm::Triple::arm ||
- Triple.getArch() == llvm::Triple::thumb) &&
- (getContext().getTypeSizeInChars(IVART)
- > CharUnits::fromQuantity(4)) &&
- CGM.getObjCRuntime().GetGetStructFunction()) {
- GenerateObjCAtomicSetterBody(OMD, Ivar);
- }
- else if (IsAtomic &&
- (IVART->isScalarType() && !IVART->isRealFloatingType()) &&
- Triple.getArch() == llvm::Triple::x86 &&
- (getContext().getTypeSizeInChars(IVART)
- > CharUnits::fromQuantity(4)) &&
- CGM.getObjCRuntime().GetGetStructFunction()) {
- GenerateObjCAtomicSetterBody(OMD, Ivar);
- }
- else if (IsAtomic &&
- (IVART->isScalarType() && !IVART->isRealFloatingType()) &&
- Triple.getArch() == llvm::Triple::x86_64 &&
- (getContext().getTypeSizeInChars(IVART)
- > CharUnits::fromQuantity(8)) &&
- CGM.getObjCRuntime().GetGetStructFunction()) {
- GenerateObjCAtomicSetterBody(OMD, Ivar);
- }
- else {
- // FIXME: Find a clean way to avoid AST node creation.
- SourceLocation Loc = PID->getLocStart();
- ValueDecl *Self = OMD->getSelfDecl();
- ObjCIvarDecl *Ivar = PID->getPropertyIvarDecl();
- DeclRefExpr Base(Self, Self->getType(), VK_RValue, Loc);
- ParmVarDecl *ArgDecl = *OMD->param_begin();
- QualType T = ArgDecl->getType();
- if (T->isReferenceType())
- T = cast<ReferenceType>(T)->getPointeeType();
- DeclRefExpr Arg(ArgDecl, T, VK_LValue, Loc);
- ObjCIvarRefExpr IvarRef(Ivar, Ivar->getType(), Loc, &Base, true, true);
-
- // The property type can differ from the ivar type in some situations with
- // Objective-C pointer types, we can always bit cast the RHS in these cases.
- if (getContext().getCanonicalType(Ivar->getType()) !=
- getContext().getCanonicalType(ArgDecl->getType())) {
- ImplicitCastExpr ArgCasted(ImplicitCastExpr::OnStack,
- Ivar->getType(), CK_BitCast, &Arg,
- VK_RValue);
- BinaryOperator Assign(&IvarRef, &ArgCasted, BO_Assign,
- Ivar->getType(), VK_RValue, OK_Ordinary, Loc);
- EmitStmt(&Assign);
- } else {
- BinaryOperator Assign(&IvarRef, &Arg, BO_Assign,
- Ivar->getType(), VK_RValue, OK_Ordinary, Loc);
- EmitStmt(&Assign);
- }
- }
- }
+ generateObjCSetterBody(IMP, PID);
FinishFunction();
}
@@ -716,9 +990,8 @@ static void emitCXXDestructMethod(CodeGenFunction &CGF,
llvm::Value *self = CGF.LoadObjCSelf();
- ObjCInterfaceDecl *iface
- = const_cast<ObjCInterfaceDecl*>(impl->getClassInterface());
- for (ObjCIvarDecl *ivar = iface->all_declared_ivar_begin();
+ const ObjCInterfaceDecl *iface = impl->getClassInterface();
+ for (const ObjCIvarDecl *ivar = iface->all_declared_ivar_begin();
ivar; ivar = ivar->getNextIvar()) {
QualType type = ivar->getType();
@@ -758,7 +1031,7 @@ void CodeGenFunction::GenerateObjCCtorDtorMethod(ObjCImplementationDecl *IMP,
// Suppress the final autorelease in ARC.
AutoreleaseResult = false;
- llvm::SmallVector<CXXCtorInitializer *, 8> IvarInitializers;
+ SmallVector<CXXCtorInitializer *, 8> IvarInitializers;
for (ObjCImplementationDecl::init_const_iterator B = IMP->init_begin(),
E = IMP->init_end(); B != E; ++B) {
CXXCtorInitializer *IvarInit = (*B);
@@ -766,7 +1039,10 @@ void CodeGenFunction::GenerateObjCCtorDtorMethod(ObjCImplementationDecl *IMP,
ObjCIvarDecl *Ivar = cast<ObjCIvarDecl>(Field);
LValue LV = EmitLValueForIvar(TypeOfSelfObject(),
LoadObjCSelf(), Ivar, 0);
- EmitAggExpr(IvarInit->getInit(), AggValueSlot::forLValue(LV, true));
+ EmitAggExpr(IvarInit->getInit(),
+ AggValueSlot::forLValue(LV, AggValueSlot::IsDestructed,
+ AggValueSlot::DoesNotNeedGCBarriers,
+ AggValueSlot::IsNotAliased));
}
// constructor returns 'self'.
CodeGenTypes &Types = CGM.getTypes();
@@ -791,7 +1067,7 @@ bool CodeGenFunction::IndirectObjCSetterArg(const CGFunctionInfo &FI) {
}
bool CodeGenFunction::IvarTypeWithAggrGCObjects(QualType Ty) {
- if (CGM.getLangOptions().getGCMode() == LangOptions::NonGC)
+ if (CGM.getLangOptions().getGC() == LangOptions::NonGC)
return false;
if (const RecordType *FDTTy = Ty.getTypePtr()->getAs<RecordType>())
return FDTTy->getDecl()->hasObjectMember();
@@ -896,7 +1172,7 @@ void CodeGenFunction::EmitStoreThroughPropertyRefLValue(RValue Src,
if (Src.isScalar()) {
llvm::Value *SrcVal = Src.getScalarVal();
QualType DstType = getContext().getCanonicalType(ArgType);
- const llvm::Type *DstTy = ConvertType(DstType);
+ llvm::Type *DstTy = ConvertType(DstType);
if (SrcVal->getType() != DstTy)
Src =
RValue::get(EmitScalarConversion(SrcVal, E->getType(), DstType));
@@ -932,10 +1208,8 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){
}
CGDebugInfo *DI = getDebugInfo();
- if (DI) {
- DI->setLocation(S.getSourceRange().getBegin());
- DI->EmitRegionStart(Builder);
- }
+ if (DI)
+ DI->EmitLexicalBlockStart(Builder, S.getSourceRange().getBegin());
// The local variable comes into scope immediately.
AutoVarEmission variable = AutoVarEmission::invalid();
@@ -943,10 +1217,9 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){
variable = EmitAutoVarAlloca(*cast<VarDecl>(SD->getSingleDecl()));
JumpDest LoopEnd = getJumpDestInCurrentScope("forcoll.end");
- JumpDest AfterBody = getJumpDestInCurrentScope("forcoll.next");
// Fast enumeration state.
- QualType StateTy = getContext().getObjCFastEnumerationStateType();
+ QualType StateTy = CGM.getObjCFastEnumerationStateType();
llvm::Value *StatePtr = CreateMemTemp(StateTy, "state.ptr");
EmitNullInitialization(StatePtr, StateTy);
@@ -968,8 +1241,20 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){
ArrayType::Normal, 0);
llvm::Value *ItemsPtr = CreateMemTemp(ItemsTy, "items.ptr");
- // Emit the collection pointer.
- llvm::Value *Collection = EmitScalarExpr(S.getCollection());
+ // Emit the collection pointer. In ARC, we do a retain.
+ llvm::Value *Collection;
+ if (getLangOptions().ObjCAutoRefCount) {
+ Collection = EmitARCRetainScalarExpr(S.getCollection());
+
+ // Enter a cleanup to do the release.
+ EmitObjCConsumeObject(S.getCollection()->getType(), Collection);
+ } else {
+ Collection = EmitScalarExpr(S.getCollection());
+ }
+
+ // The 'continue' label needs to appear within the cleanup for the
+ // collection object.
+ JumpDest AfterBody = getJumpDestInCurrentScope("forcoll.next");
// Send it our message:
CallArgList Args;
@@ -985,7 +1270,7 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){
Args.add(RValue::get(ItemsPtr), getContext().getPointerType(ItemsTy));
// The third argument is the capacity of that temporary array.
- const llvm::Type *UnsignedLongLTy = ConvertType(getContext().UnsignedLongTy);
+ llvm::Type *UnsignedLongLTy = ConvertType(getContext().UnsignedLongTy);
llvm::Constant *Count = llvm::ConstantInt::get(UnsignedLongLTy, NumItems);
Args.add(RValue::get(Count), getContext().UnsignedLongTy);
@@ -1053,8 +1338,7 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){
EmitBlock(WasMutatedBB);
llvm::Value *V =
Builder.CreateBitCast(Collection,
- ConvertType(getContext().getObjCIdType()),
- "tmp");
+ ConvertType(getContext().getObjCIdType()));
CallArgList Args2;
Args2.add(RValue::get(V), getContext().getObjCIdType());
// FIXME: We shouldn't need to get the function info here, the runtime already
@@ -1089,7 +1373,7 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){
elementType = cast<Expr>(S.getElement())->getType();
elementIsVariable = false;
}
- const llvm::Type *convertedElementType = ConvertType(elementType);
+ llvm::Type *convertedElementType = ConvertType(elementType);
// Fetch the buffer out of the enumeration state.
// TODO: this pointer should actually be invariant between
@@ -1179,10 +1463,12 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){
EmitStoreThroughLValue(RValue::get(null), elementLValue);
}
- if (DI) {
- DI->setLocation(S.getSourceRange().getEnd());
- DI->EmitRegionEnd(Builder);
- }
+ if (DI)
+ DI->EmitLexicalBlockEnd(Builder, S.getSourceRange().getEnd());
+
+ // Leave the cleanup we entered in ARC.
+ if (getLangOptions().ObjCAutoRefCount)
+ PopCleanupBlock();
EmitBlock(LoopEnd.getBlock());
}
@@ -1200,7 +1486,7 @@ void CodeGenFunction::EmitObjCAtSynchronizedStmt(
CGM.getObjCRuntime().EmitSynchronizedStmt(*this, S);
}
-/// Produce the code for a CK_ObjCProduceObject. Just does a
+/// Produce the code for a CK_ARCProduceObject. Just does a
/// primitive retain.
llvm::Value *CodeGenFunction::EmitObjCProduceObject(QualType type,
llvm::Value *value) {
@@ -1209,63 +1495,22 @@ llvm::Value *CodeGenFunction::EmitObjCProduceObject(QualType type,
namespace {
struct CallObjCRelease : EHScopeStack::Cleanup {
- CallObjCRelease(QualType type, llvm::Value *ptr, llvm::Value *condition)
- : type(type), ptr(ptr), condition(condition) {}
- QualType type;
- llvm::Value *ptr;
- llvm::Value *condition;
+ CallObjCRelease(llvm::Value *object) : object(object) {}
+ llvm::Value *object;
void Emit(CodeGenFunction &CGF, Flags flags) {
- llvm::Value *object;
-
- // If we're in a conditional branch, we had to stash away in an
- // alloca the pointer to be released.
- llvm::BasicBlock *cont = 0;
- if (condition) {
- llvm::BasicBlock *release = CGF.createBasicBlock("release.yes");
- cont = CGF.createBasicBlock("release.cont");
-
- llvm::Value *cond = CGF.Builder.CreateLoad(condition);
- CGF.Builder.CreateCondBr(cond, release, cont);
- CGF.EmitBlock(release);
- object = CGF.Builder.CreateLoad(ptr);
- } else {
- object = ptr;
- }
-
CGF.EmitARCRelease(object, /*precise*/ true);
-
- if (cont) CGF.EmitBlock(cont);
}
};
}
-/// Produce the code for a CK_ObjCConsumeObject. Does a primitive
+/// Produce the code for a CK_ARCConsumeObject. Does a primitive
/// release at the end of the full-expression.
llvm::Value *CodeGenFunction::EmitObjCConsumeObject(QualType type,
llvm::Value *object) {
// If we're in a conditional branch, we need to make the cleanup
- // conditional. FIXME: this really needs to be supported by the
- // environment.
- llvm::AllocaInst *cond;
- llvm::Value *ptr;
- if (isInConditionalBranch()) {
- cond = CreateTempAlloca(Builder.getInt1Ty(), "release.cond");
- ptr = CreateTempAlloca(object->getType(), "release.value");
-
- // The alloca is false until we get here.
- // FIXME: er. doesn't this need to be set at the start of the condition?
- InitTempAlloca(cond, Builder.getFalse());
-
- // Then it turns true.
- Builder.CreateStore(Builder.getTrue(), cond);
- Builder.CreateStore(object, ptr);
- } else {
- cond = 0;
- ptr = object;
- }
-
- EHStack.pushCleanup<CallObjCRelease>(getARCCleanupKind(), type, ptr, cond);
+ // conditional.
+ pushFullExprCleanup<CallObjCRelease>(getARCCleanupKind(), object);
return object;
}
@@ -1276,8 +1521,8 @@ llvm::Value *CodeGenFunction::EmitObjCExtendObjectLifetime(QualType type,
static llvm::Constant *createARCRuntimeFunction(CodeGenModule &CGM,
- const llvm::FunctionType *type,
- llvm::StringRef fnName) {
+ llvm::FunctionType *type,
+ StringRef fnName) {
llvm::Constant *fn = CGM.CreateRuntimeFunction(type, fnName);
// In -fobjc-no-arc-runtime, emit weak references to the runtime
@@ -1295,18 +1540,18 @@ static llvm::Constant *createARCRuntimeFunction(CodeGenModule &CGM,
static llvm::Value *emitARCValueOperation(CodeGenFunction &CGF,
llvm::Value *value,
llvm::Constant *&fn,
- llvm::StringRef fnName) {
+ StringRef fnName) {
if (isa<llvm::ConstantPointerNull>(value)) return value;
if (!fn) {
std::vector<llvm::Type*> args(1, CGF.Int8PtrTy);
- const llvm::FunctionType *fnType =
+ llvm::FunctionType *fnType =
llvm::FunctionType::get(CGF.Int8PtrTy, args, false);
fn = createARCRuntimeFunction(CGF.CGM, fnType, fnName);
}
// Cast the argument to 'id'.
- const llvm::Type *origType = value->getType();
+ llvm::Type *origType = value->getType();
value = CGF.Builder.CreateBitCast(value, CGF.Int8PtrTy);
// Call the function.
@@ -1322,16 +1567,16 @@ static llvm::Value *emitARCValueOperation(CodeGenFunction &CGF,
static llvm::Value *emitARCLoadOperation(CodeGenFunction &CGF,
llvm::Value *addr,
llvm::Constant *&fn,
- llvm::StringRef fnName) {
+ StringRef fnName) {
if (!fn) {
std::vector<llvm::Type*> args(1, CGF.Int8PtrPtrTy);
- const llvm::FunctionType *fnType =
+ llvm::FunctionType *fnType =
llvm::FunctionType::get(CGF.Int8PtrTy, args, false);
fn = createARCRuntimeFunction(CGF.CGM, fnType, fnName);
}
// Cast the argument to 'id*'.
- const llvm::Type *origType = addr->getType();
+ llvm::Type *origType = addr->getType();
addr = CGF.Builder.CreateBitCast(addr, CGF.Int8PtrPtrTy);
// Call the function.
@@ -1353,7 +1598,7 @@ static llvm::Value *emitARCStoreOperation(CodeGenFunction &CGF,
llvm::Value *addr,
llvm::Value *value,
llvm::Constant *&fn,
- llvm::StringRef fnName,
+ StringRef fnName,
bool ignored) {
assert(cast<llvm::PointerType>(addr->getType())->getElementType()
== value->getType());
@@ -1363,12 +1608,12 @@ static llvm::Value *emitARCStoreOperation(CodeGenFunction &CGF,
argTypes[0] = CGF.Int8PtrPtrTy;
argTypes[1] = CGF.Int8PtrTy;
- const llvm::FunctionType *fnType
+ llvm::FunctionType *fnType
= llvm::FunctionType::get(CGF.Int8PtrTy, argTypes, false);
fn = createARCRuntimeFunction(CGF.CGM, fnType, fnName);
}
- const llvm::Type *origType = value->getType();
+ llvm::Type *origType = value->getType();
addr = CGF.Builder.CreateBitCast(addr, CGF.Int8PtrPtrTy);
value = CGF.Builder.CreateBitCast(value, CGF.Int8PtrTy);
@@ -1387,12 +1632,12 @@ static void emitARCCopyOperation(CodeGenFunction &CGF,
llvm::Value *dst,
llvm::Value *src,
llvm::Constant *&fn,
- llvm::StringRef fnName) {
+ StringRef fnName) {
assert(dst->getType() == src->getType());
if (!fn) {
std::vector<llvm::Type*> argTypes(2, CGF.Int8PtrPtrTy);
- const llvm::FunctionType *fnType
+ llvm::FunctionType *fnType
= llvm::FunctionType::get(CGF.Builder.getVoidTy(), argTypes, false);
fn = createARCRuntimeFunction(CGF.CGM, fnType, fnName);
}
@@ -1409,7 +1654,7 @@ static void emitARCCopyOperation(CodeGenFunction &CGF,
/// call i8* @objc_retainBlock(i8* %value)
llvm::Value *CodeGenFunction::EmitARCRetain(QualType type, llvm::Value *value) {
if (type->isBlockPointerType())
- return EmitARCRetainBlock(value);
+ return EmitARCRetainBlock(value, /*mandatory*/ false);
else
return EmitARCRetainNonBlock(value);
}
@@ -1424,10 +1669,32 @@ llvm::Value *CodeGenFunction::EmitARCRetainNonBlock(llvm::Value *value) {
/// Retain the given block, with _Block_copy semantics.
/// call i8* @objc_retainBlock(i8* %value)
-llvm::Value *CodeGenFunction::EmitARCRetainBlock(llvm::Value *value) {
- return emitARCValueOperation(*this, value,
- CGM.getARCEntrypoints().objc_retainBlock,
- "objc_retainBlock");
+///
+/// \param mandatory - If false, emit the call with metadata
+/// indicating that it's okay for the optimizer to eliminate this call
+/// if it can prove that the block never escapes except down the stack.
+llvm::Value *CodeGenFunction::EmitARCRetainBlock(llvm::Value *value,
+ bool mandatory) {
+ llvm::Value *result
+ = emitARCValueOperation(*this, value,
+ CGM.getARCEntrypoints().objc_retainBlock,
+ "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
+ // block doesn't escape, where being passed as an argument doesn't
+ // count as escaping.
+ if (!mandatory && isa<llvm::Instruction>(result)) {
+ llvm::CallInst *call
+ = cast<llvm::CallInst>(result->stripPointerCasts());
+ assert(call->getCalledValue() == CGM.getARCEntrypoints().objc_retainBlock);
+
+ SmallVector<llvm::Value*,1> args;
+ call->setMetadata("clang.arc.copy_on_escape",
+ llvm::MDNode::get(Builder.getContext(), args));
+ }
+
+ return result;
}
/// Retain the given object which is the result of a function call.
@@ -1442,7 +1709,7 @@ CodeGenFunction::EmitARCRetainAutoreleasedReturnValue(llvm::Value *value) {
llvm::InlineAsm *&marker
= CGM.getARCEntrypoints().retainAutoreleasedReturnValueMarker;
if (!marker) {
- llvm::StringRef assembly
+ StringRef assembly
= CGM.getTargetCodeGenInfo()
.getARCRetainAutoreleasedReturnValueMarker();
@@ -1468,8 +1735,7 @@ CodeGenFunction::EmitARCRetainAutoreleasedReturnValue(llvm::Value *value) {
assert(metadata->getNumOperands() <= 1);
if (metadata->getNumOperands() == 0) {
llvm::Value *string = llvm::MDString::get(getLLVMContext(), assembly);
- llvm::Value *args[] = { string };
- metadata->addOperand(llvm::MDNode::get(getLLVMContext(), args));
+ metadata->addOperand(llvm::MDNode::get(getLLVMContext(), string));
}
}
}
@@ -1490,7 +1756,7 @@ void CodeGenFunction::EmitARCRelease(llvm::Value *value, bool precise) {
llvm::Constant *&fn = CGM.getARCEntrypoints().objc_release;
if (!fn) {
std::vector<llvm::Type*> args(1, Int8PtrTy);
- const llvm::FunctionType *fnType =
+ llvm::FunctionType *fnType =
llvm::FunctionType::get(Builder.getVoidTy(), args, false);
fn = createARCRuntimeFunction(CGM, fnType, "objc_release");
}
@@ -1503,7 +1769,7 @@ void CodeGenFunction::EmitARCRelease(llvm::Value *value, bool precise) {
call->setDoesNotThrow();
if (!precise) {
- llvm::SmallVector<llvm::Value*,1> args;
+ SmallVector<llvm::Value*,1> args;
call->setMetadata("clang.imprecise_release",
llvm::MDNode::get(Builder.getContext(), args));
}
@@ -1520,7 +1786,7 @@ llvm::Value *CodeGenFunction::EmitARCStoreStrongCall(llvm::Value *addr,
llvm::Constant *&fn = CGM.getARCEntrypoints().objc_storeStrong;
if (!fn) {
llvm::Type *argTypes[] = { Int8PtrPtrTy, Int8PtrTy };
- const llvm::FunctionType *fnType
+ llvm::FunctionType *fnType
= llvm::FunctionType::get(Builder.getVoidTy(), argTypes, false);
fn = createARCRuntimeFunction(CGM, fnType, "objc_storeStrong");
}
@@ -1607,9 +1873,9 @@ llvm::Value *CodeGenFunction::EmitARCRetainAutorelease(QualType type,
if (isa<llvm::ConstantPointerNull>(value)) return value;
- const llvm::Type *origType = value->getType();
+ llvm::Type *origType = value->getType();
value = Builder.CreateBitCast(value, Int8PtrTy);
- value = EmitARCRetainBlock(value);
+ value = EmitARCRetainBlock(value, /*mandatory*/ true);
value = EmitARCAutorelease(value);
return Builder.CreateBitCast(value, origType);
}
@@ -1674,7 +1940,7 @@ void CodeGenFunction::EmitARCDestroyWeak(llvm::Value *addr) {
llvm::Constant *&fn = CGM.getARCEntrypoints().objc_destroyWeak;
if (!fn) {
std::vector<llvm::Type*> args(1, Int8PtrPtrTy);
- const llvm::FunctionType *fnType =
+ llvm::FunctionType *fnType =
llvm::FunctionType::get(Builder.getVoidTy(), args, false);
fn = createARCRuntimeFunction(CGM, fnType, "objc_destroyWeak");
}
@@ -1709,7 +1975,7 @@ void CodeGenFunction::EmitARCCopyWeak(llvm::Value *dst, llvm::Value *src) {
llvm::Value *CodeGenFunction::EmitObjCAutoreleasePoolPush() {
llvm::Constant *&fn = CGM.getRREntrypoints().objc_autoreleasePoolPush;
if (!fn) {
- const llvm::FunctionType *fnType =
+ llvm::FunctionType *fnType =
llvm::FunctionType::get(Int8PtrTy, false);
fn = createARCRuntimeFunction(CGM, fnType, "objc_autoreleasePoolPush");
}
@@ -1728,7 +1994,7 @@ void CodeGenFunction::EmitObjCAutoreleasePoolPop(llvm::Value *value) {
llvm::Constant *&fn = CGM.getRREntrypoints().objc_autoreleasePoolPop;
if (!fn) {
std::vector<llvm::Type*> args(1, Int8PtrTy);
- const llvm::FunctionType *fnType =
+ llvm::FunctionType *fnType =
llvm::FunctionType::get(Builder.getVoidTy(), args, false);
// We don't want to use a weak import here; instead we should not
@@ -1851,6 +2117,24 @@ static TryEmitResult tryEmitARCRetainLoadOfScalar(CodeGenFunction &CGF,
e = e->IgnoreParens();
QualType type = e->getType();
+ // If we're loading retained from a __strong xvalue, we can avoid
+ // an extra retain/release pair by zeroing out the source of this
+ // "move" operation.
+ if (e->isXValue() &&
+ !type.isConstQualified() &&
+ type.getObjCLifetime() == Qualifiers::OCL_Strong) {
+ // Emit the lvalue.
+ LValue lv = CGF.EmitLValue(e);
+
+ // Load the object pointer.
+ llvm::Value *result = CGF.EmitLoadOfLValue(lv).getScalarVal();
+
+ // Set the source pointer to NULL.
+ CGF.EmitStoreOfScalar(getNullForVariable(lv.getAddress()), lv);
+
+ return TryEmitResult(result, true);
+ }
+
// As a very special optimization, in ARC++, if the l-value is the
// result of a non-volatile assignment, do a simple retain of the
// result of the call to objc_storeWeak instead of reloading.
@@ -1913,35 +2197,53 @@ static llvm::Value *emitARCRetainAfterCall(CodeGenFunction &CGF,
}
}
+/// Determine whether it might be important to emit a separate
+/// objc_retain_block on the result of the given expression, or
+/// whether it's okay to just emit it in a +1 context.
+static bool shouldEmitSeparateBlockRetain(const Expr *e) {
+ assert(e->getType()->isBlockPointerType());
+ e = e->IgnoreParens();
+
+ // For future goodness, emit block expressions directly in +1
+ // contexts if we can.
+ if (isa<BlockExpr>(e))
+ return false;
+
+ if (const CastExpr *cast = dyn_cast<CastExpr>(e)) {
+ switch (cast->getCastKind()) {
+ // Emitting these operations in +1 contexts is goodness.
+ case CK_LValueToRValue:
+ case CK_ARCReclaimReturnedObject:
+ case CK_ARCConsumeObject:
+ case CK_ARCProduceObject:
+ return false;
+
+ // These operations preserve a block type.
+ case CK_NoOp:
+ case CK_BitCast:
+ return shouldEmitSeparateBlockRetain(cast->getSubExpr());
+
+ // These operations are known to be bad (or haven't been considered).
+ case CK_AnyPointerToBlockPointerCast:
+ default:
+ return true;
+ }
+ }
+
+ return true;
+}
+
static TryEmitResult
tryEmitARCRetainScalarExpr(CodeGenFunction &CGF, const Expr *e) {
+ // Look through cleanups.
+ if (const ExprWithCleanups *cleanups = dyn_cast<ExprWithCleanups>(e)) {
+ CodeGenFunction::RunCleanupsScope scope(CGF);
+ return tryEmitARCRetainScalarExpr(CGF, cleanups->getSubExpr());
+ }
+
// The desired result type, if it differs from the type of the
// ultimate opaque expression.
- const llvm::Type *resultType = 0;
-
- // If we're loading retained from a __strong xvalue, we can avoid
- // an extra retain/release pair by zeroing out the source of this
- // "move" operation.
- if (e->isXValue() && !e->getType().isConstQualified() &&
- e->getType().getObjCLifetime() == Qualifiers::OCL_Strong) {
- // Emit the lvalue
- LValue lv = CGF.EmitLValue(e);
-
- // Load the object pointer and cast it to the appropriate type.
- QualType exprType = e->getType();
- llvm::Value *result = CGF.EmitLoadOfLValue(lv).getScalarVal();
-
- if (resultType)
- result = CGF.Builder.CreateBitCast(result, resultType);
-
- // Set the source pointer to NULL.
- llvm::Value *null
- = llvm::ConstantPointerNull::get(
- cast<llvm::PointerType>(CGF.ConvertType(exprType)));
- CGF.EmitStoreOfScalar(null, lv);
-
- return TryEmitResult(result, true);
- }
+ llvm::Type *resultType = 0;
while (true) {
e = e->IgnoreParens();
@@ -1969,7 +2271,8 @@ tryEmitARCRetainScalarExpr(CodeGenFunction &CGF, const Expr *e) {
// These casts can change the type, so remember that and
// soldier on. We only need to remember the outermost such
// cast, though.
- case CK_AnyPointerToObjCPointerCast:
+ case CK_CPointerToObjCPointerCast:
+ case CK_BlockPointerToObjCPointerCast:
case CK_AnyPointerToBlockPointerCast:
case CK_BitCast:
if (!resultType)
@@ -1980,15 +2283,49 @@ tryEmitARCRetainScalarExpr(CodeGenFunction &CGF, const Expr *e) {
// For consumptions, just emit the subexpression and thus elide
// the retain/release pair.
- case CK_ObjCConsumeObject: {
+ case CK_ARCConsumeObject: {
llvm::Value *result = CGF.EmitScalarExpr(ce->getSubExpr());
if (resultType) result = CGF.Builder.CreateBitCast(result, resultType);
return TryEmitResult(result, true);
}
+ // Block extends are net +0. Naively, we could just recurse on
+ // the subexpression, but actually we need to ensure that the
+ // value is copied as a block, so there's a little filter here.
+ case CK_ARCExtendBlockObject: {
+ llvm::Value *result; // will be a +0 value
+
+ // If we can't safely assume the sub-expression will produce a
+ // block-copied value, emit the sub-expression at +0.
+ if (shouldEmitSeparateBlockRetain(ce->getSubExpr())) {
+ result = CGF.EmitScalarExpr(ce->getSubExpr());
+
+ // Otherwise, try to emit the sub-expression at +1 recursively.
+ } else {
+ TryEmitResult subresult
+ = tryEmitARCRetainScalarExpr(CGF, ce->getSubExpr());
+ result = subresult.getPointer();
+
+ // If that produced a retained value, just use that,
+ // possibly casting down.
+ if (subresult.getInt()) {
+ if (resultType)
+ result = CGF.Builder.CreateBitCast(result, resultType);
+ return TryEmitResult(result, true);
+ }
+
+ // Otherwise it's +0.
+ }
+
+ // Retain the object as a block, then cast down.
+ result = CGF.EmitARCRetainBlock(result, /*mandatory*/ true);
+ if (resultType) result = CGF.Builder.CreateBitCast(result, resultType);
+ return TryEmitResult(result, true);
+ }
+
// For reclaims, emit the subexpression as a retained call and
// skip the consumption.
- case CK_ObjCReclaimReturnedObject: {
+ case CK_ARCReclaimReturnedObject: {
llvm::Value *result = emitARCRetainCall(CGF, ce->getSubExpr());
if (resultType) result = CGF.Builder.CreateBitCast(result, resultType);
return TryEmitResult(result, true);
@@ -2067,6 +2404,48 @@ CodeGenFunction::EmitARCRetainAutoreleaseScalarExpr(const Expr *e) {
return value;
}
+llvm::Value *CodeGenFunction::EmitARCExtendBlockObject(const Expr *e) {
+ llvm::Value *result;
+ bool doRetain;
+
+ if (shouldEmitSeparateBlockRetain(e)) {
+ result = EmitScalarExpr(e);
+ doRetain = true;
+ } else {
+ TryEmitResult subresult = tryEmitARCRetainScalarExpr(*this, e);
+ result = subresult.getPointer();
+ doRetain = !subresult.getInt();
+ }
+
+ if (doRetain)
+ result = EmitARCRetainBlock(result, /*mandatory*/ true);
+ return EmitObjCConsumeObject(e->getType(), result);
+}
+
+llvm::Value *CodeGenFunction::EmitObjCThrowOperand(const Expr *expr) {
+ // In ARC, retain and autorelease the expression.
+ if (getLangOptions().ObjCAutoRefCount) {
+ // Do so before running any cleanups for the full-expression.
+ // tryEmitARCRetainScalarExpr does make an effort to do things
+ // inside cleanups, but there are crazy cases like
+ // @throw A().foo;
+ // where a full retain+autorelease is required and would
+ // otherwise happen after the destructor for the temporary.
+ CodeGenFunction::RunCleanupsScope cleanups(*this);
+ if (const ExprWithCleanups *ewc = dyn_cast<ExprWithCleanups>(expr))
+ expr = ewc->getSubExpr();
+
+ return EmitARCRetainAutoreleaseScalarExpr(expr);
+ }
+
+ // Otherwise, use the normal scalar-expression emission. The
+ // exception machinery doesn't do anything special with the
+ // exception like retaining it, so there's no safety associated with
+ // only running cleanups after the throw has started, and when it
+ // matters it tends to be substantially inferior code.
+ return EmitScalarExpr(expr);
+}
+
std::pair<LValue,llvm::Value*>
CodeGenFunction::EmitARCStoreStrong(const BinaryOperator *e,
bool ignored) {
@@ -2074,10 +2453,20 @@ CodeGenFunction::EmitARCStoreStrong(const BinaryOperator *e,
TryEmitResult result = tryEmitARCRetainScalarExpr(*this, e->getRHS());
llvm::Value *value = result.getPointer();
+ bool hasImmediateRetain = result.getInt();
+
+ // If we didn't emit a retained object, and the l-value is of block
+ // type, then we need to emit the block-retain immediately in case
+ // it invalidates the l-value.
+ if (!hasImmediateRetain && e->getType()->isBlockPointerType()) {
+ value = EmitARCRetainBlock(value, /*mandatory*/ false);
+ hasImmediateRetain = true;
+ }
+
LValue lvalue = EmitLValue(e->getLHS());
// If the RHS was emitted retained, expand this.
- if (result.getInt()) {
+ if (hasImmediateRetain) {
llvm::Value *oldValue =
EmitLoadOfScalar(lvalue.getAddress(), lvalue.isVolatileQualified(),
lvalue.getAlignment(), e->getType(),
@@ -2111,10 +2500,8 @@ void CodeGenFunction::EmitObjCAutoreleasePoolStmt(
const CompoundStmt &S = cast<CompoundStmt>(*subStmt);
CGDebugInfo *DI = getDebugInfo();
- if (DI) {
- DI->setLocation(S.getLBracLoc());
- DI->EmitRegionStart(Builder);
- }
+ if (DI)
+ DI->EmitLexicalBlockStart(Builder, S.getLBracLoc());
// Keep track of the current cleanup stack depth.
RunCleanupsScope Scope(*this);
@@ -2130,19 +2517,16 @@ void CodeGenFunction::EmitObjCAutoreleasePoolStmt(
E = S.body_end(); I != E; ++I)
EmitStmt(*I);
- if (DI) {
- DI->setLocation(S.getRBracLoc());
- DI->EmitRegionEnd(Builder);
- }
+ if (DI)
+ DI->EmitLexicalBlockEnd(Builder, S.getRBracLoc());
}
/// EmitExtendGCLifetime - Given a pointer to an Objective-C object,
/// make sure it survives garbage collection until this point.
void CodeGenFunction::EmitExtendGCLifetime(llvm::Value *object) {
// We just use an inline assembly.
- llvm::Type *paramTypes[] = { VoidPtrTy };
llvm::FunctionType *extenderType
- = llvm::FunctionType::get(VoidTy, paramTypes, /*variadic*/ false);
+ = llvm::FunctionType::get(VoidTy, VoidPtrTy, /*variadic*/ false);
llvm::Value *extender
= llvm::InlineAsm::get(extenderType,
/* assembly */ "",