[PATCH] D30809: [coroutines] Add codegen for await and yield expressions

2017-03-26 Thread Gor Nishanov via Phabricator via cfe-commits
GorNishanov closed this revision.
GorNishanov added a comment.

Commit: r298784


https://reviews.llvm.org/D30809



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


[PATCH] D30809: [coroutines] Add codegen for await and yield expressions

2017-03-25 Thread Gor Nishanov via Phabricator via cfe-commits
GorNishanov updated this revision to Diff 93061.
GorNishanov added a comment.

Thank you very much for the review!

Merged with the top of the trunk and preparing to land


https://reviews.llvm.org/D30809

Files:
  lib/CodeGen/CGCoroutine.cpp
  lib/CodeGen/CGExprAgg.cpp
  lib/CodeGen/CGExprComplex.cpp
  lib/CodeGen/CGExprScalar.cpp
  lib/CodeGen/CodeGenFunction.h
  test/CodeGenCoroutines/coro-await.cpp

Index: test/CodeGenCoroutines/coro-await.cpp
===
--- /dev/null
+++ test/CodeGenCoroutines/coro-await.cpp
@@ -0,0 +1,230 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fcoroutines-ts -std=c++14 -emit-llvm %s -o - -disable-llvm-passes | FileCheck %s
+
+namespace std {
+namespace experimental {
+template 
+struct coroutine_traits;
+
+template  struct coroutine_handle;
+
+template <>
+struct coroutine_handle {
+  void *ptr;
+  static coroutine_handle from_address(void *);
+};
+
+template 
+struct coroutine_handle : coroutine_handle<> {
+  static coroutine_handle from_address(void *);
+};
+
+}
+}
+
+struct suspend_always {
+  int stuff;
+  bool await_ready();
+  void await_suspend(std::experimental::coroutine_handle<>);
+  void await_resume();
+};
+
+template<>
+struct std::experimental::coroutine_traits {
+  struct promise_type {
+void get_return_object();
+suspend_always initial_suspend();
+suspend_always final_suspend();
+void return_void();
+  };
+};
+
+// CHECK-LABEL: f0(
+extern "C" void f0() {
+
+  co_await suspend_always{};
+  // See if we need to suspend:
+  // --
+  // CHECK: %[[READY:.+]] = call zeroext i1 @_ZN14suspend_always11await_readyEv(%struct.suspend_always* %[[AWAITABLE:.+]])
+  // CHECK: br i1 %[[READY]], label %[[READY_BB:.+]], label %[[SUSPEND_BB:.+]]
+
+  // If we are suspending:
+  // -
+  // CHECK: [[SUSPEND_BB]]:
+  // CHECK: %[[SUSPEND_ID:.+]] = call token @llvm.coro.save(
+  // ---
+  // Build the coroutine handle and pass it to await_suspend
+  // ---
+  // CHECK: %[[FRAME:.+]] = call i8* @llvm.coro.frame()
+  // CHECK: call i8* @_ZNSt12experimental16coroutine_handleINS_16coroutine_traitsIJvEE12promise_typeEE12from_addressEPv(i8* %[[FRAME]])
+  //   ... many lines of code to coerce coroutine_handle into an i8* scalar
+  // CHECK: %[[CH:.+]] = load i8*, i8** %{{.+}}
+  // CHECK: call void @_ZN14suspend_always13await_suspendENSt12experimental16coroutine_handleIvEE(%struct.suspend_always* %[[AWAITABLE]], i8* %[[CH]])
+  // -
+  // Generate a suspend point:
+  // -
+  // CHECK: %[[OUTCOME:.+]] = call i8 @llvm.coro.suspend(token %[[SUSPEND_ID]], i1 false)
+  // CHECK: switch i8 %[[OUTCOME]], label %[[RET_BB:.+]] [
+  // CHECK:   i8 0, label %[[READY_BB]]
+  // CHECK:   i8 1, label %[[CLEANUP_BB:.+]]
+  // CHECK: ]
+
+  // Cleanup code goes here:
+  // ---
+  // CHECK: [[CLEANUP_BB]]:
+
+  // When coroutine is resumed, call await_resume
+  // --
+  // CHECK: [[READY_BB]]:
+  // CHECK:  call void @_ZN14suspend_always12await_resumeEv(%struct.suspend_always* %[[AWAITABLE]])
+}
+
+struct suspend_maybe {
+  float stuff;
+  ~suspend_maybe();
+  bool await_ready();
+  bool await_suspend(std::experimental::coroutine_handle<>);
+  void await_resume();
+};
+
+
+template<>
+struct std::experimental::coroutine_traits {
+  struct promise_type {
+void get_return_object();
+suspend_always initial_suspend();
+suspend_always final_suspend();
+void return_void();
+suspend_maybe yield_value(int);
+  };
+};
+
+// CHECK-LABEL: f1(
+extern "C" void f1(int) {
+  co_yield 42;
+  // CHECK: %[[PROMISE:.+]] = alloca %"struct.std::experimental::coroutine_traits::promise_type"
+  // CHECK: call void @_ZNSt12experimental16coroutine_traitsIJviEE12promise_type11yield_valueEi(%struct.suspend_maybe* sret %[[AWAITER:.+]], %"struct.std::experimental::coroutine_traits::promise_type"* %[[PROMISE]], i32 42)
+
+  // See if we need to suspend:
+  // --
+  // CHECK: %[[READY:.+]] = call zeroext i1 @_ZN13suspend_maybe11await_readyEv(%struct.suspend_maybe* %[[AWAITABLE]])
+  // CHECK: br i1 %[[READY]], label %[[READY_BB:.+]], label %[[SUSPEND_BB:.+]]
+
+  // If we are suspending:
+  // -
+  // CHECK: [[SUSPEND_BB]]:
+  // CHECK: %[[SUSPEND_ID:.+]] = call token @llvm.coro.save(
+  // ---
+  // Build the coroutine handle and pass it to await_suspend
+  // ---
+  // CHECK: %[[FRAME:.+]] = call i8* @llvm.coro.frame()
+  // CHECK: call i8* @_ZNSt12experimental16coroutine_handleINS_16coroutine_traitsIJviEE12promise_typeEE12from_addressEPv(i8* %[[FRAME]])
+  //   ... many lines of code to coerce coroutine_handle into an i8* scalar
+  // CHECK: %[[CH:.+]] = load i8*, i8** %{{.+}}
+  // CHECK: %[[YES:.+]] = call zeroext i1 @_ZN13suspend_maybe13await_suspendENSt12

[PATCH] D30809: [coroutines] Add codegen for await and yield expressions

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

Looks great, thanks.


https://reviews.llvm.org/D30809



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


[PATCH] D30809: [coroutines] Add codegen for await and yield expressions

2017-03-20 Thread Gor Nishanov via Phabricator via cfe-commits
GorNishanov marked 2 inline comments as done.
GorNishanov added a comment.

Looks good now?


https://reviews.llvm.org/D30809



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


[PATCH] D30809: [coroutines] Add codegen for await and yield expressions

2017-03-14 Thread Gor Nishanov via Phabricator via cfe-commits
GorNishanov marked 4 inline comments as done.
GorNishanov added inline comments.



Comment at: lib/CodeGen/CGCoroutine.cpp:26
+enum class AwaitKind { Init, Normal, Yield, Final };
+char const *AwaitKindStr[] = {"init", "await", "yield", "final"};
+}

majnemer wrote:
> I'd move this into buildSuspendSuffixStr.
I prefer to keep AwaitKindStr here, so it is trivial to visually inspect that 
the order in the array matches the order of the enum.



Comment at: lib/CodeGen/CGCoroutine.cpp:85
+  unsigned No = 0;
+  StringRef AwaitKindStr = 0;
+  switch (Kind) {

rjmccall wrote:
> majnemer wrote:
> > I'd just let the default constructor do its thing.
> Agreed.  Assigning 0 to a StringRef reads very wrong.
I got rid of this one and now use a llvm::StringLiteral array to get names.



Comment at: lib/CodeGen/CGCoroutine.cpp:203
+break;
+  }
+  return nullptr;

rjmccall wrote:
> This function should return an RValue and take an AggValueSlot, just like 
> every other generically-typed expression emitter.  That way, you can just use 
> EmitAnyExpr here instead of inlining two of three cases.
> 
> And you should implement it in CGExprComplex, of course, and add that as a 
> test case.
Thank you! That was very helpful. The code shrunk and looks nicer now. Not 
sure, if ignoreResult is needed, but, I added it as well to match EmitAnyExpr.


https://reviews.llvm.org/D30809



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


[PATCH] D30809: [coroutines] Add codegen for await and yield expressions

2017-03-14 Thread Gor Nishanov via Phabricator via cfe-commits
GorNishanov updated this revision to Diff 91790.
GorNishanov added a comment.

- reworked EmitAwait/Yield to has the signature similar to EmitAnyExpr
- await expresions now support _Complex types.
- s/Suffix/Prefix in buildCoroutineSuffix, since it was actually building a 
prefix
- buildCoroutineSuffix uses literal array for names, as opposed to getting 
names from the switch stmt.
- added tests to test for Aggr, Scalar and Complex
- added tests for codegen for operator co_await
- sprinkled more comments

Thank you very much for your feedback, John and David!


https://reviews.llvm.org/D30809

Files:
  lib/CodeGen/CGCoroutine.cpp
  lib/CodeGen/CGExprAgg.cpp
  lib/CodeGen/CGExprComplex.cpp
  lib/CodeGen/CGExprScalar.cpp
  lib/CodeGen/CodeGenFunction.h
  test/CodeGenCoroutines/coro-await.cpp

Index: test/CodeGenCoroutines/coro-await.cpp
===
--- /dev/null
+++ test/CodeGenCoroutines/coro-await.cpp
@@ -0,0 +1,230 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fcoroutines-ts -std=c++14 -emit-llvm %s -o - -disable-llvm-passes | FileCheck %s
+
+namespace std {
+namespace experimental {
+template 
+struct coroutine_traits;
+
+template  struct coroutine_handle;
+
+template <>
+struct coroutine_handle {
+  void *ptr;
+  static coroutine_handle from_address(void *);
+};
+
+template 
+struct coroutine_handle : coroutine_handle<> {
+  static coroutine_handle from_address(void *);
+};
+
+}
+}
+
+struct suspend_always {
+  int stuff;
+  bool await_ready();
+  void await_suspend(std::experimental::coroutine_handle<>);
+  void await_resume();
+};
+
+template<>
+struct std::experimental::coroutine_traits {
+  struct promise_type {
+void get_return_object();
+suspend_always initial_suspend();
+suspend_always final_suspend();
+void return_void();
+  };
+};
+
+// CHECK-LABEL: f0(
+extern "C" void f0() {
+
+  co_await suspend_always{};
+  // See if we need to suspend:
+  // --
+  // CHECK: %[[READY:.+]] = call zeroext i1 @_ZN14suspend_always11await_readyEv(%struct.suspend_always* %[[AWAITABLE:.+]])
+  // CHECK: br i1 %[[READY]], label %[[READY_BB:.+]], label %[[SUSPEND_BB:.+]]
+
+  // If we are suspending:
+  // -
+  // CHECK: [[SUSPEND_BB]]:
+  // CHECK: %[[SUSPEND_ID:.+]] = call token @llvm.coro.save(
+  // ---
+  // Build the coroutine handle and pass it to await_suspend
+  // ---
+  // CHECK: %[[FRAME:.+]] = call i8* @llvm.coro.frame()
+  // CHECK: call i8* @_ZNSt12experimental16coroutine_handleINS_16coroutine_traitsIJvEE12promise_typeEE12from_addressEPv(i8* %[[FRAME]])
+  //   ... many lines of code to coerce coroutine_handle into an i8* scalar
+  // CHECK: %[[CH:.+]] = load i8*, i8** %{{.+}}
+  // CHECK: call void @_ZN14suspend_always13await_suspendENSt12experimental16coroutine_handleIvEE(%struct.suspend_always* %[[AWAITABLE]], i8* %[[CH]])
+  // -
+  // Generate a suspend point:
+  // -
+  // CHECK: %[[OUTCOME:.+]] = call i8 @llvm.coro.suspend(token %[[SUSPEND_ID]], i1 false)
+  // CHECK: switch i8 %[[OUTCOME]], label %[[RET_BB:.+]] [
+  // CHECK:   i8 0, label %[[READY_BB]]
+  // CHECK:   i8 1, label %[[CLEANUP_BB:.+]]
+  // CHECK: ]
+
+  // Cleanup code goes here:
+  // ---
+  // CHECK: [[CLEANUP_BB]]:
+
+  // When coroutine is resumed, call await_resume
+  // --
+  // CHECK: [[READY_BB]]:
+  // CHECK:  call void @_ZN14suspend_always12await_resumeEv(%struct.suspend_always* %[[AWAITABLE]])
+}
+
+struct suspend_maybe {
+  float stuff;
+  ~suspend_maybe();
+  bool await_ready();
+  bool await_suspend(std::experimental::coroutine_handle<>);
+  void await_resume();
+};
+
+
+template<>
+struct std::experimental::coroutine_traits {
+  struct promise_type {
+void get_return_object();
+suspend_always initial_suspend();
+suspend_always final_suspend();
+void return_void();
+suspend_maybe yield_value(int);
+  };
+};
+
+// CHECK-LABEL: f1(
+extern "C" void f1(int) {
+  co_yield 42;
+  // CHECK: %[[PROMISE:.+]] = alloca %"struct.std::experimental::coroutine_traits::promise_type"
+  // CHECK: call void @_ZNSt12experimental16coroutine_traitsIJviEE12promise_type11yield_valueEi(%struct.suspend_maybe* sret %[[AWAITER:.+]], %"struct.std::experimental::coroutine_traits::promise_type"* %[[PROMISE]], i32 42)
+
+  // See if we need to suspend:
+  // --
+  // CHECK: %[[READY:.+]] = call zeroext i1 @_ZN13suspend_maybe11await_readyEv(%struct.suspend_maybe* %[[AWAITABLE]])
+  // CHECK: br i1 %[[READY]], label %[[READY_BB:.+]], label %[[SUSPEND_BB:.+]]
+
+  // If we are suspending:
+  // -
+  // CHECK: [[SUSPEND_BB]]:
+  // CHECK: %[[SUSPEND_ID:.+]] = call token @llvm.coro.save(
+  // ---
+  // Build the coroutine handle and pass it to await_suspend
+  // ---
+  // CHE

[PATCH] D30809: [coroutines] Add codegen for await and yield expressions

2017-03-14 Thread John McCall via Phabricator via cfe-commits
rjmccall added inline comments.



Comment at: lib/CodeGen/CGCoroutine.cpp:32
 
 struct CGCoroData {
+  AwaitKind CurrentAwaitKind = AwaitKind::Init;

GorNishanov wrote:
> majnemer wrote:
> > Shouldn't this struct be in an anonymous namespace?
> It is forward declared in CodeGenFunction.h and CodeGenFunction class holds a 
> unique_ptr to CGCoroData as a member.
> Here is the snippet from CodeGenFunction.h:
> 
> ```
>   // Holds coroutine data if the current function is a coroutine. We use a
>   // wrapper to manage its lifetime, so that we don't have to define 
> CGCoroData
>   // in this header.
>   struct CGCoroInfo {
> std::unique_ptr Data;
> CGCoroInfo();
> ~CGCoroInfo();
>   };
>   CGCoroInfo CurCoro;
> ```
If it's already forward-declared, you should check here that you're matching it 
by doing:

  struct CodeGen::CGCoroData {
...
  };

instead of making namespace declarations.



Comment at: lib/CodeGen/CGCoroutine.cpp:42
+  unsigned YieldNum = 0;
   unsigned CoreturnCount = 0;
 

Comments about what these mean would be useful.



Comment at: lib/CodeGen/CGCoroutine.cpp:85
+  unsigned No = 0;
+  StringRef AwaitKindStr = 0;
+  switch (Kind) {

majnemer wrote:
> I'd just let the default constructor do its thing.
Agreed.  Assigning 0 to a StringRef reads very wrong.



Comment at: lib/CodeGen/CGCoroutine.cpp:203
+break;
+  }
+  return nullptr;

This function should return an RValue and take an AggValueSlot, just like every 
other generically-typed expression emitter.  That way, you can just use 
EmitAnyExpr here instead of inlining two of three cases.

And you should implement it in CGExprComplex, of course, and add that as a test 
case.


https://reviews.llvm.org/D30809



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


[PATCH] D30809: [coroutines] Add codegen for await and yield expressions

2017-03-13 Thread David Majnemer via Phabricator via cfe-commits
majnemer added inline comments.



Comment at: lib/CodeGen/CGCoroutine.cpp:85
+  unsigned No = 0;
+  StringRef AwaitKindStr = 0;
+  switch (Kind) {

I'd just let the default constructor do its thing.


https://reviews.llvm.org/D30809



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


[PATCH] D30809: [coroutines] Add codegen for await and yield expressions

2017-03-12 Thread Gor Nishanov via Phabricator via cfe-commits
GorNishanov marked an inline comment as done.
GorNishanov added inline comments.



Comment at: lib/CodeGen/CGCoroutine.cpp:85
+  unsigned No = 0;
+  const char* AwaitKindStr = 0;
+  switch (Kind) {

majnemer wrote:
> I'd use a StringRef here.
StringRef it is.



https://reviews.llvm.org/D30809



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


[PATCH] D30809: [coroutines] Add codegen for await and yield expressions

2017-03-12 Thread Gor Nishanov via Phabricator via cfe-commits
GorNishanov updated this revision to Diff 91497.
GorNishanov added a comment.

Implemented review feedback: const char * => StringRef in buildSuspendSuffixStr


https://reviews.llvm.org/D30809

Files:
  lib/CodeGen/CGCoroutine.cpp
  lib/CodeGen/CGExprAgg.cpp
  lib/CodeGen/CGExprScalar.cpp
  lib/CodeGen/CodeGenFunction.h
  test/CodeGenCoroutines/coro-await.cpp

Index: test/CodeGenCoroutines/coro-await.cpp
===
--- /dev/null
+++ test/CodeGenCoroutines/coro-await.cpp
@@ -0,0 +1,134 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fcoroutines-ts -std=c++14 -emit-llvm %s -o - -disable-llvm-passes | FileCheck %s
+
+namespace std {
+namespace experimental {
+template 
+struct coroutine_traits;
+
+template  struct coroutine_handle;
+
+template <>
+struct coroutine_handle {
+  void *ptr;
+  static coroutine_handle from_address(void *);
+};
+
+template 
+struct coroutine_handle : coroutine_handle<> {
+  static coroutine_handle from_address(void *);
+};
+
+}
+}
+
+struct suspend_always {
+  int stuff;
+  bool await_ready();
+  void await_suspend(std::experimental::coroutine_handle<>);
+  void await_resume();
+};
+
+template<>
+struct std::experimental::coroutine_traits {
+  struct promise_type {
+void get_return_object();
+suspend_always initial_suspend();
+suspend_always final_suspend();
+void return_void();
+  };
+};
+
+// CHECK-LABEL: f0(
+extern "C" void f0() {
+
+  co_await suspend_always{};
+  // See if we need to suspend:
+  // --
+  // CHECK: %[[READY:.+]] = call zeroext i1 @_ZN14suspend_always11await_readyEv(%struct.suspend_always* %[[AWAITABLE:.+]])
+  // CHECK: br i1 %[[READY]], label %[[READY_BB:.+]], label %[[SUSPEND_BB:.+]]
+
+  // If we are suspending:
+  // -
+  // CHECK: [[SUSPEND_BB]]:
+  // CHECK: %[[SUSPEND_ID:.+]] = call token @llvm.coro.save(
+  // ---
+  // Build the coroutine handle and pass it to await_suspend
+  // ---
+  // CHECK: %[[FRAME:.+]] = call i8* @llvm.coro.frame()
+  // CHECK: call i8* @_ZNSt12experimental16coroutine_handleINS_16coroutine_traitsIJvEE12promise_typeEE12from_addressEPv(i8* %[[FRAME]])
+  //   ... many lines of code to coerce coroutine_handle into an i8* scalar
+  // CHECK: %[[CH:.+]] = load i8*, i8** %{{.+}}
+  // CHECK: call void @_ZN14suspend_always13await_suspendENSt12experimental16coroutine_handleIvEE(%struct.suspend_always* %[[AWAITABLE]], i8* %[[CH]])
+  // -
+  // Generate a suspend point:
+  // -
+  // CHECK: %[[OUTCOME:.+]] = call i8 @llvm.coro.suspend(token %[[SUSPEND_ID]], i1 false)
+  // CHECK: switch i8 %[[OUTCOME]], label %[[RET_BB:.+]] [
+  // CHECK:   i8 0, label %[[READY_BB]]
+  // CHECK:   i8 1, label %[[CLEANUP_BB:.+]]
+  // CHECK: ]
+
+  // Cleanup code goes here:
+  // ---
+  // CHECK: [[CLEANUP_BB]]:
+  
+  // When coroutine is resumed, call await_resume
+  // --
+  // CHECK: [[READY_BB]]:
+  // CHECK:  call void @_ZN14suspend_always12await_resumeEv(%struct.suspend_always* %[[AWAITABLE]])
+}
+
+struct suspend_maybe {
+  float stuff;
+  ~suspend_maybe();
+  bool await_ready();
+  bool await_suspend(std::experimental::coroutine_handle<>);
+  void await_resume();
+};
+
+
+template<>
+struct std::experimental::coroutine_traits {
+  struct promise_type {
+void get_return_object();
+suspend_always initial_suspend();
+suspend_always final_suspend();
+void return_void();
+suspend_maybe yield_value(int);
+  };
+};
+
+// CHECK-LABEL: f1(
+extern "C" void f1(int) {
+  co_yield 42;
+  // CHECK: %[[PROMISE:.+]] = alloca %"struct.std::experimental::coroutine_traits::promise_type"
+  // CHECK: call void @_ZNSt12experimental16coroutine_traitsIJviEE12promise_type11yield_valueEi(%struct.suspend_maybe* sret %[[AWAITER:.+]], %"struct.std::experimental::coroutine_traits::promise_type"* %[[PROMISE]], i32 42)
+
+  // See if we need to suspend:
+  // --
+  // CHECK: %[[READY:.+]] = call zeroext i1 @_ZN13suspend_maybe11await_readyEv(%struct.suspend_maybe* %[[AWAITABLE]])
+  // CHECK: br i1 %[[READY]], label %[[READY_BB:.+]], label %[[SUSPEND_BB:.+]]
+
+  // If we are suspending:
+  // -
+  // CHECK: [[SUSPEND_BB]]:
+  // CHECK: %[[SUSPEND_ID:.+]] = call token @llvm.coro.save(
+  // ---
+  // Build the coroutine handle and pass it to await_suspend
+  // ---
+  // CHECK: %[[FRAME:.+]] = call i8* @llvm.coro.frame()
+  // CHECK: call i8* @_ZNSt12experimental16coroutine_handleINS_16coroutine_traitsIJviEE12promise_typeEE12from_addressEPv(i8* %[[FRAME]])
+  //   ... many lines of code to coerce coroutine_handle into an i8* scalar
+  // CHECK: %[[CH:.+]] = load i8*, i8** %{{.+}}
+  // CHECK: %[[YES:.+]] = call zeroext i1 @_ZN13suspend_maybe13await_suspendENSt12experimental16coroutine_handleIvEE(%struct

[PATCH] D30809: [coroutines] Add codegen for await and yield expressions

2017-03-11 Thread David Majnemer via Phabricator via cfe-commits
majnemer added inline comments.



Comment at: lib/CodeGen/CGCoroutine.cpp:85
+  unsigned No = 0;
+  const char* AwaitKindStr = 0;
+  switch (Kind) {

I'd use a StringRef here.


https://reviews.llvm.org/D30809



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


[PATCH] D30809: [coroutines] Add codegen for await and yield expressions

2017-03-11 Thread Gor Nishanov via Phabricator via cfe-commits
GorNishanov marked 4 inline comments as done.
GorNishanov added inline comments.



Comment at: lib/CodeGen/CGCoroutine.cpp:32
 
 struct CGCoroData {
+  AwaitKind CurrentAwaitKind = AwaitKind::Init;

majnemer wrote:
> Shouldn't this struct be in an anonymous namespace?
It is forward declared in CodeGenFunction.h and CodeGenFunction class holds a 
unique_ptr to CGCoroData as a member.
Here is the snippet from CodeGenFunction.h:

```
  // Holds coroutine data if the current function is a coroutine. We use a
  // wrapper to manage its lifetime, so that we don't have to define CGCoroData
  // in this header.
  struct CGCoroInfo {
std::unique_ptr Data;
CGCoroInfo();
~CGCoroInfo();
  };
  CGCoroInfo CurCoro;
```


https://reviews.llvm.org/D30809



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


[PATCH] D30809: [coroutines] Add codegen for await and yield expressions

2017-03-11 Thread Gor Nishanov via Phabricator via cfe-commits
GorNishanov updated this revision to Diff 91486.
GorNishanov added a comment.

Addressed review feedback

- clang-format three functions in CGExprScalar.cpp
- got rid of AwaitKindStr array and select appropriate string in the switch 
statement in buildAwaitKindPrefix


https://reviews.llvm.org/D30809

Files:
  lib/CodeGen/CGCoroutine.cpp
  lib/CodeGen/CGExprAgg.cpp
  lib/CodeGen/CGExprScalar.cpp
  lib/CodeGen/CodeGenFunction.h
  test/CodeGenCoroutines/coro-await.cpp

Index: test/CodeGenCoroutines/coro-await.cpp
===
--- /dev/null
+++ test/CodeGenCoroutines/coro-await.cpp
@@ -0,0 +1,134 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fcoroutines-ts -std=c++14 -emit-llvm %s -o - -disable-llvm-passes | FileCheck %s
+
+namespace std {
+namespace experimental {
+template 
+struct coroutine_traits;
+
+template  struct coroutine_handle;
+
+template <>
+struct coroutine_handle {
+  void *ptr;
+  static coroutine_handle from_address(void *);
+};
+
+template 
+struct coroutine_handle : coroutine_handle<> {
+  static coroutine_handle from_address(void *);
+};
+
+}
+}
+
+struct suspend_always {
+  int stuff;
+  bool await_ready();
+  void await_suspend(std::experimental::coroutine_handle<>);
+  void await_resume();
+};
+
+template<>
+struct std::experimental::coroutine_traits {
+  struct promise_type {
+void get_return_object();
+suspend_always initial_suspend();
+suspend_always final_suspend();
+void return_void();
+  };
+};
+
+// CHECK-LABEL: f0(
+extern "C" void f0() {
+
+  co_await suspend_always{};
+  // See if we need to suspend:
+  // --
+  // CHECK: %[[READY:.+]] = call zeroext i1 @_ZN14suspend_always11await_readyEv(%struct.suspend_always* %[[AWAITABLE:.+]])
+  // CHECK: br i1 %[[READY]], label %[[READY_BB:.+]], label %[[SUSPEND_BB:.+]]
+
+  // If we are suspending:
+  // -
+  // CHECK: [[SUSPEND_BB]]:
+  // CHECK: %[[SUSPEND_ID:.+]] = call token @llvm.coro.save(
+  // ---
+  // Build the coroutine handle and pass it to await_suspend
+  // ---
+  // CHECK: %[[FRAME:.+]] = call i8* @llvm.coro.frame()
+  // CHECK: call i8* @_ZNSt12experimental16coroutine_handleINS_16coroutine_traitsIJvEE12promise_typeEE12from_addressEPv(i8* %[[FRAME]])
+  //   ... many lines of code to coerce coroutine_handle into an i8* scalar
+  // CHECK: %[[CH:.+]] = load i8*, i8** %{{.+}}
+  // CHECK: call void @_ZN14suspend_always13await_suspendENSt12experimental16coroutine_handleIvEE(%struct.suspend_always* %[[AWAITABLE]], i8* %[[CH]])
+  // -
+  // Generate a suspend point:
+  // -
+  // CHECK: %[[OUTCOME:.+]] = call i8 @llvm.coro.suspend(token %[[SUSPEND_ID]], i1 false)
+  // CHECK: switch i8 %[[OUTCOME]], label %[[RET_BB:.+]] [
+  // CHECK:   i8 0, label %[[READY_BB]]
+  // CHECK:   i8 1, label %[[CLEANUP_BB:.+]]
+  // CHECK: ]
+
+  // Cleanup code goes here:
+  // ---
+  // CHECK: [[CLEANUP_BB]]:
+  
+  // When coroutine is resumed, call await_resume
+  // --
+  // CHECK: [[READY_BB]]:
+  // CHECK:  call void @_ZN14suspend_always12await_resumeEv(%struct.suspend_always* %[[AWAITABLE]])
+}
+
+struct suspend_maybe {
+  float stuff;
+  ~suspend_maybe();
+  bool await_ready();
+  bool await_suspend(std::experimental::coroutine_handle<>);
+  void await_resume();
+};
+
+
+template<>
+struct std::experimental::coroutine_traits {
+  struct promise_type {
+void get_return_object();
+suspend_always initial_suspend();
+suspend_always final_suspend();
+void return_void();
+suspend_maybe yield_value(int);
+  };
+};
+
+// CHECK-LABEL: f1(
+extern "C" void f1(int) {
+  co_yield 42;
+  // CHECK: %[[PROMISE:.+]] = alloca %"struct.std::experimental::coroutine_traits::promise_type"
+  // CHECK: call void @_ZNSt12experimental16coroutine_traitsIJviEE12promise_type11yield_valueEi(%struct.suspend_maybe* sret %[[AWAITER:.+]], %"struct.std::experimental::coroutine_traits::promise_type"* %[[PROMISE]], i32 42)
+
+  // See if we need to suspend:
+  // --
+  // CHECK: %[[READY:.+]] = call zeroext i1 @_ZN13suspend_maybe11await_readyEv(%struct.suspend_maybe* %[[AWAITABLE]])
+  // CHECK: br i1 %[[READY]], label %[[READY_BB:.+]], label %[[SUSPEND_BB:.+]]
+
+  // If we are suspending:
+  // -
+  // CHECK: [[SUSPEND_BB]]:
+  // CHECK: %[[SUSPEND_ID:.+]] = call token @llvm.coro.save(
+  // ---
+  // Build the coroutine handle and pass it to await_suspend
+  // ---
+  // CHECK: %[[FRAME:.+]] = call i8* @llvm.coro.frame()
+  // CHECK: call i8* @_ZNSt12experimental16coroutine_handleINS_16coroutine_traitsIJviEE12promise_typeEE12from_addressEPv(i8* %[[FRAME]])
+  //   ... many lines of code to coerce coroutine_handle into an i8* scalar
+  // CHECK: %[[CH:.+]] = load i8*, i8** %{{.+}}
+  // CHECK: %[[

[PATCH] D30809: [coroutines] Add codegen for await and yield expressions

2017-03-11 Thread David Majnemer via Phabricator via cfe-commits
majnemer added inline comments.



Comment at: lib/CodeGen/CGCoroutine.cpp:26
+enum class AwaitKind { Init, Normal, Yield, Final };
+char const *AwaitKindStr[] = {"init", "await", "yield", "final"};
+}

I'd move this into buildSuspendSuffixStr.



Comment at: lib/CodeGen/CGCoroutine.cpp:32
 
 struct CGCoroData {
+  AwaitKind CurrentAwaitKind = AwaitKind::Init;

Shouldn't this struct be in an anonymous namespace?



Comment at: lib/CodeGen/CGCoroutine.cpp:86-88
+  switch (Kind) {
+  default:
+break;

I'd just make this fully covered, it's just two more cases.



Comment at: lib/CodeGen/CGExprScalar.cpp:279-282
+  Value *VisitCoawaitExpr(CoawaitExpr* S) {
+return CGF.EmitCoawaitExpr(*S);
+  }
+  Value *VisitCoyieldExpr(CoyieldExpr* S) {

Pointers should lean right.



Comment at: lib/CodeGen/CGExprScalar.cpp:285
+  }
+  Value *VisitUnaryCoawait  (const UnaryOperator *E) {
+return Visit(E->getSubExpr());

Formatting looks off.


https://reviews.llvm.org/D30809



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


[PATCH] D30809: [coroutines] Add codegen for await and yield expressions

2017-03-11 Thread Gor Nishanov via Phabricator via cfe-commits
GorNishanov added a comment.

+ @majnemer who is most familiar with LLVM Coroutines representation.


https://reviews.llvm.org/D30809



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


[PATCH] D30809: [coroutines] Add codegen for await and yield expressions

2017-03-09 Thread Gor Nishanov via Phabricator via cfe-commits
GorNishanov created this revision.
Herald added a subscriber: mehdi_amini.

Emit suspend expression which roughly looks like:

  auto && x = CommonExpr();
  if (!x.await_ready()) {
 llvm_coro_save();
 x.await_suspend(...); (*)
 llvm_coro_suspend(); (**)
  }
  x.await_resume();

where the result of the entire expression is the result of x.await_resume()

  (*) If x.await_suspend return type is bool, it allows to veto a suspend:

  if (x.await_suspend(...)) 
 llvm_coro_suspend();

(**) llvm_coro_suspend() encodes three possible continuations as a switch 
instruction:

  %where-to = call i8 @llvm.coro.suspend(...)
  switch i8 %where-to, label %coro.ret [ ; jump to epilogue to suspend
i8 0, label %yield.ready   ; go here when resumed
i8 1, label %yield.cleanup ; go here when destroyed
  ]


https://reviews.llvm.org/D30809

Files:
  lib/CodeGen/CGCoroutine.cpp
  lib/CodeGen/CGExprAgg.cpp
  lib/CodeGen/CGExprScalar.cpp
  lib/CodeGen/CodeGenFunction.h
  test/CodeGenCoroutines/coro-await.cpp

Index: test/CodeGenCoroutines/coro-await.cpp
===
--- /dev/null
+++ test/CodeGenCoroutines/coro-await.cpp
@@ -0,0 +1,134 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fcoroutines-ts -std=c++14 -emit-llvm %s -o - -disable-llvm-passes | FileCheck %s
+
+namespace std {
+namespace experimental {
+template 
+struct coroutine_traits;
+
+template  struct coroutine_handle;
+
+template <>
+struct coroutine_handle {
+  void *ptr;
+  static coroutine_handle from_address(void *);
+};
+
+template 
+struct coroutine_handle : coroutine_handle<> {
+  static coroutine_handle from_address(void *);
+};
+
+}
+}
+
+struct suspend_always {
+  int stuff;
+  bool await_ready();
+  void await_suspend(std::experimental::coroutine_handle<>);
+  void await_resume();
+};
+
+template<>
+struct std::experimental::coroutine_traits {
+  struct promise_type {
+void get_return_object();
+suspend_always initial_suspend();
+suspend_always final_suspend();
+void return_void();
+  };
+};
+
+// CHECK-LABEL: f0(
+extern "C" void f0() {
+
+  co_await suspend_always{};
+  // See if we need to suspend:
+  // --
+  // CHECK: %[[READY:.+]] = call zeroext i1 @_ZN14suspend_always11await_readyEv(%struct.suspend_always* %[[AWAITABLE:.+]])
+  // CHECK: br i1 %[[READY]], label %[[READY_BB:.+]], label %[[SUSPEND_BB:.+]]
+
+  // If we are suspending:
+  // -
+  // CHECK: [[SUSPEND_BB]]:
+  // CHECK: %[[SUSPEND_ID:.+]] = call token @llvm.coro.save(
+  // ---
+  // Build the coroutine handle and pass it to await_suspend
+  // ---
+  // CHECK: %[[FRAME:.+]] = call i8* @llvm.coro.frame()
+  // CHECK: call i8* @_ZNSt12experimental16coroutine_handleINS_16coroutine_traitsIJvEE12promise_typeEE12from_addressEPv(i8* %[[FRAME]])
+  //   ... many lines of code to coerce coroutine_handle into an i8* scalar
+  // CHECK: %[[CH:.+]] = load i8*, i8** %{{.+}}
+  // CHECK: call void @_ZN14suspend_always13await_suspendENSt12experimental16coroutine_handleIvEE(%struct.suspend_always* %[[AWAITABLE]], i8* %[[CH]])
+  // -
+  // Generate a suspend point:
+  // -
+  // CHECK: %[[OUTCOME:.+]] = call i8 @llvm.coro.suspend(token %[[SUSPEND_ID]], i1 false)
+  // CHECK: switch i8 %[[OUTCOME]], label %[[RET_BB:.+]] [
+  // CHECK:   i8 0, label %[[READY_BB]]
+  // CHECK:   i8 1, label %[[CLEANUP_BB:.+]]
+  // CHECK: ]
+
+  // Cleanup code goes here:
+  // ---
+  // CHECK: [[CLEANUP_BB]]:
+  
+  // When coroutine is resumed, call await_resume
+  // --
+  // CHECK: [[READY_BB]]:
+  // CHECK:  call void @_ZN14suspend_always12await_resumeEv(%struct.suspend_always* %[[AWAITABLE]])
+}
+
+struct suspend_maybe {
+  float stuff;
+  ~suspend_maybe();
+  bool await_ready();
+  bool await_suspend(std::experimental::coroutine_handle<>);
+  void await_resume();
+};
+
+
+template<>
+struct std::experimental::coroutine_traits {
+  struct promise_type {
+void get_return_object();
+suspend_always initial_suspend();
+suspend_always final_suspend();
+void return_void();
+suspend_maybe yield_value(int);
+  };
+};
+
+// CHECK-LABEL: f1(
+extern "C" void f1(int) {
+  co_yield 42;
+  // CHECK: %[[PROMISE:.+]] = alloca %"struct.std::experimental::coroutine_traits::promise_type"
+  // CHECK: call void @_ZNSt12experimental16coroutine_traitsIJviEE12promise_type11yield_valueEi(%struct.suspend_maybe* sret %[[AWAITER:.+]], %"struct.std::experimental::coroutine_traits::promise_type"* %[[PROMISE]], i32 42)
+
+  // See if we need to suspend:
+  // --
+  // CHECK: %[[READY:.+]] = call zeroext i1 @_ZN13suspend_maybe11await_readyEv(%struct.suspend_maybe* %[[AWAITABLE]])
+  // CHECK: br i1 %[[READY]], label %[[READY_BB:.+]], label %[[SUSPEND_BB:.+]]
+
+  // If we are suspending:
+  // -
+