msl:ast_printer: Polyfill 4x8 int dot products on AMD RDNA1, RDNA2
Remove end2end test suppression for Metal AMD
The IR MSL backend emits code similar to the non-polyfilled AST backend.
That may need reworking.
Fixed: chromium:355485146
Change-Id: I815c33f6768d5db4706e441d5f5d059f46b203cc
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/202054
Reviewed-by: James Price <jrprice@google.com>
Auto-Submit: David Neto <dneto@google.com>
Commit-Queue: James Price <jrprice@google.com>
diff --git a/src/dawn/native/metal/PhysicalDeviceMTL.mm b/src/dawn/native/metal/PhysicalDeviceMTL.mm
index dfe472b..129ff51 100644
--- a/src/dawn/native/metal/PhysicalDeviceMTL.mm
+++ b/src/dawn/native/metal/PhysicalDeviceMTL.mm
@@ -547,6 +547,14 @@
deviceToggles->Default(
Toggle::MetalUseBothDepthAndStencilAttachmentsForCombinedDepthStencilFormats, true);
}
+
+ // Packed 4x8 integer dot products fail on Macbook Pro 16" with AMD Radeon Pro 5300M,
+ // which are the RDNA1 architecture.
+ // Conservatively, polyfill these functions on RDNA1 and RDNA2.
+ // crbug.com/355485146
+ if (gpu_info::IsAMDRDNA1(vendorId, deviceId) || gpu_info::IsAMDRDNA2(vendorId, deviceId)) {
+ deviceToggles->Default(Toggle::PolyFillPacked4x8DotProduct, true);
+ }
#endif
}
diff --git a/src/dawn/native/metal/ShaderModuleMTL.mm b/src/dawn/native/metal/ShaderModuleMTL.mm
index 0151a18..6e087e8 100644
--- a/src/dawn/native/metal/ShaderModuleMTL.mm
+++ b/src/dawn/native/metal/ShaderModuleMTL.mm
@@ -290,6 +290,8 @@
req.use_tint_ir = device->IsToggleEnabled(Toggle::UseTintIR);
req.tintOptions.disable_polyfill_integer_div_mod =
device->IsToggleEnabled(Toggle::DisablePolyfillsOnIntegerDivisonAndModulo);
+ req.tintOptions.polyfill_dot_4x8_packed =
+ device->IsToggleEnabled(Toggle::PolyFillPacked4x8DotProduct);
const CombinedLimits& limits = device->GetLimits();
req.limits = LimitsForCompilationRequest::Create(limits.v1);
diff --git a/src/dawn/tests/end2end/Packed4x8IntegerDotProductTests.cpp b/src/dawn/tests/end2end/Packed4x8IntegerDotProductTests.cpp
index 1c8d76c..d6433b1 100644
--- a/src/dawn/tests/end2end/Packed4x8IntegerDotProductTests.cpp
+++ b/src/dawn/tests/end2end/Packed4x8IntegerDotProductTests.cpp
@@ -36,9 +36,6 @@
class Packed4x8IntegerDotProductTests : public DawnTest {};
TEST_P(Packed4x8IntegerDotProductTests, Dot4x8Packed) {
- // crbug.com/355485146.
- DAWN_SUPPRESS_TEST_IF(IsMacOS() && IsAMD() && IsMetal());
-
const char* computeShader = R"(
struct Buf {
data1 : i32,
diff --git a/src/tint/lang/msl/writer/ast_printer/ast_printer.cc b/src/tint/lang/msl/writer/ast_printer/ast_printer.cc
index 18c49ea..2fec05f 100644
--- a/src/tint/lang/msl/writer/ast_printer/ast_printer.cc
+++ b/src/tint/lang/msl/writer/ast_printer/ast_printer.cc
@@ -201,6 +201,7 @@
polyfills.sign_int = true;
polyfills.texture_sample_base_clamp_to_edge_2d_f32 = true;
polyfills.workgroup_uniform_load = true;
+ polyfills.dot_4x8_packed = options.polyfill_dot_4x8_packed;
polyfills.pack_unpack_4x8 = true;
polyfills.pack_4xu8_clamp = true;
data.Add<ast::transform::BuiltinPolyfill::Config>(polyfills);
diff --git a/src/tint/lang/msl/writer/ast_printer/builtin_test.cc b/src/tint/lang/msl/writer/ast_printer/builtin_test.cc
index 8837a20..0539763 100644
--- a/src/tint/lang/msl/writer/ast_printer/builtin_test.cc
+++ b/src/tint/lang/msl/writer/ast_printer/builtin_test.cc
@@ -1142,5 +1142,125 @@
)");
}
+TEST_F(MslASTPrinterTest, PolyfillDot4I8Packed_False) {
+ WrapInFunction(Decl(Let("zero", Expr(0_u))), //
+ Decl(Let("v", Call("dot4I8Packed", "zero", Expr(1_u)))));
+
+ Options options;
+ options.polyfill_dot_4x8_packed = false;
+ ASTPrinter& gen = SanitizeAndBuild(options);
+
+ ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
+ EXPECT_EQ(gen.Result(), R"(#include <metal_stdlib>
+
+using namespace metal;
+
+int tint_dot4I8Packed(uint param_0, uint param_1) {
+ char4 vec1 = as_type<char4>(param_0);
+ char4 vec2 = as_type<char4>(param_1);
+ return vec1[0] * vec2[0] + vec1[1] * vec2[1] + vec1[2] * vec2[2] + vec1[3] * vec2[3];
+}
+
+kernel void test_function() {
+ uint const zero = 0u;
+ int const v = tint_dot4I8Packed(zero, 1u);
+ return;
+}
+
+)");
+}
+
+TEST_F(MslASTPrinterTest, PolyfillDot4I8Packed_True) {
+ WrapInFunction(Decl(Let("zero", Expr(0_u))), //
+ Decl(Let("v", Call("dot4I8Packed", "zero", Expr(1_u)))));
+
+ Options options;
+ options.polyfill_dot_4x8_packed = true;
+ ASTPrinter& gen = SanitizeAndBuild(options);
+
+ ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
+ EXPECT_EQ(gen.Result(), R"(#include <metal_stdlib>
+
+using namespace metal;
+
+template<typename T>
+T tint_dot4(vec<T,4> a, vec<T,4> b) {
+ return a[0]*b[0] + a[1]*b[1] + a[2]*b[2] + a[3]*b[3];
+}
+int tint_dot4_i8_packed(uint a, uint b) {
+ int4 const a_i8 = (as_type<int4>((uint4(a) << uint4(24u, 16u, 8u, 0u))) >> uint4(24u));
+ int4 const b_i8 = (as_type<int4>((uint4(b) << uint4(24u, 16u, 8u, 0u))) >> uint4(24u));
+ return tint_dot4(a_i8, b_i8);
+}
+
+kernel void test_function() {
+ uint const zero = 0u;
+ int const v = tint_dot4_i8_packed(zero, 1u);
+ return;
+}
+
+)");
+}
+
+TEST_F(MslASTPrinterTest, PolyfillDot4U8Packed_False) {
+ WrapInFunction(Decl(Let("zero", Expr(0_u))), //
+ Decl(Let("v", Call("dot4U8Packed", "zero", Expr(1_u)))));
+
+ Options options;
+ options.polyfill_dot_4x8_packed = false;
+ ASTPrinter& gen = SanitizeAndBuild(options);
+
+ ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
+ EXPECT_EQ(gen.Result(), R"(#include <metal_stdlib>
+
+using namespace metal;
+
+uint tint_dot4U8Packed(uint param_0, uint param_1) {
+ uchar4 vec1 = as_type<uchar4>(param_0);
+ uchar4 vec2 = as_type<uchar4>(param_1);
+ return vec1[0] * vec2[0] + vec1[1] * vec2[1] + vec1[2] * vec2[2] + vec1[3] * vec2[3];
+}
+
+kernel void test_function() {
+ uint const zero = 0u;
+ uint const v = tint_dot4U8Packed(zero, 1u);
+ return;
+}
+
+)");
+}
+
+TEST_F(MslASTPrinterTest, PolyfillDot4U8Packed_True) {
+ WrapInFunction(Decl(Let("zero", Expr(0_u))), //
+ Decl(Let("v", Call("dot4U8Packed", "zero", Expr(1_u)))));
+
+ Options options;
+ options.polyfill_dot_4x8_packed = true;
+ ASTPrinter& gen = SanitizeAndBuild(options);
+
+ ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
+ EXPECT_EQ(gen.Result(), R"(#include <metal_stdlib>
+
+using namespace metal;
+
+template<typename T>
+T tint_dot4(vec<T,4> a, vec<T,4> b) {
+ return a[0]*b[0] + a[1]*b[1] + a[2]*b[2] + a[3]*b[3];
+}
+uint tint_dot4_u8_packed(uint a, uint b) {
+ uint4 const a_u8 = ((uint4(a) >> uint4(24u, 16u, 8u, 0u)) & uint4(255u));
+ uint4 const b_u8 = ((uint4(b) >> uint4(24u, 16u, 8u, 0u)) & uint4(255u));
+ return tint_dot4(a_u8, b_u8);
+}
+
+kernel void test_function() {
+ uint const zero = 0u;
+ uint const v = tint_dot4_u8_packed(zero, 1u);
+ return;
+}
+
+)");
+}
+
} // namespace
} // namespace tint::msl::writer
diff --git a/src/tint/lang/msl/writer/common/options.h b/src/tint/lang/msl/writer/common/options.h
index bd783c9..fb57e0d 100644
--- a/src/tint/lang/msl/writer/common/options.h
+++ b/src/tint/lang/msl/writer/common/options.h
@@ -166,6 +166,9 @@
/// The bindings
Bindings bindings;
+ /// Set to `true` to polyfill dot4I8Packed() dot4U8Packed().
+ bool polyfill_dot_4x8_packed = false;
+
/// Reflect the fields of this class so that it can be used by tint::ForeachField()
TINT_REFLECT(Options,
disable_robustness,
@@ -176,7 +179,8 @@
fixed_sample_mask,
pixel_local_attachments,
array_length_from_uniform,
- bindings);
+ bindings,
+ polyfill_dot_4x8_packed);
};
} // namespace tint::msl::writer