From e2e0b6272b98ef2ec810fbabcdc91a21e54a71a3 Mon Sep 17 00:00:00 2001 From: Vexu Date: Fri, 30 Oct 2020 13:24:47 +0200 Subject: [PATCH] stage2: return same hash for different representations of same value --- src/value.zig | 52 +++++++++++++++++++++++++++++++++++------------- src/zir_sema.zig | 6 ++++++ 2 files changed, 44 insertions(+), 14 deletions(-) diff --git a/src/value.zig b/src/value.zig index f6a7b24d48..8cbffecab6 100644 --- a/src/value.zig +++ b/src/value.zig @@ -565,7 +565,7 @@ pub const Value = extern union { .int_u64 => return BigIntMutable.init(&space.limbs, self.cast(Payload.Int_u64).?.int).toConst(), .int_i64 => return BigIntMutable.init(&space.limbs, self.cast(Payload.Int_i64).?.int).toConst(), .int_big_positive => return self.cast(Payload.IntBigPositive).?.asBigInt(), - .int_big_negative => return self.cast(Payload.IntBigPositive).?.asBigInt(), + .int_big_negative => return self.cast(Payload.IntBigNegative).?.asBigInt(), } } @@ -1255,7 +1255,6 @@ pub const Value = extern union { pub fn hash(self: Value) u64 { var hasher = std.hash.Wyhash.init(0); - std.hash.autoHash(&hasher, self.tag()); switch (self.tag()) { .u8_type, @@ -1321,18 +1320,19 @@ pub const Value = extern union { } }, - .undef, - .zero, - .one, - .void_value, - .unreachable_value, .empty_struct_value, .empty_array, - .null_value, - .bool_true, - .bool_false, => {}, + .undef, + .null_value, + .void_value, + .unreachable_value, + => std.hash.autoHash(&hasher, self.tag()), + + .zero, .bool_false => std.hash.autoHash(&hasher, @as(u64, 0)), + .one, .bool_true => std.hash.autoHash(&hasher, @as(u64, 1)), + .float_16, .float_32, .float_64, .float_128 => {}, .enum_literal, .bytes => { const payload = @fieldParentPtr(Payload.Bytes, "base", self.ptr_otherwise); @@ -1357,9 +1357,18 @@ pub const Value = extern union { .int_big_positive, .int_big_negative => { var space: BigIntSpace = undefined; const big = self.toBigInt(&space); - std.hash.autoHash(&hasher, big.positive); - for (big.limbs) |limb| { - std.hash.autoHash(&hasher, limb); + if (big.limbs.len == 1) { + // handle like {u,i}64 to ensure same hash as with Int{i,u}64 + if (big.positive) { + std.hash.autoHash(&hasher, @as(u64, big.limbs[0])); + } else { + std.hash.autoHash(&hasher, @as(u64, @bitCast(usize, -@bitCast(isize, big.limbs[0])))); + } + } else { + std.hash.autoHash(&hasher, big.positive); + for (big.limbs) |limb| { + std.hash.autoHash(&hasher, limb); + } } }, .elem_ptr => { @@ -1741,7 +1750,7 @@ pub const Value = extern union { .@"error", .empty_struct_value, .null_value, - => false, + => false, .undef => unreachable, .unreachable_value => unreachable, @@ -1882,3 +1891,18 @@ pub const Value = extern union { limbs: [(@sizeOf(u64) / @sizeOf(std.math.big.Limb)) + 1]std.math.big.Limb, }; }; + +test "hash same value different representation" { + const zero_1 = Value.initTag(.zero); + var payload_1 = Value.Payload.Int_u64{ .int = 0 }; + const zero_2 = Value.initPayload(&payload_1.base); + std.testing.expectEqual(zero_1.hash(), zero_2.hash()); + + var payload_2 = Value.Payload.Int_i64{ .int = 0 }; + const zero_3 = Value.initPayload(&payload_2.base); + std.testing.expectEqual(zero_2.hash(), zero_3.hash()); + + var payload_3 = Value.Payload.IntBigNegative{ .limbs = &[_]std.math.big.Limb{0} }; + const zero_4 = Value.initPayload(&payload_3.base); + std.testing.expectEqual(zero_3.hash(), zero_4.hash()); +} diff --git a/src/zir_sema.zig b/src/zir_sema.zig index fc7291aa85..602da97f81 100644 --- a/src/zir_sema.zig +++ b/src/zir_sema.zig @@ -1253,6 +1253,12 @@ fn analyzeInstSwitchBr(mod: *Module, scope: *Scope, inst: *zir.Inst.SwitchBr) In return mod.constNoReturn(scope, inst.base.src); } + if (inst.positionals.cases.len == 0) { + // no cases just analyze else_branch + try analyzeBody(mod, scope, inst.positionals.else_body); + return mod.constNoReturn(scope, inst.base.src); + } + const parent_block = try mod.requireRuntimeBlock(scope, inst.base.src); const cases = try parent_block.arena.alloc(Inst.SwitchBr.Case, inst.positionals.cases.len);