transform: Avoid symbol collision in Canonicalize IO

Correctly rename fields when combining two or more input structures together into a single input structure.

Bug: chromium:1251009
Change-Id: I0c7ab5ed3116b97035e100d1ef96e772e819f640
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/64545
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: James Price <jrprice@google.com>
Commit-Queue: Ben Clayton <bclayton@google.com>
This commit is contained in:
Ben Clayton
2021-09-27 21:40:33 +00:00
committed by Tint LUCI CQ
parent 231b50baab
commit 9c7cd9e9c3
7 changed files with 343 additions and 16 deletions

View File

@@ -112,6 +112,8 @@ struct CanonicalizeEntryPointIO::State {
std::vector<OutputValue> wrapper_output_values;
/// The body of the wrapper function.
ast::StatementList wrapper_body;
/// Input names used by the entrypoint
std::unordered_set<std::string> input_names;
/// Constructor
/// @param context the clone context
@@ -171,29 +173,35 @@ struct CanonicalizeEntryPointIO::State {
ctx.dst->ID(), ast::DisabledValidation::kIgnoreStorageClass));
// Create the global variable and use its value for the shader input.
auto var = ctx.dst->Symbols().New(name);
ast::Expression* value = ctx.dst->Expr(var);
auto symbol = ctx.dst->Symbols().New(name);
ast::Expression* value = ctx.dst->Expr(symbol);
if (HasSampleMask(attributes)) {
// Vulkan requires the type of a SampleMask builtin to be an array.
// Declare it as array<u32, 1> and then load the first element.
type = ctx.dst->ty.array(type, 1);
value = ctx.dst->IndexAccessor(value, 0);
}
ctx.dst->Global(var, type, ast::StorageClass::kInput,
ctx.dst->Global(symbol, type, ast::StorageClass::kInput,
std::move(attributes));
return value;
} else if (cfg.shader_style == ShaderStyle::kMsl &&
ast::HasDecoration<ast::BuiltinDecoration>(attributes)) {
// If this input is a builtin and we are targeting MSL, then add it to the
// parameter list and pass it directly to the inner function.
Symbol symbol = input_names.emplace(name).second
? ctx.dst->Symbols().Register(name)
: ctx.dst->Symbols().New(name);
wrapper_ep_parameters.push_back(
ctx.dst->Param(name, type, std::move(attributes)));
return ctx.dst->Expr(name);
ctx.dst->Param(symbol, type, std::move(attributes)));
return ctx.dst->Expr(symbol);
} else {
// Otherwise, move it to the new structure member list.
Symbol symbol = input_names.emplace(name).second
? ctx.dst->Symbols().Register(name)
: ctx.dst->Symbols().New(name);
wrapper_struct_param_members.push_back(
ctx.dst->Member(name, type, std::move(attributes)));
return ctx.dst->MemberAccessor(InputStructSymbol(), name);
ctx.dst->Member(symbol, type, std::move(attributes)));
return ctx.dst->MemberAccessor(InputStructSymbol(), symbol);
}
}

View File

@@ -2062,18 +2062,31 @@ var<private> vertex_point_size : f32;
var<private> vertex_point_size_1 : f32;
var<private> vertex_point_size_2 : f32;
struct VertIn1 {
[[location(0)]] collide : f32;
};
struct VertIn2 {
[[location(1)]] collide : f32;
};
struct VertOut {
[[location(0)]] vertex_point_size : f32;
[[builtin(position)]] vertex_point_size_1 : vec4<f32>;
};
[[stage(vertex)]]
fn vert_main() -> VertOut {
fn vert_main(collide : VertIn1, collide_1 : VertIn2) -> VertOut {
let x = collide.collide + collide_1.collide;
return VertOut();
}
)";
auto* expect = R"(
[[location(0), internal(disable_validation__ignore_storage_class)]] var<in> collide_2 : f32;
[[location(1), internal(disable_validation__ignore_storage_class)]] var<in> collide_3 : f32;
[[location(0), internal(disable_validation__ignore_storage_class)]] var<out> vertex_point_size_3 : f32;
[[builtin(position), internal(disable_validation__ignore_storage_class)]] var<out> vertex_point_size_1_1 : vec4<f32>;
@@ -2086,18 +2099,27 @@ var<private> vertex_point_size_1 : f32;
var<private> vertex_point_size_2 : f32;
struct VertIn1 {
collide : f32;
};
struct VertIn2 {
collide : f32;
};
struct VertOut {
vertex_point_size : f32;
vertex_point_size_1 : vec4<f32>;
};
fn vert_main_inner() -> VertOut {
fn vert_main_inner(collide : VertIn1, collide_1 : VertIn2) -> VertOut {
let x = (collide.collide + collide_1.collide);
return VertOut();
}
[[stage(vertex)]]
fn vert_main() {
let inner_result = vert_main_inner();
let inner_result = vert_main_inner(VertIn1(collide_2), VertIn2(collide_3));
vertex_point_size_3 = inner_result.vertex_point_size;
vertex_point_size_1_1 = inner_result.vertex_point_size_1;
vertex_point_size_4 = 1.0;
@@ -2114,24 +2136,48 @@ fn vert_main() {
TEST_F(CanonicalizeEntryPointIOTest, EmitVertexPointSize_AvoidNameClash_Msl) {
auto* src = R"(
struct VertIn1 {
[[location(0)]] collide : f32;
};
struct VertIn2 {
[[location(1)]] collide : f32;
};
struct VertOut {
[[location(0)]] vertex_point_size : vec4<f32>;
[[builtin(position)]] vertex_point_size_1 : vec4<f32>;
};
[[stage(vertex)]]
fn vert_main() -> VertOut {
fn vert_main(collide : VertIn1, collide_1 : VertIn2) -> VertOut {
let x = collide.collide + collide_1.collide;
return VertOut();
}
)";
auto* expect = R"(
struct VertIn1 {
collide : f32;
};
struct VertIn2 {
collide : f32;
};
struct VertOut {
vertex_point_size : vec4<f32>;
vertex_point_size_1 : vec4<f32>;
};
struct tint_symbol {
struct tint_symbol_1 {
[[location(0)]]
collide : f32;
[[location(1)]]
collide_2 : f32;
};
struct tint_symbol_2 {
[[location(0)]]
vertex_point_size : vec4<f32>;
[[builtin(position)]]
@@ -2140,14 +2186,15 @@ struct tint_symbol {
vertex_point_size_2 : f32;
};
fn vert_main_inner() -> VertOut {
fn vert_main_inner(collide : VertIn1, collide_1 : VertIn2) -> VertOut {
let x = (collide.collide + collide_1.collide);
return VertOut();
}
[[stage(vertex)]]
fn vert_main() -> tint_symbol {
let inner_result = vert_main_inner();
var wrapper_result : tint_symbol;
fn vert_main(tint_symbol : tint_symbol_1) -> tint_symbol_2 {
let inner_result = vert_main_inner(VertIn1(tint_symbol.collide), VertIn2(tint_symbol.collide_2));
var wrapper_result : tint_symbol_2;
wrapper_result.vertex_point_size = inner_result.vertex_point_size;
wrapper_result.vertex_point_size_1 = inner_result.vertex_point_size_1;
wrapper_result.vertex_point_size_2 = 1.0;
@@ -2163,6 +2210,82 @@ fn vert_main() -> tint_symbol {
EXPECT_EQ(expect, str(got));
}
TEST_F(CanonicalizeEntryPointIOTest, EmitVertexPointSize_AvoidNameClash_Hlsl) {
auto* src = R"(
struct VertIn1 {
[[location(0)]] collide : f32;
};
struct VertIn2 {
[[location(1)]] collide : f32;
};
struct VertOut {
[[location(0)]] vertex_point_size : vec4<f32>;
[[builtin(position)]] vertex_point_size_1 : vec4<f32>;
};
[[stage(vertex)]]
fn vert_main(collide : VertIn1, collide_1 : VertIn2) -> VertOut {
let x = collide.collide + collide_1.collide;
return VertOut();
}
)";
auto* expect = R"(
struct VertIn1 {
collide : f32;
};
struct VertIn2 {
collide : f32;
};
struct VertOut {
vertex_point_size : vec4<f32>;
vertex_point_size_1 : vec4<f32>;
};
struct tint_symbol_1 {
[[location(0)]]
collide : f32;
[[location(1)]]
collide_2 : f32;
};
struct tint_symbol_2 {
[[location(0)]]
vertex_point_size : vec4<f32>;
[[builtin(position)]]
vertex_point_size_1 : vec4<f32>;
[[builtin(pointsize)]]
vertex_point_size_2 : f32;
};
fn vert_main_inner(collide : VertIn1, collide_1 : VertIn2) -> VertOut {
let x = (collide.collide + collide_1.collide);
return VertOut();
}
[[stage(vertex)]]
fn vert_main(tint_symbol : tint_symbol_1) -> tint_symbol_2 {
let inner_result = vert_main_inner(VertIn1(tint_symbol.collide), VertIn2(tint_symbol.collide_2));
var wrapper_result : tint_symbol_2;
wrapper_result.vertex_point_size = inner_result.vertex_point_size;
wrapper_result.vertex_point_size_1 = inner_result.vertex_point_size_1;
wrapper_result.vertex_point_size_2 = 1.0;
return wrapper_result;
}
)";
DataMap data;
data.Add<CanonicalizeEntryPointIO::Config>(
CanonicalizeEntryPointIO::ShaderStyle::kHlsl, 0xFFFFFFFF, true);
auto got = Run<CanonicalizeEntryPointIO>(src, data);
EXPECT_EQ(expect, str(got));
}
TEST_F(CanonicalizeEntryPointIOTest, SpirvSampleMaskBuiltins) {
auto* src = R"(
[[stage(fragment)]]