[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>
This commit is contained in:
dan sinclair 2023-03-08 21:19:13 +00:00 committed by Dawn LUCI CQ
parent 51be3420b8
commit 724a70f7a1
15 changed files with 566 additions and 6 deletions

View File

@ -699,8 +699,14 @@ if(${TINT_BUILD_IR})
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 @@ if(${TINT_BUILD_IR})
ir/temp.h
ir/terminator.cc
ir/terminator.h
ir/user_call.cc
ir/user_call.h
ir/value.cc
ir/value.h
)

View File

@ -177,4 +177,20 @@ ir::Bitcast* Builder::Bitcast(const type::Type* type, Value* val) {
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

View File

@ -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 @@ class Builder {
/// @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();

View File

@ -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 @@ bool BuilderImpl::EmitStatement(const ast::Statement* stmt) {
[&](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 @@ utils::Result<Value*> BuilderImpl::EmitExpression(const ast::Expression* expr) {
// },
[&](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 @@ utils::Result<Value*> BuilderImpl::EmitBitcast(const ast::BitcastExpression* exp
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) {

View File

@ -39,6 +39,8 @@ class BitcastExpression;
class BlockStatement;
class BreakIfStatement;
class BreakStatement;
class CallExpression;
class CallStatement;
class ContinueStatement;
class Expression;
class ForLoopStatement;
@ -61,6 +63,9 @@ class Loop;
class Switch;
class Terminator;
} // namespace tint::ir
namespace tint::sem {
class Builtin;
} // namespace tint::sem
namespace tint::ir {
@ -165,6 +170,16 @@ class BuilderImpl {
/// @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

View File

@ -1858,5 +1858,70 @@ TEST_F(IR_BuilderImplTest, EmitExpression_Bitcast) {
)");
}
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

40
src/tint/ir/call.cc Normal file
View File

@ -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

54
src/tint/ir/call.h Normal file
View File

@ -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_

37
src/tint/ir/construct.cc Normal file
View File

@ -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

49
src/tint/ir/construct.h Normal file
View File

@ -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_

36
src/tint/ir/convert.cc Normal file
View File

@ -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

58
src/tint/ir/convert.h Normal file
View File

@ -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_

View File

@ -40,6 +40,8 @@ class TestHelperBase : public BASE, public ProgramBuilder {
/// return the same builder without rebuilding.
/// @return the builder
BuilderImpl& CreateBuilder() {
SetResolveOnBuild(true);
if (gen_) {
return *gen_;
}

36
src/tint/ir/user_call.cc Normal file
View File

@ -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

56
src/tint/ir/user_call.h Normal file
View File

@ -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_