stage2: return same hash for different representations of same value

master
Vexu 2020-10-30 13:24:47 +02:00
parent 3cc68bd913
commit e2e0b6272b
No known key found for this signature in database
GPG Key ID: 59AEB8936E16A6AC
2 changed files with 44 additions and 14 deletions

View File

@ -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());
}

View File

@ -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);