Remove isNan, isInf, isFinite, and isNormal

These were deprecated in M98.

Fixed: tint:1312
Change-Id: Ieec17bfcc729f90d0a9aa8904a162167b9de54ed
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/82800
Reviewed-by: Ben Clayton <bclayton@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
Commit-Queue: James Price <jrprice@google.com>
This commit is contained in:
James Price
2022-03-05 00:39:14 +00:00
committed by Tint LUCI CQ
parent e228319549
commit bcd9ad2ebb
142 changed files with 2546 additions and 9268 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -340,14 +340,6 @@ fn insertBits<T: iu32>(T, T, u32, u32) -> T
fn insertBits<N: num, T: iu32>(vec<N, T>, vec<N, T>, u32, u32) -> vec<N, T>
fn inverseSqrt(f32) -> f32
fn inverseSqrt<N: num>(vec<N, f32>) -> vec<N, f32>
[[deprecated]] fn isFinite(f32) -> bool
[[deprecated]] fn isFinite<N: num>(vec<N, f32>) -> vec<N, bool>
[[deprecated]] fn isInf(f32) -> bool
[[deprecated]] fn isInf<N: num>(vec<N, f32>) -> vec<N, bool>
[[deprecated]] fn isNan(f32) -> bool
[[deprecated]] fn isNan<N: num>(vec<N, f32>) -> vec<N, bool>
[[deprecated]] fn isNormal(f32) -> bool
[[deprecated]] fn isNormal<N: num>(vec<N, f32>) -> vec<N, bool>
fn ldexp(f32, i32) -> f32
fn ldexp<N: num>(vec<N, f32>, vec<N, i32>) -> vec<N, f32>
fn length(f32) -> f32

View File

@@ -138,75 +138,6 @@ INSTANTIATE_TEST_SUITE_P(ResolverTest,
ResolverBuiltinTest_BoolMethod,
testing::Values("any", "all"));
using ResolverBuiltinTest_FloatMethod = ResolverTestWithParam<std::string>;
TEST_P(ResolverBuiltinTest_FloatMethod, Vector) {
auto name = GetParam();
Global("my_var", ty.vec3<f32>(), ast::StorageClass::kPrivate);
auto* expr = Call(name, "my_var");
WrapInFunction(expr);
EXPECT_TRUE(r()->Resolve()) << r()->error();
ASSERT_NE(TypeOf(expr), nullptr);
ASSERT_TRUE(TypeOf(expr)->Is<sem::Vector>());
EXPECT_TRUE(TypeOf(expr)->As<sem::Vector>()->type()->Is<sem::Bool>());
EXPECT_EQ(TypeOf(expr)->As<sem::Vector>()->Width(), 3u);
}
TEST_P(ResolverBuiltinTest_FloatMethod, Scalar) {
auto name = GetParam();
Global("my_var", ty.f32(), ast::StorageClass::kPrivate);
auto* expr = Call(name, "my_var");
WrapInFunction(expr);
EXPECT_TRUE(r()->Resolve()) << r()->error();
ASSERT_NE(TypeOf(expr), nullptr);
EXPECT_TRUE(TypeOf(expr)->Is<sem::Bool>());
}
TEST_P(ResolverBuiltinTest_FloatMethod, MissingParam) {
auto name = GetParam();
Global("my_var", ty.f32(), ast::StorageClass::kPrivate);
auto* expr = Call(name);
WrapInFunction(expr);
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(), "error: no matching call to " + name +
"()\n\n"
"2 candidate functions:\n " +
name + "(f32) -> bool\n " + name +
"(vecN<f32>) -> vecN<bool>\n");
}
TEST_P(ResolverBuiltinTest_FloatMethod, TooManyParams) {
auto name = GetParam();
Global("my_var", ty.f32(), ast::StorageClass::kPrivate);
auto* expr = Call(name, "my_var", 1.23f);
WrapInFunction(expr);
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(), "error: no matching call to " + name +
"(f32, f32)\n\n"
"2 candidate functions:\n " +
name + "(f32) -> bool\n " + name +
"(vecN<f32>) -> vecN<bool>\n");
}
INSTANTIATE_TEST_SUITE_P(
ResolverTest,
ResolverBuiltinTest_FloatMethod,
testing::Values("isInf", "isNan", "isFinite", "isNormal"));
enum class Texture { kF32, kI32, kU32 };
inline std::ostream& operator<<(std::ostream& out, Texture data) {
if (data == Texture::kF32) {

View File

@@ -46,11 +46,6 @@ bool IsDerivativeBuiltin(BuiltinType i) {
IsFineDerivativeBuiltin(i);
}
bool IsFloatClassificationBuiltin(BuiltinType i) {
return i == BuiltinType::kIsFinite || i == BuiltinType::kIsInf ||
i == BuiltinType::kIsNan || i == BuiltinType::kIsNormal;
}
bool IsTextureBuiltin(BuiltinType i) {
return IsImageQueryBuiltin(i) || i == BuiltinType::kTextureLoad ||
i == BuiltinType::kTextureGather ||
@@ -132,10 +127,6 @@ bool Builtin::IsDerivative() const {
return IsDerivativeBuiltin(type_);
}
bool Builtin::IsFloatClassification() const {
return IsFloatClassificationBuiltin(type_);
}
bool Builtin::IsTexture() const {
return IsTextureBuiltin(type_);
}

View File

@@ -41,11 +41,6 @@ bool IsFineDerivativeBuiltin(BuiltinType i);
/// @returns true if the given `i` is a derivative builtin
bool IsDerivativeBuiltin(BuiltinType i);
/// Determines if the given `i` is a float classification builtin
/// @param i the builtin type
/// @returns true if the given `i` is a float builtin
bool IsFloatClassificationBuiltin(BuiltinType i);
/// Determines if the given `i` is a texture operation builtin
/// @param i the builtin type
/// @returns true if the given `i` is a texture operation builtin
@@ -118,9 +113,6 @@ class Builtin : public Castable<Builtin, CallTarget> {
/// @returns true if builtin is a derivative builtin
bool IsDerivative() const;
/// @returns true if builtin is a float builtin
bool IsFloatClassification() const;
/// @returns true if builtin is a texture operation builtin
bool IsTexture() const;

View File

@@ -75,10 +75,6 @@ INSTANTIATE_TEST_SUITE_P(
BuiltinData{"fwidthCoarse", BuiltinType::kFwidthCoarse},
BuiltinData{"fwidthFine", BuiltinType::kFwidthFine},
BuiltinData{"inverseSqrt", BuiltinType::kInverseSqrt},
BuiltinData{"isFinite", BuiltinType::kIsFinite},
BuiltinData{"isInf", BuiltinType::kIsInf},
BuiltinData{"isNan", BuiltinType::kIsNan},
BuiltinData{"isNormal", BuiltinType::kIsNormal},
BuiltinData{"ldexp", BuiltinType::kLdexp},
BuiltinData{"length", BuiltinType::kLength},
BuiltinData{"log", BuiltinType::kLog},

View File

@@ -153,18 +153,6 @@ BuiltinType ParseBuiltinType(const std::string& name) {
if (name == "inverseSqrt") {
return BuiltinType::kInverseSqrt;
}
if (name == "isFinite") {
return BuiltinType::kIsFinite;
}
if (name == "isInf") {
return BuiltinType::kIsInf;
}
if (name == "isNan") {
return BuiltinType::kIsNan;
}
if (name == "isNormal") {
return BuiltinType::kIsNormal;
}
if (name == "ldexp") {
return BuiltinType::kLdexp;
}
@@ -443,14 +431,6 @@ const char* str(BuiltinType i) {
return "insertBits";
case BuiltinType::kInverseSqrt:
return "inverseSqrt";
case BuiltinType::kIsFinite:
return "isFinite";
case BuiltinType::kIsInf:
return "isInf";
case BuiltinType::kIsNan:
return "isNan";
case BuiltinType::kIsNormal:
return "isNormal";
case BuiltinType::kLdexp:
return "ldexp";
case BuiltinType::kLength:

View File

@@ -75,10 +75,6 @@ enum class BuiltinType {
kFwidthFine,
kInsertBits,
kInverseSqrt,
kIsFinite,
kIsInf,
kIsNan,
kIsNormal,
kLdexp,
kLength,
kLog,

View File

@@ -663,9 +663,6 @@ bool GeneratorImpl::EmitBuiltinCall(std::ostream& out,
if (builtin->Type() == sem::BuiltinType::kFrexp) {
return EmitFrexpCall(out, expr, builtin);
}
if (builtin->Type() == sem::BuiltinType::kIsNormal) {
return EmitIsNormalCall(out, expr, builtin);
}
if (builtin->Type() == sem::BuiltinType::kDegrees) {
return EmitDegreesCall(out, expr, builtin);
}
@@ -1191,40 +1188,6 @@ bool GeneratorImpl::EmitFrexpCall(std::ostream& out,
});
}
bool GeneratorImpl::EmitIsNormalCall(std::ostream& out,
const ast::CallExpression* expr,
const sem::Builtin* builtin) {
// GLSL doesn't have a isNormal builtin, we need to emulate
return CallBuiltinHelper(
out, expr, builtin,
[&](TextBuffer* b, const std::vector<std::string>& params) {
auto* input_ty = builtin->Parameters()[0]->Type();
std::string vec_type;
if (auto* vec = input_ty->As<sem::Vector>()) {
vec_type = "uvec" + std::to_string(vec->Width());
} else {
vec_type = "uint";
}
constexpr auto* kExponentMask = "0x7f80000u";
constexpr auto* kMinNormalExponent = "0x0080000u";
constexpr auto* kMaxNormalExponent = "0x7f00000u";
line(b) << vec_type << " exponent = floatBitsToUint(" << params[0]
<< ") & " << kExponentMask << ";";
line(b) << vec_type << " clamped = "
<< "clamp(exponent, " << kMinNormalExponent << ", "
<< kMaxNormalExponent << ");";
if (input_ty->Is<sem::Vector>()) {
line(b) << "return equal(clamped, exponent);";
} else {
line(b) << "return clamped == exponent;";
}
return true;
});
}
bool GeneratorImpl::EmitDegreesCall(std::ostream& out,
const ast::CallExpression* expr,
const sem::Builtin* builtin) {
@@ -1625,12 +1588,6 @@ std::string GeneratorImpl::generate_builtin_name(const sem::Builtin* builtin) {
return "fwidth";
case sem::BuiltinType::kInverseSqrt:
return "inversesqrt";
case sem::BuiltinType::kIsFinite:
return "isfinite";
case sem::BuiltinType::kIsInf:
return "isinf";
case sem::BuiltinType::kIsNan:
return "isnan";
case sem::BuiltinType::kMix:
return "mix";
case sem::BuiltinType::kPack2x16float:

View File

@@ -239,14 +239,6 @@ class GeneratorImpl : public TextGenerator {
bool EmitFrexpCall(std::ostream& out,
const ast::CallExpression* expr,
const sem::Builtin* builtin);
/// Handles generating a call to the `isNormal()` builtin
/// @param out the output of the expression stream
/// @param expr the call expression
/// @param builtin the semantic information for the builtin
/// @returns true if the call expression is emitted
bool EmitIsNormalCall(std::ostream& out,
const ast::CallExpression* expr,
const sem::Builtin* builtin);
/// Handles generating a call to the `degrees()` builtin
/// @param out the output of the expression stream
/// @param expr the call expression

View File

@@ -84,10 +84,6 @@ const ast::CallExpression* GenerateCall(BuiltinType builtin,
case BuiltinType::kFwidthCoarse:
case BuiltinType::kFwidthFine:
case BuiltinType::kInverseSqrt:
case BuiltinType::kIsFinite:
case BuiltinType::kIsInf:
case BuiltinType::kIsNan:
case BuiltinType::kIsNormal:
case BuiltinType::kLength:
case BuiltinType::kLog:
case BuiltinType::kLog2:
@@ -219,9 +215,6 @@ INSTANTIATE_TEST_SUITE_P(
BuiltinData{BuiltinType::kFwidthCoarse, ParamType::kF32, "fwidth"},
BuiltinData{BuiltinType::kFwidthFine, ParamType::kF32, "fwidth"},
BuiltinData{BuiltinType::kInverseSqrt, ParamType::kF32, "inversesqrt"},
BuiltinData{BuiltinType::kIsFinite, ParamType::kF32, "isfinite"},
BuiltinData{BuiltinType::kIsInf, ParamType::kF32, "isinf"},
BuiltinData{BuiltinType::kIsNan, ParamType::kF32, "isnan"},
BuiltinData{BuiltinType::kLdexp, ParamType::kF32, "ldexp"},
BuiltinData{BuiltinType::kLength, ParamType::kF32, "length"},
BuiltinData{BuiltinType::kLog, ParamType::kF32, "log"},
@@ -248,10 +241,6 @@ INSTANTIATE_TEST_SUITE_P(
BuiltinData{BuiltinType::kTranspose, ParamType::kF32, "transpose"},
BuiltinData{BuiltinType::kTrunc, ParamType::kF32, "trunc"}));
TEST_F(GlslGeneratorImplTest_Builtin, DISABLED_Builtin_IsNormal) {
FAIL();
}
TEST_F(GlslGeneratorImplTest_Builtin, Builtin_Call) {
auto* call = Call("dot", "param1", "param2");
@@ -416,62 +405,6 @@ void main() {
)"));
}
TEST_F(GlslGeneratorImplTest_Builtin, IsNormal_Scalar) {
auto* val = Var("val", ty.f32());
auto* call = Call("isNormal", val);
WrapInFunction(val, call);
GeneratorImpl& gen = SanitizeAndBuild();
ASSERT_TRUE(gen.Generate()) << gen.error();
EXPECT_THAT(gen.result(), HasSubstr(R"(ion 310 es
bool tint_isNormal(float param_0) {
uint exponent = floatBitsToUint(param_0) & 0x7f80000u;
uint clamped = clamp(exponent, 0x0080000u, 0x7f00000u);
return clamped == exponent;
}
void test_function() {
float val = 0.0f;
bool tint_symbol = tint_isNormal(val);
}
layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
void main() {
test_function();
)"));
}
TEST_F(GlslGeneratorImplTest_Builtin, IsNormal_Vector) {
auto* val = Var("val", ty.vec3<f32>());
auto* call = Call("isNormal", val);
WrapInFunction(val, call);
GeneratorImpl& gen = SanitizeAndBuild();
ASSERT_TRUE(gen.Generate()) << gen.error();
EXPECT_THAT(gen.result(), HasSubstr(R"( 310 es
bvec3 tint_isNormal(vec3 param_0) {
uvec3 exponent = floatBitsToUint(param_0) & 0x7f80000u;
uvec3 clamped = clamp(exponent, 0x0080000u, 0x7f00000u);
return equal(clamped, exponent);
}
void test_function() {
vec3 val = vec3(0.0f, 0.0f, 0.0f);
bvec3 tint_symbol = tint_isNormal(val);
}
layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
void main() {
test_function();
)"));
}
TEST_F(GlslGeneratorImplTest_Builtin, Degrees_Scalar) {
auto* val = Var("val", ty.f32());
auto* call = Call("degrees", val);

View File

@@ -1034,9 +1034,6 @@ bool GeneratorImpl::EmitBuiltinCall(std::ostream& out,
if (builtin->Type() == sem::BuiltinType::kFrexp) {
return EmitFrexpCall(out, expr, builtin);
}
if (builtin->Type() == sem::BuiltinType::kIsNormal) {
return EmitIsNormalCall(out, expr, builtin);
}
if (builtin->Type() == sem::BuiltinType::kDegrees) {
return EmitDegreesCall(out, expr, builtin);
}
@@ -1922,34 +1919,6 @@ bool GeneratorImpl::EmitFrexpCall(std::ostream& out,
});
}
bool GeneratorImpl::EmitIsNormalCall(std::ostream& out,
const ast::CallExpression* expr,
const sem::Builtin* builtin) {
// HLSL doesn't have a isNormal builtin, we need to emulate
return CallBuiltinHelper(
out, expr, builtin,
[&](TextBuffer* b, const std::vector<std::string>& params) {
auto* input_ty = builtin->Parameters()[0]->Type();
std::string width;
if (auto* vec = input_ty->As<sem::Vector>()) {
width = std::to_string(vec->Width());
}
constexpr auto* kExponentMask = "0x7f80000";
constexpr auto* kMinNormalExponent = "0x0080000";
constexpr auto* kMaxNormalExponent = "0x7f00000";
line(b) << "uint" << width << " exponent = asuint(" << params[0]
<< ") & " << kExponentMask << ";";
line(b) << "uint" << width << " clamped = "
<< "clamp(exponent, " << kMinNormalExponent << ", "
<< kMaxNormalExponent << ");";
line(b) << "return clamped == exponent;";
return true;
});
}
bool GeneratorImpl::EmitDegreesCall(std::ostream& out,
const ast::CallExpression* expr,
const sem::Builtin* builtin) {
@@ -2571,12 +2540,6 @@ std::string GeneratorImpl::generate_builtin_name(const sem::Builtin* builtin) {
return "fwidth";
case sem::BuiltinType::kInverseSqrt:
return "rsqrt";
case sem::BuiltinType::kIsFinite:
return "isfinite";
case sem::BuiltinType::kIsInf:
return "isinf";
case sem::BuiltinType::kIsNan:
return "isnan";
case sem::BuiltinType::kMix:
return "lerp";
case sem::BuiltinType::kReverseBits:

View File

@@ -241,14 +241,6 @@ class GeneratorImpl : public TextGenerator {
bool EmitFrexpCall(std::ostream& out,
const ast::CallExpression* expr,
const sem::Builtin* builtin);
/// Handles generating a call to the `isNormal()` builtin
/// @param out the output of the expression stream
/// @param expr the call expression
/// @param builtin the semantic information for the builtin
/// @returns true if the call expression is emitted
bool EmitIsNormalCall(std::ostream& out,
const ast::CallExpression* expr,
const sem::Builtin* builtin);
/// Handles generating a call to the `degrees()` builtin
/// @param out the output of the expression stream
/// @param expr the call expression

View File

@@ -84,10 +84,6 @@ const ast::CallExpression* GenerateCall(BuiltinType builtin,
case BuiltinType::kFwidthCoarse:
case BuiltinType::kFwidthFine:
case BuiltinType::kInverseSqrt:
case BuiltinType::kIsFinite:
case BuiltinType::kIsInf:
case BuiltinType::kIsNan:
case BuiltinType::kIsNormal:
case BuiltinType::kLength:
case BuiltinType::kLog:
case BuiltinType::kLog2:
@@ -219,9 +215,6 @@ INSTANTIATE_TEST_SUITE_P(
BuiltinData{BuiltinType::kFwidthCoarse, ParamType::kF32, "fwidth"},
BuiltinData{BuiltinType::kFwidthFine, ParamType::kF32, "fwidth"},
BuiltinData{BuiltinType::kInverseSqrt, ParamType::kF32, "rsqrt"},
BuiltinData{BuiltinType::kIsFinite, ParamType::kF32, "isfinite"},
BuiltinData{BuiltinType::kIsInf, ParamType::kF32, "isinf"},
BuiltinData{BuiltinType::kIsNan, ParamType::kF32, "isnan"},
BuiltinData{BuiltinType::kLdexp, ParamType::kF32, "ldexp"},
BuiltinData{BuiltinType::kLength, ParamType::kF32, "length"},
BuiltinData{BuiltinType::kLog, ParamType::kF32, "log"},
@@ -247,10 +240,6 @@ INSTANTIATE_TEST_SUITE_P(
BuiltinData{BuiltinType::kTranspose, ParamType::kF32, "transpose"},
BuiltinData{BuiltinType::kTrunc, ParamType::kF32, "trunc"}));
TEST_F(HlslGeneratorImplTest_Builtin, DISABLED_Builtin_IsNormal) {
FAIL();
}
TEST_F(HlslGeneratorImplTest_Builtin, Builtin_Call) {
auto* call = Call("dot", "param1", "param2");
@@ -394,52 +383,6 @@ void test_function() {
)");
}
TEST_F(HlslGeneratorImplTest_Builtin, IsNormal_Scalar) {
auto* val = Var("val", ty.f32());
auto* call = Call("isNormal", val);
WrapInFunction(val, call);
GeneratorImpl& gen = SanitizeAndBuild();
ASSERT_TRUE(gen.Generate()) << gen.error();
EXPECT_EQ(gen.result(), R"(bool tint_isNormal(float param_0) {
uint exponent = asuint(param_0) & 0x7f80000;
uint clamped = clamp(exponent, 0x0080000, 0x7f00000);
return clamped == exponent;
}
[numthreads(1, 1, 1)]
void test_function() {
float val = 0.0f;
const bool tint_symbol = tint_isNormal(val);
return;
}
)");
}
TEST_F(HlslGeneratorImplTest_Builtin, IsNormal_Vector) {
auto* val = Var("val", ty.vec3<f32>());
auto* call = Call("isNormal", val);
WrapInFunction(val, call);
GeneratorImpl& gen = SanitizeAndBuild();
ASSERT_TRUE(gen.Generate()) << gen.error();
EXPECT_EQ(gen.result(), R"(bool3 tint_isNormal(float3 param_0) {
uint3 exponent = asuint(param_0) & 0x7f80000;
uint3 clamped = clamp(exponent, 0x0080000, 0x7f00000);
return clamped == exponent;
}
[numthreads(1, 1, 1)]
void test_function() {
float3 val = float3(0.0f, 0.0f, 0.0f);
const bool3 tint_symbol = tint_isNormal(val);
return;
}
)");
}
TEST_F(HlslGeneratorImplTest_Builtin, Degrees_Scalar) {
auto* val = Var("val", ty.f32());
auto* call = Call("degrees", val);

View File

@@ -1385,18 +1385,6 @@ std::string GeneratorImpl::generate_builtin_name(const sem::Builtin* builtin) {
case sem::BuiltinType::kFwidthFine:
out += "fwidth";
break;
case sem::BuiltinType::kIsFinite:
out += "isfinite";
break;
case sem::BuiltinType::kIsInf:
out += "isinf";
break;
case sem::BuiltinType::kIsNan:
out += "isnan";
break;
case sem::BuiltinType::kIsNormal:
out += "isnormal";
break;
case sem::BuiltinType::kMax:
if (builtin->ReturnType()->is_float_scalar_or_vector()) {
out += "fmax";

View File

@@ -80,10 +80,6 @@ const ast::CallExpression* GenerateCall(BuiltinType builtin,
case BuiltinType::kFwidthCoarse:
case BuiltinType::kFwidthFine:
case BuiltinType::kInverseSqrt:
case BuiltinType::kIsFinite:
case BuiltinType::kIsInf:
case BuiltinType::kIsNan:
case BuiltinType::kIsNormal:
case BuiltinType::kLength:
case BuiltinType::kLog:
case BuiltinType::kLog2:
@@ -243,10 +239,6 @@ INSTANTIATE_TEST_SUITE_P(
BuiltinData{BuiltinType::kFwidthFine, ParamType::kF32, "fwidth"},
BuiltinData{BuiltinType::kInsertBits, ParamType::kU32, "insert_bits"},
BuiltinData{BuiltinType::kInverseSqrt, ParamType::kF32, "rsqrt"},
BuiltinData{BuiltinType::kIsFinite, ParamType::kF32, "isfinite"},
BuiltinData{BuiltinType::kIsInf, ParamType::kF32, "isinf"},
BuiltinData{BuiltinType::kIsNan, ParamType::kF32, "isnan"},
BuiltinData{BuiltinType::kIsNormal, ParamType::kF32, "isnormal"},
BuiltinData{BuiltinType::kLdexp, ParamType::kF32, "ldexp"},
BuiltinData{BuiltinType::kLength, ParamType::kF32, "length"},
BuiltinData{BuiltinType::kLog, ParamType::kF32, "log"},

View File

@@ -2527,116 +2527,6 @@ uint32_t Builder::GenerateBuiltinCall(const sem::Call* call,
case BuiltinType::kInsertBits:
op = spv::Op::OpBitFieldInsert;
break;
case BuiltinType::kIsInf:
op = spv::Op::OpIsInf;
break;
case BuiltinType::kIsNan:
op = spv::Op::OpIsNan;
break;
case BuiltinType::kIsFinite: {
// Implemented as: not(IsInf or IsNan)
auto val_id = get_arg_as_value_id(0);
if (!val_id) {
return 0;
}
auto inf_result = result_op();
auto nan_result = result_op();
auto or_result = result_op();
if (push_function_inst(spv::Op::OpIsInf,
{Operand::Int(result_type_id), inf_result,
Operand::Int(val_id)}) &&
push_function_inst(spv::Op::OpIsNan,
{Operand::Int(result_type_id), nan_result,
Operand::Int(val_id)}) &&
push_function_inst(spv::Op::OpLogicalOr,
{Operand::Int(result_type_id), or_result,
Operand::Int(inf_result.to_i()),
Operand::Int(nan_result.to_i())}) &&
push_function_inst(spv::Op::OpLogicalNot,
{Operand::Int(result_type_id), result,
Operand::Int(or_result.to_i())})) {
return result_id;
}
return 0;
}
case BuiltinType::kIsNormal: {
// A normal number is finite, non-zero, and not subnormal.
// Its exponent is neither of the extreme possible values.
// Implemented as:
// exponent_bits = bitcast<u32>(f);
// clamped = uclamp(1,254,exponent_bits);
// result = (clamped == exponent_bits);
//
auto val_id = get_arg_as_value_id(0);
if (!val_id) {
return 0;
}
// These parameters are valid for IEEE 754 binary32
const uint32_t kExponentMask = 0x7f80000;
const uint32_t kMinNormalExponent = 0x0080000;
const uint32_t kMaxNormalExponent = 0x7f00000;
auto set_id = GetGLSLstd450Import();
auto* u32 = builder_.create<sem::U32>();
auto unsigned_id = GenerateTypeIfNeeded(u32);
auto exponent_mask_id =
GenerateConstantIfNeeded(ScalarConstant::U32(kExponentMask));
auto min_exponent_id =
GenerateConstantIfNeeded(ScalarConstant::U32(kMinNormalExponent));
auto max_exponent_id =
GenerateConstantIfNeeded(ScalarConstant::U32(kMaxNormalExponent));
if (auto* fvec_ty = builtin->ReturnType()->As<sem::Vector>()) {
// In the vector case, update the unsigned type to a vector type of the
// same size, and create vector constants by replicating the scalars.
// I expect backend compilers to fold these into unique constants, so
// there is no loss of efficiency.
auto* uvec_ty = builder_.create<sem::Vector>(u32, fvec_ty->Width());
unsigned_id = GenerateTypeIfNeeded(uvec_ty);
auto splat = [&](uint32_t scalar_id) -> uint32_t {
auto splat_result = result_op();
OperandList splat_params{Operand::Int(unsigned_id), splat_result};
for (size_t i = 0; i < fvec_ty->Width(); i++) {
splat_params.emplace_back(Operand::Int(scalar_id));
}
if (!push_function_inst(spv::Op::OpCompositeConstruct,
std::move(splat_params))) {
return 0;
}
return splat_result.to_i();
};
exponent_mask_id = splat(exponent_mask_id);
min_exponent_id = splat(min_exponent_id);
max_exponent_id = splat(max_exponent_id);
}
auto cast_result = result_op();
auto exponent_bits_result = result_op();
auto clamp_result = result_op();
if (set_id && unsigned_id && exponent_mask_id && min_exponent_id &&
max_exponent_id &&
push_function_inst(
spv::Op::OpBitcast,
{Operand::Int(unsigned_id), cast_result, Operand::Int(val_id)}) &&
push_function_inst(spv::Op::OpBitwiseAnd,
{Operand::Int(unsigned_id), exponent_bits_result,
Operand::Int(cast_result.to_i()),
Operand::Int(exponent_mask_id)}) &&
push_function_inst(
spv::Op::OpExtInst,
{Operand::Int(unsigned_id), clamp_result, Operand::Int(set_id),
Operand::Int(GLSLstd450UClamp),
Operand::Int(exponent_bits_result.to_i()),
Operand::Int(min_exponent_id), Operand::Int(max_exponent_id)}) &&
push_function_inst(spv::Op::OpIEqual,
{Operand::Int(result_type_id), result,
Operand::Int(exponent_bits_result.to_i()),
Operand::Int(clamp_result.to_i())})) {
return result_id;
}
return 0;
}
case BuiltinType::kMix: {
auto std450 = Operand::Int(GetGLSLstd450Import());

View File

@@ -102,225 +102,6 @@ INSTANTIATE_TEST_SUITE_P(BuiltinBuilderTest,
testing::Values(BuiltinData{"any", "OpAny"},
BuiltinData{"all", "OpAll"}));
using BuiltinFloatTest = BuiltinBuilderTestWithParam<BuiltinData>;
TEST_P(BuiltinFloatTest, Call_Float_Scalar) {
auto param = GetParam();
auto* var = Global("v", ty.f32(), ast::StorageClass::kPrivate);
auto* expr = Call(param.name, "v");
auto* func = Func("a_func", {}, ty.void_(),
{
Assign(Phony(), expr),
});
spirv::Builder& b = Build();
ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeFloat 32
%2 = OpTypePointer Private %3
%4 = OpConstantNull %3
%1 = OpVariable %2 Private %4
%6 = OpTypeVoid
%5 = OpTypeFunction %6
%10 = OpTypeBool
)");
auto expected = utils::ReplaceAll(R"(%11 = OpLoad %3 %1
%9 = ${op} %10 %11
OpReturn
)",
"${op}", param.op);
EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), expected);
}
TEST_P(BuiltinFloatTest, Call_Float_Vector) {
auto param = GetParam();
auto* var = Global("v", ty.vec3<f32>(), ast::StorageClass::kPrivate);
auto* expr = Call(param.name, "v");
auto* func = Func("a_func", {}, ty.void_(),
{
Assign(Phony(), expr),
});
spirv::Builder& b = Build();
ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32
%3 = OpTypeVector %4 3
%2 = OpTypePointer Private %3
%5 = OpConstantNull %3
%1 = OpVariable %2 Private %5
%7 = OpTypeVoid
%6 = OpTypeFunction %7
%12 = OpTypeBool
%11 = OpTypeVector %12 3
)");
auto expected = utils::ReplaceAll(R"(%13 = OpLoad %3 %1
%10 = ${op} %11 %13
OpReturn
)",
"${op}", param.op);
EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), expected);
}
INSTANTIATE_TEST_SUITE_P(BuiltinBuilderTest,
BuiltinFloatTest,
testing::Values(BuiltinData{"isNan", "OpIsNan"},
BuiltinData{"isInf", "OpIsInf"}));
TEST_F(BuiltinBuilderTest, IsFinite_Scalar) {
auto* var = Global("v", ty.f32(), ast::StorageClass::kPrivate);
auto* expr = Call("isFinite", "v");
auto* func = Func("a_func", {}, ty.void_(),
{
Assign(Phony(), expr),
});
spirv::Builder& b = Build();
ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeFloat 32
%2 = OpTypePointer Private %3
%4 = OpConstantNull %3
%1 = OpVariable %2 Private %4
%6 = OpTypeVoid
%5 = OpTypeFunction %6
%10 = OpTypeBool
)");
EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
R"(%11 = OpLoad %3 %1
%12 = OpIsInf %10 %11
%13 = OpIsNan %10 %11
%14 = OpLogicalOr %10 %12 %13
%9 = OpLogicalNot %10 %14
OpReturn
)");
}
TEST_F(BuiltinBuilderTest, IsFinite_Vector) {
auto* var = Global("v", ty.vec3<f32>(), ast::StorageClass::kPrivate);
auto* expr = Call("isFinite", "v");
auto* func = Func("a_func", {}, ty.void_(),
{
Assign(Phony(), expr),
});
spirv::Builder& b = Build();
ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32
%3 = OpTypeVector %4 3
%2 = OpTypePointer Private %3
%5 = OpConstantNull %3
%1 = OpVariable %2 Private %5
%7 = OpTypeVoid
%6 = OpTypeFunction %7
%12 = OpTypeBool
%11 = OpTypeVector %12 3
)");
EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
R"(%13 = OpLoad %3 %1
%14 = OpIsInf %11 %13
%15 = OpIsNan %11 %13
%16 = OpLogicalOr %11 %14 %15
%10 = OpLogicalNot %11 %16
OpReturn
)");
}
TEST_F(BuiltinBuilderTest, IsNormal_Scalar) {
auto* var = Global("v", ty.f32(), ast::StorageClass::kPrivate);
auto* expr = Call("isNormal", "v");
auto* func = Func("a_func", {}, ty.void_(),
{
Assign(Phony(), expr),
});
spirv::Builder& b = Build();
ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
auto got = DumpBuilder(b);
EXPECT_EQ(got, R"(%12 = OpExtInstImport "GLSL.std.450"
OpName %1 "v"
OpName %7 "a_func"
%3 = OpTypeFloat 32
%2 = OpTypePointer Private %3
%4 = OpConstantNull %3
%1 = OpVariable %2 Private %4
%6 = OpTypeVoid
%5 = OpTypeFunction %6
%10 = OpTypeBool
%13 = OpTypeInt 32 0
%14 = OpConstant %13 133693440
%15 = OpConstant %13 524288
%16 = OpConstant %13 133169152
%7 = OpFunction %6 None %5
%8 = OpLabel
%11 = OpLoad %3 %1
%17 = OpBitcast %13 %11
%18 = OpBitwiseAnd %13 %17 %14
%19 = OpExtInst %13 %12 UClamp %18 %15 %16
%9 = OpIEqual %10 %18 %19
OpReturn
OpFunctionEnd
)");
}
TEST_F(BuiltinBuilderTest, IsNormal_Vector) {
auto* var = Global("v", ty.vec2<f32>(), ast::StorageClass::kPrivate);
auto* expr = Call("isNormal", "v");
auto* func = Func("a_func", {}, ty.void_(),
{
Assign(Phony(), expr),
});
spirv::Builder& b = Build();
ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
auto got = DumpBuilder(b);
EXPECT_EQ(got, R"(%14 = OpExtInstImport "GLSL.std.450"
OpName %1 "v"
OpName %8 "a_func"
%4 = OpTypeFloat 32
%3 = OpTypeVector %4 2
%2 = OpTypePointer Private %3
%5 = OpConstantNull %3
%1 = OpVariable %2 Private %5
%7 = OpTypeVoid
%6 = OpTypeFunction %7
%12 = OpTypeBool
%11 = OpTypeVector %12 2
%15 = OpTypeInt 32 0
%16 = OpConstant %15 133693440
%17 = OpConstant %15 524288
%18 = OpConstant %15 133169152
%19 = OpTypeVector %15 2
%8 = OpFunction %7 None %6
%9 = OpLabel
%13 = OpLoad %3 %1
%20 = OpCompositeConstruct %19 %16 %16
%21 = OpCompositeConstruct %19 %17 %17
%22 = OpCompositeConstruct %19 %18 %18
%23 = OpBitcast %19 %13
%24 = OpBitwiseAnd %19 %23 %20
%25 = OpExtInst %19 %14 UClamp %24 %21 %22
%10 = OpIEqual %11 %24 %25
OpReturn
OpFunctionEnd
)");
}
using BuiltinIntTest = BuiltinBuilderTestWithParam<BuiltinData>;
TEST_P(BuiltinIntTest, Call_SInt_Scalar) {
auto param = GetParam();