[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.
This commit is contained in:
parent
4b794c8aff
commit
bbb7f01481
@ -3842,6 +3842,10 @@ private:
|
||||
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 @@ private:
|
||||
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 @@ private:
|
||||
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 @@ private:
|
||||
} 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 @@ private:
|
||||
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 {
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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 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@+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>
|
||||
}
|
||||
|
@ -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 @@ end subroutine
|
||||
! 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 @@ end subroutine
|
||||
! 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 @@ end subroutine
|
||||
! 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 @@ end subroutine
|
||||
! 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>)
|
||||
|
@ -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>
|
||||
|
Loading…
x
Reference in New Issue
Block a user