Implement Pointers and References

This change implements pointers and references as described by the WGSL
specification change in https://github.com/gpuweb/gpuweb/pull/1569.

reader/spirv:
* Now emits address-of `&expr` and indirection `*expr` operators as
  needed.
* As an identifier may now resolve to a pointer or reference type
  depending on whether the declaration is a `var`, `let` or
  parameter, `Function::identifier_values_` has been changed from
  an ID set to an ID -> Type* map.

resolver:
* Now correctly resolves all expressions to either a value type,
  reference type or pointer type.
* Validates pointer / reference rules on assignment, `var` and `let`
  construction, and usage.
* Handles the address-of and indirection operators.
* No longer does any implicit loads of pointer types.
* Storage class validation is still TODO (crbug.com/tint/809)

writer/spirv:
* Correctly handles variables and expressions of pointer and
  reference types, emitting OpLoads where necessary.

test:
* Lots of new test cases

Fixed: tint:727
Change-Id: I77d3281590e35e5a3122f5b74cdeb71a6fe51f74
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/50740
Commit-Queue: Ben Clayton <bclayton@chromium.org>
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: David Neto <dneto@google.com>
This commit is contained in:
Ben Clayton
2021-05-18 10:28:48 +00:00
committed by Commit Bot service account
parent d1232670ae
commit 9b54a2e53c
192 changed files with 6289 additions and 1680 deletions

View File

@@ -113,7 +113,7 @@ Output BindingRemapper::Run(const Program* in, const DataMap& datamap) {
auto ac_it = remappings->access_controls.find(from);
if (ac_it != remappings->access_controls.end()) {
ast::AccessControl::Access ac = ac_it->second;
auto* ty = in->Sem().Get(var)->Type();
auto* ty = in->Sem().Get(var)->Type()->UnwrapRef();
ast::Type* inner_ty = CreateASTTypeFor(&ctx, ty);
auto* new_ty = ctx.dst->create<ast::AccessControl>(ac, inner_ty);
auto* new_var = ctx.dst->create<ast::Variable>(

View File

@@ -41,7 +41,7 @@ ast::ArrayAccessorExpression* BoundArrayAccessors::Transform(
CloneContext* ctx) {
auto& diags = ctx->dst->Diagnostics();
auto* ret_type = ctx->src->Sem().Get(expr->array())->Type()->UnwrapAll();
auto* ret_type = ctx->src->Sem().Get(expr->array())->Type()->UnwrapRef();
if (!ret_type->Is<sem::Array>() && !ret_type->Is<sem::Matrix>() &&
!ret_type->Is<sem::Vector>()) {
return nullptr;

View File

@@ -29,7 +29,7 @@ var<private> a : array<f32, 3>;
let c : u32 = 1u;
fn f() {
let b : ptr<private, f32> = a[c];
let b : f32 = a[c];
}
)";
@@ -39,7 +39,7 @@ var<private> a : array<f32, 3>;
let c : u32 = 1u;
fn f() {
let b : ptr<private, f32> = a[min(u32(c), 2u)];
let b : f32 = a[min(u32(c), 2u)];
}
)";

View File

@@ -142,7 +142,7 @@ Output CalculateArrayLength::Run(const Program* in, const DataMap&) {
auto* storage_buffer_expr = accessor->structure();
auto* storage_buffer_sem = sem.Get(storage_buffer_expr);
auto* storage_buffer_type =
storage_buffer_sem->Type()->UnwrapAll()->As<sem::Struct>();
storage_buffer_sem->Type()->UnwrapRef()->As<sem::Struct>();
// Generate BufferSizeIntrinsic for this storage type if we haven't
// already

View File

@@ -115,7 +115,7 @@ Output CanonicalizeEntryPointIO::Run(const Program* in, const DataMap&) {
// Pull out all struct members and build initializer list.
std::vector<Symbol> member_names;
for (auto* member : str->Members()) {
if (member->Type()->UnwrapAll()->Is<sem::Struct>()) {
if (member->Type()->Is<sem::Struct>()) {
TINT_ICE(ctx.dst->Diagnostics()) << "nested pipeline IO struct";
}
@@ -205,7 +205,7 @@ Output CanonicalizeEntryPointIO::Run(const Program* in, const DataMap&) {
if (auto* str = ret_type->As<sem::Struct>()) {
// Rebuild struct with only the entry point IO attributes.
for (auto* member : str->Members()) {
if (member->Type()->UnwrapAll()->Is<sem::Struct>()) {
if (member->Type()->Is<sem::Struct>()) {
TINT_ICE(ctx.dst->Diagnostics()) << "nested pipeline IO struct";
}

View File

@@ -29,6 +29,7 @@
#include "src/sem/array.h"
#include "src/sem/call.h"
#include "src/sem/member_accessor_expression.h"
#include "src/sem/reference_type.h"
#include "src/sem/struct.h"
#include "src/sem/variable.h"
#include "src/utils/get_or_create.h"
@@ -56,7 +57,7 @@ struct OffsetExpr : Offset {
explicit OffsetExpr(ast::Expression* e) : expr(e) {}
ast::Expression* Build(CloneContext& ctx) override {
auto* type = ctx.src->Sem().Get(expr)->Type()->UnwrapAll();
auto* type = ctx.src->Sem().Get(expr)->Type()->UnwrapRef();
auto* res = ctx.Clone(expr);
if (!type->Is<sem::U32>()) {
res = ctx.dst->Construct<ProgramBuilder::u32>(res);
@@ -333,8 +334,8 @@ void InsertGlobal(CloneContext& ctx,
/// @returns the unwrapped, user-declared constructed type of ty.
const ast::NamedType* ConstructedTypeOf(const sem::Type* ty) {
while (true) {
if (auto* ptr = ty->As<sem::Pointer>()) {
ty = ptr->StoreType();
if (auto* ref = ty->As<sem::Reference>()) {
ty = ref->StoreType();
continue;
}
if (auto* str = ty->As<sem::Struct>()) {
@@ -466,14 +467,14 @@ struct DecomposeStorageAccess::State {
for (auto* member : str->Members()) {
auto* offset = ctx.dst->Add("offset", member->Offset());
Symbol load = LoadFunc(ctx, insert_after, buf_ty,
member->Type()->UnwrapAll(), var_user);
member->Type()->UnwrapRef(), var_user);
values.emplace_back(ctx.dst->Call(load, "buffer", offset));
}
} else if (auto* arr = el_ty->As<sem::Array>()) {
for (uint32_t i = 0; i < arr->Count(); i++) {
auto* offset = ctx.dst->Add("offset", arr->Stride() * i);
Symbol load = LoadFunc(ctx, insert_after, buf_ty,
arr->ElemType()->UnwrapAll(), var_user);
arr->ElemType()->UnwrapRef(), var_user);
values.emplace_back(ctx.dst->Call(load, "buffer", offset));
}
}
@@ -546,7 +547,7 @@ struct DecomposeStorageAccess::State {
auto* access = ctx.dst->MemberAccessor(
"value", ctx.Clone(member->Declaration()->symbol()));
Symbol store = StoreFunc(ctx, insert_after, buf_ty,
member->Type()->UnwrapAll(), var_user);
member->Type()->UnwrapRef(), var_user);
auto* call = ctx.dst->Call(store, "buffer", offset, access);
body.emplace_back(ctx.dst->create<ast::CallStatement>(call));
}
@@ -555,7 +556,7 @@ struct DecomposeStorageAccess::State {
auto* offset = ctx.dst->Add("offset", arr->Stride() * i);
auto* access = ctx.dst->IndexAccessor("value", ctx.dst->Expr(i));
Symbol store = StoreFunc(ctx, insert_after, buf_ty,
arr->ElemType()->UnwrapAll(), var_user);
arr->ElemType()->UnwrapRef(), var_user);
auto* call = ctx.dst->Call(store, "buffer", offset, access);
body.emplace_back(ctx.dst->create<ast::CallStatement>(call));
}
@@ -661,7 +662,7 @@ Output DecomposeStorageAccess::Run(const Program* in, const DataMap&) {
state.AddAccess(ident, {
var,
ToOffset(0u),
var->Type()->UnwrapAll(),
var->Type()->UnwrapRef(),
});
}
}
@@ -681,7 +682,7 @@ Output DecomposeStorageAccess::Run(const Program* in, const DataMap&) {
accessor, {
access.var,
Add(std::move(access.offset), std::move(offset)),
vec_ty->type()->UnwrapAll(),
vec_ty->type()->UnwrapRef(),
});
}
}
@@ -694,7 +695,7 @@ Output DecomposeStorageAccess::Run(const Program* in, const DataMap&) {
{
access.var,
Add(std::move(access.offset), std::move(offset)),
member->Type()->UnwrapAll(),
member->Type()->UnwrapRef(),
});
}
}
@@ -710,7 +711,7 @@ Output DecomposeStorageAccess::Run(const Program* in, const DataMap&) {
{
access.var,
Add(std::move(access.offset), std::move(offset)),
arr->ElemType()->UnwrapAll(),
arr->ElemType()->UnwrapRef(),
});
continue;
}
@@ -720,7 +721,7 @@ Output DecomposeStorageAccess::Run(const Program* in, const DataMap&) {
{
access.var,
Add(std::move(access.offset), std::move(offset)),
vec_ty->type()->UnwrapAll(),
vec_ty->type()->UnwrapRef(),
});
continue;
}
@@ -770,8 +771,8 @@ Output DecomposeStorageAccess::Run(const Program* in, const DataMap&) {
auto* buf = access.var->Declaration();
auto* offset = access.offset->Build(ctx);
auto* buf_ty = access.var->Type()->UnwrapPtr();
auto* el_ty = access.type->UnwrapAll();
auto* buf_ty = access.var->Type()->UnwrapRef();
auto* el_ty = access.type->UnwrapRef();
auto* insert_after = ConstructedTypeOf(access.var->Type());
Symbol func = state.LoadFunc(ctx, insert_after, buf_ty, el_ty,
access.var->As<sem::VariableUser>());
@@ -785,8 +786,8 @@ Output DecomposeStorageAccess::Run(const Program* in, const DataMap&) {
for (auto& store : state.stores) {
auto* buf = store.target.var->Declaration();
auto* offset = store.target.offset->Build(ctx);
auto* buf_ty = store.target.var->Type()->UnwrapPtr();
auto* el_ty = store.target.type->UnwrapAll();
auto* buf_ty = store.target.var->Type()->UnwrapRef();
auto* el_ty = store.target.type->UnwrapRef();
auto* value = store.assignment->rhs();
auto* insert_after = ConstructedTypeOf(store.target.var->Type());
Symbol func = state.StoreFunc(ctx, insert_after, buf_ty, el_ty,

View File

@@ -52,7 +52,10 @@ Output ExternalTextureTransform::Run(const Program* in, const DataMap&) {
// if the first parameter is an external texture.
if (auto* var =
sem.Get(call_expr->params()[0])->As<sem::VariableUser>()) {
if (var->Variable()->Type()->Is<sem::ExternalTexture>()) {
if (var->Variable()
->Type()
->UnwrapRef()
->Is<sem::ExternalTexture>()) {
if (intrinsic->Type() == sem::IntrinsicType::kTextureLoad &&
call_expr->params().size() != 2) {
TINT_ICE(ctx.dst->Diagnostics())

View File

@@ -17,6 +17,7 @@
#include <algorithm>
#include "src/program_builder.h"
#include "src/sem/reference_type.h"
TINT_INSTANTIATE_TYPEINFO(tint::transform::Data);
@@ -107,6 +108,9 @@ ast::Type* Transform::CreateASTTypeFor(CloneContext* ctx, const sem::Type* ty) {
return ctx->dst->create<ast::TypeName>(
ctx->Clone(s->Declaration()->name()));
}
if (auto* s = ty->As<sem::Reference>()) {
return CreateASTTypeFor(ctx, s->StoreType());
}
TINT_UNREACHABLE(ctx->dst->Diagnostics())
<< "Unhandled type: " << ty->TypeInfo().name;
return nullptr;