mirror of
https://github.com/encounter/dawn-cmake.git
synced 2025-06-08 07:33:33 +00:00
Factor out structure layout print function
Simplifies Resolver::ValidateStorageClassLayout and would allow us to use this function for displaying structure layout in a language server, for example. Bug: tint:1348 Change-Id: I9d83329f0a168e5d8c094b3282d07cd1ab321dca Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/76080 Reviewed-by: Ben Clayton <bclayton@google.com> Kokoro: Kokoro <noreply+kokoro@google.com> Commit-Queue: Antonio Maiorano <amaiorano@google.com>
This commit is contained in:
parent
65112dc77c
commit
e232e35723
@ -15,8 +15,6 @@
|
|||||||
#include "src/resolver/resolver.h"
|
#include "src/resolver/resolver.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cmath>
|
|
||||||
#include <iomanip>
|
|
||||||
#include <limits>
|
#include <limits>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
@ -257,87 +255,6 @@ bool Resolver::ValidateStorageClassLayout(const sem::Struct* str,
|
|||||||
return builder_->Symbols().NameFor(sm->Declaration()->symbol);
|
return builder_->Symbols().NameFor(sm->Declaration()->symbol);
|
||||||
};
|
};
|
||||||
|
|
||||||
auto type_name_of = [this](const sem::StructMember* sm) {
|
|
||||||
return TypeNameOf(sm->Type());
|
|
||||||
};
|
|
||||||
|
|
||||||
// TODO(amaiorano): Output struct and member decorations so that this output
|
|
||||||
// can be copied verbatim back into source
|
|
||||||
auto get_struct_layout_string = [this, member_name_of, type_name_of](
|
|
||||||
const sem::Struct* st) -> std::string {
|
|
||||||
std::stringstream ss;
|
|
||||||
|
|
||||||
if (st->Members().empty()) {
|
|
||||||
TINT_ICE(Resolver, diagnostics_) << "Validation should have ensured that "
|
|
||||||
"structs have at least one member";
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
const auto* const last_member = st->Members().back();
|
|
||||||
const uint32_t last_member_struct_padding_offset =
|
|
||||||
last_member->Offset() + last_member->Size();
|
|
||||||
|
|
||||||
// Compute max widths to align output
|
|
||||||
const auto offset_w =
|
|
||||||
static_cast<int>(::log10(last_member_struct_padding_offset)) + 1;
|
|
||||||
const auto size_w = static_cast<int>(::log10(st->Size())) + 1;
|
|
||||||
const auto align_w = static_cast<int>(::log10(st->Align())) + 1;
|
|
||||||
|
|
||||||
auto print_struct_begin_line = [&](size_t align, size_t size,
|
|
||||||
std::string struct_name) {
|
|
||||||
ss << "/* " << std::setw(offset_w) << " "
|
|
||||||
<< "align(" << std::setw(align_w) << align << ") size("
|
|
||||||
<< std::setw(size_w) << size << ") */ struct " << struct_name
|
|
||||||
<< " {\n";
|
|
||||||
};
|
|
||||||
|
|
||||||
auto print_struct_end_line = [&]() {
|
|
||||||
ss << "/* "
|
|
||||||
<< std::setw(offset_w + size_w + align_w) << " "
|
|
||||||
<< "*/ };";
|
|
||||||
};
|
|
||||||
|
|
||||||
auto print_member_line = [&](size_t offset, size_t align, size_t size,
|
|
||||||
std::string s) {
|
|
||||||
ss << "/* offset(" << std::setw(offset_w) << offset << ") align("
|
|
||||||
<< std::setw(align_w) << align << ") size(" << std::setw(size_w)
|
|
||||||
<< size << ") */ " << s << ";\n";
|
|
||||||
};
|
|
||||||
|
|
||||||
print_struct_begin_line(st->Align(), st->Size(), TypeNameOf(st));
|
|
||||||
|
|
||||||
for (size_t i = 0; i < st->Members().size(); ++i) {
|
|
||||||
auto* const m = st->Members()[i];
|
|
||||||
|
|
||||||
// Output field alignment padding, if any
|
|
||||||
auto* const prev_member = (i == 0) ? nullptr : st->Members()[i - 1];
|
|
||||||
if (prev_member) {
|
|
||||||
uint32_t padding =
|
|
||||||
m->Offset() - (prev_member->Offset() + prev_member->Size());
|
|
||||||
if (padding > 0) {
|
|
||||||
size_t padding_offset = m->Offset() - padding;
|
|
||||||
print_member_line(padding_offset, 1, padding,
|
|
||||||
"// -- implicit field alignment padding --");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Output member
|
|
||||||
std::string member_name = member_name_of(m);
|
|
||||||
print_member_line(m->Offset(), m->Align(), m->Size(),
|
|
||||||
member_name_of(m) + " : " + type_name_of(m));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Output struct size padding, if any
|
|
||||||
uint32_t struct_padding = st->Size() - last_member_struct_padding_offset;
|
|
||||||
if (struct_padding > 0) {
|
|
||||||
print_member_line(last_member_struct_padding_offset, 1, struct_padding,
|
|
||||||
"// -- implicit struct size padding --");
|
|
||||||
}
|
|
||||||
|
|
||||||
print_struct_end_line();
|
|
||||||
|
|
||||||
return ss.str();
|
|
||||||
};
|
|
||||||
|
|
||||||
if (!ast::IsHostShareable(sc)) {
|
if (!ast::IsHostShareable(sc)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -348,7 +265,8 @@ bool Resolver::ValidateStorageClassLayout(const sem::Struct* str,
|
|||||||
|
|
||||||
// Validate that member is at a valid byte offset
|
// Validate that member is at a valid byte offset
|
||||||
if (m->Offset() % required_align != 0) {
|
if (m->Offset() % required_align != 0) {
|
||||||
AddError("the offset of a struct member of type '" + type_name_of(m) +
|
AddError("the offset of a struct member of type '" +
|
||||||
|
m->Type()->UnwrapRef()->FriendlyName(builder_->Symbols()) +
|
||||||
"' in storage class '" + ast::ToString(sc) +
|
"' in storage class '" + ast::ToString(sc) +
|
||||||
"' must be a multiple of " + std::to_string(required_align) +
|
"' must be a multiple of " + std::to_string(required_align) +
|
||||||
" bytes, but '" + member_name_of(m) +
|
" bytes, but '" + member_name_of(m) +
|
||||||
@ -357,12 +275,12 @@ bool Resolver::ValidateStorageClassLayout(const sem::Struct* str,
|
|||||||
std::to_string(required_align) + ")]] on this member",
|
std::to_string(required_align) + ")]] on this member",
|
||||||
m->Declaration()->source);
|
m->Declaration()->source);
|
||||||
|
|
||||||
AddNote("see layout of struct:\n" + get_struct_layout_string(str),
|
AddNote("see layout of struct:\n" + str->Layout(builder_->Symbols()),
|
||||||
str->Declaration()->source);
|
str->Declaration()->source);
|
||||||
|
|
||||||
if (auto* member_str = m->Type()->As<sem::Struct>()) {
|
if (auto* member_str = m->Type()->As<sem::Struct>()) {
|
||||||
AddNote("and layout of struct member:\n" +
|
AddNote("and layout of struct member:\n" +
|
||||||
get_struct_layout_string(member_str),
|
member_str->Layout(builder_->Symbols()),
|
||||||
member_str->Declaration()->source);
|
member_str->Declaration()->source);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -384,12 +302,12 @@ bool Resolver::ValidateStorageClassLayout(const sem::Struct* str,
|
|||||||
"'. Consider setting [[align(16)]] on this member",
|
"'. Consider setting [[align(16)]] on this member",
|
||||||
m->Declaration()->source);
|
m->Declaration()->source);
|
||||||
|
|
||||||
AddNote("see layout of struct:\n" + get_struct_layout_string(str),
|
AddNote("see layout of struct:\n" + str->Layout(builder_->Symbols()),
|
||||||
str->Declaration()->source);
|
str->Declaration()->source);
|
||||||
|
|
||||||
auto* prev_member_str = prev_member->Type()->As<sem::Struct>();
|
auto* prev_member_str = prev_member->Type()->As<sem::Struct>();
|
||||||
AddNote("and layout of previous member struct:\n" +
|
AddNote("and layout of previous member struct:\n" +
|
||||||
get_struct_layout_string(prev_member_str),
|
prev_member_str->Layout(builder_->Symbols()),
|
||||||
prev_member_str->Declaration()->source);
|
prev_member_str->Declaration()->source);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -413,7 +331,7 @@ bool Resolver::ValidateStorageClassLayout(const sem::Struct* str,
|
|||||||
utils::RoundUp(required_align, arr->Stride())) +
|
utils::RoundUp(required_align, arr->Stride())) +
|
||||||
")]] on the array type",
|
")]] on the array type",
|
||||||
m->Declaration()->type->source);
|
m->Declaration()->type->source);
|
||||||
AddNote("see layout of struct:\n" + get_struct_layout_string(str),
|
AddNote("see layout of struct:\n" + str->Layout(builder_->Symbols()),
|
||||||
str->Declaration()->source);
|
str->Declaration()->source);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -56,6 +56,47 @@ TEST_F(StructTest, FriendlyName) {
|
|||||||
EXPECT_EQ(s->FriendlyName(Symbols()), "my_struct");
|
EXPECT_EQ(s->FriendlyName(Symbols()), "my_struct");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(StructTest, Layout) {
|
||||||
|
auto* inner_st = //
|
||||||
|
Structure("Inner", {
|
||||||
|
Member("a", ty.i32()),
|
||||||
|
Member("b", ty.u32()),
|
||||||
|
Member("c", ty.f32()),
|
||||||
|
Member("d", ty.vec3<f32>()),
|
||||||
|
Member("e", ty.mat4x2<f32>()),
|
||||||
|
});
|
||||||
|
|
||||||
|
auto* outer_st =
|
||||||
|
Structure("Outer", {
|
||||||
|
Member("inner", ty.type_name("Inner")),
|
||||||
|
Member("a", ty.i32()),
|
||||||
|
});
|
||||||
|
|
||||||
|
auto p = Build();
|
||||||
|
ASSERT_TRUE(p.IsValid()) << p.Diagnostics().str();
|
||||||
|
|
||||||
|
auto* sem_inner_st = p.Sem().Get(inner_st);
|
||||||
|
auto* sem_outer_st = p.Sem().Get(outer_st);
|
||||||
|
|
||||||
|
EXPECT_EQ(sem_inner_st->Layout(p.Symbols()),
|
||||||
|
R"(/* align(16) size(64) */ struct Inner {
|
||||||
|
/* offset( 0) align( 4) size( 4) */ a : i32;
|
||||||
|
/* offset( 4) align( 4) size( 4) */ b : u32;
|
||||||
|
/* offset( 8) align( 4) size( 4) */ c : f32;
|
||||||
|
/* offset(12) align( 1) size( 4) */ // -- implicit field alignment padding --;
|
||||||
|
/* offset(16) align(16) size(12) */ d : vec3<f32>;
|
||||||
|
/* offset(28) align( 1) size( 4) */ // -- implicit field alignment padding --;
|
||||||
|
/* offset(32) align( 8) size(32) */ e : mat4x2<f32>;
|
||||||
|
/* */ };)");
|
||||||
|
|
||||||
|
EXPECT_EQ(sem_outer_st->Layout(p.Symbols()),
|
||||||
|
R"(/* align(16) size(80) */ struct Outer {
|
||||||
|
/* offset( 0) align(16) size(64) */ inner : Inner;
|
||||||
|
/* offset(64) align( 4) size( 4) */ a : i32;
|
||||||
|
/* offset(68) align( 1) size(12) */ // -- implicit struct size padding --;
|
||||||
|
/* */ };)");
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
} // namespace sem
|
} // namespace sem
|
||||||
} // namespace tint
|
} // namespace tint
|
||||||
|
@ -14,6 +14,8 @@
|
|||||||
|
|
||||||
#include "src/sem/struct.h"
|
#include "src/sem/struct.h"
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
|
#include <iomanip>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
@ -74,6 +76,82 @@ std::string Struct::FriendlyName(const SymbolTable& symbols) const {
|
|||||||
return symbols.NameFor(name_);
|
return symbols.NameFor(name_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string Struct::Layout(const tint::SymbolTable& symbols) const {
|
||||||
|
std::stringstream ss;
|
||||||
|
|
||||||
|
auto member_name_of = [&](const sem::StructMember* sm) {
|
||||||
|
return symbols.NameFor(sm->Declaration()->symbol);
|
||||||
|
};
|
||||||
|
|
||||||
|
if (Members().empty()) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
const auto* const last_member = Members().back();
|
||||||
|
const uint32_t last_member_struct_padding_offset =
|
||||||
|
last_member->Offset() + last_member->Size();
|
||||||
|
|
||||||
|
// Compute max widths to align output
|
||||||
|
const auto offset_w =
|
||||||
|
static_cast<int>(::log10(last_member_struct_padding_offset)) + 1;
|
||||||
|
const auto size_w = static_cast<int>(::log10(Size())) + 1;
|
||||||
|
const auto align_w = static_cast<int>(::log10(Align())) + 1;
|
||||||
|
|
||||||
|
auto print_struct_begin_line = [&](size_t align, size_t size,
|
||||||
|
std::string struct_name) {
|
||||||
|
ss << "/* " << std::setw(offset_w) << " "
|
||||||
|
<< "align(" << std::setw(align_w) << align << ") size("
|
||||||
|
<< std::setw(size_w) << size << ") */ struct " << struct_name << " {\n";
|
||||||
|
};
|
||||||
|
|
||||||
|
auto print_struct_end_line = [&]() {
|
||||||
|
ss << "/* "
|
||||||
|
<< std::setw(offset_w + size_w + align_w) << " "
|
||||||
|
<< "*/ };";
|
||||||
|
};
|
||||||
|
|
||||||
|
auto print_member_line = [&](size_t offset, size_t align, size_t size,
|
||||||
|
std::string s) {
|
||||||
|
ss << "/* offset(" << std::setw(offset_w) << offset << ") align("
|
||||||
|
<< std::setw(align_w) << align << ") size(" << std::setw(size_w) << size
|
||||||
|
<< ") */ " << s << ";\n";
|
||||||
|
};
|
||||||
|
|
||||||
|
print_struct_begin_line(Align(), Size(), UnwrapRef()->FriendlyName(symbols));
|
||||||
|
|
||||||
|
for (size_t i = 0; i < Members().size(); ++i) {
|
||||||
|
auto* const m = Members()[i];
|
||||||
|
|
||||||
|
// Output field alignment padding, if any
|
||||||
|
auto* const prev_member = (i == 0) ? nullptr : Members()[i - 1];
|
||||||
|
if (prev_member) {
|
||||||
|
uint32_t padding =
|
||||||
|
m->Offset() - (prev_member->Offset() + prev_member->Size());
|
||||||
|
if (padding > 0) {
|
||||||
|
size_t padding_offset = m->Offset() - padding;
|
||||||
|
print_member_line(padding_offset, 1, padding,
|
||||||
|
"// -- implicit field alignment padding --");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Output member
|
||||||
|
std::string member_name = member_name_of(m);
|
||||||
|
print_member_line(
|
||||||
|
m->Offset(), m->Align(), m->Size(),
|
||||||
|
member_name + " : " + m->Type()->UnwrapRef()->FriendlyName(symbols));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Output struct size padding, if any
|
||||||
|
uint32_t struct_padding = Size() - last_member_struct_padding_offset;
|
||||||
|
if (struct_padding > 0) {
|
||||||
|
print_member_line(last_member_struct_padding_offset, 1, struct_padding,
|
||||||
|
"// -- implicit struct size padding --");
|
||||||
|
}
|
||||||
|
|
||||||
|
print_struct_end_line();
|
||||||
|
|
||||||
|
return ss.str();
|
||||||
|
}
|
||||||
|
|
||||||
bool Struct::IsConstructible() const {
|
bool Struct::IsConstructible() const {
|
||||||
return constructible_;
|
return constructible_;
|
||||||
}
|
}
|
||||||
|
@ -150,6 +150,11 @@ class Struct : public Castable<Struct, Type> {
|
|||||||
/// declared in WGSL.
|
/// declared in WGSL.
|
||||||
std::string FriendlyName(const SymbolTable& symbols) const override;
|
std::string FriendlyName(const SymbolTable& symbols) const override;
|
||||||
|
|
||||||
|
/// @param symbols the program's symbol table
|
||||||
|
/// @returns a multiline string that describes the layout of this struct,
|
||||||
|
/// including size and alignment information.
|
||||||
|
std::string Layout(const tint::SymbolTable& symbols) const;
|
||||||
|
|
||||||
/// @returns true if constructible as per
|
/// @returns true if constructible as per
|
||||||
/// https://gpuweb.github.io/gpuweb/wgsl/#constructible-types
|
/// https://gpuweb.github.io/gpuweb/wgsl/#constructible-types
|
||||||
bool IsConstructible() const override;
|
bool IsConstructible() const override;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user