зеркало из 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;
|
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;
|
||||||
|
}
|
||||||
|
|
Загрузка…
Ссылка в новой задаче