-
Notifications
You must be signed in to change notification settings - Fork 13.4k
[flang] Correctly prepare allocatable runtime call arguments #138727
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
base: main
Are you sure you want to change the base?
[flang] Correctly prepare allocatable runtime call arguments #138727
Conversation
When lowering allocatables, the generated calls to runtime functions were not using the runtime::createArguments utility which handles the required conversions. createArguments is where I added the implicit volatile casts to handle converting volatile variables to the appropriate type based on their volatility in the callee. Because the calls to allocatable runtime functions were not using this function, their arguments were not casted to the appropriate volatility. Add a test to demonstrate that volatile and allocatable class/box/reference types are appropriately casted before calling into the runtime library. Instead of using a recursive variadic template to perform the conversions in createArguments, map over the arguments directly so that createArguments can be called with an ArrayRef of arguments. Some cases in Allocatable.cpp already had a vector of values at the point where createArguments needed to be called - the new overload allows calling with a vector of args or the variadic version with each argument spelled out at the callsite. This change resulted in the allocatable runtime calls having their arguments converted in left-to-right order, which changed some of the test results. I used CHECK-DAG to ignore the order.
@llvm/pr-subscribers-flang-fir-hlfir Author: Asher Mancinelli (ashermancinelli) ChangesWhen lowering allocatables, the generated calls to runtime functions were not using the runtime::createArguments utility which handles the required conversions. createArguments is where I added the implicit volatile casts to handle converting volatile variables to the appropriate type based on their volatility in the callee. Because the calls to allocatable runtime functions were not using this function, their arguments were not casted to have the appropriate volatility. Add a test to demonstrate that volatile and allocatable class/box/reference types are appropriately casted before calling into the runtime library. Instead of using a recursive variadic template to perform the conversions in createArguments, map over the arguments directly so that createArguments can be called with an ArrayRef of arguments. Some cases in Allocatable.cpp already had a vector of values at the point where createArguments needed to be called - the new overload allows calling with a vector of args or the variadic version with each argument spelled out at the callsite. This change resulted in the allocatable runtime calls having their arguments converted left-to-right, which changed some of the test results. I used CHECK-DAG to ignore the order. Add some missing handling of volatile class entities, which I previously missed because I had not yet enabled volatile class entities in Lower. Patch is 55.61 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/138727.diff 9 Files Affected:
diff --git a/flang/include/flang/Optimizer/Builder/Runtime/RTBuilder.h b/flang/include/flang/Optimizer/Builder/Runtime/RTBuilder.h
index 5440b36c0c628..98d7de81c7f08 100644
--- a/flang/include/flang/Optimizer/Builder/Runtime/RTBuilder.h
+++ b/flang/include/flang/Optimizer/Builder/Runtime/RTBuilder.h
@@ -26,6 +26,7 @@
#include "flang/Support/Fortran.h"
#include "mlir/IR/BuiltinTypes.h"
#include "mlir/IR/MLIRContext.h"
+#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallVector.h"
#include <cstdint>
#include <functional>
@@ -824,33 +825,23 @@ static mlir::func::FuncOp getIORuntimeFunc(mlir::Location loc,
return getRuntimeFunc<E>(loc, builder, /*isIO=*/true);
}
-namespace helper {
-template <int N, typename A>
-void createArguments(llvm::SmallVectorImpl<mlir::Value> &result,
- fir::FirOpBuilder &builder, mlir::Location loc,
- mlir::FunctionType fTy, A arg) {
- result.emplace_back(
- builder.createConvertWithVolatileCast(loc, fTy.getInput(N), arg));
-}
-
-template <int N, typename A, typename... As>
-void createArguments(llvm::SmallVectorImpl<mlir::Value> &result,
- fir::FirOpBuilder &builder, mlir::Location loc,
- mlir::FunctionType fTy, A arg, As... args) {
- result.emplace_back(
- builder.createConvertWithVolatileCast(loc, fTy.getInput(N), arg));
- createArguments<N + 1>(result, builder, loc, fTy, args...);
+inline llvm::SmallVector<mlir::Value>
+createArguments(fir::FirOpBuilder &builder, mlir::Location loc,
+ mlir::FunctionType fTy, llvm::ArrayRef<mlir::Value> args) {
+ return llvm::map_to_vector(llvm::zip_equal(fTy.getInputs(), args),
+ [&](const auto &pair) -> mlir::Value {
+ auto [type, argument] = pair;
+ return builder.createConvertWithVolatileCast(
+ loc, type, argument);
+ });
}
-} // namespace helper
/// Create a SmallVector of arguments for a runtime call.
template <typename... As>
llvm::SmallVector<mlir::Value>
createArguments(fir::FirOpBuilder &builder, mlir::Location loc,
mlir::FunctionType fTy, As... args) {
- llvm::SmallVector<mlir::Value> result;
- helper::createArguments<0>(result, builder, loc, fTy, args...);
- return result;
+ return createArguments(builder, loc, fTy, {args...});
}
} // namespace fir::runtime
diff --git a/flang/lib/Lower/Allocatable.cpp b/flang/lib/Lower/Allocatable.cpp
index 8d0444a6e5bd4..7e32575caad9b 100644
--- a/flang/lib/Lower/Allocatable.cpp
+++ b/flang/lib/Lower/Allocatable.cpp
@@ -138,12 +138,10 @@ static void genRuntimeSetBounds(fir::FirOpBuilder &builder, mlir::Location loc,
builder)
: fir::runtime::getRuntimeFunc<mkRTKey(AllocatableSetBounds)>(
loc, builder);
- llvm::SmallVector<mlir::Value> args{box.getAddr(), dimIndex, lowerBound,
- upperBound};
- llvm::SmallVector<mlir::Value> operands;
- for (auto [fst, snd] : llvm::zip(args, callee.getFunctionType().getInputs()))
- operands.emplace_back(builder.createConvert(loc, snd, fst));
- builder.create<fir::CallOp>(loc, callee, operands);
+ const auto args = fir::runtime::createArguments(
+ builder, loc, callee.getFunctionType(), box.getAddr(), dimIndex,
+ lowerBound, upperBound);
+ builder.create<fir::CallOp>(loc, callee, args);
}
/// Generate runtime call to set the lengths of a character allocatable or
@@ -162,9 +160,7 @@ static void genRuntimeInitCharacter(fir::FirOpBuilder &builder,
if (inputTypes.size() != 5)
fir::emitFatalError(
loc, "AllocatableInitCharacter runtime interface not as expected");
- llvm::SmallVector<mlir::Value> args;
- args.push_back(builder.createConvert(loc, inputTypes[0], box.getAddr()));
- args.push_back(builder.createConvert(loc, inputTypes[1], len));
+ llvm::SmallVector<mlir::Value> args = {box.getAddr(), len};
if (kind == 0)
kind = mlir::cast<fir::CharacterType>(box.getEleTy()).getFKind();
args.push_back(builder.createIntegerConstant(loc, inputTypes[2], kind));
@@ -173,7 +169,9 @@ static void genRuntimeInitCharacter(fir::FirOpBuilder &builder,
// TODO: coarrays
int corank = 0;
args.push_back(builder.createIntegerConstant(loc, inputTypes[4], corank));
- builder.create<fir::CallOp>(loc, callee, args);
+ const auto convertedArgs = fir::runtime::createArguments(
+ builder, loc, callee.getFunctionType(), args);
+ builder.create<fir::CallOp>(loc, callee, convertedArgs);
}
/// Generate a sequence of runtime calls to allocate memory.
@@ -194,10 +192,9 @@ static mlir::Value genRuntimeAllocate(fir::FirOpBuilder &builder,
args.push_back(errorManager.errMsgAddr);
args.push_back(errorManager.sourceFile);
args.push_back(errorManager.sourceLine);
- llvm::SmallVector<mlir::Value> operands;
- for (auto [fst, snd] : llvm::zip(args, callee.getFunctionType().getInputs()))
- operands.emplace_back(builder.createConvert(loc, snd, fst));
- return builder.create<fir::CallOp>(loc, callee, operands).getResult(0);
+ const auto convertedArgs = fir::runtime::createArguments(
+ builder, loc, callee.getFunctionType(), args);
+ return builder.create<fir::CallOp>(loc, callee, convertedArgs).getResult(0);
}
/// Generate a sequence of runtime calls to allocate memory and assign with the
@@ -213,14 +210,11 @@ static mlir::Value genRuntimeAllocateSource(fir::FirOpBuilder &builder,
loc, builder)
: fir::runtime::getRuntimeFunc<mkRTKey(AllocatableAllocateSource)>(
loc, builder);
- llvm::SmallVector<mlir::Value> args{
- box.getAddr(), fir::getBase(source),
- errorManager.hasStat, errorManager.errMsgAddr,
- errorManager.sourceFile, errorManager.sourceLine};
- llvm::SmallVector<mlir::Value> operands;
- for (auto [fst, snd] : llvm::zip(args, callee.getFunctionType().getInputs()))
- operands.emplace_back(builder.createConvert(loc, snd, fst));
- return builder.create<fir::CallOp>(loc, callee, operands).getResult(0);
+ const auto args = fir::runtime::createArguments(
+ builder, loc, callee.getFunctionType(), box.getAddr(),
+ fir::getBase(source), errorManager.hasStat, errorManager.errMsgAddr,
+ errorManager.sourceFile, errorManager.sourceLine);
+ return builder.create<fir::CallOp>(loc, callee, args).getResult(0);
}
/// Generate runtime call to apply mold to the descriptor.
@@ -234,14 +228,12 @@ static void genRuntimeAllocateApplyMold(fir::FirOpBuilder &builder,
builder)
: fir::runtime::getRuntimeFunc<mkRTKey(AllocatableApplyMold)>(
loc, builder);
- llvm::SmallVector<mlir::Value> args{
+ const auto args = fir::runtime::createArguments(
+ builder, loc, callee.getFunctionType(),
fir::factory::getMutableIRBox(builder, loc, box), fir::getBase(mold),
builder.createIntegerConstant(
- loc, callee.getFunctionType().getInputs()[2], rank)};
- llvm::SmallVector<mlir::Value> operands;
- for (auto [fst, snd] : llvm::zip(args, callee.getFunctionType().getInputs()))
- operands.emplace_back(builder.createConvert(loc, snd, fst));
- builder.create<fir::CallOp>(loc, callee, operands);
+ loc, callee.getFunctionType().getInputs()[2], rank));
+ builder.create<fir::CallOp>(loc, callee, args);
}
/// Generate a runtime call to deallocate memory.
@@ -669,15 +661,13 @@ class AllocateStmtHelper {
llvm::ArrayRef<mlir::Type> inputTypes =
callee.getFunctionType().getInputs();
- llvm::SmallVector<mlir::Value> args;
- args.push_back(builder.createConvert(loc, inputTypes[0], box.getAddr()));
- args.push_back(builder.createConvert(loc, inputTypes[1], typeDescAddr));
mlir::Value rankValue =
builder.createIntegerConstant(loc, inputTypes[2], rank);
mlir::Value corankValue =
builder.createIntegerConstant(loc, inputTypes[3], corank);
- args.push_back(rankValue);
- args.push_back(corankValue);
+ const auto args = fir::runtime::createArguments(
+ builder, loc, callee.getFunctionType(), box.getAddr(), typeDescAddr,
+ rankValue, corankValue);
builder.create<fir::CallOp>(loc, callee, args);
}
@@ -696,8 +686,6 @@ class AllocateStmtHelper {
llvm::ArrayRef<mlir::Type> inputTypes =
callee.getFunctionType().getInputs();
- llvm::SmallVector<mlir::Value> args;
- args.push_back(builder.createConvert(loc, inputTypes[0], box.getAddr()));
mlir::Value categoryValue = builder.createIntegerConstant(
loc, inputTypes[1], static_cast<int32_t>(category));
mlir::Value kindValue =
@@ -706,10 +694,9 @@ class AllocateStmtHelper {
builder.createIntegerConstant(loc, inputTypes[3], rank);
mlir::Value corankValue =
builder.createIntegerConstant(loc, inputTypes[4], corank);
- args.push_back(categoryValue);
- args.push_back(kindValue);
- args.push_back(rankValue);
- args.push_back(corankValue);
+ const auto args = fir::runtime::createArguments(
+ builder, loc, callee.getFunctionType(), box.getAddr(), categoryValue,
+ kindValue, rankValue, corankValue);
builder.create<fir::CallOp>(loc, callee, args);
}
diff --git a/flang/lib/Lower/ConvertExprToHLFIR.cpp b/flang/lib/Lower/ConvertExprToHLFIR.cpp
index 04b63f92a1fb4..395f4518efb1e 100644
--- a/flang/lib/Lower/ConvertExprToHLFIR.cpp
+++ b/flang/lib/Lower/ConvertExprToHLFIR.cpp
@@ -227,6 +227,12 @@ class HlfirDesignatorBuilder {
isVolatile = true;
}
+ // Check if the base type is volatile
+ if (partInfo.base.has_value()) {
+ mlir::Type baseType = partInfo.base.value().getType();
+ isVolatile = isVolatile || fir::isa_volatile_type(baseType);
+ }
+
// Dynamic type of polymorphic base must be kept if the designator is
// polymorphic.
if (isPolymorphic(designatorNode))
@@ -238,12 +244,6 @@ class HlfirDesignatorBuilder {
if (charType && charType.hasDynamicLen())
return fir::BoxCharType::get(charType.getContext(), charType.getFKind());
- // Check if the base type is volatile
- if (partInfo.base.has_value()) {
- mlir::Type baseType = partInfo.base.value().getType();
- isVolatile = isVolatile || fir::isa_volatile_type(baseType);
- }
-
// Arrays with non default lower bounds or dynamic length or dynamic extent
// need a fir.box to hold the dynamic or lower bound information.
if (fir::hasDynamicSize(resultValueType) ||
diff --git a/flang/lib/Optimizer/HLFIR/IR/HLFIROps.cpp b/flang/lib/Optimizer/HLFIR/IR/HLFIROps.cpp
index eef1377f26961..711d5d1461b08 100644
--- a/flang/lib/Optimizer/HLFIR/IR/HLFIROps.cpp
+++ b/flang/lib/Optimizer/HLFIR/IR/HLFIROps.cpp
@@ -210,15 +210,14 @@ static bool hasExplicitLowerBounds(mlir::Value shape) {
static std::pair<mlir::Type, mlir::Value> updateDeclareInputTypeWithVolatility(
mlir::Type inputType, mlir::Value memref, mlir::OpBuilder &builder,
fir::FortranVariableFlagsAttr fortran_attrs) {
- if (mlir::isa<fir::BoxType, fir::ReferenceType>(inputType) && 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);
- // If an entity is a pointer, the entity it points to is volatile, as far
- // as consumers of the pointer are concerned.
+ // A volatile pointer's pointee is volatile.
auto elementType = t.getEleTy();
const bool elementTypeIsVolatile =
isPointer || fir::isa_volatile_type(elementType);
@@ -227,8 +226,7 @@ static std::pair<mlir::Type, mlir::Value> updateDeclareInputTypeWithVolatility(
inputType = FIRT::get(newEleTy, true);
};
llvm::TypeSwitch<mlir::Type>(inputType)
- .Case<fir::ReferenceType, fir::BoxType>(updateType)
- .Default([](mlir::Type t) { return t; });
+ .Case<fir::ReferenceType, fir::BoxType, fir::ClassType>(updateType);
memref =
builder.create<fir::VolatileCastOp>(memref.getLoc(), inputType, memref);
}
diff --git a/flang/test/Lower/allocatable-polymorphic.f90 b/flang/test/Lower/allocatable-polymorphic.f90
index dd8671daeaf8e..10e703210ea61 100644
--- a/flang/test/Lower/allocatable-polymorphic.f90
+++ b/flang/test/Lower/allocatable-polymorphic.f90
@@ -41,7 +41,7 @@ subroutine proc2_p2(this)
end subroutine
! ------------------------------------------------------------------------------
-! Test lowering of ALLOCATE statement for polymoprhic pointer
+! Test lowering of ALLOCATE statement for polymorphic pointer
! ------------------------------------------------------------------------------
subroutine test_pointer()
@@ -98,10 +98,10 @@ subroutine test_pointer()
! CHECK: %[[P_DECL:.*]]:2 = hlfir.declare %[[P_DESC]] {fortran_attrs = #fir.var_attrs<pointer>, uniq_name = "_QMpolyFtest_pointerEp"} : (!fir.ref<!fir.class<!fir.ptr<!fir.type<_QMpolyTp1{a:i32,b:i32}>>>>) -> (!fir.ref<!fir.class<!fir.ptr<!fir.type<_QMpolyTp1{a:i32,b:i32}>>>>, !fir.ref<!fir.class<!fir.ptr<!fir.type<_QMpolyTp1{a:i32,b:i32}>>>>)
! CHECK: %[[TYPE_DESC_P1:.*]] = fir.type_desc !fir.type<_QMpolyTp1{a:i32,b:i32}>
-! CHECK: %[[P_DESC_CAST:.*]] = fir.convert %[[P_DECL]]#0 : (!fir.ref<!fir.class<!fir.ptr<!fir.type<_QMpolyTp1{a:i32,b:i32}>>>>) -> !fir.ref<!fir.box<none>>
-! CHECK: %[[TYPE_DESC_P1_CAST:.*]] = fir.convert %[[TYPE_DESC_P1]] : (!fir.tdesc<!fir.type<_QMpolyTp1{a:i32,b:i32}>>) -> !fir.ref<none>
-! CHECK: %[[RANK:.*]] = arith.constant 0 : i32
-! CHECK: %[[CORANK:.*]] = arith.constant 0 : i32
+! CHECK-DAG: %[[P_DESC_CAST:.*]] = fir.convert %[[P_DECL]]#0 : (!fir.ref<!fir.class<!fir.ptr<!fir.type<_QMpolyTp1{a:i32,b:i32}>>>>) -> !fir.ref<!fir.box<none>>
+! CHECK-DAG: %[[TYPE_DESC_P1_CAST:.*]] = fir.convert %[[TYPE_DESC_P1]] : (!fir.tdesc<!fir.type<_QMpolyTp1{a:i32,b:i32}>>) -> !fir.ref<none>
+! CHECK-DAG: %[[RANK:.*]] = arith.constant 0 : i32
+! CHECK-DAG: %[[CORANK:.*]] = arith.constant 0 : i32
! CHECK: fir.call @_FortranAPointerNullifyDerived(%[[P_DESC_CAST]], %[[TYPE_DESC_P1_CAST]], %[[RANK]], %[[CORANK]]) {{.*}}: (!fir.ref<!fir.box<none>>, !fir.ref<none>, i32, i32) -> ()
! CHECK: %[[P_DESC_CAST:.*]] = fir.convert %[[P_DECL]]#0 : (!fir.ref<!fir.class<!fir.ptr<!fir.type<_QMpolyTp1{a:i32,b:i32}>>>>) -> !fir.ref<!fir.box<none>>
! CHECK: %{{.*}} = fir.call @_FortranAPointerAllocate(%[[P_DESC_CAST]], %{{.*}}, %{{.*}}, %{{.*}}, %{{.*}}) {{.*}}: (!fir.ref<!fir.box<none>>, i1, !fir.box<none>, !fir.ref<i8>, i32) -> i32
@@ -111,19 +111,19 @@ subroutine test_pointer()
! CHECK: fir.dispatch "proc1"(%[[P_LOAD]] : !fir.class<!fir.ptr<!fir.type<_QMpolyTp1{a:i32,b:i32}>>>)
! CHECK: %[[TYPE_DESC_P1:.*]] = fir.type_desc !fir.type<_QMpolyTp1{a:i32,b:i32}>
-! CHECK: %[[C1_DESC_CAST:.*]] = fir.convert %[[C1_DECL:.*]]#0 : (!fir.ref<!fir.class<!fir.ptr<!fir.type<_QMpolyTp1{a:i32,b:i32}>>>>) -> !fir.ref<!fir.box<none>>
-! CHECK: %[[TYPE_DESC_P1_CAST:.*]] = fir.convert %[[TYPE_DESC_P1]] : (!fir.tdesc<!fir.type<_QMpolyTp1{a:i32,b:i32}>>) -> !fir.ref<none>
-! CHECK: %[[RANK:.*]] = arith.constant 0 : i32
-! CHECK: %[[CORANK:.*]] = arith.constant 0 : i32
+! CHECK-DAG: %[[C1_DESC_CAST:.*]] = fir.convert %[[C1_DECL:.*]]#0 : (!fir.ref<!fir.class<!fir.ptr<!fir.type<_QMpolyTp1{a:i32,b:i32}>>>>) -> !fir.ref<!fir.box<none>>
+! CHECK-DAG: %[[TYPE_DESC_P1_CAST:.*]] = fir.convert %[[TYPE_DESC_P1]] : (!fir.tdesc<!fir.type<_QMpolyTp1{a:i32,b:i32}>>) -> !fir.ref<none>
+! CHECK-DAG: %[[RANK:.*]] = arith.constant 0 : i32
+! CHECK-DAG: %[[CORANK:.*]] = arith.constant 0 : i32
! CHECK: fir.call @_FortranAPointerNullifyDerived(%[[C1_DESC_CAST]], %[[TYPE_DESC_P1_CAST]], %[[RANK]], %[[CORANK]]) {{.*}}: (!fir.ref<!fir.box<none>>, !fir.ref<none>, i32, i32) -> ()
! CHECK: %[[C1_DESC_CAST:.*]] = fir.convert %[[C1_DECL]]#0 : (!fir.ref<!fir.class<!fir.ptr<!fir.type<_QMpolyTp1{a:i32,b:i32}>>>>) -> !fir.ref<!fir.box<none>>
! CHECK: %{{.*}} = fir.call @_FortranAPointerAllocate(%[[C1_DESC_CAST]], %{{.*}}, %{{.*}}, %{{.*}}, %{{.*}}) {{.*}}: (!fir.ref<!fir.box<none>>, i1, !fir.box<none>, !fir.ref<i8>, i32) -> i32
! CHECK: %[[TYPE_DESC_P2:.*]] = fir.type_desc !fir.type<_QMpolyTp2{p1:!fir.type<_QMpolyTp1{a:i32,b:i32}>,c:i32}>
-! CHECK: %[[C2_DESC_CAST:.*]] = fir.convert %[[C2_DECL]]#0 : (!fir.ref<!fir.class<!fir.ptr<!fir.type<_QMpolyTp1{a:i32,b:i32}>>>>) -> !fir.ref<!fir.box<none>>
-! CHECK: %[[TYPE_DESC_P2_CAST:.*]] = fir.convert %[[TYPE_DESC_P2]] : (!fir.tdesc<!fir.type<_QMpolyTp2{p1:!fir.type<_QMpolyTp1{a:i32,b:i32}>,c:i32}>>) -> !fir.ref<none>
-! CHECK: %[[RANK:.*]] = arith.constant 0 : i32
-! CHECK: %[[CORANK:.*]] = arith.constant 0 : i32
+! CHECK-DAG: %[[C2_DESC_CAST:.*]] = fir.convert %[[C2_DECL]]#0 : (!fir.ref<!fir.class<!fir.ptr<!fir.type<_QMpolyTp1{a:i32,b:i32}>>>>) -> !fir.ref<!fir.box<none>>
+! CHECK-DAG: %[[TYPE_DESC_P2_CAST:.*]] = fir.convert %[[TYPE_DESC_P2]] : (!fir.tdesc<!fir.type<_QMpolyTp2{p1:!fir.type<_QMpolyTp1{a:i32,b:i32}>,c:i32}>>) -> !fir.ref<none>
+! CHECK-DAG: %[[RANK:.*]] = arith.constant 0 : i32
+! CHECK-DAG: %[[CORANK:.*]] = arith.constant 0 : i32
! CHECK: fir.call @_FortranAPointerNullifyDerived(%[[C2_DESC_CAST]], %[[TYPE_DESC_P2_CAST]], %[[RANK]], %[[CORANK]]) {{.*}}: (!fir.ref<!fir.box<none>>, !fir.ref<none>, i32, i32) -> ()
! CHECK: %[[C2_DESC_CAST:.*]] = fir.convert %[[C2_DECL]]#0 : (!fir.ref<!fir.class<!fir.ptr<!fir.type<_QMpolyTp1{a:i32,b:i32}>>>>) -> !fir.ref<!fir.box<none>>
! CHECK: %{{.*}} = fir.call @_FortranAPointerAllocate(%[[C2_DESC_CAST]], %{{.*}}, %{{.*}}, %{{.*}}, %{{.*}}) {{.*}}: (!fir.ref<!fir.box<none>>, i1, !fir.box<none>, !fir.ref<i8>, i32) -> i32
@@ -147,10 +147,10 @@ subroutine test_pointer()
! CHECK: fir.dispatch "proc2"(%[[C2_REBOX]] : !fir.class<!fir.type<_QMpolyTp1{a:i32,b:i32}>>) (%[[C2_REBOX]] : !fir.class<!fir.type<_QMpolyTp1{a:i32,b:i32}>>) {pass_arg_pos = 0 : i32}
! CHECK: %[[TYPE_DESC_P1:.*]] = fir.type_desc !fir.type<_QMpolyTp1{a:i32,b:i32}>
-! CHECK: %[[C3_CAST:.*]] = fir.convert %[[C3_DECL]]#0 : (!fir.ref<!fir.class<!fir.ptr<!fir.array<?x!fir.type<_QMpolyTp1{a:i32,b:i32}>>>>>) -> !fir.ref<!fir.box<none>>
-! CHECK: %[[TYPE_DESC_P1_CAST:.*]] = fir.convert %[[TYPE_DESC_P1]] : (!fir.tdesc<!fir.type<_QMpolyTp1{a:i32,b:i32}>>) -> !fir.ref<none>
-! CHECK: %[[RANK:.*]] = arith.constant 1 : i32
-! CHECK: %[[CORANK:.*]] = arith.constant 0 : i32
+! CHECK-DAG: %[[C3_CAST:.*]] = fir.convert %[[C3_DECL]]#0 : (!fir.ref<!fir.class<!fir.ptr<!fir.array<?x!fir.type<_QMpolyTp1{a:i32,b:i32}>>>>>) -> !fir.ref<!fir.box<none>>
+! CHECK-DAG: %[[TYPE_DESC_P1_CAST:.*]] = fir.convert %[[TYPE_DESC_P1]] : (!fir.tdesc<!fir.type<_QMpolyTp1{a:i32,b:i32}>>) -> !fir.ref<none>
+! CHECK-DAG: %[[RANK:.*]] = arith.constant 1 : i32
+! CHECK-DAG: %[[CORANK:.*]] = arith.constant 0 : i32
! CHECK: fir.call @_FortranAPointerNullifyDerived(%[[C3_CAST]], %[[TYPE_DESC_P1_CAST]], %[[RANK]], %[[CORANK]]) {{.*}}: (!fir.ref<!fir.box<none>>, !fir.ref<none>, i32, i32) -> ()
! CHECK: %[[C3_CAST:.*]] = fir.convert %[[C3_DECL]]#0 : (!fir.ref<!fir.class<!fir.ptr<!fir.array<?x!fir.type<_QMpolyTp1{a:i32,b:i32}>>>>>) -> !fir.ref<!fir.box<none>>
! CHECK: fir.call @_FortranAPointerSetBounds(%[[C3_CAST]], %{{.*}}, %{{.*}}, %{{.*}}) {{.*}}: (!fir.ref<!fir.box<none>>, i32, i64, i64) -> ()
@@ -158,10 +158,10 @@ subroutine test_pointer()
! CHECK: %{{.*}} = fir.call @_FortranAPointerAllocate(%[[C3_CAST]], %{{.*}}, %{{.*}}, %{{.*}}, %{{.*}}) {{.*}}: (!fir.ref<!fir.box<none>>, i1, !fir.box<none>, !fir.ref<i8>, i32) -> i32
! CHECK: %[[TYPE_DESC_P2:.*]] = fir.type_desc !fir.type<_QMpolyTp2{p1:!fir.type<_QMpolyTp1{a:i32,b:i32}>,c:i32}>
-! CHECK: %[[C4_CAST:.*]] = fir.convert %[[C4_DECL]]#0 : (!fir.ref<!fir.class<!fir.ptr<!fir.array<?x!fir.type<_QMpolyTp1{a:i32,b:i32}>>>>>) -> !fir.ref<!fir.box<none>>
-! CHECK: %[[TYPE_DESC_P2_CAST:.*]] = fir.convert %[[TYPE_DESC_P2]] : (!fir.tdesc<!fir.type<_QMpolyTp2{p1:!fir.type<_QMpolyTp1{a:i32,b:i32}>,c:i32}>>) -> !fir.ref<none>
-! CHECK: %[[RANK:.*]] = arith.constant 1 : i32
-! CHECK: %[[CORANK:.*]] = arith.constant 0 : i32
+! CHECK-DAG: %[[C4_CAST:.*]] = fir.c...
[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 Asher, LGTM!
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); | ||
// If an entity is a pointer, the entity it points to is volatile, as far | ||
// as consumers of the pointer are concerned. | ||
// A volatile pointer's pointee is volatile. |
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.
Unrelated to your patch, but since you updated the comment :), why doesn't this also apply to the target data of an allocatable descriptor?
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 for pointing this out! I discussed this with Slava, it's next on my volatile todo list :)
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
When lowering allocatables, the generated calls to runtime functions were not using the runtime::createArguments utility which handles the required conversions. createArguments is where I added the implicit volatile casts to handle converting volatile variables to the appropriate type based on their volatility in the callee. Because the calls to allocatable runtime functions were not using this function, their arguments were not casted to have the appropriate volatility.
Add a test to demonstrate that volatile and allocatable class/box/reference types are appropriately casted before calling into the runtime library.
Instead of using a recursive variadic template to perform the conversions in createArguments, map over the arguments directly so that createArguments can be called with an ArrayRef of arguments. Some cases in Allocatable.cpp already had a vector of values at the point where createArguments needed to be called - the new overload allows calling with a vector of args or the variadic version with each argument spelled out at the callsite.
This change resulted in the allocatable runtime calls having their arguments converted left-to-right, which changed some of the test results. I used CHECK-DAG to ignore the order.
Add some missing handling of volatile class entities, which I previously missed because I had not yet enabled volatile class entities in Lower.