| author | |
| committer | |
| log | d62f7c6b605a672f032aff8870496d2ae2366017 |
| tree | 659ae46ac0061fcafd3ec29de8682ec1f18e97cc |
| parent | e7912dee9bd63b03415f441b4de9b3babc79c859 |
| parent | 8b1900e5df76a126404c6905b9e91136c738da55 |
21 files changed, 1020 insertions(+), 205 deletions(-)
doc/langref.html.in+16| ... | @@ -8114,7 +8114,23 @@ pub const TypeInfo = union(TypeId) { | ... | @@ -8114,7 +8114,23 @@ pub const TypeInfo = union(TypeId) { |
| 8114 | This function returns a compile-time constant, which is the type of the | 8114 | This function returns a compile-time constant, which is the type of the |
| 8115 | expression passed as an argument. The expression is evaluated. | 8115 | expression passed as an argument. The expression is evaluated. |
| 8116 | </p> | 8116 | </p> |
| 8117 | <p>{#syntax#}@typeOf{#endsyntax#} guarantees no run-time side-effects within the expression:</p> | ||
| 8118 | {#code_begin|test#} | ||
| 8119 | const std = @import("std"); | ||
| 8120 | const assert = std.debug.assert; | ||
| 8121 | |||
| 8122 | test "no runtime side effects" { | ||
| 8123 | var data: i32 = 0; | ||
| 8124 | const T = @typeOf(foo(i32, &data)); | ||
| 8125 | comptime assert(T == i32); | ||
| 8126 | assert(data == 0); | ||
| 8127 | } | ||
| 8117 | 8128 | ||
| 8129 | fn foo(comptime T: type, ptr: *T) T { | ||
| 8130 | ptr.* += 1; | ||
| 8131 | return ptr.*; | ||
| 8132 | } | ||
| 8133 | {#code_end#} | ||
| 8118 | {#header_close#} | 8134 | {#header_close#} |
| 8119 | 8135 | ||
| 8120 | {#header_open|@unionInit#} | 8136 | {#header_open|@unionInit#} |
src/all_types.hpp+11-1| ... | @@ -627,7 +627,7 @@ struct AstNodeParamDecl { | ... | @@ -627,7 +627,7 @@ struct AstNodeParamDecl { |
| 627 | AstNode *type; | 627 | AstNode *type; |
| 628 | Token *var_token; | 628 | Token *var_token; |
| 629 | bool is_noalias; | 629 | bool is_noalias; |
| 630 | bool is_inline; | 630 | bool is_comptime; |
| 631 | bool is_var_args; | 631 | bool is_var_args; |
| 632 | }; | 632 | }; |
| 633 | 633 | ||
| ... | @@ -2104,6 +2104,7 @@ enum ScopeId { | ... | @@ -2104,6 +2104,7 @@ enum ScopeId { |
| 2104 | ScopeIdFnDef, | 2104 | ScopeIdFnDef, |
| 2105 | ScopeIdCompTime, | 2105 | ScopeIdCompTime, |
| 2106 | ScopeIdRuntime, | 2106 | ScopeIdRuntime, |
| 2107 | ScopeIdTypeOf, | ||
| 2107 | }; | 2108 | }; |
| 2108 | 2109 | ||
| 2109 | struct Scope { | 2110 | struct Scope { |
| ... | @@ -2244,6 +2245,13 @@ struct ScopeFnDef { | ... | @@ -2244,6 +2245,13 @@ struct ScopeFnDef { |
| 2244 | ZigFn *fn_entry; | 2245 | ZigFn *fn_entry; |
| 2245 | }; | 2246 | }; |
| 2246 | 2247 | ||
| 2248 | // This scope is created for a @typeOf. | ||
| 2249 | // All runtime side-effects are elided within it. | ||
| 2250 | // NodeTypeFnCallExpr | ||
| 2251 | struct ScopeTypeOf { | ||
| 2252 | Scope base; | ||
| 2253 | }; | ||
| 2254 | |||
| 2247 | // synchronized with code in define_builtin_compile_vars | 2255 | // synchronized with code in define_builtin_compile_vars |
| 2248 | enum AtomicOrder { | 2256 | enum AtomicOrder { |
| 2249 | AtomicOrderUnordered, | 2257 | AtomicOrderUnordered, |
| ... | @@ -2711,6 +2719,7 @@ struct IrInstructionCallSrc { | ... | @@ -2711,6 +2719,7 @@ struct IrInstructionCallSrc { |
| 2711 | IrInstruction *new_stack; | 2719 | IrInstruction *new_stack; |
| 2712 | FnInline fn_inline; | 2720 | FnInline fn_inline; |
| 2713 | bool is_async; | 2721 | bool is_async; |
| 2722 | bool is_async_call_builtin; | ||
| 2714 | bool is_comptime; | 2723 | bool is_comptime; |
| 2715 | }; | 2724 | }; |
| 2716 | 2725 | ||
| ... | @@ -2727,6 +2736,7 @@ struct IrInstructionCallGen { | ... | @@ -2727,6 +2736,7 @@ struct IrInstructionCallGen { |
| 2727 | IrInstruction *new_stack; | 2736 | IrInstruction *new_stack; |
| 2728 | FnInline fn_inline; | 2737 | FnInline fn_inline; |
| 2729 | bool is_async; | 2738 | bool is_async; |
| 2739 | bool is_async_call_builtin; | ||
| 2730 | }; | 2740 | }; |
| 2731 | 2741 | ||
| 2732 | struct IrInstructionConst { | 2742 | struct IrInstructionConst { |
src/analyze.cpp+33-4| ... | @@ -197,6 +197,12 @@ Scope *create_comptime_scope(CodeGen *g, AstNode *node, Scope *parent) { | ... | @@ -197,6 +197,12 @@ Scope *create_comptime_scope(CodeGen *g, AstNode *node, Scope *parent) { |
| 197 | return &scope->base; | 197 | return &scope->base; |
| 198 | } | 198 | } |
| 199 | 199 | ||
| 200 | Scope *create_typeof_scope(CodeGen *g, AstNode *node, Scope *parent) { | ||
| 201 | ScopeTypeOf *scope = allocate<ScopeTypeOf>(1); | ||
| 202 | init_scope(g, &scope->base, ScopeIdTypeOf, node, parent); | ||
| 203 | return &scope->base; | ||
| 204 | } | ||
| 205 | |||
| 200 | ZigType *get_scope_import(Scope *scope) { | 206 | ZigType *get_scope_import(Scope *scope) { |
| 201 | while (scope) { | 207 | while (scope) { |
| 202 | if (scope->id == ScopeIdDecls) { | 208 | if (scope->id == ScopeIdDecls) { |
| ... | @@ -209,6 +215,22 @@ ZigType *get_scope_import(Scope *scope) { | ... | @@ -209,6 +215,22 @@ ZigType *get_scope_import(Scope *scope) { |
| 209 | zig_unreachable(); | 215 | zig_unreachable(); |
| 210 | } | 216 | } |
| 211 | 217 | ||
| 218 | ScopeTypeOf *get_scope_typeof(Scope *scope) { | ||
| 219 | while (scope) { | ||
| 220 | switch (scope->id) { | ||
| 221 | case ScopeIdTypeOf: | ||
| 222 | return reinterpret_cast<ScopeTypeOf *>(scope); | ||
| 223 | case ScopeIdFnDef: | ||
| 224 | case ScopeIdDecls: | ||
| 225 | return nullptr; | ||
| 226 | default: | ||
| 227 | scope = scope->parent; | ||
| 228 | continue; | ||
| 229 | } | ||
| 230 | } | ||
| 231 | zig_unreachable(); | ||
| 232 | } | ||
| 233 | |||
| 212 | static ZigType *new_container_type_entry(CodeGen *g, ZigTypeId id, AstNode *source_node, Scope *parent_scope, | 234 | static ZigType *new_container_type_entry(CodeGen *g, ZigTypeId id, AstNode *source_node, Scope *parent_scope, |
| 213 | Buf *bare_name) | 235 | Buf *bare_name) |
| 214 | { | 236 | { |
| ... | @@ -1556,7 +1578,7 @@ static ZigType *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_sc | ... | @@ -1556,7 +1578,7 @@ static ZigType *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_sc |
| 1556 | AstNode *param_node = fn_proto->params.at(fn_type_id.next_param_index); | 1578 | AstNode *param_node = fn_proto->params.at(fn_type_id.next_param_index); |
| 1557 | assert(param_node->type == NodeTypeParamDecl); | 1579 | assert(param_node->type == NodeTypeParamDecl); |
| 1558 | 1580 | ||
| 1559 | bool param_is_comptime = param_node->data.param_decl.is_inline; | 1581 | bool param_is_comptime = param_node->data.param_decl.is_comptime; |
| 1560 | bool param_is_var_args = param_node->data.param_decl.is_var_args; | 1582 | bool param_is_var_args = param_node->data.param_decl.is_var_args; |
| 1561 | 1583 | ||
| 1562 | if (param_is_comptime) { | 1584 | if (param_is_comptime) { |
| ... | @@ -4393,7 +4415,7 @@ static void analyze_fn_ir(CodeGen *g, ZigFn *fn, AstNode *return_type_node) { | ... | @@ -4393,7 +4415,7 @@ static void analyze_fn_ir(CodeGen *g, ZigFn *fn, AstNode *return_type_node) { |
| 4393 | 4415 | ||
| 4394 | if (g->verbose_ir) { | 4416 | if (g->verbose_ir) { |
| 4395 | fprintf(stderr, "fn %s() { // (analyzed)\n", buf_ptr(&fn->symbol_name)); | 4417 | fprintf(stderr, "fn %s() { // (analyzed)\n", buf_ptr(&fn->symbol_name)); |
| 4396 | ir_print(g, stderr, &fn->analyzed_executable, 4); | 4418 | ir_print(g, stderr, &fn->analyzed_executable, 4, 2); |
| 4397 | fprintf(stderr, "}\n"); | 4419 | fprintf(stderr, "}\n"); |
| 4398 | } | 4420 | } |
| 4399 | fn->anal_state = FnAnalStateComplete; | 4421 | fn->anal_state = FnAnalStateComplete; |
| ... | @@ -4427,7 +4449,7 @@ static void analyze_fn_body(CodeGen *g, ZigFn *fn_table_entry) { | ... | @@ -4427,7 +4449,7 @@ static void analyze_fn_body(CodeGen *g, ZigFn *fn_table_entry) { |
| 4427 | fprintf(stderr, "\n"); | 4449 | fprintf(stderr, "\n"); |
| 4428 | ast_render(stderr, fn_table_entry->body_node, 4); | 4450 | ast_render(stderr, fn_table_entry->body_node, 4); |
| 4429 | fprintf(stderr, "\n{ // (IR)\n"); | 4451 | fprintf(stderr, "\n{ // (IR)\n"); |
| 4430 | ir_print(g, stderr, &fn_table_entry->ir_executable, 4); | 4452 | ir_print(g, stderr, &fn_table_entry->ir_executable, 4, 1); |
| 4431 | fprintf(stderr, "}\n"); | 4453 | fprintf(stderr, "}\n"); |
| 4432 | } | 4454 | } |
| 4433 | 4455 | ||
| ... | @@ -5705,6 +5727,10 @@ static Error resolve_async_frame(CodeGen *g, ZigType *frame_type) { | ... | @@ -5705,6 +5727,10 @@ static Error resolve_async_frame(CodeGen *g, ZigType *frame_type) { |
| 5705 | 5727 | ||
| 5706 | for (size_t i = 0; i < fn->call_list.length; i += 1) { | 5728 | for (size_t i = 0; i < fn->call_list.length; i += 1) { |
| 5707 | IrInstructionCallGen *call = fn->call_list.at(i); | 5729 | IrInstructionCallGen *call = fn->call_list.at(i); |
| 5730 | if (call->new_stack != nullptr) { | ||
| 5731 | // don't need to allocate a frame for this | ||
| 5732 | continue; | ||
| 5733 | } | ||
| 5708 | ZigFn *callee = call->fn_entry; | 5734 | ZigFn *callee = call->fn_entry; |
| 5709 | if (callee == nullptr) { | 5735 | if (callee == nullptr) { |
| 5710 | add_node_error(g, call->base.source_node, | 5736 | add_node_error(g, call->base.source_node, |
| ... | @@ -8234,6 +8260,10 @@ static void resolve_llvm_types_anyerror(CodeGen *g) { | ... | @@ -8234,6 +8260,10 @@ static void resolve_llvm_types_anyerror(CodeGen *g) { |
| 8234 | } | 8260 | } |
| 8235 | 8261 | ||
| 8236 | static void resolve_llvm_types_async_frame(CodeGen *g, ZigType *frame_type, ResolveStatus wanted_resolve_status) { | 8262 | static void resolve_llvm_types_async_frame(CodeGen *g, ZigType *frame_type, ResolveStatus wanted_resolve_status) { |
| 8263 | Error err; | ||
| 8264 | if ((err = type_resolve(g, frame_type, ResolveStatusSizeKnown))) | ||
| 8265 | zig_unreachable(); | ||
| 8266 | |||
| 8237 | ZigType *passed_frame_type = fn_is_async(frame_type->data.frame.fn) ? frame_type : nullptr; | 8267 | ZigType *passed_frame_type = fn_is_async(frame_type->data.frame.fn) ? frame_type : nullptr; |
| 8238 | resolve_llvm_types_struct(g, frame_type->data.frame.locals_struct, wanted_resolve_status, passed_frame_type); | 8268 | resolve_llvm_types_struct(g, frame_type->data.frame.locals_struct, wanted_resolve_status, passed_frame_type); |
| 8239 | frame_type->llvm_type = frame_type->data.frame.locals_struct->llvm_type; | 8269 | frame_type->llvm_type = frame_type->data.frame.locals_struct->llvm_type; |
| ... | @@ -8375,7 +8405,6 @@ static void resolve_llvm_types_any_frame(CodeGen *g, ZigType *any_frame_type, Re | ... | @@ -8375,7 +8405,6 @@ static void resolve_llvm_types_any_frame(CodeGen *g, ZigType *any_frame_type, Re |
| 8375 | } | 8405 | } |
| 8376 | 8406 | ||
| 8377 | static void resolve_llvm_types(CodeGen *g, ZigType *type, ResolveStatus wanted_resolve_status) { | 8407 | static void resolve_llvm_types(CodeGen *g, ZigType *type, ResolveStatus wanted_resolve_status) { |
| 8378 | assert(type->id == ZigTypeIdOpaque || type_is_resolved(type, ResolveStatusSizeKnown)); | ||
| 8379 | assert(wanted_resolve_status > ResolveStatusSizeKnown); | 8408 | assert(wanted_resolve_status > ResolveStatusSizeKnown); |
| 8380 | switch (type->id) { | 8409 | switch (type->id) { |
| 8381 | case ZigTypeIdInvalid: | 8410 | case ZigTypeIdInvalid: |
src/analyze.hpp+2| ... | @@ -85,6 +85,7 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node); | ... | @@ -85,6 +85,7 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node); |
| 85 | ZigFn *scope_fn_entry(Scope *scope); | 85 | ZigFn *scope_fn_entry(Scope *scope); |
| 86 | ZigPackage *scope_package(Scope *scope); | 86 | ZigPackage *scope_package(Scope *scope); |
| 87 | ZigType *get_scope_import(Scope *scope); | 87 | ZigType *get_scope_import(Scope *scope); |
| 88 | ScopeTypeOf *get_scope_typeof(Scope *scope); | ||
| 88 | void init_tld(Tld *tld, TldId id, Buf *name, VisibMod visib_mod, AstNode *source_node, Scope *parent_scope); | 89 | void init_tld(Tld *tld, TldId id, Buf *name, VisibMod visib_mod, AstNode *source_node, Scope *parent_scope); |
| 89 | ZigVar *add_variable(CodeGen *g, AstNode *source_node, Scope *parent_scope, Buf *name, | 90 | ZigVar *add_variable(CodeGen *g, AstNode *source_node, Scope *parent_scope, Buf *name, |
| 90 | bool is_const, ConstExprValue *init_value, Tld *src_tld, ZigType *var_type); | 91 | bool is_const, ConstExprValue *init_value, Tld *src_tld, ZigType *var_type); |
| ... | @@ -112,6 +113,7 @@ ScopeSuspend *create_suspend_scope(CodeGen *g, AstNode *node, Scope *parent); | ... | @@ -112,6 +113,7 @@ ScopeSuspend *create_suspend_scope(CodeGen *g, AstNode *node, Scope *parent); |
| 112 | ScopeFnDef *create_fndef_scope(CodeGen *g, AstNode *node, Scope *parent, ZigFn *fn_entry); | 113 | ScopeFnDef *create_fndef_scope(CodeGen *g, AstNode *node, Scope *parent, ZigFn *fn_entry); |
| 113 | Scope *create_comptime_scope(CodeGen *g, AstNode *node, Scope *parent); | 114 | Scope *create_comptime_scope(CodeGen *g, AstNode *node, Scope *parent); |
| 114 | Scope *create_runtime_scope(CodeGen *g, AstNode *node, Scope *parent, IrInstruction *is_comptime); | 115 | Scope *create_runtime_scope(CodeGen *g, AstNode *node, Scope *parent, IrInstruction *is_comptime); |
| 116 | Scope *create_typeof_scope(CodeGen *g, AstNode *node, Scope *parent); | ||
| 115 | 117 | ||
| 116 | void init_const_str_lit(CodeGen *g, ConstExprValue *const_val, Buf *str); | 118 | void init_const_str_lit(CodeGen *g, ConstExprValue *const_val, Buf *str); |
| 117 | ConstExprValue *create_const_str_lit(CodeGen *g, Buf *str); | 119 | ConstExprValue *create_const_str_lit(CodeGen *g, Buf *str); |
src/ast_render.cpp+1-1| ... | @@ -448,7 +448,7 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { | ... | @@ -448,7 +448,7 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { |
| 448 | assert(param_decl->type == NodeTypeParamDecl); | 448 | assert(param_decl->type == NodeTypeParamDecl); |
| 449 | if (param_decl->data.param_decl.name != nullptr) { | 449 | if (param_decl->data.param_decl.name != nullptr) { |
| 450 | const char *noalias_str = param_decl->data.param_decl.is_noalias ? "noalias " : ""; | 450 | const char *noalias_str = param_decl->data.param_decl.is_noalias ? "noalias " : ""; |
| 451 | const char *inline_str = param_decl->data.param_decl.is_inline ? "inline " : ""; | 451 | const char *inline_str = param_decl->data.param_decl.is_comptime ? "comptime " : ""; |
| 452 | fprintf(ar->f, "%s%s", noalias_str, inline_str); | 452 | fprintf(ar->f, "%s%s", noalias_str, inline_str); |
| 453 | print_symbol(ar, param_decl->data.param_decl.name); | 453 | print_symbol(ar, param_decl->data.param_decl.name); |
| 454 | fprintf(ar->f, ": "); | 454 | fprintf(ar->f, ": "); |
src/codegen.cpp+54-21| ... | @@ -645,6 +645,7 @@ static ZigLLVMDIScope *get_di_scope(CodeGen *g, Scope *scope) { | ... | @@ -645,6 +645,7 @@ static ZigLLVMDIScope *get_di_scope(CodeGen *g, Scope *scope) { |
| 645 | case ScopeIdSuspend: | 645 | case ScopeIdSuspend: |
| 646 | case ScopeIdCompTime: | 646 | case ScopeIdCompTime: |
| 647 | case ScopeIdRuntime: | 647 | case ScopeIdRuntime: |
| 648 | case ScopeIdTypeOf: | ||
| 648 | return get_di_scope(g, scope->parent); | 649 | return get_di_scope(g, scope->parent); |
| 649 | } | 650 | } |
| 650 | zig_unreachable(); | 651 | zig_unreachable(); |
| ... | @@ -3757,6 +3758,7 @@ static void render_async_var_decls(CodeGen *g, Scope *scope) { | ... | @@ -3757,6 +3758,7 @@ static void render_async_var_decls(CodeGen *g, Scope *scope) { |
| 3757 | case ScopeIdSuspend: | 3758 | case ScopeIdSuspend: |
| 3758 | case ScopeIdCompTime: | 3759 | case ScopeIdCompTime: |
| 3759 | case ScopeIdRuntime: | 3760 | case ScopeIdRuntime: |
| 3761 | case ScopeIdTypeOf: | ||
| 3760 | scope = scope->parent; | 3762 | scope = scope->parent; |
| 3761 | continue; | 3763 | continue; |
| 3762 | } | 3764 | } |
| ... | @@ -3824,17 +3826,18 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr | ... | @@ -3824,17 +3826,18 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr |
| 3824 | LLVMValueRef awaiter_init_val; | 3826 | LLVMValueRef awaiter_init_val; |
| 3825 | LLVMValueRef ret_ptr; | 3827 | LLVMValueRef ret_ptr; |
| 3826 | if (callee_is_async) { | 3828 | if (callee_is_async) { |
| 3827 | if (instruction->is_async) { | 3829 | if (instruction->new_stack == nullptr) { |
| 3828 | if (instruction->new_stack == nullptr) { | 3830 | if (instruction->is_async) { |
| 3829 | awaiter_init_val = zero; | ||
| 3830 | frame_result_loc = result_loc; | 3831 | frame_result_loc = result_loc; |
| 3831 | 3832 | } else { | |
| 3832 | if (ret_has_bits) { | 3833 | frame_result_loc = ir_llvm_value(g, instruction->frame_result_loc); |
| 3833 | // Use the result location which is inside the frame if this is an async call. | 3834 | } |
| 3834 | ret_ptr = LLVMBuildStructGEP(g->builder, frame_result_loc, frame_ret_start + 2, ""); | 3835 | } else { |
| 3835 | } | 3836 | if (instruction->new_stack->value.type->id == ZigTypeIdPointer && |
| 3836 | } else if (cc == CallingConventionAsync) { | 3837 | instruction->new_stack->value.type->data.pointer.child_type->id == ZigTypeIdFnFrame) |
| 3837 | awaiter_init_val = zero; | 3838 | { |
| 3839 | frame_result_loc = ir_llvm_value(g, instruction->new_stack); | ||
| 3840 | } else { | ||
| 3838 | LLVMValueRef frame_slice_ptr = ir_llvm_value(g, instruction->new_stack); | 3841 | LLVMValueRef frame_slice_ptr = ir_llvm_value(g, instruction->new_stack); |
| 3839 | if (ir_want_runtime_safety(g, &instruction->base)) { | 3842 | if (ir_want_runtime_safety(g, &instruction->base)) { |
| 3840 | LLVMValueRef given_len_ptr = LLVMBuildStructGEP(g->builder, frame_slice_ptr, slice_len_index, ""); | 3843 | LLVMValueRef given_len_ptr = LLVMBuildStructGEP(g->builder, frame_slice_ptr, slice_len_index, ""); |
| ... | @@ -3854,15 +3857,37 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr | ... | @@ -3854,15 +3857,37 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr |
| 3854 | } | 3857 | } |
| 3855 | LLVMValueRef frame_ptr_ptr = LLVMBuildStructGEP(g->builder, frame_slice_ptr, slice_ptr_index, ""); | 3858 | LLVMValueRef frame_ptr_ptr = LLVMBuildStructGEP(g->builder, frame_slice_ptr, slice_ptr_index, ""); |
| 3856 | LLVMValueRef frame_ptr = LLVMBuildLoad(g->builder, frame_ptr_ptr, ""); | 3859 | LLVMValueRef frame_ptr = LLVMBuildLoad(g->builder, frame_ptr_ptr, ""); |
| 3857 | frame_result_loc = LLVMBuildBitCast(g->builder, frame_ptr, | 3860 | if (instruction->fn_entry == nullptr) { |
| 3858 | get_llvm_type(g, instruction->base.value.type), ""); | 3861 | ZigType *anyframe_type = get_any_frame_type(g, src_return_type); |
| 3862 | frame_result_loc = LLVMBuildBitCast(g->builder, frame_ptr, get_llvm_type(g, anyframe_type), ""); | ||
| 3863 | } else { | ||
| 3864 | ZigType *ptr_frame_type = get_pointer_to_type(g, | ||
| 3865 | get_fn_frame_type(g, instruction->fn_entry), false); | ||
| 3866 | frame_result_loc = LLVMBuildBitCast(g->builder, frame_ptr, | ||
| 3867 | get_llvm_type(g, ptr_frame_type), ""); | ||
| 3868 | } | ||
| 3869 | } | ||
| 3870 | } | ||
| 3871 | if (instruction->is_async) { | ||
| 3872 | if (instruction->new_stack == nullptr) { | ||
| 3873 | awaiter_init_val = zero; | ||
| 3859 | 3874 | ||
| 3860 | if (ret_has_bits) { | 3875 | if (ret_has_bits) { |
| 3861 | // Use the result location provided to the @asyncCall builtin | 3876 | // Use the result location which is inside the frame if this is an async call. |
| 3862 | ret_ptr = result_loc; | 3877 | ret_ptr = LLVMBuildStructGEP(g->builder, frame_result_loc, frame_ret_start + 2, ""); |
| 3863 | } | 3878 | } |
| 3864 | } else { | 3879 | } else { |
| 3865 | zig_unreachable(); | 3880 | awaiter_init_val = zero; |
| 3881 | |||
| 3882 | if (ret_has_bits) { | ||
| 3883 | if (result_loc != nullptr) { | ||
| 3884 | // Use the result location provided to the @asyncCall builtin | ||
| 3885 | ret_ptr = result_loc; | ||
| 3886 | } else { | ||
| 3887 | // no result location provided to @asyncCall - use the one inside the frame. | ||
| 3888 | ret_ptr = LLVMBuildStructGEP(g->builder, frame_result_loc, frame_ret_start + 2, ""); | ||
| 3889 | } | ||
| 3890 | } | ||
| 3866 | } | 3891 | } |
| 3867 | 3892 | ||
| 3868 | // even if prefix_arg_err_ret_stack is true, let the async function do its own | 3893 | // even if prefix_arg_err_ret_stack is true, let the async function do its own |
| ... | @@ -3870,7 +3895,6 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr | ... | @@ -3870,7 +3895,6 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr |
| 3870 | } else { | 3895 | } else { |
| 3871 | // async function called as a normal function | 3896 | // async function called as a normal function |
| 3872 | 3897 | ||
| 3873 | frame_result_loc = ir_llvm_value(g, instruction->frame_result_loc); | ||
| 3874 | awaiter_init_val = LLVMBuildPtrToInt(g->builder, g->cur_frame_ptr, usize_type_ref, ""); // caller's own frame pointer | 3898 | awaiter_init_val = LLVMBuildPtrToInt(g->builder, g->cur_frame_ptr, usize_type_ref, ""); // caller's own frame pointer |
| 3875 | if (ret_has_bits) { | 3899 | if (ret_has_bits) { |
| 3876 | if (result_loc == nullptr) { | 3900 | if (result_loc == nullptr) { |
| ... | @@ -3986,7 +4010,7 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr | ... | @@ -3986,7 +4010,7 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr |
| 3986 | uint32_t arg_start_i = frame_index_arg(g, fn_type->data.fn.fn_type_id.return_type); | 4010 | uint32_t arg_start_i = frame_index_arg(g, fn_type->data.fn.fn_type_id.return_type); |
| 3987 | 4011 | ||
| 3988 | LLVMValueRef casted_frame; | 4012 | LLVMValueRef casted_frame; |
| 3989 | if (instruction->new_stack != nullptr) { | 4013 | if (instruction->new_stack != nullptr && instruction->fn_entry == nullptr) { |
| 3990 | // We need the frame type to be a pointer to a struct that includes the args | 4014 | // We need the frame type to be a pointer to a struct that includes the args |
| 3991 | size_t field_count = arg_start_i + gen_param_values.length; | 4015 | size_t field_count = arg_start_i + gen_param_values.length; |
| 3992 | LLVMTypeRef *field_types = allocate_nonzero<LLVMTypeRef>(field_count); | 4016 | LLVMTypeRef *field_types = allocate_nonzero<LLVMTypeRef>(field_count); |
| ... | @@ -4012,7 +4036,8 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr | ... | @@ -4012,7 +4036,8 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr |
| 4012 | if (instruction->is_async) { | 4036 | if (instruction->is_async) { |
| 4013 | gen_resume(g, fn_val, frame_result_loc, ResumeIdCall); | 4037 | gen_resume(g, fn_val, frame_result_loc, ResumeIdCall); |
| 4014 | if (instruction->new_stack != nullptr) { | 4038 | if (instruction->new_stack != nullptr) { |
| 4015 | return frame_result_loc; | 4039 | return LLVMBuildBitCast(g->builder, frame_result_loc, |
| 4040 | get_llvm_type(g, instruction->base.value.type), ""); | ||
| 4016 | } | 4041 | } |
| 4017 | return nullptr; | 4042 | return nullptr; |
| 4018 | } else { | 4043 | } else { |
| ... | @@ -4039,7 +4064,7 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr | ... | @@ -4039,7 +4064,7 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr |
| 4039 | } | 4064 | } |
| 4040 | } | 4065 | } |
| 4041 | 4066 | ||
| 4042 | if (instruction->new_stack == nullptr) { | 4067 | if (instruction->new_stack == nullptr || instruction->is_async_call_builtin) { |
| 4043 | result = ZigLLVMBuildCall(g->builder, fn_val, | 4068 | result = ZigLLVMBuildCall(g->builder, fn_val, |
| 4044 | gen_param_values.items, (unsigned)gen_param_values.length, llvm_cc, fn_inline, ""); | 4069 | gen_param_values.items, (unsigned)gen_param_values.length, llvm_cc, fn_inline, ""); |
| 4045 | } else if (instruction->is_async) { | 4070 | } else if (instruction->is_async) { |
| ... | @@ -5942,12 +5967,17 @@ static void ir_render(CodeGen *g, ZigFn *fn_entry) { | ... | @@ -5942,12 +5967,17 @@ static void ir_render(CodeGen *g, ZigFn *fn_entry) { |
| 5942 | 5967 | ||
| 5943 | for (size_t block_i = 0; block_i < executable->basic_block_list.length; block_i += 1) { | 5968 | for (size_t block_i = 0; block_i < executable->basic_block_list.length; block_i += 1) { |
| 5944 | IrBasicBlock *current_block = executable->basic_block_list.at(block_i); | 5969 | IrBasicBlock *current_block = executable->basic_block_list.at(block_i); |
| 5970 | if (get_scope_typeof(current_block->scope) != nullptr) { | ||
| 5971 | LLVMBuildBr(g->builder, current_block->llvm_block); | ||
| 5972 | } | ||
| 5945 | assert(current_block->llvm_block); | 5973 | assert(current_block->llvm_block); |
| 5946 | LLVMPositionBuilderAtEnd(g->builder, current_block->llvm_block); | 5974 | LLVMPositionBuilderAtEnd(g->builder, current_block->llvm_block); |
| 5947 | for (size_t instr_i = 0; instr_i < current_block->instruction_list.length; instr_i += 1) { | 5975 | for (size_t instr_i = 0; instr_i < current_block->instruction_list.length; instr_i += 1) { |
| 5948 | IrInstruction *instruction = current_block->instruction_list.at(instr_i); | 5976 | IrInstruction *instruction = current_block->instruction_list.at(instr_i); |
| 5949 | if (instruction->ref_count == 0 && !ir_has_side_effects(instruction)) | 5977 | if (instruction->ref_count == 0 && !ir_has_side_effects(instruction)) |
| 5950 | continue; | 5978 | continue; |
| 5979 | if (get_scope_typeof(instruction->scope) != nullptr) | ||
| 5980 | continue; | ||
| 5951 | 5981 | ||
| 5952 | if (!g->strip_debug_symbols) { | 5982 | if (!g->strip_debug_symbols) { |
| 5953 | set_debug_location(g, instruction); | 5983 | set_debug_location(g, instruction); |
| ... | @@ -6340,9 +6370,12 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c | ... | @@ -6340,9 +6370,12 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c |
| 6340 | ZigType *type_entry = const_val->type; | 6370 | ZigType *type_entry = const_val->type; |
| 6341 | assert(type_has_bits(type_entry)); | 6371 | assert(type_has_bits(type_entry)); |
| 6342 | 6372 | ||
| 6343 | switch (const_val->special) { | 6373 | check: switch (const_val->special) { |
| 6344 | case ConstValSpecialLazy: | 6374 | case ConstValSpecialLazy: |
| 6345 | zig_unreachable(); | 6375 | if ((err = ir_resolve_lazy(g, nullptr, const_val))) { |
| 6376 | report_errors_and_exit(g); | ||
| 6377 | } | ||
| 6378 | goto check; | ||
| 6346 | case ConstValSpecialRuntime: | 6379 | case ConstValSpecialRuntime: |
| 6347 | zig_unreachable(); | 6380 | zig_unreachable(); |
| 6348 | case ConstValSpecialUndef: | 6381 | case ConstValSpecialUndef: |
src/ir.cpp+239-116| ... | @@ -1382,7 +1382,7 @@ static IrInstruction *ir_build_union_field_ptr(IrBuilder *irb, Scope *scope, Ast | ... | @@ -1382,7 +1382,7 @@ static IrInstruction *ir_build_union_field_ptr(IrBuilder *irb, Scope *scope, Ast |
| 1382 | 1382 | ||
| 1383 | static IrInstruction *ir_build_call_src(IrBuilder *irb, Scope *scope, AstNode *source_node, | 1383 | static IrInstruction *ir_build_call_src(IrBuilder *irb, Scope *scope, AstNode *source_node, |
| 1384 | ZigFn *fn_entry, IrInstruction *fn_ref, size_t arg_count, IrInstruction **args, | 1384 | ZigFn *fn_entry, IrInstruction *fn_ref, size_t arg_count, IrInstruction **args, |
| 1385 | bool is_comptime, FnInline fn_inline, bool is_async, | 1385 | bool is_comptime, FnInline fn_inline, bool is_async, bool is_async_call_builtin, |
| 1386 | IrInstruction *new_stack, ResultLoc *result_loc) | 1386 | IrInstruction *new_stack, ResultLoc *result_loc) |
| 1387 | { | 1387 | { |
| 1388 | IrInstructionCallSrc *call_instruction = ir_build_instruction<IrInstructionCallSrc>(irb, scope, source_node); | 1388 | IrInstructionCallSrc *call_instruction = ir_build_instruction<IrInstructionCallSrc>(irb, scope, source_node); |
| ... | @@ -1393,6 +1393,7 @@ static IrInstruction *ir_build_call_src(IrBuilder *irb, Scope *scope, AstNode *s | ... | @@ -1393,6 +1393,7 @@ static IrInstruction *ir_build_call_src(IrBuilder *irb, Scope *scope, AstNode *s |
| 1393 | call_instruction->args = args; | 1393 | call_instruction->args = args; |
| 1394 | call_instruction->arg_count = arg_count; | 1394 | call_instruction->arg_count = arg_count; |
| 1395 | call_instruction->is_async = is_async; | 1395 | call_instruction->is_async = is_async; |
| 1396 | call_instruction->is_async_call_builtin = is_async_call_builtin; | ||
| 1396 | call_instruction->new_stack = new_stack; | 1397 | call_instruction->new_stack = new_stack; |
| 1397 | call_instruction->result_loc = result_loc; | 1398 | call_instruction->result_loc = result_loc; |
| 1398 | 1399 | ||
| ... | @@ -1410,7 +1411,7 @@ static IrInstruction *ir_build_call_src(IrBuilder *irb, Scope *scope, AstNode *s | ... | @@ -1410,7 +1411,7 @@ static IrInstruction *ir_build_call_src(IrBuilder *irb, Scope *scope, AstNode *s |
| 1410 | 1411 | ||
| 1411 | static IrInstructionCallGen *ir_build_call_gen(IrAnalyze *ira, IrInstruction *source_instruction, | 1412 | static IrInstructionCallGen *ir_build_call_gen(IrAnalyze *ira, IrInstruction *source_instruction, |
| 1412 | ZigFn *fn_entry, IrInstruction *fn_ref, size_t arg_count, IrInstruction **args, | 1413 | ZigFn *fn_entry, IrInstruction *fn_ref, size_t arg_count, IrInstruction **args, |
| 1413 | FnInline fn_inline, bool is_async, IrInstruction *new_stack, | 1414 | FnInline fn_inline, bool is_async, IrInstruction *new_stack, bool is_async_call_builtin, |
| 1414 | IrInstruction *result_loc, ZigType *return_type) | 1415 | IrInstruction *result_loc, ZigType *return_type) |
| 1415 | { | 1416 | { |
| 1416 | IrInstructionCallGen *call_instruction = ir_build_instruction<IrInstructionCallGen>(&ira->new_irb, | 1417 | IrInstructionCallGen *call_instruction = ir_build_instruction<IrInstructionCallGen>(&ira->new_irb, |
| ... | @@ -1422,6 +1423,7 @@ static IrInstructionCallGen *ir_build_call_gen(IrAnalyze *ira, IrInstruction *so | ... | @@ -1422,6 +1423,7 @@ static IrInstructionCallGen *ir_build_call_gen(IrAnalyze *ira, IrInstruction *so |
| 1422 | call_instruction->args = args; | 1423 | call_instruction->args = args; |
| 1423 | call_instruction->arg_count = arg_count; | 1424 | call_instruction->arg_count = arg_count; |
| 1424 | call_instruction->is_async = is_async; | 1425 | call_instruction->is_async = is_async; |
| 1426 | call_instruction->is_async_call_builtin = is_async_call_builtin; | ||
| 1425 | call_instruction->new_stack = new_stack; | 1427 | call_instruction->new_stack = new_stack; |
| 1426 | call_instruction->result_loc = result_loc; | 1428 | call_instruction->result_loc = result_loc; |
| 1427 | 1429 | ||
| ... | @@ -3344,6 +3346,7 @@ static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_sco | ... | @@ -3344,6 +3346,7 @@ static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_sco |
| 3344 | case ScopeIdSuspend: | 3346 | case ScopeIdSuspend: |
| 3345 | case ScopeIdCompTime: | 3347 | case ScopeIdCompTime: |
| 3346 | case ScopeIdRuntime: | 3348 | case ScopeIdRuntime: |
| 3349 | case ScopeIdTypeOf: | ||
| 3347 | scope = scope->parent; | 3350 | scope = scope->parent; |
| 3348 | continue; | 3351 | continue; |
| 3349 | case ScopeIdDeferExpr: | 3352 | case ScopeIdDeferExpr: |
| ... | @@ -3399,6 +3402,7 @@ static bool ir_gen_defers_for_block(IrBuilder *irb, Scope *inner_scope, Scope *o | ... | @@ -3399,6 +3402,7 @@ static bool ir_gen_defers_for_block(IrBuilder *irb, Scope *inner_scope, Scope *o |
| 3399 | case ScopeIdSuspend: | 3402 | case ScopeIdSuspend: |
| 3400 | case ScopeIdCompTime: | 3403 | case ScopeIdCompTime: |
| 3401 | case ScopeIdRuntime: | 3404 | case ScopeIdRuntime: |
| 3405 | case ScopeIdTypeOf: | ||
| 3402 | scope = scope->parent; | 3406 | scope = scope->parent; |
| 3403 | continue; | 3407 | continue; |
| 3404 | case ScopeIdDeferExpr: | 3408 | case ScopeIdDeferExpr: |
| ... | @@ -4349,6 +4353,54 @@ static IrInstruction *ir_gen_this(IrBuilder *irb, Scope *orig_scope, AstNode *no | ... | @@ -4349,6 +4353,54 @@ static IrInstruction *ir_gen_this(IrBuilder *irb, Scope *orig_scope, AstNode *no |
| 4349 | zig_unreachable(); | 4353 | zig_unreachable(); |
| 4350 | } | 4354 | } |
| 4351 | 4355 | ||
| 4356 | static IrInstruction *ir_gen_async_call(IrBuilder *irb, Scope *scope, AstNode *await_node, AstNode *call_node, | ||
| 4357 | LVal lval, ResultLoc *result_loc) | ||
| 4358 | { | ||
| 4359 | size_t arg_offset = 3; | ||
| 4360 | if (call_node->data.fn_call_expr.params.length < arg_offset) { | ||
| 4361 | add_node_error(irb->codegen, call_node, | ||
| 4362 | buf_sprintf("expected at least %" ZIG_PRI_usize " arguments, found %" ZIG_PRI_usize, | ||
| 4363 | arg_offset, call_node->data.fn_call_expr.params.length)); | ||
| 4364 | return irb->codegen->invalid_instruction; | ||
| 4365 | } | ||
| 4366 | |||
| 4367 | AstNode *bytes_node = call_node->data.fn_call_expr.params.at(0); | ||
| 4368 | IrInstruction *bytes = ir_gen_node(irb, bytes_node, scope); | ||
| 4369 | if (bytes == irb->codegen->invalid_instruction) | ||
| 4370 | return bytes; | ||
| 4371 | |||
| 4372 | AstNode *ret_ptr_node = call_node->data.fn_call_expr.params.at(1); | ||
| 4373 | IrInstruction *ret_ptr = ir_gen_node(irb, ret_ptr_node, scope); | ||
| 4374 | if (ret_ptr == irb->codegen->invalid_instruction) | ||
| 4375 | return ret_ptr; | ||
| 4376 | |||
| 4377 | AstNode *fn_ref_node = call_node->data.fn_call_expr.params.at(2); | ||
| 4378 | IrInstruction *fn_ref = ir_gen_node(irb, fn_ref_node, scope); | ||
| 4379 | if (fn_ref == irb->codegen->invalid_instruction) | ||
| 4380 | return fn_ref; | ||
| 4381 | |||
| 4382 | size_t arg_count = call_node->data.fn_call_expr.params.length - arg_offset; | ||
| 4383 | |||
| 4384 | // last "arg" is return pointer | ||
| 4385 | IrInstruction **args = allocate<IrInstruction*>(arg_count + 1); | ||
| 4386 | |||
| 4387 | for (size_t i = 0; i < arg_count; i += 1) { | ||
| 4388 | AstNode *arg_node = call_node->data.fn_call_expr.params.at(i + arg_offset); | ||
| 4389 | IrInstruction *arg = ir_gen_node(irb, arg_node, scope); | ||
| 4390 | if (arg == irb->codegen->invalid_instruction) | ||
| 4391 | return arg; | ||
| 4392 | args[i] = arg; | ||
| 4393 | } | ||
| 4394 | |||
| 4395 | args[arg_count] = ret_ptr; | ||
| 4396 | |||
| 4397 | bool is_async = await_node == nullptr; | ||
| 4398 | bool is_async_call_builtin = true; | ||
| 4399 | IrInstruction *call = ir_build_call_src(irb, scope, call_node, nullptr, fn_ref, arg_count, args, false, | ||
| 4400 | FnInlineAuto, is_async, is_async_call_builtin, bytes, result_loc); | ||
| 4401 | return ir_lval_wrap(irb, scope, call, lval, result_loc); | ||
| 4402 | } | ||
| 4403 | |||
| 4352 | static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval, | 4404 | static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval, |
| 4353 | ResultLoc *result_loc) | 4405 | ResultLoc *result_loc) |
| 4354 | { | 4406 | { |
| ... | @@ -4358,7 +4410,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo | ... | @@ -4358,7 +4410,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo |
| 4358 | Buf *name = fn_ref_expr->data.symbol_expr.symbol; | 4410 | Buf *name = fn_ref_expr->data.symbol_expr.symbol; |
| 4359 | auto entry = irb->codegen->builtin_fn_table.maybe_get(name); | 4411 | auto entry = irb->codegen->builtin_fn_table.maybe_get(name); |
| 4360 | 4412 | ||
| 4361 | if (!entry) { // new built in not found | 4413 | if (!entry) { |
| 4362 | add_node_error(irb->codegen, node, | 4414 | add_node_error(irb->codegen, node, |
| 4363 | buf_sprintf("invalid builtin function: '%s'", buf_ptr(name))); | 4415 | buf_sprintf("invalid builtin function: '%s'", buf_ptr(name))); |
| 4364 | return irb->codegen->invalid_instruction; | 4416 | return irb->codegen->invalid_instruction; |
| ... | @@ -4379,8 +4431,10 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo | ... | @@ -4379,8 +4431,10 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo |
| 4379 | zig_unreachable(); | 4431 | zig_unreachable(); |
| 4380 | case BuiltinFnIdTypeof: | 4432 | case BuiltinFnIdTypeof: |
| 4381 | { | 4433 | { |
| 4434 | Scope *sub_scope = create_typeof_scope(irb->codegen, node, scope); | ||
| 4435 | |||
| 4382 | AstNode *arg_node = node->data.fn_call_expr.params.at(0); | 4436 | AstNode *arg_node = node->data.fn_call_expr.params.at(0); |
| 4383 | IrInstruction *arg = ir_gen_node(irb, arg_node, scope); | 4437 | IrInstruction *arg = ir_gen_node(irb, arg_node, sub_scope); |
| 4384 | if (arg == irb->codegen->invalid_instruction) | 4438 | if (arg == irb->codegen->invalid_instruction) |
| 4385 | return arg; | 4439 | return arg; |
| 4386 | 4440 | ||
| ... | @@ -5220,7 +5274,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo | ... | @@ -5220,7 +5274,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo |
| 5220 | FnInline fn_inline = (builtin_fn->id == BuiltinFnIdInlineCall) ? FnInlineAlways : FnInlineNever; | 5274 | FnInline fn_inline = (builtin_fn->id == BuiltinFnIdInlineCall) ? FnInlineAlways : FnInlineNever; |
| 5221 | 5275 | ||
| 5222 | IrInstruction *call = ir_build_call_src(irb, scope, node, nullptr, fn_ref, arg_count, args, false, | 5276 | IrInstruction *call = ir_build_call_src(irb, scope, node, nullptr, fn_ref, arg_count, args, false, |
| 5223 | fn_inline, false, nullptr, result_loc); | 5277 | fn_inline, false, false, nullptr, result_loc); |
| 5224 | return ir_lval_wrap(irb, scope, call, lval, result_loc); | 5278 | return ir_lval_wrap(irb, scope, call, lval, result_loc); |
| 5225 | } | 5279 | } |
| 5226 | case BuiltinFnIdNewStackCall: | 5280 | case BuiltinFnIdNewStackCall: |
| ... | @@ -5253,53 +5307,11 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo | ... | @@ -5253,53 +5307,11 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo |
| 5253 | } | 5307 | } |
| 5254 | 5308 | ||
| 5255 | IrInstruction *call = ir_build_call_src(irb, scope, node, nullptr, fn_ref, arg_count, args, false, | 5309 | IrInstruction *call = ir_build_call_src(irb, scope, node, nullptr, fn_ref, arg_count, args, false, |
| 5256 | FnInlineAuto, false, new_stack, result_loc); | 5310 | FnInlineAuto, false, false, new_stack, result_loc); |
| 5257 | return ir_lval_wrap(irb, scope, call, lval, result_loc); | 5311 | return ir_lval_wrap(irb, scope, call, lval, result_loc); |
| 5258 | } | 5312 | } |
| 5259 | case BuiltinFnIdAsyncCall: | 5313 | case BuiltinFnIdAsyncCall: |
| 5260 | { | 5314 | return ir_gen_async_call(irb, scope, nullptr, node, lval, result_loc); |
| 5261 | size_t arg_offset = 3; | ||
| 5262 | if (node->data.fn_call_expr.params.length < arg_offset) { | ||
| 5263 | add_node_error(irb->codegen, node, | ||
| 5264 | buf_sprintf("expected at least %" ZIG_PRI_usize " arguments, found %" ZIG_PRI_usize, | ||
| 5265 | arg_offset, node->data.fn_call_expr.params.length)); | ||
| 5266 | return irb->codegen->invalid_instruction; | ||
| 5267 | } | ||
| 5268 | |||
| 5269 | AstNode *bytes_node = node->data.fn_call_expr.params.at(0); | ||
| 5270 | IrInstruction *bytes = ir_gen_node(irb, bytes_node, scope); | ||
| 5271 | if (bytes == irb->codegen->invalid_instruction) | ||
| 5272 | return bytes; | ||
| 5273 | |||
| 5274 | AstNode *ret_ptr_node = node->data.fn_call_expr.params.at(1); | ||
| 5275 | IrInstruction *ret_ptr = ir_gen_node(irb, ret_ptr_node, scope); | ||
| 5276 | if (ret_ptr == irb->codegen->invalid_instruction) | ||
| 5277 | return ret_ptr; | ||
| 5278 | |||
| 5279 | AstNode *fn_ref_node = node->data.fn_call_expr.params.at(2); | ||
| 5280 | IrInstruction *fn_ref = ir_gen_node(irb, fn_ref_node, scope); | ||
| 5281 | if (fn_ref == irb->codegen->invalid_instruction) | ||
| 5282 | return fn_ref; | ||
| 5283 | |||
| 5284 | size_t arg_count = node->data.fn_call_expr.params.length - arg_offset; | ||
| 5285 | |||
| 5286 | // last "arg" is return pointer | ||
| 5287 | IrInstruction **args = allocate<IrInstruction*>(arg_count + 1); | ||
| 5288 | |||
| 5289 | for (size_t i = 0; i < arg_count; i += 1) { | ||
| 5290 | AstNode *arg_node = node->data.fn_call_expr.params.at(i + arg_offset); | ||
| 5291 | IrInstruction *arg = ir_gen_node(irb, arg_node, scope); | ||
| 5292 | if (arg == irb->codegen->invalid_instruction) | ||
| 5293 | return arg; | ||
| 5294 | args[i] = arg; | ||
| 5295 | } | ||
| 5296 | |||
| 5297 | args[arg_count] = ret_ptr; | ||
| 5298 | |||
| 5299 | IrInstruction *call = ir_build_call_src(irb, scope, node, nullptr, fn_ref, arg_count, args, false, | ||
| 5300 | FnInlineAuto, true, bytes, result_loc); | ||
| 5301 | return ir_lval_wrap(irb, scope, call, lval, result_loc); | ||
| 5302 | } | ||
| 5303 | case BuiltinFnIdTypeId: | 5315 | case BuiltinFnIdTypeId: |
| 5304 | { | 5316 | { |
| 5305 | AstNode *arg0_node = node->data.fn_call_expr.params.at(0); | 5317 | AstNode *arg0_node = node->data.fn_call_expr.params.at(0); |
| ... | @@ -5603,7 +5615,7 @@ static IrInstruction *ir_gen_fn_call(IrBuilder *irb, Scope *scope, AstNode *node | ... | @@ -5603,7 +5615,7 @@ static IrInstruction *ir_gen_fn_call(IrBuilder *irb, Scope *scope, AstNode *node |
| 5603 | 5615 | ||
| 5604 | bool is_async = node->data.fn_call_expr.is_async; | 5616 | bool is_async = node->data.fn_call_expr.is_async; |
| 5605 | IrInstruction *fn_call = ir_build_call_src(irb, scope, node, nullptr, fn_ref, arg_count, args, false, | 5617 | IrInstruction *fn_call = ir_build_call_src(irb, scope, node, nullptr, fn_ref, arg_count, args, false, |
| 5606 | FnInlineAuto, is_async, nullptr, result_loc); | 5618 | FnInlineAuto, is_async, false, nullptr, result_loc); |
| 5607 | return ir_lval_wrap(irb, scope, fn_call, lval, result_loc); | 5619 | return ir_lval_wrap(irb, scope, fn_call, lval, result_loc); |
| 5608 | } | 5620 | } |
| 5609 | 5621 | ||
| ... | @@ -7896,6 +7908,19 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *scope, AstNode *n | ... | @@ -7896,6 +7908,19 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *scope, AstNode *n |
| 7896 | { | 7908 | { |
| 7897 | assert(node->type == NodeTypeAwaitExpr); | 7909 | assert(node->type == NodeTypeAwaitExpr); |
| 7898 | 7910 | ||
| 7911 | AstNode *expr_node = node->data.await_expr.expr; | ||
| 7912 | if (expr_node->type == NodeTypeFnCallExpr && expr_node->data.fn_call_expr.is_builtin) { | ||
| 7913 | AstNode *fn_ref_expr = expr_node->data.fn_call_expr.fn_ref_expr; | ||
| 7914 | Buf *name = fn_ref_expr->data.symbol_expr.symbol; | ||
| 7915 | auto entry = irb->codegen->builtin_fn_table.maybe_get(name); | ||
| 7916 | if (entry != nullptr) { | ||
| 7917 | BuiltinFnEntry *builtin_fn = entry->value; | ||
| 7918 | if (builtin_fn->id == BuiltinFnIdAsyncCall) { | ||
| 7919 | return ir_gen_async_call(irb, scope, node, expr_node, lval, result_loc); | ||
| 7920 | } | ||
| 7921 | } | ||
| 7922 | } | ||
| 7923 | |||
| 7899 | ZigFn *fn_entry = exec_fn_entry(irb->exec); | 7924 | ZigFn *fn_entry = exec_fn_entry(irb->exec); |
| 7900 | if (!fn_entry) { | 7925 | if (!fn_entry) { |
| 7901 | add_node_error(irb->codegen, node, buf_sprintf("await outside function definition")); | 7926 | add_node_error(irb->codegen, node, buf_sprintf("await outside function definition")); |
| ... | @@ -7911,7 +7936,7 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *scope, AstNode *n | ... | @@ -7911,7 +7936,7 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *scope, AstNode *n |
| 7911 | return irb->codegen->invalid_instruction; | 7936 | return irb->codegen->invalid_instruction; |
| 7912 | } | 7937 | } |
| 7913 | 7938 | ||
| 7914 | IrInstruction *target_inst = ir_gen_node_extra(irb, node->data.await_expr.expr, scope, LValPtr, nullptr); | 7939 | IrInstruction *target_inst = ir_gen_node_extra(irb, expr_node, scope, LValPtr, nullptr); |
| 7915 | if (target_inst == irb->codegen->invalid_instruction) | 7940 | if (target_inst == irb->codegen->invalid_instruction) |
| 7916 | return irb->codegen->invalid_instruction; | 7941 | return irb->codegen->invalid_instruction; |
| 7917 | 7942 | ||
| ... | @@ -8269,6 +8294,10 @@ static ConstExprValue *ir_exec_const_result(CodeGen *codegen, IrExecutable *exec | ... | @@ -8269,6 +8294,10 @@ static ConstExprValue *ir_exec_const_result(CodeGen *codegen, IrExecutable *exec |
| 8269 | break; | 8294 | break; |
| 8270 | } | 8295 | } |
| 8271 | } | 8296 | } |
| 8297 | if (get_scope_typeof(instruction->scope) != nullptr) { | ||
| 8298 | // doesn't count, it's inside a @typeOf() | ||
| 8299 | continue; | ||
| 8300 | } | ||
| 8272 | exec_add_error_node(codegen, exec, instruction->source_node, | 8301 | exec_add_error_node(codegen, exec, instruction->source_node, |
| 8273 | buf_sprintf("unable to evaluate constant expression")); | 8302 | buf_sprintf("unable to evaluate constant expression")); |
| 8274 | return &codegen->invalid_instruction->value; | 8303 | return &codegen->invalid_instruction->value; |
| ... | @@ -9012,7 +9041,42 @@ static bool ir_num_lit_fits_in_other_type(IrAnalyze *ira, IrInstruction *instruc | ... | @@ -9012,7 +9041,42 @@ static bool ir_num_lit_fits_in_other_type(IrAnalyze *ira, IrInstruction *instruc |
| 9012 | return false; | 9041 | return false; |
| 9013 | } | 9042 | } |
| 9014 | 9043 | ||
| 9015 | ConstExprValue *const_val = ir_resolve_const(ira, instruction, UndefBad); | 9044 | ConstExprValue *const_val = ir_resolve_const(ira, instruction, LazyOkNoUndef); |
| 9045 | if (const_val == nullptr) | ||
| 9046 | return false; | ||
| 9047 | |||
| 9048 | if (const_val->special == ConstValSpecialLazy) { | ||
| 9049 | switch (const_val->data.x_lazy->id) { | ||
| 9050 | case LazyValueIdAlignOf: { | ||
| 9051 | // This is guaranteed to fit into a u29 | ||
| 9052 | if (other_type->id == ZigTypeIdComptimeInt) | ||
| 9053 | return true; | ||
| 9054 | size_t align_bits = get_align_amt_type(ira->codegen)->data.integral.bit_count; | ||
| 9055 | if (other_type->id == ZigTypeIdInt && !other_type->data.integral.is_signed && | ||
| 9056 | other_type->data.integral.bit_count >= align_bits) | ||
| 9057 | { | ||
| 9058 | return true; | ||
| 9059 | } | ||
| 9060 | break; | ||
| 9061 | } | ||
| 9062 | case LazyValueIdSizeOf: { | ||
| 9063 | // This is guaranteed to fit into a usize | ||
| 9064 | if (other_type->id == ZigTypeIdComptimeInt) | ||
| 9065 | return true; | ||
| 9066 | size_t usize_bits = ira->codegen->builtin_types.entry_usize->data.integral.bit_count; | ||
| 9067 | if (other_type->id == ZigTypeIdInt && !other_type->data.integral.is_signed && | ||
| 9068 | other_type->data.integral.bit_count >= usize_bits) | ||
| 9069 | { | ||
| 9070 | return true; | ||
| 9071 | } | ||
| 9072 | break; | ||
| 9073 | } | ||
| 9074 | default: | ||
| 9075 | break; | ||
| 9076 | } | ||
| 9077 | } | ||
| 9078 | |||
| 9079 | const_val = ir_resolve_const(ira, instruction, UndefBad); | ||
| 9016 | if (const_val == nullptr) | 9080 | if (const_val == nullptr) |
| 9017 | return false; | 9081 | return false; |
| 9018 | 9082 | ||
| ... | @@ -10262,7 +10326,7 @@ static void copy_const_val(ConstExprValue *dest, ConstExprValue *src, bool same_ | ... | @@ -10262,7 +10326,7 @@ static void copy_const_val(ConstExprValue *dest, ConstExprValue *src, bool same_ |
| 10262 | memcpy(dest, src, sizeof(ConstExprValue)); | 10326 | memcpy(dest, src, sizeof(ConstExprValue)); |
| 10263 | if (!same_global_refs) { | 10327 | if (!same_global_refs) { |
| 10264 | dest->global_refs = global_refs; | 10328 | dest->global_refs = global_refs; |
| 10265 | if (src->special == ConstValSpecialUndef) | 10329 | if (src->special != ConstValSpecialStatic) |
| 10266 | return; | 10330 | return; |
| 10267 | if (dest->type->id == ZigTypeIdStruct) { | 10331 | if (dest->type->id == ZigTypeIdStruct) { |
| 10268 | dest->data.x_struct.fields = create_const_vals(dest->type->data.structure.src_field_count); | 10332 | dest->data.x_struct.fields = create_const_vals(dest->type->data.structure.src_field_count); |
| ... | @@ -10803,7 +10867,7 @@ ConstExprValue *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *nod | ... | @@ -10803,7 +10867,7 @@ ConstExprValue *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *nod |
| 10803 | fprintf(stderr, "\nSource: "); | 10867 | fprintf(stderr, "\nSource: "); |
| 10804 | ast_render(stderr, node, 4); | 10868 | ast_render(stderr, node, 4); |
| 10805 | fprintf(stderr, "\n{ // (IR)\n"); | 10869 | fprintf(stderr, "\n{ // (IR)\n"); |
| 10806 | ir_print(codegen, stderr, ir_executable, 2); | 10870 | ir_print(codegen, stderr, ir_executable, 2, 1); |
| 10807 | fprintf(stderr, "}\n"); | 10871 | fprintf(stderr, "}\n"); |
| 10808 | } | 10872 | } |
| 10809 | IrExecutable *analyzed_executable = allocate<IrExecutable>(1); | 10873 | IrExecutable *analyzed_executable = allocate<IrExecutable>(1); |
| ... | @@ -10824,7 +10888,7 @@ ConstExprValue *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *nod | ... | @@ -10824,7 +10888,7 @@ ConstExprValue *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *nod |
| 10824 | 10888 | ||
| 10825 | if (codegen->verbose_ir) { | 10889 | if (codegen->verbose_ir) { |
| 10826 | fprintf(stderr, "{ // (analyzed)\n"); | 10890 | fprintf(stderr, "{ // (analyzed)\n"); |
| 10827 | ir_print(codegen, stderr, analyzed_executable, 2); | 10891 | ir_print(codegen, stderr, analyzed_executable, 2, 2); |
| 10828 | fprintf(stderr, "}\n"); | 10892 | fprintf(stderr, "}\n"); |
| 10829 | } | 10893 | } |
| 10830 | 10894 | ||
| ... | @@ -11213,7 +11277,7 @@ static IrInstruction *ir_get_ref(IrAnalyze *ira, IrInstruction *source_instructi | ... | @@ -11213,7 +11277,7 @@ static IrInstruction *ir_get_ref(IrAnalyze *ira, IrInstruction *source_instructi |
| 11213 | return ira->codegen->invalid_instruction; | 11277 | return ira->codegen->invalid_instruction; |
| 11214 | 11278 | ||
| 11215 | if (instr_is_comptime(value)) { | 11279 | if (instr_is_comptime(value)) { |
| 11216 | ConstExprValue *val = ir_resolve_const(ira, value, UndefOk); | 11280 | ConstExprValue *val = ir_resolve_const(ira, value, LazyOk); |
| 11217 | if (!val) | 11281 | if (!val) |
| 11218 | return ira->codegen->invalid_instruction; | 11282 | return ira->codegen->invalid_instruction; |
| 11219 | return ir_get_const_ptr(ira, source_instruction, val, value->value.type, | 11283 | return ir_get_const_ptr(ira, source_instruction, val, value->value.type, |
| ... | @@ -12125,7 +12189,8 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst | ... | @@ -12125,7 +12189,8 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst |
| 12125 | if (wanted_type->id == ZigTypeIdComptimeInt || wanted_type->id == ZigTypeIdInt) { | 12189 | if (wanted_type->id == ZigTypeIdComptimeInt || wanted_type->id == ZigTypeIdInt) { |
| 12126 | IrInstruction *result = ir_const(ira, source_instr, wanted_type); | 12190 | IrInstruction *result = ir_const(ira, source_instr, wanted_type); |
| 12127 | if (actual_type->id == ZigTypeIdComptimeInt || actual_type->id == ZigTypeIdInt) { | 12191 | if (actual_type->id == ZigTypeIdComptimeInt || actual_type->id == ZigTypeIdInt) { |
| 12128 | bigint_init_bigint(&result->value.data.x_bigint, &value->value.data.x_bigint); | 12192 | copy_const_val(&result->value, &value->value, false); |
| 12193 | result->value.type = wanted_type; | ||
| 12129 | } else { | 12194 | } else { |
| 12130 | float_init_bigint(&result->value.data.x_bigint, &value->value); | 12195 | float_init_bigint(&result->value.data.x_bigint, &value->value); |
| 12131 | } | 12196 | } |
| ... | @@ -14869,7 +14934,7 @@ static IrInstruction *ir_resolve_result_raw(IrAnalyze *ira, IrInstruction *suspe | ... | @@ -14869,7 +14934,7 @@ static IrInstruction *ir_resolve_result_raw(IrAnalyze *ira, IrInstruction *suspe |
| 14869 | PtrLenSingle, 0, 0, 0, false); | 14934 | PtrLenSingle, 0, 0, 0, false); |
| 14870 | set_up_result_loc_for_inferred_comptime(&alloca_gen->base); | 14935 | set_up_result_loc_for_inferred_comptime(&alloca_gen->base); |
| 14871 | ZigFn *fn_entry = exec_fn_entry(ira->new_irb.exec); | 14936 | ZigFn *fn_entry = exec_fn_entry(ira->new_irb.exec); |
| 14872 | if (fn_entry != nullptr) { | 14937 | if (fn_entry != nullptr && get_scope_typeof(suspend_source_instr->scope) == nullptr) { |
| 14873 | fn_entry->alloca_gen_list.append(alloca_gen); | 14938 | fn_entry->alloca_gen_list.append(alloca_gen); |
| 14874 | } | 14939 | } |
| 14875 | result_loc->written = true; | 14940 | result_loc->written = true; |
| ... | @@ -15200,44 +15265,61 @@ static IrInstruction *ir_analyze_instruction_reset_result(IrAnalyze *ira, IrInst | ... | @@ -15200,44 +15265,61 @@ static IrInstruction *ir_analyze_instruction_reset_result(IrAnalyze *ira, IrInst |
| 15200 | return ir_const_void(ira, &instruction->base); | 15265 | return ir_const_void(ira, &instruction->base); |
| 15201 | } | 15266 | } |
| 15202 | 15267 | ||
| 15268 | static IrInstruction *get_async_call_result_loc(IrAnalyze *ira, IrInstructionCallSrc *call_instruction, | ||
| 15269 | ZigType *fn_ret_type) | ||
| 15270 | { | ||
| 15271 | ir_assert(call_instruction->is_async_call_builtin, &call_instruction->base); | ||
| 15272 | IrInstruction *ret_ptr_uncasted = call_instruction->args[call_instruction->arg_count]->child; | ||
| 15273 | if (type_is_invalid(ret_ptr_uncasted->value.type)) | ||
| 15274 | return ira->codegen->invalid_instruction; | ||
| 15275 | if (ret_ptr_uncasted->value.type->id == ZigTypeIdVoid) { | ||
| 15276 | // Result location will be inside the async frame. | ||
| 15277 | return nullptr; | ||
| 15278 | } | ||
| 15279 | return ir_implicit_cast(ira, ret_ptr_uncasted, get_pointer_to_type(ira->codegen, fn_ret_type, false)); | ||
| 15280 | } | ||
| 15281 | |||
| 15203 | static IrInstruction *ir_analyze_async_call(IrAnalyze *ira, IrInstructionCallSrc *call_instruction, ZigFn *fn_entry, | 15282 | static IrInstruction *ir_analyze_async_call(IrAnalyze *ira, IrInstructionCallSrc *call_instruction, ZigFn *fn_entry, |
| 15204 | ZigType *fn_type, IrInstruction *fn_ref, IrInstruction **casted_args, size_t arg_count, | 15283 | ZigType *fn_type, IrInstruction *fn_ref, IrInstruction **casted_args, size_t arg_count, |
| 15205 | IrInstruction *casted_new_stack) | 15284 | IrInstruction *casted_new_stack) |
| 15206 | { | 15285 | { |
| 15207 | if (casted_new_stack != nullptr) { | 15286 | if (fn_entry == nullptr) { |
| 15208 | // this is an @asyncCall | ||
| 15209 | |||
| 15210 | if (fn_type->data.fn.fn_type_id.cc != CallingConventionAsync) { | 15287 | if (fn_type->data.fn.fn_type_id.cc != CallingConventionAsync) { |
| 15211 | ir_add_error(ira, fn_ref, | 15288 | ir_add_error(ira, fn_ref, |
| 15212 | buf_sprintf("expected async function, found '%s'", buf_ptr(&fn_type->name))); | 15289 | buf_sprintf("expected async function, found '%s'", buf_ptr(&fn_type->name))); |
| 15213 | return ira->codegen->invalid_instruction; | 15290 | return ira->codegen->invalid_instruction; |
| 15214 | } | 15291 | } |
| 15215 | 15292 | if (casted_new_stack == nullptr) { | |
| 15216 | IrInstruction *ret_ptr = call_instruction->args[call_instruction->arg_count]->child; | 15293 | ir_add_error(ira, fn_ref, buf_sprintf("function is not comptime-known; @asyncCall required")); |
| 15217 | if (type_is_invalid(ret_ptr->value.type)) | 15294 | return ira->codegen->invalid_instruction; |
| 15295 | } | ||
| 15296 | } | ||
| 15297 | if (casted_new_stack != nullptr) { | ||
| 15298 | ZigType *fn_ret_type = fn_type->data.fn.fn_type_id.return_type; | ||
| 15299 | IrInstruction *ret_ptr = get_async_call_result_loc(ira, call_instruction, fn_ret_type); | ||
| 15300 | if (ret_ptr != nullptr && type_is_invalid(ret_ptr->value.type)) | ||
| 15218 | return ira->codegen->invalid_instruction; | 15301 | return ira->codegen->invalid_instruction; |
| 15219 | 15302 | ||
| 15220 | ZigType *anyframe_type = get_any_frame_type(ira->codegen, fn_type->data.fn.fn_type_id.return_type); | 15303 | ZigType *anyframe_type = get_any_frame_type(ira->codegen, fn_ret_type); |
| 15221 | 15304 | ||
| 15222 | IrInstructionCallGen *call_gen = ir_build_call_gen(ira, &call_instruction->base, nullptr, fn_ref, | 15305 | IrInstructionCallGen *call_gen = ir_build_call_gen(ira, &call_instruction->base, fn_entry, fn_ref, |
| 15223 | arg_count, casted_args, FnInlineAuto, true, casted_new_stack, ret_ptr, anyframe_type); | 15306 | arg_count, casted_args, FnInlineAuto, true, casted_new_stack, |
| 15307 | call_instruction->is_async_call_builtin, ret_ptr, anyframe_type); | ||
| 15224 | return &call_gen->base; | 15308 | return &call_gen->base; |
| 15225 | } else if (fn_entry == nullptr) { | 15309 | } else { |
| 15226 | ir_add_error(ira, fn_ref, buf_sprintf("function is not comptime-known; @asyncCall required")); | 15310 | ZigType *frame_type = get_fn_frame_type(ira->codegen, fn_entry); |
| 15227 | return ira->codegen->invalid_instruction; | 15311 | IrInstruction *result_loc = ir_resolve_result(ira, &call_instruction->base, call_instruction->result_loc, |
| 15228 | } | 15312 | frame_type, nullptr, true, true, false); |
| 15229 | 15313 | if (type_is_invalid(result_loc->value.type) || instr_is_unreachable(result_loc)) { | |
| 15230 | ZigType *frame_type = get_fn_frame_type(ira->codegen, fn_entry); | 15314 | return result_loc; |
| 15231 | IrInstruction *result_loc = ir_resolve_result(ira, &call_instruction->base, call_instruction->result_loc, | 15315 | } |
| 15232 | frame_type, nullptr, true, true, false); | 15316 | result_loc = ir_implicit_cast(ira, result_loc, get_pointer_to_type(ira->codegen, frame_type, false)); |
| 15233 | if (type_is_invalid(result_loc->value.type) || instr_is_unreachable(result_loc)) { | 15317 | if (type_is_invalid(result_loc->value.type)) |
| 15234 | return result_loc; | 15318 | return ira->codegen->invalid_instruction; |
| 15319 | return &ir_build_call_gen(ira, &call_instruction->base, fn_entry, fn_ref, arg_count, | ||
| 15320 | casted_args, FnInlineAuto, true, casted_new_stack, call_instruction->is_async_call_builtin, | ||
| 15321 | result_loc, frame_type)->base; | ||
| 15235 | } | 15322 | } |
| 15236 | result_loc = ir_implicit_cast(ira, result_loc, get_pointer_to_type(ira->codegen, frame_type, false)); | ||
| 15237 | if (type_is_invalid(result_loc->value.type)) | ||
| 15238 | return ira->codegen->invalid_instruction; | ||
| 15239 | return &ir_build_call_gen(ira, &call_instruction->base, fn_entry, fn_ref, arg_count, | ||
| 15240 | casted_args, FnInlineAuto, true, nullptr, result_loc, frame_type)->base; | ||
| 15241 | } | 15323 | } |
| 15242 | static bool ir_analyze_fn_call_inline_arg(IrAnalyze *ira, AstNode *fn_proto_node, | 15324 | static bool ir_analyze_fn_call_inline_arg(IrAnalyze *ira, AstNode *fn_proto_node, |
| 15243 | IrInstruction *arg, Scope **exec_scope, size_t *next_proto_i) | 15325 | IrInstruction *arg, Scope **exec_scope, size_t *next_proto_i) |
| ... | @@ -15301,7 +15383,7 @@ static bool ir_analyze_fn_call_generic_arg(IrAnalyze *ira, AstNode *fn_proto_nod | ... | @@ -15301,7 +15383,7 @@ static bool ir_analyze_fn_call_generic_arg(IrAnalyze *ira, AstNode *fn_proto_nod |
| 15301 | } | 15383 | } |
| 15302 | } | 15384 | } |
| 15303 | 15385 | ||
| 15304 | bool comptime_arg = param_decl_node->data.param_decl.is_inline || | 15386 | bool comptime_arg = param_decl_node->data.param_decl.is_comptime || |
| 15305 | casted_arg->value.type->id == ZigTypeIdComptimeInt || casted_arg->value.type->id == ZigTypeIdComptimeFloat; | 15387 | casted_arg->value.type->id == ZigTypeIdComptimeInt || casted_arg->value.type->id == ZigTypeIdComptimeFloat; |
| 15306 | 15388 | ||
| 15307 | ConstExprValue *arg_val; | 15389 | ConstExprValue *arg_val; |
| ... | @@ -15746,16 +15828,27 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c | ... | @@ -15746,16 +15828,27 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c |
| 15746 | 15828 | ||
| 15747 | IrInstruction *casted_new_stack = nullptr; | 15829 | IrInstruction *casted_new_stack = nullptr; |
| 15748 | if (call_instruction->new_stack != nullptr) { | 15830 | if (call_instruction->new_stack != nullptr) { |
| 15749 | ZigType *u8_ptr = get_pointer_to_type_extra(ira->codegen, ira->codegen->builtin_types.entry_u8, | ||
| 15750 | false, false, PtrLenUnknown, target_fn_align(ira->codegen->zig_target), 0, 0, false); | ||
| 15751 | ZigType *u8_slice = get_slice_type(ira->codegen, u8_ptr); | ||
| 15752 | IrInstruction *new_stack = call_instruction->new_stack->child; | 15831 | IrInstruction *new_stack = call_instruction->new_stack->child; |
| 15753 | if (type_is_invalid(new_stack->value.type)) | 15832 | if (type_is_invalid(new_stack->value.type)) |
| 15754 | return ira->codegen->invalid_instruction; | 15833 | return ira->codegen->invalid_instruction; |
| 15755 | 15834 | ||
| 15756 | casted_new_stack = ir_implicit_cast(ira, new_stack, u8_slice); | 15835 | if (call_instruction->is_async_call_builtin && |
| 15757 | if (type_is_invalid(casted_new_stack->value.type)) | 15836 | fn_entry != nullptr && new_stack->value.type->id == ZigTypeIdPointer && |
| 15758 | return ira->codegen->invalid_instruction; | 15837 | new_stack->value.type->data.pointer.child_type->id == ZigTypeIdFnFrame) |
| 15838 | { | ||
| 15839 | ZigType *needed_frame_type = get_pointer_to_type(ira->codegen, | ||
| 15840 | get_fn_frame_type(ira->codegen, fn_entry), false); | ||
| 15841 | casted_new_stack = ir_implicit_cast(ira, new_stack, needed_frame_type); | ||
| 15842 | if (type_is_invalid(casted_new_stack->value.type)) | ||
| 15843 | return ira->codegen->invalid_instruction; | ||
| 15844 | } else { | ||
| 15845 | ZigType *u8_ptr = get_pointer_to_type_extra(ira->codegen, ira->codegen->builtin_types.entry_u8, | ||
| 15846 | false, false, PtrLenUnknown, target_fn_align(ira->codegen->zig_target), 0, 0, false); | ||
| 15847 | ZigType *u8_slice = get_slice_type(ira->codegen, u8_ptr); | ||
| 15848 | casted_new_stack = ir_implicit_cast(ira, new_stack, u8_slice); | ||
| 15849 | if (type_is_invalid(casted_new_stack->value.type)) | ||
| 15850 | return ira->codegen->invalid_instruction; | ||
| 15851 | } | ||
| 15759 | } | 15852 | } |
| 15760 | 15853 | ||
| 15761 | if (fn_type->data.fn.is_generic) { | 15854 | if (fn_type->data.fn.is_generic) { |
| ... | @@ -15965,8 +16058,24 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c | ... | @@ -15965,8 +16058,24 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c |
| 15965 | } | 16058 | } |
| 15966 | 16059 | ||
| 15967 | FnTypeId *impl_fn_type_id = &impl_fn->type_entry->data.fn.fn_type_id; | 16060 | FnTypeId *impl_fn_type_id = &impl_fn->type_entry->data.fn.fn_type_id; |
| 16061 | |||
| 16062 | if (fn_type_can_fail(impl_fn_type_id)) { | ||
| 16063 | parent_fn_entry->calls_or_awaits_errorable_fn = true; | ||
| 16064 | } | ||
| 16065 | |||
| 16066 | size_t impl_param_count = impl_fn_type_id->param_count; | ||
| 16067 | if (call_instruction->is_async) { | ||
| 16068 | IrInstruction *result = ir_analyze_async_call(ira, call_instruction, impl_fn, impl_fn->type_entry, | ||
| 16069 | nullptr, casted_args, impl_param_count, casted_new_stack); | ||
| 16070 | return ir_finish_anal(ira, result); | ||
| 16071 | } | ||
| 16072 | |||
| 15968 | IrInstruction *result_loc; | 16073 | IrInstruction *result_loc; |
| 15969 | if (handle_is_ptr(impl_fn_type_id->return_type)) { | 16074 | if (call_instruction->is_async_call_builtin) { |
| 16075 | result_loc = get_async_call_result_loc(ira, call_instruction, impl_fn_type_id->return_type); | ||
| 16076 | if (result_loc != nullptr && type_is_invalid(result_loc->value.type)) | ||
| 16077 | return ira->codegen->invalid_instruction; | ||
| 16078 | } else if (handle_is_ptr(impl_fn_type_id->return_type)) { | ||
| 15970 | result_loc = ir_resolve_result(ira, &call_instruction->base, call_instruction->result_loc, | 16079 | result_loc = ir_resolve_result(ira, &call_instruction->base, call_instruction->result_loc, |
| 15971 | impl_fn_type_id->return_type, nullptr, true, true, false); | 16080 | impl_fn_type_id->return_type, nullptr, true, true, false); |
| 15972 | if (result_loc != nullptr) { | 16081 | if (result_loc != nullptr) { |
| ... | @@ -15982,17 +16091,6 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c | ... | @@ -15982,17 +16091,6 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c |
| 15982 | result_loc = nullptr; | 16091 | result_loc = nullptr; |
| 15983 | } | 16092 | } |
| 15984 | 16093 | ||
| 15985 | if (fn_type_can_fail(impl_fn_type_id)) { | ||
| 15986 | parent_fn_entry->calls_or_awaits_errorable_fn = true; | ||
| 15987 | } | ||
| 15988 | |||
| 15989 | size_t impl_param_count = impl_fn_type_id->param_count; | ||
| 15990 | if (call_instruction->is_async) { | ||
| 15991 | IrInstruction *result = ir_analyze_async_call(ira, call_instruction, impl_fn, impl_fn->type_entry, | ||
| 15992 | nullptr, casted_args, impl_param_count, casted_new_stack); | ||
| 15993 | return ir_finish_anal(ira, result); | ||
| 15994 | } | ||
| 15995 | |||
| 15996 | if (impl_fn_type_id->cc == CallingConventionAsync && parent_fn_entry->inferred_async_node == nullptr) { | 16094 | if (impl_fn_type_id->cc == CallingConventionAsync && parent_fn_entry->inferred_async_node == nullptr) { |
| 15997 | parent_fn_entry->inferred_async_node = fn_ref->source_node; | 16095 | parent_fn_entry->inferred_async_node = fn_ref->source_node; |
| 15998 | parent_fn_entry->inferred_async_fn = impl_fn; | 16096 | parent_fn_entry->inferred_async_fn = impl_fn; |
| ... | @@ -16000,10 +16098,12 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c | ... | @@ -16000,10 +16098,12 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c |
| 16000 | 16098 | ||
| 16001 | IrInstructionCallGen *new_call_instruction = ir_build_call_gen(ira, &call_instruction->base, | 16099 | IrInstructionCallGen *new_call_instruction = ir_build_call_gen(ira, &call_instruction->base, |
| 16002 | impl_fn, nullptr, impl_param_count, casted_args, fn_inline, | 16100 | impl_fn, nullptr, impl_param_count, casted_args, fn_inline, |
| 16003 | false, casted_new_stack, result_loc, | 16101 | false, casted_new_stack, call_instruction->is_async_call_builtin, result_loc, |
| 16004 | impl_fn_type_id->return_type); | 16102 | impl_fn_type_id->return_type); |
| 16005 | 16103 | ||
| 16006 | parent_fn_entry->call_list.append(new_call_instruction); | 16104 | if (get_scope_typeof(call_instruction->base.scope) == nullptr) { |
| 16105 | parent_fn_entry->call_list.append(new_call_instruction); | ||
| 16106 | } | ||
| 16007 | 16107 | ||
| 16008 | return ir_finish_anal(ira, &new_call_instruction->base); | 16108 | return ir_finish_anal(ira, &new_call_instruction->base); |
| 16009 | } | 16109 | } |
| ... | @@ -16123,7 +16223,11 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c | ... | @@ -16123,7 +16223,11 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c |
| 16123 | } | 16223 | } |
| 16124 | 16224 | ||
| 16125 | IrInstruction *result_loc; | 16225 | IrInstruction *result_loc; |
| 16126 | if (handle_is_ptr(return_type)) { | 16226 | if (call_instruction->is_async_call_builtin) { |
| 16227 | result_loc = get_async_call_result_loc(ira, call_instruction, return_type); | ||
| 16228 | if (result_loc != nullptr && type_is_invalid(result_loc->value.type)) | ||
| 16229 | return ira->codegen->invalid_instruction; | ||
| 16230 | } else if (handle_is_ptr(return_type)) { | ||
| 16127 | result_loc = ir_resolve_result(ira, &call_instruction->base, call_instruction->result_loc, | 16231 | result_loc = ir_resolve_result(ira, &call_instruction->base, call_instruction->result_loc, |
| 16128 | return_type, nullptr, true, true, false); | 16232 | return_type, nullptr, true, true, false); |
| 16129 | if (result_loc != nullptr) { | 16233 | if (result_loc != nullptr) { |
| ... | @@ -16141,8 +16245,10 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c | ... | @@ -16141,8 +16245,10 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c |
| 16141 | 16245 | ||
| 16142 | IrInstructionCallGen *new_call_instruction = ir_build_call_gen(ira, &call_instruction->base, fn_entry, fn_ref, | 16246 | IrInstructionCallGen *new_call_instruction = ir_build_call_gen(ira, &call_instruction->base, fn_entry, fn_ref, |
| 16143 | call_param_count, casted_args, fn_inline, false, casted_new_stack, | 16247 | call_param_count, casted_args, fn_inline, false, casted_new_stack, |
| 16144 | result_loc, return_type); | 16248 | call_instruction->is_async_call_builtin, result_loc, return_type); |
| 16145 | parent_fn_entry->call_list.append(new_call_instruction); | 16249 | if (get_scope_typeof(call_instruction->base.scope) == nullptr) { |
| 16250 | parent_fn_entry->call_list.append(new_call_instruction); | ||
| 16251 | } | ||
| 16146 | return ir_finish_anal(ira, &new_call_instruction->base); | 16252 | return ir_finish_anal(ira, &new_call_instruction->base); |
| 16147 | } | 16253 | } |
| 16148 | 16254 | ||
| ... | @@ -17594,6 +17700,11 @@ static IrInstruction *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstruc | ... | @@ -17594,6 +17700,11 @@ static IrInstruction *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstruc |
| 17594 | ConstExprValue *child_val = const_ptr_pointee(ira, ira->codegen, container_ptr_val, source_node); | 17700 | ConstExprValue *child_val = const_ptr_pointee(ira, ira->codegen, container_ptr_val, source_node); |
| 17595 | if (child_val == nullptr) | 17701 | if (child_val == nullptr) |
| 17596 | return ira->codegen->invalid_instruction; | 17702 | return ira->codegen->invalid_instruction; |
| 17703 | if ((err = ir_resolve_const_val(ira->codegen, ira->new_irb.exec, | ||
| 17704 | field_ptr_instruction->base.source_node, child_val, UndefBad))) | ||
| 17705 | { | ||
| 17706 | return ira->codegen->invalid_instruction; | ||
| 17707 | } | ||
| 17597 | ZigType *child_type = child_val->data.x_type; | 17708 | ZigType *child_type = child_val->data.x_type; |
| 17598 | 17709 | ||
| 17599 | if (type_is_invalid(child_type)) { | 17710 | if (type_is_invalid(child_type)) { |
| ... | @@ -21293,8 +21404,10 @@ static IrInstruction *ir_analyze_instruction_from_bytes(IrAnalyze *ira, IrInstru | ... | @@ -21293,8 +21404,10 @@ static IrInstruction *ir_analyze_instruction_from_bytes(IrAnalyze *ira, IrInstru |
| 21293 | src_ptr_align = get_abi_alignment(ira->codegen, target->value.type); | 21404 | src_ptr_align = get_abi_alignment(ira->codegen, target->value.type); |
| 21294 | } | 21405 | } |
| 21295 | 21406 | ||
| 21296 | if ((err = type_resolve(ira->codegen, dest_child_type, ResolveStatusSizeKnown))) | 21407 | if (src_ptr_align != 0) { |
| 21297 | return ira->codegen->invalid_instruction; | 21408 | if ((err = type_resolve(ira->codegen, dest_child_type, ResolveStatusAlignmentKnown))) |
| 21409 | return ira->codegen->invalid_instruction; | ||
| 21410 | } | ||
| 21298 | 21411 | ||
| 21299 | ZigType *dest_ptr_type = get_pointer_to_type_extra(ira->codegen, dest_child_type, | 21412 | ZigType *dest_ptr_type = get_pointer_to_type_extra(ira->codegen, dest_child_type, |
| 21300 | src_ptr_const, src_ptr_volatile, PtrLenUnknown, | 21413 | src_ptr_const, src_ptr_volatile, PtrLenUnknown, |
| ... | @@ -21337,6 +21450,8 @@ static IrInstruction *ir_analyze_instruction_from_bytes(IrAnalyze *ira, IrInstru | ... | @@ -21337,6 +21450,8 @@ static IrInstruction *ir_analyze_instruction_from_bytes(IrAnalyze *ira, IrInstru |
| 21337 | } | 21450 | } |
| 21338 | 21451 | ||
| 21339 | if (have_known_len) { | 21452 | if (have_known_len) { |
| 21453 | if ((err = type_resolve(ira->codegen, dest_child_type, ResolveStatusSizeKnown))) | ||
| 21454 | return ira->codegen->invalid_instruction; | ||
| 21340 | uint64_t child_type_size = type_size(ira->codegen, dest_child_type); | 21455 | uint64_t child_type_size = type_size(ira->codegen, dest_child_type); |
| 21341 | uint64_t remainder = known_len % child_type_size; | 21456 | uint64_t remainder = known_len % child_type_size; |
| 21342 | if (remainder != 0) { | 21457 | if (remainder != 0) { |
| ... | @@ -23963,15 +24078,23 @@ static IrInstruction *ir_analyze_instruction_ptr_type(IrAnalyze *ira, IrInstruct | ... | @@ -23963,15 +24078,23 @@ static IrInstruction *ir_analyze_instruction_ptr_type(IrAnalyze *ira, IrInstruct |
| 23963 | } | 24078 | } |
| 23964 | 24079 | ||
| 23965 | static IrInstruction *ir_analyze_instruction_align_cast(IrAnalyze *ira, IrInstructionAlignCast *instruction) { | 24080 | static IrInstruction *ir_analyze_instruction_align_cast(IrAnalyze *ira, IrInstructionAlignCast *instruction) { |
| 23966 | uint32_t align_bytes; | ||
| 23967 | IrInstruction *align_bytes_inst = instruction->align_bytes->child; | ||
| 23968 | if (!ir_resolve_align(ira, align_bytes_inst, nullptr, &align_bytes)) | ||
| 23969 | return ira->codegen->invalid_instruction; | ||
| 23970 | |||
| 23971 | IrInstruction *target = instruction->target->child; | 24081 | IrInstruction *target = instruction->target->child; |
| 23972 | if (type_is_invalid(target->value.type)) | 24082 | if (type_is_invalid(target->value.type)) |
| 23973 | return ira->codegen->invalid_instruction; | 24083 | return ira->codegen->invalid_instruction; |
| 23974 | 24084 | ||
| 24085 | ZigType *elem_type = nullptr; | ||
| 24086 | if (is_slice(target->value.type)) { | ||
| 24087 | ZigType *slice_ptr_type = target->value.type->data.structure.fields[slice_ptr_index].type_entry; | ||
| 24088 | elem_type = slice_ptr_type->data.pointer.child_type; | ||
| 24089 | } else if (target->value.type->id == ZigTypeIdPointer) { | ||
| 24090 | elem_type = target->value.type->data.pointer.child_type; | ||
| 24091 | } | ||
| 24092 | |||
| 24093 | uint32_t align_bytes; | ||
| 24094 | IrInstruction *align_bytes_inst = instruction->align_bytes->child; | ||
| 24095 | if (!ir_resolve_align(ira, align_bytes_inst, elem_type, &align_bytes)) | ||
| 24096 | return ira->codegen->invalid_instruction; | ||
| 24097 | |||
| 23975 | IrInstruction *result = ir_align_cast(ira, target, align_bytes, true); | 24098 | IrInstruction *result = ir_align_cast(ira, target, align_bytes, true); |
| 23976 | if (type_is_invalid(result->value.type)) | 24099 | if (type_is_invalid(result->value.type)) |
| 23977 | return ira->codegen->invalid_instruction; | 24100 | return ira->codegen->invalid_instruction; |
| ... | @@ -25644,7 +25767,7 @@ static Error ir_resolve_lazy_raw(AstNode *source_node, ConstExprValue *val) { | ... | @@ -25644,7 +25767,7 @@ static Error ir_resolve_lazy_raw(AstNode *source_node, ConstExprValue *val) { |
| 25644 | } | 25767 | } |
| 25645 | 25768 | ||
| 25646 | val->special = ConstValSpecialStatic; | 25769 | val->special = ConstValSpecialStatic; |
| 25647 | assert(val->type->id == ZigTypeIdComptimeInt); | 25770 | assert(val->type->id == ZigTypeIdComptimeInt || val->type->id == ZigTypeIdInt); |
| 25648 | bigint_init_unsigned(&val->data.x_bigint, align_in_bytes); | 25771 | bigint_init_unsigned(&val->data.x_bigint, align_in_bytes); |
| 25649 | return ErrorNone; | 25772 | return ErrorNone; |
| 25650 | } | 25773 | } |
| ... | @@ -25699,7 +25822,7 @@ static Error ir_resolve_lazy_raw(AstNode *source_node, ConstExprValue *val) { | ... | @@ -25699,7 +25822,7 @@ static Error ir_resolve_lazy_raw(AstNode *source_node, ConstExprValue *val) { |
| 25699 | } | 25822 | } |
| 25700 | 25823 | ||
| 25701 | val->special = ConstValSpecialStatic; | 25824 | val->special = ConstValSpecialStatic; |
| 25702 | assert(val->type->id == ZigTypeIdComptimeInt); | 25825 | assert(val->type->id == ZigTypeIdComptimeInt || val->type->id == ZigTypeIdInt); |
| 25703 | bigint_init_unsigned(&val->data.x_bigint, abi_size); | 25826 | bigint_init_unsigned(&val->data.x_bigint, abi_size); |
| 25704 | return ErrorNone; | 25827 | return ErrorNone; |
| 25705 | } | 25828 | } |
| ... | @@ -25885,7 +26008,7 @@ static Error ir_resolve_lazy_raw(AstNode *source_node, ConstExprValue *val) { | ... | @@ -25885,7 +26008,7 @@ static Error ir_resolve_lazy_raw(AstNode *source_node, ConstExprValue *val) { |
| 25885 | Error ir_resolve_lazy(CodeGen *codegen, AstNode *source_node, ConstExprValue *val) { | 26008 | Error ir_resolve_lazy(CodeGen *codegen, AstNode *source_node, ConstExprValue *val) { |
| 25886 | Error err; | 26009 | Error err; |
| 25887 | if ((err = ir_resolve_lazy_raw(source_node, val))) { | 26010 | if ((err = ir_resolve_lazy_raw(source_node, val))) { |
| 25888 | if (codegen->trace_err != nullptr && !source_node->already_traced_this_node) { | 26011 | if (codegen->trace_err != nullptr && source_node != nullptr && !source_node->already_traced_this_node) { |
| 25889 | source_node->already_traced_this_node = true; | 26012 | source_node->already_traced_this_node = true; |
| 25890 | codegen->trace_err = add_error_note(codegen, codegen->trace_err, source_node, | 26013 | codegen->trace_err = add_error_note(codegen, codegen->trace_err, source_node, |
| 25891 | buf_create_from_str("referenced here")); | 26014 | buf_create_from_str("referenced here")); |
src/ir_print.cpp+377-8| ... | @@ -10,27 +10,374 @@ | ... | @@ -10,27 +10,374 @@ |
| 10 | #include "ir_print.hpp" | 10 | #include "ir_print.hpp" |
| 11 | #include "os.hpp" | 11 | #include "os.hpp" |
| 12 | 12 | ||
| 13 | static uint32_t hash_instruction_ptr(IrInstruction* instruction) { | ||
| 14 | return (uint32_t)(uintptr_t)instruction; | ||
| 15 | } | ||
| 16 | |||
| 17 | static bool instruction_ptr_equal(IrInstruction* a, IrInstruction* b) { | ||
| 18 | return a == b; | ||
| 19 | } | ||
| 20 | |||
| 21 | using InstructionSet = HashMap<IrInstruction*, uint8_t, hash_instruction_ptr, instruction_ptr_equal>; | ||
| 22 | using InstructionList = ZigList<IrInstruction*>; | ||
| 23 | |||
| 13 | struct IrPrint { | 24 | struct IrPrint { |
| 25 | size_t pass_num; | ||
| 14 | CodeGen *codegen; | 26 | CodeGen *codegen; |
| 15 | FILE *f; | 27 | FILE *f; |
| 16 | int indent; | 28 | int indent; |
| 17 | int indent_size; | 29 | int indent_size; |
| 30 | |||
| 31 | // When printing pass 2 instructions referenced var instructions are not | ||
| 32 | // present in the instruction list. Thus we track which instructions | ||
| 33 | // are printed (per executable) and after each pass 2 instruction those | ||
| 34 | // var instructions are rendered in a trailing fashion. | ||
| 35 | InstructionSet printed; | ||
| 36 | InstructionList pending; | ||
| 18 | }; | 37 | }; |
| 19 | 38 | ||
| 20 | static void ir_print_other_instruction(IrPrint *irp, IrInstruction *instruction); | 39 | static void ir_print_other_instruction(IrPrint *irp, IrInstruction *instruction); |
| 21 | 40 | ||
| 41 | static const char* ir_instruction_type_str(IrInstruction* instruction) { | ||
| 42 | switch (instruction->id) { | ||
| 43 | case IrInstructionIdInvalid: | ||
| 44 | return "Invalid"; | ||
| 45 | case IrInstructionIdDeclVarSrc: | ||
| 46 | return "DeclVarSrc"; | ||
| 47 | case IrInstructionIdDeclVarGen: | ||
| 48 | return "DeclVarGen"; | ||
| 49 | case IrInstructionIdBr: | ||
| 50 | return "Br"; | ||
| 51 | case IrInstructionIdCondBr: | ||
| 52 | return "CondBr"; | ||
| 53 | case IrInstructionIdSwitchBr: | ||
| 54 | return "SwitchBr"; | ||
| 55 | case IrInstructionIdSwitchVar: | ||
| 56 | return "SwitchVar"; | ||
| 57 | case IrInstructionIdSwitchElseVar: | ||
| 58 | return "SwitchElseVar"; | ||
| 59 | case IrInstructionIdSwitchTarget: | ||
| 60 | return "SwitchTarget"; | ||
| 61 | case IrInstructionIdPhi: | ||
| 62 | return "Phi"; | ||
| 63 | case IrInstructionIdUnOp: | ||
| 64 | return "UnOp"; | ||
| 65 | case IrInstructionIdBinOp: | ||
| 66 | return "BinOp"; | ||
| 67 | case IrInstructionIdLoadPtr: | ||
| 68 | return "LoadPtr"; | ||
| 69 | case IrInstructionIdLoadPtrGen: | ||
| 70 | return "LoadPtrGen"; | ||
| 71 | case IrInstructionIdStorePtr: | ||
| 72 | return "StorePtr"; | ||
| 73 | case IrInstructionIdFieldPtr: | ||
| 74 | return "FieldPtr"; | ||
| 75 | case IrInstructionIdStructFieldPtr: | ||
| 76 | return "StructFieldPtr"; | ||
| 77 | case IrInstructionIdUnionFieldPtr: | ||
| 78 | return "UnionFieldPtr"; | ||
| 79 | case IrInstructionIdElemPtr: | ||
| 80 | return "ElemPtr"; | ||
| 81 | case IrInstructionIdVarPtr: | ||
| 82 | return "VarPtr"; | ||
| 83 | case IrInstructionIdReturnPtr: | ||
| 84 | return "ReturnPtr"; | ||
| 85 | case IrInstructionIdCallSrc: | ||
| 86 | return "CallSrc"; | ||
| 87 | case IrInstructionIdCallGen: | ||
| 88 | return "CallGen"; | ||
| 89 | case IrInstructionIdConst: | ||
| 90 | return "Const"; | ||
| 91 | case IrInstructionIdReturn: | ||
| 92 | return "Return"; | ||
| 93 | case IrInstructionIdCast: | ||
| 94 | return "Cast"; | ||
| 95 | case IrInstructionIdResizeSlice: | ||
| 96 | return "ResizeSlice"; | ||
| 97 | case IrInstructionIdContainerInitList: | ||
| 98 | return "ContainerInitList"; | ||
| 99 | case IrInstructionIdContainerInitFields: | ||
| 100 | return "ContainerInitFields"; | ||
| 101 | case IrInstructionIdUnreachable: | ||
| 102 | return "Unreachable"; | ||
| 103 | case IrInstructionIdTypeOf: | ||
| 104 | return "TypeOf"; | ||
| 105 | case IrInstructionIdSetCold: | ||
| 106 | return "SetCold"; | ||
| 107 | case IrInstructionIdSetRuntimeSafety: | ||
| 108 | return "SetRuntimeSafety"; | ||
| 109 | case IrInstructionIdSetFloatMode: | ||
| 110 | return "SetFloatMode"; | ||
| 111 | case IrInstructionIdArrayType: | ||
| 112 | return "ArrayType"; | ||
| 113 | case IrInstructionIdAnyFrameType: | ||
| 114 | return "AnyFrameType"; | ||
| 115 | case IrInstructionIdSliceType: | ||
| 116 | return "SliceType"; | ||
| 117 | case IrInstructionIdGlobalAsm: | ||
| 118 | return "GlobalAsm"; | ||
| 119 | case IrInstructionIdAsm: | ||
| 120 | return "Asm"; | ||
| 121 | case IrInstructionIdSizeOf: | ||
| 122 | return "SizeOf"; | ||
| 123 | case IrInstructionIdTestNonNull: | ||
| 124 | return "TestNonNull"; | ||
| 125 | case IrInstructionIdOptionalUnwrapPtr: | ||
| 126 | return "OptionalUnwrapPtr"; | ||
| 127 | case IrInstructionIdOptionalWrap: | ||
| 128 | return "OptionalWrap"; | ||
| 129 | case IrInstructionIdUnionTag: | ||
| 130 | return "UnionTag"; | ||
| 131 | case IrInstructionIdClz: | ||
| 132 | return "Clz"; | ||
| 133 | case IrInstructionIdCtz: | ||
| 134 | return "Ctz"; | ||
| 135 | case IrInstructionIdPopCount: | ||
| 136 | return "PopCount"; | ||
| 137 | case IrInstructionIdBswap: | ||
| 138 | return "Bswap"; | ||
| 139 | case IrInstructionIdBitReverse: | ||
| 140 | return "BitReverse"; | ||
| 141 | case IrInstructionIdImport: | ||
| 142 | return "Import"; | ||
| 143 | case IrInstructionIdCImport: | ||
| 144 | return "CImport"; | ||
| 145 | case IrInstructionIdCInclude: | ||
| 146 | return "CInclude"; | ||
| 147 | case IrInstructionIdCDefine: | ||
| 148 | return "CDefine"; | ||
| 149 | case IrInstructionIdCUndef: | ||
| 150 | return "CUndef"; | ||
| 151 | case IrInstructionIdRef: | ||
| 152 | return "Ref"; | ||
| 153 | case IrInstructionIdRefGen: | ||
| 154 | return "RefGen"; | ||
| 155 | case IrInstructionIdCompileErr: | ||
| 156 | return "CompileErr"; | ||
| 157 | case IrInstructionIdCompileLog: | ||
| 158 | return "CompileLog"; | ||
| 159 | case IrInstructionIdErrName: | ||
| 160 | return "ErrName"; | ||
| 161 | case IrInstructionIdEmbedFile: | ||
| 162 | return "EmbedFile"; | ||
| 163 | case IrInstructionIdCmpxchgSrc: | ||
| 164 | return "CmpxchgSrc"; | ||
| 165 | case IrInstructionIdCmpxchgGen: | ||
| 166 | return "CmpxchgGen"; | ||
| 167 | case IrInstructionIdFence: | ||
| 168 | return "Fence"; | ||
| 169 | case IrInstructionIdTruncate: | ||
| 170 | return "Truncate"; | ||
| 171 | case IrInstructionIdIntCast: | ||
| 172 | return "IntCast"; | ||
| 173 | case IrInstructionIdFloatCast: | ||
| 174 | return "FloatCast"; | ||
| 175 | case IrInstructionIdIntToFloat: | ||
| 176 | return "IntToFloat"; | ||
| 177 | case IrInstructionIdFloatToInt: | ||
| 178 | return "FloatToInt"; | ||
| 179 | case IrInstructionIdBoolToInt: | ||
| 180 | return "BoolToInt"; | ||
| 181 | case IrInstructionIdIntType: | ||
| 182 | return "IntType"; | ||
| 183 | case IrInstructionIdVectorType: | ||
| 184 | return "VectorType"; | ||
| 185 | case IrInstructionIdBoolNot: | ||
| 186 | return "BoolNot"; | ||
| 187 | case IrInstructionIdMemset: | ||
| 188 | return "Memset"; | ||
| 189 | case IrInstructionIdMemcpy: | ||
| 190 | return "Memcpy"; | ||
| 191 | case IrInstructionIdSliceSrc: | ||
| 192 | return "SliceSrc"; | ||
| 193 | case IrInstructionIdSliceGen: | ||
| 194 | return "SliceGen"; | ||
| 195 | case IrInstructionIdMemberCount: | ||
| 196 | return "MemberCount"; | ||
| 197 | case IrInstructionIdMemberType: | ||
| 198 | return "MemberType"; | ||
| 199 | case IrInstructionIdMemberName: | ||
| 200 | return "MemberName"; | ||
| 201 | case IrInstructionIdBreakpoint: | ||
| 202 | return "Breakpoint"; | ||
| 203 | case IrInstructionIdReturnAddress: | ||
| 204 | return "ReturnAddress"; | ||
| 205 | case IrInstructionIdFrameAddress: | ||
| 206 | return "FrameAddress"; | ||
| 207 | case IrInstructionIdFrameHandle: | ||
| 208 | return "FrameHandle"; | ||
| 209 | case IrInstructionIdFrameType: | ||
| 210 | return "FrameType"; | ||
| 211 | case IrInstructionIdFrameSizeSrc: | ||
| 212 | return "FrameSizeSrc"; | ||
| 213 | case IrInstructionIdFrameSizeGen: | ||
| 214 | return "FrameSizeGen"; | ||
| 215 | case IrInstructionIdAlignOf: | ||
| 216 | return "AlignOf"; | ||
| 217 | case IrInstructionIdOverflowOp: | ||
| 218 | return "OverflowOp"; | ||
| 219 | case IrInstructionIdTestErrSrc: | ||
| 220 | return "TestErrSrc"; | ||
| 221 | case IrInstructionIdTestErrGen: | ||
| 222 | return "TestErrGen"; | ||
| 223 | case IrInstructionIdMulAdd: | ||
| 224 | return "MulAdd"; | ||
| 225 | case IrInstructionIdFloatOp: | ||
| 226 | return "FloatOp"; | ||
| 227 | case IrInstructionIdUnwrapErrCode: | ||
| 228 | return "UnwrapErrCode"; | ||
| 229 | case IrInstructionIdUnwrapErrPayload: | ||
| 230 | return "UnwrapErrPayload"; | ||
| 231 | case IrInstructionIdErrWrapCode: | ||
| 232 | return "ErrWrapCode"; | ||
| 233 | case IrInstructionIdErrWrapPayload: | ||
| 234 | return "ErrWrapPayload"; | ||
| 235 | case IrInstructionIdFnProto: | ||
| 236 | return "FnProto"; | ||
| 237 | case IrInstructionIdTestComptime: | ||
| 238 | return "TestComptime"; | ||
| 239 | case IrInstructionIdPtrCastSrc: | ||
| 240 | return "PtrCastSrc"; | ||
| 241 | case IrInstructionIdPtrCastGen: | ||
| 242 | return "PtrCastGen"; | ||
| 243 | case IrInstructionIdBitCastSrc: | ||
| 244 | return "BitCastSrc"; | ||
| 245 | case IrInstructionIdBitCastGen: | ||
| 246 | return "BitCastGen"; | ||
| 247 | case IrInstructionIdWidenOrShorten: | ||
| 248 | return "WidenOrShorten"; | ||
| 249 | case IrInstructionIdIntToPtr: | ||
| 250 | return "IntToPtr"; | ||
| 251 | case IrInstructionIdPtrToInt: | ||
| 252 | return "PtrToInt"; | ||
| 253 | case IrInstructionIdIntToEnum: | ||
| 254 | return "IntToEnum"; | ||
| 255 | case IrInstructionIdEnumToInt: | ||
| 256 | return "EnumToInt"; | ||
| 257 | case IrInstructionIdIntToErr: | ||
| 258 | return "IntToErr"; | ||
| 259 | case IrInstructionIdErrToInt: | ||
| 260 | return "ErrToInt"; | ||
| 261 | case IrInstructionIdCheckSwitchProngs: | ||
| 262 | return "CheckSwitchProngs"; | ||
| 263 | case IrInstructionIdCheckStatementIsVoid: | ||
| 264 | return "CheckStatementIsVoid"; | ||
| 265 | case IrInstructionIdTypeName: | ||
| 266 | return "TypeName"; | ||
| 267 | case IrInstructionIdDeclRef: | ||
| 268 | return "DeclRef"; | ||
| 269 | case IrInstructionIdPanic: | ||
| 270 | return "Panic"; | ||
| 271 | case IrInstructionIdTagName: | ||
| 272 | return "TagName"; | ||
| 273 | case IrInstructionIdTagType: | ||
| 274 | return "TagType"; | ||
| 275 | case IrInstructionIdFieldParentPtr: | ||
| 276 | return "FieldParentPtr"; | ||
| 277 | case IrInstructionIdByteOffsetOf: | ||
| 278 | return "ByteOffsetOf"; | ||
| 279 | case IrInstructionIdBitOffsetOf: | ||
| 280 | return "BitOffsetOf"; | ||
| 281 | case IrInstructionIdTypeInfo: | ||
| 282 | return "TypeInfo"; | ||
| 283 | case IrInstructionIdHasField: | ||
| 284 | return "HasField"; | ||
| 285 | case IrInstructionIdTypeId: | ||
| 286 | return "TypeId"; | ||
| 287 | case IrInstructionIdSetEvalBranchQuota: | ||
| 288 | return "SetEvalBranchQuota"; | ||
| 289 | case IrInstructionIdPtrType: | ||
| 290 | return "PtrType"; | ||
| 291 | case IrInstructionIdAlignCast: | ||
| 292 | return "AlignCast"; | ||
| 293 | case IrInstructionIdImplicitCast: | ||
| 294 | return "ImplicitCast"; | ||
| 295 | case IrInstructionIdResolveResult: | ||
| 296 | return "ResolveResult"; | ||
| 297 | case IrInstructionIdResetResult: | ||
| 298 | return "ResetResult"; | ||
| 299 | case IrInstructionIdOpaqueType: | ||
| 300 | return "OpaqueType"; | ||
| 301 | case IrInstructionIdSetAlignStack: | ||
| 302 | return "SetAlignStack"; | ||
| 303 | case IrInstructionIdArgType: | ||
| 304 | return "ArgType"; | ||
| 305 | case IrInstructionIdExport: | ||
| 306 | return "Export"; | ||
| 307 | case IrInstructionIdErrorReturnTrace: | ||
| 308 | return "ErrorReturnTrace"; | ||
| 309 | case IrInstructionIdErrorUnion: | ||
| 310 | return "ErrorUnion"; | ||
| 311 | case IrInstructionIdAtomicRmw: | ||
| 312 | return "AtomicRmw"; | ||
| 313 | case IrInstructionIdAtomicLoad: | ||
| 314 | return "AtomicLoad"; | ||
| 315 | case IrInstructionIdSaveErrRetAddr: | ||
| 316 | return "SaveErrRetAddr"; | ||
| 317 | case IrInstructionIdAddImplicitReturnType: | ||
| 318 | return "AddImplicitReturnType"; | ||
| 319 | case IrInstructionIdErrSetCast: | ||
| 320 | return "ErrSetCast"; | ||
| 321 | case IrInstructionIdToBytes: | ||
| 322 | return "ToBytes"; | ||
| 323 | case IrInstructionIdFromBytes: | ||
| 324 | return "FromBytes"; | ||
| 325 | case IrInstructionIdCheckRuntimeScope: | ||
| 326 | return "CheckRuntimeScope"; | ||
| 327 | case IrInstructionIdVectorToArray: | ||
| 328 | return "VectorToArray"; | ||
| 329 | case IrInstructionIdArrayToVector: | ||
| 330 | return "ArrayToVector"; | ||
| 331 | case IrInstructionIdAssertZero: | ||
| 332 | return "AssertZero"; | ||
| 333 | case IrInstructionIdAssertNonNull: | ||
| 334 | return "AssertNonNull"; | ||
| 335 | case IrInstructionIdHasDecl: | ||
| 336 | return "HasDecl"; | ||
| 337 | case IrInstructionIdUndeclaredIdent: | ||
| 338 | return "UndeclaredIdent"; | ||
| 339 | case IrInstructionIdAllocaSrc: | ||
| 340 | return "AllocaSrc"; | ||
| 341 | case IrInstructionIdAllocaGen: | ||
| 342 | return "AllocaGen"; | ||
| 343 | case IrInstructionIdEndExpr: | ||
| 344 | return "EndExpr"; | ||
| 345 | case IrInstructionIdPtrOfArrayToSlice: | ||
| 346 | return "PtrOfArrayToSlice"; | ||
| 347 | case IrInstructionIdUnionInitNamedField: | ||
| 348 | return "UnionInitNamedField"; | ||
| 349 | case IrInstructionIdSuspendBegin: | ||
| 350 | return "SuspendBegin"; | ||
| 351 | case IrInstructionIdSuspendFinish: | ||
| 352 | return "SuspendFinish"; | ||
| 353 | case IrInstructionIdAwaitSrc: | ||
| 354 | return "AwaitSrc"; | ||
| 355 | case IrInstructionIdAwaitGen: | ||
| 356 | return "AwaitGen"; | ||
| 357 | case IrInstructionIdResume: | ||
| 358 | return "Resume"; | ||
| 359 | case IrInstructionIdSpillBegin: | ||
| 360 | return "SpillBegin"; | ||
| 361 | case IrInstructionIdSpillEnd: | ||
| 362 | return "SpillEnd"; | ||
| 363 | } | ||
| 364 | zig_unreachable(); | ||
| 365 | } | ||
| 366 | |||
| 22 | static void ir_print_indent(IrPrint *irp) { | 367 | static void ir_print_indent(IrPrint *irp) { |
| 23 | for (int i = 0; i < irp->indent; i += 1) { | 368 | for (int i = 0; i < irp->indent; i += 1) { |
| 24 | fprintf(irp->f, " "); | 369 | fprintf(irp->f, " "); |
| 25 | } | 370 | } |
| 26 | } | 371 | } |
| 27 | 372 | ||
| 28 | static void ir_print_prefix(IrPrint *irp, IrInstruction *instruction) { | 373 | static void ir_print_prefix(IrPrint *irp, IrInstruction *instruction, bool trailing) { |
| 29 | ir_print_indent(irp); | 374 | ir_print_indent(irp); |
| 375 | const char mark = trailing ? ':' : '#'; | ||
| 30 | const char *type_name = instruction->value.type ? buf_ptr(&instruction->value.type->name) : "(unknown)"; | 376 | const char *type_name = instruction->value.type ? buf_ptr(&instruction->value.type->name) : "(unknown)"; |
| 31 | const char *ref_count = ir_has_side_effects(instruction) ? | 377 | const char *ref_count = ir_has_side_effects(instruction) ? |
| 32 | "-" : buf_ptr(buf_sprintf("%" ZIG_PRI_usize "", instruction->ref_count)); | 378 | "-" : buf_ptr(buf_sprintf("%" ZIG_PRI_usize "", instruction->ref_count)); |
| 33 | fprintf(irp->f, "#%-3zu| %-12s| %-2s| ", instruction->debug_id, type_name, ref_count); | 379 | fprintf(irp->f, "%c%-3zu| %-22s| %-12s| %-2s| ", mark, instruction->debug_id, |
| 380 | ir_instruction_type_str(instruction), type_name, ref_count); | ||
| 34 | } | 381 | } |
| 35 | 382 | ||
| 36 | static void ir_print_const_value(IrPrint *irp, ConstExprValue *const_val) { | 383 | static void ir_print_const_value(IrPrint *irp, ConstExprValue *const_val) { |
| ... | @@ -42,6 +389,10 @@ static void ir_print_const_value(IrPrint *irp, ConstExprValue *const_val) { | ... | @@ -42,6 +389,10 @@ static void ir_print_const_value(IrPrint *irp, ConstExprValue *const_val) { |
| 42 | 389 | ||
| 43 | static void ir_print_var_instruction(IrPrint *irp, IrInstruction *instruction) { | 390 | static void ir_print_var_instruction(IrPrint *irp, IrInstruction *instruction) { |
| 44 | fprintf(irp->f, "#%" ZIG_PRI_usize "", instruction->debug_id); | 391 | fprintf(irp->f, "#%" ZIG_PRI_usize "", instruction->debug_id); |
| 392 | if (irp->pass_num == 2 && irp->printed.maybe_get(instruction) == nullptr) { | ||
| 393 | irp->printed.put(instruction, 0); | ||
| 394 | irp->pending.append(instruction); | ||
| 395 | } | ||
| 45 | } | 396 | } |
| 46 | 397 | ||
| 47 | static void ir_print_other_instruction(IrPrint *irp, IrInstruction *instruction) { | 398 | static void ir_print_other_instruction(IrPrint *irp, IrInstruction *instruction) { |
| ... | @@ -49,6 +400,7 @@ static void ir_print_other_instruction(IrPrint *irp, IrInstruction *instruction) | ... | @@ -49,6 +400,7 @@ static void ir_print_other_instruction(IrPrint *irp, IrInstruction *instruction) |
| 49 | fprintf(irp->f, "(null)"); | 400 | fprintf(irp->f, "(null)"); |
| 50 | return; | 401 | return; |
| 51 | } | 402 | } |
| 403 | |||
| 52 | if (instruction->value.special != ConstValSpecialRuntime) { | 404 | if (instruction->value.special != ConstValSpecialRuntime) { |
| 53 | ir_print_const_value(irp, &instruction->value); | 405 | ir_print_const_value(irp, &instruction->value); |
| 54 | } else { | 406 | } else { |
| ... | @@ -1550,8 +1902,8 @@ static void ir_print_spill_end(IrPrint *irp, IrInstructionSpillEnd *instruction) | ... | @@ -1550,8 +1902,8 @@ static void ir_print_spill_end(IrPrint *irp, IrInstructionSpillEnd *instruction) |
| 1550 | fprintf(irp->f, ")"); | 1902 | fprintf(irp->f, ")"); |
| 1551 | } | 1903 | } |
| 1552 | 1904 | ||
| 1553 | static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { | 1905 | static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction, bool trailing) { |
| 1554 | ir_print_prefix(irp, instruction); | 1906 | ir_print_prefix(irp, instruction, trailing); |
| 1555 | switch (instruction->id) { | 1907 | switch (instruction->id) { |
| 1556 | case IrInstructionIdInvalid: | 1908 | case IrInstructionIdInvalid: |
| 1557 | zig_unreachable(); | 1909 | zig_unreachable(); |
| ... | @@ -2036,31 +2388,48 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { | ... | @@ -2036,31 +2388,48 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { |
| 2036 | fprintf(irp->f, "\n"); | 2388 | fprintf(irp->f, "\n"); |
| 2037 | } | 2389 | } |
| 2038 | 2390 | ||
| 2039 | void ir_print(CodeGen *codegen, FILE *f, IrExecutable *executable, int indent_size) { | 2391 | void ir_print(CodeGen *codegen, FILE *f, IrExecutable *executable, int indent_size, size_t pass_num) { |
| 2040 | IrPrint ir_print = {}; | 2392 | IrPrint ir_print = {}; |
| 2041 | IrPrint *irp = &ir_print; | 2393 | IrPrint *irp = &ir_print; |
| 2394 | irp->pass_num = pass_num; | ||
| 2042 | irp->codegen = codegen; | 2395 | irp->codegen = codegen; |
| 2043 | irp->f = f; | 2396 | irp->f = f; |
| 2044 | irp->indent = indent_size; | 2397 | irp->indent = indent_size; |
| 2045 | irp->indent_size = indent_size; | 2398 | irp->indent_size = indent_size; |
| 2399 | irp->printed = {}; | ||
| 2400 | irp->printed.init(64); | ||
| 2401 | irp->pending = {}; | ||
| 2046 | 2402 | ||
| 2047 | for (size_t bb_i = 0; bb_i < executable->basic_block_list.length; bb_i += 1) { | 2403 | for (size_t bb_i = 0; bb_i < executable->basic_block_list.length; bb_i += 1) { |
| 2048 | IrBasicBlock *current_block = executable->basic_block_list.at(bb_i); | 2404 | IrBasicBlock *current_block = executable->basic_block_list.at(bb_i); |
| 2049 | fprintf(irp->f, "%s_%" ZIG_PRI_usize ":\n", current_block->name_hint, current_block->debug_id); | 2405 | fprintf(irp->f, "%s_%" ZIG_PRI_usize ":\n", current_block->name_hint, current_block->debug_id); |
| 2050 | for (size_t instr_i = 0; instr_i < current_block->instruction_list.length; instr_i += 1) { | 2406 | for (size_t instr_i = 0; instr_i < current_block->instruction_list.length; instr_i += 1) { |
| 2051 | IrInstruction *instruction = current_block->instruction_list.at(instr_i); | 2407 | IrInstruction *instruction = current_block->instruction_list.at(instr_i); |
| 2052 | ir_print_instruction(irp, instruction); | 2408 | if (irp->pass_num == 2) { |
| 2409 | irp->printed.put(instruction, 0); | ||
| 2410 | irp->pending.clear(); | ||
| 2411 | } | ||
| 2412 | ir_print_instruction(irp, instruction, false); | ||
| 2413 | for (size_t j = 0; j < irp->pending.length; ++j) | ||
| 2414 | ir_print_instruction(irp, irp->pending.at(j), true); | ||
| 2053 | } | 2415 | } |
| 2054 | } | 2416 | } |
| 2417 | |||
| 2418 | irp->pending.deinit(); | ||
| 2419 | irp->printed.deinit(); | ||
| 2055 | } | 2420 | } |
| 2056 | 2421 | ||
| 2057 | void ir_print_instruction(CodeGen *codegen, FILE *f, IrInstruction *instruction, int indent_size) { | 2422 | void ir_print_instruction(CodeGen *codegen, FILE *f, IrInstruction *instruction, int indent_size, size_t pass_num) { |
| 2058 | IrPrint ir_print = {}; | 2423 | IrPrint ir_print = {}; |
| 2059 | IrPrint *irp = &ir_print; | 2424 | IrPrint *irp = &ir_print; |
| 2425 | irp->pass_num = pass_num; | ||
| 2060 | irp->codegen = codegen; | 2426 | irp->codegen = codegen; |
| 2061 | irp->f = f; | 2427 | irp->f = f; |
| 2062 | irp->indent = indent_size; | 2428 | irp->indent = indent_size; |
| 2063 | irp->indent_size = indent_size; | 2429 | irp->indent_size = indent_size; |
| 2430 | irp->printed = {}; | ||
| 2431 | irp->printed.init(4); | ||
| 2432 | irp->pending = {}; | ||
| 2064 | 2433 | ||
| 2065 | ir_print_instruction(irp, instruction); | 2434 | ir_print_instruction(irp, instruction, false); |
| 2066 | } | 2435 | } |
src/ir_print.hpp+2-2| ... | @@ -12,7 +12,7 @@ | ... | @@ -12,7 +12,7 @@ |
| 12 | 12 | ||
| 13 | #include <stdio.h> | 13 | #include <stdio.h> |
| 14 | 14 | ||
| 15 | void ir_print(CodeGen *codegen, FILE *f, IrExecutable *executable, int indent_size); | 15 | void ir_print(CodeGen *codegen, FILE *f, IrExecutable *executable, int indent_size, size_t pass_num); |
| 16 | void ir_print_instruction(CodeGen *codegen, FILE *f, IrInstruction *instruction, int indent_size); | 16 | void ir_print_instruction(CodeGen *codegen, FILE *f, IrInstruction *instruction, int indent_size, size_t pass_num); |
| 17 | 17 | ||
| 18 | #endif | 18 | #endif |
src/os.cpp+15-15| ... | @@ -1125,27 +1125,29 @@ Error os_get_cwd(Buf *out_cwd) { | ... | @@ -1125,27 +1125,29 @@ Error os_get_cwd(Buf *out_cwd) { |
| 1125 | #endif | 1125 | #endif |
| 1126 | } | 1126 | } |
| 1127 | 1127 | ||
| 1128 | #if defined(ZIG_OS_WINDOWS) | ||
| 1128 | #define is_wprefix(s, prefix) \ | 1129 | #define is_wprefix(s, prefix) \ |
| 1129 | (wcsncmp((s), (prefix), sizeof(prefix) / sizeof(WCHAR) - 1) == 0) | 1130 | (wcsncmp((s), (prefix), sizeof(prefix) / sizeof(WCHAR) - 1) == 0) |
| 1130 | bool ATTRIBUTE_MUST_USE os_is_cygwin_pty(int fd) { | 1131 | static bool is_stderr_cyg_pty(void) { |
| 1131 | #if defined(ZIG_OS_WINDOWS) | 1132 | HANDLE stderr_handle = GetStdHandle(STD_ERROR_HANDLE); |
| 1132 | HANDLE handle = (HANDLE)_get_osfhandle(fd); | 1133 | if (stderr_handle == INVALID_HANDLE_VALUE) |
| 1133 | |||
| 1134 | // Cygwin/msys's pty is a pipe. | ||
| 1135 | if (handle == INVALID_HANDLE_VALUE || GetFileType(handle) != FILE_TYPE_PIPE) { | ||
| 1136 | return false; | 1134 | return false; |
| 1137 | } | ||
| 1138 | 1135 | ||
| 1139 | int size = sizeof(FILE_NAME_INFO) + sizeof(WCHAR) * MAX_PATH; | 1136 | int size = sizeof(FILE_NAME_INFO) + sizeof(WCHAR) * MAX_PATH; |
| 1137 | FILE_NAME_INFO *nameinfo; | ||
| 1140 | WCHAR *p = NULL; | 1138 | WCHAR *p = NULL; |
| 1141 | 1139 | ||
| 1142 | FILE_NAME_INFO *nameinfo = (FILE_NAME_INFO *)allocate<char>(size); | 1140 | // Cygwin/msys's pty is a pipe. |
| 1141 | if (GetFileType(stderr_handle) != FILE_TYPE_PIPE) { | ||
| 1142 | return 0; | ||
| 1143 | } | ||
| 1144 | nameinfo = (FILE_NAME_INFO *)allocate<char>(size); | ||
| 1143 | if (nameinfo == NULL) { | 1145 | if (nameinfo == NULL) { |
| 1144 | return false; | 1146 | return 0; |
| 1145 | } | 1147 | } |
| 1146 | // Check the name of the pipe: | 1148 | // Check the name of the pipe: |
| 1147 | // '\{cygwin,msys}-XXXXXXXXXXXXXXXX-ptyN-{from,to}-master' | 1149 | // '\{cygwin,msys}-XXXXXXXXXXXXXXXX-ptyN-{from,to}-master' |
| 1148 | if (GetFileInformationByHandleEx(handle, FileNameInfo, nameinfo, size)) { | 1150 | if (GetFileInformationByHandleEx(stderr_handle, FileNameInfo, nameinfo, size)) { |
| 1149 | nameinfo->FileName[nameinfo->FileNameLength / sizeof(WCHAR)] = L'\0'; | 1151 | nameinfo->FileName[nameinfo->FileNameLength / sizeof(WCHAR)] = L'\0'; |
| 1150 | p = nameinfo->FileName; | 1152 | p = nameinfo->FileName; |
| 1151 | if (is_wprefix(p, L"\\cygwin-")) { /* Cygwin */ | 1153 | if (is_wprefix(p, L"\\cygwin-")) { /* Cygwin */ |
| ... | @@ -1178,14 +1180,12 @@ bool ATTRIBUTE_MUST_USE os_is_cygwin_pty(int fd) { | ... | @@ -1178,14 +1180,12 @@ bool ATTRIBUTE_MUST_USE os_is_cygwin_pty(int fd) { |
| 1178 | } | 1180 | } |
| 1179 | free(nameinfo); | 1181 | free(nameinfo); |
| 1180 | return (p != NULL); | 1182 | return (p != NULL); |
| 1181 | #else | ||
| 1182 | return false; | ||
| 1183 | #endif | ||
| 1184 | } | 1183 | } |
| 1184 | #endif | ||
| 1185 | 1185 | ||
| 1186 | bool os_stderr_tty(void) { | 1186 | bool os_stderr_tty(void) { |
| 1187 | #if defined(ZIG_OS_WINDOWS) | 1187 | #if defined(ZIG_OS_WINDOWS) |
| 1188 | return _isatty(fileno(stderr)) != 0 || os_is_cygwin_pty(fileno(stderr)); | 1188 | return _isatty(_fileno(stderr)) != 0 || is_stderr_cyg_pty(); |
| 1189 | #elif defined(ZIG_OS_POSIX) | 1189 | #elif defined(ZIG_OS_POSIX) |
| 1190 | return isatty(STDERR_FILENO) != 0; | 1190 | return isatty(STDERR_FILENO) != 0; |
| 1191 | #else | 1191 | #else |
| ... | @@ -1486,7 +1486,7 @@ WORD original_console_attributes = FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_BL | ... | @@ -1486,7 +1486,7 @@ WORD original_console_attributes = FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_BL |
| 1486 | 1486 | ||
| 1487 | void os_stderr_set_color(TermColor color) { | 1487 | void os_stderr_set_color(TermColor color) { |
| 1488 | #if defined(ZIG_OS_WINDOWS) | 1488 | #if defined(ZIG_OS_WINDOWS) |
| 1489 | if (os_stderr_tty()) { | 1489 | if (is_stderr_cyg_pty()) { |
| 1490 | set_color_posix(color); | 1490 | set_color_posix(color); |
| 1491 | return; | 1491 | return; |
| 1492 | } | 1492 | } |
src/os.hpp-8| ... | @@ -11,7 +11,6 @@ | ... | @@ -11,7 +11,6 @@ |
| 11 | #include "list.hpp" | 11 | #include "list.hpp" |
| 12 | #include "buffer.hpp" | 12 | #include "buffer.hpp" |
| 13 | #include "error.hpp" | 13 | #include "error.hpp" |
| 14 | #include "target.hpp" | ||
| 15 | #include "zig_llvm.h" | 14 | #include "zig_llvm.h" |
| 16 | #include "windows_sdk.h" | 15 | #include "windows_sdk.h" |
| 17 | 16 | ||
| ... | @@ -89,11 +88,6 @@ struct Termination { | ... | @@ -89,11 +88,6 @@ struct Termination { |
| 89 | #define OsFile int | 88 | #define OsFile int |
| 90 | #endif | 89 | #endif |
| 91 | 90 | ||
| 92 | #if defined(ZIG_OS_WINDOWS) | ||
| 93 | #undef fileno | ||
| 94 | #define fileno _fileno | ||
| 95 | #endif | ||
| 96 | |||
| 97 | struct OsTimeStamp { | 91 | struct OsTimeStamp { |
| 98 | uint64_t sec; | 92 | uint64_t sec; |
| 99 | uint64_t nsec; | 93 | uint64_t nsec; |
| ... | @@ -158,8 +152,6 @@ Error ATTRIBUTE_MUST_USE os_get_win32_ucrt_include_path(ZigWindowsSDK *sdk, Buf | ... | @@ -158,8 +152,6 @@ Error ATTRIBUTE_MUST_USE os_get_win32_ucrt_include_path(ZigWindowsSDK *sdk, Buf |
| 158 | Error ATTRIBUTE_MUST_USE os_get_win32_ucrt_lib_path(ZigWindowsSDK *sdk, Buf *output_buf, ZigLLVM_ArchType platform_type); | 152 | Error ATTRIBUTE_MUST_USE os_get_win32_ucrt_lib_path(ZigWindowsSDK *sdk, Buf *output_buf, ZigLLVM_ArchType platform_type); |
| 159 | Error ATTRIBUTE_MUST_USE os_get_win32_kern32_path(ZigWindowsSDK *sdk, Buf *output_buf, ZigLLVM_ArchType platform_type); | 153 | Error ATTRIBUTE_MUST_USE os_get_win32_kern32_path(ZigWindowsSDK *sdk, Buf *output_buf, ZigLLVM_ArchType platform_type); |
| 160 | 154 | ||
| 161 | bool ATTRIBUTE_MUST_USE os_is_cygwin_pty(int fd); | ||
| 162 | |||
| 163 | Error ATTRIBUTE_MUST_USE os_self_exe_shared_libs(ZigList<Buf *> &paths); | 155 | Error ATTRIBUTE_MUST_USE os_self_exe_shared_libs(ZigList<Buf *> &paths); |
| 164 | 156 | ||
| 165 | #endif | 157 | #endif |
src/parser.cpp+1-1| ... | @@ -2075,7 +2075,7 @@ static AstNode *ast_parse_param_decl(ParseContext *pc) { | ... | @@ -2075,7 +2075,7 @@ static AstNode *ast_parse_param_decl(ParseContext *pc) { |
| 2075 | res->column = first->start_column; | 2075 | res->column = first->start_column; |
| 2076 | res->data.param_decl.name = token_buf(name); | 2076 | res->data.param_decl.name = token_buf(name); |
| 2077 | res->data.param_decl.is_noalias = first->id == TokenIdKeywordNoAlias; | 2077 | res->data.param_decl.is_noalias = first->id == TokenIdKeywordNoAlias; |
| 2078 | res->data.param_decl.is_inline = first->id == TokenIdKeywordCompTime; | 2078 | res->data.param_decl.is_comptime = first->id == TokenIdKeywordCompTime; |
| 2079 | return res; | 2079 | return res; |
| 2080 | } | 2080 | } |
| 2081 | 2081 |
src/target.cpp+1-14| ... | @@ -491,16 +491,6 @@ Error target_parse_glibc_version(ZigGLibCVersion *glibc_ver, const char *text) { | ... | @@ -491,16 +491,6 @@ Error target_parse_glibc_version(ZigGLibCVersion *glibc_ver, const char *text) { |
| 491 | return ErrorNone; | 491 | return ErrorNone; |
| 492 | } | 492 | } |
| 493 | 493 | ||
| 494 | static ZigLLVM_EnvironmentType target_get_win32_abi() { | ||
| 495 | FILE* files[] = { stdin, stdout, stderr, nullptr }; | ||
| 496 | for (int i = 0; files[i] != nullptr; i++) { | ||
| 497 | if (os_is_cygwin_pty(fileno(files[i]))) { | ||
| 498 | return ZigLLVM_GNU; | ||
| 499 | } | ||
| 500 | } | ||
| 501 | return ZigLLVM_MSVC; | ||
| 502 | } | ||
| 503 | |||
| 504 | void get_native_target(ZigTarget *target) { | 494 | void get_native_target(ZigTarget *target) { |
| 505 | // first zero initialize | 495 | // first zero initialize |
| 506 | *target = {}; | 496 | *target = {}; |
| ... | @@ -515,9 +505,6 @@ void get_native_target(ZigTarget *target) { | ... | @@ -515,9 +505,6 @@ void get_native_target(ZigTarget *target) { |
| 515 | &target->abi, | 505 | &target->abi, |
| 516 | &oformat); | 506 | &oformat); |
| 517 | target->os = get_zig_os_type(os_type); | 507 | target->os = get_zig_os_type(os_type); |
| 518 | if (target->os == OsWindows) { | ||
| 519 | target->abi = target_get_win32_abi(); | ||
| 520 | } | ||
| 521 | target->is_native = true; | 508 | target->is_native = true; |
| 522 | if (target->abi == ZigLLVM_UnknownEnvironment) { | 509 | if (target->abi == ZigLLVM_UnknownEnvironment) { |
| 523 | target->abi = target_default_abi(target->arch, target->os); | 510 | target->abi = target_default_abi(target->arch, target->os); |
| ... | @@ -1614,7 +1601,7 @@ ZigLLVM_EnvironmentType target_default_abi(ZigLLVM_ArchType arch, Os os) { | ... | @@ -1614,7 +1601,7 @@ ZigLLVM_EnvironmentType target_default_abi(ZigLLVM_ArchType arch, Os os) { |
| 1614 | return ZigLLVM_GNU; | 1601 | return ZigLLVM_GNU; |
| 1615 | case OsUefi: | 1602 | case OsUefi: |
| 1616 | case OsWindows: | 1603 | case OsWindows: |
| 1617 | return ZigLLVM_MSVC; | 1604 | return ZigLLVM_MSVC; |
| 1618 | case OsLinux: | 1605 | case OsLinux: |
| 1619 | case OsWASI: | 1606 | case OsWASI: |
| 1620 | return ZigLLVM_Musl; | 1607 | return ZigLLVM_Musl; |
std/mem.zig+9-1| ... | @@ -117,7 +117,15 @@ pub const Allocator = struct { | ... | @@ -117,7 +117,15 @@ pub const Allocator = struct { |
| 117 | const byte_slice = try self.reallocFn(self, ([*]u8)(undefined)[0..0], undefined, byte_count, a); | 117 | const byte_slice = try self.reallocFn(self, ([*]u8)(undefined)[0..0], undefined, byte_count, a); |
| 118 | assert(byte_slice.len == byte_count); | 118 | assert(byte_slice.len == byte_count); |
| 119 | @memset(byte_slice.ptr, undefined, byte_slice.len); | 119 | @memset(byte_slice.ptr, undefined, byte_slice.len); |
| 120 | return @bytesToSlice(T, @alignCast(a, byte_slice)); | 120 | if (alignment == null) { |
| 121 | // TODO This is a workaround for zig not being able to successfully do | ||
| 122 | // @bytesToSlice(T, @alignCast(a, byte_slice)) without resolving alignment of T, | ||
| 123 | // which causes a circular dependency in async functions which try to heap-allocate | ||
| 124 | // their own frame with @Frame(func). | ||
| 125 | return @intToPtr([*]T, @ptrToInt(byte_slice.ptr))[0..n]; | ||
| 126 | } else { | ||
| 127 | return @bytesToSlice(T, @alignCast(a, byte_slice)); | ||
| 128 | } | ||
| 121 | } | 129 | } |
| 122 | 130 | ||
| 123 | /// This function requests a new byte size for an existing allocation, | 131 | /// This function requests a new byte size for an existing allocation, |
std/os/windows.zig+4-3| ... | @@ -65,7 +65,7 @@ pub const CreateFileError = error{ | ... | @@ -65,7 +65,7 @@ pub const CreateFileError = error{ |
| 65 | InvalidUtf8, | 65 | InvalidUtf8, |
| 66 | 66 | ||
| 67 | /// On Windows, file paths cannot contain these characters: | 67 | /// On Windows, file paths cannot contain these characters: |
| 68 | /// '*', '?', '"', '<', '>', '|', and '/' (when the ABI is not GNU) | 68 | /// '/', '*', '?', '"', '<', '>', '|' |
| 69 | BadPathName, | 69 | BadPathName, |
| 70 | 70 | ||
| 71 | Unexpected, | 71 | Unexpected, |
| ... | @@ -836,10 +836,11 @@ pub fn sliceToPrefixedSuffixedFileW(s: []const u8, comptime suffix: []const u16) | ... | @@ -836,10 +836,11 @@ pub fn sliceToPrefixedSuffixedFileW(s: []const u8, comptime suffix: []const u16) |
| 836 | // > converting the name to an NT-style name, except when using the "\\?\" | 836 | // > converting the name to an NT-style name, except when using the "\\?\" |
| 837 | // > prefix as detailed in the following sections. | 837 | // > prefix as detailed in the following sections. |
| 838 | // from https://docs.microsoft.com/en-us/windows/desktop/FileIO/naming-a-file#maximum-path-length-limitation | 838 | // from https://docs.microsoft.com/en-us/windows/desktop/FileIO/naming-a-file#maximum-path-length-limitation |
| 839 | // Because we want the larger maximum path length for absolute paths, we | ||
| 840 | // disallow forward slashes in zig std lib file functions on Windows. | ||
| 839 | for (s) |byte| { | 841 | for (s) |byte| { |
| 840 | switch (byte) { | 842 | switch (byte) { |
| 841 | '*', '?', '"', '<', '>', '|' => return error.BadPathName, | 843 | '/', '*', '?', '"', '<', '>', '|' => return error.BadPathName, |
| 842 | '/' => if (builtin.abi == .msvc) return error.BadPathName, | ||
| 843 | else => {}, | 844 | else => {}, |
| 844 | } | 845 | } |
| 845 | } | 846 | } |
std/special/compiler_rt/comparetf2.zig+7-6| ... | @@ -38,12 +38,14 @@ pub extern fn __letf2(a: f128, b: f128) c_int { | ... | @@ -38,12 +38,14 @@ pub extern fn __letf2(a: f128, b: f128) c_int { |
| 38 | 38 | ||
| 39 | // If at least one of a and b is positive, we get the same result comparing | 39 | // If at least one of a and b is positive, we get the same result comparing |
| 40 | // a and b as signed integers as we would with a floating-point compare. | 40 | // a and b as signed integers as we would with a floating-point compare. |
| 41 | return if ((aInt & bInt) >= 0) if (aInt < bInt) | 41 | return if ((aInt & bInt) >= 0) |
| 42 | LE_LESS | 42 | if (aInt < bInt) |
| 43 | else if (aInt == bInt) | 43 | LE_LESS |
| 44 | LE_EQUAL | 44 | else if (aInt == bInt) |
| 45 | LE_EQUAL | ||
| 46 | else | ||
| 47 | LE_GREATER | ||
| 45 | else | 48 | else |
| 46 | LE_GREATER else | ||
| 47 | // Otherwise, both are negative, so we need to flip the sense of the | 49 | // Otherwise, both are negative, so we need to flip the sense of the |
| 48 | // comparison to get the correct result. (This assumes a twos- or ones- | 50 | // comparison to get the correct result. (This assumes a twos- or ones- |
| 49 | // complement integer representation; if integers are represented in a | 51 | // complement integer representation; if integers are represented in a |
| ... | @@ -73,7 +75,6 @@ pub extern fn __getf2(a: f128, b: f128) c_int { | ... | @@ -73,7 +75,6 @@ pub extern fn __getf2(a: f128, b: f128) c_int { |
| 73 | 75 | ||
| 74 | if (aAbs > infRep or bAbs > infRep) return GE_UNORDERED; | 76 | if (aAbs > infRep or bAbs > infRep) return GE_UNORDERED; |
| 75 | if ((aAbs | bAbs) == 0) return GE_EQUAL; | 77 | if ((aAbs | bAbs) == 0) return GE_EQUAL; |
| 76 | // zig fmt issue here, see https://github.com/ziglang/zig/issues/2661 | ||
| 77 | return if ((aInt & bInt) >= 0) | 78 | return if ((aInt & bInt) >= 0) |
| 78 | if (aInt < bInt) | 79 | if (aInt < bInt) |
| 79 | GE_LESS | 80 | GE_LESS |
std/zig/parser_test.zig+21| ... | @@ -482,6 +482,27 @@ test "zig fmt: if-else with comment before else" { | ... | @@ -482,6 +482,27 @@ test "zig fmt: if-else with comment before else" { |
| 482 | ); | 482 | ); |
| 483 | } | 483 | } |
| 484 | 484 | ||
| 485 | test "zig fmt: if nested" { | ||
| 486 | try testCanonical( | ||
| 487 | \\pub fn foo() void { | ||
| 488 | \\ return if ((aInt & bInt) >= 0) | ||
| 489 | \\ if (aInt < bInt) | ||
| 490 | \\ GE_LESS | ||
| 491 | \\ else if (aInt == bInt) | ||
| 492 | \\ GE_EQUAL | ||
| 493 | \\ else | ||
| 494 | \\ GE_GREATER | ||
| 495 | \\ else if (aInt > bInt) | ||
| 496 | \\ GE_LESS | ||
| 497 | \\ else if (aInt == bInt) | ||
| 498 | \\ GE_EQUAL | ||
| 499 | \\ else | ||
| 500 | \\ GE_GREATER; | ||
| 501 | \\} | ||
| 502 | \\ | ||
| 503 | ); | ||
| 504 | } | ||
| 505 | |||
| 485 | test "zig fmt: respect line breaks in if-else" { | 506 | test "zig fmt: respect line breaks in if-else" { |
| 486 | try testCanonical( | 507 | try testCanonical( |
| 487 | \\comptime { | 508 | \\comptime { |
std/zig/render.zig+4-2| ... | @@ -276,7 +276,6 @@ fn renderTopLevelDecl(allocator: *mem.Allocator, stream: var, tree: *ast.Tree, i | ... | @@ -276,7 +276,6 @@ fn renderTopLevelDecl(allocator: *mem.Allocator, stream: var, tree: *ast.Tree, i |
| 276 | } else { | 276 | } else { |
| 277 | try renderExpression(allocator, stream, tree, indent, start_col, field.type_expr.?, Space.Comma); // type, | 277 | try renderExpression(allocator, stream, tree, indent, start_col, field.type_expr.?, Space.Comma); // type, |
| 278 | } | 278 | } |
| 279 | |||
| 280 | } else if (field.type_expr == null and field.value_expr != null) { | 279 | } else if (field.type_expr == null and field.value_expr != null) { |
| 281 | try renderToken(tree, stream, field.name_token, indent, start_col, Space.Space); // name | 280 | try renderToken(tree, stream, field.name_token, indent, start_col, Space.Space); // name |
| 282 | try renderToken(tree, stream, tree.nextToken(field.name_token), indent, start_col, Space.Space); // = | 281 | try renderToken(tree, stream, tree.nextToken(field.name_token), indent, start_col, Space.Space); // = |
| ... | @@ -1521,9 +1520,12 @@ fn renderExpression( | ... | @@ -1521,9 +1520,12 @@ fn renderExpression( |
| 1521 | 1520 | ||
| 1522 | try renderExpression(allocator, stream, tree, indent, start_col, if_node.condition, Space.None); // condition | 1521 | try renderExpression(allocator, stream, tree, indent, start_col, if_node.condition, Space.None); // condition |
| 1523 | 1522 | ||
| 1523 | const body_is_if_block = if_node.body.id == ast.Node.Id.If; | ||
| 1524 | const body_is_block = nodeIsBlock(if_node.body); | 1524 | const body_is_block = nodeIsBlock(if_node.body); |
| 1525 | 1525 | ||
| 1526 | if (body_is_block) { | 1526 | if (body_is_if_block) { |
| 1527 | try renderExtraNewline(tree, stream, start_col, if_node.body); | ||
| 1528 | } else if (body_is_block) { | ||
| 1527 | const after_rparen_space = if (if_node.payload == null) Space.BlockStart else Space.Space; | 1529 | const after_rparen_space = if (if_node.payload == null) Space.BlockStart else Space.Space; |
| 1528 | try renderToken(tree, stream, rparen, indent, start_col, after_rparen_space); // ) | 1530 | try renderToken(tree, stream, rparen, indent, start_col, after_rparen_space); // ) |
| 1529 | 1531 |
test/compile_errors.zig+18| ... | @@ -2,6 +2,22 @@ const tests = @import("tests.zig"); | ... | @@ -2,6 +2,22 @@ const tests = @import("tests.zig"); |
| 2 | const builtin = @import("builtin"); | 2 | const builtin = @import("builtin"); |
| 3 | 3 | ||
| 4 | pub fn addCases(cases: *tests.CompileErrorContext) void { | 4 | pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 5 | cases.add( | ||
| 6 | "wrong type for result ptr to @asyncCall", | ||
| 7 | \\export fn entry() void { | ||
| 8 | \\ _ = async amain(); | ||
| 9 | \\} | ||
| 10 | \\fn amain() i32 { | ||
| 11 | \\ var frame: @Frame(foo) = undefined; | ||
| 12 | \\ return await @asyncCall(&frame, false, foo); | ||
| 13 | \\} | ||
| 14 | \\fn foo() i32 { | ||
| 15 | \\ return 1234; | ||
| 16 | \\} | ||
| 17 | , | ||
| 18 | "tmp.zig:6:37: error: expected type '*i32', found 'bool'", | ||
| 19 | ); | ||
| 20 | |||
| 5 | cases.add( | 21 | cases.add( |
| 6 | "struct depends on itself via optional field", | 22 | "struct depends on itself via optional field", |
| 7 | \\const LhsExpr = struct { | 23 | \\const LhsExpr = struct { |
| ... | @@ -1051,6 +1067,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { | ... | @@ -1051,6 +1067,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 1051 | \\const Foo = struct {}; | 1067 | \\const Foo = struct {}; |
| 1052 | \\export fn a() void { | 1068 | \\export fn a() void { |
| 1053 | \\ const T = [*c]Foo; | 1069 | \\ const T = [*c]Foo; |
| 1070 | \\ var t: T = undefined; | ||
| 1054 | \\} | 1071 | \\} |
| 1055 | , | 1072 | , |
| 1056 | "tmp.zig:3:19: error: C pointers cannot point to non-C-ABI-compatible type 'Foo'", | 1073 | "tmp.zig:3:19: error: C pointers cannot point to non-C-ABI-compatible type 'Foo'", |
| ... | @@ -2290,6 +2307,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { | ... | @@ -2290,6 +2307,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 2290 | "error union operator with non error set LHS", | 2307 | "error union operator with non error set LHS", |
| 2291 | \\comptime { | 2308 | \\comptime { |
| 2292 | \\ const z = i32!i32; | 2309 | \\ const z = i32!i32; |
| 2310 | \\ var x: z = undefined; | ||
| 2293 | \\} | 2311 | \\} |
| 2294 | , | 2312 | , |
| 2295 | "tmp.zig:2:15: error: expected error set type, found type 'i32'", | 2313 | "tmp.zig:2:15: error: expected error set type, found type 'i32'", |
test/stage1/behavior/async_fn.zig+179-2| ... | @@ -331,8 +331,9 @@ test "async fn with inferred error set" { | ... | @@ -331,8 +331,9 @@ test "async fn with inferred error set" { |
| 331 | 331 | ||
| 332 | fn doTheTest() void { | 332 | fn doTheTest() void { |
| 333 | var frame: [1]@Frame(middle) = undefined; | 333 | var frame: [1]@Frame(middle) = undefined; |
| 334 | var result: anyerror!void = undefined; | 334 | var fn_ptr = middle; |
| 335 | _ = @asyncCall(@sliceToBytes(frame[0..]), &result, middle); | 335 | var result: @typeOf(fn_ptr).ReturnType.ErrorSet!void = undefined; |
| 336 | _ = @asyncCall(@sliceToBytes(frame[0..]), &result, fn_ptr); | ||
| 336 | resume global_frame; | 337 | resume global_frame; |
| 337 | std.testing.expectError(error.Fail, result); | 338 | std.testing.expectError(error.Fail, result); |
| 338 | } | 339 | } |
| ... | @@ -819,6 +820,34 @@ test "struct parameter to async function is copied to the frame" { | ... | @@ -819,6 +820,34 @@ test "struct parameter to async function is copied to the frame" { |
| 819 | } | 820 | } |
| 820 | 821 | ||
| 821 | test "cast fn to async fn when it is inferred to be async" { | 822 | test "cast fn to async fn when it is inferred to be async" { |
| 823 | const S = struct { | ||
| 824 | var frame: anyframe = undefined; | ||
| 825 | var ok = false; | ||
| 826 | |||
| 827 | fn doTheTest() void { | ||
| 828 | var ptr: async fn () i32 = undefined; | ||
| 829 | ptr = func; | ||
| 830 | var buf: [100]u8 align(16) = undefined; | ||
| 831 | var result: i32 = undefined; | ||
| 832 | const f = @asyncCall(&buf, &result, ptr); | ||
| 833 | _ = await f; | ||
| 834 | expect(result == 1234); | ||
| 835 | ok = true; | ||
| 836 | } | ||
| 837 | |||
| 838 | fn func() i32 { | ||
| 839 | suspend { | ||
| 840 | frame = @frame(); | ||
| 841 | } | ||
| 842 | return 1234; | ||
| 843 | } | ||
| 844 | }; | ||
| 845 | _ = async S.doTheTest(); | ||
| 846 | resume S.frame; | ||
| 847 | expect(S.ok); | ||
| 848 | } | ||
| 849 | |||
| 850 | test "cast fn to async fn when it is inferred to be async, awaited directly" { | ||
| 822 | const S = struct { | 851 | const S = struct { |
| 823 | var frame: anyframe = undefined; | 852 | var frame: anyframe = undefined; |
| 824 | var ok = false; | 853 | var ok = false; |
| ... | @@ -854,3 +883,151 @@ test "await does not force async if callee is blocking" { | ... | @@ -854,3 +883,151 @@ test "await does not force async if callee is blocking" { |
| 854 | var x = async S.simple(); | 883 | var x = async S.simple(); |
| 855 | expect(await x == 1234); | 884 | expect(await x == 1234); |
| 856 | } | 885 | } |
| 886 | |||
| 887 | test "recursive async function" { | ||
| 888 | expect(recursiveAsyncFunctionTest(false).doTheTest() == 55); | ||
| 889 | expect(recursiveAsyncFunctionTest(true).doTheTest() == 55); | ||
| 890 | } | ||
| 891 | |||
| 892 | fn recursiveAsyncFunctionTest(comptime suspending_implementation: bool) type { | ||
| 893 | return struct { | ||
| 894 | fn fib(allocator: *std.mem.Allocator, x: u32) error{OutOfMemory}!u32 { | ||
| 895 | if (x <= 1) return x; | ||
| 896 | |||
| 897 | if (suspending_implementation) { | ||
| 898 | suspend { | ||
| 899 | resume @frame(); | ||
| 900 | } | ||
| 901 | } | ||
| 902 | |||
| 903 | const f1 = try allocator.create(@Frame(fib)); | ||
| 904 | defer allocator.destroy(f1); | ||
| 905 | |||
| 906 | const f2 = try allocator.create(@Frame(fib)); | ||
| 907 | defer allocator.destroy(f2); | ||
| 908 | |||
| 909 | f1.* = async fib(allocator, x - 1); | ||
| 910 | var f1_awaited = false; | ||
| 911 | errdefer if (!f1_awaited) { | ||
| 912 | _ = await f1; | ||
| 913 | }; | ||
| 914 | |||
| 915 | f2.* = async fib(allocator, x - 2); | ||
| 916 | var f2_awaited = false; | ||
| 917 | errdefer if (!f2_awaited) { | ||
| 918 | _ = await f2; | ||
| 919 | }; | ||
| 920 | |||
| 921 | var sum: u32 = 0; | ||
| 922 | |||
| 923 | f1_awaited = true; | ||
| 924 | const result_f1 = await f1; // TODO https://github.com/ziglang/zig/issues/3077 | ||
| 925 | sum += try result_f1; | ||
| 926 | |||
| 927 | f2_awaited = true; | ||
| 928 | const result_f2 = await f2; // TODO https://github.com/ziglang/zig/issues/3077 | ||
| 929 | sum += try result_f2; | ||
| 930 | |||
| 931 | return sum; | ||
| 932 | } | ||
| 933 | |||
| 934 | fn doTheTest() u32 { | ||
| 935 | if (suspending_implementation) { | ||
| 936 | var result: u32 = undefined; | ||
| 937 | _ = async amain(&result); | ||
| 938 | return result; | ||
| 939 | } else { | ||
| 940 | return fib(std.heap.direct_allocator, 10) catch unreachable; | ||
| 941 | } | ||
| 942 | } | ||
| 943 | |||
| 944 | fn amain(result: *u32) void { | ||
| 945 | var x = async fib(std.heap.direct_allocator, 10); | ||
| 946 | const res = await x; // TODO https://github.com/ziglang/zig/issues/3077 | ||
| 947 | result.* = res catch unreachable; | ||
| 948 | } | ||
| 949 | }; | ||
| 950 | } | ||
| 951 | |||
| 952 | test "@asyncCall with comptime-known function, but not awaited directly" { | ||
| 953 | const S = struct { | ||
| 954 | var global_frame: anyframe = undefined; | ||
| 955 | |||
| 956 | fn doTheTest() void { | ||
| 957 | var frame: [1]@Frame(middle) = undefined; | ||
| 958 | var result: @typeOf(middle).ReturnType.ErrorSet!void = undefined; | ||
| 959 | _ = @asyncCall(@sliceToBytes(frame[0..]), &result, middle); | ||
| 960 | resume global_frame; | ||
| 961 | std.testing.expectError(error.Fail, result); | ||
| 962 | } | ||
| 963 | |||
| 964 | async fn middle() !void { | ||
| 965 | var f = async middle2(); | ||
| 966 | return await f; | ||
| 967 | } | ||
| 968 | |||
| 969 | fn middle2() !void { | ||
| 970 | return failing(); | ||
| 971 | } | ||
| 972 | |||
| 973 | fn failing() !void { | ||
| 974 | global_frame = @frame(); | ||
| 975 | suspend; | ||
| 976 | return error.Fail; | ||
| 977 | } | ||
| 978 | }; | ||
| 979 | S.doTheTest(); | ||
| 980 | } | ||
| 981 | |||
| 982 | test "@asyncCall with actual frame instead of byte buffer" { | ||
| 983 | const S = struct { | ||
| 984 | fn func() i32 { | ||
| 985 | suspend; | ||
| 986 | return 1234; | ||
| 987 | } | ||
| 988 | }; | ||
| 989 | var frame: @Frame(S.func) = undefined; | ||
| 990 | var result: i32 = undefined; | ||
| 991 | const ptr = @asyncCall(&frame, &result, S.func); | ||
| 992 | resume ptr; | ||
| 993 | expect(result == 1234); | ||
| 994 | } | ||
| 995 | |||
| 996 | test "@asyncCall using the result location inside the frame" { | ||
| 997 | const S = struct { | ||
| 998 | async fn simple2(y: *i32) i32 { | ||
| 999 | defer y.* += 2; | ||
| 1000 | y.* += 1; | ||
| 1001 | suspend; | ||
| 1002 | return 1234; | ||
| 1003 | } | ||
| 1004 | fn getAnswer(f: anyframe->i32, out: *i32) void { | ||
| 1005 | var res = await f; // TODO https://github.com/ziglang/zig/issues/3077 | ||
| 1006 | out.* = res; | ||
| 1007 | } | ||
| 1008 | }; | ||
| 1009 | var data: i32 = 1; | ||
| 1010 | const Foo = struct { | ||
| 1011 | bar: async fn (*i32) i32, | ||
| 1012 | }; | ||
| 1013 | var foo = Foo{ .bar = S.simple2 }; | ||
| 1014 | var bytes: [64]u8 align(16) = undefined; | ||
| 1015 | const f = @asyncCall(&bytes, {}, foo.bar, &data); | ||
| 1016 | comptime expect(@typeOf(f) == anyframe->i32); | ||
| 1017 | expect(data == 2); | ||
| 1018 | resume f; | ||
| 1019 | expect(data == 4); | ||
| 1020 | _ = async S.getAnswer(f, &data); | ||
| 1021 | expect(data == 1234); | ||
| 1022 | } | ||
| 1023 | |||
| 1024 | test "@typeOf an async function call of generic fn with error union type" { | ||
| 1025 | const S = struct { | ||
| 1026 | fn func(comptime x: var) anyerror!i32 { | ||
| 1027 | const T = @typeOf(async func(x)); | ||
| 1028 | comptime expect(T == @typeOf(@frame()).Child); | ||
| 1029 | return undefined; | ||
| 1030 | } | ||
| 1031 | }; | ||
| 1032 | _ = async S.func(i32); | ||
| 1033 | } |
test/stage1/behavior/sizeof_and_typeof.zig+26| ... | @@ -89,3 +89,29 @@ test "@sizeOf(T) == 0 doesn't force resolving struct size" { | ... | @@ -89,3 +89,29 @@ test "@sizeOf(T) == 0 doesn't force resolving struct size" { |
| 89 | expect(@sizeOf(S.Foo) == 4); | 89 | expect(@sizeOf(S.Foo) == 4); |
| 90 | expect(@sizeOf(S.Bar) == 8); | 90 | expect(@sizeOf(S.Bar) == 8); |
| 91 | } | 91 | } |
| 92 | |||
| 93 | test "@typeOf() has no runtime side effects" { | ||
| 94 | const S = struct { | ||
| 95 | fn foo(comptime T: type, ptr: *T) T { | ||
| 96 | ptr.* += 1; | ||
| 97 | return ptr.*; | ||
| 98 | } | ||
| 99 | }; | ||
| 100 | var data: i32 = 0; | ||
| 101 | const T = @typeOf(S.foo(i32, &data)); | ||
| 102 | comptime expect(T == i32); | ||
| 103 | expect(data == 0); | ||
| 104 | } | ||
| 105 | |||
| 106 | test "branching logic inside @typeOf" { | ||
| 107 | const S = struct { | ||
| 108 | var data: i32 = 0; | ||
| 109 | fn foo() anyerror!i32 { | ||
| 110 | data += 1; | ||
| 111 | return undefined; | ||
| 112 | } | ||
| 113 | }; | ||
| 114 | const T = @typeOf(S.foo() catch undefined); | ||
| 115 | comptime expect(T == i32); | ||
| 116 | expect(S.data == 0); | ||
| 117 | } |