зеркало из https://github.com/microsoft/clang-1.git
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:
Родитель
119a1c6c40
Коммит
e68b9842d2
|
@ -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);
|
||||
|
|
|
@ -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!
|
||||
}
|
||||
|
||||
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<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){
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче