Fix TODOs dating back to when types were an AST / SEM hybrid concept. Bring the `arch.md` to reflect how things work today. Bug: tint:724 Change-Id: I6bf4174158cf490f2839aeed78164b66e3410f27 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/96141 Kokoro: Kokoro <noreply+kokoro@google.com> Reviewed-by: Antonio Maiorano <amaiorano@google.com> Commit-Queue: Ben Clayton <bclayton@google.com>
11 KiB
Tint Architecture
┏━━━━━━━━┓ ┏━━━━━━┓
┃ SPIR━V ┃ ┃ WGSL ┃
┗━━━━┃━━━┛ ┗━━━┃━━┛
▼ ▼
┏━━━━━━━━━┃━━━━━━━━━━━━━━━━━━━━━━━━━━━┃━━━━━━━━┓
┃ ┃ Reader ┃ ┃
┃ ┃ ┃ ┃
┃ ┏━━━━━━━┻━━━━━━┓ ┏━━━━━━┻━━━━━━┓ ┃
┃ ┃ SPIRV-Reader ┃ ┃ WGSL-Reader ┃ ┃
┃ ┗━━━━━━━━━━━━━━┛ ┗━━━━━━━━━━━━━┛ ┃
┗━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━┛
▼
┏━━━━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━━━┓
┃ ProgramBuilder ┃
┃ (mutable) ┃
┏━━━━━━━━━━━━►┫ ┏━━━━━┓ ┏━━━━━━━━━┓ ┃
┃ ┃ ┃ AST ┃ ┃ Symbols ┃ ┃
┃ ┃ ┗━━━━━┛ ┗━━━━━━━━━┛ ┃
┃ ┗━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┛
┃ ▼
┃ ┌┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┃┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┐
▲ ┆ Resolve ▼ ┆
┏━━━┻━━━┓ ┆ ┏━━━━━━━━┻━━━━━━━━┓ ┆
┃ Clone ┃ ┆ ┃ Resolver ┃ ┆
┗━━━┳━━━┛ ┆ ┗━━━━━━━━━━━━━━━━━┛ ┆
▲ └┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┃┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┘
┃ ▼
┃ ┏━━━━━━━━━━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━━━━━━━━┓
┃ ┃ Program ┃
┃ ┃ (immutable) ┃
┣━━━━━━◄┫ ┏━━━━━┓ ┏━━━━━━━━━━┓ ┏━━━━━━━━━┓ ┃
┃ ┃ ┃ AST ┃ ┃ Semantic ┃ ┃ Symbols ┃ ┃
┃ ┃ ┗━━━━━┛ ┗━━━━━━━━━━┛ ┗━━━━━━━━━┛ ┃
┃ ┗━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━┛
▲ ▼
┏━━━━━┻━━━━━┓ ┃ ┏━━━━━━━━━━━┓
┃ Transform ┃◄━━━━━━━━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━►┃ Inspector ┃
┗━━━━━━━━━━━┛ ┃ ┗━━━━━━━━━━━┛
▼
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ Writers ┃
┃ ┃
┃ ┏━━━━━━━━━━━━━━┓┏━━━━━━━━━━━━━┓┏━━━━━━━━━━━━━┓┏━━━━━━━━━━━━━┓┏━━━━━━━━━━━━┓ ┃
┃ ┃ SPIRV-Writer ┃┃ WGSL-Writer ┃┃ HLSL-Writer ┃┃ GLSL-Writer ┃┃ MSL-Writer ┃ ┃
┃ ┗━━━━━━━┳━━━━━━┛┗━━━━━━┳━━━━━━┛┗━━━━━━┳━━━━━━┛┗━━━━━━┳━━━━━━┛┗━━━━━━┳━━━━━┛ ┃
┗━━━━━━━━━┃━━━━━━━━━━━━━━┃━━━━━━━━━━━━━━┃━━━━━━━━━━━━━━┃━━━━━━━━━━━━━━┃━━━━━━━┛
▼ ▼ ▼ ▼ ▼
┏━━━━┻━━━┓ ┏━━━┻━━┓ ┏━━━┻━━┓ ┏━━━┻━━┓ ┏━━┻━━┓
┃ SPIR-V ┃ ┃ WGSL ┃ ┃ HLSL ┃ ┃ GLSL ┃ ┃ MSL ┃
┗━━━━━━━━┛ ┗━━━━━━┛ ┗━━━━━━┛ ┗━━━━━━┛ ┗━━━━━┛
Reader
Readers are responsible for parsing a shader program and populating a
ProgramBuilder with the parsed AST and symbol information.
The WGSL reader is a recursive descent parser. It closely follows the WGSL grammar in the naming of the parse methods.
ProgramBuilder
A ProgramBuilder is the interface to construct an immutable Program.
There are a large number of helper methods for simplifying the creation of the
AST nodes. A ProgramBuilder can only be used once, and must be discarded after
the Program is constructed.
A Program is built from the ProgramBuilder by std::move()ing the
ProgramBuilder to a new Program object. When built, resolution is performed
so the produced Program will contain all the needed semantic information.
At any time before building the Program, ProgramBuilder::IsValid() may be
called to ensure that no error diagnostics have been raised during the
construction of the AST. This includes parser syntax errors, but not semantic
validation which happens during the Resolve phase.
If further changes to the Program are needed (say via a Transform) then a
new ProgramBuilder can be produced by cloning the Program into a new
ProgramBuilder.
Unlike Programs, ProgramBuilders are not part of the public Tint API.
AST
The Abstract Syntax Tree is a directed acyclic graph of ast::Nodes which
encode the syntactic structure of the WGSL program.
The root of the AST is the ast::Module class which holds each of the declared
functions, variables and user declared types (type aliases and structures).
Each ast::Node represents a single part of the program's source, and so
ast::Nodes are not shared.
The AST does not perform any verification of its content. For example, the
ast::Array node has numeric size parameter, which is not validated to be
within the WGSL specification limits until validation of the Resolver.
Semantic information
Semantic information is held by sem::Nodes which describe the program at
a higher / more abstract level than the AST. This includes information such as
the resolved type of each expression, the resolved overload of a builtin
function call, and the module scoped variables used by each function.
Semantic information is generated by the Resolver when the Program
is built from a ProgramBuilder.
The sem::Info class holds a map of ast::Nodes to sem::Nodes.
This map is many-to-one - i.e. while a AST node might have a single
corresponding semantic node, the reverse may not be true. For example:
many ast::IdentifierExpression nodes may map to a single sem::Variable,
and so the sem::Variable does not have a single corresponding
ast::Node.
Unlike ast::Nodes, semantic nodes may not necessarily form a directed acyclic
graph, and the semantic graph may contain diamonds.
Types
AST types are regular AST nodes, in that they uniquely represent a single part of the parsed source code. Unlike semantic types, identical AST types are not de-duplicated as they refer to the source usage of the type.
Semantic types are constructed during the Resolver phase, and are held by
the Program or ProgramBuilder.
Each sem::Type node uniquely represents a particular WGSL type within the
program, so you can compare type::Type* pointers to check for type
equivalence. For example, a Program will only hold one instance of the
sem::I32 semantic type, no matter how many times an i32 is mentioned in the
source program.
WGSL type aliases resolve to their target semantic type. For example, given:
type MyI32 = i32;
const a : i32 = 1;
const b : MyI32 = 2;
The semantic types for the variables a and b will both be the same
sem::I32 node pointer.
Symbols
Symbols represent a unique string identifier in the source program. These string
identifiers are transformed into symbols within the Readers.
During the Writer phase, symbols may be emitted as strings using a Namer.
A Namer may output the symbol in any form that preserves the uniqueness of
that symbol.
Resolver
The Resolver will automatically run when a Program is built.
A Resolver creates the Programs semantic information by analyzing the
Programs AST and type information.
The Resolver will validate to make sure the generated Program is
semantically valid.
Program
A Program holds an immutable version of the information from the
ProgramBuilder along with semantic information generated by the
Resolver.
Program::IsValid() may be called to ensure the program is structurally correct
and semantically valid, and that the Resolver did not report any errors
during validation.
Unlike the ProgramBuilder, a Program is fully immutable, and is part of the
public Tint API. The immutable nature of Programs make these entirely safe
to share between multiple threads without the use of synchronization primitives.
Inspector
The inspectors job is to go through the Program and pull out various pieces of
information. The information may be used to pass information into the downstream
compilers (things like specialization constants) or may be used to pass into
transforms to update the AST before generating the resulting code.
The input Program to the inspector must be valid (pass validation).
Transforms
There maybe various transforms we want to run over the Program.
This is for things like Vertex Pulling or Robust Buffer Access.
A transform operates by cloning the input Program into a new ProgramBuilder,
applying the required changes, and then finally building and returning a new
output Program. As the resolver is always run when a Program is built,
Transforms will always emit a Program with semantic information.
The input Program to a transform must be valid (pass validation).
If the input Program of a transform is valid then the transform must guarantee
that the output program is also valid.
Writers
A writer is responsible for writing the Program in the target shader language.
The input Program to a writer must be valid (pass validation).