[PATCH] D66094: [CodeGen] Emit destructor calls for non-trivial C structs returned by function calls and loaded from volatile objects

2020-03-20 Thread Akira Hatanaka via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rGd35a454170da: [CodeGen] Emit destructor calls to destruct 
non-trivial C struct objects… (authored by ahatanak).

Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D66094/new/

https://reviews.llvm.org/D66094

Files:
  clang/lib/AST/Expr.cpp
  clang/lib/CodeGen/CGCall.cpp
  clang/lib/CodeGen/CGCall.h
  clang/lib/CodeGen/CGClass.cpp
  clang/lib/CodeGen/CGExprAgg.cpp
  clang/lib/CodeGen/CGExprConstant.cpp
  clang/lib/CodeGen/CGVTables.cpp
  clang/lib/Sema/SemaDecl.cpp
  clang/lib/Sema/SemaExpr.cpp
  clang/lib/Sema/SemaExprCXX.cpp
  clang/test/CodeGenObjC/arc.m
  clang/test/CodeGenObjC/strong-in-c-struct.m

Index: clang/test/CodeGenObjC/strong-in-c-struct.m
===
--- clang/test/CodeGenObjC/strong-in-c-struct.m
+++ clang/test/CodeGenObjC/strong-in-c-struct.m
@@ -89,6 +89,13 @@
 void calleeStrongSmall(StrongSmall);
 void func(Strong *);
 
+@interface C
+- (StrongSmall)getStrongSmall;
++ (StrongSmall)getStrongSmallClass;
+@end
+
+id g0;
+
 // CHECK: %[[STRUCT_STRONGOUTER:.*]] = type { %[[STRUCT_STRONG:.*]], i8*, double }
 // CHECK: %[[STRUCT_STRONG]] = type { %[[STRUCT_TRIVIAL:.*]], i8* }
 // CHECK: %[[STRUCT_TRIVIAL]] = type { [4 x i32] }
@@ -476,6 +483,18 @@
   getStrongSmall();
 }
 
+// CHECK: define void @test_destructor_ignored_result2(%{{.*}}* %[[C:.*]])
+// CHECK: %[[TMP:.*]] = alloca %[[STRUCT_STRONGSMALL]], align 8
+// CHECK: %[[CALL:.*]] = call [2 x i64]{{.*}}@objc_msgSend
+// CHECK: %[[V5:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[TMP]] to [2 x i64]*
+// CHECK: store [2 x i64] %[[CALL]], [2 x i64]* %[[V5]], align 8
+// CHECK: %[[V6:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[TMP]] to i8**
+// CHECK: call void @__destructor_8_s8(i8** %[[V6]])
+
+void test_destructor_ignored_result2(C *c) {
+  [c getStrongSmall];
+}
+
 // CHECK: define void @test_copy_constructor_StrongBlock(
 // CHECK: call void @__copy_constructor_8_8_sb0(
 // CHECK: call void @__destructor_8_sb0(
@@ -520,7 +539,9 @@
 
 // CHECK: define void @test_copy_constructor_StrongVolatile0(
 // CHECK: call void @__copy_constructor_8_8_t0w4_sv8(
+// CHECK-NOT: call
 // CHECK: call void @__destructor_8_sv8(
+// CHECK-NOT: call
 
 // CHECK: define linkonce_odr hidden void @__copy_constructor_8_8_t0w4_sv8(
 // CHECK: %[[V8:.*]] = load volatile i8*, i8** %{{.*}}, align 8
@@ -808,4 +829,62 @@
   func(0);
 }
 
+// CHECK: define void @test_member_access(
+// CHECK: %[[TMP:.*]] = alloca %[[STRUCT_STRONGSMALL]],
+// CHECK: %[[V3:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[TMP]] to i8**
+// CHECK: call void @__destructor_8_s8(i8** %[[V3]])
+// CHECK: call void @func(
+
+void test_member_access(void) {
+  g0 = getStrongSmall().f1;
+  func(0);
+}
+
+// CHECK: define void @test_member_access2(%{{.*}}* %[[C:.*]])
+// CHECK: %[[COERCE:.*]] = alloca %[[STRUCT_STRONGSMALL]], align 8
+// CHECK: %[[V8:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[COERCE]] to i8**
+// CHECK: call void @__destructor_8_s8(i8** %[[V8]])
+// CHECK: call void @func(
+
+void test_member_access2(C *c) {
+  g0 = [c getStrongSmall].f1;
+  func(0);
+}
+
+// CHECK: define void @test_member_access3(
+// CHECK: %[[COERCE:.*]] = alloca %[[STRUCT_STRONGSMALL]], align 8
+// CHECK: %[[V8:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[COERCE]] to i8**
+// CHECK: call void @__destructor_8_s8(i8** %[[V8]])
+// CHECK: call void @func(
+
+void test_member_access3(void) {
+  g0 = [C getStrongSmallClass].f1;
+  func(0);
+}
+
+// CHECK: define void @test_member_access4()
+// CHECK: %[[COERCE:.*]] = alloca %[[STRUCT_STRONGSMALL]], align 8
+// CHECK: %[[V5:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[COERCE]] to i8**
+// CHECK: call void @__destructor_8_s8(i8** %[[V5]])
+// CHECK: call void @func(
+
+void test_member_access4(void) {
+  g0 = ^{ StrongSmall s; return s; }().f1;
+  func(0);
+}
+
+// CHECK: define void @test_volatile_variable_reference(
+// CHECK: %[[AGG_TMP_ENSURED:.*]] = alloca %[[STRUCT_STRONGSMALL]],
+// CHECK: %[[V1:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[AGG_TMP_ENSURED]] to i8**
+// CHECK: %[[V2:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %{{.*}} to i8**
+// CHECK: call void @__copy_constructor_8_8_tv0w32_sv8(i8** %[[V1]], i8** %[[V2]])
+// CHECK: %[[V3:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[AGG_TMP_ENSURED]] to i8**
+// CHECK: call void @__destructor_8_s8(i8** %[[V3]])
+// CHECK: call void @func(
+
+void test_volatile_variable_reference(volatile StrongSmall *a) {
+  (void)*a;
+  func(0);
+}
+
 #endif /* USESTRUCT */
Index: clang/test/CodeGenObjC/arc.m
===
--- clang/test/CodeGenObjC/arc.m
+++ clang/test/CodeGenObjC/arc.m
@@ -1536,12 +1536,13 @@
 
 // CHECK-LABEL: define void @test71
 void test71(void) {
-  // FIXME: It would be nice if the __destructor_8_s40 for the first call (and
-  // the following lifetime.end) came before the second 

[PATCH] D66094: [CodeGen] Emit destructor calls for non-trivial C structs returned by function calls and loaded from volatile objects

2020-03-19 Thread John McCall via Phabricator via cfe-commits
rjmccall accepted this revision.
rjmccall added a comment.
This revision is now accepted and ready to land.

Thank, this looks great.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D66094/new/

https://reviews.llvm.org/D66094



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D66094: [CodeGen] Emit destructor calls for non-trivial C structs returned by function calls and loaded from volatile objects

2020-03-19 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak updated this revision to Diff 251463.
ahatanak marked an inline comment as done.
ahatanak added a comment.

Teach `Expr::isConstantInitializer` that `ExprWithCleanups` can be a constant.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D66094/new/

https://reviews.llvm.org/D66094

Files:
  clang/lib/AST/Expr.cpp
  clang/lib/CodeGen/CGCall.cpp
  clang/lib/CodeGen/CGCall.h
  clang/lib/CodeGen/CGClass.cpp
  clang/lib/CodeGen/CGExprAgg.cpp
  clang/lib/CodeGen/CGExprConstant.cpp
  clang/lib/CodeGen/CGVTables.cpp
  clang/lib/Sema/SemaDecl.cpp
  clang/lib/Sema/SemaExpr.cpp
  clang/lib/Sema/SemaExprCXX.cpp
  clang/test/CodeGenObjC/arc.m
  clang/test/CodeGenObjC/strong-in-c-struct.m

Index: clang/test/CodeGenObjC/strong-in-c-struct.m
===
--- clang/test/CodeGenObjC/strong-in-c-struct.m
+++ clang/test/CodeGenObjC/strong-in-c-struct.m
@@ -89,6 +89,13 @@
 void calleeStrongSmall(StrongSmall);
 void func(Strong *);
 
+@interface C
+- (StrongSmall)getStrongSmall;
++ (StrongSmall)getStrongSmallClass;
+@end
+
+id g0;
+
 // CHECK: %[[STRUCT_STRONGOUTER:.*]] = type { %[[STRUCT_STRONG:.*]], i8*, double }
 // CHECK: %[[STRUCT_STRONG]] = type { %[[STRUCT_TRIVIAL:.*]], i8* }
 // CHECK: %[[STRUCT_TRIVIAL]] = type { [4 x i32] }
@@ -476,6 +483,18 @@
   getStrongSmall();
 }
 
+// CHECK: define void @test_destructor_ignored_result2(%{{.*}}* %[[C:.*]])
+// CHECK: %[[TMP:.*]] = alloca %[[STRUCT_STRONGSMALL]], align 8
+// CHECK: %[[CALL:.*]] = call [2 x i64]{{.*}}@objc_msgSend
+// CHECK: %[[V5:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[TMP]] to [2 x i64]*
+// CHECK: store [2 x i64] %[[CALL]], [2 x i64]* %[[V5]], align 8
+// CHECK: %[[V6:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[TMP]] to i8**
+// CHECK: call void @__destructor_8_s8(i8** %[[V6]])
+
+void test_destructor_ignored_result2(C *c) {
+  [c getStrongSmall];
+}
+
 // CHECK: define void @test_copy_constructor_StrongBlock(
 // CHECK: call void @__copy_constructor_8_8_sb0(
 // CHECK: call void @__destructor_8_sb0(
@@ -520,7 +539,9 @@
 
 // CHECK: define void @test_copy_constructor_StrongVolatile0(
 // CHECK: call void @__copy_constructor_8_8_t0w4_sv8(
+// CHECK-NOT: call
 // CHECK: call void @__destructor_8_sv8(
+// CHECK-NOT: call
 
 // CHECK: define linkonce_odr hidden void @__copy_constructor_8_8_t0w4_sv8(
 // CHECK: %[[V8:.*]] = load volatile i8*, i8** %{{.*}}, align 8
@@ -808,4 +829,62 @@
   func(0);
 }
 
+// CHECK: define void @test_member_access(
+// CHECK: %[[TMP:.*]] = alloca %[[STRUCT_STRONGSMALL]],
+// CHECK: %[[V3:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[TMP]] to i8**
+// CHECK: call void @__destructor_8_s8(i8** %[[V3]])
+// CHECK: call void @func(
+
+void test_member_access(void) {
+  g0 = getStrongSmall().f1;
+  func(0);
+}
+
+// CHECK: define void @test_member_access2(%{{.*}}* %[[C:.*]])
+// CHECK: %[[COERCE:.*]] = alloca %[[STRUCT_STRONGSMALL]], align 8
+// CHECK: %[[V8:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[COERCE]] to i8**
+// CHECK: call void @__destructor_8_s8(i8** %[[V8]])
+// CHECK: call void @func(
+
+void test_member_access2(C *c) {
+  g0 = [c getStrongSmall].f1;
+  func(0);
+}
+
+// CHECK: define void @test_member_access3(
+// CHECK: %[[COERCE:.*]] = alloca %[[STRUCT_STRONGSMALL]], align 8
+// CHECK: %[[V8:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[COERCE]] to i8**
+// CHECK: call void @__destructor_8_s8(i8** %[[V8]])
+// CHECK: call void @func(
+
+void test_member_access3(void) {
+  g0 = [C getStrongSmallClass].f1;
+  func(0);
+}
+
+// CHECK: define void @test_member_access4()
+// CHECK: %[[COERCE:.*]] = alloca %[[STRUCT_STRONGSMALL]], align 8
+// CHECK: %[[V5:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[COERCE]] to i8**
+// CHECK: call void @__destructor_8_s8(i8** %[[V5]])
+// CHECK: call void @func(
+
+void test_member_access4(void) {
+  g0 = ^{ StrongSmall s; return s; }().f1;
+  func(0);
+}
+
+// CHECK: define void @test_volatile_variable_reference(
+// CHECK: %[[AGG_TMP_ENSURED:.*]] = alloca %[[STRUCT_STRONGSMALL]],
+// CHECK: %[[V1:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[AGG_TMP_ENSURED]] to i8**
+// CHECK: %[[V2:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %{{.*}} to i8**
+// CHECK: call void @__copy_constructor_8_8_tv0w32_sv8(i8** %[[V1]], i8** %[[V2]])
+// CHECK: %[[V3:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[AGG_TMP_ENSURED]] to i8**
+// CHECK: call void @__destructor_8_s8(i8** %[[V3]])
+// CHECK: call void @func(
+
+void test_volatile_variable_reference(volatile StrongSmall *a) {
+  (void)*a;
+  func(0);
+}
+
 #endif /* USESTRUCT */
Index: clang/test/CodeGenObjC/arc.m
===
--- clang/test/CodeGenObjC/arc.m
+++ clang/test/CodeGenObjC/arc.m
@@ -1536,12 +1536,13 @@
 
 // CHECK-LABEL: define void @test71
 void test71(void) {
-  // FIXME: It would be nice if the __destructor_8_s40 for the first call (and
-  // the following lifetime.end) came before the second call.
-  

[PATCH] D66094: [CodeGen] Emit destructor calls for non-trivial C structs returned by function calls and loaded from volatile objects

2020-03-19 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak added inline comments.



Comment at: clang/lib/Sema/SemaExpr.cpp:677
+  E->getType().isDestructedType() == QualType::DK_nontrivial_c_struct)
+Cleanup.setExprNeedsCleanups(true);
+

rjmccall wrote:
> ahatanak wrote:
> > rjmccall wrote:
> > > ahatanak wrote:
> > > > rjmccall wrote:
> > > > > ahatanak wrote:
> > > > > > rjmccall wrote:
> > > > > > > Why only when the l-value is volatile?
> > > > > > I was trying to avoid emitting `ExprWithCleanups` when it wasn't 
> > > > > > needed and it seemed that it wasn't needed for non-volatile types. 
> > > > > > I'm not sure it's important, so I've removed the check for 
> > > > > > volatile. Also, `ExprWithCleanups` shouldn't' be emitted when this 
> > > > > > is in file scope, so I fixed that too.
> > > > > Hmm, not sure about this file-scope thing, since the combination of 
> > > > > C++ dynamic initializers and statement-expressions means  we can have 
> > > > > pretty unrestricted code there.
> > > > I should have explained why this was needed, but I wanted to prevent 
> > > > emitting `ExprWithCleanups` in the following example:
> > > > 
> > > > ```
> > > > struct A {
> > > >   id f0;
> > > > };
> > > > 
> > > > typedef struct A A;
> > > > 
> > > > A g = (A){ .f0 = 0 };
> > > > ```
> > > > 
> > > > The l-value to r-value conversion happens here because compound 
> > > > literals are l-values. Since `g` is a global of a non-trivial C struct 
> > > > type, we shouldn't try to push a cleanup and destruct the object.
> > > > 
> > > > We don't have to think about the C++ case since the line below checks 
> > > > the type is a non-trivial C type. I didn't think about statement 
> > > > expressions, but they aren't allowed in file scope, so I guess that's 
> > > > not a problem either.
> > > I would hope that the constant-evaluator here might be smart enough to 
> > > ignore some elidable temporaries.
> > Do you mean the constant-evaluator should evaluate initializers that are 
> > `ExprWithCleanups` to constants in a case like this?  It's possible to do 
> > so by seeing whether the sub-expression of `ExprWithCleanups` is constant, 
> > but it looks like we also have to set the 
> > `CleanupInfo::CleanupsHaveSideEffects` flag to false when it's a file scope 
> > expression so that `ConstExprEmitter::VisitExprWithCleanups` can 
> > constant-fold the `ExprWithCleanups` initializer.
> In this case, what we're doing is eliding a "temporary" (really an object 
> with wider lifetime, but if the object isn't referenceable, we can compile 
> as-if the object is really temporary) and therefore bypassing the need for a 
> cleanup entirely.  I wouldn't expect the AST to change to reflect that this 
> is possible, just the constant evaluator.  Basically, it needs to look 
> through `ExprWithCleanups`; we probably already peephole the 
> `LValueToRValue(CompoundLiteralExpr)` combination.
> 
> We do try to do constant-evaluation on local initializers as well as an 
> optimization, and abstractly that should also work with these constructs.
I taught `Expr::isConstantInitializer` to look through `ExprWithCleanups` and 
`ConstExprEmitter::VisitExprWithCleanups` to ignore whether the expression has 
side effects. For the latter, I'm assuming we don't have to care about the side 
effect of the cleanup if the need for a cleanup is elided. This change causes 
`CodeGenFunction::EmitAutoVarInit` to emit the initializer as a constant too.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D66094/new/

https://reviews.llvm.org/D66094



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D66094: [CodeGen] Emit destructor calls for non-trivial C structs returned by function calls and loaded from volatile objects

2020-03-19 Thread John McCall via Phabricator via cfe-commits
rjmccall added inline comments.



Comment at: clang/lib/Sema/SemaExpr.cpp:677
+  E->getType().isDestructedType() == QualType::DK_nontrivial_c_struct)
+Cleanup.setExprNeedsCleanups(true);
+

ahatanak wrote:
> rjmccall wrote:
> > ahatanak wrote:
> > > rjmccall wrote:
> > > > ahatanak wrote:
> > > > > rjmccall wrote:
> > > > > > Why only when the l-value is volatile?
> > > > > I was trying to avoid emitting `ExprWithCleanups` when it wasn't 
> > > > > needed and it seemed that it wasn't needed for non-volatile types. 
> > > > > I'm not sure it's important, so I've removed the check for volatile. 
> > > > > Also, `ExprWithCleanups` shouldn't' be emitted when this is in file 
> > > > > scope, so I fixed that too.
> > > > Hmm, not sure about this file-scope thing, since the combination of C++ 
> > > > dynamic initializers and statement-expressions means  we can have 
> > > > pretty unrestricted code there.
> > > I should have explained why this was needed, but I wanted to prevent 
> > > emitting `ExprWithCleanups` in the following example:
> > > 
> > > ```
> > > struct A {
> > >   id f0;
> > > };
> > > 
> > > typedef struct A A;
> > > 
> > > A g = (A){ .f0 = 0 };
> > > ```
> > > 
> > > The l-value to r-value conversion happens here because compound literals 
> > > are l-values. Since `g` is a global of a non-trivial C struct type, we 
> > > shouldn't try to push a cleanup and destruct the object.
> > > 
> > > We don't have to think about the C++ case since the line below checks the 
> > > type is a non-trivial C type. I didn't think about statement expressions, 
> > > but they aren't allowed in file scope, so I guess that's not a problem 
> > > either.
> > I would hope that the constant-evaluator here might be smart enough to 
> > ignore some elidable temporaries.
> Do you mean the constant-evaluator should evaluate initializers that are 
> `ExprWithCleanups` to constants in a case like this?  It's possible to do so 
> by seeing whether the sub-expression of `ExprWithCleanups` is constant, but 
> it looks like we also have to set the `CleanupInfo::CleanupsHaveSideEffects` 
> flag to false when it's a file scope expression so that 
> `ConstExprEmitter::VisitExprWithCleanups` can constant-fold the 
> `ExprWithCleanups` initializer.
In this case, what we're doing is eliding a "temporary" (really an object with 
wider lifetime, but if the object isn't referenceable, we can compile as-if the 
object is really temporary) and therefore bypassing the need for a cleanup 
entirely.  I wouldn't expect the AST to change to reflect that this is 
possible, just the constant evaluator.  Basically, it needs to look through 
`ExprWithCleanups`; we probably already peephole the 
`LValueToRValue(CompoundLiteralExpr)` combination.

We do try to do constant-evaluation on local initializers as well as an 
optimization, and abstractly that should also work with these constructs.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D66094/new/

https://reviews.llvm.org/D66094



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D66094: [CodeGen] Emit destructor calls for non-trivial C structs returned by function calls and loaded from volatile objects

2020-03-19 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak marked an inline comment as done.
ahatanak added inline comments.



Comment at: clang/lib/Sema/SemaExpr.cpp:677
+  E->getType().isDestructedType() == QualType::DK_nontrivial_c_struct)
+Cleanup.setExprNeedsCleanups(true);
+

rjmccall wrote:
> ahatanak wrote:
> > rjmccall wrote:
> > > ahatanak wrote:
> > > > rjmccall wrote:
> > > > > Why only when the l-value is volatile?
> > > > I was trying to avoid emitting `ExprWithCleanups` when it wasn't needed 
> > > > and it seemed that it wasn't needed for non-volatile types. I'm not 
> > > > sure it's important, so I've removed the check for volatile. Also, 
> > > > `ExprWithCleanups` shouldn't' be emitted when this is in file scope, so 
> > > > I fixed that too.
> > > Hmm, not sure about this file-scope thing, since the combination of C++ 
> > > dynamic initializers and statement-expressions means  we can have pretty 
> > > unrestricted code there.
> > I should have explained why this was needed, but I wanted to prevent 
> > emitting `ExprWithCleanups` in the following example:
> > 
> > ```
> > struct A {
> >   id f0;
> > };
> > 
> > typedef struct A A;
> > 
> > A g = (A){ .f0 = 0 };
> > ```
> > 
> > The l-value to r-value conversion happens here because compound literals 
> > are l-values. Since `g` is a global of a non-trivial C struct type, we 
> > shouldn't try to push a cleanup and destruct the object.
> > 
> > We don't have to think about the C++ case since the line below checks the 
> > type is a non-trivial C type. I didn't think about statement expressions, 
> > but they aren't allowed in file scope, so I guess that's not a problem 
> > either.
> I would hope that the constant-evaluator here might be smart enough to ignore 
> some elidable temporaries.
Do you mean the constant-evaluator should evaluate initializers that are 
`ExprWithCleanups` to constants in a case like this?  It's possible to do so by 
seeing whether the sub-expression of `ExprWithCleanups` is constant, but it 
looks like we also have to set the `CleanupInfo::CleanupsHaveSideEffects` flag 
to false when it's a file scope expression so that 
`ConstExprEmitter::VisitExprWithCleanups` can constant-fold the 
`ExprWithCleanups` initializer.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D66094/new/

https://reviews.llvm.org/D66094



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D66094: [CodeGen] Emit destructor calls for non-trivial C structs returned by function calls and loaded from volatile objects

2020-03-18 Thread John McCall via Phabricator via cfe-commits
rjmccall added inline comments.



Comment at: clang/lib/Sema/SemaExpr.cpp:677
+  E->getType().isDestructedType() == QualType::DK_nontrivial_c_struct)
+Cleanup.setExprNeedsCleanups(true);
+

ahatanak wrote:
> rjmccall wrote:
> > ahatanak wrote:
> > > rjmccall wrote:
> > > > Why only when the l-value is volatile?
> > > I was trying to avoid emitting `ExprWithCleanups` when it wasn't needed 
> > > and it seemed that it wasn't needed for non-volatile types. I'm not sure 
> > > it's important, so I've removed the check for volatile. Also, 
> > > `ExprWithCleanups` shouldn't' be emitted when this is in file scope, so I 
> > > fixed that too.
> > Hmm, not sure about this file-scope thing, since the combination of C++ 
> > dynamic initializers and statement-expressions means  we can have pretty 
> > unrestricted code there.
> I should have explained why this was needed, but I wanted to prevent emitting 
> `ExprWithCleanups` in the following example:
> 
> ```
> struct A {
>   id f0;
> };
> 
> typedef struct A A;
> 
> A g = (A){ .f0 = 0 };
> ```
> 
> The l-value to r-value conversion happens here because compound literals are 
> l-values. Since `g` is a global of a non-trivial C struct type, we shouldn't 
> try to push a cleanup and destruct the object.
> 
> We don't have to think about the C++ case since the line below checks the 
> type is a non-trivial C type. I didn't think about statement expressions, but 
> they aren't allowed in file scope, so I guess that's not a problem either.
I would hope that the constant-evaluator here might be smart enough to ignore 
some elidable temporaries.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D66094/new/

https://reviews.llvm.org/D66094



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D66094: [CodeGen] Emit destructor calls for non-trivial C structs returned by function calls and loaded from volatile objects

2020-03-17 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak marked an inline comment as done.
ahatanak added inline comments.



Comment at: clang/lib/Sema/SemaExpr.cpp:677
+  E->getType().isDestructedType() == QualType::DK_nontrivial_c_struct)
+Cleanup.setExprNeedsCleanups(true);
+

rjmccall wrote:
> ahatanak wrote:
> > rjmccall wrote:
> > > Why only when the l-value is volatile?
> > I was trying to avoid emitting `ExprWithCleanups` when it wasn't needed and 
> > it seemed that it wasn't needed for non-volatile types. I'm not sure it's 
> > important, so I've removed the check for volatile. Also, `ExprWithCleanups` 
> > shouldn't' be emitted when this is in file scope, so I fixed that too.
> Hmm, not sure about this file-scope thing, since the combination of C++ 
> dynamic initializers and statement-expressions means  we can have pretty 
> unrestricted code there.
I should have explained why this was needed, but I wanted to prevent emitting 
`ExprWithCleanups` in the following example:

```
struct A {
  id f0;
};

typedef struct A A;

A g = (A){ .f0 = 0 };
```

The l-value to r-value conversion happens here because compound literals are 
l-values. Since `g` is a global of a non-trivial C struct type, we shouldn't 
try to push a cleanup and destruct the object.

We don't have to think about the C++ case since the line below checks the type 
is a non-trivial C type. I didn't think about statement expressions, but they 
aren't allowed in file scope, so I guess that's not a problem either.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D66094/new/

https://reviews.llvm.org/D66094



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D66094: [CodeGen] Emit destructor calls for non-trivial C structs returned by function calls and loaded from volatile objects

2020-03-17 Thread John McCall via Phabricator via cfe-commits
rjmccall added inline comments.



Comment at: clang/lib/Sema/SemaExpr.cpp:677
+  E->getType().isDestructedType() == QualType::DK_nontrivial_c_struct)
+Cleanup.setExprNeedsCleanups(true);
+

ahatanak wrote:
> rjmccall wrote:
> > Why only when the l-value is volatile?
> I was trying to avoid emitting `ExprWithCleanups` when it wasn't needed and 
> it seemed that it wasn't needed for non-volatile types. I'm not sure it's 
> important, so I've removed the check for volatile. Also, `ExprWithCleanups` 
> shouldn't' be emitted when this is in file scope, so I fixed that too.
Hmm, not sure about this file-scope thing, since the combination of C++ dynamic 
initializers and statement-expressions means  we can have pretty unrestricted 
code there.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D66094/new/

https://reviews.llvm.org/D66094



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D66094: [CodeGen] Emit destructor calls for non-trivial C structs returned by function calls and loaded from volatile objects

2020-03-17 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak added inline comments.



Comment at: clang/lib/Sema/SemaExpr.cpp:677
+  E->getType().isDestructedType() == QualType::DK_nontrivial_c_struct)
+Cleanup.setExprNeedsCleanups(true);
+

rjmccall wrote:
> Why only when the l-value is volatile?
I was trying to avoid emitting `ExprWithCleanups` when it wasn't needed and it 
seemed that it wasn't needed for non-volatile types. I'm not sure it's 
important, so I've removed the check for volatile. Also, `ExprWithCleanups` 
shouldn't' be emitted when this is in file scope, so I fixed that too.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D66094/new/

https://reviews.llvm.org/D66094



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D66094: [CodeGen] Emit destructor calls for non-trivial C structs returned by function calls and loaded from volatile objects

2020-03-17 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak updated this revision to Diff 250934.
ahatanak marked 2 inline comments as done.
ahatanak added a comment.

Address review comments.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D66094/new/

https://reviews.llvm.org/D66094

Files:
  clang/lib/CodeGen/CGCall.cpp
  clang/lib/CodeGen/CGCall.h
  clang/lib/CodeGen/CGClass.cpp
  clang/lib/CodeGen/CGExprAgg.cpp
  clang/lib/CodeGen/CGVTables.cpp
  clang/lib/Sema/SemaDecl.cpp
  clang/lib/Sema/SemaExpr.cpp
  clang/lib/Sema/SemaExprCXX.cpp
  clang/test/CodeGenObjC/arc.m
  clang/test/CodeGenObjC/strong-in-c-struct.m

Index: clang/test/CodeGenObjC/strong-in-c-struct.m
===
--- clang/test/CodeGenObjC/strong-in-c-struct.m
+++ clang/test/CodeGenObjC/strong-in-c-struct.m
@@ -89,6 +89,13 @@
 void calleeStrongSmall(StrongSmall);
 void func(Strong *);
 
+@interface C
+-(StrongSmall)getStrongSmall;
++(StrongSmall)getStrongSmallClass;
+@end
+
+id g0;
+
 // CHECK: %[[STRUCT_STRONGOUTER:.*]] = type { %[[STRUCT_STRONG:.*]], i8*, double }
 // CHECK: %[[STRUCT_STRONG]] = type { %[[STRUCT_TRIVIAL:.*]], i8* }
 // CHECK: %[[STRUCT_TRIVIAL]] = type { [4 x i32] }
@@ -476,6 +483,18 @@
   getStrongSmall();
 }
 
+// CHECK: define void @test_destructor_ignored_result2(%{{.*}}* %[[C:.*]])
+// CHECK: %[[TMP:.*]] = alloca %[[STRUCT_STRONGSMALL]], align 8
+// CHECK: %[[CALL:.*]] = call [2 x i64]{{.*}}@objc_msgSend
+// CHECK: %[[V5:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[TMP]] to [2 x i64]*
+// CHECK: store [2 x i64] %[[CALL]], [2 x i64]* %[[V5]], align 8
+// CHECK: %[[V6:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[TMP]] to i8**
+// CHECK: call void @__destructor_8_s8(i8** %[[V6]])
+
+void test_destructor_ignored_result2(C *c) {
+  [c getStrongSmall];
+}
+
 // CHECK: define void @test_copy_constructor_StrongBlock(
 // CHECK: call void @__copy_constructor_8_8_sb0(
 // CHECK: call void @__destructor_8_sb0(
@@ -520,7 +539,9 @@
 
 // CHECK: define void @test_copy_constructor_StrongVolatile0(
 // CHECK: call void @__copy_constructor_8_8_t0w4_sv8(
+// CHECK-NOT: call
 // CHECK: call void @__destructor_8_sv8(
+// CHECK-NOT: call
 
 // CHECK: define linkonce_odr hidden void @__copy_constructor_8_8_t0w4_sv8(
 // CHECK: %[[V8:.*]] = load volatile i8*, i8** %{{.*}}, align 8
@@ -808,4 +829,62 @@
   func(0);
 }
 
+// CHECK: define void @test_member_access(
+// CHECK: %[[TMP:.*]] = alloca %[[STRUCT_STRONGSMALL]],
+// CHECK: %[[V3:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[TMP]] to i8**
+// CHECK: call void @__destructor_8_s8(i8** %[[V3]])
+// CHECK: call void @func(
+
+void test_member_access(void) {
+  g0 = getStrongSmall().f1;
+  func(0);
+}
+
+// CHECK: define void @test_member_access2(%{{.*}}* %[[C:.*]])
+// CHECK: %[[COERCE:.*]] = alloca %[[STRUCT_STRONGSMALL]], align 8
+// CHECK: %[[V8:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[COERCE]] to i8**
+// CHECK: call void @__destructor_8_s8(i8** %[[V8]])
+// CHECK: call void @func(
+
+void test_member_access2(C *c) {
+  g0 = [c getStrongSmall].f1;
+  func(0);
+}
+
+// CHECK: define void @test_member_access3(
+// CHECK: %[[COERCE:.*]] = alloca %[[STRUCT_STRONGSMALL]], align 8
+// CHECK: %[[V8:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[COERCE]] to i8**
+// CHECK: call void @__destructor_8_s8(i8** %[[V8]])
+// CHECK: call void @func(
+
+void test_member_access3(void) {
+  g0 = [C getStrongSmallClass].f1;
+  func(0);
+}
+
+// CHECK: define void @test_member_access4()
+// CHECK: %[[COERCE:.*]] = alloca %[[STRUCT_STRONGSMALL]], align 8
+// CHECK: %[[V5:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[COERCE]] to i8**
+// CHECK: call void @__destructor_8_s8(i8** %[[V5]])
+// CHECK: call void @func(
+
+void test_member_access4(void) {
+  g0 = ^{ StrongSmall s; return s; }().f1;
+  func(0);
+}
+
+// CHECK: define void @test_volatile_variable_reference(
+// CHECK: %[[AGG_TMP_ENSURED:.*]] = alloca %[[STRUCT_STRONGSMALL]],
+// CHECK: %[[V1:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[AGG_TMP_ENSURED]] to i8**
+// CHECK: %[[V2:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %{{.*}} to i8**
+// CHECK: call void @__copy_constructor_8_8_tv0w32_sv8(i8** %[[V1]], i8** %[[V2]])
+// CHECK: %[[V3:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[AGG_TMP_ENSURED]] to i8**
+// CHECK: call void @__destructor_8_s8(i8** %[[V3]])
+// CHECK: call void @func(
+
+void test_volatile_variable_reference(volatile StrongSmall *a) {
+  (void)*a;
+  func(0);
+}
+
 #endif /* USESTRUCT */
Index: clang/test/CodeGenObjC/arc.m
===
--- clang/test/CodeGenObjC/arc.m
+++ clang/test/CodeGenObjC/arc.m
@@ -1536,12 +1536,13 @@
 
 // CHECK-LABEL: define void @test71
 void test71(void) {
-  // FIXME: It would be nice if the __destructor_8_s40 for the first call (and
-  // the following lifetime.end) came before the second call.
-  //
   // CHECK: %[[T:[^ ]+]] = bitcast %struct.AggDtor* %[[TMP1:[^ ]+]] to i8*
   // CHECK: call void 

[PATCH] D66094: [CodeGen] Emit destructor calls for non-trivial C structs returned by function calls and loaded from volatile objects

2020-03-16 Thread John McCall via Phabricator via cfe-commits
rjmccall added inline comments.



Comment at: clang/lib/Sema/SemaExpr.cpp:677
+  E->getType().isDestructedType() == QualType::DK_nontrivial_c_struct)
+Cleanup.setExprNeedsCleanups(true);
+

Why only when the l-value is volatile?



Comment at: clang/lib/Sema/SemaExpr.cpp:5733
+  QualType::DK_nontrivial_c_struct)
+Cleanup.setExprNeedsCleanups(true);
+

You should do this in `MaybeBindToTemporary`, and then you probably don't need 
it in most of these other places.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D66094/new/

https://reviews.llvm.org/D66094



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D66094: [CodeGen] Emit destructor calls for non-trivial C structs returned by function calls and loaded from volatile objects

2020-03-09 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak updated this revision to Diff 249190.
ahatanak marked an inline comment as done.
ahatanak added a comment.

Fix the way `IsExternallyDestructed` is used.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D66094/new/

https://reviews.llvm.org/D66094

Files:
  clang/include/clang/Sema/Sema.h
  clang/lib/CodeGen/CGCall.cpp
  clang/lib/CodeGen/CGCall.h
  clang/lib/CodeGen/CGClass.cpp
  clang/lib/CodeGen/CGExprAgg.cpp
  clang/lib/CodeGen/CGVTables.cpp
  clang/lib/Parse/ParseObjc.cpp
  clang/lib/Sema/SemaExpr.cpp
  clang/lib/Sema/SemaExprObjC.cpp
  clang/test/CodeGenObjC/arc.m
  clang/test/CodeGenObjC/strong-in-c-struct.m

Index: clang/test/CodeGenObjC/strong-in-c-struct.m
===
--- clang/test/CodeGenObjC/strong-in-c-struct.m
+++ clang/test/CodeGenObjC/strong-in-c-struct.m
@@ -89,6 +89,13 @@
 void calleeStrongSmall(StrongSmall);
 void func(Strong *);
 
+@interface C
+-(StrongSmall)getStrongSmall;
++(StrongSmall)getStrongSmallClass;
+@end
+
+id g0;
+
 // CHECK: %[[STRUCT_STRONGOUTER:.*]] = type { %[[STRUCT_STRONG:.*]], i8*, double }
 // CHECK: %[[STRUCT_STRONG]] = type { %[[STRUCT_TRIVIAL:.*]], i8* }
 // CHECK: %[[STRUCT_TRIVIAL]] = type { [4 x i32] }
@@ -476,6 +483,18 @@
   getStrongSmall();
 }
 
+// CHECK: define void @test_destructor_ignored_result2(%{{.*}}* %[[C:.*]])
+// CHECK: %[[TMP:.*]] = alloca %[[STRUCT_STRONGSMALL]], align 8
+// CHECK: %[[CALL:.*]] = call [2 x i64]{{.*}}@objc_msgSend
+// CHECK: %[[V5:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[TMP]] to [2 x i64]*
+// CHECK: store [2 x i64] %[[CALL]], [2 x i64]* %[[V5]], align 8
+// CHECK: %[[V6:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[TMP]] to i8**
+// CHECK: call void @__destructor_8_s8(i8** %[[V6]])
+
+void test_destructor_ignored_result2(C *c) {
+  [c getStrongSmall];
+}
+
 // CHECK: define void @test_copy_constructor_StrongBlock(
 // CHECK: call void @__copy_constructor_8_8_sb0(
 // CHECK: call void @__destructor_8_sb0(
@@ -520,7 +539,9 @@
 
 // CHECK: define void @test_copy_constructor_StrongVolatile0(
 // CHECK: call void @__copy_constructor_8_8_t0w4_sv8(
+// CHECK-NOT: call
 // CHECK: call void @__destructor_8_sv8(
+// CHECK-NOT: call
 
 // CHECK: define linkonce_odr hidden void @__copy_constructor_8_8_t0w4_sv8(
 // CHECK: %[[V8:.*]] = load volatile i8*, i8** %{{.*}}, align 8
@@ -709,4 +730,62 @@
   VolatileArray t = *a;
 }
 
+// CHECK: define void @test_member_access(
+// CHECK: %[[TMP:.*]] = alloca %[[STRUCT_STRONGSMALL]],
+// CHECK: %[[V3:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[TMP]] to i8**
+// CHECK: call void @__destructor_8_s8(i8** %[[V3]])
+// CHECK: call void @func(
+
+void test_member_access(void) {
+  g0 = getStrongSmall().f1;
+  func(0);
+}
+
+// CHECK: define void @test_member_access2(%{{.*}}* %[[C:.*]])
+// CHECK: %[[COERCE:.*]] = alloca %[[STRUCT_STRONGSMALL]], align 8
+// CHECK: %[[V8:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[COERCE]] to i8**
+// CHECK: call void @__destructor_8_s8(i8** %[[V8]])
+// CHECK: call void @func(
+
+void test_member_access2(C *c) {
+  g0 = [c getStrongSmall].f1;
+  func(0);
+}
+
+// CHECK: define void @test_member_access3(
+// CHECK: %[[COERCE:.*]] = alloca %[[STRUCT_STRONGSMALL]], align 8
+// CHECK: %[[V8:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[COERCE]] to i8**
+// CHECK: call void @__destructor_8_s8(i8** %[[V8]])
+// CHECK: call void @func(
+
+void test_member_access3(void) {
+  g0 = [C getStrongSmallClass].f1;
+  func(0);
+}
+
+// CHECK: define void @test_member_access4()
+// CHECK: %[[COERCE:.*]] = alloca %[[STRUCT_STRONGSMALL]], align 8
+// CHECK: %[[V5:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[COERCE]] to i8**
+// CHECK: call void @__destructor_8_s8(i8** %[[V5]])
+// CHECK: call void @func(
+
+void test_member_access4(void) {
+  g0 = ^{ StrongSmall s; return s; }().f1;
+  func(0);
+}
+
+// CHECK: define void @test_volatile_variable_reference(
+// CHECK: %[[AGG_TMP_ENSURED:.*]] = alloca %[[STRUCT_STRONGSMALL]],
+// CHECK: %[[V1:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[AGG_TMP_ENSURED]] to i8**
+// CHECK: %[[V2:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %{{.*}} to i8**
+// CHECK: call void @__copy_constructor_8_8_tv0w32_sv8(i8** %[[V1]], i8** %[[V2]])
+// CHECK: %[[V3:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[AGG_TMP_ENSURED]] to i8**
+// CHECK: call void @__destructor_8_s8(i8** %[[V3]])
+// CHECK: call void @func(
+
+void test_volatile_variable_reference(volatile StrongSmall *a) {
+  (void)*a;
+  func(0);
+}
+
 #endif /* USESTRUCT */
Index: clang/test/CodeGenObjC/arc.m
===
--- clang/test/CodeGenObjC/arc.m
+++ clang/test/CodeGenObjC/arc.m
@@ -1536,12 +1536,13 @@
 
 // CHECK-LABEL: define void @test71
 void test71(void) {
-  // FIXME: It would be nice if the __destructor_8_s40 for the first call (and
-  // the following lifetime.end) came before the second call.
-  //
   // CHECK: %[[T:[^ ]+]] = bitcast 

[PATCH] D66094: [CodeGen] Emit destructor calls for non-trivial C structs returned by function calls and loaded from volatile objects

2020-03-07 Thread John McCall via Phabricator via cfe-commits
rjmccall added inline comments.



Comment at: clang/lib/CodeGen/CGExprAgg.cpp:822
+Dest.setExternallyDestructed();
+  }
+

I don't think `setExternallyDestructed` can be used to communicate outwards 
like this; the code isn't set up to just do modifications on a single 
`AggValueSlot` that's passed around by reference.  Instead, the flags are used 
to communicate downwards to the callees, and the expectation needs to be that 
callees will push a destructor when they're done initializing unless 
`isExternallyDestructed` is set on the dest slot they receive.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D66094/new/

https://reviews.llvm.org/D66094



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D66094: [CodeGen] Emit destructor calls for non-trivial C structs returned by function calls and loaded from volatile objects

2020-03-04 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak updated this revision to Diff 248363.
ahatanak marked 2 inline comments as done.
ahatanak removed a project: LLVM.
ahatanak removed a subscriber: llvm-commits.
ahatanak added a comment.
Herald added a subscriber: ributzka.

Address review comments.

- Declare the flags in `ReturnValueSlot` as bitfields.
- Replace flag `RequiresDestruction` with flag `IsExternallyDestructed` and 
move the `pushDestroy` call to `EmitCall`. I audited all the places where 
`ReturnValueSlot` is constructed and there were only a few places where 
`IsExternallyDestructed` had to be set to true.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D66094/new/

https://reviews.llvm.org/D66094

Files:
  clang/include/clang/Sema/Sema.h
  clang/lib/CodeGen/CGCall.cpp
  clang/lib/CodeGen/CGCall.h
  clang/lib/CodeGen/CGClass.cpp
  clang/lib/CodeGen/CGExprAgg.cpp
  clang/lib/CodeGen/CGVTables.cpp
  clang/lib/Parse/ParseObjc.cpp
  clang/lib/Sema/SemaExpr.cpp
  clang/lib/Sema/SemaExprObjC.cpp
  clang/test/CodeGenObjC/arc.m
  clang/test/CodeGenObjC/strong-in-c-struct.m

Index: clang/test/CodeGenObjC/strong-in-c-struct.m
===
--- clang/test/CodeGenObjC/strong-in-c-struct.m
+++ clang/test/CodeGenObjC/strong-in-c-struct.m
@@ -89,6 +89,13 @@
 void calleeStrongSmall(StrongSmall);
 void func(Strong *);
 
+@interface C
+- (StrongSmall)getStrongSmall;
++ (StrongSmall)getStrongSmallClass;
+@end
+
+id g0;
+
 // CHECK: %[[STRUCT_STRONGOUTER:.*]] = type { %[[STRUCT_STRONG:.*]], i8*, double }
 // CHECK: %[[STRUCT_STRONG]] = type { %[[STRUCT_TRIVIAL:.*]], i8* }
 // CHECK: %[[STRUCT_TRIVIAL]] = type { [4 x i32] }
@@ -476,6 +483,18 @@
   getStrongSmall();
 }
 
+// CHECK: define void @test_destructor_ignored_result2(%{{.*}}* %[[C:.*]])
+// CHECK: %[[TMP:.*]] = alloca %[[STRUCT_STRONGSMALL]], align 8
+// CHECK: %[[CALL:.*]] = call [2 x i64]{{.*}}@objc_msgSend
+// CHECK: %[[V5:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[TMP]] to [2 x i64]*
+// CHECK: store [2 x i64] %[[CALL]], [2 x i64]* %[[V5]], align 8
+// CHECK: %[[V6:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[TMP]] to i8**
+// CHECK: call void @__destructor_8_s8(i8** %[[V6]])
+
+void test_destructor_ignored_result2(C *c) {
+  [c getStrongSmall];
+}
+
 // CHECK: define void @test_copy_constructor_StrongBlock(
 // CHECK: call void @__copy_constructor_8_8_sb0(
 // CHECK: call void @__destructor_8_sb0(
@@ -520,7 +539,9 @@
 
 // CHECK: define void @test_copy_constructor_StrongVolatile0(
 // CHECK: call void @__copy_constructor_8_8_t0w4_sv8(
+// CHECK-NOT: call
 // CHECK: call void @__destructor_8_sv8(
+// CHECK-NOT: call
 
 // CHECK: define linkonce_odr hidden void @__copy_constructor_8_8_t0w4_sv8(
 // CHECK: %[[V8:.*]] = load volatile i8*, i8** %{{.*}}, align 8
@@ -709,4 +730,66 @@
   VolatileArray t = *a;
 }
 
+// CHECK: define void @test_member_access(
+// CHECK: %[[TMP:.*]] = alloca %[[STRUCT_STRONGSMALL]],
+// CHECK: %[[V3:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[TMP]] to i8**
+// CHECK: call void @__destructor_8_s8(i8** %[[V3]])
+// CHECK: call void @func(
+
+void test_member_access(void) {
+  g0 = getStrongSmall().f1;
+  func(0);
+}
+
+// CHECK: define void @test_member_access2(%{{.*}}* %[[C:.*]])
+// CHECK: %[[COERCE:.*]] = alloca %[[STRUCT_STRONGSMALL]], align 8
+// CHECK: %[[V8:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[COERCE]] to i8**
+// CHECK: call void @__destructor_8_s8(i8** %[[V8]])
+// CHECK: call void @func(
+
+void test_member_access2(C *c) {
+  g0 = [c getStrongSmall].f1;
+  func(0);
+}
+
+// CHECK: define void @test_member_access3(
+// CHECK: %[[COERCE:.*]] = alloca %[[STRUCT_STRONGSMALL]], align 8
+// CHECK: %[[V8:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[COERCE]] to i8**
+// CHECK: call void @__destructor_8_s8(i8** %[[V8]])
+// CHECK: call void @func(
+
+void test_member_access3(void) {
+  g0 = [C getStrongSmallClass].f1;
+  func(0);
+}
+
+// CHECK: define void @test_member_access4()
+// CHECK: %[[COERCE:.*]] = alloca %[[STRUCT_STRONGSMALL]], align 8
+// CHECK: %[[V5:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[COERCE]] to i8**
+// CHECK: call void @__destructor_8_s8(i8** %[[V5]])
+// CHECK: call void @func(
+
+void test_member_access4(void) {
+  g0 = ^{
+StrongSmall s;
+return s;
+  }()
+.f1;
+  func(0);
+}
+
+// CHECK: define void @test_volatile_variable_reference(
+// CHECK: %[[AGG_TMP_ENSURED:.*]] = alloca %[[STRUCT_STRONGSMALL]],
+// CHECK: %[[V1:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[AGG_TMP_ENSURED]] to i8**
+// CHECK: %[[V2:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %{{.*}} to i8**
+// CHECK: call void @__copy_constructor_8_8_tv0w32_sv8(i8** %[[V1]], i8** %[[V2]])
+// CHECK: %[[V3:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[AGG_TMP_ENSURED]] to i8**
+// CHECK: call void @__destructor_8_s8(i8** %[[V3]])
+// CHECK: call void @func(
+
+void test_volatile_variable_reference(volatile StrongSmall *a) {
+  (void)*a;
+  func(0);
+}
+
 #endif /* USESTRUCT 

[PATCH] D66094: [CodeGen] Emit destructor calls for non-trivial C structs returned by function calls and loaded from volatile objects

2019-08-13 Thread John McCall via Phabricator via cfe-commits
rjmccall added inline comments.



Comment at: clang/lib/CodeGen/CGCall.h:372
+  REQUIRES_DESTRUCTION = 0x4,
 };
 

Does `llvm::Value*` actually guarantee three bits?  Presumably on 64-bit 
platforms, but we do support 32-bit hosts.

Fortunately, I don't actually think there's any reason to be space-conscious in 
this class; all the values are short-lived.  Might as well pull all the fields 
out into a bit-field or something.



Comment at: clang/lib/CodeGen/CGCall.h:390
+  return Value.getInt() & REQUIRES_DESTRUCTION;
+}
   };

I think the "is externally destructed" semantics make more sense — that is, the 
*default* should be that a destructor needs to get pushed, and maybe specific 
contexts should suppress that.  That will also let you avoid all the ugly code 
to compute whether destruction is required in a bunch of generic places.

Actually, "externally destructed" is a really problematic idea; we need to come 
up with a better solution for contexts that need to be careful about destructor 
ordering like this, and it should probably be based on passing around and 
deactivating destructors.  But that's for later.


Repository:
  rC Clang

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D66094/new/

https://reviews.llvm.org/D66094



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D66094: [CodeGen] Emit destructor calls for non-trivial C structs returned by function calls and loaded from volatile objects

2019-08-12 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak updated this revision to Diff 214660.
ahatanak added a comment.

Revert changes I made to llvm that are unrelated to this patch.


Repository:
  rC Clang

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D66094/new/

https://reviews.llvm.org/D66094

Files:
  clang/include/clang/Sema/Sema.h
  clang/lib/CodeGen/CGCall.h
  clang/lib/CodeGen/CGExpr.cpp
  clang/lib/CodeGen/CGExprAgg.cpp
  clang/lib/CodeGen/CGObjC.cpp
  clang/lib/Parse/ParseObjc.cpp
  clang/lib/Sema/SemaExpr.cpp
  clang/lib/Sema/SemaExprObjC.cpp
  clang/test/CodeGenObjC/arc.m
  clang/test/CodeGenObjC/strong-in-c-struct.m

Index: clang/test/CodeGenObjC/strong-in-c-struct.m
===
--- clang/test/CodeGenObjC/strong-in-c-struct.m
+++ clang/test/CodeGenObjC/strong-in-c-struct.m
@@ -90,6 +90,13 @@
 void calleeStrongSmall(StrongSmall);
 void func(Strong *);
 
+@interface C
+-(StrongSmall)getStrongSmall;
++(StrongSmall)getStrongSmallClass;
+@end
+
+id g0;
+
 // CHECK: %[[STRUCT_STRONGOUTER:.*]] = type { %[[STRUCT_STRONG:.*]], i8*, double }
 // CHECK: %[[STRUCT_STRONG]] = type { %[[STRUCT_TRIVIAL:.*]], i8* }
 // CHECK: %[[STRUCT_TRIVIAL]] = type { [4 x i32] }
@@ -477,6 +484,18 @@
   getStrongSmall();
 }
 
+// CHECK: define void @test_destructor_ignored_result2(%{{.*}}* %[[C:.*]])
+// CHECK: %[[TMP:.*]] = alloca %[[STRUCT_STRONGSMALL]], align 8
+// CHECK: %[[CALL:.*]] = call [2 x i64]{{.*}}@objc_msgSend
+// CHECK: %[[V5:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[TMP]] to [2 x i64]*
+// CHECK: store [2 x i64] %[[CALL]], [2 x i64]* %[[V5]], align 8
+// CHECK: %[[V6:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[TMP]] to i8**
+// CHECK: call void @__destructor_8_s8(i8** %[[V6]])
+
+void test_destructor_ignored_result2(C *c) {
+  [c getStrongSmall];
+}
+
 // CHECK: define void @test_copy_constructor_StrongBlock(
 // CHECK: call void @__copy_constructor_8_8_sb0(
 // CHECK: call void @__destructor_8_sb0(
@@ -521,7 +540,9 @@
 
 // CHECK: define void @test_copy_constructor_StrongVolatile0(
 // CHECK: call void @__copy_constructor_8_8_t0w4_sv8(
+// CHECK-NOT: call
 // CHECK: call void @__destructor_8_sv8(
+// CHECK-NOT: call
 
 // CHECK: define linkonce_odr hidden void @__copy_constructor_8_8_t0w4_sv8(
 // CHECK: %[[V8:.*]] = load volatile i8*, i8** %{{.*}}, align 8
@@ -718,4 +739,62 @@
   VolatileArray t = *a;
 }
 
+// CHECK: define void @test_member_access(
+// CHECK: %[[TMP:.*]] = alloca %[[STRUCT_STRONGSMALL]],
+// CHECK: %[[V3:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[TMP]] to i8**
+// CHECK: call void @__destructor_8_s8(i8** %[[V3]])
+// CHECK: call void @func(
+
+void test_member_access(void) {
+  g0 = getStrongSmall().f1;
+  func(0);
+}
+
+// CHECK: define void @test_member_access2(%{{.*}}* %[[C:.*]])
+// CHECK: %[[COERCE:.*]] = alloca %[[STRUCT_STRONGSMALL]], align 8
+// CHECK: %[[V8:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[COERCE]] to i8**
+// CHECK: call void @__destructor_8_s8(i8** %[[V8]])
+// CHECK: call void @func(
+
+void test_member_access2(C *c) {
+  g0 = [c getStrongSmall].f1;
+  func(0);
+}
+
+// CHECK: define void @test_member_access3(
+// CHECK: %[[COERCE:.*]] = alloca %[[STRUCT_STRONGSMALL]], align 8
+// CHECK: %[[V8:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[COERCE]] to i8**
+// CHECK: call void @__destructor_8_s8(i8** %[[V8]])
+// CHECK: call void @func(
+
+void test_member_access3(void) {
+  g0 = [C getStrongSmallClass].f1;
+  func(0);
+}
+
+// CHECK: define void @test_member_access4()
+// CHECK: %[[COERCE:.*]] = alloca %[[STRUCT_STRONGSMALL]], align 8
+// CHECK: %[[V5:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[COERCE]] to i8**
+// CHECK: call void @__destructor_8_s8(i8** %[[V5]])
+// CHECK: call void @func(
+
+void test_member_access4(void) {
+  g0 = ^{ StrongSmall s; return s; }().f1;
+  func(0);
+}
+
+// CHECK: define void @test_volatile_variable_reference(
+// CHECK: %[[AGG_TMP_ENSURED:.*]] = alloca %[[STRUCT_STRONGSMALL]],
+// CHECK: %[[V1:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[AGG_TMP_ENSURED]] to i8**
+// CHECK: %[[V2:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %{{.*}} to i8**
+// CHECK: call void @__copy_constructor_8_8_tv0w32_sv8(i8** %[[V1]], i8** %[[V2]])
+// CHECK: %[[V3:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[AGG_TMP_ENSURED]] to i8**
+// CHECK: call void @__destructor_8_s8(i8** %[[V3]])
+// CHECK: call void @func(
+
+void test_volatile_variable_reference(volatile StrongSmall *a) {
+  (void)*a;
+  func(0);
+}
+
 #endif /* USESTRUCT */
Index: clang/test/CodeGenObjC/arc.m
===
--- clang/test/CodeGenObjC/arc.m
+++ clang/test/CodeGenObjC/arc.m
@@ -1536,12 +1536,13 @@
 
 // CHECK-LABEL: define void @test71
 void test71(void) {
-  // FIXME: It would be nice if the __destructor_8_s40 for the first call (and
-  // the following lifetime.end) came before the second call.
-  //
   // CHECK: %[[T:[^ ]+]] = bitcast %struct.AggDtor* %[[TMP1:[^ ]+]] to i8*
   // CHECK: call void 

[PATCH] D66094: [CodeGen] Emit destructor calls for non-trivial C structs returned by function calls and loaded from volatile objects

2019-08-12 Thread Akira Hatanaka via Phabricator via cfe-commits
ahatanak created this revision.
ahatanak added a reviewer: rjmccall.
ahatanak added a project: clang.
Herald added subscribers: llvm-commits, dexonsmith, jkorous.
Herald added a project: LLVM.

This is the patch I split out of https://reviews.llvm.org/D64464.

The cleanup is pushed in `EmitCallExpr` and `EmitObjCMessageExpr` so that the 
destructor is called to destruct function call and ObjC message returns. I also 
added test cases for block function calls since the patch in 
https://reviews.llvm.org/D64464 wasn't handling that case correctly.

rdar://problem/51867864


Repository:
  rC Clang

https://reviews.llvm.org/D66094

Files:
  clang/include/clang/Sema/Sema.h
  clang/lib/CodeGen/CGCall.h
  clang/lib/CodeGen/CGExpr.cpp
  clang/lib/CodeGen/CGExprAgg.cpp
  clang/lib/CodeGen/CGObjC.cpp
  clang/lib/Parse/ParseObjc.cpp
  clang/lib/Sema/SemaExpr.cpp
  clang/lib/Sema/SemaExprObjC.cpp
  clang/test/CodeGenObjC/arc.m
  clang/test/CodeGenObjC/strong-in-c-struct.m
  llvm/test/Bitcode/upgrade-arc-runtime-calls.bc
  llvm/test/Bitcode/upgrade-mrr-runtime-calls.bc

Index: clang/test/CodeGenObjC/strong-in-c-struct.m
===
--- clang/test/CodeGenObjC/strong-in-c-struct.m
+++ clang/test/CodeGenObjC/strong-in-c-struct.m
@@ -90,6 +90,13 @@
 void calleeStrongSmall(StrongSmall);
 void func(Strong *);
 
+@interface C
+-(StrongSmall)getStrongSmall;
++(StrongSmall)getStrongSmallClass;
+@end
+
+id g0;
+
 // CHECK: %[[STRUCT_STRONGOUTER:.*]] = type { %[[STRUCT_STRONG:.*]], i8*, double }
 // CHECK: %[[STRUCT_STRONG]] = type { %[[STRUCT_TRIVIAL:.*]], i8* }
 // CHECK: %[[STRUCT_TRIVIAL]] = type { [4 x i32] }
@@ -477,6 +484,18 @@
   getStrongSmall();
 }
 
+// CHECK: define void @test_destructor_ignored_result2(%{{.*}}* %[[C:.*]])
+// CHECK: %[[TMP:.*]] = alloca %[[STRUCT_STRONGSMALL]], align 8
+// CHECK: %[[CALL:.*]] = call [2 x i64]{{.*}}@objc_msgSend
+// CHECK: %[[V5:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[TMP]] to [2 x i64]*
+// CHECK: store [2 x i64] %[[CALL]], [2 x i64]* %[[V5]], align 8
+// CHECK: %[[V6:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[TMP]] to i8**
+// CHECK: call void @__destructor_8_s8(i8** %[[V6]])
+
+void test_destructor_ignored_result2(C *c) {
+  [c getStrongSmall];
+}
+
 // CHECK: define void @test_copy_constructor_StrongBlock(
 // CHECK: call void @__copy_constructor_8_8_sb0(
 // CHECK: call void @__destructor_8_sb0(
@@ -521,7 +540,9 @@
 
 // CHECK: define void @test_copy_constructor_StrongVolatile0(
 // CHECK: call void @__copy_constructor_8_8_t0w4_sv8(
+// CHECK-NOT: call
 // CHECK: call void @__destructor_8_sv8(
+// CHECK-NOT: call
 
 // CHECK: define linkonce_odr hidden void @__copy_constructor_8_8_t0w4_sv8(
 // CHECK: %[[V8:.*]] = load volatile i8*, i8** %{{.*}}, align 8
@@ -718,4 +739,62 @@
   VolatileArray t = *a;
 }
 
+// CHECK: define void @test_member_access(
+// CHECK: %[[TMP:.*]] = alloca %[[STRUCT_STRONGSMALL]],
+// CHECK: %[[V3:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[TMP]] to i8**
+// CHECK: call void @__destructor_8_s8(i8** %[[V3]])
+// CHECK: call void @func(
+
+void test_member_access(void) {
+  g0 = getStrongSmall().f1;
+  func(0);
+}
+
+// CHECK: define void @test_member_access2(%{{.*}}* %[[C:.*]])
+// CHECK: %[[COERCE:.*]] = alloca %[[STRUCT_STRONGSMALL]], align 8
+// CHECK: %[[V8:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[COERCE]] to i8**
+// CHECK: call void @__destructor_8_s8(i8** %[[V8]])
+// CHECK: call void @func(
+
+void test_member_access2(C *c) {
+  g0 = [c getStrongSmall].f1;
+  func(0);
+}
+
+// CHECK: define void @test_member_access3(
+// CHECK: %[[COERCE:.*]] = alloca %[[STRUCT_STRONGSMALL]], align 8
+// CHECK: %[[V8:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[COERCE]] to i8**
+// CHECK: call void @__destructor_8_s8(i8** %[[V8]])
+// CHECK: call void @func(
+
+void test_member_access3(void) {
+  g0 = [C getStrongSmallClass].f1;
+  func(0);
+}
+
+// CHECK: define void @test_member_access4()
+// CHECK: %[[COERCE:.*]] = alloca %[[STRUCT_STRONGSMALL]], align 8
+// CHECK: %[[V5:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[COERCE]] to i8**
+// CHECK: call void @__destructor_8_s8(i8** %[[V5]])
+// CHECK: call void @func(
+
+void test_member_access4(void) {
+  g0 = ^{ StrongSmall s; return s; }().f1;
+  func(0);
+}
+
+// CHECK: define void @test_volatile_variable_reference(
+// CHECK: %[[AGG_TMP_ENSURED:.*]] = alloca %[[STRUCT_STRONGSMALL]],
+// CHECK: %[[V1:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[AGG_TMP_ENSURED]] to i8**
+// CHECK: %[[V2:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %{{.*}} to i8**
+// CHECK: call void @__copy_constructor_8_8_tv0w32_sv8(i8** %[[V1]], i8** %[[V2]])
+// CHECK: %[[V3:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[AGG_TMP_ENSURED]] to i8**
+// CHECK: call void @__destructor_8_s8(i8** %[[V3]])
+// CHECK: call void @func(
+
+void test_volatile_variable_reference(volatile StrongSmall *a) {
+  (void)*a;
+  func(0);
+}
+
 #endif /* USESTRUCT */
Index: clang/test/CodeGenObjC/arc.m