[cfe-commits] r107210 - in /cfe/trunk: lib/CodeGen/CGExprScalar.cpp test/CodeGen/assign.c test/CodeGen/object-size.c test/CodeGenCXX/member-init-assignment.cpp test/CodeGenObjC/assign.m
Daniel Dunbar
daniel at zuster.org
Tue Jun 29 15:00:45 PDT 2010
Author: ddunbar
Date: Tue Jun 29 17:00:45 2010
New Revision: 107210
URL: http://llvm.org/viewvc/llvm-project?rev=107210&view=rev
Log:
IRgen: Assignment to Objective-C properties shouldn't reload the value (which
would trigger an extra method call).
- While in the area, I also changed Clang to not emit an unnecessary load from
'x' in cases like 'y = (x = 1)'.
Added:
cfe/trunk/test/CodeGen/assign.c
cfe/trunk/test/CodeGenObjC/assign.m
Modified:
cfe/trunk/lib/CodeGen/CGExprScalar.cpp
cfe/trunk/test/CodeGen/object-size.c
cfe/trunk/test/CodeGenCXX/member-init-assignment.cpp
Modified: cfe/trunk/lib/CodeGen/CGExprScalar.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprScalar.cpp?rev=107210&r1=107209&r2=107210&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGExprScalar.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExprScalar.cpp Tue Jun 29 17:00:45 2010
@@ -334,7 +334,7 @@
BinOpInfo EmitBinOps(const BinaryOperator *E);
LValue EmitCompoundAssignLValue(const CompoundAssignOperator *E,
Value *(ScalarExprEmitter::*F)(const BinOpInfo &),
- Value *&BitFieldResult);
+ Value *&Result);
Value *EmitCompoundAssign(const CompoundAssignOperator *E,
Value *(ScalarExprEmitter::*F)(const BinOpInfo &));
@@ -1342,9 +1342,8 @@
LValue ScalarExprEmitter::EmitCompoundAssignLValue(
const CompoundAssignOperator *E,
Value *(ScalarExprEmitter::*Func)(const BinOpInfo &),
- Value *&BitFieldResult) {
+ Value *&Result) {
QualType LHSTy = E->getLHS()->getType();
- BitFieldResult = 0;
BinOpInfo OpInfo;
if (E->getComputationResultType()->isAnyComplexType()) {
@@ -1353,7 +1352,7 @@
// actually need the imaginary part of the RHS for multiplication and
// division.)
CGF.ErrorUnsupported(E, "complex compound assignment");
- llvm::UndefValue::get(CGF.ConvertType(E->getType()));
+ Result = llvm::UndefValue::get(CGF.ConvertType(E->getType()));
return LValue();
}
@@ -1370,7 +1369,7 @@
E->getComputationLHSType());
// Expand the binary operator.
- Value *Result = (this->*Func)(OpInfo);
+ Result = (this->*Func)(OpInfo);
// Convert the result back to the LHS type.
Result = EmitScalarConversion(Result, E->getComputationResultType(), LHSTy);
@@ -1379,30 +1378,35 @@
// specially because the result is altered by the store, i.e., [C99 6.5.16p1]
// 'An assignment expression has the value of the left operand after the
// assignment...'.
- if (LHSLV.isBitField()) {
- if (!LHSLV.isVolatileQualified()) {
- CGF.EmitStoreThroughBitfieldLValue(RValue::get(Result), LHSLV, LHSTy,
- &Result);
- BitFieldResult = Result;
- return LHSLV;
- } else
- CGF.EmitStoreThroughBitfieldLValue(RValue::get(Result), LHSLV, LHSTy);
- } else
+ if (LHSLV.isBitField())
+ CGF.EmitStoreThroughBitfieldLValue(RValue::get(Result), LHSLV, LHSTy,
+ &Result);
+ else
CGF.EmitStoreThroughLValue(RValue::get(Result), LHSLV, LHSTy);
+
return LHSLV;
}
Value *ScalarExprEmitter::EmitCompoundAssign(const CompoundAssignOperator *E,
Value *(ScalarExprEmitter::*Func)(const BinOpInfo &)) {
bool Ignore = TestAndClearIgnoreResultAssign();
- Value *BitFieldResult;
- LValue LHSLV = EmitCompoundAssignLValue(E, Func, BitFieldResult);
- if (BitFieldResult)
- return BitFieldResult;
-
+ Value *RHS;
+ LValue LHS = EmitCompoundAssignLValue(E, Func, RHS);
+
+ // If the result is clearly ignored, return now.
if (Ignore)
return 0;
- return EmitLoadOfLValue(LHSLV, E->getType());
+
+ // Objective-C property assignment never reloads the value following a store.
+ if (LHS.isPropertyRef() || LHS.isKVCRef())
+ return RHS;
+
+ // If the lvalue is non-volatile, return the computed value of the assignment.
+ if (!LHS.isVolatileQualified())
+ return RHS;
+
+ // Otherwise, reload the value.
+ return EmitLoadOfLValue(LHS, E->getType());
}
@@ -1838,17 +1842,25 @@
// because the result is altered by the store, i.e., [C99 6.5.16p1]
// 'An assignment expression has the value of the left operand after
// the assignment...'.
- if (LHS.isBitField()) {
- if (!LHS.isVolatileQualified()) {
- CGF.EmitStoreThroughBitfieldLValue(RValue::get(RHS), LHS, E->getType(),
- &RHS);
- return RHS;
- } else
- CGF.EmitStoreThroughBitfieldLValue(RValue::get(RHS), LHS, E->getType());
- } else
+ if (LHS.isBitField())
+ CGF.EmitStoreThroughBitfieldLValue(RValue::get(RHS), LHS, E->getType(),
+ &RHS);
+ else
CGF.EmitStoreThroughLValue(RValue::get(RHS), LHS, E->getType());
+
+ // If the result is clearly ignored, return now.
if (Ignore)
return 0;
+
+ // Objective-C property assignment never reloads the value following a store.
+ if (LHS.isPropertyRef() || LHS.isKVCRef())
+ return RHS;
+
+ // If the lvalue is non-volatile, return the computed value of the assignment.
+ if (!LHS.isVolatileQualified())
+ return RHS;
+
+ // Otherwise, reload the value.
return EmitLoadOfLValue(LHS, E->getType());
}
@@ -2188,12 +2200,12 @@
LValue CodeGenFunction::EmitCompoundAssignOperatorLValue(
const CompoundAssignOperator *E) {
ScalarExprEmitter Scalar(*this);
- Value *BitFieldResult = 0;
+ Value *Result = 0;
switch (E->getOpcode()) {
#define COMPOUND_OP(Op) \
case BinaryOperator::Op##Assign: \
return Scalar.EmitCompoundAssignLValue(E, &ScalarExprEmitter::Emit##Op, \
- BitFieldResult)
+ Result)
COMPOUND_OP(Mul);
COMPOUND_OP(Div);
COMPOUND_OP(Rem);
Added: cfe/trunk/test/CodeGen/assign.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/assign.c?rev=107210&view=auto
==============================================================================
--- cfe/trunk/test/CodeGen/assign.c (added)
+++ cfe/trunk/test/CodeGen/assign.c Tue Jun 29 17:00:45 2010
@@ -0,0 +1,32 @@
+// RUN: %clang_cc1 -triple x86_64 -emit-llvm -o - %s | FileCheck %s
+
+// Check that we don't generate unnecessary reloads.
+//
+// CHECK: define void @f0()
+// CHECK: [[x_0:%.*]] = alloca i32, align 4
+// CHECK-NEXT: [[y_0:%.*]] = alloca i32, align 4
+// CHECK-NEXT: store i32 1, i32* [[x_0]]
+// CHECK-NEXT: store i32 1, i32* [[x_0]]
+// CHECK-NEXT: store i32 1, i32* [[y_0]]
+// CHECK: }
+void f0() {
+ int x, y;
+ x = 1;
+ y = (x = 1);
+}
+
+// Check that we do generate reloads for volatile access.
+//
+// CHECK: define void @f1()
+// CHECK: [[x_1:%.*]] = alloca i32, align 4
+// CHECK-NEXT: [[y_1:%.*]] = alloca i32, align 4
+// CHECK-NEXT: volatile store i32 1, i32* [[x_1]]
+// CHECK-NEXT: volatile store i32 1, i32* [[x_1]]
+// CHECK-NEXT: [[tmp_1:%.*]] = volatile load i32* [[x_1]]
+// CHECK-NEXT: volatile store i32 [[tmp_1]], i32* [[y_1]]
+// CHECK: }
+void f1() {
+ volatile int x, y;
+ x = 1;
+ y = (x = 1);
+}
Modified: cfe/trunk/test/CodeGen/object-size.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/object-size.c?rev=107210&r1=107209&r2=107210&view=diff
==============================================================================
--- cfe/trunk/test/CodeGen/object-size.c (original)
+++ cfe/trunk/test/CodeGen/object-size.c Tue Jun 29 17:00:45 2010
@@ -13,32 +13,38 @@
char *gp;
int gi, gj;
+// CHECK: define void @test1
void test1() {
// CHECK: = call i8* @__strcpy_chk(i8* getelementptr inbounds ([63 x i8]* @gbuf, i32 0, i64 4), i8* getelementptr inbounds ([9 x i8]* @.str, i32 0, i32 0), i64 59)
strcpy(&gbuf[4], "Hi there");
}
+// CHECK: define void @test2
void test2() {
// CHECK: = call i8* @__strcpy_chk(i8* getelementptr inbounds ([63 x i8]* @gbuf, i32 0, i32 0), i8* getelementptr inbounds ([9 x i8]* @.str, i32 0, i32 0), i64 63)
strcpy(gbuf, "Hi there");
}
+// CHECK: define void @test3
void test3() {
// CHECK: = call i8* @__strcpy_chk(i8* getelementptr inbounds ([63 x i8]* @gbuf, i64 1, i64 37), i8* getelementptr inbounds ([9 x i8]* @.str, i32 0, i32 0), i64 0)
strcpy(&gbuf[100], "Hi there");
}
+// CHECK: define void @test4
void test4() {
// CHECK: = call i8* @__strcpy_chk(i8* getelementptr inbounds ([63 x i8]* @gbuf, i32 0, i64 -1), i8* getelementptr inbounds ([9 x i8]* @.str, i32 0, i32 0), i64 0)
strcpy((char*)(void*)&gbuf[-1], "Hi there");
}
+// CHECK: define void @test5
void test5() {
// CHECK: = load i8** @gp
// CHECK-NEXT:= call i64 @llvm.objectsize.i64(i8* %{{.*}}, i1 false)
strcpy(gp, "Hi there");
}
+// CHECK: define void @test6
void test6() {
char buf[57];
@@ -46,6 +52,7 @@
strcpy(&buf[4], "Hi there");
}
+// CHECK: define void @test7
void test7() {
int i;
// CHECK-NOT: __strcpy_chk
@@ -53,6 +60,7 @@
strcpy((++i, gbuf), "Hi there");
}
+// CHECK: define void @test8
void test8() {
char *buf[50];
// CHECK-NOT: __strcpy_chk
@@ -60,12 +68,14 @@
strcpy(buf[++gi], "Hi there");
}
+// CHECK: define void @test9
void test9() {
// CHECK-NOT: __strcpy_chk
// CHECK: = call i8* @__inline_strcpy_chk(i8* %{{.*}}, i8* getelementptr inbounds ([9 x i8]* @.str, i32 0, i32 0))
strcpy((char *)((++gi) + gj), "Hi there");
}
+// CHECK: define void @test10
char **p;
void test10() {
// CHECK-NOT: __strcpy_chk
@@ -73,36 +83,42 @@
strcpy(*(++p), "Hi there");
}
+// CHECK: define void @test11
void test11() {
// CHECK-NOT: __strcpy_chk
- // CHECK: = call i8* @__inline_strcpy_chk(i8* %{{.*}}, i8* getelementptr inbounds ([9 x i8]* @.str, i32 0, i32 0))
+ // CHECK: = call i8* @__inline_strcpy_chk(i8* getelementptr inbounds ([63 x i8]* @gbuf, i32 0, i32 0), i8* getelementptr inbounds ([9 x i8]* @.str, i32 0, i32 0))
strcpy(gp = gbuf, "Hi there");
}
+// CHECK: define void @test12
void test12() {
// CHECK-NOT: __strcpy_chk
// CHECK: = call i8* @__inline_strcpy_chk(i8* %{{.*}}, i8* getelementptr inbounds ([9 x i8]* @.str, i32 0, i32 0))
strcpy(++gp, "Hi there");
}
+// CHECK: define void @test13
void test13() {
// CHECK-NOT: __strcpy_chk
// CHECK: = call i8* @__inline_strcpy_chk(i8* %{{.*}}, i8* getelementptr inbounds ([9 x i8]* @.str, i32 0, i32 0))
strcpy(gp++, "Hi there");
}
+// CHECK: define void @test14
void test14() {
// CHECK-NOT: __strcpy_chk
// CHECK: = call i8* @__inline_strcpy_chk(i8* %{{.*}}, i8* getelementptr inbounds ([9 x i8]* @.str, i32 0, i32 0))
strcpy(--gp, "Hi there");
}
+// CHECK: define void @test15
void test15() {
// CHECK-NOT: __strcpy_chk
// CHECK: = call i8* @__inline_strcpy_chk(i8* %{{..*}}, i8* getelementptr inbounds ([9 x i8]* @.str, i32 0, i32 0))
strcpy(gp--, "Hi there");
}
+// CHECK: define void @test16
void test16() {
// CHECK-NOT: __strcpy_chk
// CHECK: = call i8* @__inline_strcpy_chk(i8* %{{.*}}, i8* getelementptr inbounds ([9 x i8]* @.str, i32 0, i32 0))
Modified: cfe/trunk/test/CodeGenCXX/member-init-assignment.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/member-init-assignment.cpp?rev=107210&r1=107209&r2=107210&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/member-init-assignment.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/member-init-assignment.cpp Tue Jun 29 17:00:45 2010
@@ -13,6 +13,5 @@
// CHECK: define void @_ZN3FooC2Ej
// CHECK: [[ARG:%.*]] = alloca i32
// CHECK: store i32 42, i32* [[ARG]]
-// CHECK: [[ARGVAL:%.*]] = load i32* [[ARG]]
-// CHECK: store i32 [[ARGVAL]], i32* %{{.*}}
+// CHECK: store i32 42, i32* %{{.*}}
// CHECK: ret void
Added: cfe/trunk/test/CodeGenObjC/assign.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenObjC/assign.m?rev=107210&view=auto
==============================================================================
--- cfe/trunk/test/CodeGenObjC/assign.m (added)
+++ cfe/trunk/test/CodeGenObjC/assign.m Tue Jun 29 17:00:45 2010
@@ -0,0 +1,32 @@
+// RUN: %clang_cc1 -triple x86_64 -emit-llvm -o - %s | FileCheck %s
+
+struct s0 {
+ int x;
+};
+
+ at interface C0
+ at property int x0;
+ at property _Complex int x1;
+ at property struct s0 x2;
+ at end
+
+// Check that we get exactly the message sends we expect, and no more.
+//
+// CHECK: define void @f0
+void f0(C0 *a) {
+// CHECK: objc_msgSend
+ int l0 = (a.x0 = 1);
+
+// CHECK: objc_msgSend
+ _Complex int l1 = (a.x1 = 1);
+
+// CHECK: objc_msgSend
+ struct s0 l2 = (a.x2 = (struct s0) { 1 });
+
+// CHECK: objc_msgSend
+// CHECK: objc_msgSend
+ int l3 = (a.x0 += 1);
+
+// CHECK-NOT: objc_msgSend
+// CHECK: }
+}
More information about the cfe-commits
mailing list