Commit 2a990d6966
Changed files (25)
lib
std
src
test
behavior
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
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<AsmOutput*> output_list;
ZigList<AsmInput*> input_list;
@@ -1094,7 +1097,7 @@ struct AstNodeContainerDecl {
AstNode *init_arg_expr; // enum(T), struct(endianness), or union(T), or union(enum(T))
ZigList<AstNode *> fields;
ZigList<AstNode *> 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<size_t> *line_offsets;
Buf *source_code;
ZigLLVMDIFile *di_file;
+ size_t token_count;
+ TokenId *token_ids;
+ TokenLoc *token_locs;
};
enum StructSpecial {
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<RootStruct>();
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<TokenId>(token_count);
+ memcpy(root_struct->token_ids, tokenization.ids.items, token_count * sizeof(TokenId));
+ root_struct->token_locs = g->pass1_arena->allocate<TokenLoc>(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<ZigValue>();
- 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) {
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);
src/stage1/ast_render.cpp
@@ -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 <stdio.h>
-
-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);
-}
src/stage1/ast_render.hpp
@@ -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 <stdio.h>
-
-void ast_print(FILE *f, AstNode *node, int indent);
-
-void ast_render(FILE *f, AstNode *node, int indent_size);
-
-#endif
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<IrInstSrcReturn *>(inst));
+ case IrInstSrcIdConst:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcConst *>(inst));
+ case IrInstSrcIdBinOp:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcBinOp *>(inst));
+ case IrInstSrcIdMergeErrSets:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcMergeErrSets *>(inst));
+ case IrInstSrcIdDeclVar:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcDeclVar *>(inst));
+ case IrInstSrcIdCall:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcCall *>(inst));
+ case IrInstSrcIdCallExtra:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcCallExtra *>(inst));
+ case IrInstSrcIdAsyncCallExtra:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcAsyncCallExtra *>(inst));
+ case IrInstSrcIdUnOp:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcUnOp *>(inst));
+ case IrInstSrcIdCondBr:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcCondBr *>(inst));
+ case IrInstSrcIdBr:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcBr *>(inst));
+ case IrInstSrcIdPhi:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcPhi *>(inst));
+ case IrInstSrcIdContainerInitList:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcContainerInitList *>(inst));
+ case IrInstSrcIdContainerInitFields:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcContainerInitFields *>(inst));
+ case IrInstSrcIdUnreachable:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcUnreachable *>(inst));
+ case IrInstSrcIdElemPtr:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcElemPtr *>(inst));
+ case IrInstSrcIdVarPtr:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcVarPtr *>(inst));
+ case IrInstSrcIdLoadPtr:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcLoadPtr *>(inst));
+ case IrInstSrcIdStorePtr:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcStorePtr *>(inst));
+ case IrInstSrcIdTypeOf:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcTypeOf *>(inst));
+ case IrInstSrcIdFieldPtr:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcFieldPtr *>(inst));
+ case IrInstSrcIdSetCold:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcSetCold *>(inst));
+ case IrInstSrcIdSetRuntimeSafety:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcSetRuntimeSafety *>(inst));
+ case IrInstSrcIdSetFloatMode:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcSetFloatMode *>(inst));
+ case IrInstSrcIdArrayType:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcArrayType *>(inst));
+ case IrInstSrcIdSliceType:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcSliceType *>(inst));
+ case IrInstSrcIdAnyFrameType:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcAnyFrameType *>(inst));
+ case IrInstSrcIdAsm:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcAsm *>(inst));
+ case IrInstSrcIdSizeOf:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcSizeOf *>(inst));
+ case IrInstSrcIdTestNonNull:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcTestNonNull *>(inst));
+ case IrInstSrcIdOptionalUnwrapPtr:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcOptionalUnwrapPtr *>(inst));
+ case IrInstSrcIdPopCount:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcPopCount *>(inst));
+ case IrInstSrcIdClz:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcClz *>(inst));
+ case IrInstSrcIdCtz:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcCtz *>(inst));
+ case IrInstSrcIdBswap:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcBswap *>(inst));
+ case IrInstSrcIdBitReverse:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcBitReverse *>(inst));
+ case IrInstSrcIdSwitchBr:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcSwitchBr *>(inst));
+ case IrInstSrcIdSwitchVar:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcSwitchVar *>(inst));
+ case IrInstSrcIdSwitchElseVar:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcSwitchElseVar *>(inst));
+ case IrInstSrcIdSwitchTarget:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcSwitchTarget *>(inst));
+ case IrInstSrcIdImport:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcImport *>(inst));
+ case IrInstSrcIdRef:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcRef *>(inst));
+ case IrInstSrcIdCompileErr:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcCompileErr *>(inst));
+ case IrInstSrcIdCompileLog:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcCompileLog *>(inst));
+ case IrInstSrcIdErrName:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcErrName *>(inst));
+ case IrInstSrcIdCImport:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcCImport *>(inst));
+ case IrInstSrcIdCInclude:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcCInclude *>(inst));
+ case IrInstSrcIdCDefine:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcCDefine *>(inst));
+ case IrInstSrcIdCUndef:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcCUndef *>(inst));
+ case IrInstSrcIdEmbedFile:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcEmbedFile *>(inst));
+ case IrInstSrcIdCmpxchg:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcCmpxchg *>(inst));
+ case IrInstSrcIdFence:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcFence *>(inst));
+ case IrInstSrcIdReduce:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcReduce *>(inst));
+ case IrInstSrcIdTruncate:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcTruncate *>(inst));
+ case IrInstSrcIdIntCast:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcIntCast *>(inst));
+ case IrInstSrcIdFloatCast:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcFloatCast *>(inst));
+ case IrInstSrcIdErrSetCast:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcErrSetCast *>(inst));
+ case IrInstSrcIdIntToFloat:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcIntToFloat *>(inst));
+ case IrInstSrcIdFloatToInt:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcFloatToInt *>(inst));
+ case IrInstSrcIdBoolToInt:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcBoolToInt *>(inst));
+ case IrInstSrcIdVectorType:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcVectorType *>(inst));
+ case IrInstSrcIdShuffleVector:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcShuffleVector *>(inst));
+ case IrInstSrcIdSplat:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcSplat *>(inst));
+ case IrInstSrcIdBoolNot:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcBoolNot *>(inst));
+ case IrInstSrcIdMemset:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcMemset *>(inst));
+ case IrInstSrcIdMemcpy:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcMemcpy *>(inst));
+ case IrInstSrcIdSlice:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcSlice *>(inst));
+ case IrInstSrcIdBreakpoint:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcBreakpoint *>(inst));
+ case IrInstSrcIdReturnAddress:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcReturnAddress *>(inst));
+ case IrInstSrcIdFrameAddress:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcFrameAddress *>(inst));
+ case IrInstSrcIdFrameHandle:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcFrameHandle *>(inst));
+ case IrInstSrcIdFrameType:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcFrameType *>(inst));
+ case IrInstSrcIdFrameSize:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcFrameSize *>(inst));
+ case IrInstSrcIdAlignOf:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcAlignOf *>(inst));
+ case IrInstSrcIdOverflowOp:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcOverflowOp *>(inst));
+ case IrInstSrcIdTestErr:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcTestErr *>(inst));
+ case IrInstSrcIdUnwrapErrCode:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcUnwrapErrCode *>(inst));
+ case IrInstSrcIdUnwrapErrPayload:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcUnwrapErrPayload *>(inst));
+ case IrInstSrcIdFnProto:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcFnProto *>(inst));
+ case IrInstSrcIdTestComptime:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcTestComptime *>(inst));
+ case IrInstSrcIdPtrCast:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcPtrCast *>(inst));
+ case IrInstSrcIdBitCast:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcBitCast *>(inst));
+ case IrInstSrcIdPtrToInt:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcPtrToInt *>(inst));
+ case IrInstSrcIdIntToPtr:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcIntToPtr *>(inst));
+ case IrInstSrcIdIntToEnum:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcIntToEnum *>(inst));
+ case IrInstSrcIdIntToErr:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcIntToErr *>(inst));
+ case IrInstSrcIdErrToInt:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcErrToInt *>(inst));
+ case IrInstSrcIdCheckSwitchProngsUnderNo:
+ case IrInstSrcIdCheckSwitchProngsUnderYes:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcCheckSwitchProngs *>(inst));
+ case IrInstSrcIdCheckStatementIsVoid:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcCheckStatementIsVoid *>(inst));
+ case IrInstSrcIdTypeName:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcTypeName *>(inst));
+ case IrInstSrcIdTagName:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcTagName *>(inst));
+ case IrInstSrcIdPtrType:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcPtrType *>(inst));
+ case IrInstSrcIdPtrTypeSimple:
+ case IrInstSrcIdPtrTypeSimpleConst:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcPtrTypeSimple *>(inst));
+ case IrInstSrcIdDeclRef:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcDeclRef *>(inst));
+ case IrInstSrcIdPanic:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcPanic *>(inst));
+ case IrInstSrcIdFieldParentPtr:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcFieldParentPtr *>(inst));
+ case IrInstSrcIdByteOffsetOf:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcByteOffsetOf *>(inst));
+ case IrInstSrcIdBitOffsetOf:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcBitOffsetOf *>(inst));
+ case IrInstSrcIdTypeInfo:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcTypeInfo *>(inst));
+ case IrInstSrcIdType:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcType *>(inst));
+ case IrInstSrcIdHasField:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcHasField *>(inst));
+ case IrInstSrcIdSetEvalBranchQuota:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcSetEvalBranchQuota *>(inst));
+ case IrInstSrcIdAlignCast:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcAlignCast *>(inst));
+ case IrInstSrcIdImplicitCast:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcImplicitCast *>(inst));
+ case IrInstSrcIdResolveResult:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcResolveResult *>(inst));
+ case IrInstSrcIdResetResult:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcResetResult *>(inst));
+ case IrInstSrcIdSetAlignStack:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcSetAlignStack *>(inst));
+ case IrInstSrcIdArgTypeAllowVarFalse:
+ case IrInstSrcIdArgTypeAllowVarTrue:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcArgType *>(inst));
+ case IrInstSrcIdExport:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcExport *>(inst));
+ case IrInstSrcIdExtern:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcExtern *>(inst));
+ case IrInstSrcIdErrorReturnTrace:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcErrorReturnTrace *>(inst));
+ case IrInstSrcIdErrorUnion:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcErrorUnion *>(inst));
+ case IrInstSrcIdAtomicRmw:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcAtomicRmw *>(inst));
+ case IrInstSrcIdSaveErrRetAddr:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcSaveErrRetAddr *>(inst));
+ case IrInstSrcIdAddImplicitReturnType:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcAddImplicitReturnType *>(inst));
+ case IrInstSrcIdFloatOp:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcFloatOp *>(inst));
+ case IrInstSrcIdMulAdd:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcMulAdd *>(inst));
+ case IrInstSrcIdAtomicLoad:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcAtomicLoad *>(inst));
+ case IrInstSrcIdAtomicStore:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcAtomicStore *>(inst));
+ case IrInstSrcIdEnumToInt:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcEnumToInt *>(inst));
+ case IrInstSrcIdCheckRuntimeScope:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcCheckRuntimeScope *>(inst));
+ case IrInstSrcIdHasDecl:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcHasDecl *>(inst));
+ case IrInstSrcIdUndeclaredIdent:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcUndeclaredIdent *>(inst));
+ case IrInstSrcIdAlloca:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcAlloca *>(inst));
+ case IrInstSrcIdEndExpr:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcEndExpr *>(inst));
+ case IrInstSrcIdUnionInitNamedField:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcUnionInitNamedField *>(inst));
+ case IrInstSrcIdSuspendBegin:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcSuspendBegin *>(inst));
+ case IrInstSrcIdSuspendFinish:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcSuspendFinish *>(inst));
+ case IrInstSrcIdResume:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcResume *>(inst));
+ case IrInstSrcIdAwait:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcAwait *>(inst));
+ case IrInstSrcIdSpillBegin:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcSpillBegin *>(inst));
+ case IrInstSrcIdSpillEnd:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcSpillEnd *>(inst));
+ case IrInstSrcIdCallArgs:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcCallArgs *>(inst));
+ case IrInstSrcIdWasmMemorySize:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcWasmMemorySize *>(inst));
+ case IrInstSrcIdWasmMemoryGrow:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcWasmMemoryGrow *>(inst));
+ case IrInstSrcIdSrc:
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcSrc *>(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<IrBasicBlockSrc>();
+ 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<typename T>
+static T *ir_create_instruction(IrBuilderSrc *irb, Scope *scope, AstNode *source_node) {
+ T *special_instruction = heap::c_allocator.create<T>();
+ 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<typename T>
+static T *ir_build_instruction(IrBuilderSrc *irb, Scope *scope, AstNode *source_node) {
+ T *special_instruction = ir_create_instruction<T>(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<IrInstSrcCondBr>(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<IrInstSrcReturn>(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<IrInstSrcConst>(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<IrInstSrcConst>(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<IrInstSrcConst>(irb, scope, source_node);
+ const_instruction->value = irb->codegen->pass1_arena->create<ZigValue>();
+ 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<IrInstSrcConst>(irb, scope, source_node);
+ const_instruction->value = irb->codegen->pass1_arena->create<ZigValue>();
+ 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<IrInstSrcConst>(irb, scope, source_node);
+ const_instruction->value = irb->codegen->pass1_arena->create<ZigValue>();
+ 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<IrInstSrcConst>(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<IrInstSrcConst>(irb, scope, source_node);
+ const_instruction->value = irb->codegen->pass1_arena->create<ZigValue>();
+ 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<IrInstSrcConst>(irb, scope, source_node);
+ const_instruction->value = irb->codegen->pass1_arena->create<ZigValue>();
+ 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<IrInstSrcConst>(irb, scope, source_node);
+ const_instruction->value = irb->codegen->pass1_arena->create<ZigValue>();
+ 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<IrInstSrcConst>(irb, scope, source_node);
+ const_instruction->value = irb->codegen->pass1_arena->create<ZigValue>();
+ 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<IrInstSrcConst>(irb, scope, source_node);
+ const_instruction->value = irb->codegen->pass1_arena->create<ZigValue>();
+ 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<IrInstSrcConst>(irb, scope, source_node);
+ const_instruction->value = irb->codegen->pass1_arena->create<ZigValue>();
+ 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<IrInstSrcBinOp>(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<IrInstSrcMergeErrSets>(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<IrInstSrcVarPtr>(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<IrInstSrcElemPtr>(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<IrInstSrcFieldPtr>(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<IrInstSrcFieldPtr>(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<IrInstSrcHasField>(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<IrInstSrcCallExtra>(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<IrInstSrcAsyncCallExtra>(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<IrInstSrcCallArgs>(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<IrInstSrcCall>(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<IrInstSrcPhi>(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<IrInstSrcBr>(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<IrInstSrcPtrTypeSimple>();
+ 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<IrInstSrcPtrType>(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<IrInstSrcUnOp>(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<IrInstSrcContainerInitList>(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<IrInstSrcContainerInitFields>(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<IrInstSrcUnreachable>(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<IrInstSrcStorePtr>(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<IrInstSrcDeclVar>(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<IrInstSrcExport>(
+ 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<IrInstSrcExtern>(
+ 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<IrInstSrcLoadPtr>(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<IrInstSrcTypeOf>(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<IrInstSrcTypeOf>(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<IrInstSrcSetCold>(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<IrInstSrcSetRuntimeSafety>(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<IrInstSrcSetFloatMode>(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<IrInstSrcArrayType>(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<IrInstSrcAnyFrameType>(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<IrInstSrcSliceType>(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<IrInstSrcAsm>(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<IrInstSrcSizeOf>(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<IrInstSrcTestNonNull>(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<IrInstSrcOptionalUnwrapPtr>(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<IrInstSrcClz>(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<IrInstSrcCtz>(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<IrInstSrcPopCount>(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<IrInstSrcBswap>(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<IrInstSrcBitReverse>(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<IrInstSrcSwitchBr>(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<IrInstSrcSwitchTarget>(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<IrInstSrcSwitchVar>(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<IrInstSrcSwitchElseVar>(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<IrInstSrcImport>(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<IrInstSrcRef>(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<IrInstSrcCompileErr>(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<IrInstSrcCompileLog>(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<IrInstSrcErrName>(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<IrInstSrcCImport>(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<IrInstSrcCInclude>(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<IrInstSrcCDefine>(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<IrInstSrcCUndef>(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<IrInstSrcEmbedFile>(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<IrInstSrcCmpxchg>(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<IrInstSrcFence>(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<IrInstSrcReduce>(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<IrInstSrcTruncate>(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<IrInstSrcIntCast>(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<IrInstSrcFloatCast>(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<IrInstSrcErrSetCast>(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<IrInstSrcIntToFloat>(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<IrInstSrcFloatToInt>(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<IrInstSrcBoolToInt>(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<IrInstSrcVectorType>(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<IrInstSrcShuffleVector>(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<IrInstSrcSplat>(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<IrInstSrcBoolNot>(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<IrInstSrcMemset>(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<IrInstSrcMemcpy>(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<IrInstSrcSlice>(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<IrInstSrcBreakpoint>(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<IrInstSrcReturnAddress>(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<IrInstSrcFrameAddress>(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<IrInstSrcFrameHandle>(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<IrInstSrcFrameType>(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<IrInstSrcFrameSize>(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<IrInstSrcOverflowOp>(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<IrInstSrcFloatOp>(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<IrInstSrcMulAdd>(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<IrInstSrcAlignOf>(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<IrInstSrcTestErr>(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<IrInstSrcUnwrapErrCode>(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<IrInstSrcUnwrapErrPayload>(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<IrInstSrcFnProto>(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<IrInstSrcTestComptime>(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<IrInstSrcPtrCast>(
+ 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<IrInstSrcImplicitCast>(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<IrInstSrcBitCast>(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<IrInstSrcIntToPtr>(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<IrInstSrcPtrToInt>(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<IrInstSrcIntToEnum>(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<IrInstSrcEnumToInt>(
+ 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<IrInstSrcIntToErr>(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<IrInstSrcErrToInt>(
+ 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<IrInstSrcCheckSwitchProngs>();
+ 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<IrInstSrcCheckStatementIsVoid>(
+ 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<IrInstSrcTypeName>(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<IrInstSrcDeclRef>(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<IrInstSrcPanic>(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<IrInstSrcTagName>(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<IrInstSrcFieldParentPtr>(
+ 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<IrInstSrcByteOffsetOf>(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<IrInstSrcBitOffsetOf>(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<IrInstSrcTypeInfo>(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<IrInstSrcType>(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<IrInstSrcSetEvalBranchQuota>(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<IrInstSrcAlignCast>(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<IrInstSrcResolveResult>(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<IrInstSrcResetResult>(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<IrInstSrcSetAlignStack>(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<IrInstSrcArgType>();
+ 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<IrInstSrcErrorReturnTrace>(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<IrInstSrcErrorUnion>(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<IrInstSrcAtomicRmw>(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<IrInstSrcAtomicLoad>(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<IrInstSrcAtomicStore>(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<IrInstSrcSaveErrRetAddr>(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<IrInstSrcAddImplicitReturnType>(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<IrInstSrcHasDecl>(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<IrInstSrcUndeclaredIdent>(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<IrInstSrcCheckRuntimeScope>(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<IrInstSrcUnionInitNamedField>(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<IrInstSrcAlloca>(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<IrInstSrcEndExpr>(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<IrInstSrcSuspendBegin>(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<IrInstSrcSuspendFinish>(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<IrInstSrcAwait>(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<IrInstSrcResume>(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<IrInstSrcSpillBegin>(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<IrInstSrcSpillEnd>(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<IrInstSrcWasmMemorySize>(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<IrInstSrcWasmMemoryGrow>(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<IrInstSrcSrc>(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<ResultLocReturn>();
+ 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<ResultLocReturn>();
+ 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<ZigVar>();
+ 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<ZigValue>();
+
+ 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<TldVar *>(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<ResultLocPeer>();
+ 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<IrInstSrc *> incoming_values = {0};
+ ZigList<IrBasicBlockSrc *> 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<ResultLocPeerParent>();
+ 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<ResultLocReturn>();
+ 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<ResultLocInstruction>();
+ 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<IrInstSrc *>(2);
+ incoming_values[0] = val1;
+ incoming_values[1] = val2;
+ IrBasicBlockSrc **incoming_blocks = heap::c_allocator.allocate<IrBasicBlockSrc *>(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<IrInstSrc *>(2);
+ incoming_values[0] = val1;
+ incoming_values[1] = val2;
+ IrBasicBlockSrc **incoming_blocks = heap::c_allocator.allocate<IrBasicBlockSrc *>(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<ResultLocPeerParent>();
+ 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<IrInstSrc *>(2);
+ incoming_values[0] = null_result;
+ incoming_values[1] = unwrapped_payload;
+ IrBasicBlockSrc **incoming_blocks = heap::c_allocator.allocate<IrBasicBlockSrc *>(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<IrInstSrcConst>(irb, scope, node);
+ const_instruction->value = irb->codegen->pass1_arena->create<ZigValue>();
+ 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<IrInstSrc*>(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<IrInstSrc*>(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<IrInstSrc*>(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<IrInstSrc*>(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<ResultLocBitCast>();
+ 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<IrInstSrc *>(2);
+ incoming_values[0] = then_expr_result;
+ incoming_values[1] = else_expr_result;
+ IrBasicBlockSrc **incoming_blocks = heap::c_allocator.allocate<IrBasicBlockSrc *>(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<ResultLocInstruction>();
+ 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<IrInstSrcContainerInitFieldsField>(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<ResultLocInstruction>();
+ 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<IrInstSrc *>(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<ResultLocInstruction>();
+ 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<ResultLocVar>();
+ 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<ResultLocCast>();
+ 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<IrInstSrc *> incoming_values = {0};
+ ZigList<IrBasicBlockSrc *> 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<IrInstSrc *> incoming_values = {0};
+ ZigList<IrBasicBlockSrc *> 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<IrInstSrc *> incoming_values = {0};
+ ZigList<IrBasicBlockSrc *> 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<IrInstSrc *> incoming_values = {0};
+ ZigList<IrBasicBlockSrc *> 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<IrInstSrc *>(asm_expr->input_list.length);
+ IrInstSrc **output_types = heap::c_allocator.allocate<IrInstSrc *>(asm_expr->output_list.length);
+ ZigVar **output_vars = heap::c_allocator.allocate<ZigVar *>(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<IrInstSrc *>(2);
+ incoming_values[0] = then_expr_result;
+ incoming_values[1] = else_expr_result;
+ IrBasicBlockSrc **incoming_blocks = heap::c_allocator.allocate<IrBasicBlockSrc *>(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<IrInstSrc *>(2);
+ incoming_values[0] = then_expr_result;
+ incoming_values[1] = else_expr_result;
+ IrBasicBlockSrc **incoming_blocks = heap::c_allocator.allocate<IrBasicBlockSrc *>(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<IrBasicBlockSrc *> *incoming_blocks, ZigList<IrInstSrc *> *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<IrInstSrcSwitchBrCase> 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<IrInstSrc *> incoming_values = {0};
+ ZigList<IrBasicBlockSrc *> incoming_blocks = {0};
+ ZigList<IrInstSrcCheckSwitchProngsRange> check_ranges = {0};
+
+ IrInstSrcSwitchElseVar *switch_else_var = nullptr;
+
+ ResultLocPeerParent *peer_parent = heap::c_allocator.create<ResultLocPeerParent>();
+ 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<IrInstSrc *>(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<ScopeRuntime *> 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<IrInstSrc *>(2);
+ incoming_values[0] = err_result;
+ incoming_values[1] = unwrapped_payload;
+ IrBasicBlockSrc **incoming_blocks = heap::c_allocator.allocate<IrBasicBlockSrc *>(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<TldContainer>();
+ 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<ErrorTableEntry *>(err_count);
+
+ size_t errors_count = irb->codegen->errors_by_index.length + err_count;
+ ErrorTableEntry **errors = heap::c_allocator.allocate<ErrorTableEntry *>(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<ErrorTableEntry>();
+ 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<IrInstSrc*>(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<ResultLocNone>();
+ 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<ResultLocReturn>();
+ 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);
+}
+
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
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;
}
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);
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");
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;
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<ErrorMsg>();
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<size_t> *line_offsets, Buf *msg)
-{
- ErrorMsg *err_msg = heap::c_allocator.create<ErrorMsg>();
- 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;
}
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<size_t> *line_offsets, Buf *msg);
+ErrorMsg *err_msg_create_with_offset(Buf *path, uint32_t byte_offset, const char *source, Buf *msg);
#endif
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)";
}
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 <errno.h>
#include <math.h>
-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<IrInstSrcReturn *>(inst));
- case IrInstSrcIdConst:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcConst *>(inst));
- case IrInstSrcIdBinOp:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcBinOp *>(inst));
- case IrInstSrcIdMergeErrSets:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcMergeErrSets *>(inst));
- case IrInstSrcIdDeclVar:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcDeclVar *>(inst));
- case IrInstSrcIdCall:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcCall *>(inst));
- case IrInstSrcIdCallExtra:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcCallExtra *>(inst));
- case IrInstSrcIdAsyncCallExtra:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcAsyncCallExtra *>(inst));
- case IrInstSrcIdUnOp:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcUnOp *>(inst));
- case IrInstSrcIdCondBr:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcCondBr *>(inst));
- case IrInstSrcIdBr:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcBr *>(inst));
- case IrInstSrcIdPhi:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcPhi *>(inst));
- case IrInstSrcIdContainerInitList:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcContainerInitList *>(inst));
- case IrInstSrcIdContainerInitFields:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcContainerInitFields *>(inst));
- case IrInstSrcIdUnreachable:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcUnreachable *>(inst));
- case IrInstSrcIdElemPtr:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcElemPtr *>(inst));
- case IrInstSrcIdVarPtr:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcVarPtr *>(inst));
- case IrInstSrcIdLoadPtr:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcLoadPtr *>(inst));
- case IrInstSrcIdStorePtr:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcStorePtr *>(inst));
- case IrInstSrcIdTypeOf:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcTypeOf *>(inst));
- case IrInstSrcIdFieldPtr:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcFieldPtr *>(inst));
- case IrInstSrcIdSetCold:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcSetCold *>(inst));
- case IrInstSrcIdSetRuntimeSafety:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcSetRuntimeSafety *>(inst));
- case IrInstSrcIdSetFloatMode:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcSetFloatMode *>(inst));
- case IrInstSrcIdArrayType:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcArrayType *>(inst));
- case IrInstSrcIdSliceType:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcSliceType *>(inst));
- case IrInstSrcIdAnyFrameType:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcAnyFrameType *>(inst));
- case IrInstSrcIdAsm:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcAsm *>(inst));
- case IrInstSrcIdSizeOf:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcSizeOf *>(inst));
- case IrInstSrcIdTestNonNull:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcTestNonNull *>(inst));
- case IrInstSrcIdOptionalUnwrapPtr:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcOptionalUnwrapPtr *>(inst));
- case IrInstSrcIdPopCount:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcPopCount *>(inst));
- case IrInstSrcIdClz:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcClz *>(inst));
- case IrInstSrcIdCtz:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcCtz *>(inst));
- case IrInstSrcIdBswap:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcBswap *>(inst));
- case IrInstSrcIdBitReverse:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcBitReverse *>(inst));
- case IrInstSrcIdSwitchBr:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcSwitchBr *>(inst));
- case IrInstSrcIdSwitchVar:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcSwitchVar *>(inst));
- case IrInstSrcIdSwitchElseVar:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcSwitchElseVar *>(inst));
- case IrInstSrcIdSwitchTarget:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcSwitchTarget *>(inst));
- case IrInstSrcIdImport:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcImport *>(inst));
- case IrInstSrcIdRef:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcRef *>(inst));
- case IrInstSrcIdCompileErr:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcCompileErr *>(inst));
- case IrInstSrcIdCompileLog:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcCompileLog *>(inst));
- case IrInstSrcIdErrName:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcErrName *>(inst));
- case IrInstSrcIdCImport:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcCImport *>(inst));
- case IrInstSrcIdCInclude:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcCInclude *>(inst));
- case IrInstSrcIdCDefine:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcCDefine *>(inst));
- case IrInstSrcIdCUndef:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcCUndef *>(inst));
- case IrInstSrcIdEmbedFile:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcEmbedFile *>(inst));
- case IrInstSrcIdCmpxchg:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcCmpxchg *>(inst));
- case IrInstSrcIdFence:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcFence *>(inst));
- case IrInstSrcIdReduce:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcReduce *>(inst));
- case IrInstSrcIdTruncate:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcTruncate *>(inst));
- case IrInstSrcIdIntCast:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcIntCast *>(inst));
- case IrInstSrcIdFloatCast:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcFloatCast *>(inst));
- case IrInstSrcIdErrSetCast:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcErrSetCast *>(inst));
- case IrInstSrcIdIntToFloat:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcIntToFloat *>(inst));
- case IrInstSrcIdFloatToInt:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcFloatToInt *>(inst));
- case IrInstSrcIdBoolToInt:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcBoolToInt *>(inst));
- case IrInstSrcIdVectorType:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcVectorType *>(inst));
- case IrInstSrcIdShuffleVector:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcShuffleVector *>(inst));
- case IrInstSrcIdSplat:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcSplat *>(inst));
- case IrInstSrcIdBoolNot:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcBoolNot *>(inst));
- case IrInstSrcIdMemset:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcMemset *>(inst));
- case IrInstSrcIdMemcpy:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcMemcpy *>(inst));
- case IrInstSrcIdSlice:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcSlice *>(inst));
- case IrInstSrcIdBreakpoint:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcBreakpoint *>(inst));
- case IrInstSrcIdReturnAddress:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcReturnAddress *>(inst));
- case IrInstSrcIdFrameAddress:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcFrameAddress *>(inst));
- case IrInstSrcIdFrameHandle:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcFrameHandle *>(inst));
- case IrInstSrcIdFrameType:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcFrameType *>(inst));
- case IrInstSrcIdFrameSize:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcFrameSize *>(inst));
- case IrInstSrcIdAlignOf:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcAlignOf *>(inst));
- case IrInstSrcIdOverflowOp:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcOverflowOp *>(inst));
- case IrInstSrcIdTestErr:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcTestErr *>(inst));
- case IrInstSrcIdUnwrapErrCode:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcUnwrapErrCode *>(inst));
- case IrInstSrcIdUnwrapErrPayload:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcUnwrapErrPayload *>(inst));
- case IrInstSrcIdFnProto:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcFnProto *>(inst));
- case IrInstSrcIdTestComptime:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcTestComptime *>(inst));
- case IrInstSrcIdPtrCast:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcPtrCast *>(inst));
- case IrInstSrcIdBitCast:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcBitCast *>(inst));
- case IrInstSrcIdPtrToInt:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcPtrToInt *>(inst));
- case IrInstSrcIdIntToPtr:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcIntToPtr *>(inst));
- case IrInstSrcIdIntToEnum:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcIntToEnum *>(inst));
- case IrInstSrcIdIntToErr:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcIntToErr *>(inst));
- case IrInstSrcIdErrToInt:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcErrToInt *>(inst));
- case IrInstSrcIdCheckSwitchProngsUnderNo:
- case IrInstSrcIdCheckSwitchProngsUnderYes:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcCheckSwitchProngs *>(inst));
- case IrInstSrcIdCheckStatementIsVoid:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcCheckStatementIsVoid *>(inst));
- case IrInstSrcIdTypeName:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcTypeName *>(inst));
- case IrInstSrcIdTagName:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcTagName *>(inst));
- case IrInstSrcIdPtrType:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcPtrType *>(inst));
- case IrInstSrcIdPtrTypeSimple:
- case IrInstSrcIdPtrTypeSimpleConst:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcPtrTypeSimple *>(inst));
- case IrInstSrcIdDeclRef:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcDeclRef *>(inst));
- case IrInstSrcIdPanic:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcPanic *>(inst));
- case IrInstSrcIdFieldParentPtr:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcFieldParentPtr *>(inst));
- case IrInstSrcIdByteOffsetOf:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcByteOffsetOf *>(inst));
- case IrInstSrcIdBitOffsetOf:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcBitOffsetOf *>(inst));
- case IrInstSrcIdTypeInfo:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcTypeInfo *>(inst));
- case IrInstSrcIdType:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcType *>(inst));
- case IrInstSrcIdHasField:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcHasField *>(inst));
- case IrInstSrcIdSetEvalBranchQuota:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcSetEvalBranchQuota *>(inst));
- case IrInstSrcIdAlignCast:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcAlignCast *>(inst));
- case IrInstSrcIdImplicitCast:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcImplicitCast *>(inst));
- case IrInstSrcIdResolveResult:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcResolveResult *>(inst));
- case IrInstSrcIdResetResult:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcResetResult *>(inst));
- case IrInstSrcIdSetAlignStack:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcSetAlignStack *>(inst));
- case IrInstSrcIdArgTypeAllowVarFalse:
- case IrInstSrcIdArgTypeAllowVarTrue:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcArgType *>(inst));
- case IrInstSrcIdExport:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcExport *>(inst));
- case IrInstSrcIdExtern:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcExtern *>(inst));
- case IrInstSrcIdErrorReturnTrace:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcErrorReturnTrace *>(inst));
- case IrInstSrcIdErrorUnion:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcErrorUnion *>(inst));
- case IrInstSrcIdAtomicRmw:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcAtomicRmw *>(inst));
- case IrInstSrcIdSaveErrRetAddr:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcSaveErrRetAddr *>(inst));
- case IrInstSrcIdAddImplicitReturnType:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcAddImplicitReturnType *>(inst));
- case IrInstSrcIdFloatOp:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcFloatOp *>(inst));
- case IrInstSrcIdMulAdd:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcMulAdd *>(inst));
- case IrInstSrcIdAtomicLoad:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcAtomicLoad *>(inst));
- case IrInstSrcIdAtomicStore:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcAtomicStore *>(inst));
- case IrInstSrcIdEnumToInt:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcEnumToInt *>(inst));
- case IrInstSrcIdCheckRuntimeScope:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcCheckRuntimeScope *>(inst));
- case IrInstSrcIdHasDecl:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcHasDecl *>(inst));
- case IrInstSrcIdUndeclaredIdent:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcUndeclaredIdent *>(inst));
- case IrInstSrcIdAlloca:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcAlloca *>(inst));
- case IrInstSrcIdEndExpr:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcEndExpr *>(inst));
- case IrInstSrcIdUnionInitNamedField:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcUnionInitNamedField *>(inst));
- case IrInstSrcIdSuspendBegin:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcSuspendBegin *>(inst));
- case IrInstSrcIdSuspendFinish:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcSuspendFinish *>(inst));
- case IrInstSrcIdResume:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcResume *>(inst));
- case IrInstSrcIdAwait:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcAwait *>(inst));
- case IrInstSrcIdSpillBegin:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcSpillBegin *>(inst));
- case IrInstSrcIdSpillEnd:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcSpillEnd *>(inst));
- case IrInstSrcIdCallArgs:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcCallArgs *>(inst));
- case IrInstSrcIdWasmMemorySize:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcWasmMemorySize *>(inst));
- case IrInstSrcIdWasmMemoryGrow:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcWasmMemoryGrow *>(inst));
- case IrInstSrcIdSrc:
- return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcSrc *>(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<IrBasicBlockSrc>();
- 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<IrBasicBlockGen>();
result->scope = scope;
@@ -1115,8807 +743,1687 @@ static IrBasicBlockGen *ir_build_bb_from(IrAnalyze *ira, IrBasicBlockSrc *other_
return new_bb;
}
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcDeclVar *) {
- return IrInstSrcIdDeclVar;
+static constexpr IrInstGenId ir_inst_id(IrInstGenDeclVar *) {
+ return IrInstGenIdDeclVar;
}
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcBr *) {
- return IrInstSrcIdBr;
+static constexpr IrInstGenId ir_inst_id(IrInstGenBr *) {
+ return IrInstGenIdBr;
}
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcCondBr *) {
- return IrInstSrcIdCondBr;
+static constexpr IrInstGenId ir_inst_id(IrInstGenCondBr *) {
+ return IrInstGenIdCondBr;
}
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcSwitchBr *) {
- return IrInstSrcIdSwitchBr;
+static constexpr IrInstGenId ir_inst_id(IrInstGenSwitchBr *) {
+ return IrInstGenIdSwitchBr;
}
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcSwitchVar *) {
- return IrInstSrcIdSwitchVar;
+static constexpr IrInstGenId ir_inst_id(IrInstGenPhi *) {
+ return IrInstGenIdPhi;
}
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcSwitchElseVar *) {
- return IrInstSrcIdSwitchElseVar;
+static constexpr IrInstGenId ir_inst_id(IrInstGenBinaryNot *) {
+ return IrInstGenIdBinaryNot;
}
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcSwitchTarget *) {
- return IrInstSrcIdSwitchTarget;
+static constexpr IrInstGenId ir_inst_id(IrInstGenNegation *) {
+ return IrInstGenIdNegation;
}
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcPhi *) {
- return IrInstSrcIdPhi;
+static constexpr IrInstGenId ir_inst_id(IrInstGenBinOp *) {
+ return IrInstGenIdBinOp;
}
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcUnOp *) {
- return IrInstSrcIdUnOp;
+static constexpr IrInstGenId ir_inst_id(IrInstGenLoadPtr *) {
+ return IrInstGenIdLoadPtr;
}
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcBinOp *) {
- return IrInstSrcIdBinOp;
+static constexpr IrInstGenId ir_inst_id(IrInstGenStorePtr *) {
+ return IrInstGenIdStorePtr;
}
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcMergeErrSets *) {
- return IrInstSrcIdMergeErrSets;
+static constexpr IrInstGenId ir_inst_id(IrInstGenVectorStoreElem *) {
+ return IrInstGenIdVectorStoreElem;
}
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcLoadPtr *) {
- return IrInstSrcIdLoadPtr;
+static constexpr IrInstGenId ir_inst_id(IrInstGenStructFieldPtr *) {
+ return IrInstGenIdStructFieldPtr;
}
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcStorePtr *) {
- return IrInstSrcIdStorePtr;
+static constexpr IrInstGenId ir_inst_id(IrInstGenUnionFieldPtr *) {
+ return IrInstGenIdUnionFieldPtr;
}
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcFieldPtr *) {
- return IrInstSrcIdFieldPtr;
+static constexpr IrInstGenId ir_inst_id(IrInstGenElemPtr *) {
+ return IrInstGenIdElemPtr;
}
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcElemPtr *) {
- return IrInstSrcIdElemPtr;
+static constexpr IrInstGenId ir_inst_id(IrInstGenVarPtr *) {
+ return IrInstGenIdVarPtr;
}
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcVarPtr *) {
- return IrInstSrcIdVarPtr;
+static constexpr IrInstGenId ir_inst_id(IrInstGenReturnPtr *) {
+ return IrInstGenIdReturnPtr;
}
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcCall *) {
- return IrInstSrcIdCall;
+static constexpr IrInstGenId ir_inst_id(IrInstGenCall *) {
+ return IrInstGenIdCall;
}
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcCallArgs *) {
- return IrInstSrcIdCallArgs;
+static constexpr IrInstGenId ir_inst_id(IrInstGenReturn *) {
+ return IrInstGenIdReturn;
}
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcCallExtra *) {
- return IrInstSrcIdCallExtra;
+static constexpr IrInstGenId ir_inst_id(IrInstGenCast *) {
+ return IrInstGenIdCast;
}
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcAsyncCallExtra *) {
- return IrInstSrcIdAsyncCallExtra;
+static constexpr IrInstGenId ir_inst_id(IrInstGenUnreachable *) {
+ return IrInstGenIdUnreachable;
}
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcConst *) {
- return IrInstSrcIdConst;
+static constexpr IrInstGenId ir_inst_id(IrInstGenAsm *) {
+ return IrInstGenIdAsm;
}
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcReturn *) {
- return IrInstSrcIdReturn;
+static constexpr IrInstGenId ir_inst_id(IrInstGenTestNonNull *) {
+ return IrInstGenIdTestNonNull;
}
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcContainerInitList *) {
- return IrInstSrcIdContainerInitList;
+static constexpr IrInstGenId ir_inst_id(IrInstGenOptionalUnwrapPtr *) {
+ return IrInstGenIdOptionalUnwrapPtr;
}
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcContainerInitFields *) {
- return IrInstSrcIdContainerInitFields;
+static constexpr IrInstGenId ir_inst_id(IrInstGenOptionalWrap *) {
+ return IrInstGenIdOptionalWrap;
}
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcUnreachable *) {
- return IrInstSrcIdUnreachable;
+static constexpr IrInstGenId ir_inst_id(IrInstGenUnionTag *) {
+ return IrInstGenIdUnionTag;
}
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcTypeOf *) {
- return IrInstSrcIdTypeOf;
+static constexpr IrInstGenId ir_inst_id(IrInstGenClz *) {
+ return IrInstGenIdClz;
}
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcSetCold *) {
- return IrInstSrcIdSetCold;
+static constexpr IrInstGenId ir_inst_id(IrInstGenCtz *) {
+ return IrInstGenIdCtz;
}
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcSetRuntimeSafety *) {
- return IrInstSrcIdSetRuntimeSafety;
+static constexpr IrInstGenId ir_inst_id(IrInstGenPopCount *) {
+ return IrInstGenIdPopCount;
}
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcSetFloatMode *) {
- return IrInstSrcIdSetFloatMode;
+static constexpr IrInstGenId ir_inst_id(IrInstGenBswap *) {
+ return IrInstGenIdBswap;
}
-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 IrInstGenId ir_inst_id(IrInstGenBitReverse *) {
+ return IrInstGenIdBitReverse;
}
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcSizeOf *) {
- return IrInstSrcIdSizeOf;
+static constexpr IrInstGenId ir_inst_id(IrInstGenRef *) {
+ return IrInstGenIdRef;
}
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcTestNonNull *) {
- return IrInstSrcIdTestNonNull;
+static constexpr IrInstGenId ir_inst_id(IrInstGenErrName *) {
+ return IrInstGenIdErrName;
}
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcOptionalUnwrapPtr *) {
- return IrInstSrcIdOptionalUnwrapPtr;
+static constexpr IrInstGenId ir_inst_id(IrInstGenCmpxchg *) {
+ return IrInstGenIdCmpxchg;
}
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcClz *) {
- return IrInstSrcIdClz;
+static constexpr IrInstGenId ir_inst_id(IrInstGenFence *) {
+ return IrInstGenIdFence;
}
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcCtz *) {
- return IrInstSrcIdCtz;
+static constexpr IrInstGenId ir_inst_id(IrInstGenReduce *) {
+ return IrInstGenIdReduce;
}
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcPopCount *) {
- return IrInstSrcIdPopCount;
+static constexpr IrInstGenId ir_inst_id(IrInstGenTruncate *) {
+ return IrInstGenIdTruncate;
}
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcBswap *) {
- return IrInstSrcIdBswap;
+static constexpr IrInstGenId ir_inst_id(IrInstGenShuffleVector *) {
+ return IrInstGenIdShuffleVector;
}
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcBitReverse *) {
- return IrInstSrcIdBitReverse;
+static constexpr IrInstGenId ir_inst_id(IrInstGenSplat *) {
+ return IrInstGenIdSplat;
}
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcImport *) {
- return IrInstSrcIdImport;
+static constexpr IrInstGenId ir_inst_id(IrInstGenBoolNot *) {
+ return IrInstGenIdBoolNot;
}
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcCImport *) {
- return IrInstSrcIdCImport;
+static constexpr IrInstGenId ir_inst_id(IrInstGenMemset *) {
+ return IrInstGenIdMemset;
}
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcCInclude *) {
- return IrInstSrcIdCInclude;
+static constexpr IrInstGenId ir_inst_id(IrInstGenMemcpy *) {
+ return IrInstGenIdMemcpy;
}
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcCDefine *) {
- return IrInstSrcIdCDefine;
+static constexpr IrInstGenId ir_inst_id(IrInstGenSlice *) {
+ return IrInstGenIdSlice;
}
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcCUndef *) {
- return IrInstSrcIdCUndef;
+static constexpr IrInstGenId ir_inst_id(IrInstGenBreakpoint *) {
+ return IrInstGenIdBreakpoint;
}
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcRef *) {
- return IrInstSrcIdRef;
+static constexpr IrInstGenId ir_inst_id(IrInstGenReturnAddress *) {
+ return IrInstGenIdReturnAddress;
}
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcCompileErr *) {
- return IrInstSrcIdCompileErr;
+static constexpr IrInstGenId ir_inst_id(IrInstGenFrameAddress *) {
+ return IrInstGenIdFrameAddress;
}
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcCompileLog *) {
- return IrInstSrcIdCompileLog;
+static constexpr IrInstGenId ir_inst_id(IrInstGenFrameHandle *) {
+ return IrInstGenIdFrameHandle;
}
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcErrName *) {
- return IrInstSrcIdErrName;
+static constexpr IrInstGenId ir_inst_id(IrInstGenFrameSize *) {
+ return IrInstGenIdFrameSize;
}
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcEmbedFile *) {
- return IrInstSrcIdEmbedFile;
+static constexpr IrInstGenId ir_inst_id(IrInstGenOverflowOp *) {
+ return IrInstGenIdOverflowOp;
}
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcCmpxchg *) {
- return IrInstSrcIdCmpxchg;
+static constexpr IrInstGenId ir_inst_id(IrInstGenTestErr *) {
+ return IrInstGenIdTestErr;
}
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcFence *) {
- return IrInstSrcIdFence;
+static constexpr IrInstGenId ir_inst_id(IrInstGenMulAdd *) {
+ return IrInstGenIdMulAdd;
}
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcReduce *) {
- return IrInstSrcIdReduce;
+static constexpr IrInstGenId ir_inst_id(IrInstGenFloatOp *) {
+ return IrInstGenIdFloatOp;
}
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcTruncate *) {
- return IrInstSrcIdTruncate;
+static constexpr IrInstGenId ir_inst_id(IrInstGenUnwrapErrCode *) {
+ return IrInstGenIdUnwrapErrCode;
}
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcIntCast *) {
- return IrInstSrcIdIntCast;
+static constexpr IrInstGenId ir_inst_id(IrInstGenUnwrapErrPayload *) {
+ return IrInstGenIdUnwrapErrPayload;
}
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcFloatCast *) {
- return IrInstSrcIdFloatCast;
+static constexpr IrInstGenId ir_inst_id(IrInstGenErrWrapCode *) {
+ return IrInstGenIdErrWrapCode;
}
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcIntToFloat *) {
- return IrInstSrcIdIntToFloat;
+static constexpr IrInstGenId ir_inst_id(IrInstGenErrWrapPayload *) {
+ return IrInstGenIdErrWrapPayload;
}
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcFloatToInt *) {
- return IrInstSrcIdFloatToInt;
+static constexpr IrInstGenId ir_inst_id(IrInstGenPtrCast *) {
+ return IrInstGenIdPtrCast;
}
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcBoolToInt *) {
- return IrInstSrcIdBoolToInt;
+static constexpr IrInstGenId ir_inst_id(IrInstGenBitCast *) {
+ return IrInstGenIdBitCast;
}
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcVectorType *) {
- return IrInstSrcIdVectorType;
+static constexpr IrInstGenId ir_inst_id(IrInstGenWidenOrShorten *) {
+ return IrInstGenIdWidenOrShorten;
}
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcShuffleVector *) {
- return IrInstSrcIdShuffleVector;
+static constexpr IrInstGenId ir_inst_id(IrInstGenIntToPtr *) {
+ return IrInstGenIdIntToPtr;
}
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcSplat *) {
- return IrInstSrcIdSplat;
+static constexpr IrInstGenId ir_inst_id(IrInstGenPtrToInt *) {
+ return IrInstGenIdPtrToInt;
}
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcBoolNot *) {
- return IrInstSrcIdBoolNot;
+static constexpr IrInstGenId ir_inst_id(IrInstGenIntToEnum *) {
+ return IrInstGenIdIntToEnum;
}
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcMemset *) {
- return IrInstSrcIdMemset;
+static constexpr IrInstGenId ir_inst_id(IrInstGenIntToErr *) {
+ return IrInstGenIdIntToErr;
}
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcMemcpy *) {
- return IrInstSrcIdMemcpy;
+static constexpr IrInstGenId ir_inst_id(IrInstGenErrToInt *) {
+ return IrInstGenIdErrToInt;
}
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcSlice *) {
- return IrInstSrcIdSlice;
+static constexpr IrInstGenId ir_inst_id(IrInstGenPanic *) {
+ return IrInstGenIdPanic;
}
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcBreakpoint *) {
- return IrInstSrcIdBreakpoint;
+static constexpr IrInstGenId ir_inst_id(IrInstGenTagName *) {
+ return IrInstGenIdTagName;
}
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcReturnAddress *) {
- return IrInstSrcIdReturnAddress;
+static constexpr IrInstGenId ir_inst_id(IrInstGenFieldParentPtr *) {
+ return IrInstGenIdFieldParentPtr;
}
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcFrameAddress *) {
- return IrInstSrcIdFrameAddress;
+static constexpr IrInstGenId ir_inst_id(IrInstGenAlignCast *) {
+ return IrInstGenIdAlignCast;
}
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcFrameHandle *) {
- return IrInstSrcIdFrameHandle;
+static constexpr IrInstGenId ir_inst_id(IrInstGenErrorReturnTrace *) {
+ return IrInstGenIdErrorReturnTrace;
}
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcFrameType *) {
- return IrInstSrcIdFrameType;
+static constexpr IrInstGenId ir_inst_id(IrInstGenAtomicRmw *) {
+ return IrInstGenIdAtomicRmw;
}
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcFrameSize *) {
- return IrInstSrcIdFrameSize;
+static constexpr IrInstGenId ir_inst_id(IrInstGenAtomicLoad *) {
+ return IrInstGenIdAtomicLoad;
}
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcAlignOf *) {
- return IrInstSrcIdAlignOf;
+static constexpr IrInstGenId ir_inst_id(IrInstGenAtomicStore *) {
+ return IrInstGenIdAtomicStore;
}
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcOverflowOp *) {
- return IrInstSrcIdOverflowOp;
+static constexpr IrInstGenId ir_inst_id(IrInstGenSaveErrRetAddr *) {
+ return IrInstGenIdSaveErrRetAddr;
}
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcTestErr *) {
- return IrInstSrcIdTestErr;
+static constexpr IrInstGenId ir_inst_id(IrInstGenVectorToArray *) {
+ return IrInstGenIdVectorToArray;
}
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcMulAdd *) {
- return IrInstSrcIdMulAdd;
+static constexpr IrInstGenId ir_inst_id(IrInstGenArrayToVector *) {
+ return IrInstGenIdArrayToVector;
}
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcFloatOp *) {
- return IrInstSrcIdFloatOp;
+static constexpr IrInstGenId ir_inst_id(IrInstGenAssertZero *) {
+ return IrInstGenIdAssertZero;
}
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcUnwrapErrCode *) {
- return IrInstSrcIdUnwrapErrCode;
+static constexpr IrInstGenId ir_inst_id(IrInstGenAssertNonNull *) {
+ return IrInstGenIdAssertNonNull;
}
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcUnwrapErrPayload *) {
- return IrInstSrcIdUnwrapErrPayload;
+static constexpr IrInstGenId ir_inst_id(IrInstGenPtrOfArrayToSlice *) {
+ return IrInstGenIdPtrOfArrayToSlice;
}
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcFnProto *) {
- return IrInstSrcIdFnProto;
+static constexpr IrInstGenId ir_inst_id(IrInstGenSuspendBegin *) {
+ return IrInstGenIdSuspendBegin;
}
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcTestComptime *) {
- return IrInstSrcIdTestComptime;
+static constexpr IrInstGenId ir_inst_id(IrInstGenSuspendFinish *) {
+ return IrInstGenIdSuspendFinish;
}
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcPtrCast *) {
- return IrInstSrcIdPtrCast;
+static constexpr IrInstGenId ir_inst_id(IrInstGenAwait *) {
+ return IrInstGenIdAwait;
}
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcBitCast *) {
- return IrInstSrcIdBitCast;
+static constexpr IrInstGenId ir_inst_id(IrInstGenResume *) {
+ return IrInstGenIdResume;
}
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcIntToPtr *) {
- return IrInstSrcIdIntToPtr;
+static constexpr IrInstGenId ir_inst_id(IrInstGenSpillBegin *) {
+ return IrInstGenIdSpillBegin;
}
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcPtrToInt *) {
- return IrInstSrcIdPtrToInt;
+static constexpr IrInstGenId ir_inst_id(IrInstGenSpillEnd *) {
+ return IrInstGenIdSpillEnd;
}
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcIntToEnum *) {
- return IrInstSrcIdIntToEnum;
+static constexpr IrInstGenId ir_inst_id(IrInstGenVectorExtractElem *) {
+ return IrInstGenIdVectorExtractElem;
}
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcEnumToInt *) {
- return IrInstSrcIdEnumToInt;
+static constexpr IrInstGenId ir_inst_id(IrInstGenAlloca *) {
+ return IrInstGenIdAlloca;
}
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcIntToErr *) {
- return IrInstSrcIdIntToErr;
+static constexpr IrInstGenId ir_inst_id(IrInstGenConst *) {
+ return IrInstGenIdConst;
}
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcErrToInt *) {
- return IrInstSrcIdErrToInt;
+static constexpr IrInstGenId ir_inst_id(IrInstGenWasmMemorySize *) {
+ return IrInstGenIdWasmMemorySize;
}
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcCheckStatementIsVoid *) {
- return IrInstSrcIdCheckStatementIsVoid;
+static constexpr IrInstGenId ir_inst_id(IrInstGenWasmMemoryGrow *) {
+ return IrInstGenIdWasmMemoryGrow;
}
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcTypeName *) {
- return IrInstSrcIdTypeName;
+static constexpr IrInstGenId ir_inst_id(IrInstGenExtern *) {
+ return IrInstGenIdExtern;
}
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcDeclRef *) {
- return IrInstSrcIdDeclRef;
+template<typename T>
+static T *ir_create_inst_gen(IrBuilderGen *irb, Scope *scope, AstNode *source_node) {
+ T *special_instruction = heap::c_allocator.create<T>();
+ 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_gen(irb->exec);
+ special_instruction->base.owner_bb = irb->current_basic_block;
+ special_instruction->base.value = irb->codegen->pass1_arena->create<ZigValue>();
+ return special_instruction;
}
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcPanic *) {
- return IrInstSrcIdPanic;
+template<typename T>
+static T *ir_create_inst_noval(IrBuilderGen *irb, Scope *scope, AstNode *source_node) {
+ T *special_instruction = heap::c_allocator.create<T>();
+ 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_gen(irb->exec);
+ special_instruction->base.owner_bb = irb->current_basic_block;
+ return special_instruction;
}
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcTagName *) {
- return IrInstSrcIdTagName;
+template<typename T>
+static T *ir_build_inst_gen(IrBuilderGen *irb, Scope *scope, AstNode *source_node) {
+ T *special_instruction = ir_create_inst_gen<T>(irb, scope, source_node);
+ ir_inst_gen_append(irb->current_basic_block, &special_instruction->base);
+ return special_instruction;
}
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcFieldParentPtr *) {
- return IrInstSrcIdFieldParentPtr;
+template<typename T>
+static T *ir_build_inst_noreturn(IrBuilderGen *irb, Scope *scope, AstNode *source_node) {
+ T *special_instruction = ir_create_inst_noval<T>(irb, scope, source_node);
+ special_instruction->base.value = irb->codegen->intern.for_unreachable();
+ ir_inst_gen_append(irb->current_basic_block, &special_instruction->base);
+ return special_instruction;
}
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcByteOffsetOf *) {
- return IrInstSrcIdByteOffsetOf;
+template<typename T>
+static T *ir_build_inst_void(IrBuilderGen *irb, Scope *scope, AstNode *source_node) {
+ T *special_instruction = ir_create_inst_noval<T>(irb, scope, source_node);
+ special_instruction->base.value = irb->codegen->intern.for_void();
+ ir_inst_gen_append(irb->current_basic_block, &special_instruction->base);
+ return special_instruction;
}
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcBitOffsetOf *) {
- return IrInstSrcIdBitOffsetOf;
+IrInstGen *ir_create_alloca(CodeGen *g, Scope *scope, AstNode *source_node, ZigFn *fn,
+ ZigType *var_type, const char *name_hint)
+{
+ IrInstGenAlloca *alloca_gen = heap::c_allocator.create<IrInstGenAlloca>();
+ alloca_gen->base.id = IrInstGenIdAlloca;
+ alloca_gen->base.base.source_node = source_node;
+ alloca_gen->base.base.scope = scope;
+ alloca_gen->base.value = g->pass1_arena->create<ZigValue>();
+ alloca_gen->base.value->type = get_pointer_to_type(g, var_type, false);
+ alloca_gen->base.base.ref_count = 1;
+ alloca_gen->name_hint = name_hint;
+ fn->alloca_gen_list.append(alloca_gen);
+ return &alloca_gen->base;
}
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcTypeInfo *) {
- return IrInstSrcIdTypeInfo;
-}
+static IrInstGen *ir_build_cast(IrAnalyze *ira, IrInst *source_instr,ZigType *dest_type,
+ IrInstGen *value, CastOp cast_op)
+{
+ IrInstGenCast *inst = ir_build_inst_gen<IrInstGenCast>(&ira->new_irb, source_instr->scope, source_instr->source_node);
+ inst->base.value->type = dest_type;
+ inst->value = value;
+ inst->cast_op = cast_op;
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcType *) {
- return IrInstSrcIdType;
-}
+ ir_ref_inst_gen(value);
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcHasField *) {
- return IrInstSrcIdHasField;
+ return &inst->base;
}
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcSetEvalBranchQuota *) {
- return IrInstSrcIdSetEvalBranchQuota;
-}
+static IrInstGen *ir_build_cond_br_gen(IrAnalyze *ira, IrInst *source_instr, IrInstGen *condition,
+ IrBasicBlockGen *then_block, IrBasicBlockGen *else_block)
+{
+ IrInstGenCondBr *inst = ir_build_inst_noreturn<IrInstGenCondBr>(&ira->new_irb, source_instr->scope, source_instr->source_node);
+ inst->condition = condition;
+ inst->then_block = then_block;
+ inst->else_block = else_block;
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcPtrType *) {
- return IrInstSrcIdPtrType;
-}
+ ir_ref_inst_gen(condition);
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcAlignCast *) {
- return IrInstSrcIdAlignCast;
+ return &inst->base;
}
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcImplicitCast *) {
- return IrInstSrcIdImplicitCast;
-}
+static IrInstGen *ir_build_return_gen(IrAnalyze *ira, IrInst *source_inst, IrInstGen *operand) {
+ IrInstGenReturn *inst = ir_build_inst_noreturn<IrInstGenReturn>(&ira->new_irb,
+ source_inst->scope, source_inst->source_node);
+ inst->operand = operand;
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcResolveResult *) {
- return IrInstSrcIdResolveResult;
-}
+ if (operand != nullptr) ir_ref_inst_gen(operand);
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcResetResult *) {
- return IrInstSrcIdResetResult;
+ return &inst->base;
}
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcSetAlignStack *) {
- return IrInstSrcIdSetAlignStack;
-}
+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)
+{
+ IrInstGenBinOp *inst = ir_build_inst_gen<IrInstGenBinOp>(&ira->new_irb,
+ source_instr->scope, source_instr->source_node);
+ inst->base.value->type = res_type;
+ inst->op_id = op_id;
+ inst->op1 = op1;
+ inst->op2 = op2;
+ inst->safety_check_on = safety_check_on;
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcExport *) {
- return IrInstSrcIdExport;
-}
+ ir_ref_inst_gen(op1);
+ ir_ref_inst_gen(op2);
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcExtern *) {
- return IrInstSrcIdExtern;
+ return &inst->base;
}
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcErrorReturnTrace *) {
- return IrInstSrcIdErrorReturnTrace;
-}
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcErrorUnion *) {
- return IrInstSrcIdErrorUnion;
-}
+static IrInstGen *ir_build_var_ptr_gen(IrAnalyze *ira, IrInst *source_instr, ZigVar *var) {
+ IrInstGenVarPtr *instruction = ir_build_inst_gen<IrInstGenVarPtr>(&ira->new_irb, source_instr->scope, source_instr->source_node);
+ instruction->var = var;
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcAtomicRmw *) {
- return IrInstSrcIdAtomicRmw;
-}
+ var->ref_count += 1;
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcAtomicLoad *) {
- return IrInstSrcIdAtomicLoad;
+ return &instruction->base;
}
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcAtomicStore *) {
- return IrInstSrcIdAtomicStore;
+static IrInstGen *ir_build_return_ptr(IrAnalyze *ira, Scope *scope, AstNode *source_node, ZigType *ty) {
+ IrInstGenReturnPtr *instruction = ir_build_inst_gen<IrInstGenReturnPtr>(&ira->new_irb, scope, source_node);
+ instruction->base.value->type = ty;
+ return &instruction->base;
}
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcSaveErrRetAddr *) {
- return IrInstSrcIdSaveErrRetAddr;
-}
+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)
+{
+ IrInstGenElemPtr *instruction = ir_build_inst_gen<IrInstGenElemPtr>(&ira->new_irb, scope, source_node);
+ instruction->base.value->type = return_type;
+ instruction->array_ptr = array_ptr;
+ instruction->elem_index = elem_index;
+ instruction->safety_check_on = safety_check_on;
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcAddImplicitReturnType *) {
- return IrInstSrcIdAddImplicitReturnType;
-}
+ ir_ref_inst_gen(array_ptr);
+ ir_ref_inst_gen(elem_index);
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcErrSetCast *) {
- return IrInstSrcIdErrSetCast;
+ return &instruction->base;
}
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcCheckRuntimeScope *) {
- return IrInstSrcIdCheckRuntimeScope;
-}
+static IrInstGen *ir_build_struct_field_ptr(IrAnalyze *ira, IrInst *source_instr,
+ IrInstGen *struct_ptr, TypeStructField *field, ZigType *ptr_type)
+{
+ IrInstGenStructFieldPtr *inst = ir_build_inst_gen<IrInstGenStructFieldPtr>(&ira->new_irb, source_instr->scope, source_instr->source_node);
+ inst->base.value->type = ptr_type;
+ inst->struct_ptr = struct_ptr;
+ inst->field = field;
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcHasDecl *) {
- return IrInstSrcIdHasDecl;
-}
+ ir_ref_inst_gen(struct_ptr);
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcUndeclaredIdent *) {
- return IrInstSrcIdUndeclaredIdent;
+ return &inst->base;
}
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcAlloca *) {
- return IrInstSrcIdAlloca;
-}
+static IrInstGen *ir_build_union_field_ptr(IrAnalyze *ira, IrInst *source_instr,
+ IrInstGen *union_ptr, TypeUnionField *field, bool safety_check_on, bool initializing, ZigType *ptr_type)
+{
+ IrInstGenUnionFieldPtr *inst = ir_build_inst_gen<IrInstGenUnionFieldPtr>(&ira->new_irb,
+ source_instr->scope, source_instr->source_node);
+ inst->base.value->type = ptr_type;
+ inst->initializing = initializing;
+ inst->safety_check_on = safety_check_on;
+ inst->union_ptr = union_ptr;
+ inst->field = field;
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcEndExpr *) {
- return IrInstSrcIdEndExpr;
-}
+ ir_ref_inst_gen(union_ptr);
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcUnionInitNamedField *) {
- return IrInstSrcIdUnionInitNamedField;
+ return &inst->base;
}
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcSuspendBegin *) {
- return IrInstSrcIdSuspendBegin;
-}
+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,
+ IrInstGen *result_loc, ZigType *return_type)
+{
+ IrInstGenCall *call_instruction = ir_build_inst_gen<IrInstGenCall>(&ira->new_irb,
+ source_instruction->scope, source_instruction->source_node);
+ call_instruction->base.value->type = return_type;
+ 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;
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcSuspendFinish *) {
- return IrInstSrcIdSuspendFinish;
-}
+ if (fn_ref != nullptr) ir_ref_inst_gen(fn_ref);
+ for (size_t i = 0; i < arg_count; i += 1)
+ ir_ref_inst_gen(args[i]);
+ if (new_stack != nullptr) ir_ref_inst_gen(new_stack);
+ if (result_loc != nullptr) ir_ref_inst_gen(result_loc);
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcAwait *) {
- return IrInstSrcIdAwait;
+ return call_instruction;
}
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcResume *) {
- return IrInstSrcIdResume;
-}
+static IrInstGen *ir_build_phi_gen(IrAnalyze *ira, IrInst *source_instr, size_t incoming_count,
+ IrBasicBlockGen **incoming_blocks, IrInstGen **incoming_values, ZigType *result_type)
+{
+ assert(incoming_count != 0);
+ assert(incoming_count != SIZE_MAX);
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcSpillBegin *) {
- return IrInstSrcIdSpillBegin;
-}
+ IrInstGenPhi *phi_instruction = ir_build_inst_gen<IrInstGenPhi>(&ira->new_irb,
+ source_instr->scope, source_instr->source_node);
+ phi_instruction->base.value->type = result_type;
+ phi_instruction->incoming_count = incoming_count;
+ phi_instruction->incoming_blocks = incoming_blocks;
+ phi_instruction->incoming_values = incoming_values;
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcSpillEnd *) {
- return IrInstSrcIdSpillEnd;
-}
+ for (size_t i = 0; i < incoming_count; i += 1) {
+ ir_ref_inst_gen(incoming_values[i]);
+ }
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcWasmMemorySize *) {
- return IrInstSrcIdWasmMemorySize;
+ return &phi_instruction->base;
}
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcWasmMemoryGrow *) {
- return IrInstSrcIdWasmMemoryGrow;
-}
+static IrInstGen *ir_build_br_gen(IrAnalyze *ira, IrInst *source_instr, IrBasicBlockGen *dest_block) {
+ IrInstGenBr *inst = ir_build_inst_noreturn<IrInstGenBr>(&ira->new_irb, source_instr->scope, source_instr->source_node);
+ inst->dest_block = dest_block;
-static constexpr IrInstSrcId ir_inst_id(IrInstSrcSrc *) {
- return IrInstSrcIdSrc;
+ return &inst->base;
}
-static constexpr IrInstGenId ir_inst_id(IrInstGenDeclVar *) {
- return IrInstGenIdDeclVar;
-}
+static IrInstGen *ir_build_negation(IrAnalyze *ira, IrInst *source_instr, IrInstGen *operand, ZigType *expr_type, bool wrapping) {
+ IrInstGenNegation *instruction = ir_build_inst_gen<IrInstGenNegation>(&ira->new_irb,
+ source_instr->scope, source_instr->source_node);
+ instruction->base.value->type = expr_type;
+ instruction->operand = operand;
+ instruction->wrapping = wrapping;
-static constexpr IrInstGenId ir_inst_id(IrInstGenBr *) {
- return IrInstGenIdBr;
-}
+ ir_ref_inst_gen(operand);
-static constexpr IrInstGenId ir_inst_id(IrInstGenCondBr *) {
- return IrInstGenIdCondBr;
+ return &instruction->base;
}
-static constexpr IrInstGenId ir_inst_id(IrInstGenSwitchBr *) {
- return IrInstGenIdSwitchBr;
-}
+static IrInstGen *ir_build_binary_not(IrAnalyze *ira, IrInst *source_instr, IrInstGen *operand,
+ ZigType *expr_type)
+{
+ IrInstGenBinaryNot *instruction = ir_build_inst_gen<IrInstGenBinaryNot>(&ira->new_irb,
+ source_instr->scope, source_instr->source_node);
+ instruction->base.value->type = expr_type;
+ instruction->operand = operand;
-static constexpr IrInstGenId ir_inst_id(IrInstGenPhi *) {
- return IrInstGenIdPhi;
-}
+ ir_ref_inst_gen(operand);
-static constexpr IrInstGenId ir_inst_id(IrInstGenBinaryNot *) {
- return IrInstGenIdBinaryNot;
+ return &instruction->base;
}
-static constexpr IrInstGenId ir_inst_id(IrInstGenNegation *) {
- return IrInstGenIdNegation;
+static IrInstGen *ir_build_unreachable_gen(IrAnalyze *ira, IrInst *source_instr) {
+ IrInstGenUnreachable *inst = ir_build_inst_noreturn<IrInstGenUnreachable>(&ira->new_irb, source_instr->scope, source_instr->source_node);
+ return &inst->base;
}
-static constexpr IrInstGenId ir_inst_id(IrInstGenBinOp *) {
- return IrInstGenIdBinOp;
-}
+static IrInstGen *ir_build_store_ptr_gen(IrAnalyze *ira, IrInst *source_instr, IrInstGen *ptr, IrInstGen *value) {
+ IrInstGenStorePtr *instruction = ir_build_inst_void<IrInstGenStorePtr>(&ira->new_irb,
+ source_instr->scope, source_instr->source_node);
+ instruction->ptr = ptr;
+ instruction->value = value;
-static constexpr IrInstGenId ir_inst_id(IrInstGenLoadPtr *) {
- return IrInstGenIdLoadPtr;
-}
+ ir_ref_inst_gen(ptr);
+ ir_ref_inst_gen(value);
-static constexpr IrInstGenId ir_inst_id(IrInstGenStorePtr *) {
- return IrInstGenIdStorePtr;
+ return &instruction->base;
}
-static constexpr IrInstGenId ir_inst_id(IrInstGenVectorStoreElem *) {
- return IrInstGenIdVectorStoreElem;
-}
+static IrInstGen *ir_build_vector_store_elem(IrAnalyze *ira, IrInst *src_inst,
+ IrInstGen *vector_ptr, IrInstGen *index, IrInstGen *value)
+{
+ IrInstGenVectorStoreElem *inst = ir_build_inst_void<IrInstGenVectorStoreElem>(
+ &ira->new_irb, src_inst->scope, src_inst->source_node);
+ inst->vector_ptr = vector_ptr;
+ inst->index = index;
+ inst->value = value;
-static constexpr IrInstGenId ir_inst_id(IrInstGenStructFieldPtr *) {
- return IrInstGenIdStructFieldPtr;
-}
+ ir_ref_inst_gen(vector_ptr);
+ ir_ref_inst_gen(index);
+ ir_ref_inst_gen(value);
-static constexpr IrInstGenId ir_inst_id(IrInstGenUnionFieldPtr *) {
- return IrInstGenIdUnionFieldPtr;
+ return &inst->base;
}
-static constexpr IrInstGenId ir_inst_id(IrInstGenElemPtr *) {
- return IrInstGenIdElemPtr;
-}
+static IrInstGen *ir_build_var_decl_gen(IrAnalyze *ira, IrInst *source_instruction,
+ ZigVar *var, IrInstGen *var_ptr)
+{
+ IrInstGenDeclVar *inst = ir_build_inst_gen<IrInstGenDeclVar>(&ira->new_irb,
+ source_instruction->scope, source_instruction->source_node);
+ inst->base.value->special = ConstValSpecialStatic;
+ inst->base.value->type = ira->codegen->builtin_types.entry_void;
+ inst->var = var;
+ inst->var_ptr = var_ptr;
-static constexpr IrInstGenId ir_inst_id(IrInstGenVarPtr *) {
- return IrInstGenIdVarPtr;
-}
+ ir_ref_inst_gen(var_ptr);
-static constexpr IrInstGenId ir_inst_id(IrInstGenReturnPtr *) {
- return IrInstGenIdReturnPtr;
+ return &inst->base;
}
-static constexpr IrInstGenId ir_inst_id(IrInstGenCall *) {
- return IrInstGenIdCall;
-}
+static IrInstGen *ir_build_extern_gen(IrAnalyze *ira, IrInst *source_instr, Buf *name,
+ GlobalLinkageId linkage, bool is_thread_local, ZigType *expr_type)
+{
+ IrInstGenExtern *instruction = ir_build_inst_gen<IrInstGenExtern>(&ira->new_irb,
+ source_instr->scope, source_instr->source_node);
+ instruction->base.value->type = expr_type;
+ instruction->name = name;
+ instruction->linkage = linkage;
+ instruction->is_thread_local = is_thread_local;
-static constexpr IrInstGenId ir_inst_id(IrInstGenReturn *) {
- return IrInstGenIdReturn;
+ return &instruction->base;
}
-static constexpr IrInstGenId ir_inst_id(IrInstGenCast *) {
- return IrInstGenIdCast;
-}
+static IrInstGen *ir_build_load_ptr_gen(IrAnalyze *ira, IrInst *source_instruction,
+ IrInstGen *ptr, ZigType *ty, IrInstGen *result_loc)
+{
+ IrInstGenLoadPtr *instruction = ir_build_inst_gen<IrInstGenLoadPtr>(
+ &ira->new_irb, source_instruction->scope, source_instruction->source_node);
+ instruction->base.value->type = ty;
+ instruction->ptr = ptr;
+ instruction->result_loc = result_loc;
-static constexpr IrInstGenId ir_inst_id(IrInstGenUnreachable *) {
- return IrInstGenIdUnreachable;
-}
+ ir_ref_inst_gen(ptr);
+ if (result_loc != nullptr) ir_ref_inst_gen(result_loc);
-static constexpr IrInstGenId ir_inst_id(IrInstGenAsm *) {
- return IrInstGenIdAsm;
+ return &instruction->base;
}
-static constexpr IrInstGenId ir_inst_id(IrInstGenTestNonNull *) {
- return IrInstGenIdTestNonNull;
-}
+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,
+ bool has_side_effects, ZigType *return_type)
+{
+ IrInstGenAsm *instruction = ir_build_inst_gen<IrInstGenAsm>(&ira->new_irb, source_instr->scope, source_instr->source_node);
+ instruction->base.value->type = return_type;
+ instruction->asm_template = asm_template;
+ instruction->token_list = token_list;
+ instruction->token_list_len = token_list_len;
+ 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;
-static constexpr IrInstGenId ir_inst_id(IrInstGenOptionalUnwrapPtr *) {
- return IrInstGenIdOptionalUnwrapPtr;
-}
+ assert(source_instr->source_node->type == NodeTypeAsmExpr);
+ for (size_t i = 0; i < source_instr->source_node->data.asm_expr.output_list.length; i += 1) {
+ IrInstGen *output_type = output_types[i];
+ if (output_type) ir_ref_inst_gen(output_type);
+ }
-static constexpr IrInstGenId ir_inst_id(IrInstGenOptionalWrap *) {
- return IrInstGenIdOptionalWrap;
-}
+ for (size_t i = 0; i < source_instr->source_node->data.asm_expr.input_list.length; i += 1) {
+ IrInstGen *input_value = input_list[i];
+ ir_ref_inst_gen(input_value);
+ }
-static constexpr IrInstGenId ir_inst_id(IrInstGenUnionTag *) {
- return IrInstGenIdUnionTag;
+ return &instruction->base;
}
-static constexpr IrInstGenId ir_inst_id(IrInstGenClz *) {
- return IrInstGenIdClz;
-}
+static IrInstGen *ir_build_test_non_null_gen(IrAnalyze *ira, IrInst *source_instr, IrInstGen *value) {
+ IrInstGenTestNonNull *inst = ir_build_inst_gen<IrInstGenTestNonNull>(&ira->new_irb,
+ source_instr->scope, source_instr->source_node);
+ inst->base.value->type = ira->codegen->builtin_types.entry_bool;
+ inst->value = value;
-static constexpr IrInstGenId ir_inst_id(IrInstGenCtz *) {
- return IrInstGenIdCtz;
-}
+ ir_ref_inst_gen(value);
-static constexpr IrInstGenId ir_inst_id(IrInstGenPopCount *) {
- return IrInstGenIdPopCount;
+ return &inst->base;
}
-static constexpr IrInstGenId ir_inst_id(IrInstGenBswap *) {
- return IrInstGenIdBswap;
-}
+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)
+{
+ IrInstGenOptionalUnwrapPtr *inst = ir_build_inst_gen<IrInstGenOptionalUnwrapPtr>(&ira->new_irb,
+ source_instr->scope, source_instr->source_node);
+ inst->base.value->type = result_type;
+ inst->base_ptr = base_ptr;
+ inst->safety_check_on = safety_check_on;
+ inst->initializing = initializing;
-static constexpr IrInstGenId ir_inst_id(IrInstGenBitReverse *) {
- return IrInstGenIdBitReverse;
+ ir_ref_inst_gen(base_ptr);
+
+ return &inst->base;
}
-static constexpr IrInstGenId ir_inst_id(IrInstGenRef *) {
- return IrInstGenIdRef;
-}
+static IrInstGen *ir_build_optional_wrap(IrAnalyze *ira, IrInst *source_instruction, ZigType *result_ty,
+ IrInstGen *operand, IrInstGen *result_loc)
+{
+ IrInstGenOptionalWrap *instruction = ir_build_inst_gen<IrInstGenOptionalWrap>(
+ &ira->new_irb, source_instruction->scope, source_instruction->source_node);
+ instruction->base.value->type = result_ty;
+ instruction->operand = operand;
+ instruction->result_loc = result_loc;
-static constexpr IrInstGenId ir_inst_id(IrInstGenErrName *) {
- return IrInstGenIdErrName;
-}
+ ir_ref_inst_gen(operand);
+ if (result_loc != nullptr) ir_ref_inst_gen(result_loc);
-static constexpr IrInstGenId ir_inst_id(IrInstGenCmpxchg *) {
- return IrInstGenIdCmpxchg;
+ return &instruction->base;
}
-static constexpr IrInstGenId ir_inst_id(IrInstGenFence *) {
- return IrInstGenIdFence;
-}
+static IrInstGen *ir_build_err_wrap_payload(IrAnalyze *ira, IrInst *source_instruction,
+ ZigType *result_type, IrInstGen *operand, IrInstGen *result_loc)
+{
+ IrInstGenErrWrapPayload *instruction = ir_build_inst_gen<IrInstGenErrWrapPayload>(
+ &ira->new_irb, source_instruction->scope, source_instruction->source_node);
+ instruction->base.value->type = result_type;
+ instruction->operand = operand;
+ instruction->result_loc = result_loc;
-static constexpr IrInstGenId ir_inst_id(IrInstGenReduce *) {
- return IrInstGenIdReduce;
-}
+ ir_ref_inst_gen(operand);
+ if (result_loc != nullptr) ir_ref_inst_gen(result_loc);
-static constexpr IrInstGenId ir_inst_id(IrInstGenTruncate *) {
- return IrInstGenIdTruncate;
+ return &instruction->base;
}
-static constexpr IrInstGenId ir_inst_id(IrInstGenShuffleVector *) {
- return IrInstGenIdShuffleVector;
-}
+static IrInstGen *ir_build_err_wrap_code(IrAnalyze *ira, IrInst *source_instruction,
+ ZigType *result_type, IrInstGen *operand, IrInstGen *result_loc)
+{
+ IrInstGenErrWrapCode *instruction = ir_build_inst_gen<IrInstGenErrWrapCode>(
+ &ira->new_irb, source_instruction->scope, source_instruction->source_node);
+ instruction->base.value->type = result_type;
+ instruction->operand = operand;
+ instruction->result_loc = result_loc;
-static constexpr IrInstGenId ir_inst_id(IrInstGenSplat *) {
- return IrInstGenIdSplat;
-}
+ ir_ref_inst_gen(operand);
+ if (result_loc != nullptr) ir_ref_inst_gen(result_loc);
-static constexpr IrInstGenId ir_inst_id(IrInstGenBoolNot *) {
- return IrInstGenIdBoolNot;
+ return &instruction->base;
}
-static constexpr IrInstGenId ir_inst_id(IrInstGenMemset *) {
- return IrInstGenIdMemset;
-}
+static IrInstGen *ir_build_clz_gen(IrAnalyze *ira, IrInst *source_instr, ZigType *result_type, IrInstGen *op) {
+ IrInstGenClz *instruction = ir_build_inst_gen<IrInstGenClz>(&ira->new_irb,
+ source_instr->scope, source_instr->source_node);
+ instruction->base.value->type = result_type;
+ instruction->op = op;
-static constexpr IrInstGenId ir_inst_id(IrInstGenMemcpy *) {
- return IrInstGenIdMemcpy;
-}
+ ir_ref_inst_gen(op);
-static constexpr IrInstGenId ir_inst_id(IrInstGenSlice *) {
- return IrInstGenIdSlice;
+ return &instruction->base;
}
-static constexpr IrInstGenId ir_inst_id(IrInstGenBreakpoint *) {
- return IrInstGenIdBreakpoint;
-}
+static IrInstGen *ir_build_ctz_gen(IrAnalyze *ira, IrInst *source_instr, ZigType *result_type, IrInstGen *op) {
+ IrInstGenCtz *instruction = ir_build_inst_gen<IrInstGenCtz>(&ira->new_irb,
+ source_instr->scope, source_instr->source_node);
+ instruction->base.value->type = result_type;
+ instruction->op = op;
-static constexpr IrInstGenId ir_inst_id(IrInstGenReturnAddress *) {
- return IrInstGenIdReturnAddress;
-}
+ ir_ref_inst_gen(op);
-static constexpr IrInstGenId ir_inst_id(IrInstGenFrameAddress *) {
- return IrInstGenIdFrameAddress;
+ return &instruction->base;
}
-static constexpr IrInstGenId ir_inst_id(IrInstGenFrameHandle *) {
- return IrInstGenIdFrameHandle;
-}
+static IrInstGen *ir_build_pop_count_gen(IrAnalyze *ira, IrInst *source_instr, ZigType *result_type,
+ IrInstGen *op)
+{
+ IrInstGenPopCount *instruction = ir_build_inst_gen<IrInstGenPopCount>(&ira->new_irb,
+ source_instr->scope, source_instr->source_node);
+ instruction->base.value->type = result_type;
+ instruction->op = op;
-static constexpr IrInstGenId ir_inst_id(IrInstGenFrameSize *) {
- return IrInstGenIdFrameSize;
-}
+ ir_ref_inst_gen(op);
-static constexpr IrInstGenId ir_inst_id(IrInstGenOverflowOp *) {
- return IrInstGenIdOverflowOp;
+ return &instruction->base;
}
-static constexpr IrInstGenId ir_inst_id(IrInstGenTestErr *) {
- return IrInstGenIdTestErr;
-}
+static IrInstGen *ir_build_bswap_gen(IrAnalyze *ira, IrInst *source_instr, ZigType *op_type,
+ IrInstGen *op)
+{
+ IrInstGenBswap *instruction = ir_build_inst_gen<IrInstGenBswap>(&ira->new_irb,
+ source_instr->scope, source_instr->source_node);
+ instruction->base.value->type = op_type;
+ instruction->op = op;
-static constexpr IrInstGenId ir_inst_id(IrInstGenMulAdd *) {
- return IrInstGenIdMulAdd;
-}
+ ir_ref_inst_gen(op);
-static constexpr IrInstGenId ir_inst_id(IrInstGenFloatOp *) {
- return IrInstGenIdFloatOp;
+ return &instruction->base;
}
-static constexpr IrInstGenId ir_inst_id(IrInstGenUnwrapErrCode *) {
- return IrInstGenIdUnwrapErrCode;
-}
+static IrInstGen *ir_build_bit_reverse_gen(IrAnalyze *ira, IrInst *source_instr, ZigType *int_type,
+ IrInstGen *op)
+{
+ IrInstGenBitReverse *instruction = ir_build_inst_gen<IrInstGenBitReverse>(&ira->new_irb,
+ source_instr->scope, source_instr->source_node);
+ instruction->base.value->type = int_type;
+ instruction->op = op;
-static constexpr IrInstGenId ir_inst_id(IrInstGenUnwrapErrPayload *) {
- return IrInstGenIdUnwrapErrPayload;
-}
+ ir_ref_inst_gen(op);
-static constexpr IrInstGenId ir_inst_id(IrInstGenErrWrapCode *) {
- return IrInstGenIdErrWrapCode;
+ return &instruction->base;
}
-static constexpr IrInstGenId ir_inst_id(IrInstGenErrWrapPayload *) {
- return IrInstGenIdErrWrapPayload;
-}
+static IrInstGenSwitchBr *ir_build_switch_br_gen(IrAnalyze *ira, IrInst *source_instr,
+ IrInstGen *target_value, IrBasicBlockGen *else_block, size_t case_count, IrInstGenSwitchBrCase *cases)
+{
+ IrInstGenSwitchBr *instruction = ir_build_inst_noreturn<IrInstGenSwitchBr>(&ira->new_irb,
+ source_instr->scope, source_instr->source_node);
+ instruction->target_value = target_value;
+ instruction->else_block = else_block;
+ instruction->case_count = case_count;
+ instruction->cases = cases;
-static constexpr IrInstGenId ir_inst_id(IrInstGenPtrCast *) {
- return IrInstGenIdPtrCast;
-}
+ ir_ref_inst_gen(target_value);
-static constexpr IrInstGenId ir_inst_id(IrInstGenBitCast *) {
- return IrInstGenIdBitCast;
-}
+ for (size_t i = 0; i < case_count; i += 1) {
+ ir_ref_inst_gen(cases[i].value);
+ }
-static constexpr IrInstGenId ir_inst_id(IrInstGenWidenOrShorten *) {
- return IrInstGenIdWidenOrShorten;
+ return instruction;
}
-static constexpr IrInstGenId ir_inst_id(IrInstGenIntToPtr *) {
- return IrInstGenIdIntToPtr;
-}
+static IrInstGen *ir_build_union_tag(IrAnalyze *ira, IrInst *source_instr, IrInstGen *value,
+ ZigType *tag_type)
+{
+ IrInstGenUnionTag *instruction = ir_build_inst_gen<IrInstGenUnionTag>(&ira->new_irb,
+ source_instr->scope, source_instr->source_node);
+ instruction->value = value;
+ instruction->base.value->type = tag_type;
-static constexpr IrInstGenId ir_inst_id(IrInstGenPtrToInt *) {
- return IrInstGenIdPtrToInt;
-}
+ ir_ref_inst_gen(value);
-static constexpr IrInstGenId ir_inst_id(IrInstGenIntToEnum *) {
- return IrInstGenIdIntToEnum;
+ return &instruction->base;
}
-static constexpr IrInstGenId ir_inst_id(IrInstGenIntToErr *) {
- return IrInstGenIdIntToErr;
-}
+static IrInstGen *ir_build_ref_gen(IrAnalyze *ira, IrInst *source_instruction, ZigType *result_type,
+ IrInstGen *operand, IrInstGen *result_loc)
+{
+ IrInstGenRef *instruction = ir_build_inst_gen<IrInstGenRef>(&ira->new_irb,
+ source_instruction->scope, source_instruction->source_node);
+ instruction->base.value->type = result_type;
+ instruction->operand = operand;
+ instruction->result_loc = result_loc;
-static constexpr IrInstGenId ir_inst_id(IrInstGenErrToInt *) {
- return IrInstGenIdErrToInt;
-}
+ ir_ref_inst_gen(operand);
+ if (result_loc != nullptr) ir_ref_inst_gen(result_loc);
-static constexpr IrInstGenId ir_inst_id(IrInstGenPanic *) {
- return IrInstGenIdPanic;
+ return &instruction->base;
}
-static constexpr IrInstGenId ir_inst_id(IrInstGenTagName *) {
- return IrInstGenIdTagName;
-}
+static IrInstGen *ir_build_err_name_gen(IrAnalyze *ira, IrInst *source_instr, IrInstGen *value,
+ ZigType *str_type)
+{
+ IrInstGenErrName *instruction = ir_build_inst_gen<IrInstGenErrName>(&ira->new_irb,
+ source_instr->scope, source_instr->source_node);
+ instruction->base.value->type = str_type;
+ instruction->value = value;
-static constexpr IrInstGenId ir_inst_id(IrInstGenFieldParentPtr *) {
- return IrInstGenIdFieldParentPtr;
-}
+ ir_ref_inst_gen(value);
-static constexpr IrInstGenId ir_inst_id(IrInstGenAlignCast *) {
- return IrInstGenIdAlignCast;
+ return &instruction->base;
}
-static constexpr IrInstGenId ir_inst_id(IrInstGenErrorReturnTrace *) {
- return IrInstGenIdErrorReturnTrace;
-}
+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)
+{
+ IrInstGenCmpxchg *instruction = ir_build_inst_gen<IrInstGenCmpxchg>(&ira->new_irb,
+ source_instruction->scope, source_instruction->source_node);
+ instruction->base.value->type = result_type;
+ instruction->ptr = ptr;
+ instruction->cmp_value = cmp_value;
+ instruction->new_value = new_value;
+ instruction->success_order = success_order;
+ instruction->failure_order = failure_order;
+ instruction->is_weak = is_weak;
+ instruction->result_loc = result_loc;
-static constexpr IrInstGenId ir_inst_id(IrInstGenAtomicRmw *) {
- return IrInstGenIdAtomicRmw;
-}
+ ir_ref_inst_gen(ptr);
+ ir_ref_inst_gen(cmp_value);
+ ir_ref_inst_gen(new_value);
+ if (result_loc != nullptr) ir_ref_inst_gen(result_loc);
-static constexpr IrInstGenId ir_inst_id(IrInstGenAtomicLoad *) {
- return IrInstGenIdAtomicLoad;
+ return &instruction->base;
}
-static constexpr IrInstGenId ir_inst_id(IrInstGenAtomicStore *) {
- return IrInstGenIdAtomicStore;
-}
+static IrInstGen *ir_build_fence_gen(IrAnalyze *ira, IrInst *source_instr, AtomicOrder order) {
+ IrInstGenFence *instruction = ir_build_inst_void<IrInstGenFence>(&ira->new_irb,
+ source_instr->scope, source_instr->source_node);
+ instruction->order = order;
-static constexpr IrInstGenId ir_inst_id(IrInstGenSaveErrRetAddr *) {
- return IrInstGenIdSaveErrRetAddr;
+ return &instruction->base;
}
-static constexpr IrInstGenId ir_inst_id(IrInstGenVectorToArray *) {
- return IrInstGenIdVectorToArray;
-}
-
-static constexpr IrInstGenId ir_inst_id(IrInstGenArrayToVector *) {
- return IrInstGenIdArrayToVector;
-}
+static IrInstGen *ir_build_reduce_gen(IrAnalyze *ira, IrInst *source_instruction, ReduceOp op, IrInstGen *value, ZigType *result_type) {
+ IrInstGenReduce *instruction = ir_build_inst_gen<IrInstGenReduce>(&ira->new_irb,
+ source_instruction->scope, source_instruction->source_node);
+ instruction->base.value->type = result_type;
+ instruction->op = op;
+ instruction->value = value;
-static constexpr IrInstGenId ir_inst_id(IrInstGenAssertZero *) {
- return IrInstGenIdAssertZero;
-}
+ ir_ref_inst_gen(value);
-static constexpr IrInstGenId ir_inst_id(IrInstGenAssertNonNull *) {
- return IrInstGenIdAssertNonNull;
+ return &instruction->base;
}
-static constexpr IrInstGenId ir_inst_id(IrInstGenPtrOfArrayToSlice *) {
- return IrInstGenIdPtrOfArrayToSlice;
+static void ir_set_cursor_at_end_gen(IrBuilderGen *irb, IrBasicBlockGen *basic_block) {
+ assert(basic_block);
+ irb->current_basic_block = basic_block;
}
-static constexpr IrInstGenId ir_inst_id(IrInstGenSuspendBegin *) {
- return IrInstGenIdSuspendBegin;
+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 constexpr IrInstGenId ir_inst_id(IrInstGenSuspendFinish *) {
- return IrInstGenIdSuspendFinish;
+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 constexpr IrInstGenId ir_inst_id(IrInstGenAwait *) {
- return IrInstGenIdAwait;
+static IrInstGen *ir_build_suspend_begin_gen(IrAnalyze *ira, IrInst *source_instr) {
+ IrInstGenSuspendBegin *inst = ir_build_inst_void<IrInstGenSuspendBegin>(&ira->new_irb,
+ source_instr->scope, source_instr->source_node);
+ return &inst->base;
}
-static constexpr IrInstGenId ir_inst_id(IrInstGenResume *) {
- return IrInstGenIdResume;
+static IrInstGen *ir_build_save_err_ret_addr_gen(IrAnalyze *ira, IrInst *source_instr) {
+ IrInstGenSaveErrRetAddr *inst = ir_build_inst_void<IrInstGenSaveErrRetAddr>(&ira->new_irb,
+ source_instr->scope, source_instr->source_node);
+ return &inst->base;
}
-static constexpr IrInstGenId ir_inst_id(IrInstGenSpillBegin *) {
- return IrInstGenIdSpillBegin;
-}
+static IrInstGen *ir_build_truncate_gen(IrAnalyze *ira, IrInst *source_instr, ZigType *dest_type,
+ IrInstGen *target)
+{
+ IrInstGenTruncate *instruction = ir_build_inst_gen<IrInstGenTruncate>(&ira->new_irb,
+ source_instr->scope, source_instr->source_node);
+ instruction->base.value->type = dest_type;
+ instruction->target = target;
-static constexpr IrInstGenId ir_inst_id(IrInstGenSpillEnd *) {
- return IrInstGenIdSpillEnd;
-}
+ ir_ref_inst_gen(target);
-static constexpr IrInstGenId ir_inst_id(IrInstGenVectorExtractElem *) {
- return IrInstGenIdVectorExtractElem;
+ return &instruction->base;
}
-static constexpr IrInstGenId ir_inst_id(IrInstGenAlloca *) {
- return IrInstGenIdAlloca;
-}
+static IrInstGen *ir_build_shuffle_vector_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node,
+ ZigType *result_type, IrInstGen *a, IrInstGen *b, IrInstGen *mask)
+{
+ IrInstGenShuffleVector *inst = ir_build_inst_gen<IrInstGenShuffleVector>(&ira->new_irb, scope, source_node);
+ inst->base.value->type = result_type;
+ inst->a = a;
+ inst->b = b;
+ inst->mask = mask;
-static constexpr IrInstGenId ir_inst_id(IrInstGenConst *) {
- return IrInstGenIdConst;
-}
+ ir_ref_inst_gen(a);
+ ir_ref_inst_gen(b);
+ ir_ref_inst_gen(mask);
-static constexpr IrInstGenId ir_inst_id(IrInstGenWasmMemorySize *) {
- return IrInstGenIdWasmMemorySize;
+ return &inst->base;
}
-static constexpr IrInstGenId ir_inst_id(IrInstGenWasmMemoryGrow *) {
- return IrInstGenIdWasmMemoryGrow;
-}
+static IrInstGen *ir_build_splat_gen(IrAnalyze *ira, IrInst *source_instruction, ZigType *result_type,
+ IrInstGen *scalar)
+{
+ IrInstGenSplat *instruction = ir_build_inst_gen<IrInstGenSplat>(
+ &ira->new_irb, source_instruction->scope, source_instruction->source_node);
+ instruction->base.value->type = result_type;
+ instruction->scalar = scalar;
-static constexpr IrInstGenId ir_inst_id(IrInstGenExtern *) {
- return IrInstGenIdExtern;
-}
+ ir_ref_inst_gen(scalar);
-template<typename T>
-static T *ir_create_instruction(IrBuilderSrc *irb, Scope *scope, AstNode *source_node) {
- T *special_instruction = heap::c_allocator.create<T>();
- 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;
+ return &instruction->base;
}
-template<typename T>
-static T *ir_create_inst_gen(IrBuilderGen *irb, Scope *scope, AstNode *source_node) {
- T *special_instruction = heap::c_allocator.create<T>();
- 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_gen(irb->exec);
- special_instruction->base.owner_bb = irb->current_basic_block;
- special_instruction->base.value = irb->codegen->pass1_arena->create<ZigValue>();
- return special_instruction;
-}
+static IrInstGen *ir_build_bool_not_gen(IrAnalyze *ira, IrInst *source_instr, IrInstGen *value) {
+ IrInstGenBoolNot *instruction = ir_build_inst_gen<IrInstGenBoolNot>(&ira->new_irb,
+ source_instr->scope, source_instr->source_node);
+ instruction->base.value->type = ira->codegen->builtin_types.entry_bool;
+ instruction->value = value;
-template<typename T>
-static T *ir_create_inst_noval(IrBuilderGen *irb, Scope *scope, AstNode *source_node) {
- T *special_instruction = heap::c_allocator.create<T>();
- 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_gen(irb->exec);
- special_instruction->base.owner_bb = irb->current_basic_block;
- return special_instruction;
-}
+ ir_ref_inst_gen(value);
-template<typename T>
-static T *ir_build_instruction(IrBuilderSrc *irb, Scope *scope, AstNode *source_node) {
- T *special_instruction = ir_create_instruction<T>(irb, scope, source_node);
- ir_instruction_append(irb->current_basic_block, &special_instruction->base);
- return special_instruction;
+ return &instruction->base;
}
-template<typename T>
-static T *ir_build_inst_gen(IrBuilderGen *irb, Scope *scope, AstNode *source_node) {
- T *special_instruction = ir_create_inst_gen<T>(irb, scope, source_node);
- ir_inst_gen_append(irb->current_basic_block, &special_instruction->base);
- return special_instruction;
-}
+static IrInstGen *ir_build_memset_gen(IrAnalyze *ira, IrInst *source_instr,
+ IrInstGen *dest_ptr, IrInstGen *byte, IrInstGen *count)
+{
+ IrInstGenMemset *instruction = ir_build_inst_void<IrInstGenMemset>(&ira->new_irb,
+ source_instr->scope, source_instr->source_node);
+ instruction->dest_ptr = dest_ptr;
+ instruction->byte = byte;
+ instruction->count = count;
-template<typename T>
-static T *ir_build_inst_noreturn(IrBuilderGen *irb, Scope *scope, AstNode *source_node) {
- T *special_instruction = ir_create_inst_noval<T>(irb, scope, source_node);
- special_instruction->base.value = irb->codegen->intern.for_unreachable();
- ir_inst_gen_append(irb->current_basic_block, &special_instruction->base);
- return special_instruction;
-}
+ ir_ref_inst_gen(dest_ptr);
+ ir_ref_inst_gen(byte);
+ ir_ref_inst_gen(count);
-template<typename T>
-static T *ir_build_inst_void(IrBuilderGen *irb, Scope *scope, AstNode *source_node) {
- T *special_instruction = ir_create_inst_noval<T>(irb, scope, source_node);
- special_instruction->base.value = irb->codegen->intern.for_void();
- ir_inst_gen_append(irb->current_basic_block, &special_instruction->base);
- return special_instruction;
+ return &instruction->base;
}
-IrInstGen *ir_create_alloca(CodeGen *g, Scope *scope, AstNode *source_node, ZigFn *fn,
- ZigType *var_type, const char *name_hint)
+static IrInstGen *ir_build_memcpy_gen(IrAnalyze *ira, IrInst *source_instr,
+ IrInstGen *dest_ptr, IrInstGen *src_ptr, IrInstGen *count)
{
- IrInstGenAlloca *alloca_gen = heap::c_allocator.create<IrInstGenAlloca>();
- alloca_gen->base.id = IrInstGenIdAlloca;
- alloca_gen->base.base.source_node = source_node;
- alloca_gen->base.base.scope = scope;
- alloca_gen->base.value = g->pass1_arena->create<ZigValue>();
- alloca_gen->base.value->type = get_pointer_to_type(g, var_type, false);
- alloca_gen->base.base.ref_count = 1;
- alloca_gen->name_hint = name_hint;
- fn->alloca_gen_list.append(alloca_gen);
- return &alloca_gen->base;
+ IrInstGenMemcpy *instruction = ir_build_inst_void<IrInstGenMemcpy>(&ira->new_irb,
+ source_instr->scope, source_instr->source_node);
+ instruction->dest_ptr = dest_ptr;
+ instruction->src_ptr = src_ptr;
+ instruction->count = count;
+
+ ir_ref_inst_gen(dest_ptr);
+ ir_ref_inst_gen(src_ptr);
+ ir_ref_inst_gen(count);
+
+ return &instruction->base;
}
-static IrInstGen *ir_build_cast(IrAnalyze *ira, IrInst *source_instr,ZigType *dest_type,
- IrInstGen *value, CastOp cast_op)
+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)
{
- IrInstGenCast *inst = ir_build_inst_gen<IrInstGenCast>(&ira->new_irb, source_instr->scope, source_instr->source_node);
- inst->base.value->type = dest_type;
- inst->value = value;
- inst->cast_op = cast_op;
+ IrInstGenSlice *instruction = ir_build_inst_gen<IrInstGenSlice>(
+ &ira->new_irb, source_instruction->scope, source_instruction->source_node);
+ instruction->base.value->type = slice_type;
+ instruction->ptr = ptr;
+ instruction->start = start;
+ instruction->end = end;
+ instruction->safety_check_on = safety_check_on;
+ instruction->result_loc = result_loc;
+ instruction->sentinel = sentinel;
- ir_ref_inst_gen(value);
+ ir_ref_inst_gen(ptr);
+ ir_ref_inst_gen(start);
+ if (end != nullptr) ir_ref_inst_gen(end);
+ if (result_loc != nullptr) ir_ref_inst_gen(result_loc);
- return &inst->base;
+ return &instruction->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<IrInstSrcCondBr>(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);
+static IrInstGen *ir_build_breakpoint_gen(IrAnalyze *ira, IrInst *source_instr) {
+ IrInstGenBreakpoint *instruction = ir_build_inst_void<IrInstGenBreakpoint>(&ira->new_irb,
+ source_instr->scope, source_instr->source_node);
+ return &instruction->base;
+}
+static IrInstGen *ir_build_return_address_gen(IrAnalyze *ira, IrInst *source_instr) {
+ IrInstGenReturnAddress *inst = ir_build_inst_gen<IrInstGenReturnAddress>(&ira->new_irb, source_instr->scope, source_instr->source_node);
+ inst->base.value->type = ira->codegen->builtin_types.entry_usize;
return &inst->base;
}
-static IrInstGen *ir_build_cond_br_gen(IrAnalyze *ira, IrInst *source_instr, IrInstGen *condition,
- IrBasicBlockGen *then_block, IrBasicBlockGen *else_block)
-{
- IrInstGenCondBr *inst = ir_build_inst_noreturn<IrInstGenCondBr>(&ira->new_irb, source_instr->scope, source_instr->source_node);
- inst->condition = condition;
- inst->then_block = then_block;
- inst->else_block = else_block;
-
- ir_ref_inst_gen(condition);
+static IrInstGen *ir_build_frame_address_gen(IrAnalyze *ira, IrInst *source_instr) {
+ IrInstGenFrameAddress *inst = ir_build_inst_gen<IrInstGenFrameAddress>(&ira->new_irb, source_instr->scope, source_instr->source_node);
+ inst->base.value->type = ira->codegen->builtin_types.entry_usize;
+ return &inst->base;
+}
+static IrInstGen *ir_build_handle_gen(IrAnalyze *ira, IrInst *source_instr, ZigType *ty) {
+ IrInstGenFrameHandle *inst = ir_build_inst_gen<IrInstGenFrameHandle>(&ira->new_irb, source_instr->scope, source_instr->source_node);
+ inst->base.value->type = ty;
return &inst->base;
}
-static IrInstSrc *ir_build_return_src(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrInstSrc *operand) {
- IrInstSrcReturn *inst = ir_build_instruction<IrInstSrcReturn>(irb, scope, source_node);
- inst->base.is_noreturn = true;
- inst->operand = operand;
+static IrInstGen *ir_build_frame_size_gen(IrAnalyze *ira, IrInst *source_instr, IrInstGen *fn)
+{
+ IrInstGenFrameSize *inst = ir_build_inst_gen<IrInstGenFrameSize>(&ira->new_irb, source_instr->scope, source_instr->source_node);
+ inst->base.value->type = ira->codegen->builtin_types.entry_usize;
+ inst->fn = fn;
- if (operand != nullptr) ir_ref_instruction(operand, irb->current_basic_block);
+ ir_ref_inst_gen(fn);
return &inst->base;
}
-static IrInstGen *ir_build_return_gen(IrAnalyze *ira, IrInst *source_inst, IrInstGen *operand) {
- IrInstGenReturn *inst = ir_build_inst_noreturn<IrInstGenReturn>(&ira->new_irb,
- source_inst->scope, source_inst->source_node);
- inst->operand = operand;
-
- if (operand != nullptr) ir_ref_inst_gen(operand);
-
- return &inst->base;
-}
-
-static IrInstSrc *ir_build_const_void(IrBuilderSrc *irb, Scope *scope, AstNode *source_node) {
- IrInstSrcConst *const_instruction = ir_create_instruction<IrInstSrcConst>(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<IrInstSrcConst>(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<IrInstSrcConst>(irb, scope, source_node);
- const_instruction->value = irb->codegen->pass1_arena->create<ZigValue>();
- 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 IrInstGen *ir_build_overflow_op_gen(IrAnalyze *ira, IrInst *source_instr,
+ IrOverflowOp op, IrInstGen *op1, IrInstGen *op2, IrInstGen *result_ptr,
+ ZigType *result_ptr_type)
+{
+ IrInstGenOverflowOp *instruction = ir_build_inst_gen<IrInstGenOverflowOp>(&ira->new_irb,
+ source_instr->scope, source_instr->source_node);
+ instruction->base.value->type = ira->codegen->builtin_types.entry_bool;
+ instruction->op = op;
+ instruction->op1 = op1;
+ instruction->op2 = op2;
+ instruction->result_ptr = result_ptr;
+ instruction->result_ptr_type = result_ptr_type;
-static IrInstSrc *ir_build_const_bigint(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, BigInt *bigint) {
- IrInstSrcConst *const_instruction = ir_build_instruction<IrInstSrcConst>(irb, scope, source_node);
- const_instruction->value = irb->codegen->pass1_arena->create<ZigValue>();
- 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;
-}
+ ir_ref_inst_gen(op1);
+ ir_ref_inst_gen(op2);
+ ir_ref_inst_gen(result_ptr);
-static IrInstSrc *ir_build_const_bigfloat(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, BigFloat *bigfloat) {
- IrInstSrcConst *const_instruction = ir_build_instruction<IrInstSrcConst>(irb, scope, source_node);
- const_instruction->value = irb->codegen->pass1_arena->create<ZigValue>();
- 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;
+ return &instruction->base;
}
-static IrInstSrc *ir_build_const_null(IrBuilderSrc *irb, Scope *scope, AstNode *source_node) {
- IrInstSrcConst *const_instruction = ir_create_instruction<IrInstSrcConst>(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 IrInstGen *ir_build_float_op_gen(IrAnalyze *ira, IrInst *source_instr, IrInstGen *operand,
+ BuiltinFnId fn_id, ZigType *operand_type)
+{
+ IrInstGenFloatOp *instruction = ir_build_inst_gen<IrInstGenFloatOp>(&ira->new_irb,
+ source_instr->scope, source_instr->source_node);
+ instruction->base.value->type = operand_type;
+ instruction->operand = operand;
+ instruction->fn_id = fn_id;
-static IrInstSrc *ir_build_const_usize(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, uint64_t value) {
- IrInstSrcConst *const_instruction = ir_build_instruction<IrInstSrcConst>(irb, scope, source_node);
- const_instruction->value = irb->codegen->pass1_arena->create<ZigValue>();
- 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;
-}
+ ir_ref_inst_gen(operand);
-static IrInstSrc *ir_create_const_type(IrBuilderSrc *irb, Scope *scope, AstNode *source_node,
- ZigType *type_entry)
-{
- IrInstSrcConst *const_instruction = ir_create_instruction<IrInstSrcConst>(irb, scope, source_node);
- const_instruction->value = irb->codegen->pass1_arena->create<ZigValue>();
- 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;
+ return &instruction->base;
}
-static IrInstSrc *ir_build_const_type(IrBuilderSrc *irb, Scope *scope, AstNode *source_node,
- ZigType *type_entry)
+static IrInstGen *ir_build_mul_add_gen(IrAnalyze *ira, IrInst *source_instr, IrInstGen *op1, IrInstGen *op2,
+ IrInstGen *op3, ZigType *expr_type)
{
- 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<IrInstSrcConst>(irb, scope, source_node);
- const_instruction->value = irb->codegen->pass1_arena->create<ZigValue>();
- 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;
-}
+ IrInstGenMulAdd *instruction = ir_build_inst_gen<IrInstGenMulAdd>(&ira->new_irb,
+ source_instr->scope, source_instr->source_node);
+ instruction->base.value->type = expr_type;
+ instruction->op1 = op1;
+ instruction->op2 = op2;
+ instruction->op3 = op3;
-static IrInstSrc *ir_build_const_bool(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, bool value) {
- IrInstSrcConst *const_instruction = ir_build_instruction<IrInstSrcConst>(irb, scope, source_node);
- const_instruction->value = irb->codegen->pass1_arena->create<ZigValue>();
- 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;
-}
+ ir_ref_inst_gen(op1);
+ ir_ref_inst_gen(op2);
+ ir_ref_inst_gen(op3);
-static IrInstSrc *ir_build_const_enum_literal(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, Buf *name) {
- IrInstSrcConst *const_instruction = ir_build_instruction<IrInstSrcConst>(irb, scope, source_node);
- const_instruction->value = irb->codegen->pass1_arena->create<ZigValue>();
- 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;
+ return &instruction->base;
}
-static IrInstSrc *ir_create_const_str_lit(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, Buf *str) {
- IrInstSrcConst *const_instruction = ir_create_instruction<IrInstSrcConst>(irb, scope, source_node);
- const_instruction->value = irb->codegen->pass1_arena->create<ZigValue>();
- init_const_str_lit(irb->codegen, const_instruction->value, str);
+static IrInstGen *ir_build_test_err_gen(IrAnalyze *ira, IrInst *source_instruction, IrInstGen *err_union) {
+ IrInstGenTestErr *instruction = ir_build_inst_gen<IrInstGenTestErr>(
+ &ira->new_irb, source_instruction->scope, source_instruction->source_node);
+ instruction->base.value->type = ira->codegen->builtin_types.entry_bool;
+ instruction->err_union = err_union;
- return &const_instruction->base;
-}
+ ir_ref_inst_gen(err_union);
-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;
+ return &instruction->base;
}
-static IrInstSrc *ir_build_bin_op(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrBinOp op_id,
- IrInstSrc *op1, IrInstSrc *op2, bool safety_check_on)
+static IrInstGen *ir_build_unwrap_err_code_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node,
+ IrInstGen *err_union_ptr, ZigType *result_type)
{
- IrInstSrcBinOp *inst = ir_build_instruction<IrInstSrcBinOp>(irb, scope, source_node);
- inst->op_id = op_id;
- inst->op1 = op1;
- inst->op2 = op2;
- inst->safety_check_on = safety_check_on;
+ IrInstGenUnwrapErrCode *inst = ir_build_inst_gen<IrInstGenUnwrapErrCode>(&ira->new_irb, scope, source_node);
+ inst->base.value->type = result_type;
+ inst->err_union_ptr = err_union_ptr;
- ir_ref_instruction(op1, irb->current_basic_block);
- ir_ref_instruction(op2, irb->current_basic_block);
+ ir_ref_inst_gen(err_union_ptr);
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)
+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)
{
- IrInstGenBinOp *inst = ir_build_inst_gen<IrInstGenBinOp>(&ira->new_irb,
- source_instr->scope, source_instr->source_node);
- inst->base.value->type = res_type;
- inst->op_id = op_id;
- inst->op1 = op1;
- inst->op2 = op2;
+ IrInstGenUnwrapErrPayload *inst = ir_build_inst_gen<IrInstGenUnwrapErrPayload>(&ira->new_irb, scope, source_node);
+ inst->base.value->type = result_type;
+ inst->value = value;
inst->safety_check_on = safety_check_on;
+ inst->initializing = initializing;
- ir_ref_inst_gen(op1);
- ir_ref_inst_gen(op2);
+ ir_ref_inst_gen(value);
return &inst->base;
}
-
-static IrInstSrc *ir_build_merge_err_sets(IrBuilderSrc *irb, Scope *scope, AstNode *source_node,
- IrInstSrc *op1, IrInstSrc *op2, Buf *type_name)
+static IrInstGen *ir_build_ptr_cast_gen(IrAnalyze *ira, IrInst *source_instruction,
+ ZigType *ptr_type, IrInstGen *ptr, bool safety_check_on)
{
- IrInstSrcMergeErrSets *inst = ir_build_instruction<IrInstSrcMergeErrSets>(irb, scope, source_node);
- inst->op1 = op1;
- inst->op2 = op2;
- inst->type_name = type_name;
+ IrInstGenPtrCast *instruction = ir_build_inst_gen<IrInstGenPtrCast>(
+ &ira->new_irb, source_instruction->scope, source_instruction->source_node);
+ instruction->base.value->type = ptr_type;
+ instruction->ptr = ptr;
+ instruction->safety_check_on = safety_check_on;
- ir_ref_instruction(op1, irb->current_basic_block);
- ir_ref_instruction(op2, irb->current_basic_block);
+ ir_ref_inst_gen(ptr);
- return &inst->base;
+ return &instruction->base;
}
-static IrInstSrc *ir_build_var_ptr_x(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, ZigVar *var,
- ScopeFnDef *crossed_fndef_scope)
+static IrInstGen *ir_build_bit_cast_gen(IrAnalyze *ira, IrInst *source_instruction,
+ IrInstGen *operand, ZigType *ty)
{
- IrInstSrcVarPtr *instruction = ir_build_instruction<IrInstSrcVarPtr>(irb, scope, source_node);
- instruction->var = var;
- instruction->crossed_fndef_scope = crossed_fndef_scope;
+ IrInstGenBitCast *instruction = ir_build_inst_gen<IrInstGenBitCast>(
+ &ira->new_irb, source_instruction->scope, source_instruction->source_node);
+ instruction->base.value->type = ty;
+ instruction->operand = operand;
- ir_ref_var(var);
+ ir_ref_inst_gen(operand);
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<IrInstGenVarPtr>(&ira->new_irb, source_instr->scope, source_instr->source_node);
- instruction->var = var;
+static IrInstGen *ir_build_widen_or_shorten(IrAnalyze *ira, Scope *scope, AstNode *source_node, IrInstGen *target,
+ ZigType *result_type)
+{
+ IrInstGenWidenOrShorten *inst = ir_build_inst_gen<IrInstGenWidenOrShorten>(&ira->new_irb, scope, source_node);
+ inst->base.value->type = result_type;
+ inst->target = target;
- ir_ref_var(var);
+ ir_ref_inst_gen(target);
- return &instruction->base;
+ return &inst->base;
}
-static IrInstGen *ir_build_return_ptr(IrAnalyze *ira, Scope *scope, AstNode *source_node, ZigType *ty) {
- IrInstGenReturnPtr *instruction = ir_build_inst_gen<IrInstGenReturnPtr>(&ira->new_irb, scope, source_node);
- instruction->base.value->type = ty;
+static IrInstGen *ir_build_int_to_ptr_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node,
+ IrInstGen *target, ZigType *ptr_type)
+{
+ IrInstGenIntToPtr *instruction = ir_build_inst_gen<IrInstGenIntToPtr>(&ira->new_irb, scope, source_node);
+ instruction->base.value->type = ptr_type;
+ instruction->target = target;
+
+ ir_ref_inst_gen(target);
+
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<IrInstSrcElemPtr>(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;
+static IrInstGen *ir_build_ptr_to_int_gen(IrAnalyze *ira, IrInst *source_instr, IrInstGen *target) {
+ IrInstGenPtrToInt *inst = ir_build_inst_gen<IrInstGenPtrToInt>(&ira->new_irb, source_instr->scope, source_instr->source_node);
+ inst->base.value->type = ira->codegen->builtin_types.entry_usize;
+ inst->target = target;
- ir_ref_instruction(array_ptr, irb->current_basic_block);
- ir_ref_instruction(elem_index, irb->current_basic_block);
+ ir_ref_inst_gen(target);
- return &instruction->base;
+ return &inst->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)
+static IrInstGen *ir_build_int_to_enum_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node,
+ ZigType *dest_type, IrInstGen *target)
{
- IrInstGenElemPtr *instruction = ir_build_inst_gen<IrInstGenElemPtr>(&ira->new_irb, scope, source_node);
- instruction->base.value->type = return_type;
- instruction->array_ptr = array_ptr;
- instruction->elem_index = elem_index;
- instruction->safety_check_on = safety_check_on;
+ IrInstGenIntToEnum *instruction = ir_build_inst_gen<IrInstGenIntToEnum>(&ira->new_irb, scope, source_node);
+ instruction->base.value->type = dest_type;
+ instruction->target = target;
- ir_ref_inst_gen(array_ptr);
- ir_ref_inst_gen(elem_index);
+ ir_ref_inst_gen(target);
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)
+static IrInstGen *ir_build_int_to_err_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, IrInstGen *target,
+ ZigType *wanted_type)
{
- IrInstSrcFieldPtr *instruction = ir_build_instruction<IrInstSrcFieldPtr>(irb, scope, source_node);
- instruction->container_ptr = container_ptr;
- instruction->field_name_buffer = nullptr;
- instruction->field_name_expr = field_name_expr;
- instruction->initializing = initializing;
+ IrInstGenIntToErr *instruction = ir_build_inst_gen<IrInstGenIntToErr>(&ira->new_irb, scope, source_node);
+ instruction->base.value->type = wanted_type;
+ instruction->target = target;
- ir_ref_instruction(container_ptr, irb->current_basic_block);
- ir_ref_instruction(field_name_expr, irb->current_basic_block);
+ ir_ref_inst_gen(target);
return &instruction->base;
}
-static IrInstSrc *ir_build_field_ptr(IrBuilderSrc *irb, Scope *scope, AstNode *source_node,
- IrInstSrc *container_ptr, Buf *field_name, bool initializing)
+static IrInstGen *ir_build_err_to_int_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, IrInstGen *target,
+ ZigType *wanted_type)
{
- IrInstSrcFieldPtr *instruction = ir_build_instruction<IrInstSrcFieldPtr>(irb, scope, source_node);
- instruction->container_ptr = container_ptr;
- instruction->field_name_buffer = field_name;
- instruction->field_name_expr = nullptr;
- instruction->initializing = initializing;
+ IrInstGenErrToInt *instruction = ir_build_inst_gen<IrInstGenErrToInt>(&ira->new_irb, scope, source_node);
+ instruction->base.value->type = wanted_type;
+ instruction->target = target;
- ir_ref_instruction(container_ptr, irb->current_basic_block);
+ ir_ref_inst_gen(target);
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<IrInstSrcHasField>(irb, scope, source_node);
- instruction->container_type = container_type;
- instruction->field_name = field_name;
+static IrInstGen *ir_build_panic_gen(IrAnalyze *ira, IrInst *source_instr, IrInstGen *msg) {
+ IrInstGenPanic *instruction = ir_build_inst_noreturn<IrInstGenPanic>(&ira->new_irb,
+ source_instr->scope, source_instr->source_node);
+ instruction->msg = msg;
- ir_ref_instruction(container_type, irb->current_basic_block);
- ir_ref_instruction(field_name, irb->current_basic_block);
+ ir_ref_inst_gen(msg);
return &instruction->base;
}
-static IrInstGen *ir_build_struct_field_ptr(IrAnalyze *ira, IrInst *source_instr,
- IrInstGen *struct_ptr, TypeStructField *field, ZigType *ptr_type)
+static IrInstGen *ir_build_tag_name_gen(IrAnalyze *ira, IrInst *source_instr, IrInstGen *target,
+ ZigType *result_type)
{
- IrInstGenStructFieldPtr *inst = ir_build_inst_gen<IrInstGenStructFieldPtr>(&ira->new_irb, source_instr->scope, source_instr->source_node);
- inst->base.value->type = ptr_type;
- inst->struct_ptr = struct_ptr;
- inst->field = field;
+ IrInstGenTagName *instruction = ir_build_inst_gen<IrInstGenTagName>(&ira->new_irb,
+ source_instr->scope, source_instr->source_node);
+ instruction->base.value->type = result_type;
+ instruction->target = target;
- ir_ref_inst_gen(struct_ptr);
+ ir_ref_inst_gen(target);
- return &inst->base;
+ return &instruction->base;
}
-static IrInstGen *ir_build_union_field_ptr(IrAnalyze *ira, IrInst *source_instr,
- IrInstGen *union_ptr, TypeUnionField *field, bool safety_check_on, bool initializing, ZigType *ptr_type)
+static IrInstGen *ir_build_field_parent_ptr_gen(IrAnalyze *ira, IrInst *source_instr,
+ IrInstGen *field_ptr, TypeStructField *field, ZigType *result_type)
{
- IrInstGenUnionFieldPtr *inst = ir_build_inst_gen<IrInstGenUnionFieldPtr>(&ira->new_irb,
+ IrInstGenFieldParentPtr *inst = ir_build_inst_gen<IrInstGenFieldParentPtr>(&ira->new_irb,
source_instr->scope, source_instr->source_node);
- inst->base.value->type = ptr_type;
- inst->initializing = initializing;
- inst->safety_check_on = safety_check_on;
- inst->union_ptr = union_ptr;
+ inst->base.value->type = result_type;
+ inst->field_ptr = field_ptr;
inst->field = field;
- ir_ref_inst_gen(union_ptr);
+ ir_ref_inst_gen(field_ptr);
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)
+static IrInstGen *ir_build_align_cast_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node, IrInstGen *target,
+ ZigType *result_type)
{
- IrInstSrcCallExtra *call_instruction = ir_build_instruction<IrInstSrcCallExtra>(irb, scope, source_node);
- call_instruction->options = options;
- call_instruction->fn_ref = fn_ref;
- call_instruction->args = args;
- call_instruction->result_loc = result_loc;
+ IrInstGenAlignCast *instruction = ir_build_inst_gen<IrInstGenAlignCast>(&ira->new_irb, scope, source_node);
+ instruction->base.value->type = result_type;
+ instruction->target = target;
- 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);
+ ir_ref_inst_gen(target);
- return &call_instruction->base;
+ return &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)
+static IrInstGen *ir_build_error_return_trace_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node,
+ IrInstErrorReturnTraceOptional optional, ZigType *result_type)
{
- IrInstSrcAsyncCallExtra *call_instruction = ir_build_instruction<IrInstSrcAsyncCallExtra>(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);
+ IrInstGenErrorReturnTrace *inst = ir_build_inst_gen<IrInstGenErrorReturnTrace>(&ira->new_irb, scope, source_node);
+ inst->base.value->type = result_type;
+ inst->optional = optional;
- return &call_instruction->base;
+ return &inst->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)
+static IrInstGen *ir_build_atomic_rmw_gen(IrAnalyze *ira, IrInst *source_instr,
+ IrInstGen *ptr, IrInstGen *operand, AtomicRmwOp op, AtomicOrder ordering, ZigType *operand_type)
{
- IrInstSrcCallArgs *call_instruction = ir_build_instruction<IrInstSrcCallArgs>(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<IrInstSrcCall>(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,
- IrInstGen *result_loc, ZigType *return_type)
-{
- IrInstGenCall *call_instruction = ir_build_inst_gen<IrInstGenCall>(&ira->new_irb,
- source_instruction->scope, source_instruction->source_node);
- call_instruction->base.value->type = return_type;
- 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;
-
- if (fn_ref != nullptr) ir_ref_inst_gen(fn_ref);
- for (size_t i = 0; i < arg_count; i += 1)
- ir_ref_inst_gen(args[i]);
- if (new_stack != nullptr) ir_ref_inst_gen(new_stack);
- if (result_loc != nullptr) ir_ref_inst_gen(result_loc);
-
- 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<IrInstSrcPhi>(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)
-{
- assert(incoming_count != 0);
- assert(incoming_count != SIZE_MAX);
-
- IrInstGenPhi *phi_instruction = ir_build_inst_gen<IrInstGenPhi>(&ira->new_irb,
- source_instr->scope, source_instr->source_node);
- phi_instruction->base.value->type = result_type;
- phi_instruction->incoming_count = incoming_count;
- phi_instruction->incoming_blocks = incoming_blocks;
- phi_instruction->incoming_values = incoming_values;
-
- for (size_t i = 0; i < incoming_count; i += 1) {
- ir_ref_inst_gen(incoming_values[i]);
- }
-
- 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<IrInstSrcBr>(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<IrInstGenBr>(&ira->new_irb, source_instr->scope, source_instr->source_node);
- inst->dest_block = dest_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<IrInstSrcPtrTypeSimple>();
- 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<IrInstSrcPtrType>(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<IrInstSrcUnOp>(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<IrInstGenNegation>(&ira->new_irb,
- source_instr->scope, source_instr->source_node);
- instruction->base.value->type = expr_type;
- instruction->operand = operand;
- instruction->wrapping = wrapping;
-
- ir_ref_inst_gen(operand);
-
- return &instruction->base;
-}
-
-static IrInstGen *ir_build_binary_not(IrAnalyze *ira, IrInst *source_instr, IrInstGen *operand,
- ZigType *expr_type)
-{
- IrInstGenBinaryNot *instruction = ir_build_inst_gen<IrInstGenBinaryNot>(&ira->new_irb,
- source_instr->scope, source_instr->source_node);
- instruction->base.value->type = expr_type;
- instruction->operand = operand;
-
- ir_ref_inst_gen(operand);
-
- 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<IrInstSrcContainerInitList>(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<IrInstSrcContainerInitFields>(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<IrInstSrcUnreachable>(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<IrInstGenUnreachable>(&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<IrInstSrcStorePtr>(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<IrInstGenStorePtr>(&ira->new_irb,
- source_instr->scope, source_instr->source_node);
+ IrInstGenAtomicRmw *instruction = ir_build_inst_gen<IrInstGenAtomicRmw>(&ira->new_irb, source_instr->scope, source_instr->source_node);
+ instruction->base.value->type = operand_type;
instruction->ptr = ptr;
- instruction->value = value;
+ instruction->op = op;
+ instruction->operand = operand;
+ instruction->ordering = ordering;
ir_ref_inst_gen(ptr);
- ir_ref_inst_gen(value);
+ ir_ref_inst_gen(operand);
return &instruction->base;
}
-static IrInstGen *ir_build_vector_store_elem(IrAnalyze *ira, IrInst *src_inst,
- IrInstGen *vector_ptr, IrInstGen *index, IrInstGen *value)
-{
- IrInstGenVectorStoreElem *inst = ir_build_inst_void<IrInstGenVectorStoreElem>(
- &ira->new_irb, src_inst->scope, src_inst->source_node);
- inst->vector_ptr = vector_ptr;
- inst->index = index;
- inst->value = value;
-
- ir_ref_inst_gen(vector_ptr);
- ir_ref_inst_gen(index);
- ir_ref_inst_gen(value);
-
- 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<IrInstSrcDeclVar>(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)
-{
- IrInstGenDeclVar *inst = ir_build_inst_gen<IrInstGenDeclVar>(&ira->new_irb,
- source_instruction->scope, source_instruction->source_node);
- inst->base.value->special = ConstValSpecialStatic;
- inst->base.value->type = ira->codegen->builtin_types.entry_void;
- inst->var = var;
- inst->var_ptr = var_ptr;
-
- ir_ref_inst_gen(var_ptr);
-
- 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<IrInstSrcExport>(
- 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<IrInstSrcExtern>(
- 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)
+static IrInstGen *ir_build_atomic_load_gen(IrAnalyze *ira, IrInst *source_instr,
+ IrInstGen *ptr, AtomicOrder ordering, ZigType *operand_type)
{
- IrInstGenExtern *instruction = ir_build_inst_gen<IrInstGenExtern>(&ira->new_irb,
+ IrInstGenAtomicLoad *instruction = ir_build_inst_gen<IrInstGenAtomicLoad>(&ira->new_irb,
source_instr->scope, source_instr->source_node);
- instruction->base.value->type = expr_type;
- instruction->name = name;
- instruction->linkage = linkage;
- instruction->is_thread_local = is_thread_local;
-
- return &instruction->base;
-}
-
-static IrInstSrc *ir_build_load_ptr(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrInstSrc *ptr) {
- IrInstSrcLoadPtr *instruction = ir_build_instruction<IrInstSrcLoadPtr>(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)
-{
- IrInstGenLoadPtr *instruction = ir_build_inst_gen<IrInstGenLoadPtr>(
- &ira->new_irb, source_instruction->scope, source_instruction->source_node);
- instruction->base.value->type = ty;
- instruction->ptr = ptr;
- instruction->result_loc = result_loc;
-
- ir_ref_inst_gen(ptr);
- if (result_loc != nullptr) ir_ref_inst_gen(result_loc);
-
- 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<IrInstSrcTypeOf>(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<IrInstSrcTypeOf>(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<IrInstSrcSetCold>(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<IrInstSrcSetRuntimeSafety>(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<IrInstSrcSetFloatMode>(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<IrInstSrcArrayType>(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<IrInstSrcAnyFrameType>(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<IrInstSrcSliceType>(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<IrInstSrcAsm>(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,
- bool has_side_effects, ZigType *return_type)
-{
- IrInstGenAsm *instruction = ir_build_inst_gen<IrInstGenAsm>(&ira->new_irb, source_instr->scope, source_instr->source_node);
- instruction->base.value->type = return_type;
- instruction->asm_template = asm_template;
- instruction->token_list = token_list;
- instruction->token_list_len = token_list_len;
- 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;
-
- assert(source_instr->source_node->type == NodeTypeAsmExpr);
- for (size_t i = 0; i < source_instr->source_node->data.asm_expr.output_list.length; i += 1) {
- IrInstGen *output_type = output_types[i];
- if (output_type) ir_ref_inst_gen(output_type);
- }
-
- for (size_t i = 0; i < source_instr->source_node->data.asm_expr.input_list.length; i += 1) {
- IrInstGen *input_value = input_list[i];
- ir_ref_inst_gen(input_value);
- }
-
- 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<IrInstSrcSizeOf>(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<IrInstSrcTestNonNull>(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<IrInstGenTestNonNull>(&ira->new_irb,
- source_instr->scope, source_instr->source_node);
- inst->base.value->type = ira->codegen->builtin_types.entry_bool;
- inst->value = value;
-
- ir_ref_inst_gen(value);
-
- 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<IrInstSrcOptionalUnwrapPtr>(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)
-{
- IrInstGenOptionalUnwrapPtr *inst = ir_build_inst_gen<IrInstGenOptionalUnwrapPtr>(&ira->new_irb,
- source_instr->scope, source_instr->source_node);
- inst->base.value->type = result_type;
- inst->base_ptr = base_ptr;
- inst->safety_check_on = safety_check_on;
- inst->initializing = initializing;
-
- ir_ref_inst_gen(base_ptr);
-
- return &inst->base;
-}
-
-static IrInstGen *ir_build_optional_wrap(IrAnalyze *ira, IrInst *source_instruction, ZigType *result_ty,
- IrInstGen *operand, IrInstGen *result_loc)
-{
- IrInstGenOptionalWrap *instruction = ir_build_inst_gen<IrInstGenOptionalWrap>(
- &ira->new_irb, source_instruction->scope, source_instruction->source_node);
- instruction->base.value->type = result_ty;
- instruction->operand = operand;
- instruction->result_loc = result_loc;
-
- ir_ref_inst_gen(operand);
- if (result_loc != nullptr) ir_ref_inst_gen(result_loc);
-
- return &instruction->base;
-}
-
-static IrInstGen *ir_build_err_wrap_payload(IrAnalyze *ira, IrInst *source_instruction,
- ZigType *result_type, IrInstGen *operand, IrInstGen *result_loc)
-{
- IrInstGenErrWrapPayload *instruction = ir_build_inst_gen<IrInstGenErrWrapPayload>(
- &ira->new_irb, source_instruction->scope, source_instruction->source_node);
- instruction->base.value->type = result_type;
- instruction->operand = operand;
- instruction->result_loc = result_loc;
-
- ir_ref_inst_gen(operand);
- if (result_loc != nullptr) ir_ref_inst_gen(result_loc);
-
- return &instruction->base;
-}
-
-static IrInstGen *ir_build_err_wrap_code(IrAnalyze *ira, IrInst *source_instruction,
- ZigType *result_type, IrInstGen *operand, IrInstGen *result_loc)
-{
- IrInstGenErrWrapCode *instruction = ir_build_inst_gen<IrInstGenErrWrapCode>(
- &ira->new_irb, source_instruction->scope, source_instruction->source_node);
- instruction->base.value->type = result_type;
- instruction->operand = operand;
- instruction->result_loc = result_loc;
-
- ir_ref_inst_gen(operand);
- if (result_loc != nullptr) ir_ref_inst_gen(result_loc);
-
- return &instruction->base;
-}
-
-static IrInstSrc *ir_build_clz(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrInstSrc *type,
- IrInstSrc *op)
-{
- IrInstSrcClz *instruction = ir_build_instruction<IrInstSrcClz>(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<IrInstGenClz>(&ira->new_irb,
- source_instr->scope, source_instr->source_node);
- instruction->base.value->type = result_type;
- instruction->op = op;
-
- ir_ref_inst_gen(op);
-
- return &instruction->base;
-}
-
-static IrInstSrc *ir_build_ctz(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrInstSrc *type,
- IrInstSrc *op)
-{
- IrInstSrcCtz *instruction = ir_build_instruction<IrInstSrcCtz>(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<IrInstGenCtz>(&ira->new_irb,
- source_instr->scope, source_instr->source_node);
- instruction->base.value->type = result_type;
- instruction->op = op;
-
- ir_ref_inst_gen(op);
-
- 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<IrInstSrcPopCount>(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)
-{
- IrInstGenPopCount *instruction = ir_build_inst_gen<IrInstGenPopCount>(&ira->new_irb,
- source_instr->scope, source_instr->source_node);
- instruction->base.value->type = result_type;
- instruction->op = op;
-
- ir_ref_inst_gen(op);
-
- return &instruction->base;
-}
-
-static IrInstSrc *ir_build_bswap(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrInstSrc *type,
- IrInstSrc *op)
-{
- IrInstSrcBswap *instruction = ir_build_instruction<IrInstSrcBswap>(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)
-{
- IrInstGenBswap *instruction = ir_build_inst_gen<IrInstGenBswap>(&ira->new_irb,
- source_instr->scope, source_instr->source_node);
- instruction->base.value->type = op_type;
- instruction->op = op;
-
- ir_ref_inst_gen(op);
-
- 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<IrInstSrcBitReverse>(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)
-{
- IrInstGenBitReverse *instruction = ir_build_inst_gen<IrInstGenBitReverse>(&ira->new_irb,
- source_instr->scope, source_instr->source_node);
- instruction->base.value->type = int_type;
- instruction->op = op;
-
- ir_ref_inst_gen(op);
-
- 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<IrInstSrcSwitchBr>(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)
-{
- IrInstGenSwitchBr *instruction = ir_build_inst_noreturn<IrInstGenSwitchBr>(&ira->new_irb,
- source_instr->scope, source_instr->source_node);
- instruction->target_value = target_value;
- instruction->else_block = else_block;
- instruction->case_count = case_count;
- instruction->cases = cases;
-
- ir_ref_inst_gen(target_value);
-
- for (size_t i = 0; i < case_count; i += 1) {
- ir_ref_inst_gen(cases[i].value);
- }
-
- return instruction;
-}
-
-static IrInstSrc *ir_build_switch_target(IrBuilderSrc *irb, Scope *scope, AstNode *source_node,
- IrInstSrc *target_value_ptr)
-{
- IrInstSrcSwitchTarget *instruction = ir_build_instruction<IrInstSrcSwitchTarget>(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<IrInstSrcSwitchVar>(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<IrInstSrcSwitchElseVar>(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)
-{
- IrInstGenUnionTag *instruction = ir_build_inst_gen<IrInstGenUnionTag>(&ira->new_irb,
- source_instr->scope, source_instr->source_node);
- instruction->value = value;
- instruction->base.value->type = tag_type;
-
- ir_ref_inst_gen(value);
-
- return &instruction->base;
-}
-
-static IrInstSrc *ir_build_import(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrInstSrc *name) {
- IrInstSrcImport *instruction = ir_build_instruction<IrInstSrcImport>(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<IrInstSrcRef>(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)
-{
- IrInstGenRef *instruction = ir_build_inst_gen<IrInstGenRef>(&ira->new_irb,
- source_instruction->scope, source_instruction->source_node);
- instruction->base.value->type = result_type;
- instruction->operand = operand;
- instruction->result_loc = result_loc;
-
- ir_ref_inst_gen(operand);
- if (result_loc != nullptr) ir_ref_inst_gen(result_loc);
-
- return &instruction->base;
-}
-
-static IrInstSrc *ir_build_compile_err(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrInstSrc *msg) {
- IrInstSrcCompileErr *instruction = ir_build_instruction<IrInstSrcCompileErr>(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<IrInstSrcCompileLog>(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<IrInstSrcErrName>(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)
-{
- IrInstGenErrName *instruction = ir_build_inst_gen<IrInstGenErrName>(&ira->new_irb,
- source_instr->scope, source_instr->source_node);
- instruction->base.value->type = str_type;
- instruction->value = value;
-
- ir_ref_inst_gen(value);
-
- return &instruction->base;
-}
-
-static IrInstSrc *ir_build_c_import(IrBuilderSrc *irb, Scope *scope, AstNode *source_node) {
- IrInstSrcCImport *instruction = ir_build_instruction<IrInstSrcCImport>(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<IrInstSrcCInclude>(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<IrInstSrcCDefine>(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<IrInstSrcCUndef>(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<IrInstSrcEmbedFile>(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<IrInstSrcCmpxchg>(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)
-{
- IrInstGenCmpxchg *instruction = ir_build_inst_gen<IrInstGenCmpxchg>(&ira->new_irb,
- source_instruction->scope, source_instruction->source_node);
- instruction->base.value->type = result_type;
- instruction->ptr = ptr;
- instruction->cmp_value = cmp_value;
- instruction->new_value = new_value;
- instruction->success_order = success_order;
- instruction->failure_order = failure_order;
- instruction->is_weak = is_weak;
- instruction->result_loc = result_loc;
-
- ir_ref_inst_gen(ptr);
- ir_ref_inst_gen(cmp_value);
- ir_ref_inst_gen(new_value);
- if (result_loc != nullptr) ir_ref_inst_gen(result_loc);
-
- return &instruction->base;
-}
-
-static IrInstSrc *ir_build_fence(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrInstSrc *order) {
- IrInstSrcFence *instruction = ir_build_instruction<IrInstSrcFence>(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<IrInstGenFence>(&ira->new_irb,
- source_instr->scope, source_instr->source_node);
- instruction->order = order;
-
- return &instruction->base;
-}
-
-static IrInstSrc *ir_build_reduce(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrInstSrc *op, IrInstSrc *value) {
- IrInstSrcReduce *instruction = ir_build_instruction<IrInstSrcReduce>(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<IrInstGenReduce>(&ira->new_irb,
- source_instruction->scope, source_instruction->source_node);
- instruction->base.value->type = result_type;
- instruction->op = op;
- instruction->value = value;
-
- ir_ref_inst_gen(value);
-
- 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<IrInstSrcTruncate>(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_truncate_gen(IrAnalyze *ira, IrInst *source_instr, ZigType *dest_type,
- IrInstGen *target)
-{
- IrInstGenTruncate *instruction = ir_build_inst_gen<IrInstGenTruncate>(&ira->new_irb,
- source_instr->scope, source_instr->source_node);
- instruction->base.value->type = dest_type;
- instruction->target = target;
-
- ir_ref_inst_gen(target);
-
- 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<IrInstSrcIntCast>(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<IrInstSrcFloatCast>(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<IrInstSrcErrSetCast>(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<IrInstSrcIntToFloat>(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<IrInstSrcFloatToInt>(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<IrInstSrcBoolToInt>(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<IrInstSrcVectorType>(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<IrInstSrcShuffleVector>(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)
-{
- IrInstGenShuffleVector *inst = ir_build_inst_gen<IrInstGenShuffleVector>(&ira->new_irb, scope, source_node);
- inst->base.value->type = result_type;
- inst->a = a;
- inst->b = b;
- inst->mask = mask;
-
- ir_ref_inst_gen(a);
- ir_ref_inst_gen(b);
- ir_ref_inst_gen(mask);
-
- 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<IrInstSrcSplat>(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)
-{
- IrInstGenSplat *instruction = ir_build_inst_gen<IrInstGenSplat>(
- &ira->new_irb, source_instruction->scope, source_instruction->source_node);
- instruction->base.value->type = result_type;
- instruction->scalar = scalar;
-
- ir_ref_inst_gen(scalar);
-
- return &instruction->base;
-}
-
-static IrInstSrc *ir_build_bool_not(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrInstSrc *value) {
- IrInstSrcBoolNot *instruction = ir_build_instruction<IrInstSrcBoolNot>(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<IrInstGenBoolNot>(&ira->new_irb,
- source_instr->scope, source_instr->source_node);
- instruction->base.value->type = ira->codegen->builtin_types.entry_bool;
- instruction->value = value;
-
- ir_ref_inst_gen(value);
-
- 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<IrInstSrcMemset>(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)
-{
- IrInstGenMemset *instruction = ir_build_inst_void<IrInstGenMemset>(&ira->new_irb,
- source_instr->scope, source_instr->source_node);
- instruction->dest_ptr = dest_ptr;
- instruction->byte = byte;
- instruction->count = count;
-
- ir_ref_inst_gen(dest_ptr);
- ir_ref_inst_gen(byte);
- ir_ref_inst_gen(count);
-
- 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<IrInstSrcMemcpy>(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)
-{
- IrInstGenMemcpy *instruction = ir_build_inst_void<IrInstGenMemcpy>(&ira->new_irb,
- source_instr->scope, source_instr->source_node);
- instruction->dest_ptr = dest_ptr;
- instruction->src_ptr = src_ptr;
- instruction->count = count;
-
- ir_ref_inst_gen(dest_ptr);
- ir_ref_inst_gen(src_ptr);
- ir_ref_inst_gen(count);
-
- 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<IrInstSrcSlice>(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)
-{
- IrInstGenSlice *instruction = ir_build_inst_gen<IrInstGenSlice>(
- &ira->new_irb, source_instruction->scope, source_instruction->source_node);
- instruction->base.value->type = slice_type;
- instruction->ptr = ptr;
- instruction->start = start;
- instruction->end = end;
- instruction->safety_check_on = safety_check_on;
- instruction->result_loc = result_loc;
- instruction->sentinel = sentinel;
-
- ir_ref_inst_gen(ptr);
- ir_ref_inst_gen(start);
- if (end != nullptr) ir_ref_inst_gen(end);
- if (result_loc != nullptr) ir_ref_inst_gen(result_loc);
-
- return &instruction->base;
-}
-
-static IrInstSrc *ir_build_breakpoint(IrBuilderSrc *irb, Scope *scope, AstNode *source_node) {
- IrInstSrcBreakpoint *instruction = ir_build_instruction<IrInstSrcBreakpoint>(irb, scope, source_node);
- return &instruction->base;
-}
-
-static IrInstGen *ir_build_breakpoint_gen(IrAnalyze *ira, IrInst *source_instr) {
- IrInstGenBreakpoint *instruction = ir_build_inst_void<IrInstGenBreakpoint>(&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<IrInstSrcReturnAddress>(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<IrInstGenReturnAddress>(&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<IrInstSrcFrameAddress>(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<IrInstGenFrameAddress>(&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<IrInstSrcFrameHandle>(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<IrInstGenFrameHandle>(&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<IrInstSrcFrameType>(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<IrInstSrcFrameSize>(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<IrInstGenFrameSize>(&ira->new_irb, source_instr->scope, source_instr->source_node);
- inst->base.value->type = ira->codegen->builtin_types.entry_usize;
- inst->fn = fn;
-
- ir_ref_inst_gen(fn);
-
- 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<IrInstSrcOverflowOp>(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)
-{
- IrInstGenOverflowOp *instruction = ir_build_inst_gen<IrInstGenOverflowOp>(&ira->new_irb,
- source_instr->scope, source_instr->source_node);
- instruction->base.value->type = ira->codegen->builtin_types.entry_bool;
- instruction->op = op;
- instruction->op1 = op1;
- instruction->op2 = op2;
- instruction->result_ptr = result_ptr;
- instruction->result_ptr_type = result_ptr_type;
-
- ir_ref_inst_gen(op1);
- ir_ref_inst_gen(op2);
- ir_ref_inst_gen(result_ptr);
-
- 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<IrInstSrcFloatOp>(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)
-{
- IrInstGenFloatOp *instruction = ir_build_inst_gen<IrInstGenFloatOp>(&ira->new_irb,
- source_instr->scope, source_instr->source_node);
- instruction->base.value->type = operand_type;
- instruction->operand = operand;
- instruction->fn_id = fn_id;
-
- ir_ref_inst_gen(operand);
-
- 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<IrInstSrcMulAdd>(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)
-{
- IrInstGenMulAdd *instruction = ir_build_inst_gen<IrInstGenMulAdd>(&ira->new_irb,
- source_instr->scope, source_instr->source_node);
- instruction->base.value->type = expr_type;
- instruction->op1 = op1;
- instruction->op2 = op2;
- instruction->op3 = op3;
-
- ir_ref_inst_gen(op1);
- ir_ref_inst_gen(op2);
- ir_ref_inst_gen(op3);
-
- return &instruction->base;
-}
-
-static IrInstSrc *ir_build_align_of(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrInstSrc *type_value) {
- IrInstSrcAlignOf *instruction = ir_build_instruction<IrInstSrcAlignOf>(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<IrInstSrcTestErr>(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<IrInstGenTestErr>(
- &ira->new_irb, source_instruction->scope, source_instruction->source_node);
- instruction->base.value->type = ira->codegen->builtin_types.entry_bool;
- instruction->err_union = err_union;
-
- ir_ref_inst_gen(err_union);
-
- 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<IrInstSrcUnwrapErrCode>(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)
-{
- IrInstGenUnwrapErrCode *inst = ir_build_inst_gen<IrInstGenUnwrapErrCode>(&ira->new_irb, scope, source_node);
- inst->base.value->type = result_type;
- inst->err_union_ptr = err_union_ptr;
-
- ir_ref_inst_gen(err_union_ptr);
-
- 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<IrInstSrcUnwrapErrPayload>(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)
-{
- IrInstGenUnwrapErrPayload *inst = ir_build_inst_gen<IrInstGenUnwrapErrPayload>(&ira->new_irb, scope, source_node);
- inst->base.value->type = result_type;
- inst->value = value;
- inst->safety_check_on = safety_check_on;
- inst->initializing = initializing;
-
- ir_ref_inst_gen(value);
-
- 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<IrInstSrcFnProto>(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<IrInstSrcTestComptime>(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<IrInstSrcPtrCast>(
- 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)
-{
- IrInstGenPtrCast *instruction = ir_build_inst_gen<IrInstGenPtrCast>(
- &ira->new_irb, source_instruction->scope, source_instruction->source_node);
- instruction->base.value->type = ptr_type;
- instruction->ptr = ptr;
- instruction->safety_check_on = safety_check_on;
-
- ir_ref_inst_gen(ptr);
-
- 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<IrInstSrcImplicitCast>(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<IrInstSrcBitCast>(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)
-{
- IrInstGenBitCast *instruction = ir_build_inst_gen<IrInstGenBitCast>(
- &ira->new_irb, source_instruction->scope, source_instruction->source_node);
- instruction->base.value->type = ty;
- instruction->operand = operand;
-
- ir_ref_inst_gen(operand);
-
- return &instruction->base;
-}
-
-static IrInstGen *ir_build_widen_or_shorten(IrAnalyze *ira, Scope *scope, AstNode *source_node, IrInstGen *target,
- ZigType *result_type)
-{
- IrInstGenWidenOrShorten *inst = ir_build_inst_gen<IrInstGenWidenOrShorten>(&ira->new_irb, scope, source_node);
- inst->base.value->type = result_type;
- inst->target = target;
-
- ir_ref_inst_gen(target);
-
- 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<IrInstSrcIntToPtr>(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)
-{
- IrInstGenIntToPtr *instruction = ir_build_inst_gen<IrInstGenIntToPtr>(&ira->new_irb, scope, source_node);
- instruction->base.value->type = ptr_type;
- instruction->target = target;
-
- ir_ref_inst_gen(target);
-
- 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<IrInstSrcPtrToInt>(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<IrInstGenPtrToInt>(&ira->new_irb, source_instr->scope, source_instr->source_node);
- inst->base.value->type = ira->codegen->builtin_types.entry_usize;
- inst->target = target;
-
- ir_ref_inst_gen(target);
-
- 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<IrInstSrcIntToEnum>(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)
-{
- IrInstGenIntToEnum *instruction = ir_build_inst_gen<IrInstGenIntToEnum>(&ira->new_irb, scope, source_node);
- instruction->base.value->type = dest_type;
- instruction->target = target;
-
- ir_ref_inst_gen(target);
-
- return &instruction->base;
-}
-
-static IrInstSrc *ir_build_enum_to_int(IrBuilderSrc *irb, Scope *scope, AstNode *source_node,
- IrInstSrc *target)
-{
- IrInstSrcEnumToInt *instruction = ir_build_instruction<IrInstSrcEnumToInt>(
- 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<IrInstSrcIntToErr>(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)
-{
- IrInstGenIntToErr *instruction = ir_build_inst_gen<IrInstGenIntToErr>(&ira->new_irb, scope, source_node);
- instruction->base.value->type = wanted_type;
- instruction->target = target;
-
- ir_ref_inst_gen(target);
-
- 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<IrInstSrcErrToInt>(
- 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)
-{
- IrInstGenErrToInt *instruction = ir_build_inst_gen<IrInstGenErrToInt>(&ira->new_irb, scope, source_node);
- instruction->base.value->type = wanted_type;
- instruction->target = target;
-
- ir_ref_inst_gen(target);
-
- 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<IrInstSrcCheckSwitchProngs>();
- 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<IrInstSrcCheckStatementIsVoid>(
- 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<IrInstSrcTypeName>(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<IrInstSrcDeclRef>(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<IrInstSrcPanic>(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<IrInstGenPanic>(&ira->new_irb,
- source_instr->scope, source_instr->source_node);
- instruction->msg = msg;
-
- ir_ref_inst_gen(msg);
-
- return &instruction->base;
-}
-
-static IrInstSrc *ir_build_tag_name_src(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrInstSrc *target) {
- IrInstSrcTagName *instruction = ir_build_instruction<IrInstSrcTagName>(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)
-{
- IrInstGenTagName *instruction = ir_build_inst_gen<IrInstGenTagName>(&ira->new_irb,
- source_instr->scope, source_instr->source_node);
- instruction->base.value->type = result_type;
- instruction->target = target;
-
- ir_ref_inst_gen(target);
-
- 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<IrInstSrcFieldParentPtr>(
- 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)
-{
- IrInstGenFieldParentPtr *inst = ir_build_inst_gen<IrInstGenFieldParentPtr>(&ira->new_irb,
- source_instr->scope, source_instr->source_node);
- inst->base.value->type = result_type;
- inst->field_ptr = field_ptr;
- inst->field = field;
-
- ir_ref_inst_gen(field_ptr);
-
- 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<IrInstSrcByteOffsetOf>(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<IrInstSrcBitOffsetOf>(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<IrInstSrcTypeInfo>(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<IrInstSrcType>(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<IrInstSrcSetEvalBranchQuota>(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<IrInstSrcAlignCast>(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)
-{
- IrInstGenAlignCast *instruction = ir_build_inst_gen<IrInstGenAlignCast>(&ira->new_irb, scope, source_node);
- instruction->base.value->type = result_type;
- instruction->target = target;
-
- ir_ref_inst_gen(target);
-
- 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<IrInstSrcResolveResult>(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<IrInstSrcResetResult>(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<IrInstSrcSetAlignStack>(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<IrInstSrcArgType>();
- 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<IrInstSrcErrorReturnTrace>(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)
-{
- IrInstGenErrorReturnTrace *inst = ir_build_inst_gen<IrInstGenErrorReturnTrace>(&ira->new_irb, scope, source_node);
- inst->base.value->type = result_type;
- 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<IrInstSrcErrorUnion>(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<IrInstSrcAtomicRmw>(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)
-{
- IrInstGenAtomicRmw *instruction = ir_build_inst_gen<IrInstGenAtomicRmw>(&ira->new_irb, source_instr->scope, source_instr->source_node);
- instruction->base.value->type = operand_type;
- instruction->ptr = ptr;
- instruction->op = op;
- instruction->operand = operand;
- instruction->ordering = ordering;
-
- ir_ref_inst_gen(ptr);
- ir_ref_inst_gen(operand);
-
- 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<IrInstSrcAtomicLoad>(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)
-{
- IrInstGenAtomicLoad *instruction = ir_build_inst_gen<IrInstGenAtomicLoad>(&ira->new_irb,
- source_instr->scope, source_instr->source_node);
- instruction->base.value->type = operand_type;
- instruction->ptr = ptr;
- instruction->ordering = ordering;
-
- ir_ref_inst_gen(ptr);
-
- 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<IrInstSrcAtomicStore>(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)
-{
- IrInstGenAtomicStore *instruction = ir_build_inst_void<IrInstGenAtomicStore>(&ira->new_irb,
- source_instr->scope, source_instr->source_node);
- instruction->ptr = ptr;
- instruction->value = value;
- instruction->ordering = ordering;
-
- ir_ref_inst_gen(ptr);
- ir_ref_inst_gen(value);
-
- return &instruction->base;
-}
-
-static IrInstSrc *ir_build_save_err_ret_addr_src(IrBuilderSrc *irb, Scope *scope, AstNode *source_node) {
- IrInstSrcSaveErrRetAddr *inst = ir_build_instruction<IrInstSrcSaveErrRetAddr>(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<IrInstGenSaveErrRetAddr>(&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<IrInstSrcAddImplicitReturnType>(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<IrInstSrcHasDecl>(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<IrInstSrcUndeclaredIdent>(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<IrInstSrcCheckRuntimeScope>(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<IrInstSrcUnionInitNamedField>(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)
-{
- IrInstGenVectorToArray *instruction = ir_build_inst_gen<IrInstGenVectorToArray>(&ira->new_irb,
- source_instruction->scope, source_instruction->source_node);
- instruction->base.value->type = result_type;
- instruction->vector = vector;
- instruction->result_loc = result_loc;
-
- ir_ref_inst_gen(vector);
- ir_ref_inst_gen(result_loc);
-
- return &instruction->base;
-}
-
-static IrInstGen *ir_build_ptr_of_array_to_slice(IrAnalyze *ira, IrInst *source_instruction,
- ZigType *result_type, IrInstGen *operand, IrInstGen *result_loc)
-{
- IrInstGenPtrOfArrayToSlice *instruction = ir_build_inst_gen<IrInstGenPtrOfArrayToSlice>(&ira->new_irb,
- source_instruction->scope, source_instruction->source_node);
- instruction->base.value->type = result_type;
- instruction->operand = operand;
- instruction->result_loc = result_loc;
-
- ir_ref_inst_gen(operand);
- ir_ref_inst_gen(result_loc);
-
- return &instruction->base;
-}
-
-static IrInstGen *ir_build_array_to_vector(IrAnalyze *ira, IrInst *source_instruction,
- IrInstGen *array, ZigType *result_type)
-{
- IrInstGenArrayToVector *instruction = ir_build_inst_gen<IrInstGenArrayToVector>(&ira->new_irb,
- source_instruction->scope, source_instruction->source_node);
- instruction->base.value->type = result_type;
- instruction->array = array;
-
- ir_ref_inst_gen(array);
-
- return &instruction->base;
-}
-
-static IrInstGen *ir_build_assert_zero(IrAnalyze *ira, IrInst *source_instruction,
- IrInstGen *target)
-{
- IrInstGenAssertZero *instruction = ir_build_inst_gen<IrInstGenAssertZero>(&ira->new_irb,
- source_instruction->scope, source_instruction->source_node);
- instruction->base.value->type = ira->codegen->builtin_types.entry_void;
- instruction->target = target;
-
- ir_ref_inst_gen(target);
-
- return &instruction->base;
-}
-
-static IrInstGen *ir_build_assert_non_null(IrAnalyze *ira, IrInst *source_instruction,
- IrInstGen *target)
-{
- IrInstGenAssertNonNull *instruction = ir_build_inst_gen<IrInstGenAssertNonNull>(&ira->new_irb,
- source_instruction->scope, source_instruction->source_node);
- instruction->base.value->type = ira->codegen->builtin_types.entry_void;
- instruction->target = target;
-
- ir_ref_inst_gen(target);
-
- 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<IrInstSrcAlloca>(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)
-{
- IrInstGenAlloca *instruction = ir_create_inst_gen<IrInstGenAlloca>(&ira->new_irb,
- source_instruction->scope, source_instruction->source_node);
- instruction->align = align;
- instruction->name_hint = name_hint;
-
- 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<IrInstSrcEndExpr>(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<IrInstSrcSuspendBegin>(irb, scope, source_node);
-}
-
-static IrInstGen *ir_build_suspend_begin_gen(IrAnalyze *ira, IrInst *source_instr) {
- IrInstGenSuspendBegin *inst = ir_build_inst_void<IrInstGenSuspendBegin>(&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<IrInstSrcSuspendFinish>(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<IrInstGenSuspendFinish>(&ira->new_irb,
- source_instr->scope, source_instr->source_node);
- inst->begin = begin;
-
- ir_ref_inst_gen(&begin->base);
-
- 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<IrInstSrcAwait>(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)
-{
- IrInstGenAwait *instruction = ir_build_inst_gen<IrInstGenAwait>(&ira->new_irb,
- source_instruction->scope, source_instruction->source_node);
- instruction->base.value->type = result_type;
- instruction->frame = frame;
- instruction->result_loc = result_loc;
- instruction->is_nosuspend = is_nosuspend;
-
- ir_ref_inst_gen(frame);
- if (result_loc != nullptr) ir_ref_inst_gen(result_loc);
-
- return instruction;
-}
-
-static IrInstSrc *ir_build_resume_src(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrInstSrc *frame) {
- IrInstSrcResume *instruction = ir_build_instruction<IrInstSrcResume>(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<IrInstGenResume>(&ira->new_irb,
- source_instr->scope, source_instr->source_node);
- instruction->frame = frame;
-
- ir_ref_inst_gen(frame);
-
- 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<IrInstSrcSpillBegin>(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)
-{
- IrInstGenSpillBegin *instruction = ir_build_inst_void<IrInstGenSpillBegin>(&ira->new_irb,
- source_instr->scope, source_instr->source_node);
- instruction->operand = operand;
- instruction->spill_id = spill_id;
-
- ir_ref_inst_gen(operand);
-
- return &instruction->base;
-}
-
-static IrInstSrc *ir_build_spill_end_src(IrBuilderSrc *irb, Scope *scope, AstNode *source_node,
- IrInstSrcSpillBegin *begin)
-{
- IrInstSrcSpillEnd *instruction = ir_build_instruction<IrInstSrcSpillEnd>(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)
-{
- IrInstGenSpillEnd *instruction = ir_build_inst_gen<IrInstGenSpillEnd>(&ira->new_irb,
- source_instr->scope, source_instr->source_node);
- instruction->base.value->type = result_type;
- instruction->begin = begin;
-
- ir_ref_inst_gen(&begin->base);
-
- return &instruction->base;
-}
-
-static IrInstGen *ir_build_vector_extract_elem(IrAnalyze *ira, IrInst *source_instruction,
- IrInstGen *vector, IrInstGen *index)
-{
- IrInstGenVectorExtractElem *instruction = ir_build_inst_gen<IrInstGenVectorExtractElem>(
- &ira->new_irb, source_instruction->scope, source_instruction->source_node);
- instruction->base.value->type = vector->value->type->data.vector.elem_type;
- instruction->vector = vector;
- instruction->index = index;
-
- ir_ref_inst_gen(vector);
- ir_ref_inst_gen(index);
-
- 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<IrInstSrcWasmMemorySize>(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<IrInstGenWasmMemorySize>(&ira->new_irb,
- source_instr->scope, source_instr->source_node);
- instruction->base.value->type = ira->codegen->builtin_types.entry_u32;
- instruction->index = index;
-
- ir_ref_inst_gen(index);
-
- 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<IrInstSrcWasmMemoryGrow>(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<IrInstGenWasmMemoryGrow>(&ira->new_irb,
- source_instr->scope, source_instr->source_node);
- instruction->base.value->type = ira->codegen->builtin_types.entry_i32;
- instruction->index = index;
- instruction->delta = delta;
-
- ir_ref_inst_gen(index);
- ir_ref_inst_gen(delta);
-
- return &instruction->base;
-}
-
-static IrInstSrc *ir_build_src(IrBuilderSrc *irb, Scope *scope, AstNode *source_node) {
- IrInstSrcSrc *instruction = ir_build_instruction<IrInstSrcSrc>(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<ResultLocReturn>();
- 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<ResultLocReturn>();
- 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<ZigVar>();
- 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<ZigValue>();
-
- 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<TldVar *>(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<ResultLocPeer>();
- 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<IrInstSrc *> incoming_values = {0};
- ZigList<IrBasicBlockSrc *> 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<ResultLocPeerParent>();
- 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<ResultLocReturn>();
- 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<ResultLocInstruction>();
- 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<IrInstSrc *>(2);
- incoming_values[0] = val1;
- incoming_values[1] = val2;
- IrBasicBlockSrc **incoming_blocks = heap::c_allocator.allocate<IrBasicBlockSrc *>(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<IrInstSrc *>(2);
- incoming_values[0] = val1;
- incoming_values[1] = val2;
- IrBasicBlockSrc **incoming_blocks = heap::c_allocator.allocate<IrBasicBlockSrc *>(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<ResultLocPeerParent>();
- 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<IrInstSrc *>(2);
- incoming_values[0] = null_result;
- incoming_values[1] = unwrapped_payload;
- IrBasicBlockSrc **incoming_blocks = heap::c_allocator.allocate<IrBasicBlockSrc *>(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<ScopeDecls *>(scope);
- }
- scope = scope->parent;
- }
- TldVar *tld_var = heap::c_allocator.create<TldVar>();
- 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<IrInstSrcConst>(irb, scope, node);
- const_instruction->value = irb->codegen->pass1_arena->create<ZigValue>();
- 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<IrInstSrc*>(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<IrInstSrc*>(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<IrInstSrc*>(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<IrInstSrc*>(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<ResultLocBitCast>();
- 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<IrInstSrc *>(2);
- incoming_values[0] = then_expr_result;
- incoming_values[1] = else_expr_result;
- IrBasicBlockSrc **incoming_blocks = heap::c_allocator.allocate<IrBasicBlockSrc *>(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<ResultLocInstruction>();
- 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<IrInstSrcContainerInitFieldsField>(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<ResultLocInstruction>();
- 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<IrInstSrc *>(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<ResultLocInstruction>();
- 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<ResultLocVar>();
- 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<ResultLocCast>();
- 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<IrInstSrc *> incoming_values = {0};
- ZigList<IrBasicBlockSrc *> 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<IrInstSrc *> incoming_values = {0};
- ZigList<IrBasicBlockSrc *> 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<IrInstSrc *> incoming_values = {0};
- ZigList<IrBasicBlockSrc *> 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<IrInstSrc *> incoming_values = {0};
- ZigList<IrBasicBlockSrc *> 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<AsmToken> *tok_list)
-{
- // TODO Connect the errors in this function back up to the actual source location
- // rather than just the token. https://github.com/ziglang/zig/issues/2080
- enum State {
- StateStart,
- StatePercent,
- StateTemplate,
- StateVar,
- };
-
- assert(tok_list->length == 0);
-
- AsmToken *cur_tok = nullptr;
-
- enum State state = StateStart;
-
- for (size_t i = 0; i < buf_len(asm_template); i += 1) {
- uint8_t c = *((uint8_t*)buf_ptr(asm_template) + i);
- switch (state) {
- case StateStart:
- if (c == '%') {
- tok_list->add_one();
- cur_tok = &tok_list->last();
- cur_tok->id = AsmTokenIdPercent;
- cur_tok->start = i;
- state = StatePercent;
- } else {
- tok_list->add_one();
- cur_tok = &tok_list->last();
- cur_tok->id = AsmTokenIdTemplate;
- cur_tok->start = i;
- state = StateTemplate;
- }
- break;
- case StatePercent:
- if (c == '%') {
- cur_tok->end = i;
- state = StateStart;
- } else if (c == '[') {
- cur_tok->id = AsmTokenIdVar;
- state = StateVar;
- } else if (c == '=') {
- cur_tok->id = AsmTokenIdUniqueId;
- cur_tok->end = i;
- state = StateStart;
- } else {
- add_node_error(ira->codegen, source_node,
- buf_create_from_str("expected a '%' or '['"));
- return ErrorSemanticAnalyzeFail;
- }
- break;
- case StateTemplate:
- if (c == '%') {
- cur_tok->end = i;
- i -= 1;
- cur_tok = nullptr;
- state = StateStart;
- }
- break;
- case StateVar:
- if (c == ']') {
- cur_tok->end = i;
- state = StateStart;
- } else if ((c >= 'a' && c <= 'z') ||
- (c >= '0' && c <= '9') ||
- (c == '_'))
- {
- // do nothing
- } else {
- add_node_error(ira->codegen, source_node,
- buf_sprintf("invalid substitution character: '%c'", c));
- return ErrorSemanticAnalyzeFail;
- }
- break;
- }
- }
-
- switch (state) {
- case StateStart:
- break;
- case StatePercent:
- case StateVar:
- add_node_error(ira->codegen, source_node, buf_sprintf("unexpected end of assembly template"));
- return ErrorSemanticAnalyzeFail;
- case StateTemplate:
- cur_tok->end = buf_len(asm_template);
- break;
- }
- 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<IrInstSrc *>(asm_expr->input_list.length);
- IrInstSrc **output_types = heap::c_allocator.allocate<IrInstSrc *>(asm_expr->output_list.length);
- ZigVar **output_vars = heap::c_allocator.allocate<ZigVar *>(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<IrInstSrc *>(2);
- incoming_values[0] = then_expr_result;
- incoming_values[1] = else_expr_result;
- IrBasicBlockSrc **incoming_blocks = heap::c_allocator.allocate<IrBasicBlockSrc *>(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<IrInstSrc *>(2);
- incoming_values[0] = then_expr_result;
- incoming_values[1] = else_expr_result;
- IrBasicBlockSrc **incoming_blocks = heap::c_allocator.allocate<IrBasicBlockSrc *>(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<IrBasicBlockSrc *> *incoming_blocks, ZigList<IrInstSrc *> *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<IrInstSrcSwitchBrCase> 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<IrInstSrc *> incoming_values = {0};
- ZigList<IrBasicBlockSrc *> incoming_blocks = {0};
- ZigList<IrInstSrcCheckSwitchProngsRange> check_ranges = {0};
-
- IrInstSrcSwitchElseVar *switch_else_var = nullptr;
-
- ResultLocPeerParent *peer_parent = heap::c_allocator.create<ResultLocPeerParent>();
- 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);
- }
- }
+ instruction->base.value->type = operand_type;
+ instruction->ptr = ptr;
+ instruction->ordering = ordering;
- // 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;
+ ir_ref_inst_gen(ptr);
- ResultLocPeer *this_peer_result_loc = create_peer_result(peer_parent);
+ return &instruction->base;
+}
- IrBasicBlockSrc *prong_block = ir_create_basic_block(irb, scope, "SwitchProng");
- IrInstSrc **items = heap::c_allocator.allocate<IrInstSrc *>(prong_item_count);
+static IrInstGen *ir_build_atomic_store_gen(IrAnalyze *ira, IrInst *source_instr,
+ IrInstGen *ptr, IrInstGen *value, AtomicOrder ordering)
+{
+ IrInstGenAtomicStore *instruction = ir_build_inst_void<IrInstGenAtomicStore>(&ira->new_irb,
+ source_instr->scope, source_instr->source_node);
+ instruction->ptr = ptr;
+ instruction->value = value;
+ instruction->ordering = ordering;
- 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);
+ ir_ref_inst_gen(ptr);
+ ir_ref_inst_gen(value);
- 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;
+ return &instruction->base;
+}
- 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;
+static IrInstGen *ir_build_vector_to_array(IrAnalyze *ira, IrInst *source_instruction,
+ ZigType *result_type, IrInstGen *vector, IrInstGen *result_loc)
+{
+ IrInstGenVectorToArray *instruction = ir_build_inst_gen<IrInstGenVectorToArray>(&ira->new_irb,
+ source_instruction->scope, source_instruction->source_node);
+ instruction->base.value->type = result_type;
+ instruction->vector = vector;
+ instruction->result_loc = result_loc;
- items[item_i] = item_value;
- }
+ ir_ref_inst_gen(vector);
+ ir_ref_inst_gen(result_loc);
- 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;
- }
+ return &instruction->base;
+}
- ir_set_cursor_at_end(irb, prev_block);
+static IrInstGen *ir_build_ptr_of_array_to_slice(IrAnalyze *ira, IrInst *source_instruction,
+ ZigType *result_type, IrInstGen *operand, IrInstGen *result_loc)
+{
+ IrInstGenPtrOfArrayToSlice *instruction = ir_build_inst_gen<IrInstGenPtrOfArrayToSlice>(&ira->new_irb,
+ source_instruction->scope, source_instruction->source_node);
+ instruction->base.value->type = result_type;
+ instruction->operand = operand;
+ instruction->result_loc = result_loc;
- }
+ ir_ref_inst_gen(operand);
+ ir_ref_inst_gen(result_loc);
- 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);
+ return &instruction->base;
+}
- 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;
- }
+static IrInstGen *ir_build_array_to_vector(IrAnalyze *ira, IrInst *source_instruction,
+ IrInstGen *array, ZigType *result_type)
+{
+ IrInstGenArrayToVector *instruction = ir_build_inst_gen<IrInstGenArrayToVector>(&ira->new_irb,
+ source_instruction->scope, source_instruction->source_node);
+ instruction->base.value->type = result_type;
+ instruction->array = array;
- 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_ref_inst_gen(array);
- 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);
+ return &instruction->base;
}
-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 IrInstGen *ir_build_assert_zero(IrAnalyze *ira, IrInst *source_instruction,
+ IrInstGen *target)
+{
+ IrInstGenAssertZero *instruction = ir_build_inst_gen<IrInstGenAssertZero>(&ira->new_irb,
+ source_instruction->scope, source_instruction->source_node);
+ instruction->base.value->type = ira->codegen->builtin_types.entry_void;
+ instruction->target = target;
-static IrInstSrc *ir_gen_nosuspend(IrBuilderSrc *irb, Scope *parent_scope, AstNode *node, LVal lval) {
- assert(node->type == NodeTypeNoSuspend);
+ ir_ref_inst_gen(target);
- 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);
+ return &instruction->base;
}
-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);
- }
+static IrInstGen *ir_build_assert_non_null(IrAnalyze *ira, IrInst *source_instruction,
+ IrInstGen *target)
+{
+ IrInstGenAssertNonNull *instruction = ir_build_inst_gen<IrInstGenAssertNonNull>(&ira->new_irb,
+ source_instruction->scope, source_instruction->source_node);
+ instruction->base.value->type = ira->codegen->builtin_types.entry_void;
+ instruction->target = target;
- 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;
+ ir_ref_inst_gen(target);
- 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);
+ return &instruction->base;
}
-static IrInstSrc *ir_gen_break(IrBuilderSrc *irb, Scope *break_scope, AstNode *node) {
- assert(node->type == NodeTypeBreak);
+static IrInstGenAlloca *ir_build_alloca_gen(IrAnalyze *ira, IrInst *source_instruction,
+ uint32_t align, const char *name_hint)
+{
+ IrInstGenAlloca *instruction = ir_create_inst_gen<IrInstGenAlloca>(&ira->new_irb,
+ source_instruction->scope, source_instruction->source_node);
+ instruction->align = align;
+ instruction->name_hint = name_hint;
- // 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
+ return instruction;
+}
- 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;
- }
+static IrInstGen *ir_build_suspend_finish_gen(IrAnalyze *ira, IrInst *source_instr, IrInstGenSuspendBegin *begin) {
+ IrInstGenSuspendFinish *inst = ir_build_inst_void<IrInstGenSuspendFinish>(&ira->new_irb,
+ source_instr->scope, source_instr->source_node);
+ inst->begin = begin;
- 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;
- }
+ ir_ref_inst_gen(&begin->base);
- 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);
+ return &inst->base;
+}
- 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);
- }
+static IrInstGenAwait *ir_build_await_gen(IrAnalyze *ira, IrInst *source_instruction,
+ IrInstGen *frame, ZigType *result_type, IrInstGen *result_loc, bool is_nosuspend)
+{
+ IrInstGenAwait *instruction = ir_build_inst_gen<IrInstGenAwait>(&ira->new_irb,
+ source_instruction->scope, source_instruction->source_node);
+ instruction->base.value->type = result_type;
+ instruction->frame = frame;
+ instruction->result_loc = result_loc;
+ instruction->is_nosuspend = is_nosuspend;
- 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;
+ ir_ref_inst_gen(frame);
+ if (result_loc != nullptr) ir_ref_inst_gen(result_loc);
- 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);
+ return instruction;
}
-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
+static IrInstGen *ir_build_resume_gen(IrAnalyze *ira, IrInst *source_instr, IrInstGen *frame) {
+ IrInstGenResume *instruction = ir_build_inst_void<IrInstGenResume>(&ira->new_irb,
+ source_instr->scope, source_instr->source_node);
+ instruction->frame = frame;
- ZigList<ScopeRuntime *> runtime_scopes = {};
+ ir_ref_inst_gen(frame);
- 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;
- }
+ return &instruction->base;
+}
- 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;
- }
+static IrInstGen *ir_build_spill_begin_gen(IrAnalyze *ira, IrInst *source_instr, IrInstGen *operand,
+ SpillId spill_id)
+{
+ IrInstGenSpillBegin *instruction = ir_build_inst_void<IrInstGenSpillBegin>(&ira->new_irb,
+ source_instr->scope, source_instr->source_node);
+ instruction->operand = operand;
+ instruction->spill_id = spill_id;
- 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();
+ ir_ref_inst_gen(operand);
- 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));
+ return &instruction->base;
}
-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 IrInstGen *ir_build_spill_end_gen(IrAnalyze *ira, IrInst *source_instr, IrInstGenSpillBegin *begin,
+ ZigType *result_type)
+{
+ IrInstGenSpillEnd *instruction = ir_build_inst_gen<IrInstGenSpillEnd>(&ira->new_irb,
+ source_instr->scope, source_instr->source_node);
+ instruction->base.value->type = result_type;
+ instruction->begin = begin;
+
+ ir_ref_inst_gen(&begin->base);
-static IrInstSrc *ir_gen_defer(IrBuilderSrc *irb, Scope *parent_scope, AstNode *node) {
- assert(node->type == NodeTypeDefer);
+ return &instruction->base;
+}
- ScopeDefer *defer_child_scope = create_defer_scope(irb->codegen, node, parent_scope);
- node->data.defer.child_scope = &defer_child_scope->base;
+static IrInstGen *ir_build_vector_extract_elem(IrAnalyze *ira, IrInst *source_instruction,
+ IrInstGen *vector, IrInstGen *index)
+{
+ IrInstGenVectorExtractElem *instruction = ir_build_inst_gen<IrInstGenVectorExtractElem>(
+ &ira->new_irb, source_instruction->scope, source_instruction->source_node);
+ instruction->base.value->type = vector->value->type->data.vector.elem_type;
+ instruction->vector = vector;
+ instruction->index = index;
- ScopeDeferExpr *defer_expr_scope = create_defer_expr_scope(irb->codegen, node, parent_scope);
- node->data.defer.expr_scope = &defer_expr_scope->base;
+ ir_ref_inst_gen(vector);
+ ir_ref_inst_gen(index);
- return ir_build_const_void(irb, parent_scope, node);
+ return &instruction->base;
}
-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;
+static IrInstGen *ir_build_wasm_memory_size_gen(IrAnalyze *ira, IrInst *source_instr, IrInstGen *index) {
+ IrInstGenWasmMemorySize *instruction = ir_build_inst_gen<IrInstGenWasmMemorySize>(&ira->new_irb,
+ source_instr->scope, source_instr->source_node);
+ instruction->base.value->type = ira->codegen->builtin_types.entry_u32;
+ instruction->index = index;
- 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;
+ ir_ref_inst_gen(index);
- IrInstSrc *start_value = ir_gen_node(irb, start_node, scope);
- if (start_value == irb->codegen->invalid_inst_src)
- return irb->codegen->invalid_inst_src;
+ return &instruction->base;
+}
- 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;
- }
+static IrInstGen *ir_build_wasm_memory_grow_gen(IrAnalyze *ira, IrInst *source_instr, IrInstGen *index, IrInstGen *delta) {
+ IrInstGenWasmMemoryGrow *instruction = ir_build_inst_gen<IrInstGenWasmMemoryGrow>(&ira->new_irb,
+ source_instr->scope, source_instr->source_node);
+ instruction->base.value->type = ira->codegen->builtin_types.entry_i32;
+ instruction->index = index;
+ instruction->delta = delta;
- 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;
- }
+ ir_ref_inst_gen(index);
+ ir_ref_inst_gen(delta);
- 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);
+ return &instruction->base;
}
-static IrInstSrc *ir_gen_catch(IrBuilderSrc *irb, Scope *parent_scope, AstNode *node, LVal lval,
- ResultLoc *result_loc)
+static Error parse_asm_template(IrAnalyze *ira, AstNode *source_node, Buf *asm_template,
+ ZigList<AsmToken> *tok_list)
{
- assert(node->type == NodeTypeCatchExpr);
+ // TODO Connect the errors in this function back up to the actual source location
+ // rather than just the token. https://github.com/ziglang/zig/issues/2080
+ enum State {
+ StateStart,
+ StatePercent,
+ StateTemplate,
+ StateVar,
+ };
+
+ assert(tok_list->length == 0);
+
+ AsmToken *cur_tok = nullptr;
- 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;
+ enum State state = StateStart;
- 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;
+ for (size_t i = 0; i < buf_len(asm_template); i += 1) {
+ uint8_t c = *((uint8_t*)buf_ptr(asm_template) + i);
+ switch (state) {
+ case StateStart:
+ if (c == '%') {
+ tok_list->add_one();
+ cur_tok = &tok_list->last();
+ cur_tok->id = AsmTokenIdPercent;
+ cur_tok->start = i;
+ state = StatePercent;
+ } else {
+ tok_list->add_one();
+ cur_tok = &tok_list->last();
+ cur_tok->id = AsmTokenIdTemplate;
+ cur_tok->start = i;
+ state = StateTemplate;
+ }
+ break;
+ case StatePercent:
+ if (c == '%') {
+ cur_tok->end = i;
+ state = StateStart;
+ } else if (c == '[') {
+ cur_tok->id = AsmTokenIdVar;
+ state = StateVar;
+ } else if (c == '=') {
+ cur_tok->id = AsmTokenIdUniqueId;
+ cur_tok->end = i;
+ state = StateStart;
+ } else {
+ add_node_error(ira->codegen, source_node,
+ buf_create_from_str("expected a '%' or '['"));
+ return ErrorSemanticAnalyzeFail;
+ }
+ break;
+ case StateTemplate:
+ if (c == '%') {
+ cur_tok->end = i;
+ i -= 1;
+ cur_tok = nullptr;
+ state = StateStart;
+ }
+ break;
+ case StateVar:
+ if (c == ']') {
+ cur_tok->end = i;
+ state = StateStart;
+ } else if ((c >= 'a' && c <= 'z') ||
+ (c >= '0' && c <= '9') ||
+ (c == '_'))
+ {
+ // do nothing
+ } else {
+ add_node_error(ira->codegen, source_node,
+ buf_sprintf("invalid substitution character: '%c'", c));
+ return ErrorSemanticAnalyzeFail;
+ }
+ break;
}
- 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<IrInstSrc *>(2);
- incoming_values[0] = err_result;
- incoming_values[1] = unwrapped_payload;
- IrBasicBlockSrc **incoming_blocks = heap::c_allocator.allocate<IrBasicBlockSrc *>(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);
+ switch (state) {
+ case StateStart:
+ break;
+ case StatePercent:
+ case StateVar:
+ add_node_error(ira->codegen, source_node, buf_sprintf("unexpected end of assembly template"));
+ return ErrorSemanticAnalyzeFail;
+ case StateTemplate:
+ cur_tok->end = buf_len(asm_template);
+ break;
}
-
- TldContainer *tld_container = heap::c_allocator.create<TldContainer>();
- 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);
+ return ErrorNone;
}
// errors should be populated with set1's values
@@ -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<ErrorTableEntry *>(err_count);
-
- size_t errors_count = irb->codegen->errors_by_index.length + err_count;
- ErrorTableEntry **errors = heap::c_allocator.allocate<ErrorTableEntry *>(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<ErrorTableEntry>();
- 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<IrInstSrc*>(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<ResultLocNone>();
- 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<ResultLocReturn>();
- 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<ScopeDecls *>(scope);
+ }
+ scope = scope->parent;
+ }
+ TldVar *tld_var = heap::c_allocator.create<TldVar>();
+ 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;
-}
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
src/stage1/parser.cpp
@@ -16,28 +16,34 @@
struct ParseContext {
Buf *buf;
- size_t current_token;
- ZigList<Token> *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<PtrPayload> ast_parse_ptr_payload(ParseContext *pc);
static Optional<PtrIndexPayload> 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 Token *peek_token(ParseContext *pc) {
- return peek_token_i(pc, 0);
+static TokenIndex peek_token(ParseContext *pc) {
+ return pc->current_token;
}
-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;
-}
-static BigInt *token_bigint(Token *token) {
- assert(token->id == TokenIdIntLiteral);
- return &token->data.int_lit.bigint;
+ 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 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<T *> 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<TokenId id, BinOpType op>
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<Token> *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<AstNode *> 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<AstNode *> 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<AstNode *> decls = ast_parse_list<AstNode>(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<AsmOutput *> 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<AsmOutput>();
- 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<AsmInput *> 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<AsmInput>();
- 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<Buf *> clobber_list = ast_parse_list<Buf>(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<PtrPayload> ast_parse_ptr_payload(ParseContext *pc) {
- if (eat_token_if(pc, TokenIdBinOr) == nullptr)
+ if (eat_token_if(pc, TokenIdBinOr) == 0)
return Optional<PtrPayload>::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<PtrPayload> ast_parse_ptr_payload(ParseContext *pc) {
// PtrIndexPayload <- PIPE ASTERISK? IDENTIFIER (COMMA IDENTIFIER)? PIPE
static Optional<PtrIndexPayload> ast_parse_ptr_index_payload(ParseContext *pc) {
- if (eat_token_if(pc, TokenIdBinOr) == nullptr)
+ if (eat_token_if(pc, TokenIdBinOr) == 0)
return Optional<PtrIndexPayload>::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<AstNode *> 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);
+}
+
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<Token> *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
src/stage1/stage2.h
@@ -112,6 +112,8 @@ enum Error {
ErrorZigIsTheCCompiler,
ErrorFileBusy,
ErrorLocked,
+ ErrorInvalidCharacter,
+ ErrorUnicodePointTooLarge,
};
// ABI warning
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<Token> *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<ZigList<Token>>();
- t.buf = buf;
- out->line_offsets = heap::c_allocator.create<ZigList<size_t>>();
- 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 '"':
+ begin_token(&t, TokenIdStringLiteral);
+ t.state = TokenizeState_string_literal;
+ break;
+ case '\'':
+ begin_token(&t, TokenIdCharLiteral);
+ t.state = TokenizeState_char_literal;
+ break;
case ALPHA:
case '_':
- t.state = TokenizeStateSymbol;
- begin_token(&t, TokenIdSymbol);
- buf_append_char(&t.cur_tok->data.str_lit.str, c);
+ t.state = TokenizeState_identifier;
+ begin_token(&t, TokenIdIdentifier);
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);
+ case '@':
+ begin_token(&t, TokenIdBuiltin);
+ t.state = TokenizeState_saw_at_sign;
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));
+ case '=':
+ begin_token(&t, TokenIdEq);
+ t.state = TokenizeState_equal;
break;
- case '"':
- begin_token(&t, TokenIdStringLiteral);
- t.state = TokenizeStateString;
+ case '!':
+ begin_token(&t, TokenIdBang);
+ t.state = TokenizeState_bang;
break;
- case '\'':
- begin_token(&t, TokenIdCharLiteral);
- t.state = TokenizeStateCharLiteral;
+ case '|':
+ begin_token(&t, TokenIdBinOr);
+ t.state = TokenizeState_pipe;
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, TokenIdComma);
+ break;
+ case '?':
+ begin_token(&t, TokenIdQuestion);
break;
case ':':
begin_token(&t, TokenIdColon);
- end_token(&t);
break;
- case '#':
- begin_token(&t, TokenIdNumberSign);
- end_token(&t);
+ case '%':
+ begin_token(&t, TokenIdPercent);
+ t.state = TokenizeState_percent;
break;
case '*':
begin_token(&t, TokenIdStar);
- t.state = TokenizeStateSawStar;
+ t.state = TokenizeState_asterisk;
break;
- case '/':
- begin_token(&t, TokenIdSlash);
- t.state = TokenizeStateSawSlash;
+ case '+':
+ begin_token(&t, TokenIdPlus);
+ t.state = TokenizeState_plus;
+ break;
+ case '<':
+ begin_token(&t, TokenIdCmpLessThan);
+ t.state = TokenizeState_angle_bracket_left;
+ break;
+ case '>':
+ begin_token(&t, TokenIdCmpGreaterThan);
+ t.state = TokenizeState_angle_bracket_right;
+ break;
+ case '^':
+ begin_token(&t, TokenIdBinXor);
+ t.state = TokenizeState_caret;
break;
case '\\':
- begin_token(&t, TokenIdMultilineStringLiteral);
- t.state = TokenizeStateSawBackslash;
+ begin_token(&t, TokenIdMultilineStringLiteralLine);
+ t.state = TokenizeState_backslash;
break;
- case '%':
- begin_token(&t, TokenIdPercent);
- t.state = TokenizeStateSawPercent;
+ case '{':
+ begin_token(&t, TokenIdLBrace);
break;
- case '+':
- begin_token(&t, TokenIdPlus);
- t.state = TokenizeStateSawPlus;
+ case '}':
+ begin_token(&t, TokenIdRBrace);
break;
case '~':
begin_token(&t, TokenIdTilde);
- end_token(&t);
break;
- case '@':
- begin_token(&t, TokenIdAtSign);
- t.state = TokenizeStateSawAtSign;
+ case '.':
+ begin_token(&t, TokenIdDot);
+ t.state = TokenizeState_period;
break;
case '-':
begin_token(&t, TokenIdDash);
- t.state = TokenizeStateSawDash;
+ t.state = TokenizeState_minus;
+ break;
+ case '/':
+ begin_token(&t, TokenIdSlash);
+ t.state = TokenizeState_slash;
break;
case '&':
begin_token(&t, TokenIdAmpersand);
- t.state = TokenizeStateSawAmpersand;
+ t.state = TokenizeState_ampersand;
break;
- case '^':
- begin_token(&t, TokenIdBinXor);
- t.state = TokenizeStateSawCaret;
- break;
- case '|':
- begin_token(&t, TokenIdBinOr);
- t.state = TokenizeStateSawBar;
+ case '0':
+ t.state = TokenizeState_zero;
+ begin_token(&t, TokenIdIntLiteral);
break;
- case '=':
- begin_token(&t, TokenIdEq);
- t.state = TokenizeStateSawEq;
+ case DIGIT_NON_ZERO:
+ t.state = TokenizeState_int_literal_dec;
+ begin_token(&t, TokenIdIntLiteral);
break;
- case '!':
- begin_token(&t, TokenIdBang);
- t.state = TokenizeStateSawBang;
+ default:
+ invalid_char_error(&t, c);
+ }
+ break;
+ case TokenizeState_saw_at_sign:
+ switch (c) {
+ case 0:
+ invalid_eof(&t);
+ goto eof;
+ case '"':
+ t.out->ids.last() = TokenIdIdentifier;
+ t.state = TokenizeState_string_literal;
break;
- case '<':
- begin_token(&t, TokenIdCmpLessThan);
- t.state = TokenizeStateSawLessThan;
+ case IDENTIFIER_CHAR:
+ t.state = TokenizeState_builtin;
break;
- case '>':
- begin_token(&t, TokenIdCmpGreaterThan);
- t.state = TokenizeStateSawGreaterThan;
+ default:
+ invalid_char_error(&t, c);
+ }
+ break;
+ case TokenizeState_ampersand:
+ switch (c) {
+ case 0:
+ goto eof;
+ case '&':
+ tokenize_error(&t, "`&&` is invalid. Note that `and` is boolean AND");
break;
- case '.':
- begin_token(&t, TokenIdDot);
- t.state = TokenizeStateSawDot;
+ case '=':
+ t.out->ids.last() = TokenIdBitAndEq;
+ t.state = TokenizeState_start;
break;
default:
- invalid_char_error(&t, c);
+ t.state = TokenizeState_start;
+ continue;
}
break;
- case TokenizeStateSawDot:
+ case TokenizeState_asterisk:
switch (c) {
- case '.':
- t.state = TokenizeStateSawDotDot;
- set_token_id(&t, t.cur_tok, TokenIdEllipsis2);
+ case 0:
+ goto eof;
+ case '=':
+ t.out->ids.last() = TokenIdTimesEq;
+ t.state = TokenizeState_start;
break;
case '*':
- t.state = TokenizeStateSawDotStar;
- set_token_id(&t, t.cur_tok, TokenIdDotStar);
+ 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 TokenizeStateSawDotDot:
+ case TokenizeState_asterisk_percent:
switch (c) {
- case '.':
- t.state = TokenizeStateStart;
- set_token_id(&t, t.cur_tok, TokenIdEllipsis3);
- end_token(&t);
+ case 0:
+ t.out->ids.last() = TokenIdTimesPercent;
+ goto eof;
+ case '=':
+ 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 TokenizeStateSawDotStar:
+ case TokenizeState_percent:
switch (c) {
- case '*':
- tokenize_error(&t, "`.*` can't be followed by `*`. Are you missing a space?");
+ case 0:
+ goto eof;
+ case '=':
+ 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 TokenizeStateSawGreaterThan:
+ case TokenizeState_plus:
switch (c) {
+ case 0:
+ goto eof;
case '=':
- set_token_id(&t, t.cur_tok, TokenIdCmpGreaterOrEq);
- end_token(&t);
- t.state = TokenizeStateStart;
+ t.out->ids.last() = TokenIdPlusEq;
+ t.state = TokenizeState_start;
break;
- case '>':
- set_token_id(&t, t.cur_tok, TokenIdBitShiftRight);
- t.state = TokenizeStateSawGreaterThanGreaterThan;
+ case '+':
+ t.out->ids.last() = TokenIdPlusPlus;
+ t.state = TokenizeState_start;
+ break;
+ case '%':
+ t.state = TokenizeState_plus_percent;
break;
default:
- t.pos -= 1;
- end_token(&t);
- t.state = TokenizeStateStart;
+ t.state = TokenizeState_start;
continue;
}
break;
- case TokenizeStateSawGreaterThanGreaterThan:
+ case TokenizeState_plus_percent:
switch (c) {
+ case 0:
+ t.out->ids.last() = TokenIdPlusPercent;
+ goto eof;
case '=':
- set_token_id(&t, t.cur_tok, TokenIdBitShiftRightEq);
- end_token(&t);
- t.state = TokenizeStateStart;
+ t.out->ids.last() = TokenIdPlusPercentEq;
+ t.state = TokenizeState_start;
break;
default:
- t.pos -= 1;
- end_token(&t);
- t.state = TokenizeStateStart;
+ t.out->ids.last() = TokenIdPlusPercent;
+ t.state = TokenizeState_start;
continue;
}
break;
- case TokenizeStateSawLessThan:
+ case TokenizeState_caret:
switch (c) {
+ case 0:
+ goto eof;
case '=':
- set_token_id(&t, t.cur_tok, TokenIdCmpLessOrEq);
- end_token(&t);
- t.state = TokenizeStateStart;
+ t.out->ids.last() = TokenIdBitXorEq;
+ t.state = TokenizeState_start;
break;
- case '<':
- set_token_id(&t, t.cur_tok, TokenIdBitShiftLeft);
- t.state = TokenizeStateSawLessThanLessThan;
+ default:
+ t.state = TokenizeState_start;
+ continue;
+ }
+ break;
+ 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.pos -= 1;
- end_token(&t);
- t.state = TokenizeStateStart;
+ t.state = TokenizeState_start;
continue;
}
break;
- case TokenizeStateSawLessThanLessThan:
+ case TokenizeState_backslash:
+ switch (c) {
+ case '\\':
+ t.state = TokenizeState_multiline_string_literal_line;
+ break;
+ default:
+ invalid_char_error(&t, c);
+ break;
+ }
+ break;
+ case TokenizeState_string_literal:
+ switch (c) {
+ case 0:
+ invalid_eof(&t);
+ goto eof;
+ case '\\':
+ t.state = TokenizeState_string_literal_backslash;
+ break;
+ case '"':
+ t.state = TokenizeState_start;
+ break;
+ case '\n':
+ case '\r':
+ tokenize_error(&t, "newline not allowed in string literal");
+ break;
+ default:
+ break;
+ }
+ break;
+ case TokenizeState_string_literal_backslash:
+ switch (c) {
+ case 0:
+ invalid_eof(&t);
+ goto eof;
+ case '\n':
+ case '\r':
+ tokenize_error(&t, "newline not allowed in string literal");
+ break;
+ default:
+ t.state = TokenizeState_string_literal;
+ break;
+ }
+ break;
+ case TokenizeState_char_literal:
+ if (c == 0) {
+ invalid_eof(&t);
+ goto eof;
+ } else if (c == '\\') {
+ 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
+ remaining_code_units = 1;
+ t.state = TokenizeState_char_literal_unicode;
+ } else if (c >= 0xe0 && c <= 0xef) {
+ // 1110xxxx
+ remaining_code_units = 2;
+ t.state = TokenizeState_char_literal_unicode;
+ } else if (c >= 0xf0 && c <= 0xf7) {
+ // 11110xxx
+ remaining_code_units = 3;
+ t.state = TokenizeState_char_literal_unicode;
+ } else {
+ t.state = TokenizeState_char_literal_end;
+ }
+ break;
+ case TokenizeState_char_literal_backslash:
+ switch (c) {
+ case 0:
+ invalid_eof(&t);
+ goto eof;
+ case '\n':
+ case '\r':
+ tokenize_error(&t, "newline not allowed in character literal");
+ break;
+ case 'x':
+ 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:
+ t.state = TokenizeState_char_literal_end;
+ break;
+ }
+ break;
+ 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;
+ }
+ break;
+ case TokenizeState_char_literal_unicode_escape_saw_u:
+ switch (c) {
+ case '{':
+ t.state = TokenizeState_char_literal_unicode_escape;
+ seen_escape_digits = 0;
+ break;
+ default:
+ tokenize_error(&t, "expected '{' to begin unicode escape sequence");
+ break;
+ }
+ 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);
+ break;
+ }
+ break;
+ 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 0:
+ goto eof;
+ case '\n':
+ t.state = TokenizeState_start;
+ break;
+ default:
+ break;
+ }
+ break;
+ case TokenizeState_bang:
switch (c) {
+ case 0:
+ goto eof;
case '=':
- set_token_id(&t, t.cur_tok, TokenIdBitShiftLeftEq);
- end_token(&t);
- t.state = TokenizeStateStart;
+ t.out->ids.last() = TokenIdCmpNotEq;
+ t.state = TokenizeState_start;
break;
default:
- t.pos -= 1;
- end_token(&t);
- t.state = TokenizeStateStart;
+ t.state = TokenizeState_start;
continue;
}
break;
- case TokenizeStateSawBang:
+ case TokenizeState_pipe:
switch (c) {
+ case 0:
+ goto eof;
case '=':
- set_token_id(&t, t.cur_tok, TokenIdCmpNotEq);
- end_token(&t);
- t.state = TokenizeStateStart;
+ t.out->ids.last() = TokenIdBitOrEq;
+ t.state = TokenizeState_start;
+ break;
+ case '|':
+ t.out->ids.last() = TokenIdBarBar;
+ t.state = TokenizeState_start;
break;
default:
- t.pos -= 1;
- end_token(&t);
- t.state = TokenizeStateStart;
+ t.state = TokenizeState_start;
continue;
}
break;
- case TokenizeStateSawEq:
+ case TokenizeState_equal:
switch (c) {
+ case 0:
+ goto eof;
case '=':
- set_token_id(&t, t.cur_tok, TokenIdCmpEq);
- end_token(&t);
- t.state = TokenizeStateStart;
+ t.out->ids.last() = TokenIdCmpEq;
+ t.state = TokenizeState_start;
break;
case '>':
- set_token_id(&t, t.cur_tok, TokenIdFatArrow);
- 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 '=':
+ t.out->ids.last() = TokenIdMinusEq;
+ t.state = TokenizeState_start;
+ break;
+ case '%':
+ t.state = TokenizeState_minus_percent;
break;
default:
- t.pos -= 1;
- end_token(&t);
- t.state = TokenizeStateStart;
+ t.state = TokenizeState_start;
continue;
}
break;
- case TokenizeStateSawStar:
+ case TokenizeState_minus_percent:
switch (c) {
+ case 0:
+ t.out->ids.last() = TokenIdMinusPercent;
+ goto eof;
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;
+ t.out->ids.last() = TokenIdMinusPercentEq;
+ t.state = TokenizeState_start;
break;
default:
- t.pos -= 1;
- end_token(&t);
- t.state = TokenizeStateStart;
+ t.out->ids.last() = TokenIdMinusPercent;
+ t.state = TokenizeState_start;
continue;
}
break;
- case TokenizeStateSawStarPercent:
+ case TokenizeState_angle_bracket_left:
switch (c) {
+ case 0:
+ goto eof;
case '=':
- set_token_id(&t, t.cur_tok, TokenIdTimesPercentEq);
- end_token(&t);
- t.state = TokenizeStateStart;
+ t.out->ids.last() = TokenIdCmpLessOrEq;
+ t.state = TokenizeState_start;
+ break;
+ case '<':
+ t.state = TokenizeState_angle_bracket_angle_bracket_left;
break;
default:
- t.pos -= 1;
- end_token(&t);
- t.state = TokenizeStateStart;
+ t.state = TokenizeState_start;
continue;
}
break;
- case TokenizeStateSawPercent:
+ case TokenizeState_angle_bracket_angle_bracket_left:
switch (c) {
+ case 0:
+ t.out->ids.last() = TokenIdBitShiftLeft;
+ goto eof;
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;
+ t.out->ids.last() = TokenIdBitShiftLeftEq;
+ t.state = TokenizeState_start;
break;
default:
- t.pos -= 1;
- end_token(&t);
- t.state = TokenizeStateStart;
+ t.out->ids.last() = TokenIdBitShiftLeft;
+ t.state = TokenizeState_start;
continue;
}
break;
- case TokenizeStateSawPlus:
+ case TokenizeState_angle_bracket_right:
switch (c) {
+ case 0:
+ goto eof;
case '=':
- set_token_id(&t, t.cur_tok, TokenIdPlusEq);
- end_token(&t);
- t.state = TokenizeStateStart;
+ t.out->ids.last() = TokenIdCmpGreaterOrEq;
+ t.state = TokenizeState_start;
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;
+ case '>':
+ t.state = TokenizeState_angle_bracket_angle_bracket_right;
break;
default:
- t.pos -= 1;
- end_token(&t);
- t.state = TokenizeStateStart;
+ t.state = TokenizeState_start;
continue;
}
break;
- case TokenizeStateSawPlusPercent:
+ case TokenizeState_angle_bracket_angle_bracket_right:
switch (c) {
+ case 0:
+ t.out->ids.last() = TokenIdBitShiftRight;
+ goto eof;
case '=':
- set_token_id(&t, t.cur_tok, TokenIdPlusPercentEq);
- end_token(&t);
- t.state = TokenizeStateStart;
+ t.out->ids.last() = TokenIdBitShiftRightEq;
+ t.state = TokenizeState_start;
break;
default:
- t.pos -= 1;
- end_token(&t);
- t.state = TokenizeStateStart;
+ t.out->ids.last() = TokenIdBitShiftRight;
+ t.state = TokenizeState_start;
continue;
}
break;
- case TokenizeStateSawAmpersand:
+ case TokenizeState_period:
switch (c) {
- case '&':
- tokenize_error(&t, "`&&` is invalid. Note that `and` is boolean AND");
+ case 0:
+ goto eof;
+ case '.':
+ t.state = TokenizeState_period_2;
break;
- case '=':
- set_token_id(&t, t.cur_tok, TokenIdBitAndEq);
- end_token(&t);
- t.state = TokenizeStateStart;
+ case '*':
+ t.state = TokenizeState_period_asterisk;
break;
default:
- t.pos -= 1;
- end_token(&t);
- t.state = TokenizeStateStart;
+ t.state = TokenizeState_start;
continue;
}
break;
- case TokenizeStateSawCaret:
+ case TokenizeState_period_2:
switch (c) {
- case '=':
- set_token_id(&t, t.cur_tok, TokenIdBitXorEq);
- end_token(&t);
- t.state = TokenizeStateStart;
+ case 0:
+ t.out->ids.last() = TokenIdEllipsis2;
+ goto eof;
+ case '.':
+ t.out->ids.last() = TokenIdEllipsis3;
+ t.state = TokenizeState_start;
break;
default:
- t.pos -= 1;
- end_token(&t);
- t.state = TokenizeStateStart;
+ t.out->ids.last() = TokenIdEllipsis2;
+ t.state = TokenizeState_start;
continue;
}
break;
- case TokenizeStateSawBar:
+ case TokenizeState_period_asterisk:
switch (c) {
- 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;
+ 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.pos -= 1;
- end_token(&t);
- t.state = TokenizeStateStart;
+ t.out->ids.last() = TokenIdDotStar;
+ t.state = TokenizeState_start;
continue;
}
break;
- case TokenizeStateSawSlash:
+ case TokenizeState_slash:
switch (c) {
+ case 0:
+ goto eof;
case '/':
- t.state = TokenizeStateSawSlash2;
+ t.state = TokenizeState_line_comment_start;
break;
case '=':
- set_token_id(&t, t.cur_tok, TokenIdDivEq);
- end_token(&t);
- t.state = TokenizeStateStart;
+ t.out->ids.last() = TokenIdDivEq;
+ 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_line_comment_start:
switch (c) {
+ case 0:
+ goto eof;
case '/':
- t.state = TokenizeStateSawSlash3;
+ t.state = TokenizeState_doc_comment_start;
break;
case '!':
- t.state = TokenizeStateSawSlashBang;
+ t.out->ids.last() = TokenIdContainerDocComment;
+ t.state = TokenizeState_container_doc_comment;
break;
case '\n':
cancel_token(&t);
- t.state = TokenizeStateStart;
+ t.state = TokenizeState_start;
break;
default:
cancel_token(&t);
- t.state = TokenizeStateLineComment;
+ t.state = TokenizeState_line_comment;
break;
}
break;
- case TokenizeStateSawSlash3:
+ case TokenizeState_doc_comment_start:
switch (c) {
+ case 0:
+ t.out->ids.last() = TokenIdDocComment;
+ goto eof;
case '/':
cancel_token(&t);
- t.state = TokenizeStateLineComment;
+ t.state = TokenizeState_line_comment;
break;
case '\n':
- set_token_id(&t, t.cur_tok, TokenIdDocComment);
- end_token(&t);
- t.state = TokenizeStateStart;
+ t.out->ids.last() = TokenIdDocComment;
+ t.state = TokenizeState_start;
break;
default:
- set_token_id(&t, t.cur_tok, TokenIdDocComment);
- t.state = TokenizeStateDocComment;
+ t.out->ids.last() = TokenIdDocComment;
+ t.state = TokenizeState_doc_comment;
break;
}
break;
- case TokenizeStateSawSlashBang:
+ case TokenizeState_line_comment:
switch (c) {
+ case 0:
+ goto eof;
case '\n':
- set_token_id(&t, t.cur_tok, TokenIdContainerDocComment);
- end_token(&t);
- t.state = TokenizeStateStart;
+ t.state = TokenizeState_start;
break;
default:
- set_token_id(&t, t.cur_tok, TokenIdContainerDocComment);
- t.state = TokenizeStateContainerDocComment;
break;
}
break;
- case TokenizeStateSawBackslash:
+ case TokenizeState_doc_comment:
+ case TokenizeState_container_doc_comment:
switch (c) {
- case '\\':
- t.state = TokenizeStateLineString;
+ case 0:
+ goto eof;
+ case '\n':
+ t.state = TokenizeState_start;
break;
default:
- invalid_char_error(&t, c);
+ // do nothing
break;
}
break;
- case TokenizeStateLineString:
+ case TokenizeState_zero:
switch (c) {
- case '\n':
- t.state = TokenizeStateLineStringEnd;
+ case 0:
+ goto eof;
+ case 'b':
+ t.state = TokenizeState_int_literal_bin_no_underscore;
break;
- default:
- buf_append_char(&t.cur_tok->data.str_lit.str, c);
+ case 'o':
+ t.state = TokenizeState_int_literal_oct_no_underscore;
break;
- }
- break;
- case TokenizeStateLineStringEnd:
- switch (c) {
- case WHITESPACE:
+ case 'x':
+ t.state = TokenizeState_int_literal_hex_no_underscore;
break;
- case '\\':
- t.state = TokenizeStateLineStringContinue;
+ 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.pos -= 1;
- end_token(&t);
- t.state = TokenizeStateStart;
+ t.state = TokenizeState_start;
continue;
}
break;
- case TokenizeStateLineStringContinue:
+ case TokenizeState_int_literal_bin_no_underscore:
switch (c) {
- case '\\':
- t.state = TokenizeStateLineString;
- buf_append_char(&t.cur_tok->data.str_lit.str, '\n');
+ case '0':
+ case '1':
+ t.state = TokenizeState_int_literal_bin;
break;
default:
invalid_char_error(&t, c);
- break;
}
break;
- case TokenizeStateLineComment:
+ case TokenizeState_int_literal_bin:
switch (c) {
- case '\n':
- t.state = TokenizeStateStart;
+ case 0:
+ goto eof;
+ case '_':
+ t.state = TokenizeState_int_literal_bin_no_underscore;
break;
- default:
- // do nothing
+ 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 TokenizeStateDocComment:
+ case TokenizeState_int_literal_oct_no_underscore:
switch (c) {
- case '\n':
- end_token(&t);
- t.state = TokenizeStateStart;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ t.state = TokenizeState_int_literal_oct;
break;
default:
- // do nothing
+ invalid_char_error(&t, c);
break;
}
break;
- case TokenizeStateContainerDocComment:
+ case TokenizeState_int_literal_oct:
switch (c) {
- case '\n':
- end_token(&t);
- t.state = TokenizeStateStart;
+ case 0:
+ goto eof;
+ case '_':
+ t.state = TokenizeState_int_literal_oct_no_underscore;
break;
- default:
- // do nothing
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
break;
- }
- break;
- case TokenizeStateSawAtSign:
- switch (c) {
- case '"':
- set_token_id(&t, t.cur_tok, TokenIdSymbol);
- t.state = TokenizeStateString;
+ case ALPHA:
+ case '8':
+ case '9':
+ invalid_char_error(&t, c);
break;
default:
- t.pos -= 1;
- end_token(&t);
- t.state = TokenizeStateStart;
+ t.state = TokenizeState_start;
continue;
}
break;
- case TokenizeStateSymbol:
+ case TokenizeState_int_literal_dec_no_underscore:
switch (c) {
- case SYMBOL_CHAR:
- buf_append_char(&t.cur_tok->data.str_lit.str, c);
+ case DIGIT:
+ t.state = TokenizeState_int_literal_dec;
break;
default:
- t.pos -= 1;
- end_token(&t);
- t.state = TokenizeStateStart;
- continue;
+ invalid_char_error(&t, c);
+ break;
}
break;
- case TokenizeStateString:
+ case TokenizeState_int_literal_dec:
switch (c) {
- case '"':
- end_token(&t);
- t.state = TokenizeStateStart;
+ case 0:
+ goto eof;
+ case '_':
+ t.state = TokenizeState_int_literal_dec_no_underscore;
break;
- case '\n':
- tokenize_error(&t, "newline not allowed in string literal");
+ case '.':
+ t.state = TokenizeState_num_dot_dec;
+ t.out->ids.last() = TokenIdFloatLiteral;
break;
- case '\\':
- t.state = TokenizeStateStringEscape;
+ case 'e':
+ case 'E':
+ t.state = TokenizeState_float_exponent_unsigned;
+ t.out->ids.last() = TokenIdFloatLiteral;
break;
- default:
- buf_append_char(&t.cur_tok->data.str_lit.str, c);
+ case DIGIT:
+ break;
+ case ALPHA_EXCEPT_E:
+ invalid_char_error(&t, c);
break;
+ default:
+ t.state = TokenizeState_start;
+ continue;
}
break;
- case TokenizeStateStringEscape:
+ case TokenizeState_int_literal_hex_no_underscore:
switch (c) {
- case 'x':
- t.state = TokenizeStateCharCode;
- t.radix = 16;
- t.char_code = 0;
- t.char_code_index = 0;
- t.unicode = false;
+ case HEXDIGIT:
+ t.state = TokenizeState_int_literal_hex;
break;
- case 'u':
- t.state = TokenizeStateStringEscapeUnicodeStart;
- break;
- case 'n':
- handle_string_escape(&t, '\n');
- break;
- case 'r':
- handle_string_escape(&t, '\r');
+ 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 '\\':
- handle_string_escape(&t, '\\');
+ case '.':
+ t.state = TokenizeState_num_dot_hex;
+ t.out->ids.last() = TokenIdFloatLiteral;
break;
- case 't':
- handle_string_escape(&t, '\t');
+ case 'p':
+ case 'P':
+ t.state = TokenizeState_float_exponent_unsigned;
+ t.out->ids.last() = TokenIdFloatLiteral;
break;
- case '\'':
- handle_string_escape(&t, '\'');
+ case HEXDIGIT:
break;
- case '"':
- handle_string_escape(&t, '\"');
+ case ALPHA_EXCEPT_HEX_AND_P:
+ invalid_char_error(&t, c);
break;
default:
- invalid_char_error(&t, c);
+ t.state = TokenizeState_start;
+ continue;
}
break;
- case TokenizeStateStringEscapeUnicodeStart:
+ case TokenizeState_num_dot_dec:
switch (c) {
- case '{':
- t.state = TokenizeStateCharCode;
- t.radix = 16;
- t.char_code = 0;
- t.char_code_index = 0;
- t.unicode = true;
+ case 0:
+ goto eof;
+ case '.':
+ t.out->ids.last() = TokenIdIntLiteral;
+ t.pos -= 1;
+ t.column -= 1;
+ t.state = TokenizeState_start;
+ continue;
+ case 'e':
+ case 'E':
+ t.state = TokenizeState_float_exponent_unsigned;
break;
- default:
+ 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 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();
- }
+ 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;
- }
-
- uint32_t digit_value = get_digit_value(c);
- if (digit_value >= t.radix) {
- tokenize_error(&t, "invalid digit: '%c'", c);
+ case HEXDIGIT:
+ t.out->ids.last() = TokenIdFloatLiteral;
+ t.state = TokenizeState_float_fraction_hex;
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");
- } else if (c == '\\') {
- t.state = TokenizeStateStringEscape;
- } 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;
- } else if (c >= 0xe0 && c <= 0xef) {
- // 1110xxxx
- t.cur_tok->data.char_lit.c = c & 0x0f;
- t.remaining_code_units = 2;
- t.state = TokenizeStateCharLiteralUnicode;
- } else if (c >= 0xf0 && c <= 0xf7) {
- // 11110xxx
- t.cur_tok->data.char_lit.c = c & 0x07;
- t.remaining_code_units = 3;
- t.state = TokenizeStateCharLiteralUnicode;
- } else {
- t.cur_tok->data.char_lit.c = c;
- t.state = TokenizeStateCharLiteralEnd;
+ case ALPHA_EXCEPT_HEX_AND_P:
+ invalid_char_error(&t, c);
+ break;
+ default:
+ t.state = TokenizeState_start;
+ continue;
}
break;
- case TokenizeStateCharLiteralEnd:
+ case TokenizeState_float_fraction_dec_no_underscore:
switch (c) {
- case '\'':
- end_token(&t);
- t.state = TokenizeStateStart;
+ case DIGIT:
+ t.state = TokenizeState_float_fraction_dec;
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:
+ case TokenizeState_float_fraction_dec:
switch (c) {
- case 'b':
- t.radix = 2;
- t.state = TokenizeStateNumberNoUnderscore;
+ case 0:
+ goto eof;
+ case '_':
+ t.state = TokenizeState_float_fraction_dec_no_underscore;
break;
- case 'o':
- t.radix = 8;
- t.state = TokenizeStateNumberNoUnderscore;
+ case 'e':
+ case 'E':
+ t.state = TokenizeState_float_exponent_unsigned;
break;
- case 'x':
- t.radix = 16;
- t.state = TokenizeStateNumberNoUnderscore;
+ case DIGIT:
+ break;
+ case ALPHA_EXCEPT_E:
+ invalid_char_error(&t, c);
break;
default:
- // reinterpret as normal number
- t.pos -= 1;
- t.state = TokenizeStateNumber;
+ t.state = TokenizeState_start;
continue;
}
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_float_fraction_hex_no_underscore:
+ switch (c) {
+ case HEXDIGIT:
+ t.state = TokenizeState_float_fraction_hex;
+ break;
+ default:
+ invalid_char_error(&t, c);
}
- ZIG_FALLTHROUGH;
- case TokenizeStateNumber:
- {
- if (c == '_') {
- t.is_trailing_underscore = true;
- t.state = TokenizeStateNumberNoUnderscore;
+ break;
+ case TokenizeState_float_fraction_hex:
+ switch (c) {
+ case 0:
+ goto eof;
+ case '_':
+ t.state = TokenizeState_float_fraction_hex_no_underscore;
break;
- }
- if (c == '.') {
- if (t.is_trailing_underscore) {
- invalid_char_error(&t, c);
- break;
- }
- t.state = TokenizeStateNumberDot;
+ case 'p':
+ case 'P':
+ t.state = TokenizeState_float_exponent_unsigned;
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);
+ case HEXDIGIT:
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) {
+ case ALPHA_EXCEPT_HEX_AND_P:
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;
+ default:
+ t.state = TokenizeState_start;
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_float_exponent_unsigned:
switch (c) {
case '+':
- t.state = TokenizeStateFloatExponentNumberNoUnderscore;
- break;
case '-':
- t.state = TokenizeStateFloatExponentNumberNoUnderscore;
+ t.state = TokenizeState_float_exponent_num_no_underscore;
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;
+ // Reinterpret as a normal exponent number.
+ t.state = TokenizeState_float_exponent_num_no_underscore;
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_float_exponent_num_no_underscore:
switch (c) {
- case '>':
- set_token_id(&t, t.cur_tok, TokenIdArrow);
- end_token(&t);
- t.state = TokenizeStateStart;
- break;
- case '=':
- set_token_id(&t, t.cur_tok, TokenIdMinusEq);
- end_token(&t);
- t.state = TokenizeStateStart;
- break;
- case '%':
- set_token_id(&t, t.cur_tok, TokenIdMinusPercent);
- t.state = TokenizeStateSawMinusPercent;
+ case DIGIT:
+ t.state = TokenizeState_float_exponent_num;
break;
default:
- t.pos -= 1;
- end_token(&t);
- t.state = TokenizeStateStart;
- continue;
+ invalid_char_error(&t, c);
}
break;
- case TokenizeStateSawMinusPercent:
+ case TokenizeState_float_exponent_num:
switch (c) {
- case '=':
- set_token_id(&t, t.cur_tok, TokenIdMinusPercentEq);
- end_token(&t);
- t.state = TokenizeStateStart;
+ 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.pos -= 1;
- end_token(&t);
- t.state = TokenizeStateStart;
+ 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<Token> *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;
-}
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;
-};
-
-struct TokenIntLit {
- BigInt bigint;
-};
-
-struct TokenStrLit {
- Buf str;
-};
-struct TokenCharLit {
- uint32_t c;
+ TokenIdCount,
};
-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;
+typedef uint32_t TokenIndex;
- // TokenIdStringLiteral, TokenIdMultilineStringLiteral or TokenIdSymbol
- TokenStrLit str_lit;
-
- // TokenIdCharLiteral
- TokenCharLit char_lit;
- } data;
+struct TokenLoc {
+ uint32_t offset;
+ uint32_t line;
+ uint32_t column;
};
-// work around conflicting name Token which is also found in libclang
-typedef Token ZigToken;
struct Tokenization {
- ZigList<Token> *tokens;
- ZigList<size_t> *line_offsets;
+ ZigList<TokenId> ids;
+ ZigList<TokenLoc> 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<Token> *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
src/stage1.zig
@@ -252,6 +252,8 @@ const Error = extern enum {
ZigIsTheCCompiler,
FileBusy,
Locked,
+ InvalidCharacter,
+ UnicodePointTooLarge,
};
// ABI warning
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" {
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"