GorNishanov created this revision.
GorNishanov added reviewers: rsmith, majnemer.
GorNishanov added a subscriber: cfe-commits.
Herald added subscribers: beanz, mehdi_amini.

With this commit simple coroutines can be created in plain C using coroutine 
builtins (see coro.c and coro.h for an example):


https://reviews.llvm.org/D24373

Files:
  include/clang/Basic/Builtins.def
  lib/CodeGen/BackendUtil.cpp
  lib/CodeGen/CGBuiltin.cpp
  lib/CodeGen/CMakeLists.txt
  test/Coroutines/Inputs/coro.h
  test/Coroutines/coro.c

Index: test/Coroutines/coro.c
===================================================================
--- /dev/null
+++ test/Coroutines/coro.c
@@ -0,0 +1,25 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fcoroutines -emit-llvm %s -o - -O3 | FileCheck %s
+#include "Inputs/coro.h"
+void print(int);
+
+void* f() {
+  CORO_BEGIN(malloc);
+
+  for (int i = 0;; ++i) {
+    print(i);
+    CORO_SUSPEND();
+  }
+
+  CORO_END(free);
+}
+
+// CHECK-LABEL: @main
+int main() {
+  void* coro = f();
+  CORO_RESUME(coro);
+  CORO_RESUME(coro);
+  CORO_DESTROY(coro);
+// CHECK: call void @print(i32 0)
+// CHECK: call void @print(i32 1)
+// CHECK: call void @print(i32 2)
+}
Index: test/Coroutines/Inputs/coro.h
===================================================================
--- /dev/null
+++ test/Coroutines/Inputs/coro.h
@@ -0,0 +1,36 @@
+void free(void *ptr);
+void *malloc(unsigned int);
+
+#define CORO_SUSPEND_IMPL(IsFinal)                                             \
+  switch (__builtin_coro_suspend(__builtin_coro_save(0), IsFinal)) {           \
+  case 0:                                                                      \
+    if (IsFinal)                                                               \
+      __builtin_trap();                                                        \
+    break;                                                                     \
+  case 1:                                                                      \
+    goto coro_Cleanup;                                                         \
+  default:                                                                     \
+    goto coro_Suspend;                                                         \
+  }
+
+#define CORO_SUSPEND() CORO_SUSPEND_IMPL(0)
+#define CORO_FINAL_SUSPEND() CORO_SUSPEND_IMPL(1)
+
+#define CORO_BEGIN(AllocFunc)                                                  \
+  void *coro_hdl = __builtin_coro_begin(__builtin_coro_id(0, 0, 0, 0),         \
+                                        AllocFunc(__builtin_coro_size()));
+
+#define CORO_END(FreeFunc)                                                     \
+  coro_Cleanup : {                                                             \
+    void *coro_mem = __builtin_coro_free(coro_hdl);                            \
+    if (coro_mem)                                                              \
+      FreeFunc(coro_mem);                                                      \
+  }                                                                            \
+  coro_Suspend:                                                                \
+  __builtin_coro_end(0, 0);                                                    \
+  return coro_hdl;
+
+#define CORO_RESUME(hdl) __builtin_coro_resume(hdl)
+#define CORO_DESTROY(hdl) __builtin_coro_destroy(hdl)
+
+
Index: lib/CodeGen/CMakeLists.txt
===================================================================
--- lib/CodeGen/CMakeLists.txt
+++ lib/CodeGen/CMakeLists.txt
@@ -3,6 +3,7 @@
   BitReader
   BitWriter
   Core
+  Coroutines
   Coverage
   IPO
   IRReader
Index: lib/CodeGen/CGBuiltin.cpp
===================================================================
--- lib/CodeGen/CGBuiltin.cpp
+++ lib/CodeGen/CGBuiltin.cpp
@@ -462,6 +462,25 @@
   return Builder.CreateCall(F, {EmitScalarExpr(E), CI});
 }
 
+// Emit intrinsic with all of the parameters as specified in the builtin.
+// We special case llvm.coro.free, as it takes a token parameter that has no
+// representation in the __builtin type system.
+static RValue emitSimpleIntrinsic(CodeGenFunction &CGF, const CallExpr *E,
+                                  Intrinsic::ID ID) {
+  SmallVector<Value *, 8> Args;
+  switch (ID) {
+  default:
+    break;
+  case Intrinsic::coro_free:
+    Args.push_back(llvm::ConstantTokenNone::get(CGF.getLLVMContext()));
+    break;
+  }
+  for (auto &Arg : E->arguments())
+    Args.push_back(CGF.EmitScalarExpr(Arg));
+  Value *F = CGF.CGM.getIntrinsic(ID);
+  return RValue::get(CGF.Builder.CreateCall(F, Args));
+}
+
 RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
                                         unsigned BuiltinID, const CallExpr *E,
                                         ReturnValueSlot ReturnValue) {
@@ -2057,6 +2076,41 @@
     break;
   }
 
+  case Builtin::BI__builtin_coro_size: {
+    ASTContext &Context = getContext();
+    auto SizeTy = Context.getSizeType();
+    IntegerType *T = Builder.getIntNTy(Context.getTypeSize(SizeTy));
+    Function *Fn = CGM.getIntrinsic(Intrinsic::coro_size, T);
+    return RValue::get(Builder.CreateCall(Fn));
+  }
+
+  case Builtin::BI__builtin_coro_id:
+    return emitSimpleIntrinsic(*this, E, Intrinsic::coro_id);
+  case Builtin::BI__builtin_coro_promise:
+    return emitSimpleIntrinsic(*this, E, Intrinsic::coro_promise);
+  case Builtin::BI__builtin_coro_resume:
+    return emitSimpleIntrinsic(*this, E, Intrinsic::coro_resume);
+  case Builtin::BI__builtin_coro_frame:
+    return emitSimpleIntrinsic(*this, E, Intrinsic::coro_frame);
+  case Builtin::BI__builtin_coro_free:
+    return emitSimpleIntrinsic(*this, E, Intrinsic::coro_free);
+  case Builtin::BI__builtin_coro_destroy:
+    return emitSimpleIntrinsic(*this, E, Intrinsic::coro_destroy);
+  case Builtin::BI__builtin_coro_done:
+    return emitSimpleIntrinsic(*this, E, Intrinsic::coro_done);
+  case Builtin::BI__builtin_coro_alloc:
+    return emitSimpleIntrinsic(*this, E, Intrinsic::coro_alloc);
+  case Builtin::BI__builtin_coro_begin:
+    return emitSimpleIntrinsic(*this, E, Intrinsic::coro_begin);
+  case Builtin::BI__builtin_coro_end:
+    return emitSimpleIntrinsic(*this, E, Intrinsic::coro_end);
+  case Builtin::BI__builtin_coro_save:
+    return emitSimpleIntrinsic(*this, E, Intrinsic::coro_save);
+  case Builtin::BI__builtin_coro_suspend:
+    return emitSimpleIntrinsic(*this, E, Intrinsic::coro_suspend);
+  case Builtin::BI__builtin_coro_param:
+    return emitSimpleIntrinsic(*this, E, Intrinsic::coro_param);
+
   // OpenCL v2.0 s6.13.16.2, Built-in pipe read and write functions
   case Builtin::BIread_pipe:
   case Builtin::BIwrite_pipe: {
Index: lib/CodeGen/BackendUtil.cpp
===================================================================
--- lib/CodeGen/BackendUtil.cpp
+++ lib/CodeGen/BackendUtil.cpp
@@ -41,6 +41,7 @@
 #include "llvm/Target/TargetMachine.h"
 #include "llvm/Target/TargetOptions.h"
 #include "llvm/Target/TargetSubtargetInfo.h"
+#include "llvm/Transforms/Coroutines.h"
 #include "llvm/Transforms/IPO.h"
 #include "llvm/Transforms/IPO/AlwaysInliner.h"
 #include "llvm/Transforms/IPO/PassManagerBuilder.h"
@@ -411,6 +412,9 @@
                            addDataFlowSanitizerPass);
   }
 
+  if (LangOpts.Coroutines)
+    addCoroutinePassesToExtensionPoints(PMBuilder);
+
   if (LangOpts.Sanitize.hasOneOf(SanitizerKind::Efficiency)) {
     PMBuilder.addExtension(PassManagerBuilder::EP_OptimizerLast,
                            addEfficiencySanitizerPass);
Index: include/clang/Basic/Builtins.def
===================================================================
--- include/clang/Basic/Builtins.def
+++ include/clang/Basic/Builtins.def
@@ -1280,6 +1280,24 @@
 BUILTIN(__builtin_nontemporal_store, "v.", "t")
 BUILTIN(__builtin_nontemporal_load, "v.", "t")
 
+// Coroutine intrinsics.
+BUILTIN(__builtin_coro_resume, "vv*", "")
+BUILTIN(__builtin_coro_destroy, "vv*", "n")
+BUILTIN(__builtin_coro_done, "bv*", "n")
+BUILTIN(__builtin_coro_promise, "v*v*IiIb", "n")
+
+BUILTIN(__builtin_coro_size, "z", "n")
+BUILTIN(__builtin_coro_frame, "v*", "n")
+BUILTIN(__builtin_coro_free, "v*v*", "n")
+
+BUILTIN(__builtin_coro_id, "v*Iiv*v*v*", "n")
+BUILTIN(__builtin_coro_alloc, "bv*", "n")
+BUILTIN(__builtin_coro_begin, "v*v*v*", "n")
+BUILTIN(__builtin_coro_end, "vv*Ib", "n")
+BUILTIN(__builtin_coro_save, "v*v*", "n")
+BUILTIN(__builtin_coro_suspend, "cv*Ib", "n")
+BUILTIN(__builtin_coro_param, "bv*v*", "n")
+
 // OpenCL v2.0 s6.13.16, s9.17.3.5 - Pipe functions.
 // We need the generic prototype, since the packet type could be anything.
 LANGBUILTIN(read_pipe, "i.", "tn", OCLC20_LANG)
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to