From d964d55b4a70e2f044dfdebeb8c5f53b7a9d53d2 Mon Sep 17 00:00:00 2001 From: Petrichor Park Date: Mon, 8 Jul 2024 13:32:59 -0500 Subject: [PATCH] vkd3d-shader/hlsl: Implement the frexp() intrinsic. --- libs/vkd3d-shader/hlsl.y | 48 ++++++++++++++++++++++++++++++++++++ tests/hlsl/frexp.shader_test | 34 ++++++++++++------------- 2 files changed, 65 insertions(+), 17 deletions(-) diff --git a/libs/vkd3d-shader/hlsl.y b/libs/vkd3d-shader/hlsl.y index 024d96c56..e20a12bb4 100644 --- a/libs/vkd3d-shader/hlsl.y +++ b/libs/vkd3d-shader/hlsl.y @@ -3983,6 +3983,53 @@ static bool intrinsic_frac(struct hlsl_ctx *ctx, return !!add_unary_arithmetic_expr(ctx, params->instrs, HLSL_OP1_FRACT, arg, loc); } +static bool intrinsic_frexp(struct hlsl_ctx *ctx, + const struct parse_initializer *params, const struct vkd3d_shader_location *loc) +{ + struct hlsl_type *type, *uint_dim_type, *int_dim_type, *bool_dim_type; + struct hlsl_ir_function_decl *func; + char *body; + + static const char template[] = + "%s frexp(%s x, out %s exp)\n" + "{\n" + /* If x is zero, always return zero for exp and mantissa. */ + " %s is_nonzero_mask = x != 0.0;\n" + " %s bits = asuint(x);\n" + /* Subtract 126, not 127, to increase the exponent */ + " %s exp_int = asint((bits & 0x7f800000u) >> 23) - 126;\n" + /* Clear the given exponent and replace it with the bit pattern + * for 2^-1 */ + " %s mantissa = asfloat((bits & 0x007fffffu) | 0x3f000000);\n" + " exp = is_nonzero_mask * %s(exp_int);\n" + " return is_nonzero_mask * mantissa;\n" + "}\n"; + + if (!elementwise_intrinsic_float_convert_args(ctx, params, loc)) + return false; + type = params->args[0]->data_type; + + if (type->e.numeric.type == HLSL_TYPE_DOUBLE) + { + hlsl_fixme(ctx, loc, "frexp() on doubles."); + return false; + } + type = hlsl_get_numeric_type(ctx, type->class, HLSL_TYPE_FLOAT, type->e.numeric.dimx, type->e.numeric.dimy); + uint_dim_type = hlsl_get_numeric_type(ctx, type->class, HLSL_TYPE_UINT, type->e.numeric.dimx, type->e.numeric.dimy); + int_dim_type = hlsl_get_numeric_type(ctx, type->class, HLSL_TYPE_INT, type->e.numeric.dimx, type->e.numeric.dimy); + bool_dim_type = hlsl_get_numeric_type(ctx, type->class, HLSL_TYPE_BOOL, type->e.numeric.dimx, type->e.numeric.dimy); + + if (!(body = hlsl_sprintf_alloc(ctx, template, type->name, type->name, type->name, + bool_dim_type->name, uint_dim_type->name, int_dim_type->name, type->name, type->name))) + return false; + func = hlsl_compile_internal_function(ctx, "frexp", body); + vkd3d_free(body); + if (!func) + return false; + + return !!add_user_call(ctx, func, params, false, loc); +} + static bool intrinsic_fwidth(struct hlsl_ctx *ctx, const struct parse_initializer *params, const struct vkd3d_shader_location *loc) { @@ -5283,6 +5330,7 @@ intrinsic_functions[] = {"floor", 1, true, intrinsic_floor}, {"fmod", 2, true, intrinsic_fmod}, {"frac", 1, true, intrinsic_frac}, + {"frexp", 2, true, intrinsic_frexp}, {"fwidth", 1, true, intrinsic_fwidth}, {"isinf", 1, true, intrinsic_isinf}, {"ldexp", 2, true, intrinsic_ldexp}, diff --git a/tests/hlsl/frexp.shader_test b/tests/hlsl/frexp.shader_test index 41e065374..f0fd773a4 100644 --- a/tests/hlsl/frexp.shader_test +++ b/tests/hlsl/frexp.shader_test @@ -1,4 +1,4 @@ -[pixel shader todo(sm<6)] +[pixel shader todo(sm<4)] uniform float4 f; float4 main() : sv_target @@ -10,52 +10,52 @@ float4 main() : sv_target [test] uniform 0 float4 3.1415927 0.0 0.0 0.0 -todo(sm<6 | msl) draw quad +todo(sm<4 | msl & sm>=6) draw quad probe (0, 0) f32(2.0, 0.785398185, 0.0, 0.0) uniform 0 float4 -3.1415927 0.0 0.0 0.0 -todo(sm<6 | msl) draw quad +todo(sm<4 | msl & sm>=6) draw quad if(sm<4) probe (0, 0) f32(2.0, -0.785398185, 0.0, 0.0) % Starting with shader model 4, negative inputs give positive mantissa. if(sm>=4) probe (0, 0) f32(2.0, 0.785398185, 0.0, 0.0) uniform 0 float4 7604.123 0.0 0.0 0.0 -todo(sm<6 | msl) draw quad +todo(sm<4 | msl & sm>=6) draw quad probe (0, 0) f32(13.0, 0.92823765, 0.0, 0.0) uniform 0 float4 0.00001234 0.0 0.0 0.0 -todo(sm<6 | msl) draw quad +todo(sm<4 | msl & sm>=6) draw quad probe (0, 0) f32(-16.0, 0.8087142, 0.0, 0.0) uniform 0 float4 0.0 0.0 0.0 0.0 -todo(sm<6 | msl) draw quad +todo(sm<4 | msl & sm>=6) draw quad probe (0, 0) f32(0.0, 0.0, 0.0, 0.0) uniform 0 float4 -0.0 0.0 0.0 0.0 -todo(sm<6 | msl) draw quad +todo(sm<4 | msl & sm>=6) draw quad probe (0, 0) f32(0.0, 0.0, 0.0, 0.0) uniform 0 float4 INF 0.0 0.0 0.0 -todo(sm<6 | msl) draw quad +todo(sm<4 | msl & sm>=6) draw quad if(sm<4) probe (0, 0) f32(-NAN, -NAN, 0, 0) if(sm>=4) probe (0, 0) f32(129, 0.5, 0, 0) uniform 0 float4 -INF 0.0 0.0 0.0 -todo(sm<6 | msl) draw quad +todo(sm<4 | msl & sm>=6) draw quad if(sm<4) probe (0, 0) f32(-NAN, -NAN, 0, 0) if(sm>=4) probe (0, 0) f32(129, 0.5, 0, 0) uniform 0 float4 NAN 0 0 0 -todo(sm<6 | msl) draw quad +todo(sm<4 | msl & sm>=6) draw quad if(sm<4) probe (0, 0) f32(NAN, NAN, 0, 0) if(sm>=4) probe (0, 0) f32(129, 0.75, 0, 0) % Subnormals. uniform 0 uint4 0x0007ffff 0 0 0 -todo(sm<6 | msl) draw quad +todo(sm<4 | msl & sm>=6) draw quad probe (0, 0) f32(0, 0, 0, 0) -[pixel shader todo(sm<6)] +[pixel shader todo(sm<4)] float4 main() : sv_target { int arg = 7604; @@ -66,10 +66,10 @@ float4 main() : sv_target } [test] -todo(sm<6) draw quad +todo(sm<4) draw quad probe (0, 0) f32(13.0, 0.0, 0.0, 0.0) -[pixel shader todo(sm<6)] +[pixel shader todo(sm<4)] float4 main() : sv_target { bool arg = true; @@ -80,11 +80,11 @@ float4 main() : sv_target } [test] -todo(sm<6) draw quad +todo(sm<4) draw quad if(sm<4) probe (0, 0) f32(0.0, 1.0, 0.0, 0.0) if(sm>=4) probe (0, 0) f32(1.0, 1.0, 0.0, 0.0) -[pixel shader todo(sm<6)] +[pixel shader todo(sm<4)] float4 main() : sv_target { half arg = 3.141; @@ -95,7 +95,7 @@ float4 main() : sv_target } [test] -todo(sm<6) draw quad +todo(sm<4) draw quad probe (0, 0) f32(2.0, 0.785250008, 0.0, 0.0) [require]