[ir] Add user functions, value constructors and value converters
This CL adds user function calls, value constructors and value
converters into the IR.
Bug: tint:1718
Change-Id: Iab59aa7d01b9d7831299d785f6e45e9fba12f7b5
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/122600
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/CMakeLists.txt b/src/tint/CMakeLists.txt
index 38fe7c1..4ea36bb 100644
--- a/src/tint/CMakeLists.txt
+++ b/src/tint/CMakeLists.txt
@@ -699,8 +699,14 @@
ir/builder.h
ir/builder_impl.cc
ir/builder_impl.h
+ ir/call.cc
+ ir/call.h
ir/constant.cc
ir/constant.h
+ ir/construct.cc
+ ir/construct.h
+ ir/convert.cc
+ ir/convert.h
ir/debug.cc
ir/debug.h
ir/disassembler.cc
@@ -723,6 +729,8 @@
ir/temp.h
ir/terminator.cc
ir/terminator.h
+ ir/user_call.cc
+ ir/user_call.h
ir/value.cc
ir/value.h
)
diff --git a/src/tint/ir/builder.cc b/src/tint/ir/builder.cc
index 1452dc4..96578c5 100644
--- a/src/tint/ir/builder.cc
+++ b/src/tint/ir/builder.cc
@@ -177,4 +177,20 @@
return ir.instructions.Create<ir::Bitcast>(Temp(type), val);
}
+ir::UserCall* Builder::UserCall(const type::Type* type,
+ Symbol name,
+ utils::VectorRef<Value*> args) {
+ return ir.instructions.Create<ir::UserCall>(Temp(type), name, std::move(args));
+}
+
+ir::Convert* Builder::Convert(const type::Type* to,
+ const type::Type* from,
+ utils::VectorRef<Value*> args) {
+ return ir.instructions.Create<ir::Convert>(Temp(to), from, std::move(args));
+}
+
+ir::Construct* Builder::Construct(const type::Type* to, utils::VectorRef<Value*> args) {
+ return ir.instructions.Create<ir::Construct>(Temp(to), std::move(args));
+}
+
} // namespace tint::ir
diff --git a/src/tint/ir/builder.h b/src/tint/ir/builder.h
index 147e4c4..e7d64bb 100644
--- a/src/tint/ir/builder.h
+++ b/src/tint/ir/builder.h
@@ -21,6 +21,8 @@
#include "src/tint/ir/binary.h"
#include "src/tint/ir/bitcast.h"
#include "src/tint/ir/constant.h"
+#include "src/tint/ir/construct.h"
+#include "src/tint/ir/convert.h"
#include "src/tint/ir/function.h"
#include "src/tint/ir/if.h"
#include "src/tint/ir/loop.h"
@@ -28,6 +30,7 @@
#include "src/tint/ir/switch.h"
#include "src/tint/ir/temp.h"
#include "src/tint/ir/terminator.h"
+#include "src/tint/ir/user_call.h"
#include "src/tint/ir/value.h"
#include "src/tint/type/bool.h"
#include "src/tint/type/f16.h"
@@ -279,6 +282,28 @@
/// @returns the instruction
ir::Bitcast* Bitcast(const type::Type* type, Value* val);
+ /// Creates a user function call instruction
+ /// @param type the return type of the call
+ /// @param name the name of the function being called
+ /// @param args the call arguments
+ /// @returns the instruction
+ ir::UserCall* UserCall(const type::Type* type, Symbol name, utils::VectorRef<Value*> args);
+
+ /// Creates a value conversion instruction
+ /// @param to the type converted to
+ /// @param from the type converted from
+ /// @param args the arguments to be converted
+ /// @returns the instruction
+ ir::Convert* Convert(const type::Type* to,
+ const type::Type* from,
+ utils::VectorRef<Value*> args);
+
+ /// Creates a value constructor instruction
+ /// @param to the type being converted
+ /// @param args the arguments to be converted
+ /// @returns the instruction
+ ir::Construct* Construct(const type::Type* to, utils::VectorRef<Value*> args);
+
/// @returns a unique temp id
Temp::Id AllocateTempId();
diff --git a/src/tint/ir/builder_impl.cc b/src/tint/ir/builder_impl.cc
index d3f8d53..e773966 100644
--- a/src/tint/ir/builder_impl.cc
+++ b/src/tint/ir/builder_impl.cc
@@ -14,6 +14,8 @@
#include "src/tint/ir/builder_impl.h"
+#include <iostream>
+
#include "src/tint/ast/alias.h"
#include "src/tint/ast/binary_expression.h"
#include "src/tint/ast/bitcast_expression.h"
@@ -21,6 +23,8 @@
#include "src/tint/ast/bool_literal_expression.h"
#include "src/tint/ast/break_if_statement.h"
#include "src/tint/ast/break_statement.h"
+#include "src/tint/ast/call_expression.h"
+#include "src/tint/ast/call_statement.h"
#include "src/tint/ast/const_assert.h"
#include "src/tint/ast/continue_statement.h"
#include "src/tint/ast/float_literal_expression.h"
@@ -28,6 +32,7 @@
#include "src/tint/ast/function.h"
#include "src/tint/ast/id_attribute.h"
#include "src/tint/ast/identifier.h"
+#include "src/tint/ast/identifier_expression.h"
#include "src/tint/ast/if_statement.h"
#include "src/tint/ast/int_literal_expression.h"
#include "src/tint/ast/literal_expression.h"
@@ -39,6 +44,7 @@
#include "src/tint/ast/struct_member_align_attribute.h"
#include "src/tint/ast/struct_member_size_attribute.h"
#include "src/tint/ast/switch_statement.h"
+#include "src/tint/ast/templated_identifier.h"
#include "src/tint/ast/variable_decl_statement.h"
#include "src/tint/ast/while_statement.h"
#include "src/tint/ir/function.h"
@@ -48,8 +54,12 @@
#include "src/tint/ir/switch.h"
#include "src/tint/ir/terminator.h"
#include "src/tint/program.h"
+#include "src/tint/sem/builtin.h"
+#include "src/tint/sem/call.h"
#include "src/tint/sem/module.h"
#include "src/tint/sem/switch_statement.h"
+#include "src/tint/sem/value_constructor.h"
+#include "src/tint/sem/value_conversion.h"
#include "src/tint/sem/value_expression.h"
#include "src/tint/type/void.h"
@@ -237,9 +247,7 @@
[&](const ast::BlockStatement* b) { return EmitBlock(b); },
[&](const ast::BreakStatement* b) { return EmitBreak(b); },
[&](const ast::BreakIfStatement* b) { return EmitBreakIf(b); },
- // [&](const ast::CallStatement* c) {
- // TODO(dsinclair): Implement
- // },
+ [&](const ast::CallStatement* c) { return EmitCall(c); },
// [&](const ast::CompoundAssignmentStatement* c) {
// TODO(dsinclair): Implement
// },
@@ -593,9 +601,7 @@
// },
[&](const ast::BinaryExpression* b) { return EmitBinary(b); },
[&](const ast::BitcastExpression* b) { return EmitBitcast(b); },
- // [&](const ast::CallExpression* c) {
- // TODO(dsinclair): Implement
- // },
+ [&](const ast::CallExpression* c) { return EmitCall(c); },
// [&](const ast::IdentifierExpression* i) {
// TODO(dsinclair): Implement
// },
@@ -743,6 +749,63 @@
return instr->Result();
}
+utils::Result<Value*> BuilderImpl::EmitCall(const ast::CallStatement* stmt) {
+ return EmitCall(stmt->expr);
+}
+
+utils::Result<Value*> BuilderImpl::EmitCall(const ast::CallExpression* expr) {
+ utils::Vector<Value*, 8> args;
+ args.Reserve(expr->args.Length());
+
+ // Emit the arguments
+ for (const auto* arg : expr->args) {
+ auto value = EmitExpression(arg);
+ if (!value) {
+ diagnostics_.add_error(tint::diag::System::IR, "Failed to convert arguments",
+ arg->source);
+ return utils::Failure;
+ }
+ args.Push(value.Get());
+ }
+
+ auto* sem = program_->Sem().Get<sem::Call>(expr);
+ if (!sem) {
+ diagnostics_.add_error(
+ tint::diag::System::IR,
+ "Failed to get semantic information for call " + std::string(expr->TypeInfo().name),
+ expr->source);
+ return utils::Failure;
+ }
+
+ auto* ty = sem->Target()->ReturnType()->Clone(clone_ctx_.type_ctx);
+
+ Instruction* instr = nullptr;
+
+ // If this is a builtin function, emit the specific builtin value
+ if (sem->Target()->As<sem::Builtin>()) {
+ // TODO(dsinclair): .. something ...
+ diagnostics_.add_error(tint::diag::System::IR, "Missing builtin function support",
+ expr->source);
+ } else if (sem->Target()->As<sem::ValueConstructor>()) {
+ instr = builder.Construct(ty, std::move(args));
+ } else if (auto* conv = sem->Target()->As<sem::ValueConversion>()) {
+ auto* from = conv->Source()->Clone(clone_ctx_.type_ctx);
+ instr = builder.Convert(ty, from, std::move(args));
+ } else if (expr->target->identifier->Is<ast::TemplatedIdentifier>()) {
+ TINT_UNIMPLEMENTED(IR, diagnostics_) << "Missing templated ident support";
+ return utils::Failure;
+ } else {
+ // Not a builtin and not a templated call, so this is a user function.
+ auto name = CloneSymbol(expr->target->identifier->symbol);
+ instr = builder.UserCall(ty, name, std::move(args));
+ }
+ if (instr == nullptr) {
+ return utils::Failure;
+ }
+ current_flow_block->instructions.Push(instr);
+ return instr->Result();
+}
+
utils::Result<Value*> BuilderImpl::EmitLiteral(const ast::LiteralExpression* lit) {
auto* sem = program_->Sem().Get(lit);
if (!sem) {
diff --git a/src/tint/ir/builder_impl.h b/src/tint/ir/builder_impl.h
index 034ab65..e531aed 100644
--- a/src/tint/ir/builder_impl.h
+++ b/src/tint/ir/builder_impl.h
@@ -39,6 +39,8 @@
class BlockStatement;
class BreakIfStatement;
class BreakStatement;
+class CallExpression;
+class CallStatement;
class ContinueStatement;
class Expression;
class ForLoopStatement;
@@ -61,6 +63,9 @@
class Switch;
class Terminator;
} // namespace tint::ir
+namespace tint::sem {
+class Builtin;
+} // namespace tint::sem
namespace tint::ir {
@@ -165,6 +170,16 @@
/// @returns the value storing the result if successful, utils::Failure otherwise
utils::Result<Value*> EmitBitcast(const ast::BitcastExpression* expr);
+ /// Emits a call expression
+ /// @param stmt the call statement
+ /// @returns the value storing the result if successful, utils::Failure otherwise
+ utils::Result<Value*> EmitCall(const ast::CallStatement* stmt);
+
+ /// Emits a call expression
+ /// @param expr the call expression
+ /// @returns the value storing the result if successful, utils::Failure otherwise
+ utils::Result<Value*> EmitCall(const ast::CallExpression* expr);
+
/// Emits a literal expression
/// @param lit the literal to emit
/// @returns true if successful, false otherwise
diff --git a/src/tint/ir/builder_impl_test.cc b/src/tint/ir/builder_impl_test.cc
index 9af481b..be94e65 100644
--- a/src/tint/ir/builder_impl_test.cc
+++ b/src/tint/ir/builder_impl_test.cc
@@ -1858,5 +1858,70 @@
)");
}
+TEST_F(IR_BuilderImplTest, EmitStatement_UserFunction) {
+ Func("my_func", utils::Vector{Param("p", ty.f32())}, ty.void_(), utils::Empty);
+
+ auto* stmt = CallStmt(Call("my_func", Mul(2_f, 3_f)));
+ WrapInFunction(stmt);
+
+ auto& b = CreateBuilder();
+ InjectFlowBlock();
+ auto r = b.EmitStatement(stmt);
+ ASSERT_TRUE(r) << b.error();
+
+ Disassembler d(b.builder.ir);
+ d.EmitBlockInstructions(b.current_flow_block->As<ir::Block>());
+ EXPECT_EQ(d.AsString(), R"(%1 (f32) = 2.0 * 3.0
+%2 (void) = call(my_func, %1 (f32))
+)");
+}
+
+TEST_F(IR_BuilderImplTest, EmitExpression_ConstructEmpty) {
+ auto* expr = vec3(ty.f32());
+ WrapInFunction(expr);
+
+ auto& b = CreateBuilder();
+ InjectFlowBlock();
+ auto r = b.EmitExpression(expr);
+ ASSERT_TRUE(r) << b.error();
+
+ Disassembler d(b.builder.ir);
+ d.EmitBlockInstructions(b.current_flow_block->As<ir::Block>());
+ EXPECT_EQ(d.AsString(), R"(%1 (vec3<f32>) = construct(vec3<f32>)
+)");
+}
+
+TEST_F(IR_BuilderImplTest, EmitExpression_Construct) {
+ auto i = GlobalVar("i", builtin::AddressSpace::kPrivate, Expr(1_f));
+ auto* expr = vec3(ty.f32(), 2_f, 3_f, i);
+ WrapInFunction(expr);
+
+ auto& b = CreateBuilder();
+ InjectFlowBlock();
+ auto r = b.EmitExpression(expr);
+ ASSERT_TRUE(r) << b.error();
+
+ Disassembler d(b.builder.ir);
+ d.EmitBlockInstructions(b.current_flow_block->As<ir::Block>());
+ EXPECT_EQ(d.AsString(), R"(%2 (vec3<f32>) = construct(vec3<f32>, 2.0, 3.0, %1 (void))
+)");
+}
+
+TEST_F(IR_BuilderImplTest, EmitExpression_Convert) {
+ auto i = GlobalVar("i", builtin::AddressSpace::kPrivate, Expr(1_i));
+ auto* expr = Call(ty.f32(), i);
+ WrapInFunction(expr);
+
+ auto& b = CreateBuilder();
+ InjectFlowBlock();
+ auto r = b.EmitExpression(expr);
+ ASSERT_TRUE(r) << b.error();
+
+ Disassembler d(b.builder.ir);
+ d.EmitBlockInstructions(b.current_flow_block->As<ir::Block>());
+ EXPECT_EQ(d.AsString(), R"(%2 (f32) = convert(f32, i32, %1 (void))
+)");
+}
+
} // namespace
} // namespace tint::ir
diff --git a/src/tint/ir/call.cc b/src/tint/ir/call.cc
new file mode 100644
index 0000000..9dda1f9
--- /dev/null
+++ b/src/tint/ir/call.cc
@@ -0,0 +1,40 @@
+// 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/ir/call.h"
+
+TINT_INSTANTIATE_TYPEINFO(tint::ir::Call);
+
+namespace tint::ir {
+
+Call::Call(Value* result, utils::VectorRef<Value*> args) : Base(result), args_(args) {
+ for (auto* arg : args) {
+ arg->AddUsage(this);
+ }
+}
+
+Call::~Call() = default;
+
+void Call::EmitArgs(utils::StringStream& out, const SymbolTable& st) const {
+ bool first = true;
+ for (const auto* arg : args_) {
+ if (!first) {
+ out << ", ";
+ }
+ first = false;
+ arg->ToString(out, st);
+ }
+}
+
+} // namespace tint::ir
diff --git a/src/tint/ir/call.h b/src/tint/ir/call.h
new file mode 100644
index 0000000..d6ced3f
--- /dev/null
+++ b/src/tint/ir/call.h
@@ -0,0 +1,54 @@
+// 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.
+
+#ifndef SRC_TINT_IR_CALL_H_
+#define SRC_TINT_IR_CALL_H_
+
+#include "src/tint/castable.h"
+#include "src/tint/ir/instruction.h"
+#include "src/tint/symbol_table.h"
+#include "src/tint/type/type.h"
+#include "src/tint/utils/string_stream.h"
+
+namespace tint::ir {
+
+/// A Call instruction in the IR.
+class Call : public Castable<Call, Instruction> {
+ public:
+ /// Constructor
+ /// @param result the result value
+ /// @param args the constructor arguments
+ Call(Value* result, utils::VectorRef<Value*> args);
+ Call(const Call& instr) = delete;
+ Call(Call&& instr) = delete;
+ ~Call() override;
+
+ Call& operator=(const Call& instr) = delete;
+ Call& operator=(Call&& instr) = delete;
+
+ /// @returns the constructor arguments
+ utils::VectorRef<Value*> Args() const { return args_; }
+
+ /// Writes the call arguments to the given stream.
+ /// @param out the output stream
+ /// @param st the symbol table
+ void EmitArgs(utils::StringStream& out, const SymbolTable& st) const;
+
+ private:
+ utils::Vector<Value*, 1> args_;
+};
+
+} // namespace tint::ir
+
+#endif // SRC_TINT_IR_CALL_H_
diff --git a/src/tint/ir/construct.cc b/src/tint/ir/construct.cc
new file mode 100644
index 0000000..27bb084
--- /dev/null
+++ b/src/tint/ir/construct.cc
@@ -0,0 +1,37 @@
+// 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/ir/construct.h"
+#include "src/tint/debug.h"
+
+TINT_INSTANTIATE_TYPEINFO(tint::ir::Construct);
+
+namespace tint::ir {
+
+Construct::Construct(Value* result, utils::VectorRef<Value*> args) : Base(result, args) {}
+
+Construct::~Construct() = default;
+
+utils::StringStream& Construct::ToString(utils::StringStream& out, const SymbolTable& st) const {
+ Result()->ToString(out, st);
+ out << " = construct(" << Result()->Type()->FriendlyName(st);
+ if (!Args().IsEmpty()) {
+ out << ", ";
+ EmitArgs(out, st);
+ }
+ out << ")";
+ return out;
+}
+
+} // namespace tint::ir
diff --git a/src/tint/ir/construct.h b/src/tint/ir/construct.h
new file mode 100644
index 0000000..6f620d3
--- /dev/null
+++ b/src/tint/ir/construct.h
@@ -0,0 +1,49 @@
+// 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.
+
+#ifndef SRC_TINT_IR_CONSTRUCT_H_
+#define SRC_TINT_IR_CONSTRUCT_H_
+
+#include "src/tint/castable.h"
+#include "src/tint/ir/call.h"
+#include "src/tint/symbol_table.h"
+#include "src/tint/type/type.h"
+#include "src/tint/utils/string_stream.h"
+
+namespace tint::ir {
+
+/// A constructor instruction in the IR.
+class Construct : public Castable<Construct, Call> {
+ public:
+ /// Constructor
+ /// @param result the result value
+ /// @param args the constructor arguments
+ Construct(Value* result, utils::VectorRef<Value*> args);
+ Construct(const Construct& instr) = delete;
+ Construct(Construct&& instr) = delete;
+ ~Construct() override;
+
+ Construct& operator=(const Construct& instr) = delete;
+ Construct& operator=(Construct&& instr) = delete;
+
+ /// Write the instruction to the given stream
+ /// @param out the stream to write to
+ /// @param st the symbol table
+ /// @returns the stream
+ utils::StringStream& ToString(utils::StringStream& out, const SymbolTable& st) const override;
+};
+
+} // namespace tint::ir
+
+#endif // SRC_TINT_IR_CONSTRUCT_H_
diff --git a/src/tint/ir/convert.cc b/src/tint/ir/convert.cc
new file mode 100644
index 0000000..e845adb
--- /dev/null
+++ b/src/tint/ir/convert.cc
@@ -0,0 +1,36 @@
+// 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/ir/convert.h"
+#include "src/tint/debug.h"
+
+TINT_INSTANTIATE_TYPEINFO(tint::ir::Convert);
+
+namespace tint::ir {
+
+Convert::Convert(Value* result, const type::Type* from, utils::VectorRef<Value*> args)
+ : Base(result, args), from_(from) {}
+
+Convert::~Convert() = default;
+
+utils::StringStream& Convert::ToString(utils::StringStream& out, const SymbolTable& st) const {
+ Result()->ToString(out, st);
+ out << " = convert(" << Result()->Type()->FriendlyName(st) << ", " << from_->FriendlyName(st)
+ << ", ";
+ EmitArgs(out, st);
+ out << ")";
+ return out;
+}
+
+} // namespace tint::ir
diff --git a/src/tint/ir/convert.h b/src/tint/ir/convert.h
new file mode 100644
index 0000000..5132248
--- /dev/null
+++ b/src/tint/ir/convert.h
@@ -0,0 +1,58 @@
+// 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.
+
+#ifndef SRC_TINT_IR_CONVERT_H_
+#define SRC_TINT_IR_CONVERT_H_
+
+#include "src/tint/castable.h"
+#include "src/tint/ir/call.h"
+#include "src/tint/symbol_table.h"
+#include "src/tint/type/type.h"
+#include "src/tint/utils/string_stream.h"
+
+namespace tint::ir {
+
+/// A value conversion instruction in the IR.
+class Convert : public Castable<Convert, Call> {
+ public:
+ /// Constructor
+ /// @param result the result value
+ /// @param from the type being converted from
+ /// @param args the conversion arguments
+ Convert(Value* result, const type::Type* from, utils::VectorRef<Value*> args);
+ Convert(const Convert& instr) = delete;
+ Convert(Convert&& instr) = delete;
+ ~Convert() override;
+
+ Convert& operator=(const Convert& instr) = delete;
+ Convert& operator=(Convert&& instr) = delete;
+
+ /// @returns the from type
+ const type::Type* From() const { return from_; }
+ /// @returns the to type
+ const type::Type* To() const { return Result()->Type(); }
+
+ /// Write the instruction to the given stream
+ /// @param out the stream to write to
+ /// @param st the symbol table
+ /// @returns the stream
+ utils::StringStream& ToString(utils::StringStream& out, const SymbolTable& st) const override;
+
+ private:
+ const type::Type* from_ = nullptr;
+};
+
+} // namespace tint::ir
+
+#endif // SRC_TINT_IR_CONVERT_H_
diff --git a/src/tint/ir/test_helper.h b/src/tint/ir/test_helper.h
index 9fb54cc..6e36ed3 100644
--- a/src/tint/ir/test_helper.h
+++ b/src/tint/ir/test_helper.h
@@ -40,6 +40,8 @@
/// return the same builder without rebuilding.
/// @return the builder
BuilderImpl& CreateBuilder() {
+ SetResolveOnBuild(true);
+
if (gen_) {
return *gen_;
}
diff --git a/src/tint/ir/user_call.cc b/src/tint/ir/user_call.cc
new file mode 100644
index 0000000..cf672cf
--- /dev/null
+++ b/src/tint/ir/user_call.cc
@@ -0,0 +1,36 @@
+// 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/ir/user_call.h"
+#include "src/tint/debug.h"
+
+TINT_INSTANTIATE_TYPEINFO(tint::ir::UserCall);
+
+namespace tint::ir {
+
+UserCall::UserCall(Value* result, Symbol name, utils::VectorRef<Value*> args)
+ : Base(result, args), name_(name) {}
+
+UserCall::~UserCall() = default;
+
+utils::StringStream& UserCall::ToString(utils::StringStream& out, const SymbolTable& st) const {
+ Result()->ToString(out, st);
+ out << " = call(";
+ out << st.NameFor(name_) << ", ";
+ EmitArgs(out, st);
+ out << ")";
+ return out;
+}
+
+} // namespace tint::ir
diff --git a/src/tint/ir/user_call.h b/src/tint/ir/user_call.h
new file mode 100644
index 0000000..2edeecb
--- /dev/null
+++ b/src/tint/ir/user_call.h
@@ -0,0 +1,56 @@
+// 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.
+
+#ifndef SRC_TINT_IR_USER_CALL_H_
+#define SRC_TINT_IR_USER_CALL_H_
+
+#include "src/tint/castable.h"
+#include "src/tint/ir/call.h"
+#include "src/tint/symbol_table.h"
+#include "src/tint/type/type.h"
+#include "src/tint/utils/string_stream.h"
+
+namespace tint::ir {
+
+/// A user call instruction in the IR.
+class UserCall : public Castable<UserCall, Call> {
+ public:
+ /// Constructor
+ /// @param result the result value
+ /// @param name the function name
+ /// @param args the function arguments
+ UserCall(Value* result, Symbol name, utils::VectorRef<Value*> args);
+ UserCall(const UserCall& instr) = delete;
+ UserCall(UserCall&& instr) = delete;
+ ~UserCall() override;
+
+ UserCall& operator=(const UserCall& instr) = delete;
+ UserCall& operator=(UserCall&& instr) = delete;
+
+ /// @returns the function name
+ Symbol Name() const { return name_; }
+
+ /// Write the instruction to the given stream
+ /// @param out the stream to write to
+ /// @param st the symbol table
+ /// @returns the stream
+ utils::StringStream& ToString(utils::StringStream& out, const SymbolTable& st) const override;
+
+ private:
+ Symbol name_{};
+};
+
+} // namespace tint::ir
+
+#endif // SRC_TINT_IR_USER_CALL_H_