From 00eb8dfa8bd9f88fb47d12063792f8a160be81a2 Mon Sep 17 00:00:00 2001 From: Ben Clayton Date: Tue, 23 Feb 2021 16:08:09 +0000 Subject: [PATCH] Update docs/arch.md with new design Change-Id: I8deb4416ac2f1e14f8b863b80a20c23550ed05e6 Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/40383 Reviewed-by: dan sinclair Commit-Queue: Ben Clayton --- docs/arch.md | 241 ++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 170 insertions(+), 71 deletions(-) diff --git a/docs/arch.md b/docs/arch.md index 302058186b..81385fab0e 100644 --- a/docs/arch.md +++ b/docs/arch.md @@ -1,107 +1,206 @@ # Tint Architecture ``` - +--------+ +------+ - | SPIR-V | | WGSL | - +----|---+ +---|--+ - | | - +---------|---------------------------|--------+ - | | Reader | | - | | | | - | +-------|------+ +------|------+ | - | | SPIRV-Reader | | WGSL-Reader | | - | +--------------+ +-------------+ | - +-----------------------|----------------------+ - | - +--|--+ +---------+ - | AST |------| IsValid | - +--|--+ +---------+ - | - +--------|--------+ - | Type Determiner | - +--------|--------+ - | - +-----|-----+ - | Validator | - +-----|-----+ - | - +-----|-----+ - | Inspector | - +-----|-----+ - | - +------|-----+ - | Transforms | - +------|-----+ - | -+-------------------------------------|------------------------------------+ -| Writer | -| | -| +--------------+ +-------------+ +-------------+ +------------+ | -| | SPIRV-Writer | | WGSL-Writer | | HLSL-Writer | | MSL-Writer | | -| +-------|------+ +------|------+ +------|------+ +------|-----+ | -+---------|------------------|------------------|------------------|-------+ - | | | | - +----|---+ +---|--+ +---|--+ +--|--+ - | SPIR-V | | WGSL | | HLSL | | MSL | - +--------+ +------+ +------+ +-----+ + ┏━━━━━━━━┓ ┏━━━━━━┓ + ┃ SPIR━V ┃ ┃ WGSL ┃ + ┗━━━━┃━━━┛ ┗━━━┃━━┛ + ▼ ▼ + ┏━━━━━━━━━┃━━━━━━━━━━━━━━━━━━━━━━━━━━━┃━━━━━━━━┓ + ┃ ┃ Reader ┃ ┃ + ┃ ┃ ┃ ┃ + ┃ ┏━━━━━━━┻━━━━━━┓ ┏━━━━━━┻━━━━━━┓ ┃ + ┃ ┃ SPIRV-Reader ┃ ┃ WGSL-Reader ┃ ┃ + ┃ ┗━━━━━━━━━━━━━━┛ ┗━━━━━━━━━━━━━┛ ┃ + ┗━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━┛ + ▼ + ┏━━━━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━━━┓ + ┃ ProgramBuilder ┃ + ┃ (mutable) ┃ + ┏━━━━━━━━━━━━►┫ ┏━━━━━┓ ┏━━━━━━━┓ ┏━━━━━━━━━┓ ┃ + ┃ ┃ ┃ AST ┃ ┃ Types ┃ ┃ Symbols ┃ ┃ + ┃ ┃ ┗━━━━━┛ ┗━━━━━━━┛ ┗━━━━━━━━━┛ ┃ + ┃ ┗━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┛ + ┃ ▼ + ┃ ┌┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┃┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┐ + ▲ ┆ Build ▼ ┆ + ┏━━━┻━━━┓ ┆ ┏━━━━━━━━┻━━━━━━━━┓ ┆ + ┃ Clone ┃ ┆ ┃ Type Determiner ┃ ┆ + ┗━━━┳━━━┛ ┆ ┗━━━━━━━━━━━━━━━━━┛ ┆ + ▲ └┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┃┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┘ + ┃ ▼ + ┃ ┏━━━━━━━━━━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━━━━━━━━┓ + ┃ ┃ Program ┃ + ┃ ┃ (immutable) ┃ + ┣━━━━━━◄┫ ┏━━━━━┓ ┏━━━━━━━┓ ┏━━━━━━━━━━┓ ┏━━━━━━━━━┓ ┃ + ┃ ┃ ┃ AST ┃ ┃ Types ┃ ┃ Semantic ┃ ┃ Symbols ┃ ┃ + ┃ ┃ ┗━━━━━┛ ┗━━━━━━━┛ ┗━━━━━━━━━━┛ ┗━━━━━━━━━┛ ┃ + ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━┛ + ▲ ▼ +┏━━━━━┻━━━━━┓ ┏━━━━━┻━━━━━┓ ┏━━━━━━━━━━━┓ +┃ Transform ┃◄━━━━━━━━━━━━━━━━━◄┃ Validator ┣━━━━━━►┃ Inspector ┃ +┗━━━━━━━━━━━┛ ┗━━━━━┳━━━━━┛ ┗━━━━━━━━━━━┛ + ▼ +┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ +┃ Writer ┃ +┃ ┃ +┃ ┏━━━━━━━━━━━━━━┓ ┏━━━━━━━━━━━━━┓ ┏━━━━━━━━━━━━━┓ ┏━━━━━━━━━━━━┓ ┃ +┃ ┃ SPIRV-Writer ┃ ┃ WGSL-Writer ┃ ┃ HLSL-Writer ┃ ┃ MSL-Writer ┃ ┃ +┃ ┗━━━━━━━┳━━━━━━┛ ┗━━━━━━┳━━━━━━┛ ┗━━━━━━┳━━━━━━┛ ┗━━━━━━┳━━━━━┛ ┃ +┗━━━━━━━━━┃━━━━━━━━━━━━━━━━━━┃━━━━━━━━━━━━━━━━━━┃━━━━━━━━━━━━━━━━━━┃━━━━━━━┛ + ▼ ▼ ▼ ▼ + ┏━━━━┻━━━┓ ┏━━━┻━━┓ ┏━━━┻━━┓ ┏━━┻━━┓ + ┃ SPIR-V ┃ ┃ WGSL ┃ ┃ HLSL ┃ ┃ MSL ┃ + ┗━━━━━━━━┛ ┗━━━━━━┛ ┗━━━━━━┛ ┗━━━━━┛ ``` -## WGSL Reader +## Reader + +Readers are responsible for parsing a shader program and populating a +`ProgramBuilder` with the parsed AST, type 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 primary interface to construct an immutable `Program`. +There are a number of methods exposed which make creating of the `Program` +simpler. 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, type determination is +run 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 the AST is **structurally** correct. This checks that things +like `if` statements have a condition and body attached. + +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 `Program`s, `ProgramBuilder`s are not part of the public Tint API. ## AST -The Abstract Syntax Tree is a directed acyclic graph of nodes encoding -the structure of the WGSL program. +The Abstract Syntax Tree is a directed acyclic graph of `ast::Node`s which +encode the syntactic structure of the WGSL program. -Many AST nodes have numeric parameters. For example, the ast::StrideDecoration -node has numeric stride parameter, which is a count of the number of bytes from -the start of one array element to the start of the next. The AST node itself -does not constrain the set of stride values that you can set, aside from storing -it as an unsigned integer. +The root of the AST is the `ast::Module` class which holds each of the declared +functions, variables and user defined types (type aliases and structures). -After creating the AST for the whole WGSL program, Tint will run an `IsValid` -method which verifies that the produced AST is structurally correct. This -means that things like `if` statements have a condition and body attached. +Each `ast::Node` represents a **single** part of the program's source, and so +`ast::Node`s are not shared. -A later phase of processing, Validation, will check properties such as whether -array strides satisfy all the requirements in the WGSL specification. +The AST does not perform any verification of its content. For example, the +`ast::StrideDecoration` node has numeric stride parameter, which is a count of +the number of bytes from the start of one array element to the start of the +next. The AST node itself does not constrain the set of stride values that you +can set, aside from storing it as an unsigned integer. + +## Types + +Types are constructed during the Reader and Type Determination phases, and are +held by the `Program` or `ProgramBuilder`. AST and semantic nodes can both +reference types. + +Each `type::Type` node **uniquely** represents a particular spelling of a WGSL +type within the program, so you can compare `type::Type*` pointers to check for +equivalence of type expressions. +For example, there is only one `type::Type` node for the `i32` type, no matter +how many times it is mentioned in the source program. +However, if `MyI32` is a type alias for `i32`, then they will have two different +type nodes. + +## Semantic information + +Semantic information is held by `semantic::Node`s 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 an intrinsic +function call, and the module scoped variables used by each function. + +Semantic information is generated by the `TypeDeterminer` when the `Program` +is built from a `ProgramBuilder`. + +The `semantic::Info` class holds a map of `ast::Node`s to `semantic::Node`s. +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 `semantic::Variable`, +and so the `semantic::Variable` does not have a single corresponding +`ast::Node`. + +Unlike `ast::Node`s, semantic nodes may not necessarily form a directed acyclic +graph, and the semantic graph may contain diamonds. + +## Symbols + +Symbols represent a unique string identifier in the source program. These string +identifiers are transformed into symbols within the `Reader`s. + +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. ## Type Determiner -The type determination stage assigns a result type to each node in the AST. It -will do the minimal amount of validation required in order to always be -accessing valid nodes, but that doesn't mean the overall AST is valid. (e.g. a -4 component vector type constructor with 5 components will pass type -determination but is invalid.) +The `TypeDeterminer` will automatically run when a `Program` is built. +A `TypeDeterminer` creates the `Program`s semantic information by analyzing the +`Program`s AST and type information. +The `TypeDeterminer` will do the minimal amount of validation required in order +to always be accessing valid nodes, reporting any errors found in the +`Program`'s diagnostics. Even if the `TypeDeterminer` doesn't generate any +errors doesn't mean the generated `Program` is semantically valid. Use the +`Validator` to check for a `Program`'s final validity. + +## Program + +A `Program` holds an immutable version of the information from the +`ProgramBuilder` along with semantic information generated by the +`TypeDeterminer`. + +Like `ProgramBuilder`, `Program::IsValid()` may be called to ensure the AST is +structurally correct and that the `TypeDeterminer` did not report any errors. +`Program::IsValid()` does not perform semantic validation, use the `Validator` +to check for a `Program`'s final validity. + +Unlike the `ProgramBuilder`, a `Program` is fully immutable, and is part of the +public Tint API. The immutable nature of `Program`s make these entirely safe +to share between multiple threads without the use of synchronization primitives. ## Validation -After the validation step the AST should be a known valid WGSL program. +The `Validator` checks a `Program` for static validity as specified by the WGSL +language, and reports any validation errors found. Attempting to pass a +`Program` that does not pass validation on to later stages will result in +undefined behavior. ## Inspector -The inspectors job is to go through the AST and pull out various pieces of +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 AST. This is for things -like Vertex Pulling or Robust Buffer Access. These transforms will modify the -AST and must produce valid AST after their execution. +There maybe various transforms we want to run over the `Program`. +This is for things like Vertex Pulling or Robust Buffer Access. -Currently the transforms are run individually but we should consider adding -a transform manager to maintain and execute the list of transforms. +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 type determination 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 -The writers should be thread safe, we maybe generating the HLSL and MLS output -at the same time on different threads. (The writer portion is the only one -that needs to be thread safe.) +A writer is responsible for writing the `Program` in the target shader language. + +The input `Program` to a writer must be valid (pass validation).