diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp index 3b1a82e67f..c98ee17842 100644 --- a/lib/CodeGen/CGExpr.cpp +++ b/lib/CodeGen/CGExpr.cpp @@ -2068,22 +2068,6 @@ LValue CodeGenFunction::EmitObjCIvarRefLValue(const ObjCIvarRefExpr *E) { return LV; } -LValue -CodeGenFunction::EmitObjCPropertyRefLValue(const ObjCPropertyRefExpr *E) { - // This is a special l-value that just issues sends when we load or - // store through it. - - // For certain base kinds, we need to emit the base immediately. - llvm::Value *Base; - if (E->isSuperReceiver()) - Base = 0; - else if (E->isClassReceiver()) - Base = CGM.getObjCRuntime().GetClass(Builder, E->getClassReceiver()); - else - Base = EmitScalarExpr(E->getBase()); - return LValue::MakePropertyRef(E, Base); -} - LValue CodeGenFunction::EmitStmtExprLValue(const StmtExpr *E) { // Can only get l-value for message expression returning aggregate type RValue RV = EmitAnyExprToTemp(E); diff --git a/lib/CodeGen/CGObjC.cpp b/lib/CodeGen/CGObjC.cpp index 4b2b8612e7..a8acb2b72f 100644 --- a/lib/CodeGen/CGObjC.cpp +++ b/lib/CodeGen/CGObjC.cpp @@ -509,23 +509,36 @@ QualType CodeGenFunction::TypeOfSelfObject() { return PTy->getPointeeType(); } -RValue CodeGenFunction::EmitObjCSuperPropertyGet(const Expr *Exp, - const Selector &S, - ReturnValueSlot Return) { - llvm::Value *Receiver = LoadObjCSelf(); - const ObjCMethodDecl *OMD = cast(CurFuncDecl); +LValue +CodeGenFunction::EmitObjCPropertyRefLValue(const ObjCPropertyRefExpr *E) { + // This is a special l-value that just issues sends when we load or + // store through it. + + // For certain base kinds, we need to emit the base immediately. + llvm::Value *Base; + if (E->isSuperReceiver()) + Base = LoadObjCSelf(); + else if (E->isClassReceiver()) + Base = CGM.getObjCRuntime().GetClass(Builder, E->getClassReceiver()); + else + Base = EmitScalarExpr(E->getBase()); + return LValue::MakePropertyRef(E, Base); +} + +static RValue GenerateMessageSendSuper(CodeGenFunction &CGF, + ReturnValueSlot Return, + QualType ResultType, + Selector S, + llvm::Value *Receiver, + const CallArgList &CallArgs) { + const ObjCMethodDecl *OMD = cast(CGF.CurFuncDecl); bool isClassMessage = OMD->isClassMethod(); bool isCategoryImpl = isa(OMD->getDeclContext()); - return CGM.getObjCRuntime().GenerateMessageSendSuper(*this, - Return, - Exp->getType(), - S, - OMD->getClassInterface(), - isCategoryImpl, - Receiver, - isClassMessage, - CallArgList()); - + return CGF.CGM.getObjCRuntime() + .GenerateMessageSendSuper(CGF, Return, ResultType, + S, OMD->getClassInterface(), + isCategoryImpl, Receiver, + isClassMessage, CallArgs); } RValue CodeGenFunction::EmitLoadOfPropertyRefLValue(LValue LV, @@ -543,10 +556,13 @@ RValue CodeGenFunction::EmitLoadOfPropertyRefLValue(LValue LV, ResultType = Getter->getResultType(); // with reference! } - if (E->isSuperReceiver()) - return EmitObjCSuperPropertyGet(E, S, Return); - llvm::Value *Receiver = LV.getPropertyRefBaseAddr(); + + // Accesses to 'super' follow a different code path. + if (E->isSuperReceiver()) + return GenerateMessageSendSuper(*this, Return, ResultType, + S, Receiver, CallArgList()); + const ObjCInterfaceDecl *ReceiverClass = (E->isClassReceiver() ? E->getClassReceiver() : 0); return CGM.getObjCRuntime(). @@ -554,27 +570,6 @@ RValue CodeGenFunction::EmitLoadOfPropertyRefLValue(LValue LV, Receiver, CallArgList(), ReceiverClass); } -void CodeGenFunction::EmitObjCSuperPropertySet(const Expr *Exp, - const Selector &S, - RValue Src) { - CallArgList Args; - llvm::Value *Receiver = LoadObjCSelf(); - const ObjCMethodDecl *OMD = cast(CurFuncDecl); - bool isClassMessage = OMD->isClassMethod(); - bool isCategoryImpl = isa(OMD->getDeclContext()); - Args.push_back(std::make_pair(Src, Exp->getType())); - CGM.getObjCRuntime().GenerateMessageSendSuper(*this, - ReturnValueSlot(), - getContext().VoidTy, - S, - OMD->getClassInterface(), - isCategoryImpl, - Receiver, - isClassMessage, - Args); - return; -} - void CodeGenFunction::EmitStoreThroughPropertyRefLValue(RValue Src, LValue Dst) { const ObjCPropertyRefExpr *E = Dst.getPropertyRefExpr(); @@ -588,20 +583,24 @@ void CodeGenFunction::EmitStoreThroughPropertyRefLValue(RValue Src, ArgType = E->getType(); } + CallArgList Args; + Args.push_back(std::make_pair(Src, ArgType)); + + llvm::Value *Receiver = Dst.getPropertyRefBaseAddr(); + QualType ResultType = getContext().VoidTy; + if (E->isSuperReceiver()) { - EmitObjCSuperPropertySet(E, S, Src); + GenerateMessageSendSuper(*this, ReturnValueSlot(), + ResultType, S, Receiver, Args); return; } - llvm::Value *Receiver = Dst.getPropertyRefBaseAddr(); const ObjCInterfaceDecl *ReceiverClass = (E->isClassReceiver() ? E->getClassReceiver() : 0); - CallArgList Args; - Args.push_back(std::make_pair(Src, ArgType)); CGM.getObjCRuntime().GenerateMessageSend(*this, ReturnValueSlot(), - getContext().VoidTy, S, - Receiver, Args, ReceiverClass); + ResultType, S, Receiver, Args, + ReceiverClass); } void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){ diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index 44124cb511..9730b0d4a8 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -1542,10 +1542,6 @@ public: llvm::Value *EmitObjCSelectorExpr(const ObjCSelectorExpr *E); RValue EmitObjCMessageExpr(const ObjCMessageExpr *E, ReturnValueSlot Return = ReturnValueSlot()); - RValue EmitObjCSuperPropertyGet(const Expr *Exp, const Selector &S, - ReturnValueSlot Return = ReturnValueSlot()); - void EmitObjCSuperPropertySet(const Expr *E, const Selector &S, RValue Src); - /// EmitReferenceBindingToExpr - Emits a reference binding to the passed in /// expression. Will emit a temporary variable if E is not an LValue. diff --git a/test/CodeGenObjC/property.m b/test/CodeGenObjC/property.m index 7160b16c44..1e7ca232be 100644 --- a/test/CodeGenObjC/property.m +++ b/test/CodeGenObjC/property.m @@ -1,4 +1,6 @@ -// RUN: %clang_cc1 -emit-llvm -o %t %s +// RUN: %clang_cc1 -emit-llvm -o - %s | FileCheck %s + +// TODO: actually test most of this instead of just emitting it int printf(const char *, ...); @@ -50,3 +52,28 @@ int printf(const char *, ...); return 10; } @end + +// Test that compound operations only compute the base once. +// CHECK: define void @test2 +A *test2_helper(void); +void test2() { + // CHECK: [[BASE:%.*]] = call [[A:%.*]]* @test2_helper() + // CHECK-NEXT: [[SEL:%.*]] = load i8** + // CHECK-NEXT: [[BASETMP:%.*]] = bitcast [[A]]* [[BASE]] to i8* + // CHECK-NEXT: [[LD:%.*]] = call i32 bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i32 (i8*, i8*)*)(i8* [[BASETMP]], i8* [[SEL]]) + // CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[LD]], 1 + // CHECK-NEXT: [[SEL:%.*]] = load i8** + // CHECK-NEXT: [[BASETMP:%.*]] = bitcast [[A]]* [[BASE]] to i8* + // CHECK-NEXT: call void bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (i8*, i8*, i32)*)(i8* [[BASETMP]], i8* [[SEL]], i32 [[ADD]]) + test2_helper().dyn++; + + // CHECK: [[BASE:%.*]] = call [[A]]* @test2_helper() + // CHECK-NEXT: [[SEL:%.*]] = load i8** + // CHECK-NEXT: [[BASETMP:%.*]] = bitcast [[A]]* [[BASE]] to i8* + // CHECK-NEXT: [[LD:%.*]] = call i32 bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i32 (i8*, i8*)*)(i8* [[BASETMP]], i8* [[SEL]]) + // CHECK-NEXT: [[ADD:%.*]] = mul nsw i32 [[LD]], 10 + // CHECK-NEXT: [[SEL:%.*]] = load i8** + // CHECK-NEXT: [[BASETMP:%.*]] = bitcast [[A]]* [[BASE]] to i8* + // CHECK-NEXT: call void bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (i8*, i8*, i32)*)(i8* [[BASETMP]], i8* [[SEL]], i32 [[ADD]]) + test2_helper().dyn *= 10; +}