[Mlir-commits] [mlir] b059b20 - [mlir][affine] Add optional alignment attribute to affine load/store ops (#214532)
llvmlistbot at llvm.org
llvmlistbot at llvm.org
Fri Aug 7 14:00:18 PDT 2026
Author: William Moses
Date: 2026-08-07T16:00:13-05:00
New Revision: b059b204792b75c9860b7e038f16088776178ca7
URL: https://github.com/llvm/llvm-project/commit/b059b204792b75c9860b7e038f16088776178ca7
DIFF: https://github.com/llvm/llvm-project/commit/b059b204792b75c9860b7e038f16088776178ca7.diff
LOG: [mlir][affine] Add optional alignment attribute to affine load/store ops (#214532)
Give `affine.load`, `affine.store`, `affine.vector_load` and
`affine.vector_store` the same optional `alignment` attribute that
`memref.load`/`memref.store` and `vector.load`/`vector.store` already
carry, via the same `AlignmentAttrOpInterface` and `IntValidAlignment`
constraint, and keep it standing where those ops are rebuilt:
- `--lower-affine` forwards the alignment onto the `memref`/`vector`
access it creates (previously it was dropped, since the lowering
rebuilds the access without carrying attributes over).
- The map-composition canonicalizer (`SimplifyAffineOp`) carries the
alignment over when it rebuilds an access with a composed map.
**Motivation.** Without a way to state alignment on the affine ops, a
frontend that raises an under-aligned llvm access through affine and
back must either give up on raising it, or watch the alignment silently
upgrade to the element type's ABI alignment on the way back down. That
upgrade is a miscompile: clang emits `load i128, align 8` for a 16-byte
member swap at a struct offset that is 8 mod 16; round-tripped through
affine without the alignment, the load comes back `align 16` and the
backend is entitled to `movaps`, which traps on the real address. (Found
in the wild raising MFEM through polygeist-style passes; the out-of-tree
pipeline currently has to lower attributed affine accesses itself before
`--lower-affine` to avoid the drop — this patch makes that workaround
unnecessary.)
Tests: round-trip parsing (`Dialect/Affine/ops.mlir`), verifier
rejection of non-power-of-two alignment (`invalid.mlir`), alignment
forwarding in `--lower-affine` for both scalar and vector forms
(`Conversion/AffineToStandard/lower-affine.mlir`), and preservation
through map-composition canonicalization (`canonicalize.mlir`).
Assisted-by: Claude
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply at anthropic.com>
Added:
Modified:
mlir/include/mlir/Dialect/Affine/IR/AffineOps.h
mlir/include/mlir/Dialect/Affine/IR/AffineOps.td
mlir/lib/Conversion/AffineToStandard/AffineToStandard.cpp
mlir/lib/Dialect/Affine/IR/AffineOps.cpp
mlir/test/Conversion/AffineToStandard/lower-affine.mlir
mlir/test/Dialect/Affine/canonicalize.mlir
mlir/test/Dialect/Affine/invalid.mlir
mlir/test/Dialect/Affine/ops.mlir
utils/bazel/llvm-project-overlay/mlir/BUILD.bazel
Removed:
################################################################################
diff --git a/mlir/include/mlir/Dialect/Affine/IR/AffineOps.h b/mlir/include/mlir/Dialect/Affine/IR/AffineOps.h
index 20d7f6436a896..c5cd8c6c31375 100644
--- a/mlir/include/mlir/Dialect/Affine/IR/AffineOps.h
+++ b/mlir/include/mlir/Dialect/Affine/IR/AffineOps.h
@@ -19,6 +19,7 @@
#include "mlir/Dialect/Utils/StaticValueUtils.h"
#include "mlir/IR/AffineMap.h"
#include "mlir/IR/Builders.h"
+#include "mlir/Interfaces/AlignmentAttrInterface.h"
#include "mlir/Interfaces/ControlFlowInterfaces.h"
#include "mlir/Interfaces/LoopLikeInterface.h"
namespace mlir {
diff --git a/mlir/include/mlir/Dialect/Affine/IR/AffineOps.td b/mlir/include/mlir/Dialect/Affine/IR/AffineOps.td
index 57cbbb06b9f65..05db39eb571a6 100644
--- a/mlir/include/mlir/Dialect/Affine/IR/AffineOps.td
+++ b/mlir/include/mlir/Dialect/Affine/IR/AffineOps.td
@@ -15,6 +15,7 @@
include "mlir/Dialect/Arith/IR/ArithBase.td"
include "mlir/Dialect/Affine/IR/AffineMemoryOpInterfaces.td"
+include "mlir/Interfaces/AlignmentAttrInterface.td"
include "mlir/Interfaces/ControlFlowInterfaces.td"
include "mlir/Interfaces/InferIntDivisibilityOpInterface.td"
include "mlir/Interfaces/InferIntRangeInterface.td"
@@ -480,11 +481,13 @@ class AffineLoadOpBase<string mnemonic, list<Trait> traits = []> :
Affine_Op<mnemonic, !listconcat(traits,
[DeclareOpInterfaceMethods<AffineReadOpInterface>,
DeclareOpInterfaceMethods<AffineMapAccessInterface>,
+ DeclareOpInterfaceMethods<AlignmentAttrOpInterface>,
MemRefsNormalizable])> {
let arguments = (ins Arg<AnyMemRef, "the reference to load from",
[MemRead]>:$memref,
Variadic<Index>:$indices,
- AffineMapAttr:$map);
+ AffineMapAttr:$map,
+ OptionalAttr<IntValidAlignment<I64Attr>>:$alignment);
code extraClassDeclarationBase = [{
/// Returns the operand index of the memref.
@@ -528,18 +531,27 @@ def AffineLoadOp : AffineLoadOpBase<"load"> {
```mlir
%1 = affine.load %0[%i0 + symbol(%n), %i1 + symbol(%m)] : memref<100x100xf32>
```
+
+ An optional `alignment` attribute allows to specify the byte alignment of
+ the load operation. It must be a positive power of 2. The operation must
+ access memory at an address aligned to this boundary. Violations may lead
+ to architecture-specific faults or performance penalties.
+ A value of 0 indicates no specific alignment requirement.
}];
let results = (outs AnyType:$result);
let builders = [
/// Builds an affine load op with the specified map and operands.
- OpBuilder<(ins "AffineMap":$map, "ValueRange":$operands)>,
+ OpBuilder<(ins "AffineMap":$map, "ValueRange":$operands,
+ CArg<"llvm::MaybeAlign", "llvm::MaybeAlign()">:$alignment)>,
/// Builds an affine load op with an identity map and operands.
- OpBuilder<(ins "Value":$memref, CArg<"ValueRange", "{}">:$indices)>,
+ OpBuilder<(ins "Value":$memref, CArg<"ValueRange", "{}">:$indices,
+ CArg<"llvm::MaybeAlign", "llvm::MaybeAlign()">:$alignment)>,
/// Builds an affine load op with the specified map and its operands.
OpBuilder<(ins "Value":$memref, "AffineMap":$map,
- "ValueRange":$mapOperands)>
+ "ValueRange":$mapOperands,
+ CArg<"llvm::MaybeAlign", "llvm::MaybeAlign()">:$alignment)>
];
let extraClassDeclaration = extraClassDeclarationBase;
@@ -847,6 +859,7 @@ class AffineStoreOpBase<string mnemonic, list<Trait> traits = []> :
Affine_Op<mnemonic, !listconcat(traits,
[DeclareOpInterfaceMethods<AffineWriteOpInterface>,
DeclareOpInterfaceMethods<AffineMapAccessInterface>,
+ DeclareOpInterfaceMethods<AlignmentAttrOpInterface>,
MemRefsNormalizable])> {
code extraClassDeclarationBase = [{
/// Returns the operand index of the value to be stored.
@@ -893,19 +906,28 @@ def AffineStoreOp : AffineStoreOpBase<"store"> {
```mlir
affine.store %v0, %0[%i0 + symbol(%n), %i1 + symbol(%m)] : memref<100x100xf32>
```
+
+ An optional `alignment` attribute allows to specify the byte alignment of
+ the store operation. It must be a positive power of 2. The operation must
+ access memory at an address aligned to this boundary. Violations may lead
+ to architecture-specific faults or performance penalties.
+ A value of 0 indicates no specific alignment requirement.
}];
let arguments = (ins AnyType:$value,
Arg<AnyMemRef, "the reference to store to",
[MemWrite]>:$memref,
Variadic<Index>:$indices,
- AffineMapAttr:$map);
+ AffineMapAttr:$map,
+ OptionalAttr<IntValidAlignment<I64Attr>>:$alignment);
let skipDefaultBuilders = 1;
let builders = [
OpBuilder<(ins "Value":$valueToStore, "Value":$memref,
- "ValueRange":$indices)>,
+ "ValueRange":$indices,
+ CArg<"llvm::MaybeAlign", "llvm::MaybeAlign()">:$alignment)>,
OpBuilder<(ins "Value":$valueToStore, "Value":$memref, "AffineMap":$map,
- "ValueRange":$mapOperands)>
+ "ValueRange":$mapOperands,
+ CArg<"llvm::MaybeAlign", "llvm::MaybeAlign()">:$alignment)>
];
let extraClassDeclaration = extraClassDeclarationBase;
@@ -984,13 +1006,16 @@ def AffineVectorLoadOp : AffineLoadOpBase<"vector_load"> {
let builders = [
/// Builds an affine vector load op with the specified map and operands.
OpBuilder<(ins "VectorType":$resultType, "AffineMap":$map,
- "ValueRange":$operands)>,
+ "ValueRange":$operands,
+ CArg<"llvm::MaybeAlign", "llvm::MaybeAlign()">:$alignment)>,
/// Builds an affine vector load op with an identity map and operands.
OpBuilder<(ins "VectorType":$resultType, "Value":$memref,
- CArg<"ValueRange", "{}">:$indices)>,
+ CArg<"ValueRange", "{}">:$indices,
+ CArg<"llvm::MaybeAlign", "llvm::MaybeAlign()">:$alignment)>,
/// Builds an affine vector load op with the specified map and its operands.
OpBuilder<(ins "VectorType":$resultType, "Value":$memref,
- "AffineMap":$map, "ValueRange":$mapOperands)>
+ "AffineMap":$map, "ValueRange":$mapOperands,
+ CArg<"llvm::MaybeAlign", "llvm::MaybeAlign()">:$alignment)>
];
let extraClassDeclaration = extraClassDeclarationBase # [{
@@ -1050,14 +1075,17 @@ def AffineVectorStoreOp : AffineStoreOpBase<"vector_store"> {
Arg<AnyMemRef, "the reference to store to",
[MemWrite]>:$memref,
Variadic<Index>:$indices,
- AffineMapAttr:$map);
+ AffineMapAttr:$map,
+ OptionalAttr<IntValidAlignment<I64Attr>>:$alignment);
let skipDefaultBuilders = 1;
let builders = [
OpBuilder<(ins "Value":$valueToStore, "Value":$memref,
- "ValueRange":$indices)>,
+ "ValueRange":$indices,
+ CArg<"llvm::MaybeAlign", "llvm::MaybeAlign()">:$alignment)>,
OpBuilder<(ins "Value":$valueToStore, "Value":$memref, "AffineMap":$map,
- "ValueRange":$mapOperands)>
+ "ValueRange":$mapOperands,
+ CArg<"llvm::MaybeAlign", "llvm::MaybeAlign()">:$alignment)>
];
let extraClassDeclaration = extraClassDeclarationBase # [{
diff --git a/mlir/lib/Conversion/AffineToStandard/AffineToStandard.cpp b/mlir/lib/Conversion/AffineToStandard/AffineToStandard.cpp
index 826d7547716e4..367826c93e243 100644
--- a/mlir/lib/Conversion/AffineToStandard/AffineToStandard.cpp
+++ b/mlir/lib/Conversion/AffineToStandard/AffineToStandard.cpp
@@ -363,9 +363,10 @@ class AffineLoadLowering : public OpRewritePattern<AffineLoadOp> {
if (!resultOperands)
return failure();
- // Build vector.load memref[expandedMap.results].
- rewriter.replaceOpWithNewOp<memref::LoadOp>(op, op.getMemRef(),
- *resultOperands);
+ // Build memref.load memref[expandedMap.results].
+ rewriter.replaceOpWithNewOp<memref::LoadOp>(
+ op, op.getMemRef(), *resultOperands,
+ /*nontemporal=*/false, op.getMaybeAlign());
return success();
}
};
@@ -412,7 +413,8 @@ class AffineStoreLowering : public OpRewritePattern<AffineStoreOp> {
// Build memref.store valueToStore, memref[expandedMap.results].
rewriter.replaceOpWithNewOp<memref::StoreOp>(
- op, op.getValueToStore(), op.getMemRef(), *maybeExpandedMap);
+ op, op.getValueToStore(), op.getMemRef(), *maybeExpandedMap,
+ /*nontemporal=*/false, op.getMaybeAlign());
return success();
}
};
@@ -499,7 +501,8 @@ class AffineVectorLoadLowering : public OpRewritePattern<AffineVectorLoadOp> {
// Build vector.load memref[expandedMap.results].
rewriter.replaceOpWithNewOp<vector::LoadOp>(
- op, op.getVectorType(), op.getMemRef(), *resultOperands);
+ op, op.getVectorType(), op.getMemRef(), *resultOperands,
+ /*nontemporal=*/false, op.getMaybeAlign());
return success();
}
};
@@ -521,7 +524,8 @@ class AffineVectorStoreLowering : public OpRewritePattern<AffineVectorStoreOp> {
return failure();
rewriter.replaceOpWithNewOp<vector::StoreOp>(
- op, op.getValueToStore(), op.getMemRef(), *maybeExpandedMap);
+ op, op.getValueToStore(), op.getMemRef(), *maybeExpandedMap,
+ /*nontemporal=*/false, op.getMaybeAlign());
return success();
}
};
diff --git a/mlir/lib/Dialect/Affine/IR/AffineOps.cpp b/mlir/lib/Dialect/Affine/IR/AffineOps.cpp
index 98c2be14da5aa..8523c902d0a6f 100644
--- a/mlir/lib/Dialect/Affine/IR/AffineOps.cpp
+++ b/mlir/lib/Dialect/Affine/IR/AffineOps.cpp
@@ -1810,7 +1810,7 @@ void SimplifyAffineOp<AffineLoadOp>::replaceAffineOp(
PatternRewriter &rewriter, AffineLoadOp load, AffineMap map,
ArrayRef<Value> mapOperands) const {
rewriter.replaceOpWithNewOp<AffineLoadOp>(load, load.getMemRef(), map,
- mapOperands);
+ mapOperands, load.getMaybeAlign());
}
template <>
void SimplifyAffineOp<AffinePrefetchOp>::replaceAffineOp(
@@ -1825,7 +1825,8 @@ void SimplifyAffineOp<AffineStoreOp>::replaceAffineOp(
PatternRewriter &rewriter, AffineStoreOp store, AffineMap map,
ArrayRef<Value> mapOperands) const {
rewriter.replaceOpWithNewOp<AffineStoreOp>(
- store, store.getValueToStore(), store.getMemRef(), map, mapOperands);
+ store, store.getValueToStore(), store.getMemRef(), map, mapOperands,
+ store.getMaybeAlign());
}
template <>
void SimplifyAffineOp<AffineVectorLoadOp>::replaceAffineOp(
@@ -1833,7 +1834,7 @@ void SimplifyAffineOp<AffineVectorLoadOp>::replaceAffineOp(
ArrayRef<Value> mapOperands) const {
rewriter.replaceOpWithNewOp<AffineVectorLoadOp>(
vectorload, vectorload.getVectorType(), vectorload.getMemRef(), map,
- mapOperands);
+ mapOperands, vectorload.getMaybeAlign());
}
template <>
void SimplifyAffineOp<AffineVectorStoreOp>::replaceAffineOp(
@@ -1841,7 +1842,7 @@ void SimplifyAffineOp<AffineVectorStoreOp>::replaceAffineOp(
ArrayRef<Value> mapOperands) const {
rewriter.replaceOpWithNewOp<AffineVectorStoreOp>(
vectorstore, vectorstore.getValueToStore(), vectorstore.getMemRef(), map,
- mapOperands);
+ mapOperands, vectorstore.getMaybeAlign());
}
// Generic version for ops that don't have extra operands.
@@ -3381,39 +3382,54 @@ void AffineIfOp::getCanonicalizationPatterns(RewritePatternSet &results,
results.add<SimplifyDeadElse, AlwaysTrueOrFalseIf>(context);
}
+/// Adds the optional `alignment` attribute to `result`, if one is given.
+static void addAlignmentAttr(OpBuilder &builder, OperationState &result,
+ StringAttr attrName, llvm::MaybeAlign alignment) {
+ if (alignment)
+ result.addAttribute(attrName,
+ builder.getI64IntegerAttr(alignment->value()));
+}
+
//===----------------------------------------------------------------------===//
// AffineLoadOp
//===----------------------------------------------------------------------===//
void AffineLoadOp::build(OpBuilder &builder, OperationState &result,
- AffineMap map, ValueRange operands) {
+ AffineMap map, ValueRange operands,
+ llvm::MaybeAlign alignment) {
assert(operands.size() == 1 + map.getNumInputs() && "inconsistent operands");
result.addOperands(operands);
if (map)
result.addAttribute(getMapAttrStrName(), AffineMapAttr::get(map));
+ addAlignmentAttr(builder, result, getAlignmentAttrName(result.name),
+ alignment);
auto memrefType = llvm::cast<MemRefType>(operands[0].getType());
result.types.push_back(memrefType.getElementType());
}
void AffineLoadOp::build(OpBuilder &builder, OperationState &result,
- Value memref, AffineMap map, ValueRange mapOperands) {
+ Value memref, AffineMap map, ValueRange mapOperands,
+ llvm::MaybeAlign alignment) {
assert(map.getNumInputs() == mapOperands.size() && "inconsistent index info");
result.addOperands(memref);
result.addOperands(mapOperands);
auto memrefType = llvm::cast<MemRefType>(memref.getType());
result.addAttribute(getMapAttrStrName(), AffineMapAttr::get(map));
+ addAlignmentAttr(builder, result, getAlignmentAttrName(result.name),
+ alignment);
result.types.push_back(memrefType.getElementType());
}
void AffineLoadOp::build(OpBuilder &builder, OperationState &result,
- Value memref, ValueRange indices) {
+ Value memref, ValueRange indices,
+ llvm::MaybeAlign alignment) {
auto memrefType = llvm::cast<MemRefType>(memref.getType());
int64_t rank = memrefType.getRank();
// Create identity map for memrefs with at least one dimension or () -> ()
// for zero-dimensional memrefs.
auto map =
rank ? builder.getMultiDimIdentityMap(rank) : builder.getEmptyAffineMap();
- build(builder, result, memref, map, indices);
+ build(builder, result, memref, map, indices, alignment);
}
ParseResult AffineLoadOp::parse(OpAsmParser &parser, OperationState &result) {
@@ -3527,25 +3543,27 @@ OpFoldResult AffineLoadOp::fold(FoldAdaptor adaptor) {
void AffineStoreOp::build(OpBuilder &builder, OperationState &result,
Value valueToStore, Value memref, AffineMap map,
- ValueRange mapOperands) {
+ ValueRange mapOperands, llvm::MaybeAlign alignment) {
assert(map.getNumInputs() == mapOperands.size() && "inconsistent index info");
result.addOperands(valueToStore);
result.addOperands(memref);
result.addOperands(mapOperands);
result.getOrAddProperties<Properties>().map = AffineMapAttr::get(map);
+ addAlignmentAttr(builder, result, getAlignmentAttrName(result.name),
+ alignment);
}
// Use identity map.
void AffineStoreOp::build(OpBuilder &builder, OperationState &result,
- Value valueToStore, Value memref,
- ValueRange indices) {
+ Value valueToStore, Value memref, ValueRange indices,
+ llvm::MaybeAlign alignment) {
auto memrefType = llvm::cast<MemRefType>(memref.getType());
int64_t rank = memrefType.getRank();
// Create identity map for memrefs with at least one dimension or () -> ()
// for zero-dimensional memrefs.
auto map =
rank ? builder.getMultiDimIdentityMap(rank) : builder.getEmptyAffineMap();
- build(builder, result, valueToStore, memref, map, indices);
+ build(builder, result, valueToStore, memref, map, indices, alignment);
}
ParseResult AffineStoreOp::parse(OpAsmParser &parser, OperationState &result) {
@@ -4737,34 +4755,40 @@ LogicalResult AffineYieldOp::verify() {
void AffineVectorLoadOp::build(OpBuilder &builder, OperationState &result,
VectorType resultType, AffineMap map,
- ValueRange operands) {
+ ValueRange operands,
+ llvm::MaybeAlign alignment) {
assert(operands.size() == 1 + map.getNumInputs() && "inconsistent operands");
result.addOperands(operands);
if (map)
result.addAttribute(getMapAttrStrName(), AffineMapAttr::get(map));
+ addAlignmentAttr(builder, result, getAlignmentAttrName(result.name),
+ alignment);
result.types.push_back(resultType);
}
void AffineVectorLoadOp::build(OpBuilder &builder, OperationState &result,
VectorType resultType, Value memref,
- AffineMap map, ValueRange mapOperands) {
+ AffineMap map, ValueRange mapOperands,
+ llvm::MaybeAlign alignment) {
assert(map.getNumInputs() == mapOperands.size() && "inconsistent index info");
result.addOperands(memref);
result.addOperands(mapOperands);
result.addAttribute(getMapAttrStrName(), AffineMapAttr::get(map));
+ addAlignmentAttr(builder, result, getAlignmentAttrName(result.name),
+ alignment);
result.types.push_back(resultType);
}
void AffineVectorLoadOp::build(OpBuilder &builder, OperationState &result,
VectorType resultType, Value memref,
- ValueRange indices) {
+ ValueRange indices, llvm::MaybeAlign alignment) {
auto memrefType = llvm::cast<MemRefType>(memref.getType());
int64_t rank = memrefType.getRank();
// Create identity map for memrefs with at least one dimension or () -> ()
// for zero-dimensional memrefs.
auto map =
rank ? builder.getMultiDimIdentityMap(rank) : builder.getEmptyAffineMap();
- build(builder, result, resultType, memref, map, indices);
+ build(builder, result, resultType, memref, map, indices, alignment);
}
void AffineVectorLoadOp::getCanonicalizationPatterns(RewritePatternSet &results,
@@ -4836,25 +4860,29 @@ LogicalResult AffineVectorLoadOp::verify() {
void AffineVectorStoreOp::build(OpBuilder &builder, OperationState &result,
Value valueToStore, Value memref, AffineMap map,
- ValueRange mapOperands) {
+ ValueRange mapOperands,
+ llvm::MaybeAlign alignment) {
assert(map.getNumInputs() == mapOperands.size() && "inconsistent index info");
result.addOperands(valueToStore);
result.addOperands(memref);
result.addOperands(mapOperands);
result.addAttribute(getMapAttrStrName(), AffineMapAttr::get(map));
+ addAlignmentAttr(builder, result, getAlignmentAttrName(result.name),
+ alignment);
}
// Use identity map.
void AffineVectorStoreOp::build(OpBuilder &builder, OperationState &result,
Value valueToStore, Value memref,
- ValueRange indices) {
+ ValueRange indices,
+ llvm::MaybeAlign alignment) {
auto memrefType = llvm::cast<MemRefType>(memref.getType());
int64_t rank = memrefType.getRank();
// Create identity map for memrefs with at least one dimension or () -> ()
// for zero-dimensional memrefs.
auto map =
rank ? builder.getMultiDimIdentityMap(rank) : builder.getEmptyAffineMap();
- build(builder, result, valueToStore, memref, map, indices);
+ build(builder, result, valueToStore, memref, map, indices, alignment);
}
void AffineVectorStoreOp::getCanonicalizationPatterns(
RewritePatternSet &results, MLIRContext *context) {
diff --git a/mlir/test/Conversion/AffineToStandard/lower-affine.mlir b/mlir/test/Conversion/AffineToStandard/lower-affine.mlir
index 550ea71882e14..943b8675d183c 100644
--- a/mlir/test/Conversion/AffineToStandard/lower-affine.mlir
+++ b/mlir/test/Conversion/AffineToStandard/lower-affine.mlir
@@ -927,3 +927,28 @@ func.func @affine_parallel_with_reductions_i64(%arg0: memref<3x3xi64>, %arg1: me
// CHECK: scf.reduce.return %[[RES]] : i64
// CHECK: }
// CHECK: }
+
+// -----
+
+// The alignment an affine access promises stays on the memref access it
+// becomes.
+
+// CHECK-LABEL: func @affine_load_store_alignment
+func.func @affine_load_store_alignment(%memref: memref<4xi32>) {
+ // CHECK: memref.load {{.*}} {alignment = 16 : i64}
+ %val = affine.load %memref[0] { alignment = 16 } : memref<4xi32>
+ // CHECK: memref.store {{.*}} {alignment = 16 : i64}
+ affine.store %val, %memref[0] { alignment = 16 } : memref<4xi32>
+ return
+}
+
+// -----
+
+// CHECK-LABEL: func @affine_vector_load_store_alignment
+func.func @affine_vector_load_store_alignment(%memref: memref<16xi32>) {
+ // CHECK: vector.load {{.*}} {alignment = 8 : i64}
+ %val = affine.vector_load %memref[0] { alignment = 8 } : memref<16xi32>, vector<4xi32>
+ // CHECK: vector.store {{.*}} {alignment = 8 : i64}
+ affine.vector_store %val, %memref[0] { alignment = 8 } : memref<16xi32>, vector<4xi32>
+ return
+}
diff --git a/mlir/test/Dialect/Affine/canonicalize.mlir b/mlir/test/Dialect/Affine/canonicalize.mlir
index 7d236ef3c2421..90216f8dc2b8b 100644
--- a/mlir/test/Dialect/Affine/canonicalize.mlir
+++ b/mlir/test/Dialect/Affine/canonicalize.mlir
@@ -2614,3 +2614,21 @@ func.func @split_delinearize_spanning_final_part_vector(
%1:4 = affine.delinearize_index %0 into (2, 3, 8, 4) : vector<4xindex>, vector<4xindex>, vector<4xindex>, vector<4xindex>
return %1#0, %1#1, %1#2, %1#3 : vector<4xindex>, vector<4xindex>, vector<4xindex>, vector<4xindex>
}
+
+// -----
+
+// Composing an affine.apply into an access rebuilds the op; the alignment it
+// promised stays on it.
+
+// CHECK-LABEL: func @compose_into_access_keeps_alignment
+// CHECK-BOTTOM-UP-LABEL: func @compose_into_access_keeps_alignment
+func.func @compose_into_access_keeps_alignment(%memref: memref<100xi32>, %i: index) {
+ %idx = affine.apply affine_map<(d0) -> (d0 + 1)>(%i)
+ // CHECK: affine.load {{.*}} {alignment = 16 : i64}
+ // CHECK-BOTTOM-UP: affine.load {{.*}} {alignment = 16 : i64}
+ %val = affine.load %memref[%idx] { alignment = 16 } : memref<100xi32>
+ // CHECK: affine.store {{.*}} {alignment = 16 : i64}
+ // CHECK-BOTTOM-UP: affine.store {{.*}} {alignment = 16 : i64}
+ affine.store %val, %memref[%idx] { alignment = 16 } : memref<100xi32>
+ return
+}
diff --git a/mlir/test/Dialect/Affine/invalid.mlir b/mlir/test/Dialect/Affine/invalid.mlir
index ae209b4092d98..3afebfcc07628 100644
--- a/mlir/test/Dialect/Affine/invalid.mlir
+++ b/mlir/test/Dialect/Affine/invalid.mlir
@@ -642,3 +642,19 @@ func.func @affine_for_missing_induction_var() {
}) : () -> ()
return
}
+
+// -----
+
+func.func @affine_load_alignment_not_power_of_2(%M : memref<10xi32>) {
+ // expected-error at +1 {{'affine.load' op attribute 'alignment' failed to satisfy constraint: 64-bit signless integer attribute whose value is positive and whose value is a power of two > 0}}
+ %v = affine.load %M[0] { alignment = 12 } : memref<10xi32>
+ return
+}
+
+// -----
+
+func.func @affine_store_alignment_not_power_of_2(%M : memref<10xi32>, %v : i32) {
+ // expected-error at +1 {{'affine.store' op attribute 'alignment' failed to satisfy constraint: 64-bit signless integer attribute whose value is positive and whose value is a power of two > 0}}
+ affine.store %v, %M[0] { alignment = 12 } : memref<10xi32>
+ return
+}
diff --git a/mlir/test/Dialect/Affine/ops.mlir b/mlir/test/Dialect/Affine/ops.mlir
index 35b07c1c7fe1f..148c130146f33 100644
--- a/mlir/test/Dialect/Affine/ops.mlir
+++ b/mlir/test/Dialect/Affine/ops.mlir
@@ -508,3 +508,25 @@ func.func @parallel_minnumf_reduce() {
return
}
+
+// -----
+
+// CHECK-LABEL: func.func @affine_load_store_alignment
+func.func @affine_load_store_alignment(%memref: memref<4xi32>) {
+ // CHECK: affine.load {{.*}} {alignment = 16 : i64}
+ %val = affine.load %memref[0] { alignment = 16 } : memref<4xi32>
+ // CHECK: affine.store {{.*}} {alignment = 16 : i64}
+ affine.store %val, %memref[0] { alignment = 16 } : memref<4xi32>
+ return
+}
+
+// -----
+
+// CHECK-LABEL: func.func @affine_vector_load_store_alignment
+func.func @affine_vector_load_store_alignment(%memref: memref<16xi32>) {
+ // CHECK: affine.vector_load {{.*}} {alignment = 8 : i64}
+ %val = affine.vector_load %memref[0] { alignment = 8 } : memref<16xi32>, vector<4xi32>
+ // CHECK: affine.vector_store {{.*}} {alignment = 8 : i64}
+ affine.vector_store %val, %memref[0] { alignment = 8 } : memref<16xi32>, vector<4xi32>
+ return
+}
diff --git a/utils/bazel/llvm-project-overlay/mlir/BUILD.bazel b/utils/bazel/llvm-project-overlay/mlir/BUILD.bazel
index 2246bea235cb2..fdfaa9dd2e168 100644
--- a/utils/bazel/llvm-project-overlay/mlir/BUILD.bazel
+++ b/utils/bazel/llvm-project-overlay/mlir/BUILD.bazel
@@ -1601,6 +1601,7 @@ td_library(
],
includes = ["include"],
deps = [
+ ":AlignmentAttrInterfaceTdFiles",
":ArithOpsTdFiles",
":FuncTdFiles",
":InferIntDivisibilityOpInterfaceTdFiles",
@@ -4142,6 +4143,7 @@ cc_library(
deps = [
":AffineMemoryOpInterfacesIncGen",
":AffineOpsIncGen",
+ ":AlignmentAttrInterface",
":ArithDialect",
":ControlFlowInterfaces",
":DialectUtils",
More information about the Mlir-commits
mailing list