tint/resolver: Add builtin_structs.h / .cc

Contains the builtin structure creation logic moved out from
intrinsic_table.cc.

Bug: chromium:1430309
Change-Id: I2207f9ae42c6d7343c2f2ffa81effde59e6023fe
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/129481
Reviewed-by: Dan Sinclair <dsinclair@chromium.org>
Commit-Queue: Ben Clayton <bclayton@chromium.org>
Kokoro: Kokoro <noreply+kokoro@google.com>
This commit is contained in:
Ben Clayton 2023-04-26 18:25:03 +00:00 committed by Dawn LUCI CQ
parent aae9f6bc5f
commit d3b09b90e3
5 changed files with 257 additions and 151 deletions

View File

@ -281,6 +281,8 @@ libtint_source_set("libtint_program_src") {
"clone_context.cc", "clone_context.cc",
"program.cc", "program.cc",
"program_builder.cc", "program_builder.cc",
"resolver/builtin_structs.cc",
"resolver/builtin_structs.h",
"resolver/const_eval.cc", "resolver/const_eval.cc",
"resolver/const_eval.h", "resolver/const_eval.h",
"resolver/ctor_conv_intrinsic.cc", "resolver/ctor_conv_intrinsic.cc",

View File

@ -264,6 +264,8 @@ list(APPEND TINT_LIB_SRCS
reflection.h reflection.h
reader/reader.cc reader/reader.cc
reader/reader.h reader/reader.h
resolver/builtin_structs.cc
resolver/builtin_structs.h
resolver/const_eval.cc resolver/const_eval.cc
resolver/const_eval.h resolver/const_eval.h
resolver/dependency_graph.cc resolver/dependency_graph.cc

View File

@ -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 <algorithm>
#include <string>
#include <utility>
#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<NameAndType> member_names_and_types) {
uint32_t offset = 0;
uint32_t max_align = 0;
utils::Vector<const sem::StructMember*, 4> members;
for (auto& m : member_names_and_types) {
uint32_t align = std::max<uint32_t>(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<sem::StructMember>(
/* declaration */ nullptr,
/* source */ Source{},
/* name */ b.Sym(m.name),
/* type */ m.type,
/* index */ static_cast<uint32_t>(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<sem::Struct>(
/* 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<type::F32>();
auto* f16 = b.create<type::F16>();
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<type::Vector>(b.create<type::F32>(), width);
auto* vec_f16 = b.create<type::Vector>(b.create<type::F16>(), 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<type::I32>();
return BuildStruct(b, "__frexp_result_f32", {{"fract", ty}, {"exp", i32}});
},
[&](const type::F16*) {
auto* i32 = b.create<type::I32>();
return BuildStruct(b, "__frexp_result_f16", {{"fract", ty}, {"exp", i32}});
},
[&](const type::AbstractFloat*) {
auto* f32 = b.create<type::F32>();
auto* f16 = b.create<type::F16>();
auto* i32 = b.create<type::I32>();
auto* ai = b.create<type::AbstractInt>();
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<type::Vector>(b.create<type::I32>(), width);
return BuildStruct(b, prefix + "_f32", {{"fract", ty}, {"exp", vec_i32}});
},
[&](const type::F16*) {
auto* vec_i32 = b.create<type::Vector>(b.create<type::I32>(), width);
return BuildStruct(b, prefix + "_f16", {{"fract", ty}, {"exp", vec_i32}});
},
[&](const type::AbstractFloat*) {
auto* vec_f32 = b.create<type::Vector>(b.create<type::F32>(), width);
auto* vec_f16 = b.create<type::Vector>(b.create<type::F16>(), width);
auto* vec_i32 = b.create<type::Vector>(b.create<type::I32>(), width);
auto* vec_ai = b.create<type::Vector>(b.create<type::AbstractInt>(), 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<type::Type*>(ty)}, {"exchanged", b.create<type::Bool>()}});
}
} // namespace tint::resolver

View File

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

View File

@ -20,6 +20,7 @@
#include "src/tint/ast/binary_expression.h" #include "src/tint/ast/binary_expression.h"
#include "src/tint/program_builder.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/evaluation_stage.h"
#include "src/tint/sem/pipeline_stage_set.h" #include "src/tint/sem/pipeline_stage_set.h"
#include "src/tint/sem/value_constructor.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; return false;
} }
struct NameAndType {
std::string name;
const type::Type* type;
};
sem::Struct* build_struct(ProgramBuilder& b,
std::string name,
std::initializer_list<NameAndType> member_names_and_types) {
uint32_t offset = 0;
uint32_t max_align = 0;
utils::Vector<const sem::StructMember*, 4> members;
for (auto& m : member_names_and_types) {
uint32_t align = std::max<uint32_t>(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<sem::StructMember>(
/* declaration */ nullptr,
/* source */ Source{},
/* name */ b.Sym(m.name),
/* type */ m.type,
/* index */ static_cast<uint32_t>(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<sem::Struct>(
/* 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) { const sem::Struct* build_modf_result(MatchState& state, const type::Type* el) {
auto build_f32 = [&] { return CreateModfResult(state.builder, el);
auto* ty = state.builder.create<type::F32>();
return build_struct(state.builder, "__modf_result_f32", {{"fract", ty}, {"whole", ty}});
};
auto build_f16 = [&] {
auto* ty = state.builder.create<type::F16>();
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;
});
} }
const sem::Struct* build_modf_result_vec(MatchState& state, Number& n, const type::Type* 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<type::Vector>(state.builder.create<type::F32>(), n.Value());
return build_struct(state.builder, prefix + "_f32", {{"fract", vec}, {"whole", vec}});
};
auto build_f16 = [&] {
auto* vec =
state.builder.create<type::Vector>(state.builder.create<type::F16>(), 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<type::Vector>(el, n.Value()); auto* vec = state.builder.create<type::Vector>(el, n.Value());
auto* abstract = return CreateModfResult(state.builder, vec);
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;
});
} }
const sem::Struct* build_frexp_result(MatchState& state, const type::Type* el) { const sem::Struct* build_frexp_result(MatchState& state, const type::Type* el) {
auto build_f32 = [&] { return CreateFrexpResult(state.builder, el);
auto* f = state.builder.create<type::F32>();
auto* i = state.builder.create<type::I32>();
return build_struct(state.builder, "__frexp_result_f32", {{"fract", f}, {"exp", i}});
};
auto build_f16 = [&] {
auto* f = state.builder.create<type::F16>();
auto* i = state.builder.create<type::I32>();
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<type::AbstractInt>();
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;
});
} }
const sem::Struct* build_frexp_result_vec(MatchState& state, Number& n, const type::Type* 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* vec = state.builder.create<type::Vector>(el, n.Value());
auto build_f32 = [&] { return CreateFrexpResult(state.builder, vec);
auto* f = state.builder.create<type::Vector>(state.builder.create<type::F32>(), n.Value());
auto* e = state.builder.create<type::Vector>(state.builder.create<type::I32>(), n.Value());
return build_struct(state.builder, prefix + "_f32", {{"fract", f}, {"exp", e}});
};
auto build_f16 = [&] {
auto* f = state.builder.create<type::Vector>(state.builder.create<type::F16>(), n.Value());
auto* e = state.builder.create<type::Vector>(state.builder.create<type::I32>(), 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<type::Vector>(el, n.Value());
auto* e = state.builder.create<type::Vector>(state.builder.create<type::AbstractInt>(),
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;
});
} }
const sem::Struct* build_atomic_compare_exchange_result(MatchState& state, const type::Type* ty) { 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(), return CreateAtomicCompareExchangeResult(state.builder, ty);
{{"old_value", const_cast<type::Type*>(ty)},
{"exchanged", state.builder.create<type::Bool>()}});
} }
/// ParameterInfo describes a parameter /// ParameterInfo describes a parameter