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.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@120887 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
John McCall 2010-12-04 03:11:00 +00:00
Родитель 119a1c6c40
Коммит e68b9842d2
4 изменённых файлов: 72 добавлений и 66 удалений

Просмотреть файл

@ -2068,22 +2068,6 @@ LValue CodeGenFunction::EmitObjCIvarRefLValue(const ObjCIvarRefExpr *E) {
return LV; 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) { LValue CodeGenFunction::EmitStmtExprLValue(const StmtExpr *E) {
// Can only get l-value for message expression returning aggregate type // Can only get l-value for message expression returning aggregate type
RValue RV = EmitAnyExprToTemp(E); RValue RV = EmitAnyExprToTemp(E);

Просмотреть файл

@ -509,23 +509,36 @@ QualType CodeGenFunction::TypeOfSelfObject() {
return PTy->getPointeeType(); return PTy->getPointeeType();
} }
RValue CodeGenFunction::EmitObjCSuperPropertyGet(const Expr *Exp, LValue
const Selector &S, CodeGenFunction::EmitObjCPropertyRefLValue(const ObjCPropertyRefExpr *E) {
ReturnValueSlot Return) { // This is a special l-value that just issues sends when we load or
llvm::Value *Receiver = LoadObjCSelf(); // store through it.
const ObjCMethodDecl *OMD = cast<ObjCMethodDecl>(CurFuncDecl);
// 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 isClassMessage = OMD->isClassMethod();
bool isCategoryImpl = isa<ObjCCategoryImplDecl>(OMD->getDeclContext()); bool isCategoryImpl = isa<ObjCCategoryImplDecl>(OMD->getDeclContext());
return CGM.getObjCRuntime().GenerateMessageSendSuper(*this, return CGF.CGM.getObjCRuntime()
Return, .GenerateMessageSendSuper(CGF, Return, ResultType,
Exp->getType(), S, OMD->getClassInterface(),
S, isCategoryImpl, Receiver,
OMD->getClassInterface(), isClassMessage, CallArgs);
isCategoryImpl,
Receiver,
isClassMessage,
CallArgList());
} }
RValue CodeGenFunction::EmitLoadOfPropertyRefLValue(LValue LV, RValue CodeGenFunction::EmitLoadOfPropertyRefLValue(LValue LV,
@ -543,10 +556,13 @@ RValue CodeGenFunction::EmitLoadOfPropertyRefLValue(LValue LV,
ResultType = Getter->getResultType(); // with reference! ResultType = Getter->getResultType(); // with reference!
} }
if (E->isSuperReceiver())
return EmitObjCSuperPropertyGet(E, S, Return);
llvm::Value *Receiver = LV.getPropertyRefBaseAddr(); 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 const ObjCInterfaceDecl *ReceiverClass
= (E->isClassReceiver() ? E->getClassReceiver() : 0); = (E->isClassReceiver() ? E->getClassReceiver() : 0);
return CGM.getObjCRuntime(). return CGM.getObjCRuntime().
@ -554,27 +570,6 @@ RValue CodeGenFunction::EmitLoadOfPropertyRefLValue(LValue LV,
Receiver, CallArgList(), ReceiverClass); 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, void CodeGenFunction::EmitStoreThroughPropertyRefLValue(RValue Src,
LValue Dst) { LValue Dst) {
const ObjCPropertyRefExpr *E = Dst.getPropertyRefExpr(); const ObjCPropertyRefExpr *E = Dst.getPropertyRefExpr();
@ -588,20 +583,24 @@ void CodeGenFunction::EmitStoreThroughPropertyRefLValue(RValue Src,
ArgType = E->getType(); 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()) { if (E->isSuperReceiver()) {
EmitObjCSuperPropertySet(E, S, Src); GenerateMessageSendSuper(*this, ReturnValueSlot(),
ResultType, S, Receiver, Args);
return; return;
} }
llvm::Value *Receiver = Dst.getPropertyRefBaseAddr();
const ObjCInterfaceDecl *ReceiverClass const ObjCInterfaceDecl *ReceiverClass
= (E->isClassReceiver() ? E->getClassReceiver() : 0); = (E->isClassReceiver() ? E->getClassReceiver() : 0);
CallArgList Args;
Args.push_back(std::make_pair(Src, ArgType));
CGM.getObjCRuntime().GenerateMessageSend(*this, ReturnValueSlot(), CGM.getObjCRuntime().GenerateMessageSend(*this, ReturnValueSlot(),
getContext().VoidTy, S, ResultType, S, Receiver, Args,
Receiver, Args, ReceiverClass); ReceiverClass);
} }
void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){

Просмотреть файл

@ -1542,10 +1542,6 @@ public:
llvm::Value *EmitObjCSelectorExpr(const ObjCSelectorExpr *E); llvm::Value *EmitObjCSelectorExpr(const ObjCSelectorExpr *E);
RValue EmitObjCMessageExpr(const ObjCMessageExpr *E, RValue EmitObjCMessageExpr(const ObjCMessageExpr *E,
ReturnValueSlot Return = ReturnValueSlot()); 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 /// EmitReferenceBindingToExpr - Emits a reference binding to the passed in
/// expression. Will emit a temporary variable if E is not an LValue. /// expression. Will emit a temporary variable if E is not an LValue.

Просмотреть файл

@ -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 *, ...); int printf(const char *, ...);
@ -50,3 +52,28 @@ int printf(const char *, ...);
return 10; return 10;
} }
@end @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;
}