Skip to content

Commit 0692a32

Browse files
committed
Test case for the l-value base only being evaluated once.
Also, move the l-value emission code into CGObjC.cpp and teach it, for completeness, to store away self for a super send. Also, inline the super cases for property gets and sets and make them use the correct result type for implicit getter/setter calls. llvm-svn: 120887
1 parent 87408b6 commit 0692a32

File tree

4 files changed

+71
-65
lines changed

4 files changed

+71
-65
lines changed

clang/lib/CodeGen/CGExpr.cpp

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2068,22 +2068,6 @@ LValue CodeGenFunction::EmitObjCIvarRefLValue(const ObjCIvarRefExpr *E) {
20682068
return LV;
20692069
}
20702070

2071-
LValue
2072-
CodeGenFunction::EmitObjCPropertyRefLValue(const ObjCPropertyRefExpr *E) {
2073-
// This is a special l-value that just issues sends when we load or
2074-
// store through it.
2075-
2076-
// For certain base kinds, we need to emit the base immediately.
2077-
llvm::Value *Base;
2078-
if (E->isSuperReceiver())
2079-
Base = 0;
2080-
else if (E->isClassReceiver())
2081-
Base = CGM.getObjCRuntime().GetClass(Builder, E->getClassReceiver());
2082-
else
2083-
Base = EmitScalarExpr(E->getBase());
2084-
return LValue::MakePropertyRef(E, Base);
2085-
}
2086-
20872071
LValue CodeGenFunction::EmitStmtExprLValue(const StmtExpr *E) {
20882072
// Can only get l-value for message expression returning aggregate type
20892073
RValue RV = EmitAnyExprToTemp(E);

clang/lib/CodeGen/CGObjC.cpp

Lines changed: 43 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -509,23 +509,36 @@ QualType CodeGenFunction::TypeOfSelfObject() {
509509
return PTy->getPointeeType();
510510
}
511511

512-
RValue CodeGenFunction::EmitObjCSuperPropertyGet(const Expr *Exp,
513-
const Selector &S,
514-
ReturnValueSlot Return) {
515-
llvm::Value *Receiver = LoadObjCSelf();
516-
const ObjCMethodDecl *OMD = cast<ObjCMethodDecl>(CurFuncDecl);
512+
LValue
513+
CodeGenFunction::EmitObjCPropertyRefLValue(const ObjCPropertyRefExpr *E) {
514+
// This is a special l-value that just issues sends when we load or
515+
// store through it.
516+
517+
// For certain base kinds, we need to emit the base immediately.
518+
llvm::Value *Base;
519+
if (E->isSuperReceiver())
520+
Base = LoadObjCSelf();
521+
else if (E->isClassReceiver())
522+
Base = CGM.getObjCRuntime().GetClass(Builder, E->getClassReceiver());
523+
else
524+
Base = EmitScalarExpr(E->getBase());
525+
return LValue::MakePropertyRef(E, Base);
526+
}
527+
528+
static RValue GenerateMessageSendSuper(CodeGenFunction &CGF,
529+
ReturnValueSlot Return,
530+
QualType ResultType,
531+
Selector S,
532+
llvm::Value *Receiver,
533+
const CallArgList &CallArgs) {
534+
const ObjCMethodDecl *OMD = cast<ObjCMethodDecl>(CGF.CurFuncDecl);
517535
bool isClassMessage = OMD->isClassMethod();
518536
bool isCategoryImpl = isa<ObjCCategoryImplDecl>(OMD->getDeclContext());
519-
return CGM.getObjCRuntime().GenerateMessageSendSuper(*this,
520-
Return,
521-
Exp->getType(),
522-
S,
523-
OMD->getClassInterface(),
524-
isCategoryImpl,
525-
Receiver,
526-
isClassMessage,
527-
CallArgList());
528-
537+
return CGF.CGM.getObjCRuntime()
538+
.GenerateMessageSendSuper(CGF, Return, ResultType,
539+
S, OMD->getClassInterface(),
540+
isCategoryImpl, Receiver,
541+
isClassMessage, CallArgs);
529542
}
530543

531544
RValue CodeGenFunction::EmitLoadOfPropertyRefLValue(LValue LV,
@@ -543,38 +556,20 @@ RValue CodeGenFunction::EmitLoadOfPropertyRefLValue(LValue LV,
543556
ResultType = Getter->getResultType(); // with reference!
544557
}
545558

559+
llvm::Value *Receiver = LV.getPropertyRefBaseAddr();
560+
561+
// Accesses to 'super' follow a different code path.
546562
if (E->isSuperReceiver())
547-
return EmitObjCSuperPropertyGet(E, S, Return);
563+
return GenerateMessageSendSuper(*this, Return, ResultType,
564+
S, Receiver, CallArgList());
548565

549-
llvm::Value *Receiver = LV.getPropertyRefBaseAddr();
550566
const ObjCInterfaceDecl *ReceiverClass
551567
= (E->isClassReceiver() ? E->getClassReceiver() : 0);
552568
return CGM.getObjCRuntime().
553569
GenerateMessageSend(*this, Return, ResultType, S,
554570
Receiver, CallArgList(), ReceiverClass);
555571
}
556572

557-
void CodeGenFunction::EmitObjCSuperPropertySet(const Expr *Exp,
558-
const Selector &S,
559-
RValue Src) {
560-
CallArgList Args;
561-
llvm::Value *Receiver = LoadObjCSelf();
562-
const ObjCMethodDecl *OMD = cast<ObjCMethodDecl>(CurFuncDecl);
563-
bool isClassMessage = OMD->isClassMethod();
564-
bool isCategoryImpl = isa<ObjCCategoryImplDecl>(OMD->getDeclContext());
565-
Args.push_back(std::make_pair(Src, Exp->getType()));
566-
CGM.getObjCRuntime().GenerateMessageSendSuper(*this,
567-
ReturnValueSlot(),
568-
getContext().VoidTy,
569-
S,
570-
OMD->getClassInterface(),
571-
isCategoryImpl,
572-
Receiver,
573-
isClassMessage,
574-
Args);
575-
return;
576-
}
577-
578573
void CodeGenFunction::EmitStoreThroughPropertyRefLValue(RValue Src,
579574
LValue Dst) {
580575
const ObjCPropertyRefExpr *E = Dst.getPropertyRefExpr();
@@ -588,20 +583,24 @@ void CodeGenFunction::EmitStoreThroughPropertyRefLValue(RValue Src,
588583
ArgType = E->getType();
589584
}
590585

586+
CallArgList Args;
587+
Args.push_back(std::make_pair(Src, ArgType));
588+
589+
llvm::Value *Receiver = Dst.getPropertyRefBaseAddr();
590+
QualType ResultType = getContext().VoidTy;
591+
591592
if (E->isSuperReceiver()) {
592-
EmitObjCSuperPropertySet(E, S, Src);
593+
GenerateMessageSendSuper(*this, ReturnValueSlot(),
594+
ResultType, S, Receiver, Args);
593595
return;
594596
}
595597

596-
llvm::Value *Receiver = Dst.getPropertyRefBaseAddr();
597598
const ObjCInterfaceDecl *ReceiverClass
598599
= (E->isClassReceiver() ? E->getClassReceiver() : 0);
599600

600-
CallArgList Args;
601-
Args.push_back(std::make_pair(Src, ArgType));
602601
CGM.getObjCRuntime().GenerateMessageSend(*this, ReturnValueSlot(),
603-
getContext().VoidTy, S,
604-
Receiver, Args, ReceiverClass);
602+
ResultType, S, Receiver, Args,
603+
ReceiverClass);
605604
}
606605

607606
void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){

clang/lib/CodeGen/CodeGenFunction.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1542,10 +1542,6 @@ class CodeGenFunction : public BlockFunction {
15421542
llvm::Value *EmitObjCSelectorExpr(const ObjCSelectorExpr *E);
15431543
RValue EmitObjCMessageExpr(const ObjCMessageExpr *E,
15441544
ReturnValueSlot Return = ReturnValueSlot());
1545-
RValue EmitObjCSuperPropertyGet(const Expr *Exp, const Selector &S,
1546-
ReturnValueSlot Return = ReturnValueSlot());
1547-
void EmitObjCSuperPropertySet(const Expr *E, const Selector &S, RValue Src);
1548-
15491545

15501546
/// EmitReferenceBindingToExpr - Emits a reference binding to the passed in
15511547
/// expression. Will emit a temporary variable if E is not an LValue.

clang/test/CodeGenObjC/property.m

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
// RUN: %clang_cc1 -emit-llvm -o %t %s
1+
// RUN: %clang_cc1 -emit-llvm -o - %s | FileCheck %s
2+
3+
// TODO: actually test most of this instead of just emitting it
24

35
int printf(const char *, ...);
46

@@ -50,3 +52,28 @@ -(int) dyn {
5052
return 10;
5153
}
5254
@end
55+
56+
// Test that compound operations only compute the base once.
57+
// CHECK: define void @test2
58+
A *test2_helper(void);
59+
void test2() {
60+
// CHECK: [[BASE:%.*]] = call [[A:%.*]]* @test2_helper()
61+
// CHECK-NEXT: [[SEL:%.*]] = load i8**
62+
// CHECK-NEXT: [[BASETMP:%.*]] = bitcast [[A]]* [[BASE]] to i8*
63+
// CHECK-NEXT: [[LD:%.*]] = call i32 bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i32 (i8*, i8*)*)(i8* [[BASETMP]], i8* [[SEL]])
64+
// CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[LD]], 1
65+
// CHECK-NEXT: [[SEL:%.*]] = load i8**
66+
// CHECK-NEXT: [[BASETMP:%.*]] = bitcast [[A]]* [[BASE]] to i8*
67+
// CHECK-NEXT: call void bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (i8*, i8*, i32)*)(i8* [[BASETMP]], i8* [[SEL]], i32 [[ADD]])
68+
test2_helper().dyn++;
69+
70+
// CHECK: [[BASE:%.*]] = call [[A]]* @test2_helper()
71+
// CHECK-NEXT: [[SEL:%.*]] = load i8**
72+
// CHECK-NEXT: [[BASETMP:%.*]] = bitcast [[A]]* [[BASE]] to i8*
73+
// CHECK-NEXT: [[LD:%.*]] = call i32 bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i32 (i8*, i8*)*)(i8* [[BASETMP]], i8* [[SEL]])
74+
// CHECK-NEXT: [[ADD:%.*]] = mul nsw i32 [[LD]], 10
75+
// CHECK-NEXT: [[SEL:%.*]] = load i8**
76+
// CHECK-NEXT: [[BASETMP:%.*]] = bitcast [[A]]* [[BASE]] to i8*
77+
// CHECK-NEXT: call void bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (i8*, i8*, i32)*)(i8* [[BASETMP]], i8* [[SEL]], i32 [[ADD]])
78+
test2_helper().dyn *= 10;
79+
}

0 commit comments

Comments
 (0)