[mlir][bufferization] Remove buffer-deallocation pass (#126366)

The `-buffer-deallocation` pass is not compatible with One-Shot
Bufferize and has been replaced with the Ownership-based Buffer
Deallocation pass about 1.5 years ago. To clean up the code base, this
commit removes the deprecated `buffer-deallocation` pass. All uses of
this deprecated pass within MLIR have already been migrated.

Note for LLVM integration: If you depend on this pass, migrate to the
Ownership-based Buffer Deallocation pass or copy the pass to your
codebase. For details, see
https://discourse.llvm.org/t/psa-bufferization-new-buffer-deallocation-pipeline/73375.
This commit is contained in:
Matthias Springer 2025-02-13 09:49:16 +01:00 committed by GitHub
parent 9b2fc66830
commit 213917be82
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 6 additions and 5687 deletions

View File

@ -1,705 +0,0 @@
# Buffer Deallocation - Internals
**Note:** This pass is deprecated. Please use the ownership-based buffer
deallocation pass instead.
This section covers the internal functionality of the BufferDeallocation
transformation. The transformation consists of several passes. The main pass
called BufferDeallocation can be applied via “-buffer-deallocation” on MLIR
programs.
[TOC]
## Requirements
In order to use BufferDeallocation on an arbitrary dialect, several control-flow
interfaces have to be implemented when using custom operations. This is
particularly important to understand the implicit control-flow dependencies
between different parts of the input program. Without implementing the following
interfaces, control-flow relations cannot be discovered properly and the
resulting program can become invalid:
* Branch-like terminators should implement the `BranchOpInterface` to query
and manipulate associated operands.
* Operations involving structured control flow have to implement the
`RegionBranchOpInterface` to model inter-region control flow.
* Terminators yielding values to their parent operation (in particular in the
scope of nested regions within `RegionBranchOpInterface`-based operations),
should implement the `ReturnLike` trait to represent logical “value
returns”.
Example dialects that are fully compatible are the “std” and “scf” dialects with
respect to all implemented interfaces.
During Bufferization, we convert immutable value types (tensors) to mutable
types (memref). This conversion is done in several steps and in all of these
steps the IR has to fulfill SSA like properties. The usage of memref has to be
in the following consecutive order: allocation, write-buffer, read- buffer. In
this case, there are only buffer reads allowed after the initial full buffer
write is done. In particular, there must be no partial write to a buffer after
the initial write has been finished. However, partial writes in the initializing
is allowed (fill buffer step by step in a loop e.g.). This means, all buffer
writes needs to dominate all buffer reads.
Example for breaking the invariant:
```mlir
func.func @condBranch(%arg0: i1, %arg1: memref<2xf32>) {
%0 = memref.alloc() : memref<2xf32>
cf.cond_br %arg0, ^bb1, ^bb2
^bb1:
cf.br ^bb3()
^bb2:
partial_write(%0, %0)
cf.br ^bb3()
^bb3():
test.copy(%0, %arg1) : (memref<2xf32>, memref<2xf32>) -> ()
return
}
```
The maintenance of the SSA like properties is only needed in the bufferization
process. Afterwards, for example in optimization processes, the property is no
longer needed.
## Detection of Buffer Allocations
The first step of the BufferDeallocation transformation is to identify
manageable allocation operations that implement the `SideEffects` interface.
Furthermore, these ops need to apply the effect `MemoryEffects::Allocate` to a
particular result value while not using the resource
`SideEffects::AutomaticAllocationScopeResource` (since it is currently reserved
for allocations, like `Alloca` that will be automatically deallocated by a
parent scope). Allocations that have not been detected in this phase will not be
tracked internally, and thus, not deallocated automatically. However,
BufferDeallocation is fully compatible with “hybrid” setups in which tracked and
untracked allocations are mixed:
```mlir
func.func @mixedAllocation(%arg0: i1) {
%0 = memref.alloca() : memref<2xf32> // aliases: %2
%1 = memref.alloc() : memref<2xf32> // aliases: %2
cf.cond_br %arg0, ^bb1, ^bb2
^bb1:
use(%0)
cf.br ^bb3(%0 : memref<2xf32>)
^bb2:
use(%1)
cf.br ^bb3(%1 : memref<2xf32>)
^bb3(%2: memref<2xf32>):
...
}
```
Example of using a conditional branch with alloc and alloca. BufferDeallocation
can detect and handle the different allocation types that might be intermixed.
Note: the current version does not support allocation operations returning
multiple result buffers.
## Conversion from AllocOp to AllocaOp
The PromoteBuffersToStack-pass converts AllocOps to AllocaOps, if possible. In
some cases, it can be useful to use such stack-based buffers instead of
heap-based buffers. The conversion is restricted to several constraints like:
* Control flow
* Buffer Size
* Dynamic Size
If a buffer is leaving a block, we are not allowed to convert it into an alloca.
If the size of the buffer is large, we could convert it, but regarding stack
overflow, it makes sense to limit the size of these buffers and only convert
small ones. The size can be set via a pass option. The current default value is
1KB. Furthermore, we can not convert buffers with dynamic size, since the
dimension is not known a priori.
## Movement and Placement of Allocations
Using the buffer hoisting pass, all buffer allocations are moved as far upwards
as possible in order to group them and make upcoming optimizations easier by
limiting the search space. Such a movement is shown in the following graphs. In
addition, we are able to statically free an alloc, if we move it into a
dominator of all of its uses. This simplifies further optimizations (e.g. buffer
fusion) in the future. However, movement of allocations is limited by external
data dependencies (in particular in the case of allocations of dynamically
shaped types). Furthermore, allocations can be moved out of nested regions, if
necessary. In order to move allocations to valid locations with respect to their
uses only, we leverage Liveness information.
The following code snippets shows a conditional branch before running the
BufferHoisting pass:
![branch_example_pre_move](/includes/img/branch_example_pre_move.svg)
```mlir
func.func @condBranch(%arg0: i1, %arg1: memref<2xf32>, %arg2: memref<2xf32>) {
cf.cond_br %arg0, ^bb1, ^bb2
^bb1:
cf.br ^bb3(%arg1 : memref<2xf32>)
^bb2:
%0 = memref.alloc() : memref<2xf32> // aliases: %1
use(%0)
cf.br ^bb3(%0 : memref<2xf32>)
^bb3(%1: memref<2xf32>): // %1 could be %0 or %arg1
test.copy(%1, %arg2) : (memref<2xf32>, memref<2xf32>) -> ()
return
}
```
Applying the BufferHoisting pass on this program results in the following piece
of code:
![branch_example_post_move](/includes/img/branch_example_post_move.svg)
```mlir
func.func @condBranch(%arg0: i1, %arg1: memref<2xf32>, %arg2: memref<2xf32>) {
%0 = memref.alloc() : memref<2xf32> // moved to bb0
cf.cond_br %arg0, ^bb1, ^bb2
^bb1:
cf.br ^bb3(%arg1 : memref<2xf32>)
^bb2:
use(%0)
cf.br ^bb3(%0 : memref<2xf32>)
^bb3(%1: memref<2xf32>):
test.copy(%1, %arg2) : (memref<2xf32>, memref<2xf32>) -> ()
return
}
```
The alloc is moved from bb2 to the beginning and it is passed as an argument to
bb3.
The following example demonstrates an allocation using dynamically shaped types.
Due to the data dependency of the allocation to %0, we cannot move the
allocation out of bb2 in this case:
```mlir
func.func @condBranchDynamicType(
%arg0: i1,
%arg1: memref<?xf32>,
%arg2: memref<?xf32>,
%arg3: index) {
cf.cond_br %arg0, ^bb1, ^bb2(%arg3: index)
^bb1:
cf.br ^bb3(%arg1 : memref<?xf32>)
^bb2(%0: index):
%1 = memref.alloc(%0) : memref<?xf32> // cannot be moved upwards to the data
// dependency to %0
use(%1)
cf.br ^bb3(%1 : memref<?xf32>)
^bb3(%2: memref<?xf32>):
test.copy(%2, %arg2) : (memref<?xf32>, memref<?xf32>) -> ()
return
}
```
## Introduction of Clones
In order to guarantee that all allocated buffers are freed properly, we have to
pay attention to the control flow and all potential aliases a buffer allocation
can have. Since not all allocations can be safely freed with respect to their
aliases (see the following code snippet), it is often required to introduce
copies to eliminate them. Consider the following example in which the
allocations have already been placed:
```mlir
func.func @branch(%arg0: i1) {
%0 = memref.alloc() : memref<2xf32> // aliases: %2
cf.cond_br %arg0, ^bb1, ^bb2
^bb1:
%1 = memref.alloc() : memref<2xf32> // resides here for demonstration purposes
// aliases: %2
cf.br ^bb3(%1 : memref<2xf32>)
^bb2:
use(%0)
cf.br ^bb3(%0 : memref<2xf32>)
^bb3(%2: memref<2xf32>):
return
}
```
The first alloc can be safely freed after the live range of its post-dominator
block (bb3). The alloc in bb1 has an alias %2 in bb3 that also keeps this buffer
alive until the end of bb3. Since we cannot determine the actual branches that
will be taken at runtime, we have to ensure that all buffers are freed correctly
in bb3 regardless of the branches we will take to reach the exit block. This
makes it necessary to introduce a copy for %2, which allows us to free %alloc0
in bb0 and %alloc1 in bb1. Afterwards, we can continue processing all aliases of
%2 (none in this case) and we can safely free %2 at the end of the sample
program. This sample demonstrates that not all allocations can be safely freed
in their associated post-dominator blocks. Instead, we have to pay attention to
all of their aliases.
Applying the BufferDeallocation pass to the program above yields the following
result:
```mlir
func.func @branch(%arg0: i1) {
%0 = memref.alloc() : memref<2xf32>
cf.cond_br %arg0, ^bb1, ^bb2
^bb1:
%1 = memref.alloc() : memref<2xf32>
%3 = bufferization.clone %1 : (memref<2xf32>) -> (memref<2xf32>)
memref.dealloc %1 : memref<2xf32> // %1 can be safely freed here
cf.br ^bb3(%3 : memref<2xf32>)
^bb2:
use(%0)
%4 = bufferization.clone %0 : (memref<2xf32>) -> (memref<2xf32>)
cf.br ^bb3(%4 : memref<2xf32>)
^bb3(%2: memref<2xf32>):
memref.dealloc %2 : memref<2xf32> // free temp buffer %2
memref.dealloc %0 : memref<2xf32> // %0 can be safely freed here
return
}
```
Note that a temporary buffer for %2 was introduced to free all allocations
properly. Note further that the unnecessary allocation of %3 can be easily
removed using one of the post-pass transformations or the canonicalization pass.
The presented example also works with dynamically shaped types.
BufferDeallocation performs a fix-point iteration taking all aliases of all
tracked allocations into account. We initialize the general iteration process
using all tracked allocations and their associated aliases. As soon as we
encounter an alias that is not properly dominated by our allocation, we mark
this alias as *critical* (needs to be freed and tracked by the internal
fix-point iteration). The following sample demonstrates the presence of critical
and non-critical aliases:
![nested_branch_example_pre_move](/includes/img/nested_branch_example_pre_move.svg)
```mlir
func.func @condBranchDynamicTypeNested(
%arg0: i1,
%arg1: memref<?xf32>, // aliases: %3, %4
%arg2: memref<?xf32>,
%arg3: index) {
cf.cond_br %arg0, ^bb1, ^bb2(%arg3: index)
^bb1:
cf.br ^bb6(%arg1 : memref<?xf32>)
^bb2(%0: index):
%1 = memref.alloc(%0) : memref<?xf32> // cannot be moved upwards due to the data
// dependency to %0
// aliases: %2, %3, %4
use(%1)
cf.cond_br %arg0, ^bb3, ^bb4
^bb3:
cf.br ^bb5(%1 : memref<?xf32>)
^bb4:
cf.br ^bb5(%1 : memref<?xf32>)
^bb5(%2: memref<?xf32>): // non-crit. alias of %1, since %1 dominates %2
cf.br ^bb6(%2 : memref<?xf32>)
^bb6(%3: memref<?xf32>): // crit. alias of %arg1 and %2 (in other words %1)
cf.br ^bb7(%3 : memref<?xf32>)
^bb7(%4: memref<?xf32>): // non-crit. alias of %3, since %3 dominates %4
test.copy(%4, %arg2) : (memref<?xf32>, memref<?xf32>) -> ()
return
}
```
Applying BufferDeallocation yields the following output:
![nested_branch_example_post_move](/includes/img/nested_branch_example_post_move.svg)
```mlir
func.func @condBranchDynamicTypeNested(
%arg0: i1,
%arg1: memref<?xf32>,
%arg2: memref<?xf32>,
%arg3: index) {
cf.cond_br %arg0, ^bb1, ^bb2(%arg3 : index)
^bb1:
// temp buffer required due to alias %3
%5 = bufferization.clone %arg1 : (memref<?xf32>) -> (memref<?xf32>)
cf.br ^bb6(%5 : memref<?xf32>)
^bb2(%0: index):
%1 = memref.alloc(%0) : memref<?xf32>
use(%1)
cf.cond_br %arg0, ^bb3, ^bb4
^bb3:
cf.br ^bb5(%1 : memref<?xf32>)
^bb4:
cf.br ^bb5(%1 : memref<?xf32>)
^bb5(%2: memref<?xf32>):
%6 = bufferization.clone %1 : (memref<?xf32>) -> (memref<?xf32>)
memref.dealloc %1 : memref<?xf32>
cf.br ^bb6(%6 : memref<?xf32>)
^bb6(%3: memref<?xf32>):
cf.br ^bb7(%3 : memref<?xf32>)
^bb7(%4: memref<?xf32>):
test.copy(%4, %arg2) : (memref<?xf32>, memref<?xf32>) -> ()
memref.dealloc %3 : memref<?xf32> // free %3, since %4 is a non-crit. alias of %3
return
}
```
Since %3 is a critical alias, BufferDeallocation introduces an additional
temporary copy in all predecessor blocks. %3 has an additional (non-critical)
alias %4 that extends the live range until the end of bb7. Therefore, we can
free %3 after its last use, while taking all aliases into account. Note that %4
does not need to be freed, since we did not introduce a copy for it.
The actual introduction of buffer copies is done after the fix-point iteration
has been terminated and all critical aliases have been detected. A critical
alias can be either a block argument or another value that is returned by an
operation. Copies for block arguments are handled by analyzing all predecessor
blocks. This is primarily done by querying the `BranchOpInterface` of the
associated branch terminators that can jump to the current block. Consider the
following example which involves a simple branch and the critical block argument
%2:
```mlir
custom.br ^bb1(..., %0, : ...)
...
custom.br ^bb1(..., %1, : ...)
...
^bb1(%2: memref<2xf32>):
...
```
The `BranchOpInterface` allows us to determine the actual values that will be
passed to block bb1 and its argument %2 by analyzing its predecessor blocks.
Once we have resolved the values %0 and %1 (that are associated with %2 in this
sample), we can introduce a temporary buffer and clone its contents into the new
buffer. Afterwards, we rewire the branch operands to use the newly allocated
buffer instead. However, blocks can have implicitly defined predecessors by
parent ops that implement the `RegionBranchOpInterface`. This can be the case if
this block argument belongs to the entry block of a region. In this setting, we
have to identify all predecessor regions defined by the parent operation. For
every region, we need to get all terminator operations implementing the
`ReturnLike` trait, indicating that they can branch to our current block.
Finally, we can use a similar functionality as described above to add the
temporary copy. This time, we can modify the terminator operands directly
without touching a high-level interface.
Consider the following inner-region control-flow sample that uses an imaginary
“custom.region_if” operation. It either executes the “then” or “else” region and
always continues to the “join” region. The “custom.region_if_yield” operation
returns a result to the parent operation. This sample demonstrates the use of
the `RegionBranchOpInterface` to determine predecessors in order to infer the
high-level control flow:
```mlir
func.func @inner_region_control_flow(
%arg0 : index,
%arg1 : index) -> memref<?x?xf32> {
%0 = memref.alloc(%arg0, %arg0) : memref<?x?xf32>
%1 = custom.region_if %0 : memref<?x?xf32> -> (memref<?x?xf32>)
then(%arg2 : memref<?x?xf32>) { // aliases: %arg4, %1
custom.region_if_yield %arg2 : memref<?x?xf32>
} else(%arg3 : memref<?x?xf32>) { // aliases: %arg4, %1
custom.region_if_yield %arg3 : memref<?x?xf32>
} join(%arg4 : memref<?x?xf32>) { // aliases: %1
custom.region_if_yield %arg4 : memref<?x?xf32>
}
return %1 : memref<?x?xf32>
}
```
![region_branch_example_pre_move](/includes/img/region_branch_example_pre_move.svg)
Non-block arguments (other values) can become aliases when they are returned by
dialect-specific operations. BufferDeallocation supports this behavior via the
`RegionBranchOpInterface`. Consider the following example that uses an “scf.if”
operation to determine the value of %2 at runtime which creates an alias:
```mlir
func.func @nested_region_control_flow(%arg0 : index, %arg1 : index) -> memref<?x?xf32> {
%0 = arith.cmpi "eq", %arg0, %arg1 : index
%1 = memref.alloc(%arg0, %arg0) : memref<?x?xf32>
%2 = scf.if %0 -> (memref<?x?xf32>) {
scf.yield %1 : memref<?x?xf32> // %2 will be an alias of %1
} else {
%3 = memref.alloc(%arg0, %arg1) : memref<?x?xf32> // nested allocation in a div.
// branch
use(%3)
scf.yield %1 : memref<?x?xf32> // %2 will be an alias of %1
}
return %2 : memref<?x?xf32>
}
```
In this example, a dealloc is inserted to release the buffer within the else
block since it cannot be accessed by the remainder of the program. Accessing the
`RegionBranchOpInterface`, allows us to infer that %2 is a non-critical alias of
%1 which does not need to be tracked.
```mlir
func.func @nested_region_control_flow(%arg0: index, %arg1: index) -> memref<?x?xf32> {
%0 = arith.cmpi "eq", %arg0, %arg1 : index
%1 = memref.alloc(%arg0, %arg0) : memref<?x?xf32>
%2 = scf.if %0 -> (memref<?x?xf32>) {
scf.yield %1 : memref<?x?xf32>
} else {
%3 = memref.alloc(%arg0, %arg1) : memref<?x?xf32>
use(%3)
memref.dealloc %3 : memref<?x?xf32> // %3 can be safely freed here
scf.yield %1 : memref<?x?xf32>
}
return %2 : memref<?x?xf32>
}
```
Analogous to the previous case, we have to detect all terminator operations in
all attached regions of “scf.if” that provides a value to its parent operation
(in this sample via scf.yield). Querying the `RegionBranchOpInterface` allows us
to determine the regions that “return” a result to their parent operation. Like
before, we have to update all `ReturnLike` terminators as described above.
Reconsider a slightly adapted version of the “custom.region_if” example from
above that uses a nested allocation:
```mlir
func.func @inner_region_control_flow_div(
%arg0 : index,
%arg1 : index) -> memref<?x?xf32> {
%0 = memref.alloc(%arg0, %arg0) : memref<?x?xf32>
%1 = custom.region_if %0 : memref<?x?xf32> -> (memref<?x?xf32>)
then(%arg2 : memref<?x?xf32>) { // aliases: %arg4, %1
custom.region_if_yield %arg2 : memref<?x?xf32>
} else(%arg3 : memref<?x?xf32>) {
%2 = memref.alloc(%arg0, %arg1) : memref<?x?xf32> // aliases: %arg4, %1
custom.region_if_yield %2 : memref<?x?xf32>
} join(%arg4 : memref<?x?xf32>) { // aliases: %1
custom.region_if_yield %arg4 : memref<?x?xf32>
}
return %1 : memref<?x?xf32>
}
```
Since the allocation %2 happens in a divergent branch and cannot be safely
deallocated in a post-dominator, %arg4 will be considered a critical alias.
Furthermore, %arg4 is returned to its parent operation and has an alias %1. This
causes BufferDeallocation to introduce additional copies:
```mlir
func.func @inner_region_control_flow_div(
%arg0 : index,
%arg1 : index) -> memref<?x?xf32> {
%0 = memref.alloc(%arg0, %arg0) : memref<?x?xf32>
%1 = custom.region_if %0 : memref<?x?xf32> -> (memref<?x?xf32>)
then(%arg2 : memref<?x?xf32>) {
%4 = bufferization.clone %arg2 : (memref<?x?xf32>) -> (memref<?x?xf32>)
custom.region_if_yield %4 : memref<?x?xf32>
} else(%arg3 : memref<?x?xf32>) {
%2 = memref.alloc(%arg0, %arg1) : memref<?x?xf32>
%5 = bufferization.clone %2 : (memref<?x?xf32>) -> (memref<?x?xf32>)
memref.dealloc %2 : memref<?x?xf32>
custom.region_if_yield %5 : memref<?x?xf32>
} join(%arg4: memref<?x?xf32>) {
%4 = bufferization.clone %arg4 : (memref<?x?xf32>) -> (memref<?x?xf32>)
memref.dealloc %arg4 : memref<?x?xf32>
custom.region_if_yield %4 : memref<?x?xf32>
}
memref.dealloc %0 : memref<?x?xf32> // %0 can be safely freed here
return %1 : memref<?x?xf32>
}
```
## Placement of Deallocs
After introducing allocs and copies, deallocs have to be placed to free
allocated memory and avoid memory leaks. The deallocation needs to take place
after the last use of the given value. The position can be determined by
calculating the common post-dominator of all values using their remaining
non-critical aliases. A special-case is the presence of back edges: since such
edges can cause memory leaks when a newly allocated buffer flows back to another
part of the program. In these cases, we need to free the associated buffer
instances from the previous iteration by inserting additional deallocs.
Consider the following “scf.for” use case containing a nested structured
control-flow if:
```mlir
func.func @loop_nested_if(
%lb: index,
%ub: index,
%step: index,
%buf: memref<2xf32>,
%res: memref<2xf32>) {
%0 = scf.for %i = %lb to %ub step %step
iter_args(%iterBuf = %buf) -> memref<2xf32> {
%1 = arith.cmpi "eq", %i, %ub : index
%2 = scf.if %1 -> (memref<2xf32>) {
%3 = memref.alloc() : memref<2xf32> // makes %2 a critical alias due to a
// divergent allocation
use(%3)
scf.yield %3 : memref<2xf32>
} else {
scf.yield %iterBuf : memref<2xf32>
}
scf.yield %2 : memref<2xf32>
}
test.copy(%0, %res) : (memref<2xf32>, memref<2xf32>) -> ()
return
}
```
In this example, the *then* branch of the nested “scf.if” operation returns a
newly allocated buffer.
Since this allocation happens in the scope of a divergent branch, %2 becomes a
critical alias that needs to be handled. As before, we have to insert additional
copies to eliminate this alias using copies of %3 and %iterBuf. This guarantees
that %2 will be a newly allocated buffer that is returned in each iteration.
However, “returning” %2 to its alias %iterBuf turns %iterBuf into a critical
alias as well. In other words, we have to create a copy of %2 to pass it to
%iterBuf. Since this jump represents a back edge, and %2 will always be a new
buffer, we have to free the buffer from the previous iteration to avoid memory
leaks:
```mlir
func.func @loop_nested_if(
%lb: index,
%ub: index,
%step: index,
%buf: memref<2xf32>,
%res: memref<2xf32>) {
%4 = bufferization.clone %buf : (memref<2xf32>) -> (memref<2xf32>)
%0 = scf.for %i = %lb to %ub step %step
iter_args(%iterBuf = %4) -> memref<2xf32> {
%1 = arith.cmpi "eq", %i, %ub : index
%2 = scf.if %1 -> (memref<2xf32>) {
%3 = memref.alloc() : memref<2xf32> // makes %2 a critical alias
use(%3)
%5 = bufferization.clone %3 : (memref<2xf32>) -> (memref<2xf32>)
memref.dealloc %3 : memref<2xf32>
scf.yield %5 : memref<2xf32>
} else {
%6 = bufferization.clone %iterBuf : (memref<2xf32>) -> (memref<2xf32>)
scf.yield %6 : memref<2xf32>
}
%7 = bufferization.clone %2 : (memref<2xf32>) -> (memref<2xf32>)
memref.dealloc %2 : memref<2xf32>
memref.dealloc %iterBuf : memref<2xf32> // free backedge iteration variable
scf.yield %7 : memref<2xf32>
}
test.copy(%0, %res) : (memref<2xf32>, memref<2xf32>) -> ()
memref.dealloc %0 : memref<2xf32> // free temp copy %0
return
}
```
Example for loop-like control flow. The CFG contains back edges that have to be
handled to avoid memory leaks. The bufferization is able to free the backedge
iteration variable %iterBuf.
## Private Analyses Implementations
The BufferDeallocation transformation relies on one primary control-flow
analysis: BufferPlacementAliasAnalysis. Furthermore, we also use dominance and
liveness to place and move nodes. The liveness analysis determines the live
range of a given value. Within this range, a value is alive and can or will be
used in the course of the program. After this range, the value is dead and can
be discarded - in our case, the buffer can be freed. To place the allocs, we
need to know from which position a value will be alive. The allocs have to be
placed in front of this position. However, the most important analysis is the
alias analysis that is needed to introduce copies and to place all
deallocations.
# Post Phase
In order to limit the complexity of the BufferDeallocation transformation, some
tiny code-polishing/optimization transformations are not applied on-the-fly
during placement. Currently, a canonicalization pattern is added to the clone
operation to reduce the appearance of unnecessary clones.
Note: further transformations might be added to the post-pass phase in the
future.
## Clone Canonicalization
During placement of clones it may happen, that unnecessary clones are inserted.
If these clones appear with their corresponding dealloc operation within the
same block, we can use the canonicalizer to remove these unnecessary operations.
Note, that this step needs to take place after the insertion of clones and
deallocs in the buffer deallocation step. The canonicalization inludes both, the
newly created target value from the clone operation and the source operation.
## Canonicalization of the Source Buffer of the Clone Operation
In this case, the source of the clone operation can be used instead of its
target. The unused allocation and deallocation operations that are defined for
this clone operation are also removed. Here is a working example generated by
the BufferDeallocation pass that allocates a buffer with dynamic size. A deeper
analysis of this sample reveals that the highlighted operations are redundant
and can be removed.
```mlir
func.func @dynamic_allocation(%arg0: index, %arg1: index) -> memref<?x?xf32> {
%1 = memref.alloc(%arg0, %arg1) : memref<?x?xf32>
%2 = bufferization.clone %1 : (memref<?x?xf32>) -> (memref<?x?xf32>)
memref.dealloc %1 : memref<?x?xf32>
return %2 : memref<?x?xf32>
}
```
Will be transformed to:
```mlir
func.func @dynamic_allocation(%arg0: index, %arg1: index) -> memref<?x?xf32> {
%1 = memref.alloc(%arg0, %arg1) : memref<?x?xf32>
return %1 : memref<?x?xf32>
}
```
In this case, the additional copy %2 can be replaced with its original source
buffer %1. This also applies to the associated dealloc operation of %1.
## Canonicalization of the Target Buffer of the Clone Operation
In this case, the target buffer of the clone operation can be used instead of
its source. The unused deallocation operation that is defined for this clone
operation is also removed.
Consider the following example where a generic test operation writes the result
to %temp and then copies %temp to %result. However, these two operations can be
merged into a single step. Canonicalization removes the clone operation and
%temp, and replaces the uses of %temp with %result:
```mlir
func.func @reuseTarget(%arg0: memref<2xf32>, %result: memref<2xf32>){
%temp = memref.alloc() : memref<2xf32>
test.generic {
args_in = 1 : i64,
args_out = 1 : i64,
indexing_maps = [#map0, #map0],
iterator_types = ["parallel"]} %arg0, %temp {
^bb0(%gen2_arg0: f32, %gen2_arg1: f32):
%tmp2 = math.exp %gen2_arg0 : f32
test.yield %tmp2 : f32
}: memref<2xf32>, memref<2xf32>
%result = bufferization.clone %temp : (memref<2xf32>) -> (memref<2xf32>)
memref.dealloc %temp : memref<2xf32>
return
}
```
Will be transformed to:
```mlir
func.func @reuseTarget(%arg0: memref<2xf32>, %result: memref<2xf32>){
test.generic {
args_in = 1 : i64,
args_out = 1 : i64,
indexing_maps = [#map0, #map0],
iterator_types = ["parallel"]} %arg0, %result {
^bb0(%gen2_arg0: f32, %gen2_arg1: f32):
%tmp2 = math.exp %gen2_arg0 : f32
test.yield %tmp2 : f32
}: memref<2xf32>, memref<2xf32>
return
}
```
## Known Limitations
BufferDeallocation introduces additional clones from “memref” dialect
(“bufferization.clone”). Analogous, all deallocations use the “memref”
dialect-free operation “memref.dealloc”. The actual copy process is realized
using “test.copy”. Furthermore, buffers are essentially immutable after their
creation in a block. Another limitations are known in the case using
unstructered control flow.

View File

@ -5,9 +5,7 @@
One-Shot Bufferize does not deallocate any buffers that it allocates. After
running One-Shot Bufferize, the resulting IR may have a number of `memref.alloc`
ops, but no `memref.dealloc` ops. Buffer dellocation is delegated to the
`-ownership-based-buffer-deallocation` pass. This pass supersedes the now
deprecated `-buffer-deallocation` pass, which does not work well with
One-Shot Bufferize.
`-ownership-based-buffer-deallocation` pass.
On a high level, buffers are "owned" by a basic block. Ownership materializes
as an `i1` SSA value and can be thought of as "responsibility to deallocate". It

View File

@ -1,419 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="199.99995mm"
height="173.75687mm"
viewBox="0 0 199.99995 173.75687"
version="1.1"
id="svg8"
inkscape:version="1.0.1 (c497b03c, 2020-09-10)"
sodipodi:docname="branch_hoisting_after.svg">
<defs
id="defs2">
<rect
x="18.139799"
y="132.9565"
width="42.875893"
height="13.192582"
id="rect1896" />
<rect
x="73.476562"
y="69.033791"
width="111.61496"
height="41.205557"
id="rect1370" />
<rect
x="88.85537"
y="63.907516"
width="32.124634"
height="21.53034"
id="rect3730" />
<rect
x="9.5690403"
y="9.2272892"
width="20.163336"
height="14.011809"
id="rect3679" />
<rect
x="41.227337"
y="-14.998642"
width="72.234138"
height="11.239376"
id="rect3669" />
<marker
style="overflow:visible"
id="marker3503"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow1Lend"
inkscape:isstock="true">
<path
transform="matrix(-0.8,0,0,-0.8,-10,0)"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
id="path3501" />
</marker>
<marker
style="overflow:visible"
id="marker3443"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow1Lend"
inkscape:isstock="true"
inkscape:collect="always">
<path
transform="matrix(-0.8,0,0,-0.8,-10,0)"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
id="path3441" />
</marker>
<marker
style="overflow:visible"
id="marker3389"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow1Lend"
inkscape:isstock="true"
inkscape:collect="always">
<path
transform="matrix(-0.8,0,0,-0.8,-10,0)"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
id="path3387" />
</marker>
<marker
style="overflow:visible"
id="marker3341"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow1Lend"
inkscape:isstock="true"
inkscape:collect="always">
<path
transform="matrix(-0.8,0,0,-0.8,-10,0)"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
id="path3339" />
</marker>
<marker
style="overflow:visible"
id="marker3141"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow1Lend"
inkscape:isstock="true"
inkscape:collect="always">
<path
transform="matrix(-0.8,0,0,-0.8,-10,0)"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
id="path3139" />
</marker>
<marker
style="overflow:visible"
id="marker2967"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow1Lstart"
inkscape:isstock="true">
<path
transform="matrix(0.8,0,0,0.8,10,0)"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
id="path2965" />
</marker>
<marker
style="overflow:visible"
id="Arrow1Send"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow1Send"
inkscape:isstock="true">
<path
transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
id="path2664" />
</marker>
<marker
style="overflow:visible"
id="Arrow1Lstart"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow1Lstart"
inkscape:isstock="true">
<path
transform="matrix(0.8,0,0,0.8,10,0)"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
id="path2649" />
</marker>
<rect
x="9.5690403"
y="9.2272892"
width="20.163336"
height="14.011809"
id="rect3679-2" />
<rect
x="9.5690403"
y="9.2272892"
width="20.163336"
height="14.011809"
id="rect3692" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="1.2592908"
inkscape:cx="377.95267"
inkscape:cy="328.35943"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
inkscape:document-rotation="0"
showgrid="false"
inkscape:window-width="1680"
inkscape:window-height="963"
inkscape:window-x="0"
inkscape:window-y="93"
inkscape:window-maximized="1"
showguides="true"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
lock-margins="false" />
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Ebene 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(60.000002,15.000516)"
style="display:inline">
<rect
style="opacity:1;fill:#cfe2f3;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.258106;stroke-opacity:1"
id="rect837"
width="79.741898"
height="38.498253"
x="0.12905283"
y="0.129053"
ry="6.741148" />
<rect
style="opacity:1;fill:#cfe2f3;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.258106;stroke-opacity:1"
id="rect837-9"
width="79.741898"
height="38.498253"
x="-59.870949"
y="60.129051"
ry="6.741148" />
<rect
style="opacity:1;fill:#cfe2f3;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.258;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect837-9-8"
width="79.741898"
height="38.498253"
x="60.129051"
y="60.129051"
ry="6.741148" />
<rect
style="opacity:1;fill:#cfe2f3;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.258106;stroke-opacity:1"
id="rect837-9-8-9"
width="79.741898"
height="38.498253"
x="0.12905283"
y="120.12905"
ry="6.741148" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker-end:url(#marker3141);paint-order:normal"
d="M 59.249128,38.627306 80.750874,60.129051"
id="path3329"
inkscape:connector-type="polyline"
inkscape:connector-curvature="0"
inkscape:connection-start="#rect837"
inkscape:connection-end="#rect837-9-8" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker3341)"
d="M 20.750874,38.627306 -0.75087247,60.129051"
id="path3337"
inkscape:connector-type="polyline"
inkscape:connector-curvature="0"
inkscape:connection-start="#rect837"
inkscape:connection-end="#rect837-9" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker3389)"
d="M -0.75087304,98.627304 20.750875,120.12905"
id="path3385"
inkscape:connector-type="polyline"
inkscape:connector-curvature="0"
inkscape:connection-start="#rect837-9"
inkscape:connection-end="#rect837-9-8-9" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker3443)"
d="M 80.750874,98.627304 59.249128,120.12905"
id="path3439"
inkscape:connector-type="polyline"
inkscape:connector-curvature="0"
inkscape:connection-start="#rect837-9-8"
inkscape:connection-end="#rect837-9-8-9" />
<path
style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker3503)"
d="M 41.227338,-14.998642 41.386551,0.50922611"
id="path3499"
inkscape:connector-type="polyline"
inkscape:connector-curvature="0" />
<text
xml:space="preserve"
id="text3667"
style="font-style:normal;font-weight:normal;font-size:10.58329999999999949px;line-height:1.25;font-family:sans-serif;white-space:pre;shape-inside:url(#rect3669);fill:#000000;fill-opacity:1;stroke:none;" />
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:5.64444px;line-height:1.25;font-family:sans-serif;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.265;stroke-miterlimit:4;stroke-dasharray:none"
x="44.769436"
y="-7.8602829"
id="text3675"><tspan
sodipodi:role="line"
id="tspan3673"
x="44.769436"
y="-7.8602829"
style="font-size:5.64444px;stroke-width:0.265;stroke-miterlimit:4;stroke-dasharray:none">in: %arg0, %arg1, %arg2</tspan></text>
<text
xml:space="preserve"
id="text3677"
style="font-style:normal;font-weight:normal;font-size:5.64444000000000035px;line-height:1.25;font-family:sans-serif;white-space:pre;shape-inside:url(#rect3679);fill:#000000;fill-opacity:1;stroke:none;"
transform="translate(25.051785,-8.0877048)"><tspan
x="9.5683594"
y="14.376156"><tspan
style="font-size:5.64444px">bb0</tspan></tspan></text>
<text
xml:space="preserve"
id="text3728"
style="font-style:normal;font-weight:normal;font-size:10.58329999999999949px;line-height:1.25;font-family:sans-serif;white-space:pre;shape-inside:url(#rect3730);fill:#000000;fill-opacity:1;stroke:none;" />
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:5.64444px;line-height:1.25;font-family:sans-serif;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583"
x="94.617386"
y="66.288452"
id="text3736"><tspan
sodipodi:role="line"
id="tspan3734"
x="94.617386"
y="66.288452"
style="font-size:5.64444px;stroke-width:0.264583">bb2</tspan></text>
<text
xml:space="preserve"
id="text3677-0"
style="font-style:normal;font-weight:normal;font-size:5.64444000000000035px;line-height:1.25;font-family:sans-serif;white-space:pre;shape-inside:url(#rect3679-2);fill:#000000;fill-opacity:1;stroke:none;"
transform="translate(-34.833839,51.912295)"><tspan
x="9.5683594"
y="14.376156"><tspan
style="font-size:5.64444px">bb1
</tspan></tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:5.64444px;line-height:1.25;font-family:sans-serif;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583"
x="26.288532"
y="126.28845"
id="text3736-6"><tspan
sodipodi:role="line"
id="tspan3734-5"
x="26.288532"
y="126.28845"
style="font-size:5.64444px;stroke-width:0.264583">bb3 (%1)</tspan></text>
<text
xml:space="preserve"
id="text1368"
style="font-style:normal;font-weight:normal;font-size:5.64444000000000035px;line-height:1.25;font-family:sans-serif;white-space:pre;shape-inside:url(#rect1370);fill:#000000;fill-opacity:1;stroke:none;"
transform="translate(9.8574558,-6.1666356)"><tspan
x="73.476562"
y="74.182797"><tspan
style="font-size:5.64444px">
</tspan></tspan><tspan
x="73.476562"
y="81.238347"><tspan
style="font-size:5.64444px">use(%0)
</tspan></tspan><tspan
x="73.476562"
y="88.293896"><tspan
style="font-size:5.64444px">cf.br bb3(%0)</tspan></tspan></text>
<text
xml:space="preserve"
id="text1894"
style="font-style:normal;font-weight:normal;font-size:5.64444000000000035px;line-height:1.25;font-family:sans-serif;white-space:pre;shape-inside:url(#rect1896);fill:#000000;fill-opacity:1;stroke:none;" />
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:5.64444px;line-height:1.25;font-family:sans-serif;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583"
x="16.620224"
y="137.49144"
id="text1902"><tspan
sodipodi:role="line"
id="tspan1900"
x="16.620224"
y="137.49144"
style="font-size:5.64444px;stroke-width:0.264583">copy (%1, arg2)</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:5.64444px;line-height:1.25;font-family:sans-serif;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583"
x="76.269608"
y="111.63254"
id="text3165"><tspan
sodipodi:role="line"
id="tspan3163"
x="76.269608"
y="111.63254"
style="font-size:5.64444px;stroke-width:0.264583">%0</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:5.64444px;line-height:1.25;font-family:sans-serif;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583"
x="-12.065383"
y="111.08959"
id="text3165-8"><tspan
sodipodi:role="line"
id="tspan3163-3"
x="-12.065383"
y="111.08959"
style="font-size:5.64444px;stroke-width:0.264583">%arg1</tspan><tspan
sodipodi:role="line"
x="-12.065383"
y="118.14514"
style="font-size:5.64444px;stroke-width:0.264583"
id="tspan3185" /></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:5.64444px;line-height:1.25;font-family:sans-serif;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583"
x="21.911886"
y="15.884925"
id="text3409"><tspan
sodipodi:role="line"
id="tspan3407"
x="21.911886"
y="15.884925"
style="font-size:5.64444px;fill:#008000;stroke-width:0.264583">%0 = memref.alloc()</tspan></text>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 15 KiB

View File

@ -1,409 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="199.99995mm"
height="173.75687mm"
viewBox="0 0 199.99995 173.75687"
version="1.1"
id="svg8"
inkscape:version="1.0.1 (c497b03c, 2020-09-10)"
sodipodi:docname="branch_hoisting_before.svg">
<defs
id="defs2">
<rect
x="18.139799"
y="132.9565"
width="42.875893"
height="13.192582"
id="rect1896" />
<rect
x="73.476562"
y="69.033791"
width="111.61496"
height="41.205557"
id="rect1370" />
<rect
x="88.85537"
y="63.907516"
width="32.124634"
height="21.53034"
id="rect3730" />
<rect
x="9.5690403"
y="9.2272892"
width="20.163336"
height="14.011809"
id="rect3679" />
<rect
x="41.227337"
y="-14.998642"
width="72.234138"
height="11.239376"
id="rect3669" />
<marker
style="overflow:visible"
id="marker3503"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow1Lend"
inkscape:isstock="true">
<path
transform="matrix(-0.8,0,0,-0.8,-10,0)"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
id="path3501" />
</marker>
<marker
style="overflow:visible"
id="marker3443"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow1Lend"
inkscape:isstock="true"
inkscape:collect="always">
<path
transform="matrix(-0.8,0,0,-0.8,-10,0)"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
id="path3441" />
</marker>
<marker
style="overflow:visible"
id="marker3389"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow1Lend"
inkscape:isstock="true"
inkscape:collect="always">
<path
transform="matrix(-0.8,0,0,-0.8,-10,0)"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
id="path3387" />
</marker>
<marker
style="overflow:visible"
id="marker3341"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow1Lend"
inkscape:isstock="true"
inkscape:collect="always">
<path
transform="matrix(-0.8,0,0,-0.8,-10,0)"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
id="path3339" />
</marker>
<marker
style="overflow:visible"
id="marker3141"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow1Lend"
inkscape:isstock="true"
inkscape:collect="always">
<path
transform="matrix(-0.8,0,0,-0.8,-10,0)"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
id="path3139" />
</marker>
<marker
style="overflow:visible"
id="marker2967"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow1Lstart"
inkscape:isstock="true">
<path
transform="matrix(0.8,0,0,0.8,10,0)"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
id="path2965" />
</marker>
<marker
style="overflow:visible"
id="Arrow1Send"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow1Send"
inkscape:isstock="true">
<path
transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
id="path2664" />
</marker>
<marker
style="overflow:visible"
id="Arrow1Lstart"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow1Lstart"
inkscape:isstock="true">
<path
transform="matrix(0.8,0,0,0.8,10,0)"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
id="path2649" />
</marker>
<rect
x="9.5690403"
y="9.2272892"
width="20.163336"
height="14.011809"
id="rect3679-2" />
<rect
x="9.5690403"
y="9.2272892"
width="20.163336"
height="14.011809"
id="rect3692" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="1.2592908"
inkscape:cx="377.95267"
inkscape:cy="74.248148"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
inkscape:document-rotation="0"
showgrid="false"
inkscape:window-width="1680"
inkscape:window-height="963"
inkscape:window-x="0"
inkscape:window-y="93"
inkscape:window-maximized="1"
showguides="true"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
lock-margins="false" />
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Ebene 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(60.000002,15.000516)"
style="display:inline">
<rect
style="opacity:1;fill:#cfe2f3;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.258106;stroke-opacity:1"
id="rect837"
width="79.741898"
height="38.498253"
x="0.12905283"
y="0.129053"
ry="6.741148" />
<rect
style="opacity:1;fill:#cfe2f3;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.258106;stroke-opacity:1"
id="rect837-9"
width="79.741898"
height="38.498253"
x="-59.870949"
y="60.129051"
ry="6.741148" />
<rect
style="opacity:1;fill:#cfe2f3;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.258;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect837-9-8"
width="79.741898"
height="38.498253"
x="60.129051"
y="60.129051"
ry="6.741148" />
<rect
style="opacity:1;fill:#cfe2f3;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.258106;stroke-opacity:1"
id="rect837-9-8-9"
width="79.741898"
height="38.498253"
x="0.12905283"
y="120.12905"
ry="6.741148" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker-end:url(#marker3141);paint-order:normal"
d="M 59.249128,38.627306 80.750874,60.129051"
id="path3329"
inkscape:connector-type="polyline"
inkscape:connector-curvature="0"
inkscape:connection-start="#rect837"
inkscape:connection-end="#rect837-9-8" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker3341)"
d="M 20.750874,38.627306 -0.75087247,60.129051"
id="path3337"
inkscape:connector-type="polyline"
inkscape:connector-curvature="0"
inkscape:connection-start="#rect837"
inkscape:connection-end="#rect837-9" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker3389)"
d="M -0.75087304,98.627304 20.750875,120.12905"
id="path3385"
inkscape:connector-type="polyline"
inkscape:connector-curvature="0"
inkscape:connection-start="#rect837-9"
inkscape:connection-end="#rect837-9-8-9" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker3443)"
d="M 80.750874,98.627304 59.249128,120.12905"
id="path3439"
inkscape:connector-type="polyline"
inkscape:connector-curvature="0"
inkscape:connection-start="#rect837-9-8"
inkscape:connection-end="#rect837-9-8-9" />
<path
style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker3503)"
d="M 41.227338,-14.998642 41.386551,0.50922611"
id="path3499"
inkscape:connector-type="polyline"
inkscape:connector-curvature="0" />
<text
xml:space="preserve"
id="text3667"
style="font-style:normal;font-weight:normal;font-size:10.58329999999999949px;line-height:1.25;font-family:sans-serif;white-space:pre;shape-inside:url(#rect3669);fill:#000000;fill-opacity:1;stroke:none;" />
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:5.64444px;line-height:1.25;font-family:sans-serif;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.265;stroke-miterlimit:4;stroke-dasharray:none"
x="44.769436"
y="-7.8602829"
id="text3675"><tspan
sodipodi:role="line"
id="tspan3673"
x="44.769436"
y="-7.8602829"
style="font-size:5.64444px;stroke-width:0.265;stroke-miterlimit:4;stroke-dasharray:none">in: %arg0, %arg1, %arg2</tspan></text>
<text
xml:space="preserve"
id="text3677"
style="font-style:normal;font-weight:normal;font-size:5.64444000000000035px;line-height:1.25;font-family:sans-serif;white-space:pre;shape-inside:url(#rect3679);fill:#000000;fill-opacity:1;stroke:none;"
transform="translate(25.051785,-8.0877048)"><tspan
x="9.5683594"
y="14.376156"><tspan
style="font-size:5.64444px">bb0</tspan></tspan></text>
<text
xml:space="preserve"
id="text3728"
style="font-style:normal;font-weight:normal;font-size:10.58329999999999949px;line-height:1.25;font-family:sans-serif;white-space:pre;shape-inside:url(#rect3730);fill:#000000;fill-opacity:1;stroke:none;" />
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:5.64444px;line-height:1.25;font-family:sans-serif;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583"
x="94.617386"
y="66.288452"
id="text3736"><tspan
sodipodi:role="line"
id="tspan3734"
x="94.617386"
y="66.288452"
style="font-size:5.64444px;stroke-width:0.264583">bb2</tspan></text>
<text
xml:space="preserve"
id="text3677-0"
style="font-style:normal;font-weight:normal;font-size:5.64444000000000035px;line-height:1.25;font-family:sans-serif;white-space:pre;shape-inside:url(#rect3679-2);fill:#000000;fill-opacity:1;stroke:none;"
transform="translate(-34.833839,51.912295)"><tspan
x="9.5683594"
y="14.376156"><tspan
style="font-size:5.64444px">bb1
</tspan></tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:5.64444px;line-height:1.25;font-family:sans-serif;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583"
x="26.288532"
y="126.28845"
id="text3736-6"><tspan
sodipodi:role="line"
id="tspan3734-5"
x="26.288532"
y="126.28845"
style="font-size:5.64444px;stroke-width:0.264583">bb3 (%1)</tspan></text>
<text
xml:space="preserve"
id="text1368"
style="font-style:normal;font-weight:normal;font-size:5.64444000000000035px;line-height:1.25;font-family:sans-serif;white-space:pre;shape-inside:url(#rect1370);fill:#000000;fill-opacity:1;stroke:none;"
transform="translate(8.4353227,-0.28369449)"><tspan
x="73.476562"
y="74.182797"><tspan
style="fill:#d40000;fill-opacity:1">%0 = memref.alloc()</tspan><tspan
style="font-size:5.64444px">
</tspan></tspan><tspan
x="73.476562"
y="81.238347"><tspan
style="font-size:5.64444px">use(%0)
</tspan></tspan><tspan
x="73.476562"
y="88.293896"><tspan
style="font-size:5.64444px">cf.br bb3(%0)</tspan></tspan></text>
<text
xml:space="preserve"
id="text1894"
style="font-style:normal;font-weight:normal;font-size:5.64444000000000035px;line-height:1.25;font-family:sans-serif;white-space:pre;shape-inside:url(#rect1896);fill:#000000;fill-opacity:1;stroke:none;" />
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:5.64444px;line-height:1.25;font-family:sans-serif;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583"
x="16.620224"
y="137.49144"
id="text1902"><tspan
sodipodi:role="line"
id="tspan1900"
x="16.620224"
y="137.49144"
style="font-size:5.64444px;stroke-width:0.264583">copy (%1, arg2)</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:5.64444px;line-height:1.25;font-family:sans-serif;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583"
x="76.269608"
y="111.63254"
id="text3165"><tspan
sodipodi:role="line"
id="tspan3163"
x="76.269608"
y="111.63254"
style="font-size:5.64444px;stroke-width:0.264583">%0</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:5.64444px;line-height:1.25;font-family:sans-serif;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583"
x="-12.065383"
y="111.08959"
id="text3165-8"><tspan
sodipodi:role="line"
id="tspan3163-3"
x="-12.065383"
y="111.08959"
style="font-size:5.64444px;stroke-width:0.264583">%arg1</tspan><tspan
sodipodi:role="line"
x="-12.065383"
y="118.14514"
style="font-size:5.64444px;stroke-width:0.264583"
id="tspan3185" /></text>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 15 KiB

View File

@ -1,759 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="319.99994mm"
height="354.75635mm"
viewBox="0 0 319.99993 354.75636"
version="1.1"
id="svg8"
inkscape:version="1.0.1 (c497b03c, 2020-09-10)"
sodipodi:docname="copy_branch_hoisting_after.svg">
<defs
id="defs2">
<rect
x="-44.320522"
y="314.26837"
width="57.491421"
height="11.257062"
id="rect9344" />
<rect
x="133.78227"
y="73.447647"
width="53.069004"
height="18.493744"
id="rect9332" />
<marker
style="overflow:visible"
id="marker8973"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow1Lend"
inkscape:isstock="true">
<path
transform="matrix(-0.8,0,0,-0.8,-10,0)"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
id="path8971" />
</marker>
<marker
style="overflow:visible"
id="marker8877"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow1Lend"
inkscape:isstock="true"
inkscape:collect="always">
<path
transform="matrix(-0.8,0,0,-0.8,-10,0)"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
id="path8875" />
</marker>
<marker
style="overflow:visible"
id="marker8787"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow1Lend"
inkscape:isstock="true"
inkscape:collect="always">
<path
transform="matrix(-0.8,0,0,-0.8,-10,0)"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
id="path8785" />
</marker>
<marker
style="overflow:visible"
id="marker8703"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow1Lend"
inkscape:isstock="true"
inkscape:collect="always">
<path
transform="matrix(-0.8,0,0,-0.8,-10,0)"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
id="path8701" />
</marker>
<marker
style="overflow:visible"
id="marker8625"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow1Lend"
inkscape:isstock="true"
inkscape:collect="always">
<path
transform="matrix(-0.8,0,0,-0.8,-10,0)"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
id="path8623" />
</marker>
<marker
style="overflow:visible"
id="marker8553"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow1Lend"
inkscape:isstock="true"
inkscape:collect="always">
<path
transform="matrix(-0.8,0,0,-0.8,-10,0)"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
id="path8551" />
</marker>
<marker
style="overflow:visible"
id="marker8487"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow1Lend"
inkscape:isstock="true"
inkscape:collect="always">
<path
transform="matrix(-0.8,0,0,-0.8,-10,0)"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
id="path8485" />
</marker>
<marker
style="overflow:visible"
id="marker8415"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow1Lend"
inkscape:isstock="true"
inkscape:collect="always">
<path
transform="matrix(-0.8,0,0,-0.8,-10,0)"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
id="path8413" />
</marker>
<rect
x="18.139799"
y="132.9565"
width="42.875893"
height="13.192582"
id="rect1896" />
<rect
x="73.476562"
y="69.033791"
width="111.61496"
height="41.205559"
id="rect1370" />
<rect
x="88.85537"
y="63.907516"
width="32.124634"
height="21.53034"
id="rect3730" />
<rect
x="9.5690403"
y="9.2272892"
width="20.163336"
height="14.011809"
id="rect3679" />
<rect
x="41.227337"
y="-14.998642"
width="72.234138"
height="11.239376"
id="rect3669" />
<marker
style="overflow:visible"
id="marker3503"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow1Lend"
inkscape:isstock="true"
inkscape:collect="always">
<path
transform="matrix(-0.8,0,0,-0.8,-10,0)"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
id="path3501" />
</marker>
<marker
style="overflow:visible"
id="marker3341"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow1Lend"
inkscape:isstock="true"
inkscape:collect="always">
<path
transform="matrix(-0.8,0,0,-0.8,-10,0)"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
id="path3339" />
</marker>
<marker
style="overflow:visible"
id="marker2967"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow1Lstart"
inkscape:isstock="true">
<path
transform="matrix(0.8,0,0,0.8,10,0)"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
id="path2965" />
</marker>
<marker
style="overflow:visible"
id="Arrow1Send"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow1Send"
inkscape:isstock="true">
<path
transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
id="path2664" />
</marker>
<marker
style="overflow:visible"
id="Arrow1Lstart"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow1Lstart"
inkscape:isstock="true">
<path
transform="matrix(0.8,0,0,0.8,10,0)"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
id="path2649" />
</marker>
<rect
x="9.5690403"
y="9.2272892"
width="20.163336"
height="14.011809"
id="rect3679-2" />
<rect
x="9.5690403"
y="9.2272892"
width="20.163336"
height="14.011809"
id="rect3692" />
<marker
style="overflow:visible"
id="marker3503-8"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow1Lend"
inkscape:isstock="true">
<path
transform="matrix(-0.8,0,0,-0.8,-10,0)"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
id="path3501-9" />
</marker>
<rect
x="9.5690403"
y="9.2272892"
width="33.3377"
height="13.439011"
id="rect3679-0" />
<rect
x="9.5690403"
y="9.2272892"
width="20.163336"
height="14.011809"
id="rect7499" />
<rect
x="9.5690403"
y="9.2272892"
width="20.163336"
height="14.011809"
id="rect3679-2-4" />
<rect
x="9.5690403"
y="9.2272892"
width="20.163336"
height="14.011809"
id="rect7502" />
<rect
x="73.476562"
y="69.033791"
width="111.61496"
height="41.205559"
id="rect1370-5" />
<rect
x="73.476562"
y="69.033791"
width="111.61496"
height="41.205559"
id="rect7505" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="0.79269723"
inkscape:cx="505.54239"
inkscape:cy="988.76803"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
inkscape:document-rotation="0"
showgrid="false"
inkscape:window-width="1680"
inkscape:window-height="963"
inkscape:window-x="0"
inkscape:window-y="93"
inkscape:window-maximized="1"
showguides="true"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
lock-margins="false" />
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Ebene 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(60.000002,15.000695)"
style="display:inline">
<rect
style="opacity:1;fill:#cfe2f3;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.258106;stroke-opacity:1"
id="rect837"
width="79.741898"
height="38.498253"
x="0.12905283"
y="0.129053"
ry="6.741148" />
<rect
style="opacity:1;fill:#cfe2f3;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.258106;stroke-opacity:1"
id="rect837-9"
width="79.741898"
height="38.498253"
x="-59.870949"
y="60.129051"
ry="6.741148" />
<rect
style="opacity:1;fill:#cfe2f3;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.258106;stroke-opacity:1"
id="rect837-9-8-9"
width="79.741898"
height="38.498253"
x="-59.870949"
y="240.12854"
ry="6.741148" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker3341)"
d="M 20.750874,38.627306 -0.75087247,60.129051"
id="path3337"
inkscape:connector-type="polyline"
inkscape:connector-curvature="0"
inkscape:connection-start="#rect837"
inkscape:connection-end="#rect837-9" />
<path
style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker3503)"
d="M 41.227338,-14.998642 41.386551,0.50922611"
id="path3499"
inkscape:connector-type="polyline"
inkscape:connector-curvature="0" />
<text
xml:space="preserve"
id="text3667"
style="font-style:normal;font-weight:normal;font-size:10.58329999999999949px;line-height:1.25;font-family:sans-serif;white-space:pre;shape-inside:url(#rect3669);fill:#000000;fill-opacity:1;stroke:none;" />
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:5.64444px;line-height:1.25;font-family:sans-serif;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.265;stroke-miterlimit:4;stroke-dasharray:none"
x="44.769436"
y="-7.8602829"
id="text3675"><tspan
sodipodi:role="line"
id="tspan3673"
x="44.769436"
y="-7.8602829"
style="font-size:5.64444px;stroke-width:0.265;stroke-miterlimit:4;stroke-dasharray:none">in: %arg0, %arg1, %arg2, %arg3</tspan></text>
<text
xml:space="preserve"
id="text3677"
style="font-style:normal;font-weight:normal;font-size:5.64444000000000035px;line-height:1.25;font-family:sans-serif;white-space:pre;shape-inside:url(#rect3679);fill:#000000;fill-opacity:1;stroke:none;"
transform="translate(25.051785,-8.0877048)"><tspan
x="9.5683594"
y="14.376156"><tspan
style="font-size:5.64444px">bb0</tspan></tspan></text>
<text
xml:space="preserve"
id="text3728"
style="font-style:normal;font-weight:normal;font-size:10.58329999999999949px;line-height:1.25;font-family:sans-serif;white-space:pre;shape-inside:url(#rect3730);fill:#000000;fill-opacity:1;stroke:none;" />
<text
xml:space="preserve"
id="text3677-0"
style="font-style:normal;font-weight:normal;font-size:5.64444000000000035px;line-height:1.25;font-family:sans-serif;white-space:pre;shape-inside:url(#rect3679-2);fill:#000000;fill-opacity:1;stroke:none;"
transform="translate(-34.833839,51.912295)"><tspan
x="9.5683594"
y="14.376156"><tspan
style="font-size:5.64444px">bb1
</tspan></tspan></text>
<text
xml:space="preserve"
id="text1894"
style="font-style:normal;font-weight:normal;font-size:5.64444000000000035px;line-height:1.25;font-family:sans-serif;white-space:pre;shape-inside:url(#rect1896);fill:#000000;fill-opacity:1;stroke:none;" />
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:5.64444px;line-height:1.25;font-family:sans-serif;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583"
x="-33.069748"
y="171.81396"
id="text3165-8"><tspan
sodipodi:role="line"
id="tspan3163-3"
x="-33.069748"
y="171.81396"
style="font-size:5.64444px;stroke-width:0.264583">%5</tspan><tspan
sodipodi:role="line"
x="-33.069748"
y="178.86952"
style="font-size:5.64444px;stroke-width:0.264583"
id="tspan3185" /></text>
<rect
style="display:inline;opacity:1;fill:#cfe2f3;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.258106;stroke-opacity:1"
id="rect837-4"
width="79.741898"
height="38.498253"
x="120.12905"
y="60.128536"
ry="6.741148" />
<rect
style="display:inline;opacity:1;fill:#cfe2f3;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.258106;stroke-opacity:1"
id="rect837-9-89"
width="79.741898"
height="38.498253"
x="60.129051"
y="120.12854"
ry="6.741148" />
<rect
style="display:inline;opacity:1;fill:#cfe2f3;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.258;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect837-9-8"
width="79.741898"
height="38.498253"
x="180.12904"
y="120.12849"
ry="6.741148" />
<rect
style="display:inline;opacity:1;fill:#cfe2f3;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.258106;stroke-opacity:1"
id="rect837-9-8-9-8"
width="79.741898"
height="38.498253"
x="120.12905"
y="180.12854"
ry="6.741148" />
<text
xml:space="preserve"
id="text3677-6"
style="font-style:normal;font-weight:normal;font-size:5.64444000000000035px;line-height:1.25;font-family:sans-serif;white-space:pre;shape-inside:url(#rect3679-0);display:inline;fill:#000000;fill-opacity:1;stroke:none;"
transform="translate(136.72017,51.911779)"><tspan
x="9.5683594"
y="14.376156"><tspan
style="font-size:5.64444px">bb2 (%0)</tspan></tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:5.64444px;line-height:1.25;font-family:sans-serif;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583"
x="214.61739"
y="126.28793"
id="text3736"><tspan
sodipodi:role="line"
id="tspan3734"
x="214.61739"
y="126.28793"
style="font-size:5.64444px;stroke-width:0.264583">bb4</tspan></text>
<text
xml:space="preserve"
id="text3677-0-7"
style="font-style:normal;font-weight:normal;font-size:5.64444000000000035px;line-height:1.25;font-family:sans-serif;white-space:pre;shape-inside:url(#rect3679-2-4);display:inline;fill:#000000;fill-opacity:1;stroke:none;"
transform="translate(85.166161,111.91178)"><tspan
x="9.5683594"
y="14.376156"><tspan
style="font-size:5.64444px">bb3
</tspan></tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:5.64444px;line-height:1.25;font-family:sans-serif;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583"
x="146.28853"
y="186.28793"
id="text3736-6"><tspan
sodipodi:role="line"
id="tspan3734-5"
x="146.28853"
y="186.28793"
style="font-size:5.64444px;stroke-width:0.264583">bb5 (%2)</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:5.64444px;line-height:1.25;font-family:sans-serif;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583"
x="114.09232"
y="171.63202"
id="text3165-8-0"><tspan
sodipodi:role="line"
id="tspan3163-3-8"
x="114.09232"
y="171.63202"
style="font-size:5.64444px;stroke-width:0.264583">%1</tspan><tspan
sodipodi:role="line"
x="114.09232"
y="178.68758"
style="font-size:5.64444px;stroke-width:0.264583"
id="tspan3185-9" /></text>
<rect
style="display:inline;opacity:1;fill:#cfe2f3;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.258106;stroke-opacity:1"
id="rect837-9-8-9-8-4"
width="79.741898"
height="38.498253"
x="-59.870949"
y="300.12836"
ry="6.741148" />
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:5.64444px;line-height:1.25;font-family:sans-serif;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583"
x="-33.711475"
y="306.28775"
id="text3736-6-7"><tspan
sodipodi:role="line"
id="tspan3734-5-8"
x="-33.711475"
y="306.28775"
style="font-size:5.64444px;stroke-width:0.264583">bb7 (%4)</tspan></text>
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker8415)"
d="M 76.594903,37.675473 123.4051,61.080369"
id="path8411"
inkscape:connector-type="polyline"
inkscape:connector-curvature="0"
inkscape:connection-start="#rect837"
inkscape:connection-end="#rect837-4" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker8487)"
d="m 179.24914,98.626789 21.50171,21.501701"
id="path8483"
inkscape:connector-type="polyline"
inkscape:connector-curvature="0"
inkscape:connection-start="#rect837-4"
inkscape:connection-end="#rect837-9-8" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker8553)"
d="M 140.75087,98.626789 119.24913,120.12854"
id="path8549"
inkscape:connector-type="polyline"
inkscape:connector-curvature="0"
inkscape:connection-start="#rect837-4"
inkscape:connection-end="#rect837-9-89" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker8625)"
d="m 119.24913,158.62679 21.50174,21.50175"
id="path8621"
inkscape:connector-type="polyline"
inkscape:connector-curvature="0"
inkscape:connection-end="#rect837-9-8-9-8"
inkscape:connection-start="#rect837-9-89" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker8703)"
d="m 200.75089,158.62674 -21.50178,21.5018"
id="path8699"
inkscape:connector-type="polyline"
inkscape:connector-curvature="0"
inkscape:connection-start="#rect837-9-8"
inkscape:connection-end="#rect837-9-8-9-8" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker8787)"
d="M 120.17193,212.65369 19.828068,246.10164"
id="path8783"
inkscape:connector-type="polyline"
inkscape:connector-curvature="0"
inkscape:connection-end="#rect837-9-8-9"
inkscape:connection-start="#rect837-9-8-9-8" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker8877)"
d="M -20,98.627304 V 240.12854"
id="path8873"
inkscape:connector-type="polyline"
inkscape:connector-curvature="0"
inkscape:connection-start="#rect837-9"
inkscape:connection-end="#rect837-9-8-9" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker8973)"
d="m -20,278.62679 v 21.50157"
id="path8969"
inkscape:connector-type="polyline"
inkscape:connector-curvature="0"
inkscape:connection-start="#rect837-9-8-9"
inkscape:connection-end="#rect837-9-8-9-8-4" />
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:5.64444px;line-height:1.25;font-family:sans-serif;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583"
x="-33.711472"
y="246.28775"
id="text3736-6-7-3"><tspan
sodipodi:role="line"
id="tspan3734-5-8-0"
x="-33.711472"
y="246.28775"
style="font-size:5.64444px;stroke-width:0.264583">bb6 (%3)</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:5.64444px;line-height:1.25;font-family:sans-serif;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583"
x="194.1761"
y="171.632"
id="text3165-8-0-4"><tspan
sodipodi:role="line"
id="tspan3163-3-8-8"
x="194.1761"
y="171.632"
style="font-size:5.64444px;stroke-width:0.264583">%1</tspan><tspan
sodipodi:role="line"
x="194.1761"
y="178.68756"
style="font-size:5.64444px;stroke-width:0.264583"
id="tspan3185-9-0" /></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:5.64444px;line-height:1.25;font-family:sans-serif;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583"
x="64.926964"
y="236.35626"
id="text3165-8-0-0"><tspan
sodipodi:role="line"
id="tspan3163-3-8-0"
x="64.926964"
y="236.35626"
style="font-size:5.64444px;stroke-width:0.264583">%6</tspan><tspan
sodipodi:role="line"
x="64.926964"
y="243.41182"
style="font-size:5.64444px;stroke-width:0.264583"
id="tspan3185-9-6" /></text>
<text
xml:space="preserve"
id="text9330"
style="font-style:normal;font-weight:normal;font-size:5.64444000000000035px;line-height:1.25;font-family:sans-serif;white-space:pre;shape-inside:url(#rect9332);fill:#000000;fill-opacity:1;stroke:none;" />
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:5.64444px;line-height:1.25;font-family:sans-serif;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583"
x="137.07773"
y="78.674141"
id="text9338"><tspan
sodipodi:role="line"
id="tspan9336"
x="137.07773"
y="78.674141"
style="font-size:5.64444px;fill:#999999;stroke-width:0.264583">%1 = memref.alloc(%0)</tspan><tspan
sodipodi:role="line"
x="137.07773"
y="85.729691"
style="font-size:5.64444px;stroke-width:0.264583"
id="tspan9340">use(%1)</tspan></text>
<text
xml:space="preserve"
id="text9342"
style="font-style:normal;font-weight:normal;font-size:10.58329999999999949px;line-height:1.25;font-family:sans-serif;white-space:pre;shape-inside:url(#rect9344);fill:#000000;fill-opacity:1;stroke:none;" />
<text
xml:space="preserve"
style="font-size:5.64444px;line-height:1.25;font-family:sans-serif;stroke-width:0.264583"
x="-45.424786"
y="321.90707"
id="text9350"><tspan
sodipodi:role="line"
id="tspan9348"
x="-45.424786"
y="321.90707"
style="stroke-width:0.264583">copy(%4, %arg2)</tspan><tspan
sodipodi:role="line"
x="-45.424786"
y="328.96262"
style="fill:#008000;stroke-width:0.264583"
id="tspan9569">dealloc %3</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:5.64444px;line-height:1.25;font-family:sans-serif;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583"
x="-15.402786"
y="291.8205"
id="text3165-8-0-0-4"><tspan
sodipodi:role="line"
id="tspan3163-3-8-0-1"
x="-15.402786"
y="291.8205"
style="font-size:5.64444px;stroke-width:0.264583">%3</tspan><tspan
sodipodi:role="line"
x="-15.402786"
y="298.87604"
style="font-size:5.64444px;stroke-width:0.264583"
id="tspan3185-9-6-6" /></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:5.64444px;line-height:1.25;font-family:sans-serif;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583"
x="-45.424786"
y="77.928955"
id="text9338-9"><tspan
sodipodi:role="line"
id="tspan9336-0"
x="-45.424786"
y="77.928955"
style="font-size:5.64444px;fill:#008000;stroke-width:0.264583">%5 = memref.alloc(%d0)</tspan><tspan
sodipodi:role="line"
x="-45.424786"
y="84.984505"
style="font-size:5.64444px;stroke-width:0.264583"
id="tspan9340-6">copy(%arg1, %5)</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:5.64444px;line-height:1.25;font-family:sans-serif;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583"
x="135.37999"
y="198.54033"
id="text9338-8"><tspan
sodipodi:role="line"
id="tspan9336-2"
x="135.37999"
y="198.54033"
style="font-size:5.64444px;fill:#008000;stroke-width:0.264583">%6 = memref.alloc(%d1)</tspan><tspan
sodipodi:role="line"
x="135.37999"
y="205.59589"
style="font-size:5.64444px;stroke-width:0.264583"
id="tspan9340-1">copy(%1, %6)</tspan><tspan
sodipodi:role="line"
x="135.37999"
y="212.65143"
style="font-size:5.64444px;fill:#999999;stroke-width:0.264583"
id="tspan9567">dealloc %1</tspan></text>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 28 KiB

View File

@ -1,717 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="319.99994mm"
height="354.75635mm"
viewBox="0 0 319.99993 354.75636"
version="1.1"
id="svg8"
inkscape:version="1.0.1 (c497b03c, 2020-09-10)"
sodipodi:docname="copy_branch_hoisting_before.svg">
<defs
id="defs2">
<rect
x="-44.320522"
y="314.26837"
width="57.491421"
height="11.257062"
id="rect9344" />
<rect
x="133.78227"
y="73.447647"
width="53.069004"
height="18.493744"
id="rect9332" />
<marker
style="overflow:visible"
id="marker8973"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow1Lend"
inkscape:isstock="true">
<path
transform="matrix(-0.8,0,0,-0.8,-10,0)"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
id="path8971" />
</marker>
<marker
style="overflow:visible"
id="marker8877"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow1Lend"
inkscape:isstock="true"
inkscape:collect="always">
<path
transform="matrix(-0.8,0,0,-0.8,-10,0)"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
id="path8875" />
</marker>
<marker
style="overflow:visible"
id="marker8787"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow1Lend"
inkscape:isstock="true"
inkscape:collect="always">
<path
transform="matrix(-0.8,0,0,-0.8,-10,0)"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
id="path8785" />
</marker>
<marker
style="overflow:visible"
id="marker8703"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow1Lend"
inkscape:isstock="true"
inkscape:collect="always">
<path
transform="matrix(-0.8,0,0,-0.8,-10,0)"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
id="path8701" />
</marker>
<marker
style="overflow:visible"
id="marker8625"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow1Lend"
inkscape:isstock="true"
inkscape:collect="always">
<path
transform="matrix(-0.8,0,0,-0.8,-10,0)"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
id="path8623" />
</marker>
<marker
style="overflow:visible"
id="marker8553"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow1Lend"
inkscape:isstock="true"
inkscape:collect="always">
<path
transform="matrix(-0.8,0,0,-0.8,-10,0)"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
id="path8551" />
</marker>
<marker
style="overflow:visible"
id="marker8487"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow1Lend"
inkscape:isstock="true"
inkscape:collect="always">
<path
transform="matrix(-0.8,0,0,-0.8,-10,0)"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
id="path8485" />
</marker>
<marker
style="overflow:visible"
id="marker8415"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow1Lend"
inkscape:isstock="true"
inkscape:collect="always">
<path
transform="matrix(-0.8,0,0,-0.8,-10,0)"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
id="path8413" />
</marker>
<rect
x="18.139799"
y="132.9565"
width="42.875893"
height="13.192582"
id="rect1896" />
<rect
x="73.476562"
y="69.033791"
width="111.61496"
height="41.205559"
id="rect1370" />
<rect
x="88.85537"
y="63.907516"
width="32.124634"
height="21.53034"
id="rect3730" />
<rect
x="9.5690403"
y="9.2272892"
width="20.163336"
height="14.011809"
id="rect3679" />
<rect
x="41.227337"
y="-14.998642"
width="72.234138"
height="11.239376"
id="rect3669" />
<marker
style="overflow:visible"
id="marker3503"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow1Lend"
inkscape:isstock="true"
inkscape:collect="always">
<path
transform="matrix(-0.8,0,0,-0.8,-10,0)"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
id="path3501" />
</marker>
<marker
style="overflow:visible"
id="marker3341"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow1Lend"
inkscape:isstock="true"
inkscape:collect="always">
<path
transform="matrix(-0.8,0,0,-0.8,-10,0)"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
id="path3339" />
</marker>
<marker
style="overflow:visible"
id="marker2967"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow1Lstart"
inkscape:isstock="true">
<path
transform="matrix(0.8,0,0,0.8,10,0)"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
id="path2965" />
</marker>
<marker
style="overflow:visible"
id="Arrow1Send"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow1Send"
inkscape:isstock="true">
<path
transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
id="path2664" />
</marker>
<marker
style="overflow:visible"
id="Arrow1Lstart"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow1Lstart"
inkscape:isstock="true">
<path
transform="matrix(0.8,0,0,0.8,10,0)"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
id="path2649" />
</marker>
<rect
x="9.5690403"
y="9.2272892"
width="20.163336"
height="14.011809"
id="rect3679-2" />
<rect
x="9.5690403"
y="9.2272892"
width="20.163336"
height="14.011809"
id="rect3692" />
<marker
style="overflow:visible"
id="marker3503-8"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow1Lend"
inkscape:isstock="true">
<path
transform="matrix(-0.8,0,0,-0.8,-10,0)"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
id="path3501-9" />
</marker>
<rect
x="9.5690403"
y="9.2272892"
width="33.3377"
height="13.439011"
id="rect3679-0" />
<rect
x="9.5690403"
y="9.2272892"
width="20.163336"
height="14.011809"
id="rect7499" />
<rect
x="9.5690403"
y="9.2272892"
width="20.163336"
height="14.011809"
id="rect3679-2-4" />
<rect
x="9.5690403"
y="9.2272892"
width="20.163336"
height="14.011809"
id="rect7502" />
<rect
x="73.476562"
y="69.033791"
width="111.61496"
height="41.205559"
id="rect1370-5" />
<rect
x="73.476562"
y="69.033791"
width="111.61496"
height="41.205559"
id="rect7505" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="0.65810543"
inkscape:cx="432.43428"
inkscape:cy="876.48446"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
inkscape:document-rotation="0"
showgrid="false"
inkscape:window-width="1680"
inkscape:window-height="963"
inkscape:window-x="0"
inkscape:window-y="93"
inkscape:window-maximized="1"
showguides="true"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
lock-margins="false" />
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Ebene 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(60.000002,15.000695)"
style="display:inline">
<rect
style="opacity:1;fill:#cfe2f3;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.258106;stroke-opacity:1"
id="rect837"
width="79.741898"
height="38.498253"
x="0.12905283"
y="0.129053"
ry="6.741148" />
<rect
style="opacity:1;fill:#cfe2f3;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.258106;stroke-opacity:1"
id="rect837-9"
width="79.741898"
height="38.498253"
x="-59.870949"
y="60.129051"
ry="6.741148" />
<rect
style="opacity:1;fill:#cfe2f3;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.258106;stroke-opacity:1"
id="rect837-9-8-9"
width="79.741898"
height="38.498253"
x="-59.870949"
y="240.12854"
ry="6.741148" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker3341)"
d="M 20.750874,38.627306 -0.75087247,60.129051"
id="path3337"
inkscape:connector-type="polyline"
inkscape:connector-curvature="0"
inkscape:connection-start="#rect837"
inkscape:connection-end="#rect837-9" />
<path
style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker3503)"
d="M 41.227338,-14.998642 41.386551,0.50922611"
id="path3499"
inkscape:connector-type="polyline"
inkscape:connector-curvature="0" />
<text
xml:space="preserve"
id="text3667"
style="font-style:normal;font-weight:normal;font-size:10.58329999999999949px;line-height:1.25;font-family:sans-serif;white-space:pre;shape-inside:url(#rect3669);fill:#000000;fill-opacity:1;stroke:none;" />
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:5.64444px;line-height:1.25;font-family:sans-serif;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.265;stroke-miterlimit:4;stroke-dasharray:none"
x="44.769436"
y="-7.8602829"
id="text3675"><tspan
sodipodi:role="line"
id="tspan3673"
x="44.769436"
y="-7.8602829"
style="font-size:5.64444px;stroke-width:0.265;stroke-miterlimit:4;stroke-dasharray:none">in: %arg0, %arg1, %arg2, %arg3</tspan></text>
<text
xml:space="preserve"
id="text3677"
style="font-style:normal;font-weight:normal;font-size:5.64444000000000035px;line-height:1.25;font-family:sans-serif;white-space:pre;shape-inside:url(#rect3679);fill:#000000;fill-opacity:1;stroke:none;"
transform="translate(25.051785,-8.0877048)"><tspan
x="9.5683594"
y="14.376156"><tspan
style="font-size:5.64444px">bb0</tspan></tspan></text>
<text
xml:space="preserve"
id="text3728"
style="font-style:normal;font-weight:normal;font-size:10.58329999999999949px;line-height:1.25;font-family:sans-serif;white-space:pre;shape-inside:url(#rect3730);fill:#000000;fill-opacity:1;stroke:none;" />
<text
xml:space="preserve"
id="text3677-0"
style="font-style:normal;font-weight:normal;font-size:5.64444000000000035px;line-height:1.25;font-family:sans-serif;white-space:pre;shape-inside:url(#rect3679-2);fill:#000000;fill-opacity:1;stroke:none;"
transform="translate(-34.833839,51.912295)"><tspan
x="9.5683594"
y="14.376156"><tspan
style="font-size:5.64444px">bb1
</tspan></tspan></text>
<text
xml:space="preserve"
id="text1894"
style="font-style:normal;font-weight:normal;font-size:5.64444000000000035px;line-height:1.25;font-family:sans-serif;white-space:pre;shape-inside:url(#rect1896);fill:#000000;fill-opacity:1;stroke:none;" />
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:5.64444px;line-height:1.25;font-family:sans-serif;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583"
x="-41.41415"
y="171.27377"
id="text3165-8"><tspan
sodipodi:role="line"
id="tspan3163-3"
x="-41.41415"
y="171.27377"
style="font-size:5.64444px;stroke-width:0.264583">%arg1</tspan><tspan
sodipodi:role="line"
x="-41.41415"
y="178.32933"
style="font-size:5.64444px;stroke-width:0.264583"
id="tspan3185" /></text>
<rect
style="display:inline;opacity:1;fill:#cfe2f3;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.258106;stroke-opacity:1"
id="rect837-4"
width="79.741898"
height="38.498253"
x="120.12905"
y="60.128536"
ry="6.741148" />
<rect
style="display:inline;opacity:1;fill:#cfe2f3;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.258106;stroke-opacity:1"
id="rect837-9-89"
width="79.741898"
height="38.498253"
x="60.129051"
y="120.12854"
ry="6.741148" />
<rect
style="display:inline;opacity:1;fill:#cfe2f3;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.258;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect837-9-8"
width="79.741898"
height="38.498253"
x="180.12904"
y="120.12849"
ry="6.741148" />
<rect
style="display:inline;opacity:1;fill:#cfe2f3;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.258106;stroke-opacity:1"
id="rect837-9-8-9-8"
width="79.741898"
height="38.498253"
x="120.12905"
y="180.12854"
ry="6.741148" />
<text
xml:space="preserve"
id="text3677-6"
style="font-style:normal;font-weight:normal;font-size:5.64444000000000035px;line-height:1.25;font-family:sans-serif;white-space:pre;shape-inside:url(#rect3679-0);display:inline;fill:#000000;fill-opacity:1;stroke:none;"
transform="translate(136.72017,51.911779)"><tspan
x="9.5683594"
y="14.376156"><tspan
style="font-size:5.64444px">bb2 (%0)</tspan></tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:5.64444px;line-height:1.25;font-family:sans-serif;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583"
x="214.61739"
y="126.28793"
id="text3736"><tspan
sodipodi:role="line"
id="tspan3734"
x="214.61739"
y="126.28793"
style="font-size:5.64444px;stroke-width:0.264583">bb4</tspan></text>
<text
xml:space="preserve"
id="text3677-0-7"
style="font-style:normal;font-weight:normal;font-size:5.64444000000000035px;line-height:1.25;font-family:sans-serif;white-space:pre;shape-inside:url(#rect3679-2-4);display:inline;fill:#000000;fill-opacity:1;stroke:none;"
transform="translate(85.166161,111.91178)"><tspan
x="9.5683594"
y="14.376156"><tspan
style="font-size:5.64444px">bb3
</tspan></tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:5.64444px;line-height:1.25;font-family:sans-serif;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583"
x="146.28853"
y="186.28793"
id="text3736-6"><tspan
sodipodi:role="line"
id="tspan3734-5"
x="146.28853"
y="186.28793"
style="font-size:5.64444px;stroke-width:0.264583">bb5 (%2)</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:5.64444px;line-height:1.25;font-family:sans-serif;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583"
x="114.09232"
y="171.63202"
id="text3165-8-0"><tspan
sodipodi:role="line"
id="tspan3163-3-8"
x="114.09232"
y="171.63202"
style="font-size:5.64444px;stroke-width:0.264583">%1</tspan><tspan
sodipodi:role="line"
x="114.09232"
y="178.68758"
style="font-size:5.64444px;stroke-width:0.264583"
id="tspan3185-9" /></text>
<rect
style="display:inline;opacity:1;fill:#cfe2f3;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.258106;stroke-opacity:1"
id="rect837-9-8-9-8-4"
width="79.741898"
height="38.498253"
x="-59.870949"
y="300.12836"
ry="6.741148" />
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:5.64444px;line-height:1.25;font-family:sans-serif;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583"
x="-33.711475"
y="306.28775"
id="text3736-6-7"><tspan
sodipodi:role="line"
id="tspan3734-5-8"
x="-33.711475"
y="306.28775"
style="font-size:5.64444px;stroke-width:0.264583">bb7 (%4)</tspan></text>
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker8415)"
d="M 76.594903,37.675473 123.4051,61.080369"
id="path8411"
inkscape:connector-type="polyline"
inkscape:connector-curvature="0"
inkscape:connection-start="#rect837"
inkscape:connection-end="#rect837-4" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker8487)"
d="m 179.24914,98.626789 21.50171,21.501701"
id="path8483"
inkscape:connector-type="polyline"
inkscape:connector-curvature="0"
inkscape:connection-start="#rect837-4"
inkscape:connection-end="#rect837-9-8" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker8553)"
d="M 140.75087,98.626789 119.24913,120.12854"
id="path8549"
inkscape:connector-type="polyline"
inkscape:connector-curvature="0"
inkscape:connection-start="#rect837-4"
inkscape:connection-end="#rect837-9-89" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker8625)"
d="m 119.24913,158.62679 21.50174,21.50175"
id="path8621"
inkscape:connector-type="polyline"
inkscape:connector-curvature="0"
inkscape:connection-end="#rect837-9-8-9-8"
inkscape:connection-start="#rect837-9-89" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker8703)"
d="m 200.75089,158.62674 -21.50178,21.5018"
id="path8699"
inkscape:connector-type="polyline"
inkscape:connector-curvature="0"
inkscape:connection-start="#rect837-9-8"
inkscape:connection-end="#rect837-9-8-9-8" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker8787)"
d="M 120.17193,212.65369 19.828068,246.10164"
id="path8783"
inkscape:connector-type="polyline"
inkscape:connector-curvature="0"
inkscape:connection-end="#rect837-9-8-9"
inkscape:connection-start="#rect837-9-8-9-8" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker8877)"
d="M -20,98.627304 V 240.12854"
id="path8873"
inkscape:connector-type="polyline"
inkscape:connector-curvature="0"
inkscape:connection-start="#rect837-9"
inkscape:connection-end="#rect837-9-8-9" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker8973)"
d="m -20,278.62679 v 21.50157"
id="path8969"
inkscape:connector-type="polyline"
inkscape:connector-curvature="0"
inkscape:connection-start="#rect837-9-8-9"
inkscape:connection-end="#rect837-9-8-9-8-4" />
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:5.64444px;line-height:1.25;font-family:sans-serif;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583"
x="-33.711472"
y="246.28775"
id="text3736-6-7-3"><tspan
sodipodi:role="line"
id="tspan3734-5-8-0"
x="-33.711472"
y="246.28775"
style="font-size:5.64444px;stroke-width:0.264583">bb6 (%3)</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:5.64444px;line-height:1.25;font-family:sans-serif;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583"
x="194.1761"
y="171.632"
id="text3165-8-0-4"><tspan
sodipodi:role="line"
id="tspan3163-3-8-8"
x="194.1761"
y="171.632"
style="font-size:5.64444px;stroke-width:0.264583">%1</tspan><tspan
sodipodi:role="line"
x="194.1761"
y="178.68756"
style="font-size:5.64444px;stroke-width:0.264583"
id="tspan3185-9-0" /></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:5.64444px;line-height:1.25;font-family:sans-serif;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583"
x="64.926964"
y="236.35626"
id="text3165-8-0-0"><tspan
sodipodi:role="line"
id="tspan3163-3-8-0"
x="64.926964"
y="236.35626"
style="font-size:5.64444px;stroke-width:0.264583">%2</tspan><tspan
sodipodi:role="line"
x="64.926964"
y="243.41182"
style="font-size:5.64444px;stroke-width:0.264583"
id="tspan3185-9-6" /></text>
<text
xml:space="preserve"
id="text9330"
style="font-style:normal;font-weight:normal;font-size:5.64444000000000035px;line-height:1.25;font-family:sans-serif;white-space:pre;shape-inside:url(#rect9332);fill:#000000;fill-opacity:1;stroke:none;" />
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:5.64444px;line-height:1.25;font-family:sans-serif;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583"
x="137.07773"
y="78.674141"
id="text9338"><tspan
sodipodi:role="line"
id="tspan9336"
x="137.07773"
y="78.674141"
style="font-size:5.64444px;fill:#d40000;stroke-width:0.264583">%1 = memref.alloc(%0)</tspan><tspan
sodipodi:role="line"
x="137.07773"
y="85.729691"
style="font-size:5.64444px;stroke-width:0.264583"
id="tspan9340">use(%0)</tspan></text>
<text
xml:space="preserve"
id="text9342"
style="font-style:normal;font-weight:normal;font-size:10.58329999999999949px;line-height:1.25;font-family:sans-serif;white-space:pre;shape-inside:url(#rect9344);fill:#000000;fill-opacity:1;stroke:none;" />
<text
xml:space="preserve"
style="font-size:5.64444px;line-height:1.25;font-family:sans-serif;stroke-width:0.264583"
x="-45.424786"
y="321.90707"
id="text9350"><tspan
sodipodi:role="line"
id="tspan9348"
x="-45.424786"
y="321.90707"
style="stroke-width:0.264583">copy(%4, %arg2)</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:5.64444px;line-height:1.25;font-family:sans-serif;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583"
x="-15.402786"
y="291.8205"
id="text3165-8-0-0-4"><tspan
sodipodi:role="line"
id="tspan3163-3-8-0-1"
x="-15.402786"
y="291.8205"
style="font-size:5.64444px;stroke-width:0.264583">%3</tspan><tspan
sodipodi:role="line"
x="-15.402786"
y="298.87604"
style="font-size:5.64444px;stroke-width:0.264583"
id="tspan3185-9-6-6" /></text>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 26 KiB

View File

@ -1,435 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="199.99995mm"
height="191.75687mm"
viewBox="0 0.7 199.99995 191.75687"
version="1.1"
id="svg8"
inkscape:version="1.0.1 (c497b03c, 2020-09-10)"
sodipodi:docname="region_branch_hoisting.svg">
<defs
id="defs2">
<marker
style="overflow:visible"
id="marker3478"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow1Lend"
inkscape:isstock="true">
<path
transform="matrix(-0.8,0,0,-0.8,-10,0)"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
id="path3476" />
</marker>
<rect
x="18.139799"
y="132.9565"
width="42.875893"
height="13.192582"
id="rect1896" />
<rect
x="73.476562"
y="69.033791"
width="111.61496"
height="41.205559"
id="rect1370" />
<rect
x="88.85537"
y="63.907516"
width="32.124634"
height="21.53034"
id="rect3730" />
<rect
x="9.5690403"
y="9.2272892"
width="20.163336"
height="14.011809"
id="rect3679" />
<rect
x="41.227337"
y="-14.998642"
width="72.234138"
height="11.239376"
id="rect3669" />
<marker
style="overflow:visible"
id="marker3503"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow1Lend"
inkscape:isstock="true"
inkscape:collect="always">
<path
transform="matrix(-0.8,0,0,-0.8,-10,0)"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
id="path3501" />
</marker>
<marker
style="overflow:visible"
id="marker3443"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow1Lend"
inkscape:isstock="true"
inkscape:collect="always">
<path
transform="matrix(-0.8,0,0,-0.8,-10,0)"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
id="path3441" />
</marker>
<marker
style="overflow:visible"
id="marker3389"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow1Lend"
inkscape:isstock="true"
inkscape:collect="always">
<path
transform="matrix(-0.8,0,0,-0.8,-10,0)"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
id="path3387" />
</marker>
<marker
style="overflow:visible"
id="marker3341"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow1Lend"
inkscape:isstock="true"
inkscape:collect="always">
<path
transform="matrix(-0.8,0,0,-0.8,-10,0)"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
id="path3339" />
</marker>
<marker
style="overflow:visible"
id="marker3141"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow1Lend"
inkscape:isstock="true"
inkscape:collect="always">
<path
transform="matrix(-0.8,0,0,-0.8,-10,0)"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
id="path3139" />
</marker>
<marker
style="overflow:visible"
id="marker2967"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow1Lstart"
inkscape:isstock="true">
<path
transform="matrix(0.8,0,0,0.8,10,0)"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
id="path2965" />
</marker>
<marker
style="overflow:visible"
id="Arrow1Send"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow1Send"
inkscape:isstock="true">
<path
transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
id="path2664" />
</marker>
<marker
style="overflow:visible"
id="Arrow1Lstart"
refX="0"
refY="0"
orient="auto"
inkscape:stockid="Arrow1Lstart"
inkscape:isstock="true">
<path
transform="matrix(0.8,0,0,0.8,10,0)"
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
id="path2649" />
</marker>
<rect
x="9.5690403"
y="9.2272892"
width="20.163336"
height="14.011809"
id="rect3679-2" />
<rect
x="9.5690403"
y="9.2272892"
width="20.163336"
height="14.011809"
id="rect3692" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="0.61285746"
inkscape:cx="492.87186"
inkscape:cy="475.23437"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
inkscape:document-rotation="0"
showgrid="false"
inkscape:window-width="1920"
inkscape:window-height="1035"
inkscape:window-x="1680"
inkscape:window-y="23"
inkscape:window-maximized="1"
showguides="true"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="3.3"
lock-margins="false"
viewbox-y="1.8" />
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Ebene 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(60.000002,15.000516)"
style="display:inline">
<rect
style="opacity:1;fill:#cfe2f3;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.258106;stroke-opacity:1"
id="rect837"
width="79.741898"
height="38.498253"
x="0.12905283"
y="0.129053"
ry="6.741148" />
<rect
style="opacity:1;fill:#cfe2f3;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.258106;stroke-opacity:1"
id="rect837-9"
width="79.741898"
height="38.498253"
x="-59.870949"
y="60.129051"
ry="6.741148" />
<rect
style="opacity:1;fill:#cfe2f3;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.258;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect837-9-8"
width="79.741898"
height="38.498253"
x="60.129051"
y="60.129051"
ry="6.741148" />
<rect
style="opacity:1;fill:#cfe2f3;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.258106;stroke-opacity:1"
id="rect837-9-8-9"
width="79.741898"
height="38.498253"
x="0.12905283"
y="120.12905"
ry="6.741148" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker-end:url(#marker3141);paint-order:normal"
d="M 59.249128,38.627306 80.750874,60.129051"
id="path3329"
inkscape:connector-type="polyline"
inkscape:connector-curvature="0"
inkscape:connection-start="#rect837"
inkscape:connection-end="#rect837-9-8" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker3341)"
d="M 25.563156,38.627306 9.4368463,60.129051"
id="path3337"
inkscape:connector-type="polyline"
inkscape:connector-curvature="0"
inkscape:connection-start="#rect837"
inkscape:connection-end="#rect837-9" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker3389)"
d="M -0.75087304,98.627304 20.750875,120.12905"
id="path3385"
inkscape:connector-type="polyline"
inkscape:connector-curvature="0"
inkscape:connection-start="#rect837-9"
inkscape:connection-end="#rect837-9-8-9" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker3443)"
d="M 80.750874,98.627304 59.249128,120.12905"
id="path3439"
inkscape:connector-type="polyline"
inkscape:connector-curvature="0"
inkscape:connection-start="#rect837-9-8"
inkscape:connection-end="#rect837-9-8-9" />
<path
style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker3503)"
d="M 41.227338,-14.998642 41.386551,0.50922611"
id="path3499"
inkscape:connector-type="polyline"
inkscape:connector-curvature="0" />
<text
xml:space="preserve"
id="text3667"
style="font-style:normal;font-weight:normal;font-size:10.58329999999999949px;line-height:1.25;font-family:sans-serif;white-space:pre;shape-inside:url(#rect3669);fill:#000000;fill-opacity:1;stroke:none;" />
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:5.64444px;line-height:1.25;font-family:sans-serif;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.265;stroke-miterlimit:4;stroke-dasharray:none"
x="44.769436"
y="-7.8602829"
id="text3675"><tspan
sodipodi:role="line"
id="tspan3673"
x="44.769436"
y="-7.8602829"
style="font-size:5.64444px;stroke-width:0.265;stroke-miterlimit:4;stroke-dasharray:none">%0</tspan></text>
<text
xml:space="preserve"
id="text3677"
style="font-style:normal;font-weight:normal;font-size:5.64444000000000035px;line-height:1.25;font-family:sans-serif;white-space:pre;shape-inside:url(#rect3679);fill:#000000;fill-opacity:1;stroke:none;"
transform="translate(28.330136,7.1600292)"><tspan
x="9.5683594"
y="14.376156"><tspan>if</tspan></tspan></text>
<text
xml:space="preserve"
id="text3728"
style="font-style:normal;font-weight:normal;font-size:10.58329999999999949px;line-height:1.25;font-family:sans-serif;white-space:pre;shape-inside:url(#rect3730);fill:#000000;fill-opacity:1;stroke:none;" />
<text
xml:space="preserve"
id="text3677-0"
style="font-style:normal;font-weight:normal;font-size:5.64444000000000035px;line-height:1.25;font-family:sans-serif;white-space:pre;shape-inside:url(#rect3679-2);fill:#000000;fill-opacity:1;stroke:none;"
transform="translate(-35.776417,67.110418)"><tspan
x="9.5683594"
y="14.376156"><tspan>then</tspan></tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:5.64444px;line-height:1.25;font-family:sans-serif;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583"
x="42.775875"
y="169.7245"
id="text3736-6"><tspan
sodipodi:role="line"
id="tspan3734-5"
x="42.775875"
y="169.7245"
style="font-size:5.64444px;stroke-width:0.264583">%1</tspan></text>
<text
xml:space="preserve"
id="text1368"
style="font-style:normal;font-weight:normal;font-size:5.64444000000000035px;line-height:1.25;font-family:sans-serif;white-space:pre;shape-inside:url(#rect1370);fill:#000000;fill-opacity:1;stroke:none;"
transform="translate(20.903802,7.3023994)"><tspan
x="73.476562"
y="74.182797"><tspan
style="font-size:5.64444px">else</tspan></tspan></text>
<text
xml:space="preserve"
id="text1894"
style="font-style:normal;font-weight:normal;font-size:5.64444000000000035px;line-height:1.25;font-family:sans-serif;white-space:pre;shape-inside:url(#rect1896);fill:#000000;fill-opacity:1;stroke:none;" />
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:5.64444px;line-height:1.25;font-family:sans-serif;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583"
x="35.081787"
y="140.86095"
id="text1902"><tspan
sodipodi:role="line"
id="tspan1900"
x="35.081787"
y="140.86095"
style="font-size:5.64444px;stroke-width:0.264583">join</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:5.64444px;line-height:1.25;font-family:sans-serif;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583"
x="76.269608"
y="111.63254"
id="text3165"><tspan
sodipodi:role="line"
id="tspan3163"
x="76.269608"
y="111.63254"
style="font-size:5.64444px;stroke-width:0.264583">%arg4</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:5.64444px;line-height:1.25;font-family:sans-serif;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583"
x="-12.065383"
y="111.08959"
id="text3165-8"><tspan
sodipodi:role="line"
id="tspan3163-3"
x="-12.065383"
y="111.08959"
style="font-size:5.64444px;stroke-width:0.264583">%arg4</tspan><tspan
sodipodi:role="line"
x="-12.065383"
y="118.14514"
style="font-size:5.64444px;stroke-width:0.264583"
id="tspan3185" /></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:5.64444px;line-height:1.25;font-family:sans-serif;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583"
x="-5.6124902"
y="51.136368"
id="text3165-8-4"><tspan
sodipodi:role="line"
id="tspan3163-3-0"
x="-5.6124902"
y="51.136368"
style="font-size:5.64444px;stroke-width:0.264583">%arg2</tspan><tspan
sodipodi:role="line"
x="-5.6124902"
y="58.191917"
style="font-size:5.64444px;stroke-width:0.264583"
id="tspan3185-2" /></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:5.64444px;line-height:1.25;font-family:sans-serif;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583"
x="78.175652"
y="51.089592"
id="text3165-8-9"><tspan
sodipodi:role="line"
x="78.175652"
y="51.089592"
style="font-size:5.64444px;stroke-width:0.264583"
id="tspan3185-9">%arg3</tspan></text>
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#marker3478)"
d="m 40.011796,158.71197 0.01604,17.14766"
id="path3474"
inkscape:connector-type="polyline"
inkscape:connector-curvature="0" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 16 KiB

View File

@ -30,10 +30,6 @@ using DeallocHelperMap = llvm::DenseMap<Operation *, func::FuncOp>;
#define GEN_PASS_DECL
#include "mlir/Dialect/Bufferization/Transforms/Passes.h.inc"
/// Creates an instance of the BufferDeallocation pass to free all allocated
/// buffers.
std::unique_ptr<Pass> createBufferDeallocationPass();
/// Creates an instance of the OwnershipBasedBufferDeallocation pass to free all
/// allocated buffers.
std::unique_ptr<Pass> createOwnershipBasedBufferDeallocationPass(
@ -141,9 +137,6 @@ void populateBufferizationDeallocLoweringPattern(
func::FuncOp buildDeallocationLibraryFunction(OpBuilder &builder, Location loc,
SymbolTable &symbolTable);
/// Run buffer deallocation.
LogicalResult deallocateBuffers(Operation *op);
/// Run the ownership-based buffer deallocation.
LogicalResult deallocateBuffersOwnershipBased(FunctionOpInterface op,
DeallocationOptions options);

View File

@ -11,79 +11,6 @@
include "mlir/Pass/PassBase.td"
def BufferDeallocation : Pass<"buffer-deallocation", "func::FuncOp"> {
let summary = "Adds all required dealloc operations for all allocations in "
"the input program";
let description = [{
This pass implements an algorithm to automatically introduce all required
deallocation operations for all buffers in the input program. This ensures
that the resulting program does not have any memory leaks.
Input
```mlir
#map0 = affine_map<(d0) -> (d0)>
module {
func.func @condBranch(%arg0: i1, %arg1: memref<2xf32>, %arg2: memref<2xf32>) {
cf.cond_br %arg0, ^bb1, ^bb2
^bb1:
cf.br ^bb3(%arg1 : memref<2xf32>)
^bb2:
%0 = memref.alloc() : memref<2xf32>
linalg.generic {
indexing_maps = [#map0, #map0],
iterator_types = ["parallel"]} %arg1, %0 {
^bb0(%gen1_arg0: f32, %gen1_arg1: f32):
%tmp1 = exp %gen1_arg0 : f32
linalg.yield %tmp1 : f32
}: memref<2xf32>, memref<2xf32>
cf.br ^bb3(%0 : memref<2xf32>)
^bb3(%1: memref<2xf32>):
"memref.copy"(%1, %arg2) : (memref<2xf32>, memref<2xf32>) -> ()
return
}
}
```
Output
```mlir
#map0 = affine_map<(d0) -> (d0)>
module {
func.func @condBranch(%arg0: i1, %arg1: memref<2xf32>, %arg2: memref<2xf32>) {
cf.cond_br %arg0, ^bb1, ^bb2
^bb1: // pred: ^bb0
%0 = memref.alloc() : memref<2xf32>
memref.copy(%arg1, %0) : memref<2xf32>, memref<2xf32>
cf.br ^bb3(%0 : memref<2xf32>)
^bb2: // pred: ^bb0
%1 = memref.alloc() : memref<2xf32>
linalg.generic {
indexing_maps = [#map0, #map0],
iterator_types = ["parallel"]} %arg1, %1 {
^bb0(%arg3: f32, %arg4: f32):
%4 = exp %arg3 : f32
linalg.yield %4 : f32
}: memref<2xf32>, memref<2xf32>
%2 = memref.alloc() : memref<2xf32>
memref.copy(%1, %2) : memref<2xf32>, memref<2xf32>
dealloc %1 : memref<2xf32>
cf.br ^bb3(%2 : memref<2xf32>)
^bb3(%3: memref<2xf32>): // 2 preds: ^bb1, ^bb2
memref.copy(%3, %arg2) : memref<2xf32>, memref<2xf32>
dealloc %3 : memref<2xf32>
return
}
}
```
}];
let constructor = "mlir::bufferization::createBufferDeallocationPass()";
}
def OwnershipBasedBufferDeallocation : Pass<
"ownership-based-buffer-deallocation"> {
let summary = "Adds all required dealloc operations for all allocations in "
@ -390,8 +317,9 @@ def OneShotBufferize : Pass<"one-shot-bufferize", "ModuleOp"> {
results in a new buffer allocation.
One-Shot Bufferize does not deallocate any buffers that it allocates. The
`-buffer-deallocation` pass should be run after One-Shot Bufferize to insert
the deallocation operations necessary to eliminate memory leaks.
`-buffer-deallocation-pipeline` pipeline should be run after One-Shot
Bufferize to insert the deallocation operations necessary to eliminate
memory leaks.
One-Shot Bufferize will by default reject IR that contains non-bufferizable
op, i.e., ops that do not implemement BufferizableOpInterface. Such IR can

View File

@ -1,693 +0,0 @@
//===- BufferDeallocation.cpp - the impl for buffer deallocation ----------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file implements logic for computing correct alloc and dealloc positions.
// Furthermore, buffer deallocation also adds required new clone operations to
// ensure that all buffers are deallocated. The main class is the
// BufferDeallocationPass class that implements the underlying algorithm. In
// order to put allocations and deallocations at safe positions, it is
// significantly important to put them into the correct blocks. However, the
// liveness analysis does not pay attention to aliases, which can occur due to
// branches (and their associated block arguments) in general. For this purpose,
// BufferDeallocation firstly finds all possible aliases for a single value
// (using the BufferViewFlowAnalysis class). Consider the following example:
//
// ^bb0(%arg0):
// cf.cond_br %cond, ^bb1, ^bb2
// ^bb1:
// cf.br ^exit(%arg0)
// ^bb2:
// %new_value = ...
// cf.br ^exit(%new_value)
// ^exit(%arg1):
// return %arg1;
//
// We should place the dealloc for %new_value in exit. However, we have to free
// the buffer in the same block, because it cannot be freed in the post
// dominator. However, this requires a new clone buffer for %arg1 that will
// contain the actual contents. Using the class BufferViewFlowAnalysis, we
// will find out that %new_value has a potential alias %arg1. In order to find
// the dealloc position we have to find all potential aliases, iterate over
// their uses and find the common post-dominator block (note that additional
// clones and buffers remove potential aliases and will influence the placement
// of the deallocs). In all cases, the computed block can be safely used to free
// the %new_value buffer (may be exit or bb2) as it will die and we can use
// liveness information to determine the exact operation after which we have to
// insert the dealloc. However, the algorithm supports introducing clone buffers
// and placing deallocs in safe locations to ensure that all buffers will be
// freed in the end.
//
// TODO:
// The current implementation does not support explicit-control-flow loops and
// the resulting code will be invalid with respect to program semantics.
// However, structured control-flow loops are fully supported. Furthermore, it
// doesn't accept functions which return buffers already.
//
//===----------------------------------------------------------------------===//
#include "mlir/Dialect/Bufferization/Transforms/Passes.h"
#include "mlir/Dialect/Bufferization/IR/AllocationOpInterface.h"
#include "mlir/Dialect/Bufferization/IR/Bufferization.h"
#include "mlir/Dialect/Bufferization/Transforms/BufferUtils.h"
#include "mlir/Dialect/Func/IR/FuncOps.h"
#include "mlir/Dialect/MemRef/IR/MemRef.h"
#include "llvm/ADT/SetOperations.h"
namespace mlir {
namespace bufferization {
#define GEN_PASS_DEF_BUFFERDEALLOCATION
#include "mlir/Dialect/Bufferization/Transforms/Passes.h.inc"
} // namespace bufferization
} // namespace mlir
using namespace mlir;
using namespace mlir::bufferization;
/// Walks over all immediate return-like terminators in the given region.
static LogicalResult walkReturnOperations(
Region *region,
llvm::function_ref<LogicalResult(RegionBranchTerminatorOpInterface)> func) {
for (Block &block : *region) {
Operation *terminator = block.getTerminator();
// Skip non region-return-like terminators.
if (auto regionTerminator =
dyn_cast<RegionBranchTerminatorOpInterface>(terminator)) {
if (failed(func(regionTerminator)))
return failure();
}
}
return success();
}
/// Checks if all operations that have at least one attached region implement
/// the RegionBranchOpInterface. This is not required in edge cases, where we
/// have a single attached region and the parent operation has no results.
static bool validateSupportedControlFlow(Operation *op) {
WalkResult result = op->walk([&](Operation *operation) {
// Only check ops that are inside a function.
if (!operation->getParentOfType<func::FuncOp>())
return WalkResult::advance();
auto regions = operation->getRegions();
// Walk over all operations in a region and check if the operation has at
// least one region and implements the RegionBranchOpInterface. If there
// is an operation that does not fulfill this condition, we cannot apply
// the deallocation steps. Furthermore, we accept cases, where we have a
// region that returns no results, since, in that case, the intra-region
// control flow does not affect the transformation.
size_t size = regions.size();
if (((size == 1 && !operation->getResults().empty()) || size > 1) &&
!dyn_cast<RegionBranchOpInterface>(operation)) {
operation->emitError("All operations with attached regions need to "
"implement the RegionBranchOpInterface.");
}
return WalkResult::advance();
});
return !result.wasSkipped();
}
namespace {
//===----------------------------------------------------------------------===//
// Backedges analysis
//===----------------------------------------------------------------------===//
/// A straight-forward program analysis which detects loop backedges induced by
/// explicit control flow.
class Backedges {
public:
using BlockSetT = SmallPtrSet<Block *, 16>;
using BackedgeSetT = llvm::DenseSet<std::pair<Block *, Block *>>;
public:
/// Constructs a new backedges analysis using the op provided.
Backedges(Operation *op) { recurse(op); }
/// Returns the number of backedges formed by explicit control flow.
size_t size() const { return edgeSet.size(); }
/// Returns the start iterator to loop over all backedges.
BackedgeSetT::const_iterator begin() const { return edgeSet.begin(); }
/// Returns the end iterator to loop over all backedges.
BackedgeSetT::const_iterator end() const { return edgeSet.end(); }
private:
/// Enters the current block and inserts a backedge into the `edgeSet` if we
/// have already visited the current block. The inserted edge links the given
/// `predecessor` with the `current` block.
bool enter(Block &current, Block *predecessor) {
bool inserted = visited.insert(&current).second;
if (!inserted)
edgeSet.insert(std::make_pair(predecessor, &current));
return inserted;
}
/// Leaves the current block.
void exit(Block &current) { visited.erase(&current); }
/// Recurses into the given operation while taking all attached regions into
/// account.
void recurse(Operation *op) {
Block *current = op->getBlock();
// If the current op implements the `BranchOpInterface`, there can be
// cycles in the scope of all successor blocks.
if (isa<BranchOpInterface>(op)) {
for (Block *succ : current->getSuccessors())
recurse(*succ, current);
}
// Recurse into all distinct regions and check for explicit control-flow
// loops.
for (Region &region : op->getRegions()) {
if (!region.empty())
recurse(region.front(), current);
}
}
/// Recurses into explicit control-flow structures that are given by
/// the successor relation defined on the block level.
void recurse(Block &block, Block *predecessor) {
// Try to enter the current block. If this is not possible, we are
// currently processing this block and can safely return here.
if (!enter(block, predecessor))
return;
// Recurse into all operations and successor blocks.
for (Operation &op : block.getOperations())
recurse(&op);
// Leave the current block.
exit(block);
}
/// Stores all blocks that are currently visited and on the processing stack.
BlockSetT visited;
/// Stores all backedges in the format (source, target).
BackedgeSetT edgeSet;
};
//===----------------------------------------------------------------------===//
// BufferDeallocation
//===----------------------------------------------------------------------===//
/// The buffer deallocation transformation which ensures that all allocs in the
/// program have a corresponding de-allocation. As a side-effect, it might also
/// introduce clones that in turn leads to additional deallocations.
class BufferDeallocation : public BufferPlacementTransformationBase {
public:
using AliasAllocationMapT =
llvm::DenseMap<Value, bufferization::AllocationOpInterface>;
BufferDeallocation(Operation *op)
: BufferPlacementTransformationBase(op), dominators(op),
postDominators(op) {}
/// Checks if all allocation operations either provide an already existing
/// deallocation operation or implement the AllocationOpInterface. In
/// addition, this method initializes the internal alias to
/// AllocationOpInterface mapping in order to get compatible
/// AllocationOpInterface implementations for aliases.
LogicalResult prepare() {
for (const BufferPlacementAllocs::AllocEntry &entry : allocs) {
// Get the defining allocation operation.
Value alloc = std::get<0>(entry);
auto allocationInterface =
alloc.getDefiningOp<bufferization::AllocationOpInterface>();
// If there is no existing deallocation operation and no implementation of
// the AllocationOpInterface, we cannot apply the BufferDeallocation pass.
if (!std::get<1>(entry) && !allocationInterface) {
return alloc.getDefiningOp()->emitError(
"Allocation is not deallocated explicitly nor does the operation "
"implement the AllocationOpInterface.");
}
// Register the current allocation interface implementation.
aliasToAllocations[alloc] = allocationInterface;
// Get the alias information for the current allocation node.
for (Value alias : aliases.resolve(alloc)) {
// TODO: check for incompatible implementations of the
// AllocationOpInterface. This could be realized by promoting the
// AllocationOpInterface to a DialectInterface.
aliasToAllocations[alias] = allocationInterface;
}
}
return success();
}
/// Performs the actual placement/creation of all temporary clone and dealloc
/// nodes.
LogicalResult deallocate() {
// Add additional clones that are required.
if (failed(introduceClones()))
return failure();
// Place deallocations for all allocation entries.
return placeDeallocs();
}
private:
/// Introduces required clone operations to avoid memory leaks.
LogicalResult introduceClones() {
// Initialize the set of values that require a dedicated memory free
// operation since their operands cannot be safely deallocated in a post
// dominator.
SetVector<Value> valuesToFree;
llvm::SmallDenseSet<std::tuple<Value, Block *>> visitedValues;
SmallVector<std::tuple<Value, Block *>, 8> toProcess;
// Check dominance relation for proper dominance properties. If the given
// value node does not dominate an alias, we will have to create a clone in
// order to free all buffers that can potentially leak into a post
// dominator.
auto findUnsafeValues = [&](Value source, Block *definingBlock) {
auto it = aliases.find(source);
if (it == aliases.end())
return;
for (Value value : it->second) {
if (valuesToFree.count(value) > 0)
continue;
Block *parentBlock = value.getParentBlock();
// Check whether we have to free this particular block argument or
// generic value. We have to free the current alias if it is either
// defined in a non-dominated block or it is defined in the same block
// but the current value is not dominated by the source value.
if (!dominators.dominates(definingBlock, parentBlock) ||
(definingBlock == parentBlock && isa<BlockArgument>(value))) {
toProcess.emplace_back(value, parentBlock);
valuesToFree.insert(value);
} else if (visitedValues.insert(std::make_tuple(value, definingBlock))
.second)
toProcess.emplace_back(value, definingBlock);
}
};
// Detect possibly unsafe aliases starting from all allocations.
for (BufferPlacementAllocs::AllocEntry &entry : allocs) {
Value allocValue = std::get<0>(entry);
findUnsafeValues(allocValue, allocValue.getDefiningOp()->getBlock());
}
// Try to find block arguments that require an explicit free operation
// until we reach a fix point.
while (!toProcess.empty()) {
auto current = toProcess.pop_back_val();
findUnsafeValues(std::get<0>(current), std::get<1>(current));
}
// Update buffer aliases to ensure that we free all buffers and block
// arguments at the correct locations.
aliases.remove(valuesToFree);
// Add new allocs and additional clone operations.
for (Value value : valuesToFree) {
if (failed(isa<BlockArgument>(value)
? introduceBlockArgCopy(cast<BlockArgument>(value))
: introduceValueCopyForRegionResult(value)))
return failure();
// Register the value to require a final dealloc. Note that we do not have
// to assign a block here since we do not want to move the allocation node
// to another location.
allocs.registerAlloc(std::make_tuple(value, nullptr));
}
return success();
}
/// Introduces temporary clones in all predecessors and copies the source
/// values into the newly allocated buffers.
LogicalResult introduceBlockArgCopy(BlockArgument blockArg) {
// Allocate a buffer for the current block argument in the block of
// the associated value (which will be a predecessor block by
// definition).
Block *block = blockArg.getOwner();
for (auto it = block->pred_begin(), e = block->pred_end(); it != e; ++it) {
// Get the terminator and the value that will be passed to our
// argument.
Operation *terminator = (*it)->getTerminator();
auto branchInterface = cast<BranchOpInterface>(terminator);
SuccessorOperands operands =
branchInterface.getSuccessorOperands(it.getSuccessorIndex());
// Query the associated source value.
Value sourceValue = operands[blockArg.getArgNumber()];
if (!sourceValue) {
return failure();
}
// Wire new clone and successor operand.
// Create a new clone at the current location of the terminator.
auto clone = introduceCloneBuffers(sourceValue, terminator);
if (failed(clone))
return failure();
operands.slice(blockArg.getArgNumber(), 1).assign(*clone);
}
// Check whether the block argument has implicitly defined predecessors via
// the RegionBranchOpInterface. This can be the case if the current block
// argument belongs to the first block in a region and the parent operation
// implements the RegionBranchOpInterface.
Region *argRegion = block->getParent();
Operation *parentOp = argRegion->getParentOp();
RegionBranchOpInterface regionInterface;
if (&argRegion->front() != block ||
!(regionInterface = dyn_cast<RegionBranchOpInterface>(parentOp)))
return success();
if (failed(introduceClonesForRegionSuccessors(
regionInterface, argRegion->getParentOp()->getRegions(), blockArg,
[&](RegionSuccessor &successorRegion) {
// Find a predecessor of our argRegion.
return successorRegion.getSuccessor() == argRegion;
})))
return failure();
// Check whether the block argument belongs to an entry region of the
// parent operation. In this case, we have to introduce an additional clone
// for buffer that is passed to the argument.
SmallVector<RegionSuccessor, 2> successorRegions;
regionInterface.getSuccessorRegions(/*point=*/RegionBranchPoint::parent(),
successorRegions);
auto *it =
llvm::find_if(successorRegions, [&](RegionSuccessor &successorRegion) {
return successorRegion.getSuccessor() == argRegion;
});
if (it == successorRegions.end())
return success();
// Determine the actual operand to introduce a clone for and rewire the
// operand to point to the clone instead.
auto operands = regionInterface.getEntrySuccessorOperands(argRegion);
size_t operandIndex =
llvm::find(it->getSuccessorInputs(), blockArg).getIndex() +
operands.getBeginOperandIndex();
Value operand = parentOp->getOperand(operandIndex);
assert(operand ==
operands[operandIndex - operands.getBeginOperandIndex()] &&
"region interface operands don't match parentOp operands");
auto clone = introduceCloneBuffers(operand, parentOp);
if (failed(clone))
return failure();
parentOp->setOperand(operandIndex, *clone);
return success();
}
/// Introduces temporary clones in front of all associated nested-region
/// terminators and copies the source values into the newly allocated buffers.
LogicalResult introduceValueCopyForRegionResult(Value value) {
// Get the actual result index in the scope of the parent terminator.
Operation *operation = value.getDefiningOp();
auto regionInterface = cast<RegionBranchOpInterface>(operation);
// Filter successors that return to the parent operation.
auto regionPredicate = [&](RegionSuccessor &successorRegion) {
// If the RegionSuccessor has no associated successor, it will return to
// its parent operation.
return !successorRegion.getSuccessor();
};
// Introduce a clone for all region "results" that are returned to the
// parent operation. This is required since the parent's result value has
// been considered critical. Therefore, the algorithm assumes that a clone
// of a previously allocated buffer is returned by the operation (like in
// the case of a block argument).
return introduceClonesForRegionSuccessors(
regionInterface, operation->getRegions(), value, regionPredicate);
}
/// Introduces buffer clones for all terminators in the given regions. The
/// regionPredicate is applied to every successor region in order to restrict
/// the clones to specific regions.
template <typename TPredicate>
LogicalResult introduceClonesForRegionSuccessors(
RegionBranchOpInterface regionInterface, MutableArrayRef<Region> regions,
Value argValue, const TPredicate &regionPredicate) {
for (Region &region : regions) {
// Query the regionInterface to get all successor regions of the current
// one.
SmallVector<RegionSuccessor, 2> successorRegions;
regionInterface.getSuccessorRegions(region, successorRegions);
// Try to find a matching region successor.
RegionSuccessor *regionSuccessor =
llvm::find_if(successorRegions, regionPredicate);
if (regionSuccessor == successorRegions.end())
continue;
// Get the operand index in the context of the current successor input
// bindings.
size_t operandIndex =
llvm::find(regionSuccessor->getSuccessorInputs(), argValue)
.getIndex();
// Iterate over all immediate terminator operations to introduce
// new buffer allocations. Thereby, the appropriate terminator operand
// will be adjusted to point to the newly allocated buffer instead.
if (failed(walkReturnOperations(
&region, [&](RegionBranchTerminatorOpInterface terminator) {
// Get the actual mutable operands for this terminator op.
auto terminatorOperands =
terminator.getMutableSuccessorOperands(*regionSuccessor);
// Extract the source value from the current terminator.
// This conversion needs to exist on a separate line due to a
// bug in GCC conversion analysis.
OperandRange immutableTerminatorOperands = terminatorOperands;
Value sourceValue = immutableTerminatorOperands[operandIndex];
// Create a new clone at the current location of the terminator.
auto clone = introduceCloneBuffers(sourceValue, terminator);
if (failed(clone))
return failure();
// Wire clone and terminator operand.
terminatorOperands.slice(operandIndex, 1).assign(*clone);
return success();
})))
return failure();
}
return success();
}
/// Creates a new memory allocation for the given source value and clones
/// its content into the newly allocated buffer. The terminator operation is
/// used to insert the clone operation at the right place.
FailureOr<Value> introduceCloneBuffers(Value sourceValue,
Operation *terminator) {
// Avoid multiple clones of the same source value. This can happen in the
// presence of loops when a branch acts as a backedge while also having
// another successor that returns to its parent operation. Note: that
// copying copied buffers can introduce memory leaks since the invariant of
// BufferDeallocation assumes that a buffer will be only cloned once into a
// temporary buffer. Hence, the construction of clone chains introduces
// additional allocations that are not tracked automatically by the
// algorithm.
if (clonedValues.contains(sourceValue))
return sourceValue;
// Create a new clone operation that copies the contents of the old
// buffer to the new one.
auto clone = buildClone(terminator, sourceValue);
if (succeeded(clone)) {
// Remember the clone of original source value.
clonedValues.insert(*clone);
}
return clone;
}
/// Finds correct dealloc positions according to the algorithm described at
/// the top of the file for all alloc nodes and block arguments that can be
/// handled by this analysis.
LogicalResult placeDeallocs() {
// Move or insert deallocs using the previously computed information.
// These deallocations will be linked to their associated allocation nodes
// since they don't have any aliases that can (potentially) increase their
// liveness.
for (const BufferPlacementAllocs::AllocEntry &entry : allocs) {
Value alloc = std::get<0>(entry);
auto aliasesSet = aliases.resolve(alloc);
assert(!aliasesSet.empty() && "must contain at least one alias");
// Determine the actual block to place the dealloc and get liveness
// information.
Block *placementBlock =
findCommonDominator(alloc, aliasesSet, postDominators);
const LivenessBlockInfo *livenessInfo =
liveness.getLiveness(placementBlock);
// We have to ensure that the dealloc will be after the last use of all
// aliases of the given value. We first assume that there are no uses in
// the placementBlock and that we can safely place the dealloc at the
// beginning.
Operation *endOperation = &placementBlock->front();
// Iterate over all aliases and ensure that the endOperation will point
// to the last operation of all potential aliases in the placementBlock.
for (Value alias : aliasesSet) {
// Ensure that the start operation is at least the defining operation of
// the current alias to avoid invalid placement of deallocs for aliases
// without any uses.
Operation *beforeOp = endOperation;
if (alias.getDefiningOp() &&
!(beforeOp = placementBlock->findAncestorOpInBlock(
*alias.getDefiningOp())))
continue;
Operation *aliasEndOperation =
livenessInfo->getEndOperation(alias, beforeOp);
// Check whether the aliasEndOperation lies in the desired block and
// whether it is behind the current endOperation. If yes, this will be
// the new endOperation.
if (aliasEndOperation->getBlock() == placementBlock &&
endOperation->isBeforeInBlock(aliasEndOperation))
endOperation = aliasEndOperation;
}
// endOperation is the last operation behind which we can safely store
// the dealloc taking all potential aliases into account.
// If there is an existing dealloc, move it to the right place.
Operation *deallocOperation = std::get<1>(entry);
if (deallocOperation) {
deallocOperation->moveAfter(endOperation);
} else {
// If the Dealloc position is at the terminator operation of the
// block, then the value should escape from a deallocation.
Operation *nextOp = endOperation->getNextNode();
if (!nextOp)
continue;
// If there is no dealloc node, insert one in the right place.
if (failed(buildDealloc(nextOp, alloc)))
return failure();
}
}
return success();
}
/// Builds a deallocation operation compatible with the given allocation
/// value. If there is no registered AllocationOpInterface implementation for
/// the given value (e.g. in the case of a function parameter), this method
/// builds a memref::DeallocOp.
LogicalResult buildDealloc(Operation *op, Value alloc) {
OpBuilder builder(op);
auto it = aliasToAllocations.find(alloc);
if (it != aliasToAllocations.end()) {
// Call the allocation op interface to build a supported and
// compatible deallocation operation.
auto dealloc = it->second.buildDealloc(builder, alloc);
if (!dealloc)
return op->emitError()
<< "allocations without compatible deallocations are "
"not supported";
} else {
// Build a "default" DeallocOp for unknown allocation sources.
builder.create<memref::DeallocOp>(alloc.getLoc(), alloc);
}
return success();
}
/// Builds a clone operation compatible with the given allocation value. If
/// there is no registered AllocationOpInterface implementation for the given
/// value (e.g. in the case of a function parameter), this method builds a
/// bufferization::CloneOp.
FailureOr<Value> buildClone(Operation *op, Value alloc) {
OpBuilder builder(op);
auto it = aliasToAllocations.find(alloc);
if (it != aliasToAllocations.end()) {
// Call the allocation op interface to build a supported and
// compatible clone operation.
auto clone = it->second.buildClone(builder, alloc);
if (clone)
return *clone;
return (LogicalResult)(op->emitError()
<< "allocations without compatible clone ops "
"are not supported");
}
// Build a "default" CloneOp for unknown allocation sources.
return builder.create<bufferization::CloneOp>(alloc.getLoc(), alloc)
.getResult();
}
/// The dominator info to find the appropriate start operation to move the
/// allocs.
DominanceInfo dominators;
/// The post dominator info to move the dependent allocs in the right
/// position.
PostDominanceInfo postDominators;
/// Stores already cloned buffers to avoid additional clones of clones.
ValueSetT clonedValues;
/// Maps aliases to their source allocation interfaces (inverse mapping).
AliasAllocationMapT aliasToAllocations;
};
//===----------------------------------------------------------------------===//
// BufferDeallocationPass
//===----------------------------------------------------------------------===//
/// The actual buffer deallocation pass that inserts and moves dealloc nodes
/// into the right positions. Furthermore, it inserts additional clones if
/// necessary. It uses the algorithm described at the top of the file.
struct BufferDeallocationPass
: public bufferization::impl::BufferDeallocationBase<
BufferDeallocationPass> {
void getDependentDialects(DialectRegistry &registry) const override {
registry.insert<bufferization::BufferizationDialect>();
registry.insert<memref::MemRefDialect>();
}
void runOnOperation() override {
func::FuncOp func = getOperation();
if (func.isExternal())
return;
if (failed(deallocateBuffers(func)))
signalPassFailure();
}
};
} // namespace
LogicalResult bufferization::deallocateBuffers(Operation *op) {
if (isa<ModuleOp>(op)) {
WalkResult result = op->walk([&](func::FuncOp funcOp) {
if (failed(deallocateBuffers(funcOp)))
return WalkResult::interrupt();
return WalkResult::advance();
});
return success(!result.wasInterrupted());
}
// Ensure that there are supported loops only.
Backedges backedges(op);
if (backedges.size()) {
op->emitError("Only structured control-flow loops are supported.");
return failure();
}
// Check that the control flow structures are supported.
if (!validateSupportedControlFlow(op))
return failure();
// Gather all required allocation nodes and prepare the deallocation phase.
BufferDeallocation deallocation(op);
// Check for supported AllocationOpInterface implementations and prepare the
// internal deallocation pass.
if (failed(deallocation.prepare()))
return failure();
// Place all required temporary clone and dealloc nodes.
if (failed(deallocation.deallocate()))
return failure();
return success();
}
//===----------------------------------------------------------------------===//
// BufferDeallocationPass construction
//===----------------------------------------------------------------------===//
std::unique_ptr<Pass> mlir::bufferization::createBufferDeallocationPass() {
return std::make_unique<BufferDeallocationPass>();
}

View File

@ -1,6 +1,5 @@
add_mlir_dialect_library(MLIRBufferizationTransforms
Bufferize.cpp
BufferDeallocation.cpp
BufferDeallocationSimplification.cpp
BufferOptimizations.cpp
BufferResultsToOutParams.cpp

View File

@ -1,8 +1,8 @@
// RUN: mlir-opt --no-implicit-module \
// RUN: --pass-pipeline='any(buffer-deallocation)' --verify-diagnostics \
// RUN: --pass-pipeline='any(test-function-pass)' --verify-diagnostics \
// RUN: --split-input-file %s
// Note: "buffer-deallocation" is a function pass. Any other function pass could
// Note: "test-function-pass" is a function pass. Any other function pass could
// be used for this test.
// expected-error@below {{trying to schedule a pass on an operation not marked as 'IsolatedFromAbove'}}