aboutsummaryrefslogtreecommitdiff
path: root/lib/CodeGen/CGCall.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/CodeGen/CGCall.cpp')
-rw-r--r--lib/CodeGen/CGCall.cpp91
1 files changed, 81 insertions, 10 deletions
diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp
index 9318973e64..faf32e3008 100644
--- a/lib/CodeGen/CGCall.cpp
+++ b/lib/CodeGen/CGCall.cpp
@@ -1771,7 +1771,8 @@ static bool isProvablyNonNull(llvm::Value *addr) {
/// Emit the actual writing-back of a writeback.
static void emitWriteback(CodeGenFunction &CGF,
const CallArgList::Writeback &writeback) {
- llvm::Value *srcAddr = writeback.Address;
+ const LValue &srcLV = writeback.Source;
+ llvm::Value *srcAddr = srcLV.getAddress();
assert(!isProvablyNull(srcAddr) &&
"shouldn't have writeback for provably null argument");
@@ -1798,9 +1799,35 @@ static void emitWriteback(CodeGenFunction &CGF,
"icr.writeback-cast");
// Perform the writeback.
- QualType srcAddrType = writeback.AddressType;
- CGF.EmitStoreThroughLValue(RValue::get(value),
- CGF.MakeAddrLValue(srcAddr, srcAddrType));
+
+ // If we have a "to use" value, it's something we need to emit a use
+ // of. This has to be carefully threaded in: if it's done after the
+ // release it's potentially undefined behavior (and the optimizer
+ // will ignore it), and if it happens before the retain then the
+ // optimizer could move the release there.
+ if (writeback.ToUse) {
+ assert(srcLV.getObjCLifetime() == Qualifiers::OCL_Strong);
+
+ // Retain the new value. No need to block-copy here: the block's
+ // being passed up the stack.
+ value = CGF.EmitARCRetainNonBlock(value);
+
+ // Emit the intrinsic use here.
+ CGF.EmitARCIntrinsicUse(writeback.ToUse);
+
+ // Load the old value (primitively).
+ llvm::Value *oldValue = CGF.EmitLoadOfScalar(srcLV);
+
+ // Put the new value in place (primitively).
+ CGF.EmitStoreOfScalar(value, srcLV, /*init*/ false);
+
+ // Release the old value.
+ CGF.EmitARCRelease(oldValue, srcLV.isARCPreciseLifetime());
+
+ // Otherwise, we can just do a normal lvalue store.
+ } else {
+ CGF.EmitStoreThroughLValue(RValue::get(value), srcLV);
+ }
// Jump to the continuation block.
if (!provablyNonNull)
@@ -1814,11 +1841,33 @@ static void emitWritebacks(CodeGenFunction &CGF,
emitWriteback(CGF, *i);
}
+static const Expr *maybeGetUnaryAddrOfOperand(const Expr *E) {
+ if (const UnaryOperator *uop = dyn_cast<UnaryOperator>(E->IgnoreParens()))
+ if (uop->getOpcode() == UO_AddrOf)
+ return uop->getSubExpr();
+ return 0;
+}
+
/// Emit an argument that's being passed call-by-writeback. That is,
/// we are passing the address of
static void emitWritebackArg(CodeGenFunction &CGF, CallArgList &args,
const ObjCIndirectCopyRestoreExpr *CRE) {
- llvm::Value *srcAddr = CGF.EmitScalarExpr(CRE->getSubExpr());
+ LValue srcLV;
+
+ // Make an optimistic effort to emit the address as an l-value.
+ // This can fail if the the argument expression is more complicated.
+ if (const Expr *lvExpr = maybeGetUnaryAddrOfOperand(CRE->getSubExpr())) {
+ srcLV = CGF.EmitLValue(lvExpr);
+
+ // Otherwise, just emit it as a scalar.
+ } else {
+ llvm::Value *srcAddr = CGF.EmitScalarExpr(CRE->getSubExpr());
+
+ QualType srcAddrType =
+ CRE->getSubExpr()->getType()->castAs<PointerType>()->getPointeeType();
+ srcLV = CGF.MakeNaturalAlignAddrLValue(srcAddr, srcAddrType);
+ }
+ llvm::Value *srcAddr = srcLV.getAddress();
// The dest and src types don't necessarily match in LLVM terms
// because of the crazy ObjC compatibility rules.
@@ -1833,9 +1882,6 @@ static void emitWritebackArg(CodeGenFunction &CGF, CallArgList &args,
return;
}
- QualType srcAddrType =
- CRE->getSubExpr()->getType()->castAs<PointerType>()->getPointeeType();
-
// Create the temporary.
llvm::Value *temp = CGF.CreateTempAlloca(destType->getElementType(),
"icr.temp");
@@ -1855,6 +1901,7 @@ static void emitWritebackArg(CodeGenFunction &CGF, CallArgList &args,
}
llvm::BasicBlock *contBB = 0;
+ llvm::BasicBlock *originBB = 0;
// If the address is *not* known to be non-null, we need to switch.
llvm::Value *finalArgument;
@@ -1872,6 +1919,7 @@ static void emitWritebackArg(CodeGenFunction &CGF, CallArgList &args,
// If we need to copy, then the load has to be conditional, which
// means we need control flow.
if (shouldCopy) {
+ originBB = CGF.Builder.GetInsertBlock();
contBB = CGF.createBasicBlock("icr.cont");
llvm::BasicBlock *copyBB = CGF.createBasicBlock("icr.copy");
CGF.Builder.CreateCondBr(isNull, contBB, copyBB);
@@ -1880,9 +1928,10 @@ static void emitWritebackArg(CodeGenFunction &CGF, CallArgList &args,
}
}
+ llvm::Value *valueToUse = 0;
+
// Perform a copy if necessary.
if (shouldCopy) {
- LValue srcLV = CGF.MakeAddrLValue(srcAddr, srcAddrType);
RValue srcRV = CGF.EmitLoadOfLValue(srcLV);
assert(srcRV.isScalar());
@@ -1892,15 +1941,37 @@ static void emitWritebackArg(CodeGenFunction &CGF, CallArgList &args,
// Use an ordinary store, not a store-to-lvalue.
CGF.Builder.CreateStore(src, temp);
+
+ // If optimization is enabled, and the value was held in a
+ // __strong variable, we need to tell the optimizer that this
+ // value has to stay alive until we're doing the store back.
+ // This is because the temporary is effectively unretained,
+ // and so otherwise we can violate the high-level semantics.
+ if (CGF.CGM.getCodeGenOpts().OptimizationLevel != 0 &&
+ srcLV.getObjCLifetime() == Qualifiers::OCL_Strong) {
+ valueToUse = src;
+ }
}
// Finish the control flow if we needed it.
if (shouldCopy && !provablyNonNull) {
+ llvm::BasicBlock *copyBB = CGF.Builder.GetInsertBlock();
CGF.EmitBlock(contBB);
+
+ // Make a phi for the value to intrinsically use.
+ if (valueToUse) {
+ llvm::PHINode *phiToUse = CGF.Builder.CreatePHI(valueToUse->getType(), 2,
+ "icr.to-use");
+ phiToUse->addIncoming(valueToUse, copyBB);
+ phiToUse->addIncoming(llvm::UndefValue::get(valueToUse->getType()),
+ originBB);
+ valueToUse = phiToUse;
+ }
+
condEval.end(CGF);
}
- args.addWriteback(srcAddr, srcAddrType, temp);
+ args.addWriteback(srcLV, temp, valueToUse);
args.add(RValue::get(finalArgument), CRE->getType());
}