mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-09-01 10:19:01 +00:00
compiler: make composite map hashes order dependent
Use the same multiply-and-XOR combination as the runtime interface hash for generated struct and array key hashes. This avoids systematic collisions when components are permuted.
This commit is contained in:
+5
-3
@@ -417,6 +417,7 @@ func (b *builder) generateKeyHash(keyType types.Type, llvmKeyType llvm.Type, key
|
|||||||
return b.createRuntimeCall("hashmapInterfacePtrHash", []llvm.Value{keyPtr, size, seed}, "hash")
|
return b.createRuntimeCall("hashmapInterfacePtrHash", []llvm.Value{keyPtr, size, seed}, "hash")
|
||||||
case *types.Struct:
|
case *types.Struct:
|
||||||
hash := llvm.ConstInt(b.ctx.Int32Type(), 0, false)
|
hash := llvm.ConstInt(b.ctx.Int32Type(), 0, false)
|
||||||
|
multiplier := llvm.ConstInt(b.ctx.Int32Type(), 31, false)
|
||||||
zero := llvm.ConstInt(b.ctx.Int32Type(), 0, false)
|
zero := llvm.ConstInt(b.ctx.Int32Type(), 0, false)
|
||||||
for i := 0; i < keyType.NumFields(); i++ {
|
for i := 0; i < keyType.NumFields(); i++ {
|
||||||
if keyType.Field(i).Name() == "_" {
|
if keyType.Field(i).Name() == "_" {
|
||||||
@@ -430,7 +431,7 @@ func (b *builder) generateKeyHash(keyType types.Type, llvmKeyType llvm.Type, key
|
|||||||
idx := llvm.ConstInt(b.ctx.Int32Type(), uint64(i), false)
|
idx := llvm.ConstInt(b.ctx.Int32Type(), uint64(i), false)
|
||||||
fieldPtr := b.CreateInBoundsGEP(llvmKeyType, keyPtr, []llvm.Value{zero, idx}, "")
|
fieldPtr := b.CreateInBoundsGEP(llvmKeyType, keyPtr, []llvm.Value{zero, idx}, "")
|
||||||
fieldHash := b.generateKeyHash(fieldType, llvmFieldType, fieldPtr, seed)
|
fieldHash := b.generateKeyHash(fieldType, llvmFieldType, fieldPtr, seed)
|
||||||
hash = b.CreateXor(hash, fieldHash, "")
|
hash = b.CreateXor(b.CreateMul(hash, multiplier, ""), fieldHash, "")
|
||||||
}
|
}
|
||||||
return hash
|
return hash
|
||||||
case *types.Array:
|
case *types.Array:
|
||||||
@@ -445,6 +446,7 @@ func (b *builder) generateKeyHash(keyType types.Type, llvmKeyType llvm.Type, key
|
|||||||
if arrayLen == 0 {
|
if arrayLen == 0 {
|
||||||
return llvm.ConstInt(b.ctx.Int32Type(), 0, false)
|
return llvm.ConstInt(b.ctx.Int32Type(), 0, false)
|
||||||
}
|
}
|
||||||
|
multiplier := llvm.ConstInt(b.ctx.Int32Type(), 31, false)
|
||||||
if arrayLen <= hashArrayUnrollLimit {
|
if arrayLen <= hashArrayUnrollLimit {
|
||||||
hash := llvm.ConstInt(b.ctx.Int32Type(), 0, false)
|
hash := llvm.ConstInt(b.ctx.Int32Type(), 0, false)
|
||||||
zero := llvm.ConstInt(b.ctx.Int32Type(), 0, false)
|
zero := llvm.ConstInt(b.ctx.Int32Type(), 0, false)
|
||||||
@@ -452,7 +454,7 @@ func (b *builder) generateKeyHash(keyType types.Type, llvmKeyType llvm.Type, key
|
|||||||
idx := llvm.ConstInt(b.uintptrType, uint64(i), false)
|
idx := llvm.ConstInt(b.uintptrType, uint64(i), false)
|
||||||
elemPtr := b.CreateInBoundsGEP(llvmKeyType, keyPtr, []llvm.Value{zero, idx}, "")
|
elemPtr := b.CreateInBoundsGEP(llvmKeyType, keyPtr, []llvm.Value{zero, idx}, "")
|
||||||
elemHash := b.generateKeyHash(elemType, llvmElemType, elemPtr, seed)
|
elemHash := b.generateKeyHash(elemType, llvmElemType, elemPtr, seed)
|
||||||
hash = b.CreateXor(hash, elemHash, "")
|
hash = b.CreateXor(b.CreateMul(hash, multiplier, ""), elemHash, "")
|
||||||
}
|
}
|
||||||
return hash
|
return hash
|
||||||
}
|
}
|
||||||
@@ -471,7 +473,7 @@ func (b *builder) generateKeyHash(keyType types.Type, llvmKeyType llvm.Type, key
|
|||||||
|
|
||||||
elemPtr := b.CreateInBoundsGEP(llvmKeyType, keyPtr, []llvm.Value{zero, phiI}, "")
|
elemPtr := b.CreateInBoundsGEP(llvmKeyType, keyPtr, []llvm.Value{zero, phiI}, "")
|
||||||
elemHash := b.generateKeyHash(elemType, llvmElemType, elemPtr, seed)
|
elemHash := b.generateKeyHash(elemType, llvmElemType, elemPtr, seed)
|
||||||
newHash := b.CreateXor(phiHash, elemHash, "")
|
newHash := b.CreateXor(b.CreateMul(phiHash, multiplier, ""), elemHash, "")
|
||||||
nextI := b.CreateAdd(phiI, llvm.ConstInt(b.uintptrType, 1, false), "")
|
nextI := b.CreateAdd(phiI, llvm.ConstInt(b.uintptrType, 1, false), "")
|
||||||
cond := b.CreateICmp(llvm.IntULT, nextI, llvm.ConstInt(b.uintptrType, uint64(arrayLen), false), "")
|
cond := b.CreateICmp(llvm.IntULT, nextI, llvm.ConstInt(b.uintptrType, uint64(arrayLen), false), "")
|
||||||
b.CreateCondBr(cond, loopBody, loopDone)
|
b.CreateCondBr(cond, loopBody, loopDone)
|
||||||
|
|||||||
Vendored
+14
-11
@@ -113,8 +113,9 @@ entry:
|
|||||||
%hash = call i32 @runtime.hashmapStringPtrHash(ptr %0, i32 8, i32 %2, ptr undef) #4
|
%hash = call i32 @runtime.hashmapStringPtrHash(ptr %0, i32 8, i32 %2, ptr undef) #4
|
||||||
%4 = getelementptr inbounds nuw i8, ptr %0, i32 8
|
%4 = getelementptr inbounds nuw i8, ptr %0, i32 8
|
||||||
%hash1 = call i32 @runtime.hashmapStringPtrHash(ptr nonnull %4, i32 8, i32 %2, ptr undef) #4
|
%hash1 = call i32 @runtime.hashmapStringPtrHash(ptr nonnull %4, i32 8, i32 %2, ptr undef) #4
|
||||||
%5 = xor i32 %hash, %hash1
|
%5 = mul i32 %hash, 31
|
||||||
ret i32 %5
|
%6 = xor i32 %5, %hash1
|
||||||
|
ret i32 %6
|
||||||
}
|
}
|
||||||
|
|
||||||
declare i32 @runtime.hashmapStringPtrHash(ptr, i32, i32, ptr) #0
|
declare i32 @runtime.hashmapStringPtrHash(ptr, i32, i32, ptr) #0
|
||||||
@@ -161,8 +162,9 @@ entry:
|
|||||||
%hash = call i32 @runtime.hashmapStringPtrHash(ptr %0, i32 8, i32 %2, ptr undef) #4
|
%hash = call i32 @runtime.hashmapStringPtrHash(ptr %0, i32 8, i32 %2, ptr undef) #4
|
||||||
%4 = getelementptr inbounds nuw i8, ptr %0, i32 8
|
%4 = getelementptr inbounds nuw i8, ptr %0, i32 8
|
||||||
%hash1 = call i32 @runtime.hashmapStringPtrHash(ptr nonnull %4, i32 8, i32 %2, ptr undef) #4
|
%hash1 = call i32 @runtime.hashmapStringPtrHash(ptr nonnull %4, i32 8, i32 %2, ptr undef) #4
|
||||||
%5 = xor i32 %hash, %hash1
|
%5 = mul i32 %hash, 31
|
||||||
ret i32 %5
|
%6 = xor i32 %5, %hash1
|
||||||
|
ret i32 %6
|
||||||
}
|
}
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
@@ -203,17 +205,18 @@ entry:
|
|||||||
br label %hash.array.body
|
br label %hash.array.body
|
||||||
|
|
||||||
hash.array.body: ; preds = %hash.array.body, %entry
|
hash.array.body: ; preds = %hash.array.body, %entry
|
||||||
%i = phi i32 [ 0, %entry ], [ %6, %hash.array.body ]
|
%i = phi i32 [ 0, %entry ], [ %7, %hash.array.body ]
|
||||||
%hash.acc = phi i32 [ 0, %entry ], [ %5, %hash.array.body ]
|
%hash.acc = phi i32 [ 0, %entry ], [ %6, %hash.array.body ]
|
||||||
%4 = getelementptr inbounds nuw %runtime._string, ptr %0, i32 %i
|
%4 = getelementptr inbounds nuw %runtime._string, ptr %0, i32 %i
|
||||||
%hash = call i32 @runtime.hashmapStringPtrHash(ptr %4, i32 8, i32 %2, ptr undef) #4
|
%hash = call i32 @runtime.hashmapStringPtrHash(ptr %4, i32 8, i32 %2, ptr undef) #4
|
||||||
%5 = xor i32 %hash.acc, %hash
|
%5 = mul i32 %hash.acc, 31
|
||||||
%6 = add nuw nsw i32 %i, 1
|
%6 = xor i32 %5, %hash
|
||||||
%7 = icmp samesign ult i32 %i, 4
|
%7 = add nuw nsw i32 %i, 1
|
||||||
br i1 %7, label %hash.array.body, label %hash.array.done
|
%8 = icmp samesign ult i32 %i, 4
|
||||||
|
br i1 %8, label %hash.array.body, label %hash.array.done
|
||||||
|
|
||||||
hash.array.done: ; preds = %hash.array.body
|
hash.array.done: ; preds = %hash.array.body
|
||||||
ret i32 %5
|
ret i32 %6
|
||||||
}
|
}
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
|
|||||||
Reference in New Issue
Block a user