Skip to content
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

Functional: Index fields C++ backend support #1130

Closed
wants to merge 8 commits into from
Closed

Functional: Index fields C++ backend support #1130

wants to merge 8 commits into from

Conversation

petiaccja
Copy link
Contributor

Adds index fields as a distinct argument type for the C++ binding generator. The binding generator generates the correct C++ code that passes gridtools::stencil::positional iterators to the GTFN C++ program code.

@petiaccja petiaccja marked this pull request as ready for review January 20, 2023 10:18
Copy link
Contributor

@DropD DropD left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

only minor problems with applying the new import style.

src/functional/ffront/decorator.py Show resolved Hide resolved
@@ -19,6 +19,7 @@

import numpy as np

import functional.otf.binding.type_specifications as ts
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am all for using the same abbreviations for the same module. This however is using an established abbreviation for a different module (even though that module re-imports a lot of the usual one).

Note, once we accept that we shouldn't try to get away with using the same abbreviation for different modules, the reason for re-importing inside the local type_specifications module goes away.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, the idea was that the derived modules are a strict superset of the original type_system.* modules, and in that case you can just simply import the extended module.
Sounds like it would be kinda nice to use, but to be honest it might be better as you suggest. Re-importing all the stuff is ugly and error-prone, and then not knowing which flavour of the module you are using at the moment is also a problem. Plus, it's really nasty if you want to use two extended modules at the same time.

Anyways, I think this is out of the scope of this PR, but we can change it in a follow-up PR.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree we should not use the same alias for different modules. I think it would be good enough for this PR to just change the alias to a similar but different one. For example:

import functional.otf.binding.type_specifications as bts

Comment on lines 5 to 18
from functional.type_system.type_specifications import ( # noqa: F401
CallableType as CallableType,
DataType as DataType,
DeferredType as DeferredType,
DimensionType as DimensionType,
FieldType as FieldType,
FunctionType as FunctionType,
OffsetType as OffsetType,
ScalarKind as ScalarKind,
ScalarType as ScalarType,
TupleType as TupleType,
TypeSpec as TypeSpec,
VoidType as VoidType,
)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we don't import this module elsewhere as ts, which should be reserved for functional.type_system.type_specifications, then there is no reason for re-importing these classes.

The whole reason for the import <module> [as <name>] style over import <member> from <module> is to be able to track (without IDE help) what is coming from where. Why go out of our way to negate that advantage?

Copy link
Contributor

@egparedes egparedes Jan 25, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also agree with @DropD here. I think it would be better if users of the type specs add the original ts module plus additional imports from extension modules to bring new types in scope, instead of trying to expand the original type_specifications module (which makes basically impossible to compose type extensions from different modules):

# This allows using extensions from different modules very easily
import functional.type_system.type_specifications as ts
import functional.otf.binding.type_specifications as bts

@@ -18,22 +18,37 @@

import numpy as np

import functional.otf.binding.type_specifications as ts
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ts name should be reserved for functional.type_system.type_specifications

Copy link
Contributor

@egparedes egparedes left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall, it looks good to me. I left a few comments and suggestions to improve the PR.

else:
raise ValueError("unsupported scalar type")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
raise ValueError("unsupported scalar type")
raise ValueError(f"Unsupported '{scalar_type}' scalar type.")

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't invest too much into exceptions because I want to clean the whole thing up next cycle. Anyways, you have a point that even clean-up is easier if the messages are better to begin with, so I added some better messages.

return f"BufferT{index}&& {param.name}"
else:
raise ValueError("unsupported type for parameters")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
raise ValueError("unsupported type for parameters")
raise ValueError(f"Unsupported '{param.type_}' type for parameters.")

else:
type_str = cpp_interface.render_python_type(param.dtype.type)
return type_str + " " + param.name
raise ValueError("Invalid type.")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
raise ValueError("Invalid type.")
raise ValueError(f"Invalid type in '{param}' parameter.")

Comment on lines 31 to 33
# TODO: make type_translation extendable and specialize it for the
# bindings to distinguish between buffer-backed fields and index
# fields.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I now understand that the comment about making type_translation extendable is related to use a different mechanism for the pattern matching part with the actual type, and not with the preliminary handling of the messy implementation details of python typing annotations. It makes sense, but still don't see it as a high priority for now.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wrote a new from_value function that tries to match for IndexFieldType and if it fails it delegates it to the original functional.type_system.from_value function.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd like to use a registry that allows you to register a match functor for every type of the type_system, then you can extend without raising the cyclomatic complexity through all these if statements and you can also simply chain the list of matchers to combine modules.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That would also replace the __gt_type__ solution which is an intrusive implementation because it forces objects to be aware of the type system.

Comment on lines 34 to 37
if isinstance(obj, IndexField):
dtype = type_translation.from_type_hint(obj.dtype.type)
assert isinstance(dtype, ts.ScalarType)
return interface.Parameter(name, ts.IndexFieldType(axis=obj.axis, dtype=dtype))
Copy link
Contributor

@egparedes egparedes Jan 25, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that, for consistency, this piece of code should be moved into type_translation.from_value(), since the similar handling of embedded.LocatedField is also implemented there. Additionally, it's easier to refactor the type translation code in the future if it is not spread across different functions.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I moved it to a new function from_value under functional.otf.binding.type_translation. It shouldn't be moved into the main type_translation module because IndexFieldType is not present there.

Copy link
Contributor

@tehrengruber tehrengruber left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just adding the partial review I already started.

param: interface.ScalarParameter | interface.BufferParameter, index: int
) -> str:
if isinstance(param, interface.ScalarParameter):
return f"{render_python_type(param.scalar_type.type)} {param.name}"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The render_python_type function and _TYPE_MAPPING dict is now dead code and should be removed right?

@petiaccja petiaccja closed this Jan 31, 2023
havogt added a commit that referenced this pull request Mar 27, 2023
Extracted from #1130 and married with Connectivities.

Co-authored-by: Enrique G. Paredes <18477+egparedes@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants