#include "CGDebugInfo.h"
#include "CGObjCRuntime.h"
#include "CodeGenFunction.h"
#include "CodeGenModule.h"
#include "ConstantEmitter.h"
#include "TargetInfo.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Attr.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/StmtObjC.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/CodeGen/CGFunctionInfo.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Analysis/ObjCARCUtil.h"
#include "llvm/BinaryFormat/MachO.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/InlineAsm.h"
using namespace clang;
using namespace CodeGen;
typedef llvm::PointerIntPair<llvm::Value*,1,bool> TryEmitResult;
static TryEmitResult
tryEmitARCRetainScalarExpr(CodeGenFunction &CGF, const Expr *e);
static RValue AdjustObjCObjectType(CodeGenFunction &CGF,
QualType ET,
RValue Result);
static llvm::Constant *getNullForVariable(Address addr) {
llvm::Type *type = addr.getElementType();
return llvm::ConstantPointerNull::get(cast<llvm::PointerType>(type));
}
llvm::Value *CodeGenFunction::EmitObjCStringLiteral(const ObjCStringLiteral *E)
{
llvm::Constant *C =
CGM.getObjCRuntime().GenerateConstantString(E->getString()).getPointer();
return llvm::ConstantExpr::getBitCast(C, ConvertType(E->getType()));
}
llvm::Value *
CodeGenFunction::EmitObjCBoxedExpr(const ObjCBoxedExpr *E) {
const ObjCMethodDecl *BoxingMethod = E->getBoxingMethod();
const Expr *SubExpr = E->getSubExpr();
if (E->isExpressibleAsConstantInitializer()) {
ConstantEmitter ConstEmitter(CGM);
return ConstEmitter.tryEmitAbstract(E, E->getType());
}
assert(BoxingMethod->isClassMethod() && "BoxingMethod must be a class method");
Selector Sel = BoxingMethod->getSelector();
CGObjCRuntime &Runtime = CGM.getObjCRuntime();
const ObjCInterfaceDecl *ClassDecl = BoxingMethod->getClassInterface();
llvm::Value *Receiver = Runtime.GetClass(*this, ClassDecl);
CallArgList Args;
const ParmVarDecl *ArgDecl = *BoxingMethod->param_begin();
QualType ArgQT = ArgDecl->getType().getUnqualifiedType();
const QualType ValueType(SubExpr->getType().getCanonicalType());
if (ValueType->isObjCBoxableRecordType()) {
Address Temporary = CreateMemTemp(SubExpr->getType());
EmitAnyExprToMem(SubExpr, Temporary, Qualifiers(), true);
llvm::Value *BitCast =
Builder.CreateBitCast(Temporary.getPointer(), ConvertType(ArgQT));
Args.add(RValue::get(BitCast), ArgQT);
std::string Str;
getContext().getObjCEncodingForType(ValueType, Str);
llvm::Constant *GV = CGM.GetAddrOfConstantCString(Str).getPointer();
const ParmVarDecl *EncodingDecl = BoxingMethod->parameters()[1];
QualType EncodingQT = EncodingDecl->getType().getUnqualifiedType();
llvm::Value *Cast = Builder.CreateBitCast(GV, ConvertType(EncodingQT));
Args.add(RValue::get(Cast), EncodingQT);
} else {
Args.add(EmitAnyExpr(SubExpr), ArgQT);
}
RValue result = Runtime.GenerateMessageSend(
*this, ReturnValueSlot(), BoxingMethod->getReturnType(), Sel, Receiver,
Args, ClassDecl, BoxingMethod);
return Builder.CreateBitCast(result.getScalarVal(),
ConvertType(E->getType()));
}
llvm::Value *CodeGenFunction::EmitObjCCollectionLiteral(const Expr *E,
const ObjCMethodDecl *MethodWithObjects) {
ASTContext &Context = CGM.getContext();
const ObjCDictionaryLiteral *DLE = nullptr;
const ObjCArrayLiteral *ALE = dyn_cast<ObjCArrayLiteral>(E);
if (!ALE)
DLE = cast<ObjCDictionaryLiteral>(E);
uint64_t NumElements =
ALE ? ALE->getNumElements() : DLE->getNumElements();
if (NumElements == 0 && CGM.getLangOpts().ObjCRuntime.hasEmptyCollections()) {
StringRef ConstantName = ALE ? "__NSArray0__" : "__NSDictionary0__";
QualType IdTy(CGM.getContext().getObjCIdType());
llvm::Constant *Constant =
CGM.CreateRuntimeVariable(ConvertType(IdTy), ConstantName);
LValue LV = MakeNaturalAlignAddrLValue(Constant, IdTy);
llvm::Value *Ptr = EmitLoadOfScalar(LV, E->getBeginLoc());
cast<llvm::LoadInst>(Ptr)->setMetadata(
CGM.getModule().getMDKindID("invariant.load"),
llvm::MDNode::get(getLLVMContext(), None));
return Builder.CreateBitCast(Ptr, ConvertType(E->getType()));
}
llvm::APInt APNumElements(Context.getTypeSize(Context.getSizeType()),
NumElements);
QualType ElementType = Context.getObjCIdType().withConst();
QualType ElementArrayType
= Context.getConstantArrayType(ElementType, APNumElements, nullptr,
ArrayType::Normal, 0);
Address Objects = CreateMemTemp(ElementArrayType, "objects");
Address Keys = Address::invalid();
if (DLE)
Keys = CreateMemTemp(ElementArrayType, "keys");
SmallVector<llvm::Value *, 16> NeededObjects;
bool TrackNeededObjects =
(getLangOpts().ObjCAutoRefCount &&
CGM.getCodeGenOpts().OptimizationLevel != 0);
for (uint64_t i = 0; i < NumElements; i++) {
if (ALE) {
const Expr *Rhs = ALE->getElement(i);
LValue LV = MakeAddrLValue(Builder.CreateConstArrayGEP(Objects, i),
ElementType, AlignmentSource::Decl);
llvm::Value *value = EmitScalarExpr(Rhs);
EmitStoreThroughLValue(RValue::get(value), LV, true);
if (TrackNeededObjects) {
NeededObjects.push_back(value);
}
} else {
const Expr *Key = DLE->getKeyValueElement(i).Key;
LValue KeyLV = MakeAddrLValue(Builder.CreateConstArrayGEP(Keys, i),
ElementType, AlignmentSource::Decl);
llvm::Value *keyValue = EmitScalarExpr(Key);
EmitStoreThroughLValue(RValue::get(keyValue), KeyLV, true);
const Expr *Value = DLE->getKeyValueElement(i).Value;
LValue ValueLV = MakeAddrLValue(Builder.CreateConstArrayGEP(Objects, i),
ElementType, AlignmentSource::Decl);
llvm::Value *valueValue = EmitScalarExpr(Value);
EmitStoreThroughLValue(RValue::get(valueValue), ValueLV, true);
if (TrackNeededObjects) {
NeededObjects.push_back(keyValue);
NeededObjects.push_back(valueValue);
}
}
}
CallArgList Args;
ObjCMethodDecl::param_const_iterator PI = MethodWithObjects->param_begin();
const ParmVarDecl *argDecl = *PI++;
QualType ArgQT = argDecl->getType().getUnqualifiedType();
Args.add(RValue::get(Objects.getPointer()), ArgQT);
if (DLE) {
argDecl = *PI++;
ArgQT = argDecl->getType().getUnqualifiedType();
Args.add(RValue::get(Keys.getPointer()), ArgQT);
}
argDecl = *PI;
ArgQT = argDecl->getType().getUnqualifiedType();
llvm::Value *Count =
llvm::ConstantInt::get(CGM.getTypes().ConvertType(ArgQT), NumElements);
Args.add(RValue::get(Count), ArgQT);
Selector Sel = MethodWithObjects->getSelector();
QualType ResultType = E->getType();
const ObjCObjectPointerType *InterfacePointerType
= ResultType->getAsObjCInterfacePointerType();
ObjCInterfaceDecl *Class
= InterfacePointerType->getObjectType()->getInterface();
CGObjCRuntime &Runtime = CGM.getObjCRuntime();
llvm::Value *Receiver = Runtime.GetClass(*this, Class);
RValue result = Runtime.GenerateMessageSend(
*this, ReturnValueSlot(), MethodWithObjects->getReturnType(), Sel,
Receiver, Args, Class, MethodWithObjects);
if (TrackNeededObjects) {
EmitARCIntrinsicUse(NeededObjects);
}
return Builder.CreateBitCast(result.getScalarVal(),
ConvertType(E->getType()));
}
llvm::Value *CodeGenFunction::EmitObjCArrayLiteral(const ObjCArrayLiteral *E) {
return EmitObjCCollectionLiteral(E, E->getArrayWithObjectsMethod());
}
llvm::Value *CodeGenFunction::EmitObjCDictionaryLiteral(
const ObjCDictionaryLiteral *E) {
return EmitObjCCollectionLiteral(E, E->getDictWithObjectsMethod());
}
llvm::Value *CodeGenFunction::EmitObjCSelectorExpr(const ObjCSelectorExpr *E) {
return CGM.getObjCRuntime().GetSelector(*this, E->getSelector());
}
llvm::Value *CodeGenFunction::EmitObjCProtocolExpr(const ObjCProtocolExpr *E) {
return CGM.getObjCRuntime().GenerateProtocolRef(*this, E->getProtocol());
}
static RValue AdjustObjCObjectType(CodeGenFunction &CGF, QualType ExpT,
RValue Result) {
if (!ExpT->isObjCRetainableType())
return Result;
llvm::Type *ExpLLVMTy = CGF.ConvertType(ExpT);
if (ExpLLVMTy == Result.getScalarVal()->getType())
return Result;
return RValue::get(CGF.Builder.CreateBitCast(Result.getScalarVal(),
ExpLLVMTy));
}
static bool
shouldExtendReceiverForInnerPointerMessage(const ObjCMessageExpr *message) {
switch (message->getReceiverKind()) {
case ObjCMessageExpr::Instance: {
const Expr *receiver = message->getInstanceReceiver();
if (auto opaque = dyn_cast<OpaqueValueExpr>(receiver)) {
if (opaque->getSourceExpr())
receiver = opaque->getSourceExpr()->IgnoreParens();
}
const ImplicitCastExpr *ice = dyn_cast<ImplicitCastExpr>(receiver);
if (!ice || ice->getCastKind() != CK_LValueToRValue) return true;
receiver = ice->getSubExpr()->IgnoreParens();
if (auto opaque = dyn_cast<OpaqueValueExpr>(receiver)) {
if (opaque->getSourceExpr())
receiver = opaque->getSourceExpr()->IgnoreParens();
}
if (receiver->getType().getObjCLifetime() != Qualifiers::OCL_Strong)
return true;
if (isa<MemberExpr>(receiver) || isa<ObjCIvarRefExpr>(receiver))
return false;
const DeclRefExpr *declRef = dyn_cast<DeclRefExpr>(ice->getSubExpr());
if (!declRef) return true;
const VarDecl *var = dyn_cast<VarDecl>(declRef->getDecl());
if (!var) return true;
return (var->hasLocalStorage() &&
!var->hasAttr<ObjCPreciseLifetimeAttr>());
}
case ObjCMessageExpr::Class:
case ObjCMessageExpr::SuperClass:
return false;
case ObjCMessageExpr::SuperInstance:
return false;
}
llvm_unreachable("invalid receiver kind");
}
static const Expr *findWeakLValue(const Expr *E) {
assert(E->getType()->isObjCRetainableType());
E = E->IgnoreParens();
if (auto CE = dyn_cast<CastExpr>(E)) {
if (CE->getCastKind() == CK_LValueToRValue) {
if (CE->getSubExpr()->getType().getObjCLifetime() == Qualifiers::OCL_Weak)
return CE->getSubExpr();
}
}
return nullptr;
}
static Optional<llvm::Value *>
tryGenerateSpecializedMessageSend(CodeGenFunction &CGF, QualType ResultType,
llvm::Value *Receiver,
const CallArgList& Args, Selector Sel,
const ObjCMethodDecl *method,
bool isClassMessage) {
auto &CGM = CGF.CGM;
if (!CGM.getCodeGenOpts().ObjCConvertMessagesToRuntimeCalls)
return None;
auto &Runtime = CGM.getLangOpts().ObjCRuntime;
switch (Sel.getMethodFamily()) {
case OMF_alloc:
if (isClassMessage &&
Runtime.shouldUseRuntimeFunctionsForAlloc() &&
ResultType->isObjCObjectPointerType()) {
if (Sel.isUnarySelector() && Sel.getNameForSlot(0) == "alloc")
return CGF.EmitObjCAlloc(Receiver, CGF.ConvertType(ResultType));
if (Sel.isKeywordSelector() && Sel.getNumArgs() == 1 &&
Args.size() == 1 && Args.front().getType()->isPointerType() &&
Sel.getNameForSlot(0) == "allocWithZone") {
const llvm::Value* arg = Args.front().getKnownRValue().getScalarVal();
if (isa<llvm::ConstantPointerNull>(arg))
return CGF.EmitObjCAllocWithZone(Receiver,
CGF.ConvertType(ResultType));
return None;
}
}
break;
case OMF_autorelease:
if (ResultType->isObjCObjectPointerType() &&
CGM.getLangOpts().getGC() == LangOptions::NonGC &&
Runtime.shouldUseARCFunctionsForRetainRelease())
return CGF.EmitObjCAutorelease(Receiver, CGF.ConvertType(ResultType));
break;
case OMF_retain:
if (ResultType->isObjCObjectPointerType() &&
CGM.getLangOpts().getGC() == LangOptions::NonGC &&
Runtime.shouldUseARCFunctionsForRetainRelease())
return CGF.EmitObjCRetainNonBlock(Receiver, CGF.ConvertType(ResultType));
break;
case OMF_release:
if (ResultType->isVoidType() &&
CGM.getLangOpts().getGC() == LangOptions::NonGC &&
Runtime.shouldUseARCFunctionsForRetainRelease()) {
CGF.EmitObjCRelease(Receiver, ARCPreciseLifetime);
return nullptr;
}
break;
default:
break;
}
return None;
}
CodeGen::RValue CGObjCRuntime::GeneratePossiblySpecializedMessageSend(
CodeGenFunction &CGF, ReturnValueSlot Return, QualType ResultType,
Selector Sel, llvm::Value *Receiver, const CallArgList &Args,
const ObjCInterfaceDecl *OID, const ObjCMethodDecl *Method,
bool isClassMessage) {
if (Optional<llvm::Value *> SpecializedResult =
tryGenerateSpecializedMessageSend(CGF, ResultType, Receiver, Args,
Sel, Method, isClassMessage)) {
return RValue::get(*SpecializedResult);
}
return GenerateMessageSend(CGF, Return, ResultType, Sel, Receiver, Args, OID,
Method);
}
static void AppendFirstImpliedRuntimeProtocols(
const ObjCProtocolDecl *PD,
llvm::UniqueVector<const ObjCProtocolDecl *> &PDs) {
if (!PD->isNonRuntimeProtocol()) {
const auto *Can = PD->getCanonicalDecl();
PDs.insert(Can);
return;
}
for (const auto *ParentPD : PD->protocols())
AppendFirstImpliedRuntimeProtocols(ParentPD, PDs);
}
std::vector<const ObjCProtocolDecl *>
CGObjCRuntime::GetRuntimeProtocolList(ObjCProtocolDecl::protocol_iterator begin,
ObjCProtocolDecl::protocol_iterator end) {
std::vector<const ObjCProtocolDecl *> RuntimePds;
llvm::DenseSet<const ObjCProtocolDecl *> NonRuntimePDs;
for (; begin != end; ++begin) {
const auto *It = *begin;
const auto *Can = It->getCanonicalDecl();
if (Can->isNonRuntimeProtocol())
NonRuntimePDs.insert(Can);
else
RuntimePds.push_back(Can);
}
if (NonRuntimePDs.empty())
return RuntimePds;
llvm::UniqueVector<const ObjCProtocolDecl *> FirstImpliedProtos;
for (const auto *PD : NonRuntimePDs)
AppendFirstImpliedRuntimeProtocols(PD, FirstImpliedProtos);
llvm::DenseSet<const ObjCProtocolDecl *> AllImpliedProtocols;
for (const auto *PD : RuntimePds) {
const auto *Can = PD->getCanonicalDecl();
AllImpliedProtocols.insert(Can);
Can->getImpliedProtocols(AllImpliedProtocols);
}
for (const auto *PD : FirstImpliedProtos) {
PD->getImpliedProtocols(AllImpliedProtocols);
}
for (const auto *PD : FirstImpliedProtos) {
if (!AllImpliedProtocols.contains(PD)) {
RuntimePds.push_back(PD);
}
}
return RuntimePds;
}
static Optional<llvm::Value *>
tryEmitSpecializedAllocInit(CodeGenFunction &CGF, const ObjCMessageExpr *OME) {
auto &Runtime = CGF.getLangOpts().ObjCRuntime;
if (!Runtime.shouldUseRuntimeFunctionForCombinedAllocInit())
return None;
Selector Sel = OME->getSelector();
if (OME->getReceiverKind() != ObjCMessageExpr::Instance ||
!OME->getType()->isObjCObjectPointerType() || !Sel.isUnarySelector() ||
Sel.getNameForSlot(0) != "init")
return None;
auto *SubOME =
dyn_cast<ObjCMessageExpr>(OME->getInstanceReceiver()->IgnoreParenCasts());
if (!SubOME)
return None;
Selector SubSel = SubOME->getSelector();
if (!SubOME->getType()->isObjCObjectPointerType() ||
!SubSel.isUnarySelector() || SubSel.getNameForSlot(0) != "alloc")
return None;
llvm::Value *Receiver = nullptr;
switch (SubOME->getReceiverKind()) {
case ObjCMessageExpr::Instance:
if (!SubOME->getInstanceReceiver()->getType()->isObjCClassType())
return None;
Receiver = CGF.EmitScalarExpr(SubOME->getInstanceReceiver());
break;
case ObjCMessageExpr::Class: {
QualType ReceiverType = SubOME->getClassReceiver();
const ObjCObjectType *ObjTy = ReceiverType->castAs<ObjCObjectType>();
const ObjCInterfaceDecl *ID = ObjTy->getInterface();
assert(ID && "null interface should be impossible here");
Receiver = CGF.CGM.getObjCRuntime().GetClass(CGF, ID);
break;
}
case ObjCMessageExpr::SuperInstance:
case ObjCMessageExpr::SuperClass:
return None;
}
return CGF.EmitObjCAllocInit(Receiver, CGF.ConvertType(OME->getType()));
}
RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E,
ReturnValueSlot Return) {
bool isDelegateInit = E->isDelegateInitCall();
const ObjCMethodDecl *method = E->getMethodDecl();
if (method && E->getReceiverKind() == ObjCMessageExpr::Instance &&
method->getMethodFamily() == OMF_retain) {
if (auto lvalueExpr = findWeakLValue(E->getInstanceReceiver())) {
LValue lvalue = EmitLValue(lvalueExpr);
llvm::Value *result = EmitARCLoadWeakRetained(lvalue.getAddress(*this));
return AdjustObjCObjectType(*this, E->getType(), RValue::get(result));
}
}
if (Optional<llvm::Value *> Val = tryEmitSpecializedAllocInit(*this, E))
return AdjustObjCObjectType(*this, E->getType(), RValue::get(*Val));
bool retainSelf =
(!isDelegateInit &&
CGM.getLangOpts().ObjCAutoRefCount &&
method &&
method->hasAttr<NSConsumesSelfAttr>());
CGObjCRuntime &Runtime = CGM.getObjCRuntime();
bool isSuperMessage = false;
bool isClassMessage = false;
ObjCInterfaceDecl *OID = nullptr;
QualType ReceiverType;
llvm::Value *Receiver = nullptr;
switch (E->getReceiverKind()) {
case ObjCMessageExpr::Instance:
ReceiverType = E->getInstanceReceiver()->getType();
isClassMessage = ReceiverType->isObjCClassType();
if (retainSelf) {
TryEmitResult ter = tryEmitARCRetainScalarExpr(*this,
E->getInstanceReceiver());
Receiver = ter.getPointer();
if (ter.getInt()) retainSelf = false;
} else
Receiver = EmitScalarExpr(E->getInstanceReceiver());
break;
case ObjCMessageExpr::Class: {
ReceiverType = E->getClassReceiver();
OID = ReceiverType->castAs<ObjCObjectType>()->getInterface();
assert(OID && "Invalid Objective-C class message send");
Receiver = Runtime.GetClass(*this, OID);
isClassMessage = true;
break;
}
case ObjCMessageExpr::SuperInstance:
ReceiverType = E->getSuperType();
Receiver = LoadObjCSelf();
isSuperMessage = true;
break;
case ObjCMessageExpr::SuperClass:
ReceiverType = E->getSuperType();
Receiver = LoadObjCSelf();
isSuperMessage = true;
isClassMessage = true;
break;
}
if (retainSelf)
Receiver = EmitARCRetainNonBlock(Receiver);
if (getLangOpts().ObjCAutoRefCount && method &&
method->hasAttr<ObjCReturnsInnerPointerAttr>() &&
shouldExtendReceiverForInnerPointerMessage(E))
Receiver = EmitARCRetainAutorelease(ReceiverType, Receiver);
QualType ResultType = method ? method->getReturnType() : E->getType();
CallArgList Args;
EmitCallArgs(Args, method, E->arguments(), AbstractCallee(method));
if (isDelegateInit) {
assert(getLangOpts().ObjCAutoRefCount &&
"delegate init calls should only be marked in ARC");
Address selfAddr =
GetAddrOfLocalVar(cast<ObjCMethodDecl>(CurCodeDecl)->getSelfDecl());
Builder.CreateStore(getNullForVariable(selfAddr), selfAddr);
}
RValue result;
if (isSuperMessage) {
const ObjCMethodDecl *OMD = cast<ObjCMethodDecl>(CurFuncDecl);
bool isCategoryImpl = isa<ObjCCategoryImplDecl>(OMD->getDeclContext());
result = Runtime.GenerateMessageSendSuper(*this, Return, ResultType,
E->getSelector(),
OMD->getClassInterface(),
isCategoryImpl,
Receiver,
isClassMessage,
Args,
method);
} else {
result = Runtime.GeneratePossiblySpecializedMessageSend(
*this, Return, ResultType, E->getSelector(), Receiver, Args, OID,
method, isClassMessage);
}
if (isDelegateInit) {
Address selfAddr =
GetAddrOfLocalVar(cast<ObjCMethodDecl>(CurCodeDecl)->getSelfDecl());
llvm::Value *newSelf = result.getScalarVal();
llvm::Type *selfTy = selfAddr.getElementType();
newSelf = Builder.CreateBitCast(newSelf, selfTy);
Builder.CreateStore(newSelf, selfAddr);
}
return AdjustObjCObjectType(*this, E->getType(), result);
}
namespace {
struct FinishARCDealloc final : EHScopeStack::Cleanup {
void Emit(CodeGenFunction &CGF, Flags flags) override {
const ObjCMethodDecl *method = cast<ObjCMethodDecl>(CGF.CurCodeDecl);
const ObjCImplDecl *impl = cast<ObjCImplDecl>(method->getDeclContext());
const ObjCInterfaceDecl *iface = impl->getClassInterface();
if (!iface->getSuperClass()) return;
bool isCategory = isa<ObjCCategoryImplDecl>(impl);
llvm::Value *self = CGF.LoadObjCSelf();
CallArgList args;
CGF.CGM.getObjCRuntime().GenerateMessageSendSuper(CGF, ReturnValueSlot(),
CGF.getContext().VoidTy,
method->getSelector(),
iface,
isCategory,
self,
false,
args,
method);
}
};
}
void CodeGenFunction::StartObjCMethod(const ObjCMethodDecl *OMD,
const ObjCContainerDecl *CD) {
SourceLocation StartLoc = OMD->getBeginLoc();
FunctionArgList args;
if (OMD->hasAttr<NoDebugAttr>())
DebugInfo = nullptr;
llvm::Function *Fn = CGM.getObjCRuntime().GenerateMethod(OMD, CD);
const CGFunctionInfo &FI = CGM.getTypes().arrangeObjCMethodDeclaration(OMD);
if (OMD->isDirectMethod()) {
Fn->setVisibility(llvm::Function::HiddenVisibility);
CGM.SetLLVMFunctionAttributes(OMD, FI, Fn, false);
CGM.SetLLVMFunctionAttributesForDefinition(OMD, Fn);
} else {
CGM.SetInternalFunctionAttributes(OMD, Fn, FI);
}
args.push_back(OMD->getSelfDecl());
args.push_back(OMD->getCmdDecl());
args.append(OMD->param_begin(), OMD->param_end());
CurGD = OMD;
CurEHLocation = OMD->getEndLoc();
StartFunction(OMD, OMD->getReturnType(), Fn, FI, args,
OMD->getLocation(), StartLoc);
if (OMD->isDirectMethod()) {
CGM.getObjCRuntime().GenerateDirectMethodPrologue(*this, Fn, OMD, CD);
}
if (CGM.getLangOpts().ObjCAutoRefCount &&
OMD->isInstanceMethod() &&
OMD->getSelector().isUnarySelector()) {
const IdentifierInfo *ident =
OMD->getSelector().getIdentifierInfoForSlot(0);
if (ident->isStr("dealloc"))
EHStack.pushCleanup<FinishARCDealloc>(getARCCleanupKind());
}
}
static llvm::Value *emitARCRetainLoadOfScalar(CodeGenFunction &CGF,
LValue lvalue, QualType type);
void CodeGenFunction::GenerateObjCMethod(const ObjCMethodDecl *OMD) {
StartObjCMethod(OMD, OMD->getClassInterface());
PGO.assignRegionCounters(GlobalDecl(OMD), CurFn);
assert(isa<CompoundStmt>(OMD->getBody()));
incrementProfileCounter(OMD->getBody());
EmitCompoundStmtWithoutScope(*cast<CompoundStmt>(OMD->getBody()));
FinishFunction(OMD->getBodyRBrace());
}
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)
.getPointer(CGF);
CallArgList args;
llvm::Value *dest =
CGF.Builder.CreateBitCast(CGF.ReturnValue.getPointer(), 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::FunctionCallee fn = CGF.CGM.getObjCRuntime().GetGetStructFunction();
CGCallee callee = CGCallee::forDirect(fn);
CGF.EmitCall(CGF.getTypes().arrangeBuiltinFunctionCall(Context.VoidTy, args),
callee, ReturnValueSlot(), args);
}
static bool hasUnalignedAtomics(llvm::Triple::ArchType arch) {
return false;
}
static CharUnits getMaxAtomicAccessSize(CodeGenModule &CGM,
llvm::Triple::ArchType arch) {
return CharUnits::fromQuantity(CGM.PointerSizeInBytes);
}
namespace {
class PropertyImplStrategy {
public:
enum StrategyKind {
Native,
GetSetProperty,
SetPropertyAndExpressionGet,
CopyStruct,
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;
};
}
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;
ObjCIvarDecl *ivar = propImpl->getPropertyIvarDecl();
QualType ivarType = ivar->getType();
auto TInfo = CGM.getContext().getTypeInfoInChars(ivarType);
IvarSize = TInfo.Width;
IvarAlignment = TInfo.Align;
if (IsCopy) {
Kind = IsAtomic ? GetSetProperty : SetPropertyAndExpressionGet;
return;
}
if (setterKind == ObjCPropertyDecl::Retain) {
if (CGM.getLangOpts().getGC() == LangOptions::GCOnly) {
} else if (CGM.getLangOpts().ObjCAutoRefCount && !IsAtomic) {
if (ivarType.getObjCLifetime() == Qualifiers::OCL_Strong)
Kind = Expression;
else
Kind = SetPropertyAndExpressionGet;
return;
} else if (!IsAtomic) {
Kind = SetPropertyAndExpressionGet;
return;
} else {
Kind = GetSetProperty;
return;
}
}
if (!IsAtomic) {
Kind = Expression;
return;
}
if (ivar->isBitField()) {
Kind = Expression;
return;
}
if (ivarType.hasNonTrivialObjCLifetime() ||
(CGM.getLangOpts().getGC() &&
CGM.getContext().getObjCGCAttrKind(ivarType))) {
Kind = Expression;
return;
}
if (CGM.getLangOpts().getGC())
if (const RecordType *recordType = ivarType->getAs<RecordType>())
HasStrong = recordType->getDecl()->hasObjectMember();
if (HasStrong) {
Kind = CopyStruct;
return;
}
if (!IvarSize.isPowerOfTwo()) {
Kind = CopyStruct;
return;
}
llvm::Triple::ArchType arch =
CGM.getTarget().getTriple().getArch();
if (IvarAlignment < IvarSize && !hasUnalignedAtomics(arch)) {
Kind = CopyStruct;
return;
}
if (IvarSize > getMaxAtomicAccessSize(CGM, arch)) {
Kind = CopyStruct;
return;
}
Kind = Native;
}
void CodeGenFunction::GenerateObjCGetter(ObjCImplementationDecl *IMP,
const ObjCPropertyImplDecl *PID) {
llvm::Constant *AtomicHelperFn =
CodeGenFunction(CGM).GenerateObjCAtomicGetterCopyHelperFunction(PID);
ObjCMethodDecl *OMD = PID->getGetterMethodDecl();
assert(OMD && "Invalid call to generate getter (empty method)");
StartObjCMethod(OMD, IMP->getClassInterface());
generateObjCGetterBody(IMP, PID, OMD, AtomicHelperFn);
FinishFunction(OMD->getEndLoc());
}
static bool hasTrivialGetExpr(const ObjCPropertyImplDecl *propImpl) {
const Expr *getter = propImpl->getGetterCXXConstructor();
if (!getter) return true;
if (getter->isGLValue())
return false;
if (const CXXConstructExpr *construct = dyn_cast<CXXConstructExpr>(getter))
return (construct->getConstructor()->isTrivial());
assert(isa<ExprWithCleanups>(getter));
return false;
}
static void emitCPPObjectAtomicGetterCall(CodeGenFunction &CGF,
llvm::Value *returnAddr,
ObjCIvarDecl *ivar,
llvm::Constant *AtomicHelperFn) {
CallArgList args;
args.add(RValue::get(returnAddr), CGF.getContext().VoidPtrTy);
llvm::Value *ivarAddr =
CGF.EmitLValueForIvar(CGF.TypeOfSelfObject(), CGF.LoadObjCSelf(), ivar, 0)
.getPointer(CGF);
ivarAddr = CGF.Builder.CreateBitCast(ivarAddr, CGF.Int8PtrTy);
args.add(RValue::get(ivarAddr), CGF.getContext().VoidPtrTy);
args.add(RValue::get(AtomicHelperFn), CGF.getContext().VoidPtrTy);
llvm::FunctionCallee copyCppAtomicObjectFn =
CGF.CGM.getObjCRuntime().GetCppAtomicObjectGetFunction();
CGCallee callee = CGCallee::forDirect(copyCppAtomicObjectFn);
CGF.EmitCall(
CGF.getTypes().arrangeBuiltinFunctionCall(CGF.getContext().VoidTy, args),
callee, ReturnValueSlot(), args);
}
void
CodeGenFunction::generateObjCGetterBody(const ObjCImplementationDecl *classImpl,
const ObjCPropertyImplDecl *propImpl,
const ObjCMethodDecl *GetterMethodDecl,
llvm::Constant *AtomicHelperFn) {
if (!hasTrivialGetExpr(propImpl)) {
if (!AtomicHelperFn) {
auto *ret = ReturnStmt::Create(getContext(), SourceLocation(),
propImpl->getGetterCXXConstructor(),
nullptr);
EmitReturnStmt(*ret);
}
else {
ObjCIvarDecl *ivar = propImpl->getPropertyIvarDecl();
emitCPPObjectAtomicGetterCall(*this, ReturnValue.getPointer(),
ivar, AtomicHelperFn);
}
return;
}
const ObjCPropertyDecl *prop = propImpl->getPropertyDecl();
QualType propType = prop->getType();
ObjCMethodDecl *getterMethod = propImpl->getGetterMethodDecl();
ObjCIvarDecl *ivar = propImpl->getPropertyIvarDecl();
PropertyImplStrategy strategy(CGM, propImpl);
switch (strategy.getKind()) {
case PropertyImplStrategy::Native: {
if (strategy.getIvarSize().isZero())
return;
LValue LV = EmitLValueForIvar(TypeOfSelfObject(), LoadObjCSelf(), ivar, 0);
uint64_t ivarSize = getContext().toBits(strategy.getIvarSize());
llvm::Type *bitcastType = llvm::Type::getIntNTy(getLLVMContext(), ivarSize);
Address ivarAddr = LV.getAddress(*this);
ivarAddr = Builder.CreateElementBitCast(ivarAddr, bitcastType);
llvm::LoadInst *load = Builder.CreateLoad(ivarAddr, "load");
load->setAtomic(llvm::AtomicOrdering::Unordered);
llvm::Type *retTy = ConvertType(getterMethod->getReturnType());
uint64_t retTySize = CGM.getDataLayout().getTypeSizeInBits(retTy);
llvm::Value *ivarVal = load;
if (ivarSize > retTySize) {
bitcastType = llvm::Type::getIntNTy(getLLVMContext(), retTySize);
ivarVal = Builder.CreateTrunc(load, bitcastType);
}
Builder.CreateStore(ivarVal,
Builder.CreateElementBitCast(ReturnValue, bitcastType));
AutoreleaseResult = false;
return;
}
case PropertyImplStrategy::GetSetProperty: {
llvm::FunctionCallee getPropertyFn =
CGM.getObjCRuntime().GetPropertyGetFunction();
if (!getPropertyFn) {
CGM.ErrorUnsupported(propImpl, "Obj-C getter requiring atomic copy");
return;
}
CGCallee callee = CGCallee::forDirect(getPropertyFn);
llvm::Value *cmd =
Builder.CreateLoad(GetAddrOfLocalVar(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);
llvm::CallBase *CallInstruction;
RValue RV = EmitCall(getTypes().arrangeBuiltinFunctionCall(
getContext().getObjCIdType(), args),
callee, ReturnValueSlot(), args, &CallInstruction);
if (llvm::CallInst *call = dyn_cast<llvm::CallInst>(CallInstruction))
call->setTailCall();
RV = RValue::get(Builder.CreateBitCast(
RV.getScalarVal(),
getTypes().ConvertType(getterMethod->getReturnType())));
EmitReturnOfRValue(RV, propType);
AutoreleaseResult = false;
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();
switch (getEvaluationKind(ivarType)) {
case TEK_Complex: {
ComplexPairTy pair = EmitLoadOfComplex(LV, SourceLocation());
EmitStoreOfComplex(pair, MakeAddrLValue(ReturnValue, ivarType),
true);
return;
}
case TEK_Aggregate: {
EmitAggregateCopy( MakeAddrLValue(ReturnValue, ivarType),
LV, ivarType, getOverlapForReturnValue());
return;
}
case TEK_Scalar: {
llvm::Value *value;
if (propType->isReferenceType()) {
value = LV.getAddress(*this).getPointer();
} else {
if (LV.getQuals().getObjCLifetime() == Qualifiers::OCL_Weak) {
if (getLangOpts().ObjCAutoRefCount) {
value = emitARCRetainLoadOfScalar(*this, LV, ivarType);
} else {
value = EmitARCLoadWeak(LV.getAddress(*this));
}
} else {
value = EmitLoadOfLValue(LV, SourceLocation()).getScalarVal();
AutoreleaseResult = false;
}
value = Builder.CreateBitCast(
value, ConvertType(GetterMethodDecl->getReturnType()));
}
EmitReturnOfRValue(RValue::get(value), propType);
return;
}
}
llvm_unreachable("bad evaluation kind");
}
}
llvm_unreachable("bad @property implementation strategy!");
}
static void emitStructSetterCall(CodeGenFunction &CGF, ObjCMethodDecl *OMD,
ObjCIvarDecl *ivar) {
CallArgList args;
llvm::Value *ivarAddr =
CGF.EmitLValueForIvar(CGF.TypeOfSelfObject(), CGF.LoadObjCSelf(), ivar, 0)
.getPointer(CGF);
ivarAddr = CGF.Builder.CreateBitCast(ivarAddr, CGF.Int8PtrTy);
args.add(RValue::get(ivarAddr), CGF.getContext().VoidPtrTy);
ParmVarDecl *argVar = *OMD->param_begin();
DeclRefExpr argRef(CGF.getContext(), argVar, false,
argVar->getType().getNonReferenceType(), VK_LValue,
SourceLocation());
llvm::Value *argAddr = CGF.EmitLValue(&argRef).getPointer(CGF);
argAddr = CGF.Builder.CreateBitCast(argAddr, CGF.Int8PtrTy);
args.add(RValue::get(argAddr), CGF.getContext().VoidPtrTy);
llvm::Value *size =
CGF.CGM.getSize(CGF.getContext().getTypeSizeInChars(ivar->getType()));
args.add(RValue::get(size), CGF.getContext().getSizeType());
args.add(RValue::get(CGF.Builder.getTrue()), CGF.getContext().BoolTy);
args.add(RValue::get(CGF.Builder.getFalse()), CGF.getContext().BoolTy);
llvm::FunctionCallee fn = CGF.CGM.getObjCRuntime().GetSetStructFunction();
CGCallee callee = CGCallee::forDirect(fn);
CGF.EmitCall(
CGF.getTypes().arrangeBuiltinFunctionCall(CGF.getContext().VoidTy, args),
callee, ReturnValueSlot(), args);
}
static void emitCPPObjectAtomicSetterCall(CodeGenFunction &CGF,
ObjCMethodDecl *OMD,
ObjCIvarDecl *ivar,
llvm::Constant *AtomicHelperFn) {
CallArgList args;
llvm::Value *ivarAddr =
CGF.EmitLValueForIvar(CGF.TypeOfSelfObject(), CGF.LoadObjCSelf(), ivar, 0)
.getPointer(CGF);
ivarAddr = CGF.Builder.CreateBitCast(ivarAddr, CGF.Int8PtrTy);
args.add(RValue::get(ivarAddr), CGF.getContext().VoidPtrTy);
ParmVarDecl *argVar = *OMD->param_begin();
DeclRefExpr argRef(CGF.getContext(), argVar, false,
argVar->getType().getNonReferenceType(), VK_LValue,
SourceLocation());
llvm::Value *argAddr = CGF.EmitLValue(&argRef).getPointer(CGF);
argAddr = CGF.Builder.CreateBitCast(argAddr, CGF.Int8PtrTy);
args.add(RValue::get(argAddr), CGF.getContext().VoidPtrTy);
args.add(RValue::get(AtomicHelperFn), CGF.getContext().VoidPtrTy);
llvm::FunctionCallee fn =
CGF.CGM.getObjCRuntime().GetCppAtomicObjectSetFunction();
CGCallee callee = CGCallee::forDirect(fn);
CGF.EmitCall(
CGF.getTypes().arrangeBuiltinFunctionCall(CGF.getContext().VoidTy, args),
callee, ReturnValueSlot(), args);
}
static bool hasTrivialSetExpr(const ObjCPropertyImplDecl *PID) {
Expr *setter = PID->getSetterCXXAssignment();
if (!setter) return true;
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 UseOptimizedSetter(CodeGenModule &CGM) {
if (CGM.getLangOpts().getGC() != LangOptions::NonGC)
return false;
return CGM.getLangOpts().ObjCRuntime.hasOptimizedSetter();
}
void
CodeGenFunction::generateObjCSetterBody(const ObjCImplementationDecl *classImpl,
const ObjCPropertyImplDecl *propImpl,
llvm::Constant *AtomicHelperFn) {
ObjCIvarDecl *ivar = propImpl->getPropertyIvarDecl();
ObjCMethodDecl *setterMethod = propImpl->getSetterMethodDecl();
if (!hasTrivialSetExpr(propImpl)) {
if (!AtomicHelperFn)
EmitStmt(propImpl->getSetterCXXAssignment());
else
emitCPPObjectAtomicSetterCall(*this, setterMethod, ivar,
AtomicHelperFn);
return;
}
PropertyImplStrategy strategy(CGM, propImpl);
switch (strategy.getKind()) {
case PropertyImplStrategy::Native: {
if (strategy.getIvarSize().isZero())
return;
Address argAddr = GetAddrOfLocalVar(*setterMethod->param_begin());
LValue ivarLValue =
EmitLValueForIvar(TypeOfSelfObject(), LoadObjCSelf(), ivar, 0);
Address ivarAddr = ivarLValue.getAddress(*this);
llvm::Type *bitcastType =
llvm::Type::getIntNTy(getLLVMContext(),
getContext().toBits(strategy.getIvarSize()));
argAddr = Builder.CreateElementBitCast(argAddr, bitcastType);
ivarAddr = Builder.CreateElementBitCast(ivarAddr, bitcastType);
llvm::Value *load = Builder.CreateLoad(argAddr);
llvm::StoreInst *store = Builder.CreateStore(load, ivarAddr);
store->setAtomic(llvm::AtomicOrdering::Unordered);
return;
}
case PropertyImplStrategy::GetSetProperty:
case PropertyImplStrategy::SetPropertyAndExpressionGet: {
llvm::FunctionCallee setOptimizedPropertyFn = nullptr;
llvm::FunctionCallee setPropertyFn = nullptr;
if (UseOptimizedSetter(CGM)) {
setOptimizedPropertyFn =
CGM.getObjCRuntime().GetOptimizedPropertySetFunction(
strategy.isAtomic(), strategy.isCopy());
if (!setOptimizedPropertyFn) {
CGM.ErrorUnsupported(propImpl, "Obj-C optimized setter - NYI");
return;
}
}
else {
setPropertyFn = CGM.getObjCRuntime().GetPropertySetFunction();
if (!setPropertyFn) {
CGM.ErrorUnsupported(propImpl, "Obj-C setter requiring atomic copy");
return;
}
}
llvm::Value *cmd =
Builder.CreateLoad(GetAddrOfLocalVar(setterMethod->getCmdDecl()));
llvm::Value *self =
Builder.CreateBitCast(LoadObjCSelf(), VoidPtrTy);
llvm::Value *ivarOffset =
EmitIvarOffset(classImpl->getClassInterface(), ivar);
Address argAddr = GetAddrOfLocalVar(*setterMethod->param_begin());
llvm::Value *arg = Builder.CreateLoad(argAddr, "arg");
arg = Builder.CreateBitCast(arg, VoidPtrTy);
CallArgList args;
args.add(RValue::get(self), getContext().getObjCIdType());
args.add(RValue::get(cmd), getContext().getObjCSelType());
if (setOptimizedPropertyFn) {
args.add(RValue::get(arg), getContext().getObjCIdType());
args.add(RValue::get(ivarOffset), getContext().getPointerDiffType());
CGCallee callee = CGCallee::forDirect(setOptimizedPropertyFn);
EmitCall(getTypes().arrangeBuiltinFunctionCall(getContext().VoidTy, args),
callee, ReturnValueSlot(), args);
} else {
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);
CGCallee callee = CGCallee::forDirect(setPropertyFn);
EmitCall(getTypes().arrangeBuiltinFunctionCall(getContext().VoidTy, args),
callee, ReturnValueSlot(), args);
}
return;
}
case PropertyImplStrategy::CopyStruct:
emitStructSetterCall(*this, setterMethod, ivar);
return;
case PropertyImplStrategy::Expression:
break;
}
ValueDecl *selfDecl = setterMethod->getSelfDecl();
DeclRefExpr self(getContext(), selfDecl, false, selfDecl->getType(),
VK_LValue, SourceLocation());
ImplicitCastExpr selfLoad(ImplicitCastExpr::OnStack, selfDecl->getType(),
CK_LValueToRValue, &self, VK_PRValue,
FPOptionsOverride());
ObjCIvarRefExpr ivarRef(ivar, ivar->getType().getNonReferenceType(),
SourceLocation(), SourceLocation(),
&selfLoad, true, true);
ParmVarDecl *argDecl = *setterMethod->param_begin();
QualType argType = argDecl->getType().getNonReferenceType();
DeclRefExpr arg(getContext(), argDecl, false, argType, VK_LValue,
SourceLocation());
ImplicitCastExpr argLoad(ImplicitCastExpr::OnStack,
argType.getUnqualifiedType(), CK_LValueToRValue,
&arg, VK_PRValue, FPOptionsOverride());
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;
} else if (argLoad.getType()->isAtomicType() &&
!ivarRef.getType()->isAtomicType()) {
argCK = CK_AtomicToNonAtomic;
} else if (!argLoad.getType()->isAtomicType() &&
ivarRef.getType()->isAtomicType()) {
argCK = CK_NonAtomicToAtomic;
}
ImplicitCastExpr argCast(ImplicitCastExpr::OnStack, ivarRef.getType(), argCK,
&argLoad, VK_PRValue, FPOptionsOverride());
Expr *finalArg = &argLoad;
if (!getContext().hasSameUnqualifiedType(ivarRef.getType(),
argLoad.getType()))
finalArg = &argCast;
BinaryOperator *assign = BinaryOperator::Create(
getContext(), &ivarRef, finalArg, BO_Assign, ivarRef.getType(),
VK_PRValue, OK_Ordinary, SourceLocation(), FPOptionsOverride());
EmitStmt(assign);
}
void CodeGenFunction::GenerateObjCSetter(ObjCImplementationDecl *IMP,
const ObjCPropertyImplDecl *PID) {
llvm::Constant *AtomicHelperFn =
CodeGenFunction(CGM).GenerateObjCAtomicSetterCopyHelperFunction(PID);
ObjCMethodDecl *OMD = PID->getSetterMethodDecl();
assert(OMD && "Invalid call to generate setter (empty method)");
StartObjCMethod(OMD, IMP->getClassInterface());
generateObjCSetterBody(IMP, PID, AtomicHelperFn);
FinishFunction(OMD->getEndLoc());
}
namespace {
struct DestroyIvar final : EHScopeStack::Cleanup {
private:
llvm::Value *addr;
const ObjCIvarDecl *ivar;
CodeGenFunction::Destroyer *destroyer;
bool useEHCleanupForArray;
public:
DestroyIvar(llvm::Value *addr, const ObjCIvarDecl *ivar,
CodeGenFunction::Destroyer *destroyer,
bool useEHCleanupForArray)
: addr(addr), ivar(ivar), destroyer(destroyer),
useEHCleanupForArray(useEHCleanupForArray) {}
void Emit(CodeGenFunction &CGF, Flags flags) override {
LValue lvalue
= CGF.EmitLValueForIvar(CGF.TypeOfSelfObject(), addr, ivar, 0);
CGF.emitDestroy(lvalue.getAddress(CGF), ivar->getType(), destroyer,
flags.isForNormalCleanup() && useEHCleanupForArray);
}
};
}
static void destroyARCStrongWithStore(CodeGenFunction &CGF,
Address addr,
QualType type) {
llvm::Value *null = getNullForVariable(addr);
CGF.EmitARCStoreStrongCall(addr, null, true);
}
static void emitCXXDestructMethod(CodeGenFunction &CGF,
ObjCImplementationDecl *impl) {
CodeGenFunction::RunCleanupsScope scope(CGF);
llvm::Value *self = CGF.LoadObjCSelf();
const ObjCInterfaceDecl *iface = impl->getClassInterface();
for (const ObjCIvarDecl *ivar = iface->all_declared_ivar_begin();
ivar; ivar = ivar->getNextIvar()) {
QualType type = ivar->getType();
QualType::DestructionKind dtorKind = type.isDestructedType();
if (!dtorKind) continue;
CodeGenFunction::Destroyer *destroyer = nullptr;
if (dtorKind == QualType::DK_objc_strong_lifetime) {
destroyer = destroyARCStrongWithStore;
} else {
destroyer = CGF.getDestroyer(dtorKind);
}
CleanupKind cleanupKind = CGF.getCleanupKind(dtorKind);
CGF.EHStack.pushCleanup<DestroyIvar>(cleanupKind, self, ivar, destroyer,
cleanupKind & EHCleanup);
}
assert(scope.requiresCleanups() && "nothing to do in .cxx_destruct?");
}
void CodeGenFunction::GenerateObjCCtorDtorMethod(ObjCImplementationDecl *IMP,
ObjCMethodDecl *MD,
bool ctor) {
MD->createImplicitParams(CGM.getContext(), IMP->getClassInterface());
StartObjCMethod(MD, IMP->getClassInterface());
if (ctor) {
AutoreleaseResult = false;
for (const auto *IvarInit : IMP->inits()) {
FieldDecl *Field = IvarInit->getAnyMember();
ObjCIvarDecl *Ivar = cast<ObjCIvarDecl>(Field);
LValue LV = EmitLValueForIvar(TypeOfSelfObject(),
LoadObjCSelf(), Ivar, 0);
EmitAggExpr(IvarInit->getInit(),
AggValueSlot::forLValue(LV, *this, AggValueSlot::IsDestructed,
AggValueSlot::DoesNotNeedGCBarriers,
AggValueSlot::IsNotAliased,
AggValueSlot::DoesNotOverlap));
}
CodeGenTypes &Types = CGM.getTypes();
QualType IdTy(CGM.getContext().getObjCIdType());
llvm::Value *SelfAsId =
Builder.CreateBitCast(LoadObjCSelf(), Types.ConvertType(IdTy));
EmitReturnOfRValue(RValue::get(SelfAsId), IdTy);
} else {
emitCXXDestructMethod(*this, IMP);
}
FinishFunction();
}
llvm::Value *CodeGenFunction::LoadObjCSelf() {
VarDecl *Self = cast<ObjCMethodDecl>(CurFuncDecl)->getSelfDecl();
DeclRefExpr DRE(getContext(), Self,
(CurFuncDecl != CurCodeDecl),
Self->getType(), VK_LValue, SourceLocation());
return EmitLoadOfScalar(EmitDeclRefLValue(&DRE), SourceLocation());
}
QualType CodeGenFunction::TypeOfSelfObject() {
const ObjCMethodDecl *OMD = cast<ObjCMethodDecl>(CurFuncDecl);
ImplicitParamDecl *selfDecl = OMD->getSelfDecl();
const ObjCObjectPointerType *PTy = cast<ObjCObjectPointerType>(
getContext().getCanonicalType(selfDecl->getType()));
return PTy->getPointeeType();
}
void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){
llvm::FunctionCallee EnumerationMutationFnPtr =
CGM.getObjCRuntime().EnumerationMutationFunction();
if (!EnumerationMutationFnPtr) {
CGM.ErrorUnsupported(&S, "Obj-C fast enumeration for this runtime");
return;
}
CGCallee EnumerationMutationFn =
CGCallee::forDirect(EnumerationMutationFnPtr);
CGDebugInfo *DI = getDebugInfo();
if (DI)
DI->EmitLexicalBlockStart(Builder, S.getSourceRange().getBegin());
RunCleanupsScope ForScope(*this);
AutoVarEmission variable = AutoVarEmission::invalid();
if (const DeclStmt *SD = dyn_cast<DeclStmt>(S.getElement()))
variable = EmitAutoVarAlloca(*cast<VarDecl>(SD->getSingleDecl()));
JumpDest LoopEnd = getJumpDestInCurrentScope("forcoll.end");
QualType StateTy = CGM.getObjCFastEnumerationStateType();
Address StatePtr = CreateMemTemp(StateTy, "state.ptr");
EmitNullInitialization(StatePtr, StateTy);
static const unsigned NumItems = 16;
IdentifierInfo *II[] = {
&CGM.getContext().Idents.get("countByEnumeratingWithState"),
&CGM.getContext().Idents.get("objects"),
&CGM.getContext().Idents.get("count")
};
Selector FastEnumSel =
CGM.getContext().Selectors.getSelector(llvm::array_lengthof(II), &II[0]);
QualType ItemsTy =
getContext().getConstantArrayType(getContext().getObjCIdType(),
llvm::APInt(32, NumItems), nullptr,
ArrayType::Normal, 0);
Address ItemsPtr = CreateMemTemp(ItemsTy, "items.ptr");
llvm::Value *Collection;
if (getLangOpts().ObjCAutoRefCount) {
Collection = EmitARCRetainScalarExpr(S.getCollection());
EmitObjCConsumeObject(S.getCollection()->getType(), Collection);
} else {
Collection = EmitScalarExpr(S.getCollection());
}
JumpDest AfterBody = getJumpDestInCurrentScope("forcoll.next");
CallArgList Args;
Args.add(RValue::get(StatePtr.getPointer()),
getContext().getPointerType(StateTy));
Args.add(RValue::get(ItemsPtr.getPointer()),
getContext().getPointerType(ItemsTy));
llvm::Type *NSUIntegerTy = ConvertType(getContext().getNSUIntegerType());
llvm::Constant *Count = llvm::ConstantInt::get(NSUIntegerTy, NumItems);
Args.add(RValue::get(Count), getContext().getNSUIntegerType());
RValue CountRV =
CGM.getObjCRuntime().GenerateMessageSend(*this, ReturnValueSlot(),
getContext().getNSUIntegerType(),
FastEnumSel, Collection, Args);
llvm::Value *initialBufferLimit = CountRV.getScalarVal();
llvm::BasicBlock *EmptyBB = createBasicBlock("forcoll.empty");
llvm::BasicBlock *LoopInitBB = createBasicBlock("forcoll.loopinit");
llvm::Value *zero = llvm::Constant::getNullValue(NSUIntegerTy);
uint64_t EntryCount = getCurrentProfileCount();
Builder.CreateCondBr(
Builder.CreateICmpEQ(initialBufferLimit, zero, "iszero"), EmptyBB,
LoopInitBB,
createProfileWeights(EntryCount, getProfileCount(S.getBody())));
EmitBlock(LoopInitBB);
Address StateMutationsPtrPtr =
Builder.CreateStructGEP(StatePtr, 2, "mutationsptr.ptr");
llvm::Value *StateMutationsPtr
= Builder.CreateLoad(StateMutationsPtrPtr, "mutationsptr");
llvm::Type *UnsignedLongTy = ConvertType(getContext().UnsignedLongTy);
llvm::Value *initialMutations =
Builder.CreateAlignedLoad(UnsignedLongTy, StateMutationsPtr,
getPointerAlign(), "forcoll.initial-mutations");
llvm::BasicBlock *LoopBodyBB = createBasicBlock("forcoll.loopbody");
EmitBlock(LoopBodyBB);
llvm::PHINode *index = Builder.CreatePHI(NSUIntegerTy, 3, "forcoll.index");
index->addIncoming(zero, LoopInitBB);
llvm::PHINode *count = Builder.CreatePHI(NSUIntegerTy, 3, "forcoll.count");
count->addIncoming(initialBufferLimit, LoopInitBB);
incrementProfileCounter(&S);
StateMutationsPtr = Builder.CreateLoad(StateMutationsPtrPtr, "mutationsptr");
llvm::Value *currentMutations
= Builder.CreateAlignedLoad(UnsignedLongTy, StateMutationsPtr,
getPointerAlign(), "statemutations");
llvm::BasicBlock *WasMutatedBB = createBasicBlock("forcoll.mutated");
llvm::BasicBlock *WasNotMutatedBB = createBasicBlock("forcoll.notmutated");
Builder.CreateCondBr(Builder.CreateICmpEQ(currentMutations, initialMutations),
WasNotMutatedBB, WasMutatedBB);
EmitBlock(WasMutatedBB);
llvm::Type *ObjCIdType = ConvertType(getContext().getObjCIdType());
llvm::Value *V =
Builder.CreateBitCast(Collection, ObjCIdType);
CallArgList Args2;
Args2.add(RValue::get(V), getContext().getObjCIdType());
EmitCall(
CGM.getTypes().arrangeBuiltinFunctionCall(getContext().VoidTy, Args2),
EnumerationMutationFn, ReturnValueSlot(), Args2);
EmitBlock(WasNotMutatedBB);
RunCleanupsScope elementVariableScope(*this);
bool elementIsVariable;
LValue elementLValue;
QualType elementType;
if (const DeclStmt *SD = dyn_cast<DeclStmt>(S.getElement())) {
EmitAutoVarInit(variable);
const VarDecl *D = cast<VarDecl>(SD->getSingleDecl());
DeclRefExpr tempDRE(getContext(), const_cast<VarDecl *>(D), false,
D->getType(), VK_LValue, SourceLocation());
elementLValue = EmitLValue(&tempDRE);
elementType = D->getType();
elementIsVariable = true;
if (D->isARCPseudoStrong())
elementLValue.getQuals().setObjCLifetime(Qualifiers::OCL_ExplicitNone);
} else {
elementLValue = LValue(); elementType = cast<Expr>(S.getElement())->getType();
elementIsVariable = false;
}
llvm::Type *convertedElementType = ConvertType(elementType);
Address StateItemsPtr =
Builder.CreateStructGEP(StatePtr, 1, "stateitems.ptr");
llvm::Value *EnumStateItems =
Builder.CreateLoad(StateItemsPtr, "stateitems");
llvm::Value *CurrentItemPtr = Builder.CreateGEP(
ObjCIdType, EnumStateItems, index, "currentitem.ptr");
llvm::Value *CurrentItem =
Builder.CreateAlignedLoad(ObjCIdType, CurrentItemPtr, getPointerAlign());
if (SanOpts.has(SanitizerKind::ObjCCast)) {
const ObjCObjectPointerType *ObjPtrTy =
elementType->getAsObjCInterfacePointerType();
const ObjCInterfaceType *InterfaceTy =
ObjPtrTy ? ObjPtrTy->getInterfaceType() : nullptr;
if (InterfaceTy) {
SanitizerScope SanScope(this);
auto &C = CGM.getContext();
assert(InterfaceTy->getDecl() && "No decl for ObjC interface type");
Selector IsKindOfClassSel = GetUnarySelector("isKindOfClass", C);
CallArgList IsKindOfClassArgs;
llvm::Value *Cls =
CGM.getObjCRuntime().GetClass(*this, InterfaceTy->getDecl());
IsKindOfClassArgs.add(RValue::get(Cls), C.getObjCClassType());
llvm::Value *IsClass =
CGM.getObjCRuntime()
.GenerateMessageSend(*this, ReturnValueSlot(), C.BoolTy,
IsKindOfClassSel, CurrentItem,
IsKindOfClassArgs)
.getScalarVal();
llvm::Constant *StaticData[] = {
EmitCheckSourceLocation(S.getBeginLoc()),
EmitCheckTypeDescriptor(QualType(InterfaceTy, 0))};
EmitCheck({{IsClass, SanitizerKind::ObjCCast}},
SanitizerHandler::InvalidObjCCast,
ArrayRef<llvm::Constant *>(StaticData), CurrentItem);
}
}
CurrentItem = Builder.CreateBitCast(CurrentItem, convertedElementType,
"currentitem");
if (!elementIsVariable) {
elementLValue = EmitLValue(cast<Expr>(S.getElement()));
EmitStoreThroughLValue(RValue::get(CurrentItem), elementLValue);
} else {
EmitStoreThroughLValue(RValue::get(CurrentItem), elementLValue,
true);
}
if (elementIsVariable)
EmitAutoVarCleanups(variable);
BreakContinueStack.push_back(BreakContinue(LoopEnd, AfterBody));
{
RunCleanupsScope Scope(*this);
EmitStmt(S.getBody());
}
BreakContinueStack.pop_back();
elementVariableScope.ForceCleanup();
EmitBlock(AfterBody.getBlock());
llvm::BasicBlock *FetchMoreBB = createBasicBlock("forcoll.refetch");
llvm::Value *indexPlusOne =
Builder.CreateAdd(index, llvm::ConstantInt::get(NSUIntegerTy, 1));
Builder.CreateCondBr(
Builder.CreateICmpULT(indexPlusOne, count), LoopBodyBB, FetchMoreBB,
createProfileWeights(getProfileCount(S.getBody()), EntryCount));
index->addIncoming(indexPlusOne, AfterBody.getBlock());
count->addIncoming(count, AfterBody.getBlock());
EmitBlock(FetchMoreBB);
CountRV =
CGM.getObjCRuntime().GenerateMessageSend(*this, ReturnValueSlot(),
getContext().getNSUIntegerType(),
FastEnumSel, Collection, Args);
llvm::Value *refetchCount = CountRV.getScalarVal();
index->addIncoming(zero, Builder.GetInsertBlock());
count->addIncoming(refetchCount, Builder.GetInsertBlock());
Builder.CreateCondBr(Builder.CreateICmpEQ(refetchCount, zero),
EmptyBB, LoopBodyBB);
EmitBlock(EmptyBB);
if (!elementIsVariable) {
llvm::Value *null = llvm::Constant::getNullValue(convertedElementType);
elementLValue = EmitLValue(cast<Expr>(S.getElement()));
EmitStoreThroughLValue(RValue::get(null), elementLValue);
}
if (DI)
DI->EmitLexicalBlockEnd(Builder, S.getSourceRange().getEnd());
ForScope.ForceCleanup();
EmitBlock(LoopEnd.getBlock());
}
void CodeGenFunction::EmitObjCAtTryStmt(const ObjCAtTryStmt &S) {
CGM.getObjCRuntime().EmitTryStmt(*this, S);
}
void CodeGenFunction::EmitObjCAtThrowStmt(const ObjCAtThrowStmt &S) {
CGM.getObjCRuntime().EmitThrowStmt(*this, S);
}
void CodeGenFunction::EmitObjCAtSynchronizedStmt(
const ObjCAtSynchronizedStmt &S) {
CGM.getObjCRuntime().EmitSynchronizedStmt(*this, S);
}
namespace {
struct CallObjCRelease final : EHScopeStack::Cleanup {
CallObjCRelease(llvm::Value *object) : object(object) {}
llvm::Value *object;
void Emit(CodeGenFunction &CGF, Flags flags) override {
CGF.EmitARCRelease(object, ARCImpreciseLifetime);
}
};
}
llvm::Value *CodeGenFunction::EmitObjCConsumeObject(QualType type,
llvm::Value *object) {
pushFullExprCleanup<CallObjCRelease>(getARCCleanupKind(), object);
return object;
}
llvm::Value *CodeGenFunction::EmitObjCExtendObjectLifetime(QualType type,
llvm::Value *value) {
return EmitARCRetainAutorelease(type, value);
}
void CodeGenFunction::EmitARCIntrinsicUse(ArrayRef<llvm::Value*> values) {
llvm::Function *&fn = CGM.getObjCEntrypoints().clang_arc_use;
if (!fn)
fn = CGM.getIntrinsic(llvm::Intrinsic::objc_clang_arc_use);
EmitNounwindRuntimeCall(fn, values);
}
void CodeGenFunction::EmitARCNoopIntrinsicUse(ArrayRef<llvm::Value *> values) {
llvm::Function *&fn = CGM.getObjCEntrypoints().clang_arc_noop_use;
if (!fn)
fn = CGM.getIntrinsic(llvm::Intrinsic::objc_clang_arc_noop_use);
EmitNounwindRuntimeCall(fn, values);
}
static void setARCRuntimeFunctionLinkage(CodeGenModule &CGM, llvm::Value *RTF) {
if (auto *F = dyn_cast<llvm::Function>(RTF)) {
if (!CGM.getLangOpts().ObjCRuntime.hasNativeARC() &&
!CGM.getTriple().isOSBinFormatCOFF()) {
F->setLinkage(llvm::Function::ExternalWeakLinkage);
}
}
}
static void setARCRuntimeFunctionLinkage(CodeGenModule &CGM,
llvm::FunctionCallee RTF) {
setARCRuntimeFunctionLinkage(CGM, RTF.getCallee());
}
static llvm::Function *getARCIntrinsic(llvm::Intrinsic::ID IntID,
CodeGenModule &CGM) {
llvm::Function *fn = CGM.getIntrinsic(IntID);
setARCRuntimeFunctionLinkage(CGM, fn);
return fn;
}
static llvm::Value *emitARCValueOperation(
CodeGenFunction &CGF, llvm::Value *value, llvm::Type *returnType,
llvm::Function *&fn, llvm::Intrinsic::ID IntID,
llvm::CallInst::TailCallKind tailKind = llvm::CallInst::TCK_None) {
if (isa<llvm::ConstantPointerNull>(value))
return value;
if (!fn)
fn = getARCIntrinsic(IntID, CGF.CGM);
llvm::Type *origType = returnType ? returnType : value->getType();
value = CGF.Builder.CreateBitCast(value, CGF.Int8PtrTy);
llvm::CallInst *call = CGF.EmitNounwindRuntimeCall(fn, value);
call->setTailCallKind(tailKind);
return CGF.Builder.CreateBitCast(call, origType);
}
static llvm::Value *emitARCLoadOperation(CodeGenFunction &CGF, Address addr,
llvm::Function *&fn,
llvm::Intrinsic::ID IntID) {
if (!fn)
fn = getARCIntrinsic(IntID, CGF.CGM);
llvm::Type *origType = addr.getElementType();
addr = CGF.Builder.CreateElementBitCast(addr, CGF.Int8PtrTy);
llvm::Value *result = CGF.EmitNounwindRuntimeCall(fn, addr.getPointer());
if (origType != CGF.Int8PtrTy)
result = CGF.Builder.CreateBitCast(result, origType);
return result;
}
static llvm::Value *emitARCStoreOperation(CodeGenFunction &CGF, Address addr,
llvm::Value *value,
llvm::Function *&fn,
llvm::Intrinsic::ID IntID,
bool ignored) {
assert(addr.getElementType() == value->getType());
if (!fn)
fn = getARCIntrinsic(IntID, CGF.CGM);
llvm::Type *origType = value->getType();
llvm::Value *args[] = {
CGF.Builder.CreateBitCast(addr.getPointer(), CGF.Int8PtrPtrTy),
CGF.Builder.CreateBitCast(value, CGF.Int8PtrTy)
};
llvm::CallInst *result = CGF.EmitNounwindRuntimeCall(fn, args);
if (ignored) return nullptr;
return CGF.Builder.CreateBitCast(result, origType);
}
static void emitARCCopyOperation(CodeGenFunction &CGF, Address dst, Address src,
llvm::Function *&fn,
llvm::Intrinsic::ID IntID) {
assert(dst.getType() == src.getType());
if (!fn)
fn = getARCIntrinsic(IntID, CGF.CGM);
llvm::Value *args[] = {
CGF.Builder.CreateBitCast(dst.getPointer(), CGF.Int8PtrPtrTy),
CGF.Builder.CreateBitCast(src.getPointer(), CGF.Int8PtrPtrTy)
};
CGF.EmitNounwindRuntimeCall(fn, args);
}
static llvm::Value *emitObjCValueOperation(CodeGenFunction &CGF,
llvm::Value *value,
llvm::Type *returnType,
llvm::FunctionCallee &fn,
StringRef fnName) {
if (isa<llvm::ConstantPointerNull>(value))
return value;
if (!fn) {
llvm::FunctionType *fnType =
llvm::FunctionType::get(CGF.Int8PtrTy, CGF.Int8PtrTy, false);
fn = CGF.CGM.CreateRuntimeFunction(fnType, fnName);
if (llvm::Function *f = dyn_cast<llvm::Function>(fn.getCallee()))
if (fnName == "objc_retain")
f->addFnAttr(llvm::Attribute::NonLazyBind);
}
llvm::Type *origType = returnType ? returnType : value->getType();
value = CGF.Builder.CreateBitCast(value, CGF.Int8PtrTy);
llvm::CallBase *Inst = CGF.EmitCallOrInvoke(fn, value);
if (fnName == "objc_autorelease")
if (auto *Call = dyn_cast<llvm::CallInst>(Inst))
Call->setTailCall();
return CGF.Builder.CreateBitCast(Inst, origType);
}
llvm::Value *CodeGenFunction::EmitARCRetain(QualType type, llvm::Value *value) {
if (type->isBlockPointerType())
return EmitARCRetainBlock(value, false);
else
return EmitARCRetainNonBlock(value);
}
llvm::Value *CodeGenFunction::EmitARCRetainNonBlock(llvm::Value *value) {
return emitARCValueOperation(*this, value, nullptr,
CGM.getObjCEntrypoints().objc_retain,
llvm::Intrinsic::objc_retain);
}
llvm::Value *CodeGenFunction::EmitARCRetainBlock(llvm::Value *value,
bool mandatory) {
llvm::Value *result
= emitARCValueOperation(*this, value, nullptr,
CGM.getObjCEntrypoints().objc_retainBlock,
llvm::Intrinsic::objc_retainBlock);
if (!mandatory && isa<llvm::Instruction>(result)) {
llvm::CallInst *call
= cast<llvm::CallInst>(result->stripPointerCasts());
assert(call->getCalledOperand() ==
CGM.getObjCEntrypoints().objc_retainBlock);
call->setMetadata("clang.arc.copy_on_escape",
llvm::MDNode::get(Builder.getContext(), None));
}
return result;
}
static void emitAutoreleasedReturnValueMarker(CodeGenFunction &CGF) {
llvm::InlineAsm *&marker
= CGF.CGM.getObjCEntrypoints().retainAutoreleasedReturnValueMarker;
if (!marker) {
StringRef assembly
= CGF.CGM.getTargetCodeGenInfo()
.getARCRetainAutoreleasedReturnValueMarker();
if (assembly.empty()) {
} else if (CGF.CGM.getCodeGenOpts().OptimizationLevel == 0) {
llvm::FunctionType *type =
llvm::FunctionType::get(CGF.VoidTy, false);
marker = llvm::InlineAsm::get(type, assembly, "", true);
} else {
const char *retainRVMarkerKey = llvm::objcarc::getRVMarkerModuleFlagStr();
if (!CGF.CGM.getModule().getModuleFlag(retainRVMarkerKey)) {
auto *str = llvm::MDString::get(CGF.getLLVMContext(), assembly);
CGF.CGM.getModule().addModuleFlag(llvm::Module::Error,
retainRVMarkerKey, str);
}
}
}
if (marker)
CGF.Builder.CreateCall(marker, None, CGF.getBundlesForFunclet(marker));
}
static llvm::Value *emitOptimizedARCReturnCall(llvm::Value *value,
bool IsRetainRV,
CodeGenFunction &CGF) {
emitAutoreleasedReturnValueMarker(CGF);
ObjCEntrypoints &EPs = CGF.CGM.getObjCEntrypoints();
llvm::Function *&EP = IsRetainRV
? EPs.objc_retainAutoreleasedReturnValue
: EPs.objc_unsafeClaimAutoreleasedReturnValue;
llvm::Intrinsic::ID IID =
IsRetainRV ? llvm::Intrinsic::objc_retainAutoreleasedReturnValue
: llvm::Intrinsic::objc_unsafeClaimAutoreleasedReturnValue;
EP = getARCIntrinsic(IID, CGF.CGM);
llvm::Triple::ArchType Arch = CGF.CGM.getTriple().getArch();
if (CGF.CGM.getCodeGenOpts().OptimizationLevel > 0 &&
(Arch == llvm::Triple::aarch64 || Arch == llvm::Triple::x86_64)) {
llvm::Value *bundleArgs[] = {EP};
llvm::OperandBundleDef OB("clang.arc.attachedcall", bundleArgs);
auto *oldCall = cast<llvm::CallBase>(value);
llvm::CallBase *newCall = llvm::CallBase::addOperandBundle(
oldCall, llvm::LLVMContext::OB_clang_arc_attachedcall, OB, oldCall);
newCall->copyMetadata(*oldCall);
oldCall->replaceAllUsesWith(newCall);
oldCall->eraseFromParent();
CGF.EmitARCNoopIntrinsicUse(newCall);
return newCall;
}
bool isNoTail =
CGF.CGM.getTargetCodeGenInfo().markARCOptimizedReturnCallsAsNoTail();
llvm::CallInst::TailCallKind tailKind =
isNoTail ? llvm::CallInst::TCK_NoTail : llvm::CallInst::TCK_None;
return emitARCValueOperation(CGF, value, nullptr, EP, IID, tailKind);
}
llvm::Value *
CodeGenFunction::EmitARCRetainAutoreleasedReturnValue(llvm::Value *value) {
return emitOptimizedARCReturnCall(value, true, *this);
}
llvm::Value *
CodeGenFunction::EmitARCUnsafeClaimAutoreleasedReturnValue(llvm::Value *value) {
return emitOptimizedARCReturnCall(value, false, *this);
}
void CodeGenFunction::EmitARCRelease(llvm::Value *value,
ARCPreciseLifetime_t precise) {
if (isa<llvm::ConstantPointerNull>(value)) return;
llvm::Function *&fn = CGM.getObjCEntrypoints().objc_release;
if (!fn)
fn = getARCIntrinsic(llvm::Intrinsic::objc_release, CGM);
value = Builder.CreateBitCast(value, Int8PtrTy);
llvm::CallInst *call = EmitNounwindRuntimeCall(fn, value);
if (precise == ARCImpreciseLifetime) {
call->setMetadata("clang.imprecise_release",
llvm::MDNode::get(Builder.getContext(), None));
}
}
void CodeGenFunction::EmitARCDestroyStrong(Address addr,
ARCPreciseLifetime_t precise) {
if (CGM.getCodeGenOpts().OptimizationLevel == 0) {
llvm::Value *null = getNullForVariable(addr);
EmitARCStoreStrongCall(addr, null, true);
return;
}
llvm::Value *value = Builder.CreateLoad(addr);
EmitARCRelease(value, precise);
}
llvm::Value *CodeGenFunction::EmitARCStoreStrongCall(Address addr,
llvm::Value *value,
bool ignored) {
assert(addr.getElementType() == value->getType());
llvm::Function *&fn = CGM.getObjCEntrypoints().objc_storeStrong;
if (!fn)
fn = getARCIntrinsic(llvm::Intrinsic::objc_storeStrong, CGM);
llvm::Value *args[] = {
Builder.CreateBitCast(addr.getPointer(), Int8PtrPtrTy),
Builder.CreateBitCast(value, Int8PtrTy)
};
EmitNounwindRuntimeCall(fn, args);
if (ignored) return nullptr;
return value;
}
llvm::Value *CodeGenFunction::EmitARCStoreStrong(LValue dst,
llvm::Value *newValue,
bool ignored) {
QualType type = dst.getType();
bool isBlock = type->isBlockPointerType();
if (shouldUseFusedARCCalls() &&
!isBlock &&
(dst.getAlignment().isZero() ||
dst.getAlignment() >= CharUnits::fromQuantity(PointerAlignInBytes))) {
return EmitARCStoreStrongCall(dst.getAddress(*this), newValue, ignored);
}
newValue = EmitARCRetain(type, newValue);
llvm::Value *oldValue = EmitLoadOfScalar(dst, SourceLocation());
EmitStoreOfScalar(newValue, dst);
EmitARCRelease(oldValue, dst.isARCPreciseLifetime());
return newValue;
}
llvm::Value *CodeGenFunction::EmitARCAutorelease(llvm::Value *value) {
return emitARCValueOperation(*this, value, nullptr,
CGM.getObjCEntrypoints().objc_autorelease,
llvm::Intrinsic::objc_autorelease);
}
llvm::Value *
CodeGenFunction::EmitARCAutoreleaseReturnValue(llvm::Value *value) {
return emitARCValueOperation(*this, value, nullptr,
CGM.getObjCEntrypoints().objc_autoreleaseReturnValue,
llvm::Intrinsic::objc_autoreleaseReturnValue,
llvm::CallInst::TCK_Tail);
}
llvm::Value *
CodeGenFunction::EmitARCRetainAutoreleaseReturnValue(llvm::Value *value) {
return emitARCValueOperation(*this, value, nullptr,
CGM.getObjCEntrypoints().objc_retainAutoreleaseReturnValue,
llvm::Intrinsic::objc_retainAutoreleaseReturnValue,
llvm::CallInst::TCK_Tail);
}
llvm::Value *CodeGenFunction::EmitARCRetainAutorelease(QualType type,
llvm::Value *value) {
if (!type->isBlockPointerType())
return EmitARCRetainAutoreleaseNonBlock(value);
if (isa<llvm::ConstantPointerNull>(value)) return value;
llvm::Type *origType = value->getType();
value = Builder.CreateBitCast(value, Int8PtrTy);
value = EmitARCRetainBlock(value, true);
value = EmitARCAutorelease(value);
return Builder.CreateBitCast(value, origType);
}
llvm::Value *
CodeGenFunction::EmitARCRetainAutoreleaseNonBlock(llvm::Value *value) {
return emitARCValueOperation(*this, value, nullptr,
CGM.getObjCEntrypoints().objc_retainAutorelease,
llvm::Intrinsic::objc_retainAutorelease);
}
llvm::Value *CodeGenFunction::EmitARCLoadWeak(Address addr) {
return emitARCLoadOperation(*this, addr,
CGM.getObjCEntrypoints().objc_loadWeak,
llvm::Intrinsic::objc_loadWeak);
}
llvm::Value *CodeGenFunction::EmitARCLoadWeakRetained(Address addr) {
return emitARCLoadOperation(*this, addr,
CGM.getObjCEntrypoints().objc_loadWeakRetained,
llvm::Intrinsic::objc_loadWeakRetained);
}
llvm::Value *CodeGenFunction::EmitARCStoreWeak(Address addr,
llvm::Value *value,
bool ignored) {
return emitARCStoreOperation(*this, addr, value,
CGM.getObjCEntrypoints().objc_storeWeak,
llvm::Intrinsic::objc_storeWeak, ignored);
}
void CodeGenFunction::EmitARCInitWeak(Address addr, llvm::Value *value) {
if (isa<llvm::ConstantPointerNull>(value) &&
CGM.getCodeGenOpts().OptimizationLevel == 0) {
Builder.CreateStore(value, addr);
return;
}
emitARCStoreOperation(*this, addr, value,
CGM.getObjCEntrypoints().objc_initWeak,
llvm::Intrinsic::objc_initWeak, true);
}
void CodeGenFunction::EmitARCDestroyWeak(Address addr) {
llvm::Function *&fn = CGM.getObjCEntrypoints().objc_destroyWeak;
if (!fn)
fn = getARCIntrinsic(llvm::Intrinsic::objc_destroyWeak, CGM);
addr = Builder.CreateElementBitCast(addr, Int8PtrTy);
EmitNounwindRuntimeCall(fn, addr.getPointer());
}
void CodeGenFunction::EmitARCMoveWeak(Address dst, Address src) {
emitARCCopyOperation(*this, dst, src,
CGM.getObjCEntrypoints().objc_moveWeak,
llvm::Intrinsic::objc_moveWeak);
}
void CodeGenFunction::EmitARCCopyWeak(Address dst, Address src) {
emitARCCopyOperation(*this, dst, src,
CGM.getObjCEntrypoints().objc_copyWeak,
llvm::Intrinsic::objc_copyWeak);
}
void CodeGenFunction::emitARCCopyAssignWeak(QualType Ty, Address DstAddr,
Address SrcAddr) {
llvm::Value *Object = EmitARCLoadWeakRetained(SrcAddr);
Object = EmitObjCConsumeObject(Ty, Object);
EmitARCStoreWeak(DstAddr, Object, false);
}
void CodeGenFunction::emitARCMoveAssignWeak(QualType Ty, Address DstAddr,
Address SrcAddr) {
llvm::Value *Object = EmitARCLoadWeakRetained(SrcAddr);
Object = EmitObjCConsumeObject(Ty, Object);
EmitARCStoreWeak(DstAddr, Object, false);
EmitARCDestroyWeak(SrcAddr);
}
llvm::Value *CodeGenFunction::EmitObjCAutoreleasePoolPush() {
llvm::Function *&fn = CGM.getObjCEntrypoints().objc_autoreleasePoolPush;
if (!fn)
fn = getARCIntrinsic(llvm::Intrinsic::objc_autoreleasePoolPush, CGM);
return EmitNounwindRuntimeCall(fn);
}
void CodeGenFunction::EmitObjCAutoreleasePoolPop(llvm::Value *value) {
assert(value->getType() == Int8PtrTy);
if (getInvokeDest()) {
llvm::FunctionCallee &fn =
CGM.getObjCEntrypoints().objc_autoreleasePoolPopInvoke;
if (!fn) {
llvm::FunctionType *fnType =
llvm::FunctionType::get(Builder.getVoidTy(), Int8PtrTy, false);
fn = CGM.CreateRuntimeFunction(fnType, "objc_autoreleasePoolPop");
setARCRuntimeFunctionLinkage(CGM, fn);
}
EmitRuntimeCallOrInvoke(fn, value);
} else {
llvm::FunctionCallee &fn = CGM.getObjCEntrypoints().objc_autoreleasePoolPop;
if (!fn)
fn = getARCIntrinsic(llvm::Intrinsic::objc_autoreleasePoolPop, CGM);
EmitRuntimeCall(fn, value);
}
}
llvm::Value *CodeGenFunction::EmitObjCMRRAutoreleasePoolPush() {
CGObjCRuntime &Runtime = CGM.getObjCRuntime();
llvm::Value *Receiver = Runtime.EmitNSAutoreleasePoolClassRef(*this);
IdentifierInfo *II = &CGM.getContext().Idents.get("alloc");
Selector AllocSel = getContext().Selectors.getSelector(0, &II);
CallArgList Args;
RValue AllocRV =
Runtime.GenerateMessageSend(*this, ReturnValueSlot(),
getContext().getObjCIdType(),
AllocSel, Receiver, Args);
Receiver = AllocRV.getScalarVal();
II = &CGM.getContext().Idents.get("init");
Selector InitSel = getContext().Selectors.getSelector(0, &II);
RValue InitRV =
Runtime.GenerateMessageSend(*this, ReturnValueSlot(),
getContext().getObjCIdType(),
InitSel, Receiver, Args);
return InitRV.getScalarVal();
}
llvm::Value *CodeGenFunction::EmitObjCAlloc(llvm::Value *value,
llvm::Type *resultType) {
return emitObjCValueOperation(*this, value, resultType,
CGM.getObjCEntrypoints().objc_alloc,
"objc_alloc");
}
llvm::Value *CodeGenFunction::EmitObjCAllocWithZone(llvm::Value *value,
llvm::Type *resultType) {
return emitObjCValueOperation(*this, value, resultType,
CGM.getObjCEntrypoints().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");
}
void CodeGenFunction::EmitObjCMRRAutoreleasePoolPop(llvm::Value *Arg) {
IdentifierInfo *II = &CGM.getContext().Idents.get("drain");
Selector DrainSel = getContext().Selectors.getSelector(0, &II);
CallArgList Args;
CGM.getObjCRuntime().GenerateMessageSend(*this, ReturnValueSlot(),
getContext().VoidTy, DrainSel, Arg, Args);
}
void CodeGenFunction::destroyARCStrongPrecise(CodeGenFunction &CGF,
Address addr,
QualType type) {
CGF.EmitARCDestroyStrong(addr, ARCPreciseLifetime);
}
void CodeGenFunction::destroyARCStrongImprecise(CodeGenFunction &CGF,
Address addr,
QualType type) {
CGF.EmitARCDestroyStrong(addr, ARCImpreciseLifetime);
}
void CodeGenFunction::destroyARCWeak(CodeGenFunction &CGF,
Address addr,
QualType type) {
CGF.EmitARCDestroyWeak(addr);
}
void CodeGenFunction::emitARCIntrinsicUse(CodeGenFunction &CGF, Address addr,
QualType type) {
llvm::Value *value = CGF.Builder.CreateLoad(addr);
CGF.EmitARCIntrinsicUse(value);
}
llvm::Value *CodeGenFunction::EmitObjCAutorelease(llvm::Value *value,
llvm::Type *returnType) {
return emitObjCValueOperation(
*this, value, returnType,
CGM.getObjCEntrypoints().objc_autoreleaseRuntimeFunction,
"objc_autorelease");
}
llvm::Value *CodeGenFunction::EmitObjCRetainNonBlock(llvm::Value *value,
llvm::Type *returnType) {
return emitObjCValueOperation(
*this, value, returnType,
CGM.getObjCEntrypoints().objc_retainRuntimeFunction, "objc_retain");
}
void CodeGenFunction::EmitObjCRelease(llvm::Value *value,
ARCPreciseLifetime_t precise) {
if (isa<llvm::ConstantPointerNull>(value)) return;
llvm::FunctionCallee &fn =
CGM.getObjCEntrypoints().objc_releaseRuntimeFunction;
if (!fn) {
llvm::FunctionType *fnType =
llvm::FunctionType::get(Builder.getVoidTy(), Int8PtrTy, false);
fn = CGM.CreateRuntimeFunction(fnType, "objc_release");
setARCRuntimeFunctionLinkage(CGM, fn);
if (llvm::Function *f = dyn_cast<llvm::Function>(fn.getCallee()))
f->addFnAttr(llvm::Attribute::NonLazyBind);
}
value = Builder.CreateBitCast(value, Int8PtrTy);
llvm::CallBase *call = EmitCallOrInvoke(fn, value);
if (precise == ARCImpreciseLifetime) {
call->setMetadata("clang.imprecise_release",
llvm::MDNode::get(Builder.getContext(), None));
}
}
namespace {
struct CallObjCAutoreleasePoolObject final : EHScopeStack::Cleanup {
llvm::Value *Token;
CallObjCAutoreleasePoolObject(llvm::Value *token) : Token(token) {}
void Emit(CodeGenFunction &CGF, Flags flags) override {
CGF.EmitObjCAutoreleasePoolPop(Token);
}
};
struct CallObjCMRRAutoreleasePoolObject final : EHScopeStack::Cleanup {
llvm::Value *Token;
CallObjCMRRAutoreleasePoolObject(llvm::Value *token) : Token(token) {}
void Emit(CodeGenFunction &CGF, Flags flags) override {
CGF.EmitObjCMRRAutoreleasePoolPop(Token);
}
};
}
void CodeGenFunction::EmitObjCAutoreleasePoolCleanup(llvm::Value *Ptr) {
if (CGM.getLangOpts().ObjCAutoRefCount)
EHStack.pushCleanup<CallObjCAutoreleasePoolObject>(NormalCleanup, Ptr);
else
EHStack.pushCleanup<CallObjCMRRAutoreleasePoolObject>(NormalCleanup, Ptr);
}
static bool shouldRetainObjCLifetime(Qualifiers::ObjCLifetime lifetime) {
switch (lifetime) {
case Qualifiers::OCL_None:
case Qualifiers::OCL_ExplicitNone:
case Qualifiers::OCL_Strong:
case Qualifiers::OCL_Autoreleasing:
return true;
case Qualifiers::OCL_Weak:
return false;
}
llvm_unreachable("impossible lifetime!");
}
static TryEmitResult tryEmitARCRetainLoadOfScalar(CodeGenFunction &CGF,
LValue lvalue,
QualType type) {
llvm::Value *result;
bool shouldRetain = shouldRetainObjCLifetime(type.getObjCLifetime());
if (shouldRetain) {
result = CGF.EmitLoadOfLValue(lvalue, SourceLocation()).getScalarVal();
} else {
assert(type.getObjCLifetime() == Qualifiers::OCL_Weak);
result = CGF.EmitARCLoadWeakRetained(lvalue.getAddress(CGF));
}
return TryEmitResult(result, !shouldRetain);
}
static TryEmitResult tryEmitARCRetainLoadOfScalar(CodeGenFunction &CGF,
const Expr *e) {
e = e->IgnoreParens();
QualType type = e->getType();
if (e->isXValue() &&
!type.isConstQualified() &&
type.getObjCLifetime() == Qualifiers::OCL_Strong) {
LValue lv = CGF.EmitLValue(e);
llvm::Value *result = CGF.EmitLoadOfLValue(lv,
SourceLocation()).getScalarVal();
CGF.EmitStoreOfScalar(getNullForVariable(lv.getAddress(CGF)), lv);
return TryEmitResult(result, true);
}
if (CGF.getLangOpts().CPlusPlus &&
!type.isVolatileQualified() &&
type.getObjCLifetime() == Qualifiers::OCL_Weak &&
isa<BinaryOperator>(e) &&
cast<BinaryOperator>(e)->getOpcode() == BO_Assign)
return TryEmitResult(CGF.EmitScalarExpr(e), false);
if (const auto *decl_expr = dyn_cast<DeclRefExpr>(e)) {
auto *DRE = const_cast<DeclRefExpr *>(decl_expr);
if (CodeGenFunction::ConstantEmission constant = CGF.tryEmitAsConstant(DRE))
return TryEmitResult(CGF.emitScalarConstant(constant, DRE),
!shouldRetainObjCLifetime(type.getObjCLifetime()));
}
return tryEmitARCRetainLoadOfScalar(CGF, CGF.EmitLValue(e), type);
}
typedef llvm::function_ref<llvm::Value *(CodeGenFunction &CGF,
llvm::Value *value)>
ValueTransform;
static llvm::Value *emitARCOperationAfterCall(CodeGenFunction &CGF,
llvm::Value *value,
ValueTransform doAfterCall,
ValueTransform doFallback) {
CGBuilderTy::InsertPoint ip = CGF.Builder.saveIP();
auto *callBase = dyn_cast<llvm::CallBase>(value);
if (callBase && llvm::objcarc::hasAttachedCallOpBundle(callBase)) {
value = doFallback(CGF, value);
} else if (llvm::CallInst *call = dyn_cast<llvm::CallInst>(value)) {
CGF.Builder.SetInsertPoint(call->getParent(),
++llvm::BasicBlock::iterator(call));
value = doAfterCall(CGF, value);
} else if (llvm::InvokeInst *invoke = dyn_cast<llvm::InvokeInst>(value)) {
llvm::BasicBlock *BB = invoke->getNormalDest();
CGF.Builder.SetInsertPoint(BB, BB->begin());
value = doAfterCall(CGF, value);
} else if (llvm::BitCastInst *bitcast = dyn_cast<llvm::BitCastInst>(value)) {
CGF.Builder.SetInsertPoint(bitcast->getParent(), bitcast->getIterator());
llvm::Value *operand = bitcast->getOperand(0);
operand = emitARCOperationAfterCall(CGF, operand, doAfterCall, doFallback);
bitcast->setOperand(0, operand);
value = bitcast;
} else {
auto *phi = dyn_cast<llvm::PHINode>(value);
if (phi && phi->getNumIncomingValues() == 2 &&
isa<llvm::ConstantPointerNull>(phi->getIncomingValue(1)) &&
isa<llvm::CallBase>(phi->getIncomingValue(0))) {
llvm::Value *inVal = phi->getIncomingValue(0);
inVal = emitARCOperationAfterCall(CGF, inVal, doAfterCall, doFallback);
phi->setIncomingValue(0, inVal);
value = phi;
} else {
value = doFallback(CGF, value);
}
}
CGF.Builder.restoreIP(ip);
return value;
}
static llvm::Value *emitARCRetainCallResult(CodeGenFunction &CGF,
const Expr *e) {
llvm::Value *value = CGF.EmitScalarExpr(e);
return emitARCOperationAfterCall(CGF, value,
[](CodeGenFunction &CGF, llvm::Value *value) {
return CGF.EmitARCRetainAutoreleasedReturnValue(value);
},
[](CodeGenFunction &CGF, llvm::Value *value) {
return CGF.EmitARCRetainNonBlock(value);
});
}
static llvm::Value *emitARCUnsafeClaimCallResult(CodeGenFunction &CGF,
const Expr *e) {
llvm::Value *value = CGF.EmitScalarExpr(e);
return emitARCOperationAfterCall(CGF, value,
[](CodeGenFunction &CGF, llvm::Value *value) {
return CGF.EmitARCUnsafeClaimAutoreleasedReturnValue(value);
},
[](CodeGenFunction &CGF, llvm::Value *value) {
return value;
});
}
llvm::Value *CodeGenFunction::EmitARCReclaimReturnedObject(const Expr *E,
bool allowUnsafeClaim) {
if (allowUnsafeClaim &&
CGM.getLangOpts().ObjCRuntime.hasARCUnsafeClaimAutoreleasedReturnValue()) {
return emitARCUnsafeClaimCallResult(*this, E);
} else {
llvm::Value *value = emitARCRetainCallResult(*this, E);
return EmitObjCConsumeObject(E->getType(), value);
}
}
static bool shouldEmitSeparateBlockRetain(const Expr *e) {
assert(e->getType()->isBlockPointerType());
e = e->IgnoreParens();
if (isa<BlockExpr>(e))
return false;
if (const CastExpr *cast = dyn_cast<CastExpr>(e)) {
switch (cast->getCastKind()) {
case CK_LValueToRValue:
case CK_ARCReclaimReturnedObject:
case CK_ARCConsumeObject:
case CK_ARCProduceObject:
return false;
case CK_NoOp:
case CK_BitCast:
return shouldEmitSeparateBlockRetain(cast->getSubExpr());
case CK_AnyPointerToBlockPointerCast:
default:
return true;
}
}
return true;
}
namespace {
template <typename Impl, typename Result> class ARCExprEmitter {
protected:
CodeGenFunction &CGF;
Impl &asImpl() { return *static_cast<Impl*>(this); }
ARCExprEmitter(CodeGenFunction &CGF) : CGF(CGF) {}
public:
Result visit(const Expr *e);
Result visitCastExpr(const CastExpr *e);
Result visitPseudoObjectExpr(const PseudoObjectExpr *e);
Result visitBlockExpr(const BlockExpr *e);
Result visitBinaryOperator(const BinaryOperator *e);
Result visitBinAssign(const BinaryOperator *e);
Result visitBinAssignUnsafeUnretained(const BinaryOperator *e);
Result visitBinAssignAutoreleasing(const BinaryOperator *e);
Result visitBinAssignWeak(const BinaryOperator *e);
Result visitBinAssignStrong(const BinaryOperator *e);
};
}
template <typename Impl, typename Result>
Result
ARCExprEmitter<Impl,Result>::visitPseudoObjectExpr(const PseudoObjectExpr *E) {
SmallVector<CodeGenFunction::OpaqueValueMappingData, 4> opaques;
const Expr *resultExpr = E->getResultExpr();
assert(resultExpr);
Result result;
for (PseudoObjectExpr::const_semantics_iterator
i = E->semantics_begin(), e = E->semantics_end(); i != e; ++i) {
const Expr *semantic = *i;
if (const OpaqueValueExpr *ov = dyn_cast<OpaqueValueExpr>(semantic)) {
typedef CodeGenFunction::OpaqueValueMappingData OVMA;
OVMA opaqueData;
if (ov == resultExpr) {
assert(!OVMA::shouldBindAsLValue(ov));
result = asImpl().visit(ov->getSourceExpr());
opaqueData = OVMA::bind(CGF, ov,
RValue::get(asImpl().getValueOfResult(result)));
} else {
opaqueData = OVMA::bind(CGF, ov, ov->getSourceExpr());
}
opaques.push_back(opaqueData);
} else if (semantic == resultExpr) {
result = asImpl().visit(semantic);
} else {
CGF.EmitIgnoredExpr(semantic);
}
}
for (unsigned i = 0, e = opaques.size(); i != e; ++i)
opaques[i].unbind(CGF);
return result;
}
template <typename Impl, typename Result>
Result ARCExprEmitter<Impl, Result>::visitBlockExpr(const BlockExpr *e) {
return asImpl().visitExpr(e);
}
template <typename Impl, typename Result>
Result ARCExprEmitter<Impl,Result>::visitCastExpr(const CastExpr *e) {
switch (e->getCastKind()) {
case CK_NoOp:
return asImpl().visit(e->getSubExpr());
case CK_CPointerToObjCPointerCast:
case CK_BlockPointerToObjCPointerCast:
case CK_AnyPointerToBlockPointerCast:
case CK_BitCast: {
llvm::Type *resultType = CGF.ConvertType(e->getType());
assert(e->getSubExpr()->getType()->hasPointerRepresentation());
Result result = asImpl().visit(e->getSubExpr());
return asImpl().emitBitCast(result, resultType);
}
case CK_LValueToRValue:
return asImpl().visitLValueToRValue(e->getSubExpr());
case CK_ARCConsumeObject:
return asImpl().visitConsumeObject(e->getSubExpr());
case CK_ARCExtendBlockObject:
return asImpl().visitExtendBlockObject(e->getSubExpr());
case CK_ARCReclaimReturnedObject:
return asImpl().visitReclaimReturnedObject(e->getSubExpr());
default:
return asImpl().visitExpr(e);
}
}
template <typename Impl, typename Result>
Result
ARCExprEmitter<Impl,Result>::visitBinaryOperator(const BinaryOperator *e) {
switch (e->getOpcode()) {
case BO_Comma:
CGF.EmitIgnoredExpr(e->getLHS());
CGF.EnsureInsertPoint();
return asImpl().visit(e->getRHS());
case BO_Assign:
return asImpl().visitBinAssign(e);
default:
return asImpl().visitExpr(e);
}
}
template <typename Impl, typename Result>
Result ARCExprEmitter<Impl,Result>::visitBinAssign(const BinaryOperator *e) {
switch (e->getLHS()->getType().getObjCLifetime()) {
case Qualifiers::OCL_ExplicitNone:
return asImpl().visitBinAssignUnsafeUnretained(e);
case Qualifiers::OCL_Weak:
return asImpl().visitBinAssignWeak(e);
case Qualifiers::OCL_Autoreleasing:
return asImpl().visitBinAssignAutoreleasing(e);
case Qualifiers::OCL_Strong:
return asImpl().visitBinAssignStrong(e);
case Qualifiers::OCL_None:
return asImpl().visitExpr(e);
}
llvm_unreachable("bad ObjC ownership qualifier");
}
template <typename Impl, typename Result>
Result ARCExprEmitter<Impl,Result>::
visitBinAssignUnsafeUnretained(const BinaryOperator *e) {
Result result = asImpl().visit(e->getRHS());
LValue lvalue =
CGF.EmitCheckedLValue(e->getLHS(), CodeGenFunction::TCK_Store);
CGF.EmitStoreThroughLValue(RValue::get(asImpl().getValueOfResult(result)),
lvalue);
return result;
}
template <typename Impl, typename Result>
Result
ARCExprEmitter<Impl,Result>::visitBinAssignAutoreleasing(const BinaryOperator *e) {
return asImpl().visitExpr(e);
}
template <typename Impl, typename Result>
Result
ARCExprEmitter<Impl,Result>::visitBinAssignWeak(const BinaryOperator *e) {
return asImpl().visitExpr(e);
}
template <typename Impl, typename Result>
Result
ARCExprEmitter<Impl,Result>::visitBinAssignStrong(const BinaryOperator *e) {
return asImpl().visitExpr(e);
}
template <typename Impl, typename Result>
Result ARCExprEmitter<Impl,Result>::visit(const Expr *e) {
assert(!isa<ExprWithCleanups>(e));
e = e->IgnoreParens();
if (const CastExpr *ce = dyn_cast<CastExpr>(e)) {
return asImpl().visitCastExpr(ce);
} else if (auto op = dyn_cast<BinaryOperator>(e)) {
return asImpl().visitBinaryOperator(op);
} else if (isa<CallExpr>(e) ||
(isa<ObjCMessageExpr>(e) &&
!cast<ObjCMessageExpr>(e)->isDelegateInitCall())) {
return asImpl().visitCall(e);
} else if (const PseudoObjectExpr *pseudo = dyn_cast<PseudoObjectExpr>(e)) {
return asImpl().visitPseudoObjectExpr(pseudo);
} else if (auto *be = dyn_cast<BlockExpr>(e))
return asImpl().visitBlockExpr(be);
return asImpl().visitExpr(e);
}
namespace {
struct ARCRetainExprEmitter :
public ARCExprEmitter<ARCRetainExprEmitter, TryEmitResult> {
ARCRetainExprEmitter(CodeGenFunction &CGF) : ARCExprEmitter(CGF) {}
llvm::Value *getValueOfResult(TryEmitResult result) {
return result.getPointer();
}
TryEmitResult emitBitCast(TryEmitResult result, llvm::Type *resultType) {
llvm::Value *value = result.getPointer();
value = CGF.Builder.CreateBitCast(value, resultType);
result.setPointer(value);
return result;
}
TryEmitResult visitLValueToRValue(const Expr *e) {
return tryEmitARCRetainLoadOfScalar(CGF, e);
}
TryEmitResult visitConsumeObject(const Expr *e) {
llvm::Value *result = CGF.EmitScalarExpr(e);
return TryEmitResult(result, true);
}
TryEmitResult visitBlockExpr(const BlockExpr *e) {
TryEmitResult result = visitExpr(e);
if (CGF.CGM.getCodeGenOpts().ObjCAvoidHeapifyLocalBlocks &&
e->getBlockDecl()->canAvoidCopyToHeap())
result.setInt(true);
return result;
}
TryEmitResult visitExtendBlockObject(const Expr *e) {
llvm::Value *result;
if (shouldEmitSeparateBlockRetain(e)) {
result = CGF.EmitScalarExpr(e);
} else {
TryEmitResult subresult = asImpl().visit(e);
if (subresult.getInt()) {
return subresult;
}
result = subresult.getPointer();
}
result = CGF.EmitARCRetainBlock(result, true);
return TryEmitResult(result, true);
}
TryEmitResult visitReclaimReturnedObject(const Expr *e) {
llvm::Value *result = emitARCRetainCallResult(CGF, e);
return TryEmitResult(result, true);
}
TryEmitResult visitCall(const Expr *e) {
llvm::Value *result = emitARCRetainCallResult(CGF, e);
return TryEmitResult(result, true);
}
TryEmitResult visitExpr(const Expr *e) {
llvm::Value *result = CGF.EmitScalarExpr(e);
return TryEmitResult(result, false);
}
};
}
static TryEmitResult
tryEmitARCRetainScalarExpr(CodeGenFunction &CGF, const Expr *e) {
return ARCRetainExprEmitter(CGF).visit(e);
}
static llvm::Value *emitARCRetainLoadOfScalar(CodeGenFunction &CGF,
LValue lvalue,
QualType type) {
TryEmitResult result = tryEmitARCRetainLoadOfScalar(CGF, lvalue, type);
llvm::Value *value = result.getPointer();
if (!result.getInt())
value = CGF.EmitARCRetain(type, value);
return value;
}
llvm::Value *CodeGenFunction::EmitARCRetainScalarExpr(const Expr *e) {
if (const ExprWithCleanups *cleanups = dyn_cast<ExprWithCleanups>(e)) {
RunCleanupsScope scope(*this);
return EmitARCRetainScalarExpr(cleanups->getSubExpr());
}
TryEmitResult result = tryEmitARCRetainScalarExpr(*this, e);
llvm::Value *value = result.getPointer();
if (!result.getInt())
value = EmitARCRetain(e->getType(), value);
return value;
}
llvm::Value *
CodeGenFunction::EmitARCRetainAutoreleaseScalarExpr(const Expr *e) {
if (const ExprWithCleanups *cleanups = dyn_cast<ExprWithCleanups>(e)) {
RunCleanupsScope scope(*this);
return EmitARCRetainAutoreleaseScalarExpr(cleanups->getSubExpr());
}
TryEmitResult result = tryEmitARCRetainScalarExpr(*this, e);
llvm::Value *value = result.getPointer();
if (result.getInt())
value = EmitARCAutorelease(value);
else
value = EmitARCRetainAutorelease(e->getType(), value);
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, true);
return EmitObjCConsumeObject(e->getType(), result);
}
llvm::Value *CodeGenFunction::EmitObjCThrowOperand(const Expr *expr) {
if (getLangOpts().ObjCAutoRefCount) {
return EmitARCRetainAutoreleaseScalarExpr(expr);
}
return EmitScalarExpr(expr);
}
namespace {
struct ARCUnsafeUnretainedExprEmitter :
public ARCExprEmitter<ARCUnsafeUnretainedExprEmitter, llvm::Value*> {
ARCUnsafeUnretainedExprEmitter(CodeGenFunction &CGF) : ARCExprEmitter(CGF) {}
llvm::Value *getValueOfResult(llvm::Value *value) {
return value;
}
llvm::Value *emitBitCast(llvm::Value *value, llvm::Type *resultType) {
return CGF.Builder.CreateBitCast(value, resultType);
}
llvm::Value *visitLValueToRValue(const Expr *e) {
return CGF.EmitScalarExpr(e);
}
llvm::Value *visitConsumeObject(const Expr *e) {
llvm::Value *value = CGF.EmitScalarExpr(e);
return CGF.EmitObjCConsumeObject(e->getType(), value);
}
llvm::Value *visitExtendBlockObject(const Expr *e) {
return CGF.EmitARCExtendBlockObject(e);
}
llvm::Value *visitReclaimReturnedObject(const Expr *e) {
return CGF.EmitARCReclaimReturnedObject(e, true);
}
llvm::Value *visitCall(const Expr *e) {
return CGF.EmitScalarExpr(e);
}
llvm::Value *visitExpr(const Expr *e) {
return CGF.EmitScalarExpr(e);
}
};
}
static llvm::Value *emitARCUnsafeUnretainedScalarExpr(CodeGenFunction &CGF,
const Expr *e) {
return ARCUnsafeUnretainedExprEmitter(CGF).visit(e);
}
llvm::Value *CodeGenFunction::EmitARCUnsafeUnretainedScalarExpr(const Expr *e) {
if (const ExprWithCleanups *cleanups = dyn_cast<ExprWithCleanups>(e)) {
RunCleanupsScope scope(*this);
return emitARCUnsafeUnretainedScalarExpr(*this, cleanups->getSubExpr());
}
return emitARCUnsafeUnretainedScalarExpr(*this, e);
}
std::pair<LValue,llvm::Value*>
CodeGenFunction::EmitARCStoreUnsafeUnretained(const BinaryOperator *e,
bool ignored) {
llvm::Value *value;
if (ignored) {
value = EmitARCUnsafeUnretainedScalarExpr(e->getRHS());
} else {
value = EmitScalarExpr(e->getRHS());
}
LValue lvalue = EmitLValue(e->getLHS());
EmitStoreOfScalar(value, lvalue);
return std::pair<LValue,llvm::Value*>(std::move(lvalue), value);
}
std::pair<LValue,llvm::Value*>
CodeGenFunction::EmitARCStoreStrong(const BinaryOperator *e,
bool ignored) {
TryEmitResult result = tryEmitARCRetainScalarExpr(*this, e->getRHS());
llvm::Value *value = result.getPointer();
bool hasImmediateRetain = result.getInt();
if (!hasImmediateRetain && e->getType()->isBlockPointerType()) {
value = EmitARCRetainBlock(value, false);
hasImmediateRetain = true;
}
LValue lvalue = EmitLValue(e->getLHS());
if (hasImmediateRetain) {
llvm::Value *oldValue = EmitLoadOfScalar(lvalue, SourceLocation());
EmitStoreOfScalar(value, lvalue);
EmitARCRelease(oldValue, lvalue.isARCPreciseLifetime());
} else {
value = EmitARCStoreStrong(lvalue, value, ignored);
}
return std::pair<LValue,llvm::Value*>(lvalue, value);
}
std::pair<LValue,llvm::Value*>
CodeGenFunction::EmitARCStoreAutoreleasing(const BinaryOperator *e) {
llvm::Value *value = EmitARCRetainAutoreleaseScalarExpr(e->getRHS());
LValue lvalue = EmitLValue(e->getLHS());
EmitStoreOfScalar(value, lvalue);
return std::pair<LValue,llvm::Value*>(lvalue, value);
}
void CodeGenFunction::EmitObjCAutoreleasePoolStmt(
const ObjCAutoreleasePoolStmt &ARPS) {
const Stmt *subStmt = ARPS.getSubStmt();
const CompoundStmt &S = cast<CompoundStmt>(*subStmt);
CGDebugInfo *DI = getDebugInfo();
if (DI)
DI->EmitLexicalBlockStart(Builder, S.getLBracLoc());
RunCleanupsScope Scope(*this);
if (CGM.getLangOpts().ObjCRuntime.hasNativeARC()) {
llvm::Value *token = EmitObjCAutoreleasePoolPush();
EHStack.pushCleanup<CallObjCAutoreleasePoolObject>(NormalCleanup, token);
} else {
llvm::Value *token = EmitObjCMRRAutoreleasePoolPush();
EHStack.pushCleanup<CallObjCMRRAutoreleasePoolObject>(NormalCleanup, token);
}
for (const auto *I : S.body())
EmitStmt(I);
if (DI)
DI->EmitLexicalBlockEnd(Builder, S.getRBracLoc());
}
void CodeGenFunction::EmitExtendGCLifetime(llvm::Value *object) {
llvm::FunctionType *extenderType
= llvm::FunctionType::get(VoidTy, VoidPtrTy, RequiredArgs::All);
llvm::InlineAsm *extender = llvm::InlineAsm::get(extenderType,
"",
"r",
true);
object = Builder.CreateBitCast(object, VoidPtrTy);
EmitNounwindRuntimeCall(extender, object);
}
llvm::Constant *
CodeGenFunction::GenerateObjCAtomicSetterCopyHelperFunction(
const ObjCPropertyImplDecl *PID) {
if (!getLangOpts().CPlusPlus ||
!getLangOpts().ObjCRuntime.hasAtomicCopyHelper())
return nullptr;
QualType Ty = PID->getPropertyIvarDecl()->getType();
if (!Ty->isRecordType())
return nullptr;
const ObjCPropertyDecl *PD = PID->getPropertyDecl();
if ((!(PD->getPropertyAttributes() & ObjCPropertyAttribute::kind_atomic)))
return nullptr;
llvm::Constant *HelperFn = nullptr;
if (hasTrivialSetExpr(PID))
return nullptr;
assert(PID->getSetterCXXAssignment() && "SetterCXXAssignment - null");
if ((HelperFn = CGM.getAtomicSetterHelperFnMap(Ty)))
return HelperFn;
ASTContext &C = getContext();
IdentifierInfo *II
= &CGM.getContext().Idents.get("__assign_helper_atomic_property_");
QualType ReturnTy = C.VoidTy;
QualType DestTy = C.getPointerType(Ty);
QualType SrcTy = Ty;
SrcTy.addConst();
SrcTy = C.getPointerType(SrcTy);
SmallVector<QualType, 2> ArgTys;
ArgTys.push_back(DestTy);
ArgTys.push_back(SrcTy);
QualType FunctionTy = C.getFunctionType(ReturnTy, ArgTys, {});
FunctionDecl *FD = FunctionDecl::Create(
C, C.getTranslationUnitDecl(), SourceLocation(), SourceLocation(), II,
FunctionTy, nullptr, SC_Static, false, false, false);
FunctionArgList args;
ParmVarDecl *Params[2];
ParmVarDecl *DstDecl = ParmVarDecl::Create(
C, FD, SourceLocation(), SourceLocation(), nullptr, DestTy,
C.getTrivialTypeSourceInfo(DestTy, SourceLocation()), SC_None,
nullptr);
args.push_back(Params[0] = DstDecl);
ParmVarDecl *SrcDecl = ParmVarDecl::Create(
C, FD, SourceLocation(), SourceLocation(), nullptr, SrcTy,
C.getTrivialTypeSourceInfo(SrcTy, SourceLocation()), SC_None,
nullptr);
args.push_back(Params[1] = SrcDecl);
FD->setParams(Params);
const CGFunctionInfo &FI =
CGM.getTypes().arrangeBuiltinFunctionDeclaration(ReturnTy, args);
llvm::FunctionType *LTy = CGM.getTypes().GetFunctionType(FI);
llvm::Function *Fn =
llvm::Function::Create(LTy, llvm::GlobalValue::InternalLinkage,
"__assign_helper_atomic_property_",
&CGM.getModule());
CGM.SetInternalFunctionAttributes(GlobalDecl(), Fn, FI);
StartFunction(FD, ReturnTy, Fn, FI, args);
DeclRefExpr DstExpr(C, DstDecl, false, DestTy, VK_PRValue, SourceLocation());
UnaryOperator *DST = UnaryOperator::Create(
C, &DstExpr, UO_Deref, DestTy->getPointeeType(), VK_LValue, OK_Ordinary,
SourceLocation(), false, FPOptionsOverride());
DeclRefExpr SrcExpr(C, SrcDecl, false, SrcTy, VK_PRValue, SourceLocation());
UnaryOperator *SRC = UnaryOperator::Create(
C, &SrcExpr, UO_Deref, SrcTy->getPointeeType(), VK_LValue, OK_Ordinary,
SourceLocation(), false, FPOptionsOverride());
Expr *Args[2] = {DST, SRC};
CallExpr *CalleeExp = cast<CallExpr>(PID->getSetterCXXAssignment());
CXXOperatorCallExpr *TheCall = CXXOperatorCallExpr::Create(
C, OO_Equal, CalleeExp->getCallee(), Args, DestTy->getPointeeType(),
VK_LValue, SourceLocation(), FPOptionsOverride());
EmitStmt(TheCall);
FinishFunction();
HelperFn = llvm::ConstantExpr::getBitCast(Fn, VoidPtrTy);
CGM.setAtomicSetterHelperFnMap(Ty, HelperFn);
return HelperFn;
}
llvm::Constant *
CodeGenFunction::GenerateObjCAtomicGetterCopyHelperFunction(
const ObjCPropertyImplDecl *PID) {
if (!getLangOpts().CPlusPlus ||
!getLangOpts().ObjCRuntime.hasAtomicCopyHelper())
return nullptr;
const ObjCPropertyDecl *PD = PID->getPropertyDecl();
QualType Ty = PD->getType();
if (!Ty->isRecordType())
return nullptr;
if ((!(PD->getPropertyAttributes() & ObjCPropertyAttribute::kind_atomic)))
return nullptr;
llvm::Constant *HelperFn = nullptr;
if (hasTrivialGetExpr(PID))
return nullptr;
assert(PID->getGetterCXXConstructor() && "getGetterCXXConstructor - null");
if ((HelperFn = CGM.getAtomicGetterHelperFnMap(Ty)))
return HelperFn;
ASTContext &C = getContext();
IdentifierInfo *II =
&CGM.getContext().Idents.get("__copy_helper_atomic_property_");
QualType ReturnTy = C.VoidTy;
QualType DestTy = C.getPointerType(Ty);
QualType SrcTy = Ty;
SrcTy.addConst();
SrcTy = C.getPointerType(SrcTy);
SmallVector<QualType, 2> ArgTys;
ArgTys.push_back(DestTy);
ArgTys.push_back(SrcTy);
QualType FunctionTy = C.getFunctionType(ReturnTy, ArgTys, {});
FunctionDecl *FD = FunctionDecl::Create(
C, C.getTranslationUnitDecl(), SourceLocation(), SourceLocation(), II,
FunctionTy, nullptr, SC_Static, false, false, false);
FunctionArgList args;
ParmVarDecl *Params[2];
ParmVarDecl *DstDecl = ParmVarDecl::Create(
C, FD, SourceLocation(), SourceLocation(), nullptr, DestTy,
C.getTrivialTypeSourceInfo(DestTy, SourceLocation()), SC_None,
nullptr);
args.push_back(Params[0] = DstDecl);
ParmVarDecl *SrcDecl = ParmVarDecl::Create(
C, FD, SourceLocation(), SourceLocation(), nullptr, SrcTy,
C.getTrivialTypeSourceInfo(SrcTy, SourceLocation()), SC_None,
nullptr);
args.push_back(Params[1] = SrcDecl);
FD->setParams(Params);
const CGFunctionInfo &FI =
CGM.getTypes().arrangeBuiltinFunctionDeclaration(ReturnTy, args);
llvm::FunctionType *LTy = CGM.getTypes().GetFunctionType(FI);
llvm::Function *Fn = llvm::Function::Create(
LTy, llvm::GlobalValue::InternalLinkage, "__copy_helper_atomic_property_",
&CGM.getModule());
CGM.SetInternalFunctionAttributes(GlobalDecl(), Fn, FI);
StartFunction(FD, ReturnTy, Fn, FI, args);
DeclRefExpr SrcExpr(getContext(), SrcDecl, false, SrcTy, VK_PRValue,
SourceLocation());
UnaryOperator *SRC = UnaryOperator::Create(
C, &SrcExpr, UO_Deref, SrcTy->getPointeeType(), VK_LValue, OK_Ordinary,
SourceLocation(), false, FPOptionsOverride());
CXXConstructExpr *CXXConstExpr =
cast<CXXConstructExpr>(PID->getGetterCXXConstructor());
SmallVector<Expr*, 4> ConstructorArgs;
ConstructorArgs.push_back(SRC);
ConstructorArgs.append(std::next(CXXConstExpr->arg_begin()),
CXXConstExpr->arg_end());
CXXConstructExpr *TheCXXConstructExpr =
CXXConstructExpr::Create(C, Ty, SourceLocation(),
CXXConstExpr->getConstructor(),
CXXConstExpr->isElidable(),
ConstructorArgs,
CXXConstExpr->hadMultipleCandidates(),
CXXConstExpr->isListInitialization(),
CXXConstExpr->isStdInitListInitialization(),
CXXConstExpr->requiresZeroInitialization(),
CXXConstExpr->getConstructionKind(),
SourceRange());
DeclRefExpr DstExpr(getContext(), DstDecl, false, DestTy, VK_PRValue,
SourceLocation());
RValue DV = EmitAnyExpr(&DstExpr);
CharUnits Alignment =
getContext().getTypeAlignInChars(TheCXXConstructExpr->getType());
EmitAggExpr(TheCXXConstructExpr,
AggValueSlot::forAddr(
Address(DV.getScalarVal(), ConvertTypeForMem(Ty), Alignment),
Qualifiers(), AggValueSlot::IsDestructed,
AggValueSlot::DoesNotNeedGCBarriers,
AggValueSlot::IsNotAliased, AggValueSlot::DoesNotOverlap));
FinishFunction();
HelperFn = llvm::ConstantExpr::getBitCast(Fn, VoidPtrTy);
CGM.setAtomicGetterHelperFnMap(Ty, HelperFn);
return HelperFn;
}
llvm::Value *
CodeGenFunction::EmitBlockCopyAndAutorelease(llvm::Value *Block, QualType Ty) {
IdentifierInfo *CopyID = &getContext().Idents.get("copy");
Selector CopySelector =
getContext().Selectors.getNullarySelector(CopyID);
IdentifierInfo *AutoreleaseID = &getContext().Idents.get("autorelease");
Selector AutoreleaseSelector =
getContext().Selectors.getNullarySelector(AutoreleaseID);
CGObjCRuntime &Runtime = CGM.getObjCRuntime();
llvm::Value *Val = Block;
RValue Result;
Result = Runtime.GenerateMessageSend(*this, ReturnValueSlot(),
Ty, CopySelector,
Val, CallArgList(), nullptr, nullptr);
Val = Result.getScalarVal();
Result = Runtime.GenerateMessageSend(*this, ReturnValueSlot(),
Ty, AutoreleaseSelector,
Val, CallArgList(), nullptr, nullptr);
Val = Result.getScalarVal();
return Val;
}
static unsigned getBaseMachOPlatformID(const llvm::Triple &TT) {
switch (TT.getOS()) {
case llvm::Triple::Darwin:
case llvm::Triple::MacOSX:
return llvm::MachO::PLATFORM_MACOS;
case llvm::Triple::IOS:
return llvm::MachO::PLATFORM_IOS;
case llvm::Triple::TvOS:
return llvm::MachO::PLATFORM_TVOS;
case llvm::Triple::WatchOS:
return llvm::MachO::PLATFORM_WATCHOS;
case llvm::Triple::DriverKit:
return llvm::MachO::PLATFORM_DRIVERKIT;
default:
return 0;
}
}
static llvm::Value *emitIsPlatformVersionAtLeast(CodeGenFunction &CGF,
const VersionTuple &Version) {
CodeGenModule &CGM = CGF.CGM;
llvm::SmallVector<llvm::Value *, 8> Args;
auto EmitArgs = [&](const VersionTuple &Version, const llvm::Triple &TT) {
Optional<unsigned> Min = Version.getMinor(), SMin = Version.getSubminor();
Args.push_back(
llvm::ConstantInt::get(CGM.Int32Ty, getBaseMachOPlatformID(TT)));
Args.push_back(llvm::ConstantInt::get(CGM.Int32Ty, Version.getMajor()));
Args.push_back(llvm::ConstantInt::get(CGM.Int32Ty, Min.value_or(0)));
Args.push_back(llvm::ConstantInt::get(CGM.Int32Ty, SMin.value_or(0)));
};
assert(!Version.empty() && "unexpected empty version");
EmitArgs(Version, CGM.getTarget().getTriple());
if (!CGM.IsPlatformVersionAtLeastFn) {
llvm::FunctionType *FTy = llvm::FunctionType::get(
CGM.Int32Ty, {CGM.Int32Ty, CGM.Int32Ty, CGM.Int32Ty, CGM.Int32Ty},
false);
CGM.IsPlatformVersionAtLeastFn =
CGM.CreateRuntimeFunction(FTy, "__isPlatformVersionAtLeast");
}
llvm::Value *Check =
CGF.EmitNounwindRuntimeCall(CGM.IsPlatformVersionAtLeastFn, Args);
return CGF.Builder.CreateICmpNE(Check,
llvm::Constant::getNullValue(CGM.Int32Ty));
}
llvm::Value *
CodeGenFunction::EmitBuiltinAvailable(const VersionTuple &Version) {
if (CGM.getTarget().getTriple().isOSDarwin())
return emitIsPlatformVersionAtLeast(*this, Version);
if (!CGM.IsOSVersionAtLeastFn) {
llvm::FunctionType *FTy =
llvm::FunctionType::get(Int32Ty, {Int32Ty, Int32Ty, Int32Ty}, false);
CGM.IsOSVersionAtLeastFn =
CGM.CreateRuntimeFunction(FTy, "__isOSVersionAtLeast");
}
Optional<unsigned> Min = Version.getMinor(), SMin = Version.getSubminor();
llvm::Value *Args[] = {
llvm::ConstantInt::get(CGM.Int32Ty, Version.getMajor()),
llvm::ConstantInt::get(CGM.Int32Ty, Min.value_or(0)),
llvm::ConstantInt::get(CGM.Int32Ty, SMin.value_or(0))};
llvm::Value *CallRes =
EmitNounwindRuntimeCall(CGM.IsOSVersionAtLeastFn, Args);
return Builder.CreateICmpNE(CallRes, llvm::Constant::getNullValue(Int32Ty));
}
static bool isFoundationNeededForDarwinAvailabilityCheck(
const llvm::Triple &TT, const VersionTuple &TargetVersion) {
VersionTuple FoundationDroppedInVersion;
switch (TT.getOS()) {
case llvm::Triple::IOS:
case llvm::Triple::TvOS:
FoundationDroppedInVersion = VersionTuple(13);
break;
case llvm::Triple::WatchOS:
FoundationDroppedInVersion = VersionTuple(6);
break;
case llvm::Triple::Darwin:
case llvm::Triple::MacOSX:
FoundationDroppedInVersion = VersionTuple(10, 15);
break;
case llvm::Triple::DriverKit:
return false;
default:
llvm_unreachable("Unexpected OS");
}
return TargetVersion < FoundationDroppedInVersion;
}
void CodeGenModule::emitAtAvailableLinkGuard() {
if (!IsPlatformVersionAtLeastFn)
return;
if (!Target.getTriple().isOSDarwin())
return;
if (!isFoundationNeededForDarwinAvailabilityCheck(
Target.getTriple(), Target.getPlatformMinVersion()))
return;
auto &Context = getLLVMContext();
llvm::Metadata *Args[2] = {llvm::MDString::get(Context, "-framework"),
llvm::MDString::get(Context, "CoreFoundation")};
LinkerOptionsMetadata.push_back(llvm::MDNode::get(Context, Args));
llvm::FunctionType *FTy =
llvm::FunctionType::get(Int32Ty, {VoidPtrTy}, false);
llvm::FunctionCallee CFFunc =
CreateRuntimeFunction(FTy, "CFBundleGetVersionNumber");
llvm::FunctionType *CheckFTy = llvm::FunctionType::get(VoidTy, {}, false);
llvm::FunctionCallee CFLinkCheckFuncRef = CreateRuntimeFunction(
CheckFTy, "__clang_at_available_requires_core_foundation_framework",
llvm::AttributeList(), true);
llvm::Function *CFLinkCheckFunc =
cast<llvm::Function>(CFLinkCheckFuncRef.getCallee()->stripPointerCasts());
if (CFLinkCheckFunc->empty()) {
CFLinkCheckFunc->setLinkage(llvm::GlobalValue::LinkOnceAnyLinkage);
CFLinkCheckFunc->setVisibility(llvm::GlobalValue::HiddenVisibility);
CodeGenFunction CGF(*this);
CGF.Builder.SetInsertPoint(CGF.createBasicBlock("", CFLinkCheckFunc));
CGF.EmitNounwindRuntimeCall(CFFunc,
llvm::Constant::getNullValue(VoidPtrTy));
CGF.Builder.CreateUnreachable();
addCompilerUsedGlobal(CFLinkCheckFunc);
}
}
CGObjCRuntime::~CGObjCRuntime() {}