tint: Track originating variables in the resolver
Attach the source variable to the sem::Expression nodes. Bug: tint:1341 Change-Id: I71d8fcf5920c4daab9035c7a5615b34378889dac Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/87606 Reviewed-by: Ben Clayton <bclayton@google.com> Kokoro: Kokoro <noreply+kokoro@google.com>
This commit is contained in:
parent
0690b9623e
commit
98eb169692
|
@ -763,6 +763,7 @@ if(TINT_BUILD_TESTS)
|
||||||
resolver/resolver_test_helper.h
|
resolver/resolver_test_helper.h
|
||||||
resolver/resolver_test.cc
|
resolver/resolver_test.cc
|
||||||
resolver/side_effects_test.cc
|
resolver/side_effects_test.cc
|
||||||
|
resolver/source_variable_test.cc
|
||||||
resolver/storage_class_layout_validation_test.cc
|
resolver/storage_class_layout_validation_test.cc
|
||||||
resolver/storage_class_validation_test.cc
|
resolver/storage_class_validation_test.cc
|
||||||
resolver/struct_layout_test.cc
|
resolver/struct_layout_test.cc
|
||||||
|
|
|
@ -1209,7 +1209,8 @@ sem::Expression* Resolver::IndexAccessor(
|
||||||
auto val = EvaluateConstantValue(expr, ty);
|
auto val = EvaluateConstantValue(expr, ty);
|
||||||
bool has_side_effects = idx->HasSideEffects() || obj->HasSideEffects();
|
bool has_side_effects = idx->HasSideEffects() || obj->HasSideEffects();
|
||||||
auto* sem = builder_->create<sem::Expression>(expr, ty, current_statement_,
|
auto* sem = builder_->create<sem::Expression>(expr, ty, current_statement_,
|
||||||
val, has_side_effects);
|
val, has_side_effects,
|
||||||
|
obj->SourceVariable());
|
||||||
sem->Behaviors() = idx->Behaviors() + obj->Behaviors();
|
sem->Behaviors() = idx->Behaviors() + obj->Behaviors();
|
||||||
return sem;
|
return sem;
|
||||||
}
|
}
|
||||||
|
@ -1731,6 +1732,7 @@ sem::Expression* Resolver::MemberAccessor(
|
||||||
const ast::MemberAccessorExpression* expr) {
|
const ast::MemberAccessorExpression* expr) {
|
||||||
auto* structure = sem_.TypeOf(expr->structure);
|
auto* structure = sem_.TypeOf(expr->structure);
|
||||||
auto* storage_ty = structure->UnwrapRef();
|
auto* storage_ty = structure->UnwrapRef();
|
||||||
|
auto* source_var = sem_.Get(expr->structure)->SourceVariable();
|
||||||
|
|
||||||
const sem::Type* ret = nullptr;
|
const sem::Type* ret = nullptr;
|
||||||
std::vector<uint32_t> swizzle;
|
std::vector<uint32_t> swizzle;
|
||||||
|
@ -1766,7 +1768,7 @@ sem::Expression* Resolver::MemberAccessor(
|
||||||
}
|
}
|
||||||
|
|
||||||
return builder_->create<sem::StructMemberAccess>(
|
return builder_->create<sem::StructMemberAccess>(
|
||||||
expr, ret, current_statement_, member, has_side_effects);
|
expr, ret, current_statement_, member, has_side_effects, source_var);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (auto* vec = storage_ty->As<sem::Vector>()) {
|
if (auto* vec = storage_ty->As<sem::Vector>()) {
|
||||||
|
@ -1839,7 +1841,8 @@ sem::Expression* Resolver::MemberAccessor(
|
||||||
static_cast<uint32_t>(size));
|
static_cast<uint32_t>(size));
|
||||||
}
|
}
|
||||||
return builder_->create<sem::Swizzle>(expr, ret, current_statement_,
|
return builder_->create<sem::Swizzle>(expr, ret, current_statement_,
|
||||||
std::move(swizzle), has_side_effects);
|
std::move(swizzle), has_side_effects,
|
||||||
|
source_var);
|
||||||
}
|
}
|
||||||
|
|
||||||
AddError(
|
AddError(
|
||||||
|
@ -2047,6 +2050,7 @@ sem::Expression* Resolver::UnaryOp(const ast::UnaryOpExpression* unary) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const sem::Type* ty = nullptr;
|
const sem::Type* ty = nullptr;
|
||||||
|
const sem::Variable* source_var = nullptr;
|
||||||
|
|
||||||
switch (unary->op) {
|
switch (unary->op) {
|
||||||
case ast::UnaryOp::kNot:
|
case ast::UnaryOp::kNot:
|
||||||
|
@ -2105,6 +2109,8 @@ sem::Expression* Resolver::UnaryOp(const ast::UnaryOpExpression* unary) {
|
||||||
|
|
||||||
ty = builder_->create<sem::Pointer>(ref->StoreType(),
|
ty = builder_->create<sem::Pointer>(ref->StoreType(),
|
||||||
ref->StorageClass(), ref->Access());
|
ref->StorageClass(), ref->Access());
|
||||||
|
|
||||||
|
source_var = expr->SourceVariable();
|
||||||
} else {
|
} else {
|
||||||
AddError("cannot take the address of expression", unary->expr->source);
|
AddError("cannot take the address of expression", unary->expr->source);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
@ -2115,6 +2121,7 @@ sem::Expression* Resolver::UnaryOp(const ast::UnaryOpExpression* unary) {
|
||||||
if (auto* ptr = expr_ty->As<sem::Pointer>()) {
|
if (auto* ptr = expr_ty->As<sem::Pointer>()) {
|
||||||
ty = builder_->create<sem::Reference>(
|
ty = builder_->create<sem::Reference>(
|
||||||
ptr->StoreType(), ptr->StorageClass(), ptr->Access());
|
ptr->StoreType(), ptr->StorageClass(), ptr->Access());
|
||||||
|
source_var = expr->SourceVariable();
|
||||||
} else {
|
} else {
|
||||||
AddError("cannot dereference expression of type '" +
|
AddError("cannot dereference expression of type '" +
|
||||||
sem_.TypeNameOf(expr_ty) + "'",
|
sem_.TypeNameOf(expr_ty) + "'",
|
||||||
|
@ -2125,8 +2132,8 @@ sem::Expression* Resolver::UnaryOp(const ast::UnaryOpExpression* unary) {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto val = EvaluateConstantValue(unary, ty);
|
auto val = EvaluateConstantValue(unary, ty);
|
||||||
auto* sem = builder_->create<sem::Expression>(unary, ty, current_statement_,
|
auto* sem = builder_->create<sem::Expression>(
|
||||||
val, expr->HasSideEffects());
|
unary, ty, current_statement_, val, expr->HasSideEffects(), source_var);
|
||||||
sem->Behaviors() = expr->Behaviors();
|
sem->Behaviors() = expr->Behaviors();
|
||||||
return sem;
|
return sem;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,293 @@
|
||||||
|
// Copyright 2022 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/resolver.h"
|
||||||
|
|
||||||
|
#include "src/tint/resolver/resolver_test_helper.h"
|
||||||
|
#include "src/tint/sem/member_accessor_expression.h"
|
||||||
|
|
||||||
|
namespace tint::resolver {
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
class ResolverSourceVariableTest : public ResolverTest {};
|
||||||
|
|
||||||
|
TEST_F(ResolverSourceVariableTest, GlobalPrivateVar) {
|
||||||
|
auto* a = Global("a", ty.f32(), ast::StorageClass::kPrivate);
|
||||||
|
auto* expr = Expr(a);
|
||||||
|
WrapInFunction(expr);
|
||||||
|
|
||||||
|
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||||
|
|
||||||
|
auto* sem_a = Sem().Get(a);
|
||||||
|
EXPECT_EQ(Sem().Get(expr)->SourceVariable(), sem_a);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ResolverSourceVariableTest, GlobalWorkgroupVar) {
|
||||||
|
auto* a = Global("a", ty.f32(), ast::StorageClass::kWorkgroup);
|
||||||
|
auto* expr = Expr(a);
|
||||||
|
WrapInFunction(expr);
|
||||||
|
|
||||||
|
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||||
|
|
||||||
|
auto* sem_a = Sem().Get(a);
|
||||||
|
EXPECT_EQ(Sem().Get(expr)->SourceVariable(), sem_a);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ResolverSourceVariableTest, GlobalStorageVar) {
|
||||||
|
auto* a =
|
||||||
|
Global("a", ty.f32(), ast::StorageClass::kStorage, GroupAndBinding(0, 0));
|
||||||
|
auto* expr = Expr(a);
|
||||||
|
WrapInFunction(expr);
|
||||||
|
|
||||||
|
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||||
|
|
||||||
|
auto* sem_a = Sem().Get(a);
|
||||||
|
EXPECT_EQ(Sem().Get(expr)->SourceVariable(), sem_a);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ResolverSourceVariableTest, GlobalUniformVar) {
|
||||||
|
auto* a =
|
||||||
|
Global("a", ty.f32(), ast::StorageClass::kUniform, GroupAndBinding(0, 0));
|
||||||
|
auto* expr = Expr(a);
|
||||||
|
WrapInFunction(expr);
|
||||||
|
|
||||||
|
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||||
|
|
||||||
|
auto* sem_a = Sem().Get(a);
|
||||||
|
EXPECT_EQ(Sem().Get(expr)->SourceVariable(), sem_a);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ResolverSourceVariableTest, GlobalTextureVar) {
|
||||||
|
auto* a =
|
||||||
|
Global("a", ty.sampled_texture(ast::TextureDimension::k2d, ty.f32()),
|
||||||
|
ast::StorageClass::kNone, GroupAndBinding(0, 0));
|
||||||
|
auto* expr = Expr(a);
|
||||||
|
WrapInFunction(Call("textureDimensions", expr));
|
||||||
|
|
||||||
|
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||||
|
|
||||||
|
auto* sem_a = Sem().Get(a);
|
||||||
|
EXPECT_EQ(Sem().Get(expr)->SourceVariable(), sem_a);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ResolverSourceVariableTest, GlobalOverride) {
|
||||||
|
auto* a = Override("a", ty.f32(), Expr(1.f));
|
||||||
|
auto* expr = Expr(a);
|
||||||
|
WrapInFunction(expr);
|
||||||
|
|
||||||
|
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||||
|
|
||||||
|
auto* sem_a = Sem().Get(a);
|
||||||
|
EXPECT_EQ(Sem().Get(expr)->SourceVariable(), sem_a);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ResolverSourceVariableTest, GlobalLet) {
|
||||||
|
auto* a = GlobalConst("a", ty.f32(), Expr(1.f));
|
||||||
|
auto* expr = Expr(a);
|
||||||
|
WrapInFunction(expr);
|
||||||
|
|
||||||
|
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||||
|
|
||||||
|
auto* sem_a = Sem().Get(a);
|
||||||
|
EXPECT_EQ(Sem().Get(expr)->SourceVariable(), sem_a);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ResolverSourceVariableTest, FunctionVar) {
|
||||||
|
auto* a = Var("a", ty.f32(), ast::StorageClass::kNone);
|
||||||
|
auto* expr = Expr(a);
|
||||||
|
WrapInFunction(a, expr);
|
||||||
|
|
||||||
|
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||||
|
|
||||||
|
auto* sem_a = Sem().Get(a);
|
||||||
|
EXPECT_EQ(Sem().Get(expr)->SourceVariable(), sem_a);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ResolverSourceVariableTest, FunctionLet) {
|
||||||
|
auto* a = Const("a", ty.f32(), Expr(1.f));
|
||||||
|
auto* expr = Expr(a);
|
||||||
|
WrapInFunction(a, expr);
|
||||||
|
|
||||||
|
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||||
|
|
||||||
|
auto* sem_a = Sem().Get(a);
|
||||||
|
EXPECT_EQ(Sem().Get(expr)->SourceVariable(), sem_a);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ResolverSourceVariableTest, Parameter) {
|
||||||
|
auto* a = Param("a", ty.f32());
|
||||||
|
auto* expr = Expr(a);
|
||||||
|
Func("foo", {a}, ty.void_(), {WrapInStatement(expr)});
|
||||||
|
|
||||||
|
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||||
|
|
||||||
|
auto* sem_a = Sem().Get(a);
|
||||||
|
EXPECT_EQ(Sem().Get(expr)->SourceVariable(), sem_a);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ResolverSourceVariableTest, PointerParameter) {
|
||||||
|
// fn foo(a : ptr<function, f32>)
|
||||||
|
// {
|
||||||
|
// let b = a;
|
||||||
|
// }
|
||||||
|
auto* param = Param("a", ty.pointer(ty.f32(), ast::StorageClass::kFunction));
|
||||||
|
auto* expr_param = Expr(param);
|
||||||
|
auto* let = Const("b", nullptr, expr_param);
|
||||||
|
auto* expr_let = Expr("b");
|
||||||
|
Func("foo", {param}, ty.void_(),
|
||||||
|
{WrapInStatement(let), WrapInStatement(expr_let)});
|
||||||
|
|
||||||
|
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||||
|
|
||||||
|
auto* sem_param = Sem().Get(param);
|
||||||
|
EXPECT_EQ(Sem().Get(expr_param)->SourceVariable(), sem_param);
|
||||||
|
EXPECT_EQ(Sem().Get(expr_let)->SourceVariable(), sem_param);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ResolverSourceVariableTest, VarCopyVar) {
|
||||||
|
// {
|
||||||
|
// var a : f32;
|
||||||
|
// var b = a;
|
||||||
|
// }
|
||||||
|
auto* a = Var("a", ty.f32(), ast::StorageClass::kNone);
|
||||||
|
auto* expr_a = Expr(a);
|
||||||
|
auto* b = Var("b", ty.f32(), ast::StorageClass::kNone, expr_a);
|
||||||
|
auto* expr_b = Expr(b);
|
||||||
|
WrapInFunction(a, b, expr_b);
|
||||||
|
|
||||||
|
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||||
|
|
||||||
|
auto* sem_a = Sem().Get(a);
|
||||||
|
auto* sem_b = Sem().Get(b);
|
||||||
|
EXPECT_EQ(Sem().Get(expr_a)->SourceVariable(), sem_a);
|
||||||
|
EXPECT_EQ(Sem().Get(expr_b)->SourceVariable(), sem_b);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ResolverSourceVariableTest, LetCopyVar) {
|
||||||
|
// {
|
||||||
|
// var a : f32;
|
||||||
|
// let b = a;
|
||||||
|
// }
|
||||||
|
auto* a = Var("a", ty.f32(), ast::StorageClass::kNone);
|
||||||
|
auto* expr_a = Expr(a);
|
||||||
|
auto* b = Const("b", ty.f32(), expr_a);
|
||||||
|
auto* expr_b = Expr(b);
|
||||||
|
WrapInFunction(a, b, expr_b);
|
||||||
|
|
||||||
|
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||||
|
|
||||||
|
auto* sem_a = Sem().Get(a);
|
||||||
|
auto* sem_b = Sem().Get(b);
|
||||||
|
EXPECT_EQ(Sem().Get(expr_a)->SourceVariable(), sem_a);
|
||||||
|
EXPECT_EQ(Sem().Get(expr_b)->SourceVariable(), sem_b);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ResolverSourceVariableTest, ThroughIndexAccessor) {
|
||||||
|
// var<private> a : array<f32, 4>;
|
||||||
|
// {
|
||||||
|
// a[2]
|
||||||
|
// }
|
||||||
|
auto* a = Global("a", ty.array(ty.f32(), 4), ast::StorageClass::kPrivate);
|
||||||
|
auto* expr = IndexAccessor(a, 2);
|
||||||
|
WrapInFunction(expr);
|
||||||
|
|
||||||
|
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||||
|
|
||||||
|
auto* sem_a = Sem().Get(a);
|
||||||
|
EXPECT_EQ(Sem().Get(expr)->SourceVariable(), sem_a);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ResolverSourceVariableTest, ThroughMemberAccessor) {
|
||||||
|
// struct S { f : f32 }
|
||||||
|
// var<private> a : S;
|
||||||
|
// {
|
||||||
|
// a.f
|
||||||
|
// }
|
||||||
|
auto* S = Structure("S", {Member("f", ty.f32())});
|
||||||
|
auto* a = Global("a", ty.Of(S), ast::StorageClass::kPrivate);
|
||||||
|
auto* expr = MemberAccessor(a, "f");
|
||||||
|
WrapInFunction(expr);
|
||||||
|
|
||||||
|
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||||
|
|
||||||
|
auto* sem_a = Sem().Get(a);
|
||||||
|
EXPECT_EQ(Sem().Get(expr)->SourceVariable(), sem_a);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ResolverSourceVariableTest, ThroughPointers) {
|
||||||
|
// var<private> a : f32;
|
||||||
|
// {
|
||||||
|
// let a_ptr1 = &*&a;
|
||||||
|
// let a_ptr2 = &*a_ptr1;
|
||||||
|
// }
|
||||||
|
auto* a = Global("a", ty.f32(), ast::StorageClass::kPrivate);
|
||||||
|
auto* address_of_1 = AddressOf(a);
|
||||||
|
auto* deref_1 = Deref(address_of_1);
|
||||||
|
auto* address_of_2 = AddressOf(deref_1);
|
||||||
|
auto* a_ptr1 = Const("a_ptr1", nullptr, address_of_2);
|
||||||
|
auto* deref_2 = Deref(a_ptr1);
|
||||||
|
auto* address_of_3 = AddressOf(deref_2);
|
||||||
|
auto* a_ptr2 = Const("a_ptr2", nullptr, address_of_3);
|
||||||
|
WrapInFunction(a_ptr1, a_ptr2);
|
||||||
|
|
||||||
|
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||||
|
|
||||||
|
auto* sem_a = Sem().Get(a);
|
||||||
|
EXPECT_EQ(Sem().Get(address_of_1)->SourceVariable(), sem_a);
|
||||||
|
EXPECT_EQ(Sem().Get(address_of_2)->SourceVariable(), sem_a);
|
||||||
|
EXPECT_EQ(Sem().Get(address_of_3)->SourceVariable(), sem_a);
|
||||||
|
EXPECT_EQ(Sem().Get(deref_1)->SourceVariable(), sem_a);
|
||||||
|
EXPECT_EQ(Sem().Get(deref_2)->SourceVariable(), sem_a);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ResolverSourceVariableTest, Literal) {
|
||||||
|
auto* expr = Expr(1.f);
|
||||||
|
WrapInFunction(expr);
|
||||||
|
|
||||||
|
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||||
|
|
||||||
|
EXPECT_EQ(Sem().Get(expr)->SourceVariable(), nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ResolverSourceVariableTest, FunctionReturnValue) {
|
||||||
|
auto* expr = Call("min", 1.f, 2.f);
|
||||||
|
WrapInFunction(expr);
|
||||||
|
|
||||||
|
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||||
|
|
||||||
|
EXPECT_EQ(Sem().Get(expr)->SourceVariable(), nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ResolverSourceVariableTest, BinaryExpression) {
|
||||||
|
auto* a = Var("a", ty.f32(), ast::StorageClass::kNone);
|
||||||
|
auto* expr = Add(a, Expr(1.f));
|
||||||
|
WrapInFunction(a, expr);
|
||||||
|
|
||||||
|
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||||
|
|
||||||
|
EXPECT_EQ(Sem().Get(expr)->SourceVariable(), nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ResolverSourceVariableTest, UnaryExpression) {
|
||||||
|
auto* a = Var("a", ty.f32(), ast::StorageClass::kNone);
|
||||||
|
auto* expr = create<ast::UnaryOpExpression>(ast::UnaryOp::kNegation, Expr(a));
|
||||||
|
WrapInFunction(a, expr);
|
||||||
|
|
||||||
|
EXPECT_TRUE(r()->Resolve()) << r()->error();
|
||||||
|
|
||||||
|
EXPECT_EQ(Sem().Get(expr)->SourceVariable(), nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
} // namespace tint::resolver
|
|
@ -24,8 +24,10 @@ Expression::Expression(const ast::Expression* declaration,
|
||||||
const sem::Type* type,
|
const sem::Type* type,
|
||||||
const Statement* statement,
|
const Statement* statement,
|
||||||
Constant constant,
|
Constant constant,
|
||||||
bool has_side_effects)
|
bool has_side_effects,
|
||||||
|
const Variable* source_var /* = nullptr */)
|
||||||
: declaration_(declaration),
|
: declaration_(declaration),
|
||||||
|
source_variable_(source_var),
|
||||||
type_(type),
|
type_(type),
|
||||||
statement_(statement),
|
statement_(statement),
|
||||||
constant_(std::move(constant)),
|
constant_(std::move(constant)),
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
namespace tint::sem {
|
namespace tint::sem {
|
||||||
class Statement;
|
class Statement;
|
||||||
class Type;
|
class Type;
|
||||||
|
class Variable;
|
||||||
} // namespace tint::sem
|
} // namespace tint::sem
|
||||||
|
|
||||||
namespace tint::sem {
|
namespace tint::sem {
|
||||||
|
@ -36,11 +37,13 @@ class Expression : public Castable<Expression, Node> {
|
||||||
/// @param statement the statement that owns this expression
|
/// @param statement the statement that owns this expression
|
||||||
/// @param constant the constant value of the expression. May be invalid
|
/// @param constant the constant value of the expression. May be invalid
|
||||||
/// @param has_side_effects true if this expression may have side-effects
|
/// @param has_side_effects true if this expression may have side-effects
|
||||||
|
/// @param source_var the (optional) source variable for this expression
|
||||||
Expression(const ast::Expression* declaration,
|
Expression(const ast::Expression* declaration,
|
||||||
const sem::Type* type,
|
const sem::Type* type,
|
||||||
const Statement* statement,
|
const Statement* statement,
|
||||||
Constant constant,
|
Constant constant,
|
||||||
bool has_side_effects);
|
bool has_side_effects,
|
||||||
|
const Variable* source_var = nullptr);
|
||||||
|
|
||||||
/// Destructor
|
/// Destructor
|
||||||
~Expression() override;
|
~Expression() override;
|
||||||
|
@ -57,6 +60,13 @@ class Expression : public Castable<Expression, Node> {
|
||||||
/// @return the constant value of this expression
|
/// @return the constant value of this expression
|
||||||
const Constant& ConstantValue() const { return constant_; }
|
const Constant& ConstantValue() const { return constant_; }
|
||||||
|
|
||||||
|
/// Returns the variable or parameter that this expression derives from.
|
||||||
|
/// For reference and pointer expressions, this will either be the originating
|
||||||
|
/// variable or a function parameter. For other types of expressions, it will
|
||||||
|
/// either be the parameter or constant declaration, or nullptr.
|
||||||
|
/// @return the source variable of this expression, or nullptr
|
||||||
|
const Variable* SourceVariable() const { return source_variable_; }
|
||||||
|
|
||||||
/// @return the behaviors of this statement
|
/// @return the behaviors of this statement
|
||||||
const sem::Behaviors& Behaviors() const { return behaviors_; }
|
const sem::Behaviors& Behaviors() const { return behaviors_; }
|
||||||
|
|
||||||
|
@ -69,6 +79,8 @@ class Expression : public Castable<Expression, Node> {
|
||||||
protected:
|
protected:
|
||||||
/// The AST expression node for this semantic expression
|
/// The AST expression node for this semantic expression
|
||||||
const ast::Expression* const declaration_;
|
const ast::Expression* const declaration_;
|
||||||
|
/// The source variable for this semantic expression, or nullptr
|
||||||
|
const Variable* source_variable_;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const sem::Type* const type_;
|
const sem::Type* const type_;
|
||||||
|
|
|
@ -27,8 +27,14 @@ MemberAccessorExpression::MemberAccessorExpression(
|
||||||
const ast::MemberAccessorExpression* declaration,
|
const ast::MemberAccessorExpression* declaration,
|
||||||
const sem::Type* type,
|
const sem::Type* type,
|
||||||
const Statement* statement,
|
const Statement* statement,
|
||||||
bool has_side_effects)
|
bool has_side_effects,
|
||||||
: Base(declaration, type, statement, Constant{}, has_side_effects) {}
|
const Variable* source_var /* = nullptr */)
|
||||||
|
: Base(declaration,
|
||||||
|
type,
|
||||||
|
statement,
|
||||||
|
Constant{},
|
||||||
|
has_side_effects,
|
||||||
|
source_var) {}
|
||||||
|
|
||||||
MemberAccessorExpression::~MemberAccessorExpression() = default;
|
MemberAccessorExpression::~MemberAccessorExpression() = default;
|
||||||
|
|
||||||
|
@ -37,8 +43,10 @@ StructMemberAccess::StructMemberAccess(
|
||||||
const sem::Type* type,
|
const sem::Type* type,
|
||||||
const Statement* statement,
|
const Statement* statement,
|
||||||
const StructMember* member,
|
const StructMember* member,
|
||||||
bool has_side_effects)
|
bool has_side_effects,
|
||||||
: Base(declaration, type, statement, has_side_effects), member_(member) {}
|
const Variable* source_var /* = nullptr */)
|
||||||
|
: Base(declaration, type, statement, has_side_effects, source_var),
|
||||||
|
member_(member) {}
|
||||||
|
|
||||||
StructMemberAccess::~StructMemberAccess() = default;
|
StructMemberAccess::~StructMemberAccess() = default;
|
||||||
|
|
||||||
|
@ -46,8 +54,9 @@ Swizzle::Swizzle(const ast::MemberAccessorExpression* declaration,
|
||||||
const sem::Type* type,
|
const sem::Type* type,
|
||||||
const Statement* statement,
|
const Statement* statement,
|
||||||
std::vector<uint32_t> indices,
|
std::vector<uint32_t> indices,
|
||||||
bool has_side_effects)
|
bool has_side_effects,
|
||||||
: Base(declaration, type, statement, has_side_effects),
|
const Variable* source_var /* = nullptr */)
|
||||||
|
: Base(declaration, type, statement, has_side_effects, source_var),
|
||||||
indices_(std::move(indices)) {}
|
indices_(std::move(indices)) {}
|
||||||
|
|
||||||
Swizzle::~Swizzle() = default;
|
Swizzle::~Swizzle() = default;
|
||||||
|
|
|
@ -40,10 +40,12 @@ class MemberAccessorExpression
|
||||||
/// @param type the resolved type of the expression
|
/// @param type the resolved type of the expression
|
||||||
/// @param statement the statement that owns this expression
|
/// @param statement the statement that owns this expression
|
||||||
/// @param has_side_effects whether this expression may have side effects
|
/// @param has_side_effects whether this expression may have side effects
|
||||||
|
/// @param source_var the (optional) source variable for this expression
|
||||||
MemberAccessorExpression(const ast::MemberAccessorExpression* declaration,
|
MemberAccessorExpression(const ast::MemberAccessorExpression* declaration,
|
||||||
const sem::Type* type,
|
const sem::Type* type,
|
||||||
const Statement* statement,
|
const Statement* statement,
|
||||||
bool has_side_effects);
|
bool has_side_effects,
|
||||||
|
const Variable* source_var = nullptr);
|
||||||
|
|
||||||
/// Destructor
|
/// Destructor
|
||||||
~MemberAccessorExpression() override;
|
~MemberAccessorExpression() override;
|
||||||
|
@ -61,11 +63,13 @@ class StructMemberAccess final
|
||||||
/// @param statement the statement that owns this expression
|
/// @param statement the statement that owns this expression
|
||||||
/// @param member the structure member
|
/// @param member the structure member
|
||||||
/// @param has_side_effects whether this expression may have side effects
|
/// @param has_side_effects whether this expression may have side effects
|
||||||
|
/// @param source_var the (optional) source variable for this expression
|
||||||
StructMemberAccess(const ast::MemberAccessorExpression* declaration,
|
StructMemberAccess(const ast::MemberAccessorExpression* declaration,
|
||||||
const sem::Type* type,
|
const sem::Type* type,
|
||||||
const Statement* statement,
|
const Statement* statement,
|
||||||
const StructMember* member,
|
const StructMember* member,
|
||||||
bool has_side_effects);
|
bool has_side_effects,
|
||||||
|
const Variable* source_var = nullptr);
|
||||||
|
|
||||||
/// Destructor
|
/// Destructor
|
||||||
~StructMemberAccess() override;
|
~StructMemberAccess() override;
|
||||||
|
@ -87,11 +91,13 @@ class Swizzle final : public Castable<Swizzle, MemberAccessorExpression> {
|
||||||
/// @param statement the statement that owns this expression
|
/// @param statement the statement that owns this expression
|
||||||
/// @param indices the swizzle indices
|
/// @param indices the swizzle indices
|
||||||
/// @param has_side_effects whether this expression may have side effects
|
/// @param has_side_effects whether this expression may have side effects
|
||||||
|
/// @param source_var the (optional) source variable for this expression
|
||||||
Swizzle(const ast::MemberAccessorExpression* declaration,
|
Swizzle(const ast::MemberAccessorExpression* declaration,
|
||||||
const sem::Type* type,
|
const sem::Type* type,
|
||||||
const Statement* statement,
|
const Statement* statement,
|
||||||
std::vector<uint32_t> indices,
|
std::vector<uint32_t> indices,
|
||||||
bool has_side_effects);
|
bool has_side_effects,
|
||||||
|
const Variable* source_var = nullptr);
|
||||||
|
|
||||||
/// Destructor
|
/// Destructor
|
||||||
~Swizzle() override;
|
~Swizzle() override;
|
||||||
|
|
|
@ -82,6 +82,13 @@ VariableUser::VariableUser(const ast::IdentifierExpression* declaration,
|
||||||
statement,
|
statement,
|
||||||
variable->ConstantValue(),
|
variable->ConstantValue(),
|
||||||
/* has_side_effects */ false),
|
/* has_side_effects */ false),
|
||||||
variable_(variable) {}
|
variable_(variable) {
|
||||||
|
auto* type = variable->Type();
|
||||||
|
if (type->Is<sem::Pointer>() && variable->Constructor()) {
|
||||||
|
source_variable_ = variable->Constructor()->SourceVariable();
|
||||||
|
} else {
|
||||||
|
source_variable_ = variable;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace tint::sem
|
} // namespace tint::sem
|
||||||
|
|
|
@ -265,6 +265,7 @@ tint_unittests_source_set("tint_unittests_resolver_src") {
|
||||||
"../../src/tint/resolver/resolver_test_helper.cc",
|
"../../src/tint/resolver/resolver_test_helper.cc",
|
||||||
"../../src/tint/resolver/resolver_test_helper.h",
|
"../../src/tint/resolver/resolver_test_helper.h",
|
||||||
"../../src/tint/resolver/side_effects_test.cc",
|
"../../src/tint/resolver/side_effects_test.cc",
|
||||||
|
"../../src/tint/resolver/source_variable_test.cc",
|
||||||
"../../src/tint/resolver/storage_class_layout_validation_test.cc",
|
"../../src/tint/resolver/storage_class_layout_validation_test.cc",
|
||||||
"../../src/tint/resolver/storage_class_validation_test.cc",
|
"../../src/tint/resolver/storage_class_validation_test.cc",
|
||||||
"../../src/tint/resolver/struct_layout_test.cc",
|
"../../src/tint/resolver/struct_layout_test.cc",
|
||||||
|
|
Loading…
Reference in New Issue