Adding ModF tests to HLK Long Vector unittests#7859
Conversation
| static std::vector<TYPE> buildExpected(Op<OpType::OPERATION, TYPE, 1>, \ | ||
| const InputSets<TYPE> &Inputs) { \ | ||
| DXASSERT_NOMSG(Inputs.size() == 1); \ | ||
| size_t VectorSize = Inputs[0].size(); \ |
There was a problem hiding this comment.
nit:
| size_t VectorSize = Inputs[0].size(); \ | |
| const size_t VectorSize = Inputs[0].size(); \ |
| #include "LongVectorOps.def" | ||
| }; | ||
|
|
||
| #define OP_WITH_OUT_PARAM(OPERATION, TYPE, IMPL) \ |
There was a problem hiding this comment.
| #define OP_WITH_OUT_PARAM(OPERATION, TYPE, IMPL) \ | |
| #define OP_WITH_OUT_PARAM_=(OPERATION, TYPE, IMPL) \ |
Given that we're restricting this to unary ops I think we can clarify that by appending the 1 in the name like some of the other macros do
| #include "LongVectorOps.def" | ||
| }; | ||
|
|
||
| #define OP_WITH_OUT_PARAM(OPERATION, TYPE, IMPL) \ |
There was a problem hiding this comment.
I also think it would be better to put this macro with the other similar class of macro definitions around line 625.
The #define OP_1" etc
| // can leverage the existing logic which verify expected values in a | ||
| // single vector. We just need to make sure that we organize the output in | ||
| // the same way in the shader and when we read it back. | ||
| OP_WITH_OUT_PARAM_1(Frexp, float, { |
There was a problem hiding this comment.
nit: You should update OP_WITH_OUT_PARAM_1 to take the fully qualified name 'OpType::Frexp'. That way we match the pattern of the other macros.
| #define DEFAULT_OP_2(OP, IMPL) OP_2(OP, DefaultValidation<T>, IMPL) | ||
| #define DEFAULT_OP_3(OP, IMPL) OP_3(OP, DefaultValidation<T>, IMPL) | ||
|
|
||
| #define OP_WITH_OUT_PARAM_1(OPERATION, TYPE, IMPL) \ |
There was a problem hiding this comment.
nit: Change 'OPEARTION' to 'OP' to match the pattern of the other macros.
damyanp
left a comment
There was a problem hiding this comment.
I'm afraid I think that some more time needs to be taken to find a better abstraction for this that doesn't involve so much preprocessor work.
| #define DEFAULT_OP_2(OP, IMPL) OP_2(OP, DefaultValidation<T>, IMPL) | ||
| #define DEFAULT_OP_3(OP, IMPL) OP_3(OP, DefaultValidation<T>, IMPL) | ||
|
|
||
| #define OP_WITH_OUT_PARAM_1(OP, TYPE, IMPL) \ |
There was a problem hiding this comment.
Putting this much code inside a macro definition makes me uneasy - especially once we start putting blocks of code in the IMPL parameter.
I think it might be worth spending some time trying to find ways to have this be written more in C++ than in the preprocessor.
| Expected.resize(VectorSize * 2); \ | ||
| for (size_t I = 0; I < VectorSize; ++I) { \ | ||
| IMPL \ |
There was a problem hiding this comment.
So....there's some kind of extra contract that I think IMPL must know to write two values to Expected, based on I and VectorSize?
As with previous comment, this is something we should be able to make more clear and obvious in the code structure, that doesn't rely on preprocessor substitutions to make it work.
| ValidationConfig.Type, VerboseLogging)); | ||
| } | ||
|
|
||
| template <typename IN_TYPE, typename OUT_TYPE> |
There was a problem hiding this comment.
You could simplify this to just use <typename T>
No need to have an in/out type. Not being used.
| } | ||
|
|
||
| template <typename IN_TYPE, typename OUT_TYPE> | ||
| static std::vector<OUT_TYPE> TransformVector_1( |
There was a problem hiding this comment.
I think it would improve readability to move this to be defined and declared right above the macro where its used.
| } | ||
|
|
||
| template <typename IN_TYPE, typename OUT_TYPE> | ||
| static std::vector<OUT_TYPE> TransformVector_1( |
There was a problem hiding this comment.
nit: I don't think 'TransformVector' is the best name.
I'm wondering if something like 'buildExpectedWithOutParam' or something similar. To better convey what its supposed to do. 'TransformVector' just feels a little too generic to me.
There was a problem hiding this comment.
TransformVector strongly implies to me that we're applying a transformation matrix to a vector.
|
|
||
| template <typename T> struct Op<OpType::ModF, T, 1> : DefaultValidation<T> {}; | ||
|
|
||
| template <typename T> T TransformModF(const T &Input, T &OutParam); |
There was a problem hiding this comment.
You could just call this modf. There is no 'Transform' part happening in here.
| // So it can conversion between float and int is safe. | ||
| Expected[I + VectorSize] = static_cast<float>(Exp); | ||
| } | ||
| float TransformFRexp(const float &Input, float &OutParam) { |
There was a problem hiding this comment.
You can just call this 'frexp'. No 'Transform' needed.
And functions should start with lowercase.
|
|
||
| template <typename IN_TYPE, typename OUT_TYPE> | ||
| static std::vector<OUT_TYPE> TransformVector_1( | ||
| const InputSets<IN_TYPE> &Inputs, |
There was a problem hiding this comment.
I also think it would be good to add a short comment to this helper just explaining that the store the output parameters in the second half of the output buffer to keep things simple as the significant majority of our tests only need one output buffer. So, we stick with that pattern.
damyanp
left a comment
There was a problem hiding this comment.
Looking through all this, I'm wondering why we don't just follow the same pattern that's used for AsUint_SplitDouble? This is another one-off that has a multiple return values.
Just doing this as a special case saves us from trying to find a way to write this generically, which seems unnecessary since I think that this is the only operation we're dealing with that has one out param like this?
| template <typename IN_TYPE, typename OUT_TYPE> | ||
| static std::vector<OUT_TYPE> TransformVector_1( | ||
| const InputSets<IN_TYPE> &Inputs, | ||
| function<OUT_TYPE(const IN_TYPE &, OUT_TYPE &)> TransformFunc) { |
There was a problem hiding this comment.
Ugh - somewhere there's a using namespace std that shouldn't be there. This should be qualified with std::function - although I'm going to ask that you don't use std::function so this is somewhat moot.
| } | ||
|
|
||
| template <typename IN_TYPE, typename OUT_TYPE> | ||
| static std::vector<OUT_TYPE> TransformVector_1( |
There was a problem hiding this comment.
TransformVector strongly implies to me that we're applying a transformation matrix to a vector.
| template <typename IN_TYPE, typename OUT_TYPE> | ||
| static std::vector<OUT_TYPE> TransformVector_1( | ||
| const InputSets<IN_TYPE> &Inputs, | ||
| function<OUT_TYPE(const IN_TYPE &, OUT_TYPE &)> TransformFunc) { |
There was a problem hiding this comment.
We shouldn't be using std::function here - you'll notice that it's not used for any of the existing opcodes. A goal here has been to have all of this resolved at compile time, while std::function requires dynamic dispatch.
| float Exp = 0.0f; | ||
| float Man = std::modf(float(Input), &Exp); |
There was a problem hiding this comment.
nit: gonna suggest this before Alex gets a chance to:
| float Exp = 0.0f; | |
| float Man = std::modf(float(Input), &Exp); | |
| float Exp = 0.0f; | |
| const float Man = std::modf(float(Input), &Exp); |
This pr is adding ModF into HLK long vector unittest. It also introduces
OP_WITH_OUT_PARAM, to help creating test for intrinsics that require of params. This was inspired by Frexp original test, so this also refactors the test to use the macro as well.Closes: #7851