implement @frame
and @Frame
This commit is contained in:
parent
ead2d32be8
commit
70bced5dcf
4
BRANCH_TODO
Normal file
4
BRANCH_TODO
Normal file
|
@ -0,0 +1,4 @@
|
|||
* await
|
||||
* await of a non async function
|
||||
* async call on a non async function
|
||||
* safety for resuming when it is awaiting
|
|
@ -1435,8 +1435,6 @@ enum BuiltinFnId {
|
|||
BuiltinFnIdErrName,
|
||||
BuiltinFnIdBreakpoint,
|
||||
BuiltinFnIdReturnAddress,
|
||||
BuiltinFnIdFrameAddress,
|
||||
BuiltinFnIdHandle,
|
||||
BuiltinFnIdEmbedFile,
|
||||
BuiltinFnIdCmpxchgWeak,
|
||||
BuiltinFnIdCmpxchgStrong,
|
||||
|
@ -1507,6 +1505,9 @@ enum BuiltinFnId {
|
|||
BuiltinFnIdAtomicLoad,
|
||||
BuiltinFnIdHasDecl,
|
||||
BuiltinFnIdUnionInit,
|
||||
BuiltinFnIdFrameAddress,
|
||||
BuiltinFnIdFrameType,
|
||||
BuiltinFnIdFrameHandle,
|
||||
};
|
||||
|
||||
struct BuiltinFnEntry {
|
||||
|
@ -2252,7 +2253,8 @@ enum IrInstructionId {
|
|||
IrInstructionIdBreakpoint,
|
||||
IrInstructionIdReturnAddress,
|
||||
IrInstructionIdFrameAddress,
|
||||
IrInstructionIdHandle,
|
||||
IrInstructionIdFrameHandle,
|
||||
IrInstructionIdFrameType,
|
||||
IrInstructionIdAlignOf,
|
||||
IrInstructionIdOverflowOp,
|
||||
IrInstructionIdTestErrSrc,
|
||||
|
@ -3038,10 +3040,16 @@ struct IrInstructionFrameAddress {
|
|||
IrInstruction base;
|
||||
};
|
||||
|
||||
struct IrInstructionHandle {
|
||||
struct IrInstructionFrameHandle {
|
||||
IrInstruction base;
|
||||
};
|
||||
|
||||
struct IrInstructionFrameType {
|
||||
IrInstruction base;
|
||||
|
||||
IrInstruction *fn;
|
||||
};
|
||||
|
||||
enum IrOverflowOp {
|
||||
IrOverflowOpAdd,
|
||||
IrOverflowOpSub,
|
||||
|
|
|
@ -4457,10 +4457,8 @@ static LLVMValueRef ir_render_frame_address(CodeGen *g, IrExecutable *executable
|
|||
return LLVMBuildPtrToInt(g->builder, ptr_val, g->builtin_types.entry_usize->llvm_type, "");
|
||||
}
|
||||
|
||||
static LLVMValueRef ir_render_handle(CodeGen *g, IrExecutable *executable,
|
||||
IrInstructionHandle *instruction)
|
||||
{
|
||||
zig_panic("TODO @handle() codegen");
|
||||
static LLVMValueRef ir_render_handle(CodeGen *g, IrExecutable *executable, IrInstructionFrameHandle *instruction) {
|
||||
return g->cur_ret_ptr;
|
||||
}
|
||||
|
||||
static LLVMValueRef render_shl_with_overflow(CodeGen *g, IrInstructionOverflowOp *instruction) {
|
||||
|
@ -5008,6 +5006,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
|
|||
case IrInstructionIdBitCastSrc:
|
||||
case IrInstructionIdTestErrSrc:
|
||||
case IrInstructionIdUnionInitNamedField:
|
||||
case IrInstructionIdFrameType:
|
||||
zig_unreachable();
|
||||
|
||||
case IrInstructionIdDeclVarGen:
|
||||
|
@ -5086,8 +5085,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
|
|||
return ir_render_return_address(g, executable, (IrInstructionReturnAddress *)instruction);
|
||||
case IrInstructionIdFrameAddress:
|
||||
return ir_render_frame_address(g, executable, (IrInstructionFrameAddress *)instruction);
|
||||
case IrInstructionIdHandle:
|
||||
return ir_render_handle(g, executable, (IrInstructionHandle *)instruction);
|
||||
case IrInstructionIdFrameHandle:
|
||||
return ir_render_handle(g, executable, (IrInstructionFrameHandle *)instruction);
|
||||
case IrInstructionIdOverflowOp:
|
||||
return ir_render_overflow_op(g, executable, (IrInstructionOverflowOp *)instruction);
|
||||
case IrInstructionIdTestErrGen:
|
||||
|
@ -6754,8 +6753,6 @@ static BuiltinFnEntry *create_builtin_fn(CodeGen *g, BuiltinFnId id, const char
|
|||
static void define_builtin_fns(CodeGen *g) {
|
||||
create_builtin_fn(g, BuiltinFnIdBreakpoint, "breakpoint", 0);
|
||||
create_builtin_fn(g, BuiltinFnIdReturnAddress, "returnAddress", 0);
|
||||
create_builtin_fn(g, BuiltinFnIdFrameAddress, "frameAddress", 0);
|
||||
create_builtin_fn(g, BuiltinFnIdHandle, "handle", 0);
|
||||
create_builtin_fn(g, BuiltinFnIdMemcpy, "memcpy", 3);
|
||||
create_builtin_fn(g, BuiltinFnIdMemset, "memset", 3);
|
||||
create_builtin_fn(g, BuiltinFnIdSizeof, "sizeOf", 1);
|
||||
|
@ -6856,6 +6853,9 @@ static void define_builtin_fns(CodeGen *g) {
|
|||
create_builtin_fn(g, BuiltinFnIdThis, "This", 0);
|
||||
create_builtin_fn(g, BuiltinFnIdHasDecl, "hasDecl", 2);
|
||||
create_builtin_fn(g, BuiltinFnIdUnionInit, "unionInit", 3);
|
||||
create_builtin_fn(g, BuiltinFnIdFrameHandle, "frame", 0);
|
||||
create_builtin_fn(g, BuiltinFnIdFrameType, "Frame", 1);
|
||||
create_builtin_fn(g, BuiltinFnIdFrameAddress, "frameAddress", 0);
|
||||
}
|
||||
|
||||
static const char *bool_to_str(bool b) {
|
||||
|
|
71
src/ir.cpp
71
src/ir.cpp
|
@ -755,8 +755,12 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionFrameAddress *)
|
|||
return IrInstructionIdFrameAddress;
|
||||
}
|
||||
|
||||
static constexpr IrInstructionId ir_instruction_id(IrInstructionHandle *) {
|
||||
return IrInstructionIdHandle;
|
||||
static constexpr IrInstructionId ir_instruction_id(IrInstructionFrameHandle *) {
|
||||
return IrInstructionIdFrameHandle;
|
||||
}
|
||||
|
||||
static constexpr IrInstructionId ir_instruction_id(IrInstructionFrameType *) {
|
||||
return IrInstructionIdFrameType;
|
||||
}
|
||||
|
||||
static constexpr IrInstructionId ir_instruction_id(IrInstructionAlignOf *) {
|
||||
|
@ -2362,7 +2366,16 @@ static IrInstruction *ir_build_frame_address(IrBuilder *irb, Scope *scope, AstNo
|
|||
}
|
||||
|
||||
static IrInstruction *ir_build_handle(IrBuilder *irb, Scope *scope, AstNode *source_node) {
|
||||
IrInstructionHandle *instruction = ir_build_instruction<IrInstructionHandle>(irb, scope, source_node);
|
||||
IrInstructionFrameHandle *instruction = ir_build_instruction<IrInstructionFrameHandle>(irb, scope, source_node);
|
||||
return &instruction->base;
|
||||
}
|
||||
|
||||
static IrInstruction *ir_build_frame_type(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *fn) {
|
||||
IrInstructionFrameType *instruction = ir_build_instruction<IrInstructionFrameType>(irb, scope, source_node);
|
||||
instruction->fn = fn;
|
||||
|
||||
ir_ref_instruction(fn, irb->current_basic_block);
|
||||
|
||||
return &instruction->base;
|
||||
}
|
||||
|
||||
|
@ -3358,11 +3371,6 @@ static ScopeDeferExpr *get_scope_defer_expr(Scope *scope) {
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
static bool exec_is_async(IrExecutable *exec) {
|
||||
ZigFn *fn_entry = exec_fn_entry(exec);
|
||||
return fn_entry != nullptr && fn_entry->type_entry->data.fn.fn_type_id.cc == CallingConventionAsync;
|
||||
}
|
||||
|
||||
static IrInstruction *ir_gen_async_return(IrBuilder *irb, Scope *scope, AstNode *node, IrInstruction *return_value,
|
||||
bool is_generated_code)
|
||||
{
|
||||
|
@ -4278,8 +4286,6 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
|
|||
return irb->codegen->invalid_instruction;
|
||||
}
|
||||
|
||||
bool is_async = exec_is_async(irb->exec);
|
||||
|
||||
switch (builtin_fn->id) {
|
||||
case BuiltinFnIdInvalid:
|
||||
zig_unreachable();
|
||||
|
@ -4902,16 +4908,21 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
|
|||
return ir_lval_wrap(irb, scope, ir_build_return_address(irb, scope, node), lval, result_loc);
|
||||
case BuiltinFnIdFrameAddress:
|
||||
return ir_lval_wrap(irb, scope, ir_build_frame_address(irb, scope, node), lval, result_loc);
|
||||
case BuiltinFnIdHandle:
|
||||
case BuiltinFnIdFrameHandle:
|
||||
if (!irb->exec->fn_entry) {
|
||||
add_node_error(irb->codegen, node, buf_sprintf("@handle() called outside of function definition"));
|
||||
return irb->codegen->invalid_instruction;
|
||||
}
|
||||
if (!is_async) {
|
||||
add_node_error(irb->codegen, node, buf_sprintf("@handle() in non-async function"));
|
||||
return irb->codegen->invalid_instruction;
|
||||
}
|
||||
return ir_lval_wrap(irb, scope, ir_build_handle(irb, scope, node), lval, result_loc);
|
||||
case BuiltinFnIdFrameType: {
|
||||
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
|
||||
IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
|
||||
if (arg0_value == irb->codegen->invalid_instruction)
|
||||
return arg0_value;
|
||||
|
||||
IrInstruction *frame_type = ir_build_frame_type(irb, scope, node, arg0_value);
|
||||
return ir_lval_wrap(irb, scope, frame_type, lval, result_loc);
|
||||
}
|
||||
case BuiltinFnIdAlignOf:
|
||||
{
|
||||
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
|
||||
|
@ -21726,8 +21737,25 @@ static IrInstruction *ir_analyze_instruction_frame_address(IrAnalyze *ira, IrIns
|
|||
return result;
|
||||
}
|
||||
|
||||
static IrInstruction *ir_analyze_instruction_handle(IrAnalyze *ira, IrInstructionHandle *instruction) {
|
||||
zig_panic("TODO anlayze @handle()");
|
||||
static IrInstruction *ir_analyze_instruction_frame_handle(IrAnalyze *ira, IrInstructionFrameHandle *instruction) {
|
||||
ZigFn *fn = exec_fn_entry(ira->new_irb.exec);
|
||||
ir_assert(fn != nullptr, &instruction->base);
|
||||
|
||||
ZigType *frame_type = get_coro_frame_type(ira->codegen, fn);
|
||||
ZigType *ptr_frame_type = get_pointer_to_type(ira->codegen, frame_type, false);
|
||||
|
||||
IrInstruction *result = ir_build_handle(&ira->new_irb, instruction->base.scope, instruction->base.source_node);
|
||||
result->value.type = ptr_frame_type;
|
||||
return result;
|
||||
}
|
||||
|
||||
static IrInstruction *ir_analyze_instruction_frame_type(IrAnalyze *ira, IrInstructionFrameType *instruction) {
|
||||
ZigFn *fn = ir_resolve_fn(ira, instruction->fn->child);
|
||||
if (fn == nullptr)
|
||||
return ira->codegen->invalid_instruction;
|
||||
|
||||
ZigType *ty = get_coro_frame_type(ira->codegen, fn);
|
||||
return ir_const_type(ira, &instruction->base, ty);
|
||||
}
|
||||
|
||||
static IrInstruction *ir_analyze_instruction_align_of(IrAnalyze *ira, IrInstructionAlignOf *instruction) {
|
||||
|
@ -24355,8 +24383,10 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction
|
|||
return ir_analyze_instruction_return_address(ira, (IrInstructionReturnAddress *)instruction);
|
||||
case IrInstructionIdFrameAddress:
|
||||
return ir_analyze_instruction_frame_address(ira, (IrInstructionFrameAddress *)instruction);
|
||||
case IrInstructionIdHandle:
|
||||
return ir_analyze_instruction_handle(ira, (IrInstructionHandle *)instruction);
|
||||
case IrInstructionIdFrameHandle:
|
||||
return ir_analyze_instruction_frame_handle(ira, (IrInstructionFrameHandle *)instruction);
|
||||
case IrInstructionIdFrameType:
|
||||
return ir_analyze_instruction_frame_type(ira, (IrInstructionFrameType *)instruction);
|
||||
case IrInstructionIdAlignOf:
|
||||
return ir_analyze_instruction_align_of(ira, (IrInstructionAlignOf *)instruction);
|
||||
case IrInstructionIdOverflowOp:
|
||||
|
@ -24650,7 +24680,8 @@ bool ir_has_side_effects(IrInstruction *instruction) {
|
|||
case IrInstructionIdAlignOf:
|
||||
case IrInstructionIdReturnAddress:
|
||||
case IrInstructionIdFrameAddress:
|
||||
case IrInstructionIdHandle:
|
||||
case IrInstructionIdFrameHandle:
|
||||
case IrInstructionIdFrameType:
|
||||
case IrInstructionIdTestErrSrc:
|
||||
case IrInstructionIdTestErrGen:
|
||||
case IrInstructionIdFnProto:
|
||||
|
|
|
@ -906,8 +906,14 @@ static void ir_print_frame_address(IrPrint *irp, IrInstructionFrameAddress *inst
|
|||
fprintf(irp->f, "@frameAddress()");
|
||||
}
|
||||
|
||||
static void ir_print_handle(IrPrint *irp, IrInstructionHandle *instruction) {
|
||||
fprintf(irp->f, "@handle()");
|
||||
static void ir_print_handle(IrPrint *irp, IrInstructionFrameHandle *instruction) {
|
||||
fprintf(irp->f, "@frame()");
|
||||
}
|
||||
|
||||
static void ir_print_frame_type(IrPrint *irp, IrInstructionFrameType *instruction) {
|
||||
fprintf(irp->f, "@Frame(");
|
||||
ir_print_other_instruction(irp, instruction->fn);
|
||||
fprintf(irp->f, ")");
|
||||
}
|
||||
|
||||
static void ir_print_return_address(IrPrint *irp, IrInstructionReturnAddress *instruction) {
|
||||
|
@ -1764,8 +1770,11 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
|
|||
case IrInstructionIdFrameAddress:
|
||||
ir_print_frame_address(irp, (IrInstructionFrameAddress *)instruction);
|
||||
break;
|
||||
case IrInstructionIdHandle:
|
||||
ir_print_handle(irp, (IrInstructionHandle *)instruction);
|
||||
case IrInstructionIdFrameHandle:
|
||||
ir_print_handle(irp, (IrInstructionFrameHandle *)instruction);
|
||||
break;
|
||||
case IrInstructionIdFrameType:
|
||||
ir_print_frame_type(irp, (IrInstructionFrameType *)instruction);
|
||||
break;
|
||||
case IrInstructionIdAlignOf:
|
||||
ir_print_align_of(irp, (IrInstructionAlignOf *)instruction);
|
||||
|
|
|
@ -79,15 +79,23 @@ test "local variable in async function" {
|
|||
|
||||
test "calling an inferred async function" {
|
||||
const S = struct {
|
||||
var x: i32 = 1;
|
||||
var other_frame: *@Frame(other) = undefined;
|
||||
|
||||
fn doTheTest() void {
|
||||
const p = async first();
|
||||
expect(x == 1);
|
||||
resume other_frame.*;
|
||||
expect(x == 2);
|
||||
}
|
||||
|
||||
fn first() void {
|
||||
other();
|
||||
}
|
||||
fn other() void {
|
||||
other_frame = @frame();
|
||||
suspend;
|
||||
x += 1;
|
||||
}
|
||||
};
|
||||
S.doTheTest();
|
||||
|
|
Loading…
Reference in New Issue
Block a user