17#include <mlir/IR/Builders.h>
18#include <mlir/IR/Value.h>
20#include <llvm/ADT/DenseMap.h>
45 unsigned protections = 0;
46 llvm::DenseMap<mlir::ArrayAttr, mlir::Value> leaves;
49 mlir::Builder builder;
50 llvm::SmallVector<Root> roots;
54 mlir::Value, llvm::ArrayRef<mlir::Attribute>, mlir::Type, mlir::Operation *
61 unsigned id = roots.size();
63 roots.back().input = input;
64 roots.back().storage = storage;
65 return {id, builder.getArrayAttr({}), type};
70 llvm::SmallVector<mlir::Attribute> path(parent.
steps.begin(), parent.
steps.end());
72 return {parent.
root, builder.getArrayAttr(path), type};
77 auto type = llvm::cast<array::ArrayType>(parent.
type);
78 auto shape = type.getShape().drop_front();
80 shape.empty() ? type.getElementType() : type.cloneWith(shape, type.getElementType());
81 return child(parent, builder.getIndexAttr(index), selected);
85 mlir::FailureOr<AccessPath>
select(
AccessPath path, mlir::Attribute step, mlir::Operation *site) {
86 if (
auto index = llvm::dyn_cast<mlir::IntegerAttr>(step)) {
87 auto type = llvm::dyn_cast<array::ArrayType>(path.
type);
88 if (!type || type.getShape().front() < 0) {
91 int64_t coordinate = index.getInt();
92 if (coordinate < 0 || coordinate >= type.getShape().front()) {
95 return element(path, coordinate);
97 auto type = llvm::dyn_cast<pod::PodType>(path.
type);
98 auto name = llvm::dyn_cast<mlir::StringAttr>(step);
102 auto record = type.getRecord(name.getValue(), [site] {
103 return site->emitError(CONSTRAINT_DIAGNOSTIC_PREFIX);
105 if (mlir::failed(record)) {
106 return mlir::failure();
108 return child(path, name, *record);
114 llvm::function_ref<mlir::LogicalResult(
AccessPath)> visit
116 auto type = llvm::dyn_cast<array::ArrayType>(path.
type);
120 int64_t size = type.getShape().front();
124 for (int64_t i = 0; i < size; ++i) {
126 return mlir::failure();
129 return mlir::success();
135 llvm::function_ref<mlir::LogicalResult(
AccessPath)> visit
137 if (llvm::isa<mlir::NoneType>(path.
type)) {
138 return mlir::success();
140 if (llvm::isa<array::ArrayType>(path.
type)) {
142 return walk(item, site, visit);
145 if (
auto type = llvm::dyn_cast<pod::PodType>(path.
type)) {
146 for (
auto record : type.getRecords()) {
147 auto field =
child(path, record.getName(), record.getType());
148 if (mlir::failed(
walk(field, site, visit))) {
149 return mlir::failure();
152 return mlir::success();
159 auto &leaves = roots[path.
root].leaves;
160 if (
auto found = leaves.find(path.
steps); found != leaves.end()) {
161 return found->second;
163 if (mlir::Value storage = roots[path.
root].storage) {
164 auto value = read(storage, path.
steps.getValue(), path.
type, site);
165 if (mlir::failed(value)) {
166 return mlir::failure();
168 leaves[path.
steps] = *value;
172 site, (roots[path.
root].input || roots[path.
root].protections)
173 ?
"read of uninitialized function input storage"
174 :
"read of uninitialized local storage"
186 const Root &root = roots[path.
root];
187 if (root.input || root.storage || root.protections) {
188 return constraintError(site,
"cannot write to function input or original storage");
190 return mlir::success();
200 llvm::SmallVector<std::pair<mlir::ArrayAttr, mlir::Value>> snapshot;
201 bool original = bool(roots[
source.root].storage);
202 auto collect = [
this, original, site, read, destination,
source,
203 &snapshot](
AccessPath leaf) -> mlir::LogicalResult {
204 const auto &leaves = roots[leaf.root].leaves;
205 if (!leaves.contains(leaf.steps) && !original) {
206 return mlir::success();
208 auto value =
load(leaf, site, read);
209 if (mlir::failed(value)) {
210 return mlir::failure();
213 for (
auto step : leaf.steps.getValue().drop_front(
source.steps.size())) {
214 auto selected =
select(target, step, site);
215 if (mlir::failed(selected)) {
216 return mlir::failure();
220 snapshot.push_back({target.
steps, *value});
221 return mlir::success();
223 if (mlir::failed(
walk(
source, site, collect))) {
224 return mlir::failure();
228 if (mlir::failed(
walk(destination, site, [
this](
AccessPath leaf) {
229 roots[leaf.
root].leaves.erase(leaf.
steps);
230 return mlir::success();
232 return mlir::failure();
234 auto &targetLeaves = roots[destination.
root].leaves;
235 for (
auto [path, value] : snapshot) {
236 targetLeaves[path] = value;
238 return mlir::success();
Apache License January AND DISTRIBUTION Definitions License shall mean the terms and conditions for and distribution as defined by Sections through of this document Licensor shall mean the copyright owner or entity authorized by the copyright owner that is granting the License Legal Entity shall mean the union of the acting entity and all other entities that control are controlled by or are under common control with that entity For the purposes of this definition control direct or to cause the direction or management of such whether by contract or including but not limited to software source documentation source
mlir::LogicalResult writable(AccessPath path, mlir::Operation *site) const
Reject writes based on destination identity, never scalar provenance.
void unprotect(AccessPath path)
Release one call's protection; enclosing calls retain their own protection.
AccessPath element(AccessPath parent, int64_t index)
Select one dimension; callers check that the coordinate is static/in-bounds.
mlir::FailureOr< mlir::Value > load(AccessPath path, mlir::Operation *site, StorageReader read)
Resolve a scalar binding; original storage is read only when needed.
mlir::LogicalResult elements(AccessPath path, mlir::Operation *site, llvm::function_ref< mlir::LogicalResult(AccessPath)> visit)
Visit array elements in row-major order, preserving aggregate element types.
mlir::FailureOr< AccessPath > select(AccessPath path, mlir::Attribute step, mlir::Operation *site)
Resolve one concrete step, including those transferred into a destination.
void protect(AccessPath path)
Temporarily make an argument root read-only without copying its identity.
mlir::LogicalResult walk(AccessPath path, mlir::Operation *site, llvm::function_ref< mlir::LogicalResult(AccessPath)> visit)
Enumerate scalar leaves using types, without allocating aggregate objects.
void store(AccessPath path, mlir::Value value)
Bind a scalar leaf during initialization or after checking writability.
llvm::function_ref< mlir::FailureOr< mlir::Value >( mlir::Value, llvm::ArrayRef< mlir::Attribute >, mlir::Type, mlir::Operation *)> StorageReader
AccessPath child(AccessPath parent, mlir::Attribute step, mlir::Type type)
Extend an already-validated path with one record or coordinate.
AccessPath create(mlir::Type type, mlir::Value input={}, mlir::Value storage={})
Create a root for a local allocation, function argument, or original storage.
mlir::LogicalResult transfer(AccessPath destination, AccessPath source, mlir::Operation *site, StorageReader read)
Snapshot leaves before replacing a subtree, including overlapping copies.
ConstraintBindings(mlir::MLIRContext *context)
Common interface for constant parameter-like symbol operations that can be defined within a TemplateO...
mlir::LogicalResult constraintError(mlir::Operation *site, const llvm::Twine &message)
Emit the common diagnostic prefix for constraint expansion and storage helpers.
std::variant< mlir::Value, AccessPath > BoundValue
Scalar expressions are SSA; aggregates are paths, never emitted allocations.
llvm::DenseMap< mlir::Value, BoundValue > Environment
A concrete subtree of one execution's storage.