Introduction
This proposal describes the new op to be added to the memref
dialect called alloca_scope
.
Motivation
Alloca operations are easy to misuse, especially if one relies on it while doing rewriting/conversion passes. For example let’s consider a simple example of two independent dialects, one defines an op that wants to allocate on-stack and another defines a construct that corresponds to some form of looping:
dialect1.looping_op {
%x = dialect2.stack_allocating_op
}
Since the dialects might not know about each other they are going to define a lowering to std/scf/etc independently:
scf.for … {
%x_temp = std.alloca …
… // do some domain-specific work using %x_temp buffer
… // and store the result into %result
%x = %result
}
Later on the scf and std.alloca
is going to be lowered to llvm using a combination of llvm.alloca
and unstructured control flow.
At this point the use of %x_temp
is bound to either be either optimized by llvm (for example using mem2reg) or in the worst case: perform an independent stack allocation on each iteration of the loop. While the llvm optimizations are likely to succeed they are not guaranteed to do so, and they provide opportunities for surprising issues with unexpected use of stack size.
Proposal
We propose a new operation that defines a finer-grain allocation scope for the alloca-allocated memory called alloca_scope
:
alloca_scope {
%x_temp = alloca …
...
}
Here the lifetime of %x_temp
is going to be bound to the narrow region within alloca_scope
. Moreover, one can also return values out of the alloca_scope with an accompanying alloca_scope.return
op (that behaves similarly to scf.yield
):
%result = alloca_scope {
%x_temp = alloca …
…
alloca_scope.return %myvalue
}
Under the hood the alloca_scope
is going to lowered to a combination of llvm.intr.stacksave
and llvm.intr.strackrestore
that are going to be invoked automatically as control-flow enters and leaves the body of the alloca_scope
.
The key value of the new op is to allow deterministic guaranteed stack use through an explicit region in the code which is finer-grain than the function-level scope of AutomaticAllocationScope
interface. alloca_scope
can be inserted at arbitrary locations and doesn’t require non-trivial transformations such as outlining.
Which dialect
Before memref dialect is split, alloca_scope
can temporarily reside in std
dialect, and later on be moved to memref
together with the rest of memory-related operations.
Implementation
An implementation of the op is available here.