[tint][ir] Use intrinsic table for unary ops.
Much like BuiltinCall, make ir::Unary abstract, with a derived class for each dialect.
Add ir::CoreUnary to hold the core-dialect unary operators.
Make the validator consult the dialet's intrinsic table.
Change-Id: I08331410c1ea318f6681b90f42ebe9923e27eed2
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/168225
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: James Price <jrprice@google.com>
Commit-Queue: Ben Clayton <bclayton@google.com>
Reviewed-by: dan sinclair <dsinclair@chromium.org>
diff --git a/src/tint/lang/core/ir/BUILD.bazel b/src/tint/lang/core/ir/BUILD.bazel
index 3c62fe9..07d5897 100644
--- a/src/tint/lang/core/ir/BUILD.bazel
+++ b/src/tint/lang/core/ir/BUILD.bazel
@@ -55,6 +55,7 @@
"control_instruction.cc",
"convert.cc",
"core_builtin_call.cc",
+ "core_unary.cc",
"disassembler.cc",
"discard.cc",
"exit.cc",
@@ -105,6 +106,7 @@
"control_instruction.h",
"convert.h",
"core_builtin_call.h",
+ "core_unary.h",
"disassembler.h",
"discard.h",
"exit.h",
@@ -179,6 +181,7 @@
"continue_test.cc",
"convert_test.cc",
"core_builtin_call_test.cc",
+ "core_unary_test.cc",
"discard_test.cc",
"exit_if_test.cc",
"exit_loop_test.cc",
@@ -204,7 +207,6 @@
"swizzle_test.cc",
"terminate_invocation_test.cc",
"traverse_test.cc",
- "unary_test.cc",
"unreachable_test.cc",
"user_call_test.cc",
"validator_test.cc",
diff --git a/src/tint/lang/core/ir/BUILD.cmake b/src/tint/lang/core/ir/BUILD.cmake
index c901636..33f118e 100644
--- a/src/tint/lang/core/ir/BUILD.cmake
+++ b/src/tint/lang/core/ir/BUILD.cmake
@@ -74,6 +74,8 @@
lang/core/ir/convert.h
lang/core/ir/core_builtin_call.cc
lang/core/ir/core_builtin_call.h
+ lang/core/ir/core_unary.cc
+ lang/core/ir/core_unary.h
lang/core/ir/disassembler.cc
lang/core/ir/disassembler.h
lang/core/ir/discard.cc
@@ -180,6 +182,7 @@
lang/core/ir/continue_test.cc
lang/core/ir/convert_test.cc
lang/core/ir/core_builtin_call_test.cc
+ lang/core/ir/core_unary_test.cc
lang/core/ir/discard_test.cc
lang/core/ir/exit_if_test.cc
lang/core/ir/exit_loop_test.cc
@@ -205,7 +208,6 @@
lang/core/ir/swizzle_test.cc
lang/core/ir/terminate_invocation_test.cc
lang/core/ir/traverse_test.cc
- lang/core/ir/unary_test.cc
lang/core/ir/unreachable_test.cc
lang/core/ir/user_call_test.cc
lang/core/ir/validator_test.cc
diff --git a/src/tint/lang/core/ir/BUILD.gn b/src/tint/lang/core/ir/BUILD.gn
index 9bcb139..2fbb5ab 100644
--- a/src/tint/lang/core/ir/BUILD.gn
+++ b/src/tint/lang/core/ir/BUILD.gn
@@ -76,6 +76,8 @@
"convert.h",
"core_builtin_call.cc",
"core_builtin_call.h",
+ "core_unary.cc",
+ "core_unary.h",
"disassembler.cc",
"disassembler.h",
"discard.cc",
@@ -179,6 +181,7 @@
"continue_test.cc",
"convert_test.cc",
"core_builtin_call_test.cc",
+ "core_unary_test.cc",
"discard_test.cc",
"exit_if_test.cc",
"exit_loop_test.cc",
@@ -204,7 +207,6 @@
"swizzle_test.cc",
"terminate_invocation_test.cc",
"traverse_test.cc",
- "unary_test.cc",
"unreachable_test.cc",
"user_call_test.cc",
"validator_test.cc",
diff --git a/src/tint/lang/core/ir/binary/decode.cc b/src/tint/lang/core/ir/binary/decode.cc
index fb77a96..d5fd41f 100644
--- a/src/tint/lang/core/ir/binary/decode.cc
+++ b/src/tint/lang/core/ir/binary/decode.cc
@@ -494,8 +494,8 @@
return switch_out;
}
- ir::Unary* CreateInstructionUnary(const pb::InstructionUnary& unary_in) {
- auto* unary_out = mod_out_.instructions.Create<ir::Unary>();
+ ir::CoreUnary* CreateInstructionUnary(const pb::InstructionUnary& unary_in) {
+ auto* unary_out = mod_out_.instructions.Create<ir::CoreUnary>();
unary_out->SetOp(UnaryOp(unary_in.op()));
return unary_out;
}
@@ -894,16 +894,22 @@
}
}
- core::ir::UnaryOp UnaryOp(pb::UnaryOp in) {
+ core::UnaryOp UnaryOp(pb::UnaryOp in) {
switch (in) {
case pb::UnaryOp::complement:
- return core::ir::UnaryOp::kComplement;
+ return core::UnaryOp::kComplement;
case pb::UnaryOp::negation:
- return core::ir::UnaryOp::kNegation;
+ return core::UnaryOp::kNegation;
+ case pb::UnaryOp::address_of:
+ return core::UnaryOp::kAddressOf;
+ case pb::UnaryOp::indirection:
+ return core::UnaryOp::kIndirection;
+ case pb::UnaryOp::not_:
+ return core::UnaryOp::kNot;
default:
TINT_ICE() << "invalid UnaryOp: " << in;
- return core::ir::UnaryOp::kComplement;
+ return core::UnaryOp::kComplement;
}
}
diff --git a/src/tint/lang/core/ir/binary/encode.cc b/src/tint/lang/core/ir/binary/encode.cc
index fa72a55..cb45846 100644
--- a/src/tint/lang/core/ir/binary/encode.cc
+++ b/src/tint/lang/core/ir/binary/encode.cc
@@ -42,6 +42,7 @@
#include "src/tint/lang/core/ir/continue.h"
#include "src/tint/lang/core/ir/convert.h"
#include "src/tint/lang/core/ir/core_builtin_call.h"
+#include "src/tint/lang/core/ir/core_unary.h"
#include "src/tint/lang/core/ir/discard.h"
#include "src/tint/lang/core/ir/exit_if.h"
#include "src/tint/lang/core/ir/exit_loop.h"
@@ -60,7 +61,6 @@
#include "src/tint/lang/core/ir/store_vector_element.h"
#include "src/tint/lang/core/ir/switch.h"
#include "src/tint/lang/core/ir/swizzle.h"
-#include "src/tint/lang/core/ir/unary.h"
#include "src/tint/lang/core/ir/unreachable.h"
#include "src/tint/lang/core/ir/user_call.h"
#include "src/tint/lang/core/ir/var.h"
@@ -230,7 +230,7 @@
},
[&](const ir::Switch* i) { InstructionSwitch(*inst_out.mutable_switch_(), i); },
[&](const ir::Swizzle* i) { InstructionSwizzle(*inst_out.mutable_swizzle(), i); },
- [&](const ir::Unary* i) { InstructionUnary(*inst_out.mutable_unary(), i); },
+ [&](const ir::CoreUnary* i) { InstructionUnary(*inst_out.mutable_unary(), i); },
[&](const ir::UserCall* i) { InstructionUserCall(*inst_out.mutable_user_call(), i); },
[&](const ir::Var* i) { InstructionVar(*inst_out.mutable_var(), i); },
[&](const ir::Unreachable* i) {
@@ -329,7 +329,7 @@
}
}
- void InstructionUnary(pb::InstructionUnary& unary_out, const ir::Unary* unary_in) {
+ void InstructionUnary(pb::InstructionUnary& unary_out, const ir::CoreUnary* unary_in) {
unary_out.set_op(UnaryOp(unary_in->Op()));
}
@@ -675,12 +675,18 @@
}
}
- pb::UnaryOp UnaryOp(core::ir::UnaryOp in) {
+ pb::UnaryOp UnaryOp(core::UnaryOp in) {
switch (in) {
- case core::ir::UnaryOp::kComplement:
+ case core::UnaryOp::kComplement:
return pb::UnaryOp::complement;
- case core::ir::UnaryOp::kNegation:
+ case core::UnaryOp::kNegation:
return pb::UnaryOp::negation;
+ case core::UnaryOp::kAddressOf:
+ return pb::UnaryOp::address_of;
+ case core::UnaryOp::kIndirection:
+ return pb::UnaryOp::indirection;
+ case core::UnaryOp::kNot:
+ return pb::UnaryOp::not_;
}
TINT_ICE() << "invalid UnaryOp: " << in;
return pb::UnaryOp::complement;
diff --git a/src/tint/lang/core/ir/binary/ir.proto b/src/tint/lang/core/ir/binary/ir.proto
index 8eb5c20..b964c92 100644
--- a/src/tint/lang/core/ir/binary/ir.proto
+++ b/src/tint/lang/core/ir/binary/ir.proto
@@ -413,6 +413,9 @@
enum UnaryOp {
complement = 0;
negation = 1;
+ address_of = 2;
+ indirection = 3;
+ not = 4;
}
enum BinaryOp {
diff --git a/src/tint/lang/core/ir/builder.h b/src/tint/lang/core/ir/builder.h
index fc847c7..5e8f502 100644
--- a/src/tint/lang/core/ir/builder.h
+++ b/src/tint/lang/core/ir/builder.h
@@ -43,6 +43,7 @@
#include "src/tint/lang/core/ir/continue.h"
#include "src/tint/lang/core/ir/convert.h"
#include "src/tint/lang/core/ir/core_builtin_call.h"
+#include "src/tint/lang/core/ir/core_unary.h"
#include "src/tint/lang/core/ir/discard.h"
#include "src/tint/lang/core/ir/exit_if.h"
#include "src/tint/lang/core/ir/exit_loop.h"
@@ -64,7 +65,6 @@
#include "src/tint/lang/core/ir/switch.h"
#include "src/tint/lang/core/ir/swizzle.h"
#include "src/tint/lang/core/ir/terminate_invocation.h"
-#include "src/tint/lang/core/ir/unary.h"
#include "src/tint/lang/core/ir/unreachable.h"
#include "src/tint/lang/core/ir/user_call.h"
#include "src/tint/lang/core/ir/value.h"
@@ -824,9 +824,9 @@
/// @param val the value of the operation
/// @returns the operation
template <typename VAL>
- ir::Unary* Unary(UnaryOp op, const core::type::Type* type, VAL&& val) {
+ ir::CoreUnary* Unary(UnaryOp op, const core::type::Type* type, VAL&& val) {
auto* value = Value(std::forward<VAL>(val));
- return Append(ir.instructions.Create<ir::Unary>(InstructionResult(type), op, value));
+ return Append(ir.instructions.Create<ir::CoreUnary>(InstructionResult(type), op, value));
}
/// Creates an op for `op val`
@@ -835,7 +835,7 @@
/// @param val the value of the operation
/// @returns the operation
template <typename TYPE, typename VAL>
- ir::Unary* Unary(UnaryOp op, VAL&& val) {
+ ir::CoreUnary* Unary(UnaryOp op, VAL&& val) {
auto* type = ir.Types().Get<TYPE>();
return Unary(op, type, std::forward<VAL>(val));
}
@@ -845,8 +845,8 @@
/// @param val the value
/// @returns the operation
template <typename VAL>
- ir::Unary* Complement(const core::type::Type* type, VAL&& val) {
- return Unary(ir::UnaryOp::kComplement, type, std::forward<VAL>(val));
+ ir::CoreUnary* Complement(const core::type::Type* type, VAL&& val) {
+ return Unary(UnaryOp::kComplement, type, std::forward<VAL>(val));
}
/// Creates a Complement operation
@@ -854,7 +854,7 @@
/// @param val the value
/// @returns the operation
template <typename TYPE, typename VAL>
- ir::Unary* Complement(VAL&& val) {
+ ir::CoreUnary* Complement(VAL&& val) {
auto* type = ir.Types().Get<TYPE>();
return Complement(type, std::forward<VAL>(val));
}
@@ -864,8 +864,8 @@
/// @param val the value
/// @returns the operation
template <typename VAL>
- ir::Unary* Negation(const core::type::Type* type, VAL&& val) {
- return Unary(ir::UnaryOp::kNegation, type, std::forward<VAL>(val));
+ ir::CoreUnary* Negation(const core::type::Type* type, VAL&& val) {
+ return Unary(UnaryOp::kNegation, type, std::forward<VAL>(val));
}
/// Creates a Negation operation
@@ -873,7 +873,7 @@
/// @param val the value
/// @returns the operation
template <typename TYPE, typename VAL>
- ir::Unary* Negation(VAL&& val) {
+ ir::CoreUnary* Negation(VAL&& val) {
auto* type = ir.Types().Get<TYPE>();
return Negation(type, std::forward<VAL>(val));
}
diff --git a/src/tint/lang/core/ir/core_unary.cc b/src/tint/lang/core/ir/core_unary.cc
new file mode 100644
index 0000000..5ab130d
--- /dev/null
+++ b/src/tint/lang/core/ir/core_unary.cc
@@ -0,0 +1,54 @@
+// Copyright 2024 The Dawn & Tint Authors
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "src/tint/lang/core/ir/core_unary.h"
+
+#include "src/tint/lang/core/intrinsic/dialect.h"
+#include "src/tint/lang/core/ir/clone_context.h"
+#include "src/tint/lang/core/ir/module.h"
+
+TINT_INSTANTIATE_TYPEINFO(tint::core::ir::CoreUnary);
+
+namespace tint::core::ir {
+
+CoreUnary::CoreUnary() = default;
+
+CoreUnary::CoreUnary(InstructionResult* result, UnaryOp op, Value* val) : Base(result, op, val) {}
+
+CoreUnary::~CoreUnary() = default;
+
+CoreUnary* CoreUnary::Clone(CloneContext& ctx) {
+ auto* new_result = ctx.Clone(Result(0));
+ auto* val = ctx.Remap(Val());
+ return ctx.ir.instructions.Create<CoreUnary>(new_result, Op(), val);
+}
+
+const core::intrinsic::TableData& CoreUnary::TableData() const {
+ return core::intrinsic::Dialect::kData;
+}
+
+} // namespace tint::core::ir
diff --git a/src/tint/lang/core/ir/core_unary.h b/src/tint/lang/core/ir/core_unary.h
new file mode 100644
index 0000000..04a02f4
--- /dev/null
+++ b/src/tint/lang/core/ir/core_unary.h
@@ -0,0 +1,60 @@
+// Copyright 2024 The Dawn & Tint Authors
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef SRC_TINT_LANG_CORE_IR_CORE_UNARY_H_
+#define SRC_TINT_LANG_CORE_IR_CORE_UNARY_H_
+
+#include "src/tint/lang/core/ir/unary.h"
+
+namespace tint::core::ir {
+
+/// A core-dialect unary instruction in the IR.
+class CoreUnary final : public Castable<CoreUnary, Unary> {
+ public:
+ /// The offset in Operands() for the value
+ static constexpr size_t kValueOperandOffset = 0;
+
+ /// Constructor (no results, no operands)
+ CoreUnary();
+
+ /// Constructor
+ /// @param result the result value
+ /// @param op the unary operator
+ /// @param val the input value for the instruction
+ CoreUnary(InstructionResult* result, UnaryOp op, Value* val);
+ ~CoreUnary() override;
+
+ /// @copydoc Instruction::Clone()
+ CoreUnary* Clone(CloneContext& ctx) override;
+
+ /// @returns the table data to validate this builtin
+ const core::intrinsic::TableData& TableData() const override;
+};
+
+} // namespace tint::core::ir
+
+#endif // SRC_TINT_LANG_CORE_IR_CORE_UNARY_H_
diff --git a/src/tint/lang/core/ir/unary_test.cc b/src/tint/lang/core/ir/core_unary_test.cc
similarity index 100%
rename from src/tint/lang/core/ir/unary_test.cc
rename to src/tint/lang/core/ir/core_unary_test.cc
diff --git a/src/tint/lang/core/ir/disassembler.cc b/src/tint/lang/core/ir/disassembler.cc
index 9292f50..ee66e2b 100644
--- a/src/tint/lang/core/ir/disassembler.cc
+++ b/src/tint/lang/core/ir/disassembler.cc
@@ -870,6 +870,15 @@
case UnaryOp::kNegation:
out_ << "negation";
break;
+ case UnaryOp::kAddressOf:
+ out_ << "ref-to-ptr";
+ break;
+ case UnaryOp::kIndirection:
+ out_ << "ptr-to-ref";
+ break;
+ case UnaryOp::kNot:
+ out_ << "not";
+ break;
}
out_ << " ";
EmitOperandList(u);
diff --git a/src/tint/lang/core/ir/unary.cc b/src/tint/lang/core/ir/unary.cc
index d4de4e1..9fdfe0f 100644
--- a/src/tint/lang/core/ir/unary.cc
+++ b/src/tint/lang/core/ir/unary.cc
@@ -43,19 +43,4 @@
Unary::~Unary() = default;
-Unary* Unary::Clone(CloneContext& ctx) {
- auto* new_result = ctx.Clone(Result(0));
- auto* val = ctx.Remap(Val());
- return ctx.ir.instructions.Create<Unary>(new_result, op_, val);
-}
-
-std::string_view ToString(enum UnaryOp op) {
- switch (op) {
- case UnaryOp::kComplement:
- return "complement";
- case UnaryOp::kNegation:
- return "negation";
- }
- return "<unknown>";
-}
} // namespace tint::core::ir
diff --git a/src/tint/lang/core/ir/unary.h b/src/tint/lang/core/ir/unary.h
index 41a4875..7cd4b37 100644
--- a/src/tint/lang/core/ir/unary.h
+++ b/src/tint/lang/core/ir/unary.h
@@ -31,18 +31,17 @@
#include <string>
#include "src/tint/lang/core/ir/operand_instruction.h"
-#include "src/tint/utils/rtti/castable.h"
+#include "src/tint/lang/core/unary_op.h"
+
+// Forward declarations
+namespace tint::core::intrinsic {
+struct TableData;
+}
namespace tint::core::ir {
-/// A unary operator.
-enum class UnaryOp {
- kComplement,
- kNegation,
-};
-
/// A unary instruction in the IR.
-class Unary final : public Castable<Unary, OperandInstruction<1, 1>> {
+class Unary : public Castable<Unary, OperandInstruction<1, 1>> {
public:
/// The offset in Operands() for the value
static constexpr size_t kValueOperandOffset = 0;
@@ -57,9 +56,6 @@
Unary(InstructionResult* result, UnaryOp op, Value* val);
~Unary() override;
- /// @copydoc Instruction::Clone()
- Unary* Clone(CloneContext& ctx) override;
-
/// @returns the value for the instruction
Value* Val() { return operands_[kValueOperandOffset]; }
@@ -75,20 +71,13 @@
/// @returns the friendly name for the instruction
std::string FriendlyName() const override { return "unary"; }
+ /// @returns the table data to validate this builtin
+ virtual const core::intrinsic::TableData& TableData() const = 0;
+
private:
UnaryOp op_ = UnaryOp::kComplement;
};
-/// @param kind the enum value
-/// @returns the string for the given enum value
-std::string_view ToString(UnaryOp kind);
-
-/// Emits the name of the intrinsic type.
-template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
-auto& operator<<(STREAM& out, UnaryOp kind) {
- return out << ToString(kind);
-}
-
} // namespace tint::core::ir
#endif // SRC_TINT_LANG_CORE_IR_UNARY_H_
diff --git a/src/tint/lang/core/ir/validator.cc b/src/tint/lang/core/ir/validator.cc
index dd7925a..57180b3 100644
--- a/src/tint/lang/core/ir/validator.cc
+++ b/src/tint/lang/core/ir/validator.cc
@@ -671,10 +671,30 @@
void Validator::CheckUnary(const Unary* u) {
CheckOperandNotNull(u, u->Val(), Unary::kValueOperandOffset);
+ if (u->Val()) {
+ auto symbols = SymbolTable::Wrap(mod_.symbols);
+ auto type_mgr = type::Manager::Wrap(mod_.Types());
+ intrinsic::Context context{
+ u->TableData(),
+ type_mgr,
+ symbols,
+ };
- if (u->Result(0) && u->Val()) {
- if (u->Result(0)->Type() != u->Val()->Type()) {
- AddError(u, InstError(u, "result type must match value type"));
+ auto overload = core::intrinsic::LookupUnary(context, u->Op(), u->Val()->Type(),
+ core::EvaluationStage::kRuntime);
+ if (overload != Success) {
+ AddError(u, InstError(u, overload.Failure()));
+ return;
+ }
+
+ if (auto* result = u->Result(0)) {
+ if (overload->return_type != result->Type()) {
+ StringStream err;
+ err << "unary instruction result type (" << result->Type()->FriendlyName()
+ << ") does not match overload result type ("
+ << overload->return_type->FriendlyName() << ")";
+ AddError(u, InstError(u, err.str()));
+ }
}
}
}
diff --git a/src/tint/lang/core/ir/validator_test.cc b/src/tint/lang/core/ir/validator_test.cc
index 7dd1d69..3f2fd5c 100644
--- a/src/tint/lang/core/ir/validator_test.cc
+++ b/src/tint/lang/core/ir/validator_test.cc
@@ -1329,7 +1329,7 @@
TEST_F(IR_ValidatorTest, Unary_Result_Nullptr) {
auto* bin =
- mod.instructions.Create<ir::Unary>(nullptr, ir::UnaryOp::kNegation, b.Constant(2_i));
+ mod.instructions.Create<ir::CoreUnary>(nullptr, UnaryOp::kNegation, b.Constant(2_i));
auto* f = b.Function("my_func", ty.void_());
@@ -1368,7 +1368,9 @@
auto res = ir::Validate(mod);
ASSERT_NE(res, Success);
- EXPECT_EQ(res.Failure().reason.str(), R"(:3:5 error: unary: result type must match value type
+ EXPECT_EQ(
+ res.Failure().reason.str(),
+ R"(:3:5 error: unary: unary instruction result type (f32) does not match overload result type (i32)
%2:f32 = complement 2i
^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/tint/lang/msl/writer/printer/printer.cc b/src/tint/lang/msl/writer/printer/printer.cc
index 6cfa838..dfc8eda 100644
--- a/src/tint/lang/msl/writer/printer/printer.cc
+++ b/src/tint/lang/msl/writer/printer/printer.cc
@@ -43,6 +43,7 @@
#include "src/tint/lang/core/ir/continue.h"
#include "src/tint/lang/core/ir/convert.h"
#include "src/tint/lang/core/ir/core_builtin_call.h"
+#include "src/tint/lang/core/ir/core_unary.h"
#include "src/tint/lang/core/ir/discard.h"
#include "src/tint/lang/core/ir/exit_if.h"
#include "src/tint/lang/core/ir/exit_loop.h"
@@ -349,7 +350,7 @@
[&](core::ir::LoadVectorElement*) { /* inlined */ }, //
[&](core::ir::Swizzle*) { /* inlined */ }, //
[&](core::ir::Bitcast*) { /* inlined */ }, //
- [&](core::ir::Unary*) { /* inlined */ }, //
+ [&](core::ir::CoreUnary*) { /* inlined */ }, //
[&](core::ir::Binary*) { /* inlined */ }, //
[&](core::ir::Load*) { /* inlined */ }, //
[&](core::ir::Construct*) { /* inlined */ }, //
@@ -365,7 +366,7 @@
[&](const core::ir::InstructionResult* r) {
Switch(
r->Instruction(), //
- [&](const core::ir::Unary* u) { EmitUnary(out, u); }, //
+ [&](const core::ir::CoreUnary* u) { EmitUnary(out, u); }, //
[&](const core::ir::Binary* b) { EmitBinary(out, b); }, //
[&](const core::ir::Convert* b) { EmitConvert(out, b); }, //
[&](const core::ir::Let* l) { out << NameOf(l->Result(0)); }, //
@@ -387,14 +388,17 @@
TINT_ICE_ON_NO_MATCH);
}
- void EmitUnary(StringStream& out, const core::ir::Unary* u) {
+ void EmitUnary(StringStream& out, const core::ir::CoreUnary* u) {
switch (u->Op()) {
- case core::ir::UnaryOp::kNegation:
+ case core::UnaryOp::kNegation:
out << "-";
break;
- case core::ir::UnaryOp::kComplement:
+ case core::UnaryOp::kComplement:
out << "~";
break;
+ default:
+ TINT_UNIMPLEMENTED() << u->Op();
+ break;
}
out << "(";
EmitValue(out, u->Val());
diff --git a/src/tint/lang/spirv/writer/printer/printer.cc b/src/tint/lang/spirv/writer/printer/printer.cc
index e5e9945..7863fd8 100644
--- a/src/tint/lang/spirv/writer/printer/printer.cc
+++ b/src/tint/lang/spirv/writer/printer/printer.cc
@@ -893,7 +893,7 @@
[&](core::ir::Store* s) { EmitStore(s); }, //
[&](core::ir::StoreVectorElement* s) { EmitStoreVectorElement(s); }, //
[&](core::ir::UserCall* c) { EmitUserCall(c); }, //
- [&](core::ir::Unary* u) { EmitUnary(u); }, //
+ [&](core::ir::CoreUnary* u) { EmitUnary(u); }, //
[&](core::ir::Var* v) { EmitVar(v); }, //
[&](core::ir::Let* l) { EmitLet(l); }, //
[&](core::ir::If* i) { EmitIf(i); }, //
@@ -1961,21 +1961,24 @@
/// Emit a unary instruction.
/// @param unary the unary instruction to emit
- void EmitUnary(core::ir::Unary* unary) {
+ void EmitUnary(core::ir::CoreUnary* unary) {
auto id = Value(unary);
auto* ty = unary->Result(0)->Type();
spv::Op op = spv::Op::Max;
switch (unary->Op()) {
- case core::ir::UnaryOp::kComplement:
+ case core::UnaryOp::kComplement:
op = spv::Op::OpNot;
break;
- case core::ir::UnaryOp::kNegation:
+ case core::UnaryOp::kNegation:
if (ty->is_float_scalar_or_vector()) {
op = spv::Op::OpFNegate;
} else if (ty->is_signed_integer_scalar_or_vector()) {
op = spv::Op::OpSNegate;
}
break;
+ default:
+ TINT_UNIMPLEMENTED() << unary->Op();
+ break;
}
current_function_.push_inst(op, {Type(ty), id, Value(unary->Val())});
}
diff --git a/src/tint/lang/spirv/writer/unary_test.cc b/src/tint/lang/spirv/writer/unary_test.cc
index 72fff71..43fb04e 100644
--- a/src/tint/lang/spirv/writer/unary_test.cc
+++ b/src/tint/lang/spirv/writer/unary_test.cc
@@ -39,7 +39,7 @@
/// The element type to test.
TestElementType type;
/// The unary operation.
- enum core::ir::UnaryOp op;
+ core::UnaryOp op;
/// The expected SPIR-V instruction.
std::string spirv_inst;
/// The expected SPIR-V result type name.
@@ -80,11 +80,11 @@
INSTANTIATE_TEST_SUITE_P(
SpirvWriterTest_Unary,
Arithmetic,
- testing::Values(UnaryTestCase{kI32, core::ir::UnaryOp::kComplement, "OpNot", "int"},
- UnaryTestCase{kU32, core::ir::UnaryOp::kComplement, "OpNot", "uint"},
- UnaryTestCase{kI32, core::ir::UnaryOp::kNegation, "OpSNegate", "int"},
- UnaryTestCase{kF32, core::ir::UnaryOp::kNegation, "OpFNegate", "float"},
- UnaryTestCase{kF16, core::ir::UnaryOp::kNegation, "OpFNegate", "half"}));
+ testing::Values(UnaryTestCase{kI32, core::UnaryOp::kComplement, "OpNot", "int"},
+ UnaryTestCase{kU32, core::UnaryOp::kComplement, "OpNot", "uint"},
+ UnaryTestCase{kI32, core::UnaryOp::kNegation, "OpSNegate", "int"},
+ UnaryTestCase{kF32, core::UnaryOp::kNegation, "OpFNegate", "float"},
+ UnaryTestCase{kF16, core::UnaryOp::kNegation, "OpFNegate", "half"}));
} // namespace
} // namespace tint::spirv::writer
diff --git a/src/tint/lang/wgsl/ir/BUILD.bazel b/src/tint/lang/wgsl/ir/BUILD.bazel
index e764df7..259b851 100644
--- a/src/tint/lang/wgsl/ir/BUILD.bazel
+++ b/src/tint/lang/wgsl/ir/BUILD.bazel
@@ -40,9 +40,11 @@
name = "ir",
srcs = [
"builtin_call.cc",
+ "unary.cc",
],
hdrs = [
"builtin_call.h",
+ "unary.h",
],
deps = [
"//src/tint/api/common",
diff --git a/src/tint/lang/wgsl/ir/BUILD.cmake b/src/tint/lang/wgsl/ir/BUILD.cmake
index f41c7a4..d0192da 100644
--- a/src/tint/lang/wgsl/ir/BUILD.cmake
+++ b/src/tint/lang/wgsl/ir/BUILD.cmake
@@ -41,6 +41,8 @@
tint_add_target(tint_lang_wgsl_ir lib
lang/wgsl/ir/builtin_call.cc
lang/wgsl/ir/builtin_call.h
+ lang/wgsl/ir/unary.cc
+ lang/wgsl/ir/unary.h
)
tint_target_add_dependencies(tint_lang_wgsl_ir lib
diff --git a/src/tint/lang/wgsl/ir/BUILD.gn b/src/tint/lang/wgsl/ir/BUILD.gn
index 462ecfa..1194bb7 100644
--- a/src/tint/lang/wgsl/ir/BUILD.gn
+++ b/src/tint/lang/wgsl/ir/BUILD.gn
@@ -42,6 +42,8 @@
sources = [
"builtin_call.cc",
"builtin_call.h",
+ "unary.cc",
+ "unary.h",
]
deps = [
"${tint_src_dir}/api/common",
diff --git a/src/tint/lang/wgsl/ir/unary.cc b/src/tint/lang/wgsl/ir/unary.cc
new file mode 100644
index 0000000..f8c90f3
--- /dev/null
+++ b/src/tint/lang/wgsl/ir/unary.cc
@@ -0,0 +1,55 @@
+// Copyright 2024 The Dawn & Tint Authors
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "src/tint/lang/wgsl/ir/unary.h"
+
+#include "src/tint/lang/core/ir/clone_context.h"
+#include "src/tint/lang/core/ir/module.h"
+#include "src/tint/lang/wgsl/intrinsic/dialect.h"
+
+TINT_INSTANTIATE_TYPEINFO(tint::wgsl::ir::Unary);
+
+namespace tint::wgsl::ir {
+
+Unary::Unary() = default;
+
+Unary::Unary(core::ir::InstructionResult* result, core::UnaryOp op, core::ir::Value* val)
+ : Base(result, op, val) {}
+
+Unary::~Unary() = default;
+
+Unary* Unary::Clone(core::ir::CloneContext& ctx) {
+ auto* new_result = ctx.Clone(Result(0));
+ auto* val = ctx.Remap(Val());
+ return ctx.ir.instructions.Create<Unary>(new_result, Op(), val);
+}
+
+const core::intrinsic::TableData& Unary::TableData() const {
+ return wgsl::intrinsic::Dialect::kData;
+}
+
+} // namespace tint::wgsl::ir
diff --git a/src/tint/lang/wgsl/ir/unary.h b/src/tint/lang/wgsl/ir/unary.h
new file mode 100644
index 0000000..9fbeeea
--- /dev/null
+++ b/src/tint/lang/wgsl/ir/unary.h
@@ -0,0 +1,60 @@
+// Copyright 2024 The Dawn & Tint Authors
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef SRC_TINT_LANG_WGSL_IR_UNARY_H_
+#define SRC_TINT_LANG_WGSL_IR_UNARY_H_
+
+#include "src/tint/lang/core/ir/unary.h"
+
+namespace tint::wgsl::ir {
+
+/// A WGSL-dialect unary instruction in the IR.
+class Unary final : public Castable<Unary, core::ir::Unary> {
+ public:
+ /// The offset in Operands() for the value
+ static constexpr size_t kValueOperandOffset = 0;
+
+ /// Constructor (no results, no operands)
+ Unary();
+
+ /// Constructor
+ /// @param result the result value
+ /// @param op the unary operator
+ /// @param val the input value for the instruction
+ Unary(core::ir::InstructionResult* result, core::UnaryOp op, core::ir::Value* val);
+ ~Unary() override;
+
+ /// @copydoc core::ir::Instruction::Clone()
+ Unary* Clone(core::ir::CloneContext& ctx) override;
+
+ /// @returns the table data to validate this builtin
+ const core::intrinsic::TableData& TableData() const override;
+};
+
+} // namespace tint::wgsl::ir
+
+#endif // SRC_TINT_LANG_WGSL_IR_UNARY_H_
diff --git a/src/tint/lang/wgsl/writer/ir_to_program/ir_to_program.cc b/src/tint/lang/wgsl/writer/ir_to_program/ir_to_program.cc
index f7b6321..642617c 100644
--- a/src/tint/lang/wgsl/writer/ir_to_program/ir_to_program.cc
+++ b/src/tint/lang/wgsl/writer/ir_to_program/ir_to_program.cc
@@ -749,12 +749,15 @@
void Unary(const core::ir::Unary* u) {
const ast::Expression* expr = nullptr;
switch (u->Op()) {
- case core::ir::UnaryOp::kComplement:
+ case core::UnaryOp::kComplement:
expr = b.Complement(Expr(u->Val()));
break;
- case core::ir::UnaryOp::kNegation:
+ case core::UnaryOp::kNegation:
expr = b.Negation(Expr(u->Val()));
break;
+ default:
+ TINT_UNIMPLEMENTED() << u->Op();
+ break;
}
Bind(u->Result(0), expr);
}