aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorPhilip Herron <philip.herron@embecosm.com>2021-05-14 12:23:33 +0100
committerPhilip Herron <philip.herron@embecosm.com>2021-05-14 12:34:24 +0100
commit9bcbfee5f3e7d69b59c985404b3e4e0788f4a607 (patch)
tree4ab3ce185bf03a191ad4241fc72a3c957066fa1d /gcc
parent5d7fbc4a78897f8f561bdd78b4d3bbc15f4b351f (diff)
downloadgcc-9bcbfee5f3e7d69b59c985404b3e4e0788f4a607.zip
gcc-9bcbfee5f3e7d69b59c985404b3e4e0788f4a607.tar.gz
gcc-9bcbfee5f3e7d69b59c985404b3e4e0788f4a607.tar.bz2
Add FNV-128 hash for legacy symbol mangling
Rustc uses a SIP128 hash for the legacy symbol mangling but an FNV hash is simpler to implement this is a port of the implementation from golang stdlib hash package. The fingerprint for the hash is simple the function signiture for now. Rustc takes into account options such as -Cmetadata to generate uniqueness. We still need to implement an SIP128 and the V0 symbol mangling but this will do in the interim. Addresses: #305 Fixes: #428
Diffstat (limited to 'gcc')
-rw-r--r--gcc/rust/backend/rust-compile-context.h5
-rw-r--r--gcc/rust/backend/rust-compile-implitem.h4
-rw-r--r--gcc/rust/backend/rust-compile-item.h4
-rw-r--r--gcc/rust/backend/rust-compile.cc35
-rw-r--r--gcc/rust/util/fnv-hash.h98
5 files changed, 134 insertions, 12 deletions
diff --git a/gcc/rust/backend/rust-compile-context.h b/gcc/rust/backend/rust-compile-context.h
index 45fb6c2..5df0d89 100644
--- a/gcc/rust/backend/rust-compile-context.h
+++ b/gcc/rust/backend/rust-compile-context.h
@@ -283,9 +283,12 @@ public:
return pop;
}
- std::string mangle_item (const std::string &name) const;
+ // this needs to support Legacy and V0 see github #429 or #305
+ std::string mangle_item (const TyTy::BaseType *ty,
+ const std::string &name) const;
std::string mangle_impl_item (const TyTy::BaseType *self,
+ const TyTy::BaseType *ty,
const std::string &name) const;
private:
diff --git a/gcc/rust/backend/rust-compile-implitem.h b/gcc/rust/backend/rust-compile-implitem.h
index b071d94..a5ca13b 100644
--- a/gcc/rust/backend/rust-compile-implitem.h
+++ b/gcc/rust/backend/rust-compile-implitem.h
@@ -125,7 +125,7 @@ public:
std::string fn_identifier
= self->get_name () + "_" + function.get_function_name ();
std::string asm_name
- = ctx->mangle_impl_item (self, function.get_function_name ());
+ = ctx->mangle_impl_item (self, fntype, function.get_function_name ());
Bfunction *fndecl
= ctx->get_backend ()->function (compiled_fn_type, fn_identifier,
@@ -310,7 +310,7 @@ public:
std::string fn_identifier
= self->get_name () + "_" + method.get_method_name ();
std::string asm_name
- = ctx->mangle_impl_item (self, method.get_method_name ());
+ = ctx->mangle_impl_item (self, fntype, method.get_method_name ());
Bfunction *fndecl
= ctx->get_backend ()->function (compiled_fn_type, fn_identifier,
diff --git a/gcc/rust/backend/rust-compile-item.h b/gcc/rust/backend/rust-compile-item.h
index c3dc279..e3b6d0f 100644
--- a/gcc/rust/backend/rust-compile-item.h
+++ b/gcc/rust/backend/rust-compile-item.h
@@ -53,7 +53,7 @@ public:
Bexpression *value = CompileExpr::Compile (var.get_expr (), ctx);
std::string name = var.get_identifier ();
- std::string asm_name = ctx->mangle_item (name);
+ std::string asm_name = ctx->mangle_item (resolved_type, name);
bool is_external = false;
bool is_hidden = false;
@@ -154,7 +154,7 @@ public:
// we don't mangle the main fn since we haven't implemented the main shim
// yet
if (!is_main_fn)
- asm_name = ctx->mangle_item (ir_symbol_name);
+ asm_name = ctx->mangle_item (fntype, ir_symbol_name);
Bfunction *fndecl
= ctx->get_backend ()->function (compiled_fn_type, ir_symbol_name,
diff --git a/gcc/rust/backend/rust-compile.cc b/gcc/rust/backend/rust-compile.cc
index 9dd3b57..480afc8b 100644
--- a/gcc/rust/backend/rust-compile.cc
+++ b/gcc/rust/backend/rust-compile.cc
@@ -20,6 +20,7 @@
#include "rust-compile-item.h"
#include "rust-compile-expr.h"
#include "rust-compile-struct-field-expr.h"
+#include "fnv-hash.h"
namespace Rust {
namespace Compile {
@@ -427,10 +428,23 @@ mangle_name (const std::string &name)
return std::to_string (name.size ()) + name;
}
+// rustc uses a sip128 hash for legacy mangling, but an fnv 128 was quicker to
+// implement for now
static std::string
-dummy_hash ()
+legacy_hash (const std::string &fingerprint)
{
- return "h0123456789abcdef";
+ Hash::FNV128 hasher;
+ hasher.write ((const unsigned char *) fingerprint.c_str (),
+ fingerprint.size ());
+
+ uint64_t hi, lo;
+ hasher.sum (&hi, &lo);
+
+ char hex[16 + 1];
+ memset (hex, 0, sizeof hex);
+ snprintf (hex, sizeof hex, "%08lx%08lx", lo, hi);
+
+ return "h" + std::string (hex, sizeof (hex) - 1);
}
static std::string
@@ -464,21 +478,28 @@ mangle_self (const TyTy::BaseType *self)
}
std::string
-Context::mangle_item (const std::string &name) const
+Context::mangle_item (const TyTy::BaseType *ty, const std::string &name) const
{
const std::string &crate_name = mappings->get_current_crate_name ();
+
+ const std::string hash = legacy_hash (ty->as_string ());
+ const std::string hash_sig = mangle_name (hash);
+
return kMangledSymbolPrefix + mangle_name (crate_name) + mangle_name (name)
- + mangle_name (dummy_hash ()) + kMangledSymbolDelim;
+ + hash_sig + kMangledSymbolDelim;
}
std::string
-Context::mangle_impl_item (const TyTy::BaseType *self,
+Context::mangle_impl_item (const TyTy::BaseType *self, const TyTy::BaseType *ty,
const std::string &name) const
{
const std::string &crate_name = mappings->get_current_crate_name ();
+
+ const std::string hash = legacy_hash (ty->as_string ());
+ const std::string hash_sig = mangle_name (hash);
+
return kMangledSymbolPrefix + mangle_name (crate_name) + mangle_self (self)
- + mangle_name (name) + mangle_name (dummy_hash ())
- + kMangledSymbolDelim;
+ + mangle_name (name) + hash_sig + kMangledSymbolDelim;
}
} // namespace Compile
diff --git a/gcc/rust/util/fnv-hash.h b/gcc/rust/util/fnv-hash.h
new file mode 100644
index 0000000..692ccde
--- /dev/null
+++ b/gcc/rust/util/fnv-hash.h
@@ -0,0 +1,98 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+#ifndef RUST_FNV_HASH_H
+#define RUST_FNV_HASH_H
+
+#include <cstdint>
+#include <cstddef>
+
+namespace Rust {
+namespace Hash {
+
+const uint64_t offset128Lower = 0x62b821756295c58d;
+const uint64_t offset128Higher = 0x6c62272e07bb0142;
+const uint64_t prime128Lower = 0x13b;
+const uint64_t prime128Shift = 24;
+
+// ported from https://github.com/golang/go/blob/master/src/hash/fnv/fnv.go
+class FNV128
+{
+public:
+ FNV128 () { reset (); }
+
+ void reset ()
+ {
+ buf[0] = offset128Higher;
+ buf[1] = offset128Lower;
+ }
+
+ void write (const unsigned char *in, size_t len)
+ {
+ for (size_t i = 0; i < len; i++)
+ {
+ unsigned char c = in[i];
+
+ // https://stackoverflow.com/questions/28868367/getting-the-high-part-of-64-bit-integer-multiplication
+ uint64_t a = prime128Lower;
+ uint64_t b = buf[1];
+
+ uint64_t a_lo = (uint32_t) a;
+ uint64_t a_hi = a >> 32;
+ uint64_t b_lo = (uint32_t) b;
+ uint64_t b_hi = b >> 32;
+
+ uint64_t a_x_b_hi = a_hi * b_hi;
+ uint64_t a_x_b_mid = a_hi * b_lo;
+ uint64_t b_x_a_mid = b_hi * a_lo;
+ uint64_t a_x_b_lo = a_lo * b_lo;
+
+ uint64_t carry_bit
+ = ((uint64_t) (uint32_t) a_x_b_mid + (uint64_t) (uint32_t) b_x_a_mid
+ + (a_x_b_lo >> 32))
+ >> 32;
+
+ uint64_t multhi
+ = a_x_b_hi + (a_x_b_mid >> 32) + (b_x_a_mid >> 32) + carry_bit;
+
+ uint64_t s0 = multhi; // high
+ uint64_t s1 = prime128Lower * buf[1]; // low
+
+ s0 += buf[1] << (prime128Shift + prime128Lower * buf[0]);
+
+ // Update the values
+ buf[1] = s1;
+ buf[0] = s0;
+ buf[1] ^= (uint64_t) c;
+ }
+ }
+
+ void sum (uint64_t *hi, uint64_t *lo) const
+ {
+ *hi = buf[0];
+ *lo = buf[1];
+ }
+
+private:
+ uint64_t buf[2];
+};
+
+} // namespace Hash
+} // namespace Rust
+
+#endif // RUST_FNV_HASH_H