tint: Add support for workgroupUniformLoad

Accept any type in the intrinsics definition, and then manually
validate that there are no atomics in the type. Add manual E2E tests
for composite types.

Use the BuiltinPolyfill transform to implement it for all backends.

Update the uniformity analysis with special-case tags for the builtin.

Fixed: tint:1780
Change-Id: I95786dff4df70a0b16ed1c53b853b5d0ec6bc501
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/114862
Reviewed-by: Ben Clayton <bclayton@google.com>
Commit-Queue: James Price <jrprice@google.com>
Kokoro: James Price <jrprice@google.com>
This commit is contained in:
James Price
2023-01-06 02:25:06 +00:00
committed by Dawn LUCI CQ
parent 3b83e389fa
commit 128980f218
148 changed files with 5314 additions and 1407 deletions

View File

@@ -39,7 +39,14 @@ struct BuiltinPolyfill::State {
/// Constructor
/// @param c the CloneContext
/// @param p the builtins to polyfill
State(CloneContext& c, Builtins p) : ctx(c), polyfill(p) {}
State(CloneContext& c, Builtins p) : ctx(c), polyfill(p) {
has_full_ptr_params = false;
for (auto* enable : c.src->AST().Enables()) {
if (enable->extension == ast::Extension::kChromiumExperimentalFullPtrParameters) {
has_full_ptr_params = true;
}
}
}
////////////////////////////////////////////////////////////////////////////
// Function polyfills
@@ -660,6 +667,29 @@ struct BuiltinPolyfill::State {
return name;
}
/// Builds the polyfill function for the `workgroupUniformLoad` builtin.
/// @param type the type being loaded
/// @return the polyfill function name
Symbol workgroupUniformLoad(const type::Type* type) {
if (!has_full_ptr_params) {
b.Enable(ast::Extension::kChromiumExperimentalFullPtrParameters);
has_full_ptr_params = true;
}
auto name = b.Symbols().New("tint_workgroupUniformLoad");
b.Func(name,
utils::Vector{
b.Param("p", b.ty.pointer(T(type), ast::AddressSpace::kWorkgroup)),
},
T(type),
utils::Vector{
b.CallStmt(b.Call("workgroupBarrier")),
b.Decl(b.Let("result", b.Deref("p"))),
b.CallStmt(b.Call("workgroupBarrier")),
b.Return("result"),
});
return name;
}
////////////////////////////////////////////////////////////////////////////
// Inline polyfills
////////////////////////////////////////////////////////////////////////////
@@ -756,6 +786,9 @@ struct BuiltinPolyfill::State {
// Polyfill functions for binary operators.
utils::Hashmap<BinaryOpSignature, Symbol, 8> binary_op_polyfills;
// Tracks whether the chromium_experimental_full_ptr_parameters extension has been enabled.
bool has_full_ptr_params;
/// @returns the AST type for the given sem type
const ast::Type* T(const type::Type* ty) const { return CreateASTTypeFor(ctx, ty); }
@@ -913,6 +946,13 @@ Transform::ApplyResult BuiltinPolyfill::Apply(const Program* src,
}
break;
case sem::BuiltinType::kWorkgroupUniformLoad:
if (polyfill.workgroup_uniform_load) {
fn = builtin_polyfills.GetOrCreate(
builtin, [&] { return s.workgroupUniformLoad(builtin->ReturnType()); });
}
break;
default:
break;
}

View File

@@ -75,6 +75,8 @@ class BuiltinPolyfill final : public Castable<BuiltinPolyfill, Transform> {
/// Should the vector form of `quantizeToF16()` be polyfilled with a scalar implementation?
/// See crbug.com/tint/1741
bool quantize_to_vec_f16 = false;
/// Should `workgroupUniformLoad()` be polyfilled?
bool workgroup_uniform_load = false;
};
/// Config is consumed by the BuiltinPolyfill transform.

View File

@@ -2942,6 +2942,169 @@ fn f() {
EXPECT_EQ(expect, str(got));
}
////////////////////////////////////////////////////////////////////////////////
// workgroupUniformLoad
////////////////////////////////////////////////////////////////////////////////
DataMap polyfillWorkgroupUniformLoad() {
BuiltinPolyfill::Builtins builtins;
builtins.workgroup_uniform_load = true;
DataMap data;
data.Add<BuiltinPolyfill::Config>(builtins);
return data;
}
TEST_F(BuiltinPolyfillTest, ShouldRunWorkgroupUniformLoad) {
auto* src = R"(
var<workgroup> v : i32;
fn f() {
workgroupUniformLoad(&v);
}
)";
EXPECT_FALSE(ShouldRun<BuiltinPolyfill>(src));
EXPECT_TRUE(ShouldRun<BuiltinPolyfill>(src, polyfillWorkgroupUniformLoad()));
}
TEST_F(BuiltinPolyfillTest, WorkgroupUniformLoad_i32) {
auto* src = R"(
var<workgroup> v : i32;
fn f() {
let r = workgroupUniformLoad(&v);
}
)";
auto* expect = R"(
enable chromium_experimental_full_ptr_parameters;
fn tint_workgroupUniformLoad(p : ptr<workgroup, i32>) -> i32 {
workgroupBarrier();
let result = *(p);
workgroupBarrier();
return result;
}
var<workgroup> v : i32;
fn f() {
let r = tint_workgroupUniformLoad(&(v));
}
)";
auto got = Run<BuiltinPolyfill>(src, polyfillWorkgroupUniformLoad());
EXPECT_EQ(expect, str(got));
}
TEST_F(BuiltinPolyfillTest, WorkgroupUniformLoad_ComplexType) {
auto* src = R"(
struct Inner {
b : bool,
v : vec4<i32>,
m : mat3x3<f32>,
}
struct Outer {
a : array<Inner, 4>,
}
var<workgroup> v : Outer;
fn f() {
let r = workgroupUniformLoad(&v);
}
)";
auto* expect = R"(
enable chromium_experimental_full_ptr_parameters;
fn tint_workgroupUniformLoad(p : ptr<workgroup, Outer>) -> Outer {
workgroupBarrier();
let result = *(p);
workgroupBarrier();
return result;
}
struct Inner {
b : bool,
v : vec4<i32>,
m : mat3x3<f32>,
}
struct Outer {
a : array<Inner, 4>,
}
var<workgroup> v : Outer;
fn f() {
let r = tint_workgroupUniformLoad(&(v));
}
)";
auto got = Run<BuiltinPolyfill>(src, polyfillWorkgroupUniformLoad());
EXPECT_EQ(expect, str(got));
}
TEST_F(BuiltinPolyfillTest, WorkgroupUniformLoad_AvoidDuplicateEnables) {
auto* src = R"(
enable chromium_experimental_full_ptr_parameters;
var<workgroup> a : i32;
var<workgroup> b : u32;
var<workgroup> c : f32;
fn f() {
let ra = workgroupUniformLoad(&a);
let rb = workgroupUniformLoad(&b);
let rc = workgroupUniformLoad(&c);
}
)";
auto* expect = R"(
enable chromium_experimental_full_ptr_parameters;
fn tint_workgroupUniformLoad(p : ptr<workgroup, i32>) -> i32 {
workgroupBarrier();
let result = *(p);
workgroupBarrier();
return result;
}
fn tint_workgroupUniformLoad_1(p : ptr<workgroup, u32>) -> u32 {
workgroupBarrier();
let result = *(p);
workgroupBarrier();
return result;
}
fn tint_workgroupUniformLoad_2(p : ptr<workgroup, f32>) -> f32 {
workgroupBarrier();
let result = *(p);
workgroupBarrier();
return result;
}
var<workgroup> a : i32;
var<workgroup> b : u32;
var<workgroup> c : f32;
fn f() {
let ra = tint_workgroupUniformLoad(&(a));
let rb = tint_workgroupUniformLoad_1(&(b));
let rc = tint_workgroupUniformLoad_2(&(c));
}
)";
auto got = Run<BuiltinPolyfill>(src, polyfillWorkgroupUniformLoad());
EXPECT_EQ(expect, str(got));
}
////////////////////////////////////////////////////////////////////////////////
// quantizeToF16
////////////////////////////////////////////////////////////////////////////////