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

New Literals Utils #80

Merged
merged 16 commits into from
Jun 10, 2024
Merged

New Literals Utils #80

merged 16 commits into from
Jun 10, 2024

Conversation

jamierpond
Copy link
Collaborator

@jamierpond jamierpond commented Apr 16, 2024

moved this into a new PR for clarity. Literals can now be written like so:

static_assert(SWAR{Literals<32, u64>, {2, 1}}.value() == 0x00000002'00000001);
static_assert(SWAR{Literals<32, u64>, {1, 2}}.value() == 0x00000001'00000002);
static_assert(SWAR{Literals<16, u64>, {4, 3, 2, 1}}.value() == 0x0004'0003'0002'0001);
static_assert(SWAR{Literals<16, u64>, {1, 2, 3, 4}}.value() == 0x0001'0002'0003'0004);

template <int NBits, typename T> struct SWAR;

template <int NumBits, typename BaseType> struct Literals_t {
constexpr static void (SWAR<NumBits, BaseType>::*value)() = nullptr;
Copy link
Owner

Choose a reason for hiding this comment

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

This is not in use, remove

m_v = result;
}

constexpr static T MaxUnsignedLaneValue = ~(((~T{0}) << (NBits - 1)) << 1);
Copy link
Owner

Choose a reason for hiding this comment

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

I agree this constant is worth including, but not here, and not with this calculation. See there are a bunch of constants in SWAR, you may, for example, put it at the end of the list like this:

MaxUnsignedLaneValue = LeastSignificantLaneMask;

Comment on lines +36 to +40
static_assert(SWAR<16, u64>::MaxUnsignedLaneValue == 65535);
static_assert(SWAR<16, u32>::MaxUnsignedLaneValue == 65535);
static_assert(SWAR<8, u32>::MaxUnsignedLaneValue == 255);
static_assert(SWAR<4, u32>::MaxUnsignedLaneValue == 15);
static_assert(SWAR<2, u32>::MaxUnsignedLaneValue == 3);
Copy link
Owner

Choose a reason for hiding this comment

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

Decimal is not the natural base for these tests.
I know we ahve a mess of decimals and hex and binary in these tests, but let's stop the mess.
You may create an assign a PR to me to clean this up if you're upset about this request.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I understand why we might want to have just one format, decimal makes the repo a little more approachable and understandable.

test/swar/BasicOperations.cpp Outdated Show resolved Hide resolved
test/swar/BasicOperations.cpp Outdated Show resolved Hide resolved
test/swar/BasicOperations.cpp Outdated Show resolved Hide resolved
test/swar/BasicOperations.cpp Outdated Show resolved Hide resolved
inc/zoo/swar/SWAR.h Outdated Show resolved Hide resolved
Comment on lines 84 to 93
template <typename U, typename ManipulationFn>
constexpr auto loadBaseTypeIntoLanes(const U (&values)[Lanes],
const ManipulationFn&& manipulation) {
auto result = T{0};
for (auto value : values) {
auto laneValue = manipulation(value);
result = (result << NBits) | laneValue;
}
return result;
}
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

not 100% sure about the names for manipulation etc right now but would be good to get your opinion on this approach.

Copy link
Owner

Choose a reason for hiding this comment

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

This might be a reasonable way to do this, but I'd use the appropriate algorithm in #include <algorithm> and I would not take by const-r-value reference something that ought to be a pure forwarding reference, meaning ManipulationFN &&
Make sure you never put const-r-value, either const-l-value when strictly necessary, or forwarding reference whenever possible.

inc/zoo/swar/SWAR.h Outdated Show resolved Hide resolved
inc/zoo/swar/SWAR.h Outdated Show resolved Hide resolved
inc/zoo/swar/SWAR.h Outdated Show resolved Hide resolved
inc/zoo/swar/SWAR.h Outdated Show resolved Hide resolved
Copy link
Owner

@thecppzoo thecppzoo left a comment

Choose a reason for hiding this comment

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

Improvements all around, but, like in the movie "Whiplash", still not quite my tempo.

Since you have given us the construction from literals, perhaps it is a good idea to do the opposite of having a conversion operator to array of values,
constexpr operator std::array<T, Lanes>();
and a named conversion to_array

}
template <std::size_t N>
constexpr BooleanSWAR(Literals_t<NBits, T>, const bool (&values)[N])
: Base(Literals<NBits, T>, values) { this->m_v << (NBits - 1); }
Copy link
Owner

Choose a reason for hiding this comment

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

My typo in the comment, this has no effect, change to <<=

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

great, works perfectly.

@jamierpond
Copy link
Collaborator Author

Improvements all around, but, like in the movie "Whiplash", still not quite my tempo.
Loving the feedback. Thank you!
Since you have given us the construction from literals, perhaps it is a good idea to do the opposite of having a conversion operator to array of values, constexpr operator std::array<T, Lanes>(); and a named conversion to_array
I like the idea of this, will check it out.

}
return result;
}

template <typename Arg, std::size_t N, typename = std::enable_if_t<N == Lanes, int>>
constexpr
SWAR(Literals_t<NBits, T>, const Arg (&values)[N])
: m_v{loadIntoLanes(values, [](auto x) { return x; })} {}
: m_v{loadIntoLanes(values)} {}
Copy link
Owner

Choose a reason for hiding this comment

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

May you please indent to multiples of four spaces?

Copy link
Owner

@thecppzoo thecppzoo left a comment

Choose a reason for hiding this comment

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

You're free to merge yourself after you're satisfied

Comment on lines 66 to 65
constexpr static auto calculateLeastSignificantLaneMask() {
const auto m =
sizeof(T) * 8 == NBits ? // needed to avoid shifting all bits
~T(0) :
~(~T(0) << NBits);
return m;
}
constexpr static inline type
Copy link
Owner

Choose a reason for hiding this comment

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

Nah...
This calculation does not deserve a name.
I think since C++17 we can use constexpr lambdas, that would be more appropriate below.
However, I showed you that this calculation is not needed, you're repating, and that's the bad part, the bulk of the work done in other constants.
Better than repeating the work is to use the work already done, primarily because then you have cross-checking that things work, if there's a mistake in the old, the new might discover it, if further nuance is discovered the new might benefit from it directly.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Thanks, should have reverted. This was a debugging attempt. Was getting a red herring compiler message about this variable not being constexpr when trying to implement to_array.

Copy link
Owner

@thecppzoo thecppzoo left a comment

Choose a reason for hiding this comment

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

The latest changes made the PR not mergeable anymore, please review

Comment on lines 102 to 96
constexpr std::array<T, Lanes> to_array() const noexcept {
std::array<T, Lanes> result;
for (int i = 0; i < Lanes; ++i) {
auto otherEnd = Lanes - i - 1;
result[otherEnd] = at(i);
}
return result;
}

Copy link
Owner

Choose a reason for hiding this comment

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

This endianness conversion bothers me.
Your code is correct, but there is something about endianness that is creeping up that is bothering me.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yeah I agree there is something to figure out here. I think you would agree that the to_array should produce arrays with the same endianness as the input like this:

static_assert(SWAR{Literals<4, u8>, {1, 2}}.to_array() == std::array<u8, 2>{1, 2});

Not sure the best thing to suggest here.

Copy link
Owner

Choose a reason for hiding this comment

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

Your code is correct. Furthermore, your choice to adopt big endianness for arrays was superior to the alternative, but now we have this flipping of endianness that I don't know what to do about; I'm just voicing the idea, and plan to keep it in the back of my head to see where we go with this.

@@ -81,7 +81,7 @@ if(MSVC)
endif()
else()
# Non-MSVC specific configuration (original content)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD 23)
Copy link
Owner

Choose a reason for hiding this comment

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

Support for compilation under MSVC is on a "best effort" basis, we try, but we can't guarantee we will succeed at all the things. It is acceptable to bump to 23, but please explain why you found the need

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This is for the non-MSVC path. This is to enable support for std::array in a constexpr context.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Reverted, we should address in another PR. This one is already hard to keep track of.

@jamierpond
Copy link
Collaborator Author

@thecppzoo maybe best to merge where we were happy and add the to_array in a seperate PR if we think that is interesting?

add to_array

oops make 23 for now

not sure we want to commit to this?

remove named function

Revert "Add to Array"

This reverts commit a7d744d.
MaxUnsignedLaneValue = LeastSignificantLaneMask;

template <typename U>
constexpr auto loadIntoLanes(const U (&values)[Lanes]) const noexcept {
Copy link
Owner

@thecppzoo thecppzoo Apr 19, 2024

Choose a reason for hiding this comment

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

Please rename to from_array. As the symmetrical operation to to_array.
Also, this is a factory, it ought to be static, a class-function, not instance.
Actually, we also need a constructor from std::array.

Apologies for all of the creep, I just think there is a lot of extra value by making SWAR a really ergonomic type as opposed to somewhat ergonomic.

I dislike that C++ forces you to do a lot of boilerplate, I've never figured out how to make tools to eliminate the work to do the boilerplate.

@thecppzoo
Copy link
Owner

My preference with this PR is to not just introduce the support for direct initialization of literals, but complete it with the following:

  1. Making the essential function from_array a part of the public interface (we ought to indicate the semantics is that of big endianness in the comments inline with the code), as a class-function, because it is a factory.
  2. Keep the Literals infrastructure you already made, extend with a constructor from std::array
  3. to_array

Separately, I think we can also add a header, such as SWAR_IO.h where the insertion and extraction operators are implemented. I don't think these things are unrelated: The ergonomics of the literals are highly cohesive with stream insertion and extraction. We need this "yesterday" for debugging and tracing.

Indicate if you'd like to split these features with me or prefer to do them all yourself.

@jamierpond
Copy link
Collaborator Author

jamierpond commented Apr 20, 2024

If you want to take on the std::array stuff and getting that to that could be nice.

From what I understood from playing around with this today we will require C++ >17 in order to use constexpr std::array in static_assert tests, but this may be a limitation of my understanding.

Even with C++23 am seeing failures to compiler on g++.

constexpr static auto from_array(const U (&values)[Lanes]) noexcept {
auto result = T{0};
for (auto value : values) {
result = (result << NBits) | value;
Copy link
Collaborator

Choose a reason for hiding this comment

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

blitElement?

Copy link
Owner

Choose a reason for hiding this comment

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

I this does not quite blit the element, if it will move in an element, it shifts up what it got and then adds to the least significant lane

@Scottbruceheart Scottbruceheart merged commit 0e2a15b into master Jun 10, 2024
2 checks passed
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.

None yet

3 participants