From d6c12968a8cb16235a2511b9af5cb09499a0b65e Mon Sep 17 00:00:00 2001 From: Anton Korobeynikov Date: Thu, 7 Sep 2023 16:20:19 -0700 Subject: [PATCH 1/2] [NFC] Update coroutine intrinsics documentation and few remaining tests to opaque pointers --- llvm/docs/Coroutines.rst | 284 +++++++++--------- .../Transforms/Coroutines/coro-async-remat.ll | 38 +-- .../Coroutines/coro-retcon-opaque-ptr.ll | 16 +- .../Coroutines/coro-retcon-remat.ll | 22 +- .../Coroutines/coro-spill-corobegin.ll | 2 +- .../Coroutines/coro-spill-promise-02.ll | 10 +- 6 files changed, 183 insertions(+), 189 deletions(-) diff --git a/llvm/docs/Coroutines.rst b/llvm/docs/Coroutines.rst index 37c0614b3985d..0a65a39119fd8 100644 --- a/llvm/docs/Coroutines.rst +++ b/llvm/docs/Coroutines.rst @@ -28,10 +28,10 @@ then destroy it: define i32 @main() { entry: - %hdl = call i8* @f(i32 4) - call void @llvm.coro.resume(i8* %hdl) - call void @llvm.coro.resume(i8* %hdl) - call void @llvm.coro.destroy(i8* %hdl) + %hdl = call ptr @f(i32 4) + call void @llvm.coro.resume(ptr %hdl) + call void @llvm.coro.resume(ptr %hdl) + call void @llvm.coro.destroy(ptr %hdl) ret i32 0 } @@ -186,7 +186,7 @@ coroutine. Therefore an async coroutine returns `void`. .. code-block:: llvm - define swiftcc void @async_coroutine(i8* %async.ctxt, i8*, i8*) { + define swiftcc void @async_coroutine(ptr %async.ctxt, ptr, ptr) { } Values live across a suspend point need to be stored in the coroutine frame to @@ -216,10 +216,10 @@ a parameter to the `llvm.coro.suspend.async` intrinsic. .. code-block:: llvm - %resume_func_ptr = call i8* @llvm.coro.async.resume() - call {i8*, i8*, i8*} (i8*, i8*, ...) @llvm.coro.suspend.async( - i8* %resume_func_ptr, - i8* %context_projection_function + %resume_func_ptr = call ptr @llvm.coro.async.resume() + call {ptr, ptr, ptr} (ptr, ptr, ...) @llvm.coro.suspend.async( + ptr %resume_func_ptr, + ptr %context_projection_function The frontend should provide a `async function pointer` struct associated with each async coroutine by `llvm.coro.id.async`'s argument. The initial size and @@ -249,11 +249,11 @@ the async coroutine. .. code-block:: llvm - call {i8*, i8*, i8*} (i8*, i8*, ...) @llvm.coro.suspend.async( - i8* %resume_func_ptr, - i8* %context_projection_function, - i8* (bitcast void (i8*, i8*, i8*)* to i8*) %suspend_function, - i8* %arg1, i8* %arg2, i8 %arg3) + call {ptr, ptr, ptr} (ptr, ptr, ...) @llvm.coro.suspend.async( + ptr %resume_func_ptr, + ptr %context_projection_function, + ptr %suspend_function, + ptr %arg1, ptr %arg2, i8 %arg3) Coroutines by Example ===================== @@ -284,12 +284,12 @@ The LLVM IR for this coroutine looks like this: .. code-block:: llvm - define i8* @f(i32 %n) presplitcoroutine { + define ptr @f(i32 %n) presplitcoroutine { entry: - %id = call token @llvm.coro.id(i32 0, i8* null, i8* null, i8* null) + %id = call token @llvm.coro.id(i32 0, ptr null, ptr null, ptr null) %size = call i32 @llvm.coro.size.i32() - %alloc = call i8* @malloc(i32 %size) - %hdl = call noalias i8* @llvm.coro.begin(token %id, i8* %alloc) + %alloc = call ptr @malloc(i32 %size) + %hdl = call noalias ptr @llvm.coro.begin(token %id, ptr %alloc) br label %loop loop: %n.val = phi i32 [ %n, %entry ], [ %inc, %loop ] @@ -299,12 +299,12 @@ The LLVM IR for this coroutine looks like this: switch i8 %0, label %suspend [i8 0, label %loop i8 1, label %cleanup] cleanup: - %mem = call i8* @llvm.coro.free(token %id, i8* %hdl) - call void @free(i8* %mem) + %mem = call ptr @llvm.coro.free(token %id, ptr %hdl) + call void @free(ptr %mem) br label %suspend suspend: - %unused = call i1 @llvm.coro.end(i8* %hdl, i1 false) - ret i8* %hdl + %unused = call i1 @llvm.coro.end(ptr %hdl, i1 false) + ret ptr %hdl } The `entry` block establishes the coroutine frame. The `coro.size`_ intrinsic is @@ -351,7 +351,7 @@ example, the coroutine frame will be: .. code-block:: llvm - %f.frame = type { void (%f.frame*)*, void (%f.frame*)*, i32 } + %f.frame = type { ptr, ptr, i32 } After resume and destroy parts are outlined, function `f` will contain only the code responsible for creation and initialization of the coroutine frame and @@ -359,35 +359,34 @@ execution of the coroutine until a suspend point is reached: .. code-block:: llvm - define i8* @f(i32 %n) { + define ptr @f(i32 %n) { entry: - %id = call token @llvm.coro.id(i32 0, i8* null, i8* null, i8* null) - %alloc = call noalias i8* @malloc(i32 24) - %0 = call noalias i8* @llvm.coro.begin(token %id, i8* %alloc) - %frame = bitcast i8* %0 to %f.frame* - %1 = getelementptr %f.frame, %f.frame* %frame, i32 0, i32 0 - store void (%f.frame*)* @f.resume, void (%f.frame*)** %1 - %2 = getelementptr %f.frame, %f.frame* %frame, i32 0, i32 1 - store void (%f.frame*)* @f.destroy, void (%f.frame*)** %2 + %id = call token @llvm.coro.id(i32 0, ptr null, ptr null, ptr null) + %alloc = call noalias ptr @malloc(i32 24) + %frame = call noalias ptr @llvm.coro.begin(token %id, ptr %alloc) + %1 = getelementptr %f.frame, ptr %frame, i32 0, i32 0 + store ptr @f.resume, ptr %1 + %2 = getelementptr %f.frame, ptr %frame, i32 0, i32 1 + store ptr @f.destroy, ptr %2 %inc = add nsw i32 %n, 1 - %inc.spill.addr = getelementptr inbounds %f.Frame, %f.Frame* %FramePtr, i32 0, i32 2 - store i32 %inc, i32* %inc.spill.addr + %inc.spill.addr = getelementptr inbounds %f.Frame, ptr %FramePtr, i32 0, i32 2 + store i32 %inc, ptr %inc.spill.addr call void @print(i32 %n) - ret i8* %frame + ret ptr %frame } Outlined resume part of the coroutine will reside in function `f.resume`: .. code-block:: llvm - define internal fastcc void @f.resume(%f.frame* %frame.ptr.resume) { + define internal fastcc void @f.resume(ptr %frame.ptr.resume) { entry: - %inc.spill.addr = getelementptr %f.frame, %f.frame* %frame.ptr.resume, i64 0, i32 2 - %inc.spill = load i32, i32* %inc.spill.addr, align 4 + %inc.spill.addr = getelementptr %f.frame, ptr %frame.ptr.resume, i64 0, i32 2 + %inc.spill = load i32, ptr %inc.spill.addr, align 4 %inc = add i32 %n.val, 1 - store i32 %inc, i32* %inc.spill.addr, align 4 + store i32 %inc, ptr %inc.spill.addr, align 4 tail call void @print(i32 %inc) ret void } @@ -396,10 +395,9 @@ Whereas function `f.destroy` will contain the cleanup code for the coroutine: .. code-block:: llvm - define internal fastcc void @f.destroy(%f.frame* %frame.ptr.destroy) { + define internal fastcc void @f.destroy(ptr %frame.ptr.destroy) { entry: - %0 = bitcast %f.frame* %frame.ptr.destroy to i8* - tail call void @free(i8* %0) + tail call void @free(ptr %frame.ptr.destroy) ret void } @@ -420,16 +418,16 @@ elided. .. code-block:: llvm entry: - %id = call token @llvm.coro.id(i32 0, i8* null, i8* null, i8* null) + %id = call token @llvm.coro.id(i32 0, ptr null, ptr null, ptr null) %need.dyn.alloc = call i1 @llvm.coro.alloc(token %id) br i1 %need.dyn.alloc, label %dyn.alloc, label %coro.begin dyn.alloc: %size = call i32 @llvm.coro.size.i32() - %alloc = call i8* @CustomAlloc(i32 %size) + %alloc = call ptr @CustomAlloc(i32 %size) br label %coro.begin coro.begin: - %phi = phi i8* [ null, %entry ], [ %alloc, %dyn.alloc ] - %hdl = call noalias i8* @llvm.coro.begin(token %id, i8* %phi) + %phi = phi ptr [ null, %entry ], [ %alloc, %dyn.alloc ] + %hdl = call noalias ptr @llvm.coro.begin(token %id, ptr %phi) In the cleanup block, we will make freeing the coroutine frame conditional on `coro.free`_ intrinsic. If allocation is elided, `coro.free`_ returns `null` @@ -438,11 +436,11 @@ thus skipping the deallocation code: .. code-block:: llvm cleanup: - %mem = call i8* @llvm.coro.free(token %id, i8* %hdl) - %need.dyn.free = icmp ne i8* %mem, null + %mem = call ptr @llvm.coro.free(token %id, ptr %hdl) + %need.dyn.free = icmp ne ptr %mem, null br i1 %need.dyn.free, label %dyn.free, label %if.end dyn.free: - call void @CustomFree(i8* %mem) + call void @CustomFree(ptr %mem) br label %if.end if.end: ... @@ -502,13 +500,13 @@ as follows: .. code-block:: llvm - define internal fastcc void @f.Resume(%f.Frame* %FramePtr) { + define internal fastcc void @f.Resume(ptr %FramePtr) { entry.Resume: - %index.addr = getelementptr inbounds %f.Frame, %f.Frame* %FramePtr, i64 0, i32 2 - %index = load i8, i8* %index.addr, align 1 + %index.addr = getelementptr inbounds %f.Frame, ptr %FramePtr, i64 0, i32 2 + %index = load i8, ptr %index.addr, align 1 %switch = icmp eq i8 %index, 0 - %n.addr = getelementptr inbounds %f.Frame, %f.Frame* %FramePtr, i64 0, i32 3 - %n = load i32, i32* %n.addr, align 4 + %n.addr = getelementptr inbounds %f.Frame, ptr %FramePtr, i64 0, i32 3 + %n = load i32, ptr %n.addr, align 4 br i1 %switch, label %loop.resume, label %loop loop.resume: @@ -517,13 +515,13 @@ as follows: br label %suspend loop: %inc = add nsw i32 %n, 1 - store i32 %inc, i32* %n.addr, align 4 + store i32 %inc, ptr %n.addr, align 4 tail call void @print(i32 %inc) br label %suspend suspend: %storemerge = phi i8 [ 0, %loop ], [ 1, %loop.resume ] - store i8 %storemerge, i8* %index.addr, align 1 + store i8 %storemerge, ptr %index.addr, align 1 ret void } @@ -579,14 +577,14 @@ correct resume point): .. code-block:: llvm if.true: - %save1 = call token @llvm.coro.save(i8* %hdl) - call void @async_op1(i8* %hdl) + %save1 = call token @llvm.coro.save(ptr %hdl) + call void @async_op1(ptr %hdl) %suspend1 = call i1 @llvm.coro.suspend(token %save1, i1 false) switch i8 %suspend1, label %suspend [i8 0, label %resume1 i8 1, label %cleanup] if.false: - %save2 = call token @llvm.coro.save(i8* %hdl) - call void @async_op2(i8* %hdl) + %save2 = call token @llvm.coro.save(ptr %hdl) + call void @async_op2(ptr %hdl) %suspend2 = call i1 @llvm.coro.suspend(token %save2, i1 false) switch i8 %suspend1, label %suspend [i8 0, label %resume2 i8 1, label %cleanup] @@ -606,35 +604,34 @@ store the current value produced by a coroutine. .. code-block:: llvm - define i8* @f(i32 %n) { + define ptr @f(i32 %n) { entry: %promise = alloca i32 - %pv = bitcast i32* %promise to i8* - %id = call token @llvm.coro.id(i32 0, i8* %pv, i8* null, i8* null) + %id = call token @llvm.coro.id(i32 0, ptr %promise, ptr null, ptr null) %need.dyn.alloc = call i1 @llvm.coro.alloc(token %id) br i1 %need.dyn.alloc, label %dyn.alloc, label %coro.begin dyn.alloc: %size = call i32 @llvm.coro.size.i32() - %alloc = call i8* @malloc(i32 %size) + %alloc = call ptr @malloc(i32 %size) br label %coro.begin coro.begin: - %phi = phi i8* [ null, %entry ], [ %alloc, %dyn.alloc ] - %hdl = call noalias i8* @llvm.coro.begin(token %id, i8* %phi) + %phi = phi ptr [ null, %entry ], [ %alloc, %dyn.alloc ] + %hdl = call noalias ptr @llvm.coro.begin(token %id, ptr %phi) br label %loop loop: %n.val = phi i32 [ %n, %coro.begin ], [ %inc, %loop ] %inc = add nsw i32 %n.val, 1 - store i32 %n.val, i32* %promise + store i32 %n.val, ptr %promise %0 = call i8 @llvm.coro.suspend(token none, i1 false) switch i8 %0, label %suspend [i8 0, label %loop i8 1, label %cleanup] cleanup: - %mem = call i8* @llvm.coro.free(token %id, i8* %hdl) - call void @free(i8* %mem) + %mem = call ptr @llvm.coro.free(token %id, ptr %hdl) + call void @free(ptr %mem) br label %suspend suspend: - %unused = call i1 @llvm.coro.end(i8* %hdl, i1 false) - ret i8* %hdl + %unused = call i1 @llvm.coro.end(ptr %hdl, i1 false) + ret ptr %hdl } A coroutine consumer can rely on the `coro.promise`_ intrinsic to access the @@ -644,18 +641,17 @@ coroutine promise. define i32 @main() { entry: - %hdl = call i8* @f(i32 4) - %promise.addr.raw = call i8* @llvm.coro.promise(i8* %hdl, i32 4, i1 false) - %promise.addr = bitcast i8* %promise.addr.raw to i32* - %val0 = load i32, i32* %promise.addr + %hdl = call ptr @f(i32 4) + %promise.addr = call ptr @llvm.coro.promise(ptr %hdl, i32 4, i1 false) + %val0 = load i32, ptr %promise.addr call void @print(i32 %val0) - call void @llvm.coro.resume(i8* %hdl) - %val1 = load i32, i32* %promise.addr + call void @llvm.coro.resume(ptr %hdl) + %val1 = load i32, ptr %promise.addr call void @print(i32 %val1) - call void @llvm.coro.resume(i8* %hdl) - %val2 = load i32, i32* %promise.addr + call void @llvm.coro.resume(ptr %hdl) + %val2 = load i32, ptr %promise.addr call void @print(i32 %val2) - call void @llvm.coro.destroy(i8* %hdl) + call void @llvm.coro.destroy(ptr %hdl) ret i32 0 } @@ -701,14 +697,14 @@ destroyed: define i32 @main() { entry: - %hdl = call i8* @f(i32 4) + %hdl = call ptr @f(i32 4) br label %while while: - call void @llvm.coro.resume(i8* %hdl) - %done = call i1 @llvm.coro.done(i8* %hdl) + call void @llvm.coro.resume(ptr %hdl) + %done = call i1 @llvm.coro.done(ptr %hdl) br i1 %done, label %end, label %while end: - call void @llvm.coro.destroy(i8* %hdl) + call void @llvm.coro.destroy(ptr %hdl) ret i32 0 } @@ -768,7 +764,7 @@ Syntax: :: - declare void @llvm.coro.destroy(i8* ) + declare void @llvm.coro.destroy(ptr ) Overview: """"""""" @@ -796,7 +792,7 @@ frame. Destroying a coroutine that is not suspended leads to undefined behavior. :: - declare void @llvm.coro.resume(i8* ) + declare void @llvm.coro.resume(ptr ) Overview: """"""""" @@ -823,7 +819,7 @@ Resuming a coroutine that is not suspended leads to undefined behavior. :: - declare i1 @llvm.coro.done(i8* ) + declare i1 @llvm.coro.done(ptr ) Overview: """"""""" @@ -849,7 +845,7 @@ or on a coroutine that is not suspended leads to undefined behavior. :: - declare i8* @llvm.coro.promise(i8* , i32 , i1 ) + declare ptr @llvm.coro.promise(ptr , i32 , i1 ) Overview: """"""""" @@ -888,28 +884,26 @@ Example: .. code-block:: llvm - define i8* @f(i32 %n) { + define ptr @f(i32 %n) { entry: %promise = alloca i32 - %pv = bitcast i32* %promise to i8* ; the second argument to coro.id points to the coroutine promise. - %id = call token @llvm.coro.id(i32 0, i8* %pv, i8* null, i8* null) + %id = call token @llvm.coro.id(i32 0, ptr %promise, ptr null, ptr null) ... - %hdl = call noalias i8* @llvm.coro.begin(token %id, i8* %alloc) + %hdl = call noalias ptr @llvm.coro.begin(token %id, ptr %alloc) ... - store i32 42, i32* %promise ; store something into the promise + store i32 42, ptr %promise ; store something into the promise ... - ret i8* %hdl + ret ptr %hdl } define i32 @main() { entry: - %hdl = call i8* @f(i32 4) ; starts the coroutine and returns its handle - %promise.addr.raw = call i8* @llvm.coro.promise(i8* %hdl, i32 4, i1 false) - %promise.addr = bitcast i8* %promise.addr.raw to i32* - %val = load i32, i32* %promise.addr ; load a value from the promise + %hdl = call ptr @f(i32 4) ; starts the coroutine and returns its handle + %promise.addr = call ptr @llvm.coro.promise(ptr %hdl, i32 4, i1 false) + %val = load i32, ptr %promise.addr ; load a value from the promise call void @print(i32 %val) - call void @llvm.coro.destroy(i8* %hdl) + call void @llvm.coro.destroy(ptr %hdl) ret i32 0 } @@ -979,7 +973,7 @@ the coroutine frame. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ :: - declare i8* @llvm.coro.begin(token , i8* ) + declare ptr @llvm.coro.begin(token , ptr ) Overview: """"""""" @@ -1013,7 +1007,7 @@ A frontend should emit exactly one `coro.begin` intrinsic per coroutine. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ :: - declare i8* @llvm.coro.free(token %id, i8* ) + declare ptr @llvm.coro.free(token %id, ptr ) Overview: """"""""" @@ -1038,11 +1032,11 @@ Example (custom deallocation function): .. code-block:: llvm cleanup: - %mem = call i8* @llvm.coro.free(token %id, i8* %frame) - %mem_not_null = icmp ne i8* %mem, null + %mem = call ptr @llvm.coro.free(token %id, ptr %frame) + %mem_not_null = icmp ne ptr %mem, null br i1 %mem_not_null, label %if.then, label %if.end if.then: - call void @CustomFree(i8* %mem) + call void @CustomFree(ptr %mem) br label %if.end if.end: ret void @@ -1053,8 +1047,8 @@ Example (standard deallocation functions): .. code-block:: llvm cleanup: - %mem = call i8* @llvm.coro.free(token %id, i8* %frame) - call void @free(i8* %mem) + %mem = call ptr @llvm.coro.free(token %id, ptr %frame) + call void @free(ptr %mem) ret void .. _coro.alloc: @@ -1091,18 +1085,18 @@ Example: .. code-block:: llvm entry: - %id = call token @llvm.coro.id(i32 0, i8* null, i8* null, i8* null) + %id = call token @llvm.coro.id(i32 0, ptr null, ptr null, ptr null) %dyn.alloc.required = call i1 @llvm.coro.alloc(token %id) br i1 %dyn.alloc.required, label %coro.alloc, label %coro.begin coro.alloc: %frame.size = call i32 @llvm.coro.size() - %alloc = call i8* @MyAlloc(i32 %frame.size) + %alloc = call ptr @MyAlloc(i32 %frame.size) br label %coro.begin coro.begin: - %phi = phi i8* [ null, %entry ], [ %alloc, %coro.alloc ] - %frame = call i8* @llvm.coro.begin(token %id, i8* %phi) + %phi = phi ptr [ null, %entry ], [ %alloc, %coro.alloc ] + %frame = call ptr @llvm.coro.begin(token %id, ptr %phi) .. _coro.noop: @@ -1110,7 +1104,7 @@ Example: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ :: - declare i8* @llvm.coro.noop() + declare ptr @llvm.coro.noop() Overview: """"""""" @@ -1136,7 +1130,7 @@ Note that in different translation units llvm.coro.noop may return different poi ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ :: - declare i8* @llvm.coro.frame() + declare ptr @llvm.coro.frame() Overview: """"""""" @@ -1162,8 +1156,8 @@ coroutine frame. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ :: - declare token @llvm.coro.id(i32 , i8* , i8* , - i8* ) + declare token @llvm.coro.id(i32 , ptr , ptr , + ptr ) Overview: """"""""" @@ -1176,7 +1170,7 @@ Arguments: The first argument provides information on the alignment of the memory returned by the allocation function and given to `coro.begin` by the first argument. If -this argument is 0, the memory is assumed to be aligned to 2 * sizeof(i8*). +this argument is 0, the memory is assumed to be aligned to 2 * sizeof(ptr). This argument only accepts constants. The second argument, if not `null`, designates a particular alloca instruction @@ -1209,8 +1203,8 @@ A frontend should emit function attribute `presplitcoroutine` for the coroutine. :: declare token @llvm.coro.id.async(i32 , i32 , - i8* , - i8* ) + ptr , + ptr ) Overview: """"""""" @@ -1249,9 +1243,9 @@ A frontend should emit function attribute `presplitcoroutine` for the coroutine. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ :: - declare token @llvm.coro.id.retcon(i32 , i32 , i8* , - i8* , - i8* , i8* ) + declare token @llvm.coro.id.retcon(i32 , i32 , ptr , + ptr , + ptr , ptr ) Overview: """"""""" @@ -1304,9 +1298,9 @@ A frontend should emit function attribute `presplitcoroutine` for the coroutine. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ :: - declare token @llvm.coro.id.retcon.once(i32 , i32 , i8* , - i8* , - i8* , i8* ) + declare token @llvm.coro.id.retcon.once(i32 , i32 , ptr , + ptr , + ptr , ptr ) Overview: """"""""" @@ -1332,7 +1326,7 @@ A frontend should emit function attribute `presplitcoroutine` for the coroutine. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ :: - declare i1 @llvm.coro.end(i8* , i1 ) + declare i1 @llvm.coro.end(ptr , i1 ) Overview: """"""""" @@ -1384,18 +1378,18 @@ For landingpad based exception model, it is expected that frontend uses the .. code-block:: llvm ehcleanup: - %InResumePart = call i1 @llvm.coro.end(i8* null, i1 true) + %InResumePart = call i1 @llvm.coro.end(ptr null, i1 true) br i1 %InResumePart, label %eh.resume, label %cleanup.cont cleanup.cont: ; rest of the cleanup eh.resume: - %exn = load i8*, i8** %exn.slot, align 8 - %sel = load i32, i32* %ehselector.slot, align 4 - %lpad.val = insertvalue { i8*, i32 } undef, i8* %exn, 0 - %lpad.val29 = insertvalue { i8*, i32 } %lpad.val, i32 %sel, 1 - resume { i8*, i32 } %lpad.val29 + %exn = load ptr, ptr %exn.slot, align 8 + %sel = load i32, ptr %ehselector.slot, align 4 + %lpad.val = insertvalue { ptr, i32 } undef, ptr %exn, 0 + %lpad.val29 = insertvalue { ptr, i32 } %lpad.val, i32 %sel, 1 + resume { ptr, i32 } %lpad.val29 The `CoroSpit` pass replaces `coro.end` with ``True`` in the resume functions, thus leading to immediate unwind to the caller, whereas in start function it @@ -1409,7 +1403,7 @@ referring to an enclosing cleanuppad as follows: ehcleanup: %tok = cleanuppad within none [] - %unused = call i1 @llvm.coro.end(i8* null, i1 true) [ "funclet"(token %tok) ] + %unused = call i1 @llvm.coro.end(ptr null, i1 true) [ "funclet"(token %tok) ] cleanupret from %tok unwind label %RestOfTheCleanup The `CoroSplit` pass, if the funclet bundle is present, will insert @@ -1439,7 +1433,7 @@ The following table summarizes the handling of `coro.end`_ intrinsic. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ :: - declare i1 @llvm.coro.end.async(i8* , i1 , ...) + declare i1 @llvm.coro.end.async(ptr , i1 , ...) Overview: """"""""" @@ -1470,10 +1464,10 @@ the function call. .. code-block:: llvm - call i1 (i8*, i1, ...) @llvm.coro.end.async( - i8* %hdl, i1 0, - void (i8*, %async.task*, %async.actor*)* @must_tail_call_return, - i8* %ctxt, %async.task* %task, %async.actor* %actor) + call i1 (ptr, i1, ...) @llvm.coro.end.async( + ptr %hdl, i1 0, + ptr @must_tail_call_return, + ptr %ctxt, ptr %task, ptr %actor) unreachable .. _coro.suspend: @@ -1547,7 +1541,7 @@ unreachable and can perform optimizations that can take advantage of that fact. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ :: - declare token @llvm.coro.save(i8* ) + declare token @llvm.coro.save(ptr ) Overview: """"""""" @@ -1584,8 +1578,8 @@ to the coroutine: .. code-block:: llvm - %save1 = call token @llvm.coro.save(i8* %hdl) - call void @async_op1(i8* %hdl) + %save1 = call token @llvm.coro.save(ptr %hdl) + call void @async_op1(ptr %hdl) %suspend1 = call i1 @llvm.coro.suspend(token %save1, i1 false) switch i8 %suspend1, label %suspend [i8 0, label %resume1 i8 1, label %cleanup] @@ -1596,9 +1590,9 @@ to the coroutine: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ :: - declare {i8*, i8*, i8*} @llvm.coro.suspend.async( - i8* , - i8* , + declare {ptr, ptr, ptr} @llvm.coro.suspend.async( + ptr , + ptr , ... ... ) @@ -1617,7 +1611,7 @@ point. The second argument is the `context projection function`. It should describe how-to restore the `async context` in the continuation function from the first -argument of the continuation function. Its type is `i8* (i8*)`. +argument of the continuation function. Its type is `ptr (ptr)`. The third argument is the function that models transfer to the callee at the suspend point. It should take 3 arguments. Lowering will `musttail` call this @@ -1638,7 +1632,7 @@ called. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ :: - declare i8* @llvm.coro.prepare.async(i8* ) + declare ptr @llvm.coro.prepare.async(ptr ) Overview: """"""""" @@ -1649,7 +1643,7 @@ async coroutine until after coroutine splitting. Arguments: """""""""" -The first argument should be an async coroutine of type `void (i8*, i8*, i8*)`. +The first argument should be an async coroutine of type `void (ptr, ptr, ptr)`. Lowering will replace this intrinsic with its coroutine function argument. .. _coro.suspend.retcon: diff --git a/llvm/test/Transforms/Coroutines/coro-async-remat.ll b/llvm/test/Transforms/Coroutines/coro-async-remat.ll index 60c045464093a..fd2a35c0c7f88 100644 --- a/llvm/test/Transforms/Coroutines/coro-async-remat.ll +++ b/llvm/test/Transforms/Coroutines/coro-async-remat.ll @@ -2,34 +2,34 @@ %async_func_ptr = type <{ i32, i32 }> %Tsq = type <{}> -%swift.context = type { %swift.context*, void (%swift.context*)*, i64 } +%swift.context = type { ptr, ptr, i64 } %swift.type = type { i64 } %FlatMapSeq = type <{}> %swift.error = type opaque %swift.opaque = type opaque -@repoTU = global %async_func_ptr <{ i32 trunc (i64 sub (i64 ptrtoint (void (%Tsq*, %swift.context*, %swift.type*, %FlatMapSeq*)* @repo to i64), i64 ptrtoint (%async_func_ptr* @repoTU to i64)) to i32), i32 20 }>, section "__TEXT,__const", align 8 +@repoTU = global %async_func_ptr <{ i32 trunc (i64 sub (i64 ptrtoint (ptr @repo to i64), i64 ptrtoint (ptr @repoTU to i64)) to i32), i32 20 }>, section "__TEXT,__const", align 8 ; Function Attrs: nounwind -declare token @llvm.coro.id.async(i32, i32, i32, i8*) #0 +declare token @llvm.coro.id.async(i32, i32, i32, ptr) #0 ; Function Attrs: nounwind -declare i8* @llvm.coro.begin(token, i8* writeonly) #0 +declare ptr @llvm.coro.begin(token, ptr writeonly) #0 ; Function Attrs: nounwind -declare i8* @llvm.coro.async.resume() #0 +declare ptr @llvm.coro.async.resume() #0 -define hidden i8* @__swift_async_resume_project_context(i8* %0) { +define hidden ptr @__swift_async_resume_project_context(ptr %0) { entry: - ret i8* undef + ret ptr undef } -define swifttailcc void @repo(%Tsq* %0, %swift.context* %1, %swift.type* %arg, %FlatMapSeq* %2) #1 { +define swifttailcc void @repo(ptr %0, ptr %1, ptr %arg, ptr %2) #1 { entry: - %swifterror = alloca swifterror %swift.error*, align 8 - %3 = call token @llvm.coro.id.async(i32 20, i32 16, i32 1, i8* bitcast (%async_func_ptr* @repoTU to i8*)) - %4 = call i8* @llvm.coro.begin(token %3, i8* null) - %5 = bitcast i8* undef to %swift.opaque* + %swifterror = alloca swifterror ptr, align 8 + %3 = call token @llvm.coro.id.async(i32 20, i32 16, i32 1, ptr @repoTU) + %4 = call ptr @llvm.coro.begin(token %3, ptr null) + %5 = bitcast ptr undef to ptr br label %6 6: ; preds = %21, %15, %entry @@ -39,11 +39,11 @@ entry: br i1 undef, label %8, label %16 8: ; preds = %7 - %initializeWithTake35 = bitcast i8* undef to %swift.opaque* (%swift.opaque*, %swift.opaque*, %swift.type*)* - %9 = call %swift.opaque* %initializeWithTake35(%swift.opaque* noalias %5, %swift.opaque* noalias undef, %swift.type* undef) #0 - %10 = call i8* @llvm.coro.async.resume() - %11 = bitcast i8* %10 to void (%swift.context*)* - %12 = call { i8*, %swift.error* } (i32, i8*, i8*, ...) @llvm.coro.suspend.async.sl_p0i8p0s_swift.error.4.220.413.429.445.461.672.683ss(i32 256, i8* %10, i8* bitcast (i8* (i8*)* @__swift_async_resume_project_context to i8*), i8* bitcast (void (i8*, %Tsq*, %swift.context*, %swift.opaque*, %swift.type*, i8**)* @__swift_suspend_dispatch_5.23 to i8*), i8* undef, %Tsq* undef, %swift.context* undef, %swift.opaque* %5, %swift.type* undef, i8** undef) + %initializeWithTake35 = bitcast ptr undef to ptr + %9 = call ptr %initializeWithTake35(ptr noalias %5, ptr noalias undef, ptr undef) #0 + %10 = call ptr @llvm.coro.async.resume() + %11 = bitcast ptr %10 to ptr + %12 = call { ptr, ptr } (i32, ptr, ptr, ...) @llvm.coro.suspend.async.sl_p0i8p0s_swift.error.4.220.413.429.445.461.672.683ss(i32 256, ptr %10, ptr @__swift_async_resume_project_context, ptr @__swift_suspend_dispatch_5.23, ptr undef, ptr undef, ptr undef, ptr %5, ptr undef, ptr undef) br i1 undef, label %25, label %13 13: ; preds = %8 @@ -120,13 +120,13 @@ entry: ret void } -define dso_local swifttailcc void @__swift_suspend_dispatch_5.23(i8* %0, %Tsq* %1, %swift.context* %2, %swift.opaque* %3, %swift.type* %4, i8** %5) { +define dso_local swifttailcc void @__swift_suspend_dispatch_5.23(ptr %0, ptr %1, ptr %2, ptr %3, ptr %4, ptr %5) { entry: ret void } ; Function Attrs: nounwind -declare { i8*, %swift.error* } @llvm.coro.suspend.async.sl_p0i8p0s_swift.error.4.220.413.429.445.461.672.683ss(i32, i8*, i8*, ...) #0 +declare { ptr, ptr } @llvm.coro.suspend.async.sl_p0i8p0s_swift.error.4.220.413.429.445.461.672.683ss(i32, ptr, ptr, ...) #0 attributes #0 = { nounwind } attributes #1 = { "tune-cpu"="generic" } diff --git a/llvm/test/Transforms/Coroutines/coro-retcon-opaque-ptr.ll b/llvm/test/Transforms/Coroutines/coro-retcon-opaque-ptr.ll index 868a9c4966756..559d3af024694 100644 --- a/llvm/test/Transforms/Coroutines/coro-retcon-opaque-ptr.ll +++ b/llvm/test/Transforms/Coroutines/coro-retcon-opaque-ptr.ll @@ -74,16 +74,16 @@ cleanup: ; preds = %loop unreachable } -declare token @llvm.coro.id.retcon(i32, i32, i8*, i8*, i8*, i8*) -declare i8* @llvm.coro.begin(token, i8*) +declare token @llvm.coro.id.retcon(i32, i32, ptr, ptr, ptr, ptr) +declare ptr @llvm.coro.begin(token, ptr) declare i1 @llvm.coro.suspend.retcon.i1(...) -declare i1 @llvm.coro.end(i8*, i1) -declare i8* @llvm.coro.prepare.retcon(i8*) +declare i1 @llvm.coro.end(ptr, i1) +declare ptr @llvm.coro.prepare.retcon(ptr) -declare i8* @prototype(i8*, i1 zeroext) -declare {i8*,i8*} @g_prototype(i8*, i1 zeroext) +declare ptr @prototype(ptr, i1 zeroext) +declare {ptr,ptr} @g_prototype(ptr, i1 zeroext) -declare noalias i8* @allocate(i32 %size) -declare void @deallocate(i8* %ptr) +declare noalias ptr @allocate(i32 %size) +declare void @deallocate(ptr %ptr) declare void @print(i32) diff --git a/llvm/test/Transforms/Coroutines/coro-retcon-remat.ll b/llvm/test/Transforms/Coroutines/coro-retcon-remat.ll index 584c4e0da87b7..70de163caff5d 100644 --- a/llvm/test/Transforms/Coroutines/coro-retcon-remat.ll +++ b/llvm/test/Transforms/Coroutines/coro-retcon-remat.ll @@ -4,10 +4,10 @@ ; CHECK: %f.Frame = type { i32 } -define { i8*, i32 } @f(i8* %buffer, i32 %n) { +define { ptr, i32 } @f(ptr %buffer, i32 %n) { entry: - %id = call token @llvm.coro.id.retcon(i32 8, i32 4, i8* %buffer, i8* bitcast ({ i8*, i32 } (i8*, i1)* @f_prototype to i8*), i8* bitcast (i8* (i32)* @allocate to i8*), i8* bitcast (void (i8*)* @deallocate to i8*)) - %hdl = call i8* @llvm.coro.begin(token %id, i8* null) + %id = call token @llvm.coro.id.retcon(i32 8, i32 4, ptr %buffer, ptr @f_prototype, ptr @allocate, ptr @deallocate) + %hdl = call ptr @llvm.coro.begin(token %id, ptr null) br label %loop loop: @@ -31,19 +31,19 @@ resume1: br label %loop cleanup: - call i1 @llvm.coro.end(i8* %hdl, i1 0) + call i1 @llvm.coro.end(ptr %hdl, i1 0) unreachable } -declare token @llvm.coro.id.retcon(i32, i32, i8*, i8*, i8*, i8*) -declare i8* @llvm.coro.begin(token, i8*) +declare token @llvm.coro.id.retcon(i32, i32, ptr, ptr, ptr, ptr) +declare ptr @llvm.coro.begin(token, ptr) declare i1 @llvm.coro.suspend.retcon.i1(...) -declare i1 @llvm.coro.end(i8*, i1) -declare i8* @llvm.coro.prepare.retcon(i8*) +declare i1 @llvm.coro.end(ptr, i1) +declare ptr @llvm.coro.prepare.retcon(ptr) -declare { i8*, i32 } @f_prototype(i8*, i1 zeroext) +declare { ptr, i32 } @f_prototype(ptr, i1 zeroext) -declare noalias i8* @allocate(i32 %size) -declare void @deallocate(i8* %ptr) +declare noalias ptr @allocate(i32 %size) +declare void @deallocate(ptr %ptr) declare void @print(i32) diff --git a/llvm/test/Transforms/Coroutines/coro-spill-corobegin.ll b/llvm/test/Transforms/Coroutines/coro-spill-corobegin.ll index 7e19fd6b76d10..9653bd5b28eea 100644 --- a/llvm/test/Transforms/Coroutines/coro-spill-corobegin.ll +++ b/llvm/test/Transforms/Coroutines/coro-spill-corobegin.ll @@ -37,7 +37,7 @@ suspend: ret ptr %hdl } -; See if the i8* for coro.begin was added to f.Frame +; See if the ptr for coro.begin was added to f.Frame ; CHECK-LABEL: %f.Frame = type { ptr, ptr, ptr, i1 } ; See if the g's coro.begin was spilled into the frame diff --git a/llvm/test/Transforms/Coroutines/coro-spill-promise-02.ll b/llvm/test/Transforms/Coroutines/coro-spill-promise-02.ll index 5ea90d79ebc24..0ea6a9dd00a96 100644 --- a/llvm/test/Transforms/Coroutines/coro-spill-promise-02.ll +++ b/llvm/test/Transforms/Coroutines/coro-spill-promise-02.ll @@ -3,7 +3,7 @@ %"class.task::promise_type" = type { [64 x i8] } -declare void @consume(i32*) +declare void @consume(ptr) declare void @consume2(%"class.task::promise_type"*) define ptr @f() presplitcoroutine { @@ -11,17 +11,17 @@ entry: %data = alloca i32, align 4 %__promise = alloca %"class.task::promise_type", align 64 %id = call token @llvm.coro.id(i32 0, ptr %__promise, ptr null, ptr null) - call void @consume2(%"class.task::promise_type"* %__promise) + call void @consume2(ptr %__promise) %size = call i32 @llvm.coro.size.i32() %alloc = call ptr @malloc(i32 %size) %hdl = call ptr @llvm.coro.begin(token %id, ptr %alloc) - call void @consume(i32* %data) + call void @consume(ptr %data) %0 = call i8 @llvm.coro.suspend(token none, i1 false) switch i8 %0, label %suspend [i8 0, label %resume i8 1, label %cleanup] resume: - call void @consume(i32* %data) - call void @consume2(%"class.task::promise_type"* %__promise) + call void @consume(ptr %data) + call void @consume2(ptr %__promise) br label %cleanup cleanup: From dc9a9b86a0ead7d58346d2adbe095eb633a50072 Mon Sep 17 00:00:00 2001 From: Anton Korobeynikov Date: Fri, 8 Sep 2023 09:26:15 -0700 Subject: [PATCH 2/2] Add one more missed cases --- llvm/test/Transforms/Coroutines/coro-spill-promise-02.ll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llvm/test/Transforms/Coroutines/coro-spill-promise-02.ll b/llvm/test/Transforms/Coroutines/coro-spill-promise-02.ll index 0ea6a9dd00a96..411067362825e 100644 --- a/llvm/test/Transforms/Coroutines/coro-spill-promise-02.ll +++ b/llvm/test/Transforms/Coroutines/coro-spill-promise-02.ll @@ -4,7 +4,7 @@ %"class.task::promise_type" = type { [64 x i8] } declare void @consume(ptr) -declare void @consume2(%"class.task::promise_type"*) +declare void @consume2(ptr) define ptr @f() presplitcoroutine { entry: