hlsl: Implement modf and frexp

Change-Id: I40b3ad7e2d4811b0a52e75402c7d5ccda090a97c
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/53809
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: David Neto <dneto@google.com>
This commit is contained in:
Ben Clayton
2021-06-09 18:53:57 +00:00
parent 241c16d626
commit 9ca78030eb
41 changed files with 678 additions and 662 deletions

View File

@@ -586,6 +586,9 @@ bool GeneratorImpl::EmitCall(std::ostream& pre,
}
if (intrinsic->Type() == sem::IntrinsicType::kSelect) {
return EmitSelectCall(pre, out, expr);
}
if (intrinsic->Type() == sem::IntrinsicType::kFrexp) {
return EmitFrexpCall(pre, out, expr, intrinsic);
} else if (intrinsic->Type() == sem::IntrinsicType::kIsNormal) {
diagnostics_.add_error("is_normal not supported in HLSL backend yet");
return false;
@@ -701,6 +704,52 @@ bool GeneratorImpl::EmitSelectCall(std::ostream& pre,
return true;
}
bool GeneratorImpl::EmitFrexpCall(std::ostream& pre,
std::ostream& out,
ast::CallExpression* expr,
const sem::Intrinsic* intrinsic) {
// Exponent is an integer in WGSL, but HLSL wants a float.
// We need to make the call with a temporary float, and then cast.
auto signficand = intrinsic->Parameters()[0];
auto exponent = intrinsic->Parameters()[1];
std::string width;
if (auto* vec = signficand.type->As<sem::Vector>()) {
width = std::to_string(vec->size());
}
// Exponent is an integer, which HLSL does not have an overload for.
// We need to cast from a float.
std::stringstream ss;
auto float_exp = generate_name(kTempNamePrefix);
ss << "float" << width << " " << float_exp << ";";
make_indent(ss << std::endl);
auto significand = generate_name(kTempNamePrefix);
ss << "float" << width << " " << significand << " = frexp(";
if (!EmitExpression(pre, ss, expr->params()[0])) {
return false;
}
ss << ", " << float_exp << ");";
make_indent(ss << std::endl);
if (!EmitExpression(pre, ss, expr->params()[1])) {
return false;
}
ss << " = ";
if (!EmitType(ss, exponent.type->UnwrapPtr(), ast::StorageClass::kNone,
ast::Access::kUndefined, "")) {
return false;
}
ss << "(" << float_exp << ");";
make_indent(ss << std::endl);
pre << ss.str();
out << significand;
return true;
}
bool GeneratorImpl::EmitDataPackingCall(std::ostream& pre,
std::ostream& out,
ast::CallExpression* expr,
@@ -1150,13 +1199,15 @@ std::string GeneratorImpl::generate_builtin_name(
const sem::Intrinsic* intrinsic) {
std::string out;
switch (intrinsic->Type()) {
case sem::IntrinsicType::kAbs:
case sem::IntrinsicType::kAcos:
case sem::IntrinsicType::kAny:
case sem::IntrinsicType::kAll:
case sem::IntrinsicType::kAny:
case sem::IntrinsicType::kAsin:
case sem::IntrinsicType::kAtan:
case sem::IntrinsicType::kAtan2:
case sem::IntrinsicType::kCeil:
case sem::IntrinsicType::kClamp:
case sem::IntrinsicType::kCos:
case sem::IntrinsicType::kCosh:
case sem::IntrinsicType::kCross:
@@ -1167,14 +1218,19 @@ std::string GeneratorImpl::generate_builtin_name(
case sem::IntrinsicType::kExp2:
case sem::IntrinsicType::kFloor:
case sem::IntrinsicType::kFma:
case sem::IntrinsicType::kFrexp:
case sem::IntrinsicType::kLdexp:
case sem::IntrinsicType::kLength:
case sem::IntrinsicType::kLog:
case sem::IntrinsicType::kLog2:
case sem::IntrinsicType::kMax:
case sem::IntrinsicType::kMin:
case sem::IntrinsicType::kModf:
case sem::IntrinsicType::kNormalize:
case sem::IntrinsicType::kPow:
case sem::IntrinsicType::kReflect:
case sem::IntrinsicType::kRound:
case sem::IntrinsicType::kSign:
case sem::IntrinsicType::kSin:
case sem::IntrinsicType::kSinh:
case sem::IntrinsicType::kSqrt:
@@ -1183,11 +1239,6 @@ std::string GeneratorImpl::generate_builtin_name(
case sem::IntrinsicType::kTanh:
case sem::IntrinsicType::kTranspose:
case sem::IntrinsicType::kTrunc:
case sem::IntrinsicType::kSign:
case sem::IntrinsicType::kAbs:
case sem::IntrinsicType::kMax:
case sem::IntrinsicType::kMin:
case sem::IntrinsicType::kClamp:
out = intrinsic->str();
break;
case sem::IntrinsicType::kCountOneBits:

View File

@@ -139,7 +139,6 @@ class GeneratorImpl : public TextGenerator {
std::ostream& out,
ast::CallExpression* expr,
const sem::Intrinsic* intrinsic);
/// Handles generating a call to the `select()` intrinsic
/// @param pre the preamble of the expression stream
/// @param out the output of the expression stream
@@ -148,7 +147,16 @@ class GeneratorImpl : public TextGenerator {
bool EmitSelectCall(std::ostream& pre,
std::ostream& out,
ast::CallExpression* expr);
/// Handles generating a call to the `frexp()` intrinsic
/// @param pre the preamble of the expression stream
/// @param out the output of the expression stream
/// @param expr the call expression
/// @param intrinsic the semantic information for the intrinsic
/// @returns true if the call expression is emitted
bool EmitFrexpCall(std::ostream& pre,
std::ostream& out,
ast::CallExpression* expr,
const sem::Intrinsic* intrinsic);
/// Handles generating a call to data packing intrinsic
/// @param pre the preamble of the expression stream
/// @param out the output of the expression stream

View File

@@ -257,10 +257,6 @@ TEST_F(HlslGeneratorImplTest_Intrinsic, DISABLED_Intrinsic_IsNormal) {
FAIL();
}
TEST_F(HlslGeneratorImplTest_Intrinsic, DISABLED_Intrinsic_Select) {
FAIL();
}
TEST_F(HlslGeneratorImplTest_Intrinsic, Intrinsic_Call) {
auto* call = Call("dot", "param1", "param2");
@@ -297,6 +293,60 @@ TEST_F(HlslGeneratorImplTest_Intrinsic, Select_Vector) {
EXPECT_EQ(result(), "(bool2(true, false) ? int2(1, 2) : int2(3, 4))");
}
TEST_F(HlslGeneratorImplTest_Intrinsic, Modf_Scalar) {
auto* res = Var("res", ty.f32());
auto* call = Call("modf", 1.0f, AddressOf(res));
WrapInFunction(res, call);
GeneratorImpl& gen = SanitizeAndBuild();
ASSERT_TRUE(gen.Generate(out)) << gen.error();
EXPECT_THAT(result(), HasSubstr("modf(1.0f, res)"));
}
TEST_F(HlslGeneratorImplTest_Intrinsic, Modf_Vector) {
auto* res = Var("res", ty.vec3<f32>());
auto* call = Call("modf", vec3<f32>(), AddressOf(res));
WrapInFunction(res, call);
GeneratorImpl& gen = SanitizeAndBuild();
ASSERT_TRUE(gen.Generate(out)) << gen.error();
EXPECT_THAT(result(), HasSubstr("modf(float3(0.0f, 0.0f, 0.0f), res)"));
}
TEST_F(HlslGeneratorImplTest_Intrinsic, Frexp_Scalar_i32) {
auto* exp = Var("exp", ty.i32());
auto* call = Call("frexp", 1.0f, AddressOf(exp));
WrapInFunction(exp, call);
GeneratorImpl& gen = SanitizeAndBuild();
ASSERT_TRUE(gen.Generate(out)) << gen.error();
EXPECT_THAT(result(), HasSubstr(R"(
float tint_tmp;
float tint_tmp_1 = frexp(1.0f, tint_tmp);
exp = int(tint_tmp);
(void) tint_tmp_1;
)"));
}
TEST_F(HlslGeneratorImplTest_Intrinsic, Frexp_Vector_i32) {
auto* res = Var("res", ty.vec3<i32>());
auto* call = Call("frexp", vec3<f32>(), AddressOf(res));
WrapInFunction(res, call);
GeneratorImpl& gen = SanitizeAndBuild();
ASSERT_TRUE(gen.Generate(out)) << gen.error();
EXPECT_THAT(result(), HasSubstr(R"(
float3 tint_tmp;
float3 tint_tmp_1 = frexp(float3(0.0f, 0.0f, 0.0f), tint_tmp);
res = int3(tint_tmp);
(void) tint_tmp_1;
)"));
}
TEST_F(HlslGeneratorImplTest_Intrinsic, Pack4x8Snorm) {
auto* call = Call("pack4x8snorm", "p1");
Global("p1", ty.vec4<f32>(), ast::StorageClass::kPrivate);