Skip to content

Commit f66c876

Browse files
committed
[MLIR] Give AffineStoreOp and AffineLoadOp Memory SideEffects.
Summary: This change results in tests also being changed to prevent dead affine.load operations from being folded away during rewrites. Also move AffineStoreOp and AffineLoadOp to an ODS file. Differential Revision: https://reviews.llvm.org/D78930
1 parent d0846b4 commit f66c876

File tree

8 files changed

+266
-240
lines changed

8 files changed

+266
-240
lines changed

mlir/include/mlir/Dialect/Affine/IR/AffineOps.h

Lines changed: 0 additions & 141 deletions
Original file line numberDiff line numberDiff line change
@@ -316,147 +316,6 @@ class AffineDmaWaitOp : public Op<AffineDmaWaitOp, OpTrait::VariadicOperands,
316316
SmallVectorImpl<OpFoldResult> &results);
317317
};
318318

319-
/// The "affine.load" op reads an element from a memref, where the index
320-
/// for each memref dimension is an affine expression of loop induction
321-
/// variables and symbols. The output of 'affine.load' is a new value with the
322-
/// same type as the elements of the memref. An affine expression of loop IVs
323-
/// and symbols must be specified for each dimension of the memref. The keyword
324-
/// 'symbol' can be used to indicate SSA identifiers which are symbolic.
325-
//
326-
// Example 1:
327-
//
328-
// %1 = affine.load %0[%i0 + 3, %i1 + 7] : memref<100x100xf32>
329-
//
330-
// Example 2: Uses 'symbol' keyword for symbols '%n' and '%m'.
331-
//
332-
// %1 = affine.load %0[%i0 + symbol(%n), %i1 + symbol(%m)]
333-
// : memref<100x100xf32>
334-
//
335-
class AffineLoadOp : public Op<AffineLoadOp, OpTrait::OneResult,
336-
OpTrait::AtLeastNOperands<1>::Impl> {
337-
public:
338-
using Op::Op;
339-
340-
/// Builds an affine load op with the specified map and operands.
341-
static void build(OpBuilder &builder, OperationState &result, AffineMap map,
342-
ValueRange operands);
343-
/// Builds an affine load op with an identity map and operands.
344-
static void build(OpBuilder &builder, OperationState &result, Value memref,
345-
ValueRange indices = {});
346-
/// Builds an affine load op with the specified map and its operands.
347-
static void build(OpBuilder &builder, OperationState &result, Value memref,
348-
AffineMap map, ValueRange mapOperands);
349-
350-
/// Returns the operand index of the memref.
351-
unsigned getMemRefOperandIndex() { return 0; }
352-
353-
/// Get memref operand.
354-
Value getMemRef() { return getOperand(getMemRefOperandIndex()); }
355-
void setMemRef(Value value) { setOperand(getMemRefOperandIndex(), value); }
356-
MemRefType getMemRefType() {
357-
return getMemRef().getType().cast<MemRefType>();
358-
}
359-
360-
/// Get affine map operands.
361-
operand_range getMapOperands() { return llvm::drop_begin(getOperands(), 1); }
362-
363-
/// Returns the affine map used to index the memref for this operation.
364-
AffineMap getAffineMap() { return getAffineMapAttr().getValue(); }
365-
AffineMapAttr getAffineMapAttr() {
366-
return getAttr(getMapAttrName()).cast<AffineMapAttr>();
367-
}
368-
369-
/// Returns the AffineMapAttr associated with 'memref'.
370-
NamedAttribute getAffineMapAttrForMemRef(Value memref) {
371-
assert(memref == getMemRef());
372-
return {Identifier::get(getMapAttrName(), getContext()),
373-
getAffineMapAttr()};
374-
}
375-
376-
static StringRef getMapAttrName() { return "map"; }
377-
static StringRef getOperationName() { return "affine.load"; }
378-
379-
// Hooks to customize behavior of this op.
380-
static ParseResult parse(OpAsmParser &parser, OperationState &result);
381-
void print(OpAsmPrinter &p);
382-
LogicalResult verify();
383-
static void getCanonicalizationPatterns(OwningRewritePatternList &results,
384-
MLIRContext *context);
385-
OpFoldResult fold(ArrayRef<Attribute> operands);
386-
};
387-
388-
/// The "affine.store" op writes an element to a memref, where the index
389-
/// for each memref dimension is an affine expression of loop induction
390-
/// variables and symbols. The 'affine.store' op stores a new value which is the
391-
/// same type as the elements of the memref. An affine expression of loop IVs
392-
/// and symbols must be specified for each dimension of the memref. The keyword
393-
/// 'symbol' can be used to indicate SSA identifiers which are symbolic.
394-
//
395-
// Example 1:
396-
//
397-
// affine.store %v0, %0[%i0 + 3, %i1 + 7] : memref<100x100xf32>
398-
//
399-
// Example 2: Uses 'symbol' keyword for symbols '%n' and '%m'.
400-
//
401-
// affine.store %v0, %0[%i0 + symbol(%n), %i1 + symbol(%m)]
402-
// : memref<100x100xf32>
403-
//
404-
class AffineStoreOp : public Op<AffineStoreOp, OpTrait::ZeroResult,
405-
OpTrait::AtLeastNOperands<1>::Impl> {
406-
public:
407-
using Op::Op;
408-
409-
/// Builds an affine store operation with the provided indices (identity map).
410-
static void build(OpBuilder &builder, OperationState &result,
411-
Value valueToStore, Value memref, ValueRange indices);
412-
/// Builds an affine store operation with the specified map and its operands.
413-
static void build(OpBuilder &builder, OperationState &result,
414-
Value valueToStore, Value memref, AffineMap map,
415-
ValueRange mapOperands);
416-
417-
/// Get value to be stored by store operation.
418-
Value getValueToStore() { return getOperand(0); }
419-
420-
/// Returns the operand index of the memref.
421-
unsigned getMemRefOperandIndex() { return 1; }
422-
423-
/// Get memref operand.
424-
Value getMemRef() { return getOperand(getMemRefOperandIndex()); }
425-
void setMemRef(Value value) { setOperand(getMemRefOperandIndex(), value); }
426-
427-
MemRefType getMemRefType() {
428-
return getMemRef().getType().cast<MemRefType>();
429-
}
430-
431-
/// Get affine map operands.
432-
operand_range getMapOperands() { return llvm::drop_begin(getOperands(), 2); }
433-
434-
/// Returns the affine map used to index the memref for this operation.
435-
AffineMap getAffineMap() { return getAffineMapAttr().getValue(); }
436-
AffineMapAttr getAffineMapAttr() {
437-
return getAttr(getMapAttrName()).cast<AffineMapAttr>();
438-
}
439-
440-
/// Returns the AffineMapAttr associated with 'memref'.
441-
NamedAttribute getAffineMapAttrForMemRef(Value memref) {
442-
assert(memref == getMemRef());
443-
return {Identifier::get(getMapAttrName(), getContext()),
444-
getAffineMapAttr()};
445-
}
446-
447-
static StringRef getMapAttrName() { return "map"; }
448-
static StringRef getOperationName() { return "affine.store"; }
449-
450-
// Hooks to customize behavior of this op.
451-
static ParseResult parse(OpAsmParser &parser, OperationState &result);
452-
void print(OpAsmPrinter &p);
453-
LogicalResult verify();
454-
static void getCanonicalizationPatterns(OwningRewritePatternList &results,
455-
MLIRContext *context);
456-
LogicalResult fold(ArrayRef<Attribute> cstOperands,
457-
SmallVectorImpl<OpFoldResult> &results);
458-
};
459-
460319
/// Returns true if the given Value can be used as a dimension id.
461320
bool isValidDim(Value value);
462321

mlir/include/mlir/Dialect/Affine/IR/AffineOps.td

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -360,6 +360,80 @@ def AffineIfOp : Affine_Op<"if",
360360
let hasFolder = 1;
361361
}
362362

363+
def AffineLoadOp : Affine_Op<"load", []> {
364+
let summary = "affine load operation";
365+
let description = [{
366+
The "affine.load" op reads an element from a memref, where the index
367+
for each memref dimension is an affine expression of loop induction
368+
variables and symbols. The output of 'affine.load' is a new value with the
369+
same type as the elements of the memref. An affine expression of loop IVs
370+
and symbols must be specified for each dimension of the memref. The keyword
371+
'symbol' can be used to indicate SSA identifiers which are symbolic.
372+
373+
Example 1:
374+
375+
```mlir
376+
%1 = affine.load %0[%i0 + 3, %i1 + 7] : memref<100x100xf32>
377+
```
378+
379+
Example 2: Uses 'symbol' keyword for symbols '%n' and '%m'.
380+
381+
```mlir
382+
%1 = affine.load %0[%i0 + symbol(%n), %i1 + symbol(%m)] : memref<100x100xf32>
383+
```
384+
}];
385+
386+
let arguments = (ins Arg<AnyMemRef, "the reference to load from",
387+
[MemRead]>:$memref,
388+
Variadic<Index>:$indices);
389+
let results = (outs AnyType:$result);
390+
391+
let builders = [
392+
/// Builds an affine load op with the specified map and operands.
393+
OpBuilder<"OpBuilder &builder, OperationState &result, AffineMap map, "
394+
"ValueRange operands">,
395+
/// Builds an affine load op with an identity map and operands.
396+
OpBuilder<"OpBuilder &builder, OperationState &result, Value memref, "
397+
"ValueRange indices = {}">,
398+
/// Builds an affine load op with the specified map and its operands.
399+
OpBuilder<"OpBuilder &builder, OperationState &result, Value memref, "
400+
"AffineMap map, ValueRange mapOperands">
401+
];
402+
403+
let extraClassDeclaration = [{
404+
/// Returns the operand index of the memref.
405+
unsigned getMemRefOperandIndex() { return 0; }
406+
407+
/// Get memref operand.
408+
Value getMemRef() { return getOperand(getMemRefOperandIndex()); }
409+
void setMemRef(Value value) { setOperand(getMemRefOperandIndex(), value); }
410+
MemRefType getMemRefType() {
411+
return getMemRef().getType().cast<MemRefType>();
412+
}
413+
414+
/// Get affine map operands.
415+
operand_range getMapOperands() { return llvm::drop_begin(getOperands(), 1); }
416+
417+
/// Returns the affine map used to index the memref for this operation.
418+
AffineMap getAffineMap() { return getAffineMapAttr().getValue(); }
419+
AffineMapAttr getAffineMapAttr() {
420+
return getAttr(getMapAttrName()).cast<AffineMapAttr>();
421+
}
422+
423+
/// Returns the AffineMapAttr associated with 'memref'.
424+
NamedAttribute getAffineMapAttrForMemRef(Value memref) {
425+
assert(memref == getMemRef());
426+
return {Identifier::get(getMapAttrName(), getContext()),
427+
getAffineMapAttr()};
428+
}
429+
430+
static StringRef getMapAttrName() { return "map"; }
431+
}];
432+
433+
let hasCanonicalizer = 1;
434+
let hasFolder = 1;
435+
}
436+
363437
class AffineMinMaxOpBase<string mnemonic, list<OpTrait> traits = []> :
364438
Op<Affine_Dialect, mnemonic, traits> {
365439
let arguments = (ins AffineMapAttr:$map, Variadic<Index>:$operands);
@@ -575,6 +649,81 @@ def AffinePrefetchOp : Affine_Op<"prefetch"> {
575649
let hasFolder = 1;
576650
}
577651

652+
def AffineStoreOp : Affine_Op<"store", []> {
653+
let summary = "affine store operation";
654+
let description = [{
655+
The "affine.store" op writes an element to a memref, where the index
656+
for each memref dimension is an affine expression of loop induction
657+
variables and symbols. The 'affine.store' op stores a new value which is the
658+
same type as the elements of the memref. An affine expression of loop IVs
659+
and symbols must be specified for each dimension of the memref. The keyword
660+
'symbol' can be used to indicate SSA identifiers which are symbolic.
661+
662+
Example 1:
663+
664+
```mlir
665+
affine.store %v0, %0[%i0 + 3, %i1 + 7] : memref<100x100xf32>
666+
```
667+
668+
Example 2: Uses 'symbol' keyword for symbols '%n' and '%m'.
669+
670+
```mlir
671+
affine.store %v0, %0[%i0 + symbol(%n), %i1 + symbol(%m)] : memref<100x100xf32>
672+
```
673+
}];
674+
let arguments = (ins AnyType:$value,
675+
Arg<AnyMemRef, "the reference to store to",
676+
[MemWrite]>:$memref,
677+
Variadic<Index>:$indices);
678+
679+
680+
let skipDefaultBuilders = 1;
681+
let builders = [
682+
OpBuilder<"OpBuilder &builder, OperationState &result, "
683+
"Value valueToStore, Value memref, ValueRange indices">,
684+
OpBuilder<"OpBuilder &builder, OperationState &result, "
685+
"Value valueToStore, Value memref, AffineMap map, "
686+
"ValueRange mapOperands">
687+
];
688+
689+
let extraClassDeclaration = [{
690+
/// Get value to be stored by store operation.
691+
Value getValueToStore() { return getOperand(0); }
692+
693+
/// Returns the operand index of the memref.
694+
unsigned getMemRefOperandIndex() { return 1; }
695+
696+
/// Get memref operand.
697+
Value getMemRef() { return getOperand(getMemRefOperandIndex()); }
698+
void setMemRef(Value value) { setOperand(getMemRefOperandIndex(), value); }
699+
700+
MemRefType getMemRefType() {
701+
return getMemRef().getType().cast<MemRefType>();
702+
}
703+
704+
/// Get affine map operands.
705+
operand_range getMapOperands() { return llvm::drop_begin(getOperands(), 2); }
706+
707+
/// Returns the affine map used to index the memref for this operation.
708+
AffineMap getAffineMap() { return getAffineMapAttr().getValue(); }
709+
AffineMapAttr getAffineMapAttr() {
710+
return getAttr(getMapAttrName()).cast<AffineMapAttr>();
711+
}
712+
713+
/// Returns the AffineMapAttr associated with 'memref'.
714+
NamedAttribute getAffineMapAttrForMemRef(Value memref) {
715+
assert(memref == getMemRef());
716+
return {Identifier::get(getMapAttrName(), getContext()),
717+
getAffineMapAttr()};
718+
}
719+
720+
static StringRef getMapAttrName() { return "map"; }
721+
}];
722+
723+
let hasCanonicalizer = 1;
724+
let hasFolder = 1;
725+
}
726+
578727
def AffineTerminatorOp :
579728
Affine_Op<"terminator", [NoSideEffect, Terminator]> {
580729
let summary = "affine terminator operation";

0 commit comments

Comments
 (0)