3030#include < tvm/ffi/reflection/structural_hash.h>
3131#include < tvm/ffi/string.h>
3232
33+ #include < cmath>
34+ #include < limits>
3335#include < unordered_map>
3436#include < utility>
3537
@@ -48,6 +50,13 @@ class StructuralHashHandler {
4850 const TVMFFIAny* src_data = AnyUnsafe::TVMFFIAnyPtrFromAny (src);
4951
5052 if (src_data->type_index < TypeIndex::kTVMFFIStaticObjectBegin ) {
53+ // specially handle nan for float, as there can be multiple representations of nan
54+ // make sure they map to the same hash value
55+ if (src_data->type_index == TypeIndex::kTVMFFIFloat && std::isnan (src_data->v_float64 )) {
56+ TVMFFIAny temp = *src_data;
57+ temp.v_float64 = std::numeric_limits<double >::quiet_NaN ();
58+ return details::StableHashCombine (temp.type_index , temp.v_uint64 );
59+ }
5160 // this is POD data, we can just hash the value
5261 return details::StableHashCombine (src_data->type_index , src_data->v_uint64 );
5362 }
@@ -83,9 +92,16 @@ class StructuralHashHandler {
8392 // NOTE: invariant: lhs and rhs are already the same type
8493 const TVMFFITypeInfo* type_info = TVMFFIGetTypeInfo (obj->type_index ());
8594 if (type_info->metadata == nullptr ) {
86- // Fallback to pointer hash
87- return std::hash<const Object*>()(obj.get ());
95+ TVM_FFI_THROW (TypeError) << " Type metadata is not set for type `"
96+ << String (type_info->type_key )
97+ << " `, so StructuralHash is not supported for this type" ;
8898 }
99+ if (type_info->metadata ->structural_eq_hash_kind == kTVMFFISEqHashKindUnsupported ) {
100+ TVM_FFI_THROW (TypeError) << " _type_s_eq_hash_kind is not set for type `"
101+ << String (type_info->type_key )
102+ << " `, so StructuralHash is not supported for this type" ;
103+ }
104+
89105 auto structural_eq_hash_kind = type_info->metadata ->structural_eq_hash_kind ;
90106 if (structural_eq_hash_kind == kTVMFFISEqHashKindUnsupported ) {
91107 // Fallback to pointer hash
@@ -97,9 +113,11 @@ class StructuralHashHandler {
97113 return it->second ;
98114 }
99115
116+ static reflection::TypeAttrColumn custom_s_hash = reflection::TypeAttrColumn (" __s_hash__" );
117+
100118 // compute the hash value
101119 uint64_t hash_value = obj->GetTypeKeyHash ();
102- if (structural_eq_hash_kind != kTVMFFISEqHashKindCustomTreeNode ) {
120+ if (custom_s_hash[type_info-> type_index ] == nullptr ) {
103121 // go over the content and hash the fields
104122 ForEachFieldInfo (type_info, [&](const TVMFFIFieldInfo* field_info) {
105123 // skip fields that are marked as structural eq hash ignore
@@ -119,22 +137,19 @@ class StructuralHashHandler {
119137 }
120138 });
121139 } else {
122- static reflection::TypeAttrColumn custom_s_hash = reflection::TypeAttrColumn (" __s_hash__" );
123- TVM_FFI_ICHECK (custom_s_hash[type_info->type_index ] != nullptr )
124- << " TypeAttr `__s_hash__` is not registered for type `" << String (type_info->type_key )
125- << " `" ;
126140 if (s_hash_callback_ == nullptr ) {
127- s_hash_callback_ = ffi::Function::FromTyped ([this ](AnyView val, bool def_region) {
128- if (def_region) {
129- bool allow_free_var = true ;
130- std::swap (allow_free_var, map_free_vars_);
131- uint64_t hash_value = HashAny (val);
132- std::swap (allow_free_var, map_free_vars_);
133- return hash_value;
134- } else {
135- return HashAny (val);
136- }
137- });
141+ s_hash_callback_ =
142+ ffi::Function::FromTyped ([this ](AnyView val, uint64_t init_hash, bool def_region) {
143+ if (def_region) {
144+ bool allow_free_var = true ;
145+ std::swap (allow_free_var, map_free_vars_);
146+ uint64_t hash_value = HashAny (val);
147+ std::swap (allow_free_var, map_free_vars_);
148+ return details::StableHashCombine (init_hash, hash_value);
149+ } else {
150+ return details::StableHashCombine (init_hash, HashAny (val));
151+ }
152+ });
138153 }
139154 hash_value = custom_s_hash[type_info->type_index ]
140155 .cast <ffi::Function>()(obj, hash_value, s_hash_callback_)
0 commit comments