Thread overview
March 02

I am trying to build a llvm coroutine with clang without libcxx. ( ref docs
https://github.com/llvm/llvm-project/blob/main/libcxx/include/__coroutine/noop_coroutine_handle.h )

Here is my code:

#include <stdio.h>

typedef struct coro {
    void *handle;
    int done;
} coro;

void coro_func(coro *c) {
    printf("Coroutine started\n");
    __builtin_coro_resume(c->handle);
    printf("Coroutine resumed\n");
    __builtin_coro_resume(c->handle);
    printf("Coroutine finished\n");
    c->done = 1;
    __builtin_coro_destroy(c->handle);
}

int main() {
    coro c;
    c.done = 0;
    c.handle = __builtin_coro_noop();

    coro_func(&c);

    printf("in main is_done=%d\n", __builtin_coro_done(c.handle));

    if (!__builtin_coro_done(c.handle)) {
        __builtin_coro_resume(c.handle);
    }

    if (c.done) {
        printf("Coroutine has finished\n");
    } else {
        printf("Coroutine has not finished\n");
        __builtin_coro_destroy(c.handle);
    }

    return 0;
}

to build it with clang++ -std=c++20 ./coro.cpp

I am doing this because I try create a extern(C) stackless coroutine solution for D.

My example is so wrong, I am not sure how to fix it.

I need a example from main coroutine switch into new create coroutine, and from new create coroutine switch into main coroutine.

Any tips how to fix this simple code ?

March 03
From what I'm reading of the documentation, it looks like you have to work at the IR level to declare a coroutine.

This isn't something you can do with only intrinsics in library code.

https://llvm.org/docs/Coroutines.html#introduction

Take note of the function attribute ``presplitcoroutine`` under coroutine representation.

https://llvm.org/docs/Coroutines.html#coroutine-representation
March 02
On Saturday, 2 March 2024 at 12:32:32 UTC, Richard (Rikki) Andrew Cattermole wrote:
> From what I'm reading of the documentation, it looks like you have to work at the IR level to declare a coroutine.
>
> This isn't something you can do with only intrinsics in library code.
>
> https://llvm.org/docs/Coroutines.html#introduction
>
> Take note of the function attribute ``presplitcoroutine`` under coroutine representation.
>
> https://llvm.org/docs/Coroutines.html#coroutine-representation

Thanks for the tips. I dont understand LLVM IR.  I want to create a LLIR function which accept 2 parameters,  first one is a pointer of coroutine function entry, the other is a pointer to a struct look like this:

```d
struct coroutine_object {
    void* coro_handler;
    void* core_argv;
    size_t core_argc;
}
```


this llvm IR should create one new coroutine, and save the handler into arg2.coro_handler, then start enter the coroutine to execute.


I use chatGPT get this code.  any one can help me fix it and export to `extern(C)`

```ir

define void @start_coroutine(i8* %func_ptr, i8** %coro_handle_ptr) {
entry:
  %func = bitcast i8* %func_ptr to void (i8*)*

  %coro_begin = call i8* @llvm.coro.begin(token none, i8* null, i8* null)

  store i8* %coro_begin, i8** %coro_handle_ptr

  call void @llvm.coro.alloc(i8* %coro_begin, i8* bitcast (void (i8*)* @coro_func to i8*))

  call void @llvm.coro.init(token none, i8* %coro_begin, i8* %coro_begin)

  call void @llvm.coro.save(i8* %coro_begin, i8** null)

  call void @llvm.coro.resume(i8* %coro_begin)

  ret void
}

declare token @llvm.coro.begin(token, i8*, i8*)
declare void @llvm.coro.alloc(i8*, i8*)
declare void @llvm.coro.init(token, i8*, i8*)
declare void @llvm.coro.save(i8*, i8**)
declare void @llvm.coro.resume(i8*)
```

to build it use :

```sh
llvm-as -o coro.bc coro.ll
llvm-ar rcs libcoro.a coro.bc
```


March 03
Even if I was to help you get that IR working, it won't do anything useful for you.

A coroutine in LLVM IR is the top of the call stack.

It must be able to see all functions it calls.

You can't pass a function in by pointer, it has to be hard coded.

This needs compiler support, you can't write code outside of the compiler for this.
March 02
On Saturday, 2 March 2024 at 13:08:48 UTC, Richard (Rikki) Andrew Cattermole wrote:
> Even if I was to help you get that IR working, it won't do anything useful for you.
>
> A coroutine in LLVM IR is the top of the call stack.
>
> It must be able to see all functions it calls.
>
> You can't pass a function in by pointer, it has to be hard coded.
>
> This needs compiler support, you can't write code outside of the compiler for this.

I see tinygo get this support by mix cpp https://github.com/tinygo-org/llvm-project/blob/master/libcxx/include/experimental/coroutine


Is the same thing can be done for D ?
March 03
On 03/03/2024 2:14 AM, Dakota wrote:
> On Saturday, 2 March 2024 at 13:08:48 UTC, Richard (Rikki) Andrew Cattermole wrote:
>> Even if I was to help you get that IR working, it won't do anything useful for you.
>>
>> A coroutine in LLVM IR is the top of the call stack.
>>
>> It must be able to see all functions it calls.
>>
>> You can't pass a function in by pointer, it has to be hard coded.
>>
>> This needs compiler support, you can't write code outside of the compiler for this.
> 
> I see tinygo get this support by mix cpp https://github.com/tinygo-org/llvm-project/blob/master/libcxx/include/experimental/coroutine
> 
> 
> Is the same thing can be done for D ?

That c++ file belongs to LLVM, it is an older intrinsics file that I believe from my quick searches has been replaced.

We can define it ourselves as part of ldc, that isn't the issue.

The compiler itself needs to be modified to output the appropriate IR for the coroutine function.

There are no free lunches here unfortunately.

Unless you want to learn LLVM IR and to modify ldc to support it, there is nothing you can do here beyond talk about how you want it in D.General sorry.
March 04
On Saturday, 2 March 2024 at 13:18:47 UTC, Richard (Rikki) Andrew Cattermole wrote:
>
> On 03/03/2024 2:14 AM, Dakota wrote:
>
> That c++ file belongs to LLVM, it is an older intrinsics file that I believe from my quick searches has been replaced.
>
> We can define it ourselves as part of ldc, that isn't the issue.
>
> The compiler itself needs to be modified to output the appropriate IR for the coroutine function.
>
> There are no free lunches here unfortunately.
>
> Unless you want to learn LLVM IR and to modify ldc to support it, there is nothing you can do here beyond talk about how you want it in D.General sorry.

Thanks.
March 05
On Saturday, 2 March 2024 at 12:56:27 UTC, Dakota wrote:
> On Saturday, 2 March 2024 at 12:32:32 UTC, Richard (Rikki) Andrew Cattermole wrote:
>> From what I'm reading of the documentation, it looks like you have to work at the IR level to declare a coroutine.
>>
>> This isn't something you can do with only intrinsics in library code.
>>
>> https://llvm.org/docs/Coroutines.html#introduction
>>
>> Take note of the function attribute ``presplitcoroutine`` under coroutine representation.
>>
>> https://llvm.org/docs/Coroutines.html#coroutine-representation
>
> Thanks for the tips. I dont understand LLVM IR.  I want to create a LLIR function which accept 2 parameters,  first one is a pointer of coroutine function entry, the other is a pointer to a struct look like this:
>
> ```d
> struct coroutine_object {
>     void* coro_handler;
>     void* core_argv;
>     size_t core_argc;
> }
> ```
>
>
> this llvm IR should create one new coroutine, and save the handler into arg2.coro_handler, then start enter the coroutine to execute.
>
>
> I use chatGPT get this code.  any one can help me fix it and export to `extern(C)`
>
> ```ir
>
> define void @start_coroutine(i8* %func_ptr, i8** %coro_handle_ptr) {
> entry:
>   %func = bitcast i8* %func_ptr to void (i8*)*
>
>   %coro_begin = call i8* @llvm.coro.begin(token none, i8* null, i8* null)
>
>   store i8* %coro_begin, i8** %coro_handle_ptr
>
>   call void @llvm.coro.alloc(i8* %coro_begin, i8* bitcast (void (i8*)* @coro_func to i8*))
>
>   call void @llvm.coro.init(token none, i8* %coro_begin, i8* %coro_begin)
>
>   call void @llvm.coro.save(i8* %coro_begin, i8** null)
>
>   call void @llvm.coro.resume(i8* %coro_begin)
>
>   ret void
> }
>
> declare token @llvm.coro.begin(token, i8*, i8*)
> declare void @llvm.coro.alloc(i8*, i8*)
> declare void @llvm.coro.init(token, i8*, i8*)
> declare void @llvm.coro.save(i8*, i8**)
> declare void @llvm.coro.resume(i8*)
> ```
>
> to build it use :
>
> ```sh
> llvm-as -o coro.bc coro.ll
> llvm-ar rcs libcoro.a coro.bc
> ```
I cannot help at any level close to or further than Rikki, but I want to state that in d with LDC you can embed ir code directly into the code like the below code (it just prints a value using a print function of Gou intrinsic. Not sure it's been long time).
void printInt(uint val){
    __irEx!(`
        @str = private addrspace(4) constant [4 x i8] c"%d\0A\00"
        declare i8* @llvm.nvvm.ptr.constant.to.gen.p0i8.p4i8(i8 addrspace(4)*) nounwind readnone
        declare i32 @vprintf(i8* nocapture, i8*) nounwind
        declare i32 addrspace(5)* @llvm.nvvm.ptr.gen.to.local.p5i32.p0i32(i32*) nounwind readnone
            `, `
        %tmp = alloca [12 x i32], align 8
        %tmp2 = getelementptr inbounds [12 x i32], [12 x i32]* %tmp, i64 0, i64 0
        %gen2local = call i32 addrspace(5)* @llvm.nvvm.ptr.gen.to.local.p5i32.p0i32(i32* %tmp2)

        %getElem12 = getelementptr i32, i32 addrspace(5)* %gen2local, i64 0
        store i32 %0, i32 addrspace(5)* %getElem12, align 8

        %fmt = call i8* @llvm.nvvm.ptr.constant.to.gen.p0i8.p4i8(i8 addrspace(4)* getelementptr inbounds ([4 x i8], [4 x i8] addrspace(4)* @str, i64 0, i64 0))

        %val = bitcast [12 x i32]* %tmp to i8*

        %call = call i32 @vprintf(i8* %fmt, i8* %val)
        ret void
            `, ``, void, uint)(val);
}