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) 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: 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 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/CMakeLists.txt =================================================================== --- lib/CodeGen/CMakeLists.txt +++ lib/CodeGen/CMakeLists.txt @@ -3,6 +3,7 @@ BitReader BitWriter Core + Coroutines Coverage IPO IRReader 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: 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) +}