Skip to content

Conversation

@joaosaffran
Copy link
Collaborator

@joaosaffran joaosaffran commented Oct 30, 2025

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

@joaosaffran joaosaffran requested a review from alsepkow October 30, 2025 18:40
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(); \
Copy link
Contributor

Choose a reason for hiding this comment

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

nit:

Suggested change
size_t VectorSize = Inputs[0].size(); \
const size_t VectorSize = Inputs[0].size(); \

#include "LongVectorOps.def"
};

#define OP_WITH_OUT_PARAM(OPERATION, TYPE, IMPL) \
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
#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) \
Copy link
Contributor

Choose a reason for hiding this comment

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

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

@joaosaffran joaosaffran requested a review from alsepkow November 3, 2025 18:53
// 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, {
Copy link
Contributor

Choose a reason for hiding this comment

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

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) \
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: Change 'OPEARTION' to 'OP' to match the pattern of the other macros.

@joaosaffran joaosaffran requested a review from alsepkow November 3, 2025 20:53
Copy link
Contributor

@alsepkow alsepkow left a comment

Choose a reason for hiding this comment

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

LGTM

@damyanp damyanp self-assigned this Nov 4, 2025
Copy link
Member

@damyanp damyanp left a comment

Choose a reason for hiding this comment

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

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) \
Copy link
Member

Choose a reason for hiding this comment

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

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.

Comment on lines 638 to 640
Expected.resize(VectorSize * 2); \
for (size_t I = 0; I < VectorSize; ++I) { \
IMPL \
Copy link
Member

Choose a reason for hiding this comment

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

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.

@github-project-automation github-project-automation bot moved this from New to In progress in HLSL Roadmap Nov 4, 2025
ValidationConfig.Type, VerboseLogging));
}

template <typename IN_TYPE, typename OUT_TYPE>
Copy link
Contributor

@alsepkow alsepkow Nov 7, 2025

Choose a reason for hiding this comment

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

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(
Copy link
Contributor

Choose a reason for hiding this comment

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

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(
Copy link
Contributor

Choose a reason for hiding this comment

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

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.

Copy link
Member

Choose a reason for hiding this comment

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

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);
Copy link
Contributor

@alsepkow alsepkow Nov 7, 2025

Choose a reason for hiding this comment

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

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) {
Copy link
Contributor

Choose a reason for hiding this comment

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

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,
Copy link
Contributor

Choose a reason for hiding this comment

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

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.

Copy link
Member

@damyanp damyanp left a comment

Choose a reason for hiding this comment

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

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) {
Copy link
Member

Choose a reason for hiding this comment

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

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(
Copy link
Member

Choose a reason for hiding this comment

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

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) {
Copy link
Member

Choose a reason for hiding this comment

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

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.

Comment on lines +1248 to +1249
float Exp = 0.0f;
float Man = std::modf(float(Input), &Exp);
Copy link
Member

@damyanp damyanp Nov 7, 2025

Choose a reason for hiding this comment

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

nit: gonna suggest this before Alex gets a chance to:

Suggested change
float Exp = 0.0f;
float Man = std::modf(float(Input), &Exp);
float Exp = 0.0f;
const float Man = std::modf(float(Input), &Exp);

Copy link
Contributor

@alsepkow alsepkow left a comment

Choose a reason for hiding this comment

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

lgtm

@joaosaffran joaosaffran merged commit 201a5b5 into microsoft:main Nov 12, 2025
12 checks passed
@github-project-automation github-project-automation bot moved this from In progress to Done in HLSL Roadmap Nov 12, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

Implement test for modf

4 participants