-
Notifications
You must be signed in to change notification settings - Fork 5.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add a monomorphization cache to the declaration engine. #2637
Conversation
9725feb
to
7209d08
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would rather get this now because it introduces new cache-aware APIs, the following PRs for those issues will depend on these APIs anyway and will build on top of this PR. I think your concerns around the stability of this makes sense though, so I've disabled the cache by default and we can enable it by default at a later stage. |
Good plan 👍 |
1c4f378
to
248ab50
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We need to think a little bit longer about how to achieve optimal results with the cache I think, could you iterate on the design another time?
.cloned() | ||
{ | ||
let monomorphized_fn_decl = copy.expect_function(&Span::dummy()).unwrap(); | ||
if &monomorphized_fn_decl.type_parameters == type_arguments { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that we may need to think more deeply about the logic of this line. In general, most generic functions are called without type arguments, so most of the time this check will fail, missing valid cache opportunities.
2a59131
to
e8b9e2a
Compare
@@ -7,7 +7,7 @@ mod resolved_type; | |||
mod trait_constraint; | |||
mod type_argument; | |||
mod type_binding; | |||
mod type_engine; | |||
pub(crate) mod type_engine; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@emilyaherbert This is needed for the following error:
error[E0603]: module `type_engine` is private
--> sway-core/src/declaration_engine/declaration_engine.rs:14:19
|
14 | type_system::{type_engine::monomorphize, EnforceTypeArguments},
| ^^^^^^^^^^^ private module
|
note: the module `type_engine` is defined here
--> sway-core/src/type_system/mod.rs:10:1
|
10 | mod type_engine;
| ^^^^^^^^^^^^^^^
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of changing the visibility of the module, change the import statement to match this example:
insert_type, monomorphize, unify_with_self, CopyTypes, EnforceTypeArguments, |
This introduces a cache to the declaration engine that keeps track of functions/structs that have been instantiated from a specific set of type parameters. This was originally prototyped in tritao/declaration-engine-and-collection-context-demo@c3aa5e7, where these APIs where wired to the function application and struct expressions instantiation code. However given the declaration engine is not hooked up yet here, this PR is just adding the APIs, and more proper testing will be added as we wire things up. Closes FuelLabs#2636.
e8b9e2a
to
44bd2c5
Compare
Updated the PR with a more generic design, threaded some more error results throughout, added enum declarations to @emilyaherbert I'm leaving the future improvements (caching generics called without type parameters) to a future issue (opening one), as right now this is blocking 2 other PRs and that can only be tested properly once the declarations are hooked to the engine anyway. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Adding the monomorphization cache is not a blocker for adding the declaration engine, and the cache-aware API is similar enough to the non-cache-aware API that switching API functions would only be a small change. Considering we are not able to test the code in the cache until the declaration engine goes in, I recommend that we merge #2631 and #2635 in before we add the cache. Would you close this PR? I recommend keeping this branch alive though so that we can bring it back when we are ready to add the cache again.
.iter() | ||
.cloned() | ||
{ | ||
if monomorphized_decl.type_parameters() == type_arguments { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This line will cause the cache to fail in some cases (e.g. nested generic function calls).
For example this:
fn foo<T, F>(a: T, b: F) -> F {
b
}
fn bar<T, F>(a: T, b: F) -> F {
foo::<T, F>(a, b)
}
would generate a false cache hit due to the implementation of PartialEq
on TypeInfo::UnknownGeneric
:
sway/sway-core/src/type_system/type_info.rs
Line 205 in a989e6c
(Self::UnknownGeneric { name: l }, Self::UnknownGeneric { name: r }) => l == r, |
} | ||
|
||
fn de_get_monomorphized_struct_copies( | ||
pub(crate) fn de_get_or_create_monomorphized_decl<T>( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove the pub(crate)
@@ -17,6 +17,7 @@ use crate::{ | |||
pub(crate) enum DeclarationWrapper { | |||
// no-op variant to fulfill the default trait | |||
Unknown, | |||
Enum(TypedEnumDeclaration), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is already a PR for adding enum support: #2713. Please remove these additions on this PR.
| DeclarationWrapper::TraitImpl(_) | ||
| DeclarationWrapper::Storage(_) | ||
| DeclarationWrapper::Unknown => { | ||
panic!("declaration type does not support type parameters") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In general, we should not use panic!
(unwrap!
, etc), unless absolutely necessary. The compiler is designed so that if there is an error when type checking one AST nodes, the other AST nodes are relatively unaffected and can continue to be type checked, providing the best end-user experience. panic!
generates an early exit, preventing the compiler from offering this feature to users. This is why we have the heafty CompileResult
struct. In this particular case, remove this panic
and I recommend that you return an empty vec instead.
} | ||
|
||
fn to_wrapper(&self) -> DeclarationWrapper { | ||
panic!("not expected to be called for DeclarationWrapper") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove the panic!
monomorphized_copies | ||
.entry(*original_id) | ||
.and_modify(|f| f.push(new_id.clone())) | ||
.or_insert_with(|| vec![new_id.clone()]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Suggests that smallvec
might be an improvement here... i.e. there tends to be a single monomorphized copy? Hard to know without a benchmark of course...
Closing this for now |
This introduces a cache to the declaration engine that keeps track of functions/structs that have been instantiated from a specific set of type parameters.
The approach here is relatively simple and relies on a linear search. I originally thought about having more maps to speed it up by keying on the type arguments, but since it adds a bit of complexity I opted for this for now. If it proves to be a bottleneck in the future we can always speed it up.
This was prototyped in tritao/declaration-engine-and-collection-context-demo@c3aa5e7, where these APIs where wired to the function application and struct expressions instantiation code.
However given the declaration engine is not hooked up yet here, this PR is just adding the APIs, and more proper testing will be added as we wire things up.
Closes #2636.