diff --git a/CMakeLists.txt b/CMakeLists.txt index 024a06b425..b58f714a22 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -292,7 +292,7 @@ set(ZIG0_SOURCES set(STAGE1_SOURCES "${CMAKE_SOURCE_DIR}/src/stage1/analyze.cpp" - "${CMAKE_SOURCE_DIR}/src/stage1/ast_render.cpp" + "${CMAKE_SOURCE_DIR}/src/stage1/astgen.cpp" "${CMAKE_SOURCE_DIR}/src/stage1/bigfloat.cpp" "${CMAKE_SOURCE_DIR}/src/stage1/bigint.cpp" "${CMAKE_SOURCE_DIR}/src/stage1/buffer.cpp" @@ -307,11 +307,11 @@ set(STAGE1_SOURCES "${CMAKE_SOURCE_DIR}/src/stage1/os.cpp" "${CMAKE_SOURCE_DIR}/src/stage1/parser.cpp" "${CMAKE_SOURCE_DIR}/src/stage1/range_set.cpp" + "${CMAKE_SOURCE_DIR}/src/stage1/softfloat_ext.cpp" "${CMAKE_SOURCE_DIR}/src/stage1/stage1.cpp" "${CMAKE_SOURCE_DIR}/src/stage1/target.cpp" "${CMAKE_SOURCE_DIR}/src/stage1/tokenizer.cpp" "${CMAKE_SOURCE_DIR}/src/stage1/util.cpp" - "${CMAKE_SOURCE_DIR}/src/stage1/softfloat_ext.cpp" ) set(OPTIMIZED_C_SOURCES "${CMAKE_SOURCE_DIR}/src/stage1/parse_f128.c" diff --git a/lib/std/zig/string_literal.zig b/lib/std/zig/string_literal.zig index 992affc829..b1dc53c47f 100644 --- a/lib/std/zig/string_literal.zig +++ b/lib/std/zig/string_literal.zig @@ -107,6 +107,7 @@ pub fn parseAppend(buf: *std.ArrayList(u8), bytes: []const u8) error{OutOfMemory const hex_str = slice[index + 2 .. index_end]; if (std.fmt.parseUnsigned(u32, hex_str, 16)) |uint| { if (uint <= 0x10ffff) { + // TODO this incorrectly depends on endianness try buf.appendSlice(std.mem.toBytes(uint)[0..]); state = State.Start; index = index_end; // loop-header increments diff --git a/src/stage1.zig b/src/stage1.zig index 1b7eadd1a8..f7cc6e2890 100644 --- a/src/stage1.zig +++ b/src/stage1.zig @@ -252,6 +252,8 @@ const Error = extern enum { ZigIsTheCCompiler, FileBusy, Locked, + InvalidCharacter, + UnicodePointTooLarge, }; // ABI warning diff --git a/src/stage1/all_types.hpp b/src/stage1/all_types.hpp index 88d10e9e6a..ad7a8cd5cb 100644 --- a/src/stage1/all_types.hpp +++ b/src/stage1/all_types.hpp @@ -670,7 +670,7 @@ enum NodeType { NodeTypeIntLiteral, NodeTypeStringLiteral, NodeTypeCharLiteral, - NodeTypeSymbol, + NodeTypeIdentifier, NodeTypePrefixOpExpr, NodeTypePointerType, NodeTypeFnCallExpr, @@ -710,6 +710,7 @@ enum NodeType { NodeTypeAwaitExpr, NodeTypeSuspend, NodeTypeAnyFrameType, + // main_token points to the identifier. NodeTypeEnumLiteral, NodeTypeAnyTypeField, }; @@ -733,7 +734,8 @@ struct AstNodeFnProto { AstNode *section_expr; // populated if the "callconv(S)" is present AstNode *callconv_expr; - Buf doc_comments; + + TokenIndex doc_comments; // This is set based only on the existence of a noinline or inline keyword. // This is then resolved to an is_noinline bool and (potentially .Inline) @@ -755,8 +757,8 @@ struct AstNodeFnDef { struct AstNodeParamDecl { Buf *name; AstNode *type; - Token *anytype_token; - Buf doc_comments; + TokenIndex doc_comments; + TokenIndex anytype_token; bool is_noalias; bool is_comptime; bool is_var_args; @@ -799,9 +801,9 @@ struct AstNodeVariableDeclaration { AstNode *align_expr; // populated if the "section(S)" is present AstNode *section_expr; - Token *threadlocal_tok; - Buf doc_comments; + TokenIndex doc_comments; + TokenIndex threadlocal_tok; VisibMod visib_mod; bool is_const; bool is_comptime; @@ -935,13 +937,14 @@ struct AstNodePrefixOpExpr { }; struct AstNodePointerType { - Token *star_token; + TokenIndex star_token; + TokenIndex allow_zero_token; + TokenIndex bit_offset_start; + TokenIndex host_int_bytes; + AstNode *sentinel; AstNode *align_expr; - BigInt *bit_offset_start; - BigInt *host_int_bytes; AstNode *op_expr; - Token *allow_zero_token; bool is_const; bool is_volatile; }; @@ -956,7 +959,7 @@ struct AstNodeArrayType { AstNode *sentinel; AstNode *child_type; AstNode *align_expr; - Token *allow_zero_token; + TokenIndex allow_zero_token; bool is_const; bool is_volatile; }; @@ -974,11 +977,11 @@ struct AstNodeIfBoolExpr { struct AstNodeTryExpr { Buf *var_symbol; - bool var_is_ptr; AstNode *target_node; AstNode *then_node; AstNode *else_node; Buf *err_symbol; + bool var_is_ptr; }; struct AstNodeTestExpr { @@ -993,12 +996,12 @@ struct AstNodeWhileExpr { Buf *name; AstNode *condition; Buf *var_symbol; - bool var_is_ptr; AstNode *continue_expr; AstNode *body; AstNode *else_node; Buf *err_symbol; bool is_inline; + bool var_is_ptr; }; struct AstNodeForExpr { @@ -1070,7 +1073,7 @@ struct AsmToken { }; struct AstNodeAsmExpr { - Token *volatile_token; + TokenIndex volatile_token; AstNode *asm_template; ZigList output_list; ZigList input_list; @@ -1094,7 +1097,7 @@ struct AstNodeContainerDecl { AstNode *init_arg_expr; // enum(T), struct(endianness), or union(T), or union(enum(T)) ZigList fields; ZigList decls; - Buf doc_comments; + TokenIndex doc_comments; ContainerKind kind; ContainerLayout layout; @@ -1103,7 +1106,7 @@ struct AstNodeContainerDecl { }; struct AstNodeErrorSetField { - Buf doc_comments; + TokenIndex doc_comments; AstNode *field_name; }; @@ -1118,28 +1121,8 @@ struct AstNodeStructField { AstNode *value; // populated if the "align(A)" is present AstNode *align_expr; - Buf doc_comments; - Token *comptime_token; -}; - -struct AstNodeStringLiteral { - Buf *buf; -}; - -struct AstNodeCharLiteral { - uint32_t value; -}; - -struct AstNodeFloatLiteral { - BigFloat *bigfloat; - - // overflow is true if when parsing the number, we discovered it would not - // fit without losing data in a double - bool overflow; -}; - -struct AstNodeIntLiteral { - BigInt *bigint; + TokenIndex doc_comments; + TokenIndex comptime_token; }; struct AstNodeStructValueField { @@ -1158,19 +1141,6 @@ struct AstNodeContainerInitExpr { ContainerInitKind kind; }; -struct AstNodeNullLiteral { -}; - -struct AstNodeUndefinedLiteral { -}; - -struct AstNodeThisLiteral { -}; - -struct AstNodeSymbolExpr { - Buf *symbol; -}; - struct AstNodeBoolLiteral { bool value; }; @@ -1188,13 +1158,6 @@ struct AstNodeContinueExpr { Buf *name; }; -struct AstNodeUnreachableExpr { -}; - - -struct AstNodeErrorType { -}; - struct AstNodeAwaitExpr { AstNode *expr; }; @@ -1207,16 +1170,10 @@ struct AstNodeAnyFrameType { AstNode *payload_type; // can be NULL }; -struct AstNodeEnumLiteral { - Token *period; - Token *identifier; -}; - struct AstNode { enum NodeType type; + TokenIndex main_token; bool already_traced_this_node; - size_t line; - size_t column; ZigType *owner; union { AstNodeFnDef fn_def; @@ -1252,30 +1209,19 @@ struct AstNode { AstNodePtrDerefExpr ptr_deref_expr; AstNodeContainerDecl container_decl; AstNodeStructField struct_field; - AstNodeStringLiteral string_literal; - AstNodeCharLiteral char_literal; - AstNodeFloatLiteral float_literal; - AstNodeIntLiteral int_literal; AstNodeContainerInitExpr container_init_expr; AstNodeStructValueField struct_val_field; - AstNodeNullLiteral null_literal; - AstNodeUndefinedLiteral undefined_literal; - AstNodeThisLiteral this_literal; - AstNodeSymbolExpr symbol_expr; AstNodeBoolLiteral bool_literal; AstNodeBreakExpr break_expr; AstNodeContinueExpr continue_expr; - AstNodeUnreachableExpr unreachable_expr; AstNodeArrayType array_type; AstNodeInferredArrayType inferred_array_type; - AstNodeErrorType error_type; AstNodeErrorSetDecl err_set_decl; AstNodeErrorSetField err_set_field; AstNodeResumeExpr resume_expr; AstNodeAwaitExpr await_expr; AstNodeSuspend suspend; AstNodeAnyFrameType anyframe_type; - AstNodeEnumLiteral enum_literal; } data; // This is a function for use in the debugger to print @@ -1409,9 +1355,11 @@ struct ZigPackage { struct RootStruct { ZigPackage *package; Buf *path; // relative to root_package->root_src_dir - ZigList *line_offsets; Buf *source_code; ZigLLVMDIFile *di_file; + size_t token_count; + TokenId *token_ids; + TokenLoc *token_locs; }; enum StructSpecial { diff --git a/src/stage1/analyze.cpp b/src/stage1/analyze.cpp index 581e34acfc..b675beb9e0 100644 --- a/src/stage1/analyze.cpp +++ b/src/stage1/analyze.cpp @@ -6,9 +6,9 @@ */ #include "analyze.hpp" -#include "ast_render.hpp" #include "codegen.hpp" #include "error.hpp" +#include "astgen.hpp" #include "ir.hpp" #include "ir_print.hpp" #include "os.hpp" @@ -41,41 +41,44 @@ static bool is_top_level_struct(ZigType *import) { return import->id == ZigTypeIdStruct && import->data.structure.root_struct != nullptr; } -static ErrorMsg *add_error_note_token(CodeGen *g, ErrorMsg *parent_msg, ZigType *owner, Token *token, Buf *msg) { +static ErrorMsg *add_error_note_token(CodeGen *g, ErrorMsg *parent_msg, ZigType *owner, + TokenIndex token, Buf *msg) +{ assert(is_top_level_struct(owner)); RootStruct *root_struct = owner->data.structure.root_struct; - - ErrorMsg *err = err_msg_create_with_line(root_struct->path, token->start_line, token->start_column, - root_struct->source_code, root_struct->line_offsets, msg); + uint32_t byte_offset = root_struct->token_locs[token].offset; + ErrorMsg *err = err_msg_create_with_offset(root_struct->path, byte_offset, + buf_ptr(root_struct->source_code), msg); err_msg_add_note(parent_msg, err); return err; } -ErrorMsg *add_token_error(CodeGen *g, ZigType *owner, Token *token, Buf *msg) { +ErrorMsg *add_token_error_offset(CodeGen *g, ZigType *owner, TokenIndex token, Buf *msg, + uint32_t bad_index) +{ assert(is_top_level_struct(owner)); RootStruct *root_struct = owner->data.structure.root_struct; - ErrorMsg *err = err_msg_create_with_line(root_struct->path, token->start_line, token->start_column, - root_struct->source_code, root_struct->line_offsets, msg); + uint32_t byte_offset = root_struct->token_locs[token].offset + bad_index; + ErrorMsg *err = err_msg_create_with_offset(root_struct->path, byte_offset, + buf_ptr(root_struct->source_code), msg); g->errors.append(err); g->trace_err = err; return err; } +ErrorMsg *add_token_error(CodeGen *g, ZigType *owner, TokenIndex token, Buf *msg) { + return add_token_error_offset(g, owner, token, msg, 0); +} + ErrorMsg *add_node_error(CodeGen *g, AstNode *node, Buf *msg) { - Token fake_token; - fake_token.start_line = node->line; - fake_token.start_column = node->column; node->already_traced_this_node = true; - return add_token_error(g, node->owner, &fake_token, msg); + return add_token_error(g, node->owner, node->main_token, msg); } ErrorMsg *add_error_note(CodeGen *g, ErrorMsg *parent_msg, const AstNode *node, Buf *msg) { - Token fake_token; - fake_token.start_line = node->line; - fake_token.start_column = node->column; - return add_error_note_token(g, parent_msg, node->owner, &fake_token, msg); + return add_error_note_token(g, parent_msg, node->owner, node->main_token, msg); } ZigType *new_type_table_entry(ZigTypeId id) { @@ -913,13 +916,27 @@ ZigType *get_slice_type(CodeGen *g, ZigType *ptr_type) { return entry; } -ZigType *get_opaque_type(CodeGen *g, Scope *scope, AstNode *source_node, const char *full_name, Buf *bare_name) { +static uint32_t node_line_onebased(AstNode *node) { + RootStruct *root_struct = node->owner->data.structure.root_struct; + assert(node->main_token < root_struct->token_count); + return root_struct->token_locs[node->main_token].line + 1; +} + +static uint32_t node_column_onebased(AstNode *node) { + RootStruct *root_struct = node->owner->data.structure.root_struct; + assert(node->main_token < root_struct->token_count); + return root_struct->token_locs[node->main_token].column + 1; +} + +ZigType *get_opaque_type(CodeGen *g, Scope *scope, AstNode *source_node, const char *full_name, + Buf *bare_name) +{ ZigType *entry = new_type_table_entry(ZigTypeIdOpaque); buf_init_from_str(&entry->name, full_name); ZigType *import = scope ? get_scope_import(scope) : nullptr; - unsigned line = source_node ? (unsigned)(source_node->line + 1) : 0; + unsigned line = source_node ? node_line_onebased(source_node) : 0; // Note: duplicated in get_partial_container_type entry->llvm_type = LLVMInt8Type(); @@ -1142,7 +1159,7 @@ ZigType *get_partial_container_type(CodeGen *g, Scope *scope, ContainerKind kind break; case ContainerKindOpaque: { ZigType *import = scope ? get_scope_import(scope) : nullptr; - unsigned line = decl_node ? (unsigned)(decl_node->line + 1) : 0; + unsigned line = decl_node ? node_line_onebased(decl_node) : 0; // Note: duplicated in get_opaque_type entry->llvm_type = LLVMInt8Type(); entry->llvm_di_type = ZigLLVMCreateDebugForwardDeclType(g->dbuilder, @@ -1584,8 +1601,9 @@ static OnePossibleValue type_val_resolve_has_one_possible_value(CodeGen *g, ZigV ZigType *analyze_type_expr(CodeGen *g, Scope *scope, AstNode *node) { Error err; // Hot path for simple identifiers, to avoid unnecessary memory allocations. - if (node->type == NodeTypeSymbol) { - Buf *variable_name = node->data.symbol_expr.symbol; + if (node->type == NodeTypeIdentifier) { + RootStruct *root_struct = node->owner->data.structure.root_struct; + Buf *variable_name = token_identifier_buf(root_struct, node->main_token); if (buf_eql_str(variable_name, "_")) goto abort_hot_path; ZigType *primitive_type; @@ -2034,7 +2052,7 @@ static ZigType *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_sc buf_sprintf("var args only allowed in functions with C calling convention")); return g->builtin_types.entry_invalid; } - } else if (param_node->data.param_decl.anytype_token != nullptr) { + } else if (param_node->data.param_decl.anytype_token != 0) { if (!calling_convention_allows_zig_types(fn_type_id.cc)) { add_node_error(g, param_node, buf_sprintf("parameter of type 'anytype' not allowed in function with calling convention '%s'", @@ -3021,7 +3039,7 @@ static Error resolve_struct_zero_bits(CodeGen *g, ZigType *struct_type) { field_node = decl_node->data.container_decl.fields.at(i); type_struct_field->name = field_node->data.struct_field.name; type_struct_field->decl_node = field_node; - if (field_node->data.struct_field.comptime_token != nullptr) { + if (field_node->data.struct_field.comptime_token != 0) { if (field_node->data.struct_field.value == nullptr) { add_token_error(g, field_node->owner, field_node->data.struct_field.comptime_token, @@ -4042,7 +4060,7 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) { case NodeTypeBoolLiteral: case NodeTypeNullLiteral: case NodeTypeUndefinedLiteral: - case NodeTypeSymbol: + case NodeTypeIdentifier: case NodeTypePrefixOpExpr: case NodeTypePointerType: case NodeTypeIfBoolExpr: @@ -4238,7 +4256,7 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var, bool allow_lazy) { bool is_const = var_decl->is_const; bool is_extern = var_decl->is_extern; bool is_export = var_decl->is_export; - bool is_thread_local = var_decl->threadlocal_tok != nullptr; + bool is_thread_local = var_decl->threadlocal_tok != 0; ZigType *explicit_type = nullptr; if (var_decl->type) { @@ -5225,8 +5243,6 @@ static void analyze_fn_body(CodeGen *g, ZigFn *fn_table_entry) { } if (g->verbose_ir) { - fprintf(stderr, "\n"); - ast_render(stderr, fn_table_entry->body_node, 4); fprintf(stderr, "\nfn %s() { // (IR)\n", buf_ptr(&fn_table_entry->symbol_name)); ir_print_src(g, stderr, fn_table_entry->ir_executable, 4); fprintf(stderr, "}\n"); @@ -5238,33 +5254,17 @@ static void analyze_fn_body(CodeGen *g, ZigFn *fn_table_entry) { ZigType *add_source_file(CodeGen *g, ZigPackage *package, Buf *resolved_path, Buf *source_code, SourceKind source_kind) { - if (g->verbose_tokenize) { - fprintf(stderr, "\nOriginal Source (%s):\n", buf_ptr(resolved_path)); - fprintf(stderr, "----------------\n"); - fprintf(stderr, "%s\n", buf_ptr(source_code)); - - fprintf(stderr, "\nTokens:\n"); - fprintf(stderr, "---------\n"); - } - Tokenization tokenization = {0}; - tokenize(source_code, &tokenization); + tokenize(buf_ptr(source_code), &tokenization); if (tokenization.err) { - ErrorMsg *err = err_msg_create_with_line(resolved_path, tokenization.err_line, tokenization.err_column, - source_code, tokenization.line_offsets, tokenization.err); + ErrorMsg *err = err_msg_create_with_offset(resolved_path, tokenization.err_byte_offset, + buf_ptr(source_code), tokenization.err); print_err_msg(err, g->err_color); exit(1); } - if (g->verbose_tokenize) { - print_tokens(source_code, tokenization.tokens); - - fprintf(stderr, "\nAST:\n"); - fprintf(stderr, "------\n"); - } - Buf *src_dirname = buf_alloc(); Buf *src_basename = buf_alloc(); os_path_split(resolved_path, src_dirname, src_basename); @@ -5297,9 +5297,20 @@ ZigType *add_source_file(CodeGen *g, ZigPackage *package, Buf *resolved_path, Bu RootStruct *root_struct = heap::c_allocator.create(); root_struct->package = package; root_struct->source_code = source_code; - root_struct->line_offsets = tokenization.line_offsets; root_struct->path = resolved_path; root_struct->di_file = ZigLLVMCreateFile(g->dbuilder, buf_ptr(src_basename), buf_ptr(src_dirname)); + + assert(tokenization.ids.length == tokenization.locs.length); + size_t token_count = tokenization.ids.length; + root_struct->token_count = token_count; + root_struct->token_ids = g->pass1_arena->allocate(token_count); + memcpy(root_struct->token_ids, tokenization.ids.items, token_count * sizeof(TokenId)); + root_struct->token_locs = g->pass1_arena->allocate(token_count); + memcpy(root_struct->token_locs, tokenization.locs.items, token_count * sizeof(TokenLoc)); + + tokenization.ids.deinit(); + tokenization.locs.deinit(); + ZigType *import_entry = get_root_container_type(g, buf_ptr(namespace_name), bare_name, root_struct); if (source_kind == SourceKindRoot) { assert(g->root_import == nullptr); @@ -5307,14 +5318,11 @@ ZigType *add_source_file(CodeGen *g, ZigPackage *package, Buf *resolved_path, Bu } g->import_table.put(resolved_path, import_entry); - AstNode *root_node = ast_parse(source_code, tokenization.tokens, import_entry, g->err_color); + AstNode *root_node = ast_parse(source_code, import_entry, g->err_color); assert(root_node != nullptr); assert(root_node->type == NodeTypeContainerDecl); import_entry->data.structure.decl_node = root_node; import_entry->data.structure.decls_scope->base.source_node = root_node; - if (g->verbose_ast) { - ast_print(stderr, root_node, 0); - } for (size_t decl_i = 0; decl_i < root_node->data.container_decl.decls.length; decl_i += 1) { AstNode *top_level_decl = root_node->data.container_decl.decls.at(decl_i); @@ -6254,9 +6262,12 @@ ReqCompTime type_requires_comptime(CodeGen *g, ZigType *ty) { zig_unreachable(); } -void init_const_str_lit(CodeGen *g, ZigValue *const_val, Buf *str) { +void init_const_str_lit(CodeGen *g, ZigValue *const_val, Buf *str, bool move_str) { auto entry = g->string_literals_table.maybe_get(str); if (entry != nullptr) { + if (move_str) { + buf_destroy(str); + } memcpy(const_val, entry->value, sizeof(ZigValue)); return; } @@ -6280,7 +6291,7 @@ void init_const_str_lit(CodeGen *g, ZigValue *const_val, Buf *str) { ZigValue *create_const_str_lit(CodeGen *g, Buf *str) { ZigValue *const_val = g->pass1_arena->create(); - init_const_str_lit(g, const_val, str); + init_const_str_lit(g, const_val, str, false); return const_val; } @@ -8626,7 +8637,7 @@ static void resolve_llvm_types_struct(CodeGen *g, ZigType *struct_type, ResolveS ZigType *import = get_scope_import(scope); di_file = import->data.structure.root_struct->di_file; di_scope = ZigLLVMFileToScope(di_file); - line = decl_node->line + 1; + line = node_line_onebased(decl_node); } else { di_file = nullptr; di_scope = ZigLLVMCompileUnitToScope(g->compile_unit); @@ -8830,7 +8841,7 @@ static void resolve_llvm_types_struct(CodeGen *g, ZigType *struct_type, ResolveS unsigned line; if (decl_node != nullptr) { AstNode *field_node = field->decl_node; - line = field_node->line + 1; + line = node_line_onebased(field_node); } else { line = 0; } @@ -8881,7 +8892,7 @@ static ZigLLVMDIType *make_empty_namespace_llvm_di_type(CodeGen *g, ZigType *imp return ZigLLVMCreateDebugStructType(g->dbuilder, ZigLLVMFileToScope(import->data.structure.root_struct->di_file), name, - import->data.structure.root_struct->di_file, (unsigned)(decl_node->line + 1), + import->data.structure.root_struct->di_file, node_line_onebased(decl_node), debug_size_in_bits, debug_align_in_bits, ZigLLVM_DIFlags_Zero, @@ -8926,7 +8937,7 @@ static void resolve_llvm_types_enum(CodeGen *g, ZigType *enum_type, ResolveStatu uint64_t tag_debug_align_in_bits = 8*tag_int_type->abi_align; ZigLLVMDIType *tag_di_type = ZigLLVMCreateDebugEnumerationType(g->dbuilder, ZigLLVMFileToScope(import->data.structure.root_struct->di_file), buf_ptr(&enum_type->name), - import->data.structure.root_struct->di_file, (unsigned)(decl_node->line + 1), + import->data.structure.root_struct->di_file, node_line_onebased(decl_node), tag_debug_size_in_bits, tag_debug_align_in_bits, di_enumerators, field_count, @@ -8966,12 +8977,12 @@ static void resolve_llvm_types_union(CodeGen *g, ZigType *union_type, ResolveSta if (union_type->data.unionation.resolve_status < ResolveStatusLLVMFwdDecl) { union_type->llvm_type = LLVMStructCreateNamed(LLVMGetGlobalContext(), buf_ptr(&union_type->name)); - size_t line = decl_node ? decl_node->line : 0; + unsigned line = decl_node ? node_line_onebased(decl_node) : 0; unsigned dwarf_kind = ZigLLVMTag_DW_structure_type(); union_type->llvm_di_type = ZigLLVMCreateReplaceableCompositeType(g->dbuilder, dwarf_kind, buf_ptr(&union_type->name), ZigLLVMFileToScope(import->data.structure.root_struct->di_file), - import->data.structure.root_struct->di_file, (unsigned)(line + 1)); + import->data.structure.root_struct->di_file, line); union_type->data.unionation.resolve_status = ResolveStatusLLVMFwdDecl; if (ResolveStatusLLVMFwdDecl >= wanted_resolve_status) return; @@ -8992,7 +9003,7 @@ static void resolve_llvm_types_union(CodeGen *g, ZigType *union_type, ResolveSta AstNode *field_node = union_field->decl_node; union_inner_di_types[union_field->gen_index] = ZigLLVMCreateDebugMemberType(g->dbuilder, ZigLLVMTypeToScope(union_type->llvm_di_type), buf_ptr(union_field->enum_field->name), - import->data.structure.root_struct->di_file, (unsigned)(field_node->line + 1), + import->data.structure.root_struct->di_file, node_line_onebased(field_node), store_size_in_bits, abi_align_in_bits, 0, @@ -9022,7 +9033,7 @@ static void resolve_llvm_types_union(CodeGen *g, ZigType *union_type, ResolveSta // create debug type for union ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugUnionType(g->dbuilder, ZigLLVMFileToScope(import->data.structure.root_struct->di_file), buf_ptr(&union_type->name), - import->data.structure.root_struct->di_file, (unsigned)(decl_node->line + 1), + import->data.structure.root_struct->di_file, node_line_onebased(decl_node), union_type->data.unionation.union_abi_size * 8, most_aligned_union_member->align * 8, ZigLLVM_DIFlags_Zero, union_inner_di_types, @@ -9057,7 +9068,7 @@ static void resolve_llvm_types_union(CodeGen *g, ZigType *union_type, ResolveSta // create debug type for union ZigLLVMDIType *union_di_type = ZigLLVMCreateDebugUnionType(g->dbuilder, ZigLLVMTypeToScope(union_type->llvm_di_type), "AnonUnion", - import->data.structure.root_struct->di_file, (unsigned)(decl_node->line + 1), + import->data.structure.root_struct->di_file, node_line_onebased(decl_node), most_aligned_union_member->type_entry->size_in_bits, 8*most_aligned_union_member->align, ZigLLVM_DIFlags_Zero, union_inner_di_types, gen_field_count, 0, ""); @@ -9068,7 +9079,7 @@ static void resolve_llvm_types_union(CodeGen *g, ZigType *union_type, ResolveSta ZigLLVMDIType *union_member_di_type = ZigLLVMCreateDebugMemberType(g->dbuilder, ZigLLVMTypeToScope(union_type->llvm_di_type), "payload", - import->data.structure.root_struct->di_file, (unsigned)(decl_node->line + 1), + import->data.structure.root_struct->di_file, node_line_onebased(decl_node), most_aligned_union_member->type_entry->size_in_bits, 8*most_aligned_union_member->align, union_offset_in_bits, @@ -9079,7 +9090,7 @@ static void resolve_llvm_types_union(CodeGen *g, ZigType *union_type, ResolveSta ZigLLVMDIType *tag_member_di_type = ZigLLVMCreateDebugMemberType(g->dbuilder, ZigLLVMTypeToScope(union_type->llvm_di_type), "tag", - import->data.structure.root_struct->di_file, (unsigned)(decl_node->line + 1), + import->data.structure.root_struct->di_file, node_line_onebased(decl_node), tag_debug_size_in_bits, tag_debug_align_in_bits, tag_offset_in_bits, @@ -9094,7 +9105,7 @@ static void resolve_llvm_types_union(CodeGen *g, ZigType *union_type, ResolveSta ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugStructType(g->dbuilder, ZigLLVMFileToScope(import->data.structure.root_struct->di_file), buf_ptr(&union_type->name), - import->data.structure.root_struct->di_file, (unsigned)(decl_node->line + 1), + import->data.structure.root_struct->di_file, node_line_onebased(decl_node), debug_size_in_bits, debug_align_in_bits, ZigLLVM_DIFlags_Zero, nullptr, di_root_members, 2, 0, nullptr, ""); @@ -9774,9 +9785,9 @@ void src_assert_impl(bool ok, AstNode *source_node, char const *file, unsigned i if (source_node == nullptr) { fprintf(stderr, "when analyzing (unknown source location) "); } else { - fprintf(stderr, "when analyzing %s:%u:%u ", - buf_ptr(source_node->owner->data.structure.root_struct->path), - (unsigned)source_node->line + 1, (unsigned)source_node->column + 1); + RootStruct *root_struct = source_node->owner->data.structure.root_struct; + fprintf(stderr, "when analyzing %s:%u:%u ", buf_ptr(root_struct->path), + node_line_onebased(source_node), node_column_onebased(source_node)); } fprintf(stderr, "in compiler source at %s:%u: ", file, line); const char *msg = "assertion failed. This is a bug in the Zig compiler."; @@ -9842,6 +9853,14 @@ Error analyze_import(CodeGen *g, ZigType *source_import, Buf *import_target_str, return ErrorNone; } +void AstNode::src() { + RootStruct *root_struct = this->owner->data.structure.root_struct; + uint32_t line = root_struct->token_locs[this->main_token].line + 1; + uint32_t column = root_struct->token_locs[this->main_token].column + 1; + fprintf(stderr, "%s:%" PRIu32 ":%" PRIu32 "\n", + buf_ptr(root_struct->path), + line, column); +} void IrExecutableSrc::src() { if (this->source_node != nullptr) { diff --git a/src/stage1/analyze.hpp b/src/stage1/analyze.hpp index 2815274f63..fee83ab7d0 100644 --- a/src/stage1/analyze.hpp +++ b/src/stage1/analyze.hpp @@ -12,7 +12,9 @@ void semantic_analyze(CodeGen *g); ErrorMsg *add_node_error(CodeGen *g, AstNode *node, Buf *msg); -ErrorMsg *add_token_error(CodeGen *g, ZigType *owner, Token *token, Buf *msg); +ErrorMsg *add_token_error(CodeGen *g, ZigType *owner, TokenIndex token, Buf *msg); +ErrorMsg *add_token_error_offset(CodeGen *g, ZigType *owner, TokenIndex token, Buf *msg, + uint32_t bad_index); ErrorMsg *add_error_note(CodeGen *g, ErrorMsg *parent_msg, const AstNode *node, Buf *msg); ZigType *new_type_table_entry(ZigTypeId id); ZigType *get_fn_frame_type(CodeGen *g, ZigFn *fn); @@ -140,7 +142,7 @@ Scope *create_runtime_scope(CodeGen *g, AstNode *node, Scope *parent, IrInstSrc Scope *create_typeof_scope(CodeGen *g, AstNode *node, Scope *parent); ScopeExpr *create_expr_scope(CodeGen *g, AstNode *node, Scope *parent); -void init_const_str_lit(CodeGen *g, ZigValue *const_val, Buf *str); +void init_const_str_lit(CodeGen *g, ZigValue *const_val, Buf *str, bool move_str); ZigValue *create_const_str_lit(CodeGen *g, Buf *str); void init_const_bigint(ZigValue *const_val, ZigType *type, const BigInt *bigint); diff --git a/src/stage1/ast_render.cpp b/src/stage1/ast_render.cpp deleted file mode 100644 index 75ad7267ab..0000000000 --- a/src/stage1/ast_render.cpp +++ /dev/null @@ -1,1241 +0,0 @@ -/* - * Copyright (c) 2016 Andrew Kelley - * - * This file is part of zig, which is MIT licensed. - * See http://opensource.org/licenses/MIT - */ - -#include "analyze.hpp" -#include "ast_render.hpp" -#include "os.hpp" - -#include - -static const char *bin_op_str(BinOpType bin_op) { - switch (bin_op) { - case BinOpTypeInvalid: return "(invalid)"; - case BinOpTypeBoolOr: return "or"; - case BinOpTypeBoolAnd: return "and"; - case BinOpTypeCmpEq: return "=="; - case BinOpTypeCmpNotEq: return "!="; - case BinOpTypeCmpLessThan: return "<"; - case BinOpTypeCmpGreaterThan: return ">"; - case BinOpTypeCmpLessOrEq: return "<="; - case BinOpTypeCmpGreaterOrEq: return ">="; - case BinOpTypeBinOr: return "|"; - case BinOpTypeBinXor: return "^"; - case BinOpTypeBinAnd: return "&"; - case BinOpTypeBitShiftLeft: return "<<"; - case BinOpTypeBitShiftRight: return ">>"; - case BinOpTypeAdd: return "+"; - case BinOpTypeAddWrap: return "+%"; - case BinOpTypeSub: return "-"; - case BinOpTypeSubWrap: return "-%"; - case BinOpTypeMult: return "*"; - case BinOpTypeMultWrap: return "*%"; - case BinOpTypeDiv: return "/"; - case BinOpTypeMod: return "%"; - case BinOpTypeAssign: return "="; - case BinOpTypeAssignTimes: return "*="; - case BinOpTypeAssignTimesWrap: return "*%="; - case BinOpTypeAssignDiv: return "/="; - case BinOpTypeAssignMod: return "%="; - case BinOpTypeAssignPlus: return "+="; - case BinOpTypeAssignPlusWrap: return "+%="; - case BinOpTypeAssignMinus: return "-="; - case BinOpTypeAssignMinusWrap: return "-%="; - case BinOpTypeAssignBitShiftLeft: return "<<="; - case BinOpTypeAssignBitShiftRight: return ">>="; - case BinOpTypeAssignBitAnd: return "&="; - case BinOpTypeAssignBitXor: return "^="; - case BinOpTypeAssignBitOr: return "|="; - case BinOpTypeUnwrapOptional: return "orelse"; - case BinOpTypeArrayCat: return "++"; - case BinOpTypeArrayMult: return "**"; - case BinOpTypeErrorUnion: return "!"; - case BinOpTypeMergeErrorSets: return "||"; - } - zig_unreachable(); -} - -static const char *prefix_op_str(PrefixOp prefix_op) { - switch (prefix_op) { - case PrefixOpInvalid: return "(invalid)"; - case PrefixOpNegation: return "-"; - case PrefixOpNegationWrap: return "-%"; - case PrefixOpBoolNot: return "!"; - case PrefixOpBinNot: return "~"; - case PrefixOpOptional: return "?"; - case PrefixOpAddrOf: return "&"; - } - zig_unreachable(); -} - -static const char *visib_mod_string(VisibMod mod) { - switch (mod) { - case VisibModPub: return "pub "; - case VisibModPrivate: return ""; - } - zig_unreachable(); -} - -static const char *return_string(ReturnKind kind) { - switch (kind) { - case ReturnKindUnconditional: return "return"; - case ReturnKindError: return "try"; - } - zig_unreachable(); -} - -static const char *defer_string(ReturnKind kind) { - switch (kind) { - case ReturnKindUnconditional: return "defer"; - case ReturnKindError: return "errdefer"; - } - zig_unreachable(); -} - -static const char *layout_string(ContainerLayout layout) { - switch (layout) { - case ContainerLayoutAuto: return ""; - case ContainerLayoutExtern: return "extern "; - case ContainerLayoutPacked: return "packed "; - } - zig_unreachable(); -} - -static const char *extern_string(bool is_extern) { - return is_extern ? "extern " : ""; -} - -static const char *export_string(bool is_export) { - return is_export ? "export " : ""; -} - -//static const char *calling_convention_string(CallingConvention cc) { -// switch (cc) { -// case CallingConventionUnspecified: return ""; -// case CallingConventionC: return "extern "; -// case CallingConventionCold: return "coldcc "; -// case CallingConventionNaked: return "nakedcc "; -// case CallingConventionStdcall: return "stdcallcc "; -// } -// zig_unreachable(); -//} - -static const char *inline_string(FnInline fn_inline) { - switch (fn_inline) { - case FnInlineAlways: return "inline "; - case FnInlineNever: return "noinline "; - case FnInlineAuto: return ""; - } - zig_unreachable(); -} - -static const char *const_or_var_string(bool is_const) { - return is_const ? "const" : "var"; -} - -static const char *thread_local_string(Token *tok) { - return (tok == nullptr) ? "" : "threadlocal "; -} - -static const char *token_to_ptr_len_str(Token *tok) { - assert(tok != nullptr); - switch (tok->id) { - case TokenIdStar: - case TokenIdStarStar: - return "*"; - case TokenIdLBracket: - return "[*]"; - case TokenIdSymbol: - return "[*c]"; - default: - zig_unreachable(); - } -} - -static const char *node_type_str(NodeType node_type) { - switch (node_type) { - case NodeTypeFnDef: - return "FnDef"; - case NodeTypeFnProto: - return "FnProto"; - case NodeTypeParamDecl: - return "ParamDecl"; - case NodeTypeBlock: - return "Block"; - case NodeTypeGroupedExpr: - return "Parens"; - case NodeTypeBinOpExpr: - return "BinOpExpr"; - case NodeTypeCatchExpr: - return "CatchExpr"; - case NodeTypeFnCallExpr: - return "FnCallExpr"; - case NodeTypeArrayAccessExpr: - return "ArrayAccessExpr"; - case NodeTypeSliceExpr: - return "SliceExpr"; - case NodeTypeReturnExpr: - return "ReturnExpr"; - case NodeTypeDefer: - return "Defer"; - case NodeTypeVariableDeclaration: - return "VariableDeclaration"; - case NodeTypeTestDecl: - return "TestDecl"; - case NodeTypeIntLiteral: - return "IntLiteral"; - case NodeTypeFloatLiteral: - return "FloatLiteral"; - case NodeTypeStringLiteral: - return "StringLiteral"; - case NodeTypeCharLiteral: - return "CharLiteral"; - case NodeTypeSymbol: - return "Symbol"; - case NodeTypePrefixOpExpr: - return "PrefixOpExpr"; - case NodeTypeUsingNamespace: - return "UsingNamespace"; - case NodeTypeBoolLiteral: - return "BoolLiteral"; - case NodeTypeNullLiteral: - return "NullLiteral"; - case NodeTypeUndefinedLiteral: - return "UndefinedLiteral"; - case NodeTypeIfBoolExpr: - return "IfBoolExpr"; - case NodeTypeWhileExpr: - return "WhileExpr"; - case NodeTypeForExpr: - return "ForExpr"; - case NodeTypeSwitchExpr: - return "SwitchExpr"; - case NodeTypeSwitchProng: - return "SwitchProng"; - case NodeTypeSwitchRange: - return "SwitchRange"; - case NodeTypeCompTime: - return "CompTime"; - case NodeTypeNoSuspend: - return "NoSuspend"; - case NodeTypeBreak: - return "Break"; - case NodeTypeContinue: - return "Continue"; - case NodeTypeUnreachable: - return "Unreachable"; - case NodeTypeAsmExpr: - return "AsmExpr"; - case NodeTypeFieldAccessExpr: - return "FieldAccessExpr"; - case NodeTypePtrDeref: - return "PtrDerefExpr"; - case NodeTypeUnwrapOptional: - return "UnwrapOptional"; - case NodeTypeContainerDecl: - return "ContainerDecl"; - case NodeTypeStructField: - return "StructField"; - case NodeTypeStructValueField: - return "StructValueField"; - case NodeTypeContainerInitExpr: - return "ContainerInitExpr"; - case NodeTypeArrayType: - return "ArrayType"; - case NodeTypeInferredArrayType: - return "InferredArrayType"; - case NodeTypeErrorType: - return "ErrorType"; - case NodeTypeIfErrorExpr: - return "IfErrorExpr"; - case NodeTypeIfOptional: - return "IfOptional"; - case NodeTypeErrorSetDecl: - return "ErrorSetDecl"; - case NodeTypeResume: - return "Resume"; - case NodeTypeAwaitExpr: - return "AwaitExpr"; - case NodeTypeSuspend: - return "Suspend"; - case NodeTypePointerType: - return "PointerType"; - case NodeTypeAnyFrameType: - return "AnyFrameType"; - case NodeTypeEnumLiteral: - return "EnumLiteral"; - case NodeTypeErrorSetField: - return "ErrorSetField"; - case NodeTypeAnyTypeField: - return "AnyTypeField"; - } - zig_unreachable(); -} - -struct AstPrint { - int indent; - FILE *f; -}; - -static void ast_print_visit(AstNode **node_ptr, void *context) { - AstNode *node = *node_ptr; - AstPrint *ap = (AstPrint *)context; - - for (int i = 0; i < ap->indent; i += 1) { - fprintf(ap->f, " "); - } - - fprintf(ap->f, "%s\n", node_type_str(node->type)); - - AstPrint new_ap; - new_ap.indent = ap->indent + 2; - new_ap.f = ap->f; - - ast_visit_node_children(node, ast_print_visit, &new_ap); -} - -void ast_print(FILE *f, AstNode *node, int indent) { - AstPrint ap; - ap.indent = indent; - ap.f = f; - ast_visit_node_children(node, ast_print_visit, &ap); -} - - -struct AstRender { - int indent; - int indent_size; - FILE *f; -}; - -static void print_indent(AstRender *ar) { - for (int i = 0; i < ar->indent; i += 1) { - fprintf(ar->f, " "); - } -} - -static bool is_alpha_under(uint8_t c) { - return (c >= 'a' && c <= 'z') || - (c >= 'A' && c <= 'Z') || c == '_'; -} - -static bool is_digit(uint8_t c) { - return (c >= '0' && c <= '9'); -} - -static bool is_printable(uint8_t c) { - if (c == 0) { - return false; - } - static const uint8_t printables[] = - " abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.~`!@#$%^&*()_-+=\\{}[];'\"?/<>,:"; - for (size_t i = 0; i < array_length(printables); i += 1) { - if (c == printables[i]) return true; - } - return false; -} - -static void string_literal_escape(Buf *source, Buf *dest) { - buf_resize(dest, 0); - for (size_t i = 0; i < buf_len(source); i += 1) { - uint8_t c = *((uint8_t*)buf_ptr(source) + i); - if (c == '\'') { - buf_append_str(dest, "\\'"); - } else if (c == '"') { - buf_append_str(dest, "\\\""); - } else if (c == '\\') { - buf_append_str(dest, "\\\\"); - } else if (c == '\n') { - buf_append_str(dest, "\\n"); - } else if (c == '\r') { - buf_append_str(dest, "\\r"); - } else if (c == '\t') { - buf_append_str(dest, "\\t"); - } else if (is_printable(c)) { - buf_append_char(dest, c); - } else { - buf_appendf(dest, "\\x%02x", (int)c); - } - } -} - -static bool is_valid_bare_symbol(Buf *symbol) { - if (buf_len(symbol) == 0) { - return false; - } - uint8_t first_char = *buf_ptr(symbol); - if (!is_alpha_under(first_char)) { - return false; - } - for (size_t i = 1; i < buf_len(symbol); i += 1) { - uint8_t c = *((uint8_t*)buf_ptr(symbol) + i); - if (!is_alpha_under(c) && !is_digit(c)) { - return false; - } - } - return true; -} - -static void print_symbol(AstRender *ar, Buf *symbol) { - if (is_zig_keyword(symbol)) { - fprintf(ar->f, "@\"%s\"", buf_ptr(symbol)); - return; - } - if (is_valid_bare_symbol(symbol)) { - fprintf(ar->f, "%s", buf_ptr(symbol)); - return; - } - Buf escaped = BUF_INIT; - string_literal_escape(symbol, &escaped); - fprintf(ar->f, "@\"%s\"", buf_ptr(&escaped)); -} - -static bool statement_terminates_without_semicolon(AstNode *node) { - switch (node->type) { - case NodeTypeIfBoolExpr: - if (node->data.if_bool_expr.else_node) - return statement_terminates_without_semicolon(node->data.if_bool_expr.else_node); - return node->data.if_bool_expr.then_block->type == NodeTypeBlock; - case NodeTypeIfErrorExpr: - if (node->data.if_err_expr.else_node) - return statement_terminates_without_semicolon(node->data.if_err_expr.else_node); - return node->data.if_err_expr.then_node->type == NodeTypeBlock; - case NodeTypeIfOptional: - if (node->data.test_expr.else_node) - return statement_terminates_without_semicolon(node->data.test_expr.else_node); - return node->data.test_expr.then_node->type == NodeTypeBlock; - case NodeTypeWhileExpr: - return node->data.while_expr.body->type == NodeTypeBlock; - case NodeTypeForExpr: - return node->data.for_expr.body->type == NodeTypeBlock; - case NodeTypeCompTime: - return node->data.comptime_expr.expr->type == NodeTypeBlock; - case NodeTypeDefer: - return node->data.defer.expr->type == NodeTypeBlock; - case NodeTypeSuspend: - return node->data.suspend.block != nullptr && node->data.suspend.block->type == NodeTypeBlock; - case NodeTypeSwitchExpr: - case NodeTypeBlock: - return true; - default: - return false; - } -} - -static void render_node_extra(AstRender *ar, AstNode *node, bool grouped); - -static void render_node_grouped(AstRender *ar, AstNode *node) { - return render_node_extra(ar, node, true); -} - -static void render_node_ungrouped(AstRender *ar, AstNode *node) { - return render_node_extra(ar, node, false); -} - -static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { - switch (node->type) { - case NodeTypeSwitchProng: - case NodeTypeSwitchRange: - case NodeTypeStructValueField: - zig_unreachable(); - case NodeTypeFnProto: - { - const char *pub_str = visib_mod_string(node->data.fn_proto.visib_mod); - const char *extern_str = extern_string(node->data.fn_proto.is_extern); - const char *export_str = export_string(node->data.fn_proto.is_export); - const char *inline_str = inline_string(node->data.fn_proto.fn_inline); - fprintf(ar->f, "%s%s%s%sfn ", pub_str, inline_str, export_str, extern_str); - if (node->data.fn_proto.name != nullptr) { - print_symbol(ar, node->data.fn_proto.name); - } - fprintf(ar->f, "("); - size_t arg_count = node->data.fn_proto.params.length; - for (size_t arg_i = 0; arg_i < arg_count; arg_i += 1) { - AstNode *param_decl = node->data.fn_proto.params.at(arg_i); - assert(param_decl->type == NodeTypeParamDecl); - if (param_decl->data.param_decl.name != nullptr) { - const char *noalias_str = param_decl->data.param_decl.is_noalias ? "noalias " : ""; - const char *inline_str = param_decl->data.param_decl.is_comptime ? "comptime " : ""; - fprintf(ar->f, "%s%s", noalias_str, inline_str); - print_symbol(ar, param_decl->data.param_decl.name); - fprintf(ar->f, ": "); - } - if (param_decl->data.param_decl.is_var_args) { - fprintf(ar->f, "..."); - } else if (param_decl->data.param_decl.anytype_token != nullptr) { - fprintf(ar->f, "anytype"); - } else { - render_node_grouped(ar, param_decl->data.param_decl.type); - } - - if (arg_i + 1 < arg_count) { - fprintf(ar->f, ", "); - } - } - if (node->data.fn_proto.is_var_args) { - fprintf(ar->f, ", ..."); - } - fprintf(ar->f, ")"); - if (node->data.fn_proto.align_expr) { - fprintf(ar->f, " align("); - render_node_grouped(ar, node->data.fn_proto.align_expr); - fprintf(ar->f, ")"); - } - if (node->data.fn_proto.section_expr) { - fprintf(ar->f, " section("); - render_node_grouped(ar, node->data.fn_proto.section_expr); - fprintf(ar->f, ")"); - } - if (node->data.fn_proto.callconv_expr) { - fprintf(ar->f, " callconv("); - render_node_grouped(ar, node->data.fn_proto.callconv_expr); - fprintf(ar->f, ")"); - } - - AstNode *return_type_node = node->data.fn_proto.return_type; - assert(return_type_node != nullptr); - fprintf(ar->f, " "); - if (node->data.fn_proto.auto_err_set) { - fprintf(ar->f, "!"); - } - render_node_grouped(ar, return_type_node); - break; - } - case NodeTypeFnDef: - { - render_node_grouped(ar, node->data.fn_def.fn_proto); - fprintf(ar->f, " "); - render_node_grouped(ar, node->data.fn_def.body); - break; - } - case NodeTypeBlock: - if (node->data.block.name != nullptr) { - fprintf(ar->f, "%s: ", buf_ptr(node->data.block.name)); - } - if (node->data.block.statements.length == 0) { - fprintf(ar->f, "{}"); - break; - } - fprintf(ar->f, "{\n"); - ar->indent += ar->indent_size; - for (size_t i = 0; i < node->data.block.statements.length; i += 1) { - AstNode *statement = node->data.block.statements.at(i); - print_indent(ar); - render_node_grouped(ar, statement); - - if (!statement_terminates_without_semicolon(statement)) - fprintf(ar->f, ";"); - - fprintf(ar->f, "\n"); - } - ar->indent -= ar->indent_size; - print_indent(ar); - fprintf(ar->f, "}"); - break; - case NodeTypeGroupedExpr: - fprintf(ar->f, "("); - render_node_ungrouped(ar, node->data.grouped_expr); - fprintf(ar->f, ")"); - break; - case NodeTypeReturnExpr: - { - const char *return_str = return_string(node->data.return_expr.kind); - fprintf(ar->f, "%s", return_str); - if (node->data.return_expr.expr) { - fprintf(ar->f, " "); - render_node_grouped(ar, node->data.return_expr.expr); - } - break; - } - case NodeTypeBreak: - { - fprintf(ar->f, "break"); - if (node->data.break_expr.name != nullptr) { - fprintf(ar->f, " :%s", buf_ptr(node->data.break_expr.name)); - } - if (node->data.break_expr.expr) { - fprintf(ar->f, " "); - render_node_grouped(ar, node->data.break_expr.expr); - } - break; - } - case NodeTypeDefer: - { - const char *defer_str = defer_string(node->data.defer.kind); - fprintf(ar->f, "%s ", defer_str); - render_node_grouped(ar, node->data.defer.expr); - break; - } - case NodeTypeVariableDeclaration: - { - const char *pub_str = visib_mod_string(node->data.variable_declaration.visib_mod); - const char *extern_str = extern_string(node->data.variable_declaration.is_extern); - const char *thread_local_str = thread_local_string(node->data.variable_declaration.threadlocal_tok); - const char *const_or_var = const_or_var_string(node->data.variable_declaration.is_const); - fprintf(ar->f, "%s%s%s%s ", pub_str, extern_str, thread_local_str, const_or_var); - print_symbol(ar, node->data.variable_declaration.symbol); - - if (node->data.variable_declaration.type) { - fprintf(ar->f, ": "); - render_node_grouped(ar, node->data.variable_declaration.type); - } - if (node->data.variable_declaration.align_expr) { - fprintf(ar->f, "align("); - render_node_grouped(ar, node->data.variable_declaration.align_expr); - fprintf(ar->f, ") "); - } - if (node->data.variable_declaration.section_expr) { - fprintf(ar->f, "section("); - render_node_grouped(ar, node->data.variable_declaration.section_expr); - fprintf(ar->f, ") "); - } - if (node->data.variable_declaration.expr) { - fprintf(ar->f, " = "); - render_node_grouped(ar, node->data.variable_declaration.expr); - } - break; - } - case NodeTypeBinOpExpr: - if (!grouped) fprintf(ar->f, "("); - render_node_ungrouped(ar, node->data.bin_op_expr.op1); - fprintf(ar->f, " %s ", bin_op_str(node->data.bin_op_expr.bin_op)); - render_node_ungrouped(ar, node->data.bin_op_expr.op2); - if (!grouped) fprintf(ar->f, ")"); - break; - case NodeTypeFloatLiteral: - { - Buf rendered_buf = BUF_INIT; - buf_resize(&rendered_buf, 0); - bigfloat_append_buf(&rendered_buf, node->data.float_literal.bigfloat); - fprintf(ar->f, "%s", buf_ptr(&rendered_buf)); - } - break; - case NodeTypeIntLiteral: - { - Buf rendered_buf = BUF_INIT; - buf_resize(&rendered_buf, 0); - bigint_append_buf(&rendered_buf, node->data.int_literal.bigint, 10); - fprintf(ar->f, "%s", buf_ptr(&rendered_buf)); - } - break; - case NodeTypeStringLiteral: - { - Buf tmp_buf = BUF_INIT; - string_literal_escape(node->data.string_literal.buf, &tmp_buf); - fprintf(ar->f, "\"%s\"", buf_ptr(&tmp_buf)); - } - break; - case NodeTypeCharLiteral: - { - uint8_t c = node->data.char_literal.value; - if (c == '\'') { - fprintf(ar->f, "'\\''"); - } else if (c == '\"') { - fprintf(ar->f, "'\\\"'"); - } else if (c == '\\') { - fprintf(ar->f, "'\\\\'"); - } else if (c == '\n') { - fprintf(ar->f, "'\\n'"); - } else if (c == '\r') { - fprintf(ar->f, "'\\r'"); - } else if (c == '\t') { - fprintf(ar->f, "'\\t'"); - } else if (is_printable(c)) { - fprintf(ar->f, "'%c'", c); - } else { - fprintf(ar->f, "'\\x%02x'", (int)c); - } - break; - } - case NodeTypeSymbol: - print_symbol(ar, node->data.symbol_expr.symbol); - break; - case NodeTypePrefixOpExpr: - { - if (!grouped) fprintf(ar->f, "("); - PrefixOp op = node->data.prefix_op_expr.prefix_op; - fprintf(ar->f, "%s", prefix_op_str(op)); - - AstNode *child_node = node->data.prefix_op_expr.primary_expr; - bool new_grouped = child_node->type == NodeTypePrefixOpExpr || child_node->type == NodeTypePointerType; - render_node_extra(ar, child_node, new_grouped); - if (!grouped) fprintf(ar->f, ")"); - break; - } - case NodeTypePointerType: - { - if (!grouped) fprintf(ar->f, "("); - const char *ptr_len_str = token_to_ptr_len_str(node->data.pointer_type.star_token); - fprintf(ar->f, "%s", ptr_len_str); - if (node->data.pointer_type.align_expr != nullptr) { - fprintf(ar->f, "align("); - render_node_grouped(ar, node->data.pointer_type.align_expr); - if (node->data.pointer_type.bit_offset_start != nullptr) { - assert(node->data.pointer_type.host_int_bytes != nullptr); - - Buf offset_start_buf = BUF_INIT; - buf_resize(&offset_start_buf, 0); - bigint_append_buf(&offset_start_buf, node->data.pointer_type.bit_offset_start, 10); - - Buf offset_end_buf = BUF_INIT; - buf_resize(&offset_end_buf, 0); - bigint_append_buf(&offset_end_buf, node->data.pointer_type.host_int_bytes, 10); - - fprintf(ar->f, ":%s:%s ", buf_ptr(&offset_start_buf), buf_ptr(&offset_end_buf)); - } - fprintf(ar->f, ") "); - } - if (node->data.pointer_type.is_const) { - fprintf(ar->f, "const "); - } - if (node->data.pointer_type.is_volatile) { - fprintf(ar->f, "volatile "); - } - - render_node_ungrouped(ar, node->data.pointer_type.op_expr); - if (!grouped) fprintf(ar->f, ")"); - break; - } - case NodeTypeFnCallExpr: - { - switch (node->data.fn_call_expr.modifier) { - case CallModifierNone: - break; - case CallModifierNoSuspend: - fprintf(ar->f, "nosuspend "); - break; - case CallModifierAsync: - fprintf(ar->f, "async "); - break; - case CallModifierNeverTail: - fprintf(ar->f, "notail "); - break; - case CallModifierNeverInline: - fprintf(ar->f, "noinline "); - break; - case CallModifierAlwaysTail: - fprintf(ar->f, "tail "); - break; - case CallModifierAlwaysInline: - fprintf(ar->f, "inline "); - break; - case CallModifierCompileTime: - fprintf(ar->f, "comptime "); - break; - case CallModifierBuiltin: - fprintf(ar->f, "@"); - break; - } - AstNode *fn_ref_node = node->data.fn_call_expr.fn_ref_expr; - bool grouped = (fn_ref_node->type != NodeTypePrefixOpExpr && fn_ref_node->type != NodeTypePointerType); - render_node_extra(ar, fn_ref_node, grouped); - fprintf(ar->f, "("); - for (size_t i = 0; i < node->data.fn_call_expr.params.length; i += 1) { - AstNode *param = node->data.fn_call_expr.params.at(i); - if (i != 0) { - fprintf(ar->f, ", "); - } - render_node_grouped(ar, param); - } - fprintf(ar->f, ")"); - break; - } - case NodeTypeArrayAccessExpr: - render_node_ungrouped(ar, node->data.array_access_expr.array_ref_expr); - fprintf(ar->f, "["); - render_node_grouped(ar, node->data.array_access_expr.subscript); - fprintf(ar->f, "]"); - break; - case NodeTypeFieldAccessExpr: - { - AstNode *lhs = node->data.field_access_expr.struct_expr; - Buf *rhs = node->data.field_access_expr.field_name; - if (lhs->type == NodeTypeErrorType) { - fprintf(ar->f, "error"); - } else { - render_node_ungrouped(ar, lhs); - } - fprintf(ar->f, "."); - print_symbol(ar, rhs); - break; - } - case NodeTypePtrDeref: - { - AstNode *lhs = node->data.ptr_deref_expr.target; - render_node_ungrouped(ar, lhs); - fprintf(ar->f, ".*"); - break; - } - case NodeTypeUnwrapOptional: - { - AstNode *lhs = node->data.unwrap_optional.expr; - render_node_ungrouped(ar, lhs); - fprintf(ar->f, ".?"); - break; - } - case NodeTypeUndefinedLiteral: - fprintf(ar->f, "undefined"); - break; - case NodeTypeContainerDecl: - { - if (!node->data.container_decl.is_root) { - const char *layout_str = layout_string(node->data.container_decl.layout); - const char *container_str = container_string(node->data.container_decl.kind); - fprintf(ar->f, "%s%s", layout_str, container_str); - if (node->data.container_decl.auto_enum) { - fprintf(ar->f, "(enum"); - } - if (node->data.container_decl.init_arg_expr != nullptr) { - fprintf(ar->f, "("); - render_node_grouped(ar, node->data.container_decl.init_arg_expr); - fprintf(ar->f, ")"); - } - if (node->data.container_decl.auto_enum) { - fprintf(ar->f, ")"); - } - - fprintf(ar->f, " {\n"); - ar->indent += ar->indent_size; - } - for (size_t field_i = 0; field_i < node->data.container_decl.fields.length; field_i += 1) { - AstNode *field_node = node->data.container_decl.fields.at(field_i); - assert(field_node->type == NodeTypeStructField); - print_indent(ar); - print_symbol(ar, field_node->data.struct_field.name); - if (field_node->data.struct_field.type != nullptr) { - fprintf(ar->f, ": "); - render_node_grouped(ar, field_node->data.struct_field.type); - } - if (field_node->data.struct_field.value != nullptr) { - fprintf(ar->f, " = "); - render_node_grouped(ar, field_node->data.struct_field.value); - } - fprintf(ar->f, ",\n"); - } - - for (size_t decl_i = 0; decl_i < node->data.container_decl.decls.length; decl_i += 1) { - AstNode *decls_node = node->data.container_decl.decls.at(decl_i); - render_node_grouped(ar, decls_node); - - if (decls_node->type == NodeTypeUsingNamespace || - decls_node->type == NodeTypeVariableDeclaration || - decls_node->type == NodeTypeFnProto) - { - fprintf(ar->f, ";"); - } - fprintf(ar->f, "\n"); - } - - if (!node->data.container_decl.is_root) { - ar->indent -= ar->indent_size; - print_indent(ar); - fprintf(ar->f, "}"); - } - break; - } - case NodeTypeContainerInitExpr: - if (node->data.container_init_expr.type != nullptr) { - render_node_ungrouped(ar, node->data.container_init_expr.type); - } - if (node->data.container_init_expr.kind == ContainerInitKindStruct) { - fprintf(ar->f, "{\n"); - ar->indent += ar->indent_size; - } else { - fprintf(ar->f, "{"); - } - for (size_t i = 0; i < node->data.container_init_expr.entries.length; i += 1) { - AstNode *entry = node->data.container_init_expr.entries.at(i); - if (entry->type == NodeTypeStructValueField) { - Buf *name = entry->data.struct_val_field.name; - AstNode *expr = entry->data.struct_val_field.expr; - print_indent(ar); - fprintf(ar->f, ".%s = ", buf_ptr(name)); - render_node_grouped(ar, expr); - fprintf(ar->f, ",\n"); - } else { - if (i != 0) - fprintf(ar->f, ", "); - render_node_grouped(ar, entry); - } - } - if (node->data.container_init_expr.kind == ContainerInitKindStruct) { - ar->indent -= ar->indent_size; - } - print_indent(ar); - fprintf(ar->f, "}"); - break; - case NodeTypeArrayType: - { - fprintf(ar->f, "["); - if (node->data.array_type.size) { - render_node_grouped(ar, node->data.array_type.size); - } - fprintf(ar->f, "]"); - if (node->data.array_type.is_const) { - fprintf(ar->f, "const "); - } - render_node_ungrouped(ar, node->data.array_type.child_type); - break; - } - case NodeTypeInferredArrayType: - { - fprintf(ar->f, "[_]"); - render_node_ungrouped(ar, node->data.inferred_array_type.child_type); - break; - } - case NodeTypeAnyFrameType: { - fprintf(ar->f, "anyframe"); - if (node->data.anyframe_type.payload_type != nullptr) { - fprintf(ar->f, "->"); - render_node_grouped(ar, node->data.anyframe_type.payload_type); - } - break; - } - case NodeTypeErrorType: - fprintf(ar->f, "anyerror"); - break; - case NodeTypeAsmExpr: - { - AstNodeAsmExpr *asm_expr = &node->data.asm_expr; - const char *volatile_str = (asm_expr->volatile_token != nullptr) ? " volatile" : ""; - fprintf(ar->f, "asm%s (", volatile_str); - render_node_ungrouped(ar, asm_expr->asm_template); - fprintf(ar->f, ")"); - print_indent(ar); - fprintf(ar->f, ": "); - for (size_t i = 0; i < asm_expr->output_list.length; i += 1) { - AsmOutput *asm_output = asm_expr->output_list.at(i); - - if (i != 0) { - fprintf(ar->f, ",\n"); - print_indent(ar); - } - - fprintf(ar->f, "[%s] \"%s\" (", - buf_ptr(asm_output->asm_symbolic_name), - buf_ptr(asm_output->constraint)); - if (asm_output->return_type) { - fprintf(ar->f, "-> "); - render_node_grouped(ar, asm_output->return_type); - } else { - fprintf(ar->f, "%s", buf_ptr(asm_output->variable_name)); - } - fprintf(ar->f, ")"); - } - fprintf(ar->f, "\n"); - print_indent(ar); - fprintf(ar->f, ": "); - for (size_t i = 0; i < asm_expr->input_list.length; i += 1) { - AsmInput *asm_input = asm_expr->input_list.at(i); - - if (i != 0) { - fprintf(ar->f, ",\n"); - print_indent(ar); - } - - fprintf(ar->f, "[%s] \"%s\" (", - buf_ptr(asm_input->asm_symbolic_name), - buf_ptr(asm_input->constraint)); - render_node_grouped(ar, asm_input->expr); - fprintf(ar->f, ")"); - } - fprintf(ar->f, "\n"); - print_indent(ar); - fprintf(ar->f, ": "); - for (size_t i = 0; i < asm_expr->clobber_list.length; i += 1) { - Buf *reg_name = asm_expr->clobber_list.at(i); - if (i != 0) fprintf(ar->f, ", "); - fprintf(ar->f, "\"%s\"", buf_ptr(reg_name)); - } - fprintf(ar->f, ")"); - break; - } - case NodeTypeWhileExpr: - { - if (node->data.while_expr.name != nullptr) { - fprintf(ar->f, "%s: ", buf_ptr(node->data.while_expr.name)); - } - const char *inline_str = node->data.while_expr.is_inline ? "inline " : ""; - fprintf(ar->f, "%swhile (", inline_str); - render_node_grouped(ar, node->data.while_expr.condition); - fprintf(ar->f, ") "); - if (node->data.while_expr.var_symbol) { - fprintf(ar->f, "|%s| ", buf_ptr(node->data.while_expr.var_symbol)); - } - if (node->data.while_expr.continue_expr) { - fprintf(ar->f, ": ("); - render_node_grouped(ar, node->data.while_expr.continue_expr); - fprintf(ar->f, ") "); - } - render_node_grouped(ar, node->data.while_expr.body); - if (node->data.while_expr.else_node) { - fprintf(ar->f, " else "); - if (node->data.while_expr.err_symbol) { - fprintf(ar->f, "|%s| ", buf_ptr(node->data.while_expr.err_symbol)); - } - render_node_grouped(ar, node->data.while_expr.else_node); - } - break; - } - case NodeTypeBoolLiteral: - { - const char *bool_str = node->data.bool_literal.value ? "true" : "false"; - fprintf(ar->f, "%s", bool_str); - break; - } - case NodeTypeIfBoolExpr: - { - fprintf(ar->f, "if ("); - render_node_grouped(ar, node->data.if_bool_expr.condition); - fprintf(ar->f, ") "); - render_node_grouped(ar, node->data.if_bool_expr.then_block); - if (node->data.if_bool_expr.else_node) { - fprintf(ar->f, " else "); - render_node_grouped(ar, node->data.if_bool_expr.else_node); - } - break; - } - case NodeTypeNullLiteral: - { - fprintf(ar->f, "null"); - break; - } - case NodeTypeIfErrorExpr: - { - fprintf(ar->f, "if ("); - render_node_grouped(ar, node->data.if_err_expr.target_node); - fprintf(ar->f, ") "); - if (node->data.if_err_expr.var_symbol) { - const char *ptr_str = node->data.if_err_expr.var_is_ptr ? "*" : ""; - const char *var_name = buf_ptr(node->data.if_err_expr.var_symbol); - fprintf(ar->f, "|%s%s| ", ptr_str, var_name); - } - render_node_grouped(ar, node->data.if_err_expr.then_node); - if (node->data.if_err_expr.else_node) { - fprintf(ar->f, " else "); - if (node->data.if_err_expr.err_symbol) { - fprintf(ar->f, "|%s| ", buf_ptr(node->data.if_err_expr.err_symbol)); - } - render_node_grouped(ar, node->data.if_err_expr.else_node); - } - break; - } - case NodeTypeIfOptional: - { - fprintf(ar->f, "if ("); - render_node_grouped(ar, node->data.test_expr.target_node); - fprintf(ar->f, ") "); - if (node->data.test_expr.var_symbol) { - const char *ptr_str = node->data.test_expr.var_is_ptr ? "*" : ""; - const char *var_name = buf_ptr(node->data.test_expr.var_symbol); - fprintf(ar->f, "|%s%s| ", ptr_str, var_name); - } - render_node_grouped(ar, node->data.test_expr.then_node); - if (node->data.test_expr.else_node) { - fprintf(ar->f, " else "); - render_node_grouped(ar, node->data.test_expr.else_node); - } - break; - } - case NodeTypeSwitchExpr: - { - AstNodeSwitchExpr *switch_expr = &node->data.switch_expr; - fprintf(ar->f, "switch ("); - render_node_grouped(ar, switch_expr->expr); - fprintf(ar->f, ") {\n"); - ar->indent += ar->indent_size; - - for (size_t prong_i = 0; prong_i < switch_expr->prongs.length; prong_i += 1) { - AstNode *prong_node = switch_expr->prongs.at(prong_i); - AstNodeSwitchProng *switch_prong = &prong_node->data.switch_prong; - print_indent(ar); - for (size_t item_i = 0; item_i < switch_prong->items.length; item_i += 1) { - AstNode *item_node = switch_prong->items.at(item_i); - if (item_i != 0) - fprintf(ar->f, ", "); - if (item_node->type == NodeTypeSwitchRange) { - AstNode *start_node = item_node->data.switch_range.start; - AstNode *end_node = item_node->data.switch_range.end; - render_node_grouped(ar, start_node); - fprintf(ar->f, "..."); - render_node_grouped(ar, end_node); - } else { - render_node_grouped(ar, item_node); - } - } - const char *else_str = (switch_prong->items.length == 0) ? "else" : ""; - fprintf(ar->f, "%s => ", else_str); - if (switch_prong->var_symbol) { - const char *star_str = switch_prong->var_is_ptr ? "*" : ""; - Buf *var_name = switch_prong->var_symbol->data.symbol_expr.symbol; - fprintf(ar->f, "|%s%s| ", star_str, buf_ptr(var_name)); - } - render_node_grouped(ar, switch_prong->expr); - fprintf(ar->f, ",\n"); - } - - ar->indent -= ar->indent_size; - print_indent(ar); - fprintf(ar->f, "}"); - break; - } - case NodeTypeCompTime: - { - fprintf(ar->f, "comptime "); - render_node_grouped(ar, node->data.comptime_expr.expr); - break; - } - case NodeTypeNoSuspend: - { - fprintf(ar->f, "nosuspend "); - render_node_grouped(ar, node->data.nosuspend_expr.expr); - break; - } - case NodeTypeForExpr: - { - if (node->data.for_expr.name != nullptr) { - fprintf(ar->f, "%s: ", buf_ptr(node->data.for_expr.name)); - } - const char *inline_str = node->data.for_expr.is_inline ? "inline " : ""; - fprintf(ar->f, "%sfor (", inline_str); - render_node_grouped(ar, node->data.for_expr.array_expr); - fprintf(ar->f, ") "); - if (node->data.for_expr.elem_node) { - fprintf(ar->f, "|"); - if (node->data.for_expr.elem_is_ptr) - fprintf(ar->f, "*"); - render_node_grouped(ar, node->data.for_expr.elem_node); - if (node->data.for_expr.index_node) { - fprintf(ar->f, ", "); - render_node_grouped(ar, node->data.for_expr.index_node); - } - fprintf(ar->f, "| "); - } - render_node_grouped(ar, node->data.for_expr.body); - if (node->data.for_expr.else_node) { - fprintf(ar->f, " else"); - render_node_grouped(ar, node->data.for_expr.else_node); - } - break; - } - case NodeTypeContinue: - { - fprintf(ar->f, "continue"); - if (node->data.continue_expr.name != nullptr) { - fprintf(ar->f, " :%s", buf_ptr(node->data.continue_expr.name)); - } - break; - } - case NodeTypeUnreachable: - { - fprintf(ar->f, "unreachable"); - break; - } - case NodeTypeSliceExpr: - { - render_node_ungrouped(ar, node->data.slice_expr.array_ref_expr); - fprintf(ar->f, "["); - render_node_grouped(ar, node->data.slice_expr.start); - fprintf(ar->f, ".."); - if (node->data.slice_expr.end) - render_node_grouped(ar, node->data.slice_expr.end); - fprintf(ar->f, "]"); - break; - } - case NodeTypeCatchExpr: - { - render_node_ungrouped(ar, node->data.unwrap_err_expr.op1); - fprintf(ar->f, " catch "); - if (node->data.unwrap_err_expr.symbol) { - Buf *var_name = node->data.unwrap_err_expr.symbol->data.symbol_expr.symbol; - fprintf(ar->f, "|%s| ", buf_ptr(var_name)); - } - render_node_ungrouped(ar, node->data.unwrap_err_expr.op2); - break; - } - case NodeTypeErrorSetDecl: - { - fprintf(ar->f, "error {\n"); - ar->indent += ar->indent_size; - - for (size_t i = 0; i < node->data.err_set_decl.decls.length; i += 1) { - AstNode *field_node = node->data.err_set_decl.decls.at(i); - switch (field_node->type) { - case NodeTypeSymbol: - print_indent(ar); - print_symbol(ar, field_node->data.symbol_expr.symbol); - fprintf(ar->f, ",\n"); - break; - case NodeTypeErrorSetField: - print_indent(ar); - print_symbol(ar, field_node->data.err_set_field.field_name->data.symbol_expr.symbol); - fprintf(ar->f, ",\n"); - break; - default: - zig_unreachable(); - } - } - - ar->indent -= ar->indent_size; - print_indent(ar); - fprintf(ar->f, "}"); - break; - } - case NodeTypeResume: - { - fprintf(ar->f, "resume "); - render_node_grouped(ar, node->data.resume_expr.expr); - break; - } - case NodeTypeAwaitExpr: - { - fprintf(ar->f, "await "); - render_node_grouped(ar, node->data.await_expr.expr); - break; - } - case NodeTypeSuspend: - { - if (node->data.suspend.block != nullptr) { - fprintf(ar->f, "suspend "); - render_node_grouped(ar, node->data.suspend.block); - } else { - fprintf(ar->f, "suspend\n"); - } - break; - } - case NodeTypeEnumLiteral: - { - fprintf(ar->f, ".%s", buf_ptr(&node->data.enum_literal.identifier->data.str_lit.str)); - break; - } - case NodeTypeAnyTypeField: { - fprintf(ar->f, "anytype"); - break; - } - case NodeTypeParamDecl: - case NodeTypeTestDecl: - case NodeTypeStructField: - case NodeTypeUsingNamespace: - case NodeTypeErrorSetField: - zig_panic("TODO more ast rendering"); - } -} - - -void ast_render(FILE *f, AstNode *node, int indent_size) { - AstRender ar = {0}; - ar.f = f; - ar.indent_size = indent_size; - ar.indent = 0; - - render_node_grouped(&ar, node); -} - -void AstNode::src() { - fprintf(stderr, "%s:%" ZIG_PRI_usize ":%" ZIG_PRI_usize "\n", - buf_ptr(this->owner->data.structure.root_struct->path), - this->line + 1, this->column + 1); -} diff --git a/src/stage1/ast_render.hpp b/src/stage1/ast_render.hpp deleted file mode 100644 index cf70b04694..0000000000 --- a/src/stage1/ast_render.hpp +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2015 Andrew Kelley - * - * This file is part of zig, which is MIT licensed. - * See http://opensource.org/licenses/MIT - */ - -#ifndef ZIG_AST_RENDER_HPP -#define ZIG_AST_RENDER_HPP - -#include "all_types.hpp" -#include "parser.hpp" - -#include - -void ast_print(FILE *f, AstNode *node, int indent); - -void ast_render(FILE *f, AstNode *node, int indent_size); - -#endif diff --git a/src/stage1/astgen.cpp b/src/stage1/astgen.cpp new file mode 100644 index 0000000000..94ade4bebc --- /dev/null +++ b/src/stage1/astgen.cpp @@ -0,0 +1,8120 @@ +/* + * Copyright (c) 2021 Andrew Kelley + * + * This file is part of zig, which is MIT licensed. + * See http://opensource.org/licenses/MIT + */ + +#include "astgen.hpp" +#include "analyze.hpp" +#include "util.hpp" +#include "os.hpp" +#include "parser.hpp" + +static IrInstSrc *ir_gen_node(IrBuilderSrc *irb, AstNode *node, Scope *scope); +static IrInstSrc *ir_gen_node_extra(IrBuilderSrc *irb, AstNode *node, Scope *scope, LVal lval, + ResultLoc *result_loc); + +static IrInstSrc *ir_lval_wrap(IrBuilderSrc *irb, Scope *scope, IrInstSrc *value, LVal lval, + ResultLoc *result_loc); +static IrInstSrc *ir_expr_wrap(IrBuilderSrc *irb, Scope *scope, IrInstSrc *inst, + ResultLoc *result_loc); +static IrInstSrc *ir_gen_union_init_expr(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, + IrInstSrc *union_type, IrInstSrc *field_name, AstNode *expr_node, + LVal lval, ResultLoc *parent_result_loc); +static ResultLocCast *ir_build_cast_result_loc(IrBuilderSrc *irb, IrInstSrc *dest_type, + ResultLoc *parent_result_loc); +static ZigVar *ir_create_var(IrBuilderSrc *irb, AstNode *node, Scope *scope, Buf *name, + bool src_is_const, bool gen_is_const, bool is_shadowable, IrInstSrc *is_comptime); +static void build_decl_var_and_init(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, + ZigVar *var, IrInstSrc *init, const char *name_hint, IrInstSrc *is_comptime); + +static void ir_assert_impl(bool ok, IrInst *source_instruction, char const *file, unsigned int line) { + if (ok) return; + src_assert_impl(ok, source_instruction->source_node, file, line); +} + +static void ir_add_call_stack_errors(CodeGen *codegen, IrExecutableSrc *exec, ErrorMsg *err_msg, int limit) { + if (!exec || !exec->source_node || limit < 0) return; + add_error_note(codegen, err_msg, exec->source_node, buf_sprintf("called from here")); + + ir_add_call_stack_errors_gen(codegen, exec->parent_exec, err_msg, limit - 1); +} + +static ErrorMsg *exec_add_error_node(CodeGen *codegen, IrExecutableSrc *exec, AstNode *source_node, Buf *msg) { + ErrorMsg *err_msg = add_node_error(codegen, source_node, msg); + invalidate_exec(exec, err_msg); + if (exec->parent_exec) { + ir_add_call_stack_errors(codegen, exec, err_msg, 10); + } + return err_msg; +} + + +#define ir_assert(OK, SOURCE_INSTRUCTION) ir_assert_impl((OK), (SOURCE_INSTRUCTION), __FILE__, __LINE__) + + +static bool instr_is_unreachable(IrInstSrc *instruction) { + return instruction->is_noreturn; +} + +void destroy_instruction_src(IrInstSrc *inst) { + switch (inst->id) { + case IrInstSrcIdInvalid: + zig_unreachable(); + case IrInstSrcIdReturn: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdConst: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdBinOp: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdMergeErrSets: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdDeclVar: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdCall: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdCallExtra: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdAsyncCallExtra: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdUnOp: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdCondBr: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdBr: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdPhi: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdContainerInitList: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdContainerInitFields: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdUnreachable: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdElemPtr: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdVarPtr: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdLoadPtr: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdStorePtr: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdTypeOf: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdFieldPtr: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdSetCold: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdSetRuntimeSafety: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdSetFloatMode: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdArrayType: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdSliceType: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdAnyFrameType: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdAsm: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdSizeOf: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdTestNonNull: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdOptionalUnwrapPtr: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdPopCount: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdClz: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdCtz: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdBswap: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdBitReverse: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdSwitchBr: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdSwitchVar: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdSwitchElseVar: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdSwitchTarget: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdImport: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdRef: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdCompileErr: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdCompileLog: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdErrName: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdCImport: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdCInclude: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdCDefine: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdCUndef: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdEmbedFile: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdCmpxchg: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdFence: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdReduce: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdTruncate: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdIntCast: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdFloatCast: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdErrSetCast: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdIntToFloat: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdFloatToInt: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdBoolToInt: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdVectorType: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdShuffleVector: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdSplat: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdBoolNot: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdMemset: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdMemcpy: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdSlice: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdBreakpoint: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdReturnAddress: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdFrameAddress: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdFrameHandle: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdFrameType: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdFrameSize: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdAlignOf: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdOverflowOp: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdTestErr: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdUnwrapErrCode: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdUnwrapErrPayload: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdFnProto: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdTestComptime: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdPtrCast: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdBitCast: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdPtrToInt: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdIntToPtr: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdIntToEnum: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdIntToErr: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdErrToInt: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdCheckSwitchProngsUnderNo: + case IrInstSrcIdCheckSwitchProngsUnderYes: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdCheckStatementIsVoid: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdTypeName: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdTagName: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdPtrType: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdPtrTypeSimple: + case IrInstSrcIdPtrTypeSimpleConst: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdDeclRef: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdPanic: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdFieldParentPtr: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdByteOffsetOf: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdBitOffsetOf: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdTypeInfo: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdType: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdHasField: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdSetEvalBranchQuota: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdAlignCast: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdImplicitCast: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdResolveResult: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdResetResult: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdSetAlignStack: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdArgTypeAllowVarFalse: + case IrInstSrcIdArgTypeAllowVarTrue: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdExport: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdExtern: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdErrorReturnTrace: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdErrorUnion: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdAtomicRmw: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdSaveErrRetAddr: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdAddImplicitReturnType: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdFloatOp: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdMulAdd: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdAtomicLoad: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdAtomicStore: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdEnumToInt: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdCheckRuntimeScope: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdHasDecl: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdUndeclaredIdent: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdAlloca: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdEndExpr: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdUnionInitNamedField: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdSuspendBegin: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdSuspendFinish: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdResume: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdAwait: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdSpillBegin: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdSpillEnd: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdCallArgs: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdWasmMemorySize: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdWasmMemoryGrow: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + case IrInstSrcIdSrc: + return heap::c_allocator.destroy(reinterpret_cast(inst)); + } + zig_unreachable(); +} + + +bool ir_should_inline(IrExecutableSrc *exec, Scope *scope) { + if (exec->is_inline) + return true; + + while (scope != nullptr) { + if (scope->id == ScopeIdCompTime) + return true; + if (scope->id == ScopeIdTypeOf) + return false; + if (scope->id == ScopeIdFnDef) + break; + scope = scope->parent; + } + return false; +} + +static void ir_instruction_append(IrBasicBlockSrc *basic_block, IrInstSrc *instruction) { + assert(basic_block); + assert(instruction); + basic_block->instruction_list.append(instruction); +} + +static size_t exec_next_debug_id(IrExecutableSrc *exec) { + size_t result = exec->next_debug_id; + exec->next_debug_id += 1; + return result; +} + +static ZigFn *exec_fn_entry(IrExecutableSrc *exec) { + return exec->fn_entry; +} + +static Buf *exec_c_import_buf(IrExecutableSrc *exec) { + return exec->c_import_buf; +} + +static void ir_ref_bb(IrBasicBlockSrc *bb) { + bb->ref_count += 1; +} + +static void ir_ref_instruction(IrInstSrc *instruction, IrBasicBlockSrc *cur_bb) { + assert(instruction->id != IrInstSrcIdInvalid); + instruction->base.ref_count += 1; + if (instruction->owner_bb != cur_bb && !instr_is_unreachable(instruction) + && instruction->id != IrInstSrcIdConst) + { + ir_ref_bb(instruction->owner_bb); + } +} + +static IrBasicBlockSrc *ir_create_basic_block(IrBuilderSrc *irb, Scope *scope, const char *name_hint) { + IrBasicBlockSrc *result = heap::c_allocator.create(); + result->scope = scope; + result->name_hint = name_hint; + result->debug_id = exec_next_debug_id(irb->exec); + result->index = UINT32_MAX; // set later + return result; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcDeclVar *) { + return IrInstSrcIdDeclVar; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcBr *) { + return IrInstSrcIdBr; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcCondBr *) { + return IrInstSrcIdCondBr; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcSwitchBr *) { + return IrInstSrcIdSwitchBr; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcSwitchVar *) { + return IrInstSrcIdSwitchVar; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcSwitchElseVar *) { + return IrInstSrcIdSwitchElseVar; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcSwitchTarget *) { + return IrInstSrcIdSwitchTarget; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcPhi *) { + return IrInstSrcIdPhi; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcUnOp *) { + return IrInstSrcIdUnOp; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcBinOp *) { + return IrInstSrcIdBinOp; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcMergeErrSets *) { + return IrInstSrcIdMergeErrSets; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcLoadPtr *) { + return IrInstSrcIdLoadPtr; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcStorePtr *) { + return IrInstSrcIdStorePtr; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcFieldPtr *) { + return IrInstSrcIdFieldPtr; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcElemPtr *) { + return IrInstSrcIdElemPtr; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcVarPtr *) { + return IrInstSrcIdVarPtr; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcCall *) { + return IrInstSrcIdCall; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcCallArgs *) { + return IrInstSrcIdCallArgs; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcCallExtra *) { + return IrInstSrcIdCallExtra; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcAsyncCallExtra *) { + return IrInstSrcIdAsyncCallExtra; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcConst *) { + return IrInstSrcIdConst; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcReturn *) { + return IrInstSrcIdReturn; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcContainerInitList *) { + return IrInstSrcIdContainerInitList; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcContainerInitFields *) { + return IrInstSrcIdContainerInitFields; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcUnreachable *) { + return IrInstSrcIdUnreachable; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcTypeOf *) { + return IrInstSrcIdTypeOf; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcSetCold *) { + return IrInstSrcIdSetCold; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcSetRuntimeSafety *) { + return IrInstSrcIdSetRuntimeSafety; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcSetFloatMode *) { + return IrInstSrcIdSetFloatMode; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcArrayType *) { + return IrInstSrcIdArrayType; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcAnyFrameType *) { + return IrInstSrcIdAnyFrameType; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcSliceType *) { + return IrInstSrcIdSliceType; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcAsm *) { + return IrInstSrcIdAsm; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcSizeOf *) { + return IrInstSrcIdSizeOf; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcTestNonNull *) { + return IrInstSrcIdTestNonNull; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcOptionalUnwrapPtr *) { + return IrInstSrcIdOptionalUnwrapPtr; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcClz *) { + return IrInstSrcIdClz; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcCtz *) { + return IrInstSrcIdCtz; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcPopCount *) { + return IrInstSrcIdPopCount; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcBswap *) { + return IrInstSrcIdBswap; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcBitReverse *) { + return IrInstSrcIdBitReverse; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcImport *) { + return IrInstSrcIdImport; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcCImport *) { + return IrInstSrcIdCImport; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcCInclude *) { + return IrInstSrcIdCInclude; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcCDefine *) { + return IrInstSrcIdCDefine; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcCUndef *) { + return IrInstSrcIdCUndef; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcRef *) { + return IrInstSrcIdRef; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcCompileErr *) { + return IrInstSrcIdCompileErr; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcCompileLog *) { + return IrInstSrcIdCompileLog; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcErrName *) { + return IrInstSrcIdErrName; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcEmbedFile *) { + return IrInstSrcIdEmbedFile; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcCmpxchg *) { + return IrInstSrcIdCmpxchg; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcFence *) { + return IrInstSrcIdFence; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcReduce *) { + return IrInstSrcIdReduce; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcTruncate *) { + return IrInstSrcIdTruncate; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcIntCast *) { + return IrInstSrcIdIntCast; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcFloatCast *) { + return IrInstSrcIdFloatCast; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcIntToFloat *) { + return IrInstSrcIdIntToFloat; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcFloatToInt *) { + return IrInstSrcIdFloatToInt; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcBoolToInt *) { + return IrInstSrcIdBoolToInt; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcVectorType *) { + return IrInstSrcIdVectorType; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcShuffleVector *) { + return IrInstSrcIdShuffleVector; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcSplat *) { + return IrInstSrcIdSplat; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcBoolNot *) { + return IrInstSrcIdBoolNot; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcMemset *) { + return IrInstSrcIdMemset; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcMemcpy *) { + return IrInstSrcIdMemcpy; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcSlice *) { + return IrInstSrcIdSlice; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcBreakpoint *) { + return IrInstSrcIdBreakpoint; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcReturnAddress *) { + return IrInstSrcIdReturnAddress; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcFrameAddress *) { + return IrInstSrcIdFrameAddress; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcFrameHandle *) { + return IrInstSrcIdFrameHandle; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcFrameType *) { + return IrInstSrcIdFrameType; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcFrameSize *) { + return IrInstSrcIdFrameSize; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcAlignOf *) { + return IrInstSrcIdAlignOf; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcOverflowOp *) { + return IrInstSrcIdOverflowOp; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcTestErr *) { + return IrInstSrcIdTestErr; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcMulAdd *) { + return IrInstSrcIdMulAdd; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcFloatOp *) { + return IrInstSrcIdFloatOp; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcUnwrapErrCode *) { + return IrInstSrcIdUnwrapErrCode; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcUnwrapErrPayload *) { + return IrInstSrcIdUnwrapErrPayload; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcFnProto *) { + return IrInstSrcIdFnProto; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcTestComptime *) { + return IrInstSrcIdTestComptime; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcPtrCast *) { + return IrInstSrcIdPtrCast; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcBitCast *) { + return IrInstSrcIdBitCast; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcIntToPtr *) { + return IrInstSrcIdIntToPtr; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcPtrToInt *) { + return IrInstSrcIdPtrToInt; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcIntToEnum *) { + return IrInstSrcIdIntToEnum; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcEnumToInt *) { + return IrInstSrcIdEnumToInt; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcIntToErr *) { + return IrInstSrcIdIntToErr; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcErrToInt *) { + return IrInstSrcIdErrToInt; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcCheckStatementIsVoid *) { + return IrInstSrcIdCheckStatementIsVoid; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcTypeName *) { + return IrInstSrcIdTypeName; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcDeclRef *) { + return IrInstSrcIdDeclRef; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcPanic *) { + return IrInstSrcIdPanic; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcTagName *) { + return IrInstSrcIdTagName; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcFieldParentPtr *) { + return IrInstSrcIdFieldParentPtr; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcByteOffsetOf *) { + return IrInstSrcIdByteOffsetOf; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcBitOffsetOf *) { + return IrInstSrcIdBitOffsetOf; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcTypeInfo *) { + return IrInstSrcIdTypeInfo; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcType *) { + return IrInstSrcIdType; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcHasField *) { + return IrInstSrcIdHasField; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcSetEvalBranchQuota *) { + return IrInstSrcIdSetEvalBranchQuota; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcPtrType *) { + return IrInstSrcIdPtrType; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcAlignCast *) { + return IrInstSrcIdAlignCast; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcImplicitCast *) { + return IrInstSrcIdImplicitCast; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcResolveResult *) { + return IrInstSrcIdResolveResult; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcResetResult *) { + return IrInstSrcIdResetResult; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcSetAlignStack *) { + return IrInstSrcIdSetAlignStack; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcExport *) { + return IrInstSrcIdExport; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcExtern *) { + return IrInstSrcIdExtern; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcErrorReturnTrace *) { + return IrInstSrcIdErrorReturnTrace; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcErrorUnion *) { + return IrInstSrcIdErrorUnion; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcAtomicRmw *) { + return IrInstSrcIdAtomicRmw; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcAtomicLoad *) { + return IrInstSrcIdAtomicLoad; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcAtomicStore *) { + return IrInstSrcIdAtomicStore; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcSaveErrRetAddr *) { + return IrInstSrcIdSaveErrRetAddr; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcAddImplicitReturnType *) { + return IrInstSrcIdAddImplicitReturnType; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcErrSetCast *) { + return IrInstSrcIdErrSetCast; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcCheckRuntimeScope *) { + return IrInstSrcIdCheckRuntimeScope; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcHasDecl *) { + return IrInstSrcIdHasDecl; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcUndeclaredIdent *) { + return IrInstSrcIdUndeclaredIdent; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcAlloca *) { + return IrInstSrcIdAlloca; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcEndExpr *) { + return IrInstSrcIdEndExpr; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcUnionInitNamedField *) { + return IrInstSrcIdUnionInitNamedField; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcSuspendBegin *) { + return IrInstSrcIdSuspendBegin; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcSuspendFinish *) { + return IrInstSrcIdSuspendFinish; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcAwait *) { + return IrInstSrcIdAwait; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcResume *) { + return IrInstSrcIdResume; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcSpillBegin *) { + return IrInstSrcIdSpillBegin; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcSpillEnd *) { + return IrInstSrcIdSpillEnd; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcWasmMemorySize *) { + return IrInstSrcIdWasmMemorySize; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcWasmMemoryGrow *) { + return IrInstSrcIdWasmMemoryGrow; +} + +static constexpr IrInstSrcId ir_inst_id(IrInstSrcSrc *) { + return IrInstSrcIdSrc; +} + +template +static T *ir_create_instruction(IrBuilderSrc *irb, Scope *scope, AstNode *source_node) { + T *special_instruction = heap::c_allocator.create(); + special_instruction->base.id = ir_inst_id(special_instruction); + special_instruction->base.base.scope = scope; + special_instruction->base.base.source_node = source_node; + special_instruction->base.base.debug_id = exec_next_debug_id(irb->exec); + special_instruction->base.owner_bb = irb->current_basic_block; + return special_instruction; +} + +template +static T *ir_build_instruction(IrBuilderSrc *irb, Scope *scope, AstNode *source_node) { + T *special_instruction = ir_create_instruction(irb, scope, source_node); + ir_instruction_append(irb->current_basic_block, &special_instruction->base); + return special_instruction; +} + +static IrInstSrc *ir_build_cond_br(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrInstSrc *condition, + IrBasicBlockSrc *then_block, IrBasicBlockSrc *else_block, IrInstSrc *is_comptime) +{ + IrInstSrcCondBr *inst = ir_build_instruction(irb, scope, source_node); + inst->base.is_noreturn = true; + inst->condition = condition; + inst->then_block = then_block; + inst->else_block = else_block; + inst->is_comptime = is_comptime; + + ir_ref_instruction(condition, irb->current_basic_block); + ir_ref_bb(then_block); + ir_ref_bb(else_block); + if (is_comptime != nullptr) ir_ref_instruction(is_comptime, irb->current_basic_block); + + return &inst->base; +} + +static IrInstSrc *ir_build_return_src(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrInstSrc *operand) { + IrInstSrcReturn *inst = ir_build_instruction(irb, scope, source_node); + inst->base.is_noreturn = true; + inst->operand = operand; + + if (operand != nullptr) ir_ref_instruction(operand, irb->current_basic_block); + + return &inst->base; +} + +static IrInstSrc *ir_build_const_void(IrBuilderSrc *irb, Scope *scope, AstNode *source_node) { + IrInstSrcConst *const_instruction = ir_create_instruction(irb, scope, source_node); + ir_instruction_append(irb->current_basic_block, &const_instruction->base); + const_instruction->value = irb->codegen->intern.for_void(); + return &const_instruction->base; +} + +static IrInstSrc *ir_build_const_undefined(IrBuilderSrc *irb, Scope *scope, AstNode *source_node) { + IrInstSrcConst *const_instruction = ir_create_instruction(irb, scope, source_node); + ir_instruction_append(irb->current_basic_block, &const_instruction->base); + const_instruction->value = irb->codegen->intern.for_undefined(); + const_instruction->value->special = ConstValSpecialUndef; + return &const_instruction->base; +} + +static IrInstSrc *ir_build_const_uint(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, uint64_t value) { + IrInstSrcConst *const_instruction = ir_build_instruction(irb, scope, source_node); + const_instruction->value = irb->codegen->pass1_arena->create(); + const_instruction->value->type = irb->codegen->builtin_types.entry_num_lit_int; + const_instruction->value->special = ConstValSpecialStatic; + bigint_init_unsigned(&const_instruction->value->data.x_bigint, value); + return &const_instruction->base; +} + +static IrInstSrc *ir_build_const_bigint(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, + BigInt bigint) +{ + IrInstSrcConst *const_instruction = ir_build_instruction(irb, scope, source_node); + const_instruction->value = irb->codegen->pass1_arena->create(); + const_instruction->value->type = irb->codegen->builtin_types.entry_num_lit_int; + const_instruction->value->special = ConstValSpecialStatic; + const_instruction->value->data.x_bigint = bigint; + return &const_instruction->base; +} + +static IrInstSrc *ir_build_const_bigfloat(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, + BigFloat bigfloat) +{ + IrInstSrcConst *const_instruction = ir_build_instruction(irb, scope, source_node); + const_instruction->value = irb->codegen->pass1_arena->create(); + const_instruction->value->type = irb->codegen->builtin_types.entry_num_lit_float; + const_instruction->value->special = ConstValSpecialStatic; + const_instruction->value->data.x_bigfloat = bigfloat; + return &const_instruction->base; +} + +static IrInstSrc *ir_build_const_null(IrBuilderSrc *irb, Scope *scope, AstNode *source_node) { + IrInstSrcConst *const_instruction = ir_create_instruction(irb, scope, source_node); + ir_instruction_append(irb->current_basic_block, &const_instruction->base); + const_instruction->value = irb->codegen->intern.for_null(); + return &const_instruction->base; +} + +static IrInstSrc *ir_build_const_usize(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, uint64_t value) { + IrInstSrcConst *const_instruction = ir_build_instruction(irb, scope, source_node); + const_instruction->value = irb->codegen->pass1_arena->create(); + const_instruction->value->type = irb->codegen->builtin_types.entry_usize; + const_instruction->value->special = ConstValSpecialStatic; + bigint_init_unsigned(&const_instruction->value->data.x_bigint, value); + return &const_instruction->base; +} + +static IrInstSrc *ir_create_const_type(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, + ZigType *type_entry) +{ + IrInstSrcConst *const_instruction = ir_create_instruction(irb, scope, source_node); + const_instruction->value = irb->codegen->pass1_arena->create(); + const_instruction->value->type = irb->codegen->builtin_types.entry_type; + const_instruction->value->special = ConstValSpecialStatic; + const_instruction->value->data.x_type = type_entry; + return &const_instruction->base; +} + +static IrInstSrc *ir_build_const_type(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, + ZigType *type_entry) +{ + IrInstSrc *instruction = ir_create_const_type(irb, scope, source_node, type_entry); + ir_instruction_append(irb->current_basic_block, instruction); + return instruction; +} + +static IrInstSrc *ir_build_const_import(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, ZigType *import) { + IrInstSrcConst *const_instruction = ir_build_instruction(irb, scope, source_node); + const_instruction->value = irb->codegen->pass1_arena->create(); + const_instruction->value->type = irb->codegen->builtin_types.entry_type; + const_instruction->value->special = ConstValSpecialStatic; + const_instruction->value->data.x_type = import; + return &const_instruction->base; +} + +static IrInstSrc *ir_build_const_bool(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, bool value) { + IrInstSrcConst *const_instruction = ir_build_instruction(irb, scope, source_node); + const_instruction->value = irb->codegen->pass1_arena->create(); + const_instruction->value->type = irb->codegen->builtin_types.entry_bool; + const_instruction->value->special = ConstValSpecialStatic; + const_instruction->value->data.x_bool = value; + return &const_instruction->base; +} + +static IrInstSrc *ir_build_const_enum_literal(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, Buf *name) { + IrInstSrcConst *const_instruction = ir_build_instruction(irb, scope, source_node); + const_instruction->value = irb->codegen->pass1_arena->create(); + const_instruction->value->type = irb->codegen->builtin_types.entry_enum_literal; + const_instruction->value->special = ConstValSpecialStatic; + const_instruction->value->data.x_enum_literal = name; + return &const_instruction->base; +} + +// Consumes `str`. +static IrInstSrc *ir_create_const_str_lit(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, Buf *str) { + IrInstSrcConst *const_instruction = ir_create_instruction(irb, scope, source_node); + const_instruction->value = irb->codegen->pass1_arena->create(); + init_const_str_lit(irb->codegen, const_instruction->value, str, true); + + return &const_instruction->base; +} + +// Consumes `str`. +static IrInstSrc *ir_build_const_str_lit(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, Buf *str) { + IrInstSrc *instruction = ir_create_const_str_lit(irb, scope, source_node, str); + ir_instruction_append(irb->current_basic_block, instruction); + return instruction; +} + +static IrInstSrc *ir_build_bin_op(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrBinOp op_id, + IrInstSrc *op1, IrInstSrc *op2, bool safety_check_on) +{ + IrInstSrcBinOp *inst = ir_build_instruction(irb, scope, source_node); + inst->op_id = op_id; + inst->op1 = op1; + inst->op2 = op2; + inst->safety_check_on = safety_check_on; + + ir_ref_instruction(op1, irb->current_basic_block); + ir_ref_instruction(op2, irb->current_basic_block); + + return &inst->base; +} + +static IrInstSrc *ir_build_merge_err_sets(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, + IrInstSrc *op1, IrInstSrc *op2, Buf *type_name) +{ + IrInstSrcMergeErrSets *inst = ir_build_instruction(irb, scope, source_node); + inst->op1 = op1; + inst->op2 = op2; + inst->type_name = type_name; + + ir_ref_instruction(op1, irb->current_basic_block); + ir_ref_instruction(op2, irb->current_basic_block); + + return &inst->base; +} + +static IrInstSrc *ir_build_var_ptr_x(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, ZigVar *var, + ScopeFnDef *crossed_fndef_scope) +{ + IrInstSrcVarPtr *instruction = ir_build_instruction(irb, scope, source_node); + instruction->var = var; + instruction->crossed_fndef_scope = crossed_fndef_scope; + + var->ref_count += 1; + + return &instruction->base; +} + +static IrInstSrc *ir_build_var_ptr(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, ZigVar *var) { + return ir_build_var_ptr_x(irb, scope, source_node, var, nullptr); +} + +static IrInstSrc *ir_build_elem_ptr(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, + IrInstSrc *array_ptr, IrInstSrc *elem_index, bool safety_check_on, PtrLen ptr_len, + AstNode *init_array_type_source_node) +{ + IrInstSrcElemPtr *instruction = ir_build_instruction(irb, scope, source_node); + instruction->array_ptr = array_ptr; + instruction->elem_index = elem_index; + instruction->safety_check_on = safety_check_on; + instruction->ptr_len = ptr_len; + instruction->init_array_type_source_node = init_array_type_source_node; + + ir_ref_instruction(array_ptr, irb->current_basic_block); + ir_ref_instruction(elem_index, irb->current_basic_block); + + return &instruction->base; +} + +static IrInstSrc *ir_build_field_ptr_instruction(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, + IrInstSrc *container_ptr, IrInstSrc *field_name_expr, bool initializing) +{ + IrInstSrcFieldPtr *instruction = ir_build_instruction(irb, scope, source_node); + instruction->container_ptr = container_ptr; + instruction->field_name_buffer = nullptr; + instruction->field_name_expr = field_name_expr; + instruction->initializing = initializing; + + ir_ref_instruction(container_ptr, irb->current_basic_block); + ir_ref_instruction(field_name_expr, irb->current_basic_block); + + return &instruction->base; +} + +static IrInstSrc *ir_build_field_ptr(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, + IrInstSrc *container_ptr, Buf *field_name, bool initializing) +{ + IrInstSrcFieldPtr *instruction = ir_build_instruction(irb, scope, source_node); + instruction->container_ptr = container_ptr; + instruction->field_name_buffer = field_name; + instruction->field_name_expr = nullptr; + instruction->initializing = initializing; + + ir_ref_instruction(container_ptr, irb->current_basic_block); + + return &instruction->base; +} + +static IrInstSrc *ir_build_has_field(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, + IrInstSrc *container_type, IrInstSrc *field_name) +{ + IrInstSrcHasField *instruction = ir_build_instruction(irb, scope, source_node); + instruction->container_type = container_type; + instruction->field_name = field_name; + + ir_ref_instruction(container_type, irb->current_basic_block); + ir_ref_instruction(field_name, irb->current_basic_block); + + return &instruction->base; +} + +static IrInstSrc *ir_build_call_extra(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, + IrInstSrc *options, IrInstSrc *fn_ref, IrInstSrc *args, ResultLoc *result_loc) +{ + IrInstSrcCallExtra *call_instruction = ir_build_instruction(irb, scope, source_node); + call_instruction->options = options; + call_instruction->fn_ref = fn_ref; + call_instruction->args = args; + call_instruction->result_loc = result_loc; + + ir_ref_instruction(options, irb->current_basic_block); + ir_ref_instruction(fn_ref, irb->current_basic_block); + ir_ref_instruction(args, irb->current_basic_block); + + return &call_instruction->base; +} + +static IrInstSrc *ir_build_async_call_extra(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, + CallModifier modifier, IrInstSrc *fn_ref, IrInstSrc *ret_ptr, IrInstSrc *new_stack, IrInstSrc *args, ResultLoc *result_loc) +{ + IrInstSrcAsyncCallExtra *call_instruction = ir_build_instruction(irb, scope, source_node); + call_instruction->modifier = modifier; + call_instruction->fn_ref = fn_ref; + call_instruction->ret_ptr = ret_ptr; + call_instruction->new_stack = new_stack; + call_instruction->args = args; + call_instruction->result_loc = result_loc; + + ir_ref_instruction(fn_ref, irb->current_basic_block); + if (ret_ptr != nullptr) ir_ref_instruction(ret_ptr, irb->current_basic_block); + ir_ref_instruction(new_stack, irb->current_basic_block); + ir_ref_instruction(args, irb->current_basic_block); + + return &call_instruction->base; +} + +static IrInstSrc *ir_build_call_args(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, + IrInstSrc *options, IrInstSrc *fn_ref, IrInstSrc **args_ptr, size_t args_len, + ResultLoc *result_loc) +{ + IrInstSrcCallArgs *call_instruction = ir_build_instruction(irb, scope, source_node); + call_instruction->options = options; + call_instruction->fn_ref = fn_ref; + call_instruction->args_ptr = args_ptr; + call_instruction->args_len = args_len; + call_instruction->result_loc = result_loc; + + ir_ref_instruction(options, irb->current_basic_block); + ir_ref_instruction(fn_ref, irb->current_basic_block); + for (size_t i = 0; i < args_len; i += 1) + ir_ref_instruction(args_ptr[i], irb->current_basic_block); + + return &call_instruction->base; +} + +static IrInstSrc *ir_build_call_src(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, + ZigFn *fn_entry, IrInstSrc *fn_ref, size_t arg_count, IrInstSrc **args, + IrInstSrc *ret_ptr, CallModifier modifier, bool is_async_call_builtin, + IrInstSrc *new_stack, ResultLoc *result_loc) +{ + IrInstSrcCall *call_instruction = ir_build_instruction(irb, scope, source_node); + call_instruction->fn_entry = fn_entry; + call_instruction->fn_ref = fn_ref; + call_instruction->args = args; + call_instruction->arg_count = arg_count; + call_instruction->modifier = modifier; + call_instruction->is_async_call_builtin = is_async_call_builtin; + call_instruction->new_stack = new_stack; + call_instruction->result_loc = result_loc; + call_instruction->ret_ptr = ret_ptr; + + if (fn_ref != nullptr) ir_ref_instruction(fn_ref, irb->current_basic_block); + for (size_t i = 0; i < arg_count; i += 1) + ir_ref_instruction(args[i], irb->current_basic_block); + if (ret_ptr != nullptr) ir_ref_instruction(ret_ptr, irb->current_basic_block); + if (new_stack != nullptr) ir_ref_instruction(new_stack, irb->current_basic_block); + + return &call_instruction->base; +} + +static IrInstSrc *ir_build_phi(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, + size_t incoming_count, IrBasicBlockSrc **incoming_blocks, IrInstSrc **incoming_values, + ResultLocPeerParent *peer_parent) +{ + assert(incoming_count != 0); + assert(incoming_count != SIZE_MAX); + + IrInstSrcPhi *phi_instruction = ir_build_instruction(irb, scope, source_node); + phi_instruction->incoming_count = incoming_count; + phi_instruction->incoming_blocks = incoming_blocks; + phi_instruction->incoming_values = incoming_values; + phi_instruction->peer_parent = peer_parent; + + for (size_t i = 0; i < incoming_count; i += 1) { + ir_ref_bb(incoming_blocks[i]); + ir_ref_instruction(incoming_values[i], irb->current_basic_block); + } + + return &phi_instruction->base; +} + +static IrInstSrc *ir_build_br(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, + IrBasicBlockSrc *dest_block, IrInstSrc *is_comptime) +{ + IrInstSrcBr *inst = ir_build_instruction(irb, scope, source_node); + inst->base.is_noreturn = true; + inst->dest_block = dest_block; + inst->is_comptime = is_comptime; + + ir_ref_bb(dest_block); + if (is_comptime) ir_ref_instruction(is_comptime, irb->current_basic_block); + + return &inst->base; +} + +static IrInstSrc *ir_build_ptr_type_simple(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, + IrInstSrc *child_type, bool is_const) +{ + IrInstSrcPtrTypeSimple *inst = heap::c_allocator.create(); + inst->base.id = is_const ? IrInstSrcIdPtrTypeSimpleConst : IrInstSrcIdPtrTypeSimple; + inst->base.base.scope = scope; + inst->base.base.source_node = source_node; + inst->base.base.debug_id = exec_next_debug_id(irb->exec); + inst->base.owner_bb = irb->current_basic_block; + ir_instruction_append(irb->current_basic_block, &inst->base); + + inst->child_type = child_type; + + ir_ref_instruction(child_type, irb->current_basic_block); + + return &inst->base; +} + +static IrInstSrc *ir_build_ptr_type(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, + IrInstSrc *child_type, bool is_const, bool is_volatile, PtrLen ptr_len, + IrInstSrc *sentinel, IrInstSrc *align_value, + uint32_t bit_offset_start, uint32_t host_int_bytes, bool is_allow_zero) +{ + if (!is_volatile && ptr_len == PtrLenSingle && sentinel == nullptr && align_value == nullptr && + bit_offset_start == 0 && host_int_bytes == 0 && is_allow_zero == 0) + { + return ir_build_ptr_type_simple(irb, scope, source_node, child_type, is_const); + } + + IrInstSrcPtrType *inst = ir_build_instruction(irb, scope, source_node); + inst->sentinel = sentinel; + inst->align_value = align_value; + inst->child_type = child_type; + inst->is_const = is_const; + inst->is_volatile = is_volatile; + inst->ptr_len = ptr_len; + inst->bit_offset_start = bit_offset_start; + inst->host_int_bytes = host_int_bytes; + inst->is_allow_zero = is_allow_zero; + + if (sentinel) ir_ref_instruction(sentinel, irb->current_basic_block); + if (align_value) ir_ref_instruction(align_value, irb->current_basic_block); + ir_ref_instruction(child_type, irb->current_basic_block); + + return &inst->base; +} + +static IrInstSrc *ir_build_un_op_lval(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrUnOp op_id, + IrInstSrc *value, LVal lval, ResultLoc *result_loc) +{ + IrInstSrcUnOp *instruction = ir_build_instruction(irb, scope, source_node); + instruction->op_id = op_id; + instruction->value = value; + instruction->lval = lval; + instruction->result_loc = result_loc; + + ir_ref_instruction(value, irb->current_basic_block); + + return &instruction->base; +} + +static IrInstSrc *ir_build_un_op(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrUnOp op_id, + IrInstSrc *value) +{ + return ir_build_un_op_lval(irb, scope, source_node, op_id, value, LValNone, nullptr); +} + +static IrInstSrc *ir_build_container_init_list(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, + size_t item_count, IrInstSrc **elem_result_loc_list, IrInstSrc *result_loc, + AstNode *init_array_type_source_node) +{ + IrInstSrcContainerInitList *container_init_list_instruction = + ir_build_instruction(irb, scope, source_node); + container_init_list_instruction->item_count = item_count; + container_init_list_instruction->elem_result_loc_list = elem_result_loc_list; + container_init_list_instruction->result_loc = result_loc; + container_init_list_instruction->init_array_type_source_node = init_array_type_source_node; + + for (size_t i = 0; i < item_count; i += 1) { + ir_ref_instruction(elem_result_loc_list[i], irb->current_basic_block); + } + if (result_loc != nullptr) ir_ref_instruction(result_loc, irb->current_basic_block); + + return &container_init_list_instruction->base; +} + +static IrInstSrc *ir_build_container_init_fields(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, + size_t field_count, IrInstSrcContainerInitFieldsField *fields, IrInstSrc *result_loc) +{ + IrInstSrcContainerInitFields *container_init_fields_instruction = + ir_build_instruction(irb, scope, source_node); + container_init_fields_instruction->field_count = field_count; + container_init_fields_instruction->fields = fields; + container_init_fields_instruction->result_loc = result_loc; + + for (size_t i = 0; i < field_count; i += 1) { + ir_ref_instruction(fields[i].result_loc, irb->current_basic_block); + } + if (result_loc != nullptr) ir_ref_instruction(result_loc, irb->current_basic_block); + + return &container_init_fields_instruction->base; +} + +static IrInstSrc *ir_build_unreachable(IrBuilderSrc *irb, Scope *scope, AstNode *source_node) { + IrInstSrcUnreachable *inst = ir_build_instruction(irb, scope, source_node); + inst->base.is_noreturn = true; + return &inst->base; +} + +static IrInstSrcStorePtr *ir_build_store_ptr(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, + IrInstSrc *ptr, IrInstSrc *value) +{ + IrInstSrcStorePtr *instruction = ir_build_instruction(irb, scope, source_node); + instruction->ptr = ptr; + instruction->value = value; + + ir_ref_instruction(ptr, irb->current_basic_block); + ir_ref_instruction(value, irb->current_basic_block); + + return instruction; +} + +static IrInstSrc *ir_build_var_decl_src(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, + ZigVar *var, IrInstSrc *align_value, IrInstSrc *ptr) +{ + IrInstSrcDeclVar *inst = ir_build_instruction(irb, scope, source_node); + inst->var = var; + inst->align_value = align_value; + inst->ptr = ptr; + + if (align_value != nullptr) ir_ref_instruction(align_value, irb->current_basic_block); + ir_ref_instruction(ptr, irb->current_basic_block); + + return &inst->base; +} + +static IrInstSrc *ir_build_export(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, + IrInstSrc *target, IrInstSrc *options) +{ + IrInstSrcExport *export_instruction = ir_build_instruction( + irb, scope, source_node); + export_instruction->target = target; + export_instruction->options = options; + + ir_ref_instruction(target, irb->current_basic_block); + ir_ref_instruction(options, irb->current_basic_block); + + return &export_instruction->base; +} + +static IrInstSrc *ir_build_extern(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, + IrInstSrc *type, IrInstSrc *options) +{ + IrInstSrcExtern *extern_instruction = ir_build_instruction( + irb, scope, source_node); + extern_instruction->type = type; + extern_instruction->options = options; + + ir_ref_instruction(type, irb->current_basic_block); + ir_ref_instruction(options, irb->current_basic_block); + + return &extern_instruction->base; +} + +static IrInstSrc *ir_build_load_ptr(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrInstSrc *ptr) { + IrInstSrcLoadPtr *instruction = ir_build_instruction(irb, scope, source_node); + instruction->ptr = ptr; + + ir_ref_instruction(ptr, irb->current_basic_block); + + return &instruction->base; +} + +static IrInstSrc *ir_build_typeof_n(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, + IrInstSrc **values, size_t value_count) +{ + assert(value_count >= 2); + + IrInstSrcTypeOf *instruction = ir_build_instruction(irb, scope, source_node); + instruction->value.list = values; + instruction->value_count = value_count; + + for (size_t i = 0; i < value_count; i++) + ir_ref_instruction(values[i], irb->current_basic_block); + + return &instruction->base; +} + +static IrInstSrc *ir_build_typeof_1(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrInstSrc *value) { + IrInstSrcTypeOf *instruction = ir_build_instruction(irb, scope, source_node); + instruction->value.scalar = value; + + ir_ref_instruction(value, irb->current_basic_block); + + return &instruction->base; +} + +static IrInstSrc *ir_build_set_cold(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrInstSrc *is_cold) { + IrInstSrcSetCold *instruction = ir_build_instruction(irb, scope, source_node); + instruction->is_cold = is_cold; + + ir_ref_instruction(is_cold, irb->current_basic_block); + + return &instruction->base; +} + +static IrInstSrc *ir_build_set_runtime_safety(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, + IrInstSrc *safety_on) +{ + IrInstSrcSetRuntimeSafety *inst = ir_build_instruction(irb, scope, source_node); + inst->safety_on = safety_on; + + ir_ref_instruction(safety_on, irb->current_basic_block); + + return &inst->base; +} + +static IrInstSrc *ir_build_set_float_mode(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, + IrInstSrc *mode_value) +{ + IrInstSrcSetFloatMode *instruction = ir_build_instruction(irb, scope, source_node); + instruction->mode_value = mode_value; + + ir_ref_instruction(mode_value, irb->current_basic_block); + + return &instruction->base; +} + +static IrInstSrc *ir_build_array_type(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrInstSrc *size, + IrInstSrc *sentinel, IrInstSrc *child_type) +{ + IrInstSrcArrayType *instruction = ir_build_instruction(irb, scope, source_node); + instruction->size = size; + instruction->sentinel = sentinel; + instruction->child_type = child_type; + + ir_ref_instruction(size, irb->current_basic_block); + if (sentinel != nullptr) ir_ref_instruction(sentinel, irb->current_basic_block); + ir_ref_instruction(child_type, irb->current_basic_block); + + return &instruction->base; +} + +static IrInstSrc *ir_build_anyframe_type(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, + IrInstSrc *payload_type) +{ + IrInstSrcAnyFrameType *instruction = ir_build_instruction(irb, scope, source_node); + instruction->payload_type = payload_type; + + if (payload_type != nullptr) ir_ref_instruction(payload_type, irb->current_basic_block); + + return &instruction->base; +} + +static IrInstSrc *ir_build_slice_type(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, + IrInstSrc *child_type, bool is_const, bool is_volatile, + IrInstSrc *sentinel, IrInstSrc *align_value, bool is_allow_zero) +{ + IrInstSrcSliceType *instruction = ir_build_instruction(irb, scope, source_node); + instruction->is_const = is_const; + instruction->is_volatile = is_volatile; + instruction->child_type = child_type; + instruction->sentinel = sentinel; + instruction->align_value = align_value; + instruction->is_allow_zero = is_allow_zero; + + if (sentinel != nullptr) ir_ref_instruction(sentinel, irb->current_basic_block); + if (align_value != nullptr) ir_ref_instruction(align_value, irb->current_basic_block); + ir_ref_instruction(child_type, irb->current_basic_block); + + return &instruction->base; +} + +static IrInstSrc *ir_build_asm_src(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, + IrInstSrc *asm_template, IrInstSrc **input_list, IrInstSrc **output_types, + ZigVar **output_vars, size_t return_count, bool has_side_effects, bool is_global) +{ + IrInstSrcAsm *instruction = ir_build_instruction(irb, scope, source_node); + instruction->asm_template = asm_template; + instruction->input_list = input_list; + instruction->output_types = output_types; + instruction->output_vars = output_vars; + instruction->return_count = return_count; + instruction->has_side_effects = has_side_effects; + instruction->is_global = is_global; + + assert(source_node->type == NodeTypeAsmExpr); + for (size_t i = 0; i < source_node->data.asm_expr.output_list.length; i += 1) { + IrInstSrc *output_type = output_types[i]; + if (output_type) ir_ref_instruction(output_type, irb->current_basic_block); + } + + for (size_t i = 0; i < source_node->data.asm_expr.input_list.length; i += 1) { + IrInstSrc *input_value = input_list[i]; + ir_ref_instruction(input_value, irb->current_basic_block); + } + + return &instruction->base; +} + +static IrInstSrc *ir_build_size_of(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrInstSrc *type_value, + bool bit_size) +{ + IrInstSrcSizeOf *instruction = ir_build_instruction(irb, scope, source_node); + instruction->type_value = type_value; + instruction->bit_size = bit_size; + + ir_ref_instruction(type_value, irb->current_basic_block); + + return &instruction->base; +} + +static IrInstSrc *ir_build_test_non_null_src(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, + IrInstSrc *value) +{ + IrInstSrcTestNonNull *instruction = ir_build_instruction(irb, scope, source_node); + instruction->value = value; + + ir_ref_instruction(value, irb->current_basic_block); + + return &instruction->base; +} + +static IrInstSrc *ir_build_optional_unwrap_ptr(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, + IrInstSrc *base_ptr, bool safety_check_on) +{ + IrInstSrcOptionalUnwrapPtr *instruction = ir_build_instruction(irb, scope, source_node); + instruction->base_ptr = base_ptr; + instruction->safety_check_on = safety_check_on; + + ir_ref_instruction(base_ptr, irb->current_basic_block); + + return &instruction->base; +} + +static IrInstSrc *ir_build_clz(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrInstSrc *type, + IrInstSrc *op) +{ + IrInstSrcClz *instruction = ir_build_instruction(irb, scope, source_node); + instruction->type = type; + instruction->op = op; + + ir_ref_instruction(type, irb->current_basic_block); + ir_ref_instruction(op, irb->current_basic_block); + + return &instruction->base; +} + +static IrInstSrc *ir_build_ctz(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrInstSrc *type, + IrInstSrc *op) +{ + IrInstSrcCtz *instruction = ir_build_instruction(irb, scope, source_node); + instruction->type = type; + instruction->op = op; + + ir_ref_instruction(type, irb->current_basic_block); + ir_ref_instruction(op, irb->current_basic_block); + + return &instruction->base; +} + +static IrInstSrc *ir_build_pop_count(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrInstSrc *type, + IrInstSrc *op) +{ + IrInstSrcPopCount *instruction = ir_build_instruction(irb, scope, source_node); + instruction->type = type; + instruction->op = op; + + ir_ref_instruction(type, irb->current_basic_block); + ir_ref_instruction(op, irb->current_basic_block); + + return &instruction->base; +} + +static IrInstSrc *ir_build_bswap(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrInstSrc *type, + IrInstSrc *op) +{ + IrInstSrcBswap *instruction = ir_build_instruction(irb, scope, source_node); + instruction->type = type; + instruction->op = op; + + ir_ref_instruction(type, irb->current_basic_block); + ir_ref_instruction(op, irb->current_basic_block); + + return &instruction->base; +} + +static IrInstSrc *ir_build_bit_reverse(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrInstSrc *type, + IrInstSrc *op) +{ + IrInstSrcBitReverse *instruction = ir_build_instruction(irb, scope, source_node); + instruction->type = type; + instruction->op = op; + + ir_ref_instruction(type, irb->current_basic_block); + ir_ref_instruction(op, irb->current_basic_block); + + return &instruction->base; +} + +static IrInstSrcSwitchBr *ir_build_switch_br_src(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, + IrInstSrc *target_value, IrBasicBlockSrc *else_block, size_t case_count, IrInstSrcSwitchBrCase *cases, + IrInstSrc *is_comptime, IrInstSrc *switch_prongs_void) +{ + IrInstSrcSwitchBr *instruction = ir_build_instruction(irb, scope, source_node); + instruction->base.is_noreturn = true; + instruction->target_value = target_value; + instruction->else_block = else_block; + instruction->case_count = case_count; + instruction->cases = cases; + instruction->is_comptime = is_comptime; + instruction->switch_prongs_void = switch_prongs_void; + + ir_ref_instruction(target_value, irb->current_basic_block); + ir_ref_instruction(is_comptime, irb->current_basic_block); + ir_ref_bb(else_block); + ir_ref_instruction(switch_prongs_void, irb->current_basic_block); + + for (size_t i = 0; i < case_count; i += 1) { + ir_ref_instruction(cases[i].value, irb->current_basic_block); + ir_ref_bb(cases[i].block); + } + + return instruction; +} + +static IrInstSrc *ir_build_switch_target(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, + IrInstSrc *target_value_ptr) +{ + IrInstSrcSwitchTarget *instruction = ir_build_instruction(irb, scope, source_node); + instruction->target_value_ptr = target_value_ptr; + + ir_ref_instruction(target_value_ptr, irb->current_basic_block); + + return &instruction->base; +} + +static IrInstSrc *ir_build_switch_var(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, + IrInstSrc *target_value_ptr, IrInstSrc **prongs_ptr, size_t prongs_len) +{ + IrInstSrcSwitchVar *instruction = ir_build_instruction(irb, scope, source_node); + instruction->target_value_ptr = target_value_ptr; + instruction->prongs_ptr = prongs_ptr; + instruction->prongs_len = prongs_len; + + ir_ref_instruction(target_value_ptr, irb->current_basic_block); + for (size_t i = 0; i < prongs_len; i += 1) { + ir_ref_instruction(prongs_ptr[i], irb->current_basic_block); + } + + return &instruction->base; +} + +// For this instruction the switch_br must be set later. +static IrInstSrcSwitchElseVar *ir_build_switch_else_var(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, + IrInstSrc *target_value_ptr) +{ + IrInstSrcSwitchElseVar *instruction = ir_build_instruction(irb, scope, source_node); + instruction->target_value_ptr = target_value_ptr; + + ir_ref_instruction(target_value_ptr, irb->current_basic_block); + + return instruction; +} + +static IrInstSrc *ir_build_import(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrInstSrc *name) { + IrInstSrcImport *instruction = ir_build_instruction(irb, scope, source_node); + instruction->name = name; + + ir_ref_instruction(name, irb->current_basic_block); + + return &instruction->base; +} + +static IrInstSrc *ir_build_ref_src(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrInstSrc *value) { + IrInstSrcRef *instruction = ir_build_instruction(irb, scope, source_node); + instruction->value = value; + + ir_ref_instruction(value, irb->current_basic_block); + + return &instruction->base; +} + +static IrInstSrc *ir_build_compile_err(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrInstSrc *msg) { + IrInstSrcCompileErr *instruction = ir_build_instruction(irb, scope, source_node); + instruction->msg = msg; + + ir_ref_instruction(msg, irb->current_basic_block); + + return &instruction->base; +} + +static IrInstSrc *ir_build_compile_log(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, + size_t msg_count, IrInstSrc **msg_list) +{ + IrInstSrcCompileLog *instruction = ir_build_instruction(irb, scope, source_node); + instruction->msg_count = msg_count; + instruction->msg_list = msg_list; + + for (size_t i = 0; i < msg_count; i += 1) { + ir_ref_instruction(msg_list[i], irb->current_basic_block); + } + + return &instruction->base; +} + +static IrInstSrc *ir_build_err_name(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrInstSrc *value) { + IrInstSrcErrName *instruction = ir_build_instruction(irb, scope, source_node); + instruction->value = value; + + ir_ref_instruction(value, irb->current_basic_block); + + return &instruction->base; +} + +static IrInstSrc *ir_build_c_import(IrBuilderSrc *irb, Scope *scope, AstNode *source_node) { + IrInstSrcCImport *instruction = ir_build_instruction(irb, scope, source_node); + return &instruction->base; +} + +static IrInstSrc *ir_build_c_include(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrInstSrc *name) { + IrInstSrcCInclude *instruction = ir_build_instruction(irb, scope, source_node); + instruction->name = name; + + ir_ref_instruction(name, irb->current_basic_block); + + return &instruction->base; +} + +static IrInstSrc *ir_build_c_define(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrInstSrc *name, IrInstSrc *value) { + IrInstSrcCDefine *instruction = ir_build_instruction(irb, scope, source_node); + instruction->name = name; + instruction->value = value; + + ir_ref_instruction(name, irb->current_basic_block); + ir_ref_instruction(value, irb->current_basic_block); + + return &instruction->base; +} + +static IrInstSrc *ir_build_c_undef(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrInstSrc *name) { + IrInstSrcCUndef *instruction = ir_build_instruction(irb, scope, source_node); + instruction->name = name; + + ir_ref_instruction(name, irb->current_basic_block); + + return &instruction->base; +} + +static IrInstSrc *ir_build_embed_file(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrInstSrc *name) { + IrInstSrcEmbedFile *instruction = ir_build_instruction(irb, scope, source_node); + instruction->name = name; + + ir_ref_instruction(name, irb->current_basic_block); + + return &instruction->base; +} + +static IrInstSrc *ir_build_cmpxchg_src(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, + IrInstSrc *type_value, IrInstSrc *ptr, IrInstSrc *cmp_value, IrInstSrc *new_value, + IrInstSrc *success_order_value, IrInstSrc *failure_order_value, bool is_weak, ResultLoc *result_loc) +{ + IrInstSrcCmpxchg *instruction = ir_build_instruction(irb, scope, source_node); + instruction->type_value = type_value; + instruction->ptr = ptr; + instruction->cmp_value = cmp_value; + instruction->new_value = new_value; + instruction->success_order_value = success_order_value; + instruction->failure_order_value = failure_order_value; + instruction->is_weak = is_weak; + instruction->result_loc = result_loc; + + ir_ref_instruction(type_value, irb->current_basic_block); + ir_ref_instruction(ptr, irb->current_basic_block); + ir_ref_instruction(cmp_value, irb->current_basic_block); + ir_ref_instruction(new_value, irb->current_basic_block); + ir_ref_instruction(success_order_value, irb->current_basic_block); + ir_ref_instruction(failure_order_value, irb->current_basic_block); + + return &instruction->base; +} + +static IrInstSrc *ir_build_fence(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrInstSrc *order) { + IrInstSrcFence *instruction = ir_build_instruction(irb, scope, source_node); + instruction->order = order; + + ir_ref_instruction(order, irb->current_basic_block); + + return &instruction->base; +} + +static IrInstSrc *ir_build_reduce(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrInstSrc *op, IrInstSrc *value) { + IrInstSrcReduce *instruction = ir_build_instruction(irb, scope, source_node); + instruction->op = op; + instruction->value = value; + + ir_ref_instruction(op, irb->current_basic_block); + ir_ref_instruction(value, irb->current_basic_block); + + return &instruction->base; +} + +static IrInstSrc *ir_build_truncate(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, + IrInstSrc *dest_type, IrInstSrc *target) +{ + IrInstSrcTruncate *instruction = ir_build_instruction(irb, scope, source_node); + instruction->dest_type = dest_type; + instruction->target = target; + + ir_ref_instruction(dest_type, irb->current_basic_block); + ir_ref_instruction(target, irb->current_basic_block); + + return &instruction->base; +} + +static IrInstSrc *ir_build_int_cast(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrInstSrc *dest_type, + IrInstSrc *target) +{ + IrInstSrcIntCast *instruction = ir_build_instruction(irb, scope, source_node); + instruction->dest_type = dest_type; + instruction->target = target; + + ir_ref_instruction(dest_type, irb->current_basic_block); + ir_ref_instruction(target, irb->current_basic_block); + + return &instruction->base; +} + +static IrInstSrc *ir_build_float_cast(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrInstSrc *dest_type, + IrInstSrc *target) +{ + IrInstSrcFloatCast *instruction = ir_build_instruction(irb, scope, source_node); + instruction->dest_type = dest_type; + instruction->target = target; + + ir_ref_instruction(dest_type, irb->current_basic_block); + ir_ref_instruction(target, irb->current_basic_block); + + return &instruction->base; +} + +static IrInstSrc *ir_build_err_set_cast(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, + IrInstSrc *dest_type, IrInstSrc *target) +{ + IrInstSrcErrSetCast *instruction = ir_build_instruction(irb, scope, source_node); + instruction->dest_type = dest_type; + instruction->target = target; + + ir_ref_instruction(dest_type, irb->current_basic_block); + ir_ref_instruction(target, irb->current_basic_block); + + return &instruction->base; +} + +static IrInstSrc *ir_build_int_to_float(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, + IrInstSrc *dest_type, IrInstSrc *target) +{ + IrInstSrcIntToFloat *instruction = ir_build_instruction(irb, scope, source_node); + instruction->dest_type = dest_type; + instruction->target = target; + + ir_ref_instruction(dest_type, irb->current_basic_block); + ir_ref_instruction(target, irb->current_basic_block); + + return &instruction->base; +} + +static IrInstSrc *ir_build_float_to_int(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, + IrInstSrc *dest_type, IrInstSrc *target) +{ + IrInstSrcFloatToInt *instruction = ir_build_instruction(irb, scope, source_node); + instruction->dest_type = dest_type; + instruction->target = target; + + ir_ref_instruction(dest_type, irb->current_basic_block); + ir_ref_instruction(target, irb->current_basic_block); + + return &instruction->base; +} + +static IrInstSrc *ir_build_bool_to_int(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrInstSrc *target) { + IrInstSrcBoolToInt *instruction = ir_build_instruction(irb, scope, source_node); + instruction->target = target; + + ir_ref_instruction(target, irb->current_basic_block); + + return &instruction->base; +} + +static IrInstSrc *ir_build_vector_type(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrInstSrc *len, + IrInstSrc *elem_type) +{ + IrInstSrcVectorType *instruction = ir_build_instruction(irb, scope, source_node); + instruction->len = len; + instruction->elem_type = elem_type; + + ir_ref_instruction(len, irb->current_basic_block); + ir_ref_instruction(elem_type, irb->current_basic_block); + + return &instruction->base; +} + +static IrInstSrc *ir_build_shuffle_vector(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, + IrInstSrc *scalar_type, IrInstSrc *a, IrInstSrc *b, IrInstSrc *mask) +{ + IrInstSrcShuffleVector *instruction = ir_build_instruction(irb, scope, source_node); + instruction->scalar_type = scalar_type; + instruction->a = a; + instruction->b = b; + instruction->mask = mask; + + if (scalar_type != nullptr) ir_ref_instruction(scalar_type, irb->current_basic_block); + ir_ref_instruction(a, irb->current_basic_block); + ir_ref_instruction(b, irb->current_basic_block); + ir_ref_instruction(mask, irb->current_basic_block); + + return &instruction->base; +} + +static IrInstSrc *ir_build_splat_src(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, + IrInstSrc *len, IrInstSrc *scalar) +{ + IrInstSrcSplat *instruction = ir_build_instruction(irb, scope, source_node); + instruction->len = len; + instruction->scalar = scalar; + + ir_ref_instruction(len, irb->current_basic_block); + ir_ref_instruction(scalar, irb->current_basic_block); + + return &instruction->base; +} + +static IrInstSrc *ir_build_bool_not(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrInstSrc *value) { + IrInstSrcBoolNot *instruction = ir_build_instruction(irb, scope, source_node); + instruction->value = value; + + ir_ref_instruction(value, irb->current_basic_block); + + return &instruction->base; +} + +static IrInstSrc *ir_build_memset_src(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, + IrInstSrc *dest_ptr, IrInstSrc *byte, IrInstSrc *count) +{ + IrInstSrcMemset *instruction = ir_build_instruction(irb, scope, source_node); + instruction->dest_ptr = dest_ptr; + instruction->byte = byte; + instruction->count = count; + + ir_ref_instruction(dest_ptr, irb->current_basic_block); + ir_ref_instruction(byte, irb->current_basic_block); + ir_ref_instruction(count, irb->current_basic_block); + + return &instruction->base; +} + +static IrInstSrc *ir_build_memcpy_src(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, + IrInstSrc *dest_ptr, IrInstSrc *src_ptr, IrInstSrc *count) +{ + IrInstSrcMemcpy *instruction = ir_build_instruction(irb, scope, source_node); + instruction->dest_ptr = dest_ptr; + instruction->src_ptr = src_ptr; + instruction->count = count; + + ir_ref_instruction(dest_ptr, irb->current_basic_block); + ir_ref_instruction(src_ptr, irb->current_basic_block); + ir_ref_instruction(count, irb->current_basic_block); + + return &instruction->base; +} + +static IrInstSrc *ir_build_slice_src(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, + IrInstSrc *ptr, IrInstSrc *start, IrInstSrc *end, IrInstSrc *sentinel, + bool safety_check_on, ResultLoc *result_loc) +{ + IrInstSrcSlice *instruction = ir_build_instruction(irb, scope, source_node); + instruction->ptr = ptr; + instruction->start = start; + instruction->end = end; + instruction->sentinel = sentinel; + instruction->safety_check_on = safety_check_on; + instruction->result_loc = result_loc; + + ir_ref_instruction(ptr, irb->current_basic_block); + ir_ref_instruction(start, irb->current_basic_block); + if (end) ir_ref_instruction(end, irb->current_basic_block); + if (sentinel) ir_ref_instruction(sentinel, irb->current_basic_block); + + return &instruction->base; +} + +static IrInstSrc *ir_build_breakpoint(IrBuilderSrc *irb, Scope *scope, AstNode *source_node) { + IrInstSrcBreakpoint *instruction = ir_build_instruction(irb, scope, source_node); + return &instruction->base; +} + +static IrInstSrc *ir_build_return_address_src(IrBuilderSrc *irb, Scope *scope, AstNode *source_node) { + IrInstSrcReturnAddress *instruction = ir_build_instruction(irb, scope, source_node); + return &instruction->base; +} + +static IrInstSrc *ir_build_frame_address_src(IrBuilderSrc *irb, Scope *scope, AstNode *source_node) { + IrInstSrcFrameAddress *inst = ir_build_instruction(irb, scope, source_node); + return &inst->base; +} + +static IrInstSrc *ir_build_handle_src(IrBuilderSrc *irb, Scope *scope, AstNode *source_node) { + IrInstSrcFrameHandle *inst = ir_build_instruction(irb, scope, source_node); + return &inst->base; +} + +static IrInstSrc *ir_build_frame_type(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrInstSrc *fn) { + IrInstSrcFrameType *inst = ir_build_instruction(irb, scope, source_node); + inst->fn = fn; + + ir_ref_instruction(fn, irb->current_basic_block); + + return &inst->base; +} + +static IrInstSrc *ir_build_frame_size_src(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrInstSrc *fn) { + IrInstSrcFrameSize *inst = ir_build_instruction(irb, scope, source_node); + inst->fn = fn; + + ir_ref_instruction(fn, irb->current_basic_block); + + return &inst->base; +} + +static IrInstSrc *ir_build_overflow_op_src(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, + IrOverflowOp op, IrInstSrc *type_value, IrInstSrc *op1, IrInstSrc *op2, IrInstSrc *result_ptr) +{ + IrInstSrcOverflowOp *instruction = ir_build_instruction(irb, scope, source_node); + instruction->op = op; + instruction->type_value = type_value; + instruction->op1 = op1; + instruction->op2 = op2; + instruction->result_ptr = result_ptr; + + ir_ref_instruction(type_value, irb->current_basic_block); + ir_ref_instruction(op1, irb->current_basic_block); + ir_ref_instruction(op2, irb->current_basic_block); + ir_ref_instruction(result_ptr, irb->current_basic_block); + + return &instruction->base; +} + +static IrInstSrc *ir_build_float_op_src(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrInstSrc *operand, + BuiltinFnId fn_id) +{ + IrInstSrcFloatOp *instruction = ir_build_instruction(irb, scope, source_node); + instruction->operand = operand; + instruction->fn_id = fn_id; + + ir_ref_instruction(operand, irb->current_basic_block); + + return &instruction->base; +} + +static IrInstSrc *ir_build_mul_add_src(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, + IrInstSrc *type_value, IrInstSrc *op1, IrInstSrc *op2, IrInstSrc *op3) +{ + IrInstSrcMulAdd *instruction = ir_build_instruction(irb, scope, source_node); + instruction->type_value = type_value; + instruction->op1 = op1; + instruction->op2 = op2; + instruction->op3 = op3; + + ir_ref_instruction(type_value, irb->current_basic_block); + ir_ref_instruction(op1, irb->current_basic_block); + ir_ref_instruction(op2, irb->current_basic_block); + ir_ref_instruction(op3, irb->current_basic_block); + + return &instruction->base; +} + +static IrInstSrc *ir_build_align_of(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrInstSrc *type_value) { + IrInstSrcAlignOf *instruction = ir_build_instruction(irb, scope, source_node); + instruction->type_value = type_value; + + ir_ref_instruction(type_value, irb->current_basic_block); + + return &instruction->base; +} + +static IrInstSrc *ir_build_test_err_src(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, + IrInstSrc *base_ptr, bool resolve_err_set, bool base_ptr_is_payload) +{ + IrInstSrcTestErr *instruction = ir_build_instruction(irb, scope, source_node); + instruction->base_ptr = base_ptr; + instruction->resolve_err_set = resolve_err_set; + instruction->base_ptr_is_payload = base_ptr_is_payload; + + ir_ref_instruction(base_ptr, irb->current_basic_block); + + return &instruction->base; +} + +static IrInstSrc *ir_build_unwrap_err_code_src(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, + IrInstSrc *err_union_ptr) +{ + IrInstSrcUnwrapErrCode *inst = ir_build_instruction(irb, scope, source_node); + inst->err_union_ptr = err_union_ptr; + + ir_ref_instruction(err_union_ptr, irb->current_basic_block); + + return &inst->base; +} + +static IrInstSrc *ir_build_unwrap_err_payload_src(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, + IrInstSrc *value, bool safety_check_on, bool initializing) +{ + IrInstSrcUnwrapErrPayload *inst = ir_build_instruction(irb, scope, source_node); + inst->value = value; + inst->safety_check_on = safety_check_on; + inst->initializing = initializing; + + ir_ref_instruction(value, irb->current_basic_block); + + return &inst->base; +} + +static IrInstSrc *ir_build_fn_proto(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, + IrInstSrc **param_types, IrInstSrc *align_value, IrInstSrc *callconv_value, + IrInstSrc *return_type, bool is_var_args) +{ + IrInstSrcFnProto *instruction = ir_build_instruction(irb, scope, source_node); + instruction->param_types = param_types; + instruction->align_value = align_value; + instruction->callconv_value = callconv_value; + instruction->return_type = return_type; + instruction->is_var_args = is_var_args; + + assert(source_node->type == NodeTypeFnProto); + size_t param_count = source_node->data.fn_proto.params.length; + if (is_var_args) param_count -= 1; + for (size_t i = 0; i < param_count; i += 1) { + if (param_types[i] != nullptr) ir_ref_instruction(param_types[i], irb->current_basic_block); + } + if (align_value != nullptr) ir_ref_instruction(align_value, irb->current_basic_block); + if (callconv_value != nullptr) ir_ref_instruction(callconv_value, irb->current_basic_block); + ir_ref_instruction(return_type, irb->current_basic_block); + + return &instruction->base; +} + +static IrInstSrc *ir_build_test_comptime(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrInstSrc *value) { + IrInstSrcTestComptime *instruction = ir_build_instruction(irb, scope, source_node); + instruction->value = value; + + ir_ref_instruction(value, irb->current_basic_block); + + return &instruction->base; +} + +static IrInstSrc *ir_build_ptr_cast_src(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, + IrInstSrc *dest_type, IrInstSrc *ptr, bool safety_check_on) +{ + IrInstSrcPtrCast *instruction = ir_build_instruction( + irb, scope, source_node); + instruction->dest_type = dest_type; + instruction->ptr = ptr; + instruction->safety_check_on = safety_check_on; + + ir_ref_instruction(dest_type, irb->current_basic_block); + ir_ref_instruction(ptr, irb->current_basic_block); + + return &instruction->base; +} + +static IrInstSrc *ir_build_implicit_cast(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, + IrInstSrc *operand, ResultLocCast *result_loc_cast) +{ + IrInstSrcImplicitCast *instruction = ir_build_instruction(irb, scope, source_node); + instruction->operand = operand; + instruction->result_loc_cast = result_loc_cast; + + ir_ref_instruction(operand, irb->current_basic_block); + + return &instruction->base; +} + +static IrInstSrc *ir_build_bit_cast_src(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, + IrInstSrc *operand, ResultLocBitCast *result_loc_bit_cast) +{ + IrInstSrcBitCast *instruction = ir_build_instruction(irb, scope, source_node); + instruction->operand = operand; + instruction->result_loc_bit_cast = result_loc_bit_cast; + + ir_ref_instruction(operand, irb->current_basic_block); + + return &instruction->base; +} + +static IrInstSrc *ir_build_int_to_ptr_src(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, + IrInstSrc *dest_type, IrInstSrc *target) +{ + IrInstSrcIntToPtr *instruction = ir_build_instruction(irb, scope, source_node); + instruction->dest_type = dest_type; + instruction->target = target; + + ir_ref_instruction(dest_type, irb->current_basic_block); + ir_ref_instruction(target, irb->current_basic_block); + + return &instruction->base; +} + +static IrInstSrc *ir_build_ptr_to_int_src(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, + IrInstSrc *target) +{ + IrInstSrcPtrToInt *inst = ir_build_instruction(irb, scope, source_node); + inst->target = target; + + ir_ref_instruction(target, irb->current_basic_block); + + return &inst->base; +} + +static IrInstSrc *ir_build_int_to_enum_src(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, + IrInstSrc *dest_type, IrInstSrc *target) +{ + IrInstSrcIntToEnum *instruction = ir_build_instruction(irb, scope, source_node); + instruction->dest_type = dest_type; + instruction->target = target; + + if (dest_type) ir_ref_instruction(dest_type, irb->current_basic_block); + ir_ref_instruction(target, irb->current_basic_block); + + return &instruction->base; +} + +static IrInstSrc *ir_build_enum_to_int(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, + IrInstSrc *target) +{ + IrInstSrcEnumToInt *instruction = ir_build_instruction( + irb, scope, source_node); + instruction->target = target; + + ir_ref_instruction(target, irb->current_basic_block); + + return &instruction->base; +} + +static IrInstSrc *ir_build_int_to_err_src(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, + IrInstSrc *target) +{ + IrInstSrcIntToErr *instruction = ir_build_instruction(irb, scope, source_node); + instruction->target = target; + + ir_ref_instruction(target, irb->current_basic_block); + + return &instruction->base; +} + +static IrInstSrc *ir_build_err_to_int_src(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, + IrInstSrc *target) +{ + IrInstSrcErrToInt *instruction = ir_build_instruction( + irb, scope, source_node); + instruction->target = target; + + ir_ref_instruction(target, irb->current_basic_block); + + return &instruction->base; +} + +static IrInstSrc *ir_build_check_switch_prongs(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, + IrInstSrc *target_value, IrInstSrcCheckSwitchProngsRange *ranges, size_t range_count, + AstNode* else_prong, bool have_underscore_prong) +{ + IrInstSrcCheckSwitchProngs *instruction = heap::c_allocator.create(); + instruction->base.id = have_underscore_prong ? + IrInstSrcIdCheckSwitchProngsUnderYes : IrInstSrcIdCheckSwitchProngsUnderNo; + instruction->base.base.scope = scope; + instruction->base.base.source_node = source_node; + instruction->base.base.debug_id = exec_next_debug_id(irb->exec); + instruction->base.owner_bb = irb->current_basic_block; + ir_instruction_append(irb->current_basic_block, &instruction->base); + + instruction->target_value = target_value; + instruction->ranges = ranges; + instruction->range_count = range_count; + instruction->else_prong = else_prong; + + ir_ref_instruction(target_value, irb->current_basic_block); + for (size_t i = 0; i < range_count; i += 1) { + ir_ref_instruction(ranges[i].start, irb->current_basic_block); + ir_ref_instruction(ranges[i].end, irb->current_basic_block); + } + + return &instruction->base; +} + +static IrInstSrc *ir_build_check_statement_is_void(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, + IrInstSrc* statement_value) +{ + IrInstSrcCheckStatementIsVoid *instruction = ir_build_instruction( + irb, scope, source_node); + instruction->statement_value = statement_value; + + ir_ref_instruction(statement_value, irb->current_basic_block); + + return &instruction->base; +} + +static IrInstSrc *ir_build_type_name(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, + IrInstSrc *type_value) +{ + IrInstSrcTypeName *instruction = ir_build_instruction(irb, scope, source_node); + instruction->type_value = type_value; + + ir_ref_instruction(type_value, irb->current_basic_block); + + return &instruction->base; +} + +static IrInstSrc *ir_build_decl_ref(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, Tld *tld, LVal lval) { + IrInstSrcDeclRef *instruction = ir_build_instruction(irb, scope, source_node); + instruction->tld = tld; + instruction->lval = lval; + + return &instruction->base; +} + +static IrInstSrc *ir_build_panic_src(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrInstSrc *msg) { + IrInstSrcPanic *instruction = ir_build_instruction(irb, scope, source_node); + instruction->base.is_noreturn = true; + instruction->msg = msg; + + ir_ref_instruction(msg, irb->current_basic_block); + + return &instruction->base; +} + +static IrInstSrc *ir_build_tag_name_src(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrInstSrc *target) { + IrInstSrcTagName *instruction = ir_build_instruction(irb, scope, source_node); + instruction->target = target; + + ir_ref_instruction(target, irb->current_basic_block); + + return &instruction->base; +} + +static IrInstSrc *ir_build_field_parent_ptr_src(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, + IrInstSrc *type_value, IrInstSrc *field_name, IrInstSrc *field_ptr) +{ + IrInstSrcFieldParentPtr *inst = ir_build_instruction( + irb, scope, source_node); + inst->type_value = type_value; + inst->field_name = field_name; + inst->field_ptr = field_ptr; + + ir_ref_instruction(type_value, irb->current_basic_block); + ir_ref_instruction(field_name, irb->current_basic_block); + ir_ref_instruction(field_ptr, irb->current_basic_block); + + return &inst->base; +} + +static IrInstSrc *ir_build_byte_offset_of(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, + IrInstSrc *type_value, IrInstSrc *field_name) +{ + IrInstSrcByteOffsetOf *instruction = ir_build_instruction(irb, scope, source_node); + instruction->type_value = type_value; + instruction->field_name = field_name; + + ir_ref_instruction(type_value, irb->current_basic_block); + ir_ref_instruction(field_name, irb->current_basic_block); + + return &instruction->base; +} + +static IrInstSrc *ir_build_bit_offset_of(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, + IrInstSrc *type_value, IrInstSrc *field_name) +{ + IrInstSrcBitOffsetOf *instruction = ir_build_instruction(irb, scope, source_node); + instruction->type_value = type_value; + instruction->field_name = field_name; + + ir_ref_instruction(type_value, irb->current_basic_block); + ir_ref_instruction(field_name, irb->current_basic_block); + + return &instruction->base; +} + +static IrInstSrc *ir_build_type_info(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrInstSrc *type_value) { + IrInstSrcTypeInfo *instruction = ir_build_instruction(irb, scope, source_node); + instruction->type_value = type_value; + + ir_ref_instruction(type_value, irb->current_basic_block); + + return &instruction->base; +} + +static IrInstSrc *ir_build_type(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrInstSrc *type_info) { + IrInstSrcType *instruction = ir_build_instruction(irb, scope, source_node); + instruction->type_info = type_info; + + ir_ref_instruction(type_info, irb->current_basic_block); + + return &instruction->base; +} + +static IrInstSrc *ir_build_set_eval_branch_quota(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, + IrInstSrc *new_quota) +{ + IrInstSrcSetEvalBranchQuota *instruction = ir_build_instruction(irb, scope, source_node); + instruction->new_quota = new_quota; + + ir_ref_instruction(new_quota, irb->current_basic_block); + + return &instruction->base; +} + +static IrInstSrc *ir_build_align_cast_src(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, + IrInstSrc *align_bytes, IrInstSrc *target) +{ + IrInstSrcAlignCast *instruction = ir_build_instruction(irb, scope, source_node); + instruction->align_bytes = align_bytes; + instruction->target = target; + + ir_ref_instruction(align_bytes, irb->current_basic_block); + ir_ref_instruction(target, irb->current_basic_block); + + return &instruction->base; +} + +static IrInstSrc *ir_build_resolve_result(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, + ResultLoc *result_loc, IrInstSrc *ty) +{ + IrInstSrcResolveResult *instruction = ir_build_instruction(irb, scope, source_node); + instruction->result_loc = result_loc; + instruction->ty = ty; + + if (ty != nullptr) ir_ref_instruction(ty, irb->current_basic_block); + + return &instruction->base; +} + +static IrInstSrc *ir_build_reset_result(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, + ResultLoc *result_loc) +{ + IrInstSrcResetResult *instruction = ir_build_instruction(irb, scope, source_node); + instruction->result_loc = result_loc; + instruction->base.is_gen = true; + + return &instruction->base; +} + +static IrInstSrc *ir_build_set_align_stack(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, + IrInstSrc *align_bytes) +{ + IrInstSrcSetAlignStack *instruction = ir_build_instruction(irb, scope, source_node); + instruction->align_bytes = align_bytes; + + ir_ref_instruction(align_bytes, irb->current_basic_block); + + return &instruction->base; +} + +static IrInstSrc *ir_build_arg_type(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, + IrInstSrc *fn_type, IrInstSrc *arg_index, bool allow_var) +{ + IrInstSrcArgType *instruction = heap::c_allocator.create(); + instruction->base.id = allow_var ? + IrInstSrcIdArgTypeAllowVarTrue : IrInstSrcIdArgTypeAllowVarFalse; + instruction->base.base.scope = scope; + instruction->base.base.source_node = source_node; + instruction->base.base.debug_id = exec_next_debug_id(irb->exec); + instruction->base.owner_bb = irb->current_basic_block; + ir_instruction_append(irb->current_basic_block, &instruction->base); + + instruction->fn_type = fn_type; + instruction->arg_index = arg_index; + + ir_ref_instruction(fn_type, irb->current_basic_block); + ir_ref_instruction(arg_index, irb->current_basic_block); + + return &instruction->base; +} + +static IrInstSrc *ir_build_error_return_trace_src(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, + IrInstErrorReturnTraceOptional optional) +{ + IrInstSrcErrorReturnTrace *inst = ir_build_instruction(irb, scope, source_node); + inst->optional = optional; + + return &inst->base; +} + +static IrInstSrc *ir_build_error_union(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, + IrInstSrc *err_set, IrInstSrc *payload) +{ + IrInstSrcErrorUnion *instruction = ir_build_instruction(irb, scope, source_node); + instruction->err_set = err_set; + instruction->payload = payload; + + ir_ref_instruction(err_set, irb->current_basic_block); + ir_ref_instruction(payload, irb->current_basic_block); + + return &instruction->base; +} + +static IrInstSrc *ir_build_atomic_rmw_src(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, + IrInstSrc *operand_type, IrInstSrc *ptr, IrInstSrc *op, IrInstSrc *operand, + IrInstSrc *ordering) +{ + IrInstSrcAtomicRmw *instruction = ir_build_instruction(irb, scope, source_node); + instruction->operand_type = operand_type; + instruction->ptr = ptr; + instruction->op = op; + instruction->operand = operand; + instruction->ordering = ordering; + + ir_ref_instruction(operand_type, irb->current_basic_block); + ir_ref_instruction(ptr, irb->current_basic_block); + ir_ref_instruction(op, irb->current_basic_block); + ir_ref_instruction(operand, irb->current_basic_block); + ir_ref_instruction(ordering, irb->current_basic_block); + + return &instruction->base; +} + +static IrInstSrc *ir_build_atomic_load_src(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, + IrInstSrc *operand_type, IrInstSrc *ptr, IrInstSrc *ordering) +{ + IrInstSrcAtomicLoad *instruction = ir_build_instruction(irb, scope, source_node); + instruction->operand_type = operand_type; + instruction->ptr = ptr; + instruction->ordering = ordering; + + ir_ref_instruction(operand_type, irb->current_basic_block); + ir_ref_instruction(ptr, irb->current_basic_block); + ir_ref_instruction(ordering, irb->current_basic_block); + + return &instruction->base; +} + +static IrInstSrc *ir_build_atomic_store_src(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, + IrInstSrc *operand_type, IrInstSrc *ptr, IrInstSrc *value, IrInstSrc *ordering) +{ + IrInstSrcAtomicStore *instruction = ir_build_instruction(irb, scope, source_node); + instruction->operand_type = operand_type; + instruction->ptr = ptr; + instruction->value = value; + instruction->ordering = ordering; + + ir_ref_instruction(operand_type, irb->current_basic_block); + ir_ref_instruction(ptr, irb->current_basic_block); + ir_ref_instruction(value, irb->current_basic_block); + ir_ref_instruction(ordering, irb->current_basic_block); + + return &instruction->base; +} + +static IrInstSrc *ir_build_save_err_ret_addr_src(IrBuilderSrc *irb, Scope *scope, AstNode *source_node) { + IrInstSrcSaveErrRetAddr *inst = ir_build_instruction(irb, scope, source_node); + return &inst->base; +} + +static IrInstSrc *ir_build_add_implicit_return_type(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, + IrInstSrc *value, ResultLocReturn *result_loc_ret) +{ + IrInstSrcAddImplicitReturnType *inst = ir_build_instruction(irb, scope, source_node); + inst->value = value; + inst->result_loc_ret = result_loc_ret; + + ir_ref_instruction(value, irb->current_basic_block); + + return &inst->base; +} + +static IrInstSrc *ir_build_has_decl(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, + IrInstSrc *container, IrInstSrc *name) +{ + IrInstSrcHasDecl *instruction = ir_build_instruction(irb, scope, source_node); + instruction->container = container; + instruction->name = name; + + ir_ref_instruction(container, irb->current_basic_block); + ir_ref_instruction(name, irb->current_basic_block); + + return &instruction->base; +} + +static IrInstSrc *ir_build_undeclared_identifier(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, Buf *name) { + IrInstSrcUndeclaredIdent *instruction = ir_build_instruction(irb, scope, source_node); + instruction->name = name; + + return &instruction->base; +} + +static IrInstSrc *ir_build_check_runtime_scope(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrInstSrc *scope_is_comptime, IrInstSrc *is_comptime) { + IrInstSrcCheckRuntimeScope *instruction = ir_build_instruction(irb, scope, source_node); + instruction->scope_is_comptime = scope_is_comptime; + instruction->is_comptime = is_comptime; + + ir_ref_instruction(scope_is_comptime, irb->current_basic_block); + ir_ref_instruction(is_comptime, irb->current_basic_block); + + return &instruction->base; +} + +static IrInstSrc *ir_build_union_init_named_field(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, + IrInstSrc *union_type, IrInstSrc *field_name, IrInstSrc *field_result_loc, IrInstSrc *result_loc) +{ + IrInstSrcUnionInitNamedField *instruction = ir_build_instruction(irb, scope, source_node); + instruction->union_type = union_type; + instruction->field_name = field_name; + instruction->field_result_loc = field_result_loc; + instruction->result_loc = result_loc; + + ir_ref_instruction(union_type, irb->current_basic_block); + ir_ref_instruction(field_name, irb->current_basic_block); + ir_ref_instruction(field_result_loc, irb->current_basic_block); + if (result_loc != nullptr) ir_ref_instruction(result_loc, irb->current_basic_block); + + return &instruction->base; +} + +static IrInstSrc *ir_build_alloca_src(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, + IrInstSrc *align, const char *name_hint, IrInstSrc *is_comptime) +{ + IrInstSrcAlloca *instruction = ir_build_instruction(irb, scope, source_node); + instruction->base.is_gen = true; + instruction->align = align; + instruction->name_hint = name_hint; + instruction->is_comptime = is_comptime; + + if (align != nullptr) ir_ref_instruction(align, irb->current_basic_block); + if (is_comptime != nullptr) ir_ref_instruction(is_comptime, irb->current_basic_block); + + return &instruction->base; +} + +static IrInstSrc *ir_build_end_expr(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, + IrInstSrc *value, ResultLoc *result_loc) +{ + IrInstSrcEndExpr *instruction = ir_build_instruction(irb, scope, source_node); + instruction->base.is_gen = true; + instruction->value = value; + instruction->result_loc = result_loc; + + ir_ref_instruction(value, irb->current_basic_block); + + return &instruction->base; +} + +static IrInstSrcSuspendBegin *ir_build_suspend_begin_src(IrBuilderSrc *irb, Scope *scope, AstNode *source_node) { + return ir_build_instruction(irb, scope, source_node); +} + +static IrInstSrc *ir_build_suspend_finish_src(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, + IrInstSrcSuspendBegin *begin) +{ + IrInstSrcSuspendFinish *inst = ir_build_instruction(irb, scope, source_node); + inst->begin = begin; + + ir_ref_instruction(&begin->base, irb->current_basic_block); + + return &inst->base; +} + +static IrInstSrc *ir_build_await_src(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, + IrInstSrc *frame, ResultLoc *result_loc, bool is_nosuspend) +{ + IrInstSrcAwait *instruction = ir_build_instruction(irb, scope, source_node); + instruction->frame = frame; + instruction->result_loc = result_loc; + instruction->is_nosuspend = is_nosuspend; + + ir_ref_instruction(frame, irb->current_basic_block); + + return &instruction->base; +} + +static IrInstSrc *ir_build_resume_src(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrInstSrc *frame) { + IrInstSrcResume *instruction = ir_build_instruction(irb, scope, source_node); + instruction->frame = frame; + + ir_ref_instruction(frame, irb->current_basic_block); + + return &instruction->base; +} + +static IrInstSrcSpillBegin *ir_build_spill_begin_src(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, + IrInstSrc *operand, SpillId spill_id) +{ + IrInstSrcSpillBegin *instruction = ir_build_instruction(irb, scope, source_node); + instruction->operand = operand; + instruction->spill_id = spill_id; + + ir_ref_instruction(operand, irb->current_basic_block); + + return instruction; +} + +static IrInstSrc *ir_build_spill_end_src(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, + IrInstSrcSpillBegin *begin) +{ + IrInstSrcSpillEnd *instruction = ir_build_instruction(irb, scope, source_node); + instruction->begin = begin; + + ir_ref_instruction(&begin->base, irb->current_basic_block); + + return &instruction->base; +} + +static IrInstSrc *ir_build_wasm_memory_size_src(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrInstSrc *index) { + IrInstSrcWasmMemorySize *instruction = ir_build_instruction(irb, scope, source_node); + instruction->index = index; + + ir_ref_instruction(index, irb->current_basic_block); + + return &instruction->base; +} + +static IrInstSrc *ir_build_wasm_memory_grow_src(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrInstSrc *index, IrInstSrc *delta) { + IrInstSrcWasmMemoryGrow *instruction = ir_build_instruction(irb, scope, source_node); + instruction->index = index; + instruction->delta = delta; + + ir_ref_instruction(index, irb->current_basic_block); + ir_ref_instruction(delta, irb->current_basic_block); + + return &instruction->base; +} + +static IrInstSrc *ir_build_src(IrBuilderSrc *irb, Scope *scope, AstNode *source_node) { + IrInstSrcSrc *instruction = ir_build_instruction(irb, scope, source_node); + + return &instruction->base; +} + +static void ir_count_defers(IrBuilderSrc *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) { + results[ReturnKindUnconditional] = 0; + results[ReturnKindError] = 0; + + Scope *scope = inner_scope; + + while (scope != outer_scope) { + assert(scope); + switch (scope->id) { + case ScopeIdDefer: { + AstNode *defer_node = scope->source_node; + assert(defer_node->type == NodeTypeDefer); + ReturnKind defer_kind = defer_node->data.defer.kind; + results[defer_kind] += 1; + scope = scope->parent; + continue; + } + case ScopeIdDecls: + case ScopeIdFnDef: + return; + case ScopeIdBlock: + case ScopeIdVarDecl: + case ScopeIdLoop: + case ScopeIdSuspend: + case ScopeIdCompTime: + case ScopeIdNoSuspend: + case ScopeIdRuntime: + case ScopeIdTypeOf: + case ScopeIdExpr: + scope = scope->parent; + continue; + case ScopeIdDeferExpr: + case ScopeIdCImport: + zig_unreachable(); + } + } +} + +static IrInstSrc *ir_mark_gen(IrInstSrc *instruction) { + instruction->is_gen = true; + return instruction; +} + +static bool ir_gen_defers_for_block(IrBuilderSrc *irb, Scope *inner_scope, Scope *outer_scope, bool *is_noreturn, IrInstSrc *err_value) { + Scope *scope = inner_scope; + if (is_noreturn != nullptr) *is_noreturn = false; + while (scope != outer_scope) { + if (!scope) + return true; + + switch (scope->id) { + case ScopeIdDefer: { + AstNode *defer_node = scope->source_node; + assert(defer_node->type == NodeTypeDefer); + ReturnKind defer_kind = defer_node->data.defer.kind; + AstNode *defer_expr_node = defer_node->data.defer.expr; + AstNode *defer_var_node = defer_node->data.defer.err_payload; + + if (defer_kind == ReturnKindError && err_value == nullptr) { + // This is an `errdefer` but we're generating code for a + // `return` that doesn't return an error, skip it + scope = scope->parent; + continue; + } + + Scope *defer_expr_scope = defer_node->data.defer.expr_scope; + if (defer_var_node != nullptr) { + assert(defer_kind == ReturnKindError); + assert(defer_var_node->type == NodeTypeIdentifier); + Buf *var_name = node_identifier_buf(defer_var_node); + + if (defer_expr_node->type == NodeTypeUnreachable) { + add_node_error(irb->codegen, defer_var_node, + buf_sprintf("unused variable: '%s'", buf_ptr(var_name))); + return false; + } + + IrInstSrc *is_comptime; + if (ir_should_inline(irb->exec, defer_expr_scope)) { + is_comptime = ir_build_const_bool(irb, defer_expr_scope, + defer_expr_node, true); + } else { + is_comptime = ir_build_test_comptime(irb, defer_expr_scope, + defer_expr_node, err_value); + } + + ZigVar *err_var = ir_create_var(irb, defer_var_node, defer_expr_scope, + var_name, true, true, false, is_comptime); + build_decl_var_and_init(irb, defer_expr_scope, defer_var_node, err_var, err_value, + buf_ptr(var_name), is_comptime); + + defer_expr_scope = err_var->child_scope; + } + + IrInstSrc *defer_expr_value = ir_gen_node(irb, defer_expr_node, defer_expr_scope); + if (defer_expr_value == irb->codegen->invalid_inst_src) + return irb->codegen->invalid_inst_src; + + if (defer_expr_value->is_noreturn) { + if (is_noreturn != nullptr) *is_noreturn = true; + } else { + ir_mark_gen(ir_build_check_statement_is_void(irb, defer_expr_scope, defer_expr_node, + defer_expr_value)); + } + scope = scope->parent; + continue; + } + case ScopeIdDecls: + case ScopeIdFnDef: + return true; + case ScopeIdBlock: + case ScopeIdVarDecl: + case ScopeIdLoop: + case ScopeIdSuspend: + case ScopeIdCompTime: + case ScopeIdNoSuspend: + case ScopeIdRuntime: + case ScopeIdTypeOf: + case ScopeIdExpr: + scope = scope->parent; + continue; + case ScopeIdDeferExpr: + case ScopeIdCImport: + zig_unreachable(); + } + } + return true; +} + +static void ir_set_cursor_at_end(IrBuilderSrc *irb, IrBasicBlockSrc *basic_block) { + assert(basic_block); + irb->current_basic_block = basic_block; +} + +static void ir_set_cursor_at_end_and_append_block(IrBuilderSrc *irb, IrBasicBlockSrc *basic_block) { + basic_block->index = irb->exec->basic_block_list.length; + irb->exec->basic_block_list.append(basic_block); + ir_set_cursor_at_end(irb, basic_block); +} + +static ScopeSuspend *get_scope_suspend(Scope *scope) { + while (scope) { + if (scope->id == ScopeIdSuspend) + return (ScopeSuspend *)scope; + if (scope->id == ScopeIdFnDef) + return nullptr; + + scope = scope->parent; + } + return nullptr; +} + +static ScopeDeferExpr *get_scope_defer_expr(Scope *scope) { + while (scope) { + if (scope->id == ScopeIdDeferExpr) + return (ScopeDeferExpr *)scope; + if (scope->id == ScopeIdFnDef) + return nullptr; + + scope = scope->parent; + } + return nullptr; +} + +static IrInstSrc *ir_gen_return(IrBuilderSrc *irb, Scope *scope, AstNode *node, LVal lval, ResultLoc *result_loc) { + assert(node->type == NodeTypeReturnExpr); + + ScopeDeferExpr *scope_defer_expr = get_scope_defer_expr(scope); + if (scope_defer_expr) { + if (!scope_defer_expr->reported_err) { + add_node_error(irb->codegen, node, buf_sprintf("cannot return from defer expression")); + scope_defer_expr->reported_err = true; + } + return irb->codegen->invalid_inst_src; + } + + Scope *outer_scope = irb->exec->begin_scope; + + AstNode *expr_node = node->data.return_expr.expr; + switch (node->data.return_expr.kind) { + case ReturnKindUnconditional: + { + ResultLocReturn *result_loc_ret = heap::c_allocator.create(); + result_loc_ret->base.id = ResultLocIdReturn; + ir_build_reset_result(irb, scope, node, &result_loc_ret->base); + + IrInstSrc *return_value; + if (expr_node) { + // Temporarily set this so that if we return a type it gets the name of the function + ZigFn *prev_name_fn = irb->exec->name_fn; + irb->exec->name_fn = exec_fn_entry(irb->exec); + return_value = ir_gen_node_extra(irb, expr_node, scope, LValNone, &result_loc_ret->base); + irb->exec->name_fn = prev_name_fn; + if (return_value == irb->codegen->invalid_inst_src) + return irb->codegen->invalid_inst_src; + } else { + return_value = ir_build_const_void(irb, scope, node); + ir_build_end_expr(irb, scope, node, return_value, &result_loc_ret->base); + } + + ir_mark_gen(ir_build_add_implicit_return_type(irb, scope, node, return_value, result_loc_ret)); + + size_t defer_counts[2]; + ir_count_defers(irb, scope, outer_scope, defer_counts); + bool have_err_defers = defer_counts[ReturnKindError] > 0; + if (!have_err_defers && !irb->codegen->have_err_ret_tracing) { + // only generate unconditional defers + if (!ir_gen_defers_for_block(irb, scope, outer_scope, nullptr, nullptr)) + return irb->codegen->invalid_inst_src; + IrInstSrc *result = ir_build_return_src(irb, scope, node, nullptr); + result_loc_ret->base.source_instruction = result; + return result; + } + bool should_inline = ir_should_inline(irb->exec, scope); + + IrBasicBlockSrc *err_block = ir_create_basic_block(irb, scope, "ErrRetErr"); + IrBasicBlockSrc *ok_block = ir_create_basic_block(irb, scope, "ErrRetOk"); + + IrInstSrc *is_err = ir_build_test_err_src(irb, scope, node, return_value, false, true); + + IrInstSrc *is_comptime; + if (should_inline) { + is_comptime = ir_build_const_bool(irb, scope, node, should_inline); + } else { + is_comptime = ir_build_test_comptime(irb, scope, node, is_err); + } + + ir_mark_gen(ir_build_cond_br(irb, scope, node, is_err, err_block, ok_block, is_comptime)); + IrBasicBlockSrc *ret_stmt_block = ir_create_basic_block(irb, scope, "RetStmt"); + + ir_set_cursor_at_end_and_append_block(irb, err_block); + if (!ir_gen_defers_for_block(irb, scope, outer_scope, nullptr, return_value)) + return irb->codegen->invalid_inst_src; + if (irb->codegen->have_err_ret_tracing && !should_inline) { + ir_build_save_err_ret_addr_src(irb, scope, node); + } + ir_build_br(irb, scope, node, ret_stmt_block, is_comptime); + + ir_set_cursor_at_end_and_append_block(irb, ok_block); + if (!ir_gen_defers_for_block(irb, scope, outer_scope, nullptr, nullptr)) + return irb->codegen->invalid_inst_src; + ir_build_br(irb, scope, node, ret_stmt_block, is_comptime); + + ir_set_cursor_at_end_and_append_block(irb, ret_stmt_block); + IrInstSrc *result = ir_build_return_src(irb, scope, node, nullptr); + result_loc_ret->base.source_instruction = result; + return result; + } + case ReturnKindError: + { + assert(expr_node); + IrInstSrc *err_union_ptr = ir_gen_node_extra(irb, expr_node, scope, LValPtr, nullptr); + if (err_union_ptr == irb->codegen->invalid_inst_src) + return irb->codegen->invalid_inst_src; + IrInstSrc *is_err_val = ir_build_test_err_src(irb, scope, node, err_union_ptr, true, false); + + IrBasicBlockSrc *return_block = ir_create_basic_block(irb, scope, "ErrRetReturn"); + IrBasicBlockSrc *continue_block = ir_create_basic_block(irb, scope, "ErrRetContinue"); + IrInstSrc *is_comptime; + bool should_inline = ir_should_inline(irb->exec, scope); + if (should_inline) { + is_comptime = ir_build_const_bool(irb, scope, node, true); + } else { + is_comptime = ir_build_test_comptime(irb, scope, node, is_err_val); + } + ir_mark_gen(ir_build_cond_br(irb, scope, node, is_err_val, return_block, continue_block, is_comptime)); + + ir_set_cursor_at_end_and_append_block(irb, return_block); + IrInstSrc *err_val_ptr = ir_build_unwrap_err_code_src(irb, scope, node, err_union_ptr); + IrInstSrc *err_val = ir_build_load_ptr(irb, scope, node, err_val_ptr); + ir_mark_gen(ir_build_add_implicit_return_type(irb, scope, node, err_val, nullptr)); + IrInstSrcSpillBegin *spill_begin = ir_build_spill_begin_src(irb, scope, node, err_val, + SpillIdRetErrCode); + ResultLocReturn *result_loc_ret = heap::c_allocator.create(); + result_loc_ret->base.id = ResultLocIdReturn; + ir_build_reset_result(irb, scope, node, &result_loc_ret->base); + ir_build_end_expr(irb, scope, node, err_val, &result_loc_ret->base); + + bool is_noreturn = false; + if (!ir_gen_defers_for_block(irb, scope, outer_scope, &is_noreturn, err_val)) { + return irb->codegen->invalid_inst_src; + } + if (!is_noreturn) { + if (irb->codegen->have_err_ret_tracing && !should_inline) { + ir_build_save_err_ret_addr_src(irb, scope, node); + } + err_val = ir_build_spill_end_src(irb, scope, node, spill_begin); + IrInstSrc *ret_inst = ir_build_return_src(irb, scope, node, err_val); + result_loc_ret->base.source_instruction = ret_inst; + } + + ir_set_cursor_at_end_and_append_block(irb, continue_block); + IrInstSrc *unwrapped_ptr = ir_build_unwrap_err_payload_src(irb, scope, node, err_union_ptr, false, false); + if (lval == LValPtr) + return unwrapped_ptr; + else + return ir_expr_wrap(irb, scope, ir_build_load_ptr(irb, scope, node, unwrapped_ptr), result_loc); + } + } + zig_unreachable(); +} + +ZigVar *create_local_var(CodeGen *codegen, AstNode *node, Scope *parent_scope, + Buf *name, bool src_is_const, bool gen_is_const, bool is_shadowable, IrInstSrc *is_comptime, + bool skip_name_check) +{ + ZigVar *variable_entry = heap::c_allocator.create(); + variable_entry->parent_scope = parent_scope; + variable_entry->shadowable = is_shadowable; + variable_entry->is_comptime = is_comptime; + variable_entry->src_arg_index = SIZE_MAX; + variable_entry->const_value = codegen->pass1_arena->create(); + + if (is_comptime != nullptr) { + is_comptime->base.ref_count += 1; + } + + if (name) { + variable_entry->name = strdup(buf_ptr(name)); + + if (!skip_name_check) { + ZigVar *existing_var = find_variable(codegen, parent_scope, name, nullptr); + if (existing_var && !existing_var->shadowable) { + if (existing_var->var_type == nullptr || !type_is_invalid(existing_var->var_type)) { + ErrorMsg *msg = add_node_error(codegen, node, + buf_sprintf("redeclaration of variable '%s'", buf_ptr(name))); + add_error_note(codegen, msg, existing_var->decl_node, buf_sprintf("previous declaration is here")); + } + variable_entry->var_type = codegen->builtin_types.entry_invalid; + } else { + ZigType *type; + if (get_primitive_type(codegen, name, &type) != ErrorPrimitiveTypeNotFound) { + add_node_error(codegen, node, + buf_sprintf("variable shadows primitive type '%s'", buf_ptr(name))); + variable_entry->var_type = codegen->builtin_types.entry_invalid; + } else { + Tld *tld = find_decl(codegen, parent_scope, name); + if (tld != nullptr) { + bool want_err_msg = true; + if (tld->id == TldIdVar) { + ZigVar *var = reinterpret_cast(tld)->var; + if (var != nullptr && var->var_type != nullptr && type_is_invalid(var->var_type)) { + want_err_msg = false; + } + } + if (want_err_msg) { + ErrorMsg *msg = add_node_error(codegen, node, + buf_sprintf("redefinition of '%s'", buf_ptr(name))); + add_error_note(codegen, msg, tld->source_node, buf_sprintf("previous definition is here")); + } + variable_entry->var_type = codegen->builtin_types.entry_invalid; + } + } + } + } + } else { + assert(is_shadowable); + // TODO make this name not actually be in scope. user should be able to make a variable called "_anon" + // might already be solved, let's just make sure it has test coverage + // maybe we put a prefix on this so the debug info doesn't clobber user debug info for same named variables + variable_entry->name = "_anon"; + } + + variable_entry->src_is_const = src_is_const; + variable_entry->gen_is_const = gen_is_const; + variable_entry->decl_node = node; + variable_entry->child_scope = create_var_scope(codegen, node, parent_scope, variable_entry); + + return variable_entry; +} + + +// Set name to nullptr to make the variable anonymous (not visible to programmer). +// After you call this function var->child_scope has the variable in scope +static ZigVar *ir_create_var(IrBuilderSrc *irb, AstNode *node, Scope *scope, Buf *name, + bool src_is_const, bool gen_is_const, bool is_shadowable, IrInstSrc *is_comptime) +{ + bool is_underscored = name ? buf_eql_str(name, "_") : false; + ZigVar *var = create_local_var(irb->codegen, node, scope, + (is_underscored ? nullptr : name), src_is_const, gen_is_const, + (is_underscored ? true : is_shadowable), is_comptime, false); + assert(var->child_scope); + return var; +} + +static ResultLocPeer *create_peer_result(ResultLocPeerParent *peer_parent) { + ResultLocPeer *result = heap::c_allocator.create(); + result->base.id = ResultLocIdPeer; + result->base.source_instruction = peer_parent->base.source_instruction; + result->parent = peer_parent; + result->base.allow_write_through_const = peer_parent->parent->allow_write_through_const; + return result; +} + +static bool is_duplicate_label(CodeGen *g, Scope *scope, AstNode *node, Buf *name) { + if (name == nullptr) return false; + + for (;;) { + if (scope == nullptr || scope->id == ScopeIdFnDef) { + break; + } else if (scope->id == ScopeIdBlock || scope->id == ScopeIdLoop) { + Buf *this_block_name = scope->id == ScopeIdBlock ? ((ScopeBlock *)scope)->name : ((ScopeLoop *)scope)->name; + if (this_block_name != nullptr && buf_eql_buf(name, this_block_name)) { + ErrorMsg *msg = add_node_error(g, node, buf_sprintf("redeclaration of label '%s'", buf_ptr(name))); + add_error_note(g, msg, scope->source_node, buf_sprintf("previous declaration is here")); + return true; + } + } + scope = scope->parent; + } + return false; +} + +static IrInstSrc *ir_gen_block(IrBuilderSrc *irb, Scope *parent_scope, AstNode *block_node, LVal lval, + ResultLoc *result_loc) +{ + assert(block_node->type == NodeTypeBlock); + + ZigList incoming_values = {0}; + ZigList incoming_blocks = {0}; + + if (is_duplicate_label(irb->codegen, parent_scope, block_node, block_node->data.block.name)) + return irb->codegen->invalid_inst_src; + + ScopeBlock *scope_block = create_block_scope(irb->codegen, block_node, parent_scope); + + Scope *outer_block_scope = &scope_block->base; + Scope *child_scope = outer_block_scope; + + ZigFn *fn_entry = scope_fn_entry(parent_scope); + if (fn_entry && fn_entry->child_scope == parent_scope) { + fn_entry->def_scope = scope_block; + } + + if (block_node->data.block.statements.length == 0) { + if (scope_block->name != nullptr) { + add_node_error(irb->codegen, block_node, buf_sprintf("unused block label")); + } + // {} + return ir_lval_wrap(irb, parent_scope, ir_build_const_void(irb, child_scope, block_node), lval, result_loc); + } + + if (block_node->data.block.name != nullptr) { + scope_block->lval = lval; + scope_block->incoming_blocks = &incoming_blocks; + scope_block->incoming_values = &incoming_values; + scope_block->end_block = ir_create_basic_block(irb, parent_scope, "BlockEnd"); + scope_block->is_comptime = ir_build_const_bool(irb, parent_scope, block_node, + ir_should_inline(irb->exec, parent_scope)); + + scope_block->peer_parent = heap::c_allocator.create(); + scope_block->peer_parent->base.id = ResultLocIdPeerParent; + scope_block->peer_parent->base.source_instruction = scope_block->is_comptime; + scope_block->peer_parent->base.allow_write_through_const = result_loc->allow_write_through_const; + scope_block->peer_parent->end_bb = scope_block->end_block; + scope_block->peer_parent->is_comptime = scope_block->is_comptime; + scope_block->peer_parent->parent = result_loc; + ir_build_reset_result(irb, parent_scope, block_node, &scope_block->peer_parent->base); + } + + bool is_continuation_unreachable = false; + bool found_invalid_inst = false; + IrInstSrc *noreturn_return_value = nullptr; + for (size_t i = 0; i < block_node->data.block.statements.length; i += 1) { + AstNode *statement_node = block_node->data.block.statements.at(i); + + IrInstSrc *statement_value = ir_gen_node(irb, statement_node, child_scope); + if (statement_value == irb->codegen->invalid_inst_src) { + // keep generating all the elements of the block in case of error, + // we want to collect other compile errors + found_invalid_inst = true; + continue; + } + + is_continuation_unreachable = instr_is_unreachable(statement_value); + if (is_continuation_unreachable) { + // keep the last noreturn statement value around in case we need to return it + noreturn_return_value = statement_value; + } + // This logic must be kept in sync with + // [STMT_EXPR_TEST_THING] <--- (search this token) + if (statement_node->type == NodeTypeDefer) { + // defer starts a new scope + child_scope = statement_node->data.defer.child_scope; + assert(child_scope); + } else if (statement_value->id == IrInstSrcIdDeclVar) { + // variable declarations start a new scope + IrInstSrcDeclVar *decl_var_instruction = (IrInstSrcDeclVar *)statement_value; + child_scope = decl_var_instruction->var->child_scope; + } else if (!is_continuation_unreachable) { + // this statement's value must be void + ir_mark_gen(ir_build_check_statement_is_void(irb, child_scope, statement_node, statement_value)); + } + } + + if (scope_block->name != nullptr && scope_block->name_used == false) { + add_node_error(irb->codegen, block_node, buf_sprintf("unused block label")); + } + + if (found_invalid_inst) + return irb->codegen->invalid_inst_src; + + if (is_continuation_unreachable) { + assert(noreturn_return_value != nullptr); + if (block_node->data.block.name == nullptr || incoming_blocks.length == 0) { + return noreturn_return_value; + } + + if (scope_block->peer_parent != nullptr && scope_block->peer_parent->peers.length != 0) { + scope_block->peer_parent->peers.last()->next_bb = scope_block->end_block; + } + ir_set_cursor_at_end_and_append_block(irb, scope_block->end_block); + IrInstSrc *phi = ir_build_phi(irb, parent_scope, block_node, incoming_blocks.length, + incoming_blocks.items, incoming_values.items, scope_block->peer_parent); + return ir_expr_wrap(irb, parent_scope, phi, result_loc); + } else { + incoming_blocks.append(irb->current_basic_block); + IrInstSrc *else_expr_result = ir_mark_gen(ir_build_const_void(irb, parent_scope, block_node)); + + if (scope_block->peer_parent != nullptr) { + ResultLocPeer *peer_result = create_peer_result(scope_block->peer_parent); + scope_block->peer_parent->peers.append(peer_result); + ir_build_end_expr(irb, parent_scope, block_node, else_expr_result, &peer_result->base); + + if (scope_block->peer_parent->peers.length != 0) { + scope_block->peer_parent->peers.last()->next_bb = scope_block->end_block; + } + } + + incoming_values.append(else_expr_result); + } + + bool is_return_from_fn = block_node == irb->main_block_node; + if (!is_return_from_fn) { + if (!ir_gen_defers_for_block(irb, child_scope, outer_block_scope, nullptr, nullptr)) + return irb->codegen->invalid_inst_src; + } + + IrInstSrc *result; + if (block_node->data.block.name != nullptr) { + ir_mark_gen(ir_build_br(irb, parent_scope, block_node, scope_block->end_block, scope_block->is_comptime)); + ir_set_cursor_at_end_and_append_block(irb, scope_block->end_block); + IrInstSrc *phi = ir_build_phi(irb, parent_scope, block_node, incoming_blocks.length, + incoming_blocks.items, incoming_values.items, scope_block->peer_parent); + result = ir_expr_wrap(irb, parent_scope, phi, result_loc); + } else { + IrInstSrc *void_inst = ir_mark_gen(ir_build_const_void(irb, child_scope, block_node)); + result = ir_lval_wrap(irb, parent_scope, void_inst, lval, result_loc); + } + if (!is_return_from_fn) + return result; + + // no need for save_err_ret_addr because this cannot return error + // only generate unconditional defers + + ir_mark_gen(ir_build_add_implicit_return_type(irb, child_scope, block_node, result, nullptr)); + ResultLocReturn *result_loc_ret = heap::c_allocator.create(); + result_loc_ret->base.id = ResultLocIdReturn; + ir_build_reset_result(irb, parent_scope, block_node, &result_loc_ret->base); + ir_mark_gen(ir_build_end_expr(irb, parent_scope, block_node, result, &result_loc_ret->base)); + if (!ir_gen_defers_for_block(irb, child_scope, outer_block_scope, nullptr, nullptr)) + return irb->codegen->invalid_inst_src; + return ir_mark_gen(ir_build_return_src(irb, child_scope, result->base.source_node, result)); +} + +static IrInstSrc *ir_gen_bin_op_id(IrBuilderSrc *irb, Scope *scope, AstNode *node, IrBinOp op_id) { + Scope *inner_scope = scope; + if (op_id == IrBinOpArrayCat || op_id == IrBinOpArrayMult) { + inner_scope = create_comptime_scope(irb->codegen, node, scope); + } + + IrInstSrc *op1 = ir_gen_node(irb, node->data.bin_op_expr.op1, inner_scope); + IrInstSrc *op2 = ir_gen_node(irb, node->data.bin_op_expr.op2, inner_scope); + + if (op1 == irb->codegen->invalid_inst_src || op2 == irb->codegen->invalid_inst_src) + return irb->codegen->invalid_inst_src; + + return ir_build_bin_op(irb, scope, node, op_id, op1, op2, true); +} + +static IrInstSrc *ir_gen_merge_err_sets(IrBuilderSrc *irb, Scope *scope, AstNode *node) { + IrInstSrc *op1 = ir_gen_node(irb, node->data.bin_op_expr.op1, scope); + IrInstSrc *op2 = ir_gen_node(irb, node->data.bin_op_expr.op2, scope); + + if (op1 == irb->codegen->invalid_inst_src || op2 == irb->codegen->invalid_inst_src) + return irb->codegen->invalid_inst_src; + + // TODO only pass type_name when the || operator is the top level AST node in the var decl expr + Buf bare_name = BUF_INIT; + Buf *type_name = get_anon_type_name(irb->codegen, irb->exec, "error", scope, node, &bare_name); + + return ir_build_merge_err_sets(irb, scope, node, op1, op2, type_name); +} + +static IrInstSrc *ir_gen_assign(IrBuilderSrc *irb, Scope *scope, AstNode *node) { + IrInstSrc *lvalue = ir_gen_node_extra(irb, node->data.bin_op_expr.op1, scope, LValAssign, nullptr); + if (lvalue == irb->codegen->invalid_inst_src) + return irb->codegen->invalid_inst_src; + + ResultLocInstruction *result_loc_inst = heap::c_allocator.create(); + result_loc_inst->base.id = ResultLocIdInstruction; + result_loc_inst->base.source_instruction = lvalue; + ir_ref_instruction(lvalue, irb->current_basic_block); + ir_build_reset_result(irb, scope, node, &result_loc_inst->base); + + IrInstSrc *rvalue = ir_gen_node_extra(irb, node->data.bin_op_expr.op2, scope, LValNone, + &result_loc_inst->base); + if (rvalue == irb->codegen->invalid_inst_src) + return irb->codegen->invalid_inst_src; + + return ir_build_const_void(irb, scope, node); +} + +static IrInstSrc *ir_gen_assign_op(IrBuilderSrc *irb, Scope *scope, AstNode *node, IrBinOp op_id) { + IrInstSrc *lvalue = ir_gen_node_extra(irb, node->data.bin_op_expr.op1, scope, LValAssign, nullptr); + if (lvalue == irb->codegen->invalid_inst_src) + return lvalue; + IrInstSrc *op1 = ir_build_load_ptr(irb, scope, node->data.bin_op_expr.op1, lvalue); + IrInstSrc *op2 = ir_gen_node(irb, node->data.bin_op_expr.op2, scope); + if (op2 == irb->codegen->invalid_inst_src) + return op2; + IrInstSrc *result = ir_build_bin_op(irb, scope, node, op_id, op1, op2, true); + ir_build_store_ptr(irb, scope, node, lvalue, result); + return ir_build_const_void(irb, scope, node); +} + +static IrInstSrc *ir_gen_bool_or(IrBuilderSrc *irb, Scope *scope, AstNode *node) { + assert(node->type == NodeTypeBinOpExpr); + + IrInstSrc *val1 = ir_gen_node(irb, node->data.bin_op_expr.op1, scope); + if (val1 == irb->codegen->invalid_inst_src) + return irb->codegen->invalid_inst_src; + IrBasicBlockSrc *post_val1_block = irb->current_basic_block; + + IrInstSrc *is_comptime; + if (ir_should_inline(irb->exec, scope)) { + is_comptime = ir_build_const_bool(irb, scope, node, true); + } else { + is_comptime = ir_build_test_comptime(irb, scope, node, val1); + } + + // block for when val1 == false + IrBasicBlockSrc *false_block = ir_create_basic_block(irb, scope, "BoolOrFalse"); + // block for when val1 == true (don't even evaluate the second part) + IrBasicBlockSrc *true_block = ir_create_basic_block(irb, scope, "BoolOrTrue"); + + ir_build_cond_br(irb, scope, node, val1, true_block, false_block, is_comptime); + + ir_set_cursor_at_end_and_append_block(irb, false_block); + IrInstSrc *val2 = ir_gen_node(irb, node->data.bin_op_expr.op2, scope); + if (val2 == irb->codegen->invalid_inst_src) + return irb->codegen->invalid_inst_src; + IrBasicBlockSrc *post_val2_block = irb->current_basic_block; + + ir_build_br(irb, scope, node, true_block, is_comptime); + + ir_set_cursor_at_end_and_append_block(irb, true_block); + + IrInstSrc **incoming_values = heap::c_allocator.allocate(2); + incoming_values[0] = val1; + incoming_values[1] = val2; + IrBasicBlockSrc **incoming_blocks = heap::c_allocator.allocate(2); + incoming_blocks[0] = post_val1_block; + incoming_blocks[1] = post_val2_block; + + return ir_build_phi(irb, scope, node, 2, incoming_blocks, incoming_values, nullptr); +} + +static IrInstSrc *ir_gen_bool_and(IrBuilderSrc *irb, Scope *scope, AstNode *node) { + assert(node->type == NodeTypeBinOpExpr); + + IrInstSrc *val1 = ir_gen_node(irb, node->data.bin_op_expr.op1, scope); + if (val1 == irb->codegen->invalid_inst_src) + return irb->codegen->invalid_inst_src; + IrBasicBlockSrc *post_val1_block = irb->current_basic_block; + + IrInstSrc *is_comptime; + if (ir_should_inline(irb->exec, scope)) { + is_comptime = ir_build_const_bool(irb, scope, node, true); + } else { + is_comptime = ir_build_test_comptime(irb, scope, node, val1); + } + + // block for when val1 == true + IrBasicBlockSrc *true_block = ir_create_basic_block(irb, scope, "BoolAndTrue"); + // block for when val1 == false (don't even evaluate the second part) + IrBasicBlockSrc *false_block = ir_create_basic_block(irb, scope, "BoolAndFalse"); + + ir_build_cond_br(irb, scope, node, val1, true_block, false_block, is_comptime); + + ir_set_cursor_at_end_and_append_block(irb, true_block); + IrInstSrc *val2 = ir_gen_node(irb, node->data.bin_op_expr.op2, scope); + if (val2 == irb->codegen->invalid_inst_src) + return irb->codegen->invalid_inst_src; + IrBasicBlockSrc *post_val2_block = irb->current_basic_block; + + ir_build_br(irb, scope, node, false_block, is_comptime); + + ir_set_cursor_at_end_and_append_block(irb, false_block); + + IrInstSrc **incoming_values = heap::c_allocator.allocate(2); + incoming_values[0] = val1; + incoming_values[1] = val2; + IrBasicBlockSrc **incoming_blocks = heap::c_allocator.allocate(2); + incoming_blocks[0] = post_val1_block; + incoming_blocks[1] = post_val2_block; + + return ir_build_phi(irb, scope, node, 2, incoming_blocks, incoming_values, nullptr); +} + +static ResultLocPeerParent *ir_build_result_peers(IrBuilderSrc *irb, IrInstSrc *cond_br_inst, + IrBasicBlockSrc *end_block, ResultLoc *parent, IrInstSrc *is_comptime) +{ + ResultLocPeerParent *peer_parent = heap::c_allocator.create(); + peer_parent->base.id = ResultLocIdPeerParent; + peer_parent->base.source_instruction = cond_br_inst; + peer_parent->base.allow_write_through_const = parent->allow_write_through_const; + peer_parent->end_bb = end_block; + peer_parent->is_comptime = is_comptime; + peer_parent->parent = parent; + + IrInstSrc *popped_inst = irb->current_basic_block->instruction_list.pop(); + ir_assert(popped_inst == cond_br_inst, &cond_br_inst->base); + + ir_build_reset_result(irb, cond_br_inst->base.scope, cond_br_inst->base.source_node, &peer_parent->base); + irb->current_basic_block->instruction_list.append(popped_inst); + + return peer_parent; +} + +static ResultLocPeerParent *ir_build_binary_result_peers(IrBuilderSrc *irb, IrInstSrc *cond_br_inst, + IrBasicBlockSrc *else_block, IrBasicBlockSrc *end_block, ResultLoc *parent, IrInstSrc *is_comptime) +{ + ResultLocPeerParent *peer_parent = ir_build_result_peers(irb, cond_br_inst, end_block, parent, is_comptime); + + peer_parent->peers.append(create_peer_result(peer_parent)); + peer_parent->peers.last()->next_bb = else_block; + + peer_parent->peers.append(create_peer_result(peer_parent)); + peer_parent->peers.last()->next_bb = end_block; + + return peer_parent; +} + +static IrInstSrc *ir_gen_orelse(IrBuilderSrc *irb, Scope *parent_scope, AstNode *node, LVal lval, + ResultLoc *result_loc) +{ + assert(node->type == NodeTypeBinOpExpr); + + AstNode *op1_node = node->data.bin_op_expr.op1; + AstNode *op2_node = node->data.bin_op_expr.op2; + + IrInstSrc *maybe_ptr = ir_gen_node_extra(irb, op1_node, parent_scope, LValPtr, nullptr); + if (maybe_ptr == irb->codegen->invalid_inst_src) + return irb->codegen->invalid_inst_src; + + IrInstSrc *maybe_val = ir_build_load_ptr(irb, parent_scope, node, maybe_ptr); + IrInstSrc *is_non_null = ir_build_test_non_null_src(irb, parent_scope, node, maybe_val); + + IrInstSrc *is_comptime; + if (ir_should_inline(irb->exec, parent_scope)) { + is_comptime = ir_build_const_bool(irb, parent_scope, node, true); + } else { + is_comptime = ir_build_test_comptime(irb, parent_scope, node, is_non_null); + } + + IrBasicBlockSrc *ok_block = ir_create_basic_block(irb, parent_scope, "OptionalNonNull"); + IrBasicBlockSrc *null_block = ir_create_basic_block(irb, parent_scope, "OptionalNull"); + IrBasicBlockSrc *end_block = ir_create_basic_block(irb, parent_scope, "OptionalEnd"); + IrInstSrc *cond_br_inst = ir_build_cond_br(irb, parent_scope, node, is_non_null, ok_block, null_block, is_comptime); + + ResultLocPeerParent *peer_parent = ir_build_binary_result_peers(irb, cond_br_inst, ok_block, end_block, + result_loc, is_comptime); + + ir_set_cursor_at_end_and_append_block(irb, null_block); + IrInstSrc *null_result = ir_gen_node_extra(irb, op2_node, parent_scope, LValNone, + &peer_parent->peers.at(0)->base); + if (null_result == irb->codegen->invalid_inst_src) + return irb->codegen->invalid_inst_src; + IrBasicBlockSrc *after_null_block = irb->current_basic_block; + if (!instr_is_unreachable(null_result)) + ir_mark_gen(ir_build_br(irb, parent_scope, node, end_block, is_comptime)); + + ir_set_cursor_at_end_and_append_block(irb, ok_block); + IrInstSrc *unwrapped_ptr = ir_build_optional_unwrap_ptr(irb, parent_scope, node, maybe_ptr, false); + IrInstSrc *unwrapped_payload = ir_build_load_ptr(irb, parent_scope, node, unwrapped_ptr); + ir_build_end_expr(irb, parent_scope, node, unwrapped_payload, &peer_parent->peers.at(1)->base); + IrBasicBlockSrc *after_ok_block = irb->current_basic_block; + ir_build_br(irb, parent_scope, node, end_block, is_comptime); + + ir_set_cursor_at_end_and_append_block(irb, end_block); + IrInstSrc **incoming_values = heap::c_allocator.allocate(2); + incoming_values[0] = null_result; + incoming_values[1] = unwrapped_payload; + IrBasicBlockSrc **incoming_blocks = heap::c_allocator.allocate(2); + incoming_blocks[0] = after_null_block; + incoming_blocks[1] = after_ok_block; + IrInstSrc *phi = ir_build_phi(irb, parent_scope, node, 2, incoming_blocks, incoming_values, peer_parent); + return ir_lval_wrap(irb, parent_scope, phi, lval, result_loc); +} + +static IrInstSrc *ir_gen_error_union(IrBuilderSrc *irb, Scope *parent_scope, AstNode *node) { + assert(node->type == NodeTypeBinOpExpr); + + AstNode *op1_node = node->data.bin_op_expr.op1; + AstNode *op2_node = node->data.bin_op_expr.op2; + + IrInstSrc *err_set = ir_gen_node(irb, op1_node, parent_scope); + if (err_set == irb->codegen->invalid_inst_src) + return irb->codegen->invalid_inst_src; + + IrInstSrc *payload = ir_gen_node(irb, op2_node, parent_scope); + if (payload == irb->codegen->invalid_inst_src) + return irb->codegen->invalid_inst_src; + + return ir_build_error_union(irb, parent_scope, node, err_set, payload); +} + +static IrInstSrc *ir_gen_bin_op(IrBuilderSrc *irb, Scope *scope, AstNode *node, LVal lval, ResultLoc *result_loc) { + assert(node->type == NodeTypeBinOpExpr); + + BinOpType bin_op_type = node->data.bin_op_expr.bin_op; + switch (bin_op_type) { + case BinOpTypeInvalid: + zig_unreachable(); + case BinOpTypeAssign: + return ir_lval_wrap(irb, scope, ir_gen_assign(irb, scope, node), lval, result_loc); + case BinOpTypeAssignTimes: + return ir_lval_wrap(irb, scope, ir_gen_assign_op(irb, scope, node, IrBinOpMult), lval, result_loc); + case BinOpTypeAssignTimesWrap: + return ir_lval_wrap(irb, scope, ir_gen_assign_op(irb, scope, node, IrBinOpMultWrap), lval, result_loc); + case BinOpTypeAssignDiv: + return ir_lval_wrap(irb, scope, ir_gen_assign_op(irb, scope, node, IrBinOpDivUnspecified), lval, result_loc); + case BinOpTypeAssignMod: + return ir_lval_wrap(irb, scope, ir_gen_assign_op(irb, scope, node, IrBinOpRemUnspecified), lval, result_loc); + case BinOpTypeAssignPlus: + return ir_lval_wrap(irb, scope, ir_gen_assign_op(irb, scope, node, IrBinOpAdd), lval, result_loc); + case BinOpTypeAssignPlusWrap: + return ir_lval_wrap(irb, scope, ir_gen_assign_op(irb, scope, node, IrBinOpAddWrap), lval, result_loc); + case BinOpTypeAssignMinus: + return ir_lval_wrap(irb, scope, ir_gen_assign_op(irb, scope, node, IrBinOpSub), lval, result_loc); + case BinOpTypeAssignMinusWrap: + return ir_lval_wrap(irb, scope, ir_gen_assign_op(irb, scope, node, IrBinOpSubWrap), lval, result_loc); + case BinOpTypeAssignBitShiftLeft: + return ir_lval_wrap(irb, scope, ir_gen_assign_op(irb, scope, node, IrBinOpBitShiftLeftLossy), lval, result_loc); + case BinOpTypeAssignBitShiftRight: + return ir_lval_wrap(irb, scope, ir_gen_assign_op(irb, scope, node, IrBinOpBitShiftRightLossy), lval, result_loc); + case BinOpTypeAssignBitAnd: + return ir_lval_wrap(irb, scope, ir_gen_assign_op(irb, scope, node, IrBinOpBinAnd), lval, result_loc); + case BinOpTypeAssignBitXor: + return ir_lval_wrap(irb, scope, ir_gen_assign_op(irb, scope, node, IrBinOpBinXor), lval, result_loc); + case BinOpTypeAssignBitOr: + return ir_lval_wrap(irb, scope, ir_gen_assign_op(irb, scope, node, IrBinOpBinOr), lval, result_loc); + case BinOpTypeBoolOr: + return ir_lval_wrap(irb, scope, ir_gen_bool_or(irb, scope, node), lval, result_loc); + case BinOpTypeBoolAnd: + return ir_lval_wrap(irb, scope, ir_gen_bool_and(irb, scope, node), lval, result_loc); + case BinOpTypeCmpEq: + return ir_lval_wrap(irb, scope, ir_gen_bin_op_id(irb, scope, node, IrBinOpCmpEq), lval, result_loc); + case BinOpTypeCmpNotEq: + return ir_lval_wrap(irb, scope, ir_gen_bin_op_id(irb, scope, node, IrBinOpCmpNotEq), lval, result_loc); + case BinOpTypeCmpLessThan: + return ir_lval_wrap(irb, scope, ir_gen_bin_op_id(irb, scope, node, IrBinOpCmpLessThan), lval, result_loc); + case BinOpTypeCmpGreaterThan: + return ir_lval_wrap(irb, scope, ir_gen_bin_op_id(irb, scope, node, IrBinOpCmpGreaterThan), lval, result_loc); + case BinOpTypeCmpLessOrEq: + return ir_lval_wrap(irb, scope, ir_gen_bin_op_id(irb, scope, node, IrBinOpCmpLessOrEq), lval, result_loc); + case BinOpTypeCmpGreaterOrEq: + return ir_lval_wrap(irb, scope, ir_gen_bin_op_id(irb, scope, node, IrBinOpCmpGreaterOrEq), lval, result_loc); + case BinOpTypeBinOr: + return ir_lval_wrap(irb, scope, ir_gen_bin_op_id(irb, scope, node, IrBinOpBinOr), lval, result_loc); + case BinOpTypeBinXor: + return ir_lval_wrap(irb, scope, ir_gen_bin_op_id(irb, scope, node, IrBinOpBinXor), lval, result_loc); + case BinOpTypeBinAnd: + return ir_lval_wrap(irb, scope, ir_gen_bin_op_id(irb, scope, node, IrBinOpBinAnd), lval, result_loc); + case BinOpTypeBitShiftLeft: + return ir_lval_wrap(irb, scope, ir_gen_bin_op_id(irb, scope, node, IrBinOpBitShiftLeftLossy), lval, result_loc); + case BinOpTypeBitShiftRight: + return ir_lval_wrap(irb, scope, ir_gen_bin_op_id(irb, scope, node, IrBinOpBitShiftRightLossy), lval, result_loc); + case BinOpTypeAdd: + return ir_lval_wrap(irb, scope, ir_gen_bin_op_id(irb, scope, node, IrBinOpAdd), lval, result_loc); + case BinOpTypeAddWrap: + return ir_lval_wrap(irb, scope, ir_gen_bin_op_id(irb, scope, node, IrBinOpAddWrap), lval, result_loc); + case BinOpTypeSub: + return ir_lval_wrap(irb, scope, ir_gen_bin_op_id(irb, scope, node, IrBinOpSub), lval, result_loc); + case BinOpTypeSubWrap: + return ir_lval_wrap(irb, scope, ir_gen_bin_op_id(irb, scope, node, IrBinOpSubWrap), lval, result_loc); + case BinOpTypeMult: + return ir_lval_wrap(irb, scope, ir_gen_bin_op_id(irb, scope, node, IrBinOpMult), lval, result_loc); + case BinOpTypeMultWrap: + return ir_lval_wrap(irb, scope, ir_gen_bin_op_id(irb, scope, node, IrBinOpMultWrap), lval, result_loc); + case BinOpTypeDiv: + return ir_lval_wrap(irb, scope, ir_gen_bin_op_id(irb, scope, node, IrBinOpDivUnspecified), lval, result_loc); + case BinOpTypeMod: + return ir_lval_wrap(irb, scope, ir_gen_bin_op_id(irb, scope, node, IrBinOpRemUnspecified), lval, result_loc); + case BinOpTypeArrayCat: + return ir_lval_wrap(irb, scope, ir_gen_bin_op_id(irb, scope, node, IrBinOpArrayCat), lval, result_loc); + case BinOpTypeArrayMult: + return ir_lval_wrap(irb, scope, ir_gen_bin_op_id(irb, scope, node, IrBinOpArrayMult), lval, result_loc); + case BinOpTypeMergeErrorSets: + return ir_lval_wrap(irb, scope, ir_gen_merge_err_sets(irb, scope, node), lval, result_loc); + case BinOpTypeUnwrapOptional: + return ir_gen_orelse(irb, scope, node, lval, result_loc); + case BinOpTypeErrorUnion: + return ir_lval_wrap(irb, scope, ir_gen_error_union(irb, scope, node), lval, result_loc); + } + zig_unreachable(); +} + +static IrInstSrc *ir_gen_int_lit(IrBuilderSrc *irb, Scope *scope, AstNode *node) { + assert(node->type == NodeTypeIntLiteral); + + RootStruct *root_struct = node->owner->data.structure.root_struct; + BigInt bigint; + token_number_literal_bigint(root_struct, &bigint, node->main_token); + return ir_build_const_bigint(irb, scope, node, bigint); +} + +static IrInstSrc *ir_gen_float_lit(IrBuilderSrc *irb, Scope *scope, AstNode *node) { + Error err; + assert(node->type == NodeTypeFloatLiteral); + + RootStruct *root_struct = node->owner->data.structure.root_struct; + const char *source = buf_ptr(root_struct->source_code); + uint32_t byte_offset = root_struct->token_locs[node->main_token].offset; + + BigFloat bigfloat; + if ((err = bigfloat_init_buf(&bigfloat, (const uint8_t *)source + byte_offset))) { + add_node_error(irb->codegen, node, buf_sprintf("float literal out of range of any type")); + return irb->codegen->invalid_inst_src; + } + + return ir_build_const_bigfloat(irb, scope, node, bigfloat); +} + +static IrInstSrc *ir_gen_char_lit(IrBuilderSrc *irb, Scope *scope, AstNode *node) { + Error err; + assert(node->type == NodeTypeCharLiteral); + + RootStruct *root_struct = node->owner->data.structure.root_struct; + const char *source = buf_ptr(root_struct->source_code); + uint32_t byte_offset = root_struct->token_locs[node->main_token].offset; + + src_assert(source[byte_offset] == '\'', node); + byte_offset += 1; + + uint32_t codepoint; + size_t bad_index; + if ((err = source_char_literal(source + byte_offset, &codepoint, &bad_index))) { + add_node_error(irb->codegen, node, buf_sprintf("invalid character")); + return irb->codegen->invalid_inst_src; + } + return ir_build_const_uint(irb, scope, node, codepoint); +} + +static IrInstSrc *ir_gen_null_literal(IrBuilderSrc *irb, Scope *scope, AstNode *node) { + assert(node->type == NodeTypeNullLiteral); + + return ir_build_const_null(irb, scope, node); +} + +static IrInstSrc *ir_gen_symbol(IrBuilderSrc *irb, Scope *scope, AstNode *node, LVal lval, ResultLoc *result_loc) { + Error err; + assert(node->type == NodeTypeIdentifier); + + Buf *variable_name = node_identifier_buf(node); + + if (buf_eql_str(variable_name, "_")) { + if (lval == LValAssign) { + IrInstSrcConst *const_instruction = ir_build_instruction(irb, scope, node); + const_instruction->value = irb->codegen->pass1_arena->create(); + const_instruction->value->type = get_pointer_to_type(irb->codegen, + irb->codegen->builtin_types.entry_void, false); + const_instruction->value->special = ConstValSpecialStatic; + const_instruction->value->data.x_ptr.special = ConstPtrSpecialDiscard; + return &const_instruction->base; + } else { + add_node_error(irb->codegen, node, buf_sprintf("`_` may only be used to assign things to")); + return irb->codegen->invalid_inst_src; + } + } + + ZigType *primitive_type; + if ((err = get_primitive_type(irb->codegen, variable_name, &primitive_type))) { + if (err == ErrorOverflow) { + add_node_error(irb->codegen, node, + buf_sprintf("primitive integer type '%s' exceeds maximum bit width of 65535", + buf_ptr(variable_name))); + return irb->codegen->invalid_inst_src; + } + assert(err == ErrorPrimitiveTypeNotFound); + } else { + IrInstSrc *value = ir_build_const_type(irb, scope, node, primitive_type); + if (lval == LValPtr || lval == LValAssign) { + return ir_build_ref_src(irb, scope, node, value); + } else { + return ir_expr_wrap(irb, scope, value, result_loc); + } + } + + ScopeFnDef *crossed_fndef_scope; + ZigVar *var = find_variable(irb->codegen, scope, variable_name, &crossed_fndef_scope); + if (var) { + IrInstSrc *var_ptr = ir_build_var_ptr_x(irb, scope, node, var, crossed_fndef_scope); + if (lval == LValPtr || lval == LValAssign) { + return var_ptr; + } else { + return ir_expr_wrap(irb, scope, ir_build_load_ptr(irb, scope, node, var_ptr), result_loc); + } + } + + Tld *tld = find_decl(irb->codegen, scope, variable_name); + if (tld) { + IrInstSrc *decl_ref = ir_build_decl_ref(irb, scope, node, tld, lval); + if (lval == LValPtr || lval == LValAssign) { + return decl_ref; + } else { + return ir_expr_wrap(irb, scope, decl_ref, result_loc); + } + } + + if (get_container_scope(node->owner)->any_imports_failed) { + // skip the error message since we had a failing import in this file + // if an import breaks we don't need redundant undeclared identifier errors + return irb->codegen->invalid_inst_src; + } + + return ir_build_undeclared_identifier(irb, scope, node, variable_name); +} + +static IrInstSrc *ir_gen_array_access(IrBuilderSrc *irb, Scope *scope, AstNode *node, LVal lval, + ResultLoc *result_loc) +{ + assert(node->type == NodeTypeArrayAccessExpr); + + AstNode *array_ref_node = node->data.array_access_expr.array_ref_expr; + IrInstSrc *array_ref_instruction = ir_gen_node_extra(irb, array_ref_node, scope, LValPtr, nullptr); + if (array_ref_instruction == irb->codegen->invalid_inst_src) + return array_ref_instruction; + + // Create an usize-typed result location to hold the subscript value, this + // makes it possible for the compiler to infer the subscript expression type + // if needed + IrInstSrc *usize_type_inst = ir_build_const_type(irb, scope, node, irb->codegen->builtin_types.entry_usize); + ResultLocCast *result_loc_cast = ir_build_cast_result_loc(irb, usize_type_inst, no_result_loc()); + + AstNode *subscript_node = node->data.array_access_expr.subscript; + IrInstSrc *subscript_value = ir_gen_node_extra(irb, subscript_node, scope, LValNone, &result_loc_cast->base); + if (subscript_value == irb->codegen->invalid_inst_src) + return irb->codegen->invalid_inst_src; + + IrInstSrc *subscript_instruction = ir_build_implicit_cast(irb, scope, subscript_node, subscript_value, result_loc_cast); + + IrInstSrc *ptr_instruction = ir_build_elem_ptr(irb, scope, node, array_ref_instruction, + subscript_instruction, true, PtrLenSingle, nullptr); + if (lval == LValPtr || lval == LValAssign) + return ptr_instruction; + + IrInstSrc *load_ptr = ir_build_load_ptr(irb, scope, node, ptr_instruction); + return ir_expr_wrap(irb, scope, load_ptr, result_loc); +} + +static IrInstSrc *ir_gen_field_access(IrBuilderSrc *irb, Scope *scope, AstNode *node) { + assert(node->type == NodeTypeFieldAccessExpr); + + AstNode *container_ref_node = node->data.field_access_expr.struct_expr; + Buf *field_name = node->data.field_access_expr.field_name; + + IrInstSrc *container_ref_instruction = ir_gen_node_extra(irb, container_ref_node, scope, LValPtr, nullptr); + if (container_ref_instruction == irb->codegen->invalid_inst_src) + return container_ref_instruction; + + return ir_build_field_ptr(irb, scope, node, container_ref_instruction, field_name, false); +} + +static IrInstSrc *ir_gen_overflow_op(IrBuilderSrc *irb, Scope *scope, AstNode *node, IrOverflowOp op) { + assert(node->type == NodeTypeFnCallExpr); + + AstNode *type_node = node->data.fn_call_expr.params.at(0); + AstNode *op1_node = node->data.fn_call_expr.params.at(1); + AstNode *op2_node = node->data.fn_call_expr.params.at(2); + AstNode *result_ptr_node = node->data.fn_call_expr.params.at(3); + + + IrInstSrc *type_value = ir_gen_node(irb, type_node, scope); + if (type_value == irb->codegen->invalid_inst_src) + return irb->codegen->invalid_inst_src; + + IrInstSrc *op1 = ir_gen_node(irb, op1_node, scope); + if (op1 == irb->codegen->invalid_inst_src) + return irb->codegen->invalid_inst_src; + + IrInstSrc *op2 = ir_gen_node(irb, op2_node, scope); + if (op2 == irb->codegen->invalid_inst_src) + return irb->codegen->invalid_inst_src; + + IrInstSrc *result_ptr = ir_gen_node(irb, result_ptr_node, scope); + if (result_ptr == irb->codegen->invalid_inst_src) + return irb->codegen->invalid_inst_src; + + return ir_build_overflow_op_src(irb, scope, node, op, type_value, op1, op2, result_ptr); +} + +static IrInstSrc *ir_gen_mul_add(IrBuilderSrc *irb, Scope *scope, AstNode *node) { + assert(node->type == NodeTypeFnCallExpr); + + AstNode *type_node = node->data.fn_call_expr.params.at(0); + AstNode *op1_node = node->data.fn_call_expr.params.at(1); + AstNode *op2_node = node->data.fn_call_expr.params.at(2); + AstNode *op3_node = node->data.fn_call_expr.params.at(3); + + IrInstSrc *type_value = ir_gen_node(irb, type_node, scope); + if (type_value == irb->codegen->invalid_inst_src) + return irb->codegen->invalid_inst_src; + + IrInstSrc *op1 = ir_gen_node(irb, op1_node, scope); + if (op1 == irb->codegen->invalid_inst_src) + return irb->codegen->invalid_inst_src; + + IrInstSrc *op2 = ir_gen_node(irb, op2_node, scope); + if (op2 == irb->codegen->invalid_inst_src) + return irb->codegen->invalid_inst_src; + + IrInstSrc *op3 = ir_gen_node(irb, op3_node, scope); + if (op3 == irb->codegen->invalid_inst_src) + return irb->codegen->invalid_inst_src; + + return ir_build_mul_add_src(irb, scope, node, type_value, op1, op2, op3); +} + +static IrInstSrc *ir_gen_this(IrBuilderSrc *irb, Scope *orig_scope, AstNode *node) { + for (Scope *it_scope = orig_scope; it_scope != nullptr; it_scope = it_scope->parent) { + if (it_scope->id == ScopeIdDecls) { + ScopeDecls *decls_scope = (ScopeDecls *)it_scope; + ZigType *container_type = decls_scope->container_type; + if (container_type != nullptr) { + return ir_build_const_type(irb, orig_scope, node, container_type); + } else { + return ir_build_const_import(irb, orig_scope, node, decls_scope->import); + } + } + } + zig_unreachable(); +} + +static IrInstSrc *ir_gen_async_call(IrBuilderSrc *irb, Scope *scope, AstNode *await_node, AstNode *call_node, + LVal lval, ResultLoc *result_loc) +{ + if (call_node->data.fn_call_expr.params.length != 4) { + add_node_error(irb->codegen, call_node, + buf_sprintf("expected 4 arguments, found %" ZIG_PRI_usize, + call_node->data.fn_call_expr.params.length)); + return irb->codegen->invalid_inst_src; + } + + AstNode *bytes_node = call_node->data.fn_call_expr.params.at(0); + IrInstSrc *bytes = ir_gen_node(irb, bytes_node, scope); + if (bytes == irb->codegen->invalid_inst_src) + return bytes; + + AstNode *ret_ptr_node = call_node->data.fn_call_expr.params.at(1); + IrInstSrc *ret_ptr = ir_gen_node(irb, ret_ptr_node, scope); + if (ret_ptr == irb->codegen->invalid_inst_src) + return ret_ptr; + + AstNode *fn_ref_node = call_node->data.fn_call_expr.params.at(2); + IrInstSrc *fn_ref = ir_gen_node(irb, fn_ref_node, scope); + if (fn_ref == irb->codegen->invalid_inst_src) + return fn_ref; + + CallModifier modifier = (await_node == nullptr) ? CallModifierAsync : CallModifierNone; + bool is_async_call_builtin = true; + AstNode *args_node = call_node->data.fn_call_expr.params.at(3); + if (args_node->type == NodeTypeContainerInitExpr) { + if (args_node->data.container_init_expr.kind == ContainerInitKindArray || + args_node->data.container_init_expr.entries.length == 0) + { + size_t arg_count = args_node->data.container_init_expr.entries.length; + IrInstSrc **args = heap::c_allocator.allocate(arg_count); + for (size_t i = 0; i < arg_count; i += 1) { + AstNode *arg_node = args_node->data.container_init_expr.entries.at(i); + IrInstSrc *arg = ir_gen_node(irb, arg_node, scope); + if (arg == irb->codegen->invalid_inst_src) + return arg; + args[i] = arg; + } + + IrInstSrc *call = ir_build_call_src(irb, scope, call_node, nullptr, fn_ref, arg_count, args, + ret_ptr, modifier, is_async_call_builtin, bytes, result_loc); + return ir_lval_wrap(irb, scope, call, lval, result_loc); + } else { + exec_add_error_node(irb->codegen, irb->exec, args_node, + buf_sprintf("TODO: @asyncCall with anon struct literal")); + return irb->codegen->invalid_inst_src; + } + } + IrInstSrc *args = ir_gen_node(irb, args_node, scope); + if (args == irb->codegen->invalid_inst_src) + return args; + + IrInstSrc *call = ir_build_async_call_extra(irb, scope, call_node, modifier, fn_ref, ret_ptr, bytes, args, result_loc); + return ir_lval_wrap(irb, scope, call, lval, result_loc); +} + +static IrInstSrc *ir_gen_fn_call_with_args(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, + AstNode *fn_ref_node, CallModifier modifier, IrInstSrc *options, + AstNode **args_ptr, size_t args_len, LVal lval, ResultLoc *result_loc) +{ + IrInstSrc *fn_ref = ir_gen_node(irb, fn_ref_node, scope); + if (fn_ref == irb->codegen->invalid_inst_src) + return fn_ref; + + IrInstSrc *fn_type = ir_build_typeof_1(irb, scope, source_node, fn_ref); + + IrInstSrc **args = heap::c_allocator.allocate(args_len); + for (size_t i = 0; i < args_len; i += 1) { + AstNode *arg_node = args_ptr[i]; + + IrInstSrc *arg_index = ir_build_const_usize(irb, scope, arg_node, i); + IrInstSrc *arg_type = ir_build_arg_type(irb, scope, source_node, fn_type, arg_index, true); + ResultLoc *no_result = no_result_loc(); + ir_build_reset_result(irb, scope, source_node, no_result); + ResultLocCast *result_loc_cast = ir_build_cast_result_loc(irb, arg_type, no_result); + + IrInstSrc *arg = ir_gen_node_extra(irb, arg_node, scope, LValNone, &result_loc_cast->base); + if (arg == irb->codegen->invalid_inst_src) + return arg; + + args[i] = ir_build_implicit_cast(irb, scope, arg_node, arg, result_loc_cast); + } + + IrInstSrc *fn_call; + if (options != nullptr) { + fn_call = ir_build_call_args(irb, scope, source_node, options, fn_ref, args, args_len, result_loc); + } else { + fn_call = ir_build_call_src(irb, scope, source_node, nullptr, fn_ref, args_len, args, nullptr, + modifier, false, nullptr, result_loc); + } + return ir_lval_wrap(irb, scope, fn_call, lval, result_loc); +} + +static IrInstSrc *ir_gen_builtin_fn_call(IrBuilderSrc *irb, Scope *scope, AstNode *node, LVal lval, + ResultLoc *result_loc) +{ + assert(node->type == NodeTypeFnCallExpr); + + AstNode *fn_ref_expr = node->data.fn_call_expr.fn_ref_expr; + Buf *name = node_identifier_buf(fn_ref_expr); + auto entry = irb->codegen->builtin_fn_table.maybe_get(name); + + if (!entry) { + add_node_error(irb->codegen, node, + buf_sprintf("invalid builtin function: '%s'", buf_ptr(name))); + return irb->codegen->invalid_inst_src; + } + + BuiltinFnEntry *builtin_fn = entry->value; + size_t actual_param_count = node->data.fn_call_expr.params.length; + + if (builtin_fn->param_count != SIZE_MAX && builtin_fn->param_count != actual_param_count) { + add_node_error(irb->codegen, node, + buf_sprintf("expected %" ZIG_PRI_usize " argument(s), found %" ZIG_PRI_usize, + builtin_fn->param_count, actual_param_count)); + return irb->codegen->invalid_inst_src; + } + + switch (builtin_fn->id) { + case BuiltinFnIdInvalid: + zig_unreachable(); + case BuiltinFnIdTypeof: + { + Scope *sub_scope = create_typeof_scope(irb->codegen, node, scope); + + size_t arg_count = node->data.fn_call_expr.params.length; + + IrInstSrc *type_of; + + if (arg_count == 0) { + add_node_error(irb->codegen, node, + buf_sprintf("expected at least 1 argument, found 0")); + return irb->codegen->invalid_inst_src; + } else if (arg_count == 1) { + AstNode *arg0_node = node->data.fn_call_expr.params.at(0); + IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, sub_scope); + if (arg0_value == irb->codegen->invalid_inst_src) + return arg0_value; + + type_of = ir_build_typeof_1(irb, scope, node, arg0_value); + } else { + IrInstSrc **args = heap::c_allocator.allocate(arg_count); + for (size_t i = 0; i < arg_count; i += 1) { + AstNode *arg_node = node->data.fn_call_expr.params.at(i); + IrInstSrc *arg = ir_gen_node(irb, arg_node, sub_scope); + if (arg == irb->codegen->invalid_inst_src) + return irb->codegen->invalid_inst_src; + args[i] = arg; + } + + type_of = ir_build_typeof_n(irb, scope, node, args, arg_count); + } + return ir_lval_wrap(irb, scope, type_of, lval, result_loc); + } + case BuiltinFnIdSetCold: + { + AstNode *arg0_node = node->data.fn_call_expr.params.at(0); + IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); + if (arg0_value == irb->codegen->invalid_inst_src) + return arg0_value; + + IrInstSrc *set_cold = ir_build_set_cold(irb, scope, node, arg0_value); + return ir_lval_wrap(irb, scope, set_cold, lval, result_loc); + } + case BuiltinFnIdSetRuntimeSafety: + { + AstNode *arg0_node = node->data.fn_call_expr.params.at(0); + IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); + if (arg0_value == irb->codegen->invalid_inst_src) + return arg0_value; + + IrInstSrc *set_safety = ir_build_set_runtime_safety(irb, scope, node, arg0_value); + return ir_lval_wrap(irb, scope, set_safety, lval, result_loc); + } + case BuiltinFnIdSetFloatMode: + { + AstNode *arg0_node = node->data.fn_call_expr.params.at(0); + IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); + if (arg0_value == irb->codegen->invalid_inst_src) + return arg0_value; + + IrInstSrc *set_float_mode = ir_build_set_float_mode(irb, scope, node, arg0_value); + return ir_lval_wrap(irb, scope, set_float_mode, lval, result_loc); + } + case BuiltinFnIdSizeof: + case BuiltinFnIdBitSizeof: + { + AstNode *arg0_node = node->data.fn_call_expr.params.at(0); + IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); + if (arg0_value == irb->codegen->invalid_inst_src) + return arg0_value; + + IrInstSrc *size_of = ir_build_size_of(irb, scope, node, arg0_value, builtin_fn->id == BuiltinFnIdBitSizeof); + return ir_lval_wrap(irb, scope, size_of, lval, result_loc); + } + case BuiltinFnIdImport: + { + AstNode *arg0_node = node->data.fn_call_expr.params.at(0); + IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); + if (arg0_value == irb->codegen->invalid_inst_src) + return arg0_value; + + IrInstSrc *import = ir_build_import(irb, scope, node, arg0_value); + return ir_lval_wrap(irb, scope, import, lval, result_loc); + } + case BuiltinFnIdCImport: + { + IrInstSrc *c_import = ir_build_c_import(irb, scope, node); + return ir_lval_wrap(irb, scope, c_import, lval, result_loc); + } + case BuiltinFnIdCInclude: + { + AstNode *arg0_node = node->data.fn_call_expr.params.at(0); + IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); + if (arg0_value == irb->codegen->invalid_inst_src) + return arg0_value; + + if (!exec_c_import_buf(irb->exec)) { + add_node_error(irb->codegen, node, buf_sprintf("C include valid only inside C import block")); + return irb->codegen->invalid_inst_src; + } + + IrInstSrc *c_include = ir_build_c_include(irb, scope, node, arg0_value); + return ir_lval_wrap(irb, scope, c_include, lval, result_loc); + } + case BuiltinFnIdCDefine: + { + AstNode *arg0_node = node->data.fn_call_expr.params.at(0); + IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); + if (arg0_value == irb->codegen->invalid_inst_src) + return arg0_value; + + AstNode *arg1_node = node->data.fn_call_expr.params.at(1); + IrInstSrc *arg1_value = ir_gen_node(irb, arg1_node, scope); + if (arg1_value == irb->codegen->invalid_inst_src) + return arg1_value; + + if (!exec_c_import_buf(irb->exec)) { + add_node_error(irb->codegen, node, buf_sprintf("C define valid only inside C import block")); + return irb->codegen->invalid_inst_src; + } + + IrInstSrc *c_define = ir_build_c_define(irb, scope, node, arg0_value, arg1_value); + return ir_lval_wrap(irb, scope, c_define, lval, result_loc); + } + case BuiltinFnIdCUndef: + { + AstNode *arg0_node = node->data.fn_call_expr.params.at(0); + IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); + if (arg0_value == irb->codegen->invalid_inst_src) + return arg0_value; + + if (!exec_c_import_buf(irb->exec)) { + add_node_error(irb->codegen, node, buf_sprintf("C undef valid only inside C import block")); + return irb->codegen->invalid_inst_src; + } + + IrInstSrc *c_undef = ir_build_c_undef(irb, scope, node, arg0_value); + return ir_lval_wrap(irb, scope, c_undef, lval, result_loc); + } + case BuiltinFnIdCompileErr: + { + AstNode *arg0_node = node->data.fn_call_expr.params.at(0); + IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); + if (arg0_value == irb->codegen->invalid_inst_src) + return arg0_value; + + IrInstSrc *compile_err = ir_build_compile_err(irb, scope, node, arg0_value); + return ir_lval_wrap(irb, scope, compile_err, lval, result_loc); + } + case BuiltinFnIdCompileLog: + { + IrInstSrc **args = heap::c_allocator.allocate(actual_param_count); + + for (size_t i = 0; i < actual_param_count; i += 1) { + AstNode *arg_node = node->data.fn_call_expr.params.at(i); + args[i] = ir_gen_node(irb, arg_node, scope); + if (args[i] == irb->codegen->invalid_inst_src) + return irb->codegen->invalid_inst_src; + } + + IrInstSrc *compile_log = ir_build_compile_log(irb, scope, node, actual_param_count, args); + return ir_lval_wrap(irb, scope, compile_log, lval, result_loc); + } + case BuiltinFnIdErrName: + { + AstNode *arg0_node = node->data.fn_call_expr.params.at(0); + IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); + if (arg0_value == irb->codegen->invalid_inst_src) + return arg0_value; + + IrInstSrc *err_name = ir_build_err_name(irb, scope, node, arg0_value); + return ir_lval_wrap(irb, scope, err_name, lval, result_loc); + } + case BuiltinFnIdEmbedFile: + { + AstNode *arg0_node = node->data.fn_call_expr.params.at(0); + IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); + if (arg0_value == irb->codegen->invalid_inst_src) + return arg0_value; + + IrInstSrc *embed_file = ir_build_embed_file(irb, scope, node, arg0_value); + return ir_lval_wrap(irb, scope, embed_file, lval, result_loc); + } + case BuiltinFnIdCmpxchgWeak: + case BuiltinFnIdCmpxchgStrong: + { + AstNode *arg0_node = node->data.fn_call_expr.params.at(0); + IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); + if (arg0_value == irb->codegen->invalid_inst_src) + return arg0_value; + + AstNode *arg1_node = node->data.fn_call_expr.params.at(1); + IrInstSrc *arg1_value = ir_gen_node(irb, arg1_node, scope); + if (arg1_value == irb->codegen->invalid_inst_src) + return arg1_value; + + AstNode *arg2_node = node->data.fn_call_expr.params.at(2); + IrInstSrc *arg2_value = ir_gen_node(irb, arg2_node, scope); + if (arg2_value == irb->codegen->invalid_inst_src) + return arg2_value; + + AstNode *arg3_node = node->data.fn_call_expr.params.at(3); + IrInstSrc *arg3_value = ir_gen_node(irb, arg3_node, scope); + if (arg3_value == irb->codegen->invalid_inst_src) + return arg3_value; + + AstNode *arg4_node = node->data.fn_call_expr.params.at(4); + IrInstSrc *arg4_value = ir_gen_node(irb, arg4_node, scope); + if (arg4_value == irb->codegen->invalid_inst_src) + return arg4_value; + + AstNode *arg5_node = node->data.fn_call_expr.params.at(5); + IrInstSrc *arg5_value = ir_gen_node(irb, arg5_node, scope); + if (arg5_value == irb->codegen->invalid_inst_src) + return arg5_value; + + IrInstSrc *cmpxchg = ir_build_cmpxchg_src(irb, scope, node, arg0_value, arg1_value, + arg2_value, arg3_value, arg4_value, arg5_value, (builtin_fn->id == BuiltinFnIdCmpxchgWeak), + result_loc); + return ir_lval_wrap(irb, scope, cmpxchg, lval, result_loc); + } + case BuiltinFnIdFence: + { + AstNode *arg0_node = node->data.fn_call_expr.params.at(0); + IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); + if (arg0_value == irb->codegen->invalid_inst_src) + return arg0_value; + + IrInstSrc *fence = ir_build_fence(irb, scope, node, arg0_value); + return ir_lval_wrap(irb, scope, fence, lval, result_loc); + } + case BuiltinFnIdReduce: + { + AstNode *arg0_node = node->data.fn_call_expr.params.at(0); + IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); + if (arg0_value == irb->codegen->invalid_inst_src) + return arg0_value; + + AstNode *arg1_node = node->data.fn_call_expr.params.at(1); + IrInstSrc *arg1_value = ir_gen_node(irb, arg1_node, scope); + if (arg1_value == irb->codegen->invalid_inst_src) + return arg1_value; + + IrInstSrc *reduce = ir_build_reduce(irb, scope, node, arg0_value, arg1_value); + return ir_lval_wrap(irb, scope, reduce, lval, result_loc); + } + case BuiltinFnIdDivExact: + { + AstNode *arg0_node = node->data.fn_call_expr.params.at(0); + IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); + if (arg0_value == irb->codegen->invalid_inst_src) + return arg0_value; + + AstNode *arg1_node = node->data.fn_call_expr.params.at(1); + IrInstSrc *arg1_value = ir_gen_node(irb, arg1_node, scope); + if (arg1_value == irb->codegen->invalid_inst_src) + return arg1_value; + + IrInstSrc *bin_op = ir_build_bin_op(irb, scope, node, IrBinOpDivExact, arg0_value, arg1_value, true); + return ir_lval_wrap(irb, scope, bin_op, lval, result_loc); + } + case BuiltinFnIdDivTrunc: + { + AstNode *arg0_node = node->data.fn_call_expr.params.at(0); + IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); + if (arg0_value == irb->codegen->invalid_inst_src) + return arg0_value; + + AstNode *arg1_node = node->data.fn_call_expr.params.at(1); + IrInstSrc *arg1_value = ir_gen_node(irb, arg1_node, scope); + if (arg1_value == irb->codegen->invalid_inst_src) + return arg1_value; + + IrInstSrc *bin_op = ir_build_bin_op(irb, scope, node, IrBinOpDivTrunc, arg0_value, arg1_value, true); + return ir_lval_wrap(irb, scope, bin_op, lval, result_loc); + } + case BuiltinFnIdDivFloor: + { + AstNode *arg0_node = node->data.fn_call_expr.params.at(0); + IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); + if (arg0_value == irb->codegen->invalid_inst_src) + return arg0_value; + + AstNode *arg1_node = node->data.fn_call_expr.params.at(1); + IrInstSrc *arg1_value = ir_gen_node(irb, arg1_node, scope); + if (arg1_value == irb->codegen->invalid_inst_src) + return arg1_value; + + IrInstSrc *bin_op = ir_build_bin_op(irb, scope, node, IrBinOpDivFloor, arg0_value, arg1_value, true); + return ir_lval_wrap(irb, scope, bin_op, lval, result_loc); + } + case BuiltinFnIdRem: + { + AstNode *arg0_node = node->data.fn_call_expr.params.at(0); + IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); + if (arg0_value == irb->codegen->invalid_inst_src) + return arg0_value; + + AstNode *arg1_node = node->data.fn_call_expr.params.at(1); + IrInstSrc *arg1_value = ir_gen_node(irb, arg1_node, scope); + if (arg1_value == irb->codegen->invalid_inst_src) + return arg1_value; + + IrInstSrc *bin_op = ir_build_bin_op(irb, scope, node, IrBinOpRemRem, arg0_value, arg1_value, true); + return ir_lval_wrap(irb, scope, bin_op, lval, result_loc); + } + case BuiltinFnIdMod: + { + AstNode *arg0_node = node->data.fn_call_expr.params.at(0); + IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); + if (arg0_value == irb->codegen->invalid_inst_src) + return arg0_value; + + AstNode *arg1_node = node->data.fn_call_expr.params.at(1); + IrInstSrc *arg1_value = ir_gen_node(irb, arg1_node, scope); + if (arg1_value == irb->codegen->invalid_inst_src) + return arg1_value; + + IrInstSrc *bin_op = ir_build_bin_op(irb, scope, node, IrBinOpRemMod, arg0_value, arg1_value, true); + return ir_lval_wrap(irb, scope, bin_op, lval, result_loc); + } + case BuiltinFnIdSqrt: + case BuiltinFnIdSin: + case BuiltinFnIdCos: + case BuiltinFnIdExp: + case BuiltinFnIdExp2: + case BuiltinFnIdLog: + case BuiltinFnIdLog2: + case BuiltinFnIdLog10: + case BuiltinFnIdFabs: + case BuiltinFnIdFloor: + case BuiltinFnIdCeil: + case BuiltinFnIdTrunc: + case BuiltinFnIdNearbyInt: + case BuiltinFnIdRound: + { + AstNode *arg0_node = node->data.fn_call_expr.params.at(0); + IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); + if (arg0_value == irb->codegen->invalid_inst_src) + return arg0_value; + + IrInstSrc *inst = ir_build_float_op_src(irb, scope, node, arg0_value, builtin_fn->id); + return ir_lval_wrap(irb, scope, inst, lval, result_loc); + } + case BuiltinFnIdTruncate: + { + AstNode *arg0_node = node->data.fn_call_expr.params.at(0); + IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); + if (arg0_value == irb->codegen->invalid_inst_src) + return arg0_value; + + AstNode *arg1_node = node->data.fn_call_expr.params.at(1); + IrInstSrc *arg1_value = ir_gen_node(irb, arg1_node, scope); + if (arg1_value == irb->codegen->invalid_inst_src) + return arg1_value; + + IrInstSrc *truncate = ir_build_truncate(irb, scope, node, arg0_value, arg1_value); + return ir_lval_wrap(irb, scope, truncate, lval, result_loc); + } + case BuiltinFnIdIntCast: + { + AstNode *arg0_node = node->data.fn_call_expr.params.at(0); + IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); + if (arg0_value == irb->codegen->invalid_inst_src) + return arg0_value; + + AstNode *arg1_node = node->data.fn_call_expr.params.at(1); + IrInstSrc *arg1_value = ir_gen_node(irb, arg1_node, scope); + if (arg1_value == irb->codegen->invalid_inst_src) + return arg1_value; + + IrInstSrc *result = ir_build_int_cast(irb, scope, node, arg0_value, arg1_value); + return ir_lval_wrap(irb, scope, result, lval, result_loc); + } + case BuiltinFnIdFloatCast: + { + AstNode *arg0_node = node->data.fn_call_expr.params.at(0); + IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); + if (arg0_value == irb->codegen->invalid_inst_src) + return arg0_value; + + AstNode *arg1_node = node->data.fn_call_expr.params.at(1); + IrInstSrc *arg1_value = ir_gen_node(irb, arg1_node, scope); + if (arg1_value == irb->codegen->invalid_inst_src) + return arg1_value; + + IrInstSrc *result = ir_build_float_cast(irb, scope, node, arg0_value, arg1_value); + return ir_lval_wrap(irb, scope, result, lval, result_loc); + } + case BuiltinFnIdErrSetCast: + { + AstNode *arg0_node = node->data.fn_call_expr.params.at(0); + IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); + if (arg0_value == irb->codegen->invalid_inst_src) + return arg0_value; + + AstNode *arg1_node = node->data.fn_call_expr.params.at(1); + IrInstSrc *arg1_value = ir_gen_node(irb, arg1_node, scope); + if (arg1_value == irb->codegen->invalid_inst_src) + return arg1_value; + + IrInstSrc *result = ir_build_err_set_cast(irb, scope, node, arg0_value, arg1_value); + return ir_lval_wrap(irb, scope, result, lval, result_loc); + } + case BuiltinFnIdIntToFloat: + { + AstNode *arg0_node = node->data.fn_call_expr.params.at(0); + IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); + if (arg0_value == irb->codegen->invalid_inst_src) + return arg0_value; + + AstNode *arg1_node = node->data.fn_call_expr.params.at(1); + IrInstSrc *arg1_value = ir_gen_node(irb, arg1_node, scope); + if (arg1_value == irb->codegen->invalid_inst_src) + return arg1_value; + + IrInstSrc *result = ir_build_int_to_float(irb, scope, node, arg0_value, arg1_value); + return ir_lval_wrap(irb, scope, result, lval, result_loc); + } + case BuiltinFnIdFloatToInt: + { + AstNode *arg0_node = node->data.fn_call_expr.params.at(0); + IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); + if (arg0_value == irb->codegen->invalid_inst_src) + return arg0_value; + + AstNode *arg1_node = node->data.fn_call_expr.params.at(1); + IrInstSrc *arg1_value = ir_gen_node(irb, arg1_node, scope); + if (arg1_value == irb->codegen->invalid_inst_src) + return arg1_value; + + IrInstSrc *result = ir_build_float_to_int(irb, scope, node, arg0_value, arg1_value); + return ir_lval_wrap(irb, scope, result, lval, result_loc); + } + case BuiltinFnIdErrToInt: + { + AstNode *arg0_node = node->data.fn_call_expr.params.at(0); + IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); + if (arg0_value == irb->codegen->invalid_inst_src) + return arg0_value; + + IrInstSrc *result = ir_build_err_to_int_src(irb, scope, node, arg0_value); + return ir_lval_wrap(irb, scope, result, lval, result_loc); + } + case BuiltinFnIdIntToErr: + { + AstNode *arg0_node = node->data.fn_call_expr.params.at(0); + IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); + if (arg0_value == irb->codegen->invalid_inst_src) + return arg0_value; + + IrInstSrc *result = ir_build_int_to_err_src(irb, scope, node, arg0_value); + return ir_lval_wrap(irb, scope, result, lval, result_loc); + } + case BuiltinFnIdBoolToInt: + { + AstNode *arg0_node = node->data.fn_call_expr.params.at(0); + IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); + if (arg0_value == irb->codegen->invalid_inst_src) + return arg0_value; + + IrInstSrc *result = ir_build_bool_to_int(irb, scope, node, arg0_value); + return ir_lval_wrap(irb, scope, result, lval, result_loc); + } + case BuiltinFnIdVectorType: + { + AstNode *arg0_node = node->data.fn_call_expr.params.at(0); + IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); + if (arg0_value == irb->codegen->invalid_inst_src) + return arg0_value; + + AstNode *arg1_node = node->data.fn_call_expr.params.at(1); + IrInstSrc *arg1_value = ir_gen_node(irb, arg1_node, scope); + if (arg1_value == irb->codegen->invalid_inst_src) + return arg1_value; + + IrInstSrc *vector_type = ir_build_vector_type(irb, scope, node, arg0_value, arg1_value); + return ir_lval_wrap(irb, scope, vector_type, lval, result_loc); + } + case BuiltinFnIdShuffle: + { + AstNode *arg0_node = node->data.fn_call_expr.params.at(0); + IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); + if (arg0_value == irb->codegen->invalid_inst_src) + return arg0_value; + + AstNode *arg1_node = node->data.fn_call_expr.params.at(1); + IrInstSrc *arg1_value = ir_gen_node(irb, arg1_node, scope); + if (arg1_value == irb->codegen->invalid_inst_src) + return arg1_value; + + AstNode *arg2_node = node->data.fn_call_expr.params.at(2); + IrInstSrc *arg2_value = ir_gen_node(irb, arg2_node, scope); + if (arg2_value == irb->codegen->invalid_inst_src) + return arg2_value; + + AstNode *arg3_node = node->data.fn_call_expr.params.at(3); + IrInstSrc *arg3_value = ir_gen_node(irb, arg3_node, scope); + if (arg3_value == irb->codegen->invalid_inst_src) + return arg3_value; + + IrInstSrc *shuffle_vector = ir_build_shuffle_vector(irb, scope, node, + arg0_value, arg1_value, arg2_value, arg3_value); + return ir_lval_wrap(irb, scope, shuffle_vector, lval, result_loc); + } + case BuiltinFnIdSplat: + { + AstNode *arg0_node = node->data.fn_call_expr.params.at(0); + IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); + if (arg0_value == irb->codegen->invalid_inst_src) + return arg0_value; + + AstNode *arg1_node = node->data.fn_call_expr.params.at(1); + IrInstSrc *arg1_value = ir_gen_node(irb, arg1_node, scope); + if (arg1_value == irb->codegen->invalid_inst_src) + return arg1_value; + + IrInstSrc *splat = ir_build_splat_src(irb, scope, node, + arg0_value, arg1_value); + return ir_lval_wrap(irb, scope, splat, lval, result_loc); + } + case BuiltinFnIdMemcpy: + { + AstNode *arg0_node = node->data.fn_call_expr.params.at(0); + IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); + if (arg0_value == irb->codegen->invalid_inst_src) + return arg0_value; + + AstNode *arg1_node = node->data.fn_call_expr.params.at(1); + IrInstSrc *arg1_value = ir_gen_node(irb, arg1_node, scope); + if (arg1_value == irb->codegen->invalid_inst_src) + return arg1_value; + + AstNode *arg2_node = node->data.fn_call_expr.params.at(2); + IrInstSrc *arg2_value = ir_gen_node(irb, arg2_node, scope); + if (arg2_value == irb->codegen->invalid_inst_src) + return arg2_value; + + IrInstSrc *ir_memcpy = ir_build_memcpy_src(irb, scope, node, arg0_value, arg1_value, arg2_value); + return ir_lval_wrap(irb, scope, ir_memcpy, lval, result_loc); + } + case BuiltinFnIdMemset: + { + AstNode *arg0_node = node->data.fn_call_expr.params.at(0); + IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); + if (arg0_value == irb->codegen->invalid_inst_src) + return arg0_value; + + AstNode *arg1_node = node->data.fn_call_expr.params.at(1); + IrInstSrc *arg1_value = ir_gen_node(irb, arg1_node, scope); + if (arg1_value == irb->codegen->invalid_inst_src) + return arg1_value; + + AstNode *arg2_node = node->data.fn_call_expr.params.at(2); + IrInstSrc *arg2_value = ir_gen_node(irb, arg2_node, scope); + if (arg2_value == irb->codegen->invalid_inst_src) + return arg2_value; + + IrInstSrc *ir_memset = ir_build_memset_src(irb, scope, node, arg0_value, arg1_value, arg2_value); + return ir_lval_wrap(irb, scope, ir_memset, lval, result_loc); + } + case BuiltinFnIdWasmMemorySize: + { + AstNode *arg0_node = node->data.fn_call_expr.params.at(0); + IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); + if (arg0_value == irb->codegen->invalid_inst_src) + return arg0_value; + + IrInstSrc *ir_wasm_memory_size = ir_build_wasm_memory_size_src(irb, scope, node, arg0_value); + return ir_lval_wrap(irb, scope, ir_wasm_memory_size, lval, result_loc); + } + case BuiltinFnIdWasmMemoryGrow: + { + AstNode *arg0_node = node->data.fn_call_expr.params.at(0); + IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); + if (arg0_value == irb->codegen->invalid_inst_src) + return arg0_value; + + AstNode *arg1_node = node->data.fn_call_expr.params.at(1); + IrInstSrc *arg1_value = ir_gen_node(irb, arg1_node, scope); + if (arg1_value == irb->codegen->invalid_inst_src) + return arg1_value; + + IrInstSrc *ir_wasm_memory_grow = ir_build_wasm_memory_grow_src(irb, scope, node, arg0_value, arg1_value); + return ir_lval_wrap(irb, scope, ir_wasm_memory_grow, lval, result_loc); + } + case BuiltinFnIdField: + { + AstNode *arg0_node = node->data.fn_call_expr.params.at(0); + IrInstSrc *arg0_value = ir_gen_node_extra(irb, arg0_node, scope, LValPtr, nullptr); + if (arg0_value == irb->codegen->invalid_inst_src) + return arg0_value; + + AstNode *arg1_node = node->data.fn_call_expr.params.at(1); + IrInstSrc *arg1_value = ir_gen_node(irb, arg1_node, scope); + if (arg1_value == irb->codegen->invalid_inst_src) + return arg1_value; + + IrInstSrc *ptr_instruction = ir_build_field_ptr_instruction(irb, scope, node, + arg0_value, arg1_value, false); + + if (lval == LValPtr || lval == LValAssign) + return ptr_instruction; + + IrInstSrc *load_ptr = ir_build_load_ptr(irb, scope, node, ptr_instruction); + return ir_expr_wrap(irb, scope, load_ptr, result_loc); + } + case BuiltinFnIdHasField: + { + AstNode *arg0_node = node->data.fn_call_expr.params.at(0); + IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); + if (arg0_value == irb->codegen->invalid_inst_src) + return arg0_value; + + AstNode *arg1_node = node->data.fn_call_expr.params.at(1); + IrInstSrc *arg1_value = ir_gen_node(irb, arg1_node, scope); + if (arg1_value == irb->codegen->invalid_inst_src) + return arg1_value; + + IrInstSrc *type_info = ir_build_has_field(irb, scope, node, arg0_value, arg1_value); + return ir_lval_wrap(irb, scope, type_info, lval, result_loc); + } + case BuiltinFnIdTypeInfo: + { + AstNode *arg0_node = node->data.fn_call_expr.params.at(0); + IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); + if (arg0_value == irb->codegen->invalid_inst_src) + return arg0_value; + + IrInstSrc *type_info = ir_build_type_info(irb, scope, node, arg0_value); + return ir_lval_wrap(irb, scope, type_info, lval, result_loc); + } + case BuiltinFnIdType: + { + AstNode *arg_node = node->data.fn_call_expr.params.at(0); + IrInstSrc *arg = ir_gen_node(irb, arg_node, scope); + if (arg == irb->codegen->invalid_inst_src) + return arg; + + IrInstSrc *type = ir_build_type(irb, scope, node, arg); + return ir_lval_wrap(irb, scope, type, lval, result_loc); + } + case BuiltinFnIdBreakpoint: + return ir_lval_wrap(irb, scope, ir_build_breakpoint(irb, scope, node), lval, result_loc); + case BuiltinFnIdReturnAddress: + return ir_lval_wrap(irb, scope, ir_build_return_address_src(irb, scope, node), lval, result_loc); + case BuiltinFnIdFrameAddress: + return ir_lval_wrap(irb, scope, ir_build_frame_address_src(irb, scope, node), lval, result_loc); + case BuiltinFnIdFrameHandle: + if (!irb->exec->fn_entry) { + add_node_error(irb->codegen, node, buf_sprintf("@frame() called outside of function definition")); + return irb->codegen->invalid_inst_src; + } + return ir_lval_wrap(irb, scope, ir_build_handle_src(irb, scope, node), lval, result_loc); + case BuiltinFnIdFrameType: { + AstNode *arg0_node = node->data.fn_call_expr.params.at(0); + IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); + if (arg0_value == irb->codegen->invalid_inst_src) + return arg0_value; + + IrInstSrc *frame_type = ir_build_frame_type(irb, scope, node, arg0_value); + return ir_lval_wrap(irb, scope, frame_type, lval, result_loc); + } + case BuiltinFnIdFrameSize: { + AstNode *arg0_node = node->data.fn_call_expr.params.at(0); + IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); + if (arg0_value == irb->codegen->invalid_inst_src) + return arg0_value; + + IrInstSrc *frame_size = ir_build_frame_size_src(irb, scope, node, arg0_value); + return ir_lval_wrap(irb, scope, frame_size, lval, result_loc); + } + case BuiltinFnIdAlignOf: + { + AstNode *arg0_node = node->data.fn_call_expr.params.at(0); + IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); + if (arg0_value == irb->codegen->invalid_inst_src) + return arg0_value; + + IrInstSrc *align_of = ir_build_align_of(irb, scope, node, arg0_value); + return ir_lval_wrap(irb, scope, align_of, lval, result_loc); + } + case BuiltinFnIdAddWithOverflow: + return ir_lval_wrap(irb, scope, ir_gen_overflow_op(irb, scope, node, IrOverflowOpAdd), lval, result_loc); + case BuiltinFnIdSubWithOverflow: + return ir_lval_wrap(irb, scope, ir_gen_overflow_op(irb, scope, node, IrOverflowOpSub), lval, result_loc); + case BuiltinFnIdMulWithOverflow: + return ir_lval_wrap(irb, scope, ir_gen_overflow_op(irb, scope, node, IrOverflowOpMul), lval, result_loc); + case BuiltinFnIdShlWithOverflow: + return ir_lval_wrap(irb, scope, ir_gen_overflow_op(irb, scope, node, IrOverflowOpShl), lval, result_loc); + case BuiltinFnIdMulAdd: + return ir_lval_wrap(irb, scope, ir_gen_mul_add(irb, scope, node), lval, result_loc); + case BuiltinFnIdTypeName: + { + AstNode *arg0_node = node->data.fn_call_expr.params.at(0); + IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); + if (arg0_value == irb->codegen->invalid_inst_src) + return arg0_value; + + IrInstSrc *type_name = ir_build_type_name(irb, scope, node, arg0_value); + return ir_lval_wrap(irb, scope, type_name, lval, result_loc); + } + case BuiltinFnIdPanic: + { + AstNode *arg0_node = node->data.fn_call_expr.params.at(0); + IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); + if (arg0_value == irb->codegen->invalid_inst_src) + return arg0_value; + + IrInstSrc *panic = ir_build_panic_src(irb, scope, node, arg0_value); + return ir_lval_wrap(irb, scope, panic, lval, result_loc); + } + case BuiltinFnIdPtrCast: + { + AstNode *arg0_node = node->data.fn_call_expr.params.at(0); + IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); + if (arg0_value == irb->codegen->invalid_inst_src) + return arg0_value; + + AstNode *arg1_node = node->data.fn_call_expr.params.at(1); + IrInstSrc *arg1_value = ir_gen_node(irb, arg1_node, scope); + if (arg1_value == irb->codegen->invalid_inst_src) + return arg1_value; + + IrInstSrc *ptr_cast = ir_build_ptr_cast_src(irb, scope, node, arg0_value, arg1_value, true); + return ir_lval_wrap(irb, scope, ptr_cast, lval, result_loc); + } + case BuiltinFnIdBitCast: + { + AstNode *dest_type_node = node->data.fn_call_expr.params.at(0); + IrInstSrc *dest_type = ir_gen_node(irb, dest_type_node, scope); + if (dest_type == irb->codegen->invalid_inst_src) + return dest_type; + + ResultLocBitCast *result_loc_bit_cast = heap::c_allocator.create(); + result_loc_bit_cast->base.id = ResultLocIdBitCast; + result_loc_bit_cast->base.source_instruction = dest_type; + result_loc_bit_cast->base.allow_write_through_const = result_loc->allow_write_through_const; + ir_ref_instruction(dest_type, irb->current_basic_block); + result_loc_bit_cast->parent = result_loc; + + ir_build_reset_result(irb, scope, node, &result_loc_bit_cast->base); + + AstNode *arg1_node = node->data.fn_call_expr.params.at(1); + IrInstSrc *arg1_value = ir_gen_node_extra(irb, arg1_node, scope, LValNone, + &result_loc_bit_cast->base); + if (arg1_value == irb->codegen->invalid_inst_src) + return arg1_value; + + IrInstSrc *bitcast = ir_build_bit_cast_src(irb, scope, arg1_node, arg1_value, result_loc_bit_cast); + return ir_lval_wrap(irb, scope, bitcast, lval, result_loc); + } + case BuiltinFnIdAs: + { + AstNode *dest_type_node = node->data.fn_call_expr.params.at(0); + IrInstSrc *dest_type = ir_gen_node(irb, dest_type_node, scope); + if (dest_type == irb->codegen->invalid_inst_src) + return dest_type; + + ResultLocCast *result_loc_cast = ir_build_cast_result_loc(irb, dest_type, result_loc); + + AstNode *arg1_node = node->data.fn_call_expr.params.at(1); + IrInstSrc *arg1_value = ir_gen_node_extra(irb, arg1_node, scope, LValNone, + &result_loc_cast->base); + if (arg1_value == irb->codegen->invalid_inst_src) + return arg1_value; + + IrInstSrc *result = ir_build_implicit_cast(irb, scope, node, arg1_value, result_loc_cast); + return ir_lval_wrap(irb, scope, result, lval, result_loc); + } + case BuiltinFnIdIntToPtr: + { + AstNode *arg0_node = node->data.fn_call_expr.params.at(0); + IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); + if (arg0_value == irb->codegen->invalid_inst_src) + return arg0_value; + + AstNode *arg1_node = node->data.fn_call_expr.params.at(1); + IrInstSrc *arg1_value = ir_gen_node(irb, arg1_node, scope); + if (arg1_value == irb->codegen->invalid_inst_src) + return arg1_value; + + IrInstSrc *int_to_ptr = ir_build_int_to_ptr_src(irb, scope, node, arg0_value, arg1_value); + return ir_lval_wrap(irb, scope, int_to_ptr, lval, result_loc); + } + case BuiltinFnIdPtrToInt: + { + AstNode *arg0_node = node->data.fn_call_expr.params.at(0); + IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); + if (arg0_value == irb->codegen->invalid_inst_src) + return arg0_value; + + IrInstSrc *ptr_to_int = ir_build_ptr_to_int_src(irb, scope, node, arg0_value); + return ir_lval_wrap(irb, scope, ptr_to_int, lval, result_loc); + } + case BuiltinFnIdTagName: + { + AstNode *arg0_node = node->data.fn_call_expr.params.at(0); + IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); + if (arg0_value == irb->codegen->invalid_inst_src) + return arg0_value; + + IrInstSrc *tag_name = ir_build_tag_name_src(irb, scope, node, arg0_value); + return ir_lval_wrap(irb, scope, tag_name, lval, result_loc); + } + case BuiltinFnIdFieldParentPtr: + { + AstNode *arg0_node = node->data.fn_call_expr.params.at(0); + IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); + if (arg0_value == irb->codegen->invalid_inst_src) + return arg0_value; + + AstNode *arg1_node = node->data.fn_call_expr.params.at(1); + IrInstSrc *arg1_value = ir_gen_node(irb, arg1_node, scope); + if (arg1_value == irb->codegen->invalid_inst_src) + return arg1_value; + + AstNode *arg2_node = node->data.fn_call_expr.params.at(2); + IrInstSrc *arg2_value = ir_gen_node(irb, arg2_node, scope); + if (arg2_value == irb->codegen->invalid_inst_src) + return arg2_value; + + IrInstSrc *field_parent_ptr = ir_build_field_parent_ptr_src(irb, scope, node, + arg0_value, arg1_value, arg2_value); + return ir_lval_wrap(irb, scope, field_parent_ptr, lval, result_loc); + } + case BuiltinFnIdByteOffsetOf: + { + AstNode *arg0_node = node->data.fn_call_expr.params.at(0); + IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); + if (arg0_value == irb->codegen->invalid_inst_src) + return arg0_value; + + AstNode *arg1_node = node->data.fn_call_expr.params.at(1); + IrInstSrc *arg1_value = ir_gen_node(irb, arg1_node, scope); + if (arg1_value == irb->codegen->invalid_inst_src) + return arg1_value; + + IrInstSrc *offset_of = ir_build_byte_offset_of(irb, scope, node, arg0_value, arg1_value); + return ir_lval_wrap(irb, scope, offset_of, lval, result_loc); + } + case BuiltinFnIdBitOffsetOf: + { + AstNode *arg0_node = node->data.fn_call_expr.params.at(0); + IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); + if (arg0_value == irb->codegen->invalid_inst_src) + return arg0_value; + + AstNode *arg1_node = node->data.fn_call_expr.params.at(1); + IrInstSrc *arg1_value = ir_gen_node(irb, arg1_node, scope); + if (arg1_value == irb->codegen->invalid_inst_src) + return arg1_value; + + IrInstSrc *offset_of = ir_build_bit_offset_of(irb, scope, node, arg0_value, arg1_value); + return ir_lval_wrap(irb, scope, offset_of, lval, result_loc); + } + case BuiltinFnIdCall: { + // Cast the options parameter to the options type + ZigType *options_type = get_builtin_type(irb->codegen, "CallOptions"); + IrInstSrc *options_type_inst = ir_build_const_type(irb, scope, node, options_type); + ResultLocCast *result_loc_cast = ir_build_cast_result_loc(irb, options_type_inst, no_result_loc()); + + AstNode *options_node = node->data.fn_call_expr.params.at(0); + IrInstSrc *options_inner = ir_gen_node_extra(irb, options_node, scope, + LValNone, &result_loc_cast->base); + if (options_inner == irb->codegen->invalid_inst_src) + return options_inner; + IrInstSrc *options = ir_build_implicit_cast(irb, scope, options_node, options_inner, result_loc_cast); + + AstNode *fn_ref_node = node->data.fn_call_expr.params.at(1); + AstNode *args_node = node->data.fn_call_expr.params.at(2); + if (args_node->type == NodeTypeContainerInitExpr) { + if (args_node->data.container_init_expr.kind == ContainerInitKindArray || + args_node->data.container_init_expr.entries.length == 0) + { + return ir_gen_fn_call_with_args(irb, scope, node, + fn_ref_node, CallModifierNone, options, + args_node->data.container_init_expr.entries.items, + args_node->data.container_init_expr.entries.length, + lval, result_loc); + } else { + exec_add_error_node(irb->codegen, irb->exec, args_node, + buf_sprintf("TODO: @call with anon struct literal")); + return irb->codegen->invalid_inst_src; + } + } else { + IrInstSrc *fn_ref = ir_gen_node(irb, fn_ref_node, scope); + if (fn_ref == irb->codegen->invalid_inst_src) + return fn_ref; + + IrInstSrc *args = ir_gen_node(irb, args_node, scope); + if (args == irb->codegen->invalid_inst_src) + return args; + + IrInstSrc *call = ir_build_call_extra(irb, scope, node, options, fn_ref, args, result_loc); + return ir_lval_wrap(irb, scope, call, lval, result_loc); + } + } + case BuiltinFnIdAsyncCall: + return ir_gen_async_call(irb, scope, nullptr, node, lval, result_loc); + case BuiltinFnIdShlExact: + { + AstNode *arg0_node = node->data.fn_call_expr.params.at(0); + IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); + if (arg0_value == irb->codegen->invalid_inst_src) + return arg0_value; + + AstNode *arg1_node = node->data.fn_call_expr.params.at(1); + IrInstSrc *arg1_value = ir_gen_node(irb, arg1_node, scope); + if (arg1_value == irb->codegen->invalid_inst_src) + return arg1_value; + + IrInstSrc *bin_op = ir_build_bin_op(irb, scope, node, IrBinOpBitShiftLeftExact, arg0_value, arg1_value, true); + return ir_lval_wrap(irb, scope, bin_op, lval, result_loc); + } + case BuiltinFnIdShrExact: + { + AstNode *arg0_node = node->data.fn_call_expr.params.at(0); + IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); + if (arg0_value == irb->codegen->invalid_inst_src) + return arg0_value; + + AstNode *arg1_node = node->data.fn_call_expr.params.at(1); + IrInstSrc *arg1_value = ir_gen_node(irb, arg1_node, scope); + if (arg1_value == irb->codegen->invalid_inst_src) + return arg1_value; + + IrInstSrc *bin_op = ir_build_bin_op(irb, scope, node, IrBinOpBitShiftRightExact, arg0_value, arg1_value, true); + return ir_lval_wrap(irb, scope, bin_op, lval, result_loc); + } + case BuiltinFnIdSetEvalBranchQuota: + { + AstNode *arg0_node = node->data.fn_call_expr.params.at(0); + IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); + if (arg0_value == irb->codegen->invalid_inst_src) + return arg0_value; + + IrInstSrc *set_eval_branch_quota = ir_build_set_eval_branch_quota(irb, scope, node, arg0_value); + return ir_lval_wrap(irb, scope, set_eval_branch_quota, lval, result_loc); + } + case BuiltinFnIdAlignCast: + { + AstNode *arg0_node = node->data.fn_call_expr.params.at(0); + IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); + if (arg0_value == irb->codegen->invalid_inst_src) + return arg0_value; + + AstNode *arg1_node = node->data.fn_call_expr.params.at(1); + IrInstSrc *arg1_value = ir_gen_node(irb, arg1_node, scope); + if (arg1_value == irb->codegen->invalid_inst_src) + return arg1_value; + + IrInstSrc *align_cast = ir_build_align_cast_src(irb, scope, node, arg0_value, arg1_value); + return ir_lval_wrap(irb, scope, align_cast, lval, result_loc); + } + case BuiltinFnIdThis: + { + IrInstSrc *this_inst = ir_gen_this(irb, scope, node); + return ir_lval_wrap(irb, scope, this_inst, lval, result_loc); + } + case BuiltinFnIdSetAlignStack: + { + AstNode *arg0_node = node->data.fn_call_expr.params.at(0); + IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); + if (arg0_value == irb->codegen->invalid_inst_src) + return arg0_value; + + IrInstSrc *set_align_stack = ir_build_set_align_stack(irb, scope, node, arg0_value); + return ir_lval_wrap(irb, scope, set_align_stack, lval, result_loc); + } + case BuiltinFnIdExport: + { + // Cast the options parameter to the options type + ZigType *options_type = get_builtin_type(irb->codegen, "ExportOptions"); + IrInstSrc *options_type_inst = ir_build_const_type(irb, scope, node, options_type); + ResultLocCast *result_loc_cast = ir_build_cast_result_loc(irb, options_type_inst, no_result_loc()); + + AstNode *target_node = node->data.fn_call_expr.params.at(0); + IrInstSrc *target_value = ir_gen_node(irb, target_node, scope); + if (target_value == irb->codegen->invalid_inst_src) + return target_value; + + AstNode *options_node = node->data.fn_call_expr.params.at(1); + IrInstSrc *options_value = ir_gen_node_extra(irb, options_node, + scope, LValNone, &result_loc_cast->base); + if (options_value == irb->codegen->invalid_inst_src) + return options_value; + + IrInstSrc *casted_options_value = ir_build_implicit_cast( + irb, scope, options_node, options_value, result_loc_cast); + + IrInstSrc *ir_export = ir_build_export(irb, scope, node, target_value, casted_options_value); + return ir_lval_wrap(irb, scope, ir_export, lval, result_loc); + } + case BuiltinFnIdExtern: + { + // Cast the options parameter to the options type + ZigType *options_type = get_builtin_type(irb->codegen, "ExternOptions"); + IrInstSrc *options_type_inst = ir_build_const_type(irb, scope, node, options_type); + ResultLocCast *result_loc_cast = ir_build_cast_result_loc(irb, options_type_inst, no_result_loc()); + + AstNode *type_node = node->data.fn_call_expr.params.at(0); + IrInstSrc *type_value = ir_gen_node(irb, type_node, scope); + if (type_value == irb->codegen->invalid_inst_src) + return type_value; + + AstNode *options_node = node->data.fn_call_expr.params.at(1); + IrInstSrc *options_value = ir_gen_node_extra(irb, options_node, + scope, LValNone, &result_loc_cast->base); + if (options_value == irb->codegen->invalid_inst_src) + return options_value; + + IrInstSrc *casted_options_value = ir_build_implicit_cast( + irb, scope, options_node, options_value, result_loc_cast); + + IrInstSrc *ir_extern = ir_build_extern(irb, scope, node, type_value, casted_options_value); + return ir_lval_wrap(irb, scope, ir_extern, lval, result_loc); + } + case BuiltinFnIdErrorReturnTrace: + { + IrInstSrc *error_return_trace = ir_build_error_return_trace_src(irb, scope, node, + IrInstErrorReturnTraceNull); + return ir_lval_wrap(irb, scope, error_return_trace, lval, result_loc); + } + case BuiltinFnIdAtomicRmw: + { + AstNode *arg0_node = node->data.fn_call_expr.params.at(0); + IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); + if (arg0_value == irb->codegen->invalid_inst_src) + return arg0_value; + + AstNode *arg1_node = node->data.fn_call_expr.params.at(1); + IrInstSrc *arg1_value = ir_gen_node(irb, arg1_node, scope); + if (arg1_value == irb->codegen->invalid_inst_src) + return arg1_value; + + AstNode *arg2_node = node->data.fn_call_expr.params.at(2); + IrInstSrc *arg2_value = ir_gen_node(irb, arg2_node, scope); + if (arg2_value == irb->codegen->invalid_inst_src) + return arg2_value; + + AstNode *arg3_node = node->data.fn_call_expr.params.at(3); + IrInstSrc *arg3_value = ir_gen_node(irb, arg3_node, scope); + if (arg3_value == irb->codegen->invalid_inst_src) + return arg3_value; + + AstNode *arg4_node = node->data.fn_call_expr.params.at(4); + IrInstSrc *arg4_value = ir_gen_node(irb, arg4_node, scope); + if (arg4_value == irb->codegen->invalid_inst_src) + return arg4_value; + + IrInstSrc *inst = ir_build_atomic_rmw_src(irb, scope, node, + arg0_value, arg1_value, arg2_value, arg3_value, arg4_value); + return ir_lval_wrap(irb, scope, inst, lval, result_loc); + } + case BuiltinFnIdAtomicLoad: + { + AstNode *arg0_node = node->data.fn_call_expr.params.at(0); + IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); + if (arg0_value == irb->codegen->invalid_inst_src) + return arg0_value; + + AstNode *arg1_node = node->data.fn_call_expr.params.at(1); + IrInstSrc *arg1_value = ir_gen_node(irb, arg1_node, scope); + if (arg1_value == irb->codegen->invalid_inst_src) + return arg1_value; + + AstNode *arg2_node = node->data.fn_call_expr.params.at(2); + IrInstSrc *arg2_value = ir_gen_node(irb, arg2_node, scope); + if (arg2_value == irb->codegen->invalid_inst_src) + return arg2_value; + + IrInstSrc *inst = ir_build_atomic_load_src(irb, scope, node, arg0_value, arg1_value, arg2_value); + return ir_lval_wrap(irb, scope, inst, lval, result_loc); + } + case BuiltinFnIdAtomicStore: + { + AstNode *arg0_node = node->data.fn_call_expr.params.at(0); + IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); + if (arg0_value == irb->codegen->invalid_inst_src) + return arg0_value; + + AstNode *arg1_node = node->data.fn_call_expr.params.at(1); + IrInstSrc *arg1_value = ir_gen_node(irb, arg1_node, scope); + if (arg1_value == irb->codegen->invalid_inst_src) + return arg1_value; + + AstNode *arg2_node = node->data.fn_call_expr.params.at(2); + IrInstSrc *arg2_value = ir_gen_node(irb, arg2_node, scope); + if (arg2_value == irb->codegen->invalid_inst_src) + return arg2_value; + + AstNode *arg3_node = node->data.fn_call_expr.params.at(3); + IrInstSrc *arg3_value = ir_gen_node(irb, arg3_node, scope); + if (arg3_value == irb->codegen->invalid_inst_src) + return arg3_value; + + IrInstSrc *inst = ir_build_atomic_store_src(irb, scope, node, arg0_value, arg1_value, + arg2_value, arg3_value); + return ir_lval_wrap(irb, scope, inst, lval, result_loc); + } + case BuiltinFnIdIntToEnum: + { + AstNode *arg0_node = node->data.fn_call_expr.params.at(0); + IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); + if (arg0_value == irb->codegen->invalid_inst_src) + return arg0_value; + + AstNode *arg1_node = node->data.fn_call_expr.params.at(1); + IrInstSrc *arg1_value = ir_gen_node(irb, arg1_node, scope); + if (arg1_value == irb->codegen->invalid_inst_src) + return arg1_value; + + IrInstSrc *result = ir_build_int_to_enum_src(irb, scope, node, arg0_value, arg1_value); + return ir_lval_wrap(irb, scope, result, lval, result_loc); + } + case BuiltinFnIdEnumToInt: + { + AstNode *arg0_node = node->data.fn_call_expr.params.at(0); + IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); + if (arg0_value == irb->codegen->invalid_inst_src) + return arg0_value; + + IrInstSrc *result = ir_build_enum_to_int(irb, scope, node, arg0_value); + return ir_lval_wrap(irb, scope, result, lval, result_loc); + } + case BuiltinFnIdCtz: + case BuiltinFnIdPopCount: + case BuiltinFnIdClz: + case BuiltinFnIdBswap: + case BuiltinFnIdBitReverse: + { + AstNode *arg0_node = node->data.fn_call_expr.params.at(0); + IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); + if (arg0_value == irb->codegen->invalid_inst_src) + return arg0_value; + + AstNode *arg1_node = node->data.fn_call_expr.params.at(1); + IrInstSrc *arg1_value = ir_gen_node(irb, arg1_node, scope); + if (arg1_value == irb->codegen->invalid_inst_src) + return arg1_value; + + IrInstSrc *result; + switch (builtin_fn->id) { + case BuiltinFnIdCtz: + result = ir_build_ctz(irb, scope, node, arg0_value, arg1_value); + break; + case BuiltinFnIdPopCount: + result = ir_build_pop_count(irb, scope, node, arg0_value, arg1_value); + break; + case BuiltinFnIdClz: + result = ir_build_clz(irb, scope, node, arg0_value, arg1_value); + break; + case BuiltinFnIdBswap: + result = ir_build_bswap(irb, scope, node, arg0_value, arg1_value); + break; + case BuiltinFnIdBitReverse: + result = ir_build_bit_reverse(irb, scope, node, arg0_value, arg1_value); + break; + default: + zig_unreachable(); + } + return ir_lval_wrap(irb, scope, result, lval, result_loc); + } + case BuiltinFnIdHasDecl: + { + AstNode *arg0_node = node->data.fn_call_expr.params.at(0); + IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); + if (arg0_value == irb->codegen->invalid_inst_src) + return arg0_value; + + AstNode *arg1_node = node->data.fn_call_expr.params.at(1); + IrInstSrc *arg1_value = ir_gen_node(irb, arg1_node, scope); + if (arg1_value == irb->codegen->invalid_inst_src) + return arg1_value; + + IrInstSrc *has_decl = ir_build_has_decl(irb, scope, node, arg0_value, arg1_value); + return ir_lval_wrap(irb, scope, has_decl, lval, result_loc); + } + case BuiltinFnIdUnionInit: + { + AstNode *union_type_node = node->data.fn_call_expr.params.at(0); + IrInstSrc *union_type_inst = ir_gen_node(irb, union_type_node, scope); + if (union_type_inst == irb->codegen->invalid_inst_src) + return union_type_inst; + + AstNode *name_node = node->data.fn_call_expr.params.at(1); + IrInstSrc *name_inst = ir_gen_node(irb, name_node, scope); + if (name_inst == irb->codegen->invalid_inst_src) + return name_inst; + + AstNode *init_node = node->data.fn_call_expr.params.at(2); + + return ir_gen_union_init_expr(irb, scope, node, union_type_inst, name_inst, init_node, + lval, result_loc); + } + case BuiltinFnIdSrc: + { + IrInstSrc *src_inst = ir_build_src(irb, scope, node); + return ir_lval_wrap(irb, scope, src_inst, lval, result_loc); + } + } + zig_unreachable(); +} + +static ScopeNoSuspend *get_scope_nosuspend(Scope *scope) { + while (scope) { + if (scope->id == ScopeIdNoSuspend) + return (ScopeNoSuspend *)scope; + if (scope->id == ScopeIdFnDef) + return nullptr; + + scope = scope->parent; + } + return nullptr; +} + +static IrInstSrc *ir_gen_fn_call(IrBuilderSrc *irb, Scope *scope, AstNode *node, LVal lval, + ResultLoc *result_loc) +{ + assert(node->type == NodeTypeFnCallExpr); + + if (node->data.fn_call_expr.modifier == CallModifierBuiltin) + return ir_gen_builtin_fn_call(irb, scope, node, lval, result_loc); + + bool is_nosuspend = get_scope_nosuspend(scope) != nullptr; + CallModifier modifier = node->data.fn_call_expr.modifier; + if (is_nosuspend && modifier != CallModifierAsync) { + modifier = CallModifierNoSuspend; + } + + AstNode *fn_ref_node = node->data.fn_call_expr.fn_ref_expr; + return ir_gen_fn_call_with_args(irb, scope, node, fn_ref_node, modifier, + nullptr, node->data.fn_call_expr.params.items, node->data.fn_call_expr.params.length, lval, result_loc); +} + +static IrInstSrc *ir_gen_if_bool_expr(IrBuilderSrc *irb, Scope *scope, AstNode *node, LVal lval, + ResultLoc *result_loc) +{ + assert(node->type == NodeTypeIfBoolExpr); + + IrInstSrc *condition = ir_gen_node(irb, node->data.if_bool_expr.condition, scope); + if (condition == irb->codegen->invalid_inst_src) + return irb->codegen->invalid_inst_src; + + IrInstSrc *is_comptime; + if (ir_should_inline(irb->exec, scope)) { + is_comptime = ir_build_const_bool(irb, scope, node, true); + } else { + is_comptime = ir_build_test_comptime(irb, scope, node, condition); + } + + AstNode *then_node = node->data.if_bool_expr.then_block; + AstNode *else_node = node->data.if_bool_expr.else_node; + + IrBasicBlockSrc *then_block = ir_create_basic_block(irb, scope, "Then"); + IrBasicBlockSrc *else_block = ir_create_basic_block(irb, scope, "Else"); + IrBasicBlockSrc *endif_block = ir_create_basic_block(irb, scope, "EndIf"); + + IrInstSrc *cond_br_inst = ir_build_cond_br(irb, scope, node, condition, + then_block, else_block, is_comptime); + ResultLocPeerParent *peer_parent = ir_build_binary_result_peers(irb, cond_br_inst, else_block, endif_block, + result_loc, is_comptime); + + ir_set_cursor_at_end_and_append_block(irb, then_block); + + Scope *subexpr_scope = create_runtime_scope(irb->codegen, node, scope, is_comptime); + IrInstSrc *then_expr_result = ir_gen_node_extra(irb, then_node, subexpr_scope, lval, + &peer_parent->peers.at(0)->base); + if (then_expr_result == irb->codegen->invalid_inst_src) + return irb->codegen->invalid_inst_src; + IrBasicBlockSrc *after_then_block = irb->current_basic_block; + if (!instr_is_unreachable(then_expr_result)) + ir_mark_gen(ir_build_br(irb, scope, node, endif_block, is_comptime)); + + ir_set_cursor_at_end_and_append_block(irb, else_block); + IrInstSrc *else_expr_result; + if (else_node) { + else_expr_result = ir_gen_node_extra(irb, else_node, subexpr_scope, lval, &peer_parent->peers.at(1)->base); + if (else_expr_result == irb->codegen->invalid_inst_src) + return irb->codegen->invalid_inst_src; + } else { + else_expr_result = ir_build_const_void(irb, scope, node); + ir_build_end_expr(irb, scope, node, else_expr_result, &peer_parent->peers.at(1)->base); + } + IrBasicBlockSrc *after_else_block = irb->current_basic_block; + if (!instr_is_unreachable(else_expr_result)) + ir_mark_gen(ir_build_br(irb, scope, node, endif_block, is_comptime)); + + ir_set_cursor_at_end_and_append_block(irb, endif_block); + IrInstSrc **incoming_values = heap::c_allocator.allocate(2); + incoming_values[0] = then_expr_result; + incoming_values[1] = else_expr_result; + IrBasicBlockSrc **incoming_blocks = heap::c_allocator.allocate(2); + incoming_blocks[0] = after_then_block; + incoming_blocks[1] = after_else_block; + + IrInstSrc *phi = ir_build_phi(irb, scope, node, 2, incoming_blocks, incoming_values, peer_parent); + return ir_expr_wrap(irb, scope, phi, result_loc); +} + +static IrInstSrc *ir_gen_prefix_op_id_lval(IrBuilderSrc *irb, Scope *scope, AstNode *node, IrUnOp op_id, LVal lval) { + assert(node->type == NodeTypePrefixOpExpr); + AstNode *expr_node = node->data.prefix_op_expr.primary_expr; + + IrInstSrc *value = ir_gen_node_extra(irb, expr_node, scope, lval, nullptr); + if (value == irb->codegen->invalid_inst_src) + return value; + + return ir_build_un_op(irb, scope, node, op_id, value); +} + +static IrInstSrc *ir_gen_prefix_op_id(IrBuilderSrc *irb, Scope *scope, AstNode *node, IrUnOp op_id) { + return ir_gen_prefix_op_id_lval(irb, scope, node, op_id, LValNone); +} + +static IrInstSrc *ir_expr_wrap(IrBuilderSrc *irb, Scope *scope, IrInstSrc *inst, ResultLoc *result_loc) { + if (inst == irb->codegen->invalid_inst_src) return inst; + ir_build_end_expr(irb, scope, inst->base.source_node, inst, result_loc); + return inst; +} + +static IrInstSrc *ir_lval_wrap(IrBuilderSrc *irb, Scope *scope, IrInstSrc *value, LVal lval, + ResultLoc *result_loc) +{ + // This logic must be kept in sync with + // [STMT_EXPR_TEST_THING] <--- (search this token) + if (value == irb->codegen->invalid_inst_src || + instr_is_unreachable(value) || + value->base.source_node->type == NodeTypeDefer || + value->id == IrInstSrcIdDeclVar) + { + return value; + } + + assert(lval != LValAssign); + if (lval == LValPtr) { + // We needed a pointer to a value, but we got a value. So we create + // an instruction which just makes a pointer of it. + return ir_build_ref_src(irb, scope, value->base.source_node, value); + } else if (result_loc != nullptr) { + return ir_expr_wrap(irb, scope, value, result_loc); + } else { + return value; + } + +} + +static PtrLen star_token_to_ptr_len(TokenId token_id) { + switch (token_id) { + case TokenIdStar: + case TokenIdStarStar: + return PtrLenSingle; + case TokenIdLBracket: + return PtrLenUnknown; + case TokenIdIdentifier: + return PtrLenC; + default: + zig_unreachable(); + } +} + +static Error token_number_literal_u32(IrBuilderSrc *irb, AstNode *source_node, + RootStruct *root_struct, uint32_t *result, TokenIndex token) +{ + BigInt bigint; + token_number_literal_bigint(root_struct, &bigint, token); + + if (!bigint_fits_in_bits(&bigint, 32, false)) { + Buf *val_buf = buf_alloc(); + bigint_append_buf(val_buf, &bigint, 10); + exec_add_error_node(irb->codegen, irb->exec, source_node, + buf_sprintf("value %s too large for u32", buf_ptr(val_buf))); + bigint_deinit(&bigint); + return ErrorSemanticAnalyzeFail; + } + *result = bigint_as_u32(&bigint); + bigint_deinit(&bigint); + return ErrorNone; + +} + +static IrInstSrc *ir_gen_pointer_type(IrBuilderSrc *irb, Scope *scope, AstNode *node) { + Error err; + assert(node->type == NodeTypePointerType); + + RootStruct *root_struct = node->owner->data.structure.root_struct; + TokenId star_tok_id = root_struct->token_ids[node->data.pointer_type.star_token]; + PtrLen ptr_len = star_token_to_ptr_len(star_tok_id); + + bool is_const = node->data.pointer_type.is_const; + bool is_volatile = node->data.pointer_type.is_volatile; + bool is_allow_zero = node->data.pointer_type.allow_zero_token != 0; + AstNode *sentinel_expr = node->data.pointer_type.sentinel; + AstNode *expr_node = node->data.pointer_type.op_expr; + AstNode *align_expr = node->data.pointer_type.align_expr; + + IrInstSrc *sentinel; + if (sentinel_expr != nullptr) { + sentinel = ir_gen_node(irb, sentinel_expr, scope); + if (sentinel == irb->codegen->invalid_inst_src) + return sentinel; + } else { + sentinel = nullptr; + } + + IrInstSrc *align_value; + if (align_expr != nullptr) { + align_value = ir_gen_node(irb, align_expr, scope); + if (align_value == irb->codegen->invalid_inst_src) + return align_value; + } else { + align_value = nullptr; + } + + IrInstSrc *child_type = ir_gen_node(irb, expr_node, scope); + if (child_type == irb->codegen->invalid_inst_src) + return child_type; + + uint32_t bit_offset_start = 0; + if (node->data.pointer_type.bit_offset_start != 0) { + if ((err = token_number_literal_u32(irb, node, root_struct, &bit_offset_start, + node->data.pointer_type.bit_offset_start))) + { + return irb->codegen->invalid_inst_src; + } + } + + uint32_t host_int_bytes = 0; + if (node->data.pointer_type.host_int_bytes != 0) { + if ((err = token_number_literal_u32(irb, node, root_struct, &host_int_bytes, + node->data.pointer_type.host_int_bytes))) + { + return irb->codegen->invalid_inst_src; + } + } + + if (host_int_bytes != 0 && bit_offset_start >= host_int_bytes * 8) { + exec_add_error_node(irb->codegen, irb->exec, node, + buf_sprintf("bit offset starts after end of host integer")); + return irb->codegen->invalid_inst_src; + } + + return ir_build_ptr_type(irb, scope, node, child_type, is_const, is_volatile, + ptr_len, sentinel, align_value, bit_offset_start, host_int_bytes, is_allow_zero); +} + +static IrInstSrc *ir_gen_catch_unreachable(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, + AstNode *expr_node, LVal lval, ResultLoc *result_loc) +{ + IrInstSrc *err_union_ptr = ir_gen_node_extra(irb, expr_node, scope, LValPtr, nullptr); + if (err_union_ptr == irb->codegen->invalid_inst_src) + return irb->codegen->invalid_inst_src; + + IrInstSrc *payload_ptr = ir_build_unwrap_err_payload_src(irb, scope, source_node, err_union_ptr, true, false); + if (payload_ptr == irb->codegen->invalid_inst_src) + return irb->codegen->invalid_inst_src; + + if (lval == LValPtr) + return payload_ptr; + + IrInstSrc *load_ptr = ir_build_load_ptr(irb, scope, source_node, payload_ptr); + return ir_expr_wrap(irb, scope, load_ptr, result_loc); +} + +static IrInstSrc *ir_gen_bool_not(IrBuilderSrc *irb, Scope *scope, AstNode *node) { + assert(node->type == NodeTypePrefixOpExpr); + AstNode *expr_node = node->data.prefix_op_expr.primary_expr; + + IrInstSrc *value = ir_gen_node(irb, expr_node, scope); + if (value == irb->codegen->invalid_inst_src) + return irb->codegen->invalid_inst_src; + + return ir_build_bool_not(irb, scope, node, value); +} + +static IrInstSrc *ir_gen_prefix_op_expr(IrBuilderSrc *irb, Scope *scope, AstNode *node, LVal lval, + ResultLoc *result_loc) +{ + assert(node->type == NodeTypePrefixOpExpr); + + PrefixOp prefix_op = node->data.prefix_op_expr.prefix_op; + + switch (prefix_op) { + case PrefixOpInvalid: + zig_unreachable(); + case PrefixOpBoolNot: + return ir_lval_wrap(irb, scope, ir_gen_bool_not(irb, scope, node), lval, result_loc); + case PrefixOpBinNot: + return ir_lval_wrap(irb, scope, ir_gen_prefix_op_id(irb, scope, node, IrUnOpBinNot), lval, result_loc); + case PrefixOpNegation: + return ir_lval_wrap(irb, scope, ir_gen_prefix_op_id(irb, scope, node, IrUnOpNegation), lval, result_loc); + case PrefixOpNegationWrap: + return ir_lval_wrap(irb, scope, ir_gen_prefix_op_id(irb, scope, node, IrUnOpNegationWrap), lval, result_loc); + case PrefixOpOptional: + return ir_lval_wrap(irb, scope, ir_gen_prefix_op_id(irb, scope, node, IrUnOpOptional), lval, result_loc); + case PrefixOpAddrOf: { + AstNode *expr_node = node->data.prefix_op_expr.primary_expr; + return ir_lval_wrap(irb, scope, ir_gen_node_extra(irb, expr_node, scope, LValPtr, nullptr), lval, result_loc); + } + } + zig_unreachable(); +} + +static IrInstSrc *ir_gen_union_init_expr(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, + IrInstSrc *union_type, IrInstSrc *field_name, AstNode *expr_node, + LVal lval, ResultLoc *parent_result_loc) +{ + IrInstSrc *container_ptr = ir_build_resolve_result(irb, scope, source_node, parent_result_loc, union_type); + IrInstSrc *field_ptr = ir_build_field_ptr_instruction(irb, scope, source_node, container_ptr, + field_name, true); + + ResultLocInstruction *result_loc_inst = heap::c_allocator.create(); + result_loc_inst->base.id = ResultLocIdInstruction; + result_loc_inst->base.source_instruction = field_ptr; + ir_ref_instruction(field_ptr, irb->current_basic_block); + ir_build_reset_result(irb, scope, expr_node, &result_loc_inst->base); + + IrInstSrc *expr_value = ir_gen_node_extra(irb, expr_node, scope, LValNone, + &result_loc_inst->base); + if (expr_value == irb->codegen->invalid_inst_src) + return expr_value; + + IrInstSrc *init_union = ir_build_union_init_named_field(irb, scope, source_node, union_type, + field_name, field_ptr, container_ptr); + + return ir_lval_wrap(irb, scope, init_union, lval, parent_result_loc); +} + +static IrInstSrc *ir_gen_container_init_expr(IrBuilderSrc *irb, Scope *scope, AstNode *node, LVal lval, + ResultLoc *parent_result_loc) +{ + assert(node->type == NodeTypeContainerInitExpr); + + AstNodeContainerInitExpr *container_init_expr = &node->data.container_init_expr; + ContainerInitKind kind = container_init_expr->kind; + + ResultLocCast *result_loc_cast = nullptr; + ResultLoc *child_result_loc; + AstNode *init_array_type_source_node; + if (container_init_expr->type != nullptr) { + IrInstSrc *container_type; + if (container_init_expr->type->type == NodeTypeInferredArrayType) { + if (kind == ContainerInitKindStruct) { + add_node_error(irb->codegen, container_init_expr->type, + buf_sprintf("initializing array with struct syntax")); + return irb->codegen->invalid_inst_src; + } + IrInstSrc *sentinel; + if (container_init_expr->type->data.inferred_array_type.sentinel != nullptr) { + sentinel = ir_gen_node(irb, container_init_expr->type->data.inferred_array_type.sentinel, scope); + if (sentinel == irb->codegen->invalid_inst_src) + return sentinel; + } else { + sentinel = nullptr; + } + + IrInstSrc *elem_type = ir_gen_node(irb, + container_init_expr->type->data.inferred_array_type.child_type, scope); + if (elem_type == irb->codegen->invalid_inst_src) + return elem_type; + size_t item_count = container_init_expr->entries.length; + IrInstSrc *item_count_inst = ir_build_const_usize(irb, scope, node, item_count); + container_type = ir_build_array_type(irb, scope, node, item_count_inst, sentinel, elem_type); + } else { + container_type = ir_gen_node(irb, container_init_expr->type, scope); + if (container_type == irb->codegen->invalid_inst_src) + return container_type; + } + + result_loc_cast = ir_build_cast_result_loc(irb, container_type, parent_result_loc); + child_result_loc = &result_loc_cast->base; + init_array_type_source_node = container_type->base.source_node; + } else { + child_result_loc = parent_result_loc; + if (parent_result_loc->source_instruction != nullptr) { + init_array_type_source_node = parent_result_loc->source_instruction->base.source_node; + } else { + init_array_type_source_node = node; + } + } + + switch (kind) { + case ContainerInitKindStruct: { + IrInstSrc *container_ptr = ir_build_resolve_result(irb, scope, node, child_result_loc, + nullptr); + + size_t field_count = container_init_expr->entries.length; + IrInstSrcContainerInitFieldsField *fields = heap::c_allocator.allocate(field_count); + for (size_t i = 0; i < field_count; i += 1) { + AstNode *entry_node = container_init_expr->entries.at(i); + assert(entry_node->type == NodeTypeStructValueField); + + Buf *name = entry_node->data.struct_val_field.name; + AstNode *expr_node = entry_node->data.struct_val_field.expr; + + IrInstSrc *field_ptr = ir_build_field_ptr(irb, scope, entry_node, container_ptr, name, true); + ResultLocInstruction *result_loc_inst = heap::c_allocator.create(); + result_loc_inst->base.id = ResultLocIdInstruction; + result_loc_inst->base.source_instruction = field_ptr; + result_loc_inst->base.allow_write_through_const = true; + ir_ref_instruction(field_ptr, irb->current_basic_block); + ir_build_reset_result(irb, scope, expr_node, &result_loc_inst->base); + + IrInstSrc *expr_value = ir_gen_node_extra(irb, expr_node, scope, LValNone, + &result_loc_inst->base); + if (expr_value == irb->codegen->invalid_inst_src) + return expr_value; + + fields[i].name = name; + fields[i].source_node = entry_node; + fields[i].result_loc = field_ptr; + } + IrInstSrc *result = ir_build_container_init_fields(irb, scope, node, field_count, + fields, container_ptr); + + if (result_loc_cast != nullptr) { + result = ir_build_implicit_cast(irb, scope, node, result, result_loc_cast); + } + return ir_lval_wrap(irb, scope, result, lval, parent_result_loc); + } + case ContainerInitKindArray: { + size_t item_count = container_init_expr->entries.length; + + IrInstSrc *container_ptr = ir_build_resolve_result(irb, scope, node, child_result_loc, + nullptr); + + IrInstSrc **result_locs = heap::c_allocator.allocate(item_count); + for (size_t i = 0; i < item_count; i += 1) { + AstNode *expr_node = container_init_expr->entries.at(i); + + IrInstSrc *elem_index = ir_build_const_usize(irb, scope, expr_node, i); + IrInstSrc *elem_ptr = ir_build_elem_ptr(irb, scope, expr_node, container_ptr, + elem_index, false, PtrLenSingle, init_array_type_source_node); + ResultLocInstruction *result_loc_inst = heap::c_allocator.create(); + result_loc_inst->base.id = ResultLocIdInstruction; + result_loc_inst->base.source_instruction = elem_ptr; + result_loc_inst->base.allow_write_through_const = true; + ir_ref_instruction(elem_ptr, irb->current_basic_block); + ir_build_reset_result(irb, scope, expr_node, &result_loc_inst->base); + + IrInstSrc *expr_value = ir_gen_node_extra(irb, expr_node, scope, LValNone, + &result_loc_inst->base); + if (expr_value == irb->codegen->invalid_inst_src) + return expr_value; + + result_locs[i] = elem_ptr; + } + IrInstSrc *result = ir_build_container_init_list(irb, scope, node, item_count, + result_locs, container_ptr, init_array_type_source_node); + if (result_loc_cast != nullptr) { + result = ir_build_implicit_cast(irb, scope, node, result, result_loc_cast); + } + return ir_lval_wrap(irb, scope, result, lval, parent_result_loc); + } + } + zig_unreachable(); +} + +static ResultLocVar *ir_build_var_result_loc(IrBuilderSrc *irb, IrInstSrc *alloca, ZigVar *var) { + ResultLocVar *result_loc_var = heap::c_allocator.create(); + result_loc_var->base.id = ResultLocIdVar; + result_loc_var->base.source_instruction = alloca; + result_loc_var->base.allow_write_through_const = true; + result_loc_var->var = var; + + ir_build_reset_result(irb, alloca->base.scope, alloca->base.source_node, &result_loc_var->base); + + return result_loc_var; +} + +static ResultLocCast *ir_build_cast_result_loc(IrBuilderSrc *irb, IrInstSrc *dest_type, + ResultLoc *parent_result_loc) +{ + ResultLocCast *result_loc_cast = heap::c_allocator.create(); + result_loc_cast->base.id = ResultLocIdCast; + result_loc_cast->base.source_instruction = dest_type; + result_loc_cast->base.allow_write_through_const = parent_result_loc->allow_write_through_const; + ir_ref_instruction(dest_type, irb->current_basic_block); + result_loc_cast->parent = parent_result_loc; + + ir_build_reset_result(irb, dest_type->base.scope, dest_type->base.source_node, &result_loc_cast->base); + + return result_loc_cast; +} + +static void build_decl_var_and_init(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, ZigVar *var, + IrInstSrc *init, const char *name_hint, IrInstSrc *is_comptime) +{ + IrInstSrc *alloca = ir_build_alloca_src(irb, scope, source_node, nullptr, name_hint, is_comptime); + ResultLocVar *var_result_loc = ir_build_var_result_loc(irb, alloca, var); + ir_build_end_expr(irb, scope, source_node, init, &var_result_loc->base); + ir_build_var_decl_src(irb, scope, source_node, var, nullptr, alloca); +} + +static IrInstSrc *ir_gen_var_decl(IrBuilderSrc *irb, Scope *scope, AstNode *node) { + assert(node->type == NodeTypeVariableDeclaration); + + AstNodeVariableDeclaration *variable_declaration = &node->data.variable_declaration; + + if (buf_eql_str(variable_declaration->symbol, "_")) { + add_node_error(irb->codegen, node, buf_sprintf("`_` is not a declarable symbol")); + return irb->codegen->invalid_inst_src; + } + + // Used for the type expr and the align expr + Scope *comptime_scope = create_comptime_scope(irb->codegen, node, scope); + + IrInstSrc *type_instruction; + if (variable_declaration->type != nullptr) { + type_instruction = ir_gen_node(irb, variable_declaration->type, comptime_scope); + if (type_instruction == irb->codegen->invalid_inst_src) + return type_instruction; + } else { + type_instruction = nullptr; + } + + bool is_shadowable = false; + bool is_const = variable_declaration->is_const; + bool is_extern = variable_declaration->is_extern; + + bool is_comptime_scalar = ir_should_inline(irb->exec, scope) || variable_declaration->is_comptime; + IrInstSrc *is_comptime = ir_build_const_bool(irb, scope, node, is_comptime_scalar); + ZigVar *var = ir_create_var(irb, node, scope, variable_declaration->symbol, + is_const, is_const, is_shadowable, is_comptime); + // we detect IrInstSrcDeclVar in gen_block to make sure the next node + // is inside var->child_scope + + if (!is_extern && !variable_declaration->expr) { + var->var_type = irb->codegen->builtin_types.entry_invalid; + add_node_error(irb->codegen, node, buf_sprintf("variables must be initialized")); + return irb->codegen->invalid_inst_src; + } + + IrInstSrc *align_value = nullptr; + if (variable_declaration->align_expr != nullptr) { + align_value = ir_gen_node(irb, variable_declaration->align_expr, comptime_scope); + if (align_value == irb->codegen->invalid_inst_src) + return align_value; + } + + if (variable_declaration->section_expr != nullptr) { + add_node_error(irb->codegen, variable_declaration->section_expr, + buf_sprintf("cannot set section of local variable '%s'", buf_ptr(variable_declaration->symbol))); + } + + // Parser should ensure that this never happens + assert(variable_declaration->threadlocal_tok == 0); + + IrInstSrc *alloca = ir_build_alloca_src(irb, scope, node, align_value, + buf_ptr(variable_declaration->symbol), is_comptime); + + // Create a result location for the initialization expression. + ResultLocVar *result_loc_var = ir_build_var_result_loc(irb, alloca, var); + ResultLoc *init_result_loc; + ResultLocCast *result_loc_cast; + if (type_instruction != nullptr) { + result_loc_cast = ir_build_cast_result_loc(irb, type_instruction, &result_loc_var->base); + init_result_loc = &result_loc_cast->base; + } else { + result_loc_cast = nullptr; + init_result_loc = &result_loc_var->base; + } + + Scope *init_scope = is_comptime_scalar ? + create_comptime_scope(irb->codegen, variable_declaration->expr, scope) : scope; + + // Temporarily set the name of the IrExecutableSrc to the VariableDeclaration + // so that the struct or enum from the init expression inherits the name. + Buf *old_exec_name = irb->exec->name; + irb->exec->name = variable_declaration->symbol; + IrInstSrc *init_value = ir_gen_node_extra(irb, variable_declaration->expr, init_scope, + LValNone, init_result_loc); + irb->exec->name = old_exec_name; + + if (init_value == irb->codegen->invalid_inst_src) + return irb->codegen->invalid_inst_src; + + if (result_loc_cast != nullptr) { + IrInstSrc *implicit_cast = ir_build_implicit_cast(irb, scope, init_value->base.source_node, + init_value, result_loc_cast); + ir_build_end_expr(irb, scope, node, implicit_cast, &result_loc_var->base); + } + + return ir_build_var_decl_src(irb, scope, node, var, align_value, alloca); +} + +static IrInstSrc *ir_gen_while_expr(IrBuilderSrc *irb, Scope *scope, AstNode *node, LVal lval, + ResultLoc *result_loc) +{ + assert(node->type == NodeTypeWhileExpr); + + AstNode *continue_expr_node = node->data.while_expr.continue_expr; + AstNode *else_node = node->data.while_expr.else_node; + + IrBasicBlockSrc *cond_block = ir_create_basic_block(irb, scope, "WhileCond"); + IrBasicBlockSrc *body_block = ir_create_basic_block(irb, scope, "WhileBody"); + IrBasicBlockSrc *continue_block = continue_expr_node ? + ir_create_basic_block(irb, scope, "WhileContinue") : cond_block; + IrBasicBlockSrc *end_block = ir_create_basic_block(irb, scope, "WhileEnd"); + IrBasicBlockSrc *else_block = else_node ? + ir_create_basic_block(irb, scope, "WhileElse") : end_block; + + IrInstSrc *is_comptime = ir_build_const_bool(irb, scope, node, + ir_should_inline(irb->exec, scope) || node->data.while_expr.is_inline); + ir_build_br(irb, scope, node, cond_block, is_comptime); + + Scope *subexpr_scope = create_runtime_scope(irb->codegen, node, scope, is_comptime); + Buf *var_symbol = node->data.while_expr.var_symbol; + Buf *err_symbol = node->data.while_expr.err_symbol; + if (err_symbol != nullptr) { + ir_set_cursor_at_end_and_append_block(irb, cond_block); + + Scope *payload_scope; + AstNode *symbol_node = node; // TODO make more accurate + ZigVar *payload_var; + if (var_symbol) { + // TODO make it an error to write to payload variable + payload_var = ir_create_var(irb, symbol_node, subexpr_scope, var_symbol, + true, false, false, is_comptime); + payload_scope = payload_var->child_scope; + } else { + payload_scope = subexpr_scope; + } + ScopeExpr *spill_scope = create_expr_scope(irb->codegen, node, payload_scope); + IrInstSrc *err_val_ptr = ir_gen_node_extra(irb, node->data.while_expr.condition, subexpr_scope, + LValPtr, nullptr); + if (err_val_ptr == irb->codegen->invalid_inst_src) + return err_val_ptr; + IrInstSrc *is_err = ir_build_test_err_src(irb, scope, node->data.while_expr.condition, err_val_ptr, + true, false); + IrBasicBlockSrc *after_cond_block = irb->current_basic_block; + IrInstSrc *void_else_result = else_node ? nullptr : ir_mark_gen(ir_build_const_void(irb, scope, node)); + IrInstSrc *cond_br_inst; + if (!instr_is_unreachable(is_err)) { + cond_br_inst = ir_build_cond_br(irb, scope, node->data.while_expr.condition, is_err, + else_block, body_block, is_comptime); + cond_br_inst->is_gen = true; + } else { + // for the purposes of the source instruction to ir_build_result_peers + cond_br_inst = irb->current_basic_block->instruction_list.last(); + } + + ResultLocPeerParent *peer_parent = ir_build_result_peers(irb, cond_br_inst, end_block, result_loc, + is_comptime); + + ir_set_cursor_at_end_and_append_block(irb, body_block); + if (var_symbol) { + IrInstSrc *payload_ptr = ir_build_unwrap_err_payload_src(irb, &spill_scope->base, symbol_node, + err_val_ptr, false, false); + IrInstSrc *var_value = node->data.while_expr.var_is_ptr ? + payload_ptr : ir_build_load_ptr(irb, &spill_scope->base, symbol_node, payload_ptr); + build_decl_var_and_init(irb, payload_scope, symbol_node, payload_var, var_value, buf_ptr(var_symbol), is_comptime); + } + + ZigList incoming_values = {0}; + ZigList incoming_blocks = {0}; + + if (is_duplicate_label(irb->codegen, payload_scope, node, node->data.while_expr.name)) + return irb->codegen->invalid_inst_src; + + ScopeLoop *loop_scope = create_loop_scope(irb->codegen, node, payload_scope); + loop_scope->break_block = end_block; + loop_scope->continue_block = continue_block; + loop_scope->is_comptime = is_comptime; + loop_scope->incoming_blocks = &incoming_blocks; + loop_scope->incoming_values = &incoming_values; + loop_scope->lval = lval; + loop_scope->peer_parent = peer_parent; + loop_scope->spill_scope = spill_scope; + + // Note the body block of the loop is not the place that lval and result_loc are used - + // it's actually in break statements, handled similarly to return statements. + // That is why we set those values in loop_scope above and not in this ir_gen_node call. + IrInstSrc *body_result = ir_gen_node(irb, node->data.while_expr.body, &loop_scope->base); + if (body_result == irb->codegen->invalid_inst_src) + return body_result; + + if (loop_scope->name != nullptr && loop_scope->name_used == false) { + add_node_error(irb->codegen, node, buf_sprintf("unused while label")); + } + + if (!instr_is_unreachable(body_result)) { + ir_mark_gen(ir_build_check_statement_is_void(irb, payload_scope, node->data.while_expr.body, body_result)); + ir_mark_gen(ir_build_br(irb, payload_scope, node, continue_block, is_comptime)); + } + + if (continue_expr_node) { + ir_set_cursor_at_end_and_append_block(irb, continue_block); + IrInstSrc *expr_result = ir_gen_node(irb, continue_expr_node, payload_scope); + if (expr_result == irb->codegen->invalid_inst_src) + return expr_result; + if (!instr_is_unreachable(expr_result)) { + ir_mark_gen(ir_build_check_statement_is_void(irb, payload_scope, continue_expr_node, expr_result)); + ir_mark_gen(ir_build_br(irb, payload_scope, node, cond_block, is_comptime)); + } + } + + ir_set_cursor_at_end_and_append_block(irb, else_block); + assert(else_node != nullptr); + + // TODO make it an error to write to error variable + AstNode *err_symbol_node = else_node; // TODO make more accurate + ZigVar *err_var = ir_create_var(irb, err_symbol_node, scope, err_symbol, + true, false, false, is_comptime); + Scope *err_scope = err_var->child_scope; + IrInstSrc *err_ptr = ir_build_unwrap_err_code_src(irb, err_scope, err_symbol_node, err_val_ptr); + IrInstSrc *err_value = ir_build_load_ptr(irb, err_scope, err_symbol_node, err_ptr); + build_decl_var_and_init(irb, err_scope, err_symbol_node, err_var, err_value, buf_ptr(err_symbol), is_comptime); + + if (peer_parent->peers.length != 0) { + peer_parent->peers.last()->next_bb = else_block; + } + ResultLocPeer *peer_result = create_peer_result(peer_parent); + peer_parent->peers.append(peer_result); + IrInstSrc *else_result = ir_gen_node_extra(irb, else_node, err_scope, lval, &peer_result->base); + if (else_result == irb->codegen->invalid_inst_src) + return else_result; + if (!instr_is_unreachable(else_result)) + ir_mark_gen(ir_build_br(irb, scope, node, end_block, is_comptime)); + IrBasicBlockSrc *after_else_block = irb->current_basic_block; + ir_set_cursor_at_end_and_append_block(irb, end_block); + if (else_result) { + incoming_blocks.append(after_else_block); + incoming_values.append(else_result); + } else { + incoming_blocks.append(after_cond_block); + incoming_values.append(void_else_result); + } + if (peer_parent->peers.length != 0) { + peer_parent->peers.last()->next_bb = end_block; + } + + IrInstSrc *phi = ir_build_phi(irb, scope, node, incoming_blocks.length, + incoming_blocks.items, incoming_values.items, peer_parent); + return ir_expr_wrap(irb, scope, phi, result_loc); + } else if (var_symbol != nullptr) { + ir_set_cursor_at_end_and_append_block(irb, cond_block); + Scope *subexpr_scope = create_runtime_scope(irb->codegen, node, scope, is_comptime); + // TODO make it an error to write to payload variable + AstNode *symbol_node = node; // TODO make more accurate + + ZigVar *payload_var = ir_create_var(irb, symbol_node, subexpr_scope, var_symbol, + true, false, false, is_comptime); + Scope *child_scope = payload_var->child_scope; + ScopeExpr *spill_scope = create_expr_scope(irb->codegen, node, child_scope); + IrInstSrc *maybe_val_ptr = ir_gen_node_extra(irb, node->data.while_expr.condition, subexpr_scope, + LValPtr, nullptr); + if (maybe_val_ptr == irb->codegen->invalid_inst_src) + return maybe_val_ptr; + IrInstSrc *maybe_val = ir_build_load_ptr(irb, scope, node->data.while_expr.condition, maybe_val_ptr); + IrInstSrc *is_non_null = ir_build_test_non_null_src(irb, scope, node->data.while_expr.condition, maybe_val); + IrBasicBlockSrc *after_cond_block = irb->current_basic_block; + IrInstSrc *void_else_result = else_node ? nullptr : ir_mark_gen(ir_build_const_void(irb, scope, node)); + IrInstSrc *cond_br_inst; + if (!instr_is_unreachable(is_non_null)) { + cond_br_inst = ir_build_cond_br(irb, scope, node->data.while_expr.condition, is_non_null, + body_block, else_block, is_comptime); + cond_br_inst->is_gen = true; + } else { + // for the purposes of the source instruction to ir_build_result_peers + cond_br_inst = irb->current_basic_block->instruction_list.last(); + } + + ResultLocPeerParent *peer_parent = ir_build_result_peers(irb, cond_br_inst, end_block, result_loc, + is_comptime); + + ir_set_cursor_at_end_and_append_block(irb, body_block); + IrInstSrc *payload_ptr = ir_build_optional_unwrap_ptr(irb, &spill_scope->base, symbol_node, maybe_val_ptr, false); + IrInstSrc *var_value = node->data.while_expr.var_is_ptr ? + payload_ptr : ir_build_load_ptr(irb, &spill_scope->base, symbol_node, payload_ptr); + build_decl_var_and_init(irb, child_scope, symbol_node, payload_var, var_value, buf_ptr(var_symbol), is_comptime); + + ZigList incoming_values = {0}; + ZigList incoming_blocks = {0}; + + if (is_duplicate_label(irb->codegen, child_scope, node, node->data.while_expr.name)) + return irb->codegen->invalid_inst_src; + + ScopeLoop *loop_scope = create_loop_scope(irb->codegen, node, child_scope); + loop_scope->break_block = end_block; + loop_scope->continue_block = continue_block; + loop_scope->is_comptime = is_comptime; + loop_scope->incoming_blocks = &incoming_blocks; + loop_scope->incoming_values = &incoming_values; + loop_scope->lval = lval; + loop_scope->peer_parent = peer_parent; + loop_scope->spill_scope = spill_scope; + + // Note the body block of the loop is not the place that lval and result_loc are used - + // it's actually in break statements, handled similarly to return statements. + // That is why we set those values in loop_scope above and not in this ir_gen_node call. + IrInstSrc *body_result = ir_gen_node(irb, node->data.while_expr.body, &loop_scope->base); + if (body_result == irb->codegen->invalid_inst_src) + return body_result; + + if (loop_scope->name != nullptr && loop_scope->name_used == false) { + add_node_error(irb->codegen, node, buf_sprintf("unused while label")); + } + + if (!instr_is_unreachable(body_result)) { + ir_mark_gen(ir_build_check_statement_is_void(irb, child_scope, node->data.while_expr.body, body_result)); + ir_mark_gen(ir_build_br(irb, child_scope, node, continue_block, is_comptime)); + } + + if (continue_expr_node) { + ir_set_cursor_at_end_and_append_block(irb, continue_block); + IrInstSrc *expr_result = ir_gen_node(irb, continue_expr_node, child_scope); + if (expr_result == irb->codegen->invalid_inst_src) + return expr_result; + if (!instr_is_unreachable(expr_result)) { + ir_mark_gen(ir_build_check_statement_is_void(irb, child_scope, continue_expr_node, expr_result)); + ir_mark_gen(ir_build_br(irb, child_scope, node, cond_block, is_comptime)); + } + } + + IrInstSrc *else_result = nullptr; + if (else_node) { + ir_set_cursor_at_end_and_append_block(irb, else_block); + + if (peer_parent->peers.length != 0) { + peer_parent->peers.last()->next_bb = else_block; + } + ResultLocPeer *peer_result = create_peer_result(peer_parent); + peer_parent->peers.append(peer_result); + else_result = ir_gen_node_extra(irb, else_node, scope, lval, &peer_result->base); + if (else_result == irb->codegen->invalid_inst_src) + return else_result; + if (!instr_is_unreachable(else_result)) + ir_mark_gen(ir_build_br(irb, scope, node, end_block, is_comptime)); + } + IrBasicBlockSrc *after_else_block = irb->current_basic_block; + ir_set_cursor_at_end_and_append_block(irb, end_block); + if (else_result) { + incoming_blocks.append(after_else_block); + incoming_values.append(else_result); + } else { + incoming_blocks.append(after_cond_block); + incoming_values.append(void_else_result); + } + if (peer_parent->peers.length != 0) { + peer_parent->peers.last()->next_bb = end_block; + } + + IrInstSrc *phi = ir_build_phi(irb, scope, node, incoming_blocks.length, + incoming_blocks.items, incoming_values.items, peer_parent); + return ir_expr_wrap(irb, scope, phi, result_loc); + } else { + ir_set_cursor_at_end_and_append_block(irb, cond_block); + IrInstSrc *cond_val = ir_gen_node(irb, node->data.while_expr.condition, scope); + if (cond_val == irb->codegen->invalid_inst_src) + return cond_val; + IrBasicBlockSrc *after_cond_block = irb->current_basic_block; + IrInstSrc *void_else_result = else_node ? nullptr : ir_mark_gen(ir_build_const_void(irb, scope, node)); + IrInstSrc *cond_br_inst; + if (!instr_is_unreachable(cond_val)) { + cond_br_inst = ir_build_cond_br(irb, scope, node->data.while_expr.condition, cond_val, + body_block, else_block, is_comptime); + cond_br_inst->is_gen = true; + } else { + // for the purposes of the source instruction to ir_build_result_peers + cond_br_inst = irb->current_basic_block->instruction_list.last(); + } + + ResultLocPeerParent *peer_parent = ir_build_result_peers(irb, cond_br_inst, end_block, result_loc, + is_comptime); + ir_set_cursor_at_end_and_append_block(irb, body_block); + + ZigList incoming_values = {0}; + ZigList incoming_blocks = {0}; + + Scope *subexpr_scope = create_runtime_scope(irb->codegen, node, scope, is_comptime); + + if (is_duplicate_label(irb->codegen, subexpr_scope, node, node->data.while_expr.name)) + return irb->codegen->invalid_inst_src; + + ScopeLoop *loop_scope = create_loop_scope(irb->codegen, node, subexpr_scope); + loop_scope->break_block = end_block; + loop_scope->continue_block = continue_block; + loop_scope->is_comptime = is_comptime; + loop_scope->incoming_blocks = &incoming_blocks; + loop_scope->incoming_values = &incoming_values; + loop_scope->lval = lval; + loop_scope->peer_parent = peer_parent; + + // Note the body block of the loop is not the place that lval and result_loc are used - + // it's actually in break statements, handled similarly to return statements. + // That is why we set those values in loop_scope above and not in this ir_gen_node call. + IrInstSrc *body_result = ir_gen_node(irb, node->data.while_expr.body, &loop_scope->base); + if (body_result == irb->codegen->invalid_inst_src) + return body_result; + + if (loop_scope->name != nullptr && loop_scope->name_used == false) { + add_node_error(irb->codegen, node, buf_sprintf("unused while label")); + } + + if (!instr_is_unreachable(body_result)) { + ir_mark_gen(ir_build_check_statement_is_void(irb, scope, node->data.while_expr.body, body_result)); + ir_mark_gen(ir_build_br(irb, scope, node, continue_block, is_comptime)); + } + + if (continue_expr_node) { + ir_set_cursor_at_end_and_append_block(irb, continue_block); + IrInstSrc *expr_result = ir_gen_node(irb, continue_expr_node, subexpr_scope); + if (expr_result == irb->codegen->invalid_inst_src) + return expr_result; + if (!instr_is_unreachable(expr_result)) { + ir_mark_gen(ir_build_check_statement_is_void(irb, scope, continue_expr_node, expr_result)); + ir_mark_gen(ir_build_br(irb, scope, node, cond_block, is_comptime)); + } + } + + IrInstSrc *else_result = nullptr; + if (else_node) { + ir_set_cursor_at_end_and_append_block(irb, else_block); + + if (peer_parent->peers.length != 0) { + peer_parent->peers.last()->next_bb = else_block; + } + ResultLocPeer *peer_result = create_peer_result(peer_parent); + peer_parent->peers.append(peer_result); + + else_result = ir_gen_node_extra(irb, else_node, subexpr_scope, lval, &peer_result->base); + if (else_result == irb->codegen->invalid_inst_src) + return else_result; + if (!instr_is_unreachable(else_result)) + ir_mark_gen(ir_build_br(irb, scope, node, end_block, is_comptime)); + } + IrBasicBlockSrc *after_else_block = irb->current_basic_block; + ir_set_cursor_at_end_and_append_block(irb, end_block); + if (else_result) { + incoming_blocks.append(after_else_block); + incoming_values.append(else_result); + } else { + incoming_blocks.append(after_cond_block); + incoming_values.append(void_else_result); + } + if (peer_parent->peers.length != 0) { + peer_parent->peers.last()->next_bb = end_block; + } + + IrInstSrc *phi = ir_build_phi(irb, scope, node, incoming_blocks.length, + incoming_blocks.items, incoming_values.items, peer_parent); + return ir_expr_wrap(irb, scope, phi, result_loc); + } +} + +static IrInstSrc *ir_gen_for_expr(IrBuilderSrc *irb, Scope *parent_scope, AstNode *node, LVal lval, + ResultLoc *result_loc) +{ + assert(node->type == NodeTypeForExpr); + + AstNode *array_node = node->data.for_expr.array_expr; + AstNode *elem_node = node->data.for_expr.elem_node; + AstNode *index_node = node->data.for_expr.index_node; + AstNode *body_node = node->data.for_expr.body; + AstNode *else_node = node->data.for_expr.else_node; + + if (!elem_node) { + add_node_error(irb->codegen, node, buf_sprintf("for loop expression missing element parameter")); + return irb->codegen->invalid_inst_src; + } + assert(elem_node->type == NodeTypeIdentifier); + + ScopeExpr *spill_scope = create_expr_scope(irb->codegen, node, parent_scope); + + IrInstSrc *array_val_ptr = ir_gen_node_extra(irb, array_node, &spill_scope->base, LValPtr, nullptr); + if (array_val_ptr == irb->codegen->invalid_inst_src) + return array_val_ptr; + + IrInstSrc *is_comptime = ir_build_const_bool(irb, parent_scope, node, + ir_should_inline(irb->exec, parent_scope) || node->data.for_expr.is_inline); + + AstNode *index_var_source_node; + ZigVar *index_var; + const char *index_var_name; + if (index_node) { + index_var_source_node = index_node; + Buf *index_var_name_buf = node_identifier_buf(index_node); + index_var = ir_create_var(irb, index_node, parent_scope, index_var_name_buf, true, false, false, is_comptime); + index_var_name = buf_ptr(index_var_name_buf); + } else { + index_var_source_node = node; + index_var = ir_create_var(irb, node, parent_scope, nullptr, true, false, true, is_comptime); + index_var_name = "i"; + } + + IrInstSrc *zero = ir_build_const_usize(irb, parent_scope, node, 0); + build_decl_var_and_init(irb, parent_scope, index_var_source_node, index_var, zero, index_var_name, is_comptime); + parent_scope = index_var->child_scope; + + IrInstSrc *one = ir_build_const_usize(irb, parent_scope, node, 1); + IrInstSrc *index_ptr = ir_build_var_ptr(irb, parent_scope, node, index_var); + + + IrBasicBlockSrc *cond_block = ir_create_basic_block(irb, parent_scope, "ForCond"); + IrBasicBlockSrc *body_block = ir_create_basic_block(irb, parent_scope, "ForBody"); + IrBasicBlockSrc *end_block = ir_create_basic_block(irb, parent_scope, "ForEnd"); + IrBasicBlockSrc *else_block = else_node ? ir_create_basic_block(irb, parent_scope, "ForElse") : end_block; + IrBasicBlockSrc *continue_block = ir_create_basic_block(irb, parent_scope, "ForContinue"); + + Buf *len_field_name = buf_create_from_str("len"); + IrInstSrc *len_ref = ir_build_field_ptr(irb, parent_scope, node, array_val_ptr, len_field_name, false); + IrInstSrc *len_val = ir_build_load_ptr(irb, &spill_scope->base, node, len_ref); + ir_build_br(irb, parent_scope, node, cond_block, is_comptime); + + ir_set_cursor_at_end_and_append_block(irb, cond_block); + IrInstSrc *index_val = ir_build_load_ptr(irb, &spill_scope->base, node, index_ptr); + IrInstSrc *cond = ir_build_bin_op(irb, parent_scope, node, IrBinOpCmpLessThan, index_val, len_val, false); + IrBasicBlockSrc *after_cond_block = irb->current_basic_block; + IrInstSrc *void_else_value = else_node ? nullptr : ir_mark_gen(ir_build_const_void(irb, parent_scope, node)); + IrInstSrc *cond_br_inst = ir_mark_gen(ir_build_cond_br(irb, parent_scope, node, cond, + body_block, else_block, is_comptime)); + + ResultLocPeerParent *peer_parent = ir_build_result_peers(irb, cond_br_inst, end_block, result_loc, is_comptime); + + ir_set_cursor_at_end_and_append_block(irb, body_block); + IrInstSrc *elem_ptr = ir_build_elem_ptr(irb, &spill_scope->base, node, array_val_ptr, index_val, + false, PtrLenSingle, nullptr); + // TODO make it an error to write to element variable or i variable. + Buf *elem_var_name = node_identifier_buf(elem_node); + ZigVar *elem_var = ir_create_var(irb, elem_node, parent_scope, elem_var_name, true, false, false, is_comptime); + Scope *child_scope = elem_var->child_scope; + + IrInstSrc *elem_value = node->data.for_expr.elem_is_ptr ? + elem_ptr : ir_build_load_ptr(irb, &spill_scope->base, elem_node, elem_ptr); + build_decl_var_and_init(irb, parent_scope, elem_node, elem_var, elem_value, buf_ptr(elem_var_name), is_comptime); + + if (is_duplicate_label(irb->codegen, child_scope, node, node->data.for_expr.name)) + return irb->codegen->invalid_inst_src; + + ZigList incoming_values = {0}; + ZigList incoming_blocks = {0}; + ScopeLoop *loop_scope = create_loop_scope(irb->codegen, node, child_scope); + loop_scope->break_block = end_block; + loop_scope->continue_block = continue_block; + loop_scope->is_comptime = is_comptime; + loop_scope->incoming_blocks = &incoming_blocks; + loop_scope->incoming_values = &incoming_values; + loop_scope->lval = LValNone; + loop_scope->peer_parent = peer_parent; + loop_scope->spill_scope = spill_scope; + + // Note the body block of the loop is not the place that lval and result_loc are used - + // it's actually in break statements, handled similarly to return statements. + // That is why we set those values in loop_scope above and not in this ir_gen_node call. + IrInstSrc *body_result = ir_gen_node(irb, body_node, &loop_scope->base); + if (body_result == irb->codegen->invalid_inst_src) + return irb->codegen->invalid_inst_src; + + if (loop_scope->name != nullptr && loop_scope->name_used == false) { + add_node_error(irb->codegen, node, buf_sprintf("unused for label")); + } + + if (!instr_is_unreachable(body_result)) { + ir_mark_gen(ir_build_check_statement_is_void(irb, child_scope, node->data.for_expr.body, body_result)); + ir_mark_gen(ir_build_br(irb, child_scope, node, continue_block, is_comptime)); + } + + ir_set_cursor_at_end_and_append_block(irb, continue_block); + IrInstSrc *new_index_val = ir_build_bin_op(irb, child_scope, node, IrBinOpAdd, index_val, one, false); + ir_build_store_ptr(irb, child_scope, node, index_ptr, new_index_val)->allow_write_through_const = true; + ir_build_br(irb, child_scope, node, cond_block, is_comptime); + + IrInstSrc *else_result = nullptr; + if (else_node) { + ir_set_cursor_at_end_and_append_block(irb, else_block); + + if (peer_parent->peers.length != 0) { + peer_parent->peers.last()->next_bb = else_block; + } + ResultLocPeer *peer_result = create_peer_result(peer_parent); + peer_parent->peers.append(peer_result); + else_result = ir_gen_node_extra(irb, else_node, parent_scope, LValNone, &peer_result->base); + if (else_result == irb->codegen->invalid_inst_src) + return else_result; + if (!instr_is_unreachable(else_result)) + ir_mark_gen(ir_build_br(irb, parent_scope, node, end_block, is_comptime)); + } + IrBasicBlockSrc *after_else_block = irb->current_basic_block; + ir_set_cursor_at_end_and_append_block(irb, end_block); + + if (else_result) { + incoming_blocks.append(after_else_block); + incoming_values.append(else_result); + } else { + incoming_blocks.append(after_cond_block); + incoming_values.append(void_else_value); + } + if (peer_parent->peers.length != 0) { + peer_parent->peers.last()->next_bb = end_block; + } + + IrInstSrc *phi = ir_build_phi(irb, parent_scope, node, incoming_blocks.length, + incoming_blocks.items, incoming_values.items, peer_parent); + return ir_lval_wrap(irb, parent_scope, phi, lval, result_loc); +} + +static IrInstSrc *ir_gen_bool_literal(IrBuilderSrc *irb, Scope *scope, AstNode *node) { + assert(node->type == NodeTypeBoolLiteral); + return ir_build_const_bool(irb, scope, node, node->data.bool_literal.value); +} + +static IrInstSrc *ir_gen_enum_literal(IrBuilderSrc *irb, Scope *scope, AstNode *node) { + assert(node->type == NodeTypeEnumLiteral); + RootStruct *root_struct = node->owner->data.structure.root_struct; + Buf *name = token_identifier_buf(root_struct, node->main_token + 1); + return ir_build_const_enum_literal(irb, scope, node, name); +} + +static IrInstSrc *ir_gen_string_literal(IrBuilderSrc *irb, Scope *scope, AstNode *node) { + Error err; + assert(node->type == NodeTypeStringLiteral); + + RootStruct *root_struct = node->owner->data.structure.root_struct; + const char *source = buf_ptr(root_struct->source_code); + + TokenId *token_ids = root_struct->token_ids; + + Buf *str = buf_alloc(); + if (token_ids[node->main_token] == TokenIdStringLiteral) { + size_t byte_offset = root_struct->token_locs[node->main_token].offset; + size_t bad_index; + if ((err = source_string_literal_buf(source + byte_offset, str, &bad_index))) { + add_token_error_offset(irb->codegen, node->owner, node->main_token, + buf_create_from_str("invalid string literal character"), bad_index); + } + src_assert(source[byte_offset] == '"', node); + byte_offset += 1; + } else if (token_ids[node->main_token] == TokenIdMultilineStringLiteralLine) { + TokenIndex tok_index = node->main_token; + bool first = true; + for (;token_ids[tok_index] == TokenIdMultilineStringLiteralLine; tok_index += 1) { + size_t byte_offset = root_struct->token_locs[tok_index].offset; + size_t end = byte_offset; + while (source[end] != 0 && source[end] != '\n') { + end += 1; + } + if (!first) { + buf_append_char(str, '\n'); + } else { + first = false; + } + buf_append_mem(str, source + byte_offset + 2, end - byte_offset - 2); + } + } else { + zig_unreachable(); + } + return ir_build_const_str_lit(irb, scope, node, str); +} + +static IrInstSrc *ir_gen_array_type(IrBuilderSrc *irb, Scope *scope, AstNode *node) { + assert(node->type == NodeTypeArrayType); + + AstNode *size_node = node->data.array_type.size; + AstNode *child_type_node = node->data.array_type.child_type; + bool is_const = node->data.array_type.is_const; + bool is_volatile = node->data.array_type.is_volatile; + bool is_allow_zero = node->data.array_type.allow_zero_token != 0; + AstNode *sentinel_expr = node->data.array_type.sentinel; + AstNode *align_expr = node->data.array_type.align_expr; + + Scope *comptime_scope = create_comptime_scope(irb->codegen, node, scope); + + IrInstSrc *sentinel; + if (sentinel_expr != nullptr) { + sentinel = ir_gen_node(irb, sentinel_expr, comptime_scope); + if (sentinel == irb->codegen->invalid_inst_src) + return sentinel; + } else { + sentinel = nullptr; + } + + if (size_node) { + if (is_const) { + add_node_error(irb->codegen, node, buf_create_from_str("const qualifier invalid on array type")); + return irb->codegen->invalid_inst_src; + } + if (is_volatile) { + add_node_error(irb->codegen, node, buf_create_from_str("volatile qualifier invalid on array type")); + return irb->codegen->invalid_inst_src; + } + if (is_allow_zero) { + add_node_error(irb->codegen, node, buf_create_from_str("allowzero qualifier invalid on array type")); + return irb->codegen->invalid_inst_src; + } + if (align_expr != nullptr) { + add_node_error(irb->codegen, node, buf_create_from_str("align qualifier invalid on array type")); + return irb->codegen->invalid_inst_src; + } + + IrInstSrc *size_value = ir_gen_node(irb, size_node, comptime_scope); + if (size_value == irb->codegen->invalid_inst_src) + return size_value; + + IrInstSrc *child_type = ir_gen_node(irb, child_type_node, comptime_scope); + if (child_type == irb->codegen->invalid_inst_src) + return child_type; + + return ir_build_array_type(irb, scope, node, size_value, sentinel, child_type); + } else { + IrInstSrc *align_value; + if (align_expr != nullptr) { + align_value = ir_gen_node(irb, align_expr, comptime_scope); + if (align_value == irb->codegen->invalid_inst_src) + return align_value; + } else { + align_value = nullptr; + } + + IrInstSrc *child_type = ir_gen_node(irb, child_type_node, comptime_scope); + if (child_type == irb->codegen->invalid_inst_src) + return child_type; + + return ir_build_slice_type(irb, scope, node, child_type, is_const, is_volatile, sentinel, + align_value, is_allow_zero); + } +} + +static IrInstSrc *ir_gen_anyframe_type(IrBuilderSrc *irb, Scope *scope, AstNode *node) { + assert(node->type == NodeTypeAnyFrameType); + + AstNode *payload_type_node = node->data.anyframe_type.payload_type; + IrInstSrc *payload_type_value = nullptr; + + if (payload_type_node != nullptr) { + payload_type_value = ir_gen_node(irb, payload_type_node, scope); + if (payload_type_value == irb->codegen->invalid_inst_src) + return payload_type_value; + + } + + return ir_build_anyframe_type(irb, scope, node, payload_type_value); +} + +static IrInstSrc *ir_gen_undefined_literal(IrBuilderSrc *irb, Scope *scope, AstNode *node) { + assert(node->type == NodeTypeUndefinedLiteral); + return ir_build_const_undefined(irb, scope, node); +} + +static IrInstSrc *ir_gen_asm_expr(IrBuilderSrc *irb, Scope *scope, AstNode *node) { + assert(node->type == NodeTypeAsmExpr); + AstNodeAsmExpr *asm_expr = &node->data.asm_expr; + + IrInstSrc *asm_template = ir_gen_node(irb, asm_expr->asm_template, scope); + if (asm_template == irb->codegen->invalid_inst_src) + return irb->codegen->invalid_inst_src; + + bool is_volatile = asm_expr->volatile_token != 0; + bool in_fn_scope = (scope_fn_entry(scope) != nullptr); + + if (!in_fn_scope) { + if (is_volatile) { + add_token_error(irb->codegen, node->owner, asm_expr->volatile_token, + buf_sprintf("volatile is meaningless on global assembly")); + return irb->codegen->invalid_inst_src; + } + + if (asm_expr->output_list.length != 0 || asm_expr->input_list.length != 0 || + asm_expr->clobber_list.length != 0) + { + add_node_error(irb->codegen, node, + buf_sprintf("global assembly cannot have inputs, outputs, or clobbers")); + return irb->codegen->invalid_inst_src; + } + + return ir_build_asm_src(irb, scope, node, asm_template, nullptr, nullptr, + nullptr, 0, is_volatile, true); + } + + IrInstSrc **input_list = heap::c_allocator.allocate(asm_expr->input_list.length); + IrInstSrc **output_types = heap::c_allocator.allocate(asm_expr->output_list.length); + ZigVar **output_vars = heap::c_allocator.allocate(asm_expr->output_list.length); + size_t return_count = 0; + if (!is_volatile && asm_expr->output_list.length == 0) { + add_node_error(irb->codegen, node, + buf_sprintf("assembly expression with no output must be marked volatile")); + return irb->codegen->invalid_inst_src; + } + for (size_t i = 0; i < asm_expr->output_list.length; i += 1) { + AsmOutput *asm_output = asm_expr->output_list.at(i); + if (asm_output->return_type) { + return_count += 1; + + IrInstSrc *return_type = ir_gen_node(irb, asm_output->return_type, scope); + if (return_type == irb->codegen->invalid_inst_src) + return irb->codegen->invalid_inst_src; + if (return_count > 1) { + add_node_error(irb->codegen, node, + buf_sprintf("inline assembly allows up to one output value")); + return irb->codegen->invalid_inst_src; + } + output_types[i] = return_type; + } else { + Buf *variable_name = asm_output->variable_name; + // TODO there is some duplication here with ir_gen_symbol. I need to do a full audit of how + // inline assembly works. https://github.com/ziglang/zig/issues/215 + ZigVar *var = find_variable(irb->codegen, scope, variable_name, nullptr); + if (var) { + output_vars[i] = var; + } else { + add_node_error(irb->codegen, node, + buf_sprintf("use of undeclared identifier '%s'", buf_ptr(variable_name))); + return irb->codegen->invalid_inst_src; + } + } + + const char modifier = *buf_ptr(asm_output->constraint); + if (modifier != '=') { + add_node_error(irb->codegen, node, + buf_sprintf("invalid modifier starting output constraint for '%s': '%c', only '=' is supported." + " Compiler TODO: see https://github.com/ziglang/zig/issues/215", + buf_ptr(asm_output->asm_symbolic_name), modifier)); + return irb->codegen->invalid_inst_src; + } + } + for (size_t i = 0; i < asm_expr->input_list.length; i += 1) { + AsmInput *asm_input = asm_expr->input_list.at(i); + IrInstSrc *input_value = ir_gen_node(irb, asm_input->expr, scope); + if (input_value == irb->codegen->invalid_inst_src) + return irb->codegen->invalid_inst_src; + + input_list[i] = input_value; + } + + return ir_build_asm_src(irb, scope, node, asm_template, input_list, output_types, + output_vars, return_count, is_volatile, false); +} + +static IrInstSrc *ir_gen_if_optional_expr(IrBuilderSrc *irb, Scope *scope, AstNode *node, LVal lval, + ResultLoc *result_loc) +{ + assert(node->type == NodeTypeIfOptional); + + Buf *var_symbol = node->data.test_expr.var_symbol; + AstNode *expr_node = node->data.test_expr.target_node; + AstNode *then_node = node->data.test_expr.then_node; + AstNode *else_node = node->data.test_expr.else_node; + bool var_is_ptr = node->data.test_expr.var_is_ptr; + + ScopeExpr *spill_scope = create_expr_scope(irb->codegen, expr_node, scope); + spill_scope->spill_harder = true; + + IrInstSrc *maybe_val_ptr = ir_gen_node_extra(irb, expr_node, &spill_scope->base, LValPtr, nullptr); + if (maybe_val_ptr == irb->codegen->invalid_inst_src) + return maybe_val_ptr; + + IrInstSrc *maybe_val = ir_build_load_ptr(irb, scope, node, maybe_val_ptr); + IrInstSrc *is_non_null = ir_build_test_non_null_src(irb, scope, node, maybe_val); + + IrBasicBlockSrc *then_block = ir_create_basic_block(irb, scope, "OptionalThen"); + IrBasicBlockSrc *else_block = ir_create_basic_block(irb, scope, "OptionalElse"); + IrBasicBlockSrc *endif_block = ir_create_basic_block(irb, scope, "OptionalEndIf"); + + IrInstSrc *is_comptime; + if (ir_should_inline(irb->exec, scope)) { + is_comptime = ir_build_const_bool(irb, scope, node, true); + } else { + is_comptime = ir_build_test_comptime(irb, scope, node, is_non_null); + } + IrInstSrc *cond_br_inst = ir_build_cond_br(irb, scope, node, is_non_null, + then_block, else_block, is_comptime); + + ResultLocPeerParent *peer_parent = ir_build_binary_result_peers(irb, cond_br_inst, else_block, endif_block, + result_loc, is_comptime); + + ir_set_cursor_at_end_and_append_block(irb, then_block); + + Scope *subexpr_scope = create_runtime_scope(irb->codegen, node, &spill_scope->base, is_comptime); + Scope *var_scope; + if (var_symbol) { + bool is_shadowable = false; + bool is_const = true; + ZigVar *var = ir_create_var(irb, node, subexpr_scope, + var_symbol, is_const, is_const, is_shadowable, is_comptime); + + IrInstSrc *payload_ptr = ir_build_optional_unwrap_ptr(irb, subexpr_scope, node, maybe_val_ptr, false); + IrInstSrc *var_value = var_is_ptr ? + payload_ptr : ir_build_load_ptr(irb, &spill_scope->base, node, payload_ptr); + build_decl_var_and_init(irb, subexpr_scope, node, var, var_value, buf_ptr(var_symbol), is_comptime); + var_scope = var->child_scope; + } else { + var_scope = subexpr_scope; + } + IrInstSrc *then_expr_result = ir_gen_node_extra(irb, then_node, var_scope, lval, + &peer_parent->peers.at(0)->base); + if (then_expr_result == irb->codegen->invalid_inst_src) + return then_expr_result; + IrBasicBlockSrc *after_then_block = irb->current_basic_block; + if (!instr_is_unreachable(then_expr_result)) + ir_mark_gen(ir_build_br(irb, scope, node, endif_block, is_comptime)); + + ir_set_cursor_at_end_and_append_block(irb, else_block); + IrInstSrc *else_expr_result; + if (else_node) { + else_expr_result = ir_gen_node_extra(irb, else_node, subexpr_scope, lval, &peer_parent->peers.at(1)->base); + if (else_expr_result == irb->codegen->invalid_inst_src) + return else_expr_result; + } else { + else_expr_result = ir_build_const_void(irb, scope, node); + ir_build_end_expr(irb, scope, node, else_expr_result, &peer_parent->peers.at(1)->base); + } + IrBasicBlockSrc *after_else_block = irb->current_basic_block; + if (!instr_is_unreachable(else_expr_result)) + ir_mark_gen(ir_build_br(irb, scope, node, endif_block, is_comptime)); + + ir_set_cursor_at_end_and_append_block(irb, endif_block); + IrInstSrc **incoming_values = heap::c_allocator.allocate(2); + incoming_values[0] = then_expr_result; + incoming_values[1] = else_expr_result; + IrBasicBlockSrc **incoming_blocks = heap::c_allocator.allocate(2); + incoming_blocks[0] = after_then_block; + incoming_blocks[1] = after_else_block; + + IrInstSrc *phi = ir_build_phi(irb, scope, node, 2, incoming_blocks, incoming_values, peer_parent); + return ir_expr_wrap(irb, scope, phi, result_loc); +} + +static IrInstSrc *ir_gen_if_err_expr(IrBuilderSrc *irb, Scope *scope, AstNode *node, LVal lval, + ResultLoc *result_loc) +{ + assert(node->type == NodeTypeIfErrorExpr); + + AstNode *target_node = node->data.if_err_expr.target_node; + AstNode *then_node = node->data.if_err_expr.then_node; + AstNode *else_node = node->data.if_err_expr.else_node; + bool var_is_ptr = node->data.if_err_expr.var_is_ptr; + bool var_is_const = true; + Buf *var_symbol = node->data.if_err_expr.var_symbol; + Buf *err_symbol = node->data.if_err_expr.err_symbol; + + IrInstSrc *err_val_ptr = ir_gen_node_extra(irb, target_node, scope, LValPtr, nullptr); + if (err_val_ptr == irb->codegen->invalid_inst_src) + return err_val_ptr; + + IrInstSrc *err_val = ir_build_load_ptr(irb, scope, node, err_val_ptr); + IrInstSrc *is_err = ir_build_test_err_src(irb, scope, node, err_val_ptr, true, false); + + IrBasicBlockSrc *ok_block = ir_create_basic_block(irb, scope, "TryOk"); + IrBasicBlockSrc *else_block = ir_create_basic_block(irb, scope, "TryElse"); + IrBasicBlockSrc *endif_block = ir_create_basic_block(irb, scope, "TryEnd"); + + bool force_comptime = ir_should_inline(irb->exec, scope); + IrInstSrc *is_comptime = force_comptime ? ir_build_const_bool(irb, scope, node, true) : ir_build_test_comptime(irb, scope, node, is_err); + IrInstSrc *cond_br_inst = ir_build_cond_br(irb, scope, node, is_err, else_block, ok_block, is_comptime); + + ResultLocPeerParent *peer_parent = ir_build_binary_result_peers(irb, cond_br_inst, else_block, endif_block, + result_loc, is_comptime); + + ir_set_cursor_at_end_and_append_block(irb, ok_block); + + Scope *subexpr_scope = create_runtime_scope(irb->codegen, node, scope, is_comptime); + Scope *var_scope; + if (var_symbol) { + bool is_shadowable = false; + IrInstSrc *var_is_comptime = force_comptime ? ir_build_const_bool(irb, subexpr_scope, node, true) : ir_build_test_comptime(irb, subexpr_scope, node, err_val); + ZigVar *var = ir_create_var(irb, node, subexpr_scope, + var_symbol, var_is_const, var_is_const, is_shadowable, var_is_comptime); + + IrInstSrc *payload_ptr = ir_build_unwrap_err_payload_src(irb, subexpr_scope, node, err_val_ptr, false, false); + IrInstSrc *var_value = var_is_ptr ? + payload_ptr : ir_build_load_ptr(irb, subexpr_scope, node, payload_ptr); + build_decl_var_and_init(irb, subexpr_scope, node, var, var_value, buf_ptr(var_symbol), var_is_comptime); + var_scope = var->child_scope; + } else { + var_scope = subexpr_scope; + } + IrInstSrc *then_expr_result = ir_gen_node_extra(irb, then_node, var_scope, lval, + &peer_parent->peers.at(0)->base); + if (then_expr_result == irb->codegen->invalid_inst_src) + return then_expr_result; + IrBasicBlockSrc *after_then_block = irb->current_basic_block; + if (!instr_is_unreachable(then_expr_result)) + ir_mark_gen(ir_build_br(irb, scope, node, endif_block, is_comptime)); + + ir_set_cursor_at_end_and_append_block(irb, else_block); + + IrInstSrc *else_expr_result; + if (else_node) { + Scope *err_var_scope; + if (err_symbol) { + bool is_shadowable = false; + bool is_const = true; + ZigVar *var = ir_create_var(irb, node, subexpr_scope, + err_symbol, is_const, is_const, is_shadowable, is_comptime); + + IrInstSrc *err_ptr = ir_build_unwrap_err_code_src(irb, subexpr_scope, node, err_val_ptr); + IrInstSrc *err_value = ir_build_load_ptr(irb, subexpr_scope, node, err_ptr); + build_decl_var_and_init(irb, subexpr_scope, node, var, err_value, buf_ptr(err_symbol), is_comptime); + err_var_scope = var->child_scope; + } else { + err_var_scope = subexpr_scope; + } + else_expr_result = ir_gen_node_extra(irb, else_node, err_var_scope, lval, &peer_parent->peers.at(1)->base); + if (else_expr_result == irb->codegen->invalid_inst_src) + return else_expr_result; + } else { + else_expr_result = ir_build_const_void(irb, scope, node); + ir_build_end_expr(irb, scope, node, else_expr_result, &peer_parent->peers.at(1)->base); + } + IrBasicBlockSrc *after_else_block = irb->current_basic_block; + if (!instr_is_unreachable(else_expr_result)) + ir_mark_gen(ir_build_br(irb, scope, node, endif_block, is_comptime)); + + ir_set_cursor_at_end_and_append_block(irb, endif_block); + IrInstSrc **incoming_values = heap::c_allocator.allocate(2); + incoming_values[0] = then_expr_result; + incoming_values[1] = else_expr_result; + IrBasicBlockSrc **incoming_blocks = heap::c_allocator.allocate(2); + incoming_blocks[0] = after_then_block; + incoming_blocks[1] = after_else_block; + + IrInstSrc *phi = ir_build_phi(irb, scope, node, 2, incoming_blocks, incoming_values, peer_parent); + return ir_expr_wrap(irb, scope, phi, result_loc); +} + +static bool ir_gen_switch_prong_expr(IrBuilderSrc *irb, Scope *scope, AstNode *switch_node, AstNode *prong_node, + IrBasicBlockSrc *end_block, IrInstSrc *is_comptime, IrInstSrc *var_is_comptime, + IrInstSrc *target_value_ptr, IrInstSrc **prong_values, size_t prong_values_len, + ZigList *incoming_blocks, ZigList *incoming_values, + IrInstSrcSwitchElseVar **out_switch_else_var, LVal lval, ResultLoc *result_loc) +{ + assert(switch_node->type == NodeTypeSwitchExpr); + assert(prong_node->type == NodeTypeSwitchProng); + + AstNode *expr_node = prong_node->data.switch_prong.expr; + AstNode *var_symbol_node = prong_node->data.switch_prong.var_symbol; + Scope *child_scope; + if (var_symbol_node) { + assert(var_symbol_node->type == NodeTypeIdentifier); + Buf *var_name = node_identifier_buf(var_symbol_node); + bool var_is_ptr = prong_node->data.switch_prong.var_is_ptr; + + bool is_shadowable = false; + bool is_const = true; + ZigVar *var = ir_create_var(irb, var_symbol_node, scope, + var_name, is_const, is_const, is_shadowable, var_is_comptime); + child_scope = var->child_scope; + IrInstSrc *var_value; + if (out_switch_else_var != nullptr) { + IrInstSrcSwitchElseVar *switch_else_var = ir_build_switch_else_var(irb, scope, var_symbol_node, + target_value_ptr); + *out_switch_else_var = switch_else_var; + IrInstSrc *payload_ptr = &switch_else_var->base; + var_value = var_is_ptr ? + payload_ptr : ir_build_load_ptr(irb, scope, var_symbol_node, payload_ptr); + } else if (prong_values != nullptr) { + IrInstSrc *payload_ptr = ir_build_switch_var(irb, scope, var_symbol_node, target_value_ptr, + prong_values, prong_values_len); + var_value = var_is_ptr ? + payload_ptr : ir_build_load_ptr(irb, scope, var_symbol_node, payload_ptr); + } else { + var_value = var_is_ptr ? + target_value_ptr : ir_build_load_ptr(irb, scope, var_symbol_node, target_value_ptr); + } + build_decl_var_and_init(irb, scope, var_symbol_node, var, var_value, buf_ptr(var_name), var_is_comptime); + } else { + child_scope = scope; + } + + IrInstSrc *expr_result = ir_gen_node_extra(irb, expr_node, child_scope, lval, result_loc); + if (expr_result == irb->codegen->invalid_inst_src) + return false; + if (!instr_is_unreachable(expr_result)) + ir_mark_gen(ir_build_br(irb, scope, switch_node, end_block, is_comptime)); + incoming_blocks->append(irb->current_basic_block); + incoming_values->append(expr_result); + return true; +} + +static IrInstSrc *ir_gen_switch_expr(IrBuilderSrc *irb, Scope *scope, AstNode *node, LVal lval, + ResultLoc *result_loc) +{ + assert(node->type == NodeTypeSwitchExpr); + + AstNode *target_node = node->data.switch_expr.expr; + IrInstSrc *target_value_ptr = ir_gen_node_extra(irb, target_node, scope, LValPtr, nullptr); + if (target_value_ptr == irb->codegen->invalid_inst_src) + return target_value_ptr; + IrInstSrc *target_value = ir_build_switch_target(irb, scope, node, target_value_ptr); + + IrBasicBlockSrc *else_block = ir_create_basic_block(irb, scope, "SwitchElse"); + IrBasicBlockSrc *end_block = ir_create_basic_block(irb, scope, "SwitchEnd"); + + size_t prong_count = node->data.switch_expr.prongs.length; + ZigList cases = {0}; + + IrInstSrc *is_comptime; + IrInstSrc *var_is_comptime; + if (ir_should_inline(irb->exec, scope)) { + is_comptime = ir_build_const_bool(irb, scope, node, true); + var_is_comptime = is_comptime; + } else { + is_comptime = ir_build_test_comptime(irb, scope, node, target_value); + var_is_comptime = ir_build_test_comptime(irb, scope, node, target_value_ptr); + } + + ZigList incoming_values = {0}; + ZigList incoming_blocks = {0}; + ZigList check_ranges = {0}; + + IrInstSrcSwitchElseVar *switch_else_var = nullptr; + + ResultLocPeerParent *peer_parent = heap::c_allocator.create(); + peer_parent->base.id = ResultLocIdPeerParent; + peer_parent->base.allow_write_through_const = result_loc->allow_write_through_const; + peer_parent->end_bb = end_block; + peer_parent->is_comptime = is_comptime; + peer_parent->parent = result_loc; + + ir_build_reset_result(irb, scope, node, &peer_parent->base); + + // First do the else and the ranges + Scope *subexpr_scope = create_runtime_scope(irb->codegen, node, scope, is_comptime); + Scope *comptime_scope = create_comptime_scope(irb->codegen, node, scope); + AstNode *else_prong = nullptr; + AstNode *underscore_prong = nullptr; + for (size_t prong_i = 0; prong_i < prong_count; prong_i += 1) { + AstNode *prong_node = node->data.switch_expr.prongs.at(prong_i); + size_t prong_item_count = prong_node->data.switch_prong.items.length; + if (prong_node->data.switch_prong.any_items_are_range) { + ResultLocPeer *this_peer_result_loc = create_peer_result(peer_parent); + + IrInstSrc *ok_bit = nullptr; + AstNode *last_item_node = nullptr; + for (size_t item_i = 0; item_i < prong_item_count; item_i += 1) { + AstNode *item_node = prong_node->data.switch_prong.items.at(item_i); + last_item_node = item_node; + if (item_node->type == NodeTypeSwitchRange) { + AstNode *start_node = item_node->data.switch_range.start; + AstNode *end_node = item_node->data.switch_range.end; + + IrInstSrc *start_value = ir_gen_node(irb, start_node, comptime_scope); + if (start_value == irb->codegen->invalid_inst_src) + return irb->codegen->invalid_inst_src; + + IrInstSrc *end_value = ir_gen_node(irb, end_node, comptime_scope); + if (end_value == irb->codegen->invalid_inst_src) + return irb->codegen->invalid_inst_src; + + IrInstSrcCheckSwitchProngsRange *check_range = check_ranges.add_one(); + check_range->start = start_value; + check_range->end = end_value; + + IrInstSrc *lower_range_ok = ir_build_bin_op(irb, scope, item_node, IrBinOpCmpGreaterOrEq, + target_value, start_value, false); + IrInstSrc *upper_range_ok = ir_build_bin_op(irb, scope, item_node, IrBinOpCmpLessOrEq, + target_value, end_value, false); + IrInstSrc *both_ok = ir_build_bin_op(irb, scope, item_node, IrBinOpBoolAnd, + lower_range_ok, upper_range_ok, false); + if (ok_bit) { + ok_bit = ir_build_bin_op(irb, scope, item_node, IrBinOpBoolOr, both_ok, ok_bit, false); + } else { + ok_bit = both_ok; + } + } else { + IrInstSrc *item_value = ir_gen_node(irb, item_node, comptime_scope); + if (item_value == irb->codegen->invalid_inst_src) + return irb->codegen->invalid_inst_src; + + IrInstSrcCheckSwitchProngsRange *check_range = check_ranges.add_one(); + check_range->start = item_value; + check_range->end = item_value; + + IrInstSrc *cmp_ok = ir_build_bin_op(irb, scope, item_node, IrBinOpCmpEq, + item_value, target_value, false); + if (ok_bit) { + ok_bit = ir_build_bin_op(irb, scope, item_node, IrBinOpBoolOr, cmp_ok, ok_bit, false); + } else { + ok_bit = cmp_ok; + } + } + } + + IrBasicBlockSrc *range_block_yes = ir_create_basic_block(irb, scope, "SwitchRangeYes"); + IrBasicBlockSrc *range_block_no = ir_create_basic_block(irb, scope, "SwitchRangeNo"); + + assert(ok_bit); + assert(last_item_node); + IrInstSrc *br_inst = ir_mark_gen(ir_build_cond_br(irb, scope, last_item_node, ok_bit, + range_block_yes, range_block_no, is_comptime)); + if (peer_parent->base.source_instruction == nullptr) { + peer_parent->base.source_instruction = br_inst; + } + + if (peer_parent->peers.length > 0) { + peer_parent->peers.last()->next_bb = range_block_yes; + } + peer_parent->peers.append(this_peer_result_loc); + ir_set_cursor_at_end_and_append_block(irb, range_block_yes); + if (!ir_gen_switch_prong_expr(irb, subexpr_scope, node, prong_node, end_block, + is_comptime, var_is_comptime, target_value_ptr, nullptr, 0, + &incoming_blocks, &incoming_values, nullptr, LValNone, &this_peer_result_loc->base)) + { + return irb->codegen->invalid_inst_src; + } + + ir_set_cursor_at_end_and_append_block(irb, range_block_no); + } else { + if (prong_item_count == 0) { + if (else_prong) { + ErrorMsg *msg = add_node_error(irb->codegen, prong_node, + buf_sprintf("multiple else prongs in switch expression")); + add_error_note(irb->codegen, msg, else_prong, + buf_sprintf("previous else prong is here")); + return irb->codegen->invalid_inst_src; + } + else_prong = prong_node; + } else if (prong_item_count == 1 && + prong_node->data.switch_prong.items.at(0)->type == NodeTypeIdentifier && + buf_eql_str(node_identifier_buf(prong_node->data.switch_prong.items.at(0)), "_")) { + if (underscore_prong) { + ErrorMsg *msg = add_node_error(irb->codegen, prong_node, + buf_sprintf("multiple '_' prongs in switch expression")); + add_error_note(irb->codegen, msg, underscore_prong, + buf_sprintf("previous '_' prong is here")); + return irb->codegen->invalid_inst_src; + } + underscore_prong = prong_node; + } else { + continue; + } + if (underscore_prong && else_prong) { + ErrorMsg *msg = add_node_error(irb->codegen, prong_node, + buf_sprintf("else and '_' prong in switch expression")); + if (underscore_prong == prong_node) + add_error_note(irb->codegen, msg, else_prong, + buf_sprintf("else prong is here")); + else + add_error_note(irb->codegen, msg, underscore_prong, + buf_sprintf("'_' prong is here")); + return irb->codegen->invalid_inst_src; + } + ResultLocPeer *this_peer_result_loc = create_peer_result(peer_parent); + + IrBasicBlockSrc *prev_block = irb->current_basic_block; + if (peer_parent->peers.length > 0) { + peer_parent->peers.last()->next_bb = else_block; + } + peer_parent->peers.append(this_peer_result_loc); + ir_set_cursor_at_end_and_append_block(irb, else_block); + if (!ir_gen_switch_prong_expr(irb, subexpr_scope, node, prong_node, end_block, + is_comptime, var_is_comptime, target_value_ptr, nullptr, 0, &incoming_blocks, &incoming_values, + &switch_else_var, LValNone, &this_peer_result_loc->base)) + { + return irb->codegen->invalid_inst_src; + } + ir_set_cursor_at_end(irb, prev_block); + } + } + + // next do the non-else non-ranges + for (size_t prong_i = 0; prong_i < prong_count; prong_i += 1) { + AstNode *prong_node = node->data.switch_expr.prongs.at(prong_i); + size_t prong_item_count = prong_node->data.switch_prong.items.length; + if (prong_item_count == 0) + continue; + if (prong_node->data.switch_prong.any_items_are_range) + continue; + if (underscore_prong == prong_node) + continue; + + ResultLocPeer *this_peer_result_loc = create_peer_result(peer_parent); + + IrBasicBlockSrc *prong_block = ir_create_basic_block(irb, scope, "SwitchProng"); + IrInstSrc **items = heap::c_allocator.allocate(prong_item_count); + + for (size_t item_i = 0; item_i < prong_item_count; item_i += 1) { + AstNode *item_node = prong_node->data.switch_prong.items.at(item_i); + assert(item_node->type != NodeTypeSwitchRange); + + IrInstSrc *item_value = ir_gen_node(irb, item_node, comptime_scope); + if (item_value == irb->codegen->invalid_inst_src) + return irb->codegen->invalid_inst_src; + + IrInstSrcCheckSwitchProngsRange *check_range = check_ranges.add_one(); + check_range->start = item_value; + check_range->end = item_value; + + IrInstSrcSwitchBrCase *this_case = cases.add_one(); + this_case->value = item_value; + this_case->block = prong_block; + + items[item_i] = item_value; + } + + IrBasicBlockSrc *prev_block = irb->current_basic_block; + if (peer_parent->peers.length > 0) { + peer_parent->peers.last()->next_bb = prong_block; + } + peer_parent->peers.append(this_peer_result_loc); + ir_set_cursor_at_end_and_append_block(irb, prong_block); + if (!ir_gen_switch_prong_expr(irb, subexpr_scope, node, prong_node, end_block, + is_comptime, var_is_comptime, target_value_ptr, items, prong_item_count, + &incoming_blocks, &incoming_values, nullptr, LValNone, &this_peer_result_loc->base)) + { + return irb->codegen->invalid_inst_src; + } + + ir_set_cursor_at_end(irb, prev_block); + + } + + IrInstSrc *switch_prongs_void = ir_build_check_switch_prongs(irb, scope, node, target_value, + check_ranges.items, check_ranges.length, else_prong, underscore_prong != nullptr); + + IrInstSrc *br_instruction; + if (cases.length == 0) { + br_instruction = ir_build_br(irb, scope, node, else_block, is_comptime); + } else { + IrInstSrcSwitchBr *switch_br = ir_build_switch_br_src(irb, scope, node, target_value, else_block, + cases.length, cases.items, is_comptime, switch_prongs_void); + if (switch_else_var != nullptr) { + switch_else_var->switch_br = switch_br; + } + br_instruction = &switch_br->base; + } + if (peer_parent->base.source_instruction == nullptr) { + peer_parent->base.source_instruction = br_instruction; + } + for (size_t i = 0; i < peer_parent->peers.length; i += 1) { + peer_parent->peers.at(i)->base.source_instruction = peer_parent->base.source_instruction; + } + + if (!else_prong && !underscore_prong) { + if (peer_parent->peers.length != 0) { + peer_parent->peers.last()->next_bb = else_block; + } + ir_set_cursor_at_end_and_append_block(irb, else_block); + ir_build_unreachable(irb, scope, node); + } else { + if (peer_parent->peers.length != 0) { + peer_parent->peers.last()->next_bb = end_block; + } + } + + ir_set_cursor_at_end_and_append_block(irb, end_block); + assert(incoming_blocks.length == incoming_values.length); + IrInstSrc *result_instruction; + if (incoming_blocks.length == 0) { + result_instruction = ir_build_const_void(irb, scope, node); + } else { + result_instruction = ir_build_phi(irb, scope, node, incoming_blocks.length, + incoming_blocks.items, incoming_values.items, peer_parent); + } + return ir_lval_wrap(irb, scope, result_instruction, lval, result_loc); +} + +static IrInstSrc *ir_gen_comptime(IrBuilderSrc *irb, Scope *parent_scope, AstNode *node, LVal lval) { + assert(node->type == NodeTypeCompTime); + + Scope *child_scope = create_comptime_scope(irb->codegen, node, parent_scope); + // purposefully pass null for result_loc and let EndExpr handle it + return ir_gen_node_extra(irb, node->data.comptime_expr.expr, child_scope, lval, nullptr); +} + +static IrInstSrc *ir_gen_nosuspend(IrBuilderSrc *irb, Scope *parent_scope, AstNode *node, LVal lval) { + assert(node->type == NodeTypeNoSuspend); + + Scope *child_scope = create_nosuspend_scope(irb->codegen, node, parent_scope); + // purposefully pass null for result_loc and let EndExpr handle it + return ir_gen_node_extra(irb, node->data.nosuspend_expr.expr, child_scope, lval, nullptr); +} + +static IrInstSrc *ir_gen_return_from_block(IrBuilderSrc *irb, Scope *break_scope, AstNode *node, ScopeBlock *block_scope) { + IrInstSrc *is_comptime; + if (ir_should_inline(irb->exec, break_scope)) { + is_comptime = ir_build_const_bool(irb, break_scope, node, true); + } else { + is_comptime = block_scope->is_comptime; + } + + IrInstSrc *result_value; + if (node->data.break_expr.expr) { + ResultLocPeer *peer_result = create_peer_result(block_scope->peer_parent); + block_scope->peer_parent->peers.append(peer_result); + + result_value = ir_gen_node_extra(irb, node->data.break_expr.expr, break_scope, block_scope->lval, + &peer_result->base); + if (result_value == irb->codegen->invalid_inst_src) + return irb->codegen->invalid_inst_src; + } else { + result_value = ir_build_const_void(irb, break_scope, node); + } + + IrBasicBlockSrc *dest_block = block_scope->end_block; + if (!ir_gen_defers_for_block(irb, break_scope, dest_block->scope, nullptr, nullptr)) + return irb->codegen->invalid_inst_src; + + block_scope->incoming_blocks->append(irb->current_basic_block); + block_scope->incoming_values->append(result_value); + return ir_build_br(irb, break_scope, node, dest_block, is_comptime); +} + +static IrInstSrc *ir_gen_break(IrBuilderSrc *irb, Scope *break_scope, AstNode *node) { + assert(node->type == NodeTypeBreak); + + // Search up the scope. We'll find one of these things first: + // * function definition scope or global scope => error, break outside loop + // * defer expression scope => error, cannot break out of defer expression + // * loop scope => OK + // * (if it's a labeled break) labeled block => OK + + Scope *search_scope = break_scope; + ScopeLoop *loop_scope; + for (;;) { + if (search_scope == nullptr || search_scope->id == ScopeIdFnDef) { + if (node->data.break_expr.name != nullptr) { + add_node_error(irb->codegen, node, buf_sprintf("label not found: '%s'", buf_ptr(node->data.break_expr.name))); + return irb->codegen->invalid_inst_src; + } else { + add_node_error(irb->codegen, node, buf_sprintf("break expression outside loop")); + return irb->codegen->invalid_inst_src; + } + } else if (search_scope->id == ScopeIdDeferExpr) { + add_node_error(irb->codegen, node, buf_sprintf("cannot break out of defer expression")); + return irb->codegen->invalid_inst_src; + } else if (search_scope->id == ScopeIdLoop) { + ScopeLoop *this_loop_scope = (ScopeLoop *)search_scope; + if (node->data.break_expr.name == nullptr || + (this_loop_scope->name != nullptr && buf_eql_buf(node->data.break_expr.name, this_loop_scope->name))) + { + this_loop_scope->name_used = true; + loop_scope = this_loop_scope; + break; + } + } else if (search_scope->id == ScopeIdBlock) { + ScopeBlock *this_block_scope = (ScopeBlock *)search_scope; + if (node->data.break_expr.name != nullptr && + (this_block_scope->name != nullptr && buf_eql_buf(node->data.break_expr.name, this_block_scope->name))) + { + assert(this_block_scope->end_block != nullptr); + this_block_scope->name_used = true; + return ir_gen_return_from_block(irb, break_scope, node, this_block_scope); + } + } else if (search_scope->id == ScopeIdSuspend) { + add_node_error(irb->codegen, node, buf_sprintf("cannot break out of suspend block")); + return irb->codegen->invalid_inst_src; + } + search_scope = search_scope->parent; + } + + IrInstSrc *is_comptime; + if (ir_should_inline(irb->exec, break_scope)) { + is_comptime = ir_build_const_bool(irb, break_scope, node, true); + } else { + is_comptime = loop_scope->is_comptime; + } + + IrInstSrc *result_value; + if (node->data.break_expr.expr) { + ResultLocPeer *peer_result = create_peer_result(loop_scope->peer_parent); + loop_scope->peer_parent->peers.append(peer_result); + + result_value = ir_gen_node_extra(irb, node->data.break_expr.expr, break_scope, + loop_scope->lval, &peer_result->base); + if (result_value == irb->codegen->invalid_inst_src) + return irb->codegen->invalid_inst_src; + } else { + result_value = ir_build_const_void(irb, break_scope, node); + } + + IrBasicBlockSrc *dest_block = loop_scope->break_block; + if (!ir_gen_defers_for_block(irb, break_scope, dest_block->scope, nullptr, nullptr)) + return irb->codegen->invalid_inst_src; + + loop_scope->incoming_blocks->append(irb->current_basic_block); + loop_scope->incoming_values->append(result_value); + return ir_build_br(irb, break_scope, node, dest_block, is_comptime); +} + +static IrInstSrc *ir_gen_continue(IrBuilderSrc *irb, Scope *continue_scope, AstNode *node) { + assert(node->type == NodeTypeContinue); + + // Search up the scope. We'll find one of these things first: + // * function definition scope or global scope => error, break outside loop + // * defer expression scope => error, cannot break out of defer expression + // * loop scope => OK + + ZigList runtime_scopes = {}; + + Scope *search_scope = continue_scope; + ScopeLoop *loop_scope; + for (;;) { + if (search_scope == nullptr || search_scope->id == ScopeIdFnDef) { + if (node->data.continue_expr.name != nullptr) { + add_node_error(irb->codegen, node, buf_sprintf("labeled loop not found: '%s'", buf_ptr(node->data.continue_expr.name))); + return irb->codegen->invalid_inst_src; + } else { + add_node_error(irb->codegen, node, buf_sprintf("continue expression outside loop")); + return irb->codegen->invalid_inst_src; + } + } else if (search_scope->id == ScopeIdDeferExpr) { + add_node_error(irb->codegen, node, buf_sprintf("cannot continue out of defer expression")); + return irb->codegen->invalid_inst_src; + } else if (search_scope->id == ScopeIdLoop) { + ScopeLoop *this_loop_scope = (ScopeLoop *)search_scope; + if (node->data.continue_expr.name == nullptr || + (this_loop_scope->name != nullptr && buf_eql_buf(node->data.continue_expr.name, this_loop_scope->name))) + { + this_loop_scope->name_used = true; + loop_scope = this_loop_scope; + break; + } + } else if (search_scope->id == ScopeIdRuntime) { + ScopeRuntime *scope_runtime = (ScopeRuntime *)search_scope; + runtime_scopes.append(scope_runtime); + } + search_scope = search_scope->parent; + } + + IrInstSrc *is_comptime; + if (ir_should_inline(irb->exec, continue_scope)) { + is_comptime = ir_build_const_bool(irb, continue_scope, node, true); + } else { + is_comptime = loop_scope->is_comptime; + } + + for (size_t i = 0; i < runtime_scopes.length; i += 1) { + ScopeRuntime *scope_runtime = runtime_scopes.at(i); + ir_mark_gen(ir_build_check_runtime_scope(irb, continue_scope, node, scope_runtime->is_comptime, is_comptime)); + } + runtime_scopes.deinit(); + + IrBasicBlockSrc *dest_block = loop_scope->continue_block; + if (!ir_gen_defers_for_block(irb, continue_scope, dest_block->scope, nullptr, nullptr)) + return irb->codegen->invalid_inst_src; + return ir_mark_gen(ir_build_br(irb, continue_scope, node, dest_block, is_comptime)); +} + +static IrInstSrc *ir_gen_error_type(IrBuilderSrc *irb, Scope *scope, AstNode *node) { + assert(node->type == NodeTypeErrorType); + return ir_build_const_type(irb, scope, node, irb->codegen->builtin_types.entry_global_error_set); +} + +static IrInstSrc *ir_gen_defer(IrBuilderSrc *irb, Scope *parent_scope, AstNode *node) { + assert(node->type == NodeTypeDefer); + + ScopeDefer *defer_child_scope = create_defer_scope(irb->codegen, node, parent_scope); + node->data.defer.child_scope = &defer_child_scope->base; + + ScopeDeferExpr *defer_expr_scope = create_defer_expr_scope(irb->codegen, node, parent_scope); + node->data.defer.expr_scope = &defer_expr_scope->base; + + return ir_build_const_void(irb, parent_scope, node); +} + +static IrInstSrc *ir_gen_slice(IrBuilderSrc *irb, Scope *scope, AstNode *node, LVal lval, ResultLoc *result_loc) { + assert(node->type == NodeTypeSliceExpr); + + AstNodeSliceExpr *slice_expr = &node->data.slice_expr; + AstNode *array_node = slice_expr->array_ref_expr; + AstNode *start_node = slice_expr->start; + AstNode *end_node = slice_expr->end; + AstNode *sentinel_node = slice_expr->sentinel; + + IrInstSrc *ptr_value = ir_gen_node_extra(irb, array_node, scope, LValPtr, nullptr); + if (ptr_value == irb->codegen->invalid_inst_src) + return irb->codegen->invalid_inst_src; + + IrInstSrc *start_value = ir_gen_node(irb, start_node, scope); + if (start_value == irb->codegen->invalid_inst_src) + return irb->codegen->invalid_inst_src; + + IrInstSrc *end_value; + if (end_node) { + end_value = ir_gen_node(irb, end_node, scope); + if (end_value == irb->codegen->invalid_inst_src) + return irb->codegen->invalid_inst_src; + } else { + end_value = nullptr; + } + + IrInstSrc *sentinel_value; + if (sentinel_node) { + sentinel_value = ir_gen_node(irb, sentinel_node, scope); + if (sentinel_value == irb->codegen->invalid_inst_src) + return irb->codegen->invalid_inst_src; + } else { + sentinel_value = nullptr; + } + + IrInstSrc *slice = ir_build_slice_src(irb, scope, node, ptr_value, start_value, end_value, + sentinel_value, true, result_loc); + return ir_lval_wrap(irb, scope, slice, lval, result_loc); +} + +static IrInstSrc *ir_gen_catch(IrBuilderSrc *irb, Scope *parent_scope, AstNode *node, LVal lval, + ResultLoc *result_loc) +{ + assert(node->type == NodeTypeCatchExpr); + + AstNode *op1_node = node->data.unwrap_err_expr.op1; + AstNode *op2_node = node->data.unwrap_err_expr.op2; + AstNode *var_node = node->data.unwrap_err_expr.symbol; + + if (op2_node->type == NodeTypeUnreachable) { + if (var_node != nullptr) { + assert(var_node->type == NodeTypeIdentifier); + Buf *var_name = node_identifier_buf(var_node); + add_node_error(irb->codegen, var_node, buf_sprintf("unused variable: '%s'", buf_ptr(var_name))); + return irb->codegen->invalid_inst_src; + } + return ir_gen_catch_unreachable(irb, parent_scope, node, op1_node, lval, result_loc); + } + + + ScopeExpr *spill_scope = create_expr_scope(irb->codegen, op1_node, parent_scope); + spill_scope->spill_harder = true; + + IrInstSrc *err_union_ptr = ir_gen_node_extra(irb, op1_node, &spill_scope->base, LValPtr, nullptr); + if (err_union_ptr == irb->codegen->invalid_inst_src) + return irb->codegen->invalid_inst_src; + + IrInstSrc *is_err = ir_build_test_err_src(irb, parent_scope, node, err_union_ptr, true, false); + + IrInstSrc *is_comptime; + if (ir_should_inline(irb->exec, parent_scope)) { + is_comptime = ir_build_const_bool(irb, parent_scope, node, true); + } else { + is_comptime = ir_build_test_comptime(irb, parent_scope, node, is_err); + } + + IrBasicBlockSrc *ok_block = ir_create_basic_block(irb, parent_scope, "UnwrapErrOk"); + IrBasicBlockSrc *err_block = ir_create_basic_block(irb, parent_scope, "UnwrapErrError"); + IrBasicBlockSrc *end_block = ir_create_basic_block(irb, parent_scope, "UnwrapErrEnd"); + IrInstSrc *cond_br_inst = ir_build_cond_br(irb, parent_scope, node, is_err, err_block, ok_block, is_comptime); + + ResultLocPeerParent *peer_parent = ir_build_binary_result_peers(irb, cond_br_inst, ok_block, end_block, result_loc, + is_comptime); + + ir_set_cursor_at_end_and_append_block(irb, err_block); + Scope *subexpr_scope = create_runtime_scope(irb->codegen, node, &spill_scope->base, is_comptime); + Scope *err_scope; + if (var_node) { + assert(var_node->type == NodeTypeIdentifier); + Buf *var_name = node_identifier_buf(var_node); + bool is_const = true; + bool is_shadowable = false; + ZigVar *var = ir_create_var(irb, node, subexpr_scope, var_name, + is_const, is_const, is_shadowable, is_comptime); + err_scope = var->child_scope; + IrInstSrc *err_ptr = ir_build_unwrap_err_code_src(irb, err_scope, node, err_union_ptr); + IrInstSrc *err_value = ir_build_load_ptr(irb, err_scope, var_node, err_ptr); + build_decl_var_and_init(irb, err_scope, var_node, var, err_value, buf_ptr(var_name), is_comptime); + } else { + err_scope = subexpr_scope; + } + IrInstSrc *err_result = ir_gen_node_extra(irb, op2_node, err_scope, LValNone, &peer_parent->peers.at(0)->base); + if (err_result == irb->codegen->invalid_inst_src) + return irb->codegen->invalid_inst_src; + IrBasicBlockSrc *after_err_block = irb->current_basic_block; + if (!instr_is_unreachable(err_result)) + ir_mark_gen(ir_build_br(irb, parent_scope, node, end_block, is_comptime)); + + ir_set_cursor_at_end_and_append_block(irb, ok_block); + IrInstSrc *unwrapped_ptr = ir_build_unwrap_err_payload_src(irb, parent_scope, node, err_union_ptr, false, false); + IrInstSrc *unwrapped_payload = ir_build_load_ptr(irb, parent_scope, node, unwrapped_ptr); + ir_build_end_expr(irb, parent_scope, node, unwrapped_payload, &peer_parent->peers.at(1)->base); + IrBasicBlockSrc *after_ok_block = irb->current_basic_block; + ir_build_br(irb, parent_scope, node, end_block, is_comptime); + + ir_set_cursor_at_end_and_append_block(irb, end_block); + IrInstSrc **incoming_values = heap::c_allocator.allocate(2); + incoming_values[0] = err_result; + incoming_values[1] = unwrapped_payload; + IrBasicBlockSrc **incoming_blocks = heap::c_allocator.allocate(2); + incoming_blocks[0] = after_err_block; + incoming_blocks[1] = after_ok_block; + IrInstSrc *phi = ir_build_phi(irb, parent_scope, node, 2, incoming_blocks, incoming_values, peer_parent); + return ir_lval_wrap(irb, parent_scope, phi, lval, result_loc); +} + +static bool render_instance_name_recursive(CodeGen *codegen, Buf *name, Scope *outer_scope, Scope *inner_scope) { + if (inner_scope == nullptr || inner_scope == outer_scope) return false; + bool need_comma = render_instance_name_recursive(codegen, name, outer_scope, inner_scope->parent); + if (inner_scope->id != ScopeIdVarDecl) + return need_comma; + + ScopeVarDecl *var_scope = (ScopeVarDecl *)inner_scope; + if (need_comma) + buf_append_char(name, ','); + // TODO: const ptr reinterpret here to make the var type agree with the value? + render_const_value(codegen, name, var_scope->var->const_value); + return true; +} + +Buf *get_anon_type_name(CodeGen *codegen, IrExecutableSrc *exec, const char *kind_name, + Scope *scope, AstNode *source_node, Buf *out_bare_name) +{ + if (exec != nullptr && exec->name) { + ZigType *import = get_scope_import(scope); + Buf *namespace_name = buf_alloc(); + append_namespace_qualification(codegen, namespace_name, import); + buf_append_buf(namespace_name, exec->name); + buf_init_from_buf(out_bare_name, exec->name); + return namespace_name; + } else if (exec != nullptr && exec->name_fn != nullptr) { + Buf *name = buf_alloc(); + buf_append_buf(name, &exec->name_fn->symbol_name); + buf_appendf(name, "("); + render_instance_name_recursive(codegen, name, &exec->name_fn->fndef_scope->base, exec->begin_scope); + buf_appendf(name, ")"); + buf_init_from_buf(out_bare_name, name); + return name; + } else { + ZigType *import = get_scope_import(scope); + Buf *namespace_name = buf_alloc(); + append_namespace_qualification(codegen, namespace_name, import); + RootStruct *root_struct = source_node->owner->data.structure.root_struct; + TokenLoc tok_loc = root_struct->token_locs[source_node->main_token]; + buf_appendf(namespace_name, "%s:%u:%u", kind_name, + tok_loc.line + 1, tok_loc.column + 1); + buf_init_from_buf(out_bare_name, namespace_name); + return namespace_name; + } +} + +static IrInstSrc *ir_gen_container_decl(IrBuilderSrc *irb, Scope *parent_scope, AstNode *node) { + assert(node->type == NodeTypeContainerDecl); + + ContainerKind kind = node->data.container_decl.kind; + Buf *bare_name = buf_alloc(); + Buf *name = get_anon_type_name(irb->codegen, irb->exec, container_string(kind), parent_scope, node, bare_name); + + ContainerLayout layout = node->data.container_decl.layout; + ZigType *container_type = get_partial_container_type(irb->codegen, parent_scope, + kind, node, buf_ptr(name), bare_name, layout); + ScopeDecls *child_scope = get_container_scope(container_type); + + for (size_t i = 0; i < node->data.container_decl.decls.length; i += 1) { + AstNode *child_node = node->data.container_decl.decls.at(i); + scan_decls(irb->codegen, child_scope, child_node); + } + + TldContainer *tld_container = heap::c_allocator.create(); + init_tld(&tld_container->base, TldIdContainer, bare_name, VisibModPub, node, parent_scope); + tld_container->type_entry = container_type; + tld_container->decls_scope = child_scope; + irb->codegen->resolve_queue.append(&tld_container->base); + + // Add this to the list to mark as invalid if analyzing this exec fails. + irb->exec->tld_list.append(&tld_container->base); + + return ir_build_const_type(irb, parent_scope, node, container_type); +} + +static IrInstSrc *ir_gen_err_set_decl(IrBuilderSrc *irb, Scope *parent_scope, AstNode *node) { + assert(node->type == NodeTypeErrorSetDecl); + + uint32_t err_count = node->data.err_set_decl.decls.length; + + Buf bare_name = BUF_INIT; + Buf *type_name = get_anon_type_name(irb->codegen, irb->exec, "error", parent_scope, node, &bare_name); + ZigType *err_set_type = new_type_table_entry(ZigTypeIdErrorSet); + buf_init_from_buf(&err_set_type->name, type_name); + err_set_type->data.error_set.err_count = err_count; + err_set_type->size_in_bits = irb->codegen->builtin_types.entry_global_error_set->size_in_bits; + err_set_type->abi_align = irb->codegen->builtin_types.entry_global_error_set->abi_align; + err_set_type->abi_size = irb->codegen->builtin_types.entry_global_error_set->abi_size; + err_set_type->data.error_set.errors = heap::c_allocator.allocate(err_count); + + size_t errors_count = irb->codegen->errors_by_index.length + err_count; + ErrorTableEntry **errors = heap::c_allocator.allocate(errors_count); + + for (uint32_t i = 0; i < err_count; i += 1) { + AstNode *field_node = node->data.err_set_decl.decls.at(i); + AstNode *symbol_node = ast_field_to_symbol_node(field_node); + Buf *err_name = node_identifier_buf(symbol_node); + ErrorTableEntry *err = heap::c_allocator.create(); + err->decl_node = field_node; + buf_init_from_buf(&err->name, err_name); + + auto existing_entry = irb->codegen->error_table.put_unique(err_name, err); + if (existing_entry) { + err->value = existing_entry->value->value; + } else { + size_t error_value_count = irb->codegen->errors_by_index.length; + assert((uint32_t)error_value_count < (((uint32_t)1) << (uint32_t)irb->codegen->err_tag_type->data.integral.bit_count)); + err->value = error_value_count; + irb->codegen->errors_by_index.append(err); + } + err_set_type->data.error_set.errors[i] = err; + + ErrorTableEntry *prev_err = errors[err->value]; + if (prev_err != nullptr) { + ErrorMsg *msg = add_node_error(irb->codegen, ast_field_to_symbol_node(err->decl_node), + buf_sprintf("duplicate error: '%s'", buf_ptr(&err->name))); + add_error_note(irb->codegen, msg, ast_field_to_symbol_node(prev_err->decl_node), + buf_sprintf("other error here")); + return irb->codegen->invalid_inst_src; + } + errors[err->value] = err; + } + heap::c_allocator.deallocate(errors, errors_count); + return ir_build_const_type(irb, parent_scope, node, err_set_type); +} + +static IrInstSrc *ir_gen_fn_proto(IrBuilderSrc *irb, Scope *parent_scope, AstNode *node) { + assert(node->type == NodeTypeFnProto); + + size_t param_count = node->data.fn_proto.params.length; + IrInstSrc **param_types = heap::c_allocator.allocate(param_count); + + bool is_var_args = false; + for (size_t i = 0; i < param_count; i += 1) { + AstNode *param_node = node->data.fn_proto.params.at(i); + if (param_node->data.param_decl.is_var_args) { + is_var_args = true; + break; + } + if (param_node->data.param_decl.anytype_token == 0) { + AstNode *type_node = param_node->data.param_decl.type; + IrInstSrc *type_value = ir_gen_node(irb, type_node, parent_scope); + if (type_value == irb->codegen->invalid_inst_src) + return irb->codegen->invalid_inst_src; + param_types[i] = type_value; + } else { + param_types[i] = nullptr; + } + } + + IrInstSrc *align_value = nullptr; + if (node->data.fn_proto.align_expr != nullptr) { + align_value = ir_gen_node(irb, node->data.fn_proto.align_expr, parent_scope); + if (align_value == irb->codegen->invalid_inst_src) + return irb->codegen->invalid_inst_src; + } + + IrInstSrc *callconv_value = nullptr; + if (node->data.fn_proto.callconv_expr != nullptr) { + callconv_value = ir_gen_node(irb, node->data.fn_proto.callconv_expr, parent_scope); + if (callconv_value == irb->codegen->invalid_inst_src) + return irb->codegen->invalid_inst_src; + } + + IrInstSrc *return_type; + if (node->data.fn_proto.return_type == nullptr) { + return_type = ir_build_const_type(irb, parent_scope, node, irb->codegen->builtin_types.entry_void); + } else { + return_type = ir_gen_node(irb, node->data.fn_proto.return_type, parent_scope); + if (return_type == irb->codegen->invalid_inst_src) + return irb->codegen->invalid_inst_src; + } + + return ir_build_fn_proto(irb, parent_scope, node, param_types, align_value, callconv_value, return_type, is_var_args); +} + +static IrInstSrc *ir_gen_resume(IrBuilderSrc *irb, Scope *scope, AstNode *node) { + assert(node->type == NodeTypeResume); + + IrInstSrc *target_inst = ir_gen_node_extra(irb, node->data.resume_expr.expr, scope, LValPtr, nullptr); + if (target_inst == irb->codegen->invalid_inst_src) + return irb->codegen->invalid_inst_src; + + return ir_build_resume_src(irb, scope, node, target_inst); +} + +static IrInstSrc *ir_gen_await_expr(IrBuilderSrc *irb, Scope *scope, AstNode *node, LVal lval, + ResultLoc *result_loc) +{ + assert(node->type == NodeTypeAwaitExpr); + + bool is_nosuspend = get_scope_nosuspend(scope) != nullptr; + + AstNode *expr_node = node->data.await_expr.expr; + if (expr_node->type == NodeTypeFnCallExpr && expr_node->data.fn_call_expr.modifier == CallModifierBuiltin) { + AstNode *fn_ref_expr = expr_node->data.fn_call_expr.fn_ref_expr; + Buf *name = node_identifier_buf(fn_ref_expr); + auto entry = irb->codegen->builtin_fn_table.maybe_get(name); + if (entry != nullptr) { + BuiltinFnEntry *builtin_fn = entry->value; + if (builtin_fn->id == BuiltinFnIdAsyncCall) { + return ir_gen_async_call(irb, scope, node, expr_node, lval, result_loc); + } + } + } + + ZigFn *fn_entry = exec_fn_entry(irb->exec); + if (!fn_entry) { + add_node_error(irb->codegen, node, buf_sprintf("await outside function definition")); + return irb->codegen->invalid_inst_src; + } + ScopeSuspend *existing_suspend_scope = get_scope_suspend(scope); + if (existing_suspend_scope) { + if (!existing_suspend_scope->reported_err) { + ErrorMsg *msg = add_node_error(irb->codegen, node, buf_sprintf("cannot await inside suspend block")); + add_error_note(irb->codegen, msg, existing_suspend_scope->base.source_node, buf_sprintf("suspend block here")); + existing_suspend_scope->reported_err = true; + } + return irb->codegen->invalid_inst_src; + } + + IrInstSrc *target_inst = ir_gen_node_extra(irb, expr_node, scope, LValPtr, nullptr); + if (target_inst == irb->codegen->invalid_inst_src) + return irb->codegen->invalid_inst_src; + + IrInstSrc *await_inst = ir_build_await_src(irb, scope, node, target_inst, result_loc, is_nosuspend); + return ir_lval_wrap(irb, scope, await_inst, lval, result_loc); +} + +static IrInstSrc *ir_gen_suspend(IrBuilderSrc *irb, Scope *parent_scope, AstNode *node) { + assert(node->type == NodeTypeSuspend); + + ZigFn *fn_entry = exec_fn_entry(irb->exec); + if (!fn_entry) { + add_node_error(irb->codegen, node, buf_sprintf("suspend outside function definition")); + return irb->codegen->invalid_inst_src; + } + if (get_scope_nosuspend(parent_scope) != nullptr) { + add_node_error(irb->codegen, node, buf_sprintf("suspend in nosuspend scope")); + return irb->codegen->invalid_inst_src; + } + + ScopeSuspend *existing_suspend_scope = get_scope_suspend(parent_scope); + if (existing_suspend_scope) { + if (!existing_suspend_scope->reported_err) { + ErrorMsg *msg = add_node_error(irb->codegen, node, buf_sprintf("cannot suspend inside suspend block")); + add_error_note(irb->codegen, msg, existing_suspend_scope->base.source_node, buf_sprintf("other suspend block here")); + existing_suspend_scope->reported_err = true; + } + return irb->codegen->invalid_inst_src; + } + + IrInstSrcSuspendBegin *begin = ir_build_suspend_begin_src(irb, parent_scope, node); + ScopeSuspend *suspend_scope = create_suspend_scope(irb->codegen, node, parent_scope); + Scope *child_scope = &suspend_scope->base; + IrInstSrc *susp_res = ir_gen_node(irb, node->data.suspend.block, child_scope); + if (susp_res == irb->codegen->invalid_inst_src) + return irb->codegen->invalid_inst_src; + ir_mark_gen(ir_build_check_statement_is_void(irb, child_scope, node->data.suspend.block, susp_res)); + + return ir_mark_gen(ir_build_suspend_finish_src(irb, parent_scope, node, begin)); +} + +static IrInstSrc *ir_gen_node_raw(IrBuilderSrc *irb, AstNode *node, Scope *scope, + LVal lval, ResultLoc *result_loc) +{ + assert(scope); + switch (node->type) { + case NodeTypeStructValueField: + case NodeTypeParamDecl: + case NodeTypeUsingNamespace: + case NodeTypeSwitchProng: + case NodeTypeSwitchRange: + case NodeTypeStructField: + case NodeTypeErrorSetField: + case NodeTypeFnDef: + case NodeTypeTestDecl: + zig_unreachable(); + case NodeTypeBlock: + return ir_gen_block(irb, scope, node, lval, result_loc); + case NodeTypeGroupedExpr: + return ir_gen_node_raw(irb, node->data.grouped_expr, scope, lval, result_loc); + case NodeTypeBinOpExpr: + return ir_gen_bin_op(irb, scope, node, lval, result_loc); + case NodeTypeIntLiteral: + return ir_lval_wrap(irb, scope, ir_gen_int_lit(irb, scope, node), lval, result_loc); + case NodeTypeFloatLiteral: + return ir_lval_wrap(irb, scope, ir_gen_float_lit(irb, scope, node), lval, result_loc); + case NodeTypeCharLiteral: + return ir_lval_wrap(irb, scope, ir_gen_char_lit(irb, scope, node), lval, result_loc); + case NodeTypeIdentifier: + return ir_gen_symbol(irb, scope, node, lval, result_loc); + case NodeTypeFnCallExpr: + return ir_gen_fn_call(irb, scope, node, lval, result_loc); + case NodeTypeIfBoolExpr: + return ir_gen_if_bool_expr(irb, scope, node, lval, result_loc); + case NodeTypePrefixOpExpr: + return ir_gen_prefix_op_expr(irb, scope, node, lval, result_loc); + case NodeTypeContainerInitExpr: + return ir_gen_container_init_expr(irb, scope, node, lval, result_loc); + case NodeTypeVariableDeclaration: + return ir_gen_var_decl(irb, scope, node); + case NodeTypeWhileExpr: + return ir_gen_while_expr(irb, scope, node, lval, result_loc); + case NodeTypeForExpr: + return ir_gen_for_expr(irb, scope, node, lval, result_loc); + case NodeTypeArrayAccessExpr: + return ir_gen_array_access(irb, scope, node, lval, result_loc); + case NodeTypeReturnExpr: + return ir_gen_return(irb, scope, node, lval, result_loc); + case NodeTypeFieldAccessExpr: + { + IrInstSrc *ptr_instruction = ir_gen_field_access(irb, scope, node); + if (ptr_instruction == irb->codegen->invalid_inst_src) + return ptr_instruction; + if (lval == LValPtr || lval == LValAssign) + return ptr_instruction; + + IrInstSrc *load_ptr = ir_build_load_ptr(irb, scope, node, ptr_instruction); + return ir_expr_wrap(irb, scope, load_ptr, result_loc); + } + case NodeTypePtrDeref: { + AstNode *expr_node = node->data.ptr_deref_expr.target; + + LVal child_lval = lval; + if (child_lval == LValAssign) + child_lval = LValPtr; + + IrInstSrc *value = ir_gen_node_extra(irb, expr_node, scope, child_lval, nullptr); + if (value == irb->codegen->invalid_inst_src) + return value; + + // We essentially just converted any lvalue from &(x.*) to (&x).*; + // this inhibits checking that x is a pointer later, so we directly + // record whether the pointer check is needed + IrInstSrc *un_op = ir_build_un_op_lval(irb, scope, node, IrUnOpDereference, value, lval, result_loc); + return ir_expr_wrap(irb, scope, un_op, result_loc); + } + case NodeTypeUnwrapOptional: { + AstNode *expr_node = node->data.unwrap_optional.expr; + + IrInstSrc *maybe_ptr = ir_gen_node_extra(irb, expr_node, scope, LValPtr, nullptr); + if (maybe_ptr == irb->codegen->invalid_inst_src) + return irb->codegen->invalid_inst_src; + + IrInstSrc *unwrapped_ptr = ir_build_optional_unwrap_ptr(irb, scope, node, maybe_ptr, true ); + if (lval == LValPtr || lval == LValAssign) + return unwrapped_ptr; + + IrInstSrc *load_ptr = ir_build_load_ptr(irb, scope, node, unwrapped_ptr); + return ir_expr_wrap(irb, scope, load_ptr, result_loc); + } + case NodeTypeBoolLiteral: + return ir_lval_wrap(irb, scope, ir_gen_bool_literal(irb, scope, node), lval, result_loc); + case NodeTypeArrayType: + return ir_lval_wrap(irb, scope, ir_gen_array_type(irb, scope, node), lval, result_loc); + case NodeTypePointerType: + return ir_lval_wrap(irb, scope, ir_gen_pointer_type(irb, scope, node), lval, result_loc); + case NodeTypeAnyFrameType: + return ir_lval_wrap(irb, scope, ir_gen_anyframe_type(irb, scope, node), lval, result_loc); + case NodeTypeStringLiteral: + return ir_lval_wrap(irb, scope, ir_gen_string_literal(irb, scope, node), lval, result_loc); + case NodeTypeUndefinedLiteral: + return ir_lval_wrap(irb, scope, ir_gen_undefined_literal(irb, scope, node), lval, result_loc); + case NodeTypeAsmExpr: + return ir_lval_wrap(irb, scope, ir_gen_asm_expr(irb, scope, node), lval, result_loc); + case NodeTypeNullLiteral: + return ir_lval_wrap(irb, scope, ir_gen_null_literal(irb, scope, node), lval, result_loc); + case NodeTypeIfErrorExpr: + return ir_gen_if_err_expr(irb, scope, node, lval, result_loc); + case NodeTypeIfOptional: + return ir_gen_if_optional_expr(irb, scope, node, lval, result_loc); + case NodeTypeSwitchExpr: + return ir_gen_switch_expr(irb, scope, node, lval, result_loc); + case NodeTypeCompTime: + return ir_expr_wrap(irb, scope, ir_gen_comptime(irb, scope, node, lval), result_loc); + case NodeTypeNoSuspend: + return ir_expr_wrap(irb, scope, ir_gen_nosuspend(irb, scope, node, lval), result_loc); + case NodeTypeErrorType: + return ir_lval_wrap(irb, scope, ir_gen_error_type(irb, scope, node), lval, result_loc); + case NodeTypeBreak: + return ir_lval_wrap(irb, scope, ir_gen_break(irb, scope, node), lval, result_loc); + case NodeTypeContinue: + return ir_lval_wrap(irb, scope, ir_gen_continue(irb, scope, node), lval, result_loc); + case NodeTypeUnreachable: + return ir_build_unreachable(irb, scope, node); + case NodeTypeDefer: + return ir_lval_wrap(irb, scope, ir_gen_defer(irb, scope, node), lval, result_loc); + case NodeTypeSliceExpr: + return ir_gen_slice(irb, scope, node, lval, result_loc); + case NodeTypeCatchExpr: + return ir_gen_catch(irb, scope, node, lval, result_loc); + case NodeTypeContainerDecl: + return ir_lval_wrap(irb, scope, ir_gen_container_decl(irb, scope, node), lval, result_loc); + case NodeTypeFnProto: + return ir_lval_wrap(irb, scope, ir_gen_fn_proto(irb, scope, node), lval, result_loc); + case NodeTypeErrorSetDecl: + return ir_lval_wrap(irb, scope, ir_gen_err_set_decl(irb, scope, node), lval, result_loc); + case NodeTypeResume: + return ir_lval_wrap(irb, scope, ir_gen_resume(irb, scope, node), lval, result_loc); + case NodeTypeAwaitExpr: + return ir_gen_await_expr(irb, scope, node, lval, result_loc); + case NodeTypeSuspend: + return ir_lval_wrap(irb, scope, ir_gen_suspend(irb, scope, node), lval, result_loc); + case NodeTypeEnumLiteral: + return ir_lval_wrap(irb, scope, ir_gen_enum_literal(irb, scope, node), lval, result_loc); + case NodeTypeInferredArrayType: + add_node_error(irb->codegen, node, + buf_sprintf("inferred array size invalid here")); + return irb->codegen->invalid_inst_src; + case NodeTypeAnyTypeField: + return ir_lval_wrap(irb, scope, + ir_build_const_type(irb, scope, node, irb->codegen->builtin_types.entry_anytype), lval, result_loc); + } + zig_unreachable(); +} + +ResultLoc *no_result_loc(void) { + ResultLocNone *result_loc_none = heap::c_allocator.create(); + result_loc_none->base.id = ResultLocIdNone; + return &result_loc_none->base; +} + +static IrInstSrc *ir_gen_node_extra(IrBuilderSrc *irb, AstNode *node, Scope *scope, LVal lval, + ResultLoc *result_loc) +{ + if (lval == LValAssign) { + switch (node->type) { + case NodeTypeStructValueField: + case NodeTypeParamDecl: + case NodeTypeUsingNamespace: + case NodeTypeSwitchProng: + case NodeTypeSwitchRange: + case NodeTypeStructField: + case NodeTypeErrorSetField: + case NodeTypeFnDef: + case NodeTypeTestDecl: + zig_unreachable(); + + // cannot be assigned to + case NodeTypeBlock: + case NodeTypeGroupedExpr: + case NodeTypeBinOpExpr: + case NodeTypeIntLiteral: + case NodeTypeFloatLiteral: + case NodeTypeCharLiteral: + case NodeTypeIfBoolExpr: + case NodeTypeContainerInitExpr: + case NodeTypeVariableDeclaration: + case NodeTypeWhileExpr: + case NodeTypeForExpr: + case NodeTypeReturnExpr: + case NodeTypeBoolLiteral: + case NodeTypeArrayType: + case NodeTypePointerType: + case NodeTypeAnyFrameType: + case NodeTypeStringLiteral: + case NodeTypeUndefinedLiteral: + case NodeTypeAsmExpr: + case NodeTypeNullLiteral: + case NodeTypeIfErrorExpr: + case NodeTypeIfOptional: + case NodeTypeSwitchExpr: + case NodeTypeCompTime: + case NodeTypeNoSuspend: + case NodeTypeErrorType: + case NodeTypeBreak: + case NodeTypeContinue: + case NodeTypeUnreachable: + case NodeTypeDefer: + case NodeTypeSliceExpr: + case NodeTypeCatchExpr: + case NodeTypeContainerDecl: + case NodeTypeFnProto: + case NodeTypeErrorSetDecl: + case NodeTypeResume: + case NodeTypeAwaitExpr: + case NodeTypeSuspend: + case NodeTypeEnumLiteral: + case NodeTypeInferredArrayType: + case NodeTypeAnyTypeField: + case NodeTypePrefixOpExpr: + add_node_error(irb->codegen, node, + buf_sprintf("invalid left-hand side to assignment")); + return irb->codegen->invalid_inst_src; + + // @field can be assigned to + case NodeTypeFnCallExpr: + if (node->data.fn_call_expr.modifier == CallModifierBuiltin) { + AstNode *fn_ref_expr = node->data.fn_call_expr.fn_ref_expr; + Buf *name = node_identifier_buf(fn_ref_expr); + auto entry = irb->codegen->builtin_fn_table.maybe_get(name); + + if (!entry) { + add_node_error(irb->codegen, node, + buf_sprintf("invalid builtin function: '%s'", buf_ptr(name))); + return irb->codegen->invalid_inst_src; + } + + if (entry->value->id == BuiltinFnIdField) { + break; + } + } + add_node_error(irb->codegen, node, + buf_sprintf("invalid left-hand side to assignment")); + return irb->codegen->invalid_inst_src; + + + // can be assigned to + case NodeTypeUnwrapOptional: + case NodeTypePtrDeref: + case NodeTypeFieldAccessExpr: + case NodeTypeArrayAccessExpr: + case NodeTypeIdentifier: + break; + } + } + if (result_loc == nullptr) { + // Create a result location indicating there is none - but if one gets created + // it will be properly distributed. + result_loc = no_result_loc(); + ir_build_reset_result(irb, scope, node, result_loc); + } + Scope *child_scope; + if (irb->exec->is_inline || + (irb->exec->fn_entry != nullptr && irb->exec->fn_entry->child_scope == scope)) + { + child_scope = scope; + } else { + child_scope = &create_expr_scope(irb->codegen, node, scope)->base; + } + IrInstSrc *result = ir_gen_node_raw(irb, node, child_scope, lval, result_loc); + if (result == irb->codegen->invalid_inst_src) { + if (irb->exec->first_err_trace_msg == nullptr) { + irb->exec->first_err_trace_msg = irb->codegen->trace_err; + } + } + return result; +} + +static IrInstSrc *ir_gen_node(IrBuilderSrc *irb, AstNode *node, Scope *scope) { + return ir_gen_node_extra(irb, node, scope, LValNone, nullptr); +} + +bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutableSrc *ir_executable) { + assert(node->owner); + + IrBuilderSrc ir_builder = {0}; + IrBuilderSrc *irb = &ir_builder; + + irb->codegen = codegen; + irb->exec = ir_executable; + irb->main_block_node = node; + + IrBasicBlockSrc *entry_block = ir_create_basic_block(irb, scope, "Entry"); + ir_set_cursor_at_end_and_append_block(irb, entry_block); + // Entry block gets a reference because we enter it to begin. + ir_ref_bb(irb->current_basic_block); + + IrInstSrc *result = ir_gen_node_extra(irb, node, scope, LValNone, nullptr); + + if (result == irb->codegen->invalid_inst_src) + return false; + + if (irb->exec->first_err_trace_msg != nullptr) { + codegen->trace_err = irb->exec->first_err_trace_msg; + return false; + } + + if (!instr_is_unreachable(result)) { + ir_mark_gen(ir_build_add_implicit_return_type(irb, scope, result->base.source_node, result, nullptr)); + // no need for save_err_ret_addr because this cannot return error + ResultLocReturn *result_loc_ret = heap::c_allocator.create(); + result_loc_ret->base.id = ResultLocIdReturn; + ir_build_reset_result(irb, scope, node, &result_loc_ret->base); + ir_mark_gen(ir_build_end_expr(irb, scope, node, result, &result_loc_ret->base)); + ir_mark_gen(ir_build_return_src(irb, scope, result->base.source_node, result)); + } + + return true; +} + +bool ir_gen_fn(CodeGen *codegen, ZigFn *fn_entry) { + assert(fn_entry); + + IrExecutableSrc *ir_executable = fn_entry->ir_executable; + AstNode *body_node = fn_entry->body_node; + + assert(fn_entry->child_scope); + + return ir_gen(codegen, body_node, fn_entry->child_scope, ir_executable); +} + +void invalidate_exec(IrExecutableSrc *exec, ErrorMsg *msg) { + if (exec->first_err_trace_msg != nullptr) + return; + + exec->first_err_trace_msg = msg; + + for (size_t i = 0; i < exec->tld_list.length; i += 1) { + exec->tld_list.items[i]->resolution = TldResolutionInvalid; + } +} + +AstNode *ast_field_to_symbol_node(AstNode *err_set_field_node) { + if (err_set_field_node->type == NodeTypeIdentifier) { + return err_set_field_node; + } else if (err_set_field_node->type == NodeTypeErrorSetField) { + assert(err_set_field_node->data.err_set_field.field_name->type == NodeTypeIdentifier); + return err_set_field_node->data.err_set_field.field_name; + } else { + return err_set_field_node; + } +} + +void ir_add_call_stack_errors_gen(CodeGen *codegen, IrExecutableGen *exec, ErrorMsg *err_msg, int limit) { + if (!exec || !exec->source_node || limit < 0) return; + add_error_note(codegen, err_msg, exec->source_node, buf_sprintf("called from here")); + + ir_add_call_stack_errors_gen(codegen, exec->parent_exec, err_msg, limit - 1); +} + diff --git a/src/stage1/astgen.hpp b/src/stage1/astgen.hpp new file mode 100644 index 0000000000..c3750aac98 --- /dev/null +++ b/src/stage1/astgen.hpp @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2021 Andrew Kelley + * + * This file is part of zig, which is MIT licensed. + * See http://opensource.org/licenses/MIT + */ + +#ifndef ZIG_ASTGEN_HPP +#define ZIG_ASTGEN_HPP + +#include "all_types.hpp" + +bool ir_gen(CodeGen *g, AstNode *node, Scope *scope, IrExecutableSrc *ir_executable); +bool ir_gen_fn(CodeGen *g, ZigFn *fn_entry); + +bool ir_inst_src_has_side_effects(IrInstSrc *inst); + +ZigVar *create_local_var(CodeGen *codegen, AstNode *node, Scope *parent_scope, + Buf *name, bool src_is_const, bool gen_is_const, bool is_shadowable, IrInstSrc *is_comptime, + bool skip_name_check); + +ResultLoc *no_result_loc(void); + +void invalidate_exec(IrExecutableSrc *exec, ErrorMsg *msg); + +AstNode *ast_field_to_symbol_node(AstNode *err_set_field_node); +void ir_add_call_stack_errors_gen(CodeGen *codegen, IrExecutableGen *exec, ErrorMsg *err_msg, + int limit); + +void destroy_instruction_src(IrInstSrc *inst); + +struct IrBuilderSrc { + CodeGen *codegen; + IrExecutableSrc *exec; + IrBasicBlockSrc *current_basic_block; + AstNode *main_block_node; +}; + +bool ir_should_inline(IrExecutableSrc *exec, Scope *scope); +Buf *get_anon_type_name(CodeGen *codegen, IrExecutableSrc *exec, const char *kind_name, + Scope *scope, AstNode *source_node, Buf *out_bare_name); + +#endif diff --git a/src/stage1/bigfloat.cpp b/src/stage1/bigfloat.cpp index 840cdccc8b..56bf2637e3 100644 --- a/src/stage1/bigfloat.cpp +++ b/src/stage1/bigfloat.cpp @@ -69,7 +69,7 @@ void bigfloat_init_bigint(BigFloat *dest, const BigInt *op) { } } -Error bigfloat_init_buf(BigFloat *dest, const uint8_t *buf_ptr, size_t buf_len) { +Error bigfloat_init_buf(BigFloat *dest, const uint8_t *buf_ptr) { char *str_begin = (char *)buf_ptr; char *str_end; @@ -79,7 +79,6 @@ Error bigfloat_init_buf(BigFloat *dest, const uint8_t *buf_ptr, size_t buf_len) return ErrorOverflow; } - assert(str_end <= ((char*)buf_ptr) + buf_len); return ErrorNone; } diff --git a/src/stage1/bigfloat.hpp b/src/stage1/bigfloat.hpp index 3ed6624fdc..52e92d20f4 100644 --- a/src/stage1/bigfloat.hpp +++ b/src/stage1/bigfloat.hpp @@ -28,7 +28,7 @@ void bigfloat_init_64(BigFloat *dest, double x); void bigfloat_init_128(BigFloat *dest, float128_t x); void bigfloat_init_bigfloat(BigFloat *dest, const BigFloat *x); void bigfloat_init_bigint(BigFloat *dest, const BigInt *op); -Error bigfloat_init_buf(BigFloat *dest, const uint8_t *buf_ptr, size_t buf_len); +Error bigfloat_init_buf(BigFloat *dest, const uint8_t *buf_ptr); float16_t bigfloat_to_f16(const BigFloat *bigfloat); float bigfloat_to_f32(const BigFloat *bigfloat); diff --git a/src/stage1/codegen.cpp b/src/stage1/codegen.cpp index 1a6f047ee1..1dd3aa8d45 100644 --- a/src/stage1/codegen.cpp +++ b/src/stage1/codegen.cpp @@ -6,7 +6,6 @@ */ #include "analyze.hpp" -#include "ast_render.hpp" #include "codegen.hpp" #include "errmsg.hpp" #include "error.hpp" @@ -642,6 +641,18 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, ZigFn *fn) { return fn->llvm_value; } +static uint32_t node_line_onebased(AstNode *node) { + RootStruct *root_struct = node->owner->data.structure.root_struct; + assert(node->main_token < root_struct->token_count); + return root_struct->token_locs[node->main_token].line + 1; +} + +static uint32_t node_column_onebased(AstNode *node) { + RootStruct *root_struct = node->owner->data.structure.root_struct; + assert(node->main_token < root_struct->token_count); + return root_struct->token_locs[node->main_token].column + 1; +} + static ZigLLVMDIScope *get_di_scope(CodeGen *g, Scope *scope) { if (scope->di_scope) return scope->di_scope; @@ -657,8 +668,7 @@ static ZigLLVMDIScope *get_di_scope(CodeGen *g, Scope *scope) { ZigFn *fn_table_entry = fn_scope->fn_entry; if (!fn_table_entry->proto_node) return get_di_scope(g, scope->parent); - unsigned line_number = (unsigned)(fn_table_entry->proto_node->line == 0) ? - 0 : (fn_table_entry->proto_node->line + 1); + unsigned line_number = node_line_onebased(fn_table_entry->proto_node); unsigned scope_line = line_number; bool is_definition = fn_table_entry->body_node != nullptr; bool is_optimized = g->build_mode != BuildModeDebug; @@ -696,8 +706,8 @@ static ZigLLVMDIScope *get_di_scope(CodeGen *g, Scope *scope) { ZigLLVMDILexicalBlock *di_block = ZigLLVMCreateLexicalBlock(g->dbuilder, get_di_scope(g, scope->parent), import->data.structure.root_struct->di_file, - (unsigned)scope->source_node->line + 1, - (unsigned)scope->source_node->column + 1); + node_line_onebased(scope->source_node), + node_column_onebased(scope->source_node)); scope->di_scope = ZigLLVMLexicalBlockToScope(di_block); return scope->di_scope; } @@ -1798,8 +1808,8 @@ static void gen_var_debug_decl(CodeGen *g, ZigVar *var) { if (g->strip_debug_symbols) return; assert(var->di_loc_var != nullptr); AstNode *source_node = var->decl_node; - ZigLLVMDILocation *debug_loc = ZigLLVMGetDebugLoc((unsigned)source_node->line + 1, - (unsigned)source_node->column + 1, get_di_scope(g, var->parent_scope)); + ZigLLVMDILocation *debug_loc = ZigLLVMGetDebugLoc(node_line_onebased(source_node), + node_column_onebased(source_node), get_di_scope(g, var->parent_scope)); ZigLLVMInsertDeclareAtEnd(g->dbuilder, var->value_ref, var->di_loc_var, debug_loc, LLVMGetInsertBlock(g->builder)); } @@ -2198,7 +2208,7 @@ var_ok: // arg index + 1 because the 0 index is return value var->di_loc_var = ZigLLVMCreateParameterVariable(g->dbuilder, get_di_scope(g, var->parent_scope), var->name, fn_walk->data.vars.import->data.structure.root_struct->di_file, - (unsigned)(var->decl_node->line + 1), + node_line_onebased(var->decl_node), get_llvm_di_type(g, dest_ty), !g->strip_debug_symbols, 0, di_arg_index + 1); } return true; @@ -4126,7 +4136,7 @@ static void render_async_spills(CodeGen *g) { if (var->decl_node) { var->di_loc_var = ZigLLVMCreateAutoVariable(g->dbuilder, get_di_scope(g, var->parent_scope), var->name, import->data.structure.root_struct->di_file, - (unsigned)(var->decl_node->line + 1), + node_line_onebased(var->decl_node), get_llvm_di_type(g, var->var_type), !g->strip_debug_symbols, 0); gen_var_debug_decl(g, var); } @@ -6797,8 +6807,8 @@ static void set_debug_location(CodeGen *g, IrInstGen *instruction) { assert(source_node); assert(scope); - ZigLLVMSetCurrentDebugLocation(g->builder, (int)source_node->line + 1, - (int)source_node->column + 1, get_di_scope(g, scope)); + ZigLLVMSetCurrentDebugLocation(g->builder, node_line_onebased(source_node), + node_column_onebased(source_node), get_di_scope(g, scope)); } static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutableGen *executable, IrInstGen *instruction) { @@ -8021,7 +8031,7 @@ static void gen_global_var(CodeGen *g, ZigVar *var, LLVMValueRef init_val, bool is_local_to_unit = true; ZigLLVMCreateGlobalVariable(g->dbuilder, get_di_scope(g, var->parent_scope), var->name, var->name, import->data.structure.root_struct->di_file, - (unsigned)(var->decl_node->line + 1), + node_line_onebased(var->decl_node), get_llvm_di_type(g, type_entry), is_local_to_unit); // TODO ^^ make an actual global variable @@ -8296,7 +8306,8 @@ static void do_code_gen(CodeGen *g) { if (var->src_arg_index == SIZE_MAX) { var->di_loc_var = ZigLLVMCreateAutoVariable(g->dbuilder, get_di_scope(g, var->parent_scope), - var->name, import->data.structure.root_struct->di_file, (unsigned)(var->decl_node->line + 1), + var->name, import->data.structure.root_struct->di_file, + node_line_onebased(var->decl_node), get_llvm_di_type(g, var->var_type), !g->strip_debug_symbols, 0); } else if (is_c_abi) { @@ -8321,7 +8332,7 @@ static void do_code_gen(CodeGen *g) { if (var->decl_node) { var->di_loc_var = ZigLLVMCreateParameterVariable(g->dbuilder, get_di_scope(g, var->parent_scope), var->name, import->data.structure.root_struct->di_file, - (unsigned)(var->decl_node->line + 1), + node_line_onebased(var->decl_node), get_llvm_di_type(g, gen_type), !g->strip_debug_symbols, 0, (unsigned)(gen_info->gen_index+1)); } @@ -8365,8 +8376,9 @@ static void do_code_gen(CodeGen *g) { if (!g->strip_debug_symbols) { AstNode *source_node = fn_table_entry->proto_node; - ZigLLVMSetCurrentDebugLocation(g->builder, (int)source_node->line + 1, - (int)source_node->column + 1, get_di_scope(g, fn_table_entry->child_scope)); + ZigLLVMSetCurrentDebugLocation(g->builder, + node_line_onebased(source_node), node_column_onebased(source_node), + get_di_scope(g, fn_table_entry->child_scope)); } IrExecutableGen *executable = &fn_table_entry->analyzed_executable; LLVMBasicBlockRef bad_resume_block = LLVMAppendBasicBlock(g->cur_fn_val, "BadResume"); diff --git a/src/stage1/dump_analysis.cpp b/src/stage1/dump_analysis.cpp index 69a797bdaf..15cd7c2874 100644 --- a/src/stage1/dump_analysis.cpp +++ b/src/stage1/dump_analysis.cpp @@ -1084,19 +1084,43 @@ static void anal_dump_type(AnalDumpCtx *ctx, ZigType *ty) { jw_end_object(jw); } +static Buf *collect_doc_comments(RootStruct *root_struct, TokenIndex first_token) { + if (first_token == 0) + return nullptr; + + TokenId *token_ids = root_struct->token_ids; + TokenLoc *token_locs = root_struct->token_locs; + Buf *str = buf_alloc(); + const char *source = buf_ptr(root_struct->source_code); + TokenIndex doc_token = first_token; + for (;token_ids[doc_token] == TokenIdDocComment; doc_token += 1) { + // chops off '///' but leaves '\n' + uint32_t start_pos = token_locs[doc_token].offset; + uint32_t token_len = 0; + while (source[start_pos + token_len] != '\n' && + source[start_pos + token_len] != 0) + { + token_len += 1; + } + buf_append_mem(str, source + start_pos + 3, token_len - 3); + } + return str; +} + static void anal_dump_node(AnalDumpCtx *ctx, const AstNode *node) { JsonWriter *jw = &ctx->jw; jw_begin_object(jw); jw_object_field(jw, "file"); - anal_dump_file_ref(ctx, node->owner->data.structure.root_struct->path); + RootStruct *root_struct = node->owner->data.structure.root_struct; + anal_dump_file_ref(ctx, root_struct->path); jw_object_field(jw, "line"); - jw_int(jw, node->line); + jw_int(jw, root_struct->token_locs[node->main_token].line); jw_object_field(jw, "col"); - jw_int(jw, node->column); + jw_int(jw, root_struct->token_locs[node->main_token].column); const Buf *doc_comments_buf = nullptr; const Buf *name_buf = nullptr; @@ -1107,30 +1131,30 @@ static void anal_dump_node(AnalDumpCtx *ctx, const AstNode *node) { switch (node->type) { case NodeTypeParamDecl: - doc_comments_buf = &node->data.param_decl.doc_comments; + doc_comments_buf = collect_doc_comments(root_struct, node->data.param_decl.doc_comments); name_buf = node->data.param_decl.name; is_var_args = node->data.param_decl.is_var_args; is_noalias = node->data.param_decl.is_noalias; is_comptime = node->data.param_decl.is_comptime; break; case NodeTypeFnProto: - doc_comments_buf = &node->data.fn_proto.doc_comments; + doc_comments_buf = collect_doc_comments(root_struct, node->data.fn_proto.doc_comments); field_nodes = &node->data.fn_proto.params; is_var_args = node->data.fn_proto.is_var_args; break; case NodeTypeVariableDeclaration: - doc_comments_buf = &node->data.variable_declaration.doc_comments; + doc_comments_buf = collect_doc_comments(root_struct, node->data.variable_declaration.doc_comments); break; case NodeTypeErrorSetField: - doc_comments_buf = &node->data.err_set_field.doc_comments; + doc_comments_buf = collect_doc_comments(root_struct, node->data.err_set_field.doc_comments); break; case NodeTypeStructField: - doc_comments_buf = &node->data.struct_field.doc_comments; + doc_comments_buf = collect_doc_comments(root_struct, node->data.struct_field.doc_comments); name_buf = node->data.struct_field.name; break; case NodeTypeContainerDecl: field_nodes = &node->data.container_decl.fields; - doc_comments_buf = &node->data.container_decl.doc_comments; + doc_comments_buf = collect_doc_comments(root_struct, node->data.container_decl.doc_comments); break; default: break; diff --git a/src/stage1/errmsg.cpp b/src/stage1/errmsg.cpp index 7bf096547f..e04d39fe88 100644 --- a/src/stage1/errmsg.cpp +++ b/src/stage1/errmsg.cpp @@ -96,14 +96,14 @@ void err_msg_add_note(ErrorMsg *parent, ErrorMsg *note) { parent->notes.append(note); } -ErrorMsg *err_msg_create_with_offset(Buf *path, size_t line, size_t column, size_t offset, - const char *source, Buf *msg) +ErrorMsg *err_msg_create_with_offset(Buf *path, uint32_t byte_offset, const char *source, + Buf *msg) { ErrorMsg *err_msg = heap::c_allocator.create(); err_msg->path = path; - err_msg->line_start = line; - err_msg->column_start = column; err_msg->msg = msg; + err_msg->line_start = 0; + err_msg->column_start = 0; if (source == nullptr) { // Must initialize the buffer anyway @@ -111,46 +111,25 @@ ErrorMsg *err_msg_create_with_offset(Buf *path, size_t line, size_t column, size return err_msg; } - size_t line_start_offset = offset; - for (;;) { - if (line_start_offset == 0) { - break; - } - - line_start_offset -= 1; - - if (source[line_start_offset] == '\n') { - line_start_offset += 1; - break; + size_t line_start = 0; + size_t i = 0; + for (;i < byte_offset; i += 1) { + switch (source[i]) { + case '\n': + err_msg->line_start += 1; + err_msg->column_start = 0; + line_start = i + 1; + continue; + default: + err_msg->column_start += 1; + continue; } } - - size_t line_end_offset = offset; - while (source[line_end_offset] && source[line_end_offset] != '\n') { - line_end_offset += 1; + while (source[i] != '\n' && source[i] != 0) { + i += 1; } - buf_init_from_mem(&err_msg->line_buf, source + line_start_offset, line_end_offset - line_start_offset); - - return err_msg; -} - -ErrorMsg *err_msg_create_with_line(Buf *path, size_t line, size_t column, - Buf *source, ZigList *line_offsets, Buf *msg) -{ - ErrorMsg *err_msg = heap::c_allocator.create(); - err_msg->path = path; - err_msg->line_start = line; - err_msg->column_start = column; - err_msg->msg = msg; - - size_t line_start_offset = line_offsets->at(line); - size_t end_line = line + 1; - size_t line_end_offset = (end_line >= line_offsets->length) ? buf_len(source) : line_offsets->at(line + 1); - size_t len = (line_end_offset + 1 > line_start_offset) ? (line_end_offset - line_start_offset - 1) : 0; - if (len == SIZE_MAX) len = 0; - - buf_init_from_mem(&err_msg->line_buf, buf_ptr(source) + line_start_offset, len); + buf_init_from_mem(&err_msg->line_buf, source + line_start, i - line_start); return err_msg; } diff --git a/src/stage1/errmsg.hpp b/src/stage1/errmsg.hpp index 73cbd4e0d9..b8b6b3e7f2 100644 --- a/src/stage1/errmsg.hpp +++ b/src/stage1/errmsg.hpp @@ -25,10 +25,6 @@ struct ErrorMsg { void print_err_msg(ErrorMsg *msg, ErrColor color); void err_msg_add_note(ErrorMsg *parent, ErrorMsg *note); -ErrorMsg *err_msg_create_with_offset(Buf *path, size_t line, size_t column, size_t offset, - const char *source, Buf *msg); - -ErrorMsg *err_msg_create_with_line(Buf *path, size_t line, size_t column, - Buf *source, ZigList *line_offsets, Buf *msg); +ErrorMsg *err_msg_create_with_offset(Buf *path, uint32_t byte_offset, const char *source, Buf *msg); #endif diff --git a/src/stage1/error.cpp b/src/stage1/error.cpp index d8bb4ac8a2..e77632e8f2 100644 --- a/src/stage1/error.cpp +++ b/src/stage1/error.cpp @@ -88,6 +88,8 @@ const char *err_str(Error err) { case ErrorZigIsTheCCompiler: return "Zig was not provided with libc installation information, and so it does not know where the libc paths are on the system. Zig attempted to use the system C compiler to find out where the libc paths are, but discovered that Zig is being used as the system C compiler."; case ErrorFileBusy: return "file is busy"; case ErrorLocked: return "file is locked by another process"; + case ErrorInvalidCharacter: return "invalid character"; + case ErrorUnicodePointTooLarge: return "unicode codepoint too large"; } return "(invalid error)"; } diff --git a/src/stage1/ir.cpp b/src/stage1/ir.cpp index 4bd608a687..4070372a12 100644 --- a/src/stage1/ir.cpp +++ b/src/stage1/ir.cpp @@ -5,8 +5,8 @@ * See http://opensource.org/licenses/MIT */ +#include "astgen.hpp" #include "analyze.hpp" -#include "ast_render.hpp" #include "error.hpp" #include "ir.hpp" #include "ir_print.hpp" @@ -22,13 +22,6 @@ #include #include -struct IrBuilderSrc { - CodeGen *codegen; - IrExecutableSrc *exec; - IrBasicBlockSrc *current_basic_block; - AstNode *main_block_node; -}; - struct IrBuilderGen { CodeGen *codegen; IrExecutableGen *exec; @@ -216,27 +209,18 @@ struct DbgIrBreakPoint { const char *src_file; uint32_t line; }; -DbgIrBreakPoint dbg_ir_breakpoints_buf[20]; -size_t dbg_ir_breakpoints_count = 0; -static IrInstSrc *ir_gen_node(IrBuilderSrc *irb, AstNode *node, Scope *scope); -static IrInstSrc *ir_gen_node_extra(IrBuilderSrc *irb, AstNode *node, Scope *scope, LVal lval, - ResultLoc *result_loc); static IrInstGen *ir_implicit_cast(IrAnalyze *ira, IrInstGen *value, ZigType *expected_type); static IrInstGen *ir_implicit_cast2(IrAnalyze *ira, IrInst *value_source_instr, IrInstGen *value, ZigType *expected_type); static IrInstGen *ir_get_deref(IrAnalyze *ira, IrInst *source_instr, IrInstGen *ptr, ResultLoc *result_loc); -static ErrorMsg *exec_add_error_node(CodeGen *codegen, IrExecutableSrc *exec, AstNode *source_node, Buf *msg); static IrInstGen *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_name, IrInst* source_instr, IrInstGen *container_ptr, IrInst *container_ptr_src, ZigType *container_type, bool initializing); -static void ir_assert_impl(bool ok, IrInst* source_instruction, const char *file, unsigned int line); static void ir_assert_gen_impl(bool ok, IrInstGen *source_instruction, const char *file, unsigned int line); static IrInstGen *ir_get_var_ptr(IrAnalyze *ira, IrInst *source_instr, ZigVar *var); static ZigType *ir_resolve_atomic_operand_type(IrAnalyze *ira, IrInstGen *op); -static IrInstSrc *ir_lval_wrap(IrBuilderSrc *irb, Scope *scope, IrInstSrc *value, LVal lval, ResultLoc *result_loc); -static IrInstSrc *ir_expr_wrap(IrBuilderSrc *irb, Scope *scope, IrInstSrc *inst, ResultLoc *result_loc); static ZigType *adjust_ptr_align(CodeGen *g, ZigType *ptr_type, uint32_t new_align); static ZigType *adjust_ptr_const(CodeGen *g, ZigType *ptr_type, bool is_const); static ZigType *adjust_slice_align(CodeGen *g, ZigType *slice_type, uint32_t new_align); @@ -265,26 +249,14 @@ static IrInstGen *ir_analyze_unwrap_err_code(IrAnalyze *ira, IrInst* source_inst IrInstGen *base_ptr, bool initializing); static IrInstGen *ir_analyze_store_ptr(IrAnalyze *ira, IrInst* source_instr, IrInstGen *ptr, IrInstGen *uncasted_value, bool allow_write_through_const); -static IrInstSrc *ir_gen_union_init_expr(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, - IrInstSrc *union_type, IrInstSrc *field_name, AstNode *expr_node, - LVal lval, ResultLoc *parent_result_loc); static void ir_reset_result(ResultLoc *result_loc); -static Buf *get_anon_type_name(CodeGen *codegen, IrExecutableSrc *exec, const char *kind_name, - Scope *scope, AstNode *source_node, Buf *out_bare_name); -static ResultLocCast *ir_build_cast_result_loc(IrBuilderSrc *irb, IrInstSrc *dest_type, - ResultLoc *parent_result_loc); static IrInstGen *ir_analyze_struct_field_ptr(IrAnalyze *ira, IrInst* source_instr, TypeStructField *field, IrInstGen *struct_ptr, ZigType *struct_type, bool initializing); static IrInstGen *ir_analyze_inferred_field_ptr(IrAnalyze *ira, Buf *field_name, IrInst* source_instr, IrInstGen *container_ptr, ZigType *container_type); -static ResultLoc *no_result_loc(void); static IrInstGen *ir_analyze_test_non_null(IrAnalyze *ira, IrInst *source_inst, IrInstGen *value); static IrInstGen *ir_error_dependency_loop(IrAnalyze *ira, IrInst *source_instr); static IrInstGen *ir_const_undef(IrAnalyze *ira, IrInst *source_instruction, ZigType *ty); -static ZigVar *ir_create_var(IrBuilderSrc *irb, AstNode *node, Scope *scope, Buf *name, - bool src_is_const, bool gen_is_const, bool is_shadowable, IrInstSrc *is_comptime); -static void build_decl_var_and_init(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, ZigVar *var, - IrInstSrc *init, const char *name_hint, IrInstSrc *is_comptime); static IrInstGen *ir_analyze_union_init(IrAnalyze *ira, IrInst* source_instruction, AstNode *field_source_node, ZigType *union_type, Buf *field_name, IrInstGen *field_result_loc, IrInstGen *result_loc); @@ -295,292 +267,15 @@ static bool value_cmp_numeric_val_all(ZigValue *left, Cmp predicate, ZigValue *r static void memoize_field_init_val(CodeGen *codegen, ZigType *container_type, TypeStructField *field); static void value_to_bigfloat(BigFloat *out, ZigValue *val); +static void ir_assert_impl(bool ok, IrInst *source_instruction, char const *file, unsigned int line) { + if (ok) return; + src_assert_impl(ok, source_instruction->source_node, file, line); +} + + #define ir_assert(OK, SOURCE_INSTRUCTION) ir_assert_impl((OK), (SOURCE_INSTRUCTION), __FILE__, __LINE__) #define ir_assert_gen(OK, SOURCE_INSTRUCTION) ir_assert_gen_impl((OK), (SOURCE_INSTRUCTION), __FILE__, __LINE__) -static void destroy_instruction_src(IrInstSrc *inst) { - switch (inst->id) { - case IrInstSrcIdInvalid: - zig_unreachable(); - case IrInstSrcIdReturn: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdConst: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdBinOp: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdMergeErrSets: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdDeclVar: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdCall: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdCallExtra: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdAsyncCallExtra: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdUnOp: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdCondBr: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdBr: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdPhi: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdContainerInitList: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdContainerInitFields: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdUnreachable: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdElemPtr: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdVarPtr: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdLoadPtr: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdStorePtr: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdTypeOf: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdFieldPtr: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdSetCold: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdSetRuntimeSafety: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdSetFloatMode: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdArrayType: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdSliceType: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdAnyFrameType: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdAsm: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdSizeOf: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdTestNonNull: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdOptionalUnwrapPtr: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdPopCount: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdClz: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdCtz: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdBswap: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdBitReverse: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdSwitchBr: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdSwitchVar: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdSwitchElseVar: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdSwitchTarget: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdImport: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdRef: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdCompileErr: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdCompileLog: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdErrName: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdCImport: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdCInclude: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdCDefine: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdCUndef: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdEmbedFile: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdCmpxchg: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdFence: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdReduce: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdTruncate: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdIntCast: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdFloatCast: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdErrSetCast: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdIntToFloat: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdFloatToInt: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdBoolToInt: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdVectorType: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdShuffleVector: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdSplat: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdBoolNot: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdMemset: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdMemcpy: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdSlice: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdBreakpoint: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdReturnAddress: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdFrameAddress: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdFrameHandle: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdFrameType: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdFrameSize: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdAlignOf: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdOverflowOp: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdTestErr: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdUnwrapErrCode: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdUnwrapErrPayload: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdFnProto: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdTestComptime: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdPtrCast: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdBitCast: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdPtrToInt: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdIntToPtr: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdIntToEnum: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdIntToErr: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdErrToInt: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdCheckSwitchProngsUnderNo: - case IrInstSrcIdCheckSwitchProngsUnderYes: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdCheckStatementIsVoid: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdTypeName: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdTagName: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdPtrType: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdPtrTypeSimple: - case IrInstSrcIdPtrTypeSimpleConst: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdDeclRef: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdPanic: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdFieldParentPtr: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdByteOffsetOf: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdBitOffsetOf: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdTypeInfo: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdType: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdHasField: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdSetEvalBranchQuota: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdAlignCast: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdImplicitCast: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdResolveResult: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdResetResult: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdSetAlignStack: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdArgTypeAllowVarFalse: - case IrInstSrcIdArgTypeAllowVarTrue: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdExport: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdExtern: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdErrorReturnTrace: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdErrorUnion: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdAtomicRmw: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdSaveErrRetAddr: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdAddImplicitReturnType: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdFloatOp: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdMulAdd: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdAtomicLoad: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdAtomicStore: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdEnumToInt: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdCheckRuntimeScope: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdHasDecl: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdUndeclaredIdent: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdAlloca: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdEndExpr: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdUnionInitNamedField: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdSuspendBegin: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdSuspendFinish: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdResume: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdAwait: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdSpillBegin: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdSpillEnd: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdCallArgs: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdWasmMemorySize: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdWasmMemoryGrow: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - case IrInstSrcIdSrc: - return heap::c_allocator.destroy(reinterpret_cast(inst)); - } - zig_unreachable(); -} - void destroy_instruction_gen(IrInstGen *inst) { switch (inst->id) { case IrInstGenIdInvalid: @@ -970,54 +665,18 @@ static bool types_have_same_zig_comptime_repr(CodeGen *codegen, ZigType *expecte zig_unreachable(); } -static bool ir_should_inline(IrExecutableSrc *exec, Scope *scope) { - if (exec->is_inline) - return true; - - while (scope != nullptr) { - if (scope->id == ScopeIdCompTime) - return true; - if (scope->id == ScopeIdTypeOf) - return false; - if (scope->id == ScopeIdFnDef) - break; - scope = scope->parent; - } - return false; -} - -static void ir_instruction_append(IrBasicBlockSrc *basic_block, IrInstSrc *instruction) { - assert(basic_block); - assert(instruction); - basic_block->instruction_list.append(instruction); -} - static void ir_inst_gen_append(IrBasicBlockGen *basic_block, IrInstGen *instruction) { assert(basic_block); assert(instruction); basic_block->instruction_list.append(instruction); } -static size_t exec_next_debug_id(IrExecutableSrc *exec) { - size_t result = exec->next_debug_id; - exec->next_debug_id += 1; - return result; -} - static size_t exec_next_debug_id_gen(IrExecutableGen *exec) { size_t result = exec->next_debug_id; exec->next_debug_id += 1; return result; } -static ZigFn *exec_fn_entry(IrExecutableSrc *exec) { - return exec->fn_entry; -} - -static Buf *exec_c_import_buf(IrExecutableSrc *exec) { - return exec->c_import_buf; -} - static bool value_is_comptime(ZigValue *const_val) { return const_val->special != ConstValSpecialRuntime; } @@ -1026,33 +685,11 @@ static bool instr_is_comptime(IrInstGen *instruction) { return value_is_comptime(instruction->value); } -static bool instr_is_unreachable(IrInstSrc *instruction) { - return instruction->is_noreturn; -} - -static void ir_ref_bb(IrBasicBlockSrc *bb) { - bb->ref_count += 1; -} - -static void ir_ref_instruction(IrInstSrc *instruction, IrBasicBlockSrc *cur_bb) { - assert(instruction->id != IrInstSrcIdInvalid); - instruction->base.ref_count += 1; - if (instruction->owner_bb != cur_bb && !instr_is_unreachable(instruction) - && instruction->id != IrInstSrcIdConst) - { - ir_ref_bb(instruction->owner_bb); - } -} - static void ir_ref_inst_gen(IrInstGen *instruction) { assert(instruction->id != IrInstGenIdInvalid); instruction->base.ref_count += 1; } -static void ir_ref_var(ZigVar *var) { - var->ref_count += 1; -} - static void create_result_ptr(CodeGen *codegen, ZigType *expected_type, ZigValue **out_result, ZigValue **out_result_ptr) { @@ -1092,15 +729,6 @@ ZigType *ir_analyze_type_expr(IrAnalyze *ira, Scope *scope, AstNode *node) { return res_type; } -static IrBasicBlockSrc *ir_create_basic_block(IrBuilderSrc *irb, Scope *scope, const char *name_hint) { - IrBasicBlockSrc *result = heap::c_allocator.create(); - result->scope = scope; - result->name_hint = name_hint; - result->debug_id = exec_next_debug_id(irb->exec); - result->index = UINT32_MAX; // set later - return result; -} - static IrBasicBlockGen *ir_create_basic_block_gen(IrAnalyze *ira, Scope *scope, const char *name_hint) { IrBasicBlockGen *result = heap::c_allocator.create(); result->scope = scope; @@ -1115,538 +743,6 @@ static IrBasicBlockGen *ir_build_bb_from(IrAnalyze *ira, IrBasicBlockSrc *other_ return new_bb; } -static constexpr IrInstSrcId ir_inst_id(IrInstSrcDeclVar *) { - return IrInstSrcIdDeclVar; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcBr *) { - return IrInstSrcIdBr; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcCondBr *) { - return IrInstSrcIdCondBr; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcSwitchBr *) { - return IrInstSrcIdSwitchBr; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcSwitchVar *) { - return IrInstSrcIdSwitchVar; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcSwitchElseVar *) { - return IrInstSrcIdSwitchElseVar; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcSwitchTarget *) { - return IrInstSrcIdSwitchTarget; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcPhi *) { - return IrInstSrcIdPhi; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcUnOp *) { - return IrInstSrcIdUnOp; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcBinOp *) { - return IrInstSrcIdBinOp; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcMergeErrSets *) { - return IrInstSrcIdMergeErrSets; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcLoadPtr *) { - return IrInstSrcIdLoadPtr; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcStorePtr *) { - return IrInstSrcIdStorePtr; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcFieldPtr *) { - return IrInstSrcIdFieldPtr; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcElemPtr *) { - return IrInstSrcIdElemPtr; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcVarPtr *) { - return IrInstSrcIdVarPtr; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcCall *) { - return IrInstSrcIdCall; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcCallArgs *) { - return IrInstSrcIdCallArgs; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcCallExtra *) { - return IrInstSrcIdCallExtra; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcAsyncCallExtra *) { - return IrInstSrcIdAsyncCallExtra; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcConst *) { - return IrInstSrcIdConst; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcReturn *) { - return IrInstSrcIdReturn; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcContainerInitList *) { - return IrInstSrcIdContainerInitList; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcContainerInitFields *) { - return IrInstSrcIdContainerInitFields; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcUnreachable *) { - return IrInstSrcIdUnreachable; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcTypeOf *) { - return IrInstSrcIdTypeOf; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcSetCold *) { - return IrInstSrcIdSetCold; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcSetRuntimeSafety *) { - return IrInstSrcIdSetRuntimeSafety; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcSetFloatMode *) { - return IrInstSrcIdSetFloatMode; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcArrayType *) { - return IrInstSrcIdArrayType; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcAnyFrameType *) { - return IrInstSrcIdAnyFrameType; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcSliceType *) { - return IrInstSrcIdSliceType; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcAsm *) { - return IrInstSrcIdAsm; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcSizeOf *) { - return IrInstSrcIdSizeOf; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcTestNonNull *) { - return IrInstSrcIdTestNonNull; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcOptionalUnwrapPtr *) { - return IrInstSrcIdOptionalUnwrapPtr; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcClz *) { - return IrInstSrcIdClz; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcCtz *) { - return IrInstSrcIdCtz; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcPopCount *) { - return IrInstSrcIdPopCount; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcBswap *) { - return IrInstSrcIdBswap; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcBitReverse *) { - return IrInstSrcIdBitReverse; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcImport *) { - return IrInstSrcIdImport; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcCImport *) { - return IrInstSrcIdCImport; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcCInclude *) { - return IrInstSrcIdCInclude; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcCDefine *) { - return IrInstSrcIdCDefine; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcCUndef *) { - return IrInstSrcIdCUndef; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcRef *) { - return IrInstSrcIdRef; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcCompileErr *) { - return IrInstSrcIdCompileErr; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcCompileLog *) { - return IrInstSrcIdCompileLog; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcErrName *) { - return IrInstSrcIdErrName; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcEmbedFile *) { - return IrInstSrcIdEmbedFile; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcCmpxchg *) { - return IrInstSrcIdCmpxchg; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcFence *) { - return IrInstSrcIdFence; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcReduce *) { - return IrInstSrcIdReduce; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcTruncate *) { - return IrInstSrcIdTruncate; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcIntCast *) { - return IrInstSrcIdIntCast; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcFloatCast *) { - return IrInstSrcIdFloatCast; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcIntToFloat *) { - return IrInstSrcIdIntToFloat; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcFloatToInt *) { - return IrInstSrcIdFloatToInt; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcBoolToInt *) { - return IrInstSrcIdBoolToInt; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcVectorType *) { - return IrInstSrcIdVectorType; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcShuffleVector *) { - return IrInstSrcIdShuffleVector; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcSplat *) { - return IrInstSrcIdSplat; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcBoolNot *) { - return IrInstSrcIdBoolNot; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcMemset *) { - return IrInstSrcIdMemset; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcMemcpy *) { - return IrInstSrcIdMemcpy; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcSlice *) { - return IrInstSrcIdSlice; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcBreakpoint *) { - return IrInstSrcIdBreakpoint; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcReturnAddress *) { - return IrInstSrcIdReturnAddress; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcFrameAddress *) { - return IrInstSrcIdFrameAddress; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcFrameHandle *) { - return IrInstSrcIdFrameHandle; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcFrameType *) { - return IrInstSrcIdFrameType; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcFrameSize *) { - return IrInstSrcIdFrameSize; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcAlignOf *) { - return IrInstSrcIdAlignOf; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcOverflowOp *) { - return IrInstSrcIdOverflowOp; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcTestErr *) { - return IrInstSrcIdTestErr; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcMulAdd *) { - return IrInstSrcIdMulAdd; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcFloatOp *) { - return IrInstSrcIdFloatOp; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcUnwrapErrCode *) { - return IrInstSrcIdUnwrapErrCode; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcUnwrapErrPayload *) { - return IrInstSrcIdUnwrapErrPayload; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcFnProto *) { - return IrInstSrcIdFnProto; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcTestComptime *) { - return IrInstSrcIdTestComptime; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcPtrCast *) { - return IrInstSrcIdPtrCast; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcBitCast *) { - return IrInstSrcIdBitCast; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcIntToPtr *) { - return IrInstSrcIdIntToPtr; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcPtrToInt *) { - return IrInstSrcIdPtrToInt; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcIntToEnum *) { - return IrInstSrcIdIntToEnum; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcEnumToInt *) { - return IrInstSrcIdEnumToInt; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcIntToErr *) { - return IrInstSrcIdIntToErr; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcErrToInt *) { - return IrInstSrcIdErrToInt; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcCheckStatementIsVoid *) { - return IrInstSrcIdCheckStatementIsVoid; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcTypeName *) { - return IrInstSrcIdTypeName; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcDeclRef *) { - return IrInstSrcIdDeclRef; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcPanic *) { - return IrInstSrcIdPanic; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcTagName *) { - return IrInstSrcIdTagName; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcFieldParentPtr *) { - return IrInstSrcIdFieldParentPtr; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcByteOffsetOf *) { - return IrInstSrcIdByteOffsetOf; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcBitOffsetOf *) { - return IrInstSrcIdBitOffsetOf; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcTypeInfo *) { - return IrInstSrcIdTypeInfo; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcType *) { - return IrInstSrcIdType; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcHasField *) { - return IrInstSrcIdHasField; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcSetEvalBranchQuota *) { - return IrInstSrcIdSetEvalBranchQuota; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcPtrType *) { - return IrInstSrcIdPtrType; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcAlignCast *) { - return IrInstSrcIdAlignCast; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcImplicitCast *) { - return IrInstSrcIdImplicitCast; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcResolveResult *) { - return IrInstSrcIdResolveResult; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcResetResult *) { - return IrInstSrcIdResetResult; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcSetAlignStack *) { - return IrInstSrcIdSetAlignStack; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcExport *) { - return IrInstSrcIdExport; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcExtern *) { - return IrInstSrcIdExtern; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcErrorReturnTrace *) { - return IrInstSrcIdErrorReturnTrace; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcErrorUnion *) { - return IrInstSrcIdErrorUnion; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcAtomicRmw *) { - return IrInstSrcIdAtomicRmw; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcAtomicLoad *) { - return IrInstSrcIdAtomicLoad; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcAtomicStore *) { - return IrInstSrcIdAtomicStore; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcSaveErrRetAddr *) { - return IrInstSrcIdSaveErrRetAddr; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcAddImplicitReturnType *) { - return IrInstSrcIdAddImplicitReturnType; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcErrSetCast *) { - return IrInstSrcIdErrSetCast; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcCheckRuntimeScope *) { - return IrInstSrcIdCheckRuntimeScope; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcHasDecl *) { - return IrInstSrcIdHasDecl; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcUndeclaredIdent *) { - return IrInstSrcIdUndeclaredIdent; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcAlloca *) { - return IrInstSrcIdAlloca; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcEndExpr *) { - return IrInstSrcIdEndExpr; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcUnionInitNamedField *) { - return IrInstSrcIdUnionInitNamedField; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcSuspendBegin *) { - return IrInstSrcIdSuspendBegin; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcSuspendFinish *) { - return IrInstSrcIdSuspendFinish; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcAwait *) { - return IrInstSrcIdAwait; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcResume *) { - return IrInstSrcIdResume; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcSpillBegin *) { - return IrInstSrcIdSpillBegin; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcSpillEnd *) { - return IrInstSrcIdSpillEnd; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcWasmMemorySize *) { - return IrInstSrcIdWasmMemorySize; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcWasmMemoryGrow *) { - return IrInstSrcIdWasmMemoryGrow; -} - -static constexpr IrInstSrcId ir_inst_id(IrInstSrcSrc *) { - return IrInstSrcIdSrc; -} - static constexpr IrInstGenId ir_inst_id(IrInstGenDeclVar *) { return IrInstGenIdDeclVar; } @@ -2003,17 +1099,6 @@ static constexpr IrInstGenId ir_inst_id(IrInstGenExtern *) { return IrInstGenIdExtern; } -template -static T *ir_create_instruction(IrBuilderSrc *irb, Scope *scope, AstNode *source_node) { - T *special_instruction = heap::c_allocator.create(); - special_instruction->base.id = ir_inst_id(special_instruction); - special_instruction->base.base.scope = scope; - special_instruction->base.base.source_node = source_node; - special_instruction->base.base.debug_id = exec_next_debug_id(irb->exec); - special_instruction->base.owner_bb = irb->current_basic_block; - return special_instruction; -} - template static T *ir_create_inst_gen(IrBuilderGen *irb, Scope *scope, AstNode *source_node) { T *special_instruction = heap::c_allocator.create(); @@ -2037,13 +1122,6 @@ static T *ir_create_inst_noval(IrBuilderGen *irb, Scope *scope, AstNode *source_ return special_instruction; } -template -static T *ir_build_instruction(IrBuilderSrc *irb, Scope *scope, AstNode *source_node) { - T *special_instruction = ir_create_instruction(irb, scope, source_node); - ir_instruction_append(irb->current_basic_block, &special_instruction->base); - return special_instruction; -} - template static T *ir_build_inst_gen(IrBuilderGen *irb, Scope *scope, AstNode *source_node) { T *special_instruction = ir_create_inst_gen(irb, scope, source_node); @@ -2095,24 +1173,6 @@ static IrInstGen *ir_build_cast(IrAnalyze *ira, IrInst *source_instr,ZigType *de return &inst->base; } -static IrInstSrc *ir_build_cond_br(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrInstSrc *condition, - IrBasicBlockSrc *then_block, IrBasicBlockSrc *else_block, IrInstSrc *is_comptime) -{ - IrInstSrcCondBr *inst = ir_build_instruction(irb, scope, source_node); - inst->base.is_noreturn = true; - inst->condition = condition; - inst->then_block = then_block; - inst->else_block = else_block; - inst->is_comptime = is_comptime; - - ir_ref_instruction(condition, irb->current_basic_block); - ir_ref_bb(then_block); - ir_ref_bb(else_block); - if (is_comptime != nullptr) ir_ref_instruction(is_comptime, irb->current_basic_block); - - return &inst->base; -} - static IrInstGen *ir_build_cond_br_gen(IrAnalyze *ira, IrInst *source_instr, IrInstGen *condition, IrBasicBlockGen *then_block, IrBasicBlockGen *else_block) { @@ -2126,16 +1186,6 @@ static IrInstGen *ir_build_cond_br_gen(IrAnalyze *ira, IrInst *source_instr, IrI return &inst->base; } -static IrInstSrc *ir_build_return_src(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrInstSrc *operand) { - IrInstSrcReturn *inst = ir_build_instruction(irb, scope, source_node); - inst->base.is_noreturn = true; - inst->operand = operand; - - if (operand != nullptr) ir_ref_instruction(operand, irb->current_basic_block); - - return &inst->base; -} - static IrInstGen *ir_build_return_gen(IrAnalyze *ira, IrInst *source_inst, IrInstGen *operand) { IrInstGenReturn *inst = ir_build_inst_noreturn(&ira->new_irb, source_inst->scope, source_inst->source_node); @@ -2146,139 +1196,6 @@ static IrInstGen *ir_build_return_gen(IrAnalyze *ira, IrInst *source_inst, IrIns return &inst->base; } -static IrInstSrc *ir_build_const_void(IrBuilderSrc *irb, Scope *scope, AstNode *source_node) { - IrInstSrcConst *const_instruction = ir_create_instruction(irb, scope, source_node); - ir_instruction_append(irb->current_basic_block, &const_instruction->base); - const_instruction->value = irb->codegen->intern.for_void(); - return &const_instruction->base; -} - -static IrInstSrc *ir_build_const_undefined(IrBuilderSrc *irb, Scope *scope, AstNode *source_node) { - IrInstSrcConst *const_instruction = ir_create_instruction(irb, scope, source_node); - ir_instruction_append(irb->current_basic_block, &const_instruction->base); - const_instruction->value = irb->codegen->intern.for_undefined(); - const_instruction->value->special = ConstValSpecialUndef; - return &const_instruction->base; -} - -static IrInstSrc *ir_build_const_uint(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, uint64_t value) { - IrInstSrcConst *const_instruction = ir_build_instruction(irb, scope, source_node); - const_instruction->value = irb->codegen->pass1_arena->create(); - const_instruction->value->type = irb->codegen->builtin_types.entry_num_lit_int; - const_instruction->value->special = ConstValSpecialStatic; - bigint_init_unsigned(&const_instruction->value->data.x_bigint, value); - return &const_instruction->base; -} - -static IrInstSrc *ir_build_const_bigint(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, BigInt *bigint) { - IrInstSrcConst *const_instruction = ir_build_instruction(irb, scope, source_node); - const_instruction->value = irb->codegen->pass1_arena->create(); - const_instruction->value->type = irb->codegen->builtin_types.entry_num_lit_int; - const_instruction->value->special = ConstValSpecialStatic; - bigint_init_bigint(&const_instruction->value->data.x_bigint, bigint); - return &const_instruction->base; -} - -static IrInstSrc *ir_build_const_bigfloat(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, BigFloat *bigfloat) { - IrInstSrcConst *const_instruction = ir_build_instruction(irb, scope, source_node); - const_instruction->value = irb->codegen->pass1_arena->create(); - const_instruction->value->type = irb->codegen->builtin_types.entry_num_lit_float; - const_instruction->value->special = ConstValSpecialStatic; - bigfloat_init_bigfloat(&const_instruction->value->data.x_bigfloat, bigfloat); - return &const_instruction->base; -} - -static IrInstSrc *ir_build_const_null(IrBuilderSrc *irb, Scope *scope, AstNode *source_node) { - IrInstSrcConst *const_instruction = ir_create_instruction(irb, scope, source_node); - ir_instruction_append(irb->current_basic_block, &const_instruction->base); - const_instruction->value = irb->codegen->intern.for_null(); - return &const_instruction->base; -} - -static IrInstSrc *ir_build_const_usize(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, uint64_t value) { - IrInstSrcConst *const_instruction = ir_build_instruction(irb, scope, source_node); - const_instruction->value = irb->codegen->pass1_arena->create(); - const_instruction->value->type = irb->codegen->builtin_types.entry_usize; - const_instruction->value->special = ConstValSpecialStatic; - bigint_init_unsigned(&const_instruction->value->data.x_bigint, value); - return &const_instruction->base; -} - -static IrInstSrc *ir_create_const_type(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, - ZigType *type_entry) -{ - IrInstSrcConst *const_instruction = ir_create_instruction(irb, scope, source_node); - const_instruction->value = irb->codegen->pass1_arena->create(); - const_instruction->value->type = irb->codegen->builtin_types.entry_type; - const_instruction->value->special = ConstValSpecialStatic; - const_instruction->value->data.x_type = type_entry; - return &const_instruction->base; -} - -static IrInstSrc *ir_build_const_type(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, - ZigType *type_entry) -{ - IrInstSrc *instruction = ir_create_const_type(irb, scope, source_node, type_entry); - ir_instruction_append(irb->current_basic_block, instruction); - return instruction; -} - -static IrInstSrc *ir_build_const_import(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, ZigType *import) { - IrInstSrcConst *const_instruction = ir_build_instruction(irb, scope, source_node); - const_instruction->value = irb->codegen->pass1_arena->create(); - const_instruction->value->type = irb->codegen->builtin_types.entry_type; - const_instruction->value->special = ConstValSpecialStatic; - const_instruction->value->data.x_type = import; - return &const_instruction->base; -} - -static IrInstSrc *ir_build_const_bool(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, bool value) { - IrInstSrcConst *const_instruction = ir_build_instruction(irb, scope, source_node); - const_instruction->value = irb->codegen->pass1_arena->create(); - const_instruction->value->type = irb->codegen->builtin_types.entry_bool; - const_instruction->value->special = ConstValSpecialStatic; - const_instruction->value->data.x_bool = value; - return &const_instruction->base; -} - -static IrInstSrc *ir_build_const_enum_literal(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, Buf *name) { - IrInstSrcConst *const_instruction = ir_build_instruction(irb, scope, source_node); - const_instruction->value = irb->codegen->pass1_arena->create(); - const_instruction->value->type = irb->codegen->builtin_types.entry_enum_literal; - const_instruction->value->special = ConstValSpecialStatic; - const_instruction->value->data.x_enum_literal = name; - return &const_instruction->base; -} - -static IrInstSrc *ir_create_const_str_lit(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, Buf *str) { - IrInstSrcConst *const_instruction = ir_create_instruction(irb, scope, source_node); - const_instruction->value = irb->codegen->pass1_arena->create(); - init_const_str_lit(irb->codegen, const_instruction->value, str); - - return &const_instruction->base; -} - -static IrInstSrc *ir_build_const_str_lit(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, Buf *str) { - IrInstSrc *instruction = ir_create_const_str_lit(irb, scope, source_node, str); - ir_instruction_append(irb->current_basic_block, instruction); - return instruction; -} - -static IrInstSrc *ir_build_bin_op(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrBinOp op_id, - IrInstSrc *op1, IrInstSrc *op2, bool safety_check_on) -{ - IrInstSrcBinOp *inst = ir_build_instruction(irb, scope, source_node); - inst->op_id = op_id; - inst->op1 = op1; - inst->op2 = op2; - inst->safety_check_on = safety_check_on; - - ir_ref_instruction(op1, irb->current_basic_block); - ir_ref_instruction(op2, irb->current_basic_block); - - return &inst->base; -} - static IrInstGen *ir_build_bin_op_gen(IrAnalyze *ira, IrInst *source_instr, ZigType *res_type, IrBinOp op_id, IrInstGen *op1, IrInstGen *op2, bool safety_check_on) { @@ -2297,41 +1214,11 @@ static IrInstGen *ir_build_bin_op_gen(IrAnalyze *ira, IrInst *source_instr, ZigT } -static IrInstSrc *ir_build_merge_err_sets(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, - IrInstSrc *op1, IrInstSrc *op2, Buf *type_name) -{ - IrInstSrcMergeErrSets *inst = ir_build_instruction(irb, scope, source_node); - inst->op1 = op1; - inst->op2 = op2; - inst->type_name = type_name; - - ir_ref_instruction(op1, irb->current_basic_block); - ir_ref_instruction(op2, irb->current_basic_block); - - return &inst->base; -} - -static IrInstSrc *ir_build_var_ptr_x(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, ZigVar *var, - ScopeFnDef *crossed_fndef_scope) -{ - IrInstSrcVarPtr *instruction = ir_build_instruction(irb, scope, source_node); - instruction->var = var; - instruction->crossed_fndef_scope = crossed_fndef_scope; - - ir_ref_var(var); - - return &instruction->base; -} - -static IrInstSrc *ir_build_var_ptr(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, ZigVar *var) { - return ir_build_var_ptr_x(irb, scope, source_node, var, nullptr); -} - static IrInstGen *ir_build_var_ptr_gen(IrAnalyze *ira, IrInst *source_instr, ZigVar *var) { IrInstGenVarPtr *instruction = ir_build_inst_gen(&ira->new_irb, source_instr->scope, source_instr->source_node); instruction->var = var; - ir_ref_var(var); + var->ref_count += 1; return &instruction->base; } @@ -2342,23 +1229,6 @@ static IrInstGen *ir_build_return_ptr(IrAnalyze *ira, Scope *scope, AstNode *sou return &instruction->base; } -static IrInstSrc *ir_build_elem_ptr(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, - IrInstSrc *array_ptr, IrInstSrc *elem_index, bool safety_check_on, PtrLen ptr_len, - AstNode *init_array_type_source_node) -{ - IrInstSrcElemPtr *instruction = ir_build_instruction(irb, scope, source_node); - instruction->array_ptr = array_ptr; - instruction->elem_index = elem_index; - instruction->safety_check_on = safety_check_on; - instruction->ptr_len = ptr_len; - instruction->init_array_type_source_node = init_array_type_source_node; - - ir_ref_instruction(array_ptr, irb->current_basic_block); - ir_ref_instruction(elem_index, irb->current_basic_block); - - return &instruction->base; -} - static IrInstGen *ir_build_elem_ptr_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, IrInstGen *array_ptr, IrInstGen *elem_index, bool safety_check_on, ZigType *return_type) { @@ -2374,48 +1244,6 @@ static IrInstGen *ir_build_elem_ptr_gen(IrAnalyze *ira, Scope *scope, AstNode *s return &instruction->base; } -static IrInstSrc *ir_build_field_ptr_instruction(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, - IrInstSrc *container_ptr, IrInstSrc *field_name_expr, bool initializing) -{ - IrInstSrcFieldPtr *instruction = ir_build_instruction(irb, scope, source_node); - instruction->container_ptr = container_ptr; - instruction->field_name_buffer = nullptr; - instruction->field_name_expr = field_name_expr; - instruction->initializing = initializing; - - ir_ref_instruction(container_ptr, irb->current_basic_block); - ir_ref_instruction(field_name_expr, irb->current_basic_block); - - return &instruction->base; -} - -static IrInstSrc *ir_build_field_ptr(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, - IrInstSrc *container_ptr, Buf *field_name, bool initializing) -{ - IrInstSrcFieldPtr *instruction = ir_build_instruction(irb, scope, source_node); - instruction->container_ptr = container_ptr; - instruction->field_name_buffer = field_name; - instruction->field_name_expr = nullptr; - instruction->initializing = initializing; - - ir_ref_instruction(container_ptr, irb->current_basic_block); - - return &instruction->base; -} - -static IrInstSrc *ir_build_has_field(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, - IrInstSrc *container_type, IrInstSrc *field_name) -{ - IrInstSrcHasField *instruction = ir_build_instruction(irb, scope, source_node); - instruction->container_type = container_type; - instruction->field_name = field_name; - - ir_ref_instruction(container_type, irb->current_basic_block); - ir_ref_instruction(field_name, irb->current_basic_block); - - return &instruction->base; -} - static IrInstGen *ir_build_struct_field_ptr(IrAnalyze *ira, IrInst *source_instr, IrInstGen *struct_ptr, TypeStructField *field, ZigType *ptr_type) { @@ -2445,85 +1273,6 @@ static IrInstGen *ir_build_union_field_ptr(IrAnalyze *ira, IrInst *source_instr, return &inst->base; } -static IrInstSrc *ir_build_call_extra(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, - IrInstSrc *options, IrInstSrc *fn_ref, IrInstSrc *args, ResultLoc *result_loc) -{ - IrInstSrcCallExtra *call_instruction = ir_build_instruction(irb, scope, source_node); - call_instruction->options = options; - call_instruction->fn_ref = fn_ref; - call_instruction->args = args; - call_instruction->result_loc = result_loc; - - ir_ref_instruction(options, irb->current_basic_block); - ir_ref_instruction(fn_ref, irb->current_basic_block); - ir_ref_instruction(args, irb->current_basic_block); - - return &call_instruction->base; -} - -static IrInstSrc *ir_build_async_call_extra(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, - CallModifier modifier, IrInstSrc *fn_ref, IrInstSrc *ret_ptr, IrInstSrc *new_stack, IrInstSrc *args, ResultLoc *result_loc) -{ - IrInstSrcAsyncCallExtra *call_instruction = ir_build_instruction(irb, scope, source_node); - call_instruction->modifier = modifier; - call_instruction->fn_ref = fn_ref; - call_instruction->ret_ptr = ret_ptr; - call_instruction->new_stack = new_stack; - call_instruction->args = args; - call_instruction->result_loc = result_loc; - - ir_ref_instruction(fn_ref, irb->current_basic_block); - if (ret_ptr != nullptr) ir_ref_instruction(ret_ptr, irb->current_basic_block); - ir_ref_instruction(new_stack, irb->current_basic_block); - ir_ref_instruction(args, irb->current_basic_block); - - return &call_instruction->base; -} - -static IrInstSrc *ir_build_call_args(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, - IrInstSrc *options, IrInstSrc *fn_ref, IrInstSrc **args_ptr, size_t args_len, - ResultLoc *result_loc) -{ - IrInstSrcCallArgs *call_instruction = ir_build_instruction(irb, scope, source_node); - call_instruction->options = options; - call_instruction->fn_ref = fn_ref; - call_instruction->args_ptr = args_ptr; - call_instruction->args_len = args_len; - call_instruction->result_loc = result_loc; - - ir_ref_instruction(options, irb->current_basic_block); - ir_ref_instruction(fn_ref, irb->current_basic_block); - for (size_t i = 0; i < args_len; i += 1) - ir_ref_instruction(args_ptr[i], irb->current_basic_block); - - return &call_instruction->base; -} - -static IrInstSrc *ir_build_call_src(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, - ZigFn *fn_entry, IrInstSrc *fn_ref, size_t arg_count, IrInstSrc **args, - IrInstSrc *ret_ptr, CallModifier modifier, bool is_async_call_builtin, - IrInstSrc *new_stack, ResultLoc *result_loc) -{ - IrInstSrcCall *call_instruction = ir_build_instruction(irb, scope, source_node); - call_instruction->fn_entry = fn_entry; - call_instruction->fn_ref = fn_ref; - call_instruction->args = args; - call_instruction->arg_count = arg_count; - call_instruction->modifier = modifier; - call_instruction->is_async_call_builtin = is_async_call_builtin; - call_instruction->new_stack = new_stack; - call_instruction->result_loc = result_loc; - call_instruction->ret_ptr = ret_ptr; - - if (fn_ref != nullptr) ir_ref_instruction(fn_ref, irb->current_basic_block); - for (size_t i = 0; i < arg_count; i += 1) - ir_ref_instruction(args[i], irb->current_basic_block); - if (ret_ptr != nullptr) ir_ref_instruction(ret_ptr, irb->current_basic_block); - if (new_stack != nullptr) ir_ref_instruction(new_stack, irb->current_basic_block); - - return &call_instruction->base; -} - static IrInstGenCall *ir_build_call_gen(IrAnalyze *ira, IrInst *source_instruction, ZigFn *fn_entry, IrInstGen *fn_ref, size_t arg_count, IrInstGen **args, CallModifier modifier, IrInstGen *new_stack, bool is_async_call_builtin, @@ -2550,27 +1299,6 @@ static IrInstGenCall *ir_build_call_gen(IrAnalyze *ira, IrInst *source_instructi return call_instruction; } -static IrInstSrc *ir_build_phi(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, - size_t incoming_count, IrBasicBlockSrc **incoming_blocks, IrInstSrc **incoming_values, - ResultLocPeerParent *peer_parent) -{ - assert(incoming_count != 0); - assert(incoming_count != SIZE_MAX); - - IrInstSrcPhi *phi_instruction = ir_build_instruction(irb, scope, source_node); - phi_instruction->incoming_count = incoming_count; - phi_instruction->incoming_blocks = incoming_blocks; - phi_instruction->incoming_values = incoming_values; - phi_instruction->peer_parent = peer_parent; - - for (size_t i = 0; i < incoming_count; i += 1) { - ir_ref_bb(incoming_blocks[i]); - ir_ref_instruction(incoming_values[i], irb->current_basic_block); - } - - return &phi_instruction->base; -} - static IrInstGen *ir_build_phi_gen(IrAnalyze *ira, IrInst *source_instr, size_t incoming_count, IrBasicBlockGen **incoming_blocks, IrInstGen **incoming_values, ZigType *result_type) { @@ -2591,20 +1319,6 @@ static IrInstGen *ir_build_phi_gen(IrAnalyze *ira, IrInst *source_instr, size_t return &phi_instruction->base; } -static IrInstSrc *ir_build_br(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, - IrBasicBlockSrc *dest_block, IrInstSrc *is_comptime) -{ - IrInstSrcBr *inst = ir_build_instruction(irb, scope, source_node); - inst->base.is_noreturn = true; - inst->dest_block = dest_block; - inst->is_comptime = is_comptime; - - ir_ref_bb(dest_block); - if (is_comptime) ir_ref_instruction(is_comptime, irb->current_basic_block); - - return &inst->base; -} - static IrInstGen *ir_build_br_gen(IrAnalyze *ira, IrInst *source_instr, IrBasicBlockGen *dest_block) { IrInstGenBr *inst = ir_build_inst_noreturn(&ira->new_irb, source_instr->scope, source_instr->source_node); inst->dest_block = dest_block; @@ -2612,73 +1326,6 @@ static IrInstGen *ir_build_br_gen(IrAnalyze *ira, IrInst *source_instr, IrBasicB return &inst->base; } -static IrInstSrc *ir_build_ptr_type_simple(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, - IrInstSrc *child_type, bool is_const) -{ - IrInstSrcPtrTypeSimple *inst = heap::c_allocator.create(); - inst->base.id = is_const ? IrInstSrcIdPtrTypeSimpleConst : IrInstSrcIdPtrTypeSimple; - inst->base.base.scope = scope; - inst->base.base.source_node = source_node; - inst->base.base.debug_id = exec_next_debug_id(irb->exec); - inst->base.owner_bb = irb->current_basic_block; - ir_instruction_append(irb->current_basic_block, &inst->base); - - inst->child_type = child_type; - - ir_ref_instruction(child_type, irb->current_basic_block); - - return &inst->base; -} - -static IrInstSrc *ir_build_ptr_type(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, - IrInstSrc *child_type, bool is_const, bool is_volatile, PtrLen ptr_len, - IrInstSrc *sentinel, IrInstSrc *align_value, - uint32_t bit_offset_start, uint32_t host_int_bytes, bool is_allow_zero) -{ - if (!is_volatile && ptr_len == PtrLenSingle && sentinel == nullptr && align_value == nullptr && - bit_offset_start == 0 && host_int_bytes == 0 && is_allow_zero == 0) - { - return ir_build_ptr_type_simple(irb, scope, source_node, child_type, is_const); - } - - IrInstSrcPtrType *inst = ir_build_instruction(irb, scope, source_node); - inst->sentinel = sentinel; - inst->align_value = align_value; - inst->child_type = child_type; - inst->is_const = is_const; - inst->is_volatile = is_volatile; - inst->ptr_len = ptr_len; - inst->bit_offset_start = bit_offset_start; - inst->host_int_bytes = host_int_bytes; - inst->is_allow_zero = is_allow_zero; - - if (sentinel) ir_ref_instruction(sentinel, irb->current_basic_block); - if (align_value) ir_ref_instruction(align_value, irb->current_basic_block); - ir_ref_instruction(child_type, irb->current_basic_block); - - return &inst->base; -} - -static IrInstSrc *ir_build_un_op_lval(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrUnOp op_id, - IrInstSrc *value, LVal lval, ResultLoc *result_loc) -{ - IrInstSrcUnOp *instruction = ir_build_instruction(irb, scope, source_node); - instruction->op_id = op_id; - instruction->value = value; - instruction->lval = lval; - instruction->result_loc = result_loc; - - ir_ref_instruction(value, irb->current_basic_block); - - return &instruction->base; -} - -static IrInstSrc *ir_build_un_op(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrUnOp op_id, - IrInstSrc *value) -{ - return ir_build_un_op_lval(irb, scope, source_node, op_id, value, LValNone, nullptr); -} - static IrInstGen *ir_build_negation(IrAnalyze *ira, IrInst *source_instr, IrInstGen *operand, ZigType *expr_type, bool wrapping) { IrInstGenNegation *instruction = ir_build_inst_gen(&ira->new_irb, source_instr->scope, source_instr->source_node); @@ -2704,66 +1351,11 @@ static IrInstGen *ir_build_binary_not(IrAnalyze *ira, IrInst *source_instr, IrIn return &instruction->base; } -static IrInstSrc *ir_build_container_init_list(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, - size_t item_count, IrInstSrc **elem_result_loc_list, IrInstSrc *result_loc, - AstNode *init_array_type_source_node) -{ - IrInstSrcContainerInitList *container_init_list_instruction = - ir_build_instruction(irb, scope, source_node); - container_init_list_instruction->item_count = item_count; - container_init_list_instruction->elem_result_loc_list = elem_result_loc_list; - container_init_list_instruction->result_loc = result_loc; - container_init_list_instruction->init_array_type_source_node = init_array_type_source_node; - - for (size_t i = 0; i < item_count; i += 1) { - ir_ref_instruction(elem_result_loc_list[i], irb->current_basic_block); - } - if (result_loc != nullptr) ir_ref_instruction(result_loc, irb->current_basic_block); - - return &container_init_list_instruction->base; -} - -static IrInstSrc *ir_build_container_init_fields(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, - size_t field_count, IrInstSrcContainerInitFieldsField *fields, IrInstSrc *result_loc) -{ - IrInstSrcContainerInitFields *container_init_fields_instruction = - ir_build_instruction(irb, scope, source_node); - container_init_fields_instruction->field_count = field_count; - container_init_fields_instruction->fields = fields; - container_init_fields_instruction->result_loc = result_loc; - - for (size_t i = 0; i < field_count; i += 1) { - ir_ref_instruction(fields[i].result_loc, irb->current_basic_block); - } - if (result_loc != nullptr) ir_ref_instruction(result_loc, irb->current_basic_block); - - return &container_init_fields_instruction->base; -} - -static IrInstSrc *ir_build_unreachable(IrBuilderSrc *irb, Scope *scope, AstNode *source_node) { - IrInstSrcUnreachable *inst = ir_build_instruction(irb, scope, source_node); - inst->base.is_noreturn = true; - return &inst->base; -} - static IrInstGen *ir_build_unreachable_gen(IrAnalyze *ira, IrInst *source_instr) { IrInstGenUnreachable *inst = ir_build_inst_noreturn(&ira->new_irb, source_instr->scope, source_instr->source_node); return &inst->base; } -static IrInstSrcStorePtr *ir_build_store_ptr(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, - IrInstSrc *ptr, IrInstSrc *value) -{ - IrInstSrcStorePtr *instruction = ir_build_instruction(irb, scope, source_node); - instruction->ptr = ptr; - instruction->value = value; - - ir_ref_instruction(ptr, irb->current_basic_block); - ir_ref_instruction(value, irb->current_basic_block); - - return instruction; -} - static IrInstGen *ir_build_store_ptr_gen(IrAnalyze *ira, IrInst *source_instr, IrInstGen *ptr, IrInstGen *value) { IrInstGenStorePtr *instruction = ir_build_inst_void(&ira->new_irb, source_instr->scope, source_instr->source_node); @@ -2792,20 +1384,6 @@ static IrInstGen *ir_build_vector_store_elem(IrAnalyze *ira, IrInst *src_inst, return &inst->base; } -static IrInstSrc *ir_build_var_decl_src(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, - ZigVar *var, IrInstSrc *align_value, IrInstSrc *ptr) -{ - IrInstSrcDeclVar *inst = ir_build_instruction(irb, scope, source_node); - inst->var = var; - inst->align_value = align_value; - inst->ptr = ptr; - - if (align_value != nullptr) ir_ref_instruction(align_value, irb->current_basic_block); - ir_ref_instruction(ptr, irb->current_basic_block); - - return &inst->base; -} - static IrInstGen *ir_build_var_decl_gen(IrAnalyze *ira, IrInst *source_instruction, ZigVar *var, IrInstGen *var_ptr) { @@ -2821,34 +1399,6 @@ static IrInstGen *ir_build_var_decl_gen(IrAnalyze *ira, IrInst *source_instructi return &inst->base; } -static IrInstSrc *ir_build_export(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, - IrInstSrc *target, IrInstSrc *options) -{ - IrInstSrcExport *export_instruction = ir_build_instruction( - irb, scope, source_node); - export_instruction->target = target; - export_instruction->options = options; - - ir_ref_instruction(target, irb->current_basic_block); - ir_ref_instruction(options, irb->current_basic_block); - - return &export_instruction->base; -} - -static IrInstSrc *ir_build_extern(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, - IrInstSrc *type, IrInstSrc *options) -{ - IrInstSrcExtern *extern_instruction = ir_build_instruction( - irb, scope, source_node); - extern_instruction->type = type; - extern_instruction->options = options; - - ir_ref_instruction(type, irb->current_basic_block); - ir_ref_instruction(options, irb->current_basic_block); - - return &extern_instruction->base; -} - static IrInstGen *ir_build_extern_gen(IrAnalyze *ira, IrInst *source_instr, Buf *name, GlobalLinkageId linkage, bool is_thread_local, ZigType *expr_type) { @@ -2862,15 +1412,6 @@ static IrInstGen *ir_build_extern_gen(IrAnalyze *ira, IrInst *source_instr, Buf return &instruction->base; } -static IrInstSrc *ir_build_load_ptr(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrInstSrc *ptr) { - IrInstSrcLoadPtr *instruction = ir_build_instruction(irb, scope, source_node); - instruction->ptr = ptr; - - ir_ref_instruction(ptr, irb->current_basic_block); - - return &instruction->base; -} - static IrInstGen *ir_build_load_ptr_gen(IrAnalyze *ira, IrInst *source_instruction, IrInstGen *ptr, ZigType *ty, IrInstGen *result_loc) { @@ -2886,133 +1427,6 @@ static IrInstGen *ir_build_load_ptr_gen(IrAnalyze *ira, IrInst *source_instructi return &instruction->base; } -static IrInstSrc *ir_build_typeof_n(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, - IrInstSrc **values, size_t value_count) -{ - assert(value_count >= 2); - - IrInstSrcTypeOf *instruction = ir_build_instruction(irb, scope, source_node); - instruction->value.list = values; - instruction->value_count = value_count; - - for (size_t i = 0; i < value_count; i++) - ir_ref_instruction(values[i], irb->current_basic_block); - - return &instruction->base; -} - -static IrInstSrc *ir_build_typeof_1(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrInstSrc *value) { - IrInstSrcTypeOf *instruction = ir_build_instruction(irb, scope, source_node); - instruction->value.scalar = value; - - ir_ref_instruction(value, irb->current_basic_block); - - return &instruction->base; -} - -static IrInstSrc *ir_build_set_cold(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrInstSrc *is_cold) { - IrInstSrcSetCold *instruction = ir_build_instruction(irb, scope, source_node); - instruction->is_cold = is_cold; - - ir_ref_instruction(is_cold, irb->current_basic_block); - - return &instruction->base; -} - -static IrInstSrc *ir_build_set_runtime_safety(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, - IrInstSrc *safety_on) -{ - IrInstSrcSetRuntimeSafety *inst = ir_build_instruction(irb, scope, source_node); - inst->safety_on = safety_on; - - ir_ref_instruction(safety_on, irb->current_basic_block); - - return &inst->base; -} - -static IrInstSrc *ir_build_set_float_mode(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, - IrInstSrc *mode_value) -{ - IrInstSrcSetFloatMode *instruction = ir_build_instruction(irb, scope, source_node); - instruction->mode_value = mode_value; - - ir_ref_instruction(mode_value, irb->current_basic_block); - - return &instruction->base; -} - -static IrInstSrc *ir_build_array_type(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrInstSrc *size, - IrInstSrc *sentinel, IrInstSrc *child_type) -{ - IrInstSrcArrayType *instruction = ir_build_instruction(irb, scope, source_node); - instruction->size = size; - instruction->sentinel = sentinel; - instruction->child_type = child_type; - - ir_ref_instruction(size, irb->current_basic_block); - if (sentinel != nullptr) ir_ref_instruction(sentinel, irb->current_basic_block); - ir_ref_instruction(child_type, irb->current_basic_block); - - return &instruction->base; -} - -static IrInstSrc *ir_build_anyframe_type(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, - IrInstSrc *payload_type) -{ - IrInstSrcAnyFrameType *instruction = ir_build_instruction(irb, scope, source_node); - instruction->payload_type = payload_type; - - if (payload_type != nullptr) ir_ref_instruction(payload_type, irb->current_basic_block); - - return &instruction->base; -} - -static IrInstSrc *ir_build_slice_type(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, - IrInstSrc *child_type, bool is_const, bool is_volatile, - IrInstSrc *sentinel, IrInstSrc *align_value, bool is_allow_zero) -{ - IrInstSrcSliceType *instruction = ir_build_instruction(irb, scope, source_node); - instruction->is_const = is_const; - instruction->is_volatile = is_volatile; - instruction->child_type = child_type; - instruction->sentinel = sentinel; - instruction->align_value = align_value; - instruction->is_allow_zero = is_allow_zero; - - if (sentinel != nullptr) ir_ref_instruction(sentinel, irb->current_basic_block); - if (align_value != nullptr) ir_ref_instruction(align_value, irb->current_basic_block); - ir_ref_instruction(child_type, irb->current_basic_block); - - return &instruction->base; -} - -static IrInstSrc *ir_build_asm_src(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, - IrInstSrc *asm_template, IrInstSrc **input_list, IrInstSrc **output_types, - ZigVar **output_vars, size_t return_count, bool has_side_effects, bool is_global) -{ - IrInstSrcAsm *instruction = ir_build_instruction(irb, scope, source_node); - instruction->asm_template = asm_template; - instruction->input_list = input_list; - instruction->output_types = output_types; - instruction->output_vars = output_vars; - instruction->return_count = return_count; - instruction->has_side_effects = has_side_effects; - instruction->is_global = is_global; - - assert(source_node->type == NodeTypeAsmExpr); - for (size_t i = 0; i < source_node->data.asm_expr.output_list.length; i += 1) { - IrInstSrc *output_type = output_types[i]; - if (output_type) ir_ref_instruction(output_type, irb->current_basic_block); - } - - for (size_t i = 0; i < source_node->data.asm_expr.input_list.length; i += 1) { - IrInstSrc *input_value = input_list[i]; - ir_ref_instruction(input_value, irb->current_basic_block); - } - - return &instruction->base; -} - static IrInstGen *ir_build_asm_gen(IrAnalyze *ira, IrInst *source_instr, Buf *asm_template, AsmToken *token_list, size_t token_list_len, IrInstGen **input_list, IrInstGen **output_types, ZigVar **output_vars, size_t return_count, @@ -3043,29 +1457,6 @@ static IrInstGen *ir_build_asm_gen(IrAnalyze *ira, IrInst *source_instr, return &instruction->base; } -static IrInstSrc *ir_build_size_of(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrInstSrc *type_value, - bool bit_size) -{ - IrInstSrcSizeOf *instruction = ir_build_instruction(irb, scope, source_node); - instruction->type_value = type_value; - instruction->bit_size = bit_size; - - ir_ref_instruction(type_value, irb->current_basic_block); - - return &instruction->base; -} - -static IrInstSrc *ir_build_test_non_null_src(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, - IrInstSrc *value) -{ - IrInstSrcTestNonNull *instruction = ir_build_instruction(irb, scope, source_node); - instruction->value = value; - - ir_ref_instruction(value, irb->current_basic_block); - - return &instruction->base; -} - static IrInstGen *ir_build_test_non_null_gen(IrAnalyze *ira, IrInst *source_instr, IrInstGen *value) { IrInstGenTestNonNull *inst = ir_build_inst_gen(&ira->new_irb, source_instr->scope, source_instr->source_node); @@ -3077,18 +1468,6 @@ static IrInstGen *ir_build_test_non_null_gen(IrAnalyze *ira, IrInst *source_inst return &inst->base; } -static IrInstSrc *ir_build_optional_unwrap_ptr(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, - IrInstSrc *base_ptr, bool safety_check_on) -{ - IrInstSrcOptionalUnwrapPtr *instruction = ir_build_instruction(irb, scope, source_node); - instruction->base_ptr = base_ptr; - instruction->safety_check_on = safety_check_on; - - ir_ref_instruction(base_ptr, irb->current_basic_block); - - return &instruction->base; -} - static IrInstGen *ir_build_optional_unwrap_ptr_gen(IrAnalyze *ira, IrInst *source_instr, IrInstGen *base_ptr, bool safety_check_on, bool initializing, ZigType *result_type) { @@ -3149,19 +1528,6 @@ static IrInstGen *ir_build_err_wrap_code(IrAnalyze *ira, IrInst *source_instruct return &instruction->base; } -static IrInstSrc *ir_build_clz(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrInstSrc *type, - IrInstSrc *op) -{ - IrInstSrcClz *instruction = ir_build_instruction(irb, scope, source_node); - instruction->type = type; - instruction->op = op; - - ir_ref_instruction(type, irb->current_basic_block); - ir_ref_instruction(op, irb->current_basic_block); - - return &instruction->base; -} - static IrInstGen *ir_build_clz_gen(IrAnalyze *ira, IrInst *source_instr, ZigType *result_type, IrInstGen *op) { IrInstGenClz *instruction = ir_build_inst_gen(&ira->new_irb, source_instr->scope, source_instr->source_node); @@ -3173,19 +1539,6 @@ static IrInstGen *ir_build_clz_gen(IrAnalyze *ira, IrInst *source_instr, ZigType return &instruction->base; } -static IrInstSrc *ir_build_ctz(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrInstSrc *type, - IrInstSrc *op) -{ - IrInstSrcCtz *instruction = ir_build_instruction(irb, scope, source_node); - instruction->type = type; - instruction->op = op; - - ir_ref_instruction(type, irb->current_basic_block); - ir_ref_instruction(op, irb->current_basic_block); - - return &instruction->base; -} - static IrInstGen *ir_build_ctz_gen(IrAnalyze *ira, IrInst *source_instr, ZigType *result_type, IrInstGen *op) { IrInstGenCtz *instruction = ir_build_inst_gen(&ira->new_irb, source_instr->scope, source_instr->source_node); @@ -3197,19 +1550,6 @@ static IrInstGen *ir_build_ctz_gen(IrAnalyze *ira, IrInst *source_instr, ZigType return &instruction->base; } -static IrInstSrc *ir_build_pop_count(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrInstSrc *type, - IrInstSrc *op) -{ - IrInstSrcPopCount *instruction = ir_build_instruction(irb, scope, source_node); - instruction->type = type; - instruction->op = op; - - ir_ref_instruction(type, irb->current_basic_block); - ir_ref_instruction(op, irb->current_basic_block); - - return &instruction->base; -} - static IrInstGen *ir_build_pop_count_gen(IrAnalyze *ira, IrInst *source_instr, ZigType *result_type, IrInstGen *op) { @@ -3223,19 +1563,6 @@ static IrInstGen *ir_build_pop_count_gen(IrAnalyze *ira, IrInst *source_instr, Z return &instruction->base; } -static IrInstSrc *ir_build_bswap(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrInstSrc *type, - IrInstSrc *op) -{ - IrInstSrcBswap *instruction = ir_build_instruction(irb, scope, source_node); - instruction->type = type; - instruction->op = op; - - ir_ref_instruction(type, irb->current_basic_block); - ir_ref_instruction(op, irb->current_basic_block); - - return &instruction->base; -} - static IrInstGen *ir_build_bswap_gen(IrAnalyze *ira, IrInst *source_instr, ZigType *op_type, IrInstGen *op) { @@ -3249,19 +1576,6 @@ static IrInstGen *ir_build_bswap_gen(IrAnalyze *ira, IrInst *source_instr, ZigTy return &instruction->base; } -static IrInstSrc *ir_build_bit_reverse(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrInstSrc *type, - IrInstSrc *op) -{ - IrInstSrcBitReverse *instruction = ir_build_instruction(irb, scope, source_node); - instruction->type = type; - instruction->op = op; - - ir_ref_instruction(type, irb->current_basic_block); - ir_ref_instruction(op, irb->current_basic_block); - - return &instruction->base; -} - static IrInstGen *ir_build_bit_reverse_gen(IrAnalyze *ira, IrInst *source_instr, ZigType *int_type, IrInstGen *op) { @@ -3275,32 +1589,6 @@ static IrInstGen *ir_build_bit_reverse_gen(IrAnalyze *ira, IrInst *source_instr, return &instruction->base; } -static IrInstSrcSwitchBr *ir_build_switch_br_src(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, - IrInstSrc *target_value, IrBasicBlockSrc *else_block, size_t case_count, IrInstSrcSwitchBrCase *cases, - IrInstSrc *is_comptime, IrInstSrc *switch_prongs_void) -{ - IrInstSrcSwitchBr *instruction = ir_build_instruction(irb, scope, source_node); - instruction->base.is_noreturn = true; - instruction->target_value = target_value; - instruction->else_block = else_block; - instruction->case_count = case_count; - instruction->cases = cases; - instruction->is_comptime = is_comptime; - instruction->switch_prongs_void = switch_prongs_void; - - ir_ref_instruction(target_value, irb->current_basic_block); - ir_ref_instruction(is_comptime, irb->current_basic_block); - ir_ref_bb(else_block); - ir_ref_instruction(switch_prongs_void, irb->current_basic_block); - - for (size_t i = 0; i < case_count; i += 1) { - ir_ref_instruction(cases[i].value, irb->current_basic_block); - ir_ref_bb(cases[i].block); - } - - return instruction; -} - static IrInstGenSwitchBr *ir_build_switch_br_gen(IrAnalyze *ira, IrInst *source_instr, IrInstGen *target_value, IrBasicBlockGen *else_block, size_t case_count, IrInstGenSwitchBrCase *cases) { @@ -3320,45 +1608,6 @@ static IrInstGenSwitchBr *ir_build_switch_br_gen(IrAnalyze *ira, IrInst *source_ return instruction; } -static IrInstSrc *ir_build_switch_target(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, - IrInstSrc *target_value_ptr) -{ - IrInstSrcSwitchTarget *instruction = ir_build_instruction(irb, scope, source_node); - instruction->target_value_ptr = target_value_ptr; - - ir_ref_instruction(target_value_ptr, irb->current_basic_block); - - return &instruction->base; -} - -static IrInstSrc *ir_build_switch_var(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, - IrInstSrc *target_value_ptr, IrInstSrc **prongs_ptr, size_t prongs_len) -{ - IrInstSrcSwitchVar *instruction = ir_build_instruction(irb, scope, source_node); - instruction->target_value_ptr = target_value_ptr; - instruction->prongs_ptr = prongs_ptr; - instruction->prongs_len = prongs_len; - - ir_ref_instruction(target_value_ptr, irb->current_basic_block); - for (size_t i = 0; i < prongs_len; i += 1) { - ir_ref_instruction(prongs_ptr[i], irb->current_basic_block); - } - - return &instruction->base; -} - -// For this instruction the switch_br must be set later. -static IrInstSrcSwitchElseVar *ir_build_switch_else_var(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, - IrInstSrc *target_value_ptr) -{ - IrInstSrcSwitchElseVar *instruction = ir_build_instruction(irb, scope, source_node); - instruction->target_value_ptr = target_value_ptr; - - ir_ref_instruction(target_value_ptr, irb->current_basic_block); - - return instruction; -} - static IrInstGen *ir_build_union_tag(IrAnalyze *ira, IrInst *source_instr, IrInstGen *value, ZigType *tag_type) { @@ -3372,24 +1621,6 @@ static IrInstGen *ir_build_union_tag(IrAnalyze *ira, IrInst *source_instr, IrIns return &instruction->base; } -static IrInstSrc *ir_build_import(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrInstSrc *name) { - IrInstSrcImport *instruction = ir_build_instruction(irb, scope, source_node); - instruction->name = name; - - ir_ref_instruction(name, irb->current_basic_block); - - return &instruction->base; -} - -static IrInstSrc *ir_build_ref_src(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrInstSrc *value) { - IrInstSrcRef *instruction = ir_build_instruction(irb, scope, source_node); - instruction->value = value; - - ir_ref_instruction(value, irb->current_basic_block); - - return &instruction->base; -} - static IrInstGen *ir_build_ref_gen(IrAnalyze *ira, IrInst *source_instruction, ZigType *result_type, IrInstGen *operand, IrInstGen *result_loc) { @@ -3405,38 +1636,6 @@ static IrInstGen *ir_build_ref_gen(IrAnalyze *ira, IrInst *source_instruction, Z return &instruction->base; } -static IrInstSrc *ir_build_compile_err(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrInstSrc *msg) { - IrInstSrcCompileErr *instruction = ir_build_instruction(irb, scope, source_node); - instruction->msg = msg; - - ir_ref_instruction(msg, irb->current_basic_block); - - return &instruction->base; -} - -static IrInstSrc *ir_build_compile_log(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, - size_t msg_count, IrInstSrc **msg_list) -{ - IrInstSrcCompileLog *instruction = ir_build_instruction(irb, scope, source_node); - instruction->msg_count = msg_count; - instruction->msg_list = msg_list; - - for (size_t i = 0; i < msg_count; i += 1) { - ir_ref_instruction(msg_list[i], irb->current_basic_block); - } - - return &instruction->base; -} - -static IrInstSrc *ir_build_err_name(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrInstSrc *value) { - IrInstSrcErrName *instruction = ir_build_instruction(irb, scope, source_node); - instruction->value = value; - - ir_ref_instruction(value, irb->current_basic_block); - - return &instruction->base; -} - static IrInstGen *ir_build_err_name_gen(IrAnalyze *ira, IrInst *source_instr, IrInstGen *value, ZigType *str_type) { @@ -3450,73 +1649,6 @@ static IrInstGen *ir_build_err_name_gen(IrAnalyze *ira, IrInst *source_instr, Ir return &instruction->base; } -static IrInstSrc *ir_build_c_import(IrBuilderSrc *irb, Scope *scope, AstNode *source_node) { - IrInstSrcCImport *instruction = ir_build_instruction(irb, scope, source_node); - return &instruction->base; -} - -static IrInstSrc *ir_build_c_include(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrInstSrc *name) { - IrInstSrcCInclude *instruction = ir_build_instruction(irb, scope, source_node); - instruction->name = name; - - ir_ref_instruction(name, irb->current_basic_block); - - return &instruction->base; -} - -static IrInstSrc *ir_build_c_define(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrInstSrc *name, IrInstSrc *value) { - IrInstSrcCDefine *instruction = ir_build_instruction(irb, scope, source_node); - instruction->name = name; - instruction->value = value; - - ir_ref_instruction(name, irb->current_basic_block); - ir_ref_instruction(value, irb->current_basic_block); - - return &instruction->base; -} - -static IrInstSrc *ir_build_c_undef(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrInstSrc *name) { - IrInstSrcCUndef *instruction = ir_build_instruction(irb, scope, source_node); - instruction->name = name; - - ir_ref_instruction(name, irb->current_basic_block); - - return &instruction->base; -} - -static IrInstSrc *ir_build_embed_file(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrInstSrc *name) { - IrInstSrcEmbedFile *instruction = ir_build_instruction(irb, scope, source_node); - instruction->name = name; - - ir_ref_instruction(name, irb->current_basic_block); - - return &instruction->base; -} - -static IrInstSrc *ir_build_cmpxchg_src(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, - IrInstSrc *type_value, IrInstSrc *ptr, IrInstSrc *cmp_value, IrInstSrc *new_value, - IrInstSrc *success_order_value, IrInstSrc *failure_order_value, bool is_weak, ResultLoc *result_loc) -{ - IrInstSrcCmpxchg *instruction = ir_build_instruction(irb, scope, source_node); - instruction->type_value = type_value; - instruction->ptr = ptr; - instruction->cmp_value = cmp_value; - instruction->new_value = new_value; - instruction->success_order_value = success_order_value; - instruction->failure_order_value = failure_order_value; - instruction->is_weak = is_weak; - instruction->result_loc = result_loc; - - ir_ref_instruction(type_value, irb->current_basic_block); - ir_ref_instruction(ptr, irb->current_basic_block); - ir_ref_instruction(cmp_value, irb->current_basic_block); - ir_ref_instruction(new_value, irb->current_basic_block); - ir_ref_instruction(success_order_value, irb->current_basic_block); - ir_ref_instruction(failure_order_value, irb->current_basic_block); - - return &instruction->base; -} - static IrInstGen *ir_build_cmpxchg_gen(IrAnalyze *ira, IrInst *source_instruction, ZigType *result_type, IrInstGen *ptr, IrInstGen *cmp_value, IrInstGen *new_value, AtomicOrder success_order, AtomicOrder failure_order, bool is_weak, IrInstGen *result_loc) @@ -3540,15 +1672,6 @@ static IrInstGen *ir_build_cmpxchg_gen(IrAnalyze *ira, IrInst *source_instructio return &instruction->base; } -static IrInstSrc *ir_build_fence(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrInstSrc *order) { - IrInstSrcFence *instruction = ir_build_instruction(irb, scope, source_node); - instruction->order = order; - - ir_ref_instruction(order, irb->current_basic_block); - - return &instruction->base; -} - static IrInstGen *ir_build_fence_gen(IrAnalyze *ira, IrInst *source_instr, AtomicOrder order) { IrInstGenFence *instruction = ir_build_inst_void(&ira->new_irb, source_instr->scope, source_instr->source_node); @@ -3557,17 +1680,6 @@ static IrInstGen *ir_build_fence_gen(IrAnalyze *ira, IrInst *source_instr, Atomi return &instruction->base; } -static IrInstSrc *ir_build_reduce(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrInstSrc *op, IrInstSrc *value) { - IrInstSrcReduce *instruction = ir_build_instruction(irb, scope, source_node); - instruction->op = op; - instruction->value = value; - - ir_ref_instruction(op, irb->current_basic_block); - ir_ref_instruction(value, irb->current_basic_block); - - return &instruction->base; -} - static IrInstGen *ir_build_reduce_gen(IrAnalyze *ira, IrInst *source_instruction, ReduceOp op, IrInstGen *value, ZigType *result_type) { IrInstGenReduce *instruction = ir_build_inst_gen(&ira->new_irb, source_instruction->scope, source_instruction->source_node); @@ -3580,17 +1692,32 @@ static IrInstGen *ir_build_reduce_gen(IrAnalyze *ira, IrInst *source_instruction return &instruction->base; } -static IrInstSrc *ir_build_truncate(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, - IrInstSrc *dest_type, IrInstSrc *target) -{ - IrInstSrcTruncate *instruction = ir_build_instruction(irb, scope, source_node); - instruction->dest_type = dest_type; - instruction->target = target; +static void ir_set_cursor_at_end_gen(IrBuilderGen *irb, IrBasicBlockGen *basic_block) { + assert(basic_block); + irb->current_basic_block = basic_block; +} - ir_ref_instruction(dest_type, irb->current_basic_block); - ir_ref_instruction(target, irb->current_basic_block); +static void ir_append_basic_block_gen(IrBuilderGen *irb, IrBasicBlockGen *bb) { + assert(!bb->already_appended); + bb->already_appended = true; + irb->exec->basic_block_list.append(bb); +} - return &instruction->base; +static void ir_set_cursor_at_end_and_append_block_gen(IrBuilderGen *irb, IrBasicBlockGen *basic_block) { + ir_append_basic_block_gen(irb, basic_block); + ir_set_cursor_at_end_gen(irb, basic_block); +} + +static IrInstGen *ir_build_suspend_begin_gen(IrAnalyze *ira, IrInst *source_instr) { + IrInstGenSuspendBegin *inst = ir_build_inst_void(&ira->new_irb, + source_instr->scope, source_instr->source_node); + return &inst->base; +} + +static IrInstGen *ir_build_save_err_ret_addr_gen(IrAnalyze *ira, IrInst *source_instr) { + IrInstGenSaveErrRetAddr *inst = ir_build_inst_void(&ira->new_irb, + source_instr->scope, source_instr->source_node); + return &inst->base; } static IrInstGen *ir_build_truncate_gen(IrAnalyze *ira, IrInst *source_instr, ZigType *dest_type, @@ -3606,110 +1733,6 @@ static IrInstGen *ir_build_truncate_gen(IrAnalyze *ira, IrInst *source_instr, Zi return &instruction->base; } -static IrInstSrc *ir_build_int_cast(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrInstSrc *dest_type, - IrInstSrc *target) -{ - IrInstSrcIntCast *instruction = ir_build_instruction(irb, scope, source_node); - instruction->dest_type = dest_type; - instruction->target = target; - - ir_ref_instruction(dest_type, irb->current_basic_block); - ir_ref_instruction(target, irb->current_basic_block); - - return &instruction->base; -} - -static IrInstSrc *ir_build_float_cast(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrInstSrc *dest_type, - IrInstSrc *target) -{ - IrInstSrcFloatCast *instruction = ir_build_instruction(irb, scope, source_node); - instruction->dest_type = dest_type; - instruction->target = target; - - ir_ref_instruction(dest_type, irb->current_basic_block); - ir_ref_instruction(target, irb->current_basic_block); - - return &instruction->base; -} - -static IrInstSrc *ir_build_err_set_cast(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, - IrInstSrc *dest_type, IrInstSrc *target) -{ - IrInstSrcErrSetCast *instruction = ir_build_instruction(irb, scope, source_node); - instruction->dest_type = dest_type; - instruction->target = target; - - ir_ref_instruction(dest_type, irb->current_basic_block); - ir_ref_instruction(target, irb->current_basic_block); - - return &instruction->base; -} - -static IrInstSrc *ir_build_int_to_float(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, - IrInstSrc *dest_type, IrInstSrc *target) -{ - IrInstSrcIntToFloat *instruction = ir_build_instruction(irb, scope, source_node); - instruction->dest_type = dest_type; - instruction->target = target; - - ir_ref_instruction(dest_type, irb->current_basic_block); - ir_ref_instruction(target, irb->current_basic_block); - - return &instruction->base; -} - -static IrInstSrc *ir_build_float_to_int(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, - IrInstSrc *dest_type, IrInstSrc *target) -{ - IrInstSrcFloatToInt *instruction = ir_build_instruction(irb, scope, source_node); - instruction->dest_type = dest_type; - instruction->target = target; - - ir_ref_instruction(dest_type, irb->current_basic_block); - ir_ref_instruction(target, irb->current_basic_block); - - return &instruction->base; -} - -static IrInstSrc *ir_build_bool_to_int(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrInstSrc *target) { - IrInstSrcBoolToInt *instruction = ir_build_instruction(irb, scope, source_node); - instruction->target = target; - - ir_ref_instruction(target, irb->current_basic_block); - - return &instruction->base; -} - -static IrInstSrc *ir_build_vector_type(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrInstSrc *len, - IrInstSrc *elem_type) -{ - IrInstSrcVectorType *instruction = ir_build_instruction(irb, scope, source_node); - instruction->len = len; - instruction->elem_type = elem_type; - - ir_ref_instruction(len, irb->current_basic_block); - ir_ref_instruction(elem_type, irb->current_basic_block); - - return &instruction->base; -} - -static IrInstSrc *ir_build_shuffle_vector(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, - IrInstSrc *scalar_type, IrInstSrc *a, IrInstSrc *b, IrInstSrc *mask) -{ - IrInstSrcShuffleVector *instruction = ir_build_instruction(irb, scope, source_node); - instruction->scalar_type = scalar_type; - instruction->a = a; - instruction->b = b; - instruction->mask = mask; - - if (scalar_type != nullptr) ir_ref_instruction(scalar_type, irb->current_basic_block); - ir_ref_instruction(a, irb->current_basic_block); - ir_ref_instruction(b, irb->current_basic_block); - ir_ref_instruction(mask, irb->current_basic_block); - - return &instruction->base; -} - static IrInstGen *ir_build_shuffle_vector_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, ZigType *result_type, IrInstGen *a, IrInstGen *b, IrInstGen *mask) { @@ -3726,19 +1749,6 @@ static IrInstGen *ir_build_shuffle_vector_gen(IrAnalyze *ira, Scope *scope, AstN return &inst->base; } -static IrInstSrc *ir_build_splat_src(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, - IrInstSrc *len, IrInstSrc *scalar) -{ - IrInstSrcSplat *instruction = ir_build_instruction(irb, scope, source_node); - instruction->len = len; - instruction->scalar = scalar; - - ir_ref_instruction(len, irb->current_basic_block); - ir_ref_instruction(scalar, irb->current_basic_block); - - return &instruction->base; -} - static IrInstGen *ir_build_splat_gen(IrAnalyze *ira, IrInst *source_instruction, ZigType *result_type, IrInstGen *scalar) { @@ -3752,15 +1762,6 @@ static IrInstGen *ir_build_splat_gen(IrAnalyze *ira, IrInst *source_instruction, return &instruction->base; } -static IrInstSrc *ir_build_bool_not(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrInstSrc *value) { - IrInstSrcBoolNot *instruction = ir_build_instruction(irb, scope, source_node); - instruction->value = value; - - ir_ref_instruction(value, irb->current_basic_block); - - return &instruction->base; -} - static IrInstGen *ir_build_bool_not_gen(IrAnalyze *ira, IrInst *source_instr, IrInstGen *value) { IrInstGenBoolNot *instruction = ir_build_inst_gen(&ira->new_irb, source_instr->scope, source_instr->source_node); @@ -3772,21 +1773,6 @@ static IrInstGen *ir_build_bool_not_gen(IrAnalyze *ira, IrInst *source_instr, Ir return &instruction->base; } -static IrInstSrc *ir_build_memset_src(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, - IrInstSrc *dest_ptr, IrInstSrc *byte, IrInstSrc *count) -{ - IrInstSrcMemset *instruction = ir_build_instruction(irb, scope, source_node); - instruction->dest_ptr = dest_ptr; - instruction->byte = byte; - instruction->count = count; - - ir_ref_instruction(dest_ptr, irb->current_basic_block); - ir_ref_instruction(byte, irb->current_basic_block); - ir_ref_instruction(count, irb->current_basic_block); - - return &instruction->base; -} - static IrInstGen *ir_build_memset_gen(IrAnalyze *ira, IrInst *source_instr, IrInstGen *dest_ptr, IrInstGen *byte, IrInstGen *count) { @@ -3803,21 +1789,6 @@ static IrInstGen *ir_build_memset_gen(IrAnalyze *ira, IrInst *source_instr, return &instruction->base; } -static IrInstSrc *ir_build_memcpy_src(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, - IrInstSrc *dest_ptr, IrInstSrc *src_ptr, IrInstSrc *count) -{ - IrInstSrcMemcpy *instruction = ir_build_instruction(irb, scope, source_node); - instruction->dest_ptr = dest_ptr; - instruction->src_ptr = src_ptr; - instruction->count = count; - - ir_ref_instruction(dest_ptr, irb->current_basic_block); - ir_ref_instruction(src_ptr, irb->current_basic_block); - ir_ref_instruction(count, irb->current_basic_block); - - return &instruction->base; -} - static IrInstGen *ir_build_memcpy_gen(IrAnalyze *ira, IrInst *source_instr, IrInstGen *dest_ptr, IrInstGen *src_ptr, IrInstGen *count) { @@ -3834,26 +1805,6 @@ static IrInstGen *ir_build_memcpy_gen(IrAnalyze *ira, IrInst *source_instr, return &instruction->base; } -static IrInstSrc *ir_build_slice_src(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, - IrInstSrc *ptr, IrInstSrc *start, IrInstSrc *end, IrInstSrc *sentinel, - bool safety_check_on, ResultLoc *result_loc) -{ - IrInstSrcSlice *instruction = ir_build_instruction(irb, scope, source_node); - instruction->ptr = ptr; - instruction->start = start; - instruction->end = end; - instruction->sentinel = sentinel; - instruction->safety_check_on = safety_check_on; - instruction->result_loc = result_loc; - - ir_ref_instruction(ptr, irb->current_basic_block); - ir_ref_instruction(start, irb->current_basic_block); - if (end) ir_ref_instruction(end, irb->current_basic_block); - if (sentinel) ir_ref_instruction(sentinel, irb->current_basic_block); - - return &instruction->base; -} - static IrInstGen *ir_build_slice_gen(IrAnalyze *ira, IrInst *source_instruction, ZigType *slice_type, IrInstGen *ptr, IrInstGen *start, IrInstGen *end, bool safety_check_on, IrInstGen *result_loc, ZigValue *sentinel) @@ -3876,68 +1827,30 @@ static IrInstGen *ir_build_slice_gen(IrAnalyze *ira, IrInst *source_instruction, return &instruction->base; } -static IrInstSrc *ir_build_breakpoint(IrBuilderSrc *irb, Scope *scope, AstNode *source_node) { - IrInstSrcBreakpoint *instruction = ir_build_instruction(irb, scope, source_node); - return &instruction->base; -} - static IrInstGen *ir_build_breakpoint_gen(IrAnalyze *ira, IrInst *source_instr) { IrInstGenBreakpoint *instruction = ir_build_inst_void(&ira->new_irb, source_instr->scope, source_instr->source_node); return &instruction->base; } -static IrInstSrc *ir_build_return_address_src(IrBuilderSrc *irb, Scope *scope, AstNode *source_node) { - IrInstSrcReturnAddress *instruction = ir_build_instruction(irb, scope, source_node); - return &instruction->base; -} - static IrInstGen *ir_build_return_address_gen(IrAnalyze *ira, IrInst *source_instr) { IrInstGenReturnAddress *inst = ir_build_inst_gen(&ira->new_irb, source_instr->scope, source_instr->source_node); inst->base.value->type = ira->codegen->builtin_types.entry_usize; return &inst->base; } -static IrInstSrc *ir_build_frame_address_src(IrBuilderSrc *irb, Scope *scope, AstNode *source_node) { - IrInstSrcFrameAddress *inst = ir_build_instruction(irb, scope, source_node); - return &inst->base; -} - static IrInstGen *ir_build_frame_address_gen(IrAnalyze *ira, IrInst *source_instr) { IrInstGenFrameAddress *inst = ir_build_inst_gen(&ira->new_irb, source_instr->scope, source_instr->source_node); inst->base.value->type = ira->codegen->builtin_types.entry_usize; return &inst->base; } -static IrInstSrc *ir_build_handle_src(IrBuilderSrc *irb, Scope *scope, AstNode *source_node) { - IrInstSrcFrameHandle *inst = ir_build_instruction(irb, scope, source_node); - return &inst->base; -} - static IrInstGen *ir_build_handle_gen(IrAnalyze *ira, IrInst *source_instr, ZigType *ty) { IrInstGenFrameHandle *inst = ir_build_inst_gen(&ira->new_irb, source_instr->scope, source_instr->source_node); inst->base.value->type = ty; return &inst->base; } -static IrInstSrc *ir_build_frame_type(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrInstSrc *fn) { - IrInstSrcFrameType *inst = ir_build_instruction(irb, scope, source_node); - inst->fn = fn; - - ir_ref_instruction(fn, irb->current_basic_block); - - return &inst->base; -} - -static IrInstSrc *ir_build_frame_size_src(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrInstSrc *fn) { - IrInstSrcFrameSize *inst = ir_build_instruction(irb, scope, source_node); - inst->fn = fn; - - ir_ref_instruction(fn, irb->current_basic_block); - - return &inst->base; -} - static IrInstGen *ir_build_frame_size_gen(IrAnalyze *ira, IrInst *source_instr, IrInstGen *fn) { IrInstGenFrameSize *inst = ir_build_inst_gen(&ira->new_irb, source_instr->scope, source_instr->source_node); @@ -3949,24 +1862,6 @@ static IrInstGen *ir_build_frame_size_gen(IrAnalyze *ira, IrInst *source_instr, return &inst->base; } -static IrInstSrc *ir_build_overflow_op_src(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, - IrOverflowOp op, IrInstSrc *type_value, IrInstSrc *op1, IrInstSrc *op2, IrInstSrc *result_ptr) -{ - IrInstSrcOverflowOp *instruction = ir_build_instruction(irb, scope, source_node); - instruction->op = op; - instruction->type_value = type_value; - instruction->op1 = op1; - instruction->op2 = op2; - instruction->result_ptr = result_ptr; - - ir_ref_instruction(type_value, irb->current_basic_block); - ir_ref_instruction(op1, irb->current_basic_block); - ir_ref_instruction(op2, irb->current_basic_block); - ir_ref_instruction(result_ptr, irb->current_basic_block); - - return &instruction->base; -} - static IrInstGen *ir_build_overflow_op_gen(IrAnalyze *ira, IrInst *source_instr, IrOverflowOp op, IrInstGen *op1, IrInstGen *op2, IrInstGen *result_ptr, ZigType *result_ptr_type) @@ -3987,18 +1882,6 @@ static IrInstGen *ir_build_overflow_op_gen(IrAnalyze *ira, IrInst *source_instr, return &instruction->base; } -static IrInstSrc *ir_build_float_op_src(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrInstSrc *operand, - BuiltinFnId fn_id) -{ - IrInstSrcFloatOp *instruction = ir_build_instruction(irb, scope, source_node); - instruction->operand = operand; - instruction->fn_id = fn_id; - - ir_ref_instruction(operand, irb->current_basic_block); - - return &instruction->base; -} - static IrInstGen *ir_build_float_op_gen(IrAnalyze *ira, IrInst *source_instr, IrInstGen *operand, BuiltinFnId fn_id, ZigType *operand_type) { @@ -4013,23 +1896,6 @@ static IrInstGen *ir_build_float_op_gen(IrAnalyze *ira, IrInst *source_instr, Ir return &instruction->base; } -static IrInstSrc *ir_build_mul_add_src(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, - IrInstSrc *type_value, IrInstSrc *op1, IrInstSrc *op2, IrInstSrc *op3) -{ - IrInstSrcMulAdd *instruction = ir_build_instruction(irb, scope, source_node); - instruction->type_value = type_value; - instruction->op1 = op1; - instruction->op2 = op2; - instruction->op3 = op3; - - ir_ref_instruction(type_value, irb->current_basic_block); - ir_ref_instruction(op1, irb->current_basic_block); - ir_ref_instruction(op2, irb->current_basic_block); - ir_ref_instruction(op3, irb->current_basic_block); - - return &instruction->base; -} - static IrInstGen *ir_build_mul_add_gen(IrAnalyze *ira, IrInst *source_instr, IrInstGen *op1, IrInstGen *op2, IrInstGen *op3, ZigType *expr_type) { @@ -4047,28 +1913,6 @@ static IrInstGen *ir_build_mul_add_gen(IrAnalyze *ira, IrInst *source_instr, IrI return &instruction->base; } -static IrInstSrc *ir_build_align_of(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrInstSrc *type_value) { - IrInstSrcAlignOf *instruction = ir_build_instruction(irb, scope, source_node); - instruction->type_value = type_value; - - ir_ref_instruction(type_value, irb->current_basic_block); - - return &instruction->base; -} - -static IrInstSrc *ir_build_test_err_src(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, - IrInstSrc *base_ptr, bool resolve_err_set, bool base_ptr_is_payload) -{ - IrInstSrcTestErr *instruction = ir_build_instruction(irb, scope, source_node); - instruction->base_ptr = base_ptr; - instruction->resolve_err_set = resolve_err_set; - instruction->base_ptr_is_payload = base_ptr_is_payload; - - ir_ref_instruction(base_ptr, irb->current_basic_block); - - return &instruction->base; -} - static IrInstGen *ir_build_test_err_gen(IrAnalyze *ira, IrInst *source_instruction, IrInstGen *err_union) { IrInstGenTestErr *instruction = ir_build_inst_gen( &ira->new_irb, source_instruction->scope, source_instruction->source_node); @@ -4080,17 +1924,6 @@ static IrInstGen *ir_build_test_err_gen(IrAnalyze *ira, IrInst *source_instructi return &instruction->base; } -static IrInstSrc *ir_build_unwrap_err_code_src(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, - IrInstSrc *err_union_ptr) -{ - IrInstSrcUnwrapErrCode *inst = ir_build_instruction(irb, scope, source_node); - inst->err_union_ptr = err_union_ptr; - - ir_ref_instruction(err_union_ptr, irb->current_basic_block); - - return &inst->base; -} - static IrInstGen *ir_build_unwrap_err_code_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, IrInstGen *err_union_ptr, ZigType *result_type) { @@ -4103,19 +1936,6 @@ static IrInstGen *ir_build_unwrap_err_code_gen(IrAnalyze *ira, Scope *scope, Ast return &inst->base; } -static IrInstSrc *ir_build_unwrap_err_payload_src(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, - IrInstSrc *value, bool safety_check_on, bool initializing) -{ - IrInstSrcUnwrapErrPayload *inst = ir_build_instruction(irb, scope, source_node); - inst->value = value; - inst->safety_check_on = safety_check_on; - inst->initializing = initializing; - - ir_ref_instruction(value, irb->current_basic_block); - - return &inst->base; -} - static IrInstGen *ir_build_unwrap_err_payload_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, IrInstGen *value, bool safety_check_on, bool initializing, ZigType *result_type) { @@ -4130,54 +1950,6 @@ static IrInstGen *ir_build_unwrap_err_payload_gen(IrAnalyze *ira, Scope *scope, return &inst->base; } -static IrInstSrc *ir_build_fn_proto(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, - IrInstSrc **param_types, IrInstSrc *align_value, IrInstSrc *callconv_value, - IrInstSrc *return_type, bool is_var_args) -{ - IrInstSrcFnProto *instruction = ir_build_instruction(irb, scope, source_node); - instruction->param_types = param_types; - instruction->align_value = align_value; - instruction->callconv_value = callconv_value; - instruction->return_type = return_type; - instruction->is_var_args = is_var_args; - - assert(source_node->type == NodeTypeFnProto); - size_t param_count = source_node->data.fn_proto.params.length; - if (is_var_args) param_count -= 1; - for (size_t i = 0; i < param_count; i += 1) { - if (param_types[i] != nullptr) ir_ref_instruction(param_types[i], irb->current_basic_block); - } - if (align_value != nullptr) ir_ref_instruction(align_value, irb->current_basic_block); - if (callconv_value != nullptr) ir_ref_instruction(callconv_value, irb->current_basic_block); - ir_ref_instruction(return_type, irb->current_basic_block); - - return &instruction->base; -} - -static IrInstSrc *ir_build_test_comptime(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrInstSrc *value) { - IrInstSrcTestComptime *instruction = ir_build_instruction(irb, scope, source_node); - instruction->value = value; - - ir_ref_instruction(value, irb->current_basic_block); - - return &instruction->base; -} - -static IrInstSrc *ir_build_ptr_cast_src(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, - IrInstSrc *dest_type, IrInstSrc *ptr, bool safety_check_on) -{ - IrInstSrcPtrCast *instruction = ir_build_instruction( - irb, scope, source_node); - instruction->dest_type = dest_type; - instruction->ptr = ptr; - instruction->safety_check_on = safety_check_on; - - ir_ref_instruction(dest_type, irb->current_basic_block); - ir_ref_instruction(ptr, irb->current_basic_block); - - return &instruction->base; -} - static IrInstGen *ir_build_ptr_cast_gen(IrAnalyze *ira, IrInst *source_instruction, ZigType *ptr_type, IrInstGen *ptr, bool safety_check_on) { @@ -4192,30 +1964,6 @@ static IrInstGen *ir_build_ptr_cast_gen(IrAnalyze *ira, IrInst *source_instructi return &instruction->base; } -static IrInstSrc *ir_build_implicit_cast(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, - IrInstSrc *operand, ResultLocCast *result_loc_cast) -{ - IrInstSrcImplicitCast *instruction = ir_build_instruction(irb, scope, source_node); - instruction->operand = operand; - instruction->result_loc_cast = result_loc_cast; - - ir_ref_instruction(operand, irb->current_basic_block); - - return &instruction->base; -} - -static IrInstSrc *ir_build_bit_cast_src(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, - IrInstSrc *operand, ResultLocBitCast *result_loc_bit_cast) -{ - IrInstSrcBitCast *instruction = ir_build_instruction(irb, scope, source_node); - instruction->operand = operand; - instruction->result_loc_bit_cast = result_loc_bit_cast; - - ir_ref_instruction(operand, irb->current_basic_block); - - return &instruction->base; -} - static IrInstGen *ir_build_bit_cast_gen(IrAnalyze *ira, IrInst *source_instruction, IrInstGen *operand, ZigType *ty) { @@ -4241,19 +1989,6 @@ static IrInstGen *ir_build_widen_or_shorten(IrAnalyze *ira, Scope *scope, AstNod return &inst->base; } -static IrInstSrc *ir_build_int_to_ptr_src(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, - IrInstSrc *dest_type, IrInstSrc *target) -{ - IrInstSrcIntToPtr *instruction = ir_build_instruction(irb, scope, source_node); - instruction->dest_type = dest_type; - instruction->target = target; - - ir_ref_instruction(dest_type, irb->current_basic_block); - ir_ref_instruction(target, irb->current_basic_block); - - return &instruction->base; -} - static IrInstGen *ir_build_int_to_ptr_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, IrInstGen *target, ZigType *ptr_type) { @@ -4266,17 +2001,6 @@ static IrInstGen *ir_build_int_to_ptr_gen(IrAnalyze *ira, Scope *scope, AstNode return &instruction->base; } -static IrInstSrc *ir_build_ptr_to_int_src(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, - IrInstSrc *target) -{ - IrInstSrcPtrToInt *inst = ir_build_instruction(irb, scope, source_node); - inst->target = target; - - ir_ref_instruction(target, irb->current_basic_block); - - return &inst->base; -} - static IrInstGen *ir_build_ptr_to_int_gen(IrAnalyze *ira, IrInst *source_instr, IrInstGen *target) { IrInstGenPtrToInt *inst = ir_build_inst_gen(&ira->new_irb, source_instr->scope, source_instr->source_node); inst->base.value->type = ira->codegen->builtin_types.entry_usize; @@ -4287,19 +2011,6 @@ static IrInstGen *ir_build_ptr_to_int_gen(IrAnalyze *ira, IrInst *source_instr, return &inst->base; } -static IrInstSrc *ir_build_int_to_enum_src(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, - IrInstSrc *dest_type, IrInstSrc *target) -{ - IrInstSrcIntToEnum *instruction = ir_build_instruction(irb, scope, source_node); - instruction->dest_type = dest_type; - instruction->target = target; - - if (dest_type) ir_ref_instruction(dest_type, irb->current_basic_block); - ir_ref_instruction(target, irb->current_basic_block); - - return &instruction->base; -} - static IrInstGen *ir_build_int_to_enum_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, ZigType *dest_type, IrInstGen *target) { @@ -4312,29 +2023,6 @@ static IrInstGen *ir_build_int_to_enum_gen(IrAnalyze *ira, Scope *scope, AstNode return &instruction->base; } -static IrInstSrc *ir_build_enum_to_int(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, - IrInstSrc *target) -{ - IrInstSrcEnumToInt *instruction = ir_build_instruction( - irb, scope, source_node); - instruction->target = target; - - ir_ref_instruction(target, irb->current_basic_block); - - return &instruction->base; -} - -static IrInstSrc *ir_build_int_to_err_src(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, - IrInstSrc *target) -{ - IrInstSrcIntToErr *instruction = ir_build_instruction(irb, scope, source_node); - instruction->target = target; - - ir_ref_instruction(target, irb->current_basic_block); - - return &instruction->base; -} - static IrInstGen *ir_build_int_to_err_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, IrInstGen *target, ZigType *wanted_type) { @@ -4347,18 +2035,6 @@ static IrInstGen *ir_build_int_to_err_gen(IrAnalyze *ira, Scope *scope, AstNode return &instruction->base; } -static IrInstSrc *ir_build_err_to_int_src(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, - IrInstSrc *target) -{ - IrInstSrcErrToInt *instruction = ir_build_instruction( - irb, scope, source_node); - instruction->target = target; - - ir_ref_instruction(target, irb->current_basic_block); - - return &instruction->base; -} - static IrInstGen *ir_build_err_to_int_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, IrInstGen *target, ZigType *wanted_type) { @@ -4371,74 +2047,6 @@ static IrInstGen *ir_build_err_to_int_gen(IrAnalyze *ira, Scope *scope, AstNode return &instruction->base; } -static IrInstSrc *ir_build_check_switch_prongs(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, - IrInstSrc *target_value, IrInstSrcCheckSwitchProngsRange *ranges, size_t range_count, - AstNode* else_prong, bool have_underscore_prong) -{ - IrInstSrcCheckSwitchProngs *instruction = heap::c_allocator.create(); - instruction->base.id = have_underscore_prong ? - IrInstSrcIdCheckSwitchProngsUnderYes : IrInstSrcIdCheckSwitchProngsUnderNo; - instruction->base.base.scope = scope; - instruction->base.base.source_node = source_node; - instruction->base.base.debug_id = exec_next_debug_id(irb->exec); - instruction->base.owner_bb = irb->current_basic_block; - ir_instruction_append(irb->current_basic_block, &instruction->base); - - instruction->target_value = target_value; - instruction->ranges = ranges; - instruction->range_count = range_count; - instruction->else_prong = else_prong; - - ir_ref_instruction(target_value, irb->current_basic_block); - for (size_t i = 0; i < range_count; i += 1) { - ir_ref_instruction(ranges[i].start, irb->current_basic_block); - ir_ref_instruction(ranges[i].end, irb->current_basic_block); - } - - return &instruction->base; -} - -static IrInstSrc *ir_build_check_statement_is_void(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, - IrInstSrc* statement_value) -{ - IrInstSrcCheckStatementIsVoid *instruction = ir_build_instruction( - irb, scope, source_node); - instruction->statement_value = statement_value; - - ir_ref_instruction(statement_value, irb->current_basic_block); - - return &instruction->base; -} - -static IrInstSrc *ir_build_type_name(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, - IrInstSrc *type_value) -{ - IrInstSrcTypeName *instruction = ir_build_instruction(irb, scope, source_node); - instruction->type_value = type_value; - - ir_ref_instruction(type_value, irb->current_basic_block); - - return &instruction->base; -} - -static IrInstSrc *ir_build_decl_ref(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, Tld *tld, LVal lval) { - IrInstSrcDeclRef *instruction = ir_build_instruction(irb, scope, source_node); - instruction->tld = tld; - instruction->lval = lval; - - return &instruction->base; -} - -static IrInstSrc *ir_build_panic_src(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrInstSrc *msg) { - IrInstSrcPanic *instruction = ir_build_instruction(irb, scope, source_node); - instruction->base.is_noreturn = true; - instruction->msg = msg; - - ir_ref_instruction(msg, irb->current_basic_block); - - return &instruction->base; -} - static IrInstGen *ir_build_panic_gen(IrAnalyze *ira, IrInst *source_instr, IrInstGen *msg) { IrInstGenPanic *instruction = ir_build_inst_noreturn(&ira->new_irb, source_instr->scope, source_instr->source_node); @@ -4449,15 +2057,6 @@ static IrInstGen *ir_build_panic_gen(IrAnalyze *ira, IrInst *source_instr, IrIns return &instruction->base; } -static IrInstSrc *ir_build_tag_name_src(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrInstSrc *target) { - IrInstSrcTagName *instruction = ir_build_instruction(irb, scope, source_node); - instruction->target = target; - - ir_ref_instruction(target, irb->current_basic_block); - - return &instruction->base; -} - static IrInstGen *ir_build_tag_name_gen(IrAnalyze *ira, IrInst *source_instr, IrInstGen *target, ZigType *result_type) { @@ -4471,22 +2070,6 @@ static IrInstGen *ir_build_tag_name_gen(IrAnalyze *ira, IrInst *source_instr, Ir return &instruction->base; } -static IrInstSrc *ir_build_field_parent_ptr_src(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, - IrInstSrc *type_value, IrInstSrc *field_name, IrInstSrc *field_ptr) -{ - IrInstSrcFieldParentPtr *inst = ir_build_instruction( - irb, scope, source_node); - inst->type_value = type_value; - inst->field_name = field_name; - inst->field_ptr = field_ptr; - - ir_ref_instruction(type_value, irb->current_basic_block); - ir_ref_instruction(field_name, irb->current_basic_block); - ir_ref_instruction(field_ptr, irb->current_basic_block); - - return &inst->base; -} - static IrInstGen *ir_build_field_parent_ptr_gen(IrAnalyze *ira, IrInst *source_instr, IrInstGen *field_ptr, TypeStructField *field, ZigType *result_type) { @@ -4501,74 +2084,6 @@ static IrInstGen *ir_build_field_parent_ptr_gen(IrAnalyze *ira, IrInst *source_i return &inst->base; } -static IrInstSrc *ir_build_byte_offset_of(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, - IrInstSrc *type_value, IrInstSrc *field_name) -{ - IrInstSrcByteOffsetOf *instruction = ir_build_instruction(irb, scope, source_node); - instruction->type_value = type_value; - instruction->field_name = field_name; - - ir_ref_instruction(type_value, irb->current_basic_block); - ir_ref_instruction(field_name, irb->current_basic_block); - - return &instruction->base; -} - -static IrInstSrc *ir_build_bit_offset_of(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, - IrInstSrc *type_value, IrInstSrc *field_name) -{ - IrInstSrcBitOffsetOf *instruction = ir_build_instruction(irb, scope, source_node); - instruction->type_value = type_value; - instruction->field_name = field_name; - - ir_ref_instruction(type_value, irb->current_basic_block); - ir_ref_instruction(field_name, irb->current_basic_block); - - return &instruction->base; -} - -static IrInstSrc *ir_build_type_info(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrInstSrc *type_value) { - IrInstSrcTypeInfo *instruction = ir_build_instruction(irb, scope, source_node); - instruction->type_value = type_value; - - ir_ref_instruction(type_value, irb->current_basic_block); - - return &instruction->base; -} - -static IrInstSrc *ir_build_type(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrInstSrc *type_info) { - IrInstSrcType *instruction = ir_build_instruction(irb, scope, source_node); - instruction->type_info = type_info; - - ir_ref_instruction(type_info, irb->current_basic_block); - - return &instruction->base; -} - -static IrInstSrc *ir_build_set_eval_branch_quota(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, - IrInstSrc *new_quota) -{ - IrInstSrcSetEvalBranchQuota *instruction = ir_build_instruction(irb, scope, source_node); - instruction->new_quota = new_quota; - - ir_ref_instruction(new_quota, irb->current_basic_block); - - return &instruction->base; -} - -static IrInstSrc *ir_build_align_cast_src(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, - IrInstSrc *align_bytes, IrInstSrc *target) -{ - IrInstSrcAlignCast *instruction = ir_build_instruction(irb, scope, source_node); - instruction->align_bytes = align_bytes; - instruction->target = target; - - ir_ref_instruction(align_bytes, irb->current_basic_block); - ir_ref_instruction(target, irb->current_basic_block); - - return &instruction->base; -} - static IrInstGen *ir_build_align_cast_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, IrInstGen *target, ZigType *result_type) { @@ -4581,69 +2096,6 @@ static IrInstGen *ir_build_align_cast_gen(IrAnalyze *ira, Scope *scope, AstNode return &instruction->base; } -static IrInstSrc *ir_build_resolve_result(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, - ResultLoc *result_loc, IrInstSrc *ty) -{ - IrInstSrcResolveResult *instruction = ir_build_instruction(irb, scope, source_node); - instruction->result_loc = result_loc; - instruction->ty = ty; - - if (ty != nullptr) ir_ref_instruction(ty, irb->current_basic_block); - - return &instruction->base; -} - -static IrInstSrc *ir_build_reset_result(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, - ResultLoc *result_loc) -{ - IrInstSrcResetResult *instruction = ir_build_instruction(irb, scope, source_node); - instruction->result_loc = result_loc; - instruction->base.is_gen = true; - - return &instruction->base; -} - -static IrInstSrc *ir_build_set_align_stack(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, - IrInstSrc *align_bytes) -{ - IrInstSrcSetAlignStack *instruction = ir_build_instruction(irb, scope, source_node); - instruction->align_bytes = align_bytes; - - ir_ref_instruction(align_bytes, irb->current_basic_block); - - return &instruction->base; -} - -static IrInstSrc *ir_build_arg_type(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, - IrInstSrc *fn_type, IrInstSrc *arg_index, bool allow_var) -{ - IrInstSrcArgType *instruction = heap::c_allocator.create(); - instruction->base.id = allow_var ? - IrInstSrcIdArgTypeAllowVarTrue : IrInstSrcIdArgTypeAllowVarFalse; - instruction->base.base.scope = scope; - instruction->base.base.source_node = source_node; - instruction->base.base.debug_id = exec_next_debug_id(irb->exec); - instruction->base.owner_bb = irb->current_basic_block; - ir_instruction_append(irb->current_basic_block, &instruction->base); - - instruction->fn_type = fn_type; - instruction->arg_index = arg_index; - - ir_ref_instruction(fn_type, irb->current_basic_block); - ir_ref_instruction(arg_index, irb->current_basic_block); - - return &instruction->base; -} - -static IrInstSrc *ir_build_error_return_trace_src(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, - IrInstErrorReturnTraceOptional optional) -{ - IrInstSrcErrorReturnTrace *inst = ir_build_instruction(irb, scope, source_node); - inst->optional = optional; - - return &inst->base; -} - static IrInstGen *ir_build_error_return_trace_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, IrInstErrorReturnTraceOptional optional, ZigType *result_type) { @@ -4654,39 +2106,6 @@ static IrInstGen *ir_build_error_return_trace_gen(IrAnalyze *ira, Scope *scope, return &inst->base; } -static IrInstSrc *ir_build_error_union(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, - IrInstSrc *err_set, IrInstSrc *payload) -{ - IrInstSrcErrorUnion *instruction = ir_build_instruction(irb, scope, source_node); - instruction->err_set = err_set; - instruction->payload = payload; - - ir_ref_instruction(err_set, irb->current_basic_block); - ir_ref_instruction(payload, irb->current_basic_block); - - return &instruction->base; -} - -static IrInstSrc *ir_build_atomic_rmw_src(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, - IrInstSrc *operand_type, IrInstSrc *ptr, IrInstSrc *op, IrInstSrc *operand, - IrInstSrc *ordering) -{ - IrInstSrcAtomicRmw *instruction = ir_build_instruction(irb, scope, source_node); - instruction->operand_type = operand_type; - instruction->ptr = ptr; - instruction->op = op; - instruction->operand = operand; - instruction->ordering = ordering; - - ir_ref_instruction(operand_type, irb->current_basic_block); - ir_ref_instruction(ptr, irb->current_basic_block); - ir_ref_instruction(op, irb->current_basic_block); - ir_ref_instruction(operand, irb->current_basic_block); - ir_ref_instruction(ordering, irb->current_basic_block); - - return &instruction->base; -} - static IrInstGen *ir_build_atomic_rmw_gen(IrAnalyze *ira, IrInst *source_instr, IrInstGen *ptr, IrInstGen *operand, AtomicRmwOp op, AtomicOrder ordering, ZigType *operand_type) { @@ -4703,21 +2122,6 @@ static IrInstGen *ir_build_atomic_rmw_gen(IrAnalyze *ira, IrInst *source_instr, return &instruction->base; } -static IrInstSrc *ir_build_atomic_load_src(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, - IrInstSrc *operand_type, IrInstSrc *ptr, IrInstSrc *ordering) -{ - IrInstSrcAtomicLoad *instruction = ir_build_instruction(irb, scope, source_node); - instruction->operand_type = operand_type; - instruction->ptr = ptr; - instruction->ordering = ordering; - - ir_ref_instruction(operand_type, irb->current_basic_block); - ir_ref_instruction(ptr, irb->current_basic_block); - ir_ref_instruction(ordering, irb->current_basic_block); - - return &instruction->base; -} - static IrInstGen *ir_build_atomic_load_gen(IrAnalyze *ira, IrInst *source_instr, IrInstGen *ptr, AtomicOrder ordering, ZigType *operand_type) { @@ -4732,23 +2136,6 @@ static IrInstGen *ir_build_atomic_load_gen(IrAnalyze *ira, IrInst *source_instr, return &instruction->base; } -static IrInstSrc *ir_build_atomic_store_src(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, - IrInstSrc *operand_type, IrInstSrc *ptr, IrInstSrc *value, IrInstSrc *ordering) -{ - IrInstSrcAtomicStore *instruction = ir_build_instruction(irb, scope, source_node); - instruction->operand_type = operand_type; - instruction->ptr = ptr; - instruction->value = value; - instruction->ordering = ordering; - - ir_ref_instruction(operand_type, irb->current_basic_block); - ir_ref_instruction(ptr, irb->current_basic_block); - ir_ref_instruction(value, irb->current_basic_block); - ir_ref_instruction(ordering, irb->current_basic_block); - - return &instruction->base; -} - static IrInstGen *ir_build_atomic_store_gen(IrAnalyze *ira, IrInst *source_instr, IrInstGen *ptr, IrInstGen *value, AtomicOrder ordering) { @@ -4764,77 +2151,6 @@ static IrInstGen *ir_build_atomic_store_gen(IrAnalyze *ira, IrInst *source_instr return &instruction->base; } -static IrInstSrc *ir_build_save_err_ret_addr_src(IrBuilderSrc *irb, Scope *scope, AstNode *source_node) { - IrInstSrcSaveErrRetAddr *inst = ir_build_instruction(irb, scope, source_node); - return &inst->base; -} - -static IrInstGen *ir_build_save_err_ret_addr_gen(IrAnalyze *ira, IrInst *source_instr) { - IrInstGenSaveErrRetAddr *inst = ir_build_inst_void(&ira->new_irb, - source_instr->scope, source_instr->source_node); - return &inst->base; -} - -static IrInstSrc *ir_build_add_implicit_return_type(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, - IrInstSrc *value, ResultLocReturn *result_loc_ret) -{ - IrInstSrcAddImplicitReturnType *inst = ir_build_instruction(irb, scope, source_node); - inst->value = value; - inst->result_loc_ret = result_loc_ret; - - ir_ref_instruction(value, irb->current_basic_block); - - return &inst->base; -} - -static IrInstSrc *ir_build_has_decl(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, - IrInstSrc *container, IrInstSrc *name) -{ - IrInstSrcHasDecl *instruction = ir_build_instruction(irb, scope, source_node); - instruction->container = container; - instruction->name = name; - - ir_ref_instruction(container, irb->current_basic_block); - ir_ref_instruction(name, irb->current_basic_block); - - return &instruction->base; -} - -static IrInstSrc *ir_build_undeclared_identifier(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, Buf *name) { - IrInstSrcUndeclaredIdent *instruction = ir_build_instruction(irb, scope, source_node); - instruction->name = name; - - return &instruction->base; -} - -static IrInstSrc *ir_build_check_runtime_scope(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrInstSrc *scope_is_comptime, IrInstSrc *is_comptime) { - IrInstSrcCheckRuntimeScope *instruction = ir_build_instruction(irb, scope, source_node); - instruction->scope_is_comptime = scope_is_comptime; - instruction->is_comptime = is_comptime; - - ir_ref_instruction(scope_is_comptime, irb->current_basic_block); - ir_ref_instruction(is_comptime, irb->current_basic_block); - - return &instruction->base; -} - -static IrInstSrc *ir_build_union_init_named_field(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, - IrInstSrc *union_type, IrInstSrc *field_name, IrInstSrc *field_result_loc, IrInstSrc *result_loc) -{ - IrInstSrcUnionInitNamedField *instruction = ir_build_instruction(irb, scope, source_node); - instruction->union_type = union_type; - instruction->field_name = field_name; - instruction->field_result_loc = field_result_loc; - instruction->result_loc = result_loc; - - ir_ref_instruction(union_type, irb->current_basic_block); - ir_ref_instruction(field_name, irb->current_basic_block); - ir_ref_instruction(field_result_loc, irb->current_basic_block); - if (result_loc != nullptr) ir_ref_instruction(result_loc, irb->current_basic_block); - - return &instruction->base; -} - static IrInstGen *ir_build_vector_to_array(IrAnalyze *ira, IrInst *source_instruction, ZigType *result_type, IrInstGen *vector, IrInstGen *result_loc) @@ -4905,21 +2221,6 @@ static IrInstGen *ir_build_assert_non_null(IrAnalyze *ira, IrInst *source_instru return &instruction->base; } -static IrInstSrc *ir_build_alloca_src(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, - IrInstSrc *align, const char *name_hint, IrInstSrc *is_comptime) -{ - IrInstSrcAlloca *instruction = ir_build_instruction(irb, scope, source_node); - instruction->base.is_gen = true; - instruction->align = align; - instruction->name_hint = name_hint; - instruction->is_comptime = is_comptime; - - if (align != nullptr) ir_ref_instruction(align, irb->current_basic_block); - if (is_comptime != nullptr) ir_ref_instruction(is_comptime, irb->current_basic_block); - - return &instruction->base; -} - static IrInstGenAlloca *ir_build_alloca_gen(IrAnalyze *ira, IrInst *source_instruction, uint32_t align, const char *name_hint) { @@ -4931,40 +2232,6 @@ static IrInstGenAlloca *ir_build_alloca_gen(IrAnalyze *ira, IrInst *source_instr return instruction; } -static IrInstSrc *ir_build_end_expr(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, - IrInstSrc *value, ResultLoc *result_loc) -{ - IrInstSrcEndExpr *instruction = ir_build_instruction(irb, scope, source_node); - instruction->base.is_gen = true; - instruction->value = value; - instruction->result_loc = result_loc; - - ir_ref_instruction(value, irb->current_basic_block); - - return &instruction->base; -} - -static IrInstSrcSuspendBegin *ir_build_suspend_begin_src(IrBuilderSrc *irb, Scope *scope, AstNode *source_node) { - return ir_build_instruction(irb, scope, source_node); -} - -static IrInstGen *ir_build_suspend_begin_gen(IrAnalyze *ira, IrInst *source_instr) { - IrInstGenSuspendBegin *inst = ir_build_inst_void(&ira->new_irb, - source_instr->scope, source_instr->source_node); - return &inst->base; -} - -static IrInstSrc *ir_build_suspend_finish_src(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, - IrInstSrcSuspendBegin *begin) -{ - IrInstSrcSuspendFinish *inst = ir_build_instruction(irb, scope, source_node); - inst->begin = begin; - - ir_ref_instruction(&begin->base, irb->current_basic_block); - - return &inst->base; -} - static IrInstGen *ir_build_suspend_finish_gen(IrAnalyze *ira, IrInst *source_instr, IrInstGenSuspendBegin *begin) { IrInstGenSuspendFinish *inst = ir_build_inst_void(&ira->new_irb, source_instr->scope, source_instr->source_node); @@ -4975,19 +2242,6 @@ static IrInstGen *ir_build_suspend_finish_gen(IrAnalyze *ira, IrInst *source_ins return &inst->base; } -static IrInstSrc *ir_build_await_src(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, - IrInstSrc *frame, ResultLoc *result_loc, bool is_nosuspend) -{ - IrInstSrcAwait *instruction = ir_build_instruction(irb, scope, source_node); - instruction->frame = frame; - instruction->result_loc = result_loc; - instruction->is_nosuspend = is_nosuspend; - - ir_ref_instruction(frame, irb->current_basic_block); - - return &instruction->base; -} - static IrInstGenAwait *ir_build_await_gen(IrAnalyze *ira, IrInst *source_instruction, IrInstGen *frame, ZigType *result_type, IrInstGen *result_loc, bool is_nosuspend) { @@ -5004,15 +2258,6 @@ static IrInstGenAwait *ir_build_await_gen(IrAnalyze *ira, IrInst *source_instruc return instruction; } -static IrInstSrc *ir_build_resume_src(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrInstSrc *frame) { - IrInstSrcResume *instruction = ir_build_instruction(irb, scope, source_node); - instruction->frame = frame; - - ir_ref_instruction(frame, irb->current_basic_block); - - return &instruction->base; -} - static IrInstGen *ir_build_resume_gen(IrAnalyze *ira, IrInst *source_instr, IrInstGen *frame) { IrInstGenResume *instruction = ir_build_inst_void(&ira->new_irb, source_instr->scope, source_instr->source_node); @@ -5023,18 +2268,6 @@ static IrInstGen *ir_build_resume_gen(IrAnalyze *ira, IrInst *source_instr, IrIn return &instruction->base; } -static IrInstSrcSpillBegin *ir_build_spill_begin_src(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, - IrInstSrc *operand, SpillId spill_id) -{ - IrInstSrcSpillBegin *instruction = ir_build_instruction(irb, scope, source_node); - instruction->operand = operand; - instruction->spill_id = spill_id; - - ir_ref_instruction(operand, irb->current_basic_block); - - return instruction; -} - static IrInstGen *ir_build_spill_begin_gen(IrAnalyze *ira, IrInst *source_instr, IrInstGen *operand, SpillId spill_id) { @@ -5048,17 +2281,6 @@ static IrInstGen *ir_build_spill_begin_gen(IrAnalyze *ira, IrInst *source_instr, return &instruction->base; } -static IrInstSrc *ir_build_spill_end_src(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, - IrInstSrcSpillBegin *begin) -{ - IrInstSrcSpillEnd *instruction = ir_build_instruction(irb, scope, source_node); - instruction->begin = begin; - - ir_ref_instruction(&begin->base, irb->current_basic_block); - - return &instruction->base; -} - static IrInstGen *ir_build_spill_end_gen(IrAnalyze *ira, IrInst *source_instr, IrInstGenSpillBegin *begin, ZigType *result_type) { @@ -5087,15 +2309,6 @@ static IrInstGen *ir_build_vector_extract_elem(IrAnalyze *ira, IrInst *source_in return &instruction->base; } -static IrInstSrc *ir_build_wasm_memory_size_src(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrInstSrc *index) { - IrInstSrcWasmMemorySize *instruction = ir_build_instruction(irb, scope, source_node); - instruction->index = index; - - ir_ref_instruction(index, irb->current_basic_block); - - return &instruction->base; -} - static IrInstGen *ir_build_wasm_memory_size_gen(IrAnalyze *ira, IrInst *source_instr, IrInstGen *index) { IrInstGenWasmMemorySize *instruction = ir_build_inst_gen(&ira->new_irb, source_instr->scope, source_instr->source_node); @@ -5107,17 +2320,6 @@ static IrInstGen *ir_build_wasm_memory_size_gen(IrAnalyze *ira, IrInst *source_i return &instruction->base; } -static IrInstSrc *ir_build_wasm_memory_grow_src(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrInstSrc *index, IrInstSrc *delta) { - IrInstSrcWasmMemoryGrow *instruction = ir_build_instruction(irb, scope, source_node); - instruction->index = index; - instruction->delta = delta; - - ir_ref_instruction(index, irb->current_basic_block); - ir_ref_instruction(delta, irb->current_basic_block); - - return &instruction->base; -} - static IrInstGen *ir_build_wasm_memory_grow_gen(IrAnalyze *ira, IrInst *source_instr, IrInstGen *index, IrInstGen *delta) { IrInstGenWasmMemoryGrow *instruction = ir_build_inst_gen(&ira->new_irb, source_instr->scope, source_instr->source_node); @@ -5131,3676 +2333,6 @@ static IrInstGen *ir_build_wasm_memory_grow_gen(IrAnalyze *ira, IrInst *source_i return &instruction->base; } -static IrInstSrc *ir_build_src(IrBuilderSrc *irb, Scope *scope, AstNode *source_node) { - IrInstSrcSrc *instruction = ir_build_instruction(irb, scope, source_node); - - return &instruction->base; -} - -static void ir_count_defers(IrBuilderSrc *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) { - results[ReturnKindUnconditional] = 0; - results[ReturnKindError] = 0; - - Scope *scope = inner_scope; - - while (scope != outer_scope) { - assert(scope); - switch (scope->id) { - case ScopeIdDefer: { - AstNode *defer_node = scope->source_node; - assert(defer_node->type == NodeTypeDefer); - ReturnKind defer_kind = defer_node->data.defer.kind; - results[defer_kind] += 1; - scope = scope->parent; - continue; - } - case ScopeIdDecls: - case ScopeIdFnDef: - return; - case ScopeIdBlock: - case ScopeIdVarDecl: - case ScopeIdLoop: - case ScopeIdSuspend: - case ScopeIdCompTime: - case ScopeIdNoSuspend: - case ScopeIdRuntime: - case ScopeIdTypeOf: - case ScopeIdExpr: - scope = scope->parent; - continue; - case ScopeIdDeferExpr: - case ScopeIdCImport: - zig_unreachable(); - } - } -} - -static IrInstSrc *ir_mark_gen(IrInstSrc *instruction) { - instruction->is_gen = true; - return instruction; -} - -static bool ir_gen_defers_for_block(IrBuilderSrc *irb, Scope *inner_scope, Scope *outer_scope, bool *is_noreturn, IrInstSrc *err_value) { - Scope *scope = inner_scope; - if (is_noreturn != nullptr) *is_noreturn = false; - while (scope != outer_scope) { - if (!scope) - return true; - - switch (scope->id) { - case ScopeIdDefer: { - AstNode *defer_node = scope->source_node; - assert(defer_node->type == NodeTypeDefer); - ReturnKind defer_kind = defer_node->data.defer.kind; - AstNode *defer_expr_node = defer_node->data.defer.expr; - AstNode *defer_var_node = defer_node->data.defer.err_payload; - - if (defer_kind == ReturnKindError && err_value == nullptr) { - // This is an `errdefer` but we're generating code for a - // `return` that doesn't return an error, skip it - scope = scope->parent; - continue; - } - - Scope *defer_expr_scope = defer_node->data.defer.expr_scope; - if (defer_var_node != nullptr) { - assert(defer_kind == ReturnKindError); - assert(defer_var_node->type == NodeTypeSymbol); - Buf *var_name = defer_var_node->data.symbol_expr.symbol; - - if (defer_expr_node->type == NodeTypeUnreachable) { - add_node_error(irb->codegen, defer_var_node, - buf_sprintf("unused variable: '%s'", buf_ptr(var_name))); - return false; - } - - IrInstSrc *is_comptime; - if (ir_should_inline(irb->exec, defer_expr_scope)) { - is_comptime = ir_build_const_bool(irb, defer_expr_scope, - defer_expr_node, true); - } else { - is_comptime = ir_build_test_comptime(irb, defer_expr_scope, - defer_expr_node, err_value); - } - - ZigVar *err_var = ir_create_var(irb, defer_var_node, defer_expr_scope, - var_name, true, true, false, is_comptime); - build_decl_var_and_init(irb, defer_expr_scope, defer_var_node, err_var, err_value, - buf_ptr(var_name), is_comptime); - - defer_expr_scope = err_var->child_scope; - } - - IrInstSrc *defer_expr_value = ir_gen_node(irb, defer_expr_node, defer_expr_scope); - if (defer_expr_value == irb->codegen->invalid_inst_src) - return irb->codegen->invalid_inst_src; - - if (defer_expr_value->is_noreturn) { - if (is_noreturn != nullptr) *is_noreturn = true; - } else { - ir_mark_gen(ir_build_check_statement_is_void(irb, defer_expr_scope, defer_expr_node, - defer_expr_value)); - } - scope = scope->parent; - continue; - } - case ScopeIdDecls: - case ScopeIdFnDef: - return true; - case ScopeIdBlock: - case ScopeIdVarDecl: - case ScopeIdLoop: - case ScopeIdSuspend: - case ScopeIdCompTime: - case ScopeIdNoSuspend: - case ScopeIdRuntime: - case ScopeIdTypeOf: - case ScopeIdExpr: - scope = scope->parent; - continue; - case ScopeIdDeferExpr: - case ScopeIdCImport: - zig_unreachable(); - } - } - return true; -} - -static void ir_set_cursor_at_end_gen(IrBuilderGen *irb, IrBasicBlockGen *basic_block) { - assert(basic_block); - irb->current_basic_block = basic_block; -} - -static void ir_set_cursor_at_end(IrBuilderSrc *irb, IrBasicBlockSrc *basic_block) { - assert(basic_block); - irb->current_basic_block = basic_block; -} - -static void ir_append_basic_block_gen(IrBuilderGen *irb, IrBasicBlockGen *bb) { - assert(!bb->already_appended); - bb->already_appended = true; - irb->exec->basic_block_list.append(bb); -} - -static void ir_set_cursor_at_end_and_append_block_gen(IrBuilderGen *irb, IrBasicBlockGen *basic_block) { - ir_append_basic_block_gen(irb, basic_block); - ir_set_cursor_at_end_gen(irb, basic_block); -} - -static void ir_set_cursor_at_end_and_append_block(IrBuilderSrc *irb, IrBasicBlockSrc *basic_block) { - basic_block->index = irb->exec->basic_block_list.length; - irb->exec->basic_block_list.append(basic_block); - ir_set_cursor_at_end(irb, basic_block); -} - -static ScopeSuspend *get_scope_suspend(Scope *scope) { - while (scope) { - if (scope->id == ScopeIdSuspend) - return (ScopeSuspend *)scope; - if (scope->id == ScopeIdFnDef) - return nullptr; - - scope = scope->parent; - } - return nullptr; -} - -static ScopeDeferExpr *get_scope_defer_expr(Scope *scope) { - while (scope) { - if (scope->id == ScopeIdDeferExpr) - return (ScopeDeferExpr *)scope; - if (scope->id == ScopeIdFnDef) - return nullptr; - - scope = scope->parent; - } - return nullptr; -} - -static IrInstSrc *ir_gen_return(IrBuilderSrc *irb, Scope *scope, AstNode *node, LVal lval, ResultLoc *result_loc) { - assert(node->type == NodeTypeReturnExpr); - - ScopeDeferExpr *scope_defer_expr = get_scope_defer_expr(scope); - if (scope_defer_expr) { - if (!scope_defer_expr->reported_err) { - add_node_error(irb->codegen, node, buf_sprintf("cannot return from defer expression")); - scope_defer_expr->reported_err = true; - } - return irb->codegen->invalid_inst_src; - } - - Scope *outer_scope = irb->exec->begin_scope; - - AstNode *expr_node = node->data.return_expr.expr; - switch (node->data.return_expr.kind) { - case ReturnKindUnconditional: - { - ResultLocReturn *result_loc_ret = heap::c_allocator.create(); - result_loc_ret->base.id = ResultLocIdReturn; - ir_build_reset_result(irb, scope, node, &result_loc_ret->base); - - IrInstSrc *return_value; - if (expr_node) { - // Temporarily set this so that if we return a type it gets the name of the function - ZigFn *prev_name_fn = irb->exec->name_fn; - irb->exec->name_fn = exec_fn_entry(irb->exec); - return_value = ir_gen_node_extra(irb, expr_node, scope, LValNone, &result_loc_ret->base); - irb->exec->name_fn = prev_name_fn; - if (return_value == irb->codegen->invalid_inst_src) - return irb->codegen->invalid_inst_src; - } else { - return_value = ir_build_const_void(irb, scope, node); - ir_build_end_expr(irb, scope, node, return_value, &result_loc_ret->base); - } - - ir_mark_gen(ir_build_add_implicit_return_type(irb, scope, node, return_value, result_loc_ret)); - - size_t defer_counts[2]; - ir_count_defers(irb, scope, outer_scope, defer_counts); - bool have_err_defers = defer_counts[ReturnKindError] > 0; - if (!have_err_defers && !irb->codegen->have_err_ret_tracing) { - // only generate unconditional defers - if (!ir_gen_defers_for_block(irb, scope, outer_scope, nullptr, nullptr)) - return irb->codegen->invalid_inst_src; - IrInstSrc *result = ir_build_return_src(irb, scope, node, nullptr); - result_loc_ret->base.source_instruction = result; - return result; - } - bool should_inline = ir_should_inline(irb->exec, scope); - - IrBasicBlockSrc *err_block = ir_create_basic_block(irb, scope, "ErrRetErr"); - IrBasicBlockSrc *ok_block = ir_create_basic_block(irb, scope, "ErrRetOk"); - - IrInstSrc *is_err = ir_build_test_err_src(irb, scope, node, return_value, false, true); - - IrInstSrc *is_comptime; - if (should_inline) { - is_comptime = ir_build_const_bool(irb, scope, node, should_inline); - } else { - is_comptime = ir_build_test_comptime(irb, scope, node, is_err); - } - - ir_mark_gen(ir_build_cond_br(irb, scope, node, is_err, err_block, ok_block, is_comptime)); - IrBasicBlockSrc *ret_stmt_block = ir_create_basic_block(irb, scope, "RetStmt"); - - ir_set_cursor_at_end_and_append_block(irb, err_block); - if (!ir_gen_defers_for_block(irb, scope, outer_scope, nullptr, return_value)) - return irb->codegen->invalid_inst_src; - if (irb->codegen->have_err_ret_tracing && !should_inline) { - ir_build_save_err_ret_addr_src(irb, scope, node); - } - ir_build_br(irb, scope, node, ret_stmt_block, is_comptime); - - ir_set_cursor_at_end_and_append_block(irb, ok_block); - if (!ir_gen_defers_for_block(irb, scope, outer_scope, nullptr, nullptr)) - return irb->codegen->invalid_inst_src; - ir_build_br(irb, scope, node, ret_stmt_block, is_comptime); - - ir_set_cursor_at_end_and_append_block(irb, ret_stmt_block); - IrInstSrc *result = ir_build_return_src(irb, scope, node, nullptr); - result_loc_ret->base.source_instruction = result; - return result; - } - case ReturnKindError: - { - assert(expr_node); - IrInstSrc *err_union_ptr = ir_gen_node_extra(irb, expr_node, scope, LValPtr, nullptr); - if (err_union_ptr == irb->codegen->invalid_inst_src) - return irb->codegen->invalid_inst_src; - IrInstSrc *is_err_val = ir_build_test_err_src(irb, scope, node, err_union_ptr, true, false); - - IrBasicBlockSrc *return_block = ir_create_basic_block(irb, scope, "ErrRetReturn"); - IrBasicBlockSrc *continue_block = ir_create_basic_block(irb, scope, "ErrRetContinue"); - IrInstSrc *is_comptime; - bool should_inline = ir_should_inline(irb->exec, scope); - if (should_inline) { - is_comptime = ir_build_const_bool(irb, scope, node, true); - } else { - is_comptime = ir_build_test_comptime(irb, scope, node, is_err_val); - } - ir_mark_gen(ir_build_cond_br(irb, scope, node, is_err_val, return_block, continue_block, is_comptime)); - - ir_set_cursor_at_end_and_append_block(irb, return_block); - IrInstSrc *err_val_ptr = ir_build_unwrap_err_code_src(irb, scope, node, err_union_ptr); - IrInstSrc *err_val = ir_build_load_ptr(irb, scope, node, err_val_ptr); - ir_mark_gen(ir_build_add_implicit_return_type(irb, scope, node, err_val, nullptr)); - IrInstSrcSpillBegin *spill_begin = ir_build_spill_begin_src(irb, scope, node, err_val, - SpillIdRetErrCode); - ResultLocReturn *result_loc_ret = heap::c_allocator.create(); - result_loc_ret->base.id = ResultLocIdReturn; - ir_build_reset_result(irb, scope, node, &result_loc_ret->base); - ir_build_end_expr(irb, scope, node, err_val, &result_loc_ret->base); - - bool is_noreturn = false; - if (!ir_gen_defers_for_block(irb, scope, outer_scope, &is_noreturn, err_val)) { - return irb->codegen->invalid_inst_src; - } - if (!is_noreturn) { - if (irb->codegen->have_err_ret_tracing && !should_inline) { - ir_build_save_err_ret_addr_src(irb, scope, node); - } - err_val = ir_build_spill_end_src(irb, scope, node, spill_begin); - IrInstSrc *ret_inst = ir_build_return_src(irb, scope, node, err_val); - result_loc_ret->base.source_instruction = ret_inst; - } - - ir_set_cursor_at_end_and_append_block(irb, continue_block); - IrInstSrc *unwrapped_ptr = ir_build_unwrap_err_payload_src(irb, scope, node, err_union_ptr, false, false); - if (lval == LValPtr) - return unwrapped_ptr; - else - return ir_expr_wrap(irb, scope, ir_build_load_ptr(irb, scope, node, unwrapped_ptr), result_loc); - } - } - zig_unreachable(); -} - -static ZigVar *create_local_var(CodeGen *codegen, AstNode *node, Scope *parent_scope, - Buf *name, bool src_is_const, bool gen_is_const, bool is_shadowable, IrInstSrc *is_comptime, - bool skip_name_check) -{ - ZigVar *variable_entry = heap::c_allocator.create(); - variable_entry->parent_scope = parent_scope; - variable_entry->shadowable = is_shadowable; - variable_entry->is_comptime = is_comptime; - variable_entry->src_arg_index = SIZE_MAX; - variable_entry->const_value = codegen->pass1_arena->create(); - - if (is_comptime != nullptr) { - is_comptime->base.ref_count += 1; - } - - if (name) { - variable_entry->name = strdup(buf_ptr(name)); - - if (!skip_name_check) { - ZigVar *existing_var = find_variable(codegen, parent_scope, name, nullptr); - if (existing_var && !existing_var->shadowable) { - if (existing_var->var_type == nullptr || !type_is_invalid(existing_var->var_type)) { - ErrorMsg *msg = add_node_error(codegen, node, - buf_sprintf("redeclaration of variable '%s'", buf_ptr(name))); - add_error_note(codegen, msg, existing_var->decl_node, buf_sprintf("previous declaration is here")); - } - variable_entry->var_type = codegen->builtin_types.entry_invalid; - } else { - ZigType *type; - if (get_primitive_type(codegen, name, &type) != ErrorPrimitiveTypeNotFound) { - add_node_error(codegen, node, - buf_sprintf("variable shadows primitive type '%s'", buf_ptr(name))); - variable_entry->var_type = codegen->builtin_types.entry_invalid; - } else { - Tld *tld = find_decl(codegen, parent_scope, name); - if (tld != nullptr) { - bool want_err_msg = true; - if (tld->id == TldIdVar) { - ZigVar *var = reinterpret_cast(tld)->var; - if (var != nullptr && var->var_type != nullptr && type_is_invalid(var->var_type)) { - want_err_msg = false; - } - } - if (want_err_msg) { - ErrorMsg *msg = add_node_error(codegen, node, - buf_sprintf("redefinition of '%s'", buf_ptr(name))); - add_error_note(codegen, msg, tld->source_node, buf_sprintf("previous definition is here")); - } - variable_entry->var_type = codegen->builtin_types.entry_invalid; - } - } - } - } - } else { - assert(is_shadowable); - // TODO make this name not actually be in scope. user should be able to make a variable called "_anon" - // might already be solved, let's just make sure it has test coverage - // maybe we put a prefix on this so the debug info doesn't clobber user debug info for same named variables - variable_entry->name = "_anon"; - } - - variable_entry->src_is_const = src_is_const; - variable_entry->gen_is_const = gen_is_const; - variable_entry->decl_node = node; - variable_entry->child_scope = create_var_scope(codegen, node, parent_scope, variable_entry); - - return variable_entry; -} - -// Set name to nullptr to make the variable anonymous (not visible to programmer). -// After you call this function var->child_scope has the variable in scope -static ZigVar *ir_create_var(IrBuilderSrc *irb, AstNode *node, Scope *scope, Buf *name, - bool src_is_const, bool gen_is_const, bool is_shadowable, IrInstSrc *is_comptime) -{ - bool is_underscored = name ? buf_eql_str(name, "_") : false; - ZigVar *var = create_local_var(irb->codegen, node, scope, - (is_underscored ? nullptr : name), src_is_const, gen_is_const, - (is_underscored ? true : is_shadowable), is_comptime, false); - assert(var->child_scope); - return var; -} - -static ResultLocPeer *create_peer_result(ResultLocPeerParent *peer_parent) { - ResultLocPeer *result = heap::c_allocator.create(); - result->base.id = ResultLocIdPeer; - result->base.source_instruction = peer_parent->base.source_instruction; - result->parent = peer_parent; - result->base.allow_write_through_const = peer_parent->parent->allow_write_through_const; - return result; -} - -static bool is_duplicate_label(CodeGen *g, Scope *scope, AstNode *node, Buf *name) { - if (name == nullptr) return false; - - for (;;) { - if (scope == nullptr || scope->id == ScopeIdFnDef) { - break; - } else if (scope->id == ScopeIdBlock || scope->id == ScopeIdLoop) { - Buf *this_block_name = scope->id == ScopeIdBlock ? ((ScopeBlock *)scope)->name : ((ScopeLoop *)scope)->name; - if (this_block_name != nullptr && buf_eql_buf(name, this_block_name)) { - ErrorMsg *msg = add_node_error(g, node, buf_sprintf("redeclaration of label '%s'", buf_ptr(name))); - add_error_note(g, msg, scope->source_node, buf_sprintf("previous declaration is here")); - return true; - } - } - scope = scope->parent; - } - return false; -} - -static IrInstSrc *ir_gen_block(IrBuilderSrc *irb, Scope *parent_scope, AstNode *block_node, LVal lval, - ResultLoc *result_loc) -{ - assert(block_node->type == NodeTypeBlock); - - ZigList incoming_values = {0}; - ZigList incoming_blocks = {0}; - - if (is_duplicate_label(irb->codegen, parent_scope, block_node, block_node->data.block.name)) - return irb->codegen->invalid_inst_src; - - ScopeBlock *scope_block = create_block_scope(irb->codegen, block_node, parent_scope); - - Scope *outer_block_scope = &scope_block->base; - Scope *child_scope = outer_block_scope; - - ZigFn *fn_entry = scope_fn_entry(parent_scope); - if (fn_entry && fn_entry->child_scope == parent_scope) { - fn_entry->def_scope = scope_block; - } - - if (block_node->data.block.statements.length == 0) { - if (scope_block->name != nullptr) { - add_node_error(irb->codegen, block_node, buf_sprintf("unused block label")); - } - // {} - return ir_lval_wrap(irb, parent_scope, ir_build_const_void(irb, child_scope, block_node), lval, result_loc); - } - - if (block_node->data.block.name != nullptr) { - scope_block->lval = lval; - scope_block->incoming_blocks = &incoming_blocks; - scope_block->incoming_values = &incoming_values; - scope_block->end_block = ir_create_basic_block(irb, parent_scope, "BlockEnd"); - scope_block->is_comptime = ir_build_const_bool(irb, parent_scope, block_node, - ir_should_inline(irb->exec, parent_scope)); - - scope_block->peer_parent = heap::c_allocator.create(); - scope_block->peer_parent->base.id = ResultLocIdPeerParent; - scope_block->peer_parent->base.source_instruction = scope_block->is_comptime; - scope_block->peer_parent->base.allow_write_through_const = result_loc->allow_write_through_const; - scope_block->peer_parent->end_bb = scope_block->end_block; - scope_block->peer_parent->is_comptime = scope_block->is_comptime; - scope_block->peer_parent->parent = result_loc; - ir_build_reset_result(irb, parent_scope, block_node, &scope_block->peer_parent->base); - } - - bool is_continuation_unreachable = false; - bool found_invalid_inst = false; - IrInstSrc *noreturn_return_value = nullptr; - for (size_t i = 0; i < block_node->data.block.statements.length; i += 1) { - AstNode *statement_node = block_node->data.block.statements.at(i); - - IrInstSrc *statement_value = ir_gen_node(irb, statement_node, child_scope); - if (statement_value == irb->codegen->invalid_inst_src) { - // keep generating all the elements of the block in case of error, - // we want to collect other compile errors - found_invalid_inst = true; - continue; - } - - is_continuation_unreachable = instr_is_unreachable(statement_value); - if (is_continuation_unreachable) { - // keep the last noreturn statement value around in case we need to return it - noreturn_return_value = statement_value; - } - // This logic must be kept in sync with - // [STMT_EXPR_TEST_THING] <--- (search this token) - if (statement_node->type == NodeTypeDefer) { - // defer starts a new scope - child_scope = statement_node->data.defer.child_scope; - assert(child_scope); - } else if (statement_value->id == IrInstSrcIdDeclVar) { - // variable declarations start a new scope - IrInstSrcDeclVar *decl_var_instruction = (IrInstSrcDeclVar *)statement_value; - child_scope = decl_var_instruction->var->child_scope; - } else if (!is_continuation_unreachable) { - // this statement's value must be void - ir_mark_gen(ir_build_check_statement_is_void(irb, child_scope, statement_node, statement_value)); - } - } - - if (scope_block->name != nullptr && scope_block->name_used == false) { - add_node_error(irb->codegen, block_node, buf_sprintf("unused block label")); - } - - if (found_invalid_inst) - return irb->codegen->invalid_inst_src; - - if (is_continuation_unreachable) { - assert(noreturn_return_value != nullptr); - if (block_node->data.block.name == nullptr || incoming_blocks.length == 0) { - return noreturn_return_value; - } - - if (scope_block->peer_parent != nullptr && scope_block->peer_parent->peers.length != 0) { - scope_block->peer_parent->peers.last()->next_bb = scope_block->end_block; - } - ir_set_cursor_at_end_and_append_block(irb, scope_block->end_block); - IrInstSrc *phi = ir_build_phi(irb, parent_scope, block_node, incoming_blocks.length, - incoming_blocks.items, incoming_values.items, scope_block->peer_parent); - return ir_expr_wrap(irb, parent_scope, phi, result_loc); - } else { - incoming_blocks.append(irb->current_basic_block); - IrInstSrc *else_expr_result = ir_mark_gen(ir_build_const_void(irb, parent_scope, block_node)); - - if (scope_block->peer_parent != nullptr) { - ResultLocPeer *peer_result = create_peer_result(scope_block->peer_parent); - scope_block->peer_parent->peers.append(peer_result); - ir_build_end_expr(irb, parent_scope, block_node, else_expr_result, &peer_result->base); - - if (scope_block->peer_parent->peers.length != 0) { - scope_block->peer_parent->peers.last()->next_bb = scope_block->end_block; - } - } - - incoming_values.append(else_expr_result); - } - - bool is_return_from_fn = block_node == irb->main_block_node; - if (!is_return_from_fn) { - if (!ir_gen_defers_for_block(irb, child_scope, outer_block_scope, nullptr, nullptr)) - return irb->codegen->invalid_inst_src; - } - - IrInstSrc *result; - if (block_node->data.block.name != nullptr) { - ir_mark_gen(ir_build_br(irb, parent_scope, block_node, scope_block->end_block, scope_block->is_comptime)); - ir_set_cursor_at_end_and_append_block(irb, scope_block->end_block); - IrInstSrc *phi = ir_build_phi(irb, parent_scope, block_node, incoming_blocks.length, - incoming_blocks.items, incoming_values.items, scope_block->peer_parent); - result = ir_expr_wrap(irb, parent_scope, phi, result_loc); - } else { - IrInstSrc *void_inst = ir_mark_gen(ir_build_const_void(irb, child_scope, block_node)); - result = ir_lval_wrap(irb, parent_scope, void_inst, lval, result_loc); - } - if (!is_return_from_fn) - return result; - - // no need for save_err_ret_addr because this cannot return error - // only generate unconditional defers - - ir_mark_gen(ir_build_add_implicit_return_type(irb, child_scope, block_node, result, nullptr)); - ResultLocReturn *result_loc_ret = heap::c_allocator.create(); - result_loc_ret->base.id = ResultLocIdReturn; - ir_build_reset_result(irb, parent_scope, block_node, &result_loc_ret->base); - ir_mark_gen(ir_build_end_expr(irb, parent_scope, block_node, result, &result_loc_ret->base)); - if (!ir_gen_defers_for_block(irb, child_scope, outer_block_scope, nullptr, nullptr)) - return irb->codegen->invalid_inst_src; - return ir_mark_gen(ir_build_return_src(irb, child_scope, result->base.source_node, result)); -} - -static IrInstSrc *ir_gen_bin_op_id(IrBuilderSrc *irb, Scope *scope, AstNode *node, IrBinOp op_id) { - Scope *inner_scope = scope; - if (op_id == IrBinOpArrayCat || op_id == IrBinOpArrayMult) { - inner_scope = create_comptime_scope(irb->codegen, node, scope); - } - - IrInstSrc *op1 = ir_gen_node(irb, node->data.bin_op_expr.op1, inner_scope); - IrInstSrc *op2 = ir_gen_node(irb, node->data.bin_op_expr.op2, inner_scope); - - if (op1 == irb->codegen->invalid_inst_src || op2 == irb->codegen->invalid_inst_src) - return irb->codegen->invalid_inst_src; - - return ir_build_bin_op(irb, scope, node, op_id, op1, op2, true); -} - -static IrInstSrc *ir_gen_merge_err_sets(IrBuilderSrc *irb, Scope *scope, AstNode *node) { - IrInstSrc *op1 = ir_gen_node(irb, node->data.bin_op_expr.op1, scope); - IrInstSrc *op2 = ir_gen_node(irb, node->data.bin_op_expr.op2, scope); - - if (op1 == irb->codegen->invalid_inst_src || op2 == irb->codegen->invalid_inst_src) - return irb->codegen->invalid_inst_src; - - // TODO only pass type_name when the || operator is the top level AST node in the var decl expr - Buf bare_name = BUF_INIT; - Buf *type_name = get_anon_type_name(irb->codegen, irb->exec, "error", scope, node, &bare_name); - - return ir_build_merge_err_sets(irb, scope, node, op1, op2, type_name); -} - -static IrInstSrc *ir_gen_assign(IrBuilderSrc *irb, Scope *scope, AstNode *node) { - IrInstSrc *lvalue = ir_gen_node_extra(irb, node->data.bin_op_expr.op1, scope, LValAssign, nullptr); - if (lvalue == irb->codegen->invalid_inst_src) - return irb->codegen->invalid_inst_src; - - ResultLocInstruction *result_loc_inst = heap::c_allocator.create(); - result_loc_inst->base.id = ResultLocIdInstruction; - result_loc_inst->base.source_instruction = lvalue; - ir_ref_instruction(lvalue, irb->current_basic_block); - ir_build_reset_result(irb, scope, node, &result_loc_inst->base); - - IrInstSrc *rvalue = ir_gen_node_extra(irb, node->data.bin_op_expr.op2, scope, LValNone, - &result_loc_inst->base); - if (rvalue == irb->codegen->invalid_inst_src) - return irb->codegen->invalid_inst_src; - - return ir_build_const_void(irb, scope, node); -} - -static IrInstSrc *ir_gen_assign_op(IrBuilderSrc *irb, Scope *scope, AstNode *node, IrBinOp op_id) { - IrInstSrc *lvalue = ir_gen_node_extra(irb, node->data.bin_op_expr.op1, scope, LValAssign, nullptr); - if (lvalue == irb->codegen->invalid_inst_src) - return lvalue; - IrInstSrc *op1 = ir_build_load_ptr(irb, scope, node->data.bin_op_expr.op1, lvalue); - IrInstSrc *op2 = ir_gen_node(irb, node->data.bin_op_expr.op2, scope); - if (op2 == irb->codegen->invalid_inst_src) - return op2; - IrInstSrc *result = ir_build_bin_op(irb, scope, node, op_id, op1, op2, true); - ir_build_store_ptr(irb, scope, node, lvalue, result); - return ir_build_const_void(irb, scope, node); -} - -static IrInstSrc *ir_gen_bool_or(IrBuilderSrc *irb, Scope *scope, AstNode *node) { - assert(node->type == NodeTypeBinOpExpr); - - IrInstSrc *val1 = ir_gen_node(irb, node->data.bin_op_expr.op1, scope); - if (val1 == irb->codegen->invalid_inst_src) - return irb->codegen->invalid_inst_src; - IrBasicBlockSrc *post_val1_block = irb->current_basic_block; - - IrInstSrc *is_comptime; - if (ir_should_inline(irb->exec, scope)) { - is_comptime = ir_build_const_bool(irb, scope, node, true); - } else { - is_comptime = ir_build_test_comptime(irb, scope, node, val1); - } - - // block for when val1 == false - IrBasicBlockSrc *false_block = ir_create_basic_block(irb, scope, "BoolOrFalse"); - // block for when val1 == true (don't even evaluate the second part) - IrBasicBlockSrc *true_block = ir_create_basic_block(irb, scope, "BoolOrTrue"); - - ir_build_cond_br(irb, scope, node, val1, true_block, false_block, is_comptime); - - ir_set_cursor_at_end_and_append_block(irb, false_block); - IrInstSrc *val2 = ir_gen_node(irb, node->data.bin_op_expr.op2, scope); - if (val2 == irb->codegen->invalid_inst_src) - return irb->codegen->invalid_inst_src; - IrBasicBlockSrc *post_val2_block = irb->current_basic_block; - - ir_build_br(irb, scope, node, true_block, is_comptime); - - ir_set_cursor_at_end_and_append_block(irb, true_block); - - IrInstSrc **incoming_values = heap::c_allocator.allocate(2); - incoming_values[0] = val1; - incoming_values[1] = val2; - IrBasicBlockSrc **incoming_blocks = heap::c_allocator.allocate(2); - incoming_blocks[0] = post_val1_block; - incoming_blocks[1] = post_val2_block; - - return ir_build_phi(irb, scope, node, 2, incoming_blocks, incoming_values, nullptr); -} - -static IrInstSrc *ir_gen_bool_and(IrBuilderSrc *irb, Scope *scope, AstNode *node) { - assert(node->type == NodeTypeBinOpExpr); - - IrInstSrc *val1 = ir_gen_node(irb, node->data.bin_op_expr.op1, scope); - if (val1 == irb->codegen->invalid_inst_src) - return irb->codegen->invalid_inst_src; - IrBasicBlockSrc *post_val1_block = irb->current_basic_block; - - IrInstSrc *is_comptime; - if (ir_should_inline(irb->exec, scope)) { - is_comptime = ir_build_const_bool(irb, scope, node, true); - } else { - is_comptime = ir_build_test_comptime(irb, scope, node, val1); - } - - // block for when val1 == true - IrBasicBlockSrc *true_block = ir_create_basic_block(irb, scope, "BoolAndTrue"); - // block for when val1 == false (don't even evaluate the second part) - IrBasicBlockSrc *false_block = ir_create_basic_block(irb, scope, "BoolAndFalse"); - - ir_build_cond_br(irb, scope, node, val1, true_block, false_block, is_comptime); - - ir_set_cursor_at_end_and_append_block(irb, true_block); - IrInstSrc *val2 = ir_gen_node(irb, node->data.bin_op_expr.op2, scope); - if (val2 == irb->codegen->invalid_inst_src) - return irb->codegen->invalid_inst_src; - IrBasicBlockSrc *post_val2_block = irb->current_basic_block; - - ir_build_br(irb, scope, node, false_block, is_comptime); - - ir_set_cursor_at_end_and_append_block(irb, false_block); - - IrInstSrc **incoming_values = heap::c_allocator.allocate(2); - incoming_values[0] = val1; - incoming_values[1] = val2; - IrBasicBlockSrc **incoming_blocks = heap::c_allocator.allocate(2); - incoming_blocks[0] = post_val1_block; - incoming_blocks[1] = post_val2_block; - - return ir_build_phi(irb, scope, node, 2, incoming_blocks, incoming_values, nullptr); -} - -static ResultLocPeerParent *ir_build_result_peers(IrBuilderSrc *irb, IrInstSrc *cond_br_inst, - IrBasicBlockSrc *end_block, ResultLoc *parent, IrInstSrc *is_comptime) -{ - ResultLocPeerParent *peer_parent = heap::c_allocator.create(); - peer_parent->base.id = ResultLocIdPeerParent; - peer_parent->base.source_instruction = cond_br_inst; - peer_parent->base.allow_write_through_const = parent->allow_write_through_const; - peer_parent->end_bb = end_block; - peer_parent->is_comptime = is_comptime; - peer_parent->parent = parent; - - IrInstSrc *popped_inst = irb->current_basic_block->instruction_list.pop(); - ir_assert(popped_inst == cond_br_inst, &cond_br_inst->base); - - ir_build_reset_result(irb, cond_br_inst->base.scope, cond_br_inst->base.source_node, &peer_parent->base); - irb->current_basic_block->instruction_list.append(popped_inst); - - return peer_parent; -} - -static ResultLocPeerParent *ir_build_binary_result_peers(IrBuilderSrc *irb, IrInstSrc *cond_br_inst, - IrBasicBlockSrc *else_block, IrBasicBlockSrc *end_block, ResultLoc *parent, IrInstSrc *is_comptime) -{ - ResultLocPeerParent *peer_parent = ir_build_result_peers(irb, cond_br_inst, end_block, parent, is_comptime); - - peer_parent->peers.append(create_peer_result(peer_parent)); - peer_parent->peers.last()->next_bb = else_block; - - peer_parent->peers.append(create_peer_result(peer_parent)); - peer_parent->peers.last()->next_bb = end_block; - - return peer_parent; -} - -static IrInstSrc *ir_gen_orelse(IrBuilderSrc *irb, Scope *parent_scope, AstNode *node, LVal lval, - ResultLoc *result_loc) -{ - assert(node->type == NodeTypeBinOpExpr); - - AstNode *op1_node = node->data.bin_op_expr.op1; - AstNode *op2_node = node->data.bin_op_expr.op2; - - IrInstSrc *maybe_ptr = ir_gen_node_extra(irb, op1_node, parent_scope, LValPtr, nullptr); - if (maybe_ptr == irb->codegen->invalid_inst_src) - return irb->codegen->invalid_inst_src; - - IrInstSrc *maybe_val = ir_build_load_ptr(irb, parent_scope, node, maybe_ptr); - IrInstSrc *is_non_null = ir_build_test_non_null_src(irb, parent_scope, node, maybe_val); - - IrInstSrc *is_comptime; - if (ir_should_inline(irb->exec, parent_scope)) { - is_comptime = ir_build_const_bool(irb, parent_scope, node, true); - } else { - is_comptime = ir_build_test_comptime(irb, parent_scope, node, is_non_null); - } - - IrBasicBlockSrc *ok_block = ir_create_basic_block(irb, parent_scope, "OptionalNonNull"); - IrBasicBlockSrc *null_block = ir_create_basic_block(irb, parent_scope, "OptionalNull"); - IrBasicBlockSrc *end_block = ir_create_basic_block(irb, parent_scope, "OptionalEnd"); - IrInstSrc *cond_br_inst = ir_build_cond_br(irb, parent_scope, node, is_non_null, ok_block, null_block, is_comptime); - - ResultLocPeerParent *peer_parent = ir_build_binary_result_peers(irb, cond_br_inst, ok_block, end_block, - result_loc, is_comptime); - - ir_set_cursor_at_end_and_append_block(irb, null_block); - IrInstSrc *null_result = ir_gen_node_extra(irb, op2_node, parent_scope, LValNone, - &peer_parent->peers.at(0)->base); - if (null_result == irb->codegen->invalid_inst_src) - return irb->codegen->invalid_inst_src; - IrBasicBlockSrc *after_null_block = irb->current_basic_block; - if (!instr_is_unreachable(null_result)) - ir_mark_gen(ir_build_br(irb, parent_scope, node, end_block, is_comptime)); - - ir_set_cursor_at_end_and_append_block(irb, ok_block); - IrInstSrc *unwrapped_ptr = ir_build_optional_unwrap_ptr(irb, parent_scope, node, maybe_ptr, false); - IrInstSrc *unwrapped_payload = ir_build_load_ptr(irb, parent_scope, node, unwrapped_ptr); - ir_build_end_expr(irb, parent_scope, node, unwrapped_payload, &peer_parent->peers.at(1)->base); - IrBasicBlockSrc *after_ok_block = irb->current_basic_block; - ir_build_br(irb, parent_scope, node, end_block, is_comptime); - - ir_set_cursor_at_end_and_append_block(irb, end_block); - IrInstSrc **incoming_values = heap::c_allocator.allocate(2); - incoming_values[0] = null_result; - incoming_values[1] = unwrapped_payload; - IrBasicBlockSrc **incoming_blocks = heap::c_allocator.allocate(2); - incoming_blocks[0] = after_null_block; - incoming_blocks[1] = after_ok_block; - IrInstSrc *phi = ir_build_phi(irb, parent_scope, node, 2, incoming_blocks, incoming_values, peer_parent); - return ir_lval_wrap(irb, parent_scope, phi, lval, result_loc); -} - -static IrInstSrc *ir_gen_error_union(IrBuilderSrc *irb, Scope *parent_scope, AstNode *node) { - assert(node->type == NodeTypeBinOpExpr); - - AstNode *op1_node = node->data.bin_op_expr.op1; - AstNode *op2_node = node->data.bin_op_expr.op2; - - IrInstSrc *err_set = ir_gen_node(irb, op1_node, parent_scope); - if (err_set == irb->codegen->invalid_inst_src) - return irb->codegen->invalid_inst_src; - - IrInstSrc *payload = ir_gen_node(irb, op2_node, parent_scope); - if (payload == irb->codegen->invalid_inst_src) - return irb->codegen->invalid_inst_src; - - return ir_build_error_union(irb, parent_scope, node, err_set, payload); -} - -static IrInstSrc *ir_gen_bin_op(IrBuilderSrc *irb, Scope *scope, AstNode *node, LVal lval, ResultLoc *result_loc) { - assert(node->type == NodeTypeBinOpExpr); - - BinOpType bin_op_type = node->data.bin_op_expr.bin_op; - switch (bin_op_type) { - case BinOpTypeInvalid: - zig_unreachable(); - case BinOpTypeAssign: - return ir_lval_wrap(irb, scope, ir_gen_assign(irb, scope, node), lval, result_loc); - case BinOpTypeAssignTimes: - return ir_lval_wrap(irb, scope, ir_gen_assign_op(irb, scope, node, IrBinOpMult), lval, result_loc); - case BinOpTypeAssignTimesWrap: - return ir_lval_wrap(irb, scope, ir_gen_assign_op(irb, scope, node, IrBinOpMultWrap), lval, result_loc); - case BinOpTypeAssignDiv: - return ir_lval_wrap(irb, scope, ir_gen_assign_op(irb, scope, node, IrBinOpDivUnspecified), lval, result_loc); - case BinOpTypeAssignMod: - return ir_lval_wrap(irb, scope, ir_gen_assign_op(irb, scope, node, IrBinOpRemUnspecified), lval, result_loc); - case BinOpTypeAssignPlus: - return ir_lval_wrap(irb, scope, ir_gen_assign_op(irb, scope, node, IrBinOpAdd), lval, result_loc); - case BinOpTypeAssignPlusWrap: - return ir_lval_wrap(irb, scope, ir_gen_assign_op(irb, scope, node, IrBinOpAddWrap), lval, result_loc); - case BinOpTypeAssignMinus: - return ir_lval_wrap(irb, scope, ir_gen_assign_op(irb, scope, node, IrBinOpSub), lval, result_loc); - case BinOpTypeAssignMinusWrap: - return ir_lval_wrap(irb, scope, ir_gen_assign_op(irb, scope, node, IrBinOpSubWrap), lval, result_loc); - case BinOpTypeAssignBitShiftLeft: - return ir_lval_wrap(irb, scope, ir_gen_assign_op(irb, scope, node, IrBinOpBitShiftLeftLossy), lval, result_loc); - case BinOpTypeAssignBitShiftRight: - return ir_lval_wrap(irb, scope, ir_gen_assign_op(irb, scope, node, IrBinOpBitShiftRightLossy), lval, result_loc); - case BinOpTypeAssignBitAnd: - return ir_lval_wrap(irb, scope, ir_gen_assign_op(irb, scope, node, IrBinOpBinAnd), lval, result_loc); - case BinOpTypeAssignBitXor: - return ir_lval_wrap(irb, scope, ir_gen_assign_op(irb, scope, node, IrBinOpBinXor), lval, result_loc); - case BinOpTypeAssignBitOr: - return ir_lval_wrap(irb, scope, ir_gen_assign_op(irb, scope, node, IrBinOpBinOr), lval, result_loc); - case BinOpTypeBoolOr: - return ir_lval_wrap(irb, scope, ir_gen_bool_or(irb, scope, node), lval, result_loc); - case BinOpTypeBoolAnd: - return ir_lval_wrap(irb, scope, ir_gen_bool_and(irb, scope, node), lval, result_loc); - case BinOpTypeCmpEq: - return ir_lval_wrap(irb, scope, ir_gen_bin_op_id(irb, scope, node, IrBinOpCmpEq), lval, result_loc); - case BinOpTypeCmpNotEq: - return ir_lval_wrap(irb, scope, ir_gen_bin_op_id(irb, scope, node, IrBinOpCmpNotEq), lval, result_loc); - case BinOpTypeCmpLessThan: - return ir_lval_wrap(irb, scope, ir_gen_bin_op_id(irb, scope, node, IrBinOpCmpLessThan), lval, result_loc); - case BinOpTypeCmpGreaterThan: - return ir_lval_wrap(irb, scope, ir_gen_bin_op_id(irb, scope, node, IrBinOpCmpGreaterThan), lval, result_loc); - case BinOpTypeCmpLessOrEq: - return ir_lval_wrap(irb, scope, ir_gen_bin_op_id(irb, scope, node, IrBinOpCmpLessOrEq), lval, result_loc); - case BinOpTypeCmpGreaterOrEq: - return ir_lval_wrap(irb, scope, ir_gen_bin_op_id(irb, scope, node, IrBinOpCmpGreaterOrEq), lval, result_loc); - case BinOpTypeBinOr: - return ir_lval_wrap(irb, scope, ir_gen_bin_op_id(irb, scope, node, IrBinOpBinOr), lval, result_loc); - case BinOpTypeBinXor: - return ir_lval_wrap(irb, scope, ir_gen_bin_op_id(irb, scope, node, IrBinOpBinXor), lval, result_loc); - case BinOpTypeBinAnd: - return ir_lval_wrap(irb, scope, ir_gen_bin_op_id(irb, scope, node, IrBinOpBinAnd), lval, result_loc); - case BinOpTypeBitShiftLeft: - return ir_lval_wrap(irb, scope, ir_gen_bin_op_id(irb, scope, node, IrBinOpBitShiftLeftLossy), lval, result_loc); - case BinOpTypeBitShiftRight: - return ir_lval_wrap(irb, scope, ir_gen_bin_op_id(irb, scope, node, IrBinOpBitShiftRightLossy), lval, result_loc); - case BinOpTypeAdd: - return ir_lval_wrap(irb, scope, ir_gen_bin_op_id(irb, scope, node, IrBinOpAdd), lval, result_loc); - case BinOpTypeAddWrap: - return ir_lval_wrap(irb, scope, ir_gen_bin_op_id(irb, scope, node, IrBinOpAddWrap), lval, result_loc); - case BinOpTypeSub: - return ir_lval_wrap(irb, scope, ir_gen_bin_op_id(irb, scope, node, IrBinOpSub), lval, result_loc); - case BinOpTypeSubWrap: - return ir_lval_wrap(irb, scope, ir_gen_bin_op_id(irb, scope, node, IrBinOpSubWrap), lval, result_loc); - case BinOpTypeMult: - return ir_lval_wrap(irb, scope, ir_gen_bin_op_id(irb, scope, node, IrBinOpMult), lval, result_loc); - case BinOpTypeMultWrap: - return ir_lval_wrap(irb, scope, ir_gen_bin_op_id(irb, scope, node, IrBinOpMultWrap), lval, result_loc); - case BinOpTypeDiv: - return ir_lval_wrap(irb, scope, ir_gen_bin_op_id(irb, scope, node, IrBinOpDivUnspecified), lval, result_loc); - case BinOpTypeMod: - return ir_lval_wrap(irb, scope, ir_gen_bin_op_id(irb, scope, node, IrBinOpRemUnspecified), lval, result_loc); - case BinOpTypeArrayCat: - return ir_lval_wrap(irb, scope, ir_gen_bin_op_id(irb, scope, node, IrBinOpArrayCat), lval, result_loc); - case BinOpTypeArrayMult: - return ir_lval_wrap(irb, scope, ir_gen_bin_op_id(irb, scope, node, IrBinOpArrayMult), lval, result_loc); - case BinOpTypeMergeErrorSets: - return ir_lval_wrap(irb, scope, ir_gen_merge_err_sets(irb, scope, node), lval, result_loc); - case BinOpTypeUnwrapOptional: - return ir_gen_orelse(irb, scope, node, lval, result_loc); - case BinOpTypeErrorUnion: - return ir_lval_wrap(irb, scope, ir_gen_error_union(irb, scope, node), lval, result_loc); - } - zig_unreachable(); -} - -static IrInstSrc *ir_gen_int_lit(IrBuilderSrc *irb, Scope *scope, AstNode *node) { - assert(node->type == NodeTypeIntLiteral); - - return ir_build_const_bigint(irb, scope, node, node->data.int_literal.bigint); -} - -static IrInstSrc *ir_gen_float_lit(IrBuilderSrc *irb, Scope *scope, AstNode *node) { - assert(node->type == NodeTypeFloatLiteral); - - if (node->data.float_literal.overflow) { - add_node_error(irb->codegen, node, buf_sprintf("float literal out of range of any type")); - return irb->codegen->invalid_inst_src; - } - - return ir_build_const_bigfloat(irb, scope, node, node->data.float_literal.bigfloat); -} - -static IrInstSrc *ir_gen_char_lit(IrBuilderSrc *irb, Scope *scope, AstNode *node) { - assert(node->type == NodeTypeCharLiteral); - - return ir_build_const_uint(irb, scope, node, node->data.char_literal.value); -} - -static IrInstSrc *ir_gen_null_literal(IrBuilderSrc *irb, Scope *scope, AstNode *node) { - assert(node->type == NodeTypeNullLiteral); - - return ir_build_const_null(irb, scope, node); -} - -static void populate_invalid_variable_in_scope(CodeGen *g, Scope *scope, AstNode *node, Buf *var_name) { - ScopeDecls *scope_decls = nullptr; - while (scope != nullptr) { - if (scope->id == ScopeIdDecls) { - scope_decls = reinterpret_cast(scope); - } - scope = scope->parent; - } - TldVar *tld_var = heap::c_allocator.create(); - init_tld(&tld_var->base, TldIdVar, var_name, VisibModPub, node, &scope_decls->base); - tld_var->base.resolution = TldResolutionInvalid; - tld_var->var = add_variable(g, node, &scope_decls->base, var_name, false, - g->invalid_inst_gen->value, &tld_var->base, g->builtin_types.entry_invalid); - scope_decls->decl_table.put(var_name, &tld_var->base); -} - -static IrInstSrc *ir_gen_symbol(IrBuilderSrc *irb, Scope *scope, AstNode *node, LVal lval, ResultLoc *result_loc) { - Error err; - assert(node->type == NodeTypeSymbol); - - Buf *variable_name = node->data.symbol_expr.symbol; - - if (buf_eql_str(variable_name, "_")) { - if (lval == LValAssign) { - IrInstSrcConst *const_instruction = ir_build_instruction(irb, scope, node); - const_instruction->value = irb->codegen->pass1_arena->create(); - const_instruction->value->type = get_pointer_to_type(irb->codegen, - irb->codegen->builtin_types.entry_void, false); - const_instruction->value->special = ConstValSpecialStatic; - const_instruction->value->data.x_ptr.special = ConstPtrSpecialDiscard; - return &const_instruction->base; - } else { - add_node_error(irb->codegen, node, buf_sprintf("`_` may only be used to assign things to")); - return irb->codegen->invalid_inst_src; - } - } - - ZigType *primitive_type; - if ((err = get_primitive_type(irb->codegen, variable_name, &primitive_type))) { - if (err == ErrorOverflow) { - add_node_error(irb->codegen, node, - buf_sprintf("primitive integer type '%s' exceeds maximum bit width of 65535", - buf_ptr(variable_name))); - return irb->codegen->invalid_inst_src; - } - assert(err == ErrorPrimitiveTypeNotFound); - } else { - IrInstSrc *value = ir_build_const_type(irb, scope, node, primitive_type); - if (lval == LValPtr || lval == LValAssign) { - return ir_build_ref_src(irb, scope, node, value); - } else { - return ir_expr_wrap(irb, scope, value, result_loc); - } - } - - ScopeFnDef *crossed_fndef_scope; - ZigVar *var = find_variable(irb->codegen, scope, variable_name, &crossed_fndef_scope); - if (var) { - IrInstSrc *var_ptr = ir_build_var_ptr_x(irb, scope, node, var, crossed_fndef_scope); - if (lval == LValPtr || lval == LValAssign) { - return var_ptr; - } else { - return ir_expr_wrap(irb, scope, ir_build_load_ptr(irb, scope, node, var_ptr), result_loc); - } - } - - Tld *tld = find_decl(irb->codegen, scope, variable_name); - if (tld) { - IrInstSrc *decl_ref = ir_build_decl_ref(irb, scope, node, tld, lval); - if (lval == LValPtr || lval == LValAssign) { - return decl_ref; - } else { - return ir_expr_wrap(irb, scope, decl_ref, result_loc); - } - } - - if (get_container_scope(node->owner)->any_imports_failed) { - // skip the error message since we had a failing import in this file - // if an import breaks we don't need redundant undeclared identifier errors - return irb->codegen->invalid_inst_src; - } - - return ir_build_undeclared_identifier(irb, scope, node, variable_name); -} - -static IrInstSrc *ir_gen_array_access(IrBuilderSrc *irb, Scope *scope, AstNode *node, LVal lval, - ResultLoc *result_loc) -{ - assert(node->type == NodeTypeArrayAccessExpr); - - AstNode *array_ref_node = node->data.array_access_expr.array_ref_expr; - IrInstSrc *array_ref_instruction = ir_gen_node_extra(irb, array_ref_node, scope, LValPtr, nullptr); - if (array_ref_instruction == irb->codegen->invalid_inst_src) - return array_ref_instruction; - - // Create an usize-typed result location to hold the subscript value, this - // makes it possible for the compiler to infer the subscript expression type - // if needed - IrInstSrc *usize_type_inst = ir_build_const_type(irb, scope, node, irb->codegen->builtin_types.entry_usize); - ResultLocCast *result_loc_cast = ir_build_cast_result_loc(irb, usize_type_inst, no_result_loc()); - - AstNode *subscript_node = node->data.array_access_expr.subscript; - IrInstSrc *subscript_value = ir_gen_node_extra(irb, subscript_node, scope, LValNone, &result_loc_cast->base); - if (subscript_value == irb->codegen->invalid_inst_src) - return irb->codegen->invalid_inst_src; - - IrInstSrc *subscript_instruction = ir_build_implicit_cast(irb, scope, subscript_node, subscript_value, result_loc_cast); - - IrInstSrc *ptr_instruction = ir_build_elem_ptr(irb, scope, node, array_ref_instruction, - subscript_instruction, true, PtrLenSingle, nullptr); - if (lval == LValPtr || lval == LValAssign) - return ptr_instruction; - - IrInstSrc *load_ptr = ir_build_load_ptr(irb, scope, node, ptr_instruction); - return ir_expr_wrap(irb, scope, load_ptr, result_loc); -} - -static IrInstSrc *ir_gen_field_access(IrBuilderSrc *irb, Scope *scope, AstNode *node) { - assert(node->type == NodeTypeFieldAccessExpr); - - AstNode *container_ref_node = node->data.field_access_expr.struct_expr; - Buf *field_name = node->data.field_access_expr.field_name; - - IrInstSrc *container_ref_instruction = ir_gen_node_extra(irb, container_ref_node, scope, LValPtr, nullptr); - if (container_ref_instruction == irb->codegen->invalid_inst_src) - return container_ref_instruction; - - return ir_build_field_ptr(irb, scope, node, container_ref_instruction, field_name, false); -} - -static IrInstSrc *ir_gen_overflow_op(IrBuilderSrc *irb, Scope *scope, AstNode *node, IrOverflowOp op) { - assert(node->type == NodeTypeFnCallExpr); - - AstNode *type_node = node->data.fn_call_expr.params.at(0); - AstNode *op1_node = node->data.fn_call_expr.params.at(1); - AstNode *op2_node = node->data.fn_call_expr.params.at(2); - AstNode *result_ptr_node = node->data.fn_call_expr.params.at(3); - - - IrInstSrc *type_value = ir_gen_node(irb, type_node, scope); - if (type_value == irb->codegen->invalid_inst_src) - return irb->codegen->invalid_inst_src; - - IrInstSrc *op1 = ir_gen_node(irb, op1_node, scope); - if (op1 == irb->codegen->invalid_inst_src) - return irb->codegen->invalid_inst_src; - - IrInstSrc *op2 = ir_gen_node(irb, op2_node, scope); - if (op2 == irb->codegen->invalid_inst_src) - return irb->codegen->invalid_inst_src; - - IrInstSrc *result_ptr = ir_gen_node(irb, result_ptr_node, scope); - if (result_ptr == irb->codegen->invalid_inst_src) - return irb->codegen->invalid_inst_src; - - return ir_build_overflow_op_src(irb, scope, node, op, type_value, op1, op2, result_ptr); -} - -static IrInstSrc *ir_gen_mul_add(IrBuilderSrc *irb, Scope *scope, AstNode *node) { - assert(node->type == NodeTypeFnCallExpr); - - AstNode *type_node = node->data.fn_call_expr.params.at(0); - AstNode *op1_node = node->data.fn_call_expr.params.at(1); - AstNode *op2_node = node->data.fn_call_expr.params.at(2); - AstNode *op3_node = node->data.fn_call_expr.params.at(3); - - IrInstSrc *type_value = ir_gen_node(irb, type_node, scope); - if (type_value == irb->codegen->invalid_inst_src) - return irb->codegen->invalid_inst_src; - - IrInstSrc *op1 = ir_gen_node(irb, op1_node, scope); - if (op1 == irb->codegen->invalid_inst_src) - return irb->codegen->invalid_inst_src; - - IrInstSrc *op2 = ir_gen_node(irb, op2_node, scope); - if (op2 == irb->codegen->invalid_inst_src) - return irb->codegen->invalid_inst_src; - - IrInstSrc *op3 = ir_gen_node(irb, op3_node, scope); - if (op3 == irb->codegen->invalid_inst_src) - return irb->codegen->invalid_inst_src; - - return ir_build_mul_add_src(irb, scope, node, type_value, op1, op2, op3); -} - -static IrInstSrc *ir_gen_this(IrBuilderSrc *irb, Scope *orig_scope, AstNode *node) { - for (Scope *it_scope = orig_scope; it_scope != nullptr; it_scope = it_scope->parent) { - if (it_scope->id == ScopeIdDecls) { - ScopeDecls *decls_scope = (ScopeDecls *)it_scope; - ZigType *container_type = decls_scope->container_type; - if (container_type != nullptr) { - return ir_build_const_type(irb, orig_scope, node, container_type); - } else { - return ir_build_const_import(irb, orig_scope, node, decls_scope->import); - } - } - } - zig_unreachable(); -} - -static IrInstSrc *ir_gen_async_call(IrBuilderSrc *irb, Scope *scope, AstNode *await_node, AstNode *call_node, - LVal lval, ResultLoc *result_loc) -{ - if (call_node->data.fn_call_expr.params.length != 4) { - add_node_error(irb->codegen, call_node, - buf_sprintf("expected 4 arguments, found %" ZIG_PRI_usize, - call_node->data.fn_call_expr.params.length)); - return irb->codegen->invalid_inst_src; - } - - AstNode *bytes_node = call_node->data.fn_call_expr.params.at(0); - IrInstSrc *bytes = ir_gen_node(irb, bytes_node, scope); - if (bytes == irb->codegen->invalid_inst_src) - return bytes; - - AstNode *ret_ptr_node = call_node->data.fn_call_expr.params.at(1); - IrInstSrc *ret_ptr = ir_gen_node(irb, ret_ptr_node, scope); - if (ret_ptr == irb->codegen->invalid_inst_src) - return ret_ptr; - - AstNode *fn_ref_node = call_node->data.fn_call_expr.params.at(2); - IrInstSrc *fn_ref = ir_gen_node(irb, fn_ref_node, scope); - if (fn_ref == irb->codegen->invalid_inst_src) - return fn_ref; - - CallModifier modifier = (await_node == nullptr) ? CallModifierAsync : CallModifierNone; - bool is_async_call_builtin = true; - AstNode *args_node = call_node->data.fn_call_expr.params.at(3); - if (args_node->type == NodeTypeContainerInitExpr) { - if (args_node->data.container_init_expr.kind == ContainerInitKindArray || - args_node->data.container_init_expr.entries.length == 0) - { - size_t arg_count = args_node->data.container_init_expr.entries.length; - IrInstSrc **args = heap::c_allocator.allocate(arg_count); - for (size_t i = 0; i < arg_count; i += 1) { - AstNode *arg_node = args_node->data.container_init_expr.entries.at(i); - IrInstSrc *arg = ir_gen_node(irb, arg_node, scope); - if (arg == irb->codegen->invalid_inst_src) - return arg; - args[i] = arg; - } - - IrInstSrc *call = ir_build_call_src(irb, scope, call_node, nullptr, fn_ref, arg_count, args, - ret_ptr, modifier, is_async_call_builtin, bytes, result_loc); - return ir_lval_wrap(irb, scope, call, lval, result_loc); - } else { - exec_add_error_node(irb->codegen, irb->exec, args_node, - buf_sprintf("TODO: @asyncCall with anon struct literal")); - return irb->codegen->invalid_inst_src; - } - } - IrInstSrc *args = ir_gen_node(irb, args_node, scope); - if (args == irb->codegen->invalid_inst_src) - return args; - - IrInstSrc *call = ir_build_async_call_extra(irb, scope, call_node, modifier, fn_ref, ret_ptr, bytes, args, result_loc); - return ir_lval_wrap(irb, scope, call, lval, result_loc); -} - -static IrInstSrc *ir_gen_fn_call_with_args(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, - AstNode *fn_ref_node, CallModifier modifier, IrInstSrc *options, - AstNode **args_ptr, size_t args_len, LVal lval, ResultLoc *result_loc) -{ - IrInstSrc *fn_ref = ir_gen_node(irb, fn_ref_node, scope); - if (fn_ref == irb->codegen->invalid_inst_src) - return fn_ref; - - IrInstSrc *fn_type = ir_build_typeof_1(irb, scope, source_node, fn_ref); - - IrInstSrc **args = heap::c_allocator.allocate(args_len); - for (size_t i = 0; i < args_len; i += 1) { - AstNode *arg_node = args_ptr[i]; - - IrInstSrc *arg_index = ir_build_const_usize(irb, scope, arg_node, i); - IrInstSrc *arg_type = ir_build_arg_type(irb, scope, source_node, fn_type, arg_index, true); - ResultLoc *no_result = no_result_loc(); - ir_build_reset_result(irb, scope, source_node, no_result); - ResultLocCast *result_loc_cast = ir_build_cast_result_loc(irb, arg_type, no_result); - - IrInstSrc *arg = ir_gen_node_extra(irb, arg_node, scope, LValNone, &result_loc_cast->base); - if (arg == irb->codegen->invalid_inst_src) - return arg; - - args[i] = ir_build_implicit_cast(irb, scope, arg_node, arg, result_loc_cast); - } - - IrInstSrc *fn_call; - if (options != nullptr) { - fn_call = ir_build_call_args(irb, scope, source_node, options, fn_ref, args, args_len, result_loc); - } else { - fn_call = ir_build_call_src(irb, scope, source_node, nullptr, fn_ref, args_len, args, nullptr, - modifier, false, nullptr, result_loc); - } - return ir_lval_wrap(irb, scope, fn_call, lval, result_loc); -} - -static IrInstSrc *ir_gen_builtin_fn_call(IrBuilderSrc *irb, Scope *scope, AstNode *node, LVal lval, - ResultLoc *result_loc) -{ - assert(node->type == NodeTypeFnCallExpr); - - AstNode *fn_ref_expr = node->data.fn_call_expr.fn_ref_expr; - Buf *name = fn_ref_expr->data.symbol_expr.symbol; - auto entry = irb->codegen->builtin_fn_table.maybe_get(name); - - if (!entry) { - add_node_error(irb->codegen, node, - buf_sprintf("invalid builtin function: '%s'", buf_ptr(name))); - return irb->codegen->invalid_inst_src; - } - - BuiltinFnEntry *builtin_fn = entry->value; - size_t actual_param_count = node->data.fn_call_expr.params.length; - - if (builtin_fn->param_count != SIZE_MAX && builtin_fn->param_count != actual_param_count) { - add_node_error(irb->codegen, node, - buf_sprintf("expected %" ZIG_PRI_usize " argument(s), found %" ZIG_PRI_usize, - builtin_fn->param_count, actual_param_count)); - return irb->codegen->invalid_inst_src; - } - - switch (builtin_fn->id) { - case BuiltinFnIdInvalid: - zig_unreachable(); - case BuiltinFnIdTypeof: - { - Scope *sub_scope = create_typeof_scope(irb->codegen, node, scope); - - size_t arg_count = node->data.fn_call_expr.params.length; - - IrInstSrc *type_of; - - if (arg_count == 0) { - add_node_error(irb->codegen, node, - buf_sprintf("expected at least 1 argument, found 0")); - return irb->codegen->invalid_inst_src; - } else if (arg_count == 1) { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, sub_scope); - if (arg0_value == irb->codegen->invalid_inst_src) - return arg0_value; - - type_of = ir_build_typeof_1(irb, scope, node, arg0_value); - } else { - IrInstSrc **args = heap::c_allocator.allocate(arg_count); - for (size_t i = 0; i < arg_count; i += 1) { - AstNode *arg_node = node->data.fn_call_expr.params.at(i); - IrInstSrc *arg = ir_gen_node(irb, arg_node, sub_scope); - if (arg == irb->codegen->invalid_inst_src) - return irb->codegen->invalid_inst_src; - args[i] = arg; - } - - type_of = ir_build_typeof_n(irb, scope, node, args, arg_count); - } - return ir_lval_wrap(irb, scope, type_of, lval, result_loc); - } - case BuiltinFnIdSetCold: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); - if (arg0_value == irb->codegen->invalid_inst_src) - return arg0_value; - - IrInstSrc *set_cold = ir_build_set_cold(irb, scope, node, arg0_value); - return ir_lval_wrap(irb, scope, set_cold, lval, result_loc); - } - case BuiltinFnIdSetRuntimeSafety: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); - if (arg0_value == irb->codegen->invalid_inst_src) - return arg0_value; - - IrInstSrc *set_safety = ir_build_set_runtime_safety(irb, scope, node, arg0_value); - return ir_lval_wrap(irb, scope, set_safety, lval, result_loc); - } - case BuiltinFnIdSetFloatMode: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); - if (arg0_value == irb->codegen->invalid_inst_src) - return arg0_value; - - IrInstSrc *set_float_mode = ir_build_set_float_mode(irb, scope, node, arg0_value); - return ir_lval_wrap(irb, scope, set_float_mode, lval, result_loc); - } - case BuiltinFnIdSizeof: - case BuiltinFnIdBitSizeof: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); - if (arg0_value == irb->codegen->invalid_inst_src) - return arg0_value; - - IrInstSrc *size_of = ir_build_size_of(irb, scope, node, arg0_value, builtin_fn->id == BuiltinFnIdBitSizeof); - return ir_lval_wrap(irb, scope, size_of, lval, result_loc); - } - case BuiltinFnIdImport: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); - if (arg0_value == irb->codegen->invalid_inst_src) - return arg0_value; - - IrInstSrc *import = ir_build_import(irb, scope, node, arg0_value); - return ir_lval_wrap(irb, scope, import, lval, result_loc); - } - case BuiltinFnIdCImport: - { - IrInstSrc *c_import = ir_build_c_import(irb, scope, node); - return ir_lval_wrap(irb, scope, c_import, lval, result_loc); - } - case BuiltinFnIdCInclude: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); - if (arg0_value == irb->codegen->invalid_inst_src) - return arg0_value; - - if (!exec_c_import_buf(irb->exec)) { - add_node_error(irb->codegen, node, buf_sprintf("C include valid only inside C import block")); - return irb->codegen->invalid_inst_src; - } - - IrInstSrc *c_include = ir_build_c_include(irb, scope, node, arg0_value); - return ir_lval_wrap(irb, scope, c_include, lval, result_loc); - } - case BuiltinFnIdCDefine: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); - if (arg0_value == irb->codegen->invalid_inst_src) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - IrInstSrc *arg1_value = ir_gen_node(irb, arg1_node, scope); - if (arg1_value == irb->codegen->invalid_inst_src) - return arg1_value; - - if (!exec_c_import_buf(irb->exec)) { - add_node_error(irb->codegen, node, buf_sprintf("C define valid only inside C import block")); - return irb->codegen->invalid_inst_src; - } - - IrInstSrc *c_define = ir_build_c_define(irb, scope, node, arg0_value, arg1_value); - return ir_lval_wrap(irb, scope, c_define, lval, result_loc); - } - case BuiltinFnIdCUndef: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); - if (arg0_value == irb->codegen->invalid_inst_src) - return arg0_value; - - if (!exec_c_import_buf(irb->exec)) { - add_node_error(irb->codegen, node, buf_sprintf("C undef valid only inside C import block")); - return irb->codegen->invalid_inst_src; - } - - IrInstSrc *c_undef = ir_build_c_undef(irb, scope, node, arg0_value); - return ir_lval_wrap(irb, scope, c_undef, lval, result_loc); - } - case BuiltinFnIdCompileErr: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); - if (arg0_value == irb->codegen->invalid_inst_src) - return arg0_value; - - IrInstSrc *compile_err = ir_build_compile_err(irb, scope, node, arg0_value); - return ir_lval_wrap(irb, scope, compile_err, lval, result_loc); - } - case BuiltinFnIdCompileLog: - { - IrInstSrc **args = heap::c_allocator.allocate(actual_param_count); - - for (size_t i = 0; i < actual_param_count; i += 1) { - AstNode *arg_node = node->data.fn_call_expr.params.at(i); - args[i] = ir_gen_node(irb, arg_node, scope); - if (args[i] == irb->codegen->invalid_inst_src) - return irb->codegen->invalid_inst_src; - } - - IrInstSrc *compile_log = ir_build_compile_log(irb, scope, node, actual_param_count, args); - return ir_lval_wrap(irb, scope, compile_log, lval, result_loc); - } - case BuiltinFnIdErrName: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); - if (arg0_value == irb->codegen->invalid_inst_src) - return arg0_value; - - IrInstSrc *err_name = ir_build_err_name(irb, scope, node, arg0_value); - return ir_lval_wrap(irb, scope, err_name, lval, result_loc); - } - case BuiltinFnIdEmbedFile: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); - if (arg0_value == irb->codegen->invalid_inst_src) - return arg0_value; - - IrInstSrc *embed_file = ir_build_embed_file(irb, scope, node, arg0_value); - return ir_lval_wrap(irb, scope, embed_file, lval, result_loc); - } - case BuiltinFnIdCmpxchgWeak: - case BuiltinFnIdCmpxchgStrong: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); - if (arg0_value == irb->codegen->invalid_inst_src) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - IrInstSrc *arg1_value = ir_gen_node(irb, arg1_node, scope); - if (arg1_value == irb->codegen->invalid_inst_src) - return arg1_value; - - AstNode *arg2_node = node->data.fn_call_expr.params.at(2); - IrInstSrc *arg2_value = ir_gen_node(irb, arg2_node, scope); - if (arg2_value == irb->codegen->invalid_inst_src) - return arg2_value; - - AstNode *arg3_node = node->data.fn_call_expr.params.at(3); - IrInstSrc *arg3_value = ir_gen_node(irb, arg3_node, scope); - if (arg3_value == irb->codegen->invalid_inst_src) - return arg3_value; - - AstNode *arg4_node = node->data.fn_call_expr.params.at(4); - IrInstSrc *arg4_value = ir_gen_node(irb, arg4_node, scope); - if (arg4_value == irb->codegen->invalid_inst_src) - return arg4_value; - - AstNode *arg5_node = node->data.fn_call_expr.params.at(5); - IrInstSrc *arg5_value = ir_gen_node(irb, arg5_node, scope); - if (arg5_value == irb->codegen->invalid_inst_src) - return arg5_value; - - IrInstSrc *cmpxchg = ir_build_cmpxchg_src(irb, scope, node, arg0_value, arg1_value, - arg2_value, arg3_value, arg4_value, arg5_value, (builtin_fn->id == BuiltinFnIdCmpxchgWeak), - result_loc); - return ir_lval_wrap(irb, scope, cmpxchg, lval, result_loc); - } - case BuiltinFnIdFence: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); - if (arg0_value == irb->codegen->invalid_inst_src) - return arg0_value; - - IrInstSrc *fence = ir_build_fence(irb, scope, node, arg0_value); - return ir_lval_wrap(irb, scope, fence, lval, result_loc); - } - case BuiltinFnIdReduce: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); - if (arg0_value == irb->codegen->invalid_inst_src) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - IrInstSrc *arg1_value = ir_gen_node(irb, arg1_node, scope); - if (arg1_value == irb->codegen->invalid_inst_src) - return arg1_value; - - IrInstSrc *reduce = ir_build_reduce(irb, scope, node, arg0_value, arg1_value); - return ir_lval_wrap(irb, scope, reduce, lval, result_loc); - } - case BuiltinFnIdDivExact: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); - if (arg0_value == irb->codegen->invalid_inst_src) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - IrInstSrc *arg1_value = ir_gen_node(irb, arg1_node, scope); - if (arg1_value == irb->codegen->invalid_inst_src) - return arg1_value; - - IrInstSrc *bin_op = ir_build_bin_op(irb, scope, node, IrBinOpDivExact, arg0_value, arg1_value, true); - return ir_lval_wrap(irb, scope, bin_op, lval, result_loc); - } - case BuiltinFnIdDivTrunc: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); - if (arg0_value == irb->codegen->invalid_inst_src) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - IrInstSrc *arg1_value = ir_gen_node(irb, arg1_node, scope); - if (arg1_value == irb->codegen->invalid_inst_src) - return arg1_value; - - IrInstSrc *bin_op = ir_build_bin_op(irb, scope, node, IrBinOpDivTrunc, arg0_value, arg1_value, true); - return ir_lval_wrap(irb, scope, bin_op, lval, result_loc); - } - case BuiltinFnIdDivFloor: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); - if (arg0_value == irb->codegen->invalid_inst_src) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - IrInstSrc *arg1_value = ir_gen_node(irb, arg1_node, scope); - if (arg1_value == irb->codegen->invalid_inst_src) - return arg1_value; - - IrInstSrc *bin_op = ir_build_bin_op(irb, scope, node, IrBinOpDivFloor, arg0_value, arg1_value, true); - return ir_lval_wrap(irb, scope, bin_op, lval, result_loc); - } - case BuiltinFnIdRem: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); - if (arg0_value == irb->codegen->invalid_inst_src) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - IrInstSrc *arg1_value = ir_gen_node(irb, arg1_node, scope); - if (arg1_value == irb->codegen->invalid_inst_src) - return arg1_value; - - IrInstSrc *bin_op = ir_build_bin_op(irb, scope, node, IrBinOpRemRem, arg0_value, arg1_value, true); - return ir_lval_wrap(irb, scope, bin_op, lval, result_loc); - } - case BuiltinFnIdMod: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); - if (arg0_value == irb->codegen->invalid_inst_src) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - IrInstSrc *arg1_value = ir_gen_node(irb, arg1_node, scope); - if (arg1_value == irb->codegen->invalid_inst_src) - return arg1_value; - - IrInstSrc *bin_op = ir_build_bin_op(irb, scope, node, IrBinOpRemMod, arg0_value, arg1_value, true); - return ir_lval_wrap(irb, scope, bin_op, lval, result_loc); - } - case BuiltinFnIdSqrt: - case BuiltinFnIdSin: - case BuiltinFnIdCos: - case BuiltinFnIdExp: - case BuiltinFnIdExp2: - case BuiltinFnIdLog: - case BuiltinFnIdLog2: - case BuiltinFnIdLog10: - case BuiltinFnIdFabs: - case BuiltinFnIdFloor: - case BuiltinFnIdCeil: - case BuiltinFnIdTrunc: - case BuiltinFnIdNearbyInt: - case BuiltinFnIdRound: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); - if (arg0_value == irb->codegen->invalid_inst_src) - return arg0_value; - - IrInstSrc *inst = ir_build_float_op_src(irb, scope, node, arg0_value, builtin_fn->id); - return ir_lval_wrap(irb, scope, inst, lval, result_loc); - } - case BuiltinFnIdTruncate: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); - if (arg0_value == irb->codegen->invalid_inst_src) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - IrInstSrc *arg1_value = ir_gen_node(irb, arg1_node, scope); - if (arg1_value == irb->codegen->invalid_inst_src) - return arg1_value; - - IrInstSrc *truncate = ir_build_truncate(irb, scope, node, arg0_value, arg1_value); - return ir_lval_wrap(irb, scope, truncate, lval, result_loc); - } - case BuiltinFnIdIntCast: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); - if (arg0_value == irb->codegen->invalid_inst_src) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - IrInstSrc *arg1_value = ir_gen_node(irb, arg1_node, scope); - if (arg1_value == irb->codegen->invalid_inst_src) - return arg1_value; - - IrInstSrc *result = ir_build_int_cast(irb, scope, node, arg0_value, arg1_value); - return ir_lval_wrap(irb, scope, result, lval, result_loc); - } - case BuiltinFnIdFloatCast: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); - if (arg0_value == irb->codegen->invalid_inst_src) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - IrInstSrc *arg1_value = ir_gen_node(irb, arg1_node, scope); - if (arg1_value == irb->codegen->invalid_inst_src) - return arg1_value; - - IrInstSrc *result = ir_build_float_cast(irb, scope, node, arg0_value, arg1_value); - return ir_lval_wrap(irb, scope, result, lval, result_loc); - } - case BuiltinFnIdErrSetCast: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); - if (arg0_value == irb->codegen->invalid_inst_src) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - IrInstSrc *arg1_value = ir_gen_node(irb, arg1_node, scope); - if (arg1_value == irb->codegen->invalid_inst_src) - return arg1_value; - - IrInstSrc *result = ir_build_err_set_cast(irb, scope, node, arg0_value, arg1_value); - return ir_lval_wrap(irb, scope, result, lval, result_loc); - } - case BuiltinFnIdIntToFloat: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); - if (arg0_value == irb->codegen->invalid_inst_src) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - IrInstSrc *arg1_value = ir_gen_node(irb, arg1_node, scope); - if (arg1_value == irb->codegen->invalid_inst_src) - return arg1_value; - - IrInstSrc *result = ir_build_int_to_float(irb, scope, node, arg0_value, arg1_value); - return ir_lval_wrap(irb, scope, result, lval, result_loc); - } - case BuiltinFnIdFloatToInt: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); - if (arg0_value == irb->codegen->invalid_inst_src) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - IrInstSrc *arg1_value = ir_gen_node(irb, arg1_node, scope); - if (arg1_value == irb->codegen->invalid_inst_src) - return arg1_value; - - IrInstSrc *result = ir_build_float_to_int(irb, scope, node, arg0_value, arg1_value); - return ir_lval_wrap(irb, scope, result, lval, result_loc); - } - case BuiltinFnIdErrToInt: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); - if (arg0_value == irb->codegen->invalid_inst_src) - return arg0_value; - - IrInstSrc *result = ir_build_err_to_int_src(irb, scope, node, arg0_value); - return ir_lval_wrap(irb, scope, result, lval, result_loc); - } - case BuiltinFnIdIntToErr: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); - if (arg0_value == irb->codegen->invalid_inst_src) - return arg0_value; - - IrInstSrc *result = ir_build_int_to_err_src(irb, scope, node, arg0_value); - return ir_lval_wrap(irb, scope, result, lval, result_loc); - } - case BuiltinFnIdBoolToInt: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); - if (arg0_value == irb->codegen->invalid_inst_src) - return arg0_value; - - IrInstSrc *result = ir_build_bool_to_int(irb, scope, node, arg0_value); - return ir_lval_wrap(irb, scope, result, lval, result_loc); - } - case BuiltinFnIdVectorType: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); - if (arg0_value == irb->codegen->invalid_inst_src) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - IrInstSrc *arg1_value = ir_gen_node(irb, arg1_node, scope); - if (arg1_value == irb->codegen->invalid_inst_src) - return arg1_value; - - IrInstSrc *vector_type = ir_build_vector_type(irb, scope, node, arg0_value, arg1_value); - return ir_lval_wrap(irb, scope, vector_type, lval, result_loc); - } - case BuiltinFnIdShuffle: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); - if (arg0_value == irb->codegen->invalid_inst_src) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - IrInstSrc *arg1_value = ir_gen_node(irb, arg1_node, scope); - if (arg1_value == irb->codegen->invalid_inst_src) - return arg1_value; - - AstNode *arg2_node = node->data.fn_call_expr.params.at(2); - IrInstSrc *arg2_value = ir_gen_node(irb, arg2_node, scope); - if (arg2_value == irb->codegen->invalid_inst_src) - return arg2_value; - - AstNode *arg3_node = node->data.fn_call_expr.params.at(3); - IrInstSrc *arg3_value = ir_gen_node(irb, arg3_node, scope); - if (arg3_value == irb->codegen->invalid_inst_src) - return arg3_value; - - IrInstSrc *shuffle_vector = ir_build_shuffle_vector(irb, scope, node, - arg0_value, arg1_value, arg2_value, arg3_value); - return ir_lval_wrap(irb, scope, shuffle_vector, lval, result_loc); - } - case BuiltinFnIdSplat: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); - if (arg0_value == irb->codegen->invalid_inst_src) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - IrInstSrc *arg1_value = ir_gen_node(irb, arg1_node, scope); - if (arg1_value == irb->codegen->invalid_inst_src) - return arg1_value; - - IrInstSrc *splat = ir_build_splat_src(irb, scope, node, - arg0_value, arg1_value); - return ir_lval_wrap(irb, scope, splat, lval, result_loc); - } - case BuiltinFnIdMemcpy: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); - if (arg0_value == irb->codegen->invalid_inst_src) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - IrInstSrc *arg1_value = ir_gen_node(irb, arg1_node, scope); - if (arg1_value == irb->codegen->invalid_inst_src) - return arg1_value; - - AstNode *arg2_node = node->data.fn_call_expr.params.at(2); - IrInstSrc *arg2_value = ir_gen_node(irb, arg2_node, scope); - if (arg2_value == irb->codegen->invalid_inst_src) - return arg2_value; - - IrInstSrc *ir_memcpy = ir_build_memcpy_src(irb, scope, node, arg0_value, arg1_value, arg2_value); - return ir_lval_wrap(irb, scope, ir_memcpy, lval, result_loc); - } - case BuiltinFnIdMemset: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); - if (arg0_value == irb->codegen->invalid_inst_src) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - IrInstSrc *arg1_value = ir_gen_node(irb, arg1_node, scope); - if (arg1_value == irb->codegen->invalid_inst_src) - return arg1_value; - - AstNode *arg2_node = node->data.fn_call_expr.params.at(2); - IrInstSrc *arg2_value = ir_gen_node(irb, arg2_node, scope); - if (arg2_value == irb->codegen->invalid_inst_src) - return arg2_value; - - IrInstSrc *ir_memset = ir_build_memset_src(irb, scope, node, arg0_value, arg1_value, arg2_value); - return ir_lval_wrap(irb, scope, ir_memset, lval, result_loc); - } - case BuiltinFnIdWasmMemorySize: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); - if (arg0_value == irb->codegen->invalid_inst_src) - return arg0_value; - - IrInstSrc *ir_wasm_memory_size = ir_build_wasm_memory_size_src(irb, scope, node, arg0_value); - return ir_lval_wrap(irb, scope, ir_wasm_memory_size, lval, result_loc); - } - case BuiltinFnIdWasmMemoryGrow: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); - if (arg0_value == irb->codegen->invalid_inst_src) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - IrInstSrc *arg1_value = ir_gen_node(irb, arg1_node, scope); - if (arg1_value == irb->codegen->invalid_inst_src) - return arg1_value; - - IrInstSrc *ir_wasm_memory_grow = ir_build_wasm_memory_grow_src(irb, scope, node, arg0_value, arg1_value); - return ir_lval_wrap(irb, scope, ir_wasm_memory_grow, lval, result_loc); - } - case BuiltinFnIdField: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - IrInstSrc *arg0_value = ir_gen_node_extra(irb, arg0_node, scope, LValPtr, nullptr); - if (arg0_value == irb->codegen->invalid_inst_src) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - IrInstSrc *arg1_value = ir_gen_node(irb, arg1_node, scope); - if (arg1_value == irb->codegen->invalid_inst_src) - return arg1_value; - - IrInstSrc *ptr_instruction = ir_build_field_ptr_instruction(irb, scope, node, - arg0_value, arg1_value, false); - - if (lval == LValPtr || lval == LValAssign) - return ptr_instruction; - - IrInstSrc *load_ptr = ir_build_load_ptr(irb, scope, node, ptr_instruction); - return ir_expr_wrap(irb, scope, load_ptr, result_loc); - } - case BuiltinFnIdHasField: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); - if (arg0_value == irb->codegen->invalid_inst_src) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - IrInstSrc *arg1_value = ir_gen_node(irb, arg1_node, scope); - if (arg1_value == irb->codegen->invalid_inst_src) - return arg1_value; - - IrInstSrc *type_info = ir_build_has_field(irb, scope, node, arg0_value, arg1_value); - return ir_lval_wrap(irb, scope, type_info, lval, result_loc); - } - case BuiltinFnIdTypeInfo: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); - if (arg0_value == irb->codegen->invalid_inst_src) - return arg0_value; - - IrInstSrc *type_info = ir_build_type_info(irb, scope, node, arg0_value); - return ir_lval_wrap(irb, scope, type_info, lval, result_loc); - } - case BuiltinFnIdType: - { - AstNode *arg_node = node->data.fn_call_expr.params.at(0); - IrInstSrc *arg = ir_gen_node(irb, arg_node, scope); - if (arg == irb->codegen->invalid_inst_src) - return arg; - - IrInstSrc *type = ir_build_type(irb, scope, node, arg); - return ir_lval_wrap(irb, scope, type, lval, result_loc); - } - case BuiltinFnIdBreakpoint: - return ir_lval_wrap(irb, scope, ir_build_breakpoint(irb, scope, node), lval, result_loc); - case BuiltinFnIdReturnAddress: - return ir_lval_wrap(irb, scope, ir_build_return_address_src(irb, scope, node), lval, result_loc); - case BuiltinFnIdFrameAddress: - return ir_lval_wrap(irb, scope, ir_build_frame_address_src(irb, scope, node), lval, result_loc); - case BuiltinFnIdFrameHandle: - if (!irb->exec->fn_entry) { - add_node_error(irb->codegen, node, buf_sprintf("@frame() called outside of function definition")); - return irb->codegen->invalid_inst_src; - } - return ir_lval_wrap(irb, scope, ir_build_handle_src(irb, scope, node), lval, result_loc); - case BuiltinFnIdFrameType: { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); - if (arg0_value == irb->codegen->invalid_inst_src) - return arg0_value; - - IrInstSrc *frame_type = ir_build_frame_type(irb, scope, node, arg0_value); - return ir_lval_wrap(irb, scope, frame_type, lval, result_loc); - } - case BuiltinFnIdFrameSize: { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); - if (arg0_value == irb->codegen->invalid_inst_src) - return arg0_value; - - IrInstSrc *frame_size = ir_build_frame_size_src(irb, scope, node, arg0_value); - return ir_lval_wrap(irb, scope, frame_size, lval, result_loc); - } - case BuiltinFnIdAlignOf: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); - if (arg0_value == irb->codegen->invalid_inst_src) - return arg0_value; - - IrInstSrc *align_of = ir_build_align_of(irb, scope, node, arg0_value); - return ir_lval_wrap(irb, scope, align_of, lval, result_loc); - } - case BuiltinFnIdAddWithOverflow: - return ir_lval_wrap(irb, scope, ir_gen_overflow_op(irb, scope, node, IrOverflowOpAdd), lval, result_loc); - case BuiltinFnIdSubWithOverflow: - return ir_lval_wrap(irb, scope, ir_gen_overflow_op(irb, scope, node, IrOverflowOpSub), lval, result_loc); - case BuiltinFnIdMulWithOverflow: - return ir_lval_wrap(irb, scope, ir_gen_overflow_op(irb, scope, node, IrOverflowOpMul), lval, result_loc); - case BuiltinFnIdShlWithOverflow: - return ir_lval_wrap(irb, scope, ir_gen_overflow_op(irb, scope, node, IrOverflowOpShl), lval, result_loc); - case BuiltinFnIdMulAdd: - return ir_lval_wrap(irb, scope, ir_gen_mul_add(irb, scope, node), lval, result_loc); - case BuiltinFnIdTypeName: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); - if (arg0_value == irb->codegen->invalid_inst_src) - return arg0_value; - - IrInstSrc *type_name = ir_build_type_name(irb, scope, node, arg0_value); - return ir_lval_wrap(irb, scope, type_name, lval, result_loc); - } - case BuiltinFnIdPanic: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); - if (arg0_value == irb->codegen->invalid_inst_src) - return arg0_value; - - IrInstSrc *panic = ir_build_panic_src(irb, scope, node, arg0_value); - return ir_lval_wrap(irb, scope, panic, lval, result_loc); - } - case BuiltinFnIdPtrCast: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); - if (arg0_value == irb->codegen->invalid_inst_src) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - IrInstSrc *arg1_value = ir_gen_node(irb, arg1_node, scope); - if (arg1_value == irb->codegen->invalid_inst_src) - return arg1_value; - - IrInstSrc *ptr_cast = ir_build_ptr_cast_src(irb, scope, node, arg0_value, arg1_value, true); - return ir_lval_wrap(irb, scope, ptr_cast, lval, result_loc); - } - case BuiltinFnIdBitCast: - { - AstNode *dest_type_node = node->data.fn_call_expr.params.at(0); - IrInstSrc *dest_type = ir_gen_node(irb, dest_type_node, scope); - if (dest_type == irb->codegen->invalid_inst_src) - return dest_type; - - ResultLocBitCast *result_loc_bit_cast = heap::c_allocator.create(); - result_loc_bit_cast->base.id = ResultLocIdBitCast; - result_loc_bit_cast->base.source_instruction = dest_type; - result_loc_bit_cast->base.allow_write_through_const = result_loc->allow_write_through_const; - ir_ref_instruction(dest_type, irb->current_basic_block); - result_loc_bit_cast->parent = result_loc; - - ir_build_reset_result(irb, scope, node, &result_loc_bit_cast->base); - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - IrInstSrc *arg1_value = ir_gen_node_extra(irb, arg1_node, scope, LValNone, - &result_loc_bit_cast->base); - if (arg1_value == irb->codegen->invalid_inst_src) - return arg1_value; - - IrInstSrc *bitcast = ir_build_bit_cast_src(irb, scope, arg1_node, arg1_value, result_loc_bit_cast); - return ir_lval_wrap(irb, scope, bitcast, lval, result_loc); - } - case BuiltinFnIdAs: - { - AstNode *dest_type_node = node->data.fn_call_expr.params.at(0); - IrInstSrc *dest_type = ir_gen_node(irb, dest_type_node, scope); - if (dest_type == irb->codegen->invalid_inst_src) - return dest_type; - - ResultLocCast *result_loc_cast = ir_build_cast_result_loc(irb, dest_type, result_loc); - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - IrInstSrc *arg1_value = ir_gen_node_extra(irb, arg1_node, scope, LValNone, - &result_loc_cast->base); - if (arg1_value == irb->codegen->invalid_inst_src) - return arg1_value; - - IrInstSrc *result = ir_build_implicit_cast(irb, scope, node, arg1_value, result_loc_cast); - return ir_lval_wrap(irb, scope, result, lval, result_loc); - } - case BuiltinFnIdIntToPtr: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); - if (arg0_value == irb->codegen->invalid_inst_src) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - IrInstSrc *arg1_value = ir_gen_node(irb, arg1_node, scope); - if (arg1_value == irb->codegen->invalid_inst_src) - return arg1_value; - - IrInstSrc *int_to_ptr = ir_build_int_to_ptr_src(irb, scope, node, arg0_value, arg1_value); - return ir_lval_wrap(irb, scope, int_to_ptr, lval, result_loc); - } - case BuiltinFnIdPtrToInt: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); - if (arg0_value == irb->codegen->invalid_inst_src) - return arg0_value; - - IrInstSrc *ptr_to_int = ir_build_ptr_to_int_src(irb, scope, node, arg0_value); - return ir_lval_wrap(irb, scope, ptr_to_int, lval, result_loc); - } - case BuiltinFnIdTagName: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); - if (arg0_value == irb->codegen->invalid_inst_src) - return arg0_value; - - IrInstSrc *tag_name = ir_build_tag_name_src(irb, scope, node, arg0_value); - return ir_lval_wrap(irb, scope, tag_name, lval, result_loc); - } - case BuiltinFnIdFieldParentPtr: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); - if (arg0_value == irb->codegen->invalid_inst_src) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - IrInstSrc *arg1_value = ir_gen_node(irb, arg1_node, scope); - if (arg1_value == irb->codegen->invalid_inst_src) - return arg1_value; - - AstNode *arg2_node = node->data.fn_call_expr.params.at(2); - IrInstSrc *arg2_value = ir_gen_node(irb, arg2_node, scope); - if (arg2_value == irb->codegen->invalid_inst_src) - return arg2_value; - - IrInstSrc *field_parent_ptr = ir_build_field_parent_ptr_src(irb, scope, node, - arg0_value, arg1_value, arg2_value); - return ir_lval_wrap(irb, scope, field_parent_ptr, lval, result_loc); - } - case BuiltinFnIdByteOffsetOf: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); - if (arg0_value == irb->codegen->invalid_inst_src) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - IrInstSrc *arg1_value = ir_gen_node(irb, arg1_node, scope); - if (arg1_value == irb->codegen->invalid_inst_src) - return arg1_value; - - IrInstSrc *offset_of = ir_build_byte_offset_of(irb, scope, node, arg0_value, arg1_value); - return ir_lval_wrap(irb, scope, offset_of, lval, result_loc); - } - case BuiltinFnIdBitOffsetOf: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); - if (arg0_value == irb->codegen->invalid_inst_src) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - IrInstSrc *arg1_value = ir_gen_node(irb, arg1_node, scope); - if (arg1_value == irb->codegen->invalid_inst_src) - return arg1_value; - - IrInstSrc *offset_of = ir_build_bit_offset_of(irb, scope, node, arg0_value, arg1_value); - return ir_lval_wrap(irb, scope, offset_of, lval, result_loc); - } - case BuiltinFnIdCall: { - // Cast the options parameter to the options type - ZigType *options_type = get_builtin_type(irb->codegen, "CallOptions"); - IrInstSrc *options_type_inst = ir_build_const_type(irb, scope, node, options_type); - ResultLocCast *result_loc_cast = ir_build_cast_result_loc(irb, options_type_inst, no_result_loc()); - - AstNode *options_node = node->data.fn_call_expr.params.at(0); - IrInstSrc *options_inner = ir_gen_node_extra(irb, options_node, scope, - LValNone, &result_loc_cast->base); - if (options_inner == irb->codegen->invalid_inst_src) - return options_inner; - IrInstSrc *options = ir_build_implicit_cast(irb, scope, options_node, options_inner, result_loc_cast); - - AstNode *fn_ref_node = node->data.fn_call_expr.params.at(1); - AstNode *args_node = node->data.fn_call_expr.params.at(2); - if (args_node->type == NodeTypeContainerInitExpr) { - if (args_node->data.container_init_expr.kind == ContainerInitKindArray || - args_node->data.container_init_expr.entries.length == 0) - { - return ir_gen_fn_call_with_args(irb, scope, node, - fn_ref_node, CallModifierNone, options, - args_node->data.container_init_expr.entries.items, - args_node->data.container_init_expr.entries.length, - lval, result_loc); - } else { - exec_add_error_node(irb->codegen, irb->exec, args_node, - buf_sprintf("TODO: @call with anon struct literal")); - return irb->codegen->invalid_inst_src; - } - } else { - IrInstSrc *fn_ref = ir_gen_node(irb, fn_ref_node, scope); - if (fn_ref == irb->codegen->invalid_inst_src) - return fn_ref; - - IrInstSrc *args = ir_gen_node(irb, args_node, scope); - if (args == irb->codegen->invalid_inst_src) - return args; - - IrInstSrc *call = ir_build_call_extra(irb, scope, node, options, fn_ref, args, result_loc); - return ir_lval_wrap(irb, scope, call, lval, result_loc); - } - } - case BuiltinFnIdAsyncCall: - return ir_gen_async_call(irb, scope, nullptr, node, lval, result_loc); - case BuiltinFnIdShlExact: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); - if (arg0_value == irb->codegen->invalid_inst_src) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - IrInstSrc *arg1_value = ir_gen_node(irb, arg1_node, scope); - if (arg1_value == irb->codegen->invalid_inst_src) - return arg1_value; - - IrInstSrc *bin_op = ir_build_bin_op(irb, scope, node, IrBinOpBitShiftLeftExact, arg0_value, arg1_value, true); - return ir_lval_wrap(irb, scope, bin_op, lval, result_loc); - } - case BuiltinFnIdShrExact: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); - if (arg0_value == irb->codegen->invalid_inst_src) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - IrInstSrc *arg1_value = ir_gen_node(irb, arg1_node, scope); - if (arg1_value == irb->codegen->invalid_inst_src) - return arg1_value; - - IrInstSrc *bin_op = ir_build_bin_op(irb, scope, node, IrBinOpBitShiftRightExact, arg0_value, arg1_value, true); - return ir_lval_wrap(irb, scope, bin_op, lval, result_loc); - } - case BuiltinFnIdSetEvalBranchQuota: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); - if (arg0_value == irb->codegen->invalid_inst_src) - return arg0_value; - - IrInstSrc *set_eval_branch_quota = ir_build_set_eval_branch_quota(irb, scope, node, arg0_value); - return ir_lval_wrap(irb, scope, set_eval_branch_quota, lval, result_loc); - } - case BuiltinFnIdAlignCast: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); - if (arg0_value == irb->codegen->invalid_inst_src) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - IrInstSrc *arg1_value = ir_gen_node(irb, arg1_node, scope); - if (arg1_value == irb->codegen->invalid_inst_src) - return arg1_value; - - IrInstSrc *align_cast = ir_build_align_cast_src(irb, scope, node, arg0_value, arg1_value); - return ir_lval_wrap(irb, scope, align_cast, lval, result_loc); - } - case BuiltinFnIdThis: - { - IrInstSrc *this_inst = ir_gen_this(irb, scope, node); - return ir_lval_wrap(irb, scope, this_inst, lval, result_loc); - } - case BuiltinFnIdSetAlignStack: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); - if (arg0_value == irb->codegen->invalid_inst_src) - return arg0_value; - - IrInstSrc *set_align_stack = ir_build_set_align_stack(irb, scope, node, arg0_value); - return ir_lval_wrap(irb, scope, set_align_stack, lval, result_loc); - } - case BuiltinFnIdExport: - { - // Cast the options parameter to the options type - ZigType *options_type = get_builtin_type(irb->codegen, "ExportOptions"); - IrInstSrc *options_type_inst = ir_build_const_type(irb, scope, node, options_type); - ResultLocCast *result_loc_cast = ir_build_cast_result_loc(irb, options_type_inst, no_result_loc()); - - AstNode *target_node = node->data.fn_call_expr.params.at(0); - IrInstSrc *target_value = ir_gen_node(irb, target_node, scope); - if (target_value == irb->codegen->invalid_inst_src) - return target_value; - - AstNode *options_node = node->data.fn_call_expr.params.at(1); - IrInstSrc *options_value = ir_gen_node_extra(irb, options_node, - scope, LValNone, &result_loc_cast->base); - if (options_value == irb->codegen->invalid_inst_src) - return options_value; - - IrInstSrc *casted_options_value = ir_build_implicit_cast( - irb, scope, options_node, options_value, result_loc_cast); - - IrInstSrc *ir_export = ir_build_export(irb, scope, node, target_value, casted_options_value); - return ir_lval_wrap(irb, scope, ir_export, lval, result_loc); - } - case BuiltinFnIdExtern: - { - // Cast the options parameter to the options type - ZigType *options_type = get_builtin_type(irb->codegen, "ExternOptions"); - IrInstSrc *options_type_inst = ir_build_const_type(irb, scope, node, options_type); - ResultLocCast *result_loc_cast = ir_build_cast_result_loc(irb, options_type_inst, no_result_loc()); - - AstNode *type_node = node->data.fn_call_expr.params.at(0); - IrInstSrc *type_value = ir_gen_node(irb, type_node, scope); - if (type_value == irb->codegen->invalid_inst_src) - return type_value; - - AstNode *options_node = node->data.fn_call_expr.params.at(1); - IrInstSrc *options_value = ir_gen_node_extra(irb, options_node, - scope, LValNone, &result_loc_cast->base); - if (options_value == irb->codegen->invalid_inst_src) - return options_value; - - IrInstSrc *casted_options_value = ir_build_implicit_cast( - irb, scope, options_node, options_value, result_loc_cast); - - IrInstSrc *ir_extern = ir_build_extern(irb, scope, node, type_value, casted_options_value); - return ir_lval_wrap(irb, scope, ir_extern, lval, result_loc); - } - case BuiltinFnIdErrorReturnTrace: - { - IrInstSrc *error_return_trace = ir_build_error_return_trace_src(irb, scope, node, - IrInstErrorReturnTraceNull); - return ir_lval_wrap(irb, scope, error_return_trace, lval, result_loc); - } - case BuiltinFnIdAtomicRmw: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); - if (arg0_value == irb->codegen->invalid_inst_src) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - IrInstSrc *arg1_value = ir_gen_node(irb, arg1_node, scope); - if (arg1_value == irb->codegen->invalid_inst_src) - return arg1_value; - - AstNode *arg2_node = node->data.fn_call_expr.params.at(2); - IrInstSrc *arg2_value = ir_gen_node(irb, arg2_node, scope); - if (arg2_value == irb->codegen->invalid_inst_src) - return arg2_value; - - AstNode *arg3_node = node->data.fn_call_expr.params.at(3); - IrInstSrc *arg3_value = ir_gen_node(irb, arg3_node, scope); - if (arg3_value == irb->codegen->invalid_inst_src) - return arg3_value; - - AstNode *arg4_node = node->data.fn_call_expr.params.at(4); - IrInstSrc *arg4_value = ir_gen_node(irb, arg4_node, scope); - if (arg4_value == irb->codegen->invalid_inst_src) - return arg4_value; - - IrInstSrc *inst = ir_build_atomic_rmw_src(irb, scope, node, - arg0_value, arg1_value, arg2_value, arg3_value, arg4_value); - return ir_lval_wrap(irb, scope, inst, lval, result_loc); - } - case BuiltinFnIdAtomicLoad: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); - if (arg0_value == irb->codegen->invalid_inst_src) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - IrInstSrc *arg1_value = ir_gen_node(irb, arg1_node, scope); - if (arg1_value == irb->codegen->invalid_inst_src) - return arg1_value; - - AstNode *arg2_node = node->data.fn_call_expr.params.at(2); - IrInstSrc *arg2_value = ir_gen_node(irb, arg2_node, scope); - if (arg2_value == irb->codegen->invalid_inst_src) - return arg2_value; - - IrInstSrc *inst = ir_build_atomic_load_src(irb, scope, node, arg0_value, arg1_value, arg2_value); - return ir_lval_wrap(irb, scope, inst, lval, result_loc); - } - case BuiltinFnIdAtomicStore: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); - if (arg0_value == irb->codegen->invalid_inst_src) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - IrInstSrc *arg1_value = ir_gen_node(irb, arg1_node, scope); - if (arg1_value == irb->codegen->invalid_inst_src) - return arg1_value; - - AstNode *arg2_node = node->data.fn_call_expr.params.at(2); - IrInstSrc *arg2_value = ir_gen_node(irb, arg2_node, scope); - if (arg2_value == irb->codegen->invalid_inst_src) - return arg2_value; - - AstNode *arg3_node = node->data.fn_call_expr.params.at(3); - IrInstSrc *arg3_value = ir_gen_node(irb, arg3_node, scope); - if (arg3_value == irb->codegen->invalid_inst_src) - return arg3_value; - - IrInstSrc *inst = ir_build_atomic_store_src(irb, scope, node, arg0_value, arg1_value, - arg2_value, arg3_value); - return ir_lval_wrap(irb, scope, inst, lval, result_loc); - } - case BuiltinFnIdIntToEnum: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); - if (arg0_value == irb->codegen->invalid_inst_src) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - IrInstSrc *arg1_value = ir_gen_node(irb, arg1_node, scope); - if (arg1_value == irb->codegen->invalid_inst_src) - return arg1_value; - - IrInstSrc *result = ir_build_int_to_enum_src(irb, scope, node, arg0_value, arg1_value); - return ir_lval_wrap(irb, scope, result, lval, result_loc); - } - case BuiltinFnIdEnumToInt: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); - if (arg0_value == irb->codegen->invalid_inst_src) - return arg0_value; - - IrInstSrc *result = ir_build_enum_to_int(irb, scope, node, arg0_value); - return ir_lval_wrap(irb, scope, result, lval, result_loc); - } - case BuiltinFnIdCtz: - case BuiltinFnIdPopCount: - case BuiltinFnIdClz: - case BuiltinFnIdBswap: - case BuiltinFnIdBitReverse: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); - if (arg0_value == irb->codegen->invalid_inst_src) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - IrInstSrc *arg1_value = ir_gen_node(irb, arg1_node, scope); - if (arg1_value == irb->codegen->invalid_inst_src) - return arg1_value; - - IrInstSrc *result; - switch (builtin_fn->id) { - case BuiltinFnIdCtz: - result = ir_build_ctz(irb, scope, node, arg0_value, arg1_value); - break; - case BuiltinFnIdPopCount: - result = ir_build_pop_count(irb, scope, node, arg0_value, arg1_value); - break; - case BuiltinFnIdClz: - result = ir_build_clz(irb, scope, node, arg0_value, arg1_value); - break; - case BuiltinFnIdBswap: - result = ir_build_bswap(irb, scope, node, arg0_value, arg1_value); - break; - case BuiltinFnIdBitReverse: - result = ir_build_bit_reverse(irb, scope, node, arg0_value, arg1_value); - break; - default: - zig_unreachable(); - } - return ir_lval_wrap(irb, scope, result, lval, result_loc); - } - case BuiltinFnIdHasDecl: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - IrInstSrc *arg0_value = ir_gen_node(irb, arg0_node, scope); - if (arg0_value == irb->codegen->invalid_inst_src) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - IrInstSrc *arg1_value = ir_gen_node(irb, arg1_node, scope); - if (arg1_value == irb->codegen->invalid_inst_src) - return arg1_value; - - IrInstSrc *has_decl = ir_build_has_decl(irb, scope, node, arg0_value, arg1_value); - return ir_lval_wrap(irb, scope, has_decl, lval, result_loc); - } - case BuiltinFnIdUnionInit: - { - AstNode *union_type_node = node->data.fn_call_expr.params.at(0); - IrInstSrc *union_type_inst = ir_gen_node(irb, union_type_node, scope); - if (union_type_inst == irb->codegen->invalid_inst_src) - return union_type_inst; - - AstNode *name_node = node->data.fn_call_expr.params.at(1); - IrInstSrc *name_inst = ir_gen_node(irb, name_node, scope); - if (name_inst == irb->codegen->invalid_inst_src) - return name_inst; - - AstNode *init_node = node->data.fn_call_expr.params.at(2); - - return ir_gen_union_init_expr(irb, scope, node, union_type_inst, name_inst, init_node, - lval, result_loc); - } - case BuiltinFnIdSrc: - { - IrInstSrc *src_inst = ir_build_src(irb, scope, node); - return ir_lval_wrap(irb, scope, src_inst, lval, result_loc); - } - } - zig_unreachable(); -} - -static ScopeNoSuspend *get_scope_nosuspend(Scope *scope) { - while (scope) { - if (scope->id == ScopeIdNoSuspend) - return (ScopeNoSuspend *)scope; - if (scope->id == ScopeIdFnDef) - return nullptr; - - scope = scope->parent; - } - return nullptr; -} - -static IrInstSrc *ir_gen_fn_call(IrBuilderSrc *irb, Scope *scope, AstNode *node, LVal lval, - ResultLoc *result_loc) -{ - assert(node->type == NodeTypeFnCallExpr); - - if (node->data.fn_call_expr.modifier == CallModifierBuiltin) - return ir_gen_builtin_fn_call(irb, scope, node, lval, result_loc); - - bool is_nosuspend = get_scope_nosuspend(scope) != nullptr; - CallModifier modifier = node->data.fn_call_expr.modifier; - if (is_nosuspend && modifier != CallModifierAsync) { - modifier = CallModifierNoSuspend; - } - - AstNode *fn_ref_node = node->data.fn_call_expr.fn_ref_expr; - return ir_gen_fn_call_with_args(irb, scope, node, fn_ref_node, modifier, - nullptr, node->data.fn_call_expr.params.items, node->data.fn_call_expr.params.length, lval, result_loc); -} - -static IrInstSrc *ir_gen_if_bool_expr(IrBuilderSrc *irb, Scope *scope, AstNode *node, LVal lval, - ResultLoc *result_loc) -{ - assert(node->type == NodeTypeIfBoolExpr); - - IrInstSrc *condition = ir_gen_node(irb, node->data.if_bool_expr.condition, scope); - if (condition == irb->codegen->invalid_inst_src) - return irb->codegen->invalid_inst_src; - - IrInstSrc *is_comptime; - if (ir_should_inline(irb->exec, scope)) { - is_comptime = ir_build_const_bool(irb, scope, node, true); - } else { - is_comptime = ir_build_test_comptime(irb, scope, node, condition); - } - - AstNode *then_node = node->data.if_bool_expr.then_block; - AstNode *else_node = node->data.if_bool_expr.else_node; - - IrBasicBlockSrc *then_block = ir_create_basic_block(irb, scope, "Then"); - IrBasicBlockSrc *else_block = ir_create_basic_block(irb, scope, "Else"); - IrBasicBlockSrc *endif_block = ir_create_basic_block(irb, scope, "EndIf"); - - IrInstSrc *cond_br_inst = ir_build_cond_br(irb, scope, node, condition, - then_block, else_block, is_comptime); - ResultLocPeerParent *peer_parent = ir_build_binary_result_peers(irb, cond_br_inst, else_block, endif_block, - result_loc, is_comptime); - - ir_set_cursor_at_end_and_append_block(irb, then_block); - - Scope *subexpr_scope = create_runtime_scope(irb->codegen, node, scope, is_comptime); - IrInstSrc *then_expr_result = ir_gen_node_extra(irb, then_node, subexpr_scope, lval, - &peer_parent->peers.at(0)->base); - if (then_expr_result == irb->codegen->invalid_inst_src) - return irb->codegen->invalid_inst_src; - IrBasicBlockSrc *after_then_block = irb->current_basic_block; - if (!instr_is_unreachable(then_expr_result)) - ir_mark_gen(ir_build_br(irb, scope, node, endif_block, is_comptime)); - - ir_set_cursor_at_end_and_append_block(irb, else_block); - IrInstSrc *else_expr_result; - if (else_node) { - else_expr_result = ir_gen_node_extra(irb, else_node, subexpr_scope, lval, &peer_parent->peers.at(1)->base); - if (else_expr_result == irb->codegen->invalid_inst_src) - return irb->codegen->invalid_inst_src; - } else { - else_expr_result = ir_build_const_void(irb, scope, node); - ir_build_end_expr(irb, scope, node, else_expr_result, &peer_parent->peers.at(1)->base); - } - IrBasicBlockSrc *after_else_block = irb->current_basic_block; - if (!instr_is_unreachable(else_expr_result)) - ir_mark_gen(ir_build_br(irb, scope, node, endif_block, is_comptime)); - - ir_set_cursor_at_end_and_append_block(irb, endif_block); - IrInstSrc **incoming_values = heap::c_allocator.allocate(2); - incoming_values[0] = then_expr_result; - incoming_values[1] = else_expr_result; - IrBasicBlockSrc **incoming_blocks = heap::c_allocator.allocate(2); - incoming_blocks[0] = after_then_block; - incoming_blocks[1] = after_else_block; - - IrInstSrc *phi = ir_build_phi(irb, scope, node, 2, incoming_blocks, incoming_values, peer_parent); - return ir_expr_wrap(irb, scope, phi, result_loc); -} - -static IrInstSrc *ir_gen_prefix_op_id_lval(IrBuilderSrc *irb, Scope *scope, AstNode *node, IrUnOp op_id, LVal lval) { - assert(node->type == NodeTypePrefixOpExpr); - AstNode *expr_node = node->data.prefix_op_expr.primary_expr; - - IrInstSrc *value = ir_gen_node_extra(irb, expr_node, scope, lval, nullptr); - if (value == irb->codegen->invalid_inst_src) - return value; - - return ir_build_un_op(irb, scope, node, op_id, value); -} - -static IrInstSrc *ir_gen_prefix_op_id(IrBuilderSrc *irb, Scope *scope, AstNode *node, IrUnOp op_id) { - return ir_gen_prefix_op_id_lval(irb, scope, node, op_id, LValNone); -} - -static IrInstSrc *ir_expr_wrap(IrBuilderSrc *irb, Scope *scope, IrInstSrc *inst, ResultLoc *result_loc) { - if (inst == irb->codegen->invalid_inst_src) return inst; - ir_build_end_expr(irb, scope, inst->base.source_node, inst, result_loc); - return inst; -} - -static IrInstSrc *ir_lval_wrap(IrBuilderSrc *irb, Scope *scope, IrInstSrc *value, LVal lval, - ResultLoc *result_loc) -{ - // This logic must be kept in sync with - // [STMT_EXPR_TEST_THING] <--- (search this token) - if (value == irb->codegen->invalid_inst_src || - instr_is_unreachable(value) || - value->base.source_node->type == NodeTypeDefer || - value->id == IrInstSrcIdDeclVar) - { - return value; - } - - assert(lval != LValAssign); - if (lval == LValPtr) { - // We needed a pointer to a value, but we got a value. So we create - // an instruction which just makes a pointer of it. - return ir_build_ref_src(irb, scope, value->base.source_node, value); - } else if (result_loc != nullptr) { - return ir_expr_wrap(irb, scope, value, result_loc); - } else { - return value; - } - -} - -static PtrLen star_token_to_ptr_len(TokenId token_id) { - switch (token_id) { - case TokenIdStar: - case TokenIdStarStar: - return PtrLenSingle; - case TokenIdLBracket: - return PtrLenUnknown; - case TokenIdSymbol: - return PtrLenC; - default: - zig_unreachable(); - } -} - -static IrInstSrc *ir_gen_pointer_type(IrBuilderSrc *irb, Scope *scope, AstNode *node) { - assert(node->type == NodeTypePointerType); - - PtrLen ptr_len = star_token_to_ptr_len(node->data.pointer_type.star_token->id); - - bool is_const = node->data.pointer_type.is_const; - bool is_volatile = node->data.pointer_type.is_volatile; - bool is_allow_zero = node->data.pointer_type.allow_zero_token != nullptr; - AstNode *sentinel_expr = node->data.pointer_type.sentinel; - AstNode *expr_node = node->data.pointer_type.op_expr; - AstNode *align_expr = node->data.pointer_type.align_expr; - - IrInstSrc *sentinel; - if (sentinel_expr != nullptr) { - sentinel = ir_gen_node(irb, sentinel_expr, scope); - if (sentinel == irb->codegen->invalid_inst_src) - return sentinel; - } else { - sentinel = nullptr; - } - - IrInstSrc *align_value; - if (align_expr != nullptr) { - align_value = ir_gen_node(irb, align_expr, scope); - if (align_value == irb->codegen->invalid_inst_src) - return align_value; - } else { - align_value = nullptr; - } - - IrInstSrc *child_type = ir_gen_node(irb, expr_node, scope); - if (child_type == irb->codegen->invalid_inst_src) - return child_type; - - uint32_t bit_offset_start = 0; - if (node->data.pointer_type.bit_offset_start != nullptr) { - if (!bigint_fits_in_bits(node->data.pointer_type.bit_offset_start, 32, false)) { - Buf *val_buf = buf_alloc(); - bigint_append_buf(val_buf, node->data.pointer_type.bit_offset_start, 10); - exec_add_error_node(irb->codegen, irb->exec, node, - buf_sprintf("value %s too large for u32 bit offset", buf_ptr(val_buf))); - return irb->codegen->invalid_inst_src; - } - bit_offset_start = bigint_as_u32(node->data.pointer_type.bit_offset_start); - } - - uint32_t host_int_bytes = 0; - if (node->data.pointer_type.host_int_bytes != nullptr) { - if (!bigint_fits_in_bits(node->data.pointer_type.host_int_bytes, 32, false)) { - Buf *val_buf = buf_alloc(); - bigint_append_buf(val_buf, node->data.pointer_type.host_int_bytes, 10); - exec_add_error_node(irb->codegen, irb->exec, node, - buf_sprintf("value %s too large for u32 byte count", buf_ptr(val_buf))); - return irb->codegen->invalid_inst_src; - } - host_int_bytes = bigint_as_u32(node->data.pointer_type.host_int_bytes); - } - - if (host_int_bytes != 0 && bit_offset_start >= host_int_bytes * 8) { - exec_add_error_node(irb->codegen, irb->exec, node, - buf_sprintf("bit offset starts after end of host integer")); - return irb->codegen->invalid_inst_src; - } - - return ir_build_ptr_type(irb, scope, node, child_type, is_const, is_volatile, - ptr_len, sentinel, align_value, bit_offset_start, host_int_bytes, is_allow_zero); -} - -static IrInstSrc *ir_gen_catch_unreachable(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, - AstNode *expr_node, LVal lval, ResultLoc *result_loc) -{ - IrInstSrc *err_union_ptr = ir_gen_node_extra(irb, expr_node, scope, LValPtr, nullptr); - if (err_union_ptr == irb->codegen->invalid_inst_src) - return irb->codegen->invalid_inst_src; - - IrInstSrc *payload_ptr = ir_build_unwrap_err_payload_src(irb, scope, source_node, err_union_ptr, true, false); - if (payload_ptr == irb->codegen->invalid_inst_src) - return irb->codegen->invalid_inst_src; - - if (lval == LValPtr) - return payload_ptr; - - IrInstSrc *load_ptr = ir_build_load_ptr(irb, scope, source_node, payload_ptr); - return ir_expr_wrap(irb, scope, load_ptr, result_loc); -} - -static IrInstSrc *ir_gen_bool_not(IrBuilderSrc *irb, Scope *scope, AstNode *node) { - assert(node->type == NodeTypePrefixOpExpr); - AstNode *expr_node = node->data.prefix_op_expr.primary_expr; - - IrInstSrc *value = ir_gen_node(irb, expr_node, scope); - if (value == irb->codegen->invalid_inst_src) - return irb->codegen->invalid_inst_src; - - return ir_build_bool_not(irb, scope, node, value); -} - -static IrInstSrc *ir_gen_prefix_op_expr(IrBuilderSrc *irb, Scope *scope, AstNode *node, LVal lval, - ResultLoc *result_loc) -{ - assert(node->type == NodeTypePrefixOpExpr); - - PrefixOp prefix_op = node->data.prefix_op_expr.prefix_op; - - switch (prefix_op) { - case PrefixOpInvalid: - zig_unreachable(); - case PrefixOpBoolNot: - return ir_lval_wrap(irb, scope, ir_gen_bool_not(irb, scope, node), lval, result_loc); - case PrefixOpBinNot: - return ir_lval_wrap(irb, scope, ir_gen_prefix_op_id(irb, scope, node, IrUnOpBinNot), lval, result_loc); - case PrefixOpNegation: - return ir_lval_wrap(irb, scope, ir_gen_prefix_op_id(irb, scope, node, IrUnOpNegation), lval, result_loc); - case PrefixOpNegationWrap: - return ir_lval_wrap(irb, scope, ir_gen_prefix_op_id(irb, scope, node, IrUnOpNegationWrap), lval, result_loc); - case PrefixOpOptional: - return ir_lval_wrap(irb, scope, ir_gen_prefix_op_id(irb, scope, node, IrUnOpOptional), lval, result_loc); - case PrefixOpAddrOf: { - AstNode *expr_node = node->data.prefix_op_expr.primary_expr; - return ir_lval_wrap(irb, scope, ir_gen_node_extra(irb, expr_node, scope, LValPtr, nullptr), lval, result_loc); - } - } - zig_unreachable(); -} - -static IrInstSrc *ir_gen_union_init_expr(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, - IrInstSrc *union_type, IrInstSrc *field_name, AstNode *expr_node, - LVal lval, ResultLoc *parent_result_loc) -{ - IrInstSrc *container_ptr = ir_build_resolve_result(irb, scope, source_node, parent_result_loc, union_type); - IrInstSrc *field_ptr = ir_build_field_ptr_instruction(irb, scope, source_node, container_ptr, - field_name, true); - - ResultLocInstruction *result_loc_inst = heap::c_allocator.create(); - result_loc_inst->base.id = ResultLocIdInstruction; - result_loc_inst->base.source_instruction = field_ptr; - ir_ref_instruction(field_ptr, irb->current_basic_block); - ir_build_reset_result(irb, scope, expr_node, &result_loc_inst->base); - - IrInstSrc *expr_value = ir_gen_node_extra(irb, expr_node, scope, LValNone, - &result_loc_inst->base); - if (expr_value == irb->codegen->invalid_inst_src) - return expr_value; - - IrInstSrc *init_union = ir_build_union_init_named_field(irb, scope, source_node, union_type, - field_name, field_ptr, container_ptr); - - return ir_lval_wrap(irb, scope, init_union, lval, parent_result_loc); -} - -static IrInstSrc *ir_gen_container_init_expr(IrBuilderSrc *irb, Scope *scope, AstNode *node, LVal lval, - ResultLoc *parent_result_loc) -{ - assert(node->type == NodeTypeContainerInitExpr); - - AstNodeContainerInitExpr *container_init_expr = &node->data.container_init_expr; - ContainerInitKind kind = container_init_expr->kind; - - ResultLocCast *result_loc_cast = nullptr; - ResultLoc *child_result_loc; - AstNode *init_array_type_source_node; - if (container_init_expr->type != nullptr) { - IrInstSrc *container_type; - if (container_init_expr->type->type == NodeTypeInferredArrayType) { - if (kind == ContainerInitKindStruct) { - add_node_error(irb->codegen, container_init_expr->type, - buf_sprintf("initializing array with struct syntax")); - return irb->codegen->invalid_inst_src; - } - IrInstSrc *sentinel; - if (container_init_expr->type->data.inferred_array_type.sentinel != nullptr) { - sentinel = ir_gen_node(irb, container_init_expr->type->data.inferred_array_type.sentinel, scope); - if (sentinel == irb->codegen->invalid_inst_src) - return sentinel; - } else { - sentinel = nullptr; - } - - IrInstSrc *elem_type = ir_gen_node(irb, - container_init_expr->type->data.inferred_array_type.child_type, scope); - if (elem_type == irb->codegen->invalid_inst_src) - return elem_type; - size_t item_count = container_init_expr->entries.length; - IrInstSrc *item_count_inst = ir_build_const_usize(irb, scope, node, item_count); - container_type = ir_build_array_type(irb, scope, node, item_count_inst, sentinel, elem_type); - } else { - container_type = ir_gen_node(irb, container_init_expr->type, scope); - if (container_type == irb->codegen->invalid_inst_src) - return container_type; - } - - result_loc_cast = ir_build_cast_result_loc(irb, container_type, parent_result_loc); - child_result_loc = &result_loc_cast->base; - init_array_type_source_node = container_type->base.source_node; - } else { - child_result_loc = parent_result_loc; - if (parent_result_loc->source_instruction != nullptr) { - init_array_type_source_node = parent_result_loc->source_instruction->base.source_node; - } else { - init_array_type_source_node = node; - } - } - - switch (kind) { - case ContainerInitKindStruct: { - IrInstSrc *container_ptr = ir_build_resolve_result(irb, scope, node, child_result_loc, - nullptr); - - size_t field_count = container_init_expr->entries.length; - IrInstSrcContainerInitFieldsField *fields = heap::c_allocator.allocate(field_count); - for (size_t i = 0; i < field_count; i += 1) { - AstNode *entry_node = container_init_expr->entries.at(i); - assert(entry_node->type == NodeTypeStructValueField); - - Buf *name = entry_node->data.struct_val_field.name; - AstNode *expr_node = entry_node->data.struct_val_field.expr; - - IrInstSrc *field_ptr = ir_build_field_ptr(irb, scope, entry_node, container_ptr, name, true); - ResultLocInstruction *result_loc_inst = heap::c_allocator.create(); - result_loc_inst->base.id = ResultLocIdInstruction; - result_loc_inst->base.source_instruction = field_ptr; - result_loc_inst->base.allow_write_through_const = true; - ir_ref_instruction(field_ptr, irb->current_basic_block); - ir_build_reset_result(irb, scope, expr_node, &result_loc_inst->base); - - IrInstSrc *expr_value = ir_gen_node_extra(irb, expr_node, scope, LValNone, - &result_loc_inst->base); - if (expr_value == irb->codegen->invalid_inst_src) - return expr_value; - - fields[i].name = name; - fields[i].source_node = entry_node; - fields[i].result_loc = field_ptr; - } - IrInstSrc *result = ir_build_container_init_fields(irb, scope, node, field_count, - fields, container_ptr); - - if (result_loc_cast != nullptr) { - result = ir_build_implicit_cast(irb, scope, node, result, result_loc_cast); - } - return ir_lval_wrap(irb, scope, result, lval, parent_result_loc); - } - case ContainerInitKindArray: { - size_t item_count = container_init_expr->entries.length; - - IrInstSrc *container_ptr = ir_build_resolve_result(irb, scope, node, child_result_loc, - nullptr); - - IrInstSrc **result_locs = heap::c_allocator.allocate(item_count); - for (size_t i = 0; i < item_count; i += 1) { - AstNode *expr_node = container_init_expr->entries.at(i); - - IrInstSrc *elem_index = ir_build_const_usize(irb, scope, expr_node, i); - IrInstSrc *elem_ptr = ir_build_elem_ptr(irb, scope, expr_node, container_ptr, - elem_index, false, PtrLenSingle, init_array_type_source_node); - ResultLocInstruction *result_loc_inst = heap::c_allocator.create(); - result_loc_inst->base.id = ResultLocIdInstruction; - result_loc_inst->base.source_instruction = elem_ptr; - result_loc_inst->base.allow_write_through_const = true; - ir_ref_instruction(elem_ptr, irb->current_basic_block); - ir_build_reset_result(irb, scope, expr_node, &result_loc_inst->base); - - IrInstSrc *expr_value = ir_gen_node_extra(irb, expr_node, scope, LValNone, - &result_loc_inst->base); - if (expr_value == irb->codegen->invalid_inst_src) - return expr_value; - - result_locs[i] = elem_ptr; - } - IrInstSrc *result = ir_build_container_init_list(irb, scope, node, item_count, - result_locs, container_ptr, init_array_type_source_node); - if (result_loc_cast != nullptr) { - result = ir_build_implicit_cast(irb, scope, node, result, result_loc_cast); - } - return ir_lval_wrap(irb, scope, result, lval, parent_result_loc); - } - } - zig_unreachable(); -} - -static ResultLocVar *ir_build_var_result_loc(IrBuilderSrc *irb, IrInstSrc *alloca, ZigVar *var) { - ResultLocVar *result_loc_var = heap::c_allocator.create(); - result_loc_var->base.id = ResultLocIdVar; - result_loc_var->base.source_instruction = alloca; - result_loc_var->base.allow_write_through_const = true; - result_loc_var->var = var; - - ir_build_reset_result(irb, alloca->base.scope, alloca->base.source_node, &result_loc_var->base); - - return result_loc_var; -} - -static ResultLocCast *ir_build_cast_result_loc(IrBuilderSrc *irb, IrInstSrc *dest_type, - ResultLoc *parent_result_loc) -{ - ResultLocCast *result_loc_cast = heap::c_allocator.create(); - result_loc_cast->base.id = ResultLocIdCast; - result_loc_cast->base.source_instruction = dest_type; - result_loc_cast->base.allow_write_through_const = parent_result_loc->allow_write_through_const; - ir_ref_instruction(dest_type, irb->current_basic_block); - result_loc_cast->parent = parent_result_loc; - - ir_build_reset_result(irb, dest_type->base.scope, dest_type->base.source_node, &result_loc_cast->base); - - return result_loc_cast; -} - -static void build_decl_var_and_init(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, ZigVar *var, - IrInstSrc *init, const char *name_hint, IrInstSrc *is_comptime) -{ - IrInstSrc *alloca = ir_build_alloca_src(irb, scope, source_node, nullptr, name_hint, is_comptime); - ResultLocVar *var_result_loc = ir_build_var_result_loc(irb, alloca, var); - ir_build_end_expr(irb, scope, source_node, init, &var_result_loc->base); - ir_build_var_decl_src(irb, scope, source_node, var, nullptr, alloca); -} - -static IrInstSrc *ir_gen_var_decl(IrBuilderSrc *irb, Scope *scope, AstNode *node) { - assert(node->type == NodeTypeVariableDeclaration); - - AstNodeVariableDeclaration *variable_declaration = &node->data.variable_declaration; - - if (buf_eql_str(variable_declaration->symbol, "_")) { - add_node_error(irb->codegen, node, buf_sprintf("`_` is not a declarable symbol")); - return irb->codegen->invalid_inst_src; - } - - // Used for the type expr and the align expr - Scope *comptime_scope = create_comptime_scope(irb->codegen, node, scope); - - IrInstSrc *type_instruction; - if (variable_declaration->type != nullptr) { - type_instruction = ir_gen_node(irb, variable_declaration->type, comptime_scope); - if (type_instruction == irb->codegen->invalid_inst_src) - return type_instruction; - } else { - type_instruction = nullptr; - } - - bool is_shadowable = false; - bool is_const = variable_declaration->is_const; - bool is_extern = variable_declaration->is_extern; - - bool is_comptime_scalar = ir_should_inline(irb->exec, scope) || variable_declaration->is_comptime; - IrInstSrc *is_comptime = ir_build_const_bool(irb, scope, node, is_comptime_scalar); - ZigVar *var = ir_create_var(irb, node, scope, variable_declaration->symbol, - is_const, is_const, is_shadowable, is_comptime); - // we detect IrInstSrcDeclVar in gen_block to make sure the next node - // is inside var->child_scope - - if (!is_extern && !variable_declaration->expr) { - var->var_type = irb->codegen->builtin_types.entry_invalid; - add_node_error(irb->codegen, node, buf_sprintf("variables must be initialized")); - return irb->codegen->invalid_inst_src; - } - - IrInstSrc *align_value = nullptr; - if (variable_declaration->align_expr != nullptr) { - align_value = ir_gen_node(irb, variable_declaration->align_expr, comptime_scope); - if (align_value == irb->codegen->invalid_inst_src) - return align_value; - } - - if (variable_declaration->section_expr != nullptr) { - add_node_error(irb->codegen, variable_declaration->section_expr, - buf_sprintf("cannot set section of local variable '%s'", buf_ptr(variable_declaration->symbol))); - } - - // Parser should ensure that this never happens - assert(variable_declaration->threadlocal_tok == nullptr); - - IrInstSrc *alloca = ir_build_alloca_src(irb, scope, node, align_value, - buf_ptr(variable_declaration->symbol), is_comptime); - - // Create a result location for the initialization expression. - ResultLocVar *result_loc_var = ir_build_var_result_loc(irb, alloca, var); - ResultLoc *init_result_loc; - ResultLocCast *result_loc_cast; - if (type_instruction != nullptr) { - result_loc_cast = ir_build_cast_result_loc(irb, type_instruction, &result_loc_var->base); - init_result_loc = &result_loc_cast->base; - } else { - result_loc_cast = nullptr; - init_result_loc = &result_loc_var->base; - } - - Scope *init_scope = is_comptime_scalar ? - create_comptime_scope(irb->codegen, variable_declaration->expr, scope) : scope; - - // Temporarily set the name of the IrExecutableSrc to the VariableDeclaration - // so that the struct or enum from the init expression inherits the name. - Buf *old_exec_name = irb->exec->name; - irb->exec->name = variable_declaration->symbol; - IrInstSrc *init_value = ir_gen_node_extra(irb, variable_declaration->expr, init_scope, - LValNone, init_result_loc); - irb->exec->name = old_exec_name; - - if (init_value == irb->codegen->invalid_inst_src) - return irb->codegen->invalid_inst_src; - - if (result_loc_cast != nullptr) { - IrInstSrc *implicit_cast = ir_build_implicit_cast(irb, scope, init_value->base.source_node, - init_value, result_loc_cast); - ir_build_end_expr(irb, scope, node, implicit_cast, &result_loc_var->base); - } - - return ir_build_var_decl_src(irb, scope, node, var, align_value, alloca); -} - -static IrInstSrc *ir_gen_while_expr(IrBuilderSrc *irb, Scope *scope, AstNode *node, LVal lval, - ResultLoc *result_loc) -{ - assert(node->type == NodeTypeWhileExpr); - - AstNode *continue_expr_node = node->data.while_expr.continue_expr; - AstNode *else_node = node->data.while_expr.else_node; - - IrBasicBlockSrc *cond_block = ir_create_basic_block(irb, scope, "WhileCond"); - IrBasicBlockSrc *body_block = ir_create_basic_block(irb, scope, "WhileBody"); - IrBasicBlockSrc *continue_block = continue_expr_node ? - ir_create_basic_block(irb, scope, "WhileContinue") : cond_block; - IrBasicBlockSrc *end_block = ir_create_basic_block(irb, scope, "WhileEnd"); - IrBasicBlockSrc *else_block = else_node ? - ir_create_basic_block(irb, scope, "WhileElse") : end_block; - - IrInstSrc *is_comptime = ir_build_const_bool(irb, scope, node, - ir_should_inline(irb->exec, scope) || node->data.while_expr.is_inline); - ir_build_br(irb, scope, node, cond_block, is_comptime); - - Scope *subexpr_scope = create_runtime_scope(irb->codegen, node, scope, is_comptime); - Buf *var_symbol = node->data.while_expr.var_symbol; - Buf *err_symbol = node->data.while_expr.err_symbol; - if (err_symbol != nullptr) { - ir_set_cursor_at_end_and_append_block(irb, cond_block); - - Scope *payload_scope; - AstNode *symbol_node = node; // TODO make more accurate - ZigVar *payload_var; - if (var_symbol) { - // TODO make it an error to write to payload variable - payload_var = ir_create_var(irb, symbol_node, subexpr_scope, var_symbol, - true, false, false, is_comptime); - payload_scope = payload_var->child_scope; - } else { - payload_scope = subexpr_scope; - } - ScopeExpr *spill_scope = create_expr_scope(irb->codegen, node, payload_scope); - IrInstSrc *err_val_ptr = ir_gen_node_extra(irb, node->data.while_expr.condition, subexpr_scope, - LValPtr, nullptr); - if (err_val_ptr == irb->codegen->invalid_inst_src) - return err_val_ptr; - IrInstSrc *is_err = ir_build_test_err_src(irb, scope, node->data.while_expr.condition, err_val_ptr, - true, false); - IrBasicBlockSrc *after_cond_block = irb->current_basic_block; - IrInstSrc *void_else_result = else_node ? nullptr : ir_mark_gen(ir_build_const_void(irb, scope, node)); - IrInstSrc *cond_br_inst; - if (!instr_is_unreachable(is_err)) { - cond_br_inst = ir_build_cond_br(irb, scope, node->data.while_expr.condition, is_err, - else_block, body_block, is_comptime); - cond_br_inst->is_gen = true; - } else { - // for the purposes of the source instruction to ir_build_result_peers - cond_br_inst = irb->current_basic_block->instruction_list.last(); - } - - ResultLocPeerParent *peer_parent = ir_build_result_peers(irb, cond_br_inst, end_block, result_loc, - is_comptime); - - ir_set_cursor_at_end_and_append_block(irb, body_block); - if (var_symbol) { - IrInstSrc *payload_ptr = ir_build_unwrap_err_payload_src(irb, &spill_scope->base, symbol_node, - err_val_ptr, false, false); - IrInstSrc *var_value = node->data.while_expr.var_is_ptr ? - payload_ptr : ir_build_load_ptr(irb, &spill_scope->base, symbol_node, payload_ptr); - build_decl_var_and_init(irb, payload_scope, symbol_node, payload_var, var_value, buf_ptr(var_symbol), is_comptime); - } - - ZigList incoming_values = {0}; - ZigList incoming_blocks = {0}; - - if (is_duplicate_label(irb->codegen, payload_scope, node, node->data.while_expr.name)) - return irb->codegen->invalid_inst_src; - - ScopeLoop *loop_scope = create_loop_scope(irb->codegen, node, payload_scope); - loop_scope->break_block = end_block; - loop_scope->continue_block = continue_block; - loop_scope->is_comptime = is_comptime; - loop_scope->incoming_blocks = &incoming_blocks; - loop_scope->incoming_values = &incoming_values; - loop_scope->lval = lval; - loop_scope->peer_parent = peer_parent; - loop_scope->spill_scope = spill_scope; - - // Note the body block of the loop is not the place that lval and result_loc are used - - // it's actually in break statements, handled similarly to return statements. - // That is why we set those values in loop_scope above and not in this ir_gen_node call. - IrInstSrc *body_result = ir_gen_node(irb, node->data.while_expr.body, &loop_scope->base); - if (body_result == irb->codegen->invalid_inst_src) - return body_result; - - if (loop_scope->name != nullptr && loop_scope->name_used == false) { - add_node_error(irb->codegen, node, buf_sprintf("unused while label")); - } - - if (!instr_is_unreachable(body_result)) { - ir_mark_gen(ir_build_check_statement_is_void(irb, payload_scope, node->data.while_expr.body, body_result)); - ir_mark_gen(ir_build_br(irb, payload_scope, node, continue_block, is_comptime)); - } - - if (continue_expr_node) { - ir_set_cursor_at_end_and_append_block(irb, continue_block); - IrInstSrc *expr_result = ir_gen_node(irb, continue_expr_node, payload_scope); - if (expr_result == irb->codegen->invalid_inst_src) - return expr_result; - if (!instr_is_unreachable(expr_result)) { - ir_mark_gen(ir_build_check_statement_is_void(irb, payload_scope, continue_expr_node, expr_result)); - ir_mark_gen(ir_build_br(irb, payload_scope, node, cond_block, is_comptime)); - } - } - - ir_set_cursor_at_end_and_append_block(irb, else_block); - assert(else_node != nullptr); - - // TODO make it an error to write to error variable - AstNode *err_symbol_node = else_node; // TODO make more accurate - ZigVar *err_var = ir_create_var(irb, err_symbol_node, scope, err_symbol, - true, false, false, is_comptime); - Scope *err_scope = err_var->child_scope; - IrInstSrc *err_ptr = ir_build_unwrap_err_code_src(irb, err_scope, err_symbol_node, err_val_ptr); - IrInstSrc *err_value = ir_build_load_ptr(irb, err_scope, err_symbol_node, err_ptr); - build_decl_var_and_init(irb, err_scope, err_symbol_node, err_var, err_value, buf_ptr(err_symbol), is_comptime); - - if (peer_parent->peers.length != 0) { - peer_parent->peers.last()->next_bb = else_block; - } - ResultLocPeer *peer_result = create_peer_result(peer_parent); - peer_parent->peers.append(peer_result); - IrInstSrc *else_result = ir_gen_node_extra(irb, else_node, err_scope, lval, &peer_result->base); - if (else_result == irb->codegen->invalid_inst_src) - return else_result; - if (!instr_is_unreachable(else_result)) - ir_mark_gen(ir_build_br(irb, scope, node, end_block, is_comptime)); - IrBasicBlockSrc *after_else_block = irb->current_basic_block; - ir_set_cursor_at_end_and_append_block(irb, end_block); - if (else_result) { - incoming_blocks.append(after_else_block); - incoming_values.append(else_result); - } else { - incoming_blocks.append(after_cond_block); - incoming_values.append(void_else_result); - } - if (peer_parent->peers.length != 0) { - peer_parent->peers.last()->next_bb = end_block; - } - - IrInstSrc *phi = ir_build_phi(irb, scope, node, incoming_blocks.length, - incoming_blocks.items, incoming_values.items, peer_parent); - return ir_expr_wrap(irb, scope, phi, result_loc); - } else if (var_symbol != nullptr) { - ir_set_cursor_at_end_and_append_block(irb, cond_block); - Scope *subexpr_scope = create_runtime_scope(irb->codegen, node, scope, is_comptime); - // TODO make it an error to write to payload variable - AstNode *symbol_node = node; // TODO make more accurate - - ZigVar *payload_var = ir_create_var(irb, symbol_node, subexpr_scope, var_symbol, - true, false, false, is_comptime); - Scope *child_scope = payload_var->child_scope; - ScopeExpr *spill_scope = create_expr_scope(irb->codegen, node, child_scope); - IrInstSrc *maybe_val_ptr = ir_gen_node_extra(irb, node->data.while_expr.condition, subexpr_scope, - LValPtr, nullptr); - if (maybe_val_ptr == irb->codegen->invalid_inst_src) - return maybe_val_ptr; - IrInstSrc *maybe_val = ir_build_load_ptr(irb, scope, node->data.while_expr.condition, maybe_val_ptr); - IrInstSrc *is_non_null = ir_build_test_non_null_src(irb, scope, node->data.while_expr.condition, maybe_val); - IrBasicBlockSrc *after_cond_block = irb->current_basic_block; - IrInstSrc *void_else_result = else_node ? nullptr : ir_mark_gen(ir_build_const_void(irb, scope, node)); - IrInstSrc *cond_br_inst; - if (!instr_is_unreachable(is_non_null)) { - cond_br_inst = ir_build_cond_br(irb, scope, node->data.while_expr.condition, is_non_null, - body_block, else_block, is_comptime); - cond_br_inst->is_gen = true; - } else { - // for the purposes of the source instruction to ir_build_result_peers - cond_br_inst = irb->current_basic_block->instruction_list.last(); - } - - ResultLocPeerParent *peer_parent = ir_build_result_peers(irb, cond_br_inst, end_block, result_loc, - is_comptime); - - ir_set_cursor_at_end_and_append_block(irb, body_block); - IrInstSrc *payload_ptr = ir_build_optional_unwrap_ptr(irb, &spill_scope->base, symbol_node, maybe_val_ptr, false); - IrInstSrc *var_value = node->data.while_expr.var_is_ptr ? - payload_ptr : ir_build_load_ptr(irb, &spill_scope->base, symbol_node, payload_ptr); - build_decl_var_and_init(irb, child_scope, symbol_node, payload_var, var_value, buf_ptr(var_symbol), is_comptime); - - ZigList incoming_values = {0}; - ZigList incoming_blocks = {0}; - - if (is_duplicate_label(irb->codegen, child_scope, node, node->data.while_expr.name)) - return irb->codegen->invalid_inst_src; - - ScopeLoop *loop_scope = create_loop_scope(irb->codegen, node, child_scope); - loop_scope->break_block = end_block; - loop_scope->continue_block = continue_block; - loop_scope->is_comptime = is_comptime; - loop_scope->incoming_blocks = &incoming_blocks; - loop_scope->incoming_values = &incoming_values; - loop_scope->lval = lval; - loop_scope->peer_parent = peer_parent; - loop_scope->spill_scope = spill_scope; - - // Note the body block of the loop is not the place that lval and result_loc are used - - // it's actually in break statements, handled similarly to return statements. - // That is why we set those values in loop_scope above and not in this ir_gen_node call. - IrInstSrc *body_result = ir_gen_node(irb, node->data.while_expr.body, &loop_scope->base); - if (body_result == irb->codegen->invalid_inst_src) - return body_result; - - if (loop_scope->name != nullptr && loop_scope->name_used == false) { - add_node_error(irb->codegen, node, buf_sprintf("unused while label")); - } - - if (!instr_is_unreachable(body_result)) { - ir_mark_gen(ir_build_check_statement_is_void(irb, child_scope, node->data.while_expr.body, body_result)); - ir_mark_gen(ir_build_br(irb, child_scope, node, continue_block, is_comptime)); - } - - if (continue_expr_node) { - ir_set_cursor_at_end_and_append_block(irb, continue_block); - IrInstSrc *expr_result = ir_gen_node(irb, continue_expr_node, child_scope); - if (expr_result == irb->codegen->invalid_inst_src) - return expr_result; - if (!instr_is_unreachable(expr_result)) { - ir_mark_gen(ir_build_check_statement_is_void(irb, child_scope, continue_expr_node, expr_result)); - ir_mark_gen(ir_build_br(irb, child_scope, node, cond_block, is_comptime)); - } - } - - IrInstSrc *else_result = nullptr; - if (else_node) { - ir_set_cursor_at_end_and_append_block(irb, else_block); - - if (peer_parent->peers.length != 0) { - peer_parent->peers.last()->next_bb = else_block; - } - ResultLocPeer *peer_result = create_peer_result(peer_parent); - peer_parent->peers.append(peer_result); - else_result = ir_gen_node_extra(irb, else_node, scope, lval, &peer_result->base); - if (else_result == irb->codegen->invalid_inst_src) - return else_result; - if (!instr_is_unreachable(else_result)) - ir_mark_gen(ir_build_br(irb, scope, node, end_block, is_comptime)); - } - IrBasicBlockSrc *after_else_block = irb->current_basic_block; - ir_set_cursor_at_end_and_append_block(irb, end_block); - if (else_result) { - incoming_blocks.append(after_else_block); - incoming_values.append(else_result); - } else { - incoming_blocks.append(after_cond_block); - incoming_values.append(void_else_result); - } - if (peer_parent->peers.length != 0) { - peer_parent->peers.last()->next_bb = end_block; - } - - IrInstSrc *phi = ir_build_phi(irb, scope, node, incoming_blocks.length, - incoming_blocks.items, incoming_values.items, peer_parent); - return ir_expr_wrap(irb, scope, phi, result_loc); - } else { - ir_set_cursor_at_end_and_append_block(irb, cond_block); - IrInstSrc *cond_val = ir_gen_node(irb, node->data.while_expr.condition, scope); - if (cond_val == irb->codegen->invalid_inst_src) - return cond_val; - IrBasicBlockSrc *after_cond_block = irb->current_basic_block; - IrInstSrc *void_else_result = else_node ? nullptr : ir_mark_gen(ir_build_const_void(irb, scope, node)); - IrInstSrc *cond_br_inst; - if (!instr_is_unreachable(cond_val)) { - cond_br_inst = ir_build_cond_br(irb, scope, node->data.while_expr.condition, cond_val, - body_block, else_block, is_comptime); - cond_br_inst->is_gen = true; - } else { - // for the purposes of the source instruction to ir_build_result_peers - cond_br_inst = irb->current_basic_block->instruction_list.last(); - } - - ResultLocPeerParent *peer_parent = ir_build_result_peers(irb, cond_br_inst, end_block, result_loc, - is_comptime); - ir_set_cursor_at_end_and_append_block(irb, body_block); - - ZigList incoming_values = {0}; - ZigList incoming_blocks = {0}; - - Scope *subexpr_scope = create_runtime_scope(irb->codegen, node, scope, is_comptime); - - if (is_duplicate_label(irb->codegen, subexpr_scope, node, node->data.while_expr.name)) - return irb->codegen->invalid_inst_src; - - ScopeLoop *loop_scope = create_loop_scope(irb->codegen, node, subexpr_scope); - loop_scope->break_block = end_block; - loop_scope->continue_block = continue_block; - loop_scope->is_comptime = is_comptime; - loop_scope->incoming_blocks = &incoming_blocks; - loop_scope->incoming_values = &incoming_values; - loop_scope->lval = lval; - loop_scope->peer_parent = peer_parent; - - // Note the body block of the loop is not the place that lval and result_loc are used - - // it's actually in break statements, handled similarly to return statements. - // That is why we set those values in loop_scope above and not in this ir_gen_node call. - IrInstSrc *body_result = ir_gen_node(irb, node->data.while_expr.body, &loop_scope->base); - if (body_result == irb->codegen->invalid_inst_src) - return body_result; - - if (loop_scope->name != nullptr && loop_scope->name_used == false) { - add_node_error(irb->codegen, node, buf_sprintf("unused while label")); - } - - if (!instr_is_unreachable(body_result)) { - ir_mark_gen(ir_build_check_statement_is_void(irb, scope, node->data.while_expr.body, body_result)); - ir_mark_gen(ir_build_br(irb, scope, node, continue_block, is_comptime)); - } - - if (continue_expr_node) { - ir_set_cursor_at_end_and_append_block(irb, continue_block); - IrInstSrc *expr_result = ir_gen_node(irb, continue_expr_node, subexpr_scope); - if (expr_result == irb->codegen->invalid_inst_src) - return expr_result; - if (!instr_is_unreachable(expr_result)) { - ir_mark_gen(ir_build_check_statement_is_void(irb, scope, continue_expr_node, expr_result)); - ir_mark_gen(ir_build_br(irb, scope, node, cond_block, is_comptime)); - } - } - - IrInstSrc *else_result = nullptr; - if (else_node) { - ir_set_cursor_at_end_and_append_block(irb, else_block); - - if (peer_parent->peers.length != 0) { - peer_parent->peers.last()->next_bb = else_block; - } - ResultLocPeer *peer_result = create_peer_result(peer_parent); - peer_parent->peers.append(peer_result); - - else_result = ir_gen_node_extra(irb, else_node, subexpr_scope, lval, &peer_result->base); - if (else_result == irb->codegen->invalid_inst_src) - return else_result; - if (!instr_is_unreachable(else_result)) - ir_mark_gen(ir_build_br(irb, scope, node, end_block, is_comptime)); - } - IrBasicBlockSrc *after_else_block = irb->current_basic_block; - ir_set_cursor_at_end_and_append_block(irb, end_block); - if (else_result) { - incoming_blocks.append(after_else_block); - incoming_values.append(else_result); - } else { - incoming_blocks.append(after_cond_block); - incoming_values.append(void_else_result); - } - if (peer_parent->peers.length != 0) { - peer_parent->peers.last()->next_bb = end_block; - } - - IrInstSrc *phi = ir_build_phi(irb, scope, node, incoming_blocks.length, - incoming_blocks.items, incoming_values.items, peer_parent); - return ir_expr_wrap(irb, scope, phi, result_loc); - } -} - -static IrInstSrc *ir_gen_for_expr(IrBuilderSrc *irb, Scope *parent_scope, AstNode *node, LVal lval, - ResultLoc *result_loc) -{ - assert(node->type == NodeTypeForExpr); - - AstNode *array_node = node->data.for_expr.array_expr; - AstNode *elem_node = node->data.for_expr.elem_node; - AstNode *index_node = node->data.for_expr.index_node; - AstNode *body_node = node->data.for_expr.body; - AstNode *else_node = node->data.for_expr.else_node; - - if (!elem_node) { - add_node_error(irb->codegen, node, buf_sprintf("for loop expression missing element parameter")); - return irb->codegen->invalid_inst_src; - } - assert(elem_node->type == NodeTypeSymbol); - - ScopeExpr *spill_scope = create_expr_scope(irb->codegen, node, parent_scope); - - IrInstSrc *array_val_ptr = ir_gen_node_extra(irb, array_node, &spill_scope->base, LValPtr, nullptr); - if (array_val_ptr == irb->codegen->invalid_inst_src) - return array_val_ptr; - - IrInstSrc *is_comptime = ir_build_const_bool(irb, parent_scope, node, - ir_should_inline(irb->exec, parent_scope) || node->data.for_expr.is_inline); - - AstNode *index_var_source_node; - ZigVar *index_var; - const char *index_var_name; - if (index_node) { - index_var_source_node = index_node; - Buf *index_var_name_buf = index_node->data.symbol_expr.symbol; - index_var = ir_create_var(irb, index_node, parent_scope, index_var_name_buf, true, false, false, is_comptime); - index_var_name = buf_ptr(index_var_name_buf); - } else { - index_var_source_node = node; - index_var = ir_create_var(irb, node, parent_scope, nullptr, true, false, true, is_comptime); - index_var_name = "i"; - } - - IrInstSrc *zero = ir_build_const_usize(irb, parent_scope, node, 0); - build_decl_var_and_init(irb, parent_scope, index_var_source_node, index_var, zero, index_var_name, is_comptime); - parent_scope = index_var->child_scope; - - IrInstSrc *one = ir_build_const_usize(irb, parent_scope, node, 1); - IrInstSrc *index_ptr = ir_build_var_ptr(irb, parent_scope, node, index_var); - - - IrBasicBlockSrc *cond_block = ir_create_basic_block(irb, parent_scope, "ForCond"); - IrBasicBlockSrc *body_block = ir_create_basic_block(irb, parent_scope, "ForBody"); - IrBasicBlockSrc *end_block = ir_create_basic_block(irb, parent_scope, "ForEnd"); - IrBasicBlockSrc *else_block = else_node ? ir_create_basic_block(irb, parent_scope, "ForElse") : end_block; - IrBasicBlockSrc *continue_block = ir_create_basic_block(irb, parent_scope, "ForContinue"); - - Buf *len_field_name = buf_create_from_str("len"); - IrInstSrc *len_ref = ir_build_field_ptr(irb, parent_scope, node, array_val_ptr, len_field_name, false); - IrInstSrc *len_val = ir_build_load_ptr(irb, &spill_scope->base, node, len_ref); - ir_build_br(irb, parent_scope, node, cond_block, is_comptime); - - ir_set_cursor_at_end_and_append_block(irb, cond_block); - IrInstSrc *index_val = ir_build_load_ptr(irb, &spill_scope->base, node, index_ptr); - IrInstSrc *cond = ir_build_bin_op(irb, parent_scope, node, IrBinOpCmpLessThan, index_val, len_val, false); - IrBasicBlockSrc *after_cond_block = irb->current_basic_block; - IrInstSrc *void_else_value = else_node ? nullptr : ir_mark_gen(ir_build_const_void(irb, parent_scope, node)); - IrInstSrc *cond_br_inst = ir_mark_gen(ir_build_cond_br(irb, parent_scope, node, cond, - body_block, else_block, is_comptime)); - - ResultLocPeerParent *peer_parent = ir_build_result_peers(irb, cond_br_inst, end_block, result_loc, is_comptime); - - ir_set_cursor_at_end_and_append_block(irb, body_block); - IrInstSrc *elem_ptr = ir_build_elem_ptr(irb, &spill_scope->base, node, array_val_ptr, index_val, - false, PtrLenSingle, nullptr); - // TODO make it an error to write to element variable or i variable. - Buf *elem_var_name = elem_node->data.symbol_expr.symbol; - ZigVar *elem_var = ir_create_var(irb, elem_node, parent_scope, elem_var_name, true, false, false, is_comptime); - Scope *child_scope = elem_var->child_scope; - - IrInstSrc *elem_value = node->data.for_expr.elem_is_ptr ? - elem_ptr : ir_build_load_ptr(irb, &spill_scope->base, elem_node, elem_ptr); - build_decl_var_and_init(irb, parent_scope, elem_node, elem_var, elem_value, buf_ptr(elem_var_name), is_comptime); - - if (is_duplicate_label(irb->codegen, child_scope, node, node->data.for_expr.name)) - return irb->codegen->invalid_inst_src; - - ZigList incoming_values = {0}; - ZigList incoming_blocks = {0}; - ScopeLoop *loop_scope = create_loop_scope(irb->codegen, node, child_scope); - loop_scope->break_block = end_block; - loop_scope->continue_block = continue_block; - loop_scope->is_comptime = is_comptime; - loop_scope->incoming_blocks = &incoming_blocks; - loop_scope->incoming_values = &incoming_values; - loop_scope->lval = LValNone; - loop_scope->peer_parent = peer_parent; - loop_scope->spill_scope = spill_scope; - - // Note the body block of the loop is not the place that lval and result_loc are used - - // it's actually in break statements, handled similarly to return statements. - // That is why we set those values in loop_scope above and not in this ir_gen_node call. - IrInstSrc *body_result = ir_gen_node(irb, body_node, &loop_scope->base); - if (body_result == irb->codegen->invalid_inst_src) - return irb->codegen->invalid_inst_src; - - if (loop_scope->name != nullptr && loop_scope->name_used == false) { - add_node_error(irb->codegen, node, buf_sprintf("unused for label")); - } - - if (!instr_is_unreachable(body_result)) { - ir_mark_gen(ir_build_check_statement_is_void(irb, child_scope, node->data.for_expr.body, body_result)); - ir_mark_gen(ir_build_br(irb, child_scope, node, continue_block, is_comptime)); - } - - ir_set_cursor_at_end_and_append_block(irb, continue_block); - IrInstSrc *new_index_val = ir_build_bin_op(irb, child_scope, node, IrBinOpAdd, index_val, one, false); - ir_build_store_ptr(irb, child_scope, node, index_ptr, new_index_val)->allow_write_through_const = true; - ir_build_br(irb, child_scope, node, cond_block, is_comptime); - - IrInstSrc *else_result = nullptr; - if (else_node) { - ir_set_cursor_at_end_and_append_block(irb, else_block); - - if (peer_parent->peers.length != 0) { - peer_parent->peers.last()->next_bb = else_block; - } - ResultLocPeer *peer_result = create_peer_result(peer_parent); - peer_parent->peers.append(peer_result); - else_result = ir_gen_node_extra(irb, else_node, parent_scope, LValNone, &peer_result->base); - if (else_result == irb->codegen->invalid_inst_src) - return else_result; - if (!instr_is_unreachable(else_result)) - ir_mark_gen(ir_build_br(irb, parent_scope, node, end_block, is_comptime)); - } - IrBasicBlockSrc *after_else_block = irb->current_basic_block; - ir_set_cursor_at_end_and_append_block(irb, end_block); - - if (else_result) { - incoming_blocks.append(after_else_block); - incoming_values.append(else_result); - } else { - incoming_blocks.append(after_cond_block); - incoming_values.append(void_else_value); - } - if (peer_parent->peers.length != 0) { - peer_parent->peers.last()->next_bb = end_block; - } - - IrInstSrc *phi = ir_build_phi(irb, parent_scope, node, incoming_blocks.length, - incoming_blocks.items, incoming_values.items, peer_parent); - return ir_lval_wrap(irb, parent_scope, phi, lval, result_loc); -} - -static IrInstSrc *ir_gen_bool_literal(IrBuilderSrc *irb, Scope *scope, AstNode *node) { - assert(node->type == NodeTypeBoolLiteral); - return ir_build_const_bool(irb, scope, node, node->data.bool_literal.value); -} - -static IrInstSrc *ir_gen_enum_literal(IrBuilderSrc *irb, Scope *scope, AstNode *node) { - assert(node->type == NodeTypeEnumLiteral); - Buf *name = &node->data.enum_literal.identifier->data.str_lit.str; - return ir_build_const_enum_literal(irb, scope, node, name); -} - -static IrInstSrc *ir_gen_string_literal(IrBuilderSrc *irb, Scope *scope, AstNode *node) { - assert(node->type == NodeTypeStringLiteral); - - return ir_build_const_str_lit(irb, scope, node, node->data.string_literal.buf); -} - -static IrInstSrc *ir_gen_array_type(IrBuilderSrc *irb, Scope *scope, AstNode *node) { - assert(node->type == NodeTypeArrayType); - - AstNode *size_node = node->data.array_type.size; - AstNode *child_type_node = node->data.array_type.child_type; - bool is_const = node->data.array_type.is_const; - bool is_volatile = node->data.array_type.is_volatile; - bool is_allow_zero = node->data.array_type.allow_zero_token != nullptr; - AstNode *sentinel_expr = node->data.array_type.sentinel; - AstNode *align_expr = node->data.array_type.align_expr; - - Scope *comptime_scope = create_comptime_scope(irb->codegen, node, scope); - - IrInstSrc *sentinel; - if (sentinel_expr != nullptr) { - sentinel = ir_gen_node(irb, sentinel_expr, comptime_scope); - if (sentinel == irb->codegen->invalid_inst_src) - return sentinel; - } else { - sentinel = nullptr; - } - - if (size_node) { - if (is_const) { - add_node_error(irb->codegen, node, buf_create_from_str("const qualifier invalid on array type")); - return irb->codegen->invalid_inst_src; - } - if (is_volatile) { - add_node_error(irb->codegen, node, buf_create_from_str("volatile qualifier invalid on array type")); - return irb->codegen->invalid_inst_src; - } - if (is_allow_zero) { - add_node_error(irb->codegen, node, buf_create_from_str("allowzero qualifier invalid on array type")); - return irb->codegen->invalid_inst_src; - } - if (align_expr != nullptr) { - add_node_error(irb->codegen, node, buf_create_from_str("align qualifier invalid on array type")); - return irb->codegen->invalid_inst_src; - } - - IrInstSrc *size_value = ir_gen_node(irb, size_node, comptime_scope); - if (size_value == irb->codegen->invalid_inst_src) - return size_value; - - IrInstSrc *child_type = ir_gen_node(irb, child_type_node, comptime_scope); - if (child_type == irb->codegen->invalid_inst_src) - return child_type; - - return ir_build_array_type(irb, scope, node, size_value, sentinel, child_type); - } else { - IrInstSrc *align_value; - if (align_expr != nullptr) { - align_value = ir_gen_node(irb, align_expr, comptime_scope); - if (align_value == irb->codegen->invalid_inst_src) - return align_value; - } else { - align_value = nullptr; - } - - IrInstSrc *child_type = ir_gen_node(irb, child_type_node, comptime_scope); - if (child_type == irb->codegen->invalid_inst_src) - return child_type; - - return ir_build_slice_type(irb, scope, node, child_type, is_const, is_volatile, sentinel, - align_value, is_allow_zero); - } -} - -static IrInstSrc *ir_gen_anyframe_type(IrBuilderSrc *irb, Scope *scope, AstNode *node) { - assert(node->type == NodeTypeAnyFrameType); - - AstNode *payload_type_node = node->data.anyframe_type.payload_type; - IrInstSrc *payload_type_value = nullptr; - - if (payload_type_node != nullptr) { - payload_type_value = ir_gen_node(irb, payload_type_node, scope); - if (payload_type_value == irb->codegen->invalid_inst_src) - return payload_type_value; - - } - - return ir_build_anyframe_type(irb, scope, node, payload_type_value); -} - -static IrInstSrc *ir_gen_undefined_literal(IrBuilderSrc *irb, Scope *scope, AstNode *node) { - assert(node->type == NodeTypeUndefinedLiteral); - return ir_build_const_undefined(irb, scope, node); -} - static Error parse_asm_template(IrAnalyze *ira, AstNode *source_node, Buf *asm_template, ZigList *tok_list) { @@ -8894,1030 +2426,6 @@ static Error parse_asm_template(IrAnalyze *ira, AstNode *source_node, Buf *asm_t return ErrorNone; } -static size_t find_asm_index(CodeGen *g, AstNode *node, AsmToken *tok, Buf *src_template) { - const char *ptr = buf_ptr(src_template) + tok->start + 2; - size_t len = tok->end - tok->start - 2; - size_t result = 0; - for (size_t i = 0; i < node->data.asm_expr.output_list.length; i += 1, result += 1) { - AsmOutput *asm_output = node->data.asm_expr.output_list.at(i); - if (buf_eql_mem(asm_output->asm_symbolic_name, ptr, len)) { - return result; - } - } - for (size_t i = 0; i < node->data.asm_expr.input_list.length; i += 1, result += 1) { - AsmInput *asm_input = node->data.asm_expr.input_list.at(i); - if (buf_eql_mem(asm_input->asm_symbolic_name, ptr, len)) { - return result; - } - } - return SIZE_MAX; -} - -static IrInstSrc *ir_gen_asm_expr(IrBuilderSrc *irb, Scope *scope, AstNode *node) { - assert(node->type == NodeTypeAsmExpr); - AstNodeAsmExpr *asm_expr = &node->data.asm_expr; - - IrInstSrc *asm_template = ir_gen_node(irb, asm_expr->asm_template, scope); - if (asm_template == irb->codegen->invalid_inst_src) - return irb->codegen->invalid_inst_src; - - bool is_volatile = asm_expr->volatile_token != nullptr; - bool in_fn_scope = (scope_fn_entry(scope) != nullptr); - - if (!in_fn_scope) { - if (is_volatile) { - add_token_error(irb->codegen, node->owner, asm_expr->volatile_token, - buf_sprintf("volatile is meaningless on global assembly")); - return irb->codegen->invalid_inst_src; - } - - if (asm_expr->output_list.length != 0 || asm_expr->input_list.length != 0 || - asm_expr->clobber_list.length != 0) - { - add_node_error(irb->codegen, node, - buf_sprintf("global assembly cannot have inputs, outputs, or clobbers")); - return irb->codegen->invalid_inst_src; - } - - return ir_build_asm_src(irb, scope, node, asm_template, nullptr, nullptr, - nullptr, 0, is_volatile, true); - } - - IrInstSrc **input_list = heap::c_allocator.allocate(asm_expr->input_list.length); - IrInstSrc **output_types = heap::c_allocator.allocate(asm_expr->output_list.length); - ZigVar **output_vars = heap::c_allocator.allocate(asm_expr->output_list.length); - size_t return_count = 0; - if (!is_volatile && asm_expr->output_list.length == 0) { - add_node_error(irb->codegen, node, - buf_sprintf("assembly expression with no output must be marked volatile")); - return irb->codegen->invalid_inst_src; - } - for (size_t i = 0; i < asm_expr->output_list.length; i += 1) { - AsmOutput *asm_output = asm_expr->output_list.at(i); - if (asm_output->return_type) { - return_count += 1; - - IrInstSrc *return_type = ir_gen_node(irb, asm_output->return_type, scope); - if (return_type == irb->codegen->invalid_inst_src) - return irb->codegen->invalid_inst_src; - if (return_count > 1) { - add_node_error(irb->codegen, node, - buf_sprintf("inline assembly allows up to one output value")); - return irb->codegen->invalid_inst_src; - } - output_types[i] = return_type; - } else { - Buf *variable_name = asm_output->variable_name; - // TODO there is some duplication here with ir_gen_symbol. I need to do a full audit of how - // inline assembly works. https://github.com/ziglang/zig/issues/215 - ZigVar *var = find_variable(irb->codegen, scope, variable_name, nullptr); - if (var) { - output_vars[i] = var; - } else { - add_node_error(irb->codegen, node, - buf_sprintf("use of undeclared identifier '%s'", buf_ptr(variable_name))); - return irb->codegen->invalid_inst_src; - } - } - - const char modifier = *buf_ptr(asm_output->constraint); - if (modifier != '=') { - add_node_error(irb->codegen, node, - buf_sprintf("invalid modifier starting output constraint for '%s': '%c', only '=' is supported." - " Compiler TODO: see https://github.com/ziglang/zig/issues/215", - buf_ptr(asm_output->asm_symbolic_name), modifier)); - return irb->codegen->invalid_inst_src; - } - } - for (size_t i = 0; i < asm_expr->input_list.length; i += 1) { - AsmInput *asm_input = asm_expr->input_list.at(i); - IrInstSrc *input_value = ir_gen_node(irb, asm_input->expr, scope); - if (input_value == irb->codegen->invalid_inst_src) - return irb->codegen->invalid_inst_src; - - input_list[i] = input_value; - } - - return ir_build_asm_src(irb, scope, node, asm_template, input_list, output_types, - output_vars, return_count, is_volatile, false); -} - -static IrInstSrc *ir_gen_if_optional_expr(IrBuilderSrc *irb, Scope *scope, AstNode *node, LVal lval, - ResultLoc *result_loc) -{ - assert(node->type == NodeTypeIfOptional); - - Buf *var_symbol = node->data.test_expr.var_symbol; - AstNode *expr_node = node->data.test_expr.target_node; - AstNode *then_node = node->data.test_expr.then_node; - AstNode *else_node = node->data.test_expr.else_node; - bool var_is_ptr = node->data.test_expr.var_is_ptr; - - ScopeExpr *spill_scope = create_expr_scope(irb->codegen, expr_node, scope); - spill_scope->spill_harder = true; - - IrInstSrc *maybe_val_ptr = ir_gen_node_extra(irb, expr_node, &spill_scope->base, LValPtr, nullptr); - if (maybe_val_ptr == irb->codegen->invalid_inst_src) - return maybe_val_ptr; - - IrInstSrc *maybe_val = ir_build_load_ptr(irb, scope, node, maybe_val_ptr); - IrInstSrc *is_non_null = ir_build_test_non_null_src(irb, scope, node, maybe_val); - - IrBasicBlockSrc *then_block = ir_create_basic_block(irb, scope, "OptionalThen"); - IrBasicBlockSrc *else_block = ir_create_basic_block(irb, scope, "OptionalElse"); - IrBasicBlockSrc *endif_block = ir_create_basic_block(irb, scope, "OptionalEndIf"); - - IrInstSrc *is_comptime; - if (ir_should_inline(irb->exec, scope)) { - is_comptime = ir_build_const_bool(irb, scope, node, true); - } else { - is_comptime = ir_build_test_comptime(irb, scope, node, is_non_null); - } - IrInstSrc *cond_br_inst = ir_build_cond_br(irb, scope, node, is_non_null, - then_block, else_block, is_comptime); - - ResultLocPeerParent *peer_parent = ir_build_binary_result_peers(irb, cond_br_inst, else_block, endif_block, - result_loc, is_comptime); - - ir_set_cursor_at_end_and_append_block(irb, then_block); - - Scope *subexpr_scope = create_runtime_scope(irb->codegen, node, &spill_scope->base, is_comptime); - Scope *var_scope; - if (var_symbol) { - bool is_shadowable = false; - bool is_const = true; - ZigVar *var = ir_create_var(irb, node, subexpr_scope, - var_symbol, is_const, is_const, is_shadowable, is_comptime); - - IrInstSrc *payload_ptr = ir_build_optional_unwrap_ptr(irb, subexpr_scope, node, maybe_val_ptr, false); - IrInstSrc *var_value = var_is_ptr ? - payload_ptr : ir_build_load_ptr(irb, &spill_scope->base, node, payload_ptr); - build_decl_var_and_init(irb, subexpr_scope, node, var, var_value, buf_ptr(var_symbol), is_comptime); - var_scope = var->child_scope; - } else { - var_scope = subexpr_scope; - } - IrInstSrc *then_expr_result = ir_gen_node_extra(irb, then_node, var_scope, lval, - &peer_parent->peers.at(0)->base); - if (then_expr_result == irb->codegen->invalid_inst_src) - return then_expr_result; - IrBasicBlockSrc *after_then_block = irb->current_basic_block; - if (!instr_is_unreachable(then_expr_result)) - ir_mark_gen(ir_build_br(irb, scope, node, endif_block, is_comptime)); - - ir_set_cursor_at_end_and_append_block(irb, else_block); - IrInstSrc *else_expr_result; - if (else_node) { - else_expr_result = ir_gen_node_extra(irb, else_node, subexpr_scope, lval, &peer_parent->peers.at(1)->base); - if (else_expr_result == irb->codegen->invalid_inst_src) - return else_expr_result; - } else { - else_expr_result = ir_build_const_void(irb, scope, node); - ir_build_end_expr(irb, scope, node, else_expr_result, &peer_parent->peers.at(1)->base); - } - IrBasicBlockSrc *after_else_block = irb->current_basic_block; - if (!instr_is_unreachable(else_expr_result)) - ir_mark_gen(ir_build_br(irb, scope, node, endif_block, is_comptime)); - - ir_set_cursor_at_end_and_append_block(irb, endif_block); - IrInstSrc **incoming_values = heap::c_allocator.allocate(2); - incoming_values[0] = then_expr_result; - incoming_values[1] = else_expr_result; - IrBasicBlockSrc **incoming_blocks = heap::c_allocator.allocate(2); - incoming_blocks[0] = after_then_block; - incoming_blocks[1] = after_else_block; - - IrInstSrc *phi = ir_build_phi(irb, scope, node, 2, incoming_blocks, incoming_values, peer_parent); - return ir_expr_wrap(irb, scope, phi, result_loc); -} - -static IrInstSrc *ir_gen_if_err_expr(IrBuilderSrc *irb, Scope *scope, AstNode *node, LVal lval, - ResultLoc *result_loc) -{ - assert(node->type == NodeTypeIfErrorExpr); - - AstNode *target_node = node->data.if_err_expr.target_node; - AstNode *then_node = node->data.if_err_expr.then_node; - AstNode *else_node = node->data.if_err_expr.else_node; - bool var_is_ptr = node->data.if_err_expr.var_is_ptr; - bool var_is_const = true; - Buf *var_symbol = node->data.if_err_expr.var_symbol; - Buf *err_symbol = node->data.if_err_expr.err_symbol; - - IrInstSrc *err_val_ptr = ir_gen_node_extra(irb, target_node, scope, LValPtr, nullptr); - if (err_val_ptr == irb->codegen->invalid_inst_src) - return err_val_ptr; - - IrInstSrc *err_val = ir_build_load_ptr(irb, scope, node, err_val_ptr); - IrInstSrc *is_err = ir_build_test_err_src(irb, scope, node, err_val_ptr, true, false); - - IrBasicBlockSrc *ok_block = ir_create_basic_block(irb, scope, "TryOk"); - IrBasicBlockSrc *else_block = ir_create_basic_block(irb, scope, "TryElse"); - IrBasicBlockSrc *endif_block = ir_create_basic_block(irb, scope, "TryEnd"); - - bool force_comptime = ir_should_inline(irb->exec, scope); - IrInstSrc *is_comptime = force_comptime ? ir_build_const_bool(irb, scope, node, true) : ir_build_test_comptime(irb, scope, node, is_err); - IrInstSrc *cond_br_inst = ir_build_cond_br(irb, scope, node, is_err, else_block, ok_block, is_comptime); - - ResultLocPeerParent *peer_parent = ir_build_binary_result_peers(irb, cond_br_inst, else_block, endif_block, - result_loc, is_comptime); - - ir_set_cursor_at_end_and_append_block(irb, ok_block); - - Scope *subexpr_scope = create_runtime_scope(irb->codegen, node, scope, is_comptime); - Scope *var_scope; - if (var_symbol) { - bool is_shadowable = false; - IrInstSrc *var_is_comptime = force_comptime ? ir_build_const_bool(irb, subexpr_scope, node, true) : ir_build_test_comptime(irb, subexpr_scope, node, err_val); - ZigVar *var = ir_create_var(irb, node, subexpr_scope, - var_symbol, var_is_const, var_is_const, is_shadowable, var_is_comptime); - - IrInstSrc *payload_ptr = ir_build_unwrap_err_payload_src(irb, subexpr_scope, node, err_val_ptr, false, false); - IrInstSrc *var_value = var_is_ptr ? - payload_ptr : ir_build_load_ptr(irb, subexpr_scope, node, payload_ptr); - build_decl_var_and_init(irb, subexpr_scope, node, var, var_value, buf_ptr(var_symbol), var_is_comptime); - var_scope = var->child_scope; - } else { - var_scope = subexpr_scope; - } - IrInstSrc *then_expr_result = ir_gen_node_extra(irb, then_node, var_scope, lval, - &peer_parent->peers.at(0)->base); - if (then_expr_result == irb->codegen->invalid_inst_src) - return then_expr_result; - IrBasicBlockSrc *after_then_block = irb->current_basic_block; - if (!instr_is_unreachable(then_expr_result)) - ir_mark_gen(ir_build_br(irb, scope, node, endif_block, is_comptime)); - - ir_set_cursor_at_end_and_append_block(irb, else_block); - - IrInstSrc *else_expr_result; - if (else_node) { - Scope *err_var_scope; - if (err_symbol) { - bool is_shadowable = false; - bool is_const = true; - ZigVar *var = ir_create_var(irb, node, subexpr_scope, - err_symbol, is_const, is_const, is_shadowable, is_comptime); - - IrInstSrc *err_ptr = ir_build_unwrap_err_code_src(irb, subexpr_scope, node, err_val_ptr); - IrInstSrc *err_value = ir_build_load_ptr(irb, subexpr_scope, node, err_ptr); - build_decl_var_and_init(irb, subexpr_scope, node, var, err_value, buf_ptr(err_symbol), is_comptime); - err_var_scope = var->child_scope; - } else { - err_var_scope = subexpr_scope; - } - else_expr_result = ir_gen_node_extra(irb, else_node, err_var_scope, lval, &peer_parent->peers.at(1)->base); - if (else_expr_result == irb->codegen->invalid_inst_src) - return else_expr_result; - } else { - else_expr_result = ir_build_const_void(irb, scope, node); - ir_build_end_expr(irb, scope, node, else_expr_result, &peer_parent->peers.at(1)->base); - } - IrBasicBlockSrc *after_else_block = irb->current_basic_block; - if (!instr_is_unreachable(else_expr_result)) - ir_mark_gen(ir_build_br(irb, scope, node, endif_block, is_comptime)); - - ir_set_cursor_at_end_and_append_block(irb, endif_block); - IrInstSrc **incoming_values = heap::c_allocator.allocate(2); - incoming_values[0] = then_expr_result; - incoming_values[1] = else_expr_result; - IrBasicBlockSrc **incoming_blocks = heap::c_allocator.allocate(2); - incoming_blocks[0] = after_then_block; - incoming_blocks[1] = after_else_block; - - IrInstSrc *phi = ir_build_phi(irb, scope, node, 2, incoming_blocks, incoming_values, peer_parent); - return ir_expr_wrap(irb, scope, phi, result_loc); -} - -static bool ir_gen_switch_prong_expr(IrBuilderSrc *irb, Scope *scope, AstNode *switch_node, AstNode *prong_node, - IrBasicBlockSrc *end_block, IrInstSrc *is_comptime, IrInstSrc *var_is_comptime, - IrInstSrc *target_value_ptr, IrInstSrc **prong_values, size_t prong_values_len, - ZigList *incoming_blocks, ZigList *incoming_values, - IrInstSrcSwitchElseVar **out_switch_else_var, LVal lval, ResultLoc *result_loc) -{ - assert(switch_node->type == NodeTypeSwitchExpr); - assert(prong_node->type == NodeTypeSwitchProng); - - AstNode *expr_node = prong_node->data.switch_prong.expr; - AstNode *var_symbol_node = prong_node->data.switch_prong.var_symbol; - Scope *child_scope; - if (var_symbol_node) { - assert(var_symbol_node->type == NodeTypeSymbol); - Buf *var_name = var_symbol_node->data.symbol_expr.symbol; - bool var_is_ptr = prong_node->data.switch_prong.var_is_ptr; - - bool is_shadowable = false; - bool is_const = true; - ZigVar *var = ir_create_var(irb, var_symbol_node, scope, - var_name, is_const, is_const, is_shadowable, var_is_comptime); - child_scope = var->child_scope; - IrInstSrc *var_value; - if (out_switch_else_var != nullptr) { - IrInstSrcSwitchElseVar *switch_else_var = ir_build_switch_else_var(irb, scope, var_symbol_node, - target_value_ptr); - *out_switch_else_var = switch_else_var; - IrInstSrc *payload_ptr = &switch_else_var->base; - var_value = var_is_ptr ? - payload_ptr : ir_build_load_ptr(irb, scope, var_symbol_node, payload_ptr); - } else if (prong_values != nullptr) { - IrInstSrc *payload_ptr = ir_build_switch_var(irb, scope, var_symbol_node, target_value_ptr, - prong_values, prong_values_len); - var_value = var_is_ptr ? - payload_ptr : ir_build_load_ptr(irb, scope, var_symbol_node, payload_ptr); - } else { - var_value = var_is_ptr ? - target_value_ptr : ir_build_load_ptr(irb, scope, var_symbol_node, target_value_ptr); - } - build_decl_var_and_init(irb, scope, var_symbol_node, var, var_value, buf_ptr(var_name), var_is_comptime); - } else { - child_scope = scope; - } - - IrInstSrc *expr_result = ir_gen_node_extra(irb, expr_node, child_scope, lval, result_loc); - if (expr_result == irb->codegen->invalid_inst_src) - return false; - if (!instr_is_unreachable(expr_result)) - ir_mark_gen(ir_build_br(irb, scope, switch_node, end_block, is_comptime)); - incoming_blocks->append(irb->current_basic_block); - incoming_values->append(expr_result); - return true; -} - -static IrInstSrc *ir_gen_switch_expr(IrBuilderSrc *irb, Scope *scope, AstNode *node, LVal lval, - ResultLoc *result_loc) -{ - assert(node->type == NodeTypeSwitchExpr); - - AstNode *target_node = node->data.switch_expr.expr; - IrInstSrc *target_value_ptr = ir_gen_node_extra(irb, target_node, scope, LValPtr, nullptr); - if (target_value_ptr == irb->codegen->invalid_inst_src) - return target_value_ptr; - IrInstSrc *target_value = ir_build_switch_target(irb, scope, node, target_value_ptr); - - IrBasicBlockSrc *else_block = ir_create_basic_block(irb, scope, "SwitchElse"); - IrBasicBlockSrc *end_block = ir_create_basic_block(irb, scope, "SwitchEnd"); - - size_t prong_count = node->data.switch_expr.prongs.length; - ZigList cases = {0}; - - IrInstSrc *is_comptime; - IrInstSrc *var_is_comptime; - if (ir_should_inline(irb->exec, scope)) { - is_comptime = ir_build_const_bool(irb, scope, node, true); - var_is_comptime = is_comptime; - } else { - is_comptime = ir_build_test_comptime(irb, scope, node, target_value); - var_is_comptime = ir_build_test_comptime(irb, scope, node, target_value_ptr); - } - - ZigList incoming_values = {0}; - ZigList incoming_blocks = {0}; - ZigList check_ranges = {0}; - - IrInstSrcSwitchElseVar *switch_else_var = nullptr; - - ResultLocPeerParent *peer_parent = heap::c_allocator.create(); - peer_parent->base.id = ResultLocIdPeerParent; - peer_parent->base.allow_write_through_const = result_loc->allow_write_through_const; - peer_parent->end_bb = end_block; - peer_parent->is_comptime = is_comptime; - peer_parent->parent = result_loc; - - ir_build_reset_result(irb, scope, node, &peer_parent->base); - - // First do the else and the ranges - Scope *subexpr_scope = create_runtime_scope(irb->codegen, node, scope, is_comptime); - Scope *comptime_scope = create_comptime_scope(irb->codegen, node, scope); - AstNode *else_prong = nullptr; - AstNode *underscore_prong = nullptr; - for (size_t prong_i = 0; prong_i < prong_count; prong_i += 1) { - AstNode *prong_node = node->data.switch_expr.prongs.at(prong_i); - size_t prong_item_count = prong_node->data.switch_prong.items.length; - if (prong_node->data.switch_prong.any_items_are_range) { - ResultLocPeer *this_peer_result_loc = create_peer_result(peer_parent); - - IrInstSrc *ok_bit = nullptr; - AstNode *last_item_node = nullptr; - for (size_t item_i = 0; item_i < prong_item_count; item_i += 1) { - AstNode *item_node = prong_node->data.switch_prong.items.at(item_i); - last_item_node = item_node; - if (item_node->type == NodeTypeSwitchRange) { - AstNode *start_node = item_node->data.switch_range.start; - AstNode *end_node = item_node->data.switch_range.end; - - IrInstSrc *start_value = ir_gen_node(irb, start_node, comptime_scope); - if (start_value == irb->codegen->invalid_inst_src) - return irb->codegen->invalid_inst_src; - - IrInstSrc *end_value = ir_gen_node(irb, end_node, comptime_scope); - if (end_value == irb->codegen->invalid_inst_src) - return irb->codegen->invalid_inst_src; - - IrInstSrcCheckSwitchProngsRange *check_range = check_ranges.add_one(); - check_range->start = start_value; - check_range->end = end_value; - - IrInstSrc *lower_range_ok = ir_build_bin_op(irb, scope, item_node, IrBinOpCmpGreaterOrEq, - target_value, start_value, false); - IrInstSrc *upper_range_ok = ir_build_bin_op(irb, scope, item_node, IrBinOpCmpLessOrEq, - target_value, end_value, false); - IrInstSrc *both_ok = ir_build_bin_op(irb, scope, item_node, IrBinOpBoolAnd, - lower_range_ok, upper_range_ok, false); - if (ok_bit) { - ok_bit = ir_build_bin_op(irb, scope, item_node, IrBinOpBoolOr, both_ok, ok_bit, false); - } else { - ok_bit = both_ok; - } - } else { - IrInstSrc *item_value = ir_gen_node(irb, item_node, comptime_scope); - if (item_value == irb->codegen->invalid_inst_src) - return irb->codegen->invalid_inst_src; - - IrInstSrcCheckSwitchProngsRange *check_range = check_ranges.add_one(); - check_range->start = item_value; - check_range->end = item_value; - - IrInstSrc *cmp_ok = ir_build_bin_op(irb, scope, item_node, IrBinOpCmpEq, - item_value, target_value, false); - if (ok_bit) { - ok_bit = ir_build_bin_op(irb, scope, item_node, IrBinOpBoolOr, cmp_ok, ok_bit, false); - } else { - ok_bit = cmp_ok; - } - } - } - - IrBasicBlockSrc *range_block_yes = ir_create_basic_block(irb, scope, "SwitchRangeYes"); - IrBasicBlockSrc *range_block_no = ir_create_basic_block(irb, scope, "SwitchRangeNo"); - - assert(ok_bit); - assert(last_item_node); - IrInstSrc *br_inst = ir_mark_gen(ir_build_cond_br(irb, scope, last_item_node, ok_bit, - range_block_yes, range_block_no, is_comptime)); - if (peer_parent->base.source_instruction == nullptr) { - peer_parent->base.source_instruction = br_inst; - } - - if (peer_parent->peers.length > 0) { - peer_parent->peers.last()->next_bb = range_block_yes; - } - peer_parent->peers.append(this_peer_result_loc); - ir_set_cursor_at_end_and_append_block(irb, range_block_yes); - if (!ir_gen_switch_prong_expr(irb, subexpr_scope, node, prong_node, end_block, - is_comptime, var_is_comptime, target_value_ptr, nullptr, 0, - &incoming_blocks, &incoming_values, nullptr, LValNone, &this_peer_result_loc->base)) - { - return irb->codegen->invalid_inst_src; - } - - ir_set_cursor_at_end_and_append_block(irb, range_block_no); - } else { - if (prong_item_count == 0) { - if (else_prong) { - ErrorMsg *msg = add_node_error(irb->codegen, prong_node, - buf_sprintf("multiple else prongs in switch expression")); - add_error_note(irb->codegen, msg, else_prong, - buf_sprintf("previous else prong is here")); - return irb->codegen->invalid_inst_src; - } - else_prong = prong_node; - } else if (prong_item_count == 1 && - prong_node->data.switch_prong.items.at(0)->type == NodeTypeSymbol && - buf_eql_str(prong_node->data.switch_prong.items.at(0)->data.symbol_expr.symbol, "_")) { - if (underscore_prong) { - ErrorMsg *msg = add_node_error(irb->codegen, prong_node, - buf_sprintf("multiple '_' prongs in switch expression")); - add_error_note(irb->codegen, msg, underscore_prong, - buf_sprintf("previous '_' prong is here")); - return irb->codegen->invalid_inst_src; - } - underscore_prong = prong_node; - } else { - continue; - } - if (underscore_prong && else_prong) { - ErrorMsg *msg = add_node_error(irb->codegen, prong_node, - buf_sprintf("else and '_' prong in switch expression")); - if (underscore_prong == prong_node) - add_error_note(irb->codegen, msg, else_prong, - buf_sprintf("else prong is here")); - else - add_error_note(irb->codegen, msg, underscore_prong, - buf_sprintf("'_' prong is here")); - return irb->codegen->invalid_inst_src; - } - ResultLocPeer *this_peer_result_loc = create_peer_result(peer_parent); - - IrBasicBlockSrc *prev_block = irb->current_basic_block; - if (peer_parent->peers.length > 0) { - peer_parent->peers.last()->next_bb = else_block; - } - peer_parent->peers.append(this_peer_result_loc); - ir_set_cursor_at_end_and_append_block(irb, else_block); - if (!ir_gen_switch_prong_expr(irb, subexpr_scope, node, prong_node, end_block, - is_comptime, var_is_comptime, target_value_ptr, nullptr, 0, &incoming_blocks, &incoming_values, - &switch_else_var, LValNone, &this_peer_result_loc->base)) - { - return irb->codegen->invalid_inst_src; - } - ir_set_cursor_at_end(irb, prev_block); - } - } - - // next do the non-else non-ranges - for (size_t prong_i = 0; prong_i < prong_count; prong_i += 1) { - AstNode *prong_node = node->data.switch_expr.prongs.at(prong_i); - size_t prong_item_count = prong_node->data.switch_prong.items.length; - if (prong_item_count == 0) - continue; - if (prong_node->data.switch_prong.any_items_are_range) - continue; - if (underscore_prong == prong_node) - continue; - - ResultLocPeer *this_peer_result_loc = create_peer_result(peer_parent); - - IrBasicBlockSrc *prong_block = ir_create_basic_block(irb, scope, "SwitchProng"); - IrInstSrc **items = heap::c_allocator.allocate(prong_item_count); - - for (size_t item_i = 0; item_i < prong_item_count; item_i += 1) { - AstNode *item_node = prong_node->data.switch_prong.items.at(item_i); - assert(item_node->type != NodeTypeSwitchRange); - - IrInstSrc *item_value = ir_gen_node(irb, item_node, comptime_scope); - if (item_value == irb->codegen->invalid_inst_src) - return irb->codegen->invalid_inst_src; - - IrInstSrcCheckSwitchProngsRange *check_range = check_ranges.add_one(); - check_range->start = item_value; - check_range->end = item_value; - - IrInstSrcSwitchBrCase *this_case = cases.add_one(); - this_case->value = item_value; - this_case->block = prong_block; - - items[item_i] = item_value; - } - - IrBasicBlockSrc *prev_block = irb->current_basic_block; - if (peer_parent->peers.length > 0) { - peer_parent->peers.last()->next_bb = prong_block; - } - peer_parent->peers.append(this_peer_result_loc); - ir_set_cursor_at_end_and_append_block(irb, prong_block); - if (!ir_gen_switch_prong_expr(irb, subexpr_scope, node, prong_node, end_block, - is_comptime, var_is_comptime, target_value_ptr, items, prong_item_count, - &incoming_blocks, &incoming_values, nullptr, LValNone, &this_peer_result_loc->base)) - { - return irb->codegen->invalid_inst_src; - } - - ir_set_cursor_at_end(irb, prev_block); - - } - - IrInstSrc *switch_prongs_void = ir_build_check_switch_prongs(irb, scope, node, target_value, - check_ranges.items, check_ranges.length, else_prong, underscore_prong != nullptr); - - IrInstSrc *br_instruction; - if (cases.length == 0) { - br_instruction = ir_build_br(irb, scope, node, else_block, is_comptime); - } else { - IrInstSrcSwitchBr *switch_br = ir_build_switch_br_src(irb, scope, node, target_value, else_block, - cases.length, cases.items, is_comptime, switch_prongs_void); - if (switch_else_var != nullptr) { - switch_else_var->switch_br = switch_br; - } - br_instruction = &switch_br->base; - } - if (peer_parent->base.source_instruction == nullptr) { - peer_parent->base.source_instruction = br_instruction; - } - for (size_t i = 0; i < peer_parent->peers.length; i += 1) { - peer_parent->peers.at(i)->base.source_instruction = peer_parent->base.source_instruction; - } - - if (!else_prong && !underscore_prong) { - if (peer_parent->peers.length != 0) { - peer_parent->peers.last()->next_bb = else_block; - } - ir_set_cursor_at_end_and_append_block(irb, else_block); - ir_build_unreachable(irb, scope, node); - } else { - if (peer_parent->peers.length != 0) { - peer_parent->peers.last()->next_bb = end_block; - } - } - - ir_set_cursor_at_end_and_append_block(irb, end_block); - assert(incoming_blocks.length == incoming_values.length); - IrInstSrc *result_instruction; - if (incoming_blocks.length == 0) { - result_instruction = ir_build_const_void(irb, scope, node); - } else { - result_instruction = ir_build_phi(irb, scope, node, incoming_blocks.length, - incoming_blocks.items, incoming_values.items, peer_parent); - } - return ir_lval_wrap(irb, scope, result_instruction, lval, result_loc); -} - -static IrInstSrc *ir_gen_comptime(IrBuilderSrc *irb, Scope *parent_scope, AstNode *node, LVal lval) { - assert(node->type == NodeTypeCompTime); - - Scope *child_scope = create_comptime_scope(irb->codegen, node, parent_scope); - // purposefully pass null for result_loc and let EndExpr handle it - return ir_gen_node_extra(irb, node->data.comptime_expr.expr, child_scope, lval, nullptr); -} - -static IrInstSrc *ir_gen_nosuspend(IrBuilderSrc *irb, Scope *parent_scope, AstNode *node, LVal lval) { - assert(node->type == NodeTypeNoSuspend); - - Scope *child_scope = create_nosuspend_scope(irb->codegen, node, parent_scope); - // purposefully pass null for result_loc and let EndExpr handle it - return ir_gen_node_extra(irb, node->data.nosuspend_expr.expr, child_scope, lval, nullptr); -} - -static IrInstSrc *ir_gen_return_from_block(IrBuilderSrc *irb, Scope *break_scope, AstNode *node, ScopeBlock *block_scope) { - IrInstSrc *is_comptime; - if (ir_should_inline(irb->exec, break_scope)) { - is_comptime = ir_build_const_bool(irb, break_scope, node, true); - } else { - is_comptime = block_scope->is_comptime; - } - - IrInstSrc *result_value; - if (node->data.break_expr.expr) { - ResultLocPeer *peer_result = create_peer_result(block_scope->peer_parent); - block_scope->peer_parent->peers.append(peer_result); - - result_value = ir_gen_node_extra(irb, node->data.break_expr.expr, break_scope, block_scope->lval, - &peer_result->base); - if (result_value == irb->codegen->invalid_inst_src) - return irb->codegen->invalid_inst_src; - } else { - result_value = ir_build_const_void(irb, break_scope, node); - } - - IrBasicBlockSrc *dest_block = block_scope->end_block; - if (!ir_gen_defers_for_block(irb, break_scope, dest_block->scope, nullptr, nullptr)) - return irb->codegen->invalid_inst_src; - - block_scope->incoming_blocks->append(irb->current_basic_block); - block_scope->incoming_values->append(result_value); - return ir_build_br(irb, break_scope, node, dest_block, is_comptime); -} - -static IrInstSrc *ir_gen_break(IrBuilderSrc *irb, Scope *break_scope, AstNode *node) { - assert(node->type == NodeTypeBreak); - - // Search up the scope. We'll find one of these things first: - // * function definition scope or global scope => error, break outside loop - // * defer expression scope => error, cannot break out of defer expression - // * loop scope => OK - // * (if it's a labeled break) labeled block => OK - - Scope *search_scope = break_scope; - ScopeLoop *loop_scope; - for (;;) { - if (search_scope == nullptr || search_scope->id == ScopeIdFnDef) { - if (node->data.break_expr.name != nullptr) { - add_node_error(irb->codegen, node, buf_sprintf("label not found: '%s'", buf_ptr(node->data.break_expr.name))); - return irb->codegen->invalid_inst_src; - } else { - add_node_error(irb->codegen, node, buf_sprintf("break expression outside loop")); - return irb->codegen->invalid_inst_src; - } - } else if (search_scope->id == ScopeIdDeferExpr) { - add_node_error(irb->codegen, node, buf_sprintf("cannot break out of defer expression")); - return irb->codegen->invalid_inst_src; - } else if (search_scope->id == ScopeIdLoop) { - ScopeLoop *this_loop_scope = (ScopeLoop *)search_scope; - if (node->data.break_expr.name == nullptr || - (this_loop_scope->name != nullptr && buf_eql_buf(node->data.break_expr.name, this_loop_scope->name))) - { - this_loop_scope->name_used = true; - loop_scope = this_loop_scope; - break; - } - } else if (search_scope->id == ScopeIdBlock) { - ScopeBlock *this_block_scope = (ScopeBlock *)search_scope; - if (node->data.break_expr.name != nullptr && - (this_block_scope->name != nullptr && buf_eql_buf(node->data.break_expr.name, this_block_scope->name))) - { - assert(this_block_scope->end_block != nullptr); - this_block_scope->name_used = true; - return ir_gen_return_from_block(irb, break_scope, node, this_block_scope); - } - } else if (search_scope->id == ScopeIdSuspend) { - add_node_error(irb->codegen, node, buf_sprintf("cannot break out of suspend block")); - return irb->codegen->invalid_inst_src; - } - search_scope = search_scope->parent; - } - - IrInstSrc *is_comptime; - if (ir_should_inline(irb->exec, break_scope)) { - is_comptime = ir_build_const_bool(irb, break_scope, node, true); - } else { - is_comptime = loop_scope->is_comptime; - } - - IrInstSrc *result_value; - if (node->data.break_expr.expr) { - ResultLocPeer *peer_result = create_peer_result(loop_scope->peer_parent); - loop_scope->peer_parent->peers.append(peer_result); - - result_value = ir_gen_node_extra(irb, node->data.break_expr.expr, break_scope, - loop_scope->lval, &peer_result->base); - if (result_value == irb->codegen->invalid_inst_src) - return irb->codegen->invalid_inst_src; - } else { - result_value = ir_build_const_void(irb, break_scope, node); - } - - IrBasicBlockSrc *dest_block = loop_scope->break_block; - if (!ir_gen_defers_for_block(irb, break_scope, dest_block->scope, nullptr, nullptr)) - return irb->codegen->invalid_inst_src; - - loop_scope->incoming_blocks->append(irb->current_basic_block); - loop_scope->incoming_values->append(result_value); - return ir_build_br(irb, break_scope, node, dest_block, is_comptime); -} - -static IrInstSrc *ir_gen_continue(IrBuilderSrc *irb, Scope *continue_scope, AstNode *node) { - assert(node->type == NodeTypeContinue); - - // Search up the scope. We'll find one of these things first: - // * function definition scope or global scope => error, break outside loop - // * defer expression scope => error, cannot break out of defer expression - // * loop scope => OK - - ZigList runtime_scopes = {}; - - Scope *search_scope = continue_scope; - ScopeLoop *loop_scope; - for (;;) { - if (search_scope == nullptr || search_scope->id == ScopeIdFnDef) { - if (node->data.continue_expr.name != nullptr) { - add_node_error(irb->codegen, node, buf_sprintf("labeled loop not found: '%s'", buf_ptr(node->data.continue_expr.name))); - return irb->codegen->invalid_inst_src; - } else { - add_node_error(irb->codegen, node, buf_sprintf("continue expression outside loop")); - return irb->codegen->invalid_inst_src; - } - } else if (search_scope->id == ScopeIdDeferExpr) { - add_node_error(irb->codegen, node, buf_sprintf("cannot continue out of defer expression")); - return irb->codegen->invalid_inst_src; - } else if (search_scope->id == ScopeIdLoop) { - ScopeLoop *this_loop_scope = (ScopeLoop *)search_scope; - if (node->data.continue_expr.name == nullptr || - (this_loop_scope->name != nullptr && buf_eql_buf(node->data.continue_expr.name, this_loop_scope->name))) - { - this_loop_scope->name_used = true; - loop_scope = this_loop_scope; - break; - } - } else if (search_scope->id == ScopeIdRuntime) { - ScopeRuntime *scope_runtime = (ScopeRuntime *)search_scope; - runtime_scopes.append(scope_runtime); - } - search_scope = search_scope->parent; - } - - IrInstSrc *is_comptime; - if (ir_should_inline(irb->exec, continue_scope)) { - is_comptime = ir_build_const_bool(irb, continue_scope, node, true); - } else { - is_comptime = loop_scope->is_comptime; - } - - for (size_t i = 0; i < runtime_scopes.length; i += 1) { - ScopeRuntime *scope_runtime = runtime_scopes.at(i); - ir_mark_gen(ir_build_check_runtime_scope(irb, continue_scope, node, scope_runtime->is_comptime, is_comptime)); - } - runtime_scopes.deinit(); - - IrBasicBlockSrc *dest_block = loop_scope->continue_block; - if (!ir_gen_defers_for_block(irb, continue_scope, dest_block->scope, nullptr, nullptr)) - return irb->codegen->invalid_inst_src; - return ir_mark_gen(ir_build_br(irb, continue_scope, node, dest_block, is_comptime)); -} - -static IrInstSrc *ir_gen_error_type(IrBuilderSrc *irb, Scope *scope, AstNode *node) { - assert(node->type == NodeTypeErrorType); - return ir_build_const_type(irb, scope, node, irb->codegen->builtin_types.entry_global_error_set); -} - -static IrInstSrc *ir_gen_defer(IrBuilderSrc *irb, Scope *parent_scope, AstNode *node) { - assert(node->type == NodeTypeDefer); - - ScopeDefer *defer_child_scope = create_defer_scope(irb->codegen, node, parent_scope); - node->data.defer.child_scope = &defer_child_scope->base; - - ScopeDeferExpr *defer_expr_scope = create_defer_expr_scope(irb->codegen, node, parent_scope); - node->data.defer.expr_scope = &defer_expr_scope->base; - - return ir_build_const_void(irb, parent_scope, node); -} - -static IrInstSrc *ir_gen_slice(IrBuilderSrc *irb, Scope *scope, AstNode *node, LVal lval, ResultLoc *result_loc) { - assert(node->type == NodeTypeSliceExpr); - - AstNodeSliceExpr *slice_expr = &node->data.slice_expr; - AstNode *array_node = slice_expr->array_ref_expr; - AstNode *start_node = slice_expr->start; - AstNode *end_node = slice_expr->end; - AstNode *sentinel_node = slice_expr->sentinel; - - IrInstSrc *ptr_value = ir_gen_node_extra(irb, array_node, scope, LValPtr, nullptr); - if (ptr_value == irb->codegen->invalid_inst_src) - return irb->codegen->invalid_inst_src; - - IrInstSrc *start_value = ir_gen_node(irb, start_node, scope); - if (start_value == irb->codegen->invalid_inst_src) - return irb->codegen->invalid_inst_src; - - IrInstSrc *end_value; - if (end_node) { - end_value = ir_gen_node(irb, end_node, scope); - if (end_value == irb->codegen->invalid_inst_src) - return irb->codegen->invalid_inst_src; - } else { - end_value = nullptr; - } - - IrInstSrc *sentinel_value; - if (sentinel_node) { - sentinel_value = ir_gen_node(irb, sentinel_node, scope); - if (sentinel_value == irb->codegen->invalid_inst_src) - return irb->codegen->invalid_inst_src; - } else { - sentinel_value = nullptr; - } - - IrInstSrc *slice = ir_build_slice_src(irb, scope, node, ptr_value, start_value, end_value, - sentinel_value, true, result_loc); - return ir_lval_wrap(irb, scope, slice, lval, result_loc); -} - -static IrInstSrc *ir_gen_catch(IrBuilderSrc *irb, Scope *parent_scope, AstNode *node, LVal lval, - ResultLoc *result_loc) -{ - assert(node->type == NodeTypeCatchExpr); - - AstNode *op1_node = node->data.unwrap_err_expr.op1; - AstNode *op2_node = node->data.unwrap_err_expr.op2; - AstNode *var_node = node->data.unwrap_err_expr.symbol; - - if (op2_node->type == NodeTypeUnreachable) { - if (var_node != nullptr) { - assert(var_node->type == NodeTypeSymbol); - Buf *var_name = var_node->data.symbol_expr.symbol; - add_node_error(irb->codegen, var_node, buf_sprintf("unused variable: '%s'", buf_ptr(var_name))); - return irb->codegen->invalid_inst_src; - } - return ir_gen_catch_unreachable(irb, parent_scope, node, op1_node, lval, result_loc); - } - - - ScopeExpr *spill_scope = create_expr_scope(irb->codegen, op1_node, parent_scope); - spill_scope->spill_harder = true; - - IrInstSrc *err_union_ptr = ir_gen_node_extra(irb, op1_node, &spill_scope->base, LValPtr, nullptr); - if (err_union_ptr == irb->codegen->invalid_inst_src) - return irb->codegen->invalid_inst_src; - - IrInstSrc *is_err = ir_build_test_err_src(irb, parent_scope, node, err_union_ptr, true, false); - - IrInstSrc *is_comptime; - if (ir_should_inline(irb->exec, parent_scope)) { - is_comptime = ir_build_const_bool(irb, parent_scope, node, true); - } else { - is_comptime = ir_build_test_comptime(irb, parent_scope, node, is_err); - } - - IrBasicBlockSrc *ok_block = ir_create_basic_block(irb, parent_scope, "UnwrapErrOk"); - IrBasicBlockSrc *err_block = ir_create_basic_block(irb, parent_scope, "UnwrapErrError"); - IrBasicBlockSrc *end_block = ir_create_basic_block(irb, parent_scope, "UnwrapErrEnd"); - IrInstSrc *cond_br_inst = ir_build_cond_br(irb, parent_scope, node, is_err, err_block, ok_block, is_comptime); - - ResultLocPeerParent *peer_parent = ir_build_binary_result_peers(irb, cond_br_inst, ok_block, end_block, result_loc, - is_comptime); - - ir_set_cursor_at_end_and_append_block(irb, err_block); - Scope *subexpr_scope = create_runtime_scope(irb->codegen, node, &spill_scope->base, is_comptime); - Scope *err_scope; - if (var_node) { - assert(var_node->type == NodeTypeSymbol); - Buf *var_name = var_node->data.symbol_expr.symbol; - bool is_const = true; - bool is_shadowable = false; - ZigVar *var = ir_create_var(irb, node, subexpr_scope, var_name, - is_const, is_const, is_shadowable, is_comptime); - err_scope = var->child_scope; - IrInstSrc *err_ptr = ir_build_unwrap_err_code_src(irb, err_scope, node, err_union_ptr); - IrInstSrc *err_value = ir_build_load_ptr(irb, err_scope, var_node, err_ptr); - build_decl_var_and_init(irb, err_scope, var_node, var, err_value, buf_ptr(var_name), is_comptime); - } else { - err_scope = subexpr_scope; - } - IrInstSrc *err_result = ir_gen_node_extra(irb, op2_node, err_scope, LValNone, &peer_parent->peers.at(0)->base); - if (err_result == irb->codegen->invalid_inst_src) - return irb->codegen->invalid_inst_src; - IrBasicBlockSrc *after_err_block = irb->current_basic_block; - if (!instr_is_unreachable(err_result)) - ir_mark_gen(ir_build_br(irb, parent_scope, node, end_block, is_comptime)); - - ir_set_cursor_at_end_and_append_block(irb, ok_block); - IrInstSrc *unwrapped_ptr = ir_build_unwrap_err_payload_src(irb, parent_scope, node, err_union_ptr, false, false); - IrInstSrc *unwrapped_payload = ir_build_load_ptr(irb, parent_scope, node, unwrapped_ptr); - ir_build_end_expr(irb, parent_scope, node, unwrapped_payload, &peer_parent->peers.at(1)->base); - IrBasicBlockSrc *after_ok_block = irb->current_basic_block; - ir_build_br(irb, parent_scope, node, end_block, is_comptime); - - ir_set_cursor_at_end_and_append_block(irb, end_block); - IrInstSrc **incoming_values = heap::c_allocator.allocate(2); - incoming_values[0] = err_result; - incoming_values[1] = unwrapped_payload; - IrBasicBlockSrc **incoming_blocks = heap::c_allocator.allocate(2); - incoming_blocks[0] = after_err_block; - incoming_blocks[1] = after_ok_block; - IrInstSrc *phi = ir_build_phi(irb, parent_scope, node, 2, incoming_blocks, incoming_values, peer_parent); - return ir_lval_wrap(irb, parent_scope, phi, lval, result_loc); -} - -static bool render_instance_name_recursive(CodeGen *codegen, Buf *name, Scope *outer_scope, Scope *inner_scope) { - if (inner_scope == nullptr || inner_scope == outer_scope) return false; - bool need_comma = render_instance_name_recursive(codegen, name, outer_scope, inner_scope->parent); - if (inner_scope->id != ScopeIdVarDecl) - return need_comma; - - ScopeVarDecl *var_scope = (ScopeVarDecl *)inner_scope; - if (need_comma) - buf_append_char(name, ','); - // TODO: const ptr reinterpret here to make the var type agree with the value? - render_const_value(codegen, name, var_scope->var->const_value); - return true; -} - -static Buf *get_anon_type_name(CodeGen *codegen, IrExecutableSrc *exec, const char *kind_name, - Scope *scope, AstNode *source_node, Buf *out_bare_name) -{ - if (exec != nullptr && exec->name) { - ZigType *import = get_scope_import(scope); - Buf *namespace_name = buf_alloc(); - append_namespace_qualification(codegen, namespace_name, import); - buf_append_buf(namespace_name, exec->name); - buf_init_from_buf(out_bare_name, exec->name); - return namespace_name; - } else if (exec != nullptr && exec->name_fn != nullptr) { - Buf *name = buf_alloc(); - buf_append_buf(name, &exec->name_fn->symbol_name); - buf_appendf(name, "("); - render_instance_name_recursive(codegen, name, &exec->name_fn->fndef_scope->base, exec->begin_scope); - buf_appendf(name, ")"); - buf_init_from_buf(out_bare_name, name); - return name; - } else { - ZigType *import = get_scope_import(scope); - Buf *namespace_name = buf_alloc(); - append_namespace_qualification(codegen, namespace_name, import); - buf_appendf(namespace_name, "%s:%" ZIG_PRI_usize ":%" ZIG_PRI_usize, kind_name, - source_node->line + 1, source_node->column + 1); - buf_init_from_buf(out_bare_name, namespace_name); - return namespace_name; - } -} - -static IrInstSrc *ir_gen_container_decl(IrBuilderSrc *irb, Scope *parent_scope, AstNode *node) { - assert(node->type == NodeTypeContainerDecl); - - ContainerKind kind = node->data.container_decl.kind; - Buf *bare_name = buf_alloc(); - Buf *name = get_anon_type_name(irb->codegen, irb->exec, container_string(kind), parent_scope, node, bare_name); - - ContainerLayout layout = node->data.container_decl.layout; - ZigType *container_type = get_partial_container_type(irb->codegen, parent_scope, - kind, node, buf_ptr(name), bare_name, layout); - ScopeDecls *child_scope = get_container_scope(container_type); - - for (size_t i = 0; i < node->data.container_decl.decls.length; i += 1) { - AstNode *child_node = node->data.container_decl.decls.at(i); - scan_decls(irb->codegen, child_scope, child_node); - } - - TldContainer *tld_container = heap::c_allocator.create(); - init_tld(&tld_container->base, TldIdContainer, bare_name, VisibModPub, node, parent_scope); - tld_container->type_entry = container_type; - tld_container->decls_scope = child_scope; - irb->codegen->resolve_queue.append(&tld_container->base); - - // Add this to the list to mark as invalid if analyzing this exec fails. - irb->exec->tld_list.append(&tld_container->base); - - return ir_build_const_type(irb, parent_scope, node, container_type); -} - // errors should be populated with set1's values static ZigType *get_error_set_union(CodeGen *g, ErrorTableEntry **errors, ZigType *set1, ZigType *set2, Buf *type_name) @@ -10003,497 +2511,6 @@ static ZigType *make_err_set_with_one_item(CodeGen *g, Scope *parent_scope, AstN return err_set_type; } -static AstNode *ast_field_to_symbol_node(AstNode *err_set_field_node) { - if (err_set_field_node->type == NodeTypeSymbol) { - return err_set_field_node; - } else if (err_set_field_node->type == NodeTypeErrorSetField) { - assert(err_set_field_node->data.err_set_field.field_name->type == NodeTypeSymbol); - return err_set_field_node->data.err_set_field.field_name; - } else { - return err_set_field_node; - } -} - -static IrInstSrc *ir_gen_err_set_decl(IrBuilderSrc *irb, Scope *parent_scope, AstNode *node) { - assert(node->type == NodeTypeErrorSetDecl); - - uint32_t err_count = node->data.err_set_decl.decls.length; - - Buf bare_name = BUF_INIT; - Buf *type_name = get_anon_type_name(irb->codegen, irb->exec, "error", parent_scope, node, &bare_name); - ZigType *err_set_type = new_type_table_entry(ZigTypeIdErrorSet); - buf_init_from_buf(&err_set_type->name, type_name); - err_set_type->data.error_set.err_count = err_count; - err_set_type->size_in_bits = irb->codegen->builtin_types.entry_global_error_set->size_in_bits; - err_set_type->abi_align = irb->codegen->builtin_types.entry_global_error_set->abi_align; - err_set_type->abi_size = irb->codegen->builtin_types.entry_global_error_set->abi_size; - err_set_type->data.error_set.errors = heap::c_allocator.allocate(err_count); - - size_t errors_count = irb->codegen->errors_by_index.length + err_count; - ErrorTableEntry **errors = heap::c_allocator.allocate(errors_count); - - for (uint32_t i = 0; i < err_count; i += 1) { - AstNode *field_node = node->data.err_set_decl.decls.at(i); - AstNode *symbol_node = ast_field_to_symbol_node(field_node); - Buf *err_name = symbol_node->data.symbol_expr.symbol; - ErrorTableEntry *err = heap::c_allocator.create(); - err->decl_node = field_node; - buf_init_from_buf(&err->name, err_name); - - auto existing_entry = irb->codegen->error_table.put_unique(err_name, err); - if (existing_entry) { - err->value = existing_entry->value->value; - } else { - size_t error_value_count = irb->codegen->errors_by_index.length; - assert((uint32_t)error_value_count < (((uint32_t)1) << (uint32_t)irb->codegen->err_tag_type->data.integral.bit_count)); - err->value = error_value_count; - irb->codegen->errors_by_index.append(err); - } - err_set_type->data.error_set.errors[i] = err; - - ErrorTableEntry *prev_err = errors[err->value]; - if (prev_err != nullptr) { - ErrorMsg *msg = add_node_error(irb->codegen, ast_field_to_symbol_node(err->decl_node), - buf_sprintf("duplicate error: '%s'", buf_ptr(&err->name))); - add_error_note(irb->codegen, msg, ast_field_to_symbol_node(prev_err->decl_node), - buf_sprintf("other error here")); - return irb->codegen->invalid_inst_src; - } - errors[err->value] = err; - } - heap::c_allocator.deallocate(errors, errors_count); - return ir_build_const_type(irb, parent_scope, node, err_set_type); -} - -static IrInstSrc *ir_gen_fn_proto(IrBuilderSrc *irb, Scope *parent_scope, AstNode *node) { - assert(node->type == NodeTypeFnProto); - - size_t param_count = node->data.fn_proto.params.length; - IrInstSrc **param_types = heap::c_allocator.allocate(param_count); - - bool is_var_args = false; - for (size_t i = 0; i < param_count; i += 1) { - AstNode *param_node = node->data.fn_proto.params.at(i); - if (param_node->data.param_decl.is_var_args) { - is_var_args = true; - break; - } - if (param_node->data.param_decl.anytype_token == nullptr) { - AstNode *type_node = param_node->data.param_decl.type; - IrInstSrc *type_value = ir_gen_node(irb, type_node, parent_scope); - if (type_value == irb->codegen->invalid_inst_src) - return irb->codegen->invalid_inst_src; - param_types[i] = type_value; - } else { - param_types[i] = nullptr; - } - } - - IrInstSrc *align_value = nullptr; - if (node->data.fn_proto.align_expr != nullptr) { - align_value = ir_gen_node(irb, node->data.fn_proto.align_expr, parent_scope); - if (align_value == irb->codegen->invalid_inst_src) - return irb->codegen->invalid_inst_src; - } - - IrInstSrc *callconv_value = nullptr; - if (node->data.fn_proto.callconv_expr != nullptr) { - callconv_value = ir_gen_node(irb, node->data.fn_proto.callconv_expr, parent_scope); - if (callconv_value == irb->codegen->invalid_inst_src) - return irb->codegen->invalid_inst_src; - } - - IrInstSrc *return_type; - if (node->data.fn_proto.return_type == nullptr) { - return_type = ir_build_const_type(irb, parent_scope, node, irb->codegen->builtin_types.entry_void); - } else { - return_type = ir_gen_node(irb, node->data.fn_proto.return_type, parent_scope); - if (return_type == irb->codegen->invalid_inst_src) - return irb->codegen->invalid_inst_src; - } - - return ir_build_fn_proto(irb, parent_scope, node, param_types, align_value, callconv_value, return_type, is_var_args); -} - -static IrInstSrc *ir_gen_resume(IrBuilderSrc *irb, Scope *scope, AstNode *node) { - assert(node->type == NodeTypeResume); - - IrInstSrc *target_inst = ir_gen_node_extra(irb, node->data.resume_expr.expr, scope, LValPtr, nullptr); - if (target_inst == irb->codegen->invalid_inst_src) - return irb->codegen->invalid_inst_src; - - return ir_build_resume_src(irb, scope, node, target_inst); -} - -static IrInstSrc *ir_gen_await_expr(IrBuilderSrc *irb, Scope *scope, AstNode *node, LVal lval, - ResultLoc *result_loc) -{ - assert(node->type == NodeTypeAwaitExpr); - - bool is_nosuspend = get_scope_nosuspend(scope) != nullptr; - - AstNode *expr_node = node->data.await_expr.expr; - if (expr_node->type == NodeTypeFnCallExpr && expr_node->data.fn_call_expr.modifier == CallModifierBuiltin) { - AstNode *fn_ref_expr = expr_node->data.fn_call_expr.fn_ref_expr; - Buf *name = fn_ref_expr->data.symbol_expr.symbol; - auto entry = irb->codegen->builtin_fn_table.maybe_get(name); - if (entry != nullptr) { - BuiltinFnEntry *builtin_fn = entry->value; - if (builtin_fn->id == BuiltinFnIdAsyncCall) { - return ir_gen_async_call(irb, scope, node, expr_node, lval, result_loc); - } - } - } - - ZigFn *fn_entry = exec_fn_entry(irb->exec); - if (!fn_entry) { - add_node_error(irb->codegen, node, buf_sprintf("await outside function definition")); - return irb->codegen->invalid_inst_src; - } - ScopeSuspend *existing_suspend_scope = get_scope_suspend(scope); - if (existing_suspend_scope) { - if (!existing_suspend_scope->reported_err) { - ErrorMsg *msg = add_node_error(irb->codegen, node, buf_sprintf("cannot await inside suspend block")); - add_error_note(irb->codegen, msg, existing_suspend_scope->base.source_node, buf_sprintf("suspend block here")); - existing_suspend_scope->reported_err = true; - } - return irb->codegen->invalid_inst_src; - } - - IrInstSrc *target_inst = ir_gen_node_extra(irb, expr_node, scope, LValPtr, nullptr); - if (target_inst == irb->codegen->invalid_inst_src) - return irb->codegen->invalid_inst_src; - - IrInstSrc *await_inst = ir_build_await_src(irb, scope, node, target_inst, result_loc, is_nosuspend); - return ir_lval_wrap(irb, scope, await_inst, lval, result_loc); -} - -static IrInstSrc *ir_gen_suspend(IrBuilderSrc *irb, Scope *parent_scope, AstNode *node) { - assert(node->type == NodeTypeSuspend); - - ZigFn *fn_entry = exec_fn_entry(irb->exec); - if (!fn_entry) { - add_node_error(irb->codegen, node, buf_sprintf("suspend outside function definition")); - return irb->codegen->invalid_inst_src; - } - if (get_scope_nosuspend(parent_scope) != nullptr) { - add_node_error(irb->codegen, node, buf_sprintf("suspend in nosuspend scope")); - return irb->codegen->invalid_inst_src; - } - - ScopeSuspend *existing_suspend_scope = get_scope_suspend(parent_scope); - if (existing_suspend_scope) { - if (!existing_suspend_scope->reported_err) { - ErrorMsg *msg = add_node_error(irb->codegen, node, buf_sprintf("cannot suspend inside suspend block")); - add_error_note(irb->codegen, msg, existing_suspend_scope->base.source_node, buf_sprintf("other suspend block here")); - existing_suspend_scope->reported_err = true; - } - return irb->codegen->invalid_inst_src; - } - - IrInstSrcSuspendBegin *begin = ir_build_suspend_begin_src(irb, parent_scope, node); - ScopeSuspend *suspend_scope = create_suspend_scope(irb->codegen, node, parent_scope); - Scope *child_scope = &suspend_scope->base; - IrInstSrc *susp_res = ir_gen_node(irb, node->data.suspend.block, child_scope); - if (susp_res == irb->codegen->invalid_inst_src) - return irb->codegen->invalid_inst_src; - ir_mark_gen(ir_build_check_statement_is_void(irb, child_scope, node->data.suspend.block, susp_res)); - - return ir_mark_gen(ir_build_suspend_finish_src(irb, parent_scope, node, begin)); -} - -static IrInstSrc *ir_gen_node_raw(IrBuilderSrc *irb, AstNode *node, Scope *scope, - LVal lval, ResultLoc *result_loc) -{ - assert(scope); - switch (node->type) { - case NodeTypeStructValueField: - case NodeTypeParamDecl: - case NodeTypeUsingNamespace: - case NodeTypeSwitchProng: - case NodeTypeSwitchRange: - case NodeTypeStructField: - case NodeTypeErrorSetField: - case NodeTypeFnDef: - case NodeTypeTestDecl: - zig_unreachable(); - case NodeTypeBlock: - return ir_gen_block(irb, scope, node, lval, result_loc); - case NodeTypeGroupedExpr: - return ir_gen_node_raw(irb, node->data.grouped_expr, scope, lval, result_loc); - case NodeTypeBinOpExpr: - return ir_gen_bin_op(irb, scope, node, lval, result_loc); - case NodeTypeIntLiteral: - return ir_lval_wrap(irb, scope, ir_gen_int_lit(irb, scope, node), lval, result_loc); - case NodeTypeFloatLiteral: - return ir_lval_wrap(irb, scope, ir_gen_float_lit(irb, scope, node), lval, result_loc); - case NodeTypeCharLiteral: - return ir_lval_wrap(irb, scope, ir_gen_char_lit(irb, scope, node), lval, result_loc); - case NodeTypeSymbol: - return ir_gen_symbol(irb, scope, node, lval, result_loc); - case NodeTypeFnCallExpr: - return ir_gen_fn_call(irb, scope, node, lval, result_loc); - case NodeTypeIfBoolExpr: - return ir_gen_if_bool_expr(irb, scope, node, lval, result_loc); - case NodeTypePrefixOpExpr: - return ir_gen_prefix_op_expr(irb, scope, node, lval, result_loc); - case NodeTypeContainerInitExpr: - return ir_gen_container_init_expr(irb, scope, node, lval, result_loc); - case NodeTypeVariableDeclaration: - return ir_gen_var_decl(irb, scope, node); - case NodeTypeWhileExpr: - return ir_gen_while_expr(irb, scope, node, lval, result_loc); - case NodeTypeForExpr: - return ir_gen_for_expr(irb, scope, node, lval, result_loc); - case NodeTypeArrayAccessExpr: - return ir_gen_array_access(irb, scope, node, lval, result_loc); - case NodeTypeReturnExpr: - return ir_gen_return(irb, scope, node, lval, result_loc); - case NodeTypeFieldAccessExpr: - { - IrInstSrc *ptr_instruction = ir_gen_field_access(irb, scope, node); - if (ptr_instruction == irb->codegen->invalid_inst_src) - return ptr_instruction; - if (lval == LValPtr || lval == LValAssign) - return ptr_instruction; - - IrInstSrc *load_ptr = ir_build_load_ptr(irb, scope, node, ptr_instruction); - return ir_expr_wrap(irb, scope, load_ptr, result_loc); - } - case NodeTypePtrDeref: { - AstNode *expr_node = node->data.ptr_deref_expr.target; - - LVal child_lval = lval; - if (child_lval == LValAssign) - child_lval = LValPtr; - - IrInstSrc *value = ir_gen_node_extra(irb, expr_node, scope, child_lval, nullptr); - if (value == irb->codegen->invalid_inst_src) - return value; - - // We essentially just converted any lvalue from &(x.*) to (&x).*; - // this inhibits checking that x is a pointer later, so we directly - // record whether the pointer check is needed - IrInstSrc *un_op = ir_build_un_op_lval(irb, scope, node, IrUnOpDereference, value, lval, result_loc); - return ir_expr_wrap(irb, scope, un_op, result_loc); - } - case NodeTypeUnwrapOptional: { - AstNode *expr_node = node->data.unwrap_optional.expr; - - IrInstSrc *maybe_ptr = ir_gen_node_extra(irb, expr_node, scope, LValPtr, nullptr); - if (maybe_ptr == irb->codegen->invalid_inst_src) - return irb->codegen->invalid_inst_src; - - IrInstSrc *unwrapped_ptr = ir_build_optional_unwrap_ptr(irb, scope, node, maybe_ptr, true ); - if (lval == LValPtr || lval == LValAssign) - return unwrapped_ptr; - - IrInstSrc *load_ptr = ir_build_load_ptr(irb, scope, node, unwrapped_ptr); - return ir_expr_wrap(irb, scope, load_ptr, result_loc); - } - case NodeTypeBoolLiteral: - return ir_lval_wrap(irb, scope, ir_gen_bool_literal(irb, scope, node), lval, result_loc); - case NodeTypeArrayType: - return ir_lval_wrap(irb, scope, ir_gen_array_type(irb, scope, node), lval, result_loc); - case NodeTypePointerType: - return ir_lval_wrap(irb, scope, ir_gen_pointer_type(irb, scope, node), lval, result_loc); - case NodeTypeAnyFrameType: - return ir_lval_wrap(irb, scope, ir_gen_anyframe_type(irb, scope, node), lval, result_loc); - case NodeTypeStringLiteral: - return ir_lval_wrap(irb, scope, ir_gen_string_literal(irb, scope, node), lval, result_loc); - case NodeTypeUndefinedLiteral: - return ir_lval_wrap(irb, scope, ir_gen_undefined_literal(irb, scope, node), lval, result_loc); - case NodeTypeAsmExpr: - return ir_lval_wrap(irb, scope, ir_gen_asm_expr(irb, scope, node), lval, result_loc); - case NodeTypeNullLiteral: - return ir_lval_wrap(irb, scope, ir_gen_null_literal(irb, scope, node), lval, result_loc); - case NodeTypeIfErrorExpr: - return ir_gen_if_err_expr(irb, scope, node, lval, result_loc); - case NodeTypeIfOptional: - return ir_gen_if_optional_expr(irb, scope, node, lval, result_loc); - case NodeTypeSwitchExpr: - return ir_gen_switch_expr(irb, scope, node, lval, result_loc); - case NodeTypeCompTime: - return ir_expr_wrap(irb, scope, ir_gen_comptime(irb, scope, node, lval), result_loc); - case NodeTypeNoSuspend: - return ir_expr_wrap(irb, scope, ir_gen_nosuspend(irb, scope, node, lval), result_loc); - case NodeTypeErrorType: - return ir_lval_wrap(irb, scope, ir_gen_error_type(irb, scope, node), lval, result_loc); - case NodeTypeBreak: - return ir_lval_wrap(irb, scope, ir_gen_break(irb, scope, node), lval, result_loc); - case NodeTypeContinue: - return ir_lval_wrap(irb, scope, ir_gen_continue(irb, scope, node), lval, result_loc); - case NodeTypeUnreachable: - return ir_build_unreachable(irb, scope, node); - case NodeTypeDefer: - return ir_lval_wrap(irb, scope, ir_gen_defer(irb, scope, node), lval, result_loc); - case NodeTypeSliceExpr: - return ir_gen_slice(irb, scope, node, lval, result_loc); - case NodeTypeCatchExpr: - return ir_gen_catch(irb, scope, node, lval, result_loc); - case NodeTypeContainerDecl: - return ir_lval_wrap(irb, scope, ir_gen_container_decl(irb, scope, node), lval, result_loc); - case NodeTypeFnProto: - return ir_lval_wrap(irb, scope, ir_gen_fn_proto(irb, scope, node), lval, result_loc); - case NodeTypeErrorSetDecl: - return ir_lval_wrap(irb, scope, ir_gen_err_set_decl(irb, scope, node), lval, result_loc); - case NodeTypeResume: - return ir_lval_wrap(irb, scope, ir_gen_resume(irb, scope, node), lval, result_loc); - case NodeTypeAwaitExpr: - return ir_gen_await_expr(irb, scope, node, lval, result_loc); - case NodeTypeSuspend: - return ir_lval_wrap(irb, scope, ir_gen_suspend(irb, scope, node), lval, result_loc); - case NodeTypeEnumLiteral: - return ir_lval_wrap(irb, scope, ir_gen_enum_literal(irb, scope, node), lval, result_loc); - case NodeTypeInferredArrayType: - add_node_error(irb->codegen, node, - buf_sprintf("inferred array size invalid here")); - return irb->codegen->invalid_inst_src; - case NodeTypeAnyTypeField: - return ir_lval_wrap(irb, scope, - ir_build_const_type(irb, scope, node, irb->codegen->builtin_types.entry_anytype), lval, result_loc); - } - zig_unreachable(); -} - -static ResultLoc *no_result_loc(void) { - ResultLocNone *result_loc_none = heap::c_allocator.create(); - result_loc_none->base.id = ResultLocIdNone; - return &result_loc_none->base; -} - -static IrInstSrc *ir_gen_node_extra(IrBuilderSrc *irb, AstNode *node, Scope *scope, LVal lval, - ResultLoc *result_loc) -{ - if (lval == LValAssign) { - switch (node->type) { - case NodeTypeStructValueField: - case NodeTypeParamDecl: - case NodeTypeUsingNamespace: - case NodeTypeSwitchProng: - case NodeTypeSwitchRange: - case NodeTypeStructField: - case NodeTypeErrorSetField: - case NodeTypeFnDef: - case NodeTypeTestDecl: - zig_unreachable(); - - // cannot be assigned to - case NodeTypeBlock: - case NodeTypeGroupedExpr: - case NodeTypeBinOpExpr: - case NodeTypeIntLiteral: - case NodeTypeFloatLiteral: - case NodeTypeCharLiteral: - case NodeTypeIfBoolExpr: - case NodeTypeContainerInitExpr: - case NodeTypeVariableDeclaration: - case NodeTypeWhileExpr: - case NodeTypeForExpr: - case NodeTypeReturnExpr: - case NodeTypeBoolLiteral: - case NodeTypeArrayType: - case NodeTypePointerType: - case NodeTypeAnyFrameType: - case NodeTypeStringLiteral: - case NodeTypeUndefinedLiteral: - case NodeTypeAsmExpr: - case NodeTypeNullLiteral: - case NodeTypeIfErrorExpr: - case NodeTypeIfOptional: - case NodeTypeSwitchExpr: - case NodeTypeCompTime: - case NodeTypeNoSuspend: - case NodeTypeErrorType: - case NodeTypeBreak: - case NodeTypeContinue: - case NodeTypeUnreachable: - case NodeTypeDefer: - case NodeTypeSliceExpr: - case NodeTypeCatchExpr: - case NodeTypeContainerDecl: - case NodeTypeFnProto: - case NodeTypeErrorSetDecl: - case NodeTypeResume: - case NodeTypeAwaitExpr: - case NodeTypeSuspend: - case NodeTypeEnumLiteral: - case NodeTypeInferredArrayType: - case NodeTypeAnyTypeField: - case NodeTypePrefixOpExpr: - add_node_error(irb->codegen, node, - buf_sprintf("invalid left-hand side to assignment")); - return irb->codegen->invalid_inst_src; - - // @field can be assigned to - case NodeTypeFnCallExpr: - if (node->data.fn_call_expr.modifier == CallModifierBuiltin) { - AstNode *fn_ref_expr = node->data.fn_call_expr.fn_ref_expr; - Buf *name = fn_ref_expr->data.symbol_expr.symbol; - auto entry = irb->codegen->builtin_fn_table.maybe_get(name); - - if (!entry) { - add_node_error(irb->codegen, node, - buf_sprintf("invalid builtin function: '%s'", buf_ptr(name))); - return irb->codegen->invalid_inst_src; - } - - if (entry->value->id == BuiltinFnIdField) { - break; - } - } - add_node_error(irb->codegen, node, - buf_sprintf("invalid left-hand side to assignment")); - return irb->codegen->invalid_inst_src; - - - // can be assigned to - case NodeTypeUnwrapOptional: - case NodeTypePtrDeref: - case NodeTypeFieldAccessExpr: - case NodeTypeArrayAccessExpr: - case NodeTypeSymbol: - break; - } - } - if (result_loc == nullptr) { - // Create a result location indicating there is none - but if one gets created - // it will be properly distributed. - result_loc = no_result_loc(); - ir_build_reset_result(irb, scope, node, result_loc); - } - Scope *child_scope; - if (irb->exec->is_inline || - (irb->exec->fn_entry != nullptr && irb->exec->fn_entry->child_scope == scope)) - { - child_scope = scope; - } else { - child_scope = &create_expr_scope(irb->codegen, node, scope)->base; - } - IrInstSrc *result = ir_gen_node_raw(irb, node, child_scope, lval, result_loc); - if (result == irb->codegen->invalid_inst_src) { - if (irb->exec->first_err_trace_msg == nullptr) { - irb->exec->first_err_trace_msg = irb->codegen->trace_err; - } - } - return result; -} - -static IrInstSrc *ir_gen_node(IrBuilderSrc *irb, AstNode *node, Scope *scope) { - return ir_gen_node_extra(irb, node, scope, LValNone, nullptr); -} - -static void invalidate_exec(IrExecutableSrc *exec, ErrorMsg *msg) { - if (exec->first_err_trace_msg != nullptr) - return; - - exec->first_err_trace_msg = msg; - - for (size_t i = 0; i < exec->tld_list.length; i += 1) { - exec->tld_list.items[i]->resolution = TldResolutionInvalid; - } -} - static void invalidate_exec_gen(IrExecutableGen *exec, ErrorMsg *msg) { if (exec->first_err_trace_msg != nullptr) return; @@ -10509,78 +2526,6 @@ static void invalidate_exec_gen(IrExecutableGen *exec, ErrorMsg *msg) { } -bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutableSrc *ir_executable) { - assert(node->owner); - - IrBuilderSrc ir_builder = {0}; - IrBuilderSrc *irb = &ir_builder; - - irb->codegen = codegen; - irb->exec = ir_executable; - irb->main_block_node = node; - - IrBasicBlockSrc *entry_block = ir_create_basic_block(irb, scope, "Entry"); - ir_set_cursor_at_end_and_append_block(irb, entry_block); - // Entry block gets a reference because we enter it to begin. - ir_ref_bb(irb->current_basic_block); - - IrInstSrc *result = ir_gen_node_extra(irb, node, scope, LValNone, nullptr); - - if (result == irb->codegen->invalid_inst_src) - return false; - - if (irb->exec->first_err_trace_msg != nullptr) { - codegen->trace_err = irb->exec->first_err_trace_msg; - return false; - } - - if (!instr_is_unreachable(result)) { - ir_mark_gen(ir_build_add_implicit_return_type(irb, scope, result->base.source_node, result, nullptr)); - // no need for save_err_ret_addr because this cannot return error - ResultLocReturn *result_loc_ret = heap::c_allocator.create(); - result_loc_ret->base.id = ResultLocIdReturn; - ir_build_reset_result(irb, scope, node, &result_loc_ret->base); - ir_mark_gen(ir_build_end_expr(irb, scope, node, result, &result_loc_ret->base)); - ir_mark_gen(ir_build_return_src(irb, scope, result->base.source_node, result)); - } - - return true; -} - -bool ir_gen_fn(CodeGen *codegen, ZigFn *fn_entry) { - assert(fn_entry); - - IrExecutableSrc *ir_executable = fn_entry->ir_executable; - AstNode *body_node = fn_entry->body_node; - - assert(fn_entry->child_scope); - - return ir_gen(codegen, body_node, fn_entry->child_scope, ir_executable); -} - -static void ir_add_call_stack_errors_gen(CodeGen *codegen, IrExecutableGen *exec, ErrorMsg *err_msg, int limit) { - if (!exec || !exec->source_node || limit < 0) return; - add_error_note(codegen, err_msg, exec->source_node, buf_sprintf("called from here")); - - ir_add_call_stack_errors_gen(codegen, exec->parent_exec, err_msg, limit - 1); -} - -static void ir_add_call_stack_errors(CodeGen *codegen, IrExecutableSrc *exec, ErrorMsg *err_msg, int limit) { - if (!exec || !exec->source_node || limit < 0) return; - add_error_note(codegen, err_msg, exec->source_node, buf_sprintf("called from here")); - - ir_add_call_stack_errors_gen(codegen, exec->parent_exec, err_msg, limit - 1); -} - -static ErrorMsg *exec_add_error_node(CodeGen *codegen, IrExecutableSrc *exec, AstNode *source_node, Buf *msg) { - ErrorMsg *err_msg = add_node_error(codegen, source_node, msg); - invalidate_exec(exec, err_msg); - if (exec->parent_exec) { - ir_add_call_stack_errors(codegen, exec, err_msg, 10); - } - return err_msg; -} - static ErrorMsg *exec_add_error_node_gen(CodeGen *codegen, IrExecutableGen *exec, AstNode *source_node, Buf *msg) { ErrorMsg *err_msg = add_node_error(codegen, source_node, msg); invalidate_exec_gen(exec, err_msg); @@ -10605,11 +2550,6 @@ static ErrorMsg *ir_add_error(IrAnalyze *ira, IrInst *source_instruction, Buf *m return ir_add_error_node(ira, source_instruction->source_node, msg); } -static void ir_assert_impl(bool ok, IrInst *source_instruction, char const *file, unsigned int line) { - if (ok) return; - src_assert_impl(ok, source_instruction->source_node, file, line); -} - static void ir_assert_gen_impl(bool ok, IrInstGen *source_instruction, char const *file, unsigned int line) { if (ok) return; src_assert_impl(ok, source_instruction->base.source_node, file, line); @@ -13665,8 +5605,6 @@ Error ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node, } if (codegen->verbose_ir) { - fprintf(stderr, "\nSource: "); - ast_render(stderr, node, 4); fprintf(stderr, "\n{ // (IR)\n"); ir_print_src(codegen, stderr, ir_executable, 2); fprintf(stderr, "}\n"); @@ -19482,7 +11420,7 @@ static IrInstGen *ir_analyze_instruction_extern(IrAnalyze *ira, IrInstSrcExtern } static bool exec_has_err_ret_trace(CodeGen *g, IrExecutableSrc *exec) { - ZigFn *fn_entry = exec_fn_entry(exec); + ZigFn *fn_entry = exec->fn_entry; return fn_entry != nullptr && fn_entry->calls_or_awaits_errorable_fn && g->have_err_ret_tracing; } @@ -20319,7 +12257,7 @@ static bool ir_analyze_fn_call_inline_arg(IrAnalyze *ira, AstNode *fn_proto_node assert(param_decl_node->type == NodeTypeParamDecl); IrInstGen *casted_arg; - if (param_decl_node->data.param_decl.anytype_token == nullptr) { + if (param_decl_node->data.param_decl.anytype_token == 0) { AstNode *param_type_node = param_decl_node->data.param_decl.type; ZigType *param_type = ir_analyze_type_expr(ira, *exec_scope, param_type_node); if (type_is_invalid(param_type)) @@ -20362,7 +12300,7 @@ static bool ir_analyze_fn_call_generic_arg(IrAnalyze *ira, AstNode *fn_proto_nod casted_arg = arg; param_info_type = arg->value->type; } else { - if (param_decl_node->data.param_decl.anytype_token == nullptr) { + if (param_decl_node->data.param_decl.anytype_token == 0) { AstNode *param_type_node = param_decl_node->data.param_decl.type; ZigType *param_type = ir_analyze_type_expr(ira, *child_scope, param_type_node); if (type_is_invalid(param_type)) @@ -23593,6 +15531,25 @@ static IrInstGen *ir_analyze_instruction_slice_type(IrAnalyze *ira, IrInstSrcSli return result; } +static size_t find_asm_index(CodeGen *g, AstNode *node, AsmToken *tok, Buf *src_template) { + const char *ptr = buf_ptr(src_template) + tok->start + 2; + size_t len = tok->end - tok->start - 2; + size_t result = 0; + for (size_t i = 0; i < node->data.asm_expr.output_list.length; i += 1, result += 1) { + AsmOutput *asm_output = node->data.asm_expr.output_list.at(i); + if (buf_eql_mem(asm_output->asm_symbolic_name, ptr, len)) { + return result; + } + } + for (size_t i = 0; i < node->data.asm_expr.input_list.length; i += 1, result += 1) { + AsmInput *asm_input = node->data.asm_expr.input_list.at(i); + if (buf_eql_mem(asm_input->asm_symbolic_name, ptr, len)) { + return result; + } + } + return SIZE_MAX; +} + static IrInstGen *ir_analyze_instruction_asm(IrAnalyze *ira, IrInstSrcAsm *asm_instruction) { Error err; @@ -27066,8 +19023,10 @@ static IrInstGen *ir_analyze_instruction_c_import(IrAnalyze *ira, IrInstSrcCImpo return ira->codegen->invalid_inst_gen; ZigPackage *cur_scope_pkg = scope_package(instruction->base.base.scope); - Buf *namespace_name = buf_sprintf("%s.cimport:%" ZIG_PRI_usize ":%" ZIG_PRI_usize, - buf_ptr(&cur_scope_pkg->pkg_path), node->line + 1, node->column + 1); + RootStruct *root_struct = node->owner->data.structure.root_struct; + TokenLoc tok_loc = root_struct->token_locs[node->main_token]; + Buf *namespace_name = buf_sprintf("%s.cimport:%" PRIu32 ":%" PRIu32, + buf_ptr(&cur_scope_pkg->pkg_path), tok_loc.line + 1, tok_loc.column + 1); ZigPackage *cimport_pkg = new_anonymous_package(); cimport_pkg->package_table.put(buf_create_from_str("builtin"), ira->codegen->compile_var_package); @@ -27095,12 +19054,14 @@ static IrInstGen *ir_analyze_instruction_c_import(IrAnalyze *ira, IrInstSrcCImpo } for (size_t i = 0; i < errors_len; i += 1) { Stage2ErrorMsg *clang_err = &errors_ptr[i]; - // Clang can emit "too many errors, stopping now", in which case `source` and `filename_ptr` are null + // Clang can emit "too many errors, stopping now", in which case + // `source` and `filename_ptr` are null if (clang_err->source && clang_err->filename_ptr) { ErrorMsg *err_msg = err_msg_create_with_offset( clang_err->filename_ptr ? - buf_create_from_mem(clang_err->filename_ptr, clang_err->filename_len) : buf_alloc(), - clang_err->line, clang_err->column, clang_err->offset, clang_err->source, + buf_create_from_mem(clang_err->filename_ptr, clang_err->filename_len) : + buf_alloc(), + clang_err->offset, clang_err->source, buf_create_from_mem(clang_err->msg_ptr, clang_err->msg_len)); err_msg_add_note(parent_err_msg, err_msg); } @@ -27225,7 +19186,7 @@ static IrInstGen *ir_analyze_instruction_embed_file(IrAnalyze *ira, IrInstSrcEmb } IrInstGen *result = ir_const(ira, &instruction->base.base, nullptr); - init_const_str_lit(ira->codegen, result->value, file_contents); + init_const_str_lit(ira->codegen, result->value, file_contents, true); return result; } @@ -31851,6 +23812,22 @@ static IrInstGen *ir_analyze_instruction_has_decl(IrAnalyze *ira, IrInstSrcHasDe return ir_const_bool(ira, &instruction->base.base, true); } +static void populate_invalid_variable_in_scope(CodeGen *g, Scope *scope, AstNode *node, Buf *var_name) { + ScopeDecls *scope_decls = nullptr; + while (scope != nullptr) { + if (scope->id == ScopeIdDecls) { + scope_decls = reinterpret_cast(scope); + } + scope = scope->parent; + } + TldVar *tld_var = heap::c_allocator.create(); + init_tld(&tld_var->base, TldIdVar, var_name, VisibModPub, node, &scope_decls->base); + tld_var->base.resolution = TldResolutionInvalid; + tld_var->var = add_variable(g, node, &scope_decls->base, var_name, false, + g->invalid_inst_gen->value, &tld_var->base, g->builtin_types.entry_invalid); + scope_decls->decl_table.put(var_name, &tld_var->base); +} + static IrInstGen *ir_analyze_instruction_undeclared_ident(IrAnalyze *ira, IrInstSrcUndeclaredIdent *instruction) { // put a variable of same name with invalid type in global scope // so that future references to this same name will find a variable with an invalid type @@ -32169,7 +24146,8 @@ static IrInstGen *ir_analyze_instruction_src(IrAnalyze *ira, IrInstSrcSrc *instr fields[0]->special = ConstValSpecialStatic; ZigType *import = instruction->base.base.source_node->owner; - Buf *path = import->data.structure.root_struct->path; + RootStruct *root_struct = import->data.structure.root_struct; + Buf *path = root_struct->path; ZigValue *file_name = create_const_str_lit(ira->codegen, path)->data.x_ptr.data.ref.pointee; init_const_slice(ira->codegen, fields[0], file_name, 0, buf_len(path), true); fields[0]->type = u8_slice; @@ -32182,17 +24160,20 @@ static IrInstGen *ir_analyze_instruction_src(IrAnalyze *ira, IrInstSrcSrc *instr init_const_slice(ira->codegen, fields[1], fn_name, 0, buf_len(&fn_entry->symbol_name), true); fields[1]->type = u8_slice; + + TokenLoc tok_loc = root_struct->token_locs[instruction->base.base.source_node->main_token]; + // line: u32 ensure_field_index(source_location_type, "line", 2); fields[2]->special = ConstValSpecialStatic; fields[2]->type = ira->codegen->builtin_types.entry_u32; - bigint_init_unsigned(&fields[2]->data.x_bigint, instruction->base.base.source_node->line + 1); + bigint_init_unsigned(&fields[2]->data.x_bigint, tok_loc.line + 1); // column: u32 ensure_field_index(source_location_type, "column", 3); fields[3]->special = ConstValSpecialStatic; fields[3]->type = ira->codegen->builtin_types.entry_u32; - bigint_init_unsigned(&fields[3]->data.x_bigint, instruction->base.base.source_node->column + 1); + bigint_init_unsigned(&fields[3]->data.x_bigint, tok_loc.column + 1); return ir_const_move(ira, &instruction->base.base, result); } @@ -32539,20 +24520,6 @@ ZigType *ir_analyze(CodeGen *codegen, IrExecutableSrc *old_exec, IrExecutableGen old_instruction->src(); fprintf(stderr, "~ "); ir_print_inst_src(codegen, stderr, old_instruction, 0); - bool want_break = false; - if (ira->break_debug_id == old_instruction->base.debug_id) { - want_break = true; - } else if (old_instruction->base.source_node != nullptr) { - for (size_t i = 0; i < dbg_ir_breakpoints_count; i += 1) { - if (dbg_ir_breakpoints_buf[i].line == old_instruction->base.source_node->line + 1 && - buf_ends_with_str(old_instruction->base.source_node->owner->data.structure.root_struct->path, - dbg_ir_breakpoints_buf[i].src_file)) - { - want_break = true; - } - } - } - if (want_break) BREAKPOINT; } IrInstGen *new_instruction = ir_analyze_instruction_base(ira, old_instruction); if (new_instruction != nullptr) { @@ -33541,11 +25508,3 @@ void IrAnalyze::dump() { ir_print_basic_block_gen(this->codegen, stderr, this->new_irb.current_basic_block, 1); } } - -void dbg_ir_break(const char *src_file, uint32_t line) { - dbg_ir_breakpoints_buf[dbg_ir_breakpoints_count] = {src_file, line}; - dbg_ir_breakpoints_count += 1; -} -void dbg_ir_clear(void) { - dbg_ir_breakpoints_count = 0; -} diff --git a/src/stage1/ir.hpp b/src/stage1/ir.hpp index 3686771287..66f0b9a99b 100644 --- a/src/stage1/ir.hpp +++ b/src/stage1/ir.hpp @@ -10,9 +10,6 @@ #include "all_types.hpp" -bool ir_gen(CodeGen *g, AstNode *node, Scope *scope, IrExecutableSrc *ir_executable); -bool ir_gen_fn(CodeGen *g, ZigFn *fn_entry); - IrInstGen *ir_create_alloca(CodeGen *g, Scope *scope, AstNode *source_node, ZigFn *fn, ZigType *var_type, const char *name_hint); @@ -33,8 +30,4 @@ struct IrAnalyze; ZigValue *const_ptr_pointee(IrAnalyze *ira, CodeGen *codegen, ZigValue *const_val, AstNode *source_node); -// for debugging purposes -void dbg_ir_break(const char *src_file, uint32_t line); -void dbg_ir_clear(void); - #endif diff --git a/src/stage1/parser.cpp b/src/stage1/parser.cpp index 19cd977c71..51acc6a566 100644 --- a/src/stage1/parser.cpp +++ b/src/stage1/parser.cpp @@ -16,28 +16,34 @@ struct ParseContext { Buf *buf; - size_t current_token; - ZigList *tokens; + // Shortcut to `owner->data.structure.root_struct->token_ids`. + TokenId *token_ids; + // Shortcut to `owner->data.structure.root_struct->token_locs`. + TokenLoc *token_locs; ZigType *owner; + TokenIndex current_token; ErrColor err_color; + // Shortcut to `owner->data.structure.root_struct->token_count`. + uint32_t token_count; }; struct PtrPayload { - Token *asterisk; - Token *payload; + TokenIndex asterisk; + TokenIndex payload; }; struct PtrIndexPayload { - Token *asterisk; - Token *payload; - Token *index; + TokenIndex asterisk; + TokenIndex payload; + TokenIndex index; }; static AstNode *ast_parse_root(ParseContext *pc); static AstNodeContainerDecl ast_parse_container_members(ParseContext *pc); static AstNode *ast_parse_test_decl(ParseContext *pc); static AstNode *ast_parse_top_level_comptime(ParseContext *pc); -static AstNode *ast_parse_top_level_decl(ParseContext *pc, VisibMod visib_mod, Buf *doc_comments); +static AstNode *ast_parse_top_level_decl(ParseContext *pc, VisibMod visib_mod, + TokenIndex doc_comments); static AstNode *ast_parse_fn_proto(ParseContext *pc); static AstNode *ast_parse_var_decl(ParseContext *pc); static AstNode *ast_parse_container_field(ParseContext *pc); @@ -87,8 +93,8 @@ static AsmOutput *ast_parse_asm_output_item(ParseContext *pc); static AstNode *ast_parse_asm_input(ParseContext *pc); static AsmInput *ast_parse_asm_input_item(ParseContext *pc); static AstNode *ast_parse_asm_clobbers(ParseContext *pc); -static Token *ast_parse_break_label(ParseContext *pc); -static Token *ast_parse_block_label(ParseContext *pc); +static TokenIndex ast_parse_break_label(ParseContext *pc); +static TokenIndex ast_parse_block_label(ParseContext *pc); static AstNode *ast_parse_field_init(ParseContext *pc); static AstNode *ast_parse_while_continue_expr(ParseContext *pc); static AstNode *ast_parse_link_section(ParseContext *pc); @@ -98,7 +104,7 @@ static AstNode *ast_parse_param_type(ParseContext *pc); static AstNode *ast_parse_if_prefix(ParseContext *pc); static AstNode *ast_parse_while_prefix(ParseContext *pc); static AstNode *ast_parse_for_prefix(ParseContext *pc); -static Token *ast_parse_payload(ParseContext *pc); +static TokenIndex ast_parse_payload(ParseContext *pc); static Optional ast_parse_ptr_payload(ParseContext *pc); static Optional ast_parse_ptr_index_payload(ParseContext *pc); static AstNode *ast_parse_switch_prong(ParseContext *pc); @@ -122,27 +128,25 @@ static AstNode *ast_parse_byte_align(ParseContext *pc); ATTRIBUTE_PRINTF(3, 4) ATTRIBUTE_NORETURN -static void ast_error(ParseContext *pc, Token *token, const char *format, ...) { +static void ast_error(ParseContext *pc, TokenIndex token, const char *format, ...) { va_list ap; va_start(ap, format); Buf *msg = buf_vprintf(format, ap); va_end(ap); - - ErrorMsg *err = err_msg_create_with_line(pc->owner->data.structure.root_struct->path, - token->start_line, token->start_column, - pc->owner->data.structure.root_struct->source_code, - pc->owner->data.structure.root_struct->line_offsets, msg); - err->line_start = token->start_line; - err->column_start = token->start_column; + RootStruct *root_struct = pc->owner->data.structure.root_struct; + assert(token < root_struct->token_count); + uint32_t byte_offset = root_struct->token_locs[token].offset; + ErrorMsg *err = err_msg_create_with_offset(root_struct->path, + byte_offset, buf_ptr(root_struct->source_code), msg); print_err_msg(err, pc->err_color); exit(EXIT_FAILURE); } ATTRIBUTE_NORETURN -static void ast_invalid_token_error(ParseContext *pc, Token *token) { - ast_error(pc, token, "invalid token: '%s'", token_name(token->id)); +static void ast_invalid_token_error(ParseContext *pc, TokenIndex token) { + ast_error(pc, token, "invalid token: '%s'", token_name(pc->token_ids[token])); } static AstNode *ast_create_node_no_line_info(ParseContext *pc, NodeType type) { @@ -152,48 +156,44 @@ static AstNode *ast_create_node_no_line_info(ParseContext *pc, NodeType type) { return node; } -static AstNode *ast_create_node(ParseContext *pc, NodeType type, Token *first_token) { +static AstNode *ast_create_node(ParseContext *pc, NodeType type, TokenIndex first_token) { assert(first_token); AstNode *node = ast_create_node_no_line_info(pc, type); - node->line = first_token->start_line; - node->column = first_token->start_column; + node->main_token = first_token; return node; } static AstNode *ast_create_node_copy_line_info(ParseContext *pc, NodeType type, AstNode *from) { assert(from); AstNode *node = ast_create_node_no_line_info(pc, type); - node->line = from->line; - node->column = from->column; + node->main_token = from->main_token; return node; } -static Token *peek_token_i(ParseContext *pc, size_t i) { - return &pc->tokens->at(pc->current_token + i); +static TokenIndex peek_token(ParseContext *pc) { + return pc->current_token; } -static Token *peek_token(ParseContext *pc) { - return peek_token_i(pc, 0); -} - -static Token *eat_token(ParseContext *pc) { - Token *res = peek_token(pc); +static TokenIndex eat_token(ParseContext *pc) { + TokenIndex res = peek_token(pc); pc->current_token += 1; return res; } -static Token *eat_token_if(ParseContext *pc, TokenId id) { - Token *res = peek_token(pc); - if (res->id == id) +static TokenIndex eat_token_if(ParseContext *pc, TokenId id) { + TokenIndex res = peek_token(pc); + if (pc->token_ids[res] == id) { return eat_token(pc); + } - return nullptr; + return 0; } -static Token *expect_token(ParseContext *pc, TokenId id) { - Token *res = eat_token(pc); - if (res->id != id) - ast_error(pc, res, "expected token '%s', found '%s'", token_name(id), token_name(res->id)); +static TokenIndex expect_token(ParseContext *pc, TokenId id) { + TokenIndex res = eat_token(pc); + TokenId actual_id = pc->token_ids[res]; + if (actual_id != id) + ast_error(pc, res, "expected token '%s', found '%s'", token_name(id), token_name(actual_id)); return res; } @@ -202,23 +202,23 @@ static void put_back_token(ParseContext *pc) { pc->current_token -= 1; } -static Buf *token_buf(Token *token) { - if (token == nullptr) +static Buf *token_buf(ParseContext *pc, TokenIndex token) { + if (token == 0) return nullptr; - assert(token->id == TokenIdStringLiteral || token->id == TokenIdMultilineStringLiteral || token->id == TokenIdSymbol); - return &token->data.str_lit.str; + + RootStruct *root_struct = pc->owner->data.structure.root_struct; + if (root_struct->token_ids[token] == TokenIdIdentifier) { + return token_identifier_buf(root_struct, token); + } else if (root_struct->token_ids[token] == TokenIdStringLiteral) { + return token_string_literal_buf(root_struct, token); + } else { + zig_unreachable(); + } } -static BigInt *token_bigint(Token *token) { - assert(token->id == TokenIdIntLiteral); - return &token->data.int_lit.bigint; -} - -static AstNode *token_symbol(ParseContext *pc, Token *token) { - assert(token->id == TokenIdSymbol); - AstNode *res = ast_create_node(pc, NodeTypeSymbol, token); - res->data.symbol_expr.symbol = token_buf(token); - return res; +static AstNode *token_identifier(ParseContext *pc, TokenIndex token) { + assert(pc->token_ids[token] == TokenIdIdentifier); + return ast_create_node(pc, NodeTypeIdentifier, token); } // (Rule SEP)* Rule? @@ -231,7 +231,7 @@ static ZigList ast_parse_list(ParseContext *pc, TokenId sep, T *(*parser)(P break; res.append(curr); - if (eat_token_if(pc, sep) == nullptr) + if (eat_token_if(pc, sep) == 0) break; } @@ -355,22 +355,22 @@ static AstNode *ast_parse_if_expr_helper(ParseContext *pc, AstNode *(*body_parse return nullptr; AstNode *body = ast_expect(pc, body_parser); - Token *err_payload = nullptr; + TokenIndex err_payload = 0; AstNode *else_body = nullptr; - if (eat_token_if(pc, TokenIdKeywordElse) != nullptr) { + if (eat_token_if(pc, TokenIdKeywordElse) != 0) { err_payload = ast_parse_payload(pc); else_body = ast_expect(pc, body_parser); } assert(res->type == NodeTypeIfOptional); - if (err_payload != nullptr) { + if (err_payload != 0) { AstNodeTestExpr old = res->data.test_expr; res->type = NodeTypeIfErrorExpr; res->data.if_err_expr.target_node = old.target_node; res->data.if_err_expr.var_is_ptr = old.var_is_ptr; res->data.if_err_expr.var_symbol = old.var_symbol; res->data.if_err_expr.then_node = body; - res->data.if_err_expr.err_symbol = token_buf(err_payload); + res->data.if_err_expr.err_symbol = token_buf(pc, err_payload); res->data.if_err_expr.else_node = else_body; return res; } @@ -395,22 +395,22 @@ static AstNode *ast_parse_loop_expr_helper( AstNode *(*for_parser)(ParseContext *), AstNode *(*while_parser)(ParseContext *) ) { - Token *inline_token = eat_token_if(pc, TokenIdKeywordInline); + TokenIndex inline_token = eat_token_if(pc, TokenIdKeywordInline); AstNode *for_expr = for_parser(pc); if (for_expr != nullptr) { assert(for_expr->type == NodeTypeForExpr); - for_expr->data.for_expr.is_inline = inline_token != nullptr; + for_expr->data.for_expr.is_inline = inline_token != 0; return for_expr; } AstNode *while_expr = while_parser(pc); if (while_expr != nullptr) { assert(while_expr->type == NodeTypeWhileExpr); - while_expr->data.while_expr.is_inline = inline_token != nullptr; + while_expr->data.while_expr.is_inline = inline_token != 0; return while_expr; } - if (inline_token != nullptr) + if (inline_token != 0) ast_invalid_token_error(pc, peek_token(pc)); return nullptr; } @@ -423,7 +423,7 @@ static AstNode *ast_parse_for_expr_helper(ParseContext *pc, AstNode *(*body_pars AstNode *body = ast_expect(pc, body_parser); AstNode *else_body = nullptr; - if (eat_token_if(pc, TokenIdKeywordElse) != nullptr) + if (eat_token_if(pc, TokenIdKeywordElse) != 0) else_body = ast_expect(pc, body_parser); assert(res->type == NodeTypeForExpr); @@ -439,24 +439,24 @@ static AstNode *ast_parse_while_expr_helper(ParseContext *pc, AstNode *(*body_pa return nullptr; AstNode *body = ast_expect(pc, body_parser); - Token *err_payload = nullptr; + TokenIndex err_payload = 0; AstNode *else_body = nullptr; - if (eat_token_if(pc, TokenIdKeywordElse) != nullptr) { + if (eat_token_if(pc, TokenIdKeywordElse) != 0) { err_payload = ast_parse_payload(pc); else_body = ast_expect(pc, body_parser); } assert(res->type == NodeTypeWhileExpr); res->data.while_expr.body = body; - res->data.while_expr.err_symbol = token_buf(err_payload); + res->data.while_expr.err_symbol = token_buf(pc, err_payload); res->data.while_expr.else_node = else_body; return res; } template AstNode *ast_parse_bin_op_simple(ParseContext *pc) { - Token *op_token = eat_token_if(pc, id); - if (op_token == nullptr) + TokenIndex op_token = eat_token_if(pc, id); + if (op_token == 0) return nullptr; AstNode *res = ast_create_node(pc, NodeTypeBinOpExpr, op_token); @@ -464,20 +464,25 @@ AstNode *ast_parse_bin_op_simple(ParseContext *pc) { return res; } -AstNode *ast_parse(Buf *buf, ZigList *tokens, ZigType *owner, ErrColor err_color) { +AstNode *ast_parse(Buf *buf, ZigType *owner, ErrColor err_color) { + RootStruct *root_struct = owner->data.structure.root_struct; + ParseContext pc = {}; pc.err_color = err_color; pc.owner = owner; pc.buf = buf; - pc.tokens = tokens; + pc.token_ids = root_struct->token_ids; + pc.token_locs = root_struct->token_locs; + pc.token_count = root_struct->token_count; + pc.current_token = 1; // Skip over the first (invalid) token. return ast_parse_root(&pc); } // Root <- skip ContainerMembers eof static AstNode *ast_parse_root(ParseContext *pc) { - Token *first = peek_token(pc); + TokenIndex first = peek_token(pc); AstNodeContainerDecl members = ast_parse_container_members(pc); - if (pc->current_token != pc->tokens->length - 1) + if (pc->current_token != pc->token_count - 1) ast_invalid_token_error(pc, peek_token(pc)); AstNode *node = ast_create_node(pc, NodeTypeContainerDecl, first); @@ -486,70 +491,26 @@ static AstNode *ast_parse_root(ParseContext *pc) { node->data.container_decl.layout = ContainerLayoutAuto; node->data.container_decl.kind = ContainerKindStruct; node->data.container_decl.is_root = true; - if (buf_len(&members.doc_comments) != 0) { - node->data.container_decl.doc_comments = members.doc_comments; - } + node->data.container_decl.doc_comments = members.doc_comments; return node; } -static Token *ast_parse_multiline_string_literal(ParseContext *pc, Buf *buf) { - Token *first_str_token = nullptr; - Token *str_token = nullptr; - while ((str_token = eat_token_if(pc, TokenIdMultilineStringLiteral))) { - if (first_str_token == nullptr) { - first_str_token = str_token; - } - if (buf->list.length == 0) { - buf_resize(buf, 0); - } - buf_append_buf(buf, token_buf(str_token)); - - // Ignore inline comments - size_t cur_token = pc->current_token; - while (eat_token_if(pc, TokenIdDocComment)); - - // Lookahead to see if there's another multilne string literal, - // if not, we have to revert back to before the doc comment - if (peek_token(pc)->id != TokenIdMultilineStringLiteral) { - pc->current_token = cur_token; - } else { - buf_append_char(buf, '\n'); // Add a newline between comments - } +static TokenIndex ast_parse_multi_tok(ParseContext *pc, TokenId token_id) { + TokenIndex first_token = eat_token_if(pc, token_id); + TokenIndex token = first_token; + while (token != 0) { + token = eat_token_if(pc, token_id); } - return first_str_token; + return first_token; } -static Token *ast_parse_doc_comments(ParseContext *pc, Buf *buf) { - Token *first_doc_token = nullptr; - Token *doc_token = nullptr; - while ((doc_token = eat_token_if(pc, TokenIdDocComment))) { - if (first_doc_token == nullptr) { - first_doc_token = doc_token; - } - if (buf->list.length == 0) { - buf_resize(buf, 0); - } - // chops off '///' but leaves '\n' - buf_append_mem(buf, buf_ptr(pc->buf) + doc_token->start_pos + 3, - doc_token->end_pos - doc_token->start_pos - 3); - } - return first_doc_token; +static TokenIndex ast_parse_doc_comments(ParseContext *pc) { + return ast_parse_multi_tok(pc, TokenIdDocComment); } -static void ast_parse_container_doc_comments(ParseContext *pc, Buf *buf) { - if (buf_len(buf) != 0 && peek_token(pc)->id == TokenIdContainerDocComment) { - buf_append_char(buf, '\n'); - } - Token *doc_token = nullptr; - while ((doc_token = eat_token_if(pc, TokenIdContainerDocComment))) { - if (buf->list.length == 0) { - buf_resize(buf, 0); - } - // chops off '//!' but leaves '\n' - buf_append_mem(buf, buf_ptr(pc->buf) + doc_token->start_pos + 3, - doc_token->end_pos - doc_token->start_pos - 3); - } +static TokenIndex ast_parse_container_doc_comments(ParseContext *pc) { + return ast_parse_multi_tok(pc, TokenIdContainerDocComment); } enum ContainerFieldState { @@ -570,14 +531,11 @@ enum ContainerFieldState { // / static AstNodeContainerDecl ast_parse_container_members(ParseContext *pc) { AstNodeContainerDecl res = {}; - Buf tld_doc_comment_buf = BUF_INIT; - buf_resize(&tld_doc_comment_buf, 0); ContainerFieldState field_state = ContainerFieldStateNone; - Token *first_token = nullptr; + TokenIndex first_token = 0; + res.doc_comments = ast_parse_container_doc_comments(pc); for (;;) { - ast_parse_container_doc_comments(pc, &tld_doc_comment_buf); - - Token *peeked_token = peek_token(pc); + TokenIndex peeked_token = peek_token(pc); AstNode *test_decl = ast_parse_test_decl(pc); if (test_decl != nullptr) { @@ -599,15 +557,14 @@ static AstNodeContainerDecl ast_parse_container_members(ParseContext *pc) { continue; } - Buf doc_comment_buf = BUF_INIT; - ast_parse_doc_comments(pc, &doc_comment_buf); + TokenIndex first_doc_token = ast_parse_doc_comments(pc); peeked_token = peek_token(pc); - Token *visib_token = eat_token_if(pc, TokenIdKeywordPub); - VisibMod visib_mod = visib_token != nullptr ? VisibModPub : VisibModPrivate; + TokenIndex visib_token = eat_token_if(pc, TokenIdKeywordPub); + VisibMod visib_mod = (visib_token != 0) ? VisibModPub : VisibModPrivate; - AstNode *top_level_decl = ast_parse_top_level_decl(pc, visib_mod, &doc_comment_buf); + AstNode *top_level_decl = ast_parse_top_level_decl(pc, visib_mod, first_doc_token); if (top_level_decl != nullptr) { if (field_state == ContainerFieldStateSeen) { field_state = ContainerFieldStateEnd; @@ -617,11 +574,11 @@ static AstNodeContainerDecl ast_parse_container_members(ParseContext *pc) { continue; } - if (visib_token != nullptr) { + if (visib_token != 0) { ast_error(pc, peek_token(pc), "expected function or variable declaration after pub"); } - Token *comptime_token = eat_token_if(pc, TokenIdKeywordCompTime); + TokenIndex comptime_token = eat_token_if(pc, TokenIdKeywordCompTime); AstNode *container_field = ast_parse_container_field(pc); if (container_field != nullptr) { @@ -636,10 +593,10 @@ static AstNodeContainerDecl ast_parse_container_members(ParseContext *pc) { } assert(container_field->type == NodeTypeStructField); - container_field->data.struct_field.doc_comments = doc_comment_buf; + container_field->data.struct_field.doc_comments = first_doc_token; container_field->data.struct_field.comptime_token = comptime_token; res.fields.append(container_field); - if (eat_token_if(pc, TokenIdComma) != nullptr) { + if (eat_token_if(pc, TokenIdComma) != 0) { continue; } else { break; @@ -648,33 +605,32 @@ static AstNodeContainerDecl ast_parse_container_members(ParseContext *pc) { break; } - res.doc_comments = tld_doc_comment_buf; return res; } // TestDecl <- KEYWORD_test STRINGLITERALSINGLE Block static AstNode *ast_parse_test_decl(ParseContext *pc) { - Token *test = eat_token_if(pc, TokenIdKeywordTest); - if (test == nullptr) + TokenIndex test = eat_token_if(pc, TokenIdKeywordTest); + if (test == 0) return nullptr; - Token *name = eat_token_if(pc, TokenIdStringLiteral); + TokenIndex name = eat_token_if(pc, TokenIdStringLiteral); AstNode *block = ast_expect(pc, ast_parse_block); AstNode *res = ast_create_node(pc, NodeTypeTestDecl, test); - res->data.test_decl.name = name ? token_buf(name) : nullptr; + res->data.test_decl.name = name ? token_buf(pc, name) : nullptr; res->data.test_decl.body = block; return res; } // TopLevelComptime <- KEYWORD_comptime BlockExpr static AstNode *ast_parse_top_level_comptime(ParseContext *pc) { - Token *comptime = eat_token_if(pc, TokenIdKeywordCompTime); - if (comptime == nullptr) + TokenIndex comptime = eat_token_if(pc, TokenIdKeywordCompTime); + if (comptime == 0) return nullptr; // 1 token lookahead because it could be a comptime struct field - Token *lbrace = peek_token(pc); - if (lbrace->id != TokenIdLBrace) { + TokenIndex lbrace = peek_token(pc); + if (pc->token_ids[lbrace] != TokenIdLBrace) { put_back_token(pc); return nullptr; } @@ -689,39 +645,40 @@ static AstNode *ast_parse_top_level_comptime(ParseContext *pc) { // <- (KEYWORD_export / KEYWORD_extern STRINGLITERALSINGLE? / (KEYWORD_inline / KEYWORD_noinline))? FnProto (SEMICOLON / Block) // / (KEYWORD_export / KEYWORD_extern STRINGLITERALSINGLE?)? KEYWORD_threadlocal? VarDecl // / KEYWORD_use Expr SEMICOLON -static AstNode *ast_parse_top_level_decl(ParseContext *pc, VisibMod visib_mod, Buf *doc_comments) { - Token *first = eat_token_if(pc, TokenIdKeywordExport); - if (first == nullptr) +static AstNode *ast_parse_top_level_decl(ParseContext *pc, VisibMod visib_mod, + TokenIndex doc_comments) +{ + TokenIndex first = eat_token_if(pc, TokenIdKeywordExport); + if (first == 0) first = eat_token_if(pc, TokenIdKeywordExtern); - if (first == nullptr) + if (first == 0) first = eat_token_if(pc, TokenIdKeywordInline); - if (first == nullptr) + if (first == 0) first = eat_token_if(pc, TokenIdKeywordNoInline); - if (first != nullptr) { - Token *lib_name = nullptr; - if (first->id == TokenIdKeywordExtern) + if (first != 0) { + TokenIndex lib_name = 0; + if (pc->token_ids[first] == TokenIdKeywordExtern) lib_name = eat_token_if(pc, TokenIdStringLiteral); - if (first->id != TokenIdKeywordNoInline && first->id != TokenIdKeywordInline) { - Token *thread_local_kw = eat_token_if(pc, TokenIdKeywordThreadLocal); + if (pc->token_ids[first] != TokenIdKeywordNoInline && pc->token_ids[first] != TokenIdKeywordInline) { + TokenIndex thread_local_kw = eat_token_if(pc, TokenIdKeywordThreadLocal); AstNode *var_decl = ast_parse_var_decl(pc); if (var_decl != nullptr) { assert(var_decl->type == NodeTypeVariableDeclaration); - if (first->id == TokenIdKeywordExtern && var_decl->data.variable_declaration.expr != nullptr) { + if (pc->token_ids[first] == TokenIdKeywordExtern && var_decl->data.variable_declaration.expr != nullptr) { ast_error(pc, first, "extern variables have no initializers"); } - var_decl->line = first->start_line; - var_decl->column = first->start_column; + var_decl->main_token = first; var_decl->data.variable_declaration.threadlocal_tok = thread_local_kw; var_decl->data.variable_declaration.visib_mod = visib_mod; - var_decl->data.variable_declaration.doc_comments = *doc_comments; - var_decl->data.variable_declaration.is_extern = first->id == TokenIdKeywordExtern; - var_decl->data.variable_declaration.is_export = first->id == TokenIdKeywordExport; - var_decl->data.variable_declaration.lib_name = token_buf(lib_name); + var_decl->data.variable_declaration.doc_comments = doc_comments; + var_decl->data.variable_declaration.is_extern = pc->token_ids[first] == TokenIdKeywordExtern; + var_decl->data.variable_declaration.is_export = pc->token_ids[first] == TokenIdKeywordExport; + var_decl->data.variable_declaration.lib_name = token_buf(pc, lib_name); return var_decl; } - if (thread_local_kw != nullptr) + if (thread_local_kw != 0) put_back_token(pc); } @@ -732,14 +689,13 @@ static AstNode *ast_parse_top_level_decl(ParseContext *pc, VisibMod visib_mod, B expect_token(pc, TokenIdSemicolon); assert(fn_proto->type == NodeTypeFnProto); - fn_proto->line = first->start_line; - fn_proto->column = first->start_column; + fn_proto->main_token = first; fn_proto->data.fn_proto.visib_mod = visib_mod; - fn_proto->data.fn_proto.doc_comments = *doc_comments; + fn_proto->data.fn_proto.doc_comments = doc_comments; if (!fn_proto->data.fn_proto.is_extern) - fn_proto->data.fn_proto.is_extern = first->id == TokenIdKeywordExtern; - fn_proto->data.fn_proto.is_export = first->id == TokenIdKeywordExport; - switch (first->id) { + fn_proto->data.fn_proto.is_extern = pc->token_ids[first] == TokenIdKeywordExtern; + fn_proto->data.fn_proto.is_export = pc->token_ids[first] == TokenIdKeywordExport; + switch (pc->token_ids[first]) { case TokenIdKeywordInline: fn_proto->data.fn_proto.fn_inline = FnInlineAlways; break; @@ -750,7 +706,7 @@ static AstNode *ast_parse_top_level_decl(ParseContext *pc, VisibMod visib_mod, B fn_proto->data.fn_proto.fn_inline = FnInlineAuto; break; } - fn_proto->data.fn_proto.lib_name = token_buf(lib_name); + fn_proto->data.fn_proto.lib_name = token_buf(pc, lib_name); AstNode *res = fn_proto; if (body != nullptr) { @@ -769,17 +725,17 @@ static AstNode *ast_parse_top_level_decl(ParseContext *pc, VisibMod visib_mod, B ast_invalid_token_error(pc, peek_token(pc)); } - Token *thread_local_kw = eat_token_if(pc, TokenIdKeywordThreadLocal); + TokenIndex thread_local_kw = eat_token_if(pc, TokenIdKeywordThreadLocal); AstNode *var_decl = ast_parse_var_decl(pc); if (var_decl != nullptr) { assert(var_decl->type == NodeTypeVariableDeclaration); var_decl->data.variable_declaration.visib_mod = visib_mod; - var_decl->data.variable_declaration.doc_comments = *doc_comments; + var_decl->data.variable_declaration.doc_comments = doc_comments; var_decl->data.variable_declaration.threadlocal_tok = thread_local_kw; return var_decl; } - if (thread_local_kw != nullptr) + if (thread_local_kw != 0) put_back_token(pc); AstNode *fn_proto = ast_parse_fn_proto(pc); @@ -790,7 +746,7 @@ static AstNode *ast_parse_top_level_decl(ParseContext *pc, VisibMod visib_mod, B assert(fn_proto->type == NodeTypeFnProto); fn_proto->data.fn_proto.visib_mod = visib_mod; - fn_proto->data.fn_proto.doc_comments = *doc_comments; + fn_proto->data.fn_proto.doc_comments = doc_comments; AstNode *res = fn_proto; if (body != nullptr) { res = ast_create_node_copy_line_info(pc, NodeTypeFnDef, fn_proto); @@ -802,8 +758,8 @@ static AstNode *ast_parse_top_level_decl(ParseContext *pc, VisibMod visib_mod, B return res; } - Token *usingnamespace = eat_token_if(pc, TokenIdKeywordUsingNamespace); - if (usingnamespace != nullptr) { + TokenIndex usingnamespace = eat_token_if(pc, TokenIdKeywordUsingNamespace); + if (usingnamespace != 0) { AstNode *expr = ast_expect(pc, ast_parse_expr); expect_token(pc, TokenIdSemicolon); @@ -818,12 +774,12 @@ static AstNode *ast_parse_top_level_decl(ParseContext *pc, VisibMod visib_mod, B // FnProto <- KEYWORD_fn IDENTIFIER? LPAREN ParamDeclList RPAREN ByteAlign? LinkSection? EXCLAMATIONMARK? (KEYWORD_anytype / TypeExpr) static AstNode *ast_parse_fn_proto(ParseContext *pc) { - Token *first = eat_token_if(pc, TokenIdKeywordFn); - if (first == nullptr) { + TokenIndex first = eat_token_if(pc, TokenIdKeywordFn); + if (first == 0) { return nullptr; } - Token *identifier = eat_token_if(pc, TokenIdSymbol); + TokenIndex identifier = eat_token_if(pc, TokenIdIdentifier); expect_token(pc, TokenIdLParen); ZigList params = ast_parse_list(pc, TokenIdComma, ast_parse_param_decl); expect_token(pc, TokenIdRParen); @@ -831,29 +787,29 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc) { AstNode *align_expr = ast_parse_byte_align(pc); AstNode *section_expr = ast_parse_link_section(pc); AstNode *callconv_expr = ast_parse_callconv(pc); - Token *exmark = nullptr; + TokenIndex exmark = 0; AstNode *return_type = nullptr; exmark = eat_token_if(pc, TokenIdBang); return_type = ast_parse_type_expr(pc); if (return_type == nullptr) { - Token *next = peek_token(pc); + TokenIndex next = peek_token(pc); ast_error( pc, next, "expected return type (use 'void' to return nothing), found: '%s'", - token_name(next->id) + token_name(pc->token_ids[next]) ); } AstNode *res = ast_create_node(pc, NodeTypeFnProto, first); res->data.fn_proto = {}; - res->data.fn_proto.name = token_buf(identifier); + res->data.fn_proto.name = token_buf(pc, identifier); res->data.fn_proto.params = params; res->data.fn_proto.align_expr = align_expr; res->data.fn_proto.section_expr = section_expr; res->data.fn_proto.callconv_expr = callconv_expr; - res->data.fn_proto.auto_err_set = exmark != nullptr; + res->data.fn_proto.auto_err_set = exmark != 0; res->data.fn_proto.return_type = return_type; for (size_t i = 0; i < params.length; i++) { @@ -869,28 +825,28 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc) { // VarDecl <- (KEYWORD_const / KEYWORD_var) IDENTIFIER (COLON TypeExpr)? ByteAlign? LinkSection? (EQUAL Expr)? SEMICOLON static AstNode *ast_parse_var_decl(ParseContext *pc) { - Token *mut_kw = eat_token_if(pc, TokenIdKeywordConst); - if (mut_kw == nullptr) + TokenIndex mut_kw = eat_token_if(pc, TokenIdKeywordConst); + if (mut_kw == 0) mut_kw = eat_token_if(pc, TokenIdKeywordVar); - if (mut_kw == nullptr) + if (mut_kw == 0) return nullptr; - Token *identifier = expect_token(pc, TokenIdSymbol); + TokenIndex identifier = expect_token(pc, TokenIdIdentifier); AstNode *type_expr = nullptr; - if (eat_token_if(pc, TokenIdColon) != nullptr) + if (eat_token_if(pc, TokenIdColon) != 0) type_expr = ast_expect(pc, ast_parse_type_expr); AstNode *align_expr = ast_parse_byte_align(pc); AstNode *section_expr = ast_parse_link_section(pc); AstNode *expr = nullptr; - if (eat_token_if(pc, TokenIdEq) != nullptr) + if (eat_token_if(pc, TokenIdEq) != 0) expr = ast_expect(pc, ast_parse_expr); expect_token(pc, TokenIdSemicolon); AstNode *res = ast_create_node(pc, NodeTypeVariableDeclaration, mut_kw); - res->data.variable_declaration.is_const = mut_kw->id == TokenIdKeywordConst; - res->data.variable_declaration.symbol = token_buf(identifier); + res->data.variable_declaration.is_const = pc->token_ids[mut_kw] == TokenIdKeywordConst; + res->data.variable_declaration.symbol = token_buf(pc, identifier); res->data.variable_declaration.type = type_expr; res->data.variable_declaration.align_expr = align_expr; res->data.variable_declaration.section_expr = section_expr; @@ -900,14 +856,14 @@ static AstNode *ast_parse_var_decl(ParseContext *pc) { // ContainerField <- KEYWORD_comptime? IDENTIFIER (COLON TypeExpr ByteAlign?)? (EQUAL Expr)? static AstNode *ast_parse_container_field(ParseContext *pc) { - Token *identifier = eat_token_if(pc, TokenIdSymbol); - if (identifier == nullptr) + TokenIndex identifier = eat_token_if(pc, TokenIdIdentifier); + if (identifier == 0) return nullptr; AstNode *type_expr = nullptr; - if (eat_token_if(pc, TokenIdColon) != nullptr) { - Token *anytype_tok = eat_token_if(pc, TokenIdKeywordAnyType); - if (anytype_tok != nullptr) { + if (eat_token_if(pc, TokenIdColon) != 0) { + TokenIndex anytype_tok = eat_token_if(pc, TokenIdKeywordAnyType); + if (anytype_tok != 0) { type_expr = ast_create_node(pc, NodeTypeAnyTypeField, anytype_tok); } else { type_expr = ast_expect(pc, ast_parse_type_expr); @@ -915,11 +871,11 @@ static AstNode *ast_parse_container_field(ParseContext *pc) { } AstNode *align_expr = ast_parse_byte_align(pc); AstNode *expr = nullptr; - if (eat_token_if(pc, TokenIdEq) != nullptr) + if (eat_token_if(pc, TokenIdEq) != 0) expr = ast_expect(pc, ast_parse_expr); AstNode *res = ast_create_node(pc, NodeTypeStructField, identifier); - res->data.struct_field.name = token_buf(identifier); + res->data.struct_field.name = token_buf(pc, identifier); res->data.struct_field.type = type_expr; res->data.struct_field.value = expr; res->data.struct_field.align_expr = align_expr; @@ -938,52 +894,52 @@ static AstNode *ast_parse_container_field(ParseContext *pc) { // / SwitchExpr // / AssignExpr SEMICOLON static AstNode *ast_parse_statement(ParseContext *pc) { - Token *comptime = eat_token_if(pc, TokenIdKeywordCompTime); + TokenIndex comptime = eat_token_if(pc, TokenIdKeywordCompTime); AstNode *var_decl = ast_parse_var_decl(pc); if (var_decl != nullptr) { assert(var_decl->type == NodeTypeVariableDeclaration); - var_decl->data.variable_declaration.is_comptime = comptime != nullptr; + var_decl->data.variable_declaration.is_comptime = comptime != 0; return var_decl; } - if (comptime != nullptr) { + if (comptime != 0) { AstNode *statement = ast_expect(pc, ast_parse_block_expr_statement); AstNode *res = ast_create_node(pc, NodeTypeCompTime, comptime); res->data.comptime_expr.expr = statement; return res; } - Token *nosuspend = eat_token_if(pc, TokenIdKeywordNoSuspend); - if (nosuspend != nullptr) { + TokenIndex nosuspend = eat_token_if(pc, TokenIdKeywordNoSuspend); + if (nosuspend != 0) { AstNode *statement = ast_expect(pc, ast_parse_block_expr_statement); AstNode *res = ast_create_node(pc, NodeTypeNoSuspend, nosuspend); res->data.nosuspend_expr.expr = statement; return res; } - Token *suspend = eat_token_if(pc, TokenIdKeywordSuspend); - if (suspend != nullptr) { + TokenIndex suspend = eat_token_if(pc, TokenIdKeywordSuspend); + if (suspend != 0) { AstNode *statement = ast_expect(pc, ast_parse_block_expr_statement); AstNode *res = ast_create_node(pc, NodeTypeSuspend, suspend); res->data.suspend.block = statement; return res; } - Token *defer = eat_token_if(pc, TokenIdKeywordDefer); - if (defer == nullptr) + TokenIndex defer = eat_token_if(pc, TokenIdKeywordDefer); + if (defer == 0) defer = eat_token_if(pc, TokenIdKeywordErrdefer); - if (defer != nullptr) { - Token *payload = (defer->id == TokenIdKeywordErrdefer) ? - ast_parse_payload(pc) : nullptr; + if (defer != 0) { + TokenIndex payload = (pc->token_ids[defer] == TokenIdKeywordErrdefer) ? + ast_parse_payload(pc) : 0; AstNode *statement = ast_expect(pc, ast_parse_block_expr_statement); AstNode *res = ast_create_node(pc, NodeTypeDefer, defer); res->data.defer.kind = ReturnKindUnconditional; res->data.defer.expr = statement; - if (defer->id == TokenIdKeywordErrdefer) { + if (pc->token_ids[defer] == TokenIdKeywordErrdefer) { res->data.defer.kind = ReturnKindError; - if (payload != nullptr) - res->data.defer.err_payload = token_symbol(pc, payload); + if (payload != 0) + res->data.defer.err_payload = token_identifier(pc, payload); } return res; } @@ -1025,13 +981,13 @@ static AstNode *ast_parse_if_statement(ParseContext *pc) { } if (body == nullptr) { - Token *tok = eat_token(pc); - ast_error(pc, tok, "expected if body, found '%s'", token_name(tok->id)); + TokenIndex tok = eat_token(pc); + ast_error(pc, tok, "expected if body, found '%s'", token_name(pc->token_ids[tok])); } - Token *err_payload = nullptr; + TokenIndex err_payload = 0; AstNode *else_body = nullptr; - if (eat_token_if(pc, TokenIdKeywordElse) != nullptr) { + if (eat_token_if(pc, TokenIdKeywordElse) != 0) { err_payload = ast_parse_payload(pc); else_body = ast_expect(pc, ast_parse_statement); } @@ -1040,14 +996,14 @@ static AstNode *ast_parse_if_statement(ParseContext *pc) { expect_token(pc, TokenIdSemicolon); assert(res->type == NodeTypeIfOptional); - if (err_payload != nullptr) { + if (err_payload != 0) { AstNodeTestExpr old = res->data.test_expr; res->type = NodeTypeIfErrorExpr; res->data.if_err_expr.target_node = old.target_node; res->data.if_err_expr.var_is_ptr = old.var_is_ptr; res->data.if_err_expr.var_symbol = old.var_symbol; res->data.if_err_expr.then_node = body; - res->data.if_err_expr.err_symbol = token_buf(err_payload); + res->data.if_err_expr.err_symbol = token_buf(pc, err_payload); res->data.if_err_expr.else_node = else_body; return res; } @@ -1068,11 +1024,11 @@ static AstNode *ast_parse_if_statement(ParseContext *pc) { // LabeledStatement <- BlockLabel? (Block / LoopStatement) static AstNode *ast_parse_labeled_statement(ParseContext *pc) { - Token *label = ast_parse_block_label(pc); + TokenIndex label = ast_parse_block_label(pc); AstNode *block = ast_parse_block(pc); if (block != nullptr) { assert(block->type == NodeTypeBlock); - block->data.block.name = token_buf(label); + block->data.block.name = token_buf(pc, label); return block; } @@ -1080,10 +1036,10 @@ static AstNode *ast_parse_labeled_statement(ParseContext *pc) { if (loop != nullptr) { switch (loop->type) { case NodeTypeForExpr: - loop->data.for_expr.name = token_buf(label); + loop->data.for_expr.name = token_buf(pc, label); break; case NodeTypeWhileExpr: - loop->data.while_expr.name = token_buf(label); + loop->data.while_expr.name = token_buf(pc, label); break; default: zig_unreachable(); @@ -1091,29 +1047,29 @@ static AstNode *ast_parse_labeled_statement(ParseContext *pc) { return loop; } - if (label != nullptr) + if (label != 0) ast_invalid_token_error(pc, peek_token(pc)); return nullptr; } // LoopStatement <- KEYWORD_inline? (ForStatement / WhileStatement) static AstNode *ast_parse_loop_statement(ParseContext *pc) { - Token *inline_token = eat_token_if(pc, TokenIdKeywordInline); + TokenIndex inline_token = eat_token_if(pc, TokenIdKeywordInline); AstNode *for_statement = ast_parse_for_statement(pc); if (for_statement != nullptr) { assert(for_statement->type == NodeTypeForExpr); - for_statement->data.for_expr.is_inline = inline_token != nullptr; + for_statement->data.for_expr.is_inline = inline_token != 0; return for_statement; } AstNode *while_statement = ast_parse_while_statement(pc); if (while_statement != nullptr) { assert(while_statement->type == NodeTypeWhileExpr); - while_statement->data.while_expr.is_inline = inline_token != nullptr; + while_statement->data.while_expr.is_inline = inline_token != 0; return while_statement; } - if (inline_token != nullptr) + if (inline_token != 0) ast_invalid_token_error(pc, peek_token(pc)); return nullptr; } @@ -1134,12 +1090,12 @@ static AstNode *ast_parse_for_statement(ParseContext *pc) { } if (body == nullptr) { - Token *tok = eat_token(pc); - ast_error(pc, tok, "expected loop body, found '%s'", token_name(tok->id)); + TokenIndex tok = eat_token(pc); + ast_error(pc, tok, "expected loop body, found '%s'", token_name(pc->token_ids[tok])); } AstNode *else_body = nullptr; - if (eat_token_if(pc, TokenIdKeywordElse) != nullptr) { + if (eat_token_if(pc, TokenIdKeywordElse) != 0) { else_body = ast_expect(pc, ast_parse_statement); } @@ -1168,13 +1124,13 @@ static AstNode *ast_parse_while_statement(ParseContext *pc) { } if (body == nullptr) { - Token *tok = eat_token(pc); - ast_error(pc, tok, "expected loop body, found '%s'", token_name(tok->id)); + TokenIndex tok = eat_token(pc); + ast_error(pc, tok, "expected loop body, found '%s'", token_name(pc->token_ids[tok])); } - Token *err_payload = nullptr; + TokenIndex err_payload = 0; AstNode *else_body = nullptr; - if (eat_token_if(pc, TokenIdKeywordElse) != nullptr) { + if (eat_token_if(pc, TokenIdKeywordElse) != 0) { err_payload = ast_parse_payload(pc); else_body = ast_expect(pc, ast_parse_statement); } @@ -1184,7 +1140,7 @@ static AstNode *ast_parse_while_statement(ParseContext *pc) { assert(res->type == NodeTypeWhileExpr); res->data.while_expr.body = body; - res->data.while_expr.err_symbol = token_buf(err_payload); + res->data.while_expr.err_symbol = token_buf(pc, err_payload); res->data.while_expr.else_node = else_body; return res; } @@ -1209,11 +1165,11 @@ static AstNode *ast_parse_block_expr_statement(ParseContext *pc) { // BlockExpr <- BlockLabel? Block static AstNode *ast_parse_block_expr(ParseContext *pc) { - Token *label = ast_parse_block_label(pc); - if (label != nullptr) { + TokenIndex label = ast_parse_block_label(pc); + if (label != 0) { AstNode *res = ast_expect(pc, ast_parse_block); assert(res->type == NodeTypeBlock); - res->data.block.name = token_buf(label); + res->data.block.name = token_buf(pc, label); return res; } @@ -1230,8 +1186,8 @@ static AstNode *ast_parse_expr(ParseContext *pc) { return ast_parse_prefix_op_expr( pc, [](ParseContext *context) { - Token *try_token = eat_token_if(context, TokenIdKeywordTry); - if (try_token != nullptr) { + TokenIndex try_token = eat_token_if(context, TokenIdKeywordTry); + if (try_token != 0) { AstNode *res = ast_create_node(context, NodeTypeReturnExpr, try_token); res->data.return_expr.kind = ReturnKindError; return res; @@ -1318,72 +1274,72 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc) { if (if_expr != nullptr) return if_expr; - Token *break_token = eat_token_if(pc, TokenIdKeywordBreak); - if (break_token != nullptr) { - Token *label = ast_parse_break_label(pc); + TokenIndex break_token = eat_token_if(pc, TokenIdKeywordBreak); + if (break_token != 0) { + TokenIndex label = ast_parse_break_label(pc); AstNode *expr = ast_parse_expr(pc); AstNode *res = ast_create_node(pc, NodeTypeBreak, break_token); - res->data.break_expr.name = token_buf(label); + res->data.break_expr.name = token_buf(pc, label); res->data.break_expr.expr = expr; return res; } - Token *comptime = eat_token_if(pc, TokenIdKeywordCompTime); - if (comptime != nullptr) { + TokenIndex comptime = eat_token_if(pc, TokenIdKeywordCompTime); + if (comptime != 0) { AstNode *expr = ast_expect(pc, ast_parse_expr); AstNode *res = ast_create_node(pc, NodeTypeCompTime, comptime); res->data.comptime_expr.expr = expr; return res; } - Token *nosuspend = eat_token_if(pc, TokenIdKeywordNoSuspend); - if (nosuspend != nullptr) { + TokenIndex nosuspend = eat_token_if(pc, TokenIdKeywordNoSuspend); + if (nosuspend != 0) { AstNode *expr = ast_expect(pc, ast_parse_expr); AstNode *res = ast_create_node(pc, NodeTypeNoSuspend, nosuspend); res->data.nosuspend_expr.expr = expr; return res; } - Token *continue_token = eat_token_if(pc, TokenIdKeywordContinue); - if (continue_token != nullptr) { - Token *label = ast_parse_break_label(pc); + TokenIndex continue_token = eat_token_if(pc, TokenIdKeywordContinue); + if (continue_token != 0) { + TokenIndex label = ast_parse_break_label(pc); AstNode *res = ast_create_node(pc, NodeTypeContinue, continue_token); - res->data.continue_expr.name = token_buf(label); + res->data.continue_expr.name = token_buf(pc, label); return res; } - Token *resume = eat_token_if(pc, TokenIdKeywordResume); - if (resume != nullptr) { + TokenIndex resume = eat_token_if(pc, TokenIdKeywordResume); + if (resume != 0) { AstNode *expr = ast_expect(pc, ast_parse_expr); AstNode *res = ast_create_node(pc, NodeTypeResume, resume); res->data.resume_expr.expr = expr; return res; } - Token *return_token = eat_token_if(pc, TokenIdKeywordReturn); - if (return_token != nullptr) { + TokenIndex return_token = eat_token_if(pc, TokenIdKeywordReturn); + if (return_token != 0) { AstNode *expr = ast_parse_expr(pc); AstNode *res = ast_create_node(pc, NodeTypeReturnExpr, return_token); res->data.return_expr.expr = expr; return res; } - Token *label = ast_parse_block_label(pc); + TokenIndex label = ast_parse_block_label(pc); AstNode *loop = ast_parse_loop_expr(pc); if (loop != nullptr) { switch (loop->type) { case NodeTypeForExpr: - loop->data.for_expr.name = token_buf(label); + loop->data.for_expr.name = token_buf(pc, label); break; case NodeTypeWhileExpr: - loop->data.while_expr.name = token_buf(label); + loop->data.while_expr.name = token_buf(pc, label); break; default: zig_unreachable(); } return loop; - } else if (label != nullptr) { + } else if (label != 0) { // Restore the tokens that we eaten by ast_parse_block_label. put_back_token(pc); put_back_token(pc); @@ -1407,8 +1363,8 @@ static AstNode *ast_parse_if_expr(ParseContext *pc) { // Block <- LBRACE Statement* RBRACE static AstNode *ast_parse_block(ParseContext *pc) { - Token *lbrace = eat_token_if(pc, TokenIdLBrace); - if (lbrace == nullptr) + TokenIndex lbrace = eat_token_if(pc, TokenIdLBrace); + if (lbrace == 0) return nullptr; ZigList statements = {}; @@ -1462,8 +1418,8 @@ static AstNode *ast_parse_curly_suffix_expr(ParseContext *pc) { // / LBRACE Expr (COMMA Expr)* COMMA? RBRACE // / LBRACE RBRACE static AstNode *ast_parse_init_list(ParseContext *pc) { - Token *lbrace = eat_token_if(pc, TokenIdLBrace); - if (lbrace == nullptr) + TokenIndex lbrace = eat_token_if(pc, TokenIdLBrace); + if (lbrace == 0) return nullptr; AstNode *first = ast_parse_field_init(pc); @@ -1472,7 +1428,7 @@ static AstNode *ast_parse_init_list(ParseContext *pc) { res->data.container_init_expr.kind = ContainerInitKindStruct; res->data.container_init_expr.entries.append(first); - while (eat_token_if(pc, TokenIdComma) != nullptr) { + while (eat_token_if(pc, TokenIdComma) != 0) { AstNode *field_init = ast_parse_field_init(pc); if (field_init == nullptr) break; @@ -1490,7 +1446,7 @@ static AstNode *ast_parse_init_list(ParseContext *pc) { if (first != nullptr) { res->data.container_init_expr.entries.append(first); - while (eat_token_if(pc, TokenIdComma) != nullptr) { + while (eat_token_if(pc, TokenIdComma) != 0) { AstNode *expr = ast_parse_expr(pc); if (expr == nullptr) break; @@ -1535,7 +1491,7 @@ static AstNode *ast_parse_error_union_expr(ParseContext *pc) { // <- KEYWORD_async PrimaryTypeExpr SuffixOp* FnCallArguments // / PrimaryTypeExpr (SuffixOp / FnCallArguments)* static AstNode *ast_parse_suffix_expr(ParseContext *pc) { - Token *async_token = eat_token_if(pc, TokenIdKeywordAsync); + TokenIndex async_token = eat_token_if(pc, TokenIdKeywordAsync); if (async_token) { AstNode *child = ast_expect(pc, ast_parse_primary_type_expr); while (true) { @@ -1652,43 +1608,21 @@ static AstNode *ast_parse_suffix_expr(ParseContext *pc) { // / STRINGLITERAL // / SwitchExpr static AstNode *ast_parse_primary_type_expr(ParseContext *pc) { - // TODO: This is not in line with the grammar. - // Because the prev stage 1 tokenizer does not parse - // @[a-zA-Z_][a-zA-Z0-9_] as one token, it has to do a - // hack, where it accepts '@' (IDENTIFIER / KEYWORD_export / - // KEYWORD_extern). - // I'd say that it's better if '@' is part of the builtin - // identifier token. - Token *at_sign = eat_token_if(pc, TokenIdAtSign); - if (at_sign != nullptr) { - Buf *name; - Token *token; - if ((token = eat_token_if(pc, TokenIdKeywordExport)) != nullptr) { - name = buf_create_from_str("export"); - } else if ((token = eat_token_if(pc, TokenIdKeywordExtern)) != nullptr) { - name = buf_create_from_str("extern"); - } else { - token = expect_token(pc, TokenIdSymbol); - name = token_buf(token); - } - + TokenIndex builtin_tok = eat_token_if(pc, TokenIdBuiltin); + if (builtin_tok != 0) { AstNode *res = ast_expect(pc, ast_parse_fn_call_arguments); - AstNode *name_sym = ast_create_node(pc, NodeTypeSymbol, token); - name_sym->data.symbol_expr.symbol = name; + AstNode *name_sym = ast_create_node(pc, NodeTypeIdentifier, builtin_tok); assert(res->type == NodeTypeFnCallExpr); - res->line = at_sign->start_line; - res->column = at_sign->start_column; + res->main_token = builtin_tok; res->data.fn_call_expr.fn_ref_expr = name_sym; res->data.fn_call_expr.modifier = CallModifierBuiltin; return res; } - Token *char_lit = eat_token_if(pc, TokenIdCharLiteral); - if (char_lit != nullptr) { - AstNode *res = ast_create_node(pc, NodeTypeCharLiteral, char_lit); - res->data.char_literal.value = char_lit->data.char_lit.c; - return res; + TokenIndex char_lit = eat_token_if(pc, TokenIdCharLiteral); + if (char_lit != 0) { + return ast_create_node(pc, NodeTypeCharLiteral, char_lit); } AstNode *container_decl = ast_parse_container_decl(pc); @@ -1703,12 +1637,9 @@ static AstNode *ast_parse_primary_type_expr(ParseContext *pc) { if (error_set_decl != nullptr) return error_set_decl; - Token *float_lit = eat_token_if(pc, TokenIdFloatLiteral); - if (float_lit != nullptr) { - AstNode *res = ast_create_node(pc, NodeTypeFloatLiteral, float_lit); - res->data.float_literal.bigfloat = &float_lit->data.float_lit.bigfloat; - res->data.float_literal.overflow = float_lit->data.float_lit.overflow; - return res; + TokenIndex float_lit = eat_token_if(pc, TokenIdFloatLiteral); + if (float_lit != 0) { + return ast_create_node(pc, NodeTypeFloatLiteral, float_lit); } AstNode *fn_proto = ast_parse_fn_proto(pc); @@ -1723,86 +1654,77 @@ static AstNode *ast_parse_primary_type_expr(ParseContext *pc) { if (labeled_type_expr != nullptr) return labeled_type_expr; - Token *identifier = eat_token_if(pc, TokenIdSymbol); - if (identifier != nullptr) - return token_symbol(pc, identifier); + TokenIndex identifier = eat_token_if(pc, TokenIdIdentifier); + if (identifier != 0) + return token_identifier(pc, identifier); AstNode *if_type_expr = ast_parse_if_type_expr(pc); if (if_type_expr != nullptr) return if_type_expr; - Token *int_lit = eat_token_if(pc, TokenIdIntLiteral); - if (int_lit != nullptr) { - AstNode *res = ast_create_node(pc, NodeTypeIntLiteral, int_lit); - res->data.int_literal.bigint = &int_lit->data.int_lit.bigint; - return res; + TokenIndex int_lit = eat_token_if(pc, TokenIdIntLiteral); + if (int_lit != 0) { + return ast_create_node(pc, NodeTypeIntLiteral, int_lit); } - Token *comptime = eat_token_if(pc, TokenIdKeywordCompTime); - if (comptime != nullptr) { + TokenIndex comptime = eat_token_if(pc, TokenIdKeywordCompTime); + if (comptime != 0) { AstNode *expr = ast_expect(pc, ast_parse_type_expr); AstNode *res = ast_create_node(pc, NodeTypeCompTime, comptime); res->data.comptime_expr.expr = expr; return res; } - Token *error = eat_token_if(pc, TokenIdKeywordError); - if (error != nullptr) { - Token *dot = expect_token(pc, TokenIdDot); - Token *name = expect_token(pc, TokenIdSymbol); + TokenIndex error = eat_token_if(pc, TokenIdKeywordError); + if (error != 0) { + TokenIndex dot = expect_token(pc, TokenIdDot); + TokenIndex name = expect_token(pc, TokenIdIdentifier); AstNode *left = ast_create_node(pc, NodeTypeErrorType, error); AstNode *res = ast_create_node(pc, NodeTypeFieldAccessExpr, dot); res->data.field_access_expr.struct_expr = left; - res->data.field_access_expr.field_name = token_buf(name); + res->data.field_access_expr.field_name = token_buf(pc, name); return res; } - Token *false_token = eat_token_if(pc, TokenIdKeywordFalse); - if (false_token != nullptr) { + TokenIndex false_token = eat_token_if(pc, TokenIdKeywordFalse); + if (false_token != 0) { AstNode *res = ast_create_node(pc, NodeTypeBoolLiteral, false_token); res->data.bool_literal.value = false; return res; } - Token *null = eat_token_if(pc, TokenIdKeywordNull); - if (null != nullptr) + TokenIndex null = eat_token_if(pc, TokenIdKeywordNull); + if (null != 0) return ast_create_node(pc, NodeTypeNullLiteral, null); - Token *anyframe = eat_token_if(pc, TokenIdKeywordAnyFrame); - if (anyframe != nullptr) + TokenIndex anyframe = eat_token_if(pc, TokenIdKeywordAnyFrame); + if (anyframe != 0) return ast_create_node(pc, NodeTypeAnyFrameType, anyframe); - Token *true_token = eat_token_if(pc, TokenIdKeywordTrue); - if (true_token != nullptr) { + TokenIndex true_token = eat_token_if(pc, TokenIdKeywordTrue); + if (true_token != 0) { AstNode *res = ast_create_node(pc, NodeTypeBoolLiteral, true_token); res->data.bool_literal.value = true; return res; } - Token *undefined = eat_token_if(pc, TokenIdKeywordUndefined); - if (undefined != nullptr) + TokenIndex undefined = eat_token_if(pc, TokenIdKeywordUndefined); + if (undefined != 0) return ast_create_node(pc, NodeTypeUndefinedLiteral, undefined); - Token *unreachable = eat_token_if(pc, TokenIdKeywordUnreachable); - if (unreachable != nullptr) + TokenIndex unreachable = eat_token_if(pc, TokenIdKeywordUnreachable); + if (unreachable != 0) return ast_create_node(pc, NodeTypeUnreachable, unreachable); - Buf *string_buf; - Token *string_lit = eat_token_if(pc, TokenIdStringLiteral); - if (string_lit != nullptr) { - string_buf = token_buf(string_lit); - } else { - Buf multiline_string_buf = BUF_INIT; - string_lit = ast_parse_multiline_string_literal(pc, &multiline_string_buf); - if (string_lit != nullptr) { - string_buf = buf_create_from_buf(&multiline_string_buf); - } + TokenIndex string_lit = eat_token_if(pc, TokenIdStringLiteral); + if (string_lit != 0) { + return ast_create_node(pc, NodeTypeStringLiteral, string_lit); } - if (string_lit != nullptr) { - AstNode *res = ast_create_node(pc, NodeTypeStringLiteral, string_lit); - res->data.string_literal.buf = string_buf; - return res; + + TokenIndex multiline_str_lit = ast_parse_multi_tok(pc, TokenIdMultilineStringLiteralLine); + if (multiline_str_lit != 0) { + return ast_create_node(pc, NodeTypeStringLiteral, multiline_str_lit); } AstNode *switch_expr = ast_parse_switch_expr(pc); @@ -1814,22 +1736,21 @@ static AstNode *ast_parse_primary_type_expr(ParseContext *pc) { // ContainerDecl <- (KEYWORD_extern / KEYWORD_packed)? ContainerDeclAuto static AstNode *ast_parse_container_decl(ParseContext *pc) { - Token *layout_token = eat_token_if(pc, TokenIdKeywordExtern); - if (layout_token == nullptr) + TokenIndex layout_token = eat_token_if(pc, TokenIdKeywordExtern); + if (layout_token == 0) layout_token = eat_token_if(pc, TokenIdKeywordPacked); AstNode *res = ast_parse_container_decl_auto(pc); if (res == nullptr) { - if (layout_token != nullptr) + if (layout_token != 0) put_back_token(pc); return nullptr; } assert(res->type == NodeTypeContainerDecl); - if (layout_token != nullptr) { - res->line = layout_token->start_line; - res->column = layout_token->start_column; - res->data.container_decl.layout = layout_token->id == TokenIdKeywordExtern + if (layout_token != 0) { + res->main_token = layout_token; + res->data.container_decl.layout = pc->token_ids[layout_token] == TokenIdKeywordExtern ? ContainerLayoutExtern : ContainerLayoutPacked; } @@ -1838,28 +1759,27 @@ static AstNode *ast_parse_container_decl(ParseContext *pc) { // ErrorSetDecl <- KEYWORD_error LBRACE IdentifierList RBRACE static AstNode *ast_parse_error_set_decl(ParseContext *pc) { - Token *first = eat_token_if(pc, TokenIdKeywordError); - if (first == nullptr) + TokenIndex first = eat_token_if(pc, TokenIdKeywordError); + if (first == 0) return nullptr; - if (eat_token_if(pc, TokenIdLBrace) == nullptr) { + if (eat_token_if(pc, TokenIdLBrace) == 0) { put_back_token(pc); return nullptr; } ZigList decls = ast_parse_list(pc, TokenIdComma, [](ParseContext *context) { - Buf doc_comment_buf = BUF_INIT; - Token *doc_token = ast_parse_doc_comments(context, &doc_comment_buf); - Token *ident = eat_token_if(context, TokenIdSymbol); - if (ident == nullptr) + TokenIndex doc_token = ast_parse_doc_comments(context); + TokenIndex ident = eat_token_if(context, TokenIdIdentifier); + if (ident == 0) return (AstNode*)nullptr; - AstNode *symbol_node = token_symbol(context, ident); - if (doc_token == nullptr) + AstNode *symbol_node = token_identifier(context, ident); + if (doc_token == 0) return symbol_node; AstNode *field_node = ast_create_node(context, NodeTypeErrorSetField, doc_token); field_node->data.err_set_field.field_name = symbol_node; - field_node->data.err_set_field.doc_comments = doc_comment_buf; + field_node->data.err_set_field.doc_comments = doc_token; return field_node; }); expect_token(pc, TokenIdRBrace); @@ -1871,8 +1791,8 @@ static AstNode *ast_parse_error_set_decl(ParseContext *pc) { // GroupedExpr <- LPAREN Expr RPAREN static AstNode *ast_parse_grouped_expr(ParseContext *pc) { - Token *lparen = eat_token_if(pc, TokenIdLParen); - if (lparen == nullptr) + TokenIndex lparen = eat_token_if(pc, TokenIdLParen); + if (lparen == 0) return nullptr; AstNode *expr = ast_expect(pc, ast_parse_expr); @@ -1892,12 +1812,12 @@ static AstNode *ast_parse_if_type_expr(ParseContext *pc) { // <- BlockLabel Block // / BlockLabel? LoopTypeExpr static AstNode *ast_parse_labeled_type_expr(ParseContext *pc) { - Token *label = ast_parse_block_label(pc); - if (label != nullptr) { + TokenIndex label = ast_parse_block_label(pc); + if (label != 0) { AstNode *block = ast_parse_block(pc); if (block != nullptr) { assert(block->type == NodeTypeBlock); - block->data.block.name = token_buf(label); + block->data.block.name = token_buf(pc, label); return block; } } @@ -1906,10 +1826,10 @@ static AstNode *ast_parse_labeled_type_expr(ParseContext *pc) { if (loop != nullptr) { switch (loop->type) { case NodeTypeForExpr: - loop->data.for_expr.name = token_buf(label); + loop->data.for_expr.name = token_buf(pc, label); break; case NodeTypeWhileExpr: - loop->data.while_expr.name = token_buf(label); + loop->data.while_expr.name = token_buf(pc, label); break; default: zig_unreachable(); @@ -1917,7 +1837,7 @@ static AstNode *ast_parse_labeled_type_expr(ParseContext *pc) { return loop; } - if (label != nullptr) { + if (label != 0) { put_back_token(pc); put_back_token(pc); } @@ -1945,8 +1865,8 @@ static AstNode *ast_parse_while_type_expr(ParseContext *pc) { // SwitchExpr <- KEYWORD_switch LPAREN Expr RPAREN LBRACE SwitchProngList RBRACE static AstNode *ast_parse_switch_expr(ParseContext *pc) { - Token *switch_token = eat_token_if(pc, TokenIdKeywordSwitch); - if (switch_token == nullptr) + TokenIndex switch_token = eat_token_if(pc, TokenIdKeywordSwitch); + if (switch_token == 0) return nullptr; expect_token(pc, TokenIdLParen); @@ -1964,11 +1884,11 @@ static AstNode *ast_parse_switch_expr(ParseContext *pc) { // AsmExpr <- KEYWORD_asm KEYWORD_volatile? LPAREN STRINGLITERAL AsmOutput? RPAREN static AstNode *ast_parse_asm_expr(ParseContext *pc) { - Token *asm_token = eat_token_if(pc, TokenIdKeywordAsm); - if (asm_token == nullptr) + TokenIndex asm_token = eat_token_if(pc, TokenIdKeywordAsm); + if (asm_token == 0) return nullptr; - Token *volatile_token = eat_token_if(pc, TokenIdKeywordVolatile); + TokenIndex volatile_token = eat_token_if(pc, TokenIdKeywordVolatile); expect_token(pc, TokenIdLParen); AstNode *asm_template = ast_expect(pc, ast_parse_expr); AstNode *res = ast_parse_asm_output(pc); @@ -1976,25 +1896,21 @@ static AstNode *ast_parse_asm_expr(ParseContext *pc) { res = ast_create_node_no_line_info(pc, NodeTypeAsmExpr); expect_token(pc, TokenIdRParen); - res->line = asm_token->start_line; - res->column = asm_token->start_column; + res->main_token = asm_token; res->data.asm_expr.volatile_token = volatile_token; res->data.asm_expr.asm_template = asm_template; return res; } static AstNode *ast_parse_anon_lit(ParseContext *pc) { - Token *period = eat_token_if(pc, TokenIdDot); - if (period == nullptr) + TokenIndex period = eat_token_if(pc, TokenIdDot); + if (period == 0) return nullptr; // anon enum literal - Token *identifier = eat_token_if(pc, TokenIdSymbol); - if (identifier != nullptr) { - AstNode *res = ast_create_node(pc, NodeTypeEnumLiteral, period); - res->data.enum_literal.period = period; - res->data.enum_literal.identifier = identifier; - return res; + TokenIndex identifier = eat_token_if(pc, TokenIdIdentifier); + if (identifier != 0) { + return ast_create_node(pc, NodeTypeEnumLiteral, period); } // anon container literal @@ -2007,7 +1923,7 @@ static AstNode *ast_parse_anon_lit(ParseContext *pc) { // AsmOutput <- COLON AsmOutputList AsmInput? static AstNode *ast_parse_asm_output(ParseContext *pc) { - if (eat_token_if(pc, TokenIdColon) == nullptr) + if (eat_token_if(pc, TokenIdColon) == 0) return nullptr; ZigList output_list = ast_parse_list(pc, TokenIdComma, ast_parse_asm_output_item); @@ -2021,20 +1937,20 @@ static AstNode *ast_parse_asm_output(ParseContext *pc) { // AsmOutputItem <- LBRACKET IDENTIFIER RBRACKET STRINGLITERAL LPAREN (MINUSRARROW TypeExpr / IDENTIFIER) RPAREN static AsmOutput *ast_parse_asm_output_item(ParseContext *pc) { - if (eat_token_if(pc, TokenIdLBracket) == nullptr) + if (eat_token_if(pc, TokenIdLBracket) == 0) return nullptr; - Token *sym_name = expect_token(pc, TokenIdSymbol); + TokenIndex sym_name = expect_token(pc, TokenIdIdentifier); expect_token(pc, TokenIdRBracket); - Token *str = eat_token_if(pc, TokenIdMultilineStringLiteral); - if (str == nullptr) + TokenIndex str = ast_parse_multi_tok(pc, TokenIdMultilineStringLiteralLine); + if (str == 0) str = expect_token(pc, TokenIdStringLiteral); expect_token(pc, TokenIdLParen); - Token *var_name = eat_token_if(pc, TokenIdSymbol); + TokenIndex var_name = eat_token_if(pc, TokenIdIdentifier); AstNode *return_type = nullptr; - if (var_name == nullptr) { + if (var_name == 0) { expect_token(pc, TokenIdArrow); return_type = ast_expect(pc, ast_parse_type_expr); } @@ -2042,16 +1958,16 @@ static AsmOutput *ast_parse_asm_output_item(ParseContext *pc) { expect_token(pc, TokenIdRParen); AsmOutput *res = heap::c_allocator.create(); - res->asm_symbolic_name = token_buf(sym_name); - res->constraint = token_buf(str); - res->variable_name = token_buf(var_name); + res->asm_symbolic_name = token_buf(pc, sym_name); + res->constraint = token_buf(pc, str); + res->variable_name = token_buf(pc, var_name); res->return_type = return_type; return res; } // AsmInput <- COLON AsmInputList AsmClobbers? static AstNode *ast_parse_asm_input(ParseContext *pc) { - if (eat_token_if(pc, TokenIdColon) == nullptr) + if (eat_token_if(pc, TokenIdColon) == 0) return nullptr; ZigList input_list = ast_parse_list(pc, TokenIdComma, ast_parse_asm_input_item); @@ -2065,37 +1981,35 @@ static AstNode *ast_parse_asm_input(ParseContext *pc) { // AsmInputItem <- LBRACKET IDENTIFIER RBRACKET STRINGLITERAL LPAREN Expr RPAREN static AsmInput *ast_parse_asm_input_item(ParseContext *pc) { - if (eat_token_if(pc, TokenIdLBracket) == nullptr) + if (eat_token_if(pc, TokenIdLBracket) == 0) return nullptr; - Token *sym_name = expect_token(pc, TokenIdSymbol); + TokenIndex sym_name = expect_token(pc, TokenIdIdentifier); expect_token(pc, TokenIdRBracket); - Token *constraint = eat_token_if(pc, TokenIdMultilineStringLiteral); - if (constraint == nullptr) - constraint = expect_token(pc, TokenIdStringLiteral); + TokenIndex constraint = expect_token(pc, TokenIdStringLiteral); expect_token(pc, TokenIdLParen); AstNode *expr = ast_expect(pc, ast_parse_expr); expect_token(pc, TokenIdRParen); AsmInput *res = heap::c_allocator.create(); - res->asm_symbolic_name = token_buf(sym_name); - res->constraint = token_buf(constraint); + res->asm_symbolic_name = token_buf(pc, sym_name); + res->constraint = token_buf(pc, constraint); res->expr = expr; return res; } // AsmClobbers <- COLON StringList static AstNode *ast_parse_asm_clobbers(ParseContext *pc) { - if (eat_token_if(pc, TokenIdColon) == nullptr) + if (eat_token_if(pc, TokenIdColon) == 0) return nullptr; ZigList clobber_list = ast_parse_list(pc, TokenIdComma, [](ParseContext *context) { - Token *str = eat_token_if(context, TokenIdStringLiteral); - if (str == nullptr) - str = eat_token_if(context, TokenIdMultilineStringLiteral); - if (str != nullptr) - return token_buf(str); + TokenIndex str = eat_token_if(context, TokenIdStringLiteral); + if (str == 0) + str = ast_parse_multi_tok(context, TokenIdMultilineStringLiteralLine); + if (str != 0) + return token_buf(context, str); return (Buf*)nullptr; }); @@ -2105,24 +2019,24 @@ static AstNode *ast_parse_asm_clobbers(ParseContext *pc) { } // BreakLabel <- COLON IDENTIFIER -static Token *ast_parse_break_label(ParseContext *pc) { - if (eat_token_if(pc, TokenIdColon) == nullptr) - return nullptr; +static TokenIndex ast_parse_break_label(ParseContext *pc) { + if (eat_token_if(pc, TokenIdColon) == 0) + return 0; - return expect_token(pc, TokenIdSymbol); + return expect_token(pc, TokenIdIdentifier); } // BlockLabel <- IDENTIFIER COLON -static Token *ast_parse_block_label(ParseContext *pc) { - Token *ident = eat_token_if(pc, TokenIdSymbol); - if (ident == nullptr) - return nullptr; +static TokenIndex ast_parse_block_label(ParseContext *pc) { + TokenIndex ident = eat_token_if(pc, TokenIdIdentifier); + if (ident == 0) + return 0; // We do 2 token lookahead here, as we don't want to error when // parsing identifiers. - if (eat_token_if(pc, TokenIdColon) == nullptr) { + if (eat_token_if(pc, TokenIdColon) == 0) { put_back_token(pc); - return nullptr; + return 0; } return ident; @@ -2130,17 +2044,17 @@ static Token *ast_parse_block_label(ParseContext *pc) { // FieldInit <- DOT IDENTIFIER EQUAL Expr static AstNode *ast_parse_field_init(ParseContext *pc) { - Token *first = eat_token_if(pc, TokenIdDot); - if (first == nullptr) + TokenIndex first = eat_token_if(pc, TokenIdDot); + if (first == 0) return nullptr; - Token *name = eat_token_if(pc, TokenIdSymbol); - if (name == nullptr) { + TokenIndex name = eat_token_if(pc, TokenIdIdentifier); + if (name == 0) { // Because of anon literals ".{" is also valid. put_back_token(pc); return nullptr; } - if (eat_token_if(pc, TokenIdEq) == nullptr) { + if (eat_token_if(pc, TokenIdEq) == 0) { // Because ".Name" can also be intepreted as an enum literal, we should put back // those two tokens again so that the parser can try to parse them as the enum // literal later. @@ -2151,15 +2065,15 @@ static AstNode *ast_parse_field_init(ParseContext *pc) { AstNode *expr = ast_expect(pc, ast_parse_expr); AstNode *res = ast_create_node(pc, NodeTypeStructValueField, first); - res->data.struct_val_field.name = token_buf(name); + res->data.struct_val_field.name = token_buf(pc, name); res->data.struct_val_field.expr = expr; return res; } // WhileContinueExpr <- COLON LPAREN AssignExpr RPAREN static AstNode *ast_parse_while_continue_expr(ParseContext *pc) { - Token *first = eat_token_if(pc, TokenIdColon); - if (first == nullptr) + TokenIndex first = eat_token_if(pc, TokenIdColon); + if (first == 0) return nullptr; expect_token(pc, TokenIdLParen); @@ -2170,8 +2084,8 @@ static AstNode *ast_parse_while_continue_expr(ParseContext *pc) { // LinkSection <- KEYWORD_linksection LPAREN Expr RPAREN static AstNode *ast_parse_link_section(ParseContext *pc) { - Token *first = eat_token_if(pc, TokenIdKeywordLinkSection); - if (first == nullptr) + TokenIndex first = eat_token_if(pc, TokenIdKeywordLinkSection); + if (first == 0) return nullptr; expect_token(pc, TokenIdLParen); @@ -2182,8 +2096,8 @@ static AstNode *ast_parse_link_section(ParseContext *pc) { // CallConv <- KEYWORD_callconv LPAREN Expr RPAREN static AstNode *ast_parse_callconv(ParseContext *pc) { - Token *first = eat_token_if(pc, TokenIdKeywordCallconv); - if (first == nullptr) + TokenIndex first = eat_token_if(pc, TokenIdKeywordCallconv); + if (first == 0) return nullptr; expect_token(pc, TokenIdLParen); @@ -2194,28 +2108,27 @@ static AstNode *ast_parse_callconv(ParseContext *pc) { // ParamDecl <- (KEYWORD_noalias / KEYWORD_comptime)? (IDENTIFIER COLON)? ParamType static AstNode *ast_parse_param_decl(ParseContext *pc) { - Buf doc_comments = BUF_INIT; - ast_parse_doc_comments(pc, &doc_comments); + TokenIndex first_doc_comment = ast_parse_doc_comments(pc); - Token *first = eat_token_if(pc, TokenIdKeywordNoAlias); - if (first == nullptr) + TokenIndex first = eat_token_if(pc, TokenIdKeywordNoAlias); + if (first == 0) first = eat_token_if(pc, TokenIdKeywordCompTime); - Token *name = eat_token_if(pc, TokenIdSymbol); - if (name != nullptr) { - if (eat_token_if(pc, TokenIdColon) != nullptr) { - if (first == nullptr) + TokenIndex name = eat_token_if(pc, TokenIdIdentifier); + if (name != 0) { + if (eat_token_if(pc, TokenIdColon) != 0) { + if (first == 0) first = name; } else { // We put back the ident, so it can be parsed as a ParamType // later. put_back_token(pc); - name = nullptr; + name = 0; } } AstNode *res; - if (first == nullptr) { + if (first == 0) { first = peek_token(pc); res = ast_parse_param_type(pc); } else { @@ -2226,12 +2139,11 @@ static AstNode *ast_parse_param_decl(ParseContext *pc) { return nullptr; assert(res->type == NodeTypeParamDecl); - res->line = first->start_line; - res->column = first->start_column; - res->data.param_decl.name = token_buf(name); - res->data.param_decl.doc_comments = doc_comments; - res->data.param_decl.is_noalias = first->id == TokenIdKeywordNoAlias; - res->data.param_decl.is_comptime = first->id == TokenIdKeywordCompTime; + res->main_token = first; + res->data.param_decl.name = token_buf(pc, name); + res->data.param_decl.doc_comments = first_doc_comment; + res->data.param_decl.is_noalias = pc->token_ids[first] == TokenIdKeywordNoAlias; + res->data.param_decl.is_comptime = pc->token_ids[first] == TokenIdKeywordCompTime; return res; } @@ -2240,15 +2152,15 @@ static AstNode *ast_parse_param_decl(ParseContext *pc) { // / DOT3 // / TypeExpr static AstNode *ast_parse_param_type(ParseContext *pc) { - Token *anytype_token = eat_token_if(pc, TokenIdKeywordAnyType); - if (anytype_token != nullptr) { + TokenIndex anytype_token = eat_token_if(pc, TokenIdKeywordAnyType); + if (anytype_token != 0) { AstNode *res = ast_create_node(pc, NodeTypeParamDecl, anytype_token); res->data.param_decl.anytype_token = anytype_token; return res; } - Token *dots = eat_token_if(pc, TokenIdEllipsis3); - if (dots != nullptr) { + TokenIndex dots = eat_token_if(pc, TokenIdEllipsis3); + if (dots != 0) { AstNode *res = ast_create_node(pc, NodeTypeParamDecl, dots); res->data.param_decl.is_var_args = true; return res; @@ -2266,8 +2178,8 @@ static AstNode *ast_parse_param_type(ParseContext *pc) { // IfPrefix <- KEYWORD_if LPAREN Expr RPAREN PtrPayload? static AstNode *ast_parse_if_prefix(ParseContext *pc) { - Token *first = eat_token_if(pc, TokenIdKeywordIf); - if (first == nullptr) + TokenIndex first = eat_token_if(pc, TokenIdKeywordIf); + if (first == 0) return nullptr; expect_token(pc, TokenIdLParen); @@ -2279,16 +2191,16 @@ static AstNode *ast_parse_if_prefix(ParseContext *pc) { AstNode *res = ast_create_node(pc, NodeTypeIfOptional, first); res->data.test_expr.target_node = condition; if (opt_payload.unwrap(&payload)) { - res->data.test_expr.var_symbol = token_buf(payload.payload); - res->data.test_expr.var_is_ptr = payload.asterisk != nullptr; + res->data.test_expr.var_symbol = token_buf(pc, payload.payload); + res->data.test_expr.var_is_ptr = payload.asterisk != 0; } return res; } // WhilePrefix <- KEYWORD_while LPAREN Expr RPAREN PtrPayload? WhileContinueExpr? static AstNode *ast_parse_while_prefix(ParseContext *pc) { - Token *while_token = eat_token_if(pc, TokenIdKeywordWhile); - if (while_token == nullptr) + TokenIndex while_token = eat_token_if(pc, TokenIdKeywordWhile); + if (while_token == 0) return nullptr; expect_token(pc, TokenIdLParen); @@ -2302,8 +2214,8 @@ static AstNode *ast_parse_while_prefix(ParseContext *pc) { res->data.while_expr.condition = condition; res->data.while_expr.continue_expr = continue_expr; if (opt_payload.unwrap(&payload)) { - res->data.while_expr.var_symbol = token_buf(payload.payload); - res->data.while_expr.var_is_ptr = payload.asterisk != nullptr; + res->data.while_expr.var_symbol = token_buf(pc, payload.payload); + res->data.while_expr.var_is_ptr = payload.asterisk != 0; } return res; @@ -2311,8 +2223,8 @@ static AstNode *ast_parse_while_prefix(ParseContext *pc) { // ForPrefix <- KEYWORD_for LPAREN Expr RPAREN PtrIndexPayload static AstNode *ast_parse_for_prefix(ParseContext *pc) { - Token *for_token = eat_token_if(pc, TokenIdKeywordFor); - if (for_token == nullptr) + TokenIndex for_token = eat_token_if(pc, TokenIdKeywordFor); + if (for_token == 0) return nullptr; expect_token(pc, TokenIdLParen); @@ -2324,31 +2236,31 @@ static AstNode *ast_parse_for_prefix(ParseContext *pc) { AstNode *res = ast_create_node(pc, NodeTypeForExpr, for_token); res->data.for_expr.array_expr = array_expr; - res->data.for_expr.elem_node = token_symbol(pc, payload.payload); - res->data.for_expr.elem_is_ptr = payload.asterisk != nullptr; - if (payload.index != nullptr) - res->data.for_expr.index_node = token_symbol(pc, payload.index); + res->data.for_expr.elem_node = token_identifier(pc, payload.payload); + res->data.for_expr.elem_is_ptr = payload.asterisk != 0; + if (payload.index != 0) + res->data.for_expr.index_node = token_identifier(pc, payload.index); return res; } // Payload <- PIPE IDENTIFIER PIPE -static Token *ast_parse_payload(ParseContext *pc) { - if (eat_token_if(pc, TokenIdBinOr) == nullptr) - return nullptr; +static TokenIndex ast_parse_payload(ParseContext *pc) { + if (eat_token_if(pc, TokenIdBinOr) == 0) + return 0; - Token *res = expect_token(pc, TokenIdSymbol); + TokenIndex res = expect_token(pc, TokenIdIdentifier); expect_token(pc, TokenIdBinOr); return res; } // PtrPayload <- PIPE ASTERISK? IDENTIFIER PIPE static Optional ast_parse_ptr_payload(ParseContext *pc) { - if (eat_token_if(pc, TokenIdBinOr) == nullptr) + if (eat_token_if(pc, TokenIdBinOr) == 0) return Optional::none(); - Token *asterisk = eat_token_if(pc, TokenIdStar); - Token *payload = expect_token(pc, TokenIdSymbol); + TokenIndex asterisk = eat_token_if(pc, TokenIdStar); + TokenIndex payload = expect_token(pc, TokenIdIdentifier); expect_token(pc, TokenIdBinOr); PtrPayload res; @@ -2359,14 +2271,14 @@ static Optional ast_parse_ptr_payload(ParseContext *pc) { // PtrIndexPayload <- PIPE ASTERISK? IDENTIFIER (COMMA IDENTIFIER)? PIPE static Optional ast_parse_ptr_index_payload(ParseContext *pc) { - if (eat_token_if(pc, TokenIdBinOr) == nullptr) + if (eat_token_if(pc, TokenIdBinOr) == 0) return Optional::none(); - Token *asterisk = eat_token_if(pc, TokenIdStar); - Token *payload = expect_token(pc, TokenIdSymbol); - Token *index = nullptr; - if (eat_token_if(pc, TokenIdComma) != nullptr) - index = expect_token(pc, TokenIdSymbol); + TokenIndex asterisk = eat_token_if(pc, TokenIdStar); + TokenIndex payload = expect_token(pc, TokenIdIdentifier); + TokenIndex index = 0; + if (eat_token_if(pc, TokenIdComma) != 0) + index = expect_token(pc, TokenIdIdentifier); expect_token(pc, TokenIdBinOr); PtrIndexPayload res; @@ -2390,8 +2302,8 @@ static AstNode *ast_parse_switch_prong(ParseContext *pc) { assert(res->type == NodeTypeSwitchProng); res->data.switch_prong.expr = expr; if (opt_payload.unwrap(&payload)) { - res->data.switch_prong.var_symbol = token_symbol(pc, payload.payload); - res->data.switch_prong.var_is_ptr = payload.asterisk != nullptr; + res->data.switch_prong.var_symbol = token_identifier(pc, payload.payload); + res->data.switch_prong.var_is_ptr = payload.asterisk != 0; } return res; @@ -2407,7 +2319,7 @@ static AstNode *ast_parse_switch_case(ParseContext *pc) { res->data.switch_prong.items.append(first); res->data.switch_prong.any_items_are_range = first->type == NodeTypeSwitchRange; - while (eat_token_if(pc, TokenIdComma) != nullptr) { + while (eat_token_if(pc, TokenIdComma) != 0) { AstNode *item = ast_parse_switch_item(pc); if (item == nullptr) break; @@ -2419,8 +2331,8 @@ static AstNode *ast_parse_switch_case(ParseContext *pc) { return res; } - Token *else_token = eat_token_if(pc, TokenIdKeywordElse); - if (else_token != nullptr) + TokenIndex else_token = eat_token_if(pc, TokenIdKeywordElse); + if (else_token != 0) return ast_create_node(pc, NodeTypeSwitchProng, else_token); return nullptr; @@ -2432,8 +2344,8 @@ static AstNode *ast_parse_switch_item(ParseContext *pc) { if (expr == nullptr) return nullptr; - Token *dots = eat_token_if(pc, TokenIdEllipsis3); - if (dots != nullptr) { + TokenIndex dots = eat_token_if(pc, TokenIdEllipsis3); + if (dots != 0) { AstNode *expr2 = ast_expect(pc, ast_parse_expr); AstNode *res = ast_create_node(pc, NodeTypeSwitchRange, dots); res->data.switch_range.start = expr; @@ -2478,9 +2390,9 @@ static AstNode *ast_parse_assign_op(ParseContext *pc) { table[TokenIdTimesEq] = BinOpTypeAssignTimes; table[TokenIdTimesPercentEq] = BinOpTypeAssignTimesWrap; - BinOpType op = table[peek_token(pc)->id]; + BinOpType op = table[pc->token_ids[pc->current_token]]; if (op != BinOpTypeInvalid) { - Token *op_token = eat_token(pc); + TokenIndex op_token = eat_token(pc); AstNode *res = ast_create_node(pc, NodeTypeBinOpExpr, op_token); res->data.bin_op_expr.bin_op = op; return res; @@ -2506,9 +2418,9 @@ static AstNode *ast_parse_compare_op(ParseContext *pc) { table[TokenIdCmpLessOrEq] = BinOpTypeCmpLessOrEq; table[TokenIdCmpGreaterOrEq] = BinOpTypeCmpGreaterOrEq; - BinOpType op = table[peek_token(pc)->id]; + BinOpType op = table[pc->token_ids[pc->current_token]]; if (op != BinOpTypeInvalid) { - Token *op_token = eat_token(pc); + TokenIndex op_token = eat_token(pc); AstNode *res = ast_create_node(pc, NodeTypeBinOpExpr, op_token); res->data.bin_op_expr.bin_op = op; return res; @@ -2530,20 +2442,20 @@ static AstNode *ast_parse_bitwise_op(ParseContext *pc) { table[TokenIdBinOr] = BinOpTypeBinOr; table[TokenIdKeywordOrElse] = BinOpTypeUnwrapOptional; - BinOpType op = table[peek_token(pc)->id]; + BinOpType op = table[pc->token_ids[pc->current_token]]; if (op != BinOpTypeInvalid) { - Token *op_token = eat_token(pc); + TokenIndex op_token = eat_token(pc); AstNode *res = ast_create_node(pc, NodeTypeBinOpExpr, op_token); res->data.bin_op_expr.bin_op = op; return res; } - Token *catch_token = eat_token_if(pc, TokenIdKeywordCatch); - if (catch_token != nullptr) { - Token *payload = ast_parse_payload(pc); + TokenIndex catch_token = eat_token_if(pc, TokenIdKeywordCatch); + if (catch_token != 0) { + TokenIndex payload = ast_parse_payload(pc); AstNode *res = ast_create_node(pc, NodeTypeCatchExpr, catch_token); - if (payload != nullptr) - res->data.unwrap_err_expr.symbol = token_symbol(pc, payload); + if (payload != 0) + res->data.unwrap_err_expr.symbol = token_identifier(pc, payload); return res; } @@ -2559,9 +2471,9 @@ static AstNode *ast_parse_bit_shift_op(ParseContext *pc) { table[TokenIdBitShiftLeft] = BinOpTypeBitShiftLeft; table[TokenIdBitShiftRight] = BinOpTypeBitShiftRight; - BinOpType op = table[peek_token(pc)->id]; + BinOpType op = table[pc->token_ids[pc->current_token]]; if (op != BinOpTypeInvalid) { - Token *op_token = eat_token(pc); + TokenIndex op_token = eat_token(pc); AstNode *res = ast_create_node(pc, NodeTypeBinOpExpr, op_token); res->data.bin_op_expr.bin_op = op; return res; @@ -2584,9 +2496,9 @@ static AstNode *ast_parse_addition_op(ParseContext *pc) { table[TokenIdPlusPercent] = BinOpTypeAddWrap; table[TokenIdMinusPercent] = BinOpTypeSubWrap; - BinOpType op = table[peek_token(pc)->id]; + BinOpType op = table[pc->token_ids[pc->current_token]]; if (op != BinOpTypeInvalid) { - Token *op_token = eat_token(pc); + TokenIndex op_token = eat_token(pc); AstNode *res = ast_create_node(pc, NodeTypeBinOpExpr, op_token); res->data.bin_op_expr.bin_op = op; return res; @@ -2611,9 +2523,9 @@ static AstNode *ast_parse_multiply_op(ParseContext *pc) { table[TokenIdStarStar] = BinOpTypeArrayMult; table[TokenIdTimesPercent] = BinOpTypeMultWrap; - BinOpType op = table[peek_token(pc)->id]; + BinOpType op = table[pc->token_ids[pc->current_token]]; if (op != BinOpTypeInvalid) { - Token *op_token = eat_token(pc); + TokenIndex op_token = eat_token(pc); AstNode *res = ast_create_node(pc, NodeTypeBinOpExpr, op_token); res->data.bin_op_expr.bin_op = op; return res; @@ -2638,23 +2550,23 @@ static AstNode *ast_parse_prefix_op(ParseContext *pc) { table[TokenIdMinusPercent] = PrefixOpNegationWrap; table[TokenIdAmpersand] = PrefixOpAddrOf; - PrefixOp op = table[peek_token(pc)->id]; + PrefixOp op = table[pc->token_ids[pc->current_token]]; if (op != PrefixOpInvalid) { - Token *op_token = eat_token(pc); + TokenIndex op_token = eat_token(pc); AstNode *res = ast_create_node(pc, NodeTypePrefixOpExpr, op_token); res->data.prefix_op_expr.prefix_op = op; return res; } - Token *try_token = eat_token_if(pc, TokenIdKeywordTry); - if (try_token != nullptr) { + TokenIndex try_token = eat_token_if(pc, TokenIdKeywordTry); + if (try_token != 0) { AstNode *res = ast_create_node(pc, NodeTypeReturnExpr, try_token); res->data.return_expr.kind = ReturnKindError; return res; } - Token *await = eat_token_if(pc, TokenIdKeywordAwait); - if (await != nullptr) { + TokenIndex await = eat_token_if(pc, TokenIdKeywordAwait); + if (await != 0) { AstNode *res = ast_create_node(pc, NodeTypeAwaitExpr, await); return res; } @@ -2668,16 +2580,16 @@ static AstNode *ast_parse_prefix_op(ParseContext *pc) { // / ArrayTypeStart (ByteAlign / KEYWORD_const / KEYWORD_volatile)* // / PtrTypeStart (KEYWORD_align LPAREN Expr (COLON INTEGER COLON INTEGER)? RPAREN / KEYWORD_const / KEYWORD_volatile)* static AstNode *ast_parse_prefix_type_op(ParseContext *pc) { - Token *questionmark = eat_token_if(pc, TokenIdQuestion); - if (questionmark != nullptr) { + TokenIndex questionmark = eat_token_if(pc, TokenIdQuestion); + if (questionmark != 0) { AstNode *res = ast_create_node(pc, NodeTypePrefixOpExpr, questionmark); res->data.prefix_op_expr.prefix_op = PrefixOpOptional; return res; } - Token *anyframe = eat_token_if(pc, TokenIdKeywordAnyFrame); - if (anyframe != nullptr) { - if (eat_token_if(pc, TokenIdArrow) != nullptr) { + TokenIndex anyframe = eat_token_if(pc, TokenIdKeywordAnyFrame); + if (anyframe != 0) { + if (eat_token_if(pc, TokenIdArrow) != 0) { AstNode *res = ast_create_node(pc, NodeTypeAnyFrameType, anyframe); return res; } @@ -2685,18 +2597,18 @@ static AstNode *ast_parse_prefix_type_op(ParseContext *pc) { put_back_token(pc); } - Token *arr_init_lbracket = eat_token_if(pc, TokenIdLBracket); - if (arr_init_lbracket != nullptr) { - Token *underscore = eat_token_if(pc, TokenIdSymbol); - if (underscore == nullptr) { + TokenIndex arr_init_lbracket = eat_token_if(pc, TokenIdLBracket); + if (arr_init_lbracket != 0) { + TokenIndex underscore = eat_token_if(pc, TokenIdIdentifier); + if (underscore == 0) { put_back_token(pc); - } else if (!buf_eql_str(token_buf(underscore), "_")) { + } else if (!buf_eql_str(token_buf(pc, underscore), "_")) { put_back_token(pc); put_back_token(pc); } else { AstNode *sentinel = nullptr; - Token *colon = eat_token_if(pc, TokenIdColon); - if (colon != nullptr) { + TokenIndex colon = eat_token_if(pc, TokenIdColon); + if (colon != 0) { sentinel = ast_expect(pc, ast_parse_expr); } expect_token(pc, TokenIdRBracket); @@ -2715,33 +2627,33 @@ static AstNode *ast_parse_prefix_type_op(ParseContext *pc) { if (child == nullptr) child = ptr; while (true) { - Token *allowzero_token = eat_token_if(pc, TokenIdKeywordAllowZero); - if (allowzero_token != nullptr) { + TokenIndex allowzero_token = eat_token_if(pc, TokenIdKeywordAllowZero); + if (allowzero_token != 0) { child->data.pointer_type.allow_zero_token = allowzero_token; continue; } - if (eat_token_if(pc, TokenIdKeywordAlign) != nullptr) { + if (eat_token_if(pc, TokenIdKeywordAlign) != 0) { expect_token(pc, TokenIdLParen); AstNode *align_expr = ast_expect(pc, ast_parse_expr); child->data.pointer_type.align_expr = align_expr; - if (eat_token_if(pc, TokenIdColon) != nullptr) { - Token *bit_offset_start = expect_token(pc, TokenIdIntLiteral); + if (eat_token_if(pc, TokenIdColon) != 0) { + TokenIndex bit_offset_start = expect_token(pc, TokenIdIntLiteral); expect_token(pc, TokenIdColon); - Token *host_int_bytes = expect_token(pc, TokenIdIntLiteral); - child->data.pointer_type.bit_offset_start = token_bigint(bit_offset_start); - child->data.pointer_type.host_int_bytes = token_bigint(host_int_bytes); + TokenIndex host_int_bytes = expect_token(pc, TokenIdIntLiteral); + child->data.pointer_type.bit_offset_start = bit_offset_start; + child->data.pointer_type.host_int_bytes = host_int_bytes; } expect_token(pc, TokenIdRParen); continue; } - if (eat_token_if(pc, TokenIdKeywordConst) != nullptr) { + if (eat_token_if(pc, TokenIdKeywordConst) != 0) { child->data.pointer_type.is_const = true; continue; } - if (eat_token_if(pc, TokenIdKeywordVolatile) != nullptr) { + if (eat_token_if(pc, TokenIdKeywordVolatile) != 0) { child->data.pointer_type.is_volatile = true; continue; } @@ -2756,8 +2668,8 @@ static AstNode *ast_parse_prefix_type_op(ParseContext *pc) { if (array != nullptr) { assert(array->type == NodeTypeArrayType); while (true) { - Token *allowzero_token = eat_token_if(pc, TokenIdKeywordAllowZero); - if (allowzero_token != nullptr) { + TokenIndex allowzero_token = eat_token_if(pc, TokenIdKeywordAllowZero); + if (allowzero_token != 0) { array->data.array_type.allow_zero_token = allowzero_token; continue; } @@ -2768,12 +2680,12 @@ static AstNode *ast_parse_prefix_type_op(ParseContext *pc) { continue; } - if (eat_token_if(pc, TokenIdKeywordConst) != nullptr) { + if (eat_token_if(pc, TokenIdKeywordConst) != 0) { array->data.array_type.is_const = true; continue; } - if (eat_token_if(pc, TokenIdKeywordVolatile) != nullptr) { + if (eat_token_if(pc, TokenIdKeywordVolatile) != 0) { array->data.array_type.is_volatile = true; continue; } @@ -2793,14 +2705,14 @@ static AstNode *ast_parse_prefix_type_op(ParseContext *pc) { // / DOTASTERISK // / DOTQUESTIONMARK static AstNode *ast_parse_suffix_op(ParseContext *pc) { - Token *lbracket = eat_token_if(pc, TokenIdLBracket); - if (lbracket != nullptr) { + TokenIndex lbracket = eat_token_if(pc, TokenIdLBracket); + if (lbracket != 0) { AstNode *start = ast_expect(pc, ast_parse_expr); AstNode *end = nullptr; - if (eat_token_if(pc, TokenIdEllipsis2) != nullptr) { + if (eat_token_if(pc, TokenIdEllipsis2) != 0) { AstNode *sentinel = nullptr; end = ast_parse_expr(pc); - if (eat_token_if(pc, TokenIdColon) != nullptr) { + if (eat_token_if(pc, TokenIdColon) != 0) { sentinel = ast_parse_expr(pc); } expect_token(pc, TokenIdRBracket); @@ -2819,18 +2731,18 @@ static AstNode *ast_parse_suffix_op(ParseContext *pc) { return res; } - Token *dot_asterisk = eat_token_if(pc, TokenIdDotStar); - if (dot_asterisk != nullptr) + TokenIndex dot_asterisk = eat_token_if(pc, TokenIdDotStar); + if (dot_asterisk != 0) return ast_create_node(pc, NodeTypePtrDeref, dot_asterisk); - Token *dot = eat_token_if(pc, TokenIdDot); - if (dot != nullptr) { - if (eat_token_if(pc, TokenIdQuestion) != nullptr) + TokenIndex dot = eat_token_if(pc, TokenIdDot); + if (dot != 0) { + if (eat_token_if(pc, TokenIdQuestion) != 0) return ast_create_node(pc, NodeTypeUnwrapOptional, dot); - Token *ident = expect_token(pc, TokenIdSymbol); + TokenIndex ident = expect_token(pc, TokenIdIdentifier); AstNode *res = ast_create_node(pc, NodeTypeFieldAccessExpr, dot); - res->data.field_access_expr.field_name = token_buf(ident); + res->data.field_access_expr.field_name = token_buf(pc, ident); return res; } @@ -2839,8 +2751,8 @@ static AstNode *ast_parse_suffix_op(ParseContext *pc) { // FnCallArguments <- LPAREN ExprList RPAREN static AstNode *ast_parse_fn_call_arguments(ParseContext *pc) { - Token *paren = eat_token_if(pc, TokenIdLParen); - if (paren == nullptr) + TokenIndex paren = eat_token_if(pc, TokenIdLParen); + if (paren == 0) return nullptr; ZigList params = ast_parse_list(pc, TokenIdComma, ast_parse_expr); @@ -2854,14 +2766,14 @@ static AstNode *ast_parse_fn_call_arguments(ParseContext *pc) { // ArrayTypeStart <- LBRACKET Expr? RBRACKET static AstNode *ast_parse_array_type_start(ParseContext *pc) { - Token *lbracket = eat_token_if(pc, TokenIdLBracket); - if (lbracket == nullptr) + TokenIndex lbracket = eat_token_if(pc, TokenIdLBracket); + if (lbracket == 0) return nullptr; AstNode *size = ast_parse_expr(pc); AstNode *sentinel = nullptr; - Token *colon = eat_token_if(pc, TokenIdColon); - if (colon != nullptr) { + TokenIndex colon = eat_token_if(pc, TokenIdColon); + if (colon != 0) { sentinel = ast_expect(pc, ast_parse_expr); } expect_token(pc, TokenIdRBracket); @@ -2879,10 +2791,10 @@ static AstNode *ast_parse_array_type_start(ParseContext *pc) { static AstNode *ast_parse_ptr_type_start(ParseContext *pc) { AstNode *sentinel = nullptr; - Token *asterisk = eat_token_if(pc, TokenIdStar); - if (asterisk != nullptr) { - Token *colon = eat_token_if(pc, TokenIdColon); - if (colon != nullptr) { + TokenIndex asterisk = eat_token_if(pc, TokenIdStar); + if (asterisk != 0) { + TokenIndex colon = eat_token_if(pc, TokenIdColon); + if (colon != 0) { sentinel = ast_expect(pc, ast_parse_expr); } AstNode *res = ast_create_node(pc, NodeTypePointerType, asterisk); @@ -2891,10 +2803,10 @@ static AstNode *ast_parse_ptr_type_start(ParseContext *pc) { return res; } - Token *asterisk2 = eat_token_if(pc, TokenIdStarStar); - if (asterisk2 != nullptr) { - Token *colon = eat_token_if(pc, TokenIdColon); - if (colon != nullptr) { + TokenIndex asterisk2 = eat_token_if(pc, TokenIdStarStar); + if (asterisk2 != 0) { + TokenIndex colon = eat_token_if(pc, TokenIdColon); + if (colon != 0) { sentinel = ast_expect(pc, ast_parse_expr); } AstNode *res = ast_create_node(pc, NodeTypePointerType, asterisk2); @@ -2906,15 +2818,15 @@ static AstNode *ast_parse_ptr_type_start(ParseContext *pc) { return res; } - Token *lbracket = eat_token_if(pc, TokenIdLBracket); - if (lbracket != nullptr) { - Token *star = eat_token_if(pc, TokenIdStar); - if (star == nullptr) { + TokenIndex lbracket = eat_token_if(pc, TokenIdLBracket); + if (lbracket != 0) { + TokenIndex star = eat_token_if(pc, TokenIdStar); + if (star == 0) { put_back_token(pc); } else { - Token *c_tok = eat_token_if(pc, TokenIdSymbol); - if (c_tok != nullptr) { - if (!buf_eql_str(token_buf(c_tok), "c")) { + TokenIndex c_tok = eat_token_if(pc, TokenIdIdentifier); + if (c_tok != 0) { + if (!buf_eql_str(token_buf(pc, c_tok), "c")) { put_back_token(pc); // c symbol } else { expect_token(pc, TokenIdRBracket); @@ -2924,8 +2836,8 @@ static AstNode *ast_parse_ptr_type_start(ParseContext *pc) { } } - Token *colon = eat_token_if(pc, TokenIdColon); - if (colon != nullptr) { + TokenIndex colon = eat_token_if(pc, TokenIdColon); + if (colon != 0) { sentinel = ast_expect(pc, ast_parse_expr); } expect_token(pc, TokenIdRBracket); @@ -2951,9 +2863,7 @@ static AstNode *ast_parse_container_decl_auto(ParseContext *pc) { res->data.container_decl.fields = members.fields; res->data.container_decl.decls = members.decls; - if (buf_len(&members.doc_comments) != 0) { - res->data.container_decl.doc_comments = members.doc_comments; - } + res->data.container_decl.doc_comments = members.doc_comments; return res; } @@ -2963,8 +2873,8 @@ static AstNode *ast_parse_container_decl_auto(ParseContext *pc) { // / KEYWORD_union (LPAREN (KEYWORD_enum (LPAREN Expr RPAREN)? / Expr) RPAREN)? // / KEYWORD_opaque static AstNode *ast_parse_container_decl_type(ParseContext *pc) { - Token *first = eat_token_if(pc, TokenIdKeywordStruct); - if (first != nullptr) { + TokenIndex first = eat_token_if(pc, TokenIdKeywordStruct); + if (first != 0) { AstNode *res = ast_create_node(pc, NodeTypeContainerDecl, first); res->data.container_decl.init_arg_expr = nullptr; res->data.container_decl.kind = ContainerKindStruct; @@ -2972,7 +2882,7 @@ static AstNode *ast_parse_container_decl_type(ParseContext *pc) { } first = eat_token_if(pc, TokenIdKeywordOpaque); - if (first != nullptr) { + if (first != 0) { AstNode *res = ast_create_node(pc, NodeTypeContainerDecl, first); res->data.container_decl.init_arg_expr = nullptr; res->data.container_decl.kind = ContainerKindOpaque; @@ -2980,9 +2890,9 @@ static AstNode *ast_parse_container_decl_type(ParseContext *pc) { } first = eat_token_if(pc, TokenIdKeywordEnum); - if (first != nullptr) { + if (first != 0) { AstNode *init_arg_expr = nullptr; - if (eat_token_if(pc, TokenIdLParen) != nullptr) { + if (eat_token_if(pc, TokenIdLParen) != 0) { init_arg_expr = ast_expect(pc, ast_parse_expr); expect_token(pc, TokenIdRParen); } @@ -2993,13 +2903,13 @@ static AstNode *ast_parse_container_decl_type(ParseContext *pc) { } first = eat_token_if(pc, TokenIdKeywordUnion); - if (first != nullptr) { + if (first != 0) { AstNode *init_arg_expr = nullptr; bool auto_enum = false; - if (eat_token_if(pc, TokenIdLParen) != nullptr) { - if (eat_token_if(pc, TokenIdKeywordEnum) != nullptr) { + if (eat_token_if(pc, TokenIdLParen) != 0) { + if (eat_token_if(pc, TokenIdKeywordEnum) != 0) { auto_enum = true; - if (eat_token_if(pc, TokenIdLParen) != nullptr) { + if (eat_token_if(pc, TokenIdLParen) != 0) { init_arg_expr = ast_expect(pc, ast_parse_expr); expect_token(pc, TokenIdRParen); } @@ -3022,7 +2932,7 @@ static AstNode *ast_parse_container_decl_type(ParseContext *pc) { // ByteAlign <- KEYWORD_align LPAREN Expr RPAREN static AstNode *ast_parse_byte_align(ParseContext *pc) { - if (eat_token_if(pc, TokenIdKeywordAlign) == nullptr) + if (eat_token_if(pc, TokenIdKeywordAlign) == 0) return nullptr; expect_token(pc, TokenIdLParen); @@ -3103,7 +3013,7 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont case NodeTypeCharLiteral: // none break; - case NodeTypeSymbol: + case NodeTypeIdentifier: // none break; case NodeTypePrefixOpExpr: @@ -3264,3 +3174,414 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont break; } } + +Error source_string_literal_buf(const char *source, Buf *out, size_t *bad_index) { + size_t byte_offset = 0; + + assert(source[byte_offset] == '"'); + byte_offset += 1; + + buf_resize(out, 0); + + uint32_t codepoint; + + enum { + StateStart, + StateBackslash, + StateUnicodeLBrace, + StateUnicodeDigit, + } state = StateStart; + for (;;byte_offset += 1) { + switch (state) { + case StateStart: switch (source[byte_offset]) { + case '\\': + state = StateBackslash; + continue; + case '\n': + *bad_index = byte_offset; + return ErrorInvalidCharacter; + case '"': + return ErrorNone; + default: + buf_append_char(out, source[byte_offset]); + continue; + } + case StateBackslash: switch (source[byte_offset]) { + case 'n': + buf_append_char(out, '\n'); + state = StateStart; + continue; + case 'r': + buf_append_char(out, '\r'); + state = StateStart; + continue; + case '\\': + buf_append_char(out, '\\'); + state = StateStart; + continue; + case 't': + buf_append_char(out, '\t'); + state = StateStart; + continue; + case '\'': + buf_append_char(out, '\''); + state = StateStart; + continue; + case '"': + buf_append_char(out, '"'); + state = StateStart; + continue; + case 'x': { + byte_offset += 1; + uint8_t digit1; + if (source[byte_offset] >= '0' && source[byte_offset] <= '9') { + digit1 = source[byte_offset] - '0'; + } else if (source[byte_offset] >= 'a' && source[byte_offset] <= 'z') { + digit1 = source[byte_offset] - 'a' + 10; + } else if (source[byte_offset] >= 'A' && source[byte_offset] <= 'Z') { + digit1 = source[byte_offset] - 'A' + 10; + } else { + *bad_index = byte_offset; + return ErrorInvalidCharacter; + } + + byte_offset += 1; + uint8_t digit0; + if (source[byte_offset] >= '0' && source[byte_offset] <= '9') { + digit0 = source[byte_offset] - '0'; + } else if (source[byte_offset] >= 'a' && source[byte_offset] <= 'z') { + digit0 = source[byte_offset] - 'a' + 10; + } else if (source[byte_offset] >= 'A' && source[byte_offset] <= 'Z') { + digit0 = source[byte_offset] - 'A' + 10; + } else { + *bad_index = byte_offset; + return ErrorInvalidCharacter; + } + + buf_append_char(out, digit1 * 16 + digit0); + state = StateStart; + continue; + } + case 'u': + state = StateUnicodeLBrace; + continue; + default: + *bad_index = byte_offset; + return ErrorInvalidCharacter; + } + case StateUnicodeLBrace: switch (source[byte_offset]) { + case '{': + state = StateUnicodeDigit; + codepoint = 0; + continue; + default: + *bad_index = byte_offset; + return ErrorInvalidCharacter; + } + case StateUnicodeDigit: { + uint8_t digit; + if (source[byte_offset] >= '0' && source[byte_offset] <= '9') { + digit = source[byte_offset] - '0'; + } else if (source[byte_offset] >= 'a' && source[byte_offset] <= 'z') { + digit = source[byte_offset] - 'a' + 10; + } else if (source[byte_offset] >= 'A' && source[byte_offset] <= 'Z') { + digit = source[byte_offset] - 'A' + 10; + } else if (source[byte_offset] == '}') { + if (codepoint < 0x80) { + buf_append_char(out, codepoint); + } else if (codepoint < 0x800) { + buf_append_char(out, 0xc0 | (codepoint >> 6)); + buf_append_char(out, 0x80 | (codepoint & 0x3f)); + } else if (codepoint < 0x10000) { + buf_append_char(out, 0xe0 | (codepoint >> 12)); + buf_append_char(out, 0x80 | ((codepoint >> 6) & 0x3f)); + buf_append_char(out, 0x80 | (codepoint & 0x3f)); + } else if (codepoint < 0x110000) { + buf_append_char(out, 0xf0 | (codepoint >> 18)); + buf_append_char(out, 0x80 | ((codepoint >> 12) & 0x3f)); + buf_append_char(out, 0x80 | ((codepoint >> 6) & 0x3f)); + buf_append_char(out, 0x80 | (codepoint & 0x3f)); + } else { + *bad_index = byte_offset; + return ErrorUnicodePointTooLarge; + } + state = StateStart; + continue; + } else { + *bad_index = byte_offset; + return ErrorInvalidCharacter; + } + codepoint = codepoint * 16 + digit; + continue; + } + } + } + zig_unreachable(); +} + +static uint32_t utf8_code_point(const uint8_t *bytes) { + if (bytes[0] <= 0x7f) { + return bytes[0]; + } else if (bytes[0] >= 0xc0 && bytes[0] <= 0xdf) { + uint32_t result = bytes[0] & 0x1f; + result <<= 6; + result |= bytes[1] & 0x3f; + return result; + } else if (bytes[0] >= 0xe0 && bytes[0] <= 0xef) { + uint32_t result = bytes[0] & 0xf; + + result <<= 6; + result |= bytes[1] & 0x3f; + + result <<= 6; + result |= bytes[2] & 0x3f; + + return result; + } else if (bytes[0] >= 0xf0 && bytes[0] <= 0xf7) { + uint32_t result = bytes[0] & 0x7; + + result <<= 6; + result |= bytes[1] & 0x3f; + + result <<= 6; + result |= bytes[2] & 0x3f; + + result <<= 6; + result |= bytes[3] & 0x3f; + + return result; + } else { + zig_unreachable(); + } +} + +Error source_char_literal(const char *source, uint32_t *result, size_t *bad_index) { + if (source[0] != '\\') { + *result = utf8_code_point((const uint8_t *)source); + return ErrorNone; + } + + uint32_t byte_offset = 1; + uint32_t codepoint; + + enum State { + StateBackslash, + StateUnicodeLBrace, + StateUnicodeDigit, + } state = StateBackslash; + + for (;;byte_offset += 1) { + switch (state) { + case StateBackslash: switch (source[byte_offset]) { + case 'n': + *result = '\n'; + return ErrorNone; + case 'r': + *result = '\r'; + return ErrorNone; + case '\\': + *result = '\\'; + return ErrorNone; + case 't': + *result = '\t'; + return ErrorNone; + case '\'': + *result = '\''; + return ErrorNone; + case '"': + *result = '"'; + return ErrorNone; + case 'x': { + byte_offset += 1; + uint8_t digit1; + if (source[byte_offset] >= '0' && source[byte_offset] <= '9') { + digit1 = source[byte_offset] - '0'; + } else if (source[byte_offset] >= 'a' && source[byte_offset] <= 'z') { + digit1 = source[byte_offset] - 'a' + 10; + } else if (source[byte_offset] >= 'A' && source[byte_offset] <= 'Z') { + digit1 = source[byte_offset] - 'A' + 10; + } else { + *bad_index = byte_offset; + return ErrorInvalidCharacter; + } + + byte_offset += 1; + uint8_t digit0; + if (source[byte_offset] >= '0' && source[byte_offset] <= '9') { + digit0 = source[byte_offset] - '0'; + } else if (source[byte_offset] >= 'a' && source[byte_offset] <= 'z') { + digit0 = source[byte_offset] - 'a' + 10; + } else if (source[byte_offset] >= 'A' && source[byte_offset] <= 'Z') { + digit0 = source[byte_offset] - 'A' + 10; + } else { + *bad_index = byte_offset; + return ErrorInvalidCharacter; + } + + *result = digit1 * 16 + digit0; + return ErrorNone; + } + case 'u': + state = StateUnicodeLBrace; + continue; + default: + *bad_index = byte_offset; + return ErrorInvalidCharacter; + } + case StateUnicodeLBrace: switch (source[byte_offset]) { + case '{': + state = StateUnicodeDigit; + codepoint = 0; + continue; + default: + *bad_index = byte_offset; + return ErrorInvalidCharacter; + } + case StateUnicodeDigit: { + uint8_t digit; + if (source[byte_offset] >= '0' && source[byte_offset] <= '9') { + digit = source[byte_offset] - '0'; + } else if (source[byte_offset] >= 'a' && source[byte_offset] <= 'z') { + digit = source[byte_offset] - 'a' + 10; + } else if (source[byte_offset] >= 'A' && source[byte_offset] <= 'Z') { + digit = source[byte_offset] - 'A' + 10; + } else if (source[byte_offset] == '}') { + if (codepoint < 0x110000) { + *result = codepoint; + return ErrorNone; + } else { + *bad_index = byte_offset; + return ErrorUnicodePointTooLarge; + } + } else { + *bad_index = byte_offset; + return ErrorInvalidCharacter; + } + codepoint = codepoint * 16 + digit; + continue; + } + } + } +} + + +Buf *token_string_literal_buf(RootStruct *root_struct, TokenIndex token) { + Error err; + assert(root_struct->token_ids[token] == TokenIdStringLiteral); + const char *source = buf_ptr(root_struct->source_code); + size_t byte_offset = root_struct->token_locs[token].offset; + size_t bad_index; + Buf *str = buf_alloc(); + if ((err = source_string_literal_buf(source + byte_offset, str, &bad_index))) { + zig_panic("TODO handle string literal parse error"); + } + return str; +} + +Buf *token_identifier_buf(RootStruct *root_struct, TokenIndex token) { + Error err; + const char *source = buf_ptr(root_struct->source_code); + size_t byte_offset = root_struct->token_locs[token].offset; + if (root_struct->token_ids[token] == TokenIdBuiltin) { + byte_offset += 1; + } else { + assert(root_struct->token_ids[token] == TokenIdIdentifier); + } + assert(source[byte_offset] != '.'); // wrong token index + + if (source[byte_offset] == '@') { + size_t bad_index; + Buf *str = buf_alloc(); + if ((err = source_string_literal_buf(source + byte_offset + 1, str, &bad_index))) { + zig_panic("TODO handle string literal parse error"); + } + return str; + } else { + size_t start = byte_offset; + for (;; byte_offset += 1) { + if (source[byte_offset] == 0) break; + if ((source[byte_offset] >= 'a' && source[byte_offset] <= 'z') || + (source[byte_offset] >= 'A' && source[byte_offset] <= 'Z') || + (source[byte_offset] >= '0' && source[byte_offset] <= '9') || + source[byte_offset] == '_') + { + continue; + } + break; + } + return buf_create_from_mem(source + start, byte_offset - start); + } +} + +Buf *node_identifier_buf(AstNode *node) { + assert(node->type == NodeTypeIdentifier); + RootStruct *root_struct = node->owner->data.structure.root_struct; + return token_identifier_buf(root_struct, node->main_token); +} + +Buf *node_string_literal_buf(AstNode *node) { + assert(node->type == NodeTypeStringLiteral); + RootStruct *root_struct = node->owner->data.structure.root_struct; + return token_string_literal_buf(root_struct, node->main_token); +} + +void token_number_literal_bigint(RootStruct *root_struct, BigInt *result, TokenIndex token) { + const char *source = buf_ptr(root_struct->source_code); + uint32_t byte_offset = root_struct->token_locs[token].offset; + + bigint_init_unsigned(result, 0); + BigInt radix_bi; + + if (source[byte_offset] == '0') { + byte_offset += 1; + switch (source[byte_offset]) { + case 'b': + byte_offset += 1; + bigint_init_unsigned(&radix_bi, 2); + break; + case 'o': + byte_offset += 1; + bigint_init_unsigned(&radix_bi, 8); + break; + case 'x': + byte_offset += 1; + bigint_init_unsigned(&radix_bi, 16); + break; + default: + bigint_init_unsigned(&radix_bi, 10); + break; + } + } else { + bigint_init_unsigned(&radix_bi, 10); + } + + BigInt digit_value_bi = {}; + BigInt multiplied = {}; + + for (;source[byte_offset] != 0; byte_offset += 1) { + uint8_t digit; + if (source[byte_offset] >= '0' && source[byte_offset] <= '9') { + digit = source[byte_offset] - '0'; + } else if (source[byte_offset] >= 'a' && source[byte_offset] <= 'z') { + digit = source[byte_offset] - 'a' + 10; + } else if (source[byte_offset] >= 'A' && source[byte_offset] <= 'Z') { + digit = source[byte_offset] - 'A' + 10; + } else if (source[byte_offset] == '_') { + continue; + } else { + break; + } + bigint_deinit(&digit_value_bi); + bigint_init_unsigned(&digit_value_bi, digit); + + bigint_deinit(&multiplied); + bigint_mul(&multiplied, result, &radix_bi); + + bigint_add(result, &multiplied, &digit_value_bi); + } + + bigint_deinit(&digit_value_bi); + bigint_deinit(&multiplied); + bigint_deinit(&radix_bi); +} + diff --git a/src/stage1/parser.hpp b/src/stage1/parser.hpp index 73950993f3..2d9a5f0b4a 100644 --- a/src/stage1/parser.hpp +++ b/src/stage1/parser.hpp @@ -12,14 +12,21 @@ #include "tokenizer.hpp" #include "errmsg.hpp" -ATTRIBUTE_PRINTF(2, 3) -void ast_token_error(Token *token, const char *format, ...); - - -AstNode * ast_parse(Buf *buf, ZigList *tokens, ZigType *owner, ErrColor err_color); +AstNode * ast_parse(Buf *buf, ZigType *owner, ErrColor err_color); void ast_print(AstNode *node, int indent); void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *context), void *context); +Buf *node_identifier_buf(AstNode *node); +Buf *node_string_literal_buf(AstNode *node); + +Buf *token_identifier_buf(RootStruct *root_struct, TokenIndex token); +Buf *token_string_literal_buf(RootStruct *root_struct, TokenIndex token); + +void token_number_literal_bigint(RootStruct *root_struct, BigInt *result, TokenIndex token); + +Error source_string_literal_buf(const char *source, Buf *out, size_t *bad_index); +Error source_char_literal(const char *source, uint32_t *out, size_t *bad_index); + #endif diff --git a/src/stage1/stage2.h b/src/stage1/stage2.h index 1eb494f362..b7c8616ec0 100644 --- a/src/stage1/stage2.h +++ b/src/stage1/stage2.h @@ -112,6 +112,8 @@ enum Error { ErrorZigIsTheCCompiler, ErrorFileBusy, ErrorLocked, + ErrorInvalidCharacter, + ErrorUnicodePointTooLarge, }; // ABI warning diff --git a/src/stage1/tokenizer.cpp b/src/stage1/tokenizer.cpp index 623169a313..b1bae1865b 100644 --- a/src/stage1/tokenizer.cpp +++ b/src/stage1/tokenizer.cpp @@ -30,18 +30,28 @@ case '7': \ case '8': \ case '9' + #define DIGIT \ '0': \ case DIGIT_NON_ZERO -#define ALPHA \ +#define HEXDIGIT \ 'a': \ case 'b': \ case 'c': \ case 'd': \ case 'e': \ case 'f': \ - case 'g': \ + case 'A': \ + case 'B': \ + case 'C': \ + case 'D': \ + case 'E': \ + case 'F': \ + case DIGIT + +#define ALPHA_EXCEPT_HEX_P_O_X \ + 'g': \ case 'h': \ case 'i': \ case 'j': \ @@ -49,8 +59,6 @@ case 'l': \ case 'm': \ case 'n': \ - case 'o': \ - case 'p': \ case 'q': \ case 'r': \ case 's': \ @@ -58,15 +66,8 @@ case 'u': \ case 'v': \ case 'w': \ - case 'x': \ case 'y': \ case 'z': \ - case 'A': \ - case 'B': \ - case 'C': \ - case 'D': \ - case 'E': \ - case 'F': \ case 'G': \ case 'H': \ case 'I': \ @@ -76,7 +77,6 @@ case 'M': \ case 'N': \ case 'O': \ - case 'P': \ case 'Q': \ case 'R': \ case 'S': \ @@ -88,7 +88,46 @@ case 'Y': \ case 'Z' -#define SYMBOL_CHAR \ +#define ALPHA_EXCEPT_E_B_O_X \ + ALPHA_EXCEPT_HEX_P_O_X: \ + case 'a': \ + case 'c': \ + case 'd': \ + case 'f': \ + case 'A': \ + case 'B': \ + case 'C': \ + case 'D': \ + case 'F': \ + case 'p': \ + case 'P' + +#define ALPHA_EXCEPT_HEX_AND_P \ + ALPHA_EXCEPT_HEX_P_O_X: \ + case 'o': \ + case 'x' + +#define ALPHA_EXCEPT_E \ + ALPHA_EXCEPT_HEX_AND_P: \ + case 'a': \ + case 'b': \ + case 'c': \ + case 'd': \ + case 'f': \ + case 'A': \ + case 'B': \ + case 'C': \ + case 'D': \ + case 'F': \ + case 'p': \ + case 'P' + +#define ALPHA \ + ALPHA_EXCEPT_E: \ + case 'e': \ + case 'E' + +#define IDENTIFIER_CHAR \ ALPHA: \ case DIGIT: \ case '_' @@ -157,101 +196,92 @@ static const struct ZigKeyword zig_keywords[] = { {"while", TokenIdKeywordWhile}, }; -bool is_zig_keyword(Buf *buf) { +// Returns TokenIdIdentifier if it is not a keyword. +static TokenId zig_keyword_token(const char *name_ptr, size_t name_len) { for (size_t i = 0; i < array_length(zig_keywords); i += 1) { - if (buf_eql_str(buf, zig_keywords[i].text)) { - return true; + if (mem_eql_str(name_ptr, name_len, zig_keywords[i].text)) { + return zig_keywords[i].token_id; } } - return false; -} - -static bool is_symbol_char(uint8_t c) { - switch (c) { - case SYMBOL_CHAR: - return true; - default: - return false; - } + return TokenIdIdentifier; } enum TokenizeState { - TokenizeStateStart, - TokenizeStateSymbol, - TokenizeStateZero, // "0", which might lead to "0x" - TokenizeStateNumber, // "123", "0x123" - TokenizeStateNumberNoUnderscore, // "12_", "0x12_" next char must be digit - TokenizeStateNumberDot, - TokenizeStateFloatFraction, // "123.456", "0x123.456" - TokenizeStateFloatFractionNoUnderscore, // "123.45_", "0x123.45_" - TokenizeStateFloatExponentUnsigned, // "123.456e", "123e", "0x123p" - TokenizeStateFloatExponentNumber, // "123.456e7", "123.456e+7", "123.456e-7" - TokenizeStateFloatExponentNumberNoUnderscore, // "123.456e7_", "123.456e+7_", "123.456e-7_" - TokenizeStateString, - TokenizeStateStringEscape, - TokenizeStateStringEscapeUnicodeStart, - TokenizeStateCharLiteral, - TokenizeStateCharLiteralEnd, - TokenizeStateCharLiteralUnicode, - TokenizeStateSawStar, - TokenizeStateSawStarPercent, - TokenizeStateSawSlash, - TokenizeStateSawSlash2, - TokenizeStateSawSlash3, - TokenizeStateSawSlashBang, - TokenizeStateSawBackslash, - TokenizeStateSawPercent, - TokenizeStateSawPlus, - TokenizeStateSawPlusPercent, - TokenizeStateSawDash, - TokenizeStateSawMinusPercent, - TokenizeStateSawAmpersand, - TokenizeStateSawCaret, - TokenizeStateSawBar, - TokenizeStateDocComment, - TokenizeStateContainerDocComment, - TokenizeStateLineComment, - TokenizeStateLineString, - TokenizeStateLineStringEnd, - TokenizeStateLineStringContinue, - TokenizeStateSawEq, - TokenizeStateSawBang, - TokenizeStateSawLessThan, - TokenizeStateSawLessThanLessThan, - TokenizeStateSawGreaterThan, - TokenizeStateSawGreaterThanGreaterThan, - TokenizeStateSawDot, - TokenizeStateSawDotDot, - TokenizeStateSawDotStar, - TokenizeStateSawAtSign, - TokenizeStateCharCode, - TokenizeStateError, + TokenizeState_start, + TokenizeState_identifier, + TokenizeState_builtin, + TokenizeState_string_literal, + TokenizeState_string_literal_backslash, + TokenizeState_multiline_string_literal_line, + TokenizeState_char_literal, + TokenizeState_char_literal_backslash, + TokenizeState_char_literal_hex_escape, + TokenizeState_char_literal_unicode_escape_saw_u, + TokenizeState_char_literal_unicode_escape, + TokenizeState_char_literal_unicode, + TokenizeState_char_literal_end, + TokenizeState_backslash, + TokenizeState_equal, + TokenizeState_bang, + TokenizeState_pipe, + TokenizeState_minus, + TokenizeState_minus_percent, + TokenizeState_asterisk, + TokenizeState_asterisk_percent, + TokenizeState_slash, + TokenizeState_line_comment_start, + TokenizeState_line_comment, + TokenizeState_doc_comment_start, + TokenizeState_doc_comment, + TokenizeState_container_doc_comment, + TokenizeState_zero, + TokenizeState_int_literal_dec, + TokenizeState_int_literal_dec_no_underscore, + TokenizeState_int_literal_bin, + TokenizeState_int_literal_bin_no_underscore, + TokenizeState_int_literal_oct, + TokenizeState_int_literal_oct_no_underscore, + TokenizeState_int_literal_hex, + TokenizeState_int_literal_hex_no_underscore, + TokenizeState_num_dot_dec, + TokenizeState_num_dot_hex, + TokenizeState_float_fraction_dec, + TokenizeState_float_fraction_dec_no_underscore, + TokenizeState_float_fraction_hex, + TokenizeState_float_fraction_hex_no_underscore, + TokenizeState_float_exponent_unsigned, + TokenizeState_float_exponent_num, + TokenizeState_float_exponent_num_no_underscore, + TokenizeState_ampersand, + TokenizeState_caret, + TokenizeState_percent, + TokenizeState_plus, + TokenizeState_plus_percent, + TokenizeState_angle_bracket_left, + TokenizeState_angle_bracket_angle_bracket_left, + TokenizeState_angle_bracket_right, + TokenizeState_angle_bracket_angle_bracket_right, + TokenizeState_period, + TokenizeState_period_2, + TokenizeState_period_asterisk, + TokenizeState_saw_at_sign, + TokenizeState_error, }; struct Tokenize { - Buf *buf; + Tokenization *out; size_t pos; TokenizeState state; - ZigList *tokens; - int line; - int column; - Token *cur_tok; - Tokenization *out; - uint32_t radix; - bool is_trailing_underscore; - size_t char_code_index; - bool unicode; - uint32_t char_code; - size_t remaining_code_units; + uint32_t line; + uint32_t column; }; ATTRIBUTE_PRINTF(2, 3) static void tokenize_error(Tokenize *t, const char *format, ...) { - t->state = TokenizeStateError; + t->state = TokenizeState_error; - t->out->err_line = t->line; - t->out->err_column = t->column; + t->out->err_byte_offset = t->pos; va_list ap; va_start(ap, format); @@ -259,98 +289,18 @@ static void tokenize_error(Tokenize *t, const char *format, ...) { va_end(ap); } -static void set_token_id(Tokenize *t, Token *token, TokenId id) { - token->id = id; - - if (id == TokenIdIntLiteral) { - bigint_init_unsigned(&token->data.int_lit.bigint, 0); - } else if (id == TokenIdFloatLiteral) { - bigfloat_init_32(&token->data.float_lit.bigfloat, 0.0f); - token->data.float_lit.overflow = false; - } else if (id == TokenIdStringLiteral || id == TokenIdMultilineStringLiteral || id == TokenIdSymbol) { - memset(&token->data.str_lit.str, 0, sizeof(Buf)); - buf_resize(&token->data.str_lit.str, 0); - } -} - static void begin_token(Tokenize *t, TokenId id) { - assert(!t->cur_tok); - t->tokens->add_one(); - Token *token = &t->tokens->last(); - token->start_line = t->line; - token->start_column = t->column; - token->start_pos = t->pos; - - set_token_id(t, token, id); - - t->cur_tok = token; + t->out->ids.append(id); + t->out->locs.append({ + .offset = (uint32_t) t->pos, + .line = t->line, + .column = t->column, + }); } static void cancel_token(Tokenize *t) { - t->tokens->pop(); - t->cur_tok = nullptr; -} - -static void end_float_token(Tokenize *t) { - uint8_t *ptr_buf = (uint8_t*)buf_ptr(t->buf) + t->cur_tok->start_pos; - size_t buf_len = t->cur_tok->end_pos - t->cur_tok->start_pos; - if (bigfloat_init_buf(&t->cur_tok->data.float_lit.bigfloat, ptr_buf, buf_len)) { - t->cur_tok->data.float_lit.overflow = true; - } -} - -static void end_token(Tokenize *t) { - assert(t->cur_tok); - t->cur_tok->end_pos = t->pos + 1; - - if (t->cur_tok->id == TokenIdFloatLiteral) { - end_float_token(t); - } else if (t->cur_tok->id == TokenIdSymbol) { - char *token_mem = buf_ptr(t->buf) + t->cur_tok->start_pos; - int token_len = (int)(t->cur_tok->end_pos - t->cur_tok->start_pos); - - for (size_t i = 0; i < array_length(zig_keywords); i += 1) { - if (mem_eql_str(token_mem, token_len, zig_keywords[i].text)) { - t->cur_tok->id = zig_keywords[i].token_id; - break; - } - } - } - - t->cur_tok = nullptr; -} - -static bool is_exponent_signifier(uint8_t c, int radix) { - if (radix == 16) { - return c == 'p' || c == 'P'; - } else { - return c == 'e' || c == 'E'; - } -} - -static uint32_t get_digit_value(uint8_t c) { - if ('0' <= c && c <= '9') { - return c - '0'; - } - if ('A' <= c && c <= 'Z') { - return c - 'A' + 10; - } - if ('a' <= c && c <= 'z') { - return c - 'a' + 10; - } - return UINT32_MAX; -} - -static void handle_string_escape(Tokenize *t, uint8_t c) { - if (t->cur_tok->id == TokenIdCharLiteral) { - t->cur_tok->data.char_lit.c = c; - t->state = TokenizeStateCharLiteralEnd; - } else if (t->cur_tok->id == TokenIdStringLiteral || t->cur_tok->id == TokenIdSymbol) { - buf_append_char(&t->cur_tok->data.str_lit.str, c); - t->state = TokenizeStateString; - } else { - zig_unreachable(); - } + t->out->ids.pop(); + t->out->locs.pop(); } static const char* get_escape_shorthand(uint8_t c) { @@ -376,7 +326,15 @@ static const char* get_escape_shorthand(uint8_t c) { } } +static void invalid_eof(Tokenize *t) { + return tokenize_error(t, "unexpected End-Of-File"); +} + static void invalid_char_error(Tokenize *t, uint8_t c) { + if (c == 0) { + return invalid_eof(t); + } + if (c == '\r') { tokenize_error(t, "invalid carriage return, only '\\n' line endings are supported"); return; @@ -396,1139 +354,1092 @@ static void invalid_char_error(Tokenize *t, uint8_t c) { tokenize_error(t, "invalid character: '\\x%02x'", c); } -void tokenize(Buf *buf, Tokenization *out) { +void tokenize(const char *source, Tokenization *out) { Tokenize t = {0}; t.out = out; - t.tokens = out->tokens = heap::c_allocator.create>(); - t.buf = buf; - out->line_offsets = heap::c_allocator.create>(); - out->line_offsets->append(0); + size_t remaining_code_units; + size_t seen_escape_digits; - // Skip the UTF-8 BOM if present - if (buf_starts_with_mem(buf, "\xEF\xBB\xBF", 3)) { + // Skip the UTF-8 BOM if present. + if (source[0] == (char)0xef && + source[1] == (char)0xbb && + source[2] == (char)0xbf) + { t.pos += 3; } - for (; t.pos < buf_len(t.buf); t.pos += 1) { - uint8_t c = buf_ptr(t.buf)[t.pos]; + // Invalid token takes up index 0 so that index 0 can mean "none". + begin_token(&t, TokenIdCount); + + for (;;) { + uint8_t c = source[t.pos]; switch (t.state) { - case TokenizeStateError: - break; - case TokenizeStateStart: + case TokenizeState_error: + goto eof; + case TokenizeState_start: switch (c) { + case 0: + goto eof; case WHITESPACE: break; - case ALPHA: - case '_': - t.state = TokenizeStateSymbol; - begin_token(&t, TokenIdSymbol); - buf_append_char(&t.cur_tok->data.str_lit.str, c); - break; - case '0': - t.state = TokenizeStateZero; - begin_token(&t, TokenIdIntLiteral); - t.is_trailing_underscore = false; - t.radix = 10; - bigint_init_unsigned(&t.cur_tok->data.int_lit.bigint, 0); - break; - case DIGIT_NON_ZERO: - t.state = TokenizeStateNumber; - begin_token(&t, TokenIdIntLiteral); - t.is_trailing_underscore = false; - t.radix = 10; - bigint_init_unsigned(&t.cur_tok->data.int_lit.bigint, get_digit_value(c)); - break; case '"': begin_token(&t, TokenIdStringLiteral); - t.state = TokenizeStateString; + t.state = TokenizeState_string_literal; break; case '\'': begin_token(&t, TokenIdCharLiteral); - t.state = TokenizeStateCharLiteral; + t.state = TokenizeState_char_literal; break; - case '(': - begin_token(&t, TokenIdLParen); - end_token(&t); - break; - case ')': - begin_token(&t, TokenIdRParen); - end_token(&t); - break; - case ',': - begin_token(&t, TokenIdComma); - end_token(&t); - break; - case '?': - begin_token(&t, TokenIdQuestion); - end_token(&t); - break; - case '{': - begin_token(&t, TokenIdLBrace); - end_token(&t); - break; - case '}': - begin_token(&t, TokenIdRBrace); - end_token(&t); - break; - case '[': - begin_token(&t, TokenIdLBracket); - end_token(&t); - break; - case ']': - begin_token(&t, TokenIdRBracket); - end_token(&t); - break; - case ';': - begin_token(&t, TokenIdSemicolon); - end_token(&t); - break; - case ':': - begin_token(&t, TokenIdColon); - end_token(&t); - break; - case '#': - begin_token(&t, TokenIdNumberSign); - end_token(&t); - break; - case '*': - begin_token(&t, TokenIdStar); - t.state = TokenizeStateSawStar; - break; - case '/': - begin_token(&t, TokenIdSlash); - t.state = TokenizeStateSawSlash; - break; - case '\\': - begin_token(&t, TokenIdMultilineStringLiteral); - t.state = TokenizeStateSawBackslash; - break; - case '%': - begin_token(&t, TokenIdPercent); - t.state = TokenizeStateSawPercent; - break; - case '+': - begin_token(&t, TokenIdPlus); - t.state = TokenizeStateSawPlus; - break; - case '~': - begin_token(&t, TokenIdTilde); - end_token(&t); + case ALPHA: + case '_': + t.state = TokenizeState_identifier; + begin_token(&t, TokenIdIdentifier); break; case '@': - begin_token(&t, TokenIdAtSign); - t.state = TokenizeStateSawAtSign; - break; - case '-': - begin_token(&t, TokenIdDash); - t.state = TokenizeStateSawDash; - break; - case '&': - begin_token(&t, TokenIdAmpersand); - t.state = TokenizeStateSawAmpersand; - break; - case '^': - begin_token(&t, TokenIdBinXor); - t.state = TokenizeStateSawCaret; - break; - case '|': - begin_token(&t, TokenIdBinOr); - t.state = TokenizeStateSawBar; + begin_token(&t, TokenIdBuiltin); + t.state = TokenizeState_saw_at_sign; break; case '=': begin_token(&t, TokenIdEq); - t.state = TokenizeStateSawEq; + t.state = TokenizeState_equal; break; case '!': begin_token(&t, TokenIdBang); - t.state = TokenizeStateSawBang; + t.state = TokenizeState_bang; + break; + case '|': + begin_token(&t, TokenIdBinOr); + t.state = TokenizeState_pipe; + break; + case '(': + begin_token(&t, TokenIdLParen); + break; + case ')': + begin_token(&t, TokenIdRParen); + break; + case '[': + begin_token(&t, TokenIdLBracket); + break; + case ']': + begin_token(&t, TokenIdRBracket); + break; + case ';': + begin_token(&t, TokenIdSemicolon); + break; + case ',': + begin_token(&t, TokenIdComma); + break; + case '?': + begin_token(&t, TokenIdQuestion); + break; + case ':': + begin_token(&t, TokenIdColon); + break; + case '%': + begin_token(&t, TokenIdPercent); + t.state = TokenizeState_percent; + break; + case '*': + begin_token(&t, TokenIdStar); + t.state = TokenizeState_asterisk; + break; + case '+': + begin_token(&t, TokenIdPlus); + t.state = TokenizeState_plus; break; case '<': begin_token(&t, TokenIdCmpLessThan); - t.state = TokenizeStateSawLessThan; + t.state = TokenizeState_angle_bracket_left; break; case '>': begin_token(&t, TokenIdCmpGreaterThan); - t.state = TokenizeStateSawGreaterThan; + t.state = TokenizeState_angle_bracket_right; + break; + case '^': + begin_token(&t, TokenIdBinXor); + t.state = TokenizeState_caret; + break; + case '\\': + begin_token(&t, TokenIdMultilineStringLiteralLine); + t.state = TokenizeState_backslash; + break; + case '{': + begin_token(&t, TokenIdLBrace); + break; + case '}': + begin_token(&t, TokenIdRBrace); + break; + case '~': + begin_token(&t, TokenIdTilde); break; case '.': begin_token(&t, TokenIdDot); - t.state = TokenizeStateSawDot; + t.state = TokenizeState_period; + break; + case '-': + begin_token(&t, TokenIdDash); + t.state = TokenizeState_minus; + break; + case '/': + begin_token(&t, TokenIdSlash); + t.state = TokenizeState_slash; + break; + case '&': + begin_token(&t, TokenIdAmpersand); + t.state = TokenizeState_ampersand; + break; + case '0': + t.state = TokenizeState_zero; + begin_token(&t, TokenIdIntLiteral); + break; + case DIGIT_NON_ZERO: + t.state = TokenizeState_int_literal_dec; + begin_token(&t, TokenIdIntLiteral); break; default: invalid_char_error(&t, c); } break; - case TokenizeStateSawDot: + case TokenizeState_saw_at_sign: switch (c) { - case '.': - t.state = TokenizeStateSawDotDot; - set_token_id(&t, t.cur_tok, TokenIdEllipsis2); + case 0: + invalid_eof(&t); + goto eof; + case '"': + t.out->ids.last() = TokenIdIdentifier; + t.state = TokenizeState_string_literal; break; - case '*': - t.state = TokenizeStateSawDotStar; - set_token_id(&t, t.cur_tok, TokenIdDotStar); + case IDENTIFIER_CHAR: + t.state = TokenizeState_builtin; break; default: - t.pos -= 1; - end_token(&t); - t.state = TokenizeStateStart; - continue; + invalid_char_error(&t, c); } break; - case TokenizeStateSawDotDot: - switch (c) { - case '.': - t.state = TokenizeStateStart; - set_token_id(&t, t.cur_tok, TokenIdEllipsis3); - end_token(&t); - break; - default: - t.pos -= 1; - end_token(&t); - t.state = TokenizeStateStart; - continue; - } - break; - case TokenizeStateSawDotStar: - switch (c) { - case '*': - tokenize_error(&t, "`.*` can't be followed by `*`. Are you missing a space?"); - break; - default: - t.pos -= 1; - end_token(&t); - t.state = TokenizeStateStart; - continue; - } - break; - case TokenizeStateSawGreaterThan: - switch (c) { - case '=': - set_token_id(&t, t.cur_tok, TokenIdCmpGreaterOrEq); - end_token(&t); - t.state = TokenizeStateStart; - break; - case '>': - set_token_id(&t, t.cur_tok, TokenIdBitShiftRight); - t.state = TokenizeStateSawGreaterThanGreaterThan; - break; - default: - t.pos -= 1; - end_token(&t); - t.state = TokenizeStateStart; - continue; - } - break; - case TokenizeStateSawGreaterThanGreaterThan: - switch (c) { - case '=': - set_token_id(&t, t.cur_tok, TokenIdBitShiftRightEq); - end_token(&t); - t.state = TokenizeStateStart; - break; - default: - t.pos -= 1; - end_token(&t); - t.state = TokenizeStateStart; - continue; - } - break; - case TokenizeStateSawLessThan: - switch (c) { - case '=': - set_token_id(&t, t.cur_tok, TokenIdCmpLessOrEq); - end_token(&t); - t.state = TokenizeStateStart; - break; - case '<': - set_token_id(&t, t.cur_tok, TokenIdBitShiftLeft); - t.state = TokenizeStateSawLessThanLessThan; - break; - default: - t.pos -= 1; - end_token(&t); - t.state = TokenizeStateStart; - continue; - } - break; - case TokenizeStateSawLessThanLessThan: - switch (c) { - case '=': - set_token_id(&t, t.cur_tok, TokenIdBitShiftLeftEq); - end_token(&t); - t.state = TokenizeStateStart; - break; - default: - t.pos -= 1; - end_token(&t); - t.state = TokenizeStateStart; - continue; - } - break; - case TokenizeStateSawBang: - switch (c) { - case '=': - set_token_id(&t, t.cur_tok, TokenIdCmpNotEq); - end_token(&t); - t.state = TokenizeStateStart; - break; - default: - t.pos -= 1; - end_token(&t); - t.state = TokenizeStateStart; - continue; - } - break; - case TokenizeStateSawEq: - switch (c) { - case '=': - set_token_id(&t, t.cur_tok, TokenIdCmpEq); - end_token(&t); - t.state = TokenizeStateStart; - break; - case '>': - set_token_id(&t, t.cur_tok, TokenIdFatArrow); - end_token(&t); - t.state = TokenizeStateStart; - break; - default: - t.pos -= 1; - end_token(&t); - t.state = TokenizeStateStart; - continue; - } - break; - case TokenizeStateSawStar: - switch (c) { - case '=': - set_token_id(&t, t.cur_tok, TokenIdTimesEq); - end_token(&t); - t.state = TokenizeStateStart; - break; - case '*': - set_token_id(&t, t.cur_tok, TokenIdStarStar); - end_token(&t); - t.state = TokenizeStateStart; - break; - case '%': - set_token_id(&t, t.cur_tok, TokenIdTimesPercent); - t.state = TokenizeStateSawStarPercent; - break; - default: - t.pos -= 1; - end_token(&t); - t.state = TokenizeStateStart; - continue; - } - break; - case TokenizeStateSawStarPercent: - switch (c) { - case '=': - set_token_id(&t, t.cur_tok, TokenIdTimesPercentEq); - end_token(&t); - t.state = TokenizeStateStart; - break; - default: - t.pos -= 1; - end_token(&t); - t.state = TokenizeStateStart; - continue; - } - break; - case TokenizeStateSawPercent: - switch (c) { - case '=': - set_token_id(&t, t.cur_tok, TokenIdModEq); - end_token(&t); - t.state = TokenizeStateStart; - break; - case '.': - set_token_id(&t, t.cur_tok, TokenIdPercentDot); - end_token(&t); - t.state = TokenizeStateStart; - break; - default: - t.pos -= 1; - end_token(&t); - t.state = TokenizeStateStart; - continue; - } - break; - case TokenizeStateSawPlus: - switch (c) { - case '=': - set_token_id(&t, t.cur_tok, TokenIdPlusEq); - end_token(&t); - t.state = TokenizeStateStart; - break; - case '+': - set_token_id(&t, t.cur_tok, TokenIdPlusPlus); - end_token(&t); - t.state = TokenizeStateStart; - break; - case '%': - set_token_id(&t, t.cur_tok, TokenIdPlusPercent); - t.state = TokenizeStateSawPlusPercent; - break; - default: - t.pos -= 1; - end_token(&t); - t.state = TokenizeStateStart; - continue; - } - break; - case TokenizeStateSawPlusPercent: - switch (c) { - case '=': - set_token_id(&t, t.cur_tok, TokenIdPlusPercentEq); - end_token(&t); - t.state = TokenizeStateStart; - break; - default: - t.pos -= 1; - end_token(&t); - t.state = TokenizeStateStart; - continue; - } - break; - case TokenizeStateSawAmpersand: + case TokenizeState_ampersand: switch (c) { + case 0: + goto eof; case '&': tokenize_error(&t, "`&&` is invalid. Note that `and` is boolean AND"); break; case '=': - set_token_id(&t, t.cur_tok, TokenIdBitAndEq); - end_token(&t); - t.state = TokenizeStateStart; + t.out->ids.last() = TokenIdBitAndEq; + t.state = TokenizeState_start; break; default: - t.pos -= 1; - end_token(&t); - t.state = TokenizeStateStart; + t.state = TokenizeState_start; continue; } break; - case TokenizeStateSawCaret: + case TokenizeState_asterisk: switch (c) { + case 0: + goto eof; case '=': - set_token_id(&t, t.cur_tok, TokenIdBitXorEq); - end_token(&t); - t.state = TokenizeStateStart; + t.out->ids.last() = TokenIdTimesEq; + t.state = TokenizeState_start; + break; + case '*': + t.out->ids.last() = TokenIdStarStar; + t.state = TokenizeState_start; + break; + case '%': + t.state = TokenizeState_asterisk_percent; break; default: - t.pos -= 1; - end_token(&t); - t.state = TokenizeStateStart; + t.state = TokenizeState_start; continue; } break; - case TokenizeStateSawBar: + case TokenizeState_asterisk_percent: switch (c) { + case 0: + t.out->ids.last() = TokenIdTimesPercent; + goto eof; case '=': - set_token_id(&t, t.cur_tok, TokenIdBitOrEq); - end_token(&t); - t.state = TokenizeStateStart; - break; - case '|': - set_token_id(&t, t.cur_tok, TokenIdBarBar); - end_token(&t); - t.state = TokenizeStateStart; + t.out->ids.last() = TokenIdTimesPercentEq; + t.state = TokenizeState_start; break; default: - t.pos -= 1; - end_token(&t); - t.state = TokenizeStateStart; + t.out->ids.last() = TokenIdTimesPercent; + t.state = TokenizeState_start; continue; } break; - case TokenizeStateSawSlash: + case TokenizeState_percent: switch (c) { - case '/': - t.state = TokenizeStateSawSlash2; - break; + case 0: + goto eof; case '=': - set_token_id(&t, t.cur_tok, TokenIdDivEq); - end_token(&t); - t.state = TokenizeStateStart; + t.out->ids.last() = TokenIdModEq; + t.state = TokenizeState_start; break; default: - t.pos -= 1; - end_token(&t); - t.state = TokenizeStateStart; + t.state = TokenizeState_start; continue; } break; - case TokenizeStateSawSlash2: + case TokenizeState_plus: switch (c) { - case '/': - t.state = TokenizeStateSawSlash3; + case 0: + goto eof; + case '=': + t.out->ids.last() = TokenIdPlusEq; + t.state = TokenizeState_start; break; - case '!': - t.state = TokenizeStateSawSlashBang; + case '+': + t.out->ids.last() = TokenIdPlusPlus; + t.state = TokenizeState_start; break; - case '\n': - cancel_token(&t); - t.state = TokenizeStateStart; + case '%': + t.state = TokenizeState_plus_percent; break; default: - cancel_token(&t); - t.state = TokenizeStateLineComment; - break; + t.state = TokenizeState_start; + continue; } break; - case TokenizeStateSawSlash3: + case TokenizeState_plus_percent: switch (c) { - case '/': - cancel_token(&t); - t.state = TokenizeStateLineComment; - break; - case '\n': - set_token_id(&t, t.cur_tok, TokenIdDocComment); - end_token(&t); - t.state = TokenizeStateStart; + case 0: + t.out->ids.last() = TokenIdPlusPercent; + goto eof; + case '=': + t.out->ids.last() = TokenIdPlusPercentEq; + t.state = TokenizeState_start; break; default: - set_token_id(&t, t.cur_tok, TokenIdDocComment); - t.state = TokenizeStateDocComment; - break; + t.out->ids.last() = TokenIdPlusPercent; + t.state = TokenizeState_start; + continue; } break; - case TokenizeStateSawSlashBang: + case TokenizeState_caret: switch (c) { - case '\n': - set_token_id(&t, t.cur_tok, TokenIdContainerDocComment); - end_token(&t); - t.state = TokenizeStateStart; + case 0: + goto eof; + case '=': + t.out->ids.last() = TokenIdBitXorEq; + t.state = TokenizeState_start; break; default: - set_token_id(&t, t.cur_tok, TokenIdContainerDocComment); - t.state = TokenizeStateContainerDocComment; - break; + t.state = TokenizeState_start; + continue; } break; - case TokenizeStateSawBackslash: + case TokenizeState_identifier: + switch (c) { + case 0: { + uint32_t start_pos = t.out->locs.last().offset; + t.out->ids.last() = zig_keyword_token( + source + start_pos, t.pos - start_pos); + goto eof; + } + case IDENTIFIER_CHAR: + break; + default: { + uint32_t start_pos = t.out->locs.last().offset; + t.out->ids.last() = zig_keyword_token( + source + start_pos, t.pos - start_pos); + + t.state = TokenizeState_start; + continue; + } + } + break; + case TokenizeState_builtin: + switch (c) { + case 0: + goto eof; + case IDENTIFIER_CHAR: + break; + default: + t.state = TokenizeState_start; + continue; + } + break; + case TokenizeState_backslash: switch (c) { case '\\': - t.state = TokenizeStateLineString; + t.state = TokenizeState_multiline_string_literal_line; break; default: invalid_char_error(&t, c); break; } break; - case TokenizeStateLineString: + case TokenizeState_string_literal: switch (c) { - case '\n': - t.state = TokenizeStateLineStringEnd; - break; - default: - buf_append_char(&t.cur_tok->data.str_lit.str, c); - break; - } - break; - case TokenizeStateLineStringEnd: - switch (c) { - case WHITESPACE: - break; + case 0: + invalid_eof(&t); + goto eof; case '\\': - t.state = TokenizeStateLineStringContinue; + t.state = TokenizeState_string_literal_backslash; break; - default: - t.pos -= 1; - end_token(&t); - t.state = TokenizeStateStart; - continue; - } - break; - case TokenizeStateLineStringContinue: - switch (c) { - case '\\': - t.state = TokenizeStateLineString; - buf_append_char(&t.cur_tok->data.str_lit.str, '\n'); - break; - default: - invalid_char_error(&t, c); - break; - } - break; - case TokenizeStateLineComment: - switch (c) { - case '\n': - t.state = TokenizeStateStart; - break; - default: - // do nothing - break; - } - break; - case TokenizeStateDocComment: - switch (c) { - case '\n': - end_token(&t); - t.state = TokenizeStateStart; - break; - default: - // do nothing - break; - } - break; - case TokenizeStateContainerDocComment: - switch (c) { - case '\n': - end_token(&t); - t.state = TokenizeStateStart; - break; - default: - // do nothing - break; - } - break; - case TokenizeStateSawAtSign: - switch (c) { case '"': - set_token_id(&t, t.cur_tok, TokenIdSymbol); - t.state = TokenizeStateString; - break; - default: - t.pos -= 1; - end_token(&t); - t.state = TokenizeStateStart; - continue; - } - break; - case TokenizeStateSymbol: - switch (c) { - case SYMBOL_CHAR: - buf_append_char(&t.cur_tok->data.str_lit.str, c); - break; - default: - t.pos -= 1; - end_token(&t); - t.state = TokenizeStateStart; - continue; - } - break; - case TokenizeStateString: - switch (c) { - case '"': - end_token(&t); - t.state = TokenizeStateStart; + t.state = TokenizeState_start; break; case '\n': + case '\r': tokenize_error(&t, "newline not allowed in string literal"); break; - case '\\': - t.state = TokenizeStateStringEscape; - break; default: - buf_append_char(&t.cur_tok->data.str_lit.str, c); break; } break; - case TokenizeStateStringEscape: + case TokenizeState_string_literal_backslash: switch (c) { - case 'x': - t.state = TokenizeStateCharCode; - t.radix = 16; - t.char_code = 0; - t.char_code_index = 0; - t.unicode = false; - break; - case 'u': - t.state = TokenizeStateStringEscapeUnicodeStart; - break; - case 'n': - handle_string_escape(&t, '\n'); - break; - case 'r': - handle_string_escape(&t, '\r'); - break; - case '\\': - handle_string_escape(&t, '\\'); - break; - case 't': - handle_string_escape(&t, '\t'); - break; - case '\'': - handle_string_escape(&t, '\''); - break; - case '"': - handle_string_escape(&t, '\"'); + case 0: + invalid_eof(&t); + goto eof; + case '\n': + case '\r': + tokenize_error(&t, "newline not allowed in string literal"); break; default: - invalid_char_error(&t, c); + t.state = TokenizeState_string_literal; + break; } break; - case TokenizeStateStringEscapeUnicodeStart: - switch (c) { - case '{': - t.state = TokenizeStateCharCode; - t.radix = 16; - t.char_code = 0; - t.char_code_index = 0; - t.unicode = true; - break; - default: - invalid_char_error(&t, c); - } - break; - case TokenizeStateCharCode: - { - if (t.unicode && c == '}') { - if (t.char_code_index == 0) { - tokenize_error(&t, "empty unicode escape sequence"); - break; - } - if (t.char_code > 0x10ffff) { - tokenize_error(&t, "unicode value out of range: %x", t.char_code); - break; - } - if (t.cur_tok->id == TokenIdCharLiteral) { - t.cur_tok->data.char_lit.c = t.char_code; - t.state = TokenizeStateCharLiteralEnd; - } else if (t.char_code <= 0x7f) { - // 00000000 00000000 00000000 0xxxxxxx - handle_string_escape(&t, (uint8_t)t.char_code); - } else if (t.char_code <= 0x7ff) { - // 00000000 00000000 00000xxx xx000000 - handle_string_escape(&t, (uint8_t)(0xc0 | (t.char_code >> 6))); - // 00000000 00000000 00000000 00xxxxxx - handle_string_escape(&t, (uint8_t)(0x80 | (t.char_code & 0x3f))); - } else if (t.char_code <= 0xffff) { - // 00000000 00000000 xxxx0000 00000000 - handle_string_escape(&t, (uint8_t)(0xe0 | (t.char_code >> 12))); - // 00000000 00000000 0000xxxx xx000000 - handle_string_escape(&t, (uint8_t)(0x80 | ((t.char_code >> 6) & 0x3f))); - // 00000000 00000000 00000000 00xxxxxx - handle_string_escape(&t, (uint8_t)(0x80 | (t.char_code & 0x3f))); - } else if (t.char_code <= 0x10ffff) { - // 00000000 000xxx00 00000000 00000000 - handle_string_escape(&t, (uint8_t)(0xf0 | (t.char_code >> 18))); - // 00000000 000000xx xxxx0000 00000000 - handle_string_escape(&t, (uint8_t)(0x80 | ((t.char_code >> 12) & 0x3f))); - // 00000000 00000000 0000xxxx xx000000 - handle_string_escape(&t, (uint8_t)(0x80 | ((t.char_code >> 6) & 0x3f))); - // 00000000 00000000 00000000 00xxxxxx - handle_string_escape(&t, (uint8_t)(0x80 | (t.char_code & 0x3f))); - } else { - zig_unreachable(); - } - break; - } - - uint32_t digit_value = get_digit_value(c); - if (digit_value >= t.radix) { - tokenize_error(&t, "invalid digit: '%c'", c); - break; - } - t.char_code *= t.radix; - t.char_code += digit_value; - t.char_code_index += 1; - - if (!t.unicode && t.char_code_index >= 2) { - assert(t.char_code <= 255); - handle_string_escape(&t, (uint8_t)t.char_code); - } - } - break; - case TokenizeStateCharLiteral: - if (c == '\'') { - tokenize_error(&t, "expected character"); + case TokenizeState_char_literal: + if (c == 0) { + invalid_eof(&t); + goto eof; } else if (c == '\\') { - t.state = TokenizeStateStringEscape; + t.state = TokenizeState_char_literal_backslash; + } else if (c == '\'') { + tokenize_error(&t, "expected character"); } else if ((c >= 0x80 && c <= 0xbf) || c >= 0xf8) { // 10xxxxxx // 11111xxx invalid_char_error(&t, c); } else if (c >= 0xc0 && c <= 0xdf) { // 110xxxxx - t.cur_tok->data.char_lit.c = c & 0x1f; - t.remaining_code_units = 1; - t.state = TokenizeStateCharLiteralUnicode; + remaining_code_units = 1; + t.state = TokenizeState_char_literal_unicode; } else if (c >= 0xe0 && c <= 0xef) { // 1110xxxx - t.cur_tok->data.char_lit.c = c & 0x0f; - t.remaining_code_units = 2; - t.state = TokenizeStateCharLiteralUnicode; + remaining_code_units = 2; + t.state = TokenizeState_char_literal_unicode; } else if (c >= 0xf0 && c <= 0xf7) { // 11110xxx - t.cur_tok->data.char_lit.c = c & 0x07; - t.remaining_code_units = 3; - t.state = TokenizeStateCharLiteralUnicode; + remaining_code_units = 3; + t.state = TokenizeState_char_literal_unicode; } else { - t.cur_tok->data.char_lit.c = c; - t.state = TokenizeStateCharLiteralEnd; + t.state = TokenizeState_char_literal_end; } break; - case TokenizeStateCharLiteralEnd: + case TokenizeState_char_literal_backslash: switch (c) { - case '\'': - end_token(&t); - t.state = TokenizeStateStart; - break; - default: - invalid_char_error(&t, c); - } - break; - case TokenizeStateCharLiteralUnicode: - if (c <= 0x7f || c >= 0xc0) { - invalid_char_error(&t, c); - } - t.cur_tok->data.char_lit.c <<= 6; - t.cur_tok->data.char_lit.c += c & 0x3f; - t.remaining_code_units--; - if (t.remaining_code_units == 0) { - t.state = TokenizeStateCharLiteralEnd; - } - break; - case TokenizeStateZero: - switch (c) { - case 'b': - t.radix = 2; - t.state = TokenizeStateNumberNoUnderscore; - break; - case 'o': - t.radix = 8; - t.state = TokenizeStateNumberNoUnderscore; + case 0: + invalid_eof(&t); + goto eof; + case '\n': + case '\r': + tokenize_error(&t, "newline not allowed in character literal"); break; case 'x': - t.radix = 16; - t.state = TokenizeStateNumberNoUnderscore; + t.state = TokenizeState_char_literal_hex_escape; + seen_escape_digits = 0; + break; + case 'u': + t.state = TokenizeState_char_literal_unicode_escape_saw_u; break; default: - // reinterpret as normal number - t.pos -= 1; - t.state = TokenizeStateNumber; - continue; + t.state = TokenizeState_char_literal_end; + break; } break; - case TokenizeStateNumberNoUnderscore: - if (c == '_') { - invalid_char_error(&t, c); - break; - } else if (get_digit_value(c) < t.radix) { - t.is_trailing_underscore = false; - t.state = TokenizeStateNumber; + case TokenizeState_char_literal_hex_escape: + switch (c) { + case ALPHA: + case DIGIT: + seen_escape_digits += 1; + if (seen_escape_digits == 2) { + t.state = TokenizeState_char_literal_end; + } + break; + default: + tokenize_error(&t, "expected hex digit"); + break; } - ZIG_FALLTHROUGH; - case TokenizeStateNumber: - { - if (c == '_') { - t.is_trailing_underscore = true; - t.state = TokenizeStateNumberNoUnderscore; + break; + case TokenizeState_char_literal_unicode_escape_saw_u: + switch (c) { + case '{': + t.state = TokenizeState_char_literal_unicode_escape; + seen_escape_digits = 0; break; - } - if (c == '.') { - if (t.is_trailing_underscore) { - invalid_char_error(&t, c); - break; - } - t.state = TokenizeStateNumberDot; + default: + tokenize_error(&t, "expected '{' to begin unicode escape sequence"); break; - } - if (is_exponent_signifier(c, t.radix)) { - if (t.is_trailing_underscore) { - invalid_char_error(&t, c); - break; - } - if (t.radix != 16 && t.radix != 10) { - invalid_char_error(&t, c); - } - t.state = TokenizeStateFloatExponentUnsigned; - t.radix = 10; // exponent is always base 10 - assert(t.cur_tok->id == TokenIdIntLiteral); - set_token_id(&t, t.cur_tok, TokenIdFloatLiteral); - break; - } - uint32_t digit_value = get_digit_value(c); - if (digit_value >= t.radix) { - if (t.is_trailing_underscore) { - invalid_char_error(&t, c); - break; - } - - if (is_symbol_char(c)) { - invalid_char_error(&t, c); - } - // not my char - t.pos -= 1; - end_token(&t); - t.state = TokenizeStateStart; - continue; - } - BigInt digit_value_bi; - bigint_init_unsigned(&digit_value_bi, digit_value); - - BigInt radix_bi; - bigint_init_unsigned(&radix_bi, t.radix); - - BigInt multiplied; - bigint_mul(&multiplied, &t.cur_tok->data.int_lit.bigint, &radix_bi); - - bigint_add(&t.cur_tok->data.int_lit.bigint, &multiplied, &digit_value_bi); - break; } - case TokenizeStateNumberDot: - { - if (c == '.') { - t.pos -= 2; - end_token(&t); - t.state = TokenizeStateStart; - continue; - } - if (t.radix != 16 && t.radix != 10) { + break; + case TokenizeState_char_literal_unicode_escape: + switch (c) { + case ALPHA: + case DIGIT: + seen_escape_digits += 1; + break; + case '}': + if (seen_escape_digits == 0) { + tokenize_error(&t, "missing unicode escape sequence"); + break; + } + t.state = TokenizeState_char_literal_end; + break; + default: + tokenize_error(&t, "expected hex digit"); + break; + } + break; + case TokenizeState_char_literal_end: + switch (c) { + case '\'': + t.state = TokenizeState_start; + break; + default: invalid_char_error(&t, c); - } - t.pos -= 1; - t.state = TokenizeStateFloatFractionNoUnderscore; - assert(t.cur_tok->id == TokenIdIntLiteral); - set_token_id(&t, t.cur_tok, TokenIdFloatLiteral); - continue; - } - case TokenizeStateFloatFractionNoUnderscore: - if (c == '_') { - invalid_char_error(&t, c); - } else if (get_digit_value(c) < t.radix) { - t.is_trailing_underscore = false; - t.state = TokenizeStateFloatFraction; - } - ZIG_FALLTHROUGH; - case TokenizeStateFloatFraction: - { - if (c == '_') { - t.is_trailing_underscore = true; - t.state = TokenizeStateFloatFractionNoUnderscore; break; - } - if (is_exponent_signifier(c, t.radix)) { - if (t.is_trailing_underscore) { - invalid_char_error(&t, c); - break; - } - t.state = TokenizeStateFloatExponentUnsigned; - t.radix = 10; // exponent is always base 10 - break; - } - uint32_t digit_value = get_digit_value(c); - if (digit_value >= t.radix) { - if (t.is_trailing_underscore) { - invalid_char_error(&t, c); - break; - } - if (is_symbol_char(c)) { - invalid_char_error(&t, c); - } - // not my char - t.pos -= 1; - end_token(&t); - t.state = TokenizeStateStart; - continue; - } - - // we use parse_f128 to generate the float literal, so just - // need to get to the end of the token } break; - case TokenizeStateFloatExponentUnsigned: + case TokenizeState_char_literal_unicode: + if (c >= 0x80 && c <= 0xbf) { + remaining_code_units -= 1; + if (remaining_code_units == 0) { + t.state = TokenizeState_char_literal_end; + } + } else { + invalid_char_error(&t, c); + } + break; + case TokenizeState_multiline_string_literal_line: switch (c) { - case '+': - t.state = TokenizeStateFloatExponentNumberNoUnderscore; - break; - case '-': - t.state = TokenizeStateFloatExponentNumberNoUnderscore; + case 0: + goto eof; + case '\n': + t.state = TokenizeState_start; break; default: - // reinterpret as normal exponent number - t.pos -= 1; - t.state = TokenizeStateFloatExponentNumberNoUnderscore; - continue; - } - break; - case TokenizeStateFloatExponentNumberNoUnderscore: - if (c == '_') { - invalid_char_error(&t, c); - } else if (get_digit_value(c) < t.radix) { - t.is_trailing_underscore = false; - t.state = TokenizeStateFloatExponentNumber; - } - ZIG_FALLTHROUGH; - case TokenizeStateFloatExponentNumber: - { - if (c == '_') { - t.is_trailing_underscore = true; - t.state = TokenizeStateFloatExponentNumberNoUnderscore; break; - } - uint32_t digit_value = get_digit_value(c); - if (digit_value >= t.radix) { - if (t.is_trailing_underscore) { - invalid_char_error(&t, c); - break; - } - if (is_symbol_char(c)) { - invalid_char_error(&t, c); - } - // not my char - t.pos -= 1; - end_token(&t); - t.state = TokenizeStateStart; - continue; - } - - // we use parse_f128 to generate the float literal, so just - // need to get to the end of the token } break; - case TokenizeStateSawDash: + case TokenizeState_bang: switch (c) { + case 0: + goto eof; + case '=': + t.out->ids.last() = TokenIdCmpNotEq; + t.state = TokenizeState_start; + break; + default: + t.state = TokenizeState_start; + continue; + } + break; + case TokenizeState_pipe: + switch (c) { + case 0: + goto eof; + case '=': + t.out->ids.last() = TokenIdBitOrEq; + t.state = TokenizeState_start; + break; + case '|': + t.out->ids.last() = TokenIdBarBar; + t.state = TokenizeState_start; + break; + default: + t.state = TokenizeState_start; + continue; + } + break; + case TokenizeState_equal: + switch (c) { + case 0: + goto eof; + case '=': + t.out->ids.last() = TokenIdCmpEq; + t.state = TokenizeState_start; + break; case '>': - set_token_id(&t, t.cur_tok, TokenIdArrow); - end_token(&t); - t.state = TokenizeStateStart; + t.out->ids.last() = TokenIdFatArrow; + t.state = TokenizeState_start; + break; + default: + t.state = TokenizeState_start; + continue; + } + break; + case TokenizeState_minus: + switch (c) { + case 0: + goto eof; + case '>': + t.out->ids.last() = TokenIdArrow; + t.state = TokenizeState_start; break; case '=': - set_token_id(&t, t.cur_tok, TokenIdMinusEq); - end_token(&t); - t.state = TokenizeStateStart; + t.out->ids.last() = TokenIdMinusEq; + t.state = TokenizeState_start; break; case '%': - set_token_id(&t, t.cur_tok, TokenIdMinusPercent); - t.state = TokenizeStateSawMinusPercent; + t.state = TokenizeState_minus_percent; break; default: - t.pos -= 1; - end_token(&t); - t.state = TokenizeStateStart; + t.state = TokenizeState_start; continue; } break; - case TokenizeStateSawMinusPercent: + case TokenizeState_minus_percent: switch (c) { + case 0: + t.out->ids.last() = TokenIdMinusPercent; + goto eof; case '=': - set_token_id(&t, t.cur_tok, TokenIdMinusPercentEq); - end_token(&t); - t.state = TokenizeStateStart; + t.out->ids.last() = TokenIdMinusPercentEq; + t.state = TokenizeState_start; break; default: + t.out->ids.last() = TokenIdMinusPercent; + t.state = TokenizeState_start; + continue; + } + break; + case TokenizeState_angle_bracket_left: + switch (c) { + case 0: + goto eof; + case '=': + t.out->ids.last() = TokenIdCmpLessOrEq; + t.state = TokenizeState_start; + break; + case '<': + t.state = TokenizeState_angle_bracket_angle_bracket_left; + break; + default: + t.state = TokenizeState_start; + continue; + } + break; + case TokenizeState_angle_bracket_angle_bracket_left: + switch (c) { + case 0: + t.out->ids.last() = TokenIdBitShiftLeft; + goto eof; + case '=': + t.out->ids.last() = TokenIdBitShiftLeftEq; + t.state = TokenizeState_start; + break; + default: + t.out->ids.last() = TokenIdBitShiftLeft; + t.state = TokenizeState_start; + continue; + } + break; + case TokenizeState_angle_bracket_right: + switch (c) { + case 0: + goto eof; + case '=': + t.out->ids.last() = TokenIdCmpGreaterOrEq; + t.state = TokenizeState_start; + break; + case '>': + t.state = TokenizeState_angle_bracket_angle_bracket_right; + break; + default: + t.state = TokenizeState_start; + continue; + } + break; + case TokenizeState_angle_bracket_angle_bracket_right: + switch (c) { + case 0: + t.out->ids.last() = TokenIdBitShiftRight; + goto eof; + case '=': + t.out->ids.last() = TokenIdBitShiftRightEq; + t.state = TokenizeState_start; + break; + default: + t.out->ids.last() = TokenIdBitShiftRight; + t.state = TokenizeState_start; + continue; + } + break; + case TokenizeState_period: + switch (c) { + case 0: + goto eof; + case '.': + t.state = TokenizeState_period_2; + break; + case '*': + t.state = TokenizeState_period_asterisk; + break; + default: + t.state = TokenizeState_start; + continue; + } + break; + case TokenizeState_period_2: + switch (c) { + case 0: + t.out->ids.last() = TokenIdEllipsis2; + goto eof; + case '.': + t.out->ids.last() = TokenIdEllipsis3; + t.state = TokenizeState_start; + break; + default: + t.out->ids.last() = TokenIdEllipsis2; + t.state = TokenizeState_start; + continue; + } + break; + case TokenizeState_period_asterisk: + switch (c) { + case 0: + t.out->ids.last() = TokenIdDotStar; + goto eof; + case '*': + tokenize_error(&t, "`.*` cannot be followed by `*`. Are you missing a space?"); + break; + default: + t.out->ids.last() = TokenIdDotStar; + t.state = TokenizeState_start; + continue; + } + break; + case TokenizeState_slash: + switch (c) { + case 0: + goto eof; + case '/': + t.state = TokenizeState_line_comment_start; + break; + case '=': + t.out->ids.last() = TokenIdDivEq; + t.state = TokenizeState_start; + break; + default: + t.state = TokenizeState_start; + continue; + } + break; + case TokenizeState_line_comment_start: + switch (c) { + case 0: + goto eof; + case '/': + t.state = TokenizeState_doc_comment_start; + break; + case '!': + t.out->ids.last() = TokenIdContainerDocComment; + t.state = TokenizeState_container_doc_comment; + break; + case '\n': + cancel_token(&t); + t.state = TokenizeState_start; + break; + default: + cancel_token(&t); + t.state = TokenizeState_line_comment; + break; + } + break; + case TokenizeState_doc_comment_start: + switch (c) { + case 0: + t.out->ids.last() = TokenIdDocComment; + goto eof; + case '/': + cancel_token(&t); + t.state = TokenizeState_line_comment; + break; + case '\n': + t.out->ids.last() = TokenIdDocComment; + t.state = TokenizeState_start; + break; + default: + t.out->ids.last() = TokenIdDocComment; + t.state = TokenizeState_doc_comment; + break; + } + break; + case TokenizeState_line_comment: + switch (c) { + case 0: + goto eof; + case '\n': + t.state = TokenizeState_start; + break; + default: + break; + } + break; + case TokenizeState_doc_comment: + case TokenizeState_container_doc_comment: + switch (c) { + case 0: + goto eof; + case '\n': + t.state = TokenizeState_start; + break; + default: + // do nothing + break; + } + break; + case TokenizeState_zero: + switch (c) { + case 0: + goto eof; + case 'b': + t.state = TokenizeState_int_literal_bin_no_underscore; + break; + case 'o': + t.state = TokenizeState_int_literal_oct_no_underscore; + break; + case 'x': + t.state = TokenizeState_int_literal_hex_no_underscore; + break; + case DIGIT: + case '_': + case '.': + case 'e': + case 'E': + // Reinterpret as a decimal number. + t.state = TokenizeState_int_literal_dec; + continue; + case ALPHA_EXCEPT_E_B_O_X: + invalid_char_error(&t, c); + break; + default: + t.state = TokenizeState_start; + continue; + } + break; + case TokenizeState_int_literal_bin_no_underscore: + switch (c) { + case '0': + case '1': + t.state = TokenizeState_int_literal_bin; + break; + default: + invalid_char_error(&t, c); + } + break; + case TokenizeState_int_literal_bin: + switch (c) { + case 0: + goto eof; + case '_': + t.state = TokenizeState_int_literal_bin_no_underscore; + break; + case '0': + case '1': + break; + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case ALPHA: + invalid_char_error(&t, c); + break; + default: + t.state = TokenizeState_start; + continue; + } + break; + case TokenizeState_int_literal_oct_no_underscore: + switch (c) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + t.state = TokenizeState_int_literal_oct; + break; + default: + invalid_char_error(&t, c); + break; + } + break; + case TokenizeState_int_literal_oct: + switch (c) { + case 0: + goto eof; + case '_': + t.state = TokenizeState_int_literal_oct_no_underscore; + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + break; + case ALPHA: + case '8': + case '9': + invalid_char_error(&t, c); + break; + default: + t.state = TokenizeState_start; + continue; + } + break; + case TokenizeState_int_literal_dec_no_underscore: + switch (c) { + case DIGIT: + t.state = TokenizeState_int_literal_dec; + break; + default: + invalid_char_error(&t, c); + break; + } + break; + case TokenizeState_int_literal_dec: + switch (c) { + case 0: + goto eof; + case '_': + t.state = TokenizeState_int_literal_dec_no_underscore; + break; + case '.': + t.state = TokenizeState_num_dot_dec; + t.out->ids.last() = TokenIdFloatLiteral; + break; + case 'e': + case 'E': + t.state = TokenizeState_float_exponent_unsigned; + t.out->ids.last() = TokenIdFloatLiteral; + break; + case DIGIT: + break; + case ALPHA_EXCEPT_E: + invalid_char_error(&t, c); + break; + default: + t.state = TokenizeState_start; + continue; + } + break; + case TokenizeState_int_literal_hex_no_underscore: + switch (c) { + case HEXDIGIT: + t.state = TokenizeState_int_literal_hex; + break; + default: + invalid_char_error(&t, c); + } + break; + case TokenizeState_int_literal_hex: + switch (c) { + case 0: + goto eof; + case '_': + t.state = TokenizeState_int_literal_hex_no_underscore; + break; + case '.': + t.state = TokenizeState_num_dot_hex; + t.out->ids.last() = TokenIdFloatLiteral; + break; + case 'p': + case 'P': + t.state = TokenizeState_float_exponent_unsigned; + t.out->ids.last() = TokenIdFloatLiteral; + break; + case HEXDIGIT: + break; + case ALPHA_EXCEPT_HEX_AND_P: + invalid_char_error(&t, c); + break; + default: + t.state = TokenizeState_start; + continue; + } + break; + case TokenizeState_num_dot_dec: + switch (c) { + case 0: + goto eof; + case '.': + t.out->ids.last() = TokenIdIntLiteral; t.pos -= 1; - end_token(&t); - t.state = TokenizeStateStart; + t.column -= 1; + t.state = TokenizeState_start; + continue; + case 'e': + case 'E': + t.state = TokenizeState_float_exponent_unsigned; + break; + case DIGIT: + t.state = TokenizeState_float_fraction_dec; + break; + case ALPHA_EXCEPT_E: + invalid_char_error(&t, c); + break; + default: + t.state = TokenizeState_start; + continue; + } + break; + case TokenizeState_num_dot_hex: + switch (c) { + case 0: + goto eof; + case '.': + t.out->ids.last() = TokenIdIntLiteral; + t.pos -= 1; + t.column -= 1; + t.state = TokenizeState_start; + continue; + case 'p': + case 'P': + t.state = TokenizeState_float_exponent_unsigned; + break; + case HEXDIGIT: + t.out->ids.last() = TokenIdFloatLiteral; + t.state = TokenizeState_float_fraction_hex; + break; + case ALPHA_EXCEPT_HEX_AND_P: + invalid_char_error(&t, c); + break; + default: + t.state = TokenizeState_start; + continue; + } + break; + case TokenizeState_float_fraction_dec_no_underscore: + switch (c) { + case DIGIT: + t.state = TokenizeState_float_fraction_dec; + break; + default: + invalid_char_error(&t, c); + } + break; + case TokenizeState_float_fraction_dec: + switch (c) { + case 0: + goto eof; + case '_': + t.state = TokenizeState_float_fraction_dec_no_underscore; + break; + case 'e': + case 'E': + t.state = TokenizeState_float_exponent_unsigned; + break; + case DIGIT: + break; + case ALPHA_EXCEPT_E: + invalid_char_error(&t, c); + break; + default: + t.state = TokenizeState_start; + continue; + } + break; + case TokenizeState_float_fraction_hex_no_underscore: + switch (c) { + case HEXDIGIT: + t.state = TokenizeState_float_fraction_hex; + break; + default: + invalid_char_error(&t, c); + } + break; + case TokenizeState_float_fraction_hex: + switch (c) { + case 0: + goto eof; + case '_': + t.state = TokenizeState_float_fraction_hex_no_underscore; + break; + case 'p': + case 'P': + t.state = TokenizeState_float_exponent_unsigned; + break; + case HEXDIGIT: + break; + case ALPHA_EXCEPT_HEX_AND_P: + invalid_char_error(&t, c); + break; + default: + t.state = TokenizeState_start; + continue; + } + break; + case TokenizeState_float_exponent_unsigned: + switch (c) { + case '+': + case '-': + t.state = TokenizeState_float_exponent_num_no_underscore; + break; + default: + // Reinterpret as a normal exponent number. + t.state = TokenizeState_float_exponent_num_no_underscore; + continue; + } + break; + case TokenizeState_float_exponent_num_no_underscore: + switch (c) { + case DIGIT: + t.state = TokenizeState_float_exponent_num; + break; + default: + invalid_char_error(&t, c); + } + break; + case TokenizeState_float_exponent_num: + switch (c) { + case 0: + goto eof; + case '_': + t.state = TokenizeState_float_exponent_num_no_underscore; + break; + case DIGIT: + break; + case ALPHA: + invalid_char_error(&t, c); + break; + default: + t.state = TokenizeState_start; continue; } break; } + t.pos += 1; if (c == '\n') { - out->line_offsets->append(t.pos + 1); t.line += 1; t.column = 0; } else { t.column += 1; } } - // EOF - switch (t.state) { - case TokenizeStateStart: - case TokenizeStateError: - break; - case TokenizeStateNumberNoUnderscore: - case TokenizeStateFloatFractionNoUnderscore: - case TokenizeStateFloatExponentNumberNoUnderscore: - case TokenizeStateNumberDot: - tokenize_error(&t, "unterminated number literal"); - break; - case TokenizeStateString: - tokenize_error(&t, "unterminated string"); - break; - case TokenizeStateStringEscape: - case TokenizeStateStringEscapeUnicodeStart: - case TokenizeStateCharCode: - if (t.cur_tok->id == TokenIdStringLiteral) { - tokenize_error(&t, "unterminated string"); - break; - } else if (t.cur_tok->id == TokenIdCharLiteral) { - tokenize_error(&t, "unterminated Unicode code point literal"); - break; - } else { - zig_unreachable(); - } - break; - case TokenizeStateCharLiteral: - case TokenizeStateCharLiteralEnd: - case TokenizeStateCharLiteralUnicode: - tokenize_error(&t, "unterminated Unicode code point literal"); - break; - case TokenizeStateSymbol: - case TokenizeStateZero: - case TokenizeStateNumber: - case TokenizeStateFloatFraction: - case TokenizeStateFloatExponentUnsigned: - case TokenizeStateFloatExponentNumber: - case TokenizeStateSawStar: - case TokenizeStateSawSlash: - case TokenizeStateSawPercent: - case TokenizeStateSawPlus: - case TokenizeStateSawDash: - case TokenizeStateSawAmpersand: - case TokenizeStateSawCaret: - case TokenizeStateSawBar: - case TokenizeStateSawEq: - case TokenizeStateSawBang: - case TokenizeStateSawLessThan: - case TokenizeStateSawLessThanLessThan: - case TokenizeStateSawGreaterThan: - case TokenizeStateSawGreaterThanGreaterThan: - case TokenizeStateSawDot: - case TokenizeStateSawDotStar: - case TokenizeStateSawAtSign: - case TokenizeStateSawStarPercent: - case TokenizeStateSawPlusPercent: - case TokenizeStateSawMinusPercent: - case TokenizeStateLineString: - case TokenizeStateLineStringEnd: - case TokenizeStateDocComment: - case TokenizeStateContainerDocComment: - end_token(&t); - break; - case TokenizeStateSawDotDot: - case TokenizeStateSawBackslash: - case TokenizeStateLineStringContinue: - tokenize_error(&t, "unexpected EOF"); - break; - case TokenizeStateLineComment: - break; - case TokenizeStateSawSlash2: - cancel_token(&t); - break; - case TokenizeStateSawSlash3: - set_token_id(&t, t.cur_tok, TokenIdDocComment); - end_token(&t); - break; - case TokenizeStateSawSlashBang: - set_token_id(&t, t.cur_tok, TokenIdContainerDocComment); - end_token(&t); - break; - } - if (t.state != TokenizeStateError) { - if (t.tokens->length > 0) { - Token *last_token = &t.tokens->last(); - t.line = (int)last_token->start_line; - t.column = (int)last_token->start_column; - t.pos = last_token->start_pos; - } else { - t.pos = 0; - } - begin_token(&t, TokenIdEof); - end_token(&t); - assert(!t.cur_tok); - } +eof:; + + begin_token(&t, TokenIdEof); } const char * token_name(TokenId id) { switch (id) { case TokenIdAmpersand: return "&"; case TokenIdArrow: return "->"; - case TokenIdAtSign: return "@"; case TokenIdBang: return "!"; case TokenIdBarBar: return "||"; case TokenIdBinOr: return "|"; @@ -1622,9 +1533,7 @@ const char * token_name(TokenId id) { case TokenIdMinusPercent: return "-%"; case TokenIdMinusPercentEq: return "-%="; case TokenIdModEq: return "%="; - case TokenIdNumberSign: return "#"; case TokenIdPercent: return "%"; - case TokenIdPercentDot: return "%."; case TokenIdPlus: return "+"; case TokenIdPlusEq: return "+="; case TokenIdPlusPercent: return "+%"; @@ -1638,33 +1547,15 @@ const char * token_name(TokenId id) { case TokenIdStar: return "*"; case TokenIdStarStar: return "**"; case TokenIdStringLiteral: return "StringLiteral"; - case TokenIdMultilineStringLiteral: return "MultilineStringLiteral"; - case TokenIdSymbol: return "Symbol"; + case TokenIdMultilineStringLiteralLine: return "MultilineStringLiteralLine"; + case TokenIdIdentifier: return "Identifier"; case TokenIdTilde: return "~"; case TokenIdTimesEq: return "*="; case TokenIdTimesPercent: return "*%"; case TokenIdTimesPercentEq: return "*%="; + case TokenIdBuiltin: return "Builtin"; case TokenIdCount: zig_unreachable(); } return "(invalid token)"; } - -void print_tokens(Buf *buf, ZigList *tokens) { - for (size_t i = 0; i < tokens->length; i += 1) { - Token *token = &tokens->at(i); - fprintf(stderr, "%s ", token_name(token->id)); - if (token->start_pos != SIZE_MAX) { - fwrite(buf_ptr(buf) + token->start_pos, 1, token->end_pos - token->start_pos, stderr); - } - fprintf(stderr, "\n"); - } -} - -bool valid_symbol_starter(uint8_t c) { - switch (c) { - case SYMBOL_START: - return true; - } - return false; -} diff --git a/src/stage1/tokenizer.hpp b/src/stage1/tokenizer.hpp index 2bb673c8f3..0e196597eb 100644 --- a/src/stage1/tokenizer.hpp +++ b/src/stage1/tokenizer.hpp @@ -12,10 +12,9 @@ #include "bigint.hpp" #include "bigfloat.hpp" -enum TokenId { +enum TokenId : uint8_t { TokenIdAmpersand, TokenIdArrow, - TokenIdAtSign, TokenIdBang, TokenIdBarBar, TokenIdBinOr, @@ -27,6 +26,7 @@ enum TokenId { TokenIdBitShiftRight, TokenIdBitShiftRightEq, TokenIdBitXorEq, + TokenIdBuiltin, TokenIdCharLiteral, TokenIdCmpEq, TokenIdCmpGreaterOrEq, @@ -109,9 +109,7 @@ enum TokenId { TokenIdMinusPercent, TokenIdMinusPercentEq, TokenIdModEq, - TokenIdNumberSign, TokenIdPercent, - TokenIdPercentDot, TokenIdPlus, TokenIdPlusEq, TokenIdPlusPercent, @@ -125,75 +123,35 @@ enum TokenId { TokenIdStar, TokenIdStarStar, TokenIdStringLiteral, - TokenIdMultilineStringLiteral, - TokenIdSymbol, + TokenIdMultilineStringLiteralLine, + TokenIdIdentifier, TokenIdTilde, TokenIdTimesEq, TokenIdTimesPercent, TokenIdTimesPercentEq, + TokenIdCount, }; -struct TokenFloatLit { - BigFloat bigfloat; - // overflow is true if when parsing the number, we discovered it would not fit - // without losing data - bool overflow; +typedef uint32_t TokenIndex; + +struct TokenLoc { + uint32_t offset; + uint32_t line; + uint32_t column; }; -struct TokenIntLit { - BigInt bigint; -}; - -struct TokenStrLit { - Buf str; -}; - -struct TokenCharLit { - uint32_t c; -}; - -struct Token { - TokenId id; - size_t start_pos; - size_t end_pos; - size_t start_line; - size_t start_column; - - union { - // TokenIdIntLiteral - TokenIntLit int_lit; - - // TokenIdFloatLiteral - TokenFloatLit float_lit; - - // TokenIdStringLiteral, TokenIdMultilineStringLiteral or TokenIdSymbol - TokenStrLit str_lit; - - // TokenIdCharLiteral - TokenCharLit char_lit; - } data; -}; -// work around conflicting name Token which is also found in libclang -typedef Token ZigToken; - struct Tokenization { - ZigList *tokens; - ZigList *line_offsets; + ZigList ids; + ZigList locs; // if an error occurred Buf *err; - size_t err_line; - size_t err_column; + uint32_t err_byte_offset; }; -void tokenize(Buf *buf, Tokenization *out_tokenization); - -void print_tokens(Buf *buf, ZigList *tokens); +void tokenize(const char *source, Tokenization *out_tokenization); const char * token_name(TokenId id); -bool valid_symbol_starter(uint8_t c); -bool is_zig_keyword(Buf *buf); - #endif diff --git a/test/behavior/misc.zig b/test/behavior/misc.zig index 0300afcdea..e010644756 100644 --- a/test/behavior/misc.zig +++ b/test/behavior/misc.zig @@ -1,6 +1,7 @@ const std = @import("std"); const expect = std.testing.expect; const expectEqualSlices = std.testing.expectEqualSlices; +const expectEqualStrings = std.testing.expectEqualStrings; const mem = std.mem; const builtin = @import("builtin"); @@ -147,13 +148,13 @@ test "array mult operator" { } test "string escapes" { - try expect(mem.eql(u8, "\"", "\x22")); - try expect(mem.eql(u8, "\'", "\x27")); - try expect(mem.eql(u8, "\n", "\x0a")); - try expect(mem.eql(u8, "\r", "\x0d")); - try expect(mem.eql(u8, "\t", "\x09")); - try expect(mem.eql(u8, "\\", "\x5c")); - try expect(mem.eql(u8, "\u{1234}\u{069}\u{1}", "\xe1\x88\xb4\x69\x01")); + try expectEqualStrings("\"", "\x22"); + try expectEqualStrings("\'", "\x27"); + try expectEqualStrings("\n", "\x0a"); + try expectEqualStrings("\r", "\x0d"); + try expectEqualStrings("\t", "\x09"); + try expectEqualStrings("\\", "\x5c"); + try expectEqualStrings("\u{1234}\u{069}\u{1}", "\xe1\x88\xb4\x69\x01"); } test "multiline string" {