Skip to content

Commit

Permalink
wip [skip ci]
Browse files Browse the repository at this point in the history
  • Loading branch information
tamaroning committed Sep 20, 2023
1 parent 612a48a commit b5c7f2b
Show file tree
Hide file tree
Showing 2 changed files with 232 additions and 43 deletions.
266 changes: 223 additions & 43 deletions gcc/rust/backend/rust-mangle.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,15 @@
#include "rust-base62.h"
#include "rust-unicode.h"
#include "rust-diagnostics.h"
#include "rust-hir-full-decls.h"
#include "rust-hir-type-bounds.h"
#include "rust-system.h"
#include "rust-tyty-subst.h"
#include "rust-unicode.h"
#include "rust-punycode.h"
#include "rust-hir.h"
#include "rust-compile-type.h"
#include <sstream>

// FIXME: Rename those to legacy_*
static const std::string kMangledSymbolPrefix = "_ZN";
Expand All @@ -26,7 +33,7 @@ static const std::string kMangledComma = "$C$";
namespace Rust {
namespace Compile {

Mangler::MangleVersion Mangler::version = MangleVersion::LEGACY;
Mangler::MangleVersion Mangler::version = MangleVersion::V0;

static std::string
legacy_mangle_name (const std::string &name)
Expand All @@ -52,8 +59,7 @@ legacy_mangle_name (const std::string &name)
// _ZN74_$LT$example..Identity$u20$as$u20$example..FnLike$LT$$RF$T$C$$RF$T$GT$$GT$4call17ha9ee58935895acb3E

tl::optional<Utf8String> utf8_name = Utf8String::make_utf8_string (name);
if (!utf8_name.has_value ())
rust_unreachable ();
rust_assert (utf8_name.has_value ());
std::vector<Codepoint> chars = utf8_name.value ().get_chars ();
std::string buffer;
for (size_t i = 0; i < chars.size (); i++)
Expand Down Expand Up @@ -151,9 +157,9 @@ static std::string
v0_numeric_prefix (const TyTy::BaseType *ty)
{
static const std::map<std::string, std::string> num_prefixes = {
{"[i8]", "a"}, {"[u8]", "h"}, {"[i16]", "s"}, {"[u16]", "t"},
{"[i32]", "l"}, {"[u32]", "m"}, {"[i64]", "x"}, {"[u64]", "y"},
{"[isize]", "i"}, {"[usize]", "j"}, {"[f32]", "f"}, {"[f64]", "d"},
{"i8", "a"}, {"u8", "h"}, {"i16", "s"}, {"u16", "t"},
{"i32", "l"}, {"u32", "m"}, {"i64", "x"}, {"u64", "y"},
{"isize", "i"}, {"usize", "j"}, {"f32", "f"}, {"f64", "d"},
};

auto ty_kind = ty->get_kind ();
Expand All @@ -170,6 +176,7 @@ v0_numeric_prefix (const TyTy::BaseType *ty)
if (numeric_iter != num_prefixes.end ())
return numeric_iter->second;

rust_unreachable ();
return "";
}

Expand Down Expand Up @@ -212,46 +219,74 @@ v0_simple_type_prefix (const TyTy::BaseType *ty)
rust_unreachable ();
}

// Add an underscore-terminated base62 integer to the mangling string.
// Returns an underscore-terminated base62 integer.
// This corresponds to the `<base-62-number>` grammar in the v0 mangling RFC:
// - 0 is encoded as "_"
// - any other value is encoded as itself minus one in base 62, followed by
// "_"
static void
v0_add_integer_62 (std::string &mangled, uint64_t x)
static std::string
v0_integer_62 (uint64_t x)
{
std::stringstream s;
if (x > 0)
mangled.append (base62_integer (x - 1));
s << base62_integer (x - 1);

mangled.append ("_");
s << "_";
return s.str ();
}

// Add a tag-prefixed base62 integer to the mangling string when the
// Returns a tag-prefixed base62 integer when the
// integer is greater than 0:
// - 0 is encoded as "" (nothing)
// - any other value is encoded as <tag> + v0_add_integer_62(itself), that is
// - any other value is encoded as <tag> + v0_integer_62(itself), that is
// <tag> + base62(itself - 1) + '_'
static void
v0_add_opt_integer_62 (std::string &mangled, std::string tag, uint64_t x)
static std::string
v0_opt_integer_62 (std::string tag, uint64_t x)
{
if (x > 0)
{
mangled.append (tag);
v0_add_integer_62 (mangled, x);
return tag + v0_integer_62 (x);
}
return "";
}

static void
v0_add_disambiguator (std::string &mangled, uint64_t dis)
static std::string
v0_disambiguator (uint64_t dis)
{
v0_add_opt_integer_62 (mangled, "s", dis);
return v0_opt_integer_62 ("s", dis);
}

// Add an identifier to the mangled string. This corresponds to the
static std::string
v0_type_prefix (const TyTy::BaseType *ty)
{
auto ty_prefix = v0_simple_type_prefix (ty);
if (!ty_prefix.empty ())
return ty_prefix;

// FIXME: We need to fetch more type prefixes
rust_unreachable ();
}

static std::string
v0_generic_arg (const TyTy::BaseType *ty)
{
std::stringstream ss;
const TyTy::FnType *fnty = static_cast<const TyTy::FnType *> (ty);
TyTy::SubstitutionArgumentMappings &subst_ref
= const_cast<TyTy::FnType *> (fnty)->get_substitution_arguments ();
for (TyTy::SubstitutionArg &map : subst_ref.get_mappings ())
{
ss << v0_type_prefix (map.get_tyty ());
}
return ss.str ();
}

// Returns an mangled identifier. This corresponds to the
// `<identifier>` grammar in the v0 mangling RFC.
static void
v0_add_identifier (std::string &mangled, const std::string &identifier)
static std::string
v0_identifier (const std::string &identifier)
{
std::stringstream mangled;
// The grammar for unicode identifier is contained in
// <undisambiguated-identifier>, right under the <identifier> one. If the
// identifier contains unicode values, then an extra "u" needs to be added to
Expand Down Expand Up @@ -279,26 +314,149 @@ v0_add_identifier (std::string &mangled, const std::string &identifier)
std::replace (punycode.begin (), punycode.end (), '-', '_');

if (!is_ascii_ident)
mangled.append ("u");
mangled << "u";

mangled += std::to_string (punycode.size ());
mangled << std::to_string (punycode.size ());
// If the first character of the identifier is a digit or an underscore, we
// add an extra underscore
if (punycode[0] == '_')
mangled += "_";
mangled << "_";

mangled += punycode;
mangled << punycode;
return mangled.str ();
}

static std::string
v0_type_prefix (const TyTy::BaseType *ty)
v0_path (const TyTy::BaseType *ty, const Resolver::CanonicalPath &path)
{
auto ty_prefix = v0_simple_type_prefix (ty);
if (!ty_prefix.empty ())
return ty_prefix;
auto mappings = Analysis::Mappings::get ();

// FIXME: We need to fetch more type prefixes
rust_unreachable ();
std::string mangled;

path.iterate_segs ([&] (const Resolver::CanonicalPath &seg) {
std::string prefix = "";
std::string ns = "";
std::string ident = "";
std::string generic_prefix = "";
std::string generic_postfix = "";

HirId hir_id;
rust_assert (mappings->lookup_node_to_hir (seg.get_node_id (), &hir_id));

HirId parent_impl_id = UNKNOWN_HIRID;
HIR::ImplItem *impl_item
= mappings->lookup_hir_implitem (hir_id, &parent_impl_id);
HIR::TraitItem *trait_item = mappings->lookup_hir_trait_item (hir_id);
HIR::Item *item = mappings->lookup_hir_item (hir_id);

if (impl_item != nullptr)
{
switch (impl_item->get_impl_item_type ())
{
case HIR::ImplItem::FUNCTION: {
prefix = "N";
ns = "v";
HIR::Function *fn = static_cast<HIR::Function *> (impl_item);
if (!fn->get_generic_params ().empty ())
{
generic_prefix = "I";
generic_postfix = v0_generic_arg (ty) + "E";
}
}
break;
case HIR::ImplItem::CONSTANT:
prefix = "N";
ns = "v";
break;
default:
rust_internal_error_at (UNDEF_LOCATION, "Cannot mangle '%s'",
path.get ().c_str ());
break;
}
}
else if (trait_item != nullptr)
{
switch (trait_item->get_item_kind ())
{
case HIR::TraitItem::FUNC: {
prefix = "N";
ns = "v";
HIR::Function *fn = static_cast<HIR::Function *> (impl_item);
if (!fn->get_generic_params ().empty ())
{
generic_prefix = "I";
generic_postfix = v0_generic_arg (ty) + "E";
}
}
break;
case HIR::TraitItem::CONST:
prefix = "N";
ns = "v";
break;
default:
rust_internal_error_at (UNDEF_LOCATION, "Cannot mangle '%s'",
path.get ().c_str ());
break;
}
}
else if (item != nullptr)
switch (item->get_item_kind ())
{
case HIR::Item::ItemKind::Function: {
prefix = "N";
ns = "v";
HIR::Function *fn = static_cast<HIR::Function *> (item);
if (!fn->get_generic_params ().empty ())
{
generic_prefix = "I";
generic_postfix = v0_generic_arg (ty) + "E";
}
}
break;
case HIR::Item::ItemKind::Module:
case HIR::Item::ItemKind::Trait:
case HIR::Item::ItemKind::Static:
case HIR::Item::ItemKind::Constant:
prefix = "N";
ns = "v";
break;
case HIR::Item::ItemKind::Struct:
case HIR::Item::ItemKind::Enum:
case HIR::Item::ItemKind::Union:
prefix = "N";
ns = "t";
break;
case HIR::Item::ItemKind::Impl:
prefix = "M";
// TODO: Add <impl-path> and support trait impl
// inherent impl: M <impl-path> <type>
// trait impl: X <impl-path> <type> <path>
rust_unreachable();
break;
case HIR::Item::ItemKind::ExternBlock:
case HIR::Item::ItemKind::ExternCrate:
case HIR::Item::ItemKind::UseDeclaration:
case HIR::Item::ItemKind::TypeAlias:
case HIR::Item::ItemKind::EnumItem:
rust_internal_error_at (UNDEF_LOCATION, "Cannot mangle '%s'",
path.get ().c_str ());
break;
}
else
{
// Not HIR item, impl item, trait impl item. Assume a crate.
std::string crate_disambiguator
= v0_disambiguator (path.get_crate_num ());
prefix = "C" + crate_disambiguator;
}

if (prefix == "N")
ident = v0_identifier (seg.get ());

mangled = generic_prefix + prefix + ns + mangled + ident + generic_postfix;
return true;
});
return mangled;
}

static std::string
Expand All @@ -315,19 +473,23 @@ legacy_mangle_item (const TyTy::BaseType *ty,
static std::string
v0_mangle_item (const TyTy::BaseType *ty, const Resolver::CanonicalPath &path)
{
rust_debug ("Start mangle: %s", path.get ().c_str ());
// we can get this from the canonical_path
auto mappings = Analysis::Mappings::get ();
std::string crate_name;
bool ok = mappings->get_crate_name (path.get_crate_num (), crate_name);
rust_assert (ok);

std::string mangled;
// FIXME: Add real algorithm once all pieces are implemented
v0_add_identifier (mangled, crate_name);
v0_add_disambiguator (mangled, 62);
auto ty_prefix = v0_type_prefix (ty);
// auto mappings = Analysis::Mappings::get ();
// std::string crate_name;
// bool ok = mappings->get_crate_name (path.get_crate_num (), crate_name);
// rust_assert (ok);

rust_unreachable ();
std::stringstream mangled;
mangled << "_R";
mangled << v0_path (ty, path);

rust_debug ("v0 mangle: %s => %s", path.get ().c_str (),
mangled.str ().c_str ());

// rust_unreachable ();
return mangled.str ();
}

std::string
Expand All @@ -347,3 +509,21 @@ Mangler::mangle_item (const TyTy::BaseType *ty,

} // namespace Compile
} // namespace Rust

#if CHECKING_P
namespace selftest {

void
assert_v0_mangle (const std::string &input, const std::string &expected)
{
// TODO:
}

void
rust_v0_mangling_test (void)
{
// TODO:
}

} // namespace selftest
#endif // !CHECKING_P
9 changes: 9 additions & 0 deletions gcc/rust/backend/rust-mangle.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,4 +49,13 @@ class Mangler
} // namespace Compile
} // namespace Rust

#if CHECKING_P
namespace selftest {

void
rust_v0_mangling_test ();

} // namespace selftest
#endif // !CHECKING_P

#endif // RUST_MANGLE_H

0 comments on commit b5c7f2b

Please sign in to comment.