Skip to content

Add builtin function @handle() - #1297

Merged
andrewrk merged 39 commits into
ziglang:masterfrom
kristate:handle-builtin-issue1296
Aug 2, 2018
Merged

andrewrk merged 39 commits into
ziglang:masterfrom
kristate:handle-builtin-issue1296

Conversation

@kristate

@kristate kristate commented Jul 27, 2018

Copy link
Copy Markdown
Contributor

closes #1296 ;

  • Define Builtin @handle();
  • Check if within Async block
    I am using executable->fn_entry->type_entry->data.fn.fn_type_id.cc == CallingConventionAsync to check this condition.
  • Return promise in codegen
    Using @llvm.coro.frame
  • Remove old semantic analysis code for the feature we are removing
    remove suspend |handle| {}
  • Remove the stage1 parser code for it
  • Remove the stage2 parser code for it
  • Write documentation

@andrewrk Andrew, I took a crack at this because I want to learn more about zig's internals and based it off of @frameAddress(). I learned a lot from this article.

If you can help me understand the rest, I can start helping with more of the internals. :-)

Thanks

@andrewrk andrewrk left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for starting this effort. I hope these comments help.

Comment thread src/codegen.cpp Outdated

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in render functions in codegen.cpp it is too late - we need to put this semantic analysis and compile error in ir.cpp in the analyze_instruction_handle function. That's why that assert was there that you commented out :-)

Comment thread src/ir.cpp Outdated

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is probably actually the best place to put the compile error for @handle() used outside an async function. Search for return expression outside function definition to see an example.

Comment thread src/ir.cpp Outdated

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here, I think that @handle() should return a promise->T rather than just a promise, because we know the return type of the async function. If you look at the type of the variable that suspend blocks provide, it does this. You can see an example of this in ir_analyze_instruction_coro_begin.

@andrewrk

andrewrk commented Jul 28, 2018

Copy link
Copy Markdown
Member

Here are some more checklist items:

  • remove old semantic analysis code for the feature we are removing
  • remove the stage1 parser code for it
  • remove the stage2 parser code for it

The self-hosted compiler does not have coroutine functionality yet, (but it does have a full parser) so you don't need to port this to stage2.

Comment thread src/codegen.cpp Outdated

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@andrewrk I am pretty sure that the coro_handle is stored in IrExecutable, but I am wondering how to expose it as an LLVMValueRef ? It seems to have no llvm_value.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Solved it by LLVMBuildBitCasting executable->fn_entry->ir_executable.coro_handle->other

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm. That might be ok. A more straightforward solution would probably be to use @llvm.coro.frame: http://llvm.org/docs/Coroutines.html#llvm-coro-frame-intrinsic

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To be clear, I think you can leave this as is, but if it causes problems, we'll know to try this other approach.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cool, I replaced it with the llvm.coro.frame which I think will give better separation between IR and codegen. I did look through the docs several times, and I am not sure why I didn't pickup on it. Thanks!

@kristate

kristate commented Jul 28, 2018

Copy link
Copy Markdown
Contributor Author

@andrewrk please review :-)

Also, please let me know what you meant by "Remove old semantic analysis code"

@andrewrk

Copy link
Copy Markdown
Member

this code needs to be modified so that we're not putting a variable in scope:

        Buf *promise_symbol_name = node->data.suspend.promise_symbol->data.symbol_expr.symbol;
        Scope *child_scope;
        if (!buf_eql_str(promise_symbol_name, "_")) {
            VariableTableEntry *promise_var = ir_create_var(irb, node, parent_scope, promise_symbol_name,
                    true, true, false, const_bool_false);
            ir_build_var_decl(irb, parent_scope, node, promise_var, nullptr, nullptr, irb->exec->coro_handle);
            child_scope = promise_var->child_scope;
        } else {
            child_scope = parent_scope;
        }

Once you update the parser you'll get a compile error for this.

@andrewrk

Copy link
Copy Markdown
Member

I think it looks good so far! Once you remove the old syntax, you'll probably have to update a few places in the standard library. If those tests still pass, that'll be a good test for this patch.

@kristate

Copy link
Copy Markdown
Contributor Author

Pretty sure I got everything -- running tests locally and then I will push.

@kristate

Copy link
Copy Markdown
Contributor Author

@andrewrk I am worried that resume @handle(); is not working correctly. I created a test for it (and the tests pass), but in some cases (lock.zig + loop.zig) it seems that the value is being optimized out. Setting a var before resume works in all cases.

This sometimes fails:

suspend {
    resume @handle();
}

This will always work:

suspend {
    var h: promise = @handle();
    resume h;
}

@andrewrk

Copy link
Copy Markdown
Member

I'll have a look at the failure and see if I can figure out why it's happening

@andrewrk

andrewrk commented Jul 31, 2018

Copy link
Copy Markdown
Member

it seems that the value is being optimized out.

This actually makes me think that my suggestion to use @llvm.coro.frame was a mistake. The docs say

This intrinsic is lowered to refer to the coro.begin instruction. This is a frontend convenience intrinsic that makes it easier to refer to the coroutine frame.

It seems like a bug that LLVM would do this, and then not spill it and restore it correctly. But anyway we can work around it by having Zig store the handle in a variable secretly (which is what was happening with the old syntax).

I'm happy to take this pull request from here and drive it to completion. Would you like me to do that, or would you like to keep working on it yourself?

@kristate

kristate commented Aug 2, 2018

Copy link
Copy Markdown
Contributor Author

@andrewrk It looks like you reworked coroutines, so I will resolve this branch with the master and then test again.

kristopher tate added 19 commits August 2, 2018 16:50
Tracking Issue ziglang#1296 ;

I removed/commented-out the assert checking for no errors since we now have some errors rendered.
kristopher tate added 20 commits August 2, 2018 16:50
…e promise symbol is no in scope with suspend;

Tracking Issue ziglang#1296 ;
@kristate

kristate commented Aug 2, 2018

Copy link
Copy Markdown
Contributor Author

@andrewrk I think that the resume @handle bug has gone away after your rework! 96a94e7 uses resume @handle and if it passes, I think we're all clear to merge this PR.

@andrewrk
andrewrk merged commit 96a94e7 into ziglang:master Aug 2, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

builtin function @handle() instead of suspend capture variable

2 participants