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

How to use a class to wrap or derive from a sizeless vector type #305

Open
sh1boot opened this issue Dec 23, 2023 · 4 comments
Open

How to use a class to wrap or derive from a sizeless vector type #305

sh1boot opened this issue Dec 23, 2023 · 4 comments

Comments

@sh1boot
Copy link

sh1boot commented Dec 23, 2023

Splitting out of my comment in #238.

Despite the fact that vector types are sizeless (unless you apply a type attribute (#176)), it's still useful to be able to abstract the types into something else, sharing the same limitations as the base vector type.

This would allow the addition of static data and utility functions which don't interfere with the sizeless property, and it would allow the type to be distinguished for function overloading (like Boost's strong typedef).

If it's really not possible to use a class, then I suppose an alternative would be the above 'strong typedef' concept as a type attribute; so it's at least possible to create the abstract type and then implement the utilities externally in template and function overloads.

I think in either case there's the problem of inheriting the ability to be passed to established intrinsic overloads without extra faff, while still being distinct types for new overloads.

This is not the first time I've had problems with attaching things to magic types. It's really a broader problem with the languages, but it would be nonsense to make a generic request for a language extension without reference to a specific problem case. So I'm starting here.

@sh1boot
Copy link
Author

sh1boot commented Dec 23, 2023

I guess the strong typedef concept has the advantage of working in C if used alongside _Generic().

@rofirrim
Copy link
Collaborator

Hi @sh1boot I think there are fundamental issues with wrapping sizeless types in structs ( see for instance #238 (comment) ) which I understand are beyond the scope of this specification.

While it may be possible to somehow wrap a buffer that allocates vlmax(sew, lmul) elements (e.g. using a trailing flexible member) most approaches typically impact the way one can use objects of these C++ classes (being able to use them by value seems unlikely as the C++ object model is a bit static in that sense).

With some elbow grease it is possible to write some reasonable wrapper, but one has to be mindful of unnecessary allocations as this is not that different to a std::vector<T>. See a simple example: https://www.godbolt.org/z/aKPzos5Ka

@jan-wassenberg
Copy link

Hi @sh1boot , FWIW Highway has parallel types: one for the vector, which may be a builtin, and one plain/empty C++ class used only to describe the vector type. The latter can be used for overloading. Would that help your use-case?

@sh1boot
Copy link
Author

sh1boot commented Nov 18, 2024

Hi @sh1boot I think there are fundamental issues with wrapping sizeless types in structs ( see for instance #238 (comment) ) which I understand are beyond the scope of this specification.

Well, I think the current RVV vector types demonstrate by their own existence how to answer each of these questions individually. You just forward all of the problems on to the derived class.

That is to say, given something like class Wrapper32 : vuint32m1_t { static const int bitwidth = 32; }; no new expectations are introduced, so there's nothing new to complain about.

Of course the trouble there is that the value of the type is stored at *this or *reinterpret_cast<vuint32m1_t*>(this), and while that pointer should optimise away it may still trigger problems. I think that's why people typically prefer to go to class Wrapper32 { vuint32m1_t value; static const int bitwidth = 32; };, to which you could apply the same constraints but that's a very peculiar special-case handling for structs with a single data member.

Alternatively enum class Wrapper32 : vuint32m1_t;, which is currently illegal because it's not an integral type, but if it were given a pass then it would at least achieve the "strong typedef" goal, which would allow proper overloading of function arguments.

With some elbow grease it is possible to write some reasonable wrapper, but one has to be mindful of unnecessary allocations as this is not that different to a std::vector<T>. See a simple example: https://www.godbolt.org/z/aKPzos5Ka

I think by the time you apply that much effort you might as well set intrinsics aside and lean right in to autovectorisation, though, right?

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

No branches or pull requests

3 participants