Skip to content

Commit b261da0

Browse files
committed
add coroutine startup IR to async functions
See #727
1 parent 236bbe1 commit b261da0

File tree

4 files changed

+223
-1
lines changed

4 files changed

+223
-1
lines changed

src/all_types.hpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ struct IrExecutable {
5656
IrAnalyze *analysis;
5757
Scope *begin_scope;
5858
ZigList<Tld *> tld_list;
59+
IrInstruction *coro_handle;
5960
};
6061

6162
enum OutType {
@@ -1961,6 +1962,10 @@ enum IrInstructionId {
19611962
IrInstructionIdErrorUnion,
19621963
IrInstructionIdCancel,
19631964
IrInstructionIdGetImplicitAllocator,
1965+
IrInstructionIdCoroId,
1966+
IrInstructionIdCoroAlloc,
1967+
IrInstructionIdCoroSize,
1968+
IrInstructionIdCoroBegin,
19641969
};
19651970

19661971
struct IrInstruction {
@@ -2810,6 +2815,27 @@ struct IrInstructionGetImplicitAllocator {
28102815
IrInstruction base;
28112816
};
28122817

2818+
struct IrInstructionCoroId {
2819+
IrInstruction base;
2820+
};
2821+
2822+
struct IrInstructionCoroAlloc {
2823+
IrInstruction base;
2824+
2825+
IrInstruction *coro_id;
2826+
};
2827+
2828+
struct IrInstructionCoroSize {
2829+
IrInstruction base;
2830+
};
2831+
2832+
struct IrInstructionCoroBegin {
2833+
IrInstruction base;
2834+
2835+
IrInstruction *coro_id;
2836+
IrInstruction *coro_mem_ptr;
2837+
};
2838+
28132839
static const size_t slice_ptr_index = 0;
28142840
static const size_t slice_len_index = 1;
28152841

src/codegen.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3696,6 +3696,23 @@ static LLVMValueRef ir_render_panic(CodeGen *g, IrExecutable *executable, IrInst
36963696
return nullptr;
36973697
}
36983698

3699+
static LLVMValueRef ir_render_coro_id(CodeGen *g, IrExecutable *executable, IrInstructionCoroId *instruction) {
3700+
zig_panic("TODO ir_render_coro_id");
3701+
}
3702+
3703+
static LLVMValueRef ir_render_coro_alloc(CodeGen *g, IrExecutable *executable, IrInstructionCoroAlloc *instruction) {
3704+
zig_panic("TODO ir_render_coro_alloc");
3705+
}
3706+
3707+
static LLVMValueRef ir_render_coro_size(CodeGen *g, IrExecutable *executable, IrInstructionCoroSize *instruction) {
3708+
zig_panic("TODO ir_render_coro_size");
3709+
}
3710+
3711+
static LLVMValueRef ir_render_coro_begin(CodeGen *g, IrExecutable *executable, IrInstructionCoroBegin *instruction) {
3712+
zig_panic("TODO ir_render_coro_begin");
3713+
}
3714+
3715+
36993716
static void set_debug_location(CodeGen *g, IrInstruction *instruction) {
37003717
AstNode *source_node = instruction->source_node;
37013718
Scope *scope = instruction->scope;
@@ -3881,12 +3898,21 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
38813898
return ir_render_cancel(g, executable, (IrInstructionCancel *)instruction);
38823899
case IrInstructionIdGetImplicitAllocator:
38833900
return ir_render_get_implicit_allocator(g, executable, (IrInstructionGetImplicitAllocator *)instruction);
3901+
case IrInstructionIdCoroId:
3902+
return ir_render_coro_id(g, executable, (IrInstructionCoroId *)instruction);
3903+
case IrInstructionIdCoroAlloc:
3904+
return ir_render_coro_alloc(g, executable, (IrInstructionCoroAlloc *)instruction);
3905+
case IrInstructionIdCoroSize:
3906+
return ir_render_coro_size(g, executable, (IrInstructionCoroSize *)instruction);
3907+
case IrInstructionIdCoroBegin:
3908+
return ir_render_coro_begin(g, executable, (IrInstructionCoroBegin *)instruction);
38843909
}
38853910
zig_unreachable();
38863911
}
38873912

38883913
static void ir_render(CodeGen *g, FnTableEntry *fn_entry) {
38893914
assert(fn_entry);
3915+
38903916
IrExecutable *executable = &fn_entry->analyzed_executable;
38913917
assert(executable->basic_block_list.length > 0);
38923918
for (size_t block_i = 0; block_i < executable->basic_block_list.length; block_i += 1) {

src/ir.cpp

Lines changed: 137 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,9 @@ static LVal make_lval_addr(bool is_const, bool is_volatile) {
4545
return { true, is_const, is_volatile };
4646
}
4747

48+
static const char * ASYNC_ALLOC_FIELD_NAME = "allocFn";
49+
//static const char * ASYNC_FREE_FIELD_NAME = "freeFn";
50+
4851
enum ConstCastResultId {
4952
ConstCastResultIdOk,
5053
ConstCastResultIdErrSet,
@@ -649,6 +652,22 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionGetImplicitAlloc
649652
return IrInstructionIdGetImplicitAllocator;
650653
}
651654

655+
static constexpr IrInstructionId ir_instruction_id(IrInstructionCoroId *) {
656+
return IrInstructionIdCoroId;
657+
}
658+
659+
static constexpr IrInstructionId ir_instruction_id(IrInstructionCoroAlloc *) {
660+
return IrInstructionIdCoroAlloc;
661+
}
662+
663+
static constexpr IrInstructionId ir_instruction_id(IrInstructionCoroSize *) {
664+
return IrInstructionIdCoroSize;
665+
}
666+
667+
static constexpr IrInstructionId ir_instruction_id(IrInstructionCoroBegin *) {
668+
return IrInstructionIdCoroBegin;
669+
}
670+
652671
template<typename T>
653672
static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) {
654673
T *special_instruction = allocate<T>(1);
@@ -2420,6 +2439,38 @@ static IrInstruction *ir_build_get_implicit_allocator(IrBuilder *irb, Scope *sco
24202439
return &instruction->base;
24212440
}
24222441

2442+
static IrInstruction *ir_build_coro_id(IrBuilder *irb, Scope *scope, AstNode *source_node) {
2443+
IrInstructionCoroId *instruction = ir_build_instruction<IrInstructionCoroId>(irb, scope, source_node);
2444+
2445+
return &instruction->base;
2446+
}
2447+
2448+
static IrInstruction *ir_build_coro_alloc(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *coro_id) {
2449+
IrInstructionCoroAlloc *instruction = ir_build_instruction<IrInstructionCoroAlloc>(irb, scope, source_node);
2450+
instruction->coro_id = coro_id;
2451+
2452+
ir_ref_instruction(coro_id, irb->current_basic_block);
2453+
2454+
return &instruction->base;
2455+
}
2456+
2457+
static IrInstruction *ir_build_coro_size(IrBuilder *irb, Scope *scope, AstNode *source_node) {
2458+
IrInstructionCoroSize *instruction = ir_build_instruction<IrInstructionCoroSize>(irb, scope, source_node);
2459+
2460+
return &instruction->base;
2461+
}
2462+
2463+
static IrInstruction *ir_build_coro_begin(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *coro_id, IrInstruction *coro_mem_ptr) {
2464+
IrInstructionCoroBegin *instruction = ir_build_instruction<IrInstructionCoroBegin>(irb, scope, source_node);
2465+
instruction->coro_id = coro_id;
2466+
instruction->coro_mem_ptr = coro_mem_ptr;
2467+
2468+
ir_ref_instruction(coro_id, irb->current_basic_block);
2469+
ir_ref_instruction(coro_mem_ptr, irb->current_basic_block);
2470+
2471+
return &instruction->base;
2472+
}
2473+
24232474
static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) {
24242475
results[ReturnKindUnconditional] = 0;
24252476
results[ReturnKindError] = 0;
@@ -5782,6 +5833,63 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
57825833
// Entry block gets a reference because we enter it to begin.
57835834
ir_ref_bb(irb->current_basic_block);
57845835

5836+
FnTableEntry *fn_entry = exec_fn_entry(irb->exec);
5837+
bool is_async = fn_entry != nullptr && fn_entry->type_entry->data.fn.fn_type_id.cc == CallingConventionAsync;
5838+
if (is_async) {
5839+
IrInstruction *is_comptime_false = ir_build_const_bool(irb, scope, node, false);
5840+
IrInstruction *coro_id = ir_build_coro_id(irb, scope, node);
5841+
IrInstruction *need_dyn_alloc = ir_build_coro_alloc(irb, scope, node, coro_id);
5842+
IrInstruction *zero = ir_build_const_usize(irb, scope, node, 0);
5843+
IrInstruction *u8_ptr_type = ir_build_const_type(irb, scope, node,
5844+
get_pointer_to_type(irb->codegen, irb->codegen->builtin_types.entry_u8, false));
5845+
IrInstruction *null_ptr = ir_build_int_to_ptr(irb, scope, node, u8_ptr_type, zero);
5846+
5847+
IrBasicBlock *dyn_alloc_block = ir_create_basic_block(irb, scope, "DynAlloc");
5848+
IrBasicBlock *coro_begin_block = ir_create_basic_block(irb, scope, "CoroBegin");
5849+
ir_build_cond_br(irb, scope, node, need_dyn_alloc, dyn_alloc_block, coro_begin_block, is_comptime_false);
5850+
5851+
ir_set_cursor_at_end_and_append_block(irb, dyn_alloc_block);
5852+
IrInstruction *coro_size = ir_build_coro_size(irb, scope, node);
5853+
IrInstruction *implicit_allocator_ptr = ir_build_get_implicit_allocator(irb, scope, node);
5854+
Buf *alloc_field_name = buf_create_from_str(ASYNC_ALLOC_FIELD_NAME);
5855+
IrInstruction *alloc_fn_ptr = ir_build_field_ptr(irb, scope, node, implicit_allocator_ptr, alloc_field_name);
5856+
IrInstruction *alloc_fn = ir_build_load_ptr(irb, scope, node, alloc_fn_ptr);
5857+
IrInstruction *implicit_allocator = ir_build_load_ptr(irb, scope, node, implicit_allocator_ptr);
5858+
IrInstruction *alignment = ir_build_const_usize(irb, scope, node, irb->codegen->pointer_size_bytes * 2);
5859+
size_t arg_count = 3;
5860+
IrInstruction **args = allocate<IrInstruction *>(arg_count);
5861+
args[0] = implicit_allocator; // self
5862+
args[1] = coro_size; // byte_count
5863+
args[2] = alignment; // alignment
5864+
IrInstruction *alloc_result = ir_build_call(irb, scope, node, nullptr, alloc_fn, arg_count, args, false, FnInlineAuto, false, nullptr);
5865+
IrInstruction *alloc_result_ptr = ir_build_ref(irb, scope, node, alloc_result, true, false);
5866+
IrInstruction *alloc_result_is_err = ir_build_test_err(irb, scope, node, alloc_result_ptr);
5867+
IrBasicBlock *alloc_err_block = ir_create_basic_block(irb, scope, "AllocError");
5868+
IrBasicBlock *alloc_ok_block = ir_create_basic_block(irb, scope, "AllocOk");
5869+
ir_build_cond_br(irb, scope, node, alloc_result_is_err, alloc_err_block, alloc_ok_block, is_comptime_false);
5870+
5871+
ir_set_cursor_at_end_and_append_block(irb, alloc_err_block);
5872+
IrInstruction *err_val = ir_build_unwrap_err_code(irb, scope, node, alloc_result_ptr);
5873+
ir_build_return(irb, scope, node, err_val);
5874+
5875+
ir_set_cursor_at_end_and_append_block(irb, alloc_ok_block);
5876+
IrInstruction *unwrapped_mem_ptr = ir_build_unwrap_err_payload(irb, scope, node, alloc_result_ptr, false);
5877+
Buf *ptr_field_name = buf_create_from_str("ptr");
5878+
IrInstruction *coro_mem_ptr_field = ir_build_field_ptr(irb, scope, node, unwrapped_mem_ptr, ptr_field_name);
5879+
IrInstruction *coro_mem_ptr = ir_build_load_ptr(irb, scope, node, coro_mem_ptr_field);
5880+
ir_build_br(irb, scope, node, coro_begin_block, is_comptime_false);
5881+
5882+
ir_set_cursor_at_end_and_append_block(irb, coro_begin_block);
5883+
IrBasicBlock **incoming_blocks = allocate<IrBasicBlock *>(2);
5884+
IrInstruction **incoming_values = allocate<IrInstruction *>(2);
5885+
incoming_blocks[0] = entry_block;
5886+
incoming_values[0] = null_ptr;
5887+
incoming_blocks[1] = dyn_alloc_block;
5888+
incoming_values[1] = coro_mem_ptr;
5889+
IrInstruction *coro_mem = ir_build_phi(irb, scope, node, 2, incoming_blocks, incoming_values);
5890+
irb->exec->coro_handle = ir_build_coro_begin(irb, scope, node, coro_id, coro_mem);
5891+
}
5892+
57855893
IrInstruction *result = ir_gen_node_extra(irb, node, scope, LVAL_NONE);
57865894
assert(result);
57875895
if (irb->exec->invalid)
@@ -10805,7 +10913,7 @@ IrInstruction *ir_get_implicit_allocator(IrAnalyze *ira, IrInstruction *source_i
1080510913
static IrInstruction *ir_analyze_async_call(IrAnalyze *ira, IrInstructionCall *call_instruction, FnTableEntry *fn_entry, TypeTableEntry *fn_type,
1080610914
IrInstruction *fn_ref, IrInstruction **casted_args, size_t arg_count, IrInstruction *async_allocator_inst)
1080710915
{
10808-
Buf *alloc_field_name = buf_create_from_str("allocFn");
10916+
Buf *alloc_field_name = buf_create_from_str(ASYNC_ALLOC_FIELD_NAME);
1080910917
//Buf *free_field_name = buf_create_from_str("freeFn");
1081010918
assert(async_allocator_inst->value.type->id == TypeTableEntryIdPointer);
1081110919
TypeTableEntry *container_type = async_allocator_inst->value.type->data.pointer.child_type;
@@ -16692,6 +16800,22 @@ static TypeTableEntry *ir_analyze_instruction_cancel(IrAnalyze *ira, IrInstructi
1669216800
return result->value.type;
1669316801
}
1669416802

16803+
static TypeTableEntry *ir_analyze_instruction_coro_id(IrAnalyze *ira, IrInstructionCoroId *instruction) {
16804+
zig_panic("TODO ir_analyze_instruction_coro_id");
16805+
}
16806+
16807+
static TypeTableEntry *ir_analyze_instruction_coro_alloc(IrAnalyze *ira, IrInstructionCoroAlloc *instruction) {
16808+
zig_panic("TODO ir_analyze_instruction_coro_alloc");
16809+
}
16810+
16811+
static TypeTableEntry *ir_analyze_instruction_coro_size(IrAnalyze *ira, IrInstructionCoroSize *instruction) {
16812+
zig_panic("TODO ir_analyze_instruction_coro_size");
16813+
}
16814+
16815+
static TypeTableEntry *ir_analyze_instruction_coro_begin(IrAnalyze *ira, IrInstructionCoroBegin *instruction) {
16816+
zig_panic("TODO ir_analyze_instruction_coro_begin");
16817+
}
16818+
1669516819
static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) {
1669616820
switch (instruction->id) {
1669716821
case IrInstructionIdInvalid:
@@ -16897,6 +17021,14 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
1689717021
return ir_analyze_instruction_error_union(ira, (IrInstructionErrorUnion *)instruction);
1689817022
case IrInstructionIdCancel:
1689917023
return ir_analyze_instruction_cancel(ira, (IrInstructionCancel *)instruction);
17024+
case IrInstructionIdCoroId:
17025+
return ir_analyze_instruction_coro_id(ira, (IrInstructionCoroId *)instruction);
17026+
case IrInstructionIdCoroAlloc:
17027+
return ir_analyze_instruction_coro_alloc(ira, (IrInstructionCoroAlloc *)instruction);
17028+
case IrInstructionIdCoroSize:
17029+
return ir_analyze_instruction_coro_size(ira, (IrInstructionCoroSize *)instruction);
17030+
case IrInstructionIdCoroBegin:
17031+
return ir_analyze_instruction_coro_begin(ira, (IrInstructionCoroBegin *)instruction);
1690017032
}
1690117033
zig_unreachable();
1690217034
}
@@ -17011,6 +17143,8 @@ bool ir_has_side_effects(IrInstruction *instruction) {
1701117143
case IrInstructionIdSetAlignStack:
1701217144
case IrInstructionIdExport:
1701317145
case IrInstructionIdCancel:
17146+
case IrInstructionIdCoroId:
17147+
case IrInstructionIdCoroBegin:
1701417148
return true;
1701517149

1701617150
case IrInstructionIdPhi:
@@ -17086,6 +17220,8 @@ bool ir_has_side_effects(IrInstruction *instruction) {
1708617220
case IrInstructionIdErrorReturnTrace:
1708717221
case IrInstructionIdErrorUnion:
1708817222
case IrInstructionIdGetImplicitAllocator:
17223+
case IrInstructionIdCoroAlloc:
17224+
case IrInstructionIdCoroSize:
1708917225
return false;
1709017226

1709117227
case IrInstructionIdAsm:

src/ir_print.cpp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1028,6 +1028,28 @@ static void ir_print_get_implicit_allocator(IrPrint *irp, IrInstructionGetImplic
10281028
fprintf(irp->f, "@getImplicitAllocator()");
10291029
}
10301030

1031+
static void ir_print_coro_id(IrPrint *irp, IrInstructionCoroId *instruction) {
1032+
fprintf(irp->f, "@coroId()");
1033+
}
1034+
1035+
static void ir_print_coro_alloc(IrPrint *irp, IrInstructionCoroAlloc *instruction) {
1036+
fprintf(irp->f, "@coroAlloc(");
1037+
ir_print_other_instruction(irp, instruction->coro_id);
1038+
fprintf(irp->f, ")");
1039+
}
1040+
1041+
static void ir_print_coro_size(IrPrint *irp, IrInstructionCoroSize *instruction) {
1042+
fprintf(irp->f, "@coroSize()");
1043+
}
1044+
1045+
static void ir_print_coro_begin(IrPrint *irp, IrInstructionCoroBegin *instruction) {
1046+
fprintf(irp->f, "@coroBegin(");
1047+
ir_print_other_instruction(irp, instruction->coro_id);
1048+
fprintf(irp->f, ",");
1049+
ir_print_other_instruction(irp, instruction->coro_mem_ptr);
1050+
fprintf(irp->f, ")");
1051+
}
1052+
10311053
static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
10321054
ir_print_prefix(irp, instruction);
10331055
switch (instruction->id) {
@@ -1354,6 +1376,18 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
13541376
case IrInstructionIdGetImplicitAllocator:
13551377
ir_print_get_implicit_allocator(irp, (IrInstructionGetImplicitAllocator *)instruction);
13561378
break;
1379+
case IrInstructionIdCoroId:
1380+
ir_print_coro_id(irp, (IrInstructionCoroId *)instruction);
1381+
break;
1382+
case IrInstructionIdCoroAlloc:
1383+
ir_print_coro_alloc(irp, (IrInstructionCoroAlloc *)instruction);
1384+
break;
1385+
case IrInstructionIdCoroSize:
1386+
ir_print_coro_size(irp, (IrInstructionCoroSize *)instruction);
1387+
break;
1388+
case IrInstructionIdCoroBegin:
1389+
ir_print_coro_begin(irp, (IrInstructionCoroBegin *)instruction);
1390+
break;
13571391
}
13581392
fprintf(irp->f, "\n");
13591393
}

0 commit comments

Comments
 (0)