diff --git a/tools/clang/unittests/HLSLExec/LongVectorOps.def b/tools/clang/unittests/HLSLExec/LongVectorOps.def index 002b84a1f2..2a08b418e0 100644 --- a/tools/clang/unittests/HLSLExec/LongVectorOps.def +++ b/tools/clang/unittests/HLSLExec/LongVectorOps.def @@ -129,6 +129,8 @@ 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(FloatSpecial, ModF, 1, "TestModF", "", " -DFUNC_TEST_MODF=1", + "LongVectorOp", Default1, Default2, Default3) OP_DEFAULT(BinaryComparison, LessThan, 2, "", "<") OP_DEFAULT(BinaryComparison, LessEqual, 2, "", "<=") diff --git a/tools/clang/unittests/HLSLExec/LongVectors.cpp b/tools/clang/unittests/HLSLExec/LongVectors.cpp index dce99fd647..be5c2053ae 100644 --- a/tools/clang/unittests/HLSLExec/LongVectors.cpp +++ b/tools/clang/unittests/HLSLExec/LongVectors.cpp @@ -103,6 +103,21 @@ static constexpr Operation Operations[] = { #include "LongVectorOps.def" }; +#define OP_WITH_OUT_PARAM(OPERATION, TYPE, IMPL) \ + template <> struct ExpectedBuilder { \ + static std::vector buildExpected(Op, \ + const InputSets &Inputs) { \ + DXASSERT_NOMSG(Inputs.size() == 1); \ + size_t VectorSize = Inputs[0].size(); \ + std::vector Expected; \ + Expected.resize(VectorSize * 2); \ + for (size_t I = 0; I < VectorSize; ++I) { \ + IMPL \ + } \ + return Expected; \ + } \ + }; + constexpr const Operation &getOperation(OpType Op) { if (Op < OpType::NumOpTypes) return Operations[unsigned(Op)]; @@ -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 : DefaultValidation {}; -template <> struct ExpectedBuilder { - static std::vector buildExpected(Op &, - const InputSets &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(Frexp, float, { + int Exp = 0; + float Man = std::frexp(Inputs[0][I], &Exp); - size_t VectorSize = Inputs[0].size(); - - std::vector 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(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(Exp); +}); // // Binary Comparison @@ -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 struct Op : DefaultValidation {}; + +OP_WITH_OUT_PARAM(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(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 // @@ -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 diff --git a/tools/clang/unittests/HLSLExec/ShaderOpArith.xml b/tools/clang/unittests/HLSLExec/ShaderOpArith.xml index f89a87ca68..43fe5d6412 100644 --- a/tools/clang/unittests/HLSLExec/ShaderOpArith.xml +++ b/tools/clang/unittests/HLSLExec/ShaderOpArith.xml @@ -4112,6 +4112,20 @@ void MSMain(uint GID : SV_GroupIndex, } #endif + #ifdef FUNC_TEST_MODF + vector TestModF(vector Vector) + { + vector Mantissa; + vector Exponent; + + Mantissa = modf(Vector, Exponent); + + g_OutputVector.Store< vector >(sizeof(OUT_TYPE) * NUM, Exponent); + + return Mantissa; + } + #endif + #ifdef FUNC_SHUFFLE_VECTOR vector TestShuffleVector(TYPE Scalar) {