digitalmars.D.ldc - Need help about LLVM build coroutine
- Dakota (45/45) Mar 02 I am trying to build a llvm coroutine with clang without libcxx.
- Richard (Rikki) Andrew Cattermole (7/7) Mar 02 From what I'm reading of the documentation, it looks like you have to
- Dakota (45/53) Mar 02 Thanks for the tips. I dont understand LLVM IR. I want to create
- Richard (Rikki) Andrew Cattermole (7/7) Mar 02 Even if I was to help you get that IR working, it won't do anything
- Dakota (5/13) Mar 02 I see tinygo get this support by mix cpp
- Richard (Rikki) Andrew Cattermole (10/29) Mar 02 That c++ file belongs to LLVM, it is an older intrinsics file that I
- Dakota (3/13) Mar 03 Thanks.
- Ferhat =?UTF-8?B?S3VydHVsbXXFnw==?= (31/88) Mar 05 I cannot help at any level close to or further than Rikki, but I
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/noo _coroutine_handle.h ) Here is my code: ```c #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 ?
Mar 02
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
Mar 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-representationThanks 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 ```
Mar 02
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.
Mar 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 ?
Mar 02
On 03/03/2024 2:14 AM, Dakota wrote:On Saturday, 2 March 2024 at 13:08:48 UTC, Richard (Rikki) Andrew Cattermole 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.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 ?
Mar 02
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.
Mar 03
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: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); }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-representationThanks 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 ```
Mar 05