[flang-commits] [flang] bbb7f01 - [flang] Fix volatile attribute propagation on allocatables (#139183)
via flang-commits
flang-commits at lists.llvm.org
Tue May 13 08:13:51 PDT 2025
Author: Asher Mancinelli
Date: 2025-05-13T08:13:47-07:00
New Revision: bbb7f0148177d332df80b5cfdc7d161dca289056
URL: https://github.com/llvm/llvm-project/commit/bbb7f0148177d332df80b5cfdc7d161dca289056
DIFF: https://github.com/llvm/llvm-project/commit/bbb7f0148177d332df80b5cfdc7d161dca289056.diff
LOG: [flang] Fix volatile attribute propagation on allocatables (#139183)
Ensure volatility is reflected not just on the reference to an
allocatable, but on the box, too. When we declare a volatile
allocatable, we now get a volatile reference to a volatile box.
Some related cleanups:
* SELECT TYPE constructs check the selector's type for volatility when
creating and designating the type used in the selecting block.
* Refine the verifier for fir.convert. In general, I think it is ok to
implicitly drop volatility in any ptr-to-int conversion because it means
we are in codegen (and representing volatility on the LLVM ops and
intrinsics) or we are calling an external function (are there any cases
I'm not thinking of?)
* An allocatable test that was XFAILed is now passing. Making
allocatables' boxes volatile resulted in accesses of those boxes being
volatile, which resolved some errors coming from the strict verifier.
* I noticed a runtime function was missing the fir.runtime attribute.
Added:
Modified:
flang/lib/Lower/Bridge.cpp
flang/lib/Optimizer/Dialect/FIROps.cpp
flang/lib/Optimizer/HLFIR/IR/HLFIROps.cpp
flang/lib/Optimizer/Transforms/PolymorphicOpConversion.cpp
flang/test/Fir/invalid.fir
flang/test/Lower/volatile-allocatable.f90
flang/test/Lower/volatile-allocatable1.f90
Removed:
################################################################################
diff --git a/flang/lib/Lower/Bridge.cpp b/flang/lib/Lower/Bridge.cpp
index cf9a322680321..c9e91cf3e8042 100644
--- a/flang/lib/Lower/Bridge.cpp
+++ b/flang/lib/Lower/Bridge.cpp
@@ -3842,6 +3842,10 @@ class FirConverter : public Fortran::lower::AbstractConverter {
bool hasLocalScope = false;
llvm::SmallVector<const Fortran::semantics::Scope *> typeCaseScopes;
+ const auto selectorIsVolatile = [&selector]() {
+ return fir::isa_volatile_type(fir::getBase(selector).getType());
+ };
+
const auto &typeCaseList =
std::get<std::list<Fortran::parser::SelectTypeConstruct::TypeCase>>(
selectTypeConstruct.t);
@@ -3995,7 +3999,8 @@ class FirConverter : public Fortran::lower::AbstractConverter {
addrTy = fir::HeapType::get(addrTy);
if (std::holds_alternative<Fortran::parser::IntrinsicTypeSpec>(
typeSpec->u)) {
- mlir::Type refTy = fir::ReferenceType::get(addrTy);
+ mlir::Type refTy =
+ fir::ReferenceType::get(addrTy, selectorIsVolatile());
if (isPointer || isAllocatable)
refTy = addrTy;
exactValue = builder->create<fir::BoxAddrOp>(
@@ -4004,7 +4009,8 @@ class FirConverter : public Fortran::lower::AbstractConverter {
typeSpec->declTypeSpec->AsIntrinsic();
if (isArray) {
mlir::Value exact = builder->create<fir::ConvertOp>(
- loc, fir::BoxType::get(addrTy), fir::getBase(selector));
+ loc, fir::BoxType::get(addrTy, selectorIsVolatile()),
+ fir::getBase(selector));
addAssocEntitySymbol(selectorBox->clone(exact));
} else if (intrinsic->category() ==
Fortran::common::TypeCategory::Character) {
@@ -4019,7 +4025,8 @@ class FirConverter : public Fortran::lower::AbstractConverter {
} else if (std::holds_alternative<Fortran::parser::DerivedTypeSpec>(
typeSpec->u)) {
exactValue = builder->create<fir::ConvertOp>(
- loc, fir::BoxType::get(addrTy), fir::getBase(selector));
+ loc, fir::BoxType::get(addrTy, selectorIsVolatile()),
+ fir::getBase(selector));
addAssocEntitySymbol(selectorBox->clone(exactValue));
}
} else if (std::holds_alternative<Fortran::parser::DerivedTypeSpec>(
@@ -4037,7 +4044,8 @@ class FirConverter : public Fortran::lower::AbstractConverter {
addrTy = fir::PointerType::get(addrTy);
if (isAllocatable)
addrTy = fir::HeapType::get(addrTy);
- mlir::Type classTy = fir::ClassType::get(addrTy);
+ mlir::Type classTy =
+ fir::ClassType::get(addrTy, selectorIsVolatile());
if (classTy == baseTy) {
addAssocEntitySymbol(selector);
} else {
diff --git a/flang/lib/Optimizer/Dialect/FIROps.cpp b/flang/lib/Optimizer/Dialect/FIROps.cpp
index c1cdbddd45279..d85b38c467857 100644
--- a/flang/lib/Optimizer/Dialect/FIROps.cpp
+++ b/flang/lib/Optimizer/Dialect/FIROps.cpp
@@ -1536,20 +1536,50 @@ bool fir::ConvertOp::canBeConverted(mlir::Type inType, mlir::Type outType) {
areRecordsCompatible(inType, outType);
}
+// In general, ptrtoint-like conversions are allowed to lose volatility
+// information because they are either:
+//
+// 1. passing an entity to an external function and there's nothing we can do
+// about volatility after that happens, or
+// 2. for code generation, at which point we represent volatility with
+// attributes on the LLVM instructions and intrinsics.
+//
+// For all other cases, volatility ought to match exactly.
+static mlir::LogicalResult verifyVolatility(mlir::Type inType,
+ mlir::Type outType) {
+ const bool toLLVMPointer = mlir::isa<mlir::LLVM::LLVMPointerType>(outType);
+ const bool toInteger = fir::isa_integer(outType);
+
+ // When converting references to classes or allocatables into boxes for
+ // runtime arguments, we cast away all the volatility information and pass a
+ // box<none>. This is allowed.
+ const bool isBoxNoneLike = [&]() {
+ if (fir::isBoxNone(outType))
+ return true;
+ if (auto referenceType = mlir::dyn_cast<fir::ReferenceType>(outType)) {
+ if (fir::isBoxNone(referenceType.getElementType())) {
+ return true;
+ }
+ }
+ return false;
+ }();
+
+ const bool isPtrToIntLike = toLLVMPointer || toInteger || isBoxNoneLike;
+ if (isPtrToIntLike) {
+ return mlir::success();
+ }
+
+ // In all other cases, we need to check for an exact volatility match.
+ return mlir::success(fir::isa_volatile_type(inType) ==
+ fir::isa_volatile_type(outType));
+}
+
llvm::LogicalResult fir::ConvertOp::verify() {
mlir::Type inType = getValue().getType();
mlir::Type outType = getType();
- // If we're converting to an LLVM pointer type or an integer, we don't
- // need to check for volatility mismatch - volatility will be handled by the
- // memory operations themselves in llvm code generation and ptr-to-int can't
- // represent volatility.
- const bool toLLVMPointer = mlir::isa<mlir::LLVM::LLVMPointerType>(outType);
- const bool toInteger = fir::isa_integer(outType);
if (fir::useStrictVolatileVerification()) {
- if (fir::isa_volatile_type(inType) != fir::isa_volatile_type(outType) &&
- !toLLVMPointer && !toInteger) {
- return emitOpError("cannot convert between volatile and non-volatile "
- "types, use fir.volatile_cast instead ")
+ if (failed(verifyVolatility(inType, outType))) {
+ return emitOpError("this conversion does not preserve volatility: ")
<< inType << " / " << outType;
}
}
diff --git a/flang/lib/Optimizer/HLFIR/IR/HLFIROps.cpp b/flang/lib/Optimizer/HLFIR/IR/HLFIROps.cpp
index 711d5d1461b08..8cfca59ecdada 100644
--- a/flang/lib/Optimizer/HLFIR/IR/HLFIROps.cpp
+++ b/flang/lib/Optimizer/HLFIR/IR/HLFIROps.cpp
@@ -207,29 +207,37 @@ static bool hasExplicitLowerBounds(mlir::Value shape) {
mlir::isa<fir::ShapeShiftType, fir::ShiftType>(shape.getType());
}
-static std::pair<mlir::Type, mlir::Value> updateDeclareInputTypeWithVolatility(
- mlir::Type inputType, mlir::Value memref, mlir::OpBuilder &builder,
- fir::FortranVariableFlagsAttr fortran_attrs) {
- if (fortran_attrs &&
- bitEnumContainsAny(fortran_attrs.getFlags(),
- fir::FortranVariableFlagsEnum::fortran_volatile)) {
- const bool isPointer = bitEnumContainsAny(
- fortran_attrs.getFlags(), fir::FortranVariableFlagsEnum::pointer);
- auto updateType = [&](auto t) {
- using FIRT = decltype(t);
- // A volatile pointer's pointee is volatile.
- auto elementType = t.getEleTy();
- const bool elementTypeIsVolatile =
- isPointer || fir::isa_volatile_type(elementType);
- auto newEleTy =
- fir::updateTypeWithVolatility(elementType, elementTypeIsVolatile);
- inputType = FIRT::get(newEleTy, true);
- };
- llvm::TypeSwitch<mlir::Type>(inputType)
- .Case<fir::ReferenceType, fir::BoxType, fir::ClassType>(updateType);
- memref =
- builder.create<fir::VolatileCastOp>(memref.getLoc(), inputType, memref);
+static std::pair<mlir::Type, mlir::Value>
+updateDeclaredInputTypeWithVolatility(mlir::Type inputType, mlir::Value memref,
+ mlir::OpBuilder &builder,
+ fir::FortranVariableFlagsEnum flags) {
+ if (!bitEnumContainsAny(flags,
+ fir::FortranVariableFlagsEnum::fortran_volatile)) {
+ return std::make_pair(inputType, memref);
}
+
+ // A volatile pointer's pointee is volatile.
+ const bool isPointer =
+ bitEnumContainsAny(flags, fir::FortranVariableFlagsEnum::pointer);
+ // An allocatable's inner type's volatility matches that of the reference.
+ const bool isAllocatable =
+ bitEnumContainsAny(flags, fir::FortranVariableFlagsEnum::allocatable);
+
+ auto updateType = [&](auto t) {
+ using FIRT = decltype(t);
+ auto elementType = t.getEleTy();
+ const bool elementTypeIsBox = mlir::isa<fir::BaseBoxType>(elementType);
+ const bool elementTypeIsVolatile = isPointer || isAllocatable ||
+ elementTypeIsBox ||
+ fir::isa_volatile_type(elementType);
+ auto newEleTy =
+ fir::updateTypeWithVolatility(elementType, elementTypeIsVolatile);
+ inputType = FIRT::get(newEleTy, true);
+ };
+ llvm::TypeSwitch<mlir::Type>(inputType)
+ .Case<fir::ReferenceType, fir::BoxType, fir::ClassType>(updateType);
+ memref =
+ builder.create<fir::VolatileCastOp>(memref.getLoc(), inputType, memref);
return std::make_pair(inputType, memref);
}
@@ -243,8 +251,11 @@ void hlfir::DeclareOp::build(mlir::OpBuilder &builder,
auto nameAttr = builder.getStringAttr(uniq_name);
mlir::Type inputType = memref.getType();
bool hasExplicitLbs = hasExplicitLowerBounds(shape);
- std::tie(inputType, memref) = updateDeclareInputTypeWithVolatility(
- inputType, memref, builder, fortran_attrs);
+ if (fortran_attrs) {
+ const auto flags = fortran_attrs.getFlags();
+ std::tie(inputType, memref) = updateDeclaredInputTypeWithVolatility(
+ inputType, memref, builder, flags);
+ }
mlir::Type hlfirVariableType =
getHLFIRVariableType(inputType, hasExplicitLbs);
build(builder, result, {hlfirVariableType, inputType}, memref, shape,
diff --git a/flang/lib/Optimizer/Transforms/PolymorphicOpConversion.cpp b/flang/lib/Optimizer/Transforms/PolymorphicOpConversion.cpp
index 0c78a878cdc53..f9a4c4d0283c7 100644
--- a/flang/lib/Optimizer/Transforms/PolymorphicOpConversion.cpp
+++ b/flang/lib/Optimizer/Transforms/PolymorphicOpConversion.cpp
@@ -401,10 +401,14 @@ llvm::LogicalResult SelectTypeConv::genTypeLadderStep(
{
// Since conversion is done in parallel for each fir.select_type
// operation, the runtime function insertion must be threadsafe.
+ auto runtimeAttr =
+ mlir::NamedAttribute(fir::FIROpsDialect::getFirRuntimeAttrName(),
+ mlir::UnitAttr::get(rewriter.getContext()));
callee =
fir::createFuncOp(rewriter.getUnknownLoc(), mod, fctName,
rewriter.getFunctionType({descNoneTy, typeDescTy},
- rewriter.getI1Type()));
+ rewriter.getI1Type()),
+ {runtimeAttr});
}
cmp = rewriter
.create<fir::CallOp>(loc, callee,
diff --git a/flang/test/Fir/invalid.fir b/flang/test/Fir/invalid.fir
index 1de48b87365b3..fd607fd9066f7 100644
--- a/flang/test/Fir/invalid.fir
+++ b/flang/test/Fir/invalid.fir
@@ -1260,7 +1260,7 @@ func.func @dc_invalid_reduction(%arg0: index, %arg1: index) {
// Should fail when volatility changes from a fir.convert
func.func @bad_convert_volatile(%arg0: !fir.ref<i32>) -> !fir.ref<i32, volatile> {
- // expected-error at +1 {{'fir.convert' op cannot convert between volatile and non-volatile types, use fir.volatile_cast instead}}
+ // expected-error at +1 {{op this conversion does not preserve volatility}}
%0 = fir.convert %arg0 : (!fir.ref<i32>) -> !fir.ref<i32, volatile>
return %0 : !fir.ref<i32, volatile>
}
@@ -1269,7 +1269,7 @@ func.func @bad_convert_volatile(%arg0: !fir.ref<i32>) -> !fir.ref<i32, volatile>
// Should fail when volatility changes from a fir.convert
func.func @bad_convert_volatile2(%arg0: !fir.ref<i32, volatile>) -> !fir.ref<i32> {
- // expected-error at +1 {{'fir.convert' op cannot convert between volatile and non-volatile types, use fir.volatile_cast instead}}
+ // expected-error at +1 {{op this conversion does not preserve volatility}}
%0 = fir.convert %arg0 : (!fir.ref<i32, volatile>) -> !fir.ref<i32>
return %0 : !fir.ref<i32>
}
diff --git a/flang/test/Lower/volatile-allocatable.f90 b/flang/test/Lower/volatile-allocatable.f90
index 5f75a5425422a..e182fe8a4d9c9 100644
--- a/flang/test/Lower/volatile-allocatable.f90
+++ b/flang/test/Lower/volatile-allocatable.f90
@@ -119,10 +119,10 @@ subroutine test_unlimited_polymorphic()
end subroutine
! CHECK-LABEL: func.func @_QPtest_scalar_volatile() {
-! CHECK: %{{.+}}:2 = hlfir.declare %{{.+}} {fortran_attrs = #fir.var_attrs<allocatable, volatile>, uniq_name = "_QFtest_scalar_volatileEc1"} : (!fir.ref<!fir.box<!fir.heap<!fir.char<1,?>>>, volatile>) -> (!fir.ref<!fir.box<!fir.heap<!fir.char<1,?>>>, volatile>, !fir.ref<!fir.box<!fir.heap<!fir.char<1,?>>>, volatile>)
-! CHECK: %{{.+}}:2 = hlfir.declare %{{.+}} {fortran_attrs = #fir.var_attrs<allocatable, volatile>, uniq_name = "_QFtest_scalar_volatileEv1"} : (!fir.ref<!fir.class<!fir.heap<!fir.type<{{.*}}>>>, volatile>) -> (!fir.ref<!fir.class<!fir.heap<!fir.type<{{.*}}>>>, volatile>, !fir.ref<!fir.class<!fir.heap<!fir.type<{{.*}}>>>, volatile>)
-! CHECK: %{{.+}}:2 = hlfir.declare %{{.+}} {fortran_attrs = #fir.var_attrs<allocatable, volatile>, uniq_name = "_QFtest_scalar_volatileEv2"} : (!fir.ref<!fir.box<!fir.heap<!fir.type<{{.*}}>>>, volatile>) -> (!fir.ref<!fir.box<!fir.heap<!fir.type<{{.*}}>>>, volatile>, !fir.ref<!fir.box<!fir.heap<!fir.type<{{.*}}>>>, volatile>)
-! CHECK: %{{.+}}:2 = hlfir.declare %{{.+}} {fortran_attrs = #fir.var_attrs<allocatable, volatile>, uniq_name = "_QFtest_scalar_volatileEv3"} : (!fir.ref<!fir.box<!fir.heap<!fir.type<{{.*}}>>>, volatile>) -> (!fir.ref<!fir.box<!fir.heap<!fir.type<{{.*}}>>>, volatile>, !fir.ref<!fir.box<!fir.heap<!fir.type<{{.*}}>>>, volatile>)
+! CHECK: %{{.+}}:2 = hlfir.declare %{{.+}} {fortran_attrs = #fir.var_attrs<allocatable, volatile>, uniq_name = "_QFtest_scalar_volatileEc1"} : (!fir.ref<!fir.box<!fir.heap<!fir.char<1,?>>, volatile>, volatile>) -> (!fir.ref<!fir.box<!fir.heap<!fir.char<1,?>>, volatile>, volatile>, !fir.ref<!fir.box<!fir.heap<!fir.char<1,?>>, volatile>, volatile>)
+! CHECK: %{{.+}}:2 = hlfir.declare %{{.+}} {fortran_attrs = #fir.var_attrs<allocatable, volatile>, uniq_name = "_QFtest_scalar_volatileEv1"} : (!fir.ref<!fir.class<!fir.heap<!fir.type<{{.*}}>>, volatile>, volatile>) -> (!fir.ref<!fir.class<!fir.heap<!fir.type<{{.*}}>>, volatile>, volatile>, !fir.ref<!fir.class<!fir.heap<!fir.type<{{.*}}>>, volatile>, volatile>)
+! CHECK: %{{.+}}:2 = hlfir.declare %{{.+}} {fortran_attrs = #fir.var_attrs<allocatable, volatile>, uniq_name = "_QFtest_scalar_volatileEv2"} : (!fir.ref<!fir.box<!fir.heap<!fir.type<{{.*}}>>, volatile>, volatile>) -> (!fir.ref<!fir.box<!fir.heap<!fir.type<{{.*}}>>, volatile>, volatile>, !fir.ref<!fir.box<!fir.heap<!fir.type<{{.*}}>>, volatile>, volatile>)
+! CHECK: %{{.+}}:2 = hlfir.declare %{{.+}} {fortran_attrs = #fir.var_attrs<allocatable, volatile>, uniq_name = "_QFtest_scalar_volatileEv3"} : (!fir.ref<!fir.box<!fir.heap<!fir.type<{{.*}}>>, volatile>, volatile>) -> (!fir.ref<!fir.box<!fir.heap<!fir.type<{{.*}}>>, volatile>, volatile>, !fir.ref<!fir.box<!fir.heap<!fir.type<{{.*}}>>, volatile>, volatile>)
! CHECK: fir.call @_FortranAAllocatableInitDerivedForAllocate(%{{.+}}, %{{.+}}, %{{.+}}, %{{.+}}) fastmath<contract> : (!fir.ref<!fir.box<none>>, !fir.ref<none>, i32, i32) -> ()
! CHECK: %{{.+}} = fir.call @_FortranAAllocatableAllocate(%{{.+}}, %{{.+}}, %{{.+}}, %{{.+}}, %{{.+}}, %{{.+}}) fastmath<contract> : (!fir.ref<!fir.box<none>>, i64, i1, !fir.box<none>, !fir.ref<i8>, i32) -> i32
! CHECK: fir.call @_FortranAAllocatableInitDerivedForAllocate(%{{.+}}, %{{.+}}, %{{.+}}, %{{.+}}) fastmath<contract> : (!fir.ref<!fir.box<none>>, !fir.ref<none>, i32, i32) -> ()
@@ -140,8 +140,8 @@ subroutine test_unlimited_polymorphic()
! CHECK: %{{.+}} = fir.call @_FortranAAllocatableDeallocate(%{{.+}}, %{{.+}}, %{{.+}}, %{{.+}}, %{{.+}}) fastmath<contract> : (!fir.ref<!fir.box<none>>, i1, !fir.box<none>, !fir.ref<i8>, i32) -> i32
! CHECK: %{{.+}} = fir.call @_FortranAAllocatableDeallocatePolymorphic(%{{.+}}, %{{.+}}, %{{.+}}, %{{.+}}, %{{.+}}, %{{.+}}) fastmath<contract> : (!fir.ref<!fir.box<none>>, !fir.ref<none>, i1, !fir.box<none>, !fir.ref<i8>, i32) -> i32
! CHECK-LABEL: func.func @_QPtest_volatile_asynchronous() {
-! CHECK: %{{.+}}:2 = hlfir.declare %{{.+}} {fortran_attrs = #fir.var_attrs<allocatable, asynchronous, volatile>, uniq_name = "_QFtest_volatile_asynchronousEi1"} : (!fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>, volatile>) -> (!fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>, volatile>, !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>, volatile>)
-! CHECK: %{{.+}}:2 = hlfir.declare %{{.+}} {fortran_attrs = #fir.var_attrs<allocatable, asynchronous, volatile>, uniq_name = "_QFtest_volatile_asynchronousEv1"} : (!fir.ref<!fir.class<!fir.heap<!fir.array<?x!fir.type<{{.*}}>>>>, volatile>) -> (!fir.ref<!fir.class<!fir.heap<!fir.array<?x!fir.type<{{.*}}>>>>, volatile>, !fir.ref<!fir.class<!fir.heap<!fir.array<?x!fir.type<{{.*}}>>>>, volatile>)
+! CHECK: %{{.+}}:2 = hlfir.declare %{{.+}} {fortran_attrs = #fir.var_attrs<allocatable, asynchronous, volatile>, uniq_name = "_QFtest_volatile_asynchronousEi1"} : (!fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>, volatile>, volatile>) -> (!fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>, volatile>, volatile>, !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>, volatile>, volatile>)
+! CHECK: %{{.+}}:2 = hlfir.declare %{{.+}} {fortran_attrs = #fir.var_attrs<allocatable, asynchronous, volatile>, uniq_name = "_QFtest_volatile_asynchronousEv1"} : (!fir.ref<!fir.class<!fir.heap<!fir.array<?x!fir.type<{{.*}}>>>, volatile>, volatile>) -> (!fir.ref<!fir.class<!fir.heap<!fir.array<?x!fir.type<{{.*}}>>>, volatile>, volatile>, !fir.ref<!fir.class<!fir.heap<!fir.array<?x!fir.type<{{.*}}>>>, volatile>, volatile>)
! CHECK: fir.call @_FortranAAllocatableInitDerivedForAllocate(%{{.+}}, %{{.+}}, %{{.+}}, %{{.+}}) fastmath<contract> : (!fir.ref<!fir.box<none>>, !fir.ref<none>, i32, i32) -> ()
! CHECK: fir.call @_FortranAAllocatableSetBounds(%{{.+}}, %{{.+}}, %{{.+}}, %{{.+}}) fastmath<contract> : (!fir.ref<!fir.box<none>>, i32, i64, i64) -> ()
! CHECK: %{{.+}} = fir.call @_FortranAAllocatableAllocate(%{{.+}}, %{{.+}}, %{{.+}}, %{{.+}}, %{{.+}}, %{{.+}}) fastmath<contract> : (!fir.ref<!fir.box<none>>, i64, i1, !fir.box<none>, !fir.ref<i8>, i32) -> i32
@@ -151,10 +151,11 @@ subroutine test_unlimited_polymorphic()
! CHECK: %{{.+}} = fir.call @_FortranAAllocatableDeallocatePolymorphic(%{{.+}}, %{{.+}}, %{{.+}}, %{{.+}}, %{{.+}}, %{{.+}}) fastmath<contract> : (!fir.ref<!fir.box<none>>, !fir.ref<none>, i1, !fir.box<none>, !fir.ref<i8>, i32) -> i32
! CHECK: %{{.+}} = fir.call @_FortranAAllocatableDeallocatePolymorphic(%{{.+}}, %{{.+}}, %{{.+}}, %{{.+}}, %{{.+}}, %{{.+}}) fastmath<contract> : (!fir.ref<!fir.box<none>>, !fir.ref<none>, i1, !fir.box<none>, !fir.ref<i8>, i32) -> i32
! CHECK-LABEL: func.func @_QPtest_select_base_type_volatile() {
-! CHECK: %{{.+}}:2 = hlfir.declare %{{.+}} {fortran_attrs = #fir.var_attrs<allocatable, volatile>, uniq_name = "_QFtest_select_base_type_volatileEv"} : (!fir.ref<!fir.class<!fir.heap<!fir.array<?x!fir.type<{{.*}}>>>>, volatile>) -> (!fir.ref<!fir.class<!fir.heap<!fir.array<?x!fir.type<{{.*}}>>>>, volatile>, !fir.ref<!fir.class<!fir.heap<!fir.array<?x!fir.type<{{.*}}>>>>, volatile>)
+! CHECK: %{{.+}}:2 = hlfir.declare %{{.+}} {fortran_attrs = #fir.var_attrs<allocatable, volatile>, uniq_name = "_QFtest_select_base_type_volatileEv"} : (!fir.ref<!fir.class<!fir.heap<!fir.array<?x!fir.type<{{.*}}>>>, volatile>, volatile>) -> (!fir.ref<!fir.class<!fir.heap<!fir.array<?x!fir.type<{{.*}}>>>, volatile>, volatile>, !fir.ref<!fir.class<!fir.heap<!fir.array<?x!fir.type<{{.*}}>>>, volatile>, volatile>)
! CHECK: fir.call @_FortranAAllocatableInitDerivedForAllocate(%{{.+}}, %{{.+}}, %{{.+}}, %{{.+}}) fastmath<contract> : (!fir.ref<!fir.box<none>>, !fir.ref<none>, i32, i32) -> ()
! CHECK: fir.call @_FortranAAllocatableSetBounds(%{{.+}}, %{{.+}}, %{{.+}}, %{{.+}}) fastmath<contract> : (!fir.ref<!fir.box<none>>, i32, i64, i64) -> ()
! CHECK: %{{.+}} = fir.call @_FortranAAllocatableAllocate(%{{.+}}, %{{.+}}, %{{.+}}, %{{.+}}, %{{.+}}, %{{.+}}) fastmath<contract> : (!fir.ref<!fir.box<none>>, i64, i1, !fir.box<none>, !fir.ref<i8>, i32) -> i32
+! CHECK: %{{.+}} = fir.call @_FortranAClassIs(%{{.+}}, %{{.+}}) : (!fir.box<none>, !fir.ref<none>) -> i1
! CHECK: %{{.+}}:2 = hlfir.declare %{{.+}}(%{{.+}}) {fortran_attrs = #fir.var_attrs<volatile>, uniq_name = "_QFtest_select_base_type_volatileEv"} : (!fir.class<!fir.heap<!fir.array<?x!fir.type<{{.*}}>>>, volatile>, !fir.shift<1>) -> (!fir.class<!fir.heap<!fir.array<?x!fir.type<{{.*}}>>>, volatile>, !fir.class<!fir.heap<!fir.array<?x!fir.type<{{.*}}>>>, volatile>)
! CHECK: %{{.+}} = hlfir.designate %{{.+}}#0 (%{{.+}}) : (!fir.class<!fir.heap<!fir.array<?x!fir.type<{{.*}}>>>, volatile>, index) -> !fir.class<!fir.type<{{.*}}>, volatile>
! CHECK: %{{.+}} = hlfir.designate %{{.+}}{"i"} : (!fir.class<!fir.type<{{.*}}>, volatile>) -> !fir.ref<i32, volatile>
@@ -162,7 +163,7 @@ subroutine test_unlimited_polymorphic()
! CHECK: %{{.+}} = fir.call @_FortranAAllocatableDeallocatePolymorphic(%{{.+}}, %{{.+}}, %{{.+}}, %{{.+}}, %{{.+}}, %{{.+}}) fastmath<contract> : (!fir.ref<!fir.box<none>>, !fir.ref<none>, i1, !fir.box<none>, !fir.ref<i8>, i32) -> i32
! CHECK-LABEL: func.func @_QPtest_mold_allocation() {
! CHECK: %{{.+}}:2 = hlfir.declare %{{.+}} {uniq_name = "_QFtest_mold_allocationEtemplate"} : (!fir.ref<!fir.type<{{.*}}>>) -> (!fir.ref<!fir.type<{{.*}}>>, !fir.ref<!fir.type<{{.*}}>>)
-! CHECK: %{{.+}}:2 = hlfir.declare %{{.+}} {fortran_attrs = #fir.var_attrs<allocatable, volatile>, uniq_name = "_QFtest_mold_allocationEv"} : (!fir.ref<!fir.box<!fir.heap<!fir.array<?x!fir.type<{{.*}}>>>>, volatile>) -> (!fir.ref<!fir.box<!fir.heap<!fir.array<?x!fir.type<{{.*}}>>>>, volatile>, !fir.ref<!fir.box<!fir.heap<!fir.array<?x!fir.type<{{.*}}>>>>, volatile>)
+! CHECK: %{{.+}}:2 = hlfir.declare %{{.+}} {fortran_attrs = #fir.var_attrs<allocatable, volatile>, uniq_name = "_QFtest_mold_allocationEv"} : (!fir.ref<!fir.box<!fir.heap<!fir.array<?x!fir.type<{{.*}}>>>, volatile>, volatile>) -> (!fir.ref<!fir.box<!fir.heap<!fir.array<?x!fir.type<{{.*}}>>>, volatile>, volatile>, !fir.ref<!fir.box<!fir.heap<!fir.array<?x!fir.type<{{.*}}>>>, volatile>, volatile>)
! CHECK: %{{.+}}:2 = hlfir.declare %{{.+}} typeparams %{{.+}} {fortran_attrs = #fir.var_attrs<parameter>, uniq_name = "_QQclX6D6F6C642074657374"} : (!fir.ref<!fir.char<1,9>>, index) -> (!fir.ref<!fir.char<1,9>>, !fir.ref<!fir.char<1,9>>)
! CHECK: %{{.+}} = hlfir.designate %{{.+}}#0{"str"} typeparams %{{.+}} : (!fir.ref<!fir.type<{{.*}}>>, index) -> !fir.ref<!fir.char<1,10>>
! CHECK: %{{.+}}:2 = hlfir.declare %{{.+}}(%{{.+}}) {fortran_attrs = #fir.var_attrs<parameter>, uniq_name = "_QQro.2xi4.2"} : (!fir.ref<!fir.array<2xi32>>, !fir.shape<1>) -> (!fir.ref<!fir.array<2xi32>>, !fir.ref<!fir.array<2xi32>>)
@@ -173,8 +174,8 @@ subroutine test_unlimited_polymorphic()
! CHECK: %{{.+}} = fir.call @_FortranAAllocatableDeallocate(%{{.+}}, %{{.+}}, %{{.+}}, %{{.+}}, %{{.+}}) fastmath<contract> : (!fir.ref<!fir.box<none>>, i1, !fir.box<none>, !fir.ref<i8>, i32) -> i32
! CHECK: %{{.+}} = fir.call @_FortranAAllocatableDeallocate(%{{.+}}, %{{.+}}, %{{.+}}, %{{.+}}, %{{.+}}) fastmath<contract> : (!fir.ref<!fir.box<none>>, i1, !fir.box<none>, !fir.ref<i8>, i32) -> i32
! CHECK-LABEL: func.func @_QPtest_unlimited_polymorphic() {
-! CHECK: %{{.+}}:2 = hlfir.declare %{{.+}} {fortran_attrs = #fir.var_attrs<allocatable, volatile>, uniq_name = "_QFtest_unlimited_polymorphicEup"} : (!fir.ref<!fir.class<!fir.heap<none>>, volatile>) -> (!fir.ref<!fir.class<!fir.heap<none>>, volatile>, !fir.ref<!fir.class<!fir.heap<none>>, volatile>)
-! CHECK: %{{.+}}:2 = hlfir.declare %{{.+}} {fortran_attrs = #fir.var_attrs<allocatable, volatile>, uniq_name = "_QFtest_unlimited_polymorphicEupa"} : (!fir.ref<!fir.class<!fir.heap<!fir.array<?xnone>>>, volatile>) -> (!fir.ref<!fir.class<!fir.heap<!fir.array<?xnone>>>, volatile>, !fir.ref<!fir.class<!fir.heap<!fir.array<?xnone>>>, volatile>)
+! CHECK: %{{.+}}:2 = hlfir.declare %{{.+}} {fortran_attrs = #fir.var_attrs<allocatable, volatile>, uniq_name = "_QFtest_unlimited_polymorphicEup"} : (!fir.ref<!fir.class<!fir.heap<none>, volatile>, volatile>) -> (!fir.ref<!fir.class<!fir.heap<none>, volatile>, volatile>, !fir.ref<!fir.class<!fir.heap<none>, volatile>, volatile>)
+! CHECK: %{{.+}}:2 = hlfir.declare %{{.+}} {fortran_attrs = #fir.var_attrs<allocatable, volatile>, uniq_name = "_QFtest_unlimited_polymorphicEupa"} : (!fir.ref<!fir.class<!fir.heap<!fir.array<?xnone>>, volatile>, volatile>) -> (!fir.ref<!fir.class<!fir.heap<!fir.array<?xnone>>, volatile>, volatile>, !fir.ref<!fir.class<!fir.heap<!fir.array<?xnone>>, volatile>, volatile>)
! CHECK: fir.call @_FortranAAllocatableInitIntrinsicForAllocate(%{{.+}}, %{{.+}}, %{{.+}}, %{{.+}}, %{{.+}}) fastmath<contract> : (!fir.ref<!fir.box<none>>, i32, i32, i32, i32) -> ()
! CHECK: %{{.+}} = fir.call @_FortranAAllocatableAllocate(%{{.+}}, %{{.+}}, %{{.+}}, %{{.+}}, %{{.+}}, %{{.+}}) fastmath<contract> : (!fir.ref<!fir.box<none>>, i64, i1, !fir.box<none>, !fir.ref<i8>, i32) -> i32
! CHECK: %{{.+}}:2 = hlfir.declare %{{.+}} {fortran_attrs = #fir.var_attrs<volatile>, uniq_name = "_QFtest_unlimited_polymorphicEup"} : (!fir.heap<i32>) -> (!fir.heap<i32>, !fir.heap<i32>)
diff --git a/flang/test/Lower/volatile-allocatable1.f90 b/flang/test/Lower/volatile-allocatable1.f90
index a21359c3b4225..d2a07c8763885 100644
--- a/flang/test/Lower/volatile-allocatable1.f90
+++ b/flang/test/Lower/volatile-allocatable1.f90
@@ -1,7 +1,6 @@
! RUN: bbc --strict-fir-volatile-verifier %s -o - | FileCheck %s
! Requires correct propagation of volatility for allocatable nested types.
-! XFAIL: *
function allocatable_udt()
type :: base_type
@@ -15,3 +14,19 @@ function allocatable_udt()
allocate(v2(2,3))
allocatable_udt = v2(1,1)%i
end function
+! CHECK-LABEL: func.func @_QPallocatable_udt() -> i32 {
+! CHECK: %{{.+}}:2 = hlfir.declare %{{.+}} typeparams %{{.+}} {fortran_attrs = #fir.var_attrs<target>, uniq_name = "_QFallocatable_udtE.n.i"} : (!fir.ref<!fir.char<1>>, index) -> (!fir.ref<!fir.char<1>>, !fir.ref<!fir.char<1>>)
+! CHECK: %{{.+}}:2 = hlfir.declare %{{.+}} {fortran_attrs = #fir.var_attrs<target>, uniq_name = "_QFallocatable_udtE.di.base_type.i"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
+! CHECK: %{{.+}}:2 = hlfir.declare %{{.+}} typeparams %{{.+}} {fortran_attrs = #fir.var_attrs<target>, uniq_name = "_QFallocatable_udtE.n.base_type"} : (!fir.ref<!fir.char<1,9>>, index) -> (!fir.ref<!fir.char<1,9>>, !fir.ref<!fir.char<1,9>>)
+! CHECK: %{{.+}}:2 = hlfir.declare %{{.+}} typeparams %{{.+}} {fortran_attrs = #fir.var_attrs<target>, uniq_name = "_QFallocatable_udtE.n.j"} : (!fir.ref<!fir.char<1>>, index) -> (!fir.ref<!fir.char<1>>, !fir.ref<!fir.char<1>>)
+! CHECK: %{{.+}}:2 = hlfir.declare %{{.+}} {fortran_attrs = #fir.var_attrs<target>, uniq_name = "_QFallocatable_udtE.di.ext_type.j"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
+! CHECK: %{{.+}}:2 = hlfir.declare %{{.+}} typeparams %{{.+}} {fortran_attrs = #fir.var_attrs<target>, uniq_name = "_QFallocatable_udtE.n.ext_type"} : (!fir.ref<!fir.char<1,8>>, index) -> (!fir.ref<!fir.char<1,8>>, !fir.ref<!fir.char<1,8>>)
+! CHECK: %{{.+}}:2 = hlfir.declare %{{.+}} {uniq_name = "_QFallocatable_udtEallocatable_udt"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
+! CHECK: %{{.+}}:2 = hlfir.declare %{{.+}} {fortran_attrs = #fir.var_attrs<allocatable, volatile>, uniq_name = "_QFallocatable_udtEv2"} : (!fir.ref<!fir.box<!fir.heap<!fir.array<?x?x!fir.type<{{.*}}>>>, volatile>, volatile>) -> (!fir.ref<!fir.box<!fir.heap<!fir.array<?x?x!fir.type<{{.*}}>>>, volatile>, volatile>, !fir.ref<!fir.box<!fir.heap<!fir.array<?x?x!fir.type<{{.*}}>>>, volatile>, volatile>)
+! CHECK: %{{.+}}:2 = hlfir.declare %{{.+}}(%{{.+}}) {fortran_attrs = #fir.var_attrs<target>, uniq_name = "_QFallocatable_udtE.c.base_type"} : (!fir.ref<!fir.array<1x!fir.type<{{.*}}>>>, !fir.shapeshift<1>) -> (!fir.box<!fir.array<1x!fir.type<{{.*}}>>>, !fir.ref<!fir.array<1x!fir.type<{{.*}}>>>)
+! CHECK: %{{.+}}:2 = hlfir.declare %{{.+}} {fortran_attrs = #fir.var_attrs<target>, uniq_name = "_QFallocatable_udtE.dt.base_type"} : (!fir.ref<!fir.type<{{.*}}>>) -> (!fir.ref<!fir.type<{{.*}}>>, !fir.ref<!fir.type<{{.*}}>>)
+! CHECK: %{{.+}}:2 = hlfir.declare %{{.+}} {fortran_attrs = #fir.var_attrs<target>, uniq_name = "_QFallocatable_udtE.dt.ext_type"} : (!fir.ref<!fir.type<{{.*}}>>) -> (!fir.ref<!fir.type<{{.*}}>>, !fir.ref<!fir.type<{{.*}}>>)
+! CHECK: %{{.+}}:2 = hlfir.declare %{{.+}}(%{{.+}}) {fortran_attrs = #fir.var_attrs<target>, uniq_name = "_QFallocatable_udtE.c.ext_type"} : (!fir.ref<!fir.array<2x!fir.type<{{.*}}>>>, !fir.shapeshift<1>) -> (!fir.box<!fir.array<2x!fir.type<{{.*}}>>>, !fir.ref<!fir.array<2x!fir.type<{{.*}}>>>)
+! CHECK: %{{.+}} = hlfir.designate %{{.+}} (%{{.+}}, %{{.+}}) : (!fir.box<!fir.heap<!fir.array<?x?x!fir.type<{{.*}}>>>, volatile>, index, index) -> !fir.ref<!fir.type<{{.*}}>, volatile>
+! CHECK: %{{.+}} = hlfir.designate %{{.+}}{"base_type"} : (!fir.ref<!fir.type<{{.*}}>, volatile>) -> !fir.ref<!fir.type<{{.*}}>, volatile>
+! CHECK: %{{.+}} = hlfir.designate %{{.+}}{"i"} : (!fir.ref<!fir.type<{{.*}}>, volatile>) -> !fir.ref<i32, volatile>
More information about the flang-commits
mailing list