aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/CodeGen/CGExpr.cpp16
-rw-r--r--lib/CodeGen/CGObjC.cpp87
-rw-r--r--lib/CodeGen/CodeGenFunction.h4
-rw-r--r--test/CodeGenObjC/property.m29
4 files changed, 71 insertions, 65 deletions
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<ObjCMethodDecl>(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<ObjCMethodDecl>(CGF.CurFuncDecl);
bool isClassMessage = OMD->isClassMethod();
bool isCategoryImpl = isa<ObjCCategoryImplDecl>(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!
}
+ llvm::Value *Receiver = LV.getPropertyRefBaseAddr();
+
+ // Accesses to 'super' follow a different code path.
if (E->isSuperReceiver())
- return EmitObjCSuperPropertyGet(E, S, Return);
+ return GenerateMessageSendSuper(*this, Return, ResultType,
+ S, Receiver, CallArgList());
- llvm::Value *Receiver = LV.getPropertyRefBaseAddr();
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<ObjCMethodDecl>(CurFuncDecl);
- bool isClassMessage = OMD->isClassMethod();
- bool isCategoryImpl = isa<ObjCCategoryImplDecl>(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;
+}