Skip to content

Commit 4033624

Browse files
committed
[fir] add fir.array_modify op to allow custom assignment semantics
fir.array_update is only handling intrinsic assignments. They are two big differences with user defined assignments: 1. The LHS and RHS types may not match, this does not play well with fir.array_update that relies on both the merge and the updated element to have the same type. 2. user defined assignment has a call semantics, with potential side effects. So if a fir.array_update can hide a call, it traits would need to be updated. Instead of hiding more semantic in the fir.array_update, introduce a new fir.array_modify op that allows de-correlating indicating that an array value element is modified, and how it is modified. This allow the ArrayValueCopy pass to still perform copy elision while not having to implement the call itself, and could in general be used for all kind of assignments (e.g. character assignment). Update the alias analysis to not rely on the merge arguments (since fir.array_modify has none). Instead, analyze what is done with the element address. This implies adding the ability to follow the users of fir.array_modify, as well as being able to go through fir.store that may be generated to store the RHS value in order to pass it to a user define routine. This is done by adding a ReachCollector class to gather all array accesses.
1 parent e401ff8 commit 4033624

File tree

6 files changed

+489
-149
lines changed

6 files changed

+489
-149
lines changed

flang/include/flang/Optimizer/Dialect/FIROps.td

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1479,6 +1479,64 @@ def fir_ArrayUpdateOp : fir_Op<"array_update", [AttrSizedOperandSegments,
14791479
let verifier = "return ::verify(*this);";
14801480
}
14811481

1482+
def fir_ArrayModifyOp : fir_Op<"array_modify", [AttrSizedOperandSegments,
1483+
NoSideEffect]> {
1484+
let summary = "Get an address for an array value to modify it.";
1485+
1486+
let description = [{
1487+
Modify the value of an element in an array value through actions done
1488+
on the returned address. A new array value is also
1489+
returned where all element values of the input array are identical except
1490+
for the selected element which is the value after the modification done
1491+
on the element address.
1492+
1493+
```fortran
1494+
real :: a(n)
1495+
...
1496+
! Elemental user defined assignment from type(SomeType) to real.
1497+
a = value_of_some_type
1498+
```
1499+
1500+
One can use `fir.array_modify` to update the (implied) value of `a(i)`
1501+
in an array expression as shown above.
1502+
1503+
```mlir
1504+
%s = fir.shape %n : (index) -> !fir.shape<1>
1505+
// Load the entire array 'a'.
1506+
%v = fir.array_load %a(%s) : (!fir.ref<!fir.array<?xf32>>, !fir.shape<1>) -> !fir.array<?xf32>
1507+
// Update the value of one of the array value's elements with a user
1508+
// defined assignment from %rhs.
1509+
%new = fir.do_loop %i = ... (%inner = %v) {
1510+
%rhs = ...
1511+
%addr, %r = fir.array_modify %inner, %i, %j : (!fir.array<?xf32>, index) -> fir.ref<f32>, !fir.array<?xf32>
1512+
fir.call @user_def_assign(%addr, %rhs) (fir.ref<f32>, fir.ref<!fir.type<SomeType>>) -> ()
1513+
fir.result %r : !fir.ref<!fir.array<?xf32>>
1514+
}
1515+
fir.array_merge_store %v, %new to %a : !fir.ref<!fir.array<?xf32>>
1516+
```
1517+
1518+
An array value modification behaves as if a mapping function from the indices
1519+
to the new value has been added, replacing the previous mapping. These
1520+
mappings can be added to the ssa-value, but will not be materialized in
1521+
memory until the `fir.array_merge_store` is performed.
1522+
}];
1523+
1524+
let arguments = (ins
1525+
fir_SequenceType:$sequence,
1526+
Variadic<AnyCoordinateType>:$indices,
1527+
Variadic<AnyIntegerType>:$typeparams
1528+
);
1529+
1530+
let results = (outs fir_ReferenceType, fir_SequenceType);
1531+
1532+
let assemblyFormat = [{
1533+
$sequence `,` $indices (`typeparams` $typeparams^)? attr-dict
1534+
`:` functional-type(operands, results)
1535+
}];
1536+
1537+
let verifier = [{ return ::verify(*this); }];
1538+
}
1539+
14821540
def fir_ArrayMergeStoreOp : fir_Op<"array_merge_store",
14831541
[AttrSizedOperandSegments]> {
14841542
let summary = "Store merged array value to memory.";

flang/lib/Optimizer/Dialect/FIROps.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -499,6 +499,18 @@ static mlir::LogicalResult verify(fir::ArrayUpdateOp op) {
499499
return mlir::success();
500500
}
501501

502+
//===----------------------------------------------------------------------===//
503+
// ArrayModifyOp
504+
//===----------------------------------------------------------------------===//
505+
506+
static mlir::LogicalResult verify(fir::ArrayModifyOp op) {
507+
auto arrTy = op.sequence().getType().cast<fir::SequenceType>();
508+
auto indSize = op.indices().size();
509+
if (indSize < arrTy.getDimension())
510+
return op.emitOpError("number of indices must match array dimension");
511+
return mlir::success();
512+
}
513+
502514
//===----------------------------------------------------------------------===//
503515
// BoxAddrOp
504516
//===----------------------------------------------------------------------===//

0 commit comments

Comments
 (0)