mirror of
https://github.com/encounter/dawn-cmake.git
synced 2025-12-21 02:39:11 +00:00
tint: Implement sem::Load
The resolver now wraps sem::Expression objects with a sem::Load object anywhere that the load rule is invoked. sem::Expression provides an `UnwrapLoad()` method that returns the inner expression (or passthrough, if no load is present), which is analaguous to Type::UnwrapRef(). The logic for alias analysis in `RegisterLoadIfNeeded` has been folded into the new `Resolver::Load` method. Fixed up many transforms and tests. The only difference in output is for a single SPIR-V backend test, where some IDs have changed due to slight re-ordering of when expressions are generated. There may be further clean-ups possible (e.g. removing unnecessary calls to `UnwrapRef`, and simplifying places in the SPIR-V writer or transforms that deal with memory accesses), but these can be addressed in future patches. Fixed: tint:1654 Change-Id: I69adecfe9251faae46546b64d0cdc29eea26cd4e Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/99706 Commit-Queue: James Price <jrprice@google.com> Kokoro: Kokoro <noreply+kokoro@google.com> Reviewed-by: Antonio Maiorano <amaiorano@google.com> Reviewed-by: Ben Clayton <bclayton@google.com>
This commit is contained in:
committed by
Dawn LUCI CQ
parent
57ca8cffa4
commit
2f9a98870e
@@ -250,9 +250,10 @@ struct CombineSamplers::State {
|
||||
const sem::Expression* sampler =
|
||||
sampler_index != -1 ? call->Arguments()[static_cast<size_t>(sampler_index)]
|
||||
: nullptr;
|
||||
auto* texture_var = texture->As<sem::VariableUser>()->Variable();
|
||||
auto* texture_var = texture->UnwrapLoad()->As<sem::VariableUser>()->Variable();
|
||||
auto* sampler_var =
|
||||
sampler ? sampler->As<sem::VariableUser>()->Variable() : nullptr;
|
||||
sampler ? sampler->UnwrapLoad()->As<sem::VariableUser>()->Variable()
|
||||
: nullptr;
|
||||
sem::VariablePair new_pair(texture_var, sampler_var);
|
||||
for (auto* arg : expr->args) {
|
||||
auto* type = ctx.src->TypeOf(arg)->UnwrapRef();
|
||||
@@ -296,12 +297,14 @@ struct CombineSamplers::State {
|
||||
const sem::Variable* sampler_var = pair.second;
|
||||
if (auto* param = texture_var->As<sem::Parameter>()) {
|
||||
const sem::Expression* texture = call->Arguments()[param->Index()];
|
||||
texture_var = texture->As<sem::VariableUser>()->Variable();
|
||||
texture_var =
|
||||
texture->UnwrapLoad()->As<sem::VariableUser>()->Variable();
|
||||
}
|
||||
if (sampler_var) {
|
||||
if (auto* param = sampler_var->As<sem::Parameter>()) {
|
||||
const sem::Expression* sampler = call->Arguments()[param->Index()];
|
||||
sampler_var = sampler->As<sem::VariableUser>()->Variable();
|
||||
sampler_var =
|
||||
sampler->UnwrapLoad()->As<sem::VariableUser>()->Variable();
|
||||
}
|
||||
}
|
||||
sem::VariablePair new_pair(texture_var, sampler_var);
|
||||
|
||||
@@ -126,10 +126,10 @@ struct LoadStoreKey {
|
||||
|
||||
/// AtomicKey is the unordered map key to an atomic intrinsic.
|
||||
struct AtomicKey {
|
||||
ast::Access const access; // buffer access
|
||||
ast::Access const access; // buffer access
|
||||
type::Type const* buf_ty = nullptr; // buffer type
|
||||
type::Type const* el_ty = nullptr; // element type
|
||||
sem::BuiltinType const op; // atomic op
|
||||
sem::BuiltinType const op; // atomic op
|
||||
bool operator==(const AtomicKey& rhs) const {
|
||||
return access == rhs.access && buf_ty == rhs.buf_ty && el_ty == rhs.el_ty && op == rhs.op;
|
||||
}
|
||||
@@ -881,15 +881,17 @@ Transform::ApplyResult DecomposeMemoryAccess::Apply(const Program* src,
|
||||
for (auto* node : src->ASTNodes().Objects()) {
|
||||
if (auto* ident = node->As<ast::IdentifierExpression>()) {
|
||||
// X
|
||||
if (auto* var = sem.Get<sem::VariableUser>(ident)) {
|
||||
if (var->Variable()->AddressSpace() == ast::AddressSpace::kStorage ||
|
||||
var->Variable()->AddressSpace() == ast::AddressSpace::kUniform) {
|
||||
// Variable to a storage or uniform buffer
|
||||
state.AddAccess(ident, {
|
||||
var,
|
||||
state.ToOffset(0u),
|
||||
var->Type()->UnwrapRef(),
|
||||
});
|
||||
if (auto* sem_ident = sem.Get(ident)) {
|
||||
if (auto* var = sem_ident->UnwrapLoad()->As<sem::VariableUser>()) {
|
||||
if (var->Variable()->AddressSpace() == ast::AddressSpace::kStorage ||
|
||||
var->Variable()->AddressSpace() == ast::AddressSpace::kUniform) {
|
||||
// Variable to a storage or uniform buffer
|
||||
state.AddAccess(ident, {
|
||||
var,
|
||||
state.ToOffset(0u),
|
||||
var->Type()->UnwrapRef(),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
continue;
|
||||
@@ -897,7 +899,7 @@ Transform::ApplyResult DecomposeMemoryAccess::Apply(const Program* src,
|
||||
|
||||
if (auto* accessor = node->As<ast::MemberAccessorExpression>()) {
|
||||
// X.Y
|
||||
auto* accessor_sem = sem.Get(accessor);
|
||||
auto* accessor_sem = sem.Get(accessor)->UnwrapLoad();
|
||||
if (auto* swizzle = accessor_sem->As<sem::Swizzle>()) {
|
||||
if (swizzle->Indices().Length() == 1) {
|
||||
if (auto access = state.TakeAccess(accessor->structure)) {
|
||||
@@ -906,7 +908,7 @@ Transform::ApplyResult DecomposeMemoryAccess::Apply(const Program* src,
|
||||
state.AddAccess(accessor, {
|
||||
access.var,
|
||||
state.Add(access.offset, offset),
|
||||
vec_ty->type()->UnwrapRef(),
|
||||
vec_ty->type(),
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -918,7 +920,7 @@ Transform::ApplyResult DecomposeMemoryAccess::Apply(const Program* src,
|
||||
state.AddAccess(accessor, {
|
||||
access.var,
|
||||
state.Add(access.offset, offset),
|
||||
member->Type()->UnwrapRef(),
|
||||
member->Type(),
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -933,7 +935,7 @@ Transform::ApplyResult DecomposeMemoryAccess::Apply(const Program* src,
|
||||
state.AddAccess(accessor, {
|
||||
access.var,
|
||||
state.Add(access.offset, offset),
|
||||
arr->ElemType()->UnwrapRef(),
|
||||
arr->ElemType(),
|
||||
});
|
||||
continue;
|
||||
}
|
||||
@@ -942,7 +944,7 @@ Transform::ApplyResult DecomposeMemoryAccess::Apply(const Program* src,
|
||||
state.AddAccess(accessor, {
|
||||
access.var,
|
||||
state.Add(access.offset, offset),
|
||||
vec_ty->type()->UnwrapRef(),
|
||||
vec_ty->type(),
|
||||
});
|
||||
continue;
|
||||
}
|
||||
@@ -1014,6 +1016,7 @@ Transform::ApplyResult DecomposeMemoryAccess::Apply(const Program* src,
|
||||
|
||||
// All remaining accesses are loads, transform these into calls to the
|
||||
// corresponding load function
|
||||
// TODO(crbug.com/tint/1784): Use `sem::Load`s instead of maintaining `state.expression_order`.
|
||||
for (auto* expr : state.expression_order) {
|
||||
auto access_it = state.accesses.find(expr);
|
||||
if (access_it == state.accesses.end()) {
|
||||
|
||||
@@ -167,7 +167,7 @@ Transform::ApplyResult DecomposeStridedMatrix::Apply(const Program* src,
|
||||
// m = arr_to_mat(ssbo.mat)
|
||||
std::unordered_map<MatrixInfo, Symbol, MatrixInfo::Hasher> arr_to_mat;
|
||||
ctx.ReplaceAll([&](const ast::MemberAccessorExpression* expr) -> const ast::Expression* {
|
||||
if (auto* access = src->Sem().Get<sem::StructMemberAccess>(expr)) {
|
||||
if (auto* access = src->Sem().Get(expr)->UnwrapLoad()->As<sem::StructMemberAccess>()) {
|
||||
if (auto info = decomposed.Find(access->Member()->Declaration())) {
|
||||
auto fn = utils::GetOrCreate(arr_to_mat, *info, [&] {
|
||||
auto name =
|
||||
|
||||
@@ -139,7 +139,7 @@ Transform::ApplyResult FirstIndexOffset::Apply(const Program* src,
|
||||
// Fix up all references to the builtins with the offsets
|
||||
ctx.ReplaceAll([=, &ctx](const ast::Expression* expr) -> const ast::Expression* {
|
||||
if (auto* sem = ctx.src->Sem().Get(expr)) {
|
||||
if (auto* user = sem->As<sem::VariableUser>()) {
|
||||
if (auto* user = sem->UnwrapLoad()->As<sem::VariableUser>()) {
|
||||
auto it = builtin_vars.find(user->Variable());
|
||||
if (it != builtin_vars.end()) {
|
||||
return ctx.dst->Add(ctx.CloneWithoutTransform(expr),
|
||||
|
||||
@@ -197,7 +197,8 @@ struct MultiplanarExternalTexture::State {
|
||||
if (builtin && !builtin->Parameters().IsEmpty() &&
|
||||
builtin->Parameters()[0]->Type()->Is<type::ExternalTexture>() &&
|
||||
builtin->Type() != sem::BuiltinType::kTextureDimensions) {
|
||||
if (auto* var_user = sem.Get<sem::VariableUser>(expr->args[0])) {
|
||||
if (auto* var_user =
|
||||
sem.Get(expr->args[0])->UnwrapLoad()->As<sem::VariableUser>()) {
|
||||
auto it = new_binding_symbols.find(var_user->Variable());
|
||||
if (it == new_binding_symbols.end()) {
|
||||
// If valid new binding locations were not provided earlier, we would have
|
||||
@@ -222,7 +223,7 @@ struct MultiplanarExternalTexture::State {
|
||||
// texture_external parameter. These need to be expanded out to multiple plane
|
||||
// textures and the texture parameters structure.
|
||||
for (auto* arg : expr->args) {
|
||||
if (auto* var_user = sem.Get<sem::VariableUser>(arg)) {
|
||||
if (auto* var_user = sem.Get(arg)->UnwrapLoad()->As<sem::VariableUser>()) {
|
||||
// Check if a parameter is a texture_external by trying to find
|
||||
// it in the transform state.
|
||||
auto it = new_binding_symbols.find(var_user->Variable());
|
||||
|
||||
@@ -74,8 +74,14 @@ struct PackedVec3::State {
|
||||
// that load a whole packed vector (not a scalar / swizzle of the vector).
|
||||
utils::Hashset<const sem::Expression*, 16> refs;
|
||||
for (auto* node : ctx.src->ASTNodes().Objects()) {
|
||||
auto* sem_node = sem.Get(node);
|
||||
if (sem_node) {
|
||||
if (auto* expr = sem_node->As<sem::Expression>()) {
|
||||
sem_node = expr->UnwrapLoad();
|
||||
}
|
||||
}
|
||||
Switch(
|
||||
sem.Get(node), //
|
||||
sem_node, //
|
||||
[&](const sem::StructMemberAccess* access) {
|
||||
if (members.Contains(access->Member())) {
|
||||
// Access to a packed vector member. Seed the expression tracking.
|
||||
@@ -84,11 +90,11 @@ struct PackedVec3::State {
|
||||
},
|
||||
[&](const sem::IndexAccessorExpression* access) {
|
||||
// Not loading a whole packed vector. Ignore.
|
||||
refs.Remove(access->Object());
|
||||
refs.Remove(access->Object()->UnwrapLoad());
|
||||
},
|
||||
[&](const sem::Swizzle* access) {
|
||||
// Not loading a whole packed vector. Ignore.
|
||||
refs.Remove(access->Object());
|
||||
refs.Remove(access->Object()->UnwrapLoad());
|
||||
},
|
||||
[&](const sem::VariableUser* user) {
|
||||
auto* v = user->Variable();
|
||||
|
||||
@@ -276,7 +276,7 @@ class DecomposeSideEffects::CollectHoistsState : public StateBase {
|
||||
},
|
||||
[&](const ast::IdentifierExpression* e) {
|
||||
if (auto* sem_e = sem.Get(e)) {
|
||||
if (auto* var_user = sem_e->As<sem::VariableUser>()) {
|
||||
if (auto* var_user = sem_e->UnwrapLoad()->As<sem::VariableUser>()) {
|
||||
// Don't hoist constants.
|
||||
if (var_user->ConstantValue()) {
|
||||
return false;
|
||||
|
||||
@@ -1285,7 +1285,7 @@ Transform::ApplyResult Renamer::Apply(const Program* src,
|
||||
Switch(
|
||||
node,
|
||||
[&](const ast::MemberAccessorExpression* accessor) {
|
||||
auto* sem = src->Sem().Get(accessor);
|
||||
auto* sem = src->Sem().Get(accessor)->UnwrapLoad();
|
||||
if (sem->Is<sem::Swizzle>()) {
|
||||
preserved_identifiers.Add(accessor->member);
|
||||
} else if (auto* str_expr = src->Sem().Get(accessor->structure)) {
|
||||
|
||||
@@ -93,7 +93,8 @@ fn entry() -> @builtin(position) vec4<f32> {
|
||||
var v : vec4<f32>;
|
||||
var rgba : f32;
|
||||
var xyzw : f32;
|
||||
return v.zyxw + v.rgab;
|
||||
var z : f32;
|
||||
return v.zyxw + v.rgab * v.z;
|
||||
}
|
||||
)";
|
||||
|
||||
@@ -103,7 +104,8 @@ fn tint_symbol() -> @builtin(position) vec4<f32> {
|
||||
var tint_symbol_1 : vec4<f32>;
|
||||
var tint_symbol_2 : f32;
|
||||
var tint_symbol_3 : f32;
|
||||
return (tint_symbol_1.zyxw + tint_symbol_1.rgab);
|
||||
var tint_symbol_4 : f32;
|
||||
return (tint_symbol_1.zyxw + (tint_symbol_1.rgab * tint_symbol_1.z));
|
||||
}
|
||||
)";
|
||||
|
||||
@@ -115,10 +117,8 @@ fn tint_symbol() -> @builtin(position) vec4<f32> {
|
||||
|
||||
ASSERT_NE(data, nullptr);
|
||||
Renamer::Data::Remappings expected_remappings = {
|
||||
{"entry", "tint_symbol"},
|
||||
{"v", "tint_symbol_1"},
|
||||
{"rgba", "tint_symbol_2"},
|
||||
{"xyzw", "tint_symbol_3"},
|
||||
{"entry", "tint_symbol"}, {"v", "tint_symbol_1"}, {"rgba", "tint_symbol_2"},
|
||||
{"xyzw", "tint_symbol_3"}, {"z", "tint_symbol_4"},
|
||||
};
|
||||
EXPECT_THAT(data->remappings, ContainerEq(expected_remappings));
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@ struct Robustness::State {
|
||||
/// @return the clamped replacement expression, or nullptr if `expr` should be cloned without
|
||||
/// changes.
|
||||
const ast::IndexAccessorExpression* Transform(const ast::IndexAccessorExpression* expr) {
|
||||
auto* sem = src->Sem().Get(expr)->UnwrapMaterialize()->As<sem::IndexAccessorExpression>();
|
||||
auto* sem = src->Sem().Get(expr)->Unwrap()->As<sem::IndexAccessorExpression>();
|
||||
auto* ret_type = sem->Type();
|
||||
|
||||
auto* ref = ret_type->As<type::Reference>();
|
||||
@@ -78,7 +78,7 @@ struct Robustness::State {
|
||||
// idx return the cloned index expression, as a u32.
|
||||
auto idx = [&]() -> const ast::Expression* {
|
||||
auto* i = ctx.Clone(expr->index);
|
||||
if (sem->Index()->Type()->UnwrapRef()->is_signed_integer_scalar()) {
|
||||
if (sem->Index()->Type()->is_signed_integer_scalar()) {
|
||||
return b.Construct(b.ty.u32(), i); // u32(idx)
|
||||
}
|
||||
return i;
|
||||
|
||||
@@ -164,7 +164,7 @@ struct SpirvAtomic::State {
|
||||
void ProcessAtomicExpressions() {
|
||||
for (size_t i = 0; i < atomic_expressions.Length(); i++) {
|
||||
Switch(
|
||||
atomic_expressions[i], //
|
||||
atomic_expressions[i]->UnwrapLoad(), //
|
||||
[&](const sem::VariableUser* user) {
|
||||
auto* v = user->Variable()->Declaration();
|
||||
if (v->type && atomic_variables.emplace(user->Variable()).second) {
|
||||
@@ -262,7 +262,7 @@ struct SpirvAtomic::State {
|
||||
}
|
||||
|
||||
auto sem_rhs = ctx.src->Sem().Get(assign->rhs);
|
||||
if (is_ref_to_atomic_var(sem_rhs)) {
|
||||
if (is_ref_to_atomic_var(sem_rhs->UnwrapLoad())) {
|
||||
ctx.Replace(assign->rhs, [=] {
|
||||
auto* rhs = ctx.CloneWithoutTransform(assign->rhs);
|
||||
return b.Call(sem::str(sem::BuiltinType::kAtomicLoad),
|
||||
@@ -274,7 +274,7 @@ struct SpirvAtomic::State {
|
||||
[&](const ast::VariableDeclStatement* decl) {
|
||||
auto* var = decl->variable;
|
||||
if (auto* sem_init = ctx.src->Sem().Get(var->initializer)) {
|
||||
if (is_ref_to_atomic_var(sem_init)) {
|
||||
if (is_ref_to_atomic_var(sem_init->UnwrapLoad())) {
|
||||
ctx.Replace(var->initializer, [=] {
|
||||
auto* rhs = ctx.CloneWithoutTransform(var->initializer);
|
||||
return b.Call(sem::str(sem::BuiltinType::kAtomicLoad),
|
||||
|
||||
@@ -511,7 +511,7 @@ struct Std140::State {
|
||||
while (true) {
|
||||
enum class Action { kStop, kContinue, kError };
|
||||
Action action = Switch(
|
||||
expr, //
|
||||
expr->Unwrap(), //
|
||||
[&](const sem::VariableUser* user) {
|
||||
if (user->Variable() == access.var) {
|
||||
// Walked all the way to the root identifier. We're done traversing.
|
||||
|
||||
@@ -96,9 +96,11 @@ struct Unshadow::State {
|
||||
});
|
||||
ctx.ReplaceAll(
|
||||
[&](const ast::IdentifierExpression* ident) -> const tint::ast::IdentifierExpression* {
|
||||
if (auto* user = sem.Get<sem::VariableUser>(ident)) {
|
||||
if (auto renamed = renamed_to.Find(user->Variable())) {
|
||||
return b.Expr(*renamed);
|
||||
if (auto* sem_ident = sem.Get(ident)) {
|
||||
if (auto* user = sem_ident->UnwrapLoad()->As<sem::VariableUser>()) {
|
||||
if (auto renamed = renamed_to.Find(user->Variable())) {
|
||||
return b.Expr(*renamed);
|
||||
}
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
|
||||
@@ -760,5 +760,31 @@ type a = i32;
|
||||
EXPECT_EQ(expect, str(got));
|
||||
}
|
||||
|
||||
TEST_F(UnshadowTest, RenamedVarHasUsers) {
|
||||
auto* src = R"(
|
||||
fn F() {
|
||||
var a : bool;
|
||||
{
|
||||
var a : i32;
|
||||
var b = a + 1;
|
||||
}
|
||||
}
|
||||
)";
|
||||
|
||||
auto* expect = R"(
|
||||
fn F() {
|
||||
var a : bool;
|
||||
{
|
||||
var a_1 : i32;
|
||||
var b = (a_1 + 1);
|
||||
}
|
||||
}
|
||||
)";
|
||||
|
||||
auto got = Run<Unshadow>(src);
|
||||
|
||||
EXPECT_EQ(expect, str(got));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace tint::transform
|
||||
|
||||
Reference in New Issue
Block a user