From: John McCall Date: Sat, 14 May 2011 21:12:11 +0000 (+0000) Subject: Only perform the null-initialization of an aggregate result of a message X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=cba681af356e24ec4335bcf2b6bb6515072ace99;p=clang Only perform the null-initialization of an aggregate result of a message send if the receiver is null. Normally it's not worthwhile to check this, but avoiding the null-initialization is nice, and this also avoids nasty problems where the null-initialization is visible within the call because we use an aliased result buffer. rdar://problem/9402992 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@131366 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/CodeGen/CGObjCMac.cpp b/lib/CodeGen/CGObjCMac.cpp index 137f724c99..7cb51e2611 100644 --- a/lib/CodeGen/CGObjCMac.cpp +++ b/lib/CodeGen/CGObjCMac.cpp @@ -43,18 +43,6 @@ using namespace clang; using namespace CodeGen; -static void EmitNullReturnInitialization(CodeGenFunction &CGF, - ReturnValueSlot &returnSlot, - QualType resultType) { - // Force the return slot to exist. - if (!returnSlot.getValue()) - returnSlot = ReturnValueSlot(CGF.CreateMemTemp(resultType), false); - CGF.EmitNullInitialization(returnSlot.getValue(), resultType); -} - - -/// - namespace { typedef std::vector ConstantVector; @@ -1351,6 +1339,46 @@ public: const ObjCIvarDecl *Ivar); }; +/// A helper class for performing the null-initialization of a return +/// value. +struct NullReturnState { + llvm::BasicBlock *NullBB; + + NullReturnState() : NullBB(0) {} + + void init(CodeGenFunction &CGF, llvm::Value *receiver) { + // Make blocks for the null-init and call edges. + NullBB = CGF.createBasicBlock("msgSend.nullinit"); + llvm::BasicBlock *callBB = CGF.createBasicBlock("msgSend.call"); + + // Check for a null receiver and, if there is one, jump to the + // null-init test. + llvm::Value *isNull = CGF.Builder.CreateIsNull(receiver); + CGF.Builder.CreateCondBr(isNull, NullBB, callBB); + + // Otherwise, start performing the call. + CGF.EmitBlock(callBB); + } + + RValue complete(CodeGenFunction &CGF, RValue result, QualType resultType) { + if (!NullBB) return result; + + // Finish the call path. + llvm::BasicBlock *contBB = CGF.createBasicBlock("msgSend.cont"); + if (CGF.HaveInsertPoint()) CGF.Builder.CreateBr(contBB); + + // Emit the null-init block and perform the null-initialization there. + CGF.EmitBlock(NullBB); + assert(result.isAggregate() && "null init of non-aggregate result?"); + CGF.EmitNullInitialization(result.getAggregateAddr(), resultType); + + // Jump to the continuation block. + CGF.EmitBlock(contBB); + + return result; + } +}; + } // end anonymous namespace /* *** Helper Functions *** */ @@ -1541,9 +1569,11 @@ CGObjCCommonMac::EmitMessageSend(CodeGen::CodeGenFunction &CGF, CGM.getContext().getCanonicalType(ResultType) && "Result type mismatch!"); + NullReturnState nullReturn; + llvm::Constant *Fn = NULL; if (CGM.ReturnTypeUsesSRet(FnInfo)) { - EmitNullReturnInitialization(CGF, Return, ResultType); + if (!IsSuper) nullReturn.init(CGF, Arg0); Fn = (ObjCABI == 2) ? ObjCTypes.getSendStretFn2(IsSuper) : ObjCTypes.getSendStretFn(IsSuper); } else if (CGM.ReturnTypeUsesFPRet(ResultType)) { @@ -1554,7 +1584,8 @@ CGObjCCommonMac::EmitMessageSend(CodeGen::CodeGenFunction &CGF, : ObjCTypes.getSendFn(IsSuper); } Fn = llvm::ConstantExpr::getBitCast(Fn, llvm::PointerType::getUnqual(FTy)); - return CGF.EmitCall(FnInfo, Fn, Return, ActualArgs); + RValue rvalue = CGF.EmitCall(FnInfo, Fn, Return, ActualArgs); + return nullReturn.complete(CGF, rvalue, ResultType); } static Qualifiers::GC GetGCAttrTypeForType(ASTContext &Ctx, QualType FQT) { @@ -5590,6 +5621,8 @@ CGObjCNonFragileABIMac::EmitVTableMessageSend(CodeGenFunction &CGF, CGM.getTypes().getFunctionInfo(resultType, args, FunctionType::ExtInfo()); + NullReturnState nullReturn; + // Find the function to call and the mangled name for the message // ref structure. Using a different mangled name wouldn't actually // be a problem; it would just be a waste. @@ -5600,11 +5633,11 @@ CGObjCNonFragileABIMac::EmitVTableMessageSend(CodeGenFunction &CGF, llvm::Constant *fn = 0; std::string messageRefName("\01l_"); if (CGM.ReturnTypeUsesSRet(fnInfo)) { - EmitNullReturnInitialization(CGF, returnSlot, resultType); if (isSuper) { fn = ObjCTypes.getMessageSendSuper2StretFixupFn(); messageRefName += "objc_msgSendSuper2_stret_fixup"; } else { + nullReturn.init(CGF, arg0); fn = ObjCTypes.getMessageSendStretFixupFn(); messageRefName += "objc_msgSend_stret_fixup"; } @@ -5660,7 +5693,8 @@ CGObjCNonFragileABIMac::EmitVTableMessageSend(CodeGenFunction &CGF, callee = CGF.Builder.CreateBitCast(callee, llvm::PointerType::getUnqual(fnType)); - return CGF.EmitCall(fnInfo, callee, returnSlot, args); + RValue result = CGF.EmitCall(fnInfo, callee, returnSlot, args); + return nullReturn.complete(CGF, result, resultType); } /// Generate code for a message send expression in the nonfragile abi. diff --git a/test/CodeGenObjC/messages-2.m b/test/CodeGenObjC/messages-2.m index 5ef2261b19..e4e8cfb5e2 100644 --- a/test/CodeGenObjC/messages-2.m +++ b/test/CodeGenObjC/messages-2.m @@ -147,17 +147,29 @@ typedef struct { // rdar://problem/7854674 // CHECK: define void @test0([[A:%.*]]* // CHECK-NF: define void @test0([[A:%.*]]* -void test0(A *a) { - // CHECK: alloca [[A]]* +void test0(A *x) { + // CHECK: [[X:%.*]] = alloca [[A]]* // CHECK-NEXT: [[POINT:%.*]] = alloca [[POINT_T:%.*]], - // CHECK-NF: alloca [[A]]* - // CHECK-NF-NEXT: [[POINT:%.*]] = alloca [[POINT_T:%.*]], - + // CHECK: [[T0:%.*]] = load [[A]]** [[X]] + // CHECK: [[T1:%.*]] = bitcast [[A]]* [[T0]] to i8* + // CHECK-NEXT: icmp eq i8* [[T1]], null + // CHECK-NEXT: br i1 + // CHECK: call {{.*}} @objc_msgSend_stret to + // CHECK-NEXT: br label // CHECK: [[T0:%.*]] = bitcast [[POINT_T]]* [[POINT]] to i8* // CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* [[T0]], i8 0, i64 48, i32 4, i1 false) - // CHECK-NEXT: call {{.*}} @objc_msgSend_stret to + // CHECK-NEXT: br label + + // CHECK-NF: [[X:%.*]] = alloca [[A]]* + // CHECK-NF-NEXT: [[POINT:%.*]] = alloca [[POINT_T:%.*]], + // CHECK-NF: [[T0:%.*]] = load [[A]]** [[X]] + // CHECK-NF: [[T1:%.*]] = bitcast [[A]]* [[T0]] to i8* + // CHECK-NF-NEXT: icmp eq i8* [[T1]], null + // CHECK-NF-NEXT: br i1 + // CHECK-NF: call {{.*}} @objc_msgSend_stret to + // CHECK-NF-NEXT: br label // CHECK-NF: [[T0:%.*]] = bitcast [[POINT_T]]* [[POINT]] to i8* // CHECK-NF-NEXT: call void @llvm.memset.p0i8.i64(i8* [[T0]], i8 0, i64 48, i32 4, i1 false) - // CHECK-NF-NEXT: call {{.*}} @objc_msgSend_stret to - MyPoint point = [a returnAPoint]; + // CHECK-NF-NEXT: br label + MyPoint point = [x returnAPoint]; }