diff --git a/src/tint/BUILD.gn b/src/tint/BUILD.gn index 492e355712..8f9a688e29 100644 --- a/src/tint/BUILD.gn +++ b/src/tint/BUILD.gn @@ -281,6 +281,8 @@ libtint_source_set("libtint_program_src") { "clone_context.cc", "program.cc", "program_builder.cc", + "resolver/builtin_structs.cc", + "resolver/builtin_structs.h", "resolver/const_eval.cc", "resolver/const_eval.h", "resolver/ctor_conv_intrinsic.cc", diff --git a/src/tint/CMakeLists.txt b/src/tint/CMakeLists.txt index f71542873a..c5bcfb0793 100644 --- a/src/tint/CMakeLists.txt +++ b/src/tint/CMakeLists.txt @@ -264,6 +264,8 @@ list(APPEND TINT_LIB_SRCS reflection.h reader/reader.cc reader/reader.h + resolver/builtin_structs.cc + resolver/builtin_structs.h resolver/const_eval.cc resolver/const_eval.h resolver/dependency_graph.cc diff --git a/src/tint/resolver/builtin_structs.cc b/src/tint/resolver/builtin_structs.cc new file mode 100644 index 0000000000..02f170897b --- /dev/null +++ b/src/tint/resolver/builtin_structs.cc @@ -0,0 +1,194 @@ +// 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/resolver/builtin_structs.h" + +#include +#include +#include + +#include "src/tint/program_builder.h" +#include "src/tint/switch.h" +#include "src/tint/type/abstract_float.h" +#include "src/tint/type/abstract_int.h" +#include "src/tint/type/vector.h" + +namespace tint::resolver { + +namespace { + +struct NameAndType { + std::string name; + const type::Type* type; +}; + +sem::Struct* BuildStruct(ProgramBuilder& b, + std::string name, + std::initializer_list member_names_and_types) { + uint32_t offset = 0; + uint32_t max_align = 0; + utils::Vector members; + for (auto& m : member_names_and_types) { + uint32_t align = std::max(m.type->Align(), 1); + uint32_t size = m.type->Size(); + offset = utils::RoundUp(align, offset); + max_align = std::max(max_align, align); + members.Push(b.create( + /* declaration */ nullptr, + /* source */ Source{}, + /* name */ b.Sym(m.name), + /* type */ m.type, + /* index */ static_cast(members.Length()), + /* offset */ offset, + /* align */ align, + /* size */ size, + /* location */ std::nullopt)); + offset += size; + } + uint32_t size_without_padding = offset; + uint32_t size_with_padding = utils::RoundUp(max_align, offset); + return b.create( + /* declaration */ nullptr, + /* source */ Source{}, + /* name */ b.Sym(name), + /* members */ std::move(members), + /* align */ max_align, + /* size */ size_with_padding, + /* size_no_padding */ size_without_padding); +} +} // namespace + +sem::Struct* CreateModfResult(ProgramBuilder& b, const type::Type* ty) { + return Switch( + ty, + [&](const type::F32*) { + return BuildStruct(b, "__modf_result_f32", {{"fract", ty}, {"whole", ty}}); + }, // + [&](const type::F16*) { + return BuildStruct(b, "__modf_result_f16", {{"fract", ty}, {"whole", ty}}); + }, + [&](const type::AbstractFloat*) { + auto* abstract = + BuildStruct(b, "__modf_result_abstract", {{"fract", ty}, {"whole", ty}}); + auto* f32 = b.create(); + auto* f16 = b.create(); + abstract->SetConcreteTypes(utils::Vector{ + BuildStruct(b, "__modf_result_f32", {{"fract", f32}, {"whole", f32}}), + BuildStruct(b, "__modf_result_f16", {{"fract", f16}, {"whole", f16}}), + }); + return abstract; + }, + [&](const type::Vector* vec) { + auto width = vec->Width(); + auto prefix = "__modf_result_vec" + std::to_string(width); + return Switch( + vec->type(), // + [&](const type::F32*) { + return BuildStruct(b, prefix + "_f32", {{"fract", vec}, {"whole", vec}}); + }, + [&](const type::F16*) { + return BuildStruct(b, prefix + "_f16", {{"fract", vec}, {"whole", vec}}); + }, + [&](const type::AbstractFloat*) { + auto* vec_f32 = b.create(b.create(), width); + auto* vec_f16 = b.create(b.create(), width); + auto* abstract = + BuildStruct(b, prefix + "_abstract", {{"fract", vec}, {"whole", vec}}); + abstract->SetConcreteTypes(utils::Vector{ + BuildStruct(b, prefix + "_f32", {{"fract", vec_f32}, {"whole", vec_f32}}), + BuildStruct(b, prefix + "_f16", {{"fract", vec_f16}, {"whole", vec_f16}}), + }); + return abstract; + }, + [&](Default) { + TINT_ICE(Resolver, b.Diagnostics()) + << "unhandled modf type: " << b.FriendlyName(ty); + return nullptr; + }); + }, + [&](Default) { + TINT_ICE(Resolver, b.Diagnostics()) << "unhandled modf type: " << b.FriendlyName(ty); + return nullptr; + }); +} + +sem::Struct* CreateFrexpResult(ProgramBuilder& b, const type::Type* ty) { + return Switch( + ty, // + [&](const type::F32*) { + auto* i32 = b.create(); + return BuildStruct(b, "__frexp_result_f32", {{"fract", ty}, {"exp", i32}}); + }, + [&](const type::F16*) { + auto* i32 = b.create(); + return BuildStruct(b, "__frexp_result_f16", {{"fract", ty}, {"exp", i32}}); + }, + [&](const type::AbstractFloat*) { + auto* f32 = b.create(); + auto* f16 = b.create(); + auto* i32 = b.create(); + auto* ai = b.create(); + auto* abstract = + BuildStruct(b, "__frexp_result_abstract", {{"fract", ty}, {"exp", ai}}); + abstract->SetConcreteTypes(utils::Vector{ + BuildStruct(b, "__frexp_result_f32", {{"fract", f32}, {"exp", i32}}), + BuildStruct(b, "__frexp_result_f16", {{"fract", f16}, {"exp", i32}}), + }); + return abstract; + }, + [&](const type::Vector* vec) { + auto width = vec->Width(); + auto prefix = "__frexp_result_vec" + std::to_string(width); + return Switch( + vec->type(), // + [&](const type::F32*) { + auto* vec_i32 = b.create(b.create(), width); + return BuildStruct(b, prefix + "_f32", {{"fract", ty}, {"exp", vec_i32}}); + }, + [&](const type::F16*) { + auto* vec_i32 = b.create(b.create(), width); + return BuildStruct(b, prefix + "_f16", {{"fract", ty}, {"exp", vec_i32}}); + }, + [&](const type::AbstractFloat*) { + auto* vec_f32 = b.create(b.create(), width); + auto* vec_f16 = b.create(b.create(), width); + auto* vec_i32 = b.create(b.create(), width); + auto* vec_ai = b.create(b.create(), width); + auto* abstract = + BuildStruct(b, prefix + "_abstract", {{"fract", ty}, {"exp", vec_ai}}); + abstract->SetConcreteTypes(utils::Vector{ + BuildStruct(b, prefix + "_f32", {{"fract", vec_f32}, {"exp", vec_i32}}), + BuildStruct(b, prefix + "_f16", {{"fract", vec_f16}, {"exp", vec_i32}}), + }); + return abstract; + }, + [&](Default) { + TINT_ICE(Resolver, b.Diagnostics()) + << "unhandled frexp type: " << b.FriendlyName(ty); + return nullptr; + }); + }, + [&](Default) { + TINT_ICE(Resolver, b.Diagnostics()) << "unhandled frexp type: " << b.FriendlyName(ty); + return nullptr; + }); +} + +sem::Struct* CreateAtomicCompareExchangeResult(ProgramBuilder& b, const type::Type* ty) { + return BuildStruct( + b, "__atomic_compare_exchange_result" + ty->FriendlyName(), + {{"old_value", const_cast(ty)}, {"exchanged", b.create()}}); +} + +} // namespace tint::resolver diff --git a/src/tint/resolver/builtin_structs.h b/src/tint/resolver/builtin_structs.h new file mode 100644 index 0000000000..f8451dfd86 --- /dev/null +++ b/src/tint/resolver/builtin_structs.h @@ -0,0 +1,51 @@ +// 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_RESOLVER_BUILTIN_STRUCTS_H_ +#define SRC_TINT_RESOLVER_BUILTIN_STRUCTS_H_ + +// Forward declarations +namespace tint { +class ProgramBuilder; +} // namespace tint +namespace tint::sem { +class Struct; +} // namespace tint::sem +namespace tint::type { +class Type; +} // namespace tint::type + +namespace tint::resolver { + +/** + * @param ty the type of the `fract` and `whole` struct members. + * @return the builtin struct type for a modf() builtin call. + */ +sem::Struct* CreateModfResult(ProgramBuilder& b, const type::Type* ty); + +/** + * @param fract the type of the `fract` struct member. + * @return the builtin struct type for a frexp() builtin call. + */ +sem::Struct* CreateFrexpResult(ProgramBuilder& b, const type::Type* fract); + +/** + * @param ty the type of the `old_value` struct member. + * @return the builtin struct type for a atomic_compare_exchange() builtin call. + */ +sem::Struct* CreateAtomicCompareExchangeResult(ProgramBuilder& b, const type::Type* ty); + +} // namespace tint::resolver + +#endif // SRC_TINT_RESOLVER_BUILTIN_STRUCTS_H_ diff --git a/src/tint/resolver/intrinsic_table.cc b/src/tint/resolver/intrinsic_table.cc index fc226eb52a..89b7148789 100644 --- a/src/tint/resolver/intrinsic_table.cc +++ b/src/tint/resolver/intrinsic_table.cc @@ -20,6 +20,7 @@ #include "src/tint/ast/binary_expression.h" #include "src/tint/program_builder.h" +#include "src/tint/resolver/builtin_structs.h" #include "src/tint/sem/evaluation_stage.h" #include "src/tint/sem/pipeline_stage_set.h" #include "src/tint/sem/value_constructor.h" @@ -819,170 +820,26 @@ bool match_atomic_compare_exchange_result(MatchState&, const type::Type* ty, con return false; } -struct NameAndType { - std::string name; - const type::Type* type; -}; -sem::Struct* build_struct(ProgramBuilder& b, - std::string name, - std::initializer_list member_names_and_types) { - uint32_t offset = 0; - uint32_t max_align = 0; - utils::Vector members; - for (auto& m : member_names_and_types) { - uint32_t align = std::max(m.type->Align(), 1); - uint32_t size = m.type->Size(); - offset = utils::RoundUp(align, offset); - max_align = std::max(max_align, align); - members.Push(b.create( - /* declaration */ nullptr, - /* source */ Source{}, - /* name */ b.Sym(m.name), - /* type */ m.type, - /* index */ static_cast(members.Length()), - /* offset */ offset, - /* align */ align, - /* size */ size, - /* location */ std::nullopt)); - offset += size; - } - uint32_t size_without_padding = offset; - uint32_t size_with_padding = utils::RoundUp(max_align, offset); - return b.create( - /* declaration */ nullptr, - /* source */ Source{}, - /* name */ b.Sym(name), - /* members */ std::move(members), - /* align */ max_align, - /* size */ size_with_padding, - /* size_no_padding */ size_without_padding); -} - const sem::Struct* build_modf_result(MatchState& state, const type::Type* el) { - auto build_f32 = [&] { - auto* ty = state.builder.create(); - return build_struct(state.builder, "__modf_result_f32", {{"fract", ty}, {"whole", ty}}); - }; - auto build_f16 = [&] { - auto* ty = state.builder.create(); - return build_struct(state.builder, "__modf_result_f16", {{"fract", ty}, {"whole", ty}}); - }; - - return Switch( - el, // - [&](const type::F32*) { return build_f32(); }, // - [&](const type::F16*) { return build_f16(); }, // - [&](const type::AbstractFloat*) { - auto* abstract = build_struct(state.builder, "__modf_result_abstract", - {{"fract", el}, {"whole", el}}); - abstract->SetConcreteTypes(utils::Vector{build_f32(), build_f16()}); - return abstract; - }, - [&](Default) { - TINT_ICE(Resolver, state.builder.Diagnostics()) - << "unhandled modf type: " << state.builder.FriendlyName(el); - return nullptr; - }); + return CreateModfResult(state.builder, el); } const sem::Struct* build_modf_result_vec(MatchState& state, Number& n, const type::Type* el) { - auto prefix = "__modf_result_vec" + std::to_string(n.Value()); - auto build_f32 = [&] { - auto* vec = - state.builder.create(state.builder.create(), n.Value()); - return build_struct(state.builder, prefix + "_f32", {{"fract", vec}, {"whole", vec}}); - }; - auto build_f16 = [&] { - auto* vec = - state.builder.create(state.builder.create(), n.Value()); - return build_struct(state.builder, prefix + "_f16", {{"fract", vec}, {"whole", vec}}); - }; - - return Switch( - el, // - [&](const type::F32*) { return build_f32(); }, // - [&](const type::F16*) { return build_f16(); }, // - [&](const type::AbstractFloat*) { - auto* vec = state.builder.create(el, n.Value()); - auto* abstract = - build_struct(state.builder, prefix + "_abstract", {{"fract", vec}, {"whole", vec}}); - abstract->SetConcreteTypes(utils::Vector{build_f32(), build_f16()}); - return abstract; - }, - [&](Default) { - TINT_ICE(Resolver, state.builder.Diagnostics()) - << "unhandled modf type: " << state.builder.FriendlyName(el); - return nullptr; - }); + auto* vec = state.builder.create(el, n.Value()); + return CreateModfResult(state.builder, vec); } const sem::Struct* build_frexp_result(MatchState& state, const type::Type* el) { - auto build_f32 = [&] { - auto* f = state.builder.create(); - auto* i = state.builder.create(); - return build_struct(state.builder, "__frexp_result_f32", {{"fract", f}, {"exp", i}}); - }; - auto build_f16 = [&] { - auto* f = state.builder.create(); - auto* i = state.builder.create(); - return build_struct(state.builder, "__frexp_result_f16", {{"fract", f}, {"exp", i}}); - }; - - return Switch( - el, // - [&](const type::F32*) { return build_f32(); }, // - [&](const type::F16*) { return build_f16(); }, // - [&](const type::AbstractFloat*) { - auto* i = state.builder.create(); - auto* abstract = - build_struct(state.builder, "__frexp_result_abstract", {{"fract", el}, {"exp", i}}); - abstract->SetConcreteTypes(utils::Vector{build_f32(), build_f16()}); - return abstract; - }, - [&](Default) { - TINT_ICE(Resolver, state.builder.Diagnostics()) - << "unhandled frexp type: " << state.builder.FriendlyName(el); - return nullptr; - }); + return CreateFrexpResult(state.builder, el); } const sem::Struct* build_frexp_result_vec(MatchState& state, Number& n, const type::Type* el) { - auto prefix = "__frexp_result_vec" + std::to_string(n.Value()); - auto build_f32 = [&] { - auto* f = state.builder.create(state.builder.create(), n.Value()); - auto* e = state.builder.create(state.builder.create(), n.Value()); - return build_struct(state.builder, prefix + "_f32", {{"fract", f}, {"exp", e}}); - }; - auto build_f16 = [&] { - auto* f = state.builder.create(state.builder.create(), n.Value()); - auto* e = state.builder.create(state.builder.create(), n.Value()); - return build_struct(state.builder, prefix + "_f16", {{"fract", f}, {"exp", e}}); - }; - - return Switch( - el, // - [&](const type::F32*) { return build_f32(); }, // - [&](const type::F16*) { return build_f16(); }, // - [&](const type::AbstractFloat*) { - auto* f = state.builder.create(el, n.Value()); - auto* e = state.builder.create(state.builder.create(), - n.Value()); - auto* abstract = - build_struct(state.builder, prefix + "_abstract", {{"fract", f}, {"exp", e}}); - abstract->SetConcreteTypes(utils::Vector{build_f32(), build_f16()}); - return abstract; - }, - [&](Default) { - TINT_ICE(Resolver, state.builder.Diagnostics()) - << "unhandled frexp type: " << state.builder.FriendlyName(el); - return nullptr; - }); + auto* vec = state.builder.create(el, n.Value()); + return CreateFrexpResult(state.builder, vec); } const sem::Struct* build_atomic_compare_exchange_result(MatchState& state, const type::Type* ty) { - return build_struct(state.builder, "__atomic_compare_exchange_result" + ty->FriendlyName(), - {{"old_value", const_cast(ty)}, - {"exchanged", state.builder.create()}}); + return CreateAtomicCompareExchangeResult(state.builder, ty); } /// ParameterInfo describes a parameter