diff options
| author | BenoitJGirard <BenoitJGirard@users.noreply.github.com> | 2019-02-17 14:38:55 -0500 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2019-02-17 14:38:55 -0500 |
| commit | 6daa041932ae5ab03eed953dacf3ca506078390c (patch) | |
| tree | 0f51f6c2ff84dde51b61bba6799e5c5abccf91b4 /src/analyze.cpp | |
| parent | f0ec308e26ff957c7fbb50ccc69d3d549c42c4da (diff) | |
| parent | 8d2a902945ef97f28152c3d5a68bb974809c8539 (diff) | |
| download | zig-6daa041932ae5ab03eed953dacf3ca506078390c.tar.gz zig-6daa041932ae5ab03eed953dacf3ca506078390c.zip | |
Merge pull request #2 from ziglang/master
Refreshing fork.
Diffstat (limited to 'src/analyze.cpp')
| -rw-r--r-- | src/analyze.cpp | 919 |
1 files changed, 651 insertions, 268 deletions
diff --git a/src/analyze.cpp b/src/analyze.cpp index 2f4b173c5f..9941104bc4 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -28,28 +28,10 @@ static Error ATTRIBUTE_MUST_USE resolve_enum_zero_bits(CodeGen *g, ZigType *enum static Error ATTRIBUTE_MUST_USE resolve_union_zero_bits(CodeGen *g, ZigType *union_type); static void analyze_fn_body(CodeGen *g, ZigFn *fn_table_entry); -ErrorMsg *add_node_error(CodeGen *g, AstNode *node, Buf *msg) { - if (node->owner->c_import_node != nullptr) { - // if this happens, then translate_c generated code that - // failed semantic analysis, which isn't supposed to happen - ErrorMsg *err = add_node_error(g, node->owner->c_import_node, - buf_sprintf("compiler bug: @cImport generated invalid zig code")); - - add_error_note(g, err, node, msg); - - g->errors.append(err); - return err; - } - - ErrorMsg *err = err_msg_create_with_line(node->owner->path, node->line, node->column, - node->owner->source_code, node->owner->line_offsets, msg); - - g->errors.append(err); - return err; -} - -ErrorMsg *add_error_note(CodeGen *g, ErrorMsg *parent_msg, AstNode *node, Buf *msg) { - if (node->owner->c_import_node != nullptr) { +static ErrorMsg *add_error_note_token(CodeGen *g, ErrorMsg *parent_msg, ImportTableEntry *owner, Token *token, + Buf *msg) +{ + if (owner->c_import_node != nullptr) { // if this happens, then translate_c generated code that // failed semantic analysis, which isn't supposed to happen @@ -64,13 +46,46 @@ ErrorMsg *add_error_note(CodeGen *g, ErrorMsg *parent_msg, AstNode *node, Buf *m return note; } - ErrorMsg *err = err_msg_create_with_line(node->owner->path, node->line, node->column, - node->owner->source_code, node->owner->line_offsets, msg); + ErrorMsg *err = err_msg_create_with_line(owner->path, token->start_line, token->start_column, + owner->source_code, owner->line_offsets, msg); err_msg_add_note(parent_msg, err); return err; } +ErrorMsg *add_token_error(CodeGen *g, ImportTableEntry *owner, Token *token, Buf *msg) { + if (owner->c_import_node != nullptr) { + // if this happens, then translate_c generated code that + // failed semantic analysis, which isn't supposed to happen + ErrorMsg *err = add_node_error(g, owner->c_import_node, + buf_sprintf("compiler bug: @cImport generated invalid zig code")); + + add_error_note_token(g, err, owner, token, msg); + + g->errors.append(err); + return err; + } + ErrorMsg *err = err_msg_create_with_line(owner->path, token->start_line, token->start_column, + owner->source_code, owner->line_offsets, msg); + + g->errors.append(err); + return err; +} + +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; + return add_token_error(g, node->owner, &fake_token, msg); +} + +ErrorMsg *add_error_note(CodeGen *g, ErrorMsg *parent_msg, 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); +} + ZigType *new_type_table_entry(ZigTypeId id) { ZigType *entry = allocate<ZigType>(1); entry->id = id; @@ -250,6 +265,7 @@ AstNode *type_decl_node(ZigType *type_entry) { case ZigTypeIdBoundFn: case ZigTypeIdArgTuple: case ZigTypeIdPromise: + case ZigTypeIdVector: return nullptr; } zig_unreachable(); @@ -311,6 +327,7 @@ bool type_is_resolved(ZigType *type_entry, ResolveStatus status) { case ZigTypeIdBoundFn: case ZigTypeIdArgTuple: case ZigTypeIdPromise: + case ZigTypeIdVector: return true; } zig_unreachable(); @@ -339,6 +356,28 @@ uint64_t type_size(CodeGen *g, ZigType *type_entry) { } } + return LLVMABISizeOfType(g->target_data_ref, type_entry->type_ref); +} + +uint64_t type_size_store(CodeGen *g, ZigType *type_entry) { + assert(type_is_complete(type_entry)); + + if (!type_has_bits(type_entry)) + return 0; + + if (type_entry->id == ZigTypeIdStruct && type_entry->data.structure.layout == ContainerLayoutPacked) { + uint64_t size_in_bits = type_size_bits(g, type_entry); + return (size_in_bits + 7) / 8; + } else if (type_entry->id == ZigTypeIdArray) { + ZigType *child_type = type_entry->data.array.child_type; + if (child_type->id == ZigTypeIdStruct && + child_type->data.structure.layout == ContainerLayoutPacked) + { + uint64_t size_in_bits = type_size_bits(g, type_entry); + return (size_in_bits + 7) / 8; + } + } + return LLVMStoreSizeOfType(g->target_data_ref, type_entry->type_ref); } @@ -400,9 +439,25 @@ ZigType *get_promise_type(CodeGen *g, ZigType *result_type) { return entry; } +static const char *ptr_len_to_star_str(PtrLen ptr_len) { + switch (ptr_len) { + case PtrLenSingle: + return "*"; + case PtrLenUnknown: + return "[*]"; + case PtrLenC: + return "[*c]"; + } + zig_unreachable(); +} + ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_const, - bool is_volatile, PtrLen ptr_len, uint32_t byte_alignment, uint32_t bit_offset_in_host, uint32_t host_int_bytes) + bool is_volatile, PtrLen ptr_len, uint32_t byte_alignment, + uint32_t bit_offset_in_host, uint32_t host_int_bytes) { + // TODO when implementing https://github.com/ziglang/zig/issues/1953 + // move this to a parameter + bool allow_zero = (ptr_len == PtrLenC); assert(!type_is_invalid(child_type)); assert(ptr_len == PtrLenSingle || child_type->id != ZigTypeIdOpaque); @@ -422,7 +477,7 @@ ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_cons TypeId type_id = {}; ZigType **parent_pointer = nullptr; - if (host_int_bytes != 0 || is_volatile || byte_alignment != 0 || ptr_len != PtrLenSingle) { + if (host_int_bytes != 0 || is_volatile || byte_alignment != 0 || ptr_len != PtrLenSingle || allow_zero) { type_id.id = ZigTypeIdPointer; type_id.data.pointer.child_type = child_type; type_id.data.pointer.is_const = is_const; @@ -431,6 +486,7 @@ ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_cons type_id.data.pointer.bit_offset_in_host = bit_offset_in_host; type_id.data.pointer.host_int_bytes = host_int_bytes; type_id.data.pointer.ptr_len = ptr_len; + type_id.data.pointer.allow_zero = allow_zero; auto existing_entry = g->type_table.maybe_get(type_id); if (existing_entry) @@ -448,21 +504,31 @@ ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_cons ZigType *entry = new_type_table_entry(ZigTypeIdPointer); - const char *star_str = ptr_len == PtrLenSingle ? "*" : "[*]"; + const char *star_str = ptr_len_to_star_str(ptr_len); const char *const_str = is_const ? "const " : ""; const char *volatile_str = is_volatile ? "volatile " : ""; + const char *allow_zero_str; + if (ptr_len == PtrLenC) { + assert(allow_zero); + allow_zero_str = ""; + } else { + allow_zero_str = allow_zero ? "allowzero " : ""; + } buf_resize(&entry->name, 0); if (host_int_bytes == 0 && byte_alignment == 0) { - buf_appendf(&entry->name, "%s%s%s%s", star_str, const_str, volatile_str, buf_ptr(&child_type->name)); + buf_appendf(&entry->name, "%s%s%s%s%s", + star_str, const_str, volatile_str, allow_zero_str, buf_ptr(&child_type->name)); } else if (host_int_bytes == 0) { - buf_appendf(&entry->name, "%salign(%" PRIu32 ") %s%s%s", star_str, byte_alignment, - const_str, volatile_str, buf_ptr(&child_type->name)); + buf_appendf(&entry->name, "%salign(%" PRIu32 ") %s%s%s%s", star_str, byte_alignment, + const_str, volatile_str, allow_zero_str, buf_ptr(&child_type->name)); } else if (byte_alignment == 0) { - buf_appendf(&entry->name, "%salign(:%" PRIu32 ":%" PRIu32 ") %s%s%s", star_str, - bit_offset_in_host, host_int_bytes, const_str, volatile_str, buf_ptr(&child_type->name)); + buf_appendf(&entry->name, "%salign(:%" PRIu32 ":%" PRIu32 ") %s%s%s%s", star_str, + bit_offset_in_host, host_int_bytes, const_str, volatile_str, allow_zero_str, + buf_ptr(&child_type->name)); } else { - buf_appendf(&entry->name, "%salign(%" PRIu32 ":%" PRIu32 ":%" PRIu32 ") %s%s%s", star_str, byte_alignment, - bit_offset_in_host, host_int_bytes, const_str, volatile_str, buf_ptr(&child_type->name)); + buf_appendf(&entry->name, "%salign(%" PRIu32 ":%" PRIu32 ":%" PRIu32 ") %s%s%s%s", star_str, byte_alignment, + bit_offset_in_host, host_int_bytes, const_str, volatile_str, allow_zero_str, + buf_ptr(&child_type->name)); } assert(child_type->id != ZigTypeIdInvalid); @@ -470,7 +536,9 @@ ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_cons entry->zero_bits = !type_has_bits(child_type); if (!entry->zero_bits) { - if (is_const || is_volatile || byte_alignment != 0 || ptr_len != PtrLenSingle || bit_offset_in_host != 0) { + if (is_const || is_volatile || byte_alignment != 0 || ptr_len != PtrLenSingle || + bit_offset_in_host != 0 || allow_zero) + { ZigType *peer_type = get_pointer_to_type_extra(g, child_type, false, false, PtrLenSingle, 0, 0, host_int_bytes); entry->type_ref = peer_type->type_ref; @@ -504,6 +572,7 @@ ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_cons entry->data.pointer.explicit_alignment = byte_alignment; entry->data.pointer.bit_offset_in_host = bit_offset_in_host; entry->data.pointer.host_int_bytes = host_int_bytes; + entry->data.pointer.allow_zero = allow_zero; if (parent_pointer) { *parent_pointer = entry; @@ -569,13 +638,16 @@ ZigType *get_optional_type(CodeGen *g, ZigType *child_type) { if (child_type->zero_bits) { entry->type_ref = LLVMInt1Type(); entry->di_type = g->builtin_types.entry_bool->di_type; - } else if (type_is_codegen_pointer(child_type)) { + } else if (type_is_codegen_pointer(child_type) || child_type->id == ZigTypeIdErrorSet) { assert(child_type->di_type); // this is an optimization but also is necessary for calling C // functions where all pointers are maybe pointers // function types are technically pointers entry->type_ref = child_type->type_ref; entry->di_type = child_type->di_type; + if (entry->di_type == g->builtin_types.entry_global_error_set->di_type) { + g->error_di_types.append(&entry->di_type); + } } else { assert(child_type->di_type); // create a struct with a boolean whether this is the null value @@ -817,7 +889,7 @@ ZigType *get_slice_type(CodeGen *g, ZigType *ptr_type) { ZigType *child_type = ptr_type->data.pointer.child_type; if (ptr_type->data.pointer.is_const || ptr_type->data.pointer.is_volatile || - ptr_type->data.pointer.explicit_alignment != 0) + ptr_type->data.pointer.explicit_alignment != 0 || ptr_type->data.pointer.allow_zero) { ZigType *peer_ptr_type = get_pointer_to_type_extra(g, child_type, false, false, PtrLenUnknown, 0, 0, 0); @@ -840,7 +912,7 @@ ZigType *get_slice_type(CodeGen *g, ZigType *ptr_type) { ZigType *child_ptr_type = child_type->data.structure.fields[slice_ptr_index].type_entry; assert(child_ptr_type->id == ZigTypeIdPointer); if (child_ptr_type->data.pointer.is_const || child_ptr_type->data.pointer.is_volatile || - child_ptr_type->data.pointer.explicit_alignment != 0) + child_ptr_type->data.pointer.explicit_alignment != 0 || child_ptr_type->data.pointer.allow_zero) { ZigType *grand_child_type = child_ptr_type->data.pointer.child_type; ZigType *bland_child_ptr_type = get_pointer_to_type_extra(g, grand_child_type, false, false, @@ -1054,11 +1126,7 @@ bool want_first_arg_sret(CodeGen *g, FnTypeId *fn_type_id) { } if (g->zig_target.arch.arch == ZigLLVM_x86_64) { X64CABIClass abi_class = type_c_abi_x86_64_class(g, fn_type_id->return_type); - if (abi_class == X64CABIClass_MEMORY) { - return true; - } - zig_panic("TODO implement C ABI for x86_64 return types. type '%s'\nSee https://github.com/ziglang/zig/issues/1481", - buf_ptr(&fn_type_id->return_type->name)); + return abi_class == X64CABIClass_MEMORY; } else if (target_is_arm(&g->zig_target)) { return type_size(g, fn_type_id->return_type) > 16; } @@ -1219,7 +1287,10 @@ ZigType *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) { fn_type->data.fn.raw_type_ref = LLVMFunctionType(gen_return_type->type_ref, gen_param_types.items, (unsigned int)gen_param_types.length, fn_type_id->is_var_args); fn_type->type_ref = LLVMPointerType(fn_type->data.fn.raw_type_ref, 0); - fn_type->di_type = ZigLLVMCreateSubroutineType(g->dbuilder, param_di_types.items, (int)param_di_types.length, 0); + fn_type->data.fn.raw_di_type = ZigLLVMCreateSubroutineType(g->dbuilder, param_di_types.items, (int)param_di_types.length, 0); + fn_type->di_type = ZigLLVMCreateDebugPointerType(g->dbuilder, fn_type->data.fn.raw_di_type, + LLVMStoreSizeOfType(g->target_data_ref, fn_type->type_ref), + LLVMABIAlignmentOfType(g->target_data_ref, fn_type->type_ref), ""); } g->fn_type_table.put(&fn_type->data.fn.fn_type_id, fn_type); @@ -1274,20 +1345,22 @@ ZigType *get_partial_container_type(CodeGen *g, Scope *scope, ContainerKind kind return entry; } -static IrInstruction *analyze_const_value(CodeGen *g, Scope *scope, AstNode *node, ZigType *type_entry, Buf *type_name) { +static ConstExprValue *analyze_const_value(CodeGen *g, Scope *scope, AstNode *node, ZigType *type_entry, + Buf *type_name) +{ size_t backward_branch_count = 0; return ir_eval_const_value(g, scope, node, type_entry, &backward_branch_count, default_backward_branch_quota, - nullptr, nullptr, node, type_name, nullptr); + nullptr, nullptr, node, type_name, nullptr, nullptr); } ZigType *analyze_type_expr(CodeGen *g, Scope *scope, AstNode *node) { - IrInstruction *result = analyze_const_value(g, scope, node, g->builtin_types.entry_type, nullptr); - if (result->value.type->id == ZigTypeIdInvalid) + ConstExprValue *result = analyze_const_value(g, scope, node, g->builtin_types.entry_type, nullptr); + if (type_is_invalid(result->type)) return g->builtin_types.entry_invalid; - assert(result->value.special != ConstValSpecialRuntime); - return result->value.data.x_type; + assert(result->special != ConstValSpecialRuntime); + return result->data.x_type; } ZigType *get_generic_fn_type(CodeGen *g, FnTypeId *fn_type_id) { @@ -1338,11 +1411,11 @@ void init_fn_type_id(FnTypeId *fn_type_id, AstNode *proto_node, size_t param_cou } static bool analyze_const_align(CodeGen *g, Scope *scope, AstNode *node, uint32_t *result) { - IrInstruction *align_result = analyze_const_value(g, scope, node, get_align_amt_type(g), nullptr); - if (type_is_invalid(align_result->value.type)) + ConstExprValue *align_result = analyze_const_value(g, scope, node, get_align_amt_type(g), nullptr); + if (type_is_invalid(align_result->type)) return false; - uint32_t align_bytes = bigint_as_unsigned(&align_result->value.data.x_bigint); + uint32_t align_bytes = bigint_as_unsigned(&align_result->data.x_bigint); if (align_bytes == 0) { add_node_error(g, node, buf_sprintf("alignment must be >= 1")); return false; @@ -1360,12 +1433,12 @@ static bool analyze_const_string(CodeGen *g, Scope *scope, AstNode *node, Buf ** ZigType *ptr_type = get_pointer_to_type_extra(g, g->builtin_types.entry_u8, true, false, PtrLenUnknown, 0, 0, 0); ZigType *str_type = get_slice_type(g, ptr_type); - IrInstruction *instr = analyze_const_value(g, scope, node, str_type, nullptr); - if (type_is_invalid(instr->value.type)) + ConstExprValue *result_val = analyze_const_value(g, scope, node, str_type, nullptr); + if (type_is_invalid(result_val->type)) return false; - ConstExprValue *ptr_field = &instr->value.data.x_struct.fields[slice_ptr_index]; - ConstExprValue *len_field = &instr->value.data.x_struct.fields[slice_len_index]; + ConstExprValue *ptr_field = &result_val->data.x_struct.fields[slice_ptr_index]; + ConstExprValue *len_field = &result_val->data.x_struct.fields[slice_len_index]; assert(ptr_field->data.x_ptr.special == ConstPtrSpecialBaseArray); ConstExprValue *array_val = ptr_field->data.x_ptr.data.base_array.array_val; @@ -1418,6 +1491,7 @@ static bool type_allowed_in_packed_struct(ZigType *type_entry) { case ZigTypeIdPointer: case ZigTypeIdArray: case ZigTypeIdFn: + case ZigTypeIdVector: return true; case ZigTypeIdStruct: return type_entry->data.structure.layout == ContainerLayoutPacked; @@ -1434,7 +1508,7 @@ static bool type_allowed_in_packed_struct(ZigType *type_entry) { zig_unreachable(); } -static bool type_allowed_in_extern(CodeGen *g, ZigType *type_entry) { +bool type_allowed_in_extern(CodeGen *g, ZigType *type_entry) { switch (type_entry->id) { case ZigTypeIdInvalid: zig_unreachable(); @@ -1466,6 +1540,8 @@ static bool type_allowed_in_extern(CodeGen *g, ZigType *type_entry) { default: return false; } + case ZigTypeIdVector: + return type_allowed_in_extern(g, type_entry->data.vector.elem_type); case ZigTypeIdFloat: return true; case ZigTypeIdArray: @@ -1619,6 +1695,7 @@ static ZigType *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_sc case ZigTypeIdUnion: case ZigTypeIdFn: case ZigTypeIdPromise: + case ZigTypeIdVector: switch (type_requires_comptime(g, type_entry)) { case ReqCompTimeNo: break; @@ -1714,6 +1791,7 @@ static ZigType *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_sc case ZigTypeIdUnion: case ZigTypeIdFn: case ZigTypeIdPromise: + case ZigTypeIdVector: switch (type_requires_comptime(g, fn_type_id.return_type)) { case ReqCompTimeInvalid: return g->builtin_types.entry_invalid; @@ -2500,20 +2578,20 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) { // In this first pass we resolve explicit tag values. // In a second pass we will fill in the unspecified ones. if (tag_value != nullptr) { - IrInstruction *result_inst = analyze_const_value(g, scope, tag_value, tag_int_type, nullptr); - if (result_inst->value.type->id == ZigTypeIdInvalid) { + ConstExprValue *result = analyze_const_value(g, scope, tag_value, tag_int_type, nullptr); + if (type_is_invalid(result->type)) { enum_type->data.enumeration.is_invalid = true; continue; } - assert(result_inst->value.special != ConstValSpecialRuntime); - assert(result_inst->value.type->id == ZigTypeIdInt || - result_inst->value.type->id == ZigTypeIdComptimeInt); - auto entry = occupied_tag_values.put_unique(result_inst->value.data.x_bigint, tag_value); + assert(result->special != ConstValSpecialRuntime); + assert(result->type->id == ZigTypeIdInt || + result->type->id == ZigTypeIdComptimeInt); + auto entry = occupied_tag_values.put_unique(result->data.x_bigint, tag_value); if (entry == nullptr) { - bigint_init_bigint(&type_enum_field->value, &result_inst->value.data.x_bigint); + bigint_init_bigint(&type_enum_field->value, &result->data.x_bigint); } else { Buf *val_buf = buf_alloc(); - bigint_append_buf(val_buf, &result_inst->value.data.x_bigint, 10); + bigint_append_buf(val_buf, &result->data.x_bigint, 10); ErrorMsg *msg = add_node_error(g, tag_value, buf_sprintf("enum tag value %s already taken", buf_ptr(val_buf))); @@ -2623,6 +2701,13 @@ static Error resolve_struct_zero_bits(CodeGen *g, ZigType *struct_type) { buf_sprintf("enums, not structs, support field assignment")); } + if (field_type->id == ZigTypeIdOpaque) { + add_node_error(g, field_node->data.struct_field.type, + buf_sprintf("opaque types have unknown size and therefore cannot be directly embedded in structs")); + struct_type->data.structure.resolve_status = ResolveStatusInvalid; + continue; + } + switch (type_requires_comptime(g, field_type)) { case ReqCompTimeYes: struct_type->data.structure.requires_comptime = true; @@ -2680,39 +2765,50 @@ static Error resolve_struct_alignment(CodeGen *g, ZigType *struct_type) { assert(decl_node->type == NodeTypeContainerDecl); assert(struct_type->di_type); + size_t field_count = struct_type->data.structure.src_field_count; if (struct_type->data.structure.layout == ContainerLayoutPacked) { struct_type->data.structure.abi_alignment = 1; - } - - size_t field_count = struct_type->data.structure.src_field_count; - for (size_t i = 0; i < field_count; i += 1) { - TypeStructField *field = &struct_type->data.structure.fields[i]; - - // If this assertion trips, look up the call stack. Probably something is - // calling type_resolve with ResolveStatusAlignmentKnown when it should only - // be resolving ResolveStatusZeroBitsKnown - assert(field->type_entry != nullptr); - - if (type_is_invalid(field->type_entry)) { - struct_type->data.structure.resolve_status = ResolveStatusInvalid; - break; + for (size_t i = 0; i < field_count; i += 1) { + TypeStructField *field = &struct_type->data.structure.fields[i]; + if (field->type_entry != nullptr && type_is_invalid(field->type_entry)) { + struct_type->data.structure.resolve_status = ResolveStatusInvalid; + break; + } } + } else for (size_t i = 0; i < field_count; i += 1) { + TypeStructField *field = &struct_type->data.structure.fields[i]; + uint32_t this_field_align; + + // TODO If we have no type_entry for the field, we've already failed to + // compile the program correctly. This stage1 compiler needs a deeper + // reworking to make this correct, or we can ignore the problem + // and make sure it is fixed in stage2. This workaround is for when + // there is a false positive of a dependency loop, of alignment depending + // on itself. When this false positive happens we assume a pointer-aligned + // field, which is usually fine but could be incorrectly over-aligned or + // even under-aligned. See https://github.com/ziglang/zig/issues/1512 + if (field->type_entry == nullptr) { + this_field_align = LLVMABIAlignmentOfType(g->target_data_ref, LLVMPointerType(LLVMInt8Type(), 0)); + } else { + if (type_is_invalid(field->type_entry)) { + struct_type->data.structure.resolve_status = ResolveStatusInvalid; + break; + } - if (!type_has_bits(field->type_entry)) - continue; + if (!type_has_bits(field->type_entry)) + continue; - // alignment of structs is the alignment of the most-aligned field - if (struct_type->data.structure.layout != ContainerLayoutPacked) { if ((err = type_resolve(g, field->type_entry, ResolveStatusAlignmentKnown))) { struct_type->data.structure.resolve_status = ResolveStatusInvalid; break; } - uint32_t this_field_align = get_abi_alignment(g, field->type_entry); + this_field_align = get_abi_alignment(g, field->type_entry); assert(this_field_align != 0); - if (this_field_align > struct_type->data.structure.abi_alignment) { - struct_type->data.structure.abi_alignment = this_field_align; - } + } + // alignment of structs is the alignment of the most-aligned field + if (this_field_align > struct_type->data.structure.abi_alignment) { + struct_type->data.structure.abi_alignment = this_field_align; } } @@ -2790,7 +2886,7 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) { union_type->data.unionation.have_explicit_tag_type = decl_node->data.container_decl.auto_enum || enum_type_node != nullptr; bool auto_layout = (union_type->data.unionation.layout == ContainerLayoutAuto); - bool want_safety = (field_count >= 2) && (auto_layout || enum_type_node != nullptr); + bool want_safety = (field_count >= 2) && (auto_layout || enum_type_node != nullptr) && !(g->build_mode == BuildModeFastRelease || g->build_mode == BuildModeSmallRelease); ZigType *tag_type; bool create_enum_type = decl_node->data.container_decl.auto_enum || (enum_type_node == nullptr && want_safety); bool *covered_enum_fields; @@ -2896,6 +2992,13 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) { } union_field->type_entry = field_type; + if (field_type->id == ZigTypeIdOpaque) { + add_node_error(g, field_node->data.struct_field.type, + buf_sprintf("opaque types have unknown size and therefore cannot be directly embedded in unions")); + union_type->data.unionation.is_invalid = true; + continue; + } + switch (type_requires_comptime(g, field_type)) { case ReqCompTimeInvalid: union_type->data.unionation.is_invalid = true; @@ -2929,19 +3032,19 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) { // In a second pass we will fill in the unspecified ones. if (tag_value != nullptr) { ZigType *tag_int_type = tag_type->data.enumeration.tag_int_type; - IrInstruction *result_inst = analyze_const_value(g, scope, tag_value, tag_int_type, nullptr); - if (result_inst->value.type->id == ZigTypeIdInvalid) { + ConstExprValue *result = analyze_const_value(g, scope, tag_value, tag_int_type, nullptr); + if (type_is_invalid(result->type)) { union_type->data.unionation.is_invalid = true; continue; } - assert(result_inst->value.special != ConstValSpecialRuntime); - assert(result_inst->value.type->id == ZigTypeIdInt); - auto entry = occupied_tag_values.put_unique(result_inst->value.data.x_bigint, tag_value); + assert(result->special != ConstValSpecialRuntime); + assert(result->type->id == ZigTypeIdInt); + auto entry = occupied_tag_values.put_unique(result->data.x_bigint, tag_value); if (entry == nullptr) { - bigint_init_bigint(&union_field->enum_field->value, &result_inst->value.data.x_bigint); + bigint_init_bigint(&union_field->enum_field->value, &result->data.x_bigint); } else { Buf *val_buf = buf_alloc(); - bigint_append_buf(val_buf, &result_inst->value.data.x_bigint, 10); + bigint_append_buf(val_buf, &result->data.x_bigint, 10); ErrorMsg *msg = add_node_error(g, tag_value, buf_sprintf("enum tag value %s already taken", buf_ptr(val_buf))); @@ -3144,36 +3247,19 @@ static bool scope_is_root_decls(Scope *scope) { zig_unreachable(); } -static void wrong_panic_prototype(CodeGen *g, AstNode *proto_node, ZigType *fn_type) { - add_node_error(g, proto_node, - buf_sprintf("expected 'fn([]const u8, ?*builtin.StackTrace) noreturn', found '%s'", - buf_ptr(&fn_type->name))); -} - -static void typecheck_panic_fn(CodeGen *g, ZigFn *panic_fn) { - AstNode *proto_node = panic_fn->proto_node; - assert(proto_node->type == NodeTypeFnProto); - ZigType *fn_type = panic_fn->type_entry; - FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id; - if (fn_type_id->param_count != 2) { - return wrong_panic_prototype(g, proto_node, fn_type); - } - ZigType *const_u8_ptr = get_pointer_to_type_extra(g, g->builtin_types.entry_u8, true, false, - PtrLenUnknown, 0, 0, 0); - ZigType *const_u8_slice = get_slice_type(g, const_u8_ptr); - if (fn_type_id->param_info[0].type != const_u8_slice) { - return wrong_panic_prototype(g, proto_node, fn_type); - } +void typecheck_panic_fn(CodeGen *g, TldFn *tld_fn, ZigFn *panic_fn) { + ConstExprValue *panic_fn_type_val = get_builtin_value(g, "PanicFn"); + assert(panic_fn_type_val != nullptr); + assert(panic_fn_type_val->type->id == ZigTypeIdMetaType); + ZigType *panic_fn_type = panic_fn_type_val->data.x_type; - ZigType *optional_ptr_to_stack_trace_type = get_optional_type(g, get_ptr_to_stack_trace_type(g)); - if (fn_type_id->param_info[1].type != optional_ptr_to_stack_trace_type) { - return wrong_panic_prototype(g, proto_node, fn_type); - } + AstNode *fake_decl = allocate<AstNode>(1); + *fake_decl = *panic_fn->proto_node; + fake_decl->type = NodeTypeSymbol; + fake_decl->data.symbol_expr.symbol = &panic_fn->symbol_name; - ZigType *actual_return_type = fn_type_id->return_type; - if (actual_return_type != g->builtin_types.entry_unreachable) { - return wrong_panic_prototype(g, proto_node, fn_type); - } + // call this for the side effects of casting to panic_fn_type + analyze_const_value(g, tld_fn->base.parent_scope, fake_decl, panic_fn_type, nullptr); } ZigType *get_test_fn_type(CodeGen *g) { @@ -3191,14 +3277,12 @@ void add_fn_export(CodeGen *g, ZigFn *fn_table_entry, Buf *symbol_name, GlobalLi if (ccc) { if (buf_eql_str(symbol_name, "main") && g->libc_link_lib != nullptr) { g->have_c_main = true; - g->windows_subsystem_windows = false; - g->windows_subsystem_console = true; + g->subsystem = TargetSubsystemConsole; } else if (buf_eql_str(symbol_name, "WinMain") && g->zig_target.os == OsWindows) { g->have_winmain = true; - g->windows_subsystem_windows = true; - g->windows_subsystem_console = false; + g->subsystem = TargetSubsystemWindows; } else if (buf_eql_str(symbol_name, "WinMainCRTStartup") && g->zig_target.os == OsWindows) { @@ -3209,6 +3293,7 @@ void add_fn_export(CodeGen *g, ZigFn *fn_table_entry, Buf *symbol_name, GlobalLi g->have_dllmain_crt_startup = true; } } + FnExport *fn_export = fn_table_entry->export_list.add_one(); memset(fn_export, 0, sizeof(FnExport)); buf_init_from_buf(&fn_export->name, symbol_name); @@ -3269,18 +3354,18 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) { if (!fn_table_entry->type_entry->data.fn.is_generic) { if (fn_def_node) g->fn_defs.append(fn_table_entry); + } - if (scope_is_root_decls(tld_fn->base.parent_scope) && - (import == g->root_import || import->package == g->panic_package)) + if (scope_is_root_decls(tld_fn->base.parent_scope) && + (import == g->root_import || import->package == g->panic_package)) + { + if (g->have_pub_main && buf_eql_str(&fn_table_entry->symbol_name, "main")) { + g->main_fn = fn_table_entry; + } else if ((import->package == g->panic_package || g->have_pub_panic) && + buf_eql_str(&fn_table_entry->symbol_name, "panic")) { - if (g->have_pub_main && buf_eql_str(&fn_table_entry->symbol_name, "main")) { - g->main_fn = fn_table_entry; - } else if ((import->package == g->panic_package || g->have_pub_panic) && - buf_eql_str(&fn_table_entry->symbol_name, "panic")) - { - g->panic_fn = fn_table_entry; - typecheck_panic_fn(g, fn_table_entry); - } + g->panic_fn = fn_table_entry; + g->panic_tld_fn = tld_fn; } } } else if (source_node->type == NodeTypeTestDecl) { @@ -3405,7 +3490,8 @@ void update_compile_var(CodeGen *g, Buf *name, ConstExprValue *value) { resolve_top_level_decl(g, tld, false, tld->source_node); assert(tld->id == TldIdVar); TldVar *tld_var = (TldVar *)tld; - tld_var->var->value = value; + tld_var->var->const_value = value; + tld_var->var->var_type = value->type; tld_var->var->align_bytes = get_abi_alignment(g, value->type); } @@ -3499,7 +3585,7 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) { case NodeTypeArrayType: case NodeTypeErrorType: case NodeTypeIfErrorExpr: - case NodeTypeTestExpr: + case NodeTypeIfOptional: case NodeTypeErrorSetDecl: case NodeTypeCancel: case NodeTypeResume: @@ -3560,6 +3646,7 @@ ZigType *validate_var_type(CodeGen *g, AstNode *source_node, ZigType *type_entry case ZigTypeIdFn: case ZigTypeIdBoundFn: case ZigTypeIdPromise: + case ZigTypeIdVector: return type_entry; } zig_unreachable(); @@ -3568,13 +3655,15 @@ ZigType *validate_var_type(CodeGen *g, AstNode *source_node, ZigType *type_entry // Set name to nullptr to make the variable anonymous (not visible to programmer). // TODO merge with definition of add_local_var in ir.cpp ZigVar *add_variable(CodeGen *g, AstNode *source_node, Scope *parent_scope, Buf *name, - bool is_const, ConstExprValue *value, Tld *src_tld) + bool is_const, ConstExprValue *const_value, Tld *src_tld, ZigType *var_type) { Error err; - assert(value); + assert(const_value != nullptr); + assert(var_type != nullptr); ZigVar *variable_entry = allocate<ZigVar>(1); - variable_entry->value = value; + variable_entry->const_value = const_value; + variable_entry->var_type = var_type; variable_entry->parent_scope = parent_scope; variable_entry->shadowable = false; variable_entry->mem_slot_index = SIZE_MAX; @@ -3583,23 +3672,23 @@ ZigVar *add_variable(CodeGen *g, AstNode *source_node, Scope *parent_scope, Buf assert(name); buf_init_from_buf(&variable_entry->name, name); - if ((err = type_resolve(g, value->type, ResolveStatusAlignmentKnown))) { - variable_entry->value->type = g->builtin_types.entry_invalid; + if ((err = type_resolve(g, var_type, ResolveStatusAlignmentKnown))) { + variable_entry->var_type = g->builtin_types.entry_invalid; } else { - variable_entry->align_bytes = get_abi_alignment(g, value->type); + variable_entry->align_bytes = get_abi_alignment(g, var_type); ZigVar *existing_var = find_variable(g, parent_scope, name, nullptr); if (existing_var && !existing_var->shadowable) { ErrorMsg *msg = add_node_error(g, source_node, buf_sprintf("redeclaration of variable '%s'", buf_ptr(name))); add_error_note(g, msg, existing_var->decl_node, buf_sprintf("previous declaration is here")); - variable_entry->value->type = g->builtin_types.entry_invalid; + variable_entry->var_type = g->builtin_types.entry_invalid; } else { ZigType *type; if (get_primitive_type(g, name, &type) != ErrorPrimitiveTypeNotFound) { add_node_error(g, source_node, buf_sprintf("variable shadows primitive type '%s'", buf_ptr(name))); - variable_entry->value->type = g->builtin_types.entry_invalid; + variable_entry->var_type = g->builtin_types.entry_invalid; } else { Scope *search_scope = nullptr; if (src_tld == nullptr) { @@ -3613,7 +3702,7 @@ ZigVar *add_variable(CodeGen *g, AstNode *source_node, Scope *parent_scope, Buf ErrorMsg *msg = add_node_error(g, source_node, buf_sprintf("redefinition of '%s'", buf_ptr(name))); add_error_note(g, msg, tld->source_node, buf_sprintf("previous definition is here")); - variable_entry->value->type = g->builtin_types.entry_invalid; + variable_entry->var_type = g->builtin_types.entry_invalid; } } } @@ -3645,6 +3734,7 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var) { 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; ZigType *explicit_type = nullptr; if (var_decl->type) { @@ -3663,7 +3753,7 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var) { linkage = VarLinkageInternal; } - IrInstruction *init_value = nullptr; + ConstExprValue *init_value = nullptr; // TODO more validation for types that can't be used for export/extern variables ZigType *implicit_type = nullptr; @@ -3672,7 +3762,7 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var) { } else if (var_decl->expr) { init_value = analyze_const_value(g, tld_var->base.parent_scope, var_decl->expr, explicit_type, var_decl->symbol); assert(init_value); - implicit_type = init_value->value.type; + implicit_type = init_value->type; if (implicit_type->id == ZigTypeIdUnreachable) { add_node_error(g, source_node, buf_sprintf("variable initialization is unreachable")); @@ -3690,7 +3780,7 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var) { add_node_error(g, source_node, buf_sprintf("variable of type 'type' must be constant")); implicit_type = g->builtin_types.entry_invalid; } - assert(implicit_type->id == ZigTypeIdInvalid || init_value->value.special != ConstValSpecialRuntime); + assert(implicit_type->id == ZigTypeIdInvalid || init_value->special != ConstValSpecialRuntime); } else if (linkage != VarLinkageExternal) { add_node_error(g, source_node, buf_sprintf("variables must be initialized")); implicit_type = g->builtin_types.entry_invalid; @@ -3699,19 +3789,20 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var) { ZigType *type = explicit_type ? explicit_type : implicit_type; assert(type != nullptr); // should have been caught by the parser - ConstExprValue *init_val = init_value ? &init_value->value : create_const_runtime(type); + ConstExprValue *init_val = (init_value != nullptr) ? init_value : create_const_runtime(type); tld_var->var = add_variable(g, source_node, tld_var->base.parent_scope, var_decl->symbol, - is_const, init_val, &tld_var->base); + is_const, init_val, &tld_var->base, type); tld_var->var->linkage = linkage; + tld_var->var->is_thread_local = is_thread_local; if (implicit_type != nullptr && type_is_invalid(implicit_type)) { - tld_var->var->value->type = g->builtin_types.entry_invalid; + tld_var->var->var_type = g->builtin_types.entry_invalid; } if (var_decl->align_expr != nullptr) { if (!analyze_const_align(g, tld_var->base.parent_scope, var_decl->align_expr, &tld_var->var->align_bytes)) { - tld_var->var->value->type = g->builtin_types.entry_invalid; + tld_var->var->var_type = g->builtin_types.entry_invalid; } } @@ -3724,6 +3815,10 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var) { } } + if (is_thread_local && is_const) { + add_node_error(g, source_node, buf_sprintf("threadlocal variable cannot be constant")); + } + g->global_vars.append(tld_var); } @@ -3924,6 +4019,7 @@ static bool is_container(ZigType *type_entry) { case ZigTypeIdArgTuple: case ZigTypeIdOpaque: case ZigTypeIdPromise: + case ZigTypeIdVector: return false; } zig_unreachable(); @@ -3983,6 +4079,7 @@ void resolve_container_type(CodeGen *g, ZigType *type_entry) { case ZigTypeIdArgTuple: case ZigTypeIdOpaque: case ZigTypeIdPromise: + case ZigTypeIdVector: zig_unreachable(); } } @@ -3992,7 +4089,9 @@ ZigType *get_src_ptr_type(ZigType *type) { if (type->id == ZigTypeIdFn) return type; if (type->id == ZigTypeIdPromise) return type; if (type->id == ZigTypeIdOptional) { - if (type->data.maybe.child_type->id == ZigTypeIdPointer) return type->data.maybe.child_type; + if (type->data.maybe.child_type->id == ZigTypeIdPointer) { + return type->data.maybe.child_type->data.pointer.allow_zero ? nullptr : type->data.maybe.child_type; + } if (type->data.maybe.child_type->id == ZigTypeIdFn) return type->data.maybe.child_type; if (type->data.maybe.child_type->id == ZigTypeIdPromise) return type->data.maybe.child_type; } @@ -4006,6 +4105,10 @@ ZigType *get_codegen_ptr_type(ZigType *type) { return ty; } +bool type_is_nonnull_ptr(ZigType *type) { + return type_is_codegen_pointer(type) && !ptr_allows_addr_zero(type); +} + bool type_is_codegen_pointer(ZigType *type) { return get_codegen_ptr_type(type) == type; } @@ -4076,7 +4179,7 @@ static void define_local_param_variables(CodeGen *g, ZigFn *fn_table_entry) { } ZigVar *var = add_variable(g, param_decl_node, fn_table_entry->child_scope, - param_name, true, create_const_runtime(param_type), nullptr); + param_name, true, create_const_runtime(param_type), nullptr, param_type); var->src_arg_index = i; fn_table_entry->child_scope = var->child_scope; var->shadowable = var->shadowable || is_var_args; @@ -4214,18 +4317,17 @@ static void add_symbols_from_import(CodeGen *g, AstNode *src_use_node, AstNode * preview_use_decl(g, src_use_node); } - IrInstruction *use_target_value = src_use_node->data.use.value; - if (use_target_value->value.type->id == ZigTypeIdInvalid) { + ConstExprValue *use_target_value = src_use_node->data.use.value; + if (type_is_invalid(use_target_value->type)) { dst_use_node->owner->any_imports_failed = true; return; } dst_use_node->data.use.resolution = TldResolutionOk; - ConstExprValue *const_val = &use_target_value->value; - assert(const_val->special != ConstValSpecialRuntime); + assert(use_target_value->special != ConstValSpecialRuntime); - ImportTableEntry *target_import = const_val->data.x_import; + ImportTableEntry *target_import = use_target_value->data.x_import; assert(target_import); if (target_import->any_imports_failed) { @@ -4288,10 +4390,10 @@ void preview_use_decl(CodeGen *g, AstNode *node) { } node->data.use.resolution = TldResolutionResolving; - IrInstruction *result = analyze_const_value(g, &node->owner->decls_scope->base, + ConstExprValue *result = analyze_const_value(g, &node->owner->decls_scope->base, node->data.use.expr, g->builtin_types.entry_namespace, nullptr); - if (result->value.type->id == ZigTypeIdInvalid) + if (type_is_invalid(result->type)) node->owner->any_imports_failed = true; node->data.use.value = result; @@ -4364,8 +4466,7 @@ ImportTableEntry *add_source_file(CodeGen *g, PackageTableEntry *package, Buf *r if (is_pub && ok_cc) { if (buf_eql_str(proto_name, "main")) { g->have_pub_main = true; - g->windows_subsystem_windows = false; - g->windows_subsystem_console = true; + g->subsystem = TargetSubsystemConsole; } else if (buf_eql_str(proto_name, "panic")) { g->have_pub_panic = true; } @@ -4434,6 +4535,43 @@ ZigType *get_int_type(CodeGen *g, bool is_signed, uint32_t size_in_bits) { return new_entry; } +bool is_valid_vector_elem_type(ZigType *elem_type) { + return elem_type->id == ZigTypeIdInt || + elem_type->id == ZigTypeIdFloat || + get_codegen_ptr_type(elem_type) != nullptr; +} + +ZigType *get_vector_type(CodeGen *g, uint32_t len, ZigType *elem_type) { + assert(is_valid_vector_elem_type(elem_type)); + + TypeId type_id = {}; + type_id.id = ZigTypeIdVector; + type_id.data.vector.len = len; + type_id.data.vector.elem_type = elem_type; + + { + auto entry = g->type_table.maybe_get(type_id); + if (entry) + return entry->value; + } + + ZigType *entry = new_type_table_entry(ZigTypeIdVector); + entry->zero_bits = (len == 0) || !type_has_bits(elem_type); + entry->type_ref = entry->zero_bits ? LLVMVoidType() : LLVMVectorType(elem_type->type_ref, len); + entry->data.vector.len = len; + entry->data.vector.elem_type = elem_type; + + buf_resize(&entry->name, 0); + buf_appendf(&entry->name, "@Vector(%u, %s)", len, buf_ptr(&elem_type->name)); + + entry->di_type = ZigLLVMDIBuilderCreateVectorType(g->dbuilder, + len * type_size_bits(g, elem_type), + LLVMABIAlignmentOfType(g->target_data_ref, entry->type_ref), elem_type->di_type, len); + + g->type_table.put(type_id, entry); + return entry; +} + ZigType **get_c_int_type_ptr(CodeGen *g, CIntType c_int_type) { return &g->builtin_types.entry_c_int[c_int_type]; } @@ -4465,6 +4603,7 @@ bool handle_is_ptr(ZigType *type_entry) { case ZigTypeIdFn: case ZigTypeIdEnum: case ZigTypeIdPromise: + case ZigTypeIdVector: return false; case ZigTypeIdArray: case ZigTypeIdStruct: @@ -4473,7 +4612,8 @@ bool handle_is_ptr(ZigType *type_entry) { return type_has_bits(type_entry->data.error_union.payload_type); case ZigTypeIdOptional: return type_has_bits(type_entry->data.maybe.child_type) && - !type_is_codegen_pointer(type_entry->data.maybe.child_type); + !type_is_codegen_pointer(type_entry->data.maybe.child_type) && + type_entry->data.maybe.child_type->id != ZigTypeIdErrorSet; case ZigTypeIdUnion: assert(type_entry->data.unionation.zero_bits_known); if (type_entry->data.unionation.gen_field_count == 0) @@ -4580,8 +4720,7 @@ static Buf *get_posix_libc_include_path(void) { void find_libc_include_path(CodeGen *g) { if (g->libc_include_dir == nullptr) { if (!g->is_native_target) { - fprintf(stderr, "Unable to determine libc include path. --libc-include-dir"); - exit(1); + return; } if (g->zig_target.os == OsWindows) { @@ -4720,6 +4859,11 @@ bool fn_type_id_eql(FnTypeId *a, FnTypeId *b) { return true; } +static uint32_t hash_const_val_error_set(ConstExprValue *const_val) { + assert(const_val->data.x_err_set != nullptr); + return const_val->data.x_err_set->value ^ 2630160122; +} + static uint32_t hash_const_val_ptr(ConstExprValue *const_val) { uint32_t hash_val = 0; switch (const_val->data.x_ptr.mut) { @@ -4751,6 +4895,18 @@ static uint32_t hash_const_val_ptr(ConstExprValue *const_val) { hash_val += hash_ptr(const_val->data.x_ptr.data.base_struct.struct_val); hash_val += hash_size(const_val->data.x_ptr.data.base_struct.field_index); return hash_val; + case ConstPtrSpecialBaseErrorUnionCode: + hash_val += (uint32_t)2994743799; + hash_val += hash_ptr(const_val->data.x_ptr.data.base_err_union_code.err_union_val); + return hash_val; + case ConstPtrSpecialBaseErrorUnionPayload: + hash_val += (uint32_t)3456080131; + hash_val += hash_ptr(const_val->data.x_ptr.data.base_err_union_payload.err_union_val); + return hash_val; + case ConstPtrSpecialBaseOptionalPayload: + hash_val += (uint32_t)3163140517; + hash_val += hash_ptr(const_val->data.x_ptr.data.base_optional_payload.optional_val); + return hash_val; case ConstPtrSpecialHardCodedAddr: hash_val += (uint32_t)4048518294; hash_val += hash_size(const_val->data.x_ptr.data.hard_coded_addr.addr); @@ -4762,6 +4918,9 @@ static uint32_t hash_const_val_ptr(ConstExprValue *const_val) { hash_val += (uint32_t)2590901619; hash_val += hash_ptr(const_val->data.x_ptr.data.fn.fn_entry); return hash_val; + case ConstPtrSpecialNull: + hash_val += (uint32_t)1486246455; + return hash_val; } zig_unreachable(); } @@ -4860,7 +5019,9 @@ static uint32_t hash_const_val(ConstExprValue *const_val) { return 2709806591; case ZigTypeIdOptional: if (get_codegen_ptr_type(const_val->type) != nullptr) { - return hash_const_val(const_val) * 1992916303; + return hash_const_val_ptr(const_val) * 1992916303; + } else if (const_val->type->data.maybe.child_type->id == ZigTypeIdErrorSet) { + return hash_const_val_error_set(const_val) * 3147031929; } else { if (const_val->data.x_optional) { return hash_const_val(const_val->data.x_optional) * 1992916303; @@ -4872,10 +5033,12 @@ static uint32_t hash_const_val(ConstExprValue *const_val) { // TODO better hashing algorithm return 3415065496; case ZigTypeIdErrorSet: - assert(const_val->data.x_err_set != nullptr); - return const_val->data.x_err_set->value ^ 2630160122; + return hash_const_val_error_set(const_val); case ZigTypeIdNamespace: return hash_ptr(const_val->data.x_import); + case ZigTypeIdVector: + // TODO better hashing algorithm + return 3647867726; case ZigTypeIdBoundFn: case ZigTypeIdInvalid: case ZigTypeIdUnreachable: @@ -4928,6 +5091,7 @@ static bool can_mutate_comptime_var_state(ConstExprValue *value) { case ZigTypeIdBool: case ZigTypeIdUnreachable: case ZigTypeIdInt: + case ZigTypeIdVector: case ZigTypeIdFloat: case ZigTypeIdComptimeFloat: case ZigTypeIdComptimeInt: @@ -4975,7 +5139,7 @@ static bool can_mutate_comptime_var_state(ConstExprValue *value) { return can_mutate_comptime_var_state(value->data.x_optional); case ZigTypeIdErrorUnion: - if (value->data.x_err_union.err != nullptr) + if (value->data.x_err_union.error_set->data.x_err_set != nullptr) return false; assert(value->data.x_err_union.payload != nullptr); return can_mutate_comptime_var_state(value->data.x_err_union.payload); @@ -5011,6 +5175,7 @@ static bool return_type_is_cacheable(ZigType *return_type) { case ZigTypeIdErrorSet: case ZigTypeIdEnum: case ZigTypeIdPointer: + case ZigTypeIdVector: return true; case ZigTypeIdArray: @@ -5036,9 +5201,9 @@ bool fn_eval_cacheable(Scope *scope, ZigType *return_type) { while (scope) { if (scope->id == ScopeIdVarDecl) { ScopeVarDecl *var_scope = (ScopeVarDecl *)scope; - if (type_is_invalid(var_scope->var->value->type)) + if (type_is_invalid(var_scope->var->var_type)) return false; - if (can_mutate_comptime_var_state(var_scope->var->value)) + if (can_mutate_comptime_var_state(var_scope->var->const_value)) return false; } else if (scope->id == ScopeIdFnDef) { return true; @@ -5056,7 +5221,7 @@ uint32_t fn_eval_hash(Scope* scope) { while (scope) { if (scope->id == ScopeIdVarDecl) { ScopeVarDecl *var_scope = (ScopeVarDecl *)scope; - result += hash_const_val(var_scope->var->value); + result += hash_const_val(var_scope->var->const_value); } else if (scope->id == ScopeIdFnDef) { ScopeFnDef *fn_scope = (ScopeFnDef *)scope; result += hash_ptr(fn_scope->fn_entry); @@ -5080,10 +5245,16 @@ bool fn_eval_eql(Scope *a, Scope *b) { if (a->id == ScopeIdVarDecl) { ScopeVarDecl *a_var_scope = (ScopeVarDecl *)a; ScopeVarDecl *b_var_scope = (ScopeVarDecl *)b; - if (a_var_scope->var->value->type != b_var_scope->var->value->type) - return false; - if (!const_values_equal(a->codegen, a_var_scope->var->value, b_var_scope->var->value)) + if (a_var_scope->var->var_type != b_var_scope->var->var_type) return false; + if (a_var_scope->var->var_type == a_var_scope->var->const_value->type && + b_var_scope->var->var_type == b_var_scope->var->const_value->type) + { + if (!const_values_equal(a->codegen, a_var_scope->var->const_value, b_var_scope->var->const_value)) + return false; + } else { + zig_panic("TODO comptime ptr reinterpret for fn_eval_eql"); + } } else if (a->id == ScopeIdFnDef) { ScopeFnDef *a_fn_scope = (ScopeFnDef *)a; ScopeFnDef *b_fn_scope = (ScopeFnDef *)b; @@ -5101,6 +5272,7 @@ bool fn_eval_eql(Scope *a, Scope *b) { return false; } +// Whether the type has bits at runtime. bool type_has_bits(ZigType *type_entry) { assert(type_entry); assert(!type_is_invalid(type_entry)); @@ -5108,6 +5280,66 @@ bool type_has_bits(ZigType *type_entry) { return !type_entry->zero_bits; } +// Whether you can infer the value based solely on the type. +OnePossibleValue type_has_one_possible_value(CodeGen *g, ZigType *type_entry) { + assert(type_entry != nullptr); + Error err; + if ((err = type_resolve(g, type_entry, ResolveStatusZeroBitsKnown))) + return OnePossibleValueInvalid; + switch (type_entry->id) { + case ZigTypeIdInvalid: + zig_unreachable(); + case ZigTypeIdOpaque: + case ZigTypeIdComptimeFloat: + case ZigTypeIdComptimeInt: + case ZigTypeIdMetaType: + case ZigTypeIdNamespace: + case ZigTypeIdBoundFn: + case ZigTypeIdArgTuple: + case ZigTypeIdOptional: + case ZigTypeIdFn: + case ZigTypeIdBool: + case ZigTypeIdFloat: + case ZigTypeIdPromise: + case ZigTypeIdErrorUnion: + return OnePossibleValueNo; + case ZigTypeIdUndefined: + case ZigTypeIdNull: + case ZigTypeIdVoid: + case ZigTypeIdUnreachable: + return OnePossibleValueYes; + case ZigTypeIdArray: + if (type_entry->data.array.len == 0) + return OnePossibleValueYes; + return type_has_one_possible_value(g, type_entry->data.array.child_type); + case ZigTypeIdStruct: + for (size_t i = 0; i < type_entry->data.structure.src_field_count; i += 1) { + TypeStructField *field = &type_entry->data.structure.fields[i]; + switch (type_has_one_possible_value(g, field->type_entry)) { + case OnePossibleValueInvalid: + return OnePossibleValueInvalid; + case OnePossibleValueNo: + return OnePossibleValueNo; + case OnePossibleValueYes: + continue; + } + } + return OnePossibleValueYes; + case ZigTypeIdErrorSet: + case ZigTypeIdEnum: + case ZigTypeIdInt: + case ZigTypeIdVector: + return type_has_bits(type_entry) ? OnePossibleValueNo : OnePossibleValueYes; + case ZigTypeIdPointer: + return type_has_one_possible_value(g, type_entry->data.pointer.child_type); + case ZigTypeIdUnion: + if (type_entry->data.unionation.src_field_count > 1) + return OnePossibleValueNo; + return type_has_one_possible_value(g, type_entry->data.unionation.fields[0].type_entry); + } + zig_unreachable(); +} + ReqCompTime type_requires_comptime(CodeGen *g, ZigType *type_entry) { Error err; if ((err = type_resolve(g, type_entry, ResolveStatusZeroBitsKnown))) @@ -5147,6 +5379,7 @@ ReqCompTime type_requires_comptime(CodeGen *g, ZigType *type_entry) { case ZigTypeIdErrorSet: case ZigTypeIdBool: case ZigTypeIdInt: + case ZigTypeIdVector: case ZigTypeIdFloat: case ZigTypeIdVoid: case ZigTypeIdUnreachable: @@ -5562,6 +5795,33 @@ bool const_values_equal_ptr(ConstExprValue *a, ConstExprValue *b) { if (a->data.x_ptr.data.base_struct.field_index != b->data.x_ptr.data.base_struct.field_index) return false; return true; + case ConstPtrSpecialBaseErrorUnionCode: + if (a->data.x_ptr.data.base_err_union_code.err_union_val != + b->data.x_ptr.data.base_err_union_code.err_union_val && + a->data.x_ptr.data.base_err_union_code.err_union_val->global_refs != + b->data.x_ptr.data.base_err_union_code.err_union_val->global_refs) + { + return false; + } + return true; + case ConstPtrSpecialBaseErrorUnionPayload: + if (a->data.x_ptr.data.base_err_union_payload.err_union_val != + b->data.x_ptr.data.base_err_union_payload.err_union_val && + a->data.x_ptr.data.base_err_union_payload.err_union_val->global_refs != + b->data.x_ptr.data.base_err_union_payload.err_union_val->global_refs) + { + return false; + } + return true; + case ConstPtrSpecialBaseOptionalPayload: + if (a->data.x_ptr.data.base_optional_payload.optional_val != + b->data.x_ptr.data.base_optional_payload.optional_val && + a->data.x_ptr.data.base_optional_payload.optional_val->global_refs != + b->data.x_ptr.data.base_optional_payload.optional_val->global_refs) + { + return false; + } + return true; case ConstPtrSpecialHardCodedAddr: if (a->data.x_ptr.data.hard_coded_addr.addr != b->data.x_ptr.data.hard_coded_addr.addr) return false; @@ -5570,10 +5830,34 @@ bool const_values_equal_ptr(ConstExprValue *a, ConstExprValue *b) { return true; case ConstPtrSpecialFunction: return a->data.x_ptr.data.fn.fn_entry == b->data.x_ptr.data.fn.fn_entry; + case ConstPtrSpecialNull: + return true; } zig_unreachable(); } +static bool const_values_equal_array(CodeGen *g, ConstExprValue *a, ConstExprValue *b, size_t len) { + assert(a->data.x_array.special != ConstArraySpecialUndef); + assert(b->data.x_array.special != ConstArraySpecialUndef); + if (a->data.x_array.special == ConstArraySpecialBuf && + b->data.x_array.special == ConstArraySpecialBuf) + { + return buf_eql_buf(a->data.x_array.data.s_buf, b->data.x_array.data.s_buf); + } + expand_undef_array(g, a); + expand_undef_array(g, b); + + ConstExprValue *a_elems = a->data.x_array.data.s_none.elements; + ConstExprValue *b_elems = b->data.x_array.data.s_none.elements; + + for (size_t i = 0; i < len; i += 1) { + if (!const_values_equal(g, &a_elems[i], &b_elems[i])) + return false; + } + + return true; +} + bool const_values_equal(CodeGen *g, ConstExprValue *a, ConstExprValue *b) { assert(a->type->id == b->type->id); assert(a->special == ConstValSpecialStatic); @@ -5628,28 +5912,12 @@ bool const_values_equal(CodeGen *g, ConstExprValue *a, ConstExprValue *b) { case ZigTypeIdPointer: case ZigTypeIdFn: return const_values_equal_ptr(a, b); + case ZigTypeIdVector: + assert(a->type->data.vector.len == b->type->data.vector.len); + return const_values_equal_array(g, a, b, a->type->data.vector.len); case ZigTypeIdArray: { assert(a->type->data.array.len == b->type->data.array.len); - assert(a->data.x_array.special != ConstArraySpecialUndef); - assert(b->data.x_array.special != ConstArraySpecialUndef); - if (a->data.x_array.special == ConstArraySpecialBuf && - b->data.x_array.special == ConstArraySpecialBuf) - { - return buf_eql_buf(a->data.x_array.data.s_buf, b->data.x_array.data.s_buf); - } - expand_undef_array(g, a); - expand_undef_array(g, b); - - size_t len = a->type->data.array.len; - ConstExprValue *a_elems = a->data.x_array.data.s_none.elements; - ConstExprValue *b_elems = b->data.x_array.data.s_none.elements; - - for (size_t i = 0; i < len; ++i) { - if (!const_values_equal(g, &a_elems[i], &b_elems[i])) - return false; - } - - return true; + return const_values_equal_array(g, a, b, a->type->data.array.len); } case ZigTypeIdStruct: for (size_t i = 0; i < a->type->data.structure.src_field_count; i += 1) { @@ -5738,14 +6006,25 @@ void eval_min_max_value(CodeGen *g, ZigType *type_entry, ConstExprValue *const_v } } -void render_const_val_ptr(CodeGen *g, Buf *buf, ConstExprValue *const_val, ZigType *type_entry) { +static void render_const_val_ptr(CodeGen *g, Buf *buf, ConstExprValue *const_val, ZigType *type_entry) { + assert(type_entry->id == ZigTypeIdPointer); + + if (type_entry->data.pointer.child_type->id == ZigTypeIdOpaque) { + buf_append_buf(buf, &type_entry->name); + return; + } + switch (const_val->data.x_ptr.special) { case ConstPtrSpecialInvalid: zig_unreachable(); case ConstPtrSpecialRef: case ConstPtrSpecialBaseStruct: + case ConstPtrSpecialBaseErrorUnionCode: + case ConstPtrSpecialBaseErrorUnionPayload: + case ConstPtrSpecialBaseOptionalPayload: buf_appendf(buf, "*"); - render_const_value(g, buf, const_ptr_pointee(g, const_val)); + // TODO we need a source node for const_ptr_pointee because it can generate compile errors + render_const_value(g, buf, const_ptr_pointee(nullptr, g, const_val, nullptr)); return; case ConstPtrSpecialBaseArray: if (const_val->data.x_ptr.data.base_array.is_cstr) { @@ -5753,7 +6032,8 @@ void render_const_val_ptr(CodeGen *g, Buf *buf, ConstExprValue *const_val, ZigTy return; } else { buf_appendf(buf, "*"); - render_const_value(g, buf, const_ptr_pointee(g, const_val)); + // TODO we need a source node for const_ptr_pointee because it can generate compile errors + render_const_value(g, buf, const_ptr_pointee(nullptr, g, const_val, nullptr)); return; } case ConstPtrSpecialHardCodedAddr: @@ -5769,6 +6049,56 @@ void render_const_val_ptr(CodeGen *g, Buf *buf, ConstExprValue *const_val, ZigTy buf_appendf(buf, "@ptrCast(%s, %s)", buf_ptr(&const_val->type->name), buf_ptr(&fn_entry->symbol_name)); return; } + case ConstPtrSpecialNull: + buf_append_str(buf, "null"); + return; + } + zig_unreachable(); +} + +static void render_const_val_err_set(CodeGen *g, Buf *buf, ConstExprValue *const_val, ZigType *type_entry) { + if (const_val->data.x_err_set == nullptr) { + buf_append_str(buf, "null"); + } else { + buf_appendf(buf, "%s.%s", buf_ptr(&type_entry->name), buf_ptr(&const_val->data.x_err_set->name)); + } +} + +static void render_const_val_array(CodeGen *g, Buf *buf, Buf *type_name, ConstExprValue *const_val, uint64_t start, uint64_t len) { + ConstArrayValue *array = &const_val->data.x_array; + switch (array->special) { + case ConstArraySpecialUndef: + buf_append_str(buf, "undefined"); + return; + case ConstArraySpecialBuf: { + Buf *array_buf = array->data.s_buf; + const char *base = &buf_ptr(array_buf)[start]; + assert(start + len <= buf_len(array_buf)); + + buf_append_char(buf, '"'); + for (size_t i = 0; i < len; i += 1) { + uint8_t c = base[i]; + if (c == '"') { + buf_append_str(buf, "\\\""); + } else { + buf_append_char(buf, c); + } + } + buf_append_char(buf, '"'); + return; + } + case ConstArraySpecialNone: { + ConstExprValue *base = &array->data.s_none.elements[start]; + assert(start + len <= const_val->type->data.array.len); + + buf_appendf(buf, "%s{", buf_ptr(type_name)); + for (uint64_t i = 0; i < len; i += 1) { + if (i != 0) buf_appendf(buf, ","); + render_const_value(g, buf, &base[i]); + } + buf_appendf(buf, "}"); + return; + } } zig_unreachable(); } @@ -5853,39 +6183,16 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) { } case ZigTypeIdPointer: return render_const_val_ptr(g, buf, const_val, type_entry); - case ZigTypeIdArray: - switch (const_val->data.x_array.special) { - case ConstArraySpecialUndef: - buf_append_str(buf, "undefined"); - return; - case ConstArraySpecialBuf: { - Buf *array_buf = const_val->data.x_array.data.s_buf; - buf_append_char(buf, '"'); - for (size_t i = 0; i < buf_len(array_buf); i += 1) { - uint8_t c = buf_ptr(array_buf)[i]; - if (c == '"') { - buf_append_str(buf, "\\\""); - } else { - buf_append_char(buf, c); - } - } - buf_append_char(buf, '"'); - return; - } - case ConstArraySpecialNone: { - buf_appendf(buf, "%s{", buf_ptr(&type_entry->name)); - uint64_t len = type_entry->data.array.len; - for (uint64_t i = 0; i < len; i += 1) { - if (i != 0) - buf_appendf(buf, ","); - ConstExprValue *child_value = &const_val->data.x_array.data.s_none.elements[i]; - render_const_value(g, buf, child_value); - } - buf_appendf(buf, "}"); - return; - } - } - zig_unreachable(); + case ZigTypeIdArray: { + uint64_t len = type_entry->data.array.len; + render_const_val_array(g, buf, &type_entry->name, const_val, 0, len); + return; + } + case ZigTypeIdVector: { + uint32_t len = type_entry->data.vector.len; + render_const_val_array(g, buf, &type_entry->name, const_val, 0, len); + return; + } case ZigTypeIdNull: { buf_appendf(buf, "null"); @@ -5900,6 +6207,8 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) { { if (get_codegen_ptr_type(const_val->type) != nullptr) return render_const_val_ptr(g, buf, const_val, type_entry->data.maybe.child_type); + if (type_entry->data.maybe.child_type->id == ZigTypeIdErrorSet) + return render_const_val_err_set(g, buf, const_val, type_entry->data.maybe.child_type); if (const_val->data.x_optional) { render_const_value(g, buf, const_val->data.x_optional); } else { @@ -5925,7 +6234,24 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) { } case ZigTypeIdStruct: { - buf_appendf(buf, "(struct %s constant)", buf_ptr(&type_entry->name)); + if (is_slice(type_entry)) { + ConstExprValue *len_val = &const_val->data.x_struct.fields[slice_len_index]; + size_t len = bigint_as_unsigned(&len_val->data.x_bigint); + + ConstExprValue *ptr_val = &const_val->data.x_struct.fields[slice_ptr_index]; + if (ptr_val->special == ConstValSpecialUndef) { + assert(len == 0); + buf_appendf(buf, "((%s)(undefined))[0..0]", buf_ptr(&type_entry->name)); + return; + } + assert(ptr_val->data.x_ptr.special == ConstPtrSpecialBaseArray); + ConstExprValue *array = ptr_val->data.x_ptr.data.base_array.array_val; + size_t start = ptr_val->data.x_ptr.data.base_array.elem_index; + + render_const_val_array(g, buf, &type_entry->name, array, start, len); + } else { + buf_appendf(buf, "(struct %s constant)", buf_ptr(&type_entry->name)); + } return; } case ZigTypeIdEnum: @@ -5937,11 +6263,12 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) { case ZigTypeIdErrorUnion: { buf_appendf(buf, "%s(", buf_ptr(&type_entry->name)); - if (const_val->data.x_err_union.err == nullptr) { + ErrorTableEntry *err_set = const_val->data.x_err_union.error_set->data.x_err_set; + if (err_set == nullptr) { render_const_value(g, buf, const_val->data.x_err_union.payload); } else { buf_appendf(buf, "%s.%s", buf_ptr(&type_entry->data.error_union.err_set_type->name), - buf_ptr(&const_val->data.x_err_union.err->name)); + buf_ptr(&err_set->name)); } buf_appendf(buf, ")"); return; @@ -5956,10 +6283,7 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) { return; } case ZigTypeIdErrorSet: - { - buf_appendf(buf, "%s.%s", buf_ptr(&type_entry->name), buf_ptr(&const_val->data.x_err_set->name)); - return; - } + return render_const_val_err_set(g, buf, const_val, type_entry); case ZigTypeIdArgTuple: { buf_appendf(buf, "(args value)"); @@ -6035,6 +6359,7 @@ uint32_t type_id_hash(TypeId x) { ((x.data.pointer.ptr_len == PtrLenSingle) ? (uint32_t)1120226602 : (uint32_t)3200913342) + (x.data.pointer.is_const ? (uint32_t)2749109194 : (uint32_t)4047371087) + (x.data.pointer.is_volatile ? (uint32_t)536730450 : (uint32_t)1685612214) + + (x.data.pointer.allow_zero ? (uint32_t)3324284834 : (uint32_t)3584904923) + (((uint32_t)x.data.pointer.alignment) ^ (uint32_t)0x777fbe0e) + (((uint32_t)x.data.pointer.bit_offset_in_host) ^ (uint32_t)2639019452) + (((uint32_t)x.data.pointer.host_int_bytes) ^ (uint32_t)529908881); @@ -6044,6 +6369,8 @@ uint32_t type_id_hash(TypeId x) { case ZigTypeIdInt: return (x.data.integer.is_signed ? (uint32_t)2652528194 : (uint32_t)163929201) + (((uint32_t)x.data.integer.bit_count) ^ (uint32_t)2998081557); + case ZigTypeIdVector: + return hash_ptr(x.data.vector.elem_type) * (x.data.vector.len * 526582681); } zig_unreachable(); } @@ -6083,6 +6410,7 @@ bool type_id_eql(TypeId a, TypeId b) { a.data.pointer.ptr_len == b.data.pointer.ptr_len && a.data.pointer.is_const == b.data.pointer.is_const && a.data.pointer.is_volatile == b.data.pointer.is_volatile && + a.data.pointer.allow_zero == b.data.pointer.allow_zero && a.data.pointer.alignment == b.data.pointer.alignment && a.data.pointer.bit_offset_in_host == b.data.pointer.bit_offset_in_host && a.data.pointer.host_int_bytes == b.data.pointer.host_int_bytes; @@ -6092,6 +6420,9 @@ bool type_id_eql(TypeId a, TypeId b) { case ZigTypeIdInt: return a.data.integer.is_signed == b.data.integer.is_signed && a.data.integer.bit_count == b.data.integer.bit_count; + case ZigTypeIdVector: + return a.data.vector.elem_type == b.data.vector.elem_type && + a.data.vector.len == b.data.vector.len; } zig_unreachable(); } @@ -6110,10 +6441,15 @@ uint32_t zig_llvm_fn_key_hash(ZigLLVMFnKey x) { return (uint32_t)(x.data.floating.bit_count) * (uint32_t)1953839089; case ZigLLVMFnIdSqrt: return (uint32_t)(x.data.floating.bit_count) * (uint32_t)2225366385; + case ZigLLVMFnIdBswap: + return (uint32_t)(x.data.bswap.bit_count) * (uint32_t)3661994335; + case ZigLLVMFnIdBitReverse: + return (uint32_t)(x.data.bit_reverse.bit_count) * (uint32_t)2621398431; case ZigLLVMFnIdOverflowArithmetic: return ((uint32_t)(x.data.overflow_arithmetic.bit_count) * 87135777) + ((uint32_t)(x.data.overflow_arithmetic.add_sub_mul) * 31640542) + - ((uint32_t)(x.data.overflow_arithmetic.is_signed) ? 1062315172 : 314955820); + ((uint32_t)(x.data.overflow_arithmetic.is_signed) ? 1062315172 : 314955820) + + x.data.overflow_arithmetic.vector_len * 1435156945; } zig_unreachable(); } @@ -6128,6 +6464,10 @@ bool zig_llvm_fn_key_eql(ZigLLVMFnKey a, ZigLLVMFnKey b) { return a.data.clz.bit_count == b.data.clz.bit_count; case ZigLLVMFnIdPopCount: return a.data.pop_count.bit_count == b.data.pop_count.bit_count; + case ZigLLVMFnIdBswap: + return a.data.bswap.bit_count == b.data.bswap.bit_count; + case ZigLLVMFnIdBitReverse: + return a.data.bit_reverse.bit_count == b.data.bit_reverse.bit_count; case ZigLLVMFnIdFloor: case ZigLLVMFnIdCeil: case ZigLLVMFnIdSqrt: @@ -6135,31 +6475,42 @@ bool zig_llvm_fn_key_eql(ZigLLVMFnKey a, ZigLLVMFnKey b) { case ZigLLVMFnIdOverflowArithmetic: return (a.data.overflow_arithmetic.bit_count == b.data.overflow_arithmetic.bit_count) && (a.data.overflow_arithmetic.add_sub_mul == b.data.overflow_arithmetic.add_sub_mul) && - (a.data.overflow_arithmetic.is_signed == b.data.overflow_arithmetic.is_signed); + (a.data.overflow_arithmetic.is_signed == b.data.overflow_arithmetic.is_signed) && + (a.data.overflow_arithmetic.vector_len == b.data.overflow_arithmetic.vector_len); } zig_unreachable(); } // Canonicalize the array value as ConstArraySpecialNone void expand_undef_array(CodeGen *g, ConstExprValue *const_val) { - assert(const_val->type->id == ZigTypeIdArray); + size_t elem_count; + ZigType *elem_type; + if (const_val->type->id == ZigTypeIdArray) { + elem_count = const_val->type->data.array.len; + elem_type = const_val->type->data.array.child_type; + } else if (const_val->type->id == ZigTypeIdVector) { + elem_count = const_val->type->data.vector.len; + elem_type = const_val->type->data.vector.elem_type; + } else { + zig_unreachable(); + } + if (const_val->special == ConstValSpecialUndef) { + const_val->special = ConstValSpecialStatic; + const_val->data.x_array.special = ConstArraySpecialUndef; + } switch (const_val->data.x_array.special) { case ConstArraySpecialNone: return; case ConstArraySpecialUndef: { const_val->data.x_array.special = ConstArraySpecialNone; - size_t elem_count = const_val->type->data.array.len; const_val->data.x_array.data.s_none.elements = create_const_vals(elem_count); for (size_t i = 0; i < elem_count; i += 1) { ConstExprValue *element_val = &const_val->data.x_array.data.s_none.elements[i]; - element_val->type = const_val->type->data.array.child_type; + element_val->type = elem_type; init_const_undefined(g, element_val); - ConstParent *parent = get_const_val_parent(g, element_val); - if (parent != nullptr) { - parent->id = ConstParentIdArray; - parent->data.p_array.array_val = const_val; - parent->data.p_array.elem_index = i; - } + element_val->parent.id = ConstParentIdArray; + element_val->parent.data.p_array.array_val = const_val; + element_val->parent.data.p_array.elem_index = i; } return; } @@ -6170,7 +6521,6 @@ void expand_undef_array(CodeGen *g, ConstExprValue *const_val) { g->string_literals_table.maybe_remove(buf); const_val->data.x_array.special = ConstArraySpecialNone; - size_t elem_count = const_val->type->data.array.len; assert(elem_count == buf_len(buf)); const_val->data.x_array.data.s_none.elements = create_const_vals(elem_count); for (size_t i = 0; i < elem_count; i += 1) { @@ -6178,6 +6528,9 @@ void expand_undef_array(CodeGen *g, ConstExprValue *const_val) { this_char->special = ConstValSpecialStatic; this_char->type = g->builtin_types.entry_u8; bigint_init_unsigned(&this_char->data.x_bigint, (uint8_t)buf_ptr(buf)[i]); + this_char->parent.id = ConstParentIdArray; + this_char->parent.data.p_array.array_val = const_val; + this_char->parent.data.p_array.elem_index = i; } return; } @@ -6185,18 +6538,9 @@ void expand_undef_array(CodeGen *g, ConstExprValue *const_val) { zig_unreachable(); } +// Deprecated. Reference the parent field directly. ConstParent *get_const_val_parent(CodeGen *g, ConstExprValue *value) { - assert(value->type); - ZigType *type_entry = value->type; - if (type_entry->id == ZigTypeIdArray) { - expand_undef_array(g, value); - return &value->data.x_array.data.s_none.parent; - } else if (type_entry->id == ZigTypeIdStruct) { - return &value->data.x_struct.parent; - } else if (type_entry->id == ZigTypeIdUnion) { - return &value->data.x_union.parent; - } - return nullptr; + return &value->parent; } static const ZigTypeId all_type_ids[] = { @@ -6224,6 +6568,7 @@ static const ZigTypeId all_type_ids[] = { ZigTypeIdArgTuple, ZigTypeIdOpaque, ZigTypeIdPromise, + ZigTypeIdVector, }; ZigTypeId type_id_at_index(size_t index) { @@ -6289,6 +6634,8 @@ size_t type_id_index(ZigType *entry) { return 22; case ZigTypeIdPromise: return 23; + case ZigTypeIdVector: + return 24; } zig_unreachable(); } @@ -6345,6 +6692,8 @@ const char *type_id_name(ZigTypeId id) { return "Opaque"; case ZigTypeIdPromise: return "Promise"; + case ZigTypeIdVector: + return "Vector"; } zig_unreachable(); } @@ -6361,7 +6710,7 @@ LinkLib *add_link_lib(CodeGen *g, Buf *name) { if (is_libc && g->libc_link_lib != nullptr) return g->libc_link_lib; - if (g->enable_cache && is_libc && g->zig_target.os != OsMacOSX && g->zig_target.os != OsIOS) { + if (g->enable_cache && is_libc && g->zig_target.os != OsMacOSX && g->zig_target.os != OsIOS && g->zig_target.os != OsFreeBSD) { fprintf(stderr, "TODO linking against libc is currently incompatible with `--cache on`.\n" "Zig is not yet capable of determining whether the libc installation has changed on subsequent builds.\n"); exit(1); @@ -6424,7 +6773,7 @@ ConstExprValue *get_builtin_value(CodeGen *codegen, const char *name) { resolve_top_level_decl(codegen, tld, false, nullptr); assert(tld->id == TldIdVar); TldVar *tld_var = (TldVar *)tld; - ConstExprValue *var_value = tld_var->var->value; + ConstExprValue *var_value = tld_var->var->const_value; assert(var_value != nullptr); return var_value; } @@ -6500,6 +6849,7 @@ X64CABIClass type_c_abi_x86_64_class(CodeGen *g, ZigType *ty) { case ZigTypeIdBool: return X64CABIClass_INTEGER; case ZigTypeIdFloat: + case ZigTypeIdVector: return X64CABIClass_SSE; case ZigTypeIdStruct: { // "If the size of an object is larger than four eightbytes, or it contains unaligned @@ -6579,3 +6929,36 @@ uint32_t get_host_int_bytes(CodeGen *g, ZigType *struct_type, TypeStructField *f LLVMTypeRef field_type = LLVMStructGetTypeAtIndex(struct_type->type_ref, field->gen_index); return LLVMStoreSizeOfType(g->target_data_ref, field_type); } + +Error ensure_const_val_repr(IrAnalyze *ira, CodeGen *codegen, AstNode *source_node, + ConstExprValue *const_val, ZigType *wanted_type) +{ + ConstExprValue ptr_val = {}; + ptr_val.special = ConstValSpecialStatic; + ptr_val.type = get_pointer_to_type(codegen, wanted_type, true); + ptr_val.data.x_ptr.mut = ConstPtrMutComptimeConst; + ptr_val.data.x_ptr.special = ConstPtrSpecialRef; + ptr_val.data.x_ptr.data.ref.pointee = const_val; + if (const_ptr_pointee(ira, codegen, &ptr_val, source_node) == nullptr) + return ErrorSemanticAnalyzeFail; + + return ErrorNone; +} + +const char *container_string(ContainerKind kind) { + switch (kind) { + case ContainerKindEnum: return "enum"; + case ContainerKindStruct: return "struct"; + case ContainerKindUnion: return "union"; + } + zig_unreachable(); +} + +bool ptr_allows_addr_zero(ZigType *ptr_type) { + if (ptr_type->id == ZigTypeIdPointer) { + return ptr_type->data.pointer.allow_zero; + } else if (ptr_type->id == ZigTypeIdOptional) { + return true; + } + return false; +} |
