aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPhilip Herron <philip.herron@embecosm.com>2021-05-13 11:50:31 +0100
committerPhilip Herron <philip.herron@embecosm.com>2021-05-13 12:56:30 +0100
commitd326288aa4f32707f1340e2f39b56bd6ab608802 (patch)
tree8f987d715d879f369620061a5e2d4c336f5bae38
parenta1c148518de1cb8f60f779dc206f663e8593191a (diff)
downloadgcc-d326288aa4f32707f1340e2f39b56bd6ab608802.zip
gcc-d326288aa4f32707f1340e2f39b56bd6ab608802.tar.gz
gcc-d326288aa4f32707f1340e2f39b56bd6ab608802.tar.bz2
Fix duplicated function generation for generics
When emitting the backend IR we need to check if we have already compiled one already. This is all due to the fact when we do generic substitutions in type resolution its only upon usage of a function the function is substituted it gains a new unique ty_ref HIR ID to make sure new substituted versions of a type have unique ids. This means we can end up with multiple substitued versions of the same function which end up being compiled multiple times. This was also the case for generic data types but is already fixed. Fixes #403
-rw-r--r--gcc/rust/backend/rust-compile-context.h30
-rw-r--r--gcc/rust/backend/rust-compile-implitem.h92
-rw-r--r--gcc/rust/backend/rust-compile-item.h46
3 files changed, 103 insertions, 65 deletions
diff --git a/gcc/rust/backend/rust-compile-context.h b/gcc/rust/backend/rust-compile-context.h
index 7db4ea2..45fb6c2 100644
--- a/gcc/rust/backend/rust-compile-context.h
+++ b/gcc/rust/backend/rust-compile-context.h
@@ -157,13 +157,38 @@ public:
return true;
}
- void insert_function_decl (HirId id, ::Bfunction *fn)
+ void insert_function_decl (HirId id, ::Bfunction *fn,
+ const TyTy::BaseType *ref)
{
+ rust_assert (compiled_fn_map.find (id) == compiled_fn_map.end ());
compiled_fn_map[id] = fn;
+ if (ref != nullptr)
+ {
+ std::pair<HirId, ::Bfunction *> elem (id, fn);
+ mono_fns[ref] = std::move (elem);
+ }
}
- bool lookup_function_decl (HirId id, ::Bfunction **fn)
+ bool lookup_function_decl (HirId id, ::Bfunction **fn,
+ const TyTy::BaseType *ref = nullptr)
{
+ // for for any monomorphized fns
+ if (ref != nullptr)
+ {
+ for (auto it = mono_fns.begin (); it != mono_fns.end (); it++)
+ {
+ std::pair<HirId, ::Bfunction *> &val = it->second;
+ const TyTy::BaseType *r = it->first;
+ if (ref->is_equal (*r))
+ {
+ *fn = val.second;
+
+ return true;
+ }
+ }
+ return false;
+ }
+
auto it = compiled_fn_map.find (id);
if (it == compiled_fn_map.end ())
return false;
@@ -282,6 +307,7 @@ private:
std::vector< ::Bvariable *> loop_value_stack;
std::vector< ::Blabel *> loop_begin_labels;
std::map<const TyTy::BaseType *, std::pair<HirId, ::Btype *> > mono;
+ std::map<const TyTy::BaseType *, std::pair<HirId, ::Bfunction *> > mono_fns;
// To GCC middle-end
std::vector< ::Btype *> type_decls;
diff --git a/gcc/rust/backend/rust-compile-implitem.h b/gcc/rust/backend/rust-compile-implitem.h
index f2caa2e..b071d94 100644
--- a/gcc/rust/backend/rust-compile-implitem.h
+++ b/gcc/rust/backend/rust-compile-implitem.h
@@ -66,17 +66,6 @@ public:
if (!compile_fns)
return;
- // items can be forward compiled which means we may not need to invoke this
- // code
- Bfunction *lookup = nullptr;
- if (ctx->lookup_function_decl (function.get_mappings ().get_hirid (),
- &lookup))
- {
- // has this been added to the list then it must be finished
- if (ctx->function_completed (lookup))
- return;
- }
-
TyTy::BaseType *fntype_tyty;
if (!ctx->get_tyctx ()->lookup_type (function.get_mappings ().get_hirid (),
&fntype_tyty))
@@ -86,28 +75,43 @@ public:
return;
}
- if (fntype_tyty->get_kind () != TyTy::TypeKind::FNDEF)
- {
- rust_error_at (function.get_locus (), "invalid TyTy for function item");
- return;
- }
-
+ rust_assert (fntype_tyty->get_kind () == TyTy::TypeKind::FNDEF);
TyTy::FnType *fntype = static_cast<TyTy::FnType *> (fntype_tyty);
if (fntype->has_subsititions_defined ())
{
- // we cant do anything for this only when it is used
+ // we cant do anything for this only when it is used and a concrete type
+ // is given
if (concrete == nullptr)
return;
else
{
rust_assert (concrete->get_kind () == TyTy::TypeKind::FNDEF);
fntype = static_cast<TyTy::FnType *> (concrete);
+ }
+ }
- // override the Hir Lookups for the substituions in this context
- fntype->override_context ();
+ // items can be forward compiled which means we may not need to invoke this
+ // code. We might also have already compiled this generic function as well.
+ Bfunction *lookup = nullptr;
+ if (ctx->lookup_function_decl (fntype->get_ty_ref (), &lookup, fntype))
+ {
+ // has this been added to the list then it must be finished
+ if (ctx->function_completed (lookup))
+ {
+ Bfunction *dummy = nullptr;
+ if (!ctx->lookup_function_decl (fntype->get_ty_ref (), &dummy))
+ ctx->insert_function_decl (fntype->get_ty_ref (), lookup, fntype);
+
+ return;
}
}
+ if (fntype->has_subsititions_defined ())
+ {
+ // override the Hir Lookups for the substituions in this context
+ fntype->override_context ();
+ }
+
// convert to the actual function type
::Btype *compiled_fn_type = TyTyResolveCompile::compile (ctx, fntype);
@@ -126,7 +130,7 @@ public:
Bfunction *fndecl
= ctx->get_backend ()->function (compiled_fn_type, fn_identifier,
asm_name, flags, function.get_locus ());
- ctx->insert_function_decl (fntype->get_ty_ref (), fndecl);
+ ctx->insert_function_decl (fntype->get_ty_ref (), fndecl, fntype);
// setup the params
TyTy::BaseType *tyret = fntype->get_return_type ();
@@ -247,17 +251,6 @@ public:
if (!compile_fns)
return;
- // items can be forward compiled which means we may not need to invoke this
- // code
- Bfunction *lookup = nullptr;
- if (ctx->lookup_function_decl (method.get_mappings ().get_hirid (),
- &lookup))
- {
- // has this been added to the list then it must be finished
- if (ctx->function_completed (lookup))
- return;
- }
-
TyTy::BaseType *fntype_tyty;
if (!ctx->get_tyctx ()->lookup_type (method.get_mappings ().get_hirid (),
&fntype_tyty))
@@ -267,28 +260,43 @@ public:
return;
}
- if (fntype_tyty->get_kind () != TyTy::TypeKind::FNDEF)
- {
- rust_error_at (method.get_locus (), "invalid TyTy for function item");
- return;
- }
-
+ rust_assert (fntype_tyty->get_kind () == TyTy::TypeKind::FNDEF);
TyTy::FnType *fntype = static_cast<TyTy::FnType *> (fntype_tyty);
if (fntype->has_subsititions_defined ())
{
- // we cant do anything for this only when it is used
+ // we cant do anything for this only when it is used and a concrete type
+ // is given
if (concrete == nullptr)
return;
else
{
rust_assert (concrete->get_kind () == TyTy::TypeKind::FNDEF);
fntype = static_cast<TyTy::FnType *> (concrete);
+ }
+ }
- // override the Hir Lookups for the substituions in this context
- fntype->override_context ();
+ // items can be forward compiled which means we may not need to invoke this
+ // code. We might also have already compiled this generic function as well.
+ Bfunction *lookup = nullptr;
+ if (ctx->lookup_function_decl (fntype->get_ty_ref (), &lookup, fntype))
+ {
+ // has this been added to the list then it must be finished
+ if (ctx->function_completed (lookup))
+ {
+ Bfunction *dummy = nullptr;
+ if (!ctx->lookup_function_decl (fntype->get_ty_ref (), &dummy))
+ ctx->insert_function_decl (fntype->get_ty_ref (), lookup, fntype);
+
+ return;
}
}
+ if (fntype->has_subsititions_defined ())
+ {
+ // override the Hir Lookups for the substituions in this context
+ fntype->override_context ();
+ }
+
// convert to the actual function type
::Btype *compiled_fn_type = TyTyResolveCompile::compile (ctx, fntype);
@@ -307,7 +315,7 @@ public:
Bfunction *fndecl
= ctx->get_backend ()->function (compiled_fn_type, fn_identifier,
asm_name, flags, method.get_locus ());
- ctx->insert_function_decl (fntype->get_ty_ref (), fndecl);
+ ctx->insert_function_decl (fntype->get_ty_ref (), fndecl, fntype);
// setup the params
TyTy::BaseType *tyret = fntype->get_return_type ();
diff --git a/gcc/rust/backend/rust-compile-item.h b/gcc/rust/backend/rust-compile-item.h
index 5a7d846..c3dc279 100644
--- a/gcc/rust/backend/rust-compile-item.h
+++ b/gcc/rust/backend/rust-compile-item.h
@@ -92,17 +92,6 @@ public:
if (!compile_fns)
return;
- // items can be forward compiled which means we may not need to invoke this
- // code
- Bfunction *lookup = nullptr;
- if (ctx->lookup_function_decl (function.get_mappings ().get_hirid (),
- &lookup))
- {
- // has this been added to the list then it must be finished
- if (ctx->function_completed (lookup))
- return;
- }
-
TyTy::BaseType *fntype_tyty;
if (!ctx->get_tyctx ()->lookup_type (function.get_mappings ().get_hirid (),
&fntype_tyty))
@@ -112,28 +101,43 @@ public:
return;
}
- if (fntype_tyty->get_kind () != TyTy::TypeKind::FNDEF)
- {
- rust_error_at (function.get_locus (), "invalid TyTy for function item");
- return;
- }
-
+ rust_assert (fntype_tyty->get_kind () == TyTy::TypeKind::FNDEF);
TyTy::FnType *fntype = static_cast<TyTy::FnType *> (fntype_tyty);
if (fntype->has_subsititions_defined ())
{
- // we cant do anything for this only when it is used
+ // we cant do anything for this only when it is used and a concrete type
+ // is given
if (concrete == nullptr)
return;
else
{
rust_assert (concrete->get_kind () == TyTy::TypeKind::FNDEF);
fntype = static_cast<TyTy::FnType *> (concrete);
+ }
+ }
- // override the Hir Lookups for the substituions in this context
- fntype->override_context ();
+ // items can be forward compiled which means we may not need to invoke this
+ // code. We might also have already compiled this generic function as well.
+ Bfunction *lookup = nullptr;
+ if (ctx->lookup_function_decl (fntype->get_ty_ref (), &lookup, fntype))
+ {
+ // has this been added to the list then it must be finished
+ if (ctx->function_completed (lookup))
+ {
+ Bfunction *dummy = nullptr;
+ if (!ctx->lookup_function_decl (fntype->get_ty_ref (), &dummy))
+ ctx->insert_function_decl (fntype->get_ty_ref (), lookup, fntype);
+
+ return;
}
}
+ if (fntype->has_subsititions_defined ())
+ {
+ // override the Hir Lookups for the substituions in this context
+ fntype->override_context ();
+ }
+
::Btype *compiled_fn_type = TyTyResolveCompile::compile (ctx, fntype);
unsigned int flags = 0;
@@ -155,7 +159,7 @@ public:
Bfunction *fndecl
= ctx->get_backend ()->function (compiled_fn_type, ir_symbol_name,
asm_name, flags, function.get_locus ());
- ctx->insert_function_decl (fntype->get_ty_ref (), fndecl);
+ ctx->insert_function_decl (fntype->get_ty_ref (), fndecl, fntype);
// setup the params
TyTy::BaseType *tyret = fntype->get_return_type ();