Specify Regions in LangRef

Region is the generalization of a function body (a list of blocks forming a CFG) to be allowed to be enclosed inside any operation. This nesting of IR is already leveraged in the affine dialect to support `affine.for`, `affine.if`, and `gpu.launch` operations.

--

PiperOrigin-RevId: 246766830
This commit is contained in:
Mehdi Amini 2019-05-05 21:43:02 -07:00 committed by Mehdi Amini
parent 3f27c60688
commit e2e89f5c83
1 changed files with 107 additions and 5 deletions

View File

@ -1223,14 +1223,15 @@ argument-list ::= type attribute-dict? (`,` type attribute-dict?)* | /*empty*/
named-argument ::= ssa-id `:` type attribute-dict?
function-attributes ::= `attributes` attribute-dict
function-body ::= `{` block+ `}`
function-body ::= region
```
An external function declaration (used when referring to a function declared in
some other module) has no body. A function definition contains a control
flow graph made up of one or more blocks. While the MLIR textual form provides a
nice inline syntax for function arguments, they are internally represented as
"block arguments" to the first block in the function.
some other module) has no body. A function definition contains a
[region](#regions) made up of one or more blocks forming the function body.
While the MLIR textual form provides a nice inline syntax for function
arguments, they are internally represented as "block arguments" to the first
block in the region.
Examples:
@ -1246,6 +1247,107 @@ func @count(%x: i64) -> (i64, i64)
}
```
## Regions
A region is a CFG of MLIR [Blocks](#blocks). Regions serve as a generalization
of a function body that can be nested under arbitrary operations. A region
semantics is defined by the containing entity (operation or function). Regions
do not have a name or an address, only the blocks contained in a region do.
The first block in the region cannot be a successor of any other block. The
arguments of this block are treated as arguments of the region. The syntax for
the region is as follows:
``` {.ebnf}
region ::= region-signature? region-body
region-signature ::= `(` argument-list `)` (`->` function-result-type)?
region-body ::= `{` block+ `}`
```
The function body is an example of a region, the body of an `affine.for`
operation is another example, this time of an single-block region.
Regions provide nested control isolation: it is impossible to branch to a block
within a region from outside it, or to branch from within a region to a block
outside it. Similarly it provides a natural scoping for value visibility: SSA
values defined in a region don't escape to the enclosing region if any. By
default, a region can referenced values defined outside of the region, whenever
it would have been legal to use them as operands to the enclosing operation.
This can be further restricted using custom verifier.
Example:
```mlir {.mlir}
func $@accelerator_compute(i64, i1) -> i64 {
^bb0(%a: i64, %cond: i1): // Code dominated by ^bb0 may refer to %a
br_cond %cond, ^bb1, ^bb2
^bb1:
// This def for %value does not dominate ^bb2
%value = "op.convert"(%a) : (i64) -> i64
br ^bb3(%a: i64) // Branch passes %a as the argument
^bb2:
"accelerator.launch"() {
^bb0:
// Region of code nested under "accelerator_launch", it can reference %a but
// not %value.
%new_value = "accelerator.do_something"(%a) : (i64) -> ()
}
// %new_value cannot be referenced outside of the region
...
}
```
Regions are Single-Entry-Multiple-Exit (SEME). It means that control can only
flow into the first block of the region, but can flow out of the region at the
end of any of the blocks it contains. (This behavior is similar to that of
functions in most programming languages). Nonetheless, when exiting the region
from any of its multiple exit points, the control flows to the same successor.
Regions present in an operation can be executed any number of times. The IR does
not guarantee if a region passed as an argument to an operation will be
executed; if so, how many times and when. In particular, a region can be
executed zero, one or multiple times, in no particular order with respect to
other regions or operations. It may be executed as a part of an operation, or by
some later operation using any values produced by the operation that contains
the region. The successor to a regions exit points may not necessarily exist:
regions enclosing non-terminating code such as infinite loops are possible, as
well as an operation implementing an infinite loop over a region. Concurrent or
asynchronous execution of regions is unspecified. Operations may define pecific
rules of execution, e.g. sequential loops or switch-like blocks.
In case of zero executions, control does not flow into the region. In case of
multiple executions, the control may exit the region from any of the region exit
points and enter it again at its entry point. It may also enter another region.
If an operation has multiple region arguments, the semantics of the operation
defines into which regions the control flows and in which order, if any. An
operation may trigger execution of regions that were specified in other
operations, in particular those that defined the values the given operation
uses. When all argument regions were executed the number of times required by
the operation semantics, the control flows from any of the region exit points to
the original control-successor of the operation that triggered the execution.
Thus operations with region arguments can be treated opaquely in the enclosing
control flow graph, providing a level of control flow isolation similar to that
of the call operation.
Regions allow to define an operation that creates a closure, for example by
“boxing” the body of the region into a value they produce. It remains up to the
operation to define its semantics. In this situation, the value “containing” the
region may be passed to or returned from a function/region, at which point the
values defined in dominating blocks are no longer accessible. If this region
directly uses such values, passing a value “containing” it across function
boundaries or using it in operations leads to undefined behavior. This is
similar to returning a lambda capturing a reference to a local variable in C++.
Note that if an operation triggers asynchronous execution of the region, it is
under the responsibility of the operation caller to wait for the region to be
executed guaranteeing that any directly used values remain live.
Regions produce a (possibly empty) list of values. For function body regions,
`return` is the standard region-exiting terminator, but dialects can provide
their own. For regions passed as operation arguments, the operation semantics
defines the relation between the region results and the operation results.
## Blocks
Syntax: