mirror of
https://github.com/encounter/dawn-cmake.git
synced 2025-12-11 14:41:50 +00:00
tint/transform: Polyfill f32 conversion to i32 or u32
And vectors of those types. Fixed: tint:1866 Change-Id: Ic0b5061232c5eb5a67d43dde1cd9599c580f4388 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/123201 Reviewed-by: Dan Sinclair <dsinclair@chromium.org> Kokoro: Kokoro <noreply+kokoro@google.com> Reviewed-by: David Neto <dneto@google.com> Commit-Queue: Ben Clayton <bclayton@chromium.org> Kokoro: Ben Clayton <bclayton@chromium.org>
This commit is contained in:
committed by
Dawn LUCI CQ
parent
905b63b90f
commit
cc3f851ad8
@@ -23,6 +23,7 @@
|
||||
#include "src/tint/sem/builtin.h"
|
||||
#include "src/tint/sem/call.h"
|
||||
#include "src/tint/sem/type_expression.h"
|
||||
#include "src/tint/sem/value_conversion.h"
|
||||
#include "src/tint/switch.h"
|
||||
#include "src/tint/type/storage_texture.h"
|
||||
#include "src/tint/type/texture_dimension.h"
|
||||
@@ -135,6 +136,28 @@ struct BuiltinPolyfill::State {
|
||||
return Program(std::move(b));
|
||||
}
|
||||
|
||||
private:
|
||||
/// The source program
|
||||
Program const* const src;
|
||||
/// The transform config
|
||||
const Config& cfg;
|
||||
/// The destination program builder
|
||||
ProgramBuilder b;
|
||||
/// The clone context
|
||||
CloneContext ctx{&b, src};
|
||||
/// The source clone context
|
||||
const sem::Info& sem = src->Sem();
|
||||
/// Polyfill functions for binary operators.
|
||||
utils::Hashmap<BinaryOpSignature, Symbol, 8> binary_op_polyfills;
|
||||
/// Polyfill builtins.
|
||||
utils::Hashmap<const sem::Builtin*, Symbol, 8> builtin_polyfills;
|
||||
/// Polyfill f32 conversion to i32 or u32 (or vectors of)
|
||||
utils::Hashmap<const type::Type*, Symbol, 2> f32_conv_polyfills;
|
||||
// Tracks whether the chromium_experimental_full_ptr_parameters extension has been enabled.
|
||||
bool has_full_ptr_params = false;
|
||||
/// True if the transform has made changes (i.e. the program needs cloning)
|
||||
bool made_changes = false;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Function polyfills
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
@@ -802,6 +825,52 @@ struct BuiltinPolyfill::State {
|
||||
return name;
|
||||
}
|
||||
|
||||
/// Builds the polyfill function to value convert a scalar or vector of f32 to an i32 or u32 (or
|
||||
/// vector of).
|
||||
/// @param source the type of the value being converted
|
||||
/// @param target the target conversion type
|
||||
/// @return the polyfill function name
|
||||
Symbol ConvF32ToIU32(const type::Type* source, const type::Type* target) {
|
||||
struct Limits {
|
||||
AFloat low_condition;
|
||||
AInt low_limit;
|
||||
AFloat high_condition;
|
||||
AInt high_limit;
|
||||
};
|
||||
const bool is_signed = target->is_signed_integer_scalar_or_vector();
|
||||
const Limits limits = is_signed ? Limits{
|
||||
/* low_condition */ -AFloat(0x80000000),
|
||||
/* low_limit */ -AInt(0x80000000),
|
||||
/* high_condition */ AFloat(0x7fffff80),
|
||||
/* high_limit */ AInt(0x7fffffff),
|
||||
}
|
||||
: Limits{
|
||||
/* low_condition */ AFloat(0),
|
||||
/* low_limit */ AInt(0),
|
||||
/* high_condition */ AFloat(0xffffff00),
|
||||
/* high_limit */ AInt(0xffffffff),
|
||||
};
|
||||
|
||||
const uint32_t width = WidthOf(target);
|
||||
|
||||
// select(target(v), low_limit, v < low_condition)
|
||||
auto* select_low = b.Call(builtin::Function::kSelect, //
|
||||
b.Call(T(target), "v"), //
|
||||
ScalarOrVector(width, limits.low_limit), //
|
||||
b.LessThan("v", ScalarOrVector(width, limits.low_condition)));
|
||||
|
||||
// select(high_limit, select_low, v < high_condition)
|
||||
auto* select_high = b.Call(builtin::Function::kSelect, //
|
||||
ScalarOrVector(width, limits.high_limit), //
|
||||
select_low, //
|
||||
b.LessThan("v", ScalarOrVector(width, limits.high_condition)));
|
||||
|
||||
auto name = b.Symbols().New(is_signed ? "tint_ftoi" : "tint_ftou");
|
||||
b.Func(name, utils::Vector{b.Param("v", T(source))}, T(target),
|
||||
utils::Vector{b.Return(select_high)});
|
||||
return name;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Inline polyfills
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
@@ -971,26 +1040,6 @@ struct BuiltinPolyfill::State {
|
||||
return b.Call(fn, lhs, rhs);
|
||||
}
|
||||
|
||||
private:
|
||||
/// The source program
|
||||
Program const* const src;
|
||||
/// The transform config
|
||||
const Config& cfg;
|
||||
/// The destination program builder
|
||||
ProgramBuilder b;
|
||||
/// The clone context
|
||||
CloneContext ctx{&b, src};
|
||||
/// The source clone context
|
||||
const sem::Info& sem = src->Sem();
|
||||
/// Polyfill functions for binary operators.
|
||||
utils::Hashmap<BinaryOpSignature, Symbol, 8> binary_op_polyfills;
|
||||
/// Polyfill builtins.
|
||||
utils::Hashmap<const sem::Builtin*, Symbol, 8> builtin_polyfills;
|
||||
// Tracks whether the chromium_experimental_full_ptr_parameters extension has been enabled.
|
||||
bool has_full_ptr_params = false;
|
||||
/// True if the transform has made changes (i.e. the program needs cloning)
|
||||
bool made_changes = false;
|
||||
|
||||
/// @returns the AST type for the given sem type
|
||||
ast::Type T(const type::Type* ty) { return CreateASTTypeFor(ctx, ty); }
|
||||
|
||||
@@ -1195,6 +1244,20 @@ struct BuiltinPolyfill::State {
|
||||
default:
|
||||
return Symbol{};
|
||||
}
|
||||
},
|
||||
[&](const sem::ValueConversion* conv) {
|
||||
if (cfg.builtins.conv_f32_to_iu32) {
|
||||
auto* src_ty = conv->Source();
|
||||
if (tint::Is<type::F32>(type::Type::ElementOf(src_ty))) {
|
||||
auto* dst_ty = conv->Target();
|
||||
if (tint::IsAnyOf<type::I32, type::U32>(type::Type::ElementOf(dst_ty))) {
|
||||
return f32_conv_polyfills.GetOrCreate(dst_ty, [&] { //
|
||||
return ConvF32ToIU32(src_ty, dst_ty);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
return Symbol{};
|
||||
});
|
||||
|
||||
if (fn.IsValid()) {
|
||||
|
||||
@@ -57,6 +57,8 @@ class BuiltinPolyfill final : public Castable<BuiltinPolyfill, Transform> {
|
||||
bool count_leading_zeros = false;
|
||||
/// Should `countTrailingZeros()` be polyfilled?
|
||||
bool count_trailing_zeros = false;
|
||||
/// Should converting f32 to i32 or u32 be polyfilled?
|
||||
bool conv_f32_to_iu32 = false;
|
||||
/// What level should `extractBits()` be polyfilled?
|
||||
Level extract_bits = Level::kNone;
|
||||
/// Should `firstLeadingBit()` be polyfilled?
|
||||
|
||||
@@ -814,6 +814,157 @@ fn f() {
|
||||
EXPECT_EQ(expect, str(got));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// conv_f32_to_iu32
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
DataMap polyfillConvF32ToIU32() {
|
||||
BuiltinPolyfill::Builtins builtins;
|
||||
builtins.conv_f32_to_iu32 = true;
|
||||
DataMap data;
|
||||
data.Add<BuiltinPolyfill::Config>(builtins);
|
||||
return data;
|
||||
}
|
||||
|
||||
TEST_F(BuiltinPolyfillTest, ShouldRunConvF32ToI32) {
|
||||
auto* src = R"(
|
||||
fn f() {
|
||||
let f = 42.0;
|
||||
_ = i32(f);
|
||||
}
|
||||
)";
|
||||
|
||||
EXPECT_FALSE(ShouldRun<BuiltinPolyfill>(src));
|
||||
EXPECT_TRUE(ShouldRun<BuiltinPolyfill>(src, polyfillConvF32ToIU32()));
|
||||
}
|
||||
|
||||
TEST_F(BuiltinPolyfillTest, ShouldRunConvF32ToU32) {
|
||||
auto* src = R"(
|
||||
fn f() {
|
||||
let f = 42.0;
|
||||
_ = u32(f);
|
||||
}
|
||||
)";
|
||||
|
||||
EXPECT_FALSE(ShouldRun<BuiltinPolyfill>(src));
|
||||
EXPECT_TRUE(ShouldRun<BuiltinPolyfill>(src, polyfillConvF32ToIU32()));
|
||||
}
|
||||
|
||||
TEST_F(BuiltinPolyfillTest, ShouldRunConvVec3F32ToVec3I32) {
|
||||
auto* src = R"(
|
||||
fn f() {
|
||||
let f = vec3(42.0);
|
||||
_ = vec3<i32>(f);
|
||||
}
|
||||
)";
|
||||
|
||||
EXPECT_FALSE(ShouldRun<BuiltinPolyfill>(src));
|
||||
EXPECT_TRUE(ShouldRun<BuiltinPolyfill>(src, polyfillConvF32ToIU32()));
|
||||
}
|
||||
|
||||
TEST_F(BuiltinPolyfillTest, ShouldRunConvVec3F32ToVec3U32) {
|
||||
auto* src = R"(
|
||||
fn f() {
|
||||
let f = vec3(42.0);
|
||||
_ = vec3<u32>(f);
|
||||
}
|
||||
)";
|
||||
|
||||
EXPECT_FALSE(ShouldRun<BuiltinPolyfill>(src));
|
||||
EXPECT_TRUE(ShouldRun<BuiltinPolyfill>(src, polyfillConvF32ToIU32()));
|
||||
}
|
||||
|
||||
TEST_F(BuiltinPolyfillTest, ConvF32ToI32) {
|
||||
auto* src = R"(
|
||||
fn f() {
|
||||
let f = 42.0;
|
||||
_ = i32(f);
|
||||
}
|
||||
)";
|
||||
auto* expect = R"(
|
||||
fn tint_ftoi(v : f32) -> i32 {
|
||||
return select(2147483647, select(i32(v), -2147483648, (v < -2147483648.0)), (v < 2147483520.0));
|
||||
}
|
||||
|
||||
fn f() {
|
||||
let f = 42.0;
|
||||
_ = tint_ftoi(f);
|
||||
}
|
||||
)";
|
||||
|
||||
auto got = Run<BuiltinPolyfill>(src, polyfillConvF32ToIU32());
|
||||
|
||||
EXPECT_EQ(expect, str(got));
|
||||
}
|
||||
|
||||
TEST_F(BuiltinPolyfillTest, ConvF32ToU32) {
|
||||
auto* src = R"(
|
||||
fn f() {
|
||||
let f = 42.0;
|
||||
_ = u32(f);
|
||||
}
|
||||
)";
|
||||
auto* expect = R"(
|
||||
fn tint_ftou(v : f32) -> u32 {
|
||||
return select(4294967295, select(u32(v), 0, (v < 0.0)), (v < 4294967040.0));
|
||||
}
|
||||
|
||||
fn f() {
|
||||
let f = 42.0;
|
||||
_ = tint_ftou(f);
|
||||
}
|
||||
)";
|
||||
|
||||
auto got = Run<BuiltinPolyfill>(src, polyfillConvF32ToIU32());
|
||||
|
||||
EXPECT_EQ(expect, str(got));
|
||||
}
|
||||
|
||||
TEST_F(BuiltinPolyfillTest, ConvVec3F32ToVec3I32) {
|
||||
auto* src = R"(
|
||||
fn f() {
|
||||
let f = vec3(42.0);
|
||||
_ = vec3<i32>(f);
|
||||
}
|
||||
)";
|
||||
auto* expect = R"(
|
||||
fn tint_ftoi(v : vec3<f32>) -> vec3<i32> {
|
||||
return select(vec3(2147483647), select(vec3<i32>(v), vec3(-2147483648), (v < vec3(-2147483648.0))), (v < vec3(2147483520.0)));
|
||||
}
|
||||
|
||||
fn f() {
|
||||
let f = vec3(42.0);
|
||||
_ = tint_ftoi(f);
|
||||
}
|
||||
)";
|
||||
|
||||
auto got = Run<BuiltinPolyfill>(src, polyfillConvF32ToIU32());
|
||||
|
||||
EXPECT_EQ(expect, str(got));
|
||||
}
|
||||
|
||||
TEST_F(BuiltinPolyfillTest, ConvVec3F32ToVec3U32) {
|
||||
auto* src = R"(
|
||||
fn f() {
|
||||
let f = vec3(42.0);
|
||||
_ = vec3<u32>(f);
|
||||
}
|
||||
)";
|
||||
auto* expect = R"(
|
||||
fn tint_ftou(v : vec3<f32>) -> vec3<u32> {
|
||||
return select(vec3(4294967295), select(vec3<u32>(v), vec3(0), (v < vec3(0.0))), (v < vec3(4294967040.0)));
|
||||
}
|
||||
|
||||
fn f() {
|
||||
let f = vec3(42.0);
|
||||
_ = tint_ftou(f);
|
||||
}
|
||||
)";
|
||||
|
||||
auto got = Run<BuiltinPolyfill>(src, polyfillConvF32ToIU32());
|
||||
|
||||
EXPECT_EQ(expect, str(got));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// countLeadingZeros
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -193,6 +193,7 @@ SanitizedResult Sanitize(const Program* in,
|
||||
polyfills.atanh = transform::BuiltinPolyfill::Level::kRangeCheck;
|
||||
polyfills.bgra8unorm = true;
|
||||
polyfills.bitshift_modulo = true;
|
||||
polyfills.conv_f32_to_iu32 = true;
|
||||
polyfills.count_leading_zeros = true;
|
||||
polyfills.count_trailing_zeros = true;
|
||||
polyfills.extract_bits = transform::BuiltinPolyfill::Level::kClampParameters;
|
||||
|
||||
@@ -204,6 +204,7 @@ SanitizedResult Sanitize(const Program* in, const Options& options) {
|
||||
polyfills.clamp_int = true;
|
||||
// TODO(crbug.com/tint/1449): Some of these can map to HLSL's `firstbitlow`
|
||||
// and `firstbithigh`.
|
||||
polyfills.conv_f32_to_iu32 = true;
|
||||
polyfills.count_leading_zeros = true;
|
||||
polyfills.count_trailing_zeros = true;
|
||||
polyfills.extract_bits = transform::BuiltinPolyfill::Level::kFull;
|
||||
|
||||
@@ -219,6 +219,7 @@ SanitizedResult Sanitize(const Program* in, const Options& options) {
|
||||
polyfills.atanh = transform::BuiltinPolyfill::Level::kRangeCheck;
|
||||
polyfills.bitshift_modulo = true; // crbug.com/tint/1543
|
||||
polyfills.clamp_int = true;
|
||||
polyfills.conv_f32_to_iu32 = true;
|
||||
polyfills.extract_bits = transform::BuiltinPolyfill::Level::kClampParameters;
|
||||
polyfills.first_leading_bit = true;
|
||||
polyfills.first_trailing_bit = true;
|
||||
|
||||
@@ -89,6 +89,7 @@ SanitizedResult Sanitize(const Program* in, const Options& options) {
|
||||
polyfills.bgra8unorm = true;
|
||||
polyfills.bitshift_modulo = true;
|
||||
polyfills.clamp_int = true;
|
||||
polyfills.conv_f32_to_iu32 = true;
|
||||
polyfills.count_leading_zeros = true;
|
||||
polyfills.count_trailing_zeros = true;
|
||||
polyfills.extract_bits = transform::BuiltinPolyfill::Level::kClampParameters;
|
||||
|
||||
Reference in New Issue
Block a user