-
Notifications
You must be signed in to change notification settings - Fork 13.5k
[flang] Fix volatile attribute propagation on allocatables #139183
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] Fix volatile attribute propagation on allocatables #139183
Conversation
@llvm/pr-subscribers-flang-fir-hlfir Author: Asher Mancinelli (ashermancinelli) ChangesEnsure 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:
Patch is 28.10 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/139183.diff 7 Files Affected:
diff --git a/flang/lib/Lower/Bridge.cpp b/flang/lib/Lower/Bridge.cpp
index 0a61f61ab8f75..3706dcf37a204 100644
--- a/flang/lib/Lower/Bridge.cpp
+++ b/flang/lib/Lower/Bridge.cpp
@@ -3845,6 +3845,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);
@@ -3998,7 +4002,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>(
@@ -4007,7 +4012,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) {
@@ -4022,7 +4028,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>(
@@ -4040,7 +4047,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 332cca1ab9f95..75185e719393f 100644
--- a/flang/lib/Optimizer/Dialect/FIROps.cpp
+++ b/flang/lib/Optimizer/Dialect/FIROps.cpp
@@ -1536,20 +1536,51 @@ 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..52517eef2890d 100644
--- a/flang/lib/Optimizer/HLFIR/IR/HLFIROps.cpp
+++ b/flang/lib/Optimizer/HLFIR/IR/HLFIROps.cpp
@@ -207,20 +207,25 @@ static bool hasExplicitLowerBounds(mlir::Value shape) {
mlir::isa<fir::ShapeShiftType, fir::ShiftType>(shape.getType());
}
-static std::pair<mlir::Type, mlir::Value> updateDeclareInputTypeWithVolatility(
+static std::pair<mlir::Type, mlir::Value> updateDeclaredInputTypeWithVolatility(
mlir::Type inputType, mlir::Value memref, mlir::OpBuilder &builder,
fir::FortranVariableFlagsAttr fortran_attrs) {
if (fortran_attrs &&
bitEnumContainsAny(fortran_attrs.getFlags(),
fir::FortranVariableFlagsEnum::fortran_volatile)) {
+ // A volatile pointer's pointee is volatile.
const bool isPointer = bitEnumContainsAny(
fortran_attrs.getFlags(), fir::FortranVariableFlagsEnum::pointer);
+ // An allocatable's inner type's volatility matches that of the reference.
+ const bool isAllocatable = bitEnumContainsAny(
+ fortran_attrs.getFlags(), fir::FortranVariableFlagsEnum::allocatable);
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);
+ const bool elementTypeIsBox = mlir::isa<fir::BoxType>(elementType);
+ const bool elementTypeIsVolatile = isPointer || isAllocatable ||
+ elementTypeIsBox ||
+ fir::isa_volatile_type(elementType);
auto newEleTy =
fir::updateTypeWithVolatility(elementType, elementTypeIsVolatile);
inputType = FIRT::get(newEleTy, true);
@@ -243,7 +248,7 @@ 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(
+ std::tie(inputType, memref) = updateDeclaredInputTypeWithVolatility(
inputType, memref, builder, fortran_attrs);
mlir::Type hlfirVariableType =
getHLFIRVariableType(inputType, hasExplicitLbs);
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..834eea7df8ebe 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@+1 {{'fir.convert' op cannot convert between volatile and non-volatile types, use fir.volatile_cast instead}}
+ // expected-error@+1 {{op this conversion does not preserve volatilit}}
%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@+1 {{'fir.convert' op cannot convert between volatile and non-volatile types, use fir.volatile_cast instead}}
+ // expected-error@+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 = h...
[truncated]
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, LGTM.
If you need special handling in the SELECT TYPE, do you also need something for SELECT RANK?
I see the SELECT RANK cases and statements using only simple reference types, which I handled in earlier patches. I had not propagated volatile on CLASSes in SELECT TYPE because I had not yet enabled the propagation of the VOLATILE attribute to class entities when creating designators. This patch brings SELECT TYPE in line with what is already in SELECT RANK, but I'll reread those cases in the bridge to see if I'm missing anything. Thanks! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks!
Ensure volatility is reflected not just on the reference of an allocatable, but on the box, too. When we designate a volatile allocatable, we now get a volatile reference to a volatile box. Some related cleanups: * SELECT TYPE constructs properly handle volatility by checking the selector's type for volatility when creating the target type. * Refine the verifier for fir.convert. In general, I think it should be ok to implicitly drop volatility in any ptr-to-int conversion because it means we are in codegen or we are calling an external function, and it's okay to drop volatility from the Fir type system in these cases. * An allocatable test that was XFAILed is now passing. * I noticed a runtime function was missing the fir.runtime attribute. Fix that.
664243c
to
0345444
Compare
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: