tint: Remove ast::Void

WGSL does not have a void type. Functions that do not return a value
simply omit the return type from the function signature.

Change-Id: Id45adc008dce46115552e7dc401a2e27ae10eeb4
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/118981
Reviewed-by: James Price <jrprice@google.com>
Kokoro: Ben Clayton <bclayton@google.com>
This commit is contained in:
Ben Clayton 2023-02-07 21:28:09 +00:00
parent 08fd42f08a
commit 1906857a50
19 changed files with 63 additions and 154 deletions

View File

@ -330,7 +330,6 @@ libtint_source_set("libtint_syntax_tree_src") {
"ast/variable.h",
"ast/variable_decl_statement.h",
"ast/vector.h",
"ast/void.h",
"ast/while_statement.h",
"ast/workgroup_attribute.h",
"clone_context.cc",
@ -730,8 +729,6 @@ libtint_source_set("libtint_ast_src") {
"ast/variable_decl_statement.h",
"ast/vector.cc",
"ast/vector.h",
"ast/void.cc",
"ast/void.h",
"ast/while_statement.cc",
"ast/while_statement.h",
"ast/workgroup_attribute.cc",

View File

@ -258,8 +258,6 @@ list(APPEND TINT_LIB_SRCS
ast/variable.h
ast/vector.cc
ast/vector.h
ast/void.cc
ast/void.h
ast/while_statement.cc
ast/while_statement.h
ast/workgroup_attribute.cc

View File

@ -39,13 +39,13 @@ Function::Function(ProgramID pid,
attributes(std::move(attrs)),
return_type_attributes(std::move(return_type_attrs)) {
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, symbol, program_id);
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, return_ty, program_id);
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, body, program_id);
for (auto* param : params) {
TINT_ASSERT(AST, tint::Is<Parameter>(param));
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, param, program_id);
}
TINT_ASSERT(AST, symbol.IsValid());
TINT_ASSERT(AST, return_type);
for (auto* attr : attributes) {
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, attr, program_id);
}

View File

@ -25,14 +25,26 @@ namespace {
using FunctionTest = TestHelper;
TEST_F(FunctionTest, Creation) {
TEST_F(FunctionTest, Creation_i32ReturnType) {
utils::Vector params{Param("var", ty.i32())};
auto* i32 = ty.i32();
auto* var = params[0];
auto* f = Func("func", params, i32, utils::Empty);
EXPECT_EQ(f->symbol, Symbols().Get("func"));
ASSERT_EQ(f->params.Length(), 1u);
EXPECT_EQ(f->return_type, i32);
EXPECT_EQ(f->params[0], var);
}
TEST_F(FunctionTest, Creation_NoReturnType) {
utils::Vector params{Param("var", ty.i32())};
auto* var = params[0];
auto* f = Func("func", params, ty.void_(), utils::Empty);
EXPECT_EQ(f->symbol, Symbols().Get("func"));
ASSERT_EQ(f->params.Length(), 1u);
EXPECT_TRUE(f->return_type->Is<ast::Void>());
EXPECT_EQ(f->return_type, nullptr);
EXPECT_EQ(f->params[0], var);
}
@ -54,15 +66,6 @@ TEST_F(FunctionTest, Assert_InvalidName) {
"internal compiler error");
}
TEST_F(FunctionTest, Assert_Null_ReturnType) {
EXPECT_FATAL_FAILURE(
{
ProgramBuilder b;
b.Func("f", utils::Empty, nullptr, utils::Empty);
},
"internal compiler error");
}
TEST_F(FunctionTest, Assert_Null_Param) {
using ParamList = utils::Vector<const ast::Parameter*, 2>;
EXPECT_FATAL_FAILURE(
@ -113,6 +116,16 @@ TEST_F(FunctionTest, Assert_DifferentProgramID_Attr) {
"internal compiler error");
}
TEST_F(FunctionTest, Assert_DifferentProgramID_ReturnType) {
EXPECT_FATAL_FAILURE(
{
ProgramBuilder b1;
ProgramBuilder b2;
b1.Func("func", utils::Empty, b2.ty.i32(), utils::Empty);
},
"internal compiler error");
}
TEST_F(FunctionTest, Assert_DifferentProgramID_ReturnAttr) {
EXPECT_FATAL_FAILURE(
{

View File

@ -1,38 +0,0 @@
// Copyright 2020 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/ast/void.h"
#include "src/tint/program_builder.h"
TINT_INSTANTIATE_TYPEINFO(tint::ast::Void);
namespace tint::ast {
Void::Void(ProgramID pid, NodeID nid, const Source& src) : Base(pid, nid, src) {}
Void::Void(Void&&) = default;
Void::~Void() = default;
std::string Void::FriendlyName(const SymbolTable&) const {
return "void";
}
const Void* Void::Clone(CloneContext* ctx) const {
auto src = ctx->Clone(source);
return ctx->dst->create<Void>(src);
}
} // namespace tint::ast

View File

@ -1,49 +0,0 @@
// Copyright 2020 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_AST_VOID_H_
#define SRC_TINT_AST_VOID_H_
#include <string>
#include "src/tint/ast/type.h"
namespace tint::ast {
/// A void type
class Void final : public Castable<Void, Type> {
public:
/// Constructor
/// @param pid the identifier of the program that owns this node
/// @param nid the unique node identifier
/// @param src the source of this node
Void(ProgramID pid, NodeID nid, const Source& src);
/// Move constructor
Void(Void&&);
~Void() override;
/// @param symbols the program's symbol table
/// @returns the name for this type that closely resembles how it would be
/// declared in WGSL.
std::string FriendlyName(const SymbolTable& symbols) const override;
/// Clones this type and all transitive types using the `CloneContext` `ctx`.
/// @param ctx the clone context
/// @return the newly cloned type
const Void* Clone(CloneContext* ctx) const override;
};
} // namespace tint::ast
#endif // SRC_TINT_AST_VOID_H_

View File

@ -89,7 +89,6 @@
#include "src/tint/ast/var.h"
#include "src/tint/ast/variable_decl_statement.h"
#include "src/tint/ast/vector.h"
#include "src/tint/ast/void.h"
#include "src/tint/ast/while_statement.h"
#include "src/tint/ast/workgroup_attribute.h"
#include "src/tint/constant/composite.h"
@ -567,6 +566,9 @@ class ProgramBuilder {
return CToAST<T>::get(this);
}
/// @returns nullptr ast::Type
const ast::Type* void_() const { return nullptr; }
/// @returns a boolean type
const ast::Bool* bool_() const { return builder->create<ast::Bool>(); }
@ -612,15 +614,6 @@ class ProgramBuilder {
return builder->create<ast::U32>(source);
}
/// @returns a void type
const ast::Void* void_() const { return builder->create<ast::Void>(); }
/// @param source the Source of the node
/// @returns a void type
const ast::Void* void_(const Source& source) const {
return builder->create<ast::Void>(source);
}
/// @param type vector subtype
/// @param n vector width in elements
/// @return the tint AST type for a `n`-element vector of `type`.

View File

@ -32,15 +32,13 @@ TEST_F(ParserImplTest, FunctionDecl) {
ASSERT_NE(f.value, nullptr);
EXPECT_EQ(f->symbol, p->builder().Symbols().Get("main"));
ASSERT_NE(f->return_type, nullptr);
EXPECT_TRUE(f->return_type->Is<ast::Void>());
EXPECT_EQ(f->return_type, nullptr);
ASSERT_EQ(f->params.Length(), 2u);
EXPECT_EQ(f->params[0]->symbol, p->builder().Symbols().Get("a"));
EXPECT_EQ(f->params[1]->symbol, p->builder().Symbols().Get("b"));
ASSERT_NE(f->return_type, nullptr);
EXPECT_TRUE(f->return_type->Is<ast::Void>());
EXPECT_EQ(f->return_type, nullptr);
auto* body = f->body;
ASSERT_EQ(body->statements.Length(), 1u);
@ -77,15 +75,13 @@ TEST_F(ParserImplTest, FunctionDecl_Unicode) {
ASSERT_NE(f.value, nullptr);
EXPECT_EQ(f->symbol, p->builder().Symbols().Get(function_ident));
ASSERT_NE(f->return_type, nullptr);
EXPECT_TRUE(f->return_type->Is<ast::Void>());
EXPECT_EQ(f->return_type, nullptr);
ASSERT_EQ(f->params.Length(), 2u);
EXPECT_EQ(f->params[0]->symbol, p->builder().Symbols().Get(param_a_ident));
EXPECT_EQ(f->params[1]->symbol, p->builder().Symbols().Get(param_b_ident));
ASSERT_NE(f->return_type, nullptr);
EXPECT_TRUE(f->return_type->Is<ast::Void>());
EXPECT_EQ(f->return_type, nullptr);
auto* body = f->body;
ASSERT_EQ(body->statements.Length(), 1u);
@ -105,8 +101,7 @@ TEST_F(ParserImplTest, FunctionDecl_AttributeList) {
ASSERT_NE(f.value, nullptr);
EXPECT_EQ(f->symbol, p->builder().Symbols().Get("main"));
ASSERT_NE(f->return_type, nullptr);
EXPECT_TRUE(f->return_type->Is<ast::Void>());
EXPECT_EQ(f->return_type, nullptr);
ASSERT_EQ(f->params.Length(), 0u);
auto& attributes = f->attributes;
@ -150,8 +145,7 @@ fn main() { return; })");
ASSERT_NE(f.value, nullptr);
EXPECT_EQ(f->symbol, p->builder().Symbols().Get("main"));
ASSERT_NE(f->return_type, nullptr);
EXPECT_TRUE(f->return_type->Is<ast::Void>());
EXPECT_EQ(f->return_type, nullptr);
ASSERT_EQ(f->params.Length(), 0u);
auto& attributes = f->attributes;
@ -199,8 +193,7 @@ fn main() { return; })");
ASSERT_NE(f.value, nullptr);
EXPECT_EQ(f->symbol, p->builder().Symbols().Get("main"));
ASSERT_NE(f->return_type, nullptr);
EXPECT_TRUE(f->return_type->Is<ast::Void>());
EXPECT_EQ(f->return_type, nullptr);
ASSERT_EQ(f->params.Length(), 0u);
auto& attrs = f->attributes;

View File

@ -28,7 +28,7 @@ TEST_F(ParserImplTest, FunctionHeader) {
ASSERT_EQ(f->params.Length(), 2u);
EXPECT_EQ(f->params[0]->symbol, p->builder().Symbols().Get("a"));
EXPECT_EQ(f->params[1]->symbol, p->builder().Symbols().Get("b"));
EXPECT_TRUE(f->return_type->Is<ast::Void>());
EXPECT_EQ(f->return_type, nullptr);
}
TEST_F(ParserImplTest, FunctionHeader_TrailingComma) {
@ -40,7 +40,7 @@ TEST_F(ParserImplTest, FunctionHeader_TrailingComma) {
EXPECT_EQ(f->name, "main");
ASSERT_EQ(f->params.Length(), 1u);
EXPECT_EQ(f->params[0]->symbol, p->builder().Symbols().Get("a"));
EXPECT_TRUE(f->return_type->Is<ast::Void>());
EXPECT_EQ(f->return_type, nullptr);
}
TEST_F(ParserImplTest, FunctionHeader_AttributeReturnType) {

View File

@ -67,7 +67,6 @@
#include "src/tint/ast/u32.h"
#include "src/tint/ast/variable_decl_statement.h"
#include "src/tint/ast/vector.h"
#include "src/tint/ast/void.h"
#include "src/tint/ast/while_statement.h"
#include "src/tint/ast/workgroup_attribute.h"
#include "src/tint/scope_stack.h"
@ -405,7 +404,7 @@ class DependencyScanner {
TraverseType(tex->type);
},
[&](Default) {
if (!ty->IsAnyOf<ast::Void, ast::Bool, ast::I32, ast::U32, ast::F16, ast::F32,
if (!ty->IsAnyOf<ast::Bool, ast::I32, ast::U32, ast::F16, ast::F32,
ast::DepthTexture, ast::DepthMultisampledTexture,
ast::StorageTexture, ast::ExternalTexture, ast::Sampler>()) {
UnhandledNode(diagnostics_, ty);

View File

@ -214,10 +214,13 @@ bool Resolver::ResolveInternal() {
}
type::Type* Resolver::Type(const ast::Type* ty) {
if (ty == nullptr) {
return builder_->create<type::Void>();
}
Mark(ty);
auto* s = Switch(
ty, //
[&](const ast::Void*) { return builder_->create<type::Void>(); },
[&](const ast::Bool*) { return builder_->create<type::Bool>(); },
[&](const ast::I32*) { return builder_->create<type::I32>(); },
[&](const ast::U32*) { return builder_->create<type::U32>(); },

View File

@ -149,10 +149,6 @@
<DisplayString>{value}</DisplayString>
</Type>
<Type Name="tint::ast::Void">
<DisplayString>void</DisplayString>
</Type>
<Type Name="tint::ast::UnaryOpExpression">
<DisplayString Condition="op==tint::ast::UnaryOp::kAddressOf">&amp;({*expr})</DisplayString>
<DisplayString Condition="op==tint::ast::UnaryOp::kComplement">~({*expr})</DisplayString>

View File

@ -154,7 +154,7 @@ class State {
flag = b.Symbols().New("tint_return_flag");
new_stmts[0].Push(b.Decl(b.Var(flag, b.ty.bool_())));
if (!function->return_type->Is<ast::Void>()) {
if (function->return_type) {
retval = b.Symbols().New("tint_return_value");
new_stmts[0].Push(b.Decl(b.Var(retval, ctx.Clone(function->return_type))));
}

View File

@ -75,7 +75,7 @@ void Transform::RemoveStatement(CloneContext& ctx, const ast::Statement* stmt) {
const ast::Type* Transform::CreateASTTypeFor(CloneContext& ctx, const type::Type* ty) {
if (ty->Is<type::Void>()) {
return ctx.dst->create<ast::Void>();
return nullptr;
}
if (ty->Is<type::I32>()) {
return ctx.dst->create<ast::I32>();

View File

@ -45,7 +45,7 @@ TEST_F(CreateASTTypeForTest, Basic) {
EXPECT_TRUE(create([](ProgramBuilder& b) { return b.create<type::U32>(); })->Is<ast::U32>());
EXPECT_TRUE(create([](ProgramBuilder& b) { return b.create<type::F32>(); })->Is<ast::F32>());
EXPECT_TRUE(create([](ProgramBuilder& b) { return b.create<type::Bool>(); })->Is<ast::Bool>());
EXPECT_TRUE(create([](ProgramBuilder& b) { return b.create<type::Void>(); })->Is<ast::Void>());
EXPECT_EQ(create([](ProgramBuilder& b) { return b.create<type::Void>(); }), nullptr);
}
TEST_F(CreateASTTypeForTest, Matrix) {

View File

@ -2260,8 +2260,11 @@ bool GeneratorImpl::EmitEntryPointFunction(const ast::Function* func) {
// Emit original entry point signature
{
auto out = line();
out << func->return_type->FriendlyName(builder_.Symbols()) << " "
<< builder_.Symbols().NameFor(func->symbol) << "(";
if (!EmitTypeAndName(out, func_sem->ReturnType(), type::AddressSpace::kUndefined,
type::Access::kUndefined, builder_.Symbols().NameFor(func->symbol))) {
return false;
}
out << "(";
bool first = true;

View File

@ -3238,9 +3238,11 @@ bool GeneratorImpl::EmitEntryPointFunction(const ast::Function* func) {
out << ")]" << std::endl;
}
out << func->return_type->FriendlyName(builder_.Symbols());
out << " " << builder_.Symbols().NameFor(func->symbol) << "(";
if (!EmitTypeAndName(out, func_sem->ReturnType(), type::AddressSpace::kUndefined,
type::Access::kUndefined, builder_.Symbols().NameFor(func->symbol))) {
return false;
}
out << "(";
bool first = true;

View File

@ -30,7 +30,6 @@
#include "src/tint/ast/interpolate_attribute.h"
#include "src/tint/ast/module.h"
#include "src/tint/ast/variable_decl_statement.h"
#include "src/tint/ast/void.h"
#include "src/tint/constant/value.h"
#include "src/tint/sem/call.h"
#include "src/tint/sem/function.h"
@ -1974,6 +1973,8 @@ std::string GeneratorImpl::interpolation_to_attribute(ast::InterpolationType typ
}
bool GeneratorImpl::EmitEntryPointFunction(const ast::Function* func) {
auto* func_sem = builder_.Sem().Get(func);
auto func_name = program_->Symbols().NameFor(func->symbol);
// Returns the binding index of a variable, requiring that the group
@ -1999,8 +2000,11 @@ bool GeneratorImpl::EmitEntryPointFunction(const ast::Function* func) {
auto out = line();
EmitStage(out, func->PipelineStage());
out << " " << func->return_type->FriendlyName(program_->Symbols());
out << " " << func_name << "(";
out << " ";
if (!EmitTypeAndName(out, func_sem->ReturnType(), func_name)) {
return false;
}
out << "(";
// Emit entry point parameters.
bool first = true;

View File

@ -46,7 +46,6 @@
#include "src/tint/ast/u32.h"
#include "src/tint/ast/variable_decl_statement.h"
#include "src/tint/ast/vector.h"
#include "src/tint/ast/void.h"
#include "src/tint/ast/workgroup_attribute.h"
#include "src/tint/sem/struct.h"
#include "src/tint/sem/switch_statement.h"
@ -334,7 +333,7 @@ bool GeneratorImpl::EmitFunction(const ast::Function* func) {
out << ")";
if (!func->return_type->Is<ast::Void>() || !func->return_type_attributes.IsEmpty()) {
if (func->return_type || !func->return_type_attributes.IsEmpty()) {
out << " -> ";
if (!func->return_type_attributes.IsEmpty()) {
@ -590,10 +589,6 @@ bool GeneratorImpl::EmitType(std::ostream& out, const ast::Type* ty) {
}
return true;
},
[&](const ast::Void*) {
out << "void";
return true;
},
[&](const ast::TypeName* tn) {
out << program_->Symbols().NameFor(tn->name->symbol);
return true;