[ir] Convert materialized nodes to constants

This CL updates the IR builder to convert materialized call expressions
directly into the resulting constant values.

Bug: tint:1718
Change-Id: I184478996afdd11b00ca946775eab6801b777f3c
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/122605
Commit-Queue: Dan Sinclair <dsinclair@chromium.org>
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: Ben Clayton <bclayton@google.com>
This commit is contained in:
dan sinclair 2023-03-08 23:22:27 +00:00 committed by Dawn LUCI CQ
parent af4ca3891f
commit 03ee23ea9e
2 changed files with 42 additions and 8 deletions

View File

@ -56,6 +56,7 @@
#include "src/tint/program.h"
#include "src/tint/sem/builtin.h"
#include "src/tint/sem/call.h"
#include "src/tint/sem/materialize.h"
#include "src/tint/sem/module.h"
#include "src/tint/sem/switch_statement.h"
#include "src/tint/sem/value_constructor.h"
@ -751,6 +752,19 @@ utils::Result<Value*> BuilderImpl::EmitCall(const ast::CallStatement* stmt) {
}
utils::Result<Value*> BuilderImpl::EmitCall(const ast::CallExpression* expr) {
// If this is a materialized semantic node, just use the constant value.
if (auto* mat = program_->Sem().Get(expr)) {
if (mat->ConstantValue()) {
auto* cv = mat->ConstantValue()->Clone(clone_ctx_);
if (!cv) {
add_error(expr->source, "failed to get constant value for call " +
std::string(expr->TypeInfo().name));
return utils::Failure;
}
return builder.Constant(cv);
}
}
utils::Vector<Value*, 8> args;
args.Reserve(expr->args.Length());
@ -758,7 +772,7 @@ utils::Result<Value*> BuilderImpl::EmitCall(const ast::CallExpression* expr) {
for (const auto* arg : expr->args) {
auto value = EmitExpression(arg);
if (!value) {
add_error(arg->source, "Failed to convert arguments");
add_error(arg->source, "failed to convert arguments");
return utils::Failure;
}
args.Push(value.Get());
@ -766,7 +780,7 @@ utils::Result<Value*> BuilderImpl::EmitCall(const ast::CallExpression* expr) {
auto* sem = program_->Sem().Get<sem::Call>(expr);
if (!sem) {
add_error(expr->source, "Failed to get semantic information for call " +
add_error(expr->source, "failed to get semantic information for call " +
std::string(expr->TypeInfo().name));
return utils::Failure;
}
@ -778,14 +792,14 @@ utils::Result<Value*> BuilderImpl::EmitCall(const ast::CallExpression* expr) {
// If this is a builtin function, emit the specific builtin value
if (sem->Target()->As<sem::Builtin>()) {
// TODO(dsinclair): .. something ...
add_error(expr->source, "Missing builtin function support");
add_error(expr->source, "missing builtin function support");
} 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";
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.
@ -802,7 +816,7 @@ utils::Result<Value*> BuilderImpl::EmitCall(const ast::CallExpression* expr) {
utils::Result<Value*> BuilderImpl::EmitLiteral(const ast::LiteralExpression* lit) {
auto* sem = program_->Sem().Get(lit);
if (!sem) {
add_error(lit->source, "Failed to get semantic information for node " +
add_error(lit->source, "failed to get semantic information for node " +
std::string(lit->TypeInfo().name));
return utils::Failure;
}
@ -810,7 +824,7 @@ utils::Result<Value*> BuilderImpl::EmitLiteral(const ast::LiteralExpression* lit
auto* cv = sem->ConstantValue()->Clone(clone_ctx_);
if (!cv) {
add_error(lit->source,
"Failed to get constant value for node " + std::string(lit->TypeInfo().name));
"failed to get constant value for node " + std::string(lit->TypeInfo().name));
return utils::Failure;
}
return builder.Constant(cv);

View File

@ -1876,9 +1876,12 @@ TEST_F(IR_BuilderImplTest, EmitStatement_UserFunction) {
)");
}
TEST_F(IR_BuilderImplTest, EmitExpression_ConstructEmpty) {
// TODO(dsinclair): This needs assignment in order to output correctly. The empty constructor ends
// up materializing, so there is no expression to emit until there is a usage. When assigment is
// implemented this can be enabled (and the output updated).
TEST_F(IR_BuilderImplTest, DISABLED_EmitExpression_ConstructEmpty) {
auto* expr = vec3(ty.f32());
WrapInFunction(expr);
GlobalVar("i", builtin::AddressSpace::kPrivate, expr);
auto& b = CreateBuilder();
InjectFlowBlock();
@ -1923,5 +1926,22 @@ TEST_F(IR_BuilderImplTest, EmitExpression_Convert) {
)");
}
TEST_F(IR_BuilderImplTest, EmitExpression_MaterializedCall) {
auto* expr = Return(Call("trunc", 2.5_f));
Func("test_function", {}, ty.f32(), expr, utils::Empty);
auto r = Build();
ASSERT_TRUE(r) << Error();
auto m = r.Move();
EXPECT_EQ(Disassemble(m), R"(%bb0 = Function test_function
%bb1 = Block
Return (2.0)
FunctionEnd
)");
}
} // namespace
} // namespace tint::ir