[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