[ir][msl] Emit basic constants types
Add emission of `bool`, `f16`, `f32`, `i32`, and `i32` constants to the
MSL IR generator.
Bug: tint:1967
Change-Id: I3b3218ad7aff962063893d608a2b74d7ea9c43b8
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/138920
Reviewed-by: Ben Clayton <bclayton@google.com>
Commit-Queue: Dan Sinclair <dsinclair@chromium.org>
Kokoro: Kokoro <noreply+kokoro@google.com>
diff --git a/src/tint/BUILD.gn b/src/tint/BUILD.gn
index e2dd096..83d7421 100644
--- a/src/tint/BUILD.gn
+++ b/src/tint/BUILD.gn
@@ -2218,6 +2218,7 @@
if (tint_build_ir) {
sources += [
+ "writer/msl/ir/generator_impl_ir_constant_test.cc",
"writer/msl/ir/generator_impl_ir_function_test.cc",
"writer/msl/ir/generator_impl_ir_type_test.cc",
"writer/msl/ir/test_helper_ir.h",
diff --git a/src/tint/CMakeLists.txt b/src/tint/CMakeLists.txt
index 0ccef44..0ddae38 100644
--- a/src/tint/CMakeLists.txt
+++ b/src/tint/CMakeLists.txt
@@ -1457,6 +1457,7 @@
if(${TINT_BUILD_IR})
list(APPEND TINT_TEST_SRCS
+ writer/msl/ir/generator_impl_ir_constant_test.cc
writer/msl/ir/generator_impl_ir_function_test.cc
writer/msl/ir/generator_impl_ir_type_test.cc
writer/msl/ir/test_helper_ir.h
diff --git a/src/tint/writer/msl/generator_impl.cc b/src/tint/writer/msl/generator_impl.cc
index 83e769a..4aabeef 100644
--- a/src/tint/writer/msl/generator_impl.cc
+++ b/src/tint/writer/msl/generator_impl.cc
@@ -85,7 +85,6 @@
#include "src/tint/utils/scoped_assignment.h"
#include "src/tint/utils/string_stream.h"
#include "src/tint/writer/check_supported_extensions.h"
-#include "src/tint/writer/float_to_string.h"
#include "src/tint/writer/msl/generator_support.h"
namespace tint::writer::msl {
@@ -95,45 +94,6 @@
return utils::IsAnyOf<ast::BreakStatement>(stmts->Last());
}
-void PrintF32(utils::StringStream& out, float value) {
- // Note: Currently inf and nan should not be constructable, but this is implemented for the day
- // we support them.
- if (std::isinf(value)) {
- out << (value >= 0 ? "INFINITY" : "-INFINITY");
- } else if (std::isnan(value)) {
- out << "NAN";
- } else {
- out << FloatToString(value) << "f";
- }
-}
-
-void PrintF16(utils::StringStream& out, float value) {
- // Note: Currently inf and nan should not be constructable, but this is implemented for the day
- // we support them.
- if (std::isinf(value)) {
- // HUGE_VALH evaluates to +infinity.
- out << (value >= 0 ? "HUGE_VALH" : "-HUGE_VALH");
- } else if (std::isnan(value)) {
- // There is no NaN expr for half in MSL, "NAN" is of float type.
- out << "NAN";
- } else {
- out << FloatToString(value) << "h";
- }
-}
-
-void PrintI32(utils::StringStream& out, int32_t value) {
- // MSL (and C++) parse `-2147483648` as a `long` because it parses unary minus and `2147483648`
- // as separate tokens, and the latter doesn't fit into an (32-bit) `int`.
- // WGSL, on the other hand, parses this as an `i32`.
- // To avoid issues with `long` to `int` casts, emit `(-2147483647 - 1)` instead, which ensures
- // the expression type is `int`.
- if (auto int_min = std::numeric_limits<int32_t>::min(); value == int_min) {
- out << "(" << int_min + 1 << " - 1)";
- } else {
- out << value;
- }
-}
-
class ScopedBitCast {
public:
ScopedBitCast(GeneratorImpl* generator,
diff --git a/src/tint/writer/msl/generator_support.cc b/src/tint/writer/msl/generator_support.cc
index 3739cdd..4e3118b 100644
--- a/src/tint/writer/msl/generator_support.cc
+++ b/src/tint/writer/msl/generator_support.cc
@@ -14,6 +14,9 @@
#include "src/tint/writer/msl/generator_support.h"
+#include <cmath>
+#include <limits>
+
#include "src/tint/debug.h"
#include "src/tint/switch.h"
#include "src/tint/type/array.h"
@@ -25,6 +28,7 @@
#include "src/tint/type/struct.h"
#include "src/tint/type/u32.h"
#include "src/tint/type/vector.h"
+#include "src/tint/writer/float_to_string.h"
namespace tint::writer::msl {
@@ -211,4 +215,44 @@
return SizeAndAlign{};
});
}
+
+void PrintF32(utils::StringStream& out, float value) {
+ // Note: Currently inf and nan should not be constructable, but this is implemented for the day
+ // we support them.
+ if (std::isinf(value)) {
+ out << (value >= 0 ? "INFINITY" : "-INFINITY");
+ } else if (std::isnan(value)) {
+ out << "NAN";
+ } else {
+ out << FloatToString(value) << "f";
+ }
+}
+
+void PrintF16(utils::StringStream& out, float value) {
+ // Note: Currently inf and nan should not be constructable, but this is implemented for the day
+ // we support them.
+ if (std::isinf(value)) {
+ // HUGE_VALH evaluates to +infinity.
+ out << (value >= 0 ? "HUGE_VALH" : "-HUGE_VALH");
+ } else if (std::isnan(value)) {
+ // There is no NaN expr for half in MSL, "NAN" is of float type.
+ out << "NAN";
+ } else {
+ out << FloatToString(value) << "h";
+ }
+}
+
+void PrintI32(utils::StringStream& out, int32_t value) {
+ // MSL (and C++) parse `-2147483648` as a `long` because it parses unary minus and `2147483648`
+ // as separate tokens, and the latter doesn't fit into an (32-bit) `int`.
+ // WGSL, on the other hand, parses this as an `i32`.
+ // To avoid issues with `long` to `int` casts, emit `(-2147483647 - 1)` instead, which ensures
+ // the expression type is `int`.
+ if (auto int_min = std::numeric_limits<int32_t>::min(); value == int_min) {
+ out << "(" << int_min + 1 << " - 1)";
+ } else {
+ out << value;
+ }
+}
+
} // namespace tint::writer::msl
diff --git a/src/tint/writer/msl/generator_support.h b/src/tint/writer/msl/generator_support.h
index 4f5877f..c510f56 100644
--- a/src/tint/writer/msl/generator_support.h
+++ b/src/tint/writer/msl/generator_support.h
@@ -50,6 +50,21 @@
std::string InterpolationToAttribute(builtin::InterpolationType type,
builtin::InterpolationSampling sampling);
+/// Prints a float32 to the output stream
+/// @param out the stream to write too
+/// @param value the float32 value
+void PrintF32(utils::StringStream& out, float value);
+
+/// Prints a float16 to the output stream
+/// @param out the stream to write too
+/// @param value the float16 value
+void PrintF16(utils::StringStream& out, float value);
+
+/// Prints an int32 to the output stream
+/// @param out the stream to write too
+/// @param value the int32 value
+void PrintI32(utils::StringStream& out, int32_t value);
+
} // namespace tint::writer::msl
#endif // SRC_TINT_WRITER_MSL_GENERATOR_SUPPORT_H_
diff --git a/src/tint/writer/msl/ir/generator_impl_ir.cc b/src/tint/writer/msl/ir/generator_impl_ir.cc
index d5e9ac9..3209562 100644
--- a/src/tint/writer/msl/ir/generator_impl_ir.cc
+++ b/src/tint/writer/msl/ir/generator_impl_ir.cc
@@ -14,6 +14,7 @@
#include "src/tint/writer/msl/ir/generator_impl_ir.h"
+#include "src/tint/ir/constant.h"
#include "src/tint/ir/validate.h"
#include "src/tint/switch.h"
#include "src/tint/transform/manager.h"
@@ -429,4 +430,15 @@
preamble_buffer_.Append(str_buf);
}
+void GeneratorImplIr::EmitConstant(utils::StringStream& out, ir::Constant* c) {
+ return tint::Switch(
+ c->Type(), //
+ [&](const type::Bool*) { out << (c->Value()->ValueAs<bool>() ? "true" : "false"); },
+ [&](const type::I32*) { PrintI32(out, c->Value()->ValueAs<i32>()); },
+ [&](const type::U32*) { out << c->Value()->ValueAs<u32>() << "u"; },
+ [&](const type::F32*) { PrintF32(out, c->Value()->ValueAs<f32>()); },
+ [&](const type::F16*) { PrintF16(out, c->Value()->ValueAs<f16>()); },
+ [&](Default) { UNHANDLED_CASE(c); });
+}
+
} // namespace tint::writer::msl
diff --git a/src/tint/writer/msl/ir/generator_impl_ir.h b/src/tint/writer/msl/ir/generator_impl_ir.h
index 70e5d15..89ec1a1 100644
--- a/src/tint/writer/msl/ir/generator_impl_ir.h
+++ b/src/tint/writer/msl/ir/generator_impl_ir.h
@@ -55,6 +55,11 @@
/// @param sc the address space to generate
void EmitAddressSpace(utils::StringStream& out, builtin::AddressSpace sc);
+ /// Handles ir::Constant values
+ /// @param out the stream to write the constant too
+ /// @param c the constant to emit
+ void EmitConstant(utils::StringStream& out, ir::Constant* c);
+
/// @returns the name of the templated `tint_array` helper type, generating it if needed
const std::string& ArrayTemplateName();
diff --git a/src/tint/writer/msl/ir/generator_impl_ir_constant_test.cc b/src/tint/writer/msl/ir/generator_impl_ir_constant_test.cc
new file mode 100644
index 0000000..41a6139
--- /dev/null
+++ b/src/tint/writer/msl/ir/generator_impl_ir_constant_test.cc
@@ -0,0 +1,66 @@
+// Copyright 2023 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/tint/utils/string.h"
+#include "src/tint/writer/msl/ir/test_helper_ir.h"
+
+namespace tint::writer::msl {
+namespace {
+
+using namespace tint::number_suffixes; // NOLINT
+
+TEST_F(MslGeneratorImplIrTest, Constant_Bool_True) {
+ auto* c = b.Constant(true);
+ generator_.EmitConstant(generator_.Line(), c);
+ ASSERT_TRUE(generator_.Diagnostics().empty()) << generator_.Diagnostics().str();
+ EXPECT_EQ(utils::TrimSpace(generator_.Result()), std::string("true"));
+}
+
+TEST_F(MslGeneratorImplIrTest, Constant_Bool_False) {
+ auto* c = b.Constant(false);
+ generator_.EmitConstant(generator_.Line(), c);
+ ASSERT_TRUE(generator_.Diagnostics().empty()) << generator_.Diagnostics().str();
+ EXPECT_EQ(utils::TrimSpace(generator_.Result()), std::string("false"));
+}
+
+TEST_F(MslGeneratorImplIrTest, Constant_i32) {
+ auto* c = b.Constant(-12345_i);
+ generator_.EmitConstant(generator_.Line(), c);
+ ASSERT_TRUE(generator_.Diagnostics().empty()) << generator_.Diagnostics().str();
+ EXPECT_EQ(utils::TrimSpace(generator_.Result()), std::string("-12345"));
+}
+
+TEST_F(MslGeneratorImplIrTest, Constant_u32) {
+ auto* c = b.Constant(12345_u);
+ generator_.EmitConstant(generator_.Line(), c);
+ ASSERT_TRUE(generator_.Diagnostics().empty()) << generator_.Diagnostics().str();
+ EXPECT_EQ(utils::TrimSpace(generator_.Result()), std::string("12345u"));
+}
+
+TEST_F(MslGeneratorImplIrTest, Constant_F32) {
+ auto* c = b.Constant(f32((1 << 30) - 4));
+ generator_.EmitConstant(generator_.Line(), c);
+ ASSERT_TRUE(generator_.Diagnostics().empty()) << generator_.Diagnostics().str();
+ EXPECT_EQ(utils::TrimSpace(generator_.Result()), std::string("1073741824.0f"));
+}
+
+TEST_F(MslGeneratorImplIrTest, Constant_F16) {
+ auto* c = b.Constant(f16((1 << 15) - 8));
+ generator_.EmitConstant(generator_.Line(), c);
+ ASSERT_TRUE(generator_.Diagnostics().empty()) << generator_.Diagnostics().str();
+ EXPECT_EQ(utils::TrimSpace(generator_.Result()), std::string("32752.0h"));
+}
+
+} // namespace
+} // namespace tint::writer::msl