Skip to content
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions tools/clang/unittests/HLSLExec/LongVectorOps.def
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ OP_DEFAULT_DEFINES(UnaryMath, Frexp, 1, "TestFrexp", "", " -DFUNC_FREXP=1")
OP_DEFAULT(FloatSpecial, IsFinite, 1, "isfinite", "")
OP_DEFAULT(FloatSpecial, IsInf, 1, "isinf", "")
OP_DEFAULT(FloatSpecial, IsNan, 1, "isnan", "")
OP_DEFAULT_DEFINES(FloatSpecial, ModF, 1, "TestModF", "", " -DFUNC_TEST_MODF=1")

OP_DEFAULT(BinaryComparison, LessThan, 2, "", "<")
OP_DEFAULT(BinaryComparison, LessEqual, 2, "", "<=")
Expand Down
78 changes: 46 additions & 32 deletions tools/clang/unittests/HLSLExec/LongVectors.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -628,6 +628,21 @@ struct StrictValidation {
#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.

template <> struct ExpectedBuilder<OpType::OPERATION, TYPE> { \
static std::vector<TYPE> buildExpected(Op<OpType::OPERATION, TYPE, 1>, \
const InputSets<TYPE> &Inputs) { \
DXASSERT_NOMSG(Inputs.size() == 1); \
const size_t VectorSize = Inputs[0].size(); \
std::vector<TYPE> Expected; \
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.

} \
return Expected; \
} \
};

//
// TernaryMath
//
Expand Down Expand Up @@ -1015,41 +1030,21 @@ DEFAULT_OP_1(OpType::Log2, (std::log2(A)));
// with special logic. Frexp is only supported for fp32 values.
template <> struct Op<OpType::Frexp, float, 1> : DefaultValidation<float> {};

template <> struct ExpectedBuilder<OpType::Frexp, float> {
static std::vector<float> buildExpected(Op<OpType::Frexp, float, 1> &,
const InputSets<float> &Inputs) {
DXASSERT_NOMSG(Inputs.size() == 1);

// Expected values size is doubled. In the first half we store the
// Mantissas and in the second half we store the Exponents. This way we
// 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.

int Exp = 0;
float Man = std::frexp(Inputs[0][I], &Exp);

size_t VectorSize = Inputs[0].size();

std::vector<float> Expected;
Expected.resize(VectorSize * 2);

for (size_t I = 0; I < VectorSize; ++I) {
int Exp = 0;
float Man = std::frexp(Inputs[0][I], &Exp);
// std::frexp returns a signed mantissa. But the HLSL implmentation
// returns an unsigned mantissa.
Man = std::abs(Man);

// std::frexp returns a signed mantissa. But the HLSL implmentation
// returns an unsigned mantissa.
Man = std::abs(Man);
Expected[I] = Man;

Expected[I] = Man;

// std::frexp returns the exponent as an int, but HLSL stores it as a
// float. However, the HLSL exponents fractional component is always 0.
// So it can conversion between float and int is safe.
Expected[I + VectorSize] = static_cast<float>(Exp);
}

return Expected;
}
};
// std::frexp returns the exponent as an int, but HLSL stores it as a
// float. However, the HLSL exponents fractional component is always 0.
// So it can conversion between float and int is safe.
Expected[I + VectorSize] = static_cast<float>(Exp);
});

//
// Binary Comparison
Expand Down Expand Up @@ -1236,6 +1231,23 @@ FLOAT_SPECIAL_OP(OpType::IsInf, (std::isinf(A)));
FLOAT_SPECIAL_OP(OpType::IsNan, (std::isnan(A)));
#undef FLOAT_SPECIAL_OP

template <typename T> struct Op<OpType::ModF, T, 1> : DefaultValidation<T> {};

OP_WITH_OUT_PARAM_1(ModF, float, {
float Exp = 0.0f;
float Man = std::modf(Inputs[0][I], &Exp);
Expected[I] = Man;
Expected[I + VectorSize] = Exp;
});

OP_WITH_OUT_PARAM_1(ModF, HLSLHalf_t, {
float Exp = 0.0f;
float Inp = float(Inputs[0][I]);
float Man = std::modf(Inp, &Exp);
Expected[I] = HLSLHalf_t(Man);
Expected[I + VectorSize] = HLSLHalf_t(Exp);
});

//
// dispatchTest
//
Expand Down Expand Up @@ -1772,10 +1784,12 @@ class DxilConf_SM69_Vectorized {
HLK_TEST(IsFinite, HLSLHalf_t);
HLK_TEST(IsInf, HLSLHalf_t);
HLK_TEST(IsNan, HLSLHalf_t);
HLK_TEST(ModF, HLSLHalf_t);

HLK_TEST(IsFinite, float);
HLK_TEST(IsInf, float);
HLK_TEST(IsNan, float);
HLK_TEST(ModF, float);

// Binary Comparison

Expand Down
14 changes: 14 additions & 0 deletions tools/clang/unittests/HLSLExec/ShaderOpArith.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4112,6 +4112,20 @@ void MSMain(uint GID : SV_GroupIndex,
}
#endif

#ifdef FUNC_TEST_MODF
vector<OUT_TYPE, NUM> TestModF(vector<TYPE, NUM> Vector)
{
vector<OUT_TYPE, NUM> Mantissa;
vector<OUT_TYPE, NUM> Exponent;

Mantissa = modf(Vector, Exponent);

g_OutputVector.Store< vector<OUT_TYPE, NUM> >(sizeof(OUT_TYPE) * NUM, Exponent);

return Mantissa;
}
#endif

#ifdef FUNC_SHUFFLE_VECTOR
vector<OUT_TYPE, NUM> TestShuffleVector(TYPE Scalar)
{
Expand Down