Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[flang][hlfir] Fixed some finalization/deallocation issues. #67047

Merged
merged 7 commits into from
Sep 22, 2023
31 changes: 0 additions & 31 deletions flang/include/flang/Optimizer/Builder/HLFIRTools.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,37 +35,6 @@ class ElementalOpInterface;
class ElementalAddrOp;
class YieldElementOp;

/// Is this an SSA value type for the value of a Fortran procedure
/// designator ?
inline bool isFortranProcedureValue(mlir::Type type) {
return type.isa<fir::BoxProcType>() ||
(type.isa<mlir::TupleType>() &&
fir::isCharacterProcedureTuple(type, /*acceptRawFunc=*/false));
}

/// Is this an SSA value type for the value of a Fortran expression?
inline bool isFortranValueType(mlir::Type type) {
return type.isa<hlfir::ExprType>() || fir::isa_trivial(type) ||
isFortranProcedureValue(type);
}

/// Is this the value of a Fortran expression in an SSA value form?
inline bool isFortranValue(mlir::Value value) {
return isFortranValueType(value.getType());
}

/// Is this a Fortran variable?
/// Note that by "variable", it must be understood that the mlir::Value is
/// a memory value of a storage that can be reason about as a Fortran object
/// (its bounds, shape, and type parameters, if any, are retrievable).
/// This does not imply that the mlir::Value points to a variable from the
/// original source or can be legally defined: temporaries created to store
/// expression values are considered to be variables, and so are PARAMETERs
/// global constant address.
inline bool isFortranEntity(mlir::Value value) {
return isFortranValue(value) || isFortranVariableType(value.getType());
}

/// Is this a Fortran variable for which the defining op carrying the Fortran
/// attributes is visible?
inline bool isFortranVariableWithAttributes(mlir::Value value) {
Expand Down
38 changes: 38 additions & 0 deletions flang/include/flang/Optimizer/HLFIR/HLFIRDialect.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,37 @@ inline bool isPolymorphicType(mlir::Type type) {
return fir::isPolymorphicType(type);
}

/// Is this an SSA value type for the value of a Fortran procedure
/// designator ?
inline bool isFortranProcedureValue(mlir::Type type) {
return type.isa<fir::BoxProcType>() ||
(type.isa<mlir::TupleType>() &&
fir::isCharacterProcedureTuple(type, /*acceptRawFunc=*/false));
}

/// Is this an SSA value type for the value of a Fortran expression?
inline bool isFortranValueType(mlir::Type type) {
return type.isa<hlfir::ExprType>() || fir::isa_trivial(type) ||
isFortranProcedureValue(type);
}

/// Is this the value of a Fortran expression in an SSA value form?
inline bool isFortranValue(mlir::Value value) {
return isFortranValueType(value.getType());
}

/// Is this a Fortran variable?
/// Note that by "variable", it must be understood that the mlir::Value is
/// a memory value of a storage that can be reason about as a Fortran object
/// (its bounds, shape, and type parameters, if any, are retrievable).
/// This does not imply that the mlir::Value points to a variable from the
/// original source or can be legally defined: temporaries created to store
/// expression values are considered to be variables, and so are PARAMETERs
/// global constant address.
inline bool isFortranEntity(mlir::Value value) {
return isFortranValue(value) || isFortranVariableType(value.getType());
}

bool isFortranScalarNumericalType(mlir::Type);
bool isFortranNumericalArrayObject(mlir::Type);
bool isFortranNumericalOrLogicalArrayObject(mlir::Type);
Expand All @@ -94,6 +125,13 @@ bool isPolymorphicObject(mlir::Type);
mlir::Value genExprShape(mlir::OpBuilder &builder, const mlir::Location &loc,
const hlfir::ExprType &expr);

/// Return true iff `ty` may have allocatable component.
/// TODO: this actually belongs to FIRType.cpp, but the method's implementation
/// depends on HLFIRDialect component. FIRType.cpp itself is part of FIRDialect
/// that cannot depend on HLFIRBuilder (there will be a cyclic dependency).
/// This has to be cleaned up, when HLFIR is the default.
bool mayHaveAllocatableComponent(mlir::Type ty);

} // namespace hlfir

#endif // FORTRAN_OPTIMIZER_HLFIR_HLFIRDIALECT_H
3 changes: 3 additions & 0 deletions flang/include/flang/Optimizer/HLFIR/HLFIROps.td
Original file line number Diff line number Diff line change
Expand Up @@ -705,6 +705,8 @@ def hlfir_EndAssociateOp : hlfir_Op<"end_associate", [MemoryEffects<[MemFree]>]>

let description = [{
Mark the end of life of a variable associated to an expression.
If the expression has a derived type that may contain allocatable
components, the variable operand must be a Fortran entity.
}];

let arguments = (ins AnyRefOrBoxLike:$var,
Expand All @@ -715,6 +717,7 @@ def hlfir_EndAssociateOp : hlfir_Op<"end_associate", [MemoryEffects<[MemFree]>]>
}];

let builders = [OpBuilder<(ins "hlfir::AssociateOp":$associate)>];
let hasVerifier = 1;
}

def hlfir_AsExprOp : hlfir_Op<"as_expr",
Expand Down
5 changes: 5 additions & 0 deletions flang/lib/Optimizer/HLFIR/IR/HLFIRDialect.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -207,3 +207,8 @@ mlir::Value hlfir::genExprShape(mlir::OpBuilder &builder,
fir::ShapeOp shape = builder.create<fir::ShapeOp>(loc, shapeTy, extents);
return shape.getResult();
}

bool hlfir::mayHaveAllocatableComponent(mlir::Type ty) {
return fir::isPolymorphicType(ty) || fir::isUnlimitedPolymorphicType(ty) ||
fir::isRecordWithAllocatableMember(hlfir::getFortranElementType(ty));
}
20 changes: 19 additions & 1 deletion flang/lib/Optimizer/HLFIR/IR/HLFIROps.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1237,10 +1237,28 @@ void hlfir::AssociateOp::build(mlir::OpBuilder &builder,
void hlfir::EndAssociateOp::build(mlir::OpBuilder &builder,
mlir::OperationState &result,
hlfir::AssociateOp associate) {
return build(builder, result, associate.getFirBase(),
mlir::Value hlfirBase = associate.getBase();
mlir::Value firBase = associate.getFirBase();
// If EndAssociateOp may need to initiate the deallocation
// of allocatable components, it has to have access to the variable
// definition, so we cannot use the FIR base as the operand.
tblah marked this conversation as resolved.
Show resolved Hide resolved
return build(builder, result,
hlfir::mayHaveAllocatableComponent(hlfirBase.getType())
? hlfirBase
: firBase,
associate.getMustFreeStrorageFlag());
}

mlir::LogicalResult hlfir::EndAssociateOp::verify() {
mlir::Value var = getVar();
if (hlfir::mayHaveAllocatableComponent(var.getType()) &&
!hlfir::isFortranEntity(var))
return emitOpError("that requires components deallocation must have var "
"operand that is a Fortran entity");

return mlir::success();
}

//===----------------------------------------------------------------------===//
// AsExprOp
//===----------------------------------------------------------------------===//
Expand Down
9 changes: 9 additions & 0 deletions flang/test/HLFIR/invalid.fir
Original file line number Diff line number Diff line change
Expand Up @@ -1172,3 +1172,12 @@ func.func @destroy_with_finalize(%expr: !hlfir.expr<?xi32>) {
hlfir.destroy %expr finalize : !hlfir.expr<?xi32>
return
}

// -----

func.func @end_associate_with_alloc_comp(%var: !hlfir.expr<?x!fir.type<_QMtypesTt{x:!fir.box<!fir.heap<f32>>}>>, %shape: !fir.shape<1>) {
%4:3 = hlfir.associate %var(%shape) {uniq_name = "adapt.valuebyref"} : (!hlfir.expr<?x!fir.type<_QMtypesTt{x:!fir.box<!fir.heap<f32>>}>>, !fir.shape<1>) -> (!fir.box<!fir.array<?x!fir.type<_QMtypesTt{x:!fir.box<!fir.heap<f32>>}>>>, !fir.ref<!fir.array<?x!fir.type<_QMtypesTt{x:!fir.box<!fir.heap<f32>>}>>>, i1)
// expected-error@+1 {{'hlfir.end_associate' op that requires components deallocation must have var operand that is a Fortran entity}}
hlfir.end_associate %4#1, %4#2 : !fir.ref<!fir.array<?x!fir.type<_QMtypesTt{x:!fir.box<!fir.heap<f32>>}>>>, i1
return
}