From ead2d32be871411685f846e604ec7e4253b9f25a Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Thu, 25 Jul 2019 00:03:06 -0400
Subject: calling an inferred async function
---
src/zig_llvm.cpp | 4 ++++
1 file changed, 4 insertions(+)
(limited to 'src/zig_llvm.cpp')
diff --git a/src/zig_llvm.cpp b/src/zig_llvm.cpp
index c51c9e1a50..b52edabe65 100644
--- a/src/zig_llvm.cpp
+++ b/src/zig_llvm.cpp
@@ -898,6 +898,10 @@ LLVMValueRef ZigLLVMBuildAShrExact(LLVMBuilderRef builder, LLVMValueRef LHS, LLV
return wrap(unwrap(builder)->CreateAShr(unwrap(LHS), unwrap(RHS), name, true));
}
+void ZigLLVMSetTailCall(LLVMValueRef Call) {
+ unwrap(Call)->setTailCallKind(CallInst::TCK_MustTail);
+}
+
class MyOStream: public raw_ostream {
public:
--
cgit v1.2.3
From 7b3686861f87d006da817db98f7d3b13fada9815 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Thu, 25 Jul 2019 22:24:01 -0400
Subject: `@frameSize` works via PrefixData
---
BRANCH_TODO | 9 +++++++++
src/all_types.hpp | 1 -
src/codegen.cpp | 21 +++++++++++++--------
src/ir.cpp | 12 ++----------
src/ir_print.cpp | 2 --
src/zig_llvm.cpp | 6 +++++-
src/zig_llvm.h | 1 +
7 files changed, 30 insertions(+), 22 deletions(-)
(limited to 'src/zig_llvm.cpp')
diff --git a/BRANCH_TODO b/BRANCH_TODO
index 6ea57d2173..d10bc704d8 100644
--- a/BRANCH_TODO
+++ b/BRANCH_TODO
@@ -1,5 +1,14 @@
+ * reimplement @frameSize with Prefix Data
+ * reimplement with function splitting rather than switch
+ * add the `anyframe` type and `anyframe->T`
* await
* await of a non async function
+ * await in single-threaded mode
* async call on a non async function
+ * @asyncCall with an async function pointer
+ * cancel
+ * defer and errdefer
* safety for resuming when it is awaiting
* implicit cast of normal function to async function should be allowed when it is inferred to be async
+ * go over the commented out tests
+ * revive std.event.Loop
diff --git a/src/all_types.hpp b/src/all_types.hpp
index d30b3b8a80..6ee3a6b937 100644
--- a/src/all_types.hpp
+++ b/src/all_types.hpp
@@ -3063,7 +3063,6 @@ struct IrInstructionFrameSizeGen {
IrInstruction base;
IrInstruction *fn;
- IrInstruction *frame_ptr;
};
enum IrOverflowOp {
diff --git a/src/codegen.cpp b/src/codegen.cpp
index 6fc152ad3e..4343006b17 100644
--- a/src/codegen.cpp
+++ b/src/codegen.cpp
@@ -4914,13 +4914,16 @@ static LLVMValueRef ir_render_coro_resume(CodeGen *g, IrExecutable *executable,
return nullptr;
}
-static LLVMValueRef ir_render_frame_size(CodeGen *g, IrExecutable *executable, IrInstructionFrameSizeGen *instruction) {
+static LLVMValueRef ir_render_frame_size(CodeGen *g, IrExecutable *executable,
+ IrInstructionFrameSizeGen *instruction)
+{
+ LLVMTypeRef usize_llvm_type = g->builtin_types.entry_usize->llvm_type;
+ LLVMTypeRef ptr_usize_llvm_type = LLVMPointerType(usize_llvm_type, 0);
LLVMValueRef fn_val = ir_llvm_value(g, instruction->fn);
- LLVMValueRef frame_ptr = ir_llvm_value(g, instruction->frame_ptr);
- LLVMValueRef resume_index_ptr = LLVMBuildStructGEP(g->builder, frame_ptr, coro_resume_index_index, "");
- LLVMValueRef one = LLVMConstInt(g->builtin_types.entry_usize->llvm_type, 1, false);
- LLVMBuildStore(g->builder, one, resume_index_ptr);
- return ZigLLVMBuildCall(g->builder, fn_val, &frame_ptr, 1, LLVMFastCallConv, ZigLLVM_FnInlineAuto, "");
+ LLVMValueRef casted_fn_val = LLVMBuildBitCast(g->builder, fn_val, ptr_usize_llvm_type, "");
+ LLVMValueRef negative_one = LLVMConstInt(LLVMInt32Type(), -1, true);
+ LLVMValueRef prefix_ptr = LLVMBuildInBoundsGEP(g->builder, casted_fn_val, &negative_one, 1, "");
+ return LLVMBuildLoad(g->builder, prefix_ptr, "");
}
static void set_debug_location(CodeGen *g, IrInstruction *instruction) {
@@ -6409,13 +6412,16 @@ static void do_code_gen(CodeGen *g) {
}
if (is_async) {
+ LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->llvm_type;
+ LLVMValueRef size_val = LLVMConstInt(usize_type_ref, fn_table_entry->frame_type->abi_size, false);
+ ZigLLVMFunctionSetPrefixData(fn_table_entry->llvm_value, size_val);
+
if (!g->strip_debug_symbols) {
AstNode *source_node = fn_table_entry->proto_node;
ZigLLVMSetCurrentDebugLocation(g->builder, (int)source_node->line + 1,
(int)source_node->column + 1, get_di_scope(g, fn_table_entry->child_scope));
}
IrExecutable *executable = &fn_table_entry->analyzed_executable;
- LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->llvm_type;
LLVMBasicBlockRef bad_resume_block = LLVMAppendBasicBlock(g->cur_fn_val, "BadResume");
LLVMPositionBuilderAtEnd(g->builder, bad_resume_block);
gen_assertion_scope(g, PanicMsgIdBadResume, fn_table_entry->child_scope);
@@ -6424,7 +6430,6 @@ static void do_code_gen(CodeGen *g) {
LLVMPositionBuilderAtEnd(g->builder, get_size_block);
assert(fn_table_entry->frame_type->abi_size != 0);
assert(fn_table_entry->frame_type->abi_size != SIZE_MAX);
- LLVMValueRef size_val = LLVMConstInt(usize_type_ref, fn_table_entry->frame_type->abi_size, false);
LLVMBuildRet(g->builder, size_val);
LLVMPositionBuilderAtEnd(g->builder, fn_table_entry->preamble_llvm_block);
diff --git a/src/ir.cpp b/src/ir.cpp
index 1a62af8ce4..7a5af347b7 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -2396,15 +2396,12 @@ static IrInstruction *ir_build_frame_size_src(IrBuilder *irb, Scope *scope, AstN
return &instruction->base;
}
-static IrInstruction *ir_build_frame_size_gen(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *fn,
- IrInstruction *frame_ptr)
+static IrInstruction *ir_build_frame_size_gen(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *fn)
{
IrInstructionFrameSizeGen *instruction = ir_build_instruction(irb, scope, source_node);
instruction->fn = fn;
- instruction->frame_ptr = frame_ptr;
ir_ref_instruction(fn, irb->current_basic_block);
- ir_ref_instruction(frame_ptr, irb->current_basic_block);
return &instruction->base;
}
@@ -21808,13 +21805,8 @@ static IrInstruction *ir_analyze_instruction_frame_size(IrAnalyze *ira, IrInstru
return ira->codegen->invalid_instruction;
}
- IrInstruction *frame_ptr = ir_resolve_result(ira, &instruction->base, no_result_loc(),
- ira->codegen->builtin_types.entry_frame_header, nullptr, true, false);
- if (frame_ptr != nullptr && (type_is_invalid(frame_ptr->value.type) || instr_is_unreachable(frame_ptr)))
- return frame_ptr;
-
IrInstruction *result = ir_build_frame_size_gen(&ira->new_irb, instruction->base.scope,
- instruction->base.source_node, fn, frame_ptr);
+ instruction->base.source_node, fn);
result->value.type = ira->codegen->builtin_types.entry_usize;
return result;
}
diff --git a/src/ir_print.cpp b/src/ir_print.cpp
index 7e903ed662..ae467bdc8c 100644
--- a/src/ir_print.cpp
+++ b/src/ir_print.cpp
@@ -925,8 +925,6 @@ static void ir_print_frame_size_src(IrPrint *irp, IrInstructionFrameSizeSrc *ins
static void ir_print_frame_size_gen(IrPrint *irp, IrInstructionFrameSizeGen *instruction) {
fprintf(irp->f, "@frameSize(");
ir_print_other_instruction(irp, instruction->fn);
- fprintf(irp->f, ",");
- ir_print_other_instruction(irp, instruction->frame_ptr);
fprintf(irp->f, ")");
}
diff --git a/src/zig_llvm.cpp b/src/zig_llvm.cpp
index b52edabe65..906b278b21 100644
--- a/src/zig_llvm.cpp
+++ b/src/zig_llvm.cpp
@@ -899,9 +899,13 @@ LLVMValueRef ZigLLVMBuildAShrExact(LLVMBuilderRef builder, LLVMValueRef LHS, LLV
}
void ZigLLVMSetTailCall(LLVMValueRef Call) {
- unwrap(Call)->setTailCallKind(CallInst::TCK_MustTail);
+ unwrap(Call)->setTailCallKind(CallInst::TCK_MustTail);
}
+void ZigLLVMFunctionSetPrefixData(LLVMValueRef function, LLVMValueRef data) {
+ unwrap(function)->setPrefixData(unwrap(data));
+}
+
class MyOStream: public raw_ostream {
public:
diff --git a/src/zig_llvm.h b/src/zig_llvm.h
index 2a2ab567a6..2be119ba0c 100644
--- a/src/zig_llvm.h
+++ b/src/zig_llvm.h
@@ -212,6 +212,7 @@ ZIG_EXTERN_C struct ZigLLVMDILocation *ZigLLVMGetDebugLoc(unsigned line, unsigne
ZIG_EXTERN_C void ZigLLVMSetFastMath(LLVMBuilderRef builder_wrapped, bool on_state);
ZIG_EXTERN_C void ZigLLVMSetTailCall(LLVMValueRef Call);
+ZIG_EXTERN_C void ZigLLVMFunctionSetPrefixData(LLVMValueRef fn, LLVMValueRef data);
ZIG_EXTERN_C void ZigLLVMAddFunctionAttr(LLVMValueRef fn, const char *attr_name, const char *attr_value);
ZIG_EXTERN_C void ZigLLVMAddFunctionAttrCold(LLVMValueRef fn);
--
cgit v1.2.3
From 50926341036c3ba377215d1c70c3e97adb07a292 Mon Sep 17 00:00:00 2001
From: Andrew Kelley
Date: Tue, 13 Aug 2019 14:14:19 -0400
Subject: avoid the word "coroutine", they're "async functions"
---
BRANCH_TODO | 2 +-
doc/langref.html.in | 40 ++++++++++-----------
src-self-hosted/ir.zig | 14 --------
src-self-hosted/link.zig | 2 +-
src-self-hosted/main.zig | 2 +-
src-self-hosted/stage1.zig | 3 +-
src/all_types.hpp | 24 ++++++-------
src/analyze.cpp | 90 +++++++++++++++++++++++-----------------------
src/analyze.hpp | 2 +-
src/codegen.cpp | 62 ++++++++++++++++----------------
src/ir.cpp | 62 ++++++++++++++++----------------
src/ir_print.cpp | 9 +++--
src/zig_llvm.cpp | 3 --
std/event/fs.zig | 6 ++--
std/event/future.zig | 2 +-
std/event/group.zig | 12 +++----
std/event/lock.zig | 5 ++-
std/event/locked.zig | 2 +-
std/event/loop.zig | 2 +-
std/event/net.zig | 14 ++++----
std/event/rwlock.zig | 8 ++---
std/event/rwlocked.zig | 2 +-
std/zig/parser_test.zig | 6 ++--
23 files changed, 175 insertions(+), 199 deletions(-)
(limited to 'src/zig_llvm.cpp')
diff --git a/BRANCH_TODO b/BRANCH_TODO
index 77ea14c06f..cac275eb75 100644
--- a/BRANCH_TODO
+++ b/BRANCH_TODO
@@ -1,4 +1,4 @@
- * grep for "coroutine" and "coro" and replace all that nomenclature with "async functions"
+ * zig fmt support for the syntax
* alignment of variables not being respected in async functions
* await of a non async function
* async call on a non async function
diff --git a/doc/langref.html.in b/doc/langref.html.in
index 0cb76a4bdf..23e4dd194e 100644
--- a/doc/langref.html.in
+++ b/doc/langref.html.in
@@ -5968,9 +5968,10 @@ test "global assembly" {
TODO: @atomic rmw
TODO: builtin atomic memory ordering enum
{#header_close#}
- {#header_open|Coroutines#}
+ {#header_open|Async Functions#}
- A coroutine is a generalization of a function.
+ An async function is a function whose callsite is split into an {#syntax#}async{#endsyntax#} initiation,
+ followed by an {#syntax#}await{#endsyntax#} completion. They can also be canceled.
When you call a function, it creates a stack frame,
@@ -5980,14 +5981,14 @@ test "global assembly" {
until the function returns.
- A coroutine is like a function, but it can be suspended
+ An async function is like a function, but it can be suspended
and resumed any number of times, and then it must be
- explicitly destroyed. When a coroutine suspends, it
+ explicitly destroyed. When an async function suspends, it
returns to the resumer.
- {#header_open|Minimal Coroutine Example#}
+ {#header_open|Minimal Async Function Example#}
- Declare a coroutine with the {#syntax#}async{#endsyntax#} keyword.
+ Declare an async function with the {#syntax#}async{#endsyntax#} keyword.
The expression in angle brackets must evaluate to a struct
which has these fields:
@@ -6006,8 +6007,8 @@ test "global assembly" {
the function generic. Zig will infer the allocator type when the async function is called.
- Call a coroutine with the {#syntax#}async{#endsyntax#} keyword. Here, the expression in angle brackets
- is a pointer to the allocator struct that the coroutine expects.
+ Call an async function with the {#syntax#}async{#endsyntax#} keyword. Here, the expression in angle brackets
+ is a pointer to the allocator struct that the async function expects.
The result of an async function call is a {#syntax#}promise->T{#endsyntax#} type, where {#syntax#}T{#endsyntax#}
@@ -6058,7 +6059,7 @@ const assert = std.debug.assert;
var the_frame: anyframe = undefined;
var result = false;
-test "coroutine suspend with block" {
+test "async function suspend with block" {
_ = async testSuspendBlock();
std.debug.assert(!result);
resume the_frame;
@@ -6074,7 +6075,7 @@ fn testSuspendBlock() void {
}
{#code_end#}
- Every suspend point in an async function represents a point at which the coroutine
+ Every suspend point in an async function represents a point at which the async function
could be destroyed. If that happens, {#syntax#}defer{#endsyntax#} expressions that are in
scope are run, as well as {#syntax#}errdefer{#endsyntax#} expressions.
@@ -6083,14 +6084,14 @@ fn testSuspendBlock() void {
{#header_open|Resuming from Suspend Blocks#}
- Upon entering a {#syntax#}suspend{#endsyntax#} block, the coroutine is already considered
+ Upon entering a {#syntax#}suspend{#endsyntax#} block, the async function is already considered
suspended, and can be resumed. For example, if you started another kernel thread,
and had that thread call {#syntax#}resume{#endsyntax#} on the promise handle provided by the
{#syntax#}suspend{#endsyntax#} block, the new thread would begin executing after the suspend
block, while the old thread continued executing the suspend block.
- However, the coroutine can be directly resumed from the suspend block, in which case it
+ However, the async function can be directly resumed from the suspend block, in which case it
never returns to its resumer and continues executing.
{#code_begin|test#}
@@ -6127,8 +6128,8 @@ async fn testResumeFromSuspend(my_result: *i32) void {
If the async function associated with the promise handle has already returned,
then {#syntax#}await{#endsyntax#} destroys the target async function, and gives the return value.
Otherwise, {#syntax#}await{#endsyntax#} suspends the current async function, registering its
- promise handle with the target coroutine. It becomes the target coroutine's responsibility
- to have ensured that it will be resumed or destroyed. When the target coroutine reaches
+ promise handle with the target async function. It becomes the target async function's responsibility
+ to have ensured that it will be resumed or destroyed. When the target async function reaches
its return statement, it gives the return value to the awaiter, destroys itself, and then
resumes the awaiter.
@@ -6137,7 +6138,7 @@ async fn testResumeFromSuspend(my_result: *i32) void {
{#syntax#}await{#endsyntax#} counts as a suspend point, and therefore at every {#syntax#}await{#endsyntax#},
- a coroutine can be potentially destroyed, which would run {#syntax#}defer{#endsyntax#} and {#syntax#}errdefer{#endsyntax#} expressions.
+ a async function can be potentially destroyed, which would run {#syntax#}defer{#endsyntax#} and {#syntax#}errdefer{#endsyntax#} expressions.
{#code_begin|test#}
const std = @import("std");
@@ -6146,7 +6147,7 @@ const assert = std.debug.assert;
var the_frame: anyframe = undefined;
var final_result: i32 = 0;
-test "coroutine await" {
+test "async function await" {
seq('a');
_ = async amain();
seq('f');
@@ -6188,7 +6189,7 @@ fn seq(c: u8) void {
{#header_close#}
{#header_open|Open Issues#}
- There are a few issues with coroutines that are considered unresolved. Best be aware of them,
+ There are a few issues with async function that are considered unresolved. Best be aware of them,
as the situation is likely to change before 1.0.0: