Skip to content

Commit d89c1db

Browse files
authored
[flang][hlfir] refine hlfir.assign side effects (#113319)
hlfir.assign currently has the `MemoryEffects<[MemWrite]` which makes it look like it can write to anything. This is good for some cases where the assign effect cannot be precisely described through the MLIR side effect API (e.g., when the LHS is a descriptor and it is not possible to get an OpOperand describing the data address, or when derived type are involved and finalization could be called, or user defined assignment for some components). For the most common case of hlfir.assign on intrinsic types without whole allocatable LHS, this is pessimistic. This patch implements a finer description of the side effects when possible, and also adds the proper read/allocate/free effects when relevant. The ultimate goal is to suppress the generation of temporary for the LHS address when dealing with an assignment to a vector subscripted LHS where the vector subscript is an array constructor that does not refer to the LHS (as in `x([a,b]) = y`). Two more patches will follow to enable this.
1 parent ac5a201 commit d89c1db

File tree

3 files changed

+89
-2
lines changed

3 files changed

+89
-2
lines changed

flang/include/flang/Optimizer/HLFIR/HLFIROps.td

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ def hlfir_DeclareOp : hlfir_Op<"declare", [AttrSizedOperandSegments,
130130
let hasVerifier = 1;
131131
}
132132

133-
def fir_AssignOp : hlfir_Op<"assign", [MemoryEffects<[MemWrite]>]> {
133+
def fir_AssignOp : hlfir_Op<"assign", [DeclareOpInterfaceMethods<MemoryEffectsOpInterface>]> {
134134
let summary = "Assign an expression or variable value to a Fortran variable";
135135

136136
let description = [{
@@ -166,7 +166,7 @@ def fir_AssignOp : hlfir_Op<"assign", [MemoryEffects<[MemWrite]>]> {
166166
}];
167167

168168
let arguments = (ins AnyFortranEntity:$rhs,
169-
Arg<AnyFortranVariable, "", [MemWrite]>:$lhs,
169+
AnyFortranVariable:$lhs,
170170
UnitAttr:$realloc,
171171
UnitAttr:$keep_lhs_length_if_realloc,
172172
UnitAttr:$temporary_lhs);

flang/lib/Optimizer/HLFIR/IR/HLFIROps.cpp

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,62 @@ llvm::LogicalResult hlfir::AssignOp::verify() {
9090
return mlir::success();
9191
}
9292

93+
void hlfir::AssignOp::getEffects(
94+
llvm::SmallVectorImpl<
95+
mlir::SideEffects::EffectInstance<mlir::MemoryEffects::Effect>>
96+
&effects) {
97+
mlir::OpOperand &rhs = getRhsMutable();
98+
mlir::OpOperand &lhs = getLhsMutable();
99+
mlir::Type rhsType = getRhs().getType();
100+
mlir::Type lhsType = getLhs().getType();
101+
if (mlir::isa<fir::RecordType>(hlfir::getFortranElementType(lhsType))) {
102+
// For derived type assignments, set unknown read/write effects since it
103+
// is not known here if user defined finalization is needed, and also
104+
// because allocatable components may lead to "deeper" read/write effects
105+
// that cannot be described with this API.
106+
effects.emplace_back(mlir::MemoryEffects::Read::get(),
107+
mlir::SideEffects::DefaultResource::get());
108+
effects.emplace_back(mlir::MemoryEffects::Write::get(),
109+
mlir::SideEffects::DefaultResource::get());
110+
} else {
111+
// Read effect when RHS is a variable.
112+
if (hlfir::isFortranVariableType(rhsType)) {
113+
if (hlfir::isBoxAddressType(rhsType)) {
114+
// Unknown read effect if the RHS is a descriptor since the read effect
115+
// on the data cannot be described.
116+
effects.emplace_back(mlir::MemoryEffects::Read::get(),
117+
mlir::SideEffects::DefaultResource::get());
118+
} else {
119+
effects.emplace_back(mlir::MemoryEffects::Read::get(), &rhs,
120+
mlir::SideEffects::DefaultResource::get());
121+
}
122+
}
123+
124+
// Write effects on LHS.
125+
if (hlfir::isBoxAddressType(lhsType)) {
126+
// If the LHS is a descriptor, the descriptor will be read and the data
127+
// write cannot be described in this API (and the descriptor may be
128+
// written to in case of realloc, which is covered by the unknown write
129+
// effect.
130+
effects.emplace_back(mlir::MemoryEffects::Read::get(), &lhs,
131+
mlir::SideEffects::DefaultResource::get());
132+
effects.emplace_back(mlir::MemoryEffects::Write::get(),
133+
mlir::SideEffects::DefaultResource::get());
134+
} else {
135+
effects.emplace_back(mlir::MemoryEffects::Write::get(), &lhs,
136+
mlir::SideEffects::DefaultResource::get());
137+
}
138+
}
139+
140+
if (getRealloc()) {
141+
// Reallocation of the data cannot be precisely described by this API.
142+
effects.emplace_back(mlir::MemoryEffects::Free::get(),
143+
mlir::SideEffects::DefaultResource::get());
144+
effects.emplace_back(mlir::MemoryEffects::Allocate::get(),
145+
mlir::SideEffects::DefaultResource::get());
146+
}
147+
}
148+
93149
//===----------------------------------------------------------------------===//
94150
// DeclareOp
95151
//===----------------------------------------------------------------------===//
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// Test side effects of hlfir.assign op.
2+
// RUN: fir-opt %s --test-side-effects --verify-diagnostics
3+
4+
func.func @test1(%x: !fir.ref<i32>, %i: i32) {
5+
// expected-remark @below {{found an instance of 'write' on a op operand, on resource '<Default>'}}
6+
hlfir.assign %i to %x : i32, !fir.ref<i32>
7+
return
8+
}
9+
10+
func.func @test2(%x: !fir.ref<i32>, %y: !fir.ref<i32>) {
11+
// expected-remark @below {{found an instance of 'write' on a op operand, on resource '<Default>'}}
12+
// expected-remark @below {{found an instance of 'read' on a op operand, on resource '<Default>'}}
13+
hlfir.assign %y to %x : !fir.ref<i32>, !fir.ref<i32>
14+
return
15+
}
16+
17+
func.func @test3(%x: !fir.ref<!fir.type<t>>, %y: !fir.ref<!fir.type<t>>) {
18+
// expected-remark @below {{found an instance of 'write' on resource '<Default>'}}
19+
// expected-remark @below {{found an instance of 'read' on resource '<Default>'}}
20+
hlfir.assign %y to %x : !fir.ref<!fir.type<t>>, !fir.ref<!fir.type<t>>
21+
return
22+
}
23+
24+
func.func @test4(%x: !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, %y: !fir.box<!fir.array<?xi32>>) {
25+
// expected-remark @below {{found an instance of 'read' on a op operand, on resource '<Default>'}}
26+
// expected-remark @below {{found an instance of 'write' on resource '<Default>'}}
27+
// expected-remark @below {{found an instance of 'free' on resource '<Default>'}}
28+
// expected-remark @below {{found an instance of 'allocate' on resource '<Default>'}}
29+
hlfir.assign %y to %x realloc : !fir.box<!fir.array<?xi32>>, !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
30+
return
31+
}

0 commit comments

Comments
 (0)