diff --git a/lib/CodeGen/CGObjCMac.cpp b/lib/CodeGen/CGObjCMac.cpp index 2d67a77cfaa99e08161aae646525efd8174d853a..b61852765a671723b3d697320b9e93d79e8963c1 100644 --- a/lib/CodeGen/CGObjCMac.cpp +++ b/lib/CodeGen/CGObjCMac.cpp @@ -1547,16 +1547,18 @@ public: /// value. struct NullReturnState { llvm::BasicBlock *NullBB; - llvm::BasicBlock *callBB; - NullReturnState() : NullBB(0), callBB(0) {} + NullReturnState() : NullBB(0) {} + /// Perform a null-check of the given receiver. void init(CodeGenFunction &CGF, llvm::Value *receiver) { - // Make blocks for the null-init and call edges. - NullBB = CGF.createBasicBlock("msgSend.nullinit"); - callBB = CGF.createBasicBlock("msgSend.call"); + // Make blocks for the null-receiver and call edges. + NullBB = CGF.createBasicBlock("msgSend.null-receiver"); + llvm::BasicBlock *callBB = CGF.createBasicBlock("msgSend.call"); // Check for a null receiver and, if there is one, jump to the - // null-init test. + // null-receiver block. There's no point in trying to avoid it: + // we're always going to put *something* there, because otherwise + // we shouldn't have done this null-check in the first place. llvm::Value *isNull = CGF.Builder.CreateIsNull(receiver); CGF.Builder.CreateCondBr(isNull, NullBB, callBB); @@ -1564,25 +1566,29 @@ struct NullReturnState { CGF.EmitBlock(callBB); } + /// Complete the null-return operation. It is valid to call this + /// regardless of whether 'init' has been called. RValue complete(CodeGenFunction &CGF, RValue result, QualType resultType, const CallArgList &CallArgs, const ObjCMethodDecl *Method) { + // If we never had to do a null-check, just use the raw result. if (!NullBB) return result; - - llvm::Value *NullInitPtr = 0; - if (result.isScalar() && !resultType->isVoidType()) { - NullInitPtr = CGF.CreateTempAlloca(result.getScalarVal()->getType()); - CGF.Builder.CreateStore(result.getScalarVal(), NullInitPtr); - } + // The continuation block. This will be left null if we don't have an + // IP, which can happen if the method we're calling is marked noreturn. + llvm::BasicBlock *contBB = 0; + // Finish the call path. - llvm::BasicBlock *contBB = CGF.createBasicBlock("msgSend.cont"); - if (CGF.HaveInsertPoint()) CGF.Builder.CreateBr(contBB); + llvm::BasicBlock *callBB = CGF.Builder.GetInsertBlock(); + if (callBB) { + contBB = CGF.createBasicBlock("msgSend.cont"); + CGF.Builder.CreateBr(contBB); + } - // Emit the null-init block and perform the null-initialization there. + // Okay, start emitting the null-receiver block. CGF.EmitBlock(NullBB); - // Release consumed arguments along the null-receiver path. + // Release any consumed arguments we've got. if (Method) { CallArgList::const_iterator I = CallArgs.begin(); for (ObjCMethodDecl::param_const_iterator i = Method->param_begin(), @@ -1596,39 +1602,60 @@ struct NullReturnState { } } } - + + // The phi code below assumes that we haven't needed any control flow yet. + assert(CGF.Builder.GetInsertBlock() == NullBB); + + // If we've got a void return, just jump to the continuation block. + if (result.isScalar() && resultType->isVoidType()) { + // No jumps required if the message-send was noreturn. + if (contBB) CGF.EmitBlock(contBB); + return result; + } + + // If we've got a scalar return, build a phi. if (result.isScalar()) { - if (NullInitPtr) - CGF.EmitNullInitialization(NullInitPtr, resultType); - // Jump to the continuation block. + // Derive the null-initialization value. + llvm::Constant *null = CGF.CGM.EmitNullConstant(resultType); + + // If no join is necessary, just flow out. + if (!contBB) return RValue::get(null); + + // Otherwise, build a phi. CGF.EmitBlock(contBB); - return NullInitPtr ? RValue::get(CGF.Builder.CreateLoad(NullInitPtr)) - : result; + llvm::PHINode *phi = CGF.Builder.CreatePHI(null->getType(), 2); + phi->addIncoming(result.getScalarVal(), callBB); + phi->addIncoming(null, NullBB); + return RValue::get(phi); } - - if (!resultType->isAnyComplexType()) { + + // If we've got an aggregate return, null the buffer out. + // FIXME: maybe we should be doing things differently for all the + // cases where the ABI has us returning (1) non-agg values in + // memory or (2) agg values in registers. + if (result.isAggregate()) { assert(result.isAggregate() && "null init of non-aggregate result?"); CGF.EmitNullInitialization(result.getAggregateAddr(), resultType); - // Jump to the continuation block. - CGF.EmitBlock(contBB); + if (contBB) CGF.EmitBlock(contBB); return result; } - // _Complex type - // FIXME. Now easy to handle any other scalar type whose result is returned - // in memory due to ABI limitations. + // Complex types. CGF.EmitBlock(contBB); - CodeGenFunction::ComplexPairTy CallCV = result.getComplexVal(); - llvm::Type *MemberType = CallCV.first->getType(); - llvm::Constant *ZeroCV = llvm::Constant::getNullValue(MemberType); - // Create phi instruction for scalar complex value. - llvm::PHINode *PHIReal = CGF.Builder.CreatePHI(MemberType, 2); - PHIReal->addIncoming(ZeroCV, NullBB); - PHIReal->addIncoming(CallCV.first, callBB); - llvm::PHINode *PHIImag = CGF.Builder.CreatePHI(MemberType, 2); - PHIImag->addIncoming(ZeroCV, NullBB); - PHIImag->addIncoming(CallCV.second, callBB); - return RValue::getComplex(PHIReal, PHIImag); + CodeGenFunction::ComplexPairTy callResult = result.getComplexVal(); + + // Find the scalar type and its zero value. + llvm::Type *scalarTy = callResult.first->getType(); + llvm::Constant *scalarZero = llvm::Constant::getNullValue(scalarTy); + + // Build phis for both coordinates. + llvm::PHINode *real = CGF.Builder.CreatePHI(scalarTy, 2); + real->addIncoming(callResult.first, callBB); + real->addIncoming(scalarZero, NullBB); + llvm::PHINode *imag = CGF.Builder.CreatePHI(scalarTy, 2); + imag->addIncoming(callResult.second, callBB); + imag->addIncoming(scalarZero, NullBB); + return RValue::getComplex(real, imag); } }; diff --git a/test/CodeGenObjC/complex-double-abi.m b/test/CodeGenObjC/complex-double-abi.m index 08246d5824f68cb9c18eec99f09dde0b1b9828c4..635352004021675d30819039ff5a2a157f0767d7 100644 --- a/test/CodeGenObjC/complex-double-abi.m +++ b/test/CodeGenObjC/complex-double-abi.m @@ -9,8 +9,7 @@ double _Complex foo(CNumber *x) { return [x sum]; } -// CHECK: [[T4:%.*]] = phi double [ 0.000000e+00, [[NULLINIT:%.*]] ], [ [[R1:%.*]], [[MSGCALL:%.*]] ] -// CHECK: [[T5:%.*]] = phi double [ 0.000000e+00, [[NULLINIT:%.*]] ], [ [[I1:%.*]], [[MSGCALL:%.*]] ] - -// CHECK: store double [[T4]] -// CHECK: store double [[T5]] +// CHECK: [[R:%.*]] = phi double [ [[R1:%.*]], [[MSGCALL:%.*]] ], [ 0.000000e+00, [[NULLINIT:%.*]] ] +// CHECK-NEXT: [[I:%.*]] = phi double [ [[I1:%.*]], [[MSGCALL]] ], [ 0.000000e+00, [[NULLINIT]] ] +// CHECK: store double [[R]] +// CHECK: store double [[I]] diff --git a/test/CodeGenObjC/ns_consume_null_check.m b/test/CodeGenObjC/ns_consume_null_check.m index a8e5acd57e61eb721434d1c46dedd21f45ac84aa..5328b9feb28796b61132ee3de61f5a17710cf67b 100644 --- a/test/CodeGenObjC/ns_consume_null_check.m +++ b/test/CodeGenObjC/ns_consume_null_check.m @@ -1,5 +1,4 @@ -// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-arc -fobjc-dispatch-method=mixed -o - %s | FileCheck %s -// rdar://10444476 +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-arc -fobjc-dispatch-method=mixed -fobjc-runtime-has-weak -fexceptions -o - %s | FileCheck %s @interface NSObject - (id) new; @@ -7,26 +6,78 @@ @interface MyObject : NSObject - (char)isEqual:(id) __attribute__((ns_consumed)) object; +- (_Complex float) asComplexWithArg: (id) __attribute__((ns_consumed)) object; @end MyObject *x; -void foo() -{ - id obj = [NSObject new]; - [x isEqual : obj]; +// rdar://10444476 +void test0(void) { + id obj = [NSObject new]; + [x isEqual : obj]; } - -// CHECK: [[TMP:%.*]] = alloca i8{{$}} -// CHECK: [[FIVE:%.*]] = call i8* @objc_retain +// CHECK: define void @test0() +// CHECK: [[FIVE:%.*]] = call i8* @objc_retain // CHECK-NEXT: [[SIX:%.*]] = bitcast // CHECK-NEXT: [[SEVEN:%.*]] = icmp eq i8* [[SIX]], null // CHECK-NEXT: br i1 [[SEVEN]], label [[NULLINIT:%.*]], label [[CALL_LABEL:%.*]] -// CHECK: [[FN:%.*]] = load i8** getelementptr inbounds +// CHECK: [[FN:%.*]] = load i8** getelementptr inbounds // CHECK-NEXT: [[EIGHT:%.*]] = bitcast i8* [[FN]] // CHECK-NEXT: [[CALL:%.*]] = call signext i8 [[EIGHT]] -// CHECK-NEXT: store i8 [[CALL]], i8* [[TMP]] // CHECK-NEXT: br label [[CONT:%.*]] -// CHECK: call void @objc_release(i8* [[FIVE]]) nounwind -// CHECK-NEXT: call void @llvm.memset +// CHECK: call void @objc_release(i8* [[FIVE]]) nounwind // CHECK-NEXT: br label [[CONT]] +// CHECK: phi i8 [ [[CALL]], {{%.*}} ], [ 0, {{%.*}} ] + +// Ensure that we build PHIs correctly in the presence of cleanups. +// rdar://12046763 +void test1(void) { + id obj = [NSObject new]; + __weak id weakObj = obj; + _Complex float result = [x asComplexWithArg: obj]; +} +// CHECK: define void @test1() +// CHECK: [[OBJ:%.*]] = alloca i8*, align 8 +// CHECK-NEXT: [[WEAKOBJ:%.*]] = alloca i8*, align 8 +// CHECK-NEXT: [[RESULT:%.*]] = alloca { float, float }, align 4 +// Various initializations. +// CHECK: [[T0:%.*]] = call i8* bitcast ( +// CHECK-NEXT: store i8* [[T0]], i8** [[OBJ]] +// CHECK-NEXT: [[T0:%.*]] = load i8** [[OBJ]] +// CHECK-NEXT: call i8* @objc_initWeak(i8** [[WEAKOBJ]], i8* [[T0]]) nounwind +// Okay, start the message-send. +// CHECK-NEXT: [[T0:%.*]] = load [[MYOBJECT:%.*]]** @x +// CHECK-NEXT: [[ARG:%.*]] = load i8** [[OBJ]] +// CHECK-NEXT: [[ARG_RETAINED:%.*]] = call i8* @objc_retain(i8* [[ARG]]) +// CHECK-NEXT: load i8** @ +// CHECK-NEXT: [[SELF:%.*]] = bitcast [[MYOBJECT]]* [[T0]] to i8* +// Null check. +// CHECK-NEXT: [[T0:%.*]] = icmp eq i8* [[SELF]], null +// CHECK-NEXT: br i1 [[T0]], label [[FORNULL:%.*]], label [[FORCALL:%.*]] +// Invoke and produce the return values. +// CHECK: [[CALL:%.*]] = invoke <2 x float> bitcast +// CHECK-NEXT: to label [[INVOKE_CONT:%.*]] unwind label {{%.*}} +// CHECK: [[T0:%.*]] = bitcast { float, float }* [[COERCE:%.*]] to <2 x float>* +// CHECK-NEXT: store <2 x float> [[CALL]], <2 x float>* [[T0]], +// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds { float, float }* [[COERCE]], i32 0, i32 0 +// CHECK-NEXT: [[REALCALL:%.*]] = load float* [[T0]] +// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds { float, float }* [[COERCE]], i32 0, i32 1 +// CHECK-NEXT: [[IMAGCALL:%.*]] = load float* [[T0]] +// CHECK-NEXT: br label [[CONT:%.*]]{{$}} +// Null path. +// CHECK: call void @objc_release(i8* [[ARG_RETAINED]]) nounwind +// CHECK-NEXT: br label [[CONT]] +// Join point. +// CHECK: [[REAL:%.*]] = phi float [ [[REALCALL]], [[INVOKE_CONT]] ], [ 0.000000e+00, [[FORNULL]] ] +// CHECK-NEXT: [[IMAG:%.*]] = phi float [ [[IMAGCALL]], [[INVOKE_CONT]] ], [ 0.000000e+00, [[FORNULL]] ] +// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds { float, float }* [[RESULT]], i32 0, i32 0 +// CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds { float, float }* [[RESULT]], i32 0, i32 1 +// CHECK-NEXT: store float [[REAL]], float* [[T0]] +// CHECK-NEXT: store float [[IMAG]], float* [[T1]] +// Epilogue. +// CHECK-NEXT: call void @objc_destroyWeak(i8** [[WEAKOBJ]]) nounwind +// CHECK-NEXT: call void @objc_storeStrong(i8** [[OBJ]], i8* null) nounwind +// CHECK-NEXT: ret void +// Cleanup. +// CHECK: landingpad +// CHECK: call void @objc_destroyWeak(i8** [[WEAKOBJ]]) nounwind