From 9b0868776646934bdec84888dabebbb2b8d9924e Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 5 Jul 2021 13:05:03 -0700 Subject: [PATCH 1/6] stage1: recursively resolve lazy values before hashing When putting ZigValues into a hash map. The hash of a lazy value and a fully resolved value must equal, and so we must resolve the lazy values prior. The hash function asserts that none of the values are lazy. --- src/stage1/ir.cpp | 98 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) diff --git a/src/stage1/ir.cpp b/src/stage1/ir.cpp index 22a4bdf92f..d4daa547c7 100644 --- a/src/stage1/ir.cpp +++ b/src/stage1/ir.cpp @@ -272,6 +272,10 @@ 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 Error ir_resolve_lazy_recurse(AstNode *source_node, ZigValue *val); +static Error ir_resolve_lazy_recurse_array(AstNode *source_node, ZigValue *val, size_t len); + + static void ir_assert_impl(bool ok, IrInstGen *source_instruction, char const *file, unsigned int line) { if (ok) return; src_assert_impl(ok, source_instruction->source_node, file, line); @@ -12935,6 +12939,18 @@ static IrInstGen *ir_analyze_fn_call(IrAnalyze *ira, Scope *scope, AstNode *sour break; } + // We are about to put ZigValues into a hash map. The hash of a lazy value and a + // fully resolved value must equal, and so we must resolve the lazy values here. + // The hash function asserts that none of the values are lazy. + for (size_t i = 0; i < generic_id->param_count; i += 1) { + ZigValue *generic_param = &generic_id->params[i]; + if (generic_param->special != ConstValSpecialRuntime) { + if ((err = ir_resolve_lazy_recurse(source_node, generic_param))) { + return ira->codegen->invalid_inst_gen; + } + } + } + auto existing_entry = ira->codegen->generic_table.put_unique(generic_id, impl_fn); if (existing_entry) { // throw away all our work and use the existing function @@ -25515,6 +25531,88 @@ static Error ir_resolve_lazy_raw(AstNode *source_node, ZigValue *val) { zig_unreachable(); } +static Error ir_resolve_lazy_recurse_array(AstNode *source_node, ZigValue *val, size_t len) { + Error err; + switch (val->data.x_array.special) { + case ConstArraySpecialUndef: + case ConstArraySpecialBuf: + return ErrorNone; + case ConstArraySpecialNone: + break; + } + ZigValue *elems = val->data.x_array.data.s_none.elements; + + for (size_t i = 0; i < len; i += 1) { + if ((err = ir_resolve_lazy_recurse(source_node, &elems[i]))) + return err; + } + + return ErrorNone; +} + +static Error ir_resolve_lazy_recurse(AstNode *source_node, ZigValue *val) { + Error err; + if ((err = ir_resolve_lazy_raw(source_node, val))) + return err; + if (val->special != ConstValSpecialStatic) + return ErrorNone; + switch (val->type->id) { + case ZigTypeIdOpaque: + case ZigTypeIdEnum: + case ZigTypeIdMetaType: + case ZigTypeIdBool: + case ZigTypeIdVoid: + case ZigTypeIdComptimeFloat: + case ZigTypeIdInt: + case ZigTypeIdComptimeInt: + case ZigTypeIdEnumLiteral: + case ZigTypeIdErrorSet: + case ZigTypeIdUndefined: + case ZigTypeIdNull: + case ZigTypeIdPointer: + case ZigTypeIdFn: + case ZigTypeIdAnyFrame: + case ZigTypeIdBoundFn: + case ZigTypeIdInvalid: + case ZigTypeIdUnreachable: + case ZigTypeIdFloat: + return ErrorNone; + case ZigTypeIdFnFrame: + zig_panic("TODO: ir_resolve_lazy_recurse ZigTypeIdFnFrame"); + case ZigTypeIdUnion: { + ConstUnionValue *union_val = &val->data.x_union; + return ir_resolve_lazy_recurse(source_node, union_val->payload); + } + case ZigTypeIdVector: + return ir_resolve_lazy_recurse_array(source_node, val, val->type->data.vector.len); + case ZigTypeIdArray: + return ir_resolve_lazy_recurse_array(source_node, val, val->type->data.array.len); + case ZigTypeIdStruct: + for (size_t i = 0; i < val->type->data.structure.src_field_count; i += 1) { + ZigValue *field = val->data.x_struct.fields[i]; + if ((err = ir_resolve_lazy_recurse(source_node, field))) + return err; + } + return ErrorNone; + case ZigTypeIdOptional: + if (get_src_ptr_type(val->type) != nullptr) + return ErrorNone; + if (val->data.x_optional == nullptr) + return ErrorNone; + + return ir_resolve_lazy_recurse(source_node, val->data.x_optional); + case ZigTypeIdErrorUnion: { + bool is_err = val->data.x_err_union.error_set->data.x_err_set != nullptr; + if (is_err) { + return ir_resolve_lazy_recurse(source_node, val->data.x_err_union.error_set); + } else { + return ir_resolve_lazy_recurse(source_node, val->data.x_err_union.payload); + } + } + } + zig_unreachable(); +} + Error ir_resolve_lazy(CodeGen *codegen, AstNode *source_node, ZigValue *val) { Error err; if ((err = ir_resolve_lazy_raw(source_node, val))) { From 0e5fa87ac9695378683e770fbe0d577521860d35 Mon Sep 17 00:00:00 2001 From: Martin Wickham Date: Mon, 5 Jul 2021 15:28:13 -0500 Subject: [PATCH 2/6] Better hashing, new asserts failing --- src/stage1/analyze.cpp | 384 ++++++++++++++++++++++------------------- src/stage1/bigint.cpp | 7 + src/stage1/bigint.hpp | 1 + src/stage1/buffer.hpp | 2 +- src/stage1/ir.cpp | 33 ++-- src/stage1/util.cpp | 23 --- src/stage1/util.hpp | 7 - 7 files changed, 238 insertions(+), 219 deletions(-) diff --git a/src/stage1/analyze.cpp b/src/stage1/analyze.cpp index a4cc39e7b4..a3ad584eaf 100644 --- a/src/stage1/analyze.cpp +++ b/src/stage1/analyze.cpp @@ -5507,34 +5507,48 @@ bool handle_is_ptr(CodeGen *g, ZigType *type_entry) { zig_unreachable(); } -static uint32_t hash_ptr(void *ptr) { - return (uint32_t)(((uintptr_t)ptr) % UINT32_MAX); +static const uint32_t HASH_INIT = 0x811c9dc5U; + +template +static uint32_t hash_combine(uint32_t hash, const T *value, size_t count = 1) { + // Simple FNV32 hash + size_t len = sizeof(T) * count; + const unsigned char *char_bytes = (const unsigned char*)value; + for (size_t c = 0; c < len; ++c) { + hash ^= char_bytes[c]; + hash *= 0x01000193U; + } + return hash; } -static uint32_t hash_size(size_t x) { - return (uint32_t)(x % UINT32_MAX); +static uint32_t hash_combine_bigint(uint32_t hash, const BigInt *value) { + return hash_combine(hash, bigint_ptr(value), value->digit_count); +} + +static uint32_t hash_combine_buf(uint32_t hash, const Buf *buf) { + return hash_combine(hash, buf_ptr(buf), buf_len(buf)); } uint32_t fn_table_entry_hash(ZigFn* value) { - return ptr_hash(value); + return hash_combine(HASH_INIT, &value); } bool fn_table_entry_eql(ZigFn *a, ZigFn *b) { - return ptr_eq(a, b); + return a == b; } uint32_t fn_type_id_hash(FnTypeId *id) { - uint32_t result = 0; - result += ((uint32_t)(id->cc)) * (uint32_t)3349388391; - result += id->is_var_args ? (uint32_t)1931444534 : 0; - result += hash_ptr(id->return_type); - result += id->alignment * 0xd3b3f3e2; + uint32_t hash = HASH_INIT; + hash = hash_combine(hash, &id->cc); + hash = hash_combine(hash, &id->is_var_args); + hash = hash_combine(hash, &id->return_type); + hash = hash_combine(hash, &id->alignment); for (size_t i = 0; i < id->param_count; i += 1) { FnTypeParamInfo *info = &id->param_info[i]; - result += info->is_noalias ? (uint32_t)892356923 : 0; - result += hash_ptr(info->type); + hash = hash_combine(hash, &info->is_noalias); + hash = hash_combine(hash, &info->type); } - return result; + return hash; } bool fn_type_id_eql(FnTypeId *a, FnTypeId *b) { @@ -5559,194 +5573,202 @@ bool fn_type_id_eql(FnTypeId *a, FnTypeId *b) { return true; } -static uint32_t hash_const_val_error_set(ZigValue *const_val) { +static uint32_t hash_combine_const_val_error_set(uint32_t hash_val, ZigValue *const_val) { assert(const_val->data.x_err_set != nullptr); - return const_val->data.x_err_set->value ^ 2630160122; + return hash_combine(hash_val, &const_val->data.x_err_set->value); } -static uint32_t hash_const_val_ptr(ZigValue *const_val) { - uint32_t hash_val = 0; - switch (const_val->data.x_ptr.mut) { - case ConstPtrMutRuntimeVar: - hash_val += (uint32_t)3500721036; - break; - case ConstPtrMutComptimeConst: - hash_val += (uint32_t)4214318515; - break; - case ConstPtrMutInfer: - case ConstPtrMutComptimeVar: - hash_val += (uint32_t)1103195694; - break; - } +static uint32_t hash_combine_const_val_ptr(uint32_t hash_val, ZigValue *const_val) { + hash_val = hash_combine(hash_val, &const_val->data.x_ptr.special); switch (const_val->data.x_ptr.special) { case ConstPtrSpecialInvalid: zig_unreachable(); case ConstPtrSpecialRef: - hash_val += (uint32_t)2478261866; - hash_val += hash_ptr(const_val->data.x_ptr.data.ref.pointee); + hash_val = hash_combine(hash_val, &const_val->data.x_ptr.data.ref.pointee); return hash_val; case ConstPtrSpecialBaseArray: - hash_val += (uint32_t)1764906839; - hash_val += hash_ptr(const_val->data.x_ptr.data.base_array.array_val); - hash_val += hash_size(const_val->data.x_ptr.data.base_array.elem_index); + hash_val = hash_combine(hash_val, &const_val->data.x_ptr.data.base_array.array_val); + hash_val = hash_combine(hash_val, &const_val->data.x_ptr.data.base_array.elem_index); return hash_val; case ConstPtrSpecialSubArray: - hash_val += (uint32_t)2643358777; - hash_val += hash_ptr(const_val->data.x_ptr.data.base_array.array_val); - hash_val += hash_size(const_val->data.x_ptr.data.base_array.elem_index); + hash_val = hash_combine(hash_val, &const_val->data.x_ptr.data.base_array.array_val); + hash_val = hash_combine(hash_val, &const_val->data.x_ptr.data.base_array.elem_index); return hash_val; case ConstPtrSpecialBaseStruct: - hash_val += (uint32_t)3518317043; - 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); + hash_val = hash_combine(hash_val, &const_val->data.x_ptr.data.base_struct.struct_val); + hash_val = hash_combine(hash_val, &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); + hash_val = hash_combine(hash_val, &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); + hash_val = hash_combine(hash_val, &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); + hash_val = hash_combine(hash_val, &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); - return hash_val; - case ConstPtrSpecialDiscard: - hash_val += 2010123162; + hash_val = hash_combine(hash_val, &const_val->data.x_ptr.data.hard_coded_addr.addr); return hash_val; case ConstPtrSpecialFunction: - hash_val += (uint32_t)2590901619; - hash_val += hash_ptr(const_val->data.x_ptr.data.fn.fn_entry); + hash_val = hash_combine(hash_val, &const_val->data.x_ptr.data.fn.fn_entry); return hash_val; + case ConstPtrSpecialDiscard: case ConstPtrSpecialNull: - hash_val += (uint32_t)1486246455; + // No fields to hash return hash_val; } zig_unreachable(); } -static uint32_t hash_const_val(ZigValue *const_val) { +static uint32_t hash_combine_const_val(uint32_t hash_val, ZigValue *const_val); +static uint32_t hash_combine_const_val_array(uint32_t hash_val, ZigValue *array, size_t len) { + if (array->data.x_array.special == ConstArraySpecialUndef) { + char undef_tag = 56; + return hash_combine(hash_val, &undef_tag); + } else if (array->data.x_array.special == ConstArraySpecialBuf) { + // Hash in a way that is compatible with standard byte arrays + // If any of these asserts fails, the if after this needs to be modified + // to handle the new type in SpecialBuf. + assert(array->type->data.array.child_type->id == ZigTypeIdInt); + assert(array->type->data.array.child_type->data.integral.bit_count == 8); + assert(array->type->data.array.child_type->data.integral.is_signed == false); + const char *buf_pos = buf_ptr(array->data.x_array.data.s_buf); + const char *buf_end = buf_pos + buf_len(array->data.x_array.data.s_buf); + while (buf_pos < buf_end) { + hash_val = hash_combine(hash_val, buf_pos); + buf_pos++; + } + return hash_val; + } else if (array->type->data.array.child_type->id == ZigTypeIdInt && + array->type->data.array.child_type->data.integral.bit_count == 8 && + array->type->data.array.child_type->data.integral.is_signed == false) { + // If the type is u8, we hash it as if it's a ConstArraySpecialBuf, + // to maintain compatibility. + ZigValue *elems = array->data.x_array.data.s_none.elements; + for (size_t i = 0; i < len; i += 1) { + ZigValue *value = &elems[i]; + assert(value->type == array->type->data.array.child_type); + // N.B. Using char here instead of uint8_t to match the const char* + // returned by buf_ptr. + const char byte_value = (char) bigint_as_u8(&value->data.x_bigint); + hash_val = hash_combine(hash_val, &byte_value); + } + return hash_val; + } else { + ZigValue *elems = array->data.x_array.data.s_none.elements; + for (size_t i = 0; i < len; i += 1) { + hash_val = hash_combine_const_val(hash_val, &elems[i]); + } + return hash_val; + } +} +static uint32_t hash_combine_const_val(uint32_t hash_val, ZigValue *const_val) { + hash_val = hash_combine(hash_val, &const_val->special); + if (const_val->special == ConstValSpecialUndef) { + return hash_val; + } + // if (const_val->special == ConstValSpecialLazy || + // const_val->special == ConstValSpecialRuntime) { + // // NO_COMMIT verify this is correct + // return hash_combine(hash_val, &const_val); + // } + if (const_val->special != ConstValSpecialStatic) { + printf("\nInvalid special: %d\n", const_val->special); + } assert(const_val->special == ConstValSpecialStatic); + hash_val = hash_combine(hash_val, &const_val->type->id); switch (const_val->type->id) { case ZigTypeIdOpaque: zig_unreachable(); case ZigTypeIdBool: - return const_val->data.x_bool ? (uint32_t)127863866 : (uint32_t)215080464; + return hash_combine(hash_val, &const_val->data.x_bool); case ZigTypeIdMetaType: - return hash_ptr(const_val->data.x_type); - case ZigTypeIdVoid: - return (uint32_t)4149439618; + return hash_combine(hash_val, &const_val->data.x_type); case ZigTypeIdInt: case ZigTypeIdComptimeInt: - { - uint32_t result = 1331471175; - for (size_t i = 0; i < const_val->data.x_bigint.digit_count; i += 1) { - uint64_t digit = bigint_ptr(&const_val->data.x_bigint)[i]; - result ^= ((uint32_t)(digit >> 32)) ^ (uint32_t)(result); - } - return result; - } + return hash_combine_bigint(hash_val, &const_val->data.x_bigint); case ZigTypeIdEnumLiteral: - return buf_hash(const_val->data.x_enum_literal) * (uint32_t)2691276464; + return hash_combine_buf(hash_val, const_val->data.x_enum_literal); case ZigTypeIdEnum: - { - uint32_t result = 31643936; - for (size_t i = 0; i < const_val->data.x_enum_tag.digit_count; i += 1) { - uint64_t digit = bigint_ptr(&const_val->data.x_enum_tag)[i]; - result ^= ((uint32_t)(digit >> 32)) ^ (uint32_t)(result); - } - return result; - } + return hash_combine_bigint(hash_val, &const_val->data.x_enum_tag); case ZigTypeIdFloat: + hash_val = hash_combine(hash_val, &const_val->type->data.floating.bit_count); switch (const_val->type->data.floating.bit_count) { - case 16: - { - uint16_t result; - static_assert(sizeof(result) == sizeof(const_val->data.x_f16), ""); - memcpy(&result, &const_val->data.x_f16, sizeof(result)); - return result * 65537u; - } - case 32: - { - uint32_t result; - memcpy(&result, &const_val->data.x_f32, 4); - return result ^ 4084870010; - } - case 64: - { - uint32_t ints[2]; - memcpy(&ints[0], &const_val->data.x_f64, 8); - return ints[0] ^ ints[1] ^ 0x22ed43c6; - } - case 128: - { - uint32_t ints[4]; - memcpy(&ints[0], &const_val->data.x_f128, 16); - return ints[0] ^ ints[1] ^ ints[2] ^ ints[3] ^ 0xb5ffef27; - } - default: - zig_unreachable(); + case 16: return hash_combine(hash_val, &const_val->data.x_f16); + case 32: return hash_combine(hash_val, &const_val->data.x_f32); + case 64: return hash_combine(hash_val, &const_val->data.x_f64); + case 128: return hash_combine(hash_val, &const_val->data.x_f128); + default: zig_unreachable(); } case ZigTypeIdComptimeFloat: - { - float128_t f128 = bigfloat_to_f128(&const_val->data.x_bigfloat); - uint32_t ints[4]; - memcpy(&ints[0], &f128, 16); - return ints[0] ^ ints[1] ^ ints[2] ^ ints[3] ^ 0xed8b3dfb; - } + return hash_combine(hash_val, &const_val->data.x_bigfloat.value); case ZigTypeIdFn: assert(const_val->data.x_ptr.mut == ConstPtrMutComptimeConst); assert(const_val->data.x_ptr.special == ConstPtrSpecialFunction); - return 3677364617 ^ hash_ptr(const_val->data.x_ptr.data.fn.fn_entry); + return hash_combine(hash_val, &const_val->data.x_ptr.data.fn.fn_entry); case ZigTypeIdPointer: - return hash_const_val_ptr(const_val); + return hash_combine_const_val_ptr(hash_val, const_val); + case ZigTypeIdVoid: case ZigTypeIdUndefined: - return 162837799; case ZigTypeIdNull: - return 844854567; + return hash_val; case ZigTypeIdArray: - // TODO better hashing algorithm - return 1166190605; - case ZigTypeIdStruct: - // TODO better hashing algorithm - return 1532530855; - case ZigTypeIdUnion: - // TODO better hashing algorithm - return 2709806591; + return hash_combine_const_val_array(hash_val, const_val, const_val->type->data.array.len); + case ZigTypeIdStruct: { + size_t field_count = const_val->type->data.structure.src_field_count; + for (size_t i = 0; i < field_count; i += 1) { + ZigValue *field = const_val->data.x_struct.fields[i]; + hash_val = hash_combine_const_val(hash_val, field); + } + return hash_val; + } + case ZigTypeIdUnion: { + ConstUnionValue *union_value = &const_val->data.x_union; + hash_val = hash_combine_bigint(hash_val, &union_value->tag); + return hash_combine_const_val(hash_val, union_value->payload); + } case ZigTypeIdOptional: if (get_src_ptr_type(const_val->type) != nullptr) { - return hash_const_val_ptr(const_val) * (uint32_t)1992916303; + char tag = 1; + hash_val = hash_combine(hash_val, &tag); + return hash_combine_const_val_ptr(hash_val, const_val); } else if (const_val->type->data.maybe.child_type->id == ZigTypeIdErrorSet) { - return hash_const_val_error_set(const_val) * (uint32_t)3147031929; + char tag = 2; + hash_val = hash_combine(hash_val, &tag); + return hash_combine_const_val_error_set(hash_val, const_val); + } else if (const_val->data.x_optional) { + char tag = 3; + hash_val = hash_combine(hash_val, &tag); + return hash_combine_const_val(hash_val, const_val->data.x_optional); } else { - if (const_val->data.x_optional) { - return hash_const_val(const_val->data.x_optional) * (uint32_t)1992916303; - } else { - return 4016830364; - } + char tag = 4; + hash_val = hash_combine(hash_val, &tag); + return hash_val; } - case ZigTypeIdErrorUnion: - // TODO better hashing algorithm - return 3415065496; + case ZigTypeIdErrorUnion: { + bool is_err = const_val->data.x_err_union.error_set->data.x_err_set != nullptr; + hash_val = hash_combine(hash_val, &is_err); + if (is_err) { + hash_val = hash_combine_const_val(hash_val, const_val->data.x_err_union.error_set); + } else { + hash_val = hash_combine_const_val(hash_val, const_val->data.x_err_union.payload); + } + return hash_val; + } case ZigTypeIdErrorSet: - return hash_const_val_error_set(const_val); + return hash_combine_const_val_error_set(hash_val, const_val); case ZigTypeIdVector: - // TODO better hashing algorithm - return 3647867726; + return hash_combine_const_val_array(hash_val, const_val, const_val->type->data.vector.len); case ZigTypeIdFnFrame: // TODO better hashing algorithm - return 675741936; + return hash_val; case ZigTypeIdAnyFrame: // TODO better hashing algorithm - return 3747294894; + return hash_val; case ZigTypeIdBoundFn: { assert(const_val->data.x_bound_fn.fn != nullptr); - return 3677364617 ^ hash_ptr(const_val->data.x_bound_fn.fn); + return hash_combine(hash_val, &const_val->data.x_bound_fn.fn); } case ZigTypeIdInvalid: case ZigTypeIdUnreachable: @@ -5754,15 +5776,18 @@ static uint32_t hash_const_val(ZigValue *const_val) { } zig_unreachable(); } +static uint32_t hash_const_val(ZigValue *const_val) { + return hash_combine_const_val(HASH_INIT, const_val); +} uint32_t generic_fn_type_id_hash(GenericFnTypeId *id) { - uint32_t result = 0; - result += hash_ptr(id->fn_entry); + uint32_t result = HASH_INIT; + result = hash_combine(result, &id->fn_entry); for (size_t i = 0; i < id->param_count; i += 1) { ZigValue *generic_param = &id->params[i]; if (generic_param->special != ConstValSpecialRuntime) { - result += hash_const_val(generic_param); - result += hash_ptr(generic_param->type); + result = hash_combine_const_val(result, generic_param); + result = hash_combine(result, &generic_param->type); } } return result; @@ -5957,15 +5982,15 @@ bool fn_eval_cacheable(Scope *scope, ZigType *return_type) { } uint32_t fn_eval_hash(Scope* scope) { - uint32_t result = 0; + uint32_t hash = HASH_INIT; while (scope) { if (scope->id == ScopeIdVarDecl) { ScopeVarDecl *var_scope = (ScopeVarDecl *)scope; - result += hash_const_val(var_scope->var->const_value); + hash = hash_combine_const_val(hash, var_scope->var->const_value); } else if (scope->id == ScopeIdFnDef) { ScopeFnDef *fn_scope = (ScopeFnDef *)scope; - result += hash_ptr(fn_scope->fn_entry); - return result; + hash = hash_combine(hash, &fn_scope->fn_entry); + return hash; } else { zig_unreachable(); } @@ -7260,6 +7285,8 @@ bool const_values_equal(CodeGen *g, ZigValue *a, ZigValue *b) { case ZigTypeIdMetaType: return a->data.x_type == b->data.x_type; case ZigTypeIdVoid: + case ZigTypeIdUndefined: + case ZigTypeIdNull: return true; case ZigTypeIdErrorSet: return a->data.x_err_set->value == b->data.x_err_set->value; @@ -7292,10 +7319,9 @@ bool const_values_equal(CodeGen *g, ZigValue *a, ZigValue *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: { + case ZigTypeIdArray: assert(a->type->data.array.len == b->type->data.array.len); 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) { ZigValue *field_a = a->data.x_struct.fields[i]; @@ -7308,10 +7334,6 @@ bool const_values_equal(CodeGen *g, ZigValue *a, ZigValue *b) { zig_panic("TODO: const_values_equal ZigTypeIdFnFrame"); case ZigTypeIdAnyFrame: zig_panic("TODO: const_values_equal ZigTypeIdAnyFrame"); - case ZigTypeIdUndefined: - zig_panic("TODO: const_values_equal ZigTypeIdUndefined"); - case ZigTypeIdNull: - zig_panic("TODO: const_values_equal ZigTypeIdNull"); case ZigTypeIdOptional: if (get_src_ptr_type(a->type) != nullptr) return const_values_equal_ptr(a, b); @@ -7719,6 +7741,7 @@ ZigType *make_int_type(CodeGen *g, bool is_signed, uint32_t size_in_bits) { } uint32_t type_id_hash(TypeId x) { + uint32_t hash = hash_combine(HASH_INIT, &x.id); switch (x.id) { case ZigTypeIdInvalid: case ZigTypeIdOpaque: @@ -7743,27 +7766,38 @@ uint32_t type_id_hash(TypeId x) { case ZigTypeIdAnyFrame: zig_unreachable(); case ZigTypeIdErrorUnion: - return hash_ptr(x.data.error_union.err_set_type) ^ hash_ptr(x.data.error_union.payload_type); + hash = hash_combine(hash, &x.data.error_union.err_set_type); + hash = hash_combine(hash, &x.data.error_union.payload_type); + return hash; case ZigTypeIdPointer: - return hash_ptr(x.data.pointer.child_type) + - (uint32_t)x.data.pointer.ptr_len * 1120226602u + - (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.vector_index) ^ (uint32_t)0x19199716) + - (((uint32_t)x.data.pointer.host_int_bytes) ^ (uint32_t)529908881) * - (x.data.pointer.sentinel ? hash_const_val(x.data.pointer.sentinel) : (uint32_t)2955491856); + hash = hash_combine(hash, &x.data.pointer.child_type); + hash = hash_combine(hash, &x.data.pointer.ptr_len); + hash = hash_combine(hash, &x.data.pointer.is_const); + hash = hash_combine(hash, &x.data.pointer.is_volatile); + hash = hash_combine(hash, &x.data.pointer.allow_zero); + hash = hash_combine(hash, &x.data.pointer.alignment); + hash = hash_combine(hash, &x.data.pointer.bit_offset_in_host); + hash = hash_combine(hash, &x.data.pointer.vector_index); + hash = hash_combine(hash, &x.data.pointer.host_int_bytes); + if (x.data.pointer.sentinel != nullptr) { + hash = hash_combine_const_val(hash, x.data.pointer.sentinel); + } + return hash; case ZigTypeIdArray: - return hash_ptr(x.data.array.child_type) * - ((uint32_t)x.data.array.size ^ (uint32_t)2122979968) * - (x.data.array.sentinel ? hash_const_val(x.data.array.sentinel) : (uint32_t)1927201585); + hash = hash_combine(hash, &x.data.array.child_type); + hash = hash_combine(hash, &x.data.array.size); + if (x.data.array.sentinel != nullptr) { + hash = hash_combine_const_val(hash, x.data.array.sentinel); + } + return hash; case ZigTypeIdInt: - return (x.data.integer.is_signed ? (uint32_t)2652528194 : (uint32_t)163929201) + - (((uint32_t)x.data.integer.bit_count) ^ (uint32_t)2998081557); + hash = hash_combine(hash, &x.data.integer.is_signed); + hash = hash_combine(hash, &x.data.integer.bit_count); + return hash; case ZigTypeIdVector: - return hash_ptr(x.data.vector.elem_type) * (x.data.vector.len * 526582681); + hash = hash_combine(hash, &x.data.vector.elem_type); + hash = hash_combine(hash, &x.data.vector.len); + return hash; } zig_unreachable(); } @@ -8155,7 +8189,7 @@ ZigType *get_align_amt_type(CodeGen *g) { } uint32_t type_ptr_hash(const ZigType *ptr) { - return hash_ptr((void*)ptr); + return hash_combine(HASH_INIT, &ptr); } bool type_ptr_eql(const ZigType *a, const ZigType *b) { @@ -8163,7 +8197,7 @@ bool type_ptr_eql(const ZigType *a, const ZigType *b) { } uint32_t pkg_ptr_hash(const ZigPackage *ptr) { - return hash_ptr((void*)ptr); + return hash_combine(HASH_INIT, &ptr); } bool pkg_ptr_eql(const ZigPackage *a, const ZigPackage *b) { @@ -8171,7 +8205,7 @@ bool pkg_ptr_eql(const ZigPackage *a, const ZigPackage *b) { } uint32_t tld_ptr_hash(const Tld *ptr) { - return hash_ptr((void*)ptr); + return hash_combine(HASH_INIT, &ptr); } bool tld_ptr_eql(const Tld *a, const Tld *b) { @@ -8179,7 +8213,7 @@ bool tld_ptr_eql(const Tld *a, const Tld *b) { } uint32_t node_ptr_hash(const AstNode *ptr) { - return hash_ptr((void*)ptr); + return hash_combine(HASH_INIT, &ptr); } bool node_ptr_eql(const AstNode *a, const AstNode *b) { @@ -8187,7 +8221,7 @@ bool node_ptr_eql(const AstNode *a, const AstNode *b) { } uint32_t fn_ptr_hash(const ZigFn *ptr) { - return hash_ptr((void*)ptr); + return hash_combine(HASH_INIT, &ptr); } bool fn_ptr_eql(const ZigFn *a, const ZigFn *b) { @@ -8195,7 +8229,7 @@ bool fn_ptr_eql(const ZigFn *a, const ZigFn *b) { } uint32_t err_ptr_hash(const ErrorTableEntry *ptr) { - return hash_ptr((void*)ptr); + return hash_combine(HASH_INIT, &ptr); } bool err_ptr_eql(const ErrorTableEntry *a, const ErrorTableEntry *b) { diff --git a/src/stage1/bigint.cpp b/src/stage1/bigint.cpp index acb3e18e41..97181b6ad2 100644 --- a/src/stage1/bigint.cpp +++ b/src/stage1/bigint.cpp @@ -1691,6 +1691,13 @@ uint32_t bigint_as_u32(const BigInt *bigint) { return value32; } +uint8_t bigint_as_u8(const BigInt *bigint) { + uint64_t value64 = bigint_as_unsigned(bigint); + uint8_t value8 = (uint8_t)value64; + assert (value64 == value8); + return value8; +} + size_t bigint_as_usize(const BigInt *bigint) { uint64_t value64 = bigint_as_unsigned(bigint); size_t valueUsize = (size_t)value64; diff --git a/src/stage1/bigint.hpp b/src/stage1/bigint.hpp index aa37b9302a..521de25b1c 100644 --- a/src/stage1/bigint.hpp +++ b/src/stage1/bigint.hpp @@ -39,6 +39,7 @@ void bigint_deinit(BigInt *bi); // panics if number won't fit uint64_t bigint_as_u64(const BigInt *bigint); uint32_t bigint_as_u32(const BigInt *bigint); +uint8_t bigint_as_u8(const BigInt *bigint); size_t bigint_as_usize(const BigInt *bigint); int64_t bigint_as_signed(const BigInt *bigint); diff --git a/src/stage1/buffer.hpp b/src/stage1/buffer.hpp index 8876316589..d8a31b1bf4 100644 --- a/src/stage1/buffer.hpp +++ b/src/stage1/buffer.hpp @@ -26,7 +26,7 @@ Buf *buf_sprintf(const char *format, ...) ATTRIBUTE_PRINTF(1, 2); Buf *buf_vprintf(const char *format, va_list ap); -static inline size_t buf_len(Buf *buf) { +static inline size_t buf_len(const Buf *buf) { assert(buf); assert(buf->list.length); return buf->list.length - 1; diff --git a/src/stage1/ir.cpp b/src/stage1/ir.cpp index d4daa547c7..b5dbdd3c21 100644 --- a/src/stage1/ir.cpp +++ b/src/stage1/ir.cpp @@ -272,8 +272,8 @@ 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 Error ir_resolve_lazy_recurse(AstNode *source_node, ZigValue *val); -static Error ir_resolve_lazy_recurse_array(AstNode *source_node, ZigValue *val, size_t len); +static Error ir_resolve_lazy_recurse(IrAnalyze *ira, AstNode *source_node, ZigValue *val); +static Error ir_resolve_lazy_recurse_array(IrAnalyze *ira, AstNode *source_node, ZigValue *val, size_t len); static void ir_assert_impl(bool ok, IrInstGen *source_instruction, char const *file, unsigned int line) { @@ -12945,7 +12945,7 @@ static IrInstGen *ir_analyze_fn_call(IrAnalyze *ira, Scope *scope, AstNode *sour for (size_t i = 0; i < generic_id->param_count; i += 1) { ZigValue *generic_param = &generic_id->params[i]; if (generic_param->special != ConstValSpecialRuntime) { - if ((err = ir_resolve_lazy_recurse(source_node, generic_param))) { + if ((err = ir_resolve_lazy_recurse(ira, source_node, generic_param))) { return ira->codegen->invalid_inst_gen; } } @@ -25531,7 +25531,7 @@ static Error ir_resolve_lazy_raw(AstNode *source_node, ZigValue *val) { zig_unreachable(); } -static Error ir_resolve_lazy_recurse_array(AstNode *source_node, ZigValue *val, size_t len) { +static Error ir_resolve_lazy_recurse_array(IrAnalyze *ira, AstNode *source_node, ZigValue *val, size_t len) { Error err; switch (val->data.x_array.special) { case ConstArraySpecialUndef: @@ -25543,17 +25543,24 @@ static Error ir_resolve_lazy_recurse_array(AstNode *source_node, ZigValue *val, ZigValue *elems = val->data.x_array.data.s_none.elements; for (size_t i = 0; i < len; i += 1) { - if ((err = ir_resolve_lazy_recurse(source_node, &elems[i]))) + if ((err = ir_resolve_lazy_recurse(ira, source_node, &elems[i]))) return err; } return ErrorNone; } -static Error ir_resolve_lazy_recurse(AstNode *source_node, ZigValue *val) { +static Error ir_resolve_lazy_recurse(IrAnalyze *ira, AstNode *source_node, ZigValue *val) { Error err; if ((err = ir_resolve_lazy_raw(source_node, val))) return err; + if (val->special == ConstValSpecialRuntime) { + // This shouldn't be possible, it indicates an ICE. + // NO_COMMIT + ir_add_error_node(ira, source_node, + buf_sprintf("This is a bug in the Zig compiler. Runtime value found in comptime known parameter.")); + return ErrorSemanticAnalyzeFail; + } if (val->special != ConstValSpecialStatic) return ErrorNone; switch (val->type->id) { @@ -25581,16 +25588,16 @@ static Error ir_resolve_lazy_recurse(AstNode *source_node, ZigValue *val) { zig_panic("TODO: ir_resolve_lazy_recurse ZigTypeIdFnFrame"); case ZigTypeIdUnion: { ConstUnionValue *union_val = &val->data.x_union; - return ir_resolve_lazy_recurse(source_node, union_val->payload); + return ir_resolve_lazy_recurse(ira, source_node, union_val->payload); } case ZigTypeIdVector: - return ir_resolve_lazy_recurse_array(source_node, val, val->type->data.vector.len); + return ir_resolve_lazy_recurse_array(ira, source_node, val, val->type->data.vector.len); case ZigTypeIdArray: - return ir_resolve_lazy_recurse_array(source_node, val, val->type->data.array.len); + return ir_resolve_lazy_recurse_array(ira, source_node, val, val->type->data.array.len); case ZigTypeIdStruct: for (size_t i = 0; i < val->type->data.structure.src_field_count; i += 1) { ZigValue *field = val->data.x_struct.fields[i]; - if ((err = ir_resolve_lazy_recurse(source_node, field))) + if ((err = ir_resolve_lazy_recurse(ira, source_node, field))) return err; } return ErrorNone; @@ -25600,13 +25607,13 @@ static Error ir_resolve_lazy_recurse(AstNode *source_node, ZigValue *val) { if (val->data.x_optional == nullptr) return ErrorNone; - return ir_resolve_lazy_recurse(source_node, val->data.x_optional); + return ir_resolve_lazy_recurse(ira, source_node, val->data.x_optional); case ZigTypeIdErrorUnion: { bool is_err = val->data.x_err_union.error_set->data.x_err_set != nullptr; if (is_err) { - return ir_resolve_lazy_recurse(source_node, val->data.x_err_union.error_set); + return ir_resolve_lazy_recurse(ira, source_node, val->data.x_err_union.error_set); } else { - return ir_resolve_lazy_recurse(source_node, val->data.x_err_union.payload); + return ir_resolve_lazy_recurse(ira, source_node, val->data.x_err_union.payload); } } } diff --git a/src/stage1/util.cpp b/src/stage1/util.cpp index 2de09df808..e1e167adf9 100644 --- a/src/stage1/util.cpp +++ b/src/stage1/util.cpp @@ -21,29 +21,6 @@ void zig_panic(const char *format, ...) { abort(); } -uint32_t int_hash(int i) { - return (uint32_t)(i % UINT32_MAX); -} -bool int_eq(int a, int b) { - return a == b; -} - -uint32_t uint64_hash(uint64_t i) { - return (uint32_t)(i % UINT32_MAX); -} - -bool uint64_eq(uint64_t a, uint64_t b) { - return a == b; -} - -uint32_t ptr_hash(const void *ptr) { - return (uint32_t)(((uintptr_t)ptr) % UINT32_MAX); -} - -bool ptr_eq(const void *a, const void *b) { - return a == b; -} - // Ported from std/mem.zig. bool SplitIterator_isSplitByte(SplitIterator *self, uint8_t byte) { for (size_t i = 0; i < self->split_bytes.len; i += 1) { diff --git a/src/stage1/util.hpp b/src/stage1/util.hpp index bb4ff00f7a..35fa49acce 100644 --- a/src/stage1/util.hpp +++ b/src/stage1/util.hpp @@ -129,13 +129,6 @@ static inline uint64_t round_to_next_power_of_2(uint64_t x) { return x + 1; } -uint32_t int_hash(int i); -bool int_eq(int a, int b); -uint32_t uint64_hash(uint64_t i); -bool uint64_eq(uint64_t a, uint64_t b); -uint32_t ptr_hash(const void *ptr); -bool ptr_eq(const void *a, const void *b); - static inline uint8_t log2_u64(uint64_t x) { return (63 - clzll(x)); } From 0ff9a4d21c1b65c574659be295446f2dd7591723 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 5 Jul 2021 14:07:36 -0700 Subject: [PATCH 3/6] stage1: resolve lazy values before comptime fn call --- src/stage1/analyze.cpp | 5 +---- src/stage1/ir.cpp | 25 ++++++++++++++++++++++++- src/stage1/zig0.cpp | 5 ++++- 3 files changed, 29 insertions(+), 6 deletions(-) diff --git a/src/stage1/analyze.cpp b/src/stage1/analyze.cpp index a3ad584eaf..0f59612357 100644 --- a/src/stage1/analyze.cpp +++ b/src/stage1/analyze.cpp @@ -5674,7 +5674,7 @@ static uint32_t hash_combine_const_val(uint32_t hash_val, ZigValue *const_val) { // return hash_combine(hash_val, &const_val); // } if (const_val->special != ConstValSpecialStatic) { - printf("\nInvalid special: %d\n", const_val->special); + fprintf(stderr, "\nInvalid special: %d\n", const_val->special); } assert(const_val->special == ConstValSpecialStatic); hash_val = hash_combine(hash_val, &const_val->type->id); @@ -5776,9 +5776,6 @@ static uint32_t hash_combine_const_val(uint32_t hash_val, ZigValue *const_val) { } zig_unreachable(); } -static uint32_t hash_const_val(ZigValue *const_val) { - return hash_combine_const_val(HASH_INIT, const_val); -} uint32_t generic_fn_type_id_hash(GenericFnTypeId *id) { uint32_t result = HASH_INIT; diff --git a/src/stage1/ir.cpp b/src/stage1/ir.cpp index b5dbdd3c21..062750225d 100644 --- a/src/stage1/ir.cpp +++ b/src/stage1/ir.cpp @@ -12754,6 +12754,29 @@ static IrInstGen *ir_analyze_fn_call(IrAnalyze *ira, Scope *scope, AstNode *sour bool cacheable = fn_eval_cacheable(exec_scope, return_type); ZigValue *result = nullptr; if (cacheable) { + // We are about to put ZigValues into a hash map. The hash of a lazy value and a + // fully resolved value must equal, and so we must resolve the lazy values here. + // The hash function asserts that none of the values are lazy. + { + Scope *scope = exec_scope; + while (scope) { + if (scope->id == ScopeIdVarDecl) { + ScopeVarDecl *var_scope = (ScopeVarDecl *)scope; + if ((err = ir_resolve_lazy_recurse(ira, + var_scope->var->decl_node, + var_scope->var->const_value))) + { + return ira->codegen->invalid_inst_gen; + } + } else if (scope->id == ScopeIdFnDef) { + break; + } else { + zig_unreachable(); + } + scope = scope->parent; + } + } + auto entry = ira->codegen->memoized_fn_eval_table.maybe_get(exec_scope); if (entry) result = entry->value; @@ -25558,7 +25581,7 @@ static Error ir_resolve_lazy_recurse(IrAnalyze *ira, AstNode *source_node, ZigVa // This shouldn't be possible, it indicates an ICE. // NO_COMMIT ir_add_error_node(ira, source_node, - buf_sprintf("This is a bug in the Zig compiler. Runtime value found in comptime known parameter.")); + buf_sprintf("This is a bug in the Zig compiler. Runtime value found in comptime known value.")); return ErrorSemanticAnalyzeFail; } if (val->special != ConstValSpecialStatic) diff --git a/src/stage1/zig0.cpp b/src/stage1/zig0.cpp index a68973037f..f2412a74ef 100644 --- a/src/stage1/zig0.cpp +++ b/src/stage1/zig0.cpp @@ -265,6 +265,7 @@ int main(int argc, char **argv) { const char *override_lib_dir = nullptr; const char *mcpu = nullptr; bool single_threaded = false; + bool is_test_build = false; for (int i = 1; i < argc; i += 1) { char *arg = argv[i]; @@ -272,6 +273,8 @@ int main(int argc, char **argv) { if (arg[0] == '-') { if (strcmp(arg, "--") == 0) { fprintf(stderr, "Unexpected end-of-parameter mark: %s\n", arg); + } else if (strcmp(arg, "--test") == 0) { + is_test_build = true; } else if (strcmp(arg, "-ODebug") == 0) { optimize_mode = BuildModeDebug; } else if (strcmp(arg, "-OReleaseFast") == 0) { @@ -446,7 +449,7 @@ int main(int argc, char **argv) { nullptr, 0, in_file, strlen(in_file), override_lib_dir, strlen(override_lib_dir), - &target, false); + &target, is_test_build); stage1->main_progress_node = root_progress_node; stage1->root_name_ptr = out_name; From b3225a755a78502245bc9c7d7419ebeb67201320 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 5 Jul 2021 16:22:40 -0700 Subject: [PATCH 4/6] stage1: avoid incorrectly reading ZigValue data Hashing, equality checking, and expanding lazy values were not inspecting the is_comptime field of structs, causing incorrect behavior for tuples. When looking at a comptime value of a struct, if the is_comptime field is true, the value must be learned from the type rather than the value. --- src/stage1/analyze.cpp | 21 ++++++++++++++++++--- src/stage1/ir.cpp | 5 +++++ 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/src/stage1/analyze.cpp b/src/stage1/analyze.cpp index 0f59612357..d551dec221 100644 --- a/src/stage1/analyze.cpp +++ b/src/stage1/analyze.cpp @@ -5719,6 +5719,12 @@ static uint32_t hash_combine_const_val(uint32_t hash_val, ZigValue *const_val) { size_t field_count = const_val->type->data.structure.src_field_count; for (size_t i = 0; i < field_count; i += 1) { ZigValue *field = const_val->data.x_struct.fields[i]; + if (const_val->type->data.structure.fields[i]->is_comptime) { + // The values of comptime struct fields are part of the + // type, not the value, so they do not participate in equality + // or hash of comptime values. + continue; + } hash_val = hash_combine_const_val(hash_val, field); } return hash_val; @@ -7321,6 +7327,12 @@ bool const_values_equal(CodeGen *g, ZigValue *a, ZigValue *b) { 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) { + if (a->type->data.structure.fields[i]->is_comptime) { + // The values of comptime struct fields are part of the + // type, not the value, so they do not participate in equality + // or hash of comptime values. + continue; + } ZigValue *field_a = a->data.x_struct.fields[i]; ZigValue *field_b = b->data.x_struct.fields[i]; if (!const_values_equal(g, field_a, field_b)) @@ -9945,10 +9957,13 @@ void copy_const_val(CodeGen *g, ZigValue *dest, ZigValue *src) { dest->data.x_struct.fields = alloc_const_vals_ptrs(g, dest->type->data.structure.src_field_count); for (size_t i = 0; i < dest->type->data.structure.src_field_count; i += 1) { TypeStructField *type_struct_field = dest->type->data.structure.fields[i]; - // comptime-known values are stored in the field init_val inside - // the struct type. - if (type_struct_field->is_comptime) + if (type_struct_field->is_comptime) { + // comptime-known values are stored in the field init_val inside + // the struct type. The data stored here is not supposed to be read + // at all; the code should look at the type system and notice the field + // is comptime and look at the type to learn the value. continue; + } copy_const_val(g, dest->data.x_struct.fields[i], src->data.x_struct.fields[i]); dest->data.x_struct.fields[i]->parent.id = ConstParentIdStruct; dest->data.x_struct.fields[i]->parent.data.p_struct.struct_val = dest; diff --git a/src/stage1/ir.cpp b/src/stage1/ir.cpp index 062750225d..06e469d3c8 100644 --- a/src/stage1/ir.cpp +++ b/src/stage1/ir.cpp @@ -25620,6 +25620,11 @@ static Error ir_resolve_lazy_recurse(IrAnalyze *ira, AstNode *source_node, ZigVa case ZigTypeIdStruct: for (size_t i = 0; i < val->type->data.structure.src_field_count; i += 1) { ZigValue *field = val->data.x_struct.fields[i]; + if (val->type->data.structure.fields[i]->is_comptime) { + // comptime struct fields do not need to be resolved because + // they are not part of the value. + continue; + } if ((err = ir_resolve_lazy_recurse(ira, source_node, field))) return err; } From 149ecdfe1b5149c46a58dffe670b36319983ad7f Mon Sep 17 00:00:00 2001 From: Martin Wickham Date: Mon, 5 Jul 2021 19:41:48 -0500 Subject: [PATCH 5/6] Remove debug checks, audit field accesses --- src/stage1/analyze.cpp | 27 ++++++++------- src/stage1/codegen.cpp | 12 +++++-- src/stage1/ir.cpp | 77 ++++++++++++++++++++++++++++-------------- 3 files changed, 76 insertions(+), 40 deletions(-) diff --git a/src/stage1/analyze.cpp b/src/stage1/analyze.cpp index d551dec221..f77e217450 100644 --- a/src/stage1/analyze.cpp +++ b/src/stage1/analyze.cpp @@ -5668,14 +5668,6 @@ static uint32_t hash_combine_const_val(uint32_t hash_val, ZigValue *const_val) { if (const_val->special == ConstValSpecialUndef) { return hash_val; } - // if (const_val->special == ConstValSpecialLazy || - // const_val->special == ConstValSpecialRuntime) { - // // NO_COMMIT verify this is correct - // return hash_combine(hash_val, &const_val); - // } - if (const_val->special != ConstValSpecialStatic) { - fprintf(stderr, "\nInvalid special: %d\n", const_val->special); - } assert(const_val->special == ConstValSpecialStatic); hash_val = hash_combine(hash_val, &const_val->type->id); switch (const_val->type->id) { @@ -5718,13 +5710,13 @@ static uint32_t hash_combine_const_val(uint32_t hash_val, ZigValue *const_val) { case ZigTypeIdStruct: { size_t field_count = const_val->type->data.structure.src_field_count; for (size_t i = 0; i < field_count; i += 1) { - ZigValue *field = const_val->data.x_struct.fields[i]; if (const_val->type->data.structure.fields[i]->is_comptime) { // The values of comptime struct fields are part of the // type, not the value, so they do not participate in equality // or hash of comptime values. continue; } + ZigValue *field = const_val->data.x_struct.fields[i]; hash_val = hash_combine_const_val(hash_val, field); } return hash_val; @@ -6179,7 +6171,8 @@ ZigValue *get_the_one_possible_value(CodeGen *g, ZigType *type_entry) { for (size_t i = 0; i < field_count; i += 1) { TypeStructField *field = struct_type->data.structure.fields[i]; if (field->is_comptime) { - copy_const_val(g, result->data.x_struct.fields[i], field->init_val); + // Comptime fields are part of the type, and do not need to + // be initialized. continue; } ZigType *field_type = resolve_struct_field_type(g, field); @@ -7958,6 +7951,13 @@ static void init_const_undefined(CodeGen *g, ZigValue *const_val) { size_t field_count = wanted_type->data.structure.src_field_count; const_val->data.x_struct.fields = alloc_const_vals_ptrs(g, field_count); for (size_t i = 0; i < field_count; i += 1) { + TypeStructField *field = wanted_type->data.structure.fields[i]; + if (field->is_comptime) { + // Comptime fields are part of the type, and do not need to + // be initialized. + continue; + } + ZigValue *field_val = const_val->data.x_struct.fields[i]; field_val->type = resolve_struct_field_type(g, wanted_type->data.structure.fields[i]); assert(field_val->type); @@ -10174,8 +10174,11 @@ static void dump_value_indent(ZigValue *val, int indent) { for (int j = 0; j < indent; j += 1) { fprintf(stderr, " "); } - fprintf(stderr, "%s: ", buf_ptr(val->type->data.structure.fields[i]->name)); - if (val->data.x_struct.fields == nullptr) { + TypeStructField *field = val->type->data.structure.fields[i]; + fprintf(stderr, "%s: ", buf_ptr(field->name)); + if (field->is_comptime) { + fprintf(stderr, ""); + } else if (val->data.x_struct.fields == nullptr) { fprintf(stderr, "\n"); } else { dump_value_indent(val->data.x_struct.fields[i], 1); diff --git a/src/stage1/codegen.cpp b/src/stage1/codegen.cpp index 171b02dbd9..213d8d647a 100644 --- a/src/stage1/codegen.cpp +++ b/src/stage1/codegen.cpp @@ -3778,6 +3778,12 @@ static bool value_is_all_undef(CodeGen *g, ZigValue *const_val) { case ConstValSpecialStatic: if (const_val->type->id == ZigTypeIdStruct) { for (size_t i = 0; i < const_val->type->data.structure.src_field_count; i += 1) { + TypeStructField *field = const_val->type->data.structure.fields[i]; + if (field->is_comptime) { + // Comptime fields are part of the type, may be uninitialized, + // and should not be inspected. + continue; + } if (!value_is_all_undef(g, const_val->data.x_struct.fields[i])) return false; } @@ -7285,7 +7291,7 @@ static LLVMValueRef pack_const_int(CodeGen *g, LLVMTypeRef big_int_type_ref, Zig size_t used_bits = 0; for (size_t i = 0; i < type_entry->data.structure.src_field_count; i += 1) { TypeStructField *field = type_entry->data.structure.fields[i]; - if (field->gen_index == SIZE_MAX) { + if (field->gen_index == SIZE_MAX || field->is_comptime) { continue; } LLVMValueRef child_val = pack_const_int(g, big_int_type_ref, const_val->data.x_struct.fields[i]); @@ -7573,7 +7579,7 @@ static LLVMValueRef gen_const_val(CodeGen *g, ZigValue *const_val, const char *n size_t src_field_index = 0; while (src_field_index < src_field_count) { TypeStructField *type_struct_field = type_entry->data.structure.fields[src_field_index]; - if (type_struct_field->gen_index == SIZE_MAX) { + if (type_struct_field->gen_index == SIZE_MAX || type_struct_field->is_comptime) { src_field_index += 1; continue; } @@ -7642,7 +7648,7 @@ static LLVMValueRef gen_const_val(CodeGen *g, ZigValue *const_val, const char *n } else { for (uint32_t i = 0; i < src_field_count; i += 1) { TypeStructField *type_struct_field = type_entry->data.structure.fields[i]; - if (type_struct_field->gen_index == SIZE_MAX) { + if (type_struct_field->gen_index == SIZE_MAX || type_struct_field->is_comptime) { continue; } ZigValue *field_val = const_val->data.x_struct.fields[i]; diff --git a/src/stage1/ir.cpp b/src/stage1/ir.cpp index 06e469d3c8..ab8aac9a91 100644 --- a/src/stage1/ir.cpp +++ b/src/stage1/ir.cpp @@ -272,8 +272,8 @@ 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 Error ir_resolve_lazy_recurse(IrAnalyze *ira, AstNode *source_node, ZigValue *val); -static Error ir_resolve_lazy_recurse_array(IrAnalyze *ira, AstNode *source_node, ZigValue *val, size_t len); +static Error ir_resolve_lazy_recurse(AstNode *source_node, ZigValue *val); +static Error ir_resolve_lazy_recurse_array(AstNode *source_node, ZigValue *val, size_t len); static void ir_assert_impl(bool ok, IrInstGen *source_instruction, char const *file, unsigned int line) { @@ -558,7 +558,10 @@ static ZigValue *const_ptr_pointee_unchecked_no_isf(CodeGen *g, ZigValue *const_ case ConstPtrSpecialBaseStruct: { ZigValue *struct_val = const_val->data.x_ptr.data.base_struct.struct_val; expand_undef_struct(g, struct_val); - result = struct_val->data.x_struct.fields[const_val->data.x_ptr.data.base_struct.field_index]; + size_t field_index = const_val->data.x_ptr.data.base_struct.field_index; + assert(struct_val->type->id == ZigTypeIdStruct); + assert(!struct_val->type->data.structure.fields[field_index]->is_comptime); + result = struct_val->data.x_struct.fields[field_index]; break; } case ConstPtrSpecialBaseErrorUnionCode: @@ -7022,6 +7025,17 @@ static IrInstGen *ir_analyze_struct_literal_to_struct(IrAnalyze *ira, Scope *sco buf_sprintf("field '%s' declared here", buf_ptr(src_field->name))); return ira->codegen->invalid_inst_gen; } + if (dst_field->is_comptime) { + ErrorMsg *msg = ir_add_error_node(ira, source_node, buf_sprintf("field '%s' in struct '%s' is comptime, it cannot be assigned", + buf_ptr(src_field->name), buf_ptr(&wanted_type->name))); + if (wanted_type->data.structure.decl_node) { + add_error_note(ira->codegen, msg, wanted_type->data.structure.decl_node, + buf_sprintf("struct '%s' declared here", buf_ptr(&wanted_type->name))); + } + add_error_note(ira->codegen, msg, src_field->decl_node, + buf_sprintf("field '%s' declared here", buf_ptr(src_field->name))); + return ira->codegen->invalid_inst_gen; + } src_assert(src_field->decl_node != nullptr, source_node); AstNode *existing_assign_node = field_assign_nodes[dst_field->src_index]; @@ -7066,6 +7080,7 @@ static IrInstGen *ir_analyze_struct_literal_to_struct(IrAnalyze *ira, Scope *sco // look for a default field value TypeStructField *field = wanted_type->data.structure.fields[i]; + assert(!field->is_comptime); // field_assign_nodes[i] should be null for comptime fields memoize_field_init_val(ira->codegen, wanted_type, field); if (field->init_val == nullptr) { ir_add_error_node(ira, source_node, @@ -7101,6 +7116,9 @@ static IrInstGen *ir_analyze_struct_literal_to_struct(IrAnalyze *ira, Scope *sco for (size_t i = 0; i < actual_field_count; i += 1) { TypeStructField *field = wanted_type->data.structure.fields[i]; + if (field->is_comptime) + continue; + IrInstGen *field_ptr = ir_analyze_struct_field_ptr(ira, scope, source_node, field, result_loc_inst, wanted_type, true); if (type_is_invalid(field_ptr->value->type)) return ira->codegen->invalid_inst_gen; @@ -12762,7 +12780,7 @@ static IrInstGen *ir_analyze_fn_call(IrAnalyze *ira, Scope *scope, AstNode *sour while (scope) { if (scope->id == ScopeIdVarDecl) { ScopeVarDecl *var_scope = (ScopeVarDecl *)scope; - if ((err = ir_resolve_lazy_recurse(ira, + if ((err = ir_resolve_lazy_recurse( var_scope->var->decl_node, var_scope->var->const_value))) { @@ -12968,7 +12986,7 @@ static IrInstGen *ir_analyze_fn_call(IrAnalyze *ira, Scope *scope, AstNode *sour for (size_t i = 0; i < generic_id->param_count; i += 1) { ZigValue *generic_param = &generic_id->params[i]; if (generic_param->special != ConstValSpecialRuntime) { - if ((err = ir_resolve_lazy_recurse(ira, source_node, generic_param))) { + if ((err = ir_resolve_lazy_recurse(source_node, generic_param))) { return ira->codegen->invalid_inst_gen; } } @@ -14912,6 +14930,8 @@ static IrInstGen *ir_analyze_struct_field_ptr(IrAnalyze *ira, Scope *scope, AstN struct_val->data.x_struct.fields = alloc_const_vals_ptrs(ira->codegen, struct_type->data.structure.src_field_count); struct_val->special = ConstValSpecialStatic; for (size_t i = 0; i < struct_type->data.structure.src_field_count; i += 1) { + if (struct_type->data.structure.fields[i]->is_comptime) + continue; ZigValue *field_val = struct_val->data.x_struct.fields[i]; field_val->special = ConstValSpecialUndef; field_val->type = resolve_struct_field_type(ira->codegen, @@ -18286,7 +18306,9 @@ static ZigValue *get_const_field(IrAnalyze *ira, AstNode *source_node, ZigValue { Error err; ensure_field_index(struct_value->type, name, field_index); - ZigValue *val = struct_value->data.x_struct.fields[field_index]; + TypeStructField *field = struct_value->type->data.structure.fields[field_index]; + ZigValue *val = field->is_comptime ? field->init_val : + struct_value->data.x_struct.fields[field_index]; if ((err = ir_resolve_const_val(ira->codegen, ira->new_irb.exec, source_node, val, UndefBad))) return nullptr; return val; @@ -22461,7 +22483,7 @@ static void buf_write_value_bytes(CodeGen *codegen, uint8_t *buf, ZigValue *val) size_t src_field_count = val->type->data.structure.src_field_count; for (size_t field_i = 0; field_i < src_field_count; field_i += 1) { TypeStructField *struct_field = val->type->data.structure.fields[field_i]; - if (struct_field->gen_index == SIZE_MAX) + if (struct_field->gen_index == SIZE_MAX || struct_field->is_comptime) continue; ZigValue *field_val = val->data.x_struct.fields[field_i]; size_t offset = struct_field->offset; @@ -22490,6 +22512,10 @@ static void buf_write_value_bytes(CodeGen *codegen, uint8_t *buf, ZigValue *val) size_t used_bits = 0; while (src_i < src_field_count) { TypeStructField *field = val->type->data.structure.fields[src_i]; + if (field->is_comptime) { + src_i += 1; + continue; + } assert(field->gen_index != SIZE_MAX); if (field->gen_index != gen_i) break; @@ -22638,9 +22664,11 @@ static Error buf_read_value_bytes(IrAnalyze *ira, CodeGen *codegen, AstNode *sou size_t src_field_count = val->type->data.structure.src_field_count; val->data.x_struct.fields = alloc_const_vals_ptrs(codegen, src_field_count); for (size_t field_i = 0; field_i < src_field_count; field_i += 1) { + TypeStructField *struct_field = val->type->data.structure.fields[field_i]; + if (struct_field->is_comptime) + continue; ZigValue *field_val = val->data.x_struct.fields[field_i]; field_val->special = ConstValSpecialStatic; - TypeStructField *struct_field = val->type->data.structure.fields[field_i]; field_val->type = struct_field->type_entry; if (struct_field->gen_index == SIZE_MAX) continue; @@ -22673,6 +22701,10 @@ static Error buf_read_value_bytes(IrAnalyze *ira, CodeGen *codegen, AstNode *sou uint64_t bit_offset = 0; while (src_i < src_field_count) { TypeStructField *field = val->type->data.structure.fields[src_i]; + if (field->is_comptime) { + src_i += 1; + continue; + } src_assert(field->gen_index != SIZE_MAX, source_node); if (field->gen_index != gen_i) break; @@ -25554,7 +25586,7 @@ static Error ir_resolve_lazy_raw(AstNode *source_node, ZigValue *val) { zig_unreachable(); } -static Error ir_resolve_lazy_recurse_array(IrAnalyze *ira, AstNode *source_node, ZigValue *val, size_t len) { +static Error ir_resolve_lazy_recurse_array(AstNode *source_node, ZigValue *val, size_t len) { Error err; switch (val->data.x_array.special) { case ConstArraySpecialUndef: @@ -25566,24 +25598,19 @@ static Error ir_resolve_lazy_recurse_array(IrAnalyze *ira, AstNode *source_node, ZigValue *elems = val->data.x_array.data.s_none.elements; for (size_t i = 0; i < len; i += 1) { - if ((err = ir_resolve_lazy_recurse(ira, source_node, &elems[i]))) + if ((err = ir_resolve_lazy_recurse(source_node, &elems[i]))) return err; } return ErrorNone; } -static Error ir_resolve_lazy_recurse(IrAnalyze *ira, AstNode *source_node, ZigValue *val) { +static Error ir_resolve_lazy_recurse(AstNode *source_node, ZigValue *val) { Error err; if ((err = ir_resolve_lazy_raw(source_node, val))) return err; - if (val->special == ConstValSpecialRuntime) { - // This shouldn't be possible, it indicates an ICE. - // NO_COMMIT - ir_add_error_node(ira, source_node, - buf_sprintf("This is a bug in the Zig compiler. Runtime value found in comptime known value.")); - return ErrorSemanticAnalyzeFail; - } + assert(val->special != ConstValSpecialRuntime); + assert(val->special != ConstValSpecialLazy); if (val->special != ConstValSpecialStatic) return ErrorNone; switch (val->type->id) { @@ -25611,12 +25638,12 @@ static Error ir_resolve_lazy_recurse(IrAnalyze *ira, AstNode *source_node, ZigVa zig_panic("TODO: ir_resolve_lazy_recurse ZigTypeIdFnFrame"); case ZigTypeIdUnion: { ConstUnionValue *union_val = &val->data.x_union; - return ir_resolve_lazy_recurse(ira, source_node, union_val->payload); + return ir_resolve_lazy_recurse(source_node, union_val->payload); } case ZigTypeIdVector: - return ir_resolve_lazy_recurse_array(ira, source_node, val, val->type->data.vector.len); + return ir_resolve_lazy_recurse_array(source_node, val, val->type->data.vector.len); case ZigTypeIdArray: - return ir_resolve_lazy_recurse_array(ira, source_node, val, val->type->data.array.len); + return ir_resolve_lazy_recurse_array(source_node, val, val->type->data.array.len); case ZigTypeIdStruct: for (size_t i = 0; i < val->type->data.structure.src_field_count; i += 1) { ZigValue *field = val->data.x_struct.fields[i]; @@ -25625,7 +25652,7 @@ static Error ir_resolve_lazy_recurse(IrAnalyze *ira, AstNode *source_node, ZigVa // they are not part of the value. continue; } - if ((err = ir_resolve_lazy_recurse(ira, source_node, field))) + if ((err = ir_resolve_lazy_recurse(source_node, field))) return err; } return ErrorNone; @@ -25635,13 +25662,13 @@ static Error ir_resolve_lazy_recurse(IrAnalyze *ira, AstNode *source_node, ZigVa if (val->data.x_optional == nullptr) return ErrorNone; - return ir_resolve_lazy_recurse(ira, source_node, val->data.x_optional); + return ir_resolve_lazy_recurse(source_node, val->data.x_optional); case ZigTypeIdErrorUnion: { bool is_err = val->data.x_err_union.error_set->data.x_err_set != nullptr; if (is_err) { - return ir_resolve_lazy_recurse(ira, source_node, val->data.x_err_union.error_set); + return ir_resolve_lazy_recurse(source_node, val->data.x_err_union.error_set); } else { - return ir_resolve_lazy_recurse(ira, source_node, val->data.x_err_union.payload); + return ir_resolve_lazy_recurse(source_node, val->data.x_err_union.payload); } } } From f02ee7a9f5a72f24a645f36db7ae7828f29d3393 Mon Sep 17 00:00:00 2001 From: Martin Wickham Date: Tue, 6 Jul 2021 00:57:46 -0500 Subject: [PATCH 6/6] Avoid some large copies for another second of time saved --- src/stage1/all_types.hpp | 8 +- src/stage1/analyze.cpp | 188 ++++++++++++++++++++------------------- src/stage1/bigint.cpp | 10 +-- src/stage1/bigint.hpp | 4 +- src/stage1/hash_map.hpp | 50 ++++++++--- 5 files changed, 145 insertions(+), 115 deletions(-) diff --git a/src/stage1/all_types.hpp b/src/stage1/all_types.hpp index 6385f18ec5..9161a46569 100644 --- a/src/stage1/all_types.hpp +++ b/src/stage1/all_types.hpp @@ -1879,8 +1879,8 @@ struct TypeId { } data; }; -uint32_t type_id_hash(TypeId); -bool type_id_eql(TypeId a, TypeId b); +uint32_t type_id_hash(TypeId const *); +bool type_id_eql(TypeId const *a, TypeId const *b); enum ZigLLVMFnId { ZigLLVMFnIdCtz, @@ -1935,8 +1935,8 @@ struct ZigLLVMFnKey { } data; }; -uint32_t zig_llvm_fn_key_hash(ZigLLVMFnKey); -bool zig_llvm_fn_key_eql(ZigLLVMFnKey a, ZigLLVMFnKey b); +uint32_t zig_llvm_fn_key_hash(ZigLLVMFnKey const *); +bool zig_llvm_fn_key_eql(ZigLLVMFnKey const *a, ZigLLVMFnKey const *b); struct TimeEvent { double time; diff --git a/src/stage1/analyze.cpp b/src/stage1/analyze.cpp index f77e217450..06bd1e1ed6 100644 --- a/src/stage1/analyze.cpp +++ b/src/stage1/analyze.cpp @@ -7742,9 +7742,9 @@ ZigType *make_int_type(CodeGen *g, bool is_signed, uint32_t size_in_bits) { return entry; } -uint32_t type_id_hash(TypeId x) { - uint32_t hash = hash_combine(HASH_INIT, &x.id); - switch (x.id) { +uint32_t type_id_hash(TypeId const *x) { + uint32_t hash = hash_combine(HASH_INIT, &x->id); + switch (x->id) { case ZigTypeIdInvalid: case ZigTypeIdOpaque: case ZigTypeIdMetaType: @@ -7768,46 +7768,50 @@ uint32_t type_id_hash(TypeId x) { case ZigTypeIdAnyFrame: zig_unreachable(); case ZigTypeIdErrorUnion: - hash = hash_combine(hash, &x.data.error_union.err_set_type); - hash = hash_combine(hash, &x.data.error_union.payload_type); + hash = hash_combine(hash, &x->data.error_union.err_set_type); + hash = hash_combine(hash, &x->data.error_union.payload_type); return hash; case ZigTypeIdPointer: - hash = hash_combine(hash, &x.data.pointer.child_type); - hash = hash_combine(hash, &x.data.pointer.ptr_len); - hash = hash_combine(hash, &x.data.pointer.is_const); - hash = hash_combine(hash, &x.data.pointer.is_volatile); - hash = hash_combine(hash, &x.data.pointer.allow_zero); - hash = hash_combine(hash, &x.data.pointer.alignment); - hash = hash_combine(hash, &x.data.pointer.bit_offset_in_host); - hash = hash_combine(hash, &x.data.pointer.vector_index); - hash = hash_combine(hash, &x.data.pointer.host_int_bytes); - if (x.data.pointer.sentinel != nullptr) { - hash = hash_combine_const_val(hash, x.data.pointer.sentinel); + hash = hash_combine(hash, &x->data.pointer.child_type); + hash = hash_combine(hash, &x->data.pointer.ptr_len); + hash = hash_combine(hash, &x->data.pointer.is_const); + hash = hash_combine(hash, &x->data.pointer.is_volatile); + hash = hash_combine(hash, &x->data.pointer.allow_zero); + hash = hash_combine(hash, &x->data.pointer.alignment); + hash = hash_combine(hash, &x->data.pointer.bit_offset_in_host); + hash = hash_combine(hash, &x->data.pointer.vector_index); + hash = hash_combine(hash, &x->data.pointer.host_int_bytes); + if (x->data.pointer.sentinel != nullptr) { + hash = hash_combine_const_val(hash, x->data.pointer.sentinel); + } + if (x->data.pointer.inferred_struct_field) { + hash = hash_combine(hash, &x->data.pointer.inferred_struct_field->inferred_struct_type); + hash = hash_combine_buf(hash, x->data.pointer.inferred_struct_field->field_name); } return hash; case ZigTypeIdArray: - hash = hash_combine(hash, &x.data.array.child_type); - hash = hash_combine(hash, &x.data.array.size); - if (x.data.array.sentinel != nullptr) { - hash = hash_combine_const_val(hash, x.data.array.sentinel); + hash = hash_combine(hash, &x->data.array.child_type); + hash = hash_combine(hash, &x->data.array.size); + if (x->data.array.sentinel != nullptr) { + hash = hash_combine_const_val(hash, x->data.array.sentinel); } return hash; case ZigTypeIdInt: - hash = hash_combine(hash, &x.data.integer.is_signed); - hash = hash_combine(hash, &x.data.integer.bit_count); + hash = hash_combine(hash, &x->data.integer.is_signed); + hash = hash_combine(hash, &x->data.integer.bit_count); return hash; case ZigTypeIdVector: - hash = hash_combine(hash, &x.data.vector.elem_type); - hash = hash_combine(hash, &x.data.vector.len); + hash = hash_combine(hash, &x->data.vector.elem_type); + hash = hash_combine(hash, &x->data.vector.len); return hash; } zig_unreachable(); } -bool type_id_eql(TypeId a, TypeId b) { - if (a.id != b.id) +bool type_id_eql(TypeId const *a, TypeId const *b) { + if (a->id != b->id) return false; - switch (a.id) { + switch (a->id) { case ZigTypeIdInvalid: case ZigTypeIdMetaType: case ZigTypeIdVoid: @@ -7831,107 +7835,107 @@ bool type_id_eql(TypeId a, TypeId b) { case ZigTypeIdAnyFrame: zig_unreachable(); case ZigTypeIdErrorUnion: - return a.data.error_union.err_set_type == b.data.error_union.err_set_type && - a.data.error_union.payload_type == b.data.error_union.payload_type; + return a->data.error_union.err_set_type == b->data.error_union.err_set_type && + a->data.error_union.payload_type == b->data.error_union.payload_type; case ZigTypeIdPointer: - return a.data.pointer.child_type == b.data.pointer.child_type && - 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.vector_index == b.data.pointer.vector_index && - a.data.pointer.host_int_bytes == b.data.pointer.host_int_bytes && + return a->data.pointer.child_type == b->data.pointer.child_type && + 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.vector_index == b->data.pointer.vector_index && + a->data.pointer.host_int_bytes == b->data.pointer.host_int_bytes && ( - a.data.pointer.sentinel == b.data.pointer.sentinel || - (a.data.pointer.sentinel != nullptr && b.data.pointer.sentinel != nullptr && - const_values_equal(a.data.pointer.codegen, a.data.pointer.sentinel, b.data.pointer.sentinel)) + a->data.pointer.sentinel == b->data.pointer.sentinel || + (a->data.pointer.sentinel != nullptr && b->data.pointer.sentinel != nullptr && + const_values_equal(a->data.pointer.codegen, a->data.pointer.sentinel, b->data.pointer.sentinel)) ) && ( - a.data.pointer.inferred_struct_field == b.data.pointer.inferred_struct_field || - (a.data.pointer.inferred_struct_field != nullptr && - b.data.pointer.inferred_struct_field != nullptr && - a.data.pointer.inferred_struct_field->inferred_struct_type == - b.data.pointer.inferred_struct_field->inferred_struct_type && - buf_eql_buf(a.data.pointer.inferred_struct_field->field_name, - b.data.pointer.inferred_struct_field->field_name)) + a->data.pointer.inferred_struct_field == b->data.pointer.inferred_struct_field || + (a->data.pointer.inferred_struct_field != nullptr && + b->data.pointer.inferred_struct_field != nullptr && + a->data.pointer.inferred_struct_field->inferred_struct_type == + b->data.pointer.inferred_struct_field->inferred_struct_type && + buf_eql_buf(a->data.pointer.inferred_struct_field->field_name, + b->data.pointer.inferred_struct_field->field_name)) ); case ZigTypeIdArray: - return a.data.array.child_type == b.data.array.child_type && - a.data.array.size == b.data.array.size && + return a->data.array.child_type == b->data.array.child_type && + a->data.array.size == b->data.array.size && ( - a.data.array.sentinel == b.data.array.sentinel || - (a.data.array.sentinel != nullptr && b.data.array.sentinel != nullptr && - const_values_equal(a.data.array.codegen, a.data.array.sentinel, b.data.array.sentinel)) + a->data.array.sentinel == b->data.array.sentinel || + (a->data.array.sentinel != nullptr && b->data.array.sentinel != nullptr && + const_values_equal(a->data.array.codegen, a->data.array.sentinel, b->data.array.sentinel)) ); case ZigTypeIdInt: - return a.data.integer.is_signed == b.data.integer.is_signed && - a.data.integer.bit_count == b.data.integer.bit_count; + 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; + return a->data.vector.elem_type == b->data.vector.elem_type && + a->data.vector.len == b->data.vector.len; } zig_unreachable(); } -uint32_t zig_llvm_fn_key_hash(ZigLLVMFnKey x) { - switch (x.id) { +uint32_t zig_llvm_fn_key_hash(ZigLLVMFnKey const *x) { + switch (x->id) { case ZigLLVMFnIdCtz: - return (uint32_t)(x.data.ctz.bit_count) * (uint32_t)810453934; + return (uint32_t)(x->data.ctz.bit_count) * (uint32_t)810453934; case ZigLLVMFnIdClz: - return (uint32_t)(x.data.clz.bit_count) * (uint32_t)2428952817; + return (uint32_t)(x->data.clz.bit_count) * (uint32_t)2428952817; case ZigLLVMFnIdPopCount: - return (uint32_t)(x.data.clz.bit_count) * (uint32_t)101195049; + return (uint32_t)(x->data.clz.bit_count) * (uint32_t)101195049; case ZigLLVMFnIdFloatOp: - return (uint32_t)(x.data.floating.bit_count) * ((uint32_t)x.id + 1025) + - (uint32_t)(x.data.floating.vector_len) * (((uint32_t)x.id << 5) + 1025) + - (uint32_t)(x.data.floating.op) * (uint32_t)43789879; + return (uint32_t)(x->data.floating.bit_count) * ((uint32_t)x->id + 1025) + + (uint32_t)(x->data.floating.vector_len) * (((uint32_t)x->id << 5) + 1025) + + (uint32_t)(x->data.floating.op) * (uint32_t)43789879; case ZigLLVMFnIdFMA: - return (uint32_t)(x.data.floating.bit_count) * ((uint32_t)x.id + 1025) + - (uint32_t)(x.data.floating.vector_len) * (((uint32_t)x.id << 5) + 1025); + return (uint32_t)(x->data.floating.bit_count) * ((uint32_t)x->id + 1025) + + (uint32_t)(x->data.floating.vector_len) * (((uint32_t)x->id << 5) + 1025); case ZigLLVMFnIdBswap: - return (uint32_t)(x.data.bswap.bit_count) * ((uint32_t)3661994335) + - (uint32_t)(x.data.bswap.vector_len) * (((uint32_t)x.id << 5) + 1025); + return (uint32_t)(x->data.bswap.bit_count) * ((uint32_t)3661994335) + + (uint32_t)(x->data.bswap.vector_len) * (((uint32_t)x->id << 5) + 1025); case ZigLLVMFnIdBitReverse: - return (uint32_t)(x.data.bit_reverse.bit_count) * (uint32_t)2621398431; + 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) + - x.data.overflow_arithmetic.vector_len * 1435156945; + 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) + + x->data.overflow_arithmetic.vector_len * 1435156945; } zig_unreachable(); } -bool zig_llvm_fn_key_eql(ZigLLVMFnKey a, ZigLLVMFnKey b) { - if (a.id != b.id) +bool zig_llvm_fn_key_eql(ZigLLVMFnKey const *a, ZigLLVMFnKey const *b) { + if (a->id != b->id) return false; - switch (a.id) { + switch (a->id) { case ZigLLVMFnIdCtz: - return a.data.ctz.bit_count == b.data.ctz.bit_count; + return a->data.ctz.bit_count == b->data.ctz.bit_count; case ZigLLVMFnIdClz: - return a.data.clz.bit_count == b.data.clz.bit_count; + 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; + 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 && - a.data.bswap.vector_len == b.data.bswap.vector_len; + return a->data.bswap.bit_count == b->data.bswap.bit_count && + a->data.bswap.vector_len == b->data.bswap.vector_len; case ZigLLVMFnIdBitReverse: - return a.data.bit_reverse.bit_count == b.data.bit_reverse.bit_count; + return a->data.bit_reverse.bit_count == b->data.bit_reverse.bit_count; case ZigLLVMFnIdFloatOp: - return a.data.floating.bit_count == b.data.floating.bit_count && - a.data.floating.vector_len == b.data.floating.vector_len && - a.data.floating.op == b.data.floating.op; + return a->data.floating.bit_count == b->data.floating.bit_count && + a->data.floating.vector_len == b->data.floating.vector_len && + a->data.floating.op == b->data.floating.op; case ZigLLVMFnIdFMA: - return a.data.floating.bit_count == b.data.floating.bit_count && - a.data.floating.vector_len == b.data.floating.vector_len; + return a->data.floating.bit_count == b->data.floating.bit_count && + a->data.floating.vector_len == b->data.floating.vector_len; 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.vector_len == b.data.overflow_arithmetic.vector_len); + 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.vector_len == b->data.overflow_arithmetic.vector_len); } zig_unreachable(); } diff --git a/src/stage1/bigint.cpp b/src/stage1/bigint.cpp index 97181b6ad2..27ca148b7b 100644 --- a/src/stage1/bigint.cpp +++ b/src/stage1/bigint.cpp @@ -1730,16 +1730,16 @@ Cmp bigint_cmp_zero(const BigInt *op) { return op->is_negative ? CmpLT : CmpGT; } -uint32_t bigint_hash(BigInt x) { - if (x.digit_count == 0) { +uint32_t bigint_hash(BigInt const *x) { + if (x->digit_count == 0) { return 0; } else { - return bigint_ptr(&x)[0]; + return bigint_ptr(x)[0]; } } -bool bigint_eql(BigInt a, BigInt b) { - return bigint_cmp(&a, &b) == CmpEQ; +bool bigint_eql(BigInt const *a, BigInt const *b) { + return bigint_cmp(a, b) == CmpEQ; } void bigint_incr(BigInt *x) { diff --git a/src/stage1/bigint.hpp b/src/stage1/bigint.hpp index 521de25b1c..67f3ca1368 100644 --- a/src/stage1/bigint.hpp +++ b/src/stage1/bigint.hpp @@ -100,7 +100,7 @@ void bigint_decr(BigInt *value); bool mul_u64_overflow(uint64_t op1, uint64_t op2, uint64_t *result); -uint32_t bigint_hash(BigInt x); -bool bigint_eql(BigInt a, BigInt b); +uint32_t bigint_hash(BigInt const *x); +bool bigint_eql(BigInt const *a, BigInt const *b); #endif diff --git a/src/stage1/hash_map.hpp b/src/stage1/hash_map.hpp index 8681e5b761..0dad87289e 100644 --- a/src/stage1/hash_map.hpp +++ b/src/stage1/hash_map.hpp @@ -12,7 +12,33 @@ #include -template +template +struct MakePointer { + typedef K const *Type; + static Type convert(K const &val) { + return &val; + } +}; + +template +struct MakePointer { + typedef K *Type; + static Type convert(K * const &val) { + return val; + } +}; + +template +struct MakePointer { + typedef K const *Type; + static Type convert(K const * const &val) { + return val; + } +}; + +template::Type key), + bool (*EqualFn)(typename MakePointer::Type a, typename MakePointer::Type b)> class HashMap { public: void init(int capacity) { @@ -51,7 +77,7 @@ public: if (_index_bytes == nullptr) { if (_entries.length < 16) { - _entries.append({HashFunction(key), 0, key, value}); + _entries.append({HashFunction(MakePointer::convert(key)), 0, key, value}); return; } else { _indexes_len = 32; @@ -131,9 +157,9 @@ public: bool maybe_remove(const K &key) { _modification_count += 1; if (_index_bytes == nullptr) { - uint32_t hash = HashFunction(key); + uint32_t hash = HashFunction(MakePointer::convert(key)); for (size_t i = 0; i < _entries.length; i += 1) { - if (_entries.items[i].hash == hash && EqualFn(_entries.items[i].key, key)) { + if (_entries.items[i].hash == hash && EqualFn(MakePointer::convert(_entries.items[i].key), MakePointer::convert(key))) { _entries.swap_remove(i); return true; } @@ -223,7 +249,7 @@ private: template void internal_put(const K &key, const V &value, I *indexes) { - uint32_t hash = HashFunction(key); + uint32_t hash = HashFunction(MakePointer::convert(key)); uint32_t distance_from_start_index = 0; size_t start_index = hash_to_index(hash); for (size_t roll_over = 0; roll_over < _indexes_len; @@ -241,7 +267,7 @@ private: // This pointer survives the following append because we call // _entries.ensure_capacity before internal_put. Entry *entry = &_entries.items[index_data - 1]; - if (entry->hash == hash && EqualFn(entry->key, key)) { + if (entry->hash == hash && EqualFn(MakePointer::convert(entry->key), MakePointer::convert(key))) { *entry = {hash, distance_from_start_index, key, value}; if (distance_from_start_index > _max_distance_from_start_index) _max_distance_from_start_index = distance_from_start_index; @@ -322,9 +348,9 @@ private: Entry *internal_get(const K &key) const { if (_index_bytes == nullptr) { - uint32_t hash = HashFunction(key); + uint32_t hash = HashFunction(MakePointer::convert(key)); for (size_t i = 0; i < _entries.length; i += 1) { - if (_entries.items[i].hash == hash && EqualFn(_entries.items[i].key, key)) { + if (_entries.items[i].hash == hash && EqualFn(MakePointer::convert(_entries.items[i].key), MakePointer::convert(key))) { return &_entries.items[i]; } } @@ -340,7 +366,7 @@ private: template Entry *internal_get2(const K &key, I *indexes) const { - uint32_t hash = HashFunction(key); + uint32_t hash = HashFunction(MakePointer::convert(key)); size_t start_index = hash_to_index(hash); for (size_t roll_over = 0; roll_over <= _max_distance_from_start_index; roll_over += 1) { size_t index_index = (start_index + roll_over) % _indexes_len; @@ -349,7 +375,7 @@ private: return nullptr; Entry *entry = &_entries.items[index_data - 1]; - if (entry->hash == hash && EqualFn(entry->key, key)) + if (entry->hash == hash && EqualFn(MakePointer::convert(entry->key), MakePointer::convert(key))) return entry; } return nullptr; @@ -361,7 +387,7 @@ private: template bool internal_remove(const K &key, I *indexes) { - uint32_t hash = HashFunction(key); + uint32_t hash = HashFunction(MakePointer::convert(key)); size_t start_index = hash_to_index(hash); for (size_t roll_over = 0; roll_over <= _max_distance_from_start_index; roll_over += 1) { size_t index_index = (start_index + roll_over) % _indexes_len; @@ -371,7 +397,7 @@ private: size_t index = index_data - 1; Entry *entry = &_entries.items[index]; - if (entry->hash != hash || !EqualFn(entry->key, key)) + if (entry->hash != hash || !EqualFn(MakePointer::convert(entry->key), MakePointer::convert(key))) continue; size_t prev_index = index_index;