intrinsics: Remove deprecated modf & frexp overloads

These have been deprecated for multiple chrome releases.

Change-Id: I4cc05a74ff8f085e6d13f93aefb93077480e52f5
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/66261
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: James Price <jrprice@google.com>
Commit-Queue: Ben Clayton <bclayton@google.com>
This commit is contained in:
Ben Clayton
2021-10-12 21:57:47 +00:00
committed by Tint LUCI CQ
parent d57a129810
commit 2aa6855914
212 changed files with 2712 additions and 11621 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -16,6 +16,7 @@
#include "gmock/gmock.h"
#include "src/program_builder.h"
#include "src/sem/atomic_type.h"
#include "src/sem/depth_multisampled_texture_type.h"
#include "src/sem/depth_texture_type.h"
#include "src/sem/external_texture_type.h"
@@ -211,22 +212,24 @@ TEST_F(IntrinsicTableTest, MismatchBool) {
}
TEST_F(IntrinsicTableTest, MatchPointer) {
auto* f32 = create<sem::F32>();
auto* ptr = create<sem::Pointer>(f32, ast::StorageClass::kFunction,
auto* i32 = create<sem::I32>();
auto* atomicI32 = create<sem::Atomic>(i32);
auto* ptr = create<sem::Pointer>(atomicI32, ast::StorageClass::kWorkgroup,
ast::Access::kReadWrite);
auto* result = table->Lookup(IntrinsicType::kModf, {f32, ptr}, Source{});
auto* result = table->Lookup(IntrinsicType::kAtomicLoad, {ptr}, Source{});
ASSERT_NE(result, nullptr) << Diagnostics().str();
ASSERT_EQ(Diagnostics().str(), "");
EXPECT_THAT(result->Type(), IntrinsicType::kModf);
EXPECT_THAT(result->ReturnType(), f32);
ASSERT_EQ(result->Parameters().size(), 2u);
EXPECT_EQ(result->Parameters()[0]->Type(), f32);
EXPECT_EQ(result->Parameters()[1]->Type(), ptr);
EXPECT_THAT(result->Type(), IntrinsicType::kAtomicLoad);
EXPECT_THAT(result->ReturnType(), i32);
ASSERT_EQ(result->Parameters().size(), 1u);
EXPECT_EQ(result->Parameters()[0]->Type(), ptr);
}
TEST_F(IntrinsicTableTest, MismatchPointer) {
auto* f32 = create<sem::F32>();
auto* result = table->Lookup(IntrinsicType::kModf, {f32, f32}, Source{});
auto* i32 = create<sem::I32>();
auto* atomicI32 = create<sem::Atomic>(i32);
auto* result =
table->Lookup(IntrinsicType::kAtomicLoad, {atomicI32}, Source{});
ASSERT_EQ(result, nullptr);
ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call"));
}

View File

@@ -314,8 +314,6 @@ fn fma(f32, f32, f32) -> f32
fn fma<N: num>(vec<N, f32>, vec<N, f32>, vec<N, f32>) -> vec<N, f32>
fn fract(f32) -> f32
fn fract<N: num>(vec<N, f32>) -> vec<N, f32>
[[deprecated]] fn frexp<S: function_private_workgroup, A: access>(f32, ptr<S, i32, A>) -> f32
[[deprecated]] fn frexp<N: num, S: function_private_workgroup, A: access>(vec<N, f32>, ptr<S, vec<N, i32>, A>) -> vec<N, f32>
fn frexp(f32) -> _frexp_result
fn frexp<N: num>(vec<N, f32>) -> _frexp_result_vec<N>
[[stage("fragment")]] fn fwidth(f32) -> f32
@@ -350,8 +348,6 @@ fn min<N: num, T: fiu32>(vec<N, T>, vec<N, T>) -> vec<N, T>
fn mix(f32, f32, f32) -> f32
fn mix<N: num>(vec<N, f32>, vec<N, f32>, vec<N, f32>) -> vec<N, f32>
fn mix<N: num>(vec<N, f32>, vec<N, f32>, f32) -> vec<N, f32>
[[deprecated]] fn modf<S: function_private_workgroup, A: access>(f32, ptr<S, f32, A>) -> f32
[[deprecated]] fn modf<N: num, S: function_private_workgroup, A: access>(vec<N, f32>, ptr<S, vec<N, f32>, A>) -> vec<N, f32>
fn modf(f32) -> _modf_result
fn modf<N: num>(vec<N, f32>) -> _modf_result_vec<N>
fn normalize<N: num>(vec<N, f32>) -> vec<N, f32>

View File

@@ -766,87 +766,131 @@ TEST_F(ResolverBuiltinsValidationTest, Determinant_Mat4x4) {
}
TEST_F(ResolverBuiltinsValidationTest, Frexp_Scalar) {
auto* a = Var("a", ty.i32());
auto* builtin = Call("frexp", 1.0f, AddressOf(Expr("a")));
WrapInFunction(Decl(a), builtin);
auto* builtin = Call("frexp", 1.0f);
WrapInFunction(builtin);
EXPECT_TRUE(r()->Resolve()) << r()->error();
EXPECT_TRUE(TypeOf(builtin)->Is<sem::F32>());
EXPECT_TRUE(TypeOf(builtin->params()[1])->Is<sem::Pointer>());
auto* res_ty = TypeOf(builtin)->As<sem::Struct>();
ASSERT_TRUE(res_ty != nullptr);
auto& members = res_ty->Members();
ASSERT_EQ(members.size(), 2u);
EXPECT_TRUE(members[0]->Type()->Is<sem::F32>());
EXPECT_TRUE(members[1]->Type()->Is<sem::I32>());
}
TEST_F(ResolverBuiltinsValidationTest, Frexp_Vec2) {
auto* a = Var("a", ty.vec2<int>());
auto* builtin = Call("frexp", vec2<f32>(1.0f, 1.0f), AddressOf(Expr("a")));
WrapInFunction(Decl(a), builtin);
auto* builtin = Call("frexp", vec2<f32>(1.0f, 1.0f));
WrapInFunction(builtin);
EXPECT_TRUE(r()->Resolve()) << r()->error();
EXPECT_TRUE(TypeOf(builtin)->is_float_vector());
EXPECT_TRUE(TypeOf(builtin->params()[1])->Is<sem::Pointer>());
auto* res_ty = TypeOf(builtin)->As<sem::Struct>();
ASSERT_TRUE(res_ty != nullptr);
auto& members = res_ty->Members();
ASSERT_EQ(members.size(), 2u);
ASSERT_TRUE(members[0]->Type()->Is<sem::Vector>());
ASSERT_TRUE(members[1]->Type()->Is<sem::Vector>());
EXPECT_EQ(members[0]->Type()->As<sem::Vector>()->Width(), 2u);
EXPECT_TRUE(members[0]->Type()->As<sem::Vector>()->type()->Is<sem::F32>());
EXPECT_EQ(members[1]->Type()->As<sem::Vector>()->Width(), 2u);
EXPECT_TRUE(members[1]->Type()->As<sem::Vector>()->type()->Is<sem::I32>());
}
TEST_F(ResolverBuiltinsValidationTest, Frexp_Vec3) {
auto* a = Var("a", ty.vec3<int>());
auto* builtin =
Call("frexp", vec3<f32>(1.0f, 1.0f, 1.0f), AddressOf(Expr("a")));
WrapInFunction(Decl(a), builtin);
auto* builtin = Call("frexp", vec3<f32>(1.0f, 1.0f, 1.0f));
WrapInFunction(builtin);
EXPECT_TRUE(r()->Resolve()) << r()->error();
EXPECT_TRUE(TypeOf(builtin)->is_float_vector());
EXPECT_TRUE(TypeOf(builtin->params()[1])->Is<sem::Pointer>());
auto* res_ty = TypeOf(builtin)->As<sem::Struct>();
ASSERT_TRUE(res_ty != nullptr);
auto& members = res_ty->Members();
ASSERT_EQ(members.size(), 2u);
ASSERT_TRUE(members[0]->Type()->Is<sem::Vector>());
ASSERT_TRUE(members[1]->Type()->Is<sem::Vector>());
EXPECT_EQ(members[0]->Type()->As<sem::Vector>()->Width(), 3u);
EXPECT_TRUE(members[0]->Type()->As<sem::Vector>()->type()->Is<sem::F32>());
EXPECT_EQ(members[1]->Type()->As<sem::Vector>()->Width(), 3u);
EXPECT_TRUE(members[1]->Type()->As<sem::Vector>()->type()->Is<sem::I32>());
}
TEST_F(ResolverBuiltinsValidationTest, Frexp_Vec4) {
auto* a = Var("a", ty.vec4<int>());
auto* builtin =
Call("frexp", vec4<f32>(1.0f, 1.0f, 1.0f, 1.0f), AddressOf(Expr("a")));
WrapInFunction(Decl(a), builtin);
auto* builtin = Call("frexp", vec4<f32>(1.0f, 1.0f, 1.0f, 1.0f));
WrapInFunction(builtin);
EXPECT_TRUE(r()->Resolve()) << r()->error();
EXPECT_TRUE(TypeOf(builtin)->is_float_vector());
EXPECT_TRUE(TypeOf(builtin->params()[1])->Is<sem::Pointer>());
auto* res_ty = TypeOf(builtin)->As<sem::Struct>();
ASSERT_TRUE(res_ty != nullptr);
auto& members = res_ty->Members();
ASSERT_EQ(members.size(), 2u);
ASSERT_TRUE(members[0]->Type()->Is<sem::Vector>());
ASSERT_TRUE(members[1]->Type()->Is<sem::Vector>());
EXPECT_EQ(members[0]->Type()->As<sem::Vector>()->Width(), 4u);
EXPECT_TRUE(members[0]->Type()->As<sem::Vector>()->type()->Is<sem::F32>());
EXPECT_EQ(members[1]->Type()->As<sem::Vector>()->Width(), 4u);
EXPECT_TRUE(members[1]->Type()->As<sem::Vector>()->type()->Is<sem::I32>());
}
TEST_F(ResolverBuiltinsValidationTest, Modf_Scalar) {
auto* a = Var("a", ty.f32());
auto* builtin = Call("modf", 1.0f, AddressOf(Expr("a")));
WrapInFunction(Decl(a), builtin);
auto* builtin = Call("modf", 1.0f);
WrapInFunction(builtin);
EXPECT_TRUE(r()->Resolve()) << r()->error();
EXPECT_TRUE(TypeOf(builtin)->Is<sem::F32>());
EXPECT_TRUE(TypeOf(builtin->params()[1])->Is<sem::Pointer>());
auto* res_ty = TypeOf(builtin)->As<sem::Struct>();
ASSERT_TRUE(res_ty != nullptr);
auto& members = res_ty->Members();
ASSERT_EQ(members.size(), 2u);
EXPECT_TRUE(members[0]->Type()->Is<sem::F32>());
EXPECT_TRUE(members[1]->Type()->Is<sem::F32>());
}
TEST_F(ResolverBuiltinsValidationTest, Modf_Vec2) {
auto* a = Var("a", ty.vec2<f32>());
auto* builtin = Call("modf", vec2<f32>(1.0f, 1.0f), AddressOf(Expr("a")));
WrapInFunction(Decl(a), builtin);
auto* builtin = Call("modf", vec2<f32>(1.0f, 1.0f));
WrapInFunction(builtin);
EXPECT_TRUE(r()->Resolve()) << r()->error();
EXPECT_TRUE(TypeOf(builtin)->is_float_vector());
EXPECT_TRUE(TypeOf(builtin->params()[1])->Is<sem::Pointer>());
auto* res_ty = TypeOf(builtin)->As<sem::Struct>();
ASSERT_TRUE(res_ty != nullptr);
auto& members = res_ty->Members();
ASSERT_EQ(members.size(), 2u);
ASSERT_TRUE(members[0]->Type()->Is<sem::Vector>());
ASSERT_TRUE(members[1]->Type()->Is<sem::Vector>());
EXPECT_EQ(members[0]->Type()->As<sem::Vector>()->Width(), 2u);
EXPECT_TRUE(members[0]->Type()->As<sem::Vector>()->type()->Is<sem::F32>());
EXPECT_EQ(members[1]->Type()->As<sem::Vector>()->Width(), 2u);
EXPECT_TRUE(members[1]->Type()->As<sem::Vector>()->type()->Is<sem::F32>());
}
TEST_F(ResolverBuiltinsValidationTest, Modf_Vec3) {
auto* a = Var("a", ty.vec3<f32>());
auto* builtin =
Call("modf", vec3<f32>(1.0f, 1.0f, 1.0f), AddressOf(Expr("a")));
WrapInFunction(Decl(a), builtin);
auto* builtin = Call("modf", vec3<f32>(1.0f, 1.0f, 1.0f));
WrapInFunction(builtin);
EXPECT_TRUE(r()->Resolve()) << r()->error();
EXPECT_TRUE(TypeOf(builtin)->is_float_vector());
EXPECT_TRUE(TypeOf(builtin->params()[1])->Is<sem::Pointer>());
auto* res_ty = TypeOf(builtin)->As<sem::Struct>();
ASSERT_TRUE(res_ty != nullptr);
auto& members = res_ty->Members();
ASSERT_EQ(members.size(), 2u);
ASSERT_TRUE(members[0]->Type()->Is<sem::Vector>());
ASSERT_TRUE(members[1]->Type()->Is<sem::Vector>());
EXPECT_EQ(members[0]->Type()->As<sem::Vector>()->Width(), 3u);
EXPECT_TRUE(members[0]->Type()->As<sem::Vector>()->type()->Is<sem::F32>());
EXPECT_EQ(members[1]->Type()->As<sem::Vector>()->Width(), 3u);
EXPECT_TRUE(members[1]->Type()->As<sem::Vector>()->type()->Is<sem::F32>());
}
TEST_F(ResolverBuiltinsValidationTest, Modf_Vec4) {
auto* a = Var("a", ty.vec4<f32>());
auto* builtin =
Call("modf", vec4<f32>(1.0f, 1.0f, 1.0f, 1.0f), AddressOf(Expr("a")));
WrapInFunction(Decl(a), builtin);
auto* builtin = Call("modf", vec4<f32>(1.0f, 1.0f, 1.0f, 1.0f));
WrapInFunction(builtin);
EXPECT_TRUE(r()->Resolve()) << r()->error();
EXPECT_TRUE(TypeOf(builtin)->is_float_vector());
EXPECT_TRUE(TypeOf(builtin->params()[1])->Is<sem::Pointer>());
auto* res_ty = TypeOf(builtin)->As<sem::Struct>();
ASSERT_TRUE(res_ty != nullptr);
auto& members = res_ty->Members();
ASSERT_EQ(members.size(), 2u);
ASSERT_TRUE(members[0]->Type()->Is<sem::Vector>());
ASSERT_TRUE(members[1]->Type()->Is<sem::Vector>());
EXPECT_EQ(members[0]->Type()->As<sem::Vector>()->Width(), 4u);
EXPECT_TRUE(members[0]->Type()->As<sem::Vector>()->type()->Is<sem::F32>());
EXPECT_EQ(members[1]->Type()->As<sem::Vector>()->Width(), 4u);
EXPECT_TRUE(members[1]->Type()->As<sem::Vector>()->type()->Is<sem::F32>());
}
TEST_F(ResolverBuiltinsValidationTest, Cross_Float_Vec3) {

View File

@@ -828,29 +828,6 @@ TEST_F(ResolverIntrinsicDataTest, Normalize_Error_NoParams) {
)");
}
TEST_F(ResolverIntrinsicDataTest, DEPRECATED_FrexpScalar) {
Global("exp", ty.i32(), ast::StorageClass::kWorkgroup);
auto* call = Call("frexp", 1.0f, AddressOf("exp"));
WrapInFunction(call);
EXPECT_TRUE(r()->Resolve()) << r()->error();
ASSERT_NE(TypeOf(call), nullptr);
EXPECT_TRUE(TypeOf(call)->Is<sem::F32>());
}
TEST_F(ResolverIntrinsicDataTest, DEPRECATED_FrexpVector) {
Global("exp", ty.vec3<i32>(), ast::StorageClass::kWorkgroup);
auto* call = Call("frexp", vec3<f32>(1.0f, 2.0f, 3.0f), AddressOf("exp"));
WrapInFunction(call);
EXPECT_TRUE(r()->Resolve()) << r()->error();
ASSERT_NE(TypeOf(call), nullptr);
EXPECT_TRUE(TypeOf(call)->Is<sem::Vector>());
EXPECT_TRUE(TypeOf(call)->As<sem::Vector>()->type()->Is<sem::F32>());
}
TEST_F(ResolverIntrinsicDataTest, FrexpScalar) {
auto* call = Call("frexp", 1.0f);
WrapInFunction(call);
@@ -924,9 +901,7 @@ TEST_F(ResolverIntrinsicDataTest, Frexp_Error_FirstParamInt) {
r()->error(),
R"(error: no matching call to frexp(i32, ptr<workgroup, i32, read_write>)
4 candidate functions:
frexp(f32, ptr<S, i32, A>) -> f32 where: S is function, private or workgroup
frexp(vecN<f32>, ptr<S, vecN<i32>, A>) -> vecN<f32> where: S is function, private or workgroup
2 candidate functions:
frexp(f32) -> _frexp_result
frexp(vecN<f32>) -> _frexp_result_vecN
)");
@@ -943,10 +918,8 @@ TEST_F(ResolverIntrinsicDataTest, Frexp_Error_SecondParamFloatPtr) {
r()->error(),
R"(error: no matching call to frexp(f32, ptr<workgroup, f32, read_write>)
4 candidate functions:
frexp(f32, ptr<S, i32, A>) -> f32 where: S is function, private or workgroup
2 candidate functions:
frexp(f32) -> _frexp_result
frexp(vecN<f32>, ptr<S, vecN<i32>, A>) -> vecN<f32> where: S is function, private or workgroup
frexp(vecN<f32>) -> _frexp_result_vecN
)");
}
@@ -959,10 +932,8 @@ TEST_F(ResolverIntrinsicDataTest, Frexp_Error_SecondParamNotAPointer) {
EXPECT_EQ(r()->error(), R"(error: no matching call to frexp(f32, i32)
4 candidate functions:
frexp(f32, ptr<S, i32, A>) -> f32 where: S is function, private or workgroup
2 candidate functions:
frexp(f32) -> _frexp_result
frexp(vecN<f32>, ptr<S, vecN<i32>, A>) -> vecN<f32> where: S is function, private or workgroup
frexp(vecN<f32>) -> _frexp_result_vecN
)");
}
@@ -978,37 +949,12 @@ TEST_F(ResolverIntrinsicDataTest, Frexp_Error_VectorSizesDontMatch) {
r()->error(),
R"(error: no matching call to frexp(vec2<f32>, ptr<workgroup, vec4<i32>, read_write>)
4 candidate functions:
frexp(vecN<f32>, ptr<S, vecN<i32>, A>) -> vecN<f32> where: S is function, private or workgroup
2 candidate functions:
frexp(vecN<f32>) -> _frexp_result_vecN
frexp(f32, ptr<S, i32, A>) -> f32 where: S is function, private or workgroup
frexp(f32) -> _frexp_result
)");
}
TEST_F(ResolverIntrinsicDataTest, DEPRECATED_ModfScalar) {
Global("whole", ty.f32(), ast::StorageClass::kWorkgroup);
auto* call = Call("modf", 1.0f, AddressOf("whole"));
WrapInFunction(call);
EXPECT_TRUE(r()->Resolve()) << r()->error();
ASSERT_NE(TypeOf(call), nullptr);
EXPECT_TRUE(TypeOf(call)->Is<sem::F32>());
}
TEST_F(ResolverIntrinsicDataTest, DEPRECATED_ModfVector) {
Global("whole", ty.vec3<f32>(), ast::StorageClass::kWorkgroup);
auto* call = Call("modf", vec3<f32>(1.0f, 2.0f, 3.0f), AddressOf("whole"));
WrapInFunction(call);
EXPECT_TRUE(r()->Resolve()) << r()->error();
ASSERT_NE(TypeOf(call), nullptr);
EXPECT_TRUE(TypeOf(call)->Is<sem::Vector>());
EXPECT_TRUE(TypeOf(call)->As<sem::Vector>()->type()->Is<sem::F32>());
}
TEST_F(ResolverIntrinsicDataTest, ModfScalar) {
auto* call = Call("modf", 1.0f);
WrapInFunction(call);
@@ -1082,9 +1028,7 @@ TEST_F(ResolverIntrinsicDataTest, Modf_Error_FirstParamInt) {
r()->error(),
R"(error: no matching call to modf(i32, ptr<workgroup, f32, read_write>)
4 candidate functions:
modf(f32, ptr<S, f32, A>) -> f32 where: S is function, private or workgroup
modf(vecN<f32>, ptr<S, vecN<f32>, A>) -> vecN<f32> where: S is function, private or workgroup
2 candidate functions:
modf(f32) -> _modf_result
modf(vecN<f32>) -> _modf_result_vecN
)");
@@ -1101,10 +1045,8 @@ TEST_F(ResolverIntrinsicDataTest, Modf_Error_SecondParamIntPtr) {
r()->error(),
R"(error: no matching call to modf(f32, ptr<workgroup, i32, read_write>)
4 candidate functions:
modf(f32, ptr<S, f32, A>) -> f32 where: S is function, private or workgroup
2 candidate functions:
modf(f32) -> _modf_result
modf(vecN<f32>, ptr<S, vecN<f32>, A>) -> vecN<f32> where: S is function, private or workgroup
modf(vecN<f32>) -> _modf_result_vecN
)");
}
@@ -1117,10 +1059,8 @@ TEST_F(ResolverIntrinsicDataTest, Modf_Error_SecondParamNotAPointer) {
EXPECT_EQ(r()->error(), R"(error: no matching call to modf(f32, f32)
4 candidate functions:
modf(f32, ptr<S, f32, A>) -> f32 where: S is function, private or workgroup
2 candidate functions:
modf(f32) -> _modf_result
modf(vecN<f32>, ptr<S, vecN<f32>, A>) -> vecN<f32> where: S is function, private or workgroup
modf(vecN<f32>) -> _modf_result_vecN
)");
}
@@ -1136,10 +1076,8 @@ TEST_F(ResolverIntrinsicDataTest, Modf_Error_VectorSizesDontMatch) {
r()->error(),
R"(error: no matching call to modf(vec2<f32>, ptr<workgroup, vec4<f32>, read_write>)
4 candidate functions:
modf(vecN<f32>, ptr<S, vecN<f32>, A>) -> vecN<f32> where: S is function, private or workgroup
2 candidate functions:
modf(vecN<f32>) -> _modf_result_vecN
modf(f32, ptr<S, f32, A>) -> f32 where: S is function, private or workgroup
modf(f32) -> _modf_result
)");
}

View File

@@ -297,6 +297,7 @@ TEST_F(GlslGeneratorImplTest_Intrinsic, Select_Vector) {
EXPECT_EQ(out.str(), "(bvec2(true, false) ? ivec2(3, 4) : ivec2(1, 2))");
}
#if 0
TEST_F(GlslGeneratorImplTest_Intrinsic, Modf_Scalar) {
auto* res = Var("res", ty.f32());
auto* call = Call("modf", 1.0f, AddressOf(res));
@@ -319,7 +320,6 @@ TEST_F(GlslGeneratorImplTest_Intrinsic, Modf_Vector) {
EXPECT_THAT(gen.result(), HasSubstr("modf(vec3(0.0f, 0.0f, 0.0f), res)"));
}
#if 0
TEST_F(GlslGeneratorImplTest_Intrinsic, Frexp_Scalar_i32) {
auto* exp = Var("exp", ty.i32());
auto* call = Call("frexp", 1.0f, AddressOf(exp));

View File

@@ -1366,120 +1366,71 @@ bool GeneratorImpl::EmitSelectCall(std::ostream& out,
bool GeneratorImpl::EmitModfCall(std::ostream& out,
ast::CallExpression* expr,
const sem::Intrinsic* intrinsic) {
if (expr->params().size() == 1) {
return CallIntrinsicHelper(
out, expr, intrinsic,
[&](TextBuffer* b, const std::vector<std::string>& params) {
auto* ty = intrinsic->Parameters()[0]->Type();
auto in = params[0];
return CallIntrinsicHelper(
out, expr, intrinsic,
[&](TextBuffer* b, const std::vector<std::string>& params) {
auto* ty = intrinsic->Parameters()[0]->Type();
auto in = params[0];
std::string width;
if (auto* vec = ty->As<sem::Vector>()) {
width = std::to_string(vec->Width());
}
std::string width;
if (auto* vec = ty->As<sem::Vector>()) {
width = std::to_string(vec->Width());
}
// Emit the builtin return type unique to this overload. This does not
// exist in the AST, so it will not be generated in Generate().
if (!EmitStructType(&helpers_,
intrinsic->ReturnType()->As<sem::Struct>())) {
// Emit the builtin return type unique to this overload. This does not
// exist in the AST, so it will not be generated in Generate().
if (!EmitStructType(&helpers_,
intrinsic->ReturnType()->As<sem::Struct>())) {
return false;
}
line(b) << "float" << width << " whole;";
line(b) << "float" << width << " fract = modf(" << in << ", whole);";
{
auto l = line(b);
if (!EmitType(l, intrinsic->ReturnType(), ast::StorageClass::kNone,
ast::Access::kUndefined, "")) {
return false;
}
line(b) << "float" << width << " whole;";
line(b) << "float" << width << " fract = modf(" << in << ", whole);";
{
auto l = line(b);
if (!EmitType(l, intrinsic->ReturnType(), ast::StorageClass::kNone,
ast::Access::kUndefined, "")) {
return false;
}
l << " result = {fract, whole};";
}
line(b) << "return result;";
return true;
});
}
// DEPRECATED
out << "modf";
ScopedParen sp(out);
if (!EmitExpression(out, expr->params()[0])) {
return false;
}
out << ", ";
if (!EmitExpression(out, expr->params()[1])) {
return false;
}
return true;
l << " result = {fract, whole};";
}
line(b) << "return result;";
return true;
});
}
bool GeneratorImpl::EmitFrexpCall(std::ostream& out,
ast::CallExpression* expr,
const sem::Intrinsic* intrinsic) {
if (expr->params().size() == 1) {
return CallIntrinsicHelper(
out, expr, intrinsic,
[&](TextBuffer* b, const std::vector<std::string>& params) {
auto* ty = intrinsic->Parameters()[0]->Type();
auto in = params[0];
std::string width;
if (auto* vec = ty->As<sem::Vector>()) {
width = std::to_string(vec->Width());
}
// Emit the builtin return type unique to this overload. This does not
// exist in the AST, so it will not be generated in Generate().
if (!EmitStructType(&helpers_,
intrinsic->ReturnType()->As<sem::Struct>())) {
return false;
}
line(b) << "float" << width << " exp;";
line(b) << "float" << width << " sig = frexp(" << in << ", exp);";
{
auto l = line(b);
if (!EmitType(l, intrinsic->ReturnType(), ast::StorageClass::kNone,
ast::Access::kUndefined, "")) {
return false;
}
l << " result = {sig, int" << width << "(exp)};";
}
line(b) << "return result;";
return true;
});
}
// DEPRECATED
// Exponent is an integer in WGSL, but HLSL wants a float.
// We need to make the call with a temporary float, and then cast.
return CallIntrinsicHelper(
out, expr, intrinsic,
[&](TextBuffer* b, const std::vector<std::string>& params) {
auto* significand_ty = intrinsic->Parameters()[0]->Type();
auto significand = params[0];
auto* exponent_ty = intrinsic->Parameters()[1]->Type();
auto exponent = params[1];
auto* ty = intrinsic->Parameters()[0]->Type();
auto in = params[0];
std::string width;
if (auto* vec = significand_ty->As<sem::Vector>()) {
if (auto* vec = ty->As<sem::Vector>()) {
width = std::to_string(vec->Width());
}
// Exponent is an integer, which HLSL does not have an overload for.
// We need to cast from a float.
line(b) << "float" << width << " float_exp;";
line(b) << "float" << width << " significand = frexp(" << significand
<< ", float_exp);";
// Emit the builtin return type unique to this overload. This does not
// exist in the AST, so it will not be generated in Generate().
if (!EmitStructType(&helpers_,
intrinsic->ReturnType()->As<sem::Struct>())) {
return false;
}
line(b) << "float" << width << " exp;";
line(b) << "float" << width << " sig = frexp(" << in << ", exp);";
{
auto l = line(b);
l << exponent << " = ";
if (!EmitType(l, exponent_ty->UnwrapPtr(), ast::StorageClass::kNone,
if (!EmitType(l, intrinsic->ReturnType(), ast::StorageClass::kNone,
ast::Access::kUndefined, "")) {
return false;
}
l << "(float_exp);";
l << " result = {sig, int" << width << "(exp)};";
}
line(b) << "return significand;";
line(b) << "return result;";
return true;
});
}

View File

@@ -298,72 +298,104 @@ TEST_F(HlslGeneratorImplTest_Intrinsic, Select_Vector) {
}
TEST_F(HlslGeneratorImplTest_Intrinsic, Modf_Scalar) {
auto* res = Var("res", ty.f32());
auto* call = Call("modf", 1.0f, AddressOf(res));
WrapInFunction(res, call);
auto* call = Call("modf", 1.0f);
WrapInFunction(call);
GeneratorImpl& gen = SanitizeAndBuild();
ASSERT_TRUE(gen.Generate()) << gen.error();
EXPECT_THAT(gen.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()) << gen.error();
EXPECT_THAT(gen.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()) << gen.error();
EXPECT_EQ(gen.result(),
R"(float tint_frexp(float param_0, inout int param_1) {
float float_exp;
float significand = frexp(param_0, float_exp);
param_1 = int(float_exp);
return significand;
EXPECT_EQ(gen.result(), R"(struct modf_result {
float fract;
float whole;
};
modf_result tint_modf(float param_0) {
float whole;
float fract = modf(param_0, whole);
modf_result result = {fract, whole};
return result;
}
[numthreads(1, 1, 1)]
void test_function() {
int exp = 0;
tint_frexp(1.0f, exp);
tint_modf(1.0f);
return;
}
)");
}
TEST_F(HlslGeneratorImplTest_Intrinsic, Modf_Vector) {
auto* call = Call("modf", vec3<f32>());
WrapInFunction(call);
GeneratorImpl& gen = SanitizeAndBuild();
ASSERT_TRUE(gen.Generate()) << gen.error();
EXPECT_EQ(gen.result(), R"(struct modf_result_vec3 {
float3 fract;
float3 whole;
};
modf_result_vec3 tint_modf(float3 param_0) {
float3 whole;
float3 fract = modf(param_0, whole);
modf_result_vec3 result = {fract, whole};
return result;
}
[numthreads(1, 1, 1)]
void test_function() {
tint_modf(float3(0.0f, 0.0f, 0.0f));
return;
}
)");
}
TEST_F(HlslGeneratorImplTest_Intrinsic, Frexp_Scalar_i32) {
auto* call = Call("frexp", 1.0f);
WrapInFunction(call);
GeneratorImpl& gen = SanitizeAndBuild();
ASSERT_TRUE(gen.Generate()) << gen.error();
EXPECT_EQ(gen.result(), R"(struct frexp_result {
float sig;
int exp;
};
frexp_result tint_frexp(float param_0) {
float exp;
float sig = frexp(param_0, exp);
frexp_result result = {sig, int(exp)};
return result;
}
[numthreads(1, 1, 1)]
void test_function() {
tint_frexp(1.0f);
return;
}
)");
}
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);
auto* call = Call("frexp", vec3<f32>());
WrapInFunction(call);
GeneratorImpl& gen = SanitizeAndBuild();
ASSERT_TRUE(gen.Generate()) << gen.error();
EXPECT_EQ(gen.result(),
R"(float3 tint_frexp(float3 param_0, inout int3 param_1) {
float3 float_exp;
float3 significand = frexp(param_0, float_exp);
param_1 = int3(float_exp);
return significand;
EXPECT_EQ(gen.result(), R"(struct frexp_result_vec3 {
float3 sig;
int3 exp;
};
frexp_result_vec3 tint_frexp(float3 param_0) {
float3 exp;
float3 sig = frexp(param_0, exp);
frexp_result_vec3 result = {sig, int3(exp)};
return result;
}
[numthreads(1, 1, 1)]
void test_function() {
int3 res = int3(0, 0, 0);
tint_frexp(float3(0.0f, 0.0f, 0.0f), res);
tint_frexp(float3(0.0f, 0.0f, 0.0f));
return;
}
)");

View File

@@ -1034,48 +1034,27 @@ bool GeneratorImpl::EmitTextureCall(std::ostream& out,
bool GeneratorImpl::EmitModfCall(std::ostream& out,
ast::CallExpression* expr,
const sem::Intrinsic* intrinsic) {
if (expr->params().size() == 1) {
return CallIntrinsicHelper(
out, expr, intrinsic,
[&](TextBuffer* b, const std::vector<std::string>& params) {
auto* ty = intrinsic->Parameters()[0]->Type();
auto in = params[0];
std::string width;
if (auto* vec = ty->As<sem::Vector>()) {
width = std::to_string(vec->Width());
}
// Emit the builtin return type unique to this overload. This does not
// exist in the AST, so it will not be generated in Generate().
if (!EmitStructType(&helpers_,
intrinsic->ReturnType()->As<sem::Struct>())) {
return false;
}
line(b) << "float" << width << " whole;";
line(b) << "float" << width << " fract = modf(" << in << ", whole);";
line(b) << "return {fract, whole};";
return true;
});
}
// DEPRECATED
return CallIntrinsicHelper(
out, expr, intrinsic,
[&](TextBuffer* b, const std::vector<std::string>& params) {
auto* ty = intrinsic->Parameters()[0]->Type();
auto in = params[0];
auto out_whole = params[1];
std::string width;
if (auto* vec = ty->As<sem::Vector>()) {
width = std::to_string(vec->Width());
}
// Emit the builtin return type unique to this overload. This does not
// exist in the AST, so it will not be generated in Generate().
if (!EmitStructType(&helpers_,
intrinsic->ReturnType()->As<sem::Struct>())) {
return false;
}
line(b) << "float" << width << " whole;";
line(b) << "float" << width << " fract = modf(" << in << ", whole);";
line(b) << "*" << out_whole << " = whole;";
line(b) << "return fract;";
line(b) << "return {fract, whole};";
return true;
});
}
@@ -1083,49 +1062,27 @@ bool GeneratorImpl::EmitModfCall(std::ostream& out,
bool GeneratorImpl::EmitFrexpCall(std::ostream& out,
ast::CallExpression* expr,
const sem::Intrinsic* intrinsic) {
if (expr->params().size() == 1) {
return CallIntrinsicHelper(
out, expr, intrinsic,
[&](TextBuffer* b, const std::vector<std::string>& params) {
auto* ty = intrinsic->Parameters()[0]->Type();
auto in = params[0];
std::string width;
if (auto* vec = ty->As<sem::Vector>()) {
width = std::to_string(vec->Width());
}
// Emit the builtin return type unique to this overload. This does not
// exist in the AST, so it will not be generated in Generate().
if (!EmitStructType(&helpers_,
intrinsic->ReturnType()->As<sem::Struct>())) {
return false;
}
line(b) << "int" << width << " exp;";
line(b) << "float" << width << " sig = frexp(" << in << ", exp);";
line(b) << "return {sig, exp};";
return true;
});
}
// DEPRECATED
return CallIntrinsicHelper(
out, expr, intrinsic,
[&](TextBuffer* b, const std::vector<std::string>& params) {
auto* ty = intrinsic->Parameters()[0]->Type();
auto in = params[0];
auto out_exp = params[1];
std::string width;
if (auto* vec = ty->As<sem::Vector>()) {
width = std::to_string(vec->Width());
}
// Emit the builtin return type unique to this overload. This does not
// exist in the AST, so it will not be generated in Generate().
if (!EmitStructType(&helpers_,
intrinsic->ReturnType()->As<sem::Struct>())) {
return false;
}
line(b) << "int" << width << " exp;";
line(b) << "float" << width << " sig = frexp(" << in << ", exp);";
line(b) << "*" << out_exp << " = exp;";
line(b) << "return sig;";
line(b) << "return {sig, exp};";
return true;
});
}

View File

@@ -165,8 +165,7 @@ uint32_t intrinsic_to_glsl_method(const sem::Intrinsic* intrinsic) {
case IntrinsicType::kFract:
return GLSLstd450Fract;
case IntrinsicType::kFrexp:
return (intrinsic->Parameters().size() == 1) ? GLSLstd450FrexpStruct
: GLSLstd450Frexp;
return GLSLstd450FrexpStruct;
case IntrinsicType::kInverseSqrt:
return GLSLstd450InverseSqrt;
case IntrinsicType::kLdexp:
@@ -196,8 +195,7 @@ uint32_t intrinsic_to_glsl_method(const sem::Intrinsic* intrinsic) {
case IntrinsicType::kMix:
return GLSLstd450FMix;
case IntrinsicType::kModf:
return (intrinsic->Parameters().size() == 1) ? GLSLstd450ModfStruct
: GLSLstd450Modf;
return GLSLstd450ModfStruct;
case IntrinsicType::kNormalize:
return GLSLstd450Normalize;
case IntrinsicType::kPack4x8snorm:

View File

@@ -1452,16 +1452,48 @@ INSTANTIATE_TEST_SUITE_P(IntrinsicBuilderTest,
testing::Values(IntrinsicData{"clamp", "UClamp"}));
TEST_F(IntrinsicBuilderTest, Call_Modf) {
auto* out = Var("out", ty.vec2<f32>());
auto* expr = Call("modf", vec2<f32>(1.0f, 2.0f), AddressOf("out"));
Func("a_func", ast::VariableList{}, ty.void_(),
ast::StatementList{
Decl(out),
Ignore(expr),
},
ast::DecorationList{
Stage(ast::PipelineStage::kFragment),
});
auto* expr = Call("modf", vec2<f32>(1.0f, 2.0f));
Func("a_func", {}, ty.void_(), {Ignore(expr)},
{Stage(ast::PipelineStage::kFragment)});
spirv::Builder& b = Build();
ASSERT_TRUE(b.Build()) << b.error();
auto got = DumpBuilder(b);
auto* expect = R"(OpCapability Shader
%10 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %3 "a_func"
OpExecutionMode %3 OriginUpperLeft
OpName %3 "a_func"
OpName %7 "_modf_result_vec2"
OpMemberName %7 0 "fract"
OpMemberName %7 1 "whole"
OpMemberDecorate %7 0 Offset 0
OpMemberDecorate %7 1 Offset 8
%2 = OpTypeVoid
%1 = OpTypeFunction %2
%9 = OpTypeFloat 32
%8 = OpTypeVector %9 2
%7 = OpTypeStruct %8 %8
%11 = OpConstant %9 1
%12 = OpConstant %9 2
%13 = OpConstantComposite %8 %11 %12
%3 = OpFunction %2 None %1
%4 = OpLabel
%6 = OpExtInst %7 %10 ModfStruct %13
OpReturn
OpFunctionEnd
)";
EXPECT_EQ(expect, got);
Validate(b);
}
TEST_F(IntrinsicBuilderTest, Call_Frexp) {
auto* expr = Call("frexp", vec2<f32>(1.0f, 2.0f));
Func("a_func", {}, ty.void_(), {Ignore(expr)},
{Stage(ast::PipelineStage::kFragment)});
spirv::Builder& b = Build();
@@ -1473,66 +1505,24 @@ OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %3 "a_func"
OpExecutionMode %3 OriginUpperLeft
OpName %3 "a_func"
OpName %5 "out"
OpName %7 "_frexp_result_vec2"
OpMemberName %7 0 "sig"
OpMemberName %7 1 "exp"
OpMemberDecorate %7 0 Offset 0
OpMemberDecorate %7 1 Offset 8
%2 = OpTypeVoid
%1 = OpTypeFunction %2
%8 = OpTypeFloat 32
%7 = OpTypeVector %8 2
%6 = OpTypePointer Function %7
%9 = OpConstantNull %7
%13 = OpConstant %8 1
%14 = OpConstant %8 2
%15 = OpConstantComposite %7 %13 %14
%9 = OpTypeFloat 32
%8 = OpTypeVector %9 2
%11 = OpTypeInt 32 1
%10 = OpTypeVector %11 2
%7 = OpTypeStruct %8 %10
%13 = OpConstant %9 1
%14 = OpConstant %9 2
%15 = OpConstantComposite %8 %13 %14
%3 = OpFunction %2 None %1
%4 = OpLabel
%5 = OpVariable %6 Function %9
%11 = OpExtInst %7 %12 Modf %15 %5
OpReturn
OpFunctionEnd
)";
EXPECT_EQ(expect, got);
Validate(b);
}
TEST_F(IntrinsicBuilderTest, Call_Frexp) {
auto* out = Var("out", ty.vec2<i32>());
auto* expr = Call("frexp", vec2<f32>(1.0f, 2.0f), AddressOf("out"));
Func("a_func", ast::VariableList{}, ty.void_(),
ast::StatementList{
Decl(out),
Ignore(expr),
},
ast::DecorationList{
Stage(ast::PipelineStage::kFragment),
});
spirv::Builder& b = Build();
ASSERT_TRUE(b.Build()) << b.error();
auto got = DumpBuilder(b);
auto* expect = R"(OpCapability Shader
%14 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %3 "a_func"
OpExecutionMode %3 OriginUpperLeft
OpName %3 "a_func"
OpName %5 "out"
%2 = OpTypeVoid
%1 = OpTypeFunction %2
%8 = OpTypeInt 32 1
%7 = OpTypeVector %8 2
%6 = OpTypePointer Function %7
%9 = OpConstantNull %7
%13 = OpTypeFloat 32
%12 = OpTypeVector %13 2
%15 = OpConstant %13 1
%16 = OpConstant %13 2
%17 = OpConstantComposite %12 %15 %16
%3 = OpFunction %2 None %1
%4 = OpLabel
%5 = OpVariable %6 Function %9
%11 = OpExtInst %12 %14 Frexp %17 %5
%6 = OpExtInst %7 %12 FrexpStruct %15
OpReturn
OpFunctionEnd
)";