| ... | ... | @@ -1997,7 +1997,9 @@ static LLVMValueRef ir_render_save_err_ret_addr(CodeGen *g, IrExecutable *execut |
| 1997 | 1997 | return call_instruction; |
| 1998 | 1998 | } |
| 1999 | 1999 | |
| 2000 | | static LLVMValueRef ir_render_return(CodeGen *g, IrExecutable *executable, IrInstructionReturn *return_instruction) { |
| 2000 | static LLVMValueRef ir_render_return(CodeGen *g, IrExecutable *executable, |
| 2001 | IrInstructionReturn *return_instruction) |
| 2002 | { |
| 2001 | 2003 | if (fn_is_async(g->cur_fn)) { |
| 2002 | 2004 | LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->llvm_type; |
| 2003 | 2005 | LLVMValueRef locals_ptr = g->cur_ret_ptr; |
| ... | ... | @@ -2006,12 +2008,10 @@ static LLVMValueRef ir_render_return(CodeGen *g, IrExecutable *executable, IrIns |
| 2006 | 2008 | ZigType *ret_type = ret_type_has_bits ? return_instruction->value->value.type : nullptr; |
| 2007 | 2009 | |
| 2008 | 2010 | if (ir_want_runtime_safety(g, &return_instruction->base)) { |
| 2009 | | LLVMValueRef resume_index_ptr = LLVMBuildStructGEP(g->builder, locals_ptr, coro_fn_ptr_index, ""); |
| 2010 | | LLVMValueRef new_resume_fn = g->cur_fn->resume_blocks.last()->split_llvm_fn; |
| 2011 | | LLVMBuildStore(g->builder, new_resume_fn, resume_index_ptr); |
| 2011 | LLVMValueRef new_resume_index = LLVMConstAllOnes(usize_type_ref); |
| 2012 | LLVMBuildStore(g->builder, new_resume_index, g->cur_async_resume_index_ptr); |
| 2012 | 2013 | } |
| 2013 | 2014 | |
| 2014 | | LLVMValueRef awaiter_ptr = LLVMBuildStructGEP(g->builder, locals_ptr, coro_awaiter_index, ""); |
| 2015 | 2015 | LLVMValueRef result_ptr_as_usize; |
| 2016 | 2016 | if (ret_type_has_bits) { |
| 2017 | 2017 | LLVMValueRef result_ptr_ptr = LLVMBuildStructGEP(g->builder, locals_ptr, coro_arg_start, ""); |
| ... | ... | @@ -2029,8 +2029,8 @@ static LLVMValueRef ir_render_return(CodeGen *g, IrExecutable *executable, IrIns |
| 2029 | 2029 | } |
| 2030 | 2030 | LLVMValueRef zero = LLVMConstNull(usize_type_ref); |
| 2031 | 2031 | LLVMValueRef all_ones = LLVMConstAllOnes(usize_type_ref); |
| 2032 | | LLVMValueRef prev_val = LLVMBuildAtomicRMW(g->builder, LLVMAtomicRMWBinOpXchg, awaiter_ptr, |
| 2033 | | all_ones, LLVMAtomicOrderingSequentiallyConsistent, g->is_single_threaded); |
| 2032 | LLVMValueRef prev_val = LLVMBuildAtomicRMW(g->builder, LLVMAtomicRMWBinOpXchg, g->cur_async_awaiter_ptr, |
| 2033 | all_ones, LLVMAtomicOrderingMonotonic, g->is_single_threaded); |
| 2034 | 2034 | |
| 2035 | 2035 | LLVMBasicBlockRef bad_return_block = LLVMAppendBasicBlock(g->cur_fn_val, "BadReturn"); |
| 2036 | 2036 | LLVMBasicBlockRef early_return_block = LLVMAppendBasicBlock(g->cur_fn_val, "EarlyReturn"); |
| ... | ... | @@ -3453,7 +3453,6 @@ static void render_async_spills(CodeGen *g) { |
| 3453 | 3453 | } |
| 3454 | 3454 | |
| 3455 | 3455 | static void render_async_var_decls(CodeGen *g, Scope *scope) { |
| 3456 | | render_async_spills(g); |
| 3457 | 3456 | for (;;) { |
| 3458 | 3457 | switch (scope->id) { |
| 3459 | 3458 | case ScopeIdCImport: |
| ... | ... | @@ -3573,6 +3572,14 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr |
| 3573 | 3572 | if (instruction->is_async || callee_is_async) { |
| 3574 | 3573 | assert(frame_result_loc != nullptr); |
| 3575 | 3574 | |
| 3575 | LLVMValueRef fn_ptr_ptr = LLVMBuildStructGEP(g->builder, frame_result_loc, coro_fn_ptr_index, ""); |
| 3576 | LLVMValueRef bitcasted_fn_val = LLVMBuildBitCast(g->builder, fn_val, |
| 3577 | LLVMGetElementType(LLVMTypeOf(fn_ptr_ptr)), ""); |
| 3578 | LLVMBuildStore(g->builder, bitcasted_fn_val, fn_ptr_ptr); |
| 3579 | |
| 3580 | LLVMValueRef resume_index_ptr = LLVMBuildStructGEP(g->builder, frame_result_loc, coro_resume_index, ""); |
| 3581 | LLVMBuildStore(g->builder, zero, resume_index_ptr); |
| 3582 | |
| 3576 | 3583 | if (prefix_arg_err_ret_stack) { |
| 3577 | 3584 | zig_panic("TODO"); |
| 3578 | 3585 | } |
| ... | ... | @@ -3652,23 +3659,24 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr |
| 3652 | 3659 | return nullptr; |
| 3653 | 3660 | } else if (callee_is_async) { |
| 3654 | 3661 | ZigType *ptr_result_type = get_pointer_to_type(g, src_return_type, true); |
| 3655 | | LLVMValueRef split_llvm_fn = make_fn_llvm_value(g, g->cur_fn); |
| 3656 | | LLVMValueRef fn_ptr_ptr = LLVMBuildStructGEP(g->builder, g->cur_ret_ptr, coro_fn_ptr_index, ""); |
| 3657 | | LLVMBuildStore(g->builder, split_llvm_fn, fn_ptr_ptr); |
| 3662 | |
| 3663 | LLVMBasicBlockRef call_bb = LLVMAppendBasicBlock(g->cur_fn_val, "CallResume"); |
| 3664 | size_t new_block_index = g->cur_fn->resume_blocks.length + coro_extra_resume_block_count; |
| 3665 | g->cur_fn->resume_blocks.append(nullptr); |
| 3666 | LLVMValueRef new_block_index_val = LLVMConstInt(usize_type_ref, new_block_index, false); |
| 3667 | LLVMAddCase(g->cur_async_switch_instr, new_block_index_val, call_bb); |
| 3668 | |
| 3669 | LLVMBuildStore(g->builder, new_block_index_val, g->cur_async_resume_index_ptr); |
| 3658 | 3670 | LLVMValueRef args[] = {frame_result_loc, LLVMGetUndef(usize_type_ref)}; |
| 3659 | 3671 | LLVMValueRef call_inst = ZigLLVMBuildCall(g->builder, fn_val, args, 2, llvm_cc, fn_inline, ""); |
| 3660 | 3672 | ZigLLVMSetTailCall(call_inst); |
| 3661 | 3673 | LLVMBuildRetVoid(g->builder); |
| 3662 | 3674 | |
| 3663 | | g->cur_fn_val = split_llvm_fn; |
| 3664 | | g->cur_ret_ptr = LLVMGetParam(split_llvm_fn, 0); |
| 3665 | | LLVMBasicBlockRef call_bb = LLVMAppendBasicBlock(split_llvm_fn, "CallResume"); |
| 3666 | 3675 | LLVMPositionBuilderAtEnd(g->builder, call_bb); |
| 3667 | | |
| 3668 | 3676 | if (ir_want_runtime_safety(g, &instruction->base)) { |
| 3669 | | LLVMBasicBlockRef bad_resume_block = LLVMAppendBasicBlock(split_llvm_fn, "BadResume"); |
| 3670 | | LLVMBasicBlockRef ok_resume_block = LLVMAppendBasicBlock(split_llvm_fn, "OkResume"); |
| 3671 | | LLVMValueRef arg_val = LLVMGetParam(split_llvm_fn, 1); |
| 3677 | LLVMBasicBlockRef bad_resume_block = LLVMAppendBasicBlock(g->cur_fn_val, "BadResume"); |
| 3678 | LLVMBasicBlockRef ok_resume_block = LLVMAppendBasicBlock(g->cur_fn_val, "OkResume"); |
| 3679 | LLVMValueRef arg_val = LLVMGetParam(g->cur_fn_val, 1); |
| 3672 | 3680 | LLVMValueRef all_ones = LLVMConstAllOnes(usize_type_ref); |
| 3673 | 3681 | LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntNE, arg_val, all_ones, ""); |
| 3674 | 3682 | LLVMBuildCondBr(g->builder, ok_bit, ok_resume_block, bad_resume_block); |
| ... | ... | @@ -5144,10 +5152,9 @@ static LLVMValueRef ir_render_assert_non_null(CodeGen *g, IrExecutable *executab |
| 5144 | 5152 | static LLVMValueRef ir_render_suspend_begin(CodeGen *g, IrExecutable *executable, |
| 5145 | 5153 | IrInstructionSuspendBegin *instruction) |
| 5146 | 5154 | { |
| 5147 | | LLVMValueRef locals_ptr = g->cur_ret_ptr; |
| 5148 | | LLVMValueRef fn_ptr_ptr = LLVMBuildStructGEP(g->builder, locals_ptr, coro_fn_ptr_index, ""); |
| 5149 | | LLVMValueRef new_fn_ptr = instruction->resume_block->split_llvm_fn; |
| 5150 | | LLVMBuildStore(g->builder, new_fn_ptr, fn_ptr_ptr); |
| 5155 | LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->llvm_type; |
| 5156 | LLVMValueRef new_resume_index = LLVMConstInt(usize_type_ref, instruction->resume_block->resume_index, false); |
| 5157 | LLVMBuildStore(g->builder, new_resume_index, g->cur_async_resume_index_ptr); |
| 5151 | 5158 | return nullptr; |
| 5152 | 5159 | } |
| 5153 | 5160 | |
| ... | ... | @@ -5159,19 +5166,22 @@ static LLVMValueRef ir_render_suspend_br(CodeGen *g, IrExecutable *executable, |
| 5159 | 5166 | } |
| 5160 | 5167 | |
| 5161 | 5168 | static LLVMValueRef ir_render_await(CodeGen *g, IrExecutable *executable, IrInstructionAwait *instruction) { |
| 5169 | LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->llvm_type; |
| 5162 | 5170 | LLVMValueRef target_frame_ptr = ir_llvm_value(g, instruction->frame); |
| 5163 | 5171 | ZigType *result_type = instruction->base.value.type; |
| 5164 | 5172 | ZigType *ptr_result_type = get_pointer_to_type(g, result_type, true); |
| 5165 | 5173 | |
| 5166 | 5174 | // Prepare to be suspended |
| 5167 | | LLVMValueRef split_llvm_fn = make_fn_llvm_value(g, g->cur_fn); |
| 5168 | | LLVMValueRef fn_ptr_ptr = LLVMBuildStructGEP(g->builder, g->cur_ret_ptr, coro_fn_ptr_index, ""); |
| 5169 | | LLVMBuildStore(g->builder, split_llvm_fn, fn_ptr_ptr); |
| 5175 | LLVMBasicBlockRef resume_bb = LLVMAppendBasicBlock(g->cur_fn_val, "AwaitResume"); |
| 5176 | size_t new_block_index = g->cur_fn->resume_blocks.length + coro_extra_resume_block_count; |
| 5177 | g->cur_fn->resume_blocks.append(nullptr); |
| 5178 | LLVMValueRef new_block_index_val = LLVMConstInt(usize_type_ref, new_block_index, false); |
| 5179 | LLVMAddCase(g->cur_async_switch_instr, new_block_index_val, resume_bb); |
| 5180 | LLVMBuildStore(g->builder, new_block_index_val, g->cur_async_resume_index_ptr); |
| 5170 | 5181 | |
| 5171 | 5182 | // At this point resuming the function will do the correct thing. |
| 5172 | 5183 | // This code is as if it is running inside the suspend block. |
| 5173 | 5184 | |
| 5174 | | LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->llvm_type; |
| 5175 | 5185 | // caller's own frame pointer |
| 5176 | 5186 | LLVMValueRef awaiter_init_val = LLVMBuildPtrToInt(g->builder, g->cur_ret_ptr, usize_type_ref, ""); |
| 5177 | 5187 | LLVMValueRef awaiter_ptr = LLVMBuildStructGEP(g->builder, target_frame_ptr, coro_awaiter_index, ""); |
| ... | ... | @@ -5184,18 +5194,20 @@ static LLVMValueRef ir_render_await(CodeGen *g, IrExecutable *executable, IrInst |
| 5184 | 5194 | result_ptr_as_usize = LLVMGetUndef(usize_type_ref); |
| 5185 | 5195 | } |
| 5186 | 5196 | LLVMValueRef prev_val = LLVMBuildAtomicRMW(g->builder, LLVMAtomicRMWBinOpXchg, awaiter_ptr, awaiter_init_val, |
| 5187 | | LLVMAtomicOrderingSequentiallyConsistent, g->is_single_threaded); |
| 5197 | LLVMAtomicOrderingMonotonic, g->is_single_threaded); |
| 5188 | 5198 | |
| 5189 | 5199 | LLVMBasicBlockRef bad_await_block = LLVMAppendBasicBlock(g->cur_fn_val, "BadAwait"); |
| 5190 | 5200 | LLVMBasicBlockRef complete_suspend_block = LLVMAppendBasicBlock(g->cur_fn_val, "CompleteSuspend"); |
| 5191 | | LLVMBasicBlockRef early_return_block = LLVMAppendBasicBlock(g->cur_fn_val, "EarlyReturn"); |
| 5192 | 5201 | |
| 5193 | 5202 | LLVMValueRef zero = LLVMConstNull(usize_type_ref); |
| 5194 | 5203 | LLVMValueRef all_ones = LLVMConstAllOnes(usize_type_ref); |
| 5195 | 5204 | LLVMValueRef switch_instr = LLVMBuildSwitch(g->builder, prev_val, bad_await_block, 2); |
| 5205 | LLVMBasicBlockRef predecessor_bb = LLVMGetInsertBlock(g->builder); |
| 5196 | 5206 | |
| 5197 | 5207 | LLVMAddCase(switch_instr, zero, complete_suspend_block); |
| 5198 | | LLVMAddCase(switch_instr, all_ones, early_return_block); |
| 5208 | |
| 5209 | // Early return: The async function has already completed. No need to suspend. |
| 5210 | LLVMAddCase(switch_instr, all_ones, resume_bb); |
| 5199 | 5211 | |
| 5200 | 5212 | // We discovered that another awaiter was already here. |
| 5201 | 5213 | LLVMPositionBuilderAtEnd(g->builder, bad_await_block); |
| ... | ... | @@ -5205,25 +5217,18 @@ static LLVMValueRef ir_render_await(CodeGen *g, IrExecutable *executable, IrInst |
| 5205 | 5217 | LLVMPositionBuilderAtEnd(g->builder, complete_suspend_block); |
| 5206 | 5218 | LLVMBuildRetVoid(g->builder); |
| 5207 | 5219 | |
| 5208 | | // The async function has already completed. So we use a tail call to resume ourselves. |
| 5209 | | LLVMPositionBuilderAtEnd(g->builder, early_return_block); |
| 5210 | | LLVMValueRef args[] = {g->cur_ret_ptr, result_ptr_as_usize}; |
| 5211 | | LLVMValueRef call_inst = ZigLLVMBuildCall(g->builder, split_llvm_fn, args, 2, LLVMFastCallConv, |
| 5212 | | ZigLLVM_FnInlineAuto, ""); |
| 5213 | | ZigLLVMSetTailCall(call_inst); |
| 5214 | | LLVMBuildRetVoid(g->builder); |
| 5215 | | |
| 5216 | | g->cur_fn_val = split_llvm_fn; |
| 5217 | | g->cur_ret_ptr = LLVMGetParam(split_llvm_fn, 0); |
| 5218 | | LLVMBasicBlockRef call_bb = LLVMAppendBasicBlock(split_llvm_fn, "AwaitResume"); |
| 5219 | | LLVMPositionBuilderAtEnd(g->builder, call_bb); |
| 5220 | LLVMPositionBuilderAtEnd(g->builder, resume_bb); |
| 5221 | // We either got here from Entry (function call) or from the switch above |
| 5222 | LLVMValueRef spilled_result_ptr = LLVMBuildPhi(g->builder, usize_type_ref, ""); |
| 5223 | LLVMValueRef incoming_values[] = { LLVMGetParam(g->cur_fn_val, 1), result_ptr_as_usize }; |
| 5224 | LLVMBasicBlockRef incoming_blocks[] = { g->cur_fn->preamble_llvm_block, predecessor_bb }; |
| 5225 | LLVMAddIncoming(spilled_result_ptr, incoming_values, incoming_blocks, 2); |
| 5220 | 5226 | |
| 5221 | 5227 | if (ir_want_runtime_safety(g, &instruction->base)) { |
| 5222 | | LLVMBasicBlockRef bad_resume_block = LLVMAppendBasicBlock(split_llvm_fn, "BadResume"); |
| 5223 | | LLVMBasicBlockRef ok_resume_block = LLVMAppendBasicBlock(split_llvm_fn, "OkResume"); |
| 5224 | | LLVMValueRef arg_val = LLVMGetParam(split_llvm_fn, 1); |
| 5228 | LLVMBasicBlockRef bad_resume_block = LLVMAppendBasicBlock(g->cur_fn_val, "BadResume"); |
| 5229 | LLVMBasicBlockRef ok_resume_block = LLVMAppendBasicBlock(g->cur_fn_val, "OkResume"); |
| 5225 | 5230 | LLVMValueRef all_ones = LLVMConstAllOnes(usize_type_ref); |
| 5226 | | LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntNE, arg_val, all_ones, ""); |
| 5231 | LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntNE, spilled_result_ptr, all_ones, ""); |
| 5227 | 5232 | LLVMBuildCondBr(g->builder, ok_bit, ok_resume_block, bad_resume_block); |
| 5228 | 5233 | |
| 5229 | 5234 | LLVMPositionBuilderAtEnd(g->builder, bad_resume_block); |
| ... | ... | @@ -5235,7 +5240,6 @@ static LLVMValueRef ir_render_await(CodeGen *g, IrExecutable *executable, IrInst |
| 5235 | 5240 | render_async_var_decls(g, instruction->base.scope); |
| 5236 | 5241 | |
| 5237 | 5242 | if (type_has_bits(result_type)) { |
| 5238 | | LLVMValueRef spilled_result_ptr = LLVMGetParam(g->cur_fn_val, 1); |
| 5239 | 5243 | LLVMValueRef casted_spilled_result_ptr = LLVMBuildIntToPtr(g->builder, spilled_result_ptr, |
| 5240 | 5244 | get_llvm_type(g, ptr_result_type), ""); |
| 5241 | 5245 | return get_handle_value(g, casted_spilled_result_ptr, result_type, ptr_result_type); |
| ... | ... | @@ -5547,13 +5551,18 @@ static void ir_render(CodeGen *g, ZigFn *fn_entry) { |
| 5547 | 5551 | |
| 5548 | 5552 | IrExecutable *executable = &fn_entry->analyzed_executable; |
| 5549 | 5553 | assert(executable->basic_block_list.length > 0); |
| 5554 | |
| 5555 | if (fn_is_async(fn_entry)) { |
| 5556 | IrBasicBlock *entry_block = executable->basic_block_list.at(0); |
| 5557 | LLVMPositionBuilderAtEnd(g->builder, entry_block->llvm_block); |
| 5558 | render_async_var_decls(g, entry_block->instruction_list.at(0)->scope); |
| 5559 | } |
| 5560 | |
| 5550 | 5561 | for (size_t block_i = 0; block_i < executable->basic_block_list.length; block_i += 1) { |
| 5551 | 5562 | IrBasicBlock *current_block = executable->basic_block_list.at(block_i); |
| 5552 | 5563 | assert(current_block->llvm_block); |
| 5553 | 5564 | LLVMPositionBuilderAtEnd(g->builder, current_block->llvm_block); |
| 5554 | | if (current_block->split_llvm_fn != nullptr) { |
| 5555 | | g->cur_fn_val = current_block->split_llvm_fn; |
| 5556 | | g->cur_ret_ptr = LLVMGetParam(g->cur_fn_val, 0); |
| 5565 | if (current_block->resume_index != 0) { |
| 5557 | 5566 | render_async_var_decls(g, current_block->instruction_list.at(0)->scope); |
| 5558 | 5567 | } |
| 5559 | 5568 | for (size_t instr_i = 0; instr_i < current_block->instruction_list.length; instr_i += 1) { |
| ... | ... | @@ -6416,17 +6425,19 @@ static void build_all_basic_blocks(CodeGen *g, ZigFn *fn) { |
| 6416 | 6425 | IrExecutable *executable = &fn->analyzed_executable; |
| 6417 | 6426 | assert(executable->basic_block_list.length > 0); |
| 6418 | 6427 | LLVMValueRef fn_val = fn_llvm_value(g, fn); |
| 6428 | LLVMBasicBlockRef first_bb = nullptr; |
| 6429 | if (fn_is_async(fn)) { |
| 6430 | first_bb = LLVMAppendBasicBlock(fn_val, "AsyncSwitch"); |
| 6431 | fn->preamble_llvm_block = first_bb; |
| 6432 | } |
| 6419 | 6433 | for (size_t block_i = 0; block_i < executable->basic_block_list.length; block_i += 1) { |
| 6420 | 6434 | IrBasicBlock *bb = executable->basic_block_list.at(block_i); |
| 6421 | | if (bb->split_llvm_fn != nullptr) { |
| 6422 | | assert(bb->split_llvm_fn == reinterpret_cast<LLVMValueRef>(0x1)); |
| 6423 | | fn_val = make_fn_llvm_value(g, fn); |
| 6424 | | bb->split_llvm_fn = fn_val; |
| 6425 | | } |
| 6426 | 6435 | bb->llvm_block = LLVMAppendBasicBlock(fn_val, bb->name_hint); |
| 6427 | 6436 | } |
| 6428 | | IrBasicBlock *entry_bb = executable->basic_block_list.at(0); |
| 6429 | | LLVMPositionBuilderAtEnd(g->builder, entry_bb->llvm_block); |
| 6437 | if (first_bb == nullptr) { |
| 6438 | first_bb = executable->basic_block_list.at(0)->llvm_block; |
| 6439 | } |
| 6440 | LLVMPositionBuilderAtEnd(g->builder, first_bb); |
| 6430 | 6441 | } |
| 6431 | 6442 | |
| 6432 | 6443 | static void gen_global_var(CodeGen *g, ZigVar *var, LLVMValueRef init_val, |
| ... | ... | @@ -6636,9 +6647,7 @@ static void do_code_gen(CodeGen *g) { |
| 6636 | 6647 | g->cur_err_ret_trace_val_stack = nullptr; |
| 6637 | 6648 | } |
| 6638 | 6649 | |
| 6639 | | if (is_async) { |
| 6640 | | render_async_spills(g); |
| 6641 | | } else { |
| 6650 | if (!is_async) { |
| 6642 | 6651 | // allocate temporary stack data |
| 6643 | 6652 | for (size_t alloca_i = 0; alloca_i < fn_table_entry->alloca_gen_list.length; alloca_i += 1) { |
| 6644 | 6653 | IrInstructionAllocaGen *instruction = fn_table_entry->alloca_gen_list.at(alloca_i); |
| ... | ... | @@ -6752,17 +6761,35 @@ static void do_code_gen(CodeGen *g) { |
| 6752 | 6761 | LLVMValueRef size_val = LLVMConstInt(usize_type_ref, fn_table_entry->frame_type->abi_size, false); |
| 6753 | 6762 | ZigLLVMFunctionSetPrefixData(fn_table_entry->llvm_value, size_val); |
| 6754 | 6763 | |
| 6755 | | if (ir_want_runtime_safety_scope(g, fn_table_entry->child_scope)) { |
| 6756 | | IrBasicBlock *bad_resume_block = allocate<IrBasicBlock>(1); |
| 6757 | | bad_resume_block->name_hint = "BadResume"; |
| 6758 | | bad_resume_block->split_llvm_fn = make_fn_llvm_value(g, fn_table_entry); |
| 6759 | | |
| 6760 | | LLVMBasicBlockRef llvm_block = LLVMAppendBasicBlock(bad_resume_block->split_llvm_fn, "BadResume"); |
| 6761 | | LLVMPositionBuilderAtEnd(g->builder, llvm_block); |
| 6762 | | gen_safety_crash(g, PanicMsgIdBadResume); |
| 6764 | if (!g->strip_debug_symbols) { |
| 6765 | AstNode *source_node = fn_table_entry->proto_node; |
| 6766 | ZigLLVMSetCurrentDebugLocation(g->builder, (int)source_node->line + 1, |
| 6767 | (int)source_node->column + 1, get_di_scope(g, fn_table_entry->child_scope)); |
| 6768 | } |
| 6769 | IrExecutable *executable = &fn_table_entry->analyzed_executable; |
| 6770 | LLVMBasicBlockRef bad_resume_block = LLVMAppendBasicBlock(g->cur_fn_val, "BadResume"); |
| 6771 | LLVMPositionBuilderAtEnd(g->builder, bad_resume_block); |
| 6772 | gen_assertion_scope(g, PanicMsgIdBadResume, fn_table_entry->child_scope); |
| 6763 | 6773 | |
| 6764 | | fn_table_entry->resume_blocks.append(bad_resume_block); |
| 6774 | LLVMPositionBuilderAtEnd(g->builder, fn_table_entry->preamble_llvm_block); |
| 6775 | render_async_spills(g); |
| 6776 | g->cur_async_awaiter_ptr = LLVMBuildStructGEP(g->builder, g->cur_ret_ptr, coro_awaiter_index, ""); |
| 6777 | LLVMValueRef resume_index_ptr = LLVMBuildStructGEP(g->builder, g->cur_ret_ptr, coro_resume_index, ""); |
| 6778 | g->cur_async_resume_index_ptr = resume_index_ptr; |
| 6779 | LLVMValueRef resume_index = LLVMBuildLoad(g->builder, resume_index_ptr, ""); |
| 6780 | LLVMValueRef switch_instr = LLVMBuildSwitch(g->builder, resume_index, bad_resume_block, |
| 6781 | fn_table_entry->resume_blocks.length + coro_extra_resume_block_count); |
| 6782 | g->cur_async_switch_instr = switch_instr; |
| 6783 | |
| 6784 | LLVMValueRef zero = LLVMConstNull(usize_type_ref); |
| 6785 | LLVMAddCase(switch_instr, zero, executable->basic_block_list.at(0)->llvm_block); |
| 6786 | |
| 6787 | for (size_t resume_i = 0; resume_i < fn_table_entry->resume_blocks.length; resume_i += 1) { |
| 6788 | IrBasicBlock *resume_block = fn_table_entry->resume_blocks.at(resume_i); |
| 6789 | LLVMValueRef case_value = LLVMConstInt(usize_type_ref, resume_block->resume_index, false); |
| 6790 | LLVMAddCase(switch_instr, case_value, resume_block->llvm_block); |
| 6765 | 6791 | } |
| 6792 | |
| 6766 | 6793 | } else { |
| 6767 | 6794 | // create debug variable declarations for parameters |
| 6768 | 6795 | // rely on the first variables in the variable_list being parameters. |