kparzysz-quic commented on code in PR #14148:
URL: https://github.com/apache/tvm/pull/14148#discussion_r1124650400


##########
relax_spec.md:
##########
@@ -0,0 +1,803 @@
+# Informal Relax Language Specification
+
+Note: Text in «double chevrons» indicates features not present in the current 
prototype.
+
+In order to develop and test Relax, it is important for compiler developers to 
agree on what a given program in Relax means and what makes it valid so that 
test cases can be evaluated independently of any particular Relax 
implementation. This document is intended to describe Relax's grammar 
constructs (its [abstract syntax 
tree](https://en.wikipedia.org/wiki/Abstract_syntax_tree), or AST), the 
semantics of its grammar (what the different constructs mean), Relax's type 
system and type-checking rules (what makes a Relax program valid), and its 
rules for reasoning about structural information (such as tensor shapes) in 
detailed though still informal terms. If necessary, we may encode these rules 
more formally to allow for more automated analysis.
+
+Though this document will use the TVMScript front end for some examples, 
specifying the mapping from Python's AST to Relax's AST will be deferred until 
the parser becomes more stable.
+
+# Table of Contents
+
+1. [Overview](#overview)
+2. [Top-Level Program Organization](#top-level-program-organization-irmodule)
+3. [Values in Relax](#values-in-relax)
+4. [Variable Scoping](#variable-scoping)
+5. [Normal Form](#normal-form)
+6. [Well-Formedness Criteria](#well-formedness-criteria)
+7. [Structural Information in Relax](#structural-information-in-relax)
+8. [Semantics](#detailed-semantics)
+
+# Overview
+
+This section will outline the grammar of Relax and give very brief 
descriptions of the different components, including the semantics and 
structural information (`StructInfo`) system. The rest of this document will 
provide more detailed descriptions of these facets of the language, including 
the validity conditions that the `StructInfo` system upholds.
+
+## Differences from Relay
+
+Per the [original workshop paper](https://arxiv.org/abs/1810.00952) and the 
[later report](https://arxiv.org/abs/1904.08368), Relay was designed to be a 
high-level functional language for expressing deep learning models at a high 
level. While Relay is not entirely pure (the `Ref` type is modeled after 
reference types in SML and similar functional languages), the assumption in 
Relay is that tensor operators are generally pure, meaning that they do not 
change the program state other than by producing new values. Additionally, 
Relay's type system also requires operators to have type relations that infer 
static tensor types or conclude that a dimension is unknown at compile time 
(`Any`). The need to register type relations and ensure operators' purity makes 
it difficult to add new operators to Relay and particularly difficult to call 
directly into TIR or external libraries, which are often not pure; any such 
extension requires adding new operators and abstracting over any impurity.
+
+While Relax aims to be as general and expressive as Relay, Relax is intended 
to make it much easier to interoperate with external libraries and especially 
with TIR. In particular, Relax includes a mechanism for calling arbitrary TVM 
`PackedFunc`s (which can call external libraries) and special support for TIR. 
The language accordingly does not assume that such operations are pure, though 
this does require reasoning about aliasing and similar issues. Additionally, 
tensor shapes are no longer handled during type checking; each expression has 
associated structural information associated with it, in addition to a type. 
This structural information supports static reasoning about tensor shapes in 
many cases, but also facilitates a fallback to dynamic checking when that is 
not possible. This approach to shapes allows for richer shape constraints and 
other structural properties to be checked at run time (such as with _symbolic_ 
shapes, where some dimensions are variables) and allows for mor
 e quickly integrating calls into TIR or external libraries into Relax code by 
obviating the need for type relations.
+
+## Grammar
+
+Below is a diagram of the various AST constructs in Relax, including types. In 
code, these are defined on the C++ side in `include/tvm/relax/{expr.h, type.h}` 
and in Python in `python/tvm/relax/{expr.py, ty.py}`. This diagram will give 
the names of the AST nodes and the types and names of their members. The 
semantics will describe what computation each construct represents; an AST is 
simply data. A Relax program consists of an `IRModule` with global variables 
bound to Relax functions that implement the computations of interest.
+
+(On the notation: `[x]` means "a list of `x`," `x?` means "optionally `x`," 
`{x: y}` means "a map of `x` to `y`," `x | y` means "`x` or `y`," and `#` is 
used for comments.)
+
+```
+# PrimExprs are defined in TIR, see include/tvm/tir/expr.h
+# They are intended to have the same semantics as in TIR
+PrimExpr ::=
+           Var(name: string) # shape variables
+         | IntImm(value: int64)
+         | Add(a: PrimExpr, b: PrimExpr)
+         | Sub(a: PrimExpr, b: PrimExpr)
+         | Mul(a: PrimExpr, b: PrimExpr)
+         | Div(a: PrimExpr, b: PrimExpr)
+         | Min(a: PrimExpr, b: PrimExpr)
+         | Max(a: PrimExpr, b: PrimExpr)
+         | Not(a: PrimExpr)
+         | And(a: PrimExpr, b: PrimExpr)
+         | Or(a: PrimExpr, b: PrimExpr)
+         | Select(condition: PrimExpr, true_value: PrimExpr, false_value: 
PrimExpr)
+         # (others may be added later, as deemed necessary)
+
+# Also from TIR
+DataType ::= Int(bits: int, lanes: int)
+           | UInt(bits: int, lanes: int)
+           | Float(bits: int, lanes: int)
+           | Handle(bits: int, lanes: int)
+
+StructInfo ::= TensorStructInfo(shape: Expr?, dtype: DataType, ndim: int)
+             | ShapeStructInfo(values: [PrimExpr]?, ndim: int)
+             | PrimStructInfo(dtype: DataType)
+             | ObjectStructInfo()
+             | TupleStructInfo(fields: [StructInfo])
+             | FuncStructInfo(params: [StructInfo]?, ret: StructInfo, 
derive_func: EnvFunc?*)
+
+# expressions
+Expr ::=   Constant(data: NDArray)
+           # scoped to functions or SeqExprs
+         | Var(name_hint: string, struct_info_annotation: StructInfo?)
+           # scoped to DataflowBlocks
+         | DataflowVar(name_hint: string, struct_info_annotation: StructInfo?)
+         | GlobalVar(name_hint: string)
+         | Tuple(fields: [Expr])
+         | SeqExpr(blocks: [BindingBlock], body: Expr)
+         | PrimValue(value: PrimExpr)
+         | StringImm(value: string)
+         | DataTypeImm(value: DataType)
+         | Function(params: [Var], body: Expr, ret_struct_info: StructInfo?, 
attrs: Attrs?)
+         | If(cond: Expr, true_branch: Expr, false_branch: Expr)
+         | ExternFunc(global_symbol: string)
+         | Call(op: Expr, args: [Expr], sinfo_args: [StructInfo], attrs: 
Attrs?)
+         | ShapeExpr(values: [PrimExpr])
+         | TupleGetItem(tuple_value: Expr, index: int)
+         | Op(op_name: string)
+
+# binding blocks (analogous to sequence of statements)
+BindingBlock ::= 
+           BindingBlock(bindings: [Binding])
+         | DataflowBlock(bindings: [Binding])
+
+# bindings (analogous to statements)
+Binding ::= 
+           VarBinding(var: Var|DataflowVar, value: Expr)
+         | MatchCast(var: (Var|DataflowVar)?, struct_info: StructInfo, value: 
Expr)
+
+# Relax programs are IRModules. Modules may bind global variables either to
+# Relax functions or TIR PrimFuncs (specified separately).
+# The Relax compiler may analyze and modify the TIR PrimFUncs as well.
+Program ::= IRModule(funcs: {GlobalVar: Function|PrimFunc})
+```
+
+### Notes on `derive_func`
+
+The `derive_func` field of `FuncStructInfo` is a macro in the meta-language: 
Given a function call and the variable mapping context, return the `StructInfo` 
of the result. This field is used only at compile time for reasoning about the 
`StructInfo` of calls to `ExternFunc`s.
+
+### Notes on `DataType` and Related Terminology
+
+The representation of datatypes, `DataType`, in the above AST is taken 
directly from TIR. However, the usage of datatypes in Relax is more restricted 
than in TIR.
+1. The `lanes` field for the `Int`, `UInt`, and `Float` datatypes must always 
be 1; we do not directly consider vectorized values in Relax.
+2. The `lanes` field for the `Handle` datatype must always be 0, indicating 
that it is `Void` (see below). The `bits` field for `Handle` should always be 
set to 64 (it will not be used by Relax).
+
+We also define the following special notation for datatypes, to be used in the 
rest of the specification:
+1. `Bool()`: This is shorthand for `UInt(bits=1, lanes=1)`, since TIR does not 
have a separate Boolean type. "True" refers to a value of 1 in this datatype 
and "false" refers to a value of 0. For convenience, we will refer to Boolean 
values as a separate datatype in the specification, due to their significance 
in `If` nodes.
+2. `Void()`: This is shorthand for `Handle(bits=64, lanes=0)`. TIR uses this 
datatype to refer to opaque objects; in Relax, it is used to denote an unknown 
datatype.
+
+## Expression Survey

Review Comment:
   No, it was a brainfart.  I was focusing on reading this section and I forgot 
what I read 10 minutes prior...  :|



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to