diff --git a/flang/lib/Lower/Bridge.cpp b/flang/lib/Lower/Bridge.cpp index 43375e84f21fa..169a2780ea14d 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 typeCaseScopes; + const auto selectorIsVolatile = [&selector]() { + return fir::isa_volatile_type(fir::getBase(selector).getType()); + }; + const auto &typeCaseList = std::get>( selectTypeConstruct.t); @@ -3995,7 +3999,8 @@ class FirConverter : public Fortran::lower::AbstractConverter { addrTy = fir::HeapType::get(addrTy); if (std::holds_alternative( 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( @@ -4004,7 +4009,8 @@ class FirConverter : public Fortran::lower::AbstractConverter { typeSpec->declTypeSpec->AsIntrinsic(); if (isArray) { mlir::Value exact = builder->create( - 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( typeSpec->u)) { exactValue = builder->create( - 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( @@ -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 332cca1ab9f95..b10b5d998fa70 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(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. This is allowed. + const bool isBoxNoneLike = [&]() { + if (fir::isBoxNone(outType)) + return true; + if (auto referenceType = mlir::dyn_cast(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(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(shape.getType()); } -static std::pair 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(inputType) - .Case(updateType); - memref = - builder.create(memref.getLoc(), inputType, memref); +static std::pair +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(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(inputType) + .Case(updateType); + memref = + builder.create(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(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) -> !fir.ref { - // 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) -> !fir.ref return %0 : !fir.ref } @@ -1269,7 +1269,7 @@ func.func @bad_convert_volatile(%arg0: !fir.ref) -> !fir.ref // Should fail when volatility changes from a fir.convert func.func @bad_convert_volatile2(%arg0: !fir.ref) -> !fir.ref { - // 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) -> !fir.ref return %0 : !fir.ref } 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, uniq_name = "_QFtest_scalar_volatileEc1"} : (!fir.ref>>, volatile>) -> (!fir.ref>>, volatile>, !fir.ref>>, volatile>) -! CHECK: %{{.+}}:2 = hlfir.declare %{{.+}} {fortran_attrs = #fir.var_attrs, uniq_name = "_QFtest_scalar_volatileEv1"} : (!fir.ref>>, volatile>) -> (!fir.ref>>, volatile>, !fir.ref>>, volatile>) -! CHECK: %{{.+}}:2 = hlfir.declare %{{.+}} {fortran_attrs = #fir.var_attrs, uniq_name = "_QFtest_scalar_volatileEv2"} : (!fir.ref>>, volatile>) -> (!fir.ref>>, volatile>, !fir.ref>>, volatile>) -! CHECK: %{{.+}}:2 = hlfir.declare %{{.+}} {fortran_attrs = #fir.var_attrs, uniq_name = "_QFtest_scalar_volatileEv3"} : (!fir.ref>>, volatile>) -> (!fir.ref>>, volatile>, !fir.ref>>, volatile>) +! CHECK: %{{.+}}:2 = hlfir.declare %{{.+}} {fortran_attrs = #fir.var_attrs, uniq_name = "_QFtest_scalar_volatileEc1"} : (!fir.ref>, volatile>, volatile>) -> (!fir.ref>, volatile>, volatile>, !fir.ref>, volatile>, volatile>) +! CHECK: %{{.+}}:2 = hlfir.declare %{{.+}} {fortran_attrs = #fir.var_attrs, uniq_name = "_QFtest_scalar_volatileEv1"} : (!fir.ref>, volatile>, volatile>) -> (!fir.ref>, volatile>, volatile>, !fir.ref>, volatile>, volatile>) +! CHECK: %{{.+}}:2 = hlfir.declare %{{.+}} {fortran_attrs = #fir.var_attrs, uniq_name = "_QFtest_scalar_volatileEv2"} : (!fir.ref>, volatile>, volatile>) -> (!fir.ref>, volatile>, volatile>, !fir.ref>, volatile>, volatile>) +! CHECK: %{{.+}}:2 = hlfir.declare %{{.+}} {fortran_attrs = #fir.var_attrs, uniq_name = "_QFtest_scalar_volatileEv3"} : (!fir.ref>, volatile>, volatile>) -> (!fir.ref>, volatile>, volatile>, !fir.ref>, volatile>, volatile>) ! CHECK: fir.call @_FortranAAllocatableInitDerivedForAllocate(%{{.+}}, %{{.+}}, %{{.+}}, %{{.+}}) fastmath : (!fir.ref>, !fir.ref, i32, i32) -> () ! CHECK: %{{.+}} = fir.call @_FortranAAllocatableAllocate(%{{.+}}, %{{.+}}, %{{.+}}, %{{.+}}, %{{.+}}, %{{.+}}) fastmath : (!fir.ref>, i64, i1, !fir.box, !fir.ref, i32) -> i32 ! CHECK: fir.call @_FortranAAllocatableInitDerivedForAllocate(%{{.+}}, %{{.+}}, %{{.+}}, %{{.+}}) fastmath : (!fir.ref>, !fir.ref, i32, i32) -> () @@ -140,8 +140,8 @@ subroutine test_unlimited_polymorphic() ! CHECK: %{{.+}} = fir.call @_FortranAAllocatableDeallocate(%{{.+}}, %{{.+}}, %{{.+}}, %{{.+}}, %{{.+}}) fastmath : (!fir.ref>, i1, !fir.box, !fir.ref, i32) -> i32 ! CHECK: %{{.+}} = fir.call @_FortranAAllocatableDeallocatePolymorphic(%{{.+}}, %{{.+}}, %{{.+}}, %{{.+}}, %{{.+}}, %{{.+}}) fastmath : (!fir.ref>, !fir.ref, i1, !fir.box, !fir.ref, i32) -> i32 ! CHECK-LABEL: func.func @_QPtest_volatile_asynchronous() { -! CHECK: %{{.+}}:2 = hlfir.declare %{{.+}} {fortran_attrs = #fir.var_attrs, uniq_name = "_QFtest_volatile_asynchronousEi1"} : (!fir.ref>>, volatile>) -> (!fir.ref>>, volatile>, !fir.ref>>, volatile>) -! CHECK: %{{.+}}:2 = hlfir.declare %{{.+}} {fortran_attrs = #fir.var_attrs, uniq_name = "_QFtest_volatile_asynchronousEv1"} : (!fir.ref>>>, volatile>) -> (!fir.ref>>>, volatile>, !fir.ref>>>, volatile>) +! CHECK: %{{.+}}:2 = hlfir.declare %{{.+}} {fortran_attrs = #fir.var_attrs, uniq_name = "_QFtest_volatile_asynchronousEi1"} : (!fir.ref>, volatile>, volatile>) -> (!fir.ref>, volatile>, volatile>, !fir.ref>, volatile>, volatile>) +! CHECK: %{{.+}}:2 = hlfir.declare %{{.+}} {fortran_attrs = #fir.var_attrs, uniq_name = "_QFtest_volatile_asynchronousEv1"} : (!fir.ref>>, volatile>, volatile>) -> (!fir.ref>>, volatile>, volatile>, !fir.ref>>, volatile>, volatile>) ! CHECK: fir.call @_FortranAAllocatableInitDerivedForAllocate(%{{.+}}, %{{.+}}, %{{.+}}, %{{.+}}) fastmath : (!fir.ref>, !fir.ref, i32, i32) -> () ! CHECK: fir.call @_FortranAAllocatableSetBounds(%{{.+}}, %{{.+}}, %{{.+}}, %{{.+}}) fastmath : (!fir.ref>, i32, i64, i64) -> () ! CHECK: %{{.+}} = fir.call @_FortranAAllocatableAllocate(%{{.+}}, %{{.+}}, %{{.+}}, %{{.+}}, %{{.+}}, %{{.+}}) fastmath : (!fir.ref>, i64, i1, !fir.box, !fir.ref, i32) -> i32 @@ -151,10 +151,11 @@ subroutine test_unlimited_polymorphic() ! CHECK: %{{.+}} = fir.call @_FortranAAllocatableDeallocatePolymorphic(%{{.+}}, %{{.+}}, %{{.+}}, %{{.+}}, %{{.+}}, %{{.+}}) fastmath : (!fir.ref>, !fir.ref, i1, !fir.box, !fir.ref, i32) -> i32 ! CHECK: %{{.+}} = fir.call @_FortranAAllocatableDeallocatePolymorphic(%{{.+}}, %{{.+}}, %{{.+}}, %{{.+}}, %{{.+}}, %{{.+}}) fastmath : (!fir.ref>, !fir.ref, i1, !fir.box, !fir.ref, i32) -> i32 ! CHECK-LABEL: func.func @_QPtest_select_base_type_volatile() { -! CHECK: %{{.+}}:2 = hlfir.declare %{{.+}} {fortran_attrs = #fir.var_attrs, uniq_name = "_QFtest_select_base_type_volatileEv"} : (!fir.ref>>>, volatile>) -> (!fir.ref>>>, volatile>, !fir.ref>>>, volatile>) +! CHECK: %{{.+}}:2 = hlfir.declare %{{.+}} {fortran_attrs = #fir.var_attrs, uniq_name = "_QFtest_select_base_type_volatileEv"} : (!fir.ref>>, volatile>, volatile>) -> (!fir.ref>>, volatile>, volatile>, !fir.ref>>, volatile>, volatile>) ! CHECK: fir.call @_FortranAAllocatableInitDerivedForAllocate(%{{.+}}, %{{.+}}, %{{.+}}, %{{.+}}) fastmath : (!fir.ref>, !fir.ref, i32, i32) -> () ! CHECK: fir.call @_FortranAAllocatableSetBounds(%{{.+}}, %{{.+}}, %{{.+}}, %{{.+}}) fastmath : (!fir.ref>, i32, i64, i64) -> () ! CHECK: %{{.+}} = fir.call @_FortranAAllocatableAllocate(%{{.+}}, %{{.+}}, %{{.+}}, %{{.+}}, %{{.+}}, %{{.+}}) fastmath : (!fir.ref>, i64, i1, !fir.box, !fir.ref, i32) -> i32 +! CHECK: %{{.+}} = fir.call @_FortranAClassIs(%{{.+}}, %{{.+}}) : (!fir.box, !fir.ref) -> i1 ! CHECK: %{{.+}}:2 = hlfir.declare %{{.+}}(%{{.+}}) {fortran_attrs = #fir.var_attrs, uniq_name = "_QFtest_select_base_type_volatileEv"} : (!fir.class>>, volatile>, !fir.shift<1>) -> (!fir.class>>, volatile>, !fir.class>>, volatile>) ! CHECK: %{{.+}} = hlfir.designate %{{.+}}#0 (%{{.+}}) : (!fir.class>>, volatile>, index) -> !fir.class, volatile> ! CHECK: %{{.+}} = hlfir.designate %{{.+}}{"i"} : (!fir.class, volatile>) -> !fir.ref @@ -162,7 +163,7 @@ subroutine test_unlimited_polymorphic() ! CHECK: %{{.+}} = fir.call @_FortranAAllocatableDeallocatePolymorphic(%{{.+}}, %{{.+}}, %{{.+}}, %{{.+}}, %{{.+}}, %{{.+}}) fastmath : (!fir.ref>, !fir.ref, i1, !fir.box, !fir.ref, i32) -> i32 ! CHECK-LABEL: func.func @_QPtest_mold_allocation() { ! CHECK: %{{.+}}:2 = hlfir.declare %{{.+}} {uniq_name = "_QFtest_mold_allocationEtemplate"} : (!fir.ref>) -> (!fir.ref>, !fir.ref>) -! CHECK: %{{.+}}:2 = hlfir.declare %{{.+}} {fortran_attrs = #fir.var_attrs, uniq_name = "_QFtest_mold_allocationEv"} : (!fir.ref>>>, volatile>) -> (!fir.ref>>>, volatile>, !fir.ref>>>, volatile>) +! CHECK: %{{.+}}:2 = hlfir.declare %{{.+}} {fortran_attrs = #fir.var_attrs, uniq_name = "_QFtest_mold_allocationEv"} : (!fir.ref>>, volatile>, volatile>) -> (!fir.ref>>, volatile>, volatile>, !fir.ref>>, volatile>, volatile>) ! CHECK: %{{.+}}:2 = hlfir.declare %{{.+}} typeparams %{{.+}} {fortran_attrs = #fir.var_attrs, uniq_name = "_QQclX6D6F6C642074657374"} : (!fir.ref>, index) -> (!fir.ref>, !fir.ref>) ! CHECK: %{{.+}} = hlfir.designate %{{.+}}#0{"str"} typeparams %{{.+}} : (!fir.ref>, index) -> !fir.ref> ! CHECK: %{{.+}}:2 = hlfir.declare %{{.+}}(%{{.+}}) {fortran_attrs = #fir.var_attrs, uniq_name = "_QQro.2xi4.2"} : (!fir.ref>, !fir.shape<1>) -> (!fir.ref>, !fir.ref>) @@ -173,8 +174,8 @@ subroutine test_unlimited_polymorphic() ! CHECK: %{{.+}} = fir.call @_FortranAAllocatableDeallocate(%{{.+}}, %{{.+}}, %{{.+}}, %{{.+}}, %{{.+}}) fastmath : (!fir.ref>, i1, !fir.box, !fir.ref, i32) -> i32 ! CHECK: %{{.+}} = fir.call @_FortranAAllocatableDeallocate(%{{.+}}, %{{.+}}, %{{.+}}, %{{.+}}, %{{.+}}) fastmath : (!fir.ref>, i1, !fir.box, !fir.ref, i32) -> i32 ! CHECK-LABEL: func.func @_QPtest_unlimited_polymorphic() { -! CHECK: %{{.+}}:2 = hlfir.declare %{{.+}} {fortran_attrs = #fir.var_attrs, uniq_name = "_QFtest_unlimited_polymorphicEup"} : (!fir.ref>, volatile>) -> (!fir.ref>, volatile>, !fir.ref>, volatile>) -! CHECK: %{{.+}}:2 = hlfir.declare %{{.+}} {fortran_attrs = #fir.var_attrs, uniq_name = "_QFtest_unlimited_polymorphicEupa"} : (!fir.ref>>, volatile>) -> (!fir.ref>>, volatile>, !fir.ref>>, volatile>) +! CHECK: %{{.+}}:2 = hlfir.declare %{{.+}} {fortran_attrs = #fir.var_attrs, uniq_name = "_QFtest_unlimited_polymorphicEup"} : (!fir.ref, volatile>, volatile>) -> (!fir.ref, volatile>, volatile>, !fir.ref, volatile>, volatile>) +! CHECK: %{{.+}}:2 = hlfir.declare %{{.+}} {fortran_attrs = #fir.var_attrs, uniq_name = "_QFtest_unlimited_polymorphicEupa"} : (!fir.ref>, volatile>, volatile>) -> (!fir.ref>, volatile>, volatile>, !fir.ref>, volatile>, volatile>) ! CHECK: fir.call @_FortranAAllocatableInitIntrinsicForAllocate(%{{.+}}, %{{.+}}, %{{.+}}, %{{.+}}, %{{.+}}) fastmath : (!fir.ref>, i32, i32, i32, i32) -> () ! CHECK: %{{.+}} = fir.call @_FortranAAllocatableAllocate(%{{.+}}, %{{.+}}, %{{.+}}, %{{.+}}, %{{.+}}, %{{.+}}) fastmath : (!fir.ref>, i64, i1, !fir.box, !fir.ref, i32) -> i32 ! CHECK: %{{.+}}:2 = hlfir.declare %{{.+}} {fortran_attrs = #fir.var_attrs, uniq_name = "_QFtest_unlimited_polymorphicEup"} : (!fir.heap) -> (!fir.heap, !fir.heap) 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, uniq_name = "_QFallocatable_udtE.n.i"} : (!fir.ref>, index) -> (!fir.ref>, !fir.ref>) +! CHECK: %{{.+}}:2 = hlfir.declare %{{.+}} {fortran_attrs = #fir.var_attrs, uniq_name = "_QFallocatable_udtE.di.base_type.i"} : (!fir.ref) -> (!fir.ref, !fir.ref) +! CHECK: %{{.+}}:2 = hlfir.declare %{{.+}} typeparams %{{.+}} {fortran_attrs = #fir.var_attrs, uniq_name = "_QFallocatable_udtE.n.base_type"} : (!fir.ref>, index) -> (!fir.ref>, !fir.ref>) +! CHECK: %{{.+}}:2 = hlfir.declare %{{.+}} typeparams %{{.+}} {fortran_attrs = #fir.var_attrs, uniq_name = "_QFallocatable_udtE.n.j"} : (!fir.ref>, index) -> (!fir.ref>, !fir.ref>) +! CHECK: %{{.+}}:2 = hlfir.declare %{{.+}} {fortran_attrs = #fir.var_attrs, uniq_name = "_QFallocatable_udtE.di.ext_type.j"} : (!fir.ref) -> (!fir.ref, !fir.ref) +! CHECK: %{{.+}}:2 = hlfir.declare %{{.+}} typeparams %{{.+}} {fortran_attrs = #fir.var_attrs, uniq_name = "_QFallocatable_udtE.n.ext_type"} : (!fir.ref>, index) -> (!fir.ref>, !fir.ref>) +! CHECK: %{{.+}}:2 = hlfir.declare %{{.+}} {uniq_name = "_QFallocatable_udtEallocatable_udt"} : (!fir.ref) -> (!fir.ref, !fir.ref) +! CHECK: %{{.+}}:2 = hlfir.declare %{{.+}} {fortran_attrs = #fir.var_attrs, uniq_name = "_QFallocatable_udtEv2"} : (!fir.ref>>, volatile>, volatile>) -> (!fir.ref>>, volatile>, volatile>, !fir.ref>>, volatile>, volatile>) +! CHECK: %{{.+}}:2 = hlfir.declare %{{.+}}(%{{.+}}) {fortran_attrs = #fir.var_attrs, uniq_name = "_QFallocatable_udtE.c.base_type"} : (!fir.ref>>, !fir.shapeshift<1>) -> (!fir.box>>, !fir.ref>>) +! CHECK: %{{.+}}:2 = hlfir.declare %{{.+}} {fortran_attrs = #fir.var_attrs, uniq_name = "_QFallocatable_udtE.dt.base_type"} : (!fir.ref>) -> (!fir.ref>, !fir.ref>) +! CHECK: %{{.+}}:2 = hlfir.declare %{{.+}} {fortran_attrs = #fir.var_attrs, uniq_name = "_QFallocatable_udtE.dt.ext_type"} : (!fir.ref>) -> (!fir.ref>, !fir.ref>) +! CHECK: %{{.+}}:2 = hlfir.declare %{{.+}}(%{{.+}}) {fortran_attrs = #fir.var_attrs, uniq_name = "_QFallocatable_udtE.c.ext_type"} : (!fir.ref>>, !fir.shapeshift<1>) -> (!fir.box>>, !fir.ref>>) +! CHECK: %{{.+}} = hlfir.designate %{{.+}} (%{{.+}}, %{{.+}}) : (!fir.box>>, volatile>, index, index) -> !fir.ref, volatile> +! CHECK: %{{.+}} = hlfir.designate %{{.+}}{"base_type"} : (!fir.ref, volatile>) -> !fir.ref, volatile> +! CHECK: %{{.+}} = hlfir.designate %{{.+}}{"i"} : (!fir.ref, volatile>) -> !fir.ref