[PATCH] D81885: [Coroutines] Return false on error of buildSuspends

2020-06-15 Thread Xun Li via Phabricator via cfe-commits
lxfind created this revision.
lxfind added a reviewer: modocache.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

I believe we need to return false when buildSuspends failed, to indicate that 
ActOnCoroutineBodyStart failed.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D81885

Files:
  clang/lib/Sema/SemaCoroutine.cpp


Index: clang/lib/Sema/SemaCoroutine.cpp
===
--- clang/lib/Sema/SemaCoroutine.cpp
+++ clang/lib/Sema/SemaCoroutine.cpp
@@ -643,11 +643,11 @@
 
   StmtResult InitSuspend = buildSuspends("initial_suspend");
   if (InitSuspend.isInvalid())
-return true;
+return false;
 
   StmtResult FinalSuspend = buildSuspends("final_suspend");
   if (FinalSuspend.isInvalid())
-return true;
+return false;
 
   ScopeInfo->setCoroutineSuspends(InitSuspend.get(), FinalSuspend.get());
 


Index: clang/lib/Sema/SemaCoroutine.cpp
===
--- clang/lib/Sema/SemaCoroutine.cpp
+++ clang/lib/Sema/SemaCoroutine.cpp
@@ -643,11 +643,11 @@
 
   StmtResult InitSuspend = buildSuspends("initial_suspend");
   if (InitSuspend.isInvalid())
-return true;
+return false;
 
   StmtResult FinalSuspend = buildSuspends("final_suspend");
   if (FinalSuspend.isInvalid())
-return true;
+return false;
 
   ScopeInfo->setCoroutineSuspends(InitSuspend.get(), FinalSuspend.get());
 
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D81885: [Coroutines] Return false on error of buildSuspends

2020-06-15 Thread Xun Li via Phabricator via cfe-commits
lxfind updated this revision to Diff 270929.
lxfind added a comment.

Adjust tests


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D81885

Files:
  clang/lib/Sema/SemaCoroutine.cpp
  clang/test/SemaCXX/coroutines.cpp


Index: clang/test/SemaCXX/coroutines.cpp
===
--- clang/test/SemaCXX/coroutines.cpp
+++ clang/test/SemaCXX/coroutines.cpp
@@ -103,7 +103,7 @@
   struct promise_type {};
 };
 double bad_promise_type_2(int) { // expected-error {{no member named 
'initial_suspend'}}
-  co_yield 0; // expected-error {{no member named 'yield_value' in 
'std::experimental::coroutine_traits::promise_type'}}
+  co_yield 0;
 }
 
 struct promise; // expected-note {{forward declaration}}
@@ -476,7 +476,6 @@
   // expected-note@-1 {{call to 'initial_suspend' implicitly required by 
the initial suspend point}}
   // expected-note@+1 {{function is a coroutine due to use of 'co_await' 
here}}
   co_await transform_awaitable{};
-  // expected-error@-1 {{no member named 'await_ready'}}
 }
 template 
 coro dep_mem_fn(U u) { co_await u; }
@@ -494,7 +493,6 @@
 //expected-note@-1 {{call to 'initial_suspend' implicitly required by the 
initial suspend point}}
 //expected-note@+1 {{function is a coroutine due to use of 'co_await' 
here}}
 co_await transform_awaitable{};
-// expected-error@-1 {{no member named 'await_ready'}}
   }
 
   void operator co_await(transform_awaitable) = delete;
Index: clang/lib/Sema/SemaCoroutine.cpp
===
--- clang/lib/Sema/SemaCoroutine.cpp
+++ clang/lib/Sema/SemaCoroutine.cpp
@@ -643,11 +643,11 @@
 
   StmtResult InitSuspend = buildSuspends("initial_suspend");
   if (InitSuspend.isInvalid())
-return true;
+return false;
 
   StmtResult FinalSuspend = buildSuspends("final_suspend");
   if (FinalSuspend.isInvalid())
-return true;
+return false;
 
   ScopeInfo->setCoroutineSuspends(InitSuspend.get(), FinalSuspend.get());
 


Index: clang/test/SemaCXX/coroutines.cpp
===
--- clang/test/SemaCXX/coroutines.cpp
+++ clang/test/SemaCXX/coroutines.cpp
@@ -103,7 +103,7 @@
   struct promise_type {};
 };
 double bad_promise_type_2(int) { // expected-error {{no member named 'initial_suspend'}}
-  co_yield 0; // expected-error {{no member named 'yield_value' in 'std::experimental::coroutine_traits::promise_type'}}
+  co_yield 0;
 }
 
 struct promise; // expected-note {{forward declaration}}
@@ -476,7 +476,6 @@
   // expected-note@-1 {{call to 'initial_suspend' implicitly required by the initial suspend point}}
   // expected-note@+1 {{function is a coroutine due to use of 'co_await' here}}
   co_await transform_awaitable{};
-  // expected-error@-1 {{no member named 'await_ready'}}
 }
 template 
 coro dep_mem_fn(U u) { co_await u; }
@@ -494,7 +493,6 @@
 //expected-note@-1 {{call to 'initial_suspend' implicitly required by the initial suspend point}}
 //expected-note@+1 {{function is a coroutine due to use of 'co_await' here}}
 co_await transform_awaitable{};
-// expected-error@-1 {{no member named 'await_ready'}}
   }
 
   void operator co_await(transform_awaitable) = delete;
Index: clang/lib/Sema/SemaCoroutine.cpp
===
--- clang/lib/Sema/SemaCoroutine.cpp
+++ clang/lib/Sema/SemaCoroutine.cpp
@@ -643,11 +643,11 @@
 
   StmtResult InitSuspend = buildSuspends("initial_suspend");
   if (InitSuspend.isInvalid())
-return true;
+return false;
 
   StmtResult FinalSuspend = buildSuspends("final_suspend");
   if (FinalSuspend.isInvalid())
-return true;
+return false;
 
   ScopeInfo->setCoroutineSuspends(InitSuspend.get(), FinalSuspend.get());
 
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D82029: [Coroutines] Ensure co_await promise.final_suspend() does not throw

2020-06-17 Thread Xun Li via Phabricator via cfe-commits
lxfind created this revision.
lxfind added reviewers: lewissbaker, modocache.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

This patch addresses https://bugs.llvm.org/show_bug.cgi?id=46256
The spec of coroutine requires that the expression co_­await 
promise.final_­suspend() shall not be potentially-throwing.
To check this, we recursively look at every call (including Call, MemberCall, 
OperatorCall and Constructor) in all code
generated by the final suspend, and ensure that the callees are declared with 
noexcept. We also look at any returned data
type that requires explicit destruction, and check their destructors for 
noexcept.

This patch does not check declarations with dependent types yet, which will be 
done in future patches.

Updated all tests to add noexcept to the required functions, and added a 
dedicated test for this patch.

This patch might start to cause existing codebase fail to compile because most 
people may not have been strict in tagging
all the related functions noexcept.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D82029

Files:
  clang/include/clang/Basic/DiagnosticSemaKinds.td
  clang/include/clang/Sema/Sema.h
  clang/lib/Sema/SemaCoroutine.cpp
  clang/lib/Sema/SemaExceptionSpec.cpp
  clang/test/AST/Inputs/std-coroutine.h
  clang/test/AST/coroutine-source-location-crash.cpp
  clang/test/CodeGenCXX/ubsan-coroutines.cpp
  clang/test/CodeGenCoroutines/Inputs/coroutine.h
  clang/test/CodeGenCoroutines/coro-alloc.cpp
  clang/test/CodeGenCoroutines/coro-always-inline.cpp
  clang/test/CodeGenCoroutines/coro-await-domination.cpp
  clang/test/CodeGenCoroutines/coro-await-resume-eh.cpp
  clang/test/CodeGenCoroutines/coro-await.cpp
  clang/test/CodeGenCoroutines/coro-dest-slot.cpp
  clang/test/CodeGenCoroutines/coro-gro-nrvo.cpp
  clang/test/CodeGenCoroutines/coro-newpm-pipeline.cpp
  clang/test/CodeGenCoroutines/coro-params.cpp
  clang/test/CodeGenCoroutines/coro-promise-dtor.cpp
  clang/test/CodeGenCoroutines/coro-ret-void.cpp
  clang/test/CodeGenCoroutines/coro-return-voidtype-initlist.cpp
  clang/test/CodeGenCoroutines/coro-return.cpp
  clang/test/CodeGenCoroutines/coro-unhandled-exception.cpp
  clang/test/SemaCXX/Inputs/std-coroutine.h
  clang/test/SemaCXX/coroutine-final-suspend-noexcept.cpp
  clang/test/SemaCXX/coroutine-rvo.cpp
  clang/test/SemaCXX/coroutine-unhandled_exception-warning.cpp
  clang/test/SemaCXX/coroutine-uninitialized-warning-crash.cpp
  clang/test/SemaCXX/coroutines.cpp

Index: clang/test/SemaCXX/coroutines.cpp
===
--- clang/test/SemaCXX/coroutines.cpp
+++ clang/test/SemaCXX/coroutines.cpp
@@ -52,21 +52,24 @@
 };
 
 struct awaitable {
-  bool await_ready();
-  template  void await_suspend(F);
-  void await_resume();
+  bool await_ready() noexcept;
+  template 
+  void await_suspend(F) noexcept;
+  void await_resume() noexcept;
 } a;
 
 struct suspend_always {
-  bool await_ready() { return false; }
-  template  void await_suspend(F);
-  void await_resume() {}
+  bool await_ready() noexcept { return false; }
+  template 
+  void await_suspend(F) noexcept;
+  void await_resume() noexcept {}
 };
 
 struct suspend_never {
-  bool await_ready() { return true; }
-  template  void await_suspend(F);
-  void await_resume() {}
+  bool await_ready() noexcept { return true; }
+  template 
+  void await_suspend(F) noexcept;
+  void await_resume() noexcept {}
 };
 
 struct auto_await_suspend {
@@ -127,7 +130,7 @@
 struct promise {
   void get_return_object();
   suspend_always initial_suspend();
-  suspend_always final_suspend();
+  suspend_always final_suspend() noexcept;
   awaitable yield_value(int); // expected-note 2{{candidate}}
   awaitable yield_value(yielded_thing); // expected-note 2{{candidate}}
   not_awaitable yield_value(void()); // expected-note 2{{candidate}}
@@ -138,7 +141,7 @@
 struct promise_void {
   void get_return_object();
   suspend_always initial_suspend();
-  suspend_always final_suspend();
+  suspend_always final_suspend() noexcept;
   void return_void();
   void unhandled_exception();
 };
@@ -152,13 +155,13 @@
 namespace experimental {
 template 
 struct coroutine_handle {
-  static coroutine_handle from_address(void *);
+  static coroutine_handle from_address(void *) noexcept;
 };
 template <>
 struct coroutine_handle {
   template 
-  coroutine_handle(coroutine_handle);
-  static coroutine_handle from_address(void *);
+  coroutine_handle(coroutine_handle) noexcept;
+  static coroutine_handle from_address(void *) noexcept;
 };
 }} // namespace std::experimental
 
@@ -402,7 +405,7 @@
 
 namespace adl_ns {
 struct coawait_arg_type {};
-awaitable operator co_await(coawait_arg_type);
+awaitable operator co_await(coawait_arg_type) noexcept;
 }
 
 namespace dependent_operator_co_await_lookup {
@@ -434,7 +437,7 @@
 typedef transform_awaitable await_arg;
 coro get_return_object();
 transformed initial_suspend();
-::adl_ns::coawait_arg

[PATCH] D82928: [Coroutines] Fix code coverage for coroutine

2020-07-01 Thread Xun Li via Phabricator via cfe-commits
lxfind updated this revision to Diff 274836.
lxfind added a comment.

Rebase


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D82928

Files:
  clang/lib/CodeGen/CoverageMappingGen.cpp
  clang/test/CoverageMapping/coroutine.cpp


Index: clang/test/CoverageMapping/coroutine.cpp
===
--- /dev/null
+++ clang/test/CoverageMapping/coroutine.cpp
@@ -0,0 +1,45 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fcoroutines-ts -std=c++14 
-emit-llvm -fprofile-instrument=clang -fcoverage-mapping -dump-coverage-mapping 
%s | FileCheck %s
+
+namespace std::experimental {
+template 
+struct coroutine_traits;
+
+template 
+struct coroutine_handle {
+  coroutine_handle() = default;
+  static coroutine_handle from_address(void *) noexcept { return {}; }
+};
+template <>
+struct coroutine_handle {
+  static coroutine_handle from_address(void *) { return {}; }
+  coroutine_handle() = default;
+  template 
+  coroutine_handle(coroutine_handle) noexcept {}
+};
+} // namespace std::experimental
+
+struct suspend_always {
+  bool await_ready() noexcept;
+  void await_suspend(std::experimental::coroutine_handle<>) noexcept;
+  void await_resume() noexcept;
+};
+
+template <>
+struct std::experimental::coroutine_traits {
+  struct promise_type {
+int get_return_object();
+suspend_always initial_suspend();
+suspend_always final_suspend() noexcept;
+void return_value(int);
+  };
+};
+
+// CHECK-LABEL: _Z2f1i:
+int f1(int x) {   // CHECK-NEXT: File 0, [[@LINE]]:15 -> [[@LINE+7]]:2 = #0
+  if (x > 42) {   // CHECK-NEXT: File 0, [[@LINE]]:7 -> [[@LINE]]:13 = #0
+++x;  // CHECK-NEXT: Gap,File 0, [[@LINE-1]]:14 -> 
[[@LINE-1]]:15 = #1
+  } else {// CHECK-NEXT: File 0, [[@LINE-2]]:15 -> [[@LINE]]:4 = #1
+co_return x + 42; // CHECK-NEXT: Gap,File 0, [[@LINE-1]]:4 -> 
[[@LINE-1]]:10 = (#0 - #1)
+  }   // CHECK-NEXT: File 0, [[@LINE-2]]:10 -> [[@LINE]]:4 = 
(#0 - #1)
+  co_return x;// CHECK-NEXT: Gap,File 0, [[@LINE-1]]:4 -> [[@LINE]]:3 
= #1
+} // CHECK-NEXT: File 0, [[@LINE-1]]:3 -> [[@LINE]]:2 = #1
Index: clang/lib/CodeGen/CoverageMappingGen.cpp
===
--- clang/lib/CodeGen/CoverageMappingGen.cpp
+++ clang/lib/CodeGen/CoverageMappingGen.cpp
@@ -908,6 +908,18 @@
 terminateRegion(S);
   }
 
+  void VisitCoroutineBodyStmt(const CoroutineBodyStmt *S) {
+extendRegion(S);
+Visit(S->getBody());
+  }
+
+  void VisitCoreturnStmt(const CoreturnStmt *S) {
+extendRegion(S);
+if (S->getOperand())
+  Visit(S->getOperand());
+terminateRegion(S);
+  }
+
   void VisitCXXThrowExpr(const CXXThrowExpr *E) {
 extendRegion(E);
 if (E->getSubExpr())


Index: clang/test/CoverageMapping/coroutine.cpp
===
--- /dev/null
+++ clang/test/CoverageMapping/coroutine.cpp
@@ -0,0 +1,45 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fcoroutines-ts -std=c++14 -emit-llvm -fprofile-instrument=clang -fcoverage-mapping -dump-coverage-mapping %s | FileCheck %s
+
+namespace std::experimental {
+template 
+struct coroutine_traits;
+
+template 
+struct coroutine_handle {
+  coroutine_handle() = default;
+  static coroutine_handle from_address(void *) noexcept { return {}; }
+};
+template <>
+struct coroutine_handle {
+  static coroutine_handle from_address(void *) { return {}; }
+  coroutine_handle() = default;
+  template 
+  coroutine_handle(coroutine_handle) noexcept {}
+};
+} // namespace std::experimental
+
+struct suspend_always {
+  bool await_ready() noexcept;
+  void await_suspend(std::experimental::coroutine_handle<>) noexcept;
+  void await_resume() noexcept;
+};
+
+template <>
+struct std::experimental::coroutine_traits {
+  struct promise_type {
+int get_return_object();
+suspend_always initial_suspend();
+suspend_always final_suspend() noexcept;
+void return_value(int);
+  };
+};
+
+// CHECK-LABEL: _Z2f1i:
+int f1(int x) {   // CHECK-NEXT: File 0, [[@LINE]]:15 -> [[@LINE+7]]:2 = #0
+  if (x > 42) {   // CHECK-NEXT: File 0, [[@LINE]]:7 -> [[@LINE]]:13 = #0
+++x;  // CHECK-NEXT: Gap,File 0, [[@LINE-1]]:14 -> [[@LINE-1]]:15 = #1
+  } else {// CHECK-NEXT: File 0, [[@LINE-2]]:15 -> [[@LINE]]:4 = #1
+co_return x + 42; // CHECK-NEXT: Gap,File 0, [[@LINE-1]]:4 -> [[@LINE-1]]:10 = (#0 - #1)
+  }   // CHECK-NEXT: File 0, [[@LINE-2]]:10 -> [[@LINE]]:4 = (#0 - #1)
+  co_return x;// CHECK-NEXT: Gap,File 0, [[@LINE-1]]:4 -> [[@LINE]]:3 = #1
+} // CHECK-NEXT: File 0, [[@LINE-1]]:3 -> [[@LINE]]:2 = #1
Index: clang/lib/CodeGen/CoverageMappingGen.cpp
===
--- clang/lib/CodeGen/CoverageMappingGen.cpp
+++ clang/lib/CodeGen/CoverageMappingGen.cpp
@@ -908

[PATCH] D82314: [Coroutines] Optimize the lifespan of temporary co_await object

2020-07-01 Thread Xun Li via Phabricator via cfe-commits
lxfind added a comment.

In D82314#2124662 , @junparser wrote:

> In D82314#2124661 , @junparser wrote:
>
> > @lxfind This patch causes some mismatch when variable is used in both 
> > resume and destroy function. Besides, we should move this patch and the 
> > check in buildCoroutineFrame.
>
>
> @lxfind, Would you try to fix this? If you do not have time, then I'll try do 
> this. Thanks


Could you please help take a look, if you have a local repro? Thanks!


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D82314



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


[PATCH] D82928: [Coroutines] Fix code coverage for coroutine

2020-07-01 Thread Xun Li via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rG565e37c7702d: [Coroutines] Fix code coverage for coroutine 
(authored by lxfind).

Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D82928

Files:
  clang/lib/CodeGen/CoverageMappingGen.cpp
  clang/test/CoverageMapping/coroutine.cpp


Index: clang/test/CoverageMapping/coroutine.cpp
===
--- /dev/null
+++ clang/test/CoverageMapping/coroutine.cpp
@@ -0,0 +1,45 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fcoroutines-ts -std=c++14 
-emit-llvm -fprofile-instrument=clang -fcoverage-mapping -dump-coverage-mapping 
%s | FileCheck %s
+
+namespace std::experimental {
+template 
+struct coroutine_traits;
+
+template 
+struct coroutine_handle {
+  coroutine_handle() = default;
+  static coroutine_handle from_address(void *) noexcept { return {}; }
+};
+template <>
+struct coroutine_handle {
+  static coroutine_handle from_address(void *) { return {}; }
+  coroutine_handle() = default;
+  template 
+  coroutine_handle(coroutine_handle) noexcept {}
+};
+} // namespace std::experimental
+
+struct suspend_always {
+  bool await_ready() noexcept;
+  void await_suspend(std::experimental::coroutine_handle<>) noexcept;
+  void await_resume() noexcept;
+};
+
+template <>
+struct std::experimental::coroutine_traits {
+  struct promise_type {
+int get_return_object();
+suspend_always initial_suspend();
+suspend_always final_suspend() noexcept;
+void return_value(int);
+  };
+};
+
+// CHECK-LABEL: _Z2f1i:
+int f1(int x) {   // CHECK-NEXT: File 0, [[@LINE]]:15 -> [[@LINE+7]]:2 = #0
+  if (x > 42) {   // CHECK-NEXT: File 0, [[@LINE]]:7 -> [[@LINE]]:13 = #0
+++x;  // CHECK-NEXT: Gap,File 0, [[@LINE-1]]:14 -> 
[[@LINE-1]]:15 = #1
+  } else {// CHECK-NEXT: File 0, [[@LINE-2]]:15 -> [[@LINE]]:4 = #1
+co_return x + 42; // CHECK-NEXT: Gap,File 0, [[@LINE-1]]:4 -> 
[[@LINE-1]]:10 = (#0 - #1)
+  }   // CHECK-NEXT: File 0, [[@LINE-2]]:10 -> [[@LINE]]:4 = 
(#0 - #1)
+  co_return x;// CHECK-NEXT: Gap,File 0, [[@LINE-1]]:4 -> [[@LINE]]:3 
= #1
+} // CHECK-NEXT: File 0, [[@LINE-1]]:3 -> [[@LINE]]:2 = #1
Index: clang/lib/CodeGen/CoverageMappingGen.cpp
===
--- clang/lib/CodeGen/CoverageMappingGen.cpp
+++ clang/lib/CodeGen/CoverageMappingGen.cpp
@@ -908,6 +908,18 @@
 terminateRegion(S);
   }
 
+  void VisitCoroutineBodyStmt(const CoroutineBodyStmt *S) {
+extendRegion(S);
+Visit(S->getBody());
+  }
+
+  void VisitCoreturnStmt(const CoreturnStmt *S) {
+extendRegion(S);
+if (S->getOperand())
+  Visit(S->getOperand());
+terminateRegion(S);
+  }
+
   void VisitCXXThrowExpr(const CXXThrowExpr *E) {
 extendRegion(E);
 if (E->getSubExpr())


Index: clang/test/CoverageMapping/coroutine.cpp
===
--- /dev/null
+++ clang/test/CoverageMapping/coroutine.cpp
@@ -0,0 +1,45 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fcoroutines-ts -std=c++14 -emit-llvm -fprofile-instrument=clang -fcoverage-mapping -dump-coverage-mapping %s | FileCheck %s
+
+namespace std::experimental {
+template 
+struct coroutine_traits;
+
+template 
+struct coroutine_handle {
+  coroutine_handle() = default;
+  static coroutine_handle from_address(void *) noexcept { return {}; }
+};
+template <>
+struct coroutine_handle {
+  static coroutine_handle from_address(void *) { return {}; }
+  coroutine_handle() = default;
+  template 
+  coroutine_handle(coroutine_handle) noexcept {}
+};
+} // namespace std::experimental
+
+struct suspend_always {
+  bool await_ready() noexcept;
+  void await_suspend(std::experimental::coroutine_handle<>) noexcept;
+  void await_resume() noexcept;
+};
+
+template <>
+struct std::experimental::coroutine_traits {
+  struct promise_type {
+int get_return_object();
+suspend_always initial_suspend();
+suspend_always final_suspend() noexcept;
+void return_value(int);
+  };
+};
+
+// CHECK-LABEL: _Z2f1i:
+int f1(int x) {   // CHECK-NEXT: File 0, [[@LINE]]:15 -> [[@LINE+7]]:2 = #0
+  if (x > 42) {   // CHECK-NEXT: File 0, [[@LINE]]:7 -> [[@LINE]]:13 = #0
+++x;  // CHECK-NEXT: Gap,File 0, [[@LINE-1]]:14 -> [[@LINE-1]]:15 = #1
+  } else {// CHECK-NEXT: File 0, [[@LINE-2]]:15 -> [[@LINE]]:4 = #1
+co_return x + 42; // CHECK-NEXT: Gap,File 0, [[@LINE-1]]:4 -> [[@LINE-1]]:10 = (#0 - #1)
+  }   // CHECK-NEXT: File 0, [[@LINE-2]]:10 -> [[@LINE]]:4 = (#0 - #1)
+  co_return x;// CHECK-NEXT: Gap,File 0, [[@LINE-1]]:4 -> [[@LINE]]:3 = #1
+} // CHECK-NEXT: File 0, [[@LINE-1]]:3 -> [[@LINE]]:2 = #1
Index: clang/lib/CodeGen/CoverageMappingGen.cpp
===

[PATCH] D82928: [Coroutines] Fix code coverage for coroutine

2020-07-01 Thread Xun Li via Phabricator via cfe-commits
lxfind added a comment.

In D82928#2126018 , @fhahn wrote:

> Looks like this causes a bunch of build bot failures, e.g 
> http://lab.llvm.org:8011/builders/clang-x86_64-debian-fast/builds/31465  b
>
> It would be great if you could take a look.


Looks like it's creating a tmp file within the test dir. Let me take a look.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D82928



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


[PATCH] D82984: Revert "[Coroutines] Fix code coverage for coroutine"

2020-07-01 Thread Xun Li via Phabricator via cfe-commits
lxfind created this revision.
lxfind added reviewers: fhahn, modocache.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.
lxfind abandoned this revision.
lxfind added a comment.

Fix up in https://reviews.llvm.org/D82986


This reverts commit 565e37c7702d181804c12d36b6010c513c9b3417 
.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D82984

Files:
  clang/lib/CodeGen/CoverageMappingGen.cpp
  clang/test/CoverageMapping/coroutine.cpp


Index: clang/test/CoverageMapping/coroutine.cpp
===
--- clang/test/CoverageMapping/coroutine.cpp
+++ /dev/null
@@ -1,45 +0,0 @@
-// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fcoroutines-ts -std=c++14 
-emit-llvm -fprofile-instrument=clang -fcoverage-mapping -dump-coverage-mapping 
%s | FileCheck %s
-
-namespace std::experimental {
-template 
-struct coroutine_traits;
-
-template 
-struct coroutine_handle {
-  coroutine_handle() = default;
-  static coroutine_handle from_address(void *) noexcept { return {}; }
-};
-template <>
-struct coroutine_handle {
-  static coroutine_handle from_address(void *) { return {}; }
-  coroutine_handle() = default;
-  template 
-  coroutine_handle(coroutine_handle) noexcept {}
-};
-} // namespace std::experimental
-
-struct suspend_always {
-  bool await_ready() noexcept;
-  void await_suspend(std::experimental::coroutine_handle<>) noexcept;
-  void await_resume() noexcept;
-};
-
-template <>
-struct std::experimental::coroutine_traits {
-  struct promise_type {
-int get_return_object();
-suspend_always initial_suspend();
-suspend_always final_suspend() noexcept;
-void return_value(int);
-  };
-};
-
-// CHECK-LABEL: _Z2f1i:
-int f1(int x) {   // CHECK-NEXT: File 0, [[@LINE]]:15 -> [[@LINE+7]]:2 = #0
-  if (x > 42) {   // CHECK-NEXT: File 0, [[@LINE]]:7 -> [[@LINE]]:13 = #0
-++x;  // CHECK-NEXT: Gap,File 0, [[@LINE-1]]:14 -> 
[[@LINE-1]]:15 = #1
-  } else {// CHECK-NEXT: File 0, [[@LINE-2]]:15 -> [[@LINE]]:4 = #1
-co_return x + 42; // CHECK-NEXT: Gap,File 0, [[@LINE-1]]:4 -> 
[[@LINE-1]]:10 = (#0 - #1)
-  }   // CHECK-NEXT: File 0, [[@LINE-2]]:10 -> [[@LINE]]:4 = 
(#0 - #1)
-  co_return x;// CHECK-NEXT: Gap,File 0, [[@LINE-1]]:4 -> [[@LINE]]:3 
= #1
-} // CHECK-NEXT: File 0, [[@LINE-1]]:3 -> [[@LINE]]:2 = #1
Index: clang/lib/CodeGen/CoverageMappingGen.cpp
===
--- clang/lib/CodeGen/CoverageMappingGen.cpp
+++ clang/lib/CodeGen/CoverageMappingGen.cpp
@@ -908,18 +908,6 @@
 terminateRegion(S);
   }
 
-  void VisitCoroutineBodyStmt(const CoroutineBodyStmt *S) {
-extendRegion(S);
-Visit(S->getBody());
-  }
-
-  void VisitCoreturnStmt(const CoreturnStmt *S) {
-extendRegion(S);
-if (S->getOperand())
-  Visit(S->getOperand());
-terminateRegion(S);
-  }
-
   void VisitCXXThrowExpr(const CXXThrowExpr *E) {
 extendRegion(E);
 if (E->getSubExpr())


Index: clang/test/CoverageMapping/coroutine.cpp
===
--- clang/test/CoverageMapping/coroutine.cpp
+++ /dev/null
@@ -1,45 +0,0 @@
-// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fcoroutines-ts -std=c++14 -emit-llvm -fprofile-instrument=clang -fcoverage-mapping -dump-coverage-mapping %s | FileCheck %s
-
-namespace std::experimental {
-template 
-struct coroutine_traits;
-
-template 
-struct coroutine_handle {
-  coroutine_handle() = default;
-  static coroutine_handle from_address(void *) noexcept { return {}; }
-};
-template <>
-struct coroutine_handle {
-  static coroutine_handle from_address(void *) { return {}; }
-  coroutine_handle() = default;
-  template 
-  coroutine_handle(coroutine_handle) noexcept {}
-};
-} // namespace std::experimental
-
-struct suspend_always {
-  bool await_ready() noexcept;
-  void await_suspend(std::experimental::coroutine_handle<>) noexcept;
-  void await_resume() noexcept;
-};
-
-template <>
-struct std::experimental::coroutine_traits {
-  struct promise_type {
-int get_return_object();
-suspend_always initial_suspend();
-suspend_always final_suspend() noexcept;
-void return_value(int);
-  };
-};
-
-// CHECK-LABEL: _Z2f1i:
-int f1(int x) {   // CHECK-NEXT: File 0, [[@LINE]]:15 -> [[@LINE+7]]:2 = #0
-  if (x > 42) {   // CHECK-NEXT: File 0, [[@LINE]]:7 -> [[@LINE]]:13 = #0
-++x;  // CHECK-NEXT: Gap,File 0, [[@LINE-1]]:14 -> [[@LINE-1]]:15 = #1
-  } else {// CHECK-NEXT: File 0, [[@LINE-2]]:15 -> [[@LINE]]:4 = #1
-co_return x + 42; // CHECK-NEXT: Gap,File 0, [[@LINE-1]]:4 -> [[@LINE-1]]:10 = (#0 - #1)
-  }   // CHECK-NEXT: File 0, [[@LINE-2]]:10 -> [[@LINE]]:4 = (#0 - #1)
-  co_return x;// CHECK-NEXT: Gap,File 0, [[@LINE-1]]:4 -> [[@LINE]]:3 = #1
-} // CHECK-NEXT: File 0, [[@LINE-1]]:3

[PATCH] D82928: [Coroutines] Fix code coverage for coroutine

2020-07-01 Thread Xun Li via Phabricator via cfe-commits
lxfind added a comment.

In D82928#2126018 , @fhahn wrote:

> Looks like this causes a bunch of build bot failures, e.g 
> http://lab.llvm.org:8011/builders/clang-x86_64-debian-fast/builds/31465  b
>
> It would be great if you could take a look.


Let me revert it for now while fixing it. If you could accept: 
https://reviews.llvm.org/D82984


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D82928



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


[PATCH] D82984: Revert "[Coroutines] Fix code coverage for coroutine"

2020-07-01 Thread Xun Li via Phabricator via cfe-commits
lxfind abandoned this revision.
lxfind added a comment.

Fix up in https://reviews.llvm.org/D82986


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D82984



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


[PATCH] D82986: [Coroutines] Fix test breakage in D82928

2020-07-01 Thread Xun Li via Phabricator via cfe-commits
lxfind created this revision.
lxfind added reviewers: modocache, fhahn.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.
modocache accepted this revision.
modocache added a comment.
This revision is now accepted and ready to land.

Thanks for the fix!


The test file in D82928  generated temp files 
within the test directory, causing test failures. Fix it.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D82986

Files:
  clang/test/CoverageMapping/coroutine.cpp


Index: clang/test/CoverageMapping/coroutine.cpp
===
--- clang/test/CoverageMapping/coroutine.cpp
+++ clang/test/CoverageMapping/coroutine.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fcoroutines-ts -std=c++14 
-emit-llvm -fprofile-instrument=clang -fcoverage-mapping -dump-coverage-mapping 
%s | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fcoroutines-ts -std=c++14 
-emit-llvm -fprofile-instrument=clang -fcoverage-mapping -dump-coverage-mapping 
%s -o - | FileCheck %s
 
 namespace std::experimental {
 template 


Index: clang/test/CoverageMapping/coroutine.cpp
===
--- clang/test/CoverageMapping/coroutine.cpp
+++ clang/test/CoverageMapping/coroutine.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fcoroutines-ts -std=c++14 -emit-llvm -fprofile-instrument=clang -fcoverage-mapping -dump-coverage-mapping %s | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fcoroutines-ts -std=c++14 -emit-llvm -fprofile-instrument=clang -fcoverage-mapping -dump-coverage-mapping %s -o - | FileCheck %s
 
 namespace std::experimental {
 template 
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D82928: [Coroutines] Fix code coverage for coroutine

2020-07-01 Thread Xun Li via Phabricator via cfe-commits
lxfind added a comment.

In D82928#2126018 , @fhahn wrote:

> Looks like this causes a bunch of build bot failures, e.g 
> http://lab.llvm.org:8011/builders/clang-x86_64-debian-fast/builds/31465  b
>
> It would be great if you could take a look.


Fix patch in https://reviews.llvm.org/D82986


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D82928



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


[PATCH] D82986: [Coroutines] Fix test breakage in D82928

2020-07-01 Thread Xun Li via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rGddcf063dd52f: [Coroutines] Fix test breakage in D82928 
(authored by lxfind).

Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D82986

Files:
  clang/test/CoverageMapping/coroutine.cpp


Index: clang/test/CoverageMapping/coroutine.cpp
===
--- clang/test/CoverageMapping/coroutine.cpp
+++ clang/test/CoverageMapping/coroutine.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fcoroutines-ts -std=c++14 
-emit-llvm -fprofile-instrument=clang -fcoverage-mapping -dump-coverage-mapping 
%s | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fcoroutines-ts -std=c++14 
-emit-llvm -fprofile-instrument=clang -fcoverage-mapping -dump-coverage-mapping 
%s -o - | FileCheck %s
 
 namespace std::experimental {
 template 


Index: clang/test/CoverageMapping/coroutine.cpp
===
--- clang/test/CoverageMapping/coroutine.cpp
+++ clang/test/CoverageMapping/coroutine.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fcoroutines-ts -std=c++14 -emit-llvm -fprofile-instrument=clang -fcoverage-mapping -dump-coverage-mapping %s | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fcoroutines-ts -std=c++14 -emit-llvm -fprofile-instrument=clang -fcoverage-mapping -dump-coverage-mapping %s -o - | FileCheck %s
 
 namespace std::experimental {
 template 
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D82992: clang CoverageMapping tests bot cleanup

2020-07-01 Thread Xun Li via Phabricator via cfe-commits
lxfind created this revision.
lxfind added a reviewer: thakis.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

D82928  generated unexpected tmp files in the 
CoverageMapping test directory. This patch cleans it up and remove the file in 
the test bots.
It will be revered after a week.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D82992

Files:
  clang/test/CoverageMapping/coroutine.cpp


Index: clang/test/CoverageMapping/coroutine.cpp
===
--- clang/test/CoverageMapping/coroutine.cpp
+++ clang/test/CoverageMapping/coroutine.cpp
@@ -1,3 +1,5 @@
+// fixme: the following line is added to cleanup bots, will be removed in 
weeks.
+// RUN: rm -f %S/coroutine.ll
 // RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fcoroutines-ts -std=c++14 
-emit-llvm -fprofile-instrument=clang -fcoverage-mapping -dump-coverage-mapping 
%s -o - | FileCheck %s
 
 namespace std::experimental {


Index: clang/test/CoverageMapping/coroutine.cpp
===
--- clang/test/CoverageMapping/coroutine.cpp
+++ clang/test/CoverageMapping/coroutine.cpp
@@ -1,3 +1,5 @@
+// fixme: the following line is added to cleanup bots, will be removed in weeks.
+// RUN: rm -f %S/coroutine.ll
 // RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fcoroutines-ts -std=c++14 -emit-llvm -fprofile-instrument=clang -fcoverage-mapping -dump-coverage-mapping %s -o - | FileCheck %s
 
 namespace std::experimental {
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D82986: [Coroutines] Fix test breakage in D82928

2020-07-01 Thread Xun Li via Phabricator via cfe-commits
lxfind added a comment.

In D82986#2126479 , @thakis wrote:

> That's not enough, you also need to add an rm to remove the stale .LL file 
> still on disk, see my comment on your original change.


It's in https://reviews.llvm.org/D82992 if you could help accept it. Thanks!


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D82986



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


[PATCH] D82992: clang CoverageMapping tests bot cleanup

2020-07-01 Thread Xun Li via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rG9fc877213e07: clang CoverageMapping tests bot cleanup 
(authored by lxfind).

Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D82992

Files:
  clang/test/CoverageMapping/coroutine.cpp


Index: clang/test/CoverageMapping/coroutine.cpp
===
--- clang/test/CoverageMapping/coroutine.cpp
+++ clang/test/CoverageMapping/coroutine.cpp
@@ -1,3 +1,5 @@
+// fixme: the following line is added to cleanup bots, will be removed in 
weeks.
+// RUN: rm -f %S/coroutine.ll
 // RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fcoroutines-ts -std=c++14 
-emit-llvm -fprofile-instrument=clang -fcoverage-mapping -dump-coverage-mapping 
%s -o - | FileCheck %s
 
 namespace std::experimental {


Index: clang/test/CoverageMapping/coroutine.cpp
===
--- clang/test/CoverageMapping/coroutine.cpp
+++ clang/test/CoverageMapping/coroutine.cpp
@@ -1,3 +1,5 @@
+// fixme: the following line is added to cleanup bots, will be removed in weeks.
+// RUN: rm -f %S/coroutine.ll
 // RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fcoroutines-ts -std=c++14 -emit-llvm -fprofile-instrument=clang -fcoverage-mapping -dump-coverage-mapping %s -o - | FileCheck %s
 
 namespace std::experimental {
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D82992: clang CoverageMapping tests bot cleanup

2020-07-01 Thread Xun Li via Phabricator via cfe-commits
lxfind added a comment.

In D82992#2126898 , @MaskRay wrote:

> Hi, your git commit contains extra Phabricator tags. You can drop 
> `Reviewers:` `Subscribers:` `Tags:` and the text `Summary:` from the git 
> commit with the following script:
>
>   arcfilter () {
>   arc amend
>   git log -1 --pretty=%B | awk '/Reviewers:|Subscribers:/{p=1} 
> /Reviewed By:|Differential Revision:/{p=0} !p && !/^Summary:$/ 
> {sub(/^Summary: /,"");print}' | git commit --amend --date=now -F -
>   }
>   
>
> `Reviewed By: ` is considered important by some people. Please keep the tag. 
> (`--date=now` is my personal preference (author dates are usually not useful. 
> Using committer dates can make log almost monotonic in time))
>
> `llvm/utils/git/pre-push.py` can validate the message does not include 
> unneeded tags.


Ah good to know. Thanks!


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D82992



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


[PATCH] D81885: [Coroutines] Return false on error of buildSuspends

2020-06-18 Thread Xun Li via Phabricator via cfe-commits
lxfind abandoned this revision.
lxfind added a comment.

Makes sense. I will abandon this change.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D81885



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


[PATCH] D82029: [Coroutines] Ensure co_await promise.final_suspend() does not throw

2020-06-18 Thread Xun Li via Phabricator via cfe-commits
lxfind updated this revision to Diff 271801.
lxfind added a comment.
Herald added a subscriber: arphaman.

Address feedback and update failed tests


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D82029

Files:
  clang/include/clang/Basic/DiagnosticSemaKinds.td
  clang/include/clang/Sema/Sema.h
  clang/lib/Sema/SemaCoroutine.cpp
  clang/lib/Sema/SemaExceptionSpec.cpp
  clang/test/AST/Inputs/std-coroutine.h
  clang/test/AST/coroutine-source-location-crash.cpp
  clang/test/Analysis/more-dtors-cfg-output.cpp
  clang/test/CodeGenCXX/ubsan-coroutines.cpp
  clang/test/CodeGenCoroutines/Inputs/coroutine.h
  clang/test/CodeGenCoroutines/coro-alloc.cpp
  clang/test/CodeGenCoroutines/coro-always-inline.cpp
  clang/test/CodeGenCoroutines/coro-await-domination.cpp
  clang/test/CodeGenCoroutines/coro-await-resume-eh.cpp
  clang/test/CodeGenCoroutines/coro-await.cpp
  clang/test/CodeGenCoroutines/coro-dest-slot.cpp
  clang/test/CodeGenCoroutines/coro-gro-nrvo.cpp
  clang/test/CodeGenCoroutines/coro-newpm-pipeline.cpp
  clang/test/CodeGenCoroutines/coro-params.cpp
  clang/test/CodeGenCoroutines/coro-promise-dtor.cpp
  clang/test/CodeGenCoroutines/coro-ret-void.cpp
  clang/test/CodeGenCoroutines/coro-return-voidtype-initlist.cpp
  clang/test/CodeGenCoroutines/coro-return.cpp
  clang/test/CodeGenCoroutines/coro-unhandled-exception.cpp
  clang/test/Index/coroutines.cpp
  clang/test/SemaCXX/Inputs/std-coroutine.h
  clang/test/SemaCXX/co_await-range-for.cpp
  clang/test/SemaCXX/coreturn-eh.cpp
  clang/test/SemaCXX/coreturn.cpp
  clang/test/SemaCXX/coroutine-final-suspend-noexcept.cpp
  clang/test/SemaCXX/coroutine-rvo.cpp
  clang/test/SemaCXX/coroutine-unhandled_exception-warning.cpp
  clang/test/SemaCXX/coroutine-uninitialized-warning-crash.cpp
  clang/test/SemaCXX/coroutines.cpp

Index: clang/test/SemaCXX/coroutines.cpp
===
--- clang/test/SemaCXX/coroutines.cpp
+++ clang/test/SemaCXX/coroutines.cpp
@@ -52,21 +52,24 @@
 };
 
 struct awaitable {
-  bool await_ready();
-  template  void await_suspend(F);
-  void await_resume();
+  bool await_ready() noexcept;
+  template 
+  void await_suspend(F) noexcept;
+  void await_resume() noexcept;
 } a;
 
 struct suspend_always {
-  bool await_ready() { return false; }
-  template  void await_suspend(F);
-  void await_resume() {}
+  bool await_ready() noexcept { return false; }
+  template 
+  void await_suspend(F) noexcept;
+  void await_resume() noexcept {}
 };
 
 struct suspend_never {
-  bool await_ready() { return true; }
-  template  void await_suspend(F);
-  void await_resume() {}
+  bool await_ready() noexcept { return true; }
+  template 
+  void await_suspend(F) noexcept;
+  void await_resume() noexcept {}
 };
 
 struct auto_await_suspend {
@@ -127,7 +130,7 @@
 struct promise {
   void get_return_object();
   suspend_always initial_suspend();
-  suspend_always final_suspend();
+  suspend_always final_suspend() noexcept;
   awaitable yield_value(int); // expected-note 2{{candidate}}
   awaitable yield_value(yielded_thing); // expected-note 2{{candidate}}
   not_awaitable yield_value(void()); // expected-note 2{{candidate}}
@@ -138,7 +141,7 @@
 struct promise_void {
   void get_return_object();
   suspend_always initial_suspend();
-  suspend_always final_suspend();
+  suspend_always final_suspend() noexcept;
   void return_void();
   void unhandled_exception();
 };
@@ -152,13 +155,13 @@
 namespace experimental {
 template 
 struct coroutine_handle {
-  static coroutine_handle from_address(void *);
+  static coroutine_handle from_address(void *) noexcept;
 };
 template <>
 struct coroutine_handle {
   template 
-  coroutine_handle(coroutine_handle);
-  static coroutine_handle from_address(void *);
+  coroutine_handle(coroutine_handle) noexcept;
+  static coroutine_handle from_address(void *) noexcept;
 };
 }} // namespace std::experimental
 
@@ -402,7 +405,7 @@
 
 namespace adl_ns {
 struct coawait_arg_type {};
-awaitable operator co_await(coawait_arg_type);
+awaitable operator co_await(coawait_arg_type) noexcept;
 }
 
 namespace dependent_operator_co_await_lookup {
@@ -434,7 +437,7 @@
 typedef transform_awaitable await_arg;
 coro get_return_object();
 transformed initial_suspend();
-::adl_ns::coawait_arg_type final_suspend();
+::adl_ns::coawait_arg_type final_suspend() noexcept;
 transformed await_transform(transform_awaitable);
 void unhandled_exception();
 void return_void();
@@ -444,7 +447,7 @@
 typedef AwaitArg await_arg;
 coro get_return_object();
 awaitable initial_suspend();
-awaitable final_suspend();
+awaitable final_suspend() noexcept;
 void unhandled_exception();
 void return_void();
   };
@@ -529,7 +532,7 @@
 void return_value(int());
 
 suspend_never initial_suspend();
-suspend_never final_suspend();
+suspend_never final_suspend() noexcept;

[PATCH] D82029: [Coroutines] Ensure co_await promise.final_suspend() does not throw

2020-06-18 Thread Xun Li via Phabricator via cfe-commits
lxfind marked an inline comment as done.
lxfind added inline comments.



Comment at: clang/test/SemaCXX/coroutine-final-suspend-noexcept.cpp:14
+struct coroutine_handle {
+  static coroutine_handle from_address(void *); // expected-note {{must be 
declared with 'noexcept'}}
+};

lewissbaker wrote:
> I'm not sure that we should be _requiring_ the compiler to emit an error for 
> this line.
> 
> The language specification does not require implementations to declare the 
> from_address() method as noexcept, even though Clang now requires standard 
> library implementations to declare this method as noexcept - this is an 
> additional implementation requirement that Clang is placing on standard 
> library implementations for them to be compatible with Clang's coroutines 
> implementation.
> 
> I guess this is probably ok to raise as an error, though, as most users will 
> just be using the compiler-provided implementation and both libc++/libstdc++ 
> are (currently) compatible.
`from_address` is in fact called as part of `co_await 
__promise.final_suspend()`.
Specifically, when this `co_await` is translated into a call to 
`finalSuspendObjAwaiter.await_suspend(handle)`, the handle parameter is 
obtained by calling `from_address`.
Since the specification requires that `co_await __promise.final_suspend()` 
should not be potentially throwing, it must requires `from_address` to be 
declared as `noexcept`.



Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D82029



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


[PATCH] D82029: [Coroutines] Ensure co_await promise.final_suspend() does not throw

2020-06-19 Thread Xun Li via Phabricator via cfe-commits
lxfind updated this revision to Diff 272109.
lxfind added a comment.

Addressed comments: Updated error message, and sorted notes. The tests are kept 
unchanged.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D82029

Files:
  clang/include/clang/Basic/DiagnosticSemaKinds.td
  clang/include/clang/Sema/Sema.h
  clang/lib/Sema/SemaCoroutine.cpp
  clang/lib/Sema/SemaExceptionSpec.cpp
  clang/test/AST/Inputs/std-coroutine.h
  clang/test/AST/coroutine-source-location-crash.cpp
  clang/test/Analysis/more-dtors-cfg-output.cpp
  clang/test/CodeGenCXX/ubsan-coroutines.cpp
  clang/test/CodeGenCoroutines/Inputs/coroutine.h
  clang/test/CodeGenCoroutines/coro-alloc.cpp
  clang/test/CodeGenCoroutines/coro-always-inline.cpp
  clang/test/CodeGenCoroutines/coro-await-domination.cpp
  clang/test/CodeGenCoroutines/coro-await-resume-eh.cpp
  clang/test/CodeGenCoroutines/coro-await.cpp
  clang/test/CodeGenCoroutines/coro-dest-slot.cpp
  clang/test/CodeGenCoroutines/coro-gro-nrvo.cpp
  clang/test/CodeGenCoroutines/coro-newpm-pipeline.cpp
  clang/test/CodeGenCoroutines/coro-params.cpp
  clang/test/CodeGenCoroutines/coro-promise-dtor.cpp
  clang/test/CodeGenCoroutines/coro-ret-void.cpp
  clang/test/CodeGenCoroutines/coro-return-voidtype-initlist.cpp
  clang/test/CodeGenCoroutines/coro-return.cpp
  clang/test/CodeGenCoroutines/coro-unhandled-exception.cpp
  clang/test/Index/coroutines.cpp
  clang/test/SemaCXX/Inputs/std-coroutine.h
  clang/test/SemaCXX/co_await-range-for.cpp
  clang/test/SemaCXX/coreturn-eh.cpp
  clang/test/SemaCXX/coreturn.cpp
  clang/test/SemaCXX/coroutine-final-suspend-noexcept.cpp
  clang/test/SemaCXX/coroutine-rvo.cpp
  clang/test/SemaCXX/coroutine-unhandled_exception-warning.cpp
  clang/test/SemaCXX/coroutine-uninitialized-warning-crash.cpp
  clang/test/SemaCXX/coroutines.cpp

Index: clang/test/SemaCXX/coroutines.cpp
===
--- clang/test/SemaCXX/coroutines.cpp
+++ clang/test/SemaCXX/coroutines.cpp
@@ -52,21 +52,24 @@
 };
 
 struct awaitable {
-  bool await_ready();
-  template  void await_suspend(F);
-  void await_resume();
+  bool await_ready() noexcept;
+  template 
+  void await_suspend(F) noexcept;
+  void await_resume() noexcept;
 } a;
 
 struct suspend_always {
-  bool await_ready() { return false; }
-  template  void await_suspend(F);
-  void await_resume() {}
+  bool await_ready() noexcept { return false; }
+  template 
+  void await_suspend(F) noexcept;
+  void await_resume() noexcept {}
 };
 
 struct suspend_never {
-  bool await_ready() { return true; }
-  template  void await_suspend(F);
-  void await_resume() {}
+  bool await_ready() noexcept { return true; }
+  template 
+  void await_suspend(F) noexcept;
+  void await_resume() noexcept {}
 };
 
 struct auto_await_suspend {
@@ -127,7 +130,7 @@
 struct promise {
   void get_return_object();
   suspend_always initial_suspend();
-  suspend_always final_suspend();
+  suspend_always final_suspend() noexcept;
   awaitable yield_value(int); // expected-note 2{{candidate}}
   awaitable yield_value(yielded_thing); // expected-note 2{{candidate}}
   not_awaitable yield_value(void()); // expected-note 2{{candidate}}
@@ -138,7 +141,7 @@
 struct promise_void {
   void get_return_object();
   suspend_always initial_suspend();
-  suspend_always final_suspend();
+  suspend_always final_suspend() noexcept;
   void return_void();
   void unhandled_exception();
 };
@@ -152,13 +155,13 @@
 namespace experimental {
 template 
 struct coroutine_handle {
-  static coroutine_handle from_address(void *);
+  static coroutine_handle from_address(void *) noexcept;
 };
 template <>
 struct coroutine_handle {
   template 
-  coroutine_handle(coroutine_handle);
-  static coroutine_handle from_address(void *);
+  coroutine_handle(coroutine_handle) noexcept;
+  static coroutine_handle from_address(void *) noexcept;
 };
 }} // namespace std::experimental
 
@@ -402,7 +405,7 @@
 
 namespace adl_ns {
 struct coawait_arg_type {};
-awaitable operator co_await(coawait_arg_type);
+awaitable operator co_await(coawait_arg_type) noexcept;
 }
 
 namespace dependent_operator_co_await_lookup {
@@ -434,7 +437,7 @@
 typedef transform_awaitable await_arg;
 coro get_return_object();
 transformed initial_suspend();
-::adl_ns::coawait_arg_type final_suspend();
+::adl_ns::coawait_arg_type final_suspend() noexcept;
 transformed await_transform(transform_awaitable);
 void unhandled_exception();
 void return_void();
@@ -444,7 +447,7 @@
 typedef AwaitArg await_arg;
 coro get_return_object();
 awaitable initial_suspend();
-awaitable final_suspend();
+awaitable final_suspend() noexcept;
 void unhandled_exception();
 void return_void();
   };
@@ -529,7 +532,7 @@
 void return_value(int());
 
 suspend_never initial_suspend();
-suspend_never final_suspend();
+suspend_never final_suspend() 

[PATCH] D82029: [Coroutines] Ensure co_await promise.final_suspend() does not throw

2020-06-22 Thread Xun Li via Phabricator via cfe-commits
lxfind added a comment.

All tests are passing now. Thanks for reviewing!


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D82029



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


[PATCH] D82314: [RFC][Coroutines] Optimize the lifespan of temporary co_await object

2020-06-22 Thread Xun Li via Phabricator via cfe-commits
lxfind created this revision.
lxfind added reviewers: lewissbaker, modocache, junparser.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

If we ever assign co_await to a temporary variable, such as foo(co_await expr),
we generate AST that looks like this: 
MaterializedTemporaryExpr(CoawaitExpr(...)).
MaterializedTemporaryExpr would emit an intrinsics that marks the lifetime 
start of the
temporary storage. However such temporary storage will not be used until 
co_await is ready
to write the result. Marking the lifetime start way too early causes extra 
storage to be
put in the coroutine frame instead of the stack.
As you can see from https://godbolt.org/z/XsLUiY, the frame generated for 
get_big_object2 is 12K, which contains a big_object object unnecessarily.
After this patch, the frame size for get_big_object2 is now only 8K. There are 
still room for improvements, in particular, GCC has a 4K frame for this 
function. But that's a separate problem and not addressed in this patch.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D82314

Files:
  clang/lib/CodeGen/CGCoroutine.cpp


Index: clang/lib/CodeGen/CGCoroutine.cpp
===
--- clang/lib/CodeGen/CGCoroutine.cpp
+++ clang/lib/CodeGen/CGCoroutine.cpp
@@ -245,10 +245,39 @@
   }
 
   LValueOrRValue Res;
-  if (forLValue)
+  if (forLValue) {
 Res.LV = CGF.EmitLValue(S.getResumeExpr());
-  else
+  } else {
+// If the result of co_await is stored into a memory address, we want to
+// make sure the lifetime of that memory address does not start too early,
+// causing more space to be allocated in the frame rather than on stack.
+// The lifetime of the return value of co_await should start here right
+// before we attempt to assign it.
+auto adjustLifetimeStart = [&]() {
+  // aggSlot points to the instruction that allocated the object. Latter
+  // instructions use it in this pattern:
+  //   %tmpX = alloca %.., align 4
+  //   %0 = bitcast %...* %tmpX to i8*
+  //   call void @llvm.lifetime.start.p0i8(i64 ..., i8* nonnull %0) #2
+  // Hence we trace back through uses to eventually locate the lifetime
+  // start intrinsics marker, and move it down to the current insertion
+  // point.
+  auto *AllocaInst =
+  dyn_cast_or_null(aggSlot.getPointer());
+  if (!AllocaInst || AllocaInst->getNumUses() != 1)
+return;
+  auto *CastInst = dyn_cast(*AllocaInst->users().begin());
+  if (!CastInst || CastInst->getNumUses() != 1)
+return;
+  if (auto *LifetimeInst =
+  dyn_cast(*CastInst->users().begin())) {
+LifetimeInst->removeFromParent();
+CGF.Builder.Insert(LifetimeInst);
+  }
+};
+adjustLifetimeStart();
 Res.RV = CGF.EmitAnyExpr(S.getResumeExpr(), aggSlot, ignoreResult);
+  }
 
   if (TryStmt) {
 Builder.CreateFlagStore(false, Coro.ResumeEHVar);


Index: clang/lib/CodeGen/CGCoroutine.cpp
===
--- clang/lib/CodeGen/CGCoroutine.cpp
+++ clang/lib/CodeGen/CGCoroutine.cpp
@@ -245,10 +245,39 @@
   }
 
   LValueOrRValue Res;
-  if (forLValue)
+  if (forLValue) {
 Res.LV = CGF.EmitLValue(S.getResumeExpr());
-  else
+  } else {
+// If the result of co_await is stored into a memory address, we want to
+// make sure the lifetime of that memory address does not start too early,
+// causing more space to be allocated in the frame rather than on stack.
+// The lifetime of the return value of co_await should start here right
+// before we attempt to assign it.
+auto adjustLifetimeStart = [&]() {
+  // aggSlot points to the instruction that allocated the object. Latter
+  // instructions use it in this pattern:
+  //   %tmpX = alloca %.., align 4
+  //   %0 = bitcast %...* %tmpX to i8*
+  //   call void @llvm.lifetime.start.p0i8(i64 ..., i8* nonnull %0) #2
+  // Hence we trace back through uses to eventually locate the lifetime
+  // start intrinsics marker, and move it down to the current insertion
+  // point.
+  auto *AllocaInst =
+  dyn_cast_or_null(aggSlot.getPointer());
+  if (!AllocaInst || AllocaInst->getNumUses() != 1)
+return;
+  auto *CastInst = dyn_cast(*AllocaInst->users().begin());
+  if (!CastInst || CastInst->getNumUses() != 1)
+return;
+  if (auto *LifetimeInst =
+  dyn_cast(*CastInst->users().begin())) {
+LifetimeInst->removeFromParent();
+CGF.Builder.Insert(LifetimeInst);
+  }
+};
+adjustLifetimeStart();
 Res.RV = CGF.EmitAnyExpr(S.getResumeExpr(), aggSlot, ignoreResult);
+  }
 
   if (TryStmt) {
 Builder.CreateFlagStore(false, Coro.ResumeEHVar);
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

[PATCH] D82029: [Coroutines] Ensure co_await promise.final_suspend() does not throw

2020-06-22 Thread Xun Li via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rG516803dc8685: [Coroutines] Ensure co_await 
promise.final_suspend() does not throw (authored by lxfind).

Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D82029

Files:
  clang/include/clang/Basic/DiagnosticSemaKinds.td
  clang/include/clang/Sema/Sema.h
  clang/lib/Sema/SemaCoroutine.cpp
  clang/lib/Sema/SemaExceptionSpec.cpp
  clang/test/AST/Inputs/std-coroutine.h
  clang/test/AST/coroutine-source-location-crash.cpp
  clang/test/Analysis/more-dtors-cfg-output.cpp
  clang/test/CodeGenCXX/ubsan-coroutines.cpp
  clang/test/CodeGenCoroutines/Inputs/coroutine.h
  clang/test/CodeGenCoroutines/coro-alloc.cpp
  clang/test/CodeGenCoroutines/coro-always-inline.cpp
  clang/test/CodeGenCoroutines/coro-await-domination.cpp
  clang/test/CodeGenCoroutines/coro-await-resume-eh.cpp
  clang/test/CodeGenCoroutines/coro-await.cpp
  clang/test/CodeGenCoroutines/coro-dest-slot.cpp
  clang/test/CodeGenCoroutines/coro-gro-nrvo.cpp
  clang/test/CodeGenCoroutines/coro-newpm-pipeline.cpp
  clang/test/CodeGenCoroutines/coro-params.cpp
  clang/test/CodeGenCoroutines/coro-promise-dtor.cpp
  clang/test/CodeGenCoroutines/coro-ret-void.cpp
  clang/test/CodeGenCoroutines/coro-return-voidtype-initlist.cpp
  clang/test/CodeGenCoroutines/coro-return.cpp
  clang/test/CodeGenCoroutines/coro-unhandled-exception.cpp
  clang/test/Index/coroutines.cpp
  clang/test/SemaCXX/Inputs/std-coroutine.h
  clang/test/SemaCXX/co_await-range-for.cpp
  clang/test/SemaCXX/coreturn-eh.cpp
  clang/test/SemaCXX/coreturn.cpp
  clang/test/SemaCXX/coroutine-final-suspend-noexcept.cpp
  clang/test/SemaCXX/coroutine-rvo.cpp
  clang/test/SemaCXX/coroutine-unhandled_exception-warning.cpp
  clang/test/SemaCXX/coroutine-uninitialized-warning-crash.cpp
  clang/test/SemaCXX/coroutines.cpp

Index: clang/test/SemaCXX/coroutines.cpp
===
--- clang/test/SemaCXX/coroutines.cpp
+++ clang/test/SemaCXX/coroutines.cpp
@@ -52,21 +52,24 @@
 };
 
 struct awaitable {
-  bool await_ready();
-  template  void await_suspend(F);
-  void await_resume();
+  bool await_ready() noexcept;
+  template 
+  void await_suspend(F) noexcept;
+  void await_resume() noexcept;
 } a;
 
 struct suspend_always {
-  bool await_ready() { return false; }
-  template  void await_suspend(F);
-  void await_resume() {}
+  bool await_ready() noexcept { return false; }
+  template 
+  void await_suspend(F) noexcept;
+  void await_resume() noexcept {}
 };
 
 struct suspend_never {
-  bool await_ready() { return true; }
-  template  void await_suspend(F);
-  void await_resume() {}
+  bool await_ready() noexcept { return true; }
+  template 
+  void await_suspend(F) noexcept;
+  void await_resume() noexcept {}
 };
 
 struct auto_await_suspend {
@@ -127,7 +130,7 @@
 struct promise {
   void get_return_object();
   suspend_always initial_suspend();
-  suspend_always final_suspend();
+  suspend_always final_suspend() noexcept;
   awaitable yield_value(int); // expected-note 2{{candidate}}
   awaitable yield_value(yielded_thing); // expected-note 2{{candidate}}
   not_awaitable yield_value(void()); // expected-note 2{{candidate}}
@@ -138,7 +141,7 @@
 struct promise_void {
   void get_return_object();
   suspend_always initial_suspend();
-  suspend_always final_suspend();
+  suspend_always final_suspend() noexcept;
   void return_void();
   void unhandled_exception();
 };
@@ -152,13 +155,13 @@
 namespace experimental {
 template 
 struct coroutine_handle {
-  static coroutine_handle from_address(void *);
+  static coroutine_handle from_address(void *) noexcept;
 };
 template <>
 struct coroutine_handle {
   template 
-  coroutine_handle(coroutine_handle);
-  static coroutine_handle from_address(void *);
+  coroutine_handle(coroutine_handle) noexcept;
+  static coroutine_handle from_address(void *) noexcept;
 };
 }} // namespace std::experimental
 
@@ -402,7 +405,7 @@
 
 namespace adl_ns {
 struct coawait_arg_type {};
-awaitable operator co_await(coawait_arg_type);
+awaitable operator co_await(coawait_arg_type) noexcept;
 }
 
 namespace dependent_operator_co_await_lookup {
@@ -434,7 +437,7 @@
 typedef transform_awaitable await_arg;
 coro get_return_object();
 transformed initial_suspend();
-::adl_ns::coawait_arg_type final_suspend();
+::adl_ns::coawait_arg_type final_suspend() noexcept;
 transformed await_transform(transform_awaitable);
 void unhandled_exception();
 void return_void();
@@ -444,7 +447,7 @@
 typedef AwaitArg await_arg;
 coro get_return_object();
 awaitable initial_suspend();
-awaitable final_suspend();
+awaitable final_suspend() noexcept;
 void unhandled_exception();
 void return_void();
   };
@@ -529,7 +532,7 @@
 void return_value(int());
 
 suspend_never initial_suspend();
-suspend_never final_suspend();

[PATCH] D82029: [Coroutines] Ensure co_await promise.final_suspend() does not throw

2020-06-23 Thread Xun Li via Phabricator via cfe-commits
lxfind added a comment.

Test failures are being fixed in https://reviews.llvm.org/D82338/new/


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D82029



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


[PATCH] D82314: [RFC][Coroutines] Optimize the lifespan of temporary co_await object

2020-06-23 Thread Xun Li via Phabricator via cfe-commits
lxfind added a comment.

In D82314#2107910 , @junparser wrote:

> Rather than doing it here, can we build await_resume call expression with 
> MaterializedTemporaryExpr when expand the coawait expression. That's how gcc 
> does.


There doesn't appear to be a way to do that in Clang. It goes from the AST to 
IR directly, and there needs to be a MaterializedTemporaryExpr to wrap the 
result of co_await. Could you elaborate on how this might be done in Clang?


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D82314



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


[PATCH] D82332: [Coroutines] Handle dependent promise types for final_suspend non-throw check

2020-06-23 Thread Xun Li via Phabricator via cfe-commits
lxfind created this revision.
Herald added subscribers: cfe-commits, modocache.
Herald added a project: clang.
lxfind updated this revision to Diff 272553.
lxfind added a comment.
lxfind added reviewers: Benabik, lewissbaker, junparser.
lxfind updated this revision to Diff 272786.
lxfind edited the summary of this revision.
lxfind requested review of this revision.

Simplify tests


lxfind added a comment.

Rebase


Check that the co_await promise.final_suspend() does not potentially throw 
again after we have resolved dependent types.
This takes care of the cases where promises types are templated.
Added test cases for this scenario and confirmed that the checks happen now.
Also run libcxx tests locally to make sure all tests pass.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D82332

Files:
  clang/include/clang/Sema/Sema.h
  clang/lib/Sema/SemaCoroutine.cpp
  clang/lib/Sema/TreeTransform.h
  clang/test/SemaCXX/coroutine-final-suspend-noexcept.cpp

Index: clang/test/SemaCXX/coroutine-final-suspend-noexcept.cpp
===
--- clang/test/SemaCXX/coroutine-final-suspend-noexcept.cpp
+++ clang/test/SemaCXX/coroutine-final-suspend-noexcept.cpp
@@ -11,27 +11,27 @@
 
 template 
 struct coroutine_handle {
-  static coroutine_handle from_address(void *); // expected-note {{must be declared with 'noexcept'}}
+  static coroutine_handle from_address(void *); // expected-note 2 {{must be declared with 'noexcept'}}
 };
 template <>
 struct coroutine_handle {
   template 
-  coroutine_handle(coroutine_handle); // expected-note {{must be declared with 'noexcept'}}
+  coroutine_handle(coroutine_handle); // expected-note 2 {{must be declared with 'noexcept'}}
 };
 
 struct suspend_never {
-  bool await_ready() { return true; }   // expected-note {{must be declared with 'noexcept'}}
-  void await_suspend(coroutine_handle<>) {} // expected-note {{must be declared with 'noexcept'}}
-  void await_resume() {}// expected-note {{must be declared with 'noexcept'}}
-  ~suspend_never() noexcept(false); // expected-note {{must be declared with 'noexcept'}}
+  bool await_ready() { return true; }   // expected-note 2 {{must be declared with 'noexcept'}}
+  void await_suspend(coroutine_handle<>) {} // expected-note 2 {{must be declared with 'noexcept'}}
+  void await_resume() {}// expected-note 2 {{must be declared with 'noexcept'}}
+  ~suspend_never() noexcept(false); // expected-note 2 {{must be declared with 'noexcept'}}
 };
 
 struct suspend_always {
   bool await_ready() { return false; }
   void await_suspend(coroutine_handle<>) {}
   void await_resume() {}
-  suspend_never operator co_await(); // expected-note {{must be declared with 'noexcept'}}
-  ~suspend_always() noexcept(false); // expected-note {{must be declared with 'noexcept'}}
+  suspend_never operator co_await(); // expected-note 2 {{must be declared with 'noexcept'}}
+  ~suspend_always() noexcept(false); // expected-note 2 {{must be declared with 'noexcept'}}
 };
 
 } // namespace experimental
@@ -50,7 +50,7 @@
   struct promise_type {
 coro_t get_return_object();
 suspend_never initial_suspend();
-suspend_always final_suspend(); // expected-note {{must be declared with 'noexcept'}}
+suspend_always final_suspend(); // expected-note 2 {{must be declared with 'noexcept'}}
 void return_void();
 static void unhandled_exception();
   };
@@ -60,3 +60,13 @@
   A a{};
   co_await a;
 }
+
+template 
+coro_t f_dep(T n) { // expected-error {{the expression 'co_await __promise.final_suspend()' is required to be non-throwing}}
+  A a{};
+  co_await a;
+}
+
+void foo() {
+  f_dep(5); // expected-note {{in instantiation of function template specialization 'f_dep' requested here}}
+}
Index: clang/lib/Sema/TreeTransform.h
===
--- clang/lib/Sema/TreeTransform.h
+++ clang/lib/Sema/TreeTransform.h
@@ -7630,7 +7630,8 @@
 return StmtError();
   StmtResult FinalSuspend =
   getDerived().TransformStmt(S->getFinalSuspendStmt());
-  if (FinalSuspend.isInvalid())
+  if (FinalSuspend.isInvalid() ||
+  !SemaRef.checkFinalSuspendNoThrow(FinalSuspend.get()))
 return StmtError();
   ScopeInfo->setCoroutineSuspends(InitSuspend.get(), FinalSuspend.get());
   assert(isa(InitSuspend.get()) && isa(FinalSuspend.get()));
Index: clang/lib/Sema/SemaCoroutine.cpp
===
--- clang/lib/Sema/SemaCoroutine.cpp
+++ clang/lib/Sema/SemaCoroutine.cpp
@@ -631,7 +631,6 @@
   } else if (SC == Expr::CallExprClass || SC == Expr::CXXMemberCallExprClass ||
  SC == Expr::CXXOperatorCallExprClass) {
 if (!cast(E)->isTypeDependent()) {
-  // FIXME: Handle dependent types.
   checkDeclNoexcept(cast(E)->getCalleeDecl());
   auto ReturnType = cast(E)->getCallReturnType(S.getASTContext());
   // Ch

[PATCH] D82314: [RFC][Coroutines] Optimize the lifespan of temporary co_await object

2020-06-23 Thread Xun Li via Phabricator via cfe-commits
lxfind added a comment.

@rsmith Thanks. That's a good point. Do you know if there already exists 
optimization passes in LLVM that attempts to shrink the range of lifetime 
intrinsics? If so, I am curious why that does not help in this case. Or is it 
generally unsafe to move the lifetime intrinsics, and we could only do it here 
with specific context knowledge about coroutines.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D82314



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


[PATCH] D82415: [Coroutines] Special handle __builtin_coro_resume for final_suspend nothrow check

2020-06-23 Thread Xun Li via Phabricator via cfe-commits
lxfind created this revision.
Herald added subscribers: cfe-commits, modocache.
Herald added a project: clang.
lxfind added reviewers: modocache, lewissbaker, junparser.
lxfind requested review of this revision.

In https://reviews.llvm.org/D82029 we added the conformance check that the 
expression co_await promise.final_suspend() should not potentially throw.
As part of this expression, in cases when the await_suspend() method of the 
final suspend awaiter returns a handle, __builtin_coro_resume could be called 
on the handle to immediately resume that coroutine.
__builtin_coro_resume is not declared with noexcept and it shouldn't. We need 
to special check this case here.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D82415

Files:
  clang/lib/Sema/SemaCoroutine.cpp


Index: clang/lib/Sema/SemaCoroutine.cpp
===
--- clang/lib/Sema/SemaCoroutine.cpp
+++ clang/lib/Sema/SemaCoroutine.cpp
@@ -614,6 +614,14 @@
 // In the case of dtor, the call to dtor is implicit and hence we should
 // pass nullptr to canCalleeThrow.
 if (Sema::canCalleeThrow(S, IsDtor ? nullptr : cast(E), D)) {
+  if (auto *FD = dyn_cast(D)) {
+// co_await promise.final_suspend() could end up calling
+// __builtin_coro_resume for symmetric transfer if await_suspend()
+// returns a handle. In that case, even __builtin_coro_resume is not
+// declared as noexcept, we claim that logically it does not throw.
+if (FD->getBuiltinID() == Builtin::BI__builtin_coro_resume)
+  return;
+  }
   if (ThrowingDecls.empty()) {
 // First time seeing an error, emit the error message.
 S.Diag(cast(S.CurContext)->getLocation(),


Index: clang/lib/Sema/SemaCoroutine.cpp
===
--- clang/lib/Sema/SemaCoroutine.cpp
+++ clang/lib/Sema/SemaCoroutine.cpp
@@ -614,6 +614,14 @@
 // In the case of dtor, the call to dtor is implicit and hence we should
 // pass nullptr to canCalleeThrow.
 if (Sema::canCalleeThrow(S, IsDtor ? nullptr : cast(E), D)) {
+  if (auto *FD = dyn_cast(D)) {
+// co_await promise.final_suspend() could end up calling
+// __builtin_coro_resume for symmetric transfer if await_suspend()
+// returns a handle. In that case, even __builtin_coro_resume is not
+// declared as noexcept, we claim that logically it does not throw.
+if (FD->getBuiltinID() == Builtin::BI__builtin_coro_resume)
+  return;
+  }
   if (ThrowingDecls.empty()) {
 // First time seeing an error, emit the error message.
 S.Diag(cast(S.CurContext)->getLocation(),
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D82314: [RFC][Coroutines] Optimize the lifespan of temporary co_await object

2020-06-23 Thread Xun Li via Phabricator via cfe-commits
lxfind updated this revision to Diff 272904.
lxfind added a comment.
Herald added subscribers: llvm-commits, hiraditya.
Herald added a project: LLVM.

Tackle this problem inside CoroSplit as an optimization. Instead of only 
handling one particular case, we now look at every local variable in the 
coroutine, and sink their lifetime start markers when possible. This will bring 
in more benefits than doing so during IR emit. Confirmed that it works.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D82314

Files:
  llvm/lib/Transforms/Coroutines/CoroSplit.cpp

Index: llvm/lib/Transforms/Coroutines/CoroSplit.cpp
===
--- llvm/lib/Transforms/Coroutines/CoroSplit.cpp
+++ llvm/lib/Transforms/Coroutines/CoroSplit.cpp
@@ -75,7 +75,7 @@
 
 namespace {
 
-/// A little helper class for building 
+/// A little helper class for building
 class CoroCloner {
 public:
   enum class Kind {
@@ -563,7 +563,7 @@
   // In the original function, the AllocaSpillBlock is a block immediately
   // following the allocation of the frame object which defines GEPs for
   // all the allocas that have been moved into the frame, and it ends by
-  // branching to the original beginning of the coroutine.  Make this 
+  // branching to the original beginning of the coroutine.  Make this
   // the entry block of the cloned function.
   auto *Entry = cast(VMap[Shape.AllocaSpillBlock]);
   auto *OldEntry = &NewF->getEntryBlock();
@@ -1239,6 +1239,106 @@
   S.resize(N);
 }
 
+/// For every local variable that has lifetime intrinsics markers, we sink
+/// their lifetime.start marker to the places where the variable is being
+/// used for the first time. Doing so minimizes the lifetime of each variable,
+/// hence minimizing the amount of data we end up putting on the frame.
+static void sinkLifetimeStartMarkers(Function &F) {
+  DominatorTree Dom(F);
+  for (Instruction &I : instructions(F)) {
+// We look for this particular pattern:
+//   %tmpX = alloca %.., align ...
+//   %0 = bitcast %...* %tmpX to i8*
+//   call void @llvm.lifetime.start.p0i8(i64 ..., i8* nonnull %0) #2
+if (!isa(&I))
+  continue;
+BitCastInst *CastInst = nullptr;
+// There can be multiple lifetime start markers for the same variable.
+SmallPtrSet LifetimeStartInsts;
+// SinkBarriers stores all instructions that use this local variable.
+// When sinking the lifetime start intrinsics, we can never sink past
+// these barriers.
+SmallPtrSet SinkBarriers;
+bool Valid = true;
+auto addSinkBarrier = [&](Instruction *I) {
+  // When adding a new barrier to SinkBarriers, we maintain the case
+  // that no instruction in SinkBarriers dominates another instruction.
+  bool FoundDom = false;
+  SmallPtrSet ToRemove;
+  for (auto *S : SinkBarriers) {
+if (Dom.dominates(S, I)) {
+  FoundDom = true;
+  break;
+} else if (Dom.dominates(I, S)) {
+  ToRemove.insert(S);
+}
+  }
+  if (!FoundDom) {
+SinkBarriers.insert(I);
+for (auto *R : ToRemove) {
+  SinkBarriers.erase(R);
+}
+  }
+};
+for (User *U : I.users()) {
+  if (!isa(U))
+continue;
+  if (CastInst) {
+// If we have multiple cast instructions for the alloca, don't
+// deal with it beause it's too complex.
+Valid = false;
+break;
+  }
+  CastInst = cast(U);
+  for (User *CU : CastInst->users()) {
+// If we see any user of CastInst that's not lifetime start/end
+// intrinsics, give up because it's too complex.
+if (auto *CUI = dyn_cast(CU)) {
+  if (CUI->getIntrinsicID() == Intrinsic::lifetime_start)
+LifetimeStartInsts.insert(CUI);
+  else if (CUI->getIntrinsicID() == Intrinsic::lifetime_end)
+addSinkBarrier(CUI);
+  else
+Valid = false;
+} else {
+  Valid = false;
+}
+  }
+}
+if (!Valid || LifetimeStartInsts.empty())
+  continue;
+
+for (User *U : I.users()) {
+  if (U == CastInst)
+continue;
+  // Every user of the variable is also a sink barrier.
+  addSinkBarrier(cast(U));
+}
+
+// For each sink barrier, we insert a lifetime start marker right
+// before it.
+const auto *LifetimeStartInst = *LifetimeStartInsts.begin();
+for (auto *S : SinkBarriers) {
+  if (auto *IS = dyn_cast(S)) {
+if (IS->getIntrinsicID() == Intrinsic::lifetime_end) {
+  // If we have a lifetime end marker in SinkBarriers, meaning it's
+  // not dominated by any other users, we can safely delete it.
+  IS->eraseFromParent();
+  continue;
+}
+  }
+  LifetimeStartInst->clone()->insertBefore(S);
+}
+// All the old markers are no longer necessary.
+f

[PATCH] D82415: [Coroutines] Special handle __builtin_coro_resume for final_suspend nothrow check

2020-06-23 Thread Xun Li via Phabricator via cfe-commits
lxfind updated this revision to Diff 272905.
lxfind added a comment.

Address lint


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D82415

Files:
  clang/lib/Sema/SemaCoroutine.cpp


Index: clang/lib/Sema/SemaCoroutine.cpp
===
--- clang/lib/Sema/SemaCoroutine.cpp
+++ clang/lib/Sema/SemaCoroutine.cpp
@@ -614,6 +614,14 @@
 // In the case of dtor, the call to dtor is implicit and hence we should
 // pass nullptr to canCalleeThrow.
 if (Sema::canCalleeThrow(S, IsDtor ? nullptr : cast(E), D)) {
+  if (const auto *FD = dyn_cast(D)) {
+// co_await promise.final_suspend() could end up calling
+// __builtin_coro_resume for symmetric transfer if await_suspend()
+// returns a handle. In that case, even __builtin_coro_resume is not
+// declared as noexcept, we claim that logically it does not throw.
+if (FD->getBuiltinID() == Builtin::BI__builtin_coro_resume)
+  return;
+  }
   if (ThrowingDecls.empty()) {
 // First time seeing an error, emit the error message.
 S.Diag(cast(S.CurContext)->getLocation(),


Index: clang/lib/Sema/SemaCoroutine.cpp
===
--- clang/lib/Sema/SemaCoroutine.cpp
+++ clang/lib/Sema/SemaCoroutine.cpp
@@ -614,6 +614,14 @@
 // In the case of dtor, the call to dtor is implicit and hence we should
 // pass nullptr to canCalleeThrow.
 if (Sema::canCalleeThrow(S, IsDtor ? nullptr : cast(E), D)) {
+  if (const auto *FD = dyn_cast(D)) {
+// co_await promise.final_suspend() could end up calling
+// __builtin_coro_resume for symmetric transfer if await_suspend()
+// returns a handle. In that case, even __builtin_coro_resume is not
+// declared as noexcept, we claim that logically it does not throw.
+if (FD->getBuiltinID() == Builtin::BI__builtin_coro_resume)
+  return;
+  }
   if (ThrowingDecls.empty()) {
 // First time seeing an error, emit the error message.
 S.Diag(cast(S.CurContext)->getLocation(),
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D82415: [Coroutines] Special handle __builtin_coro_resume for final_suspend nothrow check

2020-06-23 Thread Xun Li via Phabricator via cfe-commits
lxfind updated this revision to Diff 272910.
lxfind added a comment.

rebase


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D82415

Files:
  clang/lib/Sema/SemaCoroutine.cpp


Index: clang/lib/Sema/SemaCoroutine.cpp
===
--- clang/lib/Sema/SemaCoroutine.cpp
+++ clang/lib/Sema/SemaCoroutine.cpp
@@ -614,6 +614,14 @@
 // In the case of dtor, the call to dtor is implicit and hence we should
 // pass nullptr to canCalleeThrow.
 if (Sema::canCalleeThrow(S, IsDtor ? nullptr : cast(E), D)) {
+  if (const auto *FD = dyn_cast(D)) {
+// co_await promise.final_suspend() could end up calling
+// __builtin_coro_resume for symmetric transfer if await_suspend()
+// returns a handle. In that case, even __builtin_coro_resume is not
+// declared as noexcept, we claim that logically it does not throw.
+if (FD->getBuiltinID() == Builtin::BI__builtin_coro_resume)
+  return;
+  }
   if (ThrowingDecls.empty()) {
 // First time seeing an error, emit the error message.
 S.Diag(cast(S.CurContext)->getLocation(),


Index: clang/lib/Sema/SemaCoroutine.cpp
===
--- clang/lib/Sema/SemaCoroutine.cpp
+++ clang/lib/Sema/SemaCoroutine.cpp
@@ -614,6 +614,14 @@
 // In the case of dtor, the call to dtor is implicit and hence we should
 // pass nullptr to canCalleeThrow.
 if (Sema::canCalleeThrow(S, IsDtor ? nullptr : cast(E), D)) {
+  if (const auto *FD = dyn_cast(D)) {
+// co_await promise.final_suspend() could end up calling
+// __builtin_coro_resume for symmetric transfer if await_suspend()
+// returns a handle. In that case, even __builtin_coro_resume is not
+// declared as noexcept, we claim that logically it does not throw.
+if (FD->getBuiltinID() == Builtin::BI__builtin_coro_resume)
+  return;
+  }
   if (ThrowingDecls.empty()) {
 // First time seeing an error, emit the error message.
 S.Diag(cast(S.CurContext)->getLocation(),
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D82314: [RFC][Coroutines] Optimize the lifespan of temporary co_await object

2020-06-24 Thread Xun Li via Phabricator via cfe-commits
lxfind updated this revision to Diff 272916.
lxfind added a comment.

Address test failures


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D82314

Files:
  llvm/lib/Transforms/Coroutines/CoroSplit.cpp
  llvm/test/Transforms/Coroutines/coro-split-02.ll

Index: llvm/test/Transforms/Coroutines/coro-split-02.ll
===
--- llvm/test/Transforms/Coroutines/coro-split-02.ll
+++ llvm/test/Transforms/Coroutines/coro-split-02.ll
@@ -40,14 +40,9 @@
 }
 
 ; CHECK-LABEL: @a.resume(
-; CHECK: %testval = alloca i32
 ; CHECK: getelementptr inbounds %a.Frame
 ; CHECK-NEXT:getelementptr inbounds %"struct.lean_future::Awaiter"
-; CHECK-NOT: call token @llvm.coro.save(i8* null)
 ; CHECK-NEXT:%val = load i32, i32* %Result
-; CHECK-NEXT:%cast = bitcast i32* %testval to i8*
-; CHECK-NEXT:call void @llvm.lifetime.start.p0i8(i64 4, i8* %cast)
-; CHECK-NEXT:call void @llvm.lifetime.end.p0i8(i64 4, i8* %cast)
 ; CHECK-NEXT:call void @print(i32 %val)
 ; CHECK-NEXT:ret void
 
Index: llvm/lib/Transforms/Coroutines/CoroSplit.cpp
===
--- llvm/lib/Transforms/Coroutines/CoroSplit.cpp
+++ llvm/lib/Transforms/Coroutines/CoroSplit.cpp
@@ -75,7 +75,7 @@
 
 namespace {
 
-/// A little helper class for building 
+/// A little helper class for building
 class CoroCloner {
 public:
   enum class Kind {
@@ -563,7 +563,7 @@
   // In the original function, the AllocaSpillBlock is a block immediately
   // following the allocation of the frame object which defines GEPs for
   // all the allocas that have been moved into the frame, and it ends by
-  // branching to the original beginning of the coroutine.  Make this 
+  // branching to the original beginning of the coroutine.  Make this
   // the entry block of the cloned function.
   auto *Entry = cast(VMap[Shape.AllocaSpillBlock]);
   auto *OldEntry = &NewF->getEntryBlock();
@@ -1239,6 +1239,106 @@
   S.resize(N);
 }
 
+/// For every local variable that has lifetime intrinsics markers, we sink
+/// their lifetime.start marker to the places where the variable is being
+/// used for the first time. Doing so minimizes the lifetime of each variable,
+/// hence minimizing the amount of data we end up putting on the frame.
+static void sinkLifetimeStartMarkers(Function &F) {
+  DominatorTree Dom(F);
+  for (Instruction &I : instructions(F)) {
+// We look for this particular pattern:
+//   %tmpX = alloca %.., align ...
+//   %0 = bitcast %...* %tmpX to i8*
+//   call void @llvm.lifetime.start.p0i8(i64 ..., i8* nonnull %0) #2
+if (!isa(&I))
+  continue;
+BitCastInst *CastInst = nullptr;
+// There can be multiple lifetime start markers for the same variable.
+SmallPtrSet LifetimeStartInsts;
+// SinkBarriers stores all instructions that use this local variable.
+// When sinking the lifetime start intrinsics, we can never sink past
+// these barriers.
+SmallPtrSet SinkBarriers;
+bool Valid = true;
+auto addSinkBarrier = [&](Instruction *I) {
+  // When adding a new barrier to SinkBarriers, we maintain the case
+  // that no instruction in SinkBarriers dominates another instruction.
+  bool FoundDom = false;
+  SmallPtrSet ToRemove;
+  for (auto *S : SinkBarriers) {
+if (Dom.dominates(S, I)) {
+  FoundDom = true;
+  break;
+} else if (Dom.dominates(I, S)) {
+  ToRemove.insert(S);
+}
+  }
+  if (!FoundDom) {
+SinkBarriers.insert(I);
+for (auto *R : ToRemove) {
+  SinkBarriers.erase(R);
+}
+  }
+};
+for (User *U : I.users()) {
+  if (!isa(U))
+continue;
+  if (CastInst) {
+// If we have multiple cast instructions for the alloca, don't
+// deal with it beause it's too complex.
+Valid = false;
+break;
+  }
+  CastInst = cast(U);
+  for (User *CU : CastInst->users()) {
+// If we see any user of CastInst that's not lifetime start/end
+// intrinsics, give up because it's too complex.
+if (auto *CUI = dyn_cast(CU)) {
+  if (CUI->getIntrinsicID() == Intrinsic::lifetime_start)
+LifetimeStartInsts.insert(CUI);
+  else if (CUI->getIntrinsicID() == Intrinsic::lifetime_end)
+addSinkBarrier(CUI);
+  else
+Valid = false;
+} else {
+  Valid = false;
+}
+  }
+}
+if (!Valid || LifetimeStartInsts.empty())
+  continue;
+
+for (User *U : I.users()) {
+  if (U == CastInst)
+continue;
+  // Every user of the variable is also a sink barrier.
+  addSinkBarrier(cast(U));
+}
+
+// For each sink barrier, we insert a lifetime start marker right
+// before it.
+const auto *LifetimeStartInst = *

[PATCH] D82314: [RFC][Coroutines] Optimize the lifespan of temporary co_await object

2020-06-24 Thread Xun Li via Phabricator via cfe-commits
lxfind marked an inline comment as done.
lxfind added inline comments.



Comment at: llvm/lib/Transforms/Coroutines/CoroSplit.cpp:1286
+continue;
+  if (CastInst) {
+// If we have multiple cast instructions for the alloca, don't

junparser wrote:
> It is possible to handle multiple cast instructions as long as they are only 
> used by lifetime marker intrinsic. 
It's certainly possible. I didn't do it here because a reasonable compiler 
frontend should never emit multiple cast instructions for the same variable in 
order to mark lifetime. If there are, they must be used for something else.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D82314



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


[PATCH] D82314: [RFC][Coroutines] Optimize the lifespan of temporary co_await object

2020-06-24 Thread Xun Li via Phabricator via cfe-commits
lxfind updated this revision to Diff 273169.
lxfind added a comment.

Actually it seems pretty easy to handle the case of multiple BitCastInst, so 
did it here. Also added a test.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D82314

Files:
  llvm/lib/Transforms/Coroutines/CoroSplit.cpp
  llvm/test/Transforms/Coroutines/coro-split-02.ll
  llvm/test/Transforms/Coroutines/coro-split-sink-lifetime.ll

Index: llvm/test/Transforms/Coroutines/coro-split-sink-lifetime.ll
===
--- llvm/test/Transforms/Coroutines/coro-split-sink-lifetime.ll
+++ llvm/test/Transforms/Coroutines/coro-split-sink-lifetime.ll
@@ -1,6 +1,5 @@
-; Tests that coro-split can handle the case when a code after coro.suspend uses
-; a value produces between coro.save and coro.suspend (%Result.i19)
-; and checks whether stray coro.saves are properly removed
+; Tests that coro-split will optimize the lifetime.start maker of each local variable,
+; sink them to the places closest to the actual use.
 ; RUN: opt < %s -coro-split -S | FileCheck %s
 ; RUN: opt < %s -passes=coro-split -S | FileCheck %s
 
@@ -15,6 +14,9 @@
 entry:
   %ref.tmp7 = alloca %"struct.lean_future::Awaiter", align 8
   %testval = alloca i32
+  %cast = bitcast i32* %testval to i8*
+  ; lifetime of %testval starts here, but not used until await.ready.
+  call void @llvm.lifetime.start.p0i8(i64 4, i8* %cast)
   %id = call token @llvm.coro.id(i32 0, i8* null, i8* null, i8* null)
   %alloc = call i8* @malloc(i64 16) #3
   %vFrame = call noalias nonnull i8* @llvm.coro.begin(token %id, i8* %alloc)
@@ -29,8 +31,8 @@
 await.ready:
   %StrayCoroSave = call token @llvm.coro.save(i8* null)
   %val = load i32, i32* %Result.i19
-  %cast = bitcast i32* %testval to i8*
-  call void @llvm.lifetime.start.p0i8(i64 4, i8* %cast)
+  %test = load i32, i32* %testval
+  call void @print(i32 %test)
   call void @llvm.lifetime.end.p0i8(i64 4, i8*  %cast)
   call void @print(i32 %val)
   br label %exit
@@ -40,14 +42,15 @@
 }
 
 ; CHECK-LABEL: @a.resume(
-; CHECK: %testval = alloca i32
-; CHECK: getelementptr inbounds %a.Frame
+; CHECK: %testval = alloca i32, align 4
+; CHECK-NEXT:getelementptr inbounds %a.Frame
 ; CHECK-NEXT:getelementptr inbounds %"struct.lean_future::Awaiter"
-; CHECK-NOT: call token @llvm.coro.save(i8* null)
+; CHECK-NEXT:%cast1 = bitcast i32* %testval to i8*
 ; CHECK-NEXT:%val = load i32, i32* %Result
-; CHECK-NEXT:%cast = bitcast i32* %testval to i8*
-; CHECK-NEXT:call void @llvm.lifetime.start.p0i8(i64 4, i8* %cast)
-; CHECK-NEXT:call void @llvm.lifetime.end.p0i8(i64 4, i8* %cast)
+; CHECK-NEXT:call void @llvm.lifetime.start.p0i8(i64 4, i8* %cast1)
+; CHECK-NEXT:%test = load i32, i32* %testval
+; CHECK-NEXT:call void @print(i32 %test)
+; CHECK-NEXT:call void @llvm.lifetime.end.p0i8(i64 4, i8*  %cast1)
 ; CHECK-NEXT:call void @print(i32 %val)
 ; CHECK-NEXT:ret void
 
Index: llvm/test/Transforms/Coroutines/coro-split-02.ll
===
--- llvm/test/Transforms/Coroutines/coro-split-02.ll
+++ llvm/test/Transforms/Coroutines/coro-split-02.ll
@@ -31,6 +31,8 @@
   %val = load i32, i32* %Result.i19
   %cast = bitcast i32* %testval to i8*
   call void @llvm.lifetime.start.p0i8(i64 4, i8* %cast)
+  %test = load i32, i32* %testval
+  call void @print(i32 %test)
   call void @llvm.lifetime.end.p0i8(i64 4, i8*  %cast)
   call void @print(i32 %val)
   br label %exit
@@ -40,14 +42,15 @@
 }
 
 ; CHECK-LABEL: @a.resume(
-; CHECK: %testval = alloca i32
 ; CHECK: getelementptr inbounds %a.Frame
 ; CHECK-NEXT:getelementptr inbounds %"struct.lean_future::Awaiter"
 ; CHECK-NOT: call token @llvm.coro.save(i8* null)
 ; CHECK-NEXT:%val = load i32, i32* %Result
 ; CHECK-NEXT:%cast = bitcast i32* %testval to i8*
 ; CHECK-NEXT:call void @llvm.lifetime.start.p0i8(i64 4, i8* %cast)
-; CHECK-NEXT:call void @llvm.lifetime.end.p0i8(i64 4, i8* %cast)
+; CHECK-NEXT:%test = load i32, i32* %testval
+; CHECK-NEXT:call void @print(i32 %test)
+; CHECK-NEXT:call void @llvm.lifetime.end.p0i8(i64 4, i8*  %cast)
 ; CHECK-NEXT:call void @print(i32 %val)
 ; CHECK-NEXT:ret void
 
Index: llvm/lib/Transforms/Coroutines/CoroSplit.cpp
===
--- llvm/lib/Transforms/Coroutines/CoroSplit.cpp
+++ llvm/lib/Transforms/Coroutines/CoroSplit.cpp
@@ -75,7 +75,7 @@
 
 namespace {
 
-/// A little helper class for building 
+/// A little helper class for building
 class CoroCloner {
 public:
   enum class Kind {
@@ -563,7 +563,7 @@
   // In the original function, the AllocaSpillBlock is a block immediately
   // following the allocation of the frame object which defines GEPs for
   // all the allocas that have been moved into the frame, and it end

[PATCH] D82314: [RFC][Coroutines] Optimize the lifespan of temporary co_await object

2020-06-24 Thread Xun Li via Phabricator via cfe-commits
lxfind updated this revision to Diff 273171.
lxfind added a comment.

A few unintended changes


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D82314

Files:
  llvm/lib/Transforms/Coroutines/CoroSplit.cpp
  llvm/test/Transforms/Coroutines/coro-split-02.ll
  llvm/test/Transforms/Coroutines/coro-split-sink-lifetime.ll

Index: llvm/test/Transforms/Coroutines/coro-split-sink-lifetime.ll
===
--- llvm/test/Transforms/Coroutines/coro-split-sink-lifetime.ll
+++ llvm/test/Transforms/Coroutines/coro-split-sink-lifetime.ll
@@ -1,6 +1,5 @@
-; Tests that coro-split can handle the case when a code after coro.suspend uses
-; a value produces between coro.save and coro.suspend (%Result.i19)
-; and checks whether stray coro.saves are properly removed
+; Tests that coro-split will optimize the lifetime.start maker of each local variable,
+; sink them to the places closest to the actual use.
 ; RUN: opt < %s -coro-split -S | FileCheck %s
 ; RUN: opt < %s -passes=coro-split -S | FileCheck %s
 
@@ -15,6 +14,9 @@
 entry:
   %ref.tmp7 = alloca %"struct.lean_future::Awaiter", align 8
   %testval = alloca i32
+  %cast = bitcast i32* %testval to i8*
+  ; lifetime of %testval starts here, but not used until await.ready.
+  call void @llvm.lifetime.start.p0i8(i64 4, i8* %cast)
   %id = call token @llvm.coro.id(i32 0, i8* null, i8* null, i8* null)
   %alloc = call i8* @malloc(i64 16) #3
   %vFrame = call noalias nonnull i8* @llvm.coro.begin(token %id, i8* %alloc)
@@ -29,8 +31,8 @@
 await.ready:
   %StrayCoroSave = call token @llvm.coro.save(i8* null)
   %val = load i32, i32* %Result.i19
-  %cast = bitcast i32* %testval to i8*
-  call void @llvm.lifetime.start.p0i8(i64 4, i8* %cast)
+  %test = load i32, i32* %testval
+  call void @print(i32 %test)
   call void @llvm.lifetime.end.p0i8(i64 4, i8*  %cast)
   call void @print(i32 %val)
   br label %exit
@@ -40,14 +42,15 @@
 }
 
 ; CHECK-LABEL: @a.resume(
-; CHECK: %testval = alloca i32
-; CHECK: getelementptr inbounds %a.Frame
+; CHECK: %testval = alloca i32, align 4
+; CHECK-NEXT:getelementptr inbounds %a.Frame
 ; CHECK-NEXT:getelementptr inbounds %"struct.lean_future::Awaiter"
-; CHECK-NOT: call token @llvm.coro.save(i8* null)
+; CHECK-NEXT:%cast1 = bitcast i32* %testval to i8*
 ; CHECK-NEXT:%val = load i32, i32* %Result
-; CHECK-NEXT:%cast = bitcast i32* %testval to i8*
-; CHECK-NEXT:call void @llvm.lifetime.start.p0i8(i64 4, i8* %cast)
-; CHECK-NEXT:call void @llvm.lifetime.end.p0i8(i64 4, i8* %cast)
+; CHECK-NEXT:call void @llvm.lifetime.start.p0i8(i64 4, i8* %cast1)
+; CHECK-NEXT:%test = load i32, i32* %testval
+; CHECK-NEXT:call void @print(i32 %test)
+; CHECK-NEXT:call void @llvm.lifetime.end.p0i8(i64 4, i8* %cast1)
 ; CHECK-NEXT:call void @print(i32 %val)
 ; CHECK-NEXT:ret void
 
Index: llvm/test/Transforms/Coroutines/coro-split-02.ll
===
--- llvm/test/Transforms/Coroutines/coro-split-02.ll
+++ llvm/test/Transforms/Coroutines/coro-split-02.ll
@@ -31,6 +31,8 @@
   %val = load i32, i32* %Result.i19
   %cast = bitcast i32* %testval to i8*
   call void @llvm.lifetime.start.p0i8(i64 4, i8* %cast)
+  %test = load i32, i32* %testval
+  call void @print(i32 %test)
   call void @llvm.lifetime.end.p0i8(i64 4, i8*  %cast)
   call void @print(i32 %val)
   br label %exit
@@ -47,6 +49,8 @@
 ; CHECK-NEXT:%val = load i32, i32* %Result
 ; CHECK-NEXT:%cast = bitcast i32* %testval to i8*
 ; CHECK-NEXT:call void @llvm.lifetime.start.p0i8(i64 4, i8* %cast)
+; CHECK-NEXT:%test = load i32, i32* %testval
+; CHECK-NEXT:call void @print(i32 %test)
 ; CHECK-NEXT:call void @llvm.lifetime.end.p0i8(i64 4, i8* %cast)
 ; CHECK-NEXT:call void @print(i32 %val)
 ; CHECK-NEXT:ret void
Index: llvm/lib/Transforms/Coroutines/CoroSplit.cpp
===
--- llvm/lib/Transforms/Coroutines/CoroSplit.cpp
+++ llvm/lib/Transforms/Coroutines/CoroSplit.cpp
@@ -75,7 +75,7 @@
 
 namespace {
 
-/// A little helper class for building 
+/// A little helper class for building
 class CoroCloner {
 public:
   enum class Kind {
@@ -563,7 +563,7 @@
   // In the original function, the AllocaSpillBlock is a block immediately
   // following the allocation of the frame object which defines GEPs for
   // all the allocas that have been moved into the frame, and it ends by
-  // branching to the original beginning of the coroutine.  Make this 
+  // branching to the original beginning of the coroutine.  Make this
   // the entry block of the cloned function.
   auto *Entry = cast(VMap[Shape.AllocaSpillBlock]);
   auto *OldEntry = &NewF->getEntryBlock();
@@ -1239,6 +1239,106 @@
   S.resize(N);
 }
 
+/// For every local variable that has lifetime intrinsics markers, we sin

[PATCH] D82314: [RFC][Coroutines] Optimize the lifespan of temporary co_await object

2020-06-24 Thread Xun Li via Phabricator via cfe-commits
lxfind updated this revision to Diff 273173.
lxfind added a comment.

Remove unused variable


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D82314

Files:
  llvm/lib/Transforms/Coroutines/CoroSplit.cpp
  llvm/test/Transforms/Coroutines/coro-split-02.ll
  llvm/test/Transforms/Coroutines/coro-split-sink-lifetime.ll

Index: llvm/test/Transforms/Coroutines/coro-split-sink-lifetime.ll
===
--- llvm/test/Transforms/Coroutines/coro-split-sink-lifetime.ll
+++ llvm/test/Transforms/Coroutines/coro-split-sink-lifetime.ll
@@ -1,6 +1,5 @@
-; Tests that coro-split can handle the case when a code after coro.suspend uses
-; a value produces between coro.save and coro.suspend (%Result.i19)
-; and checks whether stray coro.saves are properly removed
+; Tests that coro-split will optimize the lifetime.start maker of each local variable,
+; sink them to the places closest to the actual use.
 ; RUN: opt < %s -coro-split -S | FileCheck %s
 ; RUN: opt < %s -passes=coro-split -S | FileCheck %s
 
@@ -15,6 +14,9 @@
 entry:
   %ref.tmp7 = alloca %"struct.lean_future::Awaiter", align 8
   %testval = alloca i32
+  %cast = bitcast i32* %testval to i8*
+  ; lifetime of %testval starts here, but not used until await.ready.
+  call void @llvm.lifetime.start.p0i8(i64 4, i8* %cast)
   %id = call token @llvm.coro.id(i32 0, i8* null, i8* null, i8* null)
   %alloc = call i8* @malloc(i64 16) #3
   %vFrame = call noalias nonnull i8* @llvm.coro.begin(token %id, i8* %alloc)
@@ -29,8 +31,8 @@
 await.ready:
   %StrayCoroSave = call token @llvm.coro.save(i8* null)
   %val = load i32, i32* %Result.i19
-  %cast = bitcast i32* %testval to i8*
-  call void @llvm.lifetime.start.p0i8(i64 4, i8* %cast)
+  %test = load i32, i32* %testval
+  call void @print(i32 %test)
   call void @llvm.lifetime.end.p0i8(i64 4, i8*  %cast)
   call void @print(i32 %val)
   br label %exit
@@ -40,14 +42,15 @@
 }
 
 ; CHECK-LABEL: @a.resume(
-; CHECK: %testval = alloca i32
-; CHECK: getelementptr inbounds %a.Frame
+; CHECK: %testval = alloca i32, align 4
+; CHECK-NEXT:getelementptr inbounds %a.Frame
 ; CHECK-NEXT:getelementptr inbounds %"struct.lean_future::Awaiter"
-; CHECK-NOT: call token @llvm.coro.save(i8* null)
+; CHECK-NEXT:%cast1 = bitcast i32* %testval to i8*
 ; CHECK-NEXT:%val = load i32, i32* %Result
-; CHECK-NEXT:%cast = bitcast i32* %testval to i8*
-; CHECK-NEXT:call void @llvm.lifetime.start.p0i8(i64 4, i8* %cast)
-; CHECK-NEXT:call void @llvm.lifetime.end.p0i8(i64 4, i8* %cast)
+; CHECK-NEXT:call void @llvm.lifetime.start.p0i8(i64 4, i8* %cast1)
+; CHECK-NEXT:%test = load i32, i32* %testval
+; CHECK-NEXT:call void @print(i32 %test)
+; CHECK-NEXT:call void @llvm.lifetime.end.p0i8(i64 4, i8* %cast1)
 ; CHECK-NEXT:call void @print(i32 %val)
 ; CHECK-NEXT:ret void
 
Index: llvm/test/Transforms/Coroutines/coro-split-02.ll
===
--- llvm/test/Transforms/Coroutines/coro-split-02.ll
+++ llvm/test/Transforms/Coroutines/coro-split-02.ll
@@ -31,6 +31,8 @@
   %val = load i32, i32* %Result.i19
   %cast = bitcast i32* %testval to i8*
   call void @llvm.lifetime.start.p0i8(i64 4, i8* %cast)
+  %test = load i32, i32* %testval
+  call void @print(i32 %test)
   call void @llvm.lifetime.end.p0i8(i64 4, i8*  %cast)
   call void @print(i32 %val)
   br label %exit
@@ -47,6 +49,8 @@
 ; CHECK-NEXT:%val = load i32, i32* %Result
 ; CHECK-NEXT:%cast = bitcast i32* %testval to i8*
 ; CHECK-NEXT:call void @llvm.lifetime.start.p0i8(i64 4, i8* %cast)
+; CHECK-NEXT:%test = load i32, i32* %testval
+; CHECK-NEXT:call void @print(i32 %test)
 ; CHECK-NEXT:call void @llvm.lifetime.end.p0i8(i64 4, i8* %cast)
 ; CHECK-NEXT:call void @print(i32 %val)
 ; CHECK-NEXT:ret void
Index: llvm/lib/Transforms/Coroutines/CoroSplit.cpp
===
--- llvm/lib/Transforms/Coroutines/CoroSplit.cpp
+++ llvm/lib/Transforms/Coroutines/CoroSplit.cpp
@@ -75,7 +75,7 @@
 
 namespace {
 
-/// A little helper class for building 
+/// A little helper class for building
 class CoroCloner {
 public:
   enum class Kind {
@@ -563,7 +563,7 @@
   // In the original function, the AllocaSpillBlock is a block immediately
   // following the allocation of the frame object which defines GEPs for
   // all the allocas that have been moved into the frame, and it ends by
-  // branching to the original beginning of the coroutine.  Make this 
+  // branching to the original beginning of the coroutine.  Make this
   // the entry block of the cloned function.
   auto *Entry = cast(VMap[Shape.AllocaSpillBlock]);
   auto *OldEntry = &NewF->getEntryBlock();
@@ -1239,6 +1239,103 @@
   S.resize(N);
 }
 
+/// For every local variable that has lifetime intrinsics markers, we sink

[PATCH] D82415: [Coroutines] Special handle __builtin_coro_resume for final_suspend nothrow check

2020-06-25 Thread Xun Li via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
lxfind marked an inline comment as done.
Closed by commit rG366159566df3: [Coroutines] Special handle 
__builtin_coro_resume for final_suspend nothrow… (authored by lxfind).

Changed prior to commit:
  https://reviews.llvm.org/D82415?vs=272910&id=273466#toc

Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D82415

Files:
  clang/lib/Sema/SemaCoroutine.cpp


Index: clang/lib/Sema/SemaCoroutine.cpp
===
--- clang/lib/Sema/SemaCoroutine.cpp
+++ clang/lib/Sema/SemaCoroutine.cpp
@@ -614,6 +614,17 @@
 // In the case of dtor, the call to dtor is implicit and hence we should
 // pass nullptr to canCalleeThrow.
 if (Sema::canCalleeThrow(S, IsDtor ? nullptr : cast(E), D)) {
+  if (const auto *FD = dyn_cast(D)) {
+// co_await promise.final_suspend() could end up calling
+// __builtin_coro_resume for symmetric transfer if await_suspend()
+// returns a handle. In that case, even __builtin_coro_resume is not
+// declared as noexcept and may throw, it does not throw _into_ the
+// coroutine that just suspended, but rather throws back out from
+// whoever called coroutine_handle::resume(), hence we claim that
+// logically it does not throw.
+if (FD->getBuiltinID() == Builtin::BI__builtin_coro_resume)
+  return;
+  }
   if (ThrowingDecls.empty()) {
 // First time seeing an error, emit the error message.
 S.Diag(cast(S.CurContext)->getLocation(),


Index: clang/lib/Sema/SemaCoroutine.cpp
===
--- clang/lib/Sema/SemaCoroutine.cpp
+++ clang/lib/Sema/SemaCoroutine.cpp
@@ -614,6 +614,17 @@
 // In the case of dtor, the call to dtor is implicit and hence we should
 // pass nullptr to canCalleeThrow.
 if (Sema::canCalleeThrow(S, IsDtor ? nullptr : cast(E), D)) {
+  if (const auto *FD = dyn_cast(D)) {
+// co_await promise.final_suspend() could end up calling
+// __builtin_coro_resume for symmetric transfer if await_suspend()
+// returns a handle. In that case, even __builtin_coro_resume is not
+// declared as noexcept and may throw, it does not throw _into_ the
+// coroutine that just suspended, but rather throws back out from
+// whoever called coroutine_handle::resume(), hence we claim that
+// logically it does not throw.
+if (FD->getBuiltinID() == Builtin::BI__builtin_coro_resume)
+  return;
+  }
   if (ThrowingDecls.empty()) {
 // First time seeing an error, emit the error message.
 S.Diag(cast(S.CurContext)->getLocation(),
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D82332: [Coroutines] Handle dependent promise types for final_suspend non-throw check

2020-06-25 Thread Xun Li via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rGc25acec84594: [Coroutines] Handle dependent promise types 
for final_suspend non-throw check (authored by lxfind).

Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D82332

Files:
  clang/include/clang/Sema/Sema.h
  clang/lib/Sema/SemaCoroutine.cpp
  clang/lib/Sema/TreeTransform.h
  clang/test/SemaCXX/coroutine-final-suspend-noexcept.cpp

Index: clang/test/SemaCXX/coroutine-final-suspend-noexcept.cpp
===
--- clang/test/SemaCXX/coroutine-final-suspend-noexcept.cpp
+++ clang/test/SemaCXX/coroutine-final-suspend-noexcept.cpp
@@ -11,27 +11,27 @@
 
 template 
 struct coroutine_handle {
-  static coroutine_handle from_address(void *); // expected-note {{must be declared with 'noexcept'}}
+  static coroutine_handle from_address(void *); // expected-note 2 {{must be declared with 'noexcept'}}
 };
 template <>
 struct coroutine_handle {
   template 
-  coroutine_handle(coroutine_handle); // expected-note {{must be declared with 'noexcept'}}
+  coroutine_handle(coroutine_handle); // expected-note 2 {{must be declared with 'noexcept'}}
 };
 
 struct suspend_never {
-  bool await_ready() { return true; }   // expected-note {{must be declared with 'noexcept'}}
-  void await_suspend(coroutine_handle<>) {} // expected-note {{must be declared with 'noexcept'}}
-  void await_resume() {}// expected-note {{must be declared with 'noexcept'}}
-  ~suspend_never() noexcept(false); // expected-note {{must be declared with 'noexcept'}}
+  bool await_ready() { return true; }   // expected-note 2 {{must be declared with 'noexcept'}}
+  void await_suspend(coroutine_handle<>) {} // expected-note 2 {{must be declared with 'noexcept'}}
+  void await_resume() {}// expected-note 2 {{must be declared with 'noexcept'}}
+  ~suspend_never() noexcept(false); // expected-note 2 {{must be declared with 'noexcept'}}
 };
 
 struct suspend_always {
   bool await_ready() { return false; }
   void await_suspend(coroutine_handle<>) {}
   void await_resume() {}
-  suspend_never operator co_await(); // expected-note {{must be declared with 'noexcept'}}
-  ~suspend_always() noexcept(false); // expected-note {{must be declared with 'noexcept'}}
+  suspend_never operator co_await(); // expected-note 2 {{must be declared with 'noexcept'}}
+  ~suspend_always() noexcept(false); // expected-note 2 {{must be declared with 'noexcept'}}
 };
 
 } // namespace experimental
@@ -50,7 +50,7 @@
   struct promise_type {
 coro_t get_return_object();
 suspend_never initial_suspend();
-suspend_always final_suspend(); // expected-note {{must be declared with 'noexcept'}}
+suspend_always final_suspend(); // expected-note 2 {{must be declared with 'noexcept'}}
 void return_void();
 static void unhandled_exception();
   };
@@ -60,3 +60,13 @@
   A a{};
   co_await a;
 }
+
+template 
+coro_t f_dep(T n) { // expected-error {{the expression 'co_await __promise.final_suspend()' is required to be non-throwing}}
+  A a{};
+  co_await a;
+}
+
+void foo() {
+  f_dep(5); // expected-note {{in instantiation of function template specialization 'f_dep' requested here}}
+}
Index: clang/lib/Sema/TreeTransform.h
===
--- clang/lib/Sema/TreeTransform.h
+++ clang/lib/Sema/TreeTransform.h
@@ -7630,7 +7630,8 @@
 return StmtError();
   StmtResult FinalSuspend =
   getDerived().TransformStmt(S->getFinalSuspendStmt());
-  if (FinalSuspend.isInvalid())
+  if (FinalSuspend.isInvalid() ||
+  !SemaRef.checkFinalSuspendNoThrow(FinalSuspend.get()))
 return StmtError();
   ScopeInfo->setCoroutineSuspends(InitSuspend.get(), FinalSuspend.get());
   assert(isa(InitSuspend.get()) && isa(FinalSuspend.get()));
Index: clang/lib/Sema/SemaCoroutine.cpp
===
--- clang/lib/Sema/SemaCoroutine.cpp
+++ clang/lib/Sema/SemaCoroutine.cpp
@@ -642,7 +642,6 @@
   } else if (SC == Expr::CallExprClass || SC == Expr::CXXMemberCallExprClass ||
  SC == Expr::CXXOperatorCallExprClass) {
 if (!cast(E)->isTypeDependent()) {
-  // FIXME: Handle dependent types.
   checkDeclNoexcept(cast(E)->getCalleeDecl());
   auto ReturnType = cast(E)->getCallReturnType(S.getASTContext());
   // Check the destructor of the call return type, if any.
@@ -662,22 +661,20 @@
   }
 }
 
-/// Check that the expression co_await promise.final_suspend() shall not be
-/// potentially-throwing.
-static bool checkNoThrow(Sema &S, const Stmt *FinalSuspend) {
+bool Sema::checkFinalSuspendNoThrow(const Stmt *FinalSuspend) {
   llvm::SmallPtrSet ThrowingDecls;
   // We first collect all declarations that should not throw but not declared
   // with noexcept. We then sort them 

[PATCH] D82314: [Coroutines] Optimize the lifespan of temporary co_await object

2020-06-26 Thread Xun Li via Phabricator via cfe-commits
lxfind added a comment.

In D82314#2117543 , @lewissbaker wrote:

> >   There are still room for improvements, in particular, GCC has a 4K frame 
> > for this function.
>
> I think GCC having a smaller coroutine frame is probably because it does not 
> yet implement the allocation-elision optimisation which inlines the nested 
> coroutine frame (which is 4K) into the parent coroutine frame.
>  I have not looked yet, but I suspect that you'll see within the 
> get_big_object2() code it will perform another heap allocation for the 
> get_big_object() frame.
>
> Until we have more general support for async RVO, I think 8K is probably as 
> good as we're going to be able to get (4K for this coroutine's promise and 4K 
> for child coroutine-frame and its promise).


Yes your observation is correct. It's due to the nesting of the child frame.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D82314



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


[PATCH] D82314: [Coroutines] Optimize the lifespan of temporary co_await object

2020-06-29 Thread Xun Li via Phabricator via cfe-commits
lxfind updated this revision to Diff 273946.
lxfind added a comment.

Rebase before landing


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D82314

Files:
  llvm/lib/Transforms/Coroutines/CoroSplit.cpp
  llvm/test/Transforms/Coroutines/coro-split-02.ll
  llvm/test/Transforms/Coroutines/coro-split-sink-lifetime.ll

Index: llvm/test/Transforms/Coroutines/coro-split-sink-lifetime.ll
===
--- llvm/test/Transforms/Coroutines/coro-split-sink-lifetime.ll
+++ llvm/test/Transforms/Coroutines/coro-split-sink-lifetime.ll
@@ -1,6 +1,5 @@
-; Tests that coro-split can handle the case when a code after coro.suspend uses
-; a value produces between coro.save and coro.suspend (%Result.i19)
-; and checks whether stray coro.saves are properly removed
+; Tests that coro-split will optimize the lifetime.start maker of each local variable,
+; sink them to the places closest to the actual use.
 ; RUN: opt < %s -coro-split -S | FileCheck %s
 ; RUN: opt < %s -passes=coro-split -S | FileCheck %s
 
@@ -15,6 +14,9 @@
 entry:
   %ref.tmp7 = alloca %"struct.lean_future::Awaiter", align 8
   %testval = alloca i32
+  %cast = bitcast i32* %testval to i8*
+  ; lifetime of %testval starts here, but not used until await.ready.
+  call void @llvm.lifetime.start.p0i8(i64 4, i8* %cast)
   %id = call token @llvm.coro.id(i32 0, i8* null, i8* null, i8* null)
   %alloc = call i8* @malloc(i64 16) #3
   %vFrame = call noalias nonnull i8* @llvm.coro.begin(token %id, i8* %alloc)
@@ -29,8 +31,8 @@
 await.ready:
   %StrayCoroSave = call token @llvm.coro.save(i8* null)
   %val = load i32, i32* %Result.i19
-  %cast = bitcast i32* %testval to i8*
-  call void @llvm.lifetime.start.p0i8(i64 4, i8* %cast)
+  %test = load i32, i32* %testval
+  call void @print(i32 %test)
   call void @llvm.lifetime.end.p0i8(i64 4, i8*  %cast)
   call void @print(i32 %val)
   br label %exit
@@ -40,14 +42,15 @@
 }
 
 ; CHECK-LABEL: @a.resume(
-; CHECK: %testval = alloca i32
-; CHECK: getelementptr inbounds %a.Frame
+; CHECK: %testval = alloca i32, align 4
+; CHECK-NEXT:getelementptr inbounds %a.Frame
 ; CHECK-NEXT:getelementptr inbounds %"struct.lean_future::Awaiter"
-; CHECK-NOT: call token @llvm.coro.save(i8* null)
+; CHECK-NEXT:%cast1 = bitcast i32* %testval to i8*
 ; CHECK-NEXT:%val = load i32, i32* %Result
-; CHECK-NEXT:%cast = bitcast i32* %testval to i8*
-; CHECK-NEXT:call void @llvm.lifetime.start.p0i8(i64 4, i8* %cast)
-; CHECK-NEXT:call void @llvm.lifetime.end.p0i8(i64 4, i8* %cast)
+; CHECK-NEXT:call void @llvm.lifetime.start.p0i8(i64 4, i8* %cast1)
+; CHECK-NEXT:%test = load i32, i32* %testval
+; CHECK-NEXT:call void @print(i32 %test)
+; CHECK-NEXT:call void @llvm.lifetime.end.p0i8(i64 4, i8* %cast1)
 ; CHECK-NEXT:call void @print(i32 %val)
 ; CHECK-NEXT:ret void
 
Index: llvm/test/Transforms/Coroutines/coro-split-02.ll
===
--- llvm/test/Transforms/Coroutines/coro-split-02.ll
+++ llvm/test/Transforms/Coroutines/coro-split-02.ll
@@ -31,6 +31,8 @@
   %val = load i32, i32* %Result.i19
   %cast = bitcast i32* %testval to i8*
   call void @llvm.lifetime.start.p0i8(i64 4, i8* %cast)
+  %test = load i32, i32* %testval
+  call void @print(i32 %test)
   call void @llvm.lifetime.end.p0i8(i64 4, i8*  %cast)
   call void @print(i32 %val)
   br label %exit
@@ -47,6 +49,8 @@
 ; CHECK-NEXT:%val = load i32, i32* %Result
 ; CHECK-NEXT:%cast = bitcast i32* %testval to i8*
 ; CHECK-NEXT:call void @llvm.lifetime.start.p0i8(i64 4, i8* %cast)
+; CHECK-NEXT:%test = load i32, i32* %testval
+; CHECK-NEXT:call void @print(i32 %test)
 ; CHECK-NEXT:call void @llvm.lifetime.end.p0i8(i64 4, i8* %cast)
 ; CHECK-NEXT:call void @print(i32 %val)
 ; CHECK-NEXT:ret void
Index: llvm/lib/Transforms/Coroutines/CoroSplit.cpp
===
--- llvm/lib/Transforms/Coroutines/CoroSplit.cpp
+++ llvm/lib/Transforms/Coroutines/CoroSplit.cpp
@@ -75,7 +75,7 @@
 
 namespace {
 
-/// A little helper class for building 
+/// A little helper class for building
 class CoroCloner {
 public:
   enum class Kind {
@@ -563,7 +563,7 @@
   // In the original function, the AllocaSpillBlock is a block immediately
   // following the allocation of the frame object which defines GEPs for
   // all the allocas that have been moved into the frame, and it ends by
-  // branching to the original beginning of the coroutine.  Make this 
+  // branching to the original beginning of the coroutine.  Make this
   // the entry block of the cloned function.
   auto *Entry = cast(VMap[Shape.AllocaSpillBlock]);
   auto *OldEntry = &NewF->getEntryBlock();
@@ -1239,6 +1239,103 @@
   S.resize(N);
 }
 
+/// For every local variable that has lifetime intrinsics markers, we sink
+

[PATCH] D82314: [Coroutines] Optimize the lifespan of temporary co_await object

2020-06-29 Thread Xun Li via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rGc8755b6378c2: [Coroutines] Optimize the lifespan of 
temporary co_await object (authored by lxfind).

Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D82314

Files:
  llvm/lib/Transforms/Coroutines/CoroSplit.cpp
  llvm/test/Transforms/Coroutines/coro-split-02.ll
  llvm/test/Transforms/Coroutines/coro-split-sink-lifetime.ll

Index: llvm/test/Transforms/Coroutines/coro-split-sink-lifetime.ll
===
--- llvm/test/Transforms/Coroutines/coro-split-sink-lifetime.ll
+++ llvm/test/Transforms/Coroutines/coro-split-sink-lifetime.ll
@@ -1,6 +1,5 @@
-; Tests that coro-split can handle the case when a code after coro.suspend uses
-; a value produces between coro.save and coro.suspend (%Result.i19)
-; and checks whether stray coro.saves are properly removed
+; Tests that coro-split will optimize the lifetime.start maker of each local variable,
+; sink them to the places closest to the actual use.
 ; RUN: opt < %s -coro-split -S | FileCheck %s
 ; RUN: opt < %s -passes=coro-split -S | FileCheck %s
 
@@ -15,6 +14,9 @@
 entry:
   %ref.tmp7 = alloca %"struct.lean_future::Awaiter", align 8
   %testval = alloca i32
+  %cast = bitcast i32* %testval to i8*
+  ; lifetime of %testval starts here, but not used until await.ready.
+  call void @llvm.lifetime.start.p0i8(i64 4, i8* %cast)
   %id = call token @llvm.coro.id(i32 0, i8* null, i8* null, i8* null)
   %alloc = call i8* @malloc(i64 16) #3
   %vFrame = call noalias nonnull i8* @llvm.coro.begin(token %id, i8* %alloc)
@@ -29,8 +31,8 @@
 await.ready:
   %StrayCoroSave = call token @llvm.coro.save(i8* null)
   %val = load i32, i32* %Result.i19
-  %cast = bitcast i32* %testval to i8*
-  call void @llvm.lifetime.start.p0i8(i64 4, i8* %cast)
+  %test = load i32, i32* %testval
+  call void @print(i32 %test)
   call void @llvm.lifetime.end.p0i8(i64 4, i8*  %cast)
   call void @print(i32 %val)
   br label %exit
@@ -40,14 +42,15 @@
 }
 
 ; CHECK-LABEL: @a.resume(
-; CHECK: %testval = alloca i32
-; CHECK: getelementptr inbounds %a.Frame
+; CHECK: %testval = alloca i32, align 4
+; CHECK-NEXT:getelementptr inbounds %a.Frame
 ; CHECK-NEXT:getelementptr inbounds %"struct.lean_future::Awaiter"
-; CHECK-NOT: call token @llvm.coro.save(i8* null)
+; CHECK-NEXT:%cast1 = bitcast i32* %testval to i8*
 ; CHECK-NEXT:%val = load i32, i32* %Result
-; CHECK-NEXT:%cast = bitcast i32* %testval to i8*
-; CHECK-NEXT:call void @llvm.lifetime.start.p0i8(i64 4, i8* %cast)
-; CHECK-NEXT:call void @llvm.lifetime.end.p0i8(i64 4, i8* %cast)
+; CHECK-NEXT:call void @llvm.lifetime.start.p0i8(i64 4, i8* %cast1)
+; CHECK-NEXT:%test = load i32, i32* %testval
+; CHECK-NEXT:call void @print(i32 %test)
+; CHECK-NEXT:call void @llvm.lifetime.end.p0i8(i64 4, i8* %cast1)
 ; CHECK-NEXT:call void @print(i32 %val)
 ; CHECK-NEXT:ret void
 
Index: llvm/test/Transforms/Coroutines/coro-split-02.ll
===
--- llvm/test/Transforms/Coroutines/coro-split-02.ll
+++ llvm/test/Transforms/Coroutines/coro-split-02.ll
@@ -31,6 +31,8 @@
   %val = load i32, i32* %Result.i19
   %cast = bitcast i32* %testval to i8*
   call void @llvm.lifetime.start.p0i8(i64 4, i8* %cast)
+  %test = load i32, i32* %testval
+  call void @print(i32 %test)
   call void @llvm.lifetime.end.p0i8(i64 4, i8*  %cast)
   call void @print(i32 %val)
   br label %exit
@@ -47,6 +49,8 @@
 ; CHECK-NEXT:%val = load i32, i32* %Result
 ; CHECK-NEXT:%cast = bitcast i32* %testval to i8*
 ; CHECK-NEXT:call void @llvm.lifetime.start.p0i8(i64 4, i8* %cast)
+; CHECK-NEXT:%test = load i32, i32* %testval
+; CHECK-NEXT:call void @print(i32 %test)
 ; CHECK-NEXT:call void @llvm.lifetime.end.p0i8(i64 4, i8* %cast)
 ; CHECK-NEXT:call void @print(i32 %val)
 ; CHECK-NEXT:ret void
Index: llvm/lib/Transforms/Coroutines/CoroSplit.cpp
===
--- llvm/lib/Transforms/Coroutines/CoroSplit.cpp
+++ llvm/lib/Transforms/Coroutines/CoroSplit.cpp
@@ -75,7 +75,7 @@
 
 namespace {
 
-/// A little helper class for building 
+/// A little helper class for building
 class CoroCloner {
 public:
   enum class Kind {
@@ -563,7 +563,7 @@
   // In the original function, the AllocaSpillBlock is a block immediately
   // following the allocation of the frame object which defines GEPs for
   // all the allocas that have been moved into the frame, and it ends by
-  // branching to the original beginning of the coroutine.  Make this 
+  // branching to the original beginning of the coroutine.  Make this
   // the entry block of the cloned function.
   auto *Entry = cast(VMap[Shape.AllocaSpillBlock]);
   auto *OldEntry = &NewF->getEntryBlock();
@@ -1239,6 +1239,103 

[PATCH] D82928: [Coroutines] Fix code coverage for coroutine

2020-06-30 Thread Xun Li via Phabricator via cfe-commits
lxfind created this revision.
lxfind added reviewers: lewissbaker, modocache, junparser.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

Previously, source-based coverage analysis does not work properly for coroutine.
This patch adds processing of coroutine body and co_return in the coverage 
analysis, so that we can handle them properly.
For coroutine body, we should only look at the actual function body and ignore 
the compiler-generated things; for co_return, we need to terminate the region 
similar to return statement.
Added a test, and confirms that it now works properly. (without this patch, the 
statement after the if statement will be treated wrongly)


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D82928

Files:
  clang/lib/CodeGen/CoverageMappingGen.cpp
  clang/test/CoverageMapping/coroutine.cpp


Index: clang/test/CoverageMapping/coroutine.cpp
===
--- /dev/null
+++ clang/test/CoverageMapping/coroutine.cpp
@@ -0,0 +1,45 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fcoroutines-ts -std=c++14 
-emit-llvm -fprofile-instrument=clang -fcoverage-mapping -dump-coverage-mapping 
%s | FileCheck %s
+
+namespace std::experimental {
+template 
+struct coroutine_traits;
+
+template 
+struct coroutine_handle {
+  coroutine_handle() = default;
+  static coroutine_handle from_address(void *) noexcept { return {}; }
+};
+template <>
+struct coroutine_handle {
+  static coroutine_handle from_address(void *) { return {}; }
+  coroutine_handle() = default;
+  template 
+  coroutine_handle(coroutine_handle) noexcept {}
+};
+} // namespace std::experimental
+
+struct suspend_always {
+  bool await_ready() noexcept;
+  void await_suspend(std::experimental::coroutine_handle<>) noexcept;
+  void await_resume() noexcept;
+};
+
+template <>
+struct std::experimental::coroutine_traits {
+  struct promise_type {
+int get_return_object();
+suspend_always initial_suspend();
+suspend_always final_suspend() noexcept;
+void return_value(int);
+  };
+};
+
+// CHECK-LABEL: _Z2f1i:
+int f1(int x) {   // CHECK-NEXT: File 0, [[@LINE]]:15 -> [[@LINE+7]]:2 = #0
+  if (x > 42) {   // CHECK-NEXT: File 0, [[@LINE]]:7 -> [[@LINE]]:13 = #0
+++x;  // CHECK-NEXT: Gap,File 0, [[@LINE-1]]:14 -> 
[[@LINE-1]]:15 = #1
+  } else {// CHECK-NEXT: File 0, [[@LINE-2]]:15 -> [[@LINE]]:4 = #1
+co_return x + 42; // CHECK-NEXT: Gap,File 0, [[@LINE-1]]:4 -> 
[[@LINE-1]]:10 = (#0 - #1)
+  }   // CHECK-NEXT: File 0, [[@LINE-2]]:10 -> [[@LINE]]:4 = 
(#0 - #1)
+  co_return x;// CHECK-NEXT: Gap,File 0, [[@LINE-1]]:4 -> [[@LINE]]:3 
= #1
+} // CHECK-NEXT: File 0, [[@LINE-1]]:3 -> [[@LINE]]:2 = #1
Index: clang/lib/CodeGen/CoverageMappingGen.cpp
===
--- clang/lib/CodeGen/CoverageMappingGen.cpp
+++ clang/lib/CodeGen/CoverageMappingGen.cpp
@@ -908,6 +908,18 @@
 terminateRegion(S);
   }
 
+  void VisitCoroutineBodyStmt(const CoroutineBodyStmt *S) {
+extendRegion(S);
+Visit(S->getBody());
+  }
+
+  void VisitCoreturnStmt(const CoreturnStmt *S) {
+extendRegion(S);
+if (S->getOperand())
+  Visit(S->getOperand());
+terminateRegion(S);
+  }
+
   void VisitCXXThrowExpr(const CXXThrowExpr *E) {
 extendRegion(E);
 if (E->getSubExpr())


Index: clang/test/CoverageMapping/coroutine.cpp
===
--- /dev/null
+++ clang/test/CoverageMapping/coroutine.cpp
@@ -0,0 +1,45 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fcoroutines-ts -std=c++14 -emit-llvm -fprofile-instrument=clang -fcoverage-mapping -dump-coverage-mapping %s | FileCheck %s
+
+namespace std::experimental {
+template 
+struct coroutine_traits;
+
+template 
+struct coroutine_handle {
+  coroutine_handle() = default;
+  static coroutine_handle from_address(void *) noexcept { return {}; }
+};
+template <>
+struct coroutine_handle {
+  static coroutine_handle from_address(void *) { return {}; }
+  coroutine_handle() = default;
+  template 
+  coroutine_handle(coroutine_handle) noexcept {}
+};
+} // namespace std::experimental
+
+struct suspend_always {
+  bool await_ready() noexcept;
+  void await_suspend(std::experimental::coroutine_handle<>) noexcept;
+  void await_resume() noexcept;
+};
+
+template <>
+struct std::experimental::coroutine_traits {
+  struct promise_type {
+int get_return_object();
+suspend_always initial_suspend();
+suspend_always final_suspend() noexcept;
+void return_value(int);
+  };
+};
+
+// CHECK-LABEL: _Z2f1i:
+int f1(int x) {   // CHECK-NEXT: File 0, [[@LINE]]:15 -> [[@LINE+7]]:2 = #0
+  if (x > 42) {   // CHECK-NEXT: File 0, [[@LINE]]:7 -> [[@LINE]]:13 = #0
+++x;  // CHECK-NEXT: Gap,File 0, [[@LINE-1]]:14 -> [[@LINE-1]]:15 = #1
+  } else {// CHECK-NEXT: File 0, [[@LINE-2]]:15 -> [[@LINE

[PATCH] D79219: [CMake] Simplify CMake handling for zlib

2020-08-07 Thread Xun Li via Phabricator via cfe-commits
lxfind added a comment.

@phosek, Under this change, now when I build LLVM (with a basic config `cmake 
-G Ninja --LLVM_ENABLE_PROJECTS="clang" ../llvm`), in file 
`build_dir/lib/cmake/llvm/LLVMExports.cmake`, I see this:

  set_target_properties(LLVMSupport PROPERTIES
INTERFACE_LINK_LIBRARIES "curses;m;ZLIB::ZLIB;LLVMDemangle"

This seems broken to me. Can you take a look?


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D79219

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


[PATCH] D79219: [CMake] Simplify CMake handling for zlib

2020-08-08 Thread Xun Li via Phabricator via cfe-commits
lxfind added a comment.

In D79219#2201415 , @phosek wrote:

> In D79219#2201109 , @lxfind wrote:
>
>> @phosek, Under this change, now when I build LLVM (with a basic config 
>> `cmake -G Ninja --LLVM_ENABLE_PROJECTS=clang ../llvm`), in file 
>> `build_dir/lib/cmake/llvm/LLVMExports.cmake`, I see this:
>>
>>   set_target_properties(LLVMSupport PROPERTIES
>> INTERFACE_LINK_LIBRARIES "curses;m;ZLIB::ZLIB;LLVMDemangle"
>>
>> This seems broken to me. Can you take a look?
>
> This is correct. That target is provided by `find_package(ZLIB)`. In 
> LLVMConfig.cmake, we invoke `find_package(ZLIB)` when zlib support is 
> enabled. If you're using `LLVMExports.cmake`, you'll need to invoke 
> `find_package(ZLIB)` yourself.

@phosek, Thanks for the reply. I am not too familiar with this. Could you 
please elaborate more on why setting it to `ZLIB::ZLIB` here is more modern? 
And how one is expected to deal with `ZLIB::ZLIB` that shows up in 
LLVMExports.cmake` (in the modern way)? Should one string pattern matching for 
`ZLIB::ZLIB` and invoke `find_package(ZLIB)` again? (previously one could 
simply concatenate `-l` with the library name in there.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D79219

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


[PATCH] D87470: [Coroutine][Sema] Tighten the lifetime of symmetric transfer returned handle

2020-09-10 Thread Xun Li via Phabricator via cfe-commits
lxfind added a comment.

In D87470#2267060 , @junparser wrote:

> Thanks for the change. LGTM, and testcase?

Not sure how to add a test case for this though. We don't seem to explicitly 
test AST output.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D87470

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


[PATCH] D87470: [Coroutine][Sema] Tighten the lifetime of symmetric transfer returned handle

2020-09-10 Thread Xun Li via Phabricator via cfe-commits
lxfind updated this revision to Diff 291140.
lxfind added a comment.

Add test case. Verify that the size of the frame reduced by 8.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D87470

Files:
  clang/lib/Sema/SemaCoroutine.cpp
  clang/test/CodeGenCoroutines/Inputs/coroutine.h
  clang/test/CodeGenCoroutines/coro-semmetric-transfer.cpp

Index: clang/test/CodeGenCoroutines/coro-semmetric-transfer.cpp
===
--- /dev/null
+++ clang/test/CodeGenCoroutines/coro-semmetric-transfer.cpp
@@ -0,0 +1,52 @@
+// RUN: %clang -std=c++14 -fcoroutines-ts -fsanitize=address -emit-llvm -S -o - %s | FileCheck %s
+
+#include "Inputs/coroutine.h"
+
+namespace coro = std::experimental::coroutines_v1;
+
+struct detached_task {
+  struct promise_type {
+detached_task get_return_object() noexcept {
+  return detached_task{coro::coroutine_handle::from_promise(*this)};
+}
+
+void return_void() noexcept {}
+
+struct final_awaiter {
+  bool await_ready() noexcept { return false; }
+  coro::coroutine_handle<> await_suspend(coro::coroutine_handle h) noexcept {
+h.destroy();
+return coro::noop_coroutine();
+  }
+  void await_resume() noexcept {}
+};
+
+void unhandled_exception() noexcept {}
+
+final_awaiter final_suspend() noexcept { return {}; }
+
+coro::suspend_always initial_suspend() noexcept { return {}; }
+  };
+
+  ~detached_task() {
+if (coro_) {
+  coro_.destroy();
+  coro_ = {};
+}
+  }
+
+  void start() && {
+auto tmp = coro_;
+coro_ = {};
+tmp.resume();
+  }
+
+  coro::coroutine_handle coro_;
+};
+
+detached_task foo() {
+  co_return;
+}
+
+// This is to check that temporary handle returned by the symmetric transfer is not put in the frame.
+// CHECK: {{.*}} = call nonnull i8* @_Znwm(i64 48)
Index: clang/test/CodeGenCoroutines/Inputs/coroutine.h
===
--- clang/test/CodeGenCoroutines/Inputs/coroutine.h
+++ clang/test/CodeGenCoroutines/Inputs/coroutine.h
@@ -15,7 +15,7 @@
 return me;
   }
   void operator()() { resume(); }
-  void *address() const { return ptr; }
+  void *address() const noexcept { return ptr; }
   void resume() const { __builtin_coro_resume(ptr); }
   void destroy() const { __builtin_coro_destroy(ptr); }
   bool done() const { return __builtin_coro_done(ptr); }
@@ -52,19 +52,21 @@
   }
 };
 
-  template 
-  bool operator==(coroutine_handle<_PromiseT> const& _Left,
-coroutine_handle<_PromiseT> const& _Right) noexcept
-  {
-return _Left.address() == _Right.address();
-  }
+struct noop_coroutine_promise {};
+using noop_coroutine_handle = coroutine_handle;
+coroutine_handle<> noop_coroutine() { return {}; }
 
-  template 
-  bool operator!=(coroutine_handle<_PromiseT> const& _Left,
-coroutine_handle<_PromiseT> const& _Right) noexcept
-  {
-return !(_Left == _Right);
-  }
+template 
+bool operator==(coroutine_handle<_PromiseT> const &_Left,
+coroutine_handle<_PromiseT> const &_Right) noexcept {
+  return _Left.address() == _Right.address();
+}
+
+template 
+bool operator!=(coroutine_handle<_PromiseT> const &_Left,
+coroutine_handle<_PromiseT> const &_Right) noexcept {
+  return !(_Left == _Right);
+}
 
 struct suspend_always {
   bool await_ready() { return false; }
Index: clang/lib/Sema/SemaCoroutine.cpp
===
--- clang/lib/Sema/SemaCoroutine.cpp
+++ clang/lib/Sema/SemaCoroutine.cpp
@@ -398,8 +398,8 @@
diag::warn_coroutine_handle_address_invalid_return_type)
 << JustAddress->getType();
 
-  return buildBuiltinCall(S, Loc, Builtin::BI__builtin_coro_resume,
-  JustAddress);
+  return S.MaybeCreateExprWithCleanups(
+  buildBuiltinCall(S, Loc, Builtin::BI__builtin_coro_resume, JustAddress));
 }
 
 /// Build calls to await_ready, await_suspend, and await_resume for a co_await
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D87470: [Coroutine][Sema] Tighten the lifetime of symmetric transfer returned handle

2020-09-11 Thread Xun Li via Phabricator via cfe-commits
lxfind added a comment.

hmm @rjmccall, I don't think there is a stable way to test this. The code 
generated for symmetric transfer is way too complicated to stably pattern match 
one less item in the frame.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D87470

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


[PATCH] D87470: [Coroutine][Sema] Tighten the lifetime of symmetric transfer returned handle

2020-09-11 Thread Xun Li via Phabricator via cfe-commits
lxfind updated this revision to Diff 291255.
lxfind added a comment.

Remove unstable test


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D87470

Files:
  clang/lib/Sema/SemaCoroutine.cpp


Index: clang/lib/Sema/SemaCoroutine.cpp
===
--- clang/lib/Sema/SemaCoroutine.cpp
+++ clang/lib/Sema/SemaCoroutine.cpp
@@ -398,8 +398,8 @@
diag::warn_coroutine_handle_address_invalid_return_type)
 << JustAddress->getType();
 
-  return buildBuiltinCall(S, Loc, Builtin::BI__builtin_coro_resume,
-  JustAddress);
+  return S.MaybeCreateExprWithCleanups(
+  buildBuiltinCall(S, Loc, Builtin::BI__builtin_coro_resume, JustAddress));
 }
 
 /// Build calls to await_ready, await_suspend, and await_resume for a co_await


Index: clang/lib/Sema/SemaCoroutine.cpp
===
--- clang/lib/Sema/SemaCoroutine.cpp
+++ clang/lib/Sema/SemaCoroutine.cpp
@@ -398,8 +398,8 @@
diag::warn_coroutine_handle_address_invalid_return_type)
 << JustAddress->getType();
 
-  return buildBuiltinCall(S, Loc, Builtin::BI__builtin_coro_resume,
-  JustAddress);
+  return S.MaybeCreateExprWithCleanups(
+  buildBuiltinCall(S, Loc, Builtin::BI__builtin_coro_resume, JustAddress));
 }
 
 /// Build calls to await_ready, await_suspend, and await_resume for a co_await
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D87470: [Coroutine][Sema] Tighten the lifetime of symmetric transfer returned handle

2020-09-11 Thread Xun Li via Phabricator via cfe-commits
lxfind updated this revision to Diff 291321.
lxfind added a comment.

Add test to verify that lifetime.end appears right after the address call.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D87470

Files:
  clang/lib/Sema/SemaCoroutine.cpp
  clang/test/CodeGenCoroutines/Inputs/coroutine.h
  clang/test/CodeGenCoroutines/coro-semmetric-transfer.cpp


Index: clang/test/CodeGenCoroutines/coro-semmetric-transfer.cpp
===
--- /dev/null
+++ clang/test/CodeGenCoroutines/coro-semmetric-transfer.cpp
@@ -0,0 +1,53 @@
+// RUN: %clang -std=c++14 -fcoroutines-ts -fsanitize=address -emit-llvm -S -O1 
%s -o -
+
+#include "Inputs/coroutine.h"
+
+namespace coro = std::experimental::coroutines_v1;
+
+struct detached_task {
+  struct promise_type {
+detached_task get_return_object() noexcept {
+  return 
detached_task{coro::coroutine_handle::from_promise(*this)};
+}
+
+void return_void() noexcept {}
+
+struct final_awaiter {
+  bool await_ready() noexcept { return false; }
+  coro::coroutine_handle<> 
await_suspend(coro::coroutine_handle h) noexcept {
+h.destroy();
+return {};
+  }
+  void await_resume() noexcept {}
+};
+
+void unhandled_exception() noexcept {}
+
+final_awaiter final_suspend() noexcept { return {}; }
+
+coro::suspend_always initial_suspend() noexcept { return {}; }
+  };
+
+  ~detached_task() {
+if (coro_) {
+  coro_.destroy();
+  coro_ = {};
+}
+  }
+
+  void start() && {
+auto tmp = coro_;
+coro_ = {};
+tmp.resume();
+  }
+
+  coro::coroutine_handle coro_;
+};
+
+detached_task foo() {
+  co_return;
+}
+
+// check that the lifetime of the coroutine handle used to obtain the address 
ended right away.
+// CHECK:   %{{.*}} = call i8* 
@{{.*address.*}}(%"struct.std::experimental::coroutines_v1::coroutine_handle.0"*
 nonnull %{{.*}})
+// CHECK-NEXT:  call void @llvm.lifetime.end.p0i8(i64 8, i8* nonnull %{{.*}})
Index: clang/test/CodeGenCoroutines/Inputs/coroutine.h
===
--- clang/test/CodeGenCoroutines/Inputs/coroutine.h
+++ clang/test/CodeGenCoroutines/Inputs/coroutine.h
@@ -15,7 +15,7 @@
 return me;
   }
   void operator()() { resume(); }
-  void *address() const { return ptr; }
+  void *address() const noexcept { return ptr; }
   void resume() const { __builtin_coro_resume(ptr); }
   void destroy() const { __builtin_coro_destroy(ptr); }
   bool done() const { return __builtin_coro_done(ptr); }
Index: clang/lib/Sema/SemaCoroutine.cpp
===
--- clang/lib/Sema/SemaCoroutine.cpp
+++ clang/lib/Sema/SemaCoroutine.cpp
@@ -398,6 +398,10 @@
diag::warn_coroutine_handle_address_invalid_return_type)
 << JustAddress->getType();
 
+  // The coroutine handle used to obtain the address is no longer needed
+  // at this point, clean it up to avoid unnecessarily long lifetime which
+  // could lead to unnecessary spilling.
+  JustAddress = S.MaybeCreateExprWithCleanups(JustAddress);
   return buildBuiltinCall(S, Loc, Builtin::BI__builtin_coro_resume,
   JustAddress);
 }


Index: clang/test/CodeGenCoroutines/coro-semmetric-transfer.cpp
===
--- /dev/null
+++ clang/test/CodeGenCoroutines/coro-semmetric-transfer.cpp
@@ -0,0 +1,53 @@
+// RUN: %clang -std=c++14 -fcoroutines-ts -fsanitize=address -emit-llvm -S -O1 %s -o -
+
+#include "Inputs/coroutine.h"
+
+namespace coro = std::experimental::coroutines_v1;
+
+struct detached_task {
+  struct promise_type {
+detached_task get_return_object() noexcept {
+  return detached_task{coro::coroutine_handle::from_promise(*this)};
+}
+
+void return_void() noexcept {}
+
+struct final_awaiter {
+  bool await_ready() noexcept { return false; }
+  coro::coroutine_handle<> await_suspend(coro::coroutine_handle h) noexcept {
+h.destroy();
+return {};
+  }
+  void await_resume() noexcept {}
+};
+
+void unhandled_exception() noexcept {}
+
+final_awaiter final_suspend() noexcept { return {}; }
+
+coro::suspend_always initial_suspend() noexcept { return {}; }
+  };
+
+  ~detached_task() {
+if (coro_) {
+  coro_.destroy();
+  coro_ = {};
+}
+  }
+
+  void start() && {
+auto tmp = coro_;
+coro_ = {};
+tmp.resume();
+  }
+
+  coro::coroutine_handle coro_;
+};
+
+detached_task foo() {
+  co_return;
+}
+
+// check that the lifetime of the coroutine handle used to obtain the address ended right away.
+// CHECK:   %{{.*}} = call i8* @{{.*address.*}}(%"struct.std::experimental::coroutines_v1::coroutine_handle.0"* nonnull %{{.*}})
+// CHECK-NEXT:  call void @llvm.lifetime.end.p0i8(i64 8, i8* nonnull %{{.*}})
Index: clang/test/CodeGenCoro

[PATCH] D87470: [Coroutine][Sema] Tighten the lifetime of symmetric transfer returned handle

2020-09-11 Thread Xun Li via Phabricator via cfe-commits
lxfind updated this revision to Diff 291324.
lxfind added a comment.

remove asan option, not needed


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D87470

Files:
  clang/lib/Sema/SemaCoroutine.cpp
  clang/test/CodeGenCoroutines/Inputs/coroutine.h
  clang/test/CodeGenCoroutines/coro-semmetric-transfer.cpp


Index: clang/test/CodeGenCoroutines/coro-semmetric-transfer.cpp
===
--- /dev/null
+++ clang/test/CodeGenCoroutines/coro-semmetric-transfer.cpp
@@ -0,0 +1,53 @@
+// RUN: %clang -std=c++14 -fcoroutines-ts -emit-llvm -S -O1 %s -o -
+
+#include "Inputs/coroutine.h"
+
+namespace coro = std::experimental::coroutines_v1;
+
+struct detached_task {
+  struct promise_type {
+detached_task get_return_object() noexcept {
+  return 
detached_task{coro::coroutine_handle::from_promise(*this)};
+}
+
+void return_void() noexcept {}
+
+struct final_awaiter {
+  bool await_ready() noexcept { return false; }
+  coro::coroutine_handle<> 
await_suspend(coro::coroutine_handle h) noexcept {
+h.destroy();
+return {};
+  }
+  void await_resume() noexcept {}
+};
+
+void unhandled_exception() noexcept {}
+
+final_awaiter final_suspend() noexcept { return {}; }
+
+coro::suspend_always initial_suspend() noexcept { return {}; }
+  };
+
+  ~detached_task() {
+if (coro_) {
+  coro_.destroy();
+  coro_ = {};
+}
+  }
+
+  void start() && {
+auto tmp = coro_;
+coro_ = {};
+tmp.resume();
+  }
+
+  coro::coroutine_handle coro_;
+};
+
+detached_task foo() {
+  co_return;
+}
+
+// check that the lifetime of the coroutine handle used to obtain the address 
ended right away.
+// CHECK:   %{{.*}} = call i8* 
@{{.*address.*}}(%"struct.std::experimental::coroutines_v1::coroutine_handle.0"*
 nonnull %{{.*}})
+// CHECK-NEXT:  call void @llvm.lifetime.end.p0i8(i64 8, i8* nonnull %{{.*}})
Index: clang/test/CodeGenCoroutines/Inputs/coroutine.h
===
--- clang/test/CodeGenCoroutines/Inputs/coroutine.h
+++ clang/test/CodeGenCoroutines/Inputs/coroutine.h
@@ -15,7 +15,7 @@
 return me;
   }
   void operator()() { resume(); }
-  void *address() const { return ptr; }
+  void *address() const noexcept { return ptr; }
   void resume() const { __builtin_coro_resume(ptr); }
   void destroy() const { __builtin_coro_destroy(ptr); }
   bool done() const { return __builtin_coro_done(ptr); }
Index: clang/lib/Sema/SemaCoroutine.cpp
===
--- clang/lib/Sema/SemaCoroutine.cpp
+++ clang/lib/Sema/SemaCoroutine.cpp
@@ -398,6 +398,10 @@
diag::warn_coroutine_handle_address_invalid_return_type)
 << JustAddress->getType();
 
+  // The coroutine handle used to obtain the address is no longer needed
+  // at this point, clean it up to avoid unnecessarily long lifetime which
+  // could lead to unnecessary spilling.
+  JustAddress = S.MaybeCreateExprWithCleanups(JustAddress);
   return buildBuiltinCall(S, Loc, Builtin::BI__builtin_coro_resume,
   JustAddress);
 }


Index: clang/test/CodeGenCoroutines/coro-semmetric-transfer.cpp
===
--- /dev/null
+++ clang/test/CodeGenCoroutines/coro-semmetric-transfer.cpp
@@ -0,0 +1,53 @@
+// RUN: %clang -std=c++14 -fcoroutines-ts -emit-llvm -S -O1 %s -o -
+
+#include "Inputs/coroutine.h"
+
+namespace coro = std::experimental::coroutines_v1;
+
+struct detached_task {
+  struct promise_type {
+detached_task get_return_object() noexcept {
+  return detached_task{coro::coroutine_handle::from_promise(*this)};
+}
+
+void return_void() noexcept {}
+
+struct final_awaiter {
+  bool await_ready() noexcept { return false; }
+  coro::coroutine_handle<> await_suspend(coro::coroutine_handle h) noexcept {
+h.destroy();
+return {};
+  }
+  void await_resume() noexcept {}
+};
+
+void unhandled_exception() noexcept {}
+
+final_awaiter final_suspend() noexcept { return {}; }
+
+coro::suspend_always initial_suspend() noexcept { return {}; }
+  };
+
+  ~detached_task() {
+if (coro_) {
+  coro_.destroy();
+  coro_ = {};
+}
+  }
+
+  void start() && {
+auto tmp = coro_;
+coro_ = {};
+tmp.resume();
+  }
+
+  coro::coroutine_handle coro_;
+};
+
+detached_task foo() {
+  co_return;
+}
+
+// check that the lifetime of the coroutine handle used to obtain the address ended right away.
+// CHECK:   %{{.*}} = call i8* @{{.*address.*}}(%"struct.std::experimental::coroutines_v1::coroutine_handle.0"* nonnull %{{.*}})
+// CHECK-NEXT:  call void @llvm.lifetime.end.p0i8(i64 8, i8* nonnull %{{.*}})
Index: clang/test/CodeGenCoroutines/Inputs/coroutine.h
=

[PATCH] D87470: [Coroutine][Sema] Tighten the lifetime of symmetric transfer returned handle

2020-09-11 Thread Xun Li via Phabricator via cfe-commits
lxfind added a comment.

In D87470#2268911 , @rjmccall wrote:

> Thanks, LGTM.

Thank you for reviewing and the suggestions on testcase!


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D87470

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


[PATCH] D87470: [Coroutine][Sema] Tighten the lifetime of symmetric transfer returned handle

2020-09-11 Thread Xun Li via Phabricator via cfe-commits
This revision was landed with ongoing or failed builds.
This revision was automatically updated to reflect the committed changes.
Closed by commit rGdf477db5f9e0: [Coroutine][Sema] Tighten the lifetime of 
symmetric transfer returned handle (authored by lxfind).

Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D87470

Files:
  clang/lib/Sema/SemaCoroutine.cpp
  clang/test/CodeGenCoroutines/Inputs/coroutine.h
  clang/test/CodeGenCoroutines/coro-semmetric-transfer.cpp


Index: clang/test/CodeGenCoroutines/coro-semmetric-transfer.cpp
===
--- /dev/null
+++ clang/test/CodeGenCoroutines/coro-semmetric-transfer.cpp
@@ -0,0 +1,53 @@
+// RUN: %clang -std=c++14 -fcoroutines-ts -emit-llvm -S -O1 %s -o -
+
+#include "Inputs/coroutine.h"
+
+namespace coro = std::experimental::coroutines_v1;
+
+struct detached_task {
+  struct promise_type {
+detached_task get_return_object() noexcept {
+  return 
detached_task{coro::coroutine_handle::from_promise(*this)};
+}
+
+void return_void() noexcept {}
+
+struct final_awaiter {
+  bool await_ready() noexcept { return false; }
+  coro::coroutine_handle<> 
await_suspend(coro::coroutine_handle h) noexcept {
+h.destroy();
+return {};
+  }
+  void await_resume() noexcept {}
+};
+
+void unhandled_exception() noexcept {}
+
+final_awaiter final_suspend() noexcept { return {}; }
+
+coro::suspend_always initial_suspend() noexcept { return {}; }
+  };
+
+  ~detached_task() {
+if (coro_) {
+  coro_.destroy();
+  coro_ = {};
+}
+  }
+
+  void start() && {
+auto tmp = coro_;
+coro_ = {};
+tmp.resume();
+  }
+
+  coro::coroutine_handle coro_;
+};
+
+detached_task foo() {
+  co_return;
+}
+
+// check that the lifetime of the coroutine handle used to obtain the address 
ended right away.
+// CHECK:   %{{.*}} = call i8* 
@{{.*address.*}}(%"struct.std::experimental::coroutines_v1::coroutine_handle.0"*
 nonnull %{{.*}})
+// CHECK-NEXT:  call void @llvm.lifetime.end.p0i8(i64 8, i8* nonnull %{{.*}})
Index: clang/test/CodeGenCoroutines/Inputs/coroutine.h
===
--- clang/test/CodeGenCoroutines/Inputs/coroutine.h
+++ clang/test/CodeGenCoroutines/Inputs/coroutine.h
@@ -15,7 +15,7 @@
 return me;
   }
   void operator()() { resume(); }
-  void *address() const { return ptr; }
+  void *address() const noexcept { return ptr; }
   void resume() const { __builtin_coro_resume(ptr); }
   void destroy() const { __builtin_coro_destroy(ptr); }
   bool done() const { return __builtin_coro_done(ptr); }
Index: clang/lib/Sema/SemaCoroutine.cpp
===
--- clang/lib/Sema/SemaCoroutine.cpp
+++ clang/lib/Sema/SemaCoroutine.cpp
@@ -398,6 +398,10 @@
diag::warn_coroutine_handle_address_invalid_return_type)
 << JustAddress->getType();
 
+  // The coroutine handle used to obtain the address is no longer needed
+  // at this point, clean it up to avoid unnecessarily long lifetime which
+  // could lead to unnecessary spilling.
+  JustAddress = S.MaybeCreateExprWithCleanups(JustAddress);
   return buildBuiltinCall(S, Loc, Builtin::BI__builtin_coro_resume,
   JustAddress);
 }


Index: clang/test/CodeGenCoroutines/coro-semmetric-transfer.cpp
===
--- /dev/null
+++ clang/test/CodeGenCoroutines/coro-semmetric-transfer.cpp
@@ -0,0 +1,53 @@
+// RUN: %clang -std=c++14 -fcoroutines-ts -emit-llvm -S -O1 %s -o -
+
+#include "Inputs/coroutine.h"
+
+namespace coro = std::experimental::coroutines_v1;
+
+struct detached_task {
+  struct promise_type {
+detached_task get_return_object() noexcept {
+  return detached_task{coro::coroutine_handle::from_promise(*this)};
+}
+
+void return_void() noexcept {}
+
+struct final_awaiter {
+  bool await_ready() noexcept { return false; }
+  coro::coroutine_handle<> await_suspend(coro::coroutine_handle h) noexcept {
+h.destroy();
+return {};
+  }
+  void await_resume() noexcept {}
+};
+
+void unhandled_exception() noexcept {}
+
+final_awaiter final_suspend() noexcept { return {}; }
+
+coro::suspend_always initial_suspend() noexcept { return {}; }
+  };
+
+  ~detached_task() {
+if (coro_) {
+  coro_.destroy();
+  coro_ = {};
+}
+  }
+
+  void start() && {
+auto tmp = coro_;
+coro_ = {};
+tmp.resume();
+  }
+
+  coro::coroutine_handle coro_;
+};
+
+detached_task foo() {
+  co_return;
+}
+
+// check that the lifetime of the coroutine handle used to obtain the address ended right away.
+// CHECK:   %{{.*}} = call i8* @{{.*address.*}}(%"struct.std::experimental::coroutines_v1::coroutine_handle.0"* nonnull %{{.*}})
+// CHECK-NEXT:  call void @ll

[PATCH] D87470: [Coroutine][Sema] Tighten the lifetime of symmetric transfer returned handle

2020-09-15 Thread Xun Li via Phabricator via cfe-commits
lxfind added a comment.

In D87470#2273310 , @junparser wrote:

> @lxfind , could you backport this to branch 11?

I am actually seeing some problems with this change. Still investigating.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D87470

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


[PATCH] D87470: [Coroutine][Sema] Tighten the lifetime of symmetric transfer returned handle

2020-09-10 Thread Xun Li via Phabricator via cfe-commits
lxfind created this revision.
lxfind added reviewers: lewissbaker, wenlei, hoy, bruno, junparser, rjmccall.
Herald added subscribers: cfe-commits, dexonsmith, modocache.
Herald added a project: clang.
lxfind requested review of this revision.

In generating the code for symmetric transfer, a temporary object is created to 
store the returned handle from await_suspend() call of the awaiter. Previously 
this temp won't be cleaned up until very later, which ends up causing this temp 
to be spilled to the heap. However, we know that this temp will no longer be 
needed after the coro_resume call. We can clean it up right after.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D87470

Files:
  clang/lib/Sema/SemaCoroutine.cpp


Index: clang/lib/Sema/SemaCoroutine.cpp
===
--- clang/lib/Sema/SemaCoroutine.cpp
+++ clang/lib/Sema/SemaCoroutine.cpp
@@ -398,8 +398,8 @@
diag::warn_coroutine_handle_address_invalid_return_type)
 << JustAddress->getType();
 
-  return buildBuiltinCall(S, Loc, Builtin::BI__builtin_coro_resume,
-  JustAddress);
+  return S.MaybeCreateExprWithCleanups(
+  buildBuiltinCall(S, Loc, Builtin::BI__builtin_coro_resume, JustAddress));
 }
 
 /// Build calls to await_ready, await_suspend, and await_resume for a co_await


Index: clang/lib/Sema/SemaCoroutine.cpp
===
--- clang/lib/Sema/SemaCoroutine.cpp
+++ clang/lib/Sema/SemaCoroutine.cpp
@@ -398,8 +398,8 @@
diag::warn_coroutine_handle_address_invalid_return_type)
 << JustAddress->getType();
 
-  return buildBuiltinCall(S, Loc, Builtin::BI__builtin_coro_resume,
-  JustAddress);
+  return S.MaybeCreateExprWithCleanups(
+  buildBuiltinCall(S, Loc, Builtin::BI__builtin_coro_resume, JustAddress));
 }
 
 /// Build calls to await_ready, await_suspend, and await_resume for a co_await
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D92661: [RFC] Fix TLS and Coroutine

2020-12-08 Thread Xun Li via Phabricator via cfe-commits
lxfind added inline comments.



Comment at: llvm/include/llvm/IR/Intrinsics.td:1309
+// Intrinsic to obtain the address of a thread_local variable.
+def int_threadlocal : Intrinsic<[llvm_ptr_ty], [llvm_ptr_ty]>;
+

hoy wrote:
> lxfind wrote:
> > hoy wrote:
> > > lxfind wrote:
> > > > hoy wrote:
> > > > > hoy wrote:
> > > > > > With the intrinsic, can TLS variable reference in the same 
> > > > > > coroutine or regular routine be DCE-ed anymore?
> > > > > Sorry, I meant CSE-ed.
> > > > Since the intrinsics does not have readnone attribute, it won't be 
> > > > CSE-ed before CoroSplit.
> > > > However after CoroSplit, it will be lowered back to the direct 
> > > > reference of the TLS, and will be CSE-ed by latter passes.
> > > > I can add a test function to demonstrate that too.
> > > Sounds good. Can you please point out what optimization passes CSE-ed tls 
> > > reference without this implementation? I'm wondering if those 
> > > optimizations can be postponed to after CoroSplit. 
> > To clarify, it wasn't just CSE that would merge the references of the same 
> > TLS.
> > For instance, without this patch, a reference to "tls_variable" will just 
> > be "@tls_variable". For code like this:
> > 
> >   @tls_variable = internal thread_local global i32 0, align 4
> > 
> >   define i32* @foo(){
> > ret i32* @tls_variable
> >   }
> >   
> >   define void @bar() {
> > %tls1 = call i32* @foo()
> > ..coro.suspend..
> > %tls2 = call i32* @foo()
> > %cond = icmp eq i32* %tls1, %tls2
> >   }
> > 
> > When foo() is inlined into bar(), all uses of %tls1 will be replaced with 
> > @tls_variable.
> Thanks for the explanation. I have a dumb question. Why isn't corosplit 
> placed at the very beginning of the pipeline?
The coroutine frame size is determined during CoroSplit. So if CoroSplit 
happens too early without any optimizations, the frame size will always be very 
big and there is no chance to optimize it.
This is indeed a fundamental trade-off. If CoroSplit happens much earlier then 
it will be immune to this kind of problem.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D92661

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


[PATCH] D92661: [RFC] Fix TLS and Coroutine

2020-12-09 Thread Xun Li via Phabricator via cfe-commits
lxfind updated this revision to Diff 310575.
lxfind added a comment.
Herald added subscribers: nikic, kerbowa, jvesely.

Fix all failing tests


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D92661

Files:
  clang/lib/CodeGen/CGExpr.cpp
  clang/lib/CodeGen/ItaniumCXXABI.cpp
  clang/test/CodeGen/lto-newpm-pipeline.c
  clang/test/CodeGenCXX/cxx2a-thread-local-constinit.cpp
  clang/test/CodeGenCoroutines/coro-tls.cpp
  llvm/include/llvm/IR/IRBuilder.h
  llvm/include/llvm/IR/Intrinsics.td
  llvm/include/llvm/InitializePasses.h
  llvm/include/llvm/Transforms/Scalar.h
  llvm/include/llvm/Transforms/Scalar/LowerThreadLocalIntrinsic.h
  llvm/lib/IR/IRBuilder.cpp
  llvm/lib/Passes/PassBuilder.cpp
  llvm/lib/Transforms/IPO/PassManagerBuilder.cpp
  llvm/lib/Transforms/Scalar/CMakeLists.txt
  llvm/lib/Transforms/Scalar/LowerThreadLocalIntrinsic.cpp
  llvm/test/CodeGen/AMDGPU/opt-pipeline.ll
  llvm/test/Other/new-pass-manager.ll
  llvm/test/Other/new-pm-O0-defaults.ll
  llvm/test/Other/new-pm-defaults.ll
  llvm/test/Other/opt-O2-pipeline.ll
  llvm/test/Other/opt-O3-pipeline-enable-matrix.ll
  llvm/test/Other/opt-O3-pipeline.ll
  llvm/test/Other/opt-Os-pipeline.ll
  llvm/test/Other/pass-pipelines.ll

Index: llvm/test/Other/pass-pipelines.ll
===
--- llvm/test/Other/pass-pipelines.ll
+++ llvm/test/Other/pass-pipelines.ll
@@ -72,6 +72,7 @@
 ; Next we break out of the main Function passes inside the CGSCC pipeline with
 ; a barrier pass.
 ; CHECK-O2: A No-Op Barrier Pass
+; CHECK-O2-NEXT: Lower ThreadLocal Intrinsics
 ; CHECK-O2-NEXT: Eliminate Available Externally
 ; Inferring function attribute should be right after the CGSCC pipeline, before
 ; any other optimizations/analyses.
Index: llvm/test/Other/opt-Os-pipeline.ll
===
--- llvm/test/Other/opt-Os-pipeline.ll
+++ llvm/test/Other/opt-Os-pipeline.ll
@@ -173,6 +173,7 @@
 ; CHECK-NEXT: Optimization Remark Emitter
 ; CHECK-NEXT: Combine redundant instructions
 ; CHECK-NEXT: A No-Op Barrier Pass
+; CHECK-NEXT: Lower ThreadLocal Intrinsics
 ; CHECK-NEXT: Eliminate Available Externally Globals
 ; CHECK-NEXT: CallGraph Construction
 ; CHECK-NEXT: Deduce function attributes in RPO
Index: llvm/test/Other/opt-O3-pipeline.ll
===
--- llvm/test/Other/opt-O3-pipeline.ll
+++ llvm/test/Other/opt-O3-pipeline.ll
@@ -192,6 +192,7 @@
 ; CHECK-NEXT: Optimization Remark Emitter
 ; CHECK-NEXT: Combine redundant instructions
 ; CHECK-NEXT: A No-Op Barrier Pass
+; CHECK-NEXT: Lower ThreadLocal Intrinsics
 ; CHECK-NEXT: Eliminate Available Externally Globals
 ; CHECK-NEXT: CallGraph Construction
 ; CHECK-NEXT: Deduce function attributes in RPO
Index: llvm/test/Other/opt-O3-pipeline-enable-matrix.ll
===
--- llvm/test/Other/opt-O3-pipeline-enable-matrix.ll
+++ llvm/test/Other/opt-O3-pipeline-enable-matrix.ll
@@ -192,6 +192,7 @@
 ; CHECK-NEXT: Optimization Remark Emitter
 ; CHECK-NEXT: Combine redundant instructions
 ; CHECK-NEXT: A No-Op Barrier Pass
+; CHECK-NEXT: Lower ThreadLocal Intrinsics
 ; CHECK-NEXT: Eliminate Available Externally Globals
 ; CHECK-NEXT: CallGraph Construction
 ; CHECK-NEXT: Deduce function attributes in RPO
Index: llvm/test/Other/opt-O2-pipeline.ll
===
--- llvm/test/Other/opt-O2-pipeline.ll
+++ llvm/test/Other/opt-O2-pipeline.ll
@@ -187,6 +187,7 @@
 ; CHECK-NEXT: Optimization Remark Emitter
 ; CHECK-NEXT: Combine redundant instructions
 ; CHECK-NEXT: A No-Op Barrier Pass
+; CHECK-NEXT: Lower ThreadLocal Intrinsics
 ; CHECK-NEXT: Eliminate Available Externally Globals
 ; CHECK-NEXT: CallGraph Construction
 ; CHECK-NEXT: Deduce function attributes in RPO
Index: llvm/test/Other/new-pm-defaults.ll
===
--- llvm/test/Other/new-pm-defaults.ll
+++ llvm/test/Other/new-pm-defaults.ll
@@ -209,6 +209,7 @@
 ; CHECK-EP-CGSCC-LATE-NEXT: Running pass: NoOpCGSCCPass
 ; CHECK-O-NEXT: Finished CGSCC pass manager run.
 ; CHECK-O-NEXT: Finished llvm::Module pass manager run.
+; CHECK-O-NEXT: Running pass: LowerThreadLocalIntrinsicPass
 ; CHECK-O-NEXT: Running pass: GlobalOptPass
 ; CHECK-O-NEXT: Running pass: GlobalDCEPass
 ; CHECK-DEFAULT-NEXT: Running pass: EliminateAvailableExternallyPass
Index: llvm/test/Other/new-pm-O0-defaults.ll
===
--- llvm/test/Other/new-pm-O0-defaults.ll
+++ llvm/test/Other/new-pm-O0-defaults.ll
@@ -32,6 +32,7 @@
 ; CHECK-DEFAULT-NEXT: Running analysis: ProfileSummaryAnalysis
 ; CHECK-MATRIX-NEXT: Running

[PATCH] D92662: [Clang][Coroutine] Drop const attribute on pthread_self when coroutine is enabled

2020-12-09 Thread Xun Li via Phabricator via cfe-commits
lxfind updated this revision to Diff 310599.
lxfind added a comment.

Fix test


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D92662

Files:
  clang/lib/Sema/SemaDecl.cpp
  clang/test/CodeGenCoroutines/coro-pthread_self.cpp


Index: clang/test/CodeGenCoroutines/coro-pthread_self.cpp
===
--- /dev/null
+++ clang/test/CodeGenCoroutines/coro-pthread_self.cpp
@@ -0,0 +1,56 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fcoroutines-ts -std=c++14 
-O3 -emit-llvm %s -o - | FileCheck %s
+
+#include "Inputs/coroutine.h"
+
+namespace coro = std::experimental::coroutines_v1;
+
+typedef void *pthread_t;
+pthread_t pthread_self(void) __attribute__((__const__));
+
+struct awaitable {
+  bool await_ready() { return false; }
+  void await_suspend(coro::coroutine_handle<> h);
+  void await_resume() {}
+};
+awaitable switch_to_new_thread();
+
+struct task {
+  struct promise_type {
+task get_return_object() { return {}; }
+coro::suspend_never initial_suspend() { return {}; }
+coro::suspend_never final_suspend() noexcept { return {}; }
+void return_void() {}
+void unhandled_exception() {}
+  };
+};
+
+void check(pthread_t p1, pthread_t p2);
+
+task resuming_on_new_thread() {
+  auto pthread1 = pthread_self();
+  co_await switch_to_new_thread();
+  auto pthread2 = pthread_self();
+  check(pthread1, pthread2);
+}
+
+void non_coroutine() {
+  auto pthread1 = pthread_self();
+  check(pthread1, pthread1);
+  auto pthread2 = pthread_self();
+  check(pthread1, pthread2);
+}
+
+// CHECK-LABEL: define void @_Z13non_coroutinev()
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:%call = tail call i8* @_Z12pthread_selfv()
+// CHECK-NEXT:tail call void @_Z5checkPvS_(i8* %call, i8* %call)
+// CHECK-NEXT:%call1 = tail call i8* @_Z12pthread_selfv()
+// CHECK-NEXT:tail call void @_Z5checkPvS_(i8* %call, i8* %call1)
+// CHECK-NEXT:ret void
+// CHECK-NEXT:  }
+
+// CHECK-LABEL: define internal fastcc void @_Z22resuming_on_new_threadv.resume
+// CHECK: %[[RELOAD_ADDR:.+.reload.addr]] = getelementptr inbounds 
%_Z22resuming_on_new_threadv.Frame, %_Z22resuming_on_new_threadv.Frame* 
%FramePtr, i64 0, i32 {{.+}}
+// CHECK: %[[RELOAD:.+]] = load i8*, i8** %[[RELOAD_ADDR]], align 8
+// CHECK: %[[CALL:.+]] = tail call i8* @_Z12pthread_selfv()
+// CHECK: tail call void @_Z5checkPvS_(i8* %[[RELOAD]], i8* %[[CALL]])
Index: clang/lib/Sema/SemaDecl.cpp
===
--- clang/lib/Sema/SemaDecl.cpp
+++ clang/lib/Sema/SemaDecl.cpp
@@ -14962,6 +14962,12 @@
   IdentifierInfo *Name = FD->getIdentifier();
   if (!Name)
 return;
+
+  if (getLangOpts().Coroutines && Name->isStr("pthread_self") &&
+  FD->hasAttr()) {
+FD->dropAttr();
+  }
+
   if ((!getLangOpts().CPlusPlus &&
FD->getDeclContext()->isTranslationUnit()) ||
   (isa(FD->getDeclContext()) &&


Index: clang/test/CodeGenCoroutines/coro-pthread_self.cpp
===
--- /dev/null
+++ clang/test/CodeGenCoroutines/coro-pthread_self.cpp
@@ -0,0 +1,56 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fcoroutines-ts -std=c++14 -O3 -emit-llvm %s -o - | FileCheck %s
+
+#include "Inputs/coroutine.h"
+
+namespace coro = std::experimental::coroutines_v1;
+
+typedef void *pthread_t;
+pthread_t pthread_self(void) __attribute__((__const__));
+
+struct awaitable {
+  bool await_ready() { return false; }
+  void await_suspend(coro::coroutine_handle<> h);
+  void await_resume() {}
+};
+awaitable switch_to_new_thread();
+
+struct task {
+  struct promise_type {
+task get_return_object() { return {}; }
+coro::suspend_never initial_suspend() { return {}; }
+coro::suspend_never final_suspend() noexcept { return {}; }
+void return_void() {}
+void unhandled_exception() {}
+  };
+};
+
+void check(pthread_t p1, pthread_t p2);
+
+task resuming_on_new_thread() {
+  auto pthread1 = pthread_self();
+  co_await switch_to_new_thread();
+  auto pthread2 = pthread_self();
+  check(pthread1, pthread2);
+}
+
+void non_coroutine() {
+  auto pthread1 = pthread_self();
+  check(pthread1, pthread1);
+  auto pthread2 = pthread_self();
+  check(pthread1, pthread2);
+}
+
+// CHECK-LABEL: define void @_Z13non_coroutinev()
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:%call = tail call i8* @_Z12pthread_selfv()
+// CHECK-NEXT:tail call void @_Z5checkPvS_(i8* %call, i8* %call)
+// CHECK-NEXT:%call1 = tail call i8* @_Z12pthread_selfv()
+// CHECK-NEXT:tail call void @_Z5checkPvS_(i8* %call, i8* %call1)
+// CHECK-NEXT:ret void
+// CHECK-NEXT:  }
+
+// CHECK-LABEL: define internal fastcc void @_Z22resuming_on_new_threadv.resume
+// CHECK: %[[RELOAD_ADDR:.+.reload.addr]] = getelementptr inbounds %_Z22resuming_on_new_threadv.Frame, %_Z22resuming_on_new_threadv.Fr

[PATCH] D92662: [Clang][Coroutine] Drop const attribute on pthread_self when coroutine is enabled

2020-12-09 Thread Xun Li via Phabricator via cfe-commits
lxfind added a comment.

In D92662#2443970 , @MaskRay wrote:

> If the attribute is not suitable, glibc should drop it. The compiler can add 
> `readnone`/`readonly` if appropriate.

It's a C library interface though, and Coroutine is likely too new for this. I 
think that in the long run when Coroutine is pervasive we probably should drop 
it, but for now it's likely going to be hard for the glibc community to 
consider dropping it.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D92662

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


[PATCH] D92662: [Clang][Coroutine] Drop const attribute on pthread_self when coroutine is enabled

2020-12-10 Thread Xun Li via Phabricator via cfe-commits
lxfind added a comment.

In D92662#2446777 , @jyknight wrote:

> I don't think we should change the meaning of `__attribute__((const))` to 
> exclude depending on thread-id.
>
> However, if we do want to do so, and call the existing uses of 
> `__attribute__((const))` in glibc invalid, we need to special case many more 
> functions. Looking through it a little, I see `__errno_location`, 
> `__rpc_thread_variables`, `__ctype_b_loc`, `__ctype_tolower_loc`, 
> `__ctype_toupper_loc`, `__libc_tsd_address`...and I gave up looking after 
> that.

Thanks for pointing it out. I didn't realize there are so many of them.
Your proposals in the llvm-dev thread sound very promising. Let me think them 
over.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D92662

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


[PATCH] D90990: [Coroutine][Sema] Cleanup temporaries as early as possible

2020-11-06 Thread Xun Li via Phabricator via cfe-commits
lxfind created this revision.
Herald added subscribers: cfe-commits, modimo, wenlei, modocache.
Herald added a project: clang.
lxfind requested review of this revision.

The original bug was discovered in T75057860. Clang front-end emits an AST that 
looks like this for an co_await expression:

| - ExprWithCleanups  |
| - -CoawaitExpr  |
| - -MaterializeTemporaryExpr ... Awaiter |
|

...
  |- -CXXMemberCallExpr ... .await_ready
...
  |- -CallExpr ... __builtin_coro_resume
...
  |- -CXXMemberCallExpr ... .await_resume
...

ExprWithCleanups is responsible for cleaning up (including calling dtors) for 
the temporaries generated in the wrapping expression).
In the above structure, the __builtin_coro_resume part (which corresponds to 
the code for the suspend case in the co_await with symmetric transfer), the 
pseudocode looks like this:

  __builtin_coro_resume(
   awaiter.await_suspend(
 from_address(
   __builtin_coro_frame())).address());

One of the temporaries that's generated as part of this code is the coroutine 
handle returned from awaiter.await_suspend() call. The call returns a handle  
which is a prvalue (since it's a returned value on the fly). In order to call 
the address() method on it, it needs to be converted into an xvalue. Hence a 
materialized temp is created to hold it. This temp will need to be cleaned up 
eventually. Now, since all cleanups happen at the end of the entire co_await 
expression, which is after the  suspension point, the compiler 
will think that such a temp needs to live across suspensions, and need to be 
put on the coroutine frame, even though it's only used temporarily just to call 
address() method.
Such a phenomena not only unnecessarily increases the frame size, but can lead 
to ASAN failures, if the coroutine was already destroyed as part of the 
await_suspend() call. This is because if the coroutine was already destroyed, 
the frame no longer exists, and one can not store anything into it. But if the 
temporary object is considered to need to live on the frame, it will be stored 
into the frame after await_suspend() returns.

A fix attempt was done in https://reviews.llvm.org/D87470. Unfortunately it is 
incorrect. The reason is that cleanups in Clang works more like linearly than 
nested. There is one current state indicating whether it needs cleanup, and an 
ExprWithCleanups resets that state. This means that an ExprWithCleanups must be 
capable of cleaning up all temporaries created  in the wrapping expression, 
otherwise there will be dangling temporaries cleaned up at the wrong place.
I eventually found a walk-around (https://reviews.llvm.org/D89066) that doesn't 
break any existing tests while fixing the issue. But it targets the final 
co_await only. If we ever have a co_await that's not on the final awaiter and 
the frame gets destroyed after suspend, we are in trouble. Hence we need a 
proper fix.

This patch is the proper fix. It does the folllowing things to fully resolve 
the issue:

1. The AST has to be generated in the order according to their nesting 
relationship. We should not generate AST out of order because then the code 
generator would incorrectly track the state of temporaries and when a cleanup 
is needed. So the code in buildCoawaitCalls is reorganized so that we will be 
generating the AST for each coawait member call in order along with their child 
AST.
2. await_ready() call is wrapped with an ExprWithCleanups so that temporaries 
in it gets cleaned up as early as possible to avoid living across suspension.
3. await_suspend() call is wrapped with an ExprWithCleanups if it's not a 
symmetric transfer. In the case of a symmetric transfer, in order to maintain 
the musttail call contract, the ExprWithCleanups is wraaped before the resume 
call.
4. In the end, we mark again that it needs a cleanup, so that the entire 
CoawaitExpr will be wrapped with a ExprWithCleanups which will clean up the 
Awaiter object associated with the await expression.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D90990

Files:
  clang/lib/Sema/SemaCoroutine.cpp
  clang/test/CodeGenCoroutines/coro-symmetric-transfer-01.cpp
  clang/test/CodeGenCoroutines/coro-symmetric-transfer-02.cpp
  clang/test/CodeGenCoroutines/coro-symmetric-transfer.cpp

Index: clang/test/CodeGenCoroutines/coro-symmetric-transfer-02.cpp
===
--- /dev/null
+++ clang/test/CodeGenCoroutines/coro-symmetric-transfer-02.cpp
@@ -0,0 +1,126 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fcoroutines-ts -std=c++14 -O1 -emit-llvm %s -o - -disable-llvm-passes | FileCheck %s
+
+#include "Inputs/coroutine.h"
+
+namespace coro = std::experimental::coroutines_v1;
+
+struct Task {
+  struct promise_type {
+Task get_return_object() noexcept {
+  return Task{coro::coroutine_handle::from_promise(*this)};
+}
+
+void return_void() noexcept

[PATCH] D90990: [Coroutine][Sema] Cleanup temporaries as early as possible

2020-11-10 Thread Xun Li via Phabricator via cfe-commits
lxfind added inline comments.



Comment at: clang/lib/Sema/SemaCoroutine.cpp:475
+  if (!AwaitSuspend)
+return Calls;
   if (!AwaitSuspend->getType()->isDependentType()) {

bruno wrote:
> In case `AwaitSuspend` is null, is there any need to set `Calls.IsInvalid` as 
> well?
Thanks for the catch.



Comment at: clang/lib/Sema/SemaCoroutine.cpp:490
+  // ExprWithCleanups is wrapped within maybeTailCall() prior to the resume
+  // call.
   Calls.Results[ACT::ACT_Suspend] = TailCallSuspend;

bruno wrote:
> Is there already a test covering this tailcall case? It'd be nice to have one 
Yes both of the symmetric-transfer tests are covering this case.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D90990

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


[PATCH] D90990: [Coroutine][Sema] Cleanup temporaries as early as possible

2020-11-10 Thread Xun Li via Phabricator via cfe-commits
lxfind added inline comments.



Comment at: clang/lib/Sema/SemaCoroutine.cpp:475
+  if (!AwaitSuspend)
+return Calls;
   if (!AwaitSuspend->getType()->isDependentType()) {

lxfind wrote:
> bruno wrote:
> > In case `AwaitSuspend` is null, is there any need to set `Calls.IsInvalid` 
> > as well?
> Thanks for the catch.
Oh actually this is already set in BuildSubExpr.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D90990

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


[PATCH] D90990: [Coroutine][Sema] Cleanup temporaries as early as possible

2020-11-10 Thread Xun Li via Phabricator via cfe-commits
lxfind updated this revision to Diff 304233.
lxfind added a comment.

Add AST test


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D90990

Files:
  clang/lib/Sema/SemaCoroutine.cpp
  clang/test/AST/Inputs/std-coroutine.h
  clang/test/AST/coroutine-locals-cleanup.cpp
  clang/test/CodeGenCoroutines/coro-symmetric-transfer-01.cpp
  clang/test/CodeGenCoroutines/coro-symmetric-transfer-02.cpp
  clang/test/CodeGenCoroutines/coro-symmetric-transfer.cpp

Index: clang/test/CodeGenCoroutines/coro-symmetric-transfer-02.cpp
===
--- /dev/null
+++ clang/test/CodeGenCoroutines/coro-symmetric-transfer-02.cpp
@@ -0,0 +1,126 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fcoroutines-ts -std=c++14 -O1 -emit-llvm %s -o - -disable-llvm-passes | FileCheck %s
+
+#include "Inputs/coroutine.h"
+
+namespace coro = std::experimental::coroutines_v1;
+
+struct Task {
+  struct promise_type {
+Task get_return_object() noexcept {
+  return Task{coro::coroutine_handle::from_promise(*this)};
+}
+
+void return_void() noexcept {}
+
+struct final_awaiter {
+  bool await_ready() noexcept { return false; }
+  coro::coroutine_handle<> await_suspend(coro::coroutine_handle h) noexcept {
+h.destroy();
+return {};
+  }
+  void await_resume() noexcept {}
+};
+
+void unhandled_exception() noexcept {}
+
+final_awaiter final_suspend() noexcept { return {}; }
+
+coro::suspend_always initial_suspend() noexcept { return {}; }
+
+template 
+auto await_transform(Awaitable &&awaitable) {
+  return awaitable.co_viaIfAsync();
+}
+  };
+
+  using handle_t = coro::coroutine_handle;
+
+  class Awaiter {
+  public:
+explicit Awaiter(handle_t coro) noexcept;
+Awaiter(Awaiter &&other) noexcept;
+Awaiter(const Awaiter &) = delete;
+~Awaiter();
+
+bool await_ready() noexcept { return false; }
+handle_t await_suspend(coro::coroutine_handle<> continuation) noexcept;
+void await_resume();
+
+  private:
+handle_t coro_;
+  };
+
+  Task(handle_t coro) noexcept : coro_(coro) {}
+
+  handle_t coro_;
+
+  Task(const Task &t) = delete;
+  Task(Task &&t) noexcept;
+  ~Task();
+  Task &operator=(Task t) noexcept;
+
+  Awaiter co_viaIfAsync();
+};
+
+static Task foo() {
+  co_return;
+}
+
+Task bar() {
+  auto mode = 2;
+  switch (mode) {
+  case 1:
+co_await foo();
+break;
+  case 2:
+co_await foo();
+break;
+  default:
+break;
+  }
+}
+
+// CHECK-LABEL: define void @_Z3barv
+// CHECK: %[[MODE:.+]] = load i32, i32* %mode
+// CHECK-NEXT:switch i32 %[[MODE]], label %{{.+}} [
+// CHECK-NEXT:  i32 1, label %[[CASE1:.+]]
+// CHECK-NEXT:  i32 2, label %[[CASE2:.+]]
+// CHECK-NEXT:]
+
+// CHECK:   [[CASE1]]:
+// CHECK: br i1 %{{.+}}, label %[[CASE1_AWAIT_READY:.+]], label %[[CASE1_AWAIT_SUSPEND:.+]]
+// CHECK:   [[CASE1_AWAIT_SUSPEND]]:
+// CHECK-NEXT:%{{.+}} = call token @llvm.coro.save(i8* null)
+// CHECK-NEXT:%[[HANDLE11:.+]] = bitcast %"struct.std::experimental::coroutines_v1::coroutine_handle"* %[[TMP1:.+]] to i8*
+// CHECK-NEXT:call void @llvm.lifetime.start.p0i8(i64 8, i8* %[[HANDLE11]])
+
+// CHECK: %[[HANDLE12:.+]] = bitcast %"struct.std::experimental::coroutines_v1::coroutine_handle"* %[[TMP1]] to i8*
+// CHECK-NEXT:call void @llvm.lifetime.end.p0i8(i64 8, i8* %[[HANDLE12]])
+// CHECK-NEXT:call void @llvm.coro.resume
+// CHECK-NEXT:%{{.+}} = call i8 @llvm.coro.suspend
+// CHECK-NEXT:switch i8 %{{.+}}, label %coro.ret [
+// CHECK-NEXT:  i8 0, label %[[CASE1_AWAIT_READY]]
+// CHECK-NEXT:  i8 1, label %[[CASE1_AWAIT_CLEANUP:.+]]
+// CHECK-NEXT:]
+// CHECK:   [[CASE1_AWAIT_CLEANUP]]:
+// make sure that the awaiter eventually gets cleaned up.
+// CHECK: call void @{{.+Awaiter.+}}
+
+// CHECK:   [[CASE2]]:
+// CHECK: br i1 %{{.+}}, label %[[CASE2_AWAIT_READY:.+]], label %[[CASE2_AWAIT_SUSPEND:.+]]
+// CHECK:   [[CASE2_AWAIT_SUSPEND]]:
+// CHECK-NEXT:%{{.+}} = call token @llvm.coro.save(i8* null)
+// CHECK-NEXT:%[[HANDLE21:.+]] = bitcast %"struct.std::experimental::coroutines_v1::coroutine_handle"* %[[TMP2:.+]] to i8*
+// CHECK-NEXT:call void @llvm.lifetime.start.p0i8(i64 8, i8* %[[HANDLE21]])
+
+// CHECK: %[[HANDLE22:.+]] = bitcast %"struct.std::experimental::coroutines_v1::coroutine_handle"* %[[TMP2]] to i8*
+// CHECK-NEXT:call void @llvm.lifetime.end.p0i8(i64 8, i8* %[[HANDLE22]])
+// CHECK-NEXT:call void @llvm.coro.resume
+// CHECK-NEXT:%{{.+}} = call i8 @llvm.coro.suspend
+// CHECK-NEXT:switch i8 %{{.+}}, label %coro.ret [
+// CHECK-NEXT:  i8 0, label %[[CASE2_AWAIT_READY]]
+// CHECK-NEXT:  i8 1, label %[[CASE2_AWAIT_CLEANUP:.+]]
+// CHECK-NEXT:]
+// CHECK:   [[CASE2_AWAIT_CLEANUP]]:
+// make sure that the awaiter eventually

[PATCH] D90990: [Coroutine][Sema] Cleanup temporaries as early as possible

2020-11-10 Thread Xun Li via Phabricator via cfe-commits
This revision was landed with ongoing or failed builds.
This revision was automatically updated to reflect the committed changes.
Closed by commit rG19f077092343: [Coroutine][Sema] Cleanup temporaries as early 
as possible (authored by lxfind).

Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D90990

Files:
  clang/lib/Sema/SemaCoroutine.cpp
  clang/test/AST/Inputs/std-coroutine.h
  clang/test/AST/coroutine-locals-cleanup.cpp
  clang/test/CodeGenCoroutines/coro-symmetric-transfer-01.cpp
  clang/test/CodeGenCoroutines/coro-symmetric-transfer-02.cpp
  clang/test/CodeGenCoroutines/coro-symmetric-transfer.cpp

Index: clang/test/CodeGenCoroutines/coro-symmetric-transfer-02.cpp
===
--- /dev/null
+++ clang/test/CodeGenCoroutines/coro-symmetric-transfer-02.cpp
@@ -0,0 +1,126 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fcoroutines-ts -std=c++14 -O1 -emit-llvm %s -o - -disable-llvm-passes | FileCheck %s
+
+#include "Inputs/coroutine.h"
+
+namespace coro = std::experimental::coroutines_v1;
+
+struct Task {
+  struct promise_type {
+Task get_return_object() noexcept {
+  return Task{coro::coroutine_handle::from_promise(*this)};
+}
+
+void return_void() noexcept {}
+
+struct final_awaiter {
+  bool await_ready() noexcept { return false; }
+  coro::coroutine_handle<> await_suspend(coro::coroutine_handle h) noexcept {
+h.destroy();
+return {};
+  }
+  void await_resume() noexcept {}
+};
+
+void unhandled_exception() noexcept {}
+
+final_awaiter final_suspend() noexcept { return {}; }
+
+coro::suspend_always initial_suspend() noexcept { return {}; }
+
+template 
+auto await_transform(Awaitable &&awaitable) {
+  return awaitable.co_viaIfAsync();
+}
+  };
+
+  using handle_t = coro::coroutine_handle;
+
+  class Awaiter {
+  public:
+explicit Awaiter(handle_t coro) noexcept;
+Awaiter(Awaiter &&other) noexcept;
+Awaiter(const Awaiter &) = delete;
+~Awaiter();
+
+bool await_ready() noexcept { return false; }
+handle_t await_suspend(coro::coroutine_handle<> continuation) noexcept;
+void await_resume();
+
+  private:
+handle_t coro_;
+  };
+
+  Task(handle_t coro) noexcept : coro_(coro) {}
+
+  handle_t coro_;
+
+  Task(const Task &t) = delete;
+  Task(Task &&t) noexcept;
+  ~Task();
+  Task &operator=(Task t) noexcept;
+
+  Awaiter co_viaIfAsync();
+};
+
+static Task foo() {
+  co_return;
+}
+
+Task bar() {
+  auto mode = 2;
+  switch (mode) {
+  case 1:
+co_await foo();
+break;
+  case 2:
+co_await foo();
+break;
+  default:
+break;
+  }
+}
+
+// CHECK-LABEL: define void @_Z3barv
+// CHECK: %[[MODE:.+]] = load i32, i32* %mode
+// CHECK-NEXT:switch i32 %[[MODE]], label %{{.+}} [
+// CHECK-NEXT:  i32 1, label %[[CASE1:.+]]
+// CHECK-NEXT:  i32 2, label %[[CASE2:.+]]
+// CHECK-NEXT:]
+
+// CHECK:   [[CASE1]]:
+// CHECK: br i1 %{{.+}}, label %[[CASE1_AWAIT_READY:.+]], label %[[CASE1_AWAIT_SUSPEND:.+]]
+// CHECK:   [[CASE1_AWAIT_SUSPEND]]:
+// CHECK-NEXT:%{{.+}} = call token @llvm.coro.save(i8* null)
+// CHECK-NEXT:%[[HANDLE11:.+]] = bitcast %"struct.std::experimental::coroutines_v1::coroutine_handle"* %[[TMP1:.+]] to i8*
+// CHECK-NEXT:call void @llvm.lifetime.start.p0i8(i64 8, i8* %[[HANDLE11]])
+
+// CHECK: %[[HANDLE12:.+]] = bitcast %"struct.std::experimental::coroutines_v1::coroutine_handle"* %[[TMP1]] to i8*
+// CHECK-NEXT:call void @llvm.lifetime.end.p0i8(i64 8, i8* %[[HANDLE12]])
+// CHECK-NEXT:call void @llvm.coro.resume
+// CHECK-NEXT:%{{.+}} = call i8 @llvm.coro.suspend
+// CHECK-NEXT:switch i8 %{{.+}}, label %coro.ret [
+// CHECK-NEXT:  i8 0, label %[[CASE1_AWAIT_READY]]
+// CHECK-NEXT:  i8 1, label %[[CASE1_AWAIT_CLEANUP:.+]]
+// CHECK-NEXT:]
+// CHECK:   [[CASE1_AWAIT_CLEANUP]]:
+// make sure that the awaiter eventually gets cleaned up.
+// CHECK: call void @{{.+Awaiter.+}}
+
+// CHECK:   [[CASE2]]:
+// CHECK: br i1 %{{.+}}, label %[[CASE2_AWAIT_READY:.+]], label %[[CASE2_AWAIT_SUSPEND:.+]]
+// CHECK:   [[CASE2_AWAIT_SUSPEND]]:
+// CHECK-NEXT:%{{.+}} = call token @llvm.coro.save(i8* null)
+// CHECK-NEXT:%[[HANDLE21:.+]] = bitcast %"struct.std::experimental::coroutines_v1::coroutine_handle"* %[[TMP2:.+]] to i8*
+// CHECK-NEXT:call void @llvm.lifetime.start.p0i8(i64 8, i8* %[[HANDLE21]])
+
+// CHECK: %[[HANDLE22:.+]] = bitcast %"struct.std::experimental::coroutines_v1::coroutine_handle"* %[[TMP2]] to i8*
+// CHECK-NEXT:call void @llvm.lifetime.end.p0i8(i64 8, i8* %[[HANDLE22]])
+// CHECK-NEXT:call void @llvm.coro.resume
+// CHECK-NEXT:%{{.+}} = call i8 @llvm.coro.suspend
+// CHECK-NEXT:switch i8 %{{.+}}, label %coro.ret [
+// CHECK-NEXT:  i8 0, label %[[CASE2_AWAIT_READY]]
+// 

[PATCH] D86853: [modules] Fix crash in call to `FunctionDecl::setPure()`

2020-11-18 Thread Xun Li via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rGc6c8d4a13ebd: [modules] Fix crash in call to 
`FunctionDecl::setPure()` (authored by andrewjcg, committed by lxfind).

Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D86853

Files:
  clang/lib/Serialization/ASTReaderDecl.cpp
  clang/test/Modules/Inputs/set-pure-crash/a.h
  clang/test/Modules/Inputs/set-pure-crash/b.h
  clang/test/Modules/Inputs/set-pure-crash/c.h
  clang/test/Modules/Inputs/set-pure-crash/module.modulemap
  clang/test/Modules/set-pure-crash.cpp

Index: clang/test/Modules/set-pure-crash.cpp
===
--- /dev/null
+++ clang/test/Modules/set-pure-crash.cpp
@@ -0,0 +1,9 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -fsyntax-only -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -x c++ -I %S/Inputs/set-pure-crash -verify %s -o %t
+
+// expected-no-diagnostics
+
+#include "b.h"
+#include "c.h"
+
+auto t = simple();
Index: clang/test/Modules/Inputs/set-pure-crash/module.modulemap
===
--- /dev/null
+++ clang/test/Modules/Inputs/set-pure-crash/module.modulemap
@@ -0,0 +1,11 @@
+module a {
+  header "a.h"
+}
+
+module b {
+  header "b.h"
+}
+
+module c {
+  header "c.h"
+}
Index: clang/test/Modules/Inputs/set-pure-crash/c.h
===
--- /dev/null
+++ clang/test/Modules/Inputs/set-pure-crash/c.h
@@ -0,0 +1,5 @@
+#pragma once
+
+template 
+struct simple {
+};
Index: clang/test/Modules/Inputs/set-pure-crash/b.h
===
--- /dev/null
+++ clang/test/Modules/Inputs/set-pure-crash/b.h
@@ -0,0 +1,14 @@
+#pragma once
+
+#include "a.h"
+#include "c.h"
+
+template >
+void foo(Fun) {}
+
+class Child : public Base {
+public:
+  void func() {
+foo([]() {});
+  }
+};
Index: clang/test/Modules/Inputs/set-pure-crash/a.h
===
--- /dev/null
+++ clang/test/Modules/Inputs/set-pure-crash/a.h
@@ -0,0 +1,11 @@
+#pragma once
+
+struct Tag {};
+
+template 
+class Base {
+public:
+  virtual void func() = 0;
+};
+
+Base bar();
Index: clang/lib/Serialization/ASTReaderDecl.cpp
===
--- clang/lib/Serialization/ASTReaderDecl.cpp
+++ clang/lib/Serialization/ASTReaderDecl.cpp
@@ -868,7 +868,10 @@
   FD->setInlineSpecified(Record.readInt());
   FD->setImplicitlyInline(Record.readInt());
   FD->setVirtualAsWritten(Record.readInt());
-  FD->setPure(Record.readInt());
+  // We defer calling `FunctionDecl::setPure()` here as for methods of
+  // `CXXTemplateSpecializationDecl`s, we may not have connected up the
+  // definition (which is required for `setPure`).
+  const bool Pure = Record.readInt();
   FD->setHasInheritedPrototype(Record.readInt());
   FD->setHasWrittenPrototype(Record.readInt());
   FD->setDeletedAsWritten(Record.readInt());
@@ -1015,6 +1018,10 @@
   }
   }
 
+  // Defer calling `setPure` until merging above has guaranteed we've set
+  // `DefinitionData` (as this will need to access it).
+  FD->setPure(Pure);
+
   // Read in the parameters.
   unsigned NumParams = Record.readInt();
   SmallVector Params;
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D86853: [modules] Fix crash in call to `FunctionDecl::setPure()`

2020-11-18 Thread Xun Li via Phabricator via cfe-commits
lxfind added a comment.

@rsmith, @v.g.vassilev hey I stamped this patch assuming it looks ok. But 
definitely shout at me if more feedback needs to be addressed. Happy to follow 
up.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D86853

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


[PATCH] D89066: [Coroutine][Sema] Only tighten the suspend call temp lifetime for final awaiter

2020-10-08 Thread Xun Li via Phabricator via cfe-commits
lxfind created this revision.
lxfind added reviewers: lewissbaker, wenlei, bruno, junparser, rjmccall.
Herald added subscribers: cfe-commits, modimo, dexonsmith, modocache.
Herald added a project: clang.
lxfind requested review of this revision.

In https://reviews.llvm.org/D87470 I added the change to tighten the lifetime 
of the expression awaiter.await_suspend().address.
Howver it was incorrect. ExprWithCleanups will call the dtor and end the 
lifetime for all the temps created in the current full expr.
When this is called on a normal await call, we don't want to do that.
We only want to do this for the call on the final_awaiter, to avoid writing 
into the frame after the frame is destroyed.
This change fixes it, by checking IsImplicit.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D89066

Files:
  clang/lib/Sema/SemaCoroutine.cpp
  clang/test/CodeGenCoroutines/coro-semmetric-transfer.cpp


Index: clang/test/CodeGenCoroutines/coro-semmetric-transfer.cpp
===
--- clang/test/CodeGenCoroutines/coro-semmetric-transfer.cpp
+++ clang/test/CodeGenCoroutines/coro-semmetric-transfer.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang -std=c++14 -fcoroutines-ts -emit-llvm -S -O1 %s -o -
+// RUN: %clang -std=c++14 -fcoroutines-ts -emit-llvm -S -O1 %s -o - | 
FileCheck %s
 
 #include "Inputs/coroutine.h"
 
Index: clang/lib/Sema/SemaCoroutine.cpp
===
--- clang/lib/Sema/SemaCoroutine.cpp
+++ clang/lib/Sema/SemaCoroutine.cpp
@@ -375,7 +375,7 @@
 // returning await_suspend that results in a guaranteed tail call to the target
 // coroutine.
 static Expr *maybeTailCall(Sema &S, QualType RetType, Expr *E,
-   SourceLocation Loc) {
+   SourceLocation Loc, bool IsImplicit) {
   if (RetType->isReferenceType())
 return nullptr;
   Type const *T = RetType.getTypePtr();
@@ -398,10 +398,12 @@
diag::warn_coroutine_handle_address_invalid_return_type)
 << JustAddress->getType();
 
-  // The coroutine handle used to obtain the address is no longer needed
-  // at this point, clean it up to avoid unnecessarily long lifetime which
-  // could lead to unnecessary spilling.
-  JustAddress = S.MaybeCreateExprWithCleanups(JustAddress);
+  // After the suspend call on the final awaiter, the coroutine may have
+  // been destroyed. In that case, we can not store anything to the frame
+  // from this point on. Hence in the case of the final awaiter suspend
+  // call (indicated by IsImplciit), we wrap it immediately with a cleanup.
+  if (IsImplicit)
+JustAddress = S.MaybeCreateExprWithCleanups(JustAddress);
   return buildBuiltinCall(S, Loc, Builtin::BI__builtin_coro_resume,
   JustAddress);
 }
@@ -409,7 +411,8 @@
 /// Build calls to await_ready, await_suspend, and await_resume for a co_await
 /// expression.
 static ReadySuspendResumeResult buildCoawaitCalls(Sema &S, VarDecl 
*CoroPromise,
-  SourceLocation Loc, Expr *E) 
{
+  SourceLocation Loc, Expr *E,
+  bool IsImplicit) {
   OpaqueValueExpr *Operand = new (S.Context)
   OpaqueValueExpr(Loc, E->getType(), VK_LValue, E->getObjectKind(), E);
 
@@ -458,7 +461,8 @@
 QualType RetType = AwaitSuspend->getCallReturnType(S.Context);
 
 // Experimental support for coroutine_handle returning await_suspend.
-if (Expr *TailCallSuspend = maybeTailCall(S, RetType, AwaitSuspend, Loc))
+if (Expr *TailCallSuspend =
+maybeTailCall(S, RetType, AwaitSuspend, Loc, IsImplicit))
   Calls.Results[ACT::ACT_Suspend] = TailCallSuspend;
 else {
   // non-class prvalues always have cv-unqualified types
@@ -870,8 +874,8 @@
   SourceLocation CallLoc = E->getExprLoc();
 
   // Build the await_ready, await_suspend, await_resume calls.
-  ReadySuspendResumeResult RSS =
-  buildCoawaitCalls(*this, Coroutine->CoroutinePromise, CallLoc, E);
+  ReadySuspendResumeResult RSS = buildCoawaitCalls(
+  *this, Coroutine->CoroutinePromise, CallLoc, E, IsImplicit);
   if (RSS.IsInvalid)
 return ExprError();
 
@@ -925,8 +929,8 @@
 E = CreateMaterializeTemporaryExpr(E->getType(), E, true);
 
   // Build the await_ready, await_suspend, await_resume calls.
-  ReadySuspendResumeResult RSS =
-  buildCoawaitCalls(*this, Coroutine->CoroutinePromise, Loc, E);
+  ReadySuspendResumeResult RSS = buildCoawaitCalls(
+  *this, Coroutine->CoroutinePromise, Loc, E, /*IsImplicit*/ false);
   if (RSS.IsInvalid)
 return ExprError();
 


Index: clang/test/CodeGenCoroutines/coro-semmetric-transfer.cpp
===
--- clang/test/CodeGenCoroutines/coro-semmetric-transfer.cpp
+++ clang/test/CodeGenCoroutines/coro-semmetric-transfer.cpp
@@ -1,4 +1,4 @@
-// RUN: %cl

[PATCH] D89066: [Coroutine][Sema] Only tighten the suspend call temp lifetime for final awaiter

2020-10-11 Thread Xun Li via Phabricator via cfe-commits
lxfind added a comment.

In D89066#2324115 , @junparser wrote:

> why we should not do this with normal await call?

To be honest, I don't know yet. My understanding of how expression cleanup and 
temp lifetime management is insufficient at the moment.
But first of all, without adding any cleanup expression here, I saw ASAN 
failures due to heap-use-after-free, because sometimes the frame have already 
been destroyed after the await_suspend call, and yet we are still writing into 
the frame due to unnecessarily cross-suspend lifetime. However, if I apply the 
cleanup to all await_suepend calls, it also causes ASAN failures as it's 
cleaning up data that's still alive.
So this patch is more of a temporary walkaround to stop bleeding without 
causing any trouble.
I plan to get back to this latter after I am done with the spilling/alloca 
issues.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D89066

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


[PATCH] D89066: [Coroutine][Sema] Only tighten the suspend call temp lifetime for final awaiter

2020-10-12 Thread Xun Li via Phabricator via cfe-commits
lxfind added a comment.

In D89066#2324291 , @junparser wrote:

> In D89066#2324151 , @lxfind wrote:
>
>> In D89066#2324115 , @junparser 
>> wrote:
>>
>>> why we should not do this with normal await call?
>>
>> To be honest, I don't know yet. My understanding of how expression cleanup 
>> and temp lifetime management is insufficient at the moment.
>> But first of all, without adding any cleanup expression here, I saw ASAN 
>> failures due to heap-use-after-free, because sometimes the frame have 
>> already been destroyed after the await_suspend call, and yet we are still 
>> writing into the frame due to unnecessarily cross-suspend lifetime. However, 
>> if I apply the cleanup to all await_suepend calls, it also causes ASAN 
>> failures as it's cleaning up data that's still alive.
>> So this patch is more of a temporary walkaround to stop bleeding without 
>> causing any trouble.
>> I plan to get back to this latter after I am done with the spilling/alloca 
>> issues.
>
> I'm not familiar with ASAN instrumentation. Do you have any testcases to 
> explain this?

Unfortunately I don't.  But this is not related to ASAN. Basically, this is 
causing destructing of objects that should still be alive. I suspect that it's 
because ExprWithCleanups always clean up temps that belongs to the full 
expression, not just the sub-expression in it.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D89066

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


[PATCH] D89066: [Coroutine][Sema] Only tighten the suspend call temp lifetime for final awaiter

2020-10-12 Thread Xun Li via Phabricator via cfe-commits
lxfind updated this revision to Diff 297656.
lxfind added a comment.

Add more comments and TODO


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D89066

Files:
  clang/lib/Sema/SemaCoroutine.cpp
  clang/test/CodeGenCoroutines/coro-semmetric-transfer.cpp


Index: clang/test/CodeGenCoroutines/coro-semmetric-transfer.cpp
===
--- clang/test/CodeGenCoroutines/coro-semmetric-transfer.cpp
+++ clang/test/CodeGenCoroutines/coro-semmetric-transfer.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang -std=c++14 -fcoroutines-ts -emit-llvm -S -O1 %s -o -
+// RUN: %clang -std=c++14 -fcoroutines-ts -emit-llvm -S -O1 %s -o - | 
FileCheck %s
 
 #include "Inputs/coroutine.h"
 
Index: clang/lib/Sema/SemaCoroutine.cpp
===
--- clang/lib/Sema/SemaCoroutine.cpp
+++ clang/lib/Sema/SemaCoroutine.cpp
@@ -375,7 +375,7 @@
 // returning await_suspend that results in a guaranteed tail call to the target
 // coroutine.
 static Expr *maybeTailCall(Sema &S, QualType RetType, Expr *E,
-   SourceLocation Loc) {
+   SourceLocation Loc, bool IsImplicit) {
   if (RetType->isReferenceType())
 return nullptr;
   Type const *T = RetType.getTypePtr();
@@ -398,10 +398,17 @@
diag::warn_coroutine_handle_address_invalid_return_type)
 << JustAddress->getType();
 
-  // The coroutine handle used to obtain the address is no longer needed
-  // at this point, clean it up to avoid unnecessarily long lifetime which
-  // could lead to unnecessary spilling.
-  JustAddress = S.MaybeCreateExprWithCleanups(JustAddress);
+  // After the await_suspend call on the awaiter, the coroutine may have
+  // been destroyed. In that case, we can not store anything to the frame
+  // from this point on. Hence here we wrap it immediately with a cleanup. This
+  // could have applied to all await_suspend calls. However doing so causes
+  // alive objects being destructed for reasons that need further
+  // investigations. Here we walk-around it temporarily by only doing it after
+  // the suspend call on the final awaiter (indicated by IsImplicit) where it's
+  // most common to happen.
+  // TODO: Properly clean up the temps generated by await_suspend calls.
+  if (IsImplicit)
+JustAddress = S.MaybeCreateExprWithCleanups(JustAddress);
   return buildBuiltinCall(S, Loc, Builtin::BI__builtin_coro_resume,
   JustAddress);
 }
@@ -409,7 +416,8 @@
 /// Build calls to await_ready, await_suspend, and await_resume for a co_await
 /// expression.
 static ReadySuspendResumeResult buildCoawaitCalls(Sema &S, VarDecl 
*CoroPromise,
-  SourceLocation Loc, Expr *E) 
{
+  SourceLocation Loc, Expr *E,
+  bool IsImplicit) {
   OpaqueValueExpr *Operand = new (S.Context)
   OpaqueValueExpr(Loc, E->getType(), VK_LValue, E->getObjectKind(), E);
 
@@ -458,7 +466,8 @@
 QualType RetType = AwaitSuspend->getCallReturnType(S.Context);
 
 // Experimental support for coroutine_handle returning await_suspend.
-if (Expr *TailCallSuspend = maybeTailCall(S, RetType, AwaitSuspend, Loc))
+if (Expr *TailCallSuspend =
+maybeTailCall(S, RetType, AwaitSuspend, Loc, IsImplicit))
   Calls.Results[ACT::ACT_Suspend] = TailCallSuspend;
 else {
   // non-class prvalues always have cv-unqualified types
@@ -870,8 +879,8 @@
   SourceLocation CallLoc = E->getExprLoc();
 
   // Build the await_ready, await_suspend, await_resume calls.
-  ReadySuspendResumeResult RSS =
-  buildCoawaitCalls(*this, Coroutine->CoroutinePromise, CallLoc, E);
+  ReadySuspendResumeResult RSS = buildCoawaitCalls(
+  *this, Coroutine->CoroutinePromise, CallLoc, E, IsImplicit);
   if (RSS.IsInvalid)
 return ExprError();
 
@@ -925,8 +934,8 @@
 E = CreateMaterializeTemporaryExpr(E->getType(), E, true);
 
   // Build the await_ready, await_suspend, await_resume calls.
-  ReadySuspendResumeResult RSS =
-  buildCoawaitCalls(*this, Coroutine->CoroutinePromise, Loc, E);
+  ReadySuspendResumeResult RSS = buildCoawaitCalls(
+  *this, Coroutine->CoroutinePromise, Loc, E, /*IsImplicit*/ false);
   if (RSS.IsInvalid)
 return ExprError();
 


Index: clang/test/CodeGenCoroutines/coro-semmetric-transfer.cpp
===
--- clang/test/CodeGenCoroutines/coro-semmetric-transfer.cpp
+++ clang/test/CodeGenCoroutines/coro-semmetric-transfer.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang -std=c++14 -fcoroutines-ts -emit-llvm -S -O1 %s -o -
+// RUN: %clang -std=c++14 -fcoroutines-ts -emit-llvm -S -O1 %s -o - | FileCheck %s
 
 #include "Inputs/coroutine.h"
 
Index: clang/lib/Sema/SemaCoroutine.cpp

[PATCH] D89066: [Coroutine][Sema] Only tighten the suspend call temp lifetime for final awaiter

2020-10-12 Thread Xun Li via Phabricator via cfe-commits
This revision was landed with ongoing or failed builds.
This revision was automatically updated to reflect the committed changes.
Closed by commit rGdce8f2bb25ea: [Coroutine][Sema] Only tighten the suspend 
call temp lifetime for final awaiter (authored by lxfind).

Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D89066

Files:
  clang/lib/Sema/SemaCoroutine.cpp
  clang/test/CodeGenCoroutines/coro-semmetric-transfer.cpp


Index: clang/test/CodeGenCoroutines/coro-semmetric-transfer.cpp
===
--- clang/test/CodeGenCoroutines/coro-semmetric-transfer.cpp
+++ clang/test/CodeGenCoroutines/coro-semmetric-transfer.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang -std=c++14 -fcoroutines-ts -emit-llvm -S -O1 %s -o -
+// RUN: %clang -std=c++14 -fcoroutines-ts -emit-llvm -S -O1 %s -o - | 
FileCheck %s
 
 #include "Inputs/coroutine.h"
 
Index: clang/lib/Sema/SemaCoroutine.cpp
===
--- clang/lib/Sema/SemaCoroutine.cpp
+++ clang/lib/Sema/SemaCoroutine.cpp
@@ -375,7 +375,7 @@
 // returning await_suspend that results in a guaranteed tail call to the target
 // coroutine.
 static Expr *maybeTailCall(Sema &S, QualType RetType, Expr *E,
-   SourceLocation Loc) {
+   SourceLocation Loc, bool IsImplicit) {
   if (RetType->isReferenceType())
 return nullptr;
   Type const *T = RetType.getTypePtr();
@@ -398,10 +398,17 @@
diag::warn_coroutine_handle_address_invalid_return_type)
 << JustAddress->getType();
 
-  // The coroutine handle used to obtain the address is no longer needed
-  // at this point, clean it up to avoid unnecessarily long lifetime which
-  // could lead to unnecessary spilling.
-  JustAddress = S.MaybeCreateExprWithCleanups(JustAddress);
+  // After the await_suspend call on the awaiter, the coroutine may have
+  // been destroyed. In that case, we can not store anything to the frame
+  // from this point on. Hence here we wrap it immediately with a cleanup. This
+  // could have applied to all await_suspend calls. However doing so causes
+  // alive objects being destructed for reasons that need further
+  // investigations. Here we walk-around it temporarily by only doing it after
+  // the suspend call on the final awaiter (indicated by IsImplicit) where it's
+  // most common to happen.
+  // TODO: Properly clean up the temps generated by await_suspend calls.
+  if (IsImplicit)
+JustAddress = S.MaybeCreateExprWithCleanups(JustAddress);
   return buildBuiltinCall(S, Loc, Builtin::BI__builtin_coro_resume,
   JustAddress);
 }
@@ -409,7 +416,8 @@
 /// Build calls to await_ready, await_suspend, and await_resume for a co_await
 /// expression.
 static ReadySuspendResumeResult buildCoawaitCalls(Sema &S, VarDecl 
*CoroPromise,
-  SourceLocation Loc, Expr *E) 
{
+  SourceLocation Loc, Expr *E,
+  bool IsImplicit) {
   OpaqueValueExpr *Operand = new (S.Context)
   OpaqueValueExpr(Loc, E->getType(), VK_LValue, E->getObjectKind(), E);
 
@@ -458,7 +466,8 @@
 QualType RetType = AwaitSuspend->getCallReturnType(S.Context);
 
 // Experimental support for coroutine_handle returning await_suspend.
-if (Expr *TailCallSuspend = maybeTailCall(S, RetType, AwaitSuspend, Loc))
+if (Expr *TailCallSuspend =
+maybeTailCall(S, RetType, AwaitSuspend, Loc, IsImplicit))
   Calls.Results[ACT::ACT_Suspend] = TailCallSuspend;
 else {
   // non-class prvalues always have cv-unqualified types
@@ -870,8 +879,8 @@
   SourceLocation CallLoc = E->getExprLoc();
 
   // Build the await_ready, await_suspend, await_resume calls.
-  ReadySuspendResumeResult RSS =
-  buildCoawaitCalls(*this, Coroutine->CoroutinePromise, CallLoc, E);
+  ReadySuspendResumeResult RSS = buildCoawaitCalls(
+  *this, Coroutine->CoroutinePromise, CallLoc, E, IsImplicit);
   if (RSS.IsInvalid)
 return ExprError();
 
@@ -925,8 +934,8 @@
 E = CreateMaterializeTemporaryExpr(E->getType(), E, true);
 
   // Build the await_ready, await_suspend, await_resume calls.
-  ReadySuspendResumeResult RSS =
-  buildCoawaitCalls(*this, Coroutine->CoroutinePromise, Loc, E);
+  ReadySuspendResumeResult RSS = buildCoawaitCalls(
+  *this, Coroutine->CoroutinePromise, Loc, E, /*IsImplicit*/ false);
   if (RSS.IsInvalid)
 return ExprError();
 


Index: clang/test/CodeGenCoroutines/coro-semmetric-transfer.cpp
===
--- clang/test/CodeGenCoroutines/coro-semmetric-transfer.cpp
+++ clang/test/CodeGenCoroutines/coro-semmetric-transfer.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang -std=c++14 -fcoroutines-ts -emit-llvm -S -O1 %s -o -
+// RUN: %clang -std=c+

[PATCH] D89066: [Coroutine][Sema] Only tighten the suspend call temp lifetime for final awaiter

2020-10-12 Thread Xun Li via Phabricator via cfe-commits
lxfind added a comment.

There seems to be build failures in the buildbot, but I don't understand why 
it's happening.. (unable to repro locally and the patterns seem reasonable)
http://lab.llvm.org:8011/#/builders/12/builds/92/steps/7/logs/FAIL__Clang__coro-semmetric-transfer_cpp


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D89066

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


[PATCH] D89269: [Coroutine] Rename coro-semmetric-transfer.cpp and possibly fix test failure

2020-10-12 Thread Xun Li via Phabricator via cfe-commits
lxfind created this revision.
lxfind added reviewers: wenlei, junparser.
Herald added subscribers: cfe-commits, modimo, modocache.
Herald added a project: clang.
lxfind requested review of this revision.

Some tests start to fail after https://reviews.llvm.org/D89066.
It's because the size of pointers are different on different targets.
Limit the target in the command so there is no confusion.
Also noticed I had typo in the test name.
Adding disable-llvm-passes option to make the test more stable as well.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D89269

Files:
  clang/test/CodeGenCoroutines/coro-semmetric-transfer.cpp
  clang/test/CodeGenCoroutines/coro-symmetric-transfer.cpp


Index: clang/test/CodeGenCoroutines/coro-symmetric-transfer.cpp
===
--- clang/test/CodeGenCoroutines/coro-symmetric-transfer.cpp
+++ clang/test/CodeGenCoroutines/coro-symmetric-transfer.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang -std=c++14 -fcoroutines-ts -emit-llvm -S -O1 %s -o - | 
FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fcoroutines-ts -std=c++14 
-O1 -emit-llvm %s -o - -disable-llvm-passes | FileCheck %s
 
 #include "Inputs/coroutine.h"
 
@@ -48,6 +48,10 @@
   co_return;
 }
 
-// check that the lifetime of the coroutine handle used to obtain the address 
ended right away.
-// CHECK:   %{{.*}} = call i8* 
@{{.*address.*}}(%"struct.std::experimental::coroutines_v1::coroutine_handle.0"*
 nonnull %{{.*}})
-// CHECK-NEXT:  call void @llvm.lifetime.end.p0i8(i64 8, i8* nonnull %{{.*}})
+// check that the lifetime of the coroutine handle used to obtain the address 
is contained within single basic block.
+// CHECK-LABEL: final.suspend:
+// CHECK: %[[PTR1:.+]] = bitcast 
%"struct.std::experimental::coroutines_v1::coroutine_handle.0"* 
%[[ADDR_TMP:.+]] to i8*
+// CHECK-NEXT:call void @llvm.lifetime.start.p0i8(i64 8, i8* %[[PTR1]])
+// CHECK: call i8* 
@{{.*address.*}}(%"struct.std::experimental::coroutines_v1::coroutine_handle.0"*
 %[[ADDR_TMP]])
+// CHECK-NEXT:%[[PTR2:.+]] = bitcast 
%"struct.std::experimental::coroutines_v1::coroutine_handle.0"* %[[ADDR_TMP]] 
to i8*
+// CHECK-NEXT:call void @llvm.lifetime.end.p0i8(i64 8, i8* %[[PTR2]])


Index: clang/test/CodeGenCoroutines/coro-symmetric-transfer.cpp
===
--- clang/test/CodeGenCoroutines/coro-symmetric-transfer.cpp
+++ clang/test/CodeGenCoroutines/coro-symmetric-transfer.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang -std=c++14 -fcoroutines-ts -emit-llvm -S -O1 %s -o - | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fcoroutines-ts -std=c++14 -O1 -emit-llvm %s -o - -disable-llvm-passes | FileCheck %s
 
 #include "Inputs/coroutine.h"
 
@@ -48,6 +48,10 @@
   co_return;
 }
 
-// check that the lifetime of the coroutine handle used to obtain the address ended right away.
-// CHECK:   %{{.*}} = call i8* @{{.*address.*}}(%"struct.std::experimental::coroutines_v1::coroutine_handle.0"* nonnull %{{.*}})
-// CHECK-NEXT:  call void @llvm.lifetime.end.p0i8(i64 8, i8* nonnull %{{.*}})
+// check that the lifetime of the coroutine handle used to obtain the address is contained within single basic block.
+// CHECK-LABEL: final.suspend:
+// CHECK: %[[PTR1:.+]] = bitcast %"struct.std::experimental::coroutines_v1::coroutine_handle.0"* %[[ADDR_TMP:.+]] to i8*
+// CHECK-NEXT:call void @llvm.lifetime.start.p0i8(i64 8, i8* %[[PTR1]])
+// CHECK: call i8* @{{.*address.*}}(%"struct.std::experimental::coroutines_v1::coroutine_handle.0"* %[[ADDR_TMP]])
+// CHECK-NEXT:%[[PTR2:.+]] = bitcast %"struct.std::experimental::coroutines_v1::coroutine_handle.0"* %[[ADDR_TMP]] to i8*
+// CHECK-NEXT:call void @llvm.lifetime.end.p0i8(i64 8, i8* %[[PTR2]])
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D89066: [Coroutine][Sema] Only tighten the suspend call temp lifetime for final awaiter

2020-10-12 Thread Xun Li via Phabricator via cfe-commits
lxfind added a comment.

Test failures are being fixed in https://reviews.llvm.org/D89269.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D89066

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


[PATCH] D89269: [Coroutine] Rename coro-semmetric-transfer.cpp and fix test failure

2020-10-12 Thread Xun Li via Phabricator via cfe-commits
This revision was landed with ongoing or failed builds.
This revision was automatically updated to reflect the committed changes.
Closed by commit rGd80ecdf27faf: [Coroutine] Rename coro-semmetric-transfer.cpp 
and possibly fix test failure (authored by lxfind).

Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D89269

Files:
  clang/test/CodeGenCoroutines/coro-semmetric-transfer.cpp
  clang/test/CodeGenCoroutines/coro-symmetric-transfer.cpp


Index: clang/test/CodeGenCoroutines/coro-symmetric-transfer.cpp
===
--- clang/test/CodeGenCoroutines/coro-symmetric-transfer.cpp
+++ clang/test/CodeGenCoroutines/coro-symmetric-transfer.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang -std=c++14 -fcoroutines-ts -emit-llvm -S -O1 %s -o - | 
FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fcoroutines-ts -std=c++14 
-O1 -emit-llvm %s -o - -disable-llvm-passes | FileCheck %s
 
 #include "Inputs/coroutine.h"
 
@@ -48,6 +48,10 @@
   co_return;
 }
 
-// check that the lifetime of the coroutine handle used to obtain the address 
ended right away.
-// CHECK:   %{{.*}} = call i8* 
@{{.*address.*}}(%"struct.std::experimental::coroutines_v1::coroutine_handle.0"*
 nonnull %{{.*}})
-// CHECK-NEXT:  call void @llvm.lifetime.end.p0i8(i64 8, i8* nonnull %{{.*}})
+// check that the lifetime of the coroutine handle used to obtain the address 
is contained within single basic block.
+// CHECK-LABEL: final.suspend:
+// CHECK: %[[PTR1:.+]] = bitcast 
%"struct.std::experimental::coroutines_v1::coroutine_handle.0"* 
%[[ADDR_TMP:.+]] to i8*
+// CHECK-NEXT:call void @llvm.lifetime.start.p0i8(i64 8, i8* %[[PTR1]])
+// CHECK: call i8* 
@{{.*address.*}}(%"struct.std::experimental::coroutines_v1::coroutine_handle.0"*
 %[[ADDR_TMP]])
+// CHECK-NEXT:%[[PTR2:.+]] = bitcast 
%"struct.std::experimental::coroutines_v1::coroutine_handle.0"* %[[ADDR_TMP]] 
to i8*
+// CHECK-NEXT:call void @llvm.lifetime.end.p0i8(i64 8, i8* %[[PTR2]])


Index: clang/test/CodeGenCoroutines/coro-symmetric-transfer.cpp
===
--- clang/test/CodeGenCoroutines/coro-symmetric-transfer.cpp
+++ clang/test/CodeGenCoroutines/coro-symmetric-transfer.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang -std=c++14 -fcoroutines-ts -emit-llvm -S -O1 %s -o - | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fcoroutines-ts -std=c++14 -O1 -emit-llvm %s -o - -disable-llvm-passes | FileCheck %s
 
 #include "Inputs/coroutine.h"
 
@@ -48,6 +48,10 @@
   co_return;
 }
 
-// check that the lifetime of the coroutine handle used to obtain the address ended right away.
-// CHECK:   %{{.*}} = call i8* @{{.*address.*}}(%"struct.std::experimental::coroutines_v1::coroutine_handle.0"* nonnull %{{.*}})
-// CHECK-NEXT:  call void @llvm.lifetime.end.p0i8(i64 8, i8* nonnull %{{.*}})
+// check that the lifetime of the coroutine handle used to obtain the address is contained within single basic block.
+// CHECK-LABEL: final.suspend:
+// CHECK: %[[PTR1:.+]] = bitcast %"struct.std::experimental::coroutines_v1::coroutine_handle.0"* %[[ADDR_TMP:.+]] to i8*
+// CHECK-NEXT:call void @llvm.lifetime.start.p0i8(i64 8, i8* %[[PTR1]])
+// CHECK: call i8* @{{.*address.*}}(%"struct.std::experimental::coroutines_v1::coroutine_handle.0"* %[[ADDR_TMP]])
+// CHECK-NEXT:%[[PTR2:.+]] = bitcast %"struct.std::experimental::coroutines_v1::coroutine_handle.0"* %[[ADDR_TMP]] to i8*
+// CHECK-NEXT:call void @llvm.lifetime.end.p0i8(i64 8, i8* %[[PTR2]])
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D92661: [RFC] Fix TLS and Coroutine

2020-12-04 Thread Xun Li via Phabricator via cfe-commits
lxfind created this revision.
Herald added subscribers: hoy, modimo, wenlei, steven_wu, modocache, hiraditya, 
mgorny.
lxfind requested review of this revision.
Herald added a reviewer: jdoerfert.
Herald added subscribers: llvm-commits, cfe-commits, sstefan1, jdoerfert.
Herald added projects: clang, LLVM.

This patch is to address https://bugs.llvm.org/show_bug.cgi?id=47835.
A relevant discussion regarding pthread_self and TLS can be found here: 
http://lists.llvm.org/pipermail/llvm-dev/2020-November/146766.html.

A coroutine may suspend and resume on a different thread, and hence the address 
of a thread_local variable may change after coroutine suspension.
In the existing design, getting the address of a TLS variable is through a 
direct reference, like @tls_variable. Such kind of value can be
arbitrarily moved around/replaced in the IR within the same function. This will 
lead to incorrect caching of TLS variable address in coroutines across 
suspension points.
To fix it, we have to turn the TLS address access into an intrinsics call, so 
that it will not be simply CSE-ed.
After CoroSplit, we no longer have coroutines, and hence can safely lower the 
TLS intrinsics back into references.

Note:
The current placement of the LowerThreadLocalIntrinsicPass may not be ideal. I 
am not quite sure how to organize it. Suggestions welcome!
Testing isn't sufficient, and there may also be failing tests. I will add/fix 
more tests if this patch is along the right direction.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D92661

Files:
  clang/lib/CodeGen/CGExpr.cpp
  clang/lib/CodeGen/ItaniumCXXABI.cpp
  clang/test/CodeGen/lto-newpm-pipeline.c
  clang/test/CodeGenCXX/cxx2a-thread-local-constinit.cpp
  clang/test/CodeGenCoroutines/coro-tls.cpp
  llvm/include/llvm/IR/IRBuilder.h
  llvm/include/llvm/IR/Intrinsics.td
  llvm/include/llvm/InitializePasses.h
  llvm/include/llvm/Transforms/Scalar.h
  llvm/include/llvm/Transforms/Scalar/LowerThreadLocalIntrinsic.h
  llvm/lib/IR/IRBuilder.cpp
  llvm/lib/Passes/PassBuilder.cpp
  llvm/lib/Transforms/IPO/PassManagerBuilder.cpp
  llvm/lib/Transforms/Scalar/CMakeLists.txt
  llvm/lib/Transforms/Scalar/LowerThreadLocalIntrinsic.cpp
  llvm/test/Other/new-pass-manager.ll
  llvm/test/Other/new-pm-O0-defaults.ll
  llvm/test/Other/new-pm-defaults.ll

Index: llvm/test/Other/new-pm-defaults.ll
===
--- llvm/test/Other/new-pm-defaults.ll
+++ llvm/test/Other/new-pm-defaults.ll
@@ -209,6 +209,7 @@
 ; CHECK-EP-CGSCC-LATE-NEXT: Running pass: NoOpCGSCCPass
 ; CHECK-O-NEXT: Finished CGSCC pass manager run.
 ; CHECK-O-NEXT: Finished llvm::Module pass manager run.
+; CHECK-O-NEXT: Running pass: LowerThreadLocalIntrinsicPass
 ; CHECK-O-NEXT: Running pass: GlobalOptPass
 ; CHECK-O-NEXT: Running pass: GlobalDCEPass
 ; CHECK-DEFAULT-NEXT: Running pass: EliminateAvailableExternallyPass
Index: llvm/test/Other/new-pm-O0-defaults.ll
===
--- llvm/test/Other/new-pm-O0-defaults.ll
+++ llvm/test/Other/new-pm-O0-defaults.ll
@@ -32,6 +32,7 @@
 ; CHECK-DEFAULT-NEXT: Running analysis: ProfileSummaryAnalysis
 ; CHECK-MATRIX-NEXT: Running pass: LowerMatrixIntrinsicsPass
 ; CHECK-MATRIX-NEXT: Running analysis: TargetIRAnalysis
+; CHECK-DEFAULT-NEXT: Running pass: LowerThreadLocalIntrinsicPass
 ; CHECK-PRE-LINK-NEXT: Running pass: CanonicalizeAliasesPass
 ; CHECK-PRE-LINK-NEXT: Running pass: NameAnonGlobalPass
 ; CHECK-THINLTO-NEXT: Running pass: Annotation2MetadataPass
Index: llvm/test/Other/new-pass-manager.ll
===
--- llvm/test/Other/new-pass-manager.ll
+++ llvm/test/Other/new-pass-manager.ll
@@ -366,6 +366,7 @@
 ; CHECK-EXT-NEXT: Starting llvm::Function pass manager run.
 ; CHECK-EXT-NEXT: Running pass: {{.*}}Bye
 ; CHECK-EXT-NEXT: Finished llvm::Function pass manager run.
+; CHECK-O0-NEXT: Running pass: LowerThreadLocalIntrinsicPass
 ; CHECK-O0-NEXT: Finished llvm::Module pass manager run
 
 ; RUN: opt -disable-output -disable-verify -debug-pass-manager \
Index: llvm/lib/Transforms/Scalar/LowerThreadLocalIntrinsic.cpp
===
--- /dev/null
+++ llvm/lib/Transforms/Scalar/LowerThreadLocalIntrinsic.cpp
@@ -0,0 +1,76 @@
+//===- LowerThreadLocalIntrinsic.cpp - Lower the threadlocal intrinsic
+//---===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===--===//
+//
+// This pass lowers the llvm.threadlocal intrinsic to a direct reference to the
+// thread local variable.
+//
+//===--===//
+
+#include "llvm/Transforms/Scalar/LowerThreadLocalIntri

[PATCH] D92662: [Clang][Coroutine] Drop const attribute on pthread_self when coroutine is enabled

2020-12-04 Thread Xun Li via Phabricator via cfe-commits
lxfind created this revision.
Herald added subscribers: hoy, modimo, wenlei, modocache.
lxfind requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

This patch is to address https://bugs.llvm.org/show_bug.cgi?id=47833
A relevant discussion can also be found in 
http://lists.llvm.org/pipermail/llvm-dev/2020-November/146766.html

pthread_self() from glibc is defined with "__attribute__
((__const__))". The const attribute tells the compiler that it does
not read nor write any global state and hence always return the same
result. Hence in the following code:

auto x1 = pthread_self();
...
auto x2 = pthread_self();

the second call to pthread_self() can be optimized out. This has been
correct until coroutines. With coroutines, we can have code like this:

auto x1 = pthread_self();
co_await ...
auto x2 = pthread_self();

Now because of the co_await, the function can suspend and resume in a
different thread, in which case the second call to pthread_self()
should return a different result than the first one. Unfortunately
LLVM will still optimize out the second call in the case of
coroutines.

To fix the issue, this patch drops the readnone attribute from the pthread_self 
function in Clang.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D92662

Files:
  clang/lib/Sema/SemaDecl.cpp
  clang/test/CodeGenCoroutines/coro-pthread_self.cpp


Index: clang/test/CodeGenCoroutines/coro-pthread_self.cpp
===
--- /dev/null
+++ clang/test/CodeGenCoroutines/coro-pthread_self.cpp
@@ -0,0 +1,58 @@
+// RUN: %clang -fcoroutines-ts -std=c++14 -O3 -emit-llvm -S %s -o - | 
FileCheck %s
+
+#include "Inputs/coroutine.h"
+
+namespace coro = std::experimental::coroutines_v1;
+
+typedef void *pthread_t;
+pthread_t pthread_self(void) __attribute__((__const__));
+
+struct awaitable {
+  bool await_ready() { return false; }
+  void await_suspend(coro::coroutine_handle<> h);
+  void await_resume() {}
+};
+awaitable switch_to_new_thread();
+
+struct task {
+  struct promise_type {
+task get_return_object() { return {}; }
+coro::suspend_never initial_suspend() { return {}; }
+coro::suspend_never final_suspend() noexcept { return {}; }
+void return_void() {}
+void unhandled_exception() {}
+  };
+};
+
+void check(pthread_t p1, pthread_t p2);
+
+task resuming_on_new_thread() {
+  auto pthread1 = pthread_self();
+  co_await switch_to_new_thread();
+  auto pthread2 = pthread_self();
+  check(pthread1, pthread2);
+}
+
+void non_coroutine() {
+  auto pthread1 = pthread_self();
+  check(pthread1, pthread1);
+  auto pthread2 = pthread_self();
+  check(pthread1, pthread2);
+}
+
+// CHECK-LABEL: define void @_Z13non_coroutinev()
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:%call = tail call i8* @_Z12pthread_selfv()
+// CHECK-NEXT:tail call void @_Z5checkPvS_(i8* %call, i8* %call)
+// CHECK-NEXT:%call1 = tail call i8* @_Z12pthread_selfv()
+// CHECK-NEXT:tail call void @_Z5checkPvS_(i8* %call, i8* %call1)
+// CHECK-NEXT:ret void
+// CHECK-NEXT:  }
+
+// CHECK-LABEL: define internal fastcc void @_Z22resuming_on_new_threadv.resume
+// CHECK: %[[CALL:.+]] = invoke i8* @_Z12pthread_selfv()
+// CHECK-NEXT:to label %[[CONT:.+]] unwind label %{{.+}}
+// CHECK:  [[CONT]]:
+// CHECK-NEXT:%[[RELOAD_ADDR:.+]] = getelementptr inbounds 
%_Z22resuming_on_new_threadv.Frame, %_Z22resuming_on_new_threadv.Frame* 
%FramePtr, i64 0, i32 {{.+}}
+// CHECK-NEXT:%[[RELOAD:.+]] = load i8*, i8** %[[RELOAD_ADDR]], align 8
+// CHECK-NEXT:invoke void @_Z5checkPvS_(i8* %[[RELOAD]], i8* %[[CALL]])
Index: clang/lib/Sema/SemaDecl.cpp
===
--- clang/lib/Sema/SemaDecl.cpp
+++ clang/lib/Sema/SemaDecl.cpp
@@ -14938,6 +14938,12 @@
   IdentifierInfo *Name = FD->getIdentifier();
   if (!Name)
 return;
+
+  if (getLangOpts().Coroutines && Name->isStr("pthread_self") &&
+  FD->hasAttr()) {
+FD->dropAttr();
+  }
+
   if ((!getLangOpts().CPlusPlus &&
FD->getDeclContext()->isTranslationUnit()) ||
   (isa(FD->getDeclContext()) &&


Index: clang/test/CodeGenCoroutines/coro-pthread_self.cpp
===
--- /dev/null
+++ clang/test/CodeGenCoroutines/coro-pthread_self.cpp
@@ -0,0 +1,58 @@
+// RUN: %clang -fcoroutines-ts -std=c++14 -O3 -emit-llvm -S %s -o - | FileCheck %s
+
+#include "Inputs/coroutine.h"
+
+namespace coro = std::experimental::coroutines_v1;
+
+typedef void *pthread_t;
+pthread_t pthread_self(void) __attribute__((__const__));
+
+struct awaitable {
+  bool await_ready() { return false; }
+  void await_suspend(coro::coroutine_handle<> h);
+  void await_resume() {}
+};
+awaitable switch_to_new_thread();
+
+struct task {
+  struct promise_type {
+task get_return_object() { return {}; }
+coro::suspend_never initial_suspend() { return {}; }
+cor

[PATCH] D92661: [RFC] Fix TLS and Coroutine

2020-12-04 Thread Xun Li via Phabricator via cfe-commits
lxfind added inline comments.



Comment at: llvm/include/llvm/IR/Intrinsics.td:1309
+// Intrinsic to obtain the address of a thread_local variable.
+def int_threadlocal : Intrinsic<[llvm_ptr_ty], [llvm_ptr_ty]>;
+

hoy wrote:
> hoy wrote:
> > With the intrinsic, can TLS variable reference in the same coroutine or 
> > regular routine be DCE-ed anymore?
> Sorry, I meant CSE-ed.
Since the intrinsics does not have readnone attribute, it won't be CSE-ed 
before CoroSplit.
However after CoroSplit, it will be lowered back to the direct reference of the 
TLS, and will be CSE-ed by latter passes.
I can add a test function to demonstrate that too.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D92661

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


[PATCH] D92661: [RFC] Fix TLS and Coroutine

2020-12-04 Thread Xun Li via Phabricator via cfe-commits
lxfind added inline comments.



Comment at: llvm/include/llvm/IR/Intrinsics.td:1309
+// Intrinsic to obtain the address of a thread_local variable.
+def int_threadlocal : Intrinsic<[llvm_ptr_ty], [llvm_ptr_ty]>;
+

hoy wrote:
> lxfind wrote:
> > hoy wrote:
> > > hoy wrote:
> > > > With the intrinsic, can TLS variable reference in the same coroutine or 
> > > > regular routine be DCE-ed anymore?
> > > Sorry, I meant CSE-ed.
> > Since the intrinsics does not have readnone attribute, it won't be CSE-ed 
> > before CoroSplit.
> > However after CoroSplit, it will be lowered back to the direct reference of 
> > the TLS, and will be CSE-ed by latter passes.
> > I can add a test function to demonstrate that too.
> Sounds good. Can you please point out what optimization passes CSE-ed tls 
> reference without this implementation? I'm wondering if those optimizations 
> can be postponed to after CoroSplit. 
To clarify, it wasn't just CSE that would merge the references of the same TLS.
For instance, without this patch, a reference to "tls_variable" will just be 
"@tls_variable". For code like this:

  @tls_variable = internal thread_local global i32 0, align 4

  define i32* @foo(){
ret i32* @tls_variable
  }
  
  define void @bar() {
%tls1 = call i32* @foo()
..coro.suspend..
%tls2 = call i32* @foo()
%cond = icmp eq i32* %tls1, %tls2
  }

When foo() is inlined into bar(), all uses of %tls1 will be replaced with 
@tls_variable.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D92661

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


[PATCH] D102465: [Coroutines] Mark every parameter

2021-05-13 Thread Xun Li via Phabricator via cfe-commits
lxfind created this revision.
Herald added subscribers: ChuanqiXu, hoy, modimo, wenlei, hiraditya.
lxfind requested review of this revision.
Herald added subscribers: llvm-commits, cfe-commits, jdoerfert.
Herald added projects: clang, LLVM.

Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D102465

Files:
  clang/lib/CodeGen/CGCoroutine.cpp
  clang/test/CodeGenCoroutines/Inputs/coroutine.h
  clang/test/CodeGenCoroutines/coro-param-memcpy.cpp
  llvm/include/llvm/IR/Intrinsics.td
  llvm/lib/Transforms/Coroutines/CoroSplit.cpp

Index: llvm/lib/Transforms/Coroutines/CoroSplit.cpp
===
--- llvm/lib/Transforms/Coroutines/CoroSplit.cpp
+++ llvm/lib/Transforms/Coroutines/CoroSplit.cpp
@@ -1766,6 +1766,11 @@
   bool ReuseFrameSlot) {
   PrettyStackTraceFunction prettyStackTrace(F);
 
+  for (Instruction &I : make_early_inc_range(instructions(F)))
+if (auto *II = dyn_cast(&I))
+  if (II->getIntrinsicID() == Intrinsic::coro_mark_param)
+II->eraseFromParent();
+
   // The suspend-crossing algorithm in buildCoroutineFrame get tripped
   // up by uses in unreachable blocks, so remove them as a first pass.
   removeUnreachableBlocks(F);
Index: llvm/include/llvm/IR/Intrinsics.td
===
--- llvm/include/llvm/IR/Intrinsics.td
+++ llvm/include/llvm/IR/Intrinsics.td
@@ -1274,6 +1274,8 @@
  ReadOnly>,
  NoCapture>]>;
 
+def int_coro_mark_param : Intrinsic<[], [llvm_ptr_ty], []>;
+
 ///===-- Other Intrinsics --===//
 //
 def int_trap : Intrinsic<[], [], [IntrNoReturn, IntrCold]>,
@@ -1305,8 +1307,8 @@
 def int_sideeffect : DefaultAttrsIntrinsic<[], [], [IntrInaccessibleMemOnly, IntrWillReturn]>;
 
 // The pseudoprobe intrinsic works as a place holder to the block it probes.
-// Like the sideeffect intrinsic defined above, this intrinsic is treated by the 
-// optimizer as having opaque side effects so that it won't be get rid of or moved 
+// Like the sideeffect intrinsic defined above, this intrinsic is treated by the
+// optimizer as having opaque side effects so that it won't be get rid of or moved
 // out of the block it probes.
 def int_pseudoprobe : Intrinsic<[], [llvm_i64_ty, llvm_i64_ty, llvm_i32_ty, llvm_i64_ty],
 [IntrInaccessibleMemOnly, IntrWillReturn]>;
Index: clang/test/CodeGenCoroutines/coro-param-memcpy.cpp
===
--- /dev/null
+++ clang/test/CodeGenCoroutines/coro-param-memcpy.cpp
@@ -0,0 +1,44 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fcoroutines-ts -std=c++17 -O1 -fno-inline -emit-llvm %s -o - | FileCheck %s
+
+#include "Inputs/coroutine.h"
+
+struct task {
+  struct promise_type {
+task get_return_object() { return {this}; }
+std::experimental::suspend_always initial_suspend() { return {}; }
+std::experimental::suspend_always final_suspend() noexcept { return {}; }
+void return_void() {}
+void unhandled_exception() {}
+  };
+  promise_type *promise;
+};
+
+namespace std::experimental {
+template 
+struct coroutine_traits {
+  using promise_type = typename task::promise_type;
+};
+} // namespace std::experimental
+
+void *g = nullptr;
+
+struct A {
+  unsigned long long a = 1;
+  unsigned long long b;
+  unsigned int c;
+};
+
+task foo(A a1) {
+  A a2 = a1; // Necessary.
+  g = &a2;   // So the address isn't optimized out.
+  co_return;
+}
+
+// verify that the entire struct param is in the frame.
+// CHECK: %_Z3foo1A.Frame = type { void (%_Z3foo1A.Frame*)*, void (%_Z3foo1A.Frame*)*, %"struct.task::promise_type", i1, %"struct.std::experimental::coroutines_v1::suspend_always", [5 x i8], [24 x i8] }
+
+// CHECK-LABEL: define dso_local %"struct.task::promise_type"* @_Z3foo1A(
+// CHECK: %[[FRAME:.+]] = call noalias nonnull i8* @_Znwm(
+// CHECK: %[[PTR:.+]] = getelementptr inbounds i8, i8* %[[FRAME]], i64 24
+// CHECK: %[[PARAM:.+]] = bitcast %struct.A* %a1 to i8*
+// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* noundef nonnull align 8 dereferenceable(24) %[[PTR]], i8* noundef nonnull align 8 dereferenceable(24) %[[PARAM]], i64 24, i1 false)
Index: clang/test/CodeGenCoroutines/Inputs/coroutine.h
===
--- clang/test/CodeGenCoroutines/Inputs/coroutine.h
+++ clang/test/CodeGenCoroutines/Inputs/coroutine.h
@@ -67,9 +67,9 @@
   }
 
 struct suspend_always {
-  bool await_ready() { return false; }
-  void await_suspend(coroutine_handle<>) {}
-  void await_resume() {}
+  bool await_ready() noexcept { return false; }
+  void await_suspend(coroutine_handle<>) noexcept {}
+  void await_resume() noexcept {}
 };
 struct suspend_never {
   bool await_ready() noexcept { return true; }
Index: clang/li

[PATCH] D107155: [clang][deps] Substitute clang-scan-deps executable in lit tests

2021-07-30 Thread Xun Li via Phabricator via cfe-commits
lxfind accepted this revision.
lxfind added a comment.
This revision is now accepted and ready to land.

Thank you!


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D107155

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


[PATCH] D43477: [CFG] [analyzer] Add MaterializeTemporaryExpr into the construction context.

2021-08-02 Thread Xun Li via Phabricator via cfe-commits
lxfind added a comment.
Herald added subscribers: manas, steakhal, ASDenysPetrov, martong, dkrupp, 
donat.nagy, Szelethus, mikhail.ramalho, baloghadamsoftware.

Hi! I have a question regarding the implementation of 
"VisitMaterializeTemporaryExpr". Specifically, I wonder if we should skip 
visiting the children? Would't visiting the children of 
MaterializeTemporaryExpr cause the same expression to be visited twice?

I am debugging a crash in ThreadSafetyAnalyzer, which triggers this assertion: 
https://github.com/llvm/llvm-project/blob/main/clang/lib/Analysis/ThreadSafety.cpp#L534
Basically it's adding the same declaration twice from the same CFG block.
And I found that the redundant declaration is added during CFG construction, 
when processing cpp source code like this:

  co_return ({ static constexpr mydomain::logdevice::ErrorStacktrace::Frame 
frame{ __FUNCTION__, "logdevice/common/ZookeeperClientBase.cpp", 103}; 
mydomain::logdevice::detail::makeUnexpected(&frame, toStatus(result.rc_)); });

which corresponds to the following AST:

  |   `-CompoundStmt 0x227b13f8
  | `-CoreturnStmt 0x227b13d0
  |   |-CXXBindTemporaryExpr 0x22776218 'folly::Unexpected':'class 
folly::Unexpected' (CXXTemporary 0x22776218)
  |   | `-StmtExpr 0x227761f0 'folly::Unexpected':'class 
folly::Unexpected'
  |   |   `-CompoundStmt 0x227761d0
  |   | |-DeclStmt 0x22771e88
  |   | | `-VarDecl 0x22771c50  used frame 'const 
mydomain::logdevice::class ErrorStacktrace::Frame':'const struct 
mydomain::logdevice::ErrorStacktrace::Frame' static constexpr listinit
  |   | |   |-value: Struct
  |   | |   | `-fields: LValue , LValue , Int 103
  |   | |   `-InitListExpr 0x22771da8 'const mydomain::logdevice::class 
ErrorStacktrace::Frame':'const struct 
mydomain::logdevice::ErrorStacktrace::Frame'
  |   | | |-ImplicitCastExpr 0x22771e00 'const char *' 

  |   | | | `-PredefinedExpr 0x22771cd8 'const char [8]' lvalue 
__FUNCTION__
  |   | | |   `-StringLiteral 0x22771cb8 'const char [8]' lvalue 
"getData"
  |   | | |-ImplicitCastExpr 0x22771e18 'const char *' 

  |   | | | `-StringLiteral 0x22771cf0 'const char [41]' lvalue 
"logdevice/common/ZookeeperClientBase.cpp"
  |   | | `-IntegerLiteral 0x22771d30 'int' 103
  |   | `-ExprWithCleanups 0x227761b8 'folly::Unexpected':'class 
folly::Unexpected'
  |   |   `-CXXBindTemporaryExpr 0x22776198 
'folly::Unexpected':'class folly::Unexpected' (CXXTemporary 0x22776198)
  |   | `-CallExpr 0x22776160 'folly::Unexpected':'class 
folly::Unexpected'
  |   |   |-ImplicitCastExpr 0x22776148 'folly::Unexpected 
(*)(const class ErrorStacktrace::Frame *, mydomain::logdevice::Status)' 

  |   |   | `-DeclRefExpr 0x227760b8 'folly::Unexpected 
(const class ErrorStacktrace::Frame *, mydomain::logdevice::Status)' lvalue 
Function 0x18b49568 'makeUnexpected' 'folly::Unexpected (const class 
ErrorStacktrace::Frame *, mydomain::logdevice::Status)'
  |   |   |-UnaryOperator 0x22771fb8 'const 
mydomain::logdevice::class ErrorStacktrace::Frame *' prefix '&' cannot overflow
  |   |   | `-DeclRefExpr 0x22771f68 'const 
mydomain::logdevice::class ErrorStacktrace::Frame':'const struct 
mydomain::logdevice::ErrorStacktrace::Frame' lvalue Var 0x22771c50 'frame' 
'const mydomain::logdevice::class ErrorStacktrace::Frame':'const struct 
mydomain::logdevice::ErrorStacktrace::Frame'
  |   |   `-CallExpr 0x227720e0 'mydomain::logdevice::Status':'enum 
mydomain::logdevice::E'
  |   | |-ImplicitCastExpr 0x227720c8 
'mydomain::logdevice::Status (*)(int)' 
  |   | | `-DeclRefExpr 0x22771ff8 'mydomain::logdevice::Status 
(int)' lvalue CXXMethod 0x221cddd0 'toStatus' 'mydomain::logdevice::Status 
(int)'
  |   | `-ImplicitCastExpr 0x22772108 'int' 
  |   |   `-MemberExpr 0x22772038 'int' lvalue .rc_ 0x21f24480
  |   | `-DeclRefExpr 0x22772018 'struct 
mydomain::logdevice::zk::GetResponse':'struct 
mydomain::logdevice::zk::GetResponse' lvalue Var 0x22731508 'result' 'struct 
mydomain::logdevice::zk::GetResponse':'struct 
mydomain::logdevice::zk::GetResponse'
  |   `-ExprWithCleanups 0x227b13b8 'void'
  | `-CXXMemberCallExpr 0x227b1378 'void'
  |   |-MemberExpr 0x227b1330 '' 
.return_value 0x227b1230
  |   | `-DeclRefExpr 0x22776238 'std::__coroutine_traits_impl > 
>::promise_type':'class folly::coro::detail::TaskPromise >' lvalue Var 0x227330a0 '__promise' 
'std::__coroutine_traits_impl > >::promise_type':'class 
folly::coro::detail::TaskPromise >'
  |   `-MaterializeTemporaryExpr 0x227b13a0 
'folly::Unexpected':'class folly::Unexpected' xvalue
  | `-CXXBindTemporaryExpr 0x22776218 
'folly::Unexpected':'class folly::Unexpected' (CXXTemporary 0x22776218)
  |   `-StmtExpr 0x227761f0 '

[PATCH] D105877: [Coroutines] Run coroutine passes by default

2021-08-03 Thread Xun Li via Phabricator via cfe-commits
lxfind added a comment.

In D105877#2923257 , @nikic wrote:

> I noticed that this change had a measurable impact on `O0` memory usage, 
> which I wouldn't have expected 
> (https://llvm-compile-time-tracker.com/compare.php?from=0f9e6451a836886f39137818c4f0cfd69ae31e62&to=8a1727ba51d262365b0d9fe10fef7e50da7022cd&stat=max-rss).
>  Any idea what could cause it? Some additional analysis results hanging 
> around?

That's surprising. Is there a way to measure these benchmarks locally? We could 
probably find out which one is causing the issue by manually commenting out 
each coro pass and see how the number changes.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D105877

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


[PATCH] D105066: [Coroutines] Remove CoroElide from O0 pipeline

2021-06-28 Thread Xun Li via Phabricator via cfe-commits
lxfind created this revision.
lxfind added reviewers: ChuanqiXu, rjmccall.
Herald added subscribers: hoy, modimo, wenlei, hiraditya.
lxfind requested review of this revision.
Herald added projects: clang, LLVM.
Herald added subscribers: llvm-commits, cfe-commits.

CoroElide pass works only when a post-split coroutine is inlined into another 
post-split coroutine.
In O0, there is no inlining after CoroSplit, and hence no CoroElide can happen.
It's useless to put CoroElide pass in the O0 pipeline and it will never be 
triggered (unless I miss anything).


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D105066

Files:
  clang/test/CodeGenCoroutines/coro-newpm-pipeline.cpp
  llvm/lib/Passes/PassBuilder.cpp
  llvm/test/Transforms/Coroutines/smoketest.ll


Index: llvm/test/Transforms/Coroutines/smoketest.ll
===
--- llvm/test/Transforms/Coroutines/smoketest.ll
+++ llvm/test/Transforms/Coroutines/smoketest.ll
@@ -2,20 +2,20 @@
 ; levels and -enable-coroutines adds coroutine passes to the pipeline.
 ;
 ; RUN: opt < %s -disable-output -passes='default' -enable-coroutines \
-; RUN: -debug-pass-manager 2>&1 | FileCheck %s
+; RUN: -debug-pass-manager 2>&1 | FileCheck %s --check-prefixes=CHECK-ALL
 ; RUN: opt < %s -disable-output -passes='default' -enable-coroutines \
-; RUN: -debug-pass-manager 2>&1 | FileCheck %s
+; RUN: -debug-pass-manager 2>&1 | FileCheck %s 
--check-prefixes=CHECK-ALL,CHECK-OPT
 ; RUN: opt < %s -disable-output -passes='default' -enable-coroutines \
-; RUN: -debug-pass-manager 2>&1 | FileCheck %s
+; RUN: -debug-pass-manager 2>&1 | FileCheck %s 
--check-prefixes=CHECK-ALL,CHECK-OPT
 ; RUN: opt < %s -disable-output -passes='default' -enable-coroutines \
-; RUN: -debug-pass-manager 2>&1 | FileCheck %s
+; RUN: -debug-pass-manager 2>&1 | FileCheck %s 
--check-prefixes=CHECK-ALL,CHECK-OPT
 ; RUN: opt < %s -disable-output -debug-pass-manager \
 ; RUN: 
-passes='function(coro-early),cgscc(coro-split),function(coro-elide,coro-cleanup)'
 2>&1 \
-; RUN: | FileCheck %s
+; RUN: | FileCheck %s --check-prefixes=CHECK-ALL,CHECK-OPT
 
 ; CHECK: CoroEarlyPass
 ; CHECK: CoroSplitPass
-; CHECK: CoroElidePass
+; CHECK-OPT: CoroElidePass
 ; CHECK: CoroCleanupPass
 
 define void @foo() {
Index: llvm/lib/Passes/PassBuilder.cpp
===
--- llvm/lib/Passes/PassBuilder.cpp
+++ llvm/lib/Passes/PassBuilder.cpp
@@ -1986,7 +1986,6 @@
 
 CGSCCPassManager CGPM;
 CGPM.addPass(CoroSplitPass());
-CGPM.addPass(createCGSCCToFunctionPassAdaptor(CoroElidePass()));
 MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM)));
 
 MPM.addPass(createModuleToFunctionPassAdaptor(CoroCleanupPass()));
Index: clang/test/CodeGenCoroutines/coro-newpm-pipeline.cpp
===
--- clang/test/CodeGenCoroutines/coro-newpm-pipeline.cpp
+++ clang/test/CodeGenCoroutines/coro-newpm-pipeline.cpp
@@ -3,23 +3,23 @@
 
 // RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm-bc -o /dev/null 
\
 // RUN:   -fexperimental-new-pass-manager -fdebug-pass-manager -fcoroutines-ts 
\
-// RUN:   -O0 %s 2>&1 | FileCheck %s
+// RUN:   -O0 %s 2>&1 | FileCheck %s --check-prefixes=CHECK-ALL
 // RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm-bc -o /dev/null 
\
 // RUN:   -fexperimental-new-pass-manager -fdebug-pass-manager -fcoroutines-ts 
\
-// RUN:   -O1 %s 2>&1 | FileCheck %s
+// RUN:   -O1 %s 2>&1 | FileCheck %s --check-prefixes=CHECK-ALL,CHECK-OPT
 //
-// CHECK: Running pass:{{.*}}CoroEarlyPass
+// CHECK-ALL: Running pass:{{.*}}CoroEarlyPass
 //
 // The first coro-split pass enqueues a second run of the entire CGSCC 
pipeline.
-// CHECK: Running pass: CoroSplitPass on (_Z3foov)
-// CHECK: Running pass:{{.*}}CoroElidePass{{.*}} on {{.*}}_Z3foov{{.*}}
+// CHECK-ALL: Running pass: CoroSplitPass on (_Z3foov)
+// CHECK-OPT: Running pass:{{.*}}CoroElidePass{{.*}} on {{.*}}_Z3foov{{.*}}
 //
 // The second coro-split pass splits coroutine 'foo' into funclets
 // 'foo.resume', 'foo.destroy', and 'foo.cleanup'.
-// CHECK: Running pass: CoroSplitPass on (_Z3foov)
-// CHECK: Running pass:{{.*}}CoroElidePass{{.*}} on {{.*}}_Z3foov{{.*}}
+// CHECK-ALL: Running pass: CoroSplitPass on (_Z3foov)
+// CHECK-OPT: Running pass:{{.*}}CoroElidePass{{.*}} on {{.*}}_Z3foov{{.*}}
 //
-// CHECK: Running pass:{{.*}}CoroCleanupPass
+// CHECK-ALL: Running pass:{{.*}}CoroCleanupPass
 
 namespace std {
 namespace experimental {


Index: llvm/test/Transforms/Coroutines/smoketest.ll
===
--- llvm/test/Transforms/Coroutines/smoketest.ll
+++ llvm/test/Transforms/Coroutines/smoketest.ll
@@ -2,20 +2,20 @@
 ; levels and -enable-coroutines adds coroutine passes to the pipeline.
 ;
 ; RUN: opt < %s -disable-output -passes='default' -enable-coroutines \
-; RUN: -

[PATCH] D105066: [Coroutines] Remove CoroElide from O0 pipeline

2021-06-28 Thread Xun Li via Phabricator via cfe-commits
lxfind updated this revision to Diff 355073.
lxfind added a comment.

update tests


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D105066

Files:
  clang/test/CodeGenCoroutines/coro-newpm-pipeline.cpp
  llvm/lib/Passes/PassBuilder.cpp
  llvm/test/Transforms/Coroutines/smoketest.ll


Index: llvm/test/Transforms/Coroutines/smoketest.ll
===
--- llvm/test/Transforms/Coroutines/smoketest.ll
+++ llvm/test/Transforms/Coroutines/smoketest.ll
@@ -2,21 +2,21 @@
 ; levels and -enable-coroutines adds coroutine passes to the pipeline.
 ;
 ; RUN: opt < %s -disable-output -passes='default' -enable-coroutines \
-; RUN: -debug-pass-manager 2>&1 | FileCheck %s
+; RUN: -debug-pass-manager 2>&1 | FileCheck %s --check-prefixes=CHECK-ALL
 ; RUN: opt < %s -disable-output -passes='default' -enable-coroutines \
-; RUN: -debug-pass-manager 2>&1 | FileCheck %s
+; RUN: -debug-pass-manager 2>&1 | FileCheck %s 
--check-prefixes=CHECK-ALL,CHECK-OPT
 ; RUN: opt < %s -disable-output -passes='default' -enable-coroutines \
-; RUN: -debug-pass-manager 2>&1 | FileCheck %s
+; RUN: -debug-pass-manager 2>&1 | FileCheck %s 
--check-prefixes=CHECK-ALL,CHECK-OPT
 ; RUN: opt < %s -disable-output -passes='default' -enable-coroutines \
-; RUN: -debug-pass-manager 2>&1 | FileCheck %s
+; RUN: -debug-pass-manager 2>&1 | FileCheck %s 
--check-prefixes=CHECK-ALL,CHECK-OPT
 ; RUN: opt < %s -disable-output -debug-pass-manager \
 ; RUN: 
-passes='function(coro-early),cgscc(coro-split),function(coro-elide,coro-cleanup)'
 2>&1 \
-; RUN: | FileCheck %s
+; RUN: | FileCheck %s --check-prefixes=CHECK-ALL,CHECK-OPT
 
-; CHECK: CoroEarlyPass
-; CHECK: CoroSplitPass
-; CHECK: CoroElidePass
-; CHECK: CoroCleanupPass
+; CHECK-ALL: CoroEarlyPass
+; CHECK-ALL: CoroSplitPass
+; CHECK-OPT: CoroElidePass
+; CHECK-ALL: CoroCleanupPass
 
 define void @foo() {
   ret void
Index: llvm/lib/Passes/PassBuilder.cpp
===
--- llvm/lib/Passes/PassBuilder.cpp
+++ llvm/lib/Passes/PassBuilder.cpp
@@ -1986,7 +1986,6 @@
 
 CGSCCPassManager CGPM;
 CGPM.addPass(CoroSplitPass());
-CGPM.addPass(createCGSCCToFunctionPassAdaptor(CoroElidePass()));
 MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM)));
 
 MPM.addPass(createModuleToFunctionPassAdaptor(CoroCleanupPass()));
Index: clang/test/CodeGenCoroutines/coro-newpm-pipeline.cpp
===
--- clang/test/CodeGenCoroutines/coro-newpm-pipeline.cpp
+++ clang/test/CodeGenCoroutines/coro-newpm-pipeline.cpp
@@ -3,23 +3,23 @@
 
 // RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm-bc -o /dev/null 
\
 // RUN:   -fexperimental-new-pass-manager -fdebug-pass-manager -fcoroutines-ts 
\
-// RUN:   -O0 %s 2>&1 | FileCheck %s
+// RUN:   -O0 %s 2>&1 | FileCheck %s --check-prefixes=CHECK-ALL
 // RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm-bc -o /dev/null 
\
 // RUN:   -fexperimental-new-pass-manager -fdebug-pass-manager -fcoroutines-ts 
\
-// RUN:   -O1 %s 2>&1 | FileCheck %s
+// RUN:   -O1 %s 2>&1 | FileCheck %s --check-prefixes=CHECK-ALL,CHECK-OPT
 //
-// CHECK: Running pass:{{.*}}CoroEarlyPass
+// CHECK-ALL: Running pass:{{.*}}CoroEarlyPass
 //
 // The first coro-split pass enqueues a second run of the entire CGSCC 
pipeline.
-// CHECK: Running pass: CoroSplitPass on (_Z3foov)
-// CHECK: Running pass:{{.*}}CoroElidePass{{.*}} on {{.*}}_Z3foov{{.*}}
+// CHECK-ALL: Running pass: CoroSplitPass on (_Z3foov)
+// CHECK-OPT: Running pass:{{.*}}CoroElidePass{{.*}} on {{.*}}_Z3foov{{.*}}
 //
 // The second coro-split pass splits coroutine 'foo' into funclets
 // 'foo.resume', 'foo.destroy', and 'foo.cleanup'.
-// CHECK: Running pass: CoroSplitPass on (_Z3foov)
-// CHECK: Running pass:{{.*}}CoroElidePass{{.*}} on {{.*}}_Z3foov{{.*}}
+// CHECK-ALL: Running pass: CoroSplitPass on (_Z3foov)
+// CHECK-OPT: Running pass:{{.*}}CoroElidePass{{.*}} on {{.*}}_Z3foov{{.*}}
 //
-// CHECK: Running pass:{{.*}}CoroCleanupPass
+// CHECK-ALL: Running pass:{{.*}}CoroCleanupPass
 
 namespace std {
 namespace experimental {


Index: llvm/test/Transforms/Coroutines/smoketest.ll
===
--- llvm/test/Transforms/Coroutines/smoketest.ll
+++ llvm/test/Transforms/Coroutines/smoketest.ll
@@ -2,21 +2,21 @@
 ; levels and -enable-coroutines adds coroutine passes to the pipeline.
 ;
 ; RUN: opt < %s -disable-output -passes='default' -enable-coroutines \
-; RUN: -debug-pass-manager 2>&1 | FileCheck %s
+; RUN: -debug-pass-manager 2>&1 | FileCheck %s --check-prefixes=CHECK-ALL
 ; RUN: opt < %s -disable-output -passes='default' -enable-coroutines \
-; RUN: -debug-pass-manager 2>&1 | FileCheck %s
+; RUN: -debug-pass-manager 2>&1 | FileCheck %s --check-prefixes

[PATCH] D105066: [Coroutines] Remove CoroElide from O0 pipeline

2021-06-28 Thread Xun Li via Phabricator via cfe-commits
lxfind added a comment.

In D105066#2845958 , @ChuanqiXu wrote:

> On O0, it is possible to inline if the user marked the function with 
> `always_inline`.
> Since CoroElide is kind of optimization, it should be OK to skip in O0.
> Out of curiosity, what's the reason that you want to remove it?

Coroutine functions cannot be inlined before splitting, even if it's marked 
"always_inline" (in fact, we should make it illegal to mark a coroutine 
"always_inline", because there is no guarantee that a coroutine can be fully 
inlined, GCC does that).


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D105066

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


[PATCH] D105066: [Coroutines] Remove CoroElide from O0 pipeline

2021-06-28 Thread Xun Li via Phabricator via cfe-commits
lxfind added a comment.

> Yeah, but it may be inlined  after splitting, which could trigger coro elide.

In O0, there is no inliner pass (after CoroSplit), so inlining should never 
happen.

>> in fact, we should make it illegal to mark a coroutine "always_inline", 
>> because there is no guarantee that a coroutine can be fully inlined, GCC 
>> does that
>
> To my understanding, it looks like that we shouldn't inline it since we 
> couldn't inline all parts of the function. Is this what you want to say?
> I think it may be a problem that we can't inline the full coroutine. But it's 
> not the reason to forbid it.

That's a separate topic though. Let's agree on this diff first and then I can 
explain more about the always_inline issue.

> ---
>
> Coro Elide is not defined in the standard (although it comes up in the 
> proposal). So it should be a compiler optimization. In this way, it should be 
> OK to remove it in O0.




Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D105066

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


[PATCH] D105066: [Coroutines] Remove CoroElide from O0 pipeline

2021-06-28 Thread Xun Li via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rG31eb696fc4cd: [Coroutines] Remove CoroElide from O0 pipeline 
(authored by lxfind).

Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D105066

Files:
  clang/test/CodeGenCoroutines/coro-newpm-pipeline.cpp
  llvm/lib/Passes/PassBuilder.cpp
  llvm/test/Transforms/Coroutines/smoketest.ll


Index: llvm/test/Transforms/Coroutines/smoketest.ll
===
--- llvm/test/Transforms/Coroutines/smoketest.ll
+++ llvm/test/Transforms/Coroutines/smoketest.ll
@@ -2,21 +2,21 @@
 ; levels and -enable-coroutines adds coroutine passes to the pipeline.
 ;
 ; RUN: opt < %s -disable-output -passes='default' -enable-coroutines \
-; RUN: -debug-pass-manager 2>&1 | FileCheck %s
+; RUN: -debug-pass-manager 2>&1 | FileCheck %s --check-prefixes=CHECK-ALL
 ; RUN: opt < %s -disable-output -passes='default' -enable-coroutines \
-; RUN: -debug-pass-manager 2>&1 | FileCheck %s
+; RUN: -debug-pass-manager 2>&1 | FileCheck %s 
--check-prefixes=CHECK-ALL,CHECK-OPT
 ; RUN: opt < %s -disable-output -passes='default' -enable-coroutines \
-; RUN: -debug-pass-manager 2>&1 | FileCheck %s
+; RUN: -debug-pass-manager 2>&1 | FileCheck %s 
--check-prefixes=CHECK-ALL,CHECK-OPT
 ; RUN: opt < %s -disable-output -passes='default' -enable-coroutines \
-; RUN: -debug-pass-manager 2>&1 | FileCheck %s
+; RUN: -debug-pass-manager 2>&1 | FileCheck %s 
--check-prefixes=CHECK-ALL,CHECK-OPT
 ; RUN: opt < %s -disable-output -debug-pass-manager \
 ; RUN: 
-passes='function(coro-early),cgscc(coro-split),function(coro-elide,coro-cleanup)'
 2>&1 \
-; RUN: | FileCheck %s
+; RUN: | FileCheck %s --check-prefixes=CHECK-ALL,CHECK-OPT
 
-; CHECK: CoroEarlyPass
-; CHECK: CoroSplitPass
-; CHECK: CoroElidePass
-; CHECK: CoroCleanupPass
+; CHECK-ALL: CoroEarlyPass
+; CHECK-ALL: CoroSplitPass
+; CHECK-OPT: CoroElidePass
+; CHECK-ALL: CoroCleanupPass
 
 define void @foo() {
   ret void
Index: llvm/lib/Passes/PassBuilder.cpp
===
--- llvm/lib/Passes/PassBuilder.cpp
+++ llvm/lib/Passes/PassBuilder.cpp
@@ -1986,7 +1986,6 @@
 
 CGSCCPassManager CGPM;
 CGPM.addPass(CoroSplitPass());
-CGPM.addPass(createCGSCCToFunctionPassAdaptor(CoroElidePass()));
 MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM)));
 
 MPM.addPass(createModuleToFunctionPassAdaptor(CoroCleanupPass()));
Index: clang/test/CodeGenCoroutines/coro-newpm-pipeline.cpp
===
--- clang/test/CodeGenCoroutines/coro-newpm-pipeline.cpp
+++ clang/test/CodeGenCoroutines/coro-newpm-pipeline.cpp
@@ -3,23 +3,23 @@
 
 // RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm-bc -o /dev/null 
\
 // RUN:   -fexperimental-new-pass-manager -fdebug-pass-manager -fcoroutines-ts 
\
-// RUN:   -O0 %s 2>&1 | FileCheck %s
+// RUN:   -O0 %s 2>&1 | FileCheck %s --check-prefixes=CHECK-ALL
 // RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm-bc -o /dev/null 
\
 // RUN:   -fexperimental-new-pass-manager -fdebug-pass-manager -fcoroutines-ts 
\
-// RUN:   -O1 %s 2>&1 | FileCheck %s
+// RUN:   -O1 %s 2>&1 | FileCheck %s --check-prefixes=CHECK-ALL,CHECK-OPT
 //
-// CHECK: Running pass:{{.*}}CoroEarlyPass
+// CHECK-ALL: Running pass:{{.*}}CoroEarlyPass
 //
 // The first coro-split pass enqueues a second run of the entire CGSCC 
pipeline.
-// CHECK: Running pass: CoroSplitPass on (_Z3foov)
-// CHECK: Running pass:{{.*}}CoroElidePass{{.*}} on {{.*}}_Z3foov{{.*}}
+// CHECK-ALL: Running pass: CoroSplitPass on (_Z3foov)
+// CHECK-OPT: Running pass:{{.*}}CoroElidePass{{.*}} on {{.*}}_Z3foov{{.*}}
 //
 // The second coro-split pass splits coroutine 'foo' into funclets
 // 'foo.resume', 'foo.destroy', and 'foo.cleanup'.
-// CHECK: Running pass: CoroSplitPass on (_Z3foov)
-// CHECK: Running pass:{{.*}}CoroElidePass{{.*}} on {{.*}}_Z3foov{{.*}}
+// CHECK-ALL: Running pass: CoroSplitPass on (_Z3foov)
+// CHECK-OPT: Running pass:{{.*}}CoroElidePass{{.*}} on {{.*}}_Z3foov{{.*}}
 //
-// CHECK: Running pass:{{.*}}CoroCleanupPass
+// CHECK-ALL: Running pass:{{.*}}CoroCleanupPass
 
 namespace std {
 namespace experimental {


Index: llvm/test/Transforms/Coroutines/smoketest.ll
===
--- llvm/test/Transforms/Coroutines/smoketest.ll
+++ llvm/test/Transforms/Coroutines/smoketest.ll
@@ -2,21 +2,21 @@
 ; levels and -enable-coroutines adds coroutine passes to the pipeline.
 ;
 ; RUN: opt < %s -disable-output -passes='default' -enable-coroutines \
-; RUN: -debug-pass-manager 2>&1 | FileCheck %s
+; RUN: -debug-pass-manager 2>&1 | FileCheck %s --check-prefixes=CHECK-ALL
 ; RUN: opt < %s -disable-output -passes='default' -enable-coroutines \
-; RUN: -debug-pass-man

[PATCH] D95807: [RFC][Coroutines] Add the newly generated SCCs back to the CGSCC work queue after CoroSplit actually happened

2021-06-28 Thread Xun Li via Phabricator via cfe-commits
lxfind updated this revision to Diff 355110.
lxfind added a comment.
Herald added subscribers: cfe-commits, qcolombet.
Herald added a project: clang.

After removing the legacy test command, I was finally able to update this 
patch. It's now ready for review. I will update the decription to reflect to 
the latest changes


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D95807

Files:
  clang/test/CodeGenCoroutines/coro-newpm-pipeline.cpp
  llvm/lib/Passes/PassBuilder.cpp
  llvm/lib/Transforms/Coroutines/CoroSplit.cpp
  llvm/test/Transforms/Coroutines/ArgAddr.ll
  llvm/test/Transforms/Coroutines/coro-alloc-with-param-O0.ll
  llvm/test/Transforms/Coroutines/coro-alloc-with-param-O2.ll
  llvm/test/Transforms/Coroutines/coro-alloca-01.ll
  llvm/test/Transforms/Coroutines/coro-alloca-02.ll
  llvm/test/Transforms/Coroutines/coro-alloca-03.ll
  llvm/test/Transforms/Coroutines/coro-alloca-04.ll
  llvm/test/Transforms/Coroutines/coro-alloca-05.ll
  llvm/test/Transforms/Coroutines/coro-alloca-06.ll
  llvm/test/Transforms/Coroutines/coro-alloca-07.ll
  llvm/test/Transforms/Coroutines/coro-alloca-08.ll
  llvm/test/Transforms/Coroutines/coro-async.ll
  llvm/test/Transforms/Coroutines/coro-byval-param.ll
  llvm/test/Transforms/Coroutines/coro-catchswitch-cleanuppad.ll
  llvm/test/Transforms/Coroutines/coro-catchswitch.ll
  llvm/test/Transforms/Coroutines/coro-debug.ll
  llvm/test/Transforms/Coroutines/coro-eh-aware-edge-split-00.ll
  llvm/test/Transforms/Coroutines/coro-eh-aware-edge-split-01.ll
  llvm/test/Transforms/Coroutines/coro-eh-aware-edge-split-02.ll
  llvm/test/Transforms/Coroutines/coro-frame-arrayalloca.ll
  llvm/test/Transforms/Coroutines/coro-frame-reuse-alloca-00.ll
  llvm/test/Transforms/Coroutines/coro-frame-reuse-alloca-01.ll
  llvm/test/Transforms/Coroutines/coro-frame-reuse-alloca-02.ll
  llvm/test/Transforms/Coroutines/coro-frame-reuse-alloca-03.ll
  llvm/test/Transforms/Coroutines/coro-frame-reuse-alloca-04.ll
  llvm/test/Transforms/Coroutines/coro-frame-reuse-alloca-05.ll
  llvm/test/Transforms/Coroutines/coro-frame-unreachable.ll
  llvm/test/Transforms/Coroutines/coro-frame.ll
  llvm/test/Transforms/Coroutines/coro-materialize.ll
  llvm/test/Transforms/Coroutines/coro-padding.ll
  llvm/test/Transforms/Coroutines/coro-param-copy.ll
  llvm/test/Transforms/Coroutines/coro-retcon-alloca.ll
  llvm/test/Transforms/Coroutines/coro-retcon-frame.ll
  llvm/test/Transforms/Coroutines/coro-retcon-once-value.ll
  llvm/test/Transforms/Coroutines/coro-retcon-once-value2.ll
  llvm/test/Transforms/Coroutines/coro-retcon-resume-values.ll
  llvm/test/Transforms/Coroutines/coro-retcon-resume-values2.ll
  llvm/test/Transforms/Coroutines/coro-retcon-unreachable.ll
  llvm/test/Transforms/Coroutines/coro-retcon-value.ll
  llvm/test/Transforms/Coroutines/coro-retcon.ll
  llvm/test/Transforms/Coroutines/coro-spill-after-phi.ll
  llvm/test/Transforms/Coroutines/coro-spill-corobegin.ll
  llvm/test/Transforms/Coroutines/coro-spill-defs-before-corobegin.ll
  llvm/test/Transforms/Coroutines/coro-spill-promise.ll
  llvm/test/Transforms/Coroutines/coro-split-00.ll
  llvm/test/Transforms/Coroutines/coro-split-02.ll
  llvm/test/Transforms/Coroutines/coro-split-alloc.ll
  llvm/test/Transforms/Coroutines/coro-split-dbg.ll
  llvm/test/Transforms/Coroutines/coro-split-eh-00.ll
  llvm/test/Transforms/Coroutines/coro-split-eh-01.ll
  llvm/test/Transforms/Coroutines/coro-split-hidden.ll
  llvm/test/Transforms/Coroutines/coro-split-musttail.ll
  llvm/test/Transforms/Coroutines/coro-split-musttail1.ll
  llvm/test/Transforms/Coroutines/coro-split-musttail2.ll
  llvm/test/Transforms/Coroutines/coro-split-musttail3.ll
  llvm/test/Transforms/Coroutines/coro-split-recursive.ll
  llvm/test/Transforms/Coroutines/coro-split-sink-lifetime-01.ll
  llvm/test/Transforms/Coroutines/coro-split-sink-lifetime-02.ll
  llvm/test/Transforms/Coroutines/coro-split-sink-lifetime-03.ll
  llvm/test/Transforms/Coroutines/coro-split-sink-lifetime-04.ll
  llvm/test/Transforms/Coroutines/coro-swifterror.ll
  llvm/test/Transforms/Coroutines/coro-zero-alloca.ll
  llvm/test/Transforms/Coroutines/no-suspend.ll
  llvm/test/Transforms/Coroutines/restart-trigger.ll

Index: llvm/test/Transforms/Coroutines/restart-trigger.ll
===
--- llvm/test/Transforms/Coroutines/restart-trigger.ll
+++ llvm/test/Transforms/Coroutines/restart-trigger.ll
@@ -1,11 +1,14 @@
 ; REQUIRES: asserts
 ; The following tests use the new pass manager, and verify that the coroutine
 ; passes re-run the CGSCC pipeline.
-; RUN: opt < %s -S -passes='default' -enable-coroutines -debug-only=coro-split 2>&1 | FileCheck %s
-; RUN: opt < %s -S -passes='default' -enable-coroutines -debug-only=coro-split 2>&1 | FileCheck %s
+; RUN: opt < %s -S -passes='default' -enable-coroutines -debug-only=coro-split 2>&1 | FileCheck --check-prefix=CHECK-NEWPM %s
+; RUN: opt < %s -S -p

[PATCH] D95807: [Coroutines] Add the newly generated SCCs back to the CGSCC work queue after CoroSplit actually happened

2021-06-29 Thread Xun Li via Phabricator via cfe-commits
lxfind added a comment.

In D95807#2846358 , @ChuanqiXu wrote:

>> note that we don't really need to run Inliner again on the ramp function 
>> after split
>
> This isn't accurate. The inline may run again for ramp function after split 
> and it's required by coro elide.

If there is an inlining opportunity, it should have happened pre-split, right? 
Is there any reason it didn't happen pre-split but only post-split?

> It seems like that we don't need the attribute `CORO_PRESPLIT_ATTR` any more, 
> do we? If yes, I think we should remove them.

It's still needed by the legacy pass manager. I don't want to break that yet.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D95807

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


[PATCH] D95807: [Coroutines] Add the newly generated SCCs back to the CGSCC work queue after CoroSplit actually happened

2021-06-29 Thread Xun Li via Phabricator via cfe-commits
lxfind added a comment.

In D95807#2849053 , @aeubanks wrote:

> this will run the function simplification pipeline twice on every single 
> function when coroutines are enabled, I don't think that's the intention
>
> I thought the intention was to do all the the re-adding of SCCs inside 
> CoroSplit.cpp, including the SCC with the function that was split

Good point. I was trying to avoid the second inliner on the coroutine ramp 
function. But I guess the cost will be bigger than the win.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D95807

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


[PATCH] D95807: [Coroutines] Add the newly generated SCCs back to the CGSCC work queue after CoroSplit actually happened

2021-06-29 Thread Xun Li via Phabricator via cfe-commits
lxfind added a comment.

> If coroutine ramp function couldn't get inlined, it would disable coroutine 
> elide optimization. Could you elaborate more on why do you want to do that?

Ramp function will eventually be inlined, but not when you run Inliner on the 
inlinee.
Let's say coroutine A calls coroutine B, and eventually we want to inline B 
into A so that we could perform CoroElide on A.
After B is split, we don't need to run inliner again on B. When we run inliner 
on A, A will inline B.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D95807

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


[PATCH] D95807: [Coroutines] Add the newly generated SCCs back to the CGSCC work queue after CoroSplit actually happened

2021-06-29 Thread Xun Li via Phabricator via cfe-commits
lxfind updated this revision to Diff 355431.
lxfind added a comment.

Put the post-split ramp function back to the CGSCC worklist


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D95807

Files:
  clang/test/CodeGenCoroutines/coro-newpm-pipeline.cpp
  llvm/lib/Passes/PassBuilder.cpp
  llvm/lib/Transforms/Coroutines/CoroSplit.cpp
  llvm/test/Transforms/Coroutines/ArgAddr.ll
  llvm/test/Transforms/Coroutines/coro-alloc-with-param-O0.ll
  llvm/test/Transforms/Coroutines/coro-alloc-with-param-O2.ll
  llvm/test/Transforms/Coroutines/coro-alloca-01.ll
  llvm/test/Transforms/Coroutines/coro-alloca-02.ll
  llvm/test/Transforms/Coroutines/coro-alloca-03.ll
  llvm/test/Transforms/Coroutines/coro-alloca-04.ll
  llvm/test/Transforms/Coroutines/coro-alloca-05.ll
  llvm/test/Transforms/Coroutines/coro-alloca-06.ll
  llvm/test/Transforms/Coroutines/coro-alloca-07.ll
  llvm/test/Transforms/Coroutines/coro-alloca-08.ll
  llvm/test/Transforms/Coroutines/coro-async.ll
  llvm/test/Transforms/Coroutines/coro-byval-param.ll
  llvm/test/Transforms/Coroutines/coro-catchswitch-cleanuppad.ll
  llvm/test/Transforms/Coroutines/coro-catchswitch.ll
  llvm/test/Transforms/Coroutines/coro-debug.ll
  llvm/test/Transforms/Coroutines/coro-eh-aware-edge-split-00.ll
  llvm/test/Transforms/Coroutines/coro-eh-aware-edge-split-01.ll
  llvm/test/Transforms/Coroutines/coro-eh-aware-edge-split-02.ll
  llvm/test/Transforms/Coroutines/coro-frame-arrayalloca.ll
  llvm/test/Transforms/Coroutines/coro-frame-reuse-alloca-00.ll
  llvm/test/Transforms/Coroutines/coro-frame-reuse-alloca-01.ll
  llvm/test/Transforms/Coroutines/coro-frame-reuse-alloca-02.ll
  llvm/test/Transforms/Coroutines/coro-frame-reuse-alloca-03.ll
  llvm/test/Transforms/Coroutines/coro-frame-reuse-alloca-04.ll
  llvm/test/Transforms/Coroutines/coro-frame-reuse-alloca-05.ll
  llvm/test/Transforms/Coroutines/coro-frame-unreachable.ll
  llvm/test/Transforms/Coroutines/coro-frame.ll
  llvm/test/Transforms/Coroutines/coro-materialize.ll
  llvm/test/Transforms/Coroutines/coro-padding.ll
  llvm/test/Transforms/Coroutines/coro-param-copy.ll
  llvm/test/Transforms/Coroutines/coro-retcon-alloca.ll
  llvm/test/Transforms/Coroutines/coro-retcon-frame.ll
  llvm/test/Transforms/Coroutines/coro-retcon-once-value.ll
  llvm/test/Transforms/Coroutines/coro-retcon-once-value2.ll
  llvm/test/Transforms/Coroutines/coro-retcon-resume-values.ll
  llvm/test/Transforms/Coroutines/coro-retcon-resume-values2.ll
  llvm/test/Transforms/Coroutines/coro-retcon-unreachable.ll
  llvm/test/Transforms/Coroutines/coro-retcon-value.ll
  llvm/test/Transforms/Coroutines/coro-retcon.ll
  llvm/test/Transforms/Coroutines/coro-spill-after-phi.ll
  llvm/test/Transforms/Coroutines/coro-spill-corobegin.ll
  llvm/test/Transforms/Coroutines/coro-spill-defs-before-corobegin.ll
  llvm/test/Transforms/Coroutines/coro-spill-promise.ll
  llvm/test/Transforms/Coroutines/coro-split-00.ll
  llvm/test/Transforms/Coroutines/coro-split-02.ll
  llvm/test/Transforms/Coroutines/coro-split-alloc.ll
  llvm/test/Transforms/Coroutines/coro-split-dbg.ll
  llvm/test/Transforms/Coroutines/coro-split-eh-00.ll
  llvm/test/Transforms/Coroutines/coro-split-eh-01.ll
  llvm/test/Transforms/Coroutines/coro-split-hidden.ll
  llvm/test/Transforms/Coroutines/coro-split-musttail.ll
  llvm/test/Transforms/Coroutines/coro-split-musttail1.ll
  llvm/test/Transforms/Coroutines/coro-split-musttail2.ll
  llvm/test/Transforms/Coroutines/coro-split-musttail3.ll
  llvm/test/Transforms/Coroutines/coro-split-recursive.ll
  llvm/test/Transforms/Coroutines/coro-split-sink-lifetime-01.ll
  llvm/test/Transforms/Coroutines/coro-split-sink-lifetime-02.ll
  llvm/test/Transforms/Coroutines/coro-split-sink-lifetime-03.ll
  llvm/test/Transforms/Coroutines/coro-split-sink-lifetime-04.ll
  llvm/test/Transforms/Coroutines/coro-swifterror.ll
  llvm/test/Transforms/Coroutines/coro-zero-alloca.ll
  llvm/test/Transforms/Coroutines/no-suspend.ll
  llvm/test/Transforms/Coroutines/restart-trigger.ll
  llvm/test/Transforms/Coroutines/smoketest.ll

Index: llvm/test/Transforms/Coroutines/smoketest.ll
===
--- llvm/test/Transforms/Coroutines/smoketest.ll
+++ llvm/test/Transforms/Coroutines/smoketest.ll
@@ -10,12 +10,16 @@
 ; RUN: opt < %s -disable-output -passes='default' -enable-coroutines \
 ; RUN: -debug-pass-manager 2>&1 | FileCheck %s --check-prefixes=CHECK-ALL,CHECK-OPT
 ; RUN: opt < %s -disable-output -debug-pass-manager \
-; RUN: -passes='function(coro-early),cgscc(coro-split),function(coro-elide,coro-cleanup)' 2>&1 \
+; RUN: -passes='function(coro-early),function(coro-elide),cgscc(coro-split),function(coro-cleanup)' 2>&1 \
 ; RUN: | FileCheck %s --check-prefixes=CHECK-ALL,CHECK-OPT
 
+; note that we run CoroElidePass before CoroSplitPass. This is because CoroElidePass is part of
+; function simplification pipeline, which runs before 

[PATCH] D95807: [Coroutines] Add the newly generated SCCs back to the CGSCC work queue after CoroSplit actually happened

2021-06-30 Thread Xun Li via Phabricator via cfe-commits
lxfind added inline comments.



Comment at: llvm/lib/Transforms/Coroutines/CoroSplit.cpp:2112-2114
 StringRef Value = Attr.getValueAsString();
 LLVM_DEBUG(dbgs() << "CoroSplit: Processing coroutine '" << F.getName()
   << "' state: " << Value << "\n");

ChuanqiXu wrote:
> Refactor this into:
> ```
> LLVM_DEBUG(dbgs() << "CoroSplit: Processing coroutine '" << F.getName()
>   << "' state: " << Attr.getValueAsString() << "\n");
> ```
> could erase an warning in release build.
Good catch. How did you catch this? It seems like I don't see warning on my Mac 
by default.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D95807

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


[PATCH] D95807: [Coroutines] Add the newly generated SCCs back to the CGSCC work queue after CoroSplit actually happened

2021-06-30 Thread Xun Li via Phabricator via cfe-commits
lxfind updated this revision to Diff 355607.
lxfind added a comment.

fix warning


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D95807

Files:
  clang/test/CodeGenCoroutines/coro-newpm-pipeline.cpp
  llvm/lib/Passes/PassBuilder.cpp
  llvm/lib/Transforms/Coroutines/CoroSplit.cpp
  llvm/test/Transforms/Coroutines/ArgAddr.ll
  llvm/test/Transforms/Coroutines/coro-alloc-with-param-O0.ll
  llvm/test/Transforms/Coroutines/coro-alloc-with-param-O2.ll
  llvm/test/Transforms/Coroutines/coro-alloca-01.ll
  llvm/test/Transforms/Coroutines/coro-alloca-02.ll
  llvm/test/Transforms/Coroutines/coro-alloca-03.ll
  llvm/test/Transforms/Coroutines/coro-alloca-04.ll
  llvm/test/Transforms/Coroutines/coro-alloca-05.ll
  llvm/test/Transforms/Coroutines/coro-alloca-06.ll
  llvm/test/Transforms/Coroutines/coro-alloca-07.ll
  llvm/test/Transforms/Coroutines/coro-alloca-08.ll
  llvm/test/Transforms/Coroutines/coro-async.ll
  llvm/test/Transforms/Coroutines/coro-byval-param.ll
  llvm/test/Transforms/Coroutines/coro-catchswitch-cleanuppad.ll
  llvm/test/Transforms/Coroutines/coro-catchswitch.ll
  llvm/test/Transforms/Coroutines/coro-debug.ll
  llvm/test/Transforms/Coroutines/coro-eh-aware-edge-split-00.ll
  llvm/test/Transforms/Coroutines/coro-eh-aware-edge-split-01.ll
  llvm/test/Transforms/Coroutines/coro-eh-aware-edge-split-02.ll
  llvm/test/Transforms/Coroutines/coro-frame-arrayalloca.ll
  llvm/test/Transforms/Coroutines/coro-frame-reuse-alloca-00.ll
  llvm/test/Transforms/Coroutines/coro-frame-reuse-alloca-01.ll
  llvm/test/Transforms/Coroutines/coro-frame-reuse-alloca-02.ll
  llvm/test/Transforms/Coroutines/coro-frame-reuse-alloca-03.ll
  llvm/test/Transforms/Coroutines/coro-frame-reuse-alloca-04.ll
  llvm/test/Transforms/Coroutines/coro-frame-reuse-alloca-05.ll
  llvm/test/Transforms/Coroutines/coro-frame-unreachable.ll
  llvm/test/Transforms/Coroutines/coro-frame.ll
  llvm/test/Transforms/Coroutines/coro-materialize.ll
  llvm/test/Transforms/Coroutines/coro-padding.ll
  llvm/test/Transforms/Coroutines/coro-param-copy.ll
  llvm/test/Transforms/Coroutines/coro-retcon-alloca.ll
  llvm/test/Transforms/Coroutines/coro-retcon-frame.ll
  llvm/test/Transforms/Coroutines/coro-retcon-once-value.ll
  llvm/test/Transforms/Coroutines/coro-retcon-once-value2.ll
  llvm/test/Transforms/Coroutines/coro-retcon-resume-values.ll
  llvm/test/Transforms/Coroutines/coro-retcon-resume-values2.ll
  llvm/test/Transforms/Coroutines/coro-retcon-unreachable.ll
  llvm/test/Transforms/Coroutines/coro-retcon-value.ll
  llvm/test/Transforms/Coroutines/coro-retcon.ll
  llvm/test/Transforms/Coroutines/coro-spill-after-phi.ll
  llvm/test/Transforms/Coroutines/coro-spill-corobegin.ll
  llvm/test/Transforms/Coroutines/coro-spill-defs-before-corobegin.ll
  llvm/test/Transforms/Coroutines/coro-spill-promise.ll
  llvm/test/Transforms/Coroutines/coro-split-00.ll
  llvm/test/Transforms/Coroutines/coro-split-02.ll
  llvm/test/Transforms/Coroutines/coro-split-alloc.ll
  llvm/test/Transforms/Coroutines/coro-split-dbg.ll
  llvm/test/Transforms/Coroutines/coro-split-eh-00.ll
  llvm/test/Transforms/Coroutines/coro-split-eh-01.ll
  llvm/test/Transforms/Coroutines/coro-split-hidden.ll
  llvm/test/Transforms/Coroutines/coro-split-musttail.ll
  llvm/test/Transforms/Coroutines/coro-split-musttail1.ll
  llvm/test/Transforms/Coroutines/coro-split-musttail2.ll
  llvm/test/Transforms/Coroutines/coro-split-musttail3.ll
  llvm/test/Transforms/Coroutines/coro-split-recursive.ll
  llvm/test/Transforms/Coroutines/coro-split-sink-lifetime-01.ll
  llvm/test/Transforms/Coroutines/coro-split-sink-lifetime-02.ll
  llvm/test/Transforms/Coroutines/coro-split-sink-lifetime-03.ll
  llvm/test/Transforms/Coroutines/coro-split-sink-lifetime-04.ll
  llvm/test/Transforms/Coroutines/coro-swifterror.ll
  llvm/test/Transforms/Coroutines/coro-zero-alloca.ll
  llvm/test/Transforms/Coroutines/no-suspend.ll
  llvm/test/Transforms/Coroutines/restart-trigger.ll
  llvm/test/Transforms/Coroutines/smoketest.ll

Index: llvm/test/Transforms/Coroutines/smoketest.ll
===
--- llvm/test/Transforms/Coroutines/smoketest.ll
+++ llvm/test/Transforms/Coroutines/smoketest.ll
@@ -10,12 +10,16 @@
 ; RUN: opt < %s -disable-output -passes='default' -enable-coroutines \
 ; RUN: -debug-pass-manager 2>&1 | FileCheck %s --check-prefixes=CHECK-ALL,CHECK-OPT
 ; RUN: opt < %s -disable-output -debug-pass-manager \
-; RUN: -passes='function(coro-early),cgscc(coro-split),function(coro-elide,coro-cleanup)' 2>&1 \
+; RUN: -passes='function(coro-early),function(coro-elide),cgscc(coro-split),function(coro-cleanup)' 2>&1 \
 ; RUN: | FileCheck %s --check-prefixes=CHECK-ALL,CHECK-OPT
 
+; note that we run CoroElidePass before CoroSplitPass. This is because CoroElidePass is part of
+; function simplification pipeline, which runs before CoroSplitPass. And since @foo is not
+; a corout

[PATCH] D95807: [Coroutines] Add the newly generated SCCs back to the CGSCC work queue after CoroSplit actually happened

2021-06-30 Thread Xun Li via Phabricator via cfe-commits
lxfind added inline comments.



Comment at: llvm/lib/Transforms/Coroutines/CoroSplit.cpp:2001
 
-if ((Shape.ABI == coro::ABI::Async || Shape.ABI == coro::ABI::Retcon ||
- Shape.ABI == coro::ABI::RetconOnce) &&
-!Shape.CoroSuspends.empty()) {
-  // Run the CGSCC pipeline on the newly split functions.
-  // All clones will be in the same RefSCC, so choose a random clone.
-  UR.RCWorklist.insert(CG.lookupRefSCC(CG.get(*Clones[0])));
+if (!Shape.CoroSuspends.empty()) {
+  // Run the CGSCC pipeline on the original and newly split functions.

ychen wrote:
> aeubanks wrote:
> > ChuanqiXu wrote:
> > > I am not familiar with the Shape.ABI other than coro::ABI:switch. But the 
> > > diff line seems strange, it looks like that condition gets weaker.
> > I believe that's intentional, and a big part of this patch. We want to 
> > re-add the current SCC (and the split SCCs) any time we split an SCC. 
> > Before we weren't properly doing that.
> I got your point. So "// All clones will be in the same RefSCC " : this 
> is not accurate I think?
Note that previously this is done only for Async, Retcon and RetconOnce ABIs, 
not for the Switch ABI.
I guess that's accurate for those ABIs? But for Switch ABI this is not true.
And before we were not adding back the split functions to the pipeline to be 
properly optimized. Now we are dong that. This should help improve the 
performance of the post-split functions.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D95807

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


[PATCH] D95807: [Coroutines] Add the newly generated SCCs back to the CGSCC work queue after CoroSplit actually happened

2021-06-30 Thread Xun Li via Phabricator via cfe-commits
This revision was landed with ongoing or failed builds.
This revision was automatically updated to reflect the committed changes.
Closed by commit rG822b92aae439: [Coroutines] Add the newly generated SCCs back 
to the CGSCC work queue after… (authored by lxfind).

Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D95807

Files:
  clang/test/CodeGenCoroutines/coro-newpm-pipeline.cpp
  llvm/lib/Passes/PassBuilder.cpp
  llvm/lib/Transforms/Coroutines/CoroSplit.cpp
  llvm/test/Transforms/Coroutines/ArgAddr.ll
  llvm/test/Transforms/Coroutines/coro-alloc-with-param-O0.ll
  llvm/test/Transforms/Coroutines/coro-alloc-with-param-O2.ll
  llvm/test/Transforms/Coroutines/coro-alloca-01.ll
  llvm/test/Transforms/Coroutines/coro-alloca-02.ll
  llvm/test/Transforms/Coroutines/coro-alloca-03.ll
  llvm/test/Transforms/Coroutines/coro-alloca-04.ll
  llvm/test/Transforms/Coroutines/coro-alloca-05.ll
  llvm/test/Transforms/Coroutines/coro-alloca-06.ll
  llvm/test/Transforms/Coroutines/coro-alloca-07.ll
  llvm/test/Transforms/Coroutines/coro-alloca-08.ll
  llvm/test/Transforms/Coroutines/coro-async.ll
  llvm/test/Transforms/Coroutines/coro-byval-param.ll
  llvm/test/Transforms/Coroutines/coro-catchswitch-cleanuppad.ll
  llvm/test/Transforms/Coroutines/coro-catchswitch.ll
  llvm/test/Transforms/Coroutines/coro-debug.ll
  llvm/test/Transforms/Coroutines/coro-eh-aware-edge-split-00.ll
  llvm/test/Transforms/Coroutines/coro-eh-aware-edge-split-01.ll
  llvm/test/Transforms/Coroutines/coro-eh-aware-edge-split-02.ll
  llvm/test/Transforms/Coroutines/coro-frame-arrayalloca.ll
  llvm/test/Transforms/Coroutines/coro-frame-reuse-alloca-00.ll
  llvm/test/Transforms/Coroutines/coro-frame-reuse-alloca-01.ll
  llvm/test/Transforms/Coroutines/coro-frame-reuse-alloca-02.ll
  llvm/test/Transforms/Coroutines/coro-frame-reuse-alloca-03.ll
  llvm/test/Transforms/Coroutines/coro-frame-reuse-alloca-04.ll
  llvm/test/Transforms/Coroutines/coro-frame-reuse-alloca-05.ll
  llvm/test/Transforms/Coroutines/coro-frame-unreachable.ll
  llvm/test/Transforms/Coroutines/coro-frame.ll
  llvm/test/Transforms/Coroutines/coro-materialize.ll
  llvm/test/Transforms/Coroutines/coro-padding.ll
  llvm/test/Transforms/Coroutines/coro-param-copy.ll
  llvm/test/Transforms/Coroutines/coro-retcon-alloca.ll
  llvm/test/Transforms/Coroutines/coro-retcon-frame.ll
  llvm/test/Transforms/Coroutines/coro-retcon-once-value.ll
  llvm/test/Transforms/Coroutines/coro-retcon-once-value2.ll
  llvm/test/Transforms/Coroutines/coro-retcon-resume-values.ll
  llvm/test/Transforms/Coroutines/coro-retcon-resume-values2.ll
  llvm/test/Transforms/Coroutines/coro-retcon-unreachable.ll
  llvm/test/Transforms/Coroutines/coro-retcon-value.ll
  llvm/test/Transforms/Coroutines/coro-retcon.ll
  llvm/test/Transforms/Coroutines/coro-spill-after-phi.ll
  llvm/test/Transforms/Coroutines/coro-spill-corobegin.ll
  llvm/test/Transforms/Coroutines/coro-spill-defs-before-corobegin.ll
  llvm/test/Transforms/Coroutines/coro-spill-promise.ll
  llvm/test/Transforms/Coroutines/coro-split-00.ll
  llvm/test/Transforms/Coroutines/coro-split-02.ll
  llvm/test/Transforms/Coroutines/coro-split-alloc.ll
  llvm/test/Transforms/Coroutines/coro-split-dbg.ll
  llvm/test/Transforms/Coroutines/coro-split-eh-00.ll
  llvm/test/Transforms/Coroutines/coro-split-eh-01.ll
  llvm/test/Transforms/Coroutines/coro-split-hidden.ll
  llvm/test/Transforms/Coroutines/coro-split-musttail.ll
  llvm/test/Transforms/Coroutines/coro-split-musttail1.ll
  llvm/test/Transforms/Coroutines/coro-split-musttail2.ll
  llvm/test/Transforms/Coroutines/coro-split-musttail3.ll
  llvm/test/Transforms/Coroutines/coro-split-recursive.ll
  llvm/test/Transforms/Coroutines/coro-split-sink-lifetime-01.ll
  llvm/test/Transforms/Coroutines/coro-split-sink-lifetime-02.ll
  llvm/test/Transforms/Coroutines/coro-split-sink-lifetime-03.ll
  llvm/test/Transforms/Coroutines/coro-split-sink-lifetime-04.ll
  llvm/test/Transforms/Coroutines/coro-swifterror.ll
  llvm/test/Transforms/Coroutines/coro-zero-alloca.ll
  llvm/test/Transforms/Coroutines/no-suspend.ll
  llvm/test/Transforms/Coroutines/restart-trigger.ll
  llvm/test/Transforms/Coroutines/smoketest.ll

Index: llvm/test/Transforms/Coroutines/smoketest.ll
===
--- llvm/test/Transforms/Coroutines/smoketest.ll
+++ llvm/test/Transforms/Coroutines/smoketest.ll
@@ -10,12 +10,16 @@
 ; RUN: opt < %s -disable-output -passes='default' -enable-coroutines \
 ; RUN: -debug-pass-manager 2>&1 | FileCheck %s --check-prefixes=CHECK-ALL,CHECK-OPT
 ; RUN: opt < %s -disable-output -debug-pass-manager \
-; RUN: -passes='function(coro-early),cgscc(coro-split),function(coro-elide,coro-cleanup)' 2>&1 \
+; RUN: -passes='function(coro-early),function(coro-elide),cgscc(coro-split),function(coro-cleanup)' 2>&1 \
 ; RUN: | FileCheck %s --check-prefixes=CHECK-ALL,CHECK-OPT
 
+; note that we run

[PATCH] D108696: [Coroutines] [Frontend] Lookup in std namespace first

2021-11-03 Thread Xun Li via Phabricator via cfe-commits
lxfind accepted this revision.
lxfind added a comment.

I also agree that we should try to keep the compiler simple and not support the 
complicated case.
It should be fairly straightforward for a codebase to update fully to use std 
instead of std::experimental (we have a large coroutine codebase as well). 
Given that everyone is mostly supportive, I will accept the change.


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

https://reviews.llvm.org/D108696

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


[PATCH] D97915: [Coroutines] Handle overaligned frame allocation

2021-03-04 Thread Xun Li via Phabricator via cfe-commits
lxfind added a comment.

Could you describe in more detail what problem this patch solves?
Also, since you are adding a new intrinsics, please also update the coroutine 
documentation regarding this new intrinsics.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D97915

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


  1   2   >